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
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2019-04-17 07:17:24 +0300
committerCampbell Barton <ideasman42@gmail.com>2019-04-17 07:21:24 +0300
commite12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 (patch)
tree8cf3453d12edb177a218ef8009357518ec6cab6a /source/blender/blenkernel/intern
parentb3dabc200a4b0399ec6b81f2ff2730d07b44fcaa (diff)
ClangFormat: apply to source, most of intern
Apply clang format as proposed in T53211. For details on usage and instructions for migrating branches without conflicts, see: https://wiki.blender.org/wiki/Tools/ClangFormat
Diffstat (limited to 'source/blender/blenkernel/intern')
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf.c2221
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf.h267
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_inline.h261
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_intern.h317
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_legacy.c2456
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c1649
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c1082
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_util.c367
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c3964
-rw-r--r--source/blender/blenkernel/intern/action.c2067
-rw-r--r--source/blender/blenkernel/intern/addon.c97
-rw-r--r--source/blender/blenkernel/intern/anim.c720
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c5794
-rw-r--r--source/blender/blenkernel/intern/appdir.c1138
-rw-r--r--source/blender/blenkernel/intern/armature.c4088
-rw-r--r--source/blender/blenkernel/intern/armature_update.c1404
-rw-r--r--source/blender/blenkernel/intern/autoexec.c38
-rw-r--r--source/blender/blenkernel/intern/blender.c366
-rw-r--r--source/blender/blenkernel/intern/blender_copybuffer.c147
-rw-r--r--source/blender/blenkernel/intern/blender_undo.c116
-rw-r--r--source/blender/blenkernel/intern/blender_user_menu.c108
-rw-r--r--source/blender/blenkernel/intern/blendfile.c1057
-rw-r--r--source/blender/blenkernel/intern/boids.c3002
-rw-r--r--source/blender/blenkernel/intern/bpath.c1104
-rw-r--r--source/blender/blenkernel/intern/brush.c2236
-rw-r--r--source/blender/blenkernel/intern/bvhutils.c2176
-rw-r--r--source/blender/blenkernel/intern/cachefile.c247
-rw-r--r--source/blender/blenkernel/intern/camera.c1533
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c1917
-rw-r--r--source/blender/blenkernel/intern/cloth.c2720
-rw-r--r--source/blender/blenkernel/intern/collection.c1577
-rw-r--r--source/blender/blenkernel/intern/collision.c2853
-rw-r--r--source/blender/blenkernel/intern/colorband.c1003
-rw-r--r--source/blender/blenkernel/intern/colortools.c2738
-rw-r--r--source/blender/blenkernel/intern/constraint.c8053
-rw-r--r--source/blender/blenkernel/intern/context.c1258
-rw-r--r--source/blender/blenkernel/intern/crazyspace.c743
-rw-r--r--source/blender/blenkernel/intern/curve.c8849
-rw-r--r--source/blender/blenkernel/intern/curve_decimate.c525
-rw-r--r--source/blender/blenkernel/intern/customdata.c6295
-rw-r--r--source/blender/blenkernel/intern/customdata_file.c533
-rw-r--r--source/blender/blenkernel/intern/data_transfer.c3038
-rw-r--r--source/blender/blenkernel/intern/data_transfer_intern.h60
-rw-r--r--source/blender/blenkernel/intern/deform.c2066
-rw-r--r--source/blender/blenkernel/intern/displist.c3366
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c10534
-rw-r--r--source/blender/blenkernel/intern/editderivedmesh.c855
-rw-r--r--source/blender/blenkernel/intern/editlattice.c190
-rw-r--r--source/blender/blenkernel/intern/editmesh.c279
-rw-r--r--source/blender/blenkernel/intern/editmesh_bvh.c764
-rw-r--r--source/blender/blenkernel/intern/editmesh_cache.c125
-rw-r--r--source/blender/blenkernel/intern/editmesh_tangent.c626
-rw-r--r--source/blender/blenkernel/intern/effect.c2035
-rw-r--r--source/blender/blenkernel/intern/fcurve.c4745
-rw-r--r--source/blender/blenkernel/intern/fluidsim.c75
-rw-r--r--source/blender/blenkernel/intern/fmodifier.c2179
-rw-r--r--source/blender/blenkernel/intern/font.c2822
-rw-r--r--source/blender/blenkernel/intern/freestyle.c308
-rw-r--r--source/blender/blenkernel/intern/gpencil.c2605
-rw-r--r--source/blender/blenkernel/intern/gpencil_modifier.c1207
-rw-r--r--source/blender/blenkernel/intern/icons.c1037
-rw-r--r--source/blender/blenkernel/intern/icons_rasterize.c192
-rw-r--r--source/blender/blenkernel/intern/idcode.c476
-rw-r--r--source/blender/blenkernel/intern/idprop.c1361
-rw-r--r--source/blender/blenkernel/intern/idprop_utils.c339
-rw-r--r--source/blender/blenkernel/intern/image.c7623
-rw-r--r--source/blender/blenkernel/intern/image_gen.c810
-rw-r--r--source/blender/blenkernel/intern/ipo.c3709
-rw-r--r--source/blender/blenkernel/intern/key.c3585
-rw-r--r--source/blender/blenkernel/intern/keyconfig.c98
-rw-r--r--source/blender/blenkernel/intern/lattice.c1927
-rw-r--r--source/blender/blenkernel/intern/layer.c1805
-rw-r--r--source/blender/blenkernel/intern/layer_utils.c144
-rw-r--r--source/blender/blenkernel/intern/library.c3134
-rw-r--r--source/blender/blenkernel/intern/library_idmap.c219
-rw-r--r--source/blender/blenkernel/intern/library_override.c1015
-rw-r--r--source/blender/blenkernel/intern/library_query.c2317
-rw-r--r--source/blender/blenkernel/intern/library_remap.c1557
-rw-r--r--source/blender/blenkernel/intern/light.c170
-rw-r--r--source/blender/blenkernel/intern/lightprobe.c48
-rw-r--r--source/blender/blenkernel/intern/linestyle.c2574
-rw-r--r--source/blender/blenkernel/intern/main.c691
-rw-r--r--source/blender/blenkernel/intern/mask.c2669
-rw-r--r--source/blender/blenkernel/intern/mask_evaluate.c1365
-rw-r--r--source/blender/blenkernel/intern/mask_rasterize.c2355
-rw-r--r--source/blender/blenkernel/intern/material.c2170
-rw-r--r--source/blender/blenkernel/intern/mball.c720
-rw-r--r--source/blender/blenkernel/intern/mball_tessellate.c1915
-rw-r--r--source/blender/blenkernel/intern/mesh.c2792
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.c2569
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c6275
-rw-r--r--source/blender/blenkernel/intern/mesh_iterators.c293
-rw-r--r--source/blender/blenkernel/intern/mesh_mapping.c1835
-rw-r--r--source/blender/blenkernel/intern/mesh_merge.c1134
-rw-r--r--source/blender/blenkernel/intern/mesh_remap.c4308
-rw-r--r--source/blender/blenkernel/intern/mesh_runtime.c493
-rw-r--r--source/blender/blenkernel/intern/mesh_tangent.c1075
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.c2712
-rw-r--r--source/blender/blenkernel/intern/modifier.c1023
-rw-r--r--source/blender/blenkernel/intern/movieclip.c2236
-rw-r--r--source/blender/blenkernel/intern/multires.c3902
-rw-r--r--source/blender/blenkernel/intern/multires_inline.h59
-rw-r--r--source/blender/blenkernel/intern/multires_reshape.c1745
-rw-r--r--source/blender/blenkernel/intern/multires_subdiv.c39
-rw-r--r--source/blender/blenkernel/intern/nla.c3096
-rw-r--r--source/blender/blenkernel/intern/node.c5202
-rw-r--r--source/blender/blenkernel/intern/object.c6498
-rw-r--r--source/blender/blenkernel/intern/object_deform.c1129
-rw-r--r--source/blender/blenkernel/intern/object_dupli.c1716
-rw-r--r--source/blender/blenkernel/intern/object_facemap.c280
-rw-r--r--source/blender/blenkernel/intern/object_update.c612
-rw-r--r--source/blender/blenkernel/intern/ocean.c2301
-rw-r--r--source/blender/blenkernel/intern/outliner_treehash.c240
-rw-r--r--source/blender/blenkernel/intern/packedFile.c1127
-rw-r--r--source/blender/blenkernel/intern/paint.c1907
-rw-r--r--source/blender/blenkernel/intern/paint_toolslots.c138
-rw-r--r--source/blender/blenkernel/intern/particle.c7757
-rw-r--r--source/blender/blenkernel/intern/particle_child.c1471
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c2266
-rw-r--r--source/blender/blenkernel/intern/particle_system.c7709
-rw-r--r--source/blender/blenkernel/intern/pbvh.c3422
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c3566
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h285
-rw-r--r--source/blender/blenkernel/intern/pointcache.c6922
-rw-r--r--source/blender/blenkernel/intern/report.c382
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c3068
-rw-r--r--source/blender/blenkernel/intern/scene.c3417
-rw-r--r--source/blender/blenkernel/intern/screen.c1057
-rw-r--r--source/blender/blenkernel/intern/seqcache.c272
-rw-r--r--source/blender/blenkernel/intern/seqeffects.c6704
-rw-r--r--source/blender/blenkernel/intern/seqmodifier.c1439
-rw-r--r--source/blender/blenkernel/intern/sequencer.c9164
-rw-r--r--source/blender/blenkernel/intern/shader_fx.c215
-rw-r--r--source/blender/blenkernel/intern/shrinkwrap.c2133
-rw-r--r--source/blender/blenkernel/intern/smoke.c6053
-rw-r--r--source/blender/blenkernel/intern/softbody.c5860
-rw-r--r--source/blender/blenkernel/intern/sound.c1435
-rw-r--r--source/blender/blenkernel/intern/speaker.c51
-rw-r--r--source/blender/blenkernel/intern/studiolight.c2107
-rw-r--r--source/blender/blenkernel/intern/subdiv.c267
-rw-r--r--source/blender/blenkernel/intern/subdiv_ccg.c1884
-rw-r--r--source/blender/blenkernel/intern/subdiv_ccg_mask.c215
-rw-r--r--source/blender/blenkernel/intern/subdiv_ccg_material.c44
-rw-r--r--source/blender/blenkernel/intern/subdiv_converter.c65
-rw-r--r--source/blender/blenkernel/intern/subdiv_converter.h8
-rw-r--r--source/blender/blenkernel/intern/subdiv_converter_mesh.c514
-rw-r--r--source/blender/blenkernel/intern/subdiv_displacement.c16
-rw-r--r--source/blender/blenkernel/intern/subdiv_displacement_multires.c664
-rw-r--r--source/blender/blenkernel/intern/subdiv_eval.c528
-rw-r--r--source/blender/blenkernel/intern/subdiv_foreach.c3309
-rw-r--r--source/blender/blenkernel/intern/subdiv_inline.h117
-rw-r--r--source/blender/blenkernel/intern/subdiv_mesh.c1895
-rw-r--r--source/blender/blenkernel/intern/subdiv_stats.c69
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c4910
-rw-r--r--source/blender/blenkernel/intern/suggestions.c277
-rw-r--r--source/blender/blenkernel/intern/text.c4367
-rw-r--r--source/blender/blenkernel/intern/texture.c1026
-rw-r--r--source/blender/blenkernel/intern/tracking.c4156
-rw-r--r--source/blender/blenkernel/intern/tracking_auto.c889
-rw-r--r--source/blender/blenkernel/intern/tracking_detect.c216
-rw-r--r--source/blender/blenkernel/intern/tracking_plane_tracker.c331
-rw-r--r--source/blender/blenkernel/intern/tracking_region_tracker.c487
-rw-r--r--source/blender/blenkernel/intern/tracking_solver.c792
-rw-r--r--source/blender/blenkernel/intern/tracking_stabilize.c1905
-rw-r--r--source/blender/blenkernel/intern/tracking_util.c1345
-rw-r--r--source/blender/blenkernel/intern/undo_system.c1248
-rw-r--r--source/blender/blenkernel/intern/unit.c1385
-rw-r--r--source/blender/blenkernel/intern/workspace.c439
-rw-r--r--source/blender/blenkernel/intern/world.c127
-rw-r--r--source/blender/blenkernel/intern/writeavi.c360
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c3168
171 files changed, 170483 insertions, 163021 deletions
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c
index ef3101a14b5..2ab6eb387aa 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf.c
@@ -23,7 +23,7 @@
#include <math.h>
#include "MEM_guardedalloc.h"
-#include "BLI_sys_types.h" // for intptr_t support
+#include "BLI_sys_types.h" // for intptr_t support
#include "BLI_utildefines.h" /* for BLI_assert */
@@ -45,1531 +45,1594 @@
int BKE_ccg_gridsize(int level)
{
- return ccg_gridsize(level);
+ return ccg_gridsize(level);
}
int BKE_ccg_factor(int low_level, int high_level)
{
- BLI_assert(low_level > 0 && high_level > 0);
- BLI_assert(low_level <= high_level);
+ BLI_assert(low_level > 0 && high_level > 0);
+ BLI_assert(low_level <= high_level);
- return 1 << (high_level - low_level);
+ return 1 << (high_level - low_level);
}
/***/
static CCGVert *_vert_new(CCGVertHDL vHDL, CCGSubSurf *ss)
{
- int num_vert_data = ss->subdivLevels + 1;
- CCGVert *v = CCGSUBSURF_alloc(ss,
- sizeof(CCGVert) +
- ss->meshIFC.vertDataSize * num_vert_data +
- ss->meshIFC.vertUserSize);
- byte *userData;
+ int num_vert_data = ss->subdivLevels + 1;
+ CCGVert *v = CCGSUBSURF_alloc(
+ ss, sizeof(CCGVert) + ss->meshIFC.vertDataSize * num_vert_data + ss->meshIFC.vertUserSize);
+ byte *userData;
- v->vHDL = vHDL;
- v->edges = NULL;
- v->faces = NULL;
- v->numEdges = v->numFaces = 0;
- v->flags = 0;
+ v->vHDL = vHDL;
+ v->edges = NULL;
+ v->faces = NULL;
+ v->numEdges = v->numFaces = 0;
+ v->flags = 0;
- userData = ccgSubSurf_getVertUserData(ss, v);
- memset(userData, 0, ss->meshIFC.vertUserSize);
- if (ss->useAgeCounts) *((int *) &userData[ss->vertUserAgeOffset]) = ss->currentAge;
+ userData = ccgSubSurf_getVertUserData(ss, v);
+ memset(userData, 0, ss->meshIFC.vertUserSize);
+ if (ss->useAgeCounts)
+ *((int *)&userData[ss->vertUserAgeOffset]) = ss->currentAge;
- return v;
+ return v;
}
static void _vert_remEdge(CCGVert *v, CCGEdge *e)
{
- int i;
- for (i = 0; i < v->numEdges; i++) {
- if (v->edges[i] == e) {
- v->edges[i] = v->edges[--v->numEdges];
- break;
- }
- }
+ int i;
+ for (i = 0; i < v->numEdges; i++) {
+ if (v->edges[i] == e) {
+ v->edges[i] = v->edges[--v->numEdges];
+ break;
+ }
+ }
}
static void _vert_remFace(CCGVert *v, CCGFace *f)
{
- int i;
- for (i = 0; i < v->numFaces; i++) {
- if (v->faces[i] == f) {
- v->faces[i] = v->faces[--v->numFaces];
- break;
- }
- }
+ int i;
+ for (i = 0; i < v->numFaces; i++) {
+ if (v->faces[i] == f) {
+ v->faces[i] = v->faces[--v->numFaces];
+ break;
+ }
+ }
}
static void _vert_addEdge(CCGVert *v, CCGEdge *e, CCGSubSurf *ss)
{
- v->edges = CCGSUBSURF_realloc(ss, v->edges, (v->numEdges + 1) * sizeof(*v->edges), v->numEdges * sizeof(*v->edges));
- v->edges[v->numEdges++] = e;
+ v->edges = CCGSUBSURF_realloc(
+ ss, v->edges, (v->numEdges + 1) * sizeof(*v->edges), v->numEdges * sizeof(*v->edges));
+ v->edges[v->numEdges++] = e;
}
static void _vert_addFace(CCGVert *v, CCGFace *f, CCGSubSurf *ss)
{
- v->faces = CCGSUBSURF_realloc(ss, v->faces, (v->numFaces + 1) * sizeof(*v->faces), v->numFaces * sizeof(*v->faces));
- v->faces[v->numFaces++] = f;
+ v->faces = CCGSUBSURF_realloc(
+ ss, v->faces, (v->numFaces + 1) * sizeof(*v->faces), v->numFaces * sizeof(*v->faces));
+ v->faces[v->numFaces++] = f;
}
static CCGEdge *_vert_findEdgeTo(const CCGVert *v, const CCGVert *vQ)
{
- int i;
- for (i = 0; i < v->numEdges; i++) {
- CCGEdge *e = v->edges[v->numEdges - 1 - i]; // XXX, note reverse
- if ((e->v0 == v && e->v1 == vQ) ||
- (e->v1 == v && e->v0 == vQ))
- {
- return e;
- }
- }
- return NULL;
+ int i;
+ for (i = 0; i < v->numEdges; i++) {
+ CCGEdge *e = v->edges[v->numEdges - 1 - i]; // XXX, note reverse
+ if ((e->v0 == v && e->v1 == vQ) || (e->v1 == v && e->v0 == vQ)) {
+ return e;
+ }
+ }
+ return NULL;
}
static void _vert_free(CCGVert *v, CCGSubSurf *ss)
{
- if (v->edges) {
- CCGSUBSURF_free(ss, v->edges);
- }
+ if (v->edges) {
+ CCGSUBSURF_free(ss, v->edges);
+ }
- if (v->faces) {
- CCGSUBSURF_free(ss, v->faces);
- }
+ if (v->faces) {
+ CCGSUBSURF_free(ss, v->faces);
+ }
- CCGSUBSURF_free(ss, v);
+ CCGSUBSURF_free(ss, v);
}
/***/
static CCGEdge *_edge_new(CCGEdgeHDL eHDL, CCGVert *v0, CCGVert *v1, float crease, CCGSubSurf *ss)
{
- int num_edge_data = ccg_edgebase(ss->subdivLevels + 1);
- CCGEdge *e = CCGSUBSURF_alloc(ss,
- sizeof(CCGEdge) +
- ss->meshIFC.vertDataSize * num_edge_data +
- ss->meshIFC.edgeUserSize);
- byte *userData;
-
- e->eHDL = eHDL;
- e->v0 = v0;
- e->v1 = v1;
- e->crease = crease;
- e->faces = NULL;
- e->numFaces = 0;
- e->flags = 0;
- _vert_addEdge(v0, e, ss);
- _vert_addEdge(v1, e, ss);
-
- userData = ccgSubSurf_getEdgeUserData(ss, e);
- memset(userData, 0, ss->meshIFC.edgeUserSize);
- if (ss->useAgeCounts) *((int *) &userData[ss->edgeUserAgeOffset]) = ss->currentAge;
-
- return e;
+ int num_edge_data = ccg_edgebase(ss->subdivLevels + 1);
+ CCGEdge *e = CCGSUBSURF_alloc(
+ ss, sizeof(CCGEdge) + ss->meshIFC.vertDataSize * num_edge_data + ss->meshIFC.edgeUserSize);
+ byte *userData;
+
+ e->eHDL = eHDL;
+ e->v0 = v0;
+ e->v1 = v1;
+ e->crease = crease;
+ e->faces = NULL;
+ e->numFaces = 0;
+ e->flags = 0;
+ _vert_addEdge(v0, e, ss);
+ _vert_addEdge(v1, e, ss);
+
+ userData = ccgSubSurf_getEdgeUserData(ss, e);
+ memset(userData, 0, ss->meshIFC.edgeUserSize);
+ if (ss->useAgeCounts)
+ *((int *)&userData[ss->edgeUserAgeOffset]) = ss->currentAge;
+
+ return e;
}
static void _edge_remFace(CCGEdge *e, CCGFace *f)
{
- int i;
- for (i = 0; i < e->numFaces; i++) {
- if (e->faces[i] == f) {
- e->faces[i] = e->faces[--e->numFaces];
- break;
- }
- }
+ int i;
+ for (i = 0; i < e->numFaces; i++) {
+ if (e->faces[i] == f) {
+ e->faces[i] = e->faces[--e->numFaces];
+ break;
+ }
+ }
}
static void _edge_addFace(CCGEdge *e, CCGFace *f, CCGSubSurf *ss)
{
- e->faces = CCGSUBSURF_realloc(ss, e->faces, (e->numFaces + 1) * sizeof(*e->faces), e->numFaces * sizeof(*e->faces));
- e->faces[e->numFaces++] = f;
+ e->faces = CCGSUBSURF_realloc(
+ ss, e->faces, (e->numFaces + 1) * sizeof(*e->faces), e->numFaces * sizeof(*e->faces));
+ e->faces[e->numFaces++] = f;
}
static void *_edge_getCoVert(CCGEdge *e, CCGVert *v, int lvl, int x, int dataSize)
{
- int levelBase = ccg_edgebase(lvl);
- if (v == e->v0) {
- return &EDGE_getLevelData(e)[dataSize * (levelBase + x)];
- }
- else {
- return &EDGE_getLevelData(e)[dataSize * (levelBase + (1 << lvl) - x)];
- }
+ int levelBase = ccg_edgebase(lvl);
+ if (v == e->v0) {
+ return &EDGE_getLevelData(e)[dataSize * (levelBase + x)];
+ }
+ else {
+ return &EDGE_getLevelData(e)[dataSize * (levelBase + (1 << lvl) - x)];
+ }
}
static void _edge_free(CCGEdge *e, CCGSubSurf *ss)
{
- if (e->faces) {
- CCGSUBSURF_free(ss, e->faces);
- }
+ if (e->faces) {
+ CCGSUBSURF_free(ss, e->faces);
+ }
- CCGSUBSURF_free(ss, e);
+ CCGSUBSURF_free(ss, e);
}
static void _edge_unlinkMarkAndFree(CCGEdge *e, CCGSubSurf *ss)
{
- _vert_remEdge(e->v0, e);
- _vert_remEdge(e->v1, e);
- e->v0->flags |= Vert_eEffected;
- e->v1->flags |= Vert_eEffected;
- _edge_free(e, ss);
+ _vert_remEdge(e->v0, e);
+ _vert_remEdge(e->v1, e);
+ e->v0->flags |= Vert_eEffected;
+ e->v1->flags |= Vert_eEffected;
+ _edge_free(e, ss);
}
-static CCGFace *_face_new(CCGFaceHDL fHDL, CCGVert **verts, CCGEdge **edges, int numVerts, CCGSubSurf *ss)
+static CCGFace *_face_new(
+ CCGFaceHDL fHDL, CCGVert **verts, CCGEdge **edges, int numVerts, CCGSubSurf *ss)
{
- int maxGridSize = ccg_gridsize(ss->subdivLevels);
- int num_face_data = (numVerts * maxGridSize +
- numVerts * maxGridSize * maxGridSize + 1);
- CCGFace *f = CCGSUBSURF_alloc(ss,
- sizeof(CCGFace) +
- sizeof(CCGVert *) * numVerts +
- sizeof(CCGEdge *) * numVerts +
- ss->meshIFC.vertDataSize * num_face_data +
- ss->meshIFC.faceUserSize);
- byte *userData;
- int i;
+ int maxGridSize = ccg_gridsize(ss->subdivLevels);
+ int num_face_data = (numVerts * maxGridSize + numVerts * maxGridSize * maxGridSize + 1);
+ CCGFace *f = CCGSUBSURF_alloc(
+ ss,
+ sizeof(CCGFace) + sizeof(CCGVert *) * numVerts + sizeof(CCGEdge *) * numVerts +
+ ss->meshIFC.vertDataSize * num_face_data + ss->meshIFC.faceUserSize);
+ byte *userData;
+ int i;
- f->numVerts = numVerts;
- f->fHDL = fHDL;
- f->flags = 0;
+ f->numVerts = numVerts;
+ f->fHDL = fHDL;
+ f->flags = 0;
- for (i = 0; i < numVerts; i++) {
- FACE_getVerts(f)[i] = verts[i];
- FACE_getEdges(f)[i] = edges[i];
- _vert_addFace(verts[i], f, ss);
- _edge_addFace(edges[i], f, ss);
- }
+ for (i = 0; i < numVerts; i++) {
+ FACE_getVerts(f)[i] = verts[i];
+ FACE_getEdges(f)[i] = edges[i];
+ _vert_addFace(verts[i], f, ss);
+ _edge_addFace(edges[i], f, ss);
+ }
- userData = ccgSubSurf_getFaceUserData(ss, f);
- memset(userData, 0, ss->meshIFC.faceUserSize);
- if (ss->useAgeCounts) *((int *) &userData[ss->faceUserAgeOffset]) = ss->currentAge;
+ userData = ccgSubSurf_getFaceUserData(ss, f);
+ memset(userData, 0, ss->meshIFC.faceUserSize);
+ if (ss->useAgeCounts)
+ *((int *)&userData[ss->faceUserAgeOffset]) = ss->currentAge;
- return f;
+ return f;
}
static void _face_free(CCGFace *f, CCGSubSurf *ss)
{
- CCGSUBSURF_free(ss, f);
+ CCGSUBSURF_free(ss, f);
}
static void _face_unlinkMarkAndFree(CCGFace *f, CCGSubSurf *ss)
{
- int j;
- for (j = 0; j < f->numVerts; j++) {
- _vert_remFace(FACE_getVerts(f)[j], f);
- _edge_remFace(FACE_getEdges(f)[j], f);
- FACE_getVerts(f)[j]->flags |= Vert_eEffected;
- }
- _face_free(f, ss);
+ int j;
+ for (j = 0; j < f->numVerts; j++) {
+ _vert_remFace(FACE_getVerts(f)[j], f);
+ _edge_remFace(FACE_getEdges(f)[j], f);
+ FACE_getVerts(f)[j]->flags |= Vert_eEffected;
+ }
+ _face_free(f, ss);
}
/***/
-CCGSubSurf *ccgSubSurf_new(CCGMeshIFC *ifc, int subdivLevels, CCGAllocatorIFC *allocatorIFC, CCGAllocatorHDL allocator)
+CCGSubSurf *ccgSubSurf_new(CCGMeshIFC *ifc,
+ int subdivLevels,
+ CCGAllocatorIFC *allocatorIFC,
+ CCGAllocatorHDL allocator)
{
- if (!allocatorIFC) {
- allocatorIFC = ccg_getStandardAllocatorIFC();
- allocator = NULL;
- }
+ if (!allocatorIFC) {
+ allocatorIFC = ccg_getStandardAllocatorIFC();
+ allocator = NULL;
+ }
- if (subdivLevels < 1) {
- return NULL;
- }
- else {
- CCGSubSurf *ss = allocatorIFC->alloc(allocator, sizeof(*ss));
+ if (subdivLevels < 1) {
+ return NULL;
+ }
+ else {
+ CCGSubSurf *ss = allocatorIFC->alloc(allocator, sizeof(*ss));
- ss->allocatorIFC = *allocatorIFC;
- ss->allocator = allocator;
+ ss->allocatorIFC = *allocatorIFC;
+ ss->allocator = allocator;
- ss->vMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator);
- ss->eMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator);
- ss->fMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator);
+ ss->vMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator);
+ ss->eMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator);
+ ss->fMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator);
- ss->meshIFC = *ifc;
+ ss->meshIFC = *ifc;
- ss->subdivLevels = subdivLevels;
- ss->numGrids = 0;
- ss->allowEdgeCreation = 0;
- ss->defaultCreaseValue = 0;
- ss->defaultEdgeUserData = NULL;
+ ss->subdivLevels = subdivLevels;
+ ss->numGrids = 0;
+ ss->allowEdgeCreation = 0;
+ ss->defaultCreaseValue = 0;
+ ss->defaultEdgeUserData = NULL;
- ss->useAgeCounts = 0;
- ss->vertUserAgeOffset = ss->edgeUserAgeOffset = ss->faceUserAgeOffset = 0;
+ ss->useAgeCounts = 0;
+ ss->vertUserAgeOffset = ss->edgeUserAgeOffset = ss->faceUserAgeOffset = 0;
- ss->calcVertNormals = 0;
- ss->normalDataOffset = 0;
+ ss->calcVertNormals = 0;
+ ss->normalDataOffset = 0;
- ss->allocMask = 0;
+ ss->allocMask = 0;
- ss->q = CCGSUBSURF_alloc(ss, ss->meshIFC.vertDataSize);
- ss->r = CCGSUBSURF_alloc(ss, ss->meshIFC.vertDataSize);
+ ss->q = CCGSUBSURF_alloc(ss, ss->meshIFC.vertDataSize);
+ ss->r = CCGSUBSURF_alloc(ss, ss->meshIFC.vertDataSize);
- ss->currentAge = 0;
+ ss->currentAge = 0;
- ss->syncState = eSyncState_None;
+ ss->syncState = eSyncState_None;
- ss->oldVMap = ss->oldEMap = ss->oldFMap = NULL;
- ss->lenTempArrays = 0;
- ss->tempVerts = NULL;
- ss->tempEdges = NULL;
+ ss->oldVMap = ss->oldEMap = ss->oldFMap = NULL;
+ ss->lenTempArrays = 0;
+ ss->tempVerts = NULL;
+ ss->tempEdges = NULL;
#ifdef WITH_OPENSUBDIV
- ss->osd_evaluator = NULL;
- ss->osd_mesh = NULL;
- ss->osd_topology_refiner = NULL;
- ss->osd_mesh_invalid = false;
- ss->osd_coarse_coords_invalid = false;
- ss->osd_vao = 0;
- ss->skip_grids = false;
- ss->osd_compute = 0;
- ss->osd_next_face_ptex_index = 0;
- ss->osd_coarse_coords = NULL;
- ss->osd_num_coarse_coords = 0;
- ss->osd_subdiv_uvs = false;
+ ss->osd_evaluator = NULL;
+ ss->osd_mesh = NULL;
+ ss->osd_topology_refiner = NULL;
+ ss->osd_mesh_invalid = false;
+ ss->osd_coarse_coords_invalid = false;
+ ss->osd_vao = 0;
+ ss->skip_grids = false;
+ ss->osd_compute = 0;
+ ss->osd_next_face_ptex_index = 0;
+ ss->osd_coarse_coords = NULL;
+ ss->osd_num_coarse_coords = 0;
+ ss->osd_subdiv_uvs = false;
#endif
- return ss;
- }
+ return ss;
+ }
}
void ccgSubSurf_free(CCGSubSurf *ss)
{
- CCGAllocatorIFC allocatorIFC = ss->allocatorIFC;
- CCGAllocatorHDL allocator = ss->allocator;
+ CCGAllocatorIFC allocatorIFC = ss->allocatorIFC;
+ CCGAllocatorHDL allocator = ss->allocator;
#ifdef WITH_OPENSUBDIV
- if (ss->osd_evaluator != NULL) {
- openSubdiv_deleteEvaluator(ss->osd_evaluator);
- }
- if (ss->osd_mesh != NULL) {
- ccgSubSurf__delete_osdGLMesh(ss->osd_mesh);
- }
- if (ss->osd_vao != 0) {
- ccgSubSurf__delete_vertex_array(ss->osd_vao);
- }
- if (ss->osd_coarse_coords != NULL) {
- MEM_freeN(ss->osd_coarse_coords);
- }
- if (ss->osd_topology_refiner != NULL) {
- openSubdiv_deleteTopologyRefiner(ss->osd_topology_refiner);
- }
+ if (ss->osd_evaluator != NULL) {
+ openSubdiv_deleteEvaluator(ss->osd_evaluator);
+ }
+ if (ss->osd_mesh != NULL) {
+ ccgSubSurf__delete_osdGLMesh(ss->osd_mesh);
+ }
+ if (ss->osd_vao != 0) {
+ ccgSubSurf__delete_vertex_array(ss->osd_vao);
+ }
+ if (ss->osd_coarse_coords != NULL) {
+ MEM_freeN(ss->osd_coarse_coords);
+ }
+ if (ss->osd_topology_refiner != NULL) {
+ openSubdiv_deleteTopologyRefiner(ss->osd_topology_refiner);
+ }
#endif
- if (ss->syncState) {
- ccg_ehash_free(ss->oldFMap, (EHEntryFreeFP) _face_free, ss);
- ccg_ehash_free(ss->oldEMap, (EHEntryFreeFP) _edge_free, ss);
- ccg_ehash_free(ss->oldVMap, (EHEntryFreeFP) _vert_free, ss);
+ if (ss->syncState) {
+ ccg_ehash_free(ss->oldFMap, (EHEntryFreeFP)_face_free, ss);
+ ccg_ehash_free(ss->oldEMap, (EHEntryFreeFP)_edge_free, ss);
+ ccg_ehash_free(ss->oldVMap, (EHEntryFreeFP)_vert_free, ss);
- MEM_freeN(ss->tempVerts);
- MEM_freeN(ss->tempEdges);
- }
+ MEM_freeN(ss->tempVerts);
+ MEM_freeN(ss->tempEdges);
+ }
- CCGSUBSURF_free(ss, ss->r);
- CCGSUBSURF_free(ss, ss->q);
- if (ss->defaultEdgeUserData) CCGSUBSURF_free(ss, ss->defaultEdgeUserData);
+ CCGSUBSURF_free(ss, ss->r);
+ CCGSUBSURF_free(ss, ss->q);
+ if (ss->defaultEdgeUserData)
+ CCGSUBSURF_free(ss, ss->defaultEdgeUserData);
- ccg_ehash_free(ss->fMap, (EHEntryFreeFP) _face_free, ss);
- ccg_ehash_free(ss->eMap, (EHEntryFreeFP) _edge_free, ss);
- ccg_ehash_free(ss->vMap, (EHEntryFreeFP) _vert_free, ss);
+ ccg_ehash_free(ss->fMap, (EHEntryFreeFP)_face_free, ss);
+ ccg_ehash_free(ss->eMap, (EHEntryFreeFP)_edge_free, ss);
+ ccg_ehash_free(ss->vMap, (EHEntryFreeFP)_vert_free, ss);
- CCGSUBSURF_free(ss, ss);
+ CCGSUBSURF_free(ss, ss);
- if (allocatorIFC.release) {
- allocatorIFC.release(allocator);
- }
+ if (allocatorIFC.release) {
+ allocatorIFC.release(allocator);
+ }
}
-CCGError ccgSubSurf_setAllowEdgeCreation(CCGSubSurf *ss, int allowEdgeCreation, float defaultCreaseValue, void *defaultUserData)
+CCGError ccgSubSurf_setAllowEdgeCreation(CCGSubSurf *ss,
+ int allowEdgeCreation,
+ float defaultCreaseValue,
+ void *defaultUserData)
{
- if (ss->defaultEdgeUserData) {
- CCGSUBSURF_free(ss, ss->defaultEdgeUserData);
- }
+ if (ss->defaultEdgeUserData) {
+ CCGSUBSURF_free(ss, ss->defaultEdgeUserData);
+ }
- ss->allowEdgeCreation = !!allowEdgeCreation;
- ss->defaultCreaseValue = defaultCreaseValue;
- ss->defaultEdgeUserData = CCGSUBSURF_alloc(ss, ss->meshIFC.edgeUserSize);
+ ss->allowEdgeCreation = !!allowEdgeCreation;
+ ss->defaultCreaseValue = defaultCreaseValue;
+ ss->defaultEdgeUserData = CCGSUBSURF_alloc(ss, ss->meshIFC.edgeUserSize);
- if (defaultUserData) {
- memcpy(ss->defaultEdgeUserData, defaultUserData, ss->meshIFC.edgeUserSize);
- }
- else {
- memset(ss->defaultEdgeUserData, 0, ss->meshIFC.edgeUserSize);
- }
+ if (defaultUserData) {
+ memcpy(ss->defaultEdgeUserData, defaultUserData, ss->meshIFC.edgeUserSize);
+ }
+ else {
+ memset(ss->defaultEdgeUserData, 0, ss->meshIFC.edgeUserSize);
+ }
- return eCCGError_None;
+ return eCCGError_None;
}
-void ccgSubSurf_getAllowEdgeCreation(CCGSubSurf *ss, int *allowEdgeCreation_r, float *defaultCreaseValue_r, void *defaultUserData_r)
+void ccgSubSurf_getAllowEdgeCreation(CCGSubSurf *ss,
+ int *allowEdgeCreation_r,
+ float *defaultCreaseValue_r,
+ void *defaultUserData_r)
{
- if (allowEdgeCreation_r) *allowEdgeCreation_r = ss->allowEdgeCreation;
- if (ss->allowEdgeCreation) {
- if (defaultCreaseValue_r) *defaultCreaseValue_r = ss->defaultCreaseValue;
- if (defaultUserData_r) memcpy(defaultUserData_r, ss->defaultEdgeUserData, ss->meshIFC.edgeUserSize);
- }
+ if (allowEdgeCreation_r)
+ *allowEdgeCreation_r = ss->allowEdgeCreation;
+ if (ss->allowEdgeCreation) {
+ if (defaultCreaseValue_r)
+ *defaultCreaseValue_r = ss->defaultCreaseValue;
+ if (defaultUserData_r)
+ memcpy(defaultUserData_r, ss->defaultEdgeUserData, ss->meshIFC.edgeUserSize);
+ }
}
CCGError ccgSubSurf_setSubdivisionLevels(CCGSubSurf *ss, int subdivisionLevels)
{
- if (subdivisionLevels <= 0) {
- return eCCGError_InvalidValue;
- }
- else if (subdivisionLevels != ss->subdivLevels) {
- ss->numGrids = 0;
- ss->subdivLevels = subdivisionLevels;
- ccg_ehash_free(ss->vMap, (EHEntryFreeFP) _vert_free, ss);
- ccg_ehash_free(ss->eMap, (EHEntryFreeFP) _edge_free, ss);
- ccg_ehash_free(ss->fMap, (EHEntryFreeFP) _face_free, ss);
- ss->vMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator);
- ss->eMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator);
- ss->fMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator);
- }
-
- return eCCGError_None;
-}
-
-void ccgSubSurf_getUseAgeCounts(CCGSubSurf *ss, int *useAgeCounts_r, int *vertUserOffset_r, int *edgeUserOffset_r, int *faceUserOffset_r)
-{
- *useAgeCounts_r = ss->useAgeCounts;
-
- if (vertUserOffset_r) *vertUserOffset_r = ss->vertUserAgeOffset;
- if (edgeUserOffset_r) *edgeUserOffset_r = ss->edgeUserAgeOffset;
- if (faceUserOffset_r) *faceUserOffset_r = ss->faceUserAgeOffset;
-}
-
-CCGError ccgSubSurf_setUseAgeCounts(CCGSubSurf *ss, int useAgeCounts, int vertUserOffset, int edgeUserOffset, int faceUserOffset)
-{
- if (useAgeCounts) {
- if ((vertUserOffset + 4 > ss->meshIFC.vertUserSize) ||
- (edgeUserOffset + 4 > ss->meshIFC.edgeUserSize) ||
- (faceUserOffset + 4 > ss->meshIFC.faceUserSize))
- {
- return eCCGError_InvalidValue;
- }
- else {
- ss->useAgeCounts = 1;
- ss->vertUserAgeOffset = vertUserOffset;
- ss->edgeUserAgeOffset = edgeUserOffset;
- ss->faceUserAgeOffset = faceUserOffset;
- }
- }
- else {
- ss->useAgeCounts = 0;
- ss->vertUserAgeOffset = ss->edgeUserAgeOffset = ss->faceUserAgeOffset = 0;
- }
-
- return eCCGError_None;
+ if (subdivisionLevels <= 0) {
+ return eCCGError_InvalidValue;
+ }
+ else if (subdivisionLevels != ss->subdivLevels) {
+ ss->numGrids = 0;
+ ss->subdivLevels = subdivisionLevels;
+ ccg_ehash_free(ss->vMap, (EHEntryFreeFP)_vert_free, ss);
+ ccg_ehash_free(ss->eMap, (EHEntryFreeFP)_edge_free, ss);
+ ccg_ehash_free(ss->fMap, (EHEntryFreeFP)_face_free, ss);
+ ss->vMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator);
+ ss->eMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator);
+ ss->fMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator);
+ }
+
+ return eCCGError_None;
+}
+
+void ccgSubSurf_getUseAgeCounts(CCGSubSurf *ss,
+ int *useAgeCounts_r,
+ int *vertUserOffset_r,
+ int *edgeUserOffset_r,
+ int *faceUserOffset_r)
+{
+ *useAgeCounts_r = ss->useAgeCounts;
+
+ if (vertUserOffset_r)
+ *vertUserOffset_r = ss->vertUserAgeOffset;
+ if (edgeUserOffset_r)
+ *edgeUserOffset_r = ss->edgeUserAgeOffset;
+ if (faceUserOffset_r)
+ *faceUserOffset_r = ss->faceUserAgeOffset;
+}
+
+CCGError ccgSubSurf_setUseAgeCounts(
+ CCGSubSurf *ss, int useAgeCounts, int vertUserOffset, int edgeUserOffset, int faceUserOffset)
+{
+ if (useAgeCounts) {
+ if ((vertUserOffset + 4 > ss->meshIFC.vertUserSize) ||
+ (edgeUserOffset + 4 > ss->meshIFC.edgeUserSize) ||
+ (faceUserOffset + 4 > ss->meshIFC.faceUserSize)) {
+ return eCCGError_InvalidValue;
+ }
+ else {
+ ss->useAgeCounts = 1;
+ ss->vertUserAgeOffset = vertUserOffset;
+ ss->edgeUserAgeOffset = edgeUserOffset;
+ ss->faceUserAgeOffset = faceUserOffset;
+ }
+ }
+ else {
+ ss->useAgeCounts = 0;
+ ss->vertUserAgeOffset = ss->edgeUserAgeOffset = ss->faceUserAgeOffset = 0;
+ }
+
+ return eCCGError_None;
}
CCGError ccgSubSurf_setCalcVertexNormals(CCGSubSurf *ss, int useVertNormals, int normalDataOffset)
{
- if (useVertNormals) {
- if (normalDataOffset < 0 || normalDataOffset + 12 > ss->meshIFC.vertDataSize) {
- return eCCGError_InvalidValue;
- }
- else {
- ss->calcVertNormals = 1;
- ss->normalDataOffset = normalDataOffset;
- }
- }
- else {
- ss->calcVertNormals = 0;
- ss->normalDataOffset = 0;
- }
+ if (useVertNormals) {
+ if (normalDataOffset < 0 || normalDataOffset + 12 > ss->meshIFC.vertDataSize) {
+ return eCCGError_InvalidValue;
+ }
+ else {
+ ss->calcVertNormals = 1;
+ ss->normalDataOffset = normalDataOffset;
+ }
+ }
+ else {
+ ss->calcVertNormals = 0;
+ ss->normalDataOffset = 0;
+ }
- return eCCGError_None;
+ return eCCGError_None;
}
void ccgSubSurf_setAllocMask(CCGSubSurf *ss, int allocMask, int maskOffset)
{
- ss->allocMask = allocMask;
- ss->maskDataOffset = maskOffset;
+ ss->allocMask = allocMask;
+ ss->maskDataOffset = maskOffset;
}
void ccgSubSurf_setNumLayers(CCGSubSurf *ss, int numLayers)
{
- ss->meshIFC.numLayers = numLayers;
+ ss->meshIFC.numLayers = numLayers;
}
/***/
CCGError ccgSubSurf_initFullSync(CCGSubSurf *ss)
{
- if (ss->syncState != eSyncState_None) {
- return eCCGError_InvalidSyncState;
- }
+ if (ss->syncState != eSyncState_None) {
+ return eCCGError_InvalidSyncState;
+ }
- ss->currentAge++;
+ ss->currentAge++;
- ss->oldVMap = ss->vMap;
- ss->oldEMap = ss->eMap;
- ss->oldFMap = ss->fMap;
+ ss->oldVMap = ss->vMap;
+ ss->oldEMap = ss->eMap;
+ ss->oldFMap = ss->fMap;
- ss->vMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator);
- ss->eMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator);
- ss->fMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator);
+ ss->vMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator);
+ ss->eMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator);
+ ss->fMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator);
- ss->numGrids = 0;
+ ss->numGrids = 0;
- ss->lenTempArrays = 12;
- ss->tempVerts = MEM_mallocN(sizeof(*ss->tempVerts) * ss->lenTempArrays, "CCGSubsurf tempVerts");
- ss->tempEdges = MEM_mallocN(sizeof(*ss->tempEdges) * ss->lenTempArrays, "CCGSubsurf tempEdges");
+ ss->lenTempArrays = 12;
+ ss->tempVerts = MEM_mallocN(sizeof(*ss->tempVerts) * ss->lenTempArrays, "CCGSubsurf tempVerts");
+ ss->tempEdges = MEM_mallocN(sizeof(*ss->tempEdges) * ss->lenTempArrays, "CCGSubsurf tempEdges");
- ss->syncState = eSyncState_Vert;
+ ss->syncState = eSyncState_Vert;
#ifdef WITH_OPENSUBDIV
- ss->osd_next_face_ptex_index = 0;
+ ss->osd_next_face_ptex_index = 0;
#endif
- return eCCGError_None;
+ return eCCGError_None;
}
CCGError ccgSubSurf_initPartialSync(CCGSubSurf *ss)
{
- if (ss->syncState != eSyncState_None) {
- return eCCGError_InvalidSyncState;
- }
+ if (ss->syncState != eSyncState_None) {
+ return eCCGError_InvalidSyncState;
+ }
- ss->currentAge++;
+ ss->currentAge++;
- ss->syncState = eSyncState_Partial;
+ ss->syncState = eSyncState_Partial;
- return eCCGError_None;
+ return eCCGError_None;
}
CCGError ccgSubSurf_syncVertDel(CCGSubSurf *ss, CCGVertHDL vHDL)
{
- if (ss->syncState != eSyncState_Partial) {
- return eCCGError_InvalidSyncState;
- }
- else {
- void **prevp;
- CCGVert *v = ccg_ehash_lookupWithPrev(ss->vMap, vHDL, &prevp);
+ if (ss->syncState != eSyncState_Partial) {
+ return eCCGError_InvalidSyncState;
+ }
+ else {
+ void **prevp;
+ CCGVert *v = ccg_ehash_lookupWithPrev(ss->vMap, vHDL, &prevp);
- if (!v || v->numFaces || v->numEdges) {
- return eCCGError_InvalidValue;
- }
- else {
- *prevp = v->next;
- _vert_free(v, ss);
- }
- }
+ if (!v || v->numFaces || v->numEdges) {
+ return eCCGError_InvalidValue;
+ }
+ else {
+ *prevp = v->next;
+ _vert_free(v, ss);
+ }
+ }
- return eCCGError_None;
+ return eCCGError_None;
}
CCGError ccgSubSurf_syncEdgeDel(CCGSubSurf *ss, CCGEdgeHDL eHDL)
{
- if (ss->syncState != eSyncState_Partial) {
- return eCCGError_InvalidSyncState;
- }
- else {
- void **prevp;
- CCGEdge *e = ccg_ehash_lookupWithPrev(ss->eMap, eHDL, &prevp);
+ if (ss->syncState != eSyncState_Partial) {
+ return eCCGError_InvalidSyncState;
+ }
+ else {
+ void **prevp;
+ CCGEdge *e = ccg_ehash_lookupWithPrev(ss->eMap, eHDL, &prevp);
- if (!e || e->numFaces) {
- return eCCGError_InvalidValue;
- }
- else {
- *prevp = e->next;
- _edge_unlinkMarkAndFree(e, ss);
- }
- }
+ if (!e || e->numFaces) {
+ return eCCGError_InvalidValue;
+ }
+ else {
+ *prevp = e->next;
+ _edge_unlinkMarkAndFree(e, ss);
+ }
+ }
- return eCCGError_None;
+ return eCCGError_None;
}
CCGError ccgSubSurf_syncFaceDel(CCGSubSurf *ss, CCGFaceHDL fHDL)
{
- if (ss->syncState != eSyncState_Partial) {
- return eCCGError_InvalidSyncState;
- }
- else {
- void **prevp;
- CCGFace *f = ccg_ehash_lookupWithPrev(ss->fMap, fHDL, &prevp);
-
- if (!f) {
- return eCCGError_InvalidValue;
- }
- else {
- *prevp = f->next;
- _face_unlinkMarkAndFree(f, ss);
- }
- }
-
- return eCCGError_None;
-}
-
-CCGError ccgSubSurf_syncVert(CCGSubSurf *ss, CCGVertHDL vHDL, const void *vertData, int seam, CCGVert **v_r)
-{
- void **prevp;
- CCGVert *v = NULL;
- short seamflag = (seam) ? Vert_eSeam : 0;
-
- if (ss->syncState == eSyncState_Partial) {
- v = ccg_ehash_lookupWithPrev(ss->vMap, vHDL, &prevp);
- if (!v) {
- v = _vert_new(vHDL, ss);
- VertDataCopy(ccg_vert_getCo(v, 0, ss->meshIFC.vertDataSize), vertData, ss);
- ccg_ehash_insert(ss->vMap, (EHEntry *) v);
- v->flags = Vert_eEffected | seamflag;
- }
- else if (!VertDataEqual(vertData, ccg_vert_getCo(v, 0, ss->meshIFC.vertDataSize), ss) ||
- ((v->flags & Vert_eSeam) != seamflag))
- {
- int i, j;
-
- VertDataCopy(ccg_vert_getCo(v, 0, ss->meshIFC.vertDataSize), vertData, ss);
- v->flags = Vert_eEffected | seamflag;
-
- for (i = 0; i < v->numEdges; i++) {
- CCGEdge *e = v->edges[i];
- e->v0->flags |= Vert_eEffected;
- e->v1->flags |= Vert_eEffected;
- }
- for (i = 0; i < v->numFaces; i++) {
- CCGFace *f = v->faces[i];
- for (j = 0; j < f->numVerts; j++) {
- FACE_getVerts(f)[j]->flags |= Vert_eEffected;
- }
- }
- }
- }
- else {
- if (ss->syncState != eSyncState_Vert) {
- return eCCGError_InvalidSyncState;
- }
-
- v = ccg_ehash_lookupWithPrev(ss->oldVMap, vHDL, &prevp);
- if (!v) {
- v = _vert_new(vHDL, ss);
- VertDataCopy(ccg_vert_getCo(v, 0, ss->meshIFC.vertDataSize), vertData, ss);
- ccg_ehash_insert(ss->vMap, (EHEntry *) v);
- v->flags = Vert_eEffected | seamflag;
- }
- else if (!VertDataEqual(vertData, ccg_vert_getCo(v, 0, ss->meshIFC.vertDataSize), ss) ||
- ((v->flags & Vert_eSeam) != seamflag))
- {
- *prevp = v->next;
- ccg_ehash_insert(ss->vMap, (EHEntry *) v);
- VertDataCopy(ccg_vert_getCo(v, 0, ss->meshIFC.vertDataSize), vertData, ss);
- v->flags = Vert_eEffected | Vert_eChanged | seamflag;
- }
- else {
- *prevp = v->next;
- ccg_ehash_insert(ss->vMap, (EHEntry *) v);
- v->flags = 0;
- }
+ if (ss->syncState != eSyncState_Partial) {
+ return eCCGError_InvalidSyncState;
+ }
+ else {
+ void **prevp;
+ CCGFace *f = ccg_ehash_lookupWithPrev(ss->fMap, fHDL, &prevp);
+
+ if (!f) {
+ return eCCGError_InvalidValue;
+ }
+ else {
+ *prevp = f->next;
+ _face_unlinkMarkAndFree(f, ss);
+ }
+ }
+
+ return eCCGError_None;
+}
+
+CCGError ccgSubSurf_syncVert(
+ CCGSubSurf *ss, CCGVertHDL vHDL, const void *vertData, int seam, CCGVert **v_r)
+{
+ void **prevp;
+ CCGVert *v = NULL;
+ short seamflag = (seam) ? Vert_eSeam : 0;
+
+ if (ss->syncState == eSyncState_Partial) {
+ v = ccg_ehash_lookupWithPrev(ss->vMap, vHDL, &prevp);
+ if (!v) {
+ v = _vert_new(vHDL, ss);
+ VertDataCopy(ccg_vert_getCo(v, 0, ss->meshIFC.vertDataSize), vertData, ss);
+ ccg_ehash_insert(ss->vMap, (EHEntry *)v);
+ v->flags = Vert_eEffected | seamflag;
+ }
+ else if (!VertDataEqual(vertData, ccg_vert_getCo(v, 0, ss->meshIFC.vertDataSize), ss) ||
+ ((v->flags & Vert_eSeam) != seamflag)) {
+ int i, j;
+
+ VertDataCopy(ccg_vert_getCo(v, 0, ss->meshIFC.vertDataSize), vertData, ss);
+ v->flags = Vert_eEffected | seamflag;
+
+ for (i = 0; i < v->numEdges; i++) {
+ CCGEdge *e = v->edges[i];
+ e->v0->flags |= Vert_eEffected;
+ e->v1->flags |= Vert_eEffected;
+ }
+ for (i = 0; i < v->numFaces; i++) {
+ CCGFace *f = v->faces[i];
+ for (j = 0; j < f->numVerts; j++) {
+ FACE_getVerts(f)[j]->flags |= Vert_eEffected;
+ }
+ }
+ }
+ }
+ else {
+ if (ss->syncState != eSyncState_Vert) {
+ return eCCGError_InvalidSyncState;
+ }
+
+ v = ccg_ehash_lookupWithPrev(ss->oldVMap, vHDL, &prevp);
+ if (!v) {
+ v = _vert_new(vHDL, ss);
+ VertDataCopy(ccg_vert_getCo(v, 0, ss->meshIFC.vertDataSize), vertData, ss);
+ ccg_ehash_insert(ss->vMap, (EHEntry *)v);
+ v->flags = Vert_eEffected | seamflag;
+ }
+ else if (!VertDataEqual(vertData, ccg_vert_getCo(v, 0, ss->meshIFC.vertDataSize), ss) ||
+ ((v->flags & Vert_eSeam) != seamflag)) {
+ *prevp = v->next;
+ ccg_ehash_insert(ss->vMap, (EHEntry *)v);
+ VertDataCopy(ccg_vert_getCo(v, 0, ss->meshIFC.vertDataSize), vertData, ss);
+ v->flags = Vert_eEffected | Vert_eChanged | seamflag;
+ }
+ else {
+ *prevp = v->next;
+ ccg_ehash_insert(ss->vMap, (EHEntry *)v);
+ v->flags = 0;
+ }
#ifdef WITH_OPENSUBDIV
- v->osd_index = ss->vMap->numEntries - 1;
+ v->osd_index = ss->vMap->numEntries - 1;
#endif
- }
-
- if (v_r) *v_r = v;
- return eCCGError_None;
-}
-
-CCGError ccgSubSurf_syncEdge(CCGSubSurf *ss, CCGEdgeHDL eHDL, CCGVertHDL e_vHDL0, CCGVertHDL e_vHDL1, float crease, CCGEdge **e_r)
-{
- void **prevp;
- CCGEdge *e = NULL, *eNew;
-
- if (ss->syncState == eSyncState_Partial) {
- e = ccg_ehash_lookupWithPrev(ss->eMap, eHDL, &prevp);
- if (!e || e->v0->vHDL != e_vHDL0 || e->v1->vHDL != e_vHDL1 || crease != e->crease) {
- CCGVert *v0 = ccg_ehash_lookup(ss->vMap, e_vHDL0);
- CCGVert *v1 = ccg_ehash_lookup(ss->vMap, e_vHDL1);
-
- eNew = _edge_new(eHDL, v0, v1, crease, ss);
-
- if (e) {
- *prevp = eNew;
- eNew->next = e->next;
-
- _edge_unlinkMarkAndFree(e, ss);
- }
- else {
- ccg_ehash_insert(ss->eMap, (EHEntry *) eNew);
- }
-
- eNew->v0->flags |= Vert_eEffected;
- eNew->v1->flags |= Vert_eEffected;
- }
- }
- else {
- if (ss->syncState == eSyncState_Vert) {
- ss->syncState = eSyncState_Edge;
- }
- else if (ss->syncState != eSyncState_Edge) {
- return eCCGError_InvalidSyncState;
- }
-
- e = ccg_ehash_lookupWithPrev(ss->oldEMap, eHDL, &prevp);
- if (!e || e->v0->vHDL != e_vHDL0 || e->v1->vHDL != e_vHDL1 || e->crease != crease) {
- CCGVert *v0 = ccg_ehash_lookup(ss->vMap, e_vHDL0);
- CCGVert *v1 = ccg_ehash_lookup(ss->vMap, e_vHDL1);
- e = _edge_new(eHDL, v0, v1, crease, ss);
- ccg_ehash_insert(ss->eMap, (EHEntry *) e);
- e->v0->flags |= Vert_eEffected;
- e->v1->flags |= Vert_eEffected;
- }
- else {
- *prevp = e->next;
- ccg_ehash_insert(ss->eMap, (EHEntry *) e);
- e->flags = 0;
- if ((e->v0->flags | e->v1->flags) & Vert_eChanged) {
- e->v0->flags |= Vert_eEffected;
- e->v1->flags |= Vert_eEffected;
- }
- }
- }
-
- if (e_r) *e_r = e;
- return eCCGError_None;
-}
-
-CCGError ccgSubSurf_syncFace(CCGSubSurf *ss, CCGFaceHDL fHDL, int numVerts, CCGVertHDL *vHDLs, CCGFace **f_r)
-{
- void **prevp;
- CCGFace *f = NULL, *fNew;
- int j, k, topologyChanged = 0;
-
- if (UNLIKELY(numVerts > ss->lenTempArrays)) {
- ss->lenTempArrays = (numVerts < ss->lenTempArrays * 2) ? ss->lenTempArrays * 2 : numVerts;
- ss->tempVerts = MEM_reallocN(ss->tempVerts, sizeof(*ss->tempVerts) * ss->lenTempArrays);
- ss->tempEdges = MEM_reallocN(ss->tempEdges, sizeof(*ss->tempEdges) * ss->lenTempArrays);
- }
-
- if (ss->syncState == eSyncState_Partial) {
- f = ccg_ehash_lookupWithPrev(ss->fMap, fHDL, &prevp);
-
- for (k = 0; k < numVerts; k++) {
- ss->tempVerts[k] = ccg_ehash_lookup(ss->vMap, vHDLs[k]);
- }
- for (k = 0; k < numVerts; k++) {
- ss->tempEdges[k] = _vert_findEdgeTo(ss->tempVerts[k], ss->tempVerts[(k + 1) % numVerts]);
- }
-
- if (f) {
- if (f->numVerts != numVerts ||
- memcmp(FACE_getVerts(f), ss->tempVerts, sizeof(*ss->tempVerts) * numVerts) ||
- memcmp(FACE_getEdges(f), ss->tempEdges, sizeof(*ss->tempEdges) * numVerts))
- {
- topologyChanged = 1;
- }
- }
-
- if (!f || topologyChanged) {
- fNew = _face_new(fHDL, ss->tempVerts, ss->tempEdges, numVerts, ss);
-
- if (f) {
- ss->numGrids += numVerts - f->numVerts;
-
- *prevp = fNew;
- fNew->next = f->next;
-
- _face_unlinkMarkAndFree(f, ss);
- }
- else {
- ss->numGrids += numVerts;
- ccg_ehash_insert(ss->fMap, (EHEntry *) fNew);
- }
-
- for (k = 0; k < numVerts; k++)
- FACE_getVerts(fNew)[k]->flags |= Vert_eEffected;
- }
- }
- else {
- if (ss->syncState == eSyncState_Vert || ss->syncState == eSyncState_Edge) {
- ss->syncState = eSyncState_Face;
- }
- else if (ss->syncState != eSyncState_Face) {
- return eCCGError_InvalidSyncState;
- }
-
- f = ccg_ehash_lookupWithPrev(ss->oldFMap, fHDL, &prevp);
-
- for (k = 0; k < numVerts; k++) {
- ss->tempVerts[k] = ccg_ehash_lookup(ss->vMap, vHDLs[k]);
-
- if (!ss->tempVerts[k])
- return eCCGError_InvalidValue;
- }
- for (k = 0; k < numVerts; k++) {
- ss->tempEdges[k] = _vert_findEdgeTo(ss->tempVerts[k], ss->tempVerts[(k + 1) % numVerts]);
-
- if (!ss->tempEdges[k]) {
- if (ss->allowEdgeCreation) {
- CCGEdge *e = ss->tempEdges[k] = _edge_new((CCGEdgeHDL) - 1, ss->tempVerts[k], ss->tempVerts[(k + 1) % numVerts], ss->defaultCreaseValue, ss);
- ccg_ehash_insert(ss->eMap, (EHEntry *) e);
- e->v0->flags |= Vert_eEffected;
- e->v1->flags |= Vert_eEffected;
- if (ss->meshIFC.edgeUserSize) {
- memcpy(ccgSubSurf_getEdgeUserData(ss, e), ss->defaultEdgeUserData, ss->meshIFC.edgeUserSize);
- }
- }
- else {
- return eCCGError_InvalidValue;
- }
- }
- }
-
- if (f) {
- if (f->numVerts != numVerts ||
- memcmp(FACE_getVerts(f), ss->tempVerts, sizeof(*ss->tempVerts) * numVerts) ||
- memcmp(FACE_getEdges(f), ss->tempEdges, sizeof(*ss->tempEdges) * numVerts))
- {
- topologyChanged = 1;
- }
- }
-
- if (!f || topologyChanged) {
- f = _face_new(fHDL, ss->tempVerts, ss->tempEdges, numVerts, ss);
- ccg_ehash_insert(ss->fMap, (EHEntry *) f);
- ss->numGrids += numVerts;
-
- for (k = 0; k < numVerts; k++)
- FACE_getVerts(f)[k]->flags |= Vert_eEffected;
- }
- else {
- *prevp = f->next;
- ccg_ehash_insert(ss->fMap, (EHEntry *) f);
- f->flags = 0;
- ss->numGrids += f->numVerts;
-
- for (j = 0; j < f->numVerts; j++) {
- if (FACE_getVerts(f)[j]->flags & Vert_eChanged) {
- for (k = 0; k < f->numVerts; k++)
- FACE_getVerts(f)[k]->flags |= Vert_eEffected;
- break;
- }
- }
- }
+ }
+
+ if (v_r)
+ *v_r = v;
+ return eCCGError_None;
+}
+
+CCGError ccgSubSurf_syncEdge(CCGSubSurf *ss,
+ CCGEdgeHDL eHDL,
+ CCGVertHDL e_vHDL0,
+ CCGVertHDL e_vHDL1,
+ float crease,
+ CCGEdge **e_r)
+{
+ void **prevp;
+ CCGEdge *e = NULL, *eNew;
+
+ if (ss->syncState == eSyncState_Partial) {
+ e = ccg_ehash_lookupWithPrev(ss->eMap, eHDL, &prevp);
+ if (!e || e->v0->vHDL != e_vHDL0 || e->v1->vHDL != e_vHDL1 || crease != e->crease) {
+ CCGVert *v0 = ccg_ehash_lookup(ss->vMap, e_vHDL0);
+ CCGVert *v1 = ccg_ehash_lookup(ss->vMap, e_vHDL1);
+
+ eNew = _edge_new(eHDL, v0, v1, crease, ss);
+
+ if (e) {
+ *prevp = eNew;
+ eNew->next = e->next;
+
+ _edge_unlinkMarkAndFree(e, ss);
+ }
+ else {
+ ccg_ehash_insert(ss->eMap, (EHEntry *)eNew);
+ }
+
+ eNew->v0->flags |= Vert_eEffected;
+ eNew->v1->flags |= Vert_eEffected;
+ }
+ }
+ else {
+ if (ss->syncState == eSyncState_Vert) {
+ ss->syncState = eSyncState_Edge;
+ }
+ else if (ss->syncState != eSyncState_Edge) {
+ return eCCGError_InvalidSyncState;
+ }
+
+ e = ccg_ehash_lookupWithPrev(ss->oldEMap, eHDL, &prevp);
+ if (!e || e->v0->vHDL != e_vHDL0 || e->v1->vHDL != e_vHDL1 || e->crease != crease) {
+ CCGVert *v0 = ccg_ehash_lookup(ss->vMap, e_vHDL0);
+ CCGVert *v1 = ccg_ehash_lookup(ss->vMap, e_vHDL1);
+ e = _edge_new(eHDL, v0, v1, crease, ss);
+ ccg_ehash_insert(ss->eMap, (EHEntry *)e);
+ e->v0->flags |= Vert_eEffected;
+ e->v1->flags |= Vert_eEffected;
+ }
+ else {
+ *prevp = e->next;
+ ccg_ehash_insert(ss->eMap, (EHEntry *)e);
+ e->flags = 0;
+ if ((e->v0->flags | e->v1->flags) & Vert_eChanged) {
+ e->v0->flags |= Vert_eEffected;
+ e->v1->flags |= Vert_eEffected;
+ }
+ }
+ }
+
+ if (e_r)
+ *e_r = e;
+ return eCCGError_None;
+}
+
+CCGError ccgSubSurf_syncFace(
+ CCGSubSurf *ss, CCGFaceHDL fHDL, int numVerts, CCGVertHDL *vHDLs, CCGFace **f_r)
+{
+ void **prevp;
+ CCGFace *f = NULL, *fNew;
+ int j, k, topologyChanged = 0;
+
+ if (UNLIKELY(numVerts > ss->lenTempArrays)) {
+ ss->lenTempArrays = (numVerts < ss->lenTempArrays * 2) ? ss->lenTempArrays * 2 : numVerts;
+ ss->tempVerts = MEM_reallocN(ss->tempVerts, sizeof(*ss->tempVerts) * ss->lenTempArrays);
+ ss->tempEdges = MEM_reallocN(ss->tempEdges, sizeof(*ss->tempEdges) * ss->lenTempArrays);
+ }
+
+ if (ss->syncState == eSyncState_Partial) {
+ f = ccg_ehash_lookupWithPrev(ss->fMap, fHDL, &prevp);
+
+ for (k = 0; k < numVerts; k++) {
+ ss->tempVerts[k] = ccg_ehash_lookup(ss->vMap, vHDLs[k]);
+ }
+ for (k = 0; k < numVerts; k++) {
+ ss->tempEdges[k] = _vert_findEdgeTo(ss->tempVerts[k], ss->tempVerts[(k + 1) % numVerts]);
+ }
+
+ if (f) {
+ if (f->numVerts != numVerts ||
+ memcmp(FACE_getVerts(f), ss->tempVerts, sizeof(*ss->tempVerts) * numVerts) ||
+ memcmp(FACE_getEdges(f), ss->tempEdges, sizeof(*ss->tempEdges) * numVerts)) {
+ topologyChanged = 1;
+ }
+ }
+
+ if (!f || topologyChanged) {
+ fNew = _face_new(fHDL, ss->tempVerts, ss->tempEdges, numVerts, ss);
+
+ if (f) {
+ ss->numGrids += numVerts - f->numVerts;
+
+ *prevp = fNew;
+ fNew->next = f->next;
+
+ _face_unlinkMarkAndFree(f, ss);
+ }
+ else {
+ ss->numGrids += numVerts;
+ ccg_ehash_insert(ss->fMap, (EHEntry *)fNew);
+ }
+
+ for (k = 0; k < numVerts; k++)
+ FACE_getVerts(fNew)[k]->flags |= Vert_eEffected;
+ }
+ }
+ else {
+ if (ss->syncState == eSyncState_Vert || ss->syncState == eSyncState_Edge) {
+ ss->syncState = eSyncState_Face;
+ }
+ else if (ss->syncState != eSyncState_Face) {
+ return eCCGError_InvalidSyncState;
+ }
+
+ f = ccg_ehash_lookupWithPrev(ss->oldFMap, fHDL, &prevp);
+
+ for (k = 0; k < numVerts; k++) {
+ ss->tempVerts[k] = ccg_ehash_lookup(ss->vMap, vHDLs[k]);
+
+ if (!ss->tempVerts[k])
+ return eCCGError_InvalidValue;
+ }
+ for (k = 0; k < numVerts; k++) {
+ ss->tempEdges[k] = _vert_findEdgeTo(ss->tempVerts[k], ss->tempVerts[(k + 1) % numVerts]);
+
+ if (!ss->tempEdges[k]) {
+ if (ss->allowEdgeCreation) {
+ CCGEdge *e = ss->tempEdges[k] = _edge_new((CCGEdgeHDL)-1,
+ ss->tempVerts[k],
+ ss->tempVerts[(k + 1) % numVerts],
+ ss->defaultCreaseValue,
+ ss);
+ ccg_ehash_insert(ss->eMap, (EHEntry *)e);
+ e->v0->flags |= Vert_eEffected;
+ e->v1->flags |= Vert_eEffected;
+ if (ss->meshIFC.edgeUserSize) {
+ memcpy(ccgSubSurf_getEdgeUserData(ss, e),
+ ss->defaultEdgeUserData,
+ ss->meshIFC.edgeUserSize);
+ }
+ }
+ else {
+ return eCCGError_InvalidValue;
+ }
+ }
+ }
+
+ if (f) {
+ if (f->numVerts != numVerts ||
+ memcmp(FACE_getVerts(f), ss->tempVerts, sizeof(*ss->tempVerts) * numVerts) ||
+ memcmp(FACE_getEdges(f), ss->tempEdges, sizeof(*ss->tempEdges) * numVerts)) {
+ topologyChanged = 1;
+ }
+ }
+
+ if (!f || topologyChanged) {
+ f = _face_new(fHDL, ss->tempVerts, ss->tempEdges, numVerts, ss);
+ ccg_ehash_insert(ss->fMap, (EHEntry *)f);
+ ss->numGrids += numVerts;
+
+ for (k = 0; k < numVerts; k++)
+ FACE_getVerts(f)[k]->flags |= Vert_eEffected;
+ }
+ else {
+ *prevp = f->next;
+ ccg_ehash_insert(ss->fMap, (EHEntry *)f);
+ f->flags = 0;
+ ss->numGrids += f->numVerts;
+
+ for (j = 0; j < f->numVerts; j++) {
+ if (FACE_getVerts(f)[j]->flags & Vert_eChanged) {
+ for (k = 0; k < f->numVerts; k++)
+ FACE_getVerts(f)[k]->flags |= Vert_eEffected;
+ break;
+ }
+ }
+ }
#ifdef WITH_OPENSUBDIV
- f->osd_index = ss->osd_next_face_ptex_index;
- if (numVerts == 4) {
- ss->osd_next_face_ptex_index++;
- }
- else {
- ss->osd_next_face_ptex_index += numVerts;
- }
+ f->osd_index = ss->osd_next_face_ptex_index;
+ if (numVerts == 4) {
+ ss->osd_next_face_ptex_index++;
+ }
+ else {
+ ss->osd_next_face_ptex_index += numVerts;
+ }
#endif
- }
+ }
- if (f_r) *f_r = f;
- return eCCGError_None;
+ if (f_r)
+ *f_r = f;
+ return eCCGError_None;
}
static void ccgSubSurf__sync(CCGSubSurf *ss)
{
#ifdef WITH_OPENSUBDIV
- if (ss->skip_grids) {
- ccgSubSurf__sync_opensubdiv(ss);
- }
- else
+ if (ss->skip_grids) {
+ ccgSubSurf__sync_opensubdiv(ss);
+ }
+ else
#endif
- {
- ccgSubSurf__sync_legacy(ss);
- }
+ {
+ ccgSubSurf__sync_legacy(ss);
+ }
}
CCGError ccgSubSurf_processSync(CCGSubSurf *ss)
{
- if (ss->syncState == eSyncState_Partial) {
- ss->syncState = eSyncState_None;
+ if (ss->syncState == eSyncState_Partial) {
+ ss->syncState = eSyncState_None;
- ccgSubSurf__sync(ss);
- }
- else if (ss->syncState) {
- ccg_ehash_free(ss->oldFMap, (EHEntryFreeFP) _face_unlinkMarkAndFree, ss);
- ccg_ehash_free(ss->oldEMap, (EHEntryFreeFP) _edge_unlinkMarkAndFree, ss);
- ccg_ehash_free(ss->oldVMap, (EHEntryFreeFP) _vert_free, ss);
- MEM_freeN(ss->tempEdges);
- MEM_freeN(ss->tempVerts);
+ ccgSubSurf__sync(ss);
+ }
+ else if (ss->syncState) {
+ ccg_ehash_free(ss->oldFMap, (EHEntryFreeFP)_face_unlinkMarkAndFree, ss);
+ ccg_ehash_free(ss->oldEMap, (EHEntryFreeFP)_edge_unlinkMarkAndFree, ss);
+ ccg_ehash_free(ss->oldVMap, (EHEntryFreeFP)_vert_free, ss);
+ MEM_freeN(ss->tempEdges);
+ MEM_freeN(ss->tempVerts);
- ss->lenTempArrays = 0;
+ ss->lenTempArrays = 0;
- ss->oldFMap = ss->oldEMap = ss->oldVMap = NULL;
- ss->tempVerts = NULL;
- ss->tempEdges = NULL;
+ ss->oldFMap = ss->oldEMap = ss->oldVMap = NULL;
+ ss->tempVerts = NULL;
+ ss->tempEdges = NULL;
- ss->syncState = eSyncState_None;
+ ss->syncState = eSyncState_None;
- ccgSubSurf__sync(ss);
- }
- else {
- return eCCGError_InvalidSyncState;
- }
+ ccgSubSurf__sync(ss);
+ }
+ else {
+ return eCCGError_InvalidSyncState;
+ }
- return eCCGError_None;
+ return eCCGError_None;
}
void ccgSubSurf__allFaces(CCGSubSurf *ss, CCGFace ***faces, int *numFaces, int *freeFaces)
{
- CCGFace **array;
- int i, num;
-
- if (*faces == NULL) {
- array = MEM_mallocN(sizeof(*array) * ss->fMap->numEntries, "CCGSubsurf allFaces");
- num = 0;
- for (i = 0; i < ss->fMap->curSize; i++) {
- CCGFace *f = (CCGFace *) ss->fMap->buckets[i];
-
- for (; f; f = f->next)
- array[num++] = f;
- }
-
- *faces = array;
- *numFaces = num;
- *freeFaces = 1;
- }
- else {
- *freeFaces = 0;
- }
-}
-
-void ccgSubSurf__effectedFaceNeighbours(CCGSubSurf *ss, CCGFace **faces, int numFaces, CCGVert ***verts, int *numVerts, CCGEdge ***edges, int *numEdges)
-{
- CCGVert **arrayV;
- CCGEdge **arrayE;
- int numV, numE, i, j;
-
- arrayV = MEM_mallocN(sizeof(*arrayV) * ss->vMap->numEntries, "CCGSubsurf arrayV");
- arrayE = MEM_mallocN(sizeof(*arrayE) * ss->eMap->numEntries, "CCGSubsurf arrayV");
- numV = numE = 0;
-
- for (i = 0; i < numFaces; i++) {
- CCGFace *f = faces[i];
- f->flags |= Face_eEffected;
- }
-
- for (i = 0; i < ss->vMap->curSize; i++) {
- CCGVert *v = (CCGVert *) ss->vMap->buckets[i];
-
- for (; v; v = v->next) {
- for (j = 0; j < v->numFaces; j++)
- if (!(v->faces[j]->flags & Face_eEffected))
- break;
-
- if (j == v->numFaces) {
- arrayV[numV++] = v;
- v->flags |= Vert_eEffected;
- }
- }
- }
-
- for (i = 0; i < ss->eMap->curSize; i++) {
- CCGEdge *e = (CCGEdge *) ss->eMap->buckets[i];
-
- for (; e; e = e->next) {
- for (j = 0; j < e->numFaces; j++)
- if (!(e->faces[j]->flags & Face_eEffected))
- break;
-
- if (j == e->numFaces) {
- e->flags |= Edge_eEffected;
- arrayE[numE++] = e;
- }
- }
- }
-
- *verts = arrayV;
- *numVerts = numV;
- *edges = arrayE;
- *numEdges = numE;
+ CCGFace **array;
+ int i, num;
+
+ if (*faces == NULL) {
+ array = MEM_mallocN(sizeof(*array) * ss->fMap->numEntries, "CCGSubsurf allFaces");
+ num = 0;
+ for (i = 0; i < ss->fMap->curSize; i++) {
+ CCGFace *f = (CCGFace *)ss->fMap->buckets[i];
+
+ for (; f; f = f->next)
+ array[num++] = f;
+ }
+
+ *faces = array;
+ *numFaces = num;
+ *freeFaces = 1;
+ }
+ else {
+ *freeFaces = 0;
+ }
+}
+
+void ccgSubSurf__effectedFaceNeighbours(CCGSubSurf *ss,
+ CCGFace **faces,
+ int numFaces,
+ CCGVert ***verts,
+ int *numVerts,
+ CCGEdge ***edges,
+ int *numEdges)
+{
+ CCGVert **arrayV;
+ CCGEdge **arrayE;
+ int numV, numE, i, j;
+
+ arrayV = MEM_mallocN(sizeof(*arrayV) * ss->vMap->numEntries, "CCGSubsurf arrayV");
+ arrayE = MEM_mallocN(sizeof(*arrayE) * ss->eMap->numEntries, "CCGSubsurf arrayV");
+ numV = numE = 0;
+
+ for (i = 0; i < numFaces; i++) {
+ CCGFace *f = faces[i];
+ f->flags |= Face_eEffected;
+ }
+
+ for (i = 0; i < ss->vMap->curSize; i++) {
+ CCGVert *v = (CCGVert *)ss->vMap->buckets[i];
+
+ for (; v; v = v->next) {
+ for (j = 0; j < v->numFaces; j++)
+ if (!(v->faces[j]->flags & Face_eEffected))
+ break;
+
+ if (j == v->numFaces) {
+ arrayV[numV++] = v;
+ v->flags |= Vert_eEffected;
+ }
+ }
+ }
+
+ for (i = 0; i < ss->eMap->curSize; i++) {
+ CCGEdge *e = (CCGEdge *)ss->eMap->buckets[i];
+
+ for (; e; e = e->next) {
+ for (j = 0; j < e->numFaces; j++)
+ if (!(e->faces[j]->flags & Face_eEffected))
+ break;
+
+ if (j == e->numFaces) {
+ e->flags |= Edge_eEffected;
+ arrayE[numE++] = e;
+ }
+ }
+ }
+
+ *verts = arrayV;
+ *numVerts = numV;
+ *edges = arrayE;
+ *numEdges = numE;
}
/* copy face grid coordinates to other places */
CCGError ccgSubSurf_updateFromFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF)
{
- int i, S, x, gridSize, cornerIdx, subdivLevels;
- int vertDataSize = ss->meshIFC.vertDataSize, freeF;
+ int i, S, x, gridSize, cornerIdx, subdivLevels;
+ int vertDataSize = ss->meshIFC.vertDataSize, freeF;
- subdivLevels = ss->subdivLevels;
- lvl = (lvl) ? lvl : subdivLevels;
- gridSize = ccg_gridsize(lvl);
- cornerIdx = gridSize - 1;
+ subdivLevels = ss->subdivLevels;
+ lvl = (lvl) ? lvl : subdivLevels;
+ gridSize = ccg_gridsize(lvl);
+ cornerIdx = gridSize - 1;
- ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF);
+ ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF);
- for (i = 0; i < numEffectedF; i++) {
- CCGFace *f = effectedF[i];
+ for (i = 0; i < numEffectedF; i++) {
+ CCGFace *f = effectedF[i];
- for (S = 0; S < f->numVerts; S++) {
- CCGEdge *e = FACE_getEdges(f)[S];
- CCGEdge *prevE = FACE_getEdges(f)[(S + f->numVerts - 1) % f->numVerts];
+ for (S = 0; S < f->numVerts; S++) {
+ CCGEdge *e = FACE_getEdges(f)[S];
+ CCGEdge *prevE = FACE_getEdges(f)[(S + f->numVerts - 1) % f->numVerts];
- VertDataCopy((float *)FACE_getCenterData(f), FACE_getIFCo(f, lvl, S, 0, 0), ss);
- VertDataCopy(VERT_getCo(FACE_getVerts(f)[S], lvl), FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx), ss);
+ VertDataCopy((float *)FACE_getCenterData(f), FACE_getIFCo(f, lvl, S, 0, 0), ss);
+ VertDataCopy(
+ VERT_getCo(FACE_getVerts(f)[S], lvl), FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx), ss);
- for (x = 0; x < gridSize; x++)
- VertDataCopy(FACE_getIECo(f, lvl, S, x), FACE_getIFCo(f, lvl, S, x, 0), ss);
+ for (x = 0; x < gridSize; x++)
+ VertDataCopy(FACE_getIECo(f, lvl, S, x), FACE_getIFCo(f, lvl, S, x, 0), ss);
- for (x = 0; x < gridSize; x++) {
- int eI = gridSize - 1 - x;
- VertDataCopy(_edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI, vertDataSize), FACE_getIFCo(f, lvl, S, cornerIdx, x), ss);
- VertDataCopy(_edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI, vertDataSize), FACE_getIFCo(f, lvl, S, x, cornerIdx), ss);
- }
- }
- }
+ for (x = 0; x < gridSize; x++) {
+ int eI = gridSize - 1 - x;
+ VertDataCopy(_edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI, vertDataSize),
+ FACE_getIFCo(f, lvl, S, cornerIdx, x),
+ ss);
+ VertDataCopy(_edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI, vertDataSize),
+ FACE_getIFCo(f, lvl, S, x, cornerIdx),
+ ss);
+ }
+ }
+ }
- if (freeF) MEM_freeN(effectedF);
+ if (freeF)
+ MEM_freeN(effectedF);
- return eCCGError_None;
+ return eCCGError_None;
}
/* copy other places to face grid coordinates */
CCGError ccgSubSurf_updateToFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF)
{
- int i, S, x, gridSize, cornerIdx, subdivLevels;
- int vertDataSize = ss->meshIFC.vertDataSize, freeF;
+ int i, S, x, gridSize, cornerIdx, subdivLevels;
+ int vertDataSize = ss->meshIFC.vertDataSize, freeF;
- subdivLevels = ss->subdivLevels;
- lvl = (lvl) ? lvl : subdivLevels;
- gridSize = ccg_gridsize(lvl);
- cornerIdx = gridSize - 1;
+ subdivLevels = ss->subdivLevels;
+ lvl = (lvl) ? lvl : subdivLevels;
+ gridSize = ccg_gridsize(lvl);
+ cornerIdx = gridSize - 1;
- ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF);
+ ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF);
- for (i = 0; i < numEffectedF; i++) {
- CCGFace *f = effectedF[i];
+ for (i = 0; i < numEffectedF; i++) {
+ CCGFace *f = effectedF[i];
- for (S = 0; S < f->numVerts; S++) {
- int prevS = (S + f->numVerts - 1) % f->numVerts;
- CCGEdge *e = FACE_getEdges(f)[S];
- CCGEdge *prevE = FACE_getEdges(f)[prevS];
+ for (S = 0; S < f->numVerts; S++) {
+ int prevS = (S + f->numVerts - 1) % f->numVerts;
+ CCGEdge *e = FACE_getEdges(f)[S];
+ CCGEdge *prevE = FACE_getEdges(f)[prevS];
- for (x = 0; x < gridSize; x++) {
- int eI = gridSize - 1 - x;
- VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, x), _edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI, vertDataSize), ss);
- VertDataCopy(FACE_getIFCo(f, lvl, S, x, cornerIdx), _edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI, vertDataSize), ss);
- }
+ for (x = 0; x < gridSize; x++) {
+ int eI = gridSize - 1 - x;
+ VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, x),
+ _edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI, vertDataSize),
+ ss);
+ VertDataCopy(FACE_getIFCo(f, lvl, S, x, cornerIdx),
+ _edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI, vertDataSize),
+ ss);
+ }
- for (x = 1; x < gridSize - 1; x++) {
- VertDataCopy(FACE_getIFCo(f, lvl, S, 0, x), FACE_getIECo(f, lvl, prevS, x), ss);
- VertDataCopy(FACE_getIFCo(f, lvl, S, x, 0), FACE_getIECo(f, lvl, S, x), ss);
- }
+ for (x = 1; x < gridSize - 1; x++) {
+ VertDataCopy(FACE_getIFCo(f, lvl, S, 0, x), FACE_getIECo(f, lvl, prevS, x), ss);
+ VertDataCopy(FACE_getIFCo(f, lvl, S, x, 0), FACE_getIECo(f, lvl, S, x), ss);
+ }
- VertDataCopy(FACE_getIFCo(f, lvl, S, 0, 0), (float *)FACE_getCenterData(f), ss);
- VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], lvl), ss);
- }
- }
+ VertDataCopy(FACE_getIFCo(f, lvl, S, 0, 0), (float *)FACE_getCenterData(f), ss);
+ VertDataCopy(
+ FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], lvl), ss);
+ }
+ }
- if (freeF) MEM_freeN(effectedF);
+ if (freeF)
+ MEM_freeN(effectedF);
- return eCCGError_None;
+ return eCCGError_None;
}
/* stitch together face grids, averaging coordinates at edges
* and vertices, for multires displacements */
CCGError ccgSubSurf_stitchFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF)
{
- CCGVert **effectedV;
- CCGEdge **effectedE;
- int numEffectedV, numEffectedE, freeF;
- int i, S, x, gridSize, cornerIdx, subdivLevels, edgeSize;
- int vertDataSize = ss->meshIFC.vertDataSize;
-
- subdivLevels = ss->subdivLevels;
- lvl = (lvl) ? lvl : subdivLevels;
- gridSize = ccg_gridsize(lvl);
- edgeSize = ccg_edgesize(lvl);
- cornerIdx = gridSize - 1;
-
- ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF);
- ccgSubSurf__effectedFaceNeighbours(ss, effectedF, numEffectedF,
- &effectedV, &numEffectedV, &effectedE, &numEffectedE);
-
- /* zero */
- for (i = 0; i < numEffectedV; i++) {
- CCGVert *v = effectedV[i];
- if (v->numFaces)
- VertDataZero(VERT_getCo(v, lvl), ss);
- }
-
- for (i = 0; i < numEffectedE; i++) {
- CCGEdge *e = effectedE[i];
-
- if (e->numFaces)
- for (x = 0; x < edgeSize; x++)
- VertDataZero(EDGE_getCo(e, lvl, x), ss);
- }
-
- /* add */
- for (i = 0; i < numEffectedF; i++) {
- CCGFace *f = effectedF[i];
-
- VertDataZero((float *)FACE_getCenterData(f), ss);
-
- for (S = 0; S < f->numVerts; S++)
- for (x = 0; x < gridSize; x++)
- VertDataZero(FACE_getIECo(f, lvl, S, x), ss);
-
- for (S = 0; S < f->numVerts; S++) {
- int prevS = (S + f->numVerts - 1) % f->numVerts;
- CCGEdge *e = FACE_getEdges(f)[S];
- CCGEdge *prevE = FACE_getEdges(f)[prevS];
-
- VertDataAdd((float *)FACE_getCenterData(f), FACE_getIFCo(f, lvl, S, 0, 0), ss);
- if (FACE_getVerts(f)[S]->flags & Vert_eEffected)
- VertDataAdd(VERT_getCo(FACE_getVerts(f)[S], lvl), FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx), ss);
-
- for (x = 1; x < gridSize - 1; x++) {
- VertDataAdd(FACE_getIECo(f, lvl, S, x), FACE_getIFCo(f, lvl, S, x, 0), ss);
- VertDataAdd(FACE_getIECo(f, lvl, prevS, x), FACE_getIFCo(f, lvl, S, 0, x), ss);
- }
-
- for (x = 0; x < gridSize - 1; x++) {
- int eI = gridSize - 1 - x;
- if (FACE_getEdges(f)[S]->flags & Edge_eEffected)
- VertDataAdd(_edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI, vertDataSize), FACE_getIFCo(f, lvl, S, cornerIdx, x), ss);
- if (FACE_getEdges(f)[prevS]->flags & Edge_eEffected)
- if (x != 0)
- VertDataAdd(_edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI, vertDataSize), FACE_getIFCo(f, lvl, S, x, cornerIdx), ss);
- }
- }
- }
-
- /* average */
- for (i = 0; i < numEffectedV; i++) {
- CCGVert *v = effectedV[i];
- if (v->numFaces)
- VertDataMulN(VERT_getCo(v, lvl), 1.0f / v->numFaces, ss);
- }
-
- for (i = 0; i < numEffectedE; i++) {
- CCGEdge *e = effectedE[i];
-
- VertDataCopy(EDGE_getCo(e, lvl, 0), VERT_getCo(e->v0, lvl), ss);
- VertDataCopy(EDGE_getCo(e, lvl, edgeSize - 1), VERT_getCo(e->v1, lvl), ss);
-
- if (e->numFaces)
- for (x = 1; x < edgeSize - 1; x++)
- VertDataMulN(EDGE_getCo(e, lvl, x), 1.0f / e->numFaces, ss);
- }
-
- /* copy */
- for (i = 0; i < numEffectedF; i++) {
- CCGFace *f = effectedF[i];
-
- VertDataMulN((float *)FACE_getCenterData(f), 1.0f / f->numVerts, ss);
-
- for (S = 0; S < f->numVerts; S++)
- for (x = 1; x < gridSize - 1; x++)
- VertDataMulN(FACE_getIECo(f, lvl, S, x), 0.5f, ss);
-
- for (S = 0; S < f->numVerts; S++) {
- int prevS = (S + f->numVerts - 1) % f->numVerts;
- CCGEdge *e = FACE_getEdges(f)[S];
- CCGEdge *prevE = FACE_getEdges(f)[prevS];
-
- VertDataCopy(FACE_getIFCo(f, lvl, S, 0, 0), (float *)FACE_getCenterData(f), ss);
- VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], lvl), ss);
-
- for (x = 1; x < gridSize - 1; x++) {
- VertDataCopy(FACE_getIFCo(f, lvl, S, x, 0), FACE_getIECo(f, lvl, S, x), ss);
- VertDataCopy(FACE_getIFCo(f, lvl, S, 0, x), FACE_getIECo(f, lvl, prevS, x), ss);
- }
-
- for (x = 0; x < gridSize - 1; x++) {
- int eI = gridSize - 1 - x;
-
- VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, x), _edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI, vertDataSize), ss);
- VertDataCopy(FACE_getIFCo(f, lvl, S, x, cornerIdx), _edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI, vertDataSize), ss);
- }
-
- VertDataCopy(FACE_getIECo(f, lvl, S, 0), (float *)FACE_getCenterData(f), ss);
- VertDataCopy(FACE_getIECo(f, lvl, S, gridSize - 1), FACE_getIFCo(f, lvl, S, gridSize - 1, 0), ss);
- }
- }
-
- for (i = 0; i < numEffectedV; i++)
- effectedV[i]->flags = 0;
- for (i = 0; i < numEffectedE; i++)
- effectedE[i]->flags = 0;
- for (i = 0; i < numEffectedF; i++)
- effectedF[i]->flags = 0;
-
- MEM_freeN(effectedE);
- MEM_freeN(effectedV);
- if (freeF) MEM_freeN(effectedF);
-
- return eCCGError_None;
+ CCGVert **effectedV;
+ CCGEdge **effectedE;
+ int numEffectedV, numEffectedE, freeF;
+ int i, S, x, gridSize, cornerIdx, subdivLevels, edgeSize;
+ int vertDataSize = ss->meshIFC.vertDataSize;
+
+ subdivLevels = ss->subdivLevels;
+ lvl = (lvl) ? lvl : subdivLevels;
+ gridSize = ccg_gridsize(lvl);
+ edgeSize = ccg_edgesize(lvl);
+ cornerIdx = gridSize - 1;
+
+ ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF);
+ ccgSubSurf__effectedFaceNeighbours(
+ ss, effectedF, numEffectedF, &effectedV, &numEffectedV, &effectedE, &numEffectedE);
+
+ /* zero */
+ for (i = 0; i < numEffectedV; i++) {
+ CCGVert *v = effectedV[i];
+ if (v->numFaces)
+ VertDataZero(VERT_getCo(v, lvl), ss);
+ }
+
+ for (i = 0; i < numEffectedE; i++) {
+ CCGEdge *e = effectedE[i];
+
+ if (e->numFaces)
+ for (x = 0; x < edgeSize; x++)
+ VertDataZero(EDGE_getCo(e, lvl, x), ss);
+ }
+
+ /* add */
+ for (i = 0; i < numEffectedF; i++) {
+ CCGFace *f = effectedF[i];
+
+ VertDataZero((float *)FACE_getCenterData(f), ss);
+
+ for (S = 0; S < f->numVerts; S++)
+ for (x = 0; x < gridSize; x++)
+ VertDataZero(FACE_getIECo(f, lvl, S, x), ss);
+
+ for (S = 0; S < f->numVerts; S++) {
+ int prevS = (S + f->numVerts - 1) % f->numVerts;
+ CCGEdge *e = FACE_getEdges(f)[S];
+ CCGEdge *prevE = FACE_getEdges(f)[prevS];
+
+ VertDataAdd((float *)FACE_getCenterData(f), FACE_getIFCo(f, lvl, S, 0, 0), ss);
+ if (FACE_getVerts(f)[S]->flags & Vert_eEffected)
+ VertDataAdd(VERT_getCo(FACE_getVerts(f)[S], lvl),
+ FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx),
+ ss);
+
+ for (x = 1; x < gridSize - 1; x++) {
+ VertDataAdd(FACE_getIECo(f, lvl, S, x), FACE_getIFCo(f, lvl, S, x, 0), ss);
+ VertDataAdd(FACE_getIECo(f, lvl, prevS, x), FACE_getIFCo(f, lvl, S, 0, x), ss);
+ }
+
+ for (x = 0; x < gridSize - 1; x++) {
+ int eI = gridSize - 1 - x;
+ if (FACE_getEdges(f)[S]->flags & Edge_eEffected)
+ VertDataAdd(_edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI, vertDataSize),
+ FACE_getIFCo(f, lvl, S, cornerIdx, x),
+ ss);
+ if (FACE_getEdges(f)[prevS]->flags & Edge_eEffected)
+ if (x != 0)
+ VertDataAdd(_edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI, vertDataSize),
+ FACE_getIFCo(f, lvl, S, x, cornerIdx),
+ ss);
+ }
+ }
+ }
+
+ /* average */
+ for (i = 0; i < numEffectedV; i++) {
+ CCGVert *v = effectedV[i];
+ if (v->numFaces)
+ VertDataMulN(VERT_getCo(v, lvl), 1.0f / v->numFaces, ss);
+ }
+
+ for (i = 0; i < numEffectedE; i++) {
+ CCGEdge *e = effectedE[i];
+
+ VertDataCopy(EDGE_getCo(e, lvl, 0), VERT_getCo(e->v0, lvl), ss);
+ VertDataCopy(EDGE_getCo(e, lvl, edgeSize - 1), VERT_getCo(e->v1, lvl), ss);
+
+ if (e->numFaces)
+ for (x = 1; x < edgeSize - 1; x++)
+ VertDataMulN(EDGE_getCo(e, lvl, x), 1.0f / e->numFaces, ss);
+ }
+
+ /* copy */
+ for (i = 0; i < numEffectedF; i++) {
+ CCGFace *f = effectedF[i];
+
+ VertDataMulN((float *)FACE_getCenterData(f), 1.0f / f->numVerts, ss);
+
+ for (S = 0; S < f->numVerts; S++)
+ for (x = 1; x < gridSize - 1; x++)
+ VertDataMulN(FACE_getIECo(f, lvl, S, x), 0.5f, ss);
+
+ for (S = 0; S < f->numVerts; S++) {
+ int prevS = (S + f->numVerts - 1) % f->numVerts;
+ CCGEdge *e = FACE_getEdges(f)[S];
+ CCGEdge *prevE = FACE_getEdges(f)[prevS];
+
+ VertDataCopy(FACE_getIFCo(f, lvl, S, 0, 0), (float *)FACE_getCenterData(f), ss);
+ VertDataCopy(
+ FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], lvl), ss);
+
+ for (x = 1; x < gridSize - 1; x++) {
+ VertDataCopy(FACE_getIFCo(f, lvl, S, x, 0), FACE_getIECo(f, lvl, S, x), ss);
+ VertDataCopy(FACE_getIFCo(f, lvl, S, 0, x), FACE_getIECo(f, lvl, prevS, x), ss);
+ }
+
+ for (x = 0; x < gridSize - 1; x++) {
+ int eI = gridSize - 1 - x;
+
+ VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, x),
+ _edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI, vertDataSize),
+ ss);
+ VertDataCopy(FACE_getIFCo(f, lvl, S, x, cornerIdx),
+ _edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI, vertDataSize),
+ ss);
+ }
+
+ VertDataCopy(FACE_getIECo(f, lvl, S, 0), (float *)FACE_getCenterData(f), ss);
+ VertDataCopy(
+ FACE_getIECo(f, lvl, S, gridSize - 1), FACE_getIFCo(f, lvl, S, gridSize - 1, 0), ss);
+ }
+ }
+
+ for (i = 0; i < numEffectedV; i++)
+ effectedV[i]->flags = 0;
+ for (i = 0; i < numEffectedE; i++)
+ effectedE[i]->flags = 0;
+ for (i = 0; i < numEffectedF; i++)
+ effectedF[i]->flags = 0;
+
+ MEM_freeN(effectedE);
+ MEM_freeN(effectedV);
+ if (freeF)
+ MEM_freeN(effectedF);
+
+ return eCCGError_None;
}
/*** External API accessor functions ***/
int ccgSubSurf_getNumVerts(const CCGSubSurf *ss)
{
- return ss->vMap->numEntries;
+ return ss->vMap->numEntries;
}
int ccgSubSurf_getNumEdges(const CCGSubSurf *ss)
{
- return ss->eMap->numEntries;
+ return ss->eMap->numEntries;
}
int ccgSubSurf_getNumFaces(const CCGSubSurf *ss)
{
- return ss->fMap->numEntries;
+ return ss->fMap->numEntries;
}
CCGVert *ccgSubSurf_getVert(CCGSubSurf *ss, CCGVertHDL v)
{
- return (CCGVert *) ccg_ehash_lookup(ss->vMap, v);
+ return (CCGVert *)ccg_ehash_lookup(ss->vMap, v);
}
CCGEdge *ccgSubSurf_getEdge(CCGSubSurf *ss, CCGEdgeHDL e)
{
- return (CCGEdge *) ccg_ehash_lookup(ss->eMap, e);
+ return (CCGEdge *)ccg_ehash_lookup(ss->eMap, e);
}
CCGFace *ccgSubSurf_getFace(CCGSubSurf *ss, CCGFaceHDL f)
{
- return (CCGFace *) ccg_ehash_lookup(ss->fMap, f);
+ return (CCGFace *)ccg_ehash_lookup(ss->fMap, f);
}
int ccgSubSurf_getSubdivisionLevels(const CCGSubSurf *ss)
{
- return ss->subdivLevels;
+ return ss->subdivLevels;
}
int ccgSubSurf_getEdgeSize(const CCGSubSurf *ss)
{
- return ccgSubSurf_getEdgeLevelSize(ss, ss->subdivLevels);
+ return ccgSubSurf_getEdgeLevelSize(ss, ss->subdivLevels);
}
int ccgSubSurf_getEdgeLevelSize(const CCGSubSurf *ss, int level)
{
- if (level < 1 || level > ss->subdivLevels) {
- return -1;
- }
- else {
- return ccg_edgesize(level);
- }
+ if (level < 1 || level > ss->subdivLevels) {
+ return -1;
+ }
+ else {
+ return ccg_edgesize(level);
+ }
}
int ccgSubSurf_getGridSize(const CCGSubSurf *ss)
{
- return ccgSubSurf_getGridLevelSize(ss, ss->subdivLevels);
+ return ccgSubSurf_getGridLevelSize(ss, ss->subdivLevels);
}
int ccgSubSurf_getGridLevelSize(const CCGSubSurf *ss, int level)
{
- if (level < 1 || level > ss->subdivLevels) {
- return -1;
- }
- else {
- return ccg_gridsize(level);
- }
+ if (level < 1 || level > ss->subdivLevels) {
+ return -1;
+ }
+ else {
+ return ccg_gridsize(level);
+ }
}
int ccgSubSurf_getSimpleSubdiv(const CCGSubSurf *ss)
{
- return ss->meshIFC.simpleSubdiv;
+ return ss->meshIFC.simpleSubdiv;
}
/* Vert accessors */
CCGVertHDL ccgSubSurf_getVertVertHandle(CCGVert *v)
{
- return v->vHDL;
+ return v->vHDL;
}
int ccgSubSurf_getVertAge(CCGSubSurf *ss, CCGVert *v)
{
- if (ss->useAgeCounts) {
- byte *userData = ccgSubSurf_getVertUserData(ss, v);
- return ss->currentAge - *((int *) &userData[ss->vertUserAgeOffset]);
- }
- else {
- return 0;
- }
+ if (ss->useAgeCounts) {
+ byte *userData = ccgSubSurf_getVertUserData(ss, v);
+ return ss->currentAge - *((int *)&userData[ss->vertUserAgeOffset]);
+ }
+ else {
+ return 0;
+ }
}
void *ccgSubSurf_getVertUserData(CCGSubSurf *ss, CCGVert *v)
{
- return VERT_getLevelData(v) + ss->meshIFC.vertDataSize * (ss->subdivLevels + 1);
+ return VERT_getLevelData(v) + ss->meshIFC.vertDataSize * (ss->subdivLevels + 1);
}
int ccgSubSurf_getVertNumFaces(CCGVert *v)
{
- return v->numFaces;
+ return v->numFaces;
}
CCGFace *ccgSubSurf_getVertFace(CCGVert *v, int index)
{
- if (index < 0 || index >= v->numFaces) {
- return NULL;
- }
- else {
- return v->faces[index];
- }
+ if (index < 0 || index >= v->numFaces) {
+ return NULL;
+ }
+ else {
+ return v->faces[index];
+ }
}
int ccgSubSurf_getVertNumEdges(CCGVert *v)
{
- return v->numEdges;
+ return v->numEdges;
}
CCGEdge *ccgSubSurf_getVertEdge(CCGVert *v, int index)
{
- if (index < 0 || index >= v->numEdges) {
- return NULL;
- }
- else {
- return v->edges[index];
- }
+ if (index < 0 || index >= v->numEdges) {
+ return NULL;
+ }
+ else {
+ return v->edges[index];
+ }
}
void *ccgSubSurf_getVertData(CCGSubSurf *ss, CCGVert *v)
{
- return ccgSubSurf_getVertLevelData(ss, v, ss->subdivLevels);
+ return ccgSubSurf_getVertLevelData(ss, v, ss->subdivLevels);
}
void *ccgSubSurf_getVertLevelData(CCGSubSurf *ss, CCGVert *v, int level)
{
- if (level < 0 || level > ss->subdivLevels) {
- return NULL;
- }
- else {
- return ccg_vert_getCo(v, level, ss->meshIFC.vertDataSize);
- }
+ if (level < 0 || level > ss->subdivLevels) {
+ return NULL;
+ }
+ else {
+ return ccg_vert_getCo(v, level, ss->meshIFC.vertDataSize);
+ }
}
/* Edge accessors */
CCGEdgeHDL ccgSubSurf_getEdgeEdgeHandle(CCGEdge *e)
{
- return e->eHDL;
+ return e->eHDL;
}
int ccgSubSurf_getEdgeAge(CCGSubSurf *ss, CCGEdge *e)
{
- if (ss->useAgeCounts) {
- byte *userData = ccgSubSurf_getEdgeUserData(ss, e);
- return ss->currentAge - *((int *) &userData[ss->edgeUserAgeOffset]);
- }
- else {
- return 0;
- }
+ if (ss->useAgeCounts) {
+ byte *userData = ccgSubSurf_getEdgeUserData(ss, e);
+ return ss->currentAge - *((int *)&userData[ss->edgeUserAgeOffset]);
+ }
+ else {
+ return 0;
+ }
}
void *ccgSubSurf_getEdgeUserData(CCGSubSurf *ss, CCGEdge *e)
{
- return (EDGE_getLevelData(e) +
- ss->meshIFC.vertDataSize * ccg_edgebase(ss->subdivLevels + 1));
+ return (EDGE_getLevelData(e) + ss->meshIFC.vertDataSize * ccg_edgebase(ss->subdivLevels + 1));
}
int ccgSubSurf_getEdgeNumFaces(CCGEdge *e)
{
- return e->numFaces;
+ return e->numFaces;
}
CCGFace *ccgSubSurf_getEdgeFace(CCGEdge *e, int index)
{
- if (index < 0 || index >= e->numFaces) {
- return NULL;
- }
- else {
- return e->faces[index];
- }
+ if (index < 0 || index >= e->numFaces) {
+ return NULL;
+ }
+ else {
+ return e->faces[index];
+ }
}
CCGVert *ccgSubSurf_getEdgeVert0(CCGEdge *e)
{
- return e->v0;
+ return e->v0;
}
CCGVert *ccgSubSurf_getEdgeVert1(CCGEdge *e)
{
- return e->v1;
+ return e->v1;
}
void *ccgSubSurf_getEdgeDataArray(CCGSubSurf *ss, CCGEdge *e)
{
- return ccgSubSurf_getEdgeData(ss, e, 0);
+ return ccgSubSurf_getEdgeData(ss, e, 0);
}
void *ccgSubSurf_getEdgeData(CCGSubSurf *ss, CCGEdge *e, int x)
{
- return ccgSubSurf_getEdgeLevelData(ss, e, x, ss->subdivLevels);
+ return ccgSubSurf_getEdgeLevelData(ss, e, x, ss->subdivLevels);
}
void *ccgSubSurf_getEdgeLevelData(CCGSubSurf *ss, CCGEdge *e, int x, int level)
{
- if (level < 0 || level > ss->subdivLevels) {
- return NULL;
- }
- else {
- return ccg_edge_getCo(e, level, x, ss->meshIFC.vertDataSize);
- }
+ if (level < 0 || level > ss->subdivLevels) {
+ return NULL;
+ }
+ else {
+ return ccg_edge_getCo(e, level, x, ss->meshIFC.vertDataSize);
+ }
}
float ccgSubSurf_getEdgeCrease(CCGEdge *e)
{
- return e->crease;
+ return e->crease;
}
/* Face accessors */
CCGFaceHDL ccgSubSurf_getFaceFaceHandle(CCGFace *f)
{
- return f->fHDL;
+ return f->fHDL;
}
int ccgSubSurf_getFaceAge(CCGSubSurf *ss, CCGFace *f)
{
- if (ss->useAgeCounts) {
- byte *userData = ccgSubSurf_getFaceUserData(ss, f);
- return ss->currentAge - *((int *) &userData[ss->faceUserAgeOffset]);
- }
- else {
- return 0;
- }
+ if (ss->useAgeCounts) {
+ byte *userData = ccgSubSurf_getFaceUserData(ss, f);
+ return ss->currentAge - *((int *)&userData[ss->faceUserAgeOffset]);
+ }
+ else {
+ return 0;
+ }
}
void *ccgSubSurf_getFaceUserData(CCGSubSurf *ss, CCGFace *f)
{
- int maxGridSize = ccg_gridsize(ss->subdivLevels);
- return FACE_getCenterData(f) + ss->meshIFC.vertDataSize * (1 + f->numVerts * maxGridSize + f->numVerts * maxGridSize * maxGridSize);
+ int maxGridSize = ccg_gridsize(ss->subdivLevels);
+ return FACE_getCenterData(f) +
+ ss->meshIFC.vertDataSize *
+ (1 + f->numVerts * maxGridSize + f->numVerts * maxGridSize * maxGridSize);
}
int ccgSubSurf_getFaceNumVerts(CCGFace *f)
{
- return f->numVerts;
+ return f->numVerts;
}
CCGVert *ccgSubSurf_getFaceVert(CCGFace *f, int index)
{
- if (index < 0 || index >= f->numVerts) {
- return NULL;
- }
- else {
- return FACE_getVerts(f)[index];
- }
+ if (index < 0 || index >= f->numVerts) {
+ return NULL;
+ }
+ else {
+ return FACE_getVerts(f)[index];
+ }
}
CCGEdge *ccgSubSurf_getFaceEdge(CCGFace *f, int index)
{
- if (index < 0 || index >= f->numVerts) {
- return NULL;
- }
- else {
- return FACE_getEdges(f)[index];
- }
+ if (index < 0 || index >= f->numVerts) {
+ return NULL;
+ }
+ else {
+ return FACE_getEdges(f)[index];
+ }
}
int ccgSubSurf_getFaceEdgeIndex(CCGFace *f, CCGEdge *e)
{
- int i;
+ int i;
- for (i = 0; i < f->numVerts; i++) {
- if (FACE_getEdges(f)[i] == e) {
- return i;
- }
- }
- return -1;
+ for (i = 0; i < f->numVerts; i++) {
+ if (FACE_getEdges(f)[i] == e) {
+ return i;
+ }
+ }
+ return -1;
}
void *ccgSubSurf_getFaceCenterData(CCGFace *f)
{
- return FACE_getCenterData(f);
+ return FACE_getCenterData(f);
}
void *ccgSubSurf_getFaceGridEdgeDataArray(CCGSubSurf *ss, CCGFace *f, int gridIndex)
{
- return ccgSubSurf_getFaceGridEdgeData(ss, f, gridIndex, 0);
+ return ccgSubSurf_getFaceGridEdgeData(ss, f, gridIndex, 0);
}
void *ccgSubSurf_getFaceGridEdgeData(CCGSubSurf *ss, CCGFace *f, int gridIndex, int x)
{
- return ccg_face_getIECo(f, ss->subdivLevels, gridIndex, x, ss->subdivLevels, ss->meshIFC.vertDataSize);
+ return ccg_face_getIECo(
+ f, ss->subdivLevels, gridIndex, x, ss->subdivLevels, ss->meshIFC.vertDataSize);
}
void *ccgSubSurf_getFaceGridDataArray(CCGSubSurf *ss, CCGFace *f, int gridIndex)
{
- return ccgSubSurf_getFaceGridData(ss, f, gridIndex, 0, 0);
+ return ccgSubSurf_getFaceGridData(ss, f, gridIndex, 0, 0);
}
void *ccgSubSurf_getFaceGridData(CCGSubSurf *ss, CCGFace *f, int gridIndex, int x, int y)
{
- return ccg_face_getIFCo(f, ss->subdivLevels, gridIndex, x, y, ss->subdivLevels, ss->meshIFC.vertDataSize);
+ return ccg_face_getIFCo(
+ f, ss->subdivLevels, gridIndex, x, y, ss->subdivLevels, ss->meshIFC.vertDataSize);
}
/*** External API iterator functions ***/
void ccgSubSurf_initVertIterator(CCGSubSurf *ss, CCGVertIterator *viter)
{
- ccg_ehashIterator_init(ss->vMap, viter);
+ ccg_ehashIterator_init(ss->vMap, viter);
}
void ccgSubSurf_initEdgeIterator(CCGSubSurf *ss, CCGEdgeIterator *eiter)
{
- ccg_ehashIterator_init(ss->eMap, eiter);
+ ccg_ehashIterator_init(ss->eMap, eiter);
}
void ccgSubSurf_initFaceIterator(CCGSubSurf *ss, CCGFaceIterator *fiter)
{
- ccg_ehashIterator_init(ss->fMap, fiter);
+ ccg_ehashIterator_init(ss->fMap, fiter);
}
CCGVert *ccgVertIterator_getCurrent(CCGVertIterator *vi)
{
- return (CCGVert *) ccg_ehashIterator_getCurrent((EHashIterator *) vi);
+ return (CCGVert *)ccg_ehashIterator_getCurrent((EHashIterator *)vi);
}
int ccgVertIterator_isStopped(CCGVertIterator *vi)
{
- return ccg_ehashIterator_isStopped((EHashIterator *) vi);
+ return ccg_ehashIterator_isStopped((EHashIterator *)vi);
}
void ccgVertIterator_next(CCGVertIterator *vi)
{
- ccg_ehashIterator_next((EHashIterator *) vi);
+ ccg_ehashIterator_next((EHashIterator *)vi);
}
CCGEdge *ccgEdgeIterator_getCurrent(CCGEdgeIterator *vi)
{
- return (CCGEdge *) ccg_ehashIterator_getCurrent((EHashIterator *) vi);
+ return (CCGEdge *)ccg_ehashIterator_getCurrent((EHashIterator *)vi);
}
int ccgEdgeIterator_isStopped(CCGEdgeIterator *vi)
{
- return ccg_ehashIterator_isStopped((EHashIterator *) vi);
+ return ccg_ehashIterator_isStopped((EHashIterator *)vi);
}
void ccgEdgeIterator_next(CCGEdgeIterator *vi)
{
- ccg_ehashIterator_next((EHashIterator *) vi);
+ ccg_ehashIterator_next((EHashIterator *)vi);
}
CCGFace *ccgFaceIterator_getCurrent(CCGFaceIterator *vi)
{
- return (CCGFace *) ccg_ehashIterator_getCurrent((EHashIterator *) vi);
+ return (CCGFace *)ccg_ehashIterator_getCurrent((EHashIterator *)vi);
}
int ccgFaceIterator_isStopped(CCGFaceIterator *vi)
{
- return ccg_ehashIterator_isStopped((EHashIterator *) vi);
+ return ccg_ehashIterator_isStopped((EHashIterator *)vi);
}
void ccgFaceIterator_next(CCGFaceIterator *vi)
{
- ccg_ehashIterator_next((EHashIterator *) vi);
+ ccg_ehashIterator_next((EHashIterator *)vi);
}
/*** Extern API final vert/edge/face interface ***/
int ccgSubSurf_getNumFinalVerts(const CCGSubSurf *ss)
{
- int edgeSize = ccg_edgesize(ss->subdivLevels);
- int gridSize = ccg_gridsize(ss->subdivLevels);
- int numFinalVerts = (ss->vMap->numEntries +
- ss->eMap->numEntries * (edgeSize - 2) +
- ss->fMap->numEntries +
- ss->numGrids * ((gridSize - 2) + ((gridSize - 2) * (gridSize - 2))));
+ int edgeSize = ccg_edgesize(ss->subdivLevels);
+ int gridSize = ccg_gridsize(ss->subdivLevels);
+ int numFinalVerts = (ss->vMap->numEntries + ss->eMap->numEntries * (edgeSize - 2) +
+ ss->fMap->numEntries +
+ ss->numGrids * ((gridSize - 2) + ((gridSize - 2) * (gridSize - 2))));
#ifdef WITH_OPENSUBDIV
- if (ss->skip_grids) {
- return 0;
- }
+ if (ss->skip_grids) {
+ return 0;
+ }
#endif
- return numFinalVerts;
+ return numFinalVerts;
}
int ccgSubSurf_getNumFinalEdges(const CCGSubSurf *ss)
{
- int edgeSize = ccg_edgesize(ss->subdivLevels);
- int gridSize = ccg_gridsize(ss->subdivLevels);
- int numFinalEdges = (ss->eMap->numEntries * (edgeSize - 1) +
- ss->numGrids * ((gridSize - 1) + 2 * ((gridSize - 2) * (gridSize - 1))));
+ int edgeSize = ccg_edgesize(ss->subdivLevels);
+ int gridSize = ccg_gridsize(ss->subdivLevels);
+ int numFinalEdges = (ss->eMap->numEntries * (edgeSize - 1) +
+ ss->numGrids * ((gridSize - 1) + 2 * ((gridSize - 2) * (gridSize - 1))));
#ifdef WITH_OPENSUBDIV
- if (ss->skip_grids) {
- return 0;
- }
+ if (ss->skip_grids) {
+ return 0;
+ }
#endif
- return numFinalEdges;
+ return numFinalEdges;
}
int ccgSubSurf_getNumFinalFaces(const CCGSubSurf *ss)
{
- int gridSize = ccg_gridsize(ss->subdivLevels);
- int numFinalFaces = ss->numGrids * ((gridSize - 1) * (gridSize - 1));
+ int gridSize = ccg_gridsize(ss->subdivLevels);
+ int numFinalFaces = ss->numGrids * ((gridSize - 1) * (gridSize - 1));
#ifdef WITH_OPENSUBDIV
- if (ss->skip_grids) {
- return 0;
- }
+ if (ss->skip_grids) {
+ return 0;
+ }
#endif
- return numFinalFaces;
+ return numFinalFaces;
}
/***/
void CCG_key(CCGKey *key, const CCGSubSurf *ss, int level)
{
- key->level = level;
+ key->level = level;
- key->elem_size = ss->meshIFC.vertDataSize;
- key->has_normals = ss->calcVertNormals;
+ key->elem_size = ss->meshIFC.vertDataSize;
+ key->has_normals = ss->calcVertNormals;
- /* if normals are present, always the last three floats of an
- * element */
- if (key->has_normals)
- key->normal_offset = key->elem_size - sizeof(float) * 3;
- else
- key->normal_offset = -1;
+ /* if normals are present, always the last three floats of an
+ * element */
+ if (key->has_normals)
+ key->normal_offset = key->elem_size - sizeof(float) * 3;
+ else
+ key->normal_offset = -1;
- key->grid_size = ccgSubSurf_getGridLevelSize(ss, level);
- key->grid_area = key->grid_size * key->grid_size;
- key->grid_bytes = key->elem_size * key->grid_area;
+ key->grid_size = ccgSubSurf_getGridLevelSize(ss, level);
+ key->grid_area = key->grid_size * key->grid_size;
+ key->grid_bytes = key->elem_size * key->grid_area;
- key->has_mask = ss->allocMask;
- if (key->has_mask)
- key->mask_offset = ss->maskDataOffset;
- else
- key->mask_offset = -1;
+ key->has_mask = ss->allocMask;
+ if (key->has_mask)
+ key->mask_offset = ss->maskDataOffset;
+ else
+ key->mask_offset = -1;
}
void CCG_key_top_level(CCGKey *key, const CCGSubSurf *ss)
{
- CCG_key(key, ss, ccgSubSurf_getSubdivisionLevels(ss));
+ CCG_key(key, ss, ccgSubSurf_getSubdivisionLevels(ss));
}
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.h b/source/blender/blenkernel/intern/CCGSubSurf.h
index 8ce5099305c..83b59941ac7 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf.h
+++ b/source/blender/blenkernel/intern/CCGSubSurf.h
@@ -32,10 +32,10 @@ typedef struct CCGSubSurf CCGSubSurf;
typedef struct CCGVert CCGVert;
typedef struct CCGMeshIFC {
- int vertUserSize, edgeUserSize, faceUserSize;
- int numLayers;
- int vertDataSize;
- int simpleSubdiv;
+ int vertUserSize, edgeUserSize, faceUserSize;
+ int numLayers;
+ int vertDataSize;
+ int simpleSubdiv;
} CCGMeshIFC;
/***/
@@ -43,26 +43,26 @@ typedef struct CCGMeshIFC {
typedef void *CCGAllocatorHDL;
typedef struct CCGAllocatorIFC {
- void* (*alloc) (CCGAllocatorHDL a, int numBytes);
- void* (*realloc) (CCGAllocatorHDL a, void *ptr, int newSize, int oldSize);
- void (*free) (CCGAllocatorHDL a, void *ptr);
- void (*release) (CCGAllocatorHDL a);
+ void *(*alloc)(CCGAllocatorHDL a, int numBytes);
+ void *(*realloc)(CCGAllocatorHDL a, void *ptr, int newSize, int oldSize);
+ void (*free)(CCGAllocatorHDL a, void *ptr);
+ void (*release)(CCGAllocatorHDL a);
} CCGAllocatorIFC;
/* private, so we can allocate on the stack */
typedef struct _EHashIterator {
- struct _EHash *eh;
- int curBucket;
- struct _EHEntry *curEntry;
+ struct _EHash *eh;
+ int curBucket;
+ struct _EHEntry *curEntry;
} EHashIterator;
/***/
typedef enum {
- eCCGError_None = 0,
+ eCCGError_None = 0,
- eCCGError_InvalidSyncState,
- eCCGError_InvalidValue,
+ eCCGError_InvalidSyncState,
+ eCCGError_InvalidValue,
} CCGError;
/***/
@@ -72,101 +72,122 @@ typedef enum {
/***/
-CCGSubSurf* ccgSubSurf_new (CCGMeshIFC *ifc, int subdivisionLevels, CCGAllocatorIFC *allocatorIFC, CCGAllocatorHDL allocator);
-void ccgSubSurf_free (CCGSubSurf *ss);
+CCGSubSurf *ccgSubSurf_new(CCGMeshIFC *ifc,
+ int subdivisionLevels,
+ CCGAllocatorIFC *allocatorIFC,
+ CCGAllocatorHDL allocator);
+void ccgSubSurf_free(CCGSubSurf *ss);
-CCGError ccgSubSurf_initFullSync (CCGSubSurf *ss);
-CCGError ccgSubSurf_initPartialSync (CCGSubSurf *ss);
+CCGError ccgSubSurf_initFullSync(CCGSubSurf *ss);
+CCGError ccgSubSurf_initPartialSync(CCGSubSurf *ss);
#ifdef WITH_OPENSUBDIV
-CCGError ccgSubSurf_initOpenSubdivSync (CCGSubSurf *ss);
+CCGError ccgSubSurf_initOpenSubdivSync(CCGSubSurf *ss);
#endif
-CCGError ccgSubSurf_syncVert (CCGSubSurf *ss, CCGVertHDL vHDL, const void *vertData, int seam, CCGVert **v_r);
-CCGError ccgSubSurf_syncEdge (CCGSubSurf *ss, CCGEdgeHDL eHDL, CCGVertHDL e_vHDL0, CCGVertHDL e_vHDL1, float crease, CCGEdge **e_r);
-CCGError ccgSubSurf_syncFace (CCGSubSurf *ss, CCGFaceHDL fHDL, int numVerts, CCGVertHDL *vHDLs, CCGFace **f_r);
-
-CCGError ccgSubSurf_syncVertDel (CCGSubSurf *ss, CCGVertHDL vHDL);
-CCGError ccgSubSurf_syncEdgeDel (CCGSubSurf *ss, CCGEdgeHDL eHDL);
-CCGError ccgSubSurf_syncFaceDel (CCGSubSurf *ss, CCGFaceHDL fHDL);
-
-CCGError ccgSubSurf_processSync (CCGSubSurf *ss);
-
-CCGError ccgSubSurf_updateFromFaces(CCGSubSurf *ss, int lvl, CCGFace **faces, int numFaces);
-CCGError ccgSubSurf_updateToFaces(CCGSubSurf *ss, int lvl, CCGFace **faces, int numFaces);
-CCGError ccgSubSurf_updateNormals(CCGSubSurf *ss, CCGFace **faces, int numFaces);
-CCGError ccgSubSurf_updateLevels(CCGSubSurf *ss, int lvl, CCGFace **faces, int numFaces);
-CCGError ccgSubSurf_stitchFaces(CCGSubSurf *ss, int lvl, CCGFace **faces, int numFaces);
-
-CCGError ccgSubSurf_setSubdivisionLevels (CCGSubSurf *ss, int subdivisionLevels);
-
-CCGError ccgSubSurf_setAllowEdgeCreation (CCGSubSurf *ss, int allowEdgeCreation, float defaultCreaseValue, void *defaultUserData);
-void ccgSubSurf_getAllowEdgeCreation (CCGSubSurf *ss, int *allowEdgeCreation_r, float *defaultCreaseValue_r, void *defaultUserData_r);
-
-void ccgSubSurf_getUseAgeCounts (CCGSubSurf *ss, int *useAgeCounts_r, int *vertUserOffset_r, int *edgeUserOffset_r, int *faceUserOffset_r);
-CCGError ccgSubSurf_setUseAgeCounts (CCGSubSurf *ss, int useAgeCounts, int vertUserOffset, int edgeUserOffset, int faceUserOffset);
-
-CCGError ccgSubSurf_setCalcVertexNormals (CCGSubSurf *ss, int useVertNormals, int normalDataOffset);
-void ccgSubSurf_setAllocMask (CCGSubSurf *ss, int allocMask, int maskOffset);
-
-void ccgSubSurf_setNumLayers (CCGSubSurf *ss, int numLayers);
+CCGError ccgSubSurf_syncVert(
+ CCGSubSurf *ss, CCGVertHDL vHDL, const void *vertData, int seam, CCGVert **v_r);
+CCGError ccgSubSurf_syncEdge(CCGSubSurf *ss,
+ CCGEdgeHDL eHDL,
+ CCGVertHDL e_vHDL0,
+ CCGVertHDL e_vHDL1,
+ float crease,
+ CCGEdge **e_r);
+CCGError ccgSubSurf_syncFace(
+ CCGSubSurf *ss, CCGFaceHDL fHDL, int numVerts, CCGVertHDL *vHDLs, CCGFace **f_r);
+
+CCGError ccgSubSurf_syncVertDel(CCGSubSurf *ss, CCGVertHDL vHDL);
+CCGError ccgSubSurf_syncEdgeDel(CCGSubSurf *ss, CCGEdgeHDL eHDL);
+CCGError ccgSubSurf_syncFaceDel(CCGSubSurf *ss, CCGFaceHDL fHDL);
+
+CCGError ccgSubSurf_processSync(CCGSubSurf *ss);
+
+CCGError ccgSubSurf_updateFromFaces(CCGSubSurf *ss, int lvl, CCGFace **faces, int numFaces);
+CCGError ccgSubSurf_updateToFaces(CCGSubSurf *ss, int lvl, CCGFace **faces, int numFaces);
+CCGError ccgSubSurf_updateNormals(CCGSubSurf *ss, CCGFace **faces, int numFaces);
+CCGError ccgSubSurf_updateLevels(CCGSubSurf *ss, int lvl, CCGFace **faces, int numFaces);
+CCGError ccgSubSurf_stitchFaces(CCGSubSurf *ss, int lvl, CCGFace **faces, int numFaces);
+
+CCGError ccgSubSurf_setSubdivisionLevels(CCGSubSurf *ss, int subdivisionLevels);
+
+CCGError ccgSubSurf_setAllowEdgeCreation(CCGSubSurf *ss,
+ int allowEdgeCreation,
+ float defaultCreaseValue,
+ void *defaultUserData);
+void ccgSubSurf_getAllowEdgeCreation(CCGSubSurf *ss,
+ int *allowEdgeCreation_r,
+ float *defaultCreaseValue_r,
+ void *defaultUserData_r);
+
+void ccgSubSurf_getUseAgeCounts(CCGSubSurf *ss,
+ int *useAgeCounts_r,
+ int *vertUserOffset_r,
+ int *edgeUserOffset_r,
+ int *faceUserOffset_r);
+CCGError ccgSubSurf_setUseAgeCounts(
+ CCGSubSurf *ss, int useAgeCounts, int vertUserOffset, int edgeUserOffset, int faceUserOffset);
+
+CCGError ccgSubSurf_setCalcVertexNormals(CCGSubSurf *ss, int useVertNormals, int normalDataOffset);
+void ccgSubSurf_setAllocMask(CCGSubSurf *ss, int allocMask, int maskOffset);
+
+void ccgSubSurf_setNumLayers(CCGSubSurf *ss, int numLayers);
/***/
-int ccgSubSurf_getNumVerts (const CCGSubSurf *ss);
-int ccgSubSurf_getNumEdges (const CCGSubSurf *ss);
-int ccgSubSurf_getNumFaces (const CCGSubSurf *ss);
-
-int ccgSubSurf_getSubdivisionLevels (const CCGSubSurf *ss);
-int ccgSubSurf_getEdgeSize (const CCGSubSurf *ss);
-int ccgSubSurf_getEdgeLevelSize (const CCGSubSurf *ss, int level);
-int ccgSubSurf_getGridSize (const CCGSubSurf *ss);
-int ccgSubSurf_getGridLevelSize (const CCGSubSurf *ss, int level);
-int ccgSubSurf_getSimpleSubdiv (const CCGSubSurf *ss);
-
-CCGVert* ccgSubSurf_getVert (CCGSubSurf *ss, CCGVertHDL v);
-CCGVertHDL ccgSubSurf_getVertVertHandle (CCGVert *v);
-int ccgSubSurf_getVertNumFaces (CCGVert *v);
-CCGFace* ccgSubSurf_getVertFace (CCGVert *v, int index);
-int ccgSubSurf_getVertNumEdges (CCGVert *v);
-CCGEdge* ccgSubSurf_getVertEdge (CCGVert *v, int index);
-
-int ccgSubSurf_getVertAge (CCGSubSurf *ss, CCGVert *v);
-void* ccgSubSurf_getVertUserData (CCGSubSurf *ss, CCGVert *v);
-void* ccgSubSurf_getVertData (CCGSubSurf *ss, CCGVert *v);
-void* ccgSubSurf_getVertLevelData (CCGSubSurf *ss, CCGVert *v, int level);
-
-CCGEdge* ccgSubSurf_getEdge (CCGSubSurf *ss, CCGEdgeHDL e);
-CCGEdgeHDL ccgSubSurf_getEdgeEdgeHandle (CCGEdge *e);
-int ccgSubSurf_getEdgeNumFaces (CCGEdge *e);
-CCGFace* ccgSubSurf_getEdgeFace (CCGEdge *e, int index);
-CCGVert* ccgSubSurf_getEdgeVert0 (CCGEdge *e);
-CCGVert* ccgSubSurf_getEdgeVert1 (CCGEdge *e);
-float ccgSubSurf_getEdgeCrease (CCGEdge *e);
-
-int ccgSubSurf_getEdgeAge (CCGSubSurf *ss, CCGEdge *e);
-void* ccgSubSurf_getEdgeUserData (CCGSubSurf *ss, CCGEdge *e);
-void* ccgSubSurf_getEdgeDataArray (CCGSubSurf *ss, CCGEdge *e);
-void* ccgSubSurf_getEdgeData (CCGSubSurf *ss, CCGEdge *e, int x);
-void* ccgSubSurf_getEdgeLevelData (CCGSubSurf *ss, CCGEdge *e, int x, int level);
-
-CCGFace* ccgSubSurf_getFace (CCGSubSurf *ss, CCGFaceHDL f);
-CCGFaceHDL ccgSubSurf_getFaceFaceHandle (CCGFace *f);
-int ccgSubSurf_getFaceNumVerts (CCGFace *f);
-CCGVert* ccgSubSurf_getFaceVert (CCGFace *f, int index);
-CCGEdge* ccgSubSurf_getFaceEdge (CCGFace *f, int index);
-int ccgSubSurf_getFaceEdgeIndex (CCGFace *f, CCGEdge *e);
-
-int ccgSubSurf_getFaceAge (CCGSubSurf *ss, CCGFace *f);
-void* ccgSubSurf_getFaceUserData (CCGSubSurf *ss, CCGFace *f);
-void* ccgSubSurf_getFaceCenterData (CCGFace *f);
-void* ccgSubSurf_getFaceGridEdgeDataArray (CCGSubSurf *ss, CCGFace *f, int gridIndex);
-void* ccgSubSurf_getFaceGridEdgeData (CCGSubSurf *ss, CCGFace *f, int gridIndex, int x);
-void* ccgSubSurf_getFaceGridDataArray (CCGSubSurf *ss, CCGFace *f, int gridIndex);
-void* ccgSubSurf_getFaceGridData (CCGSubSurf *ss, CCGFace *f, int gridIndex, int x, int y);
-
-int ccgSubSurf_getNumFinalVerts (const CCGSubSurf *ss);
-int ccgSubSurf_getNumFinalEdges (const CCGSubSurf *ss);
-int ccgSubSurf_getNumFinalFaces (const CCGSubSurf *ss);
+int ccgSubSurf_getNumVerts(const CCGSubSurf *ss);
+int ccgSubSurf_getNumEdges(const CCGSubSurf *ss);
+int ccgSubSurf_getNumFaces(const CCGSubSurf *ss);
+
+int ccgSubSurf_getSubdivisionLevels(const CCGSubSurf *ss);
+int ccgSubSurf_getEdgeSize(const CCGSubSurf *ss);
+int ccgSubSurf_getEdgeLevelSize(const CCGSubSurf *ss, int level);
+int ccgSubSurf_getGridSize(const CCGSubSurf *ss);
+int ccgSubSurf_getGridLevelSize(const CCGSubSurf *ss, int level);
+int ccgSubSurf_getSimpleSubdiv(const CCGSubSurf *ss);
+
+CCGVert *ccgSubSurf_getVert(CCGSubSurf *ss, CCGVertHDL v);
+CCGVertHDL ccgSubSurf_getVertVertHandle(CCGVert *v);
+int ccgSubSurf_getVertNumFaces(CCGVert *v);
+CCGFace *ccgSubSurf_getVertFace(CCGVert *v, int index);
+int ccgSubSurf_getVertNumEdges(CCGVert *v);
+CCGEdge *ccgSubSurf_getVertEdge(CCGVert *v, int index);
+
+int ccgSubSurf_getVertAge(CCGSubSurf *ss, CCGVert *v);
+void *ccgSubSurf_getVertUserData(CCGSubSurf *ss, CCGVert *v);
+void *ccgSubSurf_getVertData(CCGSubSurf *ss, CCGVert *v);
+void *ccgSubSurf_getVertLevelData(CCGSubSurf *ss, CCGVert *v, int level);
+
+CCGEdge *ccgSubSurf_getEdge(CCGSubSurf *ss, CCGEdgeHDL e);
+CCGEdgeHDL ccgSubSurf_getEdgeEdgeHandle(CCGEdge *e);
+int ccgSubSurf_getEdgeNumFaces(CCGEdge *e);
+CCGFace *ccgSubSurf_getEdgeFace(CCGEdge *e, int index);
+CCGVert *ccgSubSurf_getEdgeVert0(CCGEdge *e);
+CCGVert *ccgSubSurf_getEdgeVert1(CCGEdge *e);
+float ccgSubSurf_getEdgeCrease(CCGEdge *e);
+
+int ccgSubSurf_getEdgeAge(CCGSubSurf *ss, CCGEdge *e);
+void *ccgSubSurf_getEdgeUserData(CCGSubSurf *ss, CCGEdge *e);
+void *ccgSubSurf_getEdgeDataArray(CCGSubSurf *ss, CCGEdge *e);
+void *ccgSubSurf_getEdgeData(CCGSubSurf *ss, CCGEdge *e, int x);
+void *ccgSubSurf_getEdgeLevelData(CCGSubSurf *ss, CCGEdge *e, int x, int level);
+
+CCGFace *ccgSubSurf_getFace(CCGSubSurf *ss, CCGFaceHDL f);
+CCGFaceHDL ccgSubSurf_getFaceFaceHandle(CCGFace *f);
+int ccgSubSurf_getFaceNumVerts(CCGFace *f);
+CCGVert *ccgSubSurf_getFaceVert(CCGFace *f, int index);
+CCGEdge *ccgSubSurf_getFaceEdge(CCGFace *f, int index);
+int ccgSubSurf_getFaceEdgeIndex(CCGFace *f, CCGEdge *e);
+
+int ccgSubSurf_getFaceAge(CCGSubSurf *ss, CCGFace *f);
+void *ccgSubSurf_getFaceUserData(CCGSubSurf *ss, CCGFace *f);
+void *ccgSubSurf_getFaceCenterData(CCGFace *f);
+void *ccgSubSurf_getFaceGridEdgeDataArray(CCGSubSurf *ss, CCGFace *f, int gridIndex);
+void *ccgSubSurf_getFaceGridEdgeData(CCGSubSurf *ss, CCGFace *f, int gridIndex, int x);
+void *ccgSubSurf_getFaceGridDataArray(CCGSubSurf *ss, CCGFace *f, int gridIndex);
+void *ccgSubSurf_getFaceGridData(CCGSubSurf *ss, CCGFace *f, int gridIndex, int x, int y);
+
+int ccgSubSurf_getNumFinalVerts(const CCGSubSurf *ss);
+int ccgSubSurf_getNumFinalEdges(const CCGSubSurf *ss);
+int ccgSubSurf_getNumFinalFaces(const CCGSubSurf *ss);
/***/
@@ -174,21 +195,21 @@ typedef struct _EHashIterator CCGEdgeIterator;
typedef struct _EHashIterator CCGFaceIterator;
typedef struct _EHashIterator CCGVertIterator;
-void ccgSubSurf_initVertIterator(CCGSubSurf *ss, CCGVertIterator *viter);
-void ccgSubSurf_initEdgeIterator(CCGSubSurf *ss, CCGEdgeIterator *eiter);
-void ccgSubSurf_initFaceIterator(CCGSubSurf *ss, CCGFaceIterator *fiter);
+void ccgSubSurf_initVertIterator(CCGSubSurf *ss, CCGVertIterator *viter);
+void ccgSubSurf_initEdgeIterator(CCGSubSurf *ss, CCGEdgeIterator *eiter);
+void ccgSubSurf_initFaceIterator(CCGSubSurf *ss, CCGFaceIterator *fiter);
-CCGVert* ccgVertIterator_getCurrent (CCGVertIterator *vi);
-int ccgVertIterator_isStopped (CCGVertIterator *vi);
-void ccgVertIterator_next (CCGVertIterator *vi);
+CCGVert *ccgVertIterator_getCurrent(CCGVertIterator *vi);
+int ccgVertIterator_isStopped(CCGVertIterator *vi);
+void ccgVertIterator_next(CCGVertIterator *vi);
-CCGEdge* ccgEdgeIterator_getCurrent (CCGEdgeIterator *ei);
-int ccgEdgeIterator_isStopped (CCGEdgeIterator *ei);
-void ccgEdgeIterator_next (CCGEdgeIterator *ei);
+CCGEdge *ccgEdgeIterator_getCurrent(CCGEdgeIterator *ei);
+int ccgEdgeIterator_isStopped(CCGEdgeIterator *ei);
+void ccgEdgeIterator_next(CCGEdgeIterator *ei);
-CCGFace* ccgFaceIterator_getCurrent (CCGFaceIterator *fi);
-int ccgFaceIterator_isStopped (CCGFaceIterator *fi);
-void ccgFaceIterator_next (CCGFaceIterator *fi);
+CCGFace *ccgFaceIterator_getCurrent(CCGFaceIterator *fi);
+int ccgFaceIterator_isStopped(CCGFaceIterator *fi);
+void ccgFaceIterator_next(CCGFaceIterator *fi);
#ifdef WITH_OPENSUBDIV
struct DerivedMesh;
@@ -209,8 +230,10 @@ bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, bool use_osd_glsl, int active_uv_i
* TODO(sergey): fill_quads is actually an invariant and should be part
* of the prepare routine.
*/
-void ccgSubSurf_drawGLMesh(CCGSubSurf *ss, bool fill_quads,
- int start_partition, int num_partitions);
+void ccgSubSurf_drawGLMesh(CCGSubSurf *ss,
+ bool fill_quads,
+ int start_partition,
+ int num_partitions);
/* Get number of base faces in a particular GL mesh. */
int ccgSubSurf_getNumGLMeshBaseFaces(CCGSubSurf *ss);
@@ -227,15 +250,11 @@ bool ccgSubSurf_needGrids(CCGSubSurf *ss);
/* Set evaluator's face varying data from UV coordinates.
* Used for CPU evaluation.
*/
-void ccgSubSurf_evaluatorSetFVarUV(CCGSubSurf *ss,
- struct DerivedMesh *dm,
- int layer_index);
+void ccgSubSurf_evaluatorSetFVarUV(CCGSubSurf *ss, struct DerivedMesh *dm, int layer_index);
/* TODO(sergey): Temporary call to test things. */
-void ccgSubSurf_evaluatorFVarUV(CCGSubSurf *ss,
- int face_index, int S,
- float grid_u, float grid_v,
- float uv[2]);
+void ccgSubSurf_evaluatorFVarUV(
+ CCGSubSurf *ss, int face_index, int S, float grid_u, float grid_v, float uv[2]);
void ccgSubSurf_free_osd_mesh(CCGSubSurf *ss);
@@ -245,4 +264,4 @@ void ccgSubSurf__sync_subdivUvs(CCGSubSurf *ss, bool subsurf_uvs);
#endif
-#endif /* __CCGSUBSURF_H__ */
+#endif /* __CCGSUBSURF_H__ */
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_inline.h b/source/blender/blenkernel/intern/CCGSubSurf_inline.h
index c62e4056b52..44e27cb89da 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_inline.h
+++ b/source/blender/blenkernel/intern/CCGSubSurf_inline.h
@@ -23,243 +23,246 @@
BLI_INLINE int ccg_gridsize(int level)
{
- BLI_assert(level > 0);
- BLI_assert(level <= CCGSUBSURF_LEVEL_MAX + 1);
- return (1 << (level - 1)) + 1;
+ BLI_assert(level > 0);
+ BLI_assert(level <= CCGSUBSURF_LEVEL_MAX + 1);
+ return (1 << (level - 1)) + 1;
}
BLI_INLINE int ccg_edgesize(int level)
{
- BLI_assert(level > 0);
- BLI_assert(level <= CCGSUBSURF_LEVEL_MAX + 1);
- return 1 + (1 << level);
+ BLI_assert(level > 0);
+ BLI_assert(level <= CCGSUBSURF_LEVEL_MAX + 1);
+ return 1 + (1 << level);
}
BLI_INLINE int ccg_spacing(int high_level, int low_level)
{
- BLI_assert(high_level > 0 && low_level > 0);
- BLI_assert(high_level >= low_level);
- BLI_assert((high_level - low_level) <= CCGSUBSURF_LEVEL_MAX);
- return 1 << (high_level - low_level);
+ BLI_assert(high_level > 0 && low_level > 0);
+ BLI_assert(high_level >= low_level);
+ BLI_assert((high_level - low_level) <= CCGSUBSURF_LEVEL_MAX);
+ return 1 << (high_level - low_level);
}
BLI_INLINE int ccg_edgebase(int level)
{
- BLI_assert(level > 0);
- BLI_assert(level <= CCGSUBSURF_LEVEL_MAX + 1);
- return level + (1 << level) - 1;
+ BLI_assert(level > 0);
+ BLI_assert(level <= CCGSUBSURF_LEVEL_MAX + 1);
+ return level + (1 << level) - 1;
}
/* **** */
BLI_INLINE byte *VERT_getLevelData(CCGVert *v)
{
- return (byte *)(&(v)[1]);
+ return (byte *)(&(v)[1]);
}
BLI_INLINE byte *EDGE_getLevelData(CCGEdge *e)
{
- return (byte *)(&(e)[1]);
+ return (byte *)(&(e)[1]);
}
BLI_INLINE CCGVert **FACE_getVerts(CCGFace *f)
{
- return (CCGVert **)(&f[1]);
+ return (CCGVert **)(&f[1]);
}
BLI_INLINE CCGEdge **FACE_getEdges(CCGFace *f)
{
- return (CCGEdge **)(&(FACE_getVerts(f)[f->numVerts]));
+ return (CCGEdge **)(&(FACE_getVerts(f)[f->numVerts]));
}
BLI_INLINE byte *FACE_getCenterData(CCGFace *f)
{
- return (byte *)(&(FACE_getEdges(f)[(f)->numVerts]));
+ return (byte *)(&(FACE_getEdges(f)[(f)->numVerts]));
}
/* **** */
BLI_INLINE void *ccg_vert_getCo(CCGVert *v, int lvl, int dataSize)
{
- return &VERT_getLevelData(v)[lvl * dataSize];
+ return &VERT_getLevelData(v)[lvl * dataSize];
}
-BLI_INLINE float *ccg_vert_getNo(CCGVert *v,
- int lvl,
- int dataSize,
- int normalDataOffset)
+BLI_INLINE float *ccg_vert_getNo(CCGVert *v, int lvl, int dataSize, int normalDataOffset)
{
- return (float *) &VERT_getLevelData(v)[lvl * dataSize + normalDataOffset];
+ return (float *)&VERT_getLevelData(v)[lvl * dataSize + normalDataOffset];
}
BLI_INLINE void *ccg_edge_getCo(CCGEdge *e, int lvl, int x, int dataSize)
{
- int levelBase = ccg_edgebase(lvl);
- return &EDGE_getLevelData(e)[dataSize * (levelBase + x)];
+ int levelBase = ccg_edgebase(lvl);
+ return &EDGE_getLevelData(e)[dataSize * (levelBase + x)];
}
-BLI_INLINE float *ccg_edge_getNo(CCGEdge *e,
- int lvl,
- int x,
- int dataSize,
- int normalDataOffset)
+BLI_INLINE float *ccg_edge_getNo(CCGEdge *e, int lvl, int x, int dataSize, int normalDataOffset)
{
- int levelBase = ccg_edgebase(lvl);
- return (float *) &EDGE_getLevelData(e)[dataSize * (levelBase + x) + normalDataOffset];
+ int levelBase = ccg_edgebase(lvl);
+ return (float *)&EDGE_getLevelData(e)[dataSize * (levelBase + x) + normalDataOffset];
}
BLI_INLINE void *ccg_face_getIECo(CCGFace *f, int lvl, int S, int x, int levels, int dataSize)
{
- int maxGridSize = ccg_gridsize(levels);
- int spacing = ccg_spacing(levels, lvl);
- byte *gridBase = FACE_getCenterData(f) + dataSize * (1 + S * (maxGridSize + maxGridSize * maxGridSize));
- return &gridBase[dataSize * x * spacing];
+ int maxGridSize = ccg_gridsize(levels);
+ int spacing = ccg_spacing(levels, lvl);
+ byte *gridBase = FACE_getCenterData(f) +
+ dataSize * (1 + S * (maxGridSize + maxGridSize * maxGridSize));
+ return &gridBase[dataSize * x * spacing];
}
-BLI_INLINE void *ccg_face_getIENo(CCGFace *f, int lvl, int S, int x, int levels, int dataSize, int normalDataOffset)
+BLI_INLINE void *ccg_face_getIENo(
+ CCGFace *f, int lvl, int S, int x, int levels, int dataSize, int normalDataOffset)
{
- int maxGridSize = ccg_gridsize(levels);
- int spacing = ccg_spacing(levels, lvl);
- byte *gridBase = FACE_getCenterData(f) + dataSize * (1 + S * (maxGridSize + maxGridSize * maxGridSize));
- return &gridBase[dataSize * x * spacing + normalDataOffset];
+ int maxGridSize = ccg_gridsize(levels);
+ int spacing = ccg_spacing(levels, lvl);
+ byte *gridBase = FACE_getCenterData(f) +
+ dataSize * (1 + S * (maxGridSize + maxGridSize * maxGridSize));
+ return &gridBase[dataSize * x * spacing + normalDataOffset];
}
-BLI_INLINE void *ccg_face_getIFCo(CCGFace *f, int lvl, int S, int x, int y, int levels, int dataSize)
+BLI_INLINE void *ccg_face_getIFCo(
+ CCGFace *f, int lvl, int S, int x, int y, int levels, int dataSize)
{
- int maxGridSize = ccg_gridsize(levels);
- int spacing = ccg_spacing(levels, lvl);
- byte *gridBase = FACE_getCenterData(f) + dataSize * (1 + S * (maxGridSize + maxGridSize * maxGridSize));
- return &gridBase[dataSize * (maxGridSize + (y * maxGridSize + x) * spacing)];
+ int maxGridSize = ccg_gridsize(levels);
+ int spacing = ccg_spacing(levels, lvl);
+ byte *gridBase = FACE_getCenterData(f) +
+ dataSize * (1 + S * (maxGridSize + maxGridSize * maxGridSize));
+ return &gridBase[dataSize * (maxGridSize + (y * maxGridSize + x) * spacing)];
}
-BLI_INLINE float *ccg_face_getIFNo(CCGFace *f, int lvl, int S, int x, int y, int levels, int dataSize, int normalDataOffset)
+BLI_INLINE float *ccg_face_getIFNo(
+ CCGFace *f, int lvl, int S, int x, int y, int levels, int dataSize, int normalDataOffset)
{
- int maxGridSize = ccg_gridsize(levels);
- int spacing = ccg_spacing(levels, lvl);
- byte *gridBase = FACE_getCenterData(f) + dataSize * (1 + S * (maxGridSize + maxGridSize * maxGridSize));
- return (float *) &gridBase[dataSize * (maxGridSize + (y * maxGridSize + x) * spacing) + normalDataOffset];
+ int maxGridSize = ccg_gridsize(levels);
+ int spacing = ccg_spacing(levels, lvl);
+ byte *gridBase = FACE_getCenterData(f) +
+ dataSize * (1 + S * (maxGridSize + maxGridSize * maxGridSize));
+ return (float *)&gridBase[dataSize * (maxGridSize + (y * maxGridSize + x) * spacing) +
+ normalDataOffset];
}
-
BLI_INLINE int ccg_face_getVertIndex(CCGFace *f, CCGVert *v)
{
- int i;
- for (i = 0; i < f->numVerts; i++)
- if (FACE_getVerts(f)[i] == v)
- return i;
- return -1;
+ int i;
+ for (i = 0; i < f->numVerts; i++)
+ if (FACE_getVerts(f)[i] == v)
+ return i;
+ return -1;
}
BLI_INLINE int ccg_face_getEdgeIndex(CCGFace *f, CCGEdge *e)
{
- int i;
- for (i = 0; i < f->numVerts; i++)
- if (FACE_getEdges(f)[i] == e)
- return i;
- return -1;
+ int i;
+ for (i = 0; i < f->numVerts; i++)
+ if (FACE_getEdges(f)[i] == e)
+ return i;
+ return -1;
}
-BLI_INLINE void *ccg_face_getIFCoEdge(CCGFace *f, CCGEdge *e, int f_ed_idx, int lvl, int eX, int eY, int levels, int dataSize)
+BLI_INLINE void *ccg_face_getIFCoEdge(
+ CCGFace *f, CCGEdge *e, int f_ed_idx, int lvl, int eX, int eY, int levels, int dataSize)
{
- int maxGridSize = ccg_gridsize(levels);
- int spacing = ccg_spacing(levels, lvl);
- int x, y, cx, cy;
-
- BLI_assert(f_ed_idx == ccg_face_getEdgeIndex(f, e));
-
- eX = eX * spacing;
- eY = eY * spacing;
- if (e->v0 != FACE_getVerts(f)[f_ed_idx]) {
- eX = (maxGridSize * 2 - 1) - 1 - eX;
- }
- y = maxGridSize - 1 - eX;
- x = maxGridSize - 1 - eY;
- if (x < 0) {
- f_ed_idx = (f_ed_idx + f->numVerts - 1) % f->numVerts;
- cx = y;
- cy = -x;
- }
- else if (y < 0) {
- f_ed_idx = (f_ed_idx + 1) % f->numVerts;
- cx = -y;
- cy = x;
- }
- else {
- cx = x;
- cy = y;
- }
- return ccg_face_getIFCo(f, levels, f_ed_idx, cx, cy, levels, dataSize);
+ int maxGridSize = ccg_gridsize(levels);
+ int spacing = ccg_spacing(levels, lvl);
+ int x, y, cx, cy;
+
+ BLI_assert(f_ed_idx == ccg_face_getEdgeIndex(f, e));
+
+ eX = eX * spacing;
+ eY = eY * spacing;
+ if (e->v0 != FACE_getVerts(f)[f_ed_idx]) {
+ eX = (maxGridSize * 2 - 1) - 1 - eX;
+ }
+ y = maxGridSize - 1 - eX;
+ x = maxGridSize - 1 - eY;
+ if (x < 0) {
+ f_ed_idx = (f_ed_idx + f->numVerts - 1) % f->numVerts;
+ cx = y;
+ cy = -x;
+ }
+ else if (y < 0) {
+ f_ed_idx = (f_ed_idx + 1) % f->numVerts;
+ cx = -y;
+ cy = x;
+ }
+ else {
+ cx = x;
+ cy = y;
+ }
+ return ccg_face_getIFCo(f, levels, f_ed_idx, cx, cy, levels, dataSize);
}
BLI_INLINE void Normalize(float no[3])
{
- const float length = sqrtf(no[0] * no[0] + no[1] * no[1] + no[2] * no[2]);
-
- if (length > EPSILON) {
- const float length_inv = 1.0f / length;
-
- no[0] *= length_inv;
- no[1] *= length_inv;
- no[2] *= length_inv;
- }
- else {
- NormZero(no);
- }
+ const float length = sqrtf(no[0] * no[0] + no[1] * no[1] + no[2] * no[2]);
+
+ if (length > EPSILON) {
+ const float length_inv = 1.0f / length;
+
+ no[0] *= length_inv;
+ no[1] *= length_inv;
+ no[2] *= length_inv;
+ }
+ else {
+ NormZero(no);
+ }
}
/* Data layers mathematics. */
BLI_INLINE int VertDataEqual(const float a[], const float b[], const CCGSubSurf *ss)
{
- int i;
- for (i = 0; i < ss->meshIFC.numLayers; i++) {
- if (a[i] != b[i])
- return 0;
- }
- return 1;
+ int i;
+ for (i = 0; i < ss->meshIFC.numLayers; i++) {
+ if (a[i] != b[i])
+ return 0;
+ }
+ return 1;
}
BLI_INLINE void VertDataZero(float v[], const CCGSubSurf *ss)
{
- memset(v, 0, sizeof(float) * ss->meshIFC.numLayers);
+ memset(v, 0, sizeof(float) * ss->meshIFC.numLayers);
}
BLI_INLINE void VertDataCopy(float dst[], const float src[], const CCGSubSurf *ss)
{
- int i;
- for (i = 0; i < ss->meshIFC.numLayers; i++)
- dst[i] = src[i];
+ int i;
+ for (i = 0; i < ss->meshIFC.numLayers; i++)
+ dst[i] = src[i];
}
BLI_INLINE void VertDataAdd(float a[], const float b[], const CCGSubSurf *ss)
{
- int i;
- for (i = 0; i < ss->meshIFC.numLayers; i++)
- a[i] += b[i];
+ int i;
+ for (i = 0; i < ss->meshIFC.numLayers; i++)
+ a[i] += b[i];
}
BLI_INLINE void VertDataSub(float a[], const float b[], const CCGSubSurf *ss)
{
- int i;
- for (i = 0; i < ss->meshIFC.numLayers; i++)
- a[i] -= b[i];
+ int i;
+ for (i = 0; i < ss->meshIFC.numLayers; i++)
+ a[i] -= b[i];
}
BLI_INLINE void VertDataMulN(float v[], float f, const CCGSubSurf *ss)
{
- int i;
- for (i = 0; i < ss->meshIFC.numLayers; i++)
- v[i] *= f;
+ int i;
+ for (i = 0; i < ss->meshIFC.numLayers; i++)
+ v[i] *= f;
}
BLI_INLINE void VertDataAvg4(float v[],
- const float a[], const float b[],
- const float c[], const float d[],
+ const float a[],
+ const float b[],
+ const float c[],
+ const float d[],
const CCGSubSurf *ss)
{
- int i;
- for (i = 0; i < ss->meshIFC.numLayers; i++)
- v[i] = (a[i] + b[i] + c[i] + d[i]) * 0.25f;
+ int i;
+ for (i = 0; i < ss->meshIFC.numLayers; i++)
+ v[i] = (a[i] + b[i] + c[i] + d[i]) * 0.25f;
}
-#endif /* __CCGSUBSURF_INLINE_H__ */
+#endif /* __CCGSUBSURF_INLINE_H__ */
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_intern.h b/source/blender/blenkernel/intern/CCGSubSurf_intern.h
index 8faf95ca508..f89545e802e 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_intern.h
+++ b/source/blender/blenkernel/intern/CCGSubSurf_intern.h
@@ -46,23 +46,23 @@ typedef unsigned char byte;
*/
typedef struct _EHEntry {
- struct _EHEntry *next;
- void *key;
+ struct _EHEntry *next;
+ void *key;
} EHEntry;
typedef struct _EHash {
- EHEntry **buckets;
- int numEntries, curSize, curSizeIdx;
+ EHEntry **buckets;
+ int numEntries, curSize, curSizeIdx;
- CCGAllocatorIFC allocatorIFC;
- CCGAllocatorHDL allocator;
+ CCGAllocatorIFC allocatorIFC;
+ CCGAllocatorHDL allocator;
} EHash;
typedef void (*EHEntryFreeFP)(EHEntry *, void *);
-#define EHASH_alloc(eh, nb) ((eh)->allocatorIFC.alloc((eh)->allocator, nb))
-#define EHASH_free(eh, ptr) ((eh)->allocatorIFC.free((eh)->allocator, ptr))
-#define EHASH_hash(eh, item) (((uintptr_t) (item)) % ((unsigned int) (eh)->curSize))
+#define EHASH_alloc(eh, nb) ((eh)->allocatorIFC.alloc((eh)->allocator, nb))
+#define EHASH_free(eh, ptr) ((eh)->allocatorIFC.free((eh)->allocator, ptr))
+#define EHASH_hash(eh, item) (((uintptr_t)(item)) % ((unsigned int)(eh)->curSize))
/* Generic hash functions. */
@@ -97,183 +97,206 @@ struct DerivedMesh;
/* ** Data structures, constants. enums ** */
enum {
- Vert_eEffected = (1 << 0),
- Vert_eChanged = (1 << 1),
- Vert_eSeam = (1 << 2),
+ Vert_eEffected = (1 << 0),
+ Vert_eChanged = (1 << 1),
+ Vert_eSeam = (1 << 2),
} /*VertFlags*/;
enum {
- Edge_eEffected = (1 << 0),
+ Edge_eEffected = (1 << 0),
} /*CCGEdgeFlags*/;
enum {
- Face_eEffected = (1 << 0),
+ Face_eEffected = (1 << 0),
} /*FaceFlags*/;
struct CCGVert {
- CCGVert *next; /* EHData.next */
- CCGVertHDL vHDL; /* EHData.key */
+ CCGVert *next; /* EHData.next */
+ CCGVertHDL vHDL; /* EHData.key */
- short numEdges, numFaces, flags;
- int osd_index; /* Index of the vertex in the map, used by OSD. */
+ short numEdges, numFaces, flags;
+ int osd_index; /* Index of the vertex in the map, used by OSD. */
- CCGEdge **edges;
- CCGFace **faces;
- /* byte *levelData; */
- /* byte *userData; */
+ CCGEdge **edges;
+ CCGFace **faces;
+ /* byte *levelData; */
+ /* byte *userData; */
};
struct CCGEdge {
- CCGEdge *next; /* EHData.next */
- CCGEdgeHDL eHDL; /* EHData.key */
+ CCGEdge *next; /* EHData.next */
+ CCGEdgeHDL eHDL; /* EHData.key */
- short numFaces, flags;
- float crease;
+ short numFaces, flags;
+ float crease;
- CCGVert *v0, *v1;
- CCGFace **faces;
+ CCGVert *v0, *v1;
+ CCGFace **faces;
- /* byte *levelData; */
- /* byte *userData; */
+ /* byte *levelData; */
+ /* byte *userData; */
};
struct CCGFace {
- CCGFace *next; /* EHData.next */
- CCGFaceHDL fHDL; /* EHData.key */
+ CCGFace *next; /* EHData.next */
+ CCGFaceHDL fHDL; /* EHData.key */
- short numVerts, flags;
- int osd_index;
+ short numVerts, flags;
+ int osd_index;
- /* CCGVert **verts; */
- /* CCGEdge **edges; */
- /* byte *centerData; */
- /* byte **gridData; */
- /* byte *userData; */
+ /* CCGVert **verts; */
+ /* CCGEdge **edges; */
+ /* byte *centerData; */
+ /* byte **gridData; */
+ /* byte *userData; */
};
typedef enum {
- eSyncState_None = 0,
- eSyncState_Vert,
- eSyncState_Edge,
- eSyncState_Face,
- eSyncState_Partial,
+ eSyncState_None = 0,
+ eSyncState_Vert,
+ eSyncState_Edge,
+ eSyncState_Face,
+ eSyncState_Partial,
#ifdef WITH_OPENSUBDIV
- eSyncState_OpenSubdiv,
+ eSyncState_OpenSubdiv,
#endif
} SyncState;
struct CCGSubSurf {
- EHash *vMap; /* map of CCGVertHDL -> Vert */
- EHash *eMap; /* map of CCGEdgeHDL -> Edge */
- EHash *fMap; /* map of CCGFaceHDL -> Face */
+ EHash *vMap; /* map of CCGVertHDL -> Vert */
+ EHash *eMap; /* map of CCGEdgeHDL -> Edge */
+ EHash *fMap; /* map of CCGFaceHDL -> Face */
- CCGMeshIFC meshIFC;
+ CCGMeshIFC meshIFC;
- CCGAllocatorIFC allocatorIFC;
- CCGAllocatorHDL allocator;
+ CCGAllocatorIFC allocatorIFC;
+ CCGAllocatorHDL allocator;
- int subdivLevels;
- int numGrids;
- int allowEdgeCreation;
- float defaultCreaseValue;
- void *defaultEdgeUserData;
+ int subdivLevels;
+ int numGrids;
+ int allowEdgeCreation;
+ float defaultCreaseValue;
+ void *defaultEdgeUserData;
- void *q, *r;
+ void *q, *r;
- /* Data for calc vert normals. */
- int calcVertNormals;
- int normalDataOffset;
+ /* Data for calc vert normals. */
+ int calcVertNormals;
+ int normalDataOffset;
- /* Data for paint masks. */
- int allocMask;
- int maskDataOffset;
+ /* Data for paint masks. */
+ int allocMask;
+ int maskDataOffset;
- /* Data for age'ing (to debug sync). */
- int currentAge;
- int useAgeCounts;
- int vertUserAgeOffset;
- int edgeUserAgeOffset;
- int faceUserAgeOffset;
+ /* Data for age'ing (to debug sync). */
+ int currentAge;
+ int useAgeCounts;
+ int vertUserAgeOffset;
+ int edgeUserAgeOffset;
+ int faceUserAgeOffset;
- /* Data used during syncing. */
- SyncState syncState;
+ /* Data used during syncing. */
+ SyncState syncState;
- EHash *oldVMap, *oldEMap, *oldFMap;
- int lenTempArrays;
- CCGVert **tempVerts;
- CCGEdge **tempEdges;
+ EHash *oldVMap, *oldEMap, *oldFMap;
+ int lenTempArrays;
+ CCGVert **tempVerts;
+ CCGEdge **tempEdges;
#ifdef WITH_OPENSUBDIV
- /* Skip grids means no CCG geometry is created and subsurf is possible
- * to be completely done on GPU.
- */
- bool skip_grids;
-
- /* ** GPU backend. ** */
-
- /* Compute device used by GL mesh. */
- short osd_compute;
- /* Coarse (base mesh) vertex coordinates.
- *
- * Filled in from the modifier stack and passed to OpenSubdiv compute
- * on mesh display.
- */
- float (*osd_coarse_coords)[3];
- int osd_num_coarse_coords;
- /* Denotes whether coarse positions in the GL mesh are invalid.
- * Used to avoid updating GL mesh coords on every redraw.
- */
- bool osd_coarse_coords_invalid;
-
- /* GL mesh descriptor, used for refinement and draw. */
- struct OpenSubdiv_GLMesh *osd_mesh;
- /* Refiner which is used to create GL mesh.
- *
- * Refiner is created from the modifier stack and used later from the main
- * thread to construct GL mesh to avoid threaded access to GL.
- */
- struct OpenSubdiv_TopologyRefiner *osd_topology_refiner; /* Only used at synchronization stage. */
- /* Denotes whether osd_mesh is invalid now due to topology changes and needs
- * to be reconstructed.
- *
- * Reconstruction happens from main thread due to OpenGL communication.
- */
- bool osd_mesh_invalid;
- /* Vertex array used for osd_mesh draw. */
- unsigned int osd_vao;
-
- /* ** CPU backend. ** */
-
- /* Limit evaluator, used to evaluate CCG. */
- struct OpenSubdiv_Evaluator *osd_evaluator;
- /* Next PTex face index, used while CCG synchronization
- * to fill in PTex index of CCGFace.
- */
- int osd_next_face_ptex_index;
-
- bool osd_subdiv_uvs;
+ /* Skip grids means no CCG geometry is created and subsurf is possible
+ * to be completely done on GPU.
+ */
+ bool skip_grids;
+
+ /* ** GPU backend. ** */
+
+ /* Compute device used by GL mesh. */
+ short osd_compute;
+ /* Coarse (base mesh) vertex coordinates.
+ *
+ * Filled in from the modifier stack and passed to OpenSubdiv compute
+ * on mesh display.
+ */
+ float (*osd_coarse_coords)[3];
+ int osd_num_coarse_coords;
+ /* Denotes whether coarse positions in the GL mesh are invalid.
+ * Used to avoid updating GL mesh coords on every redraw.
+ */
+ bool osd_coarse_coords_invalid;
+
+ /* GL mesh descriptor, used for refinement and draw. */
+ struct OpenSubdiv_GLMesh *osd_mesh;
+ /* Refiner which is used to create GL mesh.
+ *
+ * Refiner is created from the modifier stack and used later from the main
+ * thread to construct GL mesh to avoid threaded access to GL.
+ */
+ struct OpenSubdiv_TopologyRefiner
+ *osd_topology_refiner; /* Only used at synchronization stage. */
+ /* Denotes whether osd_mesh is invalid now due to topology changes and needs
+ * to be reconstructed.
+ *
+ * Reconstruction happens from main thread due to OpenGL communication.
+ */
+ bool osd_mesh_invalid;
+ /* Vertex array used for osd_mesh draw. */
+ unsigned int osd_vao;
+
+ /* ** CPU backend. ** */
+
+ /* Limit evaluator, used to evaluate CCG. */
+ struct OpenSubdiv_Evaluator *osd_evaluator;
+ /* Next PTex face index, used while CCG synchronization
+ * to fill in PTex index of CCGFace.
+ */
+ int osd_next_face_ptex_index;
+
+ bool osd_subdiv_uvs;
#endif
};
/* ** Utility macros ** */
-#define CCGSUBSURF_alloc(ss, nb) ((ss)->allocatorIFC.alloc((ss)->allocator, nb))
-#define CCGSUBSURF_realloc(ss, ptr, nb, ob) ((ss)->allocatorIFC.realloc((ss)->allocator, ptr, nb, ob))
-#define CCGSUBSURF_free(ss, ptr) ((ss)->allocatorIFC.free((ss)->allocator, ptr))
-
-#define VERT_getCo(v, lvl) ccg_vert_getCo(v, lvl, vertDataSize)
-#define VERT_getNo(v, lvl) ccg_vert_getNo(v, lvl, vertDataSize, normalDataOffset)
-#define EDGE_getCo(e, lvl, x) ccg_edge_getCo(e, lvl, x, vertDataSize)
-#define EDGE_getNo(e, lvl, x) ccg_edge_getNo(e, lvl, x, vertDataSize, normalDataOffset)
-#define FACE_getIFNo(f, lvl, S, x, y) ccg_face_getIFNo(f, lvl, S, x, y, subdivLevels, vertDataSize, normalDataOffset)
+#define CCGSUBSURF_alloc(ss, nb) ((ss)->allocatorIFC.alloc((ss)->allocator, nb))
+#define CCGSUBSURF_realloc(ss, ptr, nb, ob) \
+ ((ss)->allocatorIFC.realloc((ss)->allocator, ptr, nb, ob))
+#define CCGSUBSURF_free(ss, ptr) ((ss)->allocatorIFC.free((ss)->allocator, ptr))
+
+#define VERT_getCo(v, lvl) ccg_vert_getCo(v, lvl, vertDataSize)
+#define VERT_getNo(v, lvl) ccg_vert_getNo(v, lvl, vertDataSize, normalDataOffset)
+#define EDGE_getCo(e, lvl, x) ccg_edge_getCo(e, lvl, x, vertDataSize)
+#define EDGE_getNo(e, lvl, x) ccg_edge_getNo(e, lvl, x, vertDataSize, normalDataOffset)
+#define FACE_getIFNo(f, lvl, S, x, y) \
+ ccg_face_getIFNo(f, lvl, S, x, y, subdivLevels, vertDataSize, normalDataOffset)
//#define FACE_calcIFNo(f, lvl, S, x, y, no) _face_calcIFNo(f, lvl, S, x, y, no, subdivLevels, vertDataSize)
-#define FACE_getIENo(f, lvl, S, x) ccg_face_getIENo(f, lvl, S, x, subdivLevels, vertDataSize, normalDataOffset)
-#define FACE_getIECo(f, lvl, S, x) ccg_face_getIECo(f, lvl, S, x, subdivLevels, vertDataSize)
-#define FACE_getIFCo(f, lvl, S, x, y) ccg_face_getIFCo(f, lvl, S, x, y, subdivLevels, vertDataSize)
-
-#define NormZero(av) { float *_a = (float *) av; _a[0] = _a[1] = _a[2] = 0.0f; } (void)0
-#define NormCopy(av, bv) { float *_a = (float *) av, *_b = (float *) bv; _a[0] = _b[0]; _a[1] = _b[1]; _a[2] = _b[2]; } (void)0
-#define NormAdd(av, bv) { float *_a = (float *) av, *_b = (float *) bv; _a[0] += _b[0]; _a[1] += _b[1]; _a[2] += _b[2]; } (void)0
+#define FACE_getIENo(f, lvl, S, x) \
+ ccg_face_getIENo(f, lvl, S, x, subdivLevels, vertDataSize, normalDataOffset)
+#define FACE_getIECo(f, lvl, S, x) ccg_face_getIECo(f, lvl, S, x, subdivLevels, vertDataSize)
+#define FACE_getIFCo(f, lvl, S, x, y) ccg_face_getIFCo(f, lvl, S, x, y, subdivLevels, vertDataSize)
+
+#define NormZero(av) \
+ { \
+ float *_a = (float *)av; \
+ _a[0] = _a[1] = _a[2] = 0.0f; \
+ } \
+ (void)0
+#define NormCopy(av, bv) \
+ { \
+ float *_a = (float *)av, *_b = (float *)bv; \
+ _a[0] = _b[0]; \
+ _a[1] = _b[1]; \
+ _a[2] = _b[2]; \
+ } \
+ (void)0
+#define NormAdd(av, bv) \
+ { \
+ float *_a = (float *)av, *_b = (float *)bv; \
+ _a[0] += _b[0]; \
+ _a[1] += _b[1]; \
+ _a[2] += _b[2]; \
+ } \
+ (void)0
/* ** General purpose functions ** */
@@ -310,17 +333,13 @@ void ccgSubSurf__delete_pending(void);
struct OpenSubdiv_Converter;
-void ccgSubSurf_converter_setup_from_derivedmesh(
- CCGSubSurf *ss,
- struct DerivedMesh *dm,
- struct OpenSubdiv_Converter *converter);
+void ccgSubSurf_converter_setup_from_derivedmesh(CCGSubSurf *ss,
+ struct DerivedMesh *dm,
+ struct OpenSubdiv_Converter *converter);
-void ccgSubSurf_converter_setup_from_ccg(
- CCGSubSurf *ss,
- struct OpenSubdiv_Converter *converter);
+void ccgSubSurf_converter_setup_from_ccg(CCGSubSurf *ss, struct OpenSubdiv_Converter *converter);
-void ccgSubSurf_converter_free(
- struct OpenSubdiv_Converter *converter);
+void ccgSubSurf_converter_free(struct OpenSubdiv_Converter *converter);
/* * CCGSubSurf_util.c * */
@@ -330,4 +349,4 @@ void ccgSubSurf__dumpCoords(CCGSubSurf *ss);
#include "CCGSubSurf_inline.h"
-#endif /* __CCGSUBSURF_INTERN_H__ */
+#endif /* __CCGSUBSURF_INTERN_H__ */
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_legacy.c b/source/blender/blenkernel/intern/CCGSubSurf_legacy.c
index 2e3169ebdde..430a8ef56f5 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_legacy.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf_legacy.c
@@ -19,7 +19,7 @@
*/
#include "MEM_guardedalloc.h"
-#include "BLI_sys_types.h" // for intptr_t support
+#include "BLI_sys_types.h" // for intptr_t support
#include "BLI_utildefines.h" /* for BLI_assert */
#include "BLI_math.h"
@@ -28,1250 +28,1268 @@
#include "CCGSubSurf.h"
#include "CCGSubSurf_intern.h"
-#define FACE_calcIFNo(f, lvl, S, x, y, no) _face_calcIFNo(f, lvl, S, x, y, no, subdivLevels, vertDataSize)
+#define FACE_calcIFNo(f, lvl, S, x, y, no) \
+ _face_calcIFNo(f, lvl, S, x, y, no, subdivLevels, vertDataSize)
/* TODO(sergey): Deduplicate the following functions/ */
static void *_edge_getCoVert(CCGEdge *e, CCGVert *v, int lvl, int x, int dataSize)
{
- int levelBase = ccg_edgebase(lvl);
- if (v == e->v0) {
- return &EDGE_getLevelData(e)[dataSize * (levelBase + x)];
- }
- else {
- return &EDGE_getLevelData(e)[dataSize * (levelBase + (1 << lvl) - x)];
- }
+ int levelBase = ccg_edgebase(lvl);
+ if (v == e->v0) {
+ return &EDGE_getLevelData(e)[dataSize * (levelBase + x)];
+ }
+ else {
+ return &EDGE_getLevelData(e)[dataSize * (levelBase + (1 << lvl) - x)];
+ }
}
/* *************************************************** */
static int _edge_isBoundary(const CCGEdge *e)
{
- return e->numFaces < 2;
+ return e->numFaces < 2;
}
static int _vert_isBoundary(const CCGVert *v)
{
- int i;
- for (i = 0; i < v->numEdges; i++)
- if (_edge_isBoundary(v->edges[i]))
- return 1;
- return 0;
+ int i;
+ for (i = 0; i < v->numEdges; i++)
+ if (_edge_isBoundary(v->edges[i]))
+ return 1;
+ return 0;
}
static CCGVert *_edge_getOtherVert(CCGEdge *e, CCGVert *vQ)
{
- if (vQ == e->v0) {
- return e->v1;
- }
- else {
- return e->v0;
- }
+ if (vQ == e->v0) {
+ return e->v1;
+ }
+ else {
+ return e->v0;
+ }
}
static float *_face_getIFNoEdge(CCGFace *f,
CCGEdge *e,
int f_ed_idx,
int lvl,
- int eX, int eY,
+ int eX,
+ int eY,
int levels,
int dataSize,
int normalDataOffset)
{
- return (float *) ((byte *) ccg_face_getIFCoEdge(f, e, f_ed_idx, lvl, eX, eY, levels, dataSize) + normalDataOffset);
+ return (float *)((byte *)ccg_face_getIFCoEdge(f, e, f_ed_idx, lvl, eX, eY, levels, dataSize) +
+ normalDataOffset);
}
-static void _face_calcIFNo(CCGFace *f,
- int lvl,
- int S,
- int x, int y,
- float no[3],
- int levels,
- int dataSize)
+static void _face_calcIFNo(
+ CCGFace *f, int lvl, int S, int x, int y, float no[3], int levels, int dataSize)
{
- float *a = ccg_face_getIFCo(f, lvl, S, x + 0, y + 0, levels, dataSize);
- float *b = ccg_face_getIFCo(f, lvl, S, x + 1, y + 0, levels, dataSize);
- float *c = ccg_face_getIFCo(f, lvl, S, x + 1, y + 1, levels, dataSize);
- float *d = ccg_face_getIFCo(f, lvl, S, x + 0, y + 1, levels, dataSize);
- float a_cX = c[0] - a[0], a_cY = c[1] - a[1], a_cZ = c[2] - a[2];
- float b_dX = d[0] - b[0], b_dY = d[1] - b[1], b_dZ = d[2] - b[2];
-
- no[0] = b_dY * a_cZ - b_dZ * a_cY;
- no[1] = b_dZ * a_cX - b_dX * a_cZ;
- no[2] = b_dX * a_cY - b_dY * a_cX;
-
- Normalize(no);
+ float *a = ccg_face_getIFCo(f, lvl, S, x + 0, y + 0, levels, dataSize);
+ float *b = ccg_face_getIFCo(f, lvl, S, x + 1, y + 0, levels, dataSize);
+ float *c = ccg_face_getIFCo(f, lvl, S, x + 1, y + 1, levels, dataSize);
+ float *d = ccg_face_getIFCo(f, lvl, S, x + 0, y + 1, levels, dataSize);
+ float a_cX = c[0] - a[0], a_cY = c[1] - a[1], a_cZ = c[2] - a[2];
+ float b_dX = d[0] - b[0], b_dY = d[1] - b[1], b_dZ = d[2] - b[2];
+
+ no[0] = b_dY * a_cZ - b_dZ * a_cY;
+ no[1] = b_dZ * a_cX - b_dX * a_cZ;
+ no[2] = b_dX * a_cY - b_dY * a_cX;
+
+ Normalize(no);
}
static int VERT_seam(const CCGVert *v)
{
- return ((v->flags & Vert_eSeam) != 0);
+ return ((v->flags & Vert_eSeam) != 0);
}
static float EDGE_getSharpness(CCGEdge *e, int lvl)
{
- if (!lvl)
- return e->crease;
- else if (!e->crease)
- return 0.0f;
- else if (e->crease - lvl < 0.0f)
- return 0.0f;
- else
- return e->crease - lvl;
+ if (!lvl)
+ return e->crease;
+ else if (!e->crease)
+ return 0.0f;
+ else if (e->crease - lvl < 0.0f)
+ return 0.0f;
+ else
+ return e->crease - lvl;
}
-
-
typedef struct CCGSubSurfCalcSubdivData {
- CCGSubSurf *ss;
- CCGVert **effectedV;
- CCGEdge **effectedE;
- CCGFace **effectedF;
- int numEffectedV;
- int numEffectedE;
- int numEffectedF;
-
- int curLvl;
+ CCGSubSurf *ss;
+ CCGVert **effectedV;
+ CCGEdge **effectedE;
+ CCGFace **effectedF;
+ int numEffectedV;
+ int numEffectedE;
+ int numEffectedF;
+
+ int curLvl;
} CCGSubSurfCalcSubdivData;
static void ccgSubSurf__calcVertNormals_faces_accumulate_cb(
- void *__restrict userdata,
- const int ptrIdx,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+ void *__restrict userdata, const int ptrIdx, const ParallelRangeTLS *__restrict UNUSED(tls))
{
- CCGSubSurfCalcSubdivData *data = userdata;
-
- CCGSubSurf *ss = data->ss;
- CCGFace *f = data->effectedF[ptrIdx];
-
- const int subdivLevels = ss->subdivLevels;
- const int lvl = ss->subdivLevels;
- const int gridSize = ccg_gridsize(lvl);
- const int normalDataOffset = ss->normalDataOffset;
- const int vertDataSize = ss->meshIFC.vertDataSize;
-
- int S, x, y;
- float no[3];
-
- for (S = 0; S < f->numVerts; S++) {
- for (y = 0; y < gridSize - 1; y++) {
- for (x = 0; x < gridSize - 1; x++) {
- NormZero(FACE_getIFNo(f, lvl, S, x, y));
- }
- }
-
- if (FACE_getEdges(f)[(S - 1 + f->numVerts) % f->numVerts]->flags & Edge_eEffected) {
- for (x = 0; x < gridSize - 1; x++) {
- NormZero(FACE_getIFNo(f, lvl, S, x, gridSize - 1));
- }
- }
- if (FACE_getEdges(f)[S]->flags & Edge_eEffected) {
- for (y = 0; y < gridSize - 1; y++) {
- NormZero(FACE_getIFNo(f, lvl, S, gridSize - 1, y));
- }
- }
- if (FACE_getVerts(f)[S]->flags & Vert_eEffected) {
- NormZero(FACE_getIFNo(f, lvl, S, gridSize - 1, gridSize - 1));
- }
- }
-
- for (S = 0; S < f->numVerts; S++) {
- int yLimit = !(FACE_getEdges(f)[(S - 1 + f->numVerts) % f->numVerts]->flags & Edge_eEffected);
- int xLimit = !(FACE_getEdges(f)[S]->flags & Edge_eEffected);
- int yLimitNext = xLimit;
- int xLimitPrev = yLimit;
-
- for (y = 0; y < gridSize - 1; y++) {
- for (x = 0; x < gridSize - 1; x++) {
- int xPlusOk = (!xLimit || x < gridSize - 2);
- int yPlusOk = (!yLimit || y < gridSize - 2);
-
- FACE_calcIFNo(f, lvl, S, x, y, no);
-
- NormAdd(FACE_getIFNo(f, lvl, S, x + 0, y + 0), no);
- if (xPlusOk)
- NormAdd(FACE_getIFNo(f, lvl, S, x + 1, y + 0), no);
- if (yPlusOk)
- NormAdd(FACE_getIFNo(f, lvl, S, x + 0, y + 1), no);
- if (xPlusOk && yPlusOk) {
- if (x < gridSize - 2 || y < gridSize - 2 || FACE_getVerts(f)[S]->flags & Vert_eEffected) {
- NormAdd(FACE_getIFNo(f, lvl, S, x + 1, y + 1), no);
- }
- }
-
- if (x == 0 && y == 0) {
- int K;
-
- if (!yLimitNext || 1 < gridSize - 1)
- NormAdd(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, 1), no);
- if (!xLimitPrev || 1 < gridSize - 1)
- NormAdd(FACE_getIFNo(f, lvl, (S - 1 + f->numVerts) % f->numVerts, 1, 0), no);
-
- for (K = 0; K < f->numVerts; K++) {
- if (K != S) {
- NormAdd(FACE_getIFNo(f, lvl, K, 0, 0), no);
- }
- }
- }
- else if (y == 0) {
- NormAdd(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, x), no);
- if (!yLimitNext || x < gridSize - 2)
- NormAdd(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, x + 1), no);
- }
- else if (x == 0) {
- NormAdd(FACE_getIFNo(f, lvl, (S - 1 + f->numVerts) % f->numVerts, y, 0), no);
- if (!xLimitPrev || y < gridSize - 2)
- NormAdd(FACE_getIFNo(f, lvl, (S - 1 + f->numVerts) % f->numVerts, y + 1, 0), no);
- }
- }
- }
- }
+ CCGSubSurfCalcSubdivData *data = userdata;
+
+ CCGSubSurf *ss = data->ss;
+ CCGFace *f = data->effectedF[ptrIdx];
+
+ const int subdivLevels = ss->subdivLevels;
+ const int lvl = ss->subdivLevels;
+ const int gridSize = ccg_gridsize(lvl);
+ const int normalDataOffset = ss->normalDataOffset;
+ const int vertDataSize = ss->meshIFC.vertDataSize;
+
+ int S, x, y;
+ float no[3];
+
+ for (S = 0; S < f->numVerts; S++) {
+ for (y = 0; y < gridSize - 1; y++) {
+ for (x = 0; x < gridSize - 1; x++) {
+ NormZero(FACE_getIFNo(f, lvl, S, x, y));
+ }
+ }
+
+ if (FACE_getEdges(f)[(S - 1 + f->numVerts) % f->numVerts]->flags & Edge_eEffected) {
+ for (x = 0; x < gridSize - 1; x++) {
+ NormZero(FACE_getIFNo(f, lvl, S, x, gridSize - 1));
+ }
+ }
+ if (FACE_getEdges(f)[S]->flags & Edge_eEffected) {
+ for (y = 0; y < gridSize - 1; y++) {
+ NormZero(FACE_getIFNo(f, lvl, S, gridSize - 1, y));
+ }
+ }
+ if (FACE_getVerts(f)[S]->flags & Vert_eEffected) {
+ NormZero(FACE_getIFNo(f, lvl, S, gridSize - 1, gridSize - 1));
+ }
+ }
+
+ for (S = 0; S < f->numVerts; S++) {
+ int yLimit = !(FACE_getEdges(f)[(S - 1 + f->numVerts) % f->numVerts]->flags & Edge_eEffected);
+ int xLimit = !(FACE_getEdges(f)[S]->flags & Edge_eEffected);
+ int yLimitNext = xLimit;
+ int xLimitPrev = yLimit;
+
+ for (y = 0; y < gridSize - 1; y++) {
+ for (x = 0; x < gridSize - 1; x++) {
+ int xPlusOk = (!xLimit || x < gridSize - 2);
+ int yPlusOk = (!yLimit || y < gridSize - 2);
+
+ FACE_calcIFNo(f, lvl, S, x, y, no);
+
+ NormAdd(FACE_getIFNo(f, lvl, S, x + 0, y + 0), no);
+ if (xPlusOk)
+ NormAdd(FACE_getIFNo(f, lvl, S, x + 1, y + 0), no);
+ if (yPlusOk)
+ NormAdd(FACE_getIFNo(f, lvl, S, x + 0, y + 1), no);
+ if (xPlusOk && yPlusOk) {
+ if (x < gridSize - 2 || y < gridSize - 2 ||
+ FACE_getVerts(f)[S]->flags & Vert_eEffected) {
+ NormAdd(FACE_getIFNo(f, lvl, S, x + 1, y + 1), no);
+ }
+ }
+
+ if (x == 0 && y == 0) {
+ int K;
+
+ if (!yLimitNext || 1 < gridSize - 1)
+ NormAdd(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, 1), no);
+ if (!xLimitPrev || 1 < gridSize - 1)
+ NormAdd(FACE_getIFNo(f, lvl, (S - 1 + f->numVerts) % f->numVerts, 1, 0), no);
+
+ for (K = 0; K < f->numVerts; K++) {
+ if (K != S) {
+ NormAdd(FACE_getIFNo(f, lvl, K, 0, 0), no);
+ }
+ }
+ }
+ else if (y == 0) {
+ NormAdd(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, x), no);
+ if (!yLimitNext || x < gridSize - 2)
+ NormAdd(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, x + 1), no);
+ }
+ else if (x == 0) {
+ NormAdd(FACE_getIFNo(f, lvl, (S - 1 + f->numVerts) % f->numVerts, y, 0), no);
+ if (!xLimitPrev || y < gridSize - 2)
+ NormAdd(FACE_getIFNo(f, lvl, (S - 1 + f->numVerts) % f->numVerts, y + 1, 0), no);
+ }
+ }
+ }
+ }
}
static void ccgSubSurf__calcVertNormals_faces_finalize_cb(
- void *__restrict userdata,
- const int ptrIdx,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+ void *__restrict userdata, const int ptrIdx, const ParallelRangeTLS *__restrict UNUSED(tls))
{
- CCGSubSurfCalcSubdivData *data = userdata;
-
- CCGSubSurf *ss = data->ss;
- CCGFace *f = data->effectedF[ptrIdx];
-
- const int subdivLevels = ss->subdivLevels;
- const int lvl = ss->subdivLevels;
- const int gridSize = ccg_gridsize(lvl);
- const int normalDataOffset = ss->normalDataOffset;
- const int vertDataSize = ss->meshIFC.vertDataSize;
-
- int S, x, y;
-
- for (S = 0; S < f->numVerts; S++) {
- NormCopy(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, gridSize - 1),
- FACE_getIFNo(f, lvl, S, gridSize - 1, 0));
- }
-
- for (S = 0; S < f->numVerts; S++) {
- for (y = 0; y < gridSize; y++) {
- for (x = 0; x < gridSize; x++) {
- float *no = FACE_getIFNo(f, lvl, S, x, y);
- Normalize(no);
- }
- }
-
- VertDataCopy((float *)((byte *)FACE_getCenterData(f) + normalDataOffset),
- FACE_getIFNo(f, lvl, S, 0, 0), ss);
-
- for (x = 1; x < gridSize - 1; x++) {
- NormCopy(FACE_getIENo(f, lvl, S, x),
- FACE_getIFNo(f, lvl, S, x, 0));
- }
- }
+ CCGSubSurfCalcSubdivData *data = userdata;
+
+ CCGSubSurf *ss = data->ss;
+ CCGFace *f = data->effectedF[ptrIdx];
+
+ const int subdivLevels = ss->subdivLevels;
+ const int lvl = ss->subdivLevels;
+ const int gridSize = ccg_gridsize(lvl);
+ const int normalDataOffset = ss->normalDataOffset;
+ const int vertDataSize = ss->meshIFC.vertDataSize;
+
+ int S, x, y;
+
+ for (S = 0; S < f->numVerts; S++) {
+ NormCopy(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, gridSize - 1),
+ FACE_getIFNo(f, lvl, S, gridSize - 1, 0));
+ }
+
+ for (S = 0; S < f->numVerts; S++) {
+ for (y = 0; y < gridSize; y++) {
+ for (x = 0; x < gridSize; x++) {
+ float *no = FACE_getIFNo(f, lvl, S, x, y);
+ Normalize(no);
+ }
+ }
+
+ VertDataCopy((float *)((byte *)FACE_getCenterData(f) + normalDataOffset),
+ FACE_getIFNo(f, lvl, S, 0, 0),
+ ss);
+
+ for (x = 1; x < gridSize - 1; x++) {
+ NormCopy(FACE_getIENo(f, lvl, S, x), FACE_getIFNo(f, lvl, S, x, 0));
+ }
+ }
}
static void ccgSubSurf__calcVertNormals_edges_accumulate_cb(
- void *__restrict userdata,
- const int ptrIdx,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+ void *__restrict userdata, const int ptrIdx, const ParallelRangeTLS *__restrict UNUSED(tls))
{
- CCGSubSurfCalcSubdivData *data = userdata;
-
- CCGSubSurf *ss = data->ss;
- CCGEdge *e = data->effectedE[ptrIdx];
-
- const int subdivLevels = ss->subdivLevels;
- const int lvl = ss->subdivLevels;
- const int edgeSize = ccg_edgesize(lvl);
- const int normalDataOffset = ss->normalDataOffset;
- const int vertDataSize = ss->meshIFC.vertDataSize;
-
- if (e->numFaces) {
- CCGFace *fLast = e->faces[e->numFaces - 1];
- int x, i;
-
- for (i = 0; i < e->numFaces - 1; i++) {
- CCGFace *f = e->faces[i];
- const int f_ed_idx = ccg_face_getEdgeIndex(f, e);
- const int f_ed_idx_last = ccg_face_getEdgeIndex(fLast, e);
-
- for (x = 1; x < edgeSize - 1; x++) {
- NormAdd(_face_getIFNoEdge(fLast, e, f_ed_idx_last, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset),
- _face_getIFNoEdge(f, e, f_ed_idx, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset));
- }
- }
-
- for (i = 0; i < e->numFaces - 1; i++) {
- CCGFace *f = e->faces[i];
- const int f_ed_idx = ccg_face_getEdgeIndex(f, e);
- const int f_ed_idx_last = ccg_face_getEdgeIndex(fLast, e);
-
- for (x = 1; x < edgeSize - 1; x++) {
- NormCopy(_face_getIFNoEdge(f, e, f_ed_idx, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset),
- _face_getIFNoEdge(fLast, e, f_ed_idx_last, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset));
- }
- }
- }
+ CCGSubSurfCalcSubdivData *data = userdata;
+
+ CCGSubSurf *ss = data->ss;
+ CCGEdge *e = data->effectedE[ptrIdx];
+
+ const int subdivLevels = ss->subdivLevels;
+ const int lvl = ss->subdivLevels;
+ const int edgeSize = ccg_edgesize(lvl);
+ const int normalDataOffset = ss->normalDataOffset;
+ const int vertDataSize = ss->meshIFC.vertDataSize;
+
+ if (e->numFaces) {
+ CCGFace *fLast = e->faces[e->numFaces - 1];
+ int x, i;
+
+ for (i = 0; i < e->numFaces - 1; i++) {
+ CCGFace *f = e->faces[i];
+ const int f_ed_idx = ccg_face_getEdgeIndex(f, e);
+ const int f_ed_idx_last = ccg_face_getEdgeIndex(fLast, e);
+
+ for (x = 1; x < edgeSize - 1; x++) {
+ NormAdd(
+ _face_getIFNoEdge(
+ fLast, e, f_ed_idx_last, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset),
+ _face_getIFNoEdge(
+ f, e, f_ed_idx, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset));
+ }
+ }
+
+ for (i = 0; i < e->numFaces - 1; i++) {
+ CCGFace *f = e->faces[i];
+ const int f_ed_idx = ccg_face_getEdgeIndex(f, e);
+ const int f_ed_idx_last = ccg_face_getEdgeIndex(fLast, e);
+
+ for (x = 1; x < edgeSize - 1; x++) {
+ NormCopy(
+ _face_getIFNoEdge(
+ f, e, f_ed_idx, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset),
+ _face_getIFNoEdge(
+ fLast, e, f_ed_idx_last, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset));
+ }
+ }
+ }
}
static void ccgSubSurf__calcVertNormals(CCGSubSurf *ss,
- CCGVert **effectedV, CCGEdge **effectedE, CCGFace **effectedF,
- int numEffectedV, int numEffectedE, int numEffectedF)
+ CCGVert **effectedV,
+ CCGEdge **effectedE,
+ CCGFace **effectedF,
+ int numEffectedV,
+ int numEffectedE,
+ int numEffectedF)
{
- int i, ptrIdx;
- const int subdivLevels = ss->subdivLevels;
- const int lvl = ss->subdivLevels;
- const int edgeSize = ccg_edgesize(lvl);
- const int gridSize = ccg_gridsize(lvl);
- const int normalDataOffset = ss->normalDataOffset;
- const int vertDataSize = ss->meshIFC.vertDataSize;
-
- CCGSubSurfCalcSubdivData data = {
- .ss = ss,
- .effectedV = effectedV,
- .effectedE = effectedE,
- .effectedF = effectedF,
- .numEffectedV = numEffectedV,
- .numEffectedE = numEffectedE,
- .numEffectedF = numEffectedF,
- };
-
- {
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.min_iter_per_thread = CCG_TASK_LIMIT;
- BLI_task_parallel_range(0, numEffectedF,
- &data,
- ccgSubSurf__calcVertNormals_faces_accumulate_cb,
- &settings);
- }
-
- /* XXX can I reduce the number of normalisations here? */
- for (ptrIdx = 0; ptrIdx < numEffectedV; ptrIdx++) {
- CCGVert *v = (CCGVert *) effectedV[ptrIdx];
- float *no = VERT_getNo(v, lvl);
-
- NormZero(no);
-
- for (i = 0; i < v->numFaces; i++) {
- CCGFace *f = v->faces[i];
- NormAdd(no, FACE_getIFNo(f, lvl, ccg_face_getVertIndex(f, v), gridSize - 1, gridSize - 1));
- }
-
- if (UNLIKELY(v->numFaces == 0)) {
- NormCopy(no, VERT_getCo(v, lvl));
- }
-
- Normalize(no);
-
- for (i = 0; i < v->numFaces; i++) {
- CCGFace *f = v->faces[i];
- NormCopy(FACE_getIFNo(f, lvl, ccg_face_getVertIndex(f, v), gridSize - 1, gridSize - 1), no);
- }
- }
-
- {
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.min_iter_per_thread = CCG_TASK_LIMIT;
- BLI_task_parallel_range(0, numEffectedE,
- &data,
- ccgSubSurf__calcVertNormals_edges_accumulate_cb,
- &settings);
- }
-
- {
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.min_iter_per_thread = CCG_TASK_LIMIT;
- BLI_task_parallel_range(0, numEffectedF,
- &data,
- ccgSubSurf__calcVertNormals_faces_finalize_cb,
- &settings);
- }
-
- for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) {
- CCGEdge *e = (CCGEdge *) effectedE[ptrIdx];
-
- if (e->numFaces) {
- CCGFace *f = e->faces[0];
- int x;
- const int f_ed_idx = ccg_face_getEdgeIndex(f, e);
-
- for (x = 0; x < edgeSize; x++)
- NormCopy(EDGE_getNo(e, lvl, x),
- _face_getIFNoEdge(f, e, f_ed_idx, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset));
- }
- else {
- /* set to zero here otherwise the normals are uninitialized memory
- * render: tests/animation/knight.blend with valgrind.
- * we could be more clever and interpolate vertex normals but these are
- * most likely not used so just zero out. */
- int x;
-
- for (x = 0; x < edgeSize; x++) {
- float *no = EDGE_getNo(e, lvl, x);
- NormCopy(no, EDGE_getCo(e, lvl, x));
- Normalize(no);
- }
- }
- }
+ int i, ptrIdx;
+ const int subdivLevels = ss->subdivLevels;
+ const int lvl = ss->subdivLevels;
+ const int edgeSize = ccg_edgesize(lvl);
+ const int gridSize = ccg_gridsize(lvl);
+ const int normalDataOffset = ss->normalDataOffset;
+ const int vertDataSize = ss->meshIFC.vertDataSize;
+
+ CCGSubSurfCalcSubdivData data = {
+ .ss = ss,
+ .effectedV = effectedV,
+ .effectedE = effectedE,
+ .effectedF = effectedF,
+ .numEffectedV = numEffectedV,
+ .numEffectedE = numEffectedE,
+ .numEffectedF = numEffectedF,
+ };
+
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.min_iter_per_thread = CCG_TASK_LIMIT;
+ BLI_task_parallel_range(
+ 0, numEffectedF, &data, ccgSubSurf__calcVertNormals_faces_accumulate_cb, &settings);
+ }
+
+ /* XXX can I reduce the number of normalisations here? */
+ for (ptrIdx = 0; ptrIdx < numEffectedV; ptrIdx++) {
+ CCGVert *v = (CCGVert *)effectedV[ptrIdx];
+ float *no = VERT_getNo(v, lvl);
+
+ NormZero(no);
+
+ for (i = 0; i < v->numFaces; i++) {
+ CCGFace *f = v->faces[i];
+ NormAdd(no, FACE_getIFNo(f, lvl, ccg_face_getVertIndex(f, v), gridSize - 1, gridSize - 1));
+ }
+
+ if (UNLIKELY(v->numFaces == 0)) {
+ NormCopy(no, VERT_getCo(v, lvl));
+ }
+
+ Normalize(no);
+
+ for (i = 0; i < v->numFaces; i++) {
+ CCGFace *f = v->faces[i];
+ NormCopy(FACE_getIFNo(f, lvl, ccg_face_getVertIndex(f, v), gridSize - 1, gridSize - 1), no);
+ }
+ }
+
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.min_iter_per_thread = CCG_TASK_LIMIT;
+ BLI_task_parallel_range(
+ 0, numEffectedE, &data, ccgSubSurf__calcVertNormals_edges_accumulate_cb, &settings);
+ }
+
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.min_iter_per_thread = CCG_TASK_LIMIT;
+ BLI_task_parallel_range(
+ 0, numEffectedF, &data, ccgSubSurf__calcVertNormals_faces_finalize_cb, &settings);
+ }
+
+ for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) {
+ CCGEdge *e = (CCGEdge *)effectedE[ptrIdx];
+
+ if (e->numFaces) {
+ CCGFace *f = e->faces[0];
+ int x;
+ const int f_ed_idx = ccg_face_getEdgeIndex(f, e);
+
+ for (x = 0; x < edgeSize; x++)
+ NormCopy(EDGE_getNo(e, lvl, x),
+ _face_getIFNoEdge(
+ f, e, f_ed_idx, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset));
+ }
+ else {
+ /* set to zero here otherwise the normals are uninitialized memory
+ * render: tests/animation/knight.blend with valgrind.
+ * we could be more clever and interpolate vertex normals but these are
+ * most likely not used so just zero out. */
+ int x;
+
+ for (x = 0; x < edgeSize; x++) {
+ float *no = EDGE_getNo(e, lvl, x);
+ NormCopy(no, EDGE_getCo(e, lvl, x));
+ Normalize(no);
+ }
+ }
+ }
}
-
static void ccgSubSurf__calcSubdivLevel_interior_faces_edges_midpoints_cb(
- void *__restrict userdata,
- const int ptrIdx,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+ void *__restrict userdata, const int ptrIdx, const ParallelRangeTLS *__restrict UNUSED(tls))
{
- CCGSubSurfCalcSubdivData *data = userdata;
-
- CCGSubSurf *ss = data->ss;
- CCGFace *f = data->effectedF[ptrIdx];
-
- const int subdivLevels = ss->subdivLevels;
- const int curLvl = data->curLvl;
- const int nextLvl = curLvl + 1;
- const int gridSize = ccg_gridsize(curLvl);
- const int vertDataSize = ss->meshIFC.vertDataSize;
-
- int S, x, y;
-
- /* interior face midpoints
- * - old interior face points
- */
- for (S = 0; S < f->numVerts; S++) {
- for (y = 0; y < gridSize - 1; y++) {
- for (x = 0; x < gridSize - 1; x++) {
- int fx = 1 + 2 * x;
- int fy = 1 + 2 * y;
- const float *co0 = FACE_getIFCo(f, curLvl, S, x + 0, y + 0);
- const float *co1 = FACE_getIFCo(f, curLvl, S, x + 1, y + 0);
- const float *co2 = FACE_getIFCo(f, curLvl, S, x + 1, y + 1);
- const float *co3 = FACE_getIFCo(f, curLvl, S, x + 0, y + 1);
- float *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
-
- VertDataAvg4(co, co0, co1, co2, co3, ss);
- }
- }
- }
-
- /* interior edge midpoints
- * - old interior edge points
- * - new interior face midpoints
- */
- for (S = 0; S < f->numVerts; S++) {
- for (x = 0; x < gridSize - 1; x++) {
- int fx = x * 2 + 1;
- const float *co0 = FACE_getIECo(f, curLvl, S, x + 0);
- const float *co1 = FACE_getIECo(f, curLvl, S, x + 1);
- const float *co2 = FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx);
- const float *co3 = FACE_getIFCo(f, nextLvl, S, fx, 1);
- float *co = FACE_getIECo(f, nextLvl, S, fx);
-
- VertDataAvg4(co, co0, co1, co2, co3, ss);
- }
-
- /* interior face interior edge midpoints
- * - old interior face points
- * - new interior face midpoints
- */
-
- /* vertical */
- for (x = 1; x < gridSize - 1; x++) {
- for (y = 0; y < gridSize - 1; y++) {
- int fx = x * 2;
- int fy = y * 2 + 1;
- const float *co0 = FACE_getIFCo(f, curLvl, S, x, y + 0);
- const float *co1 = FACE_getIFCo(f, curLvl, S, x, y + 1);
- const float *co2 = FACE_getIFCo(f, nextLvl, S, fx - 1, fy);
- const float *co3 = FACE_getIFCo(f, nextLvl, S, fx + 1, fy);
- float *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
-
- VertDataAvg4(co, co0, co1, co2, co3, ss);
- }
- }
-
- /* horizontal */
- for (y = 1; y < gridSize - 1; y++) {
- for (x = 0; x < gridSize - 1; x++) {
- int fx = x * 2 + 1;
- int fy = y * 2;
- const float *co0 = FACE_getIFCo(f, curLvl, S, x + 0, y);
- const float *co1 = FACE_getIFCo(f, curLvl, S, x + 1, y);
- const float *co2 = FACE_getIFCo(f, nextLvl, S, fx, fy - 1);
- const float *co3 = FACE_getIFCo(f, nextLvl, S, fx, fy + 1);
- float *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
-
- VertDataAvg4(co, co0, co1, co2, co3, ss);
- }
- }
- }
+ CCGSubSurfCalcSubdivData *data = userdata;
+
+ CCGSubSurf *ss = data->ss;
+ CCGFace *f = data->effectedF[ptrIdx];
+
+ const int subdivLevels = ss->subdivLevels;
+ const int curLvl = data->curLvl;
+ const int nextLvl = curLvl + 1;
+ const int gridSize = ccg_gridsize(curLvl);
+ const int vertDataSize = ss->meshIFC.vertDataSize;
+
+ int S, x, y;
+
+ /* interior face midpoints
+ * - old interior face points
+ */
+ for (S = 0; S < f->numVerts; S++) {
+ for (y = 0; y < gridSize - 1; y++) {
+ for (x = 0; x < gridSize - 1; x++) {
+ int fx = 1 + 2 * x;
+ int fy = 1 + 2 * y;
+ const float *co0 = FACE_getIFCo(f, curLvl, S, x + 0, y + 0);
+ const float *co1 = FACE_getIFCo(f, curLvl, S, x + 1, y + 0);
+ const float *co2 = FACE_getIFCo(f, curLvl, S, x + 1, y + 1);
+ const float *co3 = FACE_getIFCo(f, curLvl, S, x + 0, y + 1);
+ float *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
+
+ VertDataAvg4(co, co0, co1, co2, co3, ss);
+ }
+ }
+ }
+
+ /* interior edge midpoints
+ * - old interior edge points
+ * - new interior face midpoints
+ */
+ for (S = 0; S < f->numVerts; S++) {
+ for (x = 0; x < gridSize - 1; x++) {
+ int fx = x * 2 + 1;
+ const float *co0 = FACE_getIECo(f, curLvl, S, x + 0);
+ const float *co1 = FACE_getIECo(f, curLvl, S, x + 1);
+ const float *co2 = FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx);
+ const float *co3 = FACE_getIFCo(f, nextLvl, S, fx, 1);
+ float *co = FACE_getIECo(f, nextLvl, S, fx);
+
+ VertDataAvg4(co, co0, co1, co2, co3, ss);
+ }
+
+ /* interior face interior edge midpoints
+ * - old interior face points
+ * - new interior face midpoints
+ */
+
+ /* vertical */
+ for (x = 1; x < gridSize - 1; x++) {
+ for (y = 0; y < gridSize - 1; y++) {
+ int fx = x * 2;
+ int fy = y * 2 + 1;
+ const float *co0 = FACE_getIFCo(f, curLvl, S, x, y + 0);
+ const float *co1 = FACE_getIFCo(f, curLvl, S, x, y + 1);
+ const float *co2 = FACE_getIFCo(f, nextLvl, S, fx - 1, fy);
+ const float *co3 = FACE_getIFCo(f, nextLvl, S, fx + 1, fy);
+ float *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
+
+ VertDataAvg4(co, co0, co1, co2, co3, ss);
+ }
+ }
+
+ /* horizontal */
+ for (y = 1; y < gridSize - 1; y++) {
+ for (x = 0; x < gridSize - 1; x++) {
+ int fx = x * 2 + 1;
+ int fy = y * 2;
+ const float *co0 = FACE_getIFCo(f, curLvl, S, x + 0, y);
+ const float *co1 = FACE_getIFCo(f, curLvl, S, x + 1, y);
+ const float *co2 = FACE_getIFCo(f, nextLvl, S, fx, fy - 1);
+ const float *co3 = FACE_getIFCo(f, nextLvl, S, fx, fy + 1);
+ float *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
+
+ VertDataAvg4(co, co0, co1, co2, co3, ss);
+ }
+ }
+ }
}
static void ccgSubSurf__calcSubdivLevel_interior_faces_edges_centerpoints_shift_cb(
- void *__restrict userdata,
- const int ptrIdx,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+ void *__restrict userdata, const int ptrIdx, const ParallelRangeTLS *__restrict UNUSED(tls))
{
- CCGSubSurfCalcSubdivData *data = userdata;
-
- CCGSubSurf *ss = data->ss;
- CCGFace *f = data->effectedF[ptrIdx];
-
- const int subdivLevels = ss->subdivLevels;
- const int curLvl = data->curLvl;
- const int nextLvl = curLvl + 1;
- const int gridSize = ccg_gridsize(curLvl);
- const int vertDataSize = ss->meshIFC.vertDataSize;
-
- float *q_thread = alloca(vertDataSize);
- float *r_thread = alloca(vertDataSize);
-
- int S, x, y;
-
- /* interior center point shift
- * - old face center point (shifting)
- * - old interior edge points
- * - new interior face midpoints
- */
- VertDataZero(q_thread, ss);
- for (S = 0; S < f->numVerts; S++) {
- VertDataAdd(q_thread, FACE_getIFCo(f, nextLvl, S, 1, 1), ss);
- }
- VertDataMulN(q_thread, 1.0f / f->numVerts, ss);
- VertDataZero(r_thread, ss);
- for (S = 0; S < f->numVerts; S++) {
- VertDataAdd(r_thread, FACE_getIECo(f, curLvl, S, 1), ss);
- }
- VertDataMulN(r_thread, 1.0f / f->numVerts, ss);
-
- VertDataMulN((float *)FACE_getCenterData(f), f->numVerts - 2.0f, ss);
- VertDataAdd((float *)FACE_getCenterData(f), q_thread, ss);
- VertDataAdd((float *)FACE_getCenterData(f), r_thread, ss);
- VertDataMulN((float *)FACE_getCenterData(f), 1.0f / f->numVerts, ss);
-
- for (S = 0; S < f->numVerts; S++) {
- /* interior face shift
- * - old interior face point (shifting)
- * - new interior edge midpoints
- * - new interior face midpoints
- */
- for (x = 1; x < gridSize - 1; x++) {
- for (y = 1; y < gridSize - 1; y++) {
- int fx = x * 2;
- int fy = y * 2;
- const float *co = FACE_getIFCo(f, curLvl, S, x, y);
- float *nCo = FACE_getIFCo(f, nextLvl, S, fx, fy);
-
- VertDataAvg4(q_thread,
- FACE_getIFCo(f, nextLvl, S, fx - 1, fy - 1),
- FACE_getIFCo(f, nextLvl, S, fx + 1, fy - 1),
- FACE_getIFCo(f, nextLvl, S, fx + 1, fy + 1),
- FACE_getIFCo(f, nextLvl, S, fx - 1, fy + 1),
- ss);
-
- VertDataAvg4(r_thread,
- FACE_getIFCo(f, nextLvl, S, fx - 1, fy + 0),
- FACE_getIFCo(f, nextLvl, S, fx + 1, fy + 0),
- FACE_getIFCo(f, nextLvl, S, fx + 0, fy - 1),
- FACE_getIFCo(f, nextLvl, S, fx + 0, fy + 1),
- ss);
-
- VertDataCopy(nCo, co, ss);
- VertDataSub(nCo, q_thread, ss);
- VertDataMulN(nCo, 0.25f, ss);
- VertDataAdd(nCo, r_thread, ss);
- }
- }
-
- /* interior edge interior shift
- * - old interior edge point (shifting)
- * - new interior edge midpoints
- * - new interior face midpoints
- */
- for (x = 1; x < gridSize - 1; x++) {
- int fx = x * 2;
- const float *co = FACE_getIECo(f, curLvl, S, x);
- float *nCo = FACE_getIECo(f, nextLvl, S, fx);
-
- VertDataAvg4(q_thread,
- FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx - 1),
- FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx + 1),
- FACE_getIFCo(f, nextLvl, S, fx + 1, +1),
- FACE_getIFCo(f, nextLvl, S, fx - 1, +1),
- ss);
-
- VertDataAvg4(r_thread,
- FACE_getIECo(f, nextLvl, S, fx - 1),
- FACE_getIECo(f, nextLvl, S, fx + 1),
- FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx),
- FACE_getIFCo(f, nextLvl, S, fx, 1),
- ss);
-
- VertDataCopy(nCo, co, ss);
- VertDataSub(nCo, q_thread, ss);
- VertDataMulN(nCo, 0.25f, ss);
- VertDataAdd(nCo, r_thread, ss);
- }
- }
+ CCGSubSurfCalcSubdivData *data = userdata;
+
+ CCGSubSurf *ss = data->ss;
+ CCGFace *f = data->effectedF[ptrIdx];
+
+ const int subdivLevels = ss->subdivLevels;
+ const int curLvl = data->curLvl;
+ const int nextLvl = curLvl + 1;
+ const int gridSize = ccg_gridsize(curLvl);
+ const int vertDataSize = ss->meshIFC.vertDataSize;
+
+ float *q_thread = alloca(vertDataSize);
+ float *r_thread = alloca(vertDataSize);
+
+ int S, x, y;
+
+ /* interior center point shift
+ * - old face center point (shifting)
+ * - old interior edge points
+ * - new interior face midpoints
+ */
+ VertDataZero(q_thread, ss);
+ for (S = 0; S < f->numVerts; S++) {
+ VertDataAdd(q_thread, FACE_getIFCo(f, nextLvl, S, 1, 1), ss);
+ }
+ VertDataMulN(q_thread, 1.0f / f->numVerts, ss);
+ VertDataZero(r_thread, ss);
+ for (S = 0; S < f->numVerts; S++) {
+ VertDataAdd(r_thread, FACE_getIECo(f, curLvl, S, 1), ss);
+ }
+ VertDataMulN(r_thread, 1.0f / f->numVerts, ss);
+
+ VertDataMulN((float *)FACE_getCenterData(f), f->numVerts - 2.0f, ss);
+ VertDataAdd((float *)FACE_getCenterData(f), q_thread, ss);
+ VertDataAdd((float *)FACE_getCenterData(f), r_thread, ss);
+ VertDataMulN((float *)FACE_getCenterData(f), 1.0f / f->numVerts, ss);
+
+ for (S = 0; S < f->numVerts; S++) {
+ /* interior face shift
+ * - old interior face point (shifting)
+ * - new interior edge midpoints
+ * - new interior face midpoints
+ */
+ for (x = 1; x < gridSize - 1; x++) {
+ for (y = 1; y < gridSize - 1; y++) {
+ int fx = x * 2;
+ int fy = y * 2;
+ const float *co = FACE_getIFCo(f, curLvl, S, x, y);
+ float *nCo = FACE_getIFCo(f, nextLvl, S, fx, fy);
+
+ VertDataAvg4(q_thread,
+ FACE_getIFCo(f, nextLvl, S, fx - 1, fy - 1),
+ FACE_getIFCo(f, nextLvl, S, fx + 1, fy - 1),
+ FACE_getIFCo(f, nextLvl, S, fx + 1, fy + 1),
+ FACE_getIFCo(f, nextLvl, S, fx - 1, fy + 1),
+ ss);
+
+ VertDataAvg4(r_thread,
+ FACE_getIFCo(f, nextLvl, S, fx - 1, fy + 0),
+ FACE_getIFCo(f, nextLvl, S, fx + 1, fy + 0),
+ FACE_getIFCo(f, nextLvl, S, fx + 0, fy - 1),
+ FACE_getIFCo(f, nextLvl, S, fx + 0, fy + 1),
+ ss);
+
+ VertDataCopy(nCo, co, ss);
+ VertDataSub(nCo, q_thread, ss);
+ VertDataMulN(nCo, 0.25f, ss);
+ VertDataAdd(nCo, r_thread, ss);
+ }
+ }
+
+ /* interior edge interior shift
+ * - old interior edge point (shifting)
+ * - new interior edge midpoints
+ * - new interior face midpoints
+ */
+ for (x = 1; x < gridSize - 1; x++) {
+ int fx = x * 2;
+ const float *co = FACE_getIECo(f, curLvl, S, x);
+ float *nCo = FACE_getIECo(f, nextLvl, S, fx);
+
+ VertDataAvg4(q_thread,
+ FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx - 1),
+ FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx + 1),
+ FACE_getIFCo(f, nextLvl, S, fx + 1, +1),
+ FACE_getIFCo(f, nextLvl, S, fx - 1, +1),
+ ss);
+
+ VertDataAvg4(r_thread,
+ FACE_getIECo(f, nextLvl, S, fx - 1),
+ FACE_getIECo(f, nextLvl, S, fx + 1),
+ FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx),
+ FACE_getIFCo(f, nextLvl, S, fx, 1),
+ ss);
+
+ VertDataCopy(nCo, co, ss);
+ VertDataSub(nCo, q_thread, ss);
+ VertDataMulN(nCo, 0.25f, ss);
+ VertDataAdd(nCo, r_thread, ss);
+ }
+ }
}
static void ccgSubSurf__calcSubdivLevel_verts_copydata_cb(
- void *__restrict userdata,
- const int ptrIdx,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+ void *__restrict userdata, const int ptrIdx, const ParallelRangeTLS *__restrict UNUSED(tls))
{
- CCGSubSurfCalcSubdivData *data = userdata;
-
- CCGSubSurf *ss = data->ss;
- CCGFace *f = data->effectedF[ptrIdx];
-
- const int subdivLevels = ss->subdivLevels;
- const int nextLvl = data->curLvl + 1;
- const int gridSize = ccg_gridsize(nextLvl);
- const int cornerIdx = gridSize - 1;
- const int vertDataSize = ss->meshIFC.vertDataSize;
-
- int S, x;
-
- for (S = 0; S < f->numVerts; S++) {
- CCGEdge *e = FACE_getEdges(f)[S];
- CCGEdge *prevE = FACE_getEdges(f)[(S + f->numVerts - 1) % f->numVerts];
-
- VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 0), (float *)FACE_getCenterData(f), ss);
- VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), (float *)FACE_getCenterData(f), ss);
- VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], nextLvl), ss);
- VertDataCopy(FACE_getIECo(f, nextLvl, S, cornerIdx), EDGE_getCo(FACE_getEdges(f)[S], nextLvl, cornerIdx), ss);
- for (x = 1; x < gridSize - 1; x++) {
- float *co = FACE_getIECo(f, nextLvl, S, x);
- VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, 0), co, ss);
- VertDataCopy(FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 0, x), co, ss);
- }
- for (x = 0; x < gridSize - 1; x++) {
- int eI = gridSize - 1 - x;
- VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, x), _edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, eI, vertDataSize), ss);
- VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, cornerIdx), _edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, eI, vertDataSize), ss);
- }
- }
+ CCGSubSurfCalcSubdivData *data = userdata;
+
+ CCGSubSurf *ss = data->ss;
+ CCGFace *f = data->effectedF[ptrIdx];
+
+ const int subdivLevels = ss->subdivLevels;
+ const int nextLvl = data->curLvl + 1;
+ const int gridSize = ccg_gridsize(nextLvl);
+ const int cornerIdx = gridSize - 1;
+ const int vertDataSize = ss->meshIFC.vertDataSize;
+
+ int S, x;
+
+ for (S = 0; S < f->numVerts; S++) {
+ CCGEdge *e = FACE_getEdges(f)[S];
+ CCGEdge *prevE = FACE_getEdges(f)[(S + f->numVerts - 1) % f->numVerts];
+
+ VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 0), (float *)FACE_getCenterData(f), ss);
+ VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), (float *)FACE_getCenterData(f), ss);
+ VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, cornerIdx),
+ VERT_getCo(FACE_getVerts(f)[S], nextLvl),
+ ss);
+ VertDataCopy(FACE_getIECo(f, nextLvl, S, cornerIdx),
+ EDGE_getCo(FACE_getEdges(f)[S], nextLvl, cornerIdx),
+ ss);
+ for (x = 1; x < gridSize - 1; x++) {
+ float *co = FACE_getIECo(f, nextLvl, S, x);
+ VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, 0), co, ss);
+ VertDataCopy(FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 0, x), co, ss);
+ }
+ for (x = 0; x < gridSize - 1; x++) {
+ int eI = gridSize - 1 - x;
+ VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, x),
+ _edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, eI, vertDataSize),
+ ss);
+ VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, cornerIdx),
+ _edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, eI, vertDataSize),
+ ss);
+ }
+ }
}
-static void ccgSubSurf__calcSubdivLevel(
- CCGSubSurf *ss,
- CCGVert **effectedV, CCGEdge **effectedE, CCGFace **effectedF,
- const int numEffectedV, const int numEffectedE, const int numEffectedF, const int curLvl)
+static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
+ CCGVert **effectedV,
+ CCGEdge **effectedE,
+ CCGFace **effectedF,
+ const int numEffectedV,
+ const int numEffectedE,
+ const int numEffectedF,
+ const int curLvl)
{
- const int subdivLevels = ss->subdivLevels;
- const int nextLvl = curLvl + 1;
- int edgeSize = ccg_edgesize(curLvl);
- int ptrIdx, i;
- const int vertDataSize = ss->meshIFC.vertDataSize;
- float *q = ss->q, *r = ss->r;
-
- CCGSubSurfCalcSubdivData data = {
- .ss = ss,
- .effectedV = effectedV,
- .effectedE = effectedE,
- .effectedF = effectedF,
- .numEffectedV = numEffectedV,
- .numEffectedE = numEffectedE,
- .numEffectedF = numEffectedF,
- .curLvl = curLvl,
- };
-
- {
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.min_iter_per_thread = CCG_TASK_LIMIT;
- BLI_task_parallel_range(0, numEffectedF,
- &data,
- ccgSubSurf__calcSubdivLevel_interior_faces_edges_midpoints_cb,
- &settings);
- }
-
- /* exterior edge midpoints
- * - old exterior edge points
- * - new interior face midpoints
- */
- /* Not worth parallelizing. */
- for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) {
- CCGEdge *e = (CCGEdge *) effectedE[ptrIdx];
- float sharpness = EDGE_getSharpness(e, curLvl);
- int x, j;
-
- if (_edge_isBoundary(e) || sharpness > 1.0f) {
- for (x = 0; x < edgeSize - 1; x++) {
- int fx = x * 2 + 1;
- const float *co0 = EDGE_getCo(e, curLvl, x + 0);
- const float *co1 = EDGE_getCo(e, curLvl, x + 1);
- float *co = EDGE_getCo(e, nextLvl, fx);
-
- VertDataCopy(co, co0, ss);
- VertDataAdd(co, co1, ss);
- VertDataMulN(co, 0.5f, ss);
- }
- }
- else {
- for (x = 0; x < edgeSize - 1; x++) {
- int fx = x * 2 + 1;
- const float *co0 = EDGE_getCo(e, curLvl, x + 0);
- const float *co1 = EDGE_getCo(e, curLvl, x + 1);
- float *co = EDGE_getCo(e, nextLvl, fx);
- int numFaces = 0;
-
- VertDataCopy(q, co0, ss);
- VertDataAdd(q, co1, ss);
-
- for (j = 0; j < e->numFaces; j++) {
- CCGFace *f = e->faces[j];
- const int f_ed_idx = ccg_face_getEdgeIndex(f, e);
- VertDataAdd(q, ccg_face_getIFCoEdge(f, e, f_ed_idx, nextLvl, fx, 1, subdivLevels, vertDataSize), ss);
- numFaces++;
- }
-
- VertDataMulN(q, 1.0f / (2.0f + numFaces), ss);
-
- VertDataCopy(r, co0, ss);
- VertDataAdd(r, co1, ss);
- VertDataMulN(r, 0.5f, ss);
-
- VertDataCopy(co, q, ss);
- VertDataSub(r, q, ss);
- VertDataMulN(r, sharpness, ss);
- VertDataAdd(co, r, ss);
- }
- }
- }
-
- /* exterior vertex shift
- * - old vertex points (shifting)
- * - old exterior edge points
- * - new interior face midpoints
- */
- /* Not worth parallelizing. */
- for (ptrIdx = 0; ptrIdx < numEffectedV; ptrIdx++) {
- CCGVert *v = (CCGVert *) effectedV[ptrIdx];
- const float *co = VERT_getCo(v, curLvl);
- float *nCo = VERT_getCo(v, nextLvl);
- int sharpCount = 0, allSharp = 1;
- float avgSharpness = 0.0;
- int j, seam = VERT_seam(v), seamEdges = 0;
-
- for (j = 0; j < v->numEdges; j++) {
- CCGEdge *e = v->edges[j];
- float sharpness = EDGE_getSharpness(e, curLvl);
-
- if (seam && _edge_isBoundary(e))
- seamEdges++;
-
- if (sharpness != 0.0f) {
- sharpCount++;
- avgSharpness += sharpness;
- }
- else {
- allSharp = 0;
- }
- }
-
- if (sharpCount) {
- avgSharpness /= sharpCount;
- if (avgSharpness > 1.0f) {
- avgSharpness = 1.0f;
- }
- }
-
- if (seamEdges < 2 || seamEdges != v->numEdges)
- seam = 0;
-
- if (!v->numEdges || ss->meshIFC.simpleSubdiv) {
- VertDataCopy(nCo, co, ss);
- }
- else if (_vert_isBoundary(v)) {
- int numBoundary = 0;
-
- VertDataZero(r, ss);
- for (j = 0; j < v->numEdges; j++) {
- CCGEdge *e = v->edges[j];
- if (_edge_isBoundary(e)) {
- VertDataAdd(r, _edge_getCoVert(e, v, curLvl, 1, vertDataSize), ss);
- numBoundary++;
- }
- }
-
- VertDataCopy(nCo, co, ss);
- VertDataMulN(nCo, 0.75f, ss);
- VertDataMulN(r, 0.25f / numBoundary, ss);
- VertDataAdd(nCo, r, ss);
- }
- else {
- const int cornerIdx = (1 + (1 << (curLvl))) - 2;
- int numEdges = 0, numFaces = 0;
-
- VertDataZero(q, ss);
- for (j = 0; j < v->numFaces; j++) {
- CCGFace *f = v->faces[j];
- VertDataAdd(q, FACE_getIFCo(f, nextLvl, ccg_face_getVertIndex(f, v), cornerIdx, cornerIdx), ss);
- numFaces++;
- }
- VertDataMulN(q, 1.0f / numFaces, ss);
- VertDataZero(r, ss);
- for (j = 0; j < v->numEdges; j++) {
- CCGEdge *e = v->edges[j];
- VertDataAdd(r, _edge_getCoVert(e, v, curLvl, 1, vertDataSize), ss);
- numEdges++;
- }
- VertDataMulN(r, 1.0f / numEdges, ss);
-
- VertDataCopy(nCo, co, ss);
- VertDataMulN(nCo, numEdges - 2.0f, ss);
- VertDataAdd(nCo, q, ss);
- VertDataAdd(nCo, r, ss);
- VertDataMulN(nCo, 1.0f / numEdges, ss);
- }
-
- if ((sharpCount > 1 && v->numFaces) || seam) {
- VertDataZero(q, ss);
-
- if (seam) {
- avgSharpness = 1.0f;
- sharpCount = seamEdges;
- allSharp = 1;
- }
-
- for (j = 0; j < v->numEdges; j++) {
- CCGEdge *e = v->edges[j];
- float sharpness = EDGE_getSharpness(e, curLvl);
-
- if (seam) {
- if (_edge_isBoundary(e))
- VertDataAdd(q, _edge_getCoVert(e, v, curLvl, 1, vertDataSize), ss);
- }
- else if (sharpness != 0.0f) {
- VertDataAdd(q, _edge_getCoVert(e, v, curLvl, 1, vertDataSize), ss);
- }
- }
-
- VertDataMulN(q, (float) 1 / sharpCount, ss);
-
- if (sharpCount != 2 || allSharp) {
- /* q = q + (co - q) * avgSharpness */
- VertDataCopy(r, co, ss);
- VertDataSub(r, q, ss);
- VertDataMulN(r, avgSharpness, ss);
- VertDataAdd(q, r, ss);
- }
-
- /* r = co * 0.75 + q * 0.25 */
- VertDataCopy(r, co, ss);
- VertDataMulN(r, 0.75f, ss);
- VertDataMulN(q, 0.25f, ss);
- VertDataAdd(r, q, ss);
-
- /* nCo = nCo + (r - nCo) * avgSharpness */
- VertDataSub(r, nCo, ss);
- VertDataMulN(r, avgSharpness, ss);
- VertDataAdd(nCo, r, ss);
- }
- }
-
- /* exterior edge interior shift
- * - old exterior edge midpoints (shifting)
- * - old exterior edge midpoints
- * - new interior face midpoints
- */
- /* Not worth parallelizing. */
- for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) {
- CCGEdge *e = (CCGEdge *) effectedE[ptrIdx];
- float sharpness = EDGE_getSharpness(e, curLvl);
- int sharpCount = 0;
- float avgSharpness = 0.0;
- int x, j;
-
- if (sharpness != 0.0f) {
- sharpCount = 2;
- avgSharpness += sharpness;
-
- if (avgSharpness > 1.0f) {
- avgSharpness = 1.0f;
- }
- }
- else {
- sharpCount = 0;
- avgSharpness = 0;
- }
-
- if (_edge_isBoundary(e)) {
- for (x = 1; x < edgeSize - 1; x++) {
- int fx = x * 2;
- const float *co = EDGE_getCo(e, curLvl, x);
- float *nCo = EDGE_getCo(e, nextLvl, fx);
-
- /* Average previous level's endpoints */
- VertDataCopy(r, EDGE_getCo(e, curLvl, x - 1), ss);
- VertDataAdd(r, EDGE_getCo(e, curLvl, x + 1), ss);
- VertDataMulN(r, 0.5f, ss);
-
- /* nCo = nCo * 0.75 + r * 0.25 */
- VertDataCopy(nCo, co, ss);
- VertDataMulN(nCo, 0.75f, ss);
- VertDataMulN(r, 0.25f, ss);
- VertDataAdd(nCo, r, ss);
- }
- }
- else {
- for (x = 1; x < edgeSize - 1; x++) {
- int fx = x * 2;
- const float *co = EDGE_getCo(e, curLvl, x);
- float *nCo = EDGE_getCo(e, nextLvl, fx);
- int numFaces = 0;
-
- VertDataZero(q, ss);
- VertDataZero(r, ss);
- VertDataAdd(r, EDGE_getCo(e, curLvl, x - 1), ss);
- VertDataAdd(r, EDGE_getCo(e, curLvl, x + 1), ss);
- for (j = 0; j < e->numFaces; j++) {
- CCGFace *f = e->faces[j];
- int f_ed_idx = ccg_face_getEdgeIndex(f, e);
- VertDataAdd(q, ccg_face_getIFCoEdge(f, e, f_ed_idx, nextLvl, fx - 1, 1, subdivLevels, vertDataSize), ss);
- VertDataAdd(q, ccg_face_getIFCoEdge(f, e, f_ed_idx, nextLvl, fx + 1, 1, subdivLevels, vertDataSize), ss);
-
- VertDataAdd(r, ccg_face_getIFCoEdge(f, e, f_ed_idx, curLvl, x, 1, subdivLevels, vertDataSize), ss);
- numFaces++;
- }
- VertDataMulN(q, 1.0f / (numFaces * 2.0f), ss);
- VertDataMulN(r, 1.0f / (2.0f + numFaces), ss);
-
- VertDataCopy(nCo, co, ss);
- VertDataMulN(nCo, (float) numFaces, ss);
- VertDataAdd(nCo, q, ss);
- VertDataAdd(nCo, r, ss);
- VertDataMulN(nCo, 1.0f / (2 + numFaces), ss);
-
- if (sharpCount == 2) {
- VertDataCopy(q, co, ss);
- VertDataMulN(q, 6.0f, ss);
- VertDataAdd(q, EDGE_getCo(e, curLvl, x - 1), ss);
- VertDataAdd(q, EDGE_getCo(e, curLvl, x + 1), ss);
- VertDataMulN(q, 1 / 8.0f, ss);
-
- VertDataSub(q, nCo, ss);
- VertDataMulN(q, avgSharpness, ss);
- VertDataAdd(nCo, q, ss);
- }
- }
- }
- }
-
- {
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.min_iter_per_thread = CCG_TASK_LIMIT;
- BLI_task_parallel_range(0, numEffectedF,
- &data,
- ccgSubSurf__calcSubdivLevel_interior_faces_edges_centerpoints_shift_cb,
- &settings);
- }
-
- /* copy down */
- edgeSize = ccg_edgesize(nextLvl);
-
- /* Not worth parallelizing. */
- for (i = 0; i < numEffectedE; i++) {
- CCGEdge *e = effectedE[i];
- VertDataCopy(EDGE_getCo(e, nextLvl, 0), VERT_getCo(e->v0, nextLvl), ss);
- VertDataCopy(EDGE_getCo(e, nextLvl, edgeSize - 1), VERT_getCo(e->v1, nextLvl), ss);
- }
-
- {
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.min_iter_per_thread = CCG_TASK_LIMIT;
- BLI_task_parallel_range(0, numEffectedF,
- &data,
- ccgSubSurf__calcSubdivLevel_verts_copydata_cb,
- &settings);
- }
+ const int subdivLevels = ss->subdivLevels;
+ const int nextLvl = curLvl + 1;
+ int edgeSize = ccg_edgesize(curLvl);
+ int ptrIdx, i;
+ const int vertDataSize = ss->meshIFC.vertDataSize;
+ float *q = ss->q, *r = ss->r;
+
+ CCGSubSurfCalcSubdivData data = {
+ .ss = ss,
+ .effectedV = effectedV,
+ .effectedE = effectedE,
+ .effectedF = effectedF,
+ .numEffectedV = numEffectedV,
+ .numEffectedE = numEffectedE,
+ .numEffectedF = numEffectedF,
+ .curLvl = curLvl,
+ };
+
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.min_iter_per_thread = CCG_TASK_LIMIT;
+ BLI_task_parallel_range(0,
+ numEffectedF,
+ &data,
+ ccgSubSurf__calcSubdivLevel_interior_faces_edges_midpoints_cb,
+ &settings);
+ }
+
+ /* exterior edge midpoints
+ * - old exterior edge points
+ * - new interior face midpoints
+ */
+ /* Not worth parallelizing. */
+ for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) {
+ CCGEdge *e = (CCGEdge *)effectedE[ptrIdx];
+ float sharpness = EDGE_getSharpness(e, curLvl);
+ int x, j;
+
+ if (_edge_isBoundary(e) || sharpness > 1.0f) {
+ for (x = 0; x < edgeSize - 1; x++) {
+ int fx = x * 2 + 1;
+ const float *co0 = EDGE_getCo(e, curLvl, x + 0);
+ const float *co1 = EDGE_getCo(e, curLvl, x + 1);
+ float *co = EDGE_getCo(e, nextLvl, fx);
+
+ VertDataCopy(co, co0, ss);
+ VertDataAdd(co, co1, ss);
+ VertDataMulN(co, 0.5f, ss);
+ }
+ }
+ else {
+ for (x = 0; x < edgeSize - 1; x++) {
+ int fx = x * 2 + 1;
+ const float *co0 = EDGE_getCo(e, curLvl, x + 0);
+ const float *co1 = EDGE_getCo(e, curLvl, x + 1);
+ float *co = EDGE_getCo(e, nextLvl, fx);
+ int numFaces = 0;
+
+ VertDataCopy(q, co0, ss);
+ VertDataAdd(q, co1, ss);
+
+ for (j = 0; j < e->numFaces; j++) {
+ CCGFace *f = e->faces[j];
+ const int f_ed_idx = ccg_face_getEdgeIndex(f, e);
+ VertDataAdd(
+ q,
+ ccg_face_getIFCoEdge(f, e, f_ed_idx, nextLvl, fx, 1, subdivLevels, vertDataSize),
+ ss);
+ numFaces++;
+ }
+
+ VertDataMulN(q, 1.0f / (2.0f + numFaces), ss);
+
+ VertDataCopy(r, co0, ss);
+ VertDataAdd(r, co1, ss);
+ VertDataMulN(r, 0.5f, ss);
+
+ VertDataCopy(co, q, ss);
+ VertDataSub(r, q, ss);
+ VertDataMulN(r, sharpness, ss);
+ VertDataAdd(co, r, ss);
+ }
+ }
+ }
+
+ /* exterior vertex shift
+ * - old vertex points (shifting)
+ * - old exterior edge points
+ * - new interior face midpoints
+ */
+ /* Not worth parallelizing. */
+ for (ptrIdx = 0; ptrIdx < numEffectedV; ptrIdx++) {
+ CCGVert *v = (CCGVert *)effectedV[ptrIdx];
+ const float *co = VERT_getCo(v, curLvl);
+ float *nCo = VERT_getCo(v, nextLvl);
+ int sharpCount = 0, allSharp = 1;
+ float avgSharpness = 0.0;
+ int j, seam = VERT_seam(v), seamEdges = 0;
+
+ for (j = 0; j < v->numEdges; j++) {
+ CCGEdge *e = v->edges[j];
+ float sharpness = EDGE_getSharpness(e, curLvl);
+
+ if (seam && _edge_isBoundary(e))
+ seamEdges++;
+
+ if (sharpness != 0.0f) {
+ sharpCount++;
+ avgSharpness += sharpness;
+ }
+ else {
+ allSharp = 0;
+ }
+ }
+
+ if (sharpCount) {
+ avgSharpness /= sharpCount;
+ if (avgSharpness > 1.0f) {
+ avgSharpness = 1.0f;
+ }
+ }
+
+ if (seamEdges < 2 || seamEdges != v->numEdges)
+ seam = 0;
+
+ if (!v->numEdges || ss->meshIFC.simpleSubdiv) {
+ VertDataCopy(nCo, co, ss);
+ }
+ else if (_vert_isBoundary(v)) {
+ int numBoundary = 0;
+
+ VertDataZero(r, ss);
+ for (j = 0; j < v->numEdges; j++) {
+ CCGEdge *e = v->edges[j];
+ if (_edge_isBoundary(e)) {
+ VertDataAdd(r, _edge_getCoVert(e, v, curLvl, 1, vertDataSize), ss);
+ numBoundary++;
+ }
+ }
+
+ VertDataCopy(nCo, co, ss);
+ VertDataMulN(nCo, 0.75f, ss);
+ VertDataMulN(r, 0.25f / numBoundary, ss);
+ VertDataAdd(nCo, r, ss);
+ }
+ else {
+ const int cornerIdx = (1 + (1 << (curLvl))) - 2;
+ int numEdges = 0, numFaces = 0;
+
+ VertDataZero(q, ss);
+ for (j = 0; j < v->numFaces; j++) {
+ CCGFace *f = v->faces[j];
+ VertDataAdd(
+ q, FACE_getIFCo(f, nextLvl, ccg_face_getVertIndex(f, v), cornerIdx, cornerIdx), ss);
+ numFaces++;
+ }
+ VertDataMulN(q, 1.0f / numFaces, ss);
+ VertDataZero(r, ss);
+ for (j = 0; j < v->numEdges; j++) {
+ CCGEdge *e = v->edges[j];
+ VertDataAdd(r, _edge_getCoVert(e, v, curLvl, 1, vertDataSize), ss);
+ numEdges++;
+ }
+ VertDataMulN(r, 1.0f / numEdges, ss);
+
+ VertDataCopy(nCo, co, ss);
+ VertDataMulN(nCo, numEdges - 2.0f, ss);
+ VertDataAdd(nCo, q, ss);
+ VertDataAdd(nCo, r, ss);
+ VertDataMulN(nCo, 1.0f / numEdges, ss);
+ }
+
+ if ((sharpCount > 1 && v->numFaces) || seam) {
+ VertDataZero(q, ss);
+
+ if (seam) {
+ avgSharpness = 1.0f;
+ sharpCount = seamEdges;
+ allSharp = 1;
+ }
+
+ for (j = 0; j < v->numEdges; j++) {
+ CCGEdge *e = v->edges[j];
+ float sharpness = EDGE_getSharpness(e, curLvl);
+
+ if (seam) {
+ if (_edge_isBoundary(e))
+ VertDataAdd(q, _edge_getCoVert(e, v, curLvl, 1, vertDataSize), ss);
+ }
+ else if (sharpness != 0.0f) {
+ VertDataAdd(q, _edge_getCoVert(e, v, curLvl, 1, vertDataSize), ss);
+ }
+ }
+
+ VertDataMulN(q, (float)1 / sharpCount, ss);
+
+ if (sharpCount != 2 || allSharp) {
+ /* q = q + (co - q) * avgSharpness */
+ VertDataCopy(r, co, ss);
+ VertDataSub(r, q, ss);
+ VertDataMulN(r, avgSharpness, ss);
+ VertDataAdd(q, r, ss);
+ }
+
+ /* r = co * 0.75 + q * 0.25 */
+ VertDataCopy(r, co, ss);
+ VertDataMulN(r, 0.75f, ss);
+ VertDataMulN(q, 0.25f, ss);
+ VertDataAdd(r, q, ss);
+
+ /* nCo = nCo + (r - nCo) * avgSharpness */
+ VertDataSub(r, nCo, ss);
+ VertDataMulN(r, avgSharpness, ss);
+ VertDataAdd(nCo, r, ss);
+ }
+ }
+
+ /* exterior edge interior shift
+ * - old exterior edge midpoints (shifting)
+ * - old exterior edge midpoints
+ * - new interior face midpoints
+ */
+ /* Not worth parallelizing. */
+ for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) {
+ CCGEdge *e = (CCGEdge *)effectedE[ptrIdx];
+ float sharpness = EDGE_getSharpness(e, curLvl);
+ int sharpCount = 0;
+ float avgSharpness = 0.0;
+ int x, j;
+
+ if (sharpness != 0.0f) {
+ sharpCount = 2;
+ avgSharpness += sharpness;
+
+ if (avgSharpness > 1.0f) {
+ avgSharpness = 1.0f;
+ }
+ }
+ else {
+ sharpCount = 0;
+ avgSharpness = 0;
+ }
+
+ if (_edge_isBoundary(e)) {
+ for (x = 1; x < edgeSize - 1; x++) {
+ int fx = x * 2;
+ const float *co = EDGE_getCo(e, curLvl, x);
+ float *nCo = EDGE_getCo(e, nextLvl, fx);
+
+ /* Average previous level's endpoints */
+ VertDataCopy(r, EDGE_getCo(e, curLvl, x - 1), ss);
+ VertDataAdd(r, EDGE_getCo(e, curLvl, x + 1), ss);
+ VertDataMulN(r, 0.5f, ss);
+
+ /* nCo = nCo * 0.75 + r * 0.25 */
+ VertDataCopy(nCo, co, ss);
+ VertDataMulN(nCo, 0.75f, ss);
+ VertDataMulN(r, 0.25f, ss);
+ VertDataAdd(nCo, r, ss);
+ }
+ }
+ else {
+ for (x = 1; x < edgeSize - 1; x++) {
+ int fx = x * 2;
+ const float *co = EDGE_getCo(e, curLvl, x);
+ float *nCo = EDGE_getCo(e, nextLvl, fx);
+ int numFaces = 0;
+
+ VertDataZero(q, ss);
+ VertDataZero(r, ss);
+ VertDataAdd(r, EDGE_getCo(e, curLvl, x - 1), ss);
+ VertDataAdd(r, EDGE_getCo(e, curLvl, x + 1), ss);
+ for (j = 0; j < e->numFaces; j++) {
+ CCGFace *f = e->faces[j];
+ int f_ed_idx = ccg_face_getEdgeIndex(f, e);
+ VertDataAdd(
+ q,
+ ccg_face_getIFCoEdge(f, e, f_ed_idx, nextLvl, fx - 1, 1, subdivLevels, vertDataSize),
+ ss);
+ VertDataAdd(
+ q,
+ ccg_face_getIFCoEdge(f, e, f_ed_idx, nextLvl, fx + 1, 1, subdivLevels, vertDataSize),
+ ss);
+
+ VertDataAdd(
+ r,
+ ccg_face_getIFCoEdge(f, e, f_ed_idx, curLvl, x, 1, subdivLevels, vertDataSize),
+ ss);
+ numFaces++;
+ }
+ VertDataMulN(q, 1.0f / (numFaces * 2.0f), ss);
+ VertDataMulN(r, 1.0f / (2.0f + numFaces), ss);
+
+ VertDataCopy(nCo, co, ss);
+ VertDataMulN(nCo, (float)numFaces, ss);
+ VertDataAdd(nCo, q, ss);
+ VertDataAdd(nCo, r, ss);
+ VertDataMulN(nCo, 1.0f / (2 + numFaces), ss);
+
+ if (sharpCount == 2) {
+ VertDataCopy(q, co, ss);
+ VertDataMulN(q, 6.0f, ss);
+ VertDataAdd(q, EDGE_getCo(e, curLvl, x - 1), ss);
+ VertDataAdd(q, EDGE_getCo(e, curLvl, x + 1), ss);
+ VertDataMulN(q, 1 / 8.0f, ss);
+
+ VertDataSub(q, nCo, ss);
+ VertDataMulN(q, avgSharpness, ss);
+ VertDataAdd(nCo, q, ss);
+ }
+ }
+ }
+ }
+
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.min_iter_per_thread = CCG_TASK_LIMIT;
+ BLI_task_parallel_range(0,
+ numEffectedF,
+ &data,
+ ccgSubSurf__calcSubdivLevel_interior_faces_edges_centerpoints_shift_cb,
+ &settings);
+ }
+
+ /* copy down */
+ edgeSize = ccg_edgesize(nextLvl);
+
+ /* Not worth parallelizing. */
+ for (i = 0; i < numEffectedE; i++) {
+ CCGEdge *e = effectedE[i];
+ VertDataCopy(EDGE_getCo(e, nextLvl, 0), VERT_getCo(e->v0, nextLvl), ss);
+ VertDataCopy(EDGE_getCo(e, nextLvl, edgeSize - 1), VERT_getCo(e->v1, nextLvl), ss);
+ }
+
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.min_iter_per_thread = CCG_TASK_LIMIT;
+ BLI_task_parallel_range(
+ 0, numEffectedF, &data, ccgSubSurf__calcSubdivLevel_verts_copydata_cb, &settings);
+ }
}
void ccgSubSurf__sync_legacy(CCGSubSurf *ss)
{
- CCGVert **effectedV;
- CCGEdge **effectedE;
- CCGFace **effectedF;
- int numEffectedV, numEffectedE, numEffectedF;
- int subdivLevels = ss->subdivLevels;
- int vertDataSize = ss->meshIFC.vertDataSize;
- int i, j, ptrIdx, S;
- int curLvl, nextLvl;
- void *q = ss->q, *r = ss->r;
-
- effectedV = MEM_mallocN(sizeof(*effectedV) * ss->vMap->numEntries, "CCGSubsurf effectedV");
- effectedE = MEM_mallocN(sizeof(*effectedE) * ss->eMap->numEntries, "CCGSubsurf effectedE");
- effectedF = MEM_mallocN(sizeof(*effectedF) * ss->fMap->numEntries, "CCGSubsurf effectedF");
- numEffectedV = numEffectedE = numEffectedF = 0;
- for (i = 0; i < ss->vMap->curSize; i++) {
- CCGVert *v = (CCGVert *) ss->vMap->buckets[i];
- for (; v; v = v->next) {
- if (v->flags & Vert_eEffected) {
- effectedV[numEffectedV++] = v;
-
- for (j = 0; j < v->numEdges; j++) {
- CCGEdge *e = v->edges[j];
- if (!(e->flags & Edge_eEffected)) {
- effectedE[numEffectedE++] = e;
- e->flags |= Edge_eEffected;
- }
- }
-
- for (j = 0; j < v->numFaces; j++) {
- CCGFace *f = v->faces[j];
- if (!(f->flags & Face_eEffected)) {
- effectedF[numEffectedF++] = f;
- f->flags |= Face_eEffected;
- }
- }
- }
- }
- }
-
- curLvl = 0;
- nextLvl = curLvl + 1;
-
- for (ptrIdx = 0; ptrIdx < numEffectedF; ptrIdx++) {
- CCGFace *f = effectedF[ptrIdx];
- void *co = FACE_getCenterData(f);
- VertDataZero(co, ss);
- for (i = 0; i < f->numVerts; i++) {
- VertDataAdd(co, VERT_getCo(FACE_getVerts(f)[i], curLvl), ss);
- }
- VertDataMulN(co, 1.0f / f->numVerts, ss);
-
- f->flags = 0;
- }
- for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) {
- CCGEdge *e = effectedE[ptrIdx];
- void *co = EDGE_getCo(e, nextLvl, 1);
- float sharpness = EDGE_getSharpness(e, curLvl);
-
- if (_edge_isBoundary(e) || sharpness >= 1.0f) {
- VertDataCopy(co, VERT_getCo(e->v0, curLvl), ss);
- VertDataAdd(co, VERT_getCo(e->v1, curLvl), ss);
- VertDataMulN(co, 0.5f, ss);
- }
- else {
- int numFaces = 0;
- VertDataCopy(q, VERT_getCo(e->v0, curLvl), ss);
- VertDataAdd(q, VERT_getCo(e->v1, curLvl), ss);
- for (i = 0; i < e->numFaces; i++) {
- CCGFace *f = e->faces[i];
- VertDataAdd(q, (float *)FACE_getCenterData(f), ss);
- numFaces++;
- }
- VertDataMulN(q, 1.0f / (2.0f + numFaces), ss);
-
- VertDataCopy(r, VERT_getCo(e->v0, curLvl), ss);
- VertDataAdd(r, VERT_getCo(e->v1, curLvl), ss);
- VertDataMulN(r, 0.5f, ss);
-
- VertDataCopy(co, q, ss);
- VertDataSub(r, q, ss);
- VertDataMulN(r, sharpness, ss);
- VertDataAdd(co, r, ss);
- }
-
- /* edge flags cleared later */
- }
- for (ptrIdx = 0; ptrIdx < numEffectedV; ptrIdx++) {
- CCGVert *v = effectedV[ptrIdx];
- void *co = VERT_getCo(v, curLvl);
- void *nCo = VERT_getCo(v, nextLvl);
- int sharpCount = 0, allSharp = 1;
- float avgSharpness = 0.0;
- int seam = VERT_seam(v), seamEdges = 0;
-
- for (i = 0; i < v->numEdges; i++) {
- CCGEdge *e = v->edges[i];
- float sharpness = EDGE_getSharpness(e, curLvl);
-
- if (seam && _edge_isBoundary(e))
- seamEdges++;
-
- if (sharpness != 0.0f) {
- sharpCount++;
- avgSharpness += sharpness;
- }
- else {
- allSharp = 0;
- }
- }
-
- if (sharpCount) {
- avgSharpness /= sharpCount;
- if (avgSharpness > 1.0f) {
- avgSharpness = 1.0f;
- }
- }
-
- if (seamEdges < 2 || seamEdges != v->numEdges)
- seam = 0;
-
- if (!v->numEdges || ss->meshIFC.simpleSubdiv) {
- VertDataCopy(nCo, co, ss);
- }
- else if (_vert_isBoundary(v)) {
- int numBoundary = 0;
-
- VertDataZero(r, ss);
- for (i = 0; i < v->numEdges; i++) {
- CCGEdge *e = v->edges[i];
- if (_edge_isBoundary(e)) {
- VertDataAdd(r, VERT_getCo(_edge_getOtherVert(e, v), curLvl), ss);
- numBoundary++;
- }
- }
- VertDataCopy(nCo, co, ss);
- VertDataMulN(nCo, 0.75f, ss);
- VertDataMulN(r, 0.25f / numBoundary, ss);
- VertDataAdd(nCo, r, ss);
- }
- else {
- int numEdges = 0, numFaces = 0;
-
- VertDataZero(q, ss);
- for (i = 0; i < v->numFaces; i++) {
- CCGFace *f = v->faces[i];
- VertDataAdd(q, (float *)FACE_getCenterData(f), ss);
- numFaces++;
- }
- VertDataMulN(q, 1.0f / numFaces, ss);
- VertDataZero(r, ss);
- for (i = 0; i < v->numEdges; i++) {
- CCGEdge *e = v->edges[i];
- VertDataAdd(r, VERT_getCo(_edge_getOtherVert(e, v), curLvl), ss);
- numEdges++;
- }
- VertDataMulN(r, 1.0f / numEdges, ss);
-
- VertDataCopy(nCo, co, ss);
- VertDataMulN(nCo, numEdges - 2.0f, ss);
- VertDataAdd(nCo, q, ss);
- VertDataAdd(nCo, r, ss);
- VertDataMulN(nCo, 1.0f / numEdges, ss);
- }
-
- if (sharpCount > 1 || seam) {
- VertDataZero(q, ss);
-
- if (seam) {
- avgSharpness = 1.0f;
- sharpCount = seamEdges;
- allSharp = 1;
- }
-
- for (i = 0; i < v->numEdges; i++) {
- CCGEdge *e = v->edges[i];
- float sharpness = EDGE_getSharpness(e, curLvl);
-
- if (seam) {
- if (_edge_isBoundary(e)) {
- CCGVert *oV = _edge_getOtherVert(e, v);
- VertDataAdd(q, VERT_getCo(oV, curLvl), ss);
- }
- }
- else if (sharpness != 0.0f) {
- CCGVert *oV = _edge_getOtherVert(e, v);
- VertDataAdd(q, VERT_getCo(oV, curLvl), ss);
- }
- }
-
- VertDataMulN(q, (float) 1 / sharpCount, ss);
-
- if (sharpCount != 2 || allSharp) {
- /* q = q + (co - q) * avgSharpness */
- VertDataCopy(r, co, ss);
- VertDataSub(r, q, ss);
- VertDataMulN(r, avgSharpness, ss);
- VertDataAdd(q, r, ss);
- }
-
- /* r = co * 0.75 + q * 0.25 */
- VertDataCopy(r, co, ss);
- VertDataMulN(r, 0.75f, ss);
- VertDataMulN(q, 0.25f, ss);
- VertDataAdd(r, q, ss);
-
- /* nCo = nCo + (r - nCo) * avgSharpness */
- VertDataSub(r, nCo, ss);
- VertDataMulN(r, avgSharpness, ss);
- VertDataAdd(nCo, r, ss);
- }
-
- /* vert flags cleared later */
- }
-
- if (ss->useAgeCounts) {
- for (i = 0; i < numEffectedV; i++) {
- CCGVert *v = effectedV[i];
- byte *userData = ccgSubSurf_getVertUserData(ss, v);
- *((int *) &userData[ss->vertUserAgeOffset]) = ss->currentAge;
- }
-
- for (i = 0; i < numEffectedE; i++) {
- CCGEdge *e = effectedE[i];
- byte *userData = ccgSubSurf_getEdgeUserData(ss, e);
- *((int *) &userData[ss->edgeUserAgeOffset]) = ss->currentAge;
- }
-
- for (i = 0; i < numEffectedF; i++) {
- CCGFace *f = effectedF[i];
- byte *userData = ccgSubSurf_getFaceUserData(ss, f);
- *((int *) &userData[ss->faceUserAgeOffset]) = ss->currentAge;
- }
- }
-
- for (i = 0; i < numEffectedE; i++) {
- CCGEdge *e = effectedE[i];
- VertDataCopy(EDGE_getCo(e, nextLvl, 0), VERT_getCo(e->v0, nextLvl), ss);
- VertDataCopy(EDGE_getCo(e, nextLvl, 2), VERT_getCo(e->v1, nextLvl), ss);
- }
- for (i = 0; i < numEffectedF; i++) {
- CCGFace *f = effectedF[i];
- for (S = 0; S < f->numVerts; S++) {
- CCGEdge *e = FACE_getEdges(f)[S];
- CCGEdge *prevE = FACE_getEdges(f)[(S + f->numVerts - 1) % f->numVerts];
-
- VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 0), (float *)FACE_getCenterData(f), ss);
- VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), (float *)FACE_getCenterData(f), ss);
- VertDataCopy(FACE_getIFCo(f, nextLvl, S, 1, 1), VERT_getCo(FACE_getVerts(f)[S], nextLvl), ss);
- VertDataCopy(FACE_getIECo(f, nextLvl, S, 1), EDGE_getCo(FACE_getEdges(f)[S], nextLvl, 1), ss);
-
- VertDataCopy(FACE_getIFCo(f, nextLvl, S, 1, 0), _edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, 1, vertDataSize), ss);
- VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 1), _edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, 1, vertDataSize), ss);
- }
- }
-
- for (curLvl = 1; curLvl < subdivLevels; curLvl++)
- ccgSubSurf__calcSubdivLevel(ss,
- effectedV, effectedE, effectedF,
- numEffectedV, numEffectedE, numEffectedF, curLvl);
-
- if (ss->calcVertNormals)
- ccgSubSurf__calcVertNormals(ss,
- effectedV, effectedE, effectedF,
- numEffectedV, numEffectedE, numEffectedF);
-
- for (ptrIdx = 0; ptrIdx < numEffectedV; ptrIdx++) {
- CCGVert *v = effectedV[ptrIdx];
- v->flags = 0;
- }
- for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) {
- CCGEdge *e = effectedE[ptrIdx];
- e->flags = 0;
- }
-
- MEM_freeN(effectedF);
- MEM_freeN(effectedE);
- MEM_freeN(effectedV);
+ CCGVert **effectedV;
+ CCGEdge **effectedE;
+ CCGFace **effectedF;
+ int numEffectedV, numEffectedE, numEffectedF;
+ int subdivLevels = ss->subdivLevels;
+ int vertDataSize = ss->meshIFC.vertDataSize;
+ int i, j, ptrIdx, S;
+ int curLvl, nextLvl;
+ void *q = ss->q, *r = ss->r;
+
+ effectedV = MEM_mallocN(sizeof(*effectedV) * ss->vMap->numEntries, "CCGSubsurf effectedV");
+ effectedE = MEM_mallocN(sizeof(*effectedE) * ss->eMap->numEntries, "CCGSubsurf effectedE");
+ effectedF = MEM_mallocN(sizeof(*effectedF) * ss->fMap->numEntries, "CCGSubsurf effectedF");
+ numEffectedV = numEffectedE = numEffectedF = 0;
+ for (i = 0; i < ss->vMap->curSize; i++) {
+ CCGVert *v = (CCGVert *)ss->vMap->buckets[i];
+ for (; v; v = v->next) {
+ if (v->flags & Vert_eEffected) {
+ effectedV[numEffectedV++] = v;
+
+ for (j = 0; j < v->numEdges; j++) {
+ CCGEdge *e = v->edges[j];
+ if (!(e->flags & Edge_eEffected)) {
+ effectedE[numEffectedE++] = e;
+ e->flags |= Edge_eEffected;
+ }
+ }
+
+ for (j = 0; j < v->numFaces; j++) {
+ CCGFace *f = v->faces[j];
+ if (!(f->flags & Face_eEffected)) {
+ effectedF[numEffectedF++] = f;
+ f->flags |= Face_eEffected;
+ }
+ }
+ }
+ }
+ }
+
+ curLvl = 0;
+ nextLvl = curLvl + 1;
+
+ for (ptrIdx = 0; ptrIdx < numEffectedF; ptrIdx++) {
+ CCGFace *f = effectedF[ptrIdx];
+ void *co = FACE_getCenterData(f);
+ VertDataZero(co, ss);
+ for (i = 0; i < f->numVerts; i++) {
+ VertDataAdd(co, VERT_getCo(FACE_getVerts(f)[i], curLvl), ss);
+ }
+ VertDataMulN(co, 1.0f / f->numVerts, ss);
+
+ f->flags = 0;
+ }
+ for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) {
+ CCGEdge *e = effectedE[ptrIdx];
+ void *co = EDGE_getCo(e, nextLvl, 1);
+ float sharpness = EDGE_getSharpness(e, curLvl);
+
+ if (_edge_isBoundary(e) || sharpness >= 1.0f) {
+ VertDataCopy(co, VERT_getCo(e->v0, curLvl), ss);
+ VertDataAdd(co, VERT_getCo(e->v1, curLvl), ss);
+ VertDataMulN(co, 0.5f, ss);
+ }
+ else {
+ int numFaces = 0;
+ VertDataCopy(q, VERT_getCo(e->v0, curLvl), ss);
+ VertDataAdd(q, VERT_getCo(e->v1, curLvl), ss);
+ for (i = 0; i < e->numFaces; i++) {
+ CCGFace *f = e->faces[i];
+ VertDataAdd(q, (float *)FACE_getCenterData(f), ss);
+ numFaces++;
+ }
+ VertDataMulN(q, 1.0f / (2.0f + numFaces), ss);
+
+ VertDataCopy(r, VERT_getCo(e->v0, curLvl), ss);
+ VertDataAdd(r, VERT_getCo(e->v1, curLvl), ss);
+ VertDataMulN(r, 0.5f, ss);
+
+ VertDataCopy(co, q, ss);
+ VertDataSub(r, q, ss);
+ VertDataMulN(r, sharpness, ss);
+ VertDataAdd(co, r, ss);
+ }
+
+ /* edge flags cleared later */
+ }
+ for (ptrIdx = 0; ptrIdx < numEffectedV; ptrIdx++) {
+ CCGVert *v = effectedV[ptrIdx];
+ void *co = VERT_getCo(v, curLvl);
+ void *nCo = VERT_getCo(v, nextLvl);
+ int sharpCount = 0, allSharp = 1;
+ float avgSharpness = 0.0;
+ int seam = VERT_seam(v), seamEdges = 0;
+
+ for (i = 0; i < v->numEdges; i++) {
+ CCGEdge *e = v->edges[i];
+ float sharpness = EDGE_getSharpness(e, curLvl);
+
+ if (seam && _edge_isBoundary(e))
+ seamEdges++;
+
+ if (sharpness != 0.0f) {
+ sharpCount++;
+ avgSharpness += sharpness;
+ }
+ else {
+ allSharp = 0;
+ }
+ }
+
+ if (sharpCount) {
+ avgSharpness /= sharpCount;
+ if (avgSharpness > 1.0f) {
+ avgSharpness = 1.0f;
+ }
+ }
+
+ if (seamEdges < 2 || seamEdges != v->numEdges)
+ seam = 0;
+
+ if (!v->numEdges || ss->meshIFC.simpleSubdiv) {
+ VertDataCopy(nCo, co, ss);
+ }
+ else if (_vert_isBoundary(v)) {
+ int numBoundary = 0;
+
+ VertDataZero(r, ss);
+ for (i = 0; i < v->numEdges; i++) {
+ CCGEdge *e = v->edges[i];
+ if (_edge_isBoundary(e)) {
+ VertDataAdd(r, VERT_getCo(_edge_getOtherVert(e, v), curLvl), ss);
+ numBoundary++;
+ }
+ }
+ VertDataCopy(nCo, co, ss);
+ VertDataMulN(nCo, 0.75f, ss);
+ VertDataMulN(r, 0.25f / numBoundary, ss);
+ VertDataAdd(nCo, r, ss);
+ }
+ else {
+ int numEdges = 0, numFaces = 0;
+
+ VertDataZero(q, ss);
+ for (i = 0; i < v->numFaces; i++) {
+ CCGFace *f = v->faces[i];
+ VertDataAdd(q, (float *)FACE_getCenterData(f), ss);
+ numFaces++;
+ }
+ VertDataMulN(q, 1.0f / numFaces, ss);
+ VertDataZero(r, ss);
+ for (i = 0; i < v->numEdges; i++) {
+ CCGEdge *e = v->edges[i];
+ VertDataAdd(r, VERT_getCo(_edge_getOtherVert(e, v), curLvl), ss);
+ numEdges++;
+ }
+ VertDataMulN(r, 1.0f / numEdges, ss);
+
+ VertDataCopy(nCo, co, ss);
+ VertDataMulN(nCo, numEdges - 2.0f, ss);
+ VertDataAdd(nCo, q, ss);
+ VertDataAdd(nCo, r, ss);
+ VertDataMulN(nCo, 1.0f / numEdges, ss);
+ }
+
+ if (sharpCount > 1 || seam) {
+ VertDataZero(q, ss);
+
+ if (seam) {
+ avgSharpness = 1.0f;
+ sharpCount = seamEdges;
+ allSharp = 1;
+ }
+
+ for (i = 0; i < v->numEdges; i++) {
+ CCGEdge *e = v->edges[i];
+ float sharpness = EDGE_getSharpness(e, curLvl);
+
+ if (seam) {
+ if (_edge_isBoundary(e)) {
+ CCGVert *oV = _edge_getOtherVert(e, v);
+ VertDataAdd(q, VERT_getCo(oV, curLvl), ss);
+ }
+ }
+ else if (sharpness != 0.0f) {
+ CCGVert *oV = _edge_getOtherVert(e, v);
+ VertDataAdd(q, VERT_getCo(oV, curLvl), ss);
+ }
+ }
+
+ VertDataMulN(q, (float)1 / sharpCount, ss);
+
+ if (sharpCount != 2 || allSharp) {
+ /* q = q + (co - q) * avgSharpness */
+ VertDataCopy(r, co, ss);
+ VertDataSub(r, q, ss);
+ VertDataMulN(r, avgSharpness, ss);
+ VertDataAdd(q, r, ss);
+ }
+
+ /* r = co * 0.75 + q * 0.25 */
+ VertDataCopy(r, co, ss);
+ VertDataMulN(r, 0.75f, ss);
+ VertDataMulN(q, 0.25f, ss);
+ VertDataAdd(r, q, ss);
+
+ /* nCo = nCo + (r - nCo) * avgSharpness */
+ VertDataSub(r, nCo, ss);
+ VertDataMulN(r, avgSharpness, ss);
+ VertDataAdd(nCo, r, ss);
+ }
+
+ /* vert flags cleared later */
+ }
+
+ if (ss->useAgeCounts) {
+ for (i = 0; i < numEffectedV; i++) {
+ CCGVert *v = effectedV[i];
+ byte *userData = ccgSubSurf_getVertUserData(ss, v);
+ *((int *)&userData[ss->vertUserAgeOffset]) = ss->currentAge;
+ }
+
+ for (i = 0; i < numEffectedE; i++) {
+ CCGEdge *e = effectedE[i];
+ byte *userData = ccgSubSurf_getEdgeUserData(ss, e);
+ *((int *)&userData[ss->edgeUserAgeOffset]) = ss->currentAge;
+ }
+
+ for (i = 0; i < numEffectedF; i++) {
+ CCGFace *f = effectedF[i];
+ byte *userData = ccgSubSurf_getFaceUserData(ss, f);
+ *((int *)&userData[ss->faceUserAgeOffset]) = ss->currentAge;
+ }
+ }
+
+ for (i = 0; i < numEffectedE; i++) {
+ CCGEdge *e = effectedE[i];
+ VertDataCopy(EDGE_getCo(e, nextLvl, 0), VERT_getCo(e->v0, nextLvl), ss);
+ VertDataCopy(EDGE_getCo(e, nextLvl, 2), VERT_getCo(e->v1, nextLvl), ss);
+ }
+ for (i = 0; i < numEffectedF; i++) {
+ CCGFace *f = effectedF[i];
+ for (S = 0; S < f->numVerts; S++) {
+ CCGEdge *e = FACE_getEdges(f)[S];
+ CCGEdge *prevE = FACE_getEdges(f)[(S + f->numVerts - 1) % f->numVerts];
+
+ VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 0), (float *)FACE_getCenterData(f), ss);
+ VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), (float *)FACE_getCenterData(f), ss);
+ VertDataCopy(
+ FACE_getIFCo(f, nextLvl, S, 1, 1), VERT_getCo(FACE_getVerts(f)[S], nextLvl), ss);
+ VertDataCopy(
+ FACE_getIECo(f, nextLvl, S, 1), EDGE_getCo(FACE_getEdges(f)[S], nextLvl, 1), ss);
+
+ VertDataCopy(FACE_getIFCo(f, nextLvl, S, 1, 0),
+ _edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, 1, vertDataSize),
+ ss);
+ VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 1),
+ _edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, 1, vertDataSize),
+ ss);
+ }
+ }
+
+ for (curLvl = 1; curLvl < subdivLevels; curLvl++)
+ ccgSubSurf__calcSubdivLevel(
+ ss, effectedV, effectedE, effectedF, numEffectedV, numEffectedE, numEffectedF, curLvl);
+
+ if (ss->calcVertNormals)
+ ccgSubSurf__calcVertNormals(
+ ss, effectedV, effectedE, effectedF, numEffectedV, numEffectedE, numEffectedF);
+
+ for (ptrIdx = 0; ptrIdx < numEffectedV; ptrIdx++) {
+ CCGVert *v = effectedV[ptrIdx];
+ v->flags = 0;
+ }
+ for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) {
+ CCGEdge *e = effectedE[ptrIdx];
+ e->flags = 0;
+ }
+
+ MEM_freeN(effectedF);
+ MEM_freeN(effectedE);
+ MEM_freeN(effectedV);
#ifdef DUMP_RESULT_GRIDS
- ccgSubSurf__dumpCoords(ss);
+ ccgSubSurf__dumpCoords(ss);
#endif
}
@@ -1280,31 +1298,31 @@ void ccgSubSurf__sync_legacy(CCGSubSurf *ss)
/* Update normals for specified faces. */
CCGError ccgSubSurf_updateNormals(CCGSubSurf *ss, CCGFace **effectedF, int numEffectedF)
{
- CCGVert **effectedV;
- CCGEdge **effectedE;
- int i, numEffectedV, numEffectedE, freeF;
-
- ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF);
- ccgSubSurf__effectedFaceNeighbours(ss, effectedF, numEffectedF,
- &effectedV, &numEffectedV, &effectedE, &numEffectedE);
-
- if (ss->calcVertNormals)
- ccgSubSurf__calcVertNormals(ss,
- effectedV, effectedE, effectedF,
- numEffectedV, numEffectedE, numEffectedF);
-
- for (i = 0; i < numEffectedV; i++)
- effectedV[i]->flags = 0;
- for (i = 0; i < numEffectedE; i++)
- effectedE[i]->flags = 0;
- for (i = 0; i < numEffectedF; i++)
- effectedF[i]->flags = 0;
-
- MEM_freeN(effectedE);
- MEM_freeN(effectedV);
- if (freeF) MEM_freeN(effectedF);
-
- return eCCGError_None;
+ CCGVert **effectedV;
+ CCGEdge **effectedE;
+ int i, numEffectedV, numEffectedE, freeF;
+
+ ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF);
+ ccgSubSurf__effectedFaceNeighbours(
+ ss, effectedF, numEffectedF, &effectedV, &numEffectedV, &effectedE, &numEffectedE);
+
+ if (ss->calcVertNormals)
+ ccgSubSurf__calcVertNormals(
+ ss, effectedV, effectedE, effectedF, numEffectedV, numEffectedE, numEffectedF);
+
+ for (i = 0; i < numEffectedV; i++)
+ effectedV[i]->flags = 0;
+ for (i = 0; i < numEffectedE; i++)
+ effectedE[i]->flags = 0;
+ for (i = 0; i < numEffectedF; i++)
+ effectedF[i]->flags = 0;
+
+ MEM_freeN(effectedE);
+ MEM_freeN(effectedV);
+ if (freeF)
+ MEM_freeN(effectedF);
+
+ return eCCGError_None;
}
/* compute subdivision levels from a given starting point, used by
@@ -1312,31 +1330,31 @@ CCGError ccgSubSurf_updateNormals(CCGSubSurf *ss, CCGFace **effectedF, int numEf
* certain level, and then subdividing that up to the highest level */
CCGError ccgSubSurf_updateLevels(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF)
{
- CCGVert **effectedV;
- CCGEdge **effectedE;
- int numEffectedV, numEffectedE, freeF, i;
- int curLvl, subdivLevels = ss->subdivLevels;
-
- ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF);
- ccgSubSurf__effectedFaceNeighbours(ss, effectedF, numEffectedF,
- &effectedV, &numEffectedV, &effectedE, &numEffectedE);
-
- for (curLvl = lvl; curLvl < subdivLevels; curLvl++) {
- ccgSubSurf__calcSubdivLevel(ss,
- effectedV, effectedE, effectedF,
- numEffectedV, numEffectedE, numEffectedF, curLvl);
- }
-
- for (i = 0; i < numEffectedV; i++)
- effectedV[i]->flags = 0;
- for (i = 0; i < numEffectedE; i++)
- effectedE[i]->flags = 0;
- for (i = 0; i < numEffectedF; i++)
- effectedF[i]->flags = 0;
-
- MEM_freeN(effectedE);
- MEM_freeN(effectedV);
- if (freeF) MEM_freeN(effectedF);
-
- return eCCGError_None;
+ CCGVert **effectedV;
+ CCGEdge **effectedE;
+ int numEffectedV, numEffectedE, freeF, i;
+ int curLvl, subdivLevels = ss->subdivLevels;
+
+ ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF);
+ ccgSubSurf__effectedFaceNeighbours(
+ ss, effectedF, numEffectedF, &effectedV, &numEffectedV, &effectedE, &numEffectedE);
+
+ for (curLvl = lvl; curLvl < subdivLevels; curLvl++) {
+ ccgSubSurf__calcSubdivLevel(
+ ss, effectedV, effectedE, effectedF, numEffectedV, numEffectedE, numEffectedF, curLvl);
+ }
+
+ for (i = 0; i < numEffectedV; i++)
+ effectedV[i]->flags = 0;
+ for (i = 0; i < numEffectedE; i++)
+ effectedE[i]->flags = 0;
+ for (i = 0; i < numEffectedF; i++)
+ effectedF[i]->flags = 0;
+
+ MEM_freeN(effectedE);
+ MEM_freeN(effectedV);
+ if (freeF)
+ MEM_freeN(effectedF);
+
+ return eCCGError_None;
}
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
index 7556af4cb9f..973d5415567 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
@@ -20,986 +20,951 @@
#ifdef WITH_OPENSUBDIV
-#include "MEM_guardedalloc.h"
-#include "BLI_sys_types.h" // for intptr_t support
+# include "MEM_guardedalloc.h"
+# include "BLI_sys_types.h" // for intptr_t support
-#include "BLI_utildefines.h" /* for BLI_assert */
-#include "BLI_listbase.h"
-#include "BLI_math.h"
-#include "BLI_threads.h"
+# include "BLI_utildefines.h" /* for BLI_assert */
+# include "BLI_listbase.h"
+# include "BLI_math.h"
+# include "BLI_threads.h"
-#include "CCGSubSurf.h"
-#include "CCGSubSurf_intern.h"
+# include "CCGSubSurf.h"
+# include "CCGSubSurf_intern.h"
-#include "BKE_DerivedMesh.h"
-#include "BKE_subsurf.h"
+# include "BKE_DerivedMesh.h"
+# include "BKE_subsurf.h"
-#include "DNA_userdef_types.h"
+# include "DNA_userdef_types.h"
-#include "opensubdiv_capi.h"
-#include "opensubdiv_converter_capi.h"
-#include "opensubdiv_evaluator_capi.h"
-#include "opensubdiv_gl_mesh_capi.h"
-#include "opensubdiv_topology_refiner_capi.h"
+# include "opensubdiv_capi.h"
+# include "opensubdiv_converter_capi.h"
+# include "opensubdiv_evaluator_capi.h"
+# include "opensubdiv_gl_mesh_capi.h"
+# include "opensubdiv_topology_refiner_capi.h"
-#include "GPU_glew.h"
-#include "GPU_extensions.h"
+# include "GPU_glew.h"
+# include "GPU_extensions.h"
-#define OSD_LOG if (false) printf
+# define OSD_LOG \
+ if (false) \
+ printf
static bool compare_ccg_derivedmesh_topology(CCGSubSurf *ss, DerivedMesh *dm)
{
- const int num_verts = dm->getNumVerts(dm);
- const int num_edges = dm->getNumEdges(dm);
- const int num_polys = dm->getNumPolys(dm);
- const MEdge *medge = dm->getEdgeArray(dm);
- const MLoop *mloop = dm->getLoopArray(dm);
- const MPoly *mpoly = dm->getPolyArray(dm);
-
- /* Quick preliminary tests based on the number of verts and facces. */
- {
- if (num_verts != ss->vMap->numEntries ||
- num_edges != ss->eMap->numEntries ||
- num_polys != ss->fMap->numEntries)
- {
- return false;
- }
- }
-
- /* Rather slow check for faces topology change. */
- {
- CCGFaceIterator ccg_face_iter;
- for (ccgSubSurf_initFaceIterator(ss, &ccg_face_iter);
- !ccgFaceIterator_isStopped(&ccg_face_iter);
- ccgFaceIterator_next(&ccg_face_iter))
- {
- /*const*/ CCGFace *ccg_face = ccgFaceIterator_getCurrent(&ccg_face_iter);
- const int poly_index = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(ccg_face));
- const MPoly *mp = &mpoly[poly_index];
- int corner;
- if (ccg_face->numVerts != mp->totloop) {
- return false;
- }
- for (corner = 0; corner < ccg_face->numVerts; corner++) {
- /*const*/ CCGVert *ccg_vert = FACE_getVerts(ccg_face)[corner];
- const int vert_index = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert));
- if (vert_index != mloop[mp->loopstart + corner].v) {
- return false;
- }
- }
- }
- }
-
- /* Check for edge topology change. */
- {
- CCGEdgeIterator ccg_edge_iter;
- for (ccgSubSurf_initEdgeIterator(ss, &ccg_edge_iter);
- !ccgEdgeIterator_isStopped(&ccg_edge_iter);
- ccgEdgeIterator_next(&ccg_edge_iter))
- {
- /* const */ CCGEdge *ccg_edge = ccgEdgeIterator_getCurrent(&ccg_edge_iter);
- /* const */ CCGVert *ccg_vert1 = ccg_edge->v0;
- /* const */ CCGVert *ccg_vert2 = ccg_edge->v1;
- const int ccg_vert1_index = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert1));
- const int ccg_vert2_index = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert2));
- const int edge_index = POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(ccg_edge));
- const MEdge *me = &medge[edge_index];
- if (me->v1 != ccg_vert1_index || me->v2 != ccg_vert2_index) {
- return false;
- }
- }
- }
-
- /* TODO(sergey): Crease topology changes detection. */
- {
- CCGEdgeIterator ccg_edge_iter;
- for (ccgSubSurf_initEdgeIterator(ss, &ccg_edge_iter);
- !ccgEdgeIterator_isStopped(&ccg_edge_iter);
- ccgEdgeIterator_next(&ccg_edge_iter))
- {
- /* const */ CCGEdge *ccg_edge = ccgEdgeIterator_getCurrent(&ccg_edge_iter);
- const int edge_index = POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(ccg_edge));
- if (ccg_edge->crease != medge[edge_index].crease) {
- return false;
- }
- }
- }
-
- return true;
+ const int num_verts = dm->getNumVerts(dm);
+ const int num_edges = dm->getNumEdges(dm);
+ const int num_polys = dm->getNumPolys(dm);
+ const MEdge *medge = dm->getEdgeArray(dm);
+ const MLoop *mloop = dm->getLoopArray(dm);
+ const MPoly *mpoly = dm->getPolyArray(dm);
+
+ /* Quick preliminary tests based on the number of verts and facces. */
+ {
+ if (num_verts != ss->vMap->numEntries || num_edges != ss->eMap->numEntries ||
+ num_polys != ss->fMap->numEntries) {
+ return false;
+ }
+ }
+
+ /* Rather slow check for faces topology change. */
+ {
+ CCGFaceIterator ccg_face_iter;
+ for (ccgSubSurf_initFaceIterator(ss, &ccg_face_iter);
+ !ccgFaceIterator_isStopped(&ccg_face_iter);
+ ccgFaceIterator_next(&ccg_face_iter)) {
+ /*const*/ CCGFace *ccg_face = ccgFaceIterator_getCurrent(&ccg_face_iter);
+ const int poly_index = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(ccg_face));
+ const MPoly *mp = &mpoly[poly_index];
+ int corner;
+ if (ccg_face->numVerts != mp->totloop) {
+ return false;
+ }
+ for (corner = 0; corner < ccg_face->numVerts; corner++) {
+ /*const*/ CCGVert *ccg_vert = FACE_getVerts(ccg_face)[corner];
+ const int vert_index = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert));
+ if (vert_index != mloop[mp->loopstart + corner].v) {
+ return false;
+ }
+ }
+ }
+ }
+
+ /* Check for edge topology change. */
+ {
+ CCGEdgeIterator ccg_edge_iter;
+ for (ccgSubSurf_initEdgeIterator(ss, &ccg_edge_iter);
+ !ccgEdgeIterator_isStopped(&ccg_edge_iter);
+ ccgEdgeIterator_next(&ccg_edge_iter)) {
+ /* const */ CCGEdge *ccg_edge = ccgEdgeIterator_getCurrent(&ccg_edge_iter);
+ /* const */ CCGVert *ccg_vert1 = ccg_edge->v0;
+ /* const */ CCGVert *ccg_vert2 = ccg_edge->v1;
+ const int ccg_vert1_index = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert1));
+ const int ccg_vert2_index = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert2));
+ const int edge_index = POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(ccg_edge));
+ const MEdge *me = &medge[edge_index];
+ if (me->v1 != ccg_vert1_index || me->v2 != ccg_vert2_index) {
+ return false;
+ }
+ }
+ }
+
+ /* TODO(sergey): Crease topology changes detection. */
+ {
+ CCGEdgeIterator ccg_edge_iter;
+ for (ccgSubSurf_initEdgeIterator(ss, &ccg_edge_iter);
+ !ccgEdgeIterator_isStopped(&ccg_edge_iter);
+ ccgEdgeIterator_next(&ccg_edge_iter)) {
+ /* const */ CCGEdge *ccg_edge = ccgEdgeIterator_getCurrent(&ccg_edge_iter);
+ const int edge_index = POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(ccg_edge));
+ if (ccg_edge->crease != medge[edge_index].crease) {
+ return false;
+ }
+ }
+ }
+
+ return true;
}
static bool compare_osd_derivedmesh_topology(CCGSubSurf *ss, DerivedMesh *dm)
{
- OpenSubdiv_Converter converter;
- bool result;
- if (ss->osd_mesh == NULL && ss->osd_topology_refiner == NULL) {
- return true;
- }
- /* TODO(sergey): De-duplicate with topology counter at the bottom of
- * the file.
- */
- ccgSubSurf_converter_setup_from_derivedmesh(ss, dm, &converter);
- result = openSubdiv_topologyRefinerCompareWithConverter(
- ss->osd_topology_refiner,
- &converter);
- ccgSubSurf_converter_free(&converter);
- return result;
+ OpenSubdiv_Converter converter;
+ bool result;
+ if (ss->osd_mesh == NULL && ss->osd_topology_refiner == NULL) {
+ return true;
+ }
+ /* TODO(sergey): De-duplicate with topology counter at the bottom of
+ * the file.
+ */
+ ccgSubSurf_converter_setup_from_derivedmesh(ss, dm, &converter);
+ result = openSubdiv_topologyRefinerCompareWithConverter(ss->osd_topology_refiner, &converter);
+ ccgSubSurf_converter_free(&converter);
+ return result;
}
static bool opensubdiv_is_topology_changed(CCGSubSurf *ss, DerivedMesh *dm)
{
- if (ss->osd_compute != U.opensubdiv_compute_type) {
- return true;
- }
- if (ss->osd_topology_refiner != NULL) {
- const int levels = ss->osd_topology_refiner->getSubdivisionLevel(
- ss->osd_topology_refiner);
- BLI_assert(ss->osd_mesh_invalid == true);
- if (levels != ss->subdivLevels) {
- return true;
- }
- }
- if (ss->skip_grids == false) {
- return compare_ccg_derivedmesh_topology(ss, dm) == false;
- }
- else {
- return compare_osd_derivedmesh_topology(ss, dm) == false;
- }
- return false;
+ if (ss->osd_compute != U.opensubdiv_compute_type) {
+ return true;
+ }
+ if (ss->osd_topology_refiner != NULL) {
+ const int levels = ss->osd_topology_refiner->getSubdivisionLevel(ss->osd_topology_refiner);
+ BLI_assert(ss->osd_mesh_invalid == true);
+ if (levels != ss->subdivLevels) {
+ return true;
+ }
+ }
+ if (ss->skip_grids == false) {
+ return compare_ccg_derivedmesh_topology(ss, dm) == false;
+ }
+ else {
+ return compare_osd_derivedmesh_topology(ss, dm) == false;
+ }
+ return false;
}
void ccgSubSurf_checkTopologyChanged(CCGSubSurf *ss, DerivedMesh *dm)
{
- if (opensubdiv_is_topology_changed(ss, dm)) {
- /* ** Make sure both GPU and CPU backends are properly reset. ** */
+ if (opensubdiv_is_topology_changed(ss, dm)) {
+ /* ** Make sure both GPU and CPU backends are properly reset. ** */
- ss->osd_coarse_coords_invalid = true;
+ ss->osd_coarse_coords_invalid = true;
- /* Reset GPU part. */
- ss->osd_mesh_invalid = true;
- if (ss->osd_topology_refiner != NULL) {
- openSubdiv_deleteTopologyRefiner(ss->osd_topology_refiner);
- ss->osd_topology_refiner = NULL;
- }
+ /* Reset GPU part. */
+ ss->osd_mesh_invalid = true;
+ if (ss->osd_topology_refiner != NULL) {
+ openSubdiv_deleteTopologyRefiner(ss->osd_topology_refiner);
+ ss->osd_topology_refiner = NULL;
+ }
- /* Reset CPU side. */
- if (ss->osd_evaluator != NULL) {
- openSubdiv_deleteEvaluator(ss->osd_evaluator);
- ss->osd_evaluator = NULL;
- }
- }
+ /* Reset CPU side. */
+ if (ss->osd_evaluator != NULL) {
+ openSubdiv_deleteEvaluator(ss->osd_evaluator);
+ ss->osd_evaluator = NULL;
+ }
+ }
}
static void ccgSubSurf__updateGLMeshCoords(CCGSubSurf *ss)
{
- BLI_assert(ss->meshIFC.numLayers == 3);
- ss->osd_mesh->setCoarsePositions(ss->osd_mesh,
- (float *) ss->osd_coarse_coords,
- 0,
- ss->osd_num_coarse_coords);
-}
-
-bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss,
- bool use_osd_glsl,
- int active_uv_index)
-{
- int compute_type;
-
- switch (U.opensubdiv_compute_type) {
-#define CHECK_COMPUTE_TYPE(type) \
- case USER_OPENSUBDIV_COMPUTE_ ## type: \
- compute_type = OPENSUBDIV_EVALUATOR_ ## type; \
- break;
- CHECK_COMPUTE_TYPE(CPU)
- CHECK_COMPUTE_TYPE(OPENMP)
- CHECK_COMPUTE_TYPE(OPENCL)
- CHECK_COMPUTE_TYPE(CUDA)
- CHECK_COMPUTE_TYPE(GLSL_TRANSFORM_FEEDBACK)
- CHECK_COMPUTE_TYPE(GLSL_COMPUTE)
- default:
- compute_type = OPENSUBDIV_EVALUATOR_CPU;
- break;
-#undef CHECK_COMPUTE_TYPE
- }
-
- if (ss->osd_vao == 0) {
- glGenVertexArrays(1, &ss->osd_vao);
- }
-
- if (ss->osd_mesh_invalid) {
- if (ss->osd_mesh != NULL) {
- ccgSubSurf__delete_osdGLMesh(ss->osd_mesh);
- ss->osd_mesh = NULL;
- }
- ss->osd_mesh_invalid = false;
- }
-
- if (ss->osd_mesh == NULL) {
- if (ss->osd_topology_refiner == NULL) {
- /* Happens with empty meshes. */
- /* TODO(sergey): Add assert that mesh is indeed empty. */
- return false;
- }
-
- ss->osd_mesh = openSubdiv_createOsdGLMeshFromTopologyRefiner(
- ss->osd_topology_refiner,
- compute_type);
-
- if (UNLIKELY(ss->osd_mesh == NULL)) {
- /* Most likely compute device is not available. */
- return false;
- }
-
- ccgSubSurf__updateGLMeshCoords(ss);
- ss->osd_mesh->refine(ss->osd_mesh);
- ss->osd_mesh->synchronize(ss->osd_mesh);
- ss->osd_coarse_coords_invalid = false;
-
- glBindVertexArray(ss->osd_vao);
- ss->osd_mesh->bindVertexBuffer(ss->osd_mesh);
-
- glEnableVertexAttribArray(0);
- glEnableVertexAttribArray(1);
- glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,
- sizeof(GLfloat) * 6, 0);
- glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE,
- sizeof(GLfloat) * 6, (float *)12);
-
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glBindVertexArray(0);
- }
- else if (ss->osd_coarse_coords_invalid) {
- ccgSubSurf__updateGLMeshCoords(ss);
- ss->osd_mesh->refine(ss->osd_mesh);
- ss->osd_mesh->synchronize(ss->osd_mesh);
- ss->osd_coarse_coords_invalid = false;
- }
-
- ss->osd_mesh->prepareDraw(ss->osd_mesh, use_osd_glsl, active_uv_index);
-
- return true;
-}
-
-void ccgSubSurf_drawGLMesh(CCGSubSurf *ss, bool fill_quads,
- int start_partition, int num_partitions)
-{
- if (LIKELY(ss->osd_mesh != NULL)) {
- glBindVertexArray(ss->osd_vao);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
- ss->osd_mesh->getPatchIndexBuffer(ss->osd_mesh));
-
- ss->osd_mesh->bindVertexBuffer(ss->osd_mesh);
- glBindVertexArray(ss->osd_vao);
- ss->osd_mesh->drawPatches(ss->osd_mesh, fill_quads,
- start_partition, num_partitions);
- glBindVertexArray(0);
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- }
+ BLI_assert(ss->meshIFC.numLayers == 3);
+ ss->osd_mesh->setCoarsePositions(
+ ss->osd_mesh, (float *)ss->osd_coarse_coords, 0, ss->osd_num_coarse_coords);
+}
+
+bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, bool use_osd_glsl, int active_uv_index)
+{
+ int compute_type;
+
+ switch (U.opensubdiv_compute_type) {
+# define CHECK_COMPUTE_TYPE(type) \
+ case USER_OPENSUBDIV_COMPUTE_##type: \
+ compute_type = OPENSUBDIV_EVALUATOR_##type; \
+ break;
+ CHECK_COMPUTE_TYPE(CPU)
+ CHECK_COMPUTE_TYPE(OPENMP)
+ CHECK_COMPUTE_TYPE(OPENCL)
+ CHECK_COMPUTE_TYPE(CUDA)
+ CHECK_COMPUTE_TYPE(GLSL_TRANSFORM_FEEDBACK)
+ CHECK_COMPUTE_TYPE(GLSL_COMPUTE)
+ default:
+ compute_type = OPENSUBDIV_EVALUATOR_CPU;
+ break;
+# undef CHECK_COMPUTE_TYPE
+ }
+
+ if (ss->osd_vao == 0) {
+ glGenVertexArrays(1, &ss->osd_vao);
+ }
+
+ if (ss->osd_mesh_invalid) {
+ if (ss->osd_mesh != NULL) {
+ ccgSubSurf__delete_osdGLMesh(ss->osd_mesh);
+ ss->osd_mesh = NULL;
+ }
+ ss->osd_mesh_invalid = false;
+ }
+
+ if (ss->osd_mesh == NULL) {
+ if (ss->osd_topology_refiner == NULL) {
+ /* Happens with empty meshes. */
+ /* TODO(sergey): Add assert that mesh is indeed empty. */
+ return false;
+ }
+
+ ss->osd_mesh = openSubdiv_createOsdGLMeshFromTopologyRefiner(ss->osd_topology_refiner,
+ compute_type);
+
+ if (UNLIKELY(ss->osd_mesh == NULL)) {
+ /* Most likely compute device is not available. */
+ return false;
+ }
+
+ ccgSubSurf__updateGLMeshCoords(ss);
+ ss->osd_mesh->refine(ss->osd_mesh);
+ ss->osd_mesh->synchronize(ss->osd_mesh);
+ ss->osd_coarse_coords_invalid = false;
+
+ glBindVertexArray(ss->osd_vao);
+ ss->osd_mesh->bindVertexBuffer(ss->osd_mesh);
+
+ glEnableVertexAttribArray(0);
+ glEnableVertexAttribArray(1);
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, 0);
+ glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, (float *)12);
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindVertexArray(0);
+ }
+ else if (ss->osd_coarse_coords_invalid) {
+ ccgSubSurf__updateGLMeshCoords(ss);
+ ss->osd_mesh->refine(ss->osd_mesh);
+ ss->osd_mesh->synchronize(ss->osd_mesh);
+ ss->osd_coarse_coords_invalid = false;
+ }
+
+ ss->osd_mesh->prepareDraw(ss->osd_mesh, use_osd_glsl, active_uv_index);
+
+ return true;
+}
+
+void ccgSubSurf_drawGLMesh(CCGSubSurf *ss,
+ bool fill_quads,
+ int start_partition,
+ int num_partitions)
+{
+ if (LIKELY(ss->osd_mesh != NULL)) {
+ glBindVertexArray(ss->osd_vao);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ss->osd_mesh->getPatchIndexBuffer(ss->osd_mesh));
+
+ ss->osd_mesh->bindVertexBuffer(ss->osd_mesh);
+ glBindVertexArray(ss->osd_vao);
+ ss->osd_mesh->drawPatches(ss->osd_mesh, fill_quads, start_partition, num_partitions);
+ glBindVertexArray(0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
}
int ccgSubSurf_getNumGLMeshBaseFaces(CCGSubSurf *ss)
{
- if (ss->osd_topology_refiner != NULL) {
- return ss->osd_topology_refiner->getNumFaces(
- ss->osd_topology_refiner);
- }
- return 0;
+ if (ss->osd_topology_refiner != NULL) {
+ return ss->osd_topology_refiner->getNumFaces(ss->osd_topology_refiner);
+ }
+ return 0;
}
/* Get number of vertices in base faces in a particular GL mesh. */
int ccgSubSurf_getNumGLMeshBaseFaceVerts(CCGSubSurf *ss, int face)
{
- if (ss->osd_topology_refiner != NULL) {
- return ss->osd_topology_refiner->getNumFaceVertices(
- ss->osd_topology_refiner, face);
- }
- return 0;
+ if (ss->osd_topology_refiner != NULL) {
+ return ss->osd_topology_refiner->getNumFaceVertices(ss->osd_topology_refiner, face);
+ }
+ return 0;
}
void ccgSubSurf_setSkipGrids(CCGSubSurf *ss, bool skip_grids)
{
- ss->skip_grids = skip_grids;
+ ss->skip_grids = skip_grids;
}
bool ccgSubSurf_needGrids(CCGSubSurf *ss)
{
- return ss->skip_grids == false;
-}
-
-BLI_INLINE void ccgSubSurf__mapGridToFace(int S, float grid_u, float grid_v,
- float *face_u, float *face_v)
-{
- float u, v;
-
- /* - Each grid covers half of the face along the edges.
- * - Grid's (0, 0) starts from the middle of the face.
- */
- u = 0.5f - 0.5f * grid_u;
- v = 0.5f - 0.5f * grid_v;
-
- if (S == 0) {
- *face_u = v;
- *face_v = u;
- }
- else if (S == 1) {
- *face_u = 1.0f - u;
- *face_v = v;
- }
- else if (S == 2) {
- *face_u = 1.0f - v;
- *face_v = 1.0f - u;
- }
- else {
- *face_u = u;
- *face_v = 1.0f - v;
- }
-}
-
-BLI_INLINE void ccgSubSurf__mapEdgeToFace(int S,
- int edge_segment,
- bool inverse_edge,
- int edgeSize,
- float *face_u, float *face_v)
-{
- int t = inverse_edge ? edgeSize - edge_segment - 1 : edge_segment;
- if (S == 0) {
- *face_u = (float) t / (edgeSize - 1);
- *face_v = 0.0f;
- }
- else if (S == 1) {
- *face_u = 1.0f;
- *face_v = (float) t / (edgeSize - 1);
- }
- else if (S == 2) {
- *face_u = 1.0f - (float) t / (edgeSize - 1);
- *face_v = 1.0f;
- }
- else {
- *face_u = 0.0f;
- *face_v = 1.0f - (float) t / (edgeSize - 1);
- }
-}
-
-void ccgSubSurf_evaluatorSetFVarUV(CCGSubSurf *ss,
- DerivedMesh *dm,
- int layer_index)
-{
- MPoly *mpoly = dm->getPolyArray(dm);
- MLoopUV *mloopuv = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, layer_index);
- int num_polys = dm->getNumPolys(dm);
- int index, poly;
- BLI_assert(ss->osd_evaluator != NULL);
- for (poly = 0, index = 0; poly < num_polys; poly++) {
- int loop;
- MPoly *mp = &mpoly[poly];
- for (loop = 0; loop < mp->totloop; loop++, index++) {
- MLoopUV *mluv = &mloopuv[loop + mp->loopstart];
- (void)mluv;
- /* TODO(sergey): Send mluv->uv to the evaluator's face varying
- * buffer.
- */
- }
- }
- (void)ss;
-}
-
-void ccgSubSurf_evaluatorFVarUV(CCGSubSurf *ss,
- int face_index, int S,
- float grid_u, float grid_v,
- float uv[2])
-{
- float face_u, face_v;
- ccgSubSurf__mapGridToFace(S,
- grid_u, grid_v,
- &face_u, &face_v);
- (void)ss;
- (void)face_index;
- /* TODO(sergey): Evaluate face varying coordinate. */
- zero_v2(uv);
+ return ss->skip_grids == false;
+}
+
+BLI_INLINE void ccgSubSurf__mapGridToFace(
+ int S, float grid_u, float grid_v, float *face_u, float *face_v)
+{
+ float u, v;
+
+ /* - Each grid covers half of the face along the edges.
+ * - Grid's (0, 0) starts from the middle of the face.
+ */
+ u = 0.5f - 0.5f * grid_u;
+ v = 0.5f - 0.5f * grid_v;
+
+ if (S == 0) {
+ *face_u = v;
+ *face_v = u;
+ }
+ else if (S == 1) {
+ *face_u = 1.0f - u;
+ *face_v = v;
+ }
+ else if (S == 2) {
+ *face_u = 1.0f - v;
+ *face_v = 1.0f - u;
+ }
+ else {
+ *face_u = u;
+ *face_v = 1.0f - v;
+ }
+}
+
+BLI_INLINE void ccgSubSurf__mapEdgeToFace(
+ int S, int edge_segment, bool inverse_edge, int edgeSize, float *face_u, float *face_v)
+{
+ int t = inverse_edge ? edgeSize - edge_segment - 1 : edge_segment;
+ if (S == 0) {
+ *face_u = (float)t / (edgeSize - 1);
+ *face_v = 0.0f;
+ }
+ else if (S == 1) {
+ *face_u = 1.0f;
+ *face_v = (float)t / (edgeSize - 1);
+ }
+ else if (S == 2) {
+ *face_u = 1.0f - (float)t / (edgeSize - 1);
+ *face_v = 1.0f;
+ }
+ else {
+ *face_u = 0.0f;
+ *face_v = 1.0f - (float)t / (edgeSize - 1);
+ }
+}
+
+void ccgSubSurf_evaluatorSetFVarUV(CCGSubSurf *ss, DerivedMesh *dm, int layer_index)
+{
+ MPoly *mpoly = dm->getPolyArray(dm);
+ MLoopUV *mloopuv = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, layer_index);
+ int num_polys = dm->getNumPolys(dm);
+ int index, poly;
+ BLI_assert(ss->osd_evaluator != NULL);
+ for (poly = 0, index = 0; poly < num_polys; poly++) {
+ int loop;
+ MPoly *mp = &mpoly[poly];
+ for (loop = 0; loop < mp->totloop; loop++, index++) {
+ MLoopUV *mluv = &mloopuv[loop + mp->loopstart];
+ (void)mluv;
+ /* TODO(sergey): Send mluv->uv to the evaluator's face varying
+ * buffer.
+ */
+ }
+ }
+ (void)ss;
+}
+
+void ccgSubSurf_evaluatorFVarUV(
+ CCGSubSurf *ss, int face_index, int S, float grid_u, float grid_v, float uv[2])
+{
+ float face_u, face_v;
+ ccgSubSurf__mapGridToFace(S, grid_u, grid_v, &face_u, &face_v);
+ (void)ss;
+ (void)face_index;
+ /* TODO(sergey): Evaluate face varying coordinate. */
+ zero_v2(uv);
}
static bool opensubdiv_createEvaluator(CCGSubSurf *ss)
{
- OpenSubdiv_Converter converter;
- OpenSubdiv_TopologyRefiner *topology_refiner;
- if (ss->fMap->numEntries == 0) {
- /* OpenSubdiv doesn't support meshes without faces. */
- return false;
- }
- ccgSubSurf_converter_setup_from_ccg(ss, &converter);
- OpenSubdiv_TopologyRefinerSettings settings;
- settings.level = ss->subdivLevels;
- settings.is_adaptive = false;
- topology_refiner =
- openSubdiv_createTopologyRefinerFromConverter(
- &converter, &settings);
- ccgSubSurf_converter_free(&converter);
- ss->osd_evaluator =
- openSubdiv_createEvaluatorFromTopologyRefiner(topology_refiner);
- if (ss->osd_evaluator == NULL) {
- BLI_assert(!"OpenSubdiv initialization failed, should not happen.");
- return false;
- }
- return true;
+ OpenSubdiv_Converter converter;
+ OpenSubdiv_TopologyRefiner *topology_refiner;
+ if (ss->fMap->numEntries == 0) {
+ /* OpenSubdiv doesn't support meshes without faces. */
+ return false;
+ }
+ ccgSubSurf_converter_setup_from_ccg(ss, &converter);
+ OpenSubdiv_TopologyRefinerSettings settings;
+ settings.level = ss->subdivLevels;
+ settings.is_adaptive = false;
+ topology_refiner = openSubdiv_createTopologyRefinerFromConverter(&converter, &settings);
+ ccgSubSurf_converter_free(&converter);
+ ss->osd_evaluator = openSubdiv_createEvaluatorFromTopologyRefiner(topology_refiner);
+ if (ss->osd_evaluator == NULL) {
+ BLI_assert(!"OpenSubdiv initialization failed, should not happen.");
+ return false;
+ }
+ return true;
}
static bool opensubdiv_ensureEvaluator(CCGSubSurf *ss)
{
- if (ss->osd_evaluator == NULL) {
- OSD_LOG("Allocating new evaluator, %d verts\n", ss->vMap->numEntries);
- opensubdiv_createEvaluator(ss);
- }
- return ss->osd_evaluator != NULL;
+ if (ss->osd_evaluator == NULL) {
+ OSD_LOG("Allocating new evaluator, %d verts\n", ss->vMap->numEntries);
+ opensubdiv_createEvaluator(ss);
+ }
+ return ss->osd_evaluator != NULL;
}
static void opensubdiv_updateEvaluatorCoarsePositions(CCGSubSurf *ss)
{
- float (*positions)[3];
- int vertDataSize = ss->meshIFC.vertDataSize;
- int num_basis_verts = ss->vMap->numEntries;
- int i;
-
- /* TODO(sergey): Avoid allocation on every update. We could either update
- * coordinates in chunks of 1K vertices (which will only use stack memory)
- * or do some callback magic for OSD evaluator can invoke it and fill in
- * buffer directly.
- */
- if (ss->meshIFC.numLayers == 3) {
- /* If all the components are to be initialized, no need to memset the
- * new memory block.
- */
- positions = MEM_mallocN(3 * sizeof(float) * num_basis_verts,
- "OpenSubdiv coarse points");
- }
- else {
- /* Calloc in order to have z component initialized to 0 for Uvs */
- positions = MEM_callocN(3 * sizeof(float) * num_basis_verts,
- "OpenSubdiv coarse points");
- }
-#pragma omp parallel for
- for (i = 0; i < ss->vMap->curSize; i++) {
- CCGVert *v = (CCGVert *) ss->vMap->buckets[i];
- for (; v; v = v->next) {
- float *co = VERT_getCo(v, 0);
- BLI_assert(v->osd_index < ss->vMap->numEntries);
- VertDataCopy(positions[v->osd_index], co, ss);
- OSD_LOG("Point %d has value %f %f %f\n",
- v->osd_index,
- positions[v->osd_index][0],
- positions[v->osd_index][1],
- positions[v->osd_index][2]);
- }
- }
-
- ss->osd_evaluator->setCoarsePositions(ss->osd_evaluator,
- (float *)positions,
- 0,
- num_basis_verts);
- ss->osd_evaluator->refine(ss->osd_evaluator);
-
- MEM_freeN(positions);
+ float(*positions)[3];
+ int vertDataSize = ss->meshIFC.vertDataSize;
+ int num_basis_verts = ss->vMap->numEntries;
+ int i;
+
+ /* TODO(sergey): Avoid allocation on every update. We could either update
+ * coordinates in chunks of 1K vertices (which will only use stack memory)
+ * or do some callback magic for OSD evaluator can invoke it and fill in
+ * buffer directly.
+ */
+ if (ss->meshIFC.numLayers == 3) {
+ /* If all the components are to be initialized, no need to memset the
+ * new memory block.
+ */
+ positions = MEM_mallocN(3 * sizeof(float) * num_basis_verts, "OpenSubdiv coarse points");
+ }
+ else {
+ /* Calloc in order to have z component initialized to 0 for Uvs */
+ positions = MEM_callocN(3 * sizeof(float) * num_basis_verts, "OpenSubdiv coarse points");
+ }
+# pragma omp parallel for
+ for (i = 0; i < ss->vMap->curSize; i++) {
+ CCGVert *v = (CCGVert *)ss->vMap->buckets[i];
+ for (; v; v = v->next) {
+ float *co = VERT_getCo(v, 0);
+ BLI_assert(v->osd_index < ss->vMap->numEntries);
+ VertDataCopy(positions[v->osd_index], co, ss);
+ OSD_LOG("Point %d has value %f %f %f\n",
+ v->osd_index,
+ positions[v->osd_index][0],
+ positions[v->osd_index][1],
+ positions[v->osd_index][2]);
+ }
+ }
+
+ ss->osd_evaluator->setCoarsePositions(ss->osd_evaluator, (float *)positions, 0, num_basis_verts);
+ ss->osd_evaluator->refine(ss->osd_evaluator);
+
+ MEM_freeN(positions);
}
static void opensubdiv_evaluateQuadFaceGrids(CCGSubSurf *ss,
CCGFace *face,
const int osd_face_index)
{
- int normalDataOffset = ss->normalDataOffset;
- int subdivLevels = ss->subdivLevels;
- int gridSize = ccg_gridsize(subdivLevels);
- int edgeSize = ccg_edgesize(subdivLevels);
- int vertDataSize = ss->meshIFC.vertDataSize;
- int S;
- bool do_normals = ss->meshIFC.numLayers == 3;
-
-#pragma omp parallel for
- for (S = 0; S < face->numVerts; S++) {
- int x, y, k;
- CCGEdge *edge = NULL;
- bool inverse_edge = false;
-
- for (x = 0; x < gridSize; x++) {
- for (y = 0; y < gridSize; y++) {
- float *co = FACE_getIFCo(face, subdivLevels, S, x, y);
- float *no = FACE_getIFNo(face, subdivLevels, S, x, y);
- float grid_u = (float) x / (gridSize - 1),
- grid_v = (float) y / (gridSize - 1);
- float face_u, face_v;
- float P[3], dPdu[3], dPdv[3];
-
- ccgSubSurf__mapGridToFace(S, grid_u, grid_v, &face_u, &face_v);
-
- /* TODO(sergey): Need proper port. */
- ss->osd_evaluator->evaluateLimit(
- ss->osd_evaluator, osd_face_index,
- face_u, face_v,
- P,
- do_normals ? dPdu : NULL,
- do_normals ? dPdv : NULL);
-
- OSD_LOG("face=%d, corner=%d, grid_u=%f, grid_v=%f, face_u=%f, face_v=%f, P=(%f, %f, %f)\n",
- osd_face_index, S, grid_u, grid_v, face_u, face_v, P[0], P[1], P[2]);
-
- VertDataCopy(co, P, ss);
- if (do_normals) {
- cross_v3_v3v3(no, dPdu, dPdv);
- normalize_v3(no);
- }
-
- if (x == gridSize - 1 && y == gridSize - 1) {
- float *vert_co = VERT_getCo(FACE_getVerts(face)[S], subdivLevels);
- VertDataCopy(vert_co, co, ss);
- if (do_normals) {
- float *vert_no = VERT_getNo(FACE_getVerts(face)[S], subdivLevels);
- VertDataCopy(vert_no, no, ss);
- }
- }
- if (S == 0 && x == 0 && y == 0) {
- float *center_co = (float *)FACE_getCenterData(face);
- VertDataCopy(center_co, co, ss);
- if (do_normals) {
- float *center_no = (float *)((byte *)FACE_getCenterData(face) + normalDataOffset);
- VertDataCopy(center_no, no, ss);
- }
- }
- }
- }
-
- for (x = 0; x < gridSize; x++) {
- VertDataCopy(FACE_getIECo(face, subdivLevels, S, x),
- FACE_getIFCo(face, subdivLevels, S, x, 0), ss);
- if (do_normals) {
- VertDataCopy(FACE_getIENo(face, subdivLevels, S, x),
- FACE_getIFNo(face, subdivLevels, S, x, 0), ss);
- }
- }
-
- for (k = 0; k < face->numVerts; k++) {
- CCGEdge *current_edge = FACE_getEdges(face)[k];
- CCGVert **face_verts = FACE_getVerts(face);
- if (current_edge->v0 == face_verts[S] &&
- current_edge->v1 == face_verts[(S + 1) % face->numVerts])
- {
- edge = current_edge;
- inverse_edge = false;
- break;
- }
- if (current_edge->v1 == face_verts[S] &&
- current_edge->v0 == face_verts[(S + 1) % face->numVerts])
- {
- edge = current_edge;
- inverse_edge = true;
- break;
- }
- }
-
- BLI_assert(edge != NULL);
-
- for (x = 0; x < edgeSize; x++) {
- float u = 0, v = 0;
- float *co = EDGE_getCo(edge, subdivLevels, x);
- float *no = EDGE_getNo(edge, subdivLevels, x);
- float P[3], dPdu[3], dPdv[3];
- ccgSubSurf__mapEdgeToFace(S, x,
- inverse_edge,
- edgeSize,
- &u, &v);
-
- /* TODO(sergey): Ideally we will re-use grid here, but for now
- * let's just re-evaluate for simplicity.
- */
- /* TODO(sergey): Need proper port. */
- ss->osd_evaluator->evaluateLimit(
- ss->osd_evaluator,
- osd_face_index,
- u, v,
- P, dPdu, dPdv);
- VertDataCopy(co, P, ss);
- if (do_normals) {
- cross_v3_v3v3(no, dPdu, dPdv);
- normalize_v3(no);
- }
- }
- }
+ int normalDataOffset = ss->normalDataOffset;
+ int subdivLevels = ss->subdivLevels;
+ int gridSize = ccg_gridsize(subdivLevels);
+ int edgeSize = ccg_edgesize(subdivLevels);
+ int vertDataSize = ss->meshIFC.vertDataSize;
+ int S;
+ bool do_normals = ss->meshIFC.numLayers == 3;
+
+# pragma omp parallel for
+ for (S = 0; S < face->numVerts; S++) {
+ int x, y, k;
+ CCGEdge *edge = NULL;
+ bool inverse_edge = false;
+
+ for (x = 0; x < gridSize; x++) {
+ for (y = 0; y < gridSize; y++) {
+ float *co = FACE_getIFCo(face, subdivLevels, S, x, y);
+ float *no = FACE_getIFNo(face, subdivLevels, S, x, y);
+ float grid_u = (float)x / (gridSize - 1), grid_v = (float)y / (gridSize - 1);
+ float face_u, face_v;
+ float P[3], dPdu[3], dPdv[3];
+
+ ccgSubSurf__mapGridToFace(S, grid_u, grid_v, &face_u, &face_v);
+
+ /* TODO(sergey): Need proper port. */
+ ss->osd_evaluator->evaluateLimit(ss->osd_evaluator,
+ osd_face_index,
+ face_u,
+ face_v,
+ P,
+ do_normals ? dPdu : NULL,
+ do_normals ? dPdv : NULL);
+
+ OSD_LOG("face=%d, corner=%d, grid_u=%f, grid_v=%f, face_u=%f, face_v=%f, P=(%f, %f, %f)\n",
+ osd_face_index,
+ S,
+ grid_u,
+ grid_v,
+ face_u,
+ face_v,
+ P[0],
+ P[1],
+ P[2]);
+
+ VertDataCopy(co, P, ss);
+ if (do_normals) {
+ cross_v3_v3v3(no, dPdu, dPdv);
+ normalize_v3(no);
+ }
+
+ if (x == gridSize - 1 && y == gridSize - 1) {
+ float *vert_co = VERT_getCo(FACE_getVerts(face)[S], subdivLevels);
+ VertDataCopy(vert_co, co, ss);
+ if (do_normals) {
+ float *vert_no = VERT_getNo(FACE_getVerts(face)[S], subdivLevels);
+ VertDataCopy(vert_no, no, ss);
+ }
+ }
+ if (S == 0 && x == 0 && y == 0) {
+ float *center_co = (float *)FACE_getCenterData(face);
+ VertDataCopy(center_co, co, ss);
+ if (do_normals) {
+ float *center_no = (float *)((byte *)FACE_getCenterData(face) + normalDataOffset);
+ VertDataCopy(center_no, no, ss);
+ }
+ }
+ }
+ }
+
+ for (x = 0; x < gridSize; x++) {
+ VertDataCopy(
+ FACE_getIECo(face, subdivLevels, S, x), FACE_getIFCo(face, subdivLevels, S, x, 0), ss);
+ if (do_normals) {
+ VertDataCopy(
+ FACE_getIENo(face, subdivLevels, S, x), FACE_getIFNo(face, subdivLevels, S, x, 0), ss);
+ }
+ }
+
+ for (k = 0; k < face->numVerts; k++) {
+ CCGEdge *current_edge = FACE_getEdges(face)[k];
+ CCGVert **face_verts = FACE_getVerts(face);
+ if (current_edge->v0 == face_verts[S] &&
+ current_edge->v1 == face_verts[(S + 1) % face->numVerts]) {
+ edge = current_edge;
+ inverse_edge = false;
+ break;
+ }
+ if (current_edge->v1 == face_verts[S] &&
+ current_edge->v0 == face_verts[(S + 1) % face->numVerts]) {
+ edge = current_edge;
+ inverse_edge = true;
+ break;
+ }
+ }
+
+ BLI_assert(edge != NULL);
+
+ for (x = 0; x < edgeSize; x++) {
+ float u = 0, v = 0;
+ float *co = EDGE_getCo(edge, subdivLevels, x);
+ float *no = EDGE_getNo(edge, subdivLevels, x);
+ float P[3], dPdu[3], dPdv[3];
+ ccgSubSurf__mapEdgeToFace(S, x, inverse_edge, edgeSize, &u, &v);
+
+ /* TODO(sergey): Ideally we will re-use grid here, but for now
+ * let's just re-evaluate for simplicity.
+ */
+ /* TODO(sergey): Need proper port. */
+ ss->osd_evaluator->evaluateLimit(ss->osd_evaluator, osd_face_index, u, v, P, dPdu, dPdv);
+ VertDataCopy(co, P, ss);
+ if (do_normals) {
+ cross_v3_v3v3(no, dPdu, dPdv);
+ normalize_v3(no);
+ }
+ }
+ }
}
static void opensubdiv_evaluateNGonFaceGrids(CCGSubSurf *ss,
CCGFace *face,
const int osd_face_index)
{
- CCGVert **all_verts = FACE_getVerts(face);
- int normalDataOffset = ss->normalDataOffset;
- int subdivLevels = ss->subdivLevels;
- int gridSize = ccg_gridsize(subdivLevels);
- int edgeSize = ccg_edgesize(subdivLevels);
- int vertDataSize = ss->meshIFC.vertDataSize;
- int S;
- bool do_normals = ss->meshIFC.numLayers == 3;
-
- /* Note about handling non-quad faces.
- *
- * In order to deal with non-quad faces we need to split them
- * into a quads in the following way:
- *
- * |
- * (vert_next)
- * |
- * |
- * |
- * (face_center) ------------------- (v2)
- * | (o)--------------------> |
- * | | v |
- * | | |
- * | | |
- * | | |
- * | | y ^ |
- * | | | |
- * | v u x | |
- * | <---(o) |
- * ---- (vert_prev) ---- (v1) -------------------- (vert)
- *
- * This is how grids are expected to be stored and it's how
- * OpenSubdiv deals with non-quad faces using ptex face indices.
- * We only need to convert ptex (x, y) to grid (u, v) by some
- * simple flips and evaluate the ptex face.
- */
-
- /* Evaluate face grids. */
-#pragma omp parallel for
- for (S = 0; S < face->numVerts; S++) {
- int x, y;
- for (x = 0; x < gridSize; x++) {
- for (y = 0; y < gridSize; y++) {
- float *co = FACE_getIFCo(face, subdivLevels, S, x, y);
- float *no = FACE_getIFNo(face, subdivLevels, S, x, y);
- float u = 1.0f - (float) y / (gridSize - 1),
- v = 1.0f - (float) x / (gridSize - 1);
- float P[3], dPdu[3], dPdv[3];
-
- /* TODO(sergey): Need proper port. */
- ss->osd_evaluator->evaluateLimit(
- ss->osd_evaluator,
- osd_face_index + S,
- u, v,
- P, dPdu, dPdv);
-
- OSD_LOG("face=%d, corner=%d, u=%f, v=%f, P=(%f, %f, %f)\n",
- osd_face_index + S, S, u, v, P[0], P[1], P[2]);
-
- VertDataCopy(co, P, ss);
- if (do_normals) {
- cross_v3_v3v3(no, dPdu, dPdv);
- normalize_v3(no);
- }
-
- /* TODO(sergey): De-dpuplicate with the quad case. */
- if (x == gridSize - 1 && y == gridSize - 1) {
- float *vert_co = VERT_getCo(FACE_getVerts(face)[S], subdivLevels);
- VertDataCopy(vert_co, co, ss);
- if (do_normals) {
- float *vert_no = VERT_getNo(FACE_getVerts(face)[S], subdivLevels);
- VertDataCopy(vert_no, no, ss);
- }
- }
- if (S == 0 && x == 0 && y == 0) {
- float *center_co = (float *)FACE_getCenterData(face);
- VertDataCopy(center_co, co, ss);
- if (do_normals) {
- float *center_no = (float *)((byte *)FACE_getCenterData(face) + normalDataOffset);
- VertDataCopy(center_no, no, ss);
- }
- }
- }
- }
- for (x = 0; x < gridSize; x++) {
- VertDataCopy(FACE_getIECo(face, subdivLevels, S, x),
- FACE_getIFCo(face, subdivLevels, S, x, 0), ss);
- if (do_normals) {
- VertDataCopy(FACE_getIENo(face, subdivLevels, S, x),
- FACE_getIFNo(face, subdivLevels, S, x, 0), ss);
- }
- }
- }
-
- /* Evaluate edges. */
- for (S = 0; S < face->numVerts; S++) {
- CCGEdge *edge = FACE_getEdges(face)[S];
- int x, S0 = 0, S1 = 0;
- bool flip;
-
- for (x = 0; x < face->numVerts; ++x) {
- if (all_verts[x] == edge->v0) {
- S0 = x;
- }
- else if (all_verts[x] == edge->v1) {
- S1 = x;
- }
- }
- if (S == face->numVerts - 1) {
- flip = S0 > S1;
- }
- else {
- flip = S0 < S1;
- }
-
- for (x = 0; x <= edgeSize / 2; x++) {
- float *edge_co = EDGE_getCo(edge, subdivLevels, x);
- float *edge_no = EDGE_getNo(edge, subdivLevels, x);
- float *face_edge_co;
- float *face_edge_no;
- if (flip) {
- face_edge_co = FACE_getIFCo(face, subdivLevels, S0, gridSize - 1, gridSize - 1 - x);
- face_edge_no = FACE_getIFNo(face, subdivLevels, S0, gridSize - 1, gridSize - 1 - x);
- }
- else {
- face_edge_co = FACE_getIFCo(face, subdivLevels, S0, gridSize - 1 - x, gridSize - 1);
- face_edge_no = FACE_getIFNo(face, subdivLevels, S0, gridSize - 1 - x, gridSize - 1);
- }
- VertDataCopy(edge_co, face_edge_co, ss);
- if (do_normals) {
- VertDataCopy(edge_no, face_edge_no, ss);
- }
- }
- for (x = edgeSize / 2 + 1; x < edgeSize; x++) {
- float *edge_co = EDGE_getCo(edge, subdivLevels, x);
- float *edge_no = EDGE_getNo(edge, subdivLevels, x);
- float *face_edge_co;
- float *face_edge_no;
- if (flip) {
- face_edge_co = FACE_getIFCo(face, subdivLevels, S1, x - edgeSize / 2, gridSize - 1);
- face_edge_no = FACE_getIFNo(face, subdivLevels, S1, x - edgeSize / 2, gridSize - 1);
- }
- else {
- face_edge_co = FACE_getIFCo(face, subdivLevels, S1, gridSize - 1, x - edgeSize / 2);
- face_edge_no = FACE_getIFNo(face, subdivLevels, S1, gridSize - 1, x - edgeSize / 2);
- }
- VertDataCopy(edge_co, face_edge_co, ss);
- if (do_normals) {
- VertDataCopy(edge_no, face_edge_no, ss);
- }
- }
- }
+ CCGVert **all_verts = FACE_getVerts(face);
+ int normalDataOffset = ss->normalDataOffset;
+ int subdivLevels = ss->subdivLevels;
+ int gridSize = ccg_gridsize(subdivLevels);
+ int edgeSize = ccg_edgesize(subdivLevels);
+ int vertDataSize = ss->meshIFC.vertDataSize;
+ int S;
+ bool do_normals = ss->meshIFC.numLayers == 3;
+
+ /* Note about handling non-quad faces.
+ *
+ * In order to deal with non-quad faces we need to split them
+ * into a quads in the following way:
+ *
+ * |
+ * (vert_next)
+ * |
+ * |
+ * |
+ * (face_center) ------------------- (v2)
+ * | (o)--------------------> |
+ * | | v |
+ * | | |
+ * | | |
+ * | | |
+ * | | y ^ |
+ * | | | |
+ * | v u x | |
+ * | <---(o) |
+ * ---- (vert_prev) ---- (v1) -------------------- (vert)
+ *
+ * This is how grids are expected to be stored and it's how
+ * OpenSubdiv deals with non-quad faces using ptex face indices.
+ * We only need to convert ptex (x, y) to grid (u, v) by some
+ * simple flips and evaluate the ptex face.
+ */
+
+ /* Evaluate face grids. */
+# pragma omp parallel for
+ for (S = 0; S < face->numVerts; S++) {
+ int x, y;
+ for (x = 0; x < gridSize; x++) {
+ for (y = 0; y < gridSize; y++) {
+ float *co = FACE_getIFCo(face, subdivLevels, S, x, y);
+ float *no = FACE_getIFNo(face, subdivLevels, S, x, y);
+ float u = 1.0f - (float)y / (gridSize - 1), v = 1.0f - (float)x / (gridSize - 1);
+ float P[3], dPdu[3], dPdv[3];
+
+ /* TODO(sergey): Need proper port. */
+ ss->osd_evaluator->evaluateLimit(
+ ss->osd_evaluator, osd_face_index + S, u, v, P, dPdu, dPdv);
+
+ OSD_LOG("face=%d, corner=%d, u=%f, v=%f, P=(%f, %f, %f)\n",
+ osd_face_index + S,
+ S,
+ u,
+ v,
+ P[0],
+ P[1],
+ P[2]);
+
+ VertDataCopy(co, P, ss);
+ if (do_normals) {
+ cross_v3_v3v3(no, dPdu, dPdv);
+ normalize_v3(no);
+ }
+
+ /* TODO(sergey): De-dpuplicate with the quad case. */
+ if (x == gridSize - 1 && y == gridSize - 1) {
+ float *vert_co = VERT_getCo(FACE_getVerts(face)[S], subdivLevels);
+ VertDataCopy(vert_co, co, ss);
+ if (do_normals) {
+ float *vert_no = VERT_getNo(FACE_getVerts(face)[S], subdivLevels);
+ VertDataCopy(vert_no, no, ss);
+ }
+ }
+ if (S == 0 && x == 0 && y == 0) {
+ float *center_co = (float *)FACE_getCenterData(face);
+ VertDataCopy(center_co, co, ss);
+ if (do_normals) {
+ float *center_no = (float *)((byte *)FACE_getCenterData(face) + normalDataOffset);
+ VertDataCopy(center_no, no, ss);
+ }
+ }
+ }
+ }
+ for (x = 0; x < gridSize; x++) {
+ VertDataCopy(
+ FACE_getIECo(face, subdivLevels, S, x), FACE_getIFCo(face, subdivLevels, S, x, 0), ss);
+ if (do_normals) {
+ VertDataCopy(
+ FACE_getIENo(face, subdivLevels, S, x), FACE_getIFNo(face, subdivLevels, S, x, 0), ss);
+ }
+ }
+ }
+
+ /* Evaluate edges. */
+ for (S = 0; S < face->numVerts; S++) {
+ CCGEdge *edge = FACE_getEdges(face)[S];
+ int x, S0 = 0, S1 = 0;
+ bool flip;
+
+ for (x = 0; x < face->numVerts; ++x) {
+ if (all_verts[x] == edge->v0) {
+ S0 = x;
+ }
+ else if (all_verts[x] == edge->v1) {
+ S1 = x;
+ }
+ }
+ if (S == face->numVerts - 1) {
+ flip = S0 > S1;
+ }
+ else {
+ flip = S0 < S1;
+ }
+
+ for (x = 0; x <= edgeSize / 2; x++) {
+ float *edge_co = EDGE_getCo(edge, subdivLevels, x);
+ float *edge_no = EDGE_getNo(edge, subdivLevels, x);
+ float *face_edge_co;
+ float *face_edge_no;
+ if (flip) {
+ face_edge_co = FACE_getIFCo(face, subdivLevels, S0, gridSize - 1, gridSize - 1 - x);
+ face_edge_no = FACE_getIFNo(face, subdivLevels, S0, gridSize - 1, gridSize - 1 - x);
+ }
+ else {
+ face_edge_co = FACE_getIFCo(face, subdivLevels, S0, gridSize - 1 - x, gridSize - 1);
+ face_edge_no = FACE_getIFNo(face, subdivLevels, S0, gridSize - 1 - x, gridSize - 1);
+ }
+ VertDataCopy(edge_co, face_edge_co, ss);
+ if (do_normals) {
+ VertDataCopy(edge_no, face_edge_no, ss);
+ }
+ }
+ for (x = edgeSize / 2 + 1; x < edgeSize; x++) {
+ float *edge_co = EDGE_getCo(edge, subdivLevels, x);
+ float *edge_no = EDGE_getNo(edge, subdivLevels, x);
+ float *face_edge_co;
+ float *face_edge_no;
+ if (flip) {
+ face_edge_co = FACE_getIFCo(face, subdivLevels, S1, x - edgeSize / 2, gridSize - 1);
+ face_edge_no = FACE_getIFNo(face, subdivLevels, S1, x - edgeSize / 2, gridSize - 1);
+ }
+ else {
+ face_edge_co = FACE_getIFCo(face, subdivLevels, S1, gridSize - 1, x - edgeSize / 2);
+ face_edge_no = FACE_getIFNo(face, subdivLevels, S1, gridSize - 1, x - edgeSize / 2);
+ }
+ VertDataCopy(edge_co, face_edge_co, ss);
+ if (do_normals) {
+ VertDataCopy(edge_no, face_edge_no, ss);
+ }
+ }
+ }
}
static void opensubdiv_evaluateGrids(CCGSubSurf *ss)
{
- int i;
- for (i = 0; i < ss->fMap->curSize; i++) {
- CCGFace *face = (CCGFace *) ss->fMap->buckets[i];
- for (; face; face = face->next) {
- if (face->numVerts == 4) {
- /* For quads we do special magic with converting face coords
- * into corner coords and interpolating grids from it.
- */
- opensubdiv_evaluateQuadFaceGrids(ss, face, face->osd_index);
- }
- else {
- /* NGons and tris are split into separate osd faces which
- * evaluates onto grids directly.
- */
- opensubdiv_evaluateNGonFaceGrids(ss, face, face->osd_index);
- }
- }
- }
+ int i;
+ for (i = 0; i < ss->fMap->curSize; i++) {
+ CCGFace *face = (CCGFace *)ss->fMap->buckets[i];
+ for (; face; face = face->next) {
+ if (face->numVerts == 4) {
+ /* For quads we do special magic with converting face coords
+ * into corner coords and interpolating grids from it.
+ */
+ opensubdiv_evaluateQuadFaceGrids(ss, face, face->osd_index);
+ }
+ else {
+ /* NGons and tris are split into separate osd faces which
+ * evaluates onto grids directly.
+ */
+ opensubdiv_evaluateNGonFaceGrids(ss, face, face->osd_index);
+ }
+ }
+ }
}
CCGError ccgSubSurf_initOpenSubdivSync(CCGSubSurf *ss)
{
- if (ss->syncState != eSyncState_None) {
- return eCCGError_InvalidSyncState;
- }
- ss->syncState = eSyncState_OpenSubdiv;
- return eCCGError_None;
+ if (ss->syncState != eSyncState_None) {
+ return eCCGError_InvalidSyncState;
+ }
+ ss->syncState = eSyncState_OpenSubdiv;
+ return eCCGError_None;
}
void ccgSubSurf_prepareTopologyRefiner(CCGSubSurf *ss, DerivedMesh *dm)
{
- if (ss->osd_mesh == NULL || ss->osd_mesh_invalid) {
- if (dm->getNumPolys(dm) != 0) {
- OpenSubdiv_Converter converter;
- ccgSubSurf_converter_setup_from_derivedmesh(ss, dm, &converter);
- /* TODO(sergey): Remove possibly previously allocated refiner. */
- OpenSubdiv_TopologyRefinerSettings settings;
- settings.level = ss->subdivLevels;
- settings.is_adaptive = false;
- ss->osd_topology_refiner =
- openSubdiv_createTopologyRefinerFromConverter(
- &converter, &settings);
- ccgSubSurf_converter_free(&converter);
- }
- }
-
- /* Update number of grids, needed for things like final faces
- * counter, used by display drawing.
- */
- {
- const int num_polys = dm->getNumPolys(dm);
- const MPoly *mpoly = dm->getPolyArray(dm);
- int poly;
- ss->numGrids = 0;
- for (poly = 0; poly < num_polys; ++poly) {
- ss->numGrids += mpoly[poly].totloop;
- }
- }
-
- {
- const int num_verts = dm->getNumVerts(dm);
- const MVert *mvert = dm->getVertArray(dm);
- int vert;
- if (ss->osd_coarse_coords != NULL &&
- num_verts != ss->osd_num_coarse_coords)
- {
- MEM_freeN(ss->osd_coarse_coords);
- ss->osd_coarse_coords = NULL;
- }
- if (ss->osd_coarse_coords == NULL) {
- ss->osd_coarse_coords = MEM_mallocN(sizeof(float) * 6 * num_verts, "osd coarse positions");
- }
- for (vert = 0; vert < num_verts; vert++) {
- copy_v3_v3(ss->osd_coarse_coords[vert * 2 + 0], mvert[vert].co);
- normal_short_to_float_v3(ss->osd_coarse_coords[vert * 2 + 1], mvert[vert].no);
- }
- ss->osd_num_coarse_coords = num_verts;
- ss->osd_coarse_coords_invalid = true;
- }
+ if (ss->osd_mesh == NULL || ss->osd_mesh_invalid) {
+ if (dm->getNumPolys(dm) != 0) {
+ OpenSubdiv_Converter converter;
+ ccgSubSurf_converter_setup_from_derivedmesh(ss, dm, &converter);
+ /* TODO(sergey): Remove possibly previously allocated refiner. */
+ OpenSubdiv_TopologyRefinerSettings settings;
+ settings.level = ss->subdivLevels;
+ settings.is_adaptive = false;
+ ss->osd_topology_refiner = openSubdiv_createTopologyRefinerFromConverter(&converter,
+ &settings);
+ ccgSubSurf_converter_free(&converter);
+ }
+ }
+
+ /* Update number of grids, needed for things like final faces
+ * counter, used by display drawing.
+ */
+ {
+ const int num_polys = dm->getNumPolys(dm);
+ const MPoly *mpoly = dm->getPolyArray(dm);
+ int poly;
+ ss->numGrids = 0;
+ for (poly = 0; poly < num_polys; ++poly) {
+ ss->numGrids += mpoly[poly].totloop;
+ }
+ }
+
+ {
+ const int num_verts = dm->getNumVerts(dm);
+ const MVert *mvert = dm->getVertArray(dm);
+ int vert;
+ if (ss->osd_coarse_coords != NULL && num_verts != ss->osd_num_coarse_coords) {
+ MEM_freeN(ss->osd_coarse_coords);
+ ss->osd_coarse_coords = NULL;
+ }
+ if (ss->osd_coarse_coords == NULL) {
+ ss->osd_coarse_coords = MEM_mallocN(sizeof(float) * 6 * num_verts, "osd coarse positions");
+ }
+ for (vert = 0; vert < num_verts; vert++) {
+ copy_v3_v3(ss->osd_coarse_coords[vert * 2 + 0], mvert[vert].co);
+ normal_short_to_float_v3(ss->osd_coarse_coords[vert * 2 + 1], mvert[vert].no);
+ }
+ ss->osd_num_coarse_coords = num_verts;
+ ss->osd_coarse_coords_invalid = true;
+ }
}
void ccgSubSurf__sync_opensubdiv(CCGSubSurf *ss)
{
- BLI_assert(ss->meshIFC.numLayers == 2 || ss->meshIFC.numLayers == 3);
+ BLI_assert(ss->meshIFC.numLayers == 2 || ss->meshIFC.numLayers == 3);
- /* Common synchronization steps */
- ss->osd_compute = U.opensubdiv_compute_type;
+ /* Common synchronization steps */
+ ss->osd_compute = U.opensubdiv_compute_type;
- if (ss->skip_grids == false) {
- /* Make sure OSD evaluator is up-to-date. */
- if (opensubdiv_ensureEvaluator(ss)) {
- /* Update coarse points in the OpenSubdiv evaluator. */
- opensubdiv_updateEvaluatorCoarsePositions(ss);
+ if (ss->skip_grids == false) {
+ /* Make sure OSD evaluator is up-to-date. */
+ if (opensubdiv_ensureEvaluator(ss)) {
+ /* Update coarse points in the OpenSubdiv evaluator. */
+ opensubdiv_updateEvaluatorCoarsePositions(ss);
- /* Evaluate opensubdiv mesh into the CCG grids. */
- opensubdiv_evaluateGrids(ss);
- }
- }
- else {
- BLI_assert(ss->meshIFC.numLayers == 3);
- }
+ /* Evaluate opensubdiv mesh into the CCG grids. */
+ opensubdiv_evaluateGrids(ss);
+ }
+ }
+ else {
+ BLI_assert(ss->meshIFC.numLayers == 3);
+ }
-#ifdef DUMP_RESULT_GRIDS
- ccgSubSurf__dumpCoords(ss);
-#endif
+# ifdef DUMP_RESULT_GRIDS
+ ccgSubSurf__dumpCoords(ss);
+# endif
}
void ccgSubSurf_free_osd_mesh(CCGSubSurf *ss)
{
- if (ss->osd_mesh != NULL) {
- ccgSubSurf__delete_osdGLMesh(ss->osd_mesh);
- ss->osd_mesh = NULL;
- }
- if (ss->osd_vao != 0) {
- glDeleteVertexArrays(1, &ss->osd_vao);
- ss->osd_vao = 0;
- }
+ if (ss->osd_mesh != NULL) {
+ ccgSubSurf__delete_osdGLMesh(ss->osd_mesh);
+ ss->osd_mesh = NULL;
+ }
+ if (ss->osd_vao != 0) {
+ glDeleteVertexArrays(1, &ss->osd_vao);
+ ss->osd_vao = 0;
+ }
}
void ccgSubSurf_getMinMax(CCGSubSurf *ss, float r_min[3], float r_max[3])
{
- int i;
- BLI_assert(ss->skip_grids == true);
- if (ss->osd_num_coarse_coords == 0) {
- zero_v3(r_min);
- zero_v3(r_max);
- }
- for (i = 0; i < ss->osd_num_coarse_coords; i++) {
- /* Coarse coordinates has normals interleaved into the array. */
- DO_MINMAX(ss->osd_coarse_coords[2 * i], r_min, r_max);
- }
+ int i;
+ BLI_assert(ss->skip_grids == true);
+ if (ss->osd_num_coarse_coords == 0) {
+ zero_v3(r_min);
+ zero_v3(r_max);
+ }
+ for (i = 0; i < ss->osd_num_coarse_coords; i++) {
+ /* Coarse coordinates has normals interleaved into the array. */
+ DO_MINMAX(ss->osd_coarse_coords[2 * i], r_min, r_max);
+ }
}
/* ** Delayed delete routines ** */
typedef struct OsdDeletePendingItem {
- struct OsdDeletePendingItem *next, *prev;
- OpenSubdiv_GLMesh *osd_mesh;
- unsigned int vao;
+ struct OsdDeletePendingItem *next, *prev;
+ OpenSubdiv_GLMesh *osd_mesh;
+ unsigned int vao;
} OsdDeletePendingItem;
static SpinLock delete_spin;
static ListBase delete_pool = {NULL, NULL};
-static void delete_pending_push(OpenSubdiv_GLMesh *osd_mesh,
- unsigned int vao)
+static void delete_pending_push(OpenSubdiv_GLMesh *osd_mesh, unsigned int vao)
{
- OsdDeletePendingItem *new_entry = MEM_mallocN(sizeof(OsdDeletePendingItem),
- "opensubdiv delete entry");
- new_entry->osd_mesh = osd_mesh;
- new_entry->vao = vao;
- BLI_spin_lock(&delete_spin);
- BLI_addtail(&delete_pool, new_entry);
- BLI_spin_unlock(&delete_spin);
+ OsdDeletePendingItem *new_entry = MEM_mallocN(sizeof(OsdDeletePendingItem),
+ "opensubdiv delete entry");
+ new_entry->osd_mesh = osd_mesh;
+ new_entry->vao = vao;
+ BLI_spin_lock(&delete_spin);
+ BLI_addtail(&delete_pool, new_entry);
+ BLI_spin_unlock(&delete_spin);
}
void ccgSubSurf__delete_osdGLMesh(OpenSubdiv_GLMesh *osd_mesh)
{
- if (BLI_thread_is_main()) {
- openSubdiv_deleteOsdGLMesh(osd_mesh);
- }
- else {
- delete_pending_push(osd_mesh, 0);
- }
+ if (BLI_thread_is_main()) {
+ openSubdiv_deleteOsdGLMesh(osd_mesh);
+ }
+ else {
+ delete_pending_push(osd_mesh, 0);
+ }
}
void ccgSubSurf__delete_vertex_array(unsigned int vao)
{
- if (BLI_thread_is_main()) {
- glDeleteVertexArrays(1, &vao);
- }
- else {
- delete_pending_push(NULL, vao);
- }
+ if (BLI_thread_is_main()) {
+ glDeleteVertexArrays(1, &vao);
+ }
+ else {
+ delete_pending_push(NULL, vao);
+ }
}
void ccgSubSurf__delete_pending(void)
{
- OsdDeletePendingItem *entry;
- BLI_assert(BLI_thread_is_main());
- BLI_spin_lock(&delete_spin);
- for (entry = delete_pool.first; entry != NULL; entry = entry->next) {
- if (entry->osd_mesh != NULL) {
- openSubdiv_deleteOsdGLMesh(entry->osd_mesh);
- }
- if (entry->vao != 0) {
- glDeleteVertexArrays(1, &entry->vao);
- }
- }
- BLI_freelistN(&delete_pool);
- BLI_spin_unlock(&delete_spin);
+ OsdDeletePendingItem *entry;
+ BLI_assert(BLI_thread_is_main());
+ BLI_spin_lock(&delete_spin);
+ for (entry = delete_pool.first; entry != NULL; entry = entry->next) {
+ if (entry->osd_mesh != NULL) {
+ openSubdiv_deleteOsdGLMesh(entry->osd_mesh);
+ }
+ if (entry->vao != 0) {
+ glDeleteVertexArrays(1, &entry->vao);
+ }
+ }
+ BLI_freelistN(&delete_pool);
+ BLI_spin_unlock(&delete_spin);
}
void ccgSubSurf__sync_subdivUvs(CCGSubSurf *ss, bool subdiv_uvs)
{
- ss->osd_subdiv_uvs = subdiv_uvs;
+ ss->osd_subdiv_uvs = subdiv_uvs;
}
/* ** Public API ** */
void BKE_subsurf_osd_init(void)
{
- openSubdiv_init();
- BLI_spin_init(&delete_spin);
+ openSubdiv_init();
+ BLI_spin_init(&delete_spin);
}
void BKE_subsurf_free_unused_buffers(void)
{
- ccgSubSurf__delete_pending();
+ ccgSubSurf__delete_pending();
}
void BKE_subsurf_osd_cleanup(void)
{
- openSubdiv_cleanup();
- ccgSubSurf__delete_pending();
- BLI_spin_end(&delete_spin);
+ openSubdiv_cleanup();
+ ccgSubSurf__delete_pending();
+ BLI_spin_end(&delete_spin);
}
-#endif /* WITH_OPENSUBDIV */
+#endif /* WITH_OPENSUBDIV */
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c
index e36442bda55..53af82f4c0c 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c
@@ -20,723 +20,693 @@
#ifdef WITH_OPENSUBDIV
-#include <stdlib.h>
+# include <stdlib.h>
-#include "MEM_guardedalloc.h"
-#include "BLI_sys_types.h" // for intptr_t support
+# include "MEM_guardedalloc.h"
+# include "BLI_sys_types.h" // for intptr_t support
-#include "BLI_utildefines.h" /* for BLI_assert */
-#include "BLI_math.h"
+# include "BLI_utildefines.h" /* for BLI_assert */
+# include "BLI_math.h"
-#include "CCGSubSurf.h"
-#include "CCGSubSurf_intern.h"
+# include "CCGSubSurf.h"
+# include "CCGSubSurf_intern.h"
-#include "BKE_DerivedMesh.h"
-#include "BKE_mesh_mapping.h"
+# include "BKE_DerivedMesh.h"
+# include "BKE_mesh_mapping.h"
-#include "opensubdiv_capi.h"
-#include "opensubdiv_converter_capi.h"
+# include "opensubdiv_capi.h"
+# include "opensubdiv_converter_capi.h"
/* Use mesh element mapping structures during conversion.
* Uses more memory but is much faster than naive algorithm.
*/
-#define USE_MESH_ELEMENT_MAPPING
+# define USE_MESH_ELEMENT_MAPPING
/**
* Converter from DerivedMesh.
*/
typedef struct ConvDMStorage {
- CCGSubSurf *ss;
- DerivedMesh *dm;
-
-#ifdef USE_MESH_ELEMENT_MAPPING
- MeshElemMap *vert_edge_map,
- *vert_poly_map,
- *edge_poly_map;
- int *vert_edge_mem,
- *vert_poly_mem,
- *edge_poly_mem;
-#endif
-
- MVert *mvert;
- MEdge *medge;
- MLoop *mloop;
- MPoly *mpoly;
-
- MeshIslandStore island_store;
- int num_uvs;
- float *uvs;
- int *face_uvs;
+ CCGSubSurf *ss;
+ DerivedMesh *dm;
+
+# ifdef USE_MESH_ELEMENT_MAPPING
+ MeshElemMap *vert_edge_map, *vert_poly_map, *edge_poly_map;
+ int *vert_edge_mem, *vert_poly_mem, *edge_poly_mem;
+# endif
+
+ MVert *mvert;
+ MEdge *medge;
+ MLoop *mloop;
+ MPoly *mpoly;
+
+ MeshIslandStore island_store;
+ int num_uvs;
+ float *uvs;
+ int *face_uvs;
} ConvDMStorage;
-static OpenSubdiv_SchemeType conv_dm_get_type(
- const OpenSubdiv_Converter *converter)
+static OpenSubdiv_SchemeType conv_dm_get_type(const OpenSubdiv_Converter *converter)
{
- ConvDMStorage *storage = converter->user_data;
- if (storage->ss->meshIFC.simpleSubdiv)
- return OSD_SCHEME_BILINEAR;
- else
- return OSD_SCHEME_CATMARK;
+ ConvDMStorage *storage = converter->user_data;
+ if (storage->ss->meshIFC.simpleSubdiv)
+ return OSD_SCHEME_BILINEAR;
+ else
+ return OSD_SCHEME_CATMARK;
}
-static OpenSubdiv_VtxBoundaryInterpolation
-conv_dm_get_vtx_boundary_interpolation(
- const OpenSubdiv_Converter *UNUSED(converter))
+static OpenSubdiv_VtxBoundaryInterpolation conv_dm_get_vtx_boundary_interpolation(
+ const OpenSubdiv_Converter *UNUSED(converter))
{
- return OSD_VTX_BOUNDARY_EDGE_ONLY;
+ return OSD_VTX_BOUNDARY_EDGE_ONLY;
}
static OpenSubdiv_FVarLinearInterpolation conv_dm_get_fvar_linear_interpolation(
- const OpenSubdiv_Converter *converter)
+ const OpenSubdiv_Converter *converter)
{
- ConvDMStorage *storage = converter->user_data;
- if (storage->ss->osd_subdiv_uvs) {
- return OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY;
- }
- return OSD_FVAR_LINEAR_INTERPOLATION_ALL;
+ ConvDMStorage *storage = converter->user_data;
+ if (storage->ss->osd_subdiv_uvs) {
+ return OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY;
+ }
+ return OSD_FVAR_LINEAR_INTERPOLATION_ALL;
}
-static bool conv_dm_specifies_full_topology(
- const OpenSubdiv_Converter *UNUSED(converter))
+static bool conv_dm_specifies_full_topology(const OpenSubdiv_Converter *UNUSED(converter))
{
- return true;
+ return true;
}
static int conv_dm_get_num_faces(const OpenSubdiv_Converter *converter)
{
- ConvDMStorage *storage = converter->user_data;
- DerivedMesh *dm = storage->dm;
- return dm->getNumPolys(dm);
+ ConvDMStorage *storage = converter->user_data;
+ DerivedMesh *dm = storage->dm;
+ return dm->getNumPolys(dm);
}
static int conv_dm_get_num_edges(const OpenSubdiv_Converter *converter)
{
- ConvDMStorage *storage = converter->user_data;
- DerivedMesh *dm = storage->dm;
- return dm->getNumEdges(dm);
+ ConvDMStorage *storage = converter->user_data;
+ DerivedMesh *dm = storage->dm;
+ return dm->getNumEdges(dm);
}
static int conv_dm_get_num_verts(const OpenSubdiv_Converter *converter)
{
- ConvDMStorage *storage = converter->user_data;
- DerivedMesh *dm = storage->dm;
- return dm->getNumVerts(dm);
+ ConvDMStorage *storage = converter->user_data;
+ DerivedMesh *dm = storage->dm;
+ return dm->getNumVerts(dm);
}
-static int conv_dm_get_num_face_verts(const OpenSubdiv_Converter *converter,
- int face)
+static int conv_dm_get_num_face_verts(const OpenSubdiv_Converter *converter, int face)
{
- ConvDMStorage *storage = converter->user_data;
- const MPoly *mpoly = &storage->mpoly[face];
- return mpoly->totloop;
+ ConvDMStorage *storage = converter->user_data;
+ const MPoly *mpoly = &storage->mpoly[face];
+ return mpoly->totloop;
}
static void conv_dm_get_face_verts(const OpenSubdiv_Converter *converter,
int face,
int *face_verts)
{
- ConvDMStorage *storage = converter->user_data;
- const MPoly *mpoly = &storage->mpoly[face];
- int loop;
- for (loop = 0; loop < mpoly->totloop; loop++) {
- face_verts[loop] = storage->mloop[mpoly->loopstart + loop].v;
- }
+ ConvDMStorage *storage = converter->user_data;
+ const MPoly *mpoly = &storage->mpoly[face];
+ int loop;
+ for (loop = 0; loop < mpoly->totloop; loop++) {
+ face_verts[loop] = storage->mloop[mpoly->loopstart + loop].v;
+ }
}
static void conv_dm_get_face_edges(const OpenSubdiv_Converter *converter,
int face,
int *face_edges)
{
- ConvDMStorage *storage = converter->user_data;
- const MPoly *mpoly = &storage->mpoly[face];
- int loop;
- for (loop = 0; loop < mpoly->totloop; loop++) {
- face_edges[loop] = storage->mloop[mpoly->loopstart + loop].e;
- }
+ ConvDMStorage *storage = converter->user_data;
+ const MPoly *mpoly = &storage->mpoly[face];
+ int loop;
+ for (loop = 0; loop < mpoly->totloop; loop++) {
+ face_edges[loop] = storage->mloop[mpoly->loopstart + loop].e;
+ }
}
static void conv_dm_get_edge_verts(const OpenSubdiv_Converter *converter,
int edge,
int *edge_verts)
{
- ConvDMStorage *storage = converter->user_data;
- const MEdge *medge = &storage->medge[edge];
- edge_verts[0] = medge->v1;
- edge_verts[1] = medge->v2;
-}
-
-static int conv_dm_get_num_edge_faces(const OpenSubdiv_Converter *converter,
- int edge)
-{
- ConvDMStorage *storage = converter->user_data;
-#ifndef USE_MESH_ELEMENT_MAPPING
- DerivedMesh *dm = storage->dm;
- int num = 0, poly;
- for (poly = 0; poly < dm->getNumPolys(dm); poly++) {
- const MPoly *mpoly = &user_data->mpoly[poly];
- int loop;
- for (loop = 0; loop < mpoly->totloop; loop++) {
- const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop];
- if (mloop->e == edge) {
- ++num;
- break;
- }
- }
- }
- return num;
-#else
- return storage->edge_poly_map[edge].count;
-#endif
+ ConvDMStorage *storage = converter->user_data;
+ const MEdge *medge = &storage->medge[edge];
+ edge_verts[0] = medge->v1;
+ edge_verts[1] = medge->v2;
+}
+
+static int conv_dm_get_num_edge_faces(const OpenSubdiv_Converter *converter, int edge)
+{
+ ConvDMStorage *storage = converter->user_data;
+# ifndef USE_MESH_ELEMENT_MAPPING
+ DerivedMesh *dm = storage->dm;
+ int num = 0, poly;
+ for (poly = 0; poly < dm->getNumPolys(dm); poly++) {
+ const MPoly *mpoly = &user_data->mpoly[poly];
+ int loop;
+ for (loop = 0; loop < mpoly->totloop; loop++) {
+ const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop];
+ if (mloop->e == edge) {
+ ++num;
+ break;
+ }
+ }
+ }
+ return num;
+# else
+ return storage->edge_poly_map[edge].count;
+# endif
}
static void conv_dm_get_edge_faces(const OpenSubdiv_Converter *converter,
int edge,
int *edge_faces)
{
- ConvDMStorage *storage = converter->user_data;
-#ifndef USE_MESH_ELEMENT_MAPPING
- DerivedMesh *dm = storage->dm;
- int num = 0, poly;
- for (poly = 0; poly < dm->getNumPolys(dm); poly++) {
- const MPoly *mpoly = &user_data->mpoly[poly];
- int loop;
- for (loop = 0; loop < mpoly->totloop; loop++) {
- const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop];
- if (mloop->e == edge) {
- edge_faces[num++] = poly;
- break;
- }
- }
- }
-#else
- memcpy(edge_faces,
- storage->edge_poly_map[edge].indices,
- sizeof(int) * storage->edge_poly_map[edge].count);
-#endif
-}
-
-static float conv_dm_get_edge_sharpness(const OpenSubdiv_Converter *converter,
- int edge)
-{
- ConvDMStorage *storage = converter->user_data;
- CCGSubSurf *ss = storage->ss;
- const MEdge *medge = storage->medge;
- return (float)medge[edge].crease / 255.0f * ss->subdivLevels;
-}
-
-static int conv_dm_get_num_vert_edges(const OpenSubdiv_Converter *converter,
- int vert)
-{
- ConvDMStorage *storage = converter->user_data;
-#ifndef USE_MESH_ELEMENT_MAPPING
- DerivedMesh *dm = storage->dm;
- int num = 0, edge;
- for (edge = 0; edge < dm->getNumEdges(dm); edge++) {
- const MEdge *medge = &user_data->medge[edge];
- if (medge->v1 == vert || medge->v2 == vert) {
- ++num;
- }
- }
- return num;
-#else
- return storage->vert_edge_map[vert].count;
-#endif
+ ConvDMStorage *storage = converter->user_data;
+# ifndef USE_MESH_ELEMENT_MAPPING
+ DerivedMesh *dm = storage->dm;
+ int num = 0, poly;
+ for (poly = 0; poly < dm->getNumPolys(dm); poly++) {
+ const MPoly *mpoly = &user_data->mpoly[poly];
+ int loop;
+ for (loop = 0; loop < mpoly->totloop; loop++) {
+ const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop];
+ if (mloop->e == edge) {
+ edge_faces[num++] = poly;
+ break;
+ }
+ }
+ }
+# else
+ memcpy(edge_faces,
+ storage->edge_poly_map[edge].indices,
+ sizeof(int) * storage->edge_poly_map[edge].count);
+# endif
+}
+
+static float conv_dm_get_edge_sharpness(const OpenSubdiv_Converter *converter, int edge)
+{
+ ConvDMStorage *storage = converter->user_data;
+ CCGSubSurf *ss = storage->ss;
+ const MEdge *medge = storage->medge;
+ return (float)medge[edge].crease / 255.0f * ss->subdivLevels;
+}
+
+static int conv_dm_get_num_vert_edges(const OpenSubdiv_Converter *converter, int vert)
+{
+ ConvDMStorage *storage = converter->user_data;
+# ifndef USE_MESH_ELEMENT_MAPPING
+ DerivedMesh *dm = storage->dm;
+ int num = 0, edge;
+ for (edge = 0; edge < dm->getNumEdges(dm); edge++) {
+ const MEdge *medge = &user_data->medge[edge];
+ if (medge->v1 == vert || medge->v2 == vert) {
+ ++num;
+ }
+ }
+ return num;
+# else
+ return storage->vert_edge_map[vert].count;
+# endif
}
static void conv_dm_get_vert_edges(const OpenSubdiv_Converter *converter,
int vert,
int *vert_edges)
{
- ConvDMStorage *storage = converter->user_data;
-#ifndef USE_MESH_ELEMENT_MAPPING
- DerivedMesh *dm = storage->dm;
- int num = 0, edge;
- for (edge = 0; edge < dm->getNumEdges(dm); edge++) {
- const MEdge *medge = &user_data->medge[edge];
- if (medge->v1 == vert || medge->v2 == vert) {
- vert_edges[num++] = edge;
- }
- }
-#else
- memcpy(vert_edges,
- storage->vert_edge_map[vert].indices,
- sizeof(int) * storage->vert_edge_map[vert].count);
-#endif
-}
-
-static int conv_dm_get_num_vert_faces(const OpenSubdiv_Converter *converter,
- int vert)
-{
- ConvDMStorage *storage = converter->user_data;
-#ifndef USE_MESH_ELEMENT_MAPPING
- DerivedMesh *dm = storage->dm;
- int num = 0, poly;
- for (poly = 0; poly < dm->getNumPolys(dm); poly++) {
- const MPoly *mpoly = &user_data->mpoly[poly];
- int loop;
- for (loop = 0; loop < mpoly->totloop; loop++) {
- const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop];
- if (mloop->v == vert) {
- ++num;
- break;
- }
- }
- }
- return num;
-#else
- return storage->vert_poly_map[vert].count;
-#endif
+ ConvDMStorage *storage = converter->user_data;
+# ifndef USE_MESH_ELEMENT_MAPPING
+ DerivedMesh *dm = storage->dm;
+ int num = 0, edge;
+ for (edge = 0; edge < dm->getNumEdges(dm); edge++) {
+ const MEdge *medge = &user_data->medge[edge];
+ if (medge->v1 == vert || medge->v2 == vert) {
+ vert_edges[num++] = edge;
+ }
+ }
+# else
+ memcpy(vert_edges,
+ storage->vert_edge_map[vert].indices,
+ sizeof(int) * storage->vert_edge_map[vert].count);
+# endif
+}
+
+static int conv_dm_get_num_vert_faces(const OpenSubdiv_Converter *converter, int vert)
+{
+ ConvDMStorage *storage = converter->user_data;
+# ifndef USE_MESH_ELEMENT_MAPPING
+ DerivedMesh *dm = storage->dm;
+ int num = 0, poly;
+ for (poly = 0; poly < dm->getNumPolys(dm); poly++) {
+ const MPoly *mpoly = &user_data->mpoly[poly];
+ int loop;
+ for (loop = 0; loop < mpoly->totloop; loop++) {
+ const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop];
+ if (mloop->v == vert) {
+ ++num;
+ break;
+ }
+ }
+ }
+ return num;
+# else
+ return storage->vert_poly_map[vert].count;
+# endif
}
static void conv_dm_get_vert_faces(const OpenSubdiv_Converter *converter,
int vert,
int *vert_faces)
{
- ConvDMStorage *storage = converter->user_data;
-#ifndef USE_MESH_ELEMENT_MAPPING
- DerivedMesh *dm = storage->dm;
- int num = 0, poly;
- for (poly = 0; poly < dm->getNumPolys(dm); poly++) {
- const MPoly *mpoly = &storage->mpoly[poly];
- int loop;
- for (loop = 0; loop < mpoly->totloop; loop++) {
- const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop];
- if (mloop->v == vert) {
- vert_faces[num++] = poly;
- break;
- }
- }
- }
-#else
- memcpy(vert_faces,
- storage->vert_poly_map[vert].indices,
- sizeof(int) * storage->vert_poly_map[vert].count);
-#endif
+ ConvDMStorage *storage = converter->user_data;
+# ifndef USE_MESH_ELEMENT_MAPPING
+ DerivedMesh *dm = storage->dm;
+ int num = 0, poly;
+ for (poly = 0; poly < dm->getNumPolys(dm); poly++) {
+ const MPoly *mpoly = &storage->mpoly[poly];
+ int loop;
+ for (loop = 0; loop < mpoly->totloop; loop++) {
+ const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop];
+ if (mloop->v == vert) {
+ vert_faces[num++] = poly;
+ break;
+ }
+ }
+ }
+# else
+ memcpy(vert_faces,
+ storage->vert_poly_map[vert].indices,
+ sizeof(int) * storage->vert_poly_map[vert].count);
+# endif
}
-static bool conv_dm_is_infinite_sharp_vertex(
- const OpenSubdiv_Converter *UNUSED(converter),
- int UNUSED(manifold_vertex_index))
+static bool conv_dm_is_infinite_sharp_vertex(const OpenSubdiv_Converter *UNUSED(converter),
+ int UNUSED(manifold_vertex_index))
{
- return false;
+ return false;
}
-static float conv_dm_get_vertex_sharpness(
- const OpenSubdiv_Converter *UNUSED(converter),
- int UNUSED(manifold_vertex_index))
+static float conv_dm_get_vertex_sharpness(const OpenSubdiv_Converter *UNUSED(converter),
+ int UNUSED(manifold_vertex_index))
{
- return 0.0f;
+ return 0.0f;
}
static int conv_dm_get_num_uv_layers(const OpenSubdiv_Converter *converter)
{
- ConvDMStorage *storage = converter->user_data;
- DerivedMesh *dm = storage->dm;
- int num_uv_layers = CustomData_number_of_layers(&dm->loopData, CD_MLOOPUV);
- return num_uv_layers;
-}
-
-static void conv_dm_precalc_uv_layer(const OpenSubdiv_Converter *converter,
- int layer)
-{
- ConvDMStorage *storage = converter->user_data;
- DerivedMesh *dm = storage->dm;
-
- const MLoopUV *mloopuv = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, layer);
- const int num_loops = dm->getNumLoops(dm);
-
- /* Initialize memory required for the operations. */
- if (storage->uvs == NULL) {
- storage->uvs = MEM_mallocN(sizeof(float) * 2 * num_loops, "osd uvs");
- }
- if (storage->face_uvs == NULL) {
- storage->face_uvs = MEM_mallocN(sizeof(int) * num_loops, "osd face uvs");
- }
-
- /* Calculate islands connectivity of the UVs. */
- BKE_mesh_calc_islands_loop_poly_uvmap(
- storage->mvert, dm->getNumVerts(dm),
- storage->medge, dm->getNumEdges(dm),
- storage->mpoly, dm->getNumPolys(dm),
- storage->mloop, dm->getNumLoops(dm),
- mloopuv,
- &storage->island_store);
-
- /* Here we "weld" duplicated vertices from island to the same UV value.
- * The idea here is that we need to pass individual islands to OpenSubdiv.
- */
- storage->num_uvs = 0;
- for (int island = 0; island < storage->island_store.islands_num; ++island) {
- MeshElemMap *island_poly_map = storage->island_store.islands[island];
- for (int poly = 0; poly < island_poly_map->count; ++poly) {
- int poly_index = island_poly_map->indices[poly];
- /* Within the same UV island we should share UV points across
- * loops. Otherwise each poly will be subdivided individually
- * which we don't really want.
- */
- const MPoly *mpoly = &storage->mpoly[poly_index];
- for (int loop = 0; loop < mpoly->totloop; ++loop) {
- const MLoopUV *luv = &mloopuv[mpoly->loopstart + loop];
- bool found = false;
- /* TODO(sergey): Quite bad loop, which gives us O(N^2)
- * complexity here. But how can we do it smarter, hopefully
- * without requiring lots of additional memory.
- */
- for (int i = 0; i < storage->num_uvs; ++i) {
- if (equals_v2v2(luv->uv, &storage->uvs[2 * i])) {
- storage->face_uvs[mpoly->loopstart + loop] = i;
- found = true;
- break;
- }
- }
- if (!found) {
- copy_v2_v2(&storage->uvs[2 * storage->num_uvs], luv->uv);
- storage->face_uvs[mpoly->loopstart + loop] = storage->num_uvs;
- ++storage->num_uvs;
- }
- }
- }
- }
+ ConvDMStorage *storage = converter->user_data;
+ DerivedMesh *dm = storage->dm;
+ int num_uv_layers = CustomData_number_of_layers(&dm->loopData, CD_MLOOPUV);
+ return num_uv_layers;
+}
+
+static void conv_dm_precalc_uv_layer(const OpenSubdiv_Converter *converter, int layer)
+{
+ ConvDMStorage *storage = converter->user_data;
+ DerivedMesh *dm = storage->dm;
+
+ const MLoopUV *mloopuv = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, layer);
+ const int num_loops = dm->getNumLoops(dm);
+
+ /* Initialize memory required for the operations. */
+ if (storage->uvs == NULL) {
+ storage->uvs = MEM_mallocN(sizeof(float) * 2 * num_loops, "osd uvs");
+ }
+ if (storage->face_uvs == NULL) {
+ storage->face_uvs = MEM_mallocN(sizeof(int) * num_loops, "osd face uvs");
+ }
+
+ /* Calculate islands connectivity of the UVs. */
+ BKE_mesh_calc_islands_loop_poly_uvmap(storage->mvert,
+ dm->getNumVerts(dm),
+ storage->medge,
+ dm->getNumEdges(dm),
+ storage->mpoly,
+ dm->getNumPolys(dm),
+ storage->mloop,
+ dm->getNumLoops(dm),
+ mloopuv,
+ &storage->island_store);
+
+ /* Here we "weld" duplicated vertices from island to the same UV value.
+ * The idea here is that we need to pass individual islands to OpenSubdiv.
+ */
+ storage->num_uvs = 0;
+ for (int island = 0; island < storage->island_store.islands_num; ++island) {
+ MeshElemMap *island_poly_map = storage->island_store.islands[island];
+ for (int poly = 0; poly < island_poly_map->count; ++poly) {
+ int poly_index = island_poly_map->indices[poly];
+ /* Within the same UV island we should share UV points across
+ * loops. Otherwise each poly will be subdivided individually
+ * which we don't really want.
+ */
+ const MPoly *mpoly = &storage->mpoly[poly_index];
+ for (int loop = 0; loop < mpoly->totloop; ++loop) {
+ const MLoopUV *luv = &mloopuv[mpoly->loopstart + loop];
+ bool found = false;
+ /* TODO(sergey): Quite bad loop, which gives us O(N^2)
+ * complexity here. But how can we do it smarter, hopefully
+ * without requiring lots of additional memory.
+ */
+ for (int i = 0; i < storage->num_uvs; ++i) {
+ if (equals_v2v2(luv->uv, &storage->uvs[2 * i])) {
+ storage->face_uvs[mpoly->loopstart + loop] = i;
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ copy_v2_v2(&storage->uvs[2 * storage->num_uvs], luv->uv);
+ storage->face_uvs[mpoly->loopstart + loop] = storage->num_uvs;
+ ++storage->num_uvs;
+ }
+ }
+ }
+ }
}
static void conv_dm_finish_uv_layer(const OpenSubdiv_Converter *converter)
{
- ConvDMStorage *storage = converter->user_data;
- BKE_mesh_loop_islands_free(&storage->island_store);
+ ConvDMStorage *storage = converter->user_data;
+ BKE_mesh_loop_islands_free(&storage->island_store);
}
static int conv_dm_get_num_uvs(const OpenSubdiv_Converter *converter)
{
- ConvDMStorage *storage = converter->user_data;
- return storage->num_uvs;
+ ConvDMStorage *storage = converter->user_data;
+ return storage->num_uvs;
}
static int conv_dm_get_face_corner_uv_index(const OpenSubdiv_Converter *converter,
int face,
int corner)
{
- ConvDMStorage *storage = converter->user_data;
- const MPoly *mpoly = &storage->mpoly[face];
- return storage->face_uvs[mpoly->loopstart + corner];
+ ConvDMStorage *storage = converter->user_data;
+ const MPoly *mpoly = &storage->mpoly[face];
+ return storage->face_uvs[mpoly->loopstart + corner];
}
static void conv_dm_free_user_data(const OpenSubdiv_Converter *converter)
{
- ConvDMStorage *user_data = converter->user_data;
- if (user_data->uvs != NULL) {
- MEM_freeN(user_data->uvs);
- }
- if (user_data->face_uvs != NULL) {
- MEM_freeN(user_data->face_uvs);
- }
-
-#ifdef USE_MESH_ELEMENT_MAPPING
- MEM_freeN(user_data->vert_edge_map);
- MEM_freeN(user_data->vert_edge_mem);
- MEM_freeN(user_data->vert_poly_map);
- MEM_freeN(user_data->vert_poly_mem);
- MEM_freeN(user_data->edge_poly_map);
- MEM_freeN(user_data->edge_poly_mem);
-#endif
- MEM_freeN(user_data);
-}
-
-void ccgSubSurf_converter_setup_from_derivedmesh(
- CCGSubSurf *ss,
- DerivedMesh *dm,
- OpenSubdiv_Converter *converter)
-{
- ConvDMStorage *user_data;
-
- converter->getSchemeType = conv_dm_get_type;
-
- converter->getVtxBoundaryInterpolation =
- conv_dm_get_vtx_boundary_interpolation;
- converter->getFVarLinearInterpolation =
- conv_dm_get_fvar_linear_interpolation;
- converter->specifiesFullTopology = conv_dm_specifies_full_topology;
-
- converter->getNumFaces = conv_dm_get_num_faces;
- converter->getNumEdges = conv_dm_get_num_edges;
- converter->getNumVertices = conv_dm_get_num_verts;
-
- converter->getNumFaceVertices = conv_dm_get_num_face_verts;
- converter->getFaceVertices = conv_dm_get_face_verts;
- converter->getFaceEdges = conv_dm_get_face_edges;
-
- converter->getEdgeVertices = conv_dm_get_edge_verts;
- converter->getNumEdgeFaces = conv_dm_get_num_edge_faces;
- converter->getEdgeFaces = conv_dm_get_edge_faces;
- converter->getEdgeSharpness = conv_dm_get_edge_sharpness;
-
- converter->getNumVertexEdges = conv_dm_get_num_vert_edges;
- converter->getVertexEdges = conv_dm_get_vert_edges;
- converter->getNumVertexFaces = conv_dm_get_num_vert_faces;
- converter->getVertexFaces = conv_dm_get_vert_faces;
- converter->isInfiniteSharpVertex = conv_dm_is_infinite_sharp_vertex;
- converter->getVertexSharpness = conv_dm_get_vertex_sharpness;
-
- converter->getNumUVLayers = conv_dm_get_num_uv_layers;
- converter->precalcUVLayer = conv_dm_precalc_uv_layer;
- converter->finishUVLayer = conv_dm_finish_uv_layer;
- converter->getNumUVCoordinates = conv_dm_get_num_uvs;
- converter->getFaceCornerUVIndex = conv_dm_get_face_corner_uv_index;
-
- user_data = MEM_mallocN(sizeof(ConvDMStorage), __func__);
- user_data->ss = ss;
- user_data->dm = dm;
-
- user_data->mvert = dm->getVertArray(dm);
- user_data->medge = dm->getEdgeArray(dm);
- user_data->mloop = dm->getLoopArray(dm);
- user_data->mpoly = dm->getPolyArray(dm);
-
- memset(&user_data->island_store, 0, sizeof(user_data->island_store));
-
- user_data->uvs = NULL;
- user_data->face_uvs = NULL;
-
- converter->freeUserData = conv_dm_free_user_data;
- converter->user_data = user_data;
-
-#ifdef USE_MESH_ELEMENT_MAPPING
- {
- const MEdge *medge = dm->getEdgeArray(dm);
- const MLoop *mloop = dm->getLoopArray(dm);
- const MPoly *mpoly = dm->getPolyArray(dm);
- const int num_vert = dm->getNumVerts(dm),
- num_edge = dm->getNumEdges(dm),
- num_loop = dm->getNumLoops(dm),
- num_poly = dm->getNumPolys(dm);
- BKE_mesh_vert_edge_map_create(&user_data->vert_edge_map,
- &user_data->vert_edge_mem,
- medge,
- num_vert,
- num_edge);
-
- BKE_mesh_vert_poly_map_create(&user_data->vert_poly_map,
- &user_data->vert_poly_mem,
- mpoly,
- mloop,
- num_vert,
- num_poly,
- num_loop);
-
- BKE_mesh_edge_poly_map_create(&user_data->edge_poly_map,
- &user_data->edge_poly_mem,
- medge,
- num_edge,
- mpoly,
- num_poly,
- mloop,
- num_loop);
- }
-#endif /* USE_MESH_ELEMENT_MAPPING */
+ ConvDMStorage *user_data = converter->user_data;
+ if (user_data->uvs != NULL) {
+ MEM_freeN(user_data->uvs);
+ }
+ if (user_data->face_uvs != NULL) {
+ MEM_freeN(user_data->face_uvs);
+ }
+
+# ifdef USE_MESH_ELEMENT_MAPPING
+ MEM_freeN(user_data->vert_edge_map);
+ MEM_freeN(user_data->vert_edge_mem);
+ MEM_freeN(user_data->vert_poly_map);
+ MEM_freeN(user_data->vert_poly_mem);
+ MEM_freeN(user_data->edge_poly_map);
+ MEM_freeN(user_data->edge_poly_mem);
+# endif
+ MEM_freeN(user_data);
+}
+
+void ccgSubSurf_converter_setup_from_derivedmesh(CCGSubSurf *ss,
+ DerivedMesh *dm,
+ OpenSubdiv_Converter *converter)
+{
+ ConvDMStorage *user_data;
+
+ converter->getSchemeType = conv_dm_get_type;
+
+ converter->getVtxBoundaryInterpolation = conv_dm_get_vtx_boundary_interpolation;
+ converter->getFVarLinearInterpolation = conv_dm_get_fvar_linear_interpolation;
+ converter->specifiesFullTopology = conv_dm_specifies_full_topology;
+
+ converter->getNumFaces = conv_dm_get_num_faces;
+ converter->getNumEdges = conv_dm_get_num_edges;
+ converter->getNumVertices = conv_dm_get_num_verts;
+
+ converter->getNumFaceVertices = conv_dm_get_num_face_verts;
+ converter->getFaceVertices = conv_dm_get_face_verts;
+ converter->getFaceEdges = conv_dm_get_face_edges;
+
+ converter->getEdgeVertices = conv_dm_get_edge_verts;
+ converter->getNumEdgeFaces = conv_dm_get_num_edge_faces;
+ converter->getEdgeFaces = conv_dm_get_edge_faces;
+ converter->getEdgeSharpness = conv_dm_get_edge_sharpness;
+
+ converter->getNumVertexEdges = conv_dm_get_num_vert_edges;
+ converter->getVertexEdges = conv_dm_get_vert_edges;
+ converter->getNumVertexFaces = conv_dm_get_num_vert_faces;
+ converter->getVertexFaces = conv_dm_get_vert_faces;
+ converter->isInfiniteSharpVertex = conv_dm_is_infinite_sharp_vertex;
+ converter->getVertexSharpness = conv_dm_get_vertex_sharpness;
+
+ converter->getNumUVLayers = conv_dm_get_num_uv_layers;
+ converter->precalcUVLayer = conv_dm_precalc_uv_layer;
+ converter->finishUVLayer = conv_dm_finish_uv_layer;
+ converter->getNumUVCoordinates = conv_dm_get_num_uvs;
+ converter->getFaceCornerUVIndex = conv_dm_get_face_corner_uv_index;
+
+ user_data = MEM_mallocN(sizeof(ConvDMStorage), __func__);
+ user_data->ss = ss;
+ user_data->dm = dm;
+
+ user_data->mvert = dm->getVertArray(dm);
+ user_data->medge = dm->getEdgeArray(dm);
+ user_data->mloop = dm->getLoopArray(dm);
+ user_data->mpoly = dm->getPolyArray(dm);
+
+ memset(&user_data->island_store, 0, sizeof(user_data->island_store));
+
+ user_data->uvs = NULL;
+ user_data->face_uvs = NULL;
+
+ converter->freeUserData = conv_dm_free_user_data;
+ converter->user_data = user_data;
+
+# ifdef USE_MESH_ELEMENT_MAPPING
+ {
+ const MEdge *medge = dm->getEdgeArray(dm);
+ const MLoop *mloop = dm->getLoopArray(dm);
+ const MPoly *mpoly = dm->getPolyArray(dm);
+ const int num_vert = dm->getNumVerts(dm), num_edge = dm->getNumEdges(dm),
+ num_loop = dm->getNumLoops(dm), num_poly = dm->getNumPolys(dm);
+ BKE_mesh_vert_edge_map_create(
+ &user_data->vert_edge_map, &user_data->vert_edge_mem, medge, num_vert, num_edge);
+
+ BKE_mesh_vert_poly_map_create(&user_data->vert_poly_map,
+ &user_data->vert_poly_mem,
+ mpoly,
+ mloop,
+ num_vert,
+ num_poly,
+ num_loop);
+
+ BKE_mesh_edge_poly_map_create(&user_data->edge_poly_map,
+ &user_data->edge_poly_mem,
+ medge,
+ num_edge,
+ mpoly,
+ num_poly,
+ mloop,
+ num_loop);
+ }
+# endif /* USE_MESH_ELEMENT_MAPPING */
}
/**
* Converter from CCGSubSurf
*/
-static OpenSubdiv_SchemeType conv_ccg_get_bilinear_type(
- const OpenSubdiv_Converter *converter)
+static OpenSubdiv_SchemeType conv_ccg_get_bilinear_type(const OpenSubdiv_Converter *converter)
{
- CCGSubSurf *ss = converter->user_data;
- if (ss->meshIFC.simpleSubdiv) {
- return OSD_SCHEME_BILINEAR;
- }
- else {
- return OSD_SCHEME_CATMARK;
- }
+ CCGSubSurf *ss = converter->user_data;
+ if (ss->meshIFC.simpleSubdiv) {
+ return OSD_SCHEME_BILINEAR;
+ }
+ else {
+ return OSD_SCHEME_CATMARK;
+ }
}
-static OpenSubdiv_VtxBoundaryInterpolation
-conv_ccg_get_vtx_boundary_interpolation(
- const OpenSubdiv_Converter *UNUSED(converter))
+static OpenSubdiv_VtxBoundaryInterpolation conv_ccg_get_vtx_boundary_interpolation(
+ const OpenSubdiv_Converter *UNUSED(converter))
{
- return OSD_VTX_BOUNDARY_EDGE_ONLY;
+ return OSD_VTX_BOUNDARY_EDGE_ONLY;
}
-static OpenSubdiv_FVarLinearInterpolation
-conv_ccg_get_fvar_linear_interpolation(const OpenSubdiv_Converter *converter)
+static OpenSubdiv_FVarLinearInterpolation conv_ccg_get_fvar_linear_interpolation(
+ const OpenSubdiv_Converter *converter)
{
- CCGSubSurf *ss = converter->user_data;
- if (ss->osd_subdiv_uvs) {
- return OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY;
- }
- return OSD_FVAR_LINEAR_INTERPOLATION_ALL;
+ CCGSubSurf *ss = converter->user_data;
+ if (ss->osd_subdiv_uvs) {
+ return OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY;
+ }
+ return OSD_FVAR_LINEAR_INTERPOLATION_ALL;
}
-static bool conv_ccg_specifies_full_topology(
- const OpenSubdiv_Converter *UNUSED(converter))
+static bool conv_ccg_specifies_full_topology(const OpenSubdiv_Converter *UNUSED(converter))
{
- return true;
+ return true;
}
static int conv_ccg_get_num_faces(const OpenSubdiv_Converter *converter)
{
- CCGSubSurf *ss = converter->user_data;
- return ss->fMap->numEntries;
+ CCGSubSurf *ss = converter->user_data;
+ return ss->fMap->numEntries;
}
static int conv_ccg_get_num_edges(const OpenSubdiv_Converter *converter)
{
- CCGSubSurf *ss = converter->user_data;
- return ss->eMap->numEntries;
+ CCGSubSurf *ss = converter->user_data;
+ return ss->eMap->numEntries;
}
static int conv_ccg_get_num_verts(const OpenSubdiv_Converter *converter)
{
- CCGSubSurf *ss = converter->user_data;
- return ss->vMap->numEntries;
+ CCGSubSurf *ss = converter->user_data;
+ return ss->vMap->numEntries;
}
-static int conv_ccg_get_num_face_verts(const OpenSubdiv_Converter *converter,
- int face)
+static int conv_ccg_get_num_face_verts(const OpenSubdiv_Converter *converter, int face)
{
- CCGSubSurf *ss = converter->user_data;
- CCGFace *ccg_face = ccgSubSurf_getFace(ss, POINTER_FROM_INT(face));
- return ccgSubSurf_getFaceNumVerts(ccg_face);
+ CCGSubSurf *ss = converter->user_data;
+ CCGFace *ccg_face = ccgSubSurf_getFace(ss, POINTER_FROM_INT(face));
+ return ccgSubSurf_getFaceNumVerts(ccg_face);
}
static void conv_ccg_get_face_verts(const OpenSubdiv_Converter *converter,
int face,
int *face_verts)
{
- CCGSubSurf *ss = converter->user_data;
- CCGFace *ccg_face = ccgSubSurf_getFace(ss, POINTER_FROM_INT(face));
- int num_face_verts = ccgSubSurf_getFaceNumVerts(ccg_face);
- int loop;
- for (loop = 0; loop < num_face_verts; loop++) {
- CCGVert *ccg_vert = ccgSubSurf_getFaceVert(ccg_face, loop);
- face_verts[loop] = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert));
- }
+ CCGSubSurf *ss = converter->user_data;
+ CCGFace *ccg_face = ccgSubSurf_getFace(ss, POINTER_FROM_INT(face));
+ int num_face_verts = ccgSubSurf_getFaceNumVerts(ccg_face);
+ int loop;
+ for (loop = 0; loop < num_face_verts; loop++) {
+ CCGVert *ccg_vert = ccgSubSurf_getFaceVert(ccg_face, loop);
+ face_verts[loop] = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert));
+ }
}
static void conv_ccg_get_face_edges(const OpenSubdiv_Converter *converter,
int face,
int *face_edges)
{
- CCGSubSurf *ss = converter->user_data;
- CCGFace *ccg_face = ccgSubSurf_getFace(ss, POINTER_FROM_INT(face));
- int num_face_verts = ccgSubSurf_getFaceNumVerts(ccg_face);
- int loop;
- for (loop = 0; loop < num_face_verts; loop++) {
- CCGEdge *ccg_edge = ccgSubSurf_getFaceEdge(ccg_face, loop);
- face_edges[loop] = POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(ccg_edge));
- }
+ CCGSubSurf *ss = converter->user_data;
+ CCGFace *ccg_face = ccgSubSurf_getFace(ss, POINTER_FROM_INT(face));
+ int num_face_verts = ccgSubSurf_getFaceNumVerts(ccg_face);
+ int loop;
+ for (loop = 0; loop < num_face_verts; loop++) {
+ CCGEdge *ccg_edge = ccgSubSurf_getFaceEdge(ccg_face, loop);
+ face_edges[loop] = POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(ccg_edge));
+ }
}
static void conv_ccg_get_edge_verts(const OpenSubdiv_Converter *converter,
int edge,
int *edge_verts)
{
- CCGSubSurf *ss = converter->user_data;
- CCGEdge *ccg_edge = ccgSubSurf_getEdge(ss, POINTER_FROM_INT(edge));
- CCGVert *ccg_vert0 = ccgSubSurf_getEdgeVert0(ccg_edge);
- CCGVert *ccg_vert1 = ccgSubSurf_getEdgeVert1(ccg_edge);
- edge_verts[0] = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert0));
- edge_verts[1] = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert1));
+ CCGSubSurf *ss = converter->user_data;
+ CCGEdge *ccg_edge = ccgSubSurf_getEdge(ss, POINTER_FROM_INT(edge));
+ CCGVert *ccg_vert0 = ccgSubSurf_getEdgeVert0(ccg_edge);
+ CCGVert *ccg_vert1 = ccgSubSurf_getEdgeVert1(ccg_edge);
+ edge_verts[0] = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert0));
+ edge_verts[1] = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert1));
}
-static int conv_ccg_get_num_edge_faces(const OpenSubdiv_Converter *converter,
- int edge)
+static int conv_ccg_get_num_edge_faces(const OpenSubdiv_Converter *converter, int edge)
{
- CCGSubSurf *ss = converter->user_data;
- CCGEdge *ccg_edge = ccgSubSurf_getEdge(ss, POINTER_FROM_INT(edge));
- return ccgSubSurf_getEdgeNumFaces(ccg_edge);
+ CCGSubSurf *ss = converter->user_data;
+ CCGEdge *ccg_edge = ccgSubSurf_getEdge(ss, POINTER_FROM_INT(edge));
+ return ccgSubSurf_getEdgeNumFaces(ccg_edge);
}
static void conv_ccg_get_edge_faces(const OpenSubdiv_Converter *converter,
int edge,
int *edge_faces)
{
- CCGSubSurf *ss = converter->user_data;
- CCGEdge *ccg_edge = ccgSubSurf_getEdge(ss, POINTER_FROM_INT(edge));
- int num_edge_faces = ccgSubSurf_getEdgeNumFaces(ccg_edge);
- int face;
- for (face = 0; face < num_edge_faces; face++) {
- CCGFace *ccg_face = ccgSubSurf_getEdgeFace(ccg_edge, face);
- edge_faces[face] = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(ccg_face));
- }
+ CCGSubSurf *ss = converter->user_data;
+ CCGEdge *ccg_edge = ccgSubSurf_getEdge(ss, POINTER_FROM_INT(edge));
+ int num_edge_faces = ccgSubSurf_getEdgeNumFaces(ccg_edge);
+ int face;
+ for (face = 0; face < num_edge_faces; face++) {
+ CCGFace *ccg_face = ccgSubSurf_getEdgeFace(ccg_edge, face);
+ edge_faces[face] = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(ccg_face));
+ }
}
-static float conv_ccg_get_edge_sharpness(const OpenSubdiv_Converter *converter,
- int edge)
+static float conv_ccg_get_edge_sharpness(const OpenSubdiv_Converter *converter, int edge)
{
- CCGSubSurf *ss = converter->user_data;
- CCGEdge *ccg_edge = ccgSubSurf_getEdge(ss, POINTER_FROM_INT(edge));
- /* TODO(sergey): Multiply by subdivision level once CPU evaluator
- * is switched to uniform subdivision type.
- */
- return ccg_edge->crease;
+ CCGSubSurf *ss = converter->user_data;
+ CCGEdge *ccg_edge = ccgSubSurf_getEdge(ss, POINTER_FROM_INT(edge));
+ /* TODO(sergey): Multiply by subdivision level once CPU evaluator
+ * is switched to uniform subdivision type.
+ */
+ return ccg_edge->crease;
}
-static int conv_ccg_get_num_vert_edges(const OpenSubdiv_Converter *converter,
- int vert)
+static int conv_ccg_get_num_vert_edges(const OpenSubdiv_Converter *converter, int vert)
{
- CCGSubSurf *ss = converter->user_data;
- CCGVert *ccg_vert = ccgSubSurf_getVert(ss, POINTER_FROM_INT(vert));
- return ccgSubSurf_getVertNumEdges(ccg_vert);
+ CCGSubSurf *ss = converter->user_data;
+ CCGVert *ccg_vert = ccgSubSurf_getVert(ss, POINTER_FROM_INT(vert));
+ return ccgSubSurf_getVertNumEdges(ccg_vert);
}
static void conv_ccg_get_vert_edges(const OpenSubdiv_Converter *converter,
int vert,
int *vert_edges)
{
- CCGSubSurf *ss = converter->user_data;
- CCGVert *ccg_vert = ccgSubSurf_getVert(ss, POINTER_FROM_INT(vert));
- int num_vert_edges = ccgSubSurf_getVertNumEdges(ccg_vert);
- int edge;
- for (edge = 0; edge < num_vert_edges; edge++) {
- CCGEdge *ccg_edge = ccgSubSurf_getVertEdge(ccg_vert, edge);
- vert_edges[edge] = POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(ccg_edge));
- }
+ CCGSubSurf *ss = converter->user_data;
+ CCGVert *ccg_vert = ccgSubSurf_getVert(ss, POINTER_FROM_INT(vert));
+ int num_vert_edges = ccgSubSurf_getVertNumEdges(ccg_vert);
+ int edge;
+ for (edge = 0; edge < num_vert_edges; edge++) {
+ CCGEdge *ccg_edge = ccgSubSurf_getVertEdge(ccg_vert, edge);
+ vert_edges[edge] = POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(ccg_edge));
+ }
}
-static int conv_ccg_get_num_vert_faces(const OpenSubdiv_Converter *converter,
- int vert)
+static int conv_ccg_get_num_vert_faces(const OpenSubdiv_Converter *converter, int vert)
{
- CCGSubSurf *ss = converter->user_data;
- CCGVert *ccg_vert = ccgSubSurf_getVert(ss, POINTER_FROM_INT(vert));
- return ccgSubSurf_getVertNumFaces(ccg_vert);
+ CCGSubSurf *ss = converter->user_data;
+ CCGVert *ccg_vert = ccgSubSurf_getVert(ss, POINTER_FROM_INT(vert));
+ return ccgSubSurf_getVertNumFaces(ccg_vert);
}
static void conv_ccg_get_vert_faces(const OpenSubdiv_Converter *converter,
int vert,
int *vert_faces)
{
- CCGSubSurf *ss = converter->user_data;
- CCGVert *ccg_vert = ccgSubSurf_getVert(ss, POINTER_FROM_INT(vert));
- int num_vert_faces = ccgSubSurf_getVertNumFaces(ccg_vert);
- int face;
- for (face = 0; face < num_vert_faces; face++) {
- CCGFace *ccg_face = ccgSubSurf_getVertFace(ccg_vert, face);
- vert_faces[face] = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(ccg_face));
- }
+ CCGSubSurf *ss = converter->user_data;
+ CCGVert *ccg_vert = ccgSubSurf_getVert(ss, POINTER_FROM_INT(vert));
+ int num_vert_faces = ccgSubSurf_getVertNumFaces(ccg_vert);
+ int face;
+ for (face = 0; face < num_vert_faces; face++) {
+ CCGFace *ccg_face = ccgSubSurf_getVertFace(ccg_vert, face);
+ vert_faces[face] = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(ccg_face));
+ }
}
-static bool conv_ccg_is_infinite_sharp_vertex(
- const OpenSubdiv_Converter *UNUSED(converter),
- int UNUSED(manifold_vertex_index))
+static bool conv_ccg_is_infinite_sharp_vertex(const OpenSubdiv_Converter *UNUSED(converter),
+ int UNUSED(manifold_vertex_index))
{
- return false;
+ return false;
}
-static float conv_ccg_get_vertex_sharpness(
- const OpenSubdiv_Converter *UNUSED(converter),
- int UNUSED(manifold_vertex_index))
+static float conv_ccg_get_vertex_sharpness(const OpenSubdiv_Converter *UNUSED(converter),
+ int UNUSED(manifold_vertex_index))
{
- return 0.0f;
+ return 0.0f;
}
static int conv_ccg_get_num_uv_layers(const OpenSubdiv_Converter *UNUSED(converter))
{
- return 0;
+ return 0;
}
-static void conv_ccg_precalc_uv_layer(const OpenSubdiv_Converter * UNUSED(converter),
+static void conv_ccg_precalc_uv_layer(const OpenSubdiv_Converter *UNUSED(converter),
int UNUSED(layer))
{
}
@@ -747,63 +717,59 @@ static void conv_ccg_finish_uv_layer(const OpenSubdiv_Converter *UNUSED(converte
static int conv_ccg_get_num_uvs(const OpenSubdiv_Converter *UNUSED(converter))
{
- return 0;
+ return 0;
}
static int conv_ccg_get_face_corner_uv_index(const OpenSubdiv_Converter *UNUSED(converter),
int UNUSED(face),
int UNUSED(corner_))
{
- return 0;
+ return 0;
}
-void ccgSubSurf_converter_setup_from_ccg(CCGSubSurf *ss,
- OpenSubdiv_Converter *converter)
+void ccgSubSurf_converter_setup_from_ccg(CCGSubSurf *ss, OpenSubdiv_Converter *converter)
{
- converter->getSchemeType = conv_ccg_get_bilinear_type;
+ converter->getSchemeType = conv_ccg_get_bilinear_type;
- converter->getVtxBoundaryInterpolation =
- conv_ccg_get_vtx_boundary_interpolation;
- converter->getFVarLinearInterpolation =
- conv_ccg_get_fvar_linear_interpolation;
- converter->specifiesFullTopology = conv_ccg_specifies_full_topology;
+ converter->getVtxBoundaryInterpolation = conv_ccg_get_vtx_boundary_interpolation;
+ converter->getFVarLinearInterpolation = conv_ccg_get_fvar_linear_interpolation;
+ converter->specifiesFullTopology = conv_ccg_specifies_full_topology;
- converter->getNumFaces = conv_ccg_get_num_faces;
- converter->getNumEdges = conv_ccg_get_num_edges;
- converter->getNumVertices = conv_ccg_get_num_verts;
+ converter->getNumFaces = conv_ccg_get_num_faces;
+ converter->getNumEdges = conv_ccg_get_num_edges;
+ converter->getNumVertices = conv_ccg_get_num_verts;
- converter->getNumFaceVertices = conv_ccg_get_num_face_verts;
- converter->getFaceVertices = conv_ccg_get_face_verts;
- converter->getFaceEdges = conv_ccg_get_face_edges;
+ converter->getNumFaceVertices = conv_ccg_get_num_face_verts;
+ converter->getFaceVertices = conv_ccg_get_face_verts;
+ converter->getFaceEdges = conv_ccg_get_face_edges;
- converter->getEdgeVertices = conv_ccg_get_edge_verts;
- converter->getNumEdgeFaces = conv_ccg_get_num_edge_faces;
- converter->getEdgeFaces = conv_ccg_get_edge_faces;
- converter->getEdgeSharpness = conv_ccg_get_edge_sharpness;
+ converter->getEdgeVertices = conv_ccg_get_edge_verts;
+ converter->getNumEdgeFaces = conv_ccg_get_num_edge_faces;
+ converter->getEdgeFaces = conv_ccg_get_edge_faces;
+ converter->getEdgeSharpness = conv_ccg_get_edge_sharpness;
- converter->getNumVertexEdges = conv_ccg_get_num_vert_edges;
- converter->getVertexEdges = conv_ccg_get_vert_edges;
- converter->getNumVertexFaces = conv_ccg_get_num_vert_faces;
- converter->getVertexFaces = conv_ccg_get_vert_faces;
- converter->isInfiniteSharpVertex = conv_ccg_is_infinite_sharp_vertex;
- converter->getVertexSharpness = conv_ccg_get_vertex_sharpness;
+ converter->getNumVertexEdges = conv_ccg_get_num_vert_edges;
+ converter->getVertexEdges = conv_ccg_get_vert_edges;
+ converter->getNumVertexFaces = conv_ccg_get_num_vert_faces;
+ converter->getVertexFaces = conv_ccg_get_vert_faces;
+ converter->isInfiniteSharpVertex = conv_ccg_is_infinite_sharp_vertex;
+ converter->getVertexSharpness = conv_ccg_get_vertex_sharpness;
- converter->getNumUVLayers = conv_ccg_get_num_uv_layers;
- converter->precalcUVLayer = conv_ccg_precalc_uv_layer;
- converter->finishUVLayer = conv_ccg_finish_uv_layer;
- converter->getNumUVCoordinates = conv_ccg_get_num_uvs;
- converter->getFaceCornerUVIndex = conv_ccg_get_face_corner_uv_index;
+ converter->getNumUVLayers = conv_ccg_get_num_uv_layers;
+ converter->precalcUVLayer = conv_ccg_precalc_uv_layer;
+ converter->finishUVLayer = conv_ccg_finish_uv_layer;
+ converter->getNumUVCoordinates = conv_ccg_get_num_uvs;
+ converter->getFaceCornerUVIndex = conv_ccg_get_face_corner_uv_index;
- converter->freeUserData = NULL;
- converter->user_data = ss;
+ converter->freeUserData = NULL;
+ converter->user_data = ss;
}
-void ccgSubSurf_converter_free(
- struct OpenSubdiv_Converter *converter)
+void ccgSubSurf_converter_free(struct OpenSubdiv_Converter *converter)
{
- if (converter->freeUserData) {
- converter->freeUserData(converter);
- }
+ if (converter->freeUserData) {
+ converter->freeUserData(converter);
+ }
}
-#endif /* WITH_OPENSUBDIV */
+#endif /* WITH_OPENSUBDIV */
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_util.c b/source/blender/blenkernel/intern/CCGSubSurf_util.c
index c47a922cc2a..9ad1b0cf1b1 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_util.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf_util.c
@@ -23,7 +23,7 @@
#include <math.h>
#include "MEM_guardedalloc.h"
-#include "BLI_sys_types.h" // for intptr_t support
+#include "BLI_sys_types.h" // for intptr_t support
#include "BLI_utildefines.h" /* for BLI_assert */
@@ -35,9 +35,9 @@
*/
static int kHashSizes[] = {
- 1, 3, 5, 11, 17, 37, 67, 131, 257, 521, 1031, 2053, 4099, 8209,
- 16411, 32771, 65537, 131101, 262147, 524309, 1048583, 2097169,
- 4194319, 8388617, 16777259, 33554467, 67108879, 134217757, 268435459,
+ 1, 3, 5, 11, 17, 37, 67, 131, 257, 521,
+ 1031, 2053, 4099, 8209, 16411, 32771, 65537, 131101, 262147, 524309,
+ 1048583, 2097169, 4194319, 8388617, 16777259, 33554467, 67108879, 134217757, 268435459,
};
/* Generic hash functions. */
@@ -46,137 +46,137 @@ EHash *ccg_ehash_new(int estimatedNumEntries,
CCGAllocatorIFC *allocatorIFC,
CCGAllocatorHDL allocator)
{
- EHash *eh = allocatorIFC->alloc(allocator, sizeof(*eh));
- eh->allocatorIFC = *allocatorIFC;
- eh->allocator = allocator;
- eh->numEntries = 0;
- eh->curSizeIdx = 0;
- while (kHashSizes[eh->curSizeIdx] < estimatedNumEntries)
- eh->curSizeIdx++;
- eh->curSize = kHashSizes[eh->curSizeIdx];
- eh->buckets = EHASH_alloc(eh, eh->curSize * sizeof(*eh->buckets));
- memset(eh->buckets, 0, eh->curSize * sizeof(*eh->buckets));
-
- return eh;
+ EHash *eh = allocatorIFC->alloc(allocator, sizeof(*eh));
+ eh->allocatorIFC = *allocatorIFC;
+ eh->allocator = allocator;
+ eh->numEntries = 0;
+ eh->curSizeIdx = 0;
+ while (kHashSizes[eh->curSizeIdx] < estimatedNumEntries)
+ eh->curSizeIdx++;
+ eh->curSize = kHashSizes[eh->curSizeIdx];
+ eh->buckets = EHASH_alloc(eh, eh->curSize * sizeof(*eh->buckets));
+ memset(eh->buckets, 0, eh->curSize * sizeof(*eh->buckets));
+
+ return eh;
}
void ccg_ehash_free(EHash *eh, EHEntryFreeFP freeEntry, void *userData)
{
- int numBuckets = eh->curSize;
+ int numBuckets = eh->curSize;
- while (numBuckets--) {
- EHEntry *entry = eh->buckets[numBuckets];
+ while (numBuckets--) {
+ EHEntry *entry = eh->buckets[numBuckets];
- while (entry) {
- EHEntry *next = entry->next;
+ while (entry) {
+ EHEntry *next = entry->next;
- freeEntry(entry, userData);
+ freeEntry(entry, userData);
- entry = next;
- }
- }
+ entry = next;
+ }
+ }
- EHASH_free(eh, eh->buckets);
- EHASH_free(eh, eh);
+ EHASH_free(eh, eh->buckets);
+ EHASH_free(eh, eh);
}
void ccg_ehash_insert(EHash *eh, EHEntry *entry)
{
- int numBuckets = eh->curSize;
- int hash = EHASH_hash(eh, entry->key);
- entry->next = eh->buckets[hash];
- eh->buckets[hash] = entry;
- eh->numEntries++;
+ int numBuckets = eh->curSize;
+ int hash = EHASH_hash(eh, entry->key);
+ entry->next = eh->buckets[hash];
+ eh->buckets[hash] = entry;
+ eh->numEntries++;
- if (UNLIKELY(eh->numEntries > (numBuckets * 3))) {
- EHEntry **oldBuckets = eh->buckets;
- eh->curSize = kHashSizes[++eh->curSizeIdx];
+ if (UNLIKELY(eh->numEntries > (numBuckets * 3))) {
+ EHEntry **oldBuckets = eh->buckets;
+ eh->curSize = kHashSizes[++eh->curSizeIdx];
- eh->buckets = EHASH_alloc(eh, eh->curSize * sizeof(*eh->buckets));
- memset(eh->buckets, 0, eh->curSize * sizeof(*eh->buckets));
+ eh->buckets = EHASH_alloc(eh, eh->curSize * sizeof(*eh->buckets));
+ memset(eh->buckets, 0, eh->curSize * sizeof(*eh->buckets));
- while (numBuckets--) {
- for (entry = oldBuckets[numBuckets]; entry; ) {
- EHEntry *next = entry->next;
+ while (numBuckets--) {
+ for (entry = oldBuckets[numBuckets]; entry;) {
+ EHEntry *next = entry->next;
- hash = EHASH_hash(eh, entry->key);
- entry->next = eh->buckets[hash];
- eh->buckets[hash] = entry;
+ hash = EHASH_hash(eh, entry->key);
+ entry->next = eh->buckets[hash];
+ eh->buckets[hash] = entry;
- entry = next;
- }
- }
+ entry = next;
+ }
+ }
- EHASH_free(eh, oldBuckets);
- }
+ EHASH_free(eh, oldBuckets);
+ }
}
void *ccg_ehash_lookupWithPrev(EHash *eh, void *key, void ***prevp_r)
{
- int hash = EHASH_hash(eh, key);
- void **prevp = (void **) &eh->buckets[hash];
- EHEntry *entry;
-
- for (; (entry = *prevp); prevp = (void **) &entry->next) {
- if (entry->key == key) {
- *prevp_r = (void **) prevp;
- return entry;
- }
- }
-
- return NULL;
+ int hash = EHASH_hash(eh, key);
+ void **prevp = (void **)&eh->buckets[hash];
+ EHEntry *entry;
+
+ for (; (entry = *prevp); prevp = (void **)&entry->next) {
+ if (entry->key == key) {
+ *prevp_r = (void **)prevp;
+ return entry;
+ }
+ }
+
+ return NULL;
}
void *ccg_ehash_lookup(EHash *eh, void *key)
{
- int hash = EHASH_hash(eh, key);
- EHEntry *entry;
+ int hash = EHASH_hash(eh, key);
+ EHEntry *entry;
- for (entry = eh->buckets[hash]; entry; entry = entry->next) {
- if (entry->key == key)
- break;
- }
+ for (entry = eh->buckets[hash]; entry; entry = entry->next) {
+ if (entry->key == key)
+ break;
+ }
- return entry;
+ return entry;
}
/* Hash elements iteration. */
void ccg_ehashIterator_init(EHash *eh, EHashIterator *ehi)
{
- /* fill all members */
- ehi->eh = eh;
- ehi->curBucket = -1;
- ehi->curEntry = NULL;
-
- while (!ehi->curEntry) {
- ehi->curBucket++;
- if (ehi->curBucket == ehi->eh->curSize)
- break;
- ehi->curEntry = ehi->eh->buckets[ehi->curBucket];
- }
+ /* fill all members */
+ ehi->eh = eh;
+ ehi->curBucket = -1;
+ ehi->curEntry = NULL;
+
+ while (!ehi->curEntry) {
+ ehi->curBucket++;
+ if (ehi->curBucket == ehi->eh->curSize)
+ break;
+ ehi->curEntry = ehi->eh->buckets[ehi->curBucket];
+ }
}
void *ccg_ehashIterator_getCurrent(EHashIterator *ehi)
{
- return ehi->curEntry;
+ return ehi->curEntry;
}
void ccg_ehashIterator_next(EHashIterator *ehi)
{
- if (ehi->curEntry) {
- ehi->curEntry = ehi->curEntry->next;
- while (!ehi->curEntry) {
- ehi->curBucket++;
- if (ehi->curBucket == ehi->eh->curSize)
- break;
- ehi->curEntry = ehi->eh->buckets[ehi->curBucket];
- }
- }
+ if (ehi->curEntry) {
+ ehi->curEntry = ehi->curEntry->next;
+ while (!ehi->curEntry) {
+ ehi->curBucket++;
+ if (ehi->curBucket == ehi->eh->curSize)
+ break;
+ ehi->curEntry = ehi->eh->buckets[ehi->curBucket];
+ }
+ }
}
int ccg_ehashIterator_isStopped(EHashIterator *ehi)
{
- return !ehi->curEntry;
+ return !ehi->curEntry;
}
/**
@@ -185,7 +185,7 @@ int ccg_ehashIterator_isStopped(EHashIterator *ehi)
static void *_stdAllocator_alloc(CCGAllocatorHDL UNUSED(a), int numBytes)
{
- return MEM_mallocN(numBytes, "CCG standard alloc");
+ return MEM_mallocN(numBytes, "CCG standard alloc");
}
static void *_stdAllocator_realloc(CCGAllocatorHDL UNUSED(a),
@@ -193,24 +193,24 @@ static void *_stdAllocator_realloc(CCGAllocatorHDL UNUSED(a),
int newSize,
int UNUSED(oldSize))
{
- return MEM_reallocN(ptr, newSize);
+ return MEM_reallocN(ptr, newSize);
}
static void _stdAllocator_free(CCGAllocatorHDL UNUSED(a), void *ptr)
{
- MEM_freeN(ptr);
+ MEM_freeN(ptr);
}
CCGAllocatorIFC *ccg_getStandardAllocatorIFC(void)
{
- static CCGAllocatorIFC ifc;
+ static CCGAllocatorIFC ifc;
- ifc.alloc = _stdAllocator_alloc;
- ifc.realloc = _stdAllocator_realloc;
- ifc.free = _stdAllocator_free;
- ifc.release = NULL;
+ ifc.alloc = _stdAllocator_alloc;
+ ifc.realloc = _stdAllocator_realloc;
+ ifc.free = _stdAllocator_free;
+ ifc.release = NULL;
- return &ifc;
+ return &ifc;
}
/**
@@ -220,83 +220,96 @@ CCGAllocatorIFC *ccg_getStandardAllocatorIFC(void)
#ifdef DUMP_RESULT_GRIDS
void ccgSubSurf__dumpCoords(CCGSubSurf *ss)
{
- int vertDataSize = ss->meshIFC.vertDataSize;
- int subdivLevels = ss->subdivLevels;
- int gridSize = ccg_gridsize(subdivLevels);
- int edgeSize = ccg_edgesize(subdivLevels);
- int i, index, S;
-
- for (i = 0, index = 0; i < ss->vMap->curSize; i++) {
- CCGVert *v = (CCGVert *) ss->vMap->buckets[i];
- for (; v; v = v->next, index++) {
- float *co = VERT_getCo(v, subdivLevels);
- printf("vertex index=%d, co=(%f, %f, %f)\n",
- index, co[0], co[1], co[2]);
- }
- }
-
- for (i = 0, index = 0; i < ss->eMap->curSize; i++) {
- CCGEdge *e = (CCGEdge *) ss->eMap->buckets[i];
- for (; e; e = e->next, index++) {
- int x;
- float *co = VERT_getCo(e->v0, subdivLevels);
- printf("edge index=%d, start_co=(%f, %f, %f)\n",
- index, co[0], co[1], co[2]);
- for (x = 0; x < edgeSize; x++) {
- float *co = EDGE_getCo(e, subdivLevels, x);
- printf("edge index=%d, seg=%d, co=(%f, %f, %f)\n",
- index, x, co[0], co[1], co[2]);
- }
- co = VERT_getCo(e->v1, subdivLevels);
- printf("edge index=%d, end_co=(%f, %f, %f)\n",
- index, co[0], co[1], co[2]);
- }
- }
-
- for (i = 0, index = 0; i < ss->fMap->curSize; i++) {
- CCGFace *f = (CCGFace *) ss->fMap->buckets[i];
- for (; f; f = f->next, index++) {
- for (S = 0; S < f->numVerts; S++) {
- CCGVert *v = FACE_getVerts(f)[S];
- float *co = VERT_getCo(v, subdivLevels);
- printf("face index=%d, vertex=%d, coord=(%f, %f, %f)\n",
- index, S, co[0], co[1], co[2]);
- }
- }
- }
-
- for (i = 0, index = 0; i < ss->fMap->curSize; i++) {
- CCGFace *f = (CCGFace *) ss->fMap->buckets[i];
- for (; f; f = f->next, index++) {
- for (S = 0; S < f->numVerts; S++) {
- CCGEdge *e = FACE_getEdges(f)[S];
- float *co1 = VERT_getCo(e->v0, subdivLevels);
- float *co2 = VERT_getCo(e->v1, subdivLevels);
- printf("face index=%d, edge=%d, coord1=(%f, %f, %f), coord2=(%f, %f, %f)\n",
- index, S, co1[0], co1[1], co1[2], co2[0], co2[1], co2[2]);
- }
- }
- }
-
- for (i = 0, index = 0; i < ss->fMap->curSize; i++) {
- CCGFace *f = (CCGFace *) ss->fMap->buckets[i];
- for (; f; f = f->next, index++) {
- for (S = 0; S < f->numVerts; S++) {
- int x, y;
- for (x = 0; x < gridSize; x++) {
- for (y = 0; y < gridSize; y++) {
- float *co = FACE_getIFCo(f, subdivLevels, S, x, y);
- printf("face index=%d. corner=%d, x=%d, y=%d, coord=(%f, %f, %f)\n",
- index, S, x, y, co[0], co[1], co[2]);
- }
- }
- for (x = 0; x < gridSize; x++) {
- float *co = FACE_getIECo(f, subdivLevels, S, x);
- printf("face index=%d. cornder=%d, ie_index=%d, coord=(%f, %f, %f)\n",
- index, S, x, co[0], co[1], co[2]);
- }
- }
- }
- }
+ int vertDataSize = ss->meshIFC.vertDataSize;
+ int subdivLevels = ss->subdivLevels;
+ int gridSize = ccg_gridsize(subdivLevels);
+ int edgeSize = ccg_edgesize(subdivLevels);
+ int i, index, S;
+
+ for (i = 0, index = 0; i < ss->vMap->curSize; i++) {
+ CCGVert *v = (CCGVert *)ss->vMap->buckets[i];
+ for (; v; v = v->next, index++) {
+ float *co = VERT_getCo(v, subdivLevels);
+ printf("vertex index=%d, co=(%f, %f, %f)\n", index, co[0], co[1], co[2]);
+ }
+ }
+
+ for (i = 0, index = 0; i < ss->eMap->curSize; i++) {
+ CCGEdge *e = (CCGEdge *)ss->eMap->buckets[i];
+ for (; e; e = e->next, index++) {
+ int x;
+ float *co = VERT_getCo(e->v0, subdivLevels);
+ printf("edge index=%d, start_co=(%f, %f, %f)\n", index, co[0], co[1], co[2]);
+ for (x = 0; x < edgeSize; x++) {
+ float *co = EDGE_getCo(e, subdivLevels, x);
+ printf("edge index=%d, seg=%d, co=(%f, %f, %f)\n", index, x, co[0], co[1], co[2]);
+ }
+ co = VERT_getCo(e->v1, subdivLevels);
+ printf("edge index=%d, end_co=(%f, %f, %f)\n", index, co[0], co[1], co[2]);
+ }
+ }
+
+ for (i = 0, index = 0; i < ss->fMap->curSize; i++) {
+ CCGFace *f = (CCGFace *)ss->fMap->buckets[i];
+ for (; f; f = f->next, index++) {
+ for (S = 0; S < f->numVerts; S++) {
+ CCGVert *v = FACE_getVerts(f)[S];
+ float *co = VERT_getCo(v, subdivLevels);
+ printf("face index=%d, vertex=%d, coord=(%f, %f, %f)\n", index, S, co[0], co[1], co[2]);
+ }
+ }
+ }
+
+ for (i = 0, index = 0; i < ss->fMap->curSize; i++) {
+ CCGFace *f = (CCGFace *)ss->fMap->buckets[i];
+ for (; f; f = f->next, index++) {
+ for (S = 0; S < f->numVerts; S++) {
+ CCGEdge *e = FACE_getEdges(f)[S];
+ float *co1 = VERT_getCo(e->v0, subdivLevels);
+ float *co2 = VERT_getCo(e->v1, subdivLevels);
+ printf("face index=%d, edge=%d, coord1=(%f, %f, %f), coord2=(%f, %f, %f)\n",
+ index,
+ S,
+ co1[0],
+ co1[1],
+ co1[2],
+ co2[0],
+ co2[1],
+ co2[2]);
+ }
+ }
+ }
+
+ for (i = 0, index = 0; i < ss->fMap->curSize; i++) {
+ CCGFace *f = (CCGFace *)ss->fMap->buckets[i];
+ for (; f; f = f->next, index++) {
+ for (S = 0; S < f->numVerts; S++) {
+ int x, y;
+ for (x = 0; x < gridSize; x++) {
+ for (y = 0; y < gridSize; y++) {
+ float *co = FACE_getIFCo(f, subdivLevels, S, x, y);
+ printf("face index=%d. corner=%d, x=%d, y=%d, coord=(%f, %f, %f)\n",
+ index,
+ S,
+ x,
+ y,
+ co[0],
+ co[1],
+ co[2]);
+ }
+ }
+ for (x = 0; x < gridSize; x++) {
+ float *co = FACE_getIECo(f, subdivLevels, S, x);
+ printf("face index=%d. cornder=%d, ie_index=%d, coord=(%f, %f, %f)\n",
+ index,
+ S,
+ x,
+ co[0],
+ co[1],
+ co[2]);
+ }
+ }
+ }
+ }
}
-#endif /* DUMP_RESULT_GRIDS */
+#endif /* DUMP_RESULT_GRIDS */
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 02afdfe035b..2c22f744125 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -21,7 +21,6 @@
* \ingroup bke
*/
-
#include <string.h>
#include <limits.h>
@@ -81,7 +80,8 @@
#ifdef USE_MODIFIER_VALIDATE
# define ASSERT_IS_VALID_DM(dm) (BLI_assert((dm == NULL) || (DM_is_valid(dm) == true)))
-# define ASSERT_IS_VALID_MESH(mesh) (BLI_assert((mesh == NULL) || (BKE_mesh_is_valid(mesh) == true)))
+# define ASSERT_IS_VALID_MESH(mesh) \
+ (BLI_assert((mesh == NULL) || (BKE_mesh_is_valid(mesh) == true)))
#else
# define ASSERT_IS_VALID_DM(dm)
# define ASSERT_IS_VALID_MESH(mesh)
@@ -90,197 +90,191 @@
static CLG_LogRef LOG = {"bke.derivedmesh"};
static ThreadRWMutex loops_cache_lock = PTHREAD_RWLOCK_INITIALIZER;
-
static void shapekey_layers_to_keyblocks(DerivedMesh *dm, Mesh *me, int actshape_uid);
static void mesh_init_origspace(Mesh *mesh);
-
/* -------------------------------------------------------------------- */
static MVert *dm_getVertArray(DerivedMesh *dm)
{
- MVert *mvert = CustomData_get_layer(&dm->vertData, CD_MVERT);
+ MVert *mvert = CustomData_get_layer(&dm->vertData, CD_MVERT);
- if (!mvert) {
- mvert = CustomData_add_layer(&dm->vertData, CD_MVERT, CD_CALLOC, NULL,
- dm->getNumVerts(dm));
- CustomData_set_layer_flag(&dm->vertData, CD_MVERT, CD_FLAG_TEMPORARY);
- dm->copyVertArray(dm, mvert);
- }
+ if (!mvert) {
+ mvert = CustomData_add_layer(&dm->vertData, CD_MVERT, CD_CALLOC, NULL, dm->getNumVerts(dm));
+ CustomData_set_layer_flag(&dm->vertData, CD_MVERT, CD_FLAG_TEMPORARY);
+ dm->copyVertArray(dm, mvert);
+ }
- return mvert;
+ return mvert;
}
static MEdge *dm_getEdgeArray(DerivedMesh *dm)
{
- MEdge *medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
+ MEdge *medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
- if (!medge) {
- medge = CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_CALLOC, NULL,
- dm->getNumEdges(dm));
- CustomData_set_layer_flag(&dm->edgeData, CD_MEDGE, CD_FLAG_TEMPORARY);
- dm->copyEdgeArray(dm, medge);
- }
+ if (!medge) {
+ medge = CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_CALLOC, NULL, dm->getNumEdges(dm));
+ CustomData_set_layer_flag(&dm->edgeData, CD_MEDGE, CD_FLAG_TEMPORARY);
+ dm->copyEdgeArray(dm, medge);
+ }
- return medge;
+ return medge;
}
static MFace *dm_getTessFaceArray(DerivedMesh *dm)
{
- MFace *mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
+ MFace *mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
- if (!mface) {
- int numTessFaces = dm->getNumTessFaces(dm);
+ if (!mface) {
+ int numTessFaces = dm->getNumTessFaces(dm);
- if (!numTessFaces) {
- /* Do not add layer if there's no elements in it, this leads to issues later when
- * this layer is needed with non-zero size, but currently CD stuff does not check
- * for requested layer size on creation and just returns layer which was previously
- * added (sergey) */
- return NULL;
- }
+ if (!numTessFaces) {
+ /* Do not add layer if there's no elements in it, this leads to issues later when
+ * this layer is needed with non-zero size, but currently CD stuff does not check
+ * for requested layer size on creation and just returns layer which was previously
+ * added (sergey) */
+ return NULL;
+ }
- mface = CustomData_add_layer(&dm->faceData, CD_MFACE, CD_CALLOC, NULL, numTessFaces);
- CustomData_set_layer_flag(&dm->faceData, CD_MFACE, CD_FLAG_TEMPORARY);
- dm->copyTessFaceArray(dm, mface);
- }
+ mface = CustomData_add_layer(&dm->faceData, CD_MFACE, CD_CALLOC, NULL, numTessFaces);
+ CustomData_set_layer_flag(&dm->faceData, CD_MFACE, CD_FLAG_TEMPORARY);
+ dm->copyTessFaceArray(dm, mface);
+ }
- return mface;
+ return mface;
}
static MLoop *dm_getLoopArray(DerivedMesh *dm)
{
- MLoop *mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
+ MLoop *mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
- if (!mloop) {
- mloop = CustomData_add_layer(&dm->loopData, CD_MLOOP, CD_CALLOC, NULL,
- dm->getNumLoops(dm));
- CustomData_set_layer_flag(&dm->loopData, CD_MLOOP, CD_FLAG_TEMPORARY);
- dm->copyLoopArray(dm, mloop);
- }
+ if (!mloop) {
+ mloop = CustomData_add_layer(&dm->loopData, CD_MLOOP, CD_CALLOC, NULL, dm->getNumLoops(dm));
+ CustomData_set_layer_flag(&dm->loopData, CD_MLOOP, CD_FLAG_TEMPORARY);
+ dm->copyLoopArray(dm, mloop);
+ }
- return mloop;
+ return mloop;
}
static MPoly *dm_getPolyArray(DerivedMesh *dm)
{
- MPoly *mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
+ MPoly *mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
- if (!mpoly) {
- mpoly = CustomData_add_layer(&dm->polyData, CD_MPOLY, CD_CALLOC, NULL,
- dm->getNumPolys(dm));
- CustomData_set_layer_flag(&dm->polyData, CD_MPOLY, CD_FLAG_TEMPORARY);
- dm->copyPolyArray(dm, mpoly);
- }
+ if (!mpoly) {
+ mpoly = CustomData_add_layer(&dm->polyData, CD_MPOLY, CD_CALLOC, NULL, dm->getNumPolys(dm));
+ CustomData_set_layer_flag(&dm->polyData, CD_MPOLY, CD_FLAG_TEMPORARY);
+ dm->copyPolyArray(dm, mpoly);
+ }
- return mpoly;
+ return mpoly;
}
static MVert *dm_dupVertArray(DerivedMesh *dm)
{
- MVert *tmp = MEM_malloc_arrayN(dm->getNumVerts(dm), sizeof(*tmp),
- "dm_dupVertArray tmp");
+ MVert *tmp = MEM_malloc_arrayN(dm->getNumVerts(dm), sizeof(*tmp), "dm_dupVertArray tmp");
- if (tmp) dm->copyVertArray(dm, tmp);
+ if (tmp)
+ dm->copyVertArray(dm, tmp);
- return tmp;
+ return tmp;
}
static MEdge *dm_dupEdgeArray(DerivedMesh *dm)
{
- MEdge *tmp = MEM_malloc_arrayN(dm->getNumEdges(dm), sizeof(*tmp),
- "dm_dupEdgeArray tmp");
+ MEdge *tmp = MEM_malloc_arrayN(dm->getNumEdges(dm), sizeof(*tmp), "dm_dupEdgeArray tmp");
- if (tmp) dm->copyEdgeArray(dm, tmp);
+ if (tmp)
+ dm->copyEdgeArray(dm, tmp);
- return tmp;
+ return tmp;
}
static MFace *dm_dupFaceArray(DerivedMesh *dm)
{
- MFace *tmp = MEM_malloc_arrayN(dm->getNumTessFaces(dm), sizeof(*tmp),
- "dm_dupFaceArray tmp");
+ MFace *tmp = MEM_malloc_arrayN(dm->getNumTessFaces(dm), sizeof(*tmp), "dm_dupFaceArray tmp");
- if (tmp) dm->copyTessFaceArray(dm, tmp);
+ if (tmp)
+ dm->copyTessFaceArray(dm, tmp);
- return tmp;
+ return tmp;
}
static MLoop *dm_dupLoopArray(DerivedMesh *dm)
{
- MLoop *tmp = MEM_malloc_arrayN(dm->getNumLoops(dm), sizeof(*tmp),
- "dm_dupLoopArray tmp");
+ MLoop *tmp = MEM_malloc_arrayN(dm->getNumLoops(dm), sizeof(*tmp), "dm_dupLoopArray tmp");
- if (tmp) dm->copyLoopArray(dm, tmp);
+ if (tmp)
+ dm->copyLoopArray(dm, tmp);
- return tmp;
+ return tmp;
}
static MPoly *dm_dupPolyArray(DerivedMesh *dm)
{
- MPoly *tmp = MEM_malloc_arrayN(dm->getNumPolys(dm), sizeof(*tmp),
- "dm_dupPolyArray tmp");
+ MPoly *tmp = MEM_malloc_arrayN(dm->getNumPolys(dm), sizeof(*tmp), "dm_dupPolyArray tmp");
- if (tmp) dm->copyPolyArray(dm, tmp);
+ if (tmp)
+ dm->copyPolyArray(dm, tmp);
- return tmp;
+ return tmp;
}
static int dm_getNumLoopTri(DerivedMesh *dm)
{
- const int numlooptris = poly_to_tri_count(dm->getNumPolys(dm), dm->getNumLoops(dm));
- BLI_assert(ELEM(dm->looptris.num, 0, numlooptris));
- return numlooptris;
+ const int numlooptris = poly_to_tri_count(dm->getNumPolys(dm), dm->getNumLoops(dm));
+ BLI_assert(ELEM(dm->looptris.num, 0, numlooptris));
+ return numlooptris;
}
static const MLoopTri *dm_getLoopTriArray(DerivedMesh *dm)
{
- MLoopTri *looptri;
+ MLoopTri *looptri;
- BLI_rw_mutex_lock(&loops_cache_lock, THREAD_LOCK_READ);
- looptri = dm->looptris.array;
- BLI_rw_mutex_unlock(&loops_cache_lock);
+ BLI_rw_mutex_lock(&loops_cache_lock, THREAD_LOCK_READ);
+ looptri = dm->looptris.array;
+ BLI_rw_mutex_unlock(&loops_cache_lock);
- if (looptri != NULL) {
- BLI_assert(dm->getNumLoopTri(dm) == dm->looptris.num);
- }
- else {
- BLI_rw_mutex_lock(&loops_cache_lock, THREAD_LOCK_WRITE);
- /* We need to ensure array is still NULL inside mutex-protected code, some other thread might have already
- * recomputed those looptris. */
- if (dm->looptris.array == NULL) {
- dm->recalcLoopTri(dm);
- }
- looptri = dm->looptris.array;
- BLI_rw_mutex_unlock(&loops_cache_lock);
- }
- return looptri;
+ if (looptri != NULL) {
+ BLI_assert(dm->getNumLoopTri(dm) == dm->looptris.num);
+ }
+ else {
+ BLI_rw_mutex_lock(&loops_cache_lock, THREAD_LOCK_WRITE);
+ /* We need to ensure array is still NULL inside mutex-protected code, some other thread might have already
+ * recomputed those looptris. */
+ if (dm->looptris.array == NULL) {
+ dm->recalcLoopTri(dm);
+ }
+ looptri = dm->looptris.array;
+ BLI_rw_mutex_unlock(&loops_cache_lock);
+ }
+ return looptri;
}
static CustomData *dm_getVertCData(DerivedMesh *dm)
{
- return &dm->vertData;
+ return &dm->vertData;
}
static CustomData *dm_getEdgeCData(DerivedMesh *dm)
{
- return &dm->edgeData;
+ return &dm->edgeData;
}
static CustomData *dm_getTessFaceCData(DerivedMesh *dm)
{
- return &dm->faceData;
+ return &dm->faceData;
}
static CustomData *dm_getLoopCData(DerivedMesh *dm)
{
- return &dm->loopData;
+ return &dm->loopData;
}
static CustomData *dm_getPolyCData(DerivedMesh *dm)
{
- return &dm->polyData;
+ return &dm->polyData;
}
/**
@@ -289,40 +283,40 @@ static CustomData *dm_getPolyCData(DerivedMesh *dm)
*/
void DM_init_funcs(DerivedMesh *dm)
{
- /* default function implementations */
- dm->getVertArray = dm_getVertArray;
- dm->getEdgeArray = dm_getEdgeArray;
- dm->getTessFaceArray = dm_getTessFaceArray;
- dm->getLoopArray = dm_getLoopArray;
- dm->getPolyArray = dm_getPolyArray;
- dm->dupVertArray = dm_dupVertArray;
- dm->dupEdgeArray = dm_dupEdgeArray;
- dm->dupTessFaceArray = dm_dupFaceArray;
- dm->dupLoopArray = dm_dupLoopArray;
- dm->dupPolyArray = dm_dupPolyArray;
-
- dm->getLoopTriArray = dm_getLoopTriArray;
-
- /* subtypes handle getting actual data */
- dm->getNumLoopTri = dm_getNumLoopTri;
-
- dm->getVertDataLayout = dm_getVertCData;
- dm->getEdgeDataLayout = dm_getEdgeCData;
- dm->getTessFaceDataLayout = dm_getTessFaceCData;
- dm->getLoopDataLayout = dm_getLoopCData;
- dm->getPolyDataLayout = dm_getPolyCData;
-
- dm->getVertData = DM_get_vert_data;
- dm->getEdgeData = DM_get_edge_data;
- dm->getTessFaceData = DM_get_tessface_data;
- dm->getPolyData = DM_get_poly_data;
- dm->getVertDataArray = DM_get_vert_data_layer;
- dm->getEdgeDataArray = DM_get_edge_data_layer;
- dm->getTessFaceDataArray = DM_get_tessface_data_layer;
- dm->getPolyDataArray = DM_get_poly_data_layer;
- dm->getLoopDataArray = DM_get_loop_data_layer;
-
- dm->bvhCache = NULL;
+ /* default function implementations */
+ dm->getVertArray = dm_getVertArray;
+ dm->getEdgeArray = dm_getEdgeArray;
+ dm->getTessFaceArray = dm_getTessFaceArray;
+ dm->getLoopArray = dm_getLoopArray;
+ dm->getPolyArray = dm_getPolyArray;
+ dm->dupVertArray = dm_dupVertArray;
+ dm->dupEdgeArray = dm_dupEdgeArray;
+ dm->dupTessFaceArray = dm_dupFaceArray;
+ dm->dupLoopArray = dm_dupLoopArray;
+ dm->dupPolyArray = dm_dupPolyArray;
+
+ dm->getLoopTriArray = dm_getLoopTriArray;
+
+ /* subtypes handle getting actual data */
+ dm->getNumLoopTri = dm_getNumLoopTri;
+
+ dm->getVertDataLayout = dm_getVertCData;
+ dm->getEdgeDataLayout = dm_getEdgeCData;
+ dm->getTessFaceDataLayout = dm_getTessFaceCData;
+ dm->getLoopDataLayout = dm_getLoopCData;
+ dm->getPolyDataLayout = dm_getPolyCData;
+
+ dm->getVertData = DM_get_vert_data;
+ dm->getEdgeData = DM_get_edge_data;
+ dm->getTessFaceData = DM_get_tessface_data;
+ dm->getPolyData = DM_get_poly_data;
+ dm->getVertDataArray = DM_get_vert_data_layer;
+ dm->getEdgeDataArray = DM_get_edge_data_layer;
+ dm->getTessFaceDataArray = DM_get_tessface_data_layer;
+ dm->getPolyDataArray = DM_get_poly_data_layer;
+ dm->getLoopDataArray = DM_get_loop_data_layer;
+
+ dm->bvhCache = NULL;
}
/**
@@ -330,133 +324,157 @@ void DM_init_funcs(DerivedMesh *dm)
* of vertices, edges and faces (doesn't allocate memory for them, just
* sets up the custom data layers)
*/
-void DM_init(
- DerivedMesh *dm, DerivedMeshType type, int numVerts, int numEdges,
- int numTessFaces, int numLoops, int numPolys)
-{
- dm->type = type;
- dm->numVertData = numVerts;
- dm->numEdgeData = numEdges;
- dm->numTessFaceData = numTessFaces;
- dm->numLoopData = numLoops;
- dm->numPolyData = numPolys;
-
- DM_init_funcs(dm);
-
- dm->needsFree = 1;
- dm->dirty = 0;
-
- /* don't use CustomData_reset(...); because we dont want to touch customdata */
- copy_vn_i(dm->vertData.typemap, CD_NUMTYPES, -1);
- copy_vn_i(dm->edgeData.typemap, CD_NUMTYPES, -1);
- copy_vn_i(dm->faceData.typemap, CD_NUMTYPES, -1);
- copy_vn_i(dm->loopData.typemap, CD_NUMTYPES, -1);
- copy_vn_i(dm->polyData.typemap, CD_NUMTYPES, -1);
+void DM_init(DerivedMesh *dm,
+ DerivedMeshType type,
+ int numVerts,
+ int numEdges,
+ int numTessFaces,
+ int numLoops,
+ int numPolys)
+{
+ dm->type = type;
+ dm->numVertData = numVerts;
+ dm->numEdgeData = numEdges;
+ dm->numTessFaceData = numTessFaces;
+ dm->numLoopData = numLoops;
+ dm->numPolyData = numPolys;
+
+ DM_init_funcs(dm);
+
+ dm->needsFree = 1;
+ dm->dirty = 0;
+
+ /* don't use CustomData_reset(...); because we dont want to touch customdata */
+ copy_vn_i(dm->vertData.typemap, CD_NUMTYPES, -1);
+ copy_vn_i(dm->edgeData.typemap, CD_NUMTYPES, -1);
+ copy_vn_i(dm->faceData.typemap, CD_NUMTYPES, -1);
+ copy_vn_i(dm->loopData.typemap, CD_NUMTYPES, -1);
+ copy_vn_i(dm->polyData.typemap, CD_NUMTYPES, -1);
}
/**
* Utility function to initialize a DerivedMesh for the desired number
* of vertices, edges and faces, with a layer setup copied from source
*/
-void DM_from_template_ex(
- DerivedMesh *dm, DerivedMesh *source, DerivedMeshType type,
- int numVerts, int numEdges, int numTessFaces,
- int numLoops, int numPolys,
- const CustomData_MeshMasks *mask)
-{
- CustomData_copy(&source->vertData, &dm->vertData, mask->vmask, CD_CALLOC, numVerts);
- CustomData_copy(&source->edgeData, &dm->edgeData, mask->emask, CD_CALLOC, numEdges);
- CustomData_copy(&source->faceData, &dm->faceData, mask->fmask, CD_CALLOC, numTessFaces);
- CustomData_copy(&source->loopData, &dm->loopData, mask->lmask, CD_CALLOC, numLoops);
- CustomData_copy(&source->polyData, &dm->polyData, mask->pmask, CD_CALLOC, numPolys);
-
- dm->cd_flag = source->cd_flag;
-
- dm->type = type;
- dm->numVertData = numVerts;
- dm->numEdgeData = numEdges;
- dm->numTessFaceData = numTessFaces;
- dm->numLoopData = numLoops;
- dm->numPolyData = numPolys;
-
- DM_init_funcs(dm);
-
- dm->needsFree = 1;
- dm->dirty = 0;
-}
-void DM_from_template(
- DerivedMesh *dm, DerivedMesh *source, DerivedMeshType type,
- int numVerts, int numEdges, int numTessFaces,
- int numLoops, int numPolys)
-{
- DM_from_template_ex(
- dm, source, type,
- numVerts, numEdges, numTessFaces,
- numLoops, numPolys,
- &CD_MASK_DERIVEDMESH);
+void DM_from_template_ex(DerivedMesh *dm,
+ DerivedMesh *source,
+ DerivedMeshType type,
+ int numVerts,
+ int numEdges,
+ int numTessFaces,
+ int numLoops,
+ int numPolys,
+ const CustomData_MeshMasks *mask)
+{
+ CustomData_copy(&source->vertData, &dm->vertData, mask->vmask, CD_CALLOC, numVerts);
+ CustomData_copy(&source->edgeData, &dm->edgeData, mask->emask, CD_CALLOC, numEdges);
+ CustomData_copy(&source->faceData, &dm->faceData, mask->fmask, CD_CALLOC, numTessFaces);
+ CustomData_copy(&source->loopData, &dm->loopData, mask->lmask, CD_CALLOC, numLoops);
+ CustomData_copy(&source->polyData, &dm->polyData, mask->pmask, CD_CALLOC, numPolys);
+
+ dm->cd_flag = source->cd_flag;
+
+ dm->type = type;
+ dm->numVertData = numVerts;
+ dm->numEdgeData = numEdges;
+ dm->numTessFaceData = numTessFaces;
+ dm->numLoopData = numLoops;
+ dm->numPolyData = numPolys;
+
+ DM_init_funcs(dm);
+
+ dm->needsFree = 1;
+ dm->dirty = 0;
+}
+void DM_from_template(DerivedMesh *dm,
+ DerivedMesh *source,
+ DerivedMeshType type,
+ int numVerts,
+ int numEdges,
+ int numTessFaces,
+ int numLoops,
+ int numPolys)
+{
+ DM_from_template_ex(dm,
+ source,
+ type,
+ numVerts,
+ numEdges,
+ numTessFaces,
+ numLoops,
+ numPolys,
+ &CD_MASK_DERIVEDMESH);
}
int DM_release(DerivedMesh *dm)
{
- if (dm->needsFree) {
- bvhcache_free(&dm->bvhCache);
- CustomData_free(&dm->vertData, dm->numVertData);
- CustomData_free(&dm->edgeData, dm->numEdgeData);
- CustomData_free(&dm->faceData, dm->numTessFaceData);
- CustomData_free(&dm->loopData, dm->numLoopData);
- CustomData_free(&dm->polyData, dm->numPolyData);
-
- if (dm->mat) {
- MEM_freeN(dm->mat);
- dm->mat = NULL;
- dm->totmat = 0;
- }
-
- MEM_SAFE_FREE(dm->looptris.array);
- dm->looptris.num = 0;
- dm->looptris.num_alloc = 0;
-
- return 1;
- }
- else {
- CustomData_free_temporary(&dm->vertData, dm->numVertData);
- CustomData_free_temporary(&dm->edgeData, dm->numEdgeData);
- CustomData_free_temporary(&dm->faceData, dm->numTessFaceData);
- CustomData_free_temporary(&dm->loopData, dm->numLoopData);
- CustomData_free_temporary(&dm->polyData, dm->numPolyData);
-
- return 0;
- }
+ if (dm->needsFree) {
+ bvhcache_free(&dm->bvhCache);
+ CustomData_free(&dm->vertData, dm->numVertData);
+ CustomData_free(&dm->edgeData, dm->numEdgeData);
+ CustomData_free(&dm->faceData, dm->numTessFaceData);
+ CustomData_free(&dm->loopData, dm->numLoopData);
+ CustomData_free(&dm->polyData, dm->numPolyData);
+
+ if (dm->mat) {
+ MEM_freeN(dm->mat);
+ dm->mat = NULL;
+ dm->totmat = 0;
+ }
+
+ MEM_SAFE_FREE(dm->looptris.array);
+ dm->looptris.num = 0;
+ dm->looptris.num_alloc = 0;
+
+ return 1;
+ }
+ else {
+ CustomData_free_temporary(&dm->vertData, dm->numVertData);
+ CustomData_free_temporary(&dm->edgeData, dm->numEdgeData);
+ CustomData_free_temporary(&dm->faceData, dm->numTessFaceData);
+ CustomData_free_temporary(&dm->loopData, dm->numLoopData);
+ CustomData_free_temporary(&dm->polyData, dm->numPolyData);
+
+ return 0;
+ }
}
void DM_DupPolys(DerivedMesh *source, DerivedMesh *target)
{
- CustomData_free(&target->loopData, source->numLoopData);
- CustomData_free(&target->polyData, source->numPolyData);
+ CustomData_free(&target->loopData, source->numLoopData);
+ CustomData_free(&target->polyData, source->numPolyData);
- CustomData_copy(&source->loopData, &target->loopData, CD_MASK_DERIVEDMESH.lmask, CD_DUPLICATE, source->numLoopData);
- CustomData_copy(&source->polyData, &target->polyData, CD_MASK_DERIVEDMESH.pmask, CD_DUPLICATE, source->numPolyData);
+ CustomData_copy(&source->loopData,
+ &target->loopData,
+ CD_MASK_DERIVEDMESH.lmask,
+ CD_DUPLICATE,
+ source->numLoopData);
+ CustomData_copy(&source->polyData,
+ &target->polyData,
+ CD_MASK_DERIVEDMESH.pmask,
+ CD_DUPLICATE,
+ source->numPolyData);
- target->numLoopData = source->numLoopData;
- target->numPolyData = source->numPolyData;
+ target->numLoopData = source->numLoopData;
+ target->numPolyData = source->numPolyData;
- if (!CustomData_has_layer(&target->polyData, CD_MPOLY)) {
- MPoly *mpoly;
- MLoop *mloop;
+ if (!CustomData_has_layer(&target->polyData, CD_MPOLY)) {
+ MPoly *mpoly;
+ MLoop *mloop;
- mloop = source->dupLoopArray(source);
- mpoly = source->dupPolyArray(source);
- CustomData_add_layer(&target->loopData, CD_MLOOP, CD_ASSIGN, mloop, source->numLoopData);
- CustomData_add_layer(&target->polyData, CD_MPOLY, CD_ASSIGN, mpoly, source->numPolyData);
- }
+ mloop = source->dupLoopArray(source);
+ mpoly = source->dupPolyArray(source);
+ CustomData_add_layer(&target->loopData, CD_MLOOP, CD_ASSIGN, mloop, source->numLoopData);
+ CustomData_add_layer(&target->polyData, CD_MPOLY, CD_ASSIGN, mpoly, source->numPolyData);
+ }
}
void DM_ensure_normals(DerivedMesh *dm)
{
- if (dm->dirty & DM_DIRTY_NORMALS) {
- dm->calcNormals(dm);
- }
- BLI_assert((dm->dirty & DM_DIRTY_NORMALS) == 0);
+ if (dm->dirty & DM_DIRTY_NORMALS) {
+ dm->calcNormals(dm);
+ }
+ BLI_assert((dm->dirty & DM_DIRTY_NORMALS) == 0);
}
/**
@@ -466,175 +484,178 @@ void DM_ensure_normals(DerivedMesh *dm)
*/
void DM_ensure_looptri_data(DerivedMesh *dm)
{
- const unsigned int totpoly = dm->numPolyData;
- const unsigned int totloop = dm->numLoopData;
- const int looptris_num = poly_to_tri_count(totpoly, totloop);
-
- BLI_assert(dm->looptris.array_wip == NULL);
-
- SWAP(MLoopTri *, dm->looptris.array, dm->looptris.array_wip);
-
- if ((looptris_num > dm->looptris.num_alloc) ||
- (looptris_num < dm->looptris.num_alloc * 2) ||
- (totpoly == 0))
- {
- MEM_SAFE_FREE(dm->looptris.array_wip);
- dm->looptris.num_alloc = 0;
- dm->looptris.num = 0;
- }
-
- if (totpoly) {
- if (dm->looptris.array_wip == NULL) {
- dm->looptris.array_wip = MEM_malloc_arrayN(looptris_num, sizeof(*dm->looptris.array_wip), __func__);
- dm->looptris.num_alloc = looptris_num;
- }
-
- dm->looptris.num = looptris_num;
- }
-}
-
-void DM_to_mesh(DerivedMesh *dm, Mesh *me, Object *ob, const CustomData_MeshMasks *mask, bool take_ownership)
-{
- /* dm might depend on me, so we need to do everything with a local copy */
- Mesh tmp = *me;
- int totvert, totedge /*, totface */ /* UNUSED */, totloop, totpoly;
- int did_shapekeys = 0;
- eCDAllocType alloctype = CD_DUPLICATE;
-
- if (take_ownership && dm->type == DM_TYPE_CDDM && dm->needsFree) {
- bool has_any_referenced_layers =
- CustomData_has_referenced(&dm->vertData) ||
- CustomData_has_referenced(&dm->edgeData) ||
- CustomData_has_referenced(&dm->loopData) ||
- CustomData_has_referenced(&dm->faceData) ||
- CustomData_has_referenced(&dm->polyData);
- if (!has_any_referenced_layers) {
- alloctype = CD_ASSIGN;
- }
- }
-
- CustomData_reset(&tmp.vdata);
- CustomData_reset(&tmp.edata);
- CustomData_reset(&tmp.fdata);
- CustomData_reset(&tmp.ldata);
- CustomData_reset(&tmp.pdata);
-
- DM_ensure_normals(dm);
-
- totvert = tmp.totvert = dm->getNumVerts(dm);
- totedge = tmp.totedge = dm->getNumEdges(dm);
- totloop = tmp.totloop = dm->getNumLoops(dm);
- totpoly = tmp.totpoly = dm->getNumPolys(dm);
- tmp.totface = 0;
-
- CustomData_copy(&dm->vertData, &tmp.vdata, mask->vmask, alloctype, totvert);
- CustomData_copy(&dm->edgeData, &tmp.edata, mask->emask, alloctype, totedge);
- CustomData_copy(&dm->loopData, &tmp.ldata, mask->lmask, alloctype, totloop);
- CustomData_copy(&dm->polyData, &tmp.pdata, mask->pmask, alloctype, totpoly);
- tmp.cd_flag = dm->cd_flag;
- tmp.runtime.deformed_only = dm->deformedOnly;
-
- if (CustomData_has_layer(&dm->vertData, CD_SHAPEKEY)) {
- KeyBlock *kb;
- int uid;
-
- if (ob) {
- kb = BLI_findlink(&me->key->block, ob->shapenr - 1);
- if (kb) {
- uid = kb->uid;
- }
- else {
- CLOG_ERROR(&LOG, "could not find active shapekey %d!", ob->shapenr - 1);
- uid = INT_MAX;
- }
- }
- else {
- /* if no object, set to INT_MAX so we don't mess up any shapekey layers */
- uid = INT_MAX;
- }
-
- shapekey_layers_to_keyblocks(dm, me, uid);
- did_shapekeys = 1;
- }
-
- /* copy texture space */
- if (ob) {
- BKE_mesh_texspace_copy_from_object(&tmp, ob);
- }
-
- /* not all DerivedMeshes store their verts/edges/faces in CustomData, so
- * we set them here in case they are missing */
- if (!CustomData_has_layer(&tmp.vdata, CD_MVERT)) {
- CustomData_add_layer(&tmp.vdata, CD_MVERT, CD_ASSIGN,
- (alloctype == CD_ASSIGN) ? dm->getVertArray(dm) : dm->dupVertArray(dm),
- totvert);
- }
- if (!CustomData_has_layer(&tmp.edata, CD_MEDGE)) {
- CustomData_add_layer(&tmp.edata, CD_MEDGE, CD_ASSIGN,
- (alloctype == CD_ASSIGN) ? dm->getEdgeArray(dm) : dm->dupEdgeArray(dm),
- totedge);
- }
- if (!CustomData_has_layer(&tmp.pdata, CD_MPOLY)) {
- tmp.mloop = (alloctype == CD_ASSIGN) ? dm->getLoopArray(dm) : dm->dupLoopArray(dm);
- tmp.mpoly = (alloctype == CD_ASSIGN) ? dm->getPolyArray(dm) : dm->dupPolyArray(dm);
-
- CustomData_add_layer(&tmp.ldata, CD_MLOOP, CD_ASSIGN, tmp.mloop, tmp.totloop);
- CustomData_add_layer(&tmp.pdata, CD_MPOLY, CD_ASSIGN, tmp.mpoly, tmp.totpoly);
- }
-
- /* object had got displacement layer, should copy this layer to save sculpted data */
- /* NOTE: maybe some other layers should be copied? nazgul */
- if (CustomData_has_layer(&me->ldata, CD_MDISPS)) {
- if (totloop == me->totloop) {
- MDisps *mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
- CustomData_add_layer(&tmp.ldata, CD_MDISPS, alloctype, mdisps, totloop);
- }
- }
-
- /* yes, must be before _and_ after tessellate */
- BKE_mesh_update_customdata_pointers(&tmp, false);
-
- /* since 2.65 caller must do! */
- // BKE_mesh_tessface_calc(&tmp);
-
- CustomData_free(&me->vdata, me->totvert);
- CustomData_free(&me->edata, me->totedge);
- CustomData_free(&me->fdata, me->totface);
- CustomData_free(&me->ldata, me->totloop);
- CustomData_free(&me->pdata, me->totpoly);
-
- /* ok, this should now use new CD shapekey data,
- * which should be fed through the modifier
- * stack */
- if (tmp.totvert != me->totvert && !did_shapekeys && me->key) {
- CLOG_WARN(&LOG, "YEEK! this should be recoded! Shape key loss!: ID '%s'", tmp.id.name);
- if (tmp.key && !(tmp.id.tag & LIB_TAG_NO_MAIN)) {
- id_us_min(&tmp.key->id);
- }
- tmp.key = NULL;
- }
-
- /* Clear selection history */
- MEM_SAFE_FREE(tmp.mselect);
- tmp.totselect = 0;
- BLI_assert(ELEM(tmp.bb, NULL, me->bb));
- if (me->bb) {
- MEM_freeN(me->bb);
- tmp.bb = NULL;
- }
-
- /* skip the listbase */
- MEMCPY_STRUCT_AFTER(me, &tmp, id.prev);
-
- if (take_ownership) {
- if (alloctype == CD_ASSIGN) {
- CustomData_free_typemask(&dm->vertData, dm->numVertData, ~mask->vmask);
- CustomData_free_typemask(&dm->edgeData, dm->numEdgeData, ~mask->emask);
- CustomData_free_typemask(&dm->loopData, dm->numLoopData, ~mask->lmask);
- CustomData_free_typemask(&dm->polyData, dm->numPolyData, ~mask->pmask);
- }
- dm->release(dm);
- }
+ const unsigned int totpoly = dm->numPolyData;
+ const unsigned int totloop = dm->numLoopData;
+ const int looptris_num = poly_to_tri_count(totpoly, totloop);
+
+ BLI_assert(dm->looptris.array_wip == NULL);
+
+ SWAP(MLoopTri *, dm->looptris.array, dm->looptris.array_wip);
+
+ if ((looptris_num > dm->looptris.num_alloc) || (looptris_num < dm->looptris.num_alloc * 2) ||
+ (totpoly == 0)) {
+ MEM_SAFE_FREE(dm->looptris.array_wip);
+ dm->looptris.num_alloc = 0;
+ dm->looptris.num = 0;
+ }
+
+ if (totpoly) {
+ if (dm->looptris.array_wip == NULL) {
+ dm->looptris.array_wip = MEM_malloc_arrayN(
+ looptris_num, sizeof(*dm->looptris.array_wip), __func__);
+ dm->looptris.num_alloc = looptris_num;
+ }
+
+ dm->looptris.num = looptris_num;
+ }
+}
+
+void DM_to_mesh(
+ DerivedMesh *dm, Mesh *me, Object *ob, const CustomData_MeshMasks *mask, bool take_ownership)
+{
+ /* dm might depend on me, so we need to do everything with a local copy */
+ Mesh tmp = *me;
+ int totvert, totedge /*, totface */ /* UNUSED */, totloop, totpoly;
+ int did_shapekeys = 0;
+ eCDAllocType alloctype = CD_DUPLICATE;
+
+ if (take_ownership && dm->type == DM_TYPE_CDDM && dm->needsFree) {
+ bool has_any_referenced_layers = CustomData_has_referenced(&dm->vertData) ||
+ CustomData_has_referenced(&dm->edgeData) ||
+ CustomData_has_referenced(&dm->loopData) ||
+ CustomData_has_referenced(&dm->faceData) ||
+ CustomData_has_referenced(&dm->polyData);
+ if (!has_any_referenced_layers) {
+ alloctype = CD_ASSIGN;
+ }
+ }
+
+ CustomData_reset(&tmp.vdata);
+ CustomData_reset(&tmp.edata);
+ CustomData_reset(&tmp.fdata);
+ CustomData_reset(&tmp.ldata);
+ CustomData_reset(&tmp.pdata);
+
+ DM_ensure_normals(dm);
+
+ totvert = tmp.totvert = dm->getNumVerts(dm);
+ totedge = tmp.totedge = dm->getNumEdges(dm);
+ totloop = tmp.totloop = dm->getNumLoops(dm);
+ totpoly = tmp.totpoly = dm->getNumPolys(dm);
+ tmp.totface = 0;
+
+ CustomData_copy(&dm->vertData, &tmp.vdata, mask->vmask, alloctype, totvert);
+ CustomData_copy(&dm->edgeData, &tmp.edata, mask->emask, alloctype, totedge);
+ CustomData_copy(&dm->loopData, &tmp.ldata, mask->lmask, alloctype, totloop);
+ CustomData_copy(&dm->polyData, &tmp.pdata, mask->pmask, alloctype, totpoly);
+ tmp.cd_flag = dm->cd_flag;
+ tmp.runtime.deformed_only = dm->deformedOnly;
+
+ if (CustomData_has_layer(&dm->vertData, CD_SHAPEKEY)) {
+ KeyBlock *kb;
+ int uid;
+
+ if (ob) {
+ kb = BLI_findlink(&me->key->block, ob->shapenr - 1);
+ if (kb) {
+ uid = kb->uid;
+ }
+ else {
+ CLOG_ERROR(&LOG, "could not find active shapekey %d!", ob->shapenr - 1);
+ uid = INT_MAX;
+ }
+ }
+ else {
+ /* if no object, set to INT_MAX so we don't mess up any shapekey layers */
+ uid = INT_MAX;
+ }
+
+ shapekey_layers_to_keyblocks(dm, me, uid);
+ did_shapekeys = 1;
+ }
+
+ /* copy texture space */
+ if (ob) {
+ BKE_mesh_texspace_copy_from_object(&tmp, ob);
+ }
+
+ /* not all DerivedMeshes store their verts/edges/faces in CustomData, so
+ * we set them here in case they are missing */
+ if (!CustomData_has_layer(&tmp.vdata, CD_MVERT)) {
+ CustomData_add_layer(&tmp.vdata,
+ CD_MVERT,
+ CD_ASSIGN,
+ (alloctype == CD_ASSIGN) ? dm->getVertArray(dm) : dm->dupVertArray(dm),
+ totvert);
+ }
+ if (!CustomData_has_layer(&tmp.edata, CD_MEDGE)) {
+ CustomData_add_layer(&tmp.edata,
+ CD_MEDGE,
+ CD_ASSIGN,
+ (alloctype == CD_ASSIGN) ? dm->getEdgeArray(dm) : dm->dupEdgeArray(dm),
+ totedge);
+ }
+ if (!CustomData_has_layer(&tmp.pdata, CD_MPOLY)) {
+ tmp.mloop = (alloctype == CD_ASSIGN) ? dm->getLoopArray(dm) : dm->dupLoopArray(dm);
+ tmp.mpoly = (alloctype == CD_ASSIGN) ? dm->getPolyArray(dm) : dm->dupPolyArray(dm);
+
+ CustomData_add_layer(&tmp.ldata, CD_MLOOP, CD_ASSIGN, tmp.mloop, tmp.totloop);
+ CustomData_add_layer(&tmp.pdata, CD_MPOLY, CD_ASSIGN, tmp.mpoly, tmp.totpoly);
+ }
+
+ /* object had got displacement layer, should copy this layer to save sculpted data */
+ /* NOTE: maybe some other layers should be copied? nazgul */
+ if (CustomData_has_layer(&me->ldata, CD_MDISPS)) {
+ if (totloop == me->totloop) {
+ MDisps *mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
+ CustomData_add_layer(&tmp.ldata, CD_MDISPS, alloctype, mdisps, totloop);
+ }
+ }
+
+ /* yes, must be before _and_ after tessellate */
+ BKE_mesh_update_customdata_pointers(&tmp, false);
+
+ /* since 2.65 caller must do! */
+ // BKE_mesh_tessface_calc(&tmp);
+
+ CustomData_free(&me->vdata, me->totvert);
+ CustomData_free(&me->edata, me->totedge);
+ CustomData_free(&me->fdata, me->totface);
+ CustomData_free(&me->ldata, me->totloop);
+ CustomData_free(&me->pdata, me->totpoly);
+
+ /* ok, this should now use new CD shapekey data,
+ * which should be fed through the modifier
+ * stack */
+ if (tmp.totvert != me->totvert && !did_shapekeys && me->key) {
+ CLOG_WARN(&LOG, "YEEK! this should be recoded! Shape key loss!: ID '%s'", tmp.id.name);
+ if (tmp.key && !(tmp.id.tag & LIB_TAG_NO_MAIN)) {
+ id_us_min(&tmp.key->id);
+ }
+ tmp.key = NULL;
+ }
+
+ /* Clear selection history */
+ MEM_SAFE_FREE(tmp.mselect);
+ tmp.totselect = 0;
+ BLI_assert(ELEM(tmp.bb, NULL, me->bb));
+ if (me->bb) {
+ MEM_freeN(me->bb);
+ tmp.bb = NULL;
+ }
+
+ /* skip the listbase */
+ MEMCPY_STRUCT_AFTER(me, &tmp, id.prev);
+
+ if (take_ownership) {
+ if (alloctype == CD_ASSIGN) {
+ CustomData_free_typemask(&dm->vertData, dm->numVertData, ~mask->vmask);
+ CustomData_free_typemask(&dm->edgeData, dm->numEdgeData, ~mask->emask);
+ CustomData_free_typemask(&dm->loopData, dm->numLoopData, ~mask->lmask);
+ CustomData_free_typemask(&dm->polyData, dm->numPolyData, ~mask->pmask);
+ }
+ dm->release(dm);
+ }
}
/** Utility function to convert an (evaluated) Mesh to a shape key block. */
@@ -642,13 +663,13 @@ void DM_to_mesh(DerivedMesh *dm, Mesh *me, Object *ob, const CustomData_MeshMask
* that ensures both evaluated mesh and original one has same number of vertices. */
void BKE_mesh_runtime_eval_to_meshkey(Mesh *me_deformed, Mesh *me, KeyBlock *kb)
{
- const int totvert = me_deformed->totvert;
+ const int totvert = me_deformed->totvert;
- if (totvert == 0 || me->totvert == 0 || me->totvert != totvert) {
- return;
- }
+ if (totvert == 0 || me->totvert == 0 || me->totvert != totvert) {
+ return;
+ }
- BKE_keyblock_convert_from_mesh(me_deformed, me->key, kb);
+ BKE_keyblock_convert_from_mesh(me_deformed, me->key, kb);
}
/**
@@ -658,121 +679,119 @@ void BKE_mesh_runtime_eval_to_meshkey(Mesh *me_deformed, Mesh *me, KeyBlock *kb)
*/
void DM_set_only_copy(DerivedMesh *dm, const CustomData_MeshMasks *mask)
{
- CustomData_set_only_copy(&dm->vertData, mask->vmask);
- CustomData_set_only_copy(&dm->edgeData, mask->emask);
- CustomData_set_only_copy(&dm->faceData, mask->fmask);
- /* this wasn't in 2.63 and is disabled for 2.64 because it gives problems with
- * weight paint mode when there are modifiers applied, needs further investigation,
- * see replies to r50969, Campbell */
+ CustomData_set_only_copy(&dm->vertData, mask->vmask);
+ CustomData_set_only_copy(&dm->edgeData, mask->emask);
+ CustomData_set_only_copy(&dm->faceData, mask->fmask);
+ /* this wasn't in 2.63 and is disabled for 2.64 because it gives problems with
+ * weight paint mode when there are modifiers applied, needs further investigation,
+ * see replies to r50969, Campbell */
#if 0
- CustomData_set_only_copy(&dm->loopData, mask->lmask);
- CustomData_set_only_copy(&dm->polyData, mask->pmask);
+ CustomData_set_only_copy(&dm->loopData, mask->lmask);
+ CustomData_set_only_copy(&dm->polyData, mask->pmask);
#endif
}
static void mesh_set_only_copy(Mesh *mesh, const CustomData_MeshMasks *mask)
{
- CustomData_set_only_copy(&mesh->vdata, mask->vmask);
- CustomData_set_only_copy(&mesh->edata, mask->emask);
- CustomData_set_only_copy(&mesh->fdata, mask->fmask);
- /* this wasn't in 2.63 and is disabled for 2.64 because it gives problems with
- * weight paint mode when there are modifiers applied, needs further investigation,
- * see replies to r50969, Campbell */
+ CustomData_set_only_copy(&mesh->vdata, mask->vmask);
+ CustomData_set_only_copy(&mesh->edata, mask->emask);
+ CustomData_set_only_copy(&mesh->fdata, mask->fmask);
+ /* this wasn't in 2.63 and is disabled for 2.64 because it gives problems with
+ * weight paint mode when there are modifiers applied, needs further investigation,
+ * see replies to r50969, Campbell */
#if 0
- CustomData_set_only_copy(&mesh->ldata, mask->lmask);
- CustomData_set_only_copy(&mesh->pdata, mask->pmask);
+ CustomData_set_only_copy(&mesh->ldata, mask->lmask);
+ CustomData_set_only_copy(&mesh->pdata, mask->pmask);
#endif
}
void DM_add_vert_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer)
{
- CustomData_add_layer(&dm->vertData, type, alloctype, layer, dm->numVertData);
+ CustomData_add_layer(&dm->vertData, type, alloctype, layer, dm->numVertData);
}
void DM_add_edge_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer)
{
- CustomData_add_layer(&dm->edgeData, type, alloctype, layer, dm->numEdgeData);
+ CustomData_add_layer(&dm->edgeData, type, alloctype, layer, dm->numEdgeData);
}
void DM_add_tessface_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer)
{
- CustomData_add_layer(&dm->faceData, type, alloctype, layer, dm->numTessFaceData);
+ CustomData_add_layer(&dm->faceData, type, alloctype, layer, dm->numTessFaceData);
}
void DM_add_loop_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer)
{
- CustomData_add_layer(&dm->loopData, type, alloctype, layer, dm->numLoopData);
+ CustomData_add_layer(&dm->loopData, type, alloctype, layer, dm->numLoopData);
}
void DM_add_poly_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer)
{
- CustomData_add_layer(&dm->polyData, type, alloctype, layer, dm->numPolyData);
+ CustomData_add_layer(&dm->polyData, type, alloctype, layer, dm->numPolyData);
}
void *DM_get_vert_data(DerivedMesh *dm, int index, int type)
{
- BLI_assert(index >= 0 && index < dm->getNumVerts(dm));
- return CustomData_get(&dm->vertData, index, type);
+ BLI_assert(index >= 0 && index < dm->getNumVerts(dm));
+ return CustomData_get(&dm->vertData, index, type);
}
void *DM_get_edge_data(DerivedMesh *dm, int index, int type)
{
- BLI_assert(index >= 0 && index < dm->getNumEdges(dm));
- return CustomData_get(&dm->edgeData, index, type);
+ BLI_assert(index >= 0 && index < dm->getNumEdges(dm));
+ return CustomData_get(&dm->edgeData, index, type);
}
void *DM_get_tessface_data(DerivedMesh *dm, int index, int type)
{
- BLI_assert(index >= 0 && index < dm->getNumTessFaces(dm));
- return CustomData_get(&dm->faceData, index, type);
+ BLI_assert(index >= 0 && index < dm->getNumTessFaces(dm));
+ return CustomData_get(&dm->faceData, index, type);
}
void *DM_get_poly_data(DerivedMesh *dm, int index, int type)
{
- BLI_assert(index >= 0 && index < dm->getNumPolys(dm));
- return CustomData_get(&dm->polyData, index, type);
+ BLI_assert(index >= 0 && index < dm->getNumPolys(dm));
+ return CustomData_get(&dm->polyData, index, type);
}
-
void *DM_get_vert_data_layer(DerivedMesh *dm, int type)
{
- if (type == CD_MVERT)
- return dm->getVertArray(dm);
+ if (type == CD_MVERT)
+ return dm->getVertArray(dm);
- return CustomData_get_layer(&dm->vertData, type);
+ return CustomData_get_layer(&dm->vertData, type);
}
void *DM_get_edge_data_layer(DerivedMesh *dm, int type)
{
- if (type == CD_MEDGE)
- return dm->getEdgeArray(dm);
+ if (type == CD_MEDGE)
+ return dm->getEdgeArray(dm);
- return CustomData_get_layer(&dm->edgeData, type);
+ return CustomData_get_layer(&dm->edgeData, type);
}
void *DM_get_tessface_data_layer(DerivedMesh *dm, int type)
{
- if (type == CD_MFACE)
- return dm->getTessFaceArray(dm);
+ if (type == CD_MFACE)
+ return dm->getTessFaceArray(dm);
- return CustomData_get_layer(&dm->faceData, type);
+ return CustomData_get_layer(&dm->faceData, type);
}
void *DM_get_poly_data_layer(DerivedMesh *dm, int type)
{
- return CustomData_get_layer(&dm->polyData, type);
+ return CustomData_get_layer(&dm->polyData, type);
}
void *DM_get_loop_data_layer(DerivedMesh *dm, int type)
{
- return CustomData_get_layer(&dm->loopData, type);
+ return CustomData_get_layer(&dm->loopData, type);
}
-void DM_copy_vert_data(DerivedMesh *source, DerivedMesh *dest,
- int source_index, int dest_index, int count)
+void DM_copy_vert_data(
+ DerivedMesh *source, DerivedMesh *dest, int source_index, int dest_index, int count)
{
- CustomData_copy_data(&source->vertData, &dest->vertData,
- source_index, dest_index, count);
+ CustomData_copy_data(&source->vertData, &dest->vertData, source_index, dest_index, count);
}
/**
@@ -780,1717 +799,1782 @@ void DM_copy_vert_data(DerivedMesh *source, DerivedMesh *dest,
* source mesh using the given weights and stores the result in the vertex
* indexed by dest_index in the dest mesh
*/
-void DM_interp_vert_data(
- DerivedMesh *source, DerivedMesh *dest,
- int *src_indices, float *weights,
- int count, int dest_index)
+void DM_interp_vert_data(DerivedMesh *source,
+ DerivedMesh *dest,
+ int *src_indices,
+ float *weights,
+ int count,
+ int dest_index)
{
- CustomData_interp(&source->vertData, &dest->vertData, src_indices,
- weights, NULL, count, dest_index);
+ CustomData_interp(
+ &source->vertData, &dest->vertData, src_indices, weights, NULL, count, dest_index);
}
DerivedMesh *mesh_create_derived(Mesh *me, float (*vertCos)[3])
{
- DerivedMesh *dm = CDDM_from_mesh(me);
+ DerivedMesh *dm = CDDM_from_mesh(me);
- if (!dm)
- return NULL;
+ if (!dm)
+ return NULL;
- if (vertCos) {
- CDDM_apply_vert_coords(dm, vertCos);
- }
+ if (vertCos) {
+ CDDM_apply_vert_coords(dm, vertCos);
+ }
- return dm;
+ return dm;
}
static float (*get_editbmesh_orco_verts(BMEditMesh *em))[3]
{
- BMIter iter;
- BMVert *eve;
- float (*orco)[3];
- int i;
+ BMIter iter;
+ BMVert *eve;
+ float(*orco)[3];
+ int i;
- /* these may not really be the orco's, but it's only for preview.
- * could be solver better once, but isn't simple */
+ /* these may not really be the orco's, but it's only for preview.
+ * could be solver better once, but isn't simple */
- orco = MEM_malloc_arrayN(em->bm->totvert, sizeof(float) * 3, "BMEditMesh Orco");
+ orco = MEM_malloc_arrayN(em->bm->totvert, sizeof(float) * 3, "BMEditMesh Orco");
- BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
- copy_v3_v3(orco[i], eve->co);
- }
+ BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
+ copy_v3_v3(orco[i], eve->co);
+ }
- return orco;
+ return orco;
}
/* orco custom data layer */
static float (*get_orco_coords(Object *ob, BMEditMesh *em, int layer, int *free))[3]
{
- *free = 0;
+ *free = 0;
- if (layer == CD_ORCO) {
- /* get original coordinates */
- *free = 1;
+ if (layer == CD_ORCO) {
+ /* get original coordinates */
+ *free = 1;
- if (em)
- return get_editbmesh_orco_verts(em);
- else
- return BKE_mesh_orco_verts_get(ob);
- }
- else if (layer == CD_CLOTH_ORCO) {
- /* apply shape key for cloth, this should really be solved
- * by a more flexible customdata system, but not simple */
- if (!em) {
- ClothModifierData *clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
- KeyBlock *kb = BKE_keyblock_from_key(BKE_key_from_object(ob), clmd->sim_parms->shapekey_rest);
+ if (em)
+ return get_editbmesh_orco_verts(em);
+ else
+ return BKE_mesh_orco_verts_get(ob);
+ }
+ else if (layer == CD_CLOTH_ORCO) {
+ /* apply shape key for cloth, this should really be solved
+ * by a more flexible customdata system, but not simple */
+ if (!em) {
+ ClothModifierData *clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
+ KeyBlock *kb = BKE_keyblock_from_key(BKE_key_from_object(ob),
+ clmd->sim_parms->shapekey_rest);
- if (kb && kb->data) {
- return kb->data;
- }
- }
+ if (kb && kb->data) {
+ return kb->data;
+ }
+ }
- return NULL;
- }
+ return NULL;
+ }
- return NULL;
+ return NULL;
}
static Mesh *create_orco_mesh(Object *ob, Mesh *me, BMEditMesh *em, int layer)
{
- Mesh *mesh;
- float (*orco)[3];
- int free;
+ Mesh *mesh;
+ float(*orco)[3];
+ int free;
- if (em) {
- mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL);
- }
- else {
- mesh = BKE_mesh_copy_for_eval(me, true);
- }
+ if (em) {
+ mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL);
+ }
+ else {
+ mesh = BKE_mesh_copy_for_eval(me, true);
+ }
- orco = get_orco_coords(ob, em, layer, &free);
+ orco = get_orco_coords(ob, em, layer, &free);
- if (orco) {
- BKE_mesh_apply_vert_coords(mesh, orco);
- if (free) MEM_freeN(orco);
- }
+ if (orco) {
+ BKE_mesh_apply_vert_coords(mesh, orco);
+ if (free)
+ MEM_freeN(orco);
+ }
- return mesh;
+ return mesh;
}
-static void add_orco_mesh(
- Object *ob, BMEditMesh *em, Mesh *mesh,
- Mesh *mesh_orco, int layer)
+static void add_orco_mesh(Object *ob, BMEditMesh *em, Mesh *mesh, Mesh *mesh_orco, int layer)
{
- float (*orco)[3], (*layerorco)[3];
- int totvert, free;
+ float(*orco)[3], (*layerorco)[3];
+ int totvert, free;
- totvert = mesh->totvert;
+ totvert = mesh->totvert;
- if (mesh_orco) {
- free = 1;
+ if (mesh_orco) {
+ free = 1;
- if (mesh_orco->totvert == totvert) {
- orco = BKE_mesh_vertexCos_get(mesh_orco, NULL);
- }
- else {
- orco = BKE_mesh_vertexCos_get(mesh, NULL);
- }
- }
- else {
- /* TODO(sybren): totvert should potentially change here, as ob->data
- * or em may have a different number of vertices than dm. */
- orco = get_orco_coords(ob, em, layer, &free);
- }
+ if (mesh_orco->totvert == totvert) {
+ orco = BKE_mesh_vertexCos_get(mesh_orco, NULL);
+ }
+ else {
+ orco = BKE_mesh_vertexCos_get(mesh, NULL);
+ }
+ }
+ else {
+ /* TODO(sybren): totvert should potentially change here, as ob->data
+ * or em may have a different number of vertices than dm. */
+ orco = get_orco_coords(ob, em, layer, &free);
+ }
- if (orco) {
- if (layer == CD_ORCO) {
- BKE_mesh_orco_verts_transform(ob->data, orco, totvert, 0);
- }
+ if (orco) {
+ if (layer == CD_ORCO) {
+ BKE_mesh_orco_verts_transform(ob->data, orco, totvert, 0);
+ }
- if (!(layerorco = CustomData_get_layer(&mesh->vdata, layer))) {
- CustomData_add_layer(&mesh->vdata, layer, CD_CALLOC, NULL, mesh->totvert);
- BKE_mesh_update_customdata_pointers(mesh, false);
+ if (!(layerorco = CustomData_get_layer(&mesh->vdata, layer))) {
+ CustomData_add_layer(&mesh->vdata, layer, CD_CALLOC, NULL, mesh->totvert);
+ BKE_mesh_update_customdata_pointers(mesh, false);
- layerorco = CustomData_get_layer(&mesh->vdata, layer);
- }
+ layerorco = CustomData_get_layer(&mesh->vdata, layer);
+ }
- memcpy(layerorco, orco, sizeof(float) * 3 * totvert);
- if (free) MEM_freeN(orco);
- }
+ memcpy(layerorco, orco, sizeof(float) * 3 * totvert);
+ if (free)
+ MEM_freeN(orco);
+ }
}
static void editmesh_update_statvis_color(const Scene *scene, Object *ob)
{
- BMEditMesh *em = BKE_editmesh_from_object(ob);
- Mesh *me = ob->data;
- BKE_mesh_runtime_ensure_edit_data(me);
- BKE_editmesh_statvis_calc(em, me->runtime.edit_data, &scene->toolsettings->statvis);
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ Mesh *me = ob->data;
+ BKE_mesh_runtime_ensure_edit_data(me);
+ BKE_editmesh_statvis_calc(em, me->runtime.edit_data, &scene->toolsettings->statvis);
}
static void shapekey_layers_to_keyblocks(DerivedMesh *dm, Mesh *me, int actshape_uid)
{
- KeyBlock *kb;
- int i, j, tot;
-
- if (!me->key)
- return;
-
- tot = CustomData_number_of_layers(&dm->vertData, CD_SHAPEKEY);
- for (i = 0; i < tot; i++) {
- CustomDataLayer *layer = &dm->vertData.layers[CustomData_get_layer_index_n(&dm->vertData, CD_SHAPEKEY, i)];
- float (*cos)[3], (*kbcos)[3];
-
- for (kb = me->key->block.first; kb; kb = kb->next) {
- if (kb->uid == layer->uid)
- break;
- }
-
- if (!kb) {
- kb = BKE_keyblock_add(me->key, layer->name);
- kb->uid = layer->uid;
- }
-
- if (kb->data)
- MEM_freeN(kb->data);
-
- cos = CustomData_get_layer_n(&dm->vertData, CD_SHAPEKEY, i);
- kb->totelem = dm->numVertData;
-
- kb->data = kbcos = MEM_malloc_arrayN(kb->totelem, 3 * sizeof(float), "kbcos DerivedMesh.c");
- if (kb->uid == actshape_uid) {
- MVert *mvert = dm->getVertArray(dm);
-
- for (j = 0; j < dm->numVertData; j++, kbcos++, mvert++) {
- copy_v3_v3(*kbcos, mvert->co);
- }
- }
- else {
- for (j = 0; j < kb->totelem; j++, cos++, kbcos++) {
- copy_v3_v3(*kbcos, *cos);
- }
- }
- }
-
- for (kb = me->key->block.first; kb; kb = kb->next) {
- if (kb->totelem != dm->numVertData) {
- if (kb->data)
- MEM_freeN(kb->data);
-
- kb->totelem = dm->numVertData;
- kb->data = MEM_calloc_arrayN(kb->totelem, 3 * sizeof(float), "kb->data derivedmesh.c");
- CLOG_ERROR(&LOG, "lost a shapekey layer: '%s'! (bmesh internal error)", kb->name);
- }
- }
+ KeyBlock *kb;
+ int i, j, tot;
+
+ if (!me->key)
+ return;
+
+ tot = CustomData_number_of_layers(&dm->vertData, CD_SHAPEKEY);
+ for (i = 0; i < tot; i++) {
+ CustomDataLayer *layer =
+ &dm->vertData.layers[CustomData_get_layer_index_n(&dm->vertData, CD_SHAPEKEY, i)];
+ float(*cos)[3], (*kbcos)[3];
+
+ for (kb = me->key->block.first; kb; kb = kb->next) {
+ if (kb->uid == layer->uid)
+ break;
+ }
+
+ if (!kb) {
+ kb = BKE_keyblock_add(me->key, layer->name);
+ kb->uid = layer->uid;
+ }
+
+ if (kb->data)
+ MEM_freeN(kb->data);
+
+ cos = CustomData_get_layer_n(&dm->vertData, CD_SHAPEKEY, i);
+ kb->totelem = dm->numVertData;
+
+ kb->data = kbcos = MEM_malloc_arrayN(kb->totelem, 3 * sizeof(float), "kbcos DerivedMesh.c");
+ if (kb->uid == actshape_uid) {
+ MVert *mvert = dm->getVertArray(dm);
+
+ for (j = 0; j < dm->numVertData; j++, kbcos++, mvert++) {
+ copy_v3_v3(*kbcos, mvert->co);
+ }
+ }
+ else {
+ for (j = 0; j < kb->totelem; j++, cos++, kbcos++) {
+ copy_v3_v3(*kbcos, *cos);
+ }
+ }
+ }
+
+ for (kb = me->key->block.first; kb; kb = kb->next) {
+ if (kb->totelem != dm->numVertData) {
+ if (kb->data)
+ MEM_freeN(kb->data);
+
+ kb->totelem = dm->numVertData;
+ kb->data = MEM_calloc_arrayN(kb->totelem, 3 * sizeof(float), "kb->data derivedmesh.c");
+ CLOG_ERROR(&LOG, "lost a shapekey layer: '%s'! (bmesh internal error)", kb->name);
+ }
+ }
}
static void mesh_copy_autosmooth(Mesh *me, Mesh *me_orig)
{
- if (me_orig->flag & ME_AUTOSMOOTH) {
- me->flag |= ME_AUTOSMOOTH;
- me->smoothresh = me_orig->smoothresh;
- }
-}
-
-static void mesh_calc_modifier_final_normals(
- const Mesh *mesh_input,
- const CustomData_MeshMasks *dataMask,
- const bool sculpt_dyntopo,
- Mesh *mesh_final)
-{
- /* Compute normals. */
- const bool do_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
- (dataMask->lmask & CD_MASK_NORMAL) != 0);
- /* Some modifiers may need this info from their target (other) object, simpler to generate it here as well.
- * Note that they will always be generated when no loop normals are comptuted,
- * since they are needed by drawing code. */
- const bool do_poly_normals = ((dataMask->pmask & CD_MASK_NORMAL) != 0);
-
- if (do_loop_normals) {
- /* In case we also need poly normals, add the layer here, then BKE_mesh_calc_normals_split() will fill it. */
- if (do_poly_normals) {
- if (!CustomData_has_layer(&mesh_final->pdata, CD_NORMAL)) {
- CustomData_add_layer(&mesh_final->pdata, CD_NORMAL, CD_CALLOC, NULL, mesh_final->totpoly);
- }
- }
- /* Compute loop normals (note: will compute poly and vert normals as well, if needed!) */
- BKE_mesh_calc_normals_split(mesh_final);
- BKE_mesh_tessface_clear(mesh_final);
- }
-
- if (sculpt_dyntopo == false) {
- /* watch this! after 2.75a we move to from tessface to looptri (by default) */
- if (dataMask->fmask & CD_MASK_MFACE) {
- BKE_mesh_tessface_ensure(mesh_final);
- }
-
- /* without this, drawing ngon tri's faces will show ugly tessellated face
- * normals and will also have to calculate normals on the fly, try avoid
- * this where possible since calculating polygon normals isn't fast,
- * note that this isn't a problem for subsurf (only quads) or editmode
- * which deals with drawing differently.
- *
- * Only calc vertex normals if they are flagged as dirty.
- * If using loop normals, poly nors have already been computed.
- */
- if (!do_loop_normals) {
- BKE_mesh_ensure_normals_for_display(mesh_final);
- }
- }
-
- /* Some modifiers, like datatransfer, may generate those data as temp layer, we do not want to keep them,
- * as they are used by display code when available (i.e. even if autosmooth is disabled). */
- if (!do_loop_normals && CustomData_has_layer(&mesh_final->ldata, CD_NORMAL)) {
- CustomData_free_layers(&mesh_final->ldata, CD_NORMAL, mesh_final->totloop);
- }
-}
-
-static void mesh_calc_modifiers(
- struct Depsgraph *depsgraph,
- Scene *scene, Object *ob,
- int useDeform,
- const bool need_mapping,
- const CustomData_MeshMasks *dataMask,
- const int index,
- const bool use_cache,
- /* return args */
- Mesh **r_deform,
- Mesh **r_final)
-{
- /* Input and final mesh. Final mesh is only created the moment the first
- * constructive modifier is executed, or a deform modifier needs normals
- * or certain data layers. */
- Mesh *mesh_input = ob->data;
- Mesh *mesh_final = NULL;
- Mesh *mesh_deform = NULL;
- BLI_assert((mesh_input->id.tag & LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT) == 0);
-
- /* Deformed vertex locations array. Deform only modifier need this type of
- * float array rather than MVert*. Tracked along with mesh_final as an
- * optimization to avoid copying coordinates back and forth if there are
- * multiple sequential deform only modifiers. */
- float (*deformed_verts)[3] = NULL;
- int num_deformed_verts = mesh_input->totvert;
- bool isPrevDeform = false;
-
- /* Mesh with constructive modifiers but no deformation applied. Tracked
- * along with final mesh if undeformed / orco coordinates are requested
- * for texturing. */
- Mesh *mesh_orco = NULL;
- Mesh *mesh_orco_cloth = NULL;
-
- /* Modifier evaluation modes. */
- const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
- const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime;
-
- /* Sculpt can skip certain modifiers. */
- MultiresModifierData *mmd = get_multires_modifier(scene, ob, 0);
- const bool has_multires = (mmd && mmd->sculptlvl != 0);
- bool multires_applied = false;
- const bool sculpt_mode = ob->mode & OB_MODE_SCULPT && ob->sculpt && !use_render;
- const bool sculpt_dyntopo = (sculpt_mode && ob->sculpt->bm) && !use_render;
-
- /* Modifier evaluation contexts for different types of modifiers. */
- ModifierApplyFlag app_render = use_render ? MOD_APPLY_RENDER : 0;
- ModifierApplyFlag app_cache = use_cache ? MOD_APPLY_USECACHE : 0;
- const ModifierEvalContext mectx = {depsgraph, ob, app_render | app_cache};
- const ModifierEvalContext mectx_orco = {depsgraph, ob, app_render | MOD_APPLY_ORCO};
-
- /* Get effective list of modifiers to execute. Some effects like shape keys
- * are added as virtual modifiers before the user created modifiers. */
- VirtualModifierData virtualModifierData;
- ModifierData *firstmd = modifiers_getVirtualModifierList(ob, &virtualModifierData);
- ModifierData *md = firstmd;
-
- /* Preview colors by modifiers such as dynamic paint, to show the results
- * even if the resulting data is not used in a material. Only in object mode.
- * TODO: this is broken, not drawn by the drawn manager. */
- const bool do_mod_mcol = (ob->mode == OB_MODE_OBJECT);
- ModifierData *previewmd = NULL;
- CustomData_MeshMasks previewmask = {0};
- if (do_mod_mcol) {
- /* Find the last active modifier generating a preview, or NULL if none. */
- /* XXX Currently, DPaint modifier just ignores this.
- * Needs a stupid hack...
- * The whole "modifier preview" thing has to be (re?)designed, anyway! */
- previewmd = modifiers_getLastPreview(scene, md, required_mode);
- }
-
- /* Compute accumulated datamasks needed by each modifier. It helps to do
- * this fine grained so that for example vertex groups are preserved up to
- * an armature modifier, but not through a following subsurf modifier where
- * subdividing them is expensive. */
- CDMaskLink *datamasks = modifiers_calcDataMasks(scene, ob, md, dataMask, required_mode, previewmd, &previewmask);
- CDMaskLink *md_datamask = datamasks;
- /* XXX Always copying POLYINDEX, else tessellated data are no more valid! */
- CustomData_MeshMasks append_mask = CD_MASK_BAREMESH_ORIGINDEX;
-
- /* Clear errors before evaluation. */
- modifiers_clearErrors(ob);
-
- /* Apply all leading deform modifiers. */
- if (useDeform) {
- for (; md; md = md->next, md_datamask = md_datamask->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
-
- if (!modifier_isEnabled(scene, md, required_mode)) {
- continue;
- }
-
- if (useDeform < 0 && mti->dependsOnTime && mti->dependsOnTime(md)) {
- continue;
- }
-
- if (mti->type == eModifierTypeType_OnlyDeform && !sculpt_dyntopo) {
- if (!deformed_verts) {
- deformed_verts = BKE_mesh_vertexCos_get(mesh_input, &num_deformed_verts);
- }
- else if (isPrevDeform && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
- if (mesh_final == NULL) {
- mesh_final = BKE_mesh_copy_for_eval(mesh_input, true);
- ASSERT_IS_VALID_MESH(mesh_final);
- }
- BKE_mesh_apply_vert_coords(mesh_final, deformed_verts);
- }
-
- modwrap_deformVerts(md, &mectx, mesh_final, deformed_verts, num_deformed_verts);
-
- isPrevDeform = true;
- }
- else {
- break;
- }
-
- /* grab modifiers until index i */
- if ((index != -1) && (BLI_findindex(&ob->modifiers, md) >= index))
- break;
- }
-
- /* Result of all leading deforming modifiers is cached for
- * places that wish to use the original mesh but with deformed
- * coordinates (like vertex paint). */
- if (r_deform) {
- mesh_deform = BKE_mesh_copy_for_eval(mesh_input, true);
-
- if (deformed_verts) {
- BKE_mesh_apply_vert_coords(mesh_deform, deformed_verts);
- }
- }
- }
-
- /* Apply all remaining constructive and deforming modifiers. */
- for (; md; md = md->next, md_datamask = md_datamask->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
-
- if (!modifier_isEnabled(scene, md, required_mode)) {
- continue;
- }
-
- if (mti->type == eModifierTypeType_OnlyDeform && !useDeform) {
- continue;
- }
-
- if ((mti->flags & eModifierTypeFlag_RequiresOriginalData) && mesh_final) {
- modifier_setError(md, "Modifier requires original data, bad stack position");
- continue;
- }
-
- if (sculpt_mode &&
- (!has_multires || multires_applied || sculpt_dyntopo))
- {
- bool unsupported = false;
-
- if (md->type == eModifierType_Multires && ((MultiresModifierData *)md)->sculptlvl == 0) {
- /* If multires is on level 0 skip it silently without warning message. */
- if (!sculpt_dyntopo) {
- continue;
- }
- }
-
- if (sculpt_dyntopo)
- unsupported = true;
-
- if (scene->toolsettings->sculpt->flags & SCULPT_ONLY_DEFORM)
- unsupported |= (mti->type != eModifierTypeType_OnlyDeform);
-
- unsupported |= multires_applied;
-
- if (unsupported) {
- if (sculpt_dyntopo)
- modifier_setError(md, "Not supported in dyntopo");
- else
- modifier_setError(md, "Not supported in sculpt mode");
- continue;
- }
- else {
- modifier_setError(md, "Hide, Mask and optimized display disabled");
- }
- }
-
- if (need_mapping && !modifier_supportsMapping(md)) {
- continue;
- }
-
- if (useDeform < 0 && mti->dependsOnTime && mti->dependsOnTime(md)) {
- continue;
- }
-
- /* Add an orco layer if needed by this modifier. */
- if (mesh_final && mti->requiredDataMask) {
- CustomData_MeshMasks mask = {0};
- mti->requiredDataMask(ob, md, &mask);
- if (mask.vmask & CD_MASK_ORCO) {
- add_orco_mesh(ob, NULL, mesh_final, mesh_orco, CD_ORCO);
- }
- }
-
- /* How to apply modifier depends on (a) what we already have as
- * a result of previous modifiers (could be a Mesh or just
- * deformed vertices) and (b) what type the modifier is. */
- if (mti->type == eModifierTypeType_OnlyDeform) {
- /* No existing verts to deform, need to build them. */
- if (!deformed_verts) {
- if (mesh_final) {
- /* Deforming a mesh, read the vertex locations
- * out of the mesh and deform them. Once done with this
- * run of deformers verts will be written back. */
- deformed_verts = BKE_mesh_vertexCos_get(mesh_final, &num_deformed_verts);
- }
- else {
- deformed_verts = BKE_mesh_vertexCos_get(mesh_input, &num_deformed_verts);
- }
- }
- /* if this is not the last modifier in the stack then recalculate the normals
- * to avoid giving bogus normals to the next modifier see: [#23673] */
- else if (isPrevDeform && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
- /* XXX, this covers bug #23673, but we may need normal calc for other types */
- if (mesh_final) {
- BKE_mesh_apply_vert_coords(mesh_final, deformed_verts);
- }
- }
-
- modwrap_deformVerts(md, &mectx, mesh_final, deformed_verts, num_deformed_verts);
- }
- else {
- /* determine which data layers are needed by following modifiers */
- CustomData_MeshMasks nextmask;
- if (md_datamask->next)
- nextmask = md_datamask->next->mask;
- else
- nextmask = *dataMask;
-
- /* apply vertex coordinates or build a Mesh as necessary */
- if (mesh_final) {
- if (deformed_verts) {
- BKE_mesh_apply_vert_coords(mesh_final, deformed_verts);
- }
- }
- else {
- mesh_final = BKE_mesh_copy_for_eval(mesh_input, true);
- ASSERT_IS_VALID_MESH(mesh_final);
-
- if (deformed_verts) {
- BKE_mesh_apply_vert_coords(mesh_final, deformed_verts);
- }
-
- /* Initialize original indices the first time we evaluate a
- * constructive modifier. Modifiers will then do mapping mostly
- * automatic by copying them through CustomData_copy_data along
- * with other data.
- *
- * These are created when either requested by evaluation, or if
- * following modifiers requested them. */
- if (need_mapping || ((nextmask.vmask | nextmask.emask | nextmask.pmask) & CD_MASK_ORIGINDEX)) {
- /* calc */
- CustomData_add_layer(&mesh_final->vdata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh_final->totvert);
- CustomData_add_layer(&mesh_final->edata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh_final->totedge);
- CustomData_add_layer(&mesh_final->pdata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh_final->totpoly);
-
- /* Not worth parallelizing this, gives less than 0.1% overall speedup in best of best cases... */
- range_vn_i(CustomData_get_layer(&mesh_final->vdata, CD_ORIGINDEX), mesh_final->totvert, 0);
- range_vn_i(CustomData_get_layer(&mesh_final->edata, CD_ORIGINDEX), mesh_final->totedge, 0);
- range_vn_i(CustomData_get_layer(&mesh_final->pdata, CD_ORIGINDEX), mesh_final->totpoly, 0);
- }
- }
-
-
- /* set the Mesh to only copy needed data */
- CustomData_MeshMasks mask = md_datamask->mask;
- /* needMapping check here fixes bug [#28112], otherwise it's
- * possible that it won't be copied */
- CustomData_MeshMasks_update(&mask, &append_mask);
- if (need_mapping) {
- mask.vmask |= CD_MASK_ORIGINDEX;
- mask.emask |= CD_MASK_ORIGINDEX;
- mask.pmask |= CD_MASK_ORIGINDEX;
- }
- mesh_set_only_copy(mesh_final, &mask);
-
- /* add cloth rest shape key if needed */
- if (mask.vmask & CD_MASK_CLOTH_ORCO) {
- add_orco_mesh(ob, NULL, mesh_final, mesh_orco, CD_CLOTH_ORCO);
- }
-
- /* add an origspace layer if needed */
- if ((md_datamask->mask.lmask) & CD_MASK_ORIGSPACE_MLOOP) {
- if (!CustomData_has_layer(&mesh_final->ldata, CD_ORIGSPACE_MLOOP)) {
- CustomData_add_layer(&mesh_final->ldata, CD_ORIGSPACE_MLOOP, CD_CALLOC, NULL, mesh_final->totloop);
- mesh_init_origspace(mesh_final);
- }
- }
-
- Mesh *mesh_next = modwrap_applyModifier(md, &mectx, mesh_final);
- ASSERT_IS_VALID_MESH(mesh_next);
-
- if (mesh_next) {
- /* if the modifier returned a new mesh, release the old one */
- if (mesh_final != mesh_next) {
- BLI_assert(mesh_final != mesh_input);
- BKE_id_free(NULL, mesh_final);
- }
- mesh_final = mesh_next;
-
- if (deformed_verts) {
- MEM_freeN(deformed_verts);
- deformed_verts = NULL;
- }
-
- mesh_copy_autosmooth(mesh_final, mesh_input);
- }
-
- /* create an orco mesh in parallel */
- if (nextmask.vmask & CD_MASK_ORCO) {
- if (!mesh_orco) {
- mesh_orco = create_orco_mesh(ob, mesh_input, NULL, CD_ORCO);
- }
-
- nextmask.vmask &= ~CD_MASK_ORCO;
- CustomData_MeshMasks temp_cddata_masks = {
- .vmask = CD_MASK_ORIGINDEX,
- .emask = CD_MASK_ORIGINDEX,
- .fmask = CD_MASK_ORIGINDEX,
- .pmask = CD_MASK_ORIGINDEX,
- };
- if (mti->requiredDataMask != NULL) {
- mti->requiredDataMask(ob, md, &temp_cddata_masks);
- }
- CustomData_MeshMasks_update(&temp_cddata_masks, &nextmask);
- mesh_set_only_copy(mesh_orco, &temp_cddata_masks);
-
- mesh_next = modwrap_applyModifier(md, &mectx_orco, mesh_orco);
- ASSERT_IS_VALID_MESH(mesh_next);
-
- if (mesh_next) {
- /* if the modifier returned a new mesh, release the old one */
- if (mesh_orco != mesh_next) {
- BLI_assert(mesh_orco != mesh_input);
- BKE_id_free(NULL, mesh_orco);
- }
-
- mesh_orco = mesh_next;
- }
- }
-
- /* create cloth orco mesh in parallel */
- if (nextmask.vmask & CD_MASK_CLOTH_ORCO) {
- if (!mesh_orco_cloth) {
- mesh_orco_cloth = create_orco_mesh(ob, mesh_input, NULL, CD_CLOTH_ORCO);
- }
-
- nextmask.vmask &= ~CD_MASK_CLOTH_ORCO;
- nextmask.vmask |= CD_MASK_ORIGINDEX;
- nextmask.emask |= CD_MASK_ORIGINDEX;
- nextmask.pmask |= CD_MASK_ORIGINDEX;
- mesh_set_only_copy(mesh_orco_cloth, &nextmask);
-
- mesh_next = modwrap_applyModifier(md, &mectx_orco, mesh_orco_cloth);
- ASSERT_IS_VALID_MESH(mesh_next);
-
- if (mesh_next) {
- /* if the modifier returned a new mesh, release the old one */
- if (mesh_orco_cloth != mesh_next) {
- BLI_assert(mesh_orco != mesh_input);
- BKE_id_free(NULL, mesh_orco_cloth);
- }
-
- mesh_orco_cloth = mesh_next;
- }
- }
-
- /* in case of dynamic paint, make sure preview mask remains for following modifiers */
- /* XXX Temp and hackish solution! */
- if (md->type == eModifierType_DynamicPaint) {
- append_mask.lmask |= CD_MASK_PREVIEW_MLOOPCOL;
- }
-
- mesh_final->runtime.deformed_only = false;
- }
-
- isPrevDeform = (mti->type == eModifierTypeType_OnlyDeform);
-
- /* grab modifiers until index i */
- if ((index != -1) && (BLI_findindex(&ob->modifiers, md) >= index))
- break;
-
- if (sculpt_mode && md->type == eModifierType_Multires) {
- multires_applied = true;
- }
- }
-
- BLI_linklist_free((LinkNode *)datamasks, NULL);
-
- for (md = firstmd; md; md = md->next)
- modifier_freeTemporaryData(md);
-
- /* Yay, we are done. If we have a Mesh and deformed vertices
- * need to apply these back onto the Mesh. If we have no
- * Mesh then we need to build one. */
- if (mesh_final == NULL) {
- mesh_final = BKE_mesh_copy_for_eval(mesh_input, true);
- }
- if (deformed_verts) {
- BKE_mesh_apply_vert_coords(mesh_final, deformed_verts);
- MEM_freeN(deformed_verts);
- deformed_verts = NULL;
- }
-
- /* Add orco coordinates to final and deformed mesh if requested. */
- if (dataMask->vmask & CD_MASK_ORCO) {
- add_orco_mesh(ob, NULL, mesh_final, mesh_orco, CD_ORCO);
-
- if (mesh_deform)
- add_orco_mesh(ob, NULL, mesh_deform, NULL, CD_ORCO);
- }
-
- if (mesh_orco) {
- BKE_id_free(NULL, mesh_orco);
- }
- if (mesh_orco_cloth) {
- BKE_id_free(NULL, mesh_orco_cloth);
- }
-
- /* Compute normals. */
- mesh_calc_modifier_final_normals(mesh_input, dataMask, sculpt_dyntopo, mesh_final);
-
- /* Return final mesh */
- *r_final = mesh_final;
- if (r_deform) {
- *r_deform = mesh_deform;
- }
+ if (me_orig->flag & ME_AUTOSMOOTH) {
+ me->flag |= ME_AUTOSMOOTH;
+ me->smoothresh = me_orig->smoothresh;
+ }
+}
+
+static void mesh_calc_modifier_final_normals(const Mesh *mesh_input,
+ const CustomData_MeshMasks *dataMask,
+ const bool sculpt_dyntopo,
+ Mesh *mesh_final)
+{
+ /* Compute normals. */
+ const bool do_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
+ (dataMask->lmask & CD_MASK_NORMAL) != 0);
+ /* Some modifiers may need this info from their target (other) object, simpler to generate it here as well.
+ * Note that they will always be generated when no loop normals are comptuted,
+ * since they are needed by drawing code. */
+ const bool do_poly_normals = ((dataMask->pmask & CD_MASK_NORMAL) != 0);
+
+ if (do_loop_normals) {
+ /* In case we also need poly normals, add the layer here, then BKE_mesh_calc_normals_split() will fill it. */
+ if (do_poly_normals) {
+ if (!CustomData_has_layer(&mesh_final->pdata, CD_NORMAL)) {
+ CustomData_add_layer(&mesh_final->pdata, CD_NORMAL, CD_CALLOC, NULL, mesh_final->totpoly);
+ }
+ }
+ /* Compute loop normals (note: will compute poly and vert normals as well, if needed!) */
+ BKE_mesh_calc_normals_split(mesh_final);
+ BKE_mesh_tessface_clear(mesh_final);
+ }
+
+ if (sculpt_dyntopo == false) {
+ /* watch this! after 2.75a we move to from tessface to looptri (by default) */
+ if (dataMask->fmask & CD_MASK_MFACE) {
+ BKE_mesh_tessface_ensure(mesh_final);
+ }
+
+ /* without this, drawing ngon tri's faces will show ugly tessellated face
+ * normals and will also have to calculate normals on the fly, try avoid
+ * this where possible since calculating polygon normals isn't fast,
+ * note that this isn't a problem for subsurf (only quads) or editmode
+ * which deals with drawing differently.
+ *
+ * Only calc vertex normals if they are flagged as dirty.
+ * If using loop normals, poly nors have already been computed.
+ */
+ if (!do_loop_normals) {
+ BKE_mesh_ensure_normals_for_display(mesh_final);
+ }
+ }
+
+ /* Some modifiers, like datatransfer, may generate those data as temp layer, we do not want to keep them,
+ * as they are used by display code when available (i.e. even if autosmooth is disabled). */
+ if (!do_loop_normals && CustomData_has_layer(&mesh_final->ldata, CD_NORMAL)) {
+ CustomData_free_layers(&mesh_final->ldata, CD_NORMAL, mesh_final->totloop);
+ }
+}
+
+static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ int useDeform,
+ const bool need_mapping,
+ const CustomData_MeshMasks *dataMask,
+ const int index,
+ const bool use_cache,
+ /* return args */
+ Mesh **r_deform,
+ Mesh **r_final)
+{
+ /* Input and final mesh. Final mesh is only created the moment the first
+ * constructive modifier is executed, or a deform modifier needs normals
+ * or certain data layers. */
+ Mesh *mesh_input = ob->data;
+ Mesh *mesh_final = NULL;
+ Mesh *mesh_deform = NULL;
+ BLI_assert((mesh_input->id.tag & LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT) == 0);
+
+ /* Deformed vertex locations array. Deform only modifier need this type of
+ * float array rather than MVert*. Tracked along with mesh_final as an
+ * optimization to avoid copying coordinates back and forth if there are
+ * multiple sequential deform only modifiers. */
+ float(*deformed_verts)[3] = NULL;
+ int num_deformed_verts = mesh_input->totvert;
+ bool isPrevDeform = false;
+
+ /* Mesh with constructive modifiers but no deformation applied. Tracked
+ * along with final mesh if undeformed / orco coordinates are requested
+ * for texturing. */
+ Mesh *mesh_orco = NULL;
+ Mesh *mesh_orco_cloth = NULL;
+
+ /* Modifier evaluation modes. */
+ const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
+ const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime;
+
+ /* Sculpt can skip certain modifiers. */
+ MultiresModifierData *mmd = get_multires_modifier(scene, ob, 0);
+ const bool has_multires = (mmd && mmd->sculptlvl != 0);
+ bool multires_applied = false;
+ const bool sculpt_mode = ob->mode & OB_MODE_SCULPT && ob->sculpt && !use_render;
+ const bool sculpt_dyntopo = (sculpt_mode && ob->sculpt->bm) && !use_render;
+
+ /* Modifier evaluation contexts for different types of modifiers. */
+ ModifierApplyFlag app_render = use_render ? MOD_APPLY_RENDER : 0;
+ ModifierApplyFlag app_cache = use_cache ? MOD_APPLY_USECACHE : 0;
+ const ModifierEvalContext mectx = {depsgraph, ob, app_render | app_cache};
+ const ModifierEvalContext mectx_orco = {depsgraph, ob, app_render | MOD_APPLY_ORCO};
+
+ /* Get effective list of modifiers to execute. Some effects like shape keys
+ * are added as virtual modifiers before the user created modifiers. */
+ VirtualModifierData virtualModifierData;
+ ModifierData *firstmd = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ ModifierData *md = firstmd;
+
+ /* Preview colors by modifiers such as dynamic paint, to show the results
+ * even if the resulting data is not used in a material. Only in object mode.
+ * TODO: this is broken, not drawn by the drawn manager. */
+ const bool do_mod_mcol = (ob->mode == OB_MODE_OBJECT);
+ ModifierData *previewmd = NULL;
+ CustomData_MeshMasks previewmask = {0};
+ if (do_mod_mcol) {
+ /* Find the last active modifier generating a preview, or NULL if none. */
+ /* XXX Currently, DPaint modifier just ignores this.
+ * Needs a stupid hack...
+ * The whole "modifier preview" thing has to be (re?)designed, anyway! */
+ previewmd = modifiers_getLastPreview(scene, md, required_mode);
+ }
+
+ /* Compute accumulated datamasks needed by each modifier. It helps to do
+ * this fine grained so that for example vertex groups are preserved up to
+ * an armature modifier, but not through a following subsurf modifier where
+ * subdividing them is expensive. */
+ CDMaskLink *datamasks = modifiers_calcDataMasks(
+ scene, ob, md, dataMask, required_mode, previewmd, &previewmask);
+ CDMaskLink *md_datamask = datamasks;
+ /* XXX Always copying POLYINDEX, else tessellated data are no more valid! */
+ CustomData_MeshMasks append_mask = CD_MASK_BAREMESH_ORIGINDEX;
+
+ /* Clear errors before evaluation. */
+ modifiers_clearErrors(ob);
+
+ /* Apply all leading deform modifiers. */
+ if (useDeform) {
+ for (; md; md = md->next, md_datamask = md_datamask->next) {
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if (!modifier_isEnabled(scene, md, required_mode)) {
+ continue;
+ }
+
+ if (useDeform < 0 && mti->dependsOnTime && mti->dependsOnTime(md)) {
+ continue;
+ }
+
+ if (mti->type == eModifierTypeType_OnlyDeform && !sculpt_dyntopo) {
+ if (!deformed_verts) {
+ deformed_verts = BKE_mesh_vertexCos_get(mesh_input, &num_deformed_verts);
+ }
+ else if (isPrevDeform && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
+ if (mesh_final == NULL) {
+ mesh_final = BKE_mesh_copy_for_eval(mesh_input, true);
+ ASSERT_IS_VALID_MESH(mesh_final);
+ }
+ BKE_mesh_apply_vert_coords(mesh_final, deformed_verts);
+ }
+
+ modwrap_deformVerts(md, &mectx, mesh_final, deformed_verts, num_deformed_verts);
+
+ isPrevDeform = true;
+ }
+ else {
+ break;
+ }
+
+ /* grab modifiers until index i */
+ if ((index != -1) && (BLI_findindex(&ob->modifiers, md) >= index))
+ break;
+ }
+
+ /* Result of all leading deforming modifiers is cached for
+ * places that wish to use the original mesh but with deformed
+ * coordinates (like vertex paint). */
+ if (r_deform) {
+ mesh_deform = BKE_mesh_copy_for_eval(mesh_input, true);
+
+ if (deformed_verts) {
+ BKE_mesh_apply_vert_coords(mesh_deform, deformed_verts);
+ }
+ }
+ }
+
+ /* Apply all remaining constructive and deforming modifiers. */
+ for (; md; md = md->next, md_datamask = md_datamask->next) {
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if (!modifier_isEnabled(scene, md, required_mode)) {
+ continue;
+ }
+
+ if (mti->type == eModifierTypeType_OnlyDeform && !useDeform) {
+ continue;
+ }
+
+ if ((mti->flags & eModifierTypeFlag_RequiresOriginalData) && mesh_final) {
+ modifier_setError(md, "Modifier requires original data, bad stack position");
+ continue;
+ }
+
+ if (sculpt_mode && (!has_multires || multires_applied || sculpt_dyntopo)) {
+ bool unsupported = false;
+
+ if (md->type == eModifierType_Multires && ((MultiresModifierData *)md)->sculptlvl == 0) {
+ /* If multires is on level 0 skip it silently without warning message. */
+ if (!sculpt_dyntopo) {
+ continue;
+ }
+ }
+
+ if (sculpt_dyntopo)
+ unsupported = true;
+
+ if (scene->toolsettings->sculpt->flags & SCULPT_ONLY_DEFORM)
+ unsupported |= (mti->type != eModifierTypeType_OnlyDeform);
+
+ unsupported |= multires_applied;
+
+ if (unsupported) {
+ if (sculpt_dyntopo)
+ modifier_setError(md, "Not supported in dyntopo");
+ else
+ modifier_setError(md, "Not supported in sculpt mode");
+ continue;
+ }
+ else {
+ modifier_setError(md, "Hide, Mask and optimized display disabled");
+ }
+ }
+
+ if (need_mapping && !modifier_supportsMapping(md)) {
+ continue;
+ }
+
+ if (useDeform < 0 && mti->dependsOnTime && mti->dependsOnTime(md)) {
+ continue;
+ }
+
+ /* Add an orco layer if needed by this modifier. */
+ if (mesh_final && mti->requiredDataMask) {
+ CustomData_MeshMasks mask = {0};
+ mti->requiredDataMask(ob, md, &mask);
+ if (mask.vmask & CD_MASK_ORCO) {
+ add_orco_mesh(ob, NULL, mesh_final, mesh_orco, CD_ORCO);
+ }
+ }
+
+ /* How to apply modifier depends on (a) what we already have as
+ * a result of previous modifiers (could be a Mesh or just
+ * deformed vertices) and (b) what type the modifier is. */
+ if (mti->type == eModifierTypeType_OnlyDeform) {
+ /* No existing verts to deform, need to build them. */
+ if (!deformed_verts) {
+ if (mesh_final) {
+ /* Deforming a mesh, read the vertex locations
+ * out of the mesh and deform them. Once done with this
+ * run of deformers verts will be written back. */
+ deformed_verts = BKE_mesh_vertexCos_get(mesh_final, &num_deformed_verts);
+ }
+ else {
+ deformed_verts = BKE_mesh_vertexCos_get(mesh_input, &num_deformed_verts);
+ }
+ }
+ /* if this is not the last modifier in the stack then recalculate the normals
+ * to avoid giving bogus normals to the next modifier see: [#23673] */
+ else if (isPrevDeform && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
+ /* XXX, this covers bug #23673, but we may need normal calc for other types */
+ if (mesh_final) {
+ BKE_mesh_apply_vert_coords(mesh_final, deformed_verts);
+ }
+ }
+
+ modwrap_deformVerts(md, &mectx, mesh_final, deformed_verts, num_deformed_verts);
+ }
+ else {
+ /* determine which data layers are needed by following modifiers */
+ CustomData_MeshMasks nextmask;
+ if (md_datamask->next)
+ nextmask = md_datamask->next->mask;
+ else
+ nextmask = *dataMask;
+
+ /* apply vertex coordinates or build a Mesh as necessary */
+ if (mesh_final) {
+ if (deformed_verts) {
+ BKE_mesh_apply_vert_coords(mesh_final, deformed_verts);
+ }
+ }
+ else {
+ mesh_final = BKE_mesh_copy_for_eval(mesh_input, true);
+ ASSERT_IS_VALID_MESH(mesh_final);
+
+ if (deformed_verts) {
+ BKE_mesh_apply_vert_coords(mesh_final, deformed_verts);
+ }
+
+ /* Initialize original indices the first time we evaluate a
+ * constructive modifier. Modifiers will then do mapping mostly
+ * automatic by copying them through CustomData_copy_data along
+ * with other data.
+ *
+ * These are created when either requested by evaluation, or if
+ * following modifiers requested them. */
+ if (need_mapping ||
+ ((nextmask.vmask | nextmask.emask | nextmask.pmask) & CD_MASK_ORIGINDEX)) {
+ /* calc */
+ CustomData_add_layer(
+ &mesh_final->vdata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh_final->totvert);
+ CustomData_add_layer(
+ &mesh_final->edata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh_final->totedge);
+ CustomData_add_layer(
+ &mesh_final->pdata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh_final->totpoly);
+
+ /* Not worth parallelizing this, gives less than 0.1% overall speedup in best of best cases... */
+ range_vn_i(
+ CustomData_get_layer(&mesh_final->vdata, CD_ORIGINDEX), mesh_final->totvert, 0);
+ range_vn_i(
+ CustomData_get_layer(&mesh_final->edata, CD_ORIGINDEX), mesh_final->totedge, 0);
+ range_vn_i(
+ CustomData_get_layer(&mesh_final->pdata, CD_ORIGINDEX), mesh_final->totpoly, 0);
+ }
+ }
+
+ /* set the Mesh to only copy needed data */
+ CustomData_MeshMasks mask = md_datamask->mask;
+ /* needMapping check here fixes bug [#28112], otherwise it's
+ * possible that it won't be copied */
+ CustomData_MeshMasks_update(&mask, &append_mask);
+ if (need_mapping) {
+ mask.vmask |= CD_MASK_ORIGINDEX;
+ mask.emask |= CD_MASK_ORIGINDEX;
+ mask.pmask |= CD_MASK_ORIGINDEX;
+ }
+ mesh_set_only_copy(mesh_final, &mask);
+
+ /* add cloth rest shape key if needed */
+ if (mask.vmask & CD_MASK_CLOTH_ORCO) {
+ add_orco_mesh(ob, NULL, mesh_final, mesh_orco, CD_CLOTH_ORCO);
+ }
+
+ /* add an origspace layer if needed */
+ if ((md_datamask->mask.lmask) & CD_MASK_ORIGSPACE_MLOOP) {
+ if (!CustomData_has_layer(&mesh_final->ldata, CD_ORIGSPACE_MLOOP)) {
+ CustomData_add_layer(
+ &mesh_final->ldata, CD_ORIGSPACE_MLOOP, CD_CALLOC, NULL, mesh_final->totloop);
+ mesh_init_origspace(mesh_final);
+ }
+ }
+
+ Mesh *mesh_next = modwrap_applyModifier(md, &mectx, mesh_final);
+ ASSERT_IS_VALID_MESH(mesh_next);
+
+ if (mesh_next) {
+ /* if the modifier returned a new mesh, release the old one */
+ if (mesh_final != mesh_next) {
+ BLI_assert(mesh_final != mesh_input);
+ BKE_id_free(NULL, mesh_final);
+ }
+ mesh_final = mesh_next;
+
+ if (deformed_verts) {
+ MEM_freeN(deformed_verts);
+ deformed_verts = NULL;
+ }
+
+ mesh_copy_autosmooth(mesh_final, mesh_input);
+ }
+
+ /* create an orco mesh in parallel */
+ if (nextmask.vmask & CD_MASK_ORCO) {
+ if (!mesh_orco) {
+ mesh_orco = create_orco_mesh(ob, mesh_input, NULL, CD_ORCO);
+ }
+
+ nextmask.vmask &= ~CD_MASK_ORCO;
+ CustomData_MeshMasks temp_cddata_masks = {
+ .vmask = CD_MASK_ORIGINDEX,
+ .emask = CD_MASK_ORIGINDEX,
+ .fmask = CD_MASK_ORIGINDEX,
+ .pmask = CD_MASK_ORIGINDEX,
+ };
+ if (mti->requiredDataMask != NULL) {
+ mti->requiredDataMask(ob, md, &temp_cddata_masks);
+ }
+ CustomData_MeshMasks_update(&temp_cddata_masks, &nextmask);
+ mesh_set_only_copy(mesh_orco, &temp_cddata_masks);
+
+ mesh_next = modwrap_applyModifier(md, &mectx_orco, mesh_orco);
+ ASSERT_IS_VALID_MESH(mesh_next);
+
+ if (mesh_next) {
+ /* if the modifier returned a new mesh, release the old one */
+ if (mesh_orco != mesh_next) {
+ BLI_assert(mesh_orco != mesh_input);
+ BKE_id_free(NULL, mesh_orco);
+ }
+
+ mesh_orco = mesh_next;
+ }
+ }
+
+ /* create cloth orco mesh in parallel */
+ if (nextmask.vmask & CD_MASK_CLOTH_ORCO) {
+ if (!mesh_orco_cloth) {
+ mesh_orco_cloth = create_orco_mesh(ob, mesh_input, NULL, CD_CLOTH_ORCO);
+ }
+
+ nextmask.vmask &= ~CD_MASK_CLOTH_ORCO;
+ nextmask.vmask |= CD_MASK_ORIGINDEX;
+ nextmask.emask |= CD_MASK_ORIGINDEX;
+ nextmask.pmask |= CD_MASK_ORIGINDEX;
+ mesh_set_only_copy(mesh_orco_cloth, &nextmask);
+
+ mesh_next = modwrap_applyModifier(md, &mectx_orco, mesh_orco_cloth);
+ ASSERT_IS_VALID_MESH(mesh_next);
+
+ if (mesh_next) {
+ /* if the modifier returned a new mesh, release the old one */
+ if (mesh_orco_cloth != mesh_next) {
+ BLI_assert(mesh_orco != mesh_input);
+ BKE_id_free(NULL, mesh_orco_cloth);
+ }
+
+ mesh_orco_cloth = mesh_next;
+ }
+ }
+
+ /* in case of dynamic paint, make sure preview mask remains for following modifiers */
+ /* XXX Temp and hackish solution! */
+ if (md->type == eModifierType_DynamicPaint) {
+ append_mask.lmask |= CD_MASK_PREVIEW_MLOOPCOL;
+ }
+
+ mesh_final->runtime.deformed_only = false;
+ }
+
+ isPrevDeform = (mti->type == eModifierTypeType_OnlyDeform);
+
+ /* grab modifiers until index i */
+ if ((index != -1) && (BLI_findindex(&ob->modifiers, md) >= index))
+ break;
+
+ if (sculpt_mode && md->type == eModifierType_Multires) {
+ multires_applied = true;
+ }
+ }
+
+ BLI_linklist_free((LinkNode *)datamasks, NULL);
+
+ for (md = firstmd; md; md = md->next)
+ modifier_freeTemporaryData(md);
+
+ /* Yay, we are done. If we have a Mesh and deformed vertices
+ * need to apply these back onto the Mesh. If we have no
+ * Mesh then we need to build one. */
+ if (mesh_final == NULL) {
+ mesh_final = BKE_mesh_copy_for_eval(mesh_input, true);
+ }
+ if (deformed_verts) {
+ BKE_mesh_apply_vert_coords(mesh_final, deformed_verts);
+ MEM_freeN(deformed_verts);
+ deformed_verts = NULL;
+ }
+
+ /* Add orco coordinates to final and deformed mesh if requested. */
+ if (dataMask->vmask & CD_MASK_ORCO) {
+ add_orco_mesh(ob, NULL, mesh_final, mesh_orco, CD_ORCO);
+
+ if (mesh_deform)
+ add_orco_mesh(ob, NULL, mesh_deform, NULL, CD_ORCO);
+ }
+
+ if (mesh_orco) {
+ BKE_id_free(NULL, mesh_orco);
+ }
+ if (mesh_orco_cloth) {
+ BKE_id_free(NULL, mesh_orco_cloth);
+ }
+
+ /* Compute normals. */
+ mesh_calc_modifier_final_normals(mesh_input, dataMask, sculpt_dyntopo, mesh_final);
+
+ /* Return final mesh */
+ *r_final = mesh_final;
+ if (r_deform) {
+ *r_deform = mesh_deform;
+ }
}
-
float (*editbmesh_get_vertex_cos(BMEditMesh *em, int *r_numVerts))[3]
{
- BMIter iter;
- BMVert *eve;
- float (*cos)[3];
- int i;
+ BMIter iter;
+ BMVert *eve;
+ float(*cos)[3];
+ int i;
- *r_numVerts = em->bm->totvert;
+ *r_numVerts = em->bm->totvert;
- cos = MEM_malloc_arrayN(em->bm->totvert, 3 * sizeof(float), "vertexcos");
+ cos = MEM_malloc_arrayN(em->bm->totvert, 3 * sizeof(float), "vertexcos");
- BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
- copy_v3_v3(cos[i], eve->co);
- }
+ BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
+ copy_v3_v3(cos[i], eve->co);
+ }
- return cos;
+ return cos;
}
bool editbmesh_modifier_is_enabled(Scene *scene, ModifierData *md, bool has_prev_mesh)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- const int required_mode = eModifierMode_Realtime | eModifierMode_Editmode;
-
- if (!modifier_isEnabled(scene, md, required_mode)) {
- return false;
- }
-
- if ((mti->flags & eModifierTypeFlag_RequiresOriginalData) && has_prev_mesh) {
- modifier_setError(md, "Modifier requires original data, bad stack position");
- return false;
- }
-
- return true;
-}
-
-static void editbmesh_calc_modifier_final_normals(
- const Mesh *mesh_input,
- const CustomData_MeshMasks *dataMask,
- Mesh *mesh_final)
-{
- const bool do_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
- (dataMask->lmask & CD_MASK_NORMAL) != 0);
- /* Some modifiers may need this info from their target (other) object, simpler to generate it here as well. */
- const bool do_poly_normals = ((dataMask->pmask & CD_MASK_NORMAL) != 0);
-
- if (do_loop_normals) {
- /* In case we also need poly normals, add the layer here, then BKE_mesh_calc_normals_split() will fill it. */
- if (do_poly_normals) {
- if (!CustomData_has_layer(&mesh_final->pdata, CD_NORMAL)) {
- CustomData_add_layer(&mesh_final->pdata, CD_NORMAL, CD_CALLOC, NULL, mesh_final->totpoly);
- }
- }
- /* Compute loop normals */
- BKE_mesh_calc_normals_split(mesh_final);
- BKE_mesh_tessface_clear(mesh_final);
- }
-
- /* BMESH_ONLY, ensure tessface's used for drawing,
- * but don't recalculate if the last modifier in the stack gives us tessfaces
- * check if the derived meshes are DM_TYPE_EDITBMESH before calling, this isn't essential
- * but quiets annoying error messages since tessfaces wont be created. */
- if (dataMask->fmask & CD_MASK_MFACE) {
- if (mesh_final->edit_mesh == NULL) {
- BKE_mesh_tessface_ensure(mesh_final);
- }
- }
-
- /* same as mesh_calc_modifiers (if using loop normals, poly nors have already been computed). */
- if (!do_loop_normals) {
- BKE_mesh_ensure_normals_for_display(mesh_final);
-
- /* Some modifiers, like datatransfer, may generate those data, we do not want to keep them,
- * as they are used by display code when available (i.e. even if autosmooth is disabled). */
- if (CustomData_has_layer(&mesh_final->ldata, CD_NORMAL)) {
- CustomData_free_layers(&mesh_final->ldata, CD_NORMAL, mesh_final->totloop);
- }
- }
-}
-
-static void editbmesh_calc_modifiers(
- struct Depsgraph *depsgraph,
- Scene *scene,
- Object *ob,
- BMEditMesh *em_input,
- const CustomData_MeshMasks *dataMask,
- /* return args */
- Mesh **r_cage,
- Mesh **r_final)
-{
- /* Input and final mesh. Final mesh is only created the moment the first
- * constructive modifier is executed, or a deform modifier needs normals
- * or certain data layers. */
- Mesh *mesh_input = ob->data;
- Mesh *mesh_final = NULL;
- Mesh *mesh_cage = NULL;
-
- /* Deformed vertex locations array. Deform only modifier need this type of
- * float array rather than MVert*. Tracked along with mesh_final as an
- * optimization to avoid copying coordinates back and forth if there are
- * multiple sequential deform only modifiers. */
- float (*deformed_verts)[3] = NULL;
- int num_deformed_verts = 0;
- bool isPrevDeform = false;
-
- /* Mesh with constructive modifiers but no deformation applied. Tracked
- * along with final mesh if undeformed / orco coordinates are requested
- * for texturing. */
- Mesh *mesh_orco = NULL;
-
- /* Modifier evaluation modes. */
- const int required_mode = eModifierMode_Realtime | eModifierMode_Editmode;
- const bool do_init_statvis = false; /* FIXME: use V3D_OVERLAY_EDIT_STATVIS. */
-
- /* Modifier evaluation contexts for different types of modifiers. */
- const ModifierEvalContext mectx = {depsgraph, ob, MOD_APPLY_USECACHE};
- const ModifierEvalContext mectx_orco = {depsgraph, ob, MOD_APPLY_ORCO};
-
- /* Evaluate modifiers up to certain index to get the mesh cage. */
- int cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1);
- if (r_cage && cageIndex == -1) {
- mesh_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap(em_input, dataMask, NULL);
- mesh_copy_autosmooth(mesh_cage, mesh_input);
- }
-
- /* Get effective list of modifiers to execute. Some effects like shape keys
- * are added as virtual modifiers before the user created modifiers. */
- VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
-
- /* Compute accumulated datamasks needed by each modifier. It helps to do
- * this fine grained so that for example vertex groups are preserved up to
- * an armature modifier, but not through a following subsurf modifier where
- * subdividing them is expensive. */
- CDMaskLink *datamasks = modifiers_calcDataMasks(scene, ob, md, dataMask, required_mode, NULL, NULL);
- CDMaskLink *md_datamask = datamasks;
- CustomData_MeshMasks append_mask = CD_MASK_BAREMESH;
-
- /* Clear errors before evaluation. */
- modifiers_clearErrors(ob);
-
- for (int i = 0; md; i++, md = md->next, md_datamask = md_datamask->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
-
- if (!editbmesh_modifier_is_enabled(scene, md, mesh_final != NULL)) {
- continue;
- }
-
- /* Add an orco layer if needed by this modifier. */
- if (mesh_final && mti->requiredDataMask) {
- CustomData_MeshMasks mask = {0};
- mti->requiredDataMask(ob, md, &mask);
- if (mask.vmask & CD_MASK_ORCO) {
- add_orco_mesh(ob, em_input, mesh_final, mesh_orco, CD_ORCO);
- }
- }
-
- /* How to apply modifier depends on (a) what we already have as
- * a result of previous modifiers (could be a mesh or just
- * deformed vertices) and (b) what type the modifier is. */
- if (mti->type == eModifierTypeType_OnlyDeform) {
- /* No existing verts to deform, need to build them. */
- if (!deformed_verts) {
- if (mesh_final) {
- /* Deforming a derived mesh, read the vertex locations
- * out of the mesh and deform them. Once done with this
- * run of deformers verts will be written back. */
- deformed_verts = BKE_mesh_vertexCos_get(mesh_final, &num_deformed_verts);
- }
- else {
- deformed_verts = editbmesh_get_vertex_cos(em_input, &num_deformed_verts);
- }
- }
- else if (isPrevDeform && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
- if (mesh_final == NULL) {
- mesh_final = BKE_mesh_from_bmesh_for_eval_nomain(em_input->bm, NULL);
- ASSERT_IS_VALID_MESH(mesh_final);
- mesh_copy_autosmooth(mesh_final, mesh_input);
- }
- BLI_assert(deformed_verts != NULL);
- BKE_mesh_apply_vert_coords(mesh_final, deformed_verts);
- }
-
- if (mti->deformVertsEM)
- modwrap_deformVertsEM(md, &mectx, em_input, mesh_final, deformed_verts, num_deformed_verts);
- else
- modwrap_deformVerts(md, &mectx, mesh_final, deformed_verts, num_deformed_verts);
- }
- else {
- /* apply vertex coordinates or build a DerivedMesh as necessary */
- if (mesh_final) {
- if (deformed_verts) {
- Mesh *mesh_tmp = BKE_mesh_copy_for_eval(mesh_final, false);
- if (mesh_final != mesh_cage) {
- BKE_id_free(NULL, mesh_final);
- }
- mesh_final = mesh_tmp;
- BKE_mesh_apply_vert_coords(mesh_final, deformed_verts);
- }
- else if (mesh_final == mesh_cage) {
- /* 'me' may be changed by this modifier, so we need to copy it. */
- mesh_final = BKE_mesh_copy_for_eval(mesh_final, false);
- }
-
- }
- else {
- mesh_final = BKE_mesh_from_bmesh_for_eval_nomain(em_input->bm, NULL);
- ASSERT_IS_VALID_MESH(mesh_final);
-
- mesh_copy_autosmooth(mesh_final, mesh_input);
-
- if (deformed_verts) {
- BKE_mesh_apply_vert_coords(mesh_final, deformed_verts);
- }
- }
-
- /* create an orco derivedmesh in parallel */
- CustomData_MeshMasks mask = md_datamask->mask;
- if (mask.vmask & CD_MASK_ORCO) {
- if (!mesh_orco) {
- mesh_orco = create_orco_mesh(ob, mesh_input, em_input, CD_ORCO);
- }
-
- mask.vmask &= ~CD_MASK_ORCO;
- mask.vmask |= CD_MASK_ORIGINDEX;
- mask.emask |= CD_MASK_ORIGINDEX;
- mask.pmask |= CD_MASK_ORIGINDEX;
- mesh_set_only_copy(mesh_orco, &mask);
-
- Mesh *mesh_next = modwrap_applyModifier(md, &mectx_orco, mesh_orco);
- ASSERT_IS_VALID_MESH(mesh_next);
-
- if (mesh_next) {
- /* if the modifier returned a new dm, release the old one */
- if (mesh_orco && mesh_orco != mesh_next) {
- BKE_id_free(NULL, mesh_orco);
- }
- mesh_orco = mesh_next;
- }
- }
-
- /* set the DerivedMesh to only copy needed data */
- CustomData_MeshMasks_update(&mask, &append_mask);
- /* XXX WHAT? ovewrites mask ??? */
- /* CD_MASK_ORCO may have been cleared above */
- mask = md_datamask->mask;
- mask.vmask |= CD_MASK_ORIGINDEX;
- mask.emask |= CD_MASK_ORIGINDEX;
- mask.pmask |= CD_MASK_ORIGINDEX;
-
- mesh_set_only_copy(mesh_final, &mask);
-
- if (mask.lmask & CD_MASK_ORIGSPACE_MLOOP) {
- if (!CustomData_has_layer(&mesh_final->ldata, CD_ORIGSPACE_MLOOP)) {
- CustomData_add_layer(&mesh_final->ldata, CD_ORIGSPACE_MLOOP, CD_CALLOC, NULL, mesh_final->totloop);
- mesh_init_origspace(mesh_final);
- }
- }
-
- Mesh *mesh_next = modwrap_applyModifier(md, &mectx, mesh_final);
- ASSERT_IS_VALID_MESH(mesh_next);
-
- if (mesh_next) {
- if (mesh_final && mesh_final != mesh_next) {
- BKE_id_free(NULL, mesh_final);
- }
- mesh_final = mesh_next;
-
- if (deformed_verts) {
- MEM_freeN(deformed_verts);
- deformed_verts = NULL;
- }
-
- mesh_copy_autosmooth(mesh_final, mesh_input);
- }
- mesh_final->runtime.deformed_only = false;
- }
-
- if (r_cage && i == cageIndex) {
- if (mesh_final && deformed_verts) {
- mesh_cage = BKE_mesh_copy_for_eval(mesh_final, false);
- BKE_mesh_apply_vert_coords(mesh_cage, deformed_verts);
- }
- else if (mesh_final) {
- mesh_cage = mesh_final;
- }
- else {
- Mesh *me_orig = mesh_input;
- if (me_orig->id.tag & LIB_TAG_COPIED_ON_WRITE) {
- BKE_mesh_runtime_ensure_edit_data(me_orig);
- me_orig->runtime.edit_data->vertexCos = MEM_dupallocN(deformed_verts);
- }
- mesh_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap(
- em_input, dataMask,
- deformed_verts ? MEM_dupallocN(deformed_verts) : NULL);
- mesh_copy_autosmooth(mesh_cage, mesh_input);
- }
- }
-
- isPrevDeform = (mti->type == eModifierTypeType_OnlyDeform);
- }
-
- BLI_linklist_free((LinkNode *)datamasks, NULL);
-
- /* Yay, we are done. If we have a DerivedMesh and deformed vertices need
- * to apply these back onto the DerivedMesh. If we have no DerivedMesh
- * then we need to build one. */
- if (mesh_final) {
- if (deformed_verts) {
- Mesh *mesh_tmp = BKE_mesh_copy_for_eval(mesh_final, false);
- if (mesh_final != mesh_cage) {
- BKE_id_free(NULL, mesh_final);
- }
- mesh_final = mesh_tmp;
- BKE_mesh_apply_vert_coords(mesh_final, deformed_verts);
- }
- }
- else if (!deformed_verts && mesh_cage) {
- /* cage should already have up to date normals */
- mesh_final = mesh_cage;
-
- /* In this case, we should never have weight-modifying modifiers in stack... */
- if (do_init_statvis) {
- editmesh_update_statvis_color(scene, ob);
- }
- }
- else {
- /* this is just a copy of the editmesh, no need to calc normals */
- mesh_final = BKE_mesh_from_editmesh_with_coords_thin_wrap(em_input, dataMask, deformed_verts);
- deformed_verts = NULL;
-
- mesh_copy_autosmooth(mesh_final, mesh_input);
-
- /* In this case, we should never have weight-modifying modifiers in stack... */
- if (do_init_statvis) {
- editmesh_update_statvis_color(scene, ob);
- }
- }
-
- if (deformed_verts) {
- MEM_freeN(deformed_verts);
- }
-
- /* Add orco coordinates to final and deformed mesh if requested. */
- if (dataMask->vmask & CD_MASK_ORCO) {
- add_orco_mesh(ob, em_input, mesh_final, mesh_orco, CD_ORCO);
- }
-
- if (mesh_orco) {
- BKE_id_free(NULL, mesh_orco);
- }
-
- /* Compute normals. */
- editbmesh_calc_modifier_final_normals(mesh_input, dataMask, mesh_final);
- if (mesh_cage && (mesh_cage != mesh_final)) {
- editbmesh_calc_modifier_final_normals(mesh_input, dataMask, mesh_cage);
- }
-
- /* Return final mesh. */
- *r_final = mesh_final;
- if (r_cage) {
- *r_cage = mesh_cage;
- }
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const int required_mode = eModifierMode_Realtime | eModifierMode_Editmode;
+
+ if (!modifier_isEnabled(scene, md, required_mode)) {
+ return false;
+ }
+
+ if ((mti->flags & eModifierTypeFlag_RequiresOriginalData) && has_prev_mesh) {
+ modifier_setError(md, "Modifier requires original data, bad stack position");
+ return false;
+ }
+
+ return true;
+}
+
+static void editbmesh_calc_modifier_final_normals(const Mesh *mesh_input,
+ const CustomData_MeshMasks *dataMask,
+ Mesh *mesh_final)
+{
+ const bool do_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
+ (dataMask->lmask & CD_MASK_NORMAL) != 0);
+ /* Some modifiers may need this info from their target (other) object, simpler to generate it here as well. */
+ const bool do_poly_normals = ((dataMask->pmask & CD_MASK_NORMAL) != 0);
+
+ if (do_loop_normals) {
+ /* In case we also need poly normals, add the layer here, then BKE_mesh_calc_normals_split() will fill it. */
+ if (do_poly_normals) {
+ if (!CustomData_has_layer(&mesh_final->pdata, CD_NORMAL)) {
+ CustomData_add_layer(&mesh_final->pdata, CD_NORMAL, CD_CALLOC, NULL, mesh_final->totpoly);
+ }
+ }
+ /* Compute loop normals */
+ BKE_mesh_calc_normals_split(mesh_final);
+ BKE_mesh_tessface_clear(mesh_final);
+ }
+
+ /* BMESH_ONLY, ensure tessface's used for drawing,
+ * but don't recalculate if the last modifier in the stack gives us tessfaces
+ * check if the derived meshes are DM_TYPE_EDITBMESH before calling, this isn't essential
+ * but quiets annoying error messages since tessfaces wont be created. */
+ if (dataMask->fmask & CD_MASK_MFACE) {
+ if (mesh_final->edit_mesh == NULL) {
+ BKE_mesh_tessface_ensure(mesh_final);
+ }
+ }
+
+ /* same as mesh_calc_modifiers (if using loop normals, poly nors have already been computed). */
+ if (!do_loop_normals) {
+ BKE_mesh_ensure_normals_for_display(mesh_final);
+
+ /* Some modifiers, like datatransfer, may generate those data, we do not want to keep them,
+ * as they are used by display code when available (i.e. even if autosmooth is disabled). */
+ if (CustomData_has_layer(&mesh_final->ldata, CD_NORMAL)) {
+ CustomData_free_layers(&mesh_final->ldata, CD_NORMAL, mesh_final->totloop);
+ }
+ }
+}
+
+static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ BMEditMesh *em_input,
+ const CustomData_MeshMasks *dataMask,
+ /* return args */
+ Mesh **r_cage,
+ Mesh **r_final)
+{
+ /* Input and final mesh. Final mesh is only created the moment the first
+ * constructive modifier is executed, or a deform modifier needs normals
+ * or certain data layers. */
+ Mesh *mesh_input = ob->data;
+ Mesh *mesh_final = NULL;
+ Mesh *mesh_cage = NULL;
+
+ /* Deformed vertex locations array. Deform only modifier need this type of
+ * float array rather than MVert*. Tracked along with mesh_final as an
+ * optimization to avoid copying coordinates back and forth if there are
+ * multiple sequential deform only modifiers. */
+ float(*deformed_verts)[3] = NULL;
+ int num_deformed_verts = 0;
+ bool isPrevDeform = false;
+
+ /* Mesh with constructive modifiers but no deformation applied. Tracked
+ * along with final mesh if undeformed / orco coordinates are requested
+ * for texturing. */
+ Mesh *mesh_orco = NULL;
+
+ /* Modifier evaluation modes. */
+ const int required_mode = eModifierMode_Realtime | eModifierMode_Editmode;
+ const bool do_init_statvis = false; /* FIXME: use V3D_OVERLAY_EDIT_STATVIS. */
+
+ /* Modifier evaluation contexts for different types of modifiers. */
+ const ModifierEvalContext mectx = {depsgraph, ob, MOD_APPLY_USECACHE};
+ const ModifierEvalContext mectx_orco = {depsgraph, ob, MOD_APPLY_ORCO};
+
+ /* Evaluate modifiers up to certain index to get the mesh cage. */
+ int cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1);
+ if (r_cage && cageIndex == -1) {
+ mesh_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap(em_input, dataMask, NULL);
+ mesh_copy_autosmooth(mesh_cage, mesh_input);
+ }
+
+ /* Get effective list of modifiers to execute. Some effects like shape keys
+ * are added as virtual modifiers before the user created modifiers. */
+ VirtualModifierData virtualModifierData;
+ ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+
+ /* Compute accumulated datamasks needed by each modifier. It helps to do
+ * this fine grained so that for example vertex groups are preserved up to
+ * an armature modifier, but not through a following subsurf modifier where
+ * subdividing them is expensive. */
+ CDMaskLink *datamasks = modifiers_calcDataMasks(
+ scene, ob, md, dataMask, required_mode, NULL, NULL);
+ CDMaskLink *md_datamask = datamasks;
+ CustomData_MeshMasks append_mask = CD_MASK_BAREMESH;
+
+ /* Clear errors before evaluation. */
+ modifiers_clearErrors(ob);
+
+ for (int i = 0; md; i++, md = md->next, md_datamask = md_datamask->next) {
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if (!editbmesh_modifier_is_enabled(scene, md, mesh_final != NULL)) {
+ continue;
+ }
+
+ /* Add an orco layer if needed by this modifier. */
+ if (mesh_final && mti->requiredDataMask) {
+ CustomData_MeshMasks mask = {0};
+ mti->requiredDataMask(ob, md, &mask);
+ if (mask.vmask & CD_MASK_ORCO) {
+ add_orco_mesh(ob, em_input, mesh_final, mesh_orco, CD_ORCO);
+ }
+ }
+
+ /* How to apply modifier depends on (a) what we already have as
+ * a result of previous modifiers (could be a mesh or just
+ * deformed vertices) and (b) what type the modifier is. */
+ if (mti->type == eModifierTypeType_OnlyDeform) {
+ /* No existing verts to deform, need to build them. */
+ if (!deformed_verts) {
+ if (mesh_final) {
+ /* Deforming a derived mesh, read the vertex locations
+ * out of the mesh and deform them. Once done with this
+ * run of deformers verts will be written back. */
+ deformed_verts = BKE_mesh_vertexCos_get(mesh_final, &num_deformed_verts);
+ }
+ else {
+ deformed_verts = editbmesh_get_vertex_cos(em_input, &num_deformed_verts);
+ }
+ }
+ else if (isPrevDeform && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
+ if (mesh_final == NULL) {
+ mesh_final = BKE_mesh_from_bmesh_for_eval_nomain(em_input->bm, NULL);
+ ASSERT_IS_VALID_MESH(mesh_final);
+ mesh_copy_autosmooth(mesh_final, mesh_input);
+ }
+ BLI_assert(deformed_verts != NULL);
+ BKE_mesh_apply_vert_coords(mesh_final, deformed_verts);
+ }
+
+ if (mti->deformVertsEM)
+ modwrap_deformVertsEM(
+ md, &mectx, em_input, mesh_final, deformed_verts, num_deformed_verts);
+ else
+ modwrap_deformVerts(md, &mectx, mesh_final, deformed_verts, num_deformed_verts);
+ }
+ else {
+ /* apply vertex coordinates or build a DerivedMesh as necessary */
+ if (mesh_final) {
+ if (deformed_verts) {
+ Mesh *mesh_tmp = BKE_mesh_copy_for_eval(mesh_final, false);
+ if (mesh_final != mesh_cage) {
+ BKE_id_free(NULL, mesh_final);
+ }
+ mesh_final = mesh_tmp;
+ BKE_mesh_apply_vert_coords(mesh_final, deformed_verts);
+ }
+ else if (mesh_final == mesh_cage) {
+ /* 'me' may be changed by this modifier, so we need to copy it. */
+ mesh_final = BKE_mesh_copy_for_eval(mesh_final, false);
+ }
+ }
+ else {
+ mesh_final = BKE_mesh_from_bmesh_for_eval_nomain(em_input->bm, NULL);
+ ASSERT_IS_VALID_MESH(mesh_final);
+
+ mesh_copy_autosmooth(mesh_final, mesh_input);
+
+ if (deformed_verts) {
+ BKE_mesh_apply_vert_coords(mesh_final, deformed_verts);
+ }
+ }
+
+ /* create an orco derivedmesh in parallel */
+ CustomData_MeshMasks mask = md_datamask->mask;
+ if (mask.vmask & CD_MASK_ORCO) {
+ if (!mesh_orco) {
+ mesh_orco = create_orco_mesh(ob, mesh_input, em_input, CD_ORCO);
+ }
+
+ mask.vmask &= ~CD_MASK_ORCO;
+ mask.vmask |= CD_MASK_ORIGINDEX;
+ mask.emask |= CD_MASK_ORIGINDEX;
+ mask.pmask |= CD_MASK_ORIGINDEX;
+ mesh_set_only_copy(mesh_orco, &mask);
+
+ Mesh *mesh_next = modwrap_applyModifier(md, &mectx_orco, mesh_orco);
+ ASSERT_IS_VALID_MESH(mesh_next);
+
+ if (mesh_next) {
+ /* if the modifier returned a new dm, release the old one */
+ if (mesh_orco && mesh_orco != mesh_next) {
+ BKE_id_free(NULL, mesh_orco);
+ }
+ mesh_orco = mesh_next;
+ }
+ }
+
+ /* set the DerivedMesh to only copy needed data */
+ CustomData_MeshMasks_update(&mask, &append_mask);
+ /* XXX WHAT? ovewrites mask ??? */
+ /* CD_MASK_ORCO may have been cleared above */
+ mask = md_datamask->mask;
+ mask.vmask |= CD_MASK_ORIGINDEX;
+ mask.emask |= CD_MASK_ORIGINDEX;
+ mask.pmask |= CD_MASK_ORIGINDEX;
+
+ mesh_set_only_copy(mesh_final, &mask);
+
+ if (mask.lmask & CD_MASK_ORIGSPACE_MLOOP) {
+ if (!CustomData_has_layer(&mesh_final->ldata, CD_ORIGSPACE_MLOOP)) {
+ CustomData_add_layer(
+ &mesh_final->ldata, CD_ORIGSPACE_MLOOP, CD_CALLOC, NULL, mesh_final->totloop);
+ mesh_init_origspace(mesh_final);
+ }
+ }
+
+ Mesh *mesh_next = modwrap_applyModifier(md, &mectx, mesh_final);
+ ASSERT_IS_VALID_MESH(mesh_next);
+
+ if (mesh_next) {
+ if (mesh_final && mesh_final != mesh_next) {
+ BKE_id_free(NULL, mesh_final);
+ }
+ mesh_final = mesh_next;
+
+ if (deformed_verts) {
+ MEM_freeN(deformed_verts);
+ deformed_verts = NULL;
+ }
+
+ mesh_copy_autosmooth(mesh_final, mesh_input);
+ }
+ mesh_final->runtime.deformed_only = false;
+ }
+
+ if (r_cage && i == cageIndex) {
+ if (mesh_final && deformed_verts) {
+ mesh_cage = BKE_mesh_copy_for_eval(mesh_final, false);
+ BKE_mesh_apply_vert_coords(mesh_cage, deformed_verts);
+ }
+ else if (mesh_final) {
+ mesh_cage = mesh_final;
+ }
+ else {
+ Mesh *me_orig = mesh_input;
+ if (me_orig->id.tag & LIB_TAG_COPIED_ON_WRITE) {
+ BKE_mesh_runtime_ensure_edit_data(me_orig);
+ me_orig->runtime.edit_data->vertexCos = MEM_dupallocN(deformed_verts);
+ }
+ mesh_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap(
+ em_input, dataMask, deformed_verts ? MEM_dupallocN(deformed_verts) : NULL);
+ mesh_copy_autosmooth(mesh_cage, mesh_input);
+ }
+ }
+
+ isPrevDeform = (mti->type == eModifierTypeType_OnlyDeform);
+ }
+
+ BLI_linklist_free((LinkNode *)datamasks, NULL);
+
+ /* Yay, we are done. If we have a DerivedMesh and deformed vertices need
+ * to apply these back onto the DerivedMesh. If we have no DerivedMesh
+ * then we need to build one. */
+ if (mesh_final) {
+ if (deformed_verts) {
+ Mesh *mesh_tmp = BKE_mesh_copy_for_eval(mesh_final, false);
+ if (mesh_final != mesh_cage) {
+ BKE_id_free(NULL, mesh_final);
+ }
+ mesh_final = mesh_tmp;
+ BKE_mesh_apply_vert_coords(mesh_final, deformed_verts);
+ }
+ }
+ else if (!deformed_verts && mesh_cage) {
+ /* cage should already have up to date normals */
+ mesh_final = mesh_cage;
+
+ /* In this case, we should never have weight-modifying modifiers in stack... */
+ if (do_init_statvis) {
+ editmesh_update_statvis_color(scene, ob);
+ }
+ }
+ else {
+ /* this is just a copy of the editmesh, no need to calc normals */
+ mesh_final = BKE_mesh_from_editmesh_with_coords_thin_wrap(em_input, dataMask, deformed_verts);
+ deformed_verts = NULL;
+
+ mesh_copy_autosmooth(mesh_final, mesh_input);
+
+ /* In this case, we should never have weight-modifying modifiers in stack... */
+ if (do_init_statvis) {
+ editmesh_update_statvis_color(scene, ob);
+ }
+ }
+
+ if (deformed_verts) {
+ MEM_freeN(deformed_verts);
+ }
+
+ /* Add orco coordinates to final and deformed mesh if requested. */
+ if (dataMask->vmask & CD_MASK_ORCO) {
+ add_orco_mesh(ob, em_input, mesh_final, mesh_orco, CD_ORCO);
+ }
+
+ if (mesh_orco) {
+ BKE_id_free(NULL, mesh_orco);
+ }
+
+ /* Compute normals. */
+ editbmesh_calc_modifier_final_normals(mesh_input, dataMask, mesh_final);
+ if (mesh_cage && (mesh_cage != mesh_final)) {
+ editbmesh_calc_modifier_final_normals(mesh_input, dataMask, mesh_cage);
+ }
+
+ /* Return final mesh. */
+ *r_final = mesh_final;
+ if (r_cage) {
+ *r_cage = mesh_cage;
+ }
}
static void mesh_finalize_eval(Object *object)
{
- Mesh *mesh = (Mesh *)object->data;
- Mesh *mesh_eval = object->runtime.mesh_eval;
- /* Special Tweaks for cases when evaluated mesh came from
- * BKE_mesh_new_nomain_from_template().
- */
- BLI_strncpy(mesh_eval->id.name, mesh->id.name, sizeof(mesh_eval->id.name));
- if (mesh_eval->mat != NULL) {
- MEM_freeN(mesh_eval->mat);
- }
- /* Set flag which makes it easier to see what's going on in a debugger. */
- mesh_eval->id.tag |= LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT;
- mesh_eval->mat = MEM_dupallocN(mesh->mat);
- mesh_eval->totcol = mesh->totcol;
- /* Make evaluated mesh to share same edit mesh pointer as original
- * and copied meshes.
- */
- mesh_eval->edit_mesh = mesh->edit_mesh;
- /* Copy autosmooth settings from original mesh.
- * This is not done by BKE_mesh_new_nomain_from_template(), so need to take
- * extra care here.
- */
- mesh_eval->flag |= (mesh->flag & ME_AUTOSMOOTH);
- mesh_eval->smoothresh = mesh->smoothresh;
- /* Replace evaluated object's data with fully evaluated mesh. */
- /* TODO(sergey): There was statement done by Sybren and Mai that this
- * caused modifiers to be applied twice. which is weirtd and shouldn't
- * really happen. But since there is no reference to the report, can not
- * do much about this.
- */
-
- /* Object is sometimes not evaluated!
- * TODO(sergey): BAD TEMPORARY HACK FOR UNTIL WE ARE SMARTER */
- if (object->id.tag & LIB_TAG_COPIED_ON_WRITE) {
- object->data = mesh_eval;
- }
- else {
- /* evaluated will be available via: 'object->runtime.mesh_eval' */
- }
+ Mesh *mesh = (Mesh *)object->data;
+ Mesh *mesh_eval = object->runtime.mesh_eval;
+ /* Special Tweaks for cases when evaluated mesh came from
+ * BKE_mesh_new_nomain_from_template().
+ */
+ BLI_strncpy(mesh_eval->id.name, mesh->id.name, sizeof(mesh_eval->id.name));
+ if (mesh_eval->mat != NULL) {
+ MEM_freeN(mesh_eval->mat);
+ }
+ /* Set flag which makes it easier to see what's going on in a debugger. */
+ mesh_eval->id.tag |= LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT;
+ mesh_eval->mat = MEM_dupallocN(mesh->mat);
+ mesh_eval->totcol = mesh->totcol;
+ /* Make evaluated mesh to share same edit mesh pointer as original
+ * and copied meshes.
+ */
+ mesh_eval->edit_mesh = mesh->edit_mesh;
+ /* Copy autosmooth settings from original mesh.
+ * This is not done by BKE_mesh_new_nomain_from_template(), so need to take
+ * extra care here.
+ */
+ mesh_eval->flag |= (mesh->flag & ME_AUTOSMOOTH);
+ mesh_eval->smoothresh = mesh->smoothresh;
+ /* Replace evaluated object's data with fully evaluated mesh. */
+ /* TODO(sergey): There was statement done by Sybren and Mai that this
+ * caused modifiers to be applied twice. which is weirtd and shouldn't
+ * really happen. But since there is no reference to the report, can not
+ * do much about this.
+ */
+
+ /* Object is sometimes not evaluated!
+ * TODO(sergey): BAD TEMPORARY HACK FOR UNTIL WE ARE SMARTER */
+ if (object->id.tag & LIB_TAG_COPIED_ON_WRITE) {
+ object->data = mesh_eval;
+ }
+ else {
+ /* evaluated will be available via: 'object->runtime.mesh_eval' */
+ }
}
static void mesh_build_extra_data(struct Depsgraph *depsgraph, Object *ob)
{
- uint32_t eval_flags = DEG_get_eval_flags_for_id(depsgraph, &ob->id);
+ uint32_t eval_flags = DEG_get_eval_flags_for_id(depsgraph, &ob->id);
- if (eval_flags & DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY) {
- BKE_shrinkwrap_compute_boundary_data(ob->runtime.mesh_eval);
- }
+ if (eval_flags & DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY) {
+ BKE_shrinkwrap_compute_boundary_data(ob->runtime.mesh_eval);
+ }
}
static void mesh_runtime_check_normals_valid(const Mesh *mesh)
{
- UNUSED_VARS_NDEBUG(mesh);
- BLI_assert(!(mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL));
- BLI_assert(!(mesh->runtime.cd_dirty_loop & CD_MASK_NORMAL));
- BLI_assert(!(mesh->runtime.cd_dirty_poly & CD_MASK_NORMAL));
+ UNUSED_VARS_NDEBUG(mesh);
+ BLI_assert(!(mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL));
+ BLI_assert(!(mesh->runtime.cd_dirty_loop & CD_MASK_NORMAL));
+ BLI_assert(!(mesh->runtime.cd_dirty_poly & CD_MASK_NORMAL));
}
-static void mesh_build_data(
- struct Depsgraph *depsgraph, Scene *scene, Object *ob, const CustomData_MeshMasks *dataMask,
- const bool need_mapping)
+static void mesh_build_data(struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ const CustomData_MeshMasks *dataMask,
+ const bool need_mapping)
{
- BLI_assert(ob->type == OB_MESH);
+ BLI_assert(ob->type == OB_MESH);
- /* Evaluated meshes aren't supposed to be created on original instances. If you do,
- * they aren't cleaned up properly on mode switch, causing crashes, e.g T58150. */
- BLI_assert(ob->id.tag & LIB_TAG_COPIED_ON_WRITE);
+ /* Evaluated meshes aren't supposed to be created on original instances. If you do,
+ * they aren't cleaned up properly on mode switch, causing crashes, e.g T58150. */
+ BLI_assert(ob->id.tag & LIB_TAG_COPIED_ON_WRITE);
- BKE_object_free_derived_caches(ob);
- BKE_object_sculpt_modifiers_changed(ob);
+ BKE_object_free_derived_caches(ob);
+ BKE_object_sculpt_modifiers_changed(ob);
#if 0 /* XXX This is already taken care of in mesh_calc_modifiers()... */
- if (need_mapping) {
- /* Also add the flag so that it is recorded in lastDataMask. */
- dataMask->vmask |= CD_MASK_ORIGINDEX;
- dataMask->emask |= CD_MASK_ORIGINDEX;
- dataMask->pmask |= CD_MASK_ORIGINDEX;
- }
+ if (need_mapping) {
+ /* Also add the flag so that it is recorded in lastDataMask. */
+ dataMask->vmask |= CD_MASK_ORIGINDEX;
+ dataMask->emask |= CD_MASK_ORIGINDEX;
+ dataMask->pmask |= CD_MASK_ORIGINDEX;
+ }
#endif
- mesh_calc_modifiers(
- depsgraph, scene, ob, 1, need_mapping, dataMask, -1, true,
- &ob->runtime.mesh_deform_eval, &ob->runtime.mesh_eval);
+ mesh_calc_modifiers(depsgraph,
+ scene,
+ ob,
+ 1,
+ need_mapping,
+ dataMask,
+ -1,
+ true,
+ &ob->runtime.mesh_deform_eval,
+ &ob->runtime.mesh_eval);
- BKE_object_boundbox_calc_from_mesh(ob, ob->runtime.mesh_eval);
- /* Only copy texspace from orig mesh if some modifier (hint: smoke sim, see T58492)
- * did not re-enable that flag (which always get disabled for eval mesh as a start). */
- if (!(ob->runtime.mesh_eval->texflag & ME_AUTOSPACE)) {
- BKE_mesh_texspace_copy_from_object(ob->runtime.mesh_eval, ob);
- }
+ BKE_object_boundbox_calc_from_mesh(ob, ob->runtime.mesh_eval);
+ /* Only copy texspace from orig mesh if some modifier (hint: smoke sim, see T58492)
+ * did not re-enable that flag (which always get disabled for eval mesh as a start). */
+ if (!(ob->runtime.mesh_eval->texflag & ME_AUTOSPACE)) {
+ BKE_mesh_texspace_copy_from_object(ob->runtime.mesh_eval, ob);
+ }
- mesh_finalize_eval(ob);
+ mesh_finalize_eval(ob);
- ob->runtime.last_data_mask = *dataMask;
- ob->runtime.last_need_mapping = need_mapping;
+ ob->runtime.last_data_mask = *dataMask;
+ ob->runtime.last_need_mapping = need_mapping;
- if ((ob->mode & OB_MODE_ALL_SCULPT) && ob->sculpt) {
- /* create PBVH immediately (would be created on the fly too,
- * but this avoids waiting on first stroke) */
- /* XXX Disabled for now.
- * This can create horrible nasty bugs by generating re-entrant call of mesh_get_eval_final! */
-// BKE_sculpt_update_mesh_elements(depsgraph, scene, scene->toolsettings->sculpt, ob, false, false);
- }
+ if ((ob->mode & OB_MODE_ALL_SCULPT) && ob->sculpt) {
+ /* create PBVH immediately (would be created on the fly too,
+ * but this avoids waiting on first stroke) */
+ /* XXX Disabled for now.
+ * This can create horrible nasty bugs by generating re-entrant call of mesh_get_eval_final! */
+ // BKE_sculpt_update_mesh_elements(depsgraph, scene, scene->toolsettings->sculpt, ob, false, false);
+ }
- mesh_runtime_check_normals_valid(ob->runtime.mesh_eval);
- mesh_build_extra_data(depsgraph, ob);
+ mesh_runtime_check_normals_valid(ob->runtime.mesh_eval);
+ mesh_build_extra_data(depsgraph, ob);
}
-static void editbmesh_build_data(
- struct Depsgraph *depsgraph, Scene *scene,
- Object *obedit, BMEditMesh *em, CustomData_MeshMasks *dataMask)
+static void editbmesh_build_data(struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *obedit,
+ BMEditMesh *em,
+ CustomData_MeshMasks *dataMask)
{
- BLI_assert(em->ob->id.tag & LIB_TAG_COPIED_ON_WRITE);
+ BLI_assert(em->ob->id.tag & LIB_TAG_COPIED_ON_WRITE);
- BKE_object_free_derived_caches(obedit);
- BKE_object_sculpt_modifiers_changed(obedit);
+ BKE_object_free_derived_caches(obedit);
+ BKE_object_sculpt_modifiers_changed(obedit);
- BKE_editmesh_free_derivedmesh(em);
+ BKE_editmesh_free_derivedmesh(em);
- Mesh *me_cage;
- Mesh *me_final;
+ Mesh *me_cage;
+ Mesh *me_final;
- editbmesh_calc_modifiers(
- depsgraph, scene, obedit, em, dataMask,
- &me_cage, &me_final);
+ editbmesh_calc_modifiers(depsgraph, scene, obedit, em, dataMask, &me_cage, &me_final);
- em->mesh_eval_final = me_final;
- em->mesh_eval_cage = me_cage;
+ em->mesh_eval_final = me_final;
+ em->mesh_eval_cage = me_cage;
- BKE_object_boundbox_calc_from_mesh(obedit, em->mesh_eval_final);
+ BKE_object_boundbox_calc_from_mesh(obedit, em->mesh_eval_final);
- em->lastDataMask = *dataMask;
+ em->lastDataMask = *dataMask;
- mesh_runtime_check_normals_valid(em->mesh_eval_final);
+ mesh_runtime_check_normals_valid(em->mesh_eval_final);
}
-static void object_get_datamask(const Depsgraph *depsgraph, Object *ob, CustomData_MeshMasks *r_mask, bool *r_need_mapping)
+static void object_get_datamask(const Depsgraph *depsgraph,
+ Object *ob,
+ CustomData_MeshMasks *r_mask,
+ bool *r_need_mapping)
{
- ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
- Object *actob = view_layer->basact ? DEG_get_original_object(view_layer->basact->object) : NULL;
+ ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
+ Object *actob = view_layer->basact ? DEG_get_original_object(view_layer->basact->object) : NULL;
- DEG_get_customdata_mask_for_object(depsgraph, ob, r_mask);
+ DEG_get_customdata_mask_for_object(depsgraph, ob, r_mask);
- if (r_need_mapping) {
- *r_need_mapping = false;
- }
+ if (r_need_mapping) {
+ *r_need_mapping = false;
+ }
- if (DEG_get_original_object(ob) == actob) {
- bool editing = BKE_paint_select_face_test(actob);
+ if (DEG_get_original_object(ob) == actob) {
+ bool editing = BKE_paint_select_face_test(actob);
- /* weight paint and face select need original indices because of selection buffer drawing */
- if (r_need_mapping) {
- *r_need_mapping = (editing || (ob->mode & (OB_MODE_WEIGHT_PAINT | OB_MODE_VERTEX_PAINT)));
- }
+ /* weight paint and face select need original indices because of selection buffer drawing */
+ if (r_need_mapping) {
+ *r_need_mapping = (editing || (ob->mode & (OB_MODE_WEIGHT_PAINT | OB_MODE_VERTEX_PAINT)));
+ }
- /* check if we need tfaces & mcols due to face select or texture paint */
- if ((ob->mode & OB_MODE_TEXTURE_PAINT) || editing) {
- r_mask->lmask |= CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL;
- r_mask->fmask |= CD_MASK_MTFACE;
- }
+ /* check if we need tfaces & mcols due to face select or texture paint */
+ if ((ob->mode & OB_MODE_TEXTURE_PAINT) || editing) {
+ r_mask->lmask |= CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL;
+ r_mask->fmask |= CD_MASK_MTFACE;
+ }
- /* check if we need mcols due to vertex paint or weightpaint */
- if (ob->mode & OB_MODE_VERTEX_PAINT) {
- r_mask->lmask |= CD_MASK_MLOOPCOL;
- }
+ /* check if we need mcols due to vertex paint or weightpaint */
+ if (ob->mode & OB_MODE_VERTEX_PAINT) {
+ r_mask->lmask |= CD_MASK_MLOOPCOL;
+ }
- if (ob->mode & OB_MODE_WEIGHT_PAINT) {
- r_mask->vmask |= CD_MASK_MDEFORMVERT;
- }
+ if (ob->mode & OB_MODE_WEIGHT_PAINT) {
+ r_mask->vmask |= CD_MASK_MDEFORMVERT;
+ }
- if (ob->mode & OB_MODE_EDIT)
- r_mask->vmask |= CD_MASK_MVERT_SKIN;
- }
+ if (ob->mode & OB_MODE_EDIT)
+ r_mask->vmask |= CD_MASK_MVERT_SKIN;
+ }
}
-void makeDerivedMesh(
- struct Depsgraph *depsgraph, Scene *scene, Object *ob, BMEditMesh *em,
- const CustomData_MeshMasks *dataMask)
+void makeDerivedMesh(struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ BMEditMesh *em,
+ const CustomData_MeshMasks *dataMask)
{
- bool need_mapping;
- CustomData_MeshMasks cddata_masks = *dataMask;
- object_get_datamask(depsgraph, ob, &cddata_masks, &need_mapping);
+ bool need_mapping;
+ CustomData_MeshMasks cddata_masks = *dataMask;
+ object_get_datamask(depsgraph, ob, &cddata_masks, &need_mapping);
- if (em) {
- editbmesh_build_data(depsgraph, scene, ob, em, &cddata_masks);
- }
- else {
- mesh_build_data(depsgraph, scene, ob, &cddata_masks, need_mapping);
- }
+ if (em) {
+ editbmesh_build_data(depsgraph, scene, ob, em, &cddata_masks);
+ }
+ else {
+ mesh_build_data(depsgraph, scene, ob, &cddata_masks, need_mapping);
+ }
}
/***/
-Mesh *mesh_get_eval_final(struct Depsgraph *depsgraph, Scene *scene, Object *ob, const CustomData_MeshMasks *dataMask)
+Mesh *mesh_get_eval_final(struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ const CustomData_MeshMasks *dataMask)
{
- /* This function isn't thread-safe and can't be used during evaluation. */
- BLI_assert(DEG_debug_is_evaluating(depsgraph) == false);
+ /* This function isn't thread-safe and can't be used during evaluation. */
+ BLI_assert(DEG_debug_is_evaluating(depsgraph) == false);
- /* Evaluated meshes aren't supposed to be created on original instances. If you do,
- * they aren't cleaned up properly on mode switch, causing crashes, e.g T58150. */
- BLI_assert(ob->id.tag & LIB_TAG_COPIED_ON_WRITE);
+ /* Evaluated meshes aren't supposed to be created on original instances. If you do,
+ * they aren't cleaned up properly on mode switch, causing crashes, e.g T58150. */
+ BLI_assert(ob->id.tag & LIB_TAG_COPIED_ON_WRITE);
- /* if there's no evaluated mesh or the last data mask used doesn't include
- * the data we need, rebuild the derived mesh
- */
- bool need_mapping;
- CustomData_MeshMasks cddata_masks = *dataMask;
- object_get_datamask(depsgraph, ob, &cddata_masks, &need_mapping);
+ /* if there's no evaluated mesh or the last data mask used doesn't include
+ * the data we need, rebuild the derived mesh
+ */
+ bool need_mapping;
+ CustomData_MeshMasks cddata_masks = *dataMask;
+ object_get_datamask(depsgraph, ob, &cddata_masks, &need_mapping);
- if (!ob->runtime.mesh_eval ||
- !CustomData_MeshMasks_are_matching(&(ob->runtime.last_data_mask), &cddata_masks) ||
- (need_mapping && !ob->runtime.last_need_mapping))
- {
- CustomData_MeshMasks_update(&cddata_masks, &ob->runtime.last_data_mask);
- mesh_build_data(depsgraph, scene, ob, &cddata_masks,
- need_mapping || ob->runtime.last_need_mapping);
- }
+ if (!ob->runtime.mesh_eval ||
+ !CustomData_MeshMasks_are_matching(&(ob->runtime.last_data_mask), &cddata_masks) ||
+ (need_mapping && !ob->runtime.last_need_mapping)) {
+ CustomData_MeshMasks_update(&cddata_masks, &ob->runtime.last_data_mask);
+ mesh_build_data(
+ depsgraph, scene, ob, &cddata_masks, need_mapping || ob->runtime.last_need_mapping);
+ }
- if (ob->runtime.mesh_eval) { BLI_assert(!(ob->runtime.mesh_eval->runtime.cd_dirty_vert & CD_MASK_NORMAL)); }
- return ob->runtime.mesh_eval;
+ if (ob->runtime.mesh_eval) {
+ BLI_assert(!(ob->runtime.mesh_eval->runtime.cd_dirty_vert & CD_MASK_NORMAL));
+ }
+ return ob->runtime.mesh_eval;
}
-Mesh *mesh_get_eval_deform(struct Depsgraph *depsgraph, Scene *scene, Object *ob, const CustomData_MeshMasks *dataMask)
+Mesh *mesh_get_eval_deform(struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ const CustomData_MeshMasks *dataMask)
{
- /* This function isn't thread-safe and can't be used during evaluation. */
- BLI_assert(DEG_debug_is_evaluating(depsgraph) == false);
+ /* This function isn't thread-safe and can't be used during evaluation. */
+ BLI_assert(DEG_debug_is_evaluating(depsgraph) == false);
- /* Evaluated meshes aren't supposed to be created on original instances. If you do,
- * they aren't cleaned up properly on mode switch, causing crashes, e.g T58150. */
- BLI_assert(ob->id.tag & LIB_TAG_COPIED_ON_WRITE);
+ /* Evaluated meshes aren't supposed to be created on original instances. If you do,
+ * they aren't cleaned up properly on mode switch, causing crashes, e.g T58150. */
+ BLI_assert(ob->id.tag & LIB_TAG_COPIED_ON_WRITE);
- /* if there's no derived mesh or the last data mask used doesn't include
- * the data we need, rebuild the derived mesh
- */
- bool need_mapping;
+ /* if there's no derived mesh or the last data mask used doesn't include
+ * the data we need, rebuild the derived mesh
+ */
+ bool need_mapping;
- CustomData_MeshMasks cddata_masks = *dataMask;
- object_get_datamask(depsgraph, ob, &cddata_masks, &need_mapping);
+ CustomData_MeshMasks cddata_masks = *dataMask;
+ object_get_datamask(depsgraph, ob, &cddata_masks, &need_mapping);
- if (!ob->runtime.mesh_deform_eval ||
- !CustomData_MeshMasks_are_matching(&(ob->runtime.last_data_mask), &cddata_masks) ||
- (need_mapping && !ob->runtime.last_need_mapping))
- {
- CustomData_MeshMasks_update(&cddata_masks, &ob->runtime.last_data_mask);
- mesh_build_data(depsgraph, scene, ob, &cddata_masks,
- need_mapping || ob->runtime.last_need_mapping);
- }
+ if (!ob->runtime.mesh_deform_eval ||
+ !CustomData_MeshMasks_are_matching(&(ob->runtime.last_data_mask), &cddata_masks) ||
+ (need_mapping && !ob->runtime.last_need_mapping)) {
+ CustomData_MeshMasks_update(&cddata_masks, &ob->runtime.last_data_mask);
+ mesh_build_data(
+ depsgraph, scene, ob, &cddata_masks, need_mapping || ob->runtime.last_need_mapping);
+ }
- return ob->runtime.mesh_deform_eval;
+ return ob->runtime.mesh_deform_eval;
}
-
-Mesh *mesh_create_eval_final_render(Depsgraph *depsgraph, Scene *scene, Object *ob, const CustomData_MeshMasks *dataMask)
+Mesh *mesh_create_eval_final_render(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ const CustomData_MeshMasks *dataMask)
{
- Mesh *final;
+ Mesh *final;
- mesh_calc_modifiers(
- depsgraph, scene, ob, 1, false, dataMask, -1, false,
- NULL, &final);
+ mesh_calc_modifiers(depsgraph, scene, ob, 1, false, dataMask, -1, false, NULL, &final);
- return final;
+ return final;
}
-Mesh *mesh_create_eval_final_index_render(
- Depsgraph *depsgraph, Scene *scene,
- Object *ob, const CustomData_MeshMasks *dataMask, int index)
+Mesh *mesh_create_eval_final_index_render(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ const CustomData_MeshMasks *dataMask,
+ int index)
{
- Mesh *final;
+ Mesh *final;
- mesh_calc_modifiers(
- depsgraph, scene, ob, 1, false, dataMask, index, false,
- NULL, &final);
+ mesh_calc_modifiers(depsgraph, scene, ob, 1, false, dataMask, index, false, NULL, &final);
- return final;
+ return final;
}
-Mesh *mesh_create_eval_final_view(
- Depsgraph *depsgraph, Scene *scene,
- Object *ob, const CustomData_MeshMasks *dataMask)
+Mesh *mesh_create_eval_final_view(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ const CustomData_MeshMasks *dataMask)
{
- Mesh *final;
+ Mesh *final;
- /* XXX hack
- * psys modifier updates particle state when called during dupli-list generation,
- * which can lead to wrong transforms. This disables particle system modifier execution.
- */
- ob->transflag |= OB_NO_PSYS_UPDATE;
+ /* XXX hack
+ * psys modifier updates particle state when called during dupli-list generation,
+ * which can lead to wrong transforms. This disables particle system modifier execution.
+ */
+ ob->transflag |= OB_NO_PSYS_UPDATE;
- mesh_calc_modifiers(
- depsgraph, scene, ob, 1, false, dataMask, -1, false,
- NULL, &final);
+ mesh_calc_modifiers(depsgraph, scene, ob, 1, false, dataMask, -1, false, NULL, &final);
- ob->transflag &= ~OB_NO_PSYS_UPDATE;
+ ob->transflag &= ~OB_NO_PSYS_UPDATE;
- return final;
+ return final;
}
-Mesh *mesh_create_eval_no_deform(
- Depsgraph *depsgraph, Scene *scene, Object *ob,
- const CustomData_MeshMasks *dataMask)
+Mesh *mesh_create_eval_no_deform(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ const CustomData_MeshMasks *dataMask)
{
- Mesh *final;
+ Mesh *final;
- mesh_calc_modifiers(
- depsgraph, scene, ob, 0, false, dataMask, -1, false,
- NULL, &final);
+ mesh_calc_modifiers(depsgraph, scene, ob, 0, false, dataMask, -1, false, NULL, &final);
- return final;
+ return final;
}
-Mesh *mesh_create_eval_no_deform_render(
- Depsgraph *depsgraph, Scene *scene, Object *ob,
- const CustomData_MeshMasks *dataMask)
+Mesh *mesh_create_eval_no_deform_render(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ const CustomData_MeshMasks *dataMask)
{
- Mesh *final;
+ Mesh *final;
- mesh_calc_modifiers(
- depsgraph, scene, ob, 0, false, dataMask, -1, false,
- NULL, &final);
+ mesh_calc_modifiers(depsgraph, scene, ob, 0, false, dataMask, -1, false, NULL, &final);
- return final;
+ return final;
}
/***/
-Mesh *editbmesh_get_eval_cage_and_final(
- Depsgraph *depsgraph, Scene *scene, Object *obedit, BMEditMesh *em,
- const CustomData_MeshMasks *dataMask,
- /* return args */
- Mesh **r_final)
+Mesh *editbmesh_get_eval_cage_and_final(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *obedit,
+ BMEditMesh *em,
+ const CustomData_MeshMasks *dataMask,
+ /* return args */
+ Mesh **r_final)
{
- CustomData_MeshMasks cddata_masks = *dataMask;
+ CustomData_MeshMasks cddata_masks = *dataMask;
- /* if there's no derived mesh or the last data mask used doesn't include
- * the data we need, rebuild the derived mesh
- */
- object_get_datamask(depsgraph, obedit, &cddata_masks, NULL);
+ /* if there's no derived mesh or the last data mask used doesn't include
+ * the data we need, rebuild the derived mesh
+ */
+ object_get_datamask(depsgraph, obedit, &cddata_masks, NULL);
- if (!em->mesh_eval_cage ||
- !CustomData_MeshMasks_are_matching(&(em->lastDataMask), &cddata_masks))
- {
- editbmesh_build_data(depsgraph, scene, obedit, em, &cddata_masks);
- }
+ if (!em->mesh_eval_cage ||
+ !CustomData_MeshMasks_are_matching(&(em->lastDataMask), &cddata_masks)) {
+ editbmesh_build_data(depsgraph, scene, obedit, em, &cddata_masks);
+ }
- *r_final = em->mesh_eval_final;
- if (em->mesh_eval_final) { BLI_assert(!(em->mesh_eval_final->runtime.cd_dirty_vert & DM_DIRTY_NORMALS)); }
- return em->mesh_eval_cage;
+ *r_final = em->mesh_eval_final;
+ if (em->mesh_eval_final) {
+ BLI_assert(!(em->mesh_eval_final->runtime.cd_dirty_vert & DM_DIRTY_NORMALS));
+ }
+ return em->mesh_eval_cage;
}
-Mesh *editbmesh_get_eval_cage(
- struct Depsgraph *depsgraph, Scene *scene, Object *obedit, BMEditMesh *em,
- const CustomData_MeshMasks *dataMask)
+Mesh *editbmesh_get_eval_cage(struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *obedit,
+ BMEditMesh *em,
+ const CustomData_MeshMasks *dataMask)
{
- CustomData_MeshMasks cddata_masks = *dataMask;
+ CustomData_MeshMasks cddata_masks = *dataMask;
- /* if there's no derived mesh or the last data mask used doesn't include
- * the data we need, rebuild the derived mesh
- */
- object_get_datamask(depsgraph, obedit, &cddata_masks, NULL);
+ /* if there's no derived mesh or the last data mask used doesn't include
+ * the data we need, rebuild the derived mesh
+ */
+ object_get_datamask(depsgraph, obedit, &cddata_masks, NULL);
- if (!em->mesh_eval_cage ||
- !CustomData_MeshMasks_are_matching(&(em->lastDataMask), &cddata_masks))
- {
- editbmesh_build_data(depsgraph, scene, obedit, em, &cddata_masks);
- }
+ if (!em->mesh_eval_cage ||
+ !CustomData_MeshMasks_are_matching(&(em->lastDataMask), &cddata_masks)) {
+ editbmesh_build_data(depsgraph, scene, obedit, em, &cddata_masks);
+ }
- return em->mesh_eval_cage;
+ return em->mesh_eval_cage;
}
-Mesh *editbmesh_get_eval_cage_from_orig(
- struct Depsgraph *depsgraph, Scene *scene, Object *obedit, BMEditMesh *UNUSED(em),
- const CustomData_MeshMasks *dataMask)
+Mesh *editbmesh_get_eval_cage_from_orig(struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *obedit,
+ BMEditMesh *UNUSED(em),
+ const CustomData_MeshMasks *dataMask)
{
- BLI_assert((obedit->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0);
- Scene *scene_eval = (Scene *)DEG_get_evaluated_id(depsgraph, &scene->id);
- Object *obedit_eval = (Object *)DEG_get_evaluated_id(depsgraph, &obedit->id);
- BMEditMesh *em_eval = BKE_editmesh_from_object(obedit_eval);
- return editbmesh_get_eval_cage(depsgraph, scene_eval, obedit_eval, em_eval, dataMask);
+ BLI_assert((obedit->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0);
+ Scene *scene_eval = (Scene *)DEG_get_evaluated_id(depsgraph, &scene->id);
+ Object *obedit_eval = (Object *)DEG_get_evaluated_id(depsgraph, &obedit->id);
+ BMEditMesh *em_eval = BKE_editmesh_from_object(obedit_eval);
+ return editbmesh_get_eval_cage(depsgraph, scene_eval, obedit_eval, em_eval, dataMask);
}
/***/
/* same as above but for vert coords */
typedef struct {
- float (*vertexcos)[3];
- BLI_bitmap *vertex_visit;
+ float (*vertexcos)[3];
+ BLI_bitmap *vertex_visit;
} MappedUserData;
-static void make_vertexcos__mapFunc(
- void *userData, int index, const float co[3],
- const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
+static void make_vertexcos__mapFunc(void *userData,
+ int index,
+ const float co[3],
+ const float UNUSED(no_f[3]),
+ const short UNUSED(no_s[3]))
{
- MappedUserData *mappedData = (MappedUserData *)userData;
+ MappedUserData *mappedData = (MappedUserData *)userData;
- if (BLI_BITMAP_TEST(mappedData->vertex_visit, index) == 0) {
- /* we need coord from prototype vertex, not from copies,
- * assume they stored in the beginning of vertex array stored in DM
- * (mirror modifier for eg does this) */
- copy_v3_v3(mappedData->vertexcos[index], co);
- BLI_BITMAP_ENABLE(mappedData->vertex_visit, index);
- }
+ if (BLI_BITMAP_TEST(mappedData->vertex_visit, index) == 0) {
+ /* we need coord from prototype vertex, not from copies,
+ * assume they stored in the beginning of vertex array stored in DM
+ * (mirror modifier for eg does this) */
+ copy_v3_v3(mappedData->vertexcos[index], co);
+ BLI_BITMAP_ENABLE(mappedData->vertex_visit, index);
+ }
}
void mesh_get_mapped_verts_coords(Mesh *me_eval, float (*r_cos)[3], const int totcos)
{
- if (me_eval->runtime.deformed_only == false) {
- MappedUserData userData;
- memset(r_cos, 0, sizeof(*r_cos) * totcos);
- userData.vertexcos = r_cos;
- userData.vertex_visit = BLI_BITMAP_NEW(totcos, "vertexcos flags");
- BKE_mesh_foreach_mapped_vert(me_eval, make_vertexcos__mapFunc, &userData, MESH_FOREACH_NOP);
- MEM_freeN(userData.vertex_visit);
- }
- else {
- MVert *mv = me_eval->mvert;
- for (int i = 0; i < totcos; i++, mv++) {
- copy_v3_v3(r_cos[i], mv->co);
- }
- }
-}
-
-void DM_calc_loop_tangents(
- DerivedMesh *dm, bool calc_active_tangent,
- const char (*tangent_names)[MAX_NAME], int tangent_names_len)
-{
- BKE_mesh_calc_loop_tangent_ex(
- dm->getVertArray(dm),
- dm->getPolyArray(dm), dm->getNumPolys(dm),
- dm->getLoopArray(dm),
- dm->getLoopTriArray(dm), dm->getNumLoopTri(dm),
- &dm->loopData,
- calc_active_tangent,
- tangent_names, tangent_names_len,
- CustomData_get_layer(&dm->polyData, CD_NORMAL),
- dm->getLoopDataArray(dm, CD_NORMAL),
- dm->getVertDataArray(dm, CD_ORCO), /* may be NULL */
- /* result */
- &dm->loopData, dm->getNumLoops(dm),
- &dm->tangent_mask);
+ if (me_eval->runtime.deformed_only == false) {
+ MappedUserData userData;
+ memset(r_cos, 0, sizeof(*r_cos) * totcos);
+ userData.vertexcos = r_cos;
+ userData.vertex_visit = BLI_BITMAP_NEW(totcos, "vertexcos flags");
+ BKE_mesh_foreach_mapped_vert(me_eval, make_vertexcos__mapFunc, &userData, MESH_FOREACH_NOP);
+ MEM_freeN(userData.vertex_visit);
+ }
+ else {
+ MVert *mv = me_eval->mvert;
+ for (int i = 0; i < totcos; i++, mv++) {
+ copy_v3_v3(r_cos[i], mv->co);
+ }
+ }
+}
+
+void DM_calc_loop_tangents(DerivedMesh *dm,
+ bool calc_active_tangent,
+ const char (*tangent_names)[MAX_NAME],
+ int tangent_names_len)
+{
+ BKE_mesh_calc_loop_tangent_ex(dm->getVertArray(dm),
+ dm->getPolyArray(dm),
+ dm->getNumPolys(dm),
+ dm->getLoopArray(dm),
+ dm->getLoopTriArray(dm),
+ dm->getNumLoopTri(dm),
+ &dm->loopData,
+ calc_active_tangent,
+ tangent_names,
+ tangent_names_len,
+ CustomData_get_layer(&dm->polyData, CD_NORMAL),
+ dm->getLoopDataArray(dm, CD_NORMAL),
+ dm->getVertDataArray(dm, CD_ORCO), /* may be NULL */
+ /* result */
+ &dm->loopData,
+ dm->getNumLoops(dm),
+ &dm->tangent_mask);
}
static void mesh_init_origspace(Mesh *mesh)
{
- const float default_osf[4][2] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
-
- OrigSpaceLoop *lof_array = CustomData_get_layer(&mesh->ldata, CD_ORIGSPACE_MLOOP);
- const int numpoly = mesh->totpoly;
- // const int numloop = mesh->totloop;
- MVert *mv = mesh->mvert;
- MLoop *ml = mesh->mloop;
- MPoly *mp = mesh->mpoly;
- int i, j, k;
-
- float (*vcos_2d)[2] = NULL;
- BLI_array_staticdeclare(vcos_2d, 64);
-
- for (i = 0; i < numpoly; i++, mp++) {
- OrigSpaceLoop *lof = lof_array + mp->loopstart;
-
- if (mp->totloop == 3 || mp->totloop == 4) {
- for (j = 0; j < mp->totloop; j++, lof++) {
- copy_v2_v2(lof->uv, default_osf[j]);
- }
- }
- else {
- MLoop *l = &ml[mp->loopstart];
- float p_nor[3], co[3];
- float mat[3][3];
-
- float min[2] = {FLT_MAX, FLT_MAX}, max[2] = {-FLT_MAX, -FLT_MAX};
- float translate[2], scale[2];
-
- BKE_mesh_calc_poly_normal(mp, l, mv, p_nor);
- axis_dominant_v3_to_m3(mat, p_nor);
-
- BLI_array_clear(vcos_2d);
- BLI_array_reserve(vcos_2d, mp->totloop);
- for (j = 0; j < mp->totloop; j++, l++) {
- mul_v3_m3v3(co, mat, mv[l->v].co);
- copy_v2_v2(vcos_2d[j], co);
-
- for (k = 0; k < 2; k++) {
- if (co[k] > max[k])
- max[k] = co[k];
- else if (co[k] < min[k])
- min[k] = co[k];
- }
- }
-
- /* Brings min to (0, 0). */
- negate_v2_v2(translate, min);
-
- /* Scale will bring max to (1, 1). */
- sub_v2_v2v2(scale, max, min);
- if (scale[0] == 0.0f)
- scale[0] = 1e-9f;
- if (scale[1] == 0.0f)
- scale[1] = 1e-9f;
- invert_v2(scale);
-
- /* Finally, transform all vcos_2d into ((0, 0), (1, 1)) square and assign them as origspace. */
- for (j = 0; j < mp->totloop; j++, lof++) {
- add_v2_v2v2(lof->uv, vcos_2d[j], translate);
- mul_v2_v2(lof->uv, scale);
- }
- }
- }
-
- BKE_mesh_tessface_clear(mesh);
- BLI_array_free(vcos_2d);
+ const float default_osf[4][2] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
+
+ OrigSpaceLoop *lof_array = CustomData_get_layer(&mesh->ldata, CD_ORIGSPACE_MLOOP);
+ const int numpoly = mesh->totpoly;
+ // const int numloop = mesh->totloop;
+ MVert *mv = mesh->mvert;
+ MLoop *ml = mesh->mloop;
+ MPoly *mp = mesh->mpoly;
+ int i, j, k;
+
+ float(*vcos_2d)[2] = NULL;
+ BLI_array_staticdeclare(vcos_2d, 64);
+
+ for (i = 0; i < numpoly; i++, mp++) {
+ OrigSpaceLoop *lof = lof_array + mp->loopstart;
+
+ if (mp->totloop == 3 || mp->totloop == 4) {
+ for (j = 0; j < mp->totloop; j++, lof++) {
+ copy_v2_v2(lof->uv, default_osf[j]);
+ }
+ }
+ else {
+ MLoop *l = &ml[mp->loopstart];
+ float p_nor[3], co[3];
+ float mat[3][3];
+
+ float min[2] = {FLT_MAX, FLT_MAX}, max[2] = {-FLT_MAX, -FLT_MAX};
+ float translate[2], scale[2];
+
+ BKE_mesh_calc_poly_normal(mp, l, mv, p_nor);
+ axis_dominant_v3_to_m3(mat, p_nor);
+
+ BLI_array_clear(vcos_2d);
+ BLI_array_reserve(vcos_2d, mp->totloop);
+ for (j = 0; j < mp->totloop; j++, l++) {
+ mul_v3_m3v3(co, mat, mv[l->v].co);
+ copy_v2_v2(vcos_2d[j], co);
+
+ for (k = 0; k < 2; k++) {
+ if (co[k] > max[k])
+ max[k] = co[k];
+ else if (co[k] < min[k])
+ min[k] = co[k];
+ }
+ }
+
+ /* Brings min to (0, 0). */
+ negate_v2_v2(translate, min);
+
+ /* Scale will bring max to (1, 1). */
+ sub_v2_v2v2(scale, max, min);
+ if (scale[0] == 0.0f)
+ scale[0] = 1e-9f;
+ if (scale[1] == 0.0f)
+ scale[1] = 1e-9f;
+ invert_v2(scale);
+
+ /* Finally, transform all vcos_2d into ((0, 0), (1, 1)) square and assign them as origspace. */
+ for (j = 0; j < mp->totloop; j++, lof++) {
+ add_v2_v2v2(lof->uv, vcos_2d[j], translate);
+ mul_v2_v2(lof->uv, scale);
+ }
+ }
+ }
+
+ BKE_mesh_tessface_clear(mesh);
+ BLI_array_free(vcos_2d);
}
-
/* derivedmesh info printing function,
* to help track down differences DM output */
#ifndef NDEBUG
-#include "BLI_dynstr.h"
-
-static void dm_debug_info_layers(
- DynStr *dynstr, DerivedMesh *dm, CustomData *cd,
- void *(*getElemDataArray)(DerivedMesh *, int))
-{
- int type;
-
- for (type = 0; type < CD_NUMTYPES; type++) {
- if (CustomData_has_layer(cd, type)) {
- /* note: doesn't account for multiple layers */
- const char *name = CustomData_layertype_name(type);
- const int size = CustomData_sizeof(type);
- const void *pt = getElemDataArray(dm, type);
- const int pt_size = pt ? (int)(MEM_allocN_len(pt) / size) : 0;
- const char *structname;
- int structnum;
- CustomData_file_write_info(type, &structname, &structnum);
- BLI_dynstr_appendf(dynstr,
- " dict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n",
- name, structname, type, (const void *)pt, size, pt_size);
- }
- }
+# include "BLI_dynstr.h"
+
+static void dm_debug_info_layers(DynStr *dynstr,
+ DerivedMesh *dm,
+ CustomData *cd,
+ void *(*getElemDataArray)(DerivedMesh *, int))
+{
+ int type;
+
+ for (type = 0; type < CD_NUMTYPES; type++) {
+ if (CustomData_has_layer(cd, type)) {
+ /* note: doesn't account for multiple layers */
+ const char *name = CustomData_layertype_name(type);
+ const int size = CustomData_sizeof(type);
+ const void *pt = getElemDataArray(dm, type);
+ const int pt_size = pt ? (int)(MEM_allocN_len(pt) / size) : 0;
+ const char *structname;
+ int structnum;
+ CustomData_file_write_info(type, &structname, &structnum);
+ BLI_dynstr_appendf(
+ dynstr,
+ " dict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n",
+ name,
+ structname,
+ type,
+ (const void *)pt,
+ size,
+ pt_size);
+ }
+ }
}
char *DM_debug_info(DerivedMesh *dm)
{
- DynStr *dynstr = BLI_dynstr_new();
- char *ret;
- const char *tstr;
-
- BLI_dynstr_append(dynstr, "{\n");
- BLI_dynstr_appendf(dynstr, " 'ptr': '%p',\n", (void *)dm);
- switch (dm->type) {
- case DM_TYPE_CDDM: tstr = "DM_TYPE_CDDM"; break;
- case DM_TYPE_CCGDM: tstr = "DM_TYPE_CCGDM"; break;
- default: tstr = "UNKNOWN"; break;
- }
- BLI_dynstr_appendf(dynstr, " 'type': '%s',\n", tstr);
- BLI_dynstr_appendf(dynstr, " 'numVertData': %d,\n", dm->numVertData);
- BLI_dynstr_appendf(dynstr, " 'numEdgeData': %d,\n", dm->numEdgeData);
- BLI_dynstr_appendf(dynstr, " 'numTessFaceData': %d,\n", dm->numTessFaceData);
- BLI_dynstr_appendf(dynstr, " 'numPolyData': %d,\n", dm->numPolyData);
- BLI_dynstr_appendf(dynstr, " 'deformedOnly': %d,\n", dm->deformedOnly);
-
- BLI_dynstr_append(dynstr, " 'vertexLayers': (\n");
- dm_debug_info_layers(dynstr, dm, &dm->vertData, dm->getVertDataArray);
- BLI_dynstr_append(dynstr, " ),\n");
-
- BLI_dynstr_append(dynstr, " 'edgeLayers': (\n");
- dm_debug_info_layers(dynstr, dm, &dm->edgeData, dm->getEdgeDataArray);
- BLI_dynstr_append(dynstr, " ),\n");
-
- BLI_dynstr_append(dynstr, " 'loopLayers': (\n");
- dm_debug_info_layers(dynstr, dm, &dm->loopData, dm->getLoopDataArray);
- BLI_dynstr_append(dynstr, " ),\n");
-
- BLI_dynstr_append(dynstr, " 'polyLayers': (\n");
- dm_debug_info_layers(dynstr, dm, &dm->polyData, dm->getPolyDataArray);
- BLI_dynstr_append(dynstr, " ),\n");
-
- BLI_dynstr_append(dynstr, " 'tessFaceLayers': (\n");
- dm_debug_info_layers(dynstr, dm, &dm->faceData, dm->getTessFaceDataArray);
- BLI_dynstr_append(dynstr, " ),\n");
-
- BLI_dynstr_append(dynstr, "}\n");
-
- ret = BLI_dynstr_get_cstring(dynstr);
- BLI_dynstr_free(dynstr);
- return ret;
+ DynStr *dynstr = BLI_dynstr_new();
+ char *ret;
+ const char *tstr;
+
+ BLI_dynstr_append(dynstr, "{\n");
+ BLI_dynstr_appendf(dynstr, " 'ptr': '%p',\n", (void *)dm);
+ switch (dm->type) {
+ case DM_TYPE_CDDM:
+ tstr = "DM_TYPE_CDDM";
+ break;
+ case DM_TYPE_CCGDM:
+ tstr = "DM_TYPE_CCGDM";
+ break;
+ default:
+ tstr = "UNKNOWN";
+ break;
+ }
+ BLI_dynstr_appendf(dynstr, " 'type': '%s',\n", tstr);
+ BLI_dynstr_appendf(dynstr, " 'numVertData': %d,\n", dm->numVertData);
+ BLI_dynstr_appendf(dynstr, " 'numEdgeData': %d,\n", dm->numEdgeData);
+ BLI_dynstr_appendf(dynstr, " 'numTessFaceData': %d,\n", dm->numTessFaceData);
+ BLI_dynstr_appendf(dynstr, " 'numPolyData': %d,\n", dm->numPolyData);
+ BLI_dynstr_appendf(dynstr, " 'deformedOnly': %d,\n", dm->deformedOnly);
+
+ BLI_dynstr_append(dynstr, " 'vertexLayers': (\n");
+ dm_debug_info_layers(dynstr, dm, &dm->vertData, dm->getVertDataArray);
+ BLI_dynstr_append(dynstr, " ),\n");
+
+ BLI_dynstr_append(dynstr, " 'edgeLayers': (\n");
+ dm_debug_info_layers(dynstr, dm, &dm->edgeData, dm->getEdgeDataArray);
+ BLI_dynstr_append(dynstr, " ),\n");
+
+ BLI_dynstr_append(dynstr, " 'loopLayers': (\n");
+ dm_debug_info_layers(dynstr, dm, &dm->loopData, dm->getLoopDataArray);
+ BLI_dynstr_append(dynstr, " ),\n");
+
+ BLI_dynstr_append(dynstr, " 'polyLayers': (\n");
+ dm_debug_info_layers(dynstr, dm, &dm->polyData, dm->getPolyDataArray);
+ BLI_dynstr_append(dynstr, " ),\n");
+
+ BLI_dynstr_append(dynstr, " 'tessFaceLayers': (\n");
+ dm_debug_info_layers(dynstr, dm, &dm->faceData, dm->getTessFaceDataArray);
+ BLI_dynstr_append(dynstr, " ),\n");
+
+ BLI_dynstr_append(dynstr, "}\n");
+
+ ret = BLI_dynstr_get_cstring(dynstr);
+ BLI_dynstr_free(dynstr);
+ return ret;
}
void DM_debug_print(DerivedMesh *dm)
{
- char *str = DM_debug_info(dm);
- puts(str);
- fflush(stdout);
- MEM_freeN(str);
+ char *str = DM_debug_info(dm);
+ puts(str);
+ fflush(stdout);
+ MEM_freeN(str);
}
void DM_debug_print_cdlayers(CustomData *data)
{
- int i;
- const CustomDataLayer *layer;
+ int i;
+ const CustomDataLayer *layer;
- printf("{\n");
+ printf("{\n");
- for (i = 0, layer = data->layers; i < data->totlayer; i++, layer++) {
+ for (i = 0, layer = data->layers; i < data->totlayer; i++, layer++) {
- const char *name = CustomData_layertype_name(layer->type);
- const int size = CustomData_sizeof(layer->type);
- const char *structname;
- int structnum;
- CustomData_file_write_info(layer->type, &structname, &structnum);
- printf(" dict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n",
- name, structname, layer->type, (const void *)layer->data, size, (int)(MEM_allocN_len(layer->data) / size));
- }
+ const char *name = CustomData_layertype_name(layer->type);
+ const int size = CustomData_sizeof(layer->type);
+ const char *structname;
+ int structnum;
+ CustomData_file_write_info(layer->type, &structname, &structnum);
+ printf(" dict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n",
+ name,
+ structname,
+ layer->type,
+ (const void *)layer->data,
+ size,
+ (int)(MEM_allocN_len(layer->data) / size));
+ }
- printf("}\n");
+ printf("}\n");
}
bool DM_is_valid(DerivedMesh *dm)
{
- const bool do_verbose = true;
- const bool do_fixes = false;
-
- bool is_valid = true;
- bool changed = true;
-
- is_valid &= BKE_mesh_validate_all_customdata(
- dm->getVertDataLayout(dm), dm->getNumVerts(dm),
- dm->getEdgeDataLayout(dm), dm->getNumEdges(dm),
- dm->getLoopDataLayout(dm), dm->getNumLoops(dm),
- dm->getPolyDataLayout(dm), dm->getNumPolys(dm),
- false, /* setting mask here isn't useful, gives false positives */
- do_verbose, do_fixes, &changed);
-
- is_valid &= BKE_mesh_validate_arrays(
- NULL,
- dm->getVertArray(dm), dm->getNumVerts(dm),
- dm->getEdgeArray(dm), dm->getNumEdges(dm),
- dm->getTessFaceArray(dm), dm->getNumTessFaces(dm),
- dm->getLoopArray(dm), dm->getNumLoops(dm),
- dm->getPolyArray(dm), dm->getNumPolys(dm),
- dm->getVertDataArray(dm, CD_MDEFORMVERT),
- do_verbose, do_fixes, &changed);
-
- BLI_assert(changed == false);
-
- return is_valid;
+ const bool do_verbose = true;
+ const bool do_fixes = false;
+
+ bool is_valid = true;
+ bool changed = true;
+
+ is_valid &= BKE_mesh_validate_all_customdata(
+ dm->getVertDataLayout(dm),
+ dm->getNumVerts(dm),
+ dm->getEdgeDataLayout(dm),
+ dm->getNumEdges(dm),
+ dm->getLoopDataLayout(dm),
+ dm->getNumLoops(dm),
+ dm->getPolyDataLayout(dm),
+ dm->getNumPolys(dm),
+ false, /* setting mask here isn't useful, gives false positives */
+ do_verbose,
+ do_fixes,
+ &changed);
+
+ is_valid &= BKE_mesh_validate_arrays(NULL,
+ dm->getVertArray(dm),
+ dm->getNumVerts(dm),
+ dm->getEdgeArray(dm),
+ dm->getNumEdges(dm),
+ dm->getTessFaceArray(dm),
+ dm->getNumTessFaces(dm),
+ dm->getLoopArray(dm),
+ dm->getNumLoops(dm),
+ dm->getPolyArray(dm),
+ dm->getNumPolys(dm),
+ dm->getVertDataArray(dm, CD_MDEFORMVERT),
+ do_verbose,
+ do_fixes,
+ &changed);
+
+ BLI_assert(changed == false);
+
+ return is_valid;
}
#endif /* NDEBUG */
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index da4fea26e64..a3b7df6b020 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -21,7 +21,6 @@
* \ingroup bke
*/
-
#include <string.h>
#include <math.h>
#include <stdlib.h>
@@ -81,11 +80,11 @@ static CLG_LogRef LOG = {"bke.action"};
bAction *BKE_action_add(Main *bmain, const char name[])
{
- bAction *act;
+ bAction *act;
- act = BKE_libblock_alloc(bmain, ID_AC, name, 0);
+ act = BKE_libblock_alloc(bmain, ID_AC, name, 0);
- return act;
+ return act;
}
/* .................................. */
@@ -93,7 +92,7 @@ bAction *BKE_action_add(Main *bmain, const char name[])
// does copy_fcurve...
void BKE_action_make_local(Main *bmain, bAction *act, const bool lib_local)
{
- BKE_id_make_local_generic(bmain, &act->id, true, lib_local);
+ BKE_id_make_local_generic(bmain, &act->id, true, lib_local);
}
/* .................................. */
@@ -101,16 +100,16 @@ void BKE_action_make_local(Main *bmain, bAction *act, const bool lib_local)
/** Free (or release) any data used by this action (does not free the action itself). */
void BKE_action_free(bAction *act)
{
- /* No animdata here. */
+ /* No animdata here. */
- /* Free F-Curves */
- free_fcurves(&act->curves);
+ /* Free F-Curves */
+ free_fcurves(&act->curves);
- /* Free groups */
- BLI_freelistN(&act->groups);
+ /* Free groups */
+ BLI_freelistN(&act->groups);
- /* Free pose-references (aka local markers) */
- BLI_freelistN(&act->markers);
+ /* Free pose-references (aka local markers) */
+ BLI_freelistN(&act->markers);
}
/* .................................. */
@@ -123,48 +122,50 @@ void BKE_action_free(bAction *act)
*
* \param flag: Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
*/
-void BKE_action_copy_data(Main *UNUSED(bmain), bAction *act_dst, const bAction *act_src, const int UNUSED(flag))
+void BKE_action_copy_data(Main *UNUSED(bmain),
+ bAction *act_dst,
+ const bAction *act_src,
+ const int UNUSED(flag))
{
- bActionGroup *grp_dst, *grp_src;
- FCurve *fcu_dst, *fcu_src;
-
- /* duplicate the lists of groups and markers */
- BLI_duplicatelist(&act_dst->groups, &act_src->groups);
- BLI_duplicatelist(&act_dst->markers, &act_src->markers);
-
- /* copy F-Curves, fixing up the links as we go */
- BLI_listbase_clear(&act_dst->curves);
-
- for (fcu_src = act_src->curves.first; fcu_src; fcu_src = fcu_src->next) {
- /* duplicate F-Curve */
- fcu_dst = copy_fcurve(fcu_src); /* XXX TODO pass subdata flag? But surprisingly does not seem to be doing any ID refcounting... */
- BLI_addtail(&act_dst->curves, fcu_dst);
-
- /* fix group links (kindof bad list-in-list search, but this is the most reliable way) */
- for (grp_dst = act_dst->groups.first, grp_src = act_src->groups.first;
- grp_dst && grp_src;
- grp_dst = grp_dst->next, grp_src = grp_src->next)
- {
- if (fcu_src->grp == grp_src) {
- fcu_dst->grp = grp_dst;
-
- if (grp_dst->channels.first == fcu_src) {
- grp_dst->channels.first = fcu_dst;
- }
- if (grp_dst->channels.last == fcu_src) {
- grp_dst->channels.last = fcu_dst;
- }
- break;
- }
- }
- }
+ bActionGroup *grp_dst, *grp_src;
+ FCurve *fcu_dst, *fcu_src;
+
+ /* duplicate the lists of groups and markers */
+ BLI_duplicatelist(&act_dst->groups, &act_src->groups);
+ BLI_duplicatelist(&act_dst->markers, &act_src->markers);
+
+ /* copy F-Curves, fixing up the links as we go */
+ BLI_listbase_clear(&act_dst->curves);
+
+ for (fcu_src = act_src->curves.first; fcu_src; fcu_src = fcu_src->next) {
+ /* duplicate F-Curve */
+ fcu_dst = copy_fcurve(
+ fcu_src); /* XXX TODO pass subdata flag? But surprisingly does not seem to be doing any ID refcounting... */
+ BLI_addtail(&act_dst->curves, fcu_dst);
+
+ /* fix group links (kindof bad list-in-list search, but this is the most reliable way) */
+ for (grp_dst = act_dst->groups.first, grp_src = act_src->groups.first; grp_dst && grp_src;
+ grp_dst = grp_dst->next, grp_src = grp_src->next) {
+ if (fcu_src->grp == grp_src) {
+ fcu_dst->grp = grp_dst;
+
+ if (grp_dst->channels.first == fcu_src) {
+ grp_dst->channels.first = fcu_dst;
+ }
+ if (grp_dst->channels.last == fcu_src) {
+ grp_dst->channels.last = fcu_dst;
+ }
+ break;
+ }
+ }
+ }
}
bAction *BKE_action_copy(Main *bmain, const bAction *act_src)
{
- bAction *act_copy;
- BKE_id_copy(bmain, &act_src->id, (ID **)&act_copy);
- return act_copy;
+ bAction *act_copy;
+ BKE_id_copy(bmain, &act_src->id, (ID **)&act_copy);
+ return act_copy;
}
/* *************** Action Groups *************** */
@@ -172,89 +173,90 @@ bAction *BKE_action_copy(Main *bmain, const bAction *act_src)
/* Get the active action-group for an Action */
bActionGroup *get_active_actiongroup(bAction *act)
{
- bActionGroup *agrp = NULL;
+ bActionGroup *agrp = NULL;
- if (act && act->groups.first) {
- for (agrp = act->groups.first; agrp; agrp = agrp->next) {
- if (agrp->flag & AGRP_ACTIVE)
- break;
- }
- }
+ if (act && act->groups.first) {
+ for (agrp = act->groups.first; agrp; agrp = agrp->next) {
+ if (agrp->flag & AGRP_ACTIVE)
+ break;
+ }
+ }
- return agrp;
+ return agrp;
}
/* Make the given Action-Group the active one */
void set_active_action_group(bAction *act, bActionGroup *agrp, short select)
{
- bActionGroup *grp;
-
- /* sanity checks */
- if (act == NULL)
- return;
-
- /* Deactivate all others */
- for (grp = act->groups.first; grp; grp = grp->next) {
- if ((grp == agrp) && (select))
- grp->flag |= AGRP_ACTIVE;
- else
- grp->flag &= ~AGRP_ACTIVE;
- }
+ bActionGroup *grp;
+
+ /* sanity checks */
+ if (act == NULL)
+ return;
+
+ /* Deactivate all others */
+ for (grp = act->groups.first; grp; grp = grp->next) {
+ if ((grp == agrp) && (select))
+ grp->flag |= AGRP_ACTIVE;
+ else
+ grp->flag &= ~AGRP_ACTIVE;
+ }
}
/* Sync colors used for action/bone group with theme settings */
void action_group_colors_sync(bActionGroup *grp, const bActionGroup *ref_grp)
{
- /* only do color copying if using a custom color (i.e. not default color) */
- if (grp->customCol) {
- if (grp->customCol > 0) {
- /* copy theme colors on-to group's custom color in case user tries to edit color */
- bTheme *btheme = U.themes.first;
- ThemeWireColor *col_set = &btheme->tarm[(grp->customCol - 1)];
-
- memcpy(&grp->cs, col_set, sizeof(ThemeWireColor));
- }
- else {
- /* if a reference group is provided, use the custom color from there... */
- if (ref_grp) {
- /* assumption: reference group has a color set */
- memcpy(&grp->cs, &ref_grp->cs, sizeof(ThemeWireColor));
- }
- /* otherwise, init custom color with a generic/placeholder color set if
- * no previous theme color was used that we can just keep using
- */
- else if (grp->cs.solid[0] == 0) {
- /* define for setting colors in theme below */
- rgba_char_args_set(grp->cs.solid, 0xff, 0x00, 0x00, 255);
- rgba_char_args_set(grp->cs.select, 0x81, 0xe6, 0x14, 255);
- rgba_char_args_set(grp->cs.active, 0x18, 0xb6, 0xe0, 255);
- }
- }
- }
+ /* only do color copying if using a custom color (i.e. not default color) */
+ if (grp->customCol) {
+ if (grp->customCol > 0) {
+ /* copy theme colors on-to group's custom color in case user tries to edit color */
+ bTheme *btheme = U.themes.first;
+ ThemeWireColor *col_set = &btheme->tarm[(grp->customCol - 1)];
+
+ memcpy(&grp->cs, col_set, sizeof(ThemeWireColor));
+ }
+ else {
+ /* if a reference group is provided, use the custom color from there... */
+ if (ref_grp) {
+ /* assumption: reference group has a color set */
+ memcpy(&grp->cs, &ref_grp->cs, sizeof(ThemeWireColor));
+ }
+ /* otherwise, init custom color with a generic/placeholder color set if
+ * no previous theme color was used that we can just keep using
+ */
+ else if (grp->cs.solid[0] == 0) {
+ /* define for setting colors in theme below */
+ rgba_char_args_set(grp->cs.solid, 0xff, 0x00, 0x00, 255);
+ rgba_char_args_set(grp->cs.select, 0x81, 0xe6, 0x14, 255);
+ rgba_char_args_set(grp->cs.active, 0x18, 0xb6, 0xe0, 255);
+ }
+ }
+ }
}
/* Add a new action group with the given name to the action */
bActionGroup *action_groups_add_new(bAction *act, const char name[])
{
- bActionGroup *agrp;
+ bActionGroup *agrp;
- /* sanity check: must have action and name */
- if (ELEM(NULL, act, name))
- return NULL;
+ /* sanity check: must have action and name */
+ if (ELEM(NULL, act, name))
+ return NULL;
- /* allocate a new one */
- agrp = MEM_callocN(sizeof(bActionGroup), "bActionGroup");
+ /* allocate a new one */
+ agrp = MEM_callocN(sizeof(bActionGroup), "bActionGroup");
- /* make it selected, with default name */
- agrp->flag = AGRP_SELECTED;
- BLI_strncpy(agrp->name, name[0] ? name : DATA_("Group"), sizeof(agrp->name));
+ /* make it selected, with default name */
+ agrp->flag = AGRP_SELECTED;
+ BLI_strncpy(agrp->name, name[0] ? name : DATA_("Group"), sizeof(agrp->name));
- /* add to action, and validate */
- BLI_addtail(&act->groups, agrp);
- BLI_uniquename(&act->groups, agrp, DATA_("Group"), '.', offsetof(bActionGroup, name), sizeof(agrp->name));
+ /* add to action, and validate */
+ BLI_addtail(&act->groups, agrp);
+ BLI_uniquename(
+ &act->groups, agrp, DATA_("Group"), '.', offsetof(bActionGroup, name), sizeof(agrp->name));
- /* return the new group */
- return agrp;
+ /* return the new group */
+ return agrp;
}
/* Add given channel into (active) group
@@ -263,128 +265,128 @@ bActionGroup *action_groups_add_new(bAction *act, const char name[])
*/
void action_groups_add_channel(bAction *act, bActionGroup *agrp, FCurve *fcurve)
{
- /* sanity checks */
- if (ELEM(NULL, act, agrp, fcurve))
- return;
-
- /* if no channels anywhere, just add to two lists at the same time */
- if (BLI_listbase_is_empty(&act->curves)) {
- fcurve->next = fcurve->prev = NULL;
-
- agrp->channels.first = agrp->channels.last = fcurve;
- act->curves.first = act->curves.last = fcurve;
- }
-
- /* if the group already has channels, the F-Curve can simply be added to the list
- * (i.e. as the last channel in the group)
- */
- else if (agrp->channels.first) {
- /* if the group's last F-Curve is the action's last F-Curve too,
- * then set the F-Curve as the last for the action first so that
- * the lists will be in sync after linking
- */
- if (agrp->channels.last == act->curves.last)
- act->curves.last = fcurve;
-
- /* link in the given F-Curve after the last F-Curve in the group,
- * which means that it should be able to fit in with the rest of the
- * list seamlessly
- */
- BLI_insertlinkafter(&agrp->channels, agrp->channels.last, fcurve);
- }
-
- /* otherwise, need to find the nearest F-Curve in group before/after current to link with */
- else {
- bActionGroup *grp;
-
- /* firstly, link this F-Curve to the group */
- agrp->channels.first = agrp->channels.last = fcurve;
-
- /* step through the groups preceding this one, finding the F-Curve there to attach this one after */
- for (grp = agrp->prev; grp; grp = grp->prev) {
- /* if this group has F-Curves, we want weave the given one in right after the last channel there,
- * but via the Action's list not this group's list
- * - this is so that the F-Curve is in the right place in the Action,
- * but won't be included in the previous group
- */
- if (grp->channels.last) {
- /* once we've added, break here since we don't need to search any further... */
- BLI_insertlinkafter(&act->curves, grp->channels.last, fcurve);
- break;
- }
- }
-
- /* if grp is NULL, that means we fell through, and this F-Curve should be added as the new first
- * since group is (effectively) the first group. Thus, the existing first F-Curve becomes the
- * second in the chain, etc. etc.
- */
- if (grp == NULL)
- BLI_insertlinkbefore(&act->curves, act->curves.first, fcurve);
- }
-
- /* set the F-Curve's new group */
- fcurve->grp = agrp;
+ /* sanity checks */
+ if (ELEM(NULL, act, agrp, fcurve))
+ return;
+
+ /* if no channels anywhere, just add to two lists at the same time */
+ if (BLI_listbase_is_empty(&act->curves)) {
+ fcurve->next = fcurve->prev = NULL;
+
+ agrp->channels.first = agrp->channels.last = fcurve;
+ act->curves.first = act->curves.last = fcurve;
+ }
+
+ /* if the group already has channels, the F-Curve can simply be added to the list
+ * (i.e. as the last channel in the group)
+ */
+ else if (agrp->channels.first) {
+ /* if the group's last F-Curve is the action's last F-Curve too,
+ * then set the F-Curve as the last for the action first so that
+ * the lists will be in sync after linking
+ */
+ if (agrp->channels.last == act->curves.last)
+ act->curves.last = fcurve;
+
+ /* link in the given F-Curve after the last F-Curve in the group,
+ * which means that it should be able to fit in with the rest of the
+ * list seamlessly
+ */
+ BLI_insertlinkafter(&agrp->channels, agrp->channels.last, fcurve);
+ }
+
+ /* otherwise, need to find the nearest F-Curve in group before/after current to link with */
+ else {
+ bActionGroup *grp;
+
+ /* firstly, link this F-Curve to the group */
+ agrp->channels.first = agrp->channels.last = fcurve;
+
+ /* step through the groups preceding this one, finding the F-Curve there to attach this one after */
+ for (grp = agrp->prev; grp; grp = grp->prev) {
+ /* if this group has F-Curves, we want weave the given one in right after the last channel there,
+ * but via the Action's list not this group's list
+ * - this is so that the F-Curve is in the right place in the Action,
+ * but won't be included in the previous group
+ */
+ if (grp->channels.last) {
+ /* once we've added, break here since we don't need to search any further... */
+ BLI_insertlinkafter(&act->curves, grp->channels.last, fcurve);
+ break;
+ }
+ }
+
+ /* if grp is NULL, that means we fell through, and this F-Curve should be added as the new first
+ * since group is (effectively) the first group. Thus, the existing first F-Curve becomes the
+ * second in the chain, etc. etc.
+ */
+ if (grp == NULL)
+ BLI_insertlinkbefore(&act->curves, act->curves.first, fcurve);
+ }
+
+ /* set the F-Curve's new group */
+ fcurve->grp = agrp;
}
/* Remove the given channel from all groups */
void action_groups_remove_channel(bAction *act, FCurve *fcu)
{
- /* sanity checks */
- if (ELEM(NULL, act, fcu))
- return;
-
- /* check if any group used this directly */
- if (fcu->grp) {
- bActionGroup *agrp = fcu->grp;
-
- if (agrp->channels.first == agrp->channels.last) {
- if (agrp->channels.first == fcu) {
- BLI_listbase_clear(&agrp->channels);
- }
- }
- else if (agrp->channels.first == fcu) {
- if ((fcu->next) && (fcu->next->grp == agrp))
- agrp->channels.first = fcu->next;
- else
- agrp->channels.first = NULL;
- }
- else if (agrp->channels.last == fcu) {
- if ((fcu->prev) && (fcu->prev->grp == agrp))
- agrp->channels.last = fcu->prev;
- else
- agrp->channels.last = NULL;
- }
-
- fcu->grp = NULL;
- }
-
- /* now just remove from list */
- BLI_remlink(&act->curves, fcu);
+ /* sanity checks */
+ if (ELEM(NULL, act, fcu))
+ return;
+
+ /* check if any group used this directly */
+ if (fcu->grp) {
+ bActionGroup *agrp = fcu->grp;
+
+ if (agrp->channels.first == agrp->channels.last) {
+ if (agrp->channels.first == fcu) {
+ BLI_listbase_clear(&agrp->channels);
+ }
+ }
+ else if (agrp->channels.first == fcu) {
+ if ((fcu->next) && (fcu->next->grp == agrp))
+ agrp->channels.first = fcu->next;
+ else
+ agrp->channels.first = NULL;
+ }
+ else if (agrp->channels.last == fcu) {
+ if ((fcu->prev) && (fcu->prev->grp == agrp))
+ agrp->channels.last = fcu->prev;
+ else
+ agrp->channels.last = NULL;
+ }
+
+ fcu->grp = NULL;
+ }
+
+ /* now just remove from list */
+ BLI_remlink(&act->curves, fcu);
}
/* Find a group with the given name */
bActionGroup *BKE_action_group_find_name(bAction *act, const char name[])
{
- /* sanity checks */
- if (ELEM(NULL, act, act->groups.first, name) || (name[0] == 0))
- return NULL;
+ /* sanity checks */
+ if (ELEM(NULL, act, act->groups.first, name) || (name[0] == 0))
+ return NULL;
- /* do string comparisons */
- return BLI_findstring(&act->groups, name, offsetof(bActionGroup, name));
+ /* do string comparisons */
+ return BLI_findstring(&act->groups, name, offsetof(bActionGroup, name));
}
/* Clear all 'temp' flags on all groups */
void action_groups_clear_tempflags(bAction *act)
{
- bActionGroup *agrp;
+ bActionGroup *agrp;
- /* sanity checks */
- if (ELEM(NULL, act, act->groups.first))
- return;
+ /* sanity checks */
+ if (ELEM(NULL, act, act->groups.first))
+ return;
- /* flag clearing loop */
- for (agrp = act->groups.first; agrp; agrp = agrp->next)
- agrp->flag &= ~AGRP_TEMP;
+ /* flag clearing loop */
+ for (agrp = act->groups.first; agrp; agrp = agrp->next)
+ agrp->flag &= ~AGRP_TEMP;
}
/* *************** Pose channels *************** */
@@ -395,13 +397,13 @@ void action_groups_clear_tempflags(bAction *act)
*/
bPoseChannel *BKE_pose_channel_find_name(const bPose *pose, const char *name)
{
- if (ELEM(NULL, pose, name) || (name[0] == '\0'))
- return NULL;
+ if (ELEM(NULL, pose, name) || (name[0] == '\0'))
+ return NULL;
- if (pose->chanhash)
- return BLI_ghash_lookup(pose->chanhash, (const void *)name);
+ if (pose->chanhash)
+ return BLI_ghash_lookup(pose->chanhash, (const void *)name);
- return BLI_findstring(&((const bPose *)pose)->chanbase, name, offsetof(bPoseChannel, name));
+ return BLI_findstring(&((const bPose *)pose)->chanbase, name, offsetof(bPoseChannel, name));
}
/**
@@ -414,60 +416,60 @@ bPoseChannel *BKE_pose_channel_find_name(const bPose *pose, const char *name)
*/
bPoseChannel *BKE_pose_channel_verify(bPose *pose, const char *name)
{
- bPoseChannel *chan;
+ bPoseChannel *chan;
- if (pose == NULL)
- return NULL;
+ if (pose == NULL)
+ return NULL;
- /* See if this channel exists */
- chan = BKE_pose_channel_find_name(pose, name);
- if (chan) {
- return chan;
- }
+ /* See if this channel exists */
+ chan = BKE_pose_channel_find_name(pose, name);
+ if (chan) {
+ return chan;
+ }
- /* If not, create it and add it */
- chan = MEM_callocN(sizeof(bPoseChannel), "verifyPoseChannel");
+ /* If not, create it and add it */
+ chan = MEM_callocN(sizeof(bPoseChannel), "verifyPoseChannel");
- BLI_strncpy(chan->name, name, sizeof(chan->name));
+ BLI_strncpy(chan->name, name, sizeof(chan->name));
- chan->custom_scale = 1.0f;
+ chan->custom_scale = 1.0f;
- /* init vars to prevent math errors */
- unit_qt(chan->quat);
- unit_axis_angle(chan->rotAxis, &chan->rotAngle);
- chan->size[0] = chan->size[1] = chan->size[2] = 1.0f;
+ /* init vars to prevent math errors */
+ unit_qt(chan->quat);
+ unit_axis_angle(chan->rotAxis, &chan->rotAngle);
+ chan->size[0] = chan->size[1] = chan->size[2] = 1.0f;
- chan->scaleIn = chan->scaleOut = 1.0f;
+ chan->scaleIn = chan->scaleOut = 1.0f;
- chan->limitmin[0] = chan->limitmin[1] = chan->limitmin[2] = -M_PI;
- chan->limitmax[0] = chan->limitmax[1] = chan->limitmax[2] = M_PI;
- chan->stiffness[0] = chan->stiffness[1] = chan->stiffness[2] = 0.0f;
- chan->ikrotweight = chan->iklinweight = 0.0f;
- unit_m4(chan->constinv);
+ chan->limitmin[0] = chan->limitmin[1] = chan->limitmin[2] = -M_PI;
+ chan->limitmax[0] = chan->limitmax[1] = chan->limitmax[2] = M_PI;
+ chan->stiffness[0] = chan->stiffness[1] = chan->stiffness[2] = 0.0f;
+ chan->ikrotweight = chan->iklinweight = 0.0f;
+ unit_m4(chan->constinv);
- chan->protectflag = OB_LOCK_ROT4D; /* lock by components by default */
+ chan->protectflag = OB_LOCK_ROT4D; /* lock by components by default */
- BLI_addtail(&pose->chanbase, chan);
- if (pose->chanhash) {
- BLI_ghash_insert(pose->chanhash, chan->name, chan);
- }
+ BLI_addtail(&pose->chanbase, chan);
+ if (pose->chanhash) {
+ BLI_ghash_insert(pose->chanhash, chan->name, chan);
+ }
- return chan;
+ return chan;
}
#ifndef NDEBUG
bool BKE_pose_channels_is_valid(const bPose *pose)
{
- if (pose->chanhash) {
- bPoseChannel *pchan;
- for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- if (BLI_ghash_lookup(pose->chanhash, pchan->name) != pchan) {
- return false;
- }
- }
- }
-
- return true;
+ if (pose->chanhash) {
+ bPoseChannel *pchan;
+ for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (BLI_ghash_lookup(pose->chanhash, pchan->name) != pchan) {
+ return false;
+ }
+ }
+ }
+
+ return true;
}
#endif
@@ -479,20 +481,20 @@ bool BKE_pose_channels_is_valid(const bPose *pose)
*/
bPoseChannel *BKE_pose_channel_active(Object *ob)
{
- bArmature *arm = (ob) ? ob->data : NULL;
- bPoseChannel *pchan;
+ bArmature *arm = (ob) ? ob->data : NULL;
+ bPoseChannel *pchan;
- if (ELEM(NULL, ob, ob->pose, arm)) {
- return NULL;
- }
+ if (ELEM(NULL, ob, ob->pose, arm)) {
+ return NULL;
+ }
- /* find active */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if ((pchan->bone) && (pchan->bone == arm->act_bone) && (pchan->bone->layer & arm->layer))
- return pchan;
- }
+ /* find active */
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if ((pchan->bone) && (pchan->bone == arm->act_bone) && (pchan->bone->layer & arm->layer))
+ return pchan;
+ }
- return NULL;
+ return NULL;
}
/**
@@ -500,28 +502,28 @@ bPoseChannel *BKE_pose_channel_active(Object *ob)
*/
bPoseChannel *BKE_pose_channel_get_mirrored(const bPose *pose, const char *name)
{
- char name_flip[MAXBONENAME];
+ char name_flip[MAXBONENAME];
- BLI_string_flip_side_name(name_flip, name, false, sizeof(name_flip));
+ BLI_string_flip_side_name(name_flip, name, false, sizeof(name_flip));
- if (!STREQ(name_flip, name)) {
- return BKE_pose_channel_find_name(pose, name_flip);
- }
+ if (!STREQ(name_flip, name)) {
+ return BKE_pose_channel_find_name(pose, name_flip);
+ }
- return NULL;
+ return NULL;
}
const char *BKE_pose_ikparam_get_name(bPose *pose)
{
- if (pose) {
- switch (pose->iksolver) {
- case IKSOLVER_STANDARD:
- return NULL;
- case IKSOLVER_ITASC:
- return "bItasc";
- }
- }
- return NULL;
+ if (pose) {
+ switch (pose->iksolver) {
+ case IKSOLVER_STANDARD:
+ return NULL;
+ case IKSOLVER_ITASC:
+ return "bItasc";
+ }
+ }
+ return NULL;
}
/**
@@ -530,144 +532,147 @@ const char *BKE_pose_ikparam_get_name(bPose *pose)
*
* \param dst: Should be freed already, makes entire duplicate.
*/
-void BKE_pose_copy_data_ex(bPose **dst, const bPose *src, const int flag, const bool copy_constraints)
+void BKE_pose_copy_data_ex(bPose **dst,
+ const bPose *src,
+ const int flag,
+ const bool copy_constraints)
{
- bPose *outPose;
- bPoseChannel *pchan;
- ListBase listb;
-
- if (!src) {
- *dst = NULL;
- return;
- }
-
- outPose = MEM_callocN(sizeof(bPose), "pose");
-
- BLI_duplicatelist(&outPose->chanbase, &src->chanbase);
-
- /* Rebuild ghash here too, so that name lookups below won't be too bad...
- * BUT this will have the penalty that the ghash will be built twice
- * if BKE_pose_rebuild() gets called after this...
- */
- if (outPose->chanbase.first != outPose->chanbase.last) {
- outPose->chanhash = NULL;
- BKE_pose_channels_hash_make(outPose);
- }
-
- outPose->iksolver = src->iksolver;
- outPose->ikdata = NULL;
- outPose->ikparam = MEM_dupallocN(src->ikparam);
- outPose->avs = src->avs;
-
- for (pchan = outPose->chanbase.first; pchan; pchan = pchan->next) {
- if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- id_us_plus((ID *)pchan->custom);
- }
-
- /* warning, O(n2) here, if done without the hash, but these are rarely used features. */
- if (pchan->custom_tx) {
- pchan->custom_tx = BKE_pose_channel_find_name(outPose, pchan->custom_tx->name);
- }
- if (pchan->bbone_prev) {
- pchan->bbone_prev = BKE_pose_channel_find_name(outPose, pchan->bbone_prev->name);
- }
- if (pchan->bbone_next) {
- pchan->bbone_next = BKE_pose_channel_find_name(outPose, pchan->bbone_next->name);
- }
-
- if (copy_constraints) {
- BKE_constraints_copy_ex(&listb, &pchan->constraints, flag, true); // BKE_constraints_copy NULLs listb
- pchan->constraints = listb;
-
- /* XXX: This is needed for motionpath drawing to work. Dunno why it was setting to null before... */
- pchan->mpath = animviz_copy_motionpath(pchan->mpath);
- }
-
- if (pchan->prop) {
- pchan->prop = IDP_CopyProperty_ex(pchan->prop, flag);
- }
-
- pchan->draw_data = NULL; /* Drawing cache, no need to copy. */
-
- /* Runtime data, no need to copy. */
- memset(&pchan->runtime, 0, sizeof(pchan->runtime));
- }
-
- /* for now, duplicate Bone Groups too when doing this */
- if (copy_constraints) {
- BLI_duplicatelist(&outPose->agroups, &src->agroups);
- }
-
- *dst = outPose;
+ bPose *outPose;
+ bPoseChannel *pchan;
+ ListBase listb;
+
+ if (!src) {
+ *dst = NULL;
+ return;
+ }
+
+ outPose = MEM_callocN(sizeof(bPose), "pose");
+
+ BLI_duplicatelist(&outPose->chanbase, &src->chanbase);
+
+ /* Rebuild ghash here too, so that name lookups below won't be too bad...
+ * BUT this will have the penalty that the ghash will be built twice
+ * if BKE_pose_rebuild() gets called after this...
+ */
+ if (outPose->chanbase.first != outPose->chanbase.last) {
+ outPose->chanhash = NULL;
+ BKE_pose_channels_hash_make(outPose);
+ }
+
+ outPose->iksolver = src->iksolver;
+ outPose->ikdata = NULL;
+ outPose->ikparam = MEM_dupallocN(src->ikparam);
+ outPose->avs = src->avs;
+
+ for (pchan = outPose->chanbase.first; pchan; pchan = pchan->next) {
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id_us_plus((ID *)pchan->custom);
+ }
+
+ /* warning, O(n2) here, if done without the hash, but these are rarely used features. */
+ if (pchan->custom_tx) {
+ pchan->custom_tx = BKE_pose_channel_find_name(outPose, pchan->custom_tx->name);
+ }
+ if (pchan->bbone_prev) {
+ pchan->bbone_prev = BKE_pose_channel_find_name(outPose, pchan->bbone_prev->name);
+ }
+ if (pchan->bbone_next) {
+ pchan->bbone_next = BKE_pose_channel_find_name(outPose, pchan->bbone_next->name);
+ }
+
+ if (copy_constraints) {
+ BKE_constraints_copy_ex(
+ &listb, &pchan->constraints, flag, true); // BKE_constraints_copy NULLs listb
+ pchan->constraints = listb;
+
+ /* XXX: This is needed for motionpath drawing to work. Dunno why it was setting to null before... */
+ pchan->mpath = animviz_copy_motionpath(pchan->mpath);
+ }
+
+ if (pchan->prop) {
+ pchan->prop = IDP_CopyProperty_ex(pchan->prop, flag);
+ }
+
+ pchan->draw_data = NULL; /* Drawing cache, no need to copy. */
+
+ /* Runtime data, no need to copy. */
+ memset(&pchan->runtime, 0, sizeof(pchan->runtime));
+ }
+
+ /* for now, duplicate Bone Groups too when doing this */
+ if (copy_constraints) {
+ BLI_duplicatelist(&outPose->agroups, &src->agroups);
+ }
+
+ *dst = outPose;
}
void BKE_pose_copy_data(bPose **dst, const bPose *src, const bool copy_constraints)
{
- BKE_pose_copy_data_ex(dst, src, 0, copy_constraints);
+ BKE_pose_copy_data_ex(dst, src, 0, copy_constraints);
}
void BKE_pose_itasc_init(bItasc *itasc)
{
- if (itasc) {
- itasc->iksolver = IKSOLVER_ITASC;
- itasc->minstep = 0.01f;
- itasc->maxstep = 0.06f;
- itasc->numiter = 100;
- itasc->numstep = 4;
- itasc->precision = 0.005f;
- itasc->flag = ITASC_AUTO_STEP | ITASC_INITIAL_REITERATION;
- itasc->feedback = 20.0f;
- itasc->maxvel = 50.0f;
- itasc->solver = ITASC_SOLVER_SDLS;
- itasc->dampmax = 0.5;
- itasc->dampeps = 0.15;
- }
+ if (itasc) {
+ itasc->iksolver = IKSOLVER_ITASC;
+ itasc->minstep = 0.01f;
+ itasc->maxstep = 0.06f;
+ itasc->numiter = 100;
+ itasc->numstep = 4;
+ itasc->precision = 0.005f;
+ itasc->flag = ITASC_AUTO_STEP | ITASC_INITIAL_REITERATION;
+ itasc->feedback = 20.0f;
+ itasc->maxvel = 50.0f;
+ itasc->solver = ITASC_SOLVER_SDLS;
+ itasc->dampmax = 0.5;
+ itasc->dampeps = 0.15;
+ }
}
void BKE_pose_ikparam_init(bPose *pose)
{
- bItasc *itasc;
- switch (pose->iksolver) {
- case IKSOLVER_ITASC:
- itasc = MEM_callocN(sizeof(bItasc), "itasc");
- BKE_pose_itasc_init(itasc);
- pose->ikparam = itasc;
- break;
- case IKSOLVER_STANDARD:
- default:
- pose->ikparam = NULL;
- break;
- }
+ bItasc *itasc;
+ switch (pose->iksolver) {
+ case IKSOLVER_ITASC:
+ itasc = MEM_callocN(sizeof(bItasc), "itasc");
+ BKE_pose_itasc_init(itasc);
+ pose->ikparam = itasc;
+ break;
+ case IKSOLVER_STANDARD:
+ default:
+ pose->ikparam = NULL;
+ break;
+ }
}
-
/* only for real IK, not for auto-IK */
static bool pose_channel_in_IK_chain(Object *ob, bPoseChannel *pchan, int level)
{
- bConstraint *con;
- Bone *bone;
-
- /* No need to check if constraint is active (has influence),
- * since all constraints with CONSTRAINT_IK_AUTO are active */
- for (con = pchan->constraints.first; con; con = con->next) {
- if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
- bKinematicConstraint *data = con->data;
- if ((data->rootbone == 0) || (data->rootbone > level)) {
- if ((data->flag & CONSTRAINT_IK_AUTO) == 0)
- return true;
- }
- }
- }
- for (bone = pchan->bone->childbase.first; bone; bone = bone->next) {
- pchan = BKE_pose_channel_find_name(ob->pose, bone->name);
- if (pchan && pose_channel_in_IK_chain(ob, pchan, level + 1))
- return true;
- }
- return false;
+ bConstraint *con;
+ Bone *bone;
+
+ /* No need to check if constraint is active (has influence),
+ * since all constraints with CONSTRAINT_IK_AUTO are active */
+ for (con = pchan->constraints.first; con; con = con->next) {
+ if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
+ bKinematicConstraint *data = con->data;
+ if ((data->rootbone == 0) || (data->rootbone > level)) {
+ if ((data->flag & CONSTRAINT_IK_AUTO) == 0)
+ return true;
+ }
+ }
+ }
+ for (bone = pchan->bone->childbase.first; bone; bone = bone->next) {
+ pchan = BKE_pose_channel_find_name(ob->pose, bone->name);
+ if (pchan && pose_channel_in_IK_chain(ob, pchan, level + 1))
+ return true;
+ }
+ return false;
}
bool BKE_pose_channel_in_IK_chain(Object *ob, bPoseChannel *pchan)
{
- return pose_channel_in_IK_chain(ob, pchan, 0);
+ return pose_channel_in_IK_chain(ob, pchan, 0);
}
/**
@@ -676,88 +681,88 @@ bool BKE_pose_channel_in_IK_chain(Object *ob, bPoseChannel *pchan)
*/
void BKE_pose_channels_hash_make(bPose *pose)
{
- if (!pose->chanhash) {
- bPoseChannel *pchan;
+ if (!pose->chanhash) {
+ bPoseChannel *pchan;
- pose->chanhash = BLI_ghash_str_new("make_pose_chan gh");
- for (pchan = pose->chanbase.first; pchan; pchan = pchan->next)
- BLI_ghash_insert(pose->chanhash, pchan->name, pchan);
- }
+ pose->chanhash = BLI_ghash_str_new("make_pose_chan gh");
+ for (pchan = pose->chanbase.first; pchan; pchan = pchan->next)
+ BLI_ghash_insert(pose->chanhash, pchan->name, pchan);
+ }
}
void BKE_pose_channels_hash_free(bPose *pose)
{
- if (pose->chanhash) {
- BLI_ghash_free(pose->chanhash, NULL, NULL);
- pose->chanhash = NULL;
- }
+ if (pose->chanhash) {
+ BLI_ghash_free(pose->chanhash, NULL, NULL);
+ pose->chanhash = NULL;
+ }
}
/**
* Selectively remove pose channels.
*/
-void BKE_pose_channels_remove(
- Object *ob,
- bool (*filter_fn)(const char *bone_name, void *user_data), void *user_data)
+void BKE_pose_channels_remove(Object *ob,
+ bool (*filter_fn)(const char *bone_name, void *user_data),
+ void *user_data)
{
- /* Erase any associated pose channel, along with any references to them */
- if (ob->pose) {
- bPoseChannel *pchan, *pchan_next;
- bConstraint *con;
-
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan_next) {
- pchan_next = pchan->next;
-
- if (filter_fn(pchan->name, user_data)) {
- /* Bone itself is being removed */
- BKE_pose_channel_free(pchan);
- if (ob->pose->chanhash) {
- BLI_ghash_remove(ob->pose->chanhash, pchan->name, NULL, NULL);
- }
- BLI_freelinkN(&ob->pose->chanbase, pchan);
- }
- else {
- /* Maybe something the bone references is being removed instead? */
- for (con = pchan->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- if (ct->tar == ob) {
- if (ct->subtarget[0]) {
- if (filter_fn(ct->subtarget, user_data)) {
- con->flag |= CONSTRAINT_DISABLE;
- ct->subtarget[0] = 0;
- }
- }
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 0);
- }
- }
-
- if (pchan->bbone_prev) {
- if (filter_fn(pchan->bbone_prev->name, user_data))
- pchan->bbone_prev = NULL;
- }
- if (pchan->bbone_next) {
- if (filter_fn(pchan->bbone_next->name, user_data))
- pchan->bbone_next = NULL;
- }
-
- if (pchan->custom_tx) {
- if (filter_fn(pchan->custom_tx->name, user_data))
- pchan->custom_tx = NULL;
- }
- }
- }
- }
+ /* Erase any associated pose channel, along with any references to them */
+ if (ob->pose) {
+ bPoseChannel *pchan, *pchan_next;
+ bConstraint *con;
+
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan_next) {
+ pchan_next = pchan->next;
+
+ if (filter_fn(pchan->name, user_data)) {
+ /* Bone itself is being removed */
+ BKE_pose_channel_free(pchan);
+ if (ob->pose->chanhash) {
+ BLI_ghash_remove(ob->pose->chanhash, pchan->name, NULL, NULL);
+ }
+ BLI_freelinkN(&ob->pose->chanbase, pchan);
+ }
+ else {
+ /* Maybe something the bone references is being removed instead? */
+ for (con = pchan->constraints.first; con; con = con->next) {
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
+
+ for (ct = targets.first; ct; ct = ct->next) {
+ if (ct->tar == ob) {
+ if (ct->subtarget[0]) {
+ if (filter_fn(ct->subtarget, user_data)) {
+ con->flag |= CONSTRAINT_DISABLE;
+ ct->subtarget[0] = 0;
+ }
+ }
+ }
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 0);
+ }
+ }
+
+ if (pchan->bbone_prev) {
+ if (filter_fn(pchan->bbone_prev->name, user_data))
+ pchan->bbone_prev = NULL;
+ }
+ if (pchan->bbone_next) {
+ if (filter_fn(pchan->bbone_next->name, user_data))
+ pchan->bbone_next = NULL;
+ }
+
+ if (pchan->custom_tx) {
+ if (filter_fn(pchan->custom_tx->name, user_data))
+ pchan->custom_tx = NULL;
+ }
+ }
+ }
+ }
}
/**
@@ -766,47 +771,47 @@ void BKE_pose_channels_remove(
*/
void BKE_pose_channel_free_ex(bPoseChannel *pchan, bool do_id_user)
{
- if (pchan->custom) {
- if (do_id_user) {
- id_us_min(&pchan->custom->id);
- }
- pchan->custom = NULL;
- }
-
- if (pchan->mpath) {
- animviz_free_motionpath(pchan->mpath);
- pchan->mpath = NULL;
- }
-
- BKE_constraints_free_ex(&pchan->constraints, do_id_user);
-
- if (pchan->prop) {
- IDP_FreeProperty(pchan->prop);
- MEM_freeN(pchan->prop);
- }
-
- /* Cached data, for new draw manager rendering code. */
- MEM_SAFE_FREE(pchan->draw_data);
-
- /* Cached B-Bone shape data. */
- BKE_pose_channel_free_bbone_cache(pchan);
+ if (pchan->custom) {
+ if (do_id_user) {
+ id_us_min(&pchan->custom->id);
+ }
+ pchan->custom = NULL;
+ }
+
+ if (pchan->mpath) {
+ animviz_free_motionpath(pchan->mpath);
+ pchan->mpath = NULL;
+ }
+
+ BKE_constraints_free_ex(&pchan->constraints, do_id_user);
+
+ if (pchan->prop) {
+ IDP_FreeProperty(pchan->prop);
+ MEM_freeN(pchan->prop);
+ }
+
+ /* Cached data, for new draw manager rendering code. */
+ MEM_SAFE_FREE(pchan->draw_data);
+
+ /* Cached B-Bone shape data. */
+ BKE_pose_channel_free_bbone_cache(pchan);
}
/** Deallocates runtime cache of a pose channel's B-Bone shape. */
void BKE_pose_channel_free_bbone_cache(bPoseChannel *pchan)
{
- bPoseChannel_Runtime *runtime = &pchan->runtime;
+ bPoseChannel_Runtime *runtime = &pchan->runtime;
- runtime->bbone_segments = 0;
- MEM_SAFE_FREE(runtime->bbone_rest_mats);
- MEM_SAFE_FREE(runtime->bbone_pose_mats);
- MEM_SAFE_FREE(runtime->bbone_deform_mats);
- MEM_SAFE_FREE(runtime->bbone_dual_quats);
+ runtime->bbone_segments = 0;
+ MEM_SAFE_FREE(runtime->bbone_rest_mats);
+ MEM_SAFE_FREE(runtime->bbone_pose_mats);
+ MEM_SAFE_FREE(runtime->bbone_deform_mats);
+ MEM_SAFE_FREE(runtime->bbone_dual_quats);
}
void BKE_pose_channel_free(bPoseChannel *pchan)
{
- BKE_pose_channel_free_ex(pchan, true);
+ BKE_pose_channel_free_ex(pchan, true);
}
/**
@@ -815,45 +820,45 @@ void BKE_pose_channel_free(bPoseChannel *pchan)
*/
void BKE_pose_channels_free_ex(bPose *pose, bool do_id_user)
{
- bPoseChannel *pchan;
+ bPoseChannel *pchan;
- if (pose->chanbase.first) {
- for (pchan = pose->chanbase.first; pchan; pchan = pchan->next)
- BKE_pose_channel_free_ex(pchan, do_id_user);
+ if (pose->chanbase.first) {
+ for (pchan = pose->chanbase.first; pchan; pchan = pchan->next)
+ BKE_pose_channel_free_ex(pchan, do_id_user);
- BLI_freelistN(&pose->chanbase);
- }
+ BLI_freelistN(&pose->chanbase);
+ }
- BKE_pose_channels_hash_free(pose);
+ BKE_pose_channels_hash_free(pose);
- MEM_SAFE_FREE(pose->chan_array);
+ MEM_SAFE_FREE(pose->chan_array);
}
void BKE_pose_channels_free(bPose *pose)
{
- BKE_pose_channels_free_ex(pose, true);
+ BKE_pose_channels_free_ex(pose, true);
}
void BKE_pose_free_data_ex(bPose *pose, bool do_id_user)
{
- /* free pose-channels */
- BKE_pose_channels_free_ex(pose, do_id_user);
+ /* free pose-channels */
+ BKE_pose_channels_free_ex(pose, do_id_user);
- /* free pose-groups */
- if (pose->agroups.first)
- BLI_freelistN(&pose->agroups);
+ /* free pose-groups */
+ if (pose->agroups.first)
+ BLI_freelistN(&pose->agroups);
- /* free IK solver state */
- BIK_clear_data(pose);
+ /* free IK solver state */
+ BIK_clear_data(pose);
- /* free IK solver param */
- if (pose->ikparam)
- MEM_freeN(pose->ikparam);
+ /* free IK solver param */
+ if (pose->ikparam)
+ MEM_freeN(pose->ikparam);
}
void BKE_pose_free_data(bPose *pose)
{
- BKE_pose_free_data_ex(pose, true);
+ BKE_pose_free_data_ex(pose, true);
}
/**
@@ -861,16 +866,16 @@ void BKE_pose_free_data(bPose *pose)
*/
void BKE_pose_free_ex(bPose *pose, bool do_id_user)
{
- if (pose) {
- BKE_pose_free_data_ex(pose, do_id_user);
- /* free pose */
- MEM_freeN(pose);
- }
+ if (pose) {
+ BKE_pose_free_data_ex(pose, do_id_user);
+ /* free pose */
+ MEM_freeN(pose);
+ }
}
void BKE_pose_free(bPose *pose)
{
- BKE_pose_free_ex(pose, true);
+ BKE_pose_free_ex(pose, true);
}
/**
@@ -882,117 +887,118 @@ void BKE_pose_free(bPose *pose)
*/
void BKE_pose_channel_copy_data(bPoseChannel *pchan, const bPoseChannel *pchan_from)
{
- /* copy transform locks */
- pchan->protectflag = pchan_from->protectflag;
-
- /* copy rotation mode */
- pchan->rotmode = pchan_from->rotmode;
-
- /* copy bone group */
- pchan->agrp_index = pchan_from->agrp_index;
-
- /* ik (dof) settings */
- pchan->ikflag = pchan_from->ikflag;
- copy_v3_v3(pchan->limitmin, pchan_from->limitmin);
- copy_v3_v3(pchan->limitmax, pchan_from->limitmax);
- copy_v3_v3(pchan->stiffness, pchan_from->stiffness);
- pchan->ikstretch = pchan_from->ikstretch;
- pchan->ikrotweight = pchan_from->ikrotweight;
- pchan->iklinweight = pchan_from->iklinweight;
-
- /* bbone settings (typically not animated) */
- pchan->bbone_next = pchan_from->bbone_next;
- pchan->bbone_prev = pchan_from->bbone_prev;
-
- /* constraints */
- BKE_constraints_copy(&pchan->constraints, &pchan_from->constraints, true);
-
- /* id-properties */
- if (pchan->prop) {
- /* unlikely but possible it exists */
- IDP_FreeProperty(pchan->prop);
- MEM_freeN(pchan->prop);
- pchan->prop = NULL;
- }
- if (pchan_from->prop) {
- pchan->prop = IDP_CopyProperty(pchan_from->prop);
- }
-
- /* custom shape */
- pchan->custom = pchan_from->custom;
- if (pchan->custom) {
- id_us_plus(&pchan->custom->id);
- }
-
- pchan->custom_scale = pchan_from->custom_scale;
+ /* copy transform locks */
+ pchan->protectflag = pchan_from->protectflag;
+
+ /* copy rotation mode */
+ pchan->rotmode = pchan_from->rotmode;
+
+ /* copy bone group */
+ pchan->agrp_index = pchan_from->agrp_index;
+
+ /* ik (dof) settings */
+ pchan->ikflag = pchan_from->ikflag;
+ copy_v3_v3(pchan->limitmin, pchan_from->limitmin);
+ copy_v3_v3(pchan->limitmax, pchan_from->limitmax);
+ copy_v3_v3(pchan->stiffness, pchan_from->stiffness);
+ pchan->ikstretch = pchan_from->ikstretch;
+ pchan->ikrotweight = pchan_from->ikrotweight;
+ pchan->iklinweight = pchan_from->iklinweight;
+
+ /* bbone settings (typically not animated) */
+ pchan->bbone_next = pchan_from->bbone_next;
+ pchan->bbone_prev = pchan_from->bbone_prev;
+
+ /* constraints */
+ BKE_constraints_copy(&pchan->constraints, &pchan_from->constraints, true);
+
+ /* id-properties */
+ if (pchan->prop) {
+ /* unlikely but possible it exists */
+ IDP_FreeProperty(pchan->prop);
+ MEM_freeN(pchan->prop);
+ pchan->prop = NULL;
+ }
+ if (pchan_from->prop) {
+ pchan->prop = IDP_CopyProperty(pchan_from->prop);
+ }
+
+ /* custom shape */
+ pchan->custom = pchan_from->custom;
+ if (pchan->custom) {
+ id_us_plus(&pchan->custom->id);
+ }
+
+ pchan->custom_scale = pchan_from->custom_scale;
}
-
/* checks for IK constraint, Spline IK, and also for Follow-Path constraint.
* can do more constraints flags later
*/
/* pose should be entirely OK */
void BKE_pose_update_constraint_flags(bPose *pose)
{
- bPoseChannel *pchan, *parchan;
- bConstraint *con;
-
- /* clear */
- for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- pchan->constflag = 0;
- }
- pose->flag &= ~POSE_CONSTRAINTS_TIMEDEPEND;
-
- /* detect */
- for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- for (con = pchan->constraints.first; con; con = con->next) {
- if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
- bKinematicConstraint *data = (bKinematicConstraint *)con->data;
-
- pchan->constflag |= PCHAN_HAS_IK;
-
- if (data->tar == NULL || (data->tar->type == OB_ARMATURE && data->subtarget[0] == 0))
- pchan->constflag |= PCHAN_HAS_TARGET;
-
- /* negative rootbone = recalc rootbone index. used in do_versions */
- if (data->rootbone < 0) {
- data->rootbone = 0;
-
- if (data->flag & CONSTRAINT_IK_TIP) parchan = pchan;
- else parchan = pchan->parent;
-
- while (parchan) {
- data->rootbone++;
- if ((parchan->bone->flag & BONE_CONNECTED) == 0)
- break;
- parchan = parchan->parent;
- }
- }
- }
- else if (con->type == CONSTRAINT_TYPE_FOLLOWPATH) {
- bFollowPathConstraint *data = (bFollowPathConstraint *)con->data;
-
- /* for drawing constraint colors when color set allows this */
- pchan->constflag |= PCHAN_HAS_CONST;
-
- /* if we have a valid target, make sure that this will get updated on frame-change
- * (needed for when there is no anim-data for this pose)
- */
- if ((data->tar) && (data->tar->type == OB_CURVE))
- pose->flag |= POSE_CONSTRAINTS_TIMEDEPEND;
- }
- else if (con->type == CONSTRAINT_TYPE_SPLINEIK)
- pchan->constflag |= PCHAN_HAS_SPLINEIK;
- else
- pchan->constflag |= PCHAN_HAS_CONST;
- }
- }
- pose->flag &= ~POSE_CONSTRAINTS_NEED_UPDATE_FLAGS;
+ bPoseChannel *pchan, *parchan;
+ bConstraint *con;
+
+ /* clear */
+ for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ pchan->constflag = 0;
+ }
+ pose->flag &= ~POSE_CONSTRAINTS_TIMEDEPEND;
+
+ /* detect */
+ for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ for (con = pchan->constraints.first; con; con = con->next) {
+ if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
+ bKinematicConstraint *data = (bKinematicConstraint *)con->data;
+
+ pchan->constflag |= PCHAN_HAS_IK;
+
+ if (data->tar == NULL || (data->tar->type == OB_ARMATURE && data->subtarget[0] == 0))
+ pchan->constflag |= PCHAN_HAS_TARGET;
+
+ /* negative rootbone = recalc rootbone index. used in do_versions */
+ if (data->rootbone < 0) {
+ data->rootbone = 0;
+
+ if (data->flag & CONSTRAINT_IK_TIP)
+ parchan = pchan;
+ else
+ parchan = pchan->parent;
+
+ while (parchan) {
+ data->rootbone++;
+ if ((parchan->bone->flag & BONE_CONNECTED) == 0)
+ break;
+ parchan = parchan->parent;
+ }
+ }
+ }
+ else if (con->type == CONSTRAINT_TYPE_FOLLOWPATH) {
+ bFollowPathConstraint *data = (bFollowPathConstraint *)con->data;
+
+ /* for drawing constraint colors when color set allows this */
+ pchan->constflag |= PCHAN_HAS_CONST;
+
+ /* if we have a valid target, make sure that this will get updated on frame-change
+ * (needed for when there is no anim-data for this pose)
+ */
+ if ((data->tar) && (data->tar->type == OB_CURVE))
+ pose->flag |= POSE_CONSTRAINTS_TIMEDEPEND;
+ }
+ else if (con->type == CONSTRAINT_TYPE_SPLINEIK)
+ pchan->constflag |= PCHAN_HAS_SPLINEIK;
+ else
+ pchan->constflag |= PCHAN_HAS_CONST;
+ }
+ }
+ pose->flag &= ~POSE_CONSTRAINTS_NEED_UPDATE_FLAGS;
}
void BKE_pose_tag_update_constraint_flags(bPose *pose)
{
- pose->flag |= POSE_CONSTRAINTS_NEED_UPDATE_FLAGS;
+ pose->flag |= POSE_CONSTRAINTS_NEED_UPDATE_FLAGS;
}
/* Clears all BONE_UNKEYED flags for every pose channel in every pose
@@ -1001,21 +1007,21 @@ void BKE_pose_tag_update_constraint_flags(bPose *pose)
*/
void framechange_poses_clear_unkeyed(Main *bmain)
{
- Object *ob;
- bPose *pose;
- bPoseChannel *pchan;
-
- /* This needs to be done for each object that has a pose */
- /* TODO: proxies may/may not be correctly handled here... (this needs checking) */
- for (ob = bmain->objects.first; ob; ob = ob->id.next) {
- /* we only need to do this on objects with a pose */
- if ((pose = ob->pose)) {
- for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->bone)
- pchan->bone->flag &= ~BONE_UNKEYED;
- }
- }
- }
+ Object *ob;
+ bPose *pose;
+ bPoseChannel *pchan;
+
+ /* This needs to be done for each object that has a pose */
+ /* TODO: proxies may/may not be correctly handled here... (this needs checking) */
+ for (ob = bmain->objects.first; ob; ob = ob->id.next) {
+ /* we only need to do this on objects with a pose */
+ if ((pose = ob->pose)) {
+ for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->bone)
+ pchan->bone->flag &= ~BONE_UNKEYED;
+ }
+ }
+ }
}
/* ************************** Bone Groups ************************** */
@@ -1023,70 +1029,70 @@ void framechange_poses_clear_unkeyed(Main *bmain)
/* Adds a new bone-group (name may be NULL) */
bActionGroup *BKE_pose_add_group(bPose *pose, const char *name)
{
- bActionGroup *grp;
+ bActionGroup *grp;
- if (!name) {
- name = DATA_("Group");
- }
+ if (!name) {
+ name = DATA_("Group");
+ }
- grp = MEM_callocN(sizeof(bActionGroup), "PoseGroup");
- BLI_strncpy(grp->name, name, sizeof(grp->name));
- BLI_addtail(&pose->agroups, grp);
- BLI_uniquename(&pose->agroups, grp, name, '.', offsetof(bActionGroup, name), sizeof(grp->name));
+ grp = MEM_callocN(sizeof(bActionGroup), "PoseGroup");
+ BLI_strncpy(grp->name, name, sizeof(grp->name));
+ BLI_addtail(&pose->agroups, grp);
+ BLI_uniquename(&pose->agroups, grp, name, '.', offsetof(bActionGroup, name), sizeof(grp->name));
- pose->active_group = BLI_listbase_count(&pose->agroups);
+ pose->active_group = BLI_listbase_count(&pose->agroups);
- return grp;
+ return grp;
}
/* Remove the given bone-group (expects 'virtual' index (+1 one, used by active_group etc.))
* index might be invalid ( < 1), in which case it will be find from grp. */
void BKE_pose_remove_group(bPose *pose, bActionGroup *grp, const int index)
{
- bPoseChannel *pchan;
- int idx = index;
-
- if (idx < 1) {
- idx = BLI_findindex(&pose->agroups, grp) + 1;
- }
-
- BLI_assert(idx > 0);
-
- /* adjust group references (the trouble of using indices!):
- * - firstly, make sure nothing references it
- * - also, make sure that those after this item get corrected
- */
- for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->agrp_index == idx)
- pchan->agrp_index = 0;
- else if (pchan->agrp_index > idx)
- pchan->agrp_index--;
- }
-
- /* now, remove it from the pose */
- BLI_freelinkN(&pose->agroups, grp);
- if (pose->active_group >= idx) {
- const bool has_groups = !BLI_listbase_is_empty(&pose->agroups);
- pose->active_group--;
- if (pose->active_group == 0 && has_groups) {
- pose->active_group = 1;
- }
- else if (pose->active_group < 0 || !has_groups) {
- pose->active_group = 0;
- }
- }
+ bPoseChannel *pchan;
+ int idx = index;
+
+ if (idx < 1) {
+ idx = BLI_findindex(&pose->agroups, grp) + 1;
+ }
+
+ BLI_assert(idx > 0);
+
+ /* adjust group references (the trouble of using indices!):
+ * - firstly, make sure nothing references it
+ * - also, make sure that those after this item get corrected
+ */
+ for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->agrp_index == idx)
+ pchan->agrp_index = 0;
+ else if (pchan->agrp_index > idx)
+ pchan->agrp_index--;
+ }
+
+ /* now, remove it from the pose */
+ BLI_freelinkN(&pose->agroups, grp);
+ if (pose->active_group >= idx) {
+ const bool has_groups = !BLI_listbase_is_empty(&pose->agroups);
+ pose->active_group--;
+ if (pose->active_group == 0 && has_groups) {
+ pose->active_group = 1;
+ }
+ else if (pose->active_group < 0 || !has_groups) {
+ pose->active_group = 0;
+ }
+ }
}
/* Remove the indexed bone-group (expects 'virtual' index (+1 one, used by active_group etc.)) */
void BKE_pose_remove_group_index(bPose *pose, const int index)
{
- bActionGroup *grp = NULL;
+ bActionGroup *grp = NULL;
- /* get group to remove */
- grp = BLI_findlink(&pose->agroups, index - 1);
- if (grp) {
- BKE_pose_remove_group(pose, grp, index);
- }
+ /* get group to remove */
+ grp = BLI_findlink(&pose->agroups, index - 1);
+ if (grp) {
+ BKE_pose_remove_group(pose, grp, index);
+ }
}
/* ************** F-Curve Utilities for Actions ****************** */
@@ -1094,102 +1100,103 @@ void BKE_pose_remove_group_index(bPose *pose, const int index)
/* Check if the given action has any keyframes */
bool action_has_motion(const bAction *act)
{
- FCurve *fcu;
-
- /* return on the first F-Curve that has some keyframes/samples defined */
- if (act) {
- for (fcu = act->curves.first; fcu; fcu = fcu->next) {
- if (fcu->totvert)
- return true;
- }
- }
-
- /* nothing found */
- return false;
+ FCurve *fcu;
+
+ /* return on the first F-Curve that has some keyframes/samples defined */
+ if (act) {
+ for (fcu = act->curves.first; fcu; fcu = fcu->next) {
+ if (fcu->totvert)
+ return true;
+ }
+ }
+
+ /* nothing found */
+ return false;
}
/* Calculate the extents of given action */
void calc_action_range(const bAction *act, float *start, float *end, short incl_modifiers)
{
- FCurve *fcu;
- float min = 999999999.0f, max = -999999999.0f;
- short foundvert = 0, foundmod = 0;
-
- if (act) {
- for (fcu = act->curves.first; fcu; fcu = fcu->next) {
- /* if curve has keyframes, consider them first */
- if (fcu->totvert) {
- float nmin, nmax;
-
- /* get extents for this curve
- * - no "selected only", since this is often used in the backend
- * - no "minimum length" (we will apply this later), otherwise
- * single-keyframe curves will increase the overall length by
- * a phantom frame (T50354)
- */
- calc_fcurve_range(fcu, &nmin, &nmax, false, false);
-
- /* compare to the running tally */
- min = min_ff(min, nmin);
- max = max_ff(max, nmax);
-
- foundvert = 1;
- }
-
- /* if incl_modifiers is enabled, need to consider modifiers too
- * - only really care about the last modifier
- */
- if ((incl_modifiers) && (fcu->modifiers.last)) {
- FModifier *fcm = fcu->modifiers.last;
-
- /* only use the maximum sensible limits of the modifiers if they are more extreme */
- switch (fcm->type) {
- case FMODIFIER_TYPE_LIMITS: /* Limits F-Modifier */
- {
- FMod_Limits *fmd = (FMod_Limits *)fcm->data;
-
- if (fmd->flag & FCM_LIMIT_XMIN) {
- min = min_ff(min, fmd->rect.xmin);
- }
- if (fmd->flag & FCM_LIMIT_XMAX) {
- max = max_ff(max, fmd->rect.xmax);
- }
- break;
- }
- case FMODIFIER_TYPE_CYCLES: /* Cycles F-Modifier */
- {
- FMod_Cycles *fmd = (FMod_Cycles *)fcm->data;
-
- if (fmd->before_mode != FCM_EXTRAPOLATE_NONE)
- min = MINAFRAMEF;
- if (fmd->after_mode != FCM_EXTRAPOLATE_NONE)
- max = MAXFRAMEF;
- break;
- }
- /* TODO: function modifier may need some special limits */
-
- default: /* all other standard modifiers are on the infinite range... */
- min = MINAFRAMEF;
- max = MAXFRAMEF;
- break;
- }
-
- foundmod = 1;
- }
- }
- }
-
- if (foundvert || foundmod) {
- /* ensure that action is at least 1 frame long (for NLA strips to have a valid length) */
- if (min == max) max += 1.0f;
-
- *start = min;
- *end = max;
- }
- else {
- *start = 0.0f;
- *end = 1.0f;
- }
+ FCurve *fcu;
+ float min = 999999999.0f, max = -999999999.0f;
+ short foundvert = 0, foundmod = 0;
+
+ if (act) {
+ for (fcu = act->curves.first; fcu; fcu = fcu->next) {
+ /* if curve has keyframes, consider them first */
+ if (fcu->totvert) {
+ float nmin, nmax;
+
+ /* get extents for this curve
+ * - no "selected only", since this is often used in the backend
+ * - no "minimum length" (we will apply this later), otherwise
+ * single-keyframe curves will increase the overall length by
+ * a phantom frame (T50354)
+ */
+ calc_fcurve_range(fcu, &nmin, &nmax, false, false);
+
+ /* compare to the running tally */
+ min = min_ff(min, nmin);
+ max = max_ff(max, nmax);
+
+ foundvert = 1;
+ }
+
+ /* if incl_modifiers is enabled, need to consider modifiers too
+ * - only really care about the last modifier
+ */
+ if ((incl_modifiers) && (fcu->modifiers.last)) {
+ FModifier *fcm = fcu->modifiers.last;
+
+ /* only use the maximum sensible limits of the modifiers if they are more extreme */
+ switch (fcm->type) {
+ case FMODIFIER_TYPE_LIMITS: /* Limits F-Modifier */
+ {
+ FMod_Limits *fmd = (FMod_Limits *)fcm->data;
+
+ if (fmd->flag & FCM_LIMIT_XMIN) {
+ min = min_ff(min, fmd->rect.xmin);
+ }
+ if (fmd->flag & FCM_LIMIT_XMAX) {
+ max = max_ff(max, fmd->rect.xmax);
+ }
+ break;
+ }
+ case FMODIFIER_TYPE_CYCLES: /* Cycles F-Modifier */
+ {
+ FMod_Cycles *fmd = (FMod_Cycles *)fcm->data;
+
+ if (fmd->before_mode != FCM_EXTRAPOLATE_NONE)
+ min = MINAFRAMEF;
+ if (fmd->after_mode != FCM_EXTRAPOLATE_NONE)
+ max = MAXFRAMEF;
+ break;
+ }
+ /* TODO: function modifier may need some special limits */
+
+ default: /* all other standard modifiers are on the infinite range... */
+ min = MINAFRAMEF;
+ max = MAXFRAMEF;
+ break;
+ }
+
+ foundmod = 1;
+ }
+ }
+ }
+
+ if (foundvert || foundmod) {
+ /* ensure that action is at least 1 frame long (for NLA strips to have a valid length) */
+ if (min == max)
+ max += 1.0f;
+
+ *start = min;
+ *end = max;
+ }
+ else {
+ *start = 0.0f;
+ *end = 1.0f;
+ }
}
/* Return flags indicating which transforms the given object/posechannel has
@@ -1197,118 +1204,120 @@ void calc_action_range(const bAction *act, float *start, float *end, short incl_
*/
short action_get_item_transforms(bAction *act, Object *ob, bPoseChannel *pchan, ListBase *curves)
{
- PointerRNA ptr;
- FCurve *fcu;
- char *basePath = NULL;
- short flags = 0;
-
- /* build PointerRNA from provided data to obtain the paths to use */
- if (pchan)
- RNA_pointer_create((ID *)ob, &RNA_PoseBone, pchan, &ptr);
- else if (ob)
- RNA_id_pointer_create((ID *)ob, &ptr);
- else
- return 0;
-
- /* get the basic path to the properties of interest */
- basePath = RNA_path_from_ID_to_struct(&ptr);
- if (basePath == NULL)
- return 0;
-
- /* search F-Curves for the given properties
- * - we cannot use the groups, since they may not be grouped in that way...
- */
- for (fcu = act->curves.first; fcu; fcu = fcu->next) {
- const char *bPtr = NULL, *pPtr = NULL;
-
- /* if enough flags have been found, we can stop checking unless we're also getting the curves */
- if ((flags == ACT_TRANS_ALL) && (curves == NULL))
- break;
-
- /* just in case... */
- if (fcu->rna_path == NULL)
- continue;
-
- /* step 1: check for matching base path */
- bPtr = strstr(fcu->rna_path, basePath);
-
- if (bPtr) {
- /* we must add len(basePath) bytes to the match so that we are at the end of the
- * base path so that we don't get false positives with these strings in the names
- */
- bPtr += strlen(basePath);
-
- /* step 2: check for some property with transforms
- * - to speed things up, only check for the ones not yet found
- * unless we're getting the curves too
- * - if we're getting the curves, the BLI_genericNodeN() creates a LinkData
- * node wrapping the F-Curve, which then gets added to the list
- * - once a match has been found, the curve cannot possibly be any other one
- */
- if ((curves) || (flags & ACT_TRANS_LOC) == 0) {
- pPtr = strstr(bPtr, "location");
- if (pPtr) {
- flags |= ACT_TRANS_LOC;
-
- if (curves)
- BLI_addtail(curves, BLI_genericNodeN(fcu));
- continue;
- }
- }
-
- if ((curves) || (flags & ACT_TRANS_SCALE) == 0) {
- pPtr = strstr(bPtr, "scale");
- if (pPtr) {
- flags |= ACT_TRANS_SCALE;
-
- if (curves)
- BLI_addtail(curves, BLI_genericNodeN(fcu));
- continue;
- }
- }
-
- if ((curves) || (flags & ACT_TRANS_ROT) == 0) {
- pPtr = strstr(bPtr, "rotation");
- if (pPtr) {
- flags |= ACT_TRANS_ROT;
-
- if (curves)
- BLI_addtail(curves, BLI_genericNodeN(fcu));
- continue;
- }
- }
-
- if ((curves) || (flags & ACT_TRANS_BBONE) == 0) {
- /* bbone shape properties */
- pPtr = strstr(bPtr, "bbone_");
- if (pPtr) {
- flags |= ACT_TRANS_BBONE;
-
- if (curves)
- BLI_addtail(curves, BLI_genericNodeN(fcu));
- continue;
- }
- }
-
- if ((curves) || (flags & ACT_TRANS_PROP) == 0) {
- /* custom properties only */
- pPtr = strstr(bPtr, "[\""); /* extra '"' comment here to keep my texteditor functionlist working :) */
- if (pPtr) {
- flags |= ACT_TRANS_PROP;
-
- if (curves)
- BLI_addtail(curves, BLI_genericNodeN(fcu));
- continue;
- }
- }
- }
- }
-
- /* free basePath */
- MEM_freeN(basePath);
-
- /* return flags found */
- return flags;
+ PointerRNA ptr;
+ FCurve *fcu;
+ char *basePath = NULL;
+ short flags = 0;
+
+ /* build PointerRNA from provided data to obtain the paths to use */
+ if (pchan)
+ RNA_pointer_create((ID *)ob, &RNA_PoseBone, pchan, &ptr);
+ else if (ob)
+ RNA_id_pointer_create((ID *)ob, &ptr);
+ else
+ return 0;
+
+ /* get the basic path to the properties of interest */
+ basePath = RNA_path_from_ID_to_struct(&ptr);
+ if (basePath == NULL)
+ return 0;
+
+ /* search F-Curves for the given properties
+ * - we cannot use the groups, since they may not be grouped in that way...
+ */
+ for (fcu = act->curves.first; fcu; fcu = fcu->next) {
+ const char *bPtr = NULL, *pPtr = NULL;
+
+ /* if enough flags have been found, we can stop checking unless we're also getting the curves */
+ if ((flags == ACT_TRANS_ALL) && (curves == NULL))
+ break;
+
+ /* just in case... */
+ if (fcu->rna_path == NULL)
+ continue;
+
+ /* step 1: check for matching base path */
+ bPtr = strstr(fcu->rna_path, basePath);
+
+ if (bPtr) {
+ /* we must add len(basePath) bytes to the match so that we are at the end of the
+ * base path so that we don't get false positives with these strings in the names
+ */
+ bPtr += strlen(basePath);
+
+ /* step 2: check for some property with transforms
+ * - to speed things up, only check for the ones not yet found
+ * unless we're getting the curves too
+ * - if we're getting the curves, the BLI_genericNodeN() creates a LinkData
+ * node wrapping the F-Curve, which then gets added to the list
+ * - once a match has been found, the curve cannot possibly be any other one
+ */
+ if ((curves) || (flags & ACT_TRANS_LOC) == 0) {
+ pPtr = strstr(bPtr, "location");
+ if (pPtr) {
+ flags |= ACT_TRANS_LOC;
+
+ if (curves)
+ BLI_addtail(curves, BLI_genericNodeN(fcu));
+ continue;
+ }
+ }
+
+ if ((curves) || (flags & ACT_TRANS_SCALE) == 0) {
+ pPtr = strstr(bPtr, "scale");
+ if (pPtr) {
+ flags |= ACT_TRANS_SCALE;
+
+ if (curves)
+ BLI_addtail(curves, BLI_genericNodeN(fcu));
+ continue;
+ }
+ }
+
+ if ((curves) || (flags & ACT_TRANS_ROT) == 0) {
+ pPtr = strstr(bPtr, "rotation");
+ if (pPtr) {
+ flags |= ACT_TRANS_ROT;
+
+ if (curves)
+ BLI_addtail(curves, BLI_genericNodeN(fcu));
+ continue;
+ }
+ }
+
+ if ((curves) || (flags & ACT_TRANS_BBONE) == 0) {
+ /* bbone shape properties */
+ pPtr = strstr(bPtr, "bbone_");
+ if (pPtr) {
+ flags |= ACT_TRANS_BBONE;
+
+ if (curves)
+ BLI_addtail(curves, BLI_genericNodeN(fcu));
+ continue;
+ }
+ }
+
+ if ((curves) || (flags & ACT_TRANS_PROP) == 0) {
+ /* custom properties only */
+ pPtr = strstr(
+ bPtr,
+ "[\""); /* extra '"' comment here to keep my texteditor functionlist working :) */
+ if (pPtr) {
+ flags |= ACT_TRANS_PROP;
+
+ if (curves)
+ BLI_addtail(curves, BLI_genericNodeN(fcu));
+ continue;
+ }
+ }
+ }
+ }
+
+ /* free basePath */
+ MEM_freeN(basePath);
+
+ /* return flags found */
+ return flags;
}
/* ************** Pose Management Tools ****************** */
@@ -1316,161 +1325,169 @@ short action_get_item_transforms(bAction *act, Object *ob, bPoseChannel *pchan,
/* for do_all_pose_actions, clears the pose. Now also exported for proxy and tools */
void BKE_pose_rest(bPose *pose)
{
- bPoseChannel *pchan;
+ bPoseChannel *pchan;
- if (!pose)
- return;
+ if (!pose)
+ return;
- memset(pose->stride_offset, 0, sizeof(pose->stride_offset));
- memset(pose->cyclic_offset, 0, sizeof(pose->cyclic_offset));
+ memset(pose->stride_offset, 0, sizeof(pose->stride_offset));
+ memset(pose->cyclic_offset, 0, sizeof(pose->cyclic_offset));
- for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- zero_v3(pchan->loc);
- zero_v3(pchan->eul);
- unit_qt(pchan->quat);
- unit_axis_angle(pchan->rotAxis, &pchan->rotAngle);
- pchan->size[0] = pchan->size[1] = pchan->size[2] = 1.0f;
+ for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ zero_v3(pchan->loc);
+ zero_v3(pchan->eul);
+ unit_qt(pchan->quat);
+ unit_axis_angle(pchan->rotAxis, &pchan->rotAngle);
+ pchan->size[0] = pchan->size[1] = pchan->size[2] = 1.0f;
- pchan->roll1 = pchan->roll2 = 0.0f;
- pchan->curveInX = pchan->curveInY = 0.0f;
- pchan->curveOutX = pchan->curveOutY = 0.0f;
- pchan->ease1 = pchan->ease2 = 0.0f;
- pchan->scaleIn = pchan->scaleOut = 1.0f;
+ pchan->roll1 = pchan->roll2 = 0.0f;
+ pchan->curveInX = pchan->curveInY = 0.0f;
+ pchan->curveOutX = pchan->curveOutY = 0.0f;
+ pchan->ease1 = pchan->ease2 = 0.0f;
+ pchan->scaleIn = pchan->scaleOut = 1.0f;
- pchan->flag &= ~(POSE_LOC | POSE_ROT | POSE_SIZE | POSE_BBONE_SHAPE);
- }
+ pchan->flag &= ~(POSE_LOC | POSE_ROT | POSE_SIZE | POSE_BBONE_SHAPE);
+ }
}
void BKE_pose_copyesult_pchan_result(bPoseChannel *pchanto, const bPoseChannel *pchanfrom)
{
- copy_m4_m4(pchanto->pose_mat, pchanfrom->pose_mat);
- copy_m4_m4(pchanto->chan_mat, pchanfrom->chan_mat);
-
- /* used for local constraints */
- copy_v3_v3(pchanto->loc, pchanfrom->loc);
- copy_qt_qt(pchanto->quat, pchanfrom->quat);
- copy_v3_v3(pchanto->eul, pchanfrom->eul);
- copy_v3_v3(pchanto->size, pchanfrom->size);
-
- copy_v3_v3(pchanto->pose_head, pchanfrom->pose_head);
- copy_v3_v3(pchanto->pose_tail, pchanfrom->pose_tail);
-
- pchanto->roll1 = pchanfrom->roll1;
- pchanto->roll2 = pchanfrom->roll2;
- pchanto->curveInX = pchanfrom->curveInX;
- pchanto->curveInY = pchanfrom->curveInY;
- pchanto->curveOutX = pchanfrom->curveOutX;
- pchanto->curveOutY = pchanfrom->curveOutY;
- pchanto->ease1 = pchanfrom->ease1;
- pchanto->ease2 = pchanfrom->ease2;
- pchanto->scaleIn = pchanfrom->scaleIn;
- pchanto->scaleOut = pchanfrom->scaleOut;
-
- pchanto->rotmode = pchanfrom->rotmode;
- pchanto->flag = pchanfrom->flag;
- pchanto->protectflag = pchanfrom->protectflag;
+ copy_m4_m4(pchanto->pose_mat, pchanfrom->pose_mat);
+ copy_m4_m4(pchanto->chan_mat, pchanfrom->chan_mat);
+
+ /* used for local constraints */
+ copy_v3_v3(pchanto->loc, pchanfrom->loc);
+ copy_qt_qt(pchanto->quat, pchanfrom->quat);
+ copy_v3_v3(pchanto->eul, pchanfrom->eul);
+ copy_v3_v3(pchanto->size, pchanfrom->size);
+
+ copy_v3_v3(pchanto->pose_head, pchanfrom->pose_head);
+ copy_v3_v3(pchanto->pose_tail, pchanfrom->pose_tail);
+
+ pchanto->roll1 = pchanfrom->roll1;
+ pchanto->roll2 = pchanfrom->roll2;
+ pchanto->curveInX = pchanfrom->curveInX;
+ pchanto->curveInY = pchanfrom->curveInY;
+ pchanto->curveOutX = pchanfrom->curveOutX;
+ pchanto->curveOutY = pchanfrom->curveOutY;
+ pchanto->ease1 = pchanfrom->ease1;
+ pchanto->ease2 = pchanfrom->ease2;
+ pchanto->scaleIn = pchanfrom->scaleIn;
+ pchanto->scaleOut = pchanfrom->scaleOut;
+
+ pchanto->rotmode = pchanfrom->rotmode;
+ pchanto->flag = pchanfrom->flag;
+ pchanto->protectflag = pchanfrom->protectflag;
}
/* both poses should be in sync */
bool BKE_pose_copy_result(bPose *to, bPose *from)
{
- bPoseChannel *pchanto, *pchanfrom;
-
- if (to == NULL || from == NULL) {
- CLOG_ERROR(&LOG, "Pose copy error, pose to:%p from:%p", (void *)to, (void *)from); /* debug temp */
- return false;
- }
-
- if (to == from) {
- CLOG_ERROR(&LOG, "source and target are the same");
- return false;
- }
-
- for (pchanfrom = from->chanbase.first; pchanfrom; pchanfrom = pchanfrom->next) {
- pchanto = BKE_pose_channel_find_name(to, pchanfrom->name);
- if (pchanto != NULL) {
- BKE_pose_copyesult_pchan_result(pchanto, pchanfrom);
- }
- }
- return true;
+ bPoseChannel *pchanto, *pchanfrom;
+
+ if (to == NULL || from == NULL) {
+ CLOG_ERROR(
+ &LOG, "Pose copy error, pose to:%p from:%p", (void *)to, (void *)from); /* debug temp */
+ return false;
+ }
+
+ if (to == from) {
+ CLOG_ERROR(&LOG, "source and target are the same");
+ return false;
+ }
+
+ for (pchanfrom = from->chanbase.first; pchanfrom; pchanfrom = pchanfrom->next) {
+ pchanto = BKE_pose_channel_find_name(to, pchanfrom->name);
+ if (pchanto != NULL) {
+ BKE_pose_copyesult_pchan_result(pchanto, pchanfrom);
+ }
+ }
+ return true;
}
/* Tag pose for recalc. Also tag all related data to be recalc. */
void BKE_pose_tag_recalc(Main *bmain, bPose *pose)
{
- pose->flag |= POSE_RECALC;
- /* Depsgraph components depends on actual pose state,
- * if pose was changed depsgraph is to be updated as well.
- */
- DEG_relations_tag_update(bmain);
+ pose->flag |= POSE_RECALC;
+ /* Depsgraph components depends on actual pose state,
+ * if pose was changed depsgraph is to be updated as well.
+ */
+ DEG_relations_tag_update(bmain);
}
/* For the calculation of the effects of an Action at the given frame on an object
* This is currently only used for the Action Constraint
*/
-void what_does_obaction(Object *ob, Object *workob, bPose *pose, bAction *act, char groupname[], float cframe)
+void what_does_obaction(
+ Object *ob, Object *workob, bPose *pose, bAction *act, char groupname[], float cframe)
{
- bActionGroup *agrp = BKE_action_group_find_name(act, groupname);
-
- /* clear workob */
- BKE_object_workob_clear(workob);
-
- /* init workob */
- copy_m4_m4(workob->obmat, ob->obmat);
- copy_m4_m4(workob->parentinv, ob->parentinv);
- copy_m4_m4(workob->constinv, ob->constinv);
- workob->parent = ob->parent;
-
- workob->rotmode = ob->rotmode;
-
- workob->trackflag = ob->trackflag;
- workob->upflag = ob->upflag;
-
- workob->partype = ob->partype;
- workob->par1 = ob->par1;
- workob->par2 = ob->par2;
- workob->par3 = ob->par3;
-
- workob->constraints.first = ob->constraints.first;
- workob->constraints.last = ob->constraints.last;
-
- workob->pose = pose; /* need to set pose too, since this is used for both types of Action Constraint */
- if (pose) {
- /* This function is most likely to be used with a temporary pose with a single bone in there.
- * For such cases it makes no sense to create hash since it'll only waste CPU ticks on memory
- * allocation and also will make lookup slower.
- */
- if (pose->chanbase.first != pose->chanbase.last) {
- BKE_pose_channels_hash_make(pose);
- }
- if (pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
- BKE_pose_update_constraint_flags(pose);
- }
- }
-
- BLI_strncpy(workob->parsubstr, ob->parsubstr, sizeof(workob->parsubstr));
- BLI_strncpy(workob->id.name, "OB<ConstrWorkOb>", sizeof(workob->id.name)); /* we don't use real object name, otherwise RNA screws with the real thing */
-
- /* if we're given a group to use, it's likely to be more efficient (though a bit more dangerous) */
- if (agrp) {
- /* specifically evaluate this group only */
- PointerRNA id_ptr;
-
- /* get RNA-pointer for the workob's ID */
- RNA_id_pointer_create(&workob->id, &id_ptr);
-
- /* execute action for this group only */
- animsys_evaluate_action_group(&id_ptr, act, agrp, cframe);
- }
- else {
- AnimData adt = {NULL};
-
- /* init animdata, and attach to workob */
- workob->adt = &adt;
-
- adt.action = act;
-
- /* execute effects of Action on to workob (or it's PoseChannels) */
- BKE_animsys_evaluate_animdata(NULL, NULL, &workob->id, &adt, cframe, ADT_RECALC_ANIM);
- }
+ bActionGroup *agrp = BKE_action_group_find_name(act, groupname);
+
+ /* clear workob */
+ BKE_object_workob_clear(workob);
+
+ /* init workob */
+ copy_m4_m4(workob->obmat, ob->obmat);
+ copy_m4_m4(workob->parentinv, ob->parentinv);
+ copy_m4_m4(workob->constinv, ob->constinv);
+ workob->parent = ob->parent;
+
+ workob->rotmode = ob->rotmode;
+
+ workob->trackflag = ob->trackflag;
+ workob->upflag = ob->upflag;
+
+ workob->partype = ob->partype;
+ workob->par1 = ob->par1;
+ workob->par2 = ob->par2;
+ workob->par3 = ob->par3;
+
+ workob->constraints.first = ob->constraints.first;
+ workob->constraints.last = ob->constraints.last;
+
+ workob->pose =
+ pose; /* need to set pose too, since this is used for both types of Action Constraint */
+ if (pose) {
+ /* This function is most likely to be used with a temporary pose with a single bone in there.
+ * For such cases it makes no sense to create hash since it'll only waste CPU ticks on memory
+ * allocation and also will make lookup slower.
+ */
+ if (pose->chanbase.first != pose->chanbase.last) {
+ BKE_pose_channels_hash_make(pose);
+ }
+ if (pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
+ BKE_pose_update_constraint_flags(pose);
+ }
+ }
+
+ BLI_strncpy(workob->parsubstr, ob->parsubstr, sizeof(workob->parsubstr));
+ BLI_strncpy(
+ workob->id.name,
+ "OB<ConstrWorkOb>",
+ sizeof(
+ workob->id
+ .name)); /* we don't use real object name, otherwise RNA screws with the real thing */
+
+ /* if we're given a group to use, it's likely to be more efficient (though a bit more dangerous) */
+ if (agrp) {
+ /* specifically evaluate this group only */
+ PointerRNA id_ptr;
+
+ /* get RNA-pointer for the workob's ID */
+ RNA_id_pointer_create(&workob->id, &id_ptr);
+
+ /* execute action for this group only */
+ animsys_evaluate_action_group(&id_ptr, act, agrp, cframe);
+ }
+ else {
+ AnimData adt = {NULL};
+
+ /* init animdata, and attach to workob */
+ workob->adt = &adt;
+
+ adt.action = act;
+
+ /* execute effects of Action on to workob (or it's PoseChannels) */
+ BKE_animsys_evaluate_animdata(NULL, NULL, &workob->id, &adt, cframe, ADT_RECALC_ANIM);
+ }
}
diff --git a/source/blender/blenkernel/intern/addon.c b/source/blender/blenkernel/intern/addon.c
index daeb572ce4a..486da61fe68 100644
--- a/source/blender/blenkernel/intern/addon.c
+++ b/source/blender/blenkernel/intern/addon.c
@@ -28,7 +28,7 @@
#include "BLI_string.h"
#include "BLI_listbase.h"
-#include "BKE_addon.h" /* own include */
+#include "BKE_addon.h" /* own include */
#include "BKE_idprop.h"
#include "DNA_listBase.h"
@@ -46,44 +46,44 @@ static CLG_LogRef LOG = {"bke.addon"};
bAddon *BKE_addon_new(void)
{
- bAddon *addon = MEM_callocN(sizeof(bAddon), "bAddon");
- return addon;
+ bAddon *addon = MEM_callocN(sizeof(bAddon), "bAddon");
+ return addon;
}
bAddon *BKE_addon_find(ListBase *addon_list, const char *module)
{
- return BLI_findstring(addon_list, module, offsetof(bAddon, module));
+ return BLI_findstring(addon_list, module, offsetof(bAddon, module));
}
bAddon *BKE_addon_ensure(ListBase *addon_list, const char *module)
{
- bAddon *addon = BKE_addon_find(addon_list, module);
- if (addon == NULL) {
- addon = BKE_addon_new();
- BLI_strncpy(addon->module, module, sizeof(addon->module));
- BLI_addtail(addon_list, addon);
- }
- return addon;
+ bAddon *addon = BKE_addon_find(addon_list, module);
+ if (addon == NULL) {
+ addon = BKE_addon_new();
+ BLI_strncpy(addon->module, module, sizeof(addon->module));
+ BLI_addtail(addon_list, addon);
+ }
+ return addon;
}
bool BKE_addon_remove_safe(ListBase *addon_list, const char *module)
{
- bAddon *addon = BLI_findstring(addon_list, module, offsetof(bAddon, module));
- if (addon) {
- BLI_remlink(addon_list, addon);
- BKE_addon_free(addon);
- return true;
- }
- return false;
+ bAddon *addon = BLI_findstring(addon_list, module, offsetof(bAddon, module));
+ if (addon) {
+ BLI_remlink(addon_list, addon);
+ BKE_addon_free(addon);
+ return true;
+ }
+ return false;
}
void BKE_addon_free(bAddon *addon)
{
- if (addon->prop) {
- IDP_FreeProperty(addon->prop);
- MEM_freeN(addon->prop);
- }
- MEM_freeN(addon);
+ if (addon->prop) {
+ IDP_FreeProperty(addon->prop);
+ MEM_freeN(addon->prop);
+ }
+ MEM_freeN(addon);
}
/** \} */
@@ -94,50 +94,49 @@ void BKE_addon_free(bAddon *addon)
static GHash *global_addonpreftype_hash = NULL;
-
bAddonPrefType *BKE_addon_pref_type_find(const char *idname, bool quiet)
{
- if (idname[0]) {
- bAddonPrefType *apt;
-
- apt = BLI_ghash_lookup(global_addonpreftype_hash, idname);
- if (apt) {
- return apt;
- }
-
- if (!quiet) {
- CLOG_WARN(&LOG, "search for unknown addon-pref '%s'", idname);
- }
- }
- else {
- if (!quiet) {
- CLOG_WARN(&LOG, "search for empty addon-pref");
- }
- }
-
- return NULL;
+ if (idname[0]) {
+ bAddonPrefType *apt;
+
+ apt = BLI_ghash_lookup(global_addonpreftype_hash, idname);
+ if (apt) {
+ return apt;
+ }
+
+ if (!quiet) {
+ CLOG_WARN(&LOG, "search for unknown addon-pref '%s'", idname);
+ }
+ }
+ else {
+ if (!quiet) {
+ CLOG_WARN(&LOG, "search for empty addon-pref");
+ }
+ }
+
+ return NULL;
}
void BKE_addon_pref_type_add(bAddonPrefType *apt)
{
- BLI_ghash_insert(global_addonpreftype_hash, apt->idname, apt);
+ BLI_ghash_insert(global_addonpreftype_hash, apt->idname, apt);
}
void BKE_addon_pref_type_remove(const bAddonPrefType *apt)
{
- BLI_ghash_remove(global_addonpreftype_hash, apt->idname, NULL, MEM_freeN);
+ BLI_ghash_remove(global_addonpreftype_hash, apt->idname, NULL, MEM_freeN);
}
void BKE_addon_pref_type_init(void)
{
- BLI_assert(global_addonpreftype_hash == NULL);
- global_addonpreftype_hash = BLI_ghash_str_new(__func__);
+ BLI_assert(global_addonpreftype_hash == NULL);
+ global_addonpreftype_hash = BLI_ghash_str_new(__func__);
}
void BKE_addon_pref_type_free(void)
{
- BLI_ghash_free(global_addonpreftype_hash, NULL, MEM_freeN);
- global_addonpreftype_hash = NULL;
+ BLI_ghash_free(global_addonpreftype_hash, NULL, MEM_freeN);
+ global_addonpreftype_hash = NULL;
}
/** \} */
diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c
index 25a657c4745..0e7caca9433 100644
--- a/source/blender/blenkernel/intern/anim.c
+++ b/source/blender/blenkernel/intern/anim.c
@@ -66,21 +66,21 @@ static CLG_LogRef LOG = {"bke.anim"};
/* Initialize the default settings for animation visualization */
void animviz_settings_init(bAnimVizSettings *avs)
{
- /* sanity check */
- if (avs == NULL)
- return;
+ /* sanity check */
+ if (avs == NULL)
+ return;
- /* path settings */
- avs->path_bc = avs->path_ac = 10;
+ /* path settings */
+ avs->path_bc = avs->path_ac = 10;
- avs->path_sf = 1; /* xxx - take from scene instead? */
- avs->path_ef = 250; /* xxx - take from scene instead? */
+ avs->path_sf = 1; /* xxx - take from scene instead? */
+ avs->path_ef = 250; /* xxx - take from scene instead? */
- avs->path_viewflag = (MOTIONPATH_VIEW_KFRAS | MOTIONPATH_VIEW_KFNOS);
+ avs->path_viewflag = (MOTIONPATH_VIEW_KFRAS | MOTIONPATH_VIEW_KFNOS);
- avs->path_step = 1;
+ avs->path_step = 1;
- avs->path_bakeflag |= MOTIONPATH_BAKE_HEADS;
+ avs->path_bakeflag |= MOTIONPATH_BAKE_HEADS;
}
/* ------------------- */
@@ -88,21 +88,21 @@ void animviz_settings_init(bAnimVizSettings *avs)
/* Free the given motion path's cache */
void animviz_free_motionpath_cache(bMotionPath *mpath)
{
- /* sanity check */
- if (mpath == NULL)
- return;
+ /* sanity check */
+ if (mpath == NULL)
+ return;
- /* free the path if necessary */
- if (mpath->points)
- MEM_freeN(mpath->points);
+ /* free the path if necessary */
+ if (mpath->points)
+ MEM_freeN(mpath->points);
- GPU_VERTBUF_DISCARD_SAFE(mpath->points_vbo);
- GPU_BATCH_DISCARD_SAFE(mpath->batch_line);
- GPU_BATCH_DISCARD_SAFE(mpath->batch_points);
+ GPU_VERTBUF_DISCARD_SAFE(mpath->points_vbo);
+ GPU_BATCH_DISCARD_SAFE(mpath->batch_line);
+ GPU_BATCH_DISCARD_SAFE(mpath->batch_points);
- /* reset the relevant parameters */
- mpath->points = NULL;
- mpath->length = 0;
+ /* reset the relevant parameters */
+ mpath->points = NULL;
+ mpath->length = 0;
}
/* Free the given motion path instance and its data
@@ -110,15 +110,15 @@ void animviz_free_motionpath_cache(bMotionPath *mpath)
*/
void animviz_free_motionpath(bMotionPath *mpath)
{
- /* sanity check */
- if (mpath == NULL)
- return;
+ /* sanity check */
+ if (mpath == NULL)
+ return;
- /* free the cache first */
- animviz_free_motionpath_cache(mpath);
+ /* free the cache first */
+ animviz_free_motionpath_cache(mpath);
- /* now the instance itself */
- MEM_freeN(mpath);
+ /* now the instance itself */
+ MEM_freeN(mpath);
}
/* ------------------- */
@@ -126,20 +126,20 @@ void animviz_free_motionpath(bMotionPath *mpath)
/* Make a copy of motionpath data, so that viewing with copy on write works */
bMotionPath *animviz_copy_motionpath(const bMotionPath *mpath_src)
{
- bMotionPath *mpath_dst;
+ bMotionPath *mpath_dst;
- if (mpath_src == NULL)
- return NULL;
+ if (mpath_src == NULL)
+ return NULL;
- mpath_dst = MEM_dupallocN(mpath_src);
- mpath_dst->points = MEM_dupallocN(mpath_src->points);
+ mpath_dst = MEM_dupallocN(mpath_src);
+ mpath_dst->points = MEM_dupallocN(mpath_src->points);
- /* should get recreated on draw... */
- mpath_dst->points_vbo = NULL;
- mpath_dst->batch_line = NULL;
- mpath_dst->batch_points = NULL;
+ /* should get recreated on draw... */
+ mpath_dst->points_vbo = NULL;
+ mpath_dst->batch_line = NULL;
+ mpath_dst->batch_points = NULL;
- return mpath_dst;
+ return mpath_dst;
}
/* ------------------- */
@@ -152,91 +152,96 @@ bMotionPath *animviz_copy_motionpath(const bMotionPath *mpath_src)
* \param ob: Object to add paths for (must be provided)
* \param pchan: Posechannel to add paths for (optional; if not provided, object-paths are assumed)
*/
-bMotionPath *animviz_verify_motionpaths(ReportList *reports, Scene *scene, Object *ob, bPoseChannel *pchan)
+bMotionPath *animviz_verify_motionpaths(ReportList *reports,
+ Scene *scene,
+ Object *ob,
+ bPoseChannel *pchan)
{
- bAnimVizSettings *avs;
- bMotionPath *mpath, **dst;
-
- /* sanity checks */
- if (ELEM(NULL, scene, ob))
- return NULL;
-
- /* get destination data */
- if (pchan) {
- /* paths for posechannel - assume that posechannel belongs to the object */
- avs = &ob->pose->avs;
- dst = &pchan->mpath;
- }
- else {
- /* paths for object */
- avs = &ob->avs;
- dst = &ob->mpath;
- }
-
- /* avoid 0 size allocs */
- if (avs->path_sf >= avs->path_ef) {
- BKE_reportf(reports, RPT_ERROR,
- "Motion path frame extents invalid for %s (%d to %d)%s",
- (pchan) ? pchan->name : ob->id.name,
- avs->path_sf, avs->path_ef,
- (avs->path_sf == avs->path_ef) ? TIP_(", cannot have single-frame paths") : "");
- return NULL;
- }
-
- /* if there is already a motionpath, just return that,
- * provided it's settings are ok (saves extra free+alloc)
- */
- if (*dst != NULL) {
- int expected_length = avs->path_ef - avs->path_sf;
-
- mpath = *dst;
-
- /* path is "valid" if length is valid, but must also be of the same length as is being requested */
- if ((mpath->start_frame != mpath->end_frame) && (mpath->length > 0)) {
- /* outer check ensures that we have some curve data for this path */
- if (mpath->length == expected_length) {
- /* return/use this as it is already valid length */
- return mpath;
- }
- else {
- /* clear the existing path (as the range has changed), and reallocate below */
- animviz_free_motionpath_cache(mpath);
- }
- }
- }
- else {
- /* create a new motionpath, and assign it */
- mpath = MEM_callocN(sizeof(bMotionPath), "bMotionPath");
- *dst = mpath;
- }
-
- /* set settings from the viz settings */
- mpath->start_frame = avs->path_sf;
- mpath->end_frame = avs->path_ef;
-
- mpath->length = mpath->end_frame - mpath->start_frame;
-
- if (avs->path_bakeflag & MOTIONPATH_BAKE_HEADS)
- mpath->flag |= MOTIONPATH_FLAG_BHEAD;
- else
- mpath->flag &= ~MOTIONPATH_FLAG_BHEAD;
-
- /* set default custom values */
- mpath->color[0] = 1.0; /* Red */
- mpath->color[1] = 0.0;
- mpath->color[2] = 0.0;
-
- mpath->line_thickness = 2;
- mpath->flag |= MOTIONPATH_FLAG_LINES; /* draw lines by default */
-
- /* allocate a cache */
- mpath->points = MEM_callocN(sizeof(bMotionPathVert) * mpath->length, "bMotionPathVerts");
-
- /* tag viz settings as currently having some path(s) which use it */
- avs->path_bakeflag |= MOTIONPATH_BAKE_HAS_PATHS;
-
- /* return it */
- return mpath;
+ bAnimVizSettings *avs;
+ bMotionPath *mpath, **dst;
+
+ /* sanity checks */
+ if (ELEM(NULL, scene, ob))
+ return NULL;
+
+ /* get destination data */
+ if (pchan) {
+ /* paths for posechannel - assume that posechannel belongs to the object */
+ avs = &ob->pose->avs;
+ dst = &pchan->mpath;
+ }
+ else {
+ /* paths for object */
+ avs = &ob->avs;
+ dst = &ob->mpath;
+ }
+
+ /* avoid 0 size allocs */
+ if (avs->path_sf >= avs->path_ef) {
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "Motion path frame extents invalid for %s (%d to %d)%s",
+ (pchan) ? pchan->name : ob->id.name,
+ avs->path_sf,
+ avs->path_ef,
+ (avs->path_sf == avs->path_ef) ? TIP_(", cannot have single-frame paths") : "");
+ return NULL;
+ }
+
+ /* if there is already a motionpath, just return that,
+ * provided it's settings are ok (saves extra free+alloc)
+ */
+ if (*dst != NULL) {
+ int expected_length = avs->path_ef - avs->path_sf;
+
+ mpath = *dst;
+
+ /* path is "valid" if length is valid, but must also be of the same length as is being requested */
+ if ((mpath->start_frame != mpath->end_frame) && (mpath->length > 0)) {
+ /* outer check ensures that we have some curve data for this path */
+ if (mpath->length == expected_length) {
+ /* return/use this as it is already valid length */
+ return mpath;
+ }
+ else {
+ /* clear the existing path (as the range has changed), and reallocate below */
+ animviz_free_motionpath_cache(mpath);
+ }
+ }
+ }
+ else {
+ /* create a new motionpath, and assign it */
+ mpath = MEM_callocN(sizeof(bMotionPath), "bMotionPath");
+ *dst = mpath;
+ }
+
+ /* set settings from the viz settings */
+ mpath->start_frame = avs->path_sf;
+ mpath->end_frame = avs->path_ef;
+
+ mpath->length = mpath->end_frame - mpath->start_frame;
+
+ if (avs->path_bakeflag & MOTIONPATH_BAKE_HEADS)
+ mpath->flag |= MOTIONPATH_FLAG_BHEAD;
+ else
+ mpath->flag &= ~MOTIONPATH_FLAG_BHEAD;
+
+ /* set default custom values */
+ mpath->color[0] = 1.0; /* Red */
+ mpath->color[1] = 0.0;
+ mpath->color[2] = 0.0;
+
+ mpath->line_thickness = 2;
+ mpath->flag |= MOTIONPATH_FLAG_LINES; /* draw lines by default */
+
+ /* allocate a cache */
+ mpath->points = MEM_callocN(sizeof(bMotionPathVert) * mpath->length, "bMotionPathVerts");
+
+ /* tag viz settings as currently having some path(s) which use it */
+ avs->path_bakeflag |= MOTIONPATH_BAKE_HAS_PATHS;
+
+ /* return it */
+ return mpath;
}
/* ******************************************************************** */
@@ -248,8 +253,9 @@ bMotionPath *animviz_verify_motionpaths(ReportList *reports, Scene *scene, Objec
*/
void free_path(Path *path)
{
- if (path->data) MEM_freeN(path->data);
- MEM_freeN(path);
+ if (path->data)
+ MEM_freeN(path->data);
+ MEM_freeN(path);
}
/* calculate a curve-deform path for a curve
@@ -257,129 +263,132 @@ void free_path(Path *path)
*/
void calc_curvepath(Object *ob, ListBase *nurbs)
{
- BevList *bl;
- BevPoint *bevp, *bevpn, *bevpfirst, *bevplast;
- PathPoint *pp;
- Nurb *nu;
- Path *path;
- float *fp, *dist, *maxdist, xyz[3];
- float fac, d = 0, fac1, fac2;
- int a, tot, cycl = 0;
-
- /* in a path vertices are with equal differences: path->len = number of verts */
- /* NOW WITH BEVELCURVE!!! */
-
- if (ob == NULL || ob->type != OB_CURVE) {
- return;
- }
-
- if (ob->runtime.curve_cache->path) free_path(ob->runtime.curve_cache->path);
- ob->runtime.curve_cache->path = NULL;
-
- /* weak! can only use first curve */
- bl = ob->runtime.curve_cache->bev.first;
- if (bl == NULL || !bl->nr) {
- return;
- }
-
- nu = nurbs->first;
-
- ob->runtime.curve_cache->path = path = MEM_callocN(sizeof(Path), "calc_curvepath");
-
- /* if POLY: last vertice != first vertice */
- cycl = (bl->poly != -1);
-
- tot = cycl ? bl->nr : bl->nr - 1;
-
- path->len = tot + 1;
- /* exception: vector handle paths and polygon paths should be subdivided at least a factor resolu */
- if (path->len < nu->resolu * SEGMENTSU(nu)) {
- path->len = nu->resolu * SEGMENTSU(nu);
- }
-
- dist = (float *)MEM_mallocN(sizeof(float) * (tot + 1), "calcpathdist");
-
- /* all lengths in *dist */
- bevp = bevpfirst = bl->bevpoints;
- fp = dist;
- *fp = 0.0f;
- for (a = 0; a < tot; a++) {
- fp++;
- if (cycl && a == tot - 1)
- sub_v3_v3v3(xyz, bevpfirst->vec, bevp->vec);
- else
- sub_v3_v3v3(xyz, (bevp + 1)->vec, bevp->vec);
-
- *fp = *(fp - 1) + len_v3(xyz);
- bevp++;
- }
-
- path->totdist = *fp;
-
- /* the path verts in path->data */
- /* now also with TILT value */
- pp = path->data = (PathPoint *)MEM_callocN(sizeof(PathPoint) * path->len, "pathdata");
-
- bevp = bevpfirst;
- bevpn = bevp + 1;
- bevplast = bevpfirst + (bl->nr - 1);
- if (UNLIKELY(bevpn > bevplast)) {
- bevpn = cycl ? bevpfirst : bevplast;
- }
- fp = dist + 1;
- maxdist = dist + tot;
- fac = 1.0f / ((float)path->len - 1.0f);
- fac = fac * path->totdist;
-
- for (a = 0; a < path->len; a++) {
-
- d = ((float)a) * fac;
-
- /* we're looking for location (distance) 'd' in the array */
- if (LIKELY(tot > 0)) {
- while ((fp < maxdist) && (d >= *fp)) {
- fp++;
- if (bevp < bevplast) bevp++;
- bevpn = bevp + 1;
- if (UNLIKELY(bevpn > bevplast)) {
- bevpn = cycl ? bevpfirst : bevplast;
- }
- }
-
- fac1 = (*(fp) - d) / (*(fp) - *(fp - 1));
- fac2 = 1.0f - fac1;
- }
- else {
- fac1 = 1.0f;
- fac2 = 0.0f;
- }
-
- interp_v3_v3v3(pp->vec, bevp->vec, bevpn->vec, fac2);
- pp->vec[3] = fac1 * bevp->tilt + fac2 * bevpn->tilt;
- pp->radius = fac1 * bevp->radius + fac2 * bevpn->radius;
- pp->weight = fac1 * bevp->weight + fac2 * bevpn->weight;
- interp_qt_qtqt(pp->quat, bevp->quat, bevpn->quat, fac2);
- normalize_qt(pp->quat);
-
- pp++;
- }
-
- MEM_freeN(dist);
+ BevList *bl;
+ BevPoint *bevp, *bevpn, *bevpfirst, *bevplast;
+ PathPoint *pp;
+ Nurb *nu;
+ Path *path;
+ float *fp, *dist, *maxdist, xyz[3];
+ float fac, d = 0, fac1, fac2;
+ int a, tot, cycl = 0;
+
+ /* in a path vertices are with equal differences: path->len = number of verts */
+ /* NOW WITH BEVELCURVE!!! */
+
+ if (ob == NULL || ob->type != OB_CURVE) {
+ return;
+ }
+
+ if (ob->runtime.curve_cache->path)
+ free_path(ob->runtime.curve_cache->path);
+ ob->runtime.curve_cache->path = NULL;
+
+ /* weak! can only use first curve */
+ bl = ob->runtime.curve_cache->bev.first;
+ if (bl == NULL || !bl->nr) {
+ return;
+ }
+
+ nu = nurbs->first;
+
+ ob->runtime.curve_cache->path = path = MEM_callocN(sizeof(Path), "calc_curvepath");
+
+ /* if POLY: last vertice != first vertice */
+ cycl = (bl->poly != -1);
+
+ tot = cycl ? bl->nr : bl->nr - 1;
+
+ path->len = tot + 1;
+ /* exception: vector handle paths and polygon paths should be subdivided at least a factor resolu */
+ if (path->len < nu->resolu * SEGMENTSU(nu)) {
+ path->len = nu->resolu * SEGMENTSU(nu);
+ }
+
+ dist = (float *)MEM_mallocN(sizeof(float) * (tot + 1), "calcpathdist");
+
+ /* all lengths in *dist */
+ bevp = bevpfirst = bl->bevpoints;
+ fp = dist;
+ *fp = 0.0f;
+ for (a = 0; a < tot; a++) {
+ fp++;
+ if (cycl && a == tot - 1)
+ sub_v3_v3v3(xyz, bevpfirst->vec, bevp->vec);
+ else
+ sub_v3_v3v3(xyz, (bevp + 1)->vec, bevp->vec);
+
+ *fp = *(fp - 1) + len_v3(xyz);
+ bevp++;
+ }
+
+ path->totdist = *fp;
+
+ /* the path verts in path->data */
+ /* now also with TILT value */
+ pp = path->data = (PathPoint *)MEM_callocN(sizeof(PathPoint) * path->len, "pathdata");
+
+ bevp = bevpfirst;
+ bevpn = bevp + 1;
+ bevplast = bevpfirst + (bl->nr - 1);
+ if (UNLIKELY(bevpn > bevplast)) {
+ bevpn = cycl ? bevpfirst : bevplast;
+ }
+ fp = dist + 1;
+ maxdist = dist + tot;
+ fac = 1.0f / ((float)path->len - 1.0f);
+ fac = fac * path->totdist;
+
+ for (a = 0; a < path->len; a++) {
+
+ d = ((float)a) * fac;
+
+ /* we're looking for location (distance) 'd' in the array */
+ if (LIKELY(tot > 0)) {
+ while ((fp < maxdist) && (d >= *fp)) {
+ fp++;
+ if (bevp < bevplast)
+ bevp++;
+ bevpn = bevp + 1;
+ if (UNLIKELY(bevpn > bevplast)) {
+ bevpn = cycl ? bevpfirst : bevplast;
+ }
+ }
+
+ fac1 = (*(fp)-d) / (*(fp) - *(fp - 1));
+ fac2 = 1.0f - fac1;
+ }
+ else {
+ fac1 = 1.0f;
+ fac2 = 0.0f;
+ }
+
+ interp_v3_v3v3(pp->vec, bevp->vec, bevpn->vec, fac2);
+ pp->vec[3] = fac1 * bevp->tilt + fac2 * bevpn->tilt;
+ pp->radius = fac1 * bevp->radius + fac2 * bevpn->radius;
+ pp->weight = fac1 * bevp->weight + fac2 * bevpn->weight;
+ interp_qt_qtqt(pp->quat, bevp->quat, bevpn->quat, fac2);
+ normalize_qt(pp->quat);
+
+ pp++;
+ }
+
+ MEM_freeN(dist);
}
static int interval_test(const int min, const int max, int p1, const int cycl)
{
- if (cycl) {
- p1 = mod_i(p1 - min, (max - min + 1)) + min;
- }
- else {
- if (p1 < min) p1 = min;
- else if (p1 > max) p1 = max;
- }
- return p1;
+ if (cycl) {
+ p1 = mod_i(p1 - min, (max - min + 1)) + min;
+ }
+ else {
+ if (p1 < min)
+ p1 = min;
+ else if (p1 > max)
+ p1 = max;
+ }
+ return p1;
}
-
/* calculate the deformation implied by the curve path at a given parametric position,
* and returns whether this operation succeeded.
*
@@ -387,105 +396,132 @@ static int interval_test(const int min, const int max, int p1, const int cycl)
*
* returns OK: 1/0
*/
-int where_on_path(Object *ob, float ctime, float vec[4], float dir[3], float quat[4], float *radius, float *weight)
+int where_on_path(Object *ob,
+ float ctime,
+ float vec[4],
+ float dir[3],
+ float quat[4],
+ float *radius,
+ float *weight)
{
- Curve *cu;
- Nurb *nu;
- BevList *bl;
- Path *path;
- PathPoint *pp, *p0, *p1, *p2, *p3;
- float fac;
- float data[4];
- int cycl = 0, s0, s1, s2, s3;
- ListBase *nurbs;
-
- if (ob == NULL || ob->type != OB_CURVE) return 0;
- cu = ob->data;
- if (ob->runtime.curve_cache == NULL || ob->runtime.curve_cache->path == NULL || ob->runtime.curve_cache->path->data == NULL) {
- CLOG_WARN(&LOG, "no path!");
- return 0;
- }
- path = ob->runtime.curve_cache->path;
- pp = path->data;
-
- /* test for cyclic */
- bl = ob->runtime.curve_cache->bev.first;
- if (!bl) return 0;
- if (!bl->nr) return 0;
- if (bl->poly > -1) cycl = 1;
-
- /* values below zero for non-cyclic curves give strange results */
- BLI_assert(cycl || ctime >= 0.0f);
-
- ctime *= (path->len - 1);
-
- s1 = (int)floor(ctime);
- fac = (float)(s1 + 1) - ctime;
-
- /* path->len is corrected for cyclic */
- s0 = interval_test(0, path->len - 1 - cycl, s1 - 1, cycl);
- s1 = interval_test(0, path->len - 1 - cycl, s1, cycl);
- s2 = interval_test(0, path->len - 1 - cycl, s1 + 1, cycl);
- s3 = interval_test(0, path->len - 1 - cycl, s1 + 2, cycl);
-
- p0 = pp + s0;
- p1 = pp + s1;
- p2 = pp + s2;
- p3 = pp + s3;
-
- /* NOTE: commented out for follow constraint
- *
- * If it's ever be uncommented watch out for curve_deform_verts()
- * which used to temporary set CU_FOLLOW flag for the curve and no
- * longer does it (because of threading issues of such a thing.
- */
- //if (cu->flag & CU_FOLLOW) {
-
- key_curve_tangent_weights(1.0f - fac, data, KEY_BSPLINE);
-
- interp_v3_v3v3v3v3(dir, p0->vec, p1->vec, p2->vec, p3->vec, data);
-
- /* make compatible with vectoquat */
- negate_v3(dir);
- //}
-
- nurbs = BKE_curve_editNurbs_get(cu);
- if (!nurbs)
- nurbs = &cu->nurb;
- nu = nurbs->first;
-
- /* make sure that first and last frame are included in the vectors here */
- if (nu->type == CU_POLY) key_curve_position_weights(1.0f - fac, data, KEY_LINEAR);
- else if (nu->type == CU_BEZIER) key_curve_position_weights(1.0f - fac, data, KEY_LINEAR);
- else if (s0 == s1 || p2 == p3) key_curve_position_weights(1.0f - fac, data, KEY_CARDINAL);
- else key_curve_position_weights(1.0f - fac, data, KEY_BSPLINE);
-
- vec[0] = data[0] * p0->vec[0] + data[1] * p1->vec[0] + data[2] * p2->vec[0] + data[3] * p3->vec[0]; /* X */
- vec[1] = data[0] * p0->vec[1] + data[1] * p1->vec[1] + data[2] * p2->vec[1] + data[3] * p3->vec[1]; /* Y */
- vec[2] = data[0] * p0->vec[2] + data[1] * p1->vec[2] + data[2] * p2->vec[2] + data[3] * p3->vec[2]; /* Z */
- vec[3] = data[0] * p0->vec[3] + data[1] * p1->vec[3] + data[2] * p2->vec[3] + data[3] * p3->vec[3]; /* Tilt, should not be needed since we have quat still used */
-
- if (quat) {
- float totfac, q1[4], q2[4];
-
- totfac = data[0] + data[3];
- if (totfac > FLT_EPSILON) interp_qt_qtqt(q1, p0->quat, p3->quat, data[3] / totfac);
- else copy_qt_qt(q1, p1->quat);
-
- totfac = data[1] + data[2];
- if (totfac > FLT_EPSILON) interp_qt_qtqt(q2, p1->quat, p2->quat, data[2] / totfac);
- else copy_qt_qt(q2, p3->quat);
-
- totfac = data[0] + data[1] + data[2] + data[3];
- if (totfac > FLT_EPSILON) interp_qt_qtqt(quat, q1, q2, (data[1] + data[2]) / totfac);
- else copy_qt_qt(quat, q2);
- }
-
- if (radius)
- *radius = data[0] * p0->radius + data[1] * p1->radius + data[2] * p2->radius + data[3] * p3->radius;
-
- if (weight)
- *weight = data[0] * p0->weight + data[1] * p1->weight + data[2] * p2->weight + data[3] * p3->weight;
-
- return 1;
+ Curve *cu;
+ Nurb *nu;
+ BevList *bl;
+ Path *path;
+ PathPoint *pp, *p0, *p1, *p2, *p3;
+ float fac;
+ float data[4];
+ int cycl = 0, s0, s1, s2, s3;
+ ListBase *nurbs;
+
+ if (ob == NULL || ob->type != OB_CURVE)
+ return 0;
+ cu = ob->data;
+ if (ob->runtime.curve_cache == NULL || ob->runtime.curve_cache->path == NULL ||
+ ob->runtime.curve_cache->path->data == NULL) {
+ CLOG_WARN(&LOG, "no path!");
+ return 0;
+ }
+ path = ob->runtime.curve_cache->path;
+ pp = path->data;
+
+ /* test for cyclic */
+ bl = ob->runtime.curve_cache->bev.first;
+ if (!bl)
+ return 0;
+ if (!bl->nr)
+ return 0;
+ if (bl->poly > -1)
+ cycl = 1;
+
+ /* values below zero for non-cyclic curves give strange results */
+ BLI_assert(cycl || ctime >= 0.0f);
+
+ ctime *= (path->len - 1);
+
+ s1 = (int)floor(ctime);
+ fac = (float)(s1 + 1) - ctime;
+
+ /* path->len is corrected for cyclic */
+ s0 = interval_test(0, path->len - 1 - cycl, s1 - 1, cycl);
+ s1 = interval_test(0, path->len - 1 - cycl, s1, cycl);
+ s2 = interval_test(0, path->len - 1 - cycl, s1 + 1, cycl);
+ s3 = interval_test(0, path->len - 1 - cycl, s1 + 2, cycl);
+
+ p0 = pp + s0;
+ p1 = pp + s1;
+ p2 = pp + s2;
+ p3 = pp + s3;
+
+ /* NOTE: commented out for follow constraint
+ *
+ * If it's ever be uncommented watch out for curve_deform_verts()
+ * which used to temporary set CU_FOLLOW flag for the curve and no
+ * longer does it (because of threading issues of such a thing.
+ */
+ //if (cu->flag & CU_FOLLOW) {
+
+ key_curve_tangent_weights(1.0f - fac, data, KEY_BSPLINE);
+
+ interp_v3_v3v3v3v3(dir, p0->vec, p1->vec, p2->vec, p3->vec, data);
+
+ /* make compatible with vectoquat */
+ negate_v3(dir);
+ //}
+
+ nurbs = BKE_curve_editNurbs_get(cu);
+ if (!nurbs)
+ nurbs = &cu->nurb;
+ nu = nurbs->first;
+
+ /* make sure that first and last frame are included in the vectors here */
+ if (nu->type == CU_POLY)
+ key_curve_position_weights(1.0f - fac, data, KEY_LINEAR);
+ else if (nu->type == CU_BEZIER)
+ key_curve_position_weights(1.0f - fac, data, KEY_LINEAR);
+ else if (s0 == s1 || p2 == p3)
+ key_curve_position_weights(1.0f - fac, data, KEY_CARDINAL);
+ else
+ key_curve_position_weights(1.0f - fac, data, KEY_BSPLINE);
+
+ vec[0] = data[0] * p0->vec[0] + data[1] * p1->vec[0] + data[2] * p2->vec[0] +
+ data[3] * p3->vec[0]; /* X */
+ vec[1] = data[0] * p0->vec[1] + data[1] * p1->vec[1] + data[2] * p2->vec[1] +
+ data[3] * p3->vec[1]; /* Y */
+ vec[2] = data[0] * p0->vec[2] + data[1] * p1->vec[2] + data[2] * p2->vec[2] +
+ data[3] * p3->vec[2]; /* Z */
+ vec[3] = data[0] * p0->vec[3] + data[1] * p1->vec[3] + data[2] * p2->vec[3] +
+ data[3] * p3->vec[3]; /* Tilt, should not be needed since we have quat still used */
+
+ if (quat) {
+ float totfac, q1[4], q2[4];
+
+ totfac = data[0] + data[3];
+ if (totfac > FLT_EPSILON)
+ interp_qt_qtqt(q1, p0->quat, p3->quat, data[3] / totfac);
+ else
+ copy_qt_qt(q1, p1->quat);
+
+ totfac = data[1] + data[2];
+ if (totfac > FLT_EPSILON)
+ interp_qt_qtqt(q2, p1->quat, p2->quat, data[2] / totfac);
+ else
+ copy_qt_qt(q2, p3->quat);
+
+ totfac = data[0] + data[1] + data[2] + data[3];
+ if (totfac > FLT_EPSILON)
+ interp_qt_qtqt(quat, q1, q2, (data[1] + data[2]) / totfac);
+ else
+ copy_qt_qt(quat, q2);
+ }
+
+ if (radius)
+ *radius = data[0] * p0->radius + data[1] * p1->radius + data[2] * p2->radius +
+ data[3] * p3->radius;
+
+ if (weight)
+ *weight = data[0] * p0->weight + data[1] * p1->weight + data[2] * p2->weight +
+ data[3] * p3->weight;
+
+ return 1;
}
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index 33f19caf1cc..75244a8ba8a 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -21,7 +21,6 @@
* \ingroup bke
*/
-
#include <stdio.h>
#include <string.h>
#include <stddef.h>
@@ -84,39 +83,47 @@ static CLG_LogRef LOG = {"bke.anim_sys"};
/* Check if ID can have AnimData */
bool id_type_can_have_animdata(const short id_type)
{
- /* Only some ID-blocks have this info for now */
- /* TODO: finish adding this for the other blocktypes */
- switch (id_type) {
- /* has AnimData */
- case ID_OB:
- case ID_ME: case ID_MB: case ID_CU: case ID_AR: case ID_LT:
- case ID_KE:
- case ID_PA:
- case ID_MA: case ID_TE: case ID_NT:
- case ID_LA: case ID_CA: case ID_WO:
- case ID_LS:
- case ID_LP:
- case ID_SPK:
- case ID_SCE:
- case ID_MC:
- case ID_MSK:
- case ID_GD:
- case ID_CF:
- return true;
-
- /* no AnimData */
- default:
- return false;
- }
+ /* Only some ID-blocks have this info for now */
+ /* TODO: finish adding this for the other blocktypes */
+ switch (id_type) {
+ /* has AnimData */
+ case ID_OB:
+ case ID_ME:
+ case ID_MB:
+ case ID_CU:
+ case ID_AR:
+ case ID_LT:
+ case ID_KE:
+ case ID_PA:
+ case ID_MA:
+ case ID_TE:
+ case ID_NT:
+ case ID_LA:
+ case ID_CA:
+ case ID_WO:
+ case ID_LS:
+ case ID_LP:
+ case ID_SPK:
+ case ID_SCE:
+ case ID_MC:
+ case ID_MSK:
+ case ID_GD:
+ case ID_CF:
+ return true;
+
+ /* no AnimData */
+ default:
+ return false;
+ }
}
bool id_can_have_animdata(const ID *id)
{
- /* sanity check */
- if (id == NULL)
- return false;
+ /* sanity check */
+ if (id == NULL)
+ return false;
- return id_type_can_have_animdata(GS(id->name));
+ return id_type_can_have_animdata(GS(id->name));
}
/* Get AnimData from the given ID-block. In order for this to work, we assume that
@@ -125,16 +132,16 @@ bool id_can_have_animdata(const ID *id)
*/
AnimData *BKE_animdata_from_id(ID *id)
{
- /* only some ID-blocks have this info for now, so we cast the
- * types that do to be of type IdAdtTemplate, and extract the
- * AnimData that way
- */
- if (id_can_have_animdata(id)) {
- IdAdtTemplate *iat = (IdAdtTemplate *)id;
- return iat->adt;
- }
- else
- return NULL;
+ /* only some ID-blocks have this info for now, so we cast the
+ * types that do to be of type IdAdtTemplate, and extract the
+ * AnimData that way
+ */
+ if (id_can_have_animdata(id)) {
+ IdAdtTemplate *iat = (IdAdtTemplate *)id;
+ return iat->adt;
+ }
+ else
+ return NULL;
}
/* Add AnimData to the given ID-block. In order for this to work, we assume that
@@ -143,28 +150,28 @@ AnimData *BKE_animdata_from_id(ID *id)
*/
AnimData *BKE_animdata_add_id(ID *id)
{
- /* Only some ID-blocks have this info for now, so we cast the
- * types that do to be of type IdAdtTemplate, and add the AnimData
- * to it using the template
- */
- if (id_can_have_animdata(id)) {
- IdAdtTemplate *iat = (IdAdtTemplate *)id;
+ /* Only some ID-blocks have this info for now, so we cast the
+ * types that do to be of type IdAdtTemplate, and add the AnimData
+ * to it using the template
+ */
+ if (id_can_have_animdata(id)) {
+ IdAdtTemplate *iat = (IdAdtTemplate *)id;
- /* check if there's already AnimData, in which case, don't add */
- if (iat->adt == NULL) {
- AnimData *adt;
+ /* check if there's already AnimData, in which case, don't add */
+ if (iat->adt == NULL) {
+ AnimData *adt;
- /* add animdata */
- adt = iat->adt = MEM_callocN(sizeof(AnimData), "AnimData");
+ /* add animdata */
+ adt = iat->adt = MEM_callocN(sizeof(AnimData), "AnimData");
- /* set default settings */
- adt->act_influence = 1.0f;
- }
+ /* set default settings */
+ adt->act_influence = 1.0f;
+ }
- return iat->adt;
- }
- else
- return NULL;
+ return iat->adt;
+ }
+ else
+ return NULL;
}
/* Action Setter --------------------------------------- */
@@ -172,52 +179,56 @@ AnimData *BKE_animdata_add_id(ID *id)
/* Called when user tries to change the active action of an AnimData block (via RNA, Outliner, etc.) */
bool BKE_animdata_set_action(ReportList *reports, ID *id, bAction *act)
{
- AnimData *adt = BKE_animdata_from_id(id);
- bool ok = false;
-
- /* animdata validity check */
- if (adt == NULL) {
- BKE_report(reports, RPT_WARNING, "No AnimData to set action on");
- return ok;
- }
-
- /* active action is only editable when it is not a tweaking strip
- * see rna_AnimData_action_editable() in rna_animation.c
- */
- if ((adt->flag & ADT_NLA_EDIT_ON) || (adt->actstrip) || (adt->tmpact)) {
- /* cannot remove, otherwise things turn to custard */
- BKE_report(reports, RPT_ERROR, "Cannot change action, as it is still being edited in NLA");
- return ok;
- }
-
- /* manage usercount for current action */
- if (adt->action)
- id_us_min((ID *)adt->action);
-
- /* assume that AnimData's action can in fact be edited... */
- if (act) {
- /* action must have same type as owner */
- if (ELEM(act->idroot, 0, GS(id->name))) {
- /* can set */
- adt->action = act;
- id_us_plus((ID *)adt->action);
- ok = true;
- }
- else {
- /* cannot set */
- BKE_reportf(reports, RPT_ERROR,
- "Could not set action '%s' onto ID '%s', as it does not have suitably rooted paths "
- "for this purpose", act->id.name + 2, id->name);
- /* ok = false; */
- }
- }
- else {
- /* just clearing the action... */
- adt->action = NULL;
- ok = true;
- }
-
- return ok;
+ AnimData *adt = BKE_animdata_from_id(id);
+ bool ok = false;
+
+ /* animdata validity check */
+ if (adt == NULL) {
+ BKE_report(reports, RPT_WARNING, "No AnimData to set action on");
+ return ok;
+ }
+
+ /* active action is only editable when it is not a tweaking strip
+ * see rna_AnimData_action_editable() in rna_animation.c
+ */
+ if ((adt->flag & ADT_NLA_EDIT_ON) || (adt->actstrip) || (adt->tmpact)) {
+ /* cannot remove, otherwise things turn to custard */
+ BKE_report(reports, RPT_ERROR, "Cannot change action, as it is still being edited in NLA");
+ return ok;
+ }
+
+ /* manage usercount for current action */
+ if (adt->action)
+ id_us_min((ID *)adt->action);
+
+ /* assume that AnimData's action can in fact be edited... */
+ if (act) {
+ /* action must have same type as owner */
+ if (ELEM(act->idroot, 0, GS(id->name))) {
+ /* can set */
+ adt->action = act;
+ id_us_plus((ID *)adt->action);
+ ok = true;
+ }
+ else {
+ /* cannot set */
+ BKE_reportf(
+ reports,
+ RPT_ERROR,
+ "Could not set action '%s' onto ID '%s', as it does not have suitably rooted paths "
+ "for this purpose",
+ act->id.name + 2,
+ id->name);
+ /* ok = false; */
+ }
+ }
+ else {
+ /* just clearing the action... */
+ adt->action = NULL;
+ ok = true;
+ }
+
+ return ok;
}
/* Freeing -------------------------------------------- */
@@ -225,41 +236,41 @@ bool BKE_animdata_set_action(ReportList *reports, ID *id, bAction *act)
/* Free AnimData used by the nominated ID-block, and clear ID-block's AnimData pointer */
void BKE_animdata_free(ID *id, const bool do_id_user)
{
- /* Only some ID-blocks have this info for now, so we cast the
- * types that do to be of type IdAdtTemplate
- */
- if (id_can_have_animdata(id)) {
- IdAdtTemplate *iat = (IdAdtTemplate *)id;
- AnimData *adt = iat->adt;
+ /* Only some ID-blocks have this info for now, so we cast the
+ * types that do to be of type IdAdtTemplate
+ */
+ if (id_can_have_animdata(id)) {
+ IdAdtTemplate *iat = (IdAdtTemplate *)id;
+ AnimData *adt = iat->adt;
- /* check if there's any AnimData to start with */
- if (adt) {
- if (do_id_user) {
- /* unlink action (don't free, as it's in its own list) */
- if (adt->action)
- id_us_min(&adt->action->id);
- /* same goes for the temporarily displaced action */
- if (adt->tmpact)
- id_us_min(&adt->tmpact->id);
- }
+ /* check if there's any AnimData to start with */
+ if (adt) {
+ if (do_id_user) {
+ /* unlink action (don't free, as it's in its own list) */
+ if (adt->action)
+ id_us_min(&adt->action->id);
+ /* same goes for the temporarily displaced action */
+ if (adt->tmpact)
+ id_us_min(&adt->tmpact->id);
+ }
- /* free nla data */
- BKE_nla_tracks_free(&adt->nla_tracks, do_id_user);
+ /* free nla data */
+ BKE_nla_tracks_free(&adt->nla_tracks, do_id_user);
- /* free drivers - stored as a list of F-Curves */
- free_fcurves(&adt->drivers);
+ /* free drivers - stored as a list of F-Curves */
+ free_fcurves(&adt->drivers);
- /* free driver array cache */
- MEM_SAFE_FREE(adt->driver_array);
+ /* free driver array cache */
+ MEM_SAFE_FREE(adt->driver_array);
- /* free overrides */
- /* TODO... */
+ /* free overrides */
+ /* TODO... */
- /* free animdata now */
- MEM_freeN(adt);
- iat->adt = NULL;
- }
- }
+ /* free animdata now */
+ MEM_freeN(adt);
+ iat->adt = NULL;
+ }
+ }
}
/* Copying -------------------------------------------- */
@@ -271,39 +282,39 @@ void BKE_animdata_free(ID *id, const bool do_id_user)
*/
AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const int flag)
{
- AnimData *dadt;
+ AnimData *dadt;
- const bool do_action = (flag & LIB_ID_COPY_ACTIONS) != 0 && (flag & LIB_ID_CREATE_NO_MAIN) == 0;
- const bool do_id_user = (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0;
+ const bool do_action = (flag & LIB_ID_COPY_ACTIONS) != 0 && (flag & LIB_ID_CREATE_NO_MAIN) == 0;
+ const bool do_id_user = (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0;
- /* sanity check before duplicating struct */
- if (adt == NULL)
- return NULL;
- dadt = MEM_dupallocN(adt);
+ /* sanity check before duplicating struct */
+ if (adt == NULL)
+ return NULL;
+ dadt = MEM_dupallocN(adt);
- /* make a copy of action - at worst, user has to delete copies... */
- if (do_action) {
- BLI_assert(bmain != NULL);
- BKE_id_copy(bmain, (ID *)dadt->action, (ID **)&dadt->action);
- BKE_id_copy(bmain, (ID *)dadt->tmpact, (ID **)&dadt->tmpact);
- }
- else if (do_id_user) {
- id_us_plus((ID *)dadt->action);
- id_us_plus((ID *)dadt->tmpact);
- }
+ /* make a copy of action - at worst, user has to delete copies... */
+ if (do_action) {
+ BLI_assert(bmain != NULL);
+ BKE_id_copy(bmain, (ID *)dadt->action, (ID **)&dadt->action);
+ BKE_id_copy(bmain, (ID *)dadt->tmpact, (ID **)&dadt->tmpact);
+ }
+ else if (do_id_user) {
+ id_us_plus((ID *)dadt->action);
+ id_us_plus((ID *)dadt->tmpact);
+ }
- /* duplicate NLA data */
- BKE_nla_tracks_copy(bmain, &dadt->nla_tracks, &adt->nla_tracks, flag);
+ /* duplicate NLA data */
+ BKE_nla_tracks_copy(bmain, &dadt->nla_tracks, &adt->nla_tracks, flag);
- /* duplicate drivers (F-Curves) */
- copy_fcurves(&dadt->drivers, &adt->drivers);
- dadt->driver_array = NULL;
+ /* duplicate drivers (F-Curves) */
+ copy_fcurves(&dadt->drivers, &adt->drivers);
+ dadt->driver_array = NULL;
- /* don't copy overrides */
- BLI_listbase_clear(&dadt->overrides);
+ /* don't copy overrides */
+ BLI_listbase_clear(&dadt->overrides);
- /* return */
- return dadt;
+ /* return */
+ return dadt;
}
/**
@@ -312,110 +323,110 @@ AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const int flag)
*/
bool BKE_animdata_copy_id(Main *bmain, ID *id_to, ID *id_from, const int flag)
{
- AnimData *adt;
+ AnimData *adt;
- if ((id_to && id_from) && (GS(id_to->name) != GS(id_from->name)))
- return false;
+ if ((id_to && id_from) && (GS(id_to->name) != GS(id_from->name)))
+ return false;
- BKE_animdata_free(id_to, (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0);
+ BKE_animdata_free(id_to, (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0);
- adt = BKE_animdata_from_id(id_from);
- if (adt) {
- IdAdtTemplate *iat = (IdAdtTemplate *)id_to;
- iat->adt = BKE_animdata_copy(bmain, adt, flag);
- }
+ adt = BKE_animdata_from_id(id_from);
+ if (adt) {
+ IdAdtTemplate *iat = (IdAdtTemplate *)id_to;
+ iat->adt = BKE_animdata_copy(bmain, adt, flag);
+ }
- return true;
+ return true;
}
void BKE_animdata_copy_id_action(Main *bmain, ID *id, const bool set_newid)
{
- AnimData *adt = BKE_animdata_from_id(id);
- if (adt) {
- if (adt->action) {
- id_us_min((ID *)adt->action);
- adt->action = set_newid ? ID_NEW_SET(adt->action, BKE_action_copy(bmain, adt->action)) :
- BKE_action_copy(bmain, adt->action);
- }
- if (adt->tmpact) {
- id_us_min((ID *)adt->tmpact);
- adt->tmpact = set_newid ? ID_NEW_SET(adt->tmpact, BKE_action_copy(bmain, adt->tmpact)) :
- BKE_action_copy(bmain, adt->tmpact);
- }
- }
+ AnimData *adt = BKE_animdata_from_id(id);
+ if (adt) {
+ if (adt->action) {
+ id_us_min((ID *)adt->action);
+ adt->action = set_newid ? ID_NEW_SET(adt->action, BKE_action_copy(bmain, adt->action)) :
+ BKE_action_copy(bmain, adt->action);
+ }
+ if (adt->tmpact) {
+ id_us_min((ID *)adt->tmpact);
+ adt->tmpact = set_newid ? ID_NEW_SET(adt->tmpact, BKE_action_copy(bmain, adt->tmpact)) :
+ BKE_action_copy(bmain, adt->tmpact);
+ }
+ }
}
/* Merge copies of the data from the src AnimData into the destination AnimData */
void BKE_animdata_merge_copy(
- Main *bmain, ID *dst_id, ID *src_id,
- eAnimData_MergeCopy_Modes action_mode, bool fix_drivers)
-{
- AnimData *src = BKE_animdata_from_id(src_id);
- AnimData *dst = BKE_animdata_from_id(dst_id);
-
- /* sanity checks */
- if (ELEM(NULL, dst, src))
- return;
-
- // TODO: we must unset all "tweakmode" flags
- if ((src->flag & ADT_NLA_EDIT_ON) || (dst->flag & ADT_NLA_EDIT_ON)) {
- CLOG_ERROR(&LOG, "Merging AnimData blocks while editing NLA is dangerous as it may cause data corruption");
- return;
- }
-
- /* handle actions... */
- if (action_mode == ADT_MERGECOPY_SRC_COPY) {
- /* make a copy of the actions */
- dst->action = BKE_action_copy(bmain, src->action);
- dst->tmpact = BKE_action_copy(bmain, src->tmpact);
- }
- else if (action_mode == ADT_MERGECOPY_SRC_REF) {
- /* make a reference to it */
- dst->action = src->action;
- id_us_plus((ID *)dst->action);
-
- dst->tmpact = src->tmpact;
- id_us_plus((ID *)dst->tmpact);
- }
-
- /* duplicate NLA data */
- if (src->nla_tracks.first) {
- ListBase tracks = {NULL, NULL};
-
- BKE_nla_tracks_copy(bmain, &tracks, &src->nla_tracks, 0);
- BLI_movelisttolist(&dst->nla_tracks, &tracks);
- }
-
- /* duplicate drivers (F-Curves) */
- if (src->drivers.first) {
- ListBase drivers = {NULL, NULL};
-
- copy_fcurves(&drivers, &src->drivers);
-
- /* Fix up all driver targets using the old target id
- * - This assumes that the src ID is being merged into the dst ID
- */
- if (fix_drivers) {
- FCurve *fcu;
-
- for (fcu = drivers.first; fcu; fcu = fcu->next) {
- ChannelDriver *driver = fcu->driver;
- DriverVar *dvar;
-
- for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
- DRIVER_TARGETS_USED_LOOPER_BEGIN(dvar)
- {
- if (dtar->id == src_id) {
- dtar->id = dst_id;
- }
- }
- DRIVER_TARGETS_LOOPER_END;
- }
- }
- }
-
- BLI_movelisttolist(&dst->drivers, &drivers);
- }
+ Main *bmain, ID *dst_id, ID *src_id, eAnimData_MergeCopy_Modes action_mode, bool fix_drivers)
+{
+ AnimData *src = BKE_animdata_from_id(src_id);
+ AnimData *dst = BKE_animdata_from_id(dst_id);
+
+ /* sanity checks */
+ if (ELEM(NULL, dst, src))
+ return;
+
+ // TODO: we must unset all "tweakmode" flags
+ if ((src->flag & ADT_NLA_EDIT_ON) || (dst->flag & ADT_NLA_EDIT_ON)) {
+ CLOG_ERROR(
+ &LOG,
+ "Merging AnimData blocks while editing NLA is dangerous as it may cause data corruption");
+ return;
+ }
+
+ /* handle actions... */
+ if (action_mode == ADT_MERGECOPY_SRC_COPY) {
+ /* make a copy of the actions */
+ dst->action = BKE_action_copy(bmain, src->action);
+ dst->tmpact = BKE_action_copy(bmain, src->tmpact);
+ }
+ else if (action_mode == ADT_MERGECOPY_SRC_REF) {
+ /* make a reference to it */
+ dst->action = src->action;
+ id_us_plus((ID *)dst->action);
+
+ dst->tmpact = src->tmpact;
+ id_us_plus((ID *)dst->tmpact);
+ }
+
+ /* duplicate NLA data */
+ if (src->nla_tracks.first) {
+ ListBase tracks = {NULL, NULL};
+
+ BKE_nla_tracks_copy(bmain, &tracks, &src->nla_tracks, 0);
+ BLI_movelisttolist(&dst->nla_tracks, &tracks);
+ }
+
+ /* duplicate drivers (F-Curves) */
+ if (src->drivers.first) {
+ ListBase drivers = {NULL, NULL};
+
+ copy_fcurves(&drivers, &src->drivers);
+
+ /* Fix up all driver targets using the old target id
+ * - This assumes that the src ID is being merged into the dst ID
+ */
+ if (fix_drivers) {
+ FCurve *fcu;
+
+ for (fcu = drivers.first; fcu; fcu = fcu->next) {
+ ChannelDriver *driver = fcu->driver;
+ DriverVar *dvar;
+
+ for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
+ DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
+ if (dtar->id == src_id) {
+ dtar->id = dst_id;
+ }
+ }
+ DRIVER_TARGETS_LOOPER_END;
+ }
+ }
+ }
+
+ BLI_movelisttolist(&dst->drivers, &drivers);
+ }
}
/* Sub-ID Regrouping ------------------------------------------- */
@@ -429,8 +440,8 @@ void BKE_animdata_merge_copy(
*/
static bool animpath_matches_basepath(const char path[], const char basepath[])
{
- /* we need start of path to be basepath */
- return (path && basepath) && STRPREFIX(path, basepath);
+ /* we need start of path to be basepath */
+ return (path && basepath) && STRPREFIX(path, basepath);
}
/* Move F-Curves in src action to dst action, setting up all the necessary groups
@@ -441,155 +452,160 @@ static bool animpath_matches_basepath(const char path[], const char basepath[])
*/
void action_move_fcurves_by_basepath(bAction *srcAct, bAction *dstAct, const char basepath[])
{
- FCurve *fcu, *fcn = NULL;
-
- /* sanity checks */
- if (ELEM(NULL, srcAct, dstAct, basepath)) {
- if (G.debug & G_DEBUG) {
- CLOG_ERROR(&LOG, "srcAct: %p, dstAct: %p, basepath: %p has insufficient info to work with",
- (void *)srcAct, (void *)dstAct, (void *)basepath);
- }
- return;
- }
-
- /* clear 'temp' flags on all groups in src, as we'll be needing them later
- * to identify groups that we've managed to empty out here
- */
- action_groups_clear_tempflags(srcAct);
-
- /* iterate over all src F-Curves, moving over the ones that need to be moved */
- for (fcu = srcAct->curves.first; fcu; fcu = fcn) {
- /* store next pointer in case we move stuff */
- fcn = fcu->next;
-
- /* should F-Curve be moved over?
- * - we only need the start of the path to match basepath
- */
- if (animpath_matches_basepath(fcu->rna_path, basepath)) {
- bActionGroup *agrp = NULL;
-
- /* if grouped... */
- if (fcu->grp) {
- /* make sure there will be a matching group on the other side for the migrants */
- agrp = BKE_action_group_find_name(dstAct, fcu->grp->name);
-
- if (agrp == NULL) {
- /* add a new one with a similar name (usually will be the same though) */
- agrp = action_groups_add_new(dstAct, fcu->grp->name);
- }
-
- /* old groups should be tagged with 'temp' flags so they can be removed later
- * if we remove everything from them
- */
- fcu->grp->flag |= AGRP_TEMP;
- }
-
- /* perform the migration now */
- action_groups_remove_channel(srcAct, fcu);
-
- if (agrp)
- action_groups_add_channel(dstAct, agrp, fcu);
- else
- BLI_addtail(&dstAct->curves, fcu);
- }
- }
-
- /* cleanup groups (if present) */
- if (srcAct->groups.first) {
- bActionGroup *agrp, *grp = NULL;
-
- for (agrp = srcAct->groups.first; agrp; agrp = grp) {
- grp = agrp->next;
-
- /* only tagged groups need to be considered - clearing these tags or removing them */
- if (agrp->flag & AGRP_TEMP) {
- /* if group is empty and tagged, then we can remove as this operation
- * moved out all the channels that were formerly here
- */
- if (BLI_listbase_is_empty(&agrp->channels))
- BLI_freelinkN(&srcAct->groups, agrp);
- else
- agrp->flag &= ~AGRP_TEMP;
- }
- }
- }
+ FCurve *fcu, *fcn = NULL;
+
+ /* sanity checks */
+ if (ELEM(NULL, srcAct, dstAct, basepath)) {
+ if (G.debug & G_DEBUG) {
+ CLOG_ERROR(&LOG,
+ "srcAct: %p, dstAct: %p, basepath: %p has insufficient info to work with",
+ (void *)srcAct,
+ (void *)dstAct,
+ (void *)basepath);
+ }
+ return;
+ }
+
+ /* clear 'temp' flags on all groups in src, as we'll be needing them later
+ * to identify groups that we've managed to empty out here
+ */
+ action_groups_clear_tempflags(srcAct);
+
+ /* iterate over all src F-Curves, moving over the ones that need to be moved */
+ for (fcu = srcAct->curves.first; fcu; fcu = fcn) {
+ /* store next pointer in case we move stuff */
+ fcn = fcu->next;
+
+ /* should F-Curve be moved over?
+ * - we only need the start of the path to match basepath
+ */
+ if (animpath_matches_basepath(fcu->rna_path, basepath)) {
+ bActionGroup *agrp = NULL;
+
+ /* if grouped... */
+ if (fcu->grp) {
+ /* make sure there will be a matching group on the other side for the migrants */
+ agrp = BKE_action_group_find_name(dstAct, fcu->grp->name);
+
+ if (agrp == NULL) {
+ /* add a new one with a similar name (usually will be the same though) */
+ agrp = action_groups_add_new(dstAct, fcu->grp->name);
+ }
+
+ /* old groups should be tagged with 'temp' flags so they can be removed later
+ * if we remove everything from them
+ */
+ fcu->grp->flag |= AGRP_TEMP;
+ }
+
+ /* perform the migration now */
+ action_groups_remove_channel(srcAct, fcu);
+
+ if (agrp)
+ action_groups_add_channel(dstAct, agrp, fcu);
+ else
+ BLI_addtail(&dstAct->curves, fcu);
+ }
+ }
+
+ /* cleanup groups (if present) */
+ if (srcAct->groups.first) {
+ bActionGroup *agrp, *grp = NULL;
+
+ for (agrp = srcAct->groups.first; agrp; agrp = grp) {
+ grp = agrp->next;
+
+ /* only tagged groups need to be considered - clearing these tags or removing them */
+ if (agrp->flag & AGRP_TEMP) {
+ /* if group is empty and tagged, then we can remove as this operation
+ * moved out all the channels that were formerly here
+ */
+ if (BLI_listbase_is_empty(&agrp->channels))
+ BLI_freelinkN(&srcAct->groups, agrp);
+ else
+ agrp->flag &= ~AGRP_TEMP;
+ }
+ }
+ }
}
/* Transfer the animation data from srcID to dstID where the srcID
* animation data is based off "basepath", creating new AnimData and
* associated data as necessary
*/
-void BKE_animdata_separate_by_basepath(
- Main *bmain, ID *srcID, ID *dstID, ListBase *basepaths)
-{
- AnimData *srcAdt = NULL, *dstAdt = NULL;
- LinkData *ld;
-
- /* sanity checks */
- if (ELEM(NULL, srcID, dstID)) {
- if (G.debug & G_DEBUG)
- CLOG_ERROR(&LOG, "no source or destination ID to separate AnimData with");
- return;
- }
-
- /* get animdata from src, and create for destination (if needed) */
- srcAdt = BKE_animdata_from_id(srcID);
- dstAdt = BKE_animdata_add_id(dstID);
-
- if (ELEM(NULL, srcAdt, dstAdt)) {
- if (G.debug & G_DEBUG)
- CLOG_ERROR(&LOG, "no AnimData for this pair of ID's");
- return;
- }
-
- /* active action */
- if (srcAdt->action) {
- /* set up an action if necessary, and name it in a similar way so that it can be easily found again */
- if (dstAdt->action == NULL) {
- dstAdt->action = BKE_action_add(bmain, srcAdt->action->id.name + 2);
- }
- else if (dstAdt->action == srcAdt->action) {
- CLOG_WARN(&LOG, "Argh! Source and Destination share animation! "
- "('%s' and '%s' both use '%s') Making new empty action",
- srcID->name, dstID->name, srcAdt->action->id.name);
-
- /* TODO: review this... */
- id_us_min(&dstAdt->action->id);
- dstAdt->action = BKE_action_add(bmain, dstAdt->action->id.name + 2);
- }
-
- /* loop over base paths, trying to fix for each one... */
- for (ld = basepaths->first; ld; ld = ld->next) {
- const char *basepath = (const char *)ld->data;
- action_move_fcurves_by_basepath(srcAdt->action, dstAdt->action, basepath);
- }
- }
-
- /* drivers */
- if (srcAdt->drivers.first) {
- FCurve *fcu, *fcn = NULL;
-
- /* check each driver against all the base paths to see if any should go */
- for (fcu = srcAdt->drivers.first; fcu; fcu = fcn) {
- fcn = fcu->next;
-
- /* try each basepath in turn, but stop on the first one which works */
- for (ld = basepaths->first; ld; ld = ld->next) {
- const char *basepath = (const char *)ld->data;
-
- if (animpath_matches_basepath(fcu->rna_path, basepath)) {
- /* just need to change lists */
- BLI_remlink(&srcAdt->drivers, fcu);
- BLI_addtail(&dstAdt->drivers, fcu);
-
- /* TODO: add depsgraph flushing calls? */
-
- /* can stop now, as moved already */
- break;
- }
- }
- }
- }
+void BKE_animdata_separate_by_basepath(Main *bmain, ID *srcID, ID *dstID, ListBase *basepaths)
+{
+ AnimData *srcAdt = NULL, *dstAdt = NULL;
+ LinkData *ld;
+
+ /* sanity checks */
+ if (ELEM(NULL, srcID, dstID)) {
+ if (G.debug & G_DEBUG)
+ CLOG_ERROR(&LOG, "no source or destination ID to separate AnimData with");
+ return;
+ }
+
+ /* get animdata from src, and create for destination (if needed) */
+ srcAdt = BKE_animdata_from_id(srcID);
+ dstAdt = BKE_animdata_add_id(dstID);
+
+ if (ELEM(NULL, srcAdt, dstAdt)) {
+ if (G.debug & G_DEBUG)
+ CLOG_ERROR(&LOG, "no AnimData for this pair of ID's");
+ return;
+ }
+
+ /* active action */
+ if (srcAdt->action) {
+ /* set up an action if necessary, and name it in a similar way so that it can be easily found again */
+ if (dstAdt->action == NULL) {
+ dstAdt->action = BKE_action_add(bmain, srcAdt->action->id.name + 2);
+ }
+ else if (dstAdt->action == srcAdt->action) {
+ CLOG_WARN(&LOG,
+ "Argh! Source and Destination share animation! "
+ "('%s' and '%s' both use '%s') Making new empty action",
+ srcID->name,
+ dstID->name,
+ srcAdt->action->id.name);
+
+ /* TODO: review this... */
+ id_us_min(&dstAdt->action->id);
+ dstAdt->action = BKE_action_add(bmain, dstAdt->action->id.name + 2);
+ }
+
+ /* loop over base paths, trying to fix for each one... */
+ for (ld = basepaths->first; ld; ld = ld->next) {
+ const char *basepath = (const char *)ld->data;
+ action_move_fcurves_by_basepath(srcAdt->action, dstAdt->action, basepath);
+ }
+ }
+
+ /* drivers */
+ if (srcAdt->drivers.first) {
+ FCurve *fcu, *fcn = NULL;
+
+ /* check each driver against all the base paths to see if any should go */
+ for (fcu = srcAdt->drivers.first; fcu; fcu = fcn) {
+ fcn = fcu->next;
+
+ /* try each basepath in turn, but stop on the first one which works */
+ for (ld = basepaths->first; ld; ld = ld->next) {
+ const char *basepath = (const char *)ld->data;
+
+ if (animpath_matches_basepath(fcu->rna_path, basepath)) {
+ /* just need to change lists */
+ BLI_remlink(&srcAdt->drivers, fcu);
+ BLI_addtail(&dstAdt->drivers, fcu);
+
+ /* TODO: add depsgraph flushing calls? */
+
+ /* can stop now, as moved already */
+ break;
+ }
+ }
+ }
+ }
}
/**
@@ -602,36 +618,39 @@ void BKE_animdata_separate_by_basepath(
* \param prop: RNA definition of property to add for
* \return MEM_alloc'd string representing the path to the property from the given #PointerRNA
*/
-char *BKE_animdata_driver_path_hack(bContext *C, PointerRNA *ptr, PropertyRNA *prop, char *base_path)
+char *BKE_animdata_driver_path_hack(bContext *C,
+ PointerRNA *ptr,
+ PropertyRNA *prop,
+ char *base_path)
{
- ID *id = (ID *)ptr->id.data;
- ScrArea *sa = CTX_wm_area(C);
+ ID *id = (ID *)ptr->id.data;
+ ScrArea *sa = CTX_wm_area(C);
- /* get standard path which may be extended */
- char *basepath = base_path ? base_path : RNA_path_from_ID_to_property(ptr, prop);
- char *path = basepath; /* in case no remapping is needed */
+ /* get standard path which may be extended */
+ char *basepath = base_path ? base_path : RNA_path_from_ID_to_property(ptr, prop);
+ char *path = basepath; /* in case no remapping is needed */
- /* Remapping will only be performed in the Properties Editor, as only this
- * restricts the subspace of options to the 'active' data (a manageable state)
- */
- /* TODO: watch out for pinned context? */
- if ((sa) && (sa->spacetype == SPACE_PROPERTIES)) {
- Object *ob = CTX_data_active_object(C);
+ /* Remapping will only be performed in the Properties Editor, as only this
+ * restricts the subspace of options to the 'active' data (a manageable state)
+ */
+ /* TODO: watch out for pinned context? */
+ if ((sa) && (sa->spacetype == SPACE_PROPERTIES)) {
+ Object *ob = CTX_data_active_object(C);
- if (ob && id) {
- /* TODO: after material textures were removed, this function serves
- * no purpose anymore, but could be used again so was not removed. */
+ if (ob && id) {
+ /* TODO: after material textures were removed, this function serves
+ * no purpose anymore, but could be used again so was not removed. */
- /* fix RNA pointer, as we've now changed the ID root by changing the paths */
- if (basepath != path) {
- /* rebase provided pointer so that it starts from object... */
- RNA_pointer_create(&ob->id, ptr->type, ptr->data, ptr);
- }
- }
- }
+ /* fix RNA pointer, as we've now changed the ID root by changing the paths */
+ if (basepath != path) {
+ /* rebase provided pointer so that it starts from object... */
+ RNA_pointer_create(&ob->id, ptr->type, ptr->data, ptr);
+ }
+ }
+ }
- /* the path should now have been corrected for use */
- return path;
+ /* the path should now have been corrected for use */
+ return path;
}
/* Path Validation -------------------------------------------- */
@@ -639,164 +658,190 @@ char *BKE_animdata_driver_path_hack(bContext *C, PointerRNA *ptr, PropertyRNA *p
/* Check if a given RNA Path is valid, by tracing it from the given ID, and seeing if we can resolve it */
static bool check_rna_path_is_valid(ID *owner_id, const char *path)
{
- PointerRNA id_ptr, ptr;
- PropertyRNA *prop = NULL;
+ PointerRNA id_ptr, ptr;
+ PropertyRNA *prop = NULL;
- /* make initial RNA pointer to start resolving from */
- RNA_id_pointer_create(owner_id, &id_ptr);
+ /* make initial RNA pointer to start resolving from */
+ RNA_id_pointer_create(owner_id, &id_ptr);
- /* try to resolve */
- return RNA_path_resolve_property(&id_ptr, path, &ptr, &prop);
+ /* try to resolve */
+ return RNA_path_resolve_property(&id_ptr, path, &ptr, &prop);
}
/* Check if some given RNA Path needs fixing - free the given path and set a new one as appropriate
* NOTE: we assume that oldName and newName have [" "] padding around them
*/
-static char *rna_path_rename_fix(ID *owner_id, const char *prefix, const char *oldName, const char *newName, char *oldpath, bool verify_paths)
-{
- char *prefixPtr = strstr(oldpath, prefix);
- char *oldNamePtr = strstr(oldpath, oldName);
- int prefixLen = strlen(prefix);
- int oldNameLen = strlen(oldName);
-
- /* only start fixing the path if the prefix and oldName feature in the path,
- * and prefix occurs immediately before oldName
- */
- if ( (prefixPtr && oldNamePtr) && (prefixPtr + prefixLen == oldNamePtr) ) {
- /* if we haven't aren't able to resolve the path now, try again after fixing it */
- if (!verify_paths || check_rna_path_is_valid(owner_id, oldpath) == 0) {
- DynStr *ds = BLI_dynstr_new();
- const char *postfixPtr = oldNamePtr + oldNameLen;
- char *newPath = NULL;
-
- /* add the part of the string that goes up to the start of the prefix */
- if (prefixPtr > oldpath) {
- BLI_dynstr_nappend(ds, oldpath, prefixPtr - oldpath);
- }
-
- /* add the prefix */
- BLI_dynstr_append(ds, prefix);
-
- /* add the new name (complete with brackets) */
- BLI_dynstr_append(ds, newName);
-
- /* add the postfix */
- BLI_dynstr_append(ds, postfixPtr);
-
- /* create new path, and cleanup old data */
- newPath = BLI_dynstr_get_cstring(ds);
- BLI_dynstr_free(ds);
-
- /* check if the new path will solve our problems */
- /* TODO: will need to check whether this step really helps in practice */
- if (!verify_paths || check_rna_path_is_valid(owner_id, newPath)) {
- /* free the old path, and return the new one, since we've solved the issues */
- MEM_freeN(oldpath);
- return newPath;
- }
- else {
- /* still couldn't resolve the path... so, might as well just leave it alone */
- MEM_freeN(newPath);
- }
- }
- }
-
- /* the old path doesn't need to be changed */
- return oldpath;
+static char *rna_path_rename_fix(ID *owner_id,
+ const char *prefix,
+ const char *oldName,
+ const char *newName,
+ char *oldpath,
+ bool verify_paths)
+{
+ char *prefixPtr = strstr(oldpath, prefix);
+ char *oldNamePtr = strstr(oldpath, oldName);
+ int prefixLen = strlen(prefix);
+ int oldNameLen = strlen(oldName);
+
+ /* only start fixing the path if the prefix and oldName feature in the path,
+ * and prefix occurs immediately before oldName
+ */
+ if ((prefixPtr && oldNamePtr) && (prefixPtr + prefixLen == oldNamePtr)) {
+ /* if we haven't aren't able to resolve the path now, try again after fixing it */
+ if (!verify_paths || check_rna_path_is_valid(owner_id, oldpath) == 0) {
+ DynStr *ds = BLI_dynstr_new();
+ const char *postfixPtr = oldNamePtr + oldNameLen;
+ char *newPath = NULL;
+
+ /* add the part of the string that goes up to the start of the prefix */
+ if (prefixPtr > oldpath) {
+ BLI_dynstr_nappend(ds, oldpath, prefixPtr - oldpath);
+ }
+
+ /* add the prefix */
+ BLI_dynstr_append(ds, prefix);
+
+ /* add the new name (complete with brackets) */
+ BLI_dynstr_append(ds, newName);
+
+ /* add the postfix */
+ BLI_dynstr_append(ds, postfixPtr);
+
+ /* create new path, and cleanup old data */
+ newPath = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+
+ /* check if the new path will solve our problems */
+ /* TODO: will need to check whether this step really helps in practice */
+ if (!verify_paths || check_rna_path_is_valid(owner_id, newPath)) {
+ /* free the old path, and return the new one, since we've solved the issues */
+ MEM_freeN(oldpath);
+ return newPath;
+ }
+ else {
+ /* still couldn't resolve the path... so, might as well just leave it alone */
+ MEM_freeN(newPath);
+ }
+ }
+ }
+
+ /* the old path doesn't need to be changed */
+ return oldpath;
}
/* Check RNA-Paths for a list of F-Curves */
-static bool fcurves_path_rename_fix(ID *owner_id, const char *prefix, const char *oldName, const char *newName,
- const char *oldKey, const char *newKey, ListBase *curves, bool verify_paths)
-{
- FCurve *fcu;
- bool is_changed = false;
- /* We need to check every curve. */
- for (fcu = curves->first; fcu; fcu = fcu->next) {
- if (fcu->rna_path == NULL) {
- continue;
- }
- const char *old_path = fcu->rna_path;
- /* Firstly, handle the F-Curve's own path. */
- fcu->rna_path = rna_path_rename_fix(owner_id, prefix, oldKey, newKey, fcu->rna_path, verify_paths);
- /* if path changed and the F-Curve is grouped, check if its group also needs renaming
- * (i.e. F-Curve is first of a bone's F-Curves; hence renaming this should also trigger rename) */
- if (fcu->rna_path != old_path) {
- bActionGroup *agrp = fcu->grp;
- is_changed = true;
- if ((agrp != NULL) && STREQ(oldName, agrp->name)) {
- BLI_strncpy(agrp->name, newName, sizeof(agrp->name));
- }
- }
- }
- return is_changed;
+static bool fcurves_path_rename_fix(ID *owner_id,
+ const char *prefix,
+ const char *oldName,
+ const char *newName,
+ const char *oldKey,
+ const char *newKey,
+ ListBase *curves,
+ bool verify_paths)
+{
+ FCurve *fcu;
+ bool is_changed = false;
+ /* We need to check every curve. */
+ for (fcu = curves->first; fcu; fcu = fcu->next) {
+ if (fcu->rna_path == NULL) {
+ continue;
+ }
+ const char *old_path = fcu->rna_path;
+ /* Firstly, handle the F-Curve's own path. */
+ fcu->rna_path = rna_path_rename_fix(
+ owner_id, prefix, oldKey, newKey, fcu->rna_path, verify_paths);
+ /* if path changed and the F-Curve is grouped, check if its group also needs renaming
+ * (i.e. F-Curve is first of a bone's F-Curves; hence renaming this should also trigger rename) */
+ if (fcu->rna_path != old_path) {
+ bActionGroup *agrp = fcu->grp;
+ is_changed = true;
+ if ((agrp != NULL) && STREQ(oldName, agrp->name)) {
+ BLI_strncpy(agrp->name, newName, sizeof(agrp->name));
+ }
+ }
+ }
+ return is_changed;
}
/* Check RNA-Paths for a list of Drivers */
-static bool drivers_path_rename_fix(ID *owner_id, ID *ref_id, const char *prefix, const char *oldName, const char *newName,
- const char *oldKey, const char *newKey, ListBase *curves, bool verify_paths)
-{
- bool is_changed = false;
- FCurve *fcu;
- /* We need to check every curve - drivers are F-Curves too. */
- for (fcu = curves->first; fcu; fcu = fcu->next) {
- /* firstly, handle the F-Curve's own path */
- if (fcu->rna_path != NULL) {
- const char *old_rna_path = fcu->rna_path;
- fcu->rna_path = rna_path_rename_fix(owner_id, prefix, oldKey, newKey, fcu->rna_path, verify_paths);
- is_changed |= (fcu->rna_path != old_rna_path);
- }
- if (fcu->driver == NULL) {
- continue;
- }
- ChannelDriver *driver = fcu->driver;
- DriverVar *dvar;
- /* driver variables */
- for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
- /* only change the used targets, since the others will need fixing manually anyway */
- DRIVER_TARGETS_USED_LOOPER_BEGIN(dvar)
- {
- /* rename RNA path */
- if (dtar->rna_path && dtar->id) {
- const char *old_rna_path = dtar->rna_path;
- dtar->rna_path = rna_path_rename_fix(dtar->id, prefix, oldKey, newKey, dtar->rna_path, verify_paths);
- is_changed |= (dtar->rna_path != old_rna_path);
- }
- /* also fix the bone-name (if applicable) */
- if (strstr(prefix, "bones")) {
- if ( ((dtar->id) && (GS(dtar->id->name) == ID_OB) && (!ref_id || ((Object *)(dtar->id))->data == ref_id)) &&
- (dtar->pchan_name[0]) && STREQ(oldName, dtar->pchan_name) )
- {
- is_changed = true;
- BLI_strncpy(dtar->pchan_name, newName, sizeof(dtar->pchan_name));
- }
- }
- }
- DRIVER_TARGETS_LOOPER_END;
- }
- }
- return is_changed;
+static bool drivers_path_rename_fix(ID *owner_id,
+ ID *ref_id,
+ const char *prefix,
+ const char *oldName,
+ const char *newName,
+ const char *oldKey,
+ const char *newKey,
+ ListBase *curves,
+ bool verify_paths)
+{
+ bool is_changed = false;
+ FCurve *fcu;
+ /* We need to check every curve - drivers are F-Curves too. */
+ for (fcu = curves->first; fcu; fcu = fcu->next) {
+ /* firstly, handle the F-Curve's own path */
+ if (fcu->rna_path != NULL) {
+ const char *old_rna_path = fcu->rna_path;
+ fcu->rna_path = rna_path_rename_fix(
+ owner_id, prefix, oldKey, newKey, fcu->rna_path, verify_paths);
+ is_changed |= (fcu->rna_path != old_rna_path);
+ }
+ if (fcu->driver == NULL) {
+ continue;
+ }
+ ChannelDriver *driver = fcu->driver;
+ DriverVar *dvar;
+ /* driver variables */
+ for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
+ /* only change the used targets, since the others will need fixing manually anyway */
+ DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
+ /* rename RNA path */
+ if (dtar->rna_path && dtar->id) {
+ const char *old_rna_path = dtar->rna_path;
+ dtar->rna_path = rna_path_rename_fix(
+ dtar->id, prefix, oldKey, newKey, dtar->rna_path, verify_paths);
+ is_changed |= (dtar->rna_path != old_rna_path);
+ }
+ /* also fix the bone-name (if applicable) */
+ if (strstr(prefix, "bones")) {
+ if (((dtar->id) && (GS(dtar->id->name) == ID_OB) &&
+ (!ref_id || ((Object *)(dtar->id))->data == ref_id)) &&
+ (dtar->pchan_name[0]) && STREQ(oldName, dtar->pchan_name)) {
+ is_changed = true;
+ BLI_strncpy(dtar->pchan_name, newName, sizeof(dtar->pchan_name));
+ }
+ }
+ }
+ DRIVER_TARGETS_LOOPER_END;
+ }
+ }
+ return is_changed;
}
/* Fix all RNA-Paths for Actions linked to NLA Strips */
-static bool nlastrips_path_rename_fix(ID *owner_id, const char *prefix, const char *oldName, const char *newName,
- const char *oldKey, const char *newKey, ListBase *strips, bool verify_paths)
-{
- NlaStrip *strip;
- bool is_changed = false;
- /* Recursively check strips, fixing only actions. */
- for (strip = strips->first; strip; strip = strip->next) {
- /* fix strip's action */
- if (strip->act != NULL) {
- is_changed |= fcurves_path_rename_fix(
- owner_id, prefix, oldName, newName, oldKey, newKey, &strip->act->curves, verify_paths);
- }
- /* Ignore own F-Curves, since those are local. */
- /* Check sub-strips (if metas) */
- is_changed |= nlastrips_path_rename_fix(
- owner_id, prefix, oldName, newName, oldKey, newKey, &strip->strips, verify_paths);
- }
- return is_changed;
+static bool nlastrips_path_rename_fix(ID *owner_id,
+ const char *prefix,
+ const char *oldName,
+ const char *newName,
+ const char *oldKey,
+ const char *newKey,
+ ListBase *strips,
+ bool verify_paths)
+{
+ NlaStrip *strip;
+ bool is_changed = false;
+ /* Recursively check strips, fixing only actions. */
+ for (strip = strips->first; strip; strip = strip->next) {
+ /* fix strip's action */
+ if (strip->act != NULL) {
+ is_changed |= fcurves_path_rename_fix(
+ owner_id, prefix, oldName, newName, oldKey, newKey, &strip->act->curves, verify_paths);
+ }
+ /* Ignore own F-Curves, since those are local. */
+ /* Check sub-strips (if metas) */
+ is_changed |= nlastrips_path_rename_fix(
+ owner_id, prefix, oldName, newName, oldKey, newKey, &strip->strips, verify_paths);
+ }
+ return is_changed;
}
/* Rename Sub-ID Entities in RNA Paths ----------------------- */
@@ -809,47 +854,56 @@ static bool nlastrips_path_rename_fix(ID *owner_id, const char *prefix, const ch
* NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]>
* i.e. pose.bones["Bone"]
*/
-char *BKE_animsys_fix_rna_path_rename(ID *owner_id, char *old_path, const char *prefix, const char *oldName,
- const char *newName, int oldSubscript, int newSubscript, bool verify_paths)
-{
- char *oldN, *newN;
- char *result;
-
- /* if no action, no need to proceed */
- if (ELEM(NULL, owner_id, old_path)) {
- if (G.debug & G_DEBUG) CLOG_WARN(&LOG, "early abort");
- return old_path;
- }
-
- /* Name sanitation logic - copied from BKE_animdata_fix_paths_rename() */
- if ((oldName != NULL) && (newName != NULL)) {
- /* pad the names with [" "] so that only exact matches are made */
- const size_t name_old_len = strlen(oldName);
- const size_t name_new_len = strlen(newName);
- char *name_old_esc = BLI_array_alloca(name_old_esc, (name_old_len * 2) + 1);
- char *name_new_esc = BLI_array_alloca(name_new_esc, (name_new_len * 2) + 1);
-
- BLI_strescape(name_old_esc, oldName, (name_old_len * 2) + 1);
- BLI_strescape(name_new_esc, newName, (name_new_len * 2) + 1);
- oldN = BLI_sprintfN("[\"%s\"]", name_old_esc);
- newN = BLI_sprintfN("[\"%s\"]", name_new_esc);
- }
- else {
- oldN = BLI_sprintfN("[%d]", oldSubscript);
- newN = BLI_sprintfN("[%d]", newSubscript);
- }
-
- /* fix given path */
- if (G.debug & G_DEBUG) printf("%s | %s | oldpath = %p ", oldN, newN, old_path);
- result = rna_path_rename_fix(owner_id, prefix, oldN, newN, old_path, verify_paths);
- if (G.debug & G_DEBUG) printf("path rename result = %p\n", result);
-
- /* free the temp names */
- MEM_freeN(oldN);
- MEM_freeN(newN);
-
- /* return the resulting path - may be the same path again if nothing changed */
- return result;
+char *BKE_animsys_fix_rna_path_rename(ID *owner_id,
+ char *old_path,
+ const char *prefix,
+ const char *oldName,
+ const char *newName,
+ int oldSubscript,
+ int newSubscript,
+ bool verify_paths)
+{
+ char *oldN, *newN;
+ char *result;
+
+ /* if no action, no need to proceed */
+ if (ELEM(NULL, owner_id, old_path)) {
+ if (G.debug & G_DEBUG)
+ CLOG_WARN(&LOG, "early abort");
+ return old_path;
+ }
+
+ /* Name sanitation logic - copied from BKE_animdata_fix_paths_rename() */
+ if ((oldName != NULL) && (newName != NULL)) {
+ /* pad the names with [" "] so that only exact matches are made */
+ const size_t name_old_len = strlen(oldName);
+ const size_t name_new_len = strlen(newName);
+ char *name_old_esc = BLI_array_alloca(name_old_esc, (name_old_len * 2) + 1);
+ char *name_new_esc = BLI_array_alloca(name_new_esc, (name_new_len * 2) + 1);
+
+ BLI_strescape(name_old_esc, oldName, (name_old_len * 2) + 1);
+ BLI_strescape(name_new_esc, newName, (name_new_len * 2) + 1);
+ oldN = BLI_sprintfN("[\"%s\"]", name_old_esc);
+ newN = BLI_sprintfN("[\"%s\"]", name_new_esc);
+ }
+ else {
+ oldN = BLI_sprintfN("[%d]", oldSubscript);
+ newN = BLI_sprintfN("[%d]", newSubscript);
+ }
+
+ /* fix given path */
+ if (G.debug & G_DEBUG)
+ printf("%s | %s | oldpath = %p ", oldN, newN, old_path);
+ result = rna_path_rename_fix(owner_id, prefix, oldN, newN, old_path, verify_paths);
+ if (G.debug & G_DEBUG)
+ printf("path rename result = %p\n", result);
+
+ /* free the temp names */
+ MEM_freeN(oldN);
+ MEM_freeN(newN);
+
+ /* return the resulting path - may be the same path again if nothing changed */
+ return result;
}
/* Fix all RNA_Paths in the given Action, relative to the given ID block
@@ -860,102 +914,114 @@ char *BKE_animsys_fix_rna_path_rename(ID *owner_id, char *old_path, const char *
* NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]>
* i.e. pose.bones["Bone"]
*/
-void BKE_action_fix_paths_rename(ID *owner_id, bAction *act, const char *prefix, const char *oldName,
- const char *newName, int oldSubscript, int newSubscript, bool verify_paths)
-{
- char *oldN, *newN;
-
- /* if no action, no need to proceed */
- if (ELEM(NULL, owner_id, act))
- return;
-
- /* Name sanitation logic - copied from BKE_animdata_fix_paths_rename() */
- if ((oldName != NULL) && (newName != NULL)) {
- /* pad the names with [" "] so that only exact matches are made */
- const size_t name_old_len = strlen(oldName);
- const size_t name_new_len = strlen(newName);
- char *name_old_esc = BLI_array_alloca(name_old_esc, (name_old_len * 2) + 1);
- char *name_new_esc = BLI_array_alloca(name_new_esc, (name_new_len * 2) + 1);
-
- BLI_strescape(name_old_esc, oldName, (name_old_len * 2) + 1);
- BLI_strescape(name_new_esc, newName, (name_new_len * 2) + 1);
- oldN = BLI_sprintfN("[\"%s\"]", name_old_esc);
- newN = BLI_sprintfN("[\"%s\"]", name_new_esc);
- }
- else {
- oldN = BLI_sprintfN("[%d]", oldSubscript);
- newN = BLI_sprintfN("[%d]", newSubscript);
- }
-
- /* fix paths in action */
- fcurves_path_rename_fix(owner_id, prefix, oldName, newName, oldN, newN, &act->curves, verify_paths);
-
- /* free the temp names */
- MEM_freeN(oldN);
- MEM_freeN(newN);
+void BKE_action_fix_paths_rename(ID *owner_id,
+ bAction *act,
+ const char *prefix,
+ const char *oldName,
+ const char *newName,
+ int oldSubscript,
+ int newSubscript,
+ bool verify_paths)
+{
+ char *oldN, *newN;
+
+ /* if no action, no need to proceed */
+ if (ELEM(NULL, owner_id, act))
+ return;
+
+ /* Name sanitation logic - copied from BKE_animdata_fix_paths_rename() */
+ if ((oldName != NULL) && (newName != NULL)) {
+ /* pad the names with [" "] so that only exact matches are made */
+ const size_t name_old_len = strlen(oldName);
+ const size_t name_new_len = strlen(newName);
+ char *name_old_esc = BLI_array_alloca(name_old_esc, (name_old_len * 2) + 1);
+ char *name_new_esc = BLI_array_alloca(name_new_esc, (name_new_len * 2) + 1);
+
+ BLI_strescape(name_old_esc, oldName, (name_old_len * 2) + 1);
+ BLI_strescape(name_new_esc, newName, (name_new_len * 2) + 1);
+ oldN = BLI_sprintfN("[\"%s\"]", name_old_esc);
+ newN = BLI_sprintfN("[\"%s\"]", name_new_esc);
+ }
+ else {
+ oldN = BLI_sprintfN("[%d]", oldSubscript);
+ newN = BLI_sprintfN("[%d]", newSubscript);
+ }
+
+ /* fix paths in action */
+ fcurves_path_rename_fix(
+ owner_id, prefix, oldName, newName, oldN, newN, &act->curves, verify_paths);
+
+ /* free the temp names */
+ MEM_freeN(oldN);
+ MEM_freeN(newN);
}
/* Fix all RNA-Paths in the AnimData block used by the given ID block
* NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]>
* i.e. pose.bones["Bone"]
*/
-void BKE_animdata_fix_paths_rename(ID *owner_id, AnimData *adt, ID *ref_id, const char *prefix, const char *oldName,
- const char *newName, int oldSubscript, int newSubscript, bool verify_paths)
-{
- NlaTrack *nlt;
- char *oldN, *newN;
- /* If no AnimData, no need to proceed. */
- if (ELEM(NULL, owner_id, adt)) {
- return;
- }
- bool is_self_changed = false;
- /* Name sanitation logic - shared with BKE_action_fix_paths_rename(). */
- if ((oldName != NULL) && (newName != NULL)) {
- /* Pad the names with [" "] so that only exact matches are made. */
- const size_t name_old_len = strlen(oldName);
- const size_t name_new_len = strlen(newName);
- char *name_old_esc = BLI_array_alloca(name_old_esc, (name_old_len * 2) + 1);
- char *name_new_esc = BLI_array_alloca(name_new_esc, (name_new_len * 2) + 1);
-
- BLI_strescape(name_old_esc, oldName, (name_old_len * 2) + 1);
- BLI_strescape(name_new_esc, newName, (name_new_len * 2) + 1);
- oldN = BLI_sprintfN("[\"%s\"]", name_old_esc);
- newN = BLI_sprintfN("[\"%s\"]", name_new_esc);
- }
- else {
- oldN = BLI_sprintfN("[%d]", oldSubscript);
- newN = BLI_sprintfN("[%d]", newSubscript);
- }
- /* Active action and temp action. */
- if (adt->action != NULL) {
- if (fcurves_path_rename_fix(owner_id, prefix, oldName, newName,
- oldN, newN, &adt->action->curves, verify_paths))
- {
- DEG_id_tag_update(&adt->action->id, ID_RECALC_COPY_ON_WRITE);
- }
- }
- if (adt->tmpact) {
- if (fcurves_path_rename_fix(owner_id, prefix, oldName, newName,
- oldN, newN, &adt->tmpact->curves, verify_paths))
- {
- DEG_id_tag_update(&adt->tmpact->id, ID_RECALC_COPY_ON_WRITE);
- }
- }
- /* Drivers - Drivers are really F-Curves */
- is_self_changed |= drivers_path_rename_fix(
- owner_id, ref_id, prefix, oldName, newName, oldN, newN, &adt->drivers, verify_paths);
- /* NLA Data - Animation Data for Strips */
- for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
- is_self_changed |= nlastrips_path_rename_fix(
- owner_id, prefix, oldName, newName, oldN, newN, &nlt->strips, verify_paths);
- }
- /* Tag owner ID if it */
- if (is_self_changed) {
- DEG_id_tag_update(owner_id, ID_RECALC_COPY_ON_WRITE);
- }
- /* free the temp names */
- MEM_freeN(oldN);
- MEM_freeN(newN);
+void BKE_animdata_fix_paths_rename(ID *owner_id,
+ AnimData *adt,
+ ID *ref_id,
+ const char *prefix,
+ const char *oldName,
+ const char *newName,
+ int oldSubscript,
+ int newSubscript,
+ bool verify_paths)
+{
+ NlaTrack *nlt;
+ char *oldN, *newN;
+ /* If no AnimData, no need to proceed. */
+ if (ELEM(NULL, owner_id, adt)) {
+ return;
+ }
+ bool is_self_changed = false;
+ /* Name sanitation logic - shared with BKE_action_fix_paths_rename(). */
+ if ((oldName != NULL) && (newName != NULL)) {
+ /* Pad the names with [" "] so that only exact matches are made. */
+ const size_t name_old_len = strlen(oldName);
+ const size_t name_new_len = strlen(newName);
+ char *name_old_esc = BLI_array_alloca(name_old_esc, (name_old_len * 2) + 1);
+ char *name_new_esc = BLI_array_alloca(name_new_esc, (name_new_len * 2) + 1);
+
+ BLI_strescape(name_old_esc, oldName, (name_old_len * 2) + 1);
+ BLI_strescape(name_new_esc, newName, (name_new_len * 2) + 1);
+ oldN = BLI_sprintfN("[\"%s\"]", name_old_esc);
+ newN = BLI_sprintfN("[\"%s\"]", name_new_esc);
+ }
+ else {
+ oldN = BLI_sprintfN("[%d]", oldSubscript);
+ newN = BLI_sprintfN("[%d]", newSubscript);
+ }
+ /* Active action and temp action. */
+ if (adt->action != NULL) {
+ if (fcurves_path_rename_fix(
+ owner_id, prefix, oldName, newName, oldN, newN, &adt->action->curves, verify_paths)) {
+ DEG_id_tag_update(&adt->action->id, ID_RECALC_COPY_ON_WRITE);
+ }
+ }
+ if (adt->tmpact) {
+ if (fcurves_path_rename_fix(
+ owner_id, prefix, oldName, newName, oldN, newN, &adt->tmpact->curves, verify_paths)) {
+ DEG_id_tag_update(&adt->tmpact->id, ID_RECALC_COPY_ON_WRITE);
+ }
+ }
+ /* Drivers - Drivers are really F-Curves */
+ is_self_changed |= drivers_path_rename_fix(
+ owner_id, ref_id, prefix, oldName, newName, oldN, newN, &adt->drivers, verify_paths);
+ /* NLA Data - Animation Data for Strips */
+ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ is_self_changed |= nlastrips_path_rename_fix(
+ owner_id, prefix, oldName, newName, oldN, newN, &nlt->strips, verify_paths);
+ }
+ /* Tag owner ID if it */
+ if (is_self_changed) {
+ DEG_id_tag_update(owner_id, ID_RECALC_COPY_ON_WRITE);
+ }
+ /* free the temp names */
+ MEM_freeN(oldN);
+ MEM_freeN(newN);
}
/* Remove FCurves with Prefix -------------------------------------- */
@@ -963,242 +1029,250 @@ void BKE_animdata_fix_paths_rename(ID *owner_id, AnimData *adt, ID *ref_id, cons
/* Check RNA-Paths for a list of F-Curves */
static bool fcurves_path_remove_fix(const char *prefix, ListBase *curves)
{
- FCurve *fcu, *fcn;
- bool any_removed = false;
- if (!prefix) return any_removed;
+ FCurve *fcu, *fcn;
+ bool any_removed = false;
+ if (!prefix)
+ return any_removed;
- /* we need to check every curve... */
- for (fcu = curves->first; fcu; fcu = fcn) {
- fcn = fcu->next;
+ /* we need to check every curve... */
+ for (fcu = curves->first; fcu; fcu = fcn) {
+ fcn = fcu->next;
- if (fcu->rna_path) {
- if (STRPREFIX(fcu->rna_path, prefix)) {
- BLI_remlink(curves, fcu);
- free_fcurve(fcu);
- any_removed = true;
- }
- }
- }
- return any_removed;
+ if (fcu->rna_path) {
+ if (STRPREFIX(fcu->rna_path, prefix)) {
+ BLI_remlink(curves, fcu);
+ free_fcurve(fcu);
+ any_removed = true;
+ }
+ }
+ }
+ return any_removed;
}
/* Check RNA-Paths for a list of F-Curves */
static bool nlastrips_path_remove_fix(const char *prefix, ListBase *strips)
{
- NlaStrip *strip;
- bool any_removed = false;
+ NlaStrip *strip;
+ bool any_removed = false;
- /* recursively check strips, fixing only actions... */
- for (strip = strips->first; strip; strip = strip->next) {
- /* fix strip's action */
- if (strip->act) {
- any_removed |= fcurves_path_remove_fix(prefix, &strip->act->curves);
- }
+ /* recursively check strips, fixing only actions... */
+ for (strip = strips->first; strip; strip = strip->next) {
+ /* fix strip's action */
+ if (strip->act) {
+ any_removed |= fcurves_path_remove_fix(prefix, &strip->act->curves);
+ }
- /* check sub-strips (if metas) */
- any_removed |= nlastrips_path_remove_fix(prefix, &strip->strips);
- }
- return any_removed;
+ /* check sub-strips (if metas) */
+ any_removed |= nlastrips_path_remove_fix(prefix, &strip->strips);
+ }
+ return any_removed;
}
bool BKE_animdata_fix_paths_remove(ID *id, const char *prefix)
{
- /* Only some ID-blocks have this info for now, so we cast the
- * types that do to be of type IdAdtTemplate
- */
- if (!id_can_have_animdata(id)) {
- return false;
- }
- bool any_removed = false;
- IdAdtTemplate *iat = (IdAdtTemplate *)id;
- AnimData *adt = iat->adt;
- /* check if there's any AnimData to start with */
- if (adt) {
- /* free fcurves */
- if (adt->action != NULL) {
- any_removed |= fcurves_path_remove_fix(prefix, &adt->action->curves);
- }
- if (adt->tmpact != NULL) {
- any_removed |= fcurves_path_remove_fix(prefix, &adt->tmpact->curves);
- }
- /* free drivers - stored as a list of F-Curves */
- any_removed |= fcurves_path_remove_fix(prefix, &adt->drivers);
- /* NLA Data - Animation Data for Strips */
- for (NlaTrack *nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
- any_removed |= nlastrips_path_remove_fix(prefix, &nlt->strips);
- }
- }
- return any_removed;
+ /* Only some ID-blocks have this info for now, so we cast the
+ * types that do to be of type IdAdtTemplate
+ */
+ if (!id_can_have_animdata(id)) {
+ return false;
+ }
+ bool any_removed = false;
+ IdAdtTemplate *iat = (IdAdtTemplate *)id;
+ AnimData *adt = iat->adt;
+ /* check if there's any AnimData to start with */
+ if (adt) {
+ /* free fcurves */
+ if (adt->action != NULL) {
+ any_removed |= fcurves_path_remove_fix(prefix, &adt->action->curves);
+ }
+ if (adt->tmpact != NULL) {
+ any_removed |= fcurves_path_remove_fix(prefix, &adt->tmpact->curves);
+ }
+ /* free drivers - stored as a list of F-Curves */
+ any_removed |= fcurves_path_remove_fix(prefix, &adt->drivers);
+ /* NLA Data - Animation Data for Strips */
+ for (NlaTrack *nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ any_removed |= nlastrips_path_remove_fix(prefix, &nlt->strips);
+ }
+ }
+ return any_removed;
}
/* Apply Op to All FCurves in Database --------------------------- */
/* "User-Data" wrapper used by BKE_fcurves_main_cb() */
typedef struct AllFCurvesCbWrapper {
- ID_FCurve_Edit_Callback func; /* Operation to apply on F-Curve */
- void *user_data; /* Custom data for that operation */
+ ID_FCurve_Edit_Callback func; /* Operation to apply on F-Curve */
+ void *user_data; /* Custom data for that operation */
} AllFCurvesCbWrapper;
/* Helper for adt_apply_all_fcurves_cb() - Apply wrapped operator to list of F-Curves */
-static void fcurves_apply_cb(ID *id, ListBase *fcurves, ID_FCurve_Edit_Callback func, void *user_data)
+static void fcurves_apply_cb(ID *id,
+ ListBase *fcurves,
+ ID_FCurve_Edit_Callback func,
+ void *user_data)
{
- FCurve *fcu;
+ FCurve *fcu;
- for (fcu = fcurves->first; fcu; fcu = fcu->next) {
- func(id, fcu, user_data);
- }
+ for (fcu = fcurves->first; fcu; fcu = fcu->next) {
+ func(id, fcu, user_data);
+ }
}
/* Helper for adt_apply_all_fcurves_cb() - Recursively go through each NLA strip */
static void nlastrips_apply_all_curves_cb(ID *id, ListBase *strips, AllFCurvesCbWrapper *wrapper)
{
- NlaStrip *strip;
+ NlaStrip *strip;
- for (strip = strips->first; strip; strip = strip->next) {
- /* fix strip's action */
- if (strip->act) {
- fcurves_apply_cb(id, &strip->act->curves, wrapper->func, wrapper->user_data);
- }
+ for (strip = strips->first; strip; strip = strip->next) {
+ /* fix strip's action */
+ if (strip->act) {
+ fcurves_apply_cb(id, &strip->act->curves, wrapper->func, wrapper->user_data);
+ }
- /* check sub-strips (if metas) */
- nlastrips_apply_all_curves_cb(id, &strip->strips, wrapper);
- }
+ /* check sub-strips (if metas) */
+ nlastrips_apply_all_curves_cb(id, &strip->strips, wrapper);
+ }
}
/* Helper for BKE_fcurves_main_cb() - Dispatch wrapped operator to all F-Curves */
static void adt_apply_all_fcurves_cb(ID *id, AnimData *adt, void *wrapper_data)
{
- AllFCurvesCbWrapper *wrapper = wrapper_data;
- NlaTrack *nlt;
+ AllFCurvesCbWrapper *wrapper = wrapper_data;
+ NlaTrack *nlt;
- if (adt->action) {
- fcurves_apply_cb(id, &adt->action->curves, wrapper->func, wrapper->user_data);
- }
+ if (adt->action) {
+ fcurves_apply_cb(id, &adt->action->curves, wrapper->func, wrapper->user_data);
+ }
- if (adt->tmpact) {
- fcurves_apply_cb(id, &adt->tmpact->curves, wrapper->func, wrapper->user_data);
- }
+ if (adt->tmpact) {
+ fcurves_apply_cb(id, &adt->tmpact->curves, wrapper->func, wrapper->user_data);
+ }
- /* free drivers - stored as a list of F-Curves */
- fcurves_apply_cb(id, &adt->drivers, wrapper->func, wrapper->user_data);
+ /* free drivers - stored as a list of F-Curves */
+ fcurves_apply_cb(id, &adt->drivers, wrapper->func, wrapper->user_data);
- /* NLA Data - Animation Data for Strips */
- for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
- nlastrips_apply_all_curves_cb(id, &nlt->strips, wrapper);
- }
+ /* NLA Data - Animation Data for Strips */
+ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ nlastrips_apply_all_curves_cb(id, &nlt->strips, wrapper);
+ }
}
void BKE_fcurves_id_cb(ID *id, ID_FCurve_Edit_Callback func, void *user_data)
{
- AnimData *adt = BKE_animdata_from_id(id);
- if (adt != NULL) {
- AllFCurvesCbWrapper wrapper = {func, user_data};
- adt_apply_all_fcurves_cb(id, adt, &wrapper);
- }
+ AnimData *adt = BKE_animdata_from_id(id);
+ if (adt != NULL) {
+ AllFCurvesCbWrapper wrapper = {func, user_data};
+ adt_apply_all_fcurves_cb(id, adt, &wrapper);
+ }
}
/* apply the given callback function on all F-Curves attached to data in main database */
void BKE_fcurves_main_cb(Main *bmain, ID_FCurve_Edit_Callback func, void *user_data)
{
- /* Wrap F-Curve operation stuff to pass to the general AnimData-level func */
- AllFCurvesCbWrapper wrapper = {func, user_data};
+ /* Wrap F-Curve operation stuff to pass to the general AnimData-level func */
+ AllFCurvesCbWrapper wrapper = {func, user_data};
- /* Use the AnimData-based function so that we don't have to reimplement all that stuff */
- BKE_animdata_main_cb(bmain, adt_apply_all_fcurves_cb, &wrapper);
+ /* Use the AnimData-based function so that we don't have to reimplement all that stuff */
+ BKE_animdata_main_cb(bmain, adt_apply_all_fcurves_cb, &wrapper);
}
-
/* Whole Database Ops -------------------------------------------- */
/* apply the given callback function on all data in main database */
void BKE_animdata_main_cb(Main *bmain, ID_AnimData_Edit_Callback func, void *user_data)
{
- ID *id;
+ ID *id;
- /* standard data version */
+ /* standard data version */
#define ANIMDATA_IDS_CB(first) \
- for (id = first; id; id = id->next) { \
- AnimData *adt = BKE_animdata_from_id(id); \
- if (adt) func(id, adt, user_data); \
- } (void)0
-
- /* "embedded" nodetree cases (i.e. scene/material/texture->nodetree) */
+ for (id = first; id; id = id->next) { \
+ AnimData *adt = BKE_animdata_from_id(id); \
+ if (adt) \
+ func(id, adt, user_data); \
+ } \
+ (void)0
+
+ /* "embedded" nodetree cases (i.e. scene/material/texture->nodetree) */
#define ANIMDATA_NODETREE_IDS_CB(first, NtId_Type) \
- for (id = first; id; id = id->next) { \
- AnimData *adt = BKE_animdata_from_id(id); \
- NtId_Type *ntp = (NtId_Type *)id; \
- if (ntp->nodetree) { \
- AnimData *adt2 = BKE_animdata_from_id((ID *)ntp->nodetree); \
- if (adt2) func(id, adt2, user_data); \
- } \
- if (adt) func(id, adt, user_data); \
- } (void)0
+ for (id = first; id; id = id->next) { \
+ AnimData *adt = BKE_animdata_from_id(id); \
+ NtId_Type *ntp = (NtId_Type *)id; \
+ if (ntp->nodetree) { \
+ AnimData *adt2 = BKE_animdata_from_id((ID *)ntp->nodetree); \
+ if (adt2) \
+ func(id, adt2, user_data); \
+ } \
+ if (adt) \
+ func(id, adt, user_data); \
+ } \
+ (void)0
- /* nodes */
- ANIMDATA_IDS_CB(bmain->nodetrees.first);
+ /* nodes */
+ ANIMDATA_IDS_CB(bmain->nodetrees.first);
- /* textures */
- ANIMDATA_NODETREE_IDS_CB(bmain->textures.first, Tex);
+ /* textures */
+ ANIMDATA_NODETREE_IDS_CB(bmain->textures.first, Tex);
- /* lights */
- ANIMDATA_NODETREE_IDS_CB(bmain->lights.first, Light);
+ /* lights */
+ ANIMDATA_NODETREE_IDS_CB(bmain->lights.first, Light);
- /* materials */
- ANIMDATA_NODETREE_IDS_CB(bmain->materials.first, Material);
+ /* materials */
+ ANIMDATA_NODETREE_IDS_CB(bmain->materials.first, Material);
- /* cameras */
- ANIMDATA_IDS_CB(bmain->cameras.first);
+ /* cameras */
+ ANIMDATA_IDS_CB(bmain->cameras.first);
- /* shapekeys */
- ANIMDATA_IDS_CB(bmain->shapekeys.first);
+ /* shapekeys */
+ ANIMDATA_IDS_CB(bmain->shapekeys.first);
- /* metaballs */
- ANIMDATA_IDS_CB(bmain->metaballs.first);
+ /* metaballs */
+ ANIMDATA_IDS_CB(bmain->metaballs.first);
- /* curves */
- ANIMDATA_IDS_CB(bmain->curves.first);
+ /* curves */
+ ANIMDATA_IDS_CB(bmain->curves.first);
- /* armatures */
- ANIMDATA_IDS_CB(bmain->armatures.first);
+ /* armatures */
+ ANIMDATA_IDS_CB(bmain->armatures.first);
- /* lattices */
- ANIMDATA_IDS_CB(bmain->lattices.first);
+ /* lattices */
+ ANIMDATA_IDS_CB(bmain->lattices.first);
- /* meshes */
- ANIMDATA_IDS_CB(bmain->meshes.first);
+ /* meshes */
+ ANIMDATA_IDS_CB(bmain->meshes.first);
- /* particles */
- ANIMDATA_IDS_CB(bmain->particles.first);
+ /* particles */
+ ANIMDATA_IDS_CB(bmain->particles.first);
- /* speakers */
- ANIMDATA_IDS_CB(bmain->speakers.first);
+ /* speakers */
+ ANIMDATA_IDS_CB(bmain->speakers.first);
- /* movie clips */
- ANIMDATA_IDS_CB(bmain->movieclips.first);
+ /* movie clips */
+ ANIMDATA_IDS_CB(bmain->movieclips.first);
- /* objects */
- ANIMDATA_IDS_CB(bmain->objects.first);
+ /* objects */
+ ANIMDATA_IDS_CB(bmain->objects.first);
- /* masks */
- ANIMDATA_IDS_CB(bmain->masks.first);
+ /* masks */
+ ANIMDATA_IDS_CB(bmain->masks.first);
- /* worlds */
- ANIMDATA_NODETREE_IDS_CB(bmain->worlds.first, World);
+ /* worlds */
+ ANIMDATA_NODETREE_IDS_CB(bmain->worlds.first, World);
- /* scenes */
- ANIMDATA_NODETREE_IDS_CB(bmain->scenes.first, Scene);
+ /* scenes */
+ ANIMDATA_NODETREE_IDS_CB(bmain->scenes.first, Scene);
- /* line styles */
- ANIMDATA_IDS_CB(bmain->linestyles.first);
+ /* line styles */
+ ANIMDATA_IDS_CB(bmain->linestyles.first);
- /* grease pencil */
- ANIMDATA_IDS_CB(bmain->gpencils.first);
+ /* grease pencil */
+ ANIMDATA_IDS_CB(bmain->gpencils.first);
- /* palettes */
- ANIMDATA_IDS_CB(bmain->palettes.first);
+ /* palettes */
+ ANIMDATA_IDS_CB(bmain->palettes.first);
- /* cache files */
- ANIMDATA_IDS_CB(bmain->cachefiles.first);
+ /* cache files */
+ ANIMDATA_IDS_CB(bmain->cachefiles.first);
}
/* Fix all RNA-Paths throughout the database (directly access the Global.main version)
@@ -1206,95 +1280,101 @@ void BKE_animdata_main_cb(Main *bmain, ID_AnimData_Edit_Callback func, void *use
* i.e. pose.bones["Bone"]
*/
/* TODO: use BKE_animdata_main_cb for looping over all data */
-void BKE_animdata_fix_paths_rename_all(ID *ref_id, const char *prefix, const char *oldName, const char *newName)
-{
- Main *bmain = G.main; /* XXX UGLY! */
- ID *id;
-
- /* macro for less typing
- * - whether animdata exists is checked for by the main renaming callback, though taking
- * this outside of the function may make things slightly faster?
- */
+void BKE_animdata_fix_paths_rename_all(ID *ref_id,
+ const char *prefix,
+ const char *oldName,
+ const char *newName)
+{
+ Main *bmain = G.main; /* XXX UGLY! */
+ ID *id;
+
+ /* macro for less typing
+ * - whether animdata exists is checked for by the main renaming callback, though taking
+ * this outside of the function may make things slightly faster?
+ */
#define RENAMEFIX_ANIM_IDS(first) \
- for (id = first; id; id = id->next) { \
- AnimData *adt = BKE_animdata_from_id(id); \
- BKE_animdata_fix_paths_rename(id, adt, ref_id, prefix, oldName, newName, 0, 0, 1); \
- } (void)0
+ for (id = first; id; id = id->next) { \
+ AnimData *adt = BKE_animdata_from_id(id); \
+ BKE_animdata_fix_paths_rename(id, adt, ref_id, prefix, oldName, newName, 0, 0, 1); \
+ } \
+ (void)0
- /* another version of this macro for nodetrees */
+ /* another version of this macro for nodetrees */
#define RENAMEFIX_ANIM_NODETREE_IDS(first, NtId_Type) \
- for (id = first; id; id = id->next) { \
- AnimData *adt = BKE_animdata_from_id(id); \
- NtId_Type *ntp = (NtId_Type *)id; \
- if (ntp->nodetree) { \
- AnimData *adt2 = BKE_animdata_from_id((ID *)ntp->nodetree); \
- BKE_animdata_fix_paths_rename((ID *)ntp->nodetree, adt2, ref_id, prefix, oldName, newName, 0, 0, 1); \
- } \
- BKE_animdata_fix_paths_rename(id, adt, ref_id, prefix, oldName, newName, 0, 0, 1); \
- } (void)0
+ for (id = first; id; id = id->next) { \
+ AnimData *adt = BKE_animdata_from_id(id); \
+ NtId_Type *ntp = (NtId_Type *)id; \
+ if (ntp->nodetree) { \
+ AnimData *adt2 = BKE_animdata_from_id((ID *)ntp->nodetree); \
+ BKE_animdata_fix_paths_rename( \
+ (ID *)ntp->nodetree, adt2, ref_id, prefix, oldName, newName, 0, 0, 1); \
+ } \
+ BKE_animdata_fix_paths_rename(id, adt, ref_id, prefix, oldName, newName, 0, 0, 1); \
+ } \
+ (void)0
- /* nodes */
- RENAMEFIX_ANIM_IDS(bmain->nodetrees.first);
+ /* nodes */
+ RENAMEFIX_ANIM_IDS(bmain->nodetrees.first);
- /* textures */
- RENAMEFIX_ANIM_NODETREE_IDS(bmain->textures.first, Tex);
+ /* textures */
+ RENAMEFIX_ANIM_NODETREE_IDS(bmain->textures.first, Tex);
- /* lights */
- RENAMEFIX_ANIM_NODETREE_IDS(bmain->lights.first, Light);
+ /* lights */
+ RENAMEFIX_ANIM_NODETREE_IDS(bmain->lights.first, Light);
- /* materials */
- RENAMEFIX_ANIM_NODETREE_IDS(bmain->materials.first, Material);
+ /* materials */
+ RENAMEFIX_ANIM_NODETREE_IDS(bmain->materials.first, Material);
- /* cameras */
- RENAMEFIX_ANIM_IDS(bmain->cameras.first);
+ /* cameras */
+ RENAMEFIX_ANIM_IDS(bmain->cameras.first);
- /* shapekeys */
- RENAMEFIX_ANIM_IDS(bmain->shapekeys.first);
+ /* shapekeys */
+ RENAMEFIX_ANIM_IDS(bmain->shapekeys.first);
- /* metaballs */
- RENAMEFIX_ANIM_IDS(bmain->metaballs.first);
+ /* metaballs */
+ RENAMEFIX_ANIM_IDS(bmain->metaballs.first);
- /* curves */
- RENAMEFIX_ANIM_IDS(bmain->curves.first);
+ /* curves */
+ RENAMEFIX_ANIM_IDS(bmain->curves.first);
- /* armatures */
- RENAMEFIX_ANIM_IDS(bmain->armatures.first);
+ /* armatures */
+ RENAMEFIX_ANIM_IDS(bmain->armatures.first);
- /* lattices */
- RENAMEFIX_ANIM_IDS(bmain->lattices.first);
+ /* lattices */
+ RENAMEFIX_ANIM_IDS(bmain->lattices.first);
- /* meshes */
- RENAMEFIX_ANIM_IDS(bmain->meshes.first);
+ /* meshes */
+ RENAMEFIX_ANIM_IDS(bmain->meshes.first);
- /* particles */
- RENAMEFIX_ANIM_IDS(bmain->particles.first);
+ /* particles */
+ RENAMEFIX_ANIM_IDS(bmain->particles.first);
- /* speakers */
- RENAMEFIX_ANIM_IDS(bmain->speakers.first);
+ /* speakers */
+ RENAMEFIX_ANIM_IDS(bmain->speakers.first);
- /* movie clips */
- RENAMEFIX_ANIM_IDS(bmain->movieclips.first);
+ /* movie clips */
+ RENAMEFIX_ANIM_IDS(bmain->movieclips.first);
- /* objects */
- RENAMEFIX_ANIM_IDS(bmain->objects.first);
+ /* objects */
+ RENAMEFIX_ANIM_IDS(bmain->objects.first);
- /* masks */
- RENAMEFIX_ANIM_IDS(bmain->masks.first);
+ /* masks */
+ RENAMEFIX_ANIM_IDS(bmain->masks.first);
- /* worlds */
- RENAMEFIX_ANIM_NODETREE_IDS(bmain->worlds.first, World);
+ /* worlds */
+ RENAMEFIX_ANIM_NODETREE_IDS(bmain->worlds.first, World);
- /* linestyles */
- RENAMEFIX_ANIM_IDS(bmain->linestyles.first);
+ /* linestyles */
+ RENAMEFIX_ANIM_IDS(bmain->linestyles.first);
- /* grease pencil */
- RENAMEFIX_ANIM_IDS(bmain->gpencils.first);
+ /* grease pencil */
+ RENAMEFIX_ANIM_IDS(bmain->gpencils.first);
- /* cache files */
- RENAMEFIX_ANIM_IDS(bmain->cachefiles.first);
+ /* cache files */
+ RENAMEFIX_ANIM_IDS(bmain->cachefiles.first);
- /* scenes */
- RENAMEFIX_ANIM_NODETREE_IDS(bmain->scenes.first, Scene);
+ /* scenes */
+ RENAMEFIX_ANIM_NODETREE_IDS(bmain->scenes.first, Scene);
}
/* *********************************** */
@@ -1304,161 +1384,176 @@ void BKE_animdata_fix_paths_rename_all(ID *ref_id, const char *prefix, const cha
/* Find the first path that matches the given criteria */
/* TODO: do we want some method to perform partial matches too? */
-KS_Path *BKE_keyingset_find_path(KeyingSet *ks, ID *id, const char group_name[], const char rna_path[], int array_index, int UNUSED(group_mode))
+KS_Path *BKE_keyingset_find_path(KeyingSet *ks,
+ ID *id,
+ const char group_name[],
+ const char rna_path[],
+ int array_index,
+ int UNUSED(group_mode))
{
- KS_Path *ksp;
+ KS_Path *ksp;
- /* sanity checks */
- if (ELEM(NULL, ks, rna_path, id))
- return NULL;
+ /* sanity checks */
+ if (ELEM(NULL, ks, rna_path, id))
+ return NULL;
- /* loop over paths in the current KeyingSet, finding the first one where all settings match
- * (i.e. the first one where none of the checks fail and equal 0)
- */
- for (ksp = ks->paths.first; ksp; ksp = ksp->next) {
- short eq_id = 1, eq_path = 1, eq_index = 1, eq_group = 1;
+ /* loop over paths in the current KeyingSet, finding the first one where all settings match
+ * (i.e. the first one where none of the checks fail and equal 0)
+ */
+ for (ksp = ks->paths.first; ksp; ksp = ksp->next) {
+ short eq_id = 1, eq_path = 1, eq_index = 1, eq_group = 1;
- /* id */
- if (id != ksp->id)
- eq_id = 0;
+ /* id */
+ if (id != ksp->id)
+ eq_id = 0;
- /* path */
- if ((ksp->rna_path == NULL) || !STREQ(rna_path, ksp->rna_path))
- eq_path = 0;
+ /* path */
+ if ((ksp->rna_path == NULL) || !STREQ(rna_path, ksp->rna_path))
+ eq_path = 0;
- /* index - need to compare whole-array setting too... */
- if (ksp->array_index != array_index)
- eq_index = 0;
+ /* index - need to compare whole-array setting too... */
+ if (ksp->array_index != array_index)
+ eq_index = 0;
- /* group */
- if (group_name) {
- /* FIXME: these checks need to be coded... for now, it's not too important though */
- }
+ /* group */
+ if (group_name) {
+ /* FIXME: these checks need to be coded... for now, it's not too important though */
+ }
- /* if all aspects are ok, return */
- if (eq_id && eq_path && eq_index && eq_group)
- return ksp;
- }
+ /* if all aspects are ok, return */
+ if (eq_id && eq_path && eq_index && eq_group)
+ return ksp;
+ }
- /* none found */
- return NULL;
+ /* none found */
+ return NULL;
}
/* Defining Tools --------------------------- */
/* Used to create a new 'custom' KeyingSet for the user, that will be automatically added to the stack */
-KeyingSet *BKE_keyingset_add(ListBase *list, const char idname[], const char name[], short flag, short keyingflag)
+KeyingSet *BKE_keyingset_add(
+ ListBase *list, const char idname[], const char name[], short flag, short keyingflag)
{
- KeyingSet *ks;
+ KeyingSet *ks;
- /* allocate new KeyingSet */
- ks = MEM_callocN(sizeof(KeyingSet), "KeyingSet");
+ /* allocate new KeyingSet */
+ ks = MEM_callocN(sizeof(KeyingSet), "KeyingSet");
- BLI_strncpy(ks->idname, (idname) ? idname : (name) ? name : DATA_("KeyingSet"), sizeof(ks->idname));
- BLI_strncpy(ks->name, (name) ? name : (idname) ? idname : DATA_("Keying Set"), sizeof(ks->name));
+ BLI_strncpy(
+ ks->idname, (idname) ? idname : (name) ? name : DATA_("KeyingSet"), sizeof(ks->idname));
+ BLI_strncpy(ks->name, (name) ? name : (idname) ? idname : DATA_("Keying Set"), sizeof(ks->name));
- ks->flag = flag;
- ks->keyingflag = keyingflag;
- ks->keyingoverride = keyingflag; /* NOTE: assume that if one is set one way, the other should be too, so that it'll work */
+ ks->flag = flag;
+ ks->keyingflag = keyingflag;
+ ks->keyingoverride =
+ keyingflag; /* NOTE: assume that if one is set one way, the other should be too, so that it'll work */
- /* add KeyingSet to list */
- BLI_addtail(list, ks);
+ /* add KeyingSet to list */
+ BLI_addtail(list, ks);
- /* Make sure KeyingSet has a unique idname */
- BLI_uniquename(list, ks, DATA_("KeyingSet"), '.', offsetof(KeyingSet, idname), sizeof(ks->idname));
+ /* Make sure KeyingSet has a unique idname */
+ BLI_uniquename(
+ list, ks, DATA_("KeyingSet"), '.', offsetof(KeyingSet, idname), sizeof(ks->idname));
- /* Make sure KeyingSet has a unique label (this helps with identification) */
- BLI_uniquename(list, ks, DATA_("Keying Set"), '.', offsetof(KeyingSet, name), sizeof(ks->name));
+ /* Make sure KeyingSet has a unique label (this helps with identification) */
+ BLI_uniquename(list, ks, DATA_("Keying Set"), '.', offsetof(KeyingSet, name), sizeof(ks->name));
- /* return new KeyingSet for further editing */
- return ks;
+ /* return new KeyingSet for further editing */
+ return ks;
}
/* Add a path to a KeyingSet. Nothing is returned for now...
* Checks are performed to ensure that destination is appropriate for the KeyingSet in question
*/
-KS_Path *BKE_keyingset_add_path(KeyingSet *ks, ID *id, const char group_name[], const char rna_path[], int array_index, short flag, short groupmode)
-{
- KS_Path *ksp;
-
- /* sanity checks */
- if (ELEM(NULL, ks, rna_path)) {
- CLOG_ERROR(&LOG, "no Keying Set and/or RNA Path to add path with");
- return NULL;
- }
-
- /* ID is required for all types of KeyingSets */
- if (id == NULL) {
- CLOG_ERROR(&LOG, "No ID provided for Keying Set Path");
- return NULL;
- }
-
- /* don't add if there is already a matching KS_Path in the KeyingSet */
- if (BKE_keyingset_find_path(ks, id, group_name, rna_path, array_index, groupmode)) {
- if (G.debug & G_DEBUG)
- CLOG_ERROR(&LOG, "destination already exists in Keying Set");
- return NULL;
- }
-
- /* allocate a new KeyingSet Path */
- ksp = MEM_callocN(sizeof(KS_Path), "KeyingSet Path");
-
- /* just store absolute info */
- ksp->id = id;
- if (group_name)
- BLI_strncpy(ksp->group, group_name, sizeof(ksp->group));
- else
- ksp->group[0] = '\0';
-
- /* store additional info for relative paths (just in case user makes the set relative) */
- if (id)
- ksp->idtype = GS(id->name);
-
- /* just copy path info */
- /* TODO: should array index be checked too? */
- ksp->rna_path = BLI_strdup(rna_path);
- ksp->array_index = array_index;
-
- /* store flags */
- ksp->flag = flag;
- ksp->groupmode = groupmode;
-
- /* add KeyingSet path to KeyingSet */
- BLI_addtail(&ks->paths, ksp);
-
- /* return this path */
- return ksp;
+KS_Path *BKE_keyingset_add_path(KeyingSet *ks,
+ ID *id,
+ const char group_name[],
+ const char rna_path[],
+ int array_index,
+ short flag,
+ short groupmode)
+{
+ KS_Path *ksp;
+
+ /* sanity checks */
+ if (ELEM(NULL, ks, rna_path)) {
+ CLOG_ERROR(&LOG, "no Keying Set and/or RNA Path to add path with");
+ return NULL;
+ }
+
+ /* ID is required for all types of KeyingSets */
+ if (id == NULL) {
+ CLOG_ERROR(&LOG, "No ID provided for Keying Set Path");
+ return NULL;
+ }
+
+ /* don't add if there is already a matching KS_Path in the KeyingSet */
+ if (BKE_keyingset_find_path(ks, id, group_name, rna_path, array_index, groupmode)) {
+ if (G.debug & G_DEBUG)
+ CLOG_ERROR(&LOG, "destination already exists in Keying Set");
+ return NULL;
+ }
+
+ /* allocate a new KeyingSet Path */
+ ksp = MEM_callocN(sizeof(KS_Path), "KeyingSet Path");
+
+ /* just store absolute info */
+ ksp->id = id;
+ if (group_name)
+ BLI_strncpy(ksp->group, group_name, sizeof(ksp->group));
+ else
+ ksp->group[0] = '\0';
+
+ /* store additional info for relative paths (just in case user makes the set relative) */
+ if (id)
+ ksp->idtype = GS(id->name);
+
+ /* just copy path info */
+ /* TODO: should array index be checked too? */
+ ksp->rna_path = BLI_strdup(rna_path);
+ ksp->array_index = array_index;
+
+ /* store flags */
+ ksp->flag = flag;
+ ksp->groupmode = groupmode;
+
+ /* add KeyingSet path to KeyingSet */
+ BLI_addtail(&ks->paths, ksp);
+
+ /* return this path */
+ return ksp;
}
/* Free the given Keying Set path */
void BKE_keyingset_free_path(KeyingSet *ks, KS_Path *ksp)
{
- /* sanity check */
- if (ELEM(NULL, ks, ksp))
- return;
+ /* sanity check */
+ if (ELEM(NULL, ks, ksp))
+ return;
- /* free RNA-path info */
- if (ksp->rna_path)
- MEM_freeN(ksp->rna_path);
+ /* free RNA-path info */
+ if (ksp->rna_path)
+ MEM_freeN(ksp->rna_path);
- /* free path itself */
- BLI_freelinkN(&ks->paths, ksp);
+ /* free path itself */
+ BLI_freelinkN(&ks->paths, ksp);
}
/* Copy all KeyingSets in the given list */
void BKE_keyingsets_copy(ListBase *newlist, const ListBase *list)
{
- KeyingSet *ksn;
- KS_Path *kspn;
+ KeyingSet *ksn;
+ KS_Path *kspn;
- BLI_duplicatelist(newlist, list);
+ BLI_duplicatelist(newlist, list);
- for (ksn = newlist->first; ksn; ksn = ksn->next) {
- BLI_duplicatelist(&ksn->paths, &ksn->paths);
+ for (ksn = newlist->first; ksn; ksn = ksn->next) {
+ BLI_duplicatelist(&ksn->paths, &ksn->paths);
- for (kspn = ksn->paths.first; kspn; kspn = kspn->next)
- kspn->rna_path = MEM_dupallocN(kspn->rna_path);
- }
+ for (kspn = ksn->paths.first; kspn; kspn = kspn->next)
+ kspn->rna_path = MEM_dupallocN(kspn->rna_path);
+ }
}
/* Freeing Tools --------------------------- */
@@ -1466,289 +1561,286 @@ void BKE_keyingsets_copy(ListBase *newlist, const ListBase *list)
/* Free data for KeyingSet but not set itself */
void BKE_keyingset_free(KeyingSet *ks)
{
- KS_Path *ksp, *kspn;
+ KS_Path *ksp, *kspn;
- /* sanity check */
- if (ks == NULL)
- return;
+ /* sanity check */
+ if (ks == NULL)
+ return;
- /* free each path as we go to avoid looping twice */
- for (ksp = ks->paths.first; ksp; ksp = kspn) {
- kspn = ksp->next;
- BKE_keyingset_free_path(ks, ksp);
- }
+ /* free each path as we go to avoid looping twice */
+ for (ksp = ks->paths.first; ksp; ksp = kspn) {
+ kspn = ksp->next;
+ BKE_keyingset_free_path(ks, ksp);
+ }
}
/* Free all the KeyingSets in the given list */
void BKE_keyingsets_free(ListBase *list)
{
- KeyingSet *ks, *ksn;
+ KeyingSet *ks, *ksn;
- /* sanity check */
- if (list == NULL)
- return;
+ /* sanity check */
+ if (list == NULL)
+ return;
- /* loop over KeyingSets freeing them
- * - BKE_keyingset_free() doesn't free the set itself, but it frees its sub-data
- */
- for (ks = list->first; ks; ks = ksn) {
- ksn = ks->next;
- BKE_keyingset_free(ks);
- BLI_freelinkN(list, ks);
- }
+ /* loop over KeyingSets freeing them
+ * - BKE_keyingset_free() doesn't free the set itself, but it frees its sub-data
+ */
+ for (ks = list->first; ks; ks = ksn) {
+ ksn = ks->next;
+ BKE_keyingset_free(ks);
+ BLI_freelinkN(list, ks);
+ }
}
/* ***************************************** */
/* Evaluation Data-Setting Backend */
-static bool animsys_store_rna_setting(
- PointerRNA *ptr,
- /* typically 'fcu->rna_path', 'fcu->array_index' */
- const char *rna_path, const int array_index,
- PathResolvedRNA *r_result)
-{
- bool success = false;
- const char *path = rna_path;
-
- /* write value to setting */
- if (path) {
- /* get property to write to */
- if (RNA_path_resolve_property(ptr, path, &r_result->ptr, &r_result->prop)) {
- if ((ptr->id.data == NULL) || RNA_property_animateable(&r_result->ptr, r_result->prop)) {
- int array_len = RNA_property_array_length(&r_result->ptr, r_result->prop);
-
- if (array_len && array_index >= array_len) {
- if (G.debug & G_DEBUG) {
- CLOG_WARN(&LOG, "Animato: Invalid array index. ID = '%s', '%s[%d]', array length is %d",
- (ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "<No ID>",
- path, array_index, array_len - 1);
- }
- }
- else {
- r_result->prop_index = array_len ? array_index : -1;
- success = true;
- }
- }
- }
- else {
- /* failed to get path */
- /* XXX don't tag as failed yet though, as there are some legit situations (Action Constraint)
- * where some channels will not exist, but shouldn't lock up Action */
- if (G.debug & G_DEBUG) {
- CLOG_WARN(&LOG, "Animato: Invalid path. ID = '%s', '%s[%d]'",
- (ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "<No ID>",
- path, array_index);
- }
- }
- }
-
- return success;
+static bool animsys_store_rna_setting(PointerRNA *ptr,
+ /* typically 'fcu->rna_path', 'fcu->array_index' */
+ const char *rna_path,
+ const int array_index,
+ PathResolvedRNA *r_result)
+{
+ bool success = false;
+ const char *path = rna_path;
+
+ /* write value to setting */
+ if (path) {
+ /* get property to write to */
+ if (RNA_path_resolve_property(ptr, path, &r_result->ptr, &r_result->prop)) {
+ if ((ptr->id.data == NULL) || RNA_property_animateable(&r_result->ptr, r_result->prop)) {
+ int array_len = RNA_property_array_length(&r_result->ptr, r_result->prop);
+
+ if (array_len && array_index >= array_len) {
+ if (G.debug & G_DEBUG) {
+ CLOG_WARN(&LOG,
+ "Animato: Invalid array index. ID = '%s', '%s[%d]', array length is %d",
+ (ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "<No ID>",
+ path,
+ array_index,
+ array_len - 1);
+ }
+ }
+ else {
+ r_result->prop_index = array_len ? array_index : -1;
+ success = true;
+ }
+ }
+ }
+ else {
+ /* failed to get path */
+ /* XXX don't tag as failed yet though, as there are some legit situations (Action Constraint)
+ * where some channels will not exist, but shouldn't lock up Action */
+ if (G.debug & G_DEBUG) {
+ CLOG_WARN(&LOG,
+ "Animato: Invalid path. ID = '%s', '%s[%d]'",
+ (ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "<No ID>",
+ path,
+ array_index);
+ }
+ }
+ }
+
+ return success;
}
-
/* less than 1.0 evaluates to false, use epsilon to avoid float error */
#define ANIMSYS_FLOAT_AS_BOOL(value) ((value) > ((1.0f - FLT_EPSILON)))
static bool animsys_read_rna_setting(PathResolvedRNA *anim_rna, float *r_value)
{
- PropertyRNA *prop = anim_rna->prop;
- PointerRNA *ptr = &anim_rna->ptr;
- int array_index = anim_rna->prop_index;
- float orig_value;
-
- /* caller must ensure this is animatable */
- BLI_assert(RNA_property_animateable(ptr, prop) || ptr->id.data == NULL);
-
- switch (RNA_property_type(prop)) {
- case PROP_BOOLEAN:
- {
- if (array_index != -1) {
- const int orig_value_coerce = RNA_property_boolean_get_index(ptr, prop, array_index);
- orig_value = (float)orig_value_coerce;
- }
- else {
- const int orig_value_coerce = RNA_property_boolean_get(ptr, prop);
- orig_value = (float)orig_value_coerce;
- }
- break;
- }
- case PROP_INT:
- {
- if (array_index != -1) {
- const int orig_value_coerce = RNA_property_int_get_index(ptr, prop, array_index);
- orig_value = (float)orig_value_coerce;
- }
- else {
- const int orig_value_coerce = RNA_property_int_get(ptr, prop);
- orig_value = (float)orig_value_coerce;
- }
- break;
- }
- case PROP_FLOAT:
- {
- if (array_index != -1) {
- const float orig_value_coerce = RNA_property_float_get_index(ptr, prop, array_index);
- orig_value = (float)orig_value_coerce;
- }
- else {
- const float orig_value_coerce = RNA_property_float_get(ptr, prop);
- orig_value = (float)orig_value_coerce;
- }
- break;
- }
- case PROP_ENUM:
- {
- const int orig_value_coerce = RNA_property_enum_get(ptr, prop);
- orig_value = (float)orig_value_coerce;
- break;
- }
- default:
- /* nothing can be done here... so it is unsuccessful? */
- return false;
- }
-
- if (r_value != NULL) {
- *r_value = orig_value;
- }
-
- /* successful */
- return true;
+ PropertyRNA *prop = anim_rna->prop;
+ PointerRNA *ptr = &anim_rna->ptr;
+ int array_index = anim_rna->prop_index;
+ float orig_value;
+
+ /* caller must ensure this is animatable */
+ BLI_assert(RNA_property_animateable(ptr, prop) || ptr->id.data == NULL);
+
+ switch (RNA_property_type(prop)) {
+ case PROP_BOOLEAN: {
+ if (array_index != -1) {
+ const int orig_value_coerce = RNA_property_boolean_get_index(ptr, prop, array_index);
+ orig_value = (float)orig_value_coerce;
+ }
+ else {
+ const int orig_value_coerce = RNA_property_boolean_get(ptr, prop);
+ orig_value = (float)orig_value_coerce;
+ }
+ break;
+ }
+ case PROP_INT: {
+ if (array_index != -1) {
+ const int orig_value_coerce = RNA_property_int_get_index(ptr, prop, array_index);
+ orig_value = (float)orig_value_coerce;
+ }
+ else {
+ const int orig_value_coerce = RNA_property_int_get(ptr, prop);
+ orig_value = (float)orig_value_coerce;
+ }
+ break;
+ }
+ case PROP_FLOAT: {
+ if (array_index != -1) {
+ const float orig_value_coerce = RNA_property_float_get_index(ptr, prop, array_index);
+ orig_value = (float)orig_value_coerce;
+ }
+ else {
+ const float orig_value_coerce = RNA_property_float_get(ptr, prop);
+ orig_value = (float)orig_value_coerce;
+ }
+ break;
+ }
+ case PROP_ENUM: {
+ const int orig_value_coerce = RNA_property_enum_get(ptr, prop);
+ orig_value = (float)orig_value_coerce;
+ break;
+ }
+ default:
+ /* nothing can be done here... so it is unsuccessful? */
+ return false;
+ }
+
+ if (r_value != NULL) {
+ *r_value = orig_value;
+ }
+
+ /* successful */
+ return true;
}
/* Write the given value to a setting using RNA, and return success */
static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float value)
{
- PropertyRNA *prop = anim_rna->prop;
- PointerRNA *ptr = &anim_rna->ptr;
- int array_index = anim_rna->prop_index;
-
- /* caller must ensure this is animatable */
- BLI_assert(RNA_property_animateable(ptr, prop) || ptr->id.data == NULL);
-
- /* Check whether value is new. Otherwise we skip all the updates. */
- float old_value;
- if (!animsys_read_rna_setting(anim_rna, &old_value)) {
- return false;
- }
- if (old_value == value) {
- return true;
- }
-
- switch (RNA_property_type(prop)) {
- case PROP_BOOLEAN:
- {
- const int value_coerce = ANIMSYS_FLOAT_AS_BOOL(value);
- if (array_index != -1) {
- RNA_property_boolean_set_index(ptr, prop, array_index, value_coerce);
- }
- else {
- RNA_property_boolean_set(ptr, prop, value_coerce);
- }
- break;
- }
- case PROP_INT:
- {
- int value_coerce = (int)value;
- RNA_property_int_clamp(ptr, prop, &value_coerce);
- if (array_index != -1) {
- RNA_property_int_set_index(ptr, prop, array_index, value_coerce);
- }
- else {
- RNA_property_int_set(ptr, prop, value_coerce);
- }
- break;
- }
- case PROP_FLOAT:
- {
- float value_coerce = value;
- RNA_property_float_clamp(ptr, prop, &value_coerce);
- if (array_index != -1) {
- RNA_property_float_set_index(ptr, prop, array_index, value_coerce);
- }
- else {
- RNA_property_float_set(ptr, prop, value_coerce);
- }
- break;
- }
- case PROP_ENUM:
- {
- const int value_coerce = (int)value;
- RNA_property_enum_set(ptr, prop, value_coerce);
- break;
- }
- default:
- /* nothing can be done here... so it is unsuccessful? */
- return false;
- }
-
- /* successful */
- return true;
+ PropertyRNA *prop = anim_rna->prop;
+ PointerRNA *ptr = &anim_rna->ptr;
+ int array_index = anim_rna->prop_index;
+
+ /* caller must ensure this is animatable */
+ BLI_assert(RNA_property_animateable(ptr, prop) || ptr->id.data == NULL);
+
+ /* Check whether value is new. Otherwise we skip all the updates. */
+ float old_value;
+ if (!animsys_read_rna_setting(anim_rna, &old_value)) {
+ return false;
+ }
+ if (old_value == value) {
+ return true;
+ }
+
+ switch (RNA_property_type(prop)) {
+ case PROP_BOOLEAN: {
+ const int value_coerce = ANIMSYS_FLOAT_AS_BOOL(value);
+ if (array_index != -1) {
+ RNA_property_boolean_set_index(ptr, prop, array_index, value_coerce);
+ }
+ else {
+ RNA_property_boolean_set(ptr, prop, value_coerce);
+ }
+ break;
+ }
+ case PROP_INT: {
+ int value_coerce = (int)value;
+ RNA_property_int_clamp(ptr, prop, &value_coerce);
+ if (array_index != -1) {
+ RNA_property_int_set_index(ptr, prop, array_index, value_coerce);
+ }
+ else {
+ RNA_property_int_set(ptr, prop, value_coerce);
+ }
+ break;
+ }
+ case PROP_FLOAT: {
+ float value_coerce = value;
+ RNA_property_float_clamp(ptr, prop, &value_coerce);
+ if (array_index != -1) {
+ RNA_property_float_set_index(ptr, prop, array_index, value_coerce);
+ }
+ else {
+ RNA_property_float_set(ptr, prop, value_coerce);
+ }
+ break;
+ }
+ case PROP_ENUM: {
+ const int value_coerce = (int)value;
+ RNA_property_enum_set(ptr, prop, value_coerce);
+ break;
+ }
+ default:
+ /* nothing can be done here... so it is unsuccessful? */
+ return false;
+ }
+
+ /* successful */
+ return true;
}
/* Simple replacement based data-setting of the FCurve using RNA */
bool BKE_animsys_execute_fcurve(PointerRNA *ptr, FCurve *fcu, float curval)
{
- PathResolvedRNA anim_rna;
- bool ok = false;
-
- if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
- ok = animsys_write_rna_setting(&anim_rna, curval);
- }
-
- /* return whether we were successful */
- return ok;
-}
-
-static void animsys_write_orig_anim_rna(
- PointerRNA *ptr,
- const char *rna_path,
- int array_index,
- float value)
-{
- /* Pointer is expected to be an ID pointer, if it's not -- we are doomed.
- *
- * NOTE: It is possible to have animation data on NLA strip, see T57360.
- * TODO(sergey): Find solution for those cases.
- */
- if (ptr->id.data == NULL) {
- return;
- }
- PointerRNA orig_ptr = *ptr;
- orig_ptr.id.data = ((ID *)orig_ptr.id.data)->orig_id;
- orig_ptr.data = orig_ptr.id.data;
- PathResolvedRNA orig_anim_rna;
- /* TODO(sergey): Is there a faster way to get anim_rna of original ID? */
- if (animsys_store_rna_setting(&orig_ptr, rna_path, array_index, &orig_anim_rna)) {
- animsys_write_rna_setting(&orig_anim_rna, value);
- }
+ PathResolvedRNA anim_rna;
+ bool ok = false;
+
+ if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
+ ok = animsys_write_rna_setting(&anim_rna, curval);
+ }
+
+ /* return whether we were successful */
+ return ok;
+}
+
+static void animsys_write_orig_anim_rna(PointerRNA *ptr,
+ const char *rna_path,
+ int array_index,
+ float value)
+{
+ /* Pointer is expected to be an ID pointer, if it's not -- we are doomed.
+ *
+ * NOTE: It is possible to have animation data on NLA strip, see T57360.
+ * TODO(sergey): Find solution for those cases.
+ */
+ if (ptr->id.data == NULL) {
+ return;
+ }
+ PointerRNA orig_ptr = *ptr;
+ orig_ptr.id.data = ((ID *)orig_ptr.id.data)->orig_id;
+ orig_ptr.data = orig_ptr.id.data;
+ PathResolvedRNA orig_anim_rna;
+ /* TODO(sergey): Is there a faster way to get anim_rna of original ID? */
+ if (animsys_store_rna_setting(&orig_ptr, rna_path, array_index, &orig_anim_rna)) {
+ animsys_write_rna_setting(&orig_anim_rna, value);
+ }
}
/* Evaluate all the F-Curves in the given list
* This performs a set of standard checks. If extra checks are required, separate code should be used
*/
-static void animsys_evaluate_fcurves(
- Depsgraph *depsgraph, PointerRNA *ptr, ListBase *list, float ctime)
-{
- const bool is_active_depsgraph = DEG_is_active(depsgraph);
- /* Calculate then execute each curve. */
- for (FCurve *fcu = list->first; fcu; fcu = fcu->next) {
- /* Check if this F-Curve doesn't belong to a muted group. */
- if ((fcu->grp != NULL) && (fcu->grp->flag & AGRP_MUTED)) {
- continue;
- }
- /* Check if this curve should be skipped. */
- if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED))) {
- continue;
- }
- PathResolvedRNA anim_rna;
- if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
- const float curval = calculate_fcurve(&anim_rna, fcu, ctime);
- animsys_write_rna_setting(&anim_rna, curval);
- if (is_active_depsgraph) {
- animsys_write_orig_anim_rna(ptr, fcu->rna_path, fcu->array_index, curval);
- }
- }
- }
+static void animsys_evaluate_fcurves(Depsgraph *depsgraph,
+ PointerRNA *ptr,
+ ListBase *list,
+ float ctime)
+{
+ const bool is_active_depsgraph = DEG_is_active(depsgraph);
+ /* Calculate then execute each curve. */
+ for (FCurve *fcu = list->first; fcu; fcu = fcu->next) {
+ /* Check if this F-Curve doesn't belong to a muted group. */
+ if ((fcu->grp != NULL) && (fcu->grp->flag & AGRP_MUTED)) {
+ continue;
+ }
+ /* Check if this curve should be skipped. */
+ if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED))) {
+ continue;
+ }
+ PathResolvedRNA anim_rna;
+ if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
+ const float curval = calculate_fcurve(&anim_rna, fcu, ctime);
+ animsys_write_rna_setting(&anim_rna, curval);
+ if (is_active_depsgraph) {
+ animsys_write_orig_anim_rna(ptr, fcu->rna_path, fcu->array_index, curval);
+ }
+ }
+ }
}
/* ***************************************** */
@@ -1757,36 +1849,36 @@ static void animsys_evaluate_fcurves(
/* Evaluate Drivers */
static void animsys_evaluate_drivers(PointerRNA *ptr, AnimData *adt, float ctime)
{
- FCurve *fcu;
-
- /* drivers are stored as F-Curves, but we cannot use the standard code, as we need to check if
- * the depsgraph requested that this driver be evaluated...
- */
- for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
- ChannelDriver *driver = fcu->driver;
- bool ok = false;
-
- /* check if this driver's curve should be skipped */
- if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) {
- /* check if driver itself is tagged for recalculation */
- /* XXX driver recalc flag is not set yet by depsgraph! */
- if ((driver) && !(driver->flag & DRIVER_FLAG_INVALID)) {
- /* 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 */
-
- PathResolvedRNA anim_rna;
- if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
- const float curval = calculate_fcurve(&anim_rna, fcu, ctime);
- ok = animsys_write_rna_setting(&anim_rna, curval);
- }
-
- /* set error-flag if evaluation failed */
- if (ok == 0)
- driver->flag |= DRIVER_FLAG_INVALID;
- }
- }
- }
+ FCurve *fcu;
+
+ /* drivers are stored as F-Curves, but we cannot use the standard code, as we need to check if
+ * the depsgraph requested that this driver be evaluated...
+ */
+ for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
+ ChannelDriver *driver = fcu->driver;
+ bool ok = false;
+
+ /* check if this driver's curve should be skipped */
+ if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) {
+ /* check if driver itself is tagged for recalculation */
+ /* XXX driver recalc flag is not set yet by depsgraph! */
+ if ((driver) && !(driver->flag & DRIVER_FLAG_INVALID)) {
+ /* 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 */
+
+ PathResolvedRNA anim_rna;
+ if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
+ const float curval = calculate_fcurve(&anim_rna, fcu, ctime);
+ ok = animsys_write_rna_setting(&anim_rna, curval);
+ }
+
+ /* set error-flag if evaluation failed */
+ if (ok == 0)
+ driver->flag |= DRIVER_FLAG_INVALID;
+ }
+ }
+ }
}
/* ***************************************** */
@@ -1798,29 +1890,33 @@ static void animsys_evaluate_drivers(PointerRNA *ptr, AnimData *adt, float ctime
*/
static void action_idcode_patch_check(ID *id, bAction *act)
{
- int idcode = 0;
-
- /* just in case */
- if (ELEM(NULL, id, act))
- return;
- else
- idcode = GS(id->name);
-
- /* the actual checks... hopefully not too much of a performance hit in the long run... */
- if (act->idroot == 0) {
- /* use the current root if not set already (i.e. newly created actions and actions from 2.50-2.57 builds)
- * - this has problems if there are 2 users, and the first one encountered is the invalid one
- * in which case, the user will need to manually fix this (?)
- */
- act->idroot = idcode;
- }
- else if (act->idroot != idcode) {
- /* only report this error if debug mode is enabled (to save performance everywhere else) */
- if (G.debug & G_DEBUG) {
- printf("AnimSys Safety Check Failed: Action '%s' is not meant to be used from ID-Blocks of type %d such as '%s'\n",
- act->id.name + 2, idcode, id->name);
- }
- }
+ int idcode = 0;
+
+ /* just in case */
+ if (ELEM(NULL, id, act))
+ return;
+ else
+ idcode = GS(id->name);
+
+ /* the actual checks... hopefully not too much of a performance hit in the long run... */
+ if (act->idroot == 0) {
+ /* use the current root if not set already (i.e. newly created actions and actions from 2.50-2.57 builds)
+ * - this has problems if there are 2 users, and the first one encountered is the invalid one
+ * in which case, the user will need to manually fix this (?)
+ */
+ act->idroot = idcode;
+ }
+ else if (act->idroot != idcode) {
+ /* only report this error if debug mode is enabled (to save performance everywhere else) */
+ if (G.debug & G_DEBUG) {
+ printf(
+ "AnimSys Safety Check Failed: Action '%s' is not meant to be used from ID-Blocks of "
+ "type %d such as '%s'\n",
+ act->id.name + 2,
+ idcode,
+ id->name);
+ }
+ }
}
/* ----------------------------------------- */
@@ -1828,46 +1924,50 @@ static void action_idcode_patch_check(ID *id, bAction *act)
/* Evaluate Action Group */
void animsys_evaluate_action_group(PointerRNA *ptr, bAction *act, bActionGroup *agrp, float ctime)
{
- FCurve *fcu;
+ FCurve *fcu;
- /* check if mapper is appropriate for use here (we set to NULL if it's inappropriate) */
- if (ELEM(NULL, act, agrp)) return;
+ /* check if mapper is appropriate for use here (we set to NULL if it's inappropriate) */
+ if (ELEM(NULL, act, agrp))
+ return;
- action_idcode_patch_check(ptr->id.data, act);
+ action_idcode_patch_check(ptr->id.data, act);
- /* if group is muted, don't evaluated any of the F-Curve */
- if (agrp->flag & AGRP_MUTED)
- return;
+ /* if group is muted, don't evaluated any of the F-Curve */
+ if (agrp->flag & AGRP_MUTED)
+ return;
- /* calculate then execute each curve */
- 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) {
- PathResolvedRNA anim_rna;
- if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
- const float curval = calculate_fcurve(&anim_rna, fcu, ctime);
- animsys_write_rna_setting(&anim_rna, curval);
- }
- }
- }
+ /* calculate then execute each curve */
+ 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) {
+ PathResolvedRNA anim_rna;
+ if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
+ const float curval = calculate_fcurve(&anim_rna, fcu, ctime);
+ animsys_write_rna_setting(&anim_rna, curval);
+ }
+ }
+ }
}
/* Evaluate Action (F-Curve Bag) */
-static void animsys_evaluate_action_ex(
- Depsgraph *depsgraph, PointerRNA *ptr, bAction *act, float ctime)
+static void animsys_evaluate_action_ex(Depsgraph *depsgraph,
+ PointerRNA *ptr,
+ bAction *act,
+ float ctime)
{
- /* check if mapper is appropriate for use here (we set to NULL if it's inappropriate) */
- if (act == NULL) return;
+ /* check if mapper is appropriate for use here (we set to NULL if it's inappropriate) */
+ if (act == NULL)
+ return;
- action_idcode_patch_check(ptr->id.data, act);
+ action_idcode_patch_check(ptr->id.data, act);
- /* calculate then execute each curve */
- animsys_evaluate_fcurves(depsgraph, ptr, &act->curves, ctime);
+ /* calculate then execute each curve */
+ animsys_evaluate_fcurves(depsgraph, ptr, &act->curves, ctime);
}
void animsys_evaluate_action(Depsgraph *depsgraph, PointerRNA *ptr, bAction *act, float ctime)
{
- animsys_evaluate_action_ex(depsgraph, ptr, act, ctime);
+ animsys_evaluate_action_ex(depsgraph, ptr, act, ctime);
}
/* ***************************************** */
@@ -1876,178 +1976,180 @@ void animsys_evaluate_action(Depsgraph *depsgraph, PointerRNA *ptr, bAction *act
/* calculate influence of strip based for given frame based on blendin/out values */
static float nlastrip_get_influence(NlaStrip *strip, float cframe)
{
- /* sanity checks - normalize the blendin/out values? */
- strip->blendin = fabsf(strip->blendin);
- strip->blendout = fabsf(strip->blendout);
-
- /* result depends on where frame is in respect to blendin/out values */
- if (IS_EQF(strip->blendin, 0.0f) == false && (cframe <= (strip->start + strip->blendin))) {
- /* there is some blend-in */
- return fabsf(cframe - strip->start) / (strip->blendin);
- }
- else if (IS_EQF(strip->blendout, 0.0f) == false && (cframe >= (strip->end - strip->blendout))) {
- /* there is some blend-out */
- return fabsf(strip->end - cframe) / (strip->blendout);
- }
- else {
- /* in the middle of the strip, we should be full strength */
- return 1.0f;
- }
+ /* sanity checks - normalize the blendin/out values? */
+ strip->blendin = fabsf(strip->blendin);
+ strip->blendout = fabsf(strip->blendout);
+
+ /* result depends on where frame is in respect to blendin/out values */
+ if (IS_EQF(strip->blendin, 0.0f) == false && (cframe <= (strip->start + strip->blendin))) {
+ /* there is some blend-in */
+ return fabsf(cframe - strip->start) / (strip->blendin);
+ }
+ else if (IS_EQF(strip->blendout, 0.0f) == false && (cframe >= (strip->end - strip->blendout))) {
+ /* there is some blend-out */
+ return fabsf(strip->end - cframe) / (strip->blendout);
+ }
+ else {
+ /* in the middle of the strip, we should be full strength */
+ return 1.0f;
+ }
}
/* evaluate the evaluation time and influence for the strip, storing the results in the strip */
static void nlastrip_evaluate_controls(Depsgraph *depsgraph, NlaStrip *strip, float ctime)
{
- /* now strip's evaluate F-Curves for these settings (if applicable) */
- if (strip->fcurves.first) {
- PointerRNA strip_ptr;
+ /* now strip's evaluate F-Curves for these settings (if applicable) */
+ if (strip->fcurves.first) {
+ PointerRNA strip_ptr;
- /* create RNA-pointer needed to set values */
- RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr);
+ /* create RNA-pointer needed to set values */
+ RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr);
- /* execute these settings as per normal */
- animsys_evaluate_fcurves(depsgraph, &strip_ptr, &strip->fcurves, ctime);
- }
+ /* execute these settings as per normal */
+ animsys_evaluate_fcurves(depsgraph, &strip_ptr, &strip->fcurves, ctime);
+ }
- /* analytically generate values for influence and time (if applicable)
- * - we do this after the F-Curves have been evaluated to override the effects of those
- * in case the override has been turned off.
- */
- if ((strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) == 0)
- strip->influence = nlastrip_get_influence(strip, ctime);
+ /* analytically generate values for influence and time (if applicable)
+ * - we do this after the F-Curves have been evaluated to override the effects of those
+ * in case the override has been turned off.
+ */
+ if ((strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) == 0)
+ strip->influence = nlastrip_get_influence(strip, ctime);
- /* Bypass evaluation time computation if time mapping is disabled. */
- if ((strip->flag & NLASTRIP_FLAG_NO_TIME_MAP) != 0) {
- strip->strip_time = ctime;
- return;
- }
+ /* Bypass evaluation time computation if time mapping is disabled. */
+ if ((strip->flag & NLASTRIP_FLAG_NO_TIME_MAP) != 0) {
+ strip->strip_time = ctime;
+ return;
+ }
- if ((strip->flag & NLASTRIP_FLAG_USR_TIME) == 0)
- strip->strip_time = nlastrip_get_frame(strip, ctime, NLATIME_CONVERT_EVAL);
+ if ((strip->flag & NLASTRIP_FLAG_USR_TIME) == 0)
+ strip->strip_time = nlastrip_get_frame(strip, ctime, NLATIME_CONVERT_EVAL);
- /* if user can control the evaluation time (using F-Curves), consider the option which allows this time to be clamped
- * to lie within extents of the action-clip, so that a steady changing rate of progress through several cycles of the clip
- * can be achieved easily
- */
- /* NOTE: if we add any more of these special cases, we better group them up nicely... */
- if ((strip->flag & NLASTRIP_FLAG_USR_TIME) && (strip->flag & NLASTRIP_FLAG_USR_TIME_CYCLIC))
- strip->strip_time = fmod(strip->strip_time - strip->actstart, strip->actend - strip->actstart);
+ /* if user can control the evaluation time (using F-Curves), consider the option which allows this time to be clamped
+ * to lie within extents of the action-clip, so that a steady changing rate of progress through several cycles of the clip
+ * can be achieved easily
+ */
+ /* NOTE: if we add any more of these special cases, we better group them up nicely... */
+ if ((strip->flag & NLASTRIP_FLAG_USR_TIME) && (strip->flag & NLASTRIP_FLAG_USR_TIME_CYCLIC))
+ strip->strip_time = fmod(strip->strip_time - strip->actstart, strip->actend - strip->actstart);
}
/* gets the strip active at the current time for a list of strips for evaluation purposes */
-NlaEvalStrip *nlastrips_ctime_get_strip(Depsgraph *depsgraph, ListBase *list, ListBase *strips, short index, float ctime)
-{
- NlaStrip *strip, *estrip = NULL;
- NlaEvalStrip *nes;
- short side = 0;
-
- /* loop over strips, checking if they fall within the range */
- for (strip = strips->first; strip; strip = strip->next) {
- /* check if current time occurs within this strip */
- if (IN_RANGE_INCL(ctime, strip->start, strip->end) || (strip->flag & NLASTRIP_FLAG_NO_TIME_MAP)) {
- /* this strip is active, so try to use it */
- estrip = strip;
- side = NES_TIME_WITHIN;
- break;
- }
-
- /* if time occurred before current strip... */
- if (ctime < strip->start) {
- if (strip == strips->first) {
- /* before first strip - only try to use it if it extends backwards in time too */
- if (strip->extendmode == NLASTRIP_EXTEND_HOLD)
- estrip = strip;
-
- /* side is 'before' regardless of whether there's a useful strip */
- side = NES_TIME_BEFORE;
- }
- else {
- /* before next strip - previous strip has ended, but next hasn't begun,
- * so blending mode depends on whether strip is being held or not...
- * - only occurs when no transition strip added, otherwise the transition would have
- * been picked up above...
- */
- strip = strip->prev;
-
- if (strip->extendmode != NLASTRIP_EXTEND_NOTHING)
- estrip = strip;
- side = NES_TIME_AFTER;
- }
- break;
- }
-
- /* if time occurred after current strip... */
- if (ctime > strip->end) {
- /* only if this is the last strip should we do anything, and only if that is being held */
- if (strip == strips->last) {
- if (strip->extendmode != NLASTRIP_EXTEND_NOTHING)
- estrip = strip;
-
- side = NES_TIME_AFTER;
- break;
- }
-
- /* otherwise, skip... as the 'before' case will catch it more elegantly! */
- }
- }
-
- /* check if a valid strip was found
- * - must not be muted (i.e. will have contribution
- */
- if ((estrip == NULL) || (estrip->flag & NLASTRIP_FLAG_MUTED))
- return NULL;
-
- /* if ctime was not within the boundaries of the strip, clamp! */
- switch (side) {
- case NES_TIME_BEFORE: /* extend first frame only */
- ctime = estrip->start;
- break;
- case NES_TIME_AFTER: /* extend last frame only */
- ctime = estrip->end;
- break;
- }
-
- /* evaluate strip's evaluation controls
- * - skip if no influence (i.e. same effect as muting the strip)
- * - negative influence is not supported yet... how would that be defined?
- */
- /* TODO: this sounds a bit hacky having a few isolated F-Curves stuck on some data it operates on... */
- nlastrip_evaluate_controls(depsgraph, estrip, ctime);
- if (estrip->influence <= 0.0f)
- return NULL;
-
- /* check if strip has valid data to evaluate,
- * and/or perform any additional type-specific actions
- */
- switch (estrip->type) {
- case NLASTRIP_TYPE_CLIP:
- /* clip must have some action to evaluate */
- if (estrip->act == NULL)
- return NULL;
- break;
- case NLASTRIP_TYPE_TRANSITION:
- /* there must be strips to transition from and to (i.e. prev and next required) */
- if (ELEM(NULL, estrip->prev, estrip->next))
- return NULL;
-
- /* evaluate controls for the relevant extents of the bordering strips... */
- nlastrip_evaluate_controls(depsgraph, estrip->prev, estrip->start);
- nlastrip_evaluate_controls(depsgraph, estrip->next, estrip->end);
- break;
- }
-
- /* add to list of strips we need to evaluate */
- nes = MEM_callocN(sizeof(NlaEvalStrip), "NlaEvalStrip");
-
- nes->strip = estrip;
- nes->strip_mode = side;
- nes->track_index = index;
- nes->strip_time = estrip->strip_time;
-
- if (list)
- BLI_addtail(list, nes);
-
- return nes;
+NlaEvalStrip *nlastrips_ctime_get_strip(
+ Depsgraph *depsgraph, ListBase *list, ListBase *strips, short index, float ctime)
+{
+ NlaStrip *strip, *estrip = NULL;
+ NlaEvalStrip *nes;
+ short side = 0;
+
+ /* loop over strips, checking if they fall within the range */
+ for (strip = strips->first; strip; strip = strip->next) {
+ /* check if current time occurs within this strip */
+ if (IN_RANGE_INCL(ctime, strip->start, strip->end) ||
+ (strip->flag & NLASTRIP_FLAG_NO_TIME_MAP)) {
+ /* this strip is active, so try to use it */
+ estrip = strip;
+ side = NES_TIME_WITHIN;
+ break;
+ }
+
+ /* if time occurred before current strip... */
+ if (ctime < strip->start) {
+ if (strip == strips->first) {
+ /* before first strip - only try to use it if it extends backwards in time too */
+ if (strip->extendmode == NLASTRIP_EXTEND_HOLD)
+ estrip = strip;
+
+ /* side is 'before' regardless of whether there's a useful strip */
+ side = NES_TIME_BEFORE;
+ }
+ else {
+ /* before next strip - previous strip has ended, but next hasn't begun,
+ * so blending mode depends on whether strip is being held or not...
+ * - only occurs when no transition strip added, otherwise the transition would have
+ * been picked up above...
+ */
+ strip = strip->prev;
+
+ if (strip->extendmode != NLASTRIP_EXTEND_NOTHING)
+ estrip = strip;
+ side = NES_TIME_AFTER;
+ }
+ break;
+ }
+
+ /* if time occurred after current strip... */
+ if (ctime > strip->end) {
+ /* only if this is the last strip should we do anything, and only if that is being held */
+ if (strip == strips->last) {
+ if (strip->extendmode != NLASTRIP_EXTEND_NOTHING)
+ estrip = strip;
+
+ side = NES_TIME_AFTER;
+ break;
+ }
+
+ /* otherwise, skip... as the 'before' case will catch it more elegantly! */
+ }
+ }
+
+ /* check if a valid strip was found
+ * - must not be muted (i.e. will have contribution
+ */
+ if ((estrip == NULL) || (estrip->flag & NLASTRIP_FLAG_MUTED))
+ return NULL;
+
+ /* if ctime was not within the boundaries of the strip, clamp! */
+ switch (side) {
+ case NES_TIME_BEFORE: /* extend first frame only */
+ ctime = estrip->start;
+ break;
+ case NES_TIME_AFTER: /* extend last frame only */
+ ctime = estrip->end;
+ break;
+ }
+
+ /* evaluate strip's evaluation controls
+ * - skip if no influence (i.e. same effect as muting the strip)
+ * - negative influence is not supported yet... how would that be defined?
+ */
+ /* TODO: this sounds a bit hacky having a few isolated F-Curves stuck on some data it operates on... */
+ nlastrip_evaluate_controls(depsgraph, estrip, ctime);
+ if (estrip->influence <= 0.0f)
+ return NULL;
+
+ /* check if strip has valid data to evaluate,
+ * and/or perform any additional type-specific actions
+ */
+ switch (estrip->type) {
+ case NLASTRIP_TYPE_CLIP:
+ /* clip must have some action to evaluate */
+ if (estrip->act == NULL)
+ return NULL;
+ break;
+ case NLASTRIP_TYPE_TRANSITION:
+ /* there must be strips to transition from and to (i.e. prev and next required) */
+ if (ELEM(NULL, estrip->prev, estrip->next))
+ return NULL;
+
+ /* evaluate controls for the relevant extents of the bordering strips... */
+ nlastrip_evaluate_controls(depsgraph, estrip->prev, estrip->start);
+ nlastrip_evaluate_controls(depsgraph, estrip->next, estrip->end);
+ break;
+ }
+
+ /* add to list of strips we need to evaluate */
+ nes = MEM_callocN(sizeof(NlaEvalStrip), "NlaEvalStrip");
+
+ nes->strip = estrip;
+ nes->strip_mode = side;
+ nes->track_index = index;
+ nes->strip_time = estrip->strip_time;
+
+ if (list)
+ BLI_addtail(list, nes);
+
+ return nes;
}
/* ---------------------- */
@@ -2055,20 +2157,20 @@ NlaEvalStrip *nlastrips_ctime_get_strip(Depsgraph *depsgraph, ListBase *list, Li
/* Initialize a valid mask, allocating memory if necessary. */
static void nlavalidmask_init(NlaValidMask *mask, int bits)
{
- if (BLI_BITMAP_SIZE(bits) > sizeof(mask->buffer)) {
- mask->ptr = BLI_BITMAP_NEW(bits, "NlaValidMask");
- }
- else {
- mask->ptr = mask->buffer;
- }
+ if (BLI_BITMAP_SIZE(bits) > sizeof(mask->buffer)) {
+ mask->ptr = BLI_BITMAP_NEW(bits, "NlaValidMask");
+ }
+ else {
+ mask->ptr = mask->buffer;
+ }
}
/* Free allocated memory for the mask. */
static void nlavalidmask_free(NlaValidMask *mask)
{
- if (mask->ptr != mask->buffer) {
- MEM_freeN(mask->ptr);
- }
+ if (mask->ptr != mask->buffer) {
+ MEM_freeN(mask->ptr);
+ }
}
/* ---------------------- */
@@ -2076,18 +2178,17 @@ static void nlavalidmask_free(NlaValidMask *mask)
/* Hashing functions for NlaEvalChannelKey. */
static uint nlaevalchan_keyhash(const void *ptr)
{
- const NlaEvalChannelKey *key = ptr;
- uint hash = BLI_ghashutil_ptrhash(key->ptr.data);
- return hash ^ BLI_ghashutil_ptrhash(key->prop);
+ const NlaEvalChannelKey *key = ptr;
+ uint hash = BLI_ghashutil_ptrhash(key->ptr.data);
+ return hash ^ BLI_ghashutil_ptrhash(key->prop);
}
static bool nlaevalchan_keycmp(const void *a, const void *b)
{
- const NlaEvalChannelKey *A = a;
- const NlaEvalChannelKey *B = b;
+ const NlaEvalChannelKey *A = a;
+ const NlaEvalChannelKey *B = b;
- return ((A->ptr.data != B->ptr.data) ||
- (A->prop != B->prop));
+ return ((A->ptr.data != B->ptr.data) || (A->prop != B->prop));
}
/* ---------------------- */
@@ -2095,119 +2196,127 @@ static bool nlaevalchan_keycmp(const void *a, const void *b)
/* Allocate a new blending value snapshot for the channel. */
static NlaEvalChannelSnapshot *nlaevalchan_snapshot_new(NlaEvalChannel *nec)
{
- int length = nec->base_snapshot.length;
+ int length = nec->base_snapshot.length;
- size_t byte_size = sizeof(NlaEvalChannelSnapshot) + sizeof(float) * length;
- NlaEvalChannelSnapshot *nec_snapshot = MEM_callocN(byte_size, "NlaEvalChannelSnapshot");
+ size_t byte_size = sizeof(NlaEvalChannelSnapshot) + sizeof(float) * length;
+ NlaEvalChannelSnapshot *nec_snapshot = MEM_callocN(byte_size, "NlaEvalChannelSnapshot");
- nec_snapshot->channel = nec;
- nec_snapshot->length = length;
+ nec_snapshot->channel = nec;
+ nec_snapshot->length = length;
- return nec_snapshot;
+ return nec_snapshot;
}
/* Free a channel's blending value snapshot. */
static void nlaevalchan_snapshot_free(NlaEvalChannelSnapshot *nec_snapshot)
{
- BLI_assert(!nec_snapshot->is_base);
+ BLI_assert(!nec_snapshot->is_base);
- MEM_freeN(nec_snapshot);
+ MEM_freeN(nec_snapshot);
}
/* Copy all data in the snapshot. */
-static void nlaevalchan_snapshot_copy(NlaEvalChannelSnapshot *dst, const NlaEvalChannelSnapshot *src)
+static void nlaevalchan_snapshot_copy(NlaEvalChannelSnapshot *dst,
+ const NlaEvalChannelSnapshot *src)
{
- BLI_assert(dst->channel == src->channel);
+ BLI_assert(dst->channel == src->channel);
- memcpy(dst->values, src->values, sizeof(float) * dst->length);
+ memcpy(dst->values, src->values, sizeof(float) * dst->length);
}
/* ---------------------- */
/* Initialize a blending state snapshot structure. */
-static void nlaeval_snapshot_init(NlaEvalSnapshot *snapshot, NlaEvalData *nlaeval, NlaEvalSnapshot *base)
+static void nlaeval_snapshot_init(NlaEvalSnapshot *snapshot,
+ NlaEvalData *nlaeval,
+ NlaEvalSnapshot *base)
{
- snapshot->base = base;
- snapshot->size = MAX2(16, nlaeval->num_channels);
- snapshot->channels = MEM_callocN(sizeof(*snapshot->channels) * snapshot->size, "NlaEvalSnapshot::channels");
+ snapshot->base = base;
+ snapshot->size = MAX2(16, nlaeval->num_channels);
+ snapshot->channels = MEM_callocN(sizeof(*snapshot->channels) * snapshot->size,
+ "NlaEvalSnapshot::channels");
}
/* Retrieve the individual channel snapshot. */
static NlaEvalChannelSnapshot *nlaeval_snapshot_get(NlaEvalSnapshot *snapshot, int index)
{
- return (index < snapshot->size) ? snapshot->channels[index] : NULL;
+ return (index < snapshot->size) ? snapshot->channels[index] : NULL;
}
/* Ensure at least this number of slots exists. */
static void nlaeval_snapshot_ensure_size(NlaEvalSnapshot *snapshot, int size)
{
- if (size > snapshot->size) {
- snapshot->size *= 2;
- CLAMP_MIN(snapshot->size, size);
- CLAMP_MIN(snapshot->size, 16);
+ if (size > snapshot->size) {
+ snapshot->size *= 2;
+ CLAMP_MIN(snapshot->size, size);
+ CLAMP_MIN(snapshot->size, 16);
- size_t byte_size = sizeof(*snapshot->channels) * snapshot->size;
- snapshot->channels = MEM_recallocN_id(snapshot->channels, byte_size, "NlaEvalSnapshot::channels");
- }
+ size_t byte_size = sizeof(*snapshot->channels) * snapshot->size;
+ snapshot->channels = MEM_recallocN_id(
+ snapshot->channels, byte_size, "NlaEvalSnapshot::channels");
+ }
}
/* Retrieve the address of a slot in the blending state snapshot for this channel (may realloc). */
-static NlaEvalChannelSnapshot **nlaeval_snapshot_ensure_slot(NlaEvalSnapshot *snapshot, NlaEvalChannel *nec)
+static NlaEvalChannelSnapshot **nlaeval_snapshot_ensure_slot(NlaEvalSnapshot *snapshot,
+ NlaEvalChannel *nec)
{
- nlaeval_snapshot_ensure_size(snapshot, nec->owner->num_channels);
- return &snapshot->channels[nec->index];
+ nlaeval_snapshot_ensure_size(snapshot, nec->owner->num_channels);
+ return &snapshot->channels[nec->index];
}
/* Retrieve the blending snapshot for the specified channel, with fallback to base. */
-static NlaEvalChannelSnapshot *nlaeval_snapshot_find_channel(NlaEvalSnapshot *snapshot, NlaEvalChannel *nec)
+static NlaEvalChannelSnapshot *nlaeval_snapshot_find_channel(NlaEvalSnapshot *snapshot,
+ NlaEvalChannel *nec)
{
- while (snapshot != NULL) {
- NlaEvalChannelSnapshot *nec_snapshot = nlaeval_snapshot_get(snapshot, nec->index);
- if (nec_snapshot != NULL) {
- return nec_snapshot;
- }
- snapshot = snapshot->base;
- }
+ while (snapshot != NULL) {
+ NlaEvalChannelSnapshot *nec_snapshot = nlaeval_snapshot_get(snapshot, nec->index);
+ if (nec_snapshot != NULL) {
+ return nec_snapshot;
+ }
+ snapshot = snapshot->base;
+ }
- return &nec->base_snapshot;
+ return &nec->base_snapshot;
}
/* Retrieve or create the channel value snapshot, copying from the other snapshot (or default values) */
-static NlaEvalChannelSnapshot *nlaeval_snapshot_ensure_channel(NlaEvalSnapshot *snapshot, NlaEvalChannel *nec)
+static NlaEvalChannelSnapshot *nlaeval_snapshot_ensure_channel(NlaEvalSnapshot *snapshot,
+ NlaEvalChannel *nec)
{
- NlaEvalChannelSnapshot **slot = nlaeval_snapshot_ensure_slot(snapshot, nec);
+ NlaEvalChannelSnapshot **slot = nlaeval_snapshot_ensure_slot(snapshot, nec);
- if (*slot == NULL) {
- NlaEvalChannelSnapshot *base_snapshot, *nec_snapshot;
+ if (*slot == NULL) {
+ NlaEvalChannelSnapshot *base_snapshot, *nec_snapshot;
- nec_snapshot = nlaevalchan_snapshot_new(nec);
- base_snapshot = nlaeval_snapshot_find_channel(snapshot->base, nec);
+ nec_snapshot = nlaevalchan_snapshot_new(nec);
+ base_snapshot = nlaeval_snapshot_find_channel(snapshot->base, nec);
- nlaevalchan_snapshot_copy(nec_snapshot, base_snapshot);
+ nlaevalchan_snapshot_copy(nec_snapshot, base_snapshot);
- *slot = nec_snapshot;
- }
+ *slot = nec_snapshot;
+ }
- return *slot;
+ return *slot;
}
/* Free all memory owned by this blending snapshot structure. */
static void nlaeval_snapshot_free_data(NlaEvalSnapshot *snapshot)
{
- if (snapshot->channels != NULL) {
- for (int i = 0; i < snapshot->size; i++) {
- NlaEvalChannelSnapshot *nec_snapshot = snapshot->channels[i];
- if (nec_snapshot != NULL) {
- nlaevalchan_snapshot_free(nec_snapshot);
- }
- }
+ if (snapshot->channels != NULL) {
+ for (int i = 0; i < snapshot->size; i++) {
+ NlaEvalChannelSnapshot *nec_snapshot = snapshot->channels[i];
+ if (nec_snapshot != NULL) {
+ nlaevalchan_snapshot_free(nec_snapshot);
+ }
+ }
- MEM_freeN(snapshot->channels);
- }
+ MEM_freeN(snapshot->channels);
+ }
- snapshot->base = NULL;
- snapshot->size = 0;
- snapshot->channels = NULL;
+ snapshot->base = NULL;
+ snapshot->size = 0;
+ snapshot->channels = NULL;
}
/* ---------------------- */
@@ -2215,240 +2324,247 @@ static void nlaeval_snapshot_free_data(NlaEvalSnapshot *snapshot)
/* Free memory owned by this evaluation channel. */
static void nlaevalchan_free_data(NlaEvalChannel *nec)
{
- nlavalidmask_free(&nec->valid);
+ nlavalidmask_free(&nec->valid);
- if (nec->blend_snapshot != NULL) {
- nlaevalchan_snapshot_free(nec->blend_snapshot);
- }
+ if (nec->blend_snapshot != NULL) {
+ nlaevalchan_snapshot_free(nec->blend_snapshot);
+ }
}
/* Initialize a full NLA evaluation state structure. */
static void nlaeval_init(NlaEvalData *nlaeval)
{
- memset(nlaeval, 0, sizeof(*nlaeval));
+ memset(nlaeval, 0, sizeof(*nlaeval));
- nlaeval->path_hash = BLI_ghash_str_new("NlaEvalData::path_hash");
- nlaeval->key_hash = BLI_ghash_new(nlaevalchan_keyhash, nlaevalchan_keycmp, "NlaEvalData::key_hash");
+ nlaeval->path_hash = BLI_ghash_str_new("NlaEvalData::path_hash");
+ nlaeval->key_hash = BLI_ghash_new(
+ nlaevalchan_keyhash, nlaevalchan_keycmp, "NlaEvalData::key_hash");
}
static void nlaeval_free(NlaEvalData *nlaeval)
{
- /* Delete base snapshot - its channels are part of NlaEvalChannel and shouldn't be freed. */
- MEM_SAFE_FREE(nlaeval->base_snapshot.channels);
+ /* Delete base snapshot - its channels are part of NlaEvalChannel and shouldn't be freed. */
+ MEM_SAFE_FREE(nlaeval->base_snapshot.channels);
- /* Delete result snapshot. */
- nlaeval_snapshot_free_data(&nlaeval->eval_snapshot);
+ /* Delete result snapshot. */
+ nlaeval_snapshot_free_data(&nlaeval->eval_snapshot);
- /* Delete channels. */
- for (NlaEvalChannel *nec = nlaeval->channels.first; nec; nec = nec->next) {
- nlaevalchan_free_data(nec);
- }
+ /* Delete channels. */
+ for (NlaEvalChannel *nec = nlaeval->channels.first; nec; nec = nec->next) {
+ nlaevalchan_free_data(nec);
+ }
- BLI_freelistN(&nlaeval->channels);
- BLI_ghash_free(nlaeval->path_hash, NULL, NULL);
- BLI_ghash_free(nlaeval->key_hash, NULL, NULL);
+ BLI_freelistN(&nlaeval->channels);
+ BLI_ghash_free(nlaeval->path_hash, NULL, NULL);
+ BLI_ghash_free(nlaeval->key_hash, NULL, NULL);
}
/* ---------------------- */
static int nlaevalchan_validate_index(NlaEvalChannel *nec, int index)
{
- if (nec->is_array) {
- if (index >= 0 && index < nec->base_snapshot.length) {
- return index;
- }
+ if (nec->is_array) {
+ if (index >= 0 && index < nec->base_snapshot.length) {
+ return index;
+ }
- return -1;
- }
- else {
- return 0;
- }
+ return -1;
+ }
+ else {
+ return 0;
+ }
}
/* Initialise default values for NlaEvalChannel from the property data. */
static void nlaevalchan_get_default_values(NlaEvalChannel *nec, float *r_values)
{
- PointerRNA *ptr = &nec->key.ptr;
- PropertyRNA *prop = nec->key.prop;
- int length = nec->base_snapshot.length;
-
- /* Use unit quaternion for quaternion properties. */
- if (nec->mix_mode == NEC_MIX_QUATERNION) {
- unit_qt(r_values);
- return;
- }
- /* Use all zero for Axis-Angle properties. */
- if (nec->mix_mode == NEC_MIX_AXIS_ANGLE) {
- zero_v4(r_values);
- return;
- }
-
- /* NOTE: while this doesn't work for all RNA properties as default values aren't in fact
- * set properly for most of them, at least the common ones (which also happen to get used
- * in NLA strips a lot, e.g. scale) are set correctly.
- */
- if (RNA_property_array_check(prop)) {
- BLI_assert(length == RNA_property_array_length(ptr, prop));
- bool *tmp_bool;
- int *tmp_int;
-
- switch (RNA_property_type(prop)) {
- case PROP_BOOLEAN:
- tmp_bool = MEM_malloc_arrayN(sizeof(*tmp_bool), length, __func__);
- RNA_property_boolean_get_default_array(ptr, prop, tmp_bool);
- for (int i = 0; i < length; i++) {
- r_values[i] = (float)tmp_bool[i];
- }
- MEM_freeN(tmp_bool);
- break;
- case PROP_INT:
- tmp_int = MEM_malloc_arrayN(sizeof(*tmp_int), length, __func__);
- RNA_property_int_get_default_array(ptr, prop, tmp_int);
- for (int i = 0; i < length; i++) {
- r_values[i] = (float)tmp_int[i];
- }
- MEM_freeN(tmp_int);
- break;
- case PROP_FLOAT:
- RNA_property_float_get_default_array(ptr, prop, r_values);
- break;
- default:
- memset(r_values, 0, sizeof(float) * length);
- }
- }
- else {
- BLI_assert(length == 1);
-
- switch (RNA_property_type(prop)) {
- case PROP_BOOLEAN:
- *r_values = (float)RNA_property_boolean_get_default(ptr, prop);
- break;
- case PROP_INT:
- *r_values = (float)RNA_property_int_get_default(ptr, prop);
- break;
- case PROP_FLOAT:
- *r_values = RNA_property_float_get_default(ptr, prop);
- break;
- case PROP_ENUM:
- *r_values = (float)RNA_property_enum_get_default(ptr, prop);
- break;
- default:
- *r_values = 0.0f;
- }
- }
-
- /* Ensure multiplicative properties aren't reset to 0. */
- if (nec->mix_mode == NEC_MIX_MULTIPLY) {
- for (int i = 0; i < length; i++) {
- if (r_values[i] == 0.0f) {
- r_values[i] = 1.0f;
- }
- }
- }
+ PointerRNA *ptr = &nec->key.ptr;
+ PropertyRNA *prop = nec->key.prop;
+ int length = nec->base_snapshot.length;
+
+ /* Use unit quaternion for quaternion properties. */
+ if (nec->mix_mode == NEC_MIX_QUATERNION) {
+ unit_qt(r_values);
+ return;
+ }
+ /* Use all zero for Axis-Angle properties. */
+ if (nec->mix_mode == NEC_MIX_AXIS_ANGLE) {
+ zero_v4(r_values);
+ return;
+ }
+
+ /* NOTE: while this doesn't work for all RNA properties as default values aren't in fact
+ * set properly for most of them, at least the common ones (which also happen to get used
+ * in NLA strips a lot, e.g. scale) are set correctly.
+ */
+ if (RNA_property_array_check(prop)) {
+ BLI_assert(length == RNA_property_array_length(ptr, prop));
+ bool *tmp_bool;
+ int *tmp_int;
+
+ switch (RNA_property_type(prop)) {
+ case PROP_BOOLEAN:
+ tmp_bool = MEM_malloc_arrayN(sizeof(*tmp_bool), length, __func__);
+ RNA_property_boolean_get_default_array(ptr, prop, tmp_bool);
+ for (int i = 0; i < length; i++) {
+ r_values[i] = (float)tmp_bool[i];
+ }
+ MEM_freeN(tmp_bool);
+ break;
+ case PROP_INT:
+ tmp_int = MEM_malloc_arrayN(sizeof(*tmp_int), length, __func__);
+ RNA_property_int_get_default_array(ptr, prop, tmp_int);
+ for (int i = 0; i < length; i++) {
+ r_values[i] = (float)tmp_int[i];
+ }
+ MEM_freeN(tmp_int);
+ break;
+ case PROP_FLOAT:
+ RNA_property_float_get_default_array(ptr, prop, r_values);
+ break;
+ default:
+ memset(r_values, 0, sizeof(float) * length);
+ }
+ }
+ else {
+ BLI_assert(length == 1);
+
+ switch (RNA_property_type(prop)) {
+ case PROP_BOOLEAN:
+ *r_values = (float)RNA_property_boolean_get_default(ptr, prop);
+ break;
+ case PROP_INT:
+ *r_values = (float)RNA_property_int_get_default(ptr, prop);
+ break;
+ case PROP_FLOAT:
+ *r_values = RNA_property_float_get_default(ptr, prop);
+ break;
+ case PROP_ENUM:
+ *r_values = (float)RNA_property_enum_get_default(ptr, prop);
+ break;
+ default:
+ *r_values = 0.0f;
+ }
+ }
+
+ /* Ensure multiplicative properties aren't reset to 0. */
+ if (nec->mix_mode == NEC_MIX_MULTIPLY) {
+ for (int i = 0; i < length; i++) {
+ if (r_values[i] == 0.0f) {
+ r_values[i] = 1.0f;
+ }
+ }
+ }
}
static char nlaevalchan_detect_mix_mode(NlaEvalChannelKey *key, int length)
{
- PropertySubType subtype = RNA_property_subtype(key->prop);
+ PropertySubType subtype = RNA_property_subtype(key->prop);
- if (subtype == PROP_QUATERNION && length == 4) {
- return NEC_MIX_QUATERNION;
- }
- else if (subtype == PROP_AXISANGLE && length == 4) {
- return NEC_MIX_AXIS_ANGLE;
- }
- else if (RNA_property_flag(key->prop) & PROP_PROPORTIONAL) {
- return NEC_MIX_MULTIPLY;
- }
- else {
- return NEC_MIX_ADD;
- }
+ if (subtype == PROP_QUATERNION && length == 4) {
+ return NEC_MIX_QUATERNION;
+ }
+ else if (subtype == PROP_AXISANGLE && length == 4) {
+ return NEC_MIX_AXIS_ANGLE;
+ }
+ else if (RNA_property_flag(key->prop) & PROP_PROPORTIONAL) {
+ return NEC_MIX_MULTIPLY;
+ }
+ else {
+ return NEC_MIX_ADD;
+ }
}
/* Verify that an appropriate NlaEvalChannel for this property exists. */
-static NlaEvalChannel *nlaevalchan_verify_key(NlaEvalData *nlaeval, const char *path, NlaEvalChannelKey *key)
+static NlaEvalChannel *nlaevalchan_verify_key(NlaEvalData *nlaeval,
+ const char *path,
+ NlaEvalChannelKey *key)
{
- /* Look it up in the key hash. */
- NlaEvalChannel **p_key_nec;
- NlaEvalChannelKey **p_key;
- bool found_key = BLI_ghash_ensure_p_ex(nlaeval->key_hash, key, (void ***)&p_key, (void ***)&p_key_nec);
+ /* Look it up in the key hash. */
+ NlaEvalChannel **p_key_nec;
+ NlaEvalChannelKey **p_key;
+ bool found_key = BLI_ghash_ensure_p_ex(
+ nlaeval->key_hash, key, (void ***)&p_key, (void ***)&p_key_nec);
- if (found_key) {
- return *p_key_nec;
- }
+ if (found_key) {
+ return *p_key_nec;
+ }
- /* Create the channel. */
- bool is_array = RNA_property_array_check(key->prop);
- int length = is_array ? RNA_property_array_length(&key->ptr, key->prop) : 1;
+ /* Create the channel. */
+ bool is_array = RNA_property_array_check(key->prop);
+ int length = is_array ? RNA_property_array_length(&key->ptr, key->prop) : 1;
- NlaEvalChannel *nec = MEM_callocN(sizeof(NlaEvalChannel) + sizeof(float) * length, "NlaEvalChannel");
+ NlaEvalChannel *nec = MEM_callocN(sizeof(NlaEvalChannel) + sizeof(float) * length,
+ "NlaEvalChannel");
- /* Initialize the channel. */
- nec->rna_path = path;
- nec->key = *key;
+ /* Initialize the channel. */
+ nec->rna_path = path;
+ nec->key = *key;
- nec->owner = nlaeval;
- nec->index = nlaeval->num_channels++;
- nec->is_array = is_array;
+ nec->owner = nlaeval;
+ nec->index = nlaeval->num_channels++;
+ nec->is_array = is_array;
- nec->mix_mode = nlaevalchan_detect_mix_mode(key, length);
+ nec->mix_mode = nlaevalchan_detect_mix_mode(key, length);
- nlavalidmask_init(&nec->valid, length);
+ nlavalidmask_init(&nec->valid, length);
- nec->base_snapshot.channel = nec;
- nec->base_snapshot.length = length;
- nec->base_snapshot.is_base = true;
+ nec->base_snapshot.channel = nec;
+ nec->base_snapshot.length = length;
+ nec->base_snapshot.is_base = true;
- nlaevalchan_get_default_values(nec, nec->base_snapshot.values);
+ nlaevalchan_get_default_values(nec, nec->base_snapshot.values);
- /* Store channel in data structures. */
- BLI_addtail(&nlaeval->channels, nec);
+ /* Store channel in data structures. */
+ BLI_addtail(&nlaeval->channels, nec);
- *nlaeval_snapshot_ensure_slot(&nlaeval->base_snapshot, nec) = &nec->base_snapshot;
+ *nlaeval_snapshot_ensure_slot(&nlaeval->base_snapshot, nec) = &nec->base_snapshot;
- *p_key_nec = nec;
- *p_key = &nec->key;
+ *p_key_nec = nec;
+ *p_key = &nec->key;
- return nec;
+ return nec;
}
/* Verify that an appropriate NlaEvalChannel for this path exists. */
static NlaEvalChannel *nlaevalchan_verify(PointerRNA *ptr, NlaEvalData *nlaeval, const char *path)
{
- if (path == NULL) {
- return NULL;
- }
+ if (path == NULL) {
+ return NULL;
+ }
- /* Lookup the path in the path based hash. */
- NlaEvalChannel **p_path_nec;
- bool found_path = BLI_ghash_ensure_p(nlaeval->path_hash, (void *)path, (void ***)&p_path_nec);
+ /* Lookup the path in the path based hash. */
+ NlaEvalChannel **p_path_nec;
+ bool found_path = BLI_ghash_ensure_p(nlaeval->path_hash, (void *)path, (void ***)&p_path_nec);
- if (found_path) {
- return *p_path_nec;
- }
+ if (found_path) {
+ return *p_path_nec;
+ }
- /* Resolve the property and look it up in the key hash. */
- NlaEvalChannelKey key;
+ /* Resolve the property and look it up in the key hash. */
+ NlaEvalChannelKey key;
- if (!RNA_path_resolve_property(ptr, path, &key.ptr, &key.prop)) {
- /* Report failure to resolve the path. */
- if (G.debug & G_DEBUG) {
- CLOG_WARN(&LOG, "Animato: Invalid path. ID = '%s', '%s'",
- (ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "<No ID>", path);
- }
+ if (!RNA_path_resolve_property(ptr, path, &key.ptr, &key.prop)) {
+ /* Report failure to resolve the path. */
+ if (G.debug & G_DEBUG) {
+ CLOG_WARN(&LOG,
+ "Animato: Invalid path. ID = '%s', '%s'",
+ (ptr->id.data) ? (((ID *)ptr->id.data)->name + 2) : "<No ID>",
+ path);
+ }
- /* Cache NULL result. */
- *p_path_nec = NULL;
- return NULL;
- }
+ /* Cache NULL result. */
+ *p_path_nec = NULL;
+ return NULL;
+ }
- NlaEvalChannel *nec = nlaevalchan_verify_key(nlaeval, path, &key);
+ NlaEvalChannel *nec = nlaevalchan_verify_key(nlaeval, path, &key);
- if (nec->rna_path == NULL) {
- nec->rna_path = path;
- }
+ if (nec->rna_path == NULL) {
+ nec->rna_path = path;
+ }
- return *p_path_nec = nec;
+ return *p_path_nec = nec;
}
/* ---------------------- */
@@ -2456,307 +2572,333 @@ static NlaEvalChannel *nlaevalchan_verify(PointerRNA *ptr, NlaEvalData *nlaeval,
/* accumulate the old and new values of a channel according to mode and influence */
static float nla_blend_value(int blendmode, float old_value, float value, float inf)
{
- /* optimisation: no need to try applying if there is no influence */
- if (IS_EQF(inf, 0.0f)) {
- return old_value;
- }
-
- /* perform blending */
- switch (blendmode) {
- case NLASTRIP_MODE_ADD:
- /* simply add the scaled value on to the stack */
- return old_value + (value * inf);
-
- case NLASTRIP_MODE_SUBTRACT:
- /* simply subtract the scaled value from the stack */
- return old_value - (value * inf);
-
- case NLASTRIP_MODE_MULTIPLY:
- /* multiply the scaled value with the stack */
- /* Formula Used:
- * result = fac * (a * b) + (1 - fac) * a
- */
- return inf * (old_value * value) + (1 - inf) * old_value;
-
- case NLASTRIP_MODE_COMBINE:
- BLI_assert(!"combine mode");
- ATTR_FALLTHROUGH;
-
- case NLASTRIP_MODE_REPLACE:
- default: /* TODO: do we really want to blend by default? it seems more uses might prefer add... */
- /* do linear interpolation
- * - the influence of the accumulated data (elsewhere, that is called dstweight)
- * is 1 - influence, since the strip's influence is srcweight
- */
- return old_value * (1.0f - inf) + (value * inf);
- }
+ /* optimisation: no need to try applying if there is no influence */
+ if (IS_EQF(inf, 0.0f)) {
+ return old_value;
+ }
+
+ /* perform blending */
+ switch (blendmode) {
+ case NLASTRIP_MODE_ADD:
+ /* simply add the scaled value on to the stack */
+ return old_value + (value * inf);
+
+ case NLASTRIP_MODE_SUBTRACT:
+ /* simply subtract the scaled value from the stack */
+ return old_value - (value * inf);
+
+ case NLASTRIP_MODE_MULTIPLY:
+ /* multiply the scaled value with the stack */
+ /* Formula Used:
+ * result = fac * (a * b) + (1 - fac) * a
+ */
+ return inf * (old_value * value) + (1 - inf) * old_value;
+
+ case NLASTRIP_MODE_COMBINE:
+ BLI_assert(!"combine mode");
+ ATTR_FALLTHROUGH;
+
+ case NLASTRIP_MODE_REPLACE:
+ default
+ : /* TODO: do we really want to blend by default? it seems more uses might prefer add... */
+ /* do linear interpolation
+ * - the influence of the accumulated data (elsewhere, that is called dstweight)
+ * is 1 - influence, since the strip's influence is srcweight
+ */
+ return old_value * (1.0f - inf) + (value * inf);
+ }
}
/* accumulate the old and new values of a channel according to mode and influence */
-static float nla_combine_value(int mix_mode, float base_value, float old_value, float value, float inf)
+static float nla_combine_value(
+ int mix_mode, float base_value, float old_value, float value, float inf)
{
- /* optimisation: no need to try applying if there is no influence */
- if (IS_EQF(inf, 0.0f)) {
- return old_value;
- }
+ /* optimisation: no need to try applying if there is no influence */
+ if (IS_EQF(inf, 0.0f)) {
+ return old_value;
+ }
- /* perform blending */
- switch (mix_mode) {
- case NEC_MIX_ADD:
- case NEC_MIX_AXIS_ANGLE:
- return old_value + (value - base_value) * inf;
+ /* perform blending */
+ switch (mix_mode) {
+ case NEC_MIX_ADD:
+ case NEC_MIX_AXIS_ANGLE:
+ return old_value + (value - base_value) * inf;
- case NEC_MIX_MULTIPLY:
- if (base_value == 0.0f) {
- base_value = 1.0f;
- }
- return old_value * powf(value / base_value, inf);
+ case NEC_MIX_MULTIPLY:
+ if (base_value == 0.0f) {
+ base_value = 1.0f;
+ }
+ return old_value * powf(value / base_value, inf);
- case NEC_MIX_QUATERNION:
- default:
- BLI_assert(!"invalid mix mode");
- return old_value;
- }
+ case NEC_MIX_QUATERNION:
+ default:
+ BLI_assert(!"invalid mix mode");
+ return old_value;
+ }
}
/* compute the value that would blend to the desired target value using nla_blend_value */
-static bool nla_invert_blend_value(int blend_mode, float old_value, float target_value, float influence, float *r_value)
-{
- switch (blend_mode) {
- case NLASTRIP_MODE_ADD:
- *r_value = (target_value - old_value) / influence;
- return true;
-
- case NLASTRIP_MODE_SUBTRACT:
- *r_value = (old_value - target_value) / influence;
- return true;
-
- case NLASTRIP_MODE_MULTIPLY:
- if (old_value == 0.0f) {
- /* Resolve 0/0 to 1. */
- if (target_value == 0.0f) {
- *r_value = 1.0f;
- return true;
- }
- /* Division by zero. */
- return false;
- }
- else {
- *r_value = (target_value - old_value) / influence / old_value + 1.0f;
- return true;
- }
-
- case NLASTRIP_MODE_COMBINE:
- BLI_assert(!"combine mode");
- ATTR_FALLTHROUGH;
-
- case NLASTRIP_MODE_REPLACE:
- default:
- *r_value = (target_value - old_value) / influence + old_value;
- return true;
- }
+static bool nla_invert_blend_value(
+ int blend_mode, float old_value, float target_value, float influence, float *r_value)
+{
+ switch (blend_mode) {
+ case NLASTRIP_MODE_ADD:
+ *r_value = (target_value - old_value) / influence;
+ return true;
+
+ case NLASTRIP_MODE_SUBTRACT:
+ *r_value = (old_value - target_value) / influence;
+ return true;
+
+ case NLASTRIP_MODE_MULTIPLY:
+ if (old_value == 0.0f) {
+ /* Resolve 0/0 to 1. */
+ if (target_value == 0.0f) {
+ *r_value = 1.0f;
+ return true;
+ }
+ /* Division by zero. */
+ return false;
+ }
+ else {
+ *r_value = (target_value - old_value) / influence / old_value + 1.0f;
+ return true;
+ }
+
+ case NLASTRIP_MODE_COMBINE:
+ BLI_assert(!"combine mode");
+ ATTR_FALLTHROUGH;
+
+ case NLASTRIP_MODE_REPLACE:
+ default:
+ *r_value = (target_value - old_value) / influence + old_value;
+ return true;
+ }
}
/* compute the value that would blend to the desired target value using nla_combine_value */
-static bool nla_invert_combine_value(int mix_mode, float base_value, float old_value, float target_value, float influence, float *r_value)
-{
- switch (mix_mode) {
- case NEC_MIX_ADD:
- case NEC_MIX_AXIS_ANGLE:
- *r_value = base_value + (target_value - old_value) / influence;
- return true;
-
- case NEC_MIX_MULTIPLY:
- if (base_value == 0.0f) {
- base_value = 1.0f;
- }
- if (old_value == 0.0f) {
- /* Resolve 0/0 to 1. */
- if (target_value == 0.0f) {
- *r_value = base_value;
- return true;
- }
- /* Division by zero. */
- return false;
- }
- else {
- *r_value = base_value * powf(target_value / old_value, 1.0f / influence);
- return true;
- }
-
- case NEC_MIX_QUATERNION:
- default:
- BLI_assert(!"invalid mix mode");
- return false;
- }
+static bool nla_invert_combine_value(int mix_mode,
+ float base_value,
+ float old_value,
+ float target_value,
+ float influence,
+ float *r_value)
+{
+ switch (mix_mode) {
+ case NEC_MIX_ADD:
+ case NEC_MIX_AXIS_ANGLE:
+ *r_value = base_value + (target_value - old_value) / influence;
+ return true;
+
+ case NEC_MIX_MULTIPLY:
+ if (base_value == 0.0f) {
+ base_value = 1.0f;
+ }
+ if (old_value == 0.0f) {
+ /* Resolve 0/0 to 1. */
+ if (target_value == 0.0f) {
+ *r_value = base_value;
+ return true;
+ }
+ /* Division by zero. */
+ return false;
+ }
+ else {
+ *r_value = base_value * powf(target_value / old_value, 1.0f / influence);
+ return true;
+ }
+
+ case NEC_MIX_QUATERNION:
+ default:
+ BLI_assert(!"invalid mix mode");
+ return false;
+ }
}
/* accumulate quaternion channels for Combine mode according to influence */
-static void nla_combine_quaternion(const float old_values[4], const float values[4], float influence, float result[4])
+static void nla_combine_quaternion(const float old_values[4],
+ const float values[4],
+ float influence,
+ float result[4])
{
- float tmp_old[4], tmp_new[4];
+ float tmp_old[4], tmp_new[4];
- normalize_qt_qt(tmp_old, old_values);
- normalize_qt_qt(tmp_new, values);
+ normalize_qt_qt(tmp_old, old_values);
+ normalize_qt_qt(tmp_new, values);
- pow_qt_fl_normalized(tmp_new, influence);
- mul_qt_qtqt(result, tmp_old, tmp_new);
+ pow_qt_fl_normalized(tmp_new, influence);
+ mul_qt_qtqt(result, tmp_old, tmp_new);
}
/* invert accumulation of quaternion channels for Combine mode according to influence */
-static void nla_invert_combine_quaternion(const float old_values[4], const float values[4], float influence, float result[4])
+static void nla_invert_combine_quaternion(const float old_values[4],
+ const float values[4],
+ float influence,
+ float result[4])
{
- float tmp_old[4], tmp_new[4];
+ float tmp_old[4], tmp_new[4];
- normalize_qt_qt(tmp_old, old_values);
- normalize_qt_qt(tmp_new, values);
- invert_qt_normalized(tmp_old);
+ normalize_qt_qt(tmp_old, old_values);
+ normalize_qt_qt(tmp_new, values);
+ invert_qt_normalized(tmp_old);
- mul_qt_qtqt(result, tmp_old, tmp_new);
- pow_qt_fl_normalized(result, 1.0f / influence);
+ mul_qt_qtqt(result, tmp_old, tmp_new);
+ pow_qt_fl_normalized(result, 1.0f / influence);
}
/* Data about the current blend mode. */
typedef struct NlaBlendData {
- NlaEvalSnapshot *snapshot;
- int mode;
- float influence;
+ NlaEvalSnapshot *snapshot;
+ int mode;
+ float influence;
- NlaEvalChannel *blend_queue;
+ NlaEvalChannel *blend_queue;
} NlaBlendData;
/* Queue the channel for deferred blending. */
static NlaEvalChannelSnapshot *nlaevalchan_queue_blend(NlaBlendData *blend, NlaEvalChannel *nec)
{
- if (!nec->in_blend) {
- if (nec->blend_snapshot == NULL) {
- nec->blend_snapshot = nlaevalchan_snapshot_new(nec);
- }
+ if (!nec->in_blend) {
+ if (nec->blend_snapshot == NULL) {
+ nec->blend_snapshot = nlaevalchan_snapshot_new(nec);
+ }
- nec->in_blend = true;
- nlaevalchan_snapshot_copy(nec->blend_snapshot, &nec->base_snapshot);
+ nec->in_blend = true;
+ nlaevalchan_snapshot_copy(nec->blend_snapshot, &nec->base_snapshot);
- nec->next_blend = blend->blend_queue;
- blend->blend_queue = nec;
- }
+ nec->next_blend = blend->blend_queue;
+ blend->blend_queue = nec;
+ }
- return nec->blend_snapshot;
+ return nec->blend_snapshot;
}
/* Accumulate (i.e. blend) the given value on to the channel it affects. */
-static bool nlaeval_blend_value(NlaBlendData *blend, NlaEvalChannel *nec, int array_index, float value)
-{
- if (nec == NULL) {
- return false;
- }
-
- int index = nlaevalchan_validate_index(nec, array_index);
-
- if (index < 0) {
- if (G.debug & G_DEBUG) {
- ID *id = nec->key.ptr.id.data;
- CLOG_WARN(&LOG, "Animato: Invalid array index. ID = '%s', '%s[%d]', array length is %d",
- id ? (id->name + 2) : "<No ID>", nec->rna_path, array_index, nec->base_snapshot.length);
- }
-
- return false;
- }
-
- if (nec->mix_mode == NEC_MIX_QUATERNION) {
- /* For quaternion properties, always output all sub-channels. */
- BLI_bitmap_set_all(nec->valid.ptr, true, 4);
- }
- else {
- BLI_BITMAP_ENABLE(nec->valid.ptr, index);
- }
-
- NlaEvalChannelSnapshot *nec_snapshot = nlaeval_snapshot_ensure_channel(blend->snapshot, nec);
- float *p_value = &nec_snapshot->values[index];
-
- if (blend->mode == NLASTRIP_MODE_COMBINE) {
- /* Quaternion blending is deferred until all sub-channel values are known. */
- if (nec->mix_mode == NEC_MIX_QUATERNION) {
- NlaEvalChannelSnapshot *blend_snapshot = nlaevalchan_queue_blend(blend, nec);
-
- blend_snapshot->values[index] = value;
- }
- else {
- float base_value = nec->base_snapshot.values[index];
-
- *p_value = nla_combine_value(nec->mix_mode, base_value, *p_value, value, blend->influence);
- }
- }
- else {
- *p_value = nla_blend_value(blend->mode, *p_value, value, blend->influence);
- }
-
- return true;
+static bool nlaeval_blend_value(NlaBlendData *blend,
+ NlaEvalChannel *nec,
+ int array_index,
+ float value)
+{
+ if (nec == NULL) {
+ return false;
+ }
+
+ int index = nlaevalchan_validate_index(nec, array_index);
+
+ if (index < 0) {
+ if (G.debug & G_DEBUG) {
+ ID *id = nec->key.ptr.id.data;
+ CLOG_WARN(&LOG,
+ "Animato: Invalid array index. ID = '%s', '%s[%d]', array length is %d",
+ id ? (id->name + 2) : "<No ID>",
+ nec->rna_path,
+ array_index,
+ nec->base_snapshot.length);
+ }
+
+ return false;
+ }
+
+ if (nec->mix_mode == NEC_MIX_QUATERNION) {
+ /* For quaternion properties, always output all sub-channels. */
+ BLI_bitmap_set_all(nec->valid.ptr, true, 4);
+ }
+ else {
+ BLI_BITMAP_ENABLE(nec->valid.ptr, index);
+ }
+
+ NlaEvalChannelSnapshot *nec_snapshot = nlaeval_snapshot_ensure_channel(blend->snapshot, nec);
+ float *p_value = &nec_snapshot->values[index];
+
+ if (blend->mode == NLASTRIP_MODE_COMBINE) {
+ /* Quaternion blending is deferred until all sub-channel values are known. */
+ if (nec->mix_mode == NEC_MIX_QUATERNION) {
+ NlaEvalChannelSnapshot *blend_snapshot = nlaevalchan_queue_blend(blend, nec);
+
+ blend_snapshot->values[index] = value;
+ }
+ else {
+ float base_value = nec->base_snapshot.values[index];
+
+ *p_value = nla_combine_value(nec->mix_mode, base_value, *p_value, value, blend->influence);
+ }
+ }
+ else {
+ *p_value = nla_blend_value(blend->mode, *p_value, value, blend->influence);
+ }
+
+ return true;
}
/* Finish deferred quaternion blending. */
static void nlaeval_blend_flush(NlaBlendData *blend)
{
- NlaEvalChannel *nec;
+ NlaEvalChannel *nec;
- while ((nec = blend->blend_queue)) {
- blend->blend_queue = nec->next_blend;
- nec->in_blend = false;
+ while ((nec = blend->blend_queue)) {
+ blend->blend_queue = nec->next_blend;
+ nec->in_blend = false;
- NlaEvalChannelSnapshot *nec_snapshot = nlaeval_snapshot_ensure_channel(blend->snapshot, nec);
- NlaEvalChannelSnapshot *blend_snapshot = nec->blend_snapshot;
+ NlaEvalChannelSnapshot *nec_snapshot = nlaeval_snapshot_ensure_channel(blend->snapshot, nec);
+ NlaEvalChannelSnapshot *blend_snapshot = nec->blend_snapshot;
- if (nec->mix_mode == NEC_MIX_QUATERNION) {
- nla_combine_quaternion(nec_snapshot->values, blend_snapshot->values, blend->influence, nec_snapshot->values);
- }
- else {
- BLI_assert(!"mix quaternion");
- }
- }
+ if (nec->mix_mode == NEC_MIX_QUATERNION) {
+ nla_combine_quaternion(
+ nec_snapshot->values, blend_snapshot->values, blend->influence, nec_snapshot->values);
+ }
+ else {
+ BLI_assert(!"mix quaternion");
+ }
+ }
}
/* Blend the specified snapshots into the target, and free the input snapshots. */
-static void nlaeval_snapshot_mix_and_free(NlaEvalData *nlaeval, NlaEvalSnapshot *out, NlaEvalSnapshot *in1, NlaEvalSnapshot *in2, float alpha)
-{
- BLI_assert(in1->base == out && in2->base == out);
-
- nlaeval_snapshot_ensure_size(out, nlaeval->num_channels);
-
- for (int i = 0; i < nlaeval->num_channels; i++) {
- NlaEvalChannelSnapshot *c_in1 = nlaeval_snapshot_get(in1, i);
- NlaEvalChannelSnapshot *c_in2 = nlaeval_snapshot_get(in2, i);
-
- if (c_in1 || c_in2) {
- NlaEvalChannelSnapshot *c_out = out->channels[i];
-
- /* Steal the entry from one of the input snapshots. */
- if (c_out == NULL) {
- if (c_in1 != NULL) {
- c_out = c_in1;
- in1->channels[i] = NULL;
- }
- else {
- c_out = c_in2;
- in2->channels[i] = NULL;
- }
- }
-
- if (c_in1 == NULL) {
- c_in1 = nlaeval_snapshot_find_channel(in1->base, c_out->channel);
- }
- if (c_in2 == NULL) {
- c_in2 = nlaeval_snapshot_find_channel(in2->base, c_out->channel);
- }
-
- out->channels[i] = c_out;
-
- for (int j = 0; j < c_out->length; j++) {
- c_out->values[j] = c_in1->values[j] * (1.0f - alpha) + c_in2->values[j] * alpha;
- }
- }
- }
-
- nlaeval_snapshot_free_data(in1);
- nlaeval_snapshot_free_data(in2);
+static void nlaeval_snapshot_mix_and_free(NlaEvalData *nlaeval,
+ NlaEvalSnapshot *out,
+ NlaEvalSnapshot *in1,
+ NlaEvalSnapshot *in2,
+ float alpha)
+{
+ BLI_assert(in1->base == out && in2->base == out);
+
+ nlaeval_snapshot_ensure_size(out, nlaeval->num_channels);
+
+ for (int i = 0; i < nlaeval->num_channels; i++) {
+ NlaEvalChannelSnapshot *c_in1 = nlaeval_snapshot_get(in1, i);
+ NlaEvalChannelSnapshot *c_in2 = nlaeval_snapshot_get(in2, i);
+
+ if (c_in1 || c_in2) {
+ NlaEvalChannelSnapshot *c_out = out->channels[i];
+
+ /* Steal the entry from one of the input snapshots. */
+ if (c_out == NULL) {
+ if (c_in1 != NULL) {
+ c_out = c_in1;
+ in1->channels[i] = NULL;
+ }
+ else {
+ c_out = c_in2;
+ in2->channels[i] = NULL;
+ }
+ }
+
+ if (c_in1 == NULL) {
+ c_in1 = nlaeval_snapshot_find_channel(in1->base, c_out->channel);
+ }
+ if (c_in2 == NULL) {
+ c_in2 = nlaeval_snapshot_find_channel(in2->base, c_out->channel);
+ }
+
+ out->channels[i] = c_out;
+
+ for (int j = 0; j < c_out->length; j++) {
+ c_out->values[j] = c_in1->values[j] * (1.0f - alpha) + c_in2->values[j] * alpha;
+ }
+ }
+ }
+
+ nlaeval_snapshot_free_data(in1);
+ nlaeval_snapshot_free_data(in2);
}
/* ---------------------- */
@@ -2765,330 +2907,356 @@ static void nlaeval_snapshot_mix_and_free(NlaEvalData *nlaeval, NlaEvalSnapshot
/* Temporarily join two lists of modifiers together, storing the result in a third list */
static void nlaeval_fmodifiers_join_stacks(ListBase *result, ListBase *list1, ListBase *list2)
{
- FModifier *fcm1, *fcm2;
-
- /* if list1 is invalid... */
- if (ELEM(NULL, list1, list1->first)) {
- if (list2 && list2->first) {
- result->first = list2->first;
- result->last = list2->last;
- }
- }
- /* if list 2 is invalid... */
- else if (ELEM(NULL, list2, list2->first)) {
- result->first = list1->first;
- result->last = list1->last;
- }
- else {
- /* list1 should be added first, and list2 second, with the endpoints of these being the endpoints for result
- * - the original lists must be left unchanged though, as we need that fact for restoring
- */
- result->first = list1->first;
- result->last = list2->last;
-
- fcm1 = list1->last;
- fcm2 = list2->first;
-
- fcm1->next = fcm2;
- fcm2->prev = fcm1;
- }
+ FModifier *fcm1, *fcm2;
+
+ /* if list1 is invalid... */
+ if (ELEM(NULL, list1, list1->first)) {
+ if (list2 && list2->first) {
+ result->first = list2->first;
+ result->last = list2->last;
+ }
+ }
+ /* if list 2 is invalid... */
+ else if (ELEM(NULL, list2, list2->first)) {
+ result->first = list1->first;
+ result->last = list1->last;
+ }
+ else {
+ /* list1 should be added first, and list2 second, with the endpoints of these being the endpoints for result
+ * - the original lists must be left unchanged though, as we need that fact for restoring
+ */
+ result->first = list1->first;
+ result->last = list2->last;
+
+ fcm1 = list1->last;
+ fcm2 = list2->first;
+
+ fcm1->next = fcm2;
+ fcm2->prev = fcm1;
+ }
}
/* Split two temporary lists of modifiers */
static void nlaeval_fmodifiers_split_stacks(ListBase *list1, ListBase *list2)
{
- FModifier *fcm1, *fcm2;
+ FModifier *fcm1, *fcm2;
- /* if list1/2 is invalid... just skip */
- if (ELEM(NULL, list1, list2))
- return;
- if (ELEM(NULL, list1->first, list2->first))
- return;
+ /* if list1/2 is invalid... just skip */
+ if (ELEM(NULL, list1, list2))
+ return;
+ if (ELEM(NULL, list1->first, list2->first))
+ return;
- /* get endpoints */
- fcm1 = list1->last;
- fcm2 = list2->first;
+ /* get endpoints */
+ fcm1 = list1->last;
+ fcm2 = list2->first;
- /* clear their links */
- fcm1->next = NULL;
- fcm2->prev = NULL;
+ /* clear their links */
+ fcm1->next = NULL;
+ fcm2->prev = NULL;
}
/* ---------------------- */
/* evaluate action-clip strip */
-static void nlastrip_evaluate_actionclip(PointerRNA *ptr, NlaEvalData *channels, ListBase *modifiers, NlaEvalStrip *nes, NlaEvalSnapshot *snapshot)
+static void nlastrip_evaluate_actionclip(PointerRNA *ptr,
+ NlaEvalData *channels,
+ ListBase *modifiers,
+ NlaEvalStrip *nes,
+ NlaEvalSnapshot *snapshot)
{
- FModifierStackStorage *storage;
- ListBase tmp_modifiers = {NULL, NULL};
- NlaStrip *strip = nes->strip;
- FCurve *fcu;
- float evaltime;
+ FModifierStackStorage *storage;
+ ListBase tmp_modifiers = {NULL, NULL};
+ NlaStrip *strip = nes->strip;
+ FCurve *fcu;
+ float evaltime;
- /* sanity checks for action */
- if (strip == NULL)
- return;
+ /* sanity checks for action */
+ if (strip == NULL)
+ return;
- if (strip->act == NULL) {
- CLOG_ERROR(&LOG, "NLA-Strip Eval Error: Strip '%s' has no Action", strip->name);
- return;
- }
+ if (strip->act == NULL) {
+ CLOG_ERROR(&LOG, "NLA-Strip Eval Error: Strip '%s' has no Action", strip->name);
+ return;
+ }
- action_idcode_patch_check(ptr->id.data, strip->act);
+ action_idcode_patch_check(ptr->id.data, strip->act);
- /* join this strip's modifiers to the parent's modifiers (own modifiers first) */
- nlaeval_fmodifiers_join_stacks(&tmp_modifiers, &strip->modifiers, modifiers);
+ /* join this strip's modifiers to the parent's modifiers (own modifiers first) */
+ nlaeval_fmodifiers_join_stacks(&tmp_modifiers, &strip->modifiers, modifiers);
- /* evaluate strip's modifiers which modify time to evaluate the base curves at */
- storage = evaluate_fmodifiers_storage_new(&tmp_modifiers);
- evaltime = evaluate_time_fmodifiers(storage, &tmp_modifiers, NULL, 0.0f, strip->strip_time);
+ /* evaluate strip's modifiers which modify time to evaluate the base curves at */
+ storage = evaluate_fmodifiers_storage_new(&tmp_modifiers);
+ evaltime = evaluate_time_fmodifiers(storage, &tmp_modifiers, NULL, 0.0f, strip->strip_time);
- NlaBlendData blend = {
- .snapshot = snapshot,
- .mode = strip->blendmode,
- .influence = strip->influence,
- };
+ NlaBlendData blend = {
+ .snapshot = snapshot,
+ .mode = strip->blendmode,
+ .influence = strip->influence,
+ };
- /* evaluate all the F-Curves in the action, saving the relevant pointers to data that will need to be used */
- for (fcu = strip->act->curves.first; fcu; fcu = fcu->next) {
- float value = 0.0f;
+ /* evaluate all the F-Curves in the action, saving the relevant pointers to data that will need to be used */
+ for (fcu = strip->act->curves.first; fcu; fcu = fcu->next) {
+ float value = 0.0f;
- /* check if this curve should be skipped */
- if (fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED))
- continue;
- if ((fcu->grp) && (fcu->grp->flag & AGRP_MUTED))
- continue;
+ /* check if this curve should be skipped */
+ if (fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED))
+ continue;
+ if ((fcu->grp) && (fcu->grp->flag & AGRP_MUTED))
+ continue;
- /* evaluate the F-Curve's value for the time given in the strip
- * NOTE: we use the modified time here, since strip's F-Curve Modifiers are applied on top of this
- */
- value = evaluate_fcurve(fcu, evaltime);
+ /* evaluate the F-Curve's value for the time given in the strip
+ * NOTE: we use the modified time here, since strip's F-Curve Modifiers are applied on top of this
+ */
+ value = evaluate_fcurve(fcu, evaltime);
- /* apply strip's F-Curve Modifiers on this value
- * NOTE: we apply the strip's original evaluation time not the modified one (as per standard F-Curve eval)
- */
- evaluate_value_fmodifiers(storage, &tmp_modifiers, fcu, &value, strip->strip_time);
+ /* apply strip's F-Curve Modifiers on this value
+ * NOTE: we apply the strip's original evaluation time not the modified one (as per standard F-Curve eval)
+ */
+ evaluate_value_fmodifiers(storage, &tmp_modifiers, fcu, &value, strip->strip_time);
- /* get an NLA evaluation channel to work with, and accumulate the evaluated value with the value(s)
- * stored in this channel if it has been used already
- */
- NlaEvalChannel *nec = nlaevalchan_verify(ptr, channels, fcu->rna_path);
+ /* get an NLA evaluation channel to work with, and accumulate the evaluated value with the value(s)
+ * stored in this channel if it has been used already
+ */
+ NlaEvalChannel *nec = nlaevalchan_verify(ptr, channels, fcu->rna_path);
- nlaeval_blend_value(&blend, nec, fcu->array_index, value);
- }
+ nlaeval_blend_value(&blend, nec, fcu->array_index, value);
+ }
- nlaeval_blend_flush(&blend);
+ nlaeval_blend_flush(&blend);
- /* free temporary storage */
- evaluate_fmodifiers_storage_free(storage);
+ /* free temporary storage */
+ evaluate_fmodifiers_storage_free(storage);
- /* unlink this strip's modifiers from the parent's modifiers again */
- nlaeval_fmodifiers_split_stacks(&strip->modifiers, modifiers);
+ /* unlink this strip's modifiers from the parent's modifiers again */
+ nlaeval_fmodifiers_split_stacks(&strip->modifiers, modifiers);
}
/* evaluate transition strip */
-static void nlastrip_evaluate_transition(
- Depsgraph *depsgraph, PointerRNA *ptr, NlaEvalData *channels, ListBase *modifiers, NlaEvalStrip *nes, NlaEvalSnapshot *snapshot)
-{
- ListBase tmp_modifiers = {NULL, NULL};
- NlaEvalSnapshot snapshot1, snapshot2;
- NlaEvalStrip tmp_nes;
- NlaStrip *s1, *s2;
-
- /* join this strip's modifiers to the parent's modifiers (own modifiers first) */
- nlaeval_fmodifiers_join_stacks(&tmp_modifiers, &nes->strip->modifiers, modifiers);
-
- /* get the two strips to operate on
- * - we use the endpoints of the strips directly flanking our strip
- * using these as the endpoints of the transition (destination and source)
- * - these should have already been determined to be valid...
- * - if this strip is being played in reverse, we need to swap these endpoints
- * otherwise they will be interpolated wrong
- */
- if (nes->strip->flag & NLASTRIP_FLAG_REVERSE) {
- s1 = nes->strip->next;
- s2 = nes->strip->prev;
- }
- else {
- s1 = nes->strip->prev;
- s2 = nes->strip->next;
- }
-
- /* prepare template for 'evaluation strip'
- * - based on the transition strip's evaluation strip data
- * - strip_mode is NES_TIME_TRANSITION_* based on which endpoint
- * - strip_time is the 'normalized' (i.e. in-strip) time for evaluation,
- * which doubles up as an additional weighting factor for the strip influences
- * which allows us to appear to be 'interpolating' between the two extremes
- */
- tmp_nes = *nes;
-
- /* evaluate these strips into a temp-buffer (tmp_channels) */
- /* FIXME: modifier evaluation here needs some work... */
- /* first strip */
- tmp_nes.strip_mode = NES_TIME_TRANSITION_START;
- tmp_nes.strip = s1;
- nlaeval_snapshot_init(&snapshot1, channels, snapshot);
- nlastrip_evaluate(depsgraph, ptr, channels, &tmp_modifiers, &tmp_nes, &snapshot1);
-
- /* second strip */
- tmp_nes.strip_mode = NES_TIME_TRANSITION_END;
- tmp_nes.strip = s2;
- nlaeval_snapshot_init(&snapshot2, channels, snapshot);
- nlastrip_evaluate(depsgraph, ptr, channels, &tmp_modifiers, &tmp_nes, &snapshot2);
-
- /* accumulate temp-buffer and full-buffer, using the 'real' strip */
- nlaeval_snapshot_mix_and_free(channels, snapshot, &snapshot1, &snapshot2, nes->strip_time);
-
- /* unlink this strip's modifiers from the parent's modifiers again */
- nlaeval_fmodifiers_split_stacks(&nes->strip->modifiers, modifiers);
+static void nlastrip_evaluate_transition(Depsgraph *depsgraph,
+ PointerRNA *ptr,
+ NlaEvalData *channels,
+ ListBase *modifiers,
+ NlaEvalStrip *nes,
+ NlaEvalSnapshot *snapshot)
+{
+ ListBase tmp_modifiers = {NULL, NULL};
+ NlaEvalSnapshot snapshot1, snapshot2;
+ NlaEvalStrip tmp_nes;
+ NlaStrip *s1, *s2;
+
+ /* join this strip's modifiers to the parent's modifiers (own modifiers first) */
+ nlaeval_fmodifiers_join_stacks(&tmp_modifiers, &nes->strip->modifiers, modifiers);
+
+ /* get the two strips to operate on
+ * - we use the endpoints of the strips directly flanking our strip
+ * using these as the endpoints of the transition (destination and source)
+ * - these should have already been determined to be valid...
+ * - if this strip is being played in reverse, we need to swap these endpoints
+ * otherwise they will be interpolated wrong
+ */
+ if (nes->strip->flag & NLASTRIP_FLAG_REVERSE) {
+ s1 = nes->strip->next;
+ s2 = nes->strip->prev;
+ }
+ else {
+ s1 = nes->strip->prev;
+ s2 = nes->strip->next;
+ }
+
+ /* prepare template for 'evaluation strip'
+ * - based on the transition strip's evaluation strip data
+ * - strip_mode is NES_TIME_TRANSITION_* based on which endpoint
+ * - strip_time is the 'normalized' (i.e. in-strip) time for evaluation,
+ * which doubles up as an additional weighting factor for the strip influences
+ * which allows us to appear to be 'interpolating' between the two extremes
+ */
+ tmp_nes = *nes;
+
+ /* evaluate these strips into a temp-buffer (tmp_channels) */
+ /* FIXME: modifier evaluation here needs some work... */
+ /* first strip */
+ tmp_nes.strip_mode = NES_TIME_TRANSITION_START;
+ tmp_nes.strip = s1;
+ nlaeval_snapshot_init(&snapshot1, channels, snapshot);
+ nlastrip_evaluate(depsgraph, ptr, channels, &tmp_modifiers, &tmp_nes, &snapshot1);
+
+ /* second strip */
+ tmp_nes.strip_mode = NES_TIME_TRANSITION_END;
+ tmp_nes.strip = s2;
+ nlaeval_snapshot_init(&snapshot2, channels, snapshot);
+ nlastrip_evaluate(depsgraph, ptr, channels, &tmp_modifiers, &tmp_nes, &snapshot2);
+
+ /* accumulate temp-buffer and full-buffer, using the 'real' strip */
+ nlaeval_snapshot_mix_and_free(channels, snapshot, &snapshot1, &snapshot2, nes->strip_time);
+
+ /* unlink this strip's modifiers from the parent's modifiers again */
+ nlaeval_fmodifiers_split_stacks(&nes->strip->modifiers, modifiers);
}
/* evaluate meta-strip */
-static void nlastrip_evaluate_meta(
- Depsgraph *depsgraph, PointerRNA *ptr, NlaEvalData *channels, ListBase *modifiers, NlaEvalStrip *nes, NlaEvalSnapshot *snapshot)
-{
- ListBase tmp_modifiers = {NULL, NULL};
- NlaStrip *strip = nes->strip;
- NlaEvalStrip *tmp_nes;
- float evaltime;
-
- /* meta-strip was calculated normally to have some time to be evaluated at
- * and here we 'look inside' the meta strip, treating it as a decorated window to
- * it's child strips, which get evaluated as if they were some tracks on a strip
- * (but with some extra modifiers to apply).
- *
- * NOTE: keep this in sync with animsys_evaluate_nla()
- */
-
- /* join this strip's modifiers to the parent's modifiers (own modifiers first) */
- nlaeval_fmodifiers_join_stacks(&tmp_modifiers, &strip->modifiers, modifiers);
-
- /* find the child-strip to evaluate */
- evaltime = (nes->strip_time * (strip->end - strip->start)) + strip->start;
- tmp_nes = nlastrips_ctime_get_strip(depsgraph, NULL, &strip->strips, -1, evaltime);
-
- /* directly evaluate child strip into accumulation buffer...
- * - there's no need to use a temporary buffer (as it causes issues [T40082])
- */
- if (tmp_nes) {
- nlastrip_evaluate(depsgraph, ptr, channels, &tmp_modifiers, tmp_nes, snapshot);
-
- /* free temp eval-strip */
- MEM_freeN(tmp_nes);
- }
-
- /* unlink this strip's modifiers from the parent's modifiers again */
- nlaeval_fmodifiers_split_stacks(&strip->modifiers, modifiers);
+static void nlastrip_evaluate_meta(Depsgraph *depsgraph,
+ PointerRNA *ptr,
+ NlaEvalData *channels,
+ ListBase *modifiers,
+ NlaEvalStrip *nes,
+ NlaEvalSnapshot *snapshot)
+{
+ ListBase tmp_modifiers = {NULL, NULL};
+ NlaStrip *strip = nes->strip;
+ NlaEvalStrip *tmp_nes;
+ float evaltime;
+
+ /* meta-strip was calculated normally to have some time to be evaluated at
+ * and here we 'look inside' the meta strip, treating it as a decorated window to
+ * it's child strips, which get evaluated as if they were some tracks on a strip
+ * (but with some extra modifiers to apply).
+ *
+ * NOTE: keep this in sync with animsys_evaluate_nla()
+ */
+
+ /* join this strip's modifiers to the parent's modifiers (own modifiers first) */
+ nlaeval_fmodifiers_join_stacks(&tmp_modifiers, &strip->modifiers, modifiers);
+
+ /* find the child-strip to evaluate */
+ evaltime = (nes->strip_time * (strip->end - strip->start)) + strip->start;
+ tmp_nes = nlastrips_ctime_get_strip(depsgraph, NULL, &strip->strips, -1, evaltime);
+
+ /* directly evaluate child strip into accumulation buffer...
+ * - there's no need to use a temporary buffer (as it causes issues [T40082])
+ */
+ if (tmp_nes) {
+ nlastrip_evaluate(depsgraph, ptr, channels, &tmp_modifiers, tmp_nes, snapshot);
+
+ /* free temp eval-strip */
+ MEM_freeN(tmp_nes);
+ }
+
+ /* unlink this strip's modifiers from the parent's modifiers again */
+ nlaeval_fmodifiers_split_stacks(&strip->modifiers, modifiers);
}
/* evaluates the given evaluation strip */
-void nlastrip_evaluate(Depsgraph *depsgraph, PointerRNA *ptr, NlaEvalData *channels, ListBase *modifiers, NlaEvalStrip *nes, NlaEvalSnapshot *snapshot)
-{
- NlaStrip *strip = nes->strip;
-
- /* to prevent potential infinite recursion problems (i.e. transition strip, beside meta strip containing a transition
- * several levels deep inside it), we tag the current strip as being evaluated, and clear this when we leave
- */
- /* TODO: be careful with this flag, since some edit tools may be running and have set this while animplayback was running */
- if (strip->flag & NLASTRIP_FLAG_EDIT_TOUCHED)
- return;
- strip->flag |= NLASTRIP_FLAG_EDIT_TOUCHED;
-
- /* actions to take depend on the type of strip */
- switch (strip->type) {
- case NLASTRIP_TYPE_CLIP: /* action-clip */
- nlastrip_evaluate_actionclip(ptr, channels, modifiers, nes, snapshot);
- break;
- case NLASTRIP_TYPE_TRANSITION: /* transition */
- nlastrip_evaluate_transition(depsgraph, ptr, channels, modifiers, nes, snapshot);
- break;
- case NLASTRIP_TYPE_META: /* meta */
- nlastrip_evaluate_meta(depsgraph, ptr, channels, modifiers, nes, snapshot);
- break;
-
- default: /* do nothing */
- break;
- }
-
- /* clear temp recursion safe-check */
- strip->flag &= ~NLASTRIP_FLAG_EDIT_TOUCHED;
+void nlastrip_evaluate(Depsgraph *depsgraph,
+ PointerRNA *ptr,
+ NlaEvalData *channels,
+ ListBase *modifiers,
+ NlaEvalStrip *nes,
+ NlaEvalSnapshot *snapshot)
+{
+ NlaStrip *strip = nes->strip;
+
+ /* to prevent potential infinite recursion problems (i.e. transition strip, beside meta strip containing a transition
+ * several levels deep inside it), we tag the current strip as being evaluated, and clear this when we leave
+ */
+ /* TODO: be careful with this flag, since some edit tools may be running and have set this while animplayback was running */
+ if (strip->flag & NLASTRIP_FLAG_EDIT_TOUCHED)
+ return;
+ strip->flag |= NLASTRIP_FLAG_EDIT_TOUCHED;
+
+ /* actions to take depend on the type of strip */
+ switch (strip->type) {
+ case NLASTRIP_TYPE_CLIP: /* action-clip */
+ nlastrip_evaluate_actionclip(ptr, channels, modifiers, nes, snapshot);
+ break;
+ case NLASTRIP_TYPE_TRANSITION: /* transition */
+ nlastrip_evaluate_transition(depsgraph, ptr, channels, modifiers, nes, snapshot);
+ break;
+ case NLASTRIP_TYPE_META: /* meta */
+ nlastrip_evaluate_meta(depsgraph, ptr, channels, modifiers, nes, snapshot);
+ break;
+
+ default: /* do nothing */
+ break;
+ }
+
+ /* clear temp recursion safe-check */
+ strip->flag &= ~NLASTRIP_FLAG_EDIT_TOUCHED;
}
/* write the accumulated settings to */
-void nladata_flush_channels(Depsgraph *depsgraph, PointerRNA *ptr, NlaEvalData *channels, NlaEvalSnapshot *snapshot)
-{
- /* sanity checks */
- if (channels == NULL)
- return;
-
- const bool is_active_depsgraph = DEG_is_active(depsgraph);
-
- /* for each channel with accumulated values, write its value on the property it affects */
- for (NlaEvalChannel *nec = channels->channels.first; nec; nec = nec->next) {
- NlaEvalChannelSnapshot *nec_snapshot = nlaeval_snapshot_find_channel(snapshot, nec);
-
- PathResolvedRNA rna = { nec->key.ptr, nec->key.prop, -1 };
-
- for (int i = 0; i < nec_snapshot->length; i++) {
- if (BLI_BITMAP_TEST(nec->valid.ptr, i)) {
- float value = nec_snapshot->values[i];
- if (nec->is_array) {
- rna.prop_index = i;
- }
- animsys_write_rna_setting(&rna, value);
- if (is_active_depsgraph) {
- animsys_write_orig_anim_rna(ptr, nec->rna_path, rna.prop_index, value);
- }
- }
- }
- }
+void nladata_flush_channels(Depsgraph *depsgraph,
+ PointerRNA *ptr,
+ NlaEvalData *channels,
+ NlaEvalSnapshot *snapshot)
+{
+ /* sanity checks */
+ if (channels == NULL)
+ return;
+
+ const bool is_active_depsgraph = DEG_is_active(depsgraph);
+
+ /* for each channel with accumulated values, write its value on the property it affects */
+ for (NlaEvalChannel *nec = channels->channels.first; nec; nec = nec->next) {
+ NlaEvalChannelSnapshot *nec_snapshot = nlaeval_snapshot_find_channel(snapshot, nec);
+
+ PathResolvedRNA rna = {nec->key.ptr, nec->key.prop, -1};
+
+ for (int i = 0; i < nec_snapshot->length; i++) {
+ if (BLI_BITMAP_TEST(nec->valid.ptr, i)) {
+ float value = nec_snapshot->values[i];
+ if (nec->is_array) {
+ rna.prop_index = i;
+ }
+ animsys_write_rna_setting(&rna, value);
+ if (is_active_depsgraph) {
+ animsys_write_orig_anim_rna(ptr, nec->rna_path, rna.prop_index, value);
+ }
+ }
+ }
+ }
}
/* ---------------------- */
-static void nla_eval_domain_action(PointerRNA *ptr, NlaEvalData *channels, bAction *act, GSet *touched_actions)
+static void nla_eval_domain_action(PointerRNA *ptr,
+ NlaEvalData *channels,
+ bAction *act,
+ GSet *touched_actions)
{
- if (!BLI_gset_add(touched_actions, act)) {
- return;
- }
+ if (!BLI_gset_add(touched_actions, act)) {
+ return;
+ }
- for (FCurve *fcu = act->curves.first; fcu; fcu = fcu->next) {
- /* check if this curve should be skipped */
- if (fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED))
- continue;
- if ((fcu->grp) && (fcu->grp->flag & AGRP_MUTED))
- continue;
+ for (FCurve *fcu = act->curves.first; fcu; fcu = fcu->next) {
+ /* check if this curve should be skipped */
+ if (fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED))
+ continue;
+ if ((fcu->grp) && (fcu->grp->flag & AGRP_MUTED))
+ continue;
- NlaEvalChannel *nec = nlaevalchan_verify(ptr, channels, fcu->rna_path);
+ NlaEvalChannel *nec = nlaevalchan_verify(ptr, channels, fcu->rna_path);
- if (nec != NULL) {
- /* For quaternion properties, enable all sub-channels. */
- if (nec->mix_mode == NEC_MIX_QUATERNION) {
- BLI_bitmap_set_all(nec->valid.ptr, true, 4);
- continue;
- }
+ if (nec != NULL) {
+ /* For quaternion properties, enable all sub-channels. */
+ if (nec->mix_mode == NEC_MIX_QUATERNION) {
+ BLI_bitmap_set_all(nec->valid.ptr, true, 4);
+ continue;
+ }
- int idx = nlaevalchan_validate_index(nec, fcu->array_index);
+ int idx = nlaevalchan_validate_index(nec, fcu->array_index);
- if (idx >= 0) {
- BLI_BITMAP_ENABLE(nec->valid.ptr, idx);
- }
- }
- }
+ if (idx >= 0) {
+ BLI_BITMAP_ENABLE(nec->valid.ptr, idx);
+ }
+ }
+ }
}
-static void nla_eval_domain_strips(PointerRNA *ptr, NlaEvalData *channels, ListBase *strips, GSet *touched_actions)
+static void nla_eval_domain_strips(PointerRNA *ptr,
+ NlaEvalData *channels,
+ ListBase *strips,
+ GSet *touched_actions)
{
- for (NlaStrip *strip = strips->first; strip; strip = strip->next) {
- /* check strip's action */
- if (strip->act) {
- nla_eval_domain_action(ptr, channels, strip->act, touched_actions);
- }
+ for (NlaStrip *strip = strips->first; strip; strip = strip->next) {
+ /* check strip's action */
+ if (strip->act) {
+ nla_eval_domain_action(ptr, channels, strip->act, touched_actions);
+ }
- /* check sub-strips (if metas) */
- nla_eval_domain_strips(ptr, channels, &strip->strips, touched_actions);
- }
+ /* check sub-strips (if metas) */
+ nla_eval_domain_strips(ptr, channels, &strip->strips, touched_actions);
+ }
}
/**
@@ -3097,31 +3265,31 @@ static void nla_eval_domain_strips(PointerRNA *ptr, NlaEvalData *channels, ListB
*/
static void animsys_evaluate_nla_domain(PointerRNA *ptr, NlaEvalData *channels, AnimData *adt)
{
- GSet *touched_actions = BLI_gset_ptr_new(__func__);
+ GSet *touched_actions = BLI_gset_ptr_new(__func__);
- if (adt->action) {
- nla_eval_domain_action(ptr, channels, adt->action, touched_actions);
- }
+ if (adt->action) {
+ nla_eval_domain_action(ptr, channels, adt->action, touched_actions);
+ }
- /* NLA Data - Animation Data for Strips */
- for (NlaTrack *nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
- /* solo and muting are mutually exclusive... */
- if (adt->flag & ADT_NLA_SOLO_TRACK) {
- /* skip if there is a solo track, but this isn't it */
- if ((nlt->flag & NLATRACK_SOLO) == 0)
- continue;
- /* else - mute doesn't matter */
- }
- else {
- /* no solo tracks - skip track if muted */
- if (nlt->flag & NLATRACK_MUTED)
- continue;
- }
+ /* NLA Data - Animation Data for Strips */
+ for (NlaTrack *nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ /* solo and muting are mutually exclusive... */
+ if (adt->flag & ADT_NLA_SOLO_TRACK) {
+ /* skip if there is a solo track, but this isn't it */
+ if ((nlt->flag & NLATRACK_SOLO) == 0)
+ continue;
+ /* else - mute doesn't matter */
+ }
+ else {
+ /* no solo tracks - skip track if muted */
+ if (nlt->flag & NLATRACK_MUTED)
+ continue;
+ }
- nla_eval_domain_strips(ptr, channels, &nlt->strips, touched_actions);
- }
+ nla_eval_domain_strips(ptr, channels, &nlt->strips, touched_actions);
+ }
- BLI_gset_free(touched_actions, NULL);
+ BLI_gset_free(touched_actions, NULL);
}
/* ---------------------- */
@@ -3133,169 +3301,185 @@ static void animsys_evaluate_nla_domain(PointerRNA *ptr, NlaEvalData *channels,
* \param[out] r_context If not NULL, data about the currently edited strip is stored here and excluded from value calculation.
* \return false if NLA evaluation isn't actually applicable
*/
-static bool animsys_evaluate_nla(Depsgraph *depsgraph, NlaEvalData *echannels, PointerRNA *ptr, AnimData *adt, float ctime, NlaKeyframingContext *r_context)
-{
- NlaTrack *nlt;
- short track_index = 0;
- bool has_strips = false;
-
- ListBase estrips = {NULL, NULL};
- NlaEvalStrip *nes;
- NlaStrip dummy_strip_buf;
-
- /* dummy strip for active action */
- NlaStrip *dummy_strip = r_context ? &r_context->strip : &dummy_strip_buf;
-
- memset(dummy_strip, 0, sizeof(*dummy_strip));
-
- /* 1. get the stack of strips to evaluate at current time (influence calculated here) */
- for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next, track_index++) {
- /* stop here if tweaking is on and this strip is the tweaking track (it will be the first one that's 'disabled')... */
- if ((adt->flag & ADT_NLA_EDIT_ON) && (nlt->flag & NLATRACK_DISABLED))
- break;
-
- /* solo and muting are mutually exclusive... */
- if (adt->flag & ADT_NLA_SOLO_TRACK) {
- /* skip if there is a solo track, but this isn't it */
- if ((nlt->flag & NLATRACK_SOLO) == 0)
- continue;
- /* else - mute doesn't matter */
- }
- else {
- /* no solo tracks - skip track if muted */
- if (nlt->flag & NLATRACK_MUTED)
- continue;
- }
-
- /* if this track has strips (but maybe they won't be suitable), set has_strips
- * - used for mainly for still allowing normal action evaluation...
- */
- if (nlt->strips.first)
- has_strips = true;
-
- /* otherwise, get strip to evaluate for this channel */
- nes = nlastrips_ctime_get_strip(depsgraph, &estrips, &nlt->strips, track_index, ctime);
- if (nes) nes->track = nlt;
- }
-
- /* add 'active' Action (may be tweaking track) as last strip to evaluate in NLA stack
- * - only do this if we're not exclusively evaluating the 'solo' NLA-track
- * - however, if the 'solo' track houses the current 'tweaking' strip,
- * then we should allow this to play, otherwise nothing happens
- */
- if ((adt->action) && ((adt->flag & ADT_NLA_SOLO_TRACK) == 0 || (adt->flag & ADT_NLA_EDIT_ON))) {
- /* if there are strips, evaluate action as per NLA rules */
- if ((has_strips) || (adt->actstrip)) {
- /* make dummy NLA strip, and add that to the stack */
- ListBase dummy_trackslist;
-
- dummy_trackslist.first = dummy_trackslist.last = dummy_strip;
-
- /* Strips with a user-defined time curve don't get properly remapped for editing
- * at the moment, so mapping them just for display may be confusing. */
- bool is_inplace_tweak = (nlt) && !(adt->flag & ADT_NLA_EDIT_NOMAP) && !(adt->actstrip->flag & NLASTRIP_FLAG_USR_TIME);
-
- if (is_inplace_tweak) {
- /* edit active action in-place according to its active strip, so copy the data */
- memcpy(dummy_strip, adt->actstrip, sizeof(NlaStrip));
- dummy_strip->next = dummy_strip->prev = NULL;
- }
- else {
- /* set settings of dummy NLA strip from AnimData settings */
- dummy_strip->act = adt->action;
-
- /* action range is calculated taking F-Modifiers into account (which making new strips doesn't do due to the troublesome nature of that) */
- calc_action_range(dummy_strip->act, &dummy_strip->actstart, &dummy_strip->actend, 1);
- dummy_strip->start = dummy_strip->actstart;
- dummy_strip->end = (IS_EQF(dummy_strip->actstart, dummy_strip->actend)) ? (dummy_strip->actstart + 1.0f) : (dummy_strip->actend);
-
- /* Always use the blend mode of the strip in tweak mode, even if not in-place. */
- if (nlt && adt->actstrip) {
- dummy_strip->blendmode = adt->actstrip->blendmode;
- dummy_strip->extendmode = NLASTRIP_EXTEND_HOLD;
- }
- else {
- dummy_strip->blendmode = adt->act_blendmode;
- dummy_strip->extendmode = adt->act_extendmode;
- }
-
- /* Unless extendmode is Nothing (might be useful for flattening NLA evaluation), disable range. */
- if (dummy_strip->extendmode != NLASTRIP_EXTEND_NOTHING) {
- dummy_strip->flag |= NLASTRIP_FLAG_NO_TIME_MAP;
- }
-
- dummy_strip->influence = adt->act_influence;
-
- /* NOTE: must set this, or else the default setting overrides, and this setting doesn't work */
- dummy_strip->flag |= NLASTRIP_FLAG_USR_INFLUENCE;
- }
-
- /* add this to our list of evaluation strips */
- if (r_context == NULL) {
- nlastrips_ctime_get_strip(depsgraph, &estrips, &dummy_trackslist, -1, ctime);
- }
- /* If computing the context for keyframing, store data there instead of the list. */
- else {
- /* The extend mode here effectively controls whether it is possible to keyframe beyond the ends. */
- dummy_strip->extendmode = is_inplace_tweak ? NLASTRIP_EXTEND_NOTHING : NLASTRIP_EXTEND_HOLD;
-
- r_context->eval_strip = nes = nlastrips_ctime_get_strip(depsgraph, NULL, &dummy_trackslist, -1, ctime);
-
- /* These setting combinations require no data from strips below, so exit immediately. */
- if ((nes == NULL) || (dummy_strip->blendmode == NLASTRIP_MODE_REPLACE && dummy_strip->influence == 1.0f)) {
- BLI_freelistN(&estrips);
- return true;
- }
- }
- }
- else {
- /* special case - evaluate as if there isn't any NLA data */
- BLI_freelistN(&estrips);
- return false;
- }
- }
-
- /* only continue if there are strips to evaluate */
- if (BLI_listbase_is_empty(&estrips))
- return true;
-
- /* 2. for each strip, evaluate then accumulate on top of existing channels, but don't set values yet */
- for (nes = estrips.first; nes; nes = nes->next)
- nlastrip_evaluate(depsgraph, ptr, echannels, NULL, nes, &echannels->eval_snapshot);
-
- /* 3. free temporary evaluation data that's not used elsewhere */
- BLI_freelistN(&estrips);
- return true;
+static bool animsys_evaluate_nla(Depsgraph *depsgraph,
+ NlaEvalData *echannels,
+ PointerRNA *ptr,
+ AnimData *adt,
+ float ctime,
+ NlaKeyframingContext *r_context)
+{
+ NlaTrack *nlt;
+ short track_index = 0;
+ bool has_strips = false;
+
+ ListBase estrips = {NULL, NULL};
+ NlaEvalStrip *nes;
+ NlaStrip dummy_strip_buf;
+
+ /* dummy strip for active action */
+ NlaStrip *dummy_strip = r_context ? &r_context->strip : &dummy_strip_buf;
+
+ memset(dummy_strip, 0, sizeof(*dummy_strip));
+
+ /* 1. get the stack of strips to evaluate at current time (influence calculated here) */
+ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next, track_index++) {
+ /* stop here if tweaking is on and this strip is the tweaking track (it will be the first one that's 'disabled')... */
+ if ((adt->flag & ADT_NLA_EDIT_ON) && (nlt->flag & NLATRACK_DISABLED))
+ break;
+
+ /* solo and muting are mutually exclusive... */
+ if (adt->flag & ADT_NLA_SOLO_TRACK) {
+ /* skip if there is a solo track, but this isn't it */
+ if ((nlt->flag & NLATRACK_SOLO) == 0)
+ continue;
+ /* else - mute doesn't matter */
+ }
+ else {
+ /* no solo tracks - skip track if muted */
+ if (nlt->flag & NLATRACK_MUTED)
+ continue;
+ }
+
+ /* if this track has strips (but maybe they won't be suitable), set has_strips
+ * - used for mainly for still allowing normal action evaluation...
+ */
+ if (nlt->strips.first)
+ has_strips = true;
+
+ /* otherwise, get strip to evaluate for this channel */
+ nes = nlastrips_ctime_get_strip(depsgraph, &estrips, &nlt->strips, track_index, ctime);
+ if (nes)
+ nes->track = nlt;
+ }
+
+ /* add 'active' Action (may be tweaking track) as last strip to evaluate in NLA stack
+ * - only do this if we're not exclusively evaluating the 'solo' NLA-track
+ * - however, if the 'solo' track houses the current 'tweaking' strip,
+ * then we should allow this to play, otherwise nothing happens
+ */
+ if ((adt->action) && ((adt->flag & ADT_NLA_SOLO_TRACK) == 0 || (adt->flag & ADT_NLA_EDIT_ON))) {
+ /* if there are strips, evaluate action as per NLA rules */
+ if ((has_strips) || (adt->actstrip)) {
+ /* make dummy NLA strip, and add that to the stack */
+ ListBase dummy_trackslist;
+
+ dummy_trackslist.first = dummy_trackslist.last = dummy_strip;
+
+ /* Strips with a user-defined time curve don't get properly remapped for editing
+ * at the moment, so mapping them just for display may be confusing. */
+ bool is_inplace_tweak = (nlt) && !(adt->flag & ADT_NLA_EDIT_NOMAP) &&
+ !(adt->actstrip->flag & NLASTRIP_FLAG_USR_TIME);
+
+ if (is_inplace_tweak) {
+ /* edit active action in-place according to its active strip, so copy the data */
+ memcpy(dummy_strip, adt->actstrip, sizeof(NlaStrip));
+ dummy_strip->next = dummy_strip->prev = NULL;
+ }
+ else {
+ /* set settings of dummy NLA strip from AnimData settings */
+ dummy_strip->act = adt->action;
+
+ /* action range is calculated taking F-Modifiers into account (which making new strips doesn't do due to the troublesome nature of that) */
+ calc_action_range(dummy_strip->act, &dummy_strip->actstart, &dummy_strip->actend, 1);
+ dummy_strip->start = dummy_strip->actstart;
+ dummy_strip->end = (IS_EQF(dummy_strip->actstart, dummy_strip->actend)) ?
+ (dummy_strip->actstart + 1.0f) :
+ (dummy_strip->actend);
+
+ /* Always use the blend mode of the strip in tweak mode, even if not in-place. */
+ if (nlt && adt->actstrip) {
+ dummy_strip->blendmode = adt->actstrip->blendmode;
+ dummy_strip->extendmode = NLASTRIP_EXTEND_HOLD;
+ }
+ else {
+ dummy_strip->blendmode = adt->act_blendmode;
+ dummy_strip->extendmode = adt->act_extendmode;
+ }
+
+ /* Unless extendmode is Nothing (might be useful for flattening NLA evaluation), disable range. */
+ if (dummy_strip->extendmode != NLASTRIP_EXTEND_NOTHING) {
+ dummy_strip->flag |= NLASTRIP_FLAG_NO_TIME_MAP;
+ }
+
+ dummy_strip->influence = adt->act_influence;
+
+ /* NOTE: must set this, or else the default setting overrides, and this setting doesn't work */
+ dummy_strip->flag |= NLASTRIP_FLAG_USR_INFLUENCE;
+ }
+
+ /* add this to our list of evaluation strips */
+ if (r_context == NULL) {
+ nlastrips_ctime_get_strip(depsgraph, &estrips, &dummy_trackslist, -1, ctime);
+ }
+ /* If computing the context for keyframing, store data there instead of the list. */
+ else {
+ /* The extend mode here effectively controls whether it is possible to keyframe beyond the ends. */
+ dummy_strip->extendmode = is_inplace_tweak ? NLASTRIP_EXTEND_NOTHING :
+ NLASTRIP_EXTEND_HOLD;
+
+ r_context->eval_strip = nes = nlastrips_ctime_get_strip(
+ depsgraph, NULL, &dummy_trackslist, -1, ctime);
+
+ /* These setting combinations require no data from strips below, so exit immediately. */
+ if ((nes == NULL) ||
+ (dummy_strip->blendmode == NLASTRIP_MODE_REPLACE && dummy_strip->influence == 1.0f)) {
+ BLI_freelistN(&estrips);
+ return true;
+ }
+ }
+ }
+ else {
+ /* special case - evaluate as if there isn't any NLA data */
+ BLI_freelistN(&estrips);
+ return false;
+ }
+ }
+
+ /* only continue if there are strips to evaluate */
+ if (BLI_listbase_is_empty(&estrips))
+ return true;
+
+ /* 2. for each strip, evaluate then accumulate on top of existing channels, but don't set values yet */
+ for (nes = estrips.first; nes; nes = nes->next)
+ nlastrip_evaluate(depsgraph, ptr, echannels, NULL, nes, &echannels->eval_snapshot);
+
+ /* 3. free temporary evaluation data that's not used elsewhere */
+ BLI_freelistN(&estrips);
+ return true;
}
/* NLA Evaluation function (mostly for use through do_animdata)
* - All channels that will be affected are not cleared anymore. Instead, we just evaluate into
* some temp channels, where values can be accumulated in one go.
*/
-static void animsys_calculate_nla(Depsgraph *depsgraph, PointerRNA *ptr, AnimData *adt, float ctime)
+static void animsys_calculate_nla(Depsgraph *depsgraph,
+ PointerRNA *ptr,
+ AnimData *adt,
+ float ctime)
{
- NlaEvalData echannels;
+ NlaEvalData echannels;
- nlaeval_init(&echannels);
+ nlaeval_init(&echannels);
- /* evaluate the NLA stack, obtaining a set of values to flush */
- if (animsys_evaluate_nla(depsgraph, &echannels, ptr, adt, ctime, NULL)) {
- /* reset any channels touched by currently inactive actions to default value */
- animsys_evaluate_nla_domain(ptr, &echannels, adt);
+ /* evaluate the NLA stack, obtaining a set of values to flush */
+ if (animsys_evaluate_nla(depsgraph, &echannels, ptr, adt, ctime, NULL)) {
+ /* reset any channels touched by currently inactive actions to default value */
+ animsys_evaluate_nla_domain(ptr, &echannels, adt);
- /* flush effects of accumulating channels in NLA to the actual data they affect */
- nladata_flush_channels(depsgraph, ptr, &echannels, &echannels.eval_snapshot);
- }
- else {
- /* special case - evaluate as if there isn't any NLA data */
- /* TODO: this is really just a stop-gap measure... */
- if (G.debug & G_DEBUG) CLOG_WARN(&LOG, "NLA Eval: Stopgap for active action on NLA Stack - no strips case");
+ /* flush effects of accumulating channels in NLA to the actual data they affect */
+ nladata_flush_channels(depsgraph, ptr, &echannels, &echannels.eval_snapshot);
+ }
+ else {
+ /* special case - evaluate as if there isn't any NLA data */
+ /* TODO: this is really just a stop-gap measure... */
+ if (G.debug & G_DEBUG)
+ CLOG_WARN(&LOG, "NLA Eval: Stopgap for active action on NLA Stack - no strips case");
- animsys_evaluate_action(depsgraph, ptr, adt->action, ctime);
- }
+ animsys_evaluate_action(depsgraph, ptr, adt->action, ctime);
+ }
- /* free temp data */
- nlaeval_free(&echannels);
+ /* free temp data */
+ nlaeval_free(&echannels);
}
/* ---------------------- */
@@ -3308,35 +3492,40 @@ static void animsys_calculate_nla(Depsgraph *depsgraph, PointerRNA *ptr, AnimDat
* @param ptr RNA pointer to the Object with the animation.
* @return Keyframing context, or NULL if not necessary.
*/
-NlaKeyframingContext *BKE_animsys_get_nla_keyframing_context(
- struct ListBase *cache, struct Depsgraph *depsgraph, struct PointerRNA *ptr, struct AnimData *adt, float ctime)
+NlaKeyframingContext *BKE_animsys_get_nla_keyframing_context(struct ListBase *cache,
+ struct Depsgraph *depsgraph,
+ struct PointerRNA *ptr,
+ struct AnimData *adt,
+ float ctime)
{
- /* No remapping needed if NLA is off or no action. */
- if ((adt == NULL) || (adt->action == NULL) || (adt->nla_tracks.first == NULL) || (adt->flag & ADT_NLA_EVAL_OFF)) {
- return NULL;
- }
+ /* No remapping needed if NLA is off or no action. */
+ if ((adt == NULL) || (adt->action == NULL) || (adt->nla_tracks.first == NULL) ||
+ (adt->flag & ADT_NLA_EVAL_OFF)) {
+ return NULL;
+ }
- /* No remapping if editing an ordinary Replace action with full influence. */
- if (!(adt->flag & ADT_NLA_EDIT_ON) && (adt->act_blendmode == NLASTRIP_MODE_REPLACE && adt->act_influence == 1.0f)) {
- return NULL;
- }
+ /* No remapping if editing an ordinary Replace action with full influence. */
+ if (!(adt->flag & ADT_NLA_EDIT_ON) &&
+ (adt->act_blendmode == NLASTRIP_MODE_REPLACE && adt->act_influence == 1.0f)) {
+ return NULL;
+ }
- /* Try to find a cached context. */
- NlaKeyframingContext *ctx = BLI_findptr(cache, adt, offsetof(NlaKeyframingContext, adt));
+ /* Try to find a cached context. */
+ NlaKeyframingContext *ctx = BLI_findptr(cache, adt, offsetof(NlaKeyframingContext, adt));
- if (ctx == NULL) {
- /* Allocate and evaluate a new context. */
- ctx = MEM_callocN(sizeof(*ctx), "NlaKeyframingContext");
- ctx->adt = adt;
+ if (ctx == NULL) {
+ /* Allocate and evaluate a new context. */
+ ctx = MEM_callocN(sizeof(*ctx), "NlaKeyframingContext");
+ ctx->adt = adt;
- nlaeval_init(&ctx->nla_channels);
- animsys_evaluate_nla(depsgraph, &ctx->nla_channels, ptr, adt, ctime, ctx);
+ nlaeval_init(&ctx->nla_channels);
+ animsys_evaluate_nla(depsgraph, &ctx->nla_channels, ptr, adt, ctime, ctx);
- BLI_assert(ELEM(ctx->strip.act, NULL, adt->action));
- BLI_addtail(cache, ctx);
- }
+ BLI_assert(ELEM(ctx->strip.act, NULL, adt->action));
+ BLI_addtail(cache, ctx);
+ }
- return ctx;
+ return ctx;
}
/**
@@ -3350,84 +3539,99 @@ NlaKeyframingContext *BKE_animsys_get_nla_keyframing_context(
* @param[out] r_force_all Set to true if all channels must be inserted. May be NULL.
* @return False if correction fails due to a division by zero, or null r_force_all when all channels are required.
*/
-bool BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context, struct PointerRNA *prop_ptr, struct PropertyRNA *prop, float *values, int count, int index, bool *r_force_all)
-{
- if (r_force_all != NULL) {
- *r_force_all = false;
- }
-
- /* No context means no correction. */
- if (context == NULL || context->strip.act == NULL) {
- return true;
- }
-
- /* If the strip is not evaluated, it is the same as zero influence. */
- if (context->eval_strip == NULL) {
- return false;
- }
-
- /* Full influence Replace strips also require no correction. */
- int blend_mode = context->strip.blendmode;
- float influence = context->strip.influence;
-
- if (blend_mode == NLASTRIP_MODE_REPLACE && influence == 1.0f) {
- return true;
- }
-
- /* Zero influence is division by zero. */
- if (influence <= 0.0f) {
- return false;
- }
-
- /* Find the evaluation channel for the NLA stack below current strip. */
- NlaEvalChannelKey key = { .ptr = *prop_ptr, .prop = prop, };
- NlaEvalData *nlaeval = &context->nla_channels;
- NlaEvalChannel *nec = nlaevalchan_verify_key(nlaeval, NULL, &key);
-
- if (nec->base_snapshot.length != count) {
- BLI_assert(!"invalid value count");
- return false;
- }
-
- /* Invert the blending operation to compute the desired key values. */
- NlaEvalChannelSnapshot *nec_snapshot = nlaeval_snapshot_find_channel(&nlaeval->eval_snapshot, nec);
-
- float *old_values = nec_snapshot->values;
-
- if (blend_mode == NLASTRIP_MODE_COMBINE) {
- /* Quaternion combine handles all sub-channels as a unit. */
- if (nec->mix_mode == NEC_MIX_QUATERNION) {
- if (r_force_all == NULL) {
- return false;
- }
-
- *r_force_all = true;
-
- nla_invert_combine_quaternion(old_values, values, influence, values);
- }
- else {
- float *base_values = nec->base_snapshot.values;
-
- for (int i = 0; i < count; i++) {
- if (ELEM(index, i, -1)) {
- if (!nla_invert_combine_value(nec->mix_mode, base_values[i], old_values[i], values[i], influence, &values[i])) {
- return false;
- }
- }
- }
- }
- }
- else {
- for (int i = 0; i < count; i++) {
- if (ELEM(index, i, -1)) {
- if (!nla_invert_blend_value(blend_mode, old_values[i], values[i], influence, &values[i])) {
- return false;
- }
- }
- }
- }
-
- return true;
+bool BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context,
+ struct PointerRNA *prop_ptr,
+ struct PropertyRNA *prop,
+ float *values,
+ int count,
+ int index,
+ bool *r_force_all)
+{
+ if (r_force_all != NULL) {
+ *r_force_all = false;
+ }
+
+ /* No context means no correction. */
+ if (context == NULL || context->strip.act == NULL) {
+ return true;
+ }
+
+ /* If the strip is not evaluated, it is the same as zero influence. */
+ if (context->eval_strip == NULL) {
+ return false;
+ }
+
+ /* Full influence Replace strips also require no correction. */
+ int blend_mode = context->strip.blendmode;
+ float influence = context->strip.influence;
+
+ if (blend_mode == NLASTRIP_MODE_REPLACE && influence == 1.0f) {
+ return true;
+ }
+
+ /* Zero influence is division by zero. */
+ if (influence <= 0.0f) {
+ return false;
+ }
+
+ /* Find the evaluation channel for the NLA stack below current strip. */
+ NlaEvalChannelKey key = {
+ .ptr = *prop_ptr,
+ .prop = prop,
+ };
+ NlaEvalData *nlaeval = &context->nla_channels;
+ NlaEvalChannel *nec = nlaevalchan_verify_key(nlaeval, NULL, &key);
+
+ if (nec->base_snapshot.length != count) {
+ BLI_assert(!"invalid value count");
+ return false;
+ }
+
+ /* Invert the blending operation to compute the desired key values. */
+ NlaEvalChannelSnapshot *nec_snapshot = nlaeval_snapshot_find_channel(&nlaeval->eval_snapshot,
+ nec);
+
+ float *old_values = nec_snapshot->values;
+
+ if (blend_mode == NLASTRIP_MODE_COMBINE) {
+ /* Quaternion combine handles all sub-channels as a unit. */
+ if (nec->mix_mode == NEC_MIX_QUATERNION) {
+ if (r_force_all == NULL) {
+ return false;
+ }
+
+ *r_force_all = true;
+
+ nla_invert_combine_quaternion(old_values, values, influence, values);
+ }
+ else {
+ float *base_values = nec->base_snapshot.values;
+
+ for (int i = 0; i < count; i++) {
+ if (ELEM(index, i, -1)) {
+ if (!nla_invert_combine_value(nec->mix_mode,
+ base_values[i],
+ old_values[i],
+ values[i],
+ influence,
+ &values[i])) {
+ return false;
+ }
+ }
+ }
+ }
+ }
+ else {
+ for (int i = 0; i < count; i++) {
+ if (ELEM(index, i, -1)) {
+ if (!nla_invert_blend_value(blend_mode, old_values[i], values[i], influence, &values[i])) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
}
/**
@@ -3435,12 +3639,12 @@ bool BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context,
*/
void BKE_animsys_free_nla_keyframing_context_cache(struct ListBase *cache)
{
- for (NlaKeyframingContext *ctx = cache->first; ctx; ctx = ctx->next) {
- MEM_SAFE_FREE(ctx->eval_strip);
- nlaeval_free(&ctx->nla_channels);
- }
+ for (NlaKeyframingContext *ctx = cache->first; ctx; ctx = ctx->next) {
+ MEM_SAFE_FREE(ctx->eval_strip);
+ nlaeval_free(&ctx->nla_channels);
+ }
- BLI_freelistN(cache);
+ BLI_freelistN(cache);
}
/* ***************************************** */
@@ -3449,15 +3653,15 @@ void BKE_animsys_free_nla_keyframing_context_cache(struct ListBase *cache)
/* Evaluate Overrides */
static void animsys_evaluate_overrides(PointerRNA *ptr, AnimData *adt)
{
- AnimOverride *aor;
+ AnimOverride *aor;
- /* for each override, simply execute... */
- for (aor = adt->overrides.first; aor; aor = aor->next) {
- PathResolvedRNA anim_rna;
- if (animsys_store_rna_setting(ptr, aor->rna_path, aor->array_index, &anim_rna)) {
- animsys_write_rna_setting(&anim_rna, aor->value);
- }
- }
+ /* for each override, simply execute... */
+ for (aor = adt->overrides.first; aor; aor = aor->next) {
+ PathResolvedRNA anim_rna;
+ if (animsys_store_rna_setting(ptr, aor->rna_path, aor->array_index, &anim_rna)) {
+ animsys_write_rna_setting(&anim_rna, aor->value);
+ }
+ }
}
/* ***************************************** */
@@ -3500,58 +3704,59 @@ static void animsys_evaluate_overrides(PointerRNA *ptr, AnimData *adt)
* and that the flags for which parts of the anim-data settings need to be recalculated
* have been set already by the depsgraph. Now, we use the recalc
*/
-void BKE_animsys_evaluate_animdata(Depsgraph *depsgraph, Scene *scene, ID *id, AnimData *adt, float ctime, short recalc)
-{
- PointerRNA id_ptr;
-
- /* sanity checks */
- if (ELEM(NULL, id, adt))
- return;
-
- /* get pointer to ID-block for RNA to use */
- RNA_id_pointer_create(id, &id_ptr);
-
- /* recalculate keyframe data:
- * - NLA before Active Action, as Active Action behaves as 'tweaking track'
- * that overrides 'rough' work in NLA
- */
- /* TODO: need to double check that this all works correctly */
- if (recalc & ADT_RECALC_ANIM) {
- /* evaluate NLA data */
- if ((adt->nla_tracks.first) && !(adt->flag & ADT_NLA_EVAL_OFF)) {
- /* evaluate NLA-stack
- * - active action is evaluated as part of the NLA stack as the last item
- */
- animsys_calculate_nla(depsgraph, &id_ptr, adt, ctime);
- }
- /* evaluate Active Action only */
- else if (adt->action)
- animsys_evaluate_action_ex(depsgraph, &id_ptr, adt->action, ctime);
- }
-
- /* recalculate drivers
- * - Drivers need to be evaluated afterwards, as they can either override
- * or be layered on top of existing animation data.
- * - Drivers should be in the appropriate order to be evaluated without problems...
- */
- if (recalc & ADT_RECALC_DRIVERS) {
- animsys_evaluate_drivers(&id_ptr, adt, ctime);
- }
-
- /* always execute 'overrides'
- * - Overrides allow editing, by overwriting the value(s) set from animation-data, with the
- * value last set by the user (and not keyframed yet).
- * - Overrides are cleared upon frame change and/or keyframing
- * - It is best that we execute this every time, so that no errors are likely to occur.
- */
- animsys_evaluate_overrides(&id_ptr, adt);
-
- /* execute and clear all cached property update functions */
- if (scene) {
- Main *bmain = G.main; // xxx - to get passed in!
- RNA_property_update_cache_flush(bmain, scene);
- RNA_property_update_cache_free();
- }
+void BKE_animsys_evaluate_animdata(
+ Depsgraph *depsgraph, Scene *scene, ID *id, AnimData *adt, float ctime, short recalc)
+{
+ PointerRNA id_ptr;
+
+ /* sanity checks */
+ if (ELEM(NULL, id, adt))
+ return;
+
+ /* get pointer to ID-block for RNA to use */
+ RNA_id_pointer_create(id, &id_ptr);
+
+ /* recalculate keyframe data:
+ * - NLA before Active Action, as Active Action behaves as 'tweaking track'
+ * that overrides 'rough' work in NLA
+ */
+ /* TODO: need to double check that this all works correctly */
+ if (recalc & ADT_RECALC_ANIM) {
+ /* evaluate NLA data */
+ if ((adt->nla_tracks.first) && !(adt->flag & ADT_NLA_EVAL_OFF)) {
+ /* evaluate NLA-stack
+ * - active action is evaluated as part of the NLA stack as the last item
+ */
+ animsys_calculate_nla(depsgraph, &id_ptr, adt, ctime);
+ }
+ /* evaluate Active Action only */
+ else if (adt->action)
+ animsys_evaluate_action_ex(depsgraph, &id_ptr, adt->action, ctime);
+ }
+
+ /* recalculate drivers
+ * - Drivers need to be evaluated afterwards, as they can either override
+ * or be layered on top of existing animation data.
+ * - Drivers should be in the appropriate order to be evaluated without problems...
+ */
+ if (recalc & ADT_RECALC_DRIVERS) {
+ animsys_evaluate_drivers(&id_ptr, adt, ctime);
+ }
+
+ /* always execute 'overrides'
+ * - Overrides allow editing, by overwriting the value(s) set from animation-data, with the
+ * value last set by the user (and not keyframed yet).
+ * - Overrides are cleared upon frame change and/or keyframing
+ * - It is best that we execute this every time, so that no errors are likely to occur.
+ */
+ animsys_evaluate_overrides(&id_ptr, adt);
+
+ /* execute and clear all cached property update functions */
+ if (scene) {
+ Main *bmain = G.main; // xxx - to get passed in!
+ RNA_property_update_cache_flush(bmain, scene);
+ RNA_property_update_cache_free();
+ }
}
/* Evaluation of all ID-blocks with Animation Data blocks - Animation Data Only
@@ -3561,129 +3766,135 @@ void BKE_animsys_evaluate_animdata(Depsgraph *depsgraph, Scene *scene, ID *id, A
* 'local' (i.e. belonging in the nearest ID-block that setting is related to, not a
* standard 'root') block are overridden by a larger 'user'
*/
-void BKE_animsys_evaluate_all_animation(Main *main, Depsgraph *depsgraph, Scene *scene, float ctime)
+void BKE_animsys_evaluate_all_animation(Main *main,
+ Depsgraph *depsgraph,
+ Scene *scene,
+ float ctime)
{
- ID *id;
+ ID *id;
- if (G.debug & G_DEBUG)
- printf("Evaluate all animation - %f\n", ctime);
+ if (G.debug & G_DEBUG)
+ printf("Evaluate all animation - %f\n", ctime);
- /* macros for less typing
- * - only evaluate animation data for id if it has users (and not just fake ones)
- * - whether animdata exists is checked for by the evaluation function, though taking
- * this outside of the function may make things slightly faster?
- */
+ /* macros for less typing
+ * - only evaluate animation data for id if it has users (and not just fake ones)
+ * - whether animdata exists is checked for by the evaluation function, though taking
+ * this outside of the function may make things slightly faster?
+ */
#define EVAL_ANIM_IDS(first, aflag) \
- for (id = first; id; id = id->next) { \
- if (ID_REAL_USERS(id) > 0) { \
- AnimData *adt = BKE_animdata_from_id(id); \
- BKE_animsys_evaluate_animdata(depsgraph, scene, id, adt, ctime, aflag); \
- } \
- } (void)0
-
- /* another macro for the "embedded" nodetree cases
- * - this is like EVAL_ANIM_IDS, but this handles the case "embedded nodetrees"
- * (i.e. scene/material/texture->nodetree) which we need a special exception
- * for, otherwise they'd get skipped
- * - ntp = "node tree parent" = datablock where node tree stuff resides
- */
+ for (id = first; id; id = id->next) { \
+ if (ID_REAL_USERS(id) > 0) { \
+ AnimData *adt = BKE_animdata_from_id(id); \
+ BKE_animsys_evaluate_animdata(depsgraph, scene, id, adt, ctime, aflag); \
+ } \
+ } \
+ (void)0
+
+ /* another macro for the "embedded" nodetree cases
+ * - this is like EVAL_ANIM_IDS, but this handles the case "embedded nodetrees"
+ * (i.e. scene/material/texture->nodetree) which we need a special exception
+ * for, otherwise they'd get skipped
+ * - ntp = "node tree parent" = datablock where node tree stuff resides
+ */
#define EVAL_ANIM_NODETREE_IDS(first, NtId_Type, aflag) \
- for (id = first; id; id = id->next) { \
- if (ID_REAL_USERS(id) > 0) { \
- AnimData *adt = BKE_animdata_from_id(id); \
- NtId_Type *ntp = (NtId_Type *)id; \
- if (ntp->nodetree) { \
- AnimData *adt2 = BKE_animdata_from_id((ID *)ntp->nodetree); \
- BKE_animsys_evaluate_animdata(depsgraph, scene, (ID *)ntp->nodetree, adt2, ctime, ADT_RECALC_ANIM); \
- } \
- BKE_animsys_evaluate_animdata(depsgraph, scene, id, adt, ctime, aflag); \
- } \
- } (void)0
+ for (id = first; id; id = id->next) { \
+ if (ID_REAL_USERS(id) > 0) { \
+ AnimData *adt = BKE_animdata_from_id(id); \
+ NtId_Type *ntp = (NtId_Type *)id; \
+ if (ntp->nodetree) { \
+ AnimData *adt2 = BKE_animdata_from_id((ID *)ntp->nodetree); \
+ BKE_animsys_evaluate_animdata( \
+ depsgraph, scene, (ID *)ntp->nodetree, adt2, ctime, ADT_RECALC_ANIM); \
+ } \
+ BKE_animsys_evaluate_animdata(depsgraph, scene, id, adt, ctime, aflag); \
+ } \
+ } \
+ (void)0
- /* optimization:
- * when there are no actions, don't go over database and loop over heaps of datablocks,
- * which should ultimately be empty, since it is not possible for now to have any animation
- * without some actions, and drivers wouldn't get affected by any state changes
- *
- * however, if there are some curves, we will need to make sure that their 'ctime' property gets
- * set correctly, so this optimization must be skipped in that case...
- */
- if (BLI_listbase_is_empty(&main->actions) && BLI_listbase_is_empty(&main->curves)) {
- if (G.debug & G_DEBUG)
- printf("\tNo Actions, so no animation needs to be evaluated...\n");
+ /* optimization:
+ * when there are no actions, don't go over database and loop over heaps of datablocks,
+ * which should ultimately be empty, since it is not possible for now to have any animation
+ * without some actions, and drivers wouldn't get affected by any state changes
+ *
+ * however, if there are some curves, we will need to make sure that their 'ctime' property gets
+ * set correctly, so this optimization must be skipped in that case...
+ */
+ if (BLI_listbase_is_empty(&main->actions) && BLI_listbase_is_empty(&main->curves)) {
+ if (G.debug & G_DEBUG)
+ printf("\tNo Actions, so no animation needs to be evaluated...\n");
- return;
- }
+ return;
+ }
- /* nodes */
- EVAL_ANIM_IDS(main->nodetrees.first, ADT_RECALC_ANIM);
+ /* nodes */
+ EVAL_ANIM_IDS(main->nodetrees.first, ADT_RECALC_ANIM);
- /* textures */
- EVAL_ANIM_NODETREE_IDS(main->textures.first, Tex, ADT_RECALC_ANIM);
+ /* textures */
+ EVAL_ANIM_NODETREE_IDS(main->textures.first, Tex, ADT_RECALC_ANIM);
- /* lights */
- EVAL_ANIM_NODETREE_IDS(main->lights.first, Light, ADT_RECALC_ANIM);
+ /* lights */
+ EVAL_ANIM_NODETREE_IDS(main->lights.first, Light, ADT_RECALC_ANIM);
- /* materials */
- EVAL_ANIM_NODETREE_IDS(main->materials.first, Material, ADT_RECALC_ANIM);
+ /* materials */
+ EVAL_ANIM_NODETREE_IDS(main->materials.first, Material, ADT_RECALC_ANIM);
- /* cameras */
- EVAL_ANIM_IDS(main->cameras.first, ADT_RECALC_ANIM);
+ /* cameras */
+ EVAL_ANIM_IDS(main->cameras.first, ADT_RECALC_ANIM);
- /* shapekeys */
- EVAL_ANIM_IDS(main->shapekeys.first, ADT_RECALC_ANIM);
+ /* shapekeys */
+ EVAL_ANIM_IDS(main->shapekeys.first, ADT_RECALC_ANIM);
- /* metaballs */
- EVAL_ANIM_IDS(main->metaballs.first, ADT_RECALC_ANIM);
+ /* metaballs */
+ EVAL_ANIM_IDS(main->metaballs.first, ADT_RECALC_ANIM);
- /* curves */
- EVAL_ANIM_IDS(main->curves.first, ADT_RECALC_ANIM);
+ /* curves */
+ EVAL_ANIM_IDS(main->curves.first, ADT_RECALC_ANIM);
- /* armatures */
- EVAL_ANIM_IDS(main->armatures.first, ADT_RECALC_ANIM);
+ /* armatures */
+ EVAL_ANIM_IDS(main->armatures.first, ADT_RECALC_ANIM);
- /* lattices */
- EVAL_ANIM_IDS(main->lattices.first, ADT_RECALC_ANIM);
+ /* lattices */
+ EVAL_ANIM_IDS(main->lattices.first, ADT_RECALC_ANIM);
- /* meshes */
- EVAL_ANIM_IDS(main->meshes.first, ADT_RECALC_ANIM);
+ /* meshes */
+ EVAL_ANIM_IDS(main->meshes.first, ADT_RECALC_ANIM);
- /* particles */
- EVAL_ANIM_IDS(main->particles.first, ADT_RECALC_ANIM);
+ /* particles */
+ EVAL_ANIM_IDS(main->particles.first, ADT_RECALC_ANIM);
- /* speakers */
- EVAL_ANIM_IDS(main->speakers.first, ADT_RECALC_ANIM);
+ /* speakers */
+ EVAL_ANIM_IDS(main->speakers.first, ADT_RECALC_ANIM);
- /* movie clips */
- EVAL_ANIM_IDS(main->movieclips.first, ADT_RECALC_ANIM);
+ /* movie clips */
+ EVAL_ANIM_IDS(main->movieclips.first, ADT_RECALC_ANIM);
- /* linestyles */
- EVAL_ANIM_IDS(main->linestyles.first, ADT_RECALC_ANIM);
+ /* linestyles */
+ EVAL_ANIM_IDS(main->linestyles.first, ADT_RECALC_ANIM);
- /* grease pencil */
- EVAL_ANIM_IDS(main->gpencils.first, ADT_RECALC_ANIM);
+ /* grease pencil */
+ EVAL_ANIM_IDS(main->gpencils.first, ADT_RECALC_ANIM);
- /* palettes */
- EVAL_ANIM_IDS(main->palettes.first, ADT_RECALC_ANIM);
+ /* palettes */
+ EVAL_ANIM_IDS(main->palettes.first, ADT_RECALC_ANIM);
- /* cache files */
- EVAL_ANIM_IDS(main->cachefiles.first, ADT_RECALC_ANIM);
+ /* cache files */
+ EVAL_ANIM_IDS(main->cachefiles.first, ADT_RECALC_ANIM);
- /* objects */
- /* ADT_RECALC_ANIM doesn't need to be supplied here, since object AnimData gets
- * this tagged by Depsgraph on framechange. This optimization means that objects
- * linked from other (not-visible) scenes will not need their data calculated.
- */
- EVAL_ANIM_IDS(main->objects.first, 0);
+ /* objects */
+ /* ADT_RECALC_ANIM doesn't need to be supplied here, since object AnimData gets
+ * this tagged by Depsgraph on framechange. This optimization means that objects
+ * linked from other (not-visible) scenes will not need their data calculated.
+ */
+ EVAL_ANIM_IDS(main->objects.first, 0);
- /* masks */
- EVAL_ANIM_IDS(main->masks.first, ADT_RECALC_ANIM);
+ /* masks */
+ EVAL_ANIM_IDS(main->masks.first, ADT_RECALC_ANIM);
- /* worlds */
- EVAL_ANIM_NODETREE_IDS(main->worlds.first, World, ADT_RECALC_ANIM);
+ /* worlds */
+ EVAL_ANIM_NODETREE_IDS(main->worlds.first, World, ADT_RECALC_ANIM);
- /* scenes */
- EVAL_ANIM_NODETREE_IDS(main->scenes.first, Scene, ADT_RECALC_ANIM);
+ /* scenes */
+ EVAL_ANIM_NODETREE_IDS(main->scenes.first, Scene, ADT_RECALC_ANIM);
}
/* ***************************************** */
@@ -3693,33 +3904,33 @@ void BKE_animsys_evaluate_all_animation(Main *main, Depsgraph *depsgraph, Scene
void BKE_animsys_eval_animdata(Depsgraph *depsgraph, ID *id)
{
- float ctime = DEG_get_ctime(depsgraph);
- AnimData *adt = BKE_animdata_from_id(id);
- Scene *scene = NULL; /* XXX: this is only needed for flushing RNA updates,
- * which should get handled as part of the dependency graph instead...
- */
- DEG_debug_print_eval_time(depsgraph, __func__, id->name, id, ctime);
- BKE_animsys_evaluate_animdata(depsgraph, scene, id, adt, ctime, ADT_RECALC_ANIM);
+ float ctime = DEG_get_ctime(depsgraph);
+ AnimData *adt = BKE_animdata_from_id(id);
+ Scene *scene = NULL; /* XXX: this is only needed for flushing RNA updates,
+ * which should get handled as part of the dependency graph instead...
+ */
+ DEG_debug_print_eval_time(depsgraph, __func__, id->name, id, ctime);
+ BKE_animsys_evaluate_animdata(depsgraph, scene, id, adt, ctime, ADT_RECALC_ANIM);
}
void BKE_animsys_update_driver_array(ID *id)
{
- AnimData *adt = BKE_animdata_from_id(id);
+ AnimData *adt = BKE_animdata_from_id(id);
- /* Runtime driver map to avoid O(n^2) lookups in BKE_animsys_eval_driver.
- * Ideally the depsgraph could pass a pointer to the COW driver directly,
- * but this is difficult in the current design. */
- if (adt && adt->drivers.first) {
- BLI_assert(!adt->driver_array);
+ /* Runtime driver map to avoid O(n^2) lookups in BKE_animsys_eval_driver.
+ * Ideally the depsgraph could pass a pointer to the COW driver directly,
+ * but this is difficult in the current design. */
+ if (adt && adt->drivers.first) {
+ BLI_assert(!adt->driver_array);
- int num_drivers = BLI_listbase_count(&adt->drivers);
- adt->driver_array = MEM_mallocN(sizeof(FCurve *) * num_drivers, "adt->driver_array");
+ int num_drivers = BLI_listbase_count(&adt->drivers);
+ adt->driver_array = MEM_mallocN(sizeof(FCurve *) * num_drivers, "adt->driver_array");
- int driver_index = 0;
- for (FCurve *fcu = adt->drivers.first; fcu; fcu = fcu->next) {
- adt->driver_array[driver_index++] = fcu;
- }
- }
+ int driver_index = 0;
+ for (FCurve *fcu = adt->drivers.first; fcu; fcu = fcu->next) {
+ adt->driver_array[driver_index++] = fcu;
+ }
+ }
}
void BKE_animsys_eval_driver(Depsgraph *depsgraph,
@@ -3727,74 +3938,71 @@ void BKE_animsys_eval_driver(Depsgraph *depsgraph,
int driver_index,
ChannelDriver *driver_orig)
{
- /* TODO(sergey): De-duplicate with BKE animsys. */
- PointerRNA id_ptr;
- bool ok = false;
-
- /* Lookup driver, accelerated with driver array map. */
- const AnimData *adt = BKE_animdata_from_id(id);
- FCurve *fcu;
-
- if (adt->driver_array) {
- fcu = adt->driver_array[driver_index];
- }
- else {
- fcu = BLI_findlink(&adt->drivers, driver_index);
- }
-
- DEG_debug_print_eval_subdata_index(
- depsgraph, __func__, id->name, id, "fcu", fcu->rna_path, fcu, fcu->array_index);
-
- RNA_id_pointer_create(id, &id_ptr);
-
- /* check if this driver's curve should be skipped */
- if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) {
- /* check if driver itself is tagged for recalculation */
- /* XXX driver recalc flag is not set yet by depsgraph! */
- if ((driver_orig) && !(driver_orig->flag & DRIVER_FLAG_INVALID)) {
- /* 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 */
- //printf("\told val = %f\n", fcu->curval);
-
- PathResolvedRNA anim_rna;
- if (animsys_store_rna_setting(&id_ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
- /* Evaluate driver, and write results to COW-domain destination */
- const float ctime = DEG_get_ctime(depsgraph);
- const float curval = evaluate_fcurve_driver(&anim_rna, fcu, driver_orig, ctime);
- ok = animsys_write_rna_setting(&anim_rna, curval);
-
- /* Flush results & status codes to original data for UI (T59984) */
- if (ok && DEG_is_active(depsgraph)) {
- animsys_write_orig_anim_rna(&id_ptr, fcu->rna_path, fcu->array_index, curval);
-
- /* curval is displayed in the UI, and flag contains error-status codes */
- driver_orig->curval = fcu->driver->curval;
- driver_orig->flag = fcu->driver->flag;
-
- DriverVar *dvar_orig = driver_orig->variables.first;
- DriverVar *dvar = fcu->driver->variables.first;
- for (;
- dvar_orig && dvar;
- dvar_orig = dvar_orig->next, dvar = dvar->next)
- {
- DriverTarget *dtar_orig = &dvar_orig->targets[0];
- DriverTarget *dtar = &dvar->targets[0];
- for (int i = 0; i < MAX_DRIVER_TARGETS; i++, dtar_orig++, dtar++) {
- dtar_orig->flag = dtar->flag;
- }
-
- dvar_orig->curval = dvar->curval;
- dvar_orig->flag = dvar->flag;
- }
- }
- }
-
- /* set error-flag if evaluation failed */
- if (ok == 0) {
- CLOG_ERROR(&LOG, "invalid driver - %s[%d]", fcu->rna_path, fcu->array_index);
- driver_orig->flag |= DRIVER_FLAG_INVALID;
- }
- }
- }
+ /* TODO(sergey): De-duplicate with BKE animsys. */
+ PointerRNA id_ptr;
+ bool ok = false;
+
+ /* Lookup driver, accelerated with driver array map. */
+ const AnimData *adt = BKE_animdata_from_id(id);
+ FCurve *fcu;
+
+ if (adt->driver_array) {
+ fcu = adt->driver_array[driver_index];
+ }
+ else {
+ fcu = BLI_findlink(&adt->drivers, driver_index);
+ }
+
+ DEG_debug_print_eval_subdata_index(
+ depsgraph, __func__, id->name, id, "fcu", fcu->rna_path, fcu, fcu->array_index);
+
+ RNA_id_pointer_create(id, &id_ptr);
+
+ /* check if this driver's curve should be skipped */
+ if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) {
+ /* check if driver itself is tagged for recalculation */
+ /* XXX driver recalc flag is not set yet by depsgraph! */
+ if ((driver_orig) && !(driver_orig->flag & DRIVER_FLAG_INVALID)) {
+ /* 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 */
+ //printf("\told val = %f\n", fcu->curval);
+
+ PathResolvedRNA anim_rna;
+ if (animsys_store_rna_setting(&id_ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
+ /* Evaluate driver, and write results to COW-domain destination */
+ const float ctime = DEG_get_ctime(depsgraph);
+ const float curval = evaluate_fcurve_driver(&anim_rna, fcu, driver_orig, ctime);
+ ok = animsys_write_rna_setting(&anim_rna, curval);
+
+ /* Flush results & status codes to original data for UI (T59984) */
+ if (ok && DEG_is_active(depsgraph)) {
+ animsys_write_orig_anim_rna(&id_ptr, fcu->rna_path, fcu->array_index, curval);
+
+ /* curval is displayed in the UI, and flag contains error-status codes */
+ driver_orig->curval = fcu->driver->curval;
+ driver_orig->flag = fcu->driver->flag;
+
+ DriverVar *dvar_orig = driver_orig->variables.first;
+ DriverVar *dvar = fcu->driver->variables.first;
+ for (; dvar_orig && dvar; dvar_orig = dvar_orig->next, dvar = dvar->next) {
+ DriverTarget *dtar_orig = &dvar_orig->targets[0];
+ DriverTarget *dtar = &dvar->targets[0];
+ for (int i = 0; i < MAX_DRIVER_TARGETS; i++, dtar_orig++, dtar++) {
+ dtar_orig->flag = dtar->flag;
+ }
+
+ dvar_orig->curval = dvar->curval;
+ dvar_orig->flag = dvar->flag;
+ }
+ }
+ }
+
+ /* set error-flag if evaluation failed */
+ if (ok == 0) {
+ CLOG_ERROR(&LOG, "invalid driver - %s[%d]", fcu->rna_path, fcu->array_index);
+ driver_orig->flag |= DRIVER_FLAG_INVALID;
+ }
+ }
+ }
}
diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index c8882be0dd0..5383138956e 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -32,7 +32,7 @@
#include "BLI_string.h"
#include "BKE_blender_version.h"
-#include "BKE_appdir.h" /* own include */
+#include "BKE_appdir.h" /* own include */
#include "GHOST_Path-api.h"
@@ -55,15 +55,15 @@
# ifdef WITH_BINRELOC
# include "binreloc.h"
# endif
-# include <unistd.h> /* mkdtemp on OSX (and probably all *BSD?), not worth making specific check for this OS. */
-#endif /* WIN32 */
+# include <unistd.h> /* mkdtemp on OSX (and probably all *BSD?), not worth making specific check for this OS. */
+#endif /* WIN32 */
/* local */
static CLG_LogRef LOG = {"bke.appdir"};
-static char bprogname[FILE_MAX]; /* full path to program executable */
-static char bprogdir[FILE_MAX]; /* full path to directory in which executable is located */
-static char btempdir_base[FILE_MAX]; /* persistent temporary directory */
-static char btempdir_session[FILE_MAX] = ""; /* volatile temporary directory */
+static char bprogname[FILE_MAX]; /* full path to program executable */
+static char bprogdir[FILE_MAX]; /* full path to directory in which executable is located */
+static char btempdir_base[FILE_MAX]; /* persistent temporary directory */
+static char btempdir_session[FILE_MAX] = ""; /* volatile temporary directory */
/* This is now only used to really get the user's default document folder */
/* On Windows I chose the 'Users/<MyUserName>/Documents' since it's used
@@ -71,88 +71,91 @@ static char btempdir_session[FILE_MAX] = ""; /* volatile temporary directory */
const char *BKE_appdir_folder_default(void)
{
#ifndef WIN32
- const char * const xdg_documents_dir = BLI_getenv("XDG_DOCUMENTS_DIR");
-
- if (xdg_documents_dir)
- return xdg_documents_dir;
-
- return BLI_getenv("HOME");
-#else /* Windows */
- static char documentfolder[MAXPATHLEN];
- HRESULT hResult;
-
- /* Check for %HOME% env var */
- if (uput_getenv("HOME", documentfolder, MAXPATHLEN)) {
- if (BLI_is_dir(documentfolder)) return documentfolder;
- }
-
- /* add user profile support for WIN 2K / NT.
- * This is %APPDATA%, which translates to either
- * %USERPROFILE%\Application Data or since Vista
- * to %USERPROFILE%\AppData\Roaming
- */
- hResult = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, documentfolder);
-
- if (hResult == S_OK) {
- if (BLI_is_dir(documentfolder)) return documentfolder;
- }
-
- return NULL;
+ const char *const xdg_documents_dir = BLI_getenv("XDG_DOCUMENTS_DIR");
+
+ if (xdg_documents_dir)
+ return xdg_documents_dir;
+
+ return BLI_getenv("HOME");
+#else /* Windows */
+ static char documentfolder[MAXPATHLEN];
+ HRESULT hResult;
+
+ /* Check for %HOME% env var */
+ if (uput_getenv("HOME", documentfolder, MAXPATHLEN)) {
+ if (BLI_is_dir(documentfolder))
+ return documentfolder;
+ }
+
+ /* add user profile support for WIN 2K / NT.
+ * This is %APPDATA%, which translates to either
+ * %USERPROFILE%\Application Data or since Vista
+ * to %USERPROFILE%\AppData\Roaming
+ */
+ hResult = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, documentfolder);
+
+ if (hResult == S_OK) {
+ if (BLI_is_dir(documentfolder))
+ return documentfolder;
+ }
+
+ return NULL;
#endif /* WIN32 */
}
-
// #define PATH_DEBUG
/* returns a formatted representation of the specified version number. Non-reentrant! */
static char *blender_version_decimal(const int ver)
{
- static char version_str[5];
- BLI_assert(ver < 1000);
- BLI_snprintf(version_str, sizeof(version_str), "%d.%02d", ver / 100, ver % 100);
- return version_str;
+ static char version_str[5];
+ BLI_assert(ver < 1000);
+ BLI_snprintf(version_str, sizeof(version_str), "%d.%02d", ver / 100, ver % 100);
+ return version_str;
}
/**
* Concatenates path_base, (optional) path_sep and (optional) folder_name into targetpath,
* returning true if result points to a directory.
*/
-static bool test_path(
- char *targetpath, size_t targetpath_len,
- const char *path_base, const char *path_sep, const char *folder_name)
+static bool test_path(char *targetpath,
+ size_t targetpath_len,
+ const char *path_base,
+ const char *path_sep,
+ const char *folder_name)
{
- char tmppath[FILE_MAX];
-
- if (path_sep) {
- BLI_join_dirfile(tmppath, sizeof(tmppath), path_base, path_sep);
- }
- else {
- BLI_strncpy(tmppath, path_base, sizeof(tmppath));
- }
-
- /* rare cases folder_name is omitted (when looking for ~/.config/blender/2.xx dir only) */
- if (folder_name) {
- BLI_join_dirfile(targetpath, targetpath_len, tmppath, folder_name);
- }
- else {
- BLI_strncpy(targetpath, tmppath, targetpath_len);
- }
- /* FIXME: why is "//" on front of tmppath expanded to "/" (by BLI_join_dirfile)
- * if folder_name is specified but not otherwise? */
-
- if (BLI_is_dir(targetpath)) {
+ char tmppath[FILE_MAX];
+
+ if (path_sep) {
+ BLI_join_dirfile(tmppath, sizeof(tmppath), path_base, path_sep);
+ }
+ else {
+ BLI_strncpy(tmppath, path_base, sizeof(tmppath));
+ }
+
+ /* rare cases folder_name is omitted (when looking for ~/.config/blender/2.xx dir only) */
+ if (folder_name) {
+ BLI_join_dirfile(targetpath, targetpath_len, tmppath, folder_name);
+ }
+ else {
+ BLI_strncpy(targetpath, tmppath, targetpath_len);
+ }
+ /* FIXME: why is "//" on front of tmppath expanded to "/" (by BLI_join_dirfile)
+ * if folder_name is specified but not otherwise? */
+
+ if (BLI_is_dir(targetpath)) {
#ifdef PATH_DEBUG
- printf("\t%s found: %s\n", __func__, targetpath);
+ printf("\t%s found: %s\n", __func__, targetpath);
#endif
- return true;
- }
- else {
+ return true;
+ }
+ else {
#ifdef PATH_DEBUG
- printf("\t%s missing: %s\n", __func__, targetpath);
+ printf("\t%s missing: %s\n", __func__, targetpath);
#endif
- //targetpath[0] = '\0';
- return false;
- }
+ //targetpath[0] = '\0';
+ return false;
+ }
}
/**
@@ -161,23 +164,24 @@ static bool test_path(
*/
static bool test_env_path(char *path, const char *envvar)
{
- const char *env = envvar ? BLI_getenv(envvar) : NULL;
- if (!env) return false;
+ const char *env = envvar ? BLI_getenv(envvar) : NULL;
+ if (!env)
+ return false;
- if (BLI_is_dir(env)) {
- BLI_strncpy(path, env, FILE_MAX);
+ if (BLI_is_dir(env)) {
+ BLI_strncpy(path, env, FILE_MAX);
#ifdef PATH_DEBUG
- printf("\t%s env %s found: %s\n", __func__, envvar, env);
+ printf("\t%s env %s found: %s\n", __func__, envvar, env);
#endif
- return true;
- }
- else {
- path[0] = '\0';
+ return true;
+ }
+ else {
+ path[0] = '\0';
#ifdef PATH_DEBUG
- printf("\t%s env %s missing: %s\n", __func__, envvar, env);
+ printf("\t%s env %s missing: %s\n", __func__, envvar, env);
#endif
- return false;
- }
+ return false;
+ }
}
/**
@@ -190,38 +194,41 @@ static bool test_env_path(char *path, const char *envvar)
* \param ver: To construct name of version-specific directory within bprogdir
* \return true if such a directory exists.
*/
-static bool get_path_local(
- char *targetpath, size_t targetpath_len,
- const char *folder_name, const char *subfolder_name, const int ver)
+static bool get_path_local(char *targetpath,
+ size_t targetpath_len,
+ const char *folder_name,
+ const char *subfolder_name,
+ const int ver)
{
- char relfolder[FILE_MAX];
+ char relfolder[FILE_MAX];
#ifdef PATH_DEBUG
- printf("%s...\n", __func__);
+ printf("%s...\n", __func__);
#endif
- if (folder_name) {
- if (subfolder_name) {
- BLI_join_dirfile(relfolder, sizeof(relfolder), folder_name, subfolder_name);
- }
- else {
- BLI_strncpy(relfolder, folder_name, sizeof(relfolder));
- }
- }
- else {
- relfolder[0] = '\0';
- }
-
- /* try EXECUTABLE_DIR/2.5x/folder_name - new default directory for local blender installed files */
+ if (folder_name) {
+ if (subfolder_name) {
+ BLI_join_dirfile(relfolder, sizeof(relfolder), folder_name, subfolder_name);
+ }
+ else {
+ BLI_strncpy(relfolder, folder_name, sizeof(relfolder));
+ }
+ }
+ else {
+ relfolder[0] = '\0';
+ }
+
+ /* try EXECUTABLE_DIR/2.5x/folder_name - new default directory for local blender installed files */
#ifdef __APPLE__
- /* due new codesign situation in OSX > 10.9.5 we must move the blender_version dir with contents to Resources */
- char osx_resourses[FILE_MAX];
- BLI_snprintf(osx_resourses, sizeof(osx_resourses), "%s../Resources", bprogdir);
- /* Remove the '/../' added above. */
- BLI_cleanup_path(NULL, osx_resourses);
- return test_path(targetpath, targetpath_len, osx_resourses, blender_version_decimal(ver), relfolder);
+ /* due new codesign situation in OSX > 10.9.5 we must move the blender_version dir with contents to Resources */
+ char osx_resourses[FILE_MAX];
+ BLI_snprintf(osx_resourses, sizeof(osx_resourses), "%s../Resources", bprogdir);
+ /* Remove the '/../' added above. */
+ BLI_cleanup_path(NULL, osx_resourses);
+ return test_path(
+ targetpath, targetpath_len, osx_resourses, blender_version_decimal(ver), relfolder);
#else
- return test_path(targetpath, targetpath_len, bprogdir, blender_version_decimal(ver), relfolder);
+ return test_path(targetpath, targetpath_len, bprogdir, blender_version_decimal(ver), relfolder);
#endif
}
@@ -231,11 +238,11 @@ static bool get_path_local(
*/
bool BKE_appdir_app_is_portable_install(void)
{
- /* detect portable install by the existence of config folder */
- const int ver = BLENDER_VERSION;
- char path[FILE_MAX];
+ /* detect portable install by the existence of config folder */
+ const int ver = BLENDER_VERSION;
+ char path[FILE_MAX];
- return get_path_local(path, sizeof(path), "config", NULL, ver);
+ return get_path_local(path, sizeof(path), "config", NULL, ver);
}
/**
@@ -246,29 +253,23 @@ bool BKE_appdir_app_is_portable_install(void)
* \param envvar: name of environment variable to check folder_name.
* \return true if it was able to construct such a path and the path exists.
*/
-static bool get_path_environment(
- char *targetpath,
- size_t targetpath_len,
- const char *subfolder_name,
- const char *envvar)
+static bool get_path_environment(char *targetpath,
+ size_t targetpath_len,
+ const char *subfolder_name,
+ const char *envvar)
{
- char user_path[FILE_MAX];
-
- if (test_env_path(user_path, envvar)) {
- if (subfolder_name) {
- return test_path(
- targetpath,
- targetpath_len,
- user_path,
- NULL,
- subfolder_name);
- }
- else {
- BLI_strncpy(targetpath, user_path, FILE_MAX);
- return true;
- }
- }
- return false;
+ char user_path[FILE_MAX];
+
+ if (test_env_path(user_path, envvar)) {
+ if (subfolder_name) {
+ return test_path(targetpath, targetpath_len, user_path, NULL, subfolder_name);
+ }
+ else {
+ BLI_strncpy(targetpath, user_path, FILE_MAX);
+ return true;
+ }
+ }
+ return false;
}
/**
@@ -279,25 +280,24 @@ static bool get_path_environment(
* \param envvar: name of environment variable to check folder_name.
* \return true if it was able to construct such a path.
*/
-static bool get_path_environment_notest(
- char *targetpath,
- size_t targetpath_len,
- const char *subfolder_name,
- const char *envvar)
+static bool get_path_environment_notest(char *targetpath,
+ size_t targetpath_len,
+ const char *subfolder_name,
+ const char *envvar)
{
- char user_path[FILE_MAX];
-
- if (test_env_path(user_path, envvar)) {
- if (subfolder_name) {
- BLI_join_dirfile(targetpath, targetpath_len, user_path, subfolder_name);
- return true;
- }
- else {
- BLI_strncpy(targetpath, user_path, FILE_MAX);
- return true;
- }
- }
- return false;
+ char user_path[FILE_MAX];
+
+ if (test_env_path(user_path, envvar)) {
+ if (subfolder_name) {
+ BLI_join_dirfile(targetpath, targetpath_len, user_path, subfolder_name);
+ return true;
+ }
+ else {
+ BLI_strncpy(targetpath, user_path, FILE_MAX);
+ return true;
+ }
+ }
+ return false;
}
/**
@@ -308,36 +308,38 @@ static bool get_path_environment_notest(
* \param ver: Blender version, used to construct a subdirectory name
* \return true if it was able to construct such a path.
*/
-static bool get_path_user(
- char *targetpath, size_t targetpath_len, const char *folder_name, const char *subfolder_name,
- const int ver)
+static bool get_path_user(char *targetpath,
+ size_t targetpath_len,
+ const char *folder_name,
+ const char *subfolder_name,
+ const int ver)
{
- char user_path[FILE_MAX];
- const char *user_base_path;
+ char user_path[FILE_MAX];
+ const char *user_base_path;
- /* for portable install, user path is always local */
- if (BKE_appdir_app_is_portable_install()) {
- return get_path_local(targetpath, targetpath_len, folder_name, subfolder_name, ver);
- }
- user_path[0] = '\0';
+ /* for portable install, user path is always local */
+ if (BKE_appdir_app_is_portable_install()) {
+ return get_path_local(targetpath, targetpath_len, folder_name, subfolder_name, ver);
+ }
+ user_path[0] = '\0';
- user_base_path = (const char *)GHOST_getUserDir(ver, blender_version_decimal(ver));
- if (user_base_path)
- BLI_strncpy(user_path, user_base_path, FILE_MAX);
+ user_base_path = (const char *)GHOST_getUserDir(ver, blender_version_decimal(ver));
+ if (user_base_path)
+ BLI_strncpy(user_path, user_base_path, FILE_MAX);
- if (!user_path[0])
- return false;
+ if (!user_path[0])
+ return false;
#ifdef PATH_DEBUG
- printf("%s: %s\n", __func__, user_path);
+ printf("%s: %s\n", __func__, user_path);
#endif
- if (subfolder_name) {
- return test_path(targetpath, targetpath_len, user_path, folder_name, subfolder_name);
- }
- else {
- return test_path(targetpath, targetpath_len, user_path, NULL, folder_name);
- }
+ if (subfolder_name) {
+ return test_path(targetpath, targetpath_len, user_path, folder_name, subfolder_name);
+ }
+ else {
+ return test_path(targetpath, targetpath_len, user_path, NULL, folder_name);
+ }
}
/**
@@ -349,46 +351,48 @@ static bool get_path_user(
* \param ver: Blender version, used to construct a subdirectory name
* \return true if it was able to construct such a path.
*/
-static bool get_path_system(
- char *targetpath, size_t targetpath_len, const char *folder_name, const char *subfolder_name,
- const int ver)
+static bool get_path_system(char *targetpath,
+ size_t targetpath_len,
+ const char *folder_name,
+ const char *subfolder_name,
+ const int ver)
{
- char system_path[FILE_MAX];
- const char *system_base_path;
- char relfolder[FILE_MAX];
-
- if (folder_name) {
- if (subfolder_name) {
- BLI_join_dirfile(relfolder, sizeof(relfolder), folder_name, subfolder_name);
- }
- else {
- BLI_strncpy(relfolder, folder_name, sizeof(relfolder));
- }
- }
- else {
- relfolder[0] = '\0';
- }
-
- system_path[0] = '\0';
- system_base_path = (const char *)GHOST_getSystemDir(ver, blender_version_decimal(ver));
- if (system_base_path)
- BLI_strncpy(system_path, system_base_path, FILE_MAX);
-
- if (!system_path[0])
- return false;
+ char system_path[FILE_MAX];
+ const char *system_base_path;
+ char relfolder[FILE_MAX];
+
+ if (folder_name) {
+ if (subfolder_name) {
+ BLI_join_dirfile(relfolder, sizeof(relfolder), folder_name, subfolder_name);
+ }
+ else {
+ BLI_strncpy(relfolder, folder_name, sizeof(relfolder));
+ }
+ }
+ else {
+ relfolder[0] = '\0';
+ }
+
+ system_path[0] = '\0';
+ system_base_path = (const char *)GHOST_getSystemDir(ver, blender_version_decimal(ver));
+ if (system_base_path)
+ BLI_strncpy(system_path, system_base_path, FILE_MAX);
+
+ if (!system_path[0])
+ return false;
#ifdef PATH_DEBUG
- printf("%s: %s\n", __func__, system_path);
+ printf("%s: %s\n", __func__, system_path);
#endif
- if (subfolder_name) {
- /* try $BLENDERPATH/folder_name/subfolder_name */
- return test_path(targetpath, targetpath_len, system_path, folder_name, subfolder_name);
- }
- else {
- /* try $BLENDERPATH/folder_name */
- return test_path(targetpath, targetpath_len, system_path, NULL, folder_name);
- }
+ if (subfolder_name) {
+ /* try $BLENDERPATH/folder_name/subfolder_name */
+ return test_path(targetpath, targetpath_len, system_path, folder_name, subfolder_name);
+ }
+ else {
+ /* try $BLENDERPATH/folder_name */
+ return test_path(targetpath, targetpath_len, system_path, NULL, folder_name);
+ }
}
/**
@@ -398,72 +402,94 @@ static bool get_path_system(
* \param subfolder: The name of a directory to check for,
* this may contain path separators but must resolve to a directory, checked with #BLI_is_dir.
*/
-const char *BKE_appdir_folder_id_ex(
- const int folder_id, const char *subfolder,
- char *path, size_t path_len)
+const char *BKE_appdir_folder_id_ex(const int folder_id,
+ const char *subfolder,
+ char *path,
+ size_t path_len)
{
- const int ver = BLENDER_VERSION;
-
- switch (folder_id) {
- case BLENDER_DATAFILES: /* general case */
- if (get_path_environment(path, path_len, subfolder, "BLENDER_USER_DATAFILES")) break;
- if (get_path_user(path, path_len, "datafiles", subfolder, ver)) break;
- if (get_path_environment(path, path_len, subfolder, "BLENDER_SYSTEM_DATAFILES")) break;
- if (get_path_local(path, path_len, "datafiles", subfolder, ver)) break;
- if (get_path_system(path, path_len, "datafiles", subfolder, ver)) break;
- return NULL;
-
- case BLENDER_USER_DATAFILES:
- if (get_path_environment(path, path_len, subfolder, "BLENDER_USER_DATAFILES")) break;
- if (get_path_user(path, path_len, "datafiles", subfolder, ver)) break;
- return NULL;
-
- case BLENDER_SYSTEM_DATAFILES:
- if (get_path_environment(path, path_len, subfolder, "BLENDER_SYSTEM_DATAFILES")) break;
- if (get_path_system(path, path_len, "datafiles", subfolder, ver)) break;
- if (get_path_local(path, path_len, "datafiles", subfolder, ver)) break;
- return NULL;
-
- case BLENDER_USER_AUTOSAVE:
- if (get_path_environment(path, path_len, subfolder, "BLENDER_USER_DATAFILES")) break;
- if (get_path_user(path, path_len, "autosave", subfolder, ver)) break;
- return NULL;
-
- case BLENDER_USER_CONFIG:
- if (get_path_environment(path, path_len, subfolder, "BLENDER_USER_CONFIG")) break;
- if (get_path_user(path, path_len, "config", subfolder, ver)) break;
- return NULL;
-
- case BLENDER_USER_SCRIPTS:
- if (get_path_environment(path, path_len, subfolder, "BLENDER_USER_SCRIPTS")) break;
- if (get_path_user(path, path_len, "scripts", subfolder, ver)) break;
- return NULL;
-
- case BLENDER_SYSTEM_SCRIPTS:
- if (get_path_environment(path, path_len, subfolder, "BLENDER_SYSTEM_SCRIPTS")) break;
- if (get_path_system(path, path_len, "scripts", subfolder, ver)) break;
- if (get_path_local(path, path_len, "scripts", subfolder, ver)) break;
- return NULL;
-
- case BLENDER_SYSTEM_PYTHON:
- if (get_path_environment(path, path_len, subfolder, "BLENDER_SYSTEM_PYTHON")) break;
- if (get_path_system(path, path_len, "python", subfolder, ver)) break;
- if (get_path_local(path, path_len, "python", subfolder, ver)) break;
- return NULL;
-
- default:
- BLI_assert(0);
- break;
- }
-
- return path;
+ const int ver = BLENDER_VERSION;
+
+ switch (folder_id) {
+ case BLENDER_DATAFILES: /* general case */
+ if (get_path_environment(path, path_len, subfolder, "BLENDER_USER_DATAFILES"))
+ break;
+ if (get_path_user(path, path_len, "datafiles", subfolder, ver))
+ break;
+ if (get_path_environment(path, path_len, subfolder, "BLENDER_SYSTEM_DATAFILES"))
+ break;
+ if (get_path_local(path, path_len, "datafiles", subfolder, ver))
+ break;
+ if (get_path_system(path, path_len, "datafiles", subfolder, ver))
+ break;
+ return NULL;
+
+ case BLENDER_USER_DATAFILES:
+ if (get_path_environment(path, path_len, subfolder, "BLENDER_USER_DATAFILES"))
+ break;
+ if (get_path_user(path, path_len, "datafiles", subfolder, ver))
+ break;
+ return NULL;
+
+ case BLENDER_SYSTEM_DATAFILES:
+ if (get_path_environment(path, path_len, subfolder, "BLENDER_SYSTEM_DATAFILES"))
+ break;
+ if (get_path_system(path, path_len, "datafiles", subfolder, ver))
+ break;
+ if (get_path_local(path, path_len, "datafiles", subfolder, ver))
+ break;
+ return NULL;
+
+ case BLENDER_USER_AUTOSAVE:
+ if (get_path_environment(path, path_len, subfolder, "BLENDER_USER_DATAFILES"))
+ break;
+ if (get_path_user(path, path_len, "autosave", subfolder, ver))
+ break;
+ return NULL;
+
+ case BLENDER_USER_CONFIG:
+ if (get_path_environment(path, path_len, subfolder, "BLENDER_USER_CONFIG"))
+ break;
+ if (get_path_user(path, path_len, "config", subfolder, ver))
+ break;
+ return NULL;
+
+ case BLENDER_USER_SCRIPTS:
+ if (get_path_environment(path, path_len, subfolder, "BLENDER_USER_SCRIPTS"))
+ break;
+ if (get_path_user(path, path_len, "scripts", subfolder, ver))
+ break;
+ return NULL;
+
+ case BLENDER_SYSTEM_SCRIPTS:
+ if (get_path_environment(path, path_len, subfolder, "BLENDER_SYSTEM_SCRIPTS"))
+ break;
+ if (get_path_system(path, path_len, "scripts", subfolder, ver))
+ break;
+ if (get_path_local(path, path_len, "scripts", subfolder, ver))
+ break;
+ return NULL;
+
+ case BLENDER_SYSTEM_PYTHON:
+ if (get_path_environment(path, path_len, subfolder, "BLENDER_SYSTEM_PYTHON"))
+ break;
+ if (get_path_system(path, path_len, "python", subfolder, ver))
+ break;
+ if (get_path_local(path, path_len, "python", subfolder, ver))
+ break;
+ return NULL;
+
+ default:
+ BLI_assert(0);
+ break;
+ }
+
+ return path;
}
-const char *BKE_appdir_folder_id(
- const int folder_id, const char *subfolder)
+const char *BKE_appdir_folder_id(const int folder_id, const char *subfolder)
{
- static char path[FILE_MAX] = "";
- return BKE_appdir_folder_id_ex(folder_id, subfolder, path, sizeof(path));
+ static char path[FILE_MAX] = "";
+ return BKE_appdir_folder_id_ex(folder_id, subfolder, path, sizeof(path));
}
/**
@@ -471,35 +497,39 @@ const char *BKE_appdir_folder_id(
*/
const char *BKE_appdir_folder_id_user_notest(const int folder_id, const char *subfolder)
{
- const int ver = BLENDER_VERSION;
- static char path[FILE_MAX] = "";
-
- switch (folder_id) {
- case BLENDER_USER_DATAFILES:
- if (get_path_environment_notest(path, sizeof(path), subfolder, "BLENDER_USER_DATAFILES")) break;
- get_path_user(path, sizeof(path), "datafiles", subfolder, ver);
- break;
- case BLENDER_USER_CONFIG:
- if (get_path_environment_notest(path, sizeof(path), subfolder, "BLENDER_USER_CONFIG")) break;
- get_path_user(path, sizeof(path), "config", subfolder, ver);
- break;
- case BLENDER_USER_AUTOSAVE:
- if (get_path_environment_notest(path, sizeof(path), subfolder, "BLENDER_USER_AUTOSAVE")) break;
- get_path_user(path, sizeof(path), "autosave", subfolder, ver);
- break;
- case BLENDER_USER_SCRIPTS:
- if (get_path_environment_notest(path, sizeof(path), subfolder, "BLENDER_USER_SCRIPTS")) break;
- get_path_user(path, sizeof(path), "scripts", subfolder, ver);
- break;
- default:
- BLI_assert(0);
- break;
- }
-
- if ('\0' == path[0]) {
- return NULL;
- }
- return path;
+ const int ver = BLENDER_VERSION;
+ static char path[FILE_MAX] = "";
+
+ switch (folder_id) {
+ case BLENDER_USER_DATAFILES:
+ if (get_path_environment_notest(path, sizeof(path), subfolder, "BLENDER_USER_DATAFILES"))
+ break;
+ get_path_user(path, sizeof(path), "datafiles", subfolder, ver);
+ break;
+ case BLENDER_USER_CONFIG:
+ if (get_path_environment_notest(path, sizeof(path), subfolder, "BLENDER_USER_CONFIG"))
+ break;
+ get_path_user(path, sizeof(path), "config", subfolder, ver);
+ break;
+ case BLENDER_USER_AUTOSAVE:
+ if (get_path_environment_notest(path, sizeof(path), subfolder, "BLENDER_USER_AUTOSAVE"))
+ break;
+ get_path_user(path, sizeof(path), "autosave", subfolder, ver);
+ break;
+ case BLENDER_USER_SCRIPTS:
+ if (get_path_environment_notest(path, sizeof(path), subfolder, "BLENDER_USER_SCRIPTS"))
+ break;
+ get_path_user(path, sizeof(path), "scripts", subfolder, ver);
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+
+ if ('\0' == path[0]) {
+ return NULL;
+ }
+ return path;
}
/**
@@ -507,20 +537,25 @@ const char *BKE_appdir_folder_id_user_notest(const int folder_id, const char *su
*/
const char *BKE_appdir_folder_id_create(const int folder_id, const char *subfolder)
{
- const char *path;
+ const char *path;
- /* only for user folders */
- if (!ELEM(folder_id, BLENDER_USER_DATAFILES, BLENDER_USER_CONFIG, BLENDER_USER_SCRIPTS, BLENDER_USER_AUTOSAVE))
- return NULL;
+ /* only for user folders */
+ if (!ELEM(folder_id,
+ BLENDER_USER_DATAFILES,
+ BLENDER_USER_CONFIG,
+ BLENDER_USER_SCRIPTS,
+ BLENDER_USER_AUTOSAVE))
+ return NULL;
- path = BKE_appdir_folder_id(folder_id, subfolder);
+ path = BKE_appdir_folder_id(folder_id, subfolder);
- if (!path) {
- path = BKE_appdir_folder_id_user_notest(folder_id, subfolder);
- if (path) BLI_dir_create_recursive(path);
- }
+ if (!path) {
+ path = BKE_appdir_folder_id_user_notest(folder_id, subfolder);
+ if (path)
+ BLI_dir_create_recursive(path);
+ }
- return path;
+ return path;
}
/**
@@ -529,37 +564,36 @@ const char *BKE_appdir_folder_id_create(const int folder_id, const char *subfold
*/
const char *BKE_appdir_folder_id_version(const int folder_id, const int ver, const bool do_check)
{
- static char path[FILE_MAX] = "";
- bool ok;
- switch (folder_id) {
- case BLENDER_RESOURCE_PATH_USER:
- ok = get_path_user(path, sizeof(path), NULL, NULL, ver);
- break;
- case BLENDER_RESOURCE_PATH_LOCAL:
- ok = get_path_local(path, sizeof(path), NULL, NULL, ver);
- break;
- case BLENDER_RESOURCE_PATH_SYSTEM:
- ok = get_path_system(path, sizeof(path), NULL, NULL, ver);
- break;
- default:
- path[0] = '\0'; /* in case do_check is false */
- ok = false;
- BLI_assert(!"incorrect ID");
- break;
- }
-
- if (!ok && do_check) {
- return NULL;
- }
-
- return path;
+ static char path[FILE_MAX] = "";
+ bool ok;
+ switch (folder_id) {
+ case BLENDER_RESOURCE_PATH_USER:
+ ok = get_path_user(path, sizeof(path), NULL, NULL, ver);
+ break;
+ case BLENDER_RESOURCE_PATH_LOCAL:
+ ok = get_path_local(path, sizeof(path), NULL, NULL, ver);
+ break;
+ case BLENDER_RESOURCE_PATH_SYSTEM:
+ ok = get_path_system(path, sizeof(path), NULL, NULL, ver);
+ break;
+ default:
+ path[0] = '\0'; /* in case do_check is false */
+ ok = false;
+ BLI_assert(!"incorrect ID");
+ break;
+ }
+
+ if (!ok && do_check) {
+ return NULL;
+ }
+
+ return path;
}
#ifdef PATH_DEBUG
# undef PATH_DEBUG
#endif
-
/* -------------------------------------------------------------------- */
/* Preset paths */
@@ -578,70 +612,71 @@ const char *BKE_appdir_folder_id_version(const int folder_id, const int ver, con
static void where_am_i(char *fullname, const size_t maxlen, const char *name)
{
#ifdef WITH_BINRELOC
- /* linux uses binreloc since argv[0] is not reliable, call br_init( NULL ) first */
- {
- const char *path = NULL;
- path = br_find_exe(NULL);
- if (path) {
- BLI_strncpy(fullname, path, maxlen);
- free((void *)path);
- return;
- }
- }
+ /* linux uses binreloc since argv[0] is not reliable, call br_init( NULL ) first */
+ {
+ const char *path = NULL;
+ path = br_find_exe(NULL);
+ if (path) {
+ BLI_strncpy(fullname, path, maxlen);
+ free((void *)path);
+ return;
+ }
+ }
#endif
#ifdef _WIN32
- {
- wchar_t *fullname_16 = MEM_mallocN(maxlen * sizeof(wchar_t), "ProgramPath");
- if (GetModuleFileNameW(0, fullname_16, maxlen)) {
- conv_utf_16_to_8(fullname_16, fullname, maxlen);
- if (!BLI_exists(fullname)) {
- CLOG_ERROR(&LOG, "path can't be found: \"%.*s\"", (int)maxlen, fullname);
- MessageBox(NULL, "path contains invalid characters or is too long (see console)", "Error", MB_OK);
- }
- MEM_freeN(fullname_16);
- return;
- }
-
- MEM_freeN(fullname_16);
- }
+ {
+ wchar_t *fullname_16 = MEM_mallocN(maxlen * sizeof(wchar_t), "ProgramPath");
+ if (GetModuleFileNameW(0, fullname_16, maxlen)) {
+ conv_utf_16_to_8(fullname_16, fullname, maxlen);
+ if (!BLI_exists(fullname)) {
+ CLOG_ERROR(&LOG, "path can't be found: \"%.*s\"", (int)maxlen, fullname);
+ MessageBox(
+ NULL, "path contains invalid characters or is too long (see console)", "Error", MB_OK);
+ }
+ MEM_freeN(fullname_16);
+ return;
+ }
+
+ MEM_freeN(fullname_16);
+ }
#endif
- /* unix and non linux */
- if (name && name[0]) {
+ /* unix and non linux */
+ if (name && name[0]) {
- BLI_strncpy(fullname, name, maxlen);
- if (name[0] == '.') {
- BLI_path_cwd(fullname, maxlen);
+ BLI_strncpy(fullname, name, maxlen);
+ if (name[0] == '.') {
+ BLI_path_cwd(fullname, maxlen);
#ifdef _WIN32
- BLI_path_program_extensions_add_win32(fullname, maxlen);
+ BLI_path_program_extensions_add_win32(fullname, maxlen);
#endif
- }
- else if (BLI_last_slash(name)) {
- // full path
- BLI_strncpy(fullname, name, maxlen);
+ }
+ else if (BLI_last_slash(name)) {
+ // full path
+ BLI_strncpy(fullname, name, maxlen);
#ifdef _WIN32
- BLI_path_program_extensions_add_win32(fullname, maxlen);
+ BLI_path_program_extensions_add_win32(fullname, maxlen);
#endif
- }
- else {
- BLI_path_program_search(fullname, maxlen, name);
- }
- /* Remove "/./" and "/../" so string comparisons can be used on the path. */
- BLI_cleanup_path(NULL, fullname);
+ }
+ else {
+ BLI_path_program_search(fullname, maxlen, name);
+ }
+ /* Remove "/./" and "/../" so string comparisons can be used on the path. */
+ BLI_cleanup_path(NULL, fullname);
#if defined(DEBUG)
- if (!STREQ(name, fullname)) {
- CLOG_INFO(&LOG, 2, "guessing '%s' == '%s'", name, fullname);
- }
+ if (!STREQ(name, fullname)) {
+ CLOG_INFO(&LOG, 2, "guessing '%s' == '%s'", name, fullname);
+ }
#endif
- }
+ }
}
void BKE_appdir_program_path_init(const char *argv0)
{
- where_am_i(bprogname, sizeof(bprogname), argv0);
- BLI_split_dir_part(bprogname, bprogdir, sizeof(bprogdir));
+ where_am_i(bprogname, sizeof(bprogname), argv0);
+ BLI_split_dir_part(bprogname, bprogdir, sizeof(bprogdir));
}
/**
@@ -649,7 +684,7 @@ void BKE_appdir_program_path_init(const char *argv0)
*/
const char *BKE_appdir_program_path(void)
{
- return bprogname;
+ return bprogname;
}
/**
@@ -657,82 +692,82 @@ const char *BKE_appdir_program_path(void)
*/
const char *BKE_appdir_program_dir(void)
{
- return bprogdir;
+ return bprogdir;
}
-bool BKE_appdir_program_python_search(
- char *fullpath, const size_t fullpath_len,
- const int version_major, const int version_minor)
+bool BKE_appdir_program_python_search(char *fullpath,
+ const size_t fullpath_len,
+ const int version_major,
+ const int version_minor)
{
#ifdef PYTHON_EXECUTABLE_NAME
- /* passed in from the build-systems 'PYTHON_EXECUTABLE' */
- const char *python_build_def = STRINGIFY(PYTHON_EXECUTABLE_NAME);
+ /* passed in from the build-systems 'PYTHON_EXECUTABLE' */
+ const char *python_build_def = STRINGIFY(PYTHON_EXECUTABLE_NAME);
#endif
- const char *basename = "python";
- char python_ver[16];
- /* check both possible names */
- const char *python_names[] = {
+ const char *basename = "python";
+ char python_ver[16];
+ /* check both possible names */
+ const char *python_names[] = {
#ifdef PYTHON_EXECUTABLE_NAME
- python_build_def,
+ python_build_def,
#endif
- python_ver,
- basename,
- };
- int i;
+ python_ver,
+ basename,
+ };
+ int i;
- bool is_found = false;
+ bool is_found = false;
- BLI_snprintf(python_ver, sizeof(python_ver), "%s%d.%d", basename, version_major, version_minor);
+ BLI_snprintf(python_ver, sizeof(python_ver), "%s%d.%d", basename, version_major, version_minor);
- {
- const char *python_bin_dir = BKE_appdir_folder_id(BLENDER_SYSTEM_PYTHON, "bin");
- if (python_bin_dir) {
+ {
+ const char *python_bin_dir = BKE_appdir_folder_id(BLENDER_SYSTEM_PYTHON, "bin");
+ if (python_bin_dir) {
- for (i = 0; i < ARRAY_SIZE(python_names); i++) {
- BLI_join_dirfile(fullpath, fullpath_len, python_bin_dir, python_names[i]);
+ for (i = 0; i < ARRAY_SIZE(python_names); i++) {
+ BLI_join_dirfile(fullpath, fullpath_len, python_bin_dir, python_names[i]);
- if (
+ if (
#ifdef _WIN32
- BLI_path_program_extensions_add_win32(fullpath, fullpath_len)
+ BLI_path_program_extensions_add_win32(fullpath, fullpath_len)
#else
- BLI_exists(fullpath)
+ BLI_exists(fullpath)
#endif
- )
- {
- is_found = true;
- break;
- }
- }
- }
- }
-
- if (is_found == false) {
- for (i = 0; i < ARRAY_SIZE(python_names); i++) {
- if (BLI_path_program_search(fullpath, fullpath_len, python_names[i])) {
- is_found = true;
- break;
- }
- }
- }
-
- if (is_found == false) {
- *fullpath = '\0';
- }
-
- return is_found;
+ ) {
+ is_found = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (is_found == false) {
+ for (i = 0; i < ARRAY_SIZE(python_names); i++) {
+ if (BLI_path_program_search(fullpath, fullpath_len, python_names[i])) {
+ is_found = true;
+ break;
+ }
+ }
+ }
+
+ if (is_found == false) {
+ *fullpath = '\0';
+ }
+
+ return is_found;
}
/** Keep in sync with `bpy.utils.app_template_paths()` */
static const char *app_template_directory_search[2] = {
- "startup" SEP_STR "bl_app_templates_user",
- "startup" SEP_STR "bl_app_templates_system",
+ "startup" SEP_STR "bl_app_templates_user",
+ "startup" SEP_STR "bl_app_templates_system",
};
static const int app_template_directory_id[2] = {
- /* Only 'USER' */
- BLENDER_USER_SCRIPTS,
- /* Covers 'LOCAL' & 'SYSTEM'. */
- BLENDER_SYSTEM_SCRIPTS,
+ /* Only 'USER' */
+ BLENDER_USER_SCRIPTS,
+ /* Covers 'LOCAL' & 'SYSTEM'. */
+ BLENDER_SYSTEM_SCRIPTS,
};
/**
@@ -740,57 +775,54 @@ static const int app_template_directory_id[2] = {
*/
bool BKE_appdir_app_template_any(void)
{
- char temp_dir[FILE_MAX];
- for (int i = 0; i < 2; i++) {
- if (BKE_appdir_folder_id_ex(
- app_template_directory_id[i], app_template_directory_search[i],
- temp_dir, sizeof(temp_dir)))
- {
- return true;
- }
- }
- return false;
+ char temp_dir[FILE_MAX];
+ for (int i = 0; i < 2; i++) {
+ if (BKE_appdir_folder_id_ex(app_template_directory_id[i],
+ app_template_directory_search[i],
+ temp_dir,
+ sizeof(temp_dir))) {
+ return true;
+ }
+ }
+ return false;
}
bool BKE_appdir_app_template_id_search(const char *app_template, char *path, size_t path_len)
{
- for (int i = 0; i < 2; i++) {
- char subdir[FILE_MAX];
- BLI_join_dirfile(subdir, sizeof(subdir), app_template_directory_search[i], app_template);
- if (BKE_appdir_folder_id_ex(
- app_template_directory_id[i], subdir,
- path, path_len))
- {
- return true;
- }
- }
- return false;
+ for (int i = 0; i < 2; i++) {
+ char subdir[FILE_MAX];
+ BLI_join_dirfile(subdir, sizeof(subdir), app_template_directory_search[i], app_template);
+ if (BKE_appdir_folder_id_ex(app_template_directory_id[i], subdir, path, path_len)) {
+ return true;
+ }
+ }
+ return false;
}
void BKE_appdir_app_templates(ListBase *templates)
{
- BLI_listbase_clear(templates);
-
- for (int i = 0; i < 2; i++) {
- char subdir[FILE_MAX];
- if (!BKE_appdir_folder_id_ex(
- app_template_directory_id[i], app_template_directory_search[i],
- subdir, sizeof(subdir)))
- {
- continue;
- }
-
- struct direntry *dir;
- uint totfile = BLI_filelist_dir_contents(subdir, &dir);
- for (int f = 0; f < totfile; f++) {
- if (!FILENAME_IS_CURRPAR(dir[f].relname) && S_ISDIR(dir[f].type)) {
- char *template = BLI_strdup(dir[f].relname);
- BLI_addtail(templates, BLI_genericNodeN(template));
- }
- }
-
- BLI_filelist_free(dir, totfile);
- }
+ BLI_listbase_clear(templates);
+
+ for (int i = 0; i < 2; i++) {
+ char subdir[FILE_MAX];
+ if (!BKE_appdir_folder_id_ex(app_template_directory_id[i],
+ app_template_directory_search[i],
+ subdir,
+ sizeof(subdir))) {
+ continue;
+ }
+
+ struct direntry *dir;
+ uint totfile = BLI_filelist_dir_contents(subdir, &dir);
+ for (int f = 0; f < totfile; f++) {
+ if (!FILENAME_IS_CURRPAR(dir[f].relname) && S_ISDIR(dir[f].type)) {
+ char *template = BLI_strdup(dir[f].relname);
+ BLI_addtail(templates, BLI_genericNodeN(template));
+ }
+ }
+
+ BLI_filelist_free(dir, totfile);
+ }
}
/**
@@ -806,84 +838,86 @@ void BKE_appdir_app_templates(ListBase *templates)
*/
static void where_is_temp(char *fullname, char *basename, const size_t maxlen, char *userdir)
{
- /* Clear existing temp dir, if needed. */
- BKE_tempdir_session_purge();
-
- fullname[0] = '\0';
- if (basename) {
- basename[0] = '\0';
- }
+ /* Clear existing temp dir, if needed. */
+ BKE_tempdir_session_purge();
- if (userdir && BLI_is_dir(userdir)) {
- BLI_strncpy(fullname, userdir, maxlen);
- }
+ fullname[0] = '\0';
+ if (basename) {
+ basename[0] = '\0';
+ }
+ if (userdir && BLI_is_dir(userdir)) {
+ BLI_strncpy(fullname, userdir, maxlen);
+ }
#ifdef WIN32
- if (fullname[0] == '\0') {
- const char *tmp = BLI_getenv("TEMP"); /* Windows */
- if (tmp && BLI_is_dir(tmp)) {
- BLI_strncpy(fullname, tmp, maxlen);
- }
- }
+ if (fullname[0] == '\0') {
+ const char *tmp = BLI_getenv("TEMP"); /* Windows */
+ if (tmp && BLI_is_dir(tmp)) {
+ BLI_strncpy(fullname, tmp, maxlen);
+ }
+ }
#else
- /* Other OS's - Try TMP and TMPDIR */
- if (fullname[0] == '\0') {
- const char *tmp = BLI_getenv("TMP");
- if (tmp && BLI_is_dir(tmp)) {
- BLI_strncpy(fullname, tmp, maxlen);
- }
- }
-
- if (fullname[0] == '\0') {
- const char *tmp = BLI_getenv("TMPDIR");
- if (tmp && BLI_is_dir(tmp)) {
- BLI_strncpy(fullname, tmp, maxlen);
- }
- }
+ /* Other OS's - Try TMP and TMPDIR */
+ if (fullname[0] == '\0') {
+ const char *tmp = BLI_getenv("TMP");
+ if (tmp && BLI_is_dir(tmp)) {
+ BLI_strncpy(fullname, tmp, maxlen);
+ }
+ }
+
+ if (fullname[0] == '\0') {
+ const char *tmp = BLI_getenv("TMPDIR");
+ if (tmp && BLI_is_dir(tmp)) {
+ BLI_strncpy(fullname, tmp, maxlen);
+ }
+ }
#endif
- if (fullname[0] == '\0') {
- BLI_strncpy(fullname, "/tmp/", maxlen);
- }
- else {
- /* add a trailing slash if needed */
- BLI_add_slash(fullname);
+ if (fullname[0] == '\0') {
+ BLI_strncpy(fullname, "/tmp/", maxlen);
+ }
+ else {
+ /* add a trailing slash if needed */
+ BLI_add_slash(fullname);
#ifdef WIN32
- if (userdir && userdir != fullname) {
- /* also set user pref to show %TEMP%. /tmp/ is just plain confusing for Windows users. */
- BLI_strncpy(userdir, fullname, maxlen);
- }
+ if (userdir && userdir != fullname) {
+ /* also set user pref to show %TEMP%. /tmp/ is just plain confusing for Windows users. */
+ BLI_strncpy(userdir, fullname, maxlen);
+ }
#endif
- }
-
- /* Now that we have a valid temp dir, add system-generated unique sub-dir. */
- if (basename) {
- /* 'XXXXXX' is kind of tag to be replaced by mktemp-familly by an uuid. */
- char *tmp_name = BLI_strdupcat(fullname, "blender_XXXXXX");
- const size_t ln = strlen(tmp_name) + 1;
- if (ln <= maxlen) {
+ }
+
+ /* Now that we have a valid temp dir, add system-generated unique sub-dir. */
+ if (basename) {
+ /* 'XXXXXX' is kind of tag to be replaced by mktemp-familly by an uuid. */
+ char *tmp_name = BLI_strdupcat(fullname, "blender_XXXXXX");
+ const size_t ln = strlen(tmp_name) + 1;
+ if (ln <= maxlen) {
#ifdef WIN32
- if (_mktemp_s(tmp_name, ln) == 0) {
- BLI_dir_create_recursive(tmp_name);
- }
+ if (_mktemp_s(tmp_name, ln) == 0) {
+ BLI_dir_create_recursive(tmp_name);
+ }
#else
- if (mkdtemp(tmp_name) == NULL) {
- BLI_dir_create_recursive(tmp_name);
- }
+ if (mkdtemp(tmp_name) == NULL) {
+ BLI_dir_create_recursive(tmp_name);
+ }
#endif
- }
- if (BLI_is_dir(tmp_name)) {
- BLI_strncpy(basename, fullname, maxlen);
- BLI_strncpy(fullname, tmp_name, maxlen);
- BLI_add_slash(fullname);
- }
- else {
- CLOG_WARN(&LOG, "Could not generate a temp file name for '%s', falling back to '%s'", tmp_name, fullname);
- }
-
- MEM_freeN(tmp_name);
- }
+ }
+ if (BLI_is_dir(tmp_name)) {
+ BLI_strncpy(basename, fullname, maxlen);
+ BLI_strncpy(fullname, tmp_name, maxlen);
+ BLI_add_slash(fullname);
+ }
+ else {
+ CLOG_WARN(&LOG,
+ "Could not generate a temp file name for '%s', falling back to '%s'",
+ tmp_name,
+ fullname);
+ }
+
+ MEM_freeN(tmp_name);
+ }
}
/**
@@ -895,7 +929,7 @@ static void where_is_temp(char *fullname, char *basename, const size_t maxlen, c
*/
void BKE_tempdir_init(char *userdir)
{
- where_is_temp(btempdir_session, btempdir_base, FILE_MAX, userdir);
+ where_is_temp(btempdir_session, btempdir_base, FILE_MAX, userdir);
}
/**
@@ -903,7 +937,7 @@ void BKE_tempdir_init(char *userdir)
*/
const char *BKE_tempdir_session(void)
{
- return btempdir_session[0] ? btempdir_session : BKE_tempdir_base();
+ return btempdir_session[0] ? btempdir_session : BKE_tempdir_base();
}
/**
@@ -911,7 +945,7 @@ const char *BKE_tempdir_session(void)
*/
const char *BKE_tempdir_base(void)
{
- return btempdir_base;
+ return btempdir_base;
}
/**
@@ -919,7 +953,7 @@ const char *BKE_tempdir_base(void)
*/
void BKE_tempdir_system_init(char *dir)
{
- where_is_temp(dir, NULL, FILE_MAX, NULL);
+ where_is_temp(dir, NULL, FILE_MAX, NULL);
}
/**
@@ -927,7 +961,7 @@ void BKE_tempdir_system_init(char *dir)
*/
void BKE_tempdir_session_purge(void)
{
- if (btempdir_session[0] && BLI_is_dir(btempdir_session)) {
- BLI_delete(btempdir_session, true, true);
- }
+ if (btempdir_session[0] && BLI_is_dir(btempdir_session)) {
+ BLI_delete(btempdir_session, true, true);
+ }
}
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 1b9e6dcdbc4..69721651a45 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -78,92 +78,94 @@ static CLG_LogRef LOG = {"bke.armature"};
bArmature *BKE_armature_add(Main *bmain, const char *name)
{
- bArmature *arm;
+ bArmature *arm;
- arm = BKE_libblock_alloc(bmain, ID_AR, name, 0);
- arm->deformflag = ARM_DEF_VGROUP | ARM_DEF_ENVELOPE;
- arm->flag = ARM_COL_CUSTOM; /* custom bone-group colors */
- arm->layer = 1;
- return arm;
+ arm = BKE_libblock_alloc(bmain, ID_AR, name, 0);
+ arm->deformflag = ARM_DEF_VGROUP | ARM_DEF_ENVELOPE;
+ arm->flag = ARM_COL_CUSTOM; /* custom bone-group colors */
+ arm->layer = 1;
+ return arm;
}
bArmature *BKE_armature_from_object(Object *ob)
{
- if (ob->type == OB_ARMATURE)
- return (bArmature *)ob->data;
- return NULL;
+ if (ob->type == OB_ARMATURE)
+ return (bArmature *)ob->data;
+ return NULL;
}
int BKE_armature_bonelist_count(ListBase *lb)
{
- int i = 0;
- for (Bone *bone = lb->first; bone; bone = bone->next) {
- i += 1 + BKE_armature_bonelist_count(&bone->childbase);
- }
+ int i = 0;
+ for (Bone *bone = lb->first; bone; bone = bone->next) {
+ i += 1 + BKE_armature_bonelist_count(&bone->childbase);
+ }
- return i;
+ return i;
}
void BKE_armature_bonelist_free(ListBase *lb)
{
- Bone *bone;
+ Bone *bone;
- for (bone = lb->first; bone; bone = bone->next) {
- if (bone->prop) {
- IDP_FreeProperty(bone->prop);
- MEM_freeN(bone->prop);
- }
- BKE_armature_bonelist_free(&bone->childbase);
- }
+ for (bone = lb->first; bone; bone = bone->next) {
+ if (bone->prop) {
+ IDP_FreeProperty(bone->prop);
+ MEM_freeN(bone->prop);
+ }
+ BKE_armature_bonelist_free(&bone->childbase);
+ }
- BLI_freelistN(lb);
+ BLI_freelistN(lb);
}
/** Free (or release) any data used by this armature (does not free the armature itself). */
void BKE_armature_free(bArmature *arm)
{
- BKE_animdata_free(&arm->id, false);
+ BKE_animdata_free(&arm->id, false);
- BKE_armature_bonelist_free(&arm->bonebase);
+ BKE_armature_bonelist_free(&arm->bonebase);
- /* free editmode data */
- if (arm->edbo) {
- BLI_freelistN(arm->edbo);
+ /* free editmode data */
+ if (arm->edbo) {
+ BLI_freelistN(arm->edbo);
- MEM_freeN(arm->edbo);
- arm->edbo = NULL;
- }
+ MEM_freeN(arm->edbo);
+ arm->edbo = NULL;
+ }
}
void BKE_armature_make_local(Main *bmain, bArmature *arm, const bool lib_local)
{
- BKE_id_make_local_generic(bmain, &arm->id, true, lib_local);
+ BKE_id_make_local_generic(bmain, &arm->id, true, lib_local);
}
-static void copy_bonechildren(
- Bone *bone_dst, const Bone *bone_src, const Bone *bone_src_act, Bone **r_bone_dst_act, const int flag)
+static void copy_bonechildren(Bone *bone_dst,
+ const Bone *bone_src,
+ const Bone *bone_src_act,
+ Bone **r_bone_dst_act,
+ const int flag)
{
- Bone *bone_src_child, *bone_dst_child;
+ Bone *bone_src_child, *bone_dst_child;
- if (bone_src == bone_src_act) {
- *r_bone_dst_act = bone_dst;
- }
+ if (bone_src == bone_src_act) {
+ *r_bone_dst_act = bone_dst;
+ }
- if (bone_src->prop) {
- bone_dst->prop = IDP_CopyProperty_ex(bone_src->prop, flag);
- }
+ if (bone_src->prop) {
+ bone_dst->prop = IDP_CopyProperty_ex(bone_src->prop, flag);
+ }
- /* Copy this bone's list */
- BLI_duplicatelist(&bone_dst->childbase, &bone_src->childbase);
+ /* Copy this bone's list */
+ BLI_duplicatelist(&bone_dst->childbase, &bone_src->childbase);
- /* For each child in the list, update it's children */
- for (bone_src_child = bone_src->childbase.first, bone_dst_child = bone_dst->childbase.first;
- bone_src_child;
- bone_src_child = bone_src_child->next, bone_dst_child = bone_dst_child->next)
- {
- bone_dst_child->parent = bone_dst;
- copy_bonechildren(bone_dst_child, bone_src_child, bone_src_act, r_bone_dst_act, flag);
- }
+ /* For each child in the list, update it's children */
+ for (bone_src_child = bone_src->childbase.first, bone_dst_child = bone_dst->childbase.first;
+ bone_src_child;
+ bone_src_child = bone_src_child->next, bone_dst_child = bone_dst_child->next) {
+ bone_dst_child->parent = bone_dst;
+ copy_bonechildren(bone_dst_child, bone_src_child, bone_src_act, r_bone_dst_act, flag);
+ }
}
/**
@@ -174,72 +176,74 @@ static void copy_bonechildren(
*
* \param flag: Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
*/
-void BKE_armature_copy_data(Main *UNUSED(bmain), bArmature *arm_dst, const bArmature *arm_src, const int flag)
+void BKE_armature_copy_data(Main *UNUSED(bmain),
+ bArmature *arm_dst,
+ const bArmature *arm_src,
+ const int flag)
{
- Bone *bone_src, *bone_dst;
- Bone *bone_dst_act = NULL;
+ Bone *bone_src, *bone_dst;
+ Bone *bone_dst_act = NULL;
- /* We never handle usercount here for own data. */
- const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
+ /* We never handle usercount here for own data. */
+ const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
- BLI_duplicatelist(&arm_dst->bonebase, &arm_src->bonebase);
+ BLI_duplicatelist(&arm_dst->bonebase, &arm_src->bonebase);
- /* Duplicate the childrens' lists */
- bone_dst = arm_dst->bonebase.first;
- for (bone_src = arm_src->bonebase.first; bone_src; bone_src = bone_src->next) {
- bone_dst->parent = NULL;
- copy_bonechildren(bone_dst, bone_src, arm_src->act_bone, &bone_dst_act, flag_subdata);
- bone_dst = bone_dst->next;
- }
+ /* Duplicate the childrens' lists */
+ bone_dst = arm_dst->bonebase.first;
+ for (bone_src = arm_src->bonebase.first; bone_src; bone_src = bone_src->next) {
+ bone_dst->parent = NULL;
+ copy_bonechildren(bone_dst, bone_src, arm_src->act_bone, &bone_dst_act, flag_subdata);
+ bone_dst = bone_dst->next;
+ }
- arm_dst->act_bone = bone_dst_act;
+ arm_dst->act_bone = bone_dst_act;
- arm_dst->edbo = NULL;
- arm_dst->act_edbone = NULL;
+ arm_dst->edbo = NULL;
+ arm_dst->act_edbone = NULL;
}
bArmature *BKE_armature_copy(Main *bmain, const bArmature *arm)
{
- bArmature *arm_copy;
- BKE_id_copy(bmain, &arm->id, (ID **)&arm_copy);
- return arm_copy;
+ bArmature *arm_copy;
+ BKE_id_copy(bmain, &arm->id, (ID **)&arm_copy);
+ return arm_copy;
}
static Bone *get_named_bone_bonechildren(ListBase *lb, const char *name)
{
- Bone *curBone, *rbone;
+ Bone *curBone, *rbone;
- for (curBone = lb->first; curBone; curBone = curBone->next) {
- if (STREQ(curBone->name, name))
- return curBone;
+ for (curBone = lb->first; curBone; curBone = curBone->next) {
+ if (STREQ(curBone->name, name))
+ return curBone;
- rbone = get_named_bone_bonechildren(&curBone->childbase, name);
- if (rbone)
- return rbone;
- }
+ rbone = get_named_bone_bonechildren(&curBone->childbase, name);
+ if (rbone)
+ return rbone;
+ }
- return NULL;
+ return NULL;
}
-
/**
* Walk the list until the bone is found (slow!),
* use #BKE_armature_bone_from_name_map for multiple lookups.
*/
Bone *BKE_armature_find_bone_name(bArmature *arm, const char *name)
{
- if (!arm)
- return NULL;
+ if (!arm)
+ return NULL;
- return get_named_bone_bonechildren(&arm->bonebase, name);
+ return get_named_bone_bonechildren(&arm->bonebase, name);
}
static void armature_bone_from_name_insert_recursive(GHash *bone_hash, ListBase *lb)
{
- for (Bone *bone = lb->first; bone; bone = bone->next) {
- BLI_ghash_insert(bone_hash, bone->name, bone);
- armature_bone_from_name_insert_recursive(bone_hash, &bone->childbase);
- }
+ for (Bone *bone = lb->first; bone; bone = bone->next) {
+ BLI_ghash_insert(bone_hash, bone->name, bone);
+ armature_bone_from_name_insert_recursive(bone_hash, &bone->childbase);
+ }
}
/**
@@ -250,1212 +254,1299 @@ static void armature_bone_from_name_insert_recursive(GHash *bone_hash, ListBase
*/
GHash *BKE_armature_bone_from_name_map(bArmature *arm)
{
- const int bones_count = BKE_armature_bonelist_count(&arm->bonebase);
- GHash *bone_hash = BLI_ghash_str_new_ex(__func__, bones_count);
- armature_bone_from_name_insert_recursive(bone_hash, &arm->bonebase);
- return bone_hash;
+ const int bones_count = BKE_armature_bonelist_count(&arm->bonebase);
+ GHash *bone_hash = BLI_ghash_str_new_ex(__func__, bones_count);
+ armature_bone_from_name_insert_recursive(bone_hash, &arm->bonebase);
+ return bone_hash;
}
bool BKE_armature_bone_flag_test_recursive(const Bone *bone, int flag)
{
- if (bone->flag & flag) {
- return true;
- }
- else if (bone->parent) {
- return BKE_armature_bone_flag_test_recursive(bone->parent, flag);
- }
- else {
- return false;
- }
+ if (bone->flag & flag) {
+ return true;
+ }
+ else if (bone->parent) {
+ return BKE_armature_bone_flag_test_recursive(bone->parent, flag);
+ }
+ else {
+ return false;
+ }
}
/* Finds the best possible extension to the name on a particular axis. (For renaming, check for
* unique names afterwards) strip_number: removes number extensions (TODO: not used)
* axis: the axis to name on
* head/tail: the head/tail co-ordinate of the bone on the specified axis */
-int bone_autoside_name(char name[MAXBONENAME], int UNUSED(strip_number), short axis, float head, float tail)
-{
- unsigned int len;
- char basename[MAXBONENAME] = "";
- char extension[5] = "";
-
- len = strlen(name);
- if (len == 0)
- return 0;
- BLI_strncpy(basename, name, sizeof(basename));
-
- /* Figure out extension to append:
- * - The extension to append is based upon the axis that we are working on.
- * - If head happens to be on 0, then we must consider the tail position as well to decide
- * which side the bone is on
- * -> If tail is 0, then it's bone is considered to be on axis, so no extension should be added
- * -> Otherwise, extension is added from perspective of object based on which side tail goes to
- * - If head is non-zero, extension is added from perspective of object based on side head is on
- */
- if (axis == 2) {
- /* z-axis - vertical (top/bottom) */
- if (IS_EQF(head, 0.0f)) {
- if (tail < 0)
- strcpy(extension, "Bot");
- else if (tail > 0)
- strcpy(extension, "Top");
- }
- else {
- if (head < 0)
- strcpy(extension, "Bot");
- else
- strcpy(extension, "Top");
- }
- }
- else if (axis == 1) {
- /* y-axis - depth (front/back) */
- if (IS_EQF(head, 0.0f)) {
- if (tail < 0)
- strcpy(extension, "Fr");
- else if (tail > 0)
- strcpy(extension, "Bk");
- }
- else {
- if (head < 0)
- strcpy(extension, "Fr");
- else
- strcpy(extension, "Bk");
- }
- }
- else {
- /* x-axis - horizontal (left/right) */
- if (IS_EQF(head, 0.0f)) {
- if (tail < 0)
- strcpy(extension, "R");
- else if (tail > 0)
- strcpy(extension, "L");
- }
- else {
- if (head < 0)
- strcpy(extension, "R");
- /* XXX Shouldn't this be simple else, as for z and y axes? */
- else if (head > 0)
- strcpy(extension, "L");
- }
- }
-
- /* Simple name truncation
- * - truncate if there is an extension and it wouldn't be able to fit
- * - otherwise, just append to end
- */
- if (extension[0]) {
- bool changed = true;
-
- while (changed) { /* remove extensions */
- changed = false;
- if (len > 2 && basename[len - 2] == '.') {
- if (basename[len - 1] == 'L' || basename[len - 1] == 'R') { /* L R */
- basename[len - 2] = '\0';
- len -= 2;
- changed = true;
- }
- }
- else if (len > 3 && basename[len - 3] == '.') {
- if ((basename[len - 2] == 'F' && basename[len - 1] == 'r') || /* Fr */
- (basename[len - 2] == 'B' && basename[len - 1] == 'k')) /* Bk */
- {
- basename[len - 3] = '\0';
- len -= 3;
- changed = true;
- }
- }
- else if (len > 4 && basename[len - 4] == '.') {
- if ((basename[len - 3] == 'T' && basename[len - 2] == 'o' && basename[len - 1] == 'p') || /* Top */
- (basename[len - 3] == 'B' && basename[len - 2] == 'o' && basename[len - 1] == 't')) /* Bot */
- {
- basename[len - 4] = '\0';
- len -= 4;
- changed = true;
- }
- }
- }
-
- if ((MAXBONENAME - len) < strlen(extension) + 1) { /* add 1 for the '.' */
- strncpy(name, basename, len - strlen(extension));
- }
-
- BLI_snprintf(name, MAXBONENAME, "%s.%s", basename, extension);
-
- return 1;
- }
-
- else
- return 0;
+int bone_autoside_name(
+ char name[MAXBONENAME], int UNUSED(strip_number), short axis, float head, float tail)
+{
+ unsigned int len;
+ char basename[MAXBONENAME] = "";
+ char extension[5] = "";
+
+ len = strlen(name);
+ if (len == 0)
+ return 0;
+ BLI_strncpy(basename, name, sizeof(basename));
+
+ /* Figure out extension to append:
+ * - The extension to append is based upon the axis that we are working on.
+ * - If head happens to be on 0, then we must consider the tail position as well to decide
+ * which side the bone is on
+ * -> If tail is 0, then it's bone is considered to be on axis, so no extension should be added
+ * -> Otherwise, extension is added from perspective of object based on which side tail goes to
+ * - If head is non-zero, extension is added from perspective of object based on side head is on
+ */
+ if (axis == 2) {
+ /* z-axis - vertical (top/bottom) */
+ if (IS_EQF(head, 0.0f)) {
+ if (tail < 0)
+ strcpy(extension, "Bot");
+ else if (tail > 0)
+ strcpy(extension, "Top");
+ }
+ else {
+ if (head < 0)
+ strcpy(extension, "Bot");
+ else
+ strcpy(extension, "Top");
+ }
+ }
+ else if (axis == 1) {
+ /* y-axis - depth (front/back) */
+ if (IS_EQF(head, 0.0f)) {
+ if (tail < 0)
+ strcpy(extension, "Fr");
+ else if (tail > 0)
+ strcpy(extension, "Bk");
+ }
+ else {
+ if (head < 0)
+ strcpy(extension, "Fr");
+ else
+ strcpy(extension, "Bk");
+ }
+ }
+ else {
+ /* x-axis - horizontal (left/right) */
+ if (IS_EQF(head, 0.0f)) {
+ if (tail < 0)
+ strcpy(extension, "R");
+ else if (tail > 0)
+ strcpy(extension, "L");
+ }
+ else {
+ if (head < 0)
+ strcpy(extension, "R");
+ /* XXX Shouldn't this be simple else, as for z and y axes? */
+ else if (head > 0)
+ strcpy(extension, "L");
+ }
+ }
+
+ /* Simple name truncation
+ * - truncate if there is an extension and it wouldn't be able to fit
+ * - otherwise, just append to end
+ */
+ if (extension[0]) {
+ bool changed = true;
+
+ while (changed) { /* remove extensions */
+ changed = false;
+ if (len > 2 && basename[len - 2] == '.') {
+ if (basename[len - 1] == 'L' || basename[len - 1] == 'R') { /* L R */
+ basename[len - 2] = '\0';
+ len -= 2;
+ changed = true;
+ }
+ }
+ else if (len > 3 && basename[len - 3] == '.') {
+ if ((basename[len - 2] == 'F' && basename[len - 1] == 'r') || /* Fr */
+ (basename[len - 2] == 'B' && basename[len - 1] == 'k')) /* Bk */
+ {
+ basename[len - 3] = '\0';
+ len -= 3;
+ changed = true;
+ }
+ }
+ else if (len > 4 && basename[len - 4] == '.') {
+ if ((basename[len - 3] == 'T' && basename[len - 2] == 'o' &&
+ basename[len - 1] == 'p') || /* Top */
+ (basename[len - 3] == 'B' && basename[len - 2] == 'o' &&
+ basename[len - 1] == 't')) /* Bot */
+ {
+ basename[len - 4] = '\0';
+ len -= 4;
+ changed = true;
+ }
+ }
+ }
+
+ if ((MAXBONENAME - len) < strlen(extension) + 1) { /* add 1 for the '.' */
+ strncpy(name, basename, len - strlen(extension));
+ }
+
+ BLI_snprintf(name, MAXBONENAME, "%s.%s", basename, extension);
+
+ return 1;
+ }
+
+ else
+ return 0;
}
/* ************* B-Bone support ******************* */
/* Compute a set of bezier parameter values that produce approximately equally spaced points. */
-static void equalize_cubic_bezier(const float control[4][3], int temp_segments, int final_segments, float *r_t_points)
+static void equalize_cubic_bezier(const float control[4][3],
+ int temp_segments,
+ int final_segments,
+ float *r_t_points)
{
- float (*coords)[3] = BLI_array_alloca(coords, temp_segments + 1);
- float *pdist = BLI_array_alloca(pdist, temp_segments + 1);
+ float(*coords)[3] = BLI_array_alloca(coords, temp_segments + 1);
+ float *pdist = BLI_array_alloca(pdist, temp_segments + 1);
- /* Compute the first pass of bezier point coordinates. */
- for (int i = 0; i < 3; i++) {
- BKE_curve_forward_diff_bezier(
- control[0][i], control[1][i], control[2][i], control[3][i],
- &coords[0][i], temp_segments, sizeof(*coords)
- );
- }
+ /* Compute the first pass of bezier point coordinates. */
+ for (int i = 0; i < 3; i++) {
+ BKE_curve_forward_diff_bezier(control[0][i],
+ control[1][i],
+ control[2][i],
+ control[3][i],
+ &coords[0][i],
+ temp_segments,
+ sizeof(*coords));
+ }
- /* Calculate the length of the polyline at each point. */
- pdist[0] = 0.0f;
+ /* Calculate the length of the polyline at each point. */
+ pdist[0] = 0.0f;
- for (int i = 0; i < temp_segments; i++)
- pdist[i + 1] = pdist[i] + len_v3v3(coords[i], coords[i + 1]);
+ for (int i = 0; i < temp_segments; i++)
+ pdist[i + 1] = pdist[i] + len_v3v3(coords[i], coords[i + 1]);
- /* Go over distances and calculate new parameter values. */
- float dist_step = pdist[temp_segments] / final_segments;
+ /* Go over distances and calculate new parameter values. */
+ float dist_step = pdist[temp_segments] / final_segments;
- r_t_points[0] = 0.0f;
+ r_t_points[0] = 0.0f;
- for (int i = 1, nr = 1; i <= final_segments; i++) {
- float dist = i * dist_step;
+ for (int i = 1, nr = 1; i <= final_segments; i++) {
+ float dist = i * dist_step;
- /* We're looking for location (distance) 'dist' in the array. */
- while ((nr < temp_segments) && (dist >= pdist[nr]))
- nr++;
+ /* We're looking for location (distance) 'dist' in the array. */
+ while ((nr < temp_segments) && (dist >= pdist[nr]))
+ nr++;
- float fac = (pdist[nr] - dist) / (pdist[nr] - pdist[nr - 1]);
+ float fac = (pdist[nr] - dist) / (pdist[nr] - pdist[nr - 1]);
- r_t_points[i] = (nr - fac) / temp_segments;
- }
+ r_t_points[i] = (nr - fac) / temp_segments;
+ }
- r_t_points[final_segments] = 1.0f;
+ r_t_points[final_segments] = 1.0f;
}
/* Evaluate bezier position and tangent at a specific parameter value using the De Casteljau algorithm. */
-static void evaluate_cubic_bezier(const float control[4][3], float t, float r_pos[3], float r_tangent[3])
+static void evaluate_cubic_bezier(const float control[4][3],
+ float t,
+ float r_pos[3],
+ float r_tangent[3])
{
- float layer1[3][3];
- interp_v3_v3v3(layer1[0], control[0], control[1], t);
- interp_v3_v3v3(layer1[1], control[1], control[2], t);
- interp_v3_v3v3(layer1[2], control[2], control[3], t);
+ float layer1[3][3];
+ interp_v3_v3v3(layer1[0], control[0], control[1], t);
+ interp_v3_v3v3(layer1[1], control[1], control[2], t);
+ interp_v3_v3v3(layer1[2], control[2], control[3], t);
- float layer2[2][3];
- interp_v3_v3v3(layer2[0], layer1[0], layer1[1], t);
- interp_v3_v3v3(layer2[1], layer1[1], layer1[2], t);
+ float layer2[2][3];
+ interp_v3_v3v3(layer2[0], layer1[0], layer1[1], t);
+ interp_v3_v3v3(layer2[1], layer1[1], layer1[2], t);
- sub_v3_v3v3(r_tangent, layer2[1], layer2[0]);
- madd_v3_v3v3fl(r_pos, layer2[0], r_tangent, t);
+ sub_v3_v3v3(r_tangent, layer2[1], layer2[0]);
+ madd_v3_v3v3fl(r_pos, layer2[0], r_tangent, t);
}
/* Get "next" and "prev" bones - these are used for handle calculations. */
void BKE_pchan_bbone_handles_get(bPoseChannel *pchan, bPoseChannel **r_prev, bPoseChannel **r_next)
{
- if (pchan->bone->bbone_prev_type == BBONE_HANDLE_AUTO) {
- /* Use connected parent. */
- if (pchan->bone->flag & BONE_CONNECTED) {
- *r_prev = pchan->parent;
- }
- else {
- *r_prev = NULL;
- }
- }
- else {
- /* Use the provided bone as prev - leave blank to eliminate this effect altogether. */
- *r_prev = pchan->bbone_prev;
- }
-
- if (pchan->bone->bbone_next_type == BBONE_HANDLE_AUTO) {
- /* Use connected child. */
- *r_next = pchan->child;
- }
- else {
- /* Use the provided bone as next - leave blank to eliminate this effect altogether. */
- *r_next = pchan->bbone_next;
- }
+ if (pchan->bone->bbone_prev_type == BBONE_HANDLE_AUTO) {
+ /* Use connected parent. */
+ if (pchan->bone->flag & BONE_CONNECTED) {
+ *r_prev = pchan->parent;
+ }
+ else {
+ *r_prev = NULL;
+ }
+ }
+ else {
+ /* Use the provided bone as prev - leave blank to eliminate this effect altogether. */
+ *r_prev = pchan->bbone_prev;
+ }
+
+ if (pchan->bone->bbone_next_type == BBONE_HANDLE_AUTO) {
+ /* Use connected child. */
+ *r_next = pchan->child;
+ }
+ else {
+ /* Use the provided bone as next - leave blank to eliminate this effect altogether. */
+ *r_next = pchan->bbone_next;
+ }
}
/* Compute B-Bone spline parameters for the given channel. */
-void BKE_pchan_bbone_spline_params_get(struct bPoseChannel *pchan, const bool rest, struct BBoneSplineParameters *param)
-{
- bPoseChannel *next, *prev;
- Bone *bone = pchan->bone;
- float imat[4][4], posemat[4][4];
- float delta[3];
-
- memset(param, 0, sizeof(*param));
-
- param->segments = bone->segments;
- param->length = bone->length;
-
- if (!rest) {
- float scale[3];
-
- /* Check if we need to take non-uniform bone scaling into account. */
- mat4_to_size(scale, pchan->pose_mat);
-
- if (fabsf(scale[0] - scale[1]) > 1e-6f || fabsf(scale[1] - scale[2]) > 1e-6f) {
- param->do_scale = true;
- copy_v3_v3(param->scale, scale);
- }
- }
-
- BKE_pchan_bbone_handles_get(pchan, &prev, &next);
-
- /* Find the handle points, since this is inside bone space, the
- * first point = (0, 0, 0)
- * last point = (0, length, 0) */
- if (rest) {
- invert_m4_m4(imat, pchan->bone->arm_mat);
- }
- else if (param->do_scale) {
- copy_m4_m4(posemat, pchan->pose_mat);
- normalize_m4(posemat);
- invert_m4_m4(imat, posemat);
- }
- else {
- invert_m4_m4(imat, pchan->pose_mat);
- }
-
- if (prev) {
- float h1[3];
- bool done = false;
-
- param->use_prev = true;
-
- /* Transform previous point inside this bone space. */
- if (bone->bbone_prev_type == BBONE_HANDLE_RELATIVE) {
- /* Use delta movement (from restpose), and apply this relative to the current bone's head. */
- if (rest) {
- /* In restpose, arm_head == pose_head */
- zero_v3(param->prev_h);
- done = true;
- }
- else {
- sub_v3_v3v3(delta, prev->pose_head, prev->bone->arm_head);
- sub_v3_v3v3(h1, pchan->pose_head, delta);
- }
- }
- else if (bone->bbone_prev_type == BBONE_HANDLE_TANGENT) {
- /* Use bone direction by offsetting so that its tail meets current bone's head */
- if (rest) {
- sub_v3_v3v3(delta, prev->bone->arm_tail, prev->bone->arm_head);
- sub_v3_v3v3(h1, bone->arm_head, delta);
- }
- else {
- sub_v3_v3v3(delta, prev->pose_tail, prev->pose_head);
- sub_v3_v3v3(h1, pchan->pose_head, delta);
- }
- }
- else {
- /* Apply special handling for smoothly joining B-Bone chains */
- param->prev_bbone = (prev->bone->segments > 1);
-
- /* Use bone head as absolute position. */
- copy_v3_v3(h1, rest ? prev->bone->arm_head : prev->pose_head);
- }
-
- if (!done) {
- mul_v3_m4v3(param->prev_h, imat, h1);
- }
-
- if (!param->prev_bbone) {
- /* Find the previous roll to interpolate. */
- mul_m4_m4m4(param->prev_mat, imat, rest ? prev->bone->arm_mat : prev->pose_mat);
- }
- }
-
- if (next) {
- float h2[3];
- bool done = false;
-
- param->use_next = true;
-
- /* Transform next point inside this bone space. */
- if (bone->bbone_next_type == BBONE_HANDLE_RELATIVE) {
- /* Use delta movement (from restpose), and apply this relative to the current bone's tail. */
- if (rest) {
- /* In restpose, arm_head == pose_head */
- copy_v3_fl3(param->next_h, 0.0f, param->length, 0.0);
- done = true;
- }
- else {
- sub_v3_v3v3(delta, next->pose_head, next->bone->arm_head);
- add_v3_v3v3(h2, pchan->pose_tail, delta);
- }
- }
- else if (bone->bbone_next_type == BBONE_HANDLE_TANGENT) {
- /* Use bone direction by offsetting so that its head meets current bone's tail */
- if (rest) {
- sub_v3_v3v3(delta, next->bone->arm_tail, next->bone->arm_head);
- add_v3_v3v3(h2, bone->arm_tail, delta);
- }
- else {
- sub_v3_v3v3(delta, next->pose_tail, next->pose_head);
- add_v3_v3v3(h2, pchan->pose_tail, delta);
- }
- }
- else {
- /* Apply special handling for smoothly joining B-Bone chains */
- param->next_bbone = (next->bone->segments > 1);
-
- /* Use bone tail as absolute position. */
- copy_v3_v3(h2, rest ? next->bone->arm_tail : next->pose_tail);
- }
-
- if (!done) {
- mul_v3_m4v3(param->next_h, imat, h2);
- }
-
- /* Find the next roll to interpolate as well. */
- mul_m4_m4m4(param->next_mat, imat, rest ? next->bone->arm_mat : next->pose_mat);
- }
-
- /* Add effects from bbone properties over the top
- * - These properties allow users to hand-animate the
- * bone curve/shape, without having to resort to using
- * extra bones
- * - The "bone" level offsets are for defining the restpose
- * shape of the bone (e.g. for curved eyebrows for example).
- * -> In the viewport, it's needed to define what the rest pose
- * looks like
- * -> For "rest == 0", we also still need to have it present
- * so that we can "cancel out" this restpose when it comes
- * time to deform some geometry, it won't cause double transforms.
- * - The "pchan" level offsets are the ones that animators actually
- * end up animating
- */
- {
- param->ease1 = bone->ease1 + (!rest ? pchan->ease1 : 0.0f);
- param->ease2 = bone->ease2 + (!rest ? pchan->ease2 : 0.0f);
-
- param->roll1 = bone->roll1 + (!rest ? pchan->roll1 : 0.0f);
- param->roll2 = bone->roll2 + (!rest ? pchan->roll2 : 0.0f);
-
- if (bone->flag & BONE_ADD_PARENT_END_ROLL) {
- if (prev) {
- if (prev->bone) {
- param->roll1 += prev->bone->roll2;
- }
-
- if (!rest) {
- param->roll1 += prev->roll2;
- }
- }
- }
-
- param->scaleIn = bone->scaleIn * (!rest ? pchan->scaleIn : 1.0f);
- param->scaleOut = bone->scaleOut * (!rest ? pchan->scaleOut : 1.0f);
-
- /* Extra curve x / y */
- param->curveInX = bone->curveInX + (!rest ? pchan->curveInX : 0.0f);
- param->curveInY = bone->curveInY + (!rest ? pchan->curveInY : 0.0f);
-
- param->curveOutX = bone->curveOutX + (!rest ? pchan->curveOutX : 0.0f);
- param->curveOutY = bone->curveOutY + (!rest ? pchan->curveOutY : 0.0f);
- }
+void BKE_pchan_bbone_spline_params_get(struct bPoseChannel *pchan,
+ const bool rest,
+ struct BBoneSplineParameters *param)
+{
+ bPoseChannel *next, *prev;
+ Bone *bone = pchan->bone;
+ float imat[4][4], posemat[4][4];
+ float delta[3];
+
+ memset(param, 0, sizeof(*param));
+
+ param->segments = bone->segments;
+ param->length = bone->length;
+
+ if (!rest) {
+ float scale[3];
+
+ /* Check if we need to take non-uniform bone scaling into account. */
+ mat4_to_size(scale, pchan->pose_mat);
+
+ if (fabsf(scale[0] - scale[1]) > 1e-6f || fabsf(scale[1] - scale[2]) > 1e-6f) {
+ param->do_scale = true;
+ copy_v3_v3(param->scale, scale);
+ }
+ }
+
+ BKE_pchan_bbone_handles_get(pchan, &prev, &next);
+
+ /* Find the handle points, since this is inside bone space, the
+ * first point = (0, 0, 0)
+ * last point = (0, length, 0) */
+ if (rest) {
+ invert_m4_m4(imat, pchan->bone->arm_mat);
+ }
+ else if (param->do_scale) {
+ copy_m4_m4(posemat, pchan->pose_mat);
+ normalize_m4(posemat);
+ invert_m4_m4(imat, posemat);
+ }
+ else {
+ invert_m4_m4(imat, pchan->pose_mat);
+ }
+
+ if (prev) {
+ float h1[3];
+ bool done = false;
+
+ param->use_prev = true;
+
+ /* Transform previous point inside this bone space. */
+ if (bone->bbone_prev_type == BBONE_HANDLE_RELATIVE) {
+ /* Use delta movement (from restpose), and apply this relative to the current bone's head. */
+ if (rest) {
+ /* In restpose, arm_head == pose_head */
+ zero_v3(param->prev_h);
+ done = true;
+ }
+ else {
+ sub_v3_v3v3(delta, prev->pose_head, prev->bone->arm_head);
+ sub_v3_v3v3(h1, pchan->pose_head, delta);
+ }
+ }
+ else if (bone->bbone_prev_type == BBONE_HANDLE_TANGENT) {
+ /* Use bone direction by offsetting so that its tail meets current bone's head */
+ if (rest) {
+ sub_v3_v3v3(delta, prev->bone->arm_tail, prev->bone->arm_head);
+ sub_v3_v3v3(h1, bone->arm_head, delta);
+ }
+ else {
+ sub_v3_v3v3(delta, prev->pose_tail, prev->pose_head);
+ sub_v3_v3v3(h1, pchan->pose_head, delta);
+ }
+ }
+ else {
+ /* Apply special handling for smoothly joining B-Bone chains */
+ param->prev_bbone = (prev->bone->segments > 1);
+
+ /* Use bone head as absolute position. */
+ copy_v3_v3(h1, rest ? prev->bone->arm_head : prev->pose_head);
+ }
+
+ if (!done) {
+ mul_v3_m4v3(param->prev_h, imat, h1);
+ }
+
+ if (!param->prev_bbone) {
+ /* Find the previous roll to interpolate. */
+ mul_m4_m4m4(param->prev_mat, imat, rest ? prev->bone->arm_mat : prev->pose_mat);
+ }
+ }
+
+ if (next) {
+ float h2[3];
+ bool done = false;
+
+ param->use_next = true;
+
+ /* Transform next point inside this bone space. */
+ if (bone->bbone_next_type == BBONE_HANDLE_RELATIVE) {
+ /* Use delta movement (from restpose), and apply this relative to the current bone's tail. */
+ if (rest) {
+ /* In restpose, arm_head == pose_head */
+ copy_v3_fl3(param->next_h, 0.0f, param->length, 0.0);
+ done = true;
+ }
+ else {
+ sub_v3_v3v3(delta, next->pose_head, next->bone->arm_head);
+ add_v3_v3v3(h2, pchan->pose_tail, delta);
+ }
+ }
+ else if (bone->bbone_next_type == BBONE_HANDLE_TANGENT) {
+ /* Use bone direction by offsetting so that its head meets current bone's tail */
+ if (rest) {
+ sub_v3_v3v3(delta, next->bone->arm_tail, next->bone->arm_head);
+ add_v3_v3v3(h2, bone->arm_tail, delta);
+ }
+ else {
+ sub_v3_v3v3(delta, next->pose_tail, next->pose_head);
+ add_v3_v3v3(h2, pchan->pose_tail, delta);
+ }
+ }
+ else {
+ /* Apply special handling for smoothly joining B-Bone chains */
+ param->next_bbone = (next->bone->segments > 1);
+
+ /* Use bone tail as absolute position. */
+ copy_v3_v3(h2, rest ? next->bone->arm_tail : next->pose_tail);
+ }
+
+ if (!done) {
+ mul_v3_m4v3(param->next_h, imat, h2);
+ }
+
+ /* Find the next roll to interpolate as well. */
+ mul_m4_m4m4(param->next_mat, imat, rest ? next->bone->arm_mat : next->pose_mat);
+ }
+
+ /* Add effects from bbone properties over the top
+ * - These properties allow users to hand-animate the
+ * bone curve/shape, without having to resort to using
+ * extra bones
+ * - The "bone" level offsets are for defining the restpose
+ * shape of the bone (e.g. for curved eyebrows for example).
+ * -> In the viewport, it's needed to define what the rest pose
+ * looks like
+ * -> For "rest == 0", we also still need to have it present
+ * so that we can "cancel out" this restpose when it comes
+ * time to deform some geometry, it won't cause double transforms.
+ * - The "pchan" level offsets are the ones that animators actually
+ * end up animating
+ */
+ {
+ param->ease1 = bone->ease1 + (!rest ? pchan->ease1 : 0.0f);
+ param->ease2 = bone->ease2 + (!rest ? pchan->ease2 : 0.0f);
+
+ param->roll1 = bone->roll1 + (!rest ? pchan->roll1 : 0.0f);
+ param->roll2 = bone->roll2 + (!rest ? pchan->roll2 : 0.0f);
+
+ if (bone->flag & BONE_ADD_PARENT_END_ROLL) {
+ if (prev) {
+ if (prev->bone) {
+ param->roll1 += prev->bone->roll2;
+ }
+
+ if (!rest) {
+ param->roll1 += prev->roll2;
+ }
+ }
+ }
+
+ param->scaleIn = bone->scaleIn * (!rest ? pchan->scaleIn : 1.0f);
+ param->scaleOut = bone->scaleOut * (!rest ? pchan->scaleOut : 1.0f);
+
+ /* Extra curve x / y */
+ param->curveInX = bone->curveInX + (!rest ? pchan->curveInX : 0.0f);
+ param->curveInY = bone->curveInY + (!rest ? pchan->curveInY : 0.0f);
+
+ param->curveOutX = bone->curveOutX + (!rest ? pchan->curveOutX : 0.0f);
+ param->curveOutY = bone->curveOutY + (!rest ? pchan->curveOutY : 0.0f);
+ }
}
/* Fills the array with the desired amount of bone->segments elements.
* This calculation is done within unit bone space. */
-void BKE_pchan_bbone_spline_setup(bPoseChannel *pchan, const bool rest, const bool for_deform, Mat4 *result_array)
+void BKE_pchan_bbone_spline_setup(bPoseChannel *pchan,
+ const bool rest,
+ const bool for_deform,
+ Mat4 *result_array)
{
- BBoneSplineParameters param;
+ BBoneSplineParameters param;
- BKE_pchan_bbone_spline_params_get(pchan, rest, &param);
+ BKE_pchan_bbone_spline_params_get(pchan, rest, &param);
- pchan->bone->segments = BKE_pchan_bbone_spline_compute(&param, for_deform, result_array);
+ pchan->bone->segments = BKE_pchan_bbone_spline_compute(&param, for_deform, result_array);
}
/* Computes the bezier handle vectors and rolls coming from custom handles. */
-void BKE_pchan_bbone_handles_compute(const BBoneSplineParameters *param, float h1[3], float *r_roll1, float h2[3], float *r_roll2, bool ease, bool offsets)
-{
- float mat3[3][3];
- float length = param->length;
- float epsilon = 1e-5 * length;
-
- if (param->do_scale) {
- length *= param->scale[1];
- }
-
- *r_roll1 = *r_roll2 = 0.0f;
-
- if (param->use_prev) {
- copy_v3_v3(h1, param->prev_h);
-
- if (param->prev_bbone) {
- /* If previous bone is B-bone too, use average handle direction. */
- h1[1] -= length;
- }
-
- if (normalize_v3(h1) < epsilon)
- copy_v3_fl3(h1, 0.0f, -1.0f, 0.0f);
-
- negate_v3(h1);
-
- if (!param->prev_bbone) {
- /* Find the previous roll to interpolate. */
- copy_m3_m4(mat3, param->prev_mat);
- mat3_vec_to_roll(mat3, h1, r_roll1);
- }
- }
- else {
- h1[0] = 0.0f; h1[1] = 1.0; h1[2] = 0.0f;
- }
-
- if (param->use_next) {
- copy_v3_v3(h2, param->next_h);
-
- /* If next bone is B-bone too, use average handle direction. */
- if (param->next_bbone) {
- /* pass */
- }
- else {
- h2[1] -= length;
- }
-
- if (normalize_v3(h2) < epsilon)
- copy_v3_fl3(h2, 0.0f, 1.0f, 0.0f);
-
- /* Find the next roll to interpolate as well. */
- copy_m3_m4(mat3, param->next_mat);
- mat3_vec_to_roll(mat3, h2, r_roll2);
- }
- else {
- h2[0] = 0.0f; h2[1] = 1.0f; h2[2] = 0.0f;
- }
-
- if (ease) {
- const float circle_factor = length * (cubic_tangent_factor_circle_v3(h1, h2) / 0.75f);
-
- const float hlength1 = param->ease1 * circle_factor;
- const float hlength2 = param->ease2 * circle_factor;
-
- /* and only now negate h2 */
- mul_v3_fl(h1, hlength1);
- mul_v3_fl(h2, -hlength2);
- }
-
- /* Add effects from bbone properties over the top
- * - These properties allow users to hand-animate the
- * bone curve/shape, without having to resort to using
- * extra bones
- * - The "bone" level offsets are for defining the restpose
- * shape of the bone (e.g. for curved eyebrows for example).
- * -> In the viewport, it's needed to define what the rest pose
- * looks like
- * -> For "rest == 0", we also still need to have it present
- * so that we can "cancel out" this restpose when it comes
- * time to deform some geometry, it won't cause double transforms.
- * - The "pchan" level offsets are the ones that animators actually
- * end up animating
- */
- if (offsets) {
- /* Add extra rolls. */
- *r_roll1 += param->roll1;
- *r_roll2 += param->roll2;
-
- /* Extra curve x / y */
- /* NOTE: Scale correction factors here are to compensate for some random floating-point glitches
- * when scaling up the bone or it's parent by a factor of approximately 8.15/6, which results
- * in the bone length getting scaled up too (from 1 to 8), causing the curve to flatten out.
- */
- const float xscale_correction = (param->do_scale) ? param->scale[0] : 1.0f;
- const float yscale_correction = (param->do_scale) ? param->scale[2] : 1.0f;
-
- h1[0] += param->curveInX * xscale_correction;
- h1[2] += param->curveInY * yscale_correction;
-
- h2[0] += param->curveOutX * xscale_correction;
- h2[2] += param->curveOutY * yscale_correction;
- }
-}
-
-static void make_bbone_spline_matrix(
- BBoneSplineParameters *param, float scalemats[2][4][4],
- float pos[3], float axis[3], float roll, float scalefac,
- float result[4][4]
-) {
- float mat3[3][3];
-
- vec_roll_to_mat3(axis, roll, mat3);
-
- copy_m4_m3(result, mat3);
- copy_v3_v3(result[3], pos);
-
- if (param->do_scale) {
- /* Correct for scaling when this matrix is used in scaled space. */
- mul_m4_series(result, scalemats[0], result, scalemats[1]);
- }
-
- /* BBone scale... */
- mul_v3_fl(result[0], scalefac);
- mul_v3_fl(result[2], scalefac);
+void BKE_pchan_bbone_handles_compute(const BBoneSplineParameters *param,
+ float h1[3],
+ float *r_roll1,
+ float h2[3],
+ float *r_roll2,
+ bool ease,
+ bool offsets)
+{
+ float mat3[3][3];
+ float length = param->length;
+ float epsilon = 1e-5 * length;
+
+ if (param->do_scale) {
+ length *= param->scale[1];
+ }
+
+ *r_roll1 = *r_roll2 = 0.0f;
+
+ if (param->use_prev) {
+ copy_v3_v3(h1, param->prev_h);
+
+ if (param->prev_bbone) {
+ /* If previous bone is B-bone too, use average handle direction. */
+ h1[1] -= length;
+ }
+
+ if (normalize_v3(h1) < epsilon)
+ copy_v3_fl3(h1, 0.0f, -1.0f, 0.0f);
+
+ negate_v3(h1);
+
+ if (!param->prev_bbone) {
+ /* Find the previous roll to interpolate. */
+ copy_m3_m4(mat3, param->prev_mat);
+ mat3_vec_to_roll(mat3, h1, r_roll1);
+ }
+ }
+ else {
+ h1[0] = 0.0f;
+ h1[1] = 1.0;
+ h1[2] = 0.0f;
+ }
+
+ if (param->use_next) {
+ copy_v3_v3(h2, param->next_h);
+
+ /* If next bone is B-bone too, use average handle direction. */
+ if (param->next_bbone) {
+ /* pass */
+ }
+ else {
+ h2[1] -= length;
+ }
+
+ if (normalize_v3(h2) < epsilon)
+ copy_v3_fl3(h2, 0.0f, 1.0f, 0.0f);
+
+ /* Find the next roll to interpolate as well. */
+ copy_m3_m4(mat3, param->next_mat);
+ mat3_vec_to_roll(mat3, h2, r_roll2);
+ }
+ else {
+ h2[0] = 0.0f;
+ h2[1] = 1.0f;
+ h2[2] = 0.0f;
+ }
+
+ if (ease) {
+ const float circle_factor = length * (cubic_tangent_factor_circle_v3(h1, h2) / 0.75f);
+
+ const float hlength1 = param->ease1 * circle_factor;
+ const float hlength2 = param->ease2 * circle_factor;
+
+ /* and only now negate h2 */
+ mul_v3_fl(h1, hlength1);
+ mul_v3_fl(h2, -hlength2);
+ }
+
+ /* Add effects from bbone properties over the top
+ * - These properties allow users to hand-animate the
+ * bone curve/shape, without having to resort to using
+ * extra bones
+ * - The "bone" level offsets are for defining the restpose
+ * shape of the bone (e.g. for curved eyebrows for example).
+ * -> In the viewport, it's needed to define what the rest pose
+ * looks like
+ * -> For "rest == 0", we also still need to have it present
+ * so that we can "cancel out" this restpose when it comes
+ * time to deform some geometry, it won't cause double transforms.
+ * - The "pchan" level offsets are the ones that animators actually
+ * end up animating
+ */
+ if (offsets) {
+ /* Add extra rolls. */
+ *r_roll1 += param->roll1;
+ *r_roll2 += param->roll2;
+
+ /* Extra curve x / y */
+ /* NOTE: Scale correction factors here are to compensate for some random floating-point glitches
+ * when scaling up the bone or it's parent by a factor of approximately 8.15/6, which results
+ * in the bone length getting scaled up too (from 1 to 8), causing the curve to flatten out.
+ */
+ const float xscale_correction = (param->do_scale) ? param->scale[0] : 1.0f;
+ const float yscale_correction = (param->do_scale) ? param->scale[2] : 1.0f;
+
+ h1[0] += param->curveInX * xscale_correction;
+ h1[2] += param->curveInY * yscale_correction;
+
+ h2[0] += param->curveOutX * xscale_correction;
+ h2[2] += param->curveOutY * yscale_correction;
+ }
+}
+
+static void make_bbone_spline_matrix(BBoneSplineParameters *param,
+ float scalemats[2][4][4],
+ float pos[3],
+ float axis[3],
+ float roll,
+ float scalefac,
+ float result[4][4])
+{
+ float mat3[3][3];
+
+ vec_roll_to_mat3(axis, roll, mat3);
+
+ copy_m4_m3(result, mat3);
+ copy_v3_v3(result[3], pos);
+
+ if (param->do_scale) {
+ /* Correct for scaling when this matrix is used in scaled space. */
+ mul_m4_series(result, scalemats[0], result, scalemats[1]);
+ }
+
+ /* BBone scale... */
+ mul_v3_fl(result[0], scalefac);
+ mul_v3_fl(result[2], scalefac);
}
/* Fade from first to second derivative when the handle is very short. */
static void ease_handle_axis(const float deriv1[3], const float deriv2[3], float r_axis[3])
{
- const float gap = 0.1f;
+ const float gap = 0.1f;
- copy_v3_v3(r_axis, deriv1);
+ copy_v3_v3(r_axis, deriv1);
- float len1 = len_squared_v3(deriv1), len2 = len_squared_v3(deriv2);
- float ratio = len1 / len2;
+ float len1 = len_squared_v3(deriv1), len2 = len_squared_v3(deriv2);
+ float ratio = len1 / len2;
- if (ratio < gap * gap) {
- madd_v3_v3fl(r_axis, deriv2, gap - sqrtf(ratio));
- }
+ if (ratio < gap * gap) {
+ madd_v3_v3fl(r_axis, deriv2, gap - sqrtf(ratio));
+ }
}
/* Fills the array with the desired amount of bone->segments elements.
* This calculation is done within unit bone space. */
-int BKE_pchan_bbone_spline_compute(BBoneSplineParameters *param, const bool for_deform, Mat4 *result_array)
+int BKE_pchan_bbone_spline_compute(BBoneSplineParameters *param,
+ const bool for_deform,
+ Mat4 *result_array)
{
- float scalemats[2][4][4];
- float bezt_controls[4][3];
- float h1[3], roll1, h2[3], roll2, prev[3], cur[3], axis[3];
- float length = param->length;
+ float scalemats[2][4][4];
+ float bezt_controls[4][3];
+ float h1[3], roll1, h2[3], roll2, prev[3], cur[3], axis[3];
+ float length = param->length;
- if (param->do_scale) {
- size_to_mat4(scalemats[1], param->scale);
- invert_m4_m4(scalemats[0], scalemats[1]);
+ if (param->do_scale) {
+ size_to_mat4(scalemats[1], param->scale);
+ invert_m4_m4(scalemats[0], scalemats[1]);
- length *= param->scale[1];
- }
+ length *= param->scale[1];
+ }
- BKE_pchan_bbone_handles_compute(param, h1, &roll1, h2, &roll2, true, true);
+ BKE_pchan_bbone_handles_compute(param, h1, &roll1, h2, &roll2, true, true);
- /* Make curve. */
- CLAMP_MAX(param->segments, MAX_BBONE_SUBDIV);
+ /* Make curve. */
+ CLAMP_MAX(param->segments, MAX_BBONE_SUBDIV);
- copy_v3_fl3(bezt_controls[3], 0.0f, length, 0.0f);
- add_v3_v3v3(bezt_controls[2], bezt_controls[3], h2);
- copy_v3_v3(bezt_controls[1], h1);
- zero_v3(bezt_controls[0]);
+ copy_v3_fl3(bezt_controls[3], 0.0f, length, 0.0f);
+ add_v3_v3v3(bezt_controls[2], bezt_controls[3], h2);
+ copy_v3_v3(bezt_controls[1], h1);
+ zero_v3(bezt_controls[0]);
- float bezt_points[MAX_BBONE_SUBDIV + 1];
+ float bezt_points[MAX_BBONE_SUBDIV + 1];
- equalize_cubic_bezier(bezt_controls, MAX_BBONE_SUBDIV, param->segments, bezt_points);
+ equalize_cubic_bezier(bezt_controls, MAX_BBONE_SUBDIV, param->segments, bezt_points);
- /* Deformation uses N+1 matrices computed at points between the segments. */
- if (for_deform) {
- /* Bezier derivatives. */
- float bezt_deriv1[3][3], bezt_deriv2[2][3];
+ /* Deformation uses N+1 matrices computed at points between the segments. */
+ if (for_deform) {
+ /* Bezier derivatives. */
+ float bezt_deriv1[3][3], bezt_deriv2[2][3];
- for (int i = 0; i < 3; i++) {
- sub_v3_v3v3(bezt_deriv1[i], bezt_controls[i + 1], bezt_controls[i]);
- }
- for (int i = 0; i < 2; i++) {
- sub_v3_v3v3(bezt_deriv2[i], bezt_deriv1[i + 1], bezt_deriv1[i]);
- }
+ for (int i = 0; i < 3; i++) {
+ sub_v3_v3v3(bezt_deriv1[i], bezt_controls[i + 1], bezt_controls[i]);
+ }
+ for (int i = 0; i < 2; i++) {
+ sub_v3_v3v3(bezt_deriv2[i], bezt_deriv1[i + 1], bezt_deriv1[i]);
+ }
- /* End points require special handling to fix zero length handles. */
- ease_handle_axis(bezt_deriv1[0], bezt_deriv2[0], axis);
- make_bbone_spline_matrix(param, scalemats, bezt_controls[0], axis, roll1, param->scaleIn, result_array[0].mat);
+ /* End points require special handling to fix zero length handles. */
+ ease_handle_axis(bezt_deriv1[0], bezt_deriv2[0], axis);
+ make_bbone_spline_matrix(
+ param, scalemats, bezt_controls[0], axis, roll1, param->scaleIn, result_array[0].mat);
- for (int a = 1; a < param->segments; a++) {
- evaluate_cubic_bezier(bezt_controls, bezt_points[a], cur, axis);
+ for (int a = 1; a < param->segments; a++) {
+ evaluate_cubic_bezier(bezt_controls, bezt_points[a], cur, axis);
- float fac = ((float)a) / param->segments;
- float roll = interpf(roll2, roll1, fac);
- float scalefac = interpf(param->scaleOut, param->scaleIn, fac);
+ float fac = ((float)a) / param->segments;
+ float roll = interpf(roll2, roll1, fac);
+ float scalefac = interpf(param->scaleOut, param->scaleIn, fac);
- make_bbone_spline_matrix(param, scalemats, cur, axis, roll, scalefac, result_array[a].mat);
- }
+ make_bbone_spline_matrix(param, scalemats, cur, axis, roll, scalefac, result_array[a].mat);
+ }
- negate_v3(bezt_deriv2[1]);
- ease_handle_axis(bezt_deriv1[2], bezt_deriv2[1], axis);
- make_bbone_spline_matrix(param, scalemats, bezt_controls[3], axis, roll2, param->scaleOut, result_array[param->segments].mat);
- }
- /* Other code (e.g. display) uses matrices for the segments themselves. */
- else {
- zero_v3(prev);
+ negate_v3(bezt_deriv2[1]);
+ ease_handle_axis(bezt_deriv1[2], bezt_deriv2[1], axis);
+ make_bbone_spline_matrix(param,
+ scalemats,
+ bezt_controls[3],
+ axis,
+ roll2,
+ param->scaleOut,
+ result_array[param->segments].mat);
+ }
+ /* Other code (e.g. display) uses matrices for the segments themselves. */
+ else {
+ zero_v3(prev);
- for (int a = 0; a < param->segments; a++) {
- evaluate_cubic_bezier(bezt_controls, bezt_points[a + 1], cur, axis);
+ for (int a = 0; a < param->segments; a++) {
+ evaluate_cubic_bezier(bezt_controls, bezt_points[a + 1], cur, axis);
- sub_v3_v3v3(axis, cur, prev);
+ sub_v3_v3v3(axis, cur, prev);
- float fac = (a + 0.5f) / param->segments;
- float roll = interpf(roll2, roll1, fac);
- float scalefac = interpf(param->scaleOut, param->scaleIn, fac);
+ float fac = (a + 0.5f) / param->segments;
+ float roll = interpf(roll2, roll1, fac);
+ float scalefac = interpf(param->scaleOut, param->scaleIn, fac);
- make_bbone_spline_matrix(param, scalemats, prev, axis, roll, scalefac, result_array[a].mat);
- copy_v3_v3(prev, cur);
- }
- }
+ make_bbone_spline_matrix(param, scalemats, prev, axis, roll, scalefac, result_array[a].mat);
+ copy_v3_v3(prev, cur);
+ }
+ }
- return param->segments;
+ return param->segments;
}
/* ************ Armature Deform ******************* */
typedef struct bPoseChanDeform {
- DualQuat *dual_quat;
+ DualQuat *dual_quat;
} bPoseChanDeform;
/* Definition of cached object bbone deformations. */
typedef struct ObjectBBoneDeform {
- DualQuat *dualquats;
- bPoseChanDeform *pdef_info_array;
- int num_pchan;
+ DualQuat *dualquats;
+ bPoseChanDeform *pdef_info_array;
+ int num_pchan;
} ObjectBBoneDeform;
static void allocate_bbone_cache(bPoseChannel *pchan, int segments)
{
- bPoseChannel_Runtime *runtime = &pchan->runtime;
+ bPoseChannel_Runtime *runtime = &pchan->runtime;
- if (runtime->bbone_segments != segments) {
- if (runtime->bbone_segments != 0) {
- BKE_pose_channel_free_bbone_cache(pchan);
- }
+ if (runtime->bbone_segments != segments) {
+ if (runtime->bbone_segments != 0) {
+ BKE_pose_channel_free_bbone_cache(pchan);
+ }
- runtime->bbone_segments = segments;
- runtime->bbone_rest_mats = MEM_malloc_arrayN(sizeof(Mat4), 1 + (uint)segments, "bPoseChannel_Runtime::bbone_rest_mats");
- runtime->bbone_pose_mats = MEM_malloc_arrayN(sizeof(Mat4), 1 + (uint)segments, "bPoseChannel_Runtime::bbone_pose_mats");
- runtime->bbone_deform_mats = MEM_malloc_arrayN(sizeof(Mat4), 2 + (uint)segments, "bPoseChannel_Runtime::bbone_deform_mats");
- runtime->bbone_dual_quats = MEM_malloc_arrayN(sizeof(DualQuat), 1 + (uint)segments, "bPoseChannel_Runtime::bbone_dual_quats");
- }
+ runtime->bbone_segments = segments;
+ runtime->bbone_rest_mats = MEM_malloc_arrayN(
+ sizeof(Mat4), 1 + (uint)segments, "bPoseChannel_Runtime::bbone_rest_mats");
+ runtime->bbone_pose_mats = MEM_malloc_arrayN(
+ sizeof(Mat4), 1 + (uint)segments, "bPoseChannel_Runtime::bbone_pose_mats");
+ runtime->bbone_deform_mats = MEM_malloc_arrayN(
+ sizeof(Mat4), 2 + (uint)segments, "bPoseChannel_Runtime::bbone_deform_mats");
+ runtime->bbone_dual_quats = MEM_malloc_arrayN(
+ sizeof(DualQuat), 1 + (uint)segments, "bPoseChannel_Runtime::bbone_dual_quats");
+ }
}
/** Compute and cache the B-Bone shape in the channel runtime struct. */
void BKE_pchan_bbone_segments_cache_compute(bPoseChannel *pchan)
{
- bPoseChannel_Runtime *runtime = &pchan->runtime;
- Bone *bone = pchan->bone;
- int segments = bone->segments;
+ bPoseChannel_Runtime *runtime = &pchan->runtime;
+ Bone *bone = pchan->bone;
+ int segments = bone->segments;
- BLI_assert(segments > 1);
+ BLI_assert(segments > 1);
- /* Allocate the cache if needed. */
- allocate_bbone_cache(pchan, segments);
+ /* Allocate the cache if needed. */
+ allocate_bbone_cache(pchan, segments);
- /* Compute the shape. */
- Mat4 *b_bone = runtime->bbone_pose_mats;
- Mat4 *b_bone_rest = runtime->bbone_rest_mats;
- Mat4 *b_bone_mats = runtime->bbone_deform_mats;
- DualQuat *b_bone_dual_quats = runtime->bbone_dual_quats;
- int a;
+ /* Compute the shape. */
+ Mat4 *b_bone = runtime->bbone_pose_mats;
+ Mat4 *b_bone_rest = runtime->bbone_rest_mats;
+ Mat4 *b_bone_mats = runtime->bbone_deform_mats;
+ DualQuat *b_bone_dual_quats = runtime->bbone_dual_quats;
+ int a;
- BKE_pchan_bbone_spline_setup(pchan, false, true, b_bone);
- BKE_pchan_bbone_spline_setup(pchan, true, true, b_bone_rest);
+ BKE_pchan_bbone_spline_setup(pchan, false, true, b_bone);
+ BKE_pchan_bbone_spline_setup(pchan, true, true, b_bone_rest);
- /* Compute deform matrices. */
- /* first matrix is the inverse arm_mat, to bring points in local bone space
- * for finding out which segment it belongs to */
- invert_m4_m4(b_bone_mats[0].mat, bone->arm_mat);
+ /* Compute deform matrices. */
+ /* first matrix is the inverse arm_mat, to bring points in local bone space
+ * for finding out which segment it belongs to */
+ invert_m4_m4(b_bone_mats[0].mat, bone->arm_mat);
- /* then we make the b_bone_mats:
- * - first transform to local bone space
- * - translate over the curve to the bbone mat space
- * - transform with b_bone matrix
- * - transform back into global space */
+ /* then we make the b_bone_mats:
+ * - first transform to local bone space
+ * - translate over the curve to the bbone mat space
+ * - transform with b_bone matrix
+ * - transform back into global space */
- for (a = 0; a <= bone->segments; a++) {
- float tmat[4][4];
+ for (a = 0; a <= bone->segments; a++) {
+ float tmat[4][4];
- invert_m4_m4(tmat, b_bone_rest[a].mat);
- mul_m4_series(b_bone_mats[a + 1].mat, pchan->chan_mat, bone->arm_mat, b_bone[a].mat, tmat, b_bone_mats[0].mat);
+ invert_m4_m4(tmat, b_bone_rest[a].mat);
+ mul_m4_series(b_bone_mats[a + 1].mat,
+ pchan->chan_mat,
+ bone->arm_mat,
+ b_bone[a].mat,
+ tmat,
+ b_bone_mats[0].mat);
- mat4_to_dquat(&b_bone_dual_quats[a], bone->arm_mat, b_bone_mats[a + 1].mat);
- }
+ mat4_to_dquat(&b_bone_dual_quats[a], bone->arm_mat, b_bone_mats[a + 1].mat);
+ }
}
/** Copy cached B-Bone segments from one channel to another */
void BKE_pchan_bbone_segments_cache_copy(bPoseChannel *pchan, bPoseChannel *pchan_from)
{
- bPoseChannel_Runtime *runtime = &pchan->runtime;
- bPoseChannel_Runtime *runtime_from = &pchan_from->runtime;
- int segments = runtime_from->bbone_segments;
+ bPoseChannel_Runtime *runtime = &pchan->runtime;
+ bPoseChannel_Runtime *runtime_from = &pchan_from->runtime;
+ int segments = runtime_from->bbone_segments;
- if (segments <= 1) {
- BKE_pose_channel_free_bbone_cache(pchan);
- }
- else {
- allocate_bbone_cache(pchan, segments);
+ if (segments <= 1) {
+ BKE_pose_channel_free_bbone_cache(pchan);
+ }
+ else {
+ allocate_bbone_cache(pchan, segments);
- memcpy(runtime->bbone_rest_mats, runtime_from->bbone_rest_mats, sizeof(Mat4) * (1 + segments));
- memcpy(runtime->bbone_pose_mats, runtime_from->bbone_pose_mats, sizeof(Mat4) * (1 + segments));
- memcpy(runtime->bbone_deform_mats, runtime_from->bbone_deform_mats, sizeof(Mat4) * (2 + segments));
- memcpy(runtime->bbone_dual_quats, runtime_from->bbone_dual_quats, sizeof(DualQuat) * (1 + segments));
- }
+ memcpy(runtime->bbone_rest_mats, runtime_from->bbone_rest_mats, sizeof(Mat4) * (1 + segments));
+ memcpy(runtime->bbone_pose_mats, runtime_from->bbone_pose_mats, sizeof(Mat4) * (1 + segments));
+ memcpy(runtime->bbone_deform_mats,
+ runtime_from->bbone_deform_mats,
+ sizeof(Mat4) * (2 + segments));
+ memcpy(runtime->bbone_dual_quats,
+ runtime_from->bbone_dual_quats,
+ sizeof(DualQuat) * (1 + segments));
+ }
}
/** Calculate index and blend factor for the two B-Bone segment nodes affecting the point at 0 <= pos <= 1. */
-void BKE_pchan_bbone_deform_segment_index(const bPoseChannel *pchan, float pos, int *r_index, float *r_blend_next)
+void BKE_pchan_bbone_deform_segment_index(const bPoseChannel *pchan,
+ float pos,
+ int *r_index,
+ float *r_blend_next)
{
- int segments = pchan->bone->segments;
+ int segments = pchan->bone->segments;
- CLAMP(pos, 0.0f, 1.0f);
+ CLAMP(pos, 0.0f, 1.0f);
- /* Calculate the indices of the 2 affecting b_bone segments.
- * Integer part is the first segment's index.
- * Integer part plus 1 is the second segment's index.
- * Fractional part is the blend factor. */
- float pre_blend = pos * (float)segments;
+ /* Calculate the indices of the 2 affecting b_bone segments.
+ * Integer part is the first segment's index.
+ * Integer part plus 1 is the second segment's index.
+ * Fractional part is the blend factor. */
+ float pre_blend = pos * (float)segments;
- int index = (int)floorf(pre_blend);
- float blend = pre_blend - index;
+ int index = (int)floorf(pre_blend);
+ float blend = pre_blend - index;
- CLAMP(index, 0, segments);
- CLAMP(blend, 0.0f, 1.0f);
+ CLAMP(index, 0, segments);
+ CLAMP(blend, 0.0f, 1.0f);
- *r_index = index;
- *r_blend_next = blend;
+ *r_index = index;
+ *r_blend_next = blend;
}
/* Add the effect of one bone or B-Bone segment to the accumulated result. */
-static void pchan_deform_accumulate(
- const DualQuat *deform_dq, const float deform_mat[4][4], const float co_in[3], float weight,
- float co_accum[3], DualQuat *dq_accum, float mat_accum[3][3]
-) {
- if (weight == 0.0f)
- return;
+static void pchan_deform_accumulate(const DualQuat *deform_dq,
+ const float deform_mat[4][4],
+ const float co_in[3],
+ float weight,
+ float co_accum[3],
+ DualQuat *dq_accum,
+ float mat_accum[3][3])
+{
+ if (weight == 0.0f)
+ return;
- if (dq_accum) {
- BLI_assert(!co_accum);
+ if (dq_accum) {
+ BLI_assert(!co_accum);
- add_weighted_dq_dq(dq_accum, deform_dq, weight);
- }
- else {
- float tmp[3];
- mul_v3_m4v3(tmp, deform_mat, co_in);
+ add_weighted_dq_dq(dq_accum, deform_dq, weight);
+ }
+ else {
+ float tmp[3];
+ mul_v3_m4v3(tmp, deform_mat, co_in);
- sub_v3_v3(tmp, co_in);
- madd_v3_v3fl(co_accum, tmp, weight);
+ sub_v3_v3(tmp, co_in);
+ madd_v3_v3fl(co_accum, tmp, weight);
- if (mat_accum) {
- float tmpmat[3][3];
- copy_m3_m4(tmpmat, deform_mat);
+ if (mat_accum) {
+ float tmpmat[3][3];
+ copy_m3_m4(tmpmat, deform_mat);
- madd_m3_m3m3fl(mat_accum, mat_accum, tmpmat, weight);
- }
- }
+ madd_m3_m3m3fl(mat_accum, mat_accum, tmpmat, weight);
+ }
+ }
}
-static void b_bone_deform(const bPoseChannel *pchan, const float co[3], float weight, float vec[3], DualQuat *dq, float defmat[3][3])
+static void b_bone_deform(const bPoseChannel *pchan,
+ const float co[3],
+ float weight,
+ float vec[3],
+ DualQuat *dq,
+ float defmat[3][3])
{
- const DualQuat *quats = pchan->runtime.bbone_dual_quats;
- const Mat4 *mats = pchan->runtime.bbone_deform_mats;
- const float (*mat)[4] = mats[0].mat;
- float blend, y;
- int index;
+ const DualQuat *quats = pchan->runtime.bbone_dual_quats;
+ const Mat4 *mats = pchan->runtime.bbone_deform_mats;
+ const float(*mat)[4] = mats[0].mat;
+ float blend, y;
+ int index;
- /* Transform co to bone space and get its y component. */
- y = mat[0][1] * co[0] + mat[1][1] * co[1] + mat[2][1] * co[2] + mat[3][1];
+ /* Transform co to bone space and get its y component. */
+ y = mat[0][1] * co[0] + mat[1][1] * co[1] + mat[2][1] * co[2] + mat[3][1];
- /* Calculate the indices of the 2 affecting b_bone segments. */
- BKE_pchan_bbone_deform_segment_index(pchan, y / pchan->bone->length, &index, &blend);
+ /* Calculate the indices of the 2 affecting b_bone segments. */
+ BKE_pchan_bbone_deform_segment_index(pchan, y / pchan->bone->length, &index, &blend);
- pchan_deform_accumulate(&quats[index], mats[index + 1].mat, co, weight * (1.0f - blend), vec, dq, defmat);
- pchan_deform_accumulate(&quats[index + 1], mats[index + 2].mat, co, weight * blend, vec, dq, defmat);
+ pchan_deform_accumulate(
+ &quats[index], mats[index + 1].mat, co, weight * (1.0f - blend), vec, dq, defmat);
+ pchan_deform_accumulate(
+ &quats[index + 1], mats[index + 2].mat, co, weight * blend, vec, dq, defmat);
}
/* using vec with dist to bone b1 - b2 */
-float distfactor_to_bone(const float vec[3], const float b1[3], const float b2[3], float rad1, float rad2, float rdist)
-{
- float dist_sq;
- float bdelta[3];
- float pdelta[3];
- float hsqr, a, l, rad;
-
- sub_v3_v3v3(bdelta, b2, b1);
- l = normalize_v3(bdelta);
-
- sub_v3_v3v3(pdelta, vec, b1);
-
- a = dot_v3v3(bdelta, pdelta);
- hsqr = len_squared_v3(pdelta);
-
- if (a < 0.0f) {
- /* If we're past the end of the bone, do a spherical field attenuation thing */
- dist_sq = len_squared_v3v3(b1, vec);
- rad = rad1;
- }
- else if (a > l) {
- /* If we're past the end of the bone, do a spherical field attenuation thing */
- dist_sq = len_squared_v3v3(b2, vec);
- rad = rad2;
- }
- else {
- dist_sq = (hsqr - (a * a));
-
- if (l != 0.0f) {
- rad = a / l;
- rad = rad * rad2 + (1.0f - rad) * rad1;
- }
- else
- rad = rad1;
- }
-
- a = rad * rad;
- if (dist_sq < a)
- return 1.0f;
- else {
- l = rad + rdist;
- l *= l;
- if (rdist == 0.0f || dist_sq >= l)
- return 0.0f;
- else {
- a = sqrtf(dist_sq) - rad;
- return 1.0f - (a * a) / (rdist * rdist);
- }
- }
-}
-
-static float dist_bone_deform(bPoseChannel *pchan, const bPoseChanDeform *pdef_info, float vec[3], DualQuat *dq,
- float mat[3][3], const float co[3])
-{
- Bone *bone = pchan->bone;
- float fac, contrib = 0.0;
-
- if (bone == NULL)
- return 0.0f;
-
- fac = distfactor_to_bone(co, bone->arm_head, bone->arm_tail, bone->rad_head, bone->rad_tail, bone->dist);
-
- if (fac > 0.0f) {
- fac *= bone->weight;
- contrib = fac;
- if (contrib > 0.0f) {
- if (bone->segments > 1 && pchan->runtime.bbone_segments == bone->segments)
- b_bone_deform(pchan, co, fac, vec, dq, mat);
- else
- pchan_deform_accumulate(pdef_info->dual_quat, pchan->chan_mat, co, fac, vec, dq, mat);
- }
- }
-
- return contrib;
-}
-
-static void pchan_bone_deform(bPoseChannel *pchan, const bPoseChanDeform *pdef_info,
- float weight, float vec[3], DualQuat *dq,
- float mat[3][3], const float co[3], float *contrib)
-{
- Bone *bone = pchan->bone;
-
- if (!weight)
- return;
-
- if (bone->segments > 1 && pchan->runtime.bbone_segments == bone->segments)
- b_bone_deform(pchan, co, weight, vec, dq, mat);
- else
- pchan_deform_accumulate(pdef_info->dual_quat, pchan->chan_mat, co, weight, vec, dq, mat);
-
- (*contrib) += weight;
+float distfactor_to_bone(
+ const float vec[3], const float b1[3], const float b2[3], float rad1, float rad2, float rdist)
+{
+ float dist_sq;
+ float bdelta[3];
+ float pdelta[3];
+ float hsqr, a, l, rad;
+
+ sub_v3_v3v3(bdelta, b2, b1);
+ l = normalize_v3(bdelta);
+
+ sub_v3_v3v3(pdelta, vec, b1);
+
+ a = dot_v3v3(bdelta, pdelta);
+ hsqr = len_squared_v3(pdelta);
+
+ if (a < 0.0f) {
+ /* If we're past the end of the bone, do a spherical field attenuation thing */
+ dist_sq = len_squared_v3v3(b1, vec);
+ rad = rad1;
+ }
+ else if (a > l) {
+ /* If we're past the end of the bone, do a spherical field attenuation thing */
+ dist_sq = len_squared_v3v3(b2, vec);
+ rad = rad2;
+ }
+ else {
+ dist_sq = (hsqr - (a * a));
+
+ if (l != 0.0f) {
+ rad = a / l;
+ rad = rad * rad2 + (1.0f - rad) * rad1;
+ }
+ else
+ rad = rad1;
+ }
+
+ a = rad * rad;
+ if (dist_sq < a)
+ return 1.0f;
+ else {
+ l = rad + rdist;
+ l *= l;
+ if (rdist == 0.0f || dist_sq >= l)
+ return 0.0f;
+ else {
+ a = sqrtf(dist_sq) - rad;
+ return 1.0f - (a * a) / (rdist * rdist);
+ }
+ }
+}
+
+static float dist_bone_deform(bPoseChannel *pchan,
+ const bPoseChanDeform *pdef_info,
+ float vec[3],
+ DualQuat *dq,
+ float mat[3][3],
+ const float co[3])
+{
+ Bone *bone = pchan->bone;
+ float fac, contrib = 0.0;
+
+ if (bone == NULL)
+ return 0.0f;
+
+ fac = distfactor_to_bone(
+ co, bone->arm_head, bone->arm_tail, bone->rad_head, bone->rad_tail, bone->dist);
+
+ if (fac > 0.0f) {
+ fac *= bone->weight;
+ contrib = fac;
+ if (contrib > 0.0f) {
+ if (bone->segments > 1 && pchan->runtime.bbone_segments == bone->segments)
+ b_bone_deform(pchan, co, fac, vec, dq, mat);
+ else
+ pchan_deform_accumulate(pdef_info->dual_quat, pchan->chan_mat, co, fac, vec, dq, mat);
+ }
+ }
+
+ return contrib;
+}
+
+static void pchan_bone_deform(bPoseChannel *pchan,
+ const bPoseChanDeform *pdef_info,
+ float weight,
+ float vec[3],
+ DualQuat *dq,
+ float mat[3][3],
+ const float co[3],
+ float *contrib)
+{
+ Bone *bone = pchan->bone;
+
+ if (!weight)
+ return;
+
+ if (bone->segments > 1 && pchan->runtime.bbone_segments == bone->segments)
+ b_bone_deform(pchan, co, weight, vec, dq, mat);
+ else
+ pchan_deform_accumulate(pdef_info->dual_quat, pchan->chan_mat, co, weight, vec, dq, mat);
+
+ (*contrib) += weight;
}
typedef struct ArmatureBBoneDefmatsData {
- bPoseChanDeform *pdef_info_array;
- DualQuat *dualquats;
- bool use_quaternion;
+ bPoseChanDeform *pdef_info_array;
+ DualQuat *dualquats;
+ bool use_quaternion;
} ArmatureBBoneDefmatsData;
static void armature_bbone_defmats_cb(void *userdata, Link *iter, int index)
{
- ArmatureBBoneDefmatsData *data = userdata;
- bPoseChannel *pchan = (bPoseChannel *)iter;
-
- if (!(pchan->bone->flag & BONE_NO_DEFORM)) {
- bPoseChanDeform *pdef_info = &data->pdef_info_array[index];
- const bool use_quaternion = data->use_quaternion;
-
- if (use_quaternion) {
- pdef_info->dual_quat = &data->dualquats[index];
- mat4_to_dquat(pdef_info->dual_quat, pchan->bone->arm_mat, pchan->chan_mat);
- }
- }
-}
-
-void armature_deform_verts(
- Object *armOb, Object *target, const Mesh *mesh, float (*vertexCos)[3],
- float (*defMats)[3][3], int numVerts, int deformflag,
- float (*prevCos)[3], const char *defgrp_name, bGPDstroke *gps)
-{
- const bPoseChanDeform *pdef_info = NULL;
- bArmature *arm = armOb->data;
- bPoseChannel *pchan, **defnrToPC = NULL;
- int *defnrToPCIndex = NULL;
- MDeformVert *dverts = NULL;
- bDeformGroup *dg;
- float obinv[4][4], premat[4][4], postmat[4][4];
- const bool use_envelope = (deformflag & ARM_DEF_ENVELOPE) != 0;
- const bool use_quaternion = (deformflag & ARM_DEF_QUATERNION) != 0;
- const bool invert_vgroup = (deformflag & ARM_DEF_INVERT_VGROUP) != 0;
- int defbase_tot = 0; /* safety for vertexgroup index overflow */
- int i, target_totvert = 0; /* safety for vertexgroup overflow */
- bool use_dverts = false;
- int armature_def_nr;
-
- /* in editmode, or not an armature */
- if (arm->edbo || (armOb->pose == NULL)) {
- return;
- }
-
- if ((armOb->pose->flag & POSE_RECALC) != 0) {
- CLOG_ERROR(&LOG, "Trying to evaluate influence of armature '%s' which needs Pose recalc!", armOb->id.name);
- BLI_assert(0);
- }
-
- invert_m4_m4(obinv, target->obmat);
- copy_m4_m4(premat, target->obmat);
- mul_m4_m4m4(postmat, obinv, armOb->obmat);
- invert_m4_m4(premat, postmat);
-
- /* Use pre-calculated bbone deformation.
- *
- * TODO(sergey): Make this code robust somehow when there are dependency
- * cycles involved. */
- ObjectBBoneDeform *bbone_deform =
- BKE_armature_cached_bbone_deformation_get(armOb);
- if (bbone_deform == NULL || bbone_deform->pdef_info_array == NULL) {
- CLOG_ERROR(&LOG,
- "Armature does not have bbone cache %s, "
- "usually happens due to a dependency cycle.\n",
- armOb->id.name + 2);
- return;
- }
- const bPoseChanDeform *pdef_info_array = bbone_deform->pdef_info_array;
-
- /* get the def_nr for the overall armature vertex group if present */
- armature_def_nr = defgroup_name_index(target, defgrp_name);
-
- if (ELEM(target->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) {
- defbase_tot = BLI_listbase_count(&target->defbase);
-
- if (target->type == OB_MESH) {
- Mesh *me = target->data;
- dverts = me->dvert;
- if (dverts)
- target_totvert = me->totvert;
- }
- else if (target->type == OB_LATTICE) {
- Lattice *lt = target->data;
- dverts = lt->dvert;
- if (dverts)
- target_totvert = lt->pntsu * lt->pntsv * lt->pntsw;
- }
- else if (target->type == OB_GPENCIL) {
- dverts = gps->dvert;
- if (dverts)
- target_totvert = gps->totpoints;
- }
- }
-
- /* get a vertex-deform-index to posechannel array */
- if (deformflag & ARM_DEF_VGROUP) {
- if (ELEM(target->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) {
- /* if we have a Mesh, only use dverts if it has them */
- if (mesh) {
- use_dverts = (mesh->dvert != NULL);
- }
- else if (dverts) {
- use_dverts = true;
- }
-
- if (use_dverts) {
- defnrToPC = MEM_callocN(sizeof(*defnrToPC) * defbase_tot, "defnrToBone");
- defnrToPCIndex = MEM_callocN(sizeof(*defnrToPCIndex) * defbase_tot, "defnrToIndex");
- /* TODO(sergey): Some considerations here:
- *
- * - Make it more generic function, maybe even keep together with chanhash.
- * - Check whether keeping this consistent across frames gives speedup.
- * - Don't use hash for small armatures.
- */
- GHash *idx_hash = BLI_ghash_ptr_new("pose channel index by name");
- int pchan_index = 0;
- for (pchan = armOb->pose->chanbase.first; pchan != NULL; pchan = pchan->next, ++pchan_index) {
- BLI_ghash_insert(idx_hash, pchan, POINTER_FROM_INT(pchan_index));
- }
- for (i = 0, dg = target->defbase.first; dg; i++, dg = dg->next) {
- defnrToPC[i] = BKE_pose_channel_find_name(armOb->pose, dg->name);
- /* exclude non-deforming bones */
- if (defnrToPC[i]) {
- if (defnrToPC[i]->bone->flag & BONE_NO_DEFORM) {
- defnrToPC[i] = NULL;
- }
- else {
- defnrToPCIndex[i] = POINTER_AS_INT(BLI_ghash_lookup(idx_hash, defnrToPC[i]));
- }
- }
- }
- BLI_ghash_free(idx_hash, NULL, NULL);
- }
- }
- }
-
- for (i = 0; i < numVerts; i++) {
- MDeformVert *dvert;
- DualQuat sumdq, *dq = NULL;
- float *co, dco[3];
- float sumvec[3], summat[3][3];
- float *vec = NULL, (*smat)[3] = NULL;
- float contrib = 0.0f;
- float armature_weight = 1.0f; /* default to 1 if no overall def group */
- float prevco_weight = 1.0f; /* weight for optional cached vertexcos */
-
- if (use_quaternion) {
- memset(&sumdq, 0, sizeof(DualQuat));
- dq = &sumdq;
- }
- else {
- sumvec[0] = sumvec[1] = sumvec[2] = 0.0f;
- vec = sumvec;
-
- if (defMats) {
- zero_m3(summat);
- smat = summat;
- }
- }
-
- if (use_dverts || armature_def_nr != -1) {
- if (mesh) {
- BLI_assert(i < mesh->totvert);
- dvert = mesh->dvert + i;
- }
- else if (dverts && i < target_totvert)
- dvert = dverts + i;
- else
- dvert = NULL;
- }
- else
- dvert = NULL;
-
- if (armature_def_nr != -1 && dvert) {
- armature_weight = defvert_find_weight(dvert, armature_def_nr);
-
- if (invert_vgroup)
- armature_weight = 1.0f - armature_weight;
-
- /* hackish: the blending factor can be used for blending with prevCos too */
- if (prevCos) {
- prevco_weight = armature_weight;
- armature_weight = 1.0f;
- }
- }
-
- /* check if there's any point in calculating for this vert */
- if (armature_weight == 0.0f)
- continue;
-
- /* get the coord we work on */
- co = prevCos ? prevCos[i] : vertexCos[i];
-
- /* Apply the object's matrix */
- mul_m4_v3(premat, co);
-
- if (use_dverts && dvert && dvert->totweight) { /* use weight groups ? */
- MDeformWeight *dw = dvert->dw;
- int deformed = 0;
- unsigned int j;
- float acum_weight = 0;
- for (j = dvert->totweight; j != 0; j--, dw++) {
- const int index = dw->def_nr;
- if (index >= 0 && index < defbase_tot && (pchan = defnrToPC[index])) {
- float weight = dw->weight;
- Bone *bone = pchan->bone;
- pdef_info = pdef_info_array + defnrToPCIndex[index];
-
- deformed = 1;
-
- if (bone && bone->flag & BONE_MULT_VG_ENV) {
- weight *= distfactor_to_bone(co, bone->arm_head, bone->arm_tail,
- bone->rad_head, bone->rad_tail, bone->dist);
- }
-
- /* check limit of weight */
- if (target->type == OB_GPENCIL) {
- if (acum_weight + weight >= 1.0f) {
- weight = 1.0f - acum_weight;
- }
- acum_weight += weight;
- }
-
- pchan_bone_deform(pchan, pdef_info, weight, vec, dq, smat, co, &contrib);
-
- /* if acumulated weight limit exceed, exit loop */
- if ((target->type == OB_GPENCIL) && (acum_weight >= 1.0f)) {
- break;
- }
- }
- }
- /* if there are vertexgroups but not groups with bones
- * (like for softbody groups) */
- if (deformed == 0 && use_envelope) {
- pdef_info = pdef_info_array;
- for (pchan = armOb->pose->chanbase.first; pchan; pchan = pchan->next, pdef_info++) {
- if (!(pchan->bone->flag & BONE_NO_DEFORM))
- contrib += dist_bone_deform(pchan, pdef_info, vec, dq, smat, co);
- }
- }
- }
- else if (use_envelope) {
- pdef_info = pdef_info_array;
- for (pchan = armOb->pose->chanbase.first; pchan; pchan = pchan->next, pdef_info++) {
- if (!(pchan->bone->flag & BONE_NO_DEFORM))
- contrib += dist_bone_deform(pchan, pdef_info, vec, dq, smat, co);
- }
- }
-
- /* actually should be EPSILON? weight values and contrib can be like 10e-39 small */
- if (contrib > 0.0001f) {
- if (use_quaternion) {
- normalize_dq(dq, contrib);
-
- if (armature_weight != 1.0f) {
- copy_v3_v3(dco, co);
- mul_v3m3_dq(dco, (defMats) ? summat : NULL, dq);
- sub_v3_v3(dco, co);
- mul_v3_fl(dco, armature_weight);
- add_v3_v3(co, dco);
- }
- else
- mul_v3m3_dq(co, (defMats) ? summat : NULL, dq);
-
- smat = summat;
- }
- else {
- mul_v3_fl(vec, armature_weight / contrib);
- add_v3_v3v3(co, vec, co);
- }
-
- if (defMats) {
- float pre[3][3], post[3][3], tmpmat[3][3];
-
- copy_m3_m4(pre, premat);
- copy_m3_m4(post, postmat);
- copy_m3_m3(tmpmat, defMats[i]);
-
- if (!use_quaternion) /* quaternion already is scale corrected */
- mul_m3_fl(smat, armature_weight / contrib);
-
- mul_m3_series(defMats[i], post, smat, pre, tmpmat);
- }
- }
-
- /* always, check above code */
- mul_m4_v3(postmat, co);
-
- /* interpolate with previous modifier position using weight group */
- if (prevCos) {
- float mw = 1.0f - prevco_weight;
- vertexCos[i][0] = prevco_weight * vertexCos[i][0] + mw * co[0];
- vertexCos[i][1] = prevco_weight * vertexCos[i][1] + mw * co[1];
- vertexCos[i][2] = prevco_weight * vertexCos[i][2] + mw * co[2];
- }
- }
-
- if (defnrToPC)
- MEM_freeN(defnrToPC);
- if (defnrToPCIndex)
- MEM_freeN(defnrToPCIndex);
+ ArmatureBBoneDefmatsData *data = userdata;
+ bPoseChannel *pchan = (bPoseChannel *)iter;
+
+ if (!(pchan->bone->flag & BONE_NO_DEFORM)) {
+ bPoseChanDeform *pdef_info = &data->pdef_info_array[index];
+ const bool use_quaternion = data->use_quaternion;
+
+ if (use_quaternion) {
+ pdef_info->dual_quat = &data->dualquats[index];
+ mat4_to_dquat(pdef_info->dual_quat, pchan->bone->arm_mat, pchan->chan_mat);
+ }
+ }
+}
+
+void armature_deform_verts(Object *armOb,
+ Object *target,
+ const Mesh *mesh,
+ float (*vertexCos)[3],
+ float (*defMats)[3][3],
+ int numVerts,
+ int deformflag,
+ float (*prevCos)[3],
+ const char *defgrp_name,
+ bGPDstroke *gps)
+{
+ const bPoseChanDeform *pdef_info = NULL;
+ bArmature *arm = armOb->data;
+ bPoseChannel *pchan, **defnrToPC = NULL;
+ int *defnrToPCIndex = NULL;
+ MDeformVert *dverts = NULL;
+ bDeformGroup *dg;
+ float obinv[4][4], premat[4][4], postmat[4][4];
+ const bool use_envelope = (deformflag & ARM_DEF_ENVELOPE) != 0;
+ const bool use_quaternion = (deformflag & ARM_DEF_QUATERNION) != 0;
+ const bool invert_vgroup = (deformflag & ARM_DEF_INVERT_VGROUP) != 0;
+ int defbase_tot = 0; /* safety for vertexgroup index overflow */
+ int i, target_totvert = 0; /* safety for vertexgroup overflow */
+ bool use_dverts = false;
+ int armature_def_nr;
+
+ /* in editmode, or not an armature */
+ if (arm->edbo || (armOb->pose == NULL)) {
+ return;
+ }
+
+ if ((armOb->pose->flag & POSE_RECALC) != 0) {
+ CLOG_ERROR(&LOG,
+ "Trying to evaluate influence of armature '%s' which needs Pose recalc!",
+ armOb->id.name);
+ BLI_assert(0);
+ }
+
+ invert_m4_m4(obinv, target->obmat);
+ copy_m4_m4(premat, target->obmat);
+ mul_m4_m4m4(postmat, obinv, armOb->obmat);
+ invert_m4_m4(premat, postmat);
+
+ /* Use pre-calculated bbone deformation.
+ *
+ * TODO(sergey): Make this code robust somehow when there are dependency
+ * cycles involved. */
+ ObjectBBoneDeform *bbone_deform = BKE_armature_cached_bbone_deformation_get(armOb);
+ if (bbone_deform == NULL || bbone_deform->pdef_info_array == NULL) {
+ CLOG_ERROR(&LOG,
+ "Armature does not have bbone cache %s, "
+ "usually happens due to a dependency cycle.\n",
+ armOb->id.name + 2);
+ return;
+ }
+ const bPoseChanDeform *pdef_info_array = bbone_deform->pdef_info_array;
+
+ /* get the def_nr for the overall armature vertex group if present */
+ armature_def_nr = defgroup_name_index(target, defgrp_name);
+
+ if (ELEM(target->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) {
+ defbase_tot = BLI_listbase_count(&target->defbase);
+
+ if (target->type == OB_MESH) {
+ Mesh *me = target->data;
+ dverts = me->dvert;
+ if (dverts)
+ target_totvert = me->totvert;
+ }
+ else if (target->type == OB_LATTICE) {
+ Lattice *lt = target->data;
+ dverts = lt->dvert;
+ if (dverts)
+ target_totvert = lt->pntsu * lt->pntsv * lt->pntsw;
+ }
+ else if (target->type == OB_GPENCIL) {
+ dverts = gps->dvert;
+ if (dverts)
+ target_totvert = gps->totpoints;
+ }
+ }
+
+ /* get a vertex-deform-index to posechannel array */
+ if (deformflag & ARM_DEF_VGROUP) {
+ if (ELEM(target->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) {
+ /* if we have a Mesh, only use dverts if it has them */
+ if (mesh) {
+ use_dverts = (mesh->dvert != NULL);
+ }
+ else if (dverts) {
+ use_dverts = true;
+ }
+
+ if (use_dverts) {
+ defnrToPC = MEM_callocN(sizeof(*defnrToPC) * defbase_tot, "defnrToBone");
+ defnrToPCIndex = MEM_callocN(sizeof(*defnrToPCIndex) * defbase_tot, "defnrToIndex");
+ /* TODO(sergey): Some considerations here:
+ *
+ * - Make it more generic function, maybe even keep together with chanhash.
+ * - Check whether keeping this consistent across frames gives speedup.
+ * - Don't use hash for small armatures.
+ */
+ GHash *idx_hash = BLI_ghash_ptr_new("pose channel index by name");
+ int pchan_index = 0;
+ for (pchan = armOb->pose->chanbase.first; pchan != NULL;
+ pchan = pchan->next, ++pchan_index) {
+ BLI_ghash_insert(idx_hash, pchan, POINTER_FROM_INT(pchan_index));
+ }
+ for (i = 0, dg = target->defbase.first; dg; i++, dg = dg->next) {
+ defnrToPC[i] = BKE_pose_channel_find_name(armOb->pose, dg->name);
+ /* exclude non-deforming bones */
+ if (defnrToPC[i]) {
+ if (defnrToPC[i]->bone->flag & BONE_NO_DEFORM) {
+ defnrToPC[i] = NULL;
+ }
+ else {
+ defnrToPCIndex[i] = POINTER_AS_INT(BLI_ghash_lookup(idx_hash, defnrToPC[i]));
+ }
+ }
+ }
+ BLI_ghash_free(idx_hash, NULL, NULL);
+ }
+ }
+ }
+
+ for (i = 0; i < numVerts; i++) {
+ MDeformVert *dvert;
+ DualQuat sumdq, *dq = NULL;
+ float *co, dco[3];
+ float sumvec[3], summat[3][3];
+ float *vec = NULL, (*smat)[3] = NULL;
+ float contrib = 0.0f;
+ float armature_weight = 1.0f; /* default to 1 if no overall def group */
+ float prevco_weight = 1.0f; /* weight for optional cached vertexcos */
+
+ if (use_quaternion) {
+ memset(&sumdq, 0, sizeof(DualQuat));
+ dq = &sumdq;
+ }
+ else {
+ sumvec[0] = sumvec[1] = sumvec[2] = 0.0f;
+ vec = sumvec;
+
+ if (defMats) {
+ zero_m3(summat);
+ smat = summat;
+ }
+ }
+
+ if (use_dverts || armature_def_nr != -1) {
+ if (mesh) {
+ BLI_assert(i < mesh->totvert);
+ dvert = mesh->dvert + i;
+ }
+ else if (dverts && i < target_totvert)
+ dvert = dverts + i;
+ else
+ dvert = NULL;
+ }
+ else
+ dvert = NULL;
+
+ if (armature_def_nr != -1 && dvert) {
+ armature_weight = defvert_find_weight(dvert, armature_def_nr);
+
+ if (invert_vgroup)
+ armature_weight = 1.0f - armature_weight;
+
+ /* hackish: the blending factor can be used for blending with prevCos too */
+ if (prevCos) {
+ prevco_weight = armature_weight;
+ armature_weight = 1.0f;
+ }
+ }
+
+ /* check if there's any point in calculating for this vert */
+ if (armature_weight == 0.0f)
+ continue;
+
+ /* get the coord we work on */
+ co = prevCos ? prevCos[i] : vertexCos[i];
+
+ /* Apply the object's matrix */
+ mul_m4_v3(premat, co);
+
+ if (use_dverts && dvert && dvert->totweight) { /* use weight groups ? */
+ MDeformWeight *dw = dvert->dw;
+ int deformed = 0;
+ unsigned int j;
+ float acum_weight = 0;
+ for (j = dvert->totweight; j != 0; j--, dw++) {
+ const int index = dw->def_nr;
+ if (index >= 0 && index < defbase_tot && (pchan = defnrToPC[index])) {
+ float weight = dw->weight;
+ Bone *bone = pchan->bone;
+ pdef_info = pdef_info_array + defnrToPCIndex[index];
+
+ deformed = 1;
+
+ if (bone && bone->flag & BONE_MULT_VG_ENV) {
+ weight *= distfactor_to_bone(
+ co, bone->arm_head, bone->arm_tail, bone->rad_head, bone->rad_tail, bone->dist);
+ }
+
+ /* check limit of weight */
+ if (target->type == OB_GPENCIL) {
+ if (acum_weight + weight >= 1.0f) {
+ weight = 1.0f - acum_weight;
+ }
+ acum_weight += weight;
+ }
+
+ pchan_bone_deform(pchan, pdef_info, weight, vec, dq, smat, co, &contrib);
+
+ /* if acumulated weight limit exceed, exit loop */
+ if ((target->type == OB_GPENCIL) && (acum_weight >= 1.0f)) {
+ break;
+ }
+ }
+ }
+ /* if there are vertexgroups but not groups with bones
+ * (like for softbody groups) */
+ if (deformed == 0 && use_envelope) {
+ pdef_info = pdef_info_array;
+ for (pchan = armOb->pose->chanbase.first; pchan; pchan = pchan->next, pdef_info++) {
+ if (!(pchan->bone->flag & BONE_NO_DEFORM))
+ contrib += dist_bone_deform(pchan, pdef_info, vec, dq, smat, co);
+ }
+ }
+ }
+ else if (use_envelope) {
+ pdef_info = pdef_info_array;
+ for (pchan = armOb->pose->chanbase.first; pchan; pchan = pchan->next, pdef_info++) {
+ if (!(pchan->bone->flag & BONE_NO_DEFORM))
+ contrib += dist_bone_deform(pchan, pdef_info, vec, dq, smat, co);
+ }
+ }
+
+ /* actually should be EPSILON? weight values and contrib can be like 10e-39 small */
+ if (contrib > 0.0001f) {
+ if (use_quaternion) {
+ normalize_dq(dq, contrib);
+
+ if (armature_weight != 1.0f) {
+ copy_v3_v3(dco, co);
+ mul_v3m3_dq(dco, (defMats) ? summat : NULL, dq);
+ sub_v3_v3(dco, co);
+ mul_v3_fl(dco, armature_weight);
+ add_v3_v3(co, dco);
+ }
+ else
+ mul_v3m3_dq(co, (defMats) ? summat : NULL, dq);
+
+ smat = summat;
+ }
+ else {
+ mul_v3_fl(vec, armature_weight / contrib);
+ add_v3_v3v3(co, vec, co);
+ }
+
+ if (defMats) {
+ float pre[3][3], post[3][3], tmpmat[3][3];
+
+ copy_m3_m4(pre, premat);
+ copy_m3_m4(post, postmat);
+ copy_m3_m3(tmpmat, defMats[i]);
+
+ if (!use_quaternion) /* quaternion already is scale corrected */
+ mul_m3_fl(smat, armature_weight / contrib);
+
+ mul_m3_series(defMats[i], post, smat, pre, tmpmat);
+ }
+ }
+
+ /* always, check above code */
+ mul_m4_v3(postmat, co);
+
+ /* interpolate with previous modifier position using weight group */
+ if (prevCos) {
+ float mw = 1.0f - prevco_weight;
+ vertexCos[i][0] = prevco_weight * vertexCos[i][0] + mw * co[0];
+ vertexCos[i][1] = prevco_weight * vertexCos[i][1] + mw * co[1];
+ vertexCos[i][2] = prevco_weight * vertexCos[i][2] + mw * co[2];
+ }
+ }
+
+ if (defnrToPC)
+ MEM_freeN(defnrToPC);
+ if (defnrToPCIndex)
+ MEM_freeN(defnrToPCIndex);
}
/* ************ END Armature Deform ******************* */
-void get_objectspace_bone_matrix(struct Bone *bone, float M_accumulatedMatrix[4][4], int UNUSED(root),
+void get_objectspace_bone_matrix(struct Bone *bone,
+ float M_accumulatedMatrix[4][4],
+ int UNUSED(root),
int UNUSED(posed))
{
- copy_m4_m4(M_accumulatedMatrix, bone->arm_mat);
+ copy_m4_m4(M_accumulatedMatrix, bone->arm_mat);
}
/* **************** Space to Space API ****************** */
@@ -1463,17 +1554,17 @@ void get_objectspace_bone_matrix(struct Bone *bone, float M_accumulatedMatrix[4]
/* Convert World-Space Matrix to Pose-Space Matrix */
void BKE_armature_mat_world_to_pose(Object *ob, float inmat[4][4], float outmat[4][4])
{
- float obmat[4][4];
+ float obmat[4][4];
- /* prevent crashes */
- if (ob == NULL)
- return;
+ /* prevent crashes */
+ if (ob == NULL)
+ return;
- /* get inverse of (armature) object's matrix */
- invert_m4_m4(obmat, ob->obmat);
+ /* get inverse of (armature) object's matrix */
+ invert_m4_m4(obmat, ob->obmat);
- /* multiply given matrix by object's-inverse to find pose-space matrix */
- mul_m4_m4m4(outmat, inmat, obmat);
+ /* multiply given matrix by object's-inverse to find pose-space matrix */
+ mul_m4_m4m4(outmat, inmat, obmat);
}
/* Convert World-Space Location to Pose-Space Location
@@ -1481,32 +1572,32 @@ void BKE_armature_mat_world_to_pose(Object *ob, float inmat[4][4], float outmat[
* pose-channel into its local space (i.e. 'visual'-keyframing) */
void BKE_armature_loc_world_to_pose(Object *ob, const float inloc[3], float outloc[3])
{
- float xLocMat[4][4];
- float nLocMat[4][4];
+ float xLocMat[4][4];
+ float nLocMat[4][4];
- /* build matrix for location */
- unit_m4(xLocMat);
- copy_v3_v3(xLocMat[3], inloc);
+ /* build matrix for location */
+ unit_m4(xLocMat);
+ copy_v3_v3(xLocMat[3], inloc);
- /* get bone-space cursor matrix and extract location */
- BKE_armature_mat_world_to_pose(ob, xLocMat, nLocMat);
- copy_v3_v3(outloc, nLocMat[3]);
+ /* get bone-space cursor matrix and extract location */
+ BKE_armature_mat_world_to_pose(ob, xLocMat, nLocMat);
+ copy_v3_v3(outloc, nLocMat[3]);
}
/* Simple helper, computes the offset bone matrix.
* offs_bone = yoffs(b-1) + root(b) + bonemat(b). */
void BKE_bone_offset_matrix_get(const Bone *bone, float offs_bone[4][4])
{
- BLI_assert(bone->parent != NULL);
+ BLI_assert(bone->parent != NULL);
- /* Bone transform itself. */
- copy_m4_m3(offs_bone, bone->bone_mat);
+ /* Bone transform itself. */
+ copy_m4_m3(offs_bone, bone->bone_mat);
- /* The bone's root offset (is in the parent's coordinate system). */
- copy_v3_v3(offs_bone[3], bone->head);
+ /* The bone's root offset (is in the parent's coordinate system). */
+ copy_v3_v3(offs_bone[3], bone->head);
- /* Get the length translation of parent (length along y axis). */
- offs_bone[3][1] += bone->parent->length;
+ /* Get the length translation of parent (length along y axis). */
+ offs_bone[3][1] += bone->parent->length;
}
/* Construct the matrices (rot/scale and loc) to apply the PoseChannels into the armature (object) space.
@@ -1526,26 +1617,28 @@ void BKE_bone_offset_matrix_get(const Bone *bone, float offs_bone[4][4])
* pose-channel into its local space (i.e. 'visual'-keyframing).
* (note: I don't understand that, so I keep it :p --mont29).
*/
-void BKE_bone_parent_transform_calc_from_pchan(const bPoseChannel *pchan, BoneParentTransform *r_bpt)
+void BKE_bone_parent_transform_calc_from_pchan(const bPoseChannel *pchan,
+ BoneParentTransform *r_bpt)
{
- const Bone *bone, *parbone;
- const bPoseChannel *parchan;
+ const Bone *bone, *parbone;
+ const bPoseChannel *parchan;
- /* set up variables for quicker access below */
- bone = pchan->bone;
- parbone = bone->parent;
- parchan = pchan->parent;
+ /* set up variables for quicker access below */
+ bone = pchan->bone;
+ parbone = bone->parent;
+ parchan = pchan->parent;
- if (parchan) {
- float offs_bone[4][4];
- /* yoffs(b-1) + root(b) + bonemat(b). */
- BKE_bone_offset_matrix_get(bone, offs_bone);
+ if (parchan) {
+ float offs_bone[4][4];
+ /* yoffs(b-1) + root(b) + bonemat(b). */
+ BKE_bone_offset_matrix_get(bone, offs_bone);
- BKE_bone_parent_transform_calc_from_matrices(bone->flag, offs_bone, parbone->arm_mat, parchan->pose_mat, r_bpt);
- }
- else {
- BKE_bone_parent_transform_calc_from_matrices(bone->flag, bone->arm_mat, NULL, NULL, r_bpt);
- }
+ BKE_bone_parent_transform_calc_from_matrices(
+ bone->flag, offs_bone, parbone->arm_mat, parchan->pose_mat, r_bpt);
+ }
+ else {
+ BKE_bone_parent_transform_calc_from_matrices(bone->flag, bone->arm_mat, NULL, NULL, r_bpt);
+ }
}
/* Compute the parent transform using data decoupled from specific data structures.
@@ -1554,110 +1647,114 @@ void BKE_bone_parent_transform_calc_from_pchan(const bPoseChannel *pchan, BonePa
* offs_bone: delta from parent to current arm_mat (or just arm_mat if no parent)
* parent_arm_mat, parent_pose_mat: arm_mat and pose_mat of parent, or NULL
* r_bpt: OUTPUT parent transform */
-void BKE_bone_parent_transform_calc_from_matrices(
- int bone_flag, const float offs_bone[4][4], const float parent_arm_mat[4][4], const float parent_pose_mat[4][4],
- BoneParentTransform *r_bpt)
-{
- if (parent_pose_mat) {
- /* Compose the rotscale matrix for this bone. */
- if ((bone_flag & BONE_HINGE) && (bone_flag & BONE_NO_SCALE)) {
- /* Parent rest rotation and scale. */
- mul_m4_m4m4(r_bpt->rotscale_mat, parent_arm_mat, offs_bone);
- }
- else if (bone_flag & BONE_HINGE) {
- /* Parent rest rotation and pose scale. */
- float tmat[4][4], tscale[3];
-
- /* Extract the scale of the parent pose matrix. */
- mat4_to_size(tscale, parent_pose_mat);
- size_to_mat4(tmat, tscale);
-
- /* Applies the parent pose scale to the rest matrix. */
- mul_m4_m4m4(tmat, tmat, parent_arm_mat);
-
- mul_m4_m4m4(r_bpt->rotscale_mat, tmat, offs_bone);
- }
- else if (bone_flag & BONE_NO_SCALE) {
- /* Parent pose rotation and rest scale (i.e. no scaling). */
- float tmat[4][4];
- copy_m4_m4(tmat, parent_pose_mat);
- normalize_m4(tmat);
- mul_m4_m4m4(r_bpt->rotscale_mat, tmat, offs_bone);
- }
- else
- mul_m4_m4m4(r_bpt->rotscale_mat, parent_pose_mat, offs_bone);
-
- /* Compose the loc matrix for this bone. */
- /* NOTE: That version does not modify bone's loc when HINGE/NO_SCALE options are set. */
-
- /* In this case, use the object's space *orientation*. */
- if (bone_flag & BONE_NO_LOCAL_LOCATION) {
- /* XXX I'm sure that code can be simplified! */
- float bone_loc[4][4], bone_rotscale[3][3], tmat4[4][4], tmat3[3][3];
- unit_m4(bone_loc);
- unit_m4(r_bpt->loc_mat);
- unit_m4(tmat4);
-
- mul_v3_m4v3(bone_loc[3], parent_pose_mat, offs_bone[3]);
-
- unit_m3(bone_rotscale);
- copy_m3_m4(tmat3, parent_pose_mat);
- mul_m3_m3m3(bone_rotscale, tmat3, bone_rotscale);
-
- copy_m4_m3(tmat4, bone_rotscale);
- mul_m4_m4m4(r_bpt->loc_mat, bone_loc, tmat4);
- }
- /* Those flags do not affect position, use plain parent transform space! */
- else if (bone_flag & (BONE_HINGE | BONE_NO_SCALE)) {
- mul_m4_m4m4(r_bpt->loc_mat, parent_pose_mat, offs_bone);
- }
- /* Else (i.e. default, usual case), just use the same matrix for rotation/scaling, and location. */
- else
- copy_m4_m4(r_bpt->loc_mat, r_bpt->rotscale_mat);
- }
- /* Root bones. */
- else {
- /* Rotation/scaling. */
- copy_m4_m4(r_bpt->rotscale_mat, offs_bone);
- /* Translation. */
- if (bone_flag & BONE_NO_LOCAL_LOCATION) {
- /* Translation of arm_mat, without the rotation. */
- unit_m4(r_bpt->loc_mat);
- copy_v3_v3(r_bpt->loc_mat[3], offs_bone[3]);
- }
- else
- copy_m4_m4(r_bpt->loc_mat, r_bpt->rotscale_mat);
- }
+void BKE_bone_parent_transform_calc_from_matrices(int bone_flag,
+ const float offs_bone[4][4],
+ const float parent_arm_mat[4][4],
+ const float parent_pose_mat[4][4],
+ BoneParentTransform *r_bpt)
+{
+ if (parent_pose_mat) {
+ /* Compose the rotscale matrix for this bone. */
+ if ((bone_flag & BONE_HINGE) && (bone_flag & BONE_NO_SCALE)) {
+ /* Parent rest rotation and scale. */
+ mul_m4_m4m4(r_bpt->rotscale_mat, parent_arm_mat, offs_bone);
+ }
+ else if (bone_flag & BONE_HINGE) {
+ /* Parent rest rotation and pose scale. */
+ float tmat[4][4], tscale[3];
+
+ /* Extract the scale of the parent pose matrix. */
+ mat4_to_size(tscale, parent_pose_mat);
+ size_to_mat4(tmat, tscale);
+
+ /* Applies the parent pose scale to the rest matrix. */
+ mul_m4_m4m4(tmat, tmat, parent_arm_mat);
+
+ mul_m4_m4m4(r_bpt->rotscale_mat, tmat, offs_bone);
+ }
+ else if (bone_flag & BONE_NO_SCALE) {
+ /* Parent pose rotation and rest scale (i.e. no scaling). */
+ float tmat[4][4];
+ copy_m4_m4(tmat, parent_pose_mat);
+ normalize_m4(tmat);
+ mul_m4_m4m4(r_bpt->rotscale_mat, tmat, offs_bone);
+ }
+ else
+ mul_m4_m4m4(r_bpt->rotscale_mat, parent_pose_mat, offs_bone);
+
+ /* Compose the loc matrix for this bone. */
+ /* NOTE: That version does not modify bone's loc when HINGE/NO_SCALE options are set. */
+
+ /* In this case, use the object's space *orientation*. */
+ if (bone_flag & BONE_NO_LOCAL_LOCATION) {
+ /* XXX I'm sure that code can be simplified! */
+ float bone_loc[4][4], bone_rotscale[3][3], tmat4[4][4], tmat3[3][3];
+ unit_m4(bone_loc);
+ unit_m4(r_bpt->loc_mat);
+ unit_m4(tmat4);
+
+ mul_v3_m4v3(bone_loc[3], parent_pose_mat, offs_bone[3]);
+
+ unit_m3(bone_rotscale);
+ copy_m3_m4(tmat3, parent_pose_mat);
+ mul_m3_m3m3(bone_rotscale, tmat3, bone_rotscale);
+
+ copy_m4_m3(tmat4, bone_rotscale);
+ mul_m4_m4m4(r_bpt->loc_mat, bone_loc, tmat4);
+ }
+ /* Those flags do not affect position, use plain parent transform space! */
+ else if (bone_flag & (BONE_HINGE | BONE_NO_SCALE)) {
+ mul_m4_m4m4(r_bpt->loc_mat, parent_pose_mat, offs_bone);
+ }
+ /* Else (i.e. default, usual case), just use the same matrix for rotation/scaling, and location. */
+ else
+ copy_m4_m4(r_bpt->loc_mat, r_bpt->rotscale_mat);
+ }
+ /* Root bones. */
+ else {
+ /* Rotation/scaling. */
+ copy_m4_m4(r_bpt->rotscale_mat, offs_bone);
+ /* Translation. */
+ if (bone_flag & BONE_NO_LOCAL_LOCATION) {
+ /* Translation of arm_mat, without the rotation. */
+ unit_m4(r_bpt->loc_mat);
+ copy_v3_v3(r_bpt->loc_mat[3], offs_bone[3]);
+ }
+ else
+ copy_m4_m4(r_bpt->loc_mat, r_bpt->rotscale_mat);
+ }
}
void BKE_bone_parent_transform_clear(struct BoneParentTransform *bpt)
{
- unit_m4(bpt->rotscale_mat);
- unit_m4(bpt->loc_mat);
+ unit_m4(bpt->rotscale_mat);
+ unit_m4(bpt->loc_mat);
}
void BKE_bone_parent_transform_invert(struct BoneParentTransform *bpt)
{
- invert_m4(bpt->rotscale_mat);
- invert_m4(bpt->loc_mat);
+ invert_m4(bpt->rotscale_mat);
+ invert_m4(bpt->loc_mat);
}
-void BKE_bone_parent_transform_combine(
- const struct BoneParentTransform *in1, const struct BoneParentTransform *in2,
- struct BoneParentTransform *result)
+void BKE_bone_parent_transform_combine(const struct BoneParentTransform *in1,
+ const struct BoneParentTransform *in2,
+ struct BoneParentTransform *result)
{
- mul_m4_m4m4(result->rotscale_mat, in1->rotscale_mat, in2->rotscale_mat);
- mul_m4_m4m4(result->loc_mat, in1->loc_mat, in2->loc_mat);
+ mul_m4_m4m4(result->rotscale_mat, in1->rotscale_mat, in2->rotscale_mat);
+ mul_m4_m4m4(result->loc_mat, in1->loc_mat, in2->loc_mat);
}
-void BKE_bone_parent_transform_apply(const struct BoneParentTransform *bpt, const float inmat[4][4], float outmat[4][4])
+void BKE_bone_parent_transform_apply(const struct BoneParentTransform *bpt,
+ const float inmat[4][4],
+ float outmat[4][4])
{
- /* in case inmat == outmat */
- float tmploc[3];
- copy_v3_v3(tmploc, inmat[3]);
+ /* in case inmat == outmat */
+ float tmploc[3];
+ copy_v3_v3(tmploc, inmat[3]);
- mul_m4_m4m4(outmat, bpt->rotscale_mat, inmat);
- mul_v3_m4v3(outmat[3], bpt->loc_mat, tmploc);
+ mul_m4_m4m4(outmat, bpt->rotscale_mat, inmat);
+ mul_v3_m4v3(outmat[3], bpt->loc_mat, tmploc);
}
/* Convert Pose-Space Matrix to Bone-Space Matrix.
@@ -1665,20 +1762,20 @@ void BKE_bone_parent_transform_apply(const struct BoneParentTransform *bpt, cons
* pose-channel into its local space (i.e. 'visual'-keyframing) */
void BKE_armature_mat_pose_to_bone(bPoseChannel *pchan, float inmat[4][4], float outmat[4][4])
{
- BoneParentTransform bpt;
+ BoneParentTransform bpt;
- BKE_bone_parent_transform_calc_from_pchan(pchan, &bpt);
- BKE_bone_parent_transform_invert(&bpt);
- BKE_bone_parent_transform_apply(&bpt, inmat, outmat);
+ BKE_bone_parent_transform_calc_from_pchan(pchan, &bpt);
+ BKE_bone_parent_transform_invert(&bpt);
+ BKE_bone_parent_transform_apply(&bpt, inmat, outmat);
}
/* Convert Bone-Space Matrix to Pose-Space Matrix. */
void BKE_armature_mat_bone_to_pose(bPoseChannel *pchan, float inmat[4][4], float outmat[4][4])
{
- BoneParentTransform bpt;
+ BoneParentTransform bpt;
- BKE_bone_parent_transform_calc_from_pchan(pchan, &bpt);
- BKE_bone_parent_transform_apply(&bpt, inmat, outmat);
+ BKE_bone_parent_transform_calc_from_pchan(pchan, &bpt);
+ BKE_bone_parent_transform_apply(&bpt, inmat, outmat);
}
/* Convert Pose-Space Location to Bone-Space Location
@@ -1686,33 +1783,37 @@ void BKE_armature_mat_bone_to_pose(bPoseChannel *pchan, float inmat[4][4], float
* pose-channel into its local space (i.e. 'visual'-keyframing) */
void BKE_armature_loc_pose_to_bone(bPoseChannel *pchan, const float inloc[3], float outloc[3])
{
- float xLocMat[4][4];
- float nLocMat[4][4];
+ float xLocMat[4][4];
+ float nLocMat[4][4];
- /* build matrix for location */
- unit_m4(xLocMat);
- copy_v3_v3(xLocMat[3], inloc);
+ /* build matrix for location */
+ unit_m4(xLocMat);
+ copy_v3_v3(xLocMat[3], inloc);
- /* get bone-space cursor matrix and extract location */
- BKE_armature_mat_pose_to_bone(pchan, xLocMat, nLocMat);
- copy_v3_v3(outloc, nLocMat[3]);
+ /* get bone-space cursor matrix and extract location */
+ BKE_armature_mat_pose_to_bone(pchan, xLocMat, nLocMat);
+ copy_v3_v3(outloc, nLocMat[3]);
}
-void BKE_armature_mat_pose_to_bone_ex(struct Depsgraph *depsgraph, Object *ob, bPoseChannel *pchan, float inmat[4][4], float outmat[4][4])
+void BKE_armature_mat_pose_to_bone_ex(struct Depsgraph *depsgraph,
+ Object *ob,
+ bPoseChannel *pchan,
+ float inmat[4][4],
+ float outmat[4][4])
{
- bPoseChannel work_pchan = *pchan;
+ bPoseChannel work_pchan = *pchan;
- /* recalculate pose matrix with only parent transformations,
- * bone loc/sca/rot is ignored, scene and frame are not used. */
- BKE_pose_where_is_bone(depsgraph, NULL, ob, &work_pchan, 0.0f, false);
+ /* recalculate pose matrix with only parent transformations,
+ * bone loc/sca/rot is ignored, scene and frame are not used. */
+ BKE_pose_where_is_bone(depsgraph, NULL, ob, &work_pchan, 0.0f, false);
- /* find the matrix, need to remove the bone transforms first so this is
- * calculated as a matrix to set rather then a difference ontop of what's
- * already there. */
- unit_m4(outmat);
- BKE_pchan_apply_mat4(&work_pchan, outmat, false);
+ /* find the matrix, need to remove the bone transforms first so this is
+ * calculated as a matrix to set rather then a difference ontop of what's
+ * already there. */
+ unit_m4(outmat);
+ BKE_pchan_apply_mat4(&work_pchan, outmat, false);
- BKE_armature_mat_pose_to_bone(&work_pchan, inmat, outmat);
+ BKE_armature_mat_pose_to_bone(&work_pchan, inmat, outmat);
}
/**
@@ -1720,22 +1821,22 @@ void BKE_armature_mat_pose_to_bone_ex(struct Depsgraph *depsgraph, Object *ob, b
*/
void BKE_pchan_mat3_to_rot(bPoseChannel *pchan, float mat[3][3], bool use_compat)
{
- BLI_ASSERT_UNIT_M3(mat);
+ BLI_ASSERT_UNIT_M3(mat);
- switch (pchan->rotmode) {
- case ROT_MODE_QUAT:
- mat3_normalized_to_quat(pchan->quat, mat);
- break;
- case ROT_MODE_AXISANGLE:
- mat3_normalized_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, mat);
- break;
- default: /* euler */
- if (use_compat)
- mat3_normalized_to_compatible_eulO(pchan->eul, pchan->eul, pchan->rotmode, mat);
- else
- mat3_normalized_to_eulO(pchan->eul, pchan->rotmode, mat);
- break;
- }
+ switch (pchan->rotmode) {
+ case ROT_MODE_QUAT:
+ mat3_normalized_to_quat(pchan->quat, mat);
+ break;
+ case ROT_MODE_AXISANGLE:
+ mat3_normalized_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, mat);
+ break;
+ default: /* euler */
+ if (use_compat)
+ mat3_normalized_to_compatible_eulO(pchan->eul, pchan->eul, pchan->rotmode, mat);
+ else
+ mat3_normalized_to_eulO(pchan->eul, pchan->rotmode, mat);
+ break;
+ }
}
/**
@@ -1744,9 +1845,9 @@ void BKE_pchan_mat3_to_rot(bPoseChannel *pchan, float mat[3][3], bool use_compat
*/
void BKE_pchan_apply_mat4(bPoseChannel *pchan, float mat[4][4], bool use_compat)
{
- float rot[3][3];
- mat4_to_loc_rot_size(pchan->loc, rot, pchan->size, mat);
- BKE_pchan_mat3_to_rot(pchan, rot, use_compat);
+ float rot[3][3];
+ mat4_to_loc_rot_size(pchan->loc, rot, pchan->size, mat);
+ BKE_pchan_mat3_to_rot(pchan, rot, use_compat);
}
/**
@@ -1754,12 +1855,14 @@ void BKE_pchan_apply_mat4(bPoseChannel *pchan, float mat[4][4], bool use_compat)
* 'visual' transformation of pose-channel.
* (used by the Visual-Keyframing stuff).
*/
-void BKE_armature_mat_pose_to_delta(float delta_mat[4][4], float pose_mat[4][4], float arm_mat[4][4])
+void BKE_armature_mat_pose_to_delta(float delta_mat[4][4],
+ float pose_mat[4][4],
+ float arm_mat[4][4])
{
- float imat[4][4];
+ float imat[4][4];
- invert_m4_m4(imat, arm_mat);
- mul_m4_m4m4(delta_mat, imat, pose_mat);
+ invert_m4_m4(imat, arm_mat);
+ mul_m4_m4m4(delta_mat, imat, pose_mat);
}
/* **************** Rotation Mode Conversions ****************************** */
@@ -1768,49 +1871,50 @@ void BKE_armature_mat_pose_to_delta(float delta_mat[4][4], float pose_mat[4][4],
/* Called from RNA when rotation mode changes
* - the result should be that the rotations given in the provided pointers have had conversions
* applied (as appropriate), such that the rotation of the element hasn't 'visually' changed */
-void BKE_rotMode_change_values(float quat[4], float eul[3], float axis[3], float *angle, short oldMode, short newMode)
-{
- /* check if any change - if so, need to convert data */
- if (newMode > 0) { /* to euler */
- if (oldMode == ROT_MODE_AXISANGLE) {
- /* axis-angle to euler */
- axis_angle_to_eulO(eul, newMode, axis, *angle);
- }
- else if (oldMode == ROT_MODE_QUAT) {
- /* quat to euler */
- normalize_qt(quat);
- quat_to_eulO(eul, newMode, quat);
- }
- /* else { no conversion needed } */
- }
- else if (newMode == ROT_MODE_QUAT) { /* to quat */
- if (oldMode == ROT_MODE_AXISANGLE) {
- /* axis angle to quat */
- axis_angle_to_quat(quat, axis, *angle);
- }
- else if (oldMode > 0) {
- /* euler to quat */
- eulO_to_quat(quat, eul, oldMode);
- }
- /* else { no conversion needed } */
- }
- else if (newMode == ROT_MODE_AXISANGLE) { /* to axis-angle */
- if (oldMode > 0) {
- /* euler to axis angle */
- eulO_to_axis_angle(axis, angle, eul, oldMode);
- }
- else if (oldMode == ROT_MODE_QUAT) {
- /* quat to axis angle */
- normalize_qt(quat);
- quat_to_axis_angle(axis, angle, quat);
- }
-
- /* when converting to axis-angle, we need a special exception for the case when there is no axis */
- if (IS_EQF(axis[0], axis[1]) && IS_EQF(axis[1], axis[2])) {
- /* for now, rotate around y-axis then (so that it simply becomes the roll) */
- axis[1] = 1.0f;
- }
- }
+void BKE_rotMode_change_values(
+ float quat[4], float eul[3], float axis[3], float *angle, short oldMode, short newMode)
+{
+ /* check if any change - if so, need to convert data */
+ if (newMode > 0) { /* to euler */
+ if (oldMode == ROT_MODE_AXISANGLE) {
+ /* axis-angle to euler */
+ axis_angle_to_eulO(eul, newMode, axis, *angle);
+ }
+ else if (oldMode == ROT_MODE_QUAT) {
+ /* quat to euler */
+ normalize_qt(quat);
+ quat_to_eulO(eul, newMode, quat);
+ }
+ /* else { no conversion needed } */
+ }
+ else if (newMode == ROT_MODE_QUAT) { /* to quat */
+ if (oldMode == ROT_MODE_AXISANGLE) {
+ /* axis angle to quat */
+ axis_angle_to_quat(quat, axis, *angle);
+ }
+ else if (oldMode > 0) {
+ /* euler to quat */
+ eulO_to_quat(quat, eul, oldMode);
+ }
+ /* else { no conversion needed } */
+ }
+ else if (newMode == ROT_MODE_AXISANGLE) { /* to axis-angle */
+ if (oldMode > 0) {
+ /* euler to axis angle */
+ eulO_to_axis_angle(axis, angle, eul, oldMode);
+ }
+ else if (oldMode == ROT_MODE_QUAT) {
+ /* quat to axis angle */
+ normalize_qt(quat);
+ quat_to_axis_angle(axis, angle, quat);
+ }
+
+ /* when converting to axis-angle, we need a special exception for the case when there is no axis */
+ if (IS_EQF(axis[0], axis[1]) && IS_EQF(axis[1], axis[2])) {
+ /* for now, rotate around y-axis then (so that it simply becomes the roll) */
+ axis[1] = 1.0f;
+ }
+ }
}
/* **************** The new & simple (but OK!) armature evaluation ********* */
@@ -1837,26 +1941,26 @@ void BKE_rotMode_change_values(float quat[4], float eul[3], float axis[3], float
* "mat" must contain only a rotation, and no scaling. */
void mat3_to_vec_roll(const float mat[3][3], float r_vec[3], float *r_roll)
{
- if (r_vec) {
- copy_v3_v3(r_vec, mat[1]);
- }
+ if (r_vec) {
+ copy_v3_v3(r_vec, mat[1]);
+ }
- if (r_roll) {
- mat3_vec_to_roll(mat, mat[1], r_roll);
- }
+ if (r_roll) {
+ mat3_vec_to_roll(mat, mat[1], r_roll);
+ }
}
/* Computes roll around the vector that best approximates the matrix.
* If vec is the Y vector from purely rotational mat, result should be exact. */
void mat3_vec_to_roll(const float mat[3][3], const float vec[3], float *r_roll)
{
- float vecmat[3][3], vecmatinv[3][3], rollmat[3][3];
+ float vecmat[3][3], vecmatinv[3][3], rollmat[3][3];
- vec_roll_to_mat3(vec, 0.0f, vecmat);
- invert_m3_m3(vecmatinv, vecmat);
- mul_m3_m3m3(rollmat, vecmatinv, mat);
+ vec_roll_to_mat3(vec, 0.0f, vecmat);
+ invert_m3_m3(vecmatinv, vecmat);
+ mul_m3_m3m3(rollmat, vecmatinv, mat);
- *r_roll = atan2f(rollmat[2][0], rollmat[2][2]);
+ *r_roll = atan2f(rollmat[2][0], rollmat[2][2]);
}
/* Calculates the rest matrix of a bone based on its vector and a roll around that vector. */
@@ -1910,56 +2014,56 @@ void vec_roll_to_mat3_normalized(const float nor[3], const float roll, float mat
#define THETA_THRESHOLD_NEGY 1.0e-9f
#define THETA_THRESHOLD_NEGY_CLOSE 1.0e-5f
- float theta;
- float rMatrix[3][3], bMatrix[3][3];
-
- BLI_ASSERT_UNIT_V3(nor);
-
- theta = 1.0f + nor[1];
-
- /* With old algo, 1.0e-13f caused T23954 and T31333, 1.0e-6f caused T27675 and T30438,
- * so using 1.0e-9f as best compromise.
- *
- * New algo is supposed much more precise, since less complex computations are performed,
- * but it uses two different threshold values...
- *
- * Note: When theta is close to zero, we have to check we do have non-null X/Z components as well
- * (due to float precision errors, we can have nor = (0.0, 0.99999994, 0.0)...).
- */
- if (theta > THETA_THRESHOLD_NEGY_CLOSE || ((nor[0] || nor[2]) && theta > THETA_THRESHOLD_NEGY)) {
- /* nor is *not* -Y.
- * We got these values for free... so be happy with it... ;)
- */
- bMatrix[0][1] = -nor[0];
- bMatrix[1][0] = nor[0];
- bMatrix[1][1] = nor[1];
- bMatrix[1][2] = nor[2];
- bMatrix[2][1] = -nor[2];
- if (theta > THETA_THRESHOLD_NEGY_CLOSE) {
- /* If nor is far enough from -Y, apply the general case. */
- bMatrix[0][0] = 1 - nor[0] * nor[0] / theta;
- bMatrix[2][2] = 1 - nor[2] * nor[2] / theta;
- bMatrix[2][0] = bMatrix[0][2] = -nor[0] * nor[2] / theta;
- }
- else {
- /* If nor is too close to -Y, apply the special case. */
- theta = nor[0] * nor[0] + nor[2] * nor[2];
- bMatrix[0][0] = (nor[0] + nor[2]) * (nor[0] - nor[2]) / -theta;
- bMatrix[2][2] = -bMatrix[0][0];
- bMatrix[2][0] = bMatrix[0][2] = 2.0f * nor[0] * nor[2] / theta;
- }
- }
- else {
- /* If nor is -Y, simple symmetry by Z axis. */
- unit_m3(bMatrix);
- bMatrix[0][0] = bMatrix[1][1] = -1.0;
- }
-
- /* Make Roll matrix */
- axis_angle_normalized_to_mat3(rMatrix, nor, roll);
-
- /* Combine and output result */
- mul_m3_m3m3(mat, rMatrix, bMatrix);
+ float theta;
+ float rMatrix[3][3], bMatrix[3][3];
+
+ BLI_ASSERT_UNIT_V3(nor);
+
+ theta = 1.0f + nor[1];
+
+ /* With old algo, 1.0e-13f caused T23954 and T31333, 1.0e-6f caused T27675 and T30438,
+ * so using 1.0e-9f as best compromise.
+ *
+ * New algo is supposed much more precise, since less complex computations are performed,
+ * but it uses two different threshold values...
+ *
+ * Note: When theta is close to zero, we have to check we do have non-null X/Z components as well
+ * (due to float precision errors, we can have nor = (0.0, 0.99999994, 0.0)...).
+ */
+ if (theta > THETA_THRESHOLD_NEGY_CLOSE || ((nor[0] || nor[2]) && theta > THETA_THRESHOLD_NEGY)) {
+ /* nor is *not* -Y.
+ * We got these values for free... so be happy with it... ;)
+ */
+ bMatrix[0][1] = -nor[0];
+ bMatrix[1][0] = nor[0];
+ bMatrix[1][1] = nor[1];
+ bMatrix[1][2] = nor[2];
+ bMatrix[2][1] = -nor[2];
+ if (theta > THETA_THRESHOLD_NEGY_CLOSE) {
+ /* If nor is far enough from -Y, apply the general case. */
+ bMatrix[0][0] = 1 - nor[0] * nor[0] / theta;
+ bMatrix[2][2] = 1 - nor[2] * nor[2] / theta;
+ bMatrix[2][0] = bMatrix[0][2] = -nor[0] * nor[2] / theta;
+ }
+ else {
+ /* If nor is too close to -Y, apply the special case. */
+ theta = nor[0] * nor[0] + nor[2] * nor[2];
+ bMatrix[0][0] = (nor[0] + nor[2]) * (nor[0] - nor[2]) / -theta;
+ bMatrix[2][2] = -bMatrix[0][0];
+ bMatrix[2][0] = bMatrix[0][2] = 2.0f * nor[0] * nor[2] / theta;
+ }
+ }
+ else {
+ /* If nor is -Y, simple symmetry by Z axis. */
+ unit_m3(bMatrix);
+ bMatrix[0][0] = bMatrix[1][1] = -1.0;
+ }
+
+ /* Make Roll matrix */
+ axis_angle_normalized_to_mat3(rMatrix, nor, roll);
+
+ /* Combine and output result */
+ mul_m3_m3m3(mat, rMatrix, bMatrix);
#undef THETA_THRESHOLD_NEGY
#undef THETA_THRESHOLD_NEGY_CLOSE
@@ -1967,226 +2071,228 @@ void vec_roll_to_mat3_normalized(const float nor[3], const float roll, float mat
void vec_roll_to_mat3(const float vec[3], const float roll, float mat[3][3])
{
- float nor[3];
+ float nor[3];
- normalize_v3_v3(nor, vec);
- vec_roll_to_mat3_normalized(nor, roll, mat);
+ normalize_v3_v3(nor, vec);
+ vec_roll_to_mat3_normalized(nor, roll, mat);
}
/* recursive part, calculates restposition of entire tree of children */
/* used by exiting editmode too */
void BKE_armature_where_is_bone(Bone *bone, Bone *prevbone, const bool use_recursion)
{
- float vec[3];
-
- /* Bone Space */
- sub_v3_v3v3(vec, bone->tail, bone->head);
- bone->length = len_v3(vec);
- vec_roll_to_mat3(vec, bone->roll, bone->bone_mat);
-
- /* this is called on old file reading too... */
- if (bone->xwidth == 0.0f) {
- bone->xwidth = 0.1f;
- bone->zwidth = 0.1f;
- bone->segments = 1;
- }
-
- if (prevbone) {
- float offs_bone[4][4];
- /* yoffs(b-1) + root(b) + bonemat(b) */
- BKE_bone_offset_matrix_get(bone, offs_bone);
-
- /* Compose the matrix for this bone */
- mul_m4_m4m4(bone->arm_mat, prevbone->arm_mat, offs_bone);
- }
- else {
- copy_m4_m3(bone->arm_mat, bone->bone_mat);
- copy_v3_v3(bone->arm_mat[3], bone->head);
- }
-
- /* and the kiddies */
- if (use_recursion) {
- prevbone = bone;
- for (bone = bone->childbase.first; bone; bone = bone->next) {
- BKE_armature_where_is_bone(bone, prevbone, use_recursion);
- }
- }
+ float vec[3];
+
+ /* Bone Space */
+ sub_v3_v3v3(vec, bone->tail, bone->head);
+ bone->length = len_v3(vec);
+ vec_roll_to_mat3(vec, bone->roll, bone->bone_mat);
+
+ /* this is called on old file reading too... */
+ if (bone->xwidth == 0.0f) {
+ bone->xwidth = 0.1f;
+ bone->zwidth = 0.1f;
+ bone->segments = 1;
+ }
+
+ if (prevbone) {
+ float offs_bone[4][4];
+ /* yoffs(b-1) + root(b) + bonemat(b) */
+ BKE_bone_offset_matrix_get(bone, offs_bone);
+
+ /* Compose the matrix for this bone */
+ mul_m4_m4m4(bone->arm_mat, prevbone->arm_mat, offs_bone);
+ }
+ else {
+ copy_m4_m3(bone->arm_mat, bone->bone_mat);
+ copy_v3_v3(bone->arm_mat[3], bone->head);
+ }
+
+ /* and the kiddies */
+ if (use_recursion) {
+ prevbone = bone;
+ for (bone = bone->childbase.first; bone; bone = bone->next) {
+ BKE_armature_where_is_bone(bone, prevbone, use_recursion);
+ }
+ }
}
/* updates vectors and matrices on rest-position level, only needed
* after editing armature itself, now only on reading file */
void BKE_armature_where_is(bArmature *arm)
{
- Bone *bone;
+ Bone *bone;
- /* hierarchical from root to children */
- for (bone = arm->bonebase.first; bone; bone = bone->next) {
- BKE_armature_where_is_bone(bone, NULL, true);
- }
+ /* hierarchical from root to children */
+ for (bone = arm->bonebase.first; bone; bone = bone->next) {
+ BKE_armature_where_is_bone(bone, NULL, true);
+ }
}
/* if bone layer is protected, copy the data from from->pose
* when used with linked libraries this copies from the linked pose into the local pose */
static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected)
{
- bPose *pose = ob->pose, *frompose = from->pose;
- bPoseChannel *pchan, *pchanp;
- bConstraint *con;
- int error = 0;
-
- if (frompose == NULL)
- return;
-
- /* in some cases when rigs change, we cant synchronize
- * to avoid crashing check for possible errors here */
- for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->bone->layer & layer_protected) {
- if (BKE_pose_channel_find_name(frompose, pchan->name) == NULL) {
- CLOG_ERROR(&LOG, "failed to sync proxy armature because '%s' is missing pose channel '%s'",
- from->id.name, pchan->name);
- error = 1;
- }
- }
- }
-
- if (error)
- return;
-
- /* clear all transformation values from library */
- BKE_pose_rest(frompose);
-
- /* copy over all of the proxy's bone groups */
- /* TODO for later
- * - implement 'local' bone groups as for constraints
- * Note: this isn't trivial, as bones reference groups by index not by pointer,
- * so syncing things correctly needs careful attention */
- BLI_freelistN(&pose->agroups);
- BLI_duplicatelist(&pose->agroups, &frompose->agroups);
- pose->active_group = frompose->active_group;
-
- for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- pchanp = BKE_pose_channel_find_name(frompose, pchan->name);
-
- if (UNLIKELY(pchanp == NULL)) {
- /* happens for proxies that become invalid because of a missing link
- * for regular cases it shouldn't happen at all */
- }
- else if (pchan->bone->layer & layer_protected) {
- ListBase proxylocal_constraints = {NULL, NULL};
- bPoseChannel pchanw;
-
- /* copy posechannel to temp, but restore important pointers */
- pchanw = *pchanp;
- pchanw.bone = pchan->bone;
- pchanw.prev = pchan->prev;
- pchanw.next = pchan->next;
- pchanw.parent = pchan->parent;
- pchanw.child = pchan->child;
- pchanw.custom_tx = pchan->custom_tx;
- pchanw.bbone_prev = pchan->bbone_prev;
- pchanw.bbone_next = pchan->bbone_next;
-
- pchanw.mpath = pchan->mpath;
- pchan->mpath = NULL;
-
- /* this is freed so copy a copy, else undo crashes */
- if (pchanw.prop) {
- pchanw.prop = IDP_CopyProperty(pchanw.prop);
-
- /* use the values from the existing props */
- if (pchan->prop) {
- IDP_SyncGroupValues(pchanw.prop, pchan->prop);
- }
- }
-
- /* constraints - proxy constraints are flushed... local ones are added after
- * 1. extract constraints not from proxy (CONSTRAINT_PROXY_LOCAL) from pchan's constraints
- * 2. copy proxy-pchan's constraints on-to new
- * 3. add extracted local constraints back on top
- *
- * Note for BKE_constraints_copy: when copying constraints, disable 'do_extern' otherwise
- * we get the libs direct linked in this blend.
- */
- BKE_constraints_proxylocal_extract(&proxylocal_constraints, &pchan->constraints);
- BKE_constraints_copy(&pchanw.constraints, &pchanp->constraints, false);
- BLI_movelisttolist(&pchanw.constraints, &proxylocal_constraints);
-
- /* constraints - set target ob pointer to own object */
- for (con = pchanw.constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- if (ct->tar == from)
- ct->tar = ob;
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 0);
- }
- }
-
- /* free stuff from current channel */
- BKE_pose_channel_free(pchan);
-
- /* copy data in temp back over to the cleaned-out (but still allocated) original channel */
- *pchan = pchanw;
- if (pchan->custom) {
- id_us_plus(&pchan->custom->id);
- }
- }
- else {
- /* always copy custom shape */
- pchan->custom = pchanp->custom;
- if (pchan->custom) {
- id_us_plus(&pchan->custom->id);
- }
- if (pchanp->custom_tx)
- pchan->custom_tx = BKE_pose_channel_find_name(pose, pchanp->custom_tx->name);
-
- /* ID-Property Syncing */
- {
- IDProperty *prop_orig = pchan->prop;
- if (pchanp->prop) {
- pchan->prop = IDP_CopyProperty(pchanp->prop);
- if (prop_orig) {
- /* copy existing values across when types match */
- IDP_SyncGroupValues(pchan->prop, prop_orig);
- }
- }
- else {
- pchan->prop = NULL;
- }
- if (prop_orig) {
- IDP_FreeProperty(prop_orig);
- MEM_freeN(prop_orig);
- }
- }
- }
- }
+ bPose *pose = ob->pose, *frompose = from->pose;
+ bPoseChannel *pchan, *pchanp;
+ bConstraint *con;
+ int error = 0;
+
+ if (frompose == NULL)
+ return;
+
+ /* in some cases when rigs change, we cant synchronize
+ * to avoid crashing check for possible errors here */
+ for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->bone->layer & layer_protected) {
+ if (BKE_pose_channel_find_name(frompose, pchan->name) == NULL) {
+ CLOG_ERROR(&LOG,
+ "failed to sync proxy armature because '%s' is missing pose channel '%s'",
+ from->id.name,
+ pchan->name);
+ error = 1;
+ }
+ }
+ }
+
+ if (error)
+ return;
+
+ /* clear all transformation values from library */
+ BKE_pose_rest(frompose);
+
+ /* copy over all of the proxy's bone groups */
+ /* TODO for later
+ * - implement 'local' bone groups as for constraints
+ * Note: this isn't trivial, as bones reference groups by index not by pointer,
+ * so syncing things correctly needs careful attention */
+ BLI_freelistN(&pose->agroups);
+ BLI_duplicatelist(&pose->agroups, &frompose->agroups);
+ pose->active_group = frompose->active_group;
+
+ for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ pchanp = BKE_pose_channel_find_name(frompose, pchan->name);
+
+ if (UNLIKELY(pchanp == NULL)) {
+ /* happens for proxies that become invalid because of a missing link
+ * for regular cases it shouldn't happen at all */
+ }
+ else if (pchan->bone->layer & layer_protected) {
+ ListBase proxylocal_constraints = {NULL, NULL};
+ bPoseChannel pchanw;
+
+ /* copy posechannel to temp, but restore important pointers */
+ pchanw = *pchanp;
+ pchanw.bone = pchan->bone;
+ pchanw.prev = pchan->prev;
+ pchanw.next = pchan->next;
+ pchanw.parent = pchan->parent;
+ pchanw.child = pchan->child;
+ pchanw.custom_tx = pchan->custom_tx;
+ pchanw.bbone_prev = pchan->bbone_prev;
+ pchanw.bbone_next = pchan->bbone_next;
+
+ pchanw.mpath = pchan->mpath;
+ pchan->mpath = NULL;
+
+ /* this is freed so copy a copy, else undo crashes */
+ if (pchanw.prop) {
+ pchanw.prop = IDP_CopyProperty(pchanw.prop);
+
+ /* use the values from the existing props */
+ if (pchan->prop) {
+ IDP_SyncGroupValues(pchanw.prop, pchan->prop);
+ }
+ }
+
+ /* constraints - proxy constraints are flushed... local ones are added after
+ * 1. extract constraints not from proxy (CONSTRAINT_PROXY_LOCAL) from pchan's constraints
+ * 2. copy proxy-pchan's constraints on-to new
+ * 3. add extracted local constraints back on top
+ *
+ * Note for BKE_constraints_copy: when copying constraints, disable 'do_extern' otherwise
+ * we get the libs direct linked in this blend.
+ */
+ BKE_constraints_proxylocal_extract(&proxylocal_constraints, &pchan->constraints);
+ BKE_constraints_copy(&pchanw.constraints, &pchanp->constraints, false);
+ BLI_movelisttolist(&pchanw.constraints, &proxylocal_constraints);
+
+ /* constraints - set target ob pointer to own object */
+ for (con = pchanw.constraints.first; con; con = con->next) {
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
+
+ for (ct = targets.first; ct; ct = ct->next) {
+ if (ct->tar == from)
+ ct->tar = ob;
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 0);
+ }
+ }
+
+ /* free stuff from current channel */
+ BKE_pose_channel_free(pchan);
+
+ /* copy data in temp back over to the cleaned-out (but still allocated) original channel */
+ *pchan = pchanw;
+ if (pchan->custom) {
+ id_us_plus(&pchan->custom->id);
+ }
+ }
+ else {
+ /* always copy custom shape */
+ pchan->custom = pchanp->custom;
+ if (pchan->custom) {
+ id_us_plus(&pchan->custom->id);
+ }
+ if (pchanp->custom_tx)
+ pchan->custom_tx = BKE_pose_channel_find_name(pose, pchanp->custom_tx->name);
+
+ /* ID-Property Syncing */
+ {
+ IDProperty *prop_orig = pchan->prop;
+ if (pchanp->prop) {
+ pchan->prop = IDP_CopyProperty(pchanp->prop);
+ if (prop_orig) {
+ /* copy existing values across when types match */
+ IDP_SyncGroupValues(pchan->prop, prop_orig);
+ }
+ }
+ else {
+ pchan->prop = NULL;
+ }
+ if (prop_orig) {
+ IDP_FreeProperty(prop_orig);
+ MEM_freeN(prop_orig);
+ }
+ }
+ }
+ }
}
static int rebuild_pose_bone(bPose *pose, Bone *bone, bPoseChannel *parchan, int counter)
{
- bPoseChannel *pchan = BKE_pose_channel_verify(pose, bone->name); /* verify checks and/or adds */
+ bPoseChannel *pchan = BKE_pose_channel_verify(pose, bone->name); /* verify checks and/or adds */
- pchan->bone = bone;
- pchan->parent = parchan;
+ pchan->bone = bone;
+ pchan->parent = parchan;
- counter++;
+ counter++;
- for (bone = bone->childbase.first; bone; bone = bone->next) {
- counter = rebuild_pose_bone(pose, bone, pchan, counter);
- /* for quick detecting of next bone in chain, only b-bone uses it now */
- if (bone->flag & BONE_CONNECTED)
- pchan->child = BKE_pose_channel_find_name(pose, bone->name);
- }
+ for (bone = bone->childbase.first; bone; bone = bone->next) {
+ counter = rebuild_pose_bone(pose, bone, pchan, counter);
+ /* for quick detecting of next bone in chain, only b-bone uses it now */
+ if (bone->flag & BONE_CONNECTED)
+ pchan->child = BKE_pose_channel_find_name(pose, bone->name);
+ }
- return counter;
+ return counter;
}
/**
@@ -2194,32 +2300,32 @@ static int rebuild_pose_bone(bPose *pose, Bone *bone, bPoseChannel *parchan, int
*/
void BKE_pose_clear_pointers(bPose *pose)
{
- for (bPoseChannel *pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- pchan->bone = NULL;
- pchan->child = NULL;
- }
+ for (bPoseChannel *pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ pchan->bone = NULL;
+ pchan->child = NULL;
+ }
}
void BKE_pose_remap_bone_pointers(bArmature *armature, bPose *pose)
{
- GHash *bone_hash = BKE_armature_bone_from_name_map(armature);
- for (bPoseChannel *pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- pchan->bone = BLI_ghash_lookup(bone_hash, pchan->name);
- }
- BLI_ghash_free(bone_hash, NULL, NULL);
+ GHash *bone_hash = BKE_armature_bone_from_name_map(armature);
+ for (bPoseChannel *pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ pchan->bone = BLI_ghash_lookup(bone_hash, pchan->name);
+ }
+ BLI_ghash_free(bone_hash, NULL, NULL);
}
/** Find the matching pose channel using the bone name, if not NULL. */
static bPoseChannel *pose_channel_find_bone(bPose *pose, Bone *bone)
{
- return (bone != NULL) ? BKE_pose_channel_find_name(pose, bone->name) : NULL;
+ return (bone != NULL) ? BKE_pose_channel_find_name(pose, bone->name) : NULL;
}
/** Update the links for the B-Bone handles from Bone data. */
void BKE_pchan_rebuild_bbone_handles(bPose *pose, bPoseChannel *pchan)
{
- pchan->bbone_prev = pose_channel_find_bone(pose, pchan->bone->bbone_prev);
- pchan->bbone_next = pose_channel_find_bone(pose, pchan->bone->bbone_next);
+ pchan->bbone_prev = pose_channel_find_bone(pose, pchan->bone->bbone_prev);
+ pchan->bbone_next = pose_channel_find_bone(pose, pchan->bone->bbone_next);
}
/**
@@ -2231,66 +2337,66 @@ void BKE_pchan_rebuild_bbone_handles(bPose *pose, bPoseChannel *pchan)
*/
void BKE_pose_rebuild(Main *bmain, Object *ob, bArmature *arm, const bool do_id_user)
{
- Bone *bone;
- bPose *pose;
- bPoseChannel *pchan, *next;
- int counter = 0;
+ Bone *bone;
+ bPose *pose;
+ bPoseChannel *pchan, *next;
+ int counter = 0;
- /* only done here */
- if (ob->pose == NULL) {
- /* create new pose */
- ob->pose = MEM_callocN(sizeof(bPose), "new pose");
+ /* only done here */
+ if (ob->pose == NULL) {
+ /* create new pose */
+ ob->pose = MEM_callocN(sizeof(bPose), "new pose");
- /* set default settings for animviz */
- animviz_settings_init(&ob->pose->avs);
- }
- pose = ob->pose;
+ /* set default settings for animviz */
+ animviz_settings_init(&ob->pose->avs);
+ }
+ pose = ob->pose;
- /* clear */
- BKE_pose_clear_pointers(pose);
+ /* clear */
+ BKE_pose_clear_pointers(pose);
- /* first step, check if all channels are there */
- for (bone = arm->bonebase.first; bone; bone = bone->next) {
- counter = rebuild_pose_bone(pose, bone, NULL, counter);
- }
+ /* first step, check if all channels are there */
+ for (bone = arm->bonebase.first; bone; bone = bone->next) {
+ counter = rebuild_pose_bone(pose, bone, NULL, counter);
+ }
- /* and a check for garbage */
- for (pchan = pose->chanbase.first; pchan; pchan = next) {
- next = pchan->next;
- if (pchan->bone == NULL) {
- BKE_pose_channel_free_ex(pchan, do_id_user);
- BKE_pose_channels_hash_free(pose);
- BLI_freelinkN(&pose->chanbase, pchan);
- }
- }
+ /* and a check for garbage */
+ for (pchan = pose->chanbase.first; pchan; pchan = next) {
+ next = pchan->next;
+ if (pchan->bone == NULL) {
+ BKE_pose_channel_free_ex(pchan, do_id_user);
+ BKE_pose_channels_hash_free(pose);
+ BLI_freelinkN(&pose->chanbase, pchan);
+ }
+ }
- BKE_pose_channels_hash_make(pose);
+ BKE_pose_channels_hash_make(pose);
- for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- /* Find the custom B-Bone handles. */
- BKE_pchan_rebuild_bbone_handles(pose, pchan);
- }
+ for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ /* Find the custom B-Bone handles. */
+ BKE_pchan_rebuild_bbone_handles(pose, pchan);
+ }
- /* printf("rebuild pose %s, %d bones\n", ob->id.name, counter); */
+ /* printf("rebuild pose %s, %d bones\n", ob->id.name, counter); */
- /* synchronize protected layers with proxy */
- /* HACK! To preserve 2.7x behavior that you always can pose even locked bones,
- * do not do any restoration if this is a COW temp copy! */
- /* Switched back to just NO_MAIN tag, for some reasons (c) using COW tag was working this morning, but not anymore... */
- if (ob->proxy != NULL && (ob->id.tag & LIB_TAG_NO_MAIN) == 0) {
- BKE_object_copy_proxy_drivers(ob, ob->proxy);
- pose_proxy_synchronize(ob, ob->proxy, arm->layer_protected);
- }
+ /* synchronize protected layers with proxy */
+ /* HACK! To preserve 2.7x behavior that you always can pose even locked bones,
+ * do not do any restoration if this is a COW temp copy! */
+ /* Switched back to just NO_MAIN tag, for some reasons (c) using COW tag was working this morning, but not anymore... */
+ if (ob->proxy != NULL && (ob->id.tag & LIB_TAG_NO_MAIN) == 0) {
+ BKE_object_copy_proxy_drivers(ob, ob->proxy);
+ pose_proxy_synchronize(ob, ob->proxy, arm->layer_protected);
+ }
- BKE_pose_update_constraint_flags(pose); /* for IK detection for example */
+ BKE_pose_update_constraint_flags(pose); /* for IK detection for example */
- pose->flag &= ~POSE_RECALC;
- pose->flag |= POSE_WAS_REBUILT;
+ pose->flag &= ~POSE_RECALC;
+ pose->flag |= POSE_WAS_REBUILT;
- /* Rebuilding poses forces us to also rebuild the dependency graph, since there is one node per pose/bone... */
- if (bmain != NULL) {
- DEG_relations_tag_update(bmain);
- }
+ /* Rebuilding poses forces us to also rebuild the dependency graph, since there is one node per pose/bone... */
+ if (bmain != NULL) {
+ DEG_relations_tag_update(bmain);
+ }
}
/* ********************** THE POSE SOLVER ******************* */
@@ -2298,400 +2404,392 @@ void BKE_pose_rebuild(Main *bmain, Object *ob, bArmature *arm, const bool do_id_
/* loc/rot/size to given mat4 */
void BKE_pchan_to_mat4(bPoseChannel *pchan, float chan_mat[4][4])
{
- float smat[3][3];
- float rmat[3][3];
- float tmat[3][3];
-
- /* get scaling matrix */
- size_to_mat3(smat, pchan->size);
-
- /* rotations may either be quats, eulers (with various rotation orders), or axis-angle */
- if (pchan->rotmode > 0) {
- /* euler rotations (will cause gimble lock, but this can be alleviated a bit with rotation orders) */
- eulO_to_mat3(rmat, pchan->eul, pchan->rotmode);
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- /* axis-angle - not really that great for 3D-changing orientations */
- axis_angle_to_mat3(rmat, pchan->rotAxis, pchan->rotAngle);
- }
- else {
- /* quats are normalized before use to eliminate scaling issues */
- float quat[4];
-
- /* NOTE: we now don't normalize the stored values anymore, since this was kindof evil in some cases
- * but if this proves to be too problematic, switch back to the old system of operating directly on
- * the stored copy
- */
- normalize_qt_qt(quat, pchan->quat);
- quat_to_mat3(rmat, quat);
- }
-
- /* calculate matrix of bone (as 3x3 matrix, but then copy the 4x4) */
- mul_m3_m3m3(tmat, rmat, smat);
- copy_m4_m3(chan_mat, tmat);
-
- /* prevent action channels breaking chains */
- /* need to check for bone here, CONSTRAINT_TYPE_ACTION uses this call */
- if ((pchan->bone == NULL) || !(pchan->bone->flag & BONE_CONNECTED)) {
- copy_v3_v3(chan_mat[3], pchan->loc);
- }
+ float smat[3][3];
+ float rmat[3][3];
+ float tmat[3][3];
+
+ /* get scaling matrix */
+ size_to_mat3(smat, pchan->size);
+
+ /* rotations may either be quats, eulers (with various rotation orders), or axis-angle */
+ if (pchan->rotmode > 0) {
+ /* euler rotations (will cause gimble lock, but this can be alleviated a bit with rotation orders) */
+ eulO_to_mat3(rmat, pchan->eul, pchan->rotmode);
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ /* axis-angle - not really that great for 3D-changing orientations */
+ axis_angle_to_mat3(rmat, pchan->rotAxis, pchan->rotAngle);
+ }
+ else {
+ /* quats are normalized before use to eliminate scaling issues */
+ float quat[4];
+
+ /* NOTE: we now don't normalize the stored values anymore, since this was kindof evil in some cases
+ * but if this proves to be too problematic, switch back to the old system of operating directly on
+ * the stored copy
+ */
+ normalize_qt_qt(quat, pchan->quat);
+ quat_to_mat3(rmat, quat);
+ }
+
+ /* calculate matrix of bone (as 3x3 matrix, but then copy the 4x4) */
+ mul_m3_m3m3(tmat, rmat, smat);
+ copy_m4_m3(chan_mat, tmat);
+
+ /* prevent action channels breaking chains */
+ /* need to check for bone here, CONSTRAINT_TYPE_ACTION uses this call */
+ if ((pchan->bone == NULL) || !(pchan->bone->flag & BONE_CONNECTED)) {
+ copy_v3_v3(chan_mat[3], pchan->loc);
+ }
}
/* loc/rot/size to mat4 */
/* used in constraint.c too */
void BKE_pchan_calc_mat(bPoseChannel *pchan)
{
- /* this is just a wrapper around the copy of this function which calculates the matrix
- * and stores the result in any given channel
- */
- BKE_pchan_to_mat4(pchan, pchan->chan_mat);
+ /* this is just a wrapper around the copy of this function which calculates the matrix
+ * and stores the result in any given channel
+ */
+ BKE_pchan_to_mat4(pchan, pchan->chan_mat);
}
/* calculate tail of posechannel */
void BKE_pose_where_is_bone_tail(bPoseChannel *pchan)
{
- float vec[3];
+ float vec[3];
- copy_v3_v3(vec, pchan->pose_mat[1]);
- mul_v3_fl(vec, pchan->bone->length);
- add_v3_v3v3(pchan->pose_tail, pchan->pose_head, vec);
+ copy_v3_v3(vec, pchan->pose_mat[1]);
+ mul_v3_fl(vec, pchan->bone->length);
+ add_v3_v3v3(pchan->pose_tail, pchan->pose_head, vec);
}
/* The main armature solver, does all constraints excluding IK */
/* pchan is validated, as having bone and parent pointer
* 'do_extra': when zero skips loc/size/rot, constraints and strip modifiers.
*/
-void BKE_pose_where_is_bone(
- struct Depsgraph *depsgraph, Scene *scene,
- Object *ob, bPoseChannel *pchan, float ctime, bool do_extra)
-{
- /* This gives a chan_mat with actions (ipos) results. */
- if (do_extra)
- BKE_pchan_calc_mat(pchan);
- else
- unit_m4(pchan->chan_mat);
-
- /* Construct the posemat based on PoseChannels, that we do before applying constraints. */
- /* pose_mat(b) = pose_mat(b-1) * yoffs(b-1) * d_root(b) * bone_mat(b) * chan_mat(b) */
- BKE_armature_mat_bone_to_pose(pchan, pchan->chan_mat, pchan->pose_mat);
-
- /* Only rootbones get the cyclic offset (unless user doesn't want that). */
- /* XXX That could be a problem for snapping and other "reverse transform" features... */
- if (!pchan->parent) {
- if ((pchan->bone->flag & BONE_NO_CYCLICOFFSET) == 0)
- add_v3_v3(pchan->pose_mat[3], ob->pose->cyclic_offset);
- }
-
- if (do_extra) {
- /* Do constraints */
- if (pchan->constraints.first) {
- bConstraintOb *cob;
- float vec[3];
-
- /* make a copy of location of PoseChannel for later */
- copy_v3_v3(vec, pchan->pose_mat[3]);
-
- /* prepare PoseChannel for Constraint solving
- * - makes a copy of matrix, and creates temporary struct to use
- */
- cob = BKE_constraints_make_evalob(depsgraph, scene, ob, pchan, CONSTRAINT_OBTYPE_BONE);
-
- /* Solve PoseChannel's Constraints */
- BKE_constraints_solve(depsgraph, &pchan->constraints, cob, ctime); /* ctime doesn't alter objects */
-
- /* cleanup after Constraint Solving
- * - applies matrix back to pchan, and frees temporary struct used
- */
- BKE_constraints_clear_evalob(cob);
-
- /* prevent constraints breaking a chain */
- if (pchan->bone->flag & BONE_CONNECTED) {
- copy_v3_v3(pchan->pose_mat[3], vec);
- }
- }
- }
-
- /* calculate head */
- copy_v3_v3(pchan->pose_head, pchan->pose_mat[3]);
- /* calculate tail */
- BKE_pose_where_is_bone_tail(pchan);
+void BKE_pose_where_is_bone(struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ bPoseChannel *pchan,
+ float ctime,
+ bool do_extra)
+{
+ /* This gives a chan_mat with actions (ipos) results. */
+ if (do_extra)
+ BKE_pchan_calc_mat(pchan);
+ else
+ unit_m4(pchan->chan_mat);
+
+ /* Construct the posemat based on PoseChannels, that we do before applying constraints. */
+ /* pose_mat(b) = pose_mat(b-1) * yoffs(b-1) * d_root(b) * bone_mat(b) * chan_mat(b) */
+ BKE_armature_mat_bone_to_pose(pchan, pchan->chan_mat, pchan->pose_mat);
+
+ /* Only rootbones get the cyclic offset (unless user doesn't want that). */
+ /* XXX That could be a problem for snapping and other "reverse transform" features... */
+ if (!pchan->parent) {
+ if ((pchan->bone->flag & BONE_NO_CYCLICOFFSET) == 0)
+ add_v3_v3(pchan->pose_mat[3], ob->pose->cyclic_offset);
+ }
+
+ if (do_extra) {
+ /* Do constraints */
+ if (pchan->constraints.first) {
+ bConstraintOb *cob;
+ float vec[3];
+
+ /* make a copy of location of PoseChannel for later */
+ copy_v3_v3(vec, pchan->pose_mat[3]);
+
+ /* prepare PoseChannel for Constraint solving
+ * - makes a copy of matrix, and creates temporary struct to use
+ */
+ cob = BKE_constraints_make_evalob(depsgraph, scene, ob, pchan, CONSTRAINT_OBTYPE_BONE);
+
+ /* Solve PoseChannel's Constraints */
+ BKE_constraints_solve(
+ depsgraph, &pchan->constraints, cob, ctime); /* ctime doesn't alter objects */
+
+ /* cleanup after Constraint Solving
+ * - applies matrix back to pchan, and frees temporary struct used
+ */
+ BKE_constraints_clear_evalob(cob);
+
+ /* prevent constraints breaking a chain */
+ if (pchan->bone->flag & BONE_CONNECTED) {
+ copy_v3_v3(pchan->pose_mat[3], vec);
+ }
+ }
+ }
+
+ /* calculate head */
+ copy_v3_v3(pchan->pose_head, pchan->pose_mat[3]);
+ /* calculate tail */
+ BKE_pose_where_is_bone_tail(pchan);
}
/* This only reads anim data from channels, and writes to channels */
/* This is the only function adding poses */
void BKE_pose_where_is(struct Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- bArmature *arm;
- Bone *bone;
- bPoseChannel *pchan;
- float imat[4][4];
- float ctime;
-
- if (ob->type != OB_ARMATURE)
- return;
- arm = ob->data;
-
- if (ELEM(NULL, arm, scene))
- return;
- if ((ob->pose == NULL) || (ob->pose->flag & POSE_RECALC)) {
- /* WARNING! passing NULL bmain here means we won't tag depsgraph's as dirty - hopefully this is OK. */
- BKE_pose_rebuild(NULL, ob, arm, true);
- }
-
- ctime = BKE_scene_frame_get(scene); /* not accurate... */
-
- /* In editmode or restposition we read the data from the bones */
- if (arm->edbo || (arm->flag & ARM_RESTPOS)) {
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- bone = pchan->bone;
- if (bone) {
- copy_m4_m4(pchan->pose_mat, bone->arm_mat);
- copy_v3_v3(pchan->pose_head, bone->arm_head);
- copy_v3_v3(pchan->pose_tail, bone->arm_tail);
- }
- }
- }
- else {
- invert_m4_m4(ob->imat, ob->obmat); /* imat is needed */
-
- /* 1. clear flags */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- pchan->flag &= ~(POSE_DONE | POSE_CHAIN | POSE_IKTREE | POSE_IKSPLINE);
- }
-
- /* 2a. construct the IK tree (standard IK) */
- BIK_initialize_tree(depsgraph, scene, ob, ctime);
-
- /* 2b. construct the Spline IK trees
- * - this is not integrated as an IK plugin, since it should be able
- * to function in conjunction with standard IK
- */
- BKE_pose_splineik_init_tree(scene, ob, ctime);
-
- /* 3. the main loop, channels are already hierarchical sorted from root to children */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- /* 4a. if we find an IK root, we handle it separated */
- if (pchan->flag & POSE_IKTREE) {
- BIK_execute_tree(depsgraph, scene, ob, pchan, ctime);
- }
- /* 4b. if we find a Spline IK root, we handle it separated too */
- else if (pchan->flag & POSE_IKSPLINE) {
- BKE_splineik_execute_tree(depsgraph, scene, ob, pchan, ctime);
- }
- /* 5. otherwise just call the normal solver */
- else if (!(pchan->flag & POSE_DONE)) {
- BKE_pose_where_is_bone(depsgraph, scene, ob, pchan, ctime, 1);
- }
- }
- /* 6. release the IK tree */
- BIK_release_tree(scene, ob, ctime);
- }
-
- /* calculating deform matrices */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->bone) {
- invert_m4_m4(imat, pchan->bone->arm_mat);
- mul_m4_m4m4(pchan->chan_mat, pchan->pose_mat, imat);
- }
- }
+ bArmature *arm;
+ Bone *bone;
+ bPoseChannel *pchan;
+ float imat[4][4];
+ float ctime;
+
+ if (ob->type != OB_ARMATURE)
+ return;
+ arm = ob->data;
+
+ if (ELEM(NULL, arm, scene))
+ return;
+ if ((ob->pose == NULL) || (ob->pose->flag & POSE_RECALC)) {
+ /* WARNING! passing NULL bmain here means we won't tag depsgraph's as dirty - hopefully this is OK. */
+ BKE_pose_rebuild(NULL, ob, arm, true);
+ }
+
+ ctime = BKE_scene_frame_get(scene); /* not accurate... */
+
+ /* In editmode or restposition we read the data from the bones */
+ if (arm->edbo || (arm->flag & ARM_RESTPOS)) {
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ bone = pchan->bone;
+ if (bone) {
+ copy_m4_m4(pchan->pose_mat, bone->arm_mat);
+ copy_v3_v3(pchan->pose_head, bone->arm_head);
+ copy_v3_v3(pchan->pose_tail, bone->arm_tail);
+ }
+ }
+ }
+ else {
+ invert_m4_m4(ob->imat, ob->obmat); /* imat is needed */
+
+ /* 1. clear flags */
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ pchan->flag &= ~(POSE_DONE | POSE_CHAIN | POSE_IKTREE | POSE_IKSPLINE);
+ }
+
+ /* 2a. construct the IK tree (standard IK) */
+ BIK_initialize_tree(depsgraph, scene, ob, ctime);
+
+ /* 2b. construct the Spline IK trees
+ * - this is not integrated as an IK plugin, since it should be able
+ * to function in conjunction with standard IK
+ */
+ BKE_pose_splineik_init_tree(scene, ob, ctime);
+
+ /* 3. the main loop, channels are already hierarchical sorted from root to children */
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ /* 4a. if we find an IK root, we handle it separated */
+ if (pchan->flag & POSE_IKTREE) {
+ BIK_execute_tree(depsgraph, scene, ob, pchan, ctime);
+ }
+ /* 4b. if we find a Spline IK root, we handle it separated too */
+ else if (pchan->flag & POSE_IKSPLINE) {
+ BKE_splineik_execute_tree(depsgraph, scene, ob, pchan, ctime);
+ }
+ /* 5. otherwise just call the normal solver */
+ else if (!(pchan->flag & POSE_DONE)) {
+ BKE_pose_where_is_bone(depsgraph, scene, ob, pchan, ctime, 1);
+ }
+ }
+ /* 6. release the IK tree */
+ BIK_release_tree(scene, ob, ctime);
+ }
+
+ /* calculating deform matrices */
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->bone) {
+ invert_m4_m4(imat, pchan->bone->arm_mat);
+ mul_m4_m4m4(pchan->chan_mat, pchan->pose_mat, imat);
+ }
+ }
}
/************** Bounding box ********************/
static int minmax_armature(Object *ob, float r_min[3], float r_max[3])
{
- bPoseChannel *pchan;
+ bPoseChannel *pchan;
- /* For now, we assume BKE_pose_where_is has already been called (hence we have valid data in pachan). */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- minmax_v3v3_v3(r_min, r_max, pchan->pose_head);
- minmax_v3v3_v3(r_min, r_max, pchan->pose_tail);
- }
+ /* For now, we assume BKE_pose_where_is has already been called (hence we have valid data in pachan). */
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ minmax_v3v3_v3(r_min, r_max, pchan->pose_head);
+ minmax_v3v3_v3(r_min, r_max, pchan->pose_tail);
+ }
- return (BLI_listbase_is_empty(&ob->pose->chanbase) == false);
+ return (BLI_listbase_is_empty(&ob->pose->chanbase) == false);
}
static void boundbox_armature(Object *ob)
{
- BoundBox *bb;
- float min[3], max[3];
+ BoundBox *bb;
+ float min[3], max[3];
- if (ob->runtime.bb == NULL) {
- ob->runtime.bb = MEM_callocN(sizeof(BoundBox), "Armature boundbox");
- }
- bb = ob->runtime.bb;
+ if (ob->runtime.bb == NULL) {
+ ob->runtime.bb = MEM_callocN(sizeof(BoundBox), "Armature boundbox");
+ }
+ bb = ob->runtime.bb;
- INIT_MINMAX(min, max);
- if (!minmax_armature(ob, min, max)) {
- min[0] = min[1] = min[2] = -1.0f;
- max[0] = max[1] = max[2] = 1.0f;
- }
+ INIT_MINMAX(min, max);
+ if (!minmax_armature(ob, min, max)) {
+ min[0] = min[1] = min[2] = -1.0f;
+ max[0] = max[1] = max[2] = 1.0f;
+ }
- BKE_boundbox_init_from_minmax(bb, min, max);
+ BKE_boundbox_init_from_minmax(bb, min, max);
- bb->flag &= ~BOUNDBOX_DIRTY;
+ bb->flag &= ~BOUNDBOX_DIRTY;
}
BoundBox *BKE_armature_boundbox_get(Object *ob)
{
- boundbox_armature(ob);
+ boundbox_armature(ob);
- return ob->runtime.bb;
+ return ob->runtime.bb;
}
bool BKE_pose_minmax(Object *ob, float r_min[3], float r_max[3], bool use_hidden, bool use_select)
{
- bool changed = false;
-
- if (ob->pose) {
- bArmature *arm = ob->data;
- bPoseChannel *pchan;
-
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- /* XXX pchan->bone may be NULL for duplicated bones, see duplicateEditBoneObjects() comment
- * (editarmature.c:2592)... Skip in this case too! */
- if (pchan->bone &&
- (!((use_hidden == false) && (PBONE_VISIBLE(arm, pchan->bone) == false)) &&
- !((use_select == true) && ((pchan->bone->flag & BONE_SELECTED) == 0))))
- {
- bPoseChannel *pchan_tx = (pchan->custom && pchan->custom_tx) ? pchan->custom_tx : pchan;
- BoundBox *bb_custom = ((pchan->custom) && !(arm->flag & ARM_NO_CUSTOM)) ?
- BKE_object_boundbox_get(pchan->custom) : NULL;
- if (bb_custom) {
- float mat[4][4], smat[4][4];
- scale_m4_fl(smat, PCHAN_CUSTOM_DRAW_SIZE(pchan));
- mul_m4_series(mat, ob->obmat, pchan_tx->pose_mat, smat);
- BKE_boundbox_minmax(bb_custom, mat, r_min, r_max);
- }
- else {
- float vec[3];
- mul_v3_m4v3(vec, ob->obmat, pchan_tx->pose_head);
- minmax_v3v3_v3(r_min, r_max, vec);
- mul_v3_m4v3(vec, ob->obmat, pchan_tx->pose_tail);
- minmax_v3v3_v3(r_min, r_max, vec);
- }
-
- changed = true;
- }
- }
- }
-
- return changed;
+ bool changed = false;
+
+ if (ob->pose) {
+ bArmature *arm = ob->data;
+ bPoseChannel *pchan;
+
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ /* XXX pchan->bone may be NULL for duplicated bones, see duplicateEditBoneObjects() comment
+ * (editarmature.c:2592)... Skip in this case too! */
+ if (pchan->bone && (!((use_hidden == false) && (PBONE_VISIBLE(arm, pchan->bone) == false)) &&
+ !((use_select == true) && ((pchan->bone->flag & BONE_SELECTED) == 0)))) {
+ bPoseChannel *pchan_tx = (pchan->custom && pchan->custom_tx) ? pchan->custom_tx : pchan;
+ BoundBox *bb_custom = ((pchan->custom) && !(arm->flag & ARM_NO_CUSTOM)) ?
+ BKE_object_boundbox_get(pchan->custom) :
+ NULL;
+ if (bb_custom) {
+ float mat[4][4], smat[4][4];
+ scale_m4_fl(smat, PCHAN_CUSTOM_DRAW_SIZE(pchan));
+ mul_m4_series(mat, ob->obmat, pchan_tx->pose_mat, smat);
+ BKE_boundbox_minmax(bb_custom, mat, r_min, r_max);
+ }
+ else {
+ float vec[3];
+ mul_v3_m4v3(vec, ob->obmat, pchan_tx->pose_head);
+ minmax_v3v3_v3(r_min, r_max, vec);
+ mul_v3_m4v3(vec, ob->obmat, pchan_tx->pose_tail);
+ minmax_v3v3_v3(r_min, r_max, vec);
+ }
+
+ changed = true;
+ }
+ }
+ }
+
+ return changed;
}
/************** Graph evaluation ********************/
-bPoseChannel *BKE_armature_ik_solver_find_root(
- bPoseChannel *pchan,
- bKinematicConstraint *data)
-{
- bPoseChannel *rootchan = pchan;
- if (!(data->flag & CONSTRAINT_IK_TIP)) {
- /* Exclude tip from chain. */
- rootchan = rootchan->parent;
- }
- if (rootchan != NULL) {
- int segcount = 0;
- while (rootchan->parent) {
- /* Continue up chain, until we reach target number of items. */
- segcount++;
- if (segcount == data->rootbone) {
- break;
- }
- rootchan = rootchan->parent;
- }
- }
- return rootchan;
-}
-
-bPoseChannel *BKE_armature_splineik_solver_find_root(
- bPoseChannel *pchan,
- bSplineIKConstraint *data)
-{
- bPoseChannel *rootchan = pchan;
- int segcount = 0;
- BLI_assert(rootchan != NULL);
- while (rootchan->parent) {
- /* Continue up chain, until we reach target number of items. */
- segcount++;
- if (segcount == data->chainlen) {
- break;
- }
- rootchan = rootchan->parent;
- }
- return rootchan;
+bPoseChannel *BKE_armature_ik_solver_find_root(bPoseChannel *pchan, bKinematicConstraint *data)
+{
+ bPoseChannel *rootchan = pchan;
+ if (!(data->flag & CONSTRAINT_IK_TIP)) {
+ /* Exclude tip from chain. */
+ rootchan = rootchan->parent;
+ }
+ if (rootchan != NULL) {
+ int segcount = 0;
+ while (rootchan->parent) {
+ /* Continue up chain, until we reach target number of items. */
+ segcount++;
+ if (segcount == data->rootbone) {
+ break;
+ }
+ rootchan = rootchan->parent;
+ }
+ }
+ return rootchan;
+}
+
+bPoseChannel *BKE_armature_splineik_solver_find_root(bPoseChannel *pchan,
+ bSplineIKConstraint *data)
+{
+ bPoseChannel *rootchan = pchan;
+ int segcount = 0;
+ BLI_assert(rootchan != NULL);
+ while (rootchan->parent) {
+ /* Continue up chain, until we reach target number of items. */
+ segcount++;
+ if (segcount == data->chainlen) {
+ break;
+ }
+ rootchan = rootchan->parent;
+ }
+ return rootchan;
}
/* ****************************** BBone cache ****************************** */
-ObjectBBoneDeform * BKE_armature_cached_bbone_deformation_get(Object *object)
+ObjectBBoneDeform *BKE_armature_cached_bbone_deformation_get(Object *object)
{
- return object->runtime.cached_bbone_deformation;
+ return object->runtime.cached_bbone_deformation;
}
void BKE_armature_cached_bbone_deformation_free_data(Object *object)
{
- ObjectBBoneDeform *bbone_deform =
- BKE_armature_cached_bbone_deformation_get(object);
- if (bbone_deform == NULL) {
- return;
- }
- /* Free arrays. */
- MEM_SAFE_FREE(bbone_deform->pdef_info_array);
- MEM_SAFE_FREE(bbone_deform->dualquats);
- /* Tag that we've got no data, so we are safe for sequential calls to
- * data free. */
- bbone_deform->num_pchan = 0;
+ ObjectBBoneDeform *bbone_deform = BKE_armature_cached_bbone_deformation_get(object);
+ if (bbone_deform == NULL) {
+ return;
+ }
+ /* Free arrays. */
+ MEM_SAFE_FREE(bbone_deform->pdef_info_array);
+ MEM_SAFE_FREE(bbone_deform->dualquats);
+ /* Tag that we've got no data, so we are safe for sequential calls to
+ * data free. */
+ bbone_deform->num_pchan = 0;
}
void BKE_armature_cached_bbone_deformation_free(Object *object)
{
- ObjectBBoneDeform *bbone_deform =
- BKE_armature_cached_bbone_deformation_get(object);
- if (bbone_deform == NULL) {
- return;
- }
- BKE_armature_cached_bbone_deformation_free_data(object);
- MEM_freeN(bbone_deform);
- object->runtime.cached_bbone_deformation = NULL;
+ ObjectBBoneDeform *bbone_deform = BKE_armature_cached_bbone_deformation_get(object);
+ if (bbone_deform == NULL) {
+ return;
+ }
+ BKE_armature_cached_bbone_deformation_free_data(object);
+ MEM_freeN(bbone_deform);
+ object->runtime.cached_bbone_deformation = NULL;
}
void BKE_armature_cached_bbone_deformation_update(Object *object)
{
- BLI_assert(object->type == OB_ARMATURE);
- BLI_assert(object->pose != NULL);
- bPose *pose = object->pose;
- const int totchan = BLI_listbase_count(&pose->chanbase);
- const bool use_quaternion = true;
- /* Make sure cache exists. */
- ObjectBBoneDeform *bbone_deform =
- BKE_armature_cached_bbone_deformation_get(object);
- if (bbone_deform == NULL) {
- bbone_deform = MEM_callocN(sizeof(*bbone_deform), "bbone deform cache");
- object->runtime.cached_bbone_deformation = bbone_deform;
- }
- /* Make sure arrays are allocateds at the proper size. */
- BKE_armature_cached_bbone_deformation_free_data(object);
- DualQuat *dualquats = NULL;
- if (use_quaternion) {
- dualquats = MEM_calloc_arrayN(
- sizeof(DualQuat), totchan, "dualquats");
- }
- bPoseChanDeform *pdef_info_array = MEM_calloc_arrayN(
- sizeof(bPoseChanDeform), totchan, "bPoseChanDeform");
- /* Calculate deofrmation matricies. */
- ArmatureBBoneDefmatsData data = {
- .pdef_info_array = pdef_info_array,
- .dualquats = dualquats,
- .use_quaternion = use_quaternion,
- };
- BLI_task_parallel_listbase(&pose->chanbase,
- &data,
- armature_bbone_defmats_cb,
- totchan > 1024);
- /* Store pointers. */
- bbone_deform->dualquats = dualquats;
- atomic_cas_ptr((void **)&bbone_deform->pdef_info_array,
- bbone_deform->pdef_info_array,
- pdef_info_array);
- bbone_deform->num_pchan = totchan;
+ BLI_assert(object->type == OB_ARMATURE);
+ BLI_assert(object->pose != NULL);
+ bPose *pose = object->pose;
+ const int totchan = BLI_listbase_count(&pose->chanbase);
+ const bool use_quaternion = true;
+ /* Make sure cache exists. */
+ ObjectBBoneDeform *bbone_deform = BKE_armature_cached_bbone_deformation_get(object);
+ if (bbone_deform == NULL) {
+ bbone_deform = MEM_callocN(sizeof(*bbone_deform), "bbone deform cache");
+ object->runtime.cached_bbone_deformation = bbone_deform;
+ }
+ /* Make sure arrays are allocateds at the proper size. */
+ BKE_armature_cached_bbone_deformation_free_data(object);
+ DualQuat *dualquats = NULL;
+ if (use_quaternion) {
+ dualquats = MEM_calloc_arrayN(sizeof(DualQuat), totchan, "dualquats");
+ }
+ bPoseChanDeform *pdef_info_array = MEM_calloc_arrayN(
+ sizeof(bPoseChanDeform), totchan, "bPoseChanDeform");
+ /* Calculate deofrmation matricies. */
+ ArmatureBBoneDefmatsData data = {
+ .pdef_info_array = pdef_info_array,
+ .dualquats = dualquats,
+ .use_quaternion = use_quaternion,
+ };
+ BLI_task_parallel_listbase(&pose->chanbase, &data, armature_bbone_defmats_cb, totchan > 1024);
+ /* Store pointers. */
+ bbone_deform->dualquats = dualquats;
+ atomic_cas_ptr(
+ (void **)&bbone_deform->pdef_info_array, bbone_deform->pdef_info_array, pdef_info_array);
+ bbone_deform->num_pchan = totchan;
}
diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c
index 51333251b8e..6d51c7f5108 100644
--- a/source/blender/blenkernel/intern/armature_update.c
+++ b/source/blender/blenkernel/intern/armature_update.c
@@ -45,642 +45,634 @@
#include "BIK_api.h"
-
#include "DEG_depsgraph.h"
/* ********************** SPLINE IK SOLVER ******************* */
/* Temporary evaluation tree data used for Spline IK */
typedef struct tSplineIK_Tree {
- struct tSplineIK_Tree *next, *prev;
+ struct tSplineIK_Tree *next, *prev;
- int type; /* type of IK that this serves (CONSTRAINT_TYPE_KINEMATIC or ..._SPLINEIK) */
+ int type; /* type of IK that this serves (CONSTRAINT_TYPE_KINEMATIC or ..._SPLINEIK) */
- short chainlen; /* number of bones in the chain */
- float totlength; /* total length of bones in the chain */
+ short chainlen; /* number of bones in the chain */
+ float totlength; /* total length of bones in the chain */
- const float *points; /* parametric positions for the joints along the curve */
- bPoseChannel **chain; /* chain of bones to affect using Spline IK (ordered from the tip) */
+ const float *points; /* parametric positions for the joints along the curve */
+ bPoseChannel **chain; /* chain of bones to affect using Spline IK (ordered from the tip) */
- bPoseChannel *root; /* bone that is the root node of the chain */
+ bPoseChannel *root; /* bone that is the root node of the chain */
- bConstraint *con; /* constraint for this chain */
- bSplineIKConstraint *ikData; /* constraint settings for this chain */
+ bConstraint *con; /* constraint for this chain */
+ bSplineIKConstraint *ikData; /* constraint settings for this chain */
} tSplineIK_Tree;
/* ----------- */
/* Tag the bones in the chain formed by the given bone for IK */
-static void splineik_init_tree_from_pchan(Scene *UNUSED(scene), Object *UNUSED(ob), bPoseChannel *pchan_tip)
+static void splineik_init_tree_from_pchan(Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ bPoseChannel *pchan_tip)
{
- bPoseChannel *pchan, *pchanRoot = NULL;
- bPoseChannel *pchanChain[255];
- bConstraint *con = NULL;
- bSplineIKConstraint *ikData = NULL;
- float boneLengths[255];
- float totLength = 0.0f;
- int segcount = 0;
-
- /* find the SplineIK constraint */
- for (con = pchan_tip->constraints.first; con; con = con->next) {
- if (con->type == CONSTRAINT_TYPE_SPLINEIK) {
- ikData = con->data;
-
- /* target can only be curve */
- if ((ikData->tar == NULL) || (ikData->tar->type != OB_CURVE))
- continue;
- /* skip if disabled */
- if ((con->enforce == 0.0f) || (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)))
- continue;
-
- /* otherwise, constraint is ok... */
- break;
- }
- }
- if (con == NULL)
- return;
-
- /* find the root bone and the chain of bones from the root to the tip
- * NOTE: this assumes that the bones are connected, but that may not be true... */
- for (pchan = pchan_tip; pchan && (segcount < ikData->chainlen); pchan = pchan->parent, segcount++) {
- /* store this segment in the chain */
- pchanChain[segcount] = pchan;
-
- /* if performing rebinding, calculate the length of the bone */
- boneLengths[segcount] = pchan->bone->length;
- totLength += boneLengths[segcount];
- }
-
- if (segcount == 0)
- return;
- else
- pchanRoot = pchanChain[segcount - 1];
-
- /* perform binding step if required */
- if ((ikData->flag & CONSTRAINT_SPLINEIK_BOUND) == 0) {
- float segmentLen = (1.0f / (float)segcount);
- int i;
-
- /* setup new empty array for the points list */
- if (ikData->points)
- MEM_freeN(ikData->points);
- ikData->numpoints = ikData->chainlen + 1;
- ikData->points = MEM_mallocN(sizeof(float) * ikData->numpoints, "Spline IK Binding");
-
- /* bind 'tip' of chain (i.e. first joint = tip of bone with the Spline IK Constraint) */
- ikData->points[0] = 1.0f;
-
- /* perform binding of the joints to parametric positions along the curve based
- * proportion of the total length that each bone occupies
- */
- for (i = 0; i < segcount; i++) {
- /* 'head' joints, traveling towards the root of the chain
- * - 2 methods; the one chosen depends on whether we've got usable lengths
- */
- if ((ikData->flag & CONSTRAINT_SPLINEIK_EVENSPLITS) || (totLength == 0.0f)) {
- /* 1) equi-spaced joints */
- ikData->points[i + 1] = ikData->points[i] - segmentLen;
- }
- else {
- /* 2) to find this point on the curve, we take a step from the previous joint
- * a distance given by the proportion that this bone takes
- */
- ikData->points[i + 1] = ikData->points[i] - (boneLengths[i] / totLength);
- }
- }
-
- /* spline has now been bound */
- ikData->flag |= CONSTRAINT_SPLINEIK_BOUND;
- }
-
- /* disallow negative values (happens with float precision) */
- CLAMP_MIN(ikData->points[segcount], 0.0f);
-
- /* make a new Spline-IK chain, and store it in the IK chains */
- /* TODO: we should check if there is already an IK chain on this, since that would take precedence... */
- {
- /* make new tree */
- tSplineIK_Tree *tree = MEM_callocN(sizeof(tSplineIK_Tree), "SplineIK Tree");
- tree->type = CONSTRAINT_TYPE_SPLINEIK;
-
- tree->chainlen = segcount;
- tree->totlength = totLength;
-
- /* copy over the array of links to bones in the chain (from tip to root) */
- tree->chain = MEM_mallocN(sizeof(bPoseChannel *) * segcount, "SplineIK Chain");
- memcpy(tree->chain, pchanChain, sizeof(bPoseChannel *) * segcount);
-
- /* store reference to joint position array */
- tree->points = ikData->points;
-
- /* store references to different parts of the chain */
- tree->root = pchanRoot;
- tree->con = con;
- tree->ikData = ikData;
-
- /* AND! link the tree to the root */
- BLI_addtail(&pchanRoot->siktree, tree);
- }
-
- /* mark root channel having an IK tree */
- pchanRoot->flag |= POSE_IKSPLINE;
+ bPoseChannel *pchan, *pchanRoot = NULL;
+ bPoseChannel *pchanChain[255];
+ bConstraint *con = NULL;
+ bSplineIKConstraint *ikData = NULL;
+ float boneLengths[255];
+ float totLength = 0.0f;
+ int segcount = 0;
+
+ /* find the SplineIK constraint */
+ for (con = pchan_tip->constraints.first; con; con = con->next) {
+ if (con->type == CONSTRAINT_TYPE_SPLINEIK) {
+ ikData = con->data;
+
+ /* target can only be curve */
+ if ((ikData->tar == NULL) || (ikData->tar->type != OB_CURVE))
+ continue;
+ /* skip if disabled */
+ if ((con->enforce == 0.0f) || (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)))
+ continue;
+
+ /* otherwise, constraint is ok... */
+ break;
+ }
+ }
+ if (con == NULL)
+ return;
+
+ /* find the root bone and the chain of bones from the root to the tip
+ * NOTE: this assumes that the bones are connected, but that may not be true... */
+ for (pchan = pchan_tip; pchan && (segcount < ikData->chainlen);
+ pchan = pchan->parent, segcount++) {
+ /* store this segment in the chain */
+ pchanChain[segcount] = pchan;
+
+ /* if performing rebinding, calculate the length of the bone */
+ boneLengths[segcount] = pchan->bone->length;
+ totLength += boneLengths[segcount];
+ }
+
+ if (segcount == 0)
+ return;
+ else
+ pchanRoot = pchanChain[segcount - 1];
+
+ /* perform binding step if required */
+ if ((ikData->flag & CONSTRAINT_SPLINEIK_BOUND) == 0) {
+ float segmentLen = (1.0f / (float)segcount);
+ int i;
+
+ /* setup new empty array for the points list */
+ if (ikData->points)
+ MEM_freeN(ikData->points);
+ ikData->numpoints = ikData->chainlen + 1;
+ ikData->points = MEM_mallocN(sizeof(float) * ikData->numpoints, "Spline IK Binding");
+
+ /* bind 'tip' of chain (i.e. first joint = tip of bone with the Spline IK Constraint) */
+ ikData->points[0] = 1.0f;
+
+ /* perform binding of the joints to parametric positions along the curve based
+ * proportion of the total length that each bone occupies
+ */
+ for (i = 0; i < segcount; i++) {
+ /* 'head' joints, traveling towards the root of the chain
+ * - 2 methods; the one chosen depends on whether we've got usable lengths
+ */
+ if ((ikData->flag & CONSTRAINT_SPLINEIK_EVENSPLITS) || (totLength == 0.0f)) {
+ /* 1) equi-spaced joints */
+ ikData->points[i + 1] = ikData->points[i] - segmentLen;
+ }
+ else {
+ /* 2) to find this point on the curve, we take a step from the previous joint
+ * a distance given by the proportion that this bone takes
+ */
+ ikData->points[i + 1] = ikData->points[i] - (boneLengths[i] / totLength);
+ }
+ }
+
+ /* spline has now been bound */
+ ikData->flag |= CONSTRAINT_SPLINEIK_BOUND;
+ }
+
+ /* disallow negative values (happens with float precision) */
+ CLAMP_MIN(ikData->points[segcount], 0.0f);
+
+ /* make a new Spline-IK chain, and store it in the IK chains */
+ /* TODO: we should check if there is already an IK chain on this, since that would take precedence... */
+ {
+ /* make new tree */
+ tSplineIK_Tree *tree = MEM_callocN(sizeof(tSplineIK_Tree), "SplineIK Tree");
+ tree->type = CONSTRAINT_TYPE_SPLINEIK;
+
+ tree->chainlen = segcount;
+ tree->totlength = totLength;
+
+ /* copy over the array of links to bones in the chain (from tip to root) */
+ tree->chain = MEM_mallocN(sizeof(bPoseChannel *) * segcount, "SplineIK Chain");
+ memcpy(tree->chain, pchanChain, sizeof(bPoseChannel *) * segcount);
+
+ /* store reference to joint position array */
+ tree->points = ikData->points;
+
+ /* store references to different parts of the chain */
+ tree->root = pchanRoot;
+ tree->con = con;
+ tree->ikData = ikData;
+
+ /* AND! link the tree to the root */
+ BLI_addtail(&pchanRoot->siktree, tree);
+ }
+
+ /* mark root channel having an IK tree */
+ pchanRoot->flag |= POSE_IKSPLINE;
}
/* Tag which bones are members of Spline IK chains */
static void splineik_init_tree(Scene *scene, Object *ob, float UNUSED(ctime))
{
- bPoseChannel *pchan;
+ bPoseChannel *pchan;
- /* find the tips of Spline IK chains, which are simply the bones which have been tagged as such */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->constflag & PCHAN_HAS_SPLINEIK)
- splineik_init_tree_from_pchan(scene, ob, pchan);
- }
+ /* find the tips of Spline IK chains, which are simply the bones which have been tagged as such */
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->constflag & PCHAN_HAS_SPLINEIK)
+ splineik_init_tree_from_pchan(scene, ob, pchan);
+ }
}
/* ----------- */
typedef struct tSplineIk_EvalState {
- float curve_position; /* Current position along the curve. */
- float curve_scale; /* Global scale to apply to curve positions. */
- float locrot_offset[4][4]; /* Bone rotation and location offset inherited from parent. */
+ float curve_position; /* Current position along the curve. */
+ float curve_scale; /* Global scale to apply to curve positions. */
+ float locrot_offset[4][4]; /* Bone rotation and location offset inherited from parent. */
} tSplineIk_EvalState;
/* Prepare data to evaluate spline IK. */
static bool splineik_evaluate_init(tSplineIK_Tree *tree, tSplineIk_EvalState *state)
{
- bSplineIKConstraint *ikData = tree->ikData;
-
- /* Make sure that the constraint targets are ok, to avoid crashes
- * in case of a depsgraph bug or dependency cycle.
- */
- if (ikData->tar == NULL) {
- return false;
- }
-
- CurveCache *cache = ikData->tar->runtime.curve_cache;
-
- if (ELEM(NULL, cache, cache->path, cache->path->data)) {
- return false;
- }
-
- /* Initialize the evaluation state. */
- state->curve_position = 0.0f;
- state->curve_scale = 1.0f;
- unit_m4(state->locrot_offset);
-
- /* Apply corrections for sensitivity to scaling. */
- if ((ikData->yScaleMode != CONSTRAINT_SPLINEIK_YS_FIT_CURVE) && (tree->totlength != 0.0f)) {
- /* get the current length of the curve */
- /* NOTE: this is assumed to be correct even after the curve was resized */
- float splineLen = cache->path->totdist;
-
- /* calculate the scale factor to multiply all the path values by so that the
- * bone chain retains its current length, such that
- * maxScale * splineLen = totLength
- */
- state->curve_scale = tree->totlength / splineLen;
- }
-
- return true;
+ bSplineIKConstraint *ikData = tree->ikData;
+
+ /* Make sure that the constraint targets are ok, to avoid crashes
+ * in case of a depsgraph bug or dependency cycle.
+ */
+ if (ikData->tar == NULL) {
+ return false;
+ }
+
+ CurveCache *cache = ikData->tar->runtime.curve_cache;
+
+ if (ELEM(NULL, cache, cache->path, cache->path->data)) {
+ return false;
+ }
+
+ /* Initialize the evaluation state. */
+ state->curve_position = 0.0f;
+ state->curve_scale = 1.0f;
+ unit_m4(state->locrot_offset);
+
+ /* Apply corrections for sensitivity to scaling. */
+ if ((ikData->yScaleMode != CONSTRAINT_SPLINEIK_YS_FIT_CURVE) && (tree->totlength != 0.0f)) {
+ /* get the current length of the curve */
+ /* NOTE: this is assumed to be correct even after the curve was resized */
+ float splineLen = cache->path->totdist;
+
+ /* calculate the scale factor to multiply all the path values by so that the
+ * bone chain retains its current length, such that
+ * maxScale * splineLen = totLength
+ */
+ state->curve_scale = tree->totlength / splineLen;
+ }
+
+ return true;
}
/* Evaluate spline IK for a given bone. */
-static void splineik_evaluate_bone(tSplineIK_Tree *tree, Object *ob, bPoseChannel *pchan, int index, tSplineIk_EvalState *state)
+static void splineik_evaluate_bone(
+ tSplineIK_Tree *tree, Object *ob, bPoseChannel *pchan, int index, tSplineIk_EvalState *state)
{
- bSplineIKConstraint *ikData = tree->ikData;
- float origHead[3], origTail[3], poseHead[3], poseTail[3], basePoseMat[3][3], poseMat[3][3];
- float splineVec[3], scaleFac, radius = 1.0f;
- float tailBlendFac = 0.0f;
-
- mul_v3_m4v3(poseHead, state->locrot_offset, pchan->pose_head);
- mul_v3_m4v3(poseTail, state->locrot_offset, pchan->pose_tail);
-
- copy_v3_v3(origHead, poseHead);
-
- /* first, adjust the point positions on the curve */
- float curveLen = tree->points[index] - tree->points[index + 1];
- float pointStart = state->curve_position;
- float baseScale = 1.0f;
-
- if (ikData->yScaleMode == CONSTRAINT_SPLINEIK_YS_ORIGINAL) {
- /* Carry over the bone Y scale to the curve range. */
- baseScale = len_v3v3(poseHead, poseTail) / pchan->bone->length;
- }
-
- float pointEnd = pointStart + curveLen * baseScale * state->curve_scale;
-
- state->curve_position = pointEnd;
-
- /* step 1: determine the positions for the endpoints of the bone */
- if (pointStart < 1.0f) {
- float vec[4], dir[3], rad;
-
- /* determine if the bone should still be affected by SplineIK */
- if (pointEnd >= 1.0f) {
- /* blending factor depends on the amount of the bone still left on the chain */
- tailBlendFac = (1.0f - pointStart) / (pointEnd - pointStart);
- }
- else {
- tailBlendFac = 1.0f;
- }
-
- /* tail endpoint */
- if (where_on_path(ikData->tar, pointEnd, vec, dir, NULL, &rad, NULL)) {
- /* apply curve's object-mode transforms to the position
- * unless the option to allow curve to be positioned elsewhere is activated (i.e. no root)
- */
- if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) == 0)
- mul_m4_v3(ikData->tar->obmat, vec);
-
- /* convert the position to pose-space, then store it */
- mul_m4_v3(ob->imat, vec);
- copy_v3_v3(poseTail, vec);
-
- /* set the new radius */
- radius = rad;
- }
-
- /* head endpoint */
- if (where_on_path(ikData->tar, pointStart, vec, dir, NULL, &rad, NULL)) {
- /* apply curve's object-mode transforms to the position
- * unless the option to allow curve to be positioned elsewhere is activated (i.e. no root)
- */
- if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) == 0)
- mul_m4_v3(ikData->tar->obmat, vec);
-
- /* store the position, and convert it to pose space */
- mul_m4_v3(ob->imat, vec);
- copy_v3_v3(poseHead, vec);
-
- /* set the new radius (it should be the average value) */
- radius = (radius + rad) / 2;
- }
- }
-
- /* step 2: determine the implied transform from these endpoints
- * - splineVec: the vector direction that the spline applies on the bone
- * - scaleFac: the factor that the bone length is scaled by to get the desired amount
- */
- sub_v3_v3v3(splineVec, poseTail, poseHead);
- scaleFac = len_v3(splineVec) / pchan->bone->length;
-
- /* Adjust the scale factor towards the neutral state when rolling off the curve end. */
- scaleFac = interpf(scaleFac, baseScale, tailBlendFac);
-
- /* step 3: compute the shortest rotation needed to map from the bone rotation to the current axis
- * - this uses the same method as is used for the Damped Track Constraint (see the code there for details)
- */
- {
- float dmat[3][3], rmat[3][3];
- float raxis[3], rangle;
-
- /* compute the raw rotation matrix from the bone's current matrix by extracting only the
- * orientation-relevant axes, and normalizing them
- */
- mul_m3_m4m4(basePoseMat, state->locrot_offset, pchan->pose_mat);
- normalize_m3_m3(rmat, basePoseMat);
-
- /* also, normalize the orientation imposed by the bone, now that we've extracted the scale factor */
- normalize_v3(splineVec);
-
- /* calculate smallest axis-angle rotation necessary for getting from the
- * current orientation of the bone, to the spline-imposed direction
- */
- cross_v3_v3v3(raxis, rmat[1], splineVec);
-
- rangle = dot_v3v3(rmat[1], splineVec);
- CLAMP(rangle, -1.0f, 1.0f);
- rangle = acosf(rangle);
-
- /* multiply the magnitude of the angle by the influence of the constraint to
- * control the influence of the SplineIK effect
- */
- rangle *= tree->con->enforce * tailBlendFac;
-
- /* construct rotation matrix from the axis-angle rotation found above
- * - this call takes care to make sure that the axis provided is a unit vector first
- */
- axis_angle_to_mat3(dmat, raxis, rangle);
-
- /* combine these rotations so that the y-axis of the bone is now aligned as the spline dictates,
- * while still maintaining roll control from the existing bone animation
- */
- mul_m3_m3m3(poseMat, dmat, rmat);
- normalize_m3(poseMat); /* attempt to reduce shearing, though I doubt this'll really help too much now... */
-
- mul_m3_m3m3(basePoseMat, dmat, basePoseMat);
-
- /* apply rotation to the accumulated parent transform */
- mul_m4_m3m4(state->locrot_offset, dmat, state->locrot_offset);
- }
-
- /* step 4: set the scaling factors for the axes */
- {
- /* only multiply the y-axis by the scaling factor to get nice volume-preservation */
- mul_v3_fl(poseMat[1], scaleFac);
-
- /* set the scaling factors of the x and z axes from... */
- switch (ikData->xzScaleMode) {
- case CONSTRAINT_SPLINEIK_XZS_ORIGINAL:
- {
- /* original scales get used */
- float scale;
-
- /* x-axis scale */
- scale = len_v3(pchan->pose_mat[0]);
- mul_v3_fl(poseMat[0], scale);
- /* z-axis scale */
- scale = len_v3(pchan->pose_mat[2]);
- mul_v3_fl(poseMat[2], scale);
- break;
- }
- case CONSTRAINT_SPLINEIK_XZS_INVERSE:
- {
- /* old 'volume preservation' method using the inverse scale */
- float scale;
-
- /* calculate volume preservation factor which is
- * basically the inverse of the y-scaling factor
- */
- if (fabsf(scaleFac) != 0.0f) {
- scale = 1.0f / fabsf(scaleFac);
-
- /* we need to clamp this within sensible values */
- /* NOTE: these should be fine for now, but should get sanitised in future */
- CLAMP(scale, 0.0001f, 100000.0f);
- }
- else
- scale = 1.0f;
-
- /* apply the scaling */
- mul_v3_fl(poseMat[0], scale);
- mul_v3_fl(poseMat[2], scale);
- break;
- }
- case CONSTRAINT_SPLINEIK_XZS_VOLUMETRIC:
- {
- /* improved volume preservation based on the Stretch To constraint */
- float final_scale;
-
- /* as the basis for volume preservation, we use the inverse scale factor... */
- if (fabsf(scaleFac) != 0.0f) {
- /* NOTE: The method here is taken wholesale from the Stretch To constraint */
- float bulge = powf(1.0f / fabsf(scaleFac), ikData->bulge);
-
- if (bulge > 1.0f) {
- if (ikData->flag & CONSTRAINT_SPLINEIK_USE_BULGE_MAX) {
- float bulge_max = max_ff(ikData->bulge_max, 1.0f);
- float hard = min_ff(bulge, bulge_max);
-
- float range = bulge_max - 1.0f;
- float scale = (range > 0.0f) ? 1.0f / range : 0.0f;
- float soft = 1.0f + range * atanf((bulge - 1.0f) * scale) / (float)M_PI_2;
-
- bulge = interpf(soft, hard, ikData->bulge_smooth);
- }
- }
- if (bulge < 1.0f) {
- if (ikData->flag & CONSTRAINT_SPLINEIK_USE_BULGE_MIN) {
- float bulge_min = CLAMPIS(ikData->bulge_min, 0.0f, 1.0f);
- float hard = max_ff(bulge, bulge_min);
-
- float range = 1.0f - bulge_min;
- float scale = (range > 0.0f) ? 1.0f / range : 0.0f;
- float soft = 1.0f - range * atanf((1.0f - bulge) * scale) / (float)M_PI_2;
-
- bulge = interpf(soft, hard, ikData->bulge_smooth);
- }
- }
-
- /* compute scale factor for xz axes from this value */
- final_scale = sqrtf(bulge);
- }
- else {
- /* no scaling, so scale factor is simple */
- final_scale = 1.0f;
- }
-
- /* apply the scaling (assuming normalised scale) */
- mul_v3_fl(poseMat[0], final_scale);
- mul_v3_fl(poseMat[2], final_scale);
- break;
- }
- }
-
- /* finally, multiply the x and z scaling by the radius of the curve too,
- * to allow automatic scales to get tweaked still
- */
- if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_CURVERAD) == 0) {
- mul_v3_fl(poseMat[0], radius);
- mul_v3_fl(poseMat[2], radius);
- }
- }
-
- /* Blend the scaling of the matrix according to the influence. */
- sub_m3_m3m3(poseMat, poseMat, basePoseMat);
- madd_m3_m3m3fl(poseMat, basePoseMat, poseMat, tree->con->enforce * tailBlendFac);
-
- /* step 5: set the location of the bone in the matrix */
- if (ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) {
- /* when the 'no-root' option is affected, the chain can retain
- * the shape but be moved elsewhere
- */
- copy_v3_v3(poseHead, origHead);
- }
- else if (tree->con->enforce < 1.0f) {
- /* when the influence is too low
- * - blend the positions for the 'root' bone
- * - stick to the parent for any other
- */
- if (index < tree->chainlen - 1) {
- copy_v3_v3(poseHead, origHead);
- }
- else {
- interp_v3_v3v3(poseHead, origHead, poseHead, tree->con->enforce);
- }
- }
-
- /* finally, store the new transform */
- copy_m4_m3(pchan->pose_mat, poseMat);
- copy_v3_v3(pchan->pose_mat[3], poseHead);
- copy_v3_v3(pchan->pose_head, poseHead);
-
- mul_v3_mat3_m4v3(origTail, state->locrot_offset, pchan->pose_tail);
-
- /* recalculate tail, as it's now outdated after the head gets adjusted above! */
- BKE_pose_where_is_bone_tail(pchan);
-
- /* update the offset in the accumulated parent transform */
- sub_v3_v3v3(state->locrot_offset[3], pchan->pose_tail, origTail);
-
- /* done! */
- pchan->flag |= POSE_DONE;
+ bSplineIKConstraint *ikData = tree->ikData;
+ float origHead[3], origTail[3], poseHead[3], poseTail[3], basePoseMat[3][3], poseMat[3][3];
+ float splineVec[3], scaleFac, radius = 1.0f;
+ float tailBlendFac = 0.0f;
+
+ mul_v3_m4v3(poseHead, state->locrot_offset, pchan->pose_head);
+ mul_v3_m4v3(poseTail, state->locrot_offset, pchan->pose_tail);
+
+ copy_v3_v3(origHead, poseHead);
+
+ /* first, adjust the point positions on the curve */
+ float curveLen = tree->points[index] - tree->points[index + 1];
+ float pointStart = state->curve_position;
+ float baseScale = 1.0f;
+
+ if (ikData->yScaleMode == CONSTRAINT_SPLINEIK_YS_ORIGINAL) {
+ /* Carry over the bone Y scale to the curve range. */
+ baseScale = len_v3v3(poseHead, poseTail) / pchan->bone->length;
+ }
+
+ float pointEnd = pointStart + curveLen * baseScale * state->curve_scale;
+
+ state->curve_position = pointEnd;
+
+ /* step 1: determine the positions for the endpoints of the bone */
+ if (pointStart < 1.0f) {
+ float vec[4], dir[3], rad;
+
+ /* determine if the bone should still be affected by SplineIK */
+ if (pointEnd >= 1.0f) {
+ /* blending factor depends on the amount of the bone still left on the chain */
+ tailBlendFac = (1.0f - pointStart) / (pointEnd - pointStart);
+ }
+ else {
+ tailBlendFac = 1.0f;
+ }
+
+ /* tail endpoint */
+ if (where_on_path(ikData->tar, pointEnd, vec, dir, NULL, &rad, NULL)) {
+ /* apply curve's object-mode transforms to the position
+ * unless the option to allow curve to be positioned elsewhere is activated (i.e. no root)
+ */
+ if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) == 0)
+ mul_m4_v3(ikData->tar->obmat, vec);
+
+ /* convert the position to pose-space, then store it */
+ mul_m4_v3(ob->imat, vec);
+ copy_v3_v3(poseTail, vec);
+
+ /* set the new radius */
+ radius = rad;
+ }
+
+ /* head endpoint */
+ if (where_on_path(ikData->tar, pointStart, vec, dir, NULL, &rad, NULL)) {
+ /* apply curve's object-mode transforms to the position
+ * unless the option to allow curve to be positioned elsewhere is activated (i.e. no root)
+ */
+ if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) == 0)
+ mul_m4_v3(ikData->tar->obmat, vec);
+
+ /* store the position, and convert it to pose space */
+ mul_m4_v3(ob->imat, vec);
+ copy_v3_v3(poseHead, vec);
+
+ /* set the new radius (it should be the average value) */
+ radius = (radius + rad) / 2;
+ }
+ }
+
+ /* step 2: determine the implied transform from these endpoints
+ * - splineVec: the vector direction that the spline applies on the bone
+ * - scaleFac: the factor that the bone length is scaled by to get the desired amount
+ */
+ sub_v3_v3v3(splineVec, poseTail, poseHead);
+ scaleFac = len_v3(splineVec) / pchan->bone->length;
+
+ /* Adjust the scale factor towards the neutral state when rolling off the curve end. */
+ scaleFac = interpf(scaleFac, baseScale, tailBlendFac);
+
+ /* step 3: compute the shortest rotation needed to map from the bone rotation to the current axis
+ * - this uses the same method as is used for the Damped Track Constraint (see the code there for details)
+ */
+ {
+ float dmat[3][3], rmat[3][3];
+ float raxis[3], rangle;
+
+ /* compute the raw rotation matrix from the bone's current matrix by extracting only the
+ * orientation-relevant axes, and normalizing them
+ */
+ mul_m3_m4m4(basePoseMat, state->locrot_offset, pchan->pose_mat);
+ normalize_m3_m3(rmat, basePoseMat);
+
+ /* also, normalize the orientation imposed by the bone, now that we've extracted the scale factor */
+ normalize_v3(splineVec);
+
+ /* calculate smallest axis-angle rotation necessary for getting from the
+ * current orientation of the bone, to the spline-imposed direction
+ */
+ cross_v3_v3v3(raxis, rmat[1], splineVec);
+
+ rangle = dot_v3v3(rmat[1], splineVec);
+ CLAMP(rangle, -1.0f, 1.0f);
+ rangle = acosf(rangle);
+
+ /* multiply the magnitude of the angle by the influence of the constraint to
+ * control the influence of the SplineIK effect
+ */
+ rangle *= tree->con->enforce * tailBlendFac;
+
+ /* construct rotation matrix from the axis-angle rotation found above
+ * - this call takes care to make sure that the axis provided is a unit vector first
+ */
+ axis_angle_to_mat3(dmat, raxis, rangle);
+
+ /* combine these rotations so that the y-axis of the bone is now aligned as the spline dictates,
+ * while still maintaining roll control from the existing bone animation
+ */
+ mul_m3_m3m3(poseMat, dmat, rmat);
+ normalize_m3(
+ poseMat); /* attempt to reduce shearing, though I doubt this'll really help too much now... */
+
+ mul_m3_m3m3(basePoseMat, dmat, basePoseMat);
+
+ /* apply rotation to the accumulated parent transform */
+ mul_m4_m3m4(state->locrot_offset, dmat, state->locrot_offset);
+ }
+
+ /* step 4: set the scaling factors for the axes */
+ {
+ /* only multiply the y-axis by the scaling factor to get nice volume-preservation */
+ mul_v3_fl(poseMat[1], scaleFac);
+
+ /* set the scaling factors of the x and z axes from... */
+ switch (ikData->xzScaleMode) {
+ case CONSTRAINT_SPLINEIK_XZS_ORIGINAL: {
+ /* original scales get used */
+ float scale;
+
+ /* x-axis scale */
+ scale = len_v3(pchan->pose_mat[0]);
+ mul_v3_fl(poseMat[0], scale);
+ /* z-axis scale */
+ scale = len_v3(pchan->pose_mat[2]);
+ mul_v3_fl(poseMat[2], scale);
+ break;
+ }
+ case CONSTRAINT_SPLINEIK_XZS_INVERSE: {
+ /* old 'volume preservation' method using the inverse scale */
+ float scale;
+
+ /* calculate volume preservation factor which is
+ * basically the inverse of the y-scaling factor
+ */
+ if (fabsf(scaleFac) != 0.0f) {
+ scale = 1.0f / fabsf(scaleFac);
+
+ /* we need to clamp this within sensible values */
+ /* NOTE: these should be fine for now, but should get sanitised in future */
+ CLAMP(scale, 0.0001f, 100000.0f);
+ }
+ else
+ scale = 1.0f;
+
+ /* apply the scaling */
+ mul_v3_fl(poseMat[0], scale);
+ mul_v3_fl(poseMat[2], scale);
+ break;
+ }
+ case CONSTRAINT_SPLINEIK_XZS_VOLUMETRIC: {
+ /* improved volume preservation based on the Stretch To constraint */
+ float final_scale;
+
+ /* as the basis for volume preservation, we use the inverse scale factor... */
+ if (fabsf(scaleFac) != 0.0f) {
+ /* NOTE: The method here is taken wholesale from the Stretch To constraint */
+ float bulge = powf(1.0f / fabsf(scaleFac), ikData->bulge);
+
+ if (bulge > 1.0f) {
+ if (ikData->flag & CONSTRAINT_SPLINEIK_USE_BULGE_MAX) {
+ float bulge_max = max_ff(ikData->bulge_max, 1.0f);
+ float hard = min_ff(bulge, bulge_max);
+
+ float range = bulge_max - 1.0f;
+ float scale = (range > 0.0f) ? 1.0f / range : 0.0f;
+ float soft = 1.0f + range * atanf((bulge - 1.0f) * scale) / (float)M_PI_2;
+
+ bulge = interpf(soft, hard, ikData->bulge_smooth);
+ }
+ }
+ if (bulge < 1.0f) {
+ if (ikData->flag & CONSTRAINT_SPLINEIK_USE_BULGE_MIN) {
+ float bulge_min = CLAMPIS(ikData->bulge_min, 0.0f, 1.0f);
+ float hard = max_ff(bulge, bulge_min);
+
+ float range = 1.0f - bulge_min;
+ float scale = (range > 0.0f) ? 1.0f / range : 0.0f;
+ float soft = 1.0f - range * atanf((1.0f - bulge) * scale) / (float)M_PI_2;
+
+ bulge = interpf(soft, hard, ikData->bulge_smooth);
+ }
+ }
+
+ /* compute scale factor for xz axes from this value */
+ final_scale = sqrtf(bulge);
+ }
+ else {
+ /* no scaling, so scale factor is simple */
+ final_scale = 1.0f;
+ }
+
+ /* apply the scaling (assuming normalised scale) */
+ mul_v3_fl(poseMat[0], final_scale);
+ mul_v3_fl(poseMat[2], final_scale);
+ break;
+ }
+ }
+
+ /* finally, multiply the x and z scaling by the radius of the curve too,
+ * to allow automatic scales to get tweaked still
+ */
+ if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_CURVERAD) == 0) {
+ mul_v3_fl(poseMat[0], radius);
+ mul_v3_fl(poseMat[2], radius);
+ }
+ }
+
+ /* Blend the scaling of the matrix according to the influence. */
+ sub_m3_m3m3(poseMat, poseMat, basePoseMat);
+ madd_m3_m3m3fl(poseMat, basePoseMat, poseMat, tree->con->enforce * tailBlendFac);
+
+ /* step 5: set the location of the bone in the matrix */
+ if (ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) {
+ /* when the 'no-root' option is affected, the chain can retain
+ * the shape but be moved elsewhere
+ */
+ copy_v3_v3(poseHead, origHead);
+ }
+ else if (tree->con->enforce < 1.0f) {
+ /* when the influence is too low
+ * - blend the positions for the 'root' bone
+ * - stick to the parent for any other
+ */
+ if (index < tree->chainlen - 1) {
+ copy_v3_v3(poseHead, origHead);
+ }
+ else {
+ interp_v3_v3v3(poseHead, origHead, poseHead, tree->con->enforce);
+ }
+ }
+
+ /* finally, store the new transform */
+ copy_m4_m3(pchan->pose_mat, poseMat);
+ copy_v3_v3(pchan->pose_mat[3], poseHead);
+ copy_v3_v3(pchan->pose_head, poseHead);
+
+ mul_v3_mat3_m4v3(origTail, state->locrot_offset, pchan->pose_tail);
+
+ /* recalculate tail, as it's now outdated after the head gets adjusted above! */
+ BKE_pose_where_is_bone_tail(pchan);
+
+ /* update the offset in the accumulated parent transform */
+ sub_v3_v3v3(state->locrot_offset[3], pchan->pose_tail, origTail);
+
+ /* done! */
+ pchan->flag |= POSE_DONE;
}
/* Evaluate the chain starting from the nominated bone */
-static void splineik_execute_tree(struct Depsgraph *depsgraph, Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime)
+static void splineik_execute_tree(
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime)
{
- tSplineIK_Tree *tree;
-
- /* for each pose-tree, execute it if it is spline, otherwise just free it */
- while ((tree = pchan_root->siktree.first) != NULL) {
- int i;
-
- /* Firstly, calculate the bone matrix the standard way, since this is needed for roll control. */
- for (i = tree->chainlen - 1; i >= 0; i--) {
- BKE_pose_where_is_bone(depsgraph, scene, ob, tree->chain[i], ctime, 1);
- }
-
- /* After that, evaluate the actual Spline IK, unless there are missing dependencies. */
- tSplineIk_EvalState state;
-
- if (splineik_evaluate_init(tree, &state)) {
- /* Walk over each bone in the chain, calculating the effects of spline IK
- * - the chain is traversed in the opposite order to storage order (i.e. parent to children)
- * so that dependencies are correct
- */
- for (i = tree->chainlen - 1; i >= 0; i--) {
- bPoseChannel *pchan = tree->chain[i];
- splineik_evaluate_bone(tree, ob, pchan, i, &state);
- }
- }
-
- /* free the tree info specific to SplineIK trees now */
- if (tree->chain)
- MEM_freeN(tree->chain);
-
- /* free this tree */
- BLI_freelinkN(&pchan_root->siktree, tree);
- }
+ tSplineIK_Tree *tree;
+
+ /* for each pose-tree, execute it if it is spline, otherwise just free it */
+ while ((tree = pchan_root->siktree.first) != NULL) {
+ int i;
+
+ /* Firstly, calculate the bone matrix the standard way, since this is needed for roll control. */
+ for (i = tree->chainlen - 1; i >= 0; i--) {
+ BKE_pose_where_is_bone(depsgraph, scene, ob, tree->chain[i], ctime, 1);
+ }
+
+ /* After that, evaluate the actual Spline IK, unless there are missing dependencies. */
+ tSplineIk_EvalState state;
+
+ if (splineik_evaluate_init(tree, &state)) {
+ /* Walk over each bone in the chain, calculating the effects of spline IK
+ * - the chain is traversed in the opposite order to storage order (i.e. parent to children)
+ * so that dependencies are correct
+ */
+ for (i = tree->chainlen - 1; i >= 0; i--) {
+ bPoseChannel *pchan = tree->chain[i];
+ splineik_evaluate_bone(tree, ob, pchan, i, &state);
+ }
+ }
+
+ /* free the tree info specific to SplineIK trees now */
+ if (tree->chain)
+ MEM_freeN(tree->chain);
+
+ /* free this tree */
+ BLI_freelinkN(&pchan_root->siktree, tree);
+ }
}
void BKE_pose_splineik_init_tree(Scene *scene, Object *ob, float ctime)
{
- splineik_init_tree(scene, ob, ctime);
+ splineik_init_tree(scene, ob, ctime);
}
void BKE_splineik_execute_tree(
- struct Depsgraph *depsgraph, Scene *scene,
- Object *ob, bPoseChannel *pchan_root, float ctime)
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime)
{
- splineik_execute_tree(depsgraph, scene, ob, pchan_root, ctime);
+ splineik_execute_tree(depsgraph, scene, ob, pchan_root, ctime);
}
/* *************** Depsgraph evaluation callbacks ************ */
void BKE_pose_pchan_index_rebuild(bPose *pose)
{
- MEM_SAFE_FREE(pose->chan_array);
- const int num_channels = BLI_listbase_count(&pose->chanbase);
- pose->chan_array = MEM_malloc_arrayN(
- num_channels, sizeof(bPoseChannel *), "pose->chan_array");
- int pchan_index = 0;
- for (bPoseChannel *pchan = pose->chanbase.first; pchan != NULL; pchan = pchan->next) {
- pose->chan_array[pchan_index++] = pchan;
- }
+ MEM_SAFE_FREE(pose->chan_array);
+ const int num_channels = BLI_listbase_count(&pose->chanbase);
+ pose->chan_array = MEM_malloc_arrayN(num_channels, sizeof(bPoseChannel *), "pose->chan_array");
+ int pchan_index = 0;
+ for (bPoseChannel *pchan = pose->chanbase.first; pchan != NULL; pchan = pchan->next) {
+ pose->chan_array[pchan_index++] = pchan;
+ }
}
BLI_INLINE bPoseChannel *pose_pchan_get_indexed(Object *ob, int pchan_index)
{
- bPose *pose = ob->pose;
- BLI_assert(pose != NULL);
- BLI_assert(pose->chan_array != NULL);
- BLI_assert(pchan_index >= 0);
- BLI_assert(pchan_index < MEM_allocN_len(pose->chan_array) / sizeof(bPoseChannel *));
- return pose->chan_array[pchan_index];
+ bPose *pose = ob->pose;
+ BLI_assert(pose != NULL);
+ BLI_assert(pose->chan_array != NULL);
+ BLI_assert(pchan_index >= 0);
+ BLI_assert(pchan_index < MEM_allocN_len(pose->chan_array) / sizeof(bPoseChannel *));
+ return pose->chan_array[pchan_index];
}
-void BKE_pose_eval_init(struct Depsgraph *depsgraph,
- Scene *UNUSED(scene),
- Object *object)
+void BKE_pose_eval_init(struct Depsgraph *depsgraph, Scene *UNUSED(scene), Object *object)
{
- bPose *pose = object->pose;
- BLI_assert(pose != NULL);
+ bPose *pose = object->pose;
+ BLI_assert(pose != NULL);
- DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
- BLI_assert(object->type == OB_ARMATURE);
+ BLI_assert(object->type == OB_ARMATURE);
- /* We demand having proper pose. */
- BLI_assert(object->pose != NULL);
- BLI_assert((object->pose->flag & POSE_RECALC) == 0);
+ /* We demand having proper pose. */
+ BLI_assert(object->pose != NULL);
+ BLI_assert((object->pose->flag & POSE_RECALC) == 0);
- /* imat is needed for solvers. */
- invert_m4_m4(object->imat, object->obmat);
+ /* imat is needed for solvers. */
+ invert_m4_m4(object->imat, object->obmat);
- /* clear flags */
- for (bPoseChannel *pchan = pose->chanbase.first; pchan != NULL; pchan = pchan->next) {
- pchan->flag &= ~(POSE_DONE | POSE_CHAIN | POSE_IKTREE | POSE_IKSPLINE);
+ /* clear flags */
+ for (bPoseChannel *pchan = pose->chanbase.first; pchan != NULL; pchan = pchan->next) {
+ pchan->flag &= ~(POSE_DONE | POSE_CHAIN | POSE_IKTREE | POSE_IKSPLINE);
- /* Free B-Bone shape data cache if it's not a B-Bone. */
- if (pchan->bone == NULL || pchan->bone->segments <= 1) {
- BKE_pose_channel_free_bbone_cache(pchan);
- }
- }
+ /* Free B-Bone shape data cache if it's not a B-Bone. */
+ if (pchan->bone == NULL || pchan->bone->segments <= 1) {
+ BKE_pose_channel_free_bbone_cache(pchan);
+ }
+ }
- BLI_assert(pose->chan_array != NULL || BLI_listbase_is_empty(&pose->chanbase));
+ BLI_assert(pose->chan_array != NULL || BLI_listbase_is_empty(&pose->chanbase));
- BKE_armature_cached_bbone_deformation_free_data(object);
+ BKE_armature_cached_bbone_deformation_free_data(object);
}
-void BKE_pose_eval_init_ik(struct Depsgraph *depsgraph,
- Scene *scene,
- Object *object)
+void BKE_pose_eval_init_ik(struct Depsgraph *depsgraph, Scene *scene, Object *object)
{
- DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
- BLI_assert(object->type == OB_ARMATURE);
- const float ctime = BKE_scene_frame_get(scene); /* not accurate... */
- bArmature *armature = (bArmature *)object->data;
- if (armature->flag & ARM_RESTPOS) {
- return;
- }
- /* construct the IK tree (standard IK) */
- BIK_initialize_tree(depsgraph, scene, object, ctime);
- /* construct the Spline IK trees
- * - this is not integrated as an IK plugin, since it should be able
- * to function in conjunction with standard IK. */
- BKE_pose_splineik_init_tree(scene, object, ctime);
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
+ BLI_assert(object->type == OB_ARMATURE);
+ const float ctime = BKE_scene_frame_get(scene); /* not accurate... */
+ bArmature *armature = (bArmature *)object->data;
+ if (armature->flag & ARM_RESTPOS) {
+ return;
+ }
+ /* construct the IK tree (standard IK) */
+ BIK_initialize_tree(depsgraph, scene, object, ctime);
+ /* construct the Spline IK trees
+ * - this is not integrated as an IK plugin, since it should be able
+ * to function in conjunction with standard IK. */
+ BKE_pose_splineik_init_tree(scene, object, ctime);
}
-void BKE_pose_eval_bone(struct Depsgraph *depsgraph,
- Scene *scene,
- Object *object,
- int pchan_index)
+void BKE_pose_eval_bone(struct Depsgraph *depsgraph, Scene *scene, Object *object, int pchan_index)
{
- const bArmature *armature = (bArmature *)object->data;
- if (armature->edbo != NULL) {
- return;
- }
- bPoseChannel *pchan = pose_pchan_get_indexed(object, pchan_index);
- DEG_debug_print_eval_subdata(
- depsgraph, __func__, object->id.name, object,
- "pchan", pchan->name, pchan);
- BLI_assert(object->type == OB_ARMATURE);
- if (armature->flag & ARM_RESTPOS) {
- Bone *bone = pchan->bone;
- if (bone) {
- copy_m4_m4(pchan->pose_mat, bone->arm_mat);
- copy_v3_v3(pchan->pose_head, bone->arm_head);
- copy_v3_v3(pchan->pose_tail, bone->arm_tail);
- }
- }
- else {
- /* TODO(sergey): Currently if there are constraints full transform is
- * being evaluated in BKE_pose_constraints_evaluate. */
- if (pchan->constraints.first == NULL) {
- if (pchan->flag & POSE_IKTREE || pchan->flag & POSE_IKSPLINE) {
- /* pass */
- }
- else {
- if ((pchan->flag & POSE_DONE) == 0) {
- /* TODO(sergey): Use time source node for time. */
- float ctime = BKE_scene_frame_get(scene); /* not accurate... */
- BKE_pose_where_is_bone(depsgraph, scene, object, pchan, ctime, 1);
- }
- }
- }
- }
+ const bArmature *armature = (bArmature *)object->data;
+ if (armature->edbo != NULL) {
+ return;
+ }
+ bPoseChannel *pchan = pose_pchan_get_indexed(object, pchan_index);
+ DEG_debug_print_eval_subdata(
+ depsgraph, __func__, object->id.name, object, "pchan", pchan->name, pchan);
+ BLI_assert(object->type == OB_ARMATURE);
+ if (armature->flag & ARM_RESTPOS) {
+ Bone *bone = pchan->bone;
+ if (bone) {
+ copy_m4_m4(pchan->pose_mat, bone->arm_mat);
+ copy_v3_v3(pchan->pose_head, bone->arm_head);
+ copy_v3_v3(pchan->pose_tail, bone->arm_tail);
+ }
+ }
+ else {
+ /* TODO(sergey): Currently if there are constraints full transform is
+ * being evaluated in BKE_pose_constraints_evaluate. */
+ if (pchan->constraints.first == NULL) {
+ if (pchan->flag & POSE_IKTREE || pchan->flag & POSE_IKSPLINE) {
+ /* pass */
+ }
+ else {
+ if ((pchan->flag & POSE_DONE) == 0) {
+ /* TODO(sergey): Use time source node for time. */
+ float ctime = BKE_scene_frame_get(scene); /* not accurate... */
+ BKE_pose_where_is_bone(depsgraph, scene, object, pchan, ctime, 1);
+ }
+ }
+ }
+ }
}
void BKE_pose_constraints_evaluate(struct Depsgraph *depsgraph,
@@ -688,76 +680,71 @@ void BKE_pose_constraints_evaluate(struct Depsgraph *depsgraph,
Object *object,
int pchan_index)
{
- const bArmature *armature = (bArmature *)object->data;
- if (armature->edbo != NULL) {
- return;
- }
- bPoseChannel *pchan = pose_pchan_get_indexed(object, pchan_index);
- DEG_debug_print_eval_subdata(
- depsgraph, __func__, object->id.name, object,
- "pchan", pchan->name, pchan);
- if (armature->flag & ARM_RESTPOS) {
- return;
- }
- else if (pchan->flag & POSE_IKTREE || pchan->flag & POSE_IKSPLINE) {
- /* IK are being solved separately/ */
- }
- else {
- if ((pchan->flag & POSE_DONE) == 0) {
- float ctime = BKE_scene_frame_get(scene); /* not accurate... */
- BKE_pose_where_is_bone(depsgraph, scene, object, pchan, ctime, 1);
- }
- }
+ const bArmature *armature = (bArmature *)object->data;
+ if (armature->edbo != NULL) {
+ return;
+ }
+ bPoseChannel *pchan = pose_pchan_get_indexed(object, pchan_index);
+ DEG_debug_print_eval_subdata(
+ depsgraph, __func__, object->id.name, object, "pchan", pchan->name, pchan);
+ if (armature->flag & ARM_RESTPOS) {
+ return;
+ }
+ else if (pchan->flag & POSE_IKTREE || pchan->flag & POSE_IKSPLINE) {
+ /* IK are being solved separately/ */
+ }
+ else {
+ if ((pchan->flag & POSE_DONE) == 0) {
+ float ctime = BKE_scene_frame_get(scene); /* not accurate... */
+ BKE_pose_where_is_bone(depsgraph, scene, object, pchan, ctime, 1);
+ }
+ }
}
-void BKE_pose_bone_done(struct Depsgraph *depsgraph,
- struct Object *object,
- int pchan_index)
+void BKE_pose_bone_done(struct Depsgraph *depsgraph, struct Object *object, int pchan_index)
{
- const bArmature *armature = (bArmature *)object->data;
- if (armature->edbo != NULL) {
- return;
- }
- bPoseChannel *pchan = pose_pchan_get_indexed(object, pchan_index);
- float imat[4][4];
- DEG_debug_print_eval_subdata(
- depsgraph, __func__, object->id.name, object,
- "pchan", pchan->name, pchan);
- if (pchan->bone) {
- invert_m4_m4(imat, pchan->bone->arm_mat);
- mul_m4_m4m4(pchan->chan_mat, pchan->pose_mat, imat);
- }
- if (DEG_is_active(depsgraph) && armature->edbo == NULL) {
- bPoseChannel *pchan_orig = pchan->orig_pchan;
- copy_m4_m4(pchan_orig->pose_mat, pchan->pose_mat);
- copy_m4_m4(pchan_orig->chan_mat, pchan->chan_mat);
- copy_v3_v3(pchan_orig->pose_head, pchan->pose_mat[3]);
- copy_m4_m4(pchan_orig->constinv, pchan->constinv);
- BKE_pose_where_is_bone_tail(pchan_orig);
- if (pchan->bone == NULL || pchan->bone->segments <= 1) {
- BKE_pose_channel_free_bbone_cache(pchan_orig);
- }
- }
+ const bArmature *armature = (bArmature *)object->data;
+ if (armature->edbo != NULL) {
+ return;
+ }
+ bPoseChannel *pchan = pose_pchan_get_indexed(object, pchan_index);
+ float imat[4][4];
+ DEG_debug_print_eval_subdata(
+ depsgraph, __func__, object->id.name, object, "pchan", pchan->name, pchan);
+ if (pchan->bone) {
+ invert_m4_m4(imat, pchan->bone->arm_mat);
+ mul_m4_m4m4(pchan->chan_mat, pchan->pose_mat, imat);
+ }
+ if (DEG_is_active(depsgraph) && armature->edbo == NULL) {
+ bPoseChannel *pchan_orig = pchan->orig_pchan;
+ copy_m4_m4(pchan_orig->pose_mat, pchan->pose_mat);
+ copy_m4_m4(pchan_orig->chan_mat, pchan->chan_mat);
+ copy_v3_v3(pchan_orig->pose_head, pchan->pose_mat[3]);
+ copy_m4_m4(pchan_orig->constinv, pchan->constinv);
+ BKE_pose_where_is_bone_tail(pchan_orig);
+ if (pchan->bone == NULL || pchan->bone->segments <= 1) {
+ BKE_pose_channel_free_bbone_cache(pchan_orig);
+ }
+ }
}
void BKE_pose_eval_bbone_segments(struct Depsgraph *depsgraph,
struct Object *object,
int pchan_index)
{
- const bArmature *armature = (bArmature *)object->data;
- if (armature->edbo != NULL) {
- return;
- }
- bPoseChannel *pchan = pose_pchan_get_indexed(object, pchan_index);
- DEG_debug_print_eval_subdata(
- depsgraph, __func__, object->id.name, object,
- "pchan", pchan->name, pchan);
- if (pchan->bone != NULL && pchan->bone->segments > 1) {
- BKE_pchan_bbone_segments_cache_compute(pchan);
- if (DEG_is_active(depsgraph)) {
- BKE_pchan_bbone_segments_cache_copy(pchan->orig_pchan, pchan);
- }
- }
+ const bArmature *armature = (bArmature *)object->data;
+ if (armature->edbo != NULL) {
+ return;
+ }
+ bPoseChannel *pchan = pose_pchan_get_indexed(object, pchan_index);
+ DEG_debug_print_eval_subdata(
+ depsgraph, __func__, object->id.name, object, "pchan", pchan->name, pchan);
+ if (pchan->bone != NULL && pchan->bone->segments > 1) {
+ BKE_pchan_bbone_segments_cache_compute(pchan);
+ if (DEG_is_active(depsgraph)) {
+ BKE_pchan_bbone_segments_cache_copy(pchan->orig_pchan, pchan);
+ }
+ }
}
void BKE_pose_iktree_evaluate(struct Depsgraph *depsgraph,
@@ -765,20 +752,19 @@ void BKE_pose_iktree_evaluate(struct Depsgraph *depsgraph,
Object *object,
int rootchan_index)
{
- const bArmature *armature = (bArmature *)object->data;
- if (armature->edbo != NULL) {
- return;
- }
- bPoseChannel *rootchan = pose_pchan_get_indexed(object, rootchan_index);
- DEG_debug_print_eval_subdata(
- depsgraph, __func__, object->id.name, object,
- "rootchan", rootchan->name, rootchan);
- BLI_assert(object->type == OB_ARMATURE);
- const float ctime = BKE_scene_frame_get(scene); /* not accurate... */
- if (armature->flag & ARM_RESTPOS) {
- return;
- }
- BIK_execute_tree(depsgraph, scene, object, rootchan, ctime);
+ const bArmature *armature = (bArmature *)object->data;
+ if (armature->edbo != NULL) {
+ return;
+ }
+ bPoseChannel *rootchan = pose_pchan_get_indexed(object, rootchan_index);
+ DEG_debug_print_eval_subdata(
+ depsgraph, __func__, object->id.name, object, "rootchan", rootchan->name, rootchan);
+ BLI_assert(object->type == OB_ARMATURE);
+ const float ctime = BKE_scene_frame_get(scene); /* not accurate... */
+ if (armature->flag & ARM_RESTPOS) {
+ return;
+ }
+ BIK_execute_tree(depsgraph, scene, object, rootchan, ctime);
}
void BKE_pose_splineik_evaluate(struct Depsgraph *depsgraph,
@@ -787,117 +773,109 @@ void BKE_pose_splineik_evaluate(struct Depsgraph *depsgraph,
int rootchan_index)
{
- const bArmature *armature = (bArmature *)object->data;
- if (armature->edbo != NULL) {
- return;
- }
- bPoseChannel *rootchan = pose_pchan_get_indexed(object, rootchan_index);
- DEG_debug_print_eval_subdata(
- depsgraph, __func__, object->id.name, object,
- "rootchan", rootchan->name, rootchan);
- BLI_assert(object->type == OB_ARMATURE);
- const float ctime = BKE_scene_frame_get(scene); /* not accurate... */
- if (armature->flag & ARM_RESTPOS) {
- return;
- }
- BKE_splineik_execute_tree(depsgraph, scene, object, rootchan, ctime);
+ const bArmature *armature = (bArmature *)object->data;
+ if (armature->edbo != NULL) {
+ return;
+ }
+ bPoseChannel *rootchan = pose_pchan_get_indexed(object, rootchan_index);
+ DEG_debug_print_eval_subdata(
+ depsgraph, __func__, object->id.name, object, "rootchan", rootchan->name, rootchan);
+ BLI_assert(object->type == OB_ARMATURE);
+ const float ctime = BKE_scene_frame_get(scene); /* not accurate... */
+ if (armature->flag & ARM_RESTPOS) {
+ return;
+ }
+ BKE_splineik_execute_tree(depsgraph, scene, object, rootchan, ctime);
}
/* Common part for both original and proxy armatrues. */
static void pose_eval_done_common(struct Depsgraph *depsgraph, Object *object)
{
- const bArmature *armature = (bArmature *)object->data;
- if (armature->edbo != NULL) {
- return;
- }
- bPose *pose = object->pose;
- UNUSED_VARS_NDEBUG(pose);
- BLI_assert(pose != NULL);
- BKE_armature_cached_bbone_deformation_update(object);
- BKE_object_eval_boundbox(depsgraph, object);
+ const bArmature *armature = (bArmature *)object->data;
+ if (armature->edbo != NULL) {
+ return;
+ }
+ bPose *pose = object->pose;
+ UNUSED_VARS_NDEBUG(pose);
+ BLI_assert(pose != NULL);
+ BKE_armature_cached_bbone_deformation_update(object);
+ BKE_object_eval_boundbox(depsgraph, object);
}
static void pose_eval_cleanup_common(Object *object)
{
- bPose *pose = object->pose;
- BLI_assert(pose != NULL);
- BLI_assert(pose->chan_array != NULL || BLI_listbase_is_empty(&pose->chanbase));
+ bPose *pose = object->pose;
+ BLI_assert(pose != NULL);
+ BLI_assert(pose->chan_array != NULL || BLI_listbase_is_empty(&pose->chanbase));
}
void BKE_pose_eval_done(struct Depsgraph *depsgraph, Object *object)
{
- bPose *pose = object->pose;
- BLI_assert(pose != NULL);
- UNUSED_VARS_NDEBUG(pose);
- DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
- BLI_assert(object->type == OB_ARMATURE);
- pose_eval_done_common(depsgraph, object);
+ bPose *pose = object->pose;
+ BLI_assert(pose != NULL);
+ UNUSED_VARS_NDEBUG(pose);
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
+ BLI_assert(object->type == OB_ARMATURE);
+ pose_eval_done_common(depsgraph, object);
}
-void BKE_pose_eval_cleanup(struct Depsgraph *depsgraph,
- Scene *scene,
- Object *object)
+void BKE_pose_eval_cleanup(struct Depsgraph *depsgraph, Scene *scene, Object *object)
{
- bPose *pose = object->pose;
- BLI_assert(pose != NULL);
- UNUSED_VARS_NDEBUG(pose);
- const float ctime = BKE_scene_frame_get(scene); /* not accurate... */
- DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
- BLI_assert(object->type == OB_ARMATURE);
- /* Release the IK tree. */
- BIK_release_tree(scene, object, ctime);
- pose_eval_cleanup_common(object);
+ bPose *pose = object->pose;
+ BLI_assert(pose != NULL);
+ UNUSED_VARS_NDEBUG(pose);
+ const float ctime = BKE_scene_frame_get(scene); /* not accurate... */
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
+ BLI_assert(object->type == OB_ARMATURE);
+ /* Release the IK tree. */
+ BIK_release_tree(scene, object, ctime);
+ pose_eval_cleanup_common(object);
}
void BKE_pose_eval_proxy_init(struct Depsgraph *depsgraph, Object *object)
{
- BLI_assert(ID_IS_LINKED(object) && object->proxy_from != NULL);
- DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
+ BLI_assert(ID_IS_LINKED(object) && object->proxy_from != NULL);
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
- BLI_assert(object->pose->chan_array != NULL || BLI_listbase_is_empty(&object->pose->chanbase));
+ BLI_assert(object->pose->chan_array != NULL || BLI_listbase_is_empty(&object->pose->chanbase));
- BKE_armature_cached_bbone_deformation_free_data(object);
+ BKE_armature_cached_bbone_deformation_free_data(object);
}
void BKE_pose_eval_proxy_done(struct Depsgraph *depsgraph, Object *object)
{
- BLI_assert(ID_IS_LINKED(object) && object->proxy_from != NULL);
- DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
- pose_eval_done_common(depsgraph, object);
+ BLI_assert(ID_IS_LINKED(object) && object->proxy_from != NULL);
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
+ pose_eval_done_common(depsgraph, object);
}
void BKE_pose_eval_proxy_cleanup(struct Depsgraph *depsgraph, Object *object)
{
- BLI_assert(ID_IS_LINKED(object) && object->proxy_from != NULL);
- DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
- pose_eval_cleanup_common(object);
+ BLI_assert(ID_IS_LINKED(object) && object->proxy_from != NULL);
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
+ pose_eval_cleanup_common(object);
}
-void BKE_pose_eval_proxy_copy_bone(
- struct Depsgraph *depsgraph,
- Object *object,
- int pchan_index)
+void BKE_pose_eval_proxy_copy_bone(struct Depsgraph *depsgraph, Object *object, int pchan_index)
{
- const bArmature *armature = (bArmature *)object->data;
- if (armature->edbo != NULL) {
- return;
- }
- BLI_assert(ID_IS_LINKED(object) && object->proxy_from != NULL);
- bPoseChannel *pchan = pose_pchan_get_indexed(object, pchan_index);
- DEG_debug_print_eval_subdata(
- depsgraph, __func__, object->id.name, object,
- "pchan", pchan->name, pchan);
- /* TODO(sergey): Use indexec lookup, once it's guaranteed to be kept
- * around for the time while proxies are evaluating.
- */
+ const bArmature *armature = (bArmature *)object->data;
+ if (armature->edbo != NULL) {
+ return;
+ }
+ BLI_assert(ID_IS_LINKED(object) && object->proxy_from != NULL);
+ bPoseChannel *pchan = pose_pchan_get_indexed(object, pchan_index);
+ DEG_debug_print_eval_subdata(
+ depsgraph, __func__, object->id.name, object, "pchan", pchan->name, pchan);
+ /* TODO(sergey): Use indexec lookup, once it's guaranteed to be kept
+ * around for the time while proxies are evaluating.
+ */
#if 0
- bPoseChannel *pchan_from = pose_pchan_get_indexed(
- object->proxy_from, pchan_index);
+ bPoseChannel *pchan_from = pose_pchan_get_indexed(
+ object->proxy_from, pchan_index);
#else
- bPoseChannel *pchan_from = BKE_pose_channel_find_name(
- object->proxy_from->pose, pchan->name);
+ bPoseChannel *pchan_from = BKE_pose_channel_find_name(object->proxy_from->pose, pchan->name);
#endif
- BLI_assert(pchan != NULL);
- BLI_assert(pchan_from != NULL);
- BKE_pose_copyesult_pchan_result(pchan, pchan_from);
- BKE_pchan_bbone_segments_cache_copy(pchan, pchan_from);
+ BLI_assert(pchan != NULL);
+ BLI_assert(pchan_from != NULL);
+ BKE_pose_copyesult_pchan_result(pchan, pchan_from);
+ BKE_pchan_bbone_segments_cache_copy(pchan, pchan_from);
}
diff --git a/source/blender/blenkernel/intern/autoexec.c b/source/blender/blenkernel/intern/autoexec.c
index 1444c2cccbc..1616c46d05b 100644
--- a/source/blender/blenkernel/intern/autoexec.c
+++ b/source/blender/blenkernel/intern/autoexec.c
@@ -34,7 +34,7 @@
# include "BLI_string.h"
#endif
-#include "BKE_autoexec.h" /* own include */
+#include "BKE_autoexec.h" /* own include */
/**
* \param path: The path to check against.
@@ -42,29 +42,29 @@
*/
bool BKE_autoexec_match(const char *path)
{
- bPathCompare *path_cmp;
+ bPathCompare *path_cmp;
#ifdef WIN32
- const int fnmatch_flags = FNM_CASEFOLD;
+ const int fnmatch_flags = FNM_CASEFOLD;
#else
- const int fnmatch_flags = 0;
+ const int fnmatch_flags = 0;
#endif
- BLI_assert((U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0);
+ 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->path[0] == '\0') {
- /* pass */
- }
- else if ((path_cmp->flag & USER_PATHCMP_GLOB)) {
- if (fnmatch(path_cmp->path, path, fnmatch_flags) == 0) {
- return true;
- }
- }
- else if (BLI_path_ncmp(path_cmp->path, path, strlen(path_cmp->path)) == 0) {
- return true;
- }
- }
+ for (path_cmp = U.autoexec_paths.first; path_cmp; path_cmp = path_cmp->next) {
+ 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;
+ }
+ }
+ else if (BLI_path_ncmp(path_cmp->path, path, strlen(path_cmp->path)) == 0) {
+ return true;
+ }
+ }
- return false;
+ return false;
}
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index 36e9c8f36dc..cf32abbb7b7 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -38,8 +38,8 @@
#include "IMB_moviecache.h"
#include "BKE_addon.h"
-#include "BKE_blender.h" /* own include */
-#include "BKE_blender_version.h" /* own include */
+#include "BKE_blender.h" /* own include */
+#include "BKE_blender_version.h" /* own include */
#include "BKE_blender_user_menu.h"
#include "BKE_blendfile.h"
#include "BKE_brush.h"
@@ -63,7 +63,6 @@
#include "BLF_api.h"
-
Global G;
UserDef U;
@@ -74,157 +73,165 @@ char versionstr[48] = "";
/* only to be called on exit blender */
void BKE_blender_free(void)
{
- /* samples are in a global list..., also sets G_MAIN->sound->sample NULL */
+ /* samples are in a global list..., also sets G_MAIN->sound->sample NULL */
- BKE_studiolight_free(); /* needs to run before main free as wm is still referenced for icons preview jobs */
- BKE_main_free(G_MAIN);
- G_MAIN = NULL;
+ BKE_studiolight_free(); /* needs to run before main free as wm is still referenced for icons preview jobs */
+ BKE_main_free(G_MAIN);
+ G_MAIN = NULL;
- if (G.log.file != NULL) {
- fclose(G.log.file);
- }
+ if (G.log.file != NULL) {
+ fclose(G.log.file);
+ }
- BKE_spacetypes_free(); /* after free main, it uses space callbacks */
+ BKE_spacetypes_free(); /* after free main, it uses space callbacks */
- IMB_exit();
- BKE_cachefiles_exit();
- BKE_images_exit();
- DEG_free_node_types();
+ IMB_exit();
+ BKE_cachefiles_exit();
+ BKE_images_exit();
+ DEG_free_node_types();
- BKE_brush_system_exit();
- RE_texture_rng_exit();
+ BKE_brush_system_exit();
+ RE_texture_rng_exit();
- BLI_callback_global_finalize();
+ BLI_callback_global_finalize();
- BKE_sequencer_cache_destruct();
- IMB_moviecache_destruct();
+ BKE_sequencer_cache_destruct();
+ IMB_moviecache_destruct();
- free_nodesystem();
+ free_nodesystem();
}
-void BKE_blender_version_string(char *version_str, size_t maxncpy, short version, short subversion, bool v_prefix, bool include_subversion)
+void BKE_blender_version_string(char *version_str,
+ size_t maxncpy,
+ short version,
+ short subversion,
+ bool v_prefix,
+ bool include_subversion)
{
- const char *prefix = v_prefix ? "v" : "";
-
- if (include_subversion && subversion > 0) {
- BLI_snprintf(version_str, maxncpy, "%s%d.%02d.%d", prefix, version / 100, version % 100, subversion);
- }
- else {
- BLI_snprintf(version_str, maxncpy, "%s%d.%02d", prefix, version / 100, version % 100);
- }
+ const char *prefix = v_prefix ? "v" : "";
+
+ if (include_subversion && subversion > 0) {
+ BLI_snprintf(
+ version_str, maxncpy, "%s%d.%02d.%d", prefix, version / 100, version % 100, subversion);
+ }
+ else {
+ BLI_snprintf(version_str, maxncpy, "%s%d.%02d", prefix, version / 100, version % 100);
+ }
}
void BKE_blender_globals_init(void)
{
- memset(&G, 0, sizeof(Global));
+ memset(&G, 0, sizeof(Global));
- U.savetime = 1;
+ U.savetime = 1;
- G_MAIN = BKE_main_new();
+ G_MAIN = BKE_main_new();
- strcpy(G.ima, "//");
+ strcpy(G.ima, "//");
- BKE_blender_version_string(versionstr, sizeof(versionstr), BLENDER_VERSION, BLENDER_SUBVERSION, true, true);
+ BKE_blender_version_string(
+ versionstr, sizeof(versionstr), BLENDER_VERSION, BLENDER_SUBVERSION, true, true);
#ifndef WITH_PYTHON_SECURITY /* default */
- G.f |= G_FLAG_SCRIPT_AUTOEXEC;
+ G.f |= G_FLAG_SCRIPT_AUTOEXEC;
#else
- G.f &= ~G_FLAG_SCRIPT_AUTOEXEC;
+ G.f &= ~G_FLAG_SCRIPT_AUTOEXEC;
#endif
- G.log.level = 1;
+ G.log.level = 1;
}
void BKE_blender_globals_clear(void)
{
- BKE_main_free(G_MAIN); /* free all lib data */
+ BKE_main_free(G_MAIN); /* free all lib data */
- G_MAIN = NULL;
+ G_MAIN = NULL;
}
/***/
static void keymap_item_free(wmKeyMapItem *kmi)
{
- if (kmi->properties) {
- IDP_FreeProperty(kmi->properties);
- MEM_freeN(kmi->properties);
- }
- if (kmi->ptr)
- MEM_freeN(kmi->ptr);
+ if (kmi->properties) {
+ IDP_FreeProperty(kmi->properties);
+ MEM_freeN(kmi->properties);
+ }
+ if (kmi->ptr)
+ MEM_freeN(kmi->ptr);
}
void BKE_blender_userdef_data_swap(UserDef *userdef_a, UserDef *userdef_b)
{
- SWAP(UserDef, *userdef_a, *userdef_b);
+ SWAP(UserDef, *userdef_a, *userdef_b);
}
void BKE_blender_userdef_data_set(UserDef *userdef)
{
- BKE_blender_userdef_data_swap(&U, userdef);
- BKE_blender_userdef_data_free(userdef, true);
+ BKE_blender_userdef_data_swap(&U, userdef);
+ BKE_blender_userdef_data_free(userdef, true);
}
void BKE_blender_userdef_data_set_and_free(UserDef *userdef)
{
- BKE_blender_userdef_data_set(userdef);
- MEM_freeN(userdef);
+ BKE_blender_userdef_data_set(userdef);
+ MEM_freeN(userdef);
}
static void userdef_free_keymaps(UserDef *userdef)
{
- for (wmKeyMap *km = userdef->user_keymaps.first, *km_next; km; km = km_next) {
- km_next = km->next;
- for (wmKeyMapDiffItem *kmdi = km->diff_items.first; kmdi; kmdi = kmdi->next) {
- if (kmdi->add_item) {
- keymap_item_free(kmdi->add_item);
- MEM_freeN(kmdi->add_item);
- }
- if (kmdi->remove_item) {
- keymap_item_free(kmdi->remove_item);
- MEM_freeN(kmdi->remove_item);
- }
- }
-
- for (wmKeyMapItem *kmi = km->items.first; kmi; kmi = kmi->next) {
- keymap_item_free(kmi);
- }
-
- BLI_freelistN(&km->diff_items);
- BLI_freelistN(&km->items);
-
- MEM_freeN(km);
- }
- BLI_listbase_clear(&userdef->user_keymaps);
+ for (wmKeyMap *km = userdef->user_keymaps.first, *km_next; km; km = km_next) {
+ km_next = km->next;
+ for (wmKeyMapDiffItem *kmdi = km->diff_items.first; kmdi; kmdi = kmdi->next) {
+ if (kmdi->add_item) {
+ keymap_item_free(kmdi->add_item);
+ MEM_freeN(kmdi->add_item);
+ }
+ if (kmdi->remove_item) {
+ keymap_item_free(kmdi->remove_item);
+ MEM_freeN(kmdi->remove_item);
+ }
+ }
+
+ for (wmKeyMapItem *kmi = km->items.first; kmi; kmi = kmi->next) {
+ keymap_item_free(kmi);
+ }
+
+ BLI_freelistN(&km->diff_items);
+ BLI_freelistN(&km->items);
+
+ MEM_freeN(km);
+ }
+ BLI_listbase_clear(&userdef->user_keymaps);
}
static void userdef_free_keyconfig_prefs(UserDef *userdef)
{
- for (wmKeyConfigPref *kpt = userdef->user_keyconfig_prefs.first, *kpt_next; kpt; kpt = kpt_next) {
- kpt_next = kpt->next;
- IDP_FreeProperty(kpt->prop);
- MEM_freeN(kpt->prop);
- MEM_freeN(kpt);
- }
- BLI_listbase_clear(&userdef->user_keyconfig_prefs);
+ for (wmKeyConfigPref *kpt = userdef->user_keyconfig_prefs.first, *kpt_next; kpt;
+ kpt = kpt_next) {
+ kpt_next = kpt->next;
+ IDP_FreeProperty(kpt->prop);
+ MEM_freeN(kpt->prop);
+ MEM_freeN(kpt);
+ }
+ BLI_listbase_clear(&userdef->user_keyconfig_prefs);
}
static void userdef_free_user_menus(UserDef *userdef)
{
- for (bUserMenu *um = userdef->user_menus.first, *um_next; um; um = um_next) {
- um_next = um->next;
- BKE_blender_user_menu_item_free_list(&um->items);
- MEM_freeN(um);
- }
+ for (bUserMenu *um = userdef->user_menus.first, *um_next; um; um = um_next) {
+ um_next = um->next;
+ BKE_blender_user_menu_item_free_list(&um->items);
+ MEM_freeN(um);
+ }
}
static void userdef_free_addons(UserDef *userdef)
{
- for (bAddon *addon = userdef->addons.first, *addon_next; addon; addon = addon_next) {
- addon_next = addon->next;
- BKE_addon_free(addon);
- }
- BLI_listbase_clear(&userdef->addons);
+ for (bAddon *addon = userdef->addons.first, *addon_next; addon; addon = addon_next) {
+ addon_next = addon->next;
+ BKE_addon_free(addon);
+ }
+ BLI_listbase_clear(&userdef->addons);
}
/**
@@ -234,27 +241,26 @@ static void userdef_free_addons(UserDef *userdef)
void BKE_blender_userdef_data_free(UserDef *userdef, bool clear_fonts)
{
#define U _invalid_access_ /* ensure no accidental global access */
-#ifdef U /* quiet warning */
+#ifdef U /* quiet warning */
#endif
- userdef_free_keymaps(userdef);
- userdef_free_keyconfig_prefs(userdef);
- userdef_free_user_menus(userdef);
- userdef_free_addons(userdef);
-
- if (clear_fonts) {
- for (uiFont *font = userdef->uifonts.first; font; font = font->next) {
- BLF_unload_id(font->blf_id);
- }
- BLF_default_set(-1);
- }
+ userdef_free_keymaps(userdef);
+ userdef_free_keyconfig_prefs(userdef);
+ userdef_free_user_menus(userdef);
+ userdef_free_addons(userdef);
- BLI_freelistN(&userdef->autoexec_paths);
+ if (clear_fonts) {
+ for (uiFont *font = userdef->uifonts.first; font; font = font->next) {
+ BLF_unload_id(font->blf_id);
+ }
+ BLF_default_set(-1);
+ }
- BLI_freelistN(&userdef->uistyles);
- BLI_freelistN(&userdef->uifonts);
- BLI_freelistN(&userdef->themes);
+ BLI_freelistN(&userdef->autoexec_paths);
+ BLI_freelistN(&userdef->uistyles);
+ BLI_freelistN(&userdef->uifonts);
+ BLI_freelistN(&userdef->themes);
#undef U
}
@@ -265,47 +271,51 @@ void BKE_blender_userdef_data_free(UserDef *userdef, bool clear_fonts)
*/
void BKE_blender_userdef_app_template_data_swap(UserDef *userdef_a, UserDef *userdef_b)
{
- /* TODO:
- * - various minor settings (add as needed).
- */
+ /* TODO:
+ * - various minor settings (add as needed).
+ */
#define DATA_SWAP(id) \
- { \
- UserDef userdef_tmp; \
- memcpy(&(userdef_tmp.id), &(userdef_a->id), sizeof(userdef_tmp.id)); \
- memcpy(&(userdef_a->id), &(userdef_b->id), sizeof(userdef_tmp.id)); \
- memcpy(&(userdef_b->id), &(userdef_tmp.id), sizeof(userdef_tmp.id)); \
- } ((void)0)
-
-#define LIST_SWAP(id) { \
- SWAP(ListBase, userdef_a->id, userdef_b->id); \
-} ((void)0)
-
-#define FLAG_SWAP(id, ty, flags) { \
- CHECK_TYPE(&(userdef_a->id), ty *); \
- const ty f = flags; \
- const ty a = userdef_a->id; \
- const ty b = userdef_b->id; \
- userdef_a->id = (userdef_a->id & ~f) | (b & f); \
- userdef_b->id = (userdef_b->id & ~f) | (a & f); \
-} ((void)0)
-
-
- LIST_SWAP(uistyles);
- LIST_SWAP(uifonts);
- LIST_SWAP(themes);
- LIST_SWAP(addons);
- LIST_SWAP(user_keymaps);
-
- DATA_SWAP(font_path_ui);
- DATA_SWAP(font_path_ui_mono);
- DATA_SWAP(keyconfigstr);
-
- DATA_SWAP(gizmo_flag);
- DATA_SWAP(app_flag);
-
- /* We could add others. */
- FLAG_SWAP(uiflag, int, USER_SAVE_PROMPT);
+ { \
+ UserDef userdef_tmp; \
+ memcpy(&(userdef_tmp.id), &(userdef_a->id), sizeof(userdef_tmp.id)); \
+ memcpy(&(userdef_a->id), &(userdef_b->id), sizeof(userdef_tmp.id)); \
+ memcpy(&(userdef_b->id), &(userdef_tmp.id), sizeof(userdef_tmp.id)); \
+ } \
+ ((void)0)
+
+#define LIST_SWAP(id) \
+ { \
+ SWAP(ListBase, userdef_a->id, userdef_b->id); \
+ } \
+ ((void)0)
+
+#define FLAG_SWAP(id, ty, flags) \
+ { \
+ CHECK_TYPE(&(userdef_a->id), ty *); \
+ const ty f = flags; \
+ const ty a = userdef_a->id; \
+ const ty b = userdef_b->id; \
+ userdef_a->id = (userdef_a->id & ~f) | (b & f); \
+ userdef_b->id = (userdef_b->id & ~f) | (a & f); \
+ } \
+ ((void)0)
+
+ LIST_SWAP(uistyles);
+ LIST_SWAP(uifonts);
+ LIST_SWAP(themes);
+ LIST_SWAP(addons);
+ LIST_SWAP(user_keymaps);
+
+ DATA_SWAP(font_path_ui);
+ DATA_SWAP(font_path_ui_mono);
+ DATA_SWAP(keyconfigstr);
+
+ DATA_SWAP(gizmo_flag);
+ DATA_SWAP(app_flag);
+
+ /* We could add others. */
+ FLAG_SWAP(uiflag, int, USER_SAVE_PROMPT);
#undef SWAP_TYPELESS
#undef DATA_SWAP
@@ -315,14 +325,14 @@ void BKE_blender_userdef_app_template_data_swap(UserDef *userdef_a, UserDef *use
void BKE_blender_userdef_app_template_data_set(UserDef *userdef)
{
- BKE_blender_userdef_app_template_data_swap(&U, userdef);
- BKE_blender_userdef_data_free(userdef, true);
+ BKE_blender_userdef_app_template_data_swap(&U, userdef);
+ BKE_blender_userdef_data_free(userdef, true);
}
void BKE_blender_userdef_app_template_data_set_and_free(UserDef *userdef)
{
- BKE_blender_userdef_app_template_data_set(userdef);
- MEM_freeN(userdef);
+ BKE_blender_userdef_app_template_data_set(userdef);
+ MEM_freeN(userdef);
}
/** \name Blender's AtExit
@@ -331,49 +341,49 @@ void BKE_blender_userdef_app_template_data_set_and_free(UserDef *userdef)
* \{ */
static struct AtExitData {
- struct AtExitData *next;
+ struct AtExitData *next;
- void (*func)(void *user_data);
- void *user_data;
+ void (*func)(void *user_data);
+ void *user_data;
} *g_atexit = NULL;
void BKE_blender_atexit_register(void (*func)(void *user_data), void *user_data)
{
- struct AtExitData *ae = malloc(sizeof(*ae));
- ae->next = g_atexit;
- ae->func = func;
- ae->user_data = user_data;
- g_atexit = ae;
+ struct AtExitData *ae = malloc(sizeof(*ae));
+ ae->next = g_atexit;
+ ae->func = func;
+ ae->user_data = user_data;
+ g_atexit = ae;
}
void BKE_blender_atexit_unregister(void (*func)(void *user_data), const void *user_data)
{
- struct AtExitData *ae = g_atexit;
- struct AtExitData **ae_p = &g_atexit;
-
- while (ae) {
- if ((ae->func == func) && (ae->user_data == user_data)) {
- *ae_p = ae->next;
- free(ae);
- return;
- }
- ae_p = &ae;
- ae = ae->next;
- }
+ struct AtExitData *ae = g_atexit;
+ struct AtExitData **ae_p = &g_atexit;
+
+ while (ae) {
+ if ((ae->func == func) && (ae->user_data == user_data)) {
+ *ae_p = ae->next;
+ free(ae);
+ return;
+ }
+ ae_p = &ae;
+ ae = ae->next;
+ }
}
void BKE_blender_atexit(void)
{
- struct AtExitData *ae = g_atexit, *ae_next;
- while (ae) {
- ae_next = ae->next;
+ struct AtExitData *ae = g_atexit, *ae_next;
+ while (ae) {
+ ae_next = ae->next;
- ae->func(ae->user_data);
+ ae->func(ae->user_data);
- free(ae);
- ae = ae_next;
- }
- g_atexit = NULL;
+ free(ae);
+ ae = ae_next;
+ }
+ g_atexit = NULL;
}
/** \} */
diff --git a/source/blender/blenkernel/intern/blender_copybuffer.c b/source/blender/blenkernel/intern/blender_copybuffer.c
index 2ac013df620..c801c1780c8 100644
--- a/source/blender/blenkernel/intern/blender_copybuffer.c
+++ b/source/blender/blenkernel/intern/blender_copybuffer.c
@@ -36,7 +36,7 @@
#include "IMB_imbuf.h"
#include "IMB_moviecache.h"
-#include "BKE_blender_copybuffer.h" /* own include */
+#include "BKE_blender_copybuffer.h" /* own include */
#include "BKE_blendfile.h"
#include "BKE_context.h"
#include "BKE_global.h"
@@ -53,19 +53,18 @@
#include "IMB_colormanagement.h"
-
/* -------------------------------------------------------------------- */
/** \name Copy/Paste `.blend`, partial saves.
* \{ */
void BKE_copybuffer_begin(Main *bmain_src)
{
- BKE_blendfile_write_partial_begin(bmain_src);
+ BKE_blendfile_write_partial_begin(bmain_src);
}
void BKE_copybuffer_tag_ID(ID *id)
{
- BKE_blendfile_write_partial_tag_ID(id, true);
+ BKE_blendfile_write_partial_tag_ID(id, true);
}
/**
@@ -73,99 +72,105 @@ void BKE_copybuffer_tag_ID(ID *id)
*/
bool BKE_copybuffer_save(Main *bmain_src, const char *filename, ReportList *reports)
{
- const int write_flags = G_FILE_RELATIVE_REMAP;
+ const int write_flags = G_FILE_RELATIVE_REMAP;
- bool retval = BKE_blendfile_write_partial(bmain_src, filename, write_flags, reports);
+ bool retval = BKE_blendfile_write_partial(bmain_src, filename, write_flags, reports);
- BKE_blendfile_write_partial_end(bmain_src);
+ BKE_blendfile_write_partial_end(bmain_src);
- return retval;
+ return retval;
}
-bool BKE_copybuffer_read(Main *bmain_dst, const char *libname, ReportList *reports, const unsigned int id_types_mask)
+bool BKE_copybuffer_read(Main *bmain_dst,
+ const char *libname,
+ ReportList *reports,
+ const unsigned int id_types_mask)
{
- BlendHandle *bh = BLO_blendhandle_from_file(libname, reports);
- if (bh == NULL) {
- /* Error reports will have been made by BLO_blendhandle_from_file(). */
- return false;
- }
- /* Here appending/linking starts. */
- Main *mainl = BLO_library_link_begin(bmain_dst, &bh, libname);
- BLO_library_link_copypaste(mainl, bh, id_types_mask);
- BLO_library_link_end(mainl, &bh, 0, NULL, NULL, NULL, NULL);
- /* Mark all library linked objects to be updated. */
- BKE_main_lib_objects_recalc_all(bmain_dst);
- IMB_colormanagement_check_file_config(bmain_dst);
- /* Append, rather than linking. */
- Library *lib = BLI_findstring(&bmain_dst->libraries, libname, offsetof(Library, filepath));
- BKE_library_make_local(bmain_dst, lib, NULL, true, false);
- /* Important we unset, otherwise these object wont
- * link into other scenes from this blend file.
- */
- BKE_main_id_tag_all(bmain_dst, LIB_TAG_PRE_EXISTING, false);
- BLO_blendhandle_close(bh);
- return true;
+ BlendHandle *bh = BLO_blendhandle_from_file(libname, reports);
+ if (bh == NULL) {
+ /* Error reports will have been made by BLO_blendhandle_from_file(). */
+ return false;
+ }
+ /* Here appending/linking starts. */
+ Main *mainl = BLO_library_link_begin(bmain_dst, &bh, libname);
+ BLO_library_link_copypaste(mainl, bh, id_types_mask);
+ BLO_library_link_end(mainl, &bh, 0, NULL, NULL, NULL, NULL);
+ /* Mark all library linked objects to be updated. */
+ BKE_main_lib_objects_recalc_all(bmain_dst);
+ IMB_colormanagement_check_file_config(bmain_dst);
+ /* Append, rather than linking. */
+ Library *lib = BLI_findstring(&bmain_dst->libraries, libname, offsetof(Library, filepath));
+ BKE_library_make_local(bmain_dst, lib, NULL, true, false);
+ /* Important we unset, otherwise these object wont
+ * link into other scenes from this blend file.
+ */
+ BKE_main_id_tag_all(bmain_dst, LIB_TAG_PRE_EXISTING, false);
+ BLO_blendhandle_close(bh);
+ return true;
}
/**
* \return Number of IDs directly pasted from the buffer (does not includes indirectly pulled out ones).
*/
-int BKE_copybuffer_paste(
- bContext *C, const char *libname, const short flag, ReportList *reports, const unsigned int id_types_mask)
+int BKE_copybuffer_paste(bContext *C,
+ const char *libname,
+ const short flag,
+ ReportList *reports,
+ const unsigned int id_types_mask)
{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- View3D *v3d = CTX_wm_view3d(C); /* may be NULL. */
- Main *mainl = NULL;
- Library *lib;
- BlendHandle *bh;
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C); /* may be NULL. */
+ Main *mainl = NULL;
+ Library *lib;
+ BlendHandle *bh;
- bh = BLO_blendhandle_from_file(libname, reports);
+ bh = BLO_blendhandle_from_file(libname, reports);
- if (bh == NULL) {
- /* error reports will have been made by BLO_blendhandle_from_file() */
- return 0;
- }
+ if (bh == NULL) {
+ /* error reports will have been made by BLO_blendhandle_from_file() */
+ return 0;
+ }
- BKE_view_layer_base_deselect_all(view_layer);
+ BKE_view_layer_base_deselect_all(view_layer);
- /* tag everything, all untagged data can be made local
- * its also generally useful to know what is new
- *
- * take extra care BKE_main_id_flag_all(bmain, LIB_TAG_PRE_EXISTING, false) is called after! */
- BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
+ /* tag everything, all untagged data can be made local
+ * its also generally useful to know what is new
+ *
+ * take extra care BKE_main_id_flag_all(bmain, LIB_TAG_PRE_EXISTING, false) is called after! */
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
- /* here appending/linking starts */
- mainl = BLO_library_link_begin(bmain, &bh, libname);
+ /* here appending/linking starts */
+ mainl = BLO_library_link_begin(bmain, &bh, libname);
- const int num_pasted = BLO_library_link_copypaste(mainl, bh, id_types_mask);
+ const int num_pasted = BLO_library_link_copypaste(mainl, bh, id_types_mask);
- BLO_library_link_end(mainl, &bh, flag, bmain, scene, view_layer, v3d);
+ BLO_library_link_end(mainl, &bh, flag, bmain, scene, view_layer, v3d);
- /* mark all library linked objects to be updated */
- BKE_main_lib_objects_recalc_all(bmain);
- IMB_colormanagement_check_file_config(bmain);
+ /* mark all library linked objects to be updated */
+ BKE_main_lib_objects_recalc_all(bmain);
+ IMB_colormanagement_check_file_config(bmain);
- /* append, rather than linking */
- lib = BLI_findstring(&bmain->libraries, libname, offsetof(Library, filepath));
- BKE_library_make_local(bmain, lib, NULL, true, false);
+ /* append, rather than linking */
+ lib = BLI_findstring(&bmain->libraries, libname, offsetof(Library, filepath));
+ BKE_library_make_local(bmain, lib, NULL, true, false);
- /* important we unset, otherwise these object wont
- * link into other scenes from this blend file */
- BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
+ /* important we unset, otherwise these object wont
+ * link into other scenes from this blend file */
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
- /* recreate dependency graph to include new objects */
- DEG_relations_tag_update(bmain);
+ /* recreate dependency graph to include new objects */
+ DEG_relations_tag_update(bmain);
- /* Tag update the scene to flush base collection settings, since the new object is added to a
- * new (active) collection, not its original collection, thus need recalculation. */
- DEG_id_tag_update(&scene->id, 0);
+ /* Tag update the scene to flush base collection settings, since the new object is added to a
+ * new (active) collection, not its original collection, thus need recalculation. */
+ DEG_id_tag_update(&scene->id, 0);
- BLO_blendhandle_close(bh);
- /* remove library... */
+ BLO_blendhandle_close(bh);
+ /* remove library... */
- return num_pasted;
+ return num_pasted;
}
/** \} */
diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c
index dd9be07be5d..6c077ac75ba 100644
--- a/source/blender/blenkernel/intern/blender_undo.c
+++ b/source/blender/blenkernel/intern/blender_undo.c
@@ -22,16 +22,16 @@
*/
#ifndef _WIN32
-# include <unistd.h> // for read close
+# include <unistd.h> // for read close
#else
-# include <io.h> // for open close read
+# include <io.h> // for open close read
#endif
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <string.h>
-#include <fcntl.h> /* for open */
+#include <fcntl.h> /* for open */
#include <errno.h>
#include "MEM_guardedalloc.h"
@@ -43,7 +43,7 @@
#include "BLI_utildefines.h"
#include "BKE_appdir.h"
-#include "BKE_blender_undo.h" /* own include */
+#include "BKE_blender_undo.h" /* own include */
#include "BKE_blendfile.h"
#include "BKE_context.h"
#include "BKE_global.h"
@@ -59,79 +59,77 @@
/** \name Global Undo
* \{ */
-#define UNDO_DISK 0
+#define UNDO_DISK 0
bool BKE_memfile_undo_decode(MemFileUndoData *mfu, bContext *C)
{
- Main *bmain = CTX_data_main(C);
- char mainstr[sizeof(bmain->name)];
- int success = 0, fileflags;
-
- BLI_strncpy(mainstr, BKE_main_blendfile_path(bmain), sizeof(mainstr)); /* temporal store */
-
- fileflags = G.fileflags;
- G.fileflags |= G_FILE_NO_UI;
-
- if (UNDO_DISK) {
- success = (BKE_blendfile_read(C, mfu->filename, NULL, 0) != BKE_BLENDFILE_READ_FAIL);
- }
- else {
- success = BKE_blendfile_read_from_memfile(
- C, &mfu->memfile,
- &(const struct BlendFileReadParams){0},
- NULL);
- }
-
- /* Restore, bmain has been re-allocated. */
- bmain = CTX_data_main(C);
- BLI_strncpy(bmain->name, mainstr, sizeof(bmain->name));
- G.fileflags = fileflags;
-
- if (success) {
- /* important not to update time here, else non keyed transforms are lost */
- DEG_on_visible_update(bmain, false);
- }
-
- return success;
+ Main *bmain = CTX_data_main(C);
+ char mainstr[sizeof(bmain->name)];
+ int success = 0, fileflags;
+
+ BLI_strncpy(mainstr, BKE_main_blendfile_path(bmain), sizeof(mainstr)); /* temporal store */
+
+ fileflags = G.fileflags;
+ G.fileflags |= G_FILE_NO_UI;
+
+ if (UNDO_DISK) {
+ success = (BKE_blendfile_read(C, mfu->filename, NULL, 0) != BKE_BLENDFILE_READ_FAIL);
+ }
+ else {
+ success = BKE_blendfile_read_from_memfile(
+ C, &mfu->memfile, &(const struct BlendFileReadParams){0}, NULL);
+ }
+
+ /* Restore, bmain has been re-allocated. */
+ bmain = CTX_data_main(C);
+ BLI_strncpy(bmain->name, mainstr, sizeof(bmain->name));
+ G.fileflags = fileflags;
+
+ if (success) {
+ /* important not to update time here, else non keyed transforms are lost */
+ DEG_on_visible_update(bmain, false);
+ }
+
+ return success;
}
MemFileUndoData *BKE_memfile_undo_encode(Main *bmain, MemFileUndoData *mfu_prev)
{
- MemFileUndoData *mfu = MEM_callocN(sizeof(MemFileUndoData), __func__);
+ MemFileUndoData *mfu = MEM_callocN(sizeof(MemFileUndoData), __func__);
- /* disk save version */
- if (UNDO_DISK) {
- static int counter = 0;
- char filename[FILE_MAX];
- char numstr[32];
- int fileflags = G.fileflags & ~(G_FILE_HISTORY); /* don't do file history on undo */
+ /* disk save version */
+ if (UNDO_DISK) {
+ static int counter = 0;
+ char filename[FILE_MAX];
+ char numstr[32];
+ int fileflags = G.fileflags & ~(G_FILE_HISTORY); /* don't do file history on undo */
- /* Calculate current filename. */
- counter++;
- counter = counter % U.undosteps;
+ /* Calculate current filename. */
+ counter++;
+ counter = counter % U.undosteps;
- BLI_snprintf(numstr, sizeof(numstr), "%d.blend", counter);
- BLI_make_file_string("/", filename, BKE_tempdir_session(), numstr);
+ BLI_snprintf(numstr, sizeof(numstr), "%d.blend", counter);
+ BLI_make_file_string("/", filename, BKE_tempdir_session(), numstr);
- /* success = */ /* UNUSED */ BLO_write_file(bmain, filename, fileflags, NULL, NULL);
+ /* success = */ /* UNUSED */ BLO_write_file(bmain, filename, fileflags, NULL, NULL);
- BLI_strncpy(mfu->filename, filename, sizeof(mfu->filename));
- }
- else {
- MemFile *prevfile = (mfu_prev) ? &(mfu_prev->memfile) : NULL;
- /* success = */ /* UNUSED */ BLO_write_file_mem(bmain, prevfile, &mfu->memfile, G.fileflags);
- mfu->undo_size = mfu->memfile.size;
- }
+ BLI_strncpy(mfu->filename, filename, sizeof(mfu->filename));
+ }
+ else {
+ MemFile *prevfile = (mfu_prev) ? &(mfu_prev->memfile) : NULL;
+ /* success = */ /* UNUSED */ BLO_write_file_mem(bmain, prevfile, &mfu->memfile, G.fileflags);
+ mfu->undo_size = mfu->memfile.size;
+ }
- bmain->is_memfile_undo_written = true;
+ bmain->is_memfile_undo_written = true;
- return mfu;
+ return mfu;
}
void BKE_memfile_undo_free(MemFileUndoData *mfu)
{
- BLO_memfile_free(&mfu->memfile);
- MEM_freeN(mfu);
+ BLO_memfile_free(&mfu->memfile);
+ MEM_freeN(mfu);
}
/** \} */
diff --git a/source/blender/blenkernel/intern/blender_user_menu.c b/source/blender/blenkernel/intern/blender_user_menu.c
index 4db7bea0d73..911f3fdc7b2 100644
--- a/source/blender/blenkernel/intern/blender_user_menu.c
+++ b/source/blender/blenkernel/intern/blender_user_menu.c
@@ -36,30 +36,26 @@
/** \name Menu Type
* \{ */
-bUserMenu *BKE_blender_user_menu_find(
- ListBase *lb, char space_type, const char *context)
+bUserMenu *BKE_blender_user_menu_find(ListBase *lb, char space_type, const char *context)
{
- for (bUserMenu *um = lb->first; um; um = um->next) {
- if ((space_type == um->space_type) &&
- (STREQ(context, um->context)))
- {
- return um;
- }
- }
- return NULL;
+ for (bUserMenu *um = lb->first; um; um = um->next) {
+ if ((space_type == um->space_type) && (STREQ(context, um->context))) {
+ return um;
+ }
+ }
+ return NULL;
}
-bUserMenu *BKE_blender_user_menu_ensure(
- ListBase *lb, char space_type, const char *context)
+bUserMenu *BKE_blender_user_menu_ensure(ListBase *lb, char space_type, const char *context)
{
- bUserMenu *um = BKE_blender_user_menu_find(lb, space_type, context);
- if (um == NULL) {
- um = MEM_callocN(sizeof(bUserMenu), __func__);
- um->space_type = space_type;
- STRNCPY(um->context, context);
- BLI_addhead(lb, um);
- }
- return um;
+ bUserMenu *um = BKE_blender_user_menu_find(lb, space_type, context);
+ if (um == NULL) {
+ um = MEM_callocN(sizeof(bUserMenu), __func__);
+ um->space_type = space_type;
+ STRNCPY(um->context, context);
+ BLI_addhead(lb, um);
+ }
+ return um;
}
/** \} */
@@ -70,48 +66,48 @@ bUserMenu *BKE_blender_user_menu_ensure(
bUserMenuItem *BKE_blender_user_menu_item_add(ListBase *lb, int type)
{
- uint size;
-
- if (type == USER_MENU_TYPE_SEP) {
- size = sizeof(bUserMenuItem);
- }
- else if (type == USER_MENU_TYPE_OPERATOR) {
- size = sizeof(bUserMenuItem_Op);
- }
- else if (type == USER_MENU_TYPE_MENU) {
- size = sizeof(bUserMenuItem_Menu);
- }
- else if (type == USER_MENU_TYPE_PROP) {
- size = sizeof(bUserMenuItem_Prop);
- }
- else {
- size = sizeof(bUserMenuItem);
- BLI_assert(0);
- }
-
- bUserMenuItem *umi = MEM_callocN(size, __func__);
- umi->type = type;
- BLI_addtail(lb, umi);
- return umi;
+ uint size;
+
+ if (type == USER_MENU_TYPE_SEP) {
+ size = sizeof(bUserMenuItem);
+ }
+ else if (type == USER_MENU_TYPE_OPERATOR) {
+ size = sizeof(bUserMenuItem_Op);
+ }
+ else if (type == USER_MENU_TYPE_MENU) {
+ size = sizeof(bUserMenuItem_Menu);
+ }
+ else if (type == USER_MENU_TYPE_PROP) {
+ size = sizeof(bUserMenuItem_Prop);
+ }
+ else {
+ size = sizeof(bUserMenuItem);
+ BLI_assert(0);
+ }
+
+ bUserMenuItem *umi = MEM_callocN(size, __func__);
+ umi->type = type;
+ BLI_addtail(lb, umi);
+ return umi;
}
void BKE_blender_user_menu_item_free(bUserMenuItem *umi)
{
- if (umi->type == USER_MENU_TYPE_OPERATOR) {
- bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)umi;
- if (umi_op->prop) {
- IDP_FreeProperty(umi_op->prop);
- MEM_freeN(umi_op->prop);
- }
- }
- MEM_freeN(umi);
+ if (umi->type == USER_MENU_TYPE_OPERATOR) {
+ bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)umi;
+ if (umi_op->prop) {
+ IDP_FreeProperty(umi_op->prop);
+ MEM_freeN(umi_op->prop);
+ }
+ }
+ MEM_freeN(umi);
}
void BKE_blender_user_menu_item_free_list(ListBase *lb)
{
- for (bUserMenuItem *umi = lb->first, *umi_next; umi; umi = umi_next) {
- umi_next = umi->next;
- BKE_blender_user_menu_item_free(umi);
- }
- BLI_listbase_clear(lb);
+ for (bUserMenuItem *umi = lb->first, *umi_next; umi; umi = umi_next) {
+ umi_next = umi->next;
+ BKE_blender_user_menu_item_free(umi);
+ }
+ BLI_listbase_clear(lb);
}
diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c
index cd17911d65d..723c8bb48bf 100644
--- a/source/blender/blenkernel/intern/blendfile.c
+++ b/source/blender/blenkernel/intern/blendfile.c
@@ -70,32 +70,32 @@
static bool clean_paths_visit_cb(void *UNUSED(userdata), char *path_dst, const char *path_src)
{
- strcpy(path_dst, path_src);
- BLI_path_native_slash(path_dst);
- return !STREQ(path_dst, path_src);
+ strcpy(path_dst, path_src);
+ BLI_path_native_slash(path_dst);
+ return !STREQ(path_dst, path_src);
}
/* make sure path names are correct for OS */
static void clean_paths(Main *main)
{
- Scene *scene;
+ Scene *scene;
- BKE_bpath_traverse_main(main, clean_paths_visit_cb, BKE_BPATH_TRAVERSE_SKIP_MULTIFILE, NULL);
+ BKE_bpath_traverse_main(main, clean_paths_visit_cb, BKE_BPATH_TRAVERSE_SKIP_MULTIFILE, NULL);
- for (scene = main->scenes.first; scene; scene = scene->id.next) {
- BLI_path_native_slash(scene->r.pic);
- }
+ for (scene = main->scenes.first; scene; scene = scene->id.next) {
+ BLI_path_native_slash(scene->r.pic);
+ }
}
static bool wm_scene_is_visible(wmWindowManager *wm, Scene *scene)
{
- wmWindow *win;
- for (win = wm->windows.first; win; win = win->next) {
- if (win->scene == scene) {
- return true;
- }
- }
- return false;
+ wmWindow *win;
+ for (win = wm->windows.first; win; win = win->next) {
+ if (win->scene == scene) {
+ return true;
+ }
+ }
+ return false;
}
/**
@@ -107,350 +107,351 @@ static bool wm_scene_is_visible(wmWindowManager *wm, Scene *scene)
* \param bfd: Blend file data, freed by this function on exit.
* \param filepath: File path or identifier.
*/
-static void setup_app_data(
- bContext *C, BlendFileData *bfd,
- const char *filepath,
- const bool is_startup,
- ReportList *reports)
+static void setup_app_data(bContext *C,
+ BlendFileData *bfd,
+ const char *filepath,
+ const bool is_startup,
+ ReportList *reports)
{
- Main *bmain = G_MAIN;
- Scene *curscene = NULL;
- const bool recover = (G.fileflags & G_FILE_RECOVER) != 0;
- enum {
- LOAD_UI = 1,
- LOAD_UI_OFF,
- LOAD_UNDO,
- } mode;
-
- /* may happen with library files - UNDO file should never have NULL cursccene... */
- if (ELEM(NULL, bfd->curscreen, bfd->curscene)) {
- BKE_report(reports, RPT_WARNING, "Library file, loading empty scene");
- mode = LOAD_UI_OFF;
- }
- else if (BLI_listbase_is_empty(&bfd->main->screens)) {
- mode = LOAD_UNDO;
- }
- else if ((G.fileflags & G_FILE_NO_UI) && (is_startup == false)) {
- mode = LOAD_UI_OFF;
- }
- else {
- mode = LOAD_UI;
- }
-
- /* Free all render results, without this stale data gets displayed after loading files */
- if (mode != LOAD_UNDO) {
- RE_FreeAllRenderResults();
- }
-
- /* Only make filepaths compatible when loading for real (not undo) */
- if (mode != LOAD_UNDO) {
- clean_paths(bfd->main);
- }
-
- /* XXX here the complex windowmanager matching */
-
- /* no load screens? */
- if (mode != LOAD_UI) {
- /* Logic for 'track_undo_scene' is to keep using the scene which the active screen has,
- * as long as the scene associated with the undo operation is visible in one of the open windows.
- *
- * - 'curscreen->scene' - scene the user is currently looking at.
- * - 'bfd->curscene' - scene undo-step was created in.
- *
- * This means users can have 2+ windows open and undo in both without screens switching.
- * But if they close one of the screens,
- * undo will ensure that the scene being operated on will be activated
- * (otherwise we'd be undoing on an off-screen scene which isn't acceptable).
- * see: T43424
- */
- wmWindow *win;
- bScreen *curscreen = NULL;
- ViewLayer *cur_view_layer;
- bool track_undo_scene;
-
- /* comes from readfile.c */
- SWAP(ListBase, bmain->wm, bfd->main->wm);
- SWAP(ListBase, bmain->workspaces, bfd->main->workspaces);
- SWAP(ListBase, bmain->screens, bfd->main->screens);
-
- /* we re-use current window and screen */
- win = CTX_wm_window(C);
- curscreen = CTX_wm_screen(C);
- /* but use Scene pointer from new file */
- curscene = bfd->curscene;
- cur_view_layer = bfd->cur_view_layer;
-
- track_undo_scene = (mode == LOAD_UNDO && curscreen && curscene && bfd->main->wm.first);
-
- if (curscene == NULL) {
- curscene = bfd->main->scenes.first;
- }
- /* empty file, we add a scene to make Blender work */
- if (curscene == NULL) {
- curscene = BKE_scene_add(bfd->main, "Empty");
- }
- if (cur_view_layer == NULL) {
- /* fallback to scene layer */
- cur_view_layer = BKE_view_layer_default_view(curscene);
- }
-
- if (track_undo_scene) {
- /* keep the old (free'd) scene, let 'blo_lib_link_screen_restore'
- * replace it with 'curscene' if its needed */
- }
- /* and we enforce curscene to be in current screen */
- else if (win) { /* can run in bgmode */
- win->scene = curscene;
- }
-
- /* BKE_blender_globals_clear will free G_MAIN, here we can still restore pointers */
- blo_lib_link_restore(bmain, bfd->main, CTX_wm_manager(C), curscene, cur_view_layer);
- if (win) {
- curscene = win->scene;
- }
-
- if (track_undo_scene) {
- wmWindowManager *wm = bfd->main->wm.first;
- if (wm_scene_is_visible(wm, bfd->curscene) == false) {
- curscene = bfd->curscene;
- win->scene = curscene;
- BKE_screen_view3d_scene_sync(curscreen, curscene);
- }
- }
-
- /* We need to tag this here because events may be handled immediately after.
- * only the current screen is important because we wont have to handle
- * events from multiple screens at once.*/
- if (curscreen) {
- BKE_screen_gizmo_tag_refresh(curscreen);
- }
- }
-
- /* free G_MAIN Main database */
-// CTX_wm_manager_set(C, NULL);
- BKE_blender_globals_clear();
-
- /* clear old property update cache, in case some old references are left dangling */
- RNA_property_update_cache_free();
-
- bmain = G_MAIN = bfd->main;
-
- CTX_data_main_set(C, bmain);
-
- if (bfd->user) {
-
- /* only here free userdef themes... */
- BKE_blender_userdef_data_set_and_free(bfd->user);
- bfd->user = NULL;
-
- /* Security issue: any blend file could include a USER block.
- *
- * Currently we load prefs from BLENDER_STARTUP_FILE and later on load BLENDER_USERPREF_FILE,
- * to load the preferences defined in the users home dir.
- *
- * This means we will never accidentally (or maliciously)
- * enable scripts auto-execution by loading a '.blend' file.
- */
- U.flag |= USER_SCRIPT_AUTOEXEC_DISABLE;
- }
-
- /* case G_FILE_NO_UI or no screens in file */
- if (mode != LOAD_UI) {
- /* leave entire context further unaltered? */
- CTX_data_scene_set(C, curscene);
- }
- else {
- CTX_wm_manager_set(C, bmain->wm.first);
- CTX_wm_screen_set(C, bfd->curscreen);
- CTX_data_scene_set(C, bfd->curscene);
- CTX_wm_area_set(C, NULL);
- CTX_wm_region_set(C, NULL);
- CTX_wm_menu_set(C, NULL);
- curscene = bfd->curscene;
- }
-
- /* Keep state from preferences. */
- const int fileflags_keep = G_FILE_FLAG_ALL_RUNTIME;
- G.fileflags = (G.fileflags & fileflags_keep) | (bfd->fileflags & ~fileflags_keep);
-
- /* this can happen when active scene was lib-linked, and doesn't exist anymore */
- if (CTX_data_scene(C) == NULL) {
- wmWindow *win = CTX_wm_window(C);
-
- /* in case we don't even have a local scene, add one */
- if (!bmain->scenes.first)
- BKE_scene_add(bmain, "Empty");
-
- CTX_data_scene_set(C, bmain->scenes.first);
- win->scene = CTX_data_scene(C);
- curscene = CTX_data_scene(C);
- }
-
- BLI_assert(curscene == CTX_data_scene(C));
-
-
- /* special cases, override loaded flags: */
- if (G.f != bfd->globalf) {
- const int flags_keep = G_FLAG_ALL_RUNTIME;
- bfd->globalf &= G_FLAG_ALL_READFILE;
- bfd->globalf = (bfd->globalf & ~flags_keep) | (G.f & flags_keep);
- }
-
-
- G.f = bfd->globalf;
+ Main *bmain = G_MAIN;
+ Scene *curscene = NULL;
+ const bool recover = (G.fileflags & G_FILE_RECOVER) != 0;
+ enum {
+ LOAD_UI = 1,
+ LOAD_UI_OFF,
+ LOAD_UNDO,
+ } mode;
+
+ /* may happen with library files - UNDO file should never have NULL cursccene... */
+ if (ELEM(NULL, bfd->curscreen, bfd->curscene)) {
+ BKE_report(reports, RPT_WARNING, "Library file, loading empty scene");
+ mode = LOAD_UI_OFF;
+ }
+ else if (BLI_listbase_is_empty(&bfd->main->screens)) {
+ mode = LOAD_UNDO;
+ }
+ else if ((G.fileflags & G_FILE_NO_UI) && (is_startup == false)) {
+ mode = LOAD_UI_OFF;
+ }
+ else {
+ mode = LOAD_UI;
+ }
+
+ /* Free all render results, without this stale data gets displayed after loading files */
+ if (mode != LOAD_UNDO) {
+ RE_FreeAllRenderResults();
+ }
+
+ /* Only make filepaths compatible when loading for real (not undo) */
+ if (mode != LOAD_UNDO) {
+ clean_paths(bfd->main);
+ }
+
+ /* XXX here the complex windowmanager matching */
+
+ /* no load screens? */
+ if (mode != LOAD_UI) {
+ /* Logic for 'track_undo_scene' is to keep using the scene which the active screen has,
+ * as long as the scene associated with the undo operation is visible in one of the open windows.
+ *
+ * - 'curscreen->scene' - scene the user is currently looking at.
+ * - 'bfd->curscene' - scene undo-step was created in.
+ *
+ * This means users can have 2+ windows open and undo in both without screens switching.
+ * But if they close one of the screens,
+ * undo will ensure that the scene being operated on will be activated
+ * (otherwise we'd be undoing on an off-screen scene which isn't acceptable).
+ * see: T43424
+ */
+ wmWindow *win;
+ bScreen *curscreen = NULL;
+ ViewLayer *cur_view_layer;
+ bool track_undo_scene;
+
+ /* comes from readfile.c */
+ SWAP(ListBase, bmain->wm, bfd->main->wm);
+ SWAP(ListBase, bmain->workspaces, bfd->main->workspaces);
+ SWAP(ListBase, bmain->screens, bfd->main->screens);
+
+ /* we re-use current window and screen */
+ win = CTX_wm_window(C);
+ curscreen = CTX_wm_screen(C);
+ /* but use Scene pointer from new file */
+ curscene = bfd->curscene;
+ cur_view_layer = bfd->cur_view_layer;
+
+ track_undo_scene = (mode == LOAD_UNDO && curscreen && curscene && bfd->main->wm.first);
+
+ if (curscene == NULL) {
+ curscene = bfd->main->scenes.first;
+ }
+ /* empty file, we add a scene to make Blender work */
+ if (curscene == NULL) {
+ curscene = BKE_scene_add(bfd->main, "Empty");
+ }
+ if (cur_view_layer == NULL) {
+ /* fallback to scene layer */
+ cur_view_layer = BKE_view_layer_default_view(curscene);
+ }
+
+ if (track_undo_scene) {
+ /* keep the old (free'd) scene, let 'blo_lib_link_screen_restore'
+ * replace it with 'curscene' if its needed */
+ }
+ /* and we enforce curscene to be in current screen */
+ else if (win) { /* can run in bgmode */
+ win->scene = curscene;
+ }
+
+ /* BKE_blender_globals_clear will free G_MAIN, here we can still restore pointers */
+ blo_lib_link_restore(bmain, bfd->main, CTX_wm_manager(C), curscene, cur_view_layer);
+ if (win) {
+ curscene = win->scene;
+ }
+
+ if (track_undo_scene) {
+ wmWindowManager *wm = bfd->main->wm.first;
+ if (wm_scene_is_visible(wm, bfd->curscene) == false) {
+ curscene = bfd->curscene;
+ win->scene = curscene;
+ BKE_screen_view3d_scene_sync(curscreen, curscene);
+ }
+ }
+
+ /* We need to tag this here because events may be handled immediately after.
+ * only the current screen is important because we wont have to handle
+ * events from multiple screens at once.*/
+ if (curscreen) {
+ BKE_screen_gizmo_tag_refresh(curscreen);
+ }
+ }
+
+ /* free G_MAIN Main database */
+ // CTX_wm_manager_set(C, NULL);
+ BKE_blender_globals_clear();
+
+ /* clear old property update cache, in case some old references are left dangling */
+ RNA_property_update_cache_free();
+
+ bmain = G_MAIN = bfd->main;
+
+ CTX_data_main_set(C, bmain);
+
+ if (bfd->user) {
+
+ /* only here free userdef themes... */
+ BKE_blender_userdef_data_set_and_free(bfd->user);
+ bfd->user = NULL;
+
+ /* Security issue: any blend file could include a USER block.
+ *
+ * Currently we load prefs from BLENDER_STARTUP_FILE and later on load BLENDER_USERPREF_FILE,
+ * to load the preferences defined in the users home dir.
+ *
+ * This means we will never accidentally (or maliciously)
+ * enable scripts auto-execution by loading a '.blend' file.
+ */
+ U.flag |= USER_SCRIPT_AUTOEXEC_DISABLE;
+ }
+
+ /* case G_FILE_NO_UI or no screens in file */
+ if (mode != LOAD_UI) {
+ /* leave entire context further unaltered? */
+ CTX_data_scene_set(C, curscene);
+ }
+ else {
+ CTX_wm_manager_set(C, bmain->wm.first);
+ CTX_wm_screen_set(C, bfd->curscreen);
+ CTX_data_scene_set(C, bfd->curscene);
+ CTX_wm_area_set(C, NULL);
+ CTX_wm_region_set(C, NULL);
+ CTX_wm_menu_set(C, NULL);
+ curscene = bfd->curscene;
+ }
+
+ /* Keep state from preferences. */
+ const int fileflags_keep = G_FILE_FLAG_ALL_RUNTIME;
+ G.fileflags = (G.fileflags & fileflags_keep) | (bfd->fileflags & ~fileflags_keep);
+
+ /* this can happen when active scene was lib-linked, and doesn't exist anymore */
+ if (CTX_data_scene(C) == NULL) {
+ wmWindow *win = CTX_wm_window(C);
+
+ /* in case we don't even have a local scene, add one */
+ if (!bmain->scenes.first)
+ BKE_scene_add(bmain, "Empty");
+
+ CTX_data_scene_set(C, bmain->scenes.first);
+ win->scene = CTX_data_scene(C);
+ curscene = CTX_data_scene(C);
+ }
+
+ BLI_assert(curscene == CTX_data_scene(C));
+
+ /* special cases, override loaded flags: */
+ if (G.f != bfd->globalf) {
+ const int flags_keep = G_FLAG_ALL_RUNTIME;
+ bfd->globalf &= G_FLAG_ALL_READFILE;
+ bfd->globalf = (bfd->globalf & ~flags_keep) | (G.f & flags_keep);
+ }
+
+ G.f = bfd->globalf;
#ifdef WITH_PYTHON
- /* let python know about new main */
- BPY_context_update(C);
+ /* let python know about new main */
+ BPY_context_update(C);
#endif
- /* FIXME: this version patching should really be part of the file-reading code,
- * but we still get too many unrelated data-corruption crashes otherwise... */
- if (bmain->versionfile < 250)
- do_versions_ipos_to_animato(bmain);
-
- bmain->recovered = 0;
-
- /* startup.blend or recovered startup */
- if (is_startup) {
- bmain->name[0] = '\0';
- }
- else if (recover && G.relbase_valid) {
- /* in case of autosave or quit.blend, use original filename instead
- * use relbase_valid to make sure the file is saved, else we get <memory2> in the filename */
- filepath = bfd->filename;
- bmain->recovered = 1;
-
- /* these are the same at times, should never copy to the same location */
- if (bmain->name != filepath)
- BLI_strncpy(bmain->name, filepath, FILE_MAX);
- }
-
- /* baseflags, groups, make depsgraph, etc */
- /* first handle case if other windows have different scenes visible */
- if (mode == LOAD_UI) {
- wmWindowManager *wm = bmain->wm.first;
-
- if (wm) {
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
- if (win->scene && win->scene != curscene) {
- BKE_scene_set_background(bmain, win->scene);
- }
- }
- }
- }
-
- /* Setting scene might require having a dependency graph, with copy on write
- * we need to make sure we ensure scene has correct color management before
- * constructing dependency graph.
- */
- if (mode != LOAD_UNDO) {
- IMB_colormanagement_check_file_config(bmain);
- }
-
- BKE_scene_set_background(bmain, curscene);
-
- if (mode != LOAD_UNDO) {
- /* TODO(sergey): Can this be also move above? */
- RE_FreeAllPersistentData();
- }
-
- MEM_freeN(bfd);
-
+ /* FIXME: this version patching should really be part of the file-reading code,
+ * but we still get too many unrelated data-corruption crashes otherwise... */
+ if (bmain->versionfile < 250)
+ do_versions_ipos_to_animato(bmain);
+
+ bmain->recovered = 0;
+
+ /* startup.blend or recovered startup */
+ if (is_startup) {
+ bmain->name[0] = '\0';
+ }
+ else if (recover && G.relbase_valid) {
+ /* in case of autosave or quit.blend, use original filename instead
+ * use relbase_valid to make sure the file is saved, else we get <memory2> in the filename */
+ filepath = bfd->filename;
+ bmain->recovered = 1;
+
+ /* these are the same at times, should never copy to the same location */
+ if (bmain->name != filepath)
+ BLI_strncpy(bmain->name, filepath, FILE_MAX);
+ }
+
+ /* baseflags, groups, make depsgraph, etc */
+ /* first handle case if other windows have different scenes visible */
+ if (mode == LOAD_UI) {
+ wmWindowManager *wm = bmain->wm.first;
+
+ if (wm) {
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ if (win->scene && win->scene != curscene) {
+ BKE_scene_set_background(bmain, win->scene);
+ }
+ }
+ }
+ }
+
+ /* Setting scene might require having a dependency graph, with copy on write
+ * we need to make sure we ensure scene has correct color management before
+ * constructing dependency graph.
+ */
+ if (mode != LOAD_UNDO) {
+ IMB_colormanagement_check_file_config(bmain);
+ }
+
+ BKE_scene_set_background(bmain, curscene);
+
+ if (mode != LOAD_UNDO) {
+ /* TODO(sergey): Can this be also move above? */
+ RE_FreeAllPersistentData();
+ }
+
+ MEM_freeN(bfd);
}
static int handle_subversion_warning(Main *main, ReportList *reports)
{
- if (main->minversionfile > BLENDER_VERSION ||
- (main->minversionfile == BLENDER_VERSION &&
- main->minsubversionfile > BLENDER_SUBVERSION))
- {
- BKE_reportf(reports, RPT_ERROR, "File written by newer Blender binary (%d.%d), expect loss of data!",
- main->minversionfile, main->minsubversionfile);
- }
-
- return 1;
+ if (main->minversionfile > BLENDER_VERSION ||
+ (main->minversionfile == BLENDER_VERSION && main->minsubversionfile > BLENDER_SUBVERSION)) {
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "File written by newer Blender binary (%d.%d), expect loss of data!",
+ main->minversionfile,
+ main->minsubversionfile);
+ }
+
+ return 1;
}
-int BKE_blendfile_read(
- bContext *C, const char *filepath,
- const struct BlendFileReadParams *params,
- ReportList *reports)
+int BKE_blendfile_read(bContext *C,
+ const char *filepath,
+ const struct BlendFileReadParams *params,
+ ReportList *reports)
{
- BlendFileData *bfd;
- int retval = BKE_BLENDFILE_READ_OK;
-
- /* don't print user-pref loading */
- if (strstr(filepath, BLENDER_STARTUP_FILE) == NULL) {
- printf("Read blend: %s\n", filepath);
- }
-
- bfd = BLO_read_from_file(filepath, params->skip_flags, reports);
- if (bfd) {
- if (bfd->user) {
- retval = BKE_BLENDFILE_READ_OK_USERPREFS;
- }
-
- if (0 == handle_subversion_warning(bfd->main, reports)) {
- BKE_main_free(bfd->main);
- MEM_freeN(bfd);
- bfd = NULL;
- retval = BKE_BLENDFILE_READ_FAIL;
- }
- else {
- setup_app_data(C, bfd, filepath, params->is_startup, reports);
- }
- }
- else
- BKE_reports_prependf(reports, "Loading '%s' failed: ", filepath);
-
- return (bfd ? retval : BKE_BLENDFILE_READ_FAIL);
+ BlendFileData *bfd;
+ int retval = BKE_BLENDFILE_READ_OK;
+
+ /* don't print user-pref loading */
+ if (strstr(filepath, BLENDER_STARTUP_FILE) == NULL) {
+ printf("Read blend: %s\n", filepath);
+ }
+
+ bfd = BLO_read_from_file(filepath, params->skip_flags, reports);
+ if (bfd) {
+ if (bfd->user) {
+ retval = BKE_BLENDFILE_READ_OK_USERPREFS;
+ }
+
+ if (0 == handle_subversion_warning(bfd->main, reports)) {
+ BKE_main_free(bfd->main);
+ MEM_freeN(bfd);
+ bfd = NULL;
+ retval = BKE_BLENDFILE_READ_FAIL;
+ }
+ else {
+ setup_app_data(C, bfd, filepath, params->is_startup, reports);
+ }
+ }
+ else
+ BKE_reports_prependf(reports, "Loading '%s' failed: ", filepath);
+
+ return (bfd ? retval : BKE_BLENDFILE_READ_FAIL);
}
-bool BKE_blendfile_read_from_memory(
- bContext *C, const void *filebuf, int filelength, bool update_defaults,
- const struct BlendFileReadParams *params,
- ReportList *reports)
+bool BKE_blendfile_read_from_memory(bContext *C,
+ const void *filebuf,
+ int filelength,
+ bool update_defaults,
+ const struct BlendFileReadParams *params,
+ ReportList *reports)
{
- BlendFileData *bfd;
-
- bfd = BLO_read_from_memory(filebuf, filelength, params->skip_flags, reports);
- if (bfd) {
- if (update_defaults)
- BLO_update_defaults_startup_blend(bfd->main, NULL);
- setup_app_data(C, bfd, "<memory2>", params->is_startup, reports);
- }
- else {
- BKE_reports_prepend(reports, "Loading failed: ");
- }
-
- return (bfd != NULL);
+ BlendFileData *bfd;
+
+ bfd = BLO_read_from_memory(filebuf, filelength, params->skip_flags, reports);
+ if (bfd) {
+ if (update_defaults)
+ BLO_update_defaults_startup_blend(bfd->main, NULL);
+ setup_app_data(C, bfd, "<memory2>", params->is_startup, reports);
+ }
+ else {
+ BKE_reports_prepend(reports, "Loading failed: ");
+ }
+
+ return (bfd != NULL);
}
/* memfile is the undo buffer */
-bool BKE_blendfile_read_from_memfile(
- bContext *C, struct MemFile *memfile,
- const struct BlendFileReadParams *params,
- ReportList *reports)
+bool BKE_blendfile_read_from_memfile(bContext *C,
+ struct MemFile *memfile,
+ const struct BlendFileReadParams *params,
+ ReportList *reports)
{
- Main *bmain = CTX_data_main(C);
- BlendFileData *bfd;
-
- bfd = BLO_read_from_memfile(bmain, BKE_main_blendfile_path(bmain), memfile, params->skip_flags, reports);
- if (bfd) {
- /* remove the unused screens and wm */
- while (bfd->main->wm.first)
- BKE_id_free(bfd->main, bfd->main->wm.first);
- while (bfd->main->screens.first)
- BKE_id_free(bfd->main, bfd->main->screens.first);
-
- setup_app_data(C, bfd, "<memory1>", params->is_startup, reports);
- }
- else {
- BKE_reports_prepend(reports, "Loading failed: ");
- }
-
- return (bfd != NULL);
+ Main *bmain = CTX_data_main(C);
+ BlendFileData *bfd;
+
+ bfd = BLO_read_from_memfile(
+ bmain, BKE_main_blendfile_path(bmain), memfile, params->skip_flags, reports);
+ if (bfd) {
+ /* remove the unused screens and wm */
+ while (bfd->main->wm.first)
+ BKE_id_free(bfd->main, bfd->main->wm.first);
+ while (bfd->main->screens.first)
+ BKE_id_free(bfd->main, bfd->main->screens.first);
+
+ setup_app_data(C, bfd, "<memory1>", params->is_startup, reports);
+ }
+ else {
+ BKE_reports_prepend(reports, "Loading failed: ");
+ }
+
+ return (bfd != NULL);
}
/**
@@ -459,85 +460,81 @@ bool BKE_blendfile_read_from_memfile(
*/
void BKE_blendfile_read_make_empty(bContext *C)
{
- Main *bmain = CTX_data_main(C);
- ListBase *lb;
- ID *id;
-
- FOREACH_MAIN_LISTBASE_BEGIN(bmain, lb)
- {
- FOREACH_MAIN_LISTBASE_ID_BEGIN(lb, id)
- {
- if (ELEM(GS(id->name), ID_SCE, ID_SCR, ID_WM, ID_WS)) {
- break;
- }
- BKE_id_delete(bmain, id);
- }
- FOREACH_MAIN_LISTBASE_ID_END;
- }
- FOREACH_MAIN_LISTBASE_END;
+ Main *bmain = CTX_data_main(C);
+ ListBase *lb;
+ ID *id;
+
+ FOREACH_MAIN_LISTBASE_BEGIN(bmain, lb)
+ {
+ FOREACH_MAIN_LISTBASE_ID_BEGIN(lb, id)
+ {
+ if (ELEM(GS(id->name), ID_SCE, ID_SCR, ID_WM, ID_WS)) {
+ break;
+ }
+ BKE_id_delete(bmain, id);
+ }
+ FOREACH_MAIN_LISTBASE_ID_END;
+ }
+ FOREACH_MAIN_LISTBASE_END;
}
/* only read the userdef from a .blend */
UserDef *BKE_blendfile_userdef_read(const char *filepath, ReportList *reports)
{
- BlendFileData *bfd;
- UserDef *userdef = NULL;
-
- bfd = BLO_read_from_file(filepath, BLO_READ_SKIP_ALL & ~BLO_READ_SKIP_USERDEF, reports);
- if (bfd) {
- if (bfd->user) {
- userdef = bfd->user;
- }
- BKE_main_free(bfd->main);
- MEM_freeN(bfd);
- }
-
- return userdef;
+ BlendFileData *bfd;
+ UserDef *userdef = NULL;
+
+ bfd = BLO_read_from_file(filepath, BLO_READ_SKIP_ALL & ~BLO_READ_SKIP_USERDEF, reports);
+ if (bfd) {
+ if (bfd->user) {
+ userdef = bfd->user;
+ }
+ BKE_main_free(bfd->main);
+ MEM_freeN(bfd);
+ }
+
+ return userdef;
}
-
-UserDef *BKE_blendfile_userdef_read_from_memory(
- const void *filebuf, int filelength,
- ReportList *reports)
+UserDef *BKE_blendfile_userdef_read_from_memory(const void *filebuf,
+ int filelength,
+ ReportList *reports)
{
- BlendFileData *bfd;
- UserDef *userdef = NULL;
-
- bfd = BLO_read_from_memory(
- filebuf, filelength,
- BLO_READ_SKIP_ALL & ~BLO_READ_SKIP_USERDEF,
- reports);
- if (bfd) {
- if (bfd->user) {
- userdef = bfd->user;
- }
- BKE_main_free(bfd->main);
- MEM_freeN(bfd);
- }
- else {
- BKE_reports_prepend(reports, "Loading failed: ");
- }
-
- return userdef;
+ BlendFileData *bfd;
+ UserDef *userdef = NULL;
+
+ bfd = BLO_read_from_memory(
+ filebuf, filelength, BLO_READ_SKIP_ALL & ~BLO_READ_SKIP_USERDEF, reports);
+ if (bfd) {
+ if (bfd->user) {
+ userdef = bfd->user;
+ }
+ BKE_main_free(bfd->main);
+ MEM_freeN(bfd);
+ }
+ else {
+ BKE_reports_prepend(reports, "Loading failed: ");
+ }
+
+ return userdef;
}
-
/**
* Only write the userdef in a .blend
* \return success
*/
bool BKE_blendfile_userdef_write(const char *filepath, ReportList *reports)
{
- Main *mainb = MEM_callocN(sizeof(Main), "empty main");
- bool ok = false;
+ Main *mainb = MEM_callocN(sizeof(Main), "empty main");
+ bool ok = false;
- if (BLO_write_file(mainb, filepath, G_FILE_USERPREFS, reports, NULL)) {
- ok = true;
- }
+ if (BLO_write_file(mainb, filepath, G_FILE_USERPREFS, reports, NULL)) {
+ ok = true;
+ }
- MEM_freeN(mainb);
+ MEM_freeN(mainb);
- return ok;
+ return ok;
}
/**
@@ -549,182 +546,186 @@ bool BKE_blendfile_userdef_write(const char *filepath, ReportList *reports)
*/
bool BKE_blendfile_userdef_write_app_template(const char *filepath, ReportList *reports)
{
- /* if it fails, overwrite is OK. */
- UserDef *userdef_default = BKE_blendfile_userdef_read(filepath, NULL);
- if (userdef_default == NULL) {
- return BKE_blendfile_userdef_write(filepath, reports);
- }
-
- BKE_blender_userdef_app_template_data_swap(&U, userdef_default);
- bool ok = BKE_blendfile_userdef_write(filepath, reports);
- BKE_blender_userdef_app_template_data_swap(&U, userdef_default);
- BKE_blender_userdef_data_free(userdef_default, false);
- MEM_freeN(userdef_default);
- return ok;
+ /* if it fails, overwrite is OK. */
+ UserDef *userdef_default = BKE_blendfile_userdef_read(filepath, NULL);
+ if (userdef_default == NULL) {
+ return BKE_blendfile_userdef_write(filepath, reports);
+ }
+
+ BKE_blender_userdef_app_template_data_swap(&U, userdef_default);
+ bool ok = BKE_blendfile_userdef_write(filepath, reports);
+ BKE_blender_userdef_app_template_data_swap(&U, userdef_default);
+ BKE_blender_userdef_data_free(userdef_default, false);
+ MEM_freeN(userdef_default);
+ return ok;
}
-WorkspaceConfigFileData *BKE_blendfile_workspace_config_read(const char *filepath, const void *filebuf, int filelength, ReportList *reports)
+WorkspaceConfigFileData *BKE_blendfile_workspace_config_read(const char *filepath,
+ const void *filebuf,
+ int filelength,
+ ReportList *reports)
{
- BlendFileData *bfd;
- WorkspaceConfigFileData *workspace_config = NULL;
+ BlendFileData *bfd;
+ WorkspaceConfigFileData *workspace_config = NULL;
- if (filepath) {
- bfd = BLO_read_from_file(filepath, BLO_READ_SKIP_USERDEF, reports);
- }
- else {
- bfd = BLO_read_from_memory(filebuf, filelength, BLO_READ_SKIP_USERDEF, reports);
- }
+ if (filepath) {
+ bfd = BLO_read_from_file(filepath, BLO_READ_SKIP_USERDEF, reports);
+ }
+ else {
+ bfd = BLO_read_from_memory(filebuf, filelength, BLO_READ_SKIP_USERDEF, reports);
+ }
- if (bfd) {
- workspace_config = MEM_mallocN(sizeof(*workspace_config), __func__);
- workspace_config->main = bfd->main;
- workspace_config->workspaces = bfd->main->workspaces;
+ if (bfd) {
+ workspace_config = MEM_mallocN(sizeof(*workspace_config), __func__);
+ workspace_config->main = bfd->main;
+ workspace_config->workspaces = bfd->main->workspaces;
- MEM_freeN(bfd);
- }
+ MEM_freeN(bfd);
+ }
- return workspace_config;
+ return workspace_config;
}
bool BKE_blendfile_workspace_config_write(Main *bmain, const char *filepath, ReportList *reports)
{
- int fileflags = G.fileflags & ~(G_FILE_NO_UI | G_FILE_HISTORY);
- bool retval = false;
+ int fileflags = G.fileflags & ~(G_FILE_NO_UI | G_FILE_HISTORY);
+ bool retval = false;
- BKE_blendfile_write_partial_begin(bmain);
+ BKE_blendfile_write_partial_begin(bmain);
- for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
- BKE_blendfile_write_partial_tag_ID(&workspace->id, true);
- }
+ for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ BKE_blendfile_write_partial_tag_ID(&workspace->id, true);
+ }
- if (BKE_blendfile_write_partial(bmain, filepath, fileflags, reports)) {
- retval = true;
- }
+ if (BKE_blendfile_write_partial(bmain, filepath, fileflags, reports)) {
+ retval = true;
+ }
- BKE_blendfile_write_partial_end(bmain);
+ BKE_blendfile_write_partial_end(bmain);
- return retval;
+ return retval;
}
void BKE_blendfile_workspace_config_data_free(WorkspaceConfigFileData *workspace_config)
{
- BKE_main_free(workspace_config->main);
- MEM_freeN(workspace_config);
+ BKE_main_free(workspace_config->main);
+ MEM_freeN(workspace_config);
}
/** \} */
-
/* -------------------------------------------------------------------- */
/** \name Partial `.blend` file save.
* \{ */
void BKE_blendfile_write_partial_begin(Main *bmain_src)
{
- BKE_main_id_tag_all(bmain_src, LIB_TAG_NEED_EXPAND | LIB_TAG_DOIT, false);
+ BKE_main_id_tag_all(bmain_src, LIB_TAG_NEED_EXPAND | LIB_TAG_DOIT, false);
}
void BKE_blendfile_write_partial_tag_ID(ID *id, bool set)
{
- if (set) {
- id->tag |= LIB_TAG_NEED_EXPAND | LIB_TAG_DOIT;
- }
- else {
- id->tag &= ~(LIB_TAG_NEED_EXPAND | LIB_TAG_DOIT);
- }
+ if (set) {
+ id->tag |= LIB_TAG_NEED_EXPAND | LIB_TAG_DOIT;
+ }
+ else {
+ id->tag &= ~(LIB_TAG_NEED_EXPAND | LIB_TAG_DOIT);
+ }
}
static void blendfile_write_partial_cb(void *UNUSED(handle), Main *UNUSED(bmain), void *vid)
{
- if (vid) {
- ID *id = vid;
- /* only tag for need-expand if not done, prevents eternal loops */
- if ((id->tag & LIB_TAG_DOIT) == 0)
- id->tag |= LIB_TAG_NEED_EXPAND | LIB_TAG_DOIT;
-
- if (id->lib && (id->lib->id.tag & LIB_TAG_DOIT) == 0)
- id->lib->id.tag |= LIB_TAG_DOIT;
- }
+ if (vid) {
+ ID *id = vid;
+ /* only tag for need-expand if not done, prevents eternal loops */
+ if ((id->tag & LIB_TAG_DOIT) == 0)
+ id->tag |= LIB_TAG_NEED_EXPAND | LIB_TAG_DOIT;
+
+ if (id->lib && (id->lib->id.tag & LIB_TAG_DOIT) == 0)
+ id->lib->id.tag |= LIB_TAG_DOIT;
+ }
}
/**
* \return Success.
*/
-bool BKE_blendfile_write_partial(
- Main *bmain_src, const char *filepath, const int write_flags, ReportList *reports)
+bool BKE_blendfile_write_partial(Main *bmain_src,
+ const char *filepath,
+ const int write_flags,
+ ReportList *reports)
{
- Main *bmain_dst = MEM_callocN(sizeof(Main), "copybuffer");
- ListBase *lbarray_dst[MAX_LIBARRAY], *lbarray_src[MAX_LIBARRAY];
- int a, retval;
-
- void *path_list_backup = NULL;
- const int path_list_flag = (BKE_BPATH_TRAVERSE_SKIP_LIBRARY | BKE_BPATH_TRAVERSE_SKIP_MULTIFILE);
-
- /* This is needed to be able to load that file as a real one later
- * (otherwise main->name will not be set at read time). */
- BLI_strncpy(bmain_dst->name, bmain_src->name, sizeof(bmain_dst->name));
-
- BLO_main_expander(blendfile_write_partial_cb);
- BLO_expand_main(NULL, bmain_src);
-
- /* move over all tagged blocks */
- set_listbasepointers(bmain_src, lbarray_src);
- a = set_listbasepointers(bmain_dst, lbarray_dst);
- while (a--) {
- ID *id, *nextid;
- ListBase *lb_dst = lbarray_dst[a], *lb_src = lbarray_src[a];
-
- for (id = lb_src->first; id; id = nextid) {
- nextid = id->next;
- if (id->tag & LIB_TAG_DOIT) {
- BLI_remlink(lb_src, id);
- BLI_addtail(lb_dst, id);
- }
- }
- }
-
- /* Backup paths because remap relative will overwrite them.
- *
- * NOTE: we do this only on the list of datablocks that we are writing
- * because the restored full list is not guaranteed to be in the same
- * order as before, as expected by BKE_bpath_list_restore.
- *
- * This happens because id_sort_by_name does not take into account
- * string case or the library name, so the order is not strictly
- * defined for two linked datablocks with the same name! */
- if (write_flags & G_FILE_RELATIVE_REMAP) {
- path_list_backup = BKE_bpath_list_backup(bmain_dst, path_list_flag);
- }
-
- /* save the buffer */
- retval = BLO_write_file(bmain_dst, filepath, write_flags, reports, NULL);
-
- if (path_list_backup) {
- BKE_bpath_list_restore(bmain_dst, path_list_flag, path_list_backup);
- BKE_bpath_list_free(path_list_backup);
- }
-
- /* move back the main, now sorted again */
- set_listbasepointers(bmain_src, lbarray_dst);
- a = set_listbasepointers(bmain_dst, lbarray_src);
- while (a--) {
- ID *id;
- ListBase *lb_dst = lbarray_dst[a], *lb_src = lbarray_src[a];
-
- while ((id = BLI_pophead(lb_src))) {
- BLI_addtail(lb_dst, id);
- id_sort_by_name(lb_dst, id);
- }
- }
-
- MEM_freeN(bmain_dst);
-
- return retval;
+ Main *bmain_dst = MEM_callocN(sizeof(Main), "copybuffer");
+ ListBase *lbarray_dst[MAX_LIBARRAY], *lbarray_src[MAX_LIBARRAY];
+ int a, retval;
+
+ void *path_list_backup = NULL;
+ const int path_list_flag = (BKE_BPATH_TRAVERSE_SKIP_LIBRARY | BKE_BPATH_TRAVERSE_SKIP_MULTIFILE);
+
+ /* This is needed to be able to load that file as a real one later
+ * (otherwise main->name will not be set at read time). */
+ BLI_strncpy(bmain_dst->name, bmain_src->name, sizeof(bmain_dst->name));
+
+ BLO_main_expander(blendfile_write_partial_cb);
+ BLO_expand_main(NULL, bmain_src);
+
+ /* move over all tagged blocks */
+ set_listbasepointers(bmain_src, lbarray_src);
+ a = set_listbasepointers(bmain_dst, lbarray_dst);
+ while (a--) {
+ ID *id, *nextid;
+ ListBase *lb_dst = lbarray_dst[a], *lb_src = lbarray_src[a];
+
+ for (id = lb_src->first; id; id = nextid) {
+ nextid = id->next;
+ if (id->tag & LIB_TAG_DOIT) {
+ BLI_remlink(lb_src, id);
+ BLI_addtail(lb_dst, id);
+ }
+ }
+ }
+
+ /* Backup paths because remap relative will overwrite them.
+ *
+ * NOTE: we do this only on the list of datablocks that we are writing
+ * because the restored full list is not guaranteed to be in the same
+ * order as before, as expected by BKE_bpath_list_restore.
+ *
+ * This happens because id_sort_by_name does not take into account
+ * string case or the library name, so the order is not strictly
+ * defined for two linked datablocks with the same name! */
+ if (write_flags & G_FILE_RELATIVE_REMAP) {
+ path_list_backup = BKE_bpath_list_backup(bmain_dst, path_list_flag);
+ }
+
+ /* save the buffer */
+ retval = BLO_write_file(bmain_dst, filepath, write_flags, reports, NULL);
+
+ if (path_list_backup) {
+ BKE_bpath_list_restore(bmain_dst, path_list_flag, path_list_backup);
+ BKE_bpath_list_free(path_list_backup);
+ }
+
+ /* move back the main, now sorted again */
+ set_listbasepointers(bmain_src, lbarray_dst);
+ a = set_listbasepointers(bmain_dst, lbarray_src);
+ while (a--) {
+ ID *id;
+ ListBase *lb_dst = lbarray_dst[a], *lb_src = lbarray_src[a];
+
+ while ((id = BLI_pophead(lb_src))) {
+ BLI_addtail(lb_dst, id);
+ id_sort_by_name(lb_dst, id);
+ }
+ }
+
+ MEM_freeN(bmain_dst);
+
+ return retval;
}
void BKE_blendfile_write_partial_end(Main *bmain_src)
{
- BKE_main_id_tag_all(bmain_src, LIB_TAG_NEED_EXPAND | LIB_TAG_DOIT, false);
+ BKE_main_id_tag_all(bmain_src, LIB_TAG_NEED_EXPAND | LIB_TAG_DOIT, false);
}
/** \} */
diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c
index c092b2c7e79..b31a283448c 100644
--- a/source/blender/blenkernel/intern/boids.c
+++ b/source/blender/blenkernel/intern/boids.c
@@ -21,7 +21,6 @@
* \ingroup bke
*/
-
#include <string.h>
#include <math.h>
@@ -45,1587 +44,1670 @@
#include "RNA_enum_types.h"
-static float len_squared_v3v3_with_normal_bias(
- const float co_search[3], const float co_test[3], const void *user_data)
+static float len_squared_v3v3_with_normal_bias(const float co_search[3],
+ const float co_test[3],
+ const void *user_data)
{
- const float *normal = user_data;
- float d[3], dist;
+ const float *normal = user_data;
+ float d[3], dist;
- sub_v3_v3v3(d, co_test, co_search);
+ sub_v3_v3v3(d, co_test, co_search);
- dist = len_squared_v3(d);
+ dist = len_squared_v3(d);
- /* Avoid head-on collisions. */
- if (dot_v3v3(d, normal) < 0.0f) {
- dist *= 10.0f;
- }
- return dist;
+ /* Avoid head-on collisions. */
+ if (dot_v3v3(d, normal) < 0.0f) {
+ dist *= 10.0f;
+ }
+ return dist;
}
typedef struct BoidValues {
- float max_speed, max_acc;
- float max_ave, min_speed;
- float personal_space, jump_speed;
+ float max_speed, max_acc;
+ float max_ave, min_speed;
+ float personal_space, jump_speed;
} BoidValues;
-static int apply_boid_rule(BoidBrainData *bbd, BoidRule *rule, BoidValues *val, ParticleData *pa, float fuzziness);
+static int apply_boid_rule(
+ BoidBrainData *bbd, BoidRule *rule, BoidValues *val, ParticleData *pa, float fuzziness);
-static int rule_none(BoidRule *UNUSED(rule), BoidBrainData *UNUSED(data), BoidValues *UNUSED(val), ParticleData *UNUSED(pa))
+static int rule_none(BoidRule *UNUSED(rule),
+ BoidBrainData *UNUSED(data),
+ BoidValues *UNUSED(val),
+ ParticleData *UNUSED(pa))
{
- return 0;
+ return 0;
}
static int rule_goal_avoid(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
{
- BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid*) rule;
- BoidSettings *boids = bbd->part->boids;
- BoidParticle *bpa = pa->boid;
- EffectedPoint epoint;
- ListBase *effectors = bbd->sim->psys->effectors;
- EffectorCache *cur, *eff = NULL;
- EffectorCache temp_eff;
- EffectorData efd, cur_efd;
- float mul = (rule->type == eBoidRuleType_Avoid ? 1.0 : -1.0);
- float priority = 0.0f, len = 0.0f;
- int ret = 0;
-
- int p = 0;
- efd.index = cur_efd.index = &p;
-
- pd_point_from_particle(bbd->sim, pa, &pa->state, &epoint);
-
- /* first find out goal/predator with highest priority */
- if (effectors) for (cur = effectors->first; cur; cur=cur->next) {
- Object *eob = cur->ob;
- PartDeflect *pd = cur->pd;
-
- if (gabr->ob && (rule->type != eBoidRuleType_Goal || gabr->ob != bpa->ground)) {
- if (gabr->ob == eob) {
- /* TODO: effectors with multiple points */
- if (get_effector_data(cur, &efd, &epoint, 0)) {
- if (cur->pd && cur->pd->forcefield == PFIELD_BOID)
- priority = mul * pd->f_strength * effector_falloff(cur, &efd, &epoint, bbd->part->effector_weights);
- else
- priority = 1.0;
-
- eff = cur;
- }
- break;
- }
- }
- else if (rule->type == eBoidRuleType_Goal && eob == bpa->ground) {
- /* skip current object */
- }
- else if (pd->forcefield == PFIELD_BOID && mul * pd->f_strength > 0.0f && get_effector_data(cur, &cur_efd, &epoint, 0)) {
- float temp = mul * pd->f_strength * effector_falloff(cur, &cur_efd, &epoint, bbd->part->effector_weights);
-
- if (temp == 0.0f) {
- /* do nothing */
- }
- else if (temp > priority) {
- priority = temp;
- eff = cur;
- efd = cur_efd;
- len = efd.distance;
- }
- /* choose closest object with same priority */
- else if (temp == priority && efd.distance < len) {
- eff = cur;
- efd = cur_efd;
- len = efd.distance;
- }
- }
- }
-
- /* if the object doesn't have effector data we have to fake it */
- if (eff == NULL && gabr->ob) {
- memset(&temp_eff, 0, sizeof(EffectorCache));
- temp_eff.ob = gabr->ob;
- temp_eff.depsgraph = bbd->sim->depsgraph;
- temp_eff.scene = bbd->sim->scene;
- eff = &temp_eff;
- get_effector_data(eff, &efd, &epoint, 0);
- priority = 1.0f;
- }
-
- /* then use that effector */
- if (priority > (rule->type==eBoidRuleType_Avoid ? gabr->fear_factor : 0.0f)) { /* with avoid, factor is "fear factor" */
- Object *eob = eff->ob;
- PartDeflect *pd = eff->pd;
- float surface = (pd && pd->shape == PFIELD_SHAPE_SURFACE) ? 1.0f : 0.0f;
-
- if (gabr->options & BRULE_GOAL_AVOID_PREDICT) {
- /* estimate future location of target */
- get_effector_data(eff, &efd, &epoint, 1);
-
- mul_v3_fl(efd.vel, efd.distance / (val->max_speed * bbd->timestep));
- add_v3_v3(efd.loc, efd.vel);
- sub_v3_v3v3(efd.vec_to_point, pa->prev_state.co, efd.loc);
- efd.distance = len_v3(efd.vec_to_point);
- }
-
- if (rule->type == eBoidRuleType_Goal && boids->options & BOID_ALLOW_CLIMB && surface!=0.0f) {
- if (!bbd->goal_ob || bbd->goal_priority < priority) {
- bbd->goal_ob = eob;
- copy_v3_v3(bbd->goal_co, efd.loc);
- copy_v3_v3(bbd->goal_nor, efd.nor);
- }
- }
- else if ((rule->type == eBoidRuleType_Avoid) &&
- (bpa->data.mode == eBoidMode_Climbing) &&
- (priority > 2.0f * gabr->fear_factor))
- {
- /* detach from surface and try to fly away from danger */
- negate_v3_v3(efd.vec_to_point, bpa->gravity);
- }
-
- copy_v3_v3(bbd->wanted_co, efd.vec_to_point);
- mul_v3_fl(bbd->wanted_co, mul);
-
- bbd->wanted_speed = val->max_speed * priority;
-
- /* with goals factor is approach velocity factor */
- if (rule->type == eBoidRuleType_Goal && boids->landing_smoothness > 0.0f) {
- float len2 = 2.0f*len_v3(pa->prev_state.vel);
-
- surface *= pa->size * boids->height;
-
- if (len2 > 0.0f && efd.distance - surface < len2) {
- len2 = (efd.distance - surface)/len2;
- bbd->wanted_speed *= powf(len2, boids->landing_smoothness);
- }
- }
-
- ret = 1;
- }
-
- return ret;
+ BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid *)rule;
+ BoidSettings *boids = bbd->part->boids;
+ BoidParticle *bpa = pa->boid;
+ EffectedPoint epoint;
+ ListBase *effectors = bbd->sim->psys->effectors;
+ EffectorCache *cur, *eff = NULL;
+ EffectorCache temp_eff;
+ EffectorData efd, cur_efd;
+ float mul = (rule->type == eBoidRuleType_Avoid ? 1.0 : -1.0);
+ float priority = 0.0f, len = 0.0f;
+ int ret = 0;
+
+ int p = 0;
+ efd.index = cur_efd.index = &p;
+
+ pd_point_from_particle(bbd->sim, pa, &pa->state, &epoint);
+
+ /* first find out goal/predator with highest priority */
+ if (effectors)
+ for (cur = effectors->first; cur; cur = cur->next) {
+ Object *eob = cur->ob;
+ PartDeflect *pd = cur->pd;
+
+ if (gabr->ob && (rule->type != eBoidRuleType_Goal || gabr->ob != bpa->ground)) {
+ if (gabr->ob == eob) {
+ /* TODO: effectors with multiple points */
+ if (get_effector_data(cur, &efd, &epoint, 0)) {
+ if (cur->pd && cur->pd->forcefield == PFIELD_BOID)
+ priority = mul * pd->f_strength *
+ effector_falloff(cur, &efd, &epoint, bbd->part->effector_weights);
+ else
+ priority = 1.0;
+
+ eff = cur;
+ }
+ break;
+ }
+ }
+ else if (rule->type == eBoidRuleType_Goal && eob == bpa->ground) {
+ /* skip current object */
+ }
+ else if (pd->forcefield == PFIELD_BOID && mul * pd->f_strength > 0.0f &&
+ get_effector_data(cur, &cur_efd, &epoint, 0)) {
+ float temp = mul * pd->f_strength *
+ effector_falloff(cur, &cur_efd, &epoint, bbd->part->effector_weights);
+
+ if (temp == 0.0f) {
+ /* do nothing */
+ }
+ else if (temp > priority) {
+ priority = temp;
+ eff = cur;
+ efd = cur_efd;
+ len = efd.distance;
+ }
+ /* choose closest object with same priority */
+ else if (temp == priority && efd.distance < len) {
+ eff = cur;
+ efd = cur_efd;
+ len = efd.distance;
+ }
+ }
+ }
+
+ /* if the object doesn't have effector data we have to fake it */
+ if (eff == NULL && gabr->ob) {
+ memset(&temp_eff, 0, sizeof(EffectorCache));
+ temp_eff.ob = gabr->ob;
+ temp_eff.depsgraph = bbd->sim->depsgraph;
+ temp_eff.scene = bbd->sim->scene;
+ eff = &temp_eff;
+ get_effector_data(eff, &efd, &epoint, 0);
+ priority = 1.0f;
+ }
+
+ /* then use that effector */
+ if (priority > (rule->type == eBoidRuleType_Avoid ?
+ gabr->fear_factor :
+ 0.0f)) { /* with avoid, factor is "fear factor" */
+ Object *eob = eff->ob;
+ PartDeflect *pd = eff->pd;
+ float surface = (pd && pd->shape == PFIELD_SHAPE_SURFACE) ? 1.0f : 0.0f;
+
+ if (gabr->options & BRULE_GOAL_AVOID_PREDICT) {
+ /* estimate future location of target */
+ get_effector_data(eff, &efd, &epoint, 1);
+
+ mul_v3_fl(efd.vel, efd.distance / (val->max_speed * bbd->timestep));
+ add_v3_v3(efd.loc, efd.vel);
+ sub_v3_v3v3(efd.vec_to_point, pa->prev_state.co, efd.loc);
+ efd.distance = len_v3(efd.vec_to_point);
+ }
+
+ if (rule->type == eBoidRuleType_Goal && boids->options & BOID_ALLOW_CLIMB && surface != 0.0f) {
+ if (!bbd->goal_ob || bbd->goal_priority < priority) {
+ bbd->goal_ob = eob;
+ copy_v3_v3(bbd->goal_co, efd.loc);
+ copy_v3_v3(bbd->goal_nor, efd.nor);
+ }
+ }
+ else if ((rule->type == eBoidRuleType_Avoid) && (bpa->data.mode == eBoidMode_Climbing) &&
+ (priority > 2.0f * gabr->fear_factor)) {
+ /* detach from surface and try to fly away from danger */
+ negate_v3_v3(efd.vec_to_point, bpa->gravity);
+ }
+
+ copy_v3_v3(bbd->wanted_co, efd.vec_to_point);
+ mul_v3_fl(bbd->wanted_co, mul);
+
+ bbd->wanted_speed = val->max_speed * priority;
+
+ /* with goals factor is approach velocity factor */
+ if (rule->type == eBoidRuleType_Goal && boids->landing_smoothness > 0.0f) {
+ float len2 = 2.0f * len_v3(pa->prev_state.vel);
+
+ surface *= pa->size * boids->height;
+
+ if (len2 > 0.0f && efd.distance - surface < len2) {
+ len2 = (efd.distance - surface) / len2;
+ bbd->wanted_speed *= powf(len2, boids->landing_smoothness);
+ }
+ }
+
+ ret = 1;
+ }
+
+ return ret;
}
-static int rule_avoid_collision(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
+static int rule_avoid_collision(BoidRule *rule,
+ BoidBrainData *bbd,
+ BoidValues *val,
+ ParticleData *pa)
{
- const int raycast_flag = BVH_RAYCAST_DEFAULT & ~(BVH_RAYCAST_WATERTIGHT);
- BoidRuleAvoidCollision *acbr = (BoidRuleAvoidCollision*) rule;
- KDTreeNearest_3d *ptn = NULL;
- ParticleTarget *pt;
- BoidParticle *bpa = pa->boid;
- ColliderCache *coll;
- float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f};
- float co1[3], vel1[3], co2[3], vel2[3];
- float len, t, inp, t_min = 2.0f;
- int n, neighbors = 0, nearest = 0;
- int ret = 0;
-
- //check deflector objects first
- if (acbr->options & BRULE_ACOLL_WITH_DEFLECTORS && bbd->sim->colliders) {
- ParticleCollision col;
- BVHTreeRayHit hit;
- float radius = val->personal_space * pa->size, ray_dir[3];
-
- memset(&col, 0, sizeof(ParticleCollision));
-
- copy_v3_v3(col.co1, pa->prev_state.co);
- add_v3_v3v3(col.co2, pa->prev_state.co, pa->prev_state.vel);
- sub_v3_v3v3(ray_dir, col.co2, col.co1);
- mul_v3_fl(ray_dir, acbr->look_ahead);
- col.f = 0.0f;
- hit.index = -1;
- hit.dist = col.original_ray_length = normalize_v3(ray_dir);
-
- /* find out closest deflector object */
- for (coll = bbd->sim->colliders->first; coll; coll=coll->next) {
- /* don't check with current ground object */
- if (coll->ob == bpa->ground)
- continue;
-
- col.current = coll->ob;
- col.md = coll->collmd;
-
- if (col.md && col.md->bvhtree) {
- BLI_bvhtree_ray_cast_ex(
- col.md->bvhtree, col.co1, ray_dir, radius, &hit,
- BKE_psys_collision_neartest_cb, &col, raycast_flag);
- }
- }
- /* then avoid that object */
- if (hit.index>=0) {
- t = hit.dist/col.original_ray_length;
-
- /* avoid head-on collision */
- if (dot_v3v3(col.pce.nor, pa->prev_state.ave) < -0.99f) {
- /* don't know why, but uneven range [0.0, 1.0] */
- /* works much better than even [-1.0, 1.0] */
- bbd->wanted_co[0] = BLI_rng_get_float(bbd->rng);
- bbd->wanted_co[1] = BLI_rng_get_float(bbd->rng);
- bbd->wanted_co[2] = BLI_rng_get_float(bbd->rng);
- }
- else {
- copy_v3_v3(bbd->wanted_co, col.pce.nor);
- }
-
- mul_v3_fl(bbd->wanted_co, (1.0f - t) * val->personal_space * pa->size);
-
- bbd->wanted_speed = sqrtf(t) * len_v3(pa->prev_state.vel);
- bbd->wanted_speed = MAX2(bbd->wanted_speed, val->min_speed);
-
- return 1;
- }
- }
-
- //check boids in own system
- if (acbr->options & BRULE_ACOLL_WITH_BOIDS) {
- neighbors = BLI_kdtree_3d_range_search_with_len_squared_cb(
- bbd->sim->psys->tree, pa->prev_state.co, &ptn, acbr->look_ahead * len_v3(pa->prev_state.vel),
- len_squared_v3v3_with_normal_bias, pa->prev_state.ave);
- if (neighbors > 1) for (n=1; n<neighbors; n++) {
- copy_v3_v3(co1, pa->prev_state.co);
- copy_v3_v3(vel1, pa->prev_state.vel);
- copy_v3_v3(co2, (bbd->sim->psys->particles + ptn[n].index)->prev_state.co);
- copy_v3_v3(vel2, (bbd->sim->psys->particles + ptn[n].index)->prev_state.vel);
-
- sub_v3_v3v3(loc, co1, co2);
-
- sub_v3_v3v3(vec, vel1, vel2);
-
- inp = dot_v3v3(vec, vec);
-
- /* velocities not parallel */
- if (inp != 0.0f) {
- t = -dot_v3v3(loc, vec)/inp;
- /* cpa is not too far in the future so investigate further */
- if (t > 0.0f && t < t_min) {
- madd_v3_v3fl(co1, vel1, t);
- madd_v3_v3fl(co2, vel2, t);
-
- sub_v3_v3v3(vec, co2, co1);
-
- len = normalize_v3(vec);
-
- /* distance of cpa is close enough */
- if (len < 2.0f * val->personal_space * pa->size) {
- t_min = t;
-
- mul_v3_fl(vec, len_v3(vel1));
- mul_v3_fl(vec, (2.0f - t)/2.0f);
- sub_v3_v3v3(bbd->wanted_co, vel1, vec);
- bbd->wanted_speed = len_v3(bbd->wanted_co);
- ret = 1;
- }
- }
- }
- }
- }
- if (ptn) { MEM_freeN(ptn); ptn=NULL; }
-
- /* check boids in other systems */
- for (pt=bbd->sim->psys->targets.first; pt; pt=pt->next) {
- ParticleSystem *epsys = psys_get_target_system(bbd->sim->ob, pt);
-
- if (epsys) {
- BLI_assert(epsys->tree != NULL);
- neighbors = BLI_kdtree_3d_range_search_with_len_squared_cb(
- epsys->tree, pa->prev_state.co, &ptn, acbr->look_ahead * len_v3(pa->prev_state.vel),
- len_squared_v3v3_with_normal_bias, pa->prev_state.ave);
-
- if (neighbors > 0) for (n=0; n<neighbors; n++) {
- copy_v3_v3(co1, pa->prev_state.co);
- copy_v3_v3(vel1, pa->prev_state.vel);
- copy_v3_v3(co2, (epsys->particles + ptn[n].index)->prev_state.co);
- copy_v3_v3(vel2, (epsys->particles + ptn[n].index)->prev_state.vel);
-
- sub_v3_v3v3(loc, co1, co2);
-
- sub_v3_v3v3(vec, vel1, vel2);
-
- inp = dot_v3v3(vec, vec);
-
- /* velocities not parallel */
- if (inp != 0.0f) {
- t = -dot_v3v3(loc, vec)/inp;
- /* cpa is not too far in the future so investigate further */
- if (t > 0.0f && t < t_min) {
- madd_v3_v3fl(co1, vel1, t);
- madd_v3_v3fl(co2, vel2, t);
-
- sub_v3_v3v3(vec, co2, co1);
-
- len = normalize_v3(vec);
-
- /* distance of cpa is close enough */
- if (len < 2.0f * val->personal_space * pa->size) {
- t_min = t;
-
- mul_v3_fl(vec, len_v3(vel1));
- mul_v3_fl(vec, (2.0f - t)/2.0f);
- sub_v3_v3v3(bbd->wanted_co, vel1, vec);
- bbd->wanted_speed = len_v3(bbd->wanted_co);
- ret = 1;
- }
- }
- }
- }
-
- if (ptn) { MEM_freeN(ptn); ptn=NULL; }
- }
- }
-
-
- if (ptn && nearest==0)
- MEM_freeN(ptn);
-
- return ret;
+ const int raycast_flag = BVH_RAYCAST_DEFAULT & ~(BVH_RAYCAST_WATERTIGHT);
+ BoidRuleAvoidCollision *acbr = (BoidRuleAvoidCollision *)rule;
+ KDTreeNearest_3d *ptn = NULL;
+ ParticleTarget *pt;
+ BoidParticle *bpa = pa->boid;
+ ColliderCache *coll;
+ float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f};
+ float co1[3], vel1[3], co2[3], vel2[3];
+ float len, t, inp, t_min = 2.0f;
+ int n, neighbors = 0, nearest = 0;
+ int ret = 0;
+
+ //check deflector objects first
+ if (acbr->options & BRULE_ACOLL_WITH_DEFLECTORS && bbd->sim->colliders) {
+ ParticleCollision col;
+ BVHTreeRayHit hit;
+ float radius = val->personal_space * pa->size, ray_dir[3];
+
+ memset(&col, 0, sizeof(ParticleCollision));
+
+ copy_v3_v3(col.co1, pa->prev_state.co);
+ add_v3_v3v3(col.co2, pa->prev_state.co, pa->prev_state.vel);
+ sub_v3_v3v3(ray_dir, col.co2, col.co1);
+ mul_v3_fl(ray_dir, acbr->look_ahead);
+ col.f = 0.0f;
+ hit.index = -1;
+ hit.dist = col.original_ray_length = normalize_v3(ray_dir);
+
+ /* find out closest deflector object */
+ for (coll = bbd->sim->colliders->first; coll; coll = coll->next) {
+ /* don't check with current ground object */
+ if (coll->ob == bpa->ground)
+ continue;
+
+ col.current = coll->ob;
+ col.md = coll->collmd;
+
+ if (col.md && col.md->bvhtree) {
+ BLI_bvhtree_ray_cast_ex(col.md->bvhtree,
+ col.co1,
+ ray_dir,
+ radius,
+ &hit,
+ BKE_psys_collision_neartest_cb,
+ &col,
+ raycast_flag);
+ }
+ }
+ /* then avoid that object */
+ if (hit.index >= 0) {
+ t = hit.dist / col.original_ray_length;
+
+ /* avoid head-on collision */
+ if (dot_v3v3(col.pce.nor, pa->prev_state.ave) < -0.99f) {
+ /* don't know why, but uneven range [0.0, 1.0] */
+ /* works much better than even [-1.0, 1.0] */
+ bbd->wanted_co[0] = BLI_rng_get_float(bbd->rng);
+ bbd->wanted_co[1] = BLI_rng_get_float(bbd->rng);
+ bbd->wanted_co[2] = BLI_rng_get_float(bbd->rng);
+ }
+ else {
+ copy_v3_v3(bbd->wanted_co, col.pce.nor);
+ }
+
+ mul_v3_fl(bbd->wanted_co, (1.0f - t) * val->personal_space * pa->size);
+
+ bbd->wanted_speed = sqrtf(t) * len_v3(pa->prev_state.vel);
+ bbd->wanted_speed = MAX2(bbd->wanted_speed, val->min_speed);
+
+ return 1;
+ }
+ }
+
+ //check boids in own system
+ if (acbr->options & BRULE_ACOLL_WITH_BOIDS) {
+ neighbors = BLI_kdtree_3d_range_search_with_len_squared_cb(bbd->sim->psys->tree,
+ pa->prev_state.co,
+ &ptn,
+ acbr->look_ahead *
+ len_v3(pa->prev_state.vel),
+ len_squared_v3v3_with_normal_bias,
+ pa->prev_state.ave);
+ if (neighbors > 1)
+ for (n = 1; n < neighbors; n++) {
+ copy_v3_v3(co1, pa->prev_state.co);
+ copy_v3_v3(vel1, pa->prev_state.vel);
+ copy_v3_v3(co2, (bbd->sim->psys->particles + ptn[n].index)->prev_state.co);
+ copy_v3_v3(vel2, (bbd->sim->psys->particles + ptn[n].index)->prev_state.vel);
+
+ sub_v3_v3v3(loc, co1, co2);
+
+ sub_v3_v3v3(vec, vel1, vel2);
+
+ inp = dot_v3v3(vec, vec);
+
+ /* velocities not parallel */
+ if (inp != 0.0f) {
+ t = -dot_v3v3(loc, vec) / inp;
+ /* cpa is not too far in the future so investigate further */
+ if (t > 0.0f && t < t_min) {
+ madd_v3_v3fl(co1, vel1, t);
+ madd_v3_v3fl(co2, vel2, t);
+
+ sub_v3_v3v3(vec, co2, co1);
+
+ len = normalize_v3(vec);
+
+ /* distance of cpa is close enough */
+ if (len < 2.0f * val->personal_space * pa->size) {
+ t_min = t;
+
+ mul_v3_fl(vec, len_v3(vel1));
+ mul_v3_fl(vec, (2.0f - t) / 2.0f);
+ sub_v3_v3v3(bbd->wanted_co, vel1, vec);
+ bbd->wanted_speed = len_v3(bbd->wanted_co);
+ ret = 1;
+ }
+ }
+ }
+ }
+ }
+ if (ptn) {
+ MEM_freeN(ptn);
+ ptn = NULL;
+ }
+
+ /* check boids in other systems */
+ for (pt = bbd->sim->psys->targets.first; pt; pt = pt->next) {
+ ParticleSystem *epsys = psys_get_target_system(bbd->sim->ob, pt);
+
+ if (epsys) {
+ BLI_assert(epsys->tree != NULL);
+ neighbors = BLI_kdtree_3d_range_search_with_len_squared_cb(epsys->tree,
+ pa->prev_state.co,
+ &ptn,
+ acbr->look_ahead *
+ len_v3(pa->prev_state.vel),
+ len_squared_v3v3_with_normal_bias,
+ pa->prev_state.ave);
+
+ if (neighbors > 0)
+ for (n = 0; n < neighbors; n++) {
+ copy_v3_v3(co1, pa->prev_state.co);
+ copy_v3_v3(vel1, pa->prev_state.vel);
+ copy_v3_v3(co2, (epsys->particles + ptn[n].index)->prev_state.co);
+ copy_v3_v3(vel2, (epsys->particles + ptn[n].index)->prev_state.vel);
+
+ sub_v3_v3v3(loc, co1, co2);
+
+ sub_v3_v3v3(vec, vel1, vel2);
+
+ inp = dot_v3v3(vec, vec);
+
+ /* velocities not parallel */
+ if (inp != 0.0f) {
+ t = -dot_v3v3(loc, vec) / inp;
+ /* cpa is not too far in the future so investigate further */
+ if (t > 0.0f && t < t_min) {
+ madd_v3_v3fl(co1, vel1, t);
+ madd_v3_v3fl(co2, vel2, t);
+
+ sub_v3_v3v3(vec, co2, co1);
+
+ len = normalize_v3(vec);
+
+ /* distance of cpa is close enough */
+ if (len < 2.0f * val->personal_space * pa->size) {
+ t_min = t;
+
+ mul_v3_fl(vec, len_v3(vel1));
+ mul_v3_fl(vec, (2.0f - t) / 2.0f);
+ sub_v3_v3v3(bbd->wanted_co, vel1, vec);
+ bbd->wanted_speed = len_v3(bbd->wanted_co);
+ ret = 1;
+ }
+ }
+ }
+ }
+
+ if (ptn) {
+ MEM_freeN(ptn);
+ ptn = NULL;
+ }
+ }
+ }
+
+ if (ptn && nearest == 0)
+ MEM_freeN(ptn);
+
+ return ret;
}
-static int rule_separate(BoidRule *UNUSED(rule), BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
+static int rule_separate(BoidRule *UNUSED(rule),
+ BoidBrainData *bbd,
+ BoidValues *val,
+ ParticleData *pa)
{
- KDTreeNearest_3d *ptn = NULL;
- ParticleTarget *pt;
- float len = 2.0f * val->personal_space * pa->size + 1.0f;
- float vec[3] = {0.0f, 0.0f, 0.0f};
- int neighbors = BLI_kdtree_3d_range_search(
- bbd->sim->psys->tree, pa->prev_state.co,
- &ptn, 2.0f * val->personal_space * pa->size);
- int ret = 0;
-
- if (neighbors > 1 && ptn[1].dist!=0.0f) {
- sub_v3_v3v3(vec, pa->prev_state.co, bbd->sim->psys->particles[ptn[1].index].state.co);
- mul_v3_fl(vec, (2.0f * val->personal_space * pa->size - ptn[1].dist) / ptn[1].dist);
- add_v3_v3(bbd->wanted_co, vec);
- bbd->wanted_speed = val->max_speed;
- len = ptn[1].dist;
- ret = 1;
- }
- if (ptn) { MEM_freeN(ptn); ptn=NULL; }
-
- /* check other boid systems */
- for (pt=bbd->sim->psys->targets.first; pt; pt=pt->next) {
- ParticleSystem *epsys = psys_get_target_system(bbd->sim->ob, pt);
-
- if (epsys) {
- neighbors = BLI_kdtree_3d_range_search(
- epsys->tree, pa->prev_state.co,
- &ptn, 2.0f * val->personal_space * pa->size);
-
- if (neighbors > 0 && ptn[0].dist < len) {
- sub_v3_v3v3(vec, pa->prev_state.co, ptn[0].co);
- mul_v3_fl(vec, (2.0f * val->personal_space * pa->size - ptn[0].dist) / ptn[1].dist);
- add_v3_v3(bbd->wanted_co, vec);
- bbd->wanted_speed = val->max_speed;
- len = ptn[0].dist;
- ret = 1;
- }
-
- if (ptn) { MEM_freeN(ptn); ptn=NULL; }
- }
- }
- return ret;
+ KDTreeNearest_3d *ptn = NULL;
+ ParticleTarget *pt;
+ float len = 2.0f * val->personal_space * pa->size + 1.0f;
+ float vec[3] = {0.0f, 0.0f, 0.0f};
+ int neighbors = BLI_kdtree_3d_range_search(
+ bbd->sim->psys->tree, pa->prev_state.co, &ptn, 2.0f * val->personal_space * pa->size);
+ int ret = 0;
+
+ if (neighbors > 1 && ptn[1].dist != 0.0f) {
+ sub_v3_v3v3(vec, pa->prev_state.co, bbd->sim->psys->particles[ptn[1].index].state.co);
+ mul_v3_fl(vec, (2.0f * val->personal_space * pa->size - ptn[1].dist) / ptn[1].dist);
+ add_v3_v3(bbd->wanted_co, vec);
+ bbd->wanted_speed = val->max_speed;
+ len = ptn[1].dist;
+ ret = 1;
+ }
+ if (ptn) {
+ MEM_freeN(ptn);
+ ptn = NULL;
+ }
+
+ /* check other boid systems */
+ for (pt = bbd->sim->psys->targets.first; pt; pt = pt->next) {
+ ParticleSystem *epsys = psys_get_target_system(bbd->sim->ob, pt);
+
+ if (epsys) {
+ neighbors = BLI_kdtree_3d_range_search(
+ epsys->tree, pa->prev_state.co, &ptn, 2.0f * val->personal_space * pa->size);
+
+ if (neighbors > 0 && ptn[0].dist < len) {
+ sub_v3_v3v3(vec, pa->prev_state.co, ptn[0].co);
+ mul_v3_fl(vec, (2.0f * val->personal_space * pa->size - ptn[0].dist) / ptn[1].dist);
+ add_v3_v3(bbd->wanted_co, vec);
+ bbd->wanted_speed = val->max_speed;
+ len = ptn[0].dist;
+ ret = 1;
+ }
+
+ if (ptn) {
+ MEM_freeN(ptn);
+ ptn = NULL;
+ }
+ }
+ }
+ return ret;
}
-static int rule_flock(BoidRule *UNUSED(rule), BoidBrainData *bbd, BoidValues *UNUSED(val), ParticleData *pa)
+static int rule_flock(BoidRule *UNUSED(rule),
+ BoidBrainData *bbd,
+ BoidValues *UNUSED(val),
+ ParticleData *pa)
{
- KDTreeNearest_3d ptn[11];
- float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f};
- int neighbors = BLI_kdtree_3d_find_nearest_n_with_len_squared_cb(
- bbd->sim->psys->tree, pa->state.co, ptn, ARRAY_SIZE(ptn),
- len_squared_v3v3_with_normal_bias, pa->prev_state.ave);
- int n;
- int ret = 0;
-
- if (neighbors > 1) {
- for (n=1; n<neighbors; n++) {
- add_v3_v3(loc, bbd->sim->psys->particles[ptn[n].index].prev_state.co);
- add_v3_v3(vec, bbd->sim->psys->particles[ptn[n].index].prev_state.vel);
- }
-
- mul_v3_fl(loc, 1.0f/((float)neighbors - 1.0f));
- mul_v3_fl(vec, 1.0f/((float)neighbors - 1.0f));
-
- sub_v3_v3(loc, pa->prev_state.co);
- sub_v3_v3(vec, pa->prev_state.vel);
-
- add_v3_v3(bbd->wanted_co, vec);
- add_v3_v3(bbd->wanted_co, loc);
- bbd->wanted_speed = len_v3(bbd->wanted_co);
-
- ret = 1;
- }
- return ret;
+ KDTreeNearest_3d ptn[11];
+ float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f};
+ int neighbors = BLI_kdtree_3d_find_nearest_n_with_len_squared_cb(
+ bbd->sim->psys->tree,
+ pa->state.co,
+ ptn,
+ ARRAY_SIZE(ptn),
+ len_squared_v3v3_with_normal_bias,
+ pa->prev_state.ave);
+ int n;
+ int ret = 0;
+
+ if (neighbors > 1) {
+ for (n = 1; n < neighbors; n++) {
+ add_v3_v3(loc, bbd->sim->psys->particles[ptn[n].index].prev_state.co);
+ add_v3_v3(vec, bbd->sim->psys->particles[ptn[n].index].prev_state.vel);
+ }
+
+ mul_v3_fl(loc, 1.0f / ((float)neighbors - 1.0f));
+ mul_v3_fl(vec, 1.0f / ((float)neighbors - 1.0f));
+
+ sub_v3_v3(loc, pa->prev_state.co);
+ sub_v3_v3(vec, pa->prev_state.vel);
+
+ add_v3_v3(bbd->wanted_co, vec);
+ add_v3_v3(bbd->wanted_co, loc);
+ bbd->wanted_speed = len_v3(bbd->wanted_co);
+
+ ret = 1;
+ }
+ return ret;
}
-static int rule_follow_leader(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
+static int rule_follow_leader(BoidRule *rule,
+ BoidBrainData *bbd,
+ BoidValues *val,
+ ParticleData *pa)
{
- BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader*) rule;
- float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f};
- float mul, len;
- int n = (flbr->queue_size <= 1) ? bbd->sim->psys->totpart : flbr->queue_size;
- int i, ret = 0, p = pa - bbd->sim->psys->particles;
-
- if (flbr->ob) {
- float vec2[3], t;
-
- /* first check we're not blocking the leader */
- sub_v3_v3v3(vec, flbr->loc, flbr->oloc);
- mul_v3_fl(vec, 1.0f/bbd->timestep);
-
- sub_v3_v3v3(loc, pa->prev_state.co, flbr->oloc);
-
- mul = dot_v3v3(vec, vec);
-
- /* leader is not moving */
- if (mul < 0.01f) {
- len = len_v3(loc);
- /* too close to leader */
- if (len < 2.0f * val->personal_space * pa->size) {
- copy_v3_v3(bbd->wanted_co, loc);
- bbd->wanted_speed = val->max_speed;
- return 1;
- }
- }
- else {
- t = dot_v3v3(loc, vec)/mul;
-
- /* possible blocking of leader in near future */
- if (t > 0.0f && t < 3.0f) {
- copy_v3_v3(vec2, vec);
- mul_v3_fl(vec2, t);
-
- sub_v3_v3v3(vec2, loc, vec2);
-
- len = len_v3(vec2);
-
- if (len < 2.0f * val->personal_space * pa->size) {
- copy_v3_v3(bbd->wanted_co, vec2);
- bbd->wanted_speed = val->max_speed * (3.0f - t)/3.0f;
- return 1;
- }
- }
- }
-
- /* not blocking so try to follow leader */
- if (p && flbr->options & BRULE_LEADER_IN_LINE) {
- copy_v3_v3(vec, bbd->sim->psys->particles[p-1].prev_state.vel);
- copy_v3_v3(loc, bbd->sim->psys->particles[p-1].prev_state.co);
- }
- else {
- copy_v3_v3(loc, flbr->oloc);
- sub_v3_v3v3(vec, flbr->loc, flbr->oloc);
- mul_v3_fl(vec, 1.0f/bbd->timestep);
- }
-
- /* fac is seconds behind leader */
- madd_v3_v3fl(loc, vec, -flbr->distance);
-
- sub_v3_v3v3(bbd->wanted_co, loc, pa->prev_state.co);
- bbd->wanted_speed = len_v3(bbd->wanted_co);
-
- ret = 1;
- }
- else if (p % n) {
- float vec2[3], t, t_min = 3.0f;
-
- /* first check we're not blocking any leaders */
- for (i = 0; i< bbd->sim->psys->totpart; i+=n) {
- copy_v3_v3(vec, bbd->sim->psys->particles[i].prev_state.vel);
-
- sub_v3_v3v3(loc, pa->prev_state.co, bbd->sim->psys->particles[i].prev_state.co);
-
- mul = dot_v3v3(vec, vec);
-
- /* leader is not moving */
- if (mul < 0.01f) {
- len = len_v3(loc);
- /* too close to leader */
- if (len < 2.0f * val->personal_space * pa->size) {
- copy_v3_v3(bbd->wanted_co, loc);
- bbd->wanted_speed = val->max_speed;
- return 1;
- }
- }
- else {
- t = dot_v3v3(loc, vec)/mul;
-
- /* possible blocking of leader in near future */
- if (t > 0.0f && t < t_min) {
- copy_v3_v3(vec2, vec);
- mul_v3_fl(vec2, t);
-
- sub_v3_v3v3(vec2, loc, vec2);
-
- len = len_v3(vec2);
-
- if (len < 2.0f * val->personal_space * pa->size) {
- t_min = t;
- copy_v3_v3(bbd->wanted_co, loc);
- bbd->wanted_speed = val->max_speed * (3.0f - t)/3.0f;
- ret = 1;
- }
- }
- }
- }
-
- if (ret) return 1;
-
- /* not blocking so try to follow leader */
- if (flbr->options & BRULE_LEADER_IN_LINE) {
- copy_v3_v3(vec, bbd->sim->psys->particles[p-1].prev_state.vel);
- copy_v3_v3(loc, bbd->sim->psys->particles[p-1].prev_state.co);
- }
- else {
- copy_v3_v3(vec, bbd->sim->psys->particles[p - p%n].prev_state.vel);
- copy_v3_v3(loc, bbd->sim->psys->particles[p - p%n].prev_state.co);
- }
-
- /* fac is seconds behind leader */
- madd_v3_v3fl(loc, vec, -flbr->distance);
-
- sub_v3_v3v3(bbd->wanted_co, loc, pa->prev_state.co);
- bbd->wanted_speed = len_v3(bbd->wanted_co);
-
- ret = 1;
- }
-
- return ret;
+ BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader *)rule;
+ float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f};
+ float mul, len;
+ int n = (flbr->queue_size <= 1) ? bbd->sim->psys->totpart : flbr->queue_size;
+ int i, ret = 0, p = pa - bbd->sim->psys->particles;
+
+ if (flbr->ob) {
+ float vec2[3], t;
+
+ /* first check we're not blocking the leader */
+ sub_v3_v3v3(vec, flbr->loc, flbr->oloc);
+ mul_v3_fl(vec, 1.0f / bbd->timestep);
+
+ sub_v3_v3v3(loc, pa->prev_state.co, flbr->oloc);
+
+ mul = dot_v3v3(vec, vec);
+
+ /* leader is not moving */
+ if (mul < 0.01f) {
+ len = len_v3(loc);
+ /* too close to leader */
+ if (len < 2.0f * val->personal_space * pa->size) {
+ copy_v3_v3(bbd->wanted_co, loc);
+ bbd->wanted_speed = val->max_speed;
+ return 1;
+ }
+ }
+ else {
+ t = dot_v3v3(loc, vec) / mul;
+
+ /* possible blocking of leader in near future */
+ if (t > 0.0f && t < 3.0f) {
+ copy_v3_v3(vec2, vec);
+ mul_v3_fl(vec2, t);
+
+ sub_v3_v3v3(vec2, loc, vec2);
+
+ len = len_v3(vec2);
+
+ if (len < 2.0f * val->personal_space * pa->size) {
+ copy_v3_v3(bbd->wanted_co, vec2);
+ bbd->wanted_speed = val->max_speed * (3.0f - t) / 3.0f;
+ return 1;
+ }
+ }
+ }
+
+ /* not blocking so try to follow leader */
+ if (p && flbr->options & BRULE_LEADER_IN_LINE) {
+ copy_v3_v3(vec, bbd->sim->psys->particles[p - 1].prev_state.vel);
+ copy_v3_v3(loc, bbd->sim->psys->particles[p - 1].prev_state.co);
+ }
+ else {
+ copy_v3_v3(loc, flbr->oloc);
+ sub_v3_v3v3(vec, flbr->loc, flbr->oloc);
+ mul_v3_fl(vec, 1.0f / bbd->timestep);
+ }
+
+ /* fac is seconds behind leader */
+ madd_v3_v3fl(loc, vec, -flbr->distance);
+
+ sub_v3_v3v3(bbd->wanted_co, loc, pa->prev_state.co);
+ bbd->wanted_speed = len_v3(bbd->wanted_co);
+
+ ret = 1;
+ }
+ else if (p % n) {
+ float vec2[3], t, t_min = 3.0f;
+
+ /* first check we're not blocking any leaders */
+ for (i = 0; i < bbd->sim->psys->totpart; i += n) {
+ copy_v3_v3(vec, bbd->sim->psys->particles[i].prev_state.vel);
+
+ sub_v3_v3v3(loc, pa->prev_state.co, bbd->sim->psys->particles[i].prev_state.co);
+
+ mul = dot_v3v3(vec, vec);
+
+ /* leader is not moving */
+ if (mul < 0.01f) {
+ len = len_v3(loc);
+ /* too close to leader */
+ if (len < 2.0f * val->personal_space * pa->size) {
+ copy_v3_v3(bbd->wanted_co, loc);
+ bbd->wanted_speed = val->max_speed;
+ return 1;
+ }
+ }
+ else {
+ t = dot_v3v3(loc, vec) / mul;
+
+ /* possible blocking of leader in near future */
+ if (t > 0.0f && t < t_min) {
+ copy_v3_v3(vec2, vec);
+ mul_v3_fl(vec2, t);
+
+ sub_v3_v3v3(vec2, loc, vec2);
+
+ len = len_v3(vec2);
+
+ if (len < 2.0f * val->personal_space * pa->size) {
+ t_min = t;
+ copy_v3_v3(bbd->wanted_co, loc);
+ bbd->wanted_speed = val->max_speed * (3.0f - t) / 3.0f;
+ ret = 1;
+ }
+ }
+ }
+ }
+
+ if (ret)
+ return 1;
+
+ /* not blocking so try to follow leader */
+ if (flbr->options & BRULE_LEADER_IN_LINE) {
+ copy_v3_v3(vec, bbd->sim->psys->particles[p - 1].prev_state.vel);
+ copy_v3_v3(loc, bbd->sim->psys->particles[p - 1].prev_state.co);
+ }
+ else {
+ copy_v3_v3(vec, bbd->sim->psys->particles[p - p % n].prev_state.vel);
+ copy_v3_v3(loc, bbd->sim->psys->particles[p - p % n].prev_state.co);
+ }
+
+ /* fac is seconds behind leader */
+ madd_v3_v3fl(loc, vec, -flbr->distance);
+
+ sub_v3_v3v3(bbd->wanted_co, loc, pa->prev_state.co);
+ bbd->wanted_speed = len_v3(bbd->wanted_co);
+
+ ret = 1;
+ }
+
+ return ret;
}
-static int rule_average_speed(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
+static int rule_average_speed(BoidRule *rule,
+ BoidBrainData *bbd,
+ BoidValues *val,
+ ParticleData *pa)
{
- BoidParticle *bpa = pa->boid;
- BoidRuleAverageSpeed *asbr = (BoidRuleAverageSpeed*)rule;
- float vec[3] = {0.0f, 0.0f, 0.0f};
-
- if (asbr->wander > 0.0f) {
- /* abuse pa->r_ave for wandering */
- bpa->wander[0] += asbr->wander * (-1.0f + 2.0f * BLI_rng_get_float(bbd->rng));
- bpa->wander[1] += asbr->wander * (-1.0f + 2.0f * BLI_rng_get_float(bbd->rng));
- bpa->wander[2] += asbr->wander * (-1.0f + 2.0f * BLI_rng_get_float(bbd->rng));
-
- normalize_v3(bpa->wander);
-
- copy_v3_v3(vec, bpa->wander);
-
- mul_qt_v3(pa->prev_state.rot, vec);
-
- copy_v3_v3(bbd->wanted_co, pa->prev_state.ave);
-
- mul_v3_fl(bbd->wanted_co, 1.1f);
-
- add_v3_v3(bbd->wanted_co, vec);
-
- /* leveling */
- if (asbr->level > 0.0f && psys_uses_gravity(bbd->sim)) {
- project_v3_v3v3(vec, bbd->wanted_co, bbd->sim->scene->physics_settings.gravity);
- mul_v3_fl(vec, asbr->level);
- sub_v3_v3(bbd->wanted_co, vec);
- }
- }
- else {
- copy_v3_v3(bbd->wanted_co, pa->prev_state.ave);
-
- /* may happen at birth */
- if (dot_v2v2(bbd->wanted_co, bbd->wanted_co)==0.0f) {
- bbd->wanted_co[0] = 2.0f*(0.5f - BLI_rng_get_float(bbd->rng));
- bbd->wanted_co[1] = 2.0f*(0.5f - BLI_rng_get_float(bbd->rng));
- bbd->wanted_co[2] = 2.0f*(0.5f - BLI_rng_get_float(bbd->rng));
- }
-
- /* leveling */
- if (asbr->level > 0.0f && psys_uses_gravity(bbd->sim)) {
- project_v3_v3v3(vec, bbd->wanted_co, bbd->sim->scene->physics_settings.gravity);
- mul_v3_fl(vec, asbr->level);
- sub_v3_v3(bbd->wanted_co, vec);
- }
-
- }
- bbd->wanted_speed = asbr->speed * val->max_speed;
-
- return 1;
+ BoidParticle *bpa = pa->boid;
+ BoidRuleAverageSpeed *asbr = (BoidRuleAverageSpeed *)rule;
+ float vec[3] = {0.0f, 0.0f, 0.0f};
+
+ if (asbr->wander > 0.0f) {
+ /* abuse pa->r_ave for wandering */
+ bpa->wander[0] += asbr->wander * (-1.0f + 2.0f * BLI_rng_get_float(bbd->rng));
+ bpa->wander[1] += asbr->wander * (-1.0f + 2.0f * BLI_rng_get_float(bbd->rng));
+ bpa->wander[2] += asbr->wander * (-1.0f + 2.0f * BLI_rng_get_float(bbd->rng));
+
+ normalize_v3(bpa->wander);
+
+ copy_v3_v3(vec, bpa->wander);
+
+ mul_qt_v3(pa->prev_state.rot, vec);
+
+ copy_v3_v3(bbd->wanted_co, pa->prev_state.ave);
+
+ mul_v3_fl(bbd->wanted_co, 1.1f);
+
+ add_v3_v3(bbd->wanted_co, vec);
+
+ /* leveling */
+ if (asbr->level > 0.0f && psys_uses_gravity(bbd->sim)) {
+ project_v3_v3v3(vec, bbd->wanted_co, bbd->sim->scene->physics_settings.gravity);
+ mul_v3_fl(vec, asbr->level);
+ sub_v3_v3(bbd->wanted_co, vec);
+ }
+ }
+ else {
+ copy_v3_v3(bbd->wanted_co, pa->prev_state.ave);
+
+ /* may happen at birth */
+ if (dot_v2v2(bbd->wanted_co, bbd->wanted_co) == 0.0f) {
+ bbd->wanted_co[0] = 2.0f * (0.5f - BLI_rng_get_float(bbd->rng));
+ bbd->wanted_co[1] = 2.0f * (0.5f - BLI_rng_get_float(bbd->rng));
+ bbd->wanted_co[2] = 2.0f * (0.5f - BLI_rng_get_float(bbd->rng));
+ }
+
+ /* leveling */
+ if (asbr->level > 0.0f && psys_uses_gravity(bbd->sim)) {
+ project_v3_v3v3(vec, bbd->wanted_co, bbd->sim->scene->physics_settings.gravity);
+ mul_v3_fl(vec, asbr->level);
+ sub_v3_v3(bbd->wanted_co, vec);
+ }
+ }
+ bbd->wanted_speed = asbr->speed * val->max_speed;
+
+ return 1;
}
static int rule_fight(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
{
- BoidRuleFight *fbr = (BoidRuleFight*)rule;
- KDTreeNearest_3d *ptn = NULL;
- ParticleTarget *pt;
- ParticleData *epars;
- ParticleData *enemy_pa = NULL;
- BoidParticle *bpa;
- /* friends & enemies */
- float closest_enemy[3] = {0.0f, 0.0f, 0.0f};
- float closest_dist = fbr->distance + 1.0f;
- float f_strength = 0.0f, e_strength = 0.0f;
- float health = 0.0f;
- int n, ret = 0;
-
- /* calculate own group strength */
- int neighbors = BLI_kdtree_3d_range_search(
- bbd->sim->psys->tree, pa->prev_state.co,
- &ptn, fbr->distance);
- for (n=0; n<neighbors; n++) {
- bpa = bbd->sim->psys->particles[ptn[n].index].boid;
- health += bpa->data.health;
- }
-
- f_strength += bbd->part->boids->strength * health;
-
- if (ptn) { MEM_freeN(ptn); ptn=NULL; }
-
- /* add other friendlies and calculate enemy strength and find closest enemy */
- for (pt=bbd->sim->psys->targets.first; pt; pt=pt->next) {
- ParticleSystem *epsys = psys_get_target_system(bbd->sim->ob, pt);
- if (epsys) {
- epars = epsys->particles;
-
- neighbors = BLI_kdtree_3d_range_search(
- epsys->tree, pa->prev_state.co,
- &ptn, fbr->distance);
-
- health = 0.0f;
-
- for (n=0; n<neighbors; n++) {
- bpa = epars[ptn[n].index].boid;
- health += bpa->data.health;
-
- if (n==0 && pt->mode==PTARGET_MODE_ENEMY && ptn[n].dist < closest_dist) {
- copy_v3_v3(closest_enemy, ptn[n].co);
- closest_dist = ptn[n].dist;
- enemy_pa = epars + ptn[n].index;
- }
- }
- if (pt->mode==PTARGET_MODE_ENEMY)
- e_strength += epsys->part->boids->strength * health;
- else if (pt->mode==PTARGET_MODE_FRIEND)
- f_strength += epsys->part->boids->strength * health;
-
- if (ptn) { MEM_freeN(ptn); ptn=NULL; }
- }
- }
- /* decide action if enemy presence found */
- if (e_strength > 0.0f) {
- sub_v3_v3v3(bbd->wanted_co, closest_enemy, pa->prev_state.co);
-
- /* attack if in range */
- if (closest_dist <= bbd->part->boids->range + pa->size + enemy_pa->size) {
- float damage = BLI_rng_get_float(bbd->rng);
- float enemy_dir[3];
-
- normalize_v3_v3(enemy_dir, bbd->wanted_co);
-
- /* fight mode */
- bbd->wanted_speed = 0.0f;
-
- /* must face enemy to fight */
- if (dot_v3v3(pa->prev_state.ave, enemy_dir)>0.5f) {
- bpa = enemy_pa->boid;
- bpa->data.health -= bbd->part->boids->strength * bbd->timestep * ((1.0f-bbd->part->boids->accuracy)*damage + bbd->part->boids->accuracy);
- }
- }
- else {
- /* approach mode */
- bbd->wanted_speed = val->max_speed;
- }
-
- /* check if boid doesn't want to fight */
- bpa = pa->boid;
- if (bpa->data.health/bbd->part->boids->health * bbd->part->boids->aggression < e_strength / f_strength) {
- /* decide to flee */
- if (closest_dist < fbr->flee_distance * fbr->distance) {
- negate_v3(bbd->wanted_co);
- bbd->wanted_speed = val->max_speed;
- }
- else { /* wait for better odds */
- bbd->wanted_speed = 0.0f;
- }
- }
-
- ret = 1;
- }
-
- return ret;
+ BoidRuleFight *fbr = (BoidRuleFight *)rule;
+ KDTreeNearest_3d *ptn = NULL;
+ ParticleTarget *pt;
+ ParticleData *epars;
+ ParticleData *enemy_pa = NULL;
+ BoidParticle *bpa;
+ /* friends & enemies */
+ float closest_enemy[3] = {0.0f, 0.0f, 0.0f};
+ float closest_dist = fbr->distance + 1.0f;
+ float f_strength = 0.0f, e_strength = 0.0f;
+ float health = 0.0f;
+ int n, ret = 0;
+
+ /* calculate own group strength */
+ int neighbors = BLI_kdtree_3d_range_search(
+ bbd->sim->psys->tree, pa->prev_state.co, &ptn, fbr->distance);
+ for (n = 0; n < neighbors; n++) {
+ bpa = bbd->sim->psys->particles[ptn[n].index].boid;
+ health += bpa->data.health;
+ }
+
+ f_strength += bbd->part->boids->strength * health;
+
+ if (ptn) {
+ MEM_freeN(ptn);
+ ptn = NULL;
+ }
+
+ /* add other friendlies and calculate enemy strength and find closest enemy */
+ for (pt = bbd->sim->psys->targets.first; pt; pt = pt->next) {
+ ParticleSystem *epsys = psys_get_target_system(bbd->sim->ob, pt);
+ if (epsys) {
+ epars = epsys->particles;
+
+ neighbors = BLI_kdtree_3d_range_search(epsys->tree, pa->prev_state.co, &ptn, fbr->distance);
+
+ health = 0.0f;
+
+ for (n = 0; n < neighbors; n++) {
+ bpa = epars[ptn[n].index].boid;
+ health += bpa->data.health;
+
+ if (n == 0 && pt->mode == PTARGET_MODE_ENEMY && ptn[n].dist < closest_dist) {
+ copy_v3_v3(closest_enemy, ptn[n].co);
+ closest_dist = ptn[n].dist;
+ enemy_pa = epars + ptn[n].index;
+ }
+ }
+ if (pt->mode == PTARGET_MODE_ENEMY)
+ e_strength += epsys->part->boids->strength * health;
+ else if (pt->mode == PTARGET_MODE_FRIEND)
+ f_strength += epsys->part->boids->strength * health;
+
+ if (ptn) {
+ MEM_freeN(ptn);
+ ptn = NULL;
+ }
+ }
+ }
+ /* decide action if enemy presence found */
+ if (e_strength > 0.0f) {
+ sub_v3_v3v3(bbd->wanted_co, closest_enemy, pa->prev_state.co);
+
+ /* attack if in range */
+ if (closest_dist <= bbd->part->boids->range + pa->size + enemy_pa->size) {
+ float damage = BLI_rng_get_float(bbd->rng);
+ float enemy_dir[3];
+
+ normalize_v3_v3(enemy_dir, bbd->wanted_co);
+
+ /* fight mode */
+ bbd->wanted_speed = 0.0f;
+
+ /* must face enemy to fight */
+ if (dot_v3v3(pa->prev_state.ave, enemy_dir) > 0.5f) {
+ bpa = enemy_pa->boid;
+ bpa->data.health -= bbd->part->boids->strength * bbd->timestep *
+ ((1.0f - bbd->part->boids->accuracy) * damage +
+ bbd->part->boids->accuracy);
+ }
+ }
+ else {
+ /* approach mode */
+ bbd->wanted_speed = val->max_speed;
+ }
+
+ /* check if boid doesn't want to fight */
+ bpa = pa->boid;
+ if (bpa->data.health / bbd->part->boids->health * bbd->part->boids->aggression <
+ e_strength / f_strength) {
+ /* decide to flee */
+ if (closest_dist < fbr->flee_distance * fbr->distance) {
+ negate_v3(bbd->wanted_co);
+ bbd->wanted_speed = val->max_speed;
+ }
+ else { /* wait for better odds */
+ bbd->wanted_speed = 0.0f;
+ }
+ }
+
+ ret = 1;
+ }
+
+ return ret;
}
-typedef int (*boid_rule_cb)(BoidRule *rule, BoidBrainData *data, BoidValues *val, ParticleData *pa);
+typedef int (*boid_rule_cb)(BoidRule *rule,
+ BoidBrainData *data,
+ BoidValues *val,
+ ParticleData *pa);
static boid_rule_cb boid_rules[] = {
- rule_none,
- rule_goal_avoid,
- rule_goal_avoid,
- rule_avoid_collision,
- rule_separate,
- rule_flock,
- rule_follow_leader,
- rule_average_speed,
- rule_fight,
- //rule_help,
- //rule_protect,
- //rule_hide,
- //rule_follow_path,
- //rule_follow_wall,
+ rule_none,
+ rule_goal_avoid,
+ rule_goal_avoid,
+ rule_avoid_collision,
+ rule_separate,
+ rule_flock,
+ rule_follow_leader,
+ rule_average_speed,
+ rule_fight,
+ //rule_help,
+ //rule_protect,
+ //rule_hide,
+ //rule_follow_path,
+ //rule_follow_wall,
};
static void set_boid_values(BoidValues *val, BoidSettings *boids, ParticleData *pa)
{
- BoidParticle *bpa = pa->boid;
-
- if (ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)) {
- val->max_speed = boids->land_max_speed * bpa->data.health/boids->health;
- val->max_acc = boids->land_max_acc * val->max_speed;
- val->max_ave = boids->land_max_ave * (float)M_PI * bpa->data.health/boids->health;
- val->min_speed = 0.0f; /* no minimum speed on land */
- val->personal_space = boids->land_personal_space;
- val->jump_speed = boids->land_jump_speed * bpa->data.health/boids->health;
- }
- else {
- val->max_speed = boids->air_max_speed * bpa->data.health/boids->health;
- val->max_acc = boids->air_max_acc * val->max_speed;
- val->max_ave = boids->air_max_ave * (float)M_PI * bpa->data.health/boids->health;
- val->min_speed = boids->air_min_speed * boids->air_max_speed;
- val->personal_space = boids->air_personal_space;
- val->jump_speed = 0.0f; /* no jumping in air */
- }
+ BoidParticle *bpa = pa->boid;
+
+ if (ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)) {
+ val->max_speed = boids->land_max_speed * bpa->data.health / boids->health;
+ val->max_acc = boids->land_max_acc * val->max_speed;
+ val->max_ave = boids->land_max_ave * (float)M_PI * bpa->data.health / boids->health;
+ val->min_speed = 0.0f; /* no minimum speed on land */
+ val->personal_space = boids->land_personal_space;
+ val->jump_speed = boids->land_jump_speed * bpa->data.health / boids->health;
+ }
+ else {
+ val->max_speed = boids->air_max_speed * bpa->data.health / boids->health;
+ val->max_acc = boids->air_max_acc * val->max_speed;
+ val->max_ave = boids->air_max_ave * (float)M_PI * bpa->data.health / boids->health;
+ val->min_speed = boids->air_min_speed * boids->air_max_speed;
+ val->personal_space = boids->air_personal_space;
+ val->jump_speed = 0.0f; /* no jumping in air */
+ }
}
-static Object *boid_find_ground(BoidBrainData *bbd, ParticleData *pa, float ground_co[3], float ground_nor[3])
+static Object *boid_find_ground(BoidBrainData *bbd,
+ ParticleData *pa,
+ float ground_co[3],
+ float ground_nor[3])
{
- const int raycast_flag = BVH_RAYCAST_DEFAULT & ~(BVH_RAYCAST_WATERTIGHT);
- BoidParticle *bpa = pa->boid;
-
- if (bpa->data.mode == eBoidMode_Climbing) {
- SurfaceModifierData *surmd = NULL;
- float x[3], v[3];
-
- surmd = (SurfaceModifierData *)modifiers_findByType(bpa->ground, eModifierType_Surface );
-
- /* take surface velocity into account */
- closest_point_on_surface(surmd, pa->state.co, x, NULL, v);
- add_v3_v3(x, v);
-
- /* get actual position on surface */
- closest_point_on_surface(surmd, x, ground_co, ground_nor, NULL);
-
- return bpa->ground;
- }
- else {
- float zvec[3] = {0.0f, 0.0f, 2000.0f};
- ParticleCollision col;
- ColliderCache *coll;
- BVHTreeRayHit hit;
- float radius = 0.0f, t, ray_dir[3];
-
- if (!bbd->sim->colliders)
- return NULL;
-
- memset(&col, 0, sizeof(ParticleCollision));
-
- /* first try to find below boid */
- copy_v3_v3(col.co1, pa->state.co);
- sub_v3_v3v3(col.co2, pa->state.co, zvec);
- sub_v3_v3v3(ray_dir, col.co2, col.co1);
- col.f = 0.0f;
- hit.index = -1;
- hit.dist = col.original_ray_length = normalize_v3(ray_dir);
- col.pce.inside = 0;
-
- for (coll = bbd->sim->colliders->first; coll; coll = coll->next) {
- col.current = coll->ob;
- col.md = coll->collmd;
- col.fac1 = col.fac2 = 0.f;
-
- if (col.md && col.md->bvhtree) {
- BLI_bvhtree_ray_cast_ex(
- col.md->bvhtree, col.co1, ray_dir, radius, &hit,
- BKE_psys_collision_neartest_cb, &col, raycast_flag);
- }
- }
- /* then use that object */
- if (hit.index>=0) {
- t = hit.dist/col.original_ray_length;
- interp_v3_v3v3(ground_co, col.co1, col.co2, t);
- normalize_v3_v3(ground_nor, col.pce.nor);
- return col.hit;
- }
-
- /* couldn't find below, so find upmost deflector object */
- add_v3_v3v3(col.co1, pa->state.co, zvec);
- sub_v3_v3v3(col.co2, pa->state.co, zvec);
- sub_v3_v3(col.co2, zvec);
- sub_v3_v3v3(ray_dir, col.co2, col.co1);
- col.f = 0.0f;
- hit.index = -1;
- hit.dist = col.original_ray_length = normalize_v3(ray_dir);
-
- for (coll = bbd->sim->colliders->first; coll; coll = coll->next) {
- col.current = coll->ob;
- col.md = coll->collmd;
-
- if (col.md && col.md->bvhtree) {
- BLI_bvhtree_ray_cast_ex(
- col.md->bvhtree, col.co1, ray_dir, radius, &hit,
- BKE_psys_collision_neartest_cb, &col, raycast_flag);
- }
- }
- /* then use that object */
- if (hit.index>=0) {
- t = hit.dist/col.original_ray_length;
- interp_v3_v3v3(ground_co, col.co1, col.co2, t);
- normalize_v3_v3(ground_nor, col.pce.nor);
- return col.hit;
- }
-
- /* default to z=0 */
- copy_v3_v3(ground_co, pa->state.co);
- ground_co[2] = 0;
- ground_nor[0] = ground_nor[1] = 0.0f;
- ground_nor[2] = 1.0f;
- return NULL;
- }
+ const int raycast_flag = BVH_RAYCAST_DEFAULT & ~(BVH_RAYCAST_WATERTIGHT);
+ BoidParticle *bpa = pa->boid;
+
+ if (bpa->data.mode == eBoidMode_Climbing) {
+ SurfaceModifierData *surmd = NULL;
+ float x[3], v[3];
+
+ surmd = (SurfaceModifierData *)modifiers_findByType(bpa->ground, eModifierType_Surface);
+
+ /* take surface velocity into account */
+ closest_point_on_surface(surmd, pa->state.co, x, NULL, v);
+ add_v3_v3(x, v);
+
+ /* get actual position on surface */
+ closest_point_on_surface(surmd, x, ground_co, ground_nor, NULL);
+
+ return bpa->ground;
+ }
+ else {
+ float zvec[3] = {0.0f, 0.0f, 2000.0f};
+ ParticleCollision col;
+ ColliderCache *coll;
+ BVHTreeRayHit hit;
+ float radius = 0.0f, t, ray_dir[3];
+
+ if (!bbd->sim->colliders)
+ return NULL;
+
+ memset(&col, 0, sizeof(ParticleCollision));
+
+ /* first try to find below boid */
+ copy_v3_v3(col.co1, pa->state.co);
+ sub_v3_v3v3(col.co2, pa->state.co, zvec);
+ sub_v3_v3v3(ray_dir, col.co2, col.co1);
+ col.f = 0.0f;
+ hit.index = -1;
+ hit.dist = col.original_ray_length = normalize_v3(ray_dir);
+ col.pce.inside = 0;
+
+ for (coll = bbd->sim->colliders->first; coll; coll = coll->next) {
+ col.current = coll->ob;
+ col.md = coll->collmd;
+ col.fac1 = col.fac2 = 0.f;
+
+ if (col.md && col.md->bvhtree) {
+ BLI_bvhtree_ray_cast_ex(col.md->bvhtree,
+ col.co1,
+ ray_dir,
+ radius,
+ &hit,
+ BKE_psys_collision_neartest_cb,
+ &col,
+ raycast_flag);
+ }
+ }
+ /* then use that object */
+ if (hit.index >= 0) {
+ t = hit.dist / col.original_ray_length;
+ interp_v3_v3v3(ground_co, col.co1, col.co2, t);
+ normalize_v3_v3(ground_nor, col.pce.nor);
+ return col.hit;
+ }
+
+ /* couldn't find below, so find upmost deflector object */
+ add_v3_v3v3(col.co1, pa->state.co, zvec);
+ sub_v3_v3v3(col.co2, pa->state.co, zvec);
+ sub_v3_v3(col.co2, zvec);
+ sub_v3_v3v3(ray_dir, col.co2, col.co1);
+ col.f = 0.0f;
+ hit.index = -1;
+ hit.dist = col.original_ray_length = normalize_v3(ray_dir);
+
+ for (coll = bbd->sim->colliders->first; coll; coll = coll->next) {
+ col.current = coll->ob;
+ col.md = coll->collmd;
+
+ if (col.md && col.md->bvhtree) {
+ BLI_bvhtree_ray_cast_ex(col.md->bvhtree,
+ col.co1,
+ ray_dir,
+ radius,
+ &hit,
+ BKE_psys_collision_neartest_cb,
+ &col,
+ raycast_flag);
+ }
+ }
+ /* then use that object */
+ if (hit.index >= 0) {
+ t = hit.dist / col.original_ray_length;
+ interp_v3_v3v3(ground_co, col.co1, col.co2, t);
+ normalize_v3_v3(ground_nor, col.pce.nor);
+ return col.hit;
+ }
+
+ /* default to z=0 */
+ copy_v3_v3(ground_co, pa->state.co);
+ ground_co[2] = 0;
+ ground_nor[0] = ground_nor[1] = 0.0f;
+ ground_nor[2] = 1.0f;
+ return NULL;
+ }
}
static int boid_rule_applies(ParticleData *pa, BoidSettings *UNUSED(boids), BoidRule *rule)
{
- BoidParticle *bpa = pa->boid;
+ BoidParticle *bpa = pa->boid;
- if (rule==NULL)
- return 0;
+ if (rule == NULL)
+ return 0;
- if (ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing) && rule->flag & BOIDRULE_ON_LAND)
- return 1;
+ if (ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing) && rule->flag & BOIDRULE_ON_LAND)
+ return 1;
- if (bpa->data.mode==eBoidMode_InAir && rule->flag & BOIDRULE_IN_AIR)
- return 1;
+ if (bpa->data.mode == eBoidMode_InAir && rule->flag & BOIDRULE_IN_AIR)
+ return 1;
- return 0;
+ return 0;
}
void boids_precalc_rules(ParticleSettings *part, float cfra)
{
- BoidState *state = part->boids->states.first;
- BoidRule *rule;
- for (; state; state=state->next) {
- for (rule = state->rules.first; rule; rule=rule->next) {
- if (rule->type==eBoidRuleType_FollowLeader) {
- BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader*) rule;
-
- if (flbr->ob && flbr->cfra != cfra) {
- /* save object locations for velocity calculations */
- copy_v3_v3(flbr->oloc, flbr->loc);
- copy_v3_v3(flbr->loc, flbr->ob->obmat[3]);
- flbr->cfra = cfra;
- }
- }
- }
- }
+ BoidState *state = part->boids->states.first;
+ BoidRule *rule;
+ for (; state; state = state->next) {
+ for (rule = state->rules.first; rule; rule = rule->next) {
+ if (rule->type == eBoidRuleType_FollowLeader) {
+ BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader *)rule;
+
+ if (flbr->ob && flbr->cfra != cfra) {
+ /* save object locations for velocity calculations */
+ copy_v3_v3(flbr->oloc, flbr->loc);
+ copy_v3_v3(flbr->loc, flbr->ob->obmat[3]);
+ flbr->cfra = cfra;
+ }
+ }
+ }
+ }
}
-static void boid_climb(BoidSettings *boids, ParticleData *pa, float *surface_co, float *surface_nor)
+static void boid_climb(BoidSettings *boids,
+ ParticleData *pa,
+ float *surface_co,
+ float *surface_nor)
{
- BoidParticle *bpa = pa->boid;
- float nor[3], vel[3];
- copy_v3_v3(nor, surface_nor);
+ BoidParticle *bpa = pa->boid;
+ float nor[3], vel[3];
+ copy_v3_v3(nor, surface_nor);
- /* gather apparent gravity */
- madd_v3_v3fl(bpa->gravity, surface_nor, -1.0f);
- normalize_v3(bpa->gravity);
+ /* gather apparent gravity */
+ madd_v3_v3fl(bpa->gravity, surface_nor, -1.0f);
+ normalize_v3(bpa->gravity);
- /* raise boid it's size from surface */
- mul_v3_fl(nor, pa->size * boids->height);
- add_v3_v3v3(pa->state.co, surface_co, nor);
+ /* raise boid it's size from surface */
+ mul_v3_fl(nor, pa->size * boids->height);
+ add_v3_v3v3(pa->state.co, surface_co, nor);
- /* remove normal component from velocity */
- project_v3_v3v3(vel, pa->state.vel, surface_nor);
- sub_v3_v3v3(pa->state.vel, pa->state.vel, vel);
+ /* remove normal component from velocity */
+ project_v3_v3v3(vel, pa->state.vel, surface_nor);
+ sub_v3_v3v3(pa->state.vel, pa->state.vel, vel);
}
static float boid_goal_signed_dist(float *boid_co, float *goal_co, float *goal_nor)
{
- float vec[3];
+ float vec[3];
- sub_v3_v3v3(vec, boid_co, goal_co);
+ sub_v3_v3v3(vec, boid_co, goal_co);
- return dot_v3v3(vec, goal_nor);
+ return dot_v3v3(vec, goal_nor);
}
/* wanted_co is relative to boid location */
-static int apply_boid_rule(BoidBrainData *bbd, BoidRule *rule, BoidValues *val, ParticleData *pa, float fuzziness)
+static int apply_boid_rule(
+ BoidBrainData *bbd, BoidRule *rule, BoidValues *val, ParticleData *pa, float fuzziness)
{
- if (rule==NULL)
- return 0;
+ if (rule == NULL)
+ return 0;
- if (boid_rule_applies(pa, bbd->part->boids, rule)==0)
- return 0;
+ if (boid_rule_applies(pa, bbd->part->boids, rule) == 0)
+ return 0;
- if (boid_rules[rule->type](rule, bbd, val, pa)==0)
- return 0;
+ if (boid_rules[rule->type](rule, bbd, val, pa) == 0)
+ return 0;
- if (fuzziness < 0.0f || compare_len_v3v3(bbd->wanted_co, pa->prev_state.vel, fuzziness * len_v3(pa->prev_state.vel))==0)
- return 1;
- else
- return 0;
+ if (fuzziness < 0.0f || compare_len_v3v3(bbd->wanted_co,
+ pa->prev_state.vel,
+ fuzziness * len_v3(pa->prev_state.vel)) == 0)
+ return 1;
+ else
+ return 0;
}
static BoidState *get_boid_state(BoidSettings *boids, ParticleData *pa)
{
- BoidState *state = boids->states.first;
- BoidParticle *bpa = pa->boid;
+ BoidState *state = boids->states.first;
+ BoidParticle *bpa = pa->boid;
- for (; state; state=state->next) {
- if (state->id==bpa->data.state_id)
- return state;
- }
+ for (; state; state = state->next) {
+ if (state->id == bpa->data.state_id)
+ return state;
+ }
- /* for some reason particle isn't at a valid state */
- state = boids->states.first;
- if (state)
- bpa->data.state_id = state->id;
+ /* for some reason particle isn't at a valid state */
+ state = boids->states.first;
+ if (state)
+ bpa->data.state_id = state->id;
- return state;
+ return state;
}
//static int boid_condition_is_true(BoidCondition *cond)
//{
-// /* TODO */
-// return 0;
+// /* TODO */
+// return 0;
//}
/* determines the velocity the boid wants to have */
void boid_brain(BoidBrainData *bbd, int p, ParticleData *pa)
{
- BoidRule *rule;
- BoidSettings *boids = bbd->part->boids;
- BoidValues val;
- BoidState *state = get_boid_state(boids, pa);
- BoidParticle *bpa = pa->boid;
- ParticleSystem *psys = bbd->sim->psys;
- int rand;
- //BoidCondition *cond;
-
- if (bpa->data.health <= 0.0f) {
- pa->alive = PARS_DYING;
- pa->dietime = bbd->cfra;
- return;
- }
-
- //planned for near future
- //cond = state->conditions.first;
- //for (; cond; cond=cond->next) {
- // if (boid_condition_is_true(cond)) {
- // pa->boid->state_id = cond->state_id;
- // state = get_boid_state(boids, pa);
- // break; /* only first true condition is used */
- // }
- //}
-
- zero_v3(bbd->wanted_co);
- bbd->wanted_speed = 0.0f;
-
- /* create random seed for every particle & frame */
- rand = (int)(psys_frand(psys, psys->seed + p) * 1000);
- rand = (int)(psys_frand(psys, (int)bbd->cfra + rand) * 1000);
-
- set_boid_values(&val, bbd->part->boids, pa);
-
- /* go through rules */
- switch (state->ruleset_type) {
- case eBoidRulesetType_Fuzzy:
- {
- for (rule = state->rules.first; rule; rule = rule->next) {
- if (apply_boid_rule(bbd, rule, &val, pa, state->rule_fuzziness))
- break; /* only first nonzero rule that comes through fuzzy rule is applied */
- }
- break;
- }
- case eBoidRulesetType_Random:
- {
- /* use random rule for each particle (always same for same particle though) */
- const int n = BLI_listbase_count(&state->rules);
- if (n) {
- rule = BLI_findlink(&state->rules, rand % n);
- apply_boid_rule(bbd, rule, &val, pa, -1.0);
- }
- break;
- }
- case eBoidRulesetType_Average:
- {
- float wanted_co[3] = {0.0f, 0.0f, 0.0f}, wanted_speed = 0.0f;
- int n = 0;
- for (rule = state->rules.first; rule; rule=rule->next) {
- if (apply_boid_rule(bbd, rule, &val, pa, -1.0f)) {
- add_v3_v3(wanted_co, bbd->wanted_co);
- wanted_speed += bbd->wanted_speed;
- n++;
- zero_v3(bbd->wanted_co);
- bbd->wanted_speed = 0.0f;
- }
- }
-
- if (n > 1) {
- mul_v3_fl(wanted_co, 1.0f/(float)n);
- wanted_speed /= (float)n;
- }
-
- copy_v3_v3(bbd->wanted_co, wanted_co);
- bbd->wanted_speed = wanted_speed;
- break;
- }
-
- }
-
- /* decide on jumping & liftoff */
- if (bpa->data.mode == eBoidMode_OnLand) {
- /* fuzziness makes boids capable of misjudgement */
- float mul = 1.0f + state->rule_fuzziness;
-
- if (boids->options & BOID_ALLOW_FLIGHT && bbd->wanted_co[2] > 0.0f) {
- float cvel[3], dir[3];
-
- copy_v3_v3(dir, pa->prev_state.ave);
- normalize_v2(dir);
-
- copy_v3_v3(cvel, bbd->wanted_co);
- normalize_v2(cvel);
-
- if (dot_v2v2(cvel, dir) > 0.95f / mul)
- bpa->data.mode = eBoidMode_Liftoff;
- }
- else if (val.jump_speed > 0.0f) {
- float jump_v[3];
- int jump = 0;
-
- /* jump to get to a location */
- if (bbd->wanted_co[2] > 0.0f) {
- float cvel[3], dir[3];
- float z_v, ground_v, cur_v;
- float len;
-
- copy_v3_v3(dir, pa->prev_state.ave);
- normalize_v2(dir);
-
- copy_v3_v3(cvel, bbd->wanted_co);
- normalize_v2(cvel);
-
- len = len_v2(pa->prev_state.vel);
-
- /* first of all, are we going in a suitable direction? */
- /* or at a suitably slow speed */
- if (dot_v2v2(cvel, dir) > 0.95f / mul || len <= state->rule_fuzziness) {
- /* try to reach goal at highest point of the parabolic path */
- cur_v = len_v2(pa->prev_state.vel);
- z_v = sasqrt(-2.0f * bbd->sim->scene->physics_settings.gravity[2] * bbd->wanted_co[2]);
- ground_v = len_v2(bbd->wanted_co)*sasqrt(-0.5f * bbd->sim->scene->physics_settings.gravity[2] / bbd->wanted_co[2]);
-
- len = sasqrt((ground_v-cur_v)*(ground_v-cur_v) + z_v*z_v);
-
- if (len < val.jump_speed * mul || bbd->part->boids->options & BOID_ALLOW_FLIGHT) {
- jump = 1;
-
- len = MIN2(len, val.jump_speed);
-
- copy_v3_v3(jump_v, dir);
- jump_v[2] = z_v;
- mul_v3_fl(jump_v, ground_v);
-
- normalize_v3(jump_v);
- mul_v3_fl(jump_v, len);
- add_v2_v2v2(jump_v, jump_v, pa->prev_state.vel);
- }
- }
- }
-
- /* jump to go faster */
- if (jump == 0 && val.jump_speed > val.max_speed && bbd->wanted_speed > val.max_speed) {
- /* pass */
- }
-
- if (jump) {
- copy_v3_v3(pa->prev_state.vel, jump_v);
- bpa->data.mode = eBoidMode_Falling;
- }
- }
- }
+ BoidRule *rule;
+ BoidSettings *boids = bbd->part->boids;
+ BoidValues val;
+ BoidState *state = get_boid_state(boids, pa);
+ BoidParticle *bpa = pa->boid;
+ ParticleSystem *psys = bbd->sim->psys;
+ int rand;
+ //BoidCondition *cond;
+
+ if (bpa->data.health <= 0.0f) {
+ pa->alive = PARS_DYING;
+ pa->dietime = bbd->cfra;
+ return;
+ }
+
+ //planned for near future
+ //cond = state->conditions.first;
+ //for (; cond; cond=cond->next) {
+ // if (boid_condition_is_true(cond)) {
+ // pa->boid->state_id = cond->state_id;
+ // state = get_boid_state(boids, pa);
+ // break; /* only first true condition is used */
+ // }
+ //}
+
+ zero_v3(bbd->wanted_co);
+ bbd->wanted_speed = 0.0f;
+
+ /* create random seed for every particle & frame */
+ rand = (int)(psys_frand(psys, psys->seed + p) * 1000);
+ rand = (int)(psys_frand(psys, (int)bbd->cfra + rand) * 1000);
+
+ set_boid_values(&val, bbd->part->boids, pa);
+
+ /* go through rules */
+ switch (state->ruleset_type) {
+ case eBoidRulesetType_Fuzzy: {
+ for (rule = state->rules.first; rule; rule = rule->next) {
+ if (apply_boid_rule(bbd, rule, &val, pa, state->rule_fuzziness))
+ break; /* only first nonzero rule that comes through fuzzy rule is applied */
+ }
+ break;
+ }
+ case eBoidRulesetType_Random: {
+ /* use random rule for each particle (always same for same particle though) */
+ const int n = BLI_listbase_count(&state->rules);
+ if (n) {
+ rule = BLI_findlink(&state->rules, rand % n);
+ apply_boid_rule(bbd, rule, &val, pa, -1.0);
+ }
+ break;
+ }
+ case eBoidRulesetType_Average: {
+ float wanted_co[3] = {0.0f, 0.0f, 0.0f}, wanted_speed = 0.0f;
+ int n = 0;
+ for (rule = state->rules.first; rule; rule = rule->next) {
+ if (apply_boid_rule(bbd, rule, &val, pa, -1.0f)) {
+ add_v3_v3(wanted_co, bbd->wanted_co);
+ wanted_speed += bbd->wanted_speed;
+ n++;
+ zero_v3(bbd->wanted_co);
+ bbd->wanted_speed = 0.0f;
+ }
+ }
+
+ if (n > 1) {
+ mul_v3_fl(wanted_co, 1.0f / (float)n);
+ wanted_speed /= (float)n;
+ }
+
+ copy_v3_v3(bbd->wanted_co, wanted_co);
+ bbd->wanted_speed = wanted_speed;
+ break;
+ }
+ }
+
+ /* decide on jumping & liftoff */
+ if (bpa->data.mode == eBoidMode_OnLand) {
+ /* fuzziness makes boids capable of misjudgement */
+ float mul = 1.0f + state->rule_fuzziness;
+
+ if (boids->options & BOID_ALLOW_FLIGHT && bbd->wanted_co[2] > 0.0f) {
+ float cvel[3], dir[3];
+
+ copy_v3_v3(dir, pa->prev_state.ave);
+ normalize_v2(dir);
+
+ copy_v3_v3(cvel, bbd->wanted_co);
+ normalize_v2(cvel);
+
+ if (dot_v2v2(cvel, dir) > 0.95f / mul)
+ bpa->data.mode = eBoidMode_Liftoff;
+ }
+ else if (val.jump_speed > 0.0f) {
+ float jump_v[3];
+ int jump = 0;
+
+ /* jump to get to a location */
+ if (bbd->wanted_co[2] > 0.0f) {
+ float cvel[3], dir[3];
+ float z_v, ground_v, cur_v;
+ float len;
+
+ copy_v3_v3(dir, pa->prev_state.ave);
+ normalize_v2(dir);
+
+ copy_v3_v3(cvel, bbd->wanted_co);
+ normalize_v2(cvel);
+
+ len = len_v2(pa->prev_state.vel);
+
+ /* first of all, are we going in a suitable direction? */
+ /* or at a suitably slow speed */
+ if (dot_v2v2(cvel, dir) > 0.95f / mul || len <= state->rule_fuzziness) {
+ /* try to reach goal at highest point of the parabolic path */
+ cur_v = len_v2(pa->prev_state.vel);
+ z_v = sasqrt(-2.0f * bbd->sim->scene->physics_settings.gravity[2] * bbd->wanted_co[2]);
+ ground_v = len_v2(bbd->wanted_co) *
+ sasqrt(-0.5f * bbd->sim->scene->physics_settings.gravity[2] /
+ bbd->wanted_co[2]);
+
+ len = sasqrt((ground_v - cur_v) * (ground_v - cur_v) + z_v * z_v);
+
+ if (len < val.jump_speed * mul || bbd->part->boids->options & BOID_ALLOW_FLIGHT) {
+ jump = 1;
+
+ len = MIN2(len, val.jump_speed);
+
+ copy_v3_v3(jump_v, dir);
+ jump_v[2] = z_v;
+ mul_v3_fl(jump_v, ground_v);
+
+ normalize_v3(jump_v);
+ mul_v3_fl(jump_v, len);
+ add_v2_v2v2(jump_v, jump_v, pa->prev_state.vel);
+ }
+ }
+ }
+
+ /* jump to go faster */
+ if (jump == 0 && val.jump_speed > val.max_speed && bbd->wanted_speed > val.max_speed) {
+ /* pass */
+ }
+
+ if (jump) {
+ copy_v3_v3(pa->prev_state.vel, jump_v);
+ bpa->data.mode = eBoidMode_Falling;
+ }
+ }
+ }
}
/* tries to realize the wanted velocity taking all constraints into account */
void boid_body(BoidBrainData *bbd, ParticleData *pa)
{
- BoidSettings *boids = bbd->part->boids;
- BoidParticle *bpa = pa->boid;
- BoidValues val;
- EffectedPoint epoint;
- float acc[3] = {0.0f, 0.0f, 0.0f}, tan_acc[3], nor_acc[3];
- float dvec[3], bvec[3];
- float new_dir[3], new_speed;
- float old_dir[3], old_speed;
- float wanted_dir[3];
- float q[4], mat[3][3]; /* rotation */
- float ground_co[3] = {0.0f, 0.0f, 0.0f}, ground_nor[3] = {0.0f, 0.0f, 1.0f};
- float force[3] = {0.0f, 0.0f, 0.0f};
- float pa_mass=bbd->part->mass, dtime=bbd->dfra*bbd->timestep;
-
- set_boid_values(&val, boids, pa);
-
- /* make sure there's something in new velocity, location & rotation */
- copy_particle_key(&pa->state, &pa->prev_state, 0);
-
- if (bbd->part->flag & PART_SIZEMASS)
- pa_mass*=pa->size;
-
- /* if boids can't fly they fall to the ground */
- if ((boids->options & BOID_ALLOW_FLIGHT)==0 && ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)==0 && psys_uses_gravity(bbd->sim))
- bpa->data.mode = eBoidMode_Falling;
-
- if (bpa->data.mode == eBoidMode_Falling) {
- /* Falling boids are only effected by gravity. */
- acc[2] = bbd->sim->scene->physics_settings.gravity[2];
- }
- else {
- /* figure out acceleration */
- float landing_level = 2.0f;
- float level = landing_level + 1.0f;
- float new_vel[3];
-
- if (bpa->data.mode == eBoidMode_Liftoff) {
- bpa->data.mode = eBoidMode_InAir;
- bpa->ground = boid_find_ground(bbd, pa, ground_co, ground_nor);
- }
- else if (bpa->data.mode == eBoidMode_InAir && boids->options & BOID_ALLOW_LAND) {
- /* auto-leveling & landing if close to ground */
-
- bpa->ground = boid_find_ground(bbd, pa, ground_co, ground_nor);
-
- /* level = how many particle sizes above ground */
- level = (pa->prev_state.co[2] - ground_co[2])/(2.0f * pa->size) - 0.5f;
-
- landing_level = - boids->landing_smoothness * pa->prev_state.vel[2] * pa_mass;
-
- if (pa->prev_state.vel[2] < 0.0f) {
- if (level < 1.0f) {
- bbd->wanted_co[0] = bbd->wanted_co[1] = bbd->wanted_co[2] = 0.0f;
- bbd->wanted_speed = 0.0f;
- bpa->data.mode = eBoidMode_Falling;
- }
- else if (level < landing_level) {
- bbd->wanted_speed *= (level - 1.0f)/landing_level;
- bbd->wanted_co[2] *= (level - 1.0f)/landing_level;
- }
- }
- }
-
- copy_v3_v3(old_dir, pa->prev_state.ave);
- new_speed = normalize_v3_v3(wanted_dir, bbd->wanted_co);
-
- /* first check if we have valid direction we want to go towards */
- if (new_speed == 0.0f) {
- copy_v3_v3(new_dir, old_dir);
- }
- else {
- float old_dir2[2], wanted_dir2[2], nor[3], angle;
- copy_v2_v2(old_dir2, old_dir);
- normalize_v2(old_dir2);
- copy_v2_v2(wanted_dir2, wanted_dir);
- normalize_v2(wanted_dir2);
-
- /* choose random direction to turn if wanted velocity */
- /* is directly behind regardless of z-coordinate */
- if (dot_v2v2(old_dir2, wanted_dir2) < -0.99f) {
- wanted_dir[0] = 2.0f*(0.5f - BLI_rng_get_float(bbd->rng));
- wanted_dir[1] = 2.0f*(0.5f - BLI_rng_get_float(bbd->rng));
- wanted_dir[2] = 2.0f*(0.5f - BLI_rng_get_float(bbd->rng));
- normalize_v3(wanted_dir);
- }
-
- /* constrain direction with maximum angular velocity */
- angle = saacos(dot_v3v3(old_dir, wanted_dir));
- angle = min_ff(angle, val.max_ave);
-
- cross_v3_v3v3(nor, old_dir, wanted_dir);
- axis_angle_to_quat(q, nor, angle);
- copy_v3_v3(new_dir, old_dir);
- mul_qt_v3(q, new_dir);
- normalize_v3(new_dir);
-
- /* save direction in case resulting velocity too small */
- axis_angle_to_quat(q, nor, angle*dtime);
- copy_v3_v3(pa->state.ave, old_dir);
- mul_qt_v3(q, pa->state.ave);
- normalize_v3(pa->state.ave);
- }
-
- /* constrain speed with maximum acceleration */
- old_speed = len_v3(pa->prev_state.vel);
-
- if (bbd->wanted_speed < old_speed)
- new_speed = MAX2(bbd->wanted_speed, old_speed - val.max_acc);
- else
- new_speed = MIN2(bbd->wanted_speed, old_speed + val.max_acc);
-
- /* combine direction and speed */
- copy_v3_v3(new_vel, new_dir);
- mul_v3_fl(new_vel, new_speed);
-
- /* maintain minimum flying velocity if not landing */
- if (level >= landing_level) {
- float len2 = dot_v2v2(new_vel, new_vel);
- float root;
-
- len2 = MAX2(len2, val.min_speed*val.min_speed);
- root = sasqrt(new_speed*new_speed - len2);
-
- new_vel[2] = new_vel[2] < 0.0f ? -root : root;
-
- normalize_v2(new_vel);
- mul_v2_fl(new_vel, sasqrt(len2));
- }
-
- /* finally constrain speed to max speed */
- new_speed = normalize_v3(new_vel);
- mul_v3_fl(new_vel, MIN2(new_speed, val.max_speed));
-
- /* get acceleration from difference of velocities */
- sub_v3_v3v3(acc, new_vel, pa->prev_state.vel);
-
- /* break acceleration to components */
- project_v3_v3v3(tan_acc, acc, pa->prev_state.ave);
- sub_v3_v3v3(nor_acc, acc, tan_acc);
- }
-
- /* account for effectors */
- pd_point_from_particle(bbd->sim, pa, &pa->state, &epoint);
- BKE_effectors_apply(bbd->sim->psys->effectors, bbd->sim->colliders, bbd->part->effector_weights, &epoint, force, NULL);
-
- if (ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)) {
- float length = normalize_v3(force);
-
- length = MAX2(0.0f, length - boids->land_stick_force);
-
- mul_v3_fl(force, length);
- }
-
- add_v3_v3(acc, force);
-
- /* store smoothed acceleration for nice banking etc. */
- madd_v3_v3fl(bpa->data.acc, acc, dtime);
- mul_v3_fl(bpa->data.acc, 1.0f / (1.0f + dtime));
-
- /* integrate new location & velocity */
-
- /* by regarding the acceleration as a force at this stage we
- * can get better control although it's a bit unphysical */
- mul_v3_fl(acc, 1.0f/pa_mass);
-
- copy_v3_v3(dvec, acc);
- mul_v3_fl(dvec, dtime*dtime*0.5f);
-
- copy_v3_v3(bvec, pa->prev_state.vel);
- mul_v3_fl(bvec, dtime);
- add_v3_v3(dvec, bvec);
- add_v3_v3(pa->state.co, dvec);
-
- madd_v3_v3fl(pa->state.vel, acc, dtime);
-
- //if (bpa->data.mode != eBoidMode_InAir)
- bpa->ground = boid_find_ground(bbd, pa, ground_co, ground_nor);
-
- /* change modes, constrain movement & keep track of down vector */
- switch (bpa->data.mode) {
- case eBoidMode_InAir:
- {
- float grav[3];
-
- grav[0] = 0.0f;
- grav[1] = 0.0f;
- grav[2] = bbd->sim->scene->physics_settings.gravity[2] < 0.0f ? -1.0f : 0.0f;
-
- /* don't take forward acceleration into account (better banking) */
- if (dot_v3v3(bpa->data.acc, pa->state.vel) > 0.0f) {
- project_v3_v3v3(dvec, bpa->data.acc, pa->state.vel);
- sub_v3_v3v3(dvec, bpa->data.acc, dvec);
- }
- else {
- copy_v3_v3(dvec, bpa->data.acc);
- }
-
- /* gather apparent gravity */
- madd_v3_v3v3fl(bpa->gravity, grav, dvec, -boids->banking);
- normalize_v3(bpa->gravity);
-
- /* stick boid on goal when close enough */
- if (bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <= pa->size * boids->height) {
- bpa->data.mode = eBoidMode_Climbing;
- bpa->ground = bbd->goal_ob;
- boid_find_ground(bbd, pa, ground_co, ground_nor);
- boid_climb(boids, pa, ground_co, ground_nor);
- }
- else if (pa->state.co[2] <= ground_co[2] + pa->size * boids->height) {
- /* land boid when below ground */
- if (boids->options & BOID_ALLOW_LAND) {
- pa->state.co[2] = ground_co[2] + pa->size * boids->height;
- pa->state.vel[2] = 0.0f;
- bpa->data.mode = eBoidMode_OnLand;
- }
- /* fly above ground */
- else if (bpa->ground) {
- pa->state.co[2] = ground_co[2] + pa->size * boids->height;
- pa->state.vel[2] = 0.0f;
- }
- }
- break;
- }
- case eBoidMode_Falling:
- {
- float grav[3];
-
- grav[0] = 0.0f;
- grav[1] = 0.0f;
- grav[2] = bbd->sim->scene->physics_settings.gravity[2] < 0.0f ? -1.0f : 0.0f;
-
-
- /* gather apparent gravity */
- madd_v3_v3fl(bpa->gravity, grav, dtime);
- normalize_v3(bpa->gravity);
-
- if (boids->options & BOID_ALLOW_LAND) {
- /* stick boid on goal when close enough */
- if (bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <= pa->size * boids->height) {
- bpa->data.mode = eBoidMode_Climbing;
- bpa->ground = bbd->goal_ob;
- boid_find_ground(bbd, pa, ground_co, ground_nor);
- boid_climb(boids, pa, ground_co, ground_nor);
- }
- /* land boid when really near ground */
- else if (pa->state.co[2] <= ground_co[2] + 1.01f * pa->size * boids->height) {
- pa->state.co[2] = ground_co[2] + pa->size * boids->height;
- pa->state.vel[2] = 0.0f;
- bpa->data.mode = eBoidMode_OnLand;
- }
- /* if we're falling, can fly and want to go upwards lets fly */
- else if (boids->options & BOID_ALLOW_FLIGHT && bbd->wanted_co[2] > 0.0f)
- bpa->data.mode = eBoidMode_InAir;
- }
- else
- bpa->data.mode = eBoidMode_InAir;
- break;
- }
- case eBoidMode_Climbing:
- {
- boid_climb(boids, pa, ground_co, ground_nor);
- //float nor[3];
- //copy_v3_v3(nor, ground_nor);
-
- ///* gather apparent gravity to r_ve */
- //madd_v3_v3fl(pa->r_ve, ground_nor, -1.0);
- //normalize_v3(pa->r_ve);
-
- ///* raise boid it's size from surface */
- //mul_v3_fl(nor, pa->size * boids->height);
- //add_v3_v3v3(pa->state.co, ground_co, nor);
-
- ///* remove normal component from velocity */
- //project_v3_v3v3(v, pa->state.vel, ground_nor);
- //sub_v3_v3v3(pa->state.vel, pa->state.vel, v);
- break;
- }
- case eBoidMode_OnLand:
- {
- /* stick boid on goal when close enough */
- if (bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <= pa->size * boids->height) {
- bpa->data.mode = eBoidMode_Climbing;
- bpa->ground = bbd->goal_ob;
- boid_find_ground(bbd, pa, ground_co, ground_nor);
- boid_climb(boids, pa, ground_co, ground_nor);
- }
- /* ground is too far away so boid falls */
- else if (pa->state.co[2]-ground_co[2] > 1.1f * pa->size * boids->height)
- bpa->data.mode = eBoidMode_Falling;
- else {
- /* constrain to surface */
- pa->state.co[2] = ground_co[2] + pa->size * boids->height;
- pa->state.vel[2] = 0.0f;
- }
-
- if (boids->banking > 0.0f) {
- float grav[3];
- /* Don't take gravity's strength in to account, */
- /* otherwise amount of banking is hard to control. */
- negate_v3_v3(grav, ground_nor);
-
- project_v3_v3v3(dvec, bpa->data.acc, pa->state.vel);
- sub_v3_v3v3(dvec, bpa->data.acc, dvec);
-
- /* gather apparent gravity */
- madd_v3_v3v3fl(bpa->gravity, grav, dvec, -boids->banking);
- normalize_v3(bpa->gravity);
- }
- else {
- /* gather negative surface normal */
- madd_v3_v3fl(bpa->gravity, ground_nor, -1.0f);
- normalize_v3(bpa->gravity);
- }
- break;
- }
- }
-
- /* save direction to state.ave unless the boid is falling */
- /* (boids can't effect their direction when falling) */
- if (bpa->data.mode!=eBoidMode_Falling && len_v3(pa->state.vel) > 0.1f*pa->size) {
- copy_v3_v3(pa->state.ave, pa->state.vel);
- pa->state.ave[2] *= bbd->part->boids->pitch;
- normalize_v3(pa->state.ave);
- }
-
- /* apply damping */
- if (ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing))
- mul_v3_fl(pa->state.vel, 1.0f - 0.2f*bbd->part->dampfac);
-
- /* calculate rotation matrix based on forward & down vectors */
- if (bpa->data.mode == eBoidMode_InAir) {
- copy_v3_v3(mat[0], pa->state.ave);
-
- project_v3_v3v3(dvec, bpa->gravity, pa->state.ave);
- sub_v3_v3v3(mat[2], bpa->gravity, dvec);
- normalize_v3(mat[2]);
- }
- else {
- project_v3_v3v3(dvec, pa->state.ave, bpa->gravity);
- sub_v3_v3v3(mat[0], pa->state.ave, dvec);
- normalize_v3(mat[0]);
-
- copy_v3_v3(mat[2], bpa->gravity);
- }
- negate_v3(mat[2]);
- cross_v3_v3v3(mat[1], mat[2], mat[0]);
-
- /* apply rotation */
- mat3_to_quat_is_ok(q, mat);
- copy_qt_qt(pa->state.rot, q);
+ BoidSettings *boids = bbd->part->boids;
+ BoidParticle *bpa = pa->boid;
+ BoidValues val;
+ EffectedPoint epoint;
+ float acc[3] = {0.0f, 0.0f, 0.0f}, tan_acc[3], nor_acc[3];
+ float dvec[3], bvec[3];
+ float new_dir[3], new_speed;
+ float old_dir[3], old_speed;
+ float wanted_dir[3];
+ float q[4], mat[3][3]; /* rotation */
+ float ground_co[3] = {0.0f, 0.0f, 0.0f}, ground_nor[3] = {0.0f, 0.0f, 1.0f};
+ float force[3] = {0.0f, 0.0f, 0.0f};
+ float pa_mass = bbd->part->mass, dtime = bbd->dfra * bbd->timestep;
+
+ set_boid_values(&val, boids, pa);
+
+ /* make sure there's something in new velocity, location & rotation */
+ copy_particle_key(&pa->state, &pa->prev_state, 0);
+
+ if (bbd->part->flag & PART_SIZEMASS)
+ pa_mass *= pa->size;
+
+ /* if boids can't fly they fall to the ground */
+ if ((boids->options & BOID_ALLOW_FLIGHT) == 0 &&
+ ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing) == 0 &&
+ psys_uses_gravity(bbd->sim))
+ bpa->data.mode = eBoidMode_Falling;
+
+ if (bpa->data.mode == eBoidMode_Falling) {
+ /* Falling boids are only effected by gravity. */
+ acc[2] = bbd->sim->scene->physics_settings.gravity[2];
+ }
+ else {
+ /* figure out acceleration */
+ float landing_level = 2.0f;
+ float level = landing_level + 1.0f;
+ float new_vel[3];
+
+ if (bpa->data.mode == eBoidMode_Liftoff) {
+ bpa->data.mode = eBoidMode_InAir;
+ bpa->ground = boid_find_ground(bbd, pa, ground_co, ground_nor);
+ }
+ else if (bpa->data.mode == eBoidMode_InAir && boids->options & BOID_ALLOW_LAND) {
+ /* auto-leveling & landing if close to ground */
+
+ bpa->ground = boid_find_ground(bbd, pa, ground_co, ground_nor);
+
+ /* level = how many particle sizes above ground */
+ level = (pa->prev_state.co[2] - ground_co[2]) / (2.0f * pa->size) - 0.5f;
+
+ landing_level = -boids->landing_smoothness * pa->prev_state.vel[2] * pa_mass;
+
+ if (pa->prev_state.vel[2] < 0.0f) {
+ if (level < 1.0f) {
+ bbd->wanted_co[0] = bbd->wanted_co[1] = bbd->wanted_co[2] = 0.0f;
+ bbd->wanted_speed = 0.0f;
+ bpa->data.mode = eBoidMode_Falling;
+ }
+ else if (level < landing_level) {
+ bbd->wanted_speed *= (level - 1.0f) / landing_level;
+ bbd->wanted_co[2] *= (level - 1.0f) / landing_level;
+ }
+ }
+ }
+
+ copy_v3_v3(old_dir, pa->prev_state.ave);
+ new_speed = normalize_v3_v3(wanted_dir, bbd->wanted_co);
+
+ /* first check if we have valid direction we want to go towards */
+ if (new_speed == 0.0f) {
+ copy_v3_v3(new_dir, old_dir);
+ }
+ else {
+ float old_dir2[2], wanted_dir2[2], nor[3], angle;
+ copy_v2_v2(old_dir2, old_dir);
+ normalize_v2(old_dir2);
+ copy_v2_v2(wanted_dir2, wanted_dir);
+ normalize_v2(wanted_dir2);
+
+ /* choose random direction to turn if wanted velocity */
+ /* is directly behind regardless of z-coordinate */
+ if (dot_v2v2(old_dir2, wanted_dir2) < -0.99f) {
+ wanted_dir[0] = 2.0f * (0.5f - BLI_rng_get_float(bbd->rng));
+ wanted_dir[1] = 2.0f * (0.5f - BLI_rng_get_float(bbd->rng));
+ wanted_dir[2] = 2.0f * (0.5f - BLI_rng_get_float(bbd->rng));
+ normalize_v3(wanted_dir);
+ }
+
+ /* constrain direction with maximum angular velocity */
+ angle = saacos(dot_v3v3(old_dir, wanted_dir));
+ angle = min_ff(angle, val.max_ave);
+
+ cross_v3_v3v3(nor, old_dir, wanted_dir);
+ axis_angle_to_quat(q, nor, angle);
+ copy_v3_v3(new_dir, old_dir);
+ mul_qt_v3(q, new_dir);
+ normalize_v3(new_dir);
+
+ /* save direction in case resulting velocity too small */
+ axis_angle_to_quat(q, nor, angle * dtime);
+ copy_v3_v3(pa->state.ave, old_dir);
+ mul_qt_v3(q, pa->state.ave);
+ normalize_v3(pa->state.ave);
+ }
+
+ /* constrain speed with maximum acceleration */
+ old_speed = len_v3(pa->prev_state.vel);
+
+ if (bbd->wanted_speed < old_speed)
+ new_speed = MAX2(bbd->wanted_speed, old_speed - val.max_acc);
+ else
+ new_speed = MIN2(bbd->wanted_speed, old_speed + val.max_acc);
+
+ /* combine direction and speed */
+ copy_v3_v3(new_vel, new_dir);
+ mul_v3_fl(new_vel, new_speed);
+
+ /* maintain minimum flying velocity if not landing */
+ if (level >= landing_level) {
+ float len2 = dot_v2v2(new_vel, new_vel);
+ float root;
+
+ len2 = MAX2(len2, val.min_speed * val.min_speed);
+ root = sasqrt(new_speed * new_speed - len2);
+
+ new_vel[2] = new_vel[2] < 0.0f ? -root : root;
+
+ normalize_v2(new_vel);
+ mul_v2_fl(new_vel, sasqrt(len2));
+ }
+
+ /* finally constrain speed to max speed */
+ new_speed = normalize_v3(new_vel);
+ mul_v3_fl(new_vel, MIN2(new_speed, val.max_speed));
+
+ /* get acceleration from difference of velocities */
+ sub_v3_v3v3(acc, new_vel, pa->prev_state.vel);
+
+ /* break acceleration to components */
+ project_v3_v3v3(tan_acc, acc, pa->prev_state.ave);
+ sub_v3_v3v3(nor_acc, acc, tan_acc);
+ }
+
+ /* account for effectors */
+ pd_point_from_particle(bbd->sim, pa, &pa->state, &epoint);
+ BKE_effectors_apply(bbd->sim->psys->effectors,
+ bbd->sim->colliders,
+ bbd->part->effector_weights,
+ &epoint,
+ force,
+ NULL);
+
+ if (ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)) {
+ float length = normalize_v3(force);
+
+ length = MAX2(0.0f, length - boids->land_stick_force);
+
+ mul_v3_fl(force, length);
+ }
+
+ add_v3_v3(acc, force);
+
+ /* store smoothed acceleration for nice banking etc. */
+ madd_v3_v3fl(bpa->data.acc, acc, dtime);
+ mul_v3_fl(bpa->data.acc, 1.0f / (1.0f + dtime));
+
+ /* integrate new location & velocity */
+
+ /* by regarding the acceleration as a force at this stage we
+ * can get better control although it's a bit unphysical */
+ mul_v3_fl(acc, 1.0f / pa_mass);
+
+ copy_v3_v3(dvec, acc);
+ mul_v3_fl(dvec, dtime * dtime * 0.5f);
+
+ copy_v3_v3(bvec, pa->prev_state.vel);
+ mul_v3_fl(bvec, dtime);
+ add_v3_v3(dvec, bvec);
+ add_v3_v3(pa->state.co, dvec);
+
+ madd_v3_v3fl(pa->state.vel, acc, dtime);
+
+ //if (bpa->data.mode != eBoidMode_InAir)
+ bpa->ground = boid_find_ground(bbd, pa, ground_co, ground_nor);
+
+ /* change modes, constrain movement & keep track of down vector */
+ switch (bpa->data.mode) {
+ case eBoidMode_InAir: {
+ float grav[3];
+
+ grav[0] = 0.0f;
+ grav[1] = 0.0f;
+ grav[2] = bbd->sim->scene->physics_settings.gravity[2] < 0.0f ? -1.0f : 0.0f;
+
+ /* don't take forward acceleration into account (better banking) */
+ if (dot_v3v3(bpa->data.acc, pa->state.vel) > 0.0f) {
+ project_v3_v3v3(dvec, bpa->data.acc, pa->state.vel);
+ sub_v3_v3v3(dvec, bpa->data.acc, dvec);
+ }
+ else {
+ copy_v3_v3(dvec, bpa->data.acc);
+ }
+
+ /* gather apparent gravity */
+ madd_v3_v3v3fl(bpa->gravity, grav, dvec, -boids->banking);
+ normalize_v3(bpa->gravity);
+
+ /* stick boid on goal when close enough */
+ if (bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <=
+ pa->size * boids->height) {
+ bpa->data.mode = eBoidMode_Climbing;
+ bpa->ground = bbd->goal_ob;
+ boid_find_ground(bbd, pa, ground_co, ground_nor);
+ boid_climb(boids, pa, ground_co, ground_nor);
+ }
+ else if (pa->state.co[2] <= ground_co[2] + pa->size * boids->height) {
+ /* land boid when below ground */
+ if (boids->options & BOID_ALLOW_LAND) {
+ pa->state.co[2] = ground_co[2] + pa->size * boids->height;
+ pa->state.vel[2] = 0.0f;
+ bpa->data.mode = eBoidMode_OnLand;
+ }
+ /* fly above ground */
+ else if (bpa->ground) {
+ pa->state.co[2] = ground_co[2] + pa->size * boids->height;
+ pa->state.vel[2] = 0.0f;
+ }
+ }
+ break;
+ }
+ case eBoidMode_Falling: {
+ float grav[3];
+
+ grav[0] = 0.0f;
+ grav[1] = 0.0f;
+ grav[2] = bbd->sim->scene->physics_settings.gravity[2] < 0.0f ? -1.0f : 0.0f;
+
+ /* gather apparent gravity */
+ madd_v3_v3fl(bpa->gravity, grav, dtime);
+ normalize_v3(bpa->gravity);
+
+ if (boids->options & BOID_ALLOW_LAND) {
+ /* stick boid on goal when close enough */
+ if (bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <=
+ pa->size * boids->height) {
+ bpa->data.mode = eBoidMode_Climbing;
+ bpa->ground = bbd->goal_ob;
+ boid_find_ground(bbd, pa, ground_co, ground_nor);
+ boid_climb(boids, pa, ground_co, ground_nor);
+ }
+ /* land boid when really near ground */
+ else if (pa->state.co[2] <= ground_co[2] + 1.01f * pa->size * boids->height) {
+ pa->state.co[2] = ground_co[2] + pa->size * boids->height;
+ pa->state.vel[2] = 0.0f;
+ bpa->data.mode = eBoidMode_OnLand;
+ }
+ /* if we're falling, can fly and want to go upwards lets fly */
+ else if (boids->options & BOID_ALLOW_FLIGHT && bbd->wanted_co[2] > 0.0f)
+ bpa->data.mode = eBoidMode_InAir;
+ }
+ else
+ bpa->data.mode = eBoidMode_InAir;
+ break;
+ }
+ case eBoidMode_Climbing: {
+ boid_climb(boids, pa, ground_co, ground_nor);
+ //float nor[3];
+ //copy_v3_v3(nor, ground_nor);
+
+ ///* gather apparent gravity to r_ve */
+ //madd_v3_v3fl(pa->r_ve, ground_nor, -1.0);
+ //normalize_v3(pa->r_ve);
+
+ ///* raise boid it's size from surface */
+ //mul_v3_fl(nor, pa->size * boids->height);
+ //add_v3_v3v3(pa->state.co, ground_co, nor);
+
+ ///* remove normal component from velocity */
+ //project_v3_v3v3(v, pa->state.vel, ground_nor);
+ //sub_v3_v3v3(pa->state.vel, pa->state.vel, v);
+ break;
+ }
+ case eBoidMode_OnLand: {
+ /* stick boid on goal when close enough */
+ if (bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <=
+ pa->size * boids->height) {
+ bpa->data.mode = eBoidMode_Climbing;
+ bpa->ground = bbd->goal_ob;
+ boid_find_ground(bbd, pa, ground_co, ground_nor);
+ boid_climb(boids, pa, ground_co, ground_nor);
+ }
+ /* ground is too far away so boid falls */
+ else if (pa->state.co[2] - ground_co[2] > 1.1f * pa->size * boids->height)
+ bpa->data.mode = eBoidMode_Falling;
+ else {
+ /* constrain to surface */
+ pa->state.co[2] = ground_co[2] + pa->size * boids->height;
+ pa->state.vel[2] = 0.0f;
+ }
+
+ if (boids->banking > 0.0f) {
+ float grav[3];
+ /* Don't take gravity's strength in to account, */
+ /* otherwise amount of banking is hard to control. */
+ negate_v3_v3(grav, ground_nor);
+
+ project_v3_v3v3(dvec, bpa->data.acc, pa->state.vel);
+ sub_v3_v3v3(dvec, bpa->data.acc, dvec);
+
+ /* gather apparent gravity */
+ madd_v3_v3v3fl(bpa->gravity, grav, dvec, -boids->banking);
+ normalize_v3(bpa->gravity);
+ }
+ else {
+ /* gather negative surface normal */
+ madd_v3_v3fl(bpa->gravity, ground_nor, -1.0f);
+ normalize_v3(bpa->gravity);
+ }
+ break;
+ }
+ }
+
+ /* save direction to state.ave unless the boid is falling */
+ /* (boids can't effect their direction when falling) */
+ if (bpa->data.mode != eBoidMode_Falling && len_v3(pa->state.vel) > 0.1f * pa->size) {
+ copy_v3_v3(pa->state.ave, pa->state.vel);
+ pa->state.ave[2] *= bbd->part->boids->pitch;
+ normalize_v3(pa->state.ave);
+ }
+
+ /* apply damping */
+ if (ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing))
+ mul_v3_fl(pa->state.vel, 1.0f - 0.2f * bbd->part->dampfac);
+
+ /* calculate rotation matrix based on forward & down vectors */
+ if (bpa->data.mode == eBoidMode_InAir) {
+ copy_v3_v3(mat[0], pa->state.ave);
+
+ project_v3_v3v3(dvec, bpa->gravity, pa->state.ave);
+ sub_v3_v3v3(mat[2], bpa->gravity, dvec);
+ normalize_v3(mat[2]);
+ }
+ else {
+ project_v3_v3v3(dvec, pa->state.ave, bpa->gravity);
+ sub_v3_v3v3(mat[0], pa->state.ave, dvec);
+ normalize_v3(mat[0]);
+
+ copy_v3_v3(mat[2], bpa->gravity);
+ }
+ negate_v3(mat[2]);
+ cross_v3_v3v3(mat[1], mat[2], mat[0]);
+
+ /* apply rotation */
+ mat3_to_quat_is_ok(q, mat);
+ copy_qt_qt(pa->state.rot, q);
}
BoidRule *boid_new_rule(int type)
{
- BoidRule *rule = NULL;
- if (type <= 0)
- return NULL;
-
- switch (type) {
- case eBoidRuleType_Goal:
- case eBoidRuleType_Avoid:
- rule = MEM_callocN(sizeof(BoidRuleGoalAvoid), "BoidRuleGoalAvoid");
- break;
- case eBoidRuleType_AvoidCollision:
- rule = MEM_callocN(sizeof(BoidRuleAvoidCollision), "BoidRuleAvoidCollision");
- ((BoidRuleAvoidCollision*)rule)->look_ahead = 2.0f;
- break;
- case eBoidRuleType_FollowLeader:
- rule = MEM_callocN(sizeof(BoidRuleFollowLeader), "BoidRuleFollowLeader");
- ((BoidRuleFollowLeader*)rule)->distance = 1.0f;
- break;
- case eBoidRuleType_AverageSpeed:
- rule = MEM_callocN(sizeof(BoidRuleAverageSpeed), "BoidRuleAverageSpeed");
- ((BoidRuleAverageSpeed*)rule)->speed = 0.5f;
- break;
- case eBoidRuleType_Fight:
- rule = MEM_callocN(sizeof(BoidRuleFight), "BoidRuleFight");
- ((BoidRuleFight*)rule)->distance = 100.0f;
- ((BoidRuleFight*)rule)->flee_distance = 100.0f;
- break;
- default:
- rule = MEM_callocN(sizeof(BoidRule), "BoidRule");
- break;
- }
-
- rule->type = type;
- rule->flag |= BOIDRULE_IN_AIR|BOIDRULE_ON_LAND;
- BLI_strncpy(rule->name, rna_enum_boidrule_type_items[type-1].name, sizeof(rule->name));
-
- return rule;
+ BoidRule *rule = NULL;
+ if (type <= 0)
+ return NULL;
+
+ switch (type) {
+ case eBoidRuleType_Goal:
+ case eBoidRuleType_Avoid:
+ rule = MEM_callocN(sizeof(BoidRuleGoalAvoid), "BoidRuleGoalAvoid");
+ break;
+ case eBoidRuleType_AvoidCollision:
+ rule = MEM_callocN(sizeof(BoidRuleAvoidCollision), "BoidRuleAvoidCollision");
+ ((BoidRuleAvoidCollision *)rule)->look_ahead = 2.0f;
+ break;
+ case eBoidRuleType_FollowLeader:
+ rule = MEM_callocN(sizeof(BoidRuleFollowLeader), "BoidRuleFollowLeader");
+ ((BoidRuleFollowLeader *)rule)->distance = 1.0f;
+ break;
+ case eBoidRuleType_AverageSpeed:
+ rule = MEM_callocN(sizeof(BoidRuleAverageSpeed), "BoidRuleAverageSpeed");
+ ((BoidRuleAverageSpeed *)rule)->speed = 0.5f;
+ break;
+ case eBoidRuleType_Fight:
+ rule = MEM_callocN(sizeof(BoidRuleFight), "BoidRuleFight");
+ ((BoidRuleFight *)rule)->distance = 100.0f;
+ ((BoidRuleFight *)rule)->flee_distance = 100.0f;
+ break;
+ default:
+ rule = MEM_callocN(sizeof(BoidRule), "BoidRule");
+ break;
+ }
+
+ rule->type = type;
+ rule->flag |= BOIDRULE_IN_AIR | BOIDRULE_ON_LAND;
+ BLI_strncpy(rule->name, rna_enum_boidrule_type_items[type - 1].name, sizeof(rule->name));
+
+ return rule;
}
void boid_default_settings(BoidSettings *boids)
{
- boids->air_max_speed = 10.0f;
- boids->air_max_acc = 0.5f;
- boids->air_max_ave = 0.5f;
- boids->air_personal_space = 1.0f;
-
- boids->land_max_speed = 5.0f;
- boids->land_max_acc = 0.5f;
- boids->land_max_ave = 0.5f;
- boids->land_personal_space = 1.0f;
-
- boids->options = BOID_ALLOW_FLIGHT;
-
- boids->landing_smoothness = 3.0f;
- boids->banking = 1.0f;
- boids->pitch = 1.0f;
- boids->height = 1.0f;
-
- boids->health = 1.0f;
- boids->accuracy = 1.0f;
- boids->aggression = 2.0f;
- boids->range = 1.0f;
- boids->strength = 0.1f;
+ boids->air_max_speed = 10.0f;
+ boids->air_max_acc = 0.5f;
+ boids->air_max_ave = 0.5f;
+ boids->air_personal_space = 1.0f;
+
+ boids->land_max_speed = 5.0f;
+ boids->land_max_acc = 0.5f;
+ boids->land_max_ave = 0.5f;
+ boids->land_personal_space = 1.0f;
+
+ boids->options = BOID_ALLOW_FLIGHT;
+
+ boids->landing_smoothness = 3.0f;
+ boids->banking = 1.0f;
+ boids->pitch = 1.0f;
+ boids->height = 1.0f;
+
+ boids->health = 1.0f;
+ boids->accuracy = 1.0f;
+ boids->aggression = 2.0f;
+ boids->range = 1.0f;
+ boids->strength = 0.1f;
}
BoidState *boid_new_state(BoidSettings *boids)
{
- BoidState *state = MEM_callocN(sizeof(BoidState), "BoidState");
+ BoidState *state = MEM_callocN(sizeof(BoidState), "BoidState");
- state->id = boids->last_state_id++;
- if (state->id)
- BLI_snprintf(state->name, sizeof(state->name), "State %i", state->id);
- else
- strcpy(state->name, "State");
+ state->id = boids->last_state_id++;
+ if (state->id)
+ BLI_snprintf(state->name, sizeof(state->name), "State %i", state->id);
+ else
+ strcpy(state->name, "State");
- state->rule_fuzziness = 0.5;
- state->volume = 1.0f;
- state->channels |= ~0;
+ state->rule_fuzziness = 0.5;
+ state->volume = 1.0f;
+ state->channels |= ~0;
- return state;
+ return state;
}
BoidState *boid_duplicate_state(BoidSettings *boids, BoidState *state)
{
- BoidState *staten = MEM_dupallocN(state);
+ BoidState *staten = MEM_dupallocN(state);
- BLI_duplicatelist(&staten->rules, &state->rules);
- BLI_duplicatelist(&staten->conditions, &state->conditions);
- BLI_duplicatelist(&staten->actions, &state->actions);
+ BLI_duplicatelist(&staten->rules, &state->rules);
+ BLI_duplicatelist(&staten->conditions, &state->conditions);
+ BLI_duplicatelist(&staten->actions, &state->actions);
- staten->id = boids->last_state_id++;
+ staten->id = boids->last_state_id++;
- return staten;
+ return staten;
}
void boid_free_settings(BoidSettings *boids)
{
- if (boids) {
- BoidState *state = boids->states.first;
+ if (boids) {
+ BoidState *state = boids->states.first;
- for (; state; state=state->next) {
- BLI_freelistN(&state->rules);
- BLI_freelistN(&state->conditions);
- BLI_freelistN(&state->actions);
- }
+ for (; state; state = state->next) {
+ BLI_freelistN(&state->rules);
+ BLI_freelistN(&state->conditions);
+ BLI_freelistN(&state->actions);
+ }
- BLI_freelistN(&boids->states);
+ BLI_freelistN(&boids->states);
- MEM_freeN(boids);
- }
+ MEM_freeN(boids);
+ }
}
BoidSettings *boid_copy_settings(const BoidSettings *boids)
{
- BoidSettings *nboids = NULL;
+ BoidSettings *nboids = NULL;
- if (boids) {
- BoidState *state;
- BoidState *nstate;
+ if (boids) {
+ BoidState *state;
+ BoidState *nstate;
- nboids = MEM_dupallocN(boids);
+ nboids = MEM_dupallocN(boids);
- BLI_duplicatelist(&nboids->states, &boids->states);
+ BLI_duplicatelist(&nboids->states, &boids->states);
- state = boids->states.first;
- nstate = nboids->states.first;
- for (; state; state=state->next, nstate=nstate->next) {
- BLI_duplicatelist(&nstate->rules, &state->rules);
- BLI_duplicatelist(&nstate->conditions, &state->conditions);
- BLI_duplicatelist(&nstate->actions, &state->actions);
- }
- }
+ state = boids->states.first;
+ nstate = nboids->states.first;
+ for (; state; state = state->next, nstate = nstate->next) {
+ BLI_duplicatelist(&nstate->rules, &state->rules);
+ BLI_duplicatelist(&nstate->conditions, &state->conditions);
+ BLI_duplicatelist(&nstate->actions, &state->actions);
+ }
+ }
- return nboids;
+ return nboids;
}
BoidState *boid_get_current_state(BoidSettings *boids)
{
- BoidState *state = boids->states.first;
+ BoidState *state = boids->states.first;
- for (; state; state=state->next) {
- if (state->flag & BOIDSTATE_CURRENT)
- break;
- }
+ for (; state; state = state->next) {
+ if (state->flag & BOIDSTATE_CURRENT)
+ break;
+ }
- return state;
+ return state;
}
diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c
index 3d91283e1cc..25f886b815a 100644
--- a/source/blender/blenkernel/intern/bpath.c
+++ b/source/blender/blenkernel/intern/bpath.c
@@ -73,7 +73,7 @@
#include "BKE_sequencer.h"
#include "BKE_image.h"
-#include "BKE_bpath.h" /* own include */
+#include "BKE_bpath.h" /* own include */
#include "CLG_log.h"
@@ -83,118 +83,128 @@
static CLG_LogRef LOG = {"bke.bpath"};
-static bool checkMissingFiles_visit_cb(void *userdata, char *UNUSED(path_dst), const char *path_src)
+static bool checkMissingFiles_visit_cb(void *userdata,
+ char *UNUSED(path_dst),
+ const char *path_src)
{
- ReportList *reports = (ReportList *)userdata;
+ ReportList *reports = (ReportList *)userdata;
- if (!BLI_exists(path_src)) {
- BKE_reportf(reports, RPT_WARNING, "Path '%s' not found", path_src);
- }
+ if (!BLI_exists(path_src)) {
+ BKE_reportf(reports, RPT_WARNING, "Path '%s' not found", path_src);
+ }
- return false;
+ return false;
}
/* high level function */
void BKE_bpath_missing_files_check(Main *bmain, ReportList *reports)
{
- BKE_bpath_traverse_main(bmain, checkMissingFiles_visit_cb,
- BKE_BPATH_TRAVERSE_ABS | BKE_BPATH_TRAVERSE_SKIP_PACKED, reports);
+ BKE_bpath_traverse_main(bmain,
+ checkMissingFiles_visit_cb,
+ BKE_BPATH_TRAVERSE_ABS | BKE_BPATH_TRAVERSE_SKIP_PACKED,
+ reports);
}
typedef struct BPathRemap_Data {
- const char *basedir;
- ReportList *reports;
+ const char *basedir;
+ ReportList *reports;
- int count_tot;
- int count_changed;
- int count_failed;
+ int count_tot;
+ int count_changed;
+ int count_failed;
} BPathRemap_Data;
static bool bpath_relative_convert_visit_cb(void *userdata, char *path_dst, const char *path_src)
{
- BPathRemap_Data *data = (BPathRemap_Data *)userdata;
-
- data->count_tot++;
-
- if (BLI_path_is_rel(path_src)) {
- return false; /* already relative */
- }
- else {
- strcpy(path_dst, path_src);
- BLI_path_rel(path_dst, data->basedir);
- if (BLI_path_is_rel(path_dst)) {
- data->count_changed++;
- }
- else {
- BKE_reportf(data->reports, RPT_WARNING, "Path '%s' cannot be made relative", path_src);
- data->count_failed++;
- }
- return true;
- }
+ BPathRemap_Data *data = (BPathRemap_Data *)userdata;
+
+ data->count_tot++;
+
+ if (BLI_path_is_rel(path_src)) {
+ return false; /* already relative */
+ }
+ else {
+ strcpy(path_dst, path_src);
+ BLI_path_rel(path_dst, data->basedir);
+ if (BLI_path_is_rel(path_dst)) {
+ data->count_changed++;
+ }
+ else {
+ BKE_reportf(data->reports, RPT_WARNING, "Path '%s' cannot be made relative", path_src);
+ data->count_failed++;
+ }
+ return true;
+ }
}
void BKE_bpath_relative_convert(Main *bmain, const char *basedir, ReportList *reports)
{
- BPathRemap_Data data = {NULL};
- const int flag = BKE_BPATH_TRAVERSE_SKIP_LIBRARY;
+ BPathRemap_Data data = {NULL};
+ const int flag = BKE_BPATH_TRAVERSE_SKIP_LIBRARY;
- if (basedir[0] == '\0') {
- CLOG_ERROR(&LOG, "basedir='', this is a bug");
- return;
- }
+ if (basedir[0] == '\0') {
+ CLOG_ERROR(&LOG, "basedir='', this is a bug");
+ return;
+ }
- data.basedir = basedir;
- data.reports = reports;
+ data.basedir = basedir;
+ data.reports = reports;
- BKE_bpath_traverse_main(bmain, bpath_relative_convert_visit_cb, flag, (void *)&data);
+ BKE_bpath_traverse_main(bmain, bpath_relative_convert_visit_cb, flag, (void *)&data);
- BKE_reportf(reports, data.count_failed ? RPT_WARNING : RPT_INFO,
- "Total files %d | Changed %d | Failed %d",
- data.count_tot, data.count_changed, data.count_failed);
+ BKE_reportf(reports,
+ data.count_failed ? RPT_WARNING : RPT_INFO,
+ "Total files %d | Changed %d | Failed %d",
+ data.count_tot,
+ data.count_changed,
+ data.count_failed);
}
static bool bpath_absolute_convert_visit_cb(void *userdata, char *path_dst, const char *path_src)
{
- BPathRemap_Data *data = (BPathRemap_Data *)userdata;
-
- data->count_tot++;
-
- if (BLI_path_is_rel(path_src) == false) {
- return false; /* already absolute */
- }
- else {
- strcpy(path_dst, path_src);
- BLI_path_abs(path_dst, data->basedir);
- if (BLI_path_is_rel(path_dst) == false) {
- data->count_changed++;
- }
- else {
- BKE_reportf(data->reports, RPT_WARNING, "Path '%s' cannot be made absolute", path_src);
- data->count_failed++;
- }
- return true;
- }
+ BPathRemap_Data *data = (BPathRemap_Data *)userdata;
+
+ data->count_tot++;
+
+ if (BLI_path_is_rel(path_src) == false) {
+ return false; /* already absolute */
+ }
+ else {
+ strcpy(path_dst, path_src);
+ BLI_path_abs(path_dst, data->basedir);
+ if (BLI_path_is_rel(path_dst) == false) {
+ data->count_changed++;
+ }
+ else {
+ BKE_reportf(data->reports, RPT_WARNING, "Path '%s' cannot be made absolute", path_src);
+ data->count_failed++;
+ }
+ return true;
+ }
}
/* similar to BKE_bpath_relative_convert - keep in sync! */
void BKE_bpath_absolute_convert(Main *bmain, const char *basedir, ReportList *reports)
{
- BPathRemap_Data data = {NULL};
- const int flag = BKE_BPATH_TRAVERSE_SKIP_LIBRARY;
+ BPathRemap_Data data = {NULL};
+ const int flag = BKE_BPATH_TRAVERSE_SKIP_LIBRARY;
- if (basedir[0] == '\0') {
- CLOG_ERROR(&LOG, "basedir='', this is a bug");
- return;
- }
+ if (basedir[0] == '\0') {
+ CLOG_ERROR(&LOG, "basedir='', this is a bug");
+ return;
+ }
- data.basedir = basedir;
- data.reports = reports;
+ data.basedir = basedir;
+ data.reports = reports;
- BKE_bpath_traverse_main(bmain, bpath_absolute_convert_visit_cb, flag, (void *)&data);
+ BKE_bpath_traverse_main(bmain, bpath_absolute_convert_visit_cb, flag, (void *)&data);
- BKE_reportf(reports, data.count_failed ? RPT_WARNING : RPT_INFO,
- "Total files %d | Changed %d | Failed %d",
- data.count_tot, data.count_changed, data.count_failed);
+ BKE_reportf(reports,
+ data.count_failed ? RPT_WARNING : RPT_INFO,
+ "Total files %d | Changed %d | Failed %d",
+ data.count_tot,
+ data.count_changed,
+ data.count_failed);
}
/**
@@ -207,156 +217,162 @@ void BKE_bpath_absolute_convert(Main *bmain, const char *basedir, ReportList *re
* \returns found: 1/0.
*/
#define MAX_RECUR 16
-static bool missing_files_find__recursive(
- char *filename_new,
- const char *dirname,
- const char *filename,
- int64_t *r_filesize,
- int *r_recur_depth)
+static bool missing_files_find__recursive(char *filename_new,
+ const char *dirname,
+ const char *filename,
+ int64_t *r_filesize,
+ int *r_recur_depth)
{
- /* file searching stuff */
- DIR *dir;
- struct dirent *de;
- BLI_stat_t status;
- char path[FILE_MAX];
- int64_t size;
- bool found = false;
-
- dir = opendir(dirname);
-
- if (dir == NULL)
- return found;
-
- if (*r_filesize == -1)
- *r_filesize = 0; /* dir opened fine */
-
- while ((de = readdir(dir)) != NULL) {
-
- if (FILENAME_IS_CURRPAR(de->d_name))
- continue;
-
- BLI_join_dirfile(path, sizeof(path), dirname, de->d_name);
-
- if (BLI_stat(path, &status) == -1)
- continue; /* cant stat, don't bother with this file, could print debug info here */
-
- if (S_ISREG(status.st_mode)) { /* is file */
- if (BLI_path_ncmp(filename, de->d_name, FILE_MAX) == 0) { /* name matches */
- /* open the file to read its size */
- size = status.st_size;
- if ((size > 0) && (size > *r_filesize)) { /* find the biggest file */
- *r_filesize = size;
- BLI_strncpy(filename_new, path, FILE_MAX);
- found = true;
- }
- }
- }
- else if (S_ISDIR(status.st_mode)) { /* is subdir */
- if (*r_recur_depth <= MAX_RECUR) {
- (*r_recur_depth)++;
- found |= missing_files_find__recursive(filename_new, path, filename, r_filesize, r_recur_depth);
- (*r_recur_depth)--;
- }
- }
- }
- closedir(dir);
- return found;
+ /* file searching stuff */
+ DIR *dir;
+ struct dirent *de;
+ BLI_stat_t status;
+ char path[FILE_MAX];
+ int64_t size;
+ bool found = false;
+
+ dir = opendir(dirname);
+
+ if (dir == NULL)
+ return found;
+
+ if (*r_filesize == -1)
+ *r_filesize = 0; /* dir opened fine */
+
+ while ((de = readdir(dir)) != NULL) {
+
+ if (FILENAME_IS_CURRPAR(de->d_name))
+ continue;
+
+ BLI_join_dirfile(path, sizeof(path), dirname, de->d_name);
+
+ if (BLI_stat(path, &status) == -1)
+ continue; /* cant stat, don't bother with this file, could print debug info here */
+
+ if (S_ISREG(status.st_mode)) { /* is file */
+ if (BLI_path_ncmp(filename, de->d_name, FILE_MAX) == 0) { /* name matches */
+ /* open the file to read its size */
+ size = status.st_size;
+ if ((size > 0) && (size > *r_filesize)) { /* find the biggest file */
+ *r_filesize = size;
+ BLI_strncpy(filename_new, path, FILE_MAX);
+ found = true;
+ }
+ }
+ }
+ else if (S_ISDIR(status.st_mode)) { /* is subdir */
+ if (*r_recur_depth <= MAX_RECUR) {
+ (*r_recur_depth)++;
+ found |= missing_files_find__recursive(
+ filename_new, path, filename, r_filesize, r_recur_depth);
+ (*r_recur_depth)--;
+ }
+ }
+ }
+ closedir(dir);
+ return found;
}
typedef struct BPathFind_Data {
- const char *basedir;
- const char *searchdir;
- ReportList *reports;
- bool find_all;
+ const char *basedir;
+ const char *searchdir;
+ ReportList *reports;
+ bool find_all;
} BPathFind_Data;
static bool missing_files_find__visit_cb(void *userdata, char *path_dst, const char *path_src)
{
- BPathFind_Data *data = (BPathFind_Data *)userdata;
- char filename_new[FILE_MAX];
-
- int64_t filesize = -1;
- int recur_depth = 0;
- bool found;
-
- if (data->find_all == false) {
- if (BLI_exists(path_src)) {
- return false;
- }
- }
-
- filename_new[0] = '\0';
-
- found = missing_files_find__recursive(
- filename_new,
- data->searchdir, BLI_path_basename(path_src),
- &filesize, &recur_depth);
-
- if (filesize == -1) { /* could not open dir */
- BKE_reportf(data->reports, RPT_WARNING,
- "Could not open directory '%s'",
- BLI_path_basename(data->searchdir));
- return false;
- }
- else if (found == false) {
- BKE_reportf(data->reports, RPT_WARNING,
- "Could not find '%s' in '%s'",
- BLI_path_basename(path_src), data->searchdir);
- return false;
- }
- else {
- bool was_relative = BLI_path_is_rel(path_dst);
-
- BLI_strncpy(path_dst, filename_new, FILE_MAX);
-
- /* keep path relative if the previous one was relative */
- if (was_relative)
- BLI_path_rel(path_dst, data->basedir);
-
- return true;
- }
+ BPathFind_Data *data = (BPathFind_Data *)userdata;
+ char filename_new[FILE_MAX];
+
+ int64_t filesize = -1;
+ int recur_depth = 0;
+ bool found;
+
+ if (data->find_all == false) {
+ if (BLI_exists(path_src)) {
+ return false;
+ }
+ }
+
+ filename_new[0] = '\0';
+
+ found = missing_files_find__recursive(
+ filename_new, data->searchdir, BLI_path_basename(path_src), &filesize, &recur_depth);
+
+ if (filesize == -1) { /* could not open dir */
+ BKE_reportf(data->reports,
+ RPT_WARNING,
+ "Could not open directory '%s'",
+ BLI_path_basename(data->searchdir));
+ return false;
+ }
+ else if (found == false) {
+ BKE_reportf(data->reports,
+ RPT_WARNING,
+ "Could not find '%s' in '%s'",
+ BLI_path_basename(path_src),
+ data->searchdir);
+ return false;
+ }
+ else {
+ bool was_relative = BLI_path_is_rel(path_dst);
+
+ BLI_strncpy(path_dst, filename_new, FILE_MAX);
+
+ /* keep path relative if the previous one was relative */
+ if (was_relative)
+ BLI_path_rel(path_dst, data->basedir);
+
+ return true;
+ }
}
-void BKE_bpath_missing_files_find(Main *bmain, const char *searchpath, ReportList *reports,
+void BKE_bpath_missing_files_find(Main *bmain,
+ const char *searchpath,
+ ReportList *reports,
const bool find_all)
{
- struct BPathFind_Data data = {NULL};
- const int flag = BKE_BPATH_TRAVERSE_ABS | BKE_BPATH_TRAVERSE_RELOAD_EDITED;
+ struct BPathFind_Data data = {NULL};
+ const int flag = BKE_BPATH_TRAVERSE_ABS | BKE_BPATH_TRAVERSE_RELOAD_EDITED;
- data.basedir = BKE_main_blendfile_path(bmain);
- data.reports = reports;
- data.searchdir = searchpath;
- data.find_all = find_all;
+ data.basedir = BKE_main_blendfile_path(bmain);
+ data.reports = reports;
+ data.searchdir = searchpath;
+ data.find_all = find_all;
- BKE_bpath_traverse_main(bmain, missing_files_find__visit_cb, flag, (void *)&data);
+ BKE_bpath_traverse_main(bmain, missing_files_find__visit_cb, flag, (void *)&data);
}
/* Run a visitor on a string, replacing the contents of the string as needed. */
-static bool rewrite_path_fixed(char *path, BPathVisitor visit_cb, const char *absbase, void *userdata)
+static bool rewrite_path_fixed(char *path,
+ BPathVisitor visit_cb,
+ const char *absbase,
+ void *userdata)
{
- char path_src_buf[FILE_MAX];
- const char *path_src;
- char path_dst[FILE_MAX];
-
- if (absbase) {
- BLI_strncpy(path_src_buf, path, sizeof(path_src_buf));
- BLI_path_abs(path_src_buf, absbase);
- path_src = path_src_buf;
- }
- else {
- path_src = path;
- }
-
- /* so functions can check old value */
- BLI_strncpy(path_dst, path, FILE_MAX);
-
- if (visit_cb(userdata, path_dst, path_src)) {
- BLI_strncpy(path, path_dst, FILE_MAX);
- return true;
- }
- else {
- return false;
- }
+ char path_src_buf[FILE_MAX];
+ const char *path_src;
+ char path_dst[FILE_MAX];
+
+ if (absbase) {
+ BLI_strncpy(path_src_buf, path, sizeof(path_src_buf));
+ BLI_path_abs(path_src_buf, absbase);
+ path_src = path_src_buf;
+ }
+ else {
+ path_src = path;
+ }
+
+ /* so functions can check old value */
+ BLI_strncpy(path_dst, path, FILE_MAX);
+
+ if (visit_cb(userdata, path_dst, path_src)) {
+ BLI_strncpy(path, path_dst, FILE_MAX);
+ return true;
+ }
+ else {
+ return false;
+ }
}
static bool rewrite_path_fixed_dirfile(char path_dir[FILE_MAXDIR],
@@ -365,338 +381,330 @@ static bool rewrite_path_fixed_dirfile(char path_dir[FILE_MAXDIR],
const char *absbase,
void *userdata)
{
- char path_src[FILE_MAX];
- char path_dst[FILE_MAX];
+ char path_src[FILE_MAX];
+ char path_dst[FILE_MAX];
- BLI_join_dirfile(path_src, sizeof(path_src), path_dir, path_file);
+ BLI_join_dirfile(path_src, sizeof(path_src), path_dir, path_file);
- /* so functions can check old value */
- BLI_strncpy(path_dst, path_src, FILE_MAX);
+ /* so functions can check old value */
+ BLI_strncpy(path_dst, path_src, FILE_MAX);
- if (absbase) {
- BLI_path_abs(path_src, absbase);
- }
+ if (absbase) {
+ BLI_path_abs(path_src, absbase);
+ }
- if (visit_cb(userdata, path_dst, (const char *)path_src)) {
- BLI_split_dirfile(path_dst, path_dir, path_file, FILE_MAXDIR, FILE_MAXFILE);
- return true;
- }
- else {
- return false;
- }
+ if (visit_cb(userdata, path_dst, (const char *)path_src)) {
+ BLI_split_dirfile(path_dst, path_dir, path_file, FILE_MAXDIR, FILE_MAXFILE);
+ return true;
+ }
+ else {
+ return false;
+ }
}
-static bool rewrite_path_alloc(char **path, BPathVisitor visit_cb, const char *absbase, void *userdata)
+static bool rewrite_path_alloc(char **path,
+ BPathVisitor visit_cb,
+ const char *absbase,
+ void *userdata)
{
- char path_src_buf[FILE_MAX];
- const char *path_src;
- char path_dst[FILE_MAX];
-
- if (absbase) {
- BLI_strncpy(path_src_buf, *path, sizeof(path_src_buf));
- BLI_path_abs(path_src_buf, absbase);
- path_src = path_src_buf;
- }
- else {
- path_src = *path;
- }
-
- if (visit_cb(userdata, path_dst, path_src)) {
- MEM_freeN(*path);
- (*path) = BLI_strdup(path_dst);
- return true;
- }
- else {
- return false;
- }
+ char path_src_buf[FILE_MAX];
+ const char *path_src;
+ char path_dst[FILE_MAX];
+
+ if (absbase) {
+ BLI_strncpy(path_src_buf, *path, sizeof(path_src_buf));
+ BLI_path_abs(path_src_buf, absbase);
+ path_src = path_src_buf;
+ }
+ else {
+ path_src = *path;
+ }
+
+ if (visit_cb(userdata, path_dst, path_src)) {
+ MEM_freeN(*path);
+ (*path) = BLI_strdup(path_dst);
+ return true;
+ }
+ else {
+ return false;
+ }
}
/* Run visitor function 'visit' on all paths contained in 'id'. */
-void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int flag, void *bpath_user_data)
+void BKE_bpath_traverse_id(
+ Main *bmain, ID *id, BPathVisitor visit_cb, const int flag, void *bpath_user_data)
{
- const char *absbase = (flag & BKE_BPATH_TRAVERSE_ABS) ? ID_BLEND_PATH(bmain, id) : NULL;
-
- if ((flag & BKE_BPATH_TRAVERSE_SKIP_LIBRARY) && ID_IS_LINKED(id)) {
- return;
- }
-
- switch (GS(id->name)) {
- case ID_IM:
- {
- Image *ima;
- ima = (Image *)id;
- if (BKE_image_has_packedfile(ima) == false || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) {
- if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) {
- if (rewrite_path_fixed(ima->name, visit_cb, absbase, bpath_user_data)) {
- if (flag & BKE_BPATH_TRAVERSE_RELOAD_EDITED) {
- if (!BKE_image_has_packedfile(ima) &&
- /* image may have been painted onto (and not saved, T44543) */
- !BKE_image_is_dirty(ima))
- {
- BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_RELOAD);
- }
- }
- }
- }
- }
- break;
- }
- case ID_BR:
- {
- Brush *brush = (Brush *)id;
- if (brush->icon_filepath[0]) {
- rewrite_path_fixed(brush->icon_filepath, visit_cb, absbase, bpath_user_data);
- }
- break;
- }
- case ID_OB:
- {
- Object *ob = (Object *)id;
- ModifierData *md;
- ParticleSystem *psys;
-
-#define BPATH_TRAVERSE_POINTCACHE(ptcaches) \
- { \
- PointCache *cache; \
- for (cache = (ptcaches).first; cache; cache = cache->next) { \
- if (cache->flag & PTCACHE_DISK_CACHE) { \
- rewrite_path_fixed(cache->path, \
- visit_cb, \
- absbase, \
- bpath_user_data); \
- } \
- } \
- } (void)0
-
- for (md = ob->modifiers.first; md; md = md->next) {
- if (md->type == eModifierType_Fluidsim) {
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)md;
- if (fluidmd->fss) {
- rewrite_path_fixed(fluidmd->fss->surfdataPath, visit_cb, absbase, bpath_user_data);
- }
- }
- else if (md->type == eModifierType_Smoke) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
- if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
- BPATH_TRAVERSE_POINTCACHE(smd->domain->ptcaches[0]);
- }
- }
- else if (md->type == eModifierType_Cloth) {
- ClothModifierData *clmd = (ClothModifierData *) md;
- BPATH_TRAVERSE_POINTCACHE(clmd->ptcaches);
- }
- else if (md->type == eModifierType_Ocean) {
- OceanModifierData *omd = (OceanModifierData *) md;
- rewrite_path_fixed(omd->cachepath, visit_cb, absbase, bpath_user_data);
- }
- else if (md->type == eModifierType_MeshCache) {
- MeshCacheModifierData *mcmd = (MeshCacheModifierData *) md;
- rewrite_path_fixed(mcmd->filepath, visit_cb, absbase, bpath_user_data);
- }
- }
-
- if (ob->soft) {
- BPATH_TRAVERSE_POINTCACHE(ob->soft->shared->ptcaches);
- }
-
- for (psys = ob->particlesystem.first; psys; psys = psys->next) {
- BPATH_TRAVERSE_POINTCACHE(psys->ptcaches);
- }
+ const char *absbase = (flag & BKE_BPATH_TRAVERSE_ABS) ? ID_BLEND_PATH(bmain, id) : NULL;
+
+ if ((flag & BKE_BPATH_TRAVERSE_SKIP_LIBRARY) && ID_IS_LINKED(id)) {
+ return;
+ }
+
+ switch (GS(id->name)) {
+ case ID_IM: {
+ Image *ima;
+ ima = (Image *)id;
+ if (BKE_image_has_packedfile(ima) == false || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) {
+ if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) {
+ if (rewrite_path_fixed(ima->name, visit_cb, absbase, bpath_user_data)) {
+ if (flag & BKE_BPATH_TRAVERSE_RELOAD_EDITED) {
+ if (!BKE_image_has_packedfile(ima) &&
+ /* image may have been painted onto (and not saved, T44543) */
+ !BKE_image_is_dirty(ima)) {
+ BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_RELOAD);
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+ case ID_BR: {
+ Brush *brush = (Brush *)id;
+ if (brush->icon_filepath[0]) {
+ rewrite_path_fixed(brush->icon_filepath, visit_cb, absbase, bpath_user_data);
+ }
+ break;
+ }
+ case ID_OB: {
+ Object *ob = (Object *)id;
+ ModifierData *md;
+ ParticleSystem *psys;
+
+#define BPATH_TRAVERSE_POINTCACHE(ptcaches) \
+ { \
+ PointCache *cache; \
+ for (cache = (ptcaches).first; cache; cache = cache->next) { \
+ if (cache->flag & PTCACHE_DISK_CACHE) { \
+ rewrite_path_fixed(cache->path, visit_cb, absbase, bpath_user_data); \
+ } \
+ } \
+ } \
+ (void)0
+
+ for (md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_Fluidsim) {
+ FluidsimModifierData *fluidmd = (FluidsimModifierData *)md;
+ if (fluidmd->fss) {
+ rewrite_path_fixed(fluidmd->fss->surfdataPath, visit_cb, absbase, bpath_user_data);
+ }
+ }
+ else if (md->type == eModifierType_Smoke) {
+ SmokeModifierData *smd = (SmokeModifierData *)md;
+ if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
+ BPATH_TRAVERSE_POINTCACHE(smd->domain->ptcaches[0]);
+ }
+ }
+ else if (md->type == eModifierType_Cloth) {
+ ClothModifierData *clmd = (ClothModifierData *)md;
+ BPATH_TRAVERSE_POINTCACHE(clmd->ptcaches);
+ }
+ else if (md->type == eModifierType_Ocean) {
+ OceanModifierData *omd = (OceanModifierData *)md;
+ rewrite_path_fixed(omd->cachepath, visit_cb, absbase, bpath_user_data);
+ }
+ else if (md->type == eModifierType_MeshCache) {
+ MeshCacheModifierData *mcmd = (MeshCacheModifierData *)md;
+ rewrite_path_fixed(mcmd->filepath, visit_cb, absbase, bpath_user_data);
+ }
+ }
+
+ if (ob->soft) {
+ BPATH_TRAVERSE_POINTCACHE(ob->soft->shared->ptcaches);
+ }
+
+ for (psys = ob->particlesystem.first; psys; psys = psys->next) {
+ BPATH_TRAVERSE_POINTCACHE(psys->ptcaches);
+ }
#undef BPATH_TRAVERSE_POINTCACHE
- break;
- }
- case ID_SO:
- {
- bSound *sound = (bSound *)id;
- if (sound->packedfile == NULL || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) {
- rewrite_path_fixed(sound->name, visit_cb, absbase, bpath_user_data);
- }
- break;
- }
- case ID_TXT:
- if (((Text *)id)->name) {
- rewrite_path_alloc(&((Text *)id)->name, visit_cb, absbase, bpath_user_data);
- }
- break;
- case ID_VF:
- {
- VFont *vfont = (VFont *)id;
- if (vfont->packedfile == NULL || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) {
- if (BKE_vfont_is_builtin(vfont) == false) {
- rewrite_path_fixed(((VFont *)id)->name, visit_cb, absbase, bpath_user_data);
- }
- }
- break;
- }
- case ID_MA:
- {
- Material *ma = (Material *)id;
- bNodeTree *ntree = ma->nodetree;
-
- if (ntree) {
- bNode *node;
-
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == SH_NODE_SCRIPT) {
- NodeShaderScript *nss = (NodeShaderScript *)node->storage;
- rewrite_path_fixed(nss->filepath, visit_cb, absbase, bpath_user_data);
- }
- else if (node->type == SH_NODE_TEX_IES) {
- NodeShaderTexIES *ies = (NodeShaderTexIES *)node->storage;
- rewrite_path_fixed(ies->filepath, visit_cb, absbase, bpath_user_data);
- }
- }
- }
- break;
- }
- case ID_NT:
- {
- bNodeTree *ntree = (bNodeTree *)id;
- bNode *node;
-
- if (ntree->type == NTREE_SHADER) {
- /* same as lines above */
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == SH_NODE_SCRIPT) {
- NodeShaderScript *nss = (NodeShaderScript *)node->storage;
- rewrite_path_fixed(nss->filepath, visit_cb, absbase, bpath_user_data);
- }
- else if (node->type == SH_NODE_TEX_IES) {
- NodeShaderTexIES *ies = (NodeShaderTexIES *)node->storage;
- rewrite_path_fixed(ies->filepath, visit_cb, absbase, bpath_user_data);
- }
- }
- }
- break;
- }
- case ID_SCE:
- {
- Scene *scene = (Scene *)id;
- if (scene->ed) {
- Sequence *seq;
-
- SEQ_BEGIN(scene->ed, seq)
- {
- if (SEQ_HAS_PATH(seq)) {
- StripElem *se = seq->strip->stripdata;
-
- if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_SOUND_RAM) && se) {
- rewrite_path_fixed_dirfile(seq->strip->dir, se->name,
- visit_cb, absbase, bpath_user_data);
- }
- else if ((seq->type == SEQ_TYPE_IMAGE) && se) {
- /* might want an option not to loop over all strips */
- unsigned int len = (unsigned int)MEM_allocN_len(se) / (unsigned int)sizeof(*se);
- unsigned int i;
-
- if (flag & BKE_BPATH_TRAVERSE_SKIP_MULTIFILE) {
- /* only operate on one path */
- len = MIN2(1u, len);
- }
-
- for (i = 0; i < len; i++, se++) {
- rewrite_path_fixed_dirfile(seq->strip->dir, se->name,
- visit_cb, absbase, bpath_user_data);
- }
- }
- else {
- /* simple case */
- rewrite_path_fixed(seq->strip->dir, visit_cb, absbase, bpath_user_data);
- }
- }
- } SEQ_END;
- }
- break;
- }
- case ID_ME:
- {
- Mesh *me = (Mesh *)id;
- if (me->ldata.external) {
- rewrite_path_fixed(me->ldata.external->filename, visit_cb, absbase, bpath_user_data);
- }
- break;
- }
- case ID_LI:
- {
- Library *lib = (Library *)id;
- /* keep packedfile paths always relative to the blend */
- if (lib->packedfile == NULL) {
- if (rewrite_path_fixed(lib->name, visit_cb, absbase, bpath_user_data)) {
- BKE_library_filepath_set(bmain, lib, lib->name);
- }
- }
- break;
- }
- case ID_MC:
- {
- MovieClip *clip = (MovieClip *)id;
- rewrite_path_fixed(clip->name, visit_cb, absbase, bpath_user_data);
- break;
- }
- case ID_CF:
- {
- CacheFile *cache_file = (CacheFile *)id;
- rewrite_path_fixed(cache_file->filepath, visit_cb, absbase, bpath_user_data);
- break;
- }
- default:
- /* Nothing to do for other IDs that don't contain file paths. */
- break;
- }
+ break;
+ }
+ case ID_SO: {
+ bSound *sound = (bSound *)id;
+ if (sound->packedfile == NULL || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) {
+ rewrite_path_fixed(sound->name, visit_cb, absbase, bpath_user_data);
+ }
+ break;
+ }
+ case ID_TXT:
+ if (((Text *)id)->name) {
+ rewrite_path_alloc(&((Text *)id)->name, visit_cb, absbase, bpath_user_data);
+ }
+ break;
+ case ID_VF: {
+ VFont *vfont = (VFont *)id;
+ if (vfont->packedfile == NULL || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) {
+ if (BKE_vfont_is_builtin(vfont) == false) {
+ rewrite_path_fixed(((VFont *)id)->name, visit_cb, absbase, bpath_user_data);
+ }
+ }
+ break;
+ }
+ case ID_MA: {
+ Material *ma = (Material *)id;
+ bNodeTree *ntree = ma->nodetree;
+
+ if (ntree) {
+ bNode *node;
+
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_SCRIPT) {
+ NodeShaderScript *nss = (NodeShaderScript *)node->storage;
+ rewrite_path_fixed(nss->filepath, visit_cb, absbase, bpath_user_data);
+ }
+ else if (node->type == SH_NODE_TEX_IES) {
+ NodeShaderTexIES *ies = (NodeShaderTexIES *)node->storage;
+ rewrite_path_fixed(ies->filepath, visit_cb, absbase, bpath_user_data);
+ }
+ }
+ }
+ break;
+ }
+ case ID_NT: {
+ bNodeTree *ntree = (bNodeTree *)id;
+ bNode *node;
+
+ if (ntree->type == NTREE_SHADER) {
+ /* same as lines above */
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_SCRIPT) {
+ NodeShaderScript *nss = (NodeShaderScript *)node->storage;
+ rewrite_path_fixed(nss->filepath, visit_cb, absbase, bpath_user_data);
+ }
+ else if (node->type == SH_NODE_TEX_IES) {
+ NodeShaderTexIES *ies = (NodeShaderTexIES *)node->storage;
+ rewrite_path_fixed(ies->filepath, visit_cb, absbase, bpath_user_data);
+ }
+ }
+ }
+ break;
+ }
+ case ID_SCE: {
+ Scene *scene = (Scene *)id;
+ if (scene->ed) {
+ Sequence *seq;
+
+ SEQ_BEGIN (scene->ed, seq) {
+ if (SEQ_HAS_PATH(seq)) {
+ StripElem *se = seq->strip->stripdata;
+
+ if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_SOUND_RAM) && se) {
+ rewrite_path_fixed_dirfile(
+ seq->strip->dir, se->name, visit_cb, absbase, bpath_user_data);
+ }
+ else if ((seq->type == SEQ_TYPE_IMAGE) && se) {
+ /* might want an option not to loop over all strips */
+ unsigned int len = (unsigned int)MEM_allocN_len(se) / (unsigned int)sizeof(*se);
+ unsigned int i;
+
+ if (flag & BKE_BPATH_TRAVERSE_SKIP_MULTIFILE) {
+ /* only operate on one path */
+ len = MIN2(1u, len);
+ }
+
+ for (i = 0; i < len; i++, se++) {
+ rewrite_path_fixed_dirfile(
+ seq->strip->dir, se->name, visit_cb, absbase, bpath_user_data);
+ }
+ }
+ else {
+ /* simple case */
+ rewrite_path_fixed(seq->strip->dir, visit_cb, absbase, bpath_user_data);
+ }
+ }
+ }
+ SEQ_END;
+ }
+ break;
+ }
+ case ID_ME: {
+ Mesh *me = (Mesh *)id;
+ if (me->ldata.external) {
+ rewrite_path_fixed(me->ldata.external->filename, visit_cb, absbase, bpath_user_data);
+ }
+ break;
+ }
+ case ID_LI: {
+ Library *lib = (Library *)id;
+ /* keep packedfile paths always relative to the blend */
+ if (lib->packedfile == NULL) {
+ if (rewrite_path_fixed(lib->name, visit_cb, absbase, bpath_user_data)) {
+ BKE_library_filepath_set(bmain, lib, lib->name);
+ }
+ }
+ break;
+ }
+ case ID_MC: {
+ MovieClip *clip = (MovieClip *)id;
+ rewrite_path_fixed(clip->name, visit_cb, absbase, bpath_user_data);
+ break;
+ }
+ case ID_CF: {
+ CacheFile *cache_file = (CacheFile *)id;
+ rewrite_path_fixed(cache_file->filepath, visit_cb, absbase, bpath_user_data);
+ break;
+ }
+ default:
+ /* Nothing to do for other IDs that don't contain file paths. */
+ break;
+ }
}
-void BKE_bpath_traverse_id_list(Main *bmain, ListBase *lb, BPathVisitor visit_cb, const int flag, void *bpath_user_data)
+void BKE_bpath_traverse_id_list(
+ Main *bmain, ListBase *lb, BPathVisitor visit_cb, const int flag, void *bpath_user_data)
{
- ID *id;
- for (id = lb->first; id; id = id->next) {
- BKE_bpath_traverse_id(bmain, id, visit_cb, flag, bpath_user_data);
- }
+ ID *id;
+ for (id = lb->first; id; id = id->next) {
+ BKE_bpath_traverse_id(bmain, id, visit_cb, flag, bpath_user_data);
+ }
}
-void BKE_bpath_traverse_main(Main *bmain, BPathVisitor visit_cb, const int flag, void *bpath_user_data)
+void BKE_bpath_traverse_main(Main *bmain,
+ BPathVisitor visit_cb,
+ const int flag,
+ void *bpath_user_data)
{
- ListBase *lbarray[MAX_LIBARRAY];
- int a = set_listbasepointers(bmain, lbarray);
- while (a--) {
- BKE_bpath_traverse_id_list(bmain, lbarray[a], visit_cb, flag, bpath_user_data);
- }
+ ListBase *lbarray[MAX_LIBARRAY];
+ int a = set_listbasepointers(bmain, lbarray);
+ while (a--) {
+ BKE_bpath_traverse_id_list(bmain, lbarray[a], visit_cb, flag, bpath_user_data);
+ }
}
/* Rewrites a relative path to be relative to the main file - unless the path is
* absolute, in which case it is not altered. */
bool BKE_bpath_relocate_visitor(void *pathbase_v, char *path_dst, const char *path_src)
{
- /* be sure there is low chance of the path being too short */
- char filepath[(FILE_MAXDIR * 2) + FILE_MAXFILE];
- const char *base_new = ((char **)pathbase_v)[0];
- const char *base_old = ((char **)pathbase_v)[1];
-
- if (BLI_path_is_rel(base_old)) {
- CLOG_ERROR(&LOG, "old base path '%s' is not absolute.", base_old);
- return false;
- }
-
- /* Make referenced file absolute. This would be a side-effect of
- * BLI_cleanup_file, but we do it explicitly so we know if it changed. */
- BLI_strncpy(filepath, path_src, FILE_MAX);
- if (BLI_path_abs(filepath, base_old)) {
- /* Path was relative and is now absolute. Remap.
- * Important BLI_cleanup_dir runs before the path is made relative
- * because it wont work for paths that start with "//../" */
- BLI_cleanup_file(base_new, filepath);
- BLI_path_rel(filepath, base_new);
- BLI_strncpy(path_dst, filepath, FILE_MAX);
- return true;
- }
- else {
- /* Path was not relative to begin with. */
- return false;
- }
+ /* be sure there is low chance of the path being too short */
+ char filepath[(FILE_MAXDIR * 2) + FILE_MAXFILE];
+ const char *base_new = ((char **)pathbase_v)[0];
+ const char *base_old = ((char **)pathbase_v)[1];
+
+ if (BLI_path_is_rel(base_old)) {
+ CLOG_ERROR(&LOG, "old base path '%s' is not absolute.", base_old);
+ return false;
+ }
+
+ /* Make referenced file absolute. This would be a side-effect of
+ * BLI_cleanup_file, but we do it explicitly so we know if it changed. */
+ BLI_strncpy(filepath, path_src, FILE_MAX);
+ if (BLI_path_abs(filepath, base_old)) {
+ /* Path was relative and is now absolute. Remap.
+ * Important BLI_cleanup_dir runs before the path is made relative
+ * because it wont work for paths that start with "//../" */
+ BLI_cleanup_file(base_new, filepath);
+ BLI_path_rel(filepath, base_new);
+ BLI_strncpy(path_dst, filepath, FILE_MAX);
+ return true;
+ }
+ else {
+ /* Path was not relative to begin with. */
+ return false;
+ }
}
-
/* -------------------------------------------------------------------- */
/**
* Backup/Restore/Free functions,
@@ -704,64 +712,64 @@ bool BKE_bpath_relocate_visitor(void *pathbase_v, char *path_dst, const char *pa
*/
struct PathStore {
- struct PathStore *next, *prev;
+ struct PathStore *next, *prev;
};
static bool bpath_list_append(void *userdata, char *UNUSED(path_dst), const char *path_src)
{
- /* store the path and string in a single alloc */
- ListBase *ls = userdata;
- size_t path_size = strlen(path_src) + 1;
- struct PathStore *path_store = MEM_mallocN(sizeof(struct PathStore) + path_size, __func__);
- char *filepath = (char *)(path_store + 1);
-
- memcpy(filepath, path_src, path_size);
- BLI_addtail(ls, path_store);
- return false;
+ /* store the path and string in a single alloc */
+ ListBase *ls = userdata;
+ size_t path_size = strlen(path_src) + 1;
+ struct PathStore *path_store = MEM_mallocN(sizeof(struct PathStore) + path_size, __func__);
+ char *filepath = (char *)(path_store + 1);
+
+ memcpy(filepath, path_src, path_size);
+ BLI_addtail(ls, path_store);
+ return false;
}
static bool bpath_list_restore(void *userdata, char *path_dst, const char *path_src)
{
- /* assume ls->first wont be NULL because the number of paths can't change!
- * (if they do caller is wrong) */
- ListBase *ls = userdata;
- struct PathStore *path_store = ls->first;
- const char *filepath = (char *)(path_store + 1);
- bool ret;
-
- if (STREQ(path_src, filepath)) {
- ret = false;
- }
- else {
- BLI_strncpy(path_dst, filepath, FILE_MAX);
- ret = true;
- }
-
- BLI_freelinkN(ls, path_store);
- return ret;
+ /* assume ls->first wont be NULL because the number of paths can't change!
+ * (if they do caller is wrong) */
+ ListBase *ls = userdata;
+ struct PathStore *path_store = ls->first;
+ const char *filepath = (char *)(path_store + 1);
+ bool ret;
+
+ if (STREQ(path_src, filepath)) {
+ ret = false;
+ }
+ else {
+ BLI_strncpy(path_dst, filepath, FILE_MAX);
+ ret = true;
+ }
+
+ BLI_freelinkN(ls, path_store);
+ return ret;
}
/* return ls_handle */
void *BKE_bpath_list_backup(Main *bmain, const int flag)
{
- ListBase *ls = MEM_callocN(sizeof(ListBase), __func__);
+ ListBase *ls = MEM_callocN(sizeof(ListBase), __func__);
- BKE_bpath_traverse_main(bmain, bpath_list_append, flag, ls);
+ BKE_bpath_traverse_main(bmain, bpath_list_append, flag, ls);
- return ls;
+ return ls;
}
void BKE_bpath_list_restore(Main *bmain, const int flag, void *ls_handle)
{
- ListBase *ls = ls_handle;
+ ListBase *ls = ls_handle;
- BKE_bpath_traverse_main(bmain, bpath_list_restore, flag, ls);
+ BKE_bpath_traverse_main(bmain, bpath_list_restore, flag, ls);
}
void BKE_bpath_list_free(void *ls_handle)
{
- ListBase *ls = ls_handle;
- BLI_assert(BLI_listbase_is_empty(ls)); /* assumes we were used */
- BLI_freelistN(ls);
- MEM_freeN(ls);
+ ListBase *ls = ls_handle;
+ BLI_assert(BLI_listbase_is_empty(ls)); /* assumes we were used */
+ BLI_freelistN(ls);
+ MEM_freeN(ls);
}
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index bc6c0782726..56a6de62dab 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -49,99 +49,99 @@ static RNG *brush_rng;
void BKE_brush_system_init(void)
{
- brush_rng = BLI_rng_new(0);
- BLI_rng_srandom(brush_rng, 31415682);
+ brush_rng = BLI_rng_new(0);
+ BLI_rng_srandom(brush_rng, 31415682);
}
void BKE_brush_system_exit(void)
{
- BLI_rng_free(brush_rng);
+ BLI_rng_free(brush_rng);
}
-
static void brush_defaults(Brush *brush)
{
- brush->blend = 0;
- brush->flag = 0;
-
- brush->ob_mode = OB_MODE_ALL_PAINT;
-
- /* BRUSH SCULPT TOOL SETTINGS */
- brush->weight = 1.0f; /* weight of brush 0 - 1.0 */
- brush->size = 35; /* radius of the brush in pixels */
- brush->alpha = 0.5f; /* brush strength/intensity probably variable should be renamed? */
- brush->autosmooth_factor = 0.0f;
- brush->topology_rake_factor = 0.0f;
- brush->crease_pinch_factor = 0.5f;
- brush->sculpt_plane = SCULPT_DISP_DIR_AREA;
- brush->plane_offset = 0.0f; /* how far above or below the plane that is found by averaging the faces */
- brush->plane_trim = 0.5f;
- brush->clone.alpha = 0.5f;
- brush->normal_weight = 0.0f;
- brush->fill_threshold = 0.2f;
- brush->flag |= BRUSH_ALPHA_PRESSURE;
-
- /* BRUSH PAINT TOOL SETTINGS */
- brush->rgb[0] = 1.0f; /* default rgb color of the brush when painting - white */
- brush->rgb[1] = 1.0f;
- brush->rgb[2] = 1.0f;
-
- zero_v3(brush->secondary_rgb);
-
- /* BRUSH STROKE SETTINGS */
- brush->flag |= (BRUSH_SPACE | BRUSH_SPACE_ATTEN);
- brush->spacing = 10; /* how far each brush dot should be spaced as a percentage of brush diameter */
-
- brush->smooth_stroke_radius = 75;
- brush->smooth_stroke_factor = 0.9f;
-
- brush->rate = 0.1f; /* time delay between dots of paint or sculpting when doing airbrush mode */
-
- brush->jitter = 0.0f;
-
- /* BRUSH TEXTURE SETTINGS */
- BKE_texture_mtex_default(&brush->mtex);
- BKE_texture_mtex_default(&brush->mask_mtex);
-
- brush->texture_sample_bias = 0; /* value to added to texture samples */
- brush->texture_overlay_alpha = 33;
- brush->mask_overlay_alpha = 33;
- brush->cursor_overlay_alpha = 33;
- brush->overlay_flags = 0;
-
- /* brush appearance */
-
- brush->add_col[0] = 1.00; /* add mode color is light red */
- brush->add_col[1] = 0.39;
- brush->add_col[2] = 0.39;
-
- brush->sub_col[0] = 0.39; /* subtract mode color is light blue */
- brush->sub_col[1] = 0.39;
- brush->sub_col[2] = 1.00;
-
- brush->stencil_pos[0] = 256;
- brush->stencil_pos[1] = 256;
-
- brush->stencil_dimension[0] = 256;
- brush->stencil_dimension[1] = 256;
-
+ brush->blend = 0;
+ brush->flag = 0;
+
+ brush->ob_mode = OB_MODE_ALL_PAINT;
+
+ /* BRUSH SCULPT TOOL SETTINGS */
+ brush->weight = 1.0f; /* weight of brush 0 - 1.0 */
+ brush->size = 35; /* radius of the brush in pixels */
+ brush->alpha = 0.5f; /* brush strength/intensity probably variable should be renamed? */
+ brush->autosmooth_factor = 0.0f;
+ brush->topology_rake_factor = 0.0f;
+ brush->crease_pinch_factor = 0.5f;
+ brush->sculpt_plane = SCULPT_DISP_DIR_AREA;
+ brush->plane_offset =
+ 0.0f; /* how far above or below the plane that is found by averaging the faces */
+ brush->plane_trim = 0.5f;
+ brush->clone.alpha = 0.5f;
+ brush->normal_weight = 0.0f;
+ brush->fill_threshold = 0.2f;
+ brush->flag |= BRUSH_ALPHA_PRESSURE;
+
+ /* BRUSH PAINT TOOL SETTINGS */
+ brush->rgb[0] = 1.0f; /* default rgb color of the brush when painting - white */
+ brush->rgb[1] = 1.0f;
+ brush->rgb[2] = 1.0f;
+
+ zero_v3(brush->secondary_rgb);
+
+ /* BRUSH STROKE SETTINGS */
+ brush->flag |= (BRUSH_SPACE | BRUSH_SPACE_ATTEN);
+ brush->spacing =
+ 10; /* how far each brush dot should be spaced as a percentage of brush diameter */
+
+ brush->smooth_stroke_radius = 75;
+ brush->smooth_stroke_factor = 0.9f;
+
+ brush->rate = 0.1f; /* time delay between dots of paint or sculpting when doing airbrush mode */
+
+ brush->jitter = 0.0f;
+
+ /* BRUSH TEXTURE SETTINGS */
+ BKE_texture_mtex_default(&brush->mtex);
+ BKE_texture_mtex_default(&brush->mask_mtex);
+
+ brush->texture_sample_bias = 0; /* value to added to texture samples */
+ brush->texture_overlay_alpha = 33;
+ brush->mask_overlay_alpha = 33;
+ brush->cursor_overlay_alpha = 33;
+ brush->overlay_flags = 0;
+
+ /* brush appearance */
+
+ brush->add_col[0] = 1.00; /* add mode color is light red */
+ brush->add_col[1] = 0.39;
+ brush->add_col[2] = 0.39;
+
+ brush->sub_col[0] = 0.39; /* subtract mode color is light blue */
+ brush->sub_col[1] = 0.39;
+ brush->sub_col[2] = 1.00;
+
+ brush->stencil_pos[0] = 256;
+ brush->stencil_pos[1] = 256;
+
+ brush->stencil_dimension[0] = 256;
+ brush->stencil_dimension[1] = 256;
}
/* Datablock add/copy/free/make_local */
void BKE_brush_init(Brush *brush)
{
- BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(brush, id));
+ BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(brush, id));
- /* enable fake user by default */
- id_fake_user_set(&brush->id);
+ /* enable fake user by default */
+ id_fake_user_set(&brush->id);
- brush_defaults(brush);
+ brush_defaults(brush);
- brush->sculpt_tool = SCULPT_TOOL_DRAW; /* sculpting defaults to the draw tool for new brushes */
+ brush->sculpt_tool = SCULPT_TOOL_DRAW; /* sculpting defaults to the draw tool for new brushes */
- /* the default alpha falloff curve */
- BKE_brush_curve_preset(brush, CURVE_PRESET_SMOOTH);
+ /* the default alpha falloff curve */
+ BKE_brush_curve_preset(brush, CURVE_PRESET_SMOOTH);
}
/**
@@ -149,116 +149,116 @@ void BKE_brush_init(Brush *brush)
*/
Brush *BKE_brush_add(Main *bmain, const char *name, const eObjectMode ob_mode)
{
- Brush *brush;
+ Brush *brush;
- brush = BKE_libblock_alloc(bmain, ID_BR, name, 0);
+ brush = BKE_libblock_alloc(bmain, ID_BR, name, 0);
- BKE_brush_init(brush);
+ BKE_brush_init(brush);
- brush->ob_mode = ob_mode;
+ brush->ob_mode = ob_mode;
- return brush;
+ return brush;
}
/* add grease pencil settings */
void BKE_brush_init_gpencil_settings(Brush *brush)
{
- if (brush->gpencil_settings == NULL) {
- brush->gpencil_settings = MEM_callocN(sizeof(BrushGpencilSettings), "BrushGpencilSettings");
- }
-
- brush->gpencil_settings->draw_smoothlvl = 1;
- brush->gpencil_settings->flag = 0;
- brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE;
- brush->gpencil_settings->draw_sensitivity = 1.0f;
- brush->gpencil_settings->draw_strength = 1.0f;
- brush->gpencil_settings->draw_jitter = 0.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
- brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN;
- brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR;
-
- /* curves */
- brush->gpencil_settings->curve_sensitivity = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
- brush->gpencil_settings->curve_strength = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
- brush->gpencil_settings->curve_jitter = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ if (brush->gpencil_settings == NULL) {
+ brush->gpencil_settings = MEM_callocN(sizeof(BrushGpencilSettings), "BrushGpencilSettings");
+ }
+
+ brush->gpencil_settings->draw_smoothlvl = 1;
+ brush->gpencil_settings->flag = 0;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE;
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+ brush->gpencil_settings->draw_strength = 1.0f;
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN;
+ brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR;
+
+ /* curves */
+ brush->gpencil_settings->curve_sensitivity = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ brush->gpencil_settings->curve_strength = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ brush->gpencil_settings->curve_jitter = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
}
/* add a new gp-brush */
Brush *BKE_brush_add_gpencil(Main *bmain, ToolSettings *ts, const char *name)
{
- Brush *brush;
- Paint *paint = &ts->gp_paint->paint;
- brush = BKE_brush_add(bmain, name, OB_MODE_PAINT_GPENCIL);
+ Brush *brush;
+ Paint *paint = &ts->gp_paint->paint;
+ brush = BKE_brush_add(bmain, name, OB_MODE_PAINT_GPENCIL);
- BKE_paint_brush_set(paint, brush);
- id_us_min(&brush->id);
+ BKE_paint_brush_set(paint, brush);
+ id_us_min(&brush->id);
- brush->size = 3;
+ brush->size = 3;
- /* grease pencil basic settings */
- BKE_brush_init_gpencil_settings(brush);
+ /* grease pencil basic settings */
+ BKE_brush_init_gpencil_settings(brush);
- /* return brush */
- return brush;
+ /* return brush */
+ return brush;
}
/* grease pencil cumapping->preset */
typedef enum eGPCurveMappingPreset {
- GPCURVE_PRESET_PENCIL = 0,
- GPCURVE_PRESET_INK = 1,
- GPCURVE_PRESET_INKNOISE = 2,
- GPCURVE_PRESET_MARKER = 3,
+ GPCURVE_PRESET_PENCIL = 0,
+ GPCURVE_PRESET_INK = 1,
+ GPCURVE_PRESET_INKNOISE = 2,
+ GPCURVE_PRESET_MARKER = 3,
} eGPCurveMappingPreset;
static void brush_gpencil_curvemap_reset(CurveMap *cuma, int tot, int preset)
{
- if (cuma->curve)
- MEM_freeN(cuma->curve);
-
- cuma->totpoint = tot;
- cuma->curve = MEM_callocN(cuma->totpoint * sizeof(CurveMapPoint), __func__);
-
- switch (preset) {
- case GPCURVE_PRESET_PENCIL:
- cuma->curve[0].x = 0.0f;
- cuma->curve[0].y = 0.0f;
- cuma->curve[1].x = 0.75115f;
- cuma->curve[1].y = 0.25f;
- cuma->curve[2].x = 1.0f;
- cuma->curve[2].y = 1.0f;
- break;
- case GPCURVE_PRESET_INK:
- cuma->curve[0].x = 0.0f;
- cuma->curve[0].y = 0.0f;
- cuma->curve[1].x = 0.63448f;
- cuma->curve[1].y = 0.375f;
- cuma->curve[2].x = 1.0f;
- cuma->curve[2].y = 1.0f;
- break;
- case GPCURVE_PRESET_INKNOISE:
- cuma->curve[0].x = 0.0f;
- cuma->curve[0].y = 0.0f;
- cuma->curve[1].x = 0.63134f;
- cuma->curve[1].y = 0.3625f;
- cuma->curve[2].x = 1.0f;
- cuma->curve[2].y = 1.0f;
- break;
- case GPCURVE_PRESET_MARKER:
- cuma->curve[0].x = 0.0f;
- cuma->curve[0].y = 0.0f;
- cuma->curve[1].x = 0.38f;
- cuma->curve[1].y = 0.22f;
- cuma->curve[2].x = 0.65f;
- cuma->curve[2].y = 0.68f;
- cuma->curve[3].x = 1.0f;
- cuma->curve[3].y = 1.0f;
- break;
- }
-
- if (cuma->table) {
- MEM_freeN(cuma->table);
- cuma->table = NULL;
- }
+ if (cuma->curve)
+ MEM_freeN(cuma->curve);
+
+ cuma->totpoint = tot;
+ cuma->curve = MEM_callocN(cuma->totpoint * sizeof(CurveMapPoint), __func__);
+
+ switch (preset) {
+ case GPCURVE_PRESET_PENCIL:
+ cuma->curve[0].x = 0.0f;
+ cuma->curve[0].y = 0.0f;
+ cuma->curve[1].x = 0.75115f;
+ cuma->curve[1].y = 0.25f;
+ cuma->curve[2].x = 1.0f;
+ cuma->curve[2].y = 1.0f;
+ break;
+ case GPCURVE_PRESET_INK:
+ cuma->curve[0].x = 0.0f;
+ cuma->curve[0].y = 0.0f;
+ cuma->curve[1].x = 0.63448f;
+ cuma->curve[1].y = 0.375f;
+ cuma->curve[2].x = 1.0f;
+ cuma->curve[2].y = 1.0f;
+ break;
+ case GPCURVE_PRESET_INKNOISE:
+ cuma->curve[0].x = 0.0f;
+ cuma->curve[0].y = 0.0f;
+ cuma->curve[1].x = 0.63134f;
+ cuma->curve[1].y = 0.3625f;
+ cuma->curve[2].x = 1.0f;
+ cuma->curve[2].y = 1.0f;
+ break;
+ case GPCURVE_PRESET_MARKER:
+ cuma->curve[0].x = 0.0f;
+ cuma->curve[0].y = 0.0f;
+ cuma->curve[1].x = 0.38f;
+ cuma->curve[1].y = 0.22f;
+ cuma->curve[2].x = 0.65f;
+ cuma->curve[2].y = 0.68f;
+ cuma->curve[3].x = 1.0f;
+ cuma->curve[3].y = 1.0f;
+ break;
+ }
+
+ if (cuma->table) {
+ MEM_freeN(cuma->table);
+ cuma->table = NULL;
+ }
}
/* create a set of grease pencil presets */
@@ -267,316 +267,315 @@ void BKE_brush_gpencil_presets(bContext *C)
#define SMOOTH_STROKE_RADIUS 40
#define SMOOTH_STROKE_FACTOR 0.9f
- ToolSettings *ts = CTX_data_tool_settings(C);
- Paint *paint = &ts->gp_paint->paint;
- Main *bmain = CTX_data_main(C);
-
- Brush *brush, *deft;
- CurveMapping *custom_curve;
-
- /* Pencil brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Draw Pencil");
- brush->size = 25.0f;
- brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
- brush->gpencil_settings->draw_sensitivity = 1.0f;
-
- brush->gpencil_settings->draw_strength = 0.6f;
- brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
-
- brush->gpencil_settings->draw_random_press = 0.0f;
-
- brush->gpencil_settings->draw_jitter = 0.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
-
- brush->gpencil_settings->draw_angle = 0.0f;
- brush->gpencil_settings->draw_angle_factor = 0.0f;
-
- brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
- brush->gpencil_settings->draw_smoothfac = 0.1f;
- brush->gpencil_settings->draw_smoothlvl = 1;
- brush->gpencil_settings->thick_smoothfac = 1.0f;
- brush->gpencil_settings->thick_smoothlvl = 3;
- brush->gpencil_settings->draw_subdivide = 1;
- brush->gpencil_settings->draw_random_sub = 0.0f;
- brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PENCIL;
- brush->gpencil_tool = GPAINT_TOOL_DRAW;
-
- brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
- brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
-
- brush->gpencil_settings->gradient_f = 1.0f;
- brush->gpencil_settings->gradient_s[0] = 1.0f;
- brush->gpencil_settings->gradient_s[1] = 1.0f;
-
- /* Pen brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Draw Pen");
- deft = brush; /* save default brush */
- brush->size = 30.0f;
- brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
- brush->gpencil_settings->draw_sensitivity = 1.0f;
-
- brush->gpencil_settings->draw_strength = 1.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
-
- brush->gpencil_settings->draw_random_press = 0.0f;
- brush->gpencil_settings->draw_random_strength = 0.0f;
-
- brush->gpencil_settings->draw_jitter = 0.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
-
- brush->gpencil_settings->draw_angle = 0.0f;
- brush->gpencil_settings->draw_angle_factor = 0.0f;
-
- brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
- brush->gpencil_settings->draw_smoothfac = 0.1f;
- brush->gpencil_settings->draw_smoothlvl = 1;
- brush->gpencil_settings->draw_subdivide = 1;
- brush->gpencil_settings->thick_smoothfac = 1.0f;
- brush->gpencil_settings->thick_smoothlvl = 3;
- brush->gpencil_settings->draw_random_sub = 0.0f;
- brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN;
- brush->gpencil_tool = GPAINT_TOOL_DRAW;
-
- brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
- brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
-
- brush->gpencil_settings->gradient_f = 1.0f;
- brush->gpencil_settings->gradient_s[0] = 1.0f;
- brush->gpencil_settings->gradient_s[1] = 1.0f;
-
- /* Ink brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Draw Ink");
- brush->size = 60.0f;
- brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
- brush->gpencil_settings->draw_sensitivity = 1.6f;
-
- brush->gpencil_settings->draw_strength = 1.0f;
-
- brush->gpencil_settings->draw_random_press = 0.0f;
-
- brush->gpencil_settings->draw_jitter = 0.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
-
- brush->gpencil_settings->draw_angle = 0.0f;
- brush->gpencil_settings->draw_angle_factor = 0.0f;
-
- brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
- brush->gpencil_settings->draw_smoothfac = 0.1f;
- brush->gpencil_settings->draw_smoothlvl = 1;
- brush->gpencil_settings->thick_smoothfac = 1.0f;
- brush->gpencil_settings->thick_smoothlvl = 3;
- brush->gpencil_settings->draw_subdivide = 1;
- brush->gpencil_settings->draw_random_sub = 0.0f;
- brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INK;
- brush->gpencil_tool = GPAINT_TOOL_DRAW;
-
- brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
- brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
-
- brush->gpencil_settings->gradient_f = 1.0f;
- brush->gpencil_settings->gradient_s[0] = 1.0f;
- brush->gpencil_settings->gradient_s[1] = 1.0f;
-
- /* Curve */
- custom_curve = brush->gpencil_settings->curve_sensitivity;
- curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
- curvemapping_initialize(custom_curve);
- brush_gpencil_curvemap_reset(custom_curve->cm, 3, GPCURVE_PRESET_INK);
-
- /* Ink Noise brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Draw Noise");
- brush->size = 60.0f;
- brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
- brush->gpencil_settings->draw_sensitivity = 1.0f;
-
- brush->gpencil_settings->draw_strength = 1.0f;
-
- brush->gpencil_settings->flag |= GP_BRUSH_GROUP_RANDOM;
- brush->gpencil_settings->draw_random_press = 0.7f;
- brush->gpencil_settings->draw_random_strength = 0.0f;
-
- brush->gpencil_settings->draw_jitter = 0.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
-
- brush->gpencil_settings->draw_angle = 0.0f;
- brush->gpencil_settings->draw_angle_factor = 0.0f;
-
- brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
- brush->gpencil_settings->draw_smoothfac = 0.1f;
- brush->gpencil_settings->draw_smoothlvl = 2;
- brush->gpencil_settings->thick_smoothfac = 0.5f;
- brush->gpencil_settings->thick_smoothlvl = 2;
- brush->gpencil_settings->draw_subdivide = 1;
- brush->gpencil_settings->draw_random_sub = 0.0f;
- brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INKNOISE;
- brush->gpencil_tool = GPAINT_TOOL_DRAW;
-
- brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
- brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
-
- /* Curve */
- custom_curve = brush->gpencil_settings->curve_sensitivity;
- curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
- curvemapping_initialize(custom_curve);
- brush_gpencil_curvemap_reset(custom_curve->cm, 3, GPCURVE_PRESET_INKNOISE);
-
- brush->gpencil_settings->gradient_f = 1.0f;
- brush->gpencil_settings->gradient_s[0] = 1.0f;
- brush->gpencil_settings->gradient_s[1] = 1.0f;
-
- /* Block Basic brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Draw Block");
- brush->size = 150.0f;
- brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
- brush->gpencil_settings->draw_sensitivity = 1.0f;
-
- brush->gpencil_settings->draw_strength = 1.0f;
-
- brush->gpencil_settings->draw_random_press = 0.0f;
-
- brush->gpencil_settings->draw_jitter = 0.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
-
- brush->gpencil_settings->draw_angle = 0.0f;
- brush->gpencil_settings->draw_angle_factor = 0.0f;
-
- brush->gpencil_settings->draw_smoothfac = 0.1f;
- brush->gpencil_settings->draw_smoothlvl = 1;
- brush->gpencil_settings->thick_smoothfac = 1.0f;
- brush->gpencil_settings->thick_smoothlvl = 3;
- brush->gpencil_settings->draw_subdivide = 0;
- brush->gpencil_settings->draw_random_sub = 0;
- brush->gpencil_settings->icon_id = GP_BRUSH_ICON_BLOCK;
- brush->gpencil_tool = GPAINT_TOOL_DRAW;
-
- brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
- brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
-
- brush->gpencil_settings->gradient_f = 1.0f;
- brush->gpencil_settings->gradient_s[0] = 1.0f;
- brush->gpencil_settings->gradient_s[1] = 1.0f;
-
- /* Marker brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Draw Marker");
- brush->size = 80.0f;
- brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
- brush->gpencil_settings->draw_sensitivity = 1.0f;
-
- brush->gpencil_settings->draw_strength = 1.0f;
-
- brush->gpencil_settings->flag |= GP_BRUSH_GROUP_RANDOM;
- brush->gpencil_settings->draw_random_press = 0.374f;
- brush->gpencil_settings->draw_random_strength = 0.0f;
-
- brush->gpencil_settings->draw_jitter = 0.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
-
- brush->gpencil_settings->draw_angle = DEG2RAD(20.0f);
- brush->gpencil_settings->draw_angle_factor = 1.0f;
-
- brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
- brush->gpencil_settings->draw_smoothfac = 0.1f;
- brush->gpencil_settings->draw_smoothlvl = 1;
- brush->gpencil_settings->thick_smoothfac = 1.0f;
- brush->gpencil_settings->thick_smoothlvl = 3;
- brush->gpencil_settings->draw_subdivide = 1;
- brush->gpencil_settings->draw_random_sub = 0.0f;
- brush->gpencil_settings->icon_id = GP_BRUSH_ICON_MARKER;
- brush->gpencil_tool = GPAINT_TOOL_DRAW;
-
- brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
- brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
- /* Curve */
- custom_curve = brush->gpencil_settings->curve_sensitivity;
- curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
- curvemapping_initialize(custom_curve);
- brush_gpencil_curvemap_reset(custom_curve->cm, 4, GPCURVE_PRESET_MARKER);
-
- brush->gpencil_settings->gradient_f = 1.0f;
- brush->gpencil_settings->gradient_s[0] = 1.0f;
- brush->gpencil_settings->gradient_s[1] = 1.0f;
-
- /* Fill brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Fill Area");
- brush->size = 1.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR;
- brush->gpencil_settings->draw_sensitivity = 1.0f;
- brush->gpencil_settings->fill_leak = 3;
- brush->gpencil_settings->fill_threshold = 0.1f;
- brush->gpencil_settings->fill_simplylvl = 1;
- brush->gpencil_settings->fill_factor = 1;
- brush->gpencil_settings->icon_id = GP_BRUSH_ICON_FILL;
- brush->gpencil_tool = GPAINT_TOOL_FILL;
-
- brush->gpencil_settings->draw_smoothfac = 0.1f;
- brush->gpencil_settings->draw_smoothlvl = 1;
- brush->gpencil_settings->thick_smoothfac = 1.0f;
- brush->gpencil_settings->thick_smoothlvl = 3;
- brush->gpencil_settings->draw_subdivide = 1;
-
- brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
- brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
-
- brush->gpencil_settings->draw_strength = 1.0f;
-
- brush->gpencil_settings->gradient_f = 1.0f;
- brush->gpencil_settings->gradient_s[0] = 1.0f;
- brush->gpencil_settings->gradient_s[1] = 1.0f;
-
- /* Soft Eraser brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Soft");
- brush->size = 30.0f;
- brush->gpencil_settings->draw_strength = 0.5f;
- brush->gpencil_settings->flag |= (GP_BRUSH_ENABLE_CURSOR | GP_BRUSH_DEFAULT_ERASER);
- brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE;
- brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
- brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_SOFT;
- brush->gpencil_tool = GPAINT_TOOL_ERASE;
- brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_SOFT;
- brush->gpencil_settings->era_strength_f = 100.0f;
- brush->gpencil_settings->era_thickness_f = 10.0f;
-
- /* Hard Eraser brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Hard");
- brush->size = 30.0f;
- brush->gpencil_settings->draw_strength = 1.0f;
- brush->gpencil_settings->flag |= (GP_BRUSH_ENABLE_CURSOR | GP_BRUSH_DEFAULT_ERASER);
- brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_HARD;
- brush->gpencil_tool = GPAINT_TOOL_ERASE;
- brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_SOFT;
- brush->gpencil_settings->era_strength_f = 100.0f;
- brush->gpencil_settings->era_thickness_f = 50.0f;
-
- /* Point Eraser brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Point");
- brush->size = 30.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR;
- brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_HARD;
- brush->gpencil_tool = GPAINT_TOOL_ERASE;
- brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_HARD;
-
- /* Stroke Eraser brush */
- brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Stroke");
- brush->size = 30.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR;
- brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_STROKE;
- brush->gpencil_tool = GPAINT_TOOL_ERASE;
- brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_STROKE;
-
- /* set default brush */
- BKE_paint_brush_set(paint, deft);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Paint *paint = &ts->gp_paint->paint;
+ Main *bmain = CTX_data_main(C);
+
+ Brush *brush, *deft;
+ CurveMapping *custom_curve;
+
+ /* Pencil brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Draw Pencil");
+ brush->size = 25.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ brush->gpencil_settings->draw_strength = 0.6f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+
+ brush->gpencil_settings->draw_random_press = 0.0f;
+
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+ brush->gpencil_settings->draw_angle = 0.0f;
+ brush->gpencil_settings->draw_angle_factor = 0.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.1f;
+ brush->gpencil_settings->draw_smoothlvl = 1;
+ brush->gpencil_settings->thick_smoothfac = 1.0f;
+ brush->gpencil_settings->thick_smoothlvl = 3;
+ brush->gpencil_settings->draw_subdivide = 1;
+ brush->gpencil_settings->draw_random_sub = 0.0f;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PENCIL;
+ brush->gpencil_tool = GPAINT_TOOL_DRAW;
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ brush->gpencil_settings->gradient_f = 1.0f;
+ brush->gpencil_settings->gradient_s[0] = 1.0f;
+ brush->gpencil_settings->gradient_s[1] = 1.0f;
+
+ /* Pen brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Draw Pen");
+ deft = brush; /* save default brush */
+ brush->size = 30.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ brush->gpencil_settings->draw_strength = 1.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+
+ brush->gpencil_settings->draw_random_press = 0.0f;
+ brush->gpencil_settings->draw_random_strength = 0.0f;
+
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+ brush->gpencil_settings->draw_angle = 0.0f;
+ brush->gpencil_settings->draw_angle_factor = 0.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.1f;
+ brush->gpencil_settings->draw_smoothlvl = 1;
+ brush->gpencil_settings->draw_subdivide = 1;
+ brush->gpencil_settings->thick_smoothfac = 1.0f;
+ brush->gpencil_settings->thick_smoothlvl = 3;
+ brush->gpencil_settings->draw_random_sub = 0.0f;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN;
+ brush->gpencil_tool = GPAINT_TOOL_DRAW;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ brush->gpencil_settings->gradient_f = 1.0f;
+ brush->gpencil_settings->gradient_s[0] = 1.0f;
+ brush->gpencil_settings->gradient_s[1] = 1.0f;
+
+ /* Ink brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Draw Ink");
+ brush->size = 60.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+ brush->gpencil_settings->draw_sensitivity = 1.6f;
+
+ brush->gpencil_settings->draw_strength = 1.0f;
+
+ brush->gpencil_settings->draw_random_press = 0.0f;
+
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+ brush->gpencil_settings->draw_angle = 0.0f;
+ brush->gpencil_settings->draw_angle_factor = 0.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.1f;
+ brush->gpencil_settings->draw_smoothlvl = 1;
+ brush->gpencil_settings->thick_smoothfac = 1.0f;
+ brush->gpencil_settings->thick_smoothlvl = 3;
+ brush->gpencil_settings->draw_subdivide = 1;
+ brush->gpencil_settings->draw_random_sub = 0.0f;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INK;
+ brush->gpencil_tool = GPAINT_TOOL_DRAW;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ brush->gpencil_settings->gradient_f = 1.0f;
+ brush->gpencil_settings->gradient_s[0] = 1.0f;
+ brush->gpencil_settings->gradient_s[1] = 1.0f;
+
+ /* Curve */
+ custom_curve = brush->gpencil_settings->curve_sensitivity;
+ curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
+ curvemapping_initialize(custom_curve);
+ brush_gpencil_curvemap_reset(custom_curve->cm, 3, GPCURVE_PRESET_INK);
+
+ /* Ink Noise brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Draw Noise");
+ brush->size = 60.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ brush->gpencil_settings->draw_strength = 1.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_RANDOM;
+ brush->gpencil_settings->draw_random_press = 0.7f;
+ brush->gpencil_settings->draw_random_strength = 0.0f;
+
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+ brush->gpencil_settings->draw_angle = 0.0f;
+ brush->gpencil_settings->draw_angle_factor = 0.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.1f;
+ brush->gpencil_settings->draw_smoothlvl = 2;
+ brush->gpencil_settings->thick_smoothfac = 0.5f;
+ brush->gpencil_settings->thick_smoothlvl = 2;
+ brush->gpencil_settings->draw_subdivide = 1;
+ brush->gpencil_settings->draw_random_sub = 0.0f;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INKNOISE;
+ brush->gpencil_tool = GPAINT_TOOL_DRAW;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ /* Curve */
+ custom_curve = brush->gpencil_settings->curve_sensitivity;
+ curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
+ curvemapping_initialize(custom_curve);
+ brush_gpencil_curvemap_reset(custom_curve->cm, 3, GPCURVE_PRESET_INKNOISE);
+
+ brush->gpencil_settings->gradient_f = 1.0f;
+ brush->gpencil_settings->gradient_s[0] = 1.0f;
+ brush->gpencil_settings->gradient_s[1] = 1.0f;
+
+ /* Block Basic brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Draw Block");
+ brush->size = 150.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ brush->gpencil_settings->draw_strength = 1.0f;
+
+ brush->gpencil_settings->draw_random_press = 0.0f;
+
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+ brush->gpencil_settings->draw_angle = 0.0f;
+ brush->gpencil_settings->draw_angle_factor = 0.0f;
+
+ brush->gpencil_settings->draw_smoothfac = 0.1f;
+ brush->gpencil_settings->draw_smoothlvl = 1;
+ brush->gpencil_settings->thick_smoothfac = 1.0f;
+ brush->gpencil_settings->thick_smoothlvl = 3;
+ brush->gpencil_settings->draw_subdivide = 0;
+ brush->gpencil_settings->draw_random_sub = 0;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_BLOCK;
+ brush->gpencil_tool = GPAINT_TOOL_DRAW;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ brush->gpencil_settings->gradient_f = 1.0f;
+ brush->gpencil_settings->gradient_s[0] = 1.0f;
+ brush->gpencil_settings->gradient_s[1] = 1.0f;
+
+ /* Marker brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Draw Marker");
+ brush->size = 80.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ brush->gpencil_settings->draw_strength = 1.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_RANDOM;
+ brush->gpencil_settings->draw_random_press = 0.374f;
+ brush->gpencil_settings->draw_random_strength = 0.0f;
+
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+ brush->gpencil_settings->draw_angle = DEG2RAD(20.0f);
+ brush->gpencil_settings->draw_angle_factor = 1.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.1f;
+ brush->gpencil_settings->draw_smoothlvl = 1;
+ brush->gpencil_settings->thick_smoothfac = 1.0f;
+ brush->gpencil_settings->thick_smoothlvl = 3;
+ brush->gpencil_settings->draw_subdivide = 1;
+ brush->gpencil_settings->draw_random_sub = 0.0f;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_MARKER;
+ brush->gpencil_tool = GPAINT_TOOL_DRAW;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+ /* Curve */
+ custom_curve = brush->gpencil_settings->curve_sensitivity;
+ curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
+ curvemapping_initialize(custom_curve);
+ brush_gpencil_curvemap_reset(custom_curve->cm, 4, GPCURVE_PRESET_MARKER);
+
+ brush->gpencil_settings->gradient_f = 1.0f;
+ brush->gpencil_settings->gradient_s[0] = 1.0f;
+ brush->gpencil_settings->gradient_s[1] = 1.0f;
+
+ /* Fill brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Fill Area");
+ brush->size = 1.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR;
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+ brush->gpencil_settings->fill_leak = 3;
+ brush->gpencil_settings->fill_threshold = 0.1f;
+ brush->gpencil_settings->fill_simplylvl = 1;
+ brush->gpencil_settings->fill_factor = 1;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_FILL;
+ brush->gpencil_tool = GPAINT_TOOL_FILL;
+
+ brush->gpencil_settings->draw_smoothfac = 0.1f;
+ brush->gpencil_settings->draw_smoothlvl = 1;
+ brush->gpencil_settings->thick_smoothfac = 1.0f;
+ brush->gpencil_settings->thick_smoothlvl = 3;
+ brush->gpencil_settings->draw_subdivide = 1;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ brush->gpencil_settings->draw_strength = 1.0f;
+
+ brush->gpencil_settings->gradient_f = 1.0f;
+ brush->gpencil_settings->gradient_s[0] = 1.0f;
+ brush->gpencil_settings->gradient_s[1] = 1.0f;
+
+ /* Soft Eraser brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Soft");
+ brush->size = 30.0f;
+ brush->gpencil_settings->draw_strength = 0.5f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_ENABLE_CURSOR | GP_BRUSH_DEFAULT_ERASER);
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_SOFT;
+ brush->gpencil_tool = GPAINT_TOOL_ERASE;
+ brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_SOFT;
+ brush->gpencil_settings->era_strength_f = 100.0f;
+ brush->gpencil_settings->era_thickness_f = 10.0f;
+
+ /* Hard Eraser brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Hard");
+ brush->size = 30.0f;
+ brush->gpencil_settings->draw_strength = 1.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_ENABLE_CURSOR | GP_BRUSH_DEFAULT_ERASER);
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_HARD;
+ brush->gpencil_tool = GPAINT_TOOL_ERASE;
+ brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_SOFT;
+ brush->gpencil_settings->era_strength_f = 100.0f;
+ brush->gpencil_settings->era_thickness_f = 50.0f;
+
+ /* Point Eraser brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Point");
+ brush->size = 30.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_HARD;
+ brush->gpencil_tool = GPAINT_TOOL_ERASE;
+ brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_HARD;
+
+ /* Stroke Eraser brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Stroke");
+ brush->size = 30.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_STROKE;
+ brush->gpencil_tool = GPAINT_TOOL_ERASE;
+ brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_STROKE;
+
+ /* set default brush */
+ BKE_paint_brush_set(paint, deft);
}
struct Brush *BKE_brush_first_search(struct Main *bmain, const eObjectMode ob_mode)
{
- Brush *brush;
+ Brush *brush;
- for (brush = bmain->brushes.first; brush; brush = brush->id.next) {
- if (brush->ob_mode & ob_mode)
- return brush;
- }
- return NULL;
+ for (brush = bmain->brushes.first; brush; brush = brush->id.next) {
+ if (brush->ob_mode & ob_mode)
+ return brush;
+ }
+ return NULL;
}
/**
@@ -587,193 +586,198 @@ struct Brush *BKE_brush_first_search(struct Main *bmain, const eObjectMode ob_mo
*
* \param flag: Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
*/
-void BKE_brush_copy_data(Main *UNUSED(bmain), Brush *brush_dst, const Brush *brush_src, const int flag)
+void BKE_brush_copy_data(Main *UNUSED(bmain),
+ Brush *brush_dst,
+ const Brush *brush_src,
+ const int flag)
{
- if (brush_src->icon_imbuf) {
- brush_dst->icon_imbuf = IMB_dupImBuf(brush_src->icon_imbuf);
- }
-
- if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
- BKE_previewimg_id_copy(&brush_dst->id, &brush_src->id);
- }
- else {
- brush_dst->preview = NULL;
- }
-
- brush_dst->curve = curvemapping_copy(brush_src->curve);
- if (brush_src->gpencil_settings != NULL) {
- brush_dst->gpencil_settings = MEM_dupallocN(brush_src->gpencil_settings);
- brush_dst->gpencil_settings->curve_sensitivity = curvemapping_copy(brush_src->gpencil_settings->curve_sensitivity);
- brush_dst->gpencil_settings->curve_strength = curvemapping_copy(brush_src->gpencil_settings->curve_strength);
- brush_dst->gpencil_settings->curve_jitter = curvemapping_copy(brush_src->gpencil_settings->curve_jitter);
- }
-
- /* enable fake user by default */
- id_fake_user_set(&brush_dst->id);
+ if (brush_src->icon_imbuf) {
+ brush_dst->icon_imbuf = IMB_dupImBuf(brush_src->icon_imbuf);
+ }
+
+ if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
+ BKE_previewimg_id_copy(&brush_dst->id, &brush_src->id);
+ }
+ else {
+ brush_dst->preview = NULL;
+ }
+
+ brush_dst->curve = curvemapping_copy(brush_src->curve);
+ if (brush_src->gpencil_settings != NULL) {
+ brush_dst->gpencil_settings = MEM_dupallocN(brush_src->gpencil_settings);
+ brush_dst->gpencil_settings->curve_sensitivity = curvemapping_copy(
+ brush_src->gpencil_settings->curve_sensitivity);
+ brush_dst->gpencil_settings->curve_strength = curvemapping_copy(
+ brush_src->gpencil_settings->curve_strength);
+ brush_dst->gpencil_settings->curve_jitter = curvemapping_copy(
+ brush_src->gpencil_settings->curve_jitter);
+ }
+
+ /* enable fake user by default */
+ id_fake_user_set(&brush_dst->id);
}
Brush *BKE_brush_copy(Main *bmain, const Brush *brush)
{
- Brush *brush_copy;
- BKE_id_copy(bmain, &brush->id, (ID **)&brush_copy);
- return brush_copy;
+ Brush *brush_copy;
+ BKE_id_copy(bmain, &brush->id, (ID **)&brush_copy);
+ return brush_copy;
}
/** Free (or release) any data used by this brush (does not free the brush itself). */
void BKE_brush_free(Brush *brush)
{
- if (brush->icon_imbuf) {
- IMB_freeImBuf(brush->icon_imbuf);
- }
- curvemapping_free(brush->curve);
-
- if (brush->gpencil_settings != NULL) {
- curvemapping_free(brush->gpencil_settings->curve_sensitivity);
- curvemapping_free(brush->gpencil_settings->curve_strength);
- curvemapping_free(brush->gpencil_settings->curve_jitter);
- MEM_SAFE_FREE(brush->gpencil_settings);
- }
+ if (brush->icon_imbuf) {
+ IMB_freeImBuf(brush->icon_imbuf);
+ }
+ curvemapping_free(brush->curve);
- MEM_SAFE_FREE(brush->gradient);
+ if (brush->gpencil_settings != NULL) {
+ curvemapping_free(brush->gpencil_settings->curve_sensitivity);
+ curvemapping_free(brush->gpencil_settings->curve_strength);
+ curvemapping_free(brush->gpencil_settings->curve_jitter);
+ MEM_SAFE_FREE(brush->gpencil_settings);
+ }
+ MEM_SAFE_FREE(brush->gradient);
- BKE_previewimg_free(&(brush->preview));
+ BKE_previewimg_free(&(brush->preview));
}
void BKE_brush_make_local(Main *bmain, Brush *brush, const bool lib_local)
{
- bool is_local = false, is_lib = false;
+ bool is_local = false, is_lib = false;
- /* - only lib users: do nothing (unless force_local is set)
- * - only local users: set flag
- * - mixed: make copy
- */
+ /* - only lib users: do nothing (unless force_local is set)
+ * - only local users: set flag
+ * - mixed: make copy
+ */
- if (!ID_IS_LINKED(brush)) {
- return;
- }
+ if (!ID_IS_LINKED(brush)) {
+ return;
+ }
- if (brush->clone.image) {
- /* Special case: ima always local immediately. Clone image should only have one user anyway. */
- id_make_local(bmain, &brush->clone.image->id, false, false);
- }
+ if (brush->clone.image) {
+ /* Special case: ima always local immediately. Clone image should only have one user anyway. */
+ id_make_local(bmain, &brush->clone.image->id, false, false);
+ }
- BKE_library_ID_test_usages(bmain, brush, &is_local, &is_lib);
+ BKE_library_ID_test_usages(bmain, brush, &is_local, &is_lib);
- if (lib_local || is_local) {
- if (!is_lib) {
- id_clear_lib_data(bmain, &brush->id);
- BKE_id_expand_local(bmain, &brush->id);
+ if (lib_local || is_local) {
+ if (!is_lib) {
+ id_clear_lib_data(bmain, &brush->id);
+ BKE_id_expand_local(bmain, &brush->id);
- /* enable fake user by default */
- id_fake_user_set(&brush->id);
- }
- else {
- Brush *brush_new = BKE_brush_copy(bmain, brush); /* Ensures FAKE_USER is set */
+ /* enable fake user by default */
+ id_fake_user_set(&brush->id);
+ }
+ else {
+ Brush *brush_new = BKE_brush_copy(bmain, brush); /* Ensures FAKE_USER is set */
- brush_new->id.us = 0;
+ brush_new->id.us = 0;
- /* setting newid is mandatory for complex make_lib_local logic... */
- ID_NEW_SET(brush, brush_new);
+ /* setting newid is mandatory for complex make_lib_local logic... */
+ ID_NEW_SET(brush, brush_new);
- if (!lib_local) {
- BKE_libblock_remap(bmain, brush, brush_new, ID_REMAP_SKIP_INDIRECT_USAGE);
- }
- }
- }
+ if (!lib_local) {
+ BKE_libblock_remap(bmain, brush, brush_new, ID_REMAP_SKIP_INDIRECT_USAGE);
+ }
+ }
+ }
}
void BKE_brush_debug_print_state(Brush *br)
{
- /* create a fake brush and set it to the defaults */
- Brush def = {{NULL}};
- brush_defaults(&def);
-
-#define BR_TEST(field, t) \
- if (br->field != def.field) \
- printf("br->" #field " = %" #t ";\n", br->field)
-
-#define BR_TEST_FLAG(_f) \
- if ((br->flag & _f) && !(def.flag & _f)) \
- printf("br->flag |= " #_f ";\n"); \
- else if (!(br->flag & _f) && (def.flag & _f)) \
- printf("br->flag &= ~" #_f ";\n")
-
-#define BR_TEST_FLAG_OVERLAY(_f) \
- if ((br->overlay_flags & _f) && !(def.overlay_flags & _f)) \
- printf("br->overlay_flags |= " #_f ";\n"); \
- else if (!(br->overlay_flags & _f) && (def.overlay_flags & _f)) \
- printf("br->overlay_flags &= ~" #_f ";\n")
-
- /* print out any non-default brush state */
- BR_TEST(normal_weight, f);
-
- BR_TEST(blend, d);
- BR_TEST(size, d);
-
- /* br->flag */
- BR_TEST_FLAG(BRUSH_AIRBRUSH);
- BR_TEST_FLAG(BRUSH_ALPHA_PRESSURE);
- BR_TEST_FLAG(BRUSH_SIZE_PRESSURE);
- BR_TEST_FLAG(BRUSH_JITTER_PRESSURE);
- BR_TEST_FLAG(BRUSH_SPACING_PRESSURE);
- BR_TEST_FLAG(BRUSH_ANCHORED);
- BR_TEST_FLAG(BRUSH_DIR_IN);
- BR_TEST_FLAG(BRUSH_SPACE);
- BR_TEST_FLAG(BRUSH_SMOOTH_STROKE);
- BR_TEST_FLAG(BRUSH_PERSISTENT);
- BR_TEST_FLAG(BRUSH_ACCUMULATE);
- BR_TEST_FLAG(BRUSH_LOCK_ALPHA);
- BR_TEST_FLAG(BRUSH_ORIGINAL_NORMAL);
- BR_TEST_FLAG(BRUSH_OFFSET_PRESSURE);
- BR_TEST_FLAG(BRUSH_SPACE_ATTEN);
- BR_TEST_FLAG(BRUSH_ADAPTIVE_SPACE);
- BR_TEST_FLAG(BRUSH_LOCK_SIZE);
- BR_TEST_FLAG(BRUSH_EDGE_TO_EDGE);
- BR_TEST_FLAG(BRUSH_DRAG_DOT);
- BR_TEST_FLAG(BRUSH_INVERSE_SMOOTH_PRESSURE);
- BR_TEST_FLAG(BRUSH_PLANE_TRIM);
- BR_TEST_FLAG(BRUSH_FRONTFACE);
- BR_TEST_FLAG(BRUSH_CUSTOM_ICON);
-
- BR_TEST_FLAG_OVERLAY(BRUSH_OVERLAY_CURSOR);
- BR_TEST_FLAG_OVERLAY(BRUSH_OVERLAY_PRIMARY);
- BR_TEST_FLAG_OVERLAY(BRUSH_OVERLAY_SECONDARY);
- BR_TEST_FLAG_OVERLAY(BRUSH_OVERLAY_CURSOR_OVERRIDE_ON_STROKE);
- BR_TEST_FLAG_OVERLAY(BRUSH_OVERLAY_PRIMARY_OVERRIDE_ON_STROKE);
- BR_TEST_FLAG_OVERLAY(BRUSH_OVERLAY_SECONDARY_OVERRIDE_ON_STROKE);
-
- BR_TEST(jitter, f);
- BR_TEST(spacing, d);
- BR_TEST(smooth_stroke_radius, d);
- BR_TEST(smooth_stroke_factor, f);
- BR_TEST(rate, f);
-
- BR_TEST(alpha, f);
-
- BR_TEST(sculpt_plane, d);
-
- BR_TEST(plane_offset, f);
-
- BR_TEST(autosmooth_factor, f);
-
- BR_TEST(topology_rake_factor, f);
-
- BR_TEST(crease_pinch_factor, f);
-
- BR_TEST(plane_trim, f);
-
- BR_TEST(texture_sample_bias, f);
- BR_TEST(texture_overlay_alpha, d);
-
- BR_TEST(add_col[0], f);
- BR_TEST(add_col[1], f);
- BR_TEST(add_col[2], f);
- BR_TEST(sub_col[0], f);
- BR_TEST(sub_col[1], f);
- BR_TEST(sub_col[2], f);
-
- printf("\n");
+ /* create a fake brush and set it to the defaults */
+ Brush def = {{NULL}};
+ brush_defaults(&def);
+
+#define BR_TEST(field, t) \
+ if (br->field != def.field) \
+ printf("br->" #field " = %" #t ";\n", br->field)
+
+#define BR_TEST_FLAG(_f) \
+ if ((br->flag & _f) && !(def.flag & _f)) \
+ printf("br->flag |= " #_f ";\n"); \
+ else if (!(br->flag & _f) && (def.flag & _f)) \
+ printf("br->flag &= ~" #_f ";\n")
+
+#define BR_TEST_FLAG_OVERLAY(_f) \
+ if ((br->overlay_flags & _f) && !(def.overlay_flags & _f)) \
+ printf("br->overlay_flags |= " #_f ";\n"); \
+ else if (!(br->overlay_flags & _f) && (def.overlay_flags & _f)) \
+ printf("br->overlay_flags &= ~" #_f ";\n")
+
+ /* print out any non-default brush state */
+ BR_TEST(normal_weight, f);
+
+ BR_TEST(blend, d);
+ BR_TEST(size, d);
+
+ /* br->flag */
+ BR_TEST_FLAG(BRUSH_AIRBRUSH);
+ BR_TEST_FLAG(BRUSH_ALPHA_PRESSURE);
+ BR_TEST_FLAG(BRUSH_SIZE_PRESSURE);
+ BR_TEST_FLAG(BRUSH_JITTER_PRESSURE);
+ BR_TEST_FLAG(BRUSH_SPACING_PRESSURE);
+ BR_TEST_FLAG(BRUSH_ANCHORED);
+ BR_TEST_FLAG(BRUSH_DIR_IN);
+ BR_TEST_FLAG(BRUSH_SPACE);
+ BR_TEST_FLAG(BRUSH_SMOOTH_STROKE);
+ BR_TEST_FLAG(BRUSH_PERSISTENT);
+ BR_TEST_FLAG(BRUSH_ACCUMULATE);
+ BR_TEST_FLAG(BRUSH_LOCK_ALPHA);
+ BR_TEST_FLAG(BRUSH_ORIGINAL_NORMAL);
+ BR_TEST_FLAG(BRUSH_OFFSET_PRESSURE);
+ BR_TEST_FLAG(BRUSH_SPACE_ATTEN);
+ BR_TEST_FLAG(BRUSH_ADAPTIVE_SPACE);
+ BR_TEST_FLAG(BRUSH_LOCK_SIZE);
+ BR_TEST_FLAG(BRUSH_EDGE_TO_EDGE);
+ BR_TEST_FLAG(BRUSH_DRAG_DOT);
+ BR_TEST_FLAG(BRUSH_INVERSE_SMOOTH_PRESSURE);
+ BR_TEST_FLAG(BRUSH_PLANE_TRIM);
+ BR_TEST_FLAG(BRUSH_FRONTFACE);
+ BR_TEST_FLAG(BRUSH_CUSTOM_ICON);
+
+ BR_TEST_FLAG_OVERLAY(BRUSH_OVERLAY_CURSOR);
+ BR_TEST_FLAG_OVERLAY(BRUSH_OVERLAY_PRIMARY);
+ BR_TEST_FLAG_OVERLAY(BRUSH_OVERLAY_SECONDARY);
+ BR_TEST_FLAG_OVERLAY(BRUSH_OVERLAY_CURSOR_OVERRIDE_ON_STROKE);
+ BR_TEST_FLAG_OVERLAY(BRUSH_OVERLAY_PRIMARY_OVERRIDE_ON_STROKE);
+ BR_TEST_FLAG_OVERLAY(BRUSH_OVERLAY_SECONDARY_OVERRIDE_ON_STROKE);
+
+ BR_TEST(jitter, f);
+ BR_TEST(spacing, d);
+ BR_TEST(smooth_stroke_radius, d);
+ BR_TEST(smooth_stroke_factor, f);
+ BR_TEST(rate, f);
+
+ BR_TEST(alpha, f);
+
+ BR_TEST(sculpt_plane, d);
+
+ BR_TEST(plane_offset, f);
+
+ BR_TEST(autosmooth_factor, f);
+
+ BR_TEST(topology_rake_factor, f);
+
+ BR_TEST(crease_pinch_factor, f);
+
+ BR_TEST(plane_trim, f);
+
+ BR_TEST(texture_sample_bias, f);
+ BR_TEST(texture_overlay_alpha, d);
+
+ BR_TEST(add_col[0], f);
+ BR_TEST(add_col[1], f);
+ BR_TEST(add_col[2], f);
+ BR_TEST(sub_col[0], f);
+ BR_TEST(sub_col[1], f);
+ BR_TEST(sub_col[2], f);
+
+ printf("\n");
#undef BR_TEST
#undef BR_TEST_FLAG
@@ -781,81 +785,81 @@ void BKE_brush_debug_print_state(Brush *br)
void BKE_brush_sculpt_reset(Brush *br)
{
- /* enable this to see any non-default
- * settings used by a brush: */
- // BKE_brush_debug_print_state(br);
-
- brush_defaults(br);
- BKE_brush_curve_preset(br, CURVE_PRESET_SMOOTH);
-
- switch (br->sculpt_tool) {
- case SCULPT_TOOL_CLAY:
- br->flag |= BRUSH_FRONTFACE;
- break;
- case SCULPT_TOOL_CREASE:
- br->flag |= BRUSH_DIR_IN;
- br->alpha = 0.25;
- break;
- case SCULPT_TOOL_FILL:
- br->add_col[1] = 1;
- br->sub_col[0] = 0.25;
- br->sub_col[1] = 1;
- break;
- case SCULPT_TOOL_FLATTEN:
- br->add_col[1] = 1;
- br->sub_col[0] = 0.25;
- br->sub_col[1] = 1;
- break;
- case SCULPT_TOOL_INFLATE:
- br->add_col[0] = 0.750000;
- br->add_col[1] = 0.750000;
- br->add_col[2] = 0.750000;
- br->sub_col[0] = 0.250000;
- br->sub_col[1] = 0.250000;
- br->sub_col[2] = 0.250000;
- break;
- case SCULPT_TOOL_NUDGE:
- br->add_col[0] = 0.250000;
- br->add_col[1] = 1.000000;
- br->add_col[2] = 0.250000;
- break;
- case SCULPT_TOOL_PINCH:
- br->add_col[0] = 0.750000;
- br->add_col[1] = 0.750000;
- br->add_col[2] = 0.750000;
- br->sub_col[0] = 0.250000;
- br->sub_col[1] = 0.250000;
- br->sub_col[2] = 0.250000;
- break;
- case SCULPT_TOOL_SCRAPE:
- br->add_col[1] = 1.000000;
- br->sub_col[0] = 0.250000;
- br->sub_col[1] = 1.000000;
- break;
- case SCULPT_TOOL_ROTATE:
- br->alpha = 1.0;
- break;
- case SCULPT_TOOL_SMOOTH:
- br->flag &= ~BRUSH_SPACE_ATTEN;
- br->spacing = 5;
- br->add_col[0] = 0.750000;
- br->add_col[1] = 0.750000;
- br->add_col[2] = 0.750000;
- break;
- case SCULPT_TOOL_GRAB:
- case SCULPT_TOOL_SNAKE_HOOK:
- case SCULPT_TOOL_THUMB:
- br->size = 75;
- br->flag &= ~BRUSH_ALPHA_PRESSURE;
- br->flag &= ~BRUSH_SPACE;
- br->flag &= ~BRUSH_SPACE_ATTEN;
- br->add_col[0] = 0.250000;
- br->add_col[1] = 1.000000;
- br->add_col[2] = 0.250000;
- break;
- default:
- break;
- }
+ /* enable this to see any non-default
+ * settings used by a brush: */
+ // BKE_brush_debug_print_state(br);
+
+ brush_defaults(br);
+ BKE_brush_curve_preset(br, CURVE_PRESET_SMOOTH);
+
+ switch (br->sculpt_tool) {
+ case SCULPT_TOOL_CLAY:
+ br->flag |= BRUSH_FRONTFACE;
+ break;
+ case SCULPT_TOOL_CREASE:
+ br->flag |= BRUSH_DIR_IN;
+ br->alpha = 0.25;
+ break;
+ case SCULPT_TOOL_FILL:
+ br->add_col[1] = 1;
+ br->sub_col[0] = 0.25;
+ br->sub_col[1] = 1;
+ break;
+ case SCULPT_TOOL_FLATTEN:
+ br->add_col[1] = 1;
+ br->sub_col[0] = 0.25;
+ br->sub_col[1] = 1;
+ break;
+ case SCULPT_TOOL_INFLATE:
+ br->add_col[0] = 0.750000;
+ br->add_col[1] = 0.750000;
+ br->add_col[2] = 0.750000;
+ br->sub_col[0] = 0.250000;
+ br->sub_col[1] = 0.250000;
+ br->sub_col[2] = 0.250000;
+ break;
+ case SCULPT_TOOL_NUDGE:
+ br->add_col[0] = 0.250000;
+ br->add_col[1] = 1.000000;
+ br->add_col[2] = 0.250000;
+ break;
+ case SCULPT_TOOL_PINCH:
+ br->add_col[0] = 0.750000;
+ br->add_col[1] = 0.750000;
+ br->add_col[2] = 0.750000;
+ br->sub_col[0] = 0.250000;
+ br->sub_col[1] = 0.250000;
+ br->sub_col[2] = 0.250000;
+ break;
+ case SCULPT_TOOL_SCRAPE:
+ br->add_col[1] = 1.000000;
+ br->sub_col[0] = 0.250000;
+ br->sub_col[1] = 1.000000;
+ break;
+ case SCULPT_TOOL_ROTATE:
+ br->alpha = 1.0;
+ break;
+ case SCULPT_TOOL_SMOOTH:
+ br->flag &= ~BRUSH_SPACE_ATTEN;
+ br->spacing = 5;
+ br->add_col[0] = 0.750000;
+ br->add_col[1] = 0.750000;
+ br->add_col[2] = 0.750000;
+ break;
+ case SCULPT_TOOL_GRAB:
+ case SCULPT_TOOL_SNAKE_HOOK:
+ case SCULPT_TOOL_THUMB:
+ br->size = 75;
+ br->flag &= ~BRUSH_ALPHA_PRESSURE;
+ br->flag &= ~BRUSH_SPACE;
+ br->flag &= ~BRUSH_SPACE_ATTEN;
+ br->add_col[0] = 0.250000;
+ br->add_col[1] = 1.000000;
+ br->add_col[2] = 0.250000;
+ break;
+ default:
+ break;
+ }
}
/**
@@ -863,262 +867,262 @@ void BKE_brush_sculpt_reset(Brush *br)
*/
void BKE_brush_curve_preset(Brush *b, eCurveMappingPreset preset)
{
- CurveMap *cm = NULL;
+ CurveMap *cm = NULL;
- if (!b->curve)
- b->curve = curvemapping_add(1, 0, 0, 1, 1);
+ if (!b->curve)
+ b->curve = curvemapping_add(1, 0, 0, 1, 1);
- cm = b->curve->cm;
- cm->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
+ cm = b->curve->cm;
+ cm->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
- b->curve->preset = preset;
- curvemap_reset(cm, &b->curve->clipr, b->curve->preset, CURVEMAP_SLOPE_NEGATIVE);
- curvemapping_changed(b->curve, false);
+ b->curve->preset = preset;
+ curvemap_reset(cm, &b->curve->clipr, b->curve->preset, CURVEMAP_SLOPE_NEGATIVE);
+ curvemapping_changed(b->curve, false);
}
/* Generic texture sampler for 3D painting systems. point has to be either in
* region space mouse coordinates, or 3d world coordinates for 3D mapping.
*
* rgba outputs straight alpha. */
-float BKE_brush_sample_tex_3d(const Scene *scene, const Brush *br,
+float BKE_brush_sample_tex_3d(const Scene *scene,
+ const Brush *br,
const float point[3],
- float rgba[4], const int thread,
+ float rgba[4],
+ const int thread,
struct ImagePool *pool)
{
- UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
- const MTex *mtex = &br->mtex;
- float intensity = 1.0;
- bool hasrgb = false;
-
- if (!mtex->tex) {
- intensity = 1;
- }
- else if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
- /* Get strength by feeding the vertex
- * location directly into a texture */
- hasrgb = externtex(mtex, point, &intensity,
- rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
- }
- else if (mtex->brush_map_mode == MTEX_MAP_MODE_STENCIL) {
- float rotation = -mtex->rot;
- float point_2d[2] = {point[0], point[1]};
- float x, y;
- float co[3];
-
- x = point_2d[0] - br->stencil_pos[0];
- y = point_2d[1] - br->stencil_pos[1];
-
- if (rotation > 0.001f || rotation < -0.001f) {
- const float angle = atan2f(y, x) + rotation;
- const float flen = sqrtf(x * x + y * y);
-
- x = flen * cosf(angle);
- y = flen * sinf(angle);
- }
-
- if (fabsf(x) > br->stencil_dimension[0] || fabsf(y) > br->stencil_dimension[1]) {
- zero_v4(rgba);
- return 0.0f;
- }
- x /= (br->stencil_dimension[0]);
- y /= (br->stencil_dimension[1]);
-
- co[0] = x;
- co[1] = y;
- co[2] = 0.0f;
-
- hasrgb = externtex(mtex, co, &intensity,
- rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
- }
- else {
- float rotation = -mtex->rot;
- float point_2d[2] = {point[0], point[1]};
- float x = 0.0f, y = 0.0f; /* Quite warnings */
- float invradius = 1.0f; /* Quite warnings */
- float co[3];
-
- if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
- /* keep coordinates relative to mouse */
-
- rotation += ups->brush_rotation;
-
- x = point_2d[0] - ups->tex_mouse[0];
- y = point_2d[1] - ups->tex_mouse[1];
-
- /* use pressure adjusted size for fixed mode */
- invradius = 1.0f / ups->pixel_radius;
- }
- else if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) {
- /* leave the coordinates relative to the screen */
-
- /* use unadjusted size for tiled mode */
- invradius = 1.0f / BKE_brush_size_get(scene, br);
-
- x = point_2d[0];
- y = point_2d[1];
- }
- else if (mtex->brush_map_mode == MTEX_MAP_MODE_RANDOM) {
- rotation += ups->brush_rotation;
- /* these contain a random coordinate */
- x = point_2d[0] - ups->tex_mouse[0];
- y = point_2d[1] - ups->tex_mouse[1];
-
- invradius = 1.0f / ups->pixel_radius;
- }
-
- x *= invradius;
- y *= invradius;
-
- /* it is probably worth optimizing for those cases where
- * the texture is not rotated by skipping the calls to
- * atan2, sqrtf, sin, and cos. */
- if (rotation > 0.001f || rotation < -0.001f) {
- const float angle = atan2f(y, x) + rotation;
- const float flen = sqrtf(x * x + y * y);
-
- x = flen * cosf(angle);
- y = flen * sinf(angle);
- }
-
- co[0] = x;
- co[1] = y;
- co[2] = 0.0f;
-
- hasrgb = externtex(mtex, co, &intensity,
- rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
- }
-
- intensity += br->texture_sample_bias;
-
- if (!hasrgb) {
- rgba[0] = intensity;
- rgba[1] = intensity;
- rgba[2] = intensity;
- rgba[3] = 1.0f;
- }
- /* For consistency, sampling always returns color in linear space */
- else if (ups->do_linear_conversion) {
- IMB_colormanagement_colorspace_to_scene_linear_v3(rgba, ups->colorspace);
- }
-
- return intensity;
+ UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+ const MTex *mtex = &br->mtex;
+ float intensity = 1.0;
+ bool hasrgb = false;
+
+ if (!mtex->tex) {
+ intensity = 1;
+ }
+ else if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
+ /* Get strength by feeding the vertex
+ * location directly into a texture */
+ hasrgb = externtex(
+ mtex, point, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
+ }
+ else if (mtex->brush_map_mode == MTEX_MAP_MODE_STENCIL) {
+ float rotation = -mtex->rot;
+ float point_2d[2] = {point[0], point[1]};
+ float x, y;
+ float co[3];
+
+ x = point_2d[0] - br->stencil_pos[0];
+ y = point_2d[1] - br->stencil_pos[1];
+
+ if (rotation > 0.001f || rotation < -0.001f) {
+ const float angle = atan2f(y, x) + rotation;
+ const float flen = sqrtf(x * x + y * y);
+
+ x = flen * cosf(angle);
+ y = flen * sinf(angle);
+ }
+
+ if (fabsf(x) > br->stencil_dimension[0] || fabsf(y) > br->stencil_dimension[1]) {
+ zero_v4(rgba);
+ return 0.0f;
+ }
+ x /= (br->stencil_dimension[0]);
+ y /= (br->stencil_dimension[1]);
+
+ co[0] = x;
+ co[1] = y;
+ co[2] = 0.0f;
+
+ hasrgb = externtex(
+ mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
+ }
+ else {
+ float rotation = -mtex->rot;
+ float point_2d[2] = {point[0], point[1]};
+ float x = 0.0f, y = 0.0f; /* Quite warnings */
+ float invradius = 1.0f; /* Quite warnings */
+ float co[3];
+
+ if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
+ /* keep coordinates relative to mouse */
+
+ rotation += ups->brush_rotation;
+
+ x = point_2d[0] - ups->tex_mouse[0];
+ y = point_2d[1] - ups->tex_mouse[1];
+
+ /* use pressure adjusted size for fixed mode */
+ invradius = 1.0f / ups->pixel_radius;
+ }
+ else if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) {
+ /* leave the coordinates relative to the screen */
+
+ /* use unadjusted size for tiled mode */
+ invradius = 1.0f / BKE_brush_size_get(scene, br);
+
+ x = point_2d[0];
+ y = point_2d[1];
+ }
+ else if (mtex->brush_map_mode == MTEX_MAP_MODE_RANDOM) {
+ rotation += ups->brush_rotation;
+ /* these contain a random coordinate */
+ x = point_2d[0] - ups->tex_mouse[0];
+ y = point_2d[1] - ups->tex_mouse[1];
+
+ invradius = 1.0f / ups->pixel_radius;
+ }
+
+ x *= invradius;
+ y *= invradius;
+
+ /* it is probably worth optimizing for those cases where
+ * the texture is not rotated by skipping the calls to
+ * atan2, sqrtf, sin, and cos. */
+ if (rotation > 0.001f || rotation < -0.001f) {
+ const float angle = atan2f(y, x) + rotation;
+ const float flen = sqrtf(x * x + y * y);
+
+ x = flen * cosf(angle);
+ y = flen * sinf(angle);
+ }
+
+ co[0] = x;
+ co[1] = y;
+ co[2] = 0.0f;
+
+ hasrgb = externtex(
+ mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
+ }
+
+ intensity += br->texture_sample_bias;
+
+ if (!hasrgb) {
+ rgba[0] = intensity;
+ rgba[1] = intensity;
+ rgba[2] = intensity;
+ rgba[3] = 1.0f;
+ }
+ /* For consistency, sampling always returns color in linear space */
+ else if (ups->do_linear_conversion) {
+ IMB_colormanagement_colorspace_to_scene_linear_v3(rgba, ups->colorspace);
+ }
+
+ return intensity;
}
-float BKE_brush_sample_masktex(const Scene *scene, Brush *br,
- const float point[2],
- const int thread,
- struct ImagePool *pool)
+float BKE_brush_sample_masktex(
+ const Scene *scene, Brush *br, const float point[2], const int thread, struct ImagePool *pool)
{
- UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
- MTex *mtex = &br->mask_mtex;
- float rgba[4], intensity;
-
- if (!mtex->tex) {
- return 1.0f;
- }
- if (mtex->brush_map_mode == MTEX_MAP_MODE_STENCIL) {
- float rotation = -mtex->rot;
- float point_2d[2] = {point[0], point[1]};
- float x, y;
- float co[3];
-
- x = point_2d[0] - br->mask_stencil_pos[0];
- y = point_2d[1] - br->mask_stencil_pos[1];
-
- if (rotation > 0.001f || rotation < -0.001f) {
- const float angle = atan2f(y, x) + rotation;
- const float flen = sqrtf(x * x + y * y);
-
- x = flen * cosf(angle);
- y = flen * sinf(angle);
- }
-
- if (fabsf(x) > br->mask_stencil_dimension[0] || fabsf(y) > br->mask_stencil_dimension[1]) {
- zero_v4(rgba);
- return 0.0f;
- }
- x /= (br->mask_stencil_dimension[0]);
- y /= (br->mask_stencil_dimension[1]);
-
- co[0] = x;
- co[1] = y;
- co[2] = 0.0f;
-
- externtex(mtex, co, &intensity,
- rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
- }
- else {
- float rotation = -mtex->rot;
- float point_2d[2] = {point[0], point[1]};
- float x = 0.0f, y = 0.0f; /* Quite warnings */
- float invradius = 1.0f; /* Quite warnings */
- float co[3];
-
- if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
- /* keep coordinates relative to mouse */
-
- rotation += ups->brush_rotation_sec;
-
- x = point_2d[0] - ups->mask_tex_mouse[0];
- y = point_2d[1] - ups->mask_tex_mouse[1];
-
- /* use pressure adjusted size for fixed mode */
- invradius = 1.0f / ups->pixel_radius;
- }
- else if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) {
- /* leave the coordinates relative to the screen */
-
- /* use unadjusted size for tiled mode */
- invradius = 1.0f / BKE_brush_size_get(scene, br);
-
- x = point_2d[0];
- y = point_2d[1];
- }
- else if (mtex->brush_map_mode == MTEX_MAP_MODE_RANDOM) {
- rotation += ups->brush_rotation_sec;
- /* these contain a random coordinate */
- x = point_2d[0] - ups->mask_tex_mouse[0];
- y = point_2d[1] - ups->mask_tex_mouse[1];
-
- invradius = 1.0f / ups->pixel_radius;
- }
-
- x *= invradius;
- y *= invradius;
-
- /* it is probably worth optimizing for those cases where
- * the texture is not rotated by skipping the calls to
- * atan2, sqrtf, sin, and cos. */
- if (rotation > 0.001f || rotation < -0.001f) {
- const float angle = atan2f(y, x) + rotation;
- const float flen = sqrtf(x * x + y * y);
-
- x = flen * cosf(angle);
- y = flen * sinf(angle);
- }
-
- co[0] = x;
- co[1] = y;
- co[2] = 0.0f;
-
- externtex(mtex, co, &intensity,
- rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
- }
-
- CLAMP(intensity, 0.0f, 1.0f);
-
- switch (br->mask_pressure) {
- case BRUSH_MASK_PRESSURE_CUTOFF:
- intensity = ((1.0f - intensity) < ups->size_pressure_value) ? 1.0f : 0.0f;
- break;
- case BRUSH_MASK_PRESSURE_RAMP:
- intensity = ups->size_pressure_value + intensity * (1.0f - ups->size_pressure_value);
- break;
- default:
- break;
- }
-
- return intensity;
+ UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+ MTex *mtex = &br->mask_mtex;
+ float rgba[4], intensity;
+
+ if (!mtex->tex) {
+ return 1.0f;
+ }
+ if (mtex->brush_map_mode == MTEX_MAP_MODE_STENCIL) {
+ float rotation = -mtex->rot;
+ float point_2d[2] = {point[0], point[1]};
+ float x, y;
+ float co[3];
+
+ x = point_2d[0] - br->mask_stencil_pos[0];
+ y = point_2d[1] - br->mask_stencil_pos[1];
+
+ if (rotation > 0.001f || rotation < -0.001f) {
+ const float angle = atan2f(y, x) + rotation;
+ const float flen = sqrtf(x * x + y * y);
+
+ x = flen * cosf(angle);
+ y = flen * sinf(angle);
+ }
+
+ if (fabsf(x) > br->mask_stencil_dimension[0] || fabsf(y) > br->mask_stencil_dimension[1]) {
+ zero_v4(rgba);
+ return 0.0f;
+ }
+ x /= (br->mask_stencil_dimension[0]);
+ y /= (br->mask_stencil_dimension[1]);
+
+ co[0] = x;
+ co[1] = y;
+ co[2] = 0.0f;
+
+ externtex(
+ mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
+ }
+ else {
+ float rotation = -mtex->rot;
+ float point_2d[2] = {point[0], point[1]};
+ float x = 0.0f, y = 0.0f; /* Quite warnings */
+ float invradius = 1.0f; /* Quite warnings */
+ float co[3];
+
+ if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
+ /* keep coordinates relative to mouse */
+
+ rotation += ups->brush_rotation_sec;
+
+ x = point_2d[0] - ups->mask_tex_mouse[0];
+ y = point_2d[1] - ups->mask_tex_mouse[1];
+
+ /* use pressure adjusted size for fixed mode */
+ invradius = 1.0f / ups->pixel_radius;
+ }
+ else if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) {
+ /* leave the coordinates relative to the screen */
+
+ /* use unadjusted size for tiled mode */
+ invradius = 1.0f / BKE_brush_size_get(scene, br);
+
+ x = point_2d[0];
+ y = point_2d[1];
+ }
+ else if (mtex->brush_map_mode == MTEX_MAP_MODE_RANDOM) {
+ rotation += ups->brush_rotation_sec;
+ /* these contain a random coordinate */
+ x = point_2d[0] - ups->mask_tex_mouse[0];
+ y = point_2d[1] - ups->mask_tex_mouse[1];
+
+ invradius = 1.0f / ups->pixel_radius;
+ }
+
+ x *= invradius;
+ y *= invradius;
+
+ /* it is probably worth optimizing for those cases where
+ * the texture is not rotated by skipping the calls to
+ * atan2, sqrtf, sin, and cos. */
+ if (rotation > 0.001f || rotation < -0.001f) {
+ const float angle = atan2f(y, x) + rotation;
+ const float flen = sqrtf(x * x + y * y);
+
+ x = flen * cosf(angle);
+ y = flen * sinf(angle);
+ }
+
+ co[0] = x;
+ co[1] = y;
+ co[2] = 0.0f;
+
+ externtex(
+ mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
+ }
+
+ CLAMP(intensity, 0.0f, 1.0f);
+
+ switch (br->mask_pressure) {
+ case BRUSH_MASK_PRESSURE_CUTOFF:
+ intensity = ((1.0f - intensity) < ups->size_pressure_value) ? 1.0f : 0.0f;
+ break;
+ case BRUSH_MASK_PRESSURE_RAMP:
+ intensity = ups->size_pressure_value + intensity * (1.0f - ups->size_pressure_value);
+ break;
+ default:
+ break;
+ }
+
+ return intensity;
}
/* Unified Size / Strength / Color */
@@ -1136,138 +1140,139 @@ float BKE_brush_sample_masktex(const Scene *scene, Brush *br,
* In any case, a better solution is needed to prevent
* inconsistency. */
-
const float *BKE_brush_color_get(const struct Scene *scene, const struct Brush *brush)
{
- UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
- return (ups->flag & UNIFIED_PAINT_COLOR) ? ups->rgb : brush->rgb;
+ UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+ return (ups->flag & UNIFIED_PAINT_COLOR) ? ups->rgb : brush->rgb;
}
const float *BKE_brush_secondary_color_get(const struct Scene *scene, const struct Brush *brush)
{
- UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
- return (ups->flag & UNIFIED_PAINT_COLOR) ? ups->secondary_rgb : brush->secondary_rgb;
+ UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+ return (ups->flag & UNIFIED_PAINT_COLOR) ? ups->secondary_rgb : brush->secondary_rgb;
}
void BKE_brush_color_set(struct Scene *scene, struct Brush *brush, const float color[3])
{
- UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+ UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
- if (ups->flag & UNIFIED_PAINT_COLOR)
- copy_v3_v3(ups->rgb, color);
- else
- copy_v3_v3(brush->rgb, color);
+ if (ups->flag & UNIFIED_PAINT_COLOR)
+ copy_v3_v3(ups->rgb, color);
+ else
+ copy_v3_v3(brush->rgb, color);
}
void BKE_brush_size_set(Scene *scene, Brush *brush, int size)
{
- UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+ UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
- /* make sure range is sane */
- CLAMP(size, 1, MAX_BRUSH_PIXEL_RADIUS);
+ /* make sure range is sane */
+ CLAMP(size, 1, MAX_BRUSH_PIXEL_RADIUS);
- if (ups->flag & UNIFIED_PAINT_SIZE)
- ups->size = size;
- else
- brush->size = size;
+ if (ups->flag & UNIFIED_PAINT_SIZE)
+ ups->size = size;
+ else
+ brush->size = size;
}
int BKE_brush_size_get(const Scene *scene, const Brush *brush)
{
- UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
- int size = (ups->flag & UNIFIED_PAINT_SIZE) ? ups->size : brush->size;
+ UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+ int size = (ups->flag & UNIFIED_PAINT_SIZE) ? ups->size : brush->size;
- return size;
+ return size;
}
bool BKE_brush_use_locked_size(const Scene *scene, const Brush *brush)
{
- const short us_flag = scene->toolsettings->unified_paint_settings.flag;
+ const short us_flag = scene->toolsettings->unified_paint_settings.flag;
- return (us_flag & UNIFIED_PAINT_SIZE) ?
- (us_flag & UNIFIED_PAINT_BRUSH_LOCK_SIZE) :
- (brush->flag & BRUSH_LOCK_SIZE);
+ return (us_flag & UNIFIED_PAINT_SIZE) ? (us_flag & UNIFIED_PAINT_BRUSH_LOCK_SIZE) :
+ (brush->flag & BRUSH_LOCK_SIZE);
}
bool BKE_brush_use_size_pressure(const Scene *scene, const Brush *brush)
{
- const short us_flag = scene->toolsettings->unified_paint_settings.flag;
+ const short us_flag = scene->toolsettings->unified_paint_settings.flag;
- return (us_flag & UNIFIED_PAINT_SIZE) ?
- (us_flag & UNIFIED_PAINT_BRUSH_SIZE_PRESSURE) :
- (brush->flag & BRUSH_SIZE_PRESSURE);
+ return (us_flag & UNIFIED_PAINT_SIZE) ? (us_flag & UNIFIED_PAINT_BRUSH_SIZE_PRESSURE) :
+ (brush->flag & BRUSH_SIZE_PRESSURE);
}
bool BKE_brush_use_alpha_pressure(const Scene *scene, const Brush *brush)
{
- const short us_flag = scene->toolsettings->unified_paint_settings.flag;
+ const short us_flag = scene->toolsettings->unified_paint_settings.flag;
- return (us_flag & UNIFIED_PAINT_ALPHA) ?
- (us_flag & UNIFIED_PAINT_BRUSH_ALPHA_PRESSURE) :
- (brush->flag & BRUSH_ALPHA_PRESSURE);
+ return (us_flag & UNIFIED_PAINT_ALPHA) ? (us_flag & UNIFIED_PAINT_BRUSH_ALPHA_PRESSURE) :
+ (brush->flag & BRUSH_ALPHA_PRESSURE);
}
bool BKE_brush_sculpt_has_secondary_color(const Brush *brush)
{
- return ELEM(
- brush->sculpt_tool, SCULPT_TOOL_BLOB, SCULPT_TOOL_DRAW,
- SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY, SCULPT_TOOL_CLAY_STRIPS,
- SCULPT_TOOL_PINCH, SCULPT_TOOL_CREASE, SCULPT_TOOL_LAYER,
- SCULPT_TOOL_FLATTEN, SCULPT_TOOL_FILL, SCULPT_TOOL_SCRAPE,
- SCULPT_TOOL_MASK);
+ return ELEM(brush->sculpt_tool,
+ SCULPT_TOOL_BLOB,
+ SCULPT_TOOL_DRAW,
+ SCULPT_TOOL_INFLATE,
+ SCULPT_TOOL_CLAY,
+ SCULPT_TOOL_CLAY_STRIPS,
+ SCULPT_TOOL_PINCH,
+ SCULPT_TOOL_CREASE,
+ SCULPT_TOOL_LAYER,
+ SCULPT_TOOL_FLATTEN,
+ SCULPT_TOOL_FILL,
+ SCULPT_TOOL_SCRAPE,
+ SCULPT_TOOL_MASK);
}
void BKE_brush_unprojected_radius_set(Scene *scene, Brush *brush, float unprojected_radius)
{
- UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+ UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
- if (ups->flag & UNIFIED_PAINT_SIZE)
- ups->unprojected_radius = unprojected_radius;
- else
- brush->unprojected_radius = unprojected_radius;
+ if (ups->flag & UNIFIED_PAINT_SIZE)
+ ups->unprojected_radius = unprojected_radius;
+ else
+ brush->unprojected_radius = unprojected_radius;
}
float BKE_brush_unprojected_radius_get(const Scene *scene, const Brush *brush)
{
- UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+ UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
- return (ups->flag & UNIFIED_PAINT_SIZE) ?
- ups->unprojected_radius :
- brush->unprojected_radius;
+ return (ups->flag & UNIFIED_PAINT_SIZE) ? ups->unprojected_radius : brush->unprojected_radius;
}
void BKE_brush_alpha_set(Scene *scene, Brush *brush, float alpha)
{
- UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+ UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
- if (ups->flag & UNIFIED_PAINT_ALPHA)
- ups->alpha = alpha;
- else
- brush->alpha = alpha;
+ if (ups->flag & UNIFIED_PAINT_ALPHA)
+ ups->alpha = alpha;
+ else
+ brush->alpha = alpha;
}
float BKE_brush_alpha_get(const Scene *scene, const Brush *brush)
{
- UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+ UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
- return (ups->flag & UNIFIED_PAINT_ALPHA) ? ups->alpha : brush->alpha;
+ return (ups->flag & UNIFIED_PAINT_ALPHA) ? ups->alpha : brush->alpha;
}
float BKE_brush_weight_get(const Scene *scene, const Brush *brush)
{
- UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+ UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
- return (ups->flag & UNIFIED_PAINT_WEIGHT) ? ups->weight : brush->weight;
+ return (ups->flag & UNIFIED_PAINT_WEIGHT) ? ups->weight : brush->weight;
}
void BKE_brush_weight_set(const Scene *scene, Brush *brush, float value)
{
- UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+ UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
- if (ups->flag & UNIFIED_PAINT_WEIGHT)
- ups->weight = value;
- else
- brush->weight = value;
+ if (ups->flag & UNIFIED_PAINT_WEIGHT)
+ ups->weight = value;
+ else
+ brush->weight = value;
}
/* scale unprojected radius to reflect a change in the brush's 2D size */
@@ -1275,161 +1280,158 @@ void BKE_brush_scale_unprojected_radius(float *unprojected_radius,
int new_brush_size,
int old_brush_size)
{
- float scale = new_brush_size;
- /* avoid division by zero */
- if (old_brush_size != 0)
- scale /= (float)old_brush_size;
- (*unprojected_radius) *= scale;
+ float scale = new_brush_size;
+ /* avoid division by zero */
+ if (old_brush_size != 0)
+ scale /= (float)old_brush_size;
+ (*unprojected_radius) *= scale;
}
/* scale brush size to reflect a change in the brush's unprojected radius */
-void BKE_brush_scale_size(
- int *r_brush_size,
- float new_unprojected_radius,
- float old_unprojected_radius)
+void BKE_brush_scale_size(int *r_brush_size,
+ float new_unprojected_radius,
+ float old_unprojected_radius)
{
- float scale = new_unprojected_radius;
- /* avoid division by zero */
- if (old_unprojected_radius != 0)
- scale /= new_unprojected_radius;
- (*r_brush_size) = (int)((float)(*r_brush_size) * scale);
+ float scale = new_unprojected_radius;
+ /* avoid division by zero */
+ if (old_unprojected_radius != 0)
+ scale /= new_unprojected_radius;
+ (*r_brush_size) = (int)((float)(*r_brush_size) * scale);
}
void BKE_brush_jitter_pos(const Scene *scene, Brush *brush, const float pos[2], float jitterpos[2])
{
- float rand_pos[2];
- float spread;
- int diameter;
-
- do {
- rand_pos[0] = BLI_rng_get_float(brush_rng) - 0.5f;
- rand_pos[1] = BLI_rng_get_float(brush_rng) - 0.5f;
- } while (len_squared_v2(rand_pos) > SQUARE(0.5f));
-
-
- if (brush->flag & BRUSH_ABSOLUTE_JITTER) {
- diameter = 2 * brush->jitter_absolute;
- spread = 1.0;
- }
- else {
- diameter = 2 * BKE_brush_size_get(scene, brush);
- spread = brush->jitter;
- }
- /* find random position within a circle of diameter 1 */
- jitterpos[0] = pos[0] + 2 * rand_pos[0] * diameter * spread;
- jitterpos[1] = pos[1] + 2 * rand_pos[1] * diameter * spread;
+ float rand_pos[2];
+ float spread;
+ int diameter;
+
+ do {
+ rand_pos[0] = BLI_rng_get_float(brush_rng) - 0.5f;
+ rand_pos[1] = BLI_rng_get_float(brush_rng) - 0.5f;
+ } while (len_squared_v2(rand_pos) > SQUARE(0.5f));
+
+ if (brush->flag & BRUSH_ABSOLUTE_JITTER) {
+ diameter = 2 * brush->jitter_absolute;
+ spread = 1.0;
+ }
+ else {
+ diameter = 2 * BKE_brush_size_get(scene, brush);
+ spread = brush->jitter;
+ }
+ /* find random position within a circle of diameter 1 */
+ jitterpos[0] = pos[0] + 2 * rand_pos[0] * diameter * spread;
+ jitterpos[1] = pos[1] + 2 * rand_pos[1] * diameter * spread;
}
void BKE_brush_randomize_texture_coords(UnifiedPaintSettings *ups, bool mask)
{
- /* we multiply with brush radius as an optimization for the brush
- * texture sampling functions */
- if (mask) {
- ups->mask_tex_mouse[0] = BLI_rng_get_float(brush_rng) * ups->pixel_radius;
- ups->mask_tex_mouse[1] = BLI_rng_get_float(brush_rng) * ups->pixel_radius;
- }
- else {
- ups->tex_mouse[0] = BLI_rng_get_float(brush_rng) * ups->pixel_radius;
- ups->tex_mouse[1] = BLI_rng_get_float(brush_rng) * ups->pixel_radius;
- }
+ /* we multiply with brush radius as an optimization for the brush
+ * texture sampling functions */
+ if (mask) {
+ ups->mask_tex_mouse[0] = BLI_rng_get_float(brush_rng) * ups->pixel_radius;
+ ups->mask_tex_mouse[1] = BLI_rng_get_float(brush_rng) * ups->pixel_radius;
+ }
+ else {
+ ups->tex_mouse[0] = BLI_rng_get_float(brush_rng) * ups->pixel_radius;
+ ups->tex_mouse[1] = BLI_rng_get_float(brush_rng) * ups->pixel_radius;
+ }
}
/* Uses the brush curve control to find a strength value */
float BKE_brush_curve_strength(const Brush *br, float p, const float len)
{
- float strength;
+ float strength;
- if (p >= len) return 0;
- else p = p / len;
+ if (p >= len)
+ return 0;
+ else
+ p = p / len;
- strength = curvemapping_evaluateF(br->curve, 0, p);
+ strength = curvemapping_evaluateF(br->curve, 0, p);
- return strength;
+ return strength;
}
-
/* Uses the brush curve control to find a strength value between 0 and 1 */
float BKE_brush_curve_strength_clamped(Brush *br, float p, const float len)
{
- float strength = BKE_brush_curve_strength(br, p, len);
+ float strength = BKE_brush_curve_strength(br, p, len);
- CLAMP(strength, 0.0f, 1.0f);
+ CLAMP(strength, 0.0f, 1.0f);
- return strength;
+ return strength;
}
/* TODO: should probably be unified with BrushPainter stuff? */
unsigned int *BKE_brush_gen_texture_cache(Brush *br, int half_side, bool use_secondary)
{
- unsigned int *texcache = NULL;
- MTex *mtex = (use_secondary) ? &br->mask_mtex : &br->mtex;
- float intensity;
- float rgba[4];
- int ix, iy;
- int side = half_side * 2;
-
- if (mtex->tex) {
- float x, y, step = 2.0 / side, co[3];
-
- texcache = MEM_callocN(sizeof(int) * side * side, "Brush texture cache");
-
- /* do normalized canonical view coords for texture */
- for (y = -1.0, iy = 0; iy < side; iy++, y += step) {
- for (x = -1.0, ix = 0; ix < side; ix++, x += step) {
- co[0] = x;
- co[1] = y;
- co[2] = 0.0f;
-
- /* This is copied from displace modifier code */
- /* TODO(sergey): brush are always caching with CM enabled for now. */
- externtex(mtex, co, &intensity,
- rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL, false, false);
-
- ((char *)texcache)[(iy * side + ix) * 4] =
- ((char *)texcache)[(iy * side + ix) * 4 + 1] =
- ((char *)texcache)[(iy * side + ix) * 4 + 2] =
- ((char *)texcache)[(iy * side + ix) * 4 + 3] = (char)(intensity * 255.0f);
- }
- }
- }
-
- return texcache;
+ unsigned int *texcache = NULL;
+ MTex *mtex = (use_secondary) ? &br->mask_mtex : &br->mtex;
+ float intensity;
+ float rgba[4];
+ int ix, iy;
+ int side = half_side * 2;
+
+ if (mtex->tex) {
+ float x, y, step = 2.0 / side, co[3];
+
+ texcache = MEM_callocN(sizeof(int) * side * side, "Brush texture cache");
+
+ /* do normalized canonical view coords for texture */
+ for (y = -1.0, iy = 0; iy < side; iy++, y += step) {
+ for (x = -1.0, ix = 0; ix < side; ix++, x += step) {
+ co[0] = x;
+ co[1] = y;
+ co[2] = 0.0f;
+
+ /* This is copied from displace modifier code */
+ /* TODO(sergey): brush are always caching with CM enabled for now. */
+ externtex(mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL, false, false);
+
+ ((char *)texcache)[(iy * side + ix) * 4] = ((char *)texcache)[(iy * side + ix) * 4 + 1] =
+ ((char *)texcache)[(iy * side + ix) * 4 + 2] = ((
+ char *)texcache)[(iy * side + ix) * 4 + 3] = (char)(intensity * 255.0f);
+ }
+ }
+ }
+
+ return texcache;
}
-
/**** Radial Control ****/
struct ImBuf *BKE_brush_gen_radial_control_imbuf(Brush *br, bool secondary)
{
- ImBuf *im = MEM_callocN(sizeof(ImBuf), "radial control texture");
- unsigned int *texcache;
- int side = 128;
- int half = side / 2;
- int i, j;
-
- curvemapping_initialize(br->curve);
- texcache = BKE_brush_gen_texture_cache(br, half, secondary);
- im->rect_float = MEM_callocN(sizeof(float) * side * side, "radial control rect");
- im->x = im->y = side;
-
- for (i = 0; i < side; ++i) {
- for (j = 0; j < side; ++j) {
- float magn = sqrtf(pow2f(i - half) + pow2f(j - half));
- im->rect_float[i * side + j] = BKE_brush_curve_strength_clamped(br, magn, half);
- }
- }
-
- /* Modulate curve with texture */
- if (texcache) {
- for (i = 0; i < side; ++i) {
- for (j = 0; j < side; ++j) {
- const int col = texcache[i * side + j];
- im->rect_float[i * side + j] *=
- (((char *)&col)[0] + ((char *)&col)[1] + ((char *)&col)[2]) / 3.0f / 255.0f;
- }
- }
-
- MEM_freeN(texcache);
- }
-
- return im;
+ ImBuf *im = MEM_callocN(sizeof(ImBuf), "radial control texture");
+ unsigned int *texcache;
+ int side = 128;
+ int half = side / 2;
+ int i, j;
+
+ curvemapping_initialize(br->curve);
+ texcache = BKE_brush_gen_texture_cache(br, half, secondary);
+ im->rect_float = MEM_callocN(sizeof(float) * side * side, "radial control rect");
+ im->x = im->y = side;
+
+ for (i = 0; i < side; ++i) {
+ for (j = 0; j < side; ++j) {
+ float magn = sqrtf(pow2f(i - half) + pow2f(j - half));
+ im->rect_float[i * side + j] = BKE_brush_curve_strength_clamped(br, magn, half);
+ }
+ }
+
+ /* Modulate curve with texture */
+ if (texcache) {
+ for (i = 0; i < side; ++i) {
+ for (j = 0; j < side; ++j) {
+ const int col = texcache[i * side + j];
+ im->rect_float[i * side + j] *= (((char *)&col)[0] + ((char *)&col)[1] +
+ ((char *)&col)[2]) /
+ 3.0f / 255.0f;
+ }
+ }
+
+ MEM_freeN(texcache);
+ }
+
+ return im;
}
diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c
index a96411d0c00..1c17408e286 100644
--- a/source/blender/blenkernel/intern/bvhutils.c
+++ b/source/blender/blenkernel/intern/bvhutils.c
@@ -49,39 +49,44 @@ static ThreadRWMutex cache_rwlock = BLI_RWLOCK_INITIALIZER;
/* Math stuff for ray casting on mesh faces and for nearest surface */
-float bvhtree_ray_tri_intersection(
- const BVHTreeRay *ray, const float UNUSED(m_dist),
- const float v0[3], const float v1[3], const float v2[3])
+float bvhtree_ray_tri_intersection(const BVHTreeRay *ray,
+ const float UNUSED(m_dist),
+ const float v0[3],
+ const float v1[3],
+ const float v2[3])
{
- float dist;
+ float dist;
#ifdef USE_KDOPBVH_WATERTIGHT
- if (isect_ray_tri_watertight_v3(ray->origin, ray->isect_precalc, v0, v1, v2, &dist, NULL))
+ if (isect_ray_tri_watertight_v3(ray->origin, ray->isect_precalc, v0, v1, v2, &dist, NULL))
#else
- if (isect_ray_tri_epsilon_v3(ray->origin, ray->direction, v0, v1, v2, &dist, NULL, FLT_EPSILON))
+ if (isect_ray_tri_epsilon_v3(ray->origin, ray->direction, v0, v1, v2, &dist, NULL, FLT_EPSILON))
#endif
- {
- return dist;
- }
+ {
+ return dist;
+ }
- return FLT_MAX;
+ return FLT_MAX;
}
-float bvhtree_sphereray_tri_intersection(
- const BVHTreeRay *ray, float radius, const float m_dist,
- const float v0[3], const float v1[3], const float v2[3])
+float bvhtree_sphereray_tri_intersection(const BVHTreeRay *ray,
+ float radius,
+ const float m_dist,
+ const float v0[3],
+ const float v1[3],
+ const float v2[3])
{
- float idist;
- float p1[3];
- float hit_point[3];
+ float idist;
+ float p1[3];
+ float hit_point[3];
- madd_v3_v3v3fl(p1, ray->origin, ray->direction, m_dist);
- if (isect_sweeping_sphere_tri_v3(ray->origin, p1, radius, v0, v1, v2, &idist, hit_point)) {
- return idist * m_dist;
- }
+ madd_v3_v3v3fl(p1, ray->origin, ray->direction, m_dist);
+ if (isect_sweeping_sphere_tri_v3(ray->origin, p1, radius, v0, v1, v2, &idist, hit_point)) {
+ return idist * m_dist;
+ }
- return FLT_MAX;
+ return FLT_MAX;
}
/*
@@ -90,285 +95,314 @@ float bvhtree_sphereray_tri_intersection(
/* Callback to bvh tree nearest point. The tree must have been built using bvhtree_from_mesh_faces.
* userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. */
-static void mesh_faces_nearest_point(void *userdata, int index, const float co[3], BVHTreeNearest *nearest)
+static void mesh_faces_nearest_point(void *userdata,
+ int index,
+ const float co[3],
+ BVHTreeNearest *nearest)
{
- const BVHTreeFromMesh *data = (BVHTreeFromMesh *) userdata;
- const MVert *vert = data->vert;
- const MFace *face = data->face + index;
-
- const float *t0, *t1, *t2, *t3;
- t0 = vert[face->v1].co;
- t1 = vert[face->v2].co;
- t2 = vert[face->v3].co;
- t3 = face->v4 ? vert[face->v4].co : NULL;
-
-
- do {
- float nearest_tmp[3], dist_sq;
-
- closest_on_tri_to_point_v3(nearest_tmp, co, t0, t1, t2);
- dist_sq = len_squared_v3v3(co, nearest_tmp);
-
- if (dist_sq < nearest->dist_sq) {
- nearest->index = index;
- nearest->dist_sq = dist_sq;
- copy_v3_v3(nearest->co, nearest_tmp);
- normal_tri_v3(nearest->no, t0, t1, t2);
- }
-
- t1 = t2;
- t2 = t3;
- t3 = NULL;
-
- } while (t2);
+ const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
+ const MVert *vert = data->vert;
+ const MFace *face = data->face + index;
+
+ const float *t0, *t1, *t2, *t3;
+ t0 = vert[face->v1].co;
+ t1 = vert[face->v2].co;
+ t2 = vert[face->v3].co;
+ t3 = face->v4 ? vert[face->v4].co : NULL;
+
+ do {
+ float nearest_tmp[3], dist_sq;
+
+ closest_on_tri_to_point_v3(nearest_tmp, co, t0, t1, t2);
+ dist_sq = len_squared_v3v3(co, nearest_tmp);
+
+ if (dist_sq < nearest->dist_sq) {
+ nearest->index = index;
+ nearest->dist_sq = dist_sq;
+ copy_v3_v3(nearest->co, nearest_tmp);
+ normal_tri_v3(nearest->no, t0, t1, t2);
+ }
+
+ t1 = t2;
+ t2 = t3;
+ t3 = NULL;
+
+ } while (t2);
}
/* copy of function above */
-static void mesh_looptri_nearest_point(void *userdata, int index, const float co[3], BVHTreeNearest *nearest)
+static void mesh_looptri_nearest_point(void *userdata,
+ int index,
+ const float co[3],
+ BVHTreeNearest *nearest)
{
- const BVHTreeFromMesh *data = (BVHTreeFromMesh *) userdata;
- const MVert *vert = data->vert;
- const MLoopTri *lt = &data->looptri[index];
- const float *vtri_co[3] = {
- vert[data->loop[lt->tri[0]].v].co,
- vert[data->loop[lt->tri[1]].v].co,
- vert[data->loop[lt->tri[2]].v].co,
- };
- float nearest_tmp[3], dist_sq;
-
- closest_on_tri_to_point_v3(nearest_tmp, co, UNPACK3(vtri_co));
- dist_sq = len_squared_v3v3(co, nearest_tmp);
-
- if (dist_sq < nearest->dist_sq) {
- nearest->index = index;
- nearest->dist_sq = dist_sq;
- copy_v3_v3(nearest->co, nearest_tmp);
- normal_tri_v3(nearest->no, UNPACK3(vtri_co));
- }
+ const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
+ const MVert *vert = data->vert;
+ const MLoopTri *lt = &data->looptri[index];
+ const float *vtri_co[3] = {
+ vert[data->loop[lt->tri[0]].v].co,
+ vert[data->loop[lt->tri[1]].v].co,
+ vert[data->loop[lt->tri[2]].v].co,
+ };
+ float nearest_tmp[3], dist_sq;
+
+ closest_on_tri_to_point_v3(nearest_tmp, co, UNPACK3(vtri_co));
+ dist_sq = len_squared_v3v3(co, nearest_tmp);
+
+ if (dist_sq < nearest->dist_sq) {
+ nearest->index = index;
+ nearest->dist_sq = dist_sq;
+ copy_v3_v3(nearest->co, nearest_tmp);
+ normal_tri_v3(nearest->no, UNPACK3(vtri_co));
+ }
}
/* copy of function above (warning, should de-duplicate with editmesh_bvh.c) */
-static void editmesh_looptri_nearest_point(void *userdata, int index, const float co[3], BVHTreeNearest *nearest)
+static void editmesh_looptri_nearest_point(void *userdata,
+ int index,
+ const float co[3],
+ BVHTreeNearest *nearest)
{
- const BVHTreeFromEditMesh *data = userdata;
- BMEditMesh *em = data->em;
- const BMLoop **ltri = (const BMLoop **)em->looptris[index];
-
- const float *t0, *t1, *t2;
- t0 = ltri[0]->v->co;
- t1 = ltri[1]->v->co;
- t2 = ltri[2]->v->co;
-
- {
- float nearest_tmp[3], dist_sq;
-
- closest_on_tri_to_point_v3(nearest_tmp, co, t0, t1, t2);
- dist_sq = len_squared_v3v3(co, nearest_tmp);
-
- if (dist_sq < nearest->dist_sq) {
- nearest->index = index;
- nearest->dist_sq = dist_sq;
- copy_v3_v3(nearest->co, nearest_tmp);
- normal_tri_v3(nearest->no, t0, t1, t2);
- }
- }
+ const BVHTreeFromEditMesh *data = userdata;
+ BMEditMesh *em = data->em;
+ const BMLoop **ltri = (const BMLoop **)em->looptris[index];
+
+ const float *t0, *t1, *t2;
+ t0 = ltri[0]->v->co;
+ t1 = ltri[1]->v->co;
+ t2 = ltri[2]->v->co;
+
+ {
+ float nearest_tmp[3], dist_sq;
+
+ closest_on_tri_to_point_v3(nearest_tmp, co, t0, t1, t2);
+ dist_sq = len_squared_v3v3(co, nearest_tmp);
+
+ if (dist_sq < nearest->dist_sq) {
+ nearest->index = index;
+ nearest->dist_sq = dist_sq;
+ copy_v3_v3(nearest->co, nearest_tmp);
+ normal_tri_v3(nearest->no, t0, t1, t2);
+ }
+ }
}
/* Callback to bvh tree raycast. The tree must have been built using bvhtree_from_mesh_faces.
* userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. */
-static void mesh_faces_spherecast(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
+static void mesh_faces_spherecast(void *userdata,
+ int index,
+ const BVHTreeRay *ray,
+ BVHTreeRayHit *hit)
{
- const BVHTreeFromMesh *data = (BVHTreeFromMesh *) userdata;
- const MVert *vert = data->vert;
- const MFace *face = &data->face[index];
-
- const float *t0, *t1, *t2, *t3;
- t0 = vert[face->v1].co;
- t1 = vert[face->v2].co;
- t2 = vert[face->v3].co;
- t3 = face->v4 ? vert[face->v4].co : NULL;
-
-
- do {
- float dist;
- if (ray->radius == 0.0f)
- dist = bvhtree_ray_tri_intersection(ray, hit->dist, t0, t1, t2);
- else
- dist = bvhtree_sphereray_tri_intersection(ray, ray->radius, hit->dist, t0, t1, t2);
-
- if (dist >= 0 && dist < hit->dist) {
- hit->index = index;
- hit->dist = dist;
- madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
-
- normal_tri_v3(hit->no, t0, t1, t2);
- }
-
- t1 = t2;
- t2 = t3;
- t3 = NULL;
-
- } while (t2);
+ const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
+ const MVert *vert = data->vert;
+ const MFace *face = &data->face[index];
+
+ const float *t0, *t1, *t2, *t3;
+ t0 = vert[face->v1].co;
+ t1 = vert[face->v2].co;
+ t2 = vert[face->v3].co;
+ t3 = face->v4 ? vert[face->v4].co : NULL;
+
+ do {
+ float dist;
+ if (ray->radius == 0.0f)
+ dist = bvhtree_ray_tri_intersection(ray, hit->dist, t0, t1, t2);
+ else
+ dist = bvhtree_sphereray_tri_intersection(ray, ray->radius, hit->dist, t0, t1, t2);
+
+ if (dist >= 0 && dist < hit->dist) {
+ hit->index = index;
+ hit->dist = dist;
+ madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
+
+ normal_tri_v3(hit->no, t0, t1, t2);
+ }
+
+ t1 = t2;
+ t2 = t3;
+ t3 = NULL;
+
+ } while (t2);
}
/* copy of function above */
-static void mesh_looptri_spherecast(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
+static void mesh_looptri_spherecast(void *userdata,
+ int index,
+ const BVHTreeRay *ray,
+ BVHTreeRayHit *hit)
{
- const BVHTreeFromMesh *data = (BVHTreeFromMesh *) userdata;
- const MVert *vert = data->vert;
- const MLoopTri *lt = &data->looptri[index];
- const float *vtri_co[3] = {
- vert[data->loop[lt->tri[0]].v].co,
- vert[data->loop[lt->tri[1]].v].co,
- vert[data->loop[lt->tri[2]].v].co,
- };
- float dist;
-
- if (ray->radius == 0.0f)
- dist = bvhtree_ray_tri_intersection(ray, hit->dist, UNPACK3(vtri_co));
- else
- dist = bvhtree_sphereray_tri_intersection(ray, ray->radius, hit->dist, UNPACK3(vtri_co));
-
- if (dist >= 0 && dist < hit->dist) {
- hit->index = index;
- hit->dist = dist;
- madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
-
- normal_tri_v3(hit->no, UNPACK3(vtri_co));
- }
+ const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
+ const MVert *vert = data->vert;
+ const MLoopTri *lt = &data->looptri[index];
+ const float *vtri_co[3] = {
+ vert[data->loop[lt->tri[0]].v].co,
+ vert[data->loop[lt->tri[1]].v].co,
+ vert[data->loop[lt->tri[2]].v].co,
+ };
+ float dist;
+
+ if (ray->radius == 0.0f)
+ dist = bvhtree_ray_tri_intersection(ray, hit->dist, UNPACK3(vtri_co));
+ else
+ dist = bvhtree_sphereray_tri_intersection(ray, ray->radius, hit->dist, UNPACK3(vtri_co));
+
+ if (dist >= 0 && dist < hit->dist) {
+ hit->index = index;
+ hit->dist = dist;
+ madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
+
+ normal_tri_v3(hit->no, UNPACK3(vtri_co));
+ }
}
/* copy of function above (warning, should de-duplicate with editmesh_bvh.c) */
-static void editmesh_looptri_spherecast(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
+static void editmesh_looptri_spherecast(void *userdata,
+ int index,
+ const BVHTreeRay *ray,
+ BVHTreeRayHit *hit)
{
- const BVHTreeFromEditMesh *data = (BVHTreeFromEditMesh *)userdata;
- BMEditMesh *em = data->em;
- const BMLoop **ltri = (const BMLoop **)em->looptris[index];
-
- const float *t0, *t1, *t2;
- t0 = ltri[0]->v->co;
- t1 = ltri[1]->v->co;
- t2 = ltri[2]->v->co;
-
-
- {
- float dist;
- if (ray->radius == 0.0f)
- dist = bvhtree_ray_tri_intersection(ray, hit->dist, t0, t1, t2);
- else
- dist = bvhtree_sphereray_tri_intersection(ray, ray->radius, hit->dist, t0, t1, t2);
-
- if (dist >= 0 && dist < hit->dist) {
- hit->index = index;
- hit->dist = dist;
- madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
-
- normal_tri_v3(hit->no, t0, t1, t2);
- }
- }
+ const BVHTreeFromEditMesh *data = (BVHTreeFromEditMesh *)userdata;
+ BMEditMesh *em = data->em;
+ const BMLoop **ltri = (const BMLoop **)em->looptris[index];
+
+ const float *t0, *t1, *t2;
+ t0 = ltri[0]->v->co;
+ t1 = ltri[1]->v->co;
+ t2 = ltri[2]->v->co;
+
+ {
+ float dist;
+ if (ray->radius == 0.0f)
+ dist = bvhtree_ray_tri_intersection(ray, hit->dist, t0, t1, t2);
+ else
+ dist = bvhtree_sphereray_tri_intersection(ray, ray->radius, hit->dist, t0, t1, t2);
+
+ if (dist >= 0 && dist < hit->dist) {
+ hit->index = index;
+ hit->dist = dist;
+ madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
+
+ normal_tri_v3(hit->no, t0, t1, t2);
+ }
+ }
}
/* Callback to bvh tree nearest point. The tree must have been built using bvhtree_from_mesh_edges.
* userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. */
-static void mesh_edges_nearest_point(void *userdata, int index, const float co[3], BVHTreeNearest *nearest)
+static void mesh_edges_nearest_point(void *userdata,
+ int index,
+ const float co[3],
+ BVHTreeNearest *nearest)
{
- const BVHTreeFromMesh *data = (BVHTreeFromMesh *) userdata;
- const MVert *vert = data->vert;
- const MEdge *edge = data->edge + index;
- float nearest_tmp[3], dist_sq;
-
- const float *t0, *t1;
- t0 = vert[edge->v1].co;
- t1 = vert[edge->v2].co;
-
- closest_to_line_segment_v3(nearest_tmp, co, t0, t1);
- dist_sq = len_squared_v3v3(nearest_tmp, co);
-
- if (dist_sq < nearest->dist_sq) {
- nearest->index = index;
- nearest->dist_sq = dist_sq;
- copy_v3_v3(nearest->co, nearest_tmp);
- sub_v3_v3v3(nearest->no, t0, t1);
- normalize_v3(nearest->no);
- }
+ const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
+ const MVert *vert = data->vert;
+ const MEdge *edge = data->edge + index;
+ float nearest_tmp[3], dist_sq;
+
+ const float *t0, *t1;
+ t0 = vert[edge->v1].co;
+ t1 = vert[edge->v2].co;
+
+ closest_to_line_segment_v3(nearest_tmp, co, t0, t1);
+ dist_sq = len_squared_v3v3(nearest_tmp, co);
+
+ if (dist_sq < nearest->dist_sq) {
+ nearest->index = index;
+ nearest->dist_sq = dist_sq;
+ copy_v3_v3(nearest->co, nearest_tmp);
+ sub_v3_v3v3(nearest->no, t0, t1);
+ normalize_v3(nearest->no);
+ }
}
/* Helper, does all the point-spherecast work actually. */
-static void mesh_verts_spherecast_do(
- int index, const float v[3], const BVHTreeRay *ray, BVHTreeRayHit *hit)
+static void mesh_verts_spherecast_do(int index,
+ const float v[3],
+ const BVHTreeRay *ray,
+ BVHTreeRayHit *hit)
{
- float dist;
- const float *r1;
- float r2[3], i1[3];
- r1 = ray->origin;
- add_v3_v3v3(r2, r1, ray->direction);
-
- closest_to_line_segment_v3(i1, v, r1, r2);
-
- /* No hit if closest point is 'behind' the origin of the ray, or too far away from it. */
- if ((dot_v3v3v3(r1, i1, r2) >= 0.0f) && ((dist = len_v3v3(r1, i1)) < hit->dist)) {
- hit->index = index;
- hit->dist = dist;
- copy_v3_v3(hit->co, i1);
- }
+ float dist;
+ const float *r1;
+ float r2[3], i1[3];
+ r1 = ray->origin;
+ add_v3_v3v3(r2, r1, ray->direction);
+
+ closest_to_line_segment_v3(i1, v, r1, r2);
+
+ /* No hit if closest point is 'behind' the origin of the ray, or too far away from it. */
+ if ((dot_v3v3v3(r1, i1, r2) >= 0.0f) && ((dist = len_v3v3(r1, i1)) < hit->dist)) {
+ hit->index = index;
+ hit->dist = dist;
+ copy_v3_v3(hit->co, i1);
+ }
}
-static void editmesh_verts_spherecast(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
+static void editmesh_verts_spherecast(void *userdata,
+ int index,
+ const BVHTreeRay *ray,
+ BVHTreeRayHit *hit)
{
- const BVHTreeFromEditMesh *data = userdata;
- BMVert *eve = BM_vert_at_index(data->em->bm, index);
+ const BVHTreeFromEditMesh *data = userdata;
+ BMVert *eve = BM_vert_at_index(data->em->bm, index);
- mesh_verts_spherecast_do(index, eve->co, ray, hit);
+ mesh_verts_spherecast_do(index, eve->co, ray, hit);
}
/* Callback to bvh tree raycast. The tree must have been built using bvhtree_from_mesh_verts.
* userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. */
-static void mesh_verts_spherecast(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
+static void mesh_verts_spherecast(void *userdata,
+ int index,
+ const BVHTreeRay *ray,
+ BVHTreeRayHit *hit)
{
- const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
- const float *v = data->vert[index].co;
+ const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
+ const float *v = data->vert[index].co;
- mesh_verts_spherecast_do(index, v, ray, hit);
+ mesh_verts_spherecast_do(index, v, ray, hit);
}
/* Callback to bvh tree raycast. The tree must have been built using bvhtree_from_mesh_edges.
* userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. */
-static void mesh_edges_spherecast(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
+static void mesh_edges_spherecast(void *userdata,
+ int index,
+ const BVHTreeRay *ray,
+ BVHTreeRayHit *hit)
{
- const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
- const MVert *vert = data->vert;
- const MEdge *edge = &data->edge[index];
-
- const float radius_sq = SQUARE(ray->radius);
- float dist;
- const float *v1, *v2, *r1;
- float r2[3], i1[3], i2[3];
- v1 = vert[edge->v1].co;
- v2 = vert[edge->v2].co;
-
- /* In case we get a zero-length edge, handle it as a point! */
- if (equals_v3v3(v1, v2)) {
- mesh_verts_spherecast_do(index, v1, ray, hit);
- return;
- }
-
- r1 = ray->origin;
- add_v3_v3v3(r2, r1, ray->direction);
-
- if (isect_line_line_v3(v1, v2, r1, r2, i1, i2)) {
- /* No hit if intersection point is 'behind' the origin of the ray, or too far away from it. */
- if ((dot_v3v3v3(r1, i2, r2) >= 0.0f) && ((dist = len_v3v3(r1, i2)) < hit->dist)) {
- const float e_fac = line_point_factor_v3(i1, v1, v2);
- if (e_fac < 0.0f) {
- copy_v3_v3(i1, v1);
- }
- else if (e_fac > 1.0f) {
- copy_v3_v3(i1, v2);
- }
- /* Ensure ray is really close enough from edge! */
- if (len_squared_v3v3(i1, i2) <= radius_sq) {
- hit->index = index;
- hit->dist = dist;
- copy_v3_v3(hit->co, i2);
- }
- }
- }
+ const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
+ const MVert *vert = data->vert;
+ const MEdge *edge = &data->edge[index];
+
+ const float radius_sq = SQUARE(ray->radius);
+ float dist;
+ const float *v1, *v2, *r1;
+ float r2[3], i1[3], i2[3];
+ v1 = vert[edge->v1].co;
+ v2 = vert[edge->v2].co;
+
+ /* In case we get a zero-length edge, handle it as a point! */
+ if (equals_v3v3(v1, v2)) {
+ mesh_verts_spherecast_do(index, v1, ray, hit);
+ return;
+ }
+
+ r1 = ray->origin;
+ add_v3_v3v3(r2, r1, ray->direction);
+
+ if (isect_line_line_v3(v1, v2, r1, r2, i1, i2)) {
+ /* No hit if intersection point is 'behind' the origin of the ray, or too far away from it. */
+ if ((dot_v3v3v3(r1, i2, r2) >= 0.0f) && ((dist = len_v3v3(r1, i2)) < hit->dist)) {
+ const float e_fac = line_point_factor_v3(i1, v1, v2);
+ if (e_fac < 0.0f) {
+ copy_v3_v3(i1, v1);
+ }
+ else if (e_fac > 1.0f) {
+ copy_v3_v3(i1, v2);
+ }
+ /* Ensure ray is really close enough from edge! */
+ if (len_squared_v3v3(i1, i2) <= radius_sq) {
+ hit->index = index;
+ hit->dist = dist;
+ copy_v3_v3(hit->co, i2);
+ }
+ }
+ }
}
/** \} */
@@ -377,147 +411,151 @@ static void mesh_edges_spherecast(void *userdata, int index, const BVHTreeRay *r
* BVH builders
*/
-
/* -------------------------------------------------------------------- */
/** \name Vertex Builder
* \{ */
-static BVHTree *bvhtree_from_editmesh_verts_create_tree(
- float epsilon, int tree_type, int axis,
- BMEditMesh *em, const int verts_num,
- const BLI_bitmap *verts_mask, int verts_num_active)
+static BVHTree *bvhtree_from_editmesh_verts_create_tree(float epsilon,
+ int tree_type,
+ int axis,
+ BMEditMesh *em,
+ const int verts_num,
+ const BLI_bitmap *verts_mask,
+ int verts_num_active)
{
- BM_mesh_elem_table_ensure(em->bm, BM_VERT);
- if (verts_mask) {
- BLI_assert(IN_RANGE_INCL(verts_num_active, 0, verts_num));
- }
- else {
- verts_num_active = verts_num;
- }
-
- BVHTree *tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis);
-
- if (tree) {
- for (int i = 0; i < verts_num; i++) {
- if (verts_mask && !BLI_BITMAP_TEST_BOOL(verts_mask, i)) {
- continue;
- }
- BMVert *eve = BM_vert_at_index(em->bm, i);
- BLI_bvhtree_insert(tree, i, eve->co, 1);
- }
- BLI_assert(BLI_bvhtree_get_len(tree) == verts_num_active);
- BLI_bvhtree_balance(tree);
- }
-
- return tree;
+ BM_mesh_elem_table_ensure(em->bm, BM_VERT);
+ if (verts_mask) {
+ BLI_assert(IN_RANGE_INCL(verts_num_active, 0, verts_num));
+ }
+ else {
+ verts_num_active = verts_num;
+ }
+
+ BVHTree *tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis);
+
+ if (tree) {
+ for (int i = 0; i < verts_num; i++) {
+ if (verts_mask && !BLI_BITMAP_TEST_BOOL(verts_mask, i)) {
+ continue;
+ }
+ BMVert *eve = BM_vert_at_index(em->bm, i);
+ BLI_bvhtree_insert(tree, i, eve->co, 1);
+ }
+ BLI_assert(BLI_bvhtree_get_len(tree) == verts_num_active);
+ BLI_bvhtree_balance(tree);
+ }
+
+ return tree;
}
-static BVHTree *bvhtree_from_mesh_verts_create_tree(
- float epsilon, int tree_type, int axis,
- const MVert *vert, const int verts_num,
- const BLI_bitmap *verts_mask, int verts_num_active)
+static BVHTree *bvhtree_from_mesh_verts_create_tree(float epsilon,
+ int tree_type,
+ int axis,
+ const MVert *vert,
+ const int verts_num,
+ const BLI_bitmap *verts_mask,
+ int verts_num_active)
{
- BVHTree *tree = NULL;
-
- if (verts_mask) {
- BLI_assert(IN_RANGE_INCL(verts_num_active, 0, verts_num));
- }
- else {
- verts_num_active = verts_num;
- }
-
- if (verts_num_active) {
- tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis);
-
- if (tree) {
- for (int i = 0; i < verts_num; i++) {
- if (verts_mask && !BLI_BITMAP_TEST_BOOL(verts_mask, i)) {
- continue;
- }
- BLI_bvhtree_insert(tree, i, vert[i].co, 1);
- }
- BLI_assert(BLI_bvhtree_get_len(tree) == verts_num_active);
- BLI_bvhtree_balance(tree);
- }
- }
-
- return tree;
+ BVHTree *tree = NULL;
+
+ if (verts_mask) {
+ BLI_assert(IN_RANGE_INCL(verts_num_active, 0, verts_num));
+ }
+ else {
+ verts_num_active = verts_num;
+ }
+
+ if (verts_num_active) {
+ tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis);
+
+ if (tree) {
+ for (int i = 0; i < verts_num; i++) {
+ if (verts_mask && !BLI_BITMAP_TEST_BOOL(verts_mask, i)) {
+ continue;
+ }
+ BLI_bvhtree_insert(tree, i, vert[i].co, 1);
+ }
+ BLI_assert(BLI_bvhtree_get_len(tree) == verts_num_active);
+ BLI_bvhtree_balance(tree);
+ }
+ }
+
+ return tree;
}
-static void bvhtree_from_mesh_verts_setup_data(
- BVHTreeFromMesh *data, BVHTree *tree, const bool is_cached,
- const MVert *vert, const bool vert_allocated)
+static void bvhtree_from_mesh_verts_setup_data(BVHTreeFromMesh *data,
+ BVHTree *tree,
+ const bool is_cached,
+ const MVert *vert,
+ const bool vert_allocated)
{
- memset(data, 0, sizeof(*data));
+ memset(data, 0, sizeof(*data));
- data->tree = tree;
- data->cached = is_cached;
+ data->tree = tree;
+ data->cached = is_cached;
- /* a NULL nearest callback works fine
- * remember the min distance to point is the same as the min distance to BV of point */
- data->nearest_callback = NULL;
- data->raycast_callback = mesh_verts_spherecast;
+ /* a NULL nearest callback works fine
+ * remember the min distance to point is the same as the min distance to BV of point */
+ data->nearest_callback = NULL;
+ data->raycast_callback = mesh_verts_spherecast;
- data->vert = vert;
- data->vert_allocated = vert_allocated;
+ data->vert = vert;
+ data->vert_allocated = vert_allocated;
}
/* Builds a bvh tree where nodes are the vertices of the given em */
-BVHTree *bvhtree_from_editmesh_verts_ex(
- BVHTreeFromEditMesh *data, BMEditMesh *em,
- const BLI_bitmap *verts_mask, int verts_num_active,
- float epsilon, int tree_type, int axis)
+BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data,
+ BMEditMesh *em,
+ const BLI_bitmap *verts_mask,
+ int verts_num_active,
+ float epsilon,
+ int tree_type,
+ int axis)
{
- BVHTree *tree = bvhtree_from_editmesh_verts_create_tree(
- epsilon, tree_type, axis,
- em, em->bm->totvert, verts_mask, verts_num_active);
-
- if (tree) {
- memset(data, 0, sizeof(*data));
- data->tree = tree;
- data->em = em;
- data->nearest_callback = NULL;
- data->raycast_callback = editmesh_verts_spherecast;
- }
-
- return tree;
+ BVHTree *tree = bvhtree_from_editmesh_verts_create_tree(
+ epsilon, tree_type, axis, em, em->bm->totvert, verts_mask, verts_num_active);
+
+ if (tree) {
+ memset(data, 0, sizeof(*data));
+ data->tree = tree;
+ data->em = em;
+ data->nearest_callback = NULL;
+ data->raycast_callback = editmesh_verts_spherecast;
+ }
+
+ return tree;
}
-BVHTree *bvhtree_from_editmesh_verts(
- BVHTreeFromEditMesh *data, BMEditMesh *em,
- float epsilon, int tree_type, int axis, BVHCache **bvh_cache)
+BVHTree *bvhtree_from_editmesh_verts(BVHTreeFromEditMesh *data,
+ BMEditMesh *em,
+ float epsilon,
+ int tree_type,
+ int axis,
+ BVHCache **bvh_cache)
{
- if (bvh_cache) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- data->cached = bvhcache_find(*bvh_cache, BVHTREE_FROM_EM_VERTS, &data->tree);
- BLI_rw_mutex_unlock(&cache_rwlock);
-
- if (data->cached == false) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- data->cached = bvhcache_find(
- *bvh_cache, BVHTREE_FROM_EM_VERTS, &data->tree);
- if (data->cached == false) {
- data->tree = bvhtree_from_editmesh_verts_ex(
- data, em,
- NULL, -1,
- epsilon, tree_type, axis);
-
- /* Save on cache for later use */
- /* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(
- bvh_cache, data->tree, BVHTREE_FROM_EM_VERTS);
- }
- BLI_rw_mutex_unlock(&cache_rwlock);
- }
- }
- else {
- data->tree = bvhtree_from_editmesh_verts_ex(
- data, em,
- NULL, -1,
- epsilon, tree_type, axis);
- }
-
- return data->tree;
+ if (bvh_cache) {
+ BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
+ data->cached = bvhcache_find(*bvh_cache, BVHTREE_FROM_EM_VERTS, &data->tree);
+ BLI_rw_mutex_unlock(&cache_rwlock);
+
+ if (data->cached == false) {
+ BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
+ data->cached = bvhcache_find(*bvh_cache, BVHTREE_FROM_EM_VERTS, &data->tree);
+ if (data->cached == false) {
+ data->tree = bvhtree_from_editmesh_verts_ex(data, em, NULL, -1, epsilon, tree_type, axis);
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(bvh_cache, data->tree, BVHTREE_FROM_EM_VERTS);
+ }
+ BLI_rw_mutex_unlock(&cache_rwlock);
+ }
+ }
+ else {
+ data->tree = bvhtree_from_editmesh_verts_ex(data, em, NULL, -1, epsilon, tree_type, axis);
+ }
+
+ return data->tree;
}
/**
@@ -526,178 +564,187 @@ BVHTree *bvhtree_from_editmesh_verts(
* \param verts_mask: if not null, true elements give which vert to add to BVH tree.
* \param verts_num_active: if >= 0, number of active verts to add to BVH tree (else will be computed from mask).
*/
-BVHTree *bvhtree_from_mesh_verts_ex(
- BVHTreeFromMesh *data, const MVert *vert, const int verts_num, const bool vert_allocated,
- const BLI_bitmap *verts_mask, int verts_num_active,
- float epsilon, int tree_type, int axis)
+BVHTree *bvhtree_from_mesh_verts_ex(BVHTreeFromMesh *data,
+ const MVert *vert,
+ const int verts_num,
+ const bool vert_allocated,
+ const BLI_bitmap *verts_mask,
+ int verts_num_active,
+ float epsilon,
+ int tree_type,
+ int axis)
{
- BVHTree *tree = bvhtree_from_mesh_verts_create_tree(
- epsilon, tree_type, axis, vert, verts_num, verts_mask, verts_num_active);
+ BVHTree *tree = bvhtree_from_mesh_verts_create_tree(
+ epsilon, tree_type, axis, vert, verts_num, verts_mask, verts_num_active);
- /* Setup BVHTreeFromMesh */
- bvhtree_from_mesh_verts_setup_data(
- data, tree, false, vert, vert_allocated);
+ /* Setup BVHTreeFromMesh */
+ bvhtree_from_mesh_verts_setup_data(data, tree, false, vert, vert_allocated);
- return tree;
+ return tree;
}
/** \} */
-
/* -------------------------------------------------------------------- */
/** \name Edge Builder
* \{ */
-static BVHTree *bvhtree_from_editmesh_edges_create_tree(
- float epsilon, int tree_type, int axis,
- BMEditMesh *em, const int edges_num,
- const BLI_bitmap *edges_mask, int edges_num_active)
+static BVHTree *bvhtree_from_editmesh_edges_create_tree(float epsilon,
+ int tree_type,
+ int axis,
+ BMEditMesh *em,
+ const int edges_num,
+ const BLI_bitmap *edges_mask,
+ int edges_num_active)
{
- BM_mesh_elem_table_ensure(em->bm, BM_EDGE);
- if (edges_mask) {
- BLI_assert(IN_RANGE_INCL(edges_num_active, 0, edges_num));
- }
- else {
- edges_num_active = edges_num;
- }
-
- BVHTree *tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis);
-
- if (tree) {
- int i;
- BMIter iter;
- BMEdge *eed;
- BM_ITER_MESH_INDEX (eed, &iter, em->bm, BM_EDGES_OF_MESH, i) {
- if (edges_mask && !BLI_BITMAP_TEST_BOOL(edges_mask, i)) {
- continue;
- }
- float co[2][3];
- copy_v3_v3(co[0], eed->v1->co);
- copy_v3_v3(co[1], eed->v2->co);
-
- BLI_bvhtree_insert(tree, i, co[0], 2);
- }
- BLI_assert(BLI_bvhtree_get_len(tree) == edges_num_active);
- BLI_bvhtree_balance(tree);
- }
-
- return tree;
+ BM_mesh_elem_table_ensure(em->bm, BM_EDGE);
+ if (edges_mask) {
+ BLI_assert(IN_RANGE_INCL(edges_num_active, 0, edges_num));
+ }
+ else {
+ edges_num_active = edges_num;
+ }
+
+ BVHTree *tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis);
+
+ if (tree) {
+ int i;
+ BMIter iter;
+ BMEdge *eed;
+ BM_ITER_MESH_INDEX (eed, &iter, em->bm, BM_EDGES_OF_MESH, i) {
+ if (edges_mask && !BLI_BITMAP_TEST_BOOL(edges_mask, i)) {
+ continue;
+ }
+ float co[2][3];
+ copy_v3_v3(co[0], eed->v1->co);
+ copy_v3_v3(co[1], eed->v2->co);
+
+ BLI_bvhtree_insert(tree, i, co[0], 2);
+ }
+ BLI_assert(BLI_bvhtree_get_len(tree) == edges_num_active);
+ BLI_bvhtree_balance(tree);
+ }
+
+ return tree;
}
-static BVHTree *bvhtree_from_mesh_edges_create_tree(
- const MVert *vert, const MEdge *edge, const int edge_num,
- const BLI_bitmap *edges_mask, int edges_num_active,
- float epsilon, int tree_type, int axis)
+static BVHTree *bvhtree_from_mesh_edges_create_tree(const MVert *vert,
+ const MEdge *edge,
+ const int edge_num,
+ const BLI_bitmap *edges_mask,
+ int edges_num_active,
+ float epsilon,
+ int tree_type,
+ int axis)
{
- BVHTree *tree = NULL;
-
- if (edges_mask) {
- BLI_assert(IN_RANGE_INCL(edges_num_active, 0, edge_num));
- }
- else {
- edges_num_active = edge_num;
- }
-
- if (edges_num_active) {
- /* Create a bvh-tree of the given target */
- tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis);
- if (tree) {
- for (int i = 0; i < edge_num; i++) {
- if (edges_mask && !BLI_BITMAP_TEST_BOOL(edges_mask, i)) {
- continue;
- }
- float co[2][3];
- copy_v3_v3(co[0], vert[edge[i].v1].co);
- copy_v3_v3(co[1], vert[edge[i].v2].co);
-
- BLI_bvhtree_insert(tree, i, co[0], 2);
- }
- BLI_bvhtree_balance(tree);
- }
- }
-
- return tree;
+ BVHTree *tree = NULL;
+
+ if (edges_mask) {
+ BLI_assert(IN_RANGE_INCL(edges_num_active, 0, edge_num));
+ }
+ else {
+ edges_num_active = edge_num;
+ }
+
+ if (edges_num_active) {
+ /* Create a bvh-tree of the given target */
+ tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis);
+ if (tree) {
+ for (int i = 0; i < edge_num; i++) {
+ if (edges_mask && !BLI_BITMAP_TEST_BOOL(edges_mask, i)) {
+ continue;
+ }
+ float co[2][3];
+ copy_v3_v3(co[0], vert[edge[i].v1].co);
+ copy_v3_v3(co[1], vert[edge[i].v2].co);
+
+ BLI_bvhtree_insert(tree, i, co[0], 2);
+ }
+ BLI_bvhtree_balance(tree);
+ }
+ }
+
+ return tree;
}
-static void bvhtree_from_mesh_edges_setup_data(
- BVHTreeFromMesh *data, BVHTree *tree,
- const bool is_cached,
- const MVert *vert, const bool vert_allocated,
- const MEdge *edge, const bool edge_allocated)
+static void bvhtree_from_mesh_edges_setup_data(BVHTreeFromMesh *data,
+ BVHTree *tree,
+ const bool is_cached,
+ const MVert *vert,
+ const bool vert_allocated,
+ const MEdge *edge,
+ const bool edge_allocated)
{
- memset(data, 0, sizeof(*data));
+ memset(data, 0, sizeof(*data));
- data->tree = tree;
+ data->tree = tree;
- data->cached = is_cached;
+ data->cached = is_cached;
- data->nearest_callback = mesh_edges_nearest_point;
- data->raycast_callback = mesh_edges_spherecast;
+ data->nearest_callback = mesh_edges_nearest_point;
+ data->raycast_callback = mesh_edges_spherecast;
- data->vert = vert;
- data->vert_allocated = vert_allocated;
- data->edge = edge;
- data->edge_allocated = edge_allocated;
+ data->vert = vert;
+ data->vert_allocated = vert_allocated;
+ data->edge = edge;
+ data->edge_allocated = edge_allocated;
}
/* Builds a bvh tree where nodes are the edges of the given em */
-BVHTree *bvhtree_from_editmesh_edges_ex(
- BVHTreeFromEditMesh *data, BMEditMesh *em,
- const BLI_bitmap *edges_mask, int edges_num_active,
- float epsilon, int tree_type, int axis)
+BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data,
+ BMEditMesh *em,
+ const BLI_bitmap *edges_mask,
+ int edges_num_active,
+ float epsilon,
+ int tree_type,
+ int axis)
{
- int edge_num = em->bm->totedge;
+ int edge_num = em->bm->totedge;
- BVHTree *tree = bvhtree_from_editmesh_edges_create_tree(
- epsilon, tree_type, axis,
- em, edge_num, edges_mask, edges_num_active);
+ BVHTree *tree = bvhtree_from_editmesh_edges_create_tree(
+ epsilon, tree_type, axis, em, edge_num, edges_mask, edges_num_active);
- if (tree) {
- memset(data, 0, sizeof(*data));
- data->tree = tree;
- data->em = em;
- data->nearest_callback = NULL; /* TODO */
- data->raycast_callback = NULL; /* TODO */
- }
+ if (tree) {
+ memset(data, 0, sizeof(*data));
+ data->tree = tree;
+ data->em = em;
+ data->nearest_callback = NULL; /* TODO */
+ data->raycast_callback = NULL; /* TODO */
+ }
- return tree;
+ return tree;
}
-BVHTree *bvhtree_from_editmesh_edges(
- BVHTreeFromEditMesh *data, BMEditMesh *em,
- float epsilon, int tree_type, int axis, BVHCache **bvh_cache)
+BVHTree *bvhtree_from_editmesh_edges(BVHTreeFromEditMesh *data,
+ BMEditMesh *em,
+ float epsilon,
+ int tree_type,
+ int axis,
+ BVHCache **bvh_cache)
{
- if (bvh_cache) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- data->cached = bvhcache_find(*bvh_cache, BVHTREE_FROM_EM_EDGES, &data->tree);
- BLI_rw_mutex_unlock(&cache_rwlock);
-
- if (data->cached == false) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- data->cached = bvhcache_find(
- *bvh_cache, BVHTREE_FROM_EM_EDGES, &data->tree);
- if (data->cached == false) {
- data->tree = bvhtree_from_editmesh_edges_ex(
- data, em,
- NULL, -1,
- epsilon, tree_type, axis);
-
- /* Save on cache for later use */
- /* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(
- bvh_cache, data->tree, BVHTREE_FROM_EM_EDGES);
- }
- BLI_rw_mutex_unlock(&cache_rwlock);
- }
- }
- else {
- data->tree = bvhtree_from_editmesh_edges_ex(
- data, em,
- NULL, -1,
- epsilon, tree_type, axis);
- }
-
- return data->tree;
+ if (bvh_cache) {
+ BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
+ data->cached = bvhcache_find(*bvh_cache, BVHTREE_FROM_EM_EDGES, &data->tree);
+ BLI_rw_mutex_unlock(&cache_rwlock);
+
+ if (data->cached == false) {
+ BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
+ data->cached = bvhcache_find(*bvh_cache, BVHTREE_FROM_EM_EDGES, &data->tree);
+ if (data->cached == false) {
+ data->tree = bvhtree_from_editmesh_edges_ex(data, em, NULL, -1, epsilon, tree_type, axis);
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(bvh_cache, data->tree, BVHTREE_FROM_EM_EDGES);
+ }
+ BLI_rw_mutex_unlock(&cache_rwlock);
+ }
+ }
+ else {
+ data->tree = bvhtree_from_editmesh_edges_ex(data, em, NULL, -1, epsilon, tree_type, axis);
+ }
+
+ return data->tree;
}
/**
@@ -707,92 +754,102 @@ BVHTree *bvhtree_from_editmesh_edges(
* \param edges_mask: if not null, true elements give which vert to add to BVH tree.
* \param edges_num_active: if >= 0, number of active edges to add to BVH tree (else will be computed from mask).
*/
-BVHTree *bvhtree_from_mesh_edges_ex(
- BVHTreeFromMesh *data,
- const MVert *vert, const bool vert_allocated,
- const MEdge *edge, const int edges_num, const bool edge_allocated,
- const BLI_bitmap *edges_mask, int edges_num_active,
- float epsilon, int tree_type, int axis)
+BVHTree *bvhtree_from_mesh_edges_ex(BVHTreeFromMesh *data,
+ const MVert *vert,
+ const bool vert_allocated,
+ const MEdge *edge,
+ const int edges_num,
+ const bool edge_allocated,
+ const BLI_bitmap *edges_mask,
+ int edges_num_active,
+ float epsilon,
+ int tree_type,
+ int axis)
{
- BVHTree *tree = bvhtree_from_mesh_edges_create_tree(
- vert, edge, edges_num, edges_mask, edges_num_active,
- epsilon, tree_type, axis);
+ BVHTree *tree = bvhtree_from_mesh_edges_create_tree(
+ vert, edge, edges_num, edges_mask, edges_num_active, epsilon, tree_type, axis);
- /* Setup BVHTreeFromMesh */
- bvhtree_from_mesh_edges_setup_data(
- data, tree, false, vert, vert_allocated, edge, edge_allocated);
+ /* Setup BVHTreeFromMesh */
+ bvhtree_from_mesh_edges_setup_data(
+ data, tree, false, vert, vert_allocated, edge, edge_allocated);
- return tree;
+ return tree;
}
/** \} */
-
/* -------------------------------------------------------------------- */
/** \name Tessellated Face Builder
* \{ */
-static BVHTree *bvhtree_from_mesh_faces_create_tree(
- float epsilon, int tree_type, int axis,
- const MVert *vert, const MFace *face, const int faces_num,
- const BLI_bitmap *faces_mask, int faces_num_active)
+static BVHTree *bvhtree_from_mesh_faces_create_tree(float epsilon,
+ int tree_type,
+ int axis,
+ const MVert *vert,
+ const MFace *face,
+ const int faces_num,
+ const BLI_bitmap *faces_mask,
+ int faces_num_active)
{
- BVHTree *tree = NULL;
- int i;
-
- if (faces_num) {
- if (faces_mask) {
- BLI_assert(IN_RANGE_INCL(faces_num_active, 0, faces_num));
- }
- else {
- faces_num_active = faces_num;
- }
-
- /* Create a bvh-tree of the given target */
- /* printf("%s: building BVH, total=%d\n", __func__, numFaces); */
- tree = BLI_bvhtree_new(faces_num_active, epsilon, tree_type, axis);
- if (tree) {
- if (vert && face) {
- for (i = 0; i < faces_num; i++) {
- float co[4][3];
- if (faces_mask && !BLI_BITMAP_TEST_BOOL(faces_mask, i)) {
- continue;
- }
-
- copy_v3_v3(co[0], vert[face[i].v1].co);
- copy_v3_v3(co[1], vert[face[i].v2].co);
- copy_v3_v3(co[2], vert[face[i].v3].co);
- if (face[i].v4)
- copy_v3_v3(co[3], vert[face[i].v4].co);
-
- BLI_bvhtree_insert(tree, i, co[0], face[i].v4 ? 4 : 3);
- }
- }
- BLI_assert(BLI_bvhtree_get_len(tree) == faces_num_active);
- BLI_bvhtree_balance(tree);
- }
- }
-
- return tree;
+ BVHTree *tree = NULL;
+ int i;
+
+ if (faces_num) {
+ if (faces_mask) {
+ BLI_assert(IN_RANGE_INCL(faces_num_active, 0, faces_num));
+ }
+ else {
+ faces_num_active = faces_num;
+ }
+
+ /* Create a bvh-tree of the given target */
+ /* printf("%s: building BVH, total=%d\n", __func__, numFaces); */
+ tree = BLI_bvhtree_new(faces_num_active, epsilon, tree_type, axis);
+ if (tree) {
+ if (vert && face) {
+ for (i = 0; i < faces_num; i++) {
+ float co[4][3];
+ if (faces_mask && !BLI_BITMAP_TEST_BOOL(faces_mask, i)) {
+ continue;
+ }
+
+ copy_v3_v3(co[0], vert[face[i].v1].co);
+ copy_v3_v3(co[1], vert[face[i].v2].co);
+ copy_v3_v3(co[2], vert[face[i].v3].co);
+ if (face[i].v4)
+ copy_v3_v3(co[3], vert[face[i].v4].co);
+
+ BLI_bvhtree_insert(tree, i, co[0], face[i].v4 ? 4 : 3);
+ }
+ }
+ BLI_assert(BLI_bvhtree_get_len(tree) == faces_num_active);
+ BLI_bvhtree_balance(tree);
+ }
+ }
+
+ return tree;
}
-static void bvhtree_from_mesh_faces_setup_data(
- BVHTreeFromMesh *data, BVHTree *tree, const bool is_cached,
- const MVert *vert, const bool vert_allocated,
- const MFace *face, const bool face_allocated)
+static void bvhtree_from_mesh_faces_setup_data(BVHTreeFromMesh *data,
+ BVHTree *tree,
+ const bool is_cached,
+ const MVert *vert,
+ const bool vert_allocated,
+ const MFace *face,
+ const bool face_allocated)
{
- memset(data, 0, sizeof(*data));
+ memset(data, 0, sizeof(*data));
- data->tree = tree;
- data->cached = is_cached;
+ data->tree = tree;
+ data->cached = is_cached;
- data->nearest_callback = mesh_faces_nearest_point;
- data->raycast_callback = mesh_faces_spherecast;
+ data->nearest_callback = mesh_faces_nearest_point;
+ data->raycast_callback = mesh_faces_spherecast;
- data->vert = vert;
- data->vert_allocated = vert_allocated;
- data->face = face;
- data->face_allocated = face_allocated;
+ data->vert = vert;
+ data->vert_allocated = vert_allocated;
+ data->face = face;
+ data->face_allocated = face_allocated;
}
/**
@@ -802,199 +859,216 @@ static void bvhtree_from_mesh_faces_setup_data(
* \param faces_mask: if not null, true elements give which faces to add to BVH tree.
* \param faces_num_active: if >= 0, number of active faces to add to BVH tree (else will be computed from mask).
*/
-BVHTree *bvhtree_from_mesh_faces_ex(
- BVHTreeFromMesh *data, const MVert *vert, const bool vert_allocated,
- const MFace *face, const int numFaces, const bool face_allocated,
- const BLI_bitmap *faces_mask, int faces_num_active,
- float epsilon, int tree_type, int axis)
+BVHTree *bvhtree_from_mesh_faces_ex(BVHTreeFromMesh *data,
+ const MVert *vert,
+ const bool vert_allocated,
+ const MFace *face,
+ const int numFaces,
+ const bool face_allocated,
+ const BLI_bitmap *faces_mask,
+ int faces_num_active,
+ float epsilon,
+ int tree_type,
+ int axis)
{
- BVHTree *tree = bvhtree_from_mesh_faces_create_tree(
- epsilon, tree_type, axis,
- vert, face, numFaces,
- faces_mask, faces_num_active);
+ BVHTree *tree = bvhtree_from_mesh_faces_create_tree(
+ epsilon, tree_type, axis, vert, face, numFaces, faces_mask, faces_num_active);
- /* Setup BVHTreeFromMesh */
- bvhtree_from_mesh_faces_setup_data(
- data, tree, false, vert, vert_allocated, face, face_allocated);
+ /* Setup BVHTreeFromMesh */
+ bvhtree_from_mesh_faces_setup_data(
+ data, tree, false, vert, vert_allocated, face, face_allocated);
- return tree;
+ return tree;
}
/** \} */
-
/* -------------------------------------------------------------------- */
/** \name LoopTri Face Builder
* \{ */
-static BVHTree *bvhtree_from_editmesh_looptri_create_tree(
- float epsilon, int tree_type, int axis,
- BMEditMesh *em, const int looptri_num,
- const BLI_bitmap *looptri_mask, int looptri_num_active)
+static BVHTree *bvhtree_from_editmesh_looptri_create_tree(float epsilon,
+ int tree_type,
+ int axis,
+ BMEditMesh *em,
+ const int looptri_num,
+ const BLI_bitmap *looptri_mask,
+ int looptri_num_active)
{
- BVHTree *tree = NULL;
- int i;
-
- if (looptri_num) {
- if (looptri_mask) {
- BLI_assert(IN_RANGE_INCL(looptri_num_active, 0, looptri_num));
- }
- else {
- looptri_num_active = looptri_num;
- }
-
- /* Create a bvh-tree of the given target */
- /* printf("%s: building BVH, total=%d\n", __func__, numFaces); */
- tree = BLI_bvhtree_new(looptri_num_active, epsilon, tree_type, axis);
- if (tree) {
- if (em) {
- const struct BMLoop *(*looptris)[3] = (void *)em->looptris;
-
- /* Insert BMesh-tessellation triangles into the bvh tree, unless they are hidden
- * and/or selected. Even if the faces themselves are not selected for the snapped
- * transform, having a vertex selected means the face (and thus it's tessellated
- * triangles) will be moving and will not be a good snap targets. */
- for (i = 0; i < looptri_num; i++) {
- const BMLoop **ltri = looptris[i];
- bool insert = looptri_mask ? BLI_BITMAP_TEST_BOOL(looptri_mask, i) : true;
-
- if (insert) {
- /* No reason found to block hit-testing the triangle for snap, so insert it now.*/
- float co[3][3];
- copy_v3_v3(co[0], ltri[0]->v->co);
- copy_v3_v3(co[1], ltri[1]->v->co);
- copy_v3_v3(co[2], ltri[2]->v->co);
-
- BLI_bvhtree_insert(tree, i, co[0], 3);
- }
- }
- }
- BLI_assert(BLI_bvhtree_get_len(tree) == looptri_num_active);
- BLI_bvhtree_balance(tree);
- }
- }
-
- return tree;
+ BVHTree *tree = NULL;
+ int i;
+
+ if (looptri_num) {
+ if (looptri_mask) {
+ BLI_assert(IN_RANGE_INCL(looptri_num_active, 0, looptri_num));
+ }
+ else {
+ looptri_num_active = looptri_num;
+ }
+
+ /* Create a bvh-tree of the given target */
+ /* printf("%s: building BVH, total=%d\n", __func__, numFaces); */
+ tree = BLI_bvhtree_new(looptri_num_active, epsilon, tree_type, axis);
+ if (tree) {
+ if (em) {
+ const struct BMLoop *(*looptris)[3] = (void *)em->looptris;
+
+ /* Insert BMesh-tessellation triangles into the bvh tree, unless they are hidden
+ * and/or selected. Even if the faces themselves are not selected for the snapped
+ * transform, having a vertex selected means the face (and thus it's tessellated
+ * triangles) will be moving and will not be a good snap targets. */
+ for (i = 0; i < looptri_num; i++) {
+ const BMLoop **ltri = looptris[i];
+ bool insert = looptri_mask ? BLI_BITMAP_TEST_BOOL(looptri_mask, i) : true;
+
+ if (insert) {
+ /* No reason found to block hit-testing the triangle for snap, so insert it now.*/
+ float co[3][3];
+ copy_v3_v3(co[0], ltri[0]->v->co);
+ copy_v3_v3(co[1], ltri[1]->v->co);
+ copy_v3_v3(co[2], ltri[2]->v->co);
+
+ BLI_bvhtree_insert(tree, i, co[0], 3);
+ }
+ }
+ }
+ BLI_assert(BLI_bvhtree_get_len(tree) == looptri_num_active);
+ BLI_bvhtree_balance(tree);
+ }
+ }
+
+ return tree;
}
-static BVHTree *bvhtree_from_mesh_looptri_create_tree(
- float epsilon, int tree_type, int axis,
- const MVert *vert, const MLoop *mloop, const MLoopTri *looptri, const int looptri_num,
- const BLI_bitmap *looptri_mask, int looptri_num_active)
+static BVHTree *bvhtree_from_mesh_looptri_create_tree(float epsilon,
+ int tree_type,
+ int axis,
+ const MVert *vert,
+ const MLoop *mloop,
+ const MLoopTri *looptri,
+ const int looptri_num,
+ const BLI_bitmap *looptri_mask,
+ int looptri_num_active)
{
- BVHTree *tree = NULL;
-
- if (looptri_mask) {
- BLI_assert(IN_RANGE_INCL(looptri_num_active, 0, looptri_num));
- }
- else {
- looptri_num_active = looptri_num;
- }
-
- if (looptri_num_active) {
- /* Create a bvh-tree of the given target */
- /* printf("%s: building BVH, total=%d\n", __func__, numFaces); */
- tree = BLI_bvhtree_new(looptri_num_active, epsilon, tree_type, axis);
- if (tree) {
- if (vert && looptri) {
- for (int i = 0; i < looptri_num; i++) {
- float co[3][3];
- if (looptri_mask && !BLI_BITMAP_TEST_BOOL(looptri_mask, i)) {
- continue;
- }
-
- copy_v3_v3(co[0], vert[mloop[looptri[i].tri[0]].v].co);
- copy_v3_v3(co[1], vert[mloop[looptri[i].tri[1]].v].co);
- copy_v3_v3(co[2], vert[mloop[looptri[i].tri[2]].v].co);
-
- BLI_bvhtree_insert(tree, i, co[0], 3);
- }
- }
- BLI_assert(BLI_bvhtree_get_len(tree) == looptri_num_active);
- BLI_bvhtree_balance(tree);
- }
- }
-
- return tree;
+ BVHTree *tree = NULL;
+
+ if (looptri_mask) {
+ BLI_assert(IN_RANGE_INCL(looptri_num_active, 0, looptri_num));
+ }
+ else {
+ looptri_num_active = looptri_num;
+ }
+
+ if (looptri_num_active) {
+ /* Create a bvh-tree of the given target */
+ /* printf("%s: building BVH, total=%d\n", __func__, numFaces); */
+ tree = BLI_bvhtree_new(looptri_num_active, epsilon, tree_type, axis);
+ if (tree) {
+ if (vert && looptri) {
+ for (int i = 0; i < looptri_num; i++) {
+ float co[3][3];
+ if (looptri_mask && !BLI_BITMAP_TEST_BOOL(looptri_mask, i)) {
+ continue;
+ }
+
+ copy_v3_v3(co[0], vert[mloop[looptri[i].tri[0]].v].co);
+ copy_v3_v3(co[1], vert[mloop[looptri[i].tri[1]].v].co);
+ copy_v3_v3(co[2], vert[mloop[looptri[i].tri[2]].v].co);
+
+ BLI_bvhtree_insert(tree, i, co[0], 3);
+ }
+ }
+ BLI_assert(BLI_bvhtree_get_len(tree) == looptri_num_active);
+ BLI_bvhtree_balance(tree);
+ }
+ }
+
+ return tree;
}
-static void bvhtree_from_mesh_looptri_setup_data(
- BVHTreeFromMesh *data, BVHTree *tree, const bool is_cached,
- const MVert *vert, const bool vert_allocated,
- const MLoop *mloop, const bool loop_allocated,
- const MLoopTri *looptri, const bool looptri_allocated)
+static void bvhtree_from_mesh_looptri_setup_data(BVHTreeFromMesh *data,
+ BVHTree *tree,
+ const bool is_cached,
+ const MVert *vert,
+ const bool vert_allocated,
+ const MLoop *mloop,
+ const bool loop_allocated,
+ const MLoopTri *looptri,
+ const bool looptri_allocated)
{
- memset(data, 0, sizeof(*data));
+ memset(data, 0, sizeof(*data));
- data->tree = tree;
- data->cached = is_cached;
+ data->tree = tree;
+ data->cached = is_cached;
- data->nearest_callback = mesh_looptri_nearest_point;
- data->raycast_callback = mesh_looptri_spherecast;
+ data->nearest_callback = mesh_looptri_nearest_point;
+ data->raycast_callback = mesh_looptri_spherecast;
- data->vert = vert;
- data->vert_allocated = vert_allocated;
- data->loop = mloop;
- data->loop_allocated = loop_allocated;
- data->looptri = looptri;
- data->looptri_allocated = looptri_allocated;
+ data->vert = vert;
+ data->vert_allocated = vert_allocated;
+ data->loop = mloop;
+ data->loop_allocated = loop_allocated;
+ data->looptri = looptri;
+ data->looptri_allocated = looptri_allocated;
}
/**
* Builds a bvh tree where nodes are the looptri faces of the given bm
*/
-BVHTree *bvhtree_from_editmesh_looptri_ex(
- BVHTreeFromEditMesh *data, BMEditMesh *em,
- const BLI_bitmap *looptri_mask, int looptri_num_active,
- float epsilon, int tree_type, int axis, BVHCache **bvhCache)
+BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data,
+ BMEditMesh *em,
+ const BLI_bitmap *looptri_mask,
+ int looptri_num_active,
+ float epsilon,
+ int tree_type,
+ int axis,
+ BVHCache **bvhCache)
{
- /* BMESH specific check that we have tessfaces,
- * we _could_ tessellate here but rather not - campbell */
-
- BVHTree *tree = NULL;
- if (bvhCache) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- bool in_cache = bvhcache_find(*bvhCache, BVHTREE_FROM_EM_LOOPTRI, &tree);
- BLI_rw_mutex_unlock(&cache_rwlock);
- if (in_cache == false) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- in_cache = bvhcache_find(*bvhCache, BVHTREE_FROM_EM_LOOPTRI, &tree);
- if (in_cache == false) {
- tree = bvhtree_from_editmesh_looptri_create_tree(
- epsilon, tree_type, axis,
- em, em->tottri, looptri_mask, looptri_num_active);
-
- /* Save on cache for later use */
- /* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(bvhCache, tree, BVHTREE_FROM_EM_LOOPTRI);
-
- }
- BLI_rw_mutex_unlock(&cache_rwlock);
- }
- }
- else {
- tree = bvhtree_from_editmesh_looptri_create_tree(
- epsilon, tree_type, axis,
- em, em->tottri, looptri_mask, looptri_num_active);
- }
-
- if (tree) {
- data->tree = tree;
- data->nearest_callback = editmesh_looptri_nearest_point;
- data->raycast_callback = editmesh_looptri_spherecast;
- data->em = em;
- data->cached = bvhCache != NULL;
- }
- return tree;
+ /* BMESH specific check that we have tessfaces,
+ * we _could_ tessellate here but rather not - campbell */
+
+ BVHTree *tree = NULL;
+ if (bvhCache) {
+ BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
+ bool in_cache = bvhcache_find(*bvhCache, BVHTREE_FROM_EM_LOOPTRI, &tree);
+ BLI_rw_mutex_unlock(&cache_rwlock);
+ if (in_cache == false) {
+ BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
+ in_cache = bvhcache_find(*bvhCache, BVHTREE_FROM_EM_LOOPTRI, &tree);
+ if (in_cache == false) {
+ tree = bvhtree_from_editmesh_looptri_create_tree(
+ epsilon, tree_type, axis, em, em->tottri, looptri_mask, looptri_num_active);
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(bvhCache, tree, BVHTREE_FROM_EM_LOOPTRI);
+ }
+ BLI_rw_mutex_unlock(&cache_rwlock);
+ }
+ }
+ else {
+ tree = bvhtree_from_editmesh_looptri_create_tree(
+ epsilon, tree_type, axis, em, em->tottri, looptri_mask, looptri_num_active);
+ }
+
+ if (tree) {
+ data->tree = tree;
+ data->nearest_callback = editmesh_looptri_nearest_point;
+ data->raycast_callback = editmesh_looptri_spherecast;
+ data->em = em;
+ data->cached = bvhCache != NULL;
+ }
+ return tree;
}
-BVHTree *bvhtree_from_editmesh_looptri(
- BVHTreeFromEditMesh *data, BMEditMesh *em,
- float epsilon, int tree_type, int axis, BVHCache **bvhCache)
+BVHTree *bvhtree_from_editmesh_looptri(BVHTreeFromEditMesh *data,
+ BMEditMesh *em,
+ float epsilon,
+ int tree_type,
+ int axis,
+ BVHCache **bvhCache)
{
- return bvhtree_from_editmesh_looptri_ex(
- data, em, NULL, -1,
- epsilon, tree_type, axis, bvhCache);
+ return bvhtree_from_editmesh_looptri_ex(data, em, NULL, -1, epsilon, tree_type, axis, bvhCache);
}
/**
@@ -1002,308 +1076,319 @@ BVHTree *bvhtree_from_editmesh_looptri(
*
* \note for editmesh this is currently a duplicate of bvhtree_from_mesh_faces_ex
*/
-BVHTree *bvhtree_from_mesh_looptri_ex(
- BVHTreeFromMesh *data,
- const struct MVert *vert, const bool vert_allocated,
- const struct MLoop *mloop, const bool loop_allocated,
- const struct MLoopTri *looptri, const int looptri_num, const bool looptri_allocated,
- const BLI_bitmap *looptri_mask, int looptri_num_active,
- float epsilon, int tree_type, int axis)
+BVHTree *bvhtree_from_mesh_looptri_ex(BVHTreeFromMesh *data,
+ const struct MVert *vert,
+ const bool vert_allocated,
+ const struct MLoop *mloop,
+ const bool loop_allocated,
+ const struct MLoopTri *looptri,
+ const int looptri_num,
+ const bool looptri_allocated,
+ const BLI_bitmap *looptri_mask,
+ int looptri_num_active,
+ float epsilon,
+ int tree_type,
+ int axis)
{
- BVHTree *tree = bvhtree_from_mesh_looptri_create_tree(
- epsilon, tree_type, axis,
- vert, mloop, looptri, looptri_num,
- looptri_mask, looptri_num_active);
-
- /* Setup BVHTreeFromMesh */
- bvhtree_from_mesh_looptri_setup_data(
- data, tree, false,
- vert, vert_allocated,
- mloop, loop_allocated,
- looptri, looptri_allocated);
-
- return tree;
+ BVHTree *tree = bvhtree_from_mesh_looptri_create_tree(epsilon,
+ tree_type,
+ axis,
+ vert,
+ mloop,
+ looptri,
+ looptri_num,
+ looptri_mask,
+ looptri_num_active);
+
+ /* Setup BVHTreeFromMesh */
+ bvhtree_from_mesh_looptri_setup_data(
+ data, tree, false, vert, vert_allocated, mloop, loop_allocated, looptri, looptri_allocated);
+
+ return tree;
}
-static BLI_bitmap *loose_verts_map_get(
- const MEdge *medge, int edges_num,
- const MVert *UNUSED(mvert), int verts_num,
- int *r_loose_vert_num)
+static BLI_bitmap *loose_verts_map_get(const MEdge *medge,
+ int edges_num,
+ const MVert *UNUSED(mvert),
+ int verts_num,
+ int *r_loose_vert_num)
{
- BLI_bitmap *loose_verts_mask = BLI_BITMAP_NEW(verts_num, __func__);
- BLI_bitmap_set_all(loose_verts_mask, true, verts_num);
-
- const MEdge *e = medge;
- int num_linked_verts = 0;
- for (;edges_num--; e++) {
- if (BLI_BITMAP_TEST(loose_verts_mask, e->v1)) {
- BLI_BITMAP_DISABLE(loose_verts_mask, e->v1);
- num_linked_verts++;
- }
- if (BLI_BITMAP_TEST(loose_verts_mask, e->v2)) {
- BLI_BITMAP_DISABLE(loose_verts_mask, e->v2);
- num_linked_verts++;
- }
- }
-
- *r_loose_vert_num = verts_num - num_linked_verts;
-
- return loose_verts_mask;
+ BLI_bitmap *loose_verts_mask = BLI_BITMAP_NEW(verts_num, __func__);
+ BLI_bitmap_set_all(loose_verts_mask, true, verts_num);
+
+ const MEdge *e = medge;
+ int num_linked_verts = 0;
+ for (; edges_num--; e++) {
+ if (BLI_BITMAP_TEST(loose_verts_mask, e->v1)) {
+ BLI_BITMAP_DISABLE(loose_verts_mask, e->v1);
+ num_linked_verts++;
+ }
+ if (BLI_BITMAP_TEST(loose_verts_mask, e->v2)) {
+ BLI_BITMAP_DISABLE(loose_verts_mask, e->v2);
+ num_linked_verts++;
+ }
+ }
+
+ *r_loose_vert_num = verts_num - num_linked_verts;
+
+ return loose_verts_mask;
}
-static BLI_bitmap *loose_edges_map_get(
- const MEdge *medge, const int edges_len,
- int *r_loose_edge_len)
+static BLI_bitmap *loose_edges_map_get(const MEdge *medge,
+ const int edges_len,
+ int *r_loose_edge_len)
{
- BLI_bitmap *loose_edges_mask = BLI_BITMAP_NEW(edges_len, __func__);
-
- int loose_edges_len = 0;
- const MEdge *e = medge;
- for (int i = 0; i < edges_len; i++, e++) {
- if (e->flag & ME_LOOSEEDGE) {
- BLI_BITMAP_ENABLE(loose_edges_mask, i);
- loose_edges_len++;
- }
- else {
- BLI_BITMAP_DISABLE(loose_edges_mask, i);
- }
- }
-
- *r_loose_edge_len = loose_edges_len;
-
- return loose_edges_mask;
+ BLI_bitmap *loose_edges_mask = BLI_BITMAP_NEW(edges_len, __func__);
+
+ int loose_edges_len = 0;
+ const MEdge *e = medge;
+ for (int i = 0; i < edges_len; i++, e++) {
+ if (e->flag & ME_LOOSEEDGE) {
+ BLI_BITMAP_ENABLE(loose_edges_mask, i);
+ loose_edges_len++;
+ }
+ else {
+ BLI_BITMAP_DISABLE(loose_edges_mask, i);
+ }
+ }
+
+ *r_loose_edge_len = loose_edges_len;
+
+ return loose_edges_mask;
}
/**
* Builds or queries a bvhcache for the cache bvhtree of the request type.
*/
-BVHTree *BKE_bvhtree_from_mesh_get(
- struct BVHTreeFromMesh *data, struct Mesh *mesh,
- const int type, const int tree_type)
+BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
+ struct Mesh *mesh,
+ const int type,
+ const int tree_type)
{
- struct BVHTreeFromMesh data_cp = {0};
-
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- data_cp.cached = bvhcache_find(mesh->runtime.bvh_cache, type, &data_cp.tree);
- BLI_rw_mutex_unlock(&cache_rwlock);
-
- if (data_cp.cached && data_cp.tree == NULL) {
- memset(data, 0, sizeof(*data));
- return data_cp.tree;
- }
-
- switch (type) {
- case BVHTREE_FROM_VERTS:
- case BVHTREE_FROM_LOOSEVERTS:
- data_cp.raycast_callback = mesh_verts_spherecast;
-
- data_cp.vert = mesh->mvert;
-
- if (data_cp.cached == false) {
- /* TODO: a global mutex lock held during the expensive operation of
- * building the BVH tree is really bad for performance. */
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- data_cp.cached = bvhcache_find(
- mesh->runtime.bvh_cache, type, &data_cp.tree);
-
- if (data_cp.cached == false) {
- BLI_bitmap *loose_verts_mask = NULL;
- int loose_vert_len = -1;
- int verts_len = mesh->totvert;
-
- if (type == BVHTREE_FROM_LOOSEVERTS) {
- loose_verts_mask = loose_verts_map_get(
- mesh->medge, mesh->totedge, data_cp.vert,
- verts_len, &loose_vert_len);
- }
-
- data_cp.tree = bvhtree_from_mesh_verts_create_tree(
- 0.0, tree_type, 6, data_cp.vert, verts_len,
- loose_verts_mask, loose_vert_len);
-
- if (loose_verts_mask != NULL) {
- MEM_freeN(loose_verts_mask);
- }
-
- /* Save on cache for later use */
- /* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(&mesh->runtime.bvh_cache, data_cp.tree, type);
- }
- BLI_rw_mutex_unlock(&cache_rwlock);
- }
- break;
-
- case BVHTREE_FROM_EDGES:
- case BVHTREE_FROM_LOOSEEDGES:
- data_cp.nearest_callback = mesh_edges_nearest_point;
- data_cp.raycast_callback = mesh_edges_spherecast;
-
- data_cp.vert = mesh->mvert;
- data_cp.edge = mesh->medge;
-
- if (data_cp.cached == false) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- data_cp.cached = bvhcache_find(mesh->runtime.bvh_cache, type, &data_cp.tree);
- if (data_cp.cached == false) {
- BLI_bitmap *loose_edges_mask = NULL;
- int loose_edges_len = -1;
- int edges_len = mesh->totedge;
-
- if (type == BVHTREE_FROM_LOOSEEDGES) {
- loose_edges_mask = loose_edges_map_get(
- data_cp.edge, edges_len, &loose_edges_len);
- }
-
- data_cp.tree = bvhtree_from_mesh_edges_create_tree(
- data_cp.vert, data_cp.edge, edges_len,
- loose_edges_mask, loose_edges_len, 0.0, tree_type, 6);
-
- if (loose_edges_mask != NULL) {
- MEM_freeN(loose_edges_mask);
- }
-
- /* Save on cache for later use */
- /* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(&mesh->runtime.bvh_cache, data_cp.tree, type);
- }
- BLI_rw_mutex_unlock(&cache_rwlock);
- }
- break;
-
- case BVHTREE_FROM_FACES:
- data_cp.nearest_callback = mesh_faces_nearest_point;
- data_cp.raycast_callback = mesh_faces_spherecast;
-
- data_cp.vert = mesh->mvert;
- data_cp.face = mesh->mface;
-
- if (data_cp.cached == false) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- data_cp.cached = bvhcache_find(
- mesh->runtime.bvh_cache, BVHTREE_FROM_FACES, &data_cp.tree);
- if (data_cp.cached == false) {
- int num_faces = mesh->totface;
- BLI_assert(!(num_faces == 0 && mesh->totpoly != 0));
-
- data_cp.tree = bvhtree_from_mesh_faces_create_tree(
- 0.0, tree_type, 6, data_cp.vert,
- data_cp.face, num_faces, NULL, -1);
-
- /* Save on cache for later use */
- /* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(
- &mesh->runtime.bvh_cache, data_cp.tree, BVHTREE_FROM_FACES);
- }
- BLI_rw_mutex_unlock(&cache_rwlock);
- }
- break;
-
- case BVHTREE_FROM_LOOPTRI:
- data_cp.nearest_callback = mesh_looptri_nearest_point;
- data_cp.raycast_callback = mesh_looptri_spherecast;
-
- data_cp.vert = mesh->mvert;
- data_cp.loop = mesh->mloop;
-
- /* TODO: store looptris somewhere? */
- data_cp.looptri = BKE_mesh_runtime_looptri_ensure(mesh);
-
- if (data_cp.cached == false) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- data_cp.cached = bvhcache_find(
- mesh->runtime.bvh_cache, BVHTREE_FROM_LOOPTRI, &data_cp.tree);
- if (data_cp.cached == false) {
- int looptri_num = BKE_mesh_runtime_looptri_len(mesh);
- /* this assert checks we have looptris,
- * if not caller should use DM_ensure_looptri() */
- BLI_assert(!(looptri_num == 0 && mesh->totpoly != 0));
-
- data_cp.tree = bvhtree_from_mesh_looptri_create_tree(
- 0.0, tree_type, 6,
- data_cp.vert, data_cp.loop,
- data_cp.looptri, looptri_num, NULL, -1);
-
- /* Save on cache for later use */
- /* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(
- &mesh->runtime.bvh_cache, data_cp.tree, BVHTREE_FROM_LOOPTRI);
- }
- BLI_rw_mutex_unlock(&cache_rwlock);
- }
- break;
- case BVHTREE_FROM_EM_VERTS:
- case BVHTREE_FROM_EM_EDGES:
- case BVHTREE_FROM_EM_LOOPTRI:
- BLI_assert(false);
- break;
- }
-
- if (data_cp.tree != NULL) {
+ struct BVHTreeFromMesh data_cp = {0};
+
+ BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
+ data_cp.cached = bvhcache_find(mesh->runtime.bvh_cache, type, &data_cp.tree);
+ BLI_rw_mutex_unlock(&cache_rwlock);
+
+ if (data_cp.cached && data_cp.tree == NULL) {
+ memset(data, 0, sizeof(*data));
+ return data_cp.tree;
+ }
+
+ switch (type) {
+ case BVHTREE_FROM_VERTS:
+ case BVHTREE_FROM_LOOSEVERTS:
+ data_cp.raycast_callback = mesh_verts_spherecast;
+
+ data_cp.vert = mesh->mvert;
+
+ if (data_cp.cached == false) {
+ /* TODO: a global mutex lock held during the expensive operation of
+ * building the BVH tree is really bad for performance. */
+ BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
+ data_cp.cached = bvhcache_find(mesh->runtime.bvh_cache, type, &data_cp.tree);
+
+ if (data_cp.cached == false) {
+ BLI_bitmap *loose_verts_mask = NULL;
+ int loose_vert_len = -1;
+ int verts_len = mesh->totvert;
+
+ if (type == BVHTREE_FROM_LOOSEVERTS) {
+ loose_verts_mask = loose_verts_map_get(
+ mesh->medge, mesh->totedge, data_cp.vert, verts_len, &loose_vert_len);
+ }
+
+ data_cp.tree = bvhtree_from_mesh_verts_create_tree(
+ 0.0, tree_type, 6, data_cp.vert, verts_len, loose_verts_mask, loose_vert_len);
+
+ if (loose_verts_mask != NULL) {
+ MEM_freeN(loose_verts_mask);
+ }
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(&mesh->runtime.bvh_cache, data_cp.tree, type);
+ }
+ BLI_rw_mutex_unlock(&cache_rwlock);
+ }
+ break;
+
+ case BVHTREE_FROM_EDGES:
+ case BVHTREE_FROM_LOOSEEDGES:
+ data_cp.nearest_callback = mesh_edges_nearest_point;
+ data_cp.raycast_callback = mesh_edges_spherecast;
+
+ data_cp.vert = mesh->mvert;
+ data_cp.edge = mesh->medge;
+
+ if (data_cp.cached == false) {
+ BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
+ data_cp.cached = bvhcache_find(mesh->runtime.bvh_cache, type, &data_cp.tree);
+ if (data_cp.cached == false) {
+ BLI_bitmap *loose_edges_mask = NULL;
+ int loose_edges_len = -1;
+ int edges_len = mesh->totedge;
+
+ if (type == BVHTREE_FROM_LOOSEEDGES) {
+ loose_edges_mask = loose_edges_map_get(data_cp.edge, edges_len, &loose_edges_len);
+ }
+
+ data_cp.tree = bvhtree_from_mesh_edges_create_tree(data_cp.vert,
+ data_cp.edge,
+ edges_len,
+ loose_edges_mask,
+ loose_edges_len,
+ 0.0,
+ tree_type,
+ 6);
+
+ if (loose_edges_mask != NULL) {
+ MEM_freeN(loose_edges_mask);
+ }
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(&mesh->runtime.bvh_cache, data_cp.tree, type);
+ }
+ BLI_rw_mutex_unlock(&cache_rwlock);
+ }
+ break;
+
+ case BVHTREE_FROM_FACES:
+ data_cp.nearest_callback = mesh_faces_nearest_point;
+ data_cp.raycast_callback = mesh_faces_spherecast;
+
+ data_cp.vert = mesh->mvert;
+ data_cp.face = mesh->mface;
+
+ if (data_cp.cached == false) {
+ BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
+ data_cp.cached = bvhcache_find(mesh->runtime.bvh_cache, BVHTREE_FROM_FACES, &data_cp.tree);
+ if (data_cp.cached == false) {
+ int num_faces = mesh->totface;
+ BLI_assert(!(num_faces == 0 && mesh->totpoly != 0));
+
+ data_cp.tree = bvhtree_from_mesh_faces_create_tree(
+ 0.0, tree_type, 6, data_cp.vert, data_cp.face, num_faces, NULL, -1);
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(&mesh->runtime.bvh_cache, data_cp.tree, BVHTREE_FROM_FACES);
+ }
+ BLI_rw_mutex_unlock(&cache_rwlock);
+ }
+ break;
+
+ case BVHTREE_FROM_LOOPTRI:
+ data_cp.nearest_callback = mesh_looptri_nearest_point;
+ data_cp.raycast_callback = mesh_looptri_spherecast;
+
+ data_cp.vert = mesh->mvert;
+ data_cp.loop = mesh->mloop;
+
+ /* TODO: store looptris somewhere? */
+ data_cp.looptri = BKE_mesh_runtime_looptri_ensure(mesh);
+
+ if (data_cp.cached == false) {
+ BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
+ data_cp.cached = bvhcache_find(
+ mesh->runtime.bvh_cache, BVHTREE_FROM_LOOPTRI, &data_cp.tree);
+ if (data_cp.cached == false) {
+ int looptri_num = BKE_mesh_runtime_looptri_len(mesh);
+ /* this assert checks we have looptris,
+ * if not caller should use DM_ensure_looptri() */
+ BLI_assert(!(looptri_num == 0 && mesh->totpoly != 0));
+
+ data_cp.tree = bvhtree_from_mesh_looptri_create_tree(0.0,
+ tree_type,
+ 6,
+ data_cp.vert,
+ data_cp.loop,
+ data_cp.looptri,
+ looptri_num,
+ NULL,
+ -1);
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(&mesh->runtime.bvh_cache, data_cp.tree, BVHTREE_FROM_LOOPTRI);
+ }
+ BLI_rw_mutex_unlock(&cache_rwlock);
+ }
+ break;
+ case BVHTREE_FROM_EM_VERTS:
+ case BVHTREE_FROM_EM_EDGES:
+ case BVHTREE_FROM_EM_LOOPTRI:
+ BLI_assert(false);
+ break;
+ }
+
+ if (data_cp.tree != NULL) {
#ifdef DEBUG
- if (BLI_bvhtree_get_tree_type(data_cp.tree) != tree_type) {
- printf("tree_type %d obtained instead of %d\n",
- BLI_bvhtree_get_tree_type(data_cp.tree), tree_type);
- }
+ if (BLI_bvhtree_get_tree_type(data_cp.tree) != tree_type) {
+ printf("tree_type %d obtained instead of %d\n",
+ BLI_bvhtree_get_tree_type(data_cp.tree),
+ tree_type);
+ }
#endif
- data_cp.cached = true;
- memcpy(data, &data_cp, sizeof(*data));
- }
- else {
- free_bvhtree_from_mesh(&data_cp);
- memset(data, 0, sizeof(*data));
- }
-
- return data_cp.tree;
+ data_cp.cached = true;
+ memcpy(data, &data_cp, sizeof(*data));
+ }
+ else {
+ free_bvhtree_from_mesh(&data_cp);
+ memset(data, 0, sizeof(*data));
+ }
+
+ return data_cp.tree;
}
/** \} */
-
/* Frees data allocated by a call to bvhtree_from_editmesh_*. */
void free_bvhtree_from_editmesh(struct BVHTreeFromEditMesh *data)
{
- if (data->tree) {
- if (!data->cached) {
- BLI_bvhtree_free(data->tree);
- }
- memset(data, 0, sizeof(*data));
- }
+ if (data->tree) {
+ if (!data->cached) {
+ BLI_bvhtree_free(data->tree);
+ }
+ memset(data, 0, sizeof(*data));
+ }
}
/* Frees data allocated by a call to bvhtree_from_mesh_*. */
void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data)
{
- if (data->tree && !data->cached) {
- BLI_bvhtree_free(data->tree);
- }
-
- if (data->vert_allocated) {
- MEM_freeN((void *)data->vert);
- }
- if (data->edge_allocated) {
- MEM_freeN((void *)data->edge);
- }
- if (data->face_allocated) {
- MEM_freeN((void *)data->face);
- }
- if (data->loop_allocated) {
- MEM_freeN((void *)data->loop);
- }
- if (data->looptri_allocated) {
- MEM_freeN((void *)data->looptri);
- }
-
- memset(data, 0, sizeof(*data));
+ if (data->tree && !data->cached) {
+ BLI_bvhtree_free(data->tree);
+ }
+
+ if (data->vert_allocated) {
+ MEM_freeN((void *)data->vert);
+ }
+ if (data->edge_allocated) {
+ MEM_freeN((void *)data->edge);
+ }
+ if (data->face_allocated) {
+ MEM_freeN((void *)data->face);
+ }
+ if (data->loop_allocated) {
+ MEM_freeN((void *)data->loop);
+ }
+ if (data->looptri_allocated) {
+ MEM_freeN((void *)data->looptri);
+ }
+
+ memset(data, 0, sizeof(*data));
}
-
/* -------------------------------------------------------------------- */
/** \name BVHCache
* \{ */
typedef struct BVHCacheItem {
- int type;
- BVHTree *tree;
+ int type;
+ BVHTree *tree;
} BVHCacheItem;
@@ -1312,27 +1397,27 @@ typedef struct BVHCacheItem {
*/
bool bvhcache_find(const BVHCache *cache, int type, BVHTree **r_tree)
{
- while (cache) {
- const BVHCacheItem *item = cache->link;
- if (item->type == type) {
- *r_tree = item->tree;
- return true;
- }
- cache = cache->next;
- }
- return false;
+ while (cache) {
+ const BVHCacheItem *item = cache->link;
+ if (item->type == type) {
+ *r_tree = item->tree;
+ return true;
+ }
+ cache = cache->next;
+ }
+ return false;
}
bool bvhcache_has_tree(const BVHCache *cache, const BVHTree *tree)
{
- while (cache) {
- const BVHCacheItem *item = cache->link;
- if (item->tree == tree) {
- return true;
- }
- cache = cache->next;
- }
- return false;
+ while (cache) {
+ const BVHCacheItem *item = cache->link;
+ if (item->tree == tree) {
+ return true;
+ }
+ cache = cache->next;
+ }
+ return false;
}
/**
@@ -1344,16 +1429,16 @@ bool bvhcache_has_tree(const BVHCache *cache, const BVHTree *tree)
*/
void bvhcache_insert(BVHCache **cache_p, BVHTree *tree, int type)
{
- BVHCacheItem *item = NULL;
+ BVHCacheItem *item = NULL;
- assert(bvhcache_find(*cache_p, type, &(BVHTree *){0}) == false);
+ assert(bvhcache_find(*cache_p, type, &(BVHTree *){0}) == false);
- item = MEM_mallocN(sizeof(BVHCacheItem), "BVHCacheItem");
+ item = MEM_mallocN(sizeof(BVHCacheItem), "BVHCacheItem");
- item->type = type;
- item->tree = tree;
+ item->type = type;
+ item->tree = tree;
- BLI_linklist_prepend(cache_p, item);
+ BLI_linklist_prepend(cache_p, item);
}
/**
@@ -1361,17 +1446,16 @@ void bvhcache_insert(BVHCache **cache_p, BVHTree *tree, int type)
*/
static void bvhcacheitem_free(void *_item)
{
- BVHCacheItem *item = (BVHCacheItem *)_item;
+ BVHCacheItem *item = (BVHCacheItem *)_item;
- BLI_bvhtree_free(item->tree);
- MEM_freeN(item);
+ BLI_bvhtree_free(item->tree);
+ MEM_freeN(item);
}
-
void bvhcache_free(BVHCache **cache_p)
{
- BLI_linklist_free(*cache_p, (LinkNodeFreeFP)bvhcacheitem_free);
- *cache_p = NULL;
+ BLI_linklist_free(*cache_p, (LinkNodeFreeFP)bvhcacheitem_free);
+ *cache_p = NULL;
}
/** \} */
diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c
index 2c9e4966fc9..4fe8cabde65 100644
--- a/source/blender/blenkernel/intern/cachefile.c
+++ b/source/blender/blenkernel/intern/cachefile.c
@@ -49,57 +49,57 @@ static SpinLock spin;
void BKE_cachefiles_init(void)
{
- BLI_spin_init(&spin);
+ BLI_spin_init(&spin);
}
void BKE_cachefiles_exit(void)
{
- BLI_spin_end(&spin);
+ BLI_spin_end(&spin);
}
void *BKE_cachefile_add(Main *bmain, const char *name)
{
- CacheFile *cache_file = BKE_libblock_alloc(bmain, ID_CF, name, 0);
+ CacheFile *cache_file = BKE_libblock_alloc(bmain, ID_CF, name, 0);
- BKE_cachefile_init(cache_file);
+ BKE_cachefile_init(cache_file);
- return cache_file;
+ return cache_file;
}
void BKE_cachefile_init(CacheFile *cache_file)
{
- cache_file->handle = NULL;
- cache_file->filepath[0] = '\0';
- cache_file->override_frame = false;
- cache_file->frame = 0.0f;
- cache_file->is_sequence = false;
- cache_file->scale = 1.0f;
- cache_file->handle_mutex = BLI_mutex_alloc();
- BLI_listbase_clear(&cache_file->object_paths);
+ cache_file->handle = NULL;
+ cache_file->filepath[0] = '\0';
+ cache_file->override_frame = false;
+ cache_file->frame = 0.0f;
+ cache_file->is_sequence = false;
+ cache_file->scale = 1.0f;
+ cache_file->handle_mutex = BLI_mutex_alloc();
+ BLI_listbase_clear(&cache_file->object_paths);
}
/** Free (or release) any data used by this cachefile (does not free the cachefile itself). */
void BKE_cachefile_free(CacheFile *cache_file)
{
- BKE_animdata_free((ID *)cache_file, false);
+ BKE_animdata_free((ID *)cache_file, false);
- if (cache_file->id.tag & LIB_TAG_NO_MAIN) {
- /* CoW/no-main copies reuse the existing ArchiveReader and mutex */
- return;
- }
+ if (cache_file->id.tag & LIB_TAG_NO_MAIN) {
+ /* CoW/no-main copies reuse the existing ArchiveReader and mutex */
+ return;
+ }
- if (cache_file->handle) {
+ if (cache_file->handle) {
#ifdef WITH_ALEMBIC
- ABC_free_handle(cache_file->handle);
+ ABC_free_handle(cache_file->handle);
#endif
- cache_file->handle = NULL;
- }
- if (cache_file->handle_mutex) {
- BLI_mutex_free(cache_file->handle_mutex);
- cache_file->handle_mutex = NULL;
- }
-
- BLI_freelistN(&cache_file->object_paths);
+ cache_file->handle = NULL;
+ }
+ if (cache_file->handle_mutex) {
+ BLI_mutex_free(cache_file->handle_mutex);
+ cache_file->handle_mutex = NULL;
+ }
+
+ BLI_freelistN(&cache_file->object_paths);
}
/**
@@ -110,158 +110,161 @@ void BKE_cachefile_free(CacheFile *cache_file)
*
* \param flag: Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
*/
-void BKE_cachefile_copy_data(
- Main *UNUSED(bmain), CacheFile *cache_file_dst, const CacheFile *UNUSED(cache_file_src), const int UNUSED(flag))
+void BKE_cachefile_copy_data(Main *UNUSED(bmain),
+ CacheFile *cache_file_dst,
+ const CacheFile *UNUSED(cache_file_src),
+ const int UNUSED(flag))
{
- if (cache_file_dst->id.tag & LIB_TAG_NO_MAIN) {
- /* CoW/no-main copies reuse the existing ArchiveReader and mutex */
- return;
- }
-
- cache_file_dst->handle = NULL;
- cache_file_dst->handle_mutex = NULL;
- BLI_duplicatelist(&cache_file_dst->object_paths, &cache_file_dst->object_paths);
+ if (cache_file_dst->id.tag & LIB_TAG_NO_MAIN) {
+ /* CoW/no-main copies reuse the existing ArchiveReader and mutex */
+ return;
+ }
+
+ cache_file_dst->handle = NULL;
+ cache_file_dst->handle_mutex = NULL;
+ BLI_duplicatelist(&cache_file_dst->object_paths, &cache_file_dst->object_paths);
}
CacheFile *BKE_cachefile_copy(Main *bmain, const CacheFile *cache_file)
{
- CacheFile *cache_file_copy;
- BKE_id_copy(bmain, &cache_file->id, (ID **)&cache_file_copy);
- return cache_file_copy;
+ CacheFile *cache_file_copy;
+ BKE_id_copy(bmain, &cache_file->id, (ID **)&cache_file_copy);
+ return cache_file_copy;
}
void BKE_cachefile_make_local(Main *bmain, CacheFile *cache_file, const bool lib_local)
{
- BKE_id_make_local_generic(bmain, &cache_file->id, true, lib_local);
+ BKE_id_make_local_generic(bmain, &cache_file->id, true, lib_local);
}
void BKE_cachefile_reload(const Main *bmain, CacheFile *cache_file)
{
- char filepath[FILE_MAX];
+ char filepath[FILE_MAX];
- BLI_strncpy(filepath, cache_file->filepath, sizeof(filepath));
- BLI_path_abs(filepath, ID_BLEND_PATH(bmain, &cache_file->id));
+ BLI_strncpy(filepath, cache_file->filepath, sizeof(filepath));
+ BLI_path_abs(filepath, ID_BLEND_PATH(bmain, &cache_file->id));
#ifdef WITH_ALEMBIC
- if (cache_file->handle) {
- ABC_free_handle(cache_file->handle);
- }
+ if (cache_file->handle) {
+ ABC_free_handle(cache_file->handle);
+ }
- cache_file->handle = ABC_create_handle(filepath, &cache_file->object_paths);
+ cache_file->handle = ABC_create_handle(filepath, &cache_file->object_paths);
#endif
}
void BKE_cachefile_ensure_handle(const Main *bmain, CacheFile *cache_file)
{
- BLI_spin_lock(&spin);
- if (cache_file->handle_mutex == NULL) {
- cache_file->handle_mutex = BLI_mutex_alloc();
- }
- BLI_spin_unlock(&spin);
+ BLI_spin_lock(&spin);
+ if (cache_file->handle_mutex == NULL) {
+ cache_file->handle_mutex = BLI_mutex_alloc();
+ }
+ BLI_spin_unlock(&spin);
- BLI_mutex_lock(cache_file->handle_mutex);
+ BLI_mutex_lock(cache_file->handle_mutex);
- if (cache_file->handle == NULL) {
- /* Assigning to a CoW copy is a bad idea; assign to the original instead. */
- BLI_assert((cache_file->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0);
- BKE_cachefile_reload(bmain, cache_file);
- }
+ if (cache_file->handle == NULL) {
+ /* Assigning to a CoW copy is a bad idea; assign to the original instead. */
+ BLI_assert((cache_file->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0);
+ BKE_cachefile_reload(bmain, cache_file);
+ }
- BLI_mutex_unlock(cache_file->handle_mutex);
+ BLI_mutex_unlock(cache_file->handle_mutex);
}
void BKE_cachefile_update_frame(
- Main *bmain, struct Depsgraph *depsgraph, Scene *scene,
- const float ctime, const float fps)
+ Main *bmain, struct Depsgraph *depsgraph, Scene *scene, const float ctime, const float fps)
{
- CacheFile *cache_file;
- char filename[FILE_MAX];
+ CacheFile *cache_file;
+ char filename[FILE_MAX];
- for (cache_file = bmain->cachefiles.first; cache_file; cache_file = cache_file->id.next) {
- /* TODO: dependency graph should be updated to do drivers on cachefile.
- * Execute drivers only, as animation has already been done. */
- BKE_animsys_evaluate_animdata(depsgraph, scene, &cache_file->id, cache_file->adt, ctime, ADT_RECALC_DRIVERS);
+ for (cache_file = bmain->cachefiles.first; cache_file; cache_file = cache_file->id.next) {
+ /* TODO: dependency graph should be updated to do drivers on cachefile.
+ * Execute drivers only, as animation has already been done. */
+ BKE_animsys_evaluate_animdata(
+ depsgraph, scene, &cache_file->id, cache_file->adt, ctime, ADT_RECALC_DRIVERS);
- if (!cache_file->is_sequence) {
- continue;
- }
+ if (!cache_file->is_sequence) {
+ continue;
+ }
- const float time = BKE_cachefile_time_offset(cache_file, ctime, fps);
+ const float time = BKE_cachefile_time_offset(cache_file, ctime, fps);
- if (BKE_cachefile_filepath_get(bmain, cache_file, time, filename)) {
- BKE_cachefile_clean(bmain, cache_file);
+ if (BKE_cachefile_filepath_get(bmain, cache_file, time, filename)) {
+ BKE_cachefile_clean(bmain, cache_file);
#ifdef WITH_ALEMBIC
- ABC_free_handle(cache_file->handle);
- cache_file->handle = ABC_create_handle(filename, NULL);
+ ABC_free_handle(cache_file->handle);
+ cache_file->handle = ABC_create_handle(filename, NULL);
#endif
- }
- }
+ }
+ }
}
-bool BKE_cachefile_filepath_get(
- const Main *bmain, const CacheFile *cache_file, float frame,
- char r_filepath[FILE_MAX])
+bool BKE_cachefile_filepath_get(const Main *bmain,
+ const CacheFile *cache_file,
+ float frame,
+ char r_filepath[FILE_MAX])
{
- BLI_strncpy(r_filepath, cache_file->filepath, FILE_MAX);
- BLI_path_abs(r_filepath, ID_BLEND_PATH(bmain, &cache_file->id));
+ BLI_strncpy(r_filepath, cache_file->filepath, FILE_MAX);
+ BLI_path_abs(r_filepath, ID_BLEND_PATH(bmain, &cache_file->id));
- int fframe;
- int frame_len;
+ int fframe;
+ int frame_len;
- if (cache_file->is_sequence && BLI_path_frame_get(r_filepath, &fframe, &frame_len)) {
- char ext[32];
- BLI_path_frame_strip(r_filepath, ext);
- BLI_path_frame(r_filepath, frame, frame_len);
- BLI_path_extension_ensure(r_filepath, FILE_MAX, ext);
+ if (cache_file->is_sequence && BLI_path_frame_get(r_filepath, &fframe, &frame_len)) {
+ char ext[32];
+ BLI_path_frame_strip(r_filepath, ext);
+ BLI_path_frame(r_filepath, frame, frame_len);
+ BLI_path_extension_ensure(r_filepath, FILE_MAX, ext);
- /* TODO(kevin): store sequence range? */
- return BLI_exists(r_filepath);
- }
+ /* TODO(kevin): store sequence range? */
+ return BLI_exists(r_filepath);
+ }
- return true;
+ return true;
}
float BKE_cachefile_time_offset(CacheFile *cache_file, const float time, const float fps)
{
- const float time_offset = cache_file->frame_offset / fps;
- const float frame = (cache_file->override_frame ? cache_file->frame : time);
- return cache_file->is_sequence ? frame : frame / fps - time_offset;
+ const float time_offset = cache_file->frame_offset / fps;
+ const float frame = (cache_file->override_frame ? cache_file->frame : time);
+ return cache_file->is_sequence ? frame : frame / fps - time_offset;
}
/* TODO(kevin): replace this with some depsgraph mechanism, or something similar. */
void BKE_cachefile_clean(struct Main *bmain, CacheFile *cache_file)
{
- for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
- ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache);
+ for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
+ ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache);
- if (md) {
- MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
+ if (md) {
+ MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
- if (cache_file == mcmd->cache_file) {
+ if (cache_file == mcmd->cache_file) {
#ifdef WITH_ALEMBIC
- if (mcmd->reader != NULL) {
- CacheReader_free(mcmd->reader);
- }
+ if (mcmd->reader != NULL) {
+ CacheReader_free(mcmd->reader);
+ }
#endif
- mcmd->reader = NULL;
- }
- }
+ mcmd->reader = NULL;
+ }
+ }
- for (bConstraint *con = ob->constraints.first; con; con = con->next) {
- if (con->type != CONSTRAINT_TYPE_TRANSFORM_CACHE) {
- continue;
- }
+ for (bConstraint *con = ob->constraints.first; con; con = con->next) {
+ if (con->type != CONSTRAINT_TYPE_TRANSFORM_CACHE) {
+ continue;
+ }
- bTransformCacheConstraint *data = con->data;
+ bTransformCacheConstraint *data = con->data;
- if (cache_file == data->cache_file) {
+ if (cache_file == data->cache_file) {
#ifdef WITH_ALEMBIC
- if (data->reader != NULL) {
- CacheReader_free(data->reader);
- }
+ if (data->reader != NULL) {
+ CacheReader_free(data->reader);
+ }
#endif
- data->reader = NULL;
- }
- }
- }
+ data->reader = NULL;
+ }
+ }
+ }
}
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index ce3db985c49..f4d09be2991 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -54,37 +54,37 @@
void BKE_camera_init(Camera *cam)
{
- BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(cam, id));
-
- cam->lens = 50.0f;
- cam->sensor_x = DEFAULT_SENSOR_WIDTH;
- cam->sensor_y = DEFAULT_SENSOR_HEIGHT;
- cam->clip_start = 0.1f;
- cam->clip_end = 1000.0f;
- cam->drawsize = 1.0f;
- cam->ortho_scale = 6.0;
- cam->flag |= CAM_SHOWPASSEPARTOUT;
- cam->passepartalpha = 0.5f;
-
- cam->gpu_dof.fstop = 128.0f;
- cam->gpu_dof.ratio = 1.0f;
-
- /* stereoscopy 3d */
- cam->stereo.interocular_distance = 0.065f;
- cam->stereo.convergence_distance = 30.f * 0.065f;
- cam->stereo.pole_merge_angle_from = DEG2RADF(60.0f);
- cam->stereo.pole_merge_angle_to = DEG2RADF(75.0f);
+ BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(cam, id));
+
+ cam->lens = 50.0f;
+ cam->sensor_x = DEFAULT_SENSOR_WIDTH;
+ cam->sensor_y = DEFAULT_SENSOR_HEIGHT;
+ cam->clip_start = 0.1f;
+ cam->clip_end = 1000.0f;
+ cam->drawsize = 1.0f;
+ cam->ortho_scale = 6.0;
+ cam->flag |= CAM_SHOWPASSEPARTOUT;
+ cam->passepartalpha = 0.5f;
+
+ cam->gpu_dof.fstop = 128.0f;
+ cam->gpu_dof.ratio = 1.0f;
+
+ /* stereoscopy 3d */
+ cam->stereo.interocular_distance = 0.065f;
+ cam->stereo.convergence_distance = 30.f * 0.065f;
+ cam->stereo.pole_merge_angle_from = DEG2RADF(60.0f);
+ cam->stereo.pole_merge_angle_to = DEG2RADF(75.0f);
}
void *BKE_camera_add(Main *bmain, const char *name)
{
- Camera *cam;
+ Camera *cam;
- cam = BKE_libblock_alloc(bmain, ID_CA, name, 0);
+ cam = BKE_libblock_alloc(bmain, ID_CA, name, 0);
- BKE_camera_init(cam);
+ BKE_camera_init(cam);
- return cam;
+ return cam;
}
/**
@@ -95,29 +95,32 @@ void *BKE_camera_add(Main *bmain, const char *name)
*
* \param flag: Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
*/
-void BKE_camera_copy_data(Main *UNUSED(bmain), Camera *cam_dst, const Camera *cam_src, const int UNUSED(flag))
+void BKE_camera_copy_data(Main *UNUSED(bmain),
+ Camera *cam_dst,
+ const Camera *cam_src,
+ const int UNUSED(flag))
{
- BLI_duplicatelist(&cam_dst->bg_images, &cam_src->bg_images);
+ BLI_duplicatelist(&cam_dst->bg_images, &cam_src->bg_images);
}
Camera *BKE_camera_copy(Main *bmain, const Camera *cam)
{
- Camera *cam_copy;
- BKE_id_copy(bmain, &cam->id, (ID **)&cam_copy);
- return cam_copy;
+ Camera *cam_copy;
+ BKE_id_copy(bmain, &cam->id, (ID **)&cam_copy);
+ return cam_copy;
}
void BKE_camera_make_local(Main *bmain, Camera *cam, const bool lib_local)
{
- BKE_id_make_local_generic(bmain, &cam->id, true, lib_local);
+ BKE_id_make_local_generic(bmain, &cam->id, true, lib_local);
}
/** Free (or release) any data used by this camera (does not free the camera itself). */
void BKE_camera_free(Camera *ca)
{
- BLI_freelistN(&ca->bg_images);
+ BLI_freelistN(&ca->bg_images);
- BKE_animdata_free((ID *)ca, false);
+ BKE_animdata_free((ID *)ca, false);
}
/******************************** Camera Usage *******************************/
@@ -125,859 +128,917 @@ void BKE_camera_free(Camera *ca)
/* get the camera's dof value, takes the dof object into account */
float BKE_camera_object_dof_distance(Object *ob)
{
- Camera *cam = (Camera *)ob->data;
- if (ob->type != OB_CAMERA)
- return 0.0f;
- if (cam->dof_ob) {
- float view_dir[3], dof_dir[3];
- normalize_v3_v3(view_dir, ob->obmat[2]);
- sub_v3_v3v3(dof_dir, ob->obmat[3], cam->dof_ob->obmat[3]);
- return fabsf(dot_v3v3(view_dir, dof_dir));
- }
- return cam->dof_distance;
+ Camera *cam = (Camera *)ob->data;
+ if (ob->type != OB_CAMERA)
+ return 0.0f;
+ if (cam->dof_ob) {
+ float view_dir[3], dof_dir[3];
+ normalize_v3_v3(view_dir, ob->obmat[2]);
+ sub_v3_v3v3(dof_dir, ob->obmat[3], cam->dof_ob->obmat[3]);
+ return fabsf(dot_v3v3(view_dir, dof_dir));
+ }
+ return cam->dof_distance;
}
float BKE_camera_sensor_size(int sensor_fit, float sensor_x, float sensor_y)
{
- /* sensor size used to fit to. for auto, sensor_x is both x and y. */
- if (sensor_fit == CAMERA_SENSOR_FIT_VERT)
- return sensor_y;
+ /* sensor size used to fit to. for auto, sensor_x is both x and y. */
+ if (sensor_fit == CAMERA_SENSOR_FIT_VERT)
+ return sensor_y;
- return sensor_x;
+ return sensor_x;
}
int BKE_camera_sensor_fit(int sensor_fit, float sizex, float sizey)
{
- if (sensor_fit == CAMERA_SENSOR_FIT_AUTO) {
- if (sizex >= sizey)
- return CAMERA_SENSOR_FIT_HOR;
- else
- return CAMERA_SENSOR_FIT_VERT;
- }
-
- return sensor_fit;
+ if (sensor_fit == CAMERA_SENSOR_FIT_AUTO) {
+ if (sizex >= sizey)
+ return CAMERA_SENSOR_FIT_HOR;
+ else
+ return CAMERA_SENSOR_FIT_VERT;
+ }
+
+ return sensor_fit;
}
/******************************** Camera Params *******************************/
void BKE_camera_params_init(CameraParams *params)
{
- memset(params, 0, sizeof(CameraParams));
+ memset(params, 0, sizeof(CameraParams));
- /* defaults */
- params->sensor_x = DEFAULT_SENSOR_WIDTH;
- params->sensor_y = DEFAULT_SENSOR_HEIGHT;
- params->sensor_fit = CAMERA_SENSOR_FIT_AUTO;
+ /* defaults */
+ params->sensor_x = DEFAULT_SENSOR_WIDTH;
+ params->sensor_y = DEFAULT_SENSOR_HEIGHT;
+ params->sensor_fit = CAMERA_SENSOR_FIT_AUTO;
- params->zoom = 1.0f;
+ params->zoom = 1.0f;
- /* fallback for non camera objects */
- params->clip_start = 0.1f;
- params->clip_end = 100.0f;
+ /* fallback for non camera objects */
+ params->clip_start = 0.1f;
+ params->clip_end = 100.0f;
}
void BKE_camera_params_from_object(CameraParams *params, const Object *ob)
{
- if (!ob)
- return;
-
- if (ob->type == OB_CAMERA) {
- /* camera object */
- Camera *cam = ob->data;
-
- if (cam->type == CAM_ORTHO)
- params->is_ortho = true;
- params->lens = cam->lens;
- params->ortho_scale = cam->ortho_scale;
-
- params->shiftx = cam->shiftx;
- params->shifty = cam->shifty;
-
- params->sensor_x = cam->sensor_x;
- params->sensor_y = cam->sensor_y;
- params->sensor_fit = cam->sensor_fit;
-
- params->clip_start = cam->clip_start;
- params->clip_end = cam->clip_end;
- }
- else if (ob->type == OB_LAMP) {
- /* light object */
- Light *la = ob->data;
- params->lens = 16.0f / tanf(la->spotsize * 0.5f);
- if (params->lens == 0.0f)
- params->lens = 35.0f;
- }
- else {
- params->lens = 35.0f;
- }
-}
-
-void BKE_camera_params_from_view3d(CameraParams *params, Depsgraph *depsgraph, const View3D *v3d, const RegionView3D *rv3d)
-{
- /* common */
- params->lens = v3d->lens;
- params->clip_start = v3d->clip_start;
- params->clip_end = v3d->clip_end;
-
- if (rv3d->persp == RV3D_CAMOB) {
- /* camera view */
- const Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, v3d->camera);
- BKE_camera_params_from_object(params, ob_camera_eval);
-
- params->zoom = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom);
-
- params->offsetx = 2.0f * rv3d->camdx * params->zoom;
- params->offsety = 2.0f * rv3d->camdy * params->zoom;
-
- params->shiftx *= params->zoom;
- params->shifty *= params->zoom;
-
- params->zoom = CAMERA_PARAM_ZOOM_INIT_CAMOB / params->zoom;
- }
- else if (rv3d->persp == RV3D_ORTHO) {
- /* orthographic view */
- float sensor_size = BKE_camera_sensor_size(params->sensor_fit, params->sensor_x, params->sensor_y);
- /* Halve, otherwise too extreme low zbuffer quality. */
- params->clip_end *= 0.5f;
- params->clip_start = -params->clip_end;
-
- params->is_ortho = true;
- /* make sure any changes to this match ED_view3d_radius_to_dist_ortho() */
- params->ortho_scale = rv3d->dist * sensor_size / v3d->lens;
- params->zoom = CAMERA_PARAM_ZOOM_INIT_PERSP;
- }
- else {
- /* perspective view */
- params->zoom = CAMERA_PARAM_ZOOM_INIT_PERSP;
- }
-}
-
-void BKE_camera_params_compute_viewplane(CameraParams *params, int winx, int winy, float xasp, float yasp)
-{
- rctf viewplane;
- float pixsize, viewfac, sensor_size, dx, dy;
- int sensor_fit;
-
- params->ycor = yasp / xasp;
-
- if (params->is_ortho) {
- /* orthographic camera */
- /* scale == 1.0 means exact 1 to 1 mapping */
- pixsize = params->ortho_scale;
- }
- else {
- /* perspective camera */
- sensor_size = BKE_camera_sensor_size(params->sensor_fit, params->sensor_x, params->sensor_y);
- pixsize = (sensor_size * params->clip_start) / params->lens;
- }
-
- /* determine sensor fit */
- sensor_fit = BKE_camera_sensor_fit(params->sensor_fit, xasp * winx, yasp * winy);
-
- if (sensor_fit == CAMERA_SENSOR_FIT_HOR)
- viewfac = winx;
- else
- viewfac = params->ycor * winy;
-
- pixsize /= viewfac;
-
- /* extra zoom factor */
- pixsize *= params->zoom;
-
- /* compute view plane:
- * fully centered, zbuffer fills in jittered between -.5 and +.5 */
- viewplane.xmin = -0.5f * (float)winx;
- viewplane.ymin = -0.5f * params->ycor * (float)winy;
- viewplane.xmax = 0.5f * (float)winx;
- viewplane.ymax = 0.5f * params->ycor * (float)winy;
-
- /* lens shift and offset */
- dx = params->shiftx * viewfac + winx * params->offsetx;
- dy = params->shifty * viewfac + winy * params->offsety;
-
- viewplane.xmin += dx;
- viewplane.ymin += dy;
- viewplane.xmax += dx;
- viewplane.ymax += dy;
-
- /* the window matrix is used for clipping, and not changed during OSA steps */
- /* using an offset of +0.5 here would give clip errors on edges */
- viewplane.xmin *= pixsize;
- viewplane.xmax *= pixsize;
- viewplane.ymin *= pixsize;
- viewplane.ymax *= pixsize;
-
- /* Used for rendering (offset by near-clip with perspective views), passed to RE_SetPixelSize.
- * For viewport drawing 'RegionView3D.pixsize'. */
- params->viewdx = pixsize;
- params->viewdy = params->ycor * pixsize;
- params->viewplane = viewplane;
+ if (!ob)
+ return;
+
+ if (ob->type == OB_CAMERA) {
+ /* camera object */
+ Camera *cam = ob->data;
+
+ if (cam->type == CAM_ORTHO)
+ params->is_ortho = true;
+ params->lens = cam->lens;
+ params->ortho_scale = cam->ortho_scale;
+
+ params->shiftx = cam->shiftx;
+ params->shifty = cam->shifty;
+
+ params->sensor_x = cam->sensor_x;
+ params->sensor_y = cam->sensor_y;
+ params->sensor_fit = cam->sensor_fit;
+
+ params->clip_start = cam->clip_start;
+ params->clip_end = cam->clip_end;
+ }
+ else if (ob->type == OB_LAMP) {
+ /* light object */
+ Light *la = ob->data;
+ params->lens = 16.0f / tanf(la->spotsize * 0.5f);
+ if (params->lens == 0.0f)
+ params->lens = 35.0f;
+ }
+ else {
+ params->lens = 35.0f;
+ }
+}
+
+void BKE_camera_params_from_view3d(CameraParams *params,
+ Depsgraph *depsgraph,
+ const View3D *v3d,
+ const RegionView3D *rv3d)
+{
+ /* common */
+ params->lens = v3d->lens;
+ params->clip_start = v3d->clip_start;
+ params->clip_end = v3d->clip_end;
+
+ if (rv3d->persp == RV3D_CAMOB) {
+ /* camera view */
+ const Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, v3d->camera);
+ BKE_camera_params_from_object(params, ob_camera_eval);
+
+ params->zoom = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom);
+
+ params->offsetx = 2.0f * rv3d->camdx * params->zoom;
+ params->offsety = 2.0f * rv3d->camdy * params->zoom;
+
+ params->shiftx *= params->zoom;
+ params->shifty *= params->zoom;
+
+ params->zoom = CAMERA_PARAM_ZOOM_INIT_CAMOB / params->zoom;
+ }
+ else if (rv3d->persp == RV3D_ORTHO) {
+ /* orthographic view */
+ float sensor_size = BKE_camera_sensor_size(
+ params->sensor_fit, params->sensor_x, params->sensor_y);
+ /* Halve, otherwise too extreme low zbuffer quality. */
+ params->clip_end *= 0.5f;
+ params->clip_start = -params->clip_end;
+
+ params->is_ortho = true;
+ /* make sure any changes to this match ED_view3d_radius_to_dist_ortho() */
+ params->ortho_scale = rv3d->dist * sensor_size / v3d->lens;
+ params->zoom = CAMERA_PARAM_ZOOM_INIT_PERSP;
+ }
+ else {
+ /* perspective view */
+ params->zoom = CAMERA_PARAM_ZOOM_INIT_PERSP;
+ }
+}
+
+void BKE_camera_params_compute_viewplane(
+ CameraParams *params, int winx, int winy, float xasp, float yasp)
+{
+ rctf viewplane;
+ float pixsize, viewfac, sensor_size, dx, dy;
+ int sensor_fit;
+
+ params->ycor = yasp / xasp;
+
+ if (params->is_ortho) {
+ /* orthographic camera */
+ /* scale == 1.0 means exact 1 to 1 mapping */
+ pixsize = params->ortho_scale;
+ }
+ else {
+ /* perspective camera */
+ sensor_size = BKE_camera_sensor_size(params->sensor_fit, params->sensor_x, params->sensor_y);
+ pixsize = (sensor_size * params->clip_start) / params->lens;
+ }
+
+ /* determine sensor fit */
+ sensor_fit = BKE_camera_sensor_fit(params->sensor_fit, xasp * winx, yasp * winy);
+
+ if (sensor_fit == CAMERA_SENSOR_FIT_HOR)
+ viewfac = winx;
+ else
+ viewfac = params->ycor * winy;
+
+ pixsize /= viewfac;
+
+ /* extra zoom factor */
+ pixsize *= params->zoom;
+
+ /* compute view plane:
+ * fully centered, zbuffer fills in jittered between -.5 and +.5 */
+ viewplane.xmin = -0.5f * (float)winx;
+ viewplane.ymin = -0.5f * params->ycor * (float)winy;
+ viewplane.xmax = 0.5f * (float)winx;
+ viewplane.ymax = 0.5f * params->ycor * (float)winy;
+
+ /* lens shift and offset */
+ dx = params->shiftx * viewfac + winx * params->offsetx;
+ dy = params->shifty * viewfac + winy * params->offsety;
+
+ viewplane.xmin += dx;
+ viewplane.ymin += dy;
+ viewplane.xmax += dx;
+ viewplane.ymax += dy;
+
+ /* the window matrix is used for clipping, and not changed during OSA steps */
+ /* using an offset of +0.5 here would give clip errors on edges */
+ viewplane.xmin *= pixsize;
+ viewplane.xmax *= pixsize;
+ viewplane.ymin *= pixsize;
+ viewplane.ymax *= pixsize;
+
+ /* Used for rendering (offset by near-clip with perspective views), passed to RE_SetPixelSize.
+ * For viewport drawing 'RegionView3D.pixsize'. */
+ params->viewdx = pixsize;
+ params->viewdy = params->ycor * pixsize;
+ params->viewplane = viewplane;
}
/* viewplane is assumed to be already computed */
void BKE_camera_params_compute_matrix(CameraParams *params)
{
- rctf viewplane = params->viewplane;
-
- /* compute projection matrix */
- if (params->is_ortho)
- orthographic_m4(params->winmat, viewplane.xmin, viewplane.xmax,
- viewplane.ymin, viewplane.ymax, params->clip_start, params->clip_end);
- else
- perspective_m4(params->winmat, viewplane.xmin, viewplane.xmax,
- viewplane.ymin, viewplane.ymax, params->clip_start, params->clip_end);
+ rctf viewplane = params->viewplane;
+
+ /* compute projection matrix */
+ if (params->is_ortho)
+ orthographic_m4(params->winmat,
+ viewplane.xmin,
+ viewplane.xmax,
+ viewplane.ymin,
+ viewplane.ymax,
+ params->clip_start,
+ params->clip_end);
+ else
+ perspective_m4(params->winmat,
+ viewplane.xmin,
+ viewplane.xmax,
+ viewplane.ymin,
+ viewplane.ymax,
+ params->clip_start,
+ params->clip_end);
}
/***************************** Camera View Frame *****************************/
-void BKE_camera_view_frame_ex(
- const Scene *scene, const Camera *camera,
- const float drawsize, const bool do_clip, const float scale[3],
- float r_asp[2], float r_shift[2], float *r_drawsize, float r_vec[4][3])
-{
- float facx, facy;
- float depth;
-
- /* aspect correcton */
- if (scene) {
- float aspx = (float) scene->r.xsch * scene->r.xasp;
- float aspy = (float) scene->r.ysch * scene->r.yasp;
- int sensor_fit = BKE_camera_sensor_fit(camera->sensor_fit, aspx, aspy);
-
- if (sensor_fit == CAMERA_SENSOR_FIT_HOR) {
- r_asp[0] = 1.0;
- r_asp[1] = aspy / aspx;
- }
- else {
- r_asp[0] = aspx / aspy;
- r_asp[1] = 1.0;
- }
- }
- else {
- r_asp[0] = 1.0f;
- r_asp[1] = 1.0f;
- }
-
- if (camera->type == CAM_ORTHO) {
- facx = 0.5f * camera->ortho_scale * r_asp[0] * scale[0];
- facy = 0.5f * camera->ortho_scale * r_asp[1] * scale[1];
- r_shift[0] = camera->shiftx * camera->ortho_scale * scale[0];
- r_shift[1] = camera->shifty * camera->ortho_scale * scale[1];
- depth = -drawsize * scale[2];
-
- *r_drawsize = 0.5f * camera->ortho_scale;
- }
- else {
- /* that way it's always visible - clip_start+0.1 */
- float fac, scale_x, scale_y;
- float half_sensor = 0.5f * ((camera->sensor_fit == CAMERA_SENSOR_FIT_VERT) ?
- (camera->sensor_y) : (camera->sensor_x));
-
- /* fixed size, variable depth (stays a reasonable size in the 3D view) */
- *r_drawsize = (drawsize / 2.0f) / ((scale[0] + scale[1] + scale[2]) / 3.0f);
- depth = *r_drawsize * camera->lens / (-half_sensor) * scale[2];
- fac = *r_drawsize;
- scale_x = scale[0];
- scale_y = scale[1];
-
- facx = fac * r_asp[0] * scale_x;
- facy = fac * r_asp[1] * scale_y;
- r_shift[0] = camera->shiftx * fac * 2.0f * scale_x;
- r_shift[1] = camera->shifty * fac * 2.0f * scale_y;
- }
-
- r_vec[0][0] = r_shift[0] + facx; r_vec[0][1] = r_shift[1] + facy; r_vec[0][2] = depth;
- r_vec[1][0] = r_shift[0] + facx; r_vec[1][1] = r_shift[1] - facy; r_vec[1][2] = depth;
- r_vec[2][0] = r_shift[0] - facx; r_vec[2][1] = r_shift[1] - facy; r_vec[2][2] = depth;
- r_vec[3][0] = r_shift[0] - facx; r_vec[3][1] = r_shift[1] + facy; r_vec[3][2] = depth;
-
- if (do_clip) {
- /* Ensure the frame isn't behind the near clipping plane, T62814. */
- float fac = (camera->clip_start + 0.1f) / -r_vec[0][2];
- for (uint i = 0; i < 4; i++) {
- if (camera->type == CAM_ORTHO) {
- r_vec[i][2] *= fac;
- }
- else {
- mul_v3_fl(r_vec[i], fac);
- }
- }
- }
+void BKE_camera_view_frame_ex(const Scene *scene,
+ const Camera *camera,
+ const float drawsize,
+ const bool do_clip,
+ const float scale[3],
+ float r_asp[2],
+ float r_shift[2],
+ float *r_drawsize,
+ float r_vec[4][3])
+{
+ float facx, facy;
+ float depth;
+
+ /* aspect correcton */
+ if (scene) {
+ float aspx = (float)scene->r.xsch * scene->r.xasp;
+ float aspy = (float)scene->r.ysch * scene->r.yasp;
+ int sensor_fit = BKE_camera_sensor_fit(camera->sensor_fit, aspx, aspy);
+
+ if (sensor_fit == CAMERA_SENSOR_FIT_HOR) {
+ r_asp[0] = 1.0;
+ r_asp[1] = aspy / aspx;
+ }
+ else {
+ r_asp[0] = aspx / aspy;
+ r_asp[1] = 1.0;
+ }
+ }
+ else {
+ r_asp[0] = 1.0f;
+ r_asp[1] = 1.0f;
+ }
+
+ if (camera->type == CAM_ORTHO) {
+ facx = 0.5f * camera->ortho_scale * r_asp[0] * scale[0];
+ facy = 0.5f * camera->ortho_scale * r_asp[1] * scale[1];
+ r_shift[0] = camera->shiftx * camera->ortho_scale * scale[0];
+ r_shift[1] = camera->shifty * camera->ortho_scale * scale[1];
+ depth = -drawsize * scale[2];
+
+ *r_drawsize = 0.5f * camera->ortho_scale;
+ }
+ else {
+ /* that way it's always visible - clip_start+0.1 */
+ float fac, scale_x, scale_y;
+ float half_sensor = 0.5f * ((camera->sensor_fit == CAMERA_SENSOR_FIT_VERT) ?
+ (camera->sensor_y) :
+ (camera->sensor_x));
+
+ /* fixed size, variable depth (stays a reasonable size in the 3D view) */
+ *r_drawsize = (drawsize / 2.0f) / ((scale[0] + scale[1] + scale[2]) / 3.0f);
+ depth = *r_drawsize * camera->lens / (-half_sensor) * scale[2];
+ fac = *r_drawsize;
+ scale_x = scale[0];
+ scale_y = scale[1];
+
+ facx = fac * r_asp[0] * scale_x;
+ facy = fac * r_asp[1] * scale_y;
+ r_shift[0] = camera->shiftx * fac * 2.0f * scale_x;
+ r_shift[1] = camera->shifty * fac * 2.0f * scale_y;
+ }
+
+ r_vec[0][0] = r_shift[0] + facx;
+ r_vec[0][1] = r_shift[1] + facy;
+ r_vec[0][2] = depth;
+ r_vec[1][0] = r_shift[0] + facx;
+ r_vec[1][1] = r_shift[1] - facy;
+ r_vec[1][2] = depth;
+ r_vec[2][0] = r_shift[0] - facx;
+ r_vec[2][1] = r_shift[1] - facy;
+ r_vec[2][2] = depth;
+ r_vec[3][0] = r_shift[0] - facx;
+ r_vec[3][1] = r_shift[1] + facy;
+ r_vec[3][2] = depth;
+
+ if (do_clip) {
+ /* Ensure the frame isn't behind the near clipping plane, T62814. */
+ float fac = (camera->clip_start + 0.1f) / -r_vec[0][2];
+ for (uint i = 0; i < 4; i++) {
+ if (camera->type == CAM_ORTHO) {
+ r_vec[i][2] *= fac;
+ }
+ else {
+ mul_v3_fl(r_vec[i], fac);
+ }
+ }
+ }
}
void BKE_camera_view_frame(const Scene *scene, const Camera *camera, float r_vec[4][3])
{
- float dummy_asp[2];
- float dummy_shift[2];
- float dummy_drawsize;
- const float dummy_scale[3] = {1.0f, 1.0f, 1.0f};
+ float dummy_asp[2];
+ float dummy_shift[2];
+ float dummy_drawsize;
+ const float dummy_scale[3] = {1.0f, 1.0f, 1.0f};
- BKE_camera_view_frame_ex(scene, camera, 1.0, false, dummy_scale,
- dummy_asp, dummy_shift, &dummy_drawsize, r_vec);
+ BKE_camera_view_frame_ex(
+ scene, camera, 1.0, false, dummy_scale, dummy_asp, dummy_shift, &dummy_drawsize, r_vec);
}
#define CAMERA_VIEWFRAME_NUM_PLANES 4
typedef struct CameraViewFrameData {
- float plane_tx[CAMERA_VIEWFRAME_NUM_PLANES][4]; /* 4 planes */
- float normal_tx[CAMERA_VIEWFRAME_NUM_PLANES][3];
- float dist_vals_sq[CAMERA_VIEWFRAME_NUM_PLANES]; /* distance squared (signed) */
- unsigned int tot;
-
- /* Ortho camera only. */
- bool is_ortho;
- float camera_no[3];
- float dist_to_cam;
-
- /* Not used by callbacks... */
- float camera_rotmat[3][3];
+ float plane_tx[CAMERA_VIEWFRAME_NUM_PLANES][4]; /* 4 planes */
+ float normal_tx[CAMERA_VIEWFRAME_NUM_PLANES][3];
+ float dist_vals_sq[CAMERA_VIEWFRAME_NUM_PLANES]; /* distance squared (signed) */
+ unsigned int tot;
+
+ /* Ortho camera only. */
+ bool is_ortho;
+ float camera_no[3];
+ float dist_to_cam;
+
+ /* Not used by callbacks... */
+ float camera_rotmat[3][3];
} CameraViewFrameData;
static void camera_to_frame_view_cb(const float co[3], void *user_data)
{
- CameraViewFrameData *data = (CameraViewFrameData *)user_data;
- unsigned int i;
-
- for (i = 0; i < CAMERA_VIEWFRAME_NUM_PLANES; i++) {
- const float nd = dist_signed_squared_to_plane_v3(co, data->plane_tx[i]);
- CLAMP_MAX(data->dist_vals_sq[i], nd);
- }
-
- if (data->is_ortho) {
- const float d = dot_v3v3(data->camera_no, co);
- CLAMP_MAX(data->dist_to_cam, d);
- }
-
- data->tot++;
-}
-
-static void camera_frame_fit_data_init(
- const Scene *scene, const Object *ob,
- CameraParams *params, CameraViewFrameData *data)
-{
- float camera_rotmat_transposed_inversed[4][4];
- unsigned int i;
-
- /* setup parameters */
- BKE_camera_params_init(params);
- BKE_camera_params_from_object(params, ob);
-
- /* compute matrix, viewplane, .. */
- if (scene) {
- BKE_camera_params_compute_viewplane(params, scene->r.xsch, scene->r.ysch, scene->r.xasp, scene->r.yasp);
- }
- else {
- BKE_camera_params_compute_viewplane(params, 1, 1, 1.0f, 1.0f);
- }
- BKE_camera_params_compute_matrix(params);
-
- /* initialize callback data */
- copy_m3_m4(data->camera_rotmat, (float (*)[4])ob->obmat);
- normalize_m3(data->camera_rotmat);
- /* To transform a plane which is in its homogeneous representation (4d vector),
- * we need the inverse of the transpose of the transform matrix... */
- copy_m4_m3(camera_rotmat_transposed_inversed, data->camera_rotmat);
- transpose_m4(camera_rotmat_transposed_inversed);
- invert_m4(camera_rotmat_transposed_inversed);
-
- /* Extract frustum planes from projection matrix. */
- planes_from_projmat(params->winmat,
- /* left right top bottom near far */
- data->plane_tx[2], data->plane_tx[0], data->plane_tx[3], data->plane_tx[1], NULL, NULL);
-
- /* Rotate planes and get normals from them */
- for (i = 0; i < CAMERA_VIEWFRAME_NUM_PLANES; i++) {
- mul_m4_v4(camera_rotmat_transposed_inversed, data->plane_tx[i]);
- normalize_v3_v3(data->normal_tx[i], data->plane_tx[i]);
- }
-
- copy_v4_fl(data->dist_vals_sq, FLT_MAX);
- data->tot = 0;
- data->is_ortho = params->is_ortho;
- if (params->is_ortho) {
- /* we want (0, 0, -1) transformed by camera_rotmat, this is a quicker shortcut. */
- negate_v3_v3(data->camera_no, data->camera_rotmat[2]);
- data->dist_to_cam = FLT_MAX;
- }
-}
-
-static bool camera_frame_fit_calc_from_data(
- CameraParams *params, CameraViewFrameData *data, float r_co[3], float *r_scale)
-{
- float plane_tx[CAMERA_VIEWFRAME_NUM_PLANES][4];
- unsigned int i;
-
- if (data->tot <= 1) {
- return false;
- }
-
- if (params->is_ortho) {
- const float *cam_axis_x = data->camera_rotmat[0];
- const float *cam_axis_y = data->camera_rotmat[1];
- const float *cam_axis_z = data->camera_rotmat[2];
- float dists[CAMERA_VIEWFRAME_NUM_PLANES];
- float scale_diff;
-
- /* apply the dist-from-plane's to the transformed plane points */
- for (i = 0; i < CAMERA_VIEWFRAME_NUM_PLANES; i++) {
- dists[i] = sqrtf_signed(data->dist_vals_sq[i]);
- }
-
- if ((dists[0] + dists[2]) > (dists[1] + dists[3])) {
- scale_diff = (dists[1] + dists[3]) *
- (BLI_rctf_size_x(&params->viewplane) / BLI_rctf_size_y(&params->viewplane));
- }
- else {
- scale_diff = (dists[0] + dists[2]) *
- (BLI_rctf_size_y(&params->viewplane) / BLI_rctf_size_x(&params->viewplane));
- }
- *r_scale = params->ortho_scale - scale_diff;
-
- zero_v3(r_co);
- madd_v3_v3fl(r_co, cam_axis_x, (dists[2] - dists[0]) * 0.5f + params->shiftx * scale_diff);
- madd_v3_v3fl(r_co, cam_axis_y, (dists[1] - dists[3]) * 0.5f + params->shifty * scale_diff);
- madd_v3_v3fl(r_co, cam_axis_z, -(data->dist_to_cam - 1.0f - params->clip_start));
-
- return true;
- }
- else {
- float plane_isect_1[3], plane_isect_1_no[3], plane_isect_1_other[3];
- float plane_isect_2[3], plane_isect_2_no[3], plane_isect_2_other[3];
-
- float plane_isect_pt_1[3], plane_isect_pt_2[3];
-
- /* apply the dist-from-plane's to the transformed plane points */
- for (i = 0; i < CAMERA_VIEWFRAME_NUM_PLANES; i++) {
- float co[3];
- mul_v3_v3fl(co, data->normal_tx[i], sqrtf_signed(data->dist_vals_sq[i]));
- plane_from_point_normal_v3(plane_tx[i], co, data->normal_tx[i]);
- }
-
- if ((!isect_plane_plane_v3(plane_tx[0], plane_tx[2], plane_isect_1, plane_isect_1_no)) ||
- (!isect_plane_plane_v3(plane_tx[1], plane_tx[3], plane_isect_2, plane_isect_2_no)))
- {
- return false;
- }
-
- add_v3_v3v3(plane_isect_1_other, plane_isect_1, plane_isect_1_no);
- add_v3_v3v3(plane_isect_2_other, plane_isect_2, plane_isect_2_no);
-
- if (isect_line_line_v3(plane_isect_1, plane_isect_1_other,
- plane_isect_2, plane_isect_2_other,
- plane_isect_pt_1, plane_isect_pt_2) != 0)
- {
- float cam_plane_no[3];
- float plane_isect_delta[3];
- float plane_isect_delta_len;
-
- float shift_fac = BKE_camera_sensor_size(params->sensor_fit, params->sensor_x, params->sensor_y) /
- params->lens;
-
- /* we want (0, 0, -1) transformed by camera_rotmat, this is a quicker shortcut. */
- negate_v3_v3(cam_plane_no, data->camera_rotmat[2]);
-
- sub_v3_v3v3(plane_isect_delta, plane_isect_pt_2, plane_isect_pt_1);
- plane_isect_delta_len = len_v3(plane_isect_delta);
-
- if (dot_v3v3(plane_isect_delta, cam_plane_no) > 0.0f) {
- copy_v3_v3(r_co, plane_isect_pt_1);
-
- /* offset shift */
- normalize_v3(plane_isect_1_no);
- madd_v3_v3fl(r_co, plane_isect_1_no, params->shifty * plane_isect_delta_len * shift_fac);
- }
- else {
- copy_v3_v3(r_co, plane_isect_pt_2);
-
- /* offset shift */
- normalize_v3(plane_isect_2_no);
- madd_v3_v3fl(r_co, plane_isect_2_no, params->shiftx * plane_isect_delta_len * shift_fac);
- }
-
- return true;
- }
- }
-
- return false;
+ CameraViewFrameData *data = (CameraViewFrameData *)user_data;
+ unsigned int i;
+
+ for (i = 0; i < CAMERA_VIEWFRAME_NUM_PLANES; i++) {
+ const float nd = dist_signed_squared_to_plane_v3(co, data->plane_tx[i]);
+ CLAMP_MAX(data->dist_vals_sq[i], nd);
+ }
+
+ if (data->is_ortho) {
+ const float d = dot_v3v3(data->camera_no, co);
+ CLAMP_MAX(data->dist_to_cam, d);
+ }
+
+ data->tot++;
+}
+
+static void camera_frame_fit_data_init(const Scene *scene,
+ const Object *ob,
+ CameraParams *params,
+ CameraViewFrameData *data)
+{
+ float camera_rotmat_transposed_inversed[4][4];
+ unsigned int i;
+
+ /* setup parameters */
+ BKE_camera_params_init(params);
+ BKE_camera_params_from_object(params, ob);
+
+ /* compute matrix, viewplane, .. */
+ if (scene) {
+ BKE_camera_params_compute_viewplane(
+ params, scene->r.xsch, scene->r.ysch, scene->r.xasp, scene->r.yasp);
+ }
+ else {
+ BKE_camera_params_compute_viewplane(params, 1, 1, 1.0f, 1.0f);
+ }
+ BKE_camera_params_compute_matrix(params);
+
+ /* initialize callback data */
+ copy_m3_m4(data->camera_rotmat, (float(*)[4])ob->obmat);
+ normalize_m3(data->camera_rotmat);
+ /* To transform a plane which is in its homogeneous representation (4d vector),
+ * we need the inverse of the transpose of the transform matrix... */
+ copy_m4_m3(camera_rotmat_transposed_inversed, data->camera_rotmat);
+ transpose_m4(camera_rotmat_transposed_inversed);
+ invert_m4(camera_rotmat_transposed_inversed);
+
+ /* Extract frustum planes from projection matrix. */
+ planes_from_projmat(
+ params->winmat,
+ /* left right top bottom near far */
+ data->plane_tx[2],
+ data->plane_tx[0],
+ data->plane_tx[3],
+ data->plane_tx[1],
+ NULL,
+ NULL);
+
+ /* Rotate planes and get normals from them */
+ for (i = 0; i < CAMERA_VIEWFRAME_NUM_PLANES; i++) {
+ mul_m4_v4(camera_rotmat_transposed_inversed, data->plane_tx[i]);
+ normalize_v3_v3(data->normal_tx[i], data->plane_tx[i]);
+ }
+
+ copy_v4_fl(data->dist_vals_sq, FLT_MAX);
+ data->tot = 0;
+ data->is_ortho = params->is_ortho;
+ if (params->is_ortho) {
+ /* we want (0, 0, -1) transformed by camera_rotmat, this is a quicker shortcut. */
+ negate_v3_v3(data->camera_no, data->camera_rotmat[2]);
+ data->dist_to_cam = FLT_MAX;
+ }
+}
+
+static bool camera_frame_fit_calc_from_data(CameraParams *params,
+ CameraViewFrameData *data,
+ float r_co[3],
+ float *r_scale)
+{
+ float plane_tx[CAMERA_VIEWFRAME_NUM_PLANES][4];
+ unsigned int i;
+
+ if (data->tot <= 1) {
+ return false;
+ }
+
+ if (params->is_ortho) {
+ const float *cam_axis_x = data->camera_rotmat[0];
+ const float *cam_axis_y = data->camera_rotmat[1];
+ const float *cam_axis_z = data->camera_rotmat[2];
+ float dists[CAMERA_VIEWFRAME_NUM_PLANES];
+ float scale_diff;
+
+ /* apply the dist-from-plane's to the transformed plane points */
+ for (i = 0; i < CAMERA_VIEWFRAME_NUM_PLANES; i++) {
+ dists[i] = sqrtf_signed(data->dist_vals_sq[i]);
+ }
+
+ if ((dists[0] + dists[2]) > (dists[1] + dists[3])) {
+ scale_diff = (dists[1] + dists[3]) *
+ (BLI_rctf_size_x(&params->viewplane) / BLI_rctf_size_y(&params->viewplane));
+ }
+ else {
+ scale_diff = (dists[0] + dists[2]) *
+ (BLI_rctf_size_y(&params->viewplane) / BLI_rctf_size_x(&params->viewplane));
+ }
+ *r_scale = params->ortho_scale - scale_diff;
+
+ zero_v3(r_co);
+ madd_v3_v3fl(r_co, cam_axis_x, (dists[2] - dists[0]) * 0.5f + params->shiftx * scale_diff);
+ madd_v3_v3fl(r_co, cam_axis_y, (dists[1] - dists[3]) * 0.5f + params->shifty * scale_diff);
+ madd_v3_v3fl(r_co, cam_axis_z, -(data->dist_to_cam - 1.0f - params->clip_start));
+
+ return true;
+ }
+ else {
+ float plane_isect_1[3], plane_isect_1_no[3], plane_isect_1_other[3];
+ float plane_isect_2[3], plane_isect_2_no[3], plane_isect_2_other[3];
+
+ float plane_isect_pt_1[3], plane_isect_pt_2[3];
+
+ /* apply the dist-from-plane's to the transformed plane points */
+ for (i = 0; i < CAMERA_VIEWFRAME_NUM_PLANES; i++) {
+ float co[3];
+ mul_v3_v3fl(co, data->normal_tx[i], sqrtf_signed(data->dist_vals_sq[i]));
+ plane_from_point_normal_v3(plane_tx[i], co, data->normal_tx[i]);
+ }
+
+ if ((!isect_plane_plane_v3(plane_tx[0], plane_tx[2], plane_isect_1, plane_isect_1_no)) ||
+ (!isect_plane_plane_v3(plane_tx[1], plane_tx[3], plane_isect_2, plane_isect_2_no))) {
+ return false;
+ }
+
+ add_v3_v3v3(plane_isect_1_other, plane_isect_1, plane_isect_1_no);
+ add_v3_v3v3(plane_isect_2_other, plane_isect_2, plane_isect_2_no);
+
+ if (isect_line_line_v3(plane_isect_1,
+ plane_isect_1_other,
+ plane_isect_2,
+ plane_isect_2_other,
+ plane_isect_pt_1,
+ plane_isect_pt_2) != 0) {
+ float cam_plane_no[3];
+ float plane_isect_delta[3];
+ float plane_isect_delta_len;
+
+ float shift_fac = BKE_camera_sensor_size(
+ params->sensor_fit, params->sensor_x, params->sensor_y) /
+ params->lens;
+
+ /* we want (0, 0, -1) transformed by camera_rotmat, this is a quicker shortcut. */
+ negate_v3_v3(cam_plane_no, data->camera_rotmat[2]);
+
+ sub_v3_v3v3(plane_isect_delta, plane_isect_pt_2, plane_isect_pt_1);
+ plane_isect_delta_len = len_v3(plane_isect_delta);
+
+ if (dot_v3v3(plane_isect_delta, cam_plane_no) > 0.0f) {
+ copy_v3_v3(r_co, plane_isect_pt_1);
+
+ /* offset shift */
+ normalize_v3(plane_isect_1_no);
+ madd_v3_v3fl(r_co, plane_isect_1_no, params->shifty * plane_isect_delta_len * shift_fac);
+ }
+ else {
+ copy_v3_v3(r_co, plane_isect_pt_2);
+
+ /* offset shift */
+ normalize_v3(plane_isect_2_no);
+ madd_v3_v3fl(r_co, plane_isect_2_no, params->shiftx * plane_isect_delta_len * shift_fac);
+ }
+
+ return true;
+ }
+ }
+
+ return false;
}
/* don't move the camera, just yield the fit location */
/* r_scale only valid/useful for ortho cameras */
bool BKE_camera_view_frame_fit_to_scene(
- Depsgraph *depsgraph, Scene *scene, Object *camera_ob, float r_co[3], float *r_scale)
+ Depsgraph *depsgraph, Scene *scene, Object *camera_ob, float r_co[3], float *r_scale)
{
- CameraParams params;
- CameraViewFrameData data_cb;
+ CameraParams params;
+ CameraViewFrameData data_cb;
- /* just in case */
- *r_scale = 1.0f;
+ /* just in case */
+ *r_scale = 1.0f;
- camera_frame_fit_data_init(scene, camera_ob, &params, &data_cb);
+ camera_frame_fit_data_init(scene, camera_ob, &params, &data_cb);
- /* run callback on all visible points */
- BKE_scene_foreach_display_point(depsgraph, camera_to_frame_view_cb, &data_cb);
+ /* run callback on all visible points */
+ BKE_scene_foreach_display_point(depsgraph, camera_to_frame_view_cb, &data_cb);
- return camera_frame_fit_calc_from_data(&params, &data_cb, r_co, r_scale);
+ return camera_frame_fit_calc_from_data(&params, &data_cb, r_co, r_scale);
}
-bool BKE_camera_view_frame_fit_to_coords(
- const Depsgraph *depsgraph, const float (*cos)[3], int num_cos, Object *camera_ob,
- float r_co[3], float *r_scale)
+bool BKE_camera_view_frame_fit_to_coords(const Depsgraph *depsgraph,
+ const float (*cos)[3],
+ int num_cos,
+ Object *camera_ob,
+ float r_co[3],
+ float *r_scale)
{
- Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
- Object *camera_ob_eval = DEG_get_evaluated_object(depsgraph, camera_ob);
- CameraParams params;
- CameraViewFrameData data_cb;
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ Object *camera_ob_eval = DEG_get_evaluated_object(depsgraph, camera_ob);
+ CameraParams params;
+ CameraViewFrameData data_cb;
- /* just in case */
- *r_scale = 1.0f;
+ /* just in case */
+ *r_scale = 1.0f;
- camera_frame_fit_data_init(scene_eval, camera_ob_eval, &params, &data_cb);
+ camera_frame_fit_data_init(scene_eval, camera_ob_eval, &params, &data_cb);
- /* run callback on all given coordinates */
- while (num_cos--) {
- camera_to_frame_view_cb(cos[num_cos], &data_cb);
- }
+ /* run callback on all given coordinates */
+ while (num_cos--) {
+ camera_to_frame_view_cb(cos[num_cos], &data_cb);
+ }
- return camera_frame_fit_calc_from_data(&params, &data_cb, r_co, r_scale);
+ return camera_frame_fit_calc_from_data(&params, &data_cb, r_co, r_scale);
}
/******************* multiview matrix functions ***********************/
static void camera_model_matrix(const Object *camera, float r_modelmat[4][4])
{
- copy_m4_m4(r_modelmat, camera->obmat);
+ copy_m4_m4(r_modelmat, camera->obmat);
}
-static void camera_stereo3d_model_matrix(const Object *camera, const bool is_left, float r_modelmat[4][4])
+static void camera_stereo3d_model_matrix(const Object *camera,
+ const bool is_left,
+ float r_modelmat[4][4])
{
- Camera *data = (Camera *)camera->data;
- float interocular_distance, convergence_distance;
- short convergence_mode, pivot;
- float sizemat[4][4];
-
- float fac = 1.0f;
- float fac_signed;
-
- interocular_distance = data->stereo.interocular_distance;
- convergence_distance = data->stereo.convergence_distance;
- convergence_mode = data->stereo.convergence_mode;
- pivot = data->stereo.pivot;
-
- if (((pivot == CAM_S3D_PIVOT_LEFT) && is_left) ||
- ((pivot == CAM_S3D_PIVOT_RIGHT) && !is_left))
- {
- camera_model_matrix(camera, r_modelmat);
- return;
- }
- else {
- float size[3];
- mat4_to_size(size, camera->obmat);
- size_to_mat4(sizemat, size);
- }
-
- if (pivot == CAM_S3D_PIVOT_CENTER)
- fac = 0.5f;
-
- fac_signed = is_left ? fac : -fac;
-
- /* rotation */
- if (convergence_mode == CAM_S3D_TOE) {
- float angle;
- float angle_sin, angle_cos;
- float toeinmat[4][4];
- float rotmat[4][4];
-
- unit_m4(rotmat);
-
- if (pivot == CAM_S3D_PIVOT_CENTER) {
- fac = -fac;
- fac_signed = -fac_signed;
- }
-
- angle = atanf((interocular_distance * 0.5f) / convergence_distance) / fac;
-
- angle_cos = cosf(angle * fac_signed);
- angle_sin = sinf(angle * fac_signed);
-
- rotmat[0][0] = angle_cos;
- rotmat[2][0] = -angle_sin;
- rotmat[0][2] = angle_sin;
- rotmat[2][2] = angle_cos;
-
- if (pivot == CAM_S3D_PIVOT_CENTER) {
- /* set the rotation */
- copy_m4_m4(toeinmat, rotmat);
- /* set the translation */
- toeinmat[3][0] = interocular_distance * fac_signed;
-
- /* transform */
- normalize_m4_m4(r_modelmat, camera->obmat);
- mul_m4_m4m4(r_modelmat, r_modelmat, toeinmat);
-
- /* scale back to the original size */
- mul_m4_m4m4(r_modelmat, r_modelmat, sizemat);
- }
- else { /* CAM_S3D_PIVOT_LEFT, CAM_S3D_PIVOT_RIGHT */
- /* rotate perpendicular to the interocular line */
- normalize_m4_m4(r_modelmat, camera->obmat);
- mul_m4_m4m4(r_modelmat, r_modelmat, rotmat);
-
- /* translate along the interocular line */
- unit_m4(toeinmat);
- toeinmat[3][0] = -interocular_distance * fac_signed;
- mul_m4_m4m4(r_modelmat, r_modelmat, toeinmat);
-
- /* rotate to toe-in angle */
- mul_m4_m4m4(r_modelmat, r_modelmat, rotmat);
-
- /* scale back to the original size */
- mul_m4_m4m4(r_modelmat, r_modelmat, sizemat);
- }
- }
- else {
- normalize_m4_m4(r_modelmat, camera->obmat);
-
- /* translate - no rotation in CAM_S3D_OFFAXIS, CAM_S3D_PARALLEL */
- translate_m4(r_modelmat, -interocular_distance * fac_signed, 0.0f, 0.0f);
-
- /* scale back to the original size */
- mul_m4_m4m4(r_modelmat, r_modelmat, sizemat);
- }
+ Camera *data = (Camera *)camera->data;
+ float interocular_distance, convergence_distance;
+ short convergence_mode, pivot;
+ float sizemat[4][4];
+
+ float fac = 1.0f;
+ float fac_signed;
+
+ interocular_distance = data->stereo.interocular_distance;
+ convergence_distance = data->stereo.convergence_distance;
+ convergence_mode = data->stereo.convergence_mode;
+ pivot = data->stereo.pivot;
+
+ if (((pivot == CAM_S3D_PIVOT_LEFT) && is_left) || ((pivot == CAM_S3D_PIVOT_RIGHT) && !is_left)) {
+ camera_model_matrix(camera, r_modelmat);
+ return;
+ }
+ else {
+ float size[3];
+ mat4_to_size(size, camera->obmat);
+ size_to_mat4(sizemat, size);
+ }
+
+ if (pivot == CAM_S3D_PIVOT_CENTER)
+ fac = 0.5f;
+
+ fac_signed = is_left ? fac : -fac;
+
+ /* rotation */
+ if (convergence_mode == CAM_S3D_TOE) {
+ float angle;
+ float angle_sin, angle_cos;
+ float toeinmat[4][4];
+ float rotmat[4][4];
+
+ unit_m4(rotmat);
+
+ if (pivot == CAM_S3D_PIVOT_CENTER) {
+ fac = -fac;
+ fac_signed = -fac_signed;
+ }
+
+ angle = atanf((interocular_distance * 0.5f) / convergence_distance) / fac;
+
+ angle_cos = cosf(angle * fac_signed);
+ angle_sin = sinf(angle * fac_signed);
+
+ rotmat[0][0] = angle_cos;
+ rotmat[2][0] = -angle_sin;
+ rotmat[0][2] = angle_sin;
+ rotmat[2][2] = angle_cos;
+
+ if (pivot == CAM_S3D_PIVOT_CENTER) {
+ /* set the rotation */
+ copy_m4_m4(toeinmat, rotmat);
+ /* set the translation */
+ toeinmat[3][0] = interocular_distance * fac_signed;
+
+ /* transform */
+ normalize_m4_m4(r_modelmat, camera->obmat);
+ mul_m4_m4m4(r_modelmat, r_modelmat, toeinmat);
+
+ /* scale back to the original size */
+ mul_m4_m4m4(r_modelmat, r_modelmat, sizemat);
+ }
+ else { /* CAM_S3D_PIVOT_LEFT, CAM_S3D_PIVOT_RIGHT */
+ /* rotate perpendicular to the interocular line */
+ normalize_m4_m4(r_modelmat, camera->obmat);
+ mul_m4_m4m4(r_modelmat, r_modelmat, rotmat);
+
+ /* translate along the interocular line */
+ unit_m4(toeinmat);
+ toeinmat[3][0] = -interocular_distance * fac_signed;
+ mul_m4_m4m4(r_modelmat, r_modelmat, toeinmat);
+
+ /* rotate to toe-in angle */
+ mul_m4_m4m4(r_modelmat, r_modelmat, rotmat);
+
+ /* scale back to the original size */
+ mul_m4_m4m4(r_modelmat, r_modelmat, sizemat);
+ }
+ }
+ else {
+ normalize_m4_m4(r_modelmat, camera->obmat);
+
+ /* translate - no rotation in CAM_S3D_OFFAXIS, CAM_S3D_PARALLEL */
+ translate_m4(r_modelmat, -interocular_distance * fac_signed, 0.0f, 0.0f);
+
+ /* scale back to the original size */
+ mul_m4_m4m4(r_modelmat, r_modelmat, sizemat);
+ }
}
/* the view matrix is used by the viewport drawing, it is basically the inverted model matrix */
-void BKE_camera_multiview_view_matrix(RenderData *rd, const Object *camera, const bool is_left, float r_viewmat[4][4])
+void BKE_camera_multiview_view_matrix(RenderData *rd,
+ const Object *camera,
+ const bool is_left,
+ float r_viewmat[4][4])
{
- BKE_camera_multiview_model_matrix(rd, camera, is_left ? STEREO_LEFT_NAME : STEREO_RIGHT_NAME, r_viewmat);
- invert_m4(r_viewmat);
+ BKE_camera_multiview_model_matrix(
+ rd, camera, is_left ? STEREO_LEFT_NAME : STEREO_RIGHT_NAME, r_viewmat);
+ invert_m4(r_viewmat);
}
/* left is the default */
static bool camera_is_left(const char *viewname)
{
- if (viewname && viewname[0] != '\0') {
- return !STREQ(viewname, STEREO_RIGHT_NAME);
- }
- return true;
+ if (viewname && viewname[0] != '\0') {
+ return !STREQ(viewname, STEREO_RIGHT_NAME);
+ }
+ return true;
}
-void BKE_camera_multiview_model_matrix(RenderData *rd, const Object *camera, const char *viewname, float r_modelmat[4][4])
+void BKE_camera_multiview_model_matrix(RenderData *rd,
+ const Object *camera,
+ const char *viewname,
+ float r_modelmat[4][4])
{
- BKE_camera_multiview_model_matrix_scaled(rd, camera, viewname, r_modelmat);
- normalize_m4(r_modelmat);
+ BKE_camera_multiview_model_matrix_scaled(rd, camera, viewname, r_modelmat);
+ normalize_m4(r_modelmat);
}
-void BKE_camera_multiview_model_matrix_scaled(RenderData *rd, const Object *camera, const char *viewname, float r_modelmat[4][4])
+void BKE_camera_multiview_model_matrix_scaled(RenderData *rd,
+ const Object *camera,
+ const char *viewname,
+ float r_modelmat[4][4])
{
- const bool is_multiview = (rd && rd->scemode & R_MULTIVIEW) != 0;
-
- if (!is_multiview) {
- camera_model_matrix(camera, r_modelmat);
- }
- else if (rd->views_format == SCE_VIEWS_FORMAT_MULTIVIEW) {
- camera_model_matrix(camera, r_modelmat);
- }
- else { /* SCE_VIEWS_SETUP_BASIC */
- const bool is_left = camera_is_left(viewname);
- camera_stereo3d_model_matrix(camera, is_left, r_modelmat);
- }
+ const bool is_multiview = (rd && rd->scemode & R_MULTIVIEW) != 0;
+
+ if (!is_multiview) {
+ camera_model_matrix(camera, r_modelmat);
+ }
+ else if (rd->views_format == SCE_VIEWS_FORMAT_MULTIVIEW) {
+ camera_model_matrix(camera, r_modelmat);
+ }
+ else { /* SCE_VIEWS_SETUP_BASIC */
+ const bool is_left = camera_is_left(viewname);
+ camera_stereo3d_model_matrix(camera, is_left, r_modelmat);
+ }
}
-void BKE_camera_multiview_window_matrix(RenderData *rd, const Object *camera, const char *viewname, float r_winmat[4][4])
+void BKE_camera_multiview_window_matrix(RenderData *rd,
+ const Object *camera,
+ const char *viewname,
+ float r_winmat[4][4])
{
- CameraParams params;
+ CameraParams params;
- /* Setup parameters */
- BKE_camera_params_init(&params);
- BKE_camera_params_from_object(&params, camera);
- BKE_camera_multiview_params(rd, &params, camera, viewname);
+ /* Setup parameters */
+ BKE_camera_params_init(&params);
+ BKE_camera_params_from_object(&params, camera);
+ BKE_camera_multiview_params(rd, &params, camera, viewname);
- /* Compute matrix, viewplane, .. */
- BKE_camera_params_compute_viewplane(&params, rd->xsch, rd->ysch, rd->xasp, rd->yasp);
- BKE_camera_params_compute_matrix(&params);
+ /* Compute matrix, viewplane, .. */
+ BKE_camera_params_compute_viewplane(&params, rd->xsch, rd->ysch, rd->xasp, rd->yasp);
+ BKE_camera_params_compute_matrix(&params);
- copy_m4_m4(r_winmat, params.winmat);
+ copy_m4_m4(r_winmat, params.winmat);
}
bool BKE_camera_multiview_spherical_stereo(RenderData *rd, const Object *camera)
{
- Camera *cam;
- const bool is_multiview = (rd && rd->scemode & R_MULTIVIEW) != 0;
+ Camera *cam;
+ const bool is_multiview = (rd && rd->scemode & R_MULTIVIEW) != 0;
- if (!is_multiview)
- return false;
+ if (!is_multiview)
+ return false;
- if (camera->type != OB_CAMERA)
- return false;
- else
- cam = camera->data;
+ if (camera->type != OB_CAMERA)
+ return false;
+ else
+ cam = camera->data;
- if ((rd->views_format == SCE_VIEWS_FORMAT_STEREO_3D) &&
- ELEM(cam->type, CAM_PANO, CAM_PERSP) &&
- ((cam->stereo.flag & CAM_S3D_SPHERICAL) != 0))
- {
- return true;
- }
+ if ((rd->views_format == SCE_VIEWS_FORMAT_STEREO_3D) && ELEM(cam->type, CAM_PANO, CAM_PERSP) &&
+ ((cam->stereo.flag & CAM_S3D_SPHERICAL) != 0)) {
+ return true;
+ }
- return false;
+ return false;
}
static Object *camera_multiview_advanced(Scene *scene, Object *camera, const char *suffix)
{
- SceneRenderView *srv;
- char name[MAX_NAME];
- const char *camera_name = camera->id.name + 2;
- const int len_name = strlen(camera_name);
- int len_suffix_max = -1;
-
- name[0] = '\0';
-
- /* we need to take the better match, thus the len_suffix_max test */
- for (srv = scene->r.views.first; srv; srv = srv->next) {
- const int len_suffix = strlen(srv->suffix);
-
- if ((len_suffix < len_suffix_max) || (len_name < len_suffix))
- continue;
-
- if (STREQ(camera_name + (len_name - len_suffix), srv->suffix)) {
- BLI_snprintf(name, sizeof(name), "%.*s%s", (len_name - len_suffix), camera_name, suffix);
- len_suffix_max = len_suffix;
- }
- }
-
- if (name[0] != '\0') {
- Object *ob = BKE_scene_object_find_by_name(scene, name);
- if (ob != NULL) {
- return ob;
- }
- }
-
- return camera;
+ SceneRenderView *srv;
+ char name[MAX_NAME];
+ const char *camera_name = camera->id.name + 2;
+ const int len_name = strlen(camera_name);
+ int len_suffix_max = -1;
+
+ name[0] = '\0';
+
+ /* we need to take the better match, thus the len_suffix_max test */
+ for (srv = scene->r.views.first; srv; srv = srv->next) {
+ const int len_suffix = strlen(srv->suffix);
+
+ if ((len_suffix < len_suffix_max) || (len_name < len_suffix))
+ continue;
+
+ if (STREQ(camera_name + (len_name - len_suffix), srv->suffix)) {
+ BLI_snprintf(name, sizeof(name), "%.*s%s", (len_name - len_suffix), camera_name, suffix);
+ len_suffix_max = len_suffix;
+ }
+ }
+
+ if (name[0] != '\0') {
+ Object *ob = BKE_scene_object_find_by_name(scene, name);
+ if (ob != NULL) {
+ return ob;
+ }
+ }
+
+ return camera;
}
/* returns the camera to be used for render */
Object *BKE_camera_multiview_render(Scene *scene, Object *camera, const char *viewname)
{
- const bool is_multiview = (camera != NULL) && (scene->r.scemode & R_MULTIVIEW) != 0;
-
- if (!is_multiview) {
- return camera;
- }
- else if (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) {
- return camera;
- }
- else { /* SCE_VIEWS_FORMAT_MULTIVIEW */
- const char *suffix = BKE_scene_multiview_view_suffix_get(&scene->r, viewname);
- return camera_multiview_advanced(scene, camera, suffix);
- }
+ const bool is_multiview = (camera != NULL) && (scene->r.scemode & R_MULTIVIEW) != 0;
+
+ if (!is_multiview) {
+ return camera;
+ }
+ else if (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) {
+ return camera;
+ }
+ else { /* SCE_VIEWS_FORMAT_MULTIVIEW */
+ const char *suffix = BKE_scene_multiview_view_suffix_get(&scene->r, viewname);
+ return camera_multiview_advanced(scene, camera, suffix);
+ }
}
static float camera_stereo3d_shift_x(const Object *camera, const char *viewname)
{
- Camera *data = camera->data;
- float shift = data->shiftx;
- float interocular_distance, convergence_distance;
- short convergence_mode, pivot;
- bool is_left = true;
+ Camera *data = camera->data;
+ float shift = data->shiftx;
+ float interocular_distance, convergence_distance;
+ short convergence_mode, pivot;
+ bool is_left = true;
- float fac = 1.0f;
- float fac_signed;
+ float fac = 1.0f;
+ float fac_signed;
- if (viewname && viewname[0]) {
- is_left = STREQ(viewname, STEREO_LEFT_NAME);
- }
+ if (viewname && viewname[0]) {
+ is_left = STREQ(viewname, STEREO_LEFT_NAME);
+ }
- interocular_distance = data->stereo.interocular_distance;
- convergence_distance = data->stereo.convergence_distance;
- convergence_mode = data->stereo.convergence_mode;
- pivot = data->stereo.pivot;
+ interocular_distance = data->stereo.interocular_distance;
+ convergence_distance = data->stereo.convergence_distance;
+ convergence_mode = data->stereo.convergence_mode;
+ pivot = data->stereo.pivot;
- if (convergence_mode != CAM_S3D_OFFAXIS)
- return shift;
+ if (convergence_mode != CAM_S3D_OFFAXIS)
+ return shift;
- if (((pivot == CAM_S3D_PIVOT_LEFT) && is_left) ||
- ((pivot == CAM_S3D_PIVOT_RIGHT) && !is_left))
- {
- return shift;
- }
+ if (((pivot == CAM_S3D_PIVOT_LEFT) && is_left) || ((pivot == CAM_S3D_PIVOT_RIGHT) && !is_left)) {
+ return shift;
+ }
- if (pivot == CAM_S3D_PIVOT_CENTER)
- fac = 0.5f;
+ if (pivot == CAM_S3D_PIVOT_CENTER)
+ fac = 0.5f;
- fac_signed = is_left ? fac : -fac;
- shift += ((interocular_distance / data->sensor_x) * (data->lens / convergence_distance)) * fac_signed;
+ fac_signed = is_left ? fac : -fac;
+ shift += ((interocular_distance / data->sensor_x) * (data->lens / convergence_distance)) *
+ fac_signed;
- return shift;
+ return shift;
}
float BKE_camera_multiview_shift_x(RenderData *rd, const Object *camera, const char *viewname)
{
- const bool is_multiview = (rd && rd->scemode & R_MULTIVIEW) != 0;
- Camera *data = camera->data;
-
- BLI_assert(camera->type == OB_CAMERA);
-
- if (!is_multiview) {
- return data->shiftx;
- }
- else if (rd->views_format == SCE_VIEWS_FORMAT_MULTIVIEW) {
- return data->shiftx;
- }
- else { /* SCE_VIEWS_SETUP_BASIC */
- return camera_stereo3d_shift_x(camera, viewname);
- }
+ const bool is_multiview = (rd && rd->scemode & R_MULTIVIEW) != 0;
+ Camera *data = camera->data;
+
+ BLI_assert(camera->type == OB_CAMERA);
+
+ if (!is_multiview) {
+ return data->shiftx;
+ }
+ else if (rd->views_format == SCE_VIEWS_FORMAT_MULTIVIEW) {
+ return data->shiftx;
+ }
+ else { /* SCE_VIEWS_SETUP_BASIC */
+ return camera_stereo3d_shift_x(camera, viewname);
+ }
}
-void BKE_camera_multiview_params(RenderData *rd, CameraParams *params, const Object *camera, const char *viewname)
+void BKE_camera_multiview_params(RenderData *rd,
+ CameraParams *params,
+ const Object *camera,
+ const char *viewname)
{
- if (camera->type == OB_CAMERA) {
- params->shiftx = BKE_camera_multiview_shift_x(rd, camera, viewname);
- }
+ if (camera->type == OB_CAMERA) {
+ params->shiftx = BKE_camera_multiview_shift_x(rd, camera, viewname);
+ }
}
void BKE_camera_to_gpu_dof(struct Object *camera, struct GPUFXSettings *r_fx_settings)
{
- if (camera->type == OB_CAMERA) {
- Camera *cam = camera->data;
- r_fx_settings->dof = &cam->gpu_dof;
- r_fx_settings->dof->focal_length = cam->lens;
- r_fx_settings->dof->sensor = BKE_camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y);
- r_fx_settings->dof->focus_distance = BKE_camera_object_dof_distance(camera);
- }
+ if (camera->type == OB_CAMERA) {
+ Camera *cam = camera->data;
+ r_fx_settings->dof = &cam->gpu_dof;
+ r_fx_settings->dof->focal_length = cam->lens;
+ r_fx_settings->dof->sensor = BKE_camera_sensor_size(
+ cam->sensor_fit, cam->sensor_x, cam->sensor_y);
+ r_fx_settings->dof->focus_distance = BKE_camera_object_dof_distance(camera);
+ }
}
CameraBGImage *BKE_camera_background_image_new(Camera *cam)
{
- CameraBGImage *bgpic = MEM_callocN(sizeof(CameraBGImage), "Background Image");
+ CameraBGImage *bgpic = MEM_callocN(sizeof(CameraBGImage), "Background Image");
- bgpic->scale = 1.0f;
- bgpic->alpha = 0.5f;
- bgpic->iuser.ok = 1;
- bgpic->iuser.flag |= IMA_ANIM_ALWAYS;
- bgpic->flag |= CAM_BGIMG_FLAG_EXPANDED;
+ bgpic->scale = 1.0f;
+ bgpic->alpha = 0.5f;
+ bgpic->iuser.ok = 1;
+ bgpic->iuser.flag |= IMA_ANIM_ALWAYS;
+ bgpic->flag |= CAM_BGIMG_FLAG_EXPANDED;
- BLI_addtail(&cam->bg_images, bgpic);
+ BLI_addtail(&cam->bg_images, bgpic);
- return bgpic;
+ return bgpic;
}
void BKE_camera_background_image_remove(Camera *cam, CameraBGImage *bgpic)
{
- BLI_remlink(&cam->bg_images, bgpic);
+ BLI_remlink(&cam->bg_images, bgpic);
- MEM_freeN(bgpic);
+ MEM_freeN(bgpic);
}
void BKE_camera_background_image_clear(Camera *cam)
{
- CameraBGImage *bgpic = cam->bg_images.first;
+ CameraBGImage *bgpic = cam->bg_images.first;
- while (bgpic) {
- CameraBGImage *next_bgpic = bgpic->next;
+ while (bgpic) {
+ CameraBGImage *next_bgpic = bgpic->next;
- BKE_camera_background_image_remove(cam, bgpic);
+ BKE_camera_background_image_remove(cam, bgpic);
- bgpic = next_bgpic;
- }
+ bgpic = next_bgpic;
+ }
}
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index 9634cbccd91..ada746d3fcc 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -50,1120 +50,1151 @@
#include <math.h>
typedef struct {
- DerivedMesh dm;
-
- /* these point to data in the DerivedMesh custom data layers,
- * they are only here for efficiency and convenience */
- MVert *mvert;
- MEdge *medge;
- MFace *mface;
- MLoop *mloop;
- MPoly *mpoly;
-
- /* Cached */
- struct PBVH *pbvh;
- bool pbvh_draw;
-
- /* Mesh connectivity */
- MeshElemMap *pmap;
- int *pmap_mem;
+ DerivedMesh dm;
+
+ /* these point to data in the DerivedMesh custom data layers,
+ * they are only here for efficiency and convenience */
+ MVert *mvert;
+ MEdge *medge;
+ MFace *mface;
+ MLoop *mloop;
+ MPoly *mpoly;
+
+ /* Cached */
+ struct PBVH *pbvh;
+ bool pbvh_draw;
+
+ /* Mesh connectivity */
+ MeshElemMap *pmap;
+ int *pmap_mem;
} CDDerivedMesh;
/**************** DerivedMesh interface functions ****************/
static int cdDM_getNumVerts(DerivedMesh *dm)
{
- return dm->numVertData;
+ return dm->numVertData;
}
static int cdDM_getNumEdges(DerivedMesh *dm)
{
- return dm->numEdgeData;
+ return dm->numEdgeData;
}
static int cdDM_getNumTessFaces(DerivedMesh *dm)
{
- /* uncomment and add a breakpoint on the printf()
- * to help debug tessfaces issues since BMESH merge. */
+ /* uncomment and add a breakpoint on the printf()
+ * to help debug tessfaces issues since BMESH merge. */
#if 0
- if (dm->numTessFaceData == 0 && dm->numPolyData != 0) {
- printf("%s: has no faces!\n");
- }
+ if (dm->numTessFaceData == 0 && dm->numPolyData != 0) {
+ printf("%s: has no faces!\n");
+ }
#endif
- return dm->numTessFaceData;
+ return dm->numTessFaceData;
}
static int cdDM_getNumLoops(DerivedMesh *dm)
{
- return dm->numLoopData;
+ return dm->numLoopData;
}
static int cdDM_getNumPolys(DerivedMesh *dm)
{
- return dm->numPolyData;
+ return dm->numPolyData;
}
static void cdDM_getVert(DerivedMesh *dm, int index, MVert *r_vert)
{
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- *r_vert = cddm->mvert[index];
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+ *r_vert = cddm->mvert[index];
}
static void cdDM_getEdge(DerivedMesh *dm, int index, MEdge *r_edge)
{
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- *r_edge = cddm->medge[index];
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+ *r_edge = cddm->medge[index];
}
static void cdDM_getTessFace(DerivedMesh *dm, int index, MFace *r_face)
{
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- *r_face = cddm->mface[index];
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+ *r_face = cddm->mface[index];
}
static void cdDM_copyVertArray(DerivedMesh *dm, MVert *r_vert)
{
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- memcpy(r_vert, cddm->mvert, sizeof(*r_vert) * dm->numVertData);
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+ memcpy(r_vert, cddm->mvert, sizeof(*r_vert) * dm->numVertData);
}
static void cdDM_copyEdgeArray(DerivedMesh *dm, MEdge *r_edge)
{
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- memcpy(r_edge, cddm->medge, sizeof(*r_edge) * dm->numEdgeData);
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+ memcpy(r_edge, cddm->medge, sizeof(*r_edge) * dm->numEdgeData);
}
static void cdDM_copyTessFaceArray(DerivedMesh *dm, MFace *r_face)
{
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- memcpy(r_face, cddm->mface, sizeof(*r_face) * dm->numTessFaceData);
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+ memcpy(r_face, cddm->mface, sizeof(*r_face) * dm->numTessFaceData);
}
static void cdDM_copyLoopArray(DerivedMesh *dm, MLoop *r_loop)
{
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- memcpy(r_loop, cddm->mloop, sizeof(*r_loop) * dm->numLoopData);
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+ memcpy(r_loop, cddm->mloop, sizeof(*r_loop) * dm->numLoopData);
}
static void cdDM_copyPolyArray(DerivedMesh *dm, MPoly *r_poly)
{
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- memcpy(r_poly, cddm->mpoly, sizeof(*r_poly) * dm->numPolyData);
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+ memcpy(r_poly, cddm->mpoly, sizeof(*r_poly) * dm->numPolyData);
}
static void cdDM_getMinMax(DerivedMesh *dm, float r_min[3], float r_max[3])
{
- CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
- int i;
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+ int i;
- if (dm->numVertData) {
- for (i = 0; i < dm->numVertData; i++) {
- minmax_v3v3_v3(r_min, r_max, cddm->mvert[i].co);
- }
- }
- else {
- zero_v3(r_min);
- zero_v3(r_max);
- }
+ if (dm->numVertData) {
+ for (i = 0; i < dm->numVertData; i++) {
+ minmax_v3v3_v3(r_min, r_max, cddm->mvert[i].co);
+ }
+ }
+ else {
+ zero_v3(r_min);
+ zero_v3(r_max);
+ }
}
static void cdDM_getVertCo(DerivedMesh *dm, int index, float r_co[3])
{
- CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- copy_v3_v3(r_co, cddm->mvert[index].co);
+ copy_v3_v3(r_co, cddm->mvert[index].co);
}
static void cdDM_getVertCos(DerivedMesh *dm, float (*r_cos)[3])
{
- MVert *mv = CDDM_get_verts(dm);
- int i;
+ MVert *mv = CDDM_get_verts(dm);
+ int i;
- for (i = 0; i < dm->numVertData; i++, mv++)
- copy_v3_v3(r_cos[i], mv->co);
+ for (i = 0; i < dm->numVertData; i++, mv++)
+ copy_v3_v3(r_cos[i], mv->co);
}
static void cdDM_getVertNo(DerivedMesh *dm, int index, float r_no[3])
{
- CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
- normal_short_to_float_v3(r_no, cddm->mvert[index].no);
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+ normal_short_to_float_v3(r_no, cddm->mvert[index].no);
}
static const MeshElemMap *cdDM_getPolyMap(Object *ob, DerivedMesh *dm)
{
- CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- if (!cddm->pmap && ob->type == OB_MESH) {
- Mesh *me = ob->data;
+ if (!cddm->pmap && ob->type == OB_MESH) {
+ Mesh *me = ob->data;
- BKE_mesh_vert_poly_map_create(
- &cddm->pmap, &cddm->pmap_mem,
- me->mpoly, me->mloop,
- me->totvert, me->totpoly, me->totloop);
- }
+ BKE_mesh_vert_poly_map_create(
+ &cddm->pmap, &cddm->pmap_mem, me->mpoly, me->mloop, me->totvert, me->totpoly, me->totloop);
+ }
- return cddm->pmap;
+ return cddm->pmap;
}
static bool check_sculpt_object_deformed(Object *object, bool for_construction)
{
- bool deformed = false;
+ bool deformed = false;
- /* Active modifiers means extra deformation, which can't be handled correct
- * on birth of PBVH and sculpt "layer" levels, so use PBVH only for internal brush
- * stuff and show final DerivedMesh so user would see actual object shape.
- */
- deformed |= object->sculpt->modifiers_active;
+ /* Active modifiers means extra deformation, which can't be handled correct
+ * on birth of PBVH and sculpt "layer" levels, so use PBVH only for internal brush
+ * stuff and show final DerivedMesh so user would see actual object shape.
+ */
+ deformed |= object->sculpt->modifiers_active;
- if (for_construction) {
- deformed |= object->sculpt->kb != NULL;
- }
- else {
- /* As in case with modifiers, we can't synchronize deformation made against
- * PBVH and non-locked keyblock, so also use PBVH only for brushes and
- * final DM to give final result to user.
- */
- deformed |= object->sculpt->kb && (object->shapeflag & OB_SHAPE_LOCK) == 0;
- }
+ if (for_construction) {
+ deformed |= object->sculpt->kb != NULL;
+ }
+ else {
+ /* As in case with modifiers, we can't synchronize deformation made against
+ * PBVH and non-locked keyblock, so also use PBVH only for brushes and
+ * final DM to give final result to user.
+ */
+ deformed |= object->sculpt->kb && (object->shapeflag & OB_SHAPE_LOCK) == 0;
+ }
- return deformed;
+ return deformed;
}
static bool can_pbvh_draw(Object *ob, DerivedMesh *dm)
{
- CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
- Mesh *me = ob->data;
- bool deformed = check_sculpt_object_deformed(ob, false);
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+ Mesh *me = ob->data;
+ bool deformed = check_sculpt_object_deformed(ob, false);
- if (deformed) {
- return false;
- }
+ if (deformed) {
+ return false;
+ }
- return cddm->mvert == me->mvert || ob->sculpt->kb;
+ return cddm->mvert == me->mvert || ob->sculpt->kb;
}
static PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm)
{
- CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
-
- if (!ob) {
- cddm->pbvh = NULL;
- return NULL;
- }
-
- if (!ob->sculpt)
- return NULL;
-
- if (ob->sculpt->pbvh) {
- cddm->pbvh = ob->sculpt->pbvh;
- cddm->pbvh_draw = can_pbvh_draw(ob, dm);
- }
-
- /* Sculpting on a BMesh (dynamic-topology) gets a special PBVH */
- if (!cddm->pbvh && ob->sculpt->bm) {
- cddm->pbvh = BKE_pbvh_new();
- cddm->pbvh_draw = true;
-
- BKE_pbvh_build_bmesh(cddm->pbvh, ob->sculpt->bm,
- ob->sculpt->bm_smooth_shading,
- ob->sculpt->bm_log, ob->sculpt->cd_vert_node_offset,
- ob->sculpt->cd_face_node_offset);
-
- pbvh_show_diffuse_color_set(cddm->pbvh, ob->sculpt->show_diffuse_color);
- pbvh_show_mask_set(cddm->pbvh, ob->sculpt->show_mask);
- }
-
-
- /* always build pbvh from original mesh, and only use it for drawing if
- * this derivedmesh is just original mesh. it's the multires subsurf dm
- * that this is actually for, to support a pbvh on a modified mesh */
- if (!cddm->pbvh && ob->type == OB_MESH) {
- Mesh *me = BKE_object_get_original_mesh(ob);
- const int looptris_num = poly_to_tri_count(me->totpoly, me->totloop);
- MLoopTri *looptri;
- bool deformed;
-
- cddm->pbvh = BKE_pbvh_new();
- cddm->pbvh_draw = can_pbvh_draw(ob, dm);
-
- looptri = MEM_malloc_arrayN(looptris_num, sizeof(*looptri), __func__);
-
- BKE_mesh_recalc_looptri(
- me->mloop, me->mpoly,
- me->mvert,
- me->totloop, me->totpoly,
- looptri);
-
- BKE_pbvh_build_mesh(
- cddm->pbvh,
- me->mpoly, me->mloop,
- me->mvert, me->totvert, &me->vdata,
- looptri, looptris_num);
-
- pbvh_show_diffuse_color_set(cddm->pbvh, ob->sculpt->show_diffuse_color);
- pbvh_show_mask_set(cddm->pbvh, ob->sculpt->show_mask);
-
- deformed = check_sculpt_object_deformed(ob, true);
-
- if (deformed && ob->derivedDeform) {
- DerivedMesh *deformdm = ob->derivedDeform;
- float (*vertCos)[3];
- int totvert;
-
- totvert = deformdm->getNumVerts(deformdm);
- vertCos = MEM_malloc_arrayN(totvert, sizeof(float[3]), "cdDM_getPBVH vertCos");
- deformdm->getVertCos(deformdm, vertCos);
- BKE_pbvh_apply_vertCos(cddm->pbvh, vertCos, totvert);
- MEM_freeN(vertCos);
- }
- }
-
- return cddm->pbvh;
-}
-
-static void cdDM_foreachMappedVert(
- DerivedMesh *dm,
- void (*func)(void *userData, int index, const float co[3], const float no_f[3], const short no_s[3]),
- void *userData,
- DMForeachFlag flag)
-{
- MVert *mv = CDDM_get_verts(dm);
- const int *index = DM_get_vert_data_layer(dm, CD_ORIGINDEX);
- int i;
-
- if (index) {
- for (i = 0; i < dm->numVertData; i++, mv++) {
- const short *no = (flag & DM_FOREACH_USE_NORMAL) ? mv->no : NULL;
- const int orig = *index++;
- if (orig == ORIGINDEX_NONE) continue;
- func(userData, orig, mv->co, NULL, no);
- }
- }
- else {
- for (i = 0; i < dm->numVertData; i++, mv++) {
- const short *no = (flag & DM_FOREACH_USE_NORMAL) ? mv->no : NULL;
- func(userData, i, mv->co, NULL, no);
- }
- }
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+
+ if (!ob) {
+ cddm->pbvh = NULL;
+ return NULL;
+ }
+
+ if (!ob->sculpt)
+ return NULL;
+
+ if (ob->sculpt->pbvh) {
+ cddm->pbvh = ob->sculpt->pbvh;
+ cddm->pbvh_draw = can_pbvh_draw(ob, dm);
+ }
+
+ /* Sculpting on a BMesh (dynamic-topology) gets a special PBVH */
+ if (!cddm->pbvh && ob->sculpt->bm) {
+ cddm->pbvh = BKE_pbvh_new();
+ cddm->pbvh_draw = true;
+
+ BKE_pbvh_build_bmesh(cddm->pbvh,
+ ob->sculpt->bm,
+ ob->sculpt->bm_smooth_shading,
+ ob->sculpt->bm_log,
+ ob->sculpt->cd_vert_node_offset,
+ ob->sculpt->cd_face_node_offset);
+
+ pbvh_show_diffuse_color_set(cddm->pbvh, ob->sculpt->show_diffuse_color);
+ pbvh_show_mask_set(cddm->pbvh, ob->sculpt->show_mask);
+ }
+
+ /* always build pbvh from original mesh, and only use it for drawing if
+ * this derivedmesh is just original mesh. it's the multires subsurf dm
+ * that this is actually for, to support a pbvh on a modified mesh */
+ if (!cddm->pbvh && ob->type == OB_MESH) {
+ Mesh *me = BKE_object_get_original_mesh(ob);
+ const int looptris_num = poly_to_tri_count(me->totpoly, me->totloop);
+ MLoopTri *looptri;
+ bool deformed;
+
+ cddm->pbvh = BKE_pbvh_new();
+ cddm->pbvh_draw = can_pbvh_draw(ob, dm);
+
+ looptri = MEM_malloc_arrayN(looptris_num, sizeof(*looptri), __func__);
+
+ BKE_mesh_recalc_looptri(me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, looptri);
+
+ BKE_pbvh_build_mesh(cddm->pbvh,
+ me->mpoly,
+ me->mloop,
+ me->mvert,
+ me->totvert,
+ &me->vdata,
+ looptri,
+ looptris_num);
+
+ pbvh_show_diffuse_color_set(cddm->pbvh, ob->sculpt->show_diffuse_color);
+ pbvh_show_mask_set(cddm->pbvh, ob->sculpt->show_mask);
+
+ deformed = check_sculpt_object_deformed(ob, true);
+
+ if (deformed && ob->derivedDeform) {
+ DerivedMesh *deformdm = ob->derivedDeform;
+ float(*vertCos)[3];
+ int totvert;
+
+ totvert = deformdm->getNumVerts(deformdm);
+ vertCos = MEM_malloc_arrayN(totvert, sizeof(float[3]), "cdDM_getPBVH vertCos");
+ deformdm->getVertCos(deformdm, vertCos);
+ BKE_pbvh_apply_vertCos(cddm->pbvh, vertCos, totvert);
+ MEM_freeN(vertCos);
+ }
+ }
+
+ return cddm->pbvh;
+}
+
+static void cdDM_foreachMappedVert(DerivedMesh *dm,
+ void (*func)(void *userData,
+ int index,
+ const float co[3],
+ const float no_f[3],
+ const short no_s[3]),
+ void *userData,
+ DMForeachFlag flag)
+{
+ MVert *mv = CDDM_get_verts(dm);
+ const int *index = DM_get_vert_data_layer(dm, CD_ORIGINDEX);
+ int i;
+
+ if (index) {
+ for (i = 0; i < dm->numVertData; i++, mv++) {
+ const short *no = (flag & DM_FOREACH_USE_NORMAL) ? mv->no : NULL;
+ const int orig = *index++;
+ if (orig == ORIGINDEX_NONE)
+ continue;
+ func(userData, orig, mv->co, NULL, no);
+ }
+ }
+ else {
+ for (i = 0; i < dm->numVertData; i++, mv++) {
+ const short *no = (flag & DM_FOREACH_USE_NORMAL) ? mv->no : NULL;
+ func(userData, i, mv->co, NULL, no);
+ }
+ }
}
static void cdDM_foreachMappedEdge(
- DerivedMesh *dm,
- void (*func)(void *userData, int index, const float v0co[3], const float v1co[3]),
- void *userData)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
- MVert *mv = cddm->mvert;
- MEdge *med = cddm->medge;
- int i, orig, *index = DM_get_edge_data_layer(dm, CD_ORIGINDEX);
-
- for (i = 0; i < dm->numEdgeData; i++, med++) {
- if (index) {
- orig = *index++;
- if (orig == ORIGINDEX_NONE) continue;
- func(userData, orig, mv[med->v1].co, mv[med->v2].co);
- }
- else
- func(userData, i, mv[med->v1].co, mv[med->v2].co);
- }
-}
-
-static void cdDM_foreachMappedLoop(
- DerivedMesh *dm,
- void (*func)(void *userData, int vertex_index, int face_index, const float co[3], const float no[3]),
- void *userData,
- DMForeachFlag flag)
-{
- /* We can't use dm->getLoopDataLayout(dm) here, we want to always access dm->loopData, EditDerivedBMesh would
- * return loop data from bmesh itself. */
- const float (*lnors)[3] = (flag & DM_FOREACH_USE_NORMAL) ? DM_get_loop_data_layer(dm, CD_NORMAL) : NULL;
-
- const MVert *mv = CDDM_get_verts(dm);
- const MLoop *ml = CDDM_get_loops(dm);
- const MPoly *mp = CDDM_get_polys(dm);
- const int *v_index = DM_get_vert_data_layer(dm, CD_ORIGINDEX);
- const int *f_index = DM_get_poly_data_layer(dm, CD_ORIGINDEX);
- int p_idx, i;
-
- for (p_idx = 0; p_idx < dm->numPolyData; ++p_idx, ++mp) {
- for (i = 0; i < mp->totloop; ++i, ++ml) {
- const int v_idx = v_index ? v_index[ml->v] : ml->v;
- const int f_idx = f_index ? f_index[p_idx] : p_idx;
- const float *no = lnors ? *lnors++ : NULL;
- if (!ELEM(ORIGINDEX_NONE, v_idx, f_idx)) {
- func(userData, v_idx, f_idx, mv[ml->v].co, no);
- }
- }
- }
+ DerivedMesh *dm,
+ void (*func)(void *userData, int index, const float v0co[3], const float v1co[3]),
+ void *userData)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+ MVert *mv = cddm->mvert;
+ MEdge *med = cddm->medge;
+ int i, orig, *index = DM_get_edge_data_layer(dm, CD_ORIGINDEX);
+
+ for (i = 0; i < dm->numEdgeData; i++, med++) {
+ if (index) {
+ orig = *index++;
+ if (orig == ORIGINDEX_NONE)
+ continue;
+ func(userData, orig, mv[med->v1].co, mv[med->v2].co);
+ }
+ else
+ func(userData, i, mv[med->v1].co, mv[med->v2].co);
+ }
+}
+
+static void cdDM_foreachMappedLoop(DerivedMesh *dm,
+ void (*func)(void *userData,
+ int vertex_index,
+ int face_index,
+ const float co[3],
+ const float no[3]),
+ void *userData,
+ DMForeachFlag flag)
+{
+ /* We can't use dm->getLoopDataLayout(dm) here, we want to always access dm->loopData, EditDerivedBMesh would
+ * return loop data from bmesh itself. */
+ const float(*lnors)[3] = (flag & DM_FOREACH_USE_NORMAL) ? DM_get_loop_data_layer(dm, CD_NORMAL) :
+ NULL;
+
+ const MVert *mv = CDDM_get_verts(dm);
+ const MLoop *ml = CDDM_get_loops(dm);
+ const MPoly *mp = CDDM_get_polys(dm);
+ const int *v_index = DM_get_vert_data_layer(dm, CD_ORIGINDEX);
+ const int *f_index = DM_get_poly_data_layer(dm, CD_ORIGINDEX);
+ int p_idx, i;
+
+ for (p_idx = 0; p_idx < dm->numPolyData; ++p_idx, ++mp) {
+ for (i = 0; i < mp->totloop; ++i, ++ml) {
+ const int v_idx = v_index ? v_index[ml->v] : ml->v;
+ const int f_idx = f_index ? f_index[p_idx] : p_idx;
+ const float *no = lnors ? *lnors++ : NULL;
+ if (!ELEM(ORIGINDEX_NONE, v_idx, f_idx)) {
+ func(userData, v_idx, f_idx, mv[ml->v].co, no);
+ }
+ }
+ }
}
static void cdDM_foreachMappedFaceCenter(
- DerivedMesh *dm,
- void (*func)(void *userData, int index, const float cent[3], const float no[3]),
- void *userData,
- DMForeachFlag flag)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- MVert *mvert = cddm->mvert;
- MPoly *mp;
- MLoop *ml;
- int i, orig, *index;
-
- index = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX);
- mp = cddm->mpoly;
- for (i = 0; i < dm->numPolyData; i++, mp++) {
- float cent[3];
- float *no, _no[3];
-
- if (index) {
- orig = *index++;
- if (orig == ORIGINDEX_NONE) continue;
- }
- else {
- orig = i;
- }
-
- ml = &cddm->mloop[mp->loopstart];
- BKE_mesh_calc_poly_center(mp, ml, mvert, cent);
-
- if (flag & DM_FOREACH_USE_NORMAL) {
- BKE_mesh_calc_poly_normal(mp, ml, mvert, (no = _no));
- }
- else {
- no = NULL;
- }
-
- func(userData, orig, cent, no);
- }
-
+ DerivedMesh *dm,
+ void (*func)(void *userData, int index, const float cent[3], const float no[3]),
+ void *userData,
+ DMForeachFlag flag)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+ MVert *mvert = cddm->mvert;
+ MPoly *mp;
+ MLoop *ml;
+ int i, orig, *index;
+
+ index = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX);
+ mp = cddm->mpoly;
+ for (i = 0; i < dm->numPolyData; i++, mp++) {
+ float cent[3];
+ float *no, _no[3];
+
+ if (index) {
+ orig = *index++;
+ if (orig == ORIGINDEX_NONE)
+ continue;
+ }
+ else {
+ orig = i;
+ }
+
+ ml = &cddm->mloop[mp->loopstart];
+ BKE_mesh_calc_poly_center(mp, ml, mvert, cent);
+
+ if (flag & DM_FOREACH_USE_NORMAL) {
+ BKE_mesh_calc_poly_normal(mp, ml, mvert, (no = _no));
+ }
+ else {
+ no = NULL;
+ }
+
+ func(userData, orig, cent, no);
+ }
}
void CDDM_recalc_tessellation_ex(DerivedMesh *dm, const bool do_face_nor_cpy)
{
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- dm->numTessFaceData = BKE_mesh_recalc_tessellation(
- &dm->faceData, &dm->loopData, &dm->polyData,
- cddm->mvert,
- dm->numTessFaceData, dm->numLoopData, dm->numPolyData,
- do_face_nor_cpy);
+ dm->numTessFaceData = BKE_mesh_recalc_tessellation(&dm->faceData,
+ &dm->loopData,
+ &dm->polyData,
+ cddm->mvert,
+ dm->numTessFaceData,
+ dm->numLoopData,
+ dm->numPolyData,
+ do_face_nor_cpy);
- cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
+ cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
- /* Tessellation recreated faceData, and the active layer indices need to get re-propagated
- * from loops and polys to faces */
- CustomData_bmesh_update_active_layers(&dm->faceData, &dm->loopData);
+ /* Tessellation recreated faceData, and the active layer indices need to get re-propagated
+ * from loops and polys to faces */
+ CustomData_bmesh_update_active_layers(&dm->faceData, &dm->loopData);
}
void CDDM_recalc_tessellation(DerivedMesh *dm)
{
- CDDM_recalc_tessellation_ex(dm, true);
+ CDDM_recalc_tessellation_ex(dm, true);
}
void CDDM_recalc_looptri(DerivedMesh *dm)
{
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- const unsigned int totpoly = dm->numPolyData;
- const unsigned int totloop = dm->numLoopData;
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+ const unsigned int totpoly = dm->numPolyData;
+ const unsigned int totloop = dm->numLoopData;
- DM_ensure_looptri_data(dm);
- BLI_assert(totpoly == 0 || cddm->dm.looptris.array_wip != NULL);
+ DM_ensure_looptri_data(dm);
+ BLI_assert(totpoly == 0 || cddm->dm.looptris.array_wip != NULL);
- BKE_mesh_recalc_looptri(
- cddm->mloop, cddm->mpoly,
- cddm->mvert,
- totloop, totpoly,
- cddm->dm.looptris.array_wip);
+ BKE_mesh_recalc_looptri(
+ cddm->mloop, cddm->mpoly, cddm->mvert, totloop, totpoly, cddm->dm.looptris.array_wip);
- BLI_assert(cddm->dm.looptris.array == NULL);
- atomic_cas_ptr((void **)&cddm->dm.looptris.array, cddm->dm.looptris.array, cddm->dm.looptris.array_wip);
- cddm->dm.looptris.array_wip = NULL;
+ BLI_assert(cddm->dm.looptris.array == NULL);
+ atomic_cas_ptr(
+ (void **)&cddm->dm.looptris.array, cddm->dm.looptris.array, cddm->dm.looptris.array_wip);
+ cddm->dm.looptris.array_wip = NULL;
}
static void cdDM_free_internal(CDDerivedMesh *cddm)
{
- if (cddm->pmap) MEM_freeN(cddm->pmap);
- if (cddm->pmap_mem) MEM_freeN(cddm->pmap_mem);
+ if (cddm->pmap)
+ MEM_freeN(cddm->pmap);
+ if (cddm->pmap_mem)
+ MEM_freeN(cddm->pmap_mem);
}
static void cdDM_release(DerivedMesh *dm)
{
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- if (DM_release(dm)) {
- cdDM_free_internal(cddm);
- MEM_freeN(cddm);
- }
+ if (DM_release(dm)) {
+ cdDM_free_internal(cddm);
+ MEM_freeN(cddm);
+ }
}
/**************** CDDM interface functions ****************/
static CDDerivedMesh *cdDM_create(const char *desc)
{
- CDDerivedMesh *cddm;
- DerivedMesh *dm;
+ CDDerivedMesh *cddm;
+ DerivedMesh *dm;
- cddm = MEM_callocN(sizeof(*cddm), desc);
- dm = &cddm->dm;
+ cddm = MEM_callocN(sizeof(*cddm), desc);
+ dm = &cddm->dm;
- dm->getMinMax = cdDM_getMinMax;
+ dm->getMinMax = cdDM_getMinMax;
- dm->getNumVerts = cdDM_getNumVerts;
- dm->getNumEdges = cdDM_getNumEdges;
- dm->getNumTessFaces = cdDM_getNumTessFaces;
- dm->getNumLoops = cdDM_getNumLoops;
- dm->getNumPolys = cdDM_getNumPolys;
+ dm->getNumVerts = cdDM_getNumVerts;
+ dm->getNumEdges = cdDM_getNumEdges;
+ dm->getNumTessFaces = cdDM_getNumTessFaces;
+ dm->getNumLoops = cdDM_getNumLoops;
+ dm->getNumPolys = cdDM_getNumPolys;
- dm->getVert = cdDM_getVert;
- dm->getEdge = cdDM_getEdge;
- dm->getTessFace = cdDM_getTessFace;
+ dm->getVert = cdDM_getVert;
+ dm->getEdge = cdDM_getEdge;
+ dm->getTessFace = cdDM_getTessFace;
- dm->copyVertArray = cdDM_copyVertArray;
- dm->copyEdgeArray = cdDM_copyEdgeArray;
- dm->copyTessFaceArray = cdDM_copyTessFaceArray;
- dm->copyLoopArray = cdDM_copyLoopArray;
- dm->copyPolyArray = cdDM_copyPolyArray;
+ dm->copyVertArray = cdDM_copyVertArray;
+ dm->copyEdgeArray = cdDM_copyEdgeArray;
+ dm->copyTessFaceArray = cdDM_copyTessFaceArray;
+ dm->copyLoopArray = cdDM_copyLoopArray;
+ dm->copyPolyArray = cdDM_copyPolyArray;
- dm->getVertData = DM_get_vert_data;
- dm->getEdgeData = DM_get_edge_data;
- dm->getTessFaceData = DM_get_tessface_data;
- dm->getVertDataArray = DM_get_vert_data_layer;
- dm->getEdgeDataArray = DM_get_edge_data_layer;
- dm->getTessFaceDataArray = DM_get_tessface_data_layer;
+ dm->getVertData = DM_get_vert_data;
+ dm->getEdgeData = DM_get_edge_data;
+ dm->getTessFaceData = DM_get_tessface_data;
+ dm->getVertDataArray = DM_get_vert_data_layer;
+ dm->getEdgeDataArray = DM_get_edge_data_layer;
+ dm->getTessFaceDataArray = DM_get_tessface_data_layer;
- dm->calcNormals = CDDM_calc_normals;
- dm->calcLoopNormals = CDDM_calc_loop_normals;
- dm->calcLoopNormalsSpaceArray = CDDM_calc_loop_normals_spacearr;
- dm->calcLoopTangents = DM_calc_loop_tangents;
- dm->recalcTessellation = CDDM_recalc_tessellation;
- dm->recalcLoopTri = CDDM_recalc_looptri;
+ dm->calcNormals = CDDM_calc_normals;
+ dm->calcLoopNormals = CDDM_calc_loop_normals;
+ dm->calcLoopNormalsSpaceArray = CDDM_calc_loop_normals_spacearr;
+ dm->calcLoopTangents = DM_calc_loop_tangents;
+ dm->recalcTessellation = CDDM_recalc_tessellation;
+ dm->recalcLoopTri = CDDM_recalc_looptri;
- dm->getVertCos = cdDM_getVertCos;
- dm->getVertCo = cdDM_getVertCo;
- dm->getVertNo = cdDM_getVertNo;
+ dm->getVertCos = cdDM_getVertCos;
+ dm->getVertCo = cdDM_getVertCo;
+ dm->getVertNo = cdDM_getVertNo;
- dm->getPBVH = cdDM_getPBVH;
- dm->getPolyMap = cdDM_getPolyMap;
+ dm->getPBVH = cdDM_getPBVH;
+ dm->getPolyMap = cdDM_getPolyMap;
- dm->foreachMappedVert = cdDM_foreachMappedVert;
- dm->foreachMappedEdge = cdDM_foreachMappedEdge;
- dm->foreachMappedLoop = cdDM_foreachMappedLoop;
- dm->foreachMappedFaceCenter = cdDM_foreachMappedFaceCenter;
+ dm->foreachMappedVert = cdDM_foreachMappedVert;
+ dm->foreachMappedEdge = cdDM_foreachMappedEdge;
+ dm->foreachMappedLoop = cdDM_foreachMappedLoop;
+ dm->foreachMappedFaceCenter = cdDM_foreachMappedFaceCenter;
- dm->release = cdDM_release;
+ dm->release = cdDM_release;
- return cddm;
+ return cddm;
}
DerivedMesh *CDDM_new(int numVerts, int numEdges, int numTessFaces, int numLoops, int numPolys)
{
- CDDerivedMesh *cddm = cdDM_create("CDDM_new dm");
- DerivedMesh *dm = &cddm->dm;
+ CDDerivedMesh *cddm = cdDM_create("CDDM_new dm");
+ DerivedMesh *dm = &cddm->dm;
- DM_init(dm, DM_TYPE_CDDM, numVerts, numEdges, numTessFaces, numLoops, numPolys);
+ DM_init(dm, DM_TYPE_CDDM, numVerts, numEdges, numTessFaces, numLoops, numPolys);
- CustomData_add_layer(&dm->vertData, CD_ORIGINDEX, CD_CALLOC, NULL, numVerts);
- CustomData_add_layer(&dm->edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, numEdges);
- CustomData_add_layer(&dm->faceData, CD_ORIGINDEX, CD_CALLOC, NULL, numTessFaces);
- CustomData_add_layer(&dm->polyData, CD_ORIGINDEX, CD_CALLOC, NULL, numPolys);
+ CustomData_add_layer(&dm->vertData, CD_ORIGINDEX, CD_CALLOC, NULL, numVerts);
+ CustomData_add_layer(&dm->edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, numEdges);
+ CustomData_add_layer(&dm->faceData, CD_ORIGINDEX, CD_CALLOC, NULL, numTessFaces);
+ CustomData_add_layer(&dm->polyData, CD_ORIGINDEX, CD_CALLOC, NULL, numPolys);
- CustomData_add_layer(&dm->vertData, CD_MVERT, CD_CALLOC, NULL, numVerts);
- CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges);
- CustomData_add_layer(&dm->faceData, CD_MFACE, CD_CALLOC, NULL, numTessFaces);
- CustomData_add_layer(&dm->loopData, CD_MLOOP, CD_CALLOC, NULL, numLoops);
- CustomData_add_layer(&dm->polyData, CD_MPOLY, CD_CALLOC, NULL, numPolys);
+ CustomData_add_layer(&dm->vertData, CD_MVERT, CD_CALLOC, NULL, numVerts);
+ CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges);
+ CustomData_add_layer(&dm->faceData, CD_MFACE, CD_CALLOC, NULL, numTessFaces);
+ CustomData_add_layer(&dm->loopData, CD_MLOOP, CD_CALLOC, NULL, numLoops);
+ CustomData_add_layer(&dm->polyData, CD_MPOLY, CD_CALLOC, NULL, numPolys);
- cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT);
- cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
- cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
- cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
- cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
+ cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT);
+ cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
+ cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
+ cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
+ cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
- return dm;
+ return dm;
}
DerivedMesh *CDDM_from_mesh(Mesh *mesh)
{
- return CDDM_from_mesh_ex(mesh, CD_REFERENCE, &CD_MASK_MESH);
-}
-
-DerivedMesh *CDDM_from_mesh_ex(Mesh *mesh, eCDAllocType alloctype, const CustomData_MeshMasks *mask)
-{
- CDDerivedMesh *cddm = cdDM_create(__func__);
- DerivedMesh *dm = &cddm->dm;
- CustomData_MeshMasks cddata_masks = *mask;
-
- cddata_masks.lmask &= ~CD_MASK_MDISPS;
-
- /* this does a referenced copy, with an exception for fluidsim */
-
- DM_init(dm, DM_TYPE_CDDM, mesh->totvert, mesh->totedge, 0 /* mesh->totface */,
- mesh->totloop, mesh->totpoly);
-
- /* This should actually be dm->deformedOnly = mesh->runtime.deformed_only,
- * but only if the original mesh had its deformed_only flag correctly set
- * (which isn't generally the case). */
- dm->deformedOnly = 1;
- dm->cd_flag = mesh->cd_flag;
-
- if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) {
- dm->dirty |= DM_DIRTY_NORMALS;
- }
- /* TODO DM_DIRTY_TESS_CDLAYERS ? Maybe not though, since we probably want to switch to looptris ? */
-
- CustomData_merge(&mesh->vdata, &dm->vertData, cddata_masks.vmask, alloctype,
- mesh->totvert);
- CustomData_merge(&mesh->edata, &dm->edgeData, cddata_masks.emask, alloctype,
- mesh->totedge);
- CustomData_merge(&mesh->fdata, &dm->faceData, cddata_masks.fmask | CD_MASK_ORIGINDEX, alloctype,
- 0 /* mesh->totface */);
- CustomData_merge(&mesh->ldata, &dm->loopData, cddata_masks.lmask, alloctype,
- mesh->totloop);
- CustomData_merge(&mesh->pdata, &dm->polyData, cddata_masks.pmask, alloctype,
- mesh->totpoly);
-
- cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT);
- cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
- cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
- cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
+ return CDDM_from_mesh_ex(mesh, CD_REFERENCE, &CD_MASK_MESH);
+}
+
+DerivedMesh *CDDM_from_mesh_ex(Mesh *mesh,
+ eCDAllocType alloctype,
+ const CustomData_MeshMasks *mask)
+{
+ CDDerivedMesh *cddm = cdDM_create(__func__);
+ DerivedMesh *dm = &cddm->dm;
+ CustomData_MeshMasks cddata_masks = *mask;
+
+ cddata_masks.lmask &= ~CD_MASK_MDISPS;
+
+ /* this does a referenced copy, with an exception for fluidsim */
+
+ DM_init(dm,
+ DM_TYPE_CDDM,
+ mesh->totvert,
+ mesh->totedge,
+ 0 /* mesh->totface */,
+ mesh->totloop,
+ mesh->totpoly);
+
+ /* This should actually be dm->deformedOnly = mesh->runtime.deformed_only,
+ * but only if the original mesh had its deformed_only flag correctly set
+ * (which isn't generally the case). */
+ dm->deformedOnly = 1;
+ dm->cd_flag = mesh->cd_flag;
+
+ if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) {
+ dm->dirty |= DM_DIRTY_NORMALS;
+ }
+ /* TODO DM_DIRTY_TESS_CDLAYERS ? Maybe not though, since we probably want to switch to looptris ? */
+
+ CustomData_merge(&mesh->vdata, &dm->vertData, cddata_masks.vmask, alloctype, mesh->totvert);
+ CustomData_merge(&mesh->edata, &dm->edgeData, cddata_masks.emask, alloctype, mesh->totedge);
+ CustomData_merge(&mesh->fdata,
+ &dm->faceData,
+ cddata_masks.fmask | CD_MASK_ORIGINDEX,
+ alloctype,
+ 0 /* mesh->totface */);
+ CustomData_merge(&mesh->ldata, &dm->loopData, cddata_masks.lmask, alloctype, mesh->totloop);
+ CustomData_merge(&mesh->pdata, &dm->polyData, cddata_masks.pmask, alloctype, mesh->totpoly);
+
+ cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT);
+ cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
+ cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
+ cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
#if 0
- cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
+ cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
#else
- cddm->mface = NULL;
+ cddm->mface = NULL;
#endif
- /* commented since even when CD_ORIGINDEX was first added this line fails
- * on the default cube, (after editmode toggle too) - campbell */
+ /* commented since even when CD_ORIGINDEX was first added this line fails
+ * on the default cube, (after editmode toggle too) - campbell */
#if 0
- BLI_assert(CustomData_has_layer(&cddm->dm.faceData, CD_ORIGINDEX));
+ BLI_assert(CustomData_has_layer(&cddm->dm.faceData, CD_ORIGINDEX));
#endif
- return dm;
+ return dm;
}
DerivedMesh *CDDM_from_curve(Object *ob)
{
- ListBase disp = {NULL, NULL};
+ ListBase disp = {NULL, NULL};
- if (ob->runtime.curve_cache) {
- disp = ob->runtime.curve_cache->disp;
- }
+ if (ob->runtime.curve_cache) {
+ disp = ob->runtime.curve_cache->disp;
+ }
- return CDDM_from_curve_displist(ob, &disp);
+ return CDDM_from_curve_displist(ob, &disp);
}
DerivedMesh *CDDM_from_curve_displist(Object *ob, ListBase *dispbase)
{
- Curve *cu = (Curve *) ob->data;
- DerivedMesh *dm;
- CDDerivedMesh *cddm;
- MVert *allvert;
- MEdge *alledge;
- MLoop *allloop;
- MPoly *allpoly;
- MLoopUV *alluv = NULL;
- int totvert, totedge, totloop, totpoly;
- bool use_orco_uv = (cu->flag & CU_UV_ORCO) != 0;
-
- if (BKE_mesh_nurbs_displist_to_mdata(
- ob, dispbase, &allvert, &totvert, &alledge,
- &totedge, &allloop, &allpoly, (use_orco_uv) ? &alluv : NULL,
- &totloop, &totpoly) != 0)
- {
- /* Error initializing mdata. This often happens when curve is empty */
- return CDDM_new(0, 0, 0, 0, 0);
- }
-
- dm = CDDM_new(totvert, totedge, 0, totloop, totpoly);
- dm->deformedOnly = 1;
- dm->dirty |= DM_DIRTY_NORMALS;
-
- cddm = (CDDerivedMesh *)dm;
-
- memcpy(cddm->mvert, allvert, totvert * sizeof(MVert));
- memcpy(cddm->medge, alledge, totedge * sizeof(MEdge));
- memcpy(cddm->mloop, allloop, totloop * sizeof(MLoop));
- memcpy(cddm->mpoly, allpoly, totpoly * sizeof(MPoly));
-
- if (alluv) {
- const char *uvname = "Orco";
- CustomData_add_layer_named(&cddm->dm.loopData, CD_MLOOPUV, CD_ASSIGN, alluv, totloop, uvname);
- }
-
- MEM_freeN(allvert);
- MEM_freeN(alledge);
- MEM_freeN(allloop);
- MEM_freeN(allpoly);
-
- return dm;
+ Curve *cu = (Curve *)ob->data;
+ DerivedMesh *dm;
+ CDDerivedMesh *cddm;
+ MVert *allvert;
+ MEdge *alledge;
+ MLoop *allloop;
+ MPoly *allpoly;
+ MLoopUV *alluv = NULL;
+ int totvert, totedge, totloop, totpoly;
+ bool use_orco_uv = (cu->flag & CU_UV_ORCO) != 0;
+
+ if (BKE_mesh_nurbs_displist_to_mdata(ob,
+ dispbase,
+ &allvert,
+ &totvert,
+ &alledge,
+ &totedge,
+ &allloop,
+ &allpoly,
+ (use_orco_uv) ? &alluv : NULL,
+ &totloop,
+ &totpoly) != 0) {
+ /* Error initializing mdata. This often happens when curve is empty */
+ return CDDM_new(0, 0, 0, 0, 0);
+ }
+
+ dm = CDDM_new(totvert, totedge, 0, totloop, totpoly);
+ dm->deformedOnly = 1;
+ dm->dirty |= DM_DIRTY_NORMALS;
+
+ cddm = (CDDerivedMesh *)dm;
+
+ memcpy(cddm->mvert, allvert, totvert * sizeof(MVert));
+ memcpy(cddm->medge, alledge, totedge * sizeof(MEdge));
+ memcpy(cddm->mloop, allloop, totloop * sizeof(MLoop));
+ memcpy(cddm->mpoly, allpoly, totpoly * sizeof(MPoly));
+
+ if (alluv) {
+ const char *uvname = "Orco";
+ CustomData_add_layer_named(&cddm->dm.loopData, CD_MLOOPUV, CD_ASSIGN, alluv, totloop, uvname);
+ }
+
+ MEM_freeN(allvert);
+ MEM_freeN(alledge);
+ MEM_freeN(allloop);
+ MEM_freeN(allpoly);
+
+ return dm;
}
static void loops_to_customdata_corners(
- BMesh *bm, CustomData *facedata,
- int cdindex, const BMLoop *l3[3],
- int numCol, int numUV)
-{
- const BMLoop *l;
-// BMFace *f = l3[0]->f;
- MTFace *texface;
- MCol *mcol;
- MLoopCol *mloopcol;
- MLoopUV *mloopuv;
- int i, j, hasPCol = CustomData_has_layer(&bm->ldata, CD_PREVIEW_MLOOPCOL);
-
- for (i = 0; i < numUV; i++) {
- texface = CustomData_get_n(facedata, CD_MTFACE, cdindex, i);
-
- for (j = 0; j < 3; j++) {
- l = l3[j];
- mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPUV, i);
- copy_v2_v2(texface->uv[j], mloopuv->uv);
- }
- }
-
- for (i = 0; i < numCol; i++) {
- mcol = CustomData_get_n(facedata, CD_MCOL, cdindex, i);
-
- for (j = 0; j < 3; j++) {
- l = l3[j];
- mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPCOL, i);
- MESH_MLOOPCOL_TO_MCOL(mloopcol, &mcol[j]);
- }
- }
-
- if (hasPCol) {
- mcol = CustomData_get(facedata, cdindex, CD_PREVIEW_MCOL);
-
- for (j = 0; j < 3; j++) {
- l = l3[j];
- mloopcol = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_PREVIEW_MLOOPCOL);
- MESH_MLOOPCOL_TO_MCOL(mloopcol, &mcol[j]);
- }
- }
+ BMesh *bm, CustomData *facedata, int cdindex, const BMLoop *l3[3], int numCol, int numUV)
+{
+ const BMLoop *l;
+ // BMFace *f = l3[0]->f;
+ MTFace *texface;
+ MCol *mcol;
+ MLoopCol *mloopcol;
+ MLoopUV *mloopuv;
+ int i, j, hasPCol = CustomData_has_layer(&bm->ldata, CD_PREVIEW_MLOOPCOL);
+
+ for (i = 0; i < numUV; i++) {
+ texface = CustomData_get_n(facedata, CD_MTFACE, cdindex, i);
+
+ for (j = 0; j < 3; j++) {
+ l = l3[j];
+ mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPUV, i);
+ copy_v2_v2(texface->uv[j], mloopuv->uv);
+ }
+ }
+
+ for (i = 0; i < numCol; i++) {
+ mcol = CustomData_get_n(facedata, CD_MCOL, cdindex, i);
+
+ for (j = 0; j < 3; j++) {
+ l = l3[j];
+ mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPCOL, i);
+ MESH_MLOOPCOL_TO_MCOL(mloopcol, &mcol[j]);
+ }
+ }
+
+ if (hasPCol) {
+ mcol = CustomData_get(facedata, cdindex, CD_PREVIEW_MCOL);
+
+ for (j = 0; j < 3; j++) {
+ l = l3[j];
+ mloopcol = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_PREVIEW_MLOOPCOL);
+ MESH_MLOOPCOL_TO_MCOL(mloopcol, &mcol[j]);
+ }
+ }
}
/* TODO(campbell): remove, use BKE_mesh_from_bmesh_for_eval_nomain instead. */
/* used for both editbmesh and bmesh */
-static DerivedMesh *cddm_from_bmesh_ex(
- struct BMesh *bm, const bool use_mdisps,
- /* EditBMesh vars for use_tessface */
- const bool use_tessface,
- const int em_tottri, const BMLoop *(*em_looptris)[3])
-{
- DerivedMesh *dm = CDDM_new(bm->totvert,
- bm->totedge,
- use_tessface ? em_tottri : 0,
- bm->totloop,
- bm->totface);
-
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- BMIter iter;
- BMVert *eve;
- BMEdge *eed;
- BMFace *efa;
- MVert *mvert = cddm->mvert;
- MEdge *medge = cddm->medge;
- MFace *mface = cddm->mface;
- MLoop *mloop = cddm->mloop;
- MPoly *mpoly = cddm->mpoly;
- int numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);
- int numUV = CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV);
- int *index, add_orig;
- CustomData_MeshMasks mask = {0};
- unsigned int i, j;
-
- const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
- const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
- const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
-
- dm->deformedOnly = 1;
-
- /* don't add origindex layer if one already exists */
- add_orig = !CustomData_has_layer(&bm->pdata, CD_ORIGINDEX);
-
- mask = CD_MASK_DERIVEDMESH;
- if (use_mdisps) {
- mask.lmask |= CD_MASK_MDISPS;
- }
-
- /* don't process shapekeys, we only feed them through the modifier stack as needed,
- * e.g. for applying modifiers or the like*/
- mask.vmask &= ~CD_MASK_SHAPEKEY;
- CustomData_merge(&bm->vdata, &dm->vertData, mask.vmask,
- CD_CALLOC, dm->numVertData);
- CustomData_merge(&bm->edata, &dm->edgeData, mask.emask,
- CD_CALLOC, dm->numEdgeData);
- CustomData_merge(&bm->ldata, &dm->loopData, mask.lmask,
- CD_CALLOC, dm->numLoopData);
- CustomData_merge(&bm->pdata, &dm->polyData, mask.pmask,
- CD_CALLOC, dm->numPolyData);
-
- /* add tessellation mface layers */
- if (use_tessface) {
- CustomData_from_bmeshpoly(&dm->faceData, &dm->loopData, em_tottri);
- }
-
- index = dm->getVertDataArray(dm, CD_ORIGINDEX);
-
- BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
- MVert *mv = &mvert[i];
-
- copy_v3_v3(mv->co, eve->co);
-
- BM_elem_index_set(eve, i); /* set_inline */
-
- normal_float_to_short_v3(mv->no, eve->no);
-
- mv->flag = BM_vert_flag_to_mflag(eve);
-
- if (cd_vert_bweight_offset != -1) mv->bweight = BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eve, cd_vert_bweight_offset);
-
- if (add_orig) *index++ = i;
+static DerivedMesh *cddm_from_bmesh_ex(struct BMesh *bm,
+ const bool use_mdisps,
+ /* EditBMesh vars for use_tessface */
+ const bool use_tessface,
+ const int em_tottri,
+ const BMLoop *(*em_looptris)[3])
+{
+ DerivedMesh *dm = CDDM_new(
+ bm->totvert, bm->totedge, use_tessface ? em_tottri : 0, bm->totloop, bm->totface);
+
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+ BMIter iter;
+ BMVert *eve;
+ BMEdge *eed;
+ BMFace *efa;
+ MVert *mvert = cddm->mvert;
+ MEdge *medge = cddm->medge;
+ MFace *mface = cddm->mface;
+ MLoop *mloop = cddm->mloop;
+ MPoly *mpoly = cddm->mpoly;
+ int numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);
+ int numUV = CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV);
+ int *index, add_orig;
+ CustomData_MeshMasks mask = {0};
+ unsigned int i, j;
+
+ const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
+ const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
+ const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
+
+ dm->deformedOnly = 1;
+
+ /* don't add origindex layer if one already exists */
+ add_orig = !CustomData_has_layer(&bm->pdata, CD_ORIGINDEX);
+
+ mask = CD_MASK_DERIVEDMESH;
+ if (use_mdisps) {
+ mask.lmask |= CD_MASK_MDISPS;
+ }
+
+ /* don't process shapekeys, we only feed them through the modifier stack as needed,
+ * e.g. for applying modifiers or the like*/
+ mask.vmask &= ~CD_MASK_SHAPEKEY;
+ CustomData_merge(&bm->vdata, &dm->vertData, mask.vmask, CD_CALLOC, dm->numVertData);
+ CustomData_merge(&bm->edata, &dm->edgeData, mask.emask, CD_CALLOC, dm->numEdgeData);
+ CustomData_merge(&bm->ldata, &dm->loopData, mask.lmask, CD_CALLOC, dm->numLoopData);
+ CustomData_merge(&bm->pdata, &dm->polyData, mask.pmask, CD_CALLOC, dm->numPolyData);
+
+ /* add tessellation mface layers */
+ if (use_tessface) {
+ CustomData_from_bmeshpoly(&dm->faceData, &dm->loopData, em_tottri);
+ }
+
+ index = dm->getVertDataArray(dm, CD_ORIGINDEX);
+
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
+ MVert *mv = &mvert[i];
+
+ copy_v3_v3(mv->co, eve->co);
+
+ BM_elem_index_set(eve, i); /* set_inline */
+
+ normal_float_to_short_v3(mv->no, eve->no);
+
+ mv->flag = BM_vert_flag_to_mflag(eve);
+
+ if (cd_vert_bweight_offset != -1)
+ mv->bweight = BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eve, cd_vert_bweight_offset);
+
+ if (add_orig)
+ *index++ = i;
- CustomData_from_bmesh_block(&bm->vdata, &dm->vertData, eve->head.data, i);
- }
- bm->elem_index_dirty &= ~BM_VERT;
+ CustomData_from_bmesh_block(&bm->vdata, &dm->vertData, eve->head.data, i);
+ }
+ bm->elem_index_dirty &= ~BM_VERT;
- index = dm->getEdgeDataArray(dm, CD_ORIGINDEX);
- BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
- MEdge *med = &medge[i];
+ index = dm->getEdgeDataArray(dm, CD_ORIGINDEX);
+ BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
+ MEdge *med = &medge[i];
- BM_elem_index_set(eed, i); /* set_inline */
+ BM_elem_index_set(eed, i); /* set_inline */
- med->v1 = BM_elem_index_get(eed->v1);
- med->v2 = BM_elem_index_get(eed->v2);
+ med->v1 = BM_elem_index_get(eed->v1);
+ med->v2 = BM_elem_index_get(eed->v2);
- med->flag = BM_edge_flag_to_mflag(eed);
+ med->flag = BM_edge_flag_to_mflag(eed);
- /* handle this differently to editmode switching,
- * only enable draw for single user edges rather then calculating angle */
- if ((med->flag & ME_EDGEDRAW) == 0) {
- if (eed->l && eed->l == eed->l->radial_next) {
- med->flag |= ME_EDGEDRAW;
- }
- }
+ /* handle this differently to editmode switching,
+ * only enable draw for single user edges rather then calculating angle */
+ if ((med->flag & ME_EDGEDRAW) == 0) {
+ if (eed->l && eed->l == eed->l->radial_next) {
+ med->flag |= ME_EDGEDRAW;
+ }
+ }
- if (cd_edge_crease_offset != -1) med->crease = BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eed, cd_edge_crease_offset);
- if (cd_edge_bweight_offset != -1) med->bweight = BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eed, cd_edge_bweight_offset);
+ if (cd_edge_crease_offset != -1)
+ med->crease = BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eed, cd_edge_crease_offset);
+ if (cd_edge_bweight_offset != -1)
+ med->bweight = BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eed, cd_edge_bweight_offset);
- CustomData_from_bmesh_block(&bm->edata, &dm->edgeData, eed->head.data, i);
- if (add_orig) *index++ = i;
- }
- bm->elem_index_dirty &= ~BM_EDGE;
+ CustomData_from_bmesh_block(&bm->edata, &dm->edgeData, eed->head.data, i);
+ if (add_orig)
+ *index++ = i;
+ }
+ bm->elem_index_dirty &= ~BM_EDGE;
- /* avoid this where possiblem, takes extra memory */
- if (use_tessface) {
+ /* avoid this where possiblem, takes extra memory */
+ if (use_tessface) {
- BM_mesh_elem_index_ensure(bm, BM_FACE);
+ BM_mesh_elem_index_ensure(bm, BM_FACE);
- index = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
- for (i = 0; i < dm->numTessFaceData; i++) {
- MFace *mf = &mface[i];
- const BMLoop **l = em_looptris[i];
- efa = l[0]->f;
+ index = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
+ for (i = 0; i < dm->numTessFaceData; i++) {
+ MFace *mf = &mface[i];
+ const BMLoop **l = em_looptris[i];
+ efa = l[0]->f;
- mf->v1 = BM_elem_index_get(l[0]->v);
- mf->v2 = BM_elem_index_get(l[1]->v);
- mf->v3 = BM_elem_index_get(l[2]->v);
- mf->v4 = 0;
- mf->mat_nr = efa->mat_nr;
- mf->flag = BM_face_flag_to_mflag(efa);
+ mf->v1 = BM_elem_index_get(l[0]->v);
+ mf->v2 = BM_elem_index_get(l[1]->v);
+ mf->v3 = BM_elem_index_get(l[2]->v);
+ mf->v4 = 0;
+ mf->mat_nr = efa->mat_nr;
+ mf->flag = BM_face_flag_to_mflag(efa);
- /* map mfaces to polygons in the same cddm intentionally */
- *index++ = BM_elem_index_get(efa);
+ /* map mfaces to polygons in the same cddm intentionally */
+ *index++ = BM_elem_index_get(efa);
- loops_to_customdata_corners(bm, &dm->faceData, i, l, numCol, numUV);
- test_index_face(mf, &dm->faceData, i, 3);
- }
- }
+ loops_to_customdata_corners(bm, &dm->faceData, i, l, numCol, numUV);
+ test_index_face(mf, &dm->faceData, i, 3);
+ }
+ }
- index = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX);
- j = 0;
- BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
- BMLoop *l_iter;
- BMLoop *l_first;
- MPoly *mp = &mpoly[i];
+ index = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX);
+ j = 0;
+ BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
+ BMLoop *l_iter;
+ BMLoop *l_first;
+ MPoly *mp = &mpoly[i];
- BM_elem_index_set(efa, i); /* set_inline */
+ BM_elem_index_set(efa, i); /* set_inline */
- mp->totloop = efa->len;
- mp->flag = BM_face_flag_to_mflag(efa);
- mp->loopstart = j;
- mp->mat_nr = efa->mat_nr;
+ mp->totloop = efa->len;
+ mp->flag = BM_face_flag_to_mflag(efa);
+ mp->loopstart = j;
+ mp->mat_nr = efa->mat_nr;
- l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
- do {
- mloop->v = BM_elem_index_get(l_iter->v);
- mloop->e = BM_elem_index_get(l_iter->e);
- CustomData_from_bmesh_block(&bm->ldata, &dm->loopData, l_iter->head.data, j);
+ l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
+ do {
+ mloop->v = BM_elem_index_get(l_iter->v);
+ mloop->e = BM_elem_index_get(l_iter->e);
+ CustomData_from_bmesh_block(&bm->ldata, &dm->loopData, l_iter->head.data, j);
- BM_elem_index_set(l_iter, j); /* set_inline */
+ BM_elem_index_set(l_iter, j); /* set_inline */
- j++;
- mloop++;
- } while ((l_iter = l_iter->next) != l_first);
+ j++;
+ mloop++;
+ } while ((l_iter = l_iter->next) != l_first);
- CustomData_from_bmesh_block(&bm->pdata, &dm->polyData, efa->head.data, i);
+ CustomData_from_bmesh_block(&bm->pdata, &dm->polyData, efa->head.data, i);
- if (add_orig) *index++ = i;
- }
- bm->elem_index_dirty &= ~(BM_FACE | BM_LOOP);
+ if (add_orig)
+ *index++ = i;
+ }
+ bm->elem_index_dirty &= ~(BM_FACE | BM_LOOP);
- dm->cd_flag = BM_mesh_cd_flag_from_bmesh(bm);
+ dm->cd_flag = BM_mesh_cd_flag_from_bmesh(bm);
- return dm;
+ return dm;
}
struct DerivedMesh *CDDM_from_bmesh(struct BMesh *bm, const bool use_mdisps)
{
- return cddm_from_bmesh_ex(
- bm, use_mdisps, false,
- /* these vars are for editmesh only */
- 0, NULL);
+ return cddm_from_bmesh_ex(bm,
+ use_mdisps,
+ false,
+ /* these vars are for editmesh only */
+ 0,
+ NULL);
}
DerivedMesh *CDDM_from_editbmesh(BMEditMesh *em, const bool use_mdisps, const bool use_tessface)
{
- return cddm_from_bmesh_ex(
- em->bm, use_mdisps,
- /* editmesh */
- use_tessface, em->tottri, (const BMLoop *(*)[3])em->looptris);
+ return cddm_from_bmesh_ex(em->bm,
+ use_mdisps,
+ /* editmesh */
+ use_tessface,
+ em->tottri,
+ (const BMLoop *(*)[3])em->looptris);
}
DerivedMesh *CDDM_copy(DerivedMesh *source)
{
- CDDerivedMesh *cddm = cdDM_create("CDDM_copy cddm");
- DerivedMesh *dm = &cddm->dm;
- int numVerts = source->numVertData;
- int numEdges = source->numEdgeData;
- int numTessFaces = 0;
- int numLoops = source->numLoopData;
- int numPolys = source->numPolyData;
+ CDDerivedMesh *cddm = cdDM_create("CDDM_copy cddm");
+ DerivedMesh *dm = &cddm->dm;
+ int numVerts = source->numVertData;
+ int numEdges = source->numEdgeData;
+ int numTessFaces = 0;
+ int numLoops = source->numLoopData;
+ int numPolys = source->numPolyData;
- /* NOTE: Don't copy tessellation faces if not requested explicitly. */
+ /* NOTE: Don't copy tessellation faces if not requested explicitly. */
- /* ensure these are created if they are made on demand */
- source->getVertDataArray(source, CD_ORIGINDEX);
- source->getEdgeDataArray(source, CD_ORIGINDEX);
- source->getPolyDataArray(source, CD_ORIGINDEX);
+ /* ensure these are created if they are made on demand */
+ source->getVertDataArray(source, CD_ORIGINDEX);
+ source->getEdgeDataArray(source, CD_ORIGINDEX);
+ source->getPolyDataArray(source, CD_ORIGINDEX);
- /* this initializes dm, and copies all non mvert/medge/mface layers */
- DM_from_template(dm, source, DM_TYPE_CDDM, numVerts, numEdges, numTessFaces,
- numLoops, numPolys);
- dm->deformedOnly = source->deformedOnly;
- dm->cd_flag = source->cd_flag;
- dm->dirty = source->dirty;
+ /* this initializes dm, and copies all non mvert/medge/mface layers */
+ DM_from_template(dm, source, DM_TYPE_CDDM, numVerts, numEdges, numTessFaces, numLoops, numPolys);
+ dm->deformedOnly = source->deformedOnly;
+ dm->cd_flag = source->cd_flag;
+ dm->dirty = source->dirty;
- /* Tessellation data is never copied, so tag it here.
- * Only tag dirty layers if we really ignored tessellation faces.
- */
- dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
+ /* Tessellation data is never copied, so tag it here.
+ * Only tag dirty layers if we really ignored tessellation faces.
+ */
+ dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
- CustomData_copy_data(&source->vertData, &dm->vertData, 0, 0, numVerts);
- CustomData_copy_data(&source->edgeData, &dm->edgeData, 0, 0, numEdges);
+ CustomData_copy_data(&source->vertData, &dm->vertData, 0, 0, numVerts);
+ CustomData_copy_data(&source->edgeData, &dm->edgeData, 0, 0, numEdges);
- /* now add mvert/medge/mface layers */
- cddm->mvert = source->dupVertArray(source);
- cddm->medge = source->dupEdgeArray(source);
+ /* now add mvert/medge/mface layers */
+ cddm->mvert = source->dupVertArray(source);
+ cddm->medge = source->dupEdgeArray(source);
- CustomData_add_layer(&dm->vertData, CD_MVERT, CD_ASSIGN, cddm->mvert, numVerts);
- CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_ASSIGN, cddm->medge, numEdges);
+ CustomData_add_layer(&dm->vertData, CD_MVERT, CD_ASSIGN, cddm->mvert, numVerts);
+ CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_ASSIGN, cddm->medge, numEdges);
- DM_DupPolys(source, dm);
+ DM_DupPolys(source, dm);
- cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
- cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
+ cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
+ cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
- return dm;
+ return dm;
}
/* note, the CD_ORIGINDEX layers are all 0, so if there is a direct
* relationship between mesh data this needs to be set by the caller. */
DerivedMesh *CDDM_from_template_ex(DerivedMesh *source,
- int numVerts, int numEdges, int numTessFaces,
- int numLoops, int numPolys,
- const CustomData_MeshMasks *mask)
-{
- CDDerivedMesh *cddm = cdDM_create("CDDM_from_template dest");
- DerivedMesh *dm = &cddm->dm;
-
- /* ensure these are created if they are made on demand */
- source->getVertDataArray(source, CD_ORIGINDEX);
- source->getEdgeDataArray(source, CD_ORIGINDEX);
- source->getTessFaceDataArray(source, CD_ORIGINDEX);
- source->getPolyDataArray(source, CD_ORIGINDEX);
-
- /* this does a copy of all non mvert/medge/mface layers */
- DM_from_template_ex(
- dm, source, DM_TYPE_CDDM,
- numVerts, numEdges, numTessFaces,
- numLoops, numPolys,
- mask);
-
- /* now add mvert/medge/mface layers */
- CustomData_add_layer(&dm->vertData, CD_MVERT, CD_CALLOC, NULL, numVerts);
- CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges);
- CustomData_add_layer(&dm->faceData, CD_MFACE, CD_CALLOC, NULL, numTessFaces);
- CustomData_add_layer(&dm->loopData, CD_MLOOP, CD_CALLOC, NULL, numLoops);
- CustomData_add_layer(&dm->polyData, CD_MPOLY, CD_CALLOC, NULL, numPolys);
-
- if (!CustomData_get_layer(&dm->vertData, CD_ORIGINDEX))
- CustomData_add_layer(&dm->vertData, CD_ORIGINDEX, CD_CALLOC, NULL, numVerts);
- if (!CustomData_get_layer(&dm->edgeData, CD_ORIGINDEX))
- CustomData_add_layer(&dm->edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, numEdges);
- if (!CustomData_get_layer(&dm->faceData, CD_ORIGINDEX))
- CustomData_add_layer(&dm->faceData, CD_ORIGINDEX, CD_CALLOC, NULL, numTessFaces);
-
- cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT);
- cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
- cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
- cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
- cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
-
- return dm;
+ int numVerts,
+ int numEdges,
+ int numTessFaces,
+ int numLoops,
+ int numPolys,
+ const CustomData_MeshMasks *mask)
+{
+ CDDerivedMesh *cddm = cdDM_create("CDDM_from_template dest");
+ DerivedMesh *dm = &cddm->dm;
+
+ /* ensure these are created if they are made on demand */
+ source->getVertDataArray(source, CD_ORIGINDEX);
+ source->getEdgeDataArray(source, CD_ORIGINDEX);
+ source->getTessFaceDataArray(source, CD_ORIGINDEX);
+ source->getPolyDataArray(source, CD_ORIGINDEX);
+
+ /* this does a copy of all non mvert/medge/mface layers */
+ DM_from_template_ex(
+ dm, source, DM_TYPE_CDDM, numVerts, numEdges, numTessFaces, numLoops, numPolys, mask);
+
+ /* now add mvert/medge/mface layers */
+ CustomData_add_layer(&dm->vertData, CD_MVERT, CD_CALLOC, NULL, numVerts);
+ CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges);
+ CustomData_add_layer(&dm->faceData, CD_MFACE, CD_CALLOC, NULL, numTessFaces);
+ CustomData_add_layer(&dm->loopData, CD_MLOOP, CD_CALLOC, NULL, numLoops);
+ CustomData_add_layer(&dm->polyData, CD_MPOLY, CD_CALLOC, NULL, numPolys);
+
+ if (!CustomData_get_layer(&dm->vertData, CD_ORIGINDEX))
+ CustomData_add_layer(&dm->vertData, CD_ORIGINDEX, CD_CALLOC, NULL, numVerts);
+ if (!CustomData_get_layer(&dm->edgeData, CD_ORIGINDEX))
+ CustomData_add_layer(&dm->edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, numEdges);
+ if (!CustomData_get_layer(&dm->faceData, CD_ORIGINDEX))
+ CustomData_add_layer(&dm->faceData, CD_ORIGINDEX, CD_CALLOC, NULL, numTessFaces);
+
+ cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT);
+ cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
+ cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
+ cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
+ cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
+
+ return dm;
}
DerivedMesh *CDDM_from_template(
- DerivedMesh *source,
- int numVerts, int numEdges, int numTessFaces,
- int numLoops, int numPolys)
+ DerivedMesh *source, int numVerts, int numEdges, int numTessFaces, int numLoops, int numPolys)
{
- return CDDM_from_template_ex(
- source, numVerts, numEdges, numTessFaces,
- numLoops, numPolys,
- &CD_MASK_DERIVEDMESH);
+ return CDDM_from_template_ex(
+ source, numVerts, numEdges, numTessFaces, numLoops, numPolys, &CD_MASK_DERIVEDMESH);
}
void CDDM_apply_vert_coords(DerivedMesh *dm, float (*vertCoords)[3])
{
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- MVert *vert;
- int i;
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+ MVert *vert;
+ int i;
- /* this will just return the pointer if it wasn't a referenced layer */
- vert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT, dm->numVertData);
- cddm->mvert = vert;
+ /* this will just return the pointer if it wasn't a referenced layer */
+ vert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT, dm->numVertData);
+ cddm->mvert = vert;
- for (i = 0; i < dm->numVertData; ++i, ++vert)
- copy_v3_v3(vert->co, vertCoords[i]);
+ for (i = 0; i < dm->numVertData; ++i, ++vert)
+ copy_v3_v3(vert->co, vertCoords[i]);
- cddm->dm.dirty |= DM_DIRTY_NORMALS;
+ cddm->dm.dirty |= DM_DIRTY_NORMALS;
}
void CDDM_apply_vert_normals(DerivedMesh *dm, short (*vertNormals)[3])
{
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- MVert *vert;
- int i;
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+ MVert *vert;
+ int i;
- /* this will just return the pointer if it wasn't a referenced layer */
- vert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT, dm->numVertData);
- cddm->mvert = vert;
+ /* this will just return the pointer if it wasn't a referenced layer */
+ vert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT, dm->numVertData);
+ cddm->mvert = vert;
- for (i = 0; i < dm->numVertData; ++i, ++vert)
- copy_v3_v3_short(vert->no, vertNormals[i]);
+ for (i = 0; i < dm->numVertData; ++i, ++vert)
+ copy_v3_v3_short(vert->no, vertNormals[i]);
- cddm->dm.dirty &= ~DM_DIRTY_NORMALS;
+ cddm->dm.dirty &= ~DM_DIRTY_NORMALS;
}
void CDDM_calc_normals_mapping_ex(DerivedMesh *dm, const bool only_face_normals)
{
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- float (*face_nors)[3] = NULL;
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+ float(*face_nors)[3] = NULL;
- if (dm->numVertData == 0) {
- cddm->dm.dirty &= ~DM_DIRTY_NORMALS;
- return;
- }
+ if (dm->numVertData == 0) {
+ cddm->dm.dirty &= ~DM_DIRTY_NORMALS;
+ return;
+ }
- /* now we skip calculating vertex normals for referenced layer,
- * no need to duplicate verts.
- * WATCH THIS, bmesh only change!,
- * need to take care of the side effects here - campbell */
+ /* now we skip calculating vertex normals for referenced layer,
+ * no need to duplicate verts.
+ * WATCH THIS, bmesh only change!,
+ * need to take care of the side effects here - campbell */
#if 0
- /* we don't want to overwrite any referenced layers */
- cddm->mvert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT, dm->numVertData);
+ /* we don't want to overwrite any referenced layers */
+ cddm->mvert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT, dm->numVertData);
#endif
#if 0
- if (dm->numTessFaceData == 0) {
- /* No tessellation on this mesh yet, need to calculate one.
- *
- * Important not to update face normals from polys since it
- * interferes with assigning the new normal layer in the following code.
- */
- CDDM_recalc_tessellation_ex(dm, false);
- }
- else {
- /* A tessellation already exists, it should always have a CD_ORIGINDEX */
- BLI_assert(CustomData_has_layer(&dm->faceData, CD_ORIGINDEX));
- CustomData_free_layers(&dm->faceData, CD_NORMAL, dm->numTessFaceData);
- }
+ if (dm->numTessFaceData == 0) {
+ /* No tessellation on this mesh yet, need to calculate one.
+ *
+ * Important not to update face normals from polys since it
+ * interferes with assigning the new normal layer in the following code.
+ */
+ CDDM_recalc_tessellation_ex(dm, false);
+ }
+ else {
+ /* A tessellation already exists, it should always have a CD_ORIGINDEX */
+ BLI_assert(CustomData_has_layer(&dm->faceData, CD_ORIGINDEX));
+ CustomData_free_layers(&dm->faceData, CD_NORMAL, dm->numTessFaceData);
+ }
#endif
- face_nors = MEM_malloc_arrayN(dm->numPolyData, sizeof(*face_nors), "face_nors");
+ face_nors = MEM_malloc_arrayN(dm->numPolyData, sizeof(*face_nors), "face_nors");
- /* calculate face normals */
- BKE_mesh_calc_normals_poly(
- cddm->mvert, NULL, dm->numVertData, CDDM_get_loops(dm), CDDM_get_polys(dm),
- dm->numLoopData, dm->numPolyData, face_nors,
- only_face_normals);
+ /* calculate face normals */
+ BKE_mesh_calc_normals_poly(cddm->mvert,
+ NULL,
+ dm->numVertData,
+ CDDM_get_loops(dm),
+ CDDM_get_polys(dm),
+ dm->numLoopData,
+ dm->numPolyData,
+ face_nors,
+ only_face_normals);
- CustomData_add_layer(&dm->polyData, CD_NORMAL, CD_ASSIGN, face_nors, dm->numPolyData);
+ CustomData_add_layer(&dm->polyData, CD_NORMAL, CD_ASSIGN, face_nors, dm->numPolyData);
- cddm->dm.dirty &= ~DM_DIRTY_NORMALS;
+ cddm->dm.dirty &= ~DM_DIRTY_NORMALS;
}
void CDDM_calc_normals_mapping(DerivedMesh *dm)
{
- /* use this to skip calculating normals on original vert's, this may need to be changed */
- const bool only_face_normals = CustomData_is_referenced_layer(&dm->vertData, CD_MVERT);
+ /* use this to skip calculating normals on original vert's, this may need to be changed */
+ const bool only_face_normals = CustomData_is_referenced_layer(&dm->vertData, CD_MVERT);
- CDDM_calc_normals_mapping_ex(dm, only_face_normals);
+ CDDM_calc_normals_mapping_ex(dm, only_face_normals);
}
#if 0
/* bmesh note: this matches what we have in trunk */
void CDDM_calc_normals(DerivedMesh *dm)
{
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- float (*poly_nors)[3];
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+ float (*poly_nors)[3];
- if (dm->numVertData == 0) return;
+ if (dm->numVertData == 0) return;
- /* we don't want to overwrite any referenced layers */
- cddm->mvert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT, dm->numVertData);
+ /* we don't want to overwrite any referenced layers */
+ cddm->mvert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT, dm->numVertData);
- /* fill in if it exists */
- poly_nors = CustomData_get_layer(&dm->polyData, CD_NORMAL);
- if (!poly_nors) {
- poly_nors = CustomData_add_layer(&dm->polyData, CD_NORMAL, CD_CALLOC, NULL, dm->numPolyData);
- }
+ /* fill in if it exists */
+ poly_nors = CustomData_get_layer(&dm->polyData, CD_NORMAL);
+ if (!poly_nors) {
+ poly_nors = CustomData_add_layer(&dm->polyData, CD_NORMAL, CD_CALLOC, NULL, dm->numPolyData);
+ }
- BKE_mesh_calc_normals_poly(cddm->mvert, dm->numVertData, CDDM_get_loops(dm), CDDM_get_polys(dm),
- dm->numLoopData, dm->numPolyData, poly_nors, false);
+ BKE_mesh_calc_normals_poly(cddm->mvert, dm->numVertData, CDDM_get_loops(dm), CDDM_get_polys(dm),
+ dm->numLoopData, dm->numPolyData, poly_nors, false);
- cddm->dm.dirty &= ~DM_DIRTY_NORMALS;
+ cddm->dm.dirty &= ~DM_DIRTY_NORMALS;
}
#else
/* poly normal layer is now only for final display */
void CDDM_calc_normals(DerivedMesh *dm)
{
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- /* we don't want to overwrite any referenced layers */
- cddm->mvert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT, dm->numVertData);
+ /* we don't want to overwrite any referenced layers */
+ cddm->mvert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT, dm->numVertData);
- BKE_mesh_calc_normals_poly(cddm->mvert, NULL, dm->numVertData, CDDM_get_loops(dm), CDDM_get_polys(dm),
- dm->numLoopData, dm->numPolyData, NULL, false);
+ BKE_mesh_calc_normals_poly(cddm->mvert,
+ NULL,
+ dm->numVertData,
+ CDDM_get_loops(dm),
+ CDDM_get_polys(dm),
+ dm->numLoopData,
+ dm->numPolyData,
+ NULL,
+ false);
- cddm->dm.dirty &= ~DM_DIRTY_NORMALS;
+ cddm->dm.dirty &= ~DM_DIRTY_NORMALS;
}
#endif
void CDDM_calc_loop_normals(DerivedMesh *dm, const bool use_split_normals, const float split_angle)
{
- CDDM_calc_loop_normals_spacearr(dm, use_split_normals, split_angle, NULL);
+ CDDM_calc_loop_normals_spacearr(dm, use_split_normals, split_angle, NULL);
}
/* #define DEBUG_CLNORS */
@@ -1171,223 +1202,245 @@ void CDDM_calc_loop_normals(DerivedMesh *dm, const bool use_split_normals, const
# include "BLI_linklist.h"
#endif
-void CDDM_calc_loop_normals_spacearr(
- DerivedMesh *dm, const bool use_split_normals, const float split_angle, MLoopNorSpaceArray *r_lnors_spacearr)
-{
- MVert *mverts = dm->getVertArray(dm);
- MEdge *medges = dm->getEdgeArray(dm);
- MLoop *mloops = dm->getLoopArray(dm);
- MPoly *mpolys = dm->getPolyArray(dm);
-
- CustomData *ldata, *pdata;
-
- float (*lnors)[3];
- short (*clnor_data)[2];
- float (*pnors)[3];
-
- const int numVerts = dm->getNumVerts(dm);
- const int numEdges = dm->getNumEdges(dm);
- const int numLoops = dm->getNumLoops(dm);
- const int numPolys = dm->getNumPolys(dm);
-
- ldata = dm->getLoopDataLayout(dm);
- if (CustomData_has_layer(ldata, CD_NORMAL)) {
- lnors = CustomData_get_layer(ldata, CD_NORMAL);
- }
- else {
- lnors = CustomData_add_layer(ldata, CD_NORMAL, CD_CALLOC, NULL, numLoops);
- }
-
- /* Compute poly (always needed) and vert normals. */
- /* Note we can't use DM_ensure_normals, since it won't keep computed poly nors... */
- pdata = dm->getPolyDataLayout(dm);
- pnors = CustomData_get_layer(pdata, CD_NORMAL);
- if (!pnors) {
- pnors = CustomData_add_layer(pdata, CD_NORMAL, CD_CALLOC, NULL, numPolys);
- }
- BKE_mesh_calc_normals_poly(mverts, NULL, numVerts, mloops, mpolys, numLoops, numPolys, pnors,
- (dm->dirty & DM_DIRTY_NORMALS) ? false : true);
-
- dm->dirty &= ~DM_DIRTY_NORMALS;
-
- clnor_data = CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL);
-
- BKE_mesh_normals_loop_split(mverts, numVerts, medges, numEdges, mloops, lnors, numLoops,
- mpolys, (const float (*)[3])pnors, numPolys,
- use_split_normals, split_angle,
- r_lnors_spacearr, clnor_data, NULL);
+void CDDM_calc_loop_normals_spacearr(DerivedMesh *dm,
+ const bool use_split_normals,
+ const float split_angle,
+ MLoopNorSpaceArray *r_lnors_spacearr)
+{
+ MVert *mverts = dm->getVertArray(dm);
+ MEdge *medges = dm->getEdgeArray(dm);
+ MLoop *mloops = dm->getLoopArray(dm);
+ MPoly *mpolys = dm->getPolyArray(dm);
+
+ CustomData *ldata, *pdata;
+
+ float(*lnors)[3];
+ short(*clnor_data)[2];
+ float(*pnors)[3];
+
+ const int numVerts = dm->getNumVerts(dm);
+ const int numEdges = dm->getNumEdges(dm);
+ const int numLoops = dm->getNumLoops(dm);
+ const int numPolys = dm->getNumPolys(dm);
+
+ ldata = dm->getLoopDataLayout(dm);
+ if (CustomData_has_layer(ldata, CD_NORMAL)) {
+ lnors = CustomData_get_layer(ldata, CD_NORMAL);
+ }
+ else {
+ lnors = CustomData_add_layer(ldata, CD_NORMAL, CD_CALLOC, NULL, numLoops);
+ }
+
+ /* Compute poly (always needed) and vert normals. */
+ /* Note we can't use DM_ensure_normals, since it won't keep computed poly nors... */
+ pdata = dm->getPolyDataLayout(dm);
+ pnors = CustomData_get_layer(pdata, CD_NORMAL);
+ if (!pnors) {
+ pnors = CustomData_add_layer(pdata, CD_NORMAL, CD_CALLOC, NULL, numPolys);
+ }
+ BKE_mesh_calc_normals_poly(mverts,
+ NULL,
+ numVerts,
+ mloops,
+ mpolys,
+ numLoops,
+ numPolys,
+ pnors,
+ (dm->dirty & DM_DIRTY_NORMALS) ? false : true);
+
+ dm->dirty &= ~DM_DIRTY_NORMALS;
+
+ clnor_data = CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL);
+
+ BKE_mesh_normals_loop_split(mverts,
+ numVerts,
+ medges,
+ numEdges,
+ mloops,
+ lnors,
+ numLoops,
+ mpolys,
+ (const float(*)[3])pnors,
+ numPolys,
+ use_split_normals,
+ split_angle,
+ r_lnors_spacearr,
+ clnor_data,
+ NULL);
#ifdef DEBUG_CLNORS
- if (r_lnors_spacearr) {
- int i;
- for (i = 0; i < numLoops; i++) {
- if (r_lnors_spacearr->lspacearr[i]->ref_alpha != 0.0f) {
- LinkNode *loops = r_lnors_spacearr->lspacearr[i]->loops;
- printf("Loop %d uses lnor space %p:\n", i, r_lnors_spacearr->lspacearr[i]);
- print_v3("\tfinal lnor", lnors[i]);
- print_v3("\tauto lnor", r_lnors_spacearr->lspacearr[i]->vec_lnor);
- print_v3("\tref_vec", r_lnors_spacearr->lspacearr[i]->vec_ref);
- printf("\talpha: %f\n\tbeta: %f\n\tloops: %p\n", r_lnors_spacearr->lspacearr[i]->ref_alpha,
- r_lnors_spacearr->lspacearr[i]->ref_beta, r_lnors_spacearr->lspacearr[i]->loops);
- printf("\t\t(shared with loops");
- while (loops) {
- printf(" %d", POINTER_AS_INT(loops->link));
- loops = loops->next;
- }
- printf(")\n");
- }
- else {
- printf("Loop %d has no lnor space\n", i);
- }
- }
- }
+ if (r_lnors_spacearr) {
+ int i;
+ for (i = 0; i < numLoops; i++) {
+ if (r_lnors_spacearr->lspacearr[i]->ref_alpha != 0.0f) {
+ LinkNode *loops = r_lnors_spacearr->lspacearr[i]->loops;
+ printf("Loop %d uses lnor space %p:\n", i, r_lnors_spacearr->lspacearr[i]);
+ print_v3("\tfinal lnor", lnors[i]);
+ print_v3("\tauto lnor", r_lnors_spacearr->lspacearr[i]->vec_lnor);
+ print_v3("\tref_vec", r_lnors_spacearr->lspacearr[i]->vec_ref);
+ printf("\talpha: %f\n\tbeta: %f\n\tloops: %p\n",
+ r_lnors_spacearr->lspacearr[i]->ref_alpha,
+ r_lnors_spacearr->lspacearr[i]->ref_beta,
+ r_lnors_spacearr->lspacearr[i]->loops);
+ printf("\t\t(shared with loops");
+ while (loops) {
+ printf(" %d", POINTER_AS_INT(loops->link));
+ loops = loops->next;
+ }
+ printf(")\n");
+ }
+ else {
+ printf("Loop %d has no lnor space\n", i);
+ }
+ }
+ }
#endif
}
void CDDM_lower_num_verts(DerivedMesh *dm, int numVerts)
{
- BLI_assert(numVerts >= 0);
- if (numVerts < dm->numVertData)
- CustomData_free_elem(&dm->vertData, numVerts, dm->numVertData - numVerts);
+ BLI_assert(numVerts >= 0);
+ if (numVerts < dm->numVertData)
+ CustomData_free_elem(&dm->vertData, numVerts, dm->numVertData - numVerts);
- dm->numVertData = numVerts;
+ dm->numVertData = numVerts;
}
void CDDM_lower_num_edges(DerivedMesh *dm, int numEdges)
{
- BLI_assert(numEdges >= 0);
- if (numEdges < dm->numEdgeData)
- CustomData_free_elem(&dm->edgeData, numEdges, dm->numEdgeData - numEdges);
+ BLI_assert(numEdges >= 0);
+ if (numEdges < dm->numEdgeData)
+ CustomData_free_elem(&dm->edgeData, numEdges, dm->numEdgeData - numEdges);
- dm->numEdgeData = numEdges;
+ dm->numEdgeData = numEdges;
}
void CDDM_lower_num_tessfaces(DerivedMesh *dm, int numTessFaces)
{
- BLI_assert(numTessFaces >= 0);
- if (numTessFaces < dm->numTessFaceData)
- CustomData_free_elem(&dm->faceData, numTessFaces, dm->numTessFaceData - numTessFaces);
+ BLI_assert(numTessFaces >= 0);
+ if (numTessFaces < dm->numTessFaceData)
+ CustomData_free_elem(&dm->faceData, numTessFaces, dm->numTessFaceData - numTessFaces);
- dm->numTessFaceData = numTessFaces;
+ dm->numTessFaceData = numTessFaces;
}
void CDDM_lower_num_loops(DerivedMesh *dm, int numLoops)
{
- BLI_assert(numLoops >= 0);
- if (numLoops < dm->numLoopData)
- CustomData_free_elem(&dm->loopData, numLoops, dm->numLoopData - numLoops);
+ BLI_assert(numLoops >= 0);
+ if (numLoops < dm->numLoopData)
+ CustomData_free_elem(&dm->loopData, numLoops, dm->numLoopData - numLoops);
- dm->numLoopData = numLoops;
+ dm->numLoopData = numLoops;
}
void CDDM_lower_num_polys(DerivedMesh *dm, int numPolys)
{
- BLI_assert(numPolys >= 0);
- if (numPolys < dm->numPolyData)
- CustomData_free_elem(&dm->polyData, numPolys, dm->numPolyData - numPolys);
+ BLI_assert(numPolys >= 0);
+ if (numPolys < dm->numPolyData)
+ CustomData_free_elem(&dm->polyData, numPolys, dm->numPolyData - numPolys);
- dm->numPolyData = numPolys;
+ dm->numPolyData = numPolys;
}
/* mesh element access functions */
MVert *CDDM_get_vert(DerivedMesh *dm, int index)
{
- return &((CDDerivedMesh *)dm)->mvert[index];
+ return &((CDDerivedMesh *)dm)->mvert[index];
}
MEdge *CDDM_get_edge(DerivedMesh *dm, int index)
{
- return &((CDDerivedMesh *)dm)->medge[index];
+ return &((CDDerivedMesh *)dm)->medge[index];
}
MFace *CDDM_get_tessface(DerivedMesh *dm, int index)
{
- return &((CDDerivedMesh *)dm)->mface[index];
+ return &((CDDerivedMesh *)dm)->mface[index];
}
MLoop *CDDM_get_loop(DerivedMesh *dm, int index)
{
- return &((CDDerivedMesh *)dm)->mloop[index];
+ return &((CDDerivedMesh *)dm)->mloop[index];
}
MPoly *CDDM_get_poly(DerivedMesh *dm, int index)
{
- return &((CDDerivedMesh *)dm)->mpoly[index];
+ return &((CDDerivedMesh *)dm)->mpoly[index];
}
/* array access functions */
MVert *CDDM_get_verts(DerivedMesh *dm)
{
- return ((CDDerivedMesh *)dm)->mvert;
+ return ((CDDerivedMesh *)dm)->mvert;
}
MEdge *CDDM_get_edges(DerivedMesh *dm)
{
- return ((CDDerivedMesh *)dm)->medge;
+ return ((CDDerivedMesh *)dm)->medge;
}
MFace *CDDM_get_tessfaces(DerivedMesh *dm)
{
- return ((CDDerivedMesh *)dm)->mface;
+ return ((CDDerivedMesh *)dm)->mface;
}
MLoop *CDDM_get_loops(DerivedMesh *dm)
{
- return ((CDDerivedMesh *)dm)->mloop;
+ return ((CDDerivedMesh *)dm)->mloop;
}
MPoly *CDDM_get_polys(DerivedMesh *dm)
{
- return ((CDDerivedMesh *)dm)->mpoly;
+ return ((CDDerivedMesh *)dm)->mpoly;
}
void CDDM_set_mvert(DerivedMesh *dm, MVert *mvert)
{
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- if (!CustomData_has_layer(&dm->vertData, CD_MVERT))
- CustomData_add_layer(&dm->vertData, CD_MVERT, CD_ASSIGN, mvert, dm->numVertData);
+ if (!CustomData_has_layer(&dm->vertData, CD_MVERT))
+ CustomData_add_layer(&dm->vertData, CD_MVERT, CD_ASSIGN, mvert, dm->numVertData);
- cddm->mvert = mvert;
+ cddm->mvert = mvert;
}
void CDDM_set_medge(DerivedMesh *dm, MEdge *medge)
{
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- if (!CustomData_has_layer(&dm->edgeData, CD_MEDGE))
- CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_ASSIGN, medge, dm->numEdgeData);
+ if (!CustomData_has_layer(&dm->edgeData, CD_MEDGE))
+ CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_ASSIGN, medge, dm->numEdgeData);
- cddm->medge = medge;
+ cddm->medge = medge;
}
void CDDM_set_mface(DerivedMesh *dm, MFace *mface)
{
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- if (!CustomData_has_layer(&dm->faceData, CD_MFACE))
- CustomData_add_layer(&dm->faceData, CD_MFACE, CD_ASSIGN, mface, dm->numTessFaceData);
+ if (!CustomData_has_layer(&dm->faceData, CD_MFACE))
+ CustomData_add_layer(&dm->faceData, CD_MFACE, CD_ASSIGN, mface, dm->numTessFaceData);
- cddm->mface = mface;
+ cddm->mface = mface;
}
void CDDM_set_mloop(DerivedMesh *dm, MLoop *mloop)
{
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- if (!CustomData_has_layer(&dm->loopData, CD_MLOOP))
- CustomData_add_layer(&dm->loopData, CD_MLOOP, CD_ASSIGN, mloop, dm->numLoopData);
+ if (!CustomData_has_layer(&dm->loopData, CD_MLOOP))
+ CustomData_add_layer(&dm->loopData, CD_MLOOP, CD_ASSIGN, mloop, dm->numLoopData);
- cddm->mloop = mloop;
+ cddm->mloop = mloop;
}
void CDDM_set_mpoly(DerivedMesh *dm, MPoly *mpoly)
{
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- if (!CustomData_has_layer(&dm->polyData, CD_MPOLY))
- CustomData_add_layer(&dm->polyData, CD_MPOLY, CD_ASSIGN, mpoly, dm->numPolyData);
+ if (!CustomData_has_layer(&dm->polyData, CD_MPOLY))
+ CustomData_add_layer(&dm->polyData, CD_MPOLY, CD_ASSIGN, mpoly, dm->numPolyData);
- cddm->mpoly = mpoly;
+ cddm->mpoly = mpoly;
}
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index dddb34afd39..9f25cd14499 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -21,7 +21,6 @@
* \ingroup bke
*/
-
#include "MEM_guardedalloc.h"
#include "DNA_cloth_types.h"
@@ -53,19 +52,20 @@
/* ********** cloth engine ******* */
/* Prototypes for internal functions.
*/
-static void cloth_to_object (Object *ob, ClothModifierData *clmd, float (*vertexCos)[3]);
-static void cloth_from_mesh ( ClothModifierData *clmd, Mesh *mesh );
-static int cloth_from_object(Object *ob, ClothModifierData *clmd, Mesh *mesh, float framenr, int first);
-static void cloth_update_springs( ClothModifierData *clmd );
-static void cloth_update_verts( Object *ob, ClothModifierData *clmd, Mesh *mesh );
-static void cloth_update_spring_lengths( ClothModifierData *clmd, Mesh *mesh );
-static int cloth_build_springs ( ClothModifierData *clmd, Mesh *mesh );
-static void cloth_apply_vgroup ( ClothModifierData *clmd, Mesh *mesh );
+static void cloth_to_object(Object *ob, ClothModifierData *clmd, float (*vertexCos)[3]);
+static void cloth_from_mesh(ClothModifierData *clmd, Mesh *mesh);
+static int cloth_from_object(
+ Object *ob, ClothModifierData *clmd, Mesh *mesh, float framenr, int first);
+static void cloth_update_springs(ClothModifierData *clmd);
+static void cloth_update_verts(Object *ob, ClothModifierData *clmd, Mesh *mesh);
+static void cloth_update_spring_lengths(ClothModifierData *clmd, Mesh *mesh);
+static int cloth_build_springs(ClothModifierData *clmd, Mesh *mesh);
+static void cloth_apply_vgroup(ClothModifierData *clmd, Mesh *mesh);
typedef struct BendSpringRef {
- int index;
- int polys;
- ClothSpring *spring;
+ int index;
+ int polys;
+ ClothSpring *spring;
} BendSpringRef;
/******************************************************************************
@@ -79,502 +79,509 @@ typedef struct BendSpringRef {
* 1. create object
* 2. fill object with standard values or with the GUI settings if given
*/
-void cloth_init(ClothModifierData *clmd )
+void cloth_init(ClothModifierData *clmd)
{
- /* Initialize our new data structure to reasonable values. */
- clmd->sim_parms->gravity[0] = 0.0;
- clmd->sim_parms->gravity[1] = 0.0;
- clmd->sim_parms->gravity[2] = -9.81;
- clmd->sim_parms->tension = 15.0;
- clmd->sim_parms->max_tension = 15.0;
- clmd->sim_parms->compression = 15.0;
- clmd->sim_parms->max_compression = 15.0;
- clmd->sim_parms->shear = 5.0;
- clmd->sim_parms->max_shear = 5.0;
- clmd->sim_parms->bending = 0.5;
- clmd->sim_parms->max_bend = 0.5;
- clmd->sim_parms->tension_damp = 5.0;
- clmd->sim_parms->compression_damp = 5.0;
- clmd->sim_parms->shear_damp = 5.0;
- clmd->sim_parms->bending_damping = 0.5;
- clmd->sim_parms->Cvi = 1.0;
- clmd->sim_parms->mass = 0.3f;
- clmd->sim_parms->stepsPerFrame = 5;
- clmd->sim_parms->flags = 0;
- clmd->sim_parms->solver_type = 0;
- clmd->sim_parms->maxspringlen = 10;
- clmd->sim_parms->vgroup_mass = 0;
- clmd->sim_parms->vgroup_shrink = 0;
- clmd->sim_parms->shrink_min = 0.0f; /* min amount the fabric will shrink by 0.0 = no shrinking, 1.0 = shrink to nothing*/
- clmd->sim_parms->avg_spring_len = 0.0;
- clmd->sim_parms->presets = 2; /* cotton as start setting */
- clmd->sim_parms->timescale = 1.0f; /* speed factor, describes how fast cloth moves */
- clmd->sim_parms->time_scale = 1.0f; /* multiplies cloth speed */
- clmd->sim_parms->reset = 0;
-
- clmd->coll_parms->self_friction = 5.0;
- clmd->coll_parms->friction = 5.0;
- clmd->coll_parms->loop_count = 2;
- clmd->coll_parms->epsilon = 0.015f;
- clmd->coll_parms->flags = CLOTH_COLLSETTINGS_FLAG_ENABLED;
- clmd->coll_parms->collision_list = NULL;
- clmd->coll_parms->selfepsilon = 0.015;
- clmd->coll_parms->vgroup_selfcol = 0;
-
- /* These defaults are copied from softbody.c's
- * softbody_calc_forces() function.
- */
- clmd->sim_parms->eff_force_scale = 1000.0;
- clmd->sim_parms->eff_wind_scale = 250.0;
-
- // also from softbodies
- clmd->sim_parms->maxgoal = 1.0f;
- clmd->sim_parms->mingoal = 0.0f;
- clmd->sim_parms->defgoal = 0.0f;
- clmd->sim_parms->goalspring = 1.0f;
- clmd->sim_parms->goalfrict = 0.0f;
- clmd->sim_parms->velocity_smooth = 0.0f;
-
- clmd->sim_parms->voxel_cell_size = 0.1f;
-
- clmd->sim_parms->bending_model = CLOTH_BENDING_ANGULAR;
-
- if (!clmd->sim_parms->effector_weights)
- clmd->sim_parms->effector_weights = BKE_effector_add_weights(NULL);
-
- if (clmd->point_cache)
- clmd->point_cache->step = 1;
+ /* Initialize our new data structure to reasonable values. */
+ clmd->sim_parms->gravity[0] = 0.0;
+ clmd->sim_parms->gravity[1] = 0.0;
+ clmd->sim_parms->gravity[2] = -9.81;
+ clmd->sim_parms->tension = 15.0;
+ clmd->sim_parms->max_tension = 15.0;
+ clmd->sim_parms->compression = 15.0;
+ clmd->sim_parms->max_compression = 15.0;
+ clmd->sim_parms->shear = 5.0;
+ clmd->sim_parms->max_shear = 5.0;
+ clmd->sim_parms->bending = 0.5;
+ clmd->sim_parms->max_bend = 0.5;
+ clmd->sim_parms->tension_damp = 5.0;
+ clmd->sim_parms->compression_damp = 5.0;
+ clmd->sim_parms->shear_damp = 5.0;
+ clmd->sim_parms->bending_damping = 0.5;
+ clmd->sim_parms->Cvi = 1.0;
+ clmd->sim_parms->mass = 0.3f;
+ clmd->sim_parms->stepsPerFrame = 5;
+ clmd->sim_parms->flags = 0;
+ clmd->sim_parms->solver_type = 0;
+ clmd->sim_parms->maxspringlen = 10;
+ clmd->sim_parms->vgroup_mass = 0;
+ clmd->sim_parms->vgroup_shrink = 0;
+ clmd->sim_parms->shrink_min =
+ 0.0f; /* min amount the fabric will shrink by 0.0 = no shrinking, 1.0 = shrink to nothing*/
+ clmd->sim_parms->avg_spring_len = 0.0;
+ clmd->sim_parms->presets = 2; /* cotton as start setting */
+ clmd->sim_parms->timescale = 1.0f; /* speed factor, describes how fast cloth moves */
+ clmd->sim_parms->time_scale = 1.0f; /* multiplies cloth speed */
+ clmd->sim_parms->reset = 0;
+
+ clmd->coll_parms->self_friction = 5.0;
+ clmd->coll_parms->friction = 5.0;
+ clmd->coll_parms->loop_count = 2;
+ clmd->coll_parms->epsilon = 0.015f;
+ clmd->coll_parms->flags = CLOTH_COLLSETTINGS_FLAG_ENABLED;
+ clmd->coll_parms->collision_list = NULL;
+ clmd->coll_parms->selfepsilon = 0.015;
+ clmd->coll_parms->vgroup_selfcol = 0;
+
+ /* These defaults are copied from softbody.c's
+ * softbody_calc_forces() function.
+ */
+ clmd->sim_parms->eff_force_scale = 1000.0;
+ clmd->sim_parms->eff_wind_scale = 250.0;
+
+ // also from softbodies
+ clmd->sim_parms->maxgoal = 1.0f;
+ clmd->sim_parms->mingoal = 0.0f;
+ clmd->sim_parms->defgoal = 0.0f;
+ clmd->sim_parms->goalspring = 1.0f;
+ clmd->sim_parms->goalfrict = 0.0f;
+ clmd->sim_parms->velocity_smooth = 0.0f;
+
+ clmd->sim_parms->voxel_cell_size = 0.1f;
+
+ clmd->sim_parms->bending_model = CLOTH_BENDING_ANGULAR;
+
+ if (!clmd->sim_parms->effector_weights)
+ clmd->sim_parms->effector_weights = BKE_effector_add_weights(NULL);
+
+ if (clmd->point_cache)
+ clmd->point_cache->step = 1;
}
-static BVHTree *bvhtree_build_from_cloth (ClothModifierData *clmd, float epsilon)
+static BVHTree *bvhtree_build_from_cloth(ClothModifierData *clmd, float epsilon)
{
- unsigned int i;
- BVHTree *bvhtree;
- Cloth *cloth;
- ClothVertex *verts;
- const MVertTri *vt;
+ unsigned int i;
+ BVHTree *bvhtree;
+ Cloth *cloth;
+ ClothVertex *verts;
+ const MVertTri *vt;
- if (!clmd)
- return NULL;
+ if (!clmd)
+ return NULL;
- cloth = clmd->clothObject;
+ cloth = clmd->clothObject;
- if (!cloth)
- return NULL;
+ if (!cloth)
+ return NULL;
- verts = cloth->verts;
- vt = cloth->tri;
+ verts = cloth->verts;
+ vt = cloth->tri;
- /* in the moment, return zero if no faces there */
- if (!cloth->tri_num)
- return NULL;
+ /* in the moment, return zero if no faces there */
+ if (!cloth->tri_num)
+ return NULL;
- /* create quadtree with k=26 */
- bvhtree = BLI_bvhtree_new(cloth->tri_num, epsilon, 4, 26);
+ /* create quadtree with k=26 */
+ bvhtree = BLI_bvhtree_new(cloth->tri_num, epsilon, 4, 26);
- /* fill tree */
- for (i = 0; i < cloth->tri_num; i++, vt++) {
- float co[3][3];
+ /* fill tree */
+ for (i = 0; i < cloth->tri_num; i++, vt++) {
+ float co[3][3];
- copy_v3_v3(co[0], verts[vt->tri[0]].xold);
- copy_v3_v3(co[1], verts[vt->tri[1]].xold);
- copy_v3_v3(co[2], verts[vt->tri[2]].xold);
+ copy_v3_v3(co[0], verts[vt->tri[0]].xold);
+ copy_v3_v3(co[1], verts[vt->tri[1]].xold);
+ copy_v3_v3(co[2], verts[vt->tri[2]].xold);
- BLI_bvhtree_insert(bvhtree, i, co[0], 3);
- }
+ BLI_bvhtree_insert(bvhtree, i, co[0], 3);
+ }
- /* balance tree */
- BLI_bvhtree_balance(bvhtree);
+ /* balance tree */
+ BLI_bvhtree_balance(bvhtree);
- return bvhtree;
+ return bvhtree;
}
void bvhtree_update_from_cloth(ClothModifierData *clmd, bool moving, bool self)
{
- unsigned int i = 0;
- Cloth *cloth = clmd->clothObject;
- BVHTree *bvhtree;
- ClothVertex *verts = cloth->verts;
- const MVertTri *vt;
-
- if (self) {
- bvhtree = cloth->bvhselftree;
- }
- else {
- bvhtree = cloth->bvhtree;
- }
-
- if (!bvhtree)
- return;
-
- vt = cloth->tri;
-
- /* update vertex position in bvh tree */
- if (verts && vt) {
- for (i = 0; i < cloth->tri_num; i++, vt++) {
- float co[3][3], co_moving[3][3];
- bool ret;
-
- /* copy new locations into array */
- if (moving) {
- copy_v3_v3(co[0], verts[vt->tri[0]].txold);
- copy_v3_v3(co[1], verts[vt->tri[1]].txold);
- copy_v3_v3(co[2], verts[vt->tri[2]].txold);
-
- /* update moving positions */
- copy_v3_v3(co_moving[0], verts[vt->tri[0]].tx);
- copy_v3_v3(co_moving[1], verts[vt->tri[1]].tx);
- copy_v3_v3(co_moving[2], verts[vt->tri[2]].tx);
-
- ret = BLI_bvhtree_update_node(bvhtree, i, co[0], co_moving[0], 3);
- }
- else {
- copy_v3_v3(co[0], verts[vt->tri[0]].tx);
- copy_v3_v3(co[1], verts[vt->tri[1]].tx);
- copy_v3_v3(co[2], verts[vt->tri[2]].tx);
-
- ret = BLI_bvhtree_update_node(bvhtree, i, co[0], NULL, 3);
- }
-
- /* check if tree is already full */
- if (ret == false) {
- break;
- }
- }
-
- BLI_bvhtree_update_tree(bvhtree);
- }
+ unsigned int i = 0;
+ Cloth *cloth = clmd->clothObject;
+ BVHTree *bvhtree;
+ ClothVertex *verts = cloth->verts;
+ const MVertTri *vt;
+
+ if (self) {
+ bvhtree = cloth->bvhselftree;
+ }
+ else {
+ bvhtree = cloth->bvhtree;
+ }
+
+ if (!bvhtree)
+ return;
+
+ vt = cloth->tri;
+
+ /* update vertex position in bvh tree */
+ if (verts && vt) {
+ for (i = 0; i < cloth->tri_num; i++, vt++) {
+ float co[3][3], co_moving[3][3];
+ bool ret;
+
+ /* copy new locations into array */
+ if (moving) {
+ copy_v3_v3(co[0], verts[vt->tri[0]].txold);
+ copy_v3_v3(co[1], verts[vt->tri[1]].txold);
+ copy_v3_v3(co[2], verts[vt->tri[2]].txold);
+
+ /* update moving positions */
+ copy_v3_v3(co_moving[0], verts[vt->tri[0]].tx);
+ copy_v3_v3(co_moving[1], verts[vt->tri[1]].tx);
+ copy_v3_v3(co_moving[2], verts[vt->tri[2]].tx);
+
+ ret = BLI_bvhtree_update_node(bvhtree, i, co[0], co_moving[0], 3);
+ }
+ else {
+ copy_v3_v3(co[0], verts[vt->tri[0]].tx);
+ copy_v3_v3(co[1], verts[vt->tri[1]].tx);
+ copy_v3_v3(co[2], verts[vt->tri[2]].tx);
+
+ ret = BLI_bvhtree_update_node(bvhtree, i, co[0], NULL, 3);
+ }
+
+ /* check if tree is already full */
+ if (ret == false) {
+ break;
+ }
+ }
+
+ BLI_bvhtree_update_tree(bvhtree);
+ }
}
void cloth_clear_cache(Object *ob, ClothModifierData *clmd, float framenr)
{
- PTCacheID pid;
+ PTCacheID pid;
- BKE_ptcache_id_from_cloth(&pid, ob, clmd);
+ BKE_ptcache_id_from_cloth(&pid, ob, clmd);
- // don't do anything as long as we're in editmode!
- if (pid.cache->edit && ob->mode & OB_MODE_PARTICLE_EDIT)
- return;
+ // don't do anything as long as we're in editmode!
+ if (pid.cache->edit && ob->mode & OB_MODE_PARTICLE_EDIT)
+ return;
- BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_AFTER, framenr);
+ BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_AFTER, framenr);
}
static int do_init_cloth(Object *ob, ClothModifierData *clmd, Mesh *result, int framenr)
{
- PointCache *cache;
+ PointCache *cache;
- cache= clmd->point_cache;
+ cache = clmd->point_cache;
- /* initialize simulation data if it didn't exist already */
- if (clmd->clothObject == NULL) {
- if (!cloth_from_object(ob, clmd, result, framenr, 1)) {
- BKE_ptcache_invalidate(cache);
- modifier_setError(&(clmd->modifier), "Can't initialize cloth");
- return 0;
- }
+ /* initialize simulation data if it didn't exist already */
+ if (clmd->clothObject == NULL) {
+ if (!cloth_from_object(ob, clmd, result, framenr, 1)) {
+ BKE_ptcache_invalidate(cache);
+ modifier_setError(&(clmd->modifier), "Can't initialize cloth");
+ return 0;
+ }
- if (clmd->clothObject == NULL) {
- BKE_ptcache_invalidate(cache);
- modifier_setError(&(clmd->modifier), "Null cloth object");
- return 0;
- }
+ if (clmd->clothObject == NULL) {
+ BKE_ptcache_invalidate(cache);
+ modifier_setError(&(clmd->modifier), "Null cloth object");
+ return 0;
+ }
- BKE_cloth_solver_set_positions(clmd);
+ BKE_cloth_solver_set_positions(clmd);
- clmd->clothObject->last_frame= MINFRAME-1;
- clmd->sim_parms->dt = 1.0f / clmd->sim_parms->stepsPerFrame;
- }
+ clmd->clothObject->last_frame = MINFRAME - 1;
+ clmd->sim_parms->dt = 1.0f / clmd->sim_parms->stepsPerFrame;
+ }
- return 1;
+ return 1;
}
-static int do_step_cloth(Depsgraph *depsgraph, Object *ob, ClothModifierData *clmd, Mesh *result, int framenr)
+static int do_step_cloth(
+ Depsgraph *depsgraph, Object *ob, ClothModifierData *clmd, Mesh *result, int framenr)
{
- ClothVertex *verts = NULL;
- Cloth *cloth;
- ListBase *effectors = NULL;
- MVert *mvert;
- unsigned int i = 0;
- int ret = 0;
+ ClothVertex *verts = NULL;
+ Cloth *cloth;
+ ListBase *effectors = NULL;
+ MVert *mvert;
+ unsigned int i = 0;
+ int ret = 0;
- /* simulate 1 frame forward */
- cloth = clmd->clothObject;
- verts = cloth->verts;
- mvert = result->mvert;
+ /* simulate 1 frame forward */
+ cloth = clmd->clothObject;
+ verts = cloth->verts;
+ mvert = result->mvert;
- /* force any pinned verts to their constrained location. */
- for (i = 0; i < clmd->clothObject->mvert_num; i++, verts++) {
- /* save the previous position. */
- copy_v3_v3(verts->xold, verts->xconst);
- copy_v3_v3(verts->txold, verts->x);
+ /* force any pinned verts to their constrained location. */
+ for (i = 0; i < clmd->clothObject->mvert_num; i++, verts++) {
+ /* save the previous position. */
+ copy_v3_v3(verts->xold, verts->xconst);
+ copy_v3_v3(verts->txold, verts->x);
- /* Get the current position. */
- copy_v3_v3(verts->xconst, mvert[i].co);
- mul_m4_v3(ob->obmat, verts->xconst);
- }
+ /* Get the current position. */
+ copy_v3_v3(verts->xconst, mvert[i].co);
+ mul_m4_v3(ob->obmat, verts->xconst);
+ }
- effectors = BKE_effectors_create(depsgraph, ob, NULL, clmd->sim_parms->effector_weights);
+ effectors = BKE_effectors_create(depsgraph, ob, NULL, clmd->sim_parms->effector_weights);
- if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH )
- cloth_update_verts ( ob, clmd, result );
+ if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH)
+ cloth_update_verts(ob, clmd, result);
- /* Support for dynamic vertex groups, changing from frame to frame */
- cloth_apply_vgroup ( clmd, result );
+ /* Support for dynamic vertex groups, changing from frame to frame */
+ cloth_apply_vgroup(clmd, result);
- if ((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH) ||
- (clmd->sim_parms->vgroup_shrink > 0) || (clmd->sim_parms->shrink_min > 0.0f))
- {
- cloth_update_spring_lengths ( clmd, result );
- }
+ if ((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH) ||
+ (clmd->sim_parms->vgroup_shrink > 0) || (clmd->sim_parms->shrink_min > 0.0f)) {
+ cloth_update_spring_lengths(clmd, result);
+ }
- cloth_update_springs( clmd );
+ cloth_update_springs(clmd);
- // TIMEIT_START(cloth_step)
+ // TIMEIT_START(cloth_step)
- /* call the solver. */
- ret = BPH_cloth_solve(depsgraph, ob, framenr, clmd, effectors);
+ /* call the solver. */
+ ret = BPH_cloth_solve(depsgraph, ob, framenr, clmd, effectors);
- // TIMEIT_END(cloth_step)
+ // TIMEIT_END(cloth_step)
- BKE_effectors_free(effectors);
+ BKE_effectors_free(effectors);
- // printf ( "%f\n", ( float ) tval() );
+ // printf ( "%f\n", ( float ) tval() );
- return ret;
+ return ret;
}
/************************************************
* clothModifier_do - main simulation function
************************************************/
-void clothModifier_do(ClothModifierData *clmd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *mesh, float (*vertexCos)[3])
+void clothModifier_do(ClothModifierData *clmd,
+ Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ Mesh *mesh,
+ float (*vertexCos)[3])
{
- PointCache *cache;
- PTCacheID pid;
- float timescale;
- int framenr, startframe, endframe;
- int cache_result;
-
- framenr = DEG_get_ctime(depsgraph);
- cache= clmd->point_cache;
-
- BKE_ptcache_id_from_cloth(&pid, ob, clmd);
- BKE_ptcache_id_time(&pid, scene, framenr, &startframe, &endframe, &timescale);
- clmd->sim_parms->timescale= timescale * clmd->sim_parms->time_scale;
-
- if (clmd->sim_parms->reset || (clmd->clothObject && mesh->totvert != clmd->clothObject->mvert_num)) {
- clmd->sim_parms->reset = 0;
- cache->flag |= PTCACHE_OUTDATED;
- BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
- BKE_ptcache_validate(cache, 0);
- cache->last_exact= 0;
- cache->flag &= ~PTCACHE_REDO_NEEDED;
- }
-
- /* simulation is only active during a specific period */
- if (framenr < startframe) {
- BKE_ptcache_invalidate(cache);
- return;
- }
- else if (framenr > endframe) {
- framenr= endframe;
- }
-
- /* initialize simulation data if it didn't exist already */
- if (!do_init_cloth(ob, clmd, mesh, framenr))
- return;
-
- if (framenr == startframe) {
- BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
- do_init_cloth(ob, clmd, mesh, framenr);
- BKE_ptcache_validate(cache, framenr);
- cache->flag &= ~PTCACHE_REDO_NEEDED;
- clmd->clothObject->last_frame= framenr;
- return;
- }
-
- /* try to read from cache */
- bool can_simulate = (framenr == clmd->clothObject->last_frame+1) && !(cache->flag & PTCACHE_BAKED);
-
- cache_result = BKE_ptcache_read(&pid, (float)framenr+scene->r.subframe, can_simulate);
-
- if (cache_result == PTCACHE_READ_EXACT || cache_result == PTCACHE_READ_INTERPOLATED ||
- (!can_simulate && cache_result == PTCACHE_READ_OLD))
- {
- BKE_cloth_solver_set_positions(clmd);
- cloth_to_object (ob, clmd, vertexCos);
-
- BKE_ptcache_validate(cache, framenr);
-
- if (cache_result == PTCACHE_READ_INTERPOLATED && cache->flag & PTCACHE_REDO_NEEDED)
- BKE_ptcache_write(&pid, framenr);
-
- clmd->clothObject->last_frame= framenr;
-
- return;
- }
- else if (cache_result==PTCACHE_READ_OLD) {
- BKE_cloth_solver_set_positions(clmd);
- }
- else if ( /*ob->id.lib ||*/ (cache->flag & PTCACHE_BAKED)) { /* 2.4x disabled lib, but this can be used in some cases, testing further - campbell */
- /* if baked and nothing in cache, do nothing */
- BKE_ptcache_invalidate(cache);
- return;
- }
-
- /* if on second frame, write cache for first frame */
- if (cache->simframe == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact==0))
- BKE_ptcache_write(&pid, startframe);
-
- clmd->sim_parms->timescale *= framenr - cache->simframe;
-
- /* do simulation */
- BKE_ptcache_validate(cache, framenr);
-
- if (!do_step_cloth(depsgraph, ob, clmd, mesh, framenr)) {
- BKE_ptcache_invalidate(cache);
- }
- else
- BKE_ptcache_write(&pid, framenr);
-
- cloth_to_object (ob, clmd, vertexCos);
- clmd->clothObject->last_frame= framenr;
+ PointCache *cache;
+ PTCacheID pid;
+ float timescale;
+ int framenr, startframe, endframe;
+ int cache_result;
+
+ framenr = DEG_get_ctime(depsgraph);
+ cache = clmd->point_cache;
+
+ BKE_ptcache_id_from_cloth(&pid, ob, clmd);
+ BKE_ptcache_id_time(&pid, scene, framenr, &startframe, &endframe, &timescale);
+ clmd->sim_parms->timescale = timescale * clmd->sim_parms->time_scale;
+
+ if (clmd->sim_parms->reset ||
+ (clmd->clothObject && mesh->totvert != clmd->clothObject->mvert_num)) {
+ clmd->sim_parms->reset = 0;
+ cache->flag |= PTCACHE_OUTDATED;
+ BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
+ BKE_ptcache_validate(cache, 0);
+ cache->last_exact = 0;
+ cache->flag &= ~PTCACHE_REDO_NEEDED;
+ }
+
+ /* simulation is only active during a specific period */
+ if (framenr < startframe) {
+ BKE_ptcache_invalidate(cache);
+ return;
+ }
+ else if (framenr > endframe) {
+ framenr = endframe;
+ }
+
+ /* initialize simulation data if it didn't exist already */
+ if (!do_init_cloth(ob, clmd, mesh, framenr))
+ return;
+
+ if (framenr == startframe) {
+ BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
+ do_init_cloth(ob, clmd, mesh, framenr);
+ BKE_ptcache_validate(cache, framenr);
+ cache->flag &= ~PTCACHE_REDO_NEEDED;
+ clmd->clothObject->last_frame = framenr;
+ return;
+ }
+
+ /* try to read from cache */
+ bool can_simulate = (framenr == clmd->clothObject->last_frame + 1) &&
+ !(cache->flag & PTCACHE_BAKED);
+
+ cache_result = BKE_ptcache_read(&pid, (float)framenr + scene->r.subframe, can_simulate);
+
+ if (cache_result == PTCACHE_READ_EXACT || cache_result == PTCACHE_READ_INTERPOLATED ||
+ (!can_simulate && cache_result == PTCACHE_READ_OLD)) {
+ BKE_cloth_solver_set_positions(clmd);
+ cloth_to_object(ob, clmd, vertexCos);
+
+ BKE_ptcache_validate(cache, framenr);
+
+ if (cache_result == PTCACHE_READ_INTERPOLATED && cache->flag & PTCACHE_REDO_NEEDED)
+ BKE_ptcache_write(&pid, framenr);
+
+ clmd->clothObject->last_frame = framenr;
+
+ return;
+ }
+ else if (cache_result == PTCACHE_READ_OLD) {
+ BKE_cloth_solver_set_positions(clmd);
+ }
+ else if (/*ob->id.lib ||*/ (
+ cache->flag &
+ PTCACHE_BAKED)) { /* 2.4x disabled lib, but this can be used in some cases, testing further - campbell */
+ /* if baked and nothing in cache, do nothing */
+ BKE_ptcache_invalidate(cache);
+ return;
+ }
+
+ /* if on second frame, write cache for first frame */
+ if (cache->simframe == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact == 0))
+ BKE_ptcache_write(&pid, startframe);
+
+ clmd->sim_parms->timescale *= framenr - cache->simframe;
+
+ /* do simulation */
+ BKE_ptcache_validate(cache, framenr);
+
+ if (!do_step_cloth(depsgraph, ob, clmd, mesh, framenr)) {
+ BKE_ptcache_invalidate(cache);
+ }
+ else
+ BKE_ptcache_write(&pid, framenr);
+
+ cloth_to_object(ob, clmd, vertexCos);
+ clmd->clothObject->last_frame = framenr;
}
/* frees all */
-void cloth_free_modifier(ClothModifierData *clmd )
+void cloth_free_modifier(ClothModifierData *clmd)
{
- Cloth *cloth = NULL;
-
- if ( !clmd )
- return;
+ Cloth *cloth = NULL;
- cloth = clmd->clothObject;
+ if (!clmd)
+ return;
+ cloth = clmd->clothObject;
- if ( cloth ) {
- BPH_cloth_solver_free(clmd);
+ if (cloth) {
+ BPH_cloth_solver_free(clmd);
- // Free the verts.
- if ( cloth->verts != NULL )
- MEM_freeN ( cloth->verts );
+ // Free the verts.
+ if (cloth->verts != NULL)
+ MEM_freeN(cloth->verts);
- cloth->verts = NULL;
- cloth->mvert_num = 0;
+ cloth->verts = NULL;
+ cloth->mvert_num = 0;
- // Free the springs.
- if ( cloth->springs != NULL ) {
- LinkNode *search = cloth->springs;
- while (search) {
- ClothSpring *spring = search->link;
+ // Free the springs.
+ if (cloth->springs != NULL) {
+ LinkNode *search = cloth->springs;
+ while (search) {
+ ClothSpring *spring = search->link;
- MEM_SAFE_FREE(spring->pa);
- MEM_SAFE_FREE(spring->pb);
+ MEM_SAFE_FREE(spring->pa);
+ MEM_SAFE_FREE(spring->pb);
- MEM_freeN ( spring );
- search = search->next;
- }
- BLI_linklist_free(cloth->springs, NULL);
+ MEM_freeN(spring);
+ search = search->next;
+ }
+ BLI_linklist_free(cloth->springs, NULL);
- cloth->springs = NULL;
- }
+ cloth->springs = NULL;
+ }
- cloth->springs = NULL;
- cloth->numsprings = 0;
+ cloth->springs = NULL;
+ cloth->numsprings = 0;
- // free BVH collision tree
- if ( cloth->bvhtree )
- BLI_bvhtree_free ( cloth->bvhtree );
+ // free BVH collision tree
+ if (cloth->bvhtree)
+ BLI_bvhtree_free(cloth->bvhtree);
- if ( cloth->bvhselftree )
- BLI_bvhtree_free ( cloth->bvhselftree );
+ if (cloth->bvhselftree)
+ BLI_bvhtree_free(cloth->bvhselftree);
- // we save our faces for collision objects
- if (cloth->tri)
- MEM_freeN(cloth->tri);
+ // we save our faces for collision objects
+ if (cloth->tri)
+ MEM_freeN(cloth->tri);
- if (cloth->edgeset)
- BLI_edgeset_free(cloth->edgeset);
+ if (cloth->edgeset)
+ BLI_edgeset_free(cloth->edgeset);
#if 0
- if (clmd->clothObject->facemarks) {
- MEM_freeN(clmd->clothObject->facemarks);
- }
+ if (clmd->clothObject->facemarks) {
+ MEM_freeN(clmd->clothObject->facemarks);
+ }
#endif
- MEM_freeN ( cloth );
- clmd->clothObject = NULL;
- }
+ MEM_freeN(cloth);
+ clmd->clothObject = NULL;
+ }
}
/* frees all */
-void cloth_free_modifier_extern(ClothModifierData *clmd )
+void cloth_free_modifier_extern(ClothModifierData *clmd)
{
- Cloth *cloth = NULL;
- if (G.debug & G_DEBUG_SIMDATA) {
- printf("cloth_free_modifier_extern\n");
- }
-
- if ( !clmd )
- return;
+ Cloth *cloth = NULL;
+ if (G.debug & G_DEBUG_SIMDATA) {
+ printf("cloth_free_modifier_extern\n");
+ }
- cloth = clmd->clothObject;
+ if (!clmd)
+ return;
- if ( cloth ) {
- if (G.debug & G_DEBUG_SIMDATA) {
- printf("cloth_free_modifier_extern in\n");
- }
+ cloth = clmd->clothObject;
- BPH_cloth_solver_free(clmd);
+ if (cloth) {
+ if (G.debug & G_DEBUG_SIMDATA) {
+ printf("cloth_free_modifier_extern in\n");
+ }
- // Free the verts.
- if ( cloth->verts != NULL )
- MEM_freeN ( cloth->verts );
+ BPH_cloth_solver_free(clmd);
- cloth->verts = NULL;
- cloth->mvert_num = 0;
+ // Free the verts.
+ if (cloth->verts != NULL)
+ MEM_freeN(cloth->verts);
- // Free the springs.
- if ( cloth->springs != NULL ) {
- LinkNode *search = cloth->springs;
- while (search) {
- ClothSpring *spring = search->link;
+ cloth->verts = NULL;
+ cloth->mvert_num = 0;
- MEM_SAFE_FREE(spring->pa);
- MEM_SAFE_FREE(spring->pb);
+ // Free the springs.
+ if (cloth->springs != NULL) {
+ LinkNode *search = cloth->springs;
+ while (search) {
+ ClothSpring *spring = search->link;
- MEM_freeN ( spring );
- search = search->next;
- }
- BLI_linklist_free(cloth->springs, NULL);
+ MEM_SAFE_FREE(spring->pa);
+ MEM_SAFE_FREE(spring->pb);
- cloth->springs = NULL;
- }
+ MEM_freeN(spring);
+ search = search->next;
+ }
+ BLI_linklist_free(cloth->springs, NULL);
- cloth->springs = NULL;
- cloth->numsprings = 0;
+ cloth->springs = NULL;
+ }
- // free BVH collision tree
- if ( cloth->bvhtree )
- BLI_bvhtree_free ( cloth->bvhtree );
+ cloth->springs = NULL;
+ cloth->numsprings = 0;
- if ( cloth->bvhselftree )
- BLI_bvhtree_free ( cloth->bvhselftree );
+ // free BVH collision tree
+ if (cloth->bvhtree)
+ BLI_bvhtree_free(cloth->bvhtree);
- // we save our faces for collision objects
- if (cloth->tri)
- MEM_freeN(cloth->tri);
+ if (cloth->bvhselftree)
+ BLI_bvhtree_free(cloth->bvhselftree);
- if (cloth->edgeset)
- BLI_edgeset_free(cloth->edgeset);
+ // we save our faces for collision objects
+ if (cloth->tri)
+ MEM_freeN(cloth->tri);
+ if (cloth->edgeset)
+ BLI_edgeset_free(cloth->edgeset);
#if 0
- if (clmd->clothObject->facemarks) {
- MEM_freeN(clmd->clothObject->facemarks);
- }
+ if (clmd->clothObject->facemarks) {
+ MEM_freeN(clmd->clothObject->facemarks);
+ }
#endif
- MEM_freeN ( cloth );
- clmd->clothObject = NULL;
- }
+ MEM_freeN(cloth);
+ clmd->clothObject = NULL;
+ }
}
/******************************************************************************
@@ -586,268 +593,269 @@ void cloth_free_modifier_extern(ClothModifierData *clmd )
/**
* Copies the deformed vertices to the object.
*/
-static void cloth_to_object (Object *ob, ClothModifierData *clmd, float (*vertexCos)[3])
+static void cloth_to_object(Object *ob, ClothModifierData *clmd, float (*vertexCos)[3])
{
- unsigned int i = 0;
- Cloth *cloth = clmd->clothObject;
-
- if (clmd->clothObject) {
- /* inverse matrix is not uptodate... */
- invert_m4_m4(ob->imat, ob->obmat);
-
- for (i = 0; i < cloth->mvert_num; i++) {
- copy_v3_v3 (vertexCos[i], cloth->verts[i].x);
- mul_m4_v3(ob->imat, vertexCos[i]); /* cloth is in global coords */
- }
- }
+ unsigned int i = 0;
+ Cloth *cloth = clmd->clothObject;
+
+ if (clmd->clothObject) {
+ /* inverse matrix is not uptodate... */
+ invert_m4_m4(ob->imat, ob->obmat);
+
+ for (i = 0; i < cloth->mvert_num; i++) {
+ copy_v3_v3(vertexCos[i], cloth->verts[i].x);
+ mul_m4_v3(ob->imat, vertexCos[i]); /* cloth is in global coords */
+ }
+ }
}
-
int cloth_uses_vgroup(ClothModifierData *clmd)
{
- return (((clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF) && (clmd->coll_parms->vgroup_selfcol > 0)) ||
- (clmd->sim_parms->vgroup_struct > 0) ||
- (clmd->sim_parms->vgroup_bend > 0) ||
- (clmd->sim_parms->vgroup_shrink > 0) ||
- (clmd->sim_parms->vgroup_mass > 0));
+ return (((clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF) &&
+ (clmd->coll_parms->vgroup_selfcol > 0)) ||
+ (clmd->sim_parms->vgroup_struct > 0) || (clmd->sim_parms->vgroup_bend > 0) ||
+ (clmd->sim_parms->vgroup_shrink > 0) || (clmd->sim_parms->vgroup_mass > 0));
}
/**
* Applies a vertex group as specified by type.
*/
-static void cloth_apply_vgroup ( ClothModifierData *clmd, Mesh *mesh )
+static void cloth_apply_vgroup(ClothModifierData *clmd, Mesh *mesh)
{
- /* Can be optimized to do all groups in one loop. */
- int i = 0;
- int j = 0;
- MDeformVert *dvert = NULL;
- Cloth *clothObj = NULL;
- int mvert_num;
- /* float goalfac = 0; */ /* UNUSED */
- ClothVertex *verts = NULL;
-
- if (!clmd || !mesh) return;
-
- clothObj = clmd->clothObject;
-
- mvert_num = mesh->totvert;
-
- verts = clothObj->verts;
-
- if (cloth_uses_vgroup(clmd)) {
- for (i = 0; i < mvert_num; i++, verts++) {
-
- /* Reset Goal values to standard */
- if (clmd->sim_parms->vgroup_mass > 0)
- verts->goal= clmd->sim_parms->defgoal;
- else
- verts->goal= 0.0f;
-
- /* Compute base cloth shrink weight */
- verts->shrink_factor = 0.0f;
-
- /* Reset vertex flags */
- verts->flags &= ~CLOTH_VERT_FLAG_PINNED;
- verts->flags &= ~CLOTH_VERT_FLAG_NOSELFCOLL;
-
- dvert = CustomData_get(&mesh->vdata, i, CD_MDEFORMVERT);
- if ( dvert ) {
- for ( j = 0; j < dvert->totweight; j++ ) {
- if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_mass - 1)) {
- verts->goal = dvert->dw [j].weight;
-
- /* goalfac= 1.0f; */ /* UNUSED */
-
- // Kicking goal factor to simplify things...who uses that anyway?
- // ABS ( clmd->sim_parms->maxgoal - clmd->sim_parms->mingoal );
-
- verts->goal = pow4f(verts->goal);
- if ( verts->goal >= SOFTGOALSNAP )
- verts->flags |= CLOTH_VERT_FLAG_PINNED;
- }
-
- if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_struct - 1)) {
- verts->struct_stiff = dvert->dw[j].weight;
- }
-
- if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_shear - 1)) {
- verts->shear_stiff = dvert->dw[j].weight;
- }
-
- if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_bend - 1)) {
- verts->bend_stiff = dvert->dw[j].weight;
- }
-
- if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF ) {
- if ( dvert->dw[j].def_nr == (clmd->coll_parms->vgroup_selfcol-1)) {
- if (dvert->dw [j].weight > 0.0f) {
- verts->flags |= CLOTH_VERT_FLAG_NOSELFCOLL;
- }
- }
- }
- if (clmd->sim_parms->vgroup_shrink > 0) {
- if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_shrink - 1)) {
- /* Used for linear interpolation between min and max shrink factor based on weight. */
- verts->shrink_factor = dvert->dw[j].weight;
- }
- }
- }
- }
- }
- }
+ /* Can be optimized to do all groups in one loop. */
+ int i = 0;
+ int j = 0;
+ MDeformVert *dvert = NULL;
+ Cloth *clothObj = NULL;
+ int mvert_num;
+ /* float goalfac = 0; */ /* UNUSED */
+ ClothVertex *verts = NULL;
+
+ if (!clmd || !mesh)
+ return;
+
+ clothObj = clmd->clothObject;
+
+ mvert_num = mesh->totvert;
+
+ verts = clothObj->verts;
+
+ if (cloth_uses_vgroup(clmd)) {
+ for (i = 0; i < mvert_num; i++, verts++) {
+
+ /* Reset Goal values to standard */
+ if (clmd->sim_parms->vgroup_mass > 0)
+ verts->goal = clmd->sim_parms->defgoal;
+ else
+ verts->goal = 0.0f;
+
+ /* Compute base cloth shrink weight */
+ verts->shrink_factor = 0.0f;
+
+ /* Reset vertex flags */
+ verts->flags &= ~CLOTH_VERT_FLAG_PINNED;
+ verts->flags &= ~CLOTH_VERT_FLAG_NOSELFCOLL;
+
+ dvert = CustomData_get(&mesh->vdata, i, CD_MDEFORMVERT);
+ if (dvert) {
+ for (j = 0; j < dvert->totweight; j++) {
+ if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_mass - 1)) {
+ verts->goal = dvert->dw[j].weight;
+
+ /* goalfac= 1.0f; */ /* UNUSED */
+
+ // Kicking goal factor to simplify things...who uses that anyway?
+ // ABS ( clmd->sim_parms->maxgoal - clmd->sim_parms->mingoal );
+
+ verts->goal = pow4f(verts->goal);
+ if (verts->goal >= SOFTGOALSNAP)
+ verts->flags |= CLOTH_VERT_FLAG_PINNED;
+ }
+
+ if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_struct - 1)) {
+ verts->struct_stiff = dvert->dw[j].weight;
+ }
+
+ if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_shear - 1)) {
+ verts->shear_stiff = dvert->dw[j].weight;
+ }
+
+ if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_bend - 1)) {
+ verts->bend_stiff = dvert->dw[j].weight;
+ }
+
+ if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF) {
+ if (dvert->dw[j].def_nr == (clmd->coll_parms->vgroup_selfcol - 1)) {
+ if (dvert->dw[j].weight > 0.0f) {
+ verts->flags |= CLOTH_VERT_FLAG_NOSELFCOLL;
+ }
+ }
+ }
+ if (clmd->sim_parms->vgroup_shrink > 0) {
+ if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_shrink - 1)) {
+ /* Used for linear interpolation between min and max shrink factor based on weight. */
+ verts->shrink_factor = dvert->dw[j].weight;
+ }
+ }
+ }
+ }
+ }
+ }
}
static float cloth_shrink_factor(ClothModifierData *clmd, ClothVertex *verts, int i1, int i2)
{
- /* Linear interpolation between min and max shrink factor based on weight. */
- float base = 1.0f - clmd->sim_parms->shrink_min;
- float delta = clmd->sim_parms->shrink_min - clmd->sim_parms->shrink_max;
+ /* Linear interpolation between min and max shrink factor based on weight. */
+ float base = 1.0f - clmd->sim_parms->shrink_min;
+ float delta = clmd->sim_parms->shrink_min - clmd->sim_parms->shrink_max;
- float k1 = base + delta * verts[i1].shrink_factor;
- float k2 = base + delta * verts[i2].shrink_factor;
+ float k1 = base + delta * verts[i1].shrink_factor;
+ float k2 = base + delta * verts[i2].shrink_factor;
- /* Use geometrical mean to average two factors since it behaves better
- for diagonals when a rectangle transforms into a trapezoid. */
- return sqrtf(k1 * k2);
+ /* Use geometrical mean to average two factors since it behaves better
+ for diagonals when a rectangle transforms into a trapezoid. */
+ return sqrtf(k1 * k2);
}
-static int cloth_from_object(Object *ob, ClothModifierData *clmd, Mesh *mesh, float UNUSED(framenr), int first)
+static int cloth_from_object(
+ Object *ob, ClothModifierData *clmd, Mesh *mesh, float UNUSED(framenr), int first)
{
- int i = 0;
- MVert *mvert = NULL;
- ClothVertex *verts = NULL;
- float (*shapekey_rest)[3] = NULL;
- float tnull[3] = {0, 0, 0};
-
- // If we have a clothObject, free it.
- if ( clmd->clothObject != NULL ) {
- cloth_free_modifier ( clmd );
- if (G.debug & G_DEBUG_SIMDATA) {
- printf("cloth_free_modifier cloth_from_object\n");
- }
- }
-
- // Allocate a new cloth object.
- clmd->clothObject = MEM_callocN ( sizeof ( Cloth ), "cloth" );
- if ( clmd->clothObject ) {
- clmd->clothObject->old_solver_type = 255;
- clmd->clothObject->edgeset = NULL;
- }
- else if (!clmd->clothObject) {
- modifier_setError(&(clmd->modifier), "Out of memory on allocating clmd->clothObject");
- return 0;
- }
-
- // mesh input objects need Mesh
- if ( !mesh )
- return 0;
-
- cloth_from_mesh ( clmd, mesh );
-
- // create springs
- clmd->clothObject->springs = NULL;
- clmd->clothObject->numsprings = -1;
-
- if ( clmd->sim_parms->shapekey_rest && !(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH ) )
- shapekey_rest = CustomData_get_layer(&mesh->vdata, CD_CLOTH_ORCO);
-
- mvert = mesh->mvert;
-
- verts = clmd->clothObject->verts;
-
- // set initial values
- for ( i = 0; i < mesh->totvert; i++, verts++ ) {
- if (first) {
- copy_v3_v3(verts->x, mvert[i].co);
-
- mul_m4_v3(ob->obmat, verts->x);
-
- if ( shapekey_rest ) {
- copy_v3_v3(verts->xrest, shapekey_rest[i]);
- mul_m4_v3(ob->obmat, verts->xrest);
- }
- else
- copy_v3_v3(verts->xrest, verts->x);
- }
-
- /* no GUI interface yet */
- verts->mass = clmd->sim_parms->mass;
- verts->impulse_count = 0;
-
- if (clmd->sim_parms->vgroup_mass > 0)
- verts->goal= clmd->sim_parms->defgoal;
- else
- verts->goal= 0.0f;
-
- verts->shrink_factor = 0.0f;
-
- verts->flags = 0;
- copy_v3_v3 ( verts->xold, verts->x );
- copy_v3_v3 ( verts->xconst, verts->x );
- copy_v3_v3 ( verts->txold, verts->x );
- copy_v3_v3 ( verts->tx, verts->x );
- mul_v3_fl(verts->v, 0.0f);
-
- verts->impulse_count = 0;
- copy_v3_v3 ( verts->impulse, tnull );
- }
-
- // apply / set vertex groups
- // has to be happen before springs are build!
- cloth_apply_vgroup (clmd, mesh);
-
- if ( !cloth_build_springs ( clmd, mesh ) ) {
- cloth_free_modifier ( clmd );
- modifier_setError(&(clmd->modifier), "Cannot build springs");
- return 0;
- }
-
- // init our solver
- BPH_cloth_solver_init(ob, clmd);
-
- if (!first)
- BKE_cloth_solver_set_positions(clmd);
-
- clmd->clothObject->bvhtree = bvhtree_build_from_cloth (clmd, clmd->coll_parms->epsilon);
- clmd->clothObject->bvhselftree = bvhtree_build_from_cloth(clmd, clmd->coll_parms->selfepsilon);
-
- return 1;
+ int i = 0;
+ MVert *mvert = NULL;
+ ClothVertex *verts = NULL;
+ float(*shapekey_rest)[3] = NULL;
+ float tnull[3] = {0, 0, 0};
+
+ // If we have a clothObject, free it.
+ if (clmd->clothObject != NULL) {
+ cloth_free_modifier(clmd);
+ if (G.debug & G_DEBUG_SIMDATA) {
+ printf("cloth_free_modifier cloth_from_object\n");
+ }
+ }
+
+ // Allocate a new cloth object.
+ clmd->clothObject = MEM_callocN(sizeof(Cloth), "cloth");
+ if (clmd->clothObject) {
+ clmd->clothObject->old_solver_type = 255;
+ clmd->clothObject->edgeset = NULL;
+ }
+ else if (!clmd->clothObject) {
+ modifier_setError(&(clmd->modifier), "Out of memory on allocating clmd->clothObject");
+ return 0;
+ }
+
+ // mesh input objects need Mesh
+ if (!mesh)
+ return 0;
+
+ cloth_from_mesh(clmd, mesh);
+
+ // create springs
+ clmd->clothObject->springs = NULL;
+ clmd->clothObject->numsprings = -1;
+
+ if (clmd->sim_parms->shapekey_rest &&
+ !(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH))
+ shapekey_rest = CustomData_get_layer(&mesh->vdata, CD_CLOTH_ORCO);
+
+ mvert = mesh->mvert;
+
+ verts = clmd->clothObject->verts;
+
+ // set initial values
+ for (i = 0; i < mesh->totvert; i++, verts++) {
+ if (first) {
+ copy_v3_v3(verts->x, mvert[i].co);
+
+ mul_m4_v3(ob->obmat, verts->x);
+
+ if (shapekey_rest) {
+ copy_v3_v3(verts->xrest, shapekey_rest[i]);
+ mul_m4_v3(ob->obmat, verts->xrest);
+ }
+ else
+ copy_v3_v3(verts->xrest, verts->x);
+ }
+
+ /* no GUI interface yet */
+ verts->mass = clmd->sim_parms->mass;
+ verts->impulse_count = 0;
+
+ if (clmd->sim_parms->vgroup_mass > 0)
+ verts->goal = clmd->sim_parms->defgoal;
+ else
+ verts->goal = 0.0f;
+
+ verts->shrink_factor = 0.0f;
+
+ verts->flags = 0;
+ copy_v3_v3(verts->xold, verts->x);
+ copy_v3_v3(verts->xconst, verts->x);
+ copy_v3_v3(verts->txold, verts->x);
+ copy_v3_v3(verts->tx, verts->x);
+ mul_v3_fl(verts->v, 0.0f);
+
+ verts->impulse_count = 0;
+ copy_v3_v3(verts->impulse, tnull);
+ }
+
+ // apply / set vertex groups
+ // has to be happen before springs are build!
+ cloth_apply_vgroup(clmd, mesh);
+
+ if (!cloth_build_springs(clmd, mesh)) {
+ cloth_free_modifier(clmd);
+ modifier_setError(&(clmd->modifier), "Cannot build springs");
+ return 0;
+ }
+
+ // init our solver
+ BPH_cloth_solver_init(ob, clmd);
+
+ if (!first)
+ BKE_cloth_solver_set_positions(clmd);
+
+ clmd->clothObject->bvhtree = bvhtree_build_from_cloth(clmd, clmd->coll_parms->epsilon);
+ clmd->clothObject->bvhselftree = bvhtree_build_from_cloth(clmd, clmd->coll_parms->selfepsilon);
+
+ return 1;
}
-static void cloth_from_mesh ( ClothModifierData *clmd, Mesh *mesh )
+static void cloth_from_mesh(ClothModifierData *clmd, Mesh *mesh)
{
- const MLoop *mloop = mesh->mloop;
- const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(mesh);
- const unsigned int mvert_num = mesh->totvert;
- const unsigned int looptri_num = mesh->runtime.looptris.len;
-
- /* Allocate our vertices. */
- clmd->clothObject->mvert_num = mvert_num;
- clmd->clothObject->verts = MEM_callocN(sizeof(ClothVertex) * clmd->clothObject->mvert_num, "clothVertex");
- if (clmd->clothObject->verts == NULL) {
- cloth_free_modifier(clmd);
- modifier_setError(&(clmd->modifier), "Out of memory on allocating clmd->clothObject->verts");
- printf("cloth_free_modifier clmd->clothObject->verts\n");
- return;
- }
-
- /* save face information */
- clmd->clothObject->tri_num = looptri_num;
- clmd->clothObject->tri = MEM_mallocN(sizeof(MVertTri) * looptri_num, "clothLoopTris");
- if (clmd->clothObject->tri == NULL) {
- cloth_free_modifier(clmd);
- modifier_setError(&(clmd->modifier), "Out of memory on allocating clmd->clothObject->looptri");
- printf("cloth_free_modifier clmd->clothObject->looptri\n");
- return;
- }
- BKE_mesh_runtime_verttri_from_looptri(clmd->clothObject->tri, mloop, looptri, looptri_num);
-
- /* Free the springs since they can't be correct if the vertices
- * changed.
- */
- if ( clmd->clothObject->springs != NULL )
- MEM_freeN ( clmd->clothObject->springs );
-
+ const MLoop *mloop = mesh->mloop;
+ const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ const unsigned int mvert_num = mesh->totvert;
+ const unsigned int looptri_num = mesh->runtime.looptris.len;
+
+ /* Allocate our vertices. */
+ clmd->clothObject->mvert_num = mvert_num;
+ clmd->clothObject->verts = MEM_callocN(sizeof(ClothVertex) * clmd->clothObject->mvert_num,
+ "clothVertex");
+ if (clmd->clothObject->verts == NULL) {
+ cloth_free_modifier(clmd);
+ modifier_setError(&(clmd->modifier), "Out of memory on allocating clmd->clothObject->verts");
+ printf("cloth_free_modifier clmd->clothObject->verts\n");
+ return;
+ }
+
+ /* save face information */
+ clmd->clothObject->tri_num = looptri_num;
+ clmd->clothObject->tri = MEM_mallocN(sizeof(MVertTri) * looptri_num, "clothLoopTris");
+ if (clmd->clothObject->tri == NULL) {
+ cloth_free_modifier(clmd);
+ modifier_setError(&(clmd->modifier), "Out of memory on allocating clmd->clothObject->looptri");
+ printf("cloth_free_modifier clmd->clothObject->looptri\n");
+ return;
+ }
+ BKE_mesh_runtime_verttri_from_looptri(clmd->clothObject->tri, mloop, looptri, looptri_num);
+
+ /* Free the springs since they can't be correct if the vertices
+ * changed.
+ */
+ if (clmd->clothObject->springs != NULL)
+ MEM_freeN(clmd->clothObject->springs);
}
/***************************************************************************************
@@ -856,790 +864,836 @@ static void cloth_from_mesh ( ClothModifierData *clmd, Mesh *mesh )
BLI_INLINE void spring_verts_ordered_set(ClothSpring *spring, int v0, int v1)
{
- if (v0 < v1) {
- spring->ij = v0;
- spring->kl = v1;
- }
- else {
- spring->ij = v1;
- spring->kl = v0;
- }
+ if (v0 < v1) {
+ spring->ij = v0;
+ spring->kl = v1;
+ }
+ else {
+ spring->ij = v1;
+ spring->kl = v0;
+ }
}
static void cloth_free_edgelist(LinkNodePair *edgelist, unsigned int mvert_num)
{
- if (edgelist) {
- unsigned int i;
- for (i = 0; i < mvert_num; i++) {
- BLI_linklist_free(edgelist[i].list, NULL);
- }
-
- MEM_freeN(edgelist);
- }
+ if (edgelist) {
+ unsigned int i;
+ for (i = 0; i < mvert_num; i++) {
+ BLI_linklist_free(edgelist[i].list, NULL);
+ }
+
+ MEM_freeN(edgelist);
+ }
}
-static void cloth_free_errorsprings(Cloth *cloth, LinkNodePair *edgelist, BendSpringRef *spring_ref)
+static void cloth_free_errorsprings(Cloth *cloth,
+ LinkNodePair *edgelist,
+ BendSpringRef *spring_ref)
{
- if ( cloth->springs != NULL ) {
- LinkNode *search = cloth->springs;
- while (search) {
- ClothSpring *spring = search->link;
+ if (cloth->springs != NULL) {
+ LinkNode *search = cloth->springs;
+ while (search) {
+ ClothSpring *spring = search->link;
- MEM_SAFE_FREE(spring->pa);
- MEM_SAFE_FREE(spring->pb);
+ MEM_SAFE_FREE(spring->pa);
+ MEM_SAFE_FREE(spring->pb);
- MEM_freeN ( spring );
- search = search->next;
- }
- BLI_linklist_free(cloth->springs, NULL);
+ MEM_freeN(spring);
+ search = search->next;
+ }
+ BLI_linklist_free(cloth->springs, NULL);
- cloth->springs = NULL;
- }
+ cloth->springs = NULL;
+ }
- cloth_free_edgelist(edgelist, cloth->mvert_num);
+ cloth_free_edgelist(edgelist, cloth->mvert_num);
- MEM_SAFE_FREE(spring_ref);
+ MEM_SAFE_FREE(spring_ref);
- if (cloth->edgeset) {
- BLI_edgeset_free(cloth->edgeset);
- cloth->edgeset = NULL;
- }
+ if (cloth->edgeset) {
+ BLI_edgeset_free(cloth->edgeset);
+ cloth->edgeset = NULL;
+ }
}
-BLI_INLINE void cloth_bend_poly_dir(ClothVertex *verts, int i, int j, int *inds, int len, float r_dir[3])
+BLI_INLINE void cloth_bend_poly_dir(
+ ClothVertex *verts, int i, int j, int *inds, int len, float r_dir[3])
{
- float cent[3] = {0};
- float fact = 1.0f / len;
+ float cent[3] = {0};
+ float fact = 1.0f / len;
- for (int x = 0; x < len; x++) {
- madd_v3_v3fl(cent, verts[inds[x]].xrest, fact);
- }
+ for (int x = 0; x < len; x++) {
+ madd_v3_v3fl(cent, verts[inds[x]].xrest, fact);
+ }
- normal_tri_v3(r_dir, verts[i].xrest, verts[j].xrest, cent);
+ normal_tri_v3(r_dir, verts[i].xrest, verts[j].xrest, cent);
}
-static float cloth_spring_angle(ClothVertex *verts, int i, int j, int *i_a, int *i_b, int len_a, int len_b)
+static float cloth_spring_angle(
+ ClothVertex *verts, int i, int j, int *i_a, int *i_b, int len_a, int len_b)
{
- float dir_a[3], dir_b[3];
- float tmp[3], vec_e[3];
- float sin, cos;
+ float dir_a[3], dir_b[3];
+ float tmp[3], vec_e[3];
+ float sin, cos;
- /* Poly vectors. */
- cloth_bend_poly_dir(verts, j, i, i_a, len_a, dir_a);
- cloth_bend_poly_dir(verts, i, j, i_b, len_b, dir_b);
+ /* Poly vectors. */
+ cloth_bend_poly_dir(verts, j, i, i_a, len_a, dir_a);
+ cloth_bend_poly_dir(verts, i, j, i_b, len_b, dir_b);
- /* Edge vector. */
- sub_v3_v3v3(vec_e, verts[i].xrest, verts[j].xrest);
- normalize_v3(vec_e);
+ /* Edge vector. */
+ sub_v3_v3v3(vec_e, verts[i].xrest, verts[j].xrest);
+ normalize_v3(vec_e);
- /* Compute angle. */
- cos = dot_v3v3(dir_a, dir_b);
+ /* Compute angle. */
+ cos = dot_v3v3(dir_a, dir_b);
- cross_v3_v3v3(tmp, dir_a, dir_b);
- sin = dot_v3v3(tmp, vec_e);
+ cross_v3_v3v3(tmp, dir_a, dir_b);
+ sin = dot_v3v3(tmp, vec_e);
- return atan2f(sin, cos);
+ return atan2f(sin, cos);
}
static void cloth_hair_update_bending_targets(ClothModifierData *clmd)
{
- Cloth *cloth = clmd->clothObject;
- LinkNode *search = NULL;
- float hair_frame[3][3], dir_old[3], dir_new[3];
- int prev_mn; /* to find hair chains */
-
- if (!clmd->hairdata)
- return;
-
- /* XXX Note: we need to propagate frames from the root up,
- * but structural hair springs are stored in reverse order.
- * The bending springs however are then inserted in the same
- * order as vertices again ...
- * This messy situation can be resolved when solver data is
- * generated directly from a dedicated hair system.
- */
-
- prev_mn = -1;
- for (search = cloth->springs; search; search = search->next) {
- ClothSpring *spring = search->link;
- ClothHairData *hair_ij, *hair_kl;
- bool is_root = spring->kl != prev_mn;
-
- if (spring->type != CLOTH_SPRING_TYPE_BENDING_HAIR) {
- continue;
- }
-
- hair_ij = &clmd->hairdata[spring->ij];
- hair_kl = &clmd->hairdata[spring->kl];
- if (is_root) {
- /* initial hair frame from root orientation */
- copy_m3_m3(hair_frame, hair_ij->rot);
- /* surface normal is the initial direction,
- * parallel transport then keeps it aligned to the hair direction
- */
- copy_v3_v3(dir_new, hair_frame[2]);
- }
-
- copy_v3_v3(dir_old, dir_new);
- sub_v3_v3v3(dir_new, cloth->verts[spring->mn].x, cloth->verts[spring->kl].x);
- normalize_v3(dir_new);
-
- /* get local targets for kl/mn vertices by putting rest targets into the current frame,
- * then multiply with the rest length to get the actual goals
- */
-
- mul_v3_m3v3(spring->target, hair_frame, hair_kl->rest_target);
- mul_v3_fl(spring->target, spring->restlen);
-
- /* move frame to next hair segment */
- cloth_parallel_transport_hair_frame(hair_frame, dir_old, dir_new);
-
- prev_mn = spring->mn;
- }
+ Cloth *cloth = clmd->clothObject;
+ LinkNode *search = NULL;
+ float hair_frame[3][3], dir_old[3], dir_new[3];
+ int prev_mn; /* to find hair chains */
+
+ if (!clmd->hairdata)
+ return;
+
+ /* XXX Note: we need to propagate frames from the root up,
+ * but structural hair springs are stored in reverse order.
+ * The bending springs however are then inserted in the same
+ * order as vertices again ...
+ * This messy situation can be resolved when solver data is
+ * generated directly from a dedicated hair system.
+ */
+
+ prev_mn = -1;
+ for (search = cloth->springs; search; search = search->next) {
+ ClothSpring *spring = search->link;
+ ClothHairData *hair_ij, *hair_kl;
+ bool is_root = spring->kl != prev_mn;
+
+ if (spring->type != CLOTH_SPRING_TYPE_BENDING_HAIR) {
+ continue;
+ }
+
+ hair_ij = &clmd->hairdata[spring->ij];
+ hair_kl = &clmd->hairdata[spring->kl];
+ if (is_root) {
+ /* initial hair frame from root orientation */
+ copy_m3_m3(hair_frame, hair_ij->rot);
+ /* surface normal is the initial direction,
+ * parallel transport then keeps it aligned to the hair direction
+ */
+ copy_v3_v3(dir_new, hair_frame[2]);
+ }
+
+ copy_v3_v3(dir_old, dir_new);
+ sub_v3_v3v3(dir_new, cloth->verts[spring->mn].x, cloth->verts[spring->kl].x);
+ normalize_v3(dir_new);
+
+ /* get local targets for kl/mn vertices by putting rest targets into the current frame,
+ * then multiply with the rest length to get the actual goals
+ */
+
+ mul_v3_m3v3(spring->target, hair_frame, hair_kl->rest_target);
+ mul_v3_fl(spring->target, spring->restlen);
+
+ /* move frame to next hair segment */
+ cloth_parallel_transport_hair_frame(hair_frame, dir_old, dir_new);
+
+ prev_mn = spring->mn;
+ }
}
static void cloth_hair_update_bending_rest_targets(ClothModifierData *clmd)
{
- Cloth *cloth = clmd->clothObject;
- LinkNode *search = NULL;
- float hair_frame[3][3], dir_old[3], dir_new[3];
- int prev_mn; /* to find hair roots */
-
- if (!clmd->hairdata)
- return;
-
- /* XXX Note: we need to propagate frames from the root up,
- * but structural hair springs are stored in reverse order.
- * The bending springs however are then inserted in the same
- * order as vertices again ...
- * This messy situation can be resolved when solver data is
- * generated directly from a dedicated hair system.
- */
-
- prev_mn = -1;
- for (search = cloth->springs; search; search = search->next) {
- ClothSpring *spring = search->link;
- ClothHairData *hair_ij, *hair_kl;
- bool is_root = spring->kl != prev_mn;
-
- if (spring->type != CLOTH_SPRING_TYPE_BENDING_HAIR) {
- continue;
- }
-
- hair_ij = &clmd->hairdata[spring->ij];
- hair_kl = &clmd->hairdata[spring->kl];
- if (is_root) {
- /* initial hair frame from root orientation */
- copy_m3_m3(hair_frame, hair_ij->rot);
- /* surface normal is the initial direction,
- * parallel transport then keeps it aligned to the hair direction
- */
- copy_v3_v3(dir_new, hair_frame[2]);
- }
-
- copy_v3_v3(dir_old, dir_new);
- sub_v3_v3v3(dir_new, cloth->verts[spring->mn].xrest, cloth->verts[spring->kl].xrest);
- normalize_v3(dir_new);
-
- /* dir expressed in the hair frame defines the rest target direction */
- copy_v3_v3(hair_kl->rest_target, dir_new);
- mul_transposed_m3_v3(hair_frame, hair_kl->rest_target);
-
- /* move frame to next hair segment */
- cloth_parallel_transport_hair_frame(hair_frame, dir_old, dir_new);
-
- prev_mn = spring->mn;
- }
+ Cloth *cloth = clmd->clothObject;
+ LinkNode *search = NULL;
+ float hair_frame[3][3], dir_old[3], dir_new[3];
+ int prev_mn; /* to find hair roots */
+
+ if (!clmd->hairdata)
+ return;
+
+ /* XXX Note: we need to propagate frames from the root up,
+ * but structural hair springs are stored in reverse order.
+ * The bending springs however are then inserted in the same
+ * order as vertices again ...
+ * This messy situation can be resolved when solver data is
+ * generated directly from a dedicated hair system.
+ */
+
+ prev_mn = -1;
+ for (search = cloth->springs; search; search = search->next) {
+ ClothSpring *spring = search->link;
+ ClothHairData *hair_ij, *hair_kl;
+ bool is_root = spring->kl != prev_mn;
+
+ if (spring->type != CLOTH_SPRING_TYPE_BENDING_HAIR) {
+ continue;
+ }
+
+ hair_ij = &clmd->hairdata[spring->ij];
+ hair_kl = &clmd->hairdata[spring->kl];
+ if (is_root) {
+ /* initial hair frame from root orientation */
+ copy_m3_m3(hair_frame, hair_ij->rot);
+ /* surface normal is the initial direction,
+ * parallel transport then keeps it aligned to the hair direction
+ */
+ copy_v3_v3(dir_new, hair_frame[2]);
+ }
+
+ copy_v3_v3(dir_old, dir_new);
+ sub_v3_v3v3(dir_new, cloth->verts[spring->mn].xrest, cloth->verts[spring->kl].xrest);
+ normalize_v3(dir_new);
+
+ /* dir expressed in the hair frame defines the rest target direction */
+ copy_v3_v3(hair_kl->rest_target, dir_new);
+ mul_transposed_m3_v3(hair_frame, hair_kl->rest_target);
+
+ /* move frame to next hair segment */
+ cloth_parallel_transport_hair_frame(hair_frame, dir_old, dir_new);
+
+ prev_mn = spring->mn;
+ }
}
/* update stiffness if vertex group values are changing from frame to frame */
-static void cloth_update_springs( ClothModifierData *clmd )
+static void cloth_update_springs(ClothModifierData *clmd)
{
- Cloth *cloth = clmd->clothObject;
- LinkNode *search = NULL;
-
- search = cloth->springs;
- while (search) {
- ClothSpring *spring = search->link;
-
- spring->lin_stiffness = 0.0f;
-
- if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) {
- if (spring->type & CLOTH_SPRING_TYPE_BENDING) {
- spring->ang_stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f;
- }
- }
-
- if (spring->type & CLOTH_SPRING_TYPE_STRUCTURAL) {
- spring->lin_stiffness = (cloth->verts[spring->kl].struct_stiff + cloth->verts[spring->ij].struct_stiff) / 2.0f;
- }
- else if (spring->type & CLOTH_SPRING_TYPE_SHEAR) {
- spring->lin_stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0f;
- }
- else if (spring->type == CLOTH_SPRING_TYPE_BENDING) {
- spring->lin_stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f;
- }
- else if (spring->type == CLOTH_SPRING_TYPE_BENDING_HAIR) {
- ClothVertex *v1 = &cloth->verts[spring->ij];
- ClothVertex *v2 = &cloth->verts[spring->kl];
- if (clmd->hairdata) {
- /* copy extra hair data to generic cloth vertices */
- v1->bend_stiff = clmd->hairdata[spring->ij].bending_stiffness;
- v2->bend_stiff = clmd->hairdata[spring->kl].bending_stiffness;
- }
- spring->lin_stiffness = (v1->bend_stiff + v2->bend_stiff) / 2.0f;
- }
- else if (spring->type == CLOTH_SPRING_TYPE_GOAL) {
- /* Warning: Appending NEW goal springs does not work because implicit solver would need reset! */
-
- /* Activate / Deactivate existing springs */
- if ((!(cloth->verts[spring->ij].flags & CLOTH_VERT_FLAG_PINNED)) &&
- (cloth->verts[spring->ij].goal > ALMOST_ZERO))
- {
- spring->flags &= ~CLOTH_SPRING_FLAG_DEACTIVATE;
- }
- else {
- spring->flags |= CLOTH_SPRING_FLAG_DEACTIVATE;
- }
- }
-
- search = search->next;
- }
-
- cloth_hair_update_bending_targets(clmd);
+ Cloth *cloth = clmd->clothObject;
+ LinkNode *search = NULL;
+
+ search = cloth->springs;
+ while (search) {
+ ClothSpring *spring = search->link;
+
+ spring->lin_stiffness = 0.0f;
+
+ if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) {
+ if (spring->type & CLOTH_SPRING_TYPE_BENDING) {
+ spring->ang_stiffness = (cloth->verts[spring->kl].bend_stiff +
+ cloth->verts[spring->ij].bend_stiff) /
+ 2.0f;
+ }
+ }
+
+ if (spring->type & CLOTH_SPRING_TYPE_STRUCTURAL) {
+ spring->lin_stiffness = (cloth->verts[spring->kl].struct_stiff +
+ cloth->verts[spring->ij].struct_stiff) /
+ 2.0f;
+ }
+ else if (spring->type & CLOTH_SPRING_TYPE_SHEAR) {
+ spring->lin_stiffness = (cloth->verts[spring->kl].shear_stiff +
+ cloth->verts[spring->ij].shear_stiff) /
+ 2.0f;
+ }
+ else if (spring->type == CLOTH_SPRING_TYPE_BENDING) {
+ spring->lin_stiffness = (cloth->verts[spring->kl].bend_stiff +
+ cloth->verts[spring->ij].bend_stiff) /
+ 2.0f;
+ }
+ else if (spring->type == CLOTH_SPRING_TYPE_BENDING_HAIR) {
+ ClothVertex *v1 = &cloth->verts[spring->ij];
+ ClothVertex *v2 = &cloth->verts[spring->kl];
+ if (clmd->hairdata) {
+ /* copy extra hair data to generic cloth vertices */
+ v1->bend_stiff = clmd->hairdata[spring->ij].bending_stiffness;
+ v2->bend_stiff = clmd->hairdata[spring->kl].bending_stiffness;
+ }
+ spring->lin_stiffness = (v1->bend_stiff + v2->bend_stiff) / 2.0f;
+ }
+ else if (spring->type == CLOTH_SPRING_TYPE_GOAL) {
+ /* Warning: Appending NEW goal springs does not work because implicit solver would need reset! */
+
+ /* Activate / Deactivate existing springs */
+ if ((!(cloth->verts[spring->ij].flags & CLOTH_VERT_FLAG_PINNED)) &&
+ (cloth->verts[spring->ij].goal > ALMOST_ZERO)) {
+ spring->flags &= ~CLOTH_SPRING_FLAG_DEACTIVATE;
+ }
+ else {
+ spring->flags |= CLOTH_SPRING_FLAG_DEACTIVATE;
+ }
+ }
+
+ search = search->next;
+ }
+
+ cloth_hair_update_bending_targets(clmd);
}
/* Update rest verts, for dynamically deformable cloth */
-static void cloth_update_verts( Object *ob, ClothModifierData *clmd, Mesh *mesh )
+static void cloth_update_verts(Object *ob, ClothModifierData *clmd, Mesh *mesh)
{
- unsigned int i = 0;
- MVert *mvert = mesh->mvert;
- ClothVertex *verts = clmd->clothObject->verts;
-
- /* vertex count is already ensured to match */
- for ( i = 0; i < mesh->totvert; i++, verts++ ) {
- copy_v3_v3(verts->xrest, mvert[i].co);
- mul_m4_v3(ob->obmat, verts->xrest);
- }
+ unsigned int i = 0;
+ MVert *mvert = mesh->mvert;
+ ClothVertex *verts = clmd->clothObject->verts;
+
+ /* vertex count is already ensured to match */
+ for (i = 0; i < mesh->totvert; i++, verts++) {
+ copy_v3_v3(verts->xrest, mvert[i].co);
+ mul_m4_v3(ob->obmat, verts->xrest);
+ }
}
/* Update spring rest length, for dynamically deformable cloth */
-static void cloth_update_spring_lengths( ClothModifierData *clmd, Mesh *mesh )
+static void cloth_update_spring_lengths(ClothModifierData *clmd, Mesh *mesh)
{
- Cloth *cloth = clmd->clothObject;
- LinkNode *search = cloth->springs;
- unsigned int struct_springs = 0;
- unsigned int i = 0;
- unsigned int mvert_num = (unsigned int)mesh->totvert;
- float shrink_factor;
-
- clmd->sim_parms->avg_spring_len = 0.0f;
-
- for (i = 0; i < mvert_num; i++) {
- cloth->verts[i].avg_spring_len = 0.0f;
- }
-
- while (search) {
- ClothSpring *spring = search->link;
-
- if (spring->type != CLOTH_SPRING_TYPE_SEWING) {
- if (spring->type & (CLOTH_SPRING_TYPE_STRUCTURAL | CLOTH_SPRING_TYPE_SHEAR | CLOTH_SPRING_TYPE_BENDING)) {
- shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl);
- }
- else {
- shrink_factor = 1.0f;
- }
-
- spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor;
-
- if (spring->type & CLOTH_SPRING_TYPE_BENDING) {
- spring->restang = cloth_spring_angle(cloth->verts, spring->ij, spring->kl,
- spring->pa, spring->pb, spring->la, spring->lb);
- }
- }
-
- if (spring->type & CLOTH_SPRING_TYPE_STRUCTURAL) {
- clmd->sim_parms->avg_spring_len += spring->restlen;
- cloth->verts[spring->ij].avg_spring_len += spring->restlen;
- cloth->verts[spring->kl].avg_spring_len += spring->restlen;
- struct_springs++;
- }
-
- search = search->next;
- }
-
- if (struct_springs > 0) {
- clmd->sim_parms->avg_spring_len /= struct_springs;
- }
-
- for (i = 0; i < mvert_num; i++) {
- if (cloth->verts[i].spring_count > 0) {
- cloth->verts[i].avg_spring_len = cloth->verts[i].avg_spring_len * 0.49f / ((float)cloth->verts[i].spring_count);
- }
- }
+ Cloth *cloth = clmd->clothObject;
+ LinkNode *search = cloth->springs;
+ unsigned int struct_springs = 0;
+ unsigned int i = 0;
+ unsigned int mvert_num = (unsigned int)mesh->totvert;
+ float shrink_factor;
+
+ clmd->sim_parms->avg_spring_len = 0.0f;
+
+ for (i = 0; i < mvert_num; i++) {
+ cloth->verts[i].avg_spring_len = 0.0f;
+ }
+
+ while (search) {
+ ClothSpring *spring = search->link;
+
+ if (spring->type != CLOTH_SPRING_TYPE_SEWING) {
+ if (spring->type &
+ (CLOTH_SPRING_TYPE_STRUCTURAL | CLOTH_SPRING_TYPE_SHEAR | CLOTH_SPRING_TYPE_BENDING)) {
+ shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl);
+ }
+ else {
+ shrink_factor = 1.0f;
+ }
+
+ spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) *
+ shrink_factor;
+
+ if (spring->type & CLOTH_SPRING_TYPE_BENDING) {
+ spring->restang = cloth_spring_angle(
+ cloth->verts, spring->ij, spring->kl, spring->pa, spring->pb, spring->la, spring->lb);
+ }
+ }
+
+ if (spring->type & CLOTH_SPRING_TYPE_STRUCTURAL) {
+ clmd->sim_parms->avg_spring_len += spring->restlen;
+ cloth->verts[spring->ij].avg_spring_len += spring->restlen;
+ cloth->verts[spring->kl].avg_spring_len += spring->restlen;
+ struct_springs++;
+ }
+
+ search = search->next;
+ }
+
+ if (struct_springs > 0) {
+ clmd->sim_parms->avg_spring_len /= struct_springs;
+ }
+
+ for (i = 0; i < mvert_num; i++) {
+ if (cloth->verts[i].spring_count > 0) {
+ cloth->verts[i].avg_spring_len = cloth->verts[i].avg_spring_len * 0.49f /
+ ((float)cloth->verts[i].spring_count);
+ }
+ }
}
BLI_INLINE void cross_identity_v3(float r[3][3], const float v[3])
{
- zero_m3(r);
- r[0][1] = v[2];
- r[0][2] = -v[1];
- r[1][0] = -v[2];
- r[1][2] = v[0];
- r[2][0] = v[1];
- r[2][1] = -v[0];
+ zero_m3(r);
+ r[0][1] = v[2];
+ r[0][2] = -v[1];
+ r[1][0] = -v[2];
+ r[1][2] = v[0];
+ r[2][0] = v[1];
+ r[2][1] = -v[0];
}
BLI_INLINE void madd_m3_m3fl(float r[3][3], float m[3][3], float f)
{
- r[0][0] += m[0][0] * f;
- r[0][1] += m[0][1] * f;
- r[0][2] += m[0][2] * f;
- r[1][0] += m[1][0] * f;
- r[1][1] += m[1][1] * f;
- r[1][2] += m[1][2] * f;
- r[2][0] += m[2][0] * f;
- r[2][1] += m[2][1] * f;
- r[2][2] += m[2][2] * f;
+ r[0][0] += m[0][0] * f;
+ r[0][1] += m[0][1] * f;
+ r[0][2] += m[0][2] * f;
+ r[1][0] += m[1][0] * f;
+ r[1][1] += m[1][1] * f;
+ r[1][2] += m[1][2] * f;
+ r[2][0] += m[2][0] * f;
+ r[2][1] += m[2][1] * f;
+ r[2][2] += m[2][2] * f;
}
-void cloth_parallel_transport_hair_frame(float mat[3][3], const float dir_old[3], const float dir_new[3])
+void cloth_parallel_transport_hair_frame(float mat[3][3],
+ const float dir_old[3],
+ const float dir_new[3])
{
- float rot[3][3];
+ float rot[3][3];
- /* rotation between segments */
- rotation_between_vecs_to_mat3(rot, dir_old, dir_new);
+ /* rotation between segments */
+ rotation_between_vecs_to_mat3(rot, dir_old, dir_new);
- /* rotate the frame */
- mul_m3_m3m3(mat, rot, mat);
+ /* rotate the frame */
+ mul_m3_m3m3(mat, rot, mat);
}
/* Add a shear and a bend spring between two verts within a poly. */
-static bool cloth_add_shear_bend_spring(ClothModifierData *clmd, LinkNodePair *edgelist,
- const MLoop *mloop, const MPoly *mpoly, int i, int j, int k)
+static bool cloth_add_shear_bend_spring(ClothModifierData *clmd,
+ LinkNodePair *edgelist,
+ const MLoop *mloop,
+ const MPoly *mpoly,
+ int i,
+ int j,
+ int k)
{
- Cloth *cloth = clmd->clothObject;
- ClothSpring *spring;
- const MLoop *tmp_loop;
- float shrink_factor;
- int x, y;
+ Cloth *cloth = clmd->clothObject;
+ ClothSpring *spring;
+ const MLoop *tmp_loop;
+ float shrink_factor;
+ int x, y;
- /* Combined shear/bend properties. */
- spring = (ClothSpring *)MEM_callocN(sizeof(ClothSpring), "cloth spring");
+ /* Combined shear/bend properties. */
+ spring = (ClothSpring *)MEM_callocN(sizeof(ClothSpring), "cloth spring");
- if (!spring) {
- return false;
- }
+ if (!spring) {
+ return false;
+ }
- spring_verts_ordered_set(spring,
- mloop[mpoly[i].loopstart + j].v,
- mloop[mpoly[i].loopstart + k].v);
+ spring_verts_ordered_set(
+ spring, mloop[mpoly[i].loopstart + j].v, mloop[mpoly[i].loopstart + k].v);
- shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl);
- spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor;
- spring->type |= CLOTH_SPRING_TYPE_SHEAR;
- spring->lin_stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0f;
+ shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl);
+ spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) *
+ shrink_factor;
+ spring->type |= CLOTH_SPRING_TYPE_SHEAR;
+ spring->lin_stiffness = (cloth->verts[spring->kl].shear_stiff +
+ cloth->verts[spring->ij].shear_stiff) /
+ 2.0f;
- if (edgelist) {
- BLI_linklist_append(&edgelist[spring->ij], spring);
- BLI_linklist_append(&edgelist[spring->kl], spring);
- }
+ if (edgelist) {
+ BLI_linklist_append(&edgelist[spring->ij], spring);
+ BLI_linklist_append(&edgelist[spring->kl], spring);
+ }
- /* Bending specific properties. */
- if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) {
- spring->type |= CLOTH_SPRING_TYPE_BENDING;
+ /* Bending specific properties. */
+ if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) {
+ spring->type |= CLOTH_SPRING_TYPE_BENDING;
- spring->la = k - j + 1;
- spring->lb = mpoly[i].totloop - k + j + 1;
+ spring->la = k - j + 1;
+ spring->lb = mpoly[i].totloop - k + j + 1;
- spring->pa = MEM_mallocN(sizeof(*spring->pa) * spring->la, "spring poly");
- if (!spring->pa) {
- return false;
- }
+ spring->pa = MEM_mallocN(sizeof(*spring->pa) * spring->la, "spring poly");
+ if (!spring->pa) {
+ return false;
+ }
- spring->pb = MEM_mallocN(sizeof(*spring->pb) * spring->lb, "spring poly");
- if (!spring->pb) {
- return false;
- }
+ spring->pb = MEM_mallocN(sizeof(*spring->pb) * spring->lb, "spring poly");
+ if (!spring->pb) {
+ return false;
+ }
- tmp_loop = mloop + mpoly[i].loopstart;
+ tmp_loop = mloop + mpoly[i].loopstart;
- for (x = 0; x < spring->la; x++) {
- spring->pa[x] = tmp_loop[j + x].v;
- }
+ for (x = 0; x < spring->la; x++) {
+ spring->pa[x] = tmp_loop[j + x].v;
+ }
- for (x = 0; x <= j; x++) {
- spring->pb[x] = tmp_loop[x].v;
- }
+ for (x = 0; x <= j; x++) {
+ spring->pb[x] = tmp_loop[x].v;
+ }
- for (y = k; y < mpoly[i].totloop; x++, y++) {
- spring->pb[x] = tmp_loop[y].v;
- }
+ for (y = k; y < mpoly[i].totloop; x++, y++) {
+ spring->pb[x] = tmp_loop[y].v;
+ }
- spring->mn = -1;
+ spring->mn = -1;
- spring->restang = cloth_spring_angle(cloth->verts, spring->ij, spring->kl,
- spring->pa, spring->pb, spring->la, spring->lb);
+ spring->restang = cloth_spring_angle(
+ cloth->verts, spring->ij, spring->kl, spring->pa, spring->pb, spring->la, spring->lb);
- spring->ang_stiffness = (cloth->verts[spring->ij].bend_stiff + cloth->verts[spring->kl].bend_stiff) / 2.0f;
- }
+ spring->ang_stiffness = (cloth->verts[spring->ij].bend_stiff +
+ cloth->verts[spring->kl].bend_stiff) /
+ 2.0f;
+ }
- BLI_linklist_prepend(&cloth->springs, spring);
+ BLI_linklist_prepend(&cloth->springs, spring);
- return true;
+ return true;
}
BLI_INLINE bool cloth_bend_set_poly_vert_array(int **poly, int len, const MLoop *mloop)
{
- int *p = MEM_mallocN(sizeof(int) * len, "spring poly");
+ int *p = MEM_mallocN(sizeof(int) * len, "spring poly");
- if (!p) {
- return false;
- }
+ if (!p) {
+ return false;
+ }
- for (int i = 0; i < len; i++, mloop++) {
- p[i] = mloop->v;
- }
+ for (int i = 0; i < len; i++, mloop++) {
+ p[i] = mloop->v;
+ }
- *poly = p;
+ *poly = p;
- return true;
+ return true;
}
-static int cloth_build_springs ( ClothModifierData *clmd, Mesh *mesh )
+static int cloth_build_springs(ClothModifierData *clmd, Mesh *mesh)
{
- Cloth *cloth = clmd->clothObject;
- ClothSpring *spring = NULL, *tspring = NULL, *tspring2 = NULL;
- unsigned int struct_springs = 0, shear_springs=0, bend_springs = 0, struct_springs_real = 0;
- unsigned int mvert_num = (unsigned int)mesh->totvert;
- unsigned int numedges = (unsigned int)mesh->totedge;
- unsigned int numpolys = (unsigned int)mesh->totpoly;
- float shrink_factor;
- const MEdge *medge = mesh->medge;
- const MPoly *mpoly = mesh->mpoly;
- const MLoop *mloop = mesh->mloop;
- int index2 = 0; // our second vertex index
- LinkNodePair *edgelist = NULL;
- EdgeSet *edgeset = NULL;
- LinkNode *search = NULL, *search2 = NULL;
- BendSpringRef *spring_ref = NULL;
-
- // error handling
- if ( numedges==0 )
- return 0;
-
- /* NOTE: handling ownership of springs and edgeset is quite sloppy
- * currently they are never initialized but assert just to be sure */
- BLI_assert(cloth->springs == NULL);
- BLI_assert(cloth->edgeset == NULL);
-
- cloth->springs = NULL;
- cloth->edgeset = NULL;
-
- if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) {
- spring_ref = MEM_callocN(sizeof(*spring_ref) * numedges, "temp bend spring reference");
-
- if (!spring_ref) {
- return 0;
- }
- }
- else {
- edgelist = MEM_callocN(sizeof(*edgelist) * mvert_num, "cloth_edgelist_alloc" );
-
- if (!edgelist) {
- return 0;
- }
- }
-
- clmd->sim_parms->avg_spring_len = 0.0f;
- for (int i = 0; i < mvert_num; i++) {
- cloth->verts[i].avg_spring_len = 0.0f;
- }
-
- /* Structural springs. */
- for (int i = 0; i < numedges; i++) {
- spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
-
- if ( spring ) {
- spring_verts_ordered_set(spring, medge[i].v1, medge[i].v2);
- if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW && medge[i].flag & ME_LOOSEEDGE) {
- // handle sewing (loose edges will be pulled together)
- spring->restlen = 0.0f;
- spring->lin_stiffness = 1.0f;
- spring->type = CLOTH_SPRING_TYPE_SEWING;
- }
- else {
- shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl);
- spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor;
- spring->lin_stiffness = (cloth->verts[spring->kl].struct_stiff + cloth->verts[spring->ij].struct_stiff) / 2.0f;
- spring->type = CLOTH_SPRING_TYPE_STRUCTURAL;
-
- clmd->sim_parms->avg_spring_len += spring->restlen;
- cloth->verts[spring->ij].avg_spring_len += spring->restlen;
- cloth->verts[spring->kl].avg_spring_len += spring->restlen;
- cloth->verts[spring->ij].spring_count++;
- cloth->verts[spring->kl].spring_count++;
- struct_springs_real++;
- }
-
- spring->flags = 0;
- struct_springs++;
-
- BLI_linklist_prepend ( &cloth->springs, spring );
-
- if (spring_ref) {
- spring_ref[i].spring = spring;
- }
- }
- else {
- cloth_free_errorsprings(cloth, edgelist, spring_ref);
- return 0;
- }
- }
-
- if (struct_springs_real > 0)
- clmd->sim_parms->avg_spring_len /= struct_springs_real;
-
- for (int i = 0; i < mvert_num; i++) {
- if (cloth->verts[i].spring_count > 0)
- cloth->verts[i].avg_spring_len = cloth->verts[i].avg_spring_len * 0.49f / ((float)cloth->verts[i].spring_count);
- }
-
- edgeset = BLI_edgeset_new_ex(__func__, numedges);
- cloth->edgeset = edgeset;
-
- if (numpolys) {
- for (int i = 0; i < numpolys; i++) {
- /* Shear springs. */
- /* Triangle faces already have shear springs due to structural geometry. */
- if (mpoly[i].totloop > 3) {
- for (int j = 1; j < mpoly[i].totloop - 1; j++) {
- if (j > 1) {
- if (cloth_add_shear_bend_spring(clmd, edgelist, mloop, mpoly, i, 0, j)) {
- shear_springs++;
-
- if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) {
- bend_springs++;
- }
- }
- else {
- cloth_free_errorsprings(cloth, edgelist, spring_ref);
- return 0;
- }
- }
-
- for (int k = j + 2; k < mpoly[i].totloop; k++) {
- if (cloth_add_shear_bend_spring(clmd, edgelist, mloop, mpoly, i, j, k)) {
- shear_springs++;
-
- if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) {
- bend_springs++;
- }
- }
- else {
- cloth_free_errorsprings(cloth, edgelist, spring_ref);
- return 0;
- }
- }
- }
- }
-
- /* Angular bending springs along struct springs. */
- if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) {
- const MLoop *ml = mloop + mpoly[i].loopstart;
-
- for (int j = 0; j < mpoly[i].totloop; j++, ml++) {
- BendSpringRef *curr_ref = &spring_ref[ml->e];
- curr_ref->polys++;
-
- /* First poly found for this edge, store poly index. */
- if (curr_ref->polys == 1) {
- curr_ref->index = i;
- }
- /* Second poly found for this edge, add bending data. */
- else if (curr_ref->polys == 2) {
- spring = curr_ref->spring;
-
- spring->type |= CLOTH_SPRING_TYPE_BENDING;
-
- spring->la = mpoly[curr_ref->index].totloop;
- spring->lb = mpoly[i].totloop;
-
- if (!cloth_bend_set_poly_vert_array(&spring->pa, spring->la, &mloop[mpoly[curr_ref->index].loopstart]) ||
- !cloth_bend_set_poly_vert_array(&spring->pb, spring->lb, &mloop[mpoly[i].loopstart]))
- {
- cloth_free_errorsprings(cloth, edgelist, spring_ref);
- return 0;
- }
-
- spring->mn = ml->e;
-
- spring->restang = cloth_spring_angle(cloth->verts, spring->ij, spring->kl,
- spring->pa, spring->pb, spring->la, spring->lb);
-
- spring->ang_stiffness = (cloth->verts[spring->ij].bend_stiff + cloth->verts[spring->kl].bend_stiff) / 2.0f;
-
- bend_springs++;
- }
- /* Third poly found for this edge, remove bending data. */
- else if (curr_ref->polys == 3) {
- spring = curr_ref->spring;
-
- spring->type &= ~CLOTH_SPRING_TYPE_BENDING;
- MEM_freeN(spring->pa);
- MEM_freeN(spring->pb);
- spring->pa = NULL;
- spring->pb = NULL;
-
- bend_springs--;
- }
- }
- }
- }
-
- /* Linear bending springs. */
- if (clmd->sim_parms->bending_model == CLOTH_BENDING_LINEAR) {
- search2 = cloth->springs;
-
- for (int i = struct_springs; i < struct_springs+shear_springs; i++) {
- if (!search2) {
- break;
- }
-
- tspring2 = search2->link;
- search = edgelist[tspring2->kl].list;
-
- while (search) {
- tspring = search->link;
- index2 = ((tspring->ij == tspring2->kl) ? (tspring->kl) : (tspring->ij));
-
- /* Check for existing spring. */
- /* Check also if startpoint is equal to endpoint. */
- if ((index2 != tspring2->ij) &&
- !BLI_edgeset_haskey(edgeset, tspring2->ij, index2))
- {
- spring = (ClothSpring *)MEM_callocN(sizeof(ClothSpring), "cloth spring");
-
- if (!spring) {
- cloth_free_errorsprings(cloth, edgelist, spring_ref);
- return 0;
- }
-
- spring_verts_ordered_set(spring, tspring2->ij, index2);
- shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl);
- spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor;
- spring->type = CLOTH_SPRING_TYPE_BENDING;
- spring->lin_stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f;
- BLI_edgeset_insert(edgeset, spring->ij, spring->kl);
- bend_springs++;
-
- BLI_linklist_prepend(&cloth->springs, spring);
- }
-
- search = search->next;
- }
-
- search2 = search2->next;
- }
- }
- }
- else if (struct_springs > 2) {
- if (G.debug_value != 1112) {
- search = cloth->springs;
- search2 = search->next;
- while (search && search2) {
- tspring = search->link;
- tspring2 = search2->link;
-
- if (tspring->ij == tspring2->kl) {
- spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
-
- if (!spring) {
- cloth_free_errorsprings(cloth, edgelist, spring_ref);
- return 0;
- }
-
- spring->ij = tspring2->ij;
- spring->kl = tspring->ij;
- spring->mn = tspring->kl;
- spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest);
- spring->type = CLOTH_SPRING_TYPE_BENDING_HAIR;
- spring->lin_stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f;
- bend_springs++;
-
- BLI_linklist_prepend ( &cloth->springs, spring );
- }
-
- search = search->next;
- search2 = search2->next;
- }
- }
- else {
- /* bending springs for hair strands
- * The current algorithm only goes through the edges in order of the mesh edges list
- * and makes springs between the outer vert of edges sharing a vertice. This works just
- * fine for hair, but not for user generated string meshes. This could/should be later
- * extended to work with non-ordered edges so that it can be used for general "rope
- * dynamics" without the need for the vertices or edges to be ordered through the length
- * of the strands. -jahka */
- search = cloth->springs;
- search2 = search->next;
- while (search && search2) {
- tspring = search->link;
- tspring2 = search2->link;
-
- if (tspring->ij == tspring2->kl) {
- spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
-
- if (!spring) {
- cloth_free_errorsprings(cloth, edgelist, spring_ref);
- return 0;
- }
-
- spring->ij = tspring2->ij;
- spring->kl = tspring->kl;
- spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest);
- spring->type = CLOTH_SPRING_TYPE_BENDING;
- spring->lin_stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f;
- bend_springs++;
-
- BLI_linklist_prepend ( &cloth->springs, spring );
- }
-
- search = search->next;
- search2 = search2->next;
- }
- }
-
- cloth_hair_update_bending_rest_targets(clmd);
- }
-
- /* note: the edges may already exist so run reinsert */
-
- /* insert other near springs in edgeset AFTER bending springs are calculated (for selfcolls) */
- for (int i = 0; i < numedges; i++) { /* struct springs */
- BLI_edgeset_add(edgeset, medge[i].v1, medge[i].v2);
- }
-
- for (int i = 0; i < numpolys; i++) { /* edge springs */
- if (mpoly[i].totloop == 4) {
- BLI_edgeset_add(edgeset, mloop[mpoly[i].loopstart + 0].v, mloop[mpoly[i].loopstart + 2].v);
- BLI_edgeset_add(edgeset, mloop[mpoly[i].loopstart + 1].v, mloop[mpoly[i].loopstart + 3].v);
- }
- }
-
- MEM_SAFE_FREE(spring_ref);
-
- cloth->numsprings = struct_springs + shear_springs + bend_springs;
-
- cloth_free_edgelist(edgelist, mvert_num);
+ Cloth *cloth = clmd->clothObject;
+ ClothSpring *spring = NULL, *tspring = NULL, *tspring2 = NULL;
+ unsigned int struct_springs = 0, shear_springs = 0, bend_springs = 0, struct_springs_real = 0;
+ unsigned int mvert_num = (unsigned int)mesh->totvert;
+ unsigned int numedges = (unsigned int)mesh->totedge;
+ unsigned int numpolys = (unsigned int)mesh->totpoly;
+ float shrink_factor;
+ const MEdge *medge = mesh->medge;
+ const MPoly *mpoly = mesh->mpoly;
+ const MLoop *mloop = mesh->mloop;
+ int index2 = 0; // our second vertex index
+ LinkNodePair *edgelist = NULL;
+ EdgeSet *edgeset = NULL;
+ LinkNode *search = NULL, *search2 = NULL;
+ BendSpringRef *spring_ref = NULL;
+
+ // error handling
+ if (numedges == 0)
+ return 0;
+
+ /* NOTE: handling ownership of springs and edgeset is quite sloppy
+ * currently they are never initialized but assert just to be sure */
+ BLI_assert(cloth->springs == NULL);
+ BLI_assert(cloth->edgeset == NULL);
+
+ cloth->springs = NULL;
+ cloth->edgeset = NULL;
+
+ if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) {
+ spring_ref = MEM_callocN(sizeof(*spring_ref) * numedges, "temp bend spring reference");
+
+ if (!spring_ref) {
+ return 0;
+ }
+ }
+ else {
+ edgelist = MEM_callocN(sizeof(*edgelist) * mvert_num, "cloth_edgelist_alloc");
+
+ if (!edgelist) {
+ return 0;
+ }
+ }
+
+ clmd->sim_parms->avg_spring_len = 0.0f;
+ for (int i = 0; i < mvert_num; i++) {
+ cloth->verts[i].avg_spring_len = 0.0f;
+ }
+
+ /* Structural springs. */
+ for (int i = 0; i < numedges; i++) {
+ spring = (ClothSpring *)MEM_callocN(sizeof(ClothSpring), "cloth spring");
+
+ if (spring) {
+ spring_verts_ordered_set(spring, medge[i].v1, medge[i].v2);
+ if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW && medge[i].flag & ME_LOOSEEDGE) {
+ // handle sewing (loose edges will be pulled together)
+ spring->restlen = 0.0f;
+ spring->lin_stiffness = 1.0f;
+ spring->type = CLOTH_SPRING_TYPE_SEWING;
+ }
+ else {
+ shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl);
+ spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest,
+ cloth->verts[spring->ij].xrest) *
+ shrink_factor;
+ spring->lin_stiffness = (cloth->verts[spring->kl].struct_stiff +
+ cloth->verts[spring->ij].struct_stiff) /
+ 2.0f;
+ spring->type = CLOTH_SPRING_TYPE_STRUCTURAL;
+
+ clmd->sim_parms->avg_spring_len += spring->restlen;
+ cloth->verts[spring->ij].avg_spring_len += spring->restlen;
+ cloth->verts[spring->kl].avg_spring_len += spring->restlen;
+ cloth->verts[spring->ij].spring_count++;
+ cloth->verts[spring->kl].spring_count++;
+ struct_springs_real++;
+ }
+
+ spring->flags = 0;
+ struct_springs++;
+
+ BLI_linklist_prepend(&cloth->springs, spring);
+
+ if (spring_ref) {
+ spring_ref[i].spring = spring;
+ }
+ }
+ else {
+ cloth_free_errorsprings(cloth, edgelist, spring_ref);
+ return 0;
+ }
+ }
+
+ if (struct_springs_real > 0)
+ clmd->sim_parms->avg_spring_len /= struct_springs_real;
+
+ for (int i = 0; i < mvert_num; i++) {
+ if (cloth->verts[i].spring_count > 0)
+ cloth->verts[i].avg_spring_len = cloth->verts[i].avg_spring_len * 0.49f /
+ ((float)cloth->verts[i].spring_count);
+ }
+
+ edgeset = BLI_edgeset_new_ex(__func__, numedges);
+ cloth->edgeset = edgeset;
+
+ if (numpolys) {
+ for (int i = 0; i < numpolys; i++) {
+ /* Shear springs. */
+ /* Triangle faces already have shear springs due to structural geometry. */
+ if (mpoly[i].totloop > 3) {
+ for (int j = 1; j < mpoly[i].totloop - 1; j++) {
+ if (j > 1) {
+ if (cloth_add_shear_bend_spring(clmd, edgelist, mloop, mpoly, i, 0, j)) {
+ shear_springs++;
+
+ if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) {
+ bend_springs++;
+ }
+ }
+ else {
+ cloth_free_errorsprings(cloth, edgelist, spring_ref);
+ return 0;
+ }
+ }
+
+ for (int k = j + 2; k < mpoly[i].totloop; k++) {
+ if (cloth_add_shear_bend_spring(clmd, edgelist, mloop, mpoly, i, j, k)) {
+ shear_springs++;
+
+ if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) {
+ bend_springs++;
+ }
+ }
+ else {
+ cloth_free_errorsprings(cloth, edgelist, spring_ref);
+ return 0;
+ }
+ }
+ }
+ }
+
+ /* Angular bending springs along struct springs. */
+ if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) {
+ const MLoop *ml = mloop + mpoly[i].loopstart;
+
+ for (int j = 0; j < mpoly[i].totloop; j++, ml++) {
+ BendSpringRef *curr_ref = &spring_ref[ml->e];
+ curr_ref->polys++;
+
+ /* First poly found for this edge, store poly index. */
+ if (curr_ref->polys == 1) {
+ curr_ref->index = i;
+ }
+ /* Second poly found for this edge, add bending data. */
+ else if (curr_ref->polys == 2) {
+ spring = curr_ref->spring;
+
+ spring->type |= CLOTH_SPRING_TYPE_BENDING;
+
+ spring->la = mpoly[curr_ref->index].totloop;
+ spring->lb = mpoly[i].totloop;
+
+ if (!cloth_bend_set_poly_vert_array(
+ &spring->pa, spring->la, &mloop[mpoly[curr_ref->index].loopstart]) ||
+ !cloth_bend_set_poly_vert_array(
+ &spring->pb, spring->lb, &mloop[mpoly[i].loopstart])) {
+ cloth_free_errorsprings(cloth, edgelist, spring_ref);
+ return 0;
+ }
+
+ spring->mn = ml->e;
+
+ spring->restang = cloth_spring_angle(cloth->verts,
+ spring->ij,
+ spring->kl,
+ spring->pa,
+ spring->pb,
+ spring->la,
+ spring->lb);
+
+ spring->ang_stiffness = (cloth->verts[spring->ij].bend_stiff +
+ cloth->verts[spring->kl].bend_stiff) /
+ 2.0f;
+
+ bend_springs++;
+ }
+ /* Third poly found for this edge, remove bending data. */
+ else if (curr_ref->polys == 3) {
+ spring = curr_ref->spring;
+
+ spring->type &= ~CLOTH_SPRING_TYPE_BENDING;
+ MEM_freeN(spring->pa);
+ MEM_freeN(spring->pb);
+ spring->pa = NULL;
+ spring->pb = NULL;
+
+ bend_springs--;
+ }
+ }
+ }
+ }
+
+ /* Linear bending springs. */
+ if (clmd->sim_parms->bending_model == CLOTH_BENDING_LINEAR) {
+ search2 = cloth->springs;
+
+ for (int i = struct_springs; i < struct_springs + shear_springs; i++) {
+ if (!search2) {
+ break;
+ }
+
+ tspring2 = search2->link;
+ search = edgelist[tspring2->kl].list;
+
+ while (search) {
+ tspring = search->link;
+ index2 = ((tspring->ij == tspring2->kl) ? (tspring->kl) : (tspring->ij));
+
+ /* Check for existing spring. */
+ /* Check also if startpoint is equal to endpoint. */
+ if ((index2 != tspring2->ij) && !BLI_edgeset_haskey(edgeset, tspring2->ij, index2)) {
+ spring = (ClothSpring *)MEM_callocN(sizeof(ClothSpring), "cloth spring");
+
+ if (!spring) {
+ cloth_free_errorsprings(cloth, edgelist, spring_ref);
+ return 0;
+ }
+
+ spring_verts_ordered_set(spring, tspring2->ij, index2);
+ shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl);
+ spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest,
+ cloth->verts[spring->ij].xrest) *
+ shrink_factor;
+ spring->type = CLOTH_SPRING_TYPE_BENDING;
+ spring->lin_stiffness = (cloth->verts[spring->kl].bend_stiff +
+ cloth->verts[spring->ij].bend_stiff) /
+ 2.0f;
+ BLI_edgeset_insert(edgeset, spring->ij, spring->kl);
+ bend_springs++;
+
+ BLI_linklist_prepend(&cloth->springs, spring);
+ }
+
+ search = search->next;
+ }
+
+ search2 = search2->next;
+ }
+ }
+ }
+ else if (struct_springs > 2) {
+ if (G.debug_value != 1112) {
+ search = cloth->springs;
+ search2 = search->next;
+ while (search && search2) {
+ tspring = search->link;
+ tspring2 = search2->link;
+
+ if (tspring->ij == tspring2->kl) {
+ spring = (ClothSpring *)MEM_callocN(sizeof(ClothSpring), "cloth spring");
+
+ if (!spring) {
+ cloth_free_errorsprings(cloth, edgelist, spring_ref);
+ return 0;
+ }
+
+ spring->ij = tspring2->ij;
+ spring->kl = tspring->ij;
+ spring->mn = tspring->kl;
+ spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest,
+ cloth->verts[spring->ij].xrest);
+ spring->type = CLOTH_SPRING_TYPE_BENDING_HAIR;
+ spring->lin_stiffness = (cloth->verts[spring->kl].bend_stiff +
+ cloth->verts[spring->ij].bend_stiff) /
+ 2.0f;
+ bend_springs++;
+
+ BLI_linklist_prepend(&cloth->springs, spring);
+ }
+
+ search = search->next;
+ search2 = search2->next;
+ }
+ }
+ else {
+ /* bending springs for hair strands
+ * The current algorithm only goes through the edges in order of the mesh edges list
+ * and makes springs between the outer vert of edges sharing a vertice. This works just
+ * fine for hair, but not for user generated string meshes. This could/should be later
+ * extended to work with non-ordered edges so that it can be used for general "rope
+ * dynamics" without the need for the vertices or edges to be ordered through the length
+ * of the strands. -jahka */
+ search = cloth->springs;
+ search2 = search->next;
+ while (search && search2) {
+ tspring = search->link;
+ tspring2 = search2->link;
+
+ if (tspring->ij == tspring2->kl) {
+ spring = (ClothSpring *)MEM_callocN(sizeof(ClothSpring), "cloth spring");
+
+ if (!spring) {
+ cloth_free_errorsprings(cloth, edgelist, spring_ref);
+ return 0;
+ }
+
+ spring->ij = tspring2->ij;
+ spring->kl = tspring->kl;
+ spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest,
+ cloth->verts[spring->ij].xrest);
+ spring->type = CLOTH_SPRING_TYPE_BENDING;
+ spring->lin_stiffness = (cloth->verts[spring->kl].bend_stiff +
+ cloth->verts[spring->ij].bend_stiff) /
+ 2.0f;
+ bend_springs++;
+
+ BLI_linklist_prepend(&cloth->springs, spring);
+ }
+
+ search = search->next;
+ search2 = search2->next;
+ }
+ }
+
+ cloth_hair_update_bending_rest_targets(clmd);
+ }
+
+ /* note: the edges may already exist so run reinsert */
+
+ /* insert other near springs in edgeset AFTER bending springs are calculated (for selfcolls) */
+ for (int i = 0; i < numedges; i++) { /* struct springs */
+ BLI_edgeset_add(edgeset, medge[i].v1, medge[i].v2);
+ }
+
+ for (int i = 0; i < numpolys; i++) { /* edge springs */
+ if (mpoly[i].totloop == 4) {
+ BLI_edgeset_add(edgeset, mloop[mpoly[i].loopstart + 0].v, mloop[mpoly[i].loopstart + 2].v);
+ BLI_edgeset_add(edgeset, mloop[mpoly[i].loopstart + 1].v, mloop[mpoly[i].loopstart + 3].v);
+ }
+ }
+
+ MEM_SAFE_FREE(spring_ref);
+
+ cloth->numsprings = struct_springs + shear_springs + bend_springs;
+
+ cloth_free_edgelist(edgelist, mvert_num);
#if 0
- if (G.debug_value > 0)
- printf("avg_len: %f\n", clmd->sim_parms->avg_spring_len);
+ if (G.debug_value > 0)
+ printf("avg_len: %f\n", clmd->sim_parms->avg_spring_len);
#endif
- return 1;
+ return 1;
} /* cloth_build_springs */
/***************************************************************************************
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index eadf190c363..38094841e4a 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -52,10 +52,17 @@
/******************************** Prototypes ********************************/
-static bool collection_child_add(Collection *parent, Collection *collection, const int flag, const bool add_us);
+static bool collection_child_add(Collection *parent,
+ Collection *collection,
+ const int flag,
+ const bool add_us);
static bool collection_child_remove(Collection *parent, Collection *collection);
-static bool collection_object_add(Main *bmain, Collection *collection, Object *ob, int flag, const bool add_us);
-static bool collection_object_remove(Main *bmain, Collection *collection, Object *ob, const bool free_us);
+static bool collection_object_add(
+ Main *bmain, Collection *collection, Object *ob, int flag, const bool add_us);
+static bool collection_object_remove(Main *bmain,
+ Collection *collection,
+ Object *ob,
+ const bool free_us);
static CollectionChild *collection_find_child(Collection *parent, Collection *collection);
static CollectionParent *collection_find_parent(Collection *child, Collection *collection);
@@ -65,30 +72,32 @@ static bool collection_find_child_recursive(Collection *parent, Collection *coll
/***************************** Add Collection *******************************/
/* Add new collection, without view layer syncing. */
-static Collection *collection_add(Main *bmain, Collection *collection_parent, const char *name_custom)
+static Collection *collection_add(Main *bmain,
+ Collection *collection_parent,
+ const char *name_custom)
{
- /* Determine new collection name. */
- char name[MAX_NAME];
+ /* Determine new collection name. */
+ char name[MAX_NAME];
- if (name_custom) {
- STRNCPY(name, name_custom);
- }
- else {
- BKE_collection_new_name_get(collection_parent, name);
- }
+ if (name_custom) {
+ STRNCPY(name, name_custom);
+ }
+ else {
+ BKE_collection_new_name_get(collection_parent, name);
+ }
- /* Create new collection. */
- Collection *collection = BKE_libblock_alloc(bmain, ID_GR, name, 0);
+ /* Create new collection. */
+ Collection *collection = BKE_libblock_alloc(bmain, ID_GR, name, 0);
- /* We increase collection user count when linking to Collections. */
- id_us_min(&collection->id);
+ /* We increase collection user count when linking to Collections. */
+ id_us_min(&collection->id);
- /* Optionally add to parent collection. */
- if (collection_parent) {
- collection_child_add(collection_parent, collection, 0, true);
- }
+ /* Optionally add to parent collection. */
+ if (collection_parent) {
+ collection_child_add(collection_parent, collection, 0, true);
+ }
- return collection;
+ return collection;
}
/**
@@ -97,9 +106,9 @@ static Collection *collection_add(Main *bmain, Collection *collection_parent, co
*/
Collection *BKE_collection_add(Main *bmain, Collection *collection_parent, const char *name_custom)
{
- Collection *collection = collection_add(bmain, collection_parent, name_custom);
- BKE_main_collection_sync(bmain);
- return collection;
+ Collection *collection = collection_add(bmain, collection_parent, name_custom);
+ BKE_main_collection_sync(bmain);
+ return collection;
}
/*********************** Free and Delete Collection ****************************/
@@ -107,14 +116,14 @@ Collection *BKE_collection_add(Main *bmain, Collection *collection_parent, const
/** Free (or release) any data used by this collection (does not free the collection itself). */
void BKE_collection_free(Collection *collection)
{
- /* No animdata here. */
- BKE_previewimg_free(&collection->preview);
+ /* No animdata here. */
+ BKE_previewimg_free(&collection->preview);
- BLI_freelistN(&collection->gobject);
- BLI_freelistN(&collection->children);
- BLI_freelistN(&collection->parents);
+ BLI_freelistN(&collection->gobject);
+ BLI_freelistN(&collection->children);
+ BLI_freelistN(&collection->parents);
- BKE_collection_object_cache_free(collection);
+ BKE_collection_object_cache_free(collection);
}
/**
@@ -123,55 +132,57 @@ void BKE_collection_free(Collection *collection)
*/
bool BKE_collection_delete(Main *bmain, Collection *collection, bool hierarchy)
{
- /* Master collection is not real datablock, can't be removed. */
- if (collection->flag & COLLECTION_IS_MASTER) {
- BLI_assert(!"Scene master collection can't be deleted");
- return false;
- }
-
- if (hierarchy) {
- /* Remove child objects. */
- CollectionObject *cob = collection->gobject.first;
- while (cob != NULL) {
- collection_object_remove(bmain, collection, cob->ob, true);
- cob = collection->gobject.first;
- }
-
- /* Delete all child collections recursively. */
- CollectionChild *child = collection->children.first;
- while (child != NULL) {
- BKE_collection_delete(bmain, child->collection, hierarchy);
- child = collection->children.first;
- }
- }
- else {
- /* Link child collections into parent collection. */
- for (CollectionChild *child = collection->children.first; child; child = child->next) {
- for (CollectionParent *cparent = collection->parents.first; cparent; cparent = cparent->next) {
- Collection *parent = cparent->collection;
- collection_child_add(parent, child->collection, 0, true);
- }
- }
-
- CollectionObject *cob = collection->gobject.first;
- while (cob != NULL) {
- /* Link child object into parent collections. */
- for (CollectionParent *cparent = collection->parents.first; cparent; cparent = cparent->next) {
- Collection *parent = cparent->collection;
- collection_object_add(bmain, parent, cob->ob, 0, true);
- }
-
- /* Remove child object. */
- collection_object_remove(bmain, collection, cob->ob, true);
- cob = collection->gobject.first;
- }
- }
-
- BKE_id_delete(bmain, collection);
-
- BKE_main_collection_sync(bmain);
-
- return true;
+ /* Master collection is not real datablock, can't be removed. */
+ if (collection->flag & COLLECTION_IS_MASTER) {
+ BLI_assert(!"Scene master collection can't be deleted");
+ return false;
+ }
+
+ if (hierarchy) {
+ /* Remove child objects. */
+ CollectionObject *cob = collection->gobject.first;
+ while (cob != NULL) {
+ collection_object_remove(bmain, collection, cob->ob, true);
+ cob = collection->gobject.first;
+ }
+
+ /* Delete all child collections recursively. */
+ CollectionChild *child = collection->children.first;
+ while (child != NULL) {
+ BKE_collection_delete(bmain, child->collection, hierarchy);
+ child = collection->children.first;
+ }
+ }
+ else {
+ /* Link child collections into parent collection. */
+ for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ for (CollectionParent *cparent = collection->parents.first; cparent;
+ cparent = cparent->next) {
+ Collection *parent = cparent->collection;
+ collection_child_add(parent, child->collection, 0, true);
+ }
+ }
+
+ CollectionObject *cob = collection->gobject.first;
+ while (cob != NULL) {
+ /* Link child object into parent collections. */
+ for (CollectionParent *cparent = collection->parents.first; cparent;
+ cparent = cparent->next) {
+ Collection *parent = cparent->collection;
+ collection_object_add(bmain, parent, cob->ob, 0, true);
+ }
+
+ /* Remove child object. */
+ collection_object_remove(bmain, collection, cob->ob, true);
+ cob = collection->gobject.first;
+ }
+ }
+
+ BKE_id_delete(bmain, collection);
+
+ BKE_main_collection_sync(bmain);
+
+ return true;
}
/***************************** Collection Copy *******************************/
@@ -184,100 +195,107 @@ bool BKE_collection_delete(Main *bmain, Collection *collection, bool hierarchy)
*
* \param flag: Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
*/
-void BKE_collection_copy_data(
- Main *bmain, Collection *collection_dst, const Collection *collection_src, const int flag)
-{
- /* Do not copy collection's preview (same behavior as for objects). */
- if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) { /* XXX TODO temp hack */
- BKE_previewimg_id_copy(&collection_dst->id, &collection_src->id);
- }
- else {
- collection_dst->preview = NULL;
- }
-
- collection_dst->flag &= ~COLLECTION_HAS_OBJECT_CACHE;
- BLI_listbase_clear(&collection_dst->object_cache);
-
- BLI_listbase_clear(&collection_dst->gobject);
- BLI_listbase_clear(&collection_dst->children);
- BLI_listbase_clear(&collection_dst->parents);
-
- for (CollectionChild *child = collection_src->children.first; child; child = child->next) {
- collection_child_add(collection_dst, child->collection, flag, false);
- }
- for (CollectionObject *cob = collection_src->gobject.first; cob; cob = cob->next) {
- collection_object_add(bmain, collection_dst, cob->ob, flag, false);
- }
-}
-
-static Collection *collection_duplicate_recursive(
- Main *bmain, Collection *parent, Collection *collection_old,
- const bool do_hierarchy, const bool do_objects, const bool do_obdata)
-{
- Collection *collection_new;
- bool do_full_process = false;
- const int object_dupflag = (do_obdata) ? U.dupflag : 0;
-
- if (!do_hierarchy || collection_old->id.newid == NULL) {
- BKE_id_copy(bmain, &collection_old->id, (ID **)&collection_new);
- id_us_min(&collection_new->id); /* Copying add one user by default, need to get rid of that one. */
-
- if (do_hierarchy) {
- ID_NEW_SET(collection_old, collection_new);
- }
- do_full_process = true;
- }
- else {
- collection_new = (Collection *)collection_old->id.newid;
- }
-
- /* Optionally add to parent (we always want to do that, even if collection_old had already been duplicated). */
- if (parent != NULL) {
- if (collection_child_add(parent, collection_new, 0, true)) {
- /* Put collection right after existing one. */
- CollectionChild *child = collection_find_child(parent, collection_old);
- CollectionChild *child_new = collection_find_child(parent, collection_new);
-
- if (child && child_new) {
- BLI_remlink(&parent->children, child_new);
- BLI_insertlinkafter(&parent->children, child, child_new);
- }
- }
- }
-
- /* If we are not doing any kind of deep-copy, we can return immediately.
- * False do_full_process means collection_old had already been duplicated, no need to redo some deep-copy on it. */
- if (!do_hierarchy || !do_full_process) {
- return collection_new;
- }
-
- if (do_objects) {
- /* We can loop on collection_old's objects, that list is currently identical the collection_new' objects,
- * and won't be changed here. */
- for (CollectionObject *cob = collection_old->gobject.first; cob; cob = cob->next) {
- Object *ob_old = cob->ob;
- Object *ob_new = (Object *)ob_old->id.newid;
-
- if (ob_new == NULL) {
- ob_new = BKE_object_duplicate(bmain, ob_old, object_dupflag);
- ID_NEW_SET(ob_old, ob_new);
- }
-
- collection_object_add(bmain, collection_new, ob_new, 0, true);
- collection_object_remove(bmain, collection_new, ob_old, false);
- }
- }
-
- /* We can loop on collection_old's children, that list is currently identical the collection_new' children,
- * and won't be changed here. */
- for (CollectionChild *child = collection_old->children.first; child; child = child->next) {
- Collection *child_collection_old = child->collection;
-
- collection_duplicate_recursive(bmain, collection_new, child_collection_old, do_hierarchy, do_objects, do_obdata);
- collection_child_remove(collection_new, child_collection_old);
- }
-
- return collection_new;
+void BKE_collection_copy_data(Main *bmain,
+ Collection *collection_dst,
+ const Collection *collection_src,
+ const int flag)
+{
+ /* Do not copy collection's preview (same behavior as for objects). */
+ if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) { /* XXX TODO temp hack */
+ BKE_previewimg_id_copy(&collection_dst->id, &collection_src->id);
+ }
+ else {
+ collection_dst->preview = NULL;
+ }
+
+ collection_dst->flag &= ~COLLECTION_HAS_OBJECT_CACHE;
+ BLI_listbase_clear(&collection_dst->object_cache);
+
+ BLI_listbase_clear(&collection_dst->gobject);
+ BLI_listbase_clear(&collection_dst->children);
+ BLI_listbase_clear(&collection_dst->parents);
+
+ for (CollectionChild *child = collection_src->children.first; child; child = child->next) {
+ collection_child_add(collection_dst, child->collection, flag, false);
+ }
+ for (CollectionObject *cob = collection_src->gobject.first; cob; cob = cob->next) {
+ collection_object_add(bmain, collection_dst, cob->ob, flag, false);
+ }
+}
+
+static Collection *collection_duplicate_recursive(Main *bmain,
+ Collection *parent,
+ Collection *collection_old,
+ const bool do_hierarchy,
+ const bool do_objects,
+ const bool do_obdata)
+{
+ Collection *collection_new;
+ bool do_full_process = false;
+ const int object_dupflag = (do_obdata) ? U.dupflag : 0;
+
+ if (!do_hierarchy || collection_old->id.newid == NULL) {
+ BKE_id_copy(bmain, &collection_old->id, (ID **)&collection_new);
+ id_us_min(
+ &collection_new->id); /* Copying add one user by default, need to get rid of that one. */
+
+ if (do_hierarchy) {
+ ID_NEW_SET(collection_old, collection_new);
+ }
+ do_full_process = true;
+ }
+ else {
+ collection_new = (Collection *)collection_old->id.newid;
+ }
+
+ /* Optionally add to parent (we always want to do that, even if collection_old had already been duplicated). */
+ if (parent != NULL) {
+ if (collection_child_add(parent, collection_new, 0, true)) {
+ /* Put collection right after existing one. */
+ CollectionChild *child = collection_find_child(parent, collection_old);
+ CollectionChild *child_new = collection_find_child(parent, collection_new);
+
+ if (child && child_new) {
+ BLI_remlink(&parent->children, child_new);
+ BLI_insertlinkafter(&parent->children, child, child_new);
+ }
+ }
+ }
+
+ /* If we are not doing any kind of deep-copy, we can return immediately.
+ * False do_full_process means collection_old had already been duplicated, no need to redo some deep-copy on it. */
+ if (!do_hierarchy || !do_full_process) {
+ return collection_new;
+ }
+
+ if (do_objects) {
+ /* We can loop on collection_old's objects, that list is currently identical the collection_new' objects,
+ * and won't be changed here. */
+ for (CollectionObject *cob = collection_old->gobject.first; cob; cob = cob->next) {
+ Object *ob_old = cob->ob;
+ Object *ob_new = (Object *)ob_old->id.newid;
+
+ if (ob_new == NULL) {
+ ob_new = BKE_object_duplicate(bmain, ob_old, object_dupflag);
+ ID_NEW_SET(ob_old, ob_new);
+ }
+
+ collection_object_add(bmain, collection_new, ob_new, 0, true);
+ collection_object_remove(bmain, collection_new, ob_old, false);
+ }
+ }
+
+ /* We can loop on collection_old's children, that list is currently identical the collection_new' children,
+ * and won't be changed here. */
+ for (CollectionChild *child = collection_old->children.first; child; child = child->next) {
+ Collection *child_collection_old = child->collection;
+
+ collection_duplicate_recursive(
+ bmain, collection_new, child_collection_old, do_hierarchy, do_objects, do_obdata);
+ collection_child_remove(collection_new, child_collection_old);
+ }
+
+ return collection_new;
}
/**
@@ -288,7 +306,7 @@ static Collection *collection_duplicate_recursive(
*/
Collection *BKE_collection_copy(Main *bmain, Collection *parent, Collection *collection)
{
- return BKE_collection_duplicate(bmain, parent, collection, false, false, false);
+ return BKE_collection_duplicate(bmain, parent, collection, false, false, false);
}
/**
@@ -304,50 +322,53 @@ Collection *BKE_collection_copy(Main *bmain, Collection *parent, Collection *col
* \param do_obdata If true, it will also make deep duplicates of objects, using behavior defined in user settings
* (U.dupflag). This one does nothing if \a do_hierarchy and \a do_objects are not set.
*/
-Collection *BKE_collection_duplicate(
- Main *bmain, Collection *parent, Collection *collection,
- const bool do_hierarchy, const bool do_objects, const bool do_obdata)
+Collection *BKE_collection_duplicate(Main *bmain,
+ Collection *parent,
+ Collection *collection,
+ const bool do_hierarchy,
+ const bool do_objects,
+ const bool do_obdata)
{
- /* It's not allowed to copy the master collection. */
- if (collection->flag & COLLECTION_IS_MASTER) {
- BLI_assert("!Master collection can't be duplicated");
- return NULL;
- }
+ /* It's not allowed to copy the master collection. */
+ if (collection->flag & COLLECTION_IS_MASTER) {
+ BLI_assert("!Master collection can't be duplicated");
+ return NULL;
+ }
- if (do_hierarchy) {
- BKE_main_id_tag_all(bmain, LIB_TAG_NEW, false);
- BKE_main_id_clear_newpoins(bmain);
- }
+ if (do_hierarchy) {
+ BKE_main_id_tag_all(bmain, LIB_TAG_NEW, false);
+ BKE_main_id_clear_newpoins(bmain);
+ }
- Collection *collection_new = collection_duplicate_recursive(
- bmain, parent, collection, do_hierarchy, do_objects, do_obdata);
+ Collection *collection_new = collection_duplicate_recursive(
+ bmain, parent, collection, do_hierarchy, do_objects, do_obdata);
- /* This code will follows into all ID links using an ID tagged with LIB_TAG_NEW.*/
- BKE_libblock_relink_to_newid(&collection_new->id);
+ /* This code will follows into all ID links using an ID tagged with LIB_TAG_NEW.*/
+ BKE_libblock_relink_to_newid(&collection_new->id);
- if (do_hierarchy) {
- /* Cleanup. */
- BKE_main_id_tag_all(bmain, LIB_TAG_NEW, false);
- BKE_main_id_clear_newpoins(bmain);
- }
+ if (do_hierarchy) {
+ /* Cleanup. */
+ BKE_main_id_tag_all(bmain, LIB_TAG_NEW, false);
+ BKE_main_id_clear_newpoins(bmain);
+ }
- BKE_main_collection_sync(bmain);
+ BKE_main_collection_sync(bmain);
- return collection_new;
+ return collection_new;
}
Collection *BKE_collection_copy_master(Main *bmain, Collection *collection, const int flag)
{
- BLI_assert(collection->flag & COLLECTION_IS_MASTER);
+ BLI_assert(collection->flag & COLLECTION_IS_MASTER);
- Collection *collection_dst = MEM_dupallocN(collection);
- BKE_collection_copy_data(bmain, collection_dst, collection, flag);
- return collection_dst;
+ Collection *collection_dst = MEM_dupallocN(collection);
+ BKE_collection_copy_data(bmain, collection_dst, collection, flag);
+ return collection_dst;
}
void BKE_collection_make_local(Main *bmain, Collection *collection, const bool lib_local)
{
- BKE_id_make_local_generic(bmain, &collection->id, true, lib_local);
+ BKE_id_make_local_generic(bmain, &collection->id, true, lib_local);
}
/********************************* Naming *******************************/
@@ -357,24 +378,24 @@ void BKE_collection_make_local(Main *bmain, Collection *collection, const bool l
*/
void BKE_collection_new_name_get(Collection *collection_parent, char *rname)
{
- char *name;
+ char *name;
- if (!collection_parent) {
- name = BLI_strdup("Collection");
- }
- else if (collection_parent->flag & COLLECTION_IS_MASTER) {
- name = BLI_sprintfN("Collection %d", BLI_listbase_count(&collection_parent->children) + 1);
- }
- else {
- const int number = BLI_listbase_count(&collection_parent->children) + 1;
- const int digits = integer_digits_i(number);
- const int max_len =
- sizeof(collection_parent->id.name) - 1 /* NULL terminator */ - (1 + digits) /* " %d" */ - 2 /* ID */;
- name = BLI_sprintfN("%.*s %d", max_len, collection_parent->id.name + 2, number);
- }
+ if (!collection_parent) {
+ name = BLI_strdup("Collection");
+ }
+ else if (collection_parent->flag & COLLECTION_IS_MASTER) {
+ name = BLI_sprintfN("Collection %d", BLI_listbase_count(&collection_parent->children) + 1);
+ }
+ else {
+ const int number = BLI_listbase_count(&collection_parent->children) + 1;
+ const int digits = integer_digits_i(number);
+ const int max_len = sizeof(collection_parent->id.name) - 1 /* NULL terminator */ -
+ (1 + digits) /* " %d" */ - 2 /* ID */;
+ name = BLI_sprintfN("%.*s %d", max_len, collection_parent->id.name + 2, number);
+ }
- BLI_strncpy(rname, name, MAX_NAME);
- MEM_freeN(name);
+ BLI_strncpy(rname, name, MAX_NAME);
+ MEM_freeN(name);
}
/**
@@ -382,273 +403,278 @@ void BKE_collection_new_name_get(Collection *collection_parent, char *rname)
*/
const char *BKE_collection_ui_name_get(struct Collection *collection)
{
- if (collection->flag & COLLECTION_IS_MASTER) {
- return IFACE_("Scene Collection");
- }
- else {
- return collection->id.name + 2;
- }
+ if (collection->flag & COLLECTION_IS_MASTER) {
+ return IFACE_("Scene Collection");
+ }
+ else {
+ return collection->id.name + 2;
+ }
}
/* **************** Object List Cache *******************/
static void collection_object_cache_fill(ListBase *lb, Collection *collection, int parent_restrict)
{
- int child_restrict = collection->flag | parent_restrict;
+ int child_restrict = collection->flag | parent_restrict;
- for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
- Base *base = BLI_findptr(lb, cob->ob, offsetof(Base, object));
+ for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ Base *base = BLI_findptr(lb, cob->ob, offsetof(Base, object));
- if (base == NULL) {
- base = MEM_callocN(sizeof(Base), "Object Base");
- base->object = cob->ob;
- BLI_addtail(lb, base);
- }
+ if (base == NULL) {
+ base = MEM_callocN(sizeof(Base), "Object Base");
+ base->object = cob->ob;
+ BLI_addtail(lb, base);
+ }
- int object_restrict = base->object->restrictflag;
+ int object_restrict = base->object->restrictflag;
- if (((child_restrict & COLLECTION_RESTRICT_VIEW) == 0) &&
- ((object_restrict & OB_RESTRICT_VIEW) == 0))
- {
- base->flag |= BASE_ENABLED_VIEWPORT;
- }
+ if (((child_restrict & COLLECTION_RESTRICT_VIEW) == 0) &&
+ ((object_restrict & OB_RESTRICT_VIEW) == 0)) {
+ base->flag |= BASE_ENABLED_VIEWPORT;
+ }
- if (((child_restrict & COLLECTION_RESTRICT_RENDER) == 0) &&
- ((object_restrict & OB_RESTRICT_RENDER) == 0))
- {
- base->flag |= BASE_ENABLED_RENDER;
- }
- }
+ if (((child_restrict & COLLECTION_RESTRICT_RENDER) == 0) &&
+ ((object_restrict & OB_RESTRICT_RENDER) == 0)) {
+ base->flag |= BASE_ENABLED_RENDER;
+ }
+ }
- for (CollectionChild *child = collection->children.first; child; child = child->next) {
- collection_object_cache_fill(lb, child->collection, child_restrict);
- }
+ for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ collection_object_cache_fill(lb, child->collection, child_restrict);
+ }
}
ListBase BKE_collection_object_cache_get(Collection *collection)
{
- if (!(collection->flag & COLLECTION_HAS_OBJECT_CACHE)) {
- static ThreadMutex cache_lock = BLI_MUTEX_INITIALIZER;
+ if (!(collection->flag & COLLECTION_HAS_OBJECT_CACHE)) {
+ static ThreadMutex cache_lock = BLI_MUTEX_INITIALIZER;
- BLI_mutex_lock(&cache_lock);
- if (!(collection->flag & COLLECTION_HAS_OBJECT_CACHE)) {
- collection_object_cache_fill(&collection->object_cache, collection, 0);
- collection->flag |= COLLECTION_HAS_OBJECT_CACHE;
- }
- BLI_mutex_unlock(&cache_lock);
- }
+ BLI_mutex_lock(&cache_lock);
+ if (!(collection->flag & COLLECTION_HAS_OBJECT_CACHE)) {
+ collection_object_cache_fill(&collection->object_cache, collection, 0);
+ collection->flag |= COLLECTION_HAS_OBJECT_CACHE;
+ }
+ BLI_mutex_unlock(&cache_lock);
+ }
- return collection->object_cache;
+ return collection->object_cache;
}
static void collection_object_cache_free(Collection *collection)
{
- /* Clear own cache an for all parents, since those are affected by changes as well. */
- collection->flag &= ~COLLECTION_HAS_OBJECT_CACHE;
- BLI_freelistN(&collection->object_cache);
+ /* Clear own cache an for all parents, since those are affected by changes as well. */
+ collection->flag &= ~COLLECTION_HAS_OBJECT_CACHE;
+ BLI_freelistN(&collection->object_cache);
- for (CollectionParent *parent = collection->parents.first; parent; parent = parent->next) {
- collection_object_cache_free(parent->collection);
- }
+ for (CollectionParent *parent = collection->parents.first; parent; parent = parent->next) {
+ collection_object_cache_free(parent->collection);
+ }
}
void BKE_collection_object_cache_free(Collection *collection)
{
- collection_object_cache_free(collection);
+ collection_object_cache_free(collection);
}
Base *BKE_collection_or_layer_objects(const ViewLayer *view_layer, Collection *collection)
{
- if (collection) {
- return BKE_collection_object_cache_get(collection).first;
- }
- else {
- return FIRSTBASE(view_layer);
- }
+ if (collection) {
+ return BKE_collection_object_cache_get(collection).first;
+ }
+ else {
+ return FIRSTBASE(view_layer);
+ }
}
/*********************** Scene Master Collection ***************/
Collection *BKE_collection_master_add()
{
- /* Not an actual datablock, but owned by scene. */
- Collection *master_collection = MEM_callocN(sizeof(Collection), "Master Collection");
- STRNCPY(master_collection->id.name, "GRMaster Collection");
- master_collection->flag |= COLLECTION_IS_MASTER;
- return master_collection;
+ /* Not an actual datablock, but owned by scene. */
+ Collection *master_collection = MEM_callocN(sizeof(Collection), "Master Collection");
+ STRNCPY(master_collection->id.name, "GRMaster Collection");
+ master_collection->flag |= COLLECTION_IS_MASTER;
+ return master_collection;
}
Collection *BKE_collection_master(const Scene *scene)
{
- return scene->master_collection;
+ return scene->master_collection;
}
Scene *BKE_collection_master_scene_search(const Main *bmain, const Collection *master_collection)
{
- BLI_assert((master_collection->flag & COLLECTION_IS_MASTER) != 0);
+ BLI_assert((master_collection->flag & COLLECTION_IS_MASTER) != 0);
- for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
- if (scene->master_collection == master_collection) {
- return scene;
- }
- }
+ for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
+ if (scene->master_collection == master_collection) {
+ return scene;
+ }
+ }
- return NULL;
+ return NULL;
}
/*********************** Cyclic Checks ************************/
static bool collection_object_cyclic_check_internal(Object *object, Collection *collection)
{
- if (object->instance_collection) {
- Collection *dup_collection = object->instance_collection;
- if ((dup_collection->id.tag & LIB_TAG_DOIT) == 0) {
- /* Cycle already exists in collections, let's prevent further crappyness */
- return true;
- }
- /* flag the object to identify cyclic dependencies in further dupli collections */
- dup_collection->id.tag &= ~LIB_TAG_DOIT;
-
- if (dup_collection == collection) {
- return true;
- }
- else {
- FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(dup_collection, collection_object)
- {
- if (collection_object_cyclic_check_internal(collection_object, dup_collection)) {
- return true;
- }
- }
- FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
- }
-
- /* un-flag the object, it's allowed to have the same collection multiple times in parallel */
- dup_collection->id.tag |= LIB_TAG_DOIT;
- }
-
- return false;
+ if (object->instance_collection) {
+ Collection *dup_collection = object->instance_collection;
+ if ((dup_collection->id.tag & LIB_TAG_DOIT) == 0) {
+ /* Cycle already exists in collections, let's prevent further crappyness */
+ return true;
+ }
+ /* flag the object to identify cyclic dependencies in further dupli collections */
+ dup_collection->id.tag &= ~LIB_TAG_DOIT;
+
+ if (dup_collection == collection) {
+ return true;
+ }
+ else {
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (dup_collection, collection_object) {
+ if (collection_object_cyclic_check_internal(collection_object, dup_collection)) {
+ return true;
+ }
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+ }
+
+ /* un-flag the object, it's allowed to have the same collection multiple times in parallel */
+ dup_collection->id.tag |= LIB_TAG_DOIT;
+ }
+
+ return false;
}
bool BKE_collection_object_cyclic_check(Main *bmain, Object *object, Collection *collection)
{
- /* first flag all collections */
- BKE_main_id_tag_listbase(&bmain->collections, LIB_TAG_DOIT, true);
+ /* first flag all collections */
+ BKE_main_id_tag_listbase(&bmain->collections, LIB_TAG_DOIT, true);
- return collection_object_cyclic_check_internal(object, collection);
+ return collection_object_cyclic_check_internal(object, collection);
}
/******************* Collection Object Membership *******************/
bool BKE_collection_has_object(Collection *collection, Object *ob)
{
- if (ELEM(NULL, collection, ob)) {
- return false;
- }
+ if (ELEM(NULL, collection, ob)) {
+ return false;
+ }
- return (BLI_findptr(&collection->gobject, ob, offsetof(CollectionObject, ob)));
+ return (BLI_findptr(&collection->gobject, ob, offsetof(CollectionObject, ob)));
}
bool BKE_collection_has_object_recursive(Collection *collection, Object *ob)
{
- if (ELEM(NULL, collection, ob)) {
- return false;
- }
+ if (ELEM(NULL, collection, ob)) {
+ return false;
+ }
- const ListBase objects = BKE_collection_object_cache_get(collection);
- return (BLI_findptr(&objects, ob, offsetof(Base, object)));
+ const ListBase objects = BKE_collection_object_cache_get(collection);
+ return (BLI_findptr(&objects, ob, offsetof(Base, object)));
}
static Collection *collection_next_find(Main *bmain, Scene *scene, Collection *collection)
{
- if (scene && collection == BKE_collection_master(scene)) {
- return bmain->collections.first;
- }
- else {
- return collection->id.next;
- }
-}
-
-Collection *BKE_collection_object_find(Main *bmain, Scene *scene, Collection *collection, Object *ob)
-{
- if (collection) {
- collection = collection_next_find(bmain, scene, collection);
- }
- else if (scene) {
- collection = BKE_collection_master(scene);
- }
- else {
- collection = bmain->collections.first;
- }
-
- while (collection) {
- if (BKE_collection_has_object(collection, ob))
- return collection;
- collection = collection_next_find(bmain, scene, collection);
- }
- return NULL;
+ if (scene && collection == BKE_collection_master(scene)) {
+ return bmain->collections.first;
+ }
+ else {
+ return collection->id.next;
+ }
+}
+
+Collection *BKE_collection_object_find(Main *bmain,
+ Scene *scene,
+ Collection *collection,
+ Object *ob)
+{
+ if (collection) {
+ collection = collection_next_find(bmain, scene, collection);
+ }
+ else if (scene) {
+ collection = BKE_collection_master(scene);
+ }
+ else {
+ collection = bmain->collections.first;
+ }
+
+ while (collection) {
+ if (BKE_collection_has_object(collection, ob))
+ return collection;
+ collection = collection_next_find(bmain, scene, collection);
+ }
+ return NULL;
}
bool BKE_collection_is_empty(Collection *collection)
{
- return BLI_listbase_is_empty(&collection->gobject) && BLI_listbase_is_empty(&collection->children);
+ return BLI_listbase_is_empty(&collection->gobject) &&
+ BLI_listbase_is_empty(&collection->children);
}
/********************** Collection Objects *********************/
-static bool collection_object_add(Main *bmain, Collection *collection, Object *ob, int flag, const bool add_us)
+static bool collection_object_add(
+ Main *bmain, Collection *collection, Object *ob, int flag, const bool add_us)
{
- if (ob->instance_collection) {
- /* Cyclic dependency check. */
- if (collection_find_child_recursive(ob->instance_collection, collection)) {
- return false;
- }
- }
+ if (ob->instance_collection) {
+ /* Cyclic dependency check. */
+ if (collection_find_child_recursive(ob->instance_collection, collection)) {
+ return false;
+ }
+ }
- CollectionObject *cob = BLI_findptr(&collection->gobject, ob, offsetof(CollectionObject, ob));
- if (cob) {
- return false;
- }
+ CollectionObject *cob = BLI_findptr(&collection->gobject, ob, offsetof(CollectionObject, ob));
+ if (cob) {
+ return false;
+ }
- cob = MEM_callocN(sizeof(CollectionObject), __func__);
- cob->ob = ob;
- BLI_addtail(&collection->gobject, cob);
- BKE_collection_object_cache_free(collection);
+ cob = MEM_callocN(sizeof(CollectionObject), __func__);
+ cob->ob = ob;
+ BLI_addtail(&collection->gobject, cob);
+ BKE_collection_object_cache_free(collection);
- if (add_us && (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- id_us_plus(&ob->id);
- }
+ if (add_us && (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id_us_plus(&ob->id);
+ }
- if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
- DEG_id_tag_update_ex(bmain, &collection->id, ID_RECALC_COPY_ON_WRITE);
- }
+ if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
+ DEG_id_tag_update_ex(bmain, &collection->id, ID_RECALC_COPY_ON_WRITE);
+ }
- if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
- BKE_rigidbody_main_collection_object_add(bmain, collection, ob);
- }
+ if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
+ BKE_rigidbody_main_collection_object_add(bmain, collection, ob);
+ }
- return true;
+ return true;
}
-static bool collection_object_remove(Main *bmain, Collection *collection, Object *ob, const bool free_us)
+static bool collection_object_remove(Main *bmain,
+ Collection *collection,
+ Object *ob,
+ const bool free_us)
{
- CollectionObject *cob = BLI_findptr(&collection->gobject, ob, offsetof(CollectionObject, ob));
- if (cob == NULL) {
- return false;
- }
+ CollectionObject *cob = BLI_findptr(&collection->gobject, ob, offsetof(CollectionObject, ob));
+ if (cob == NULL) {
+ return false;
+ }
- BLI_freelinkN(&collection->gobject, cob);
- BKE_collection_object_cache_free(collection);
+ BLI_freelinkN(&collection->gobject, cob);
+ BKE_collection_object_cache_free(collection);
- if (free_us) {
- BKE_id_free_us(bmain, ob);
- }
- else {
- id_us_min(&ob->id);
- }
+ if (free_us) {
+ BKE_id_free_us(bmain, ob);
+ }
+ else {
+ id_us_min(&ob->id);
+ }
- DEG_id_tag_update_ex(bmain, &collection->id, ID_RECALC_COPY_ON_WRITE);
+ DEG_id_tag_update_ex(bmain, &collection->id, ID_RECALC_COPY_ON_WRITE);
- return true;
+ return true;
}
/**
@@ -656,19 +682,19 @@ static bool collection_object_remove(Main *bmain, Collection *collection, Object
*/
bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob)
{
- if (ELEM(NULL, collection, ob)) {
- return false;
- }
+ if (ELEM(NULL, collection, ob)) {
+ return false;
+ }
- if (!collection_object_add(bmain, collection, ob, 0, true)) {
- return false;
- }
+ if (!collection_object_add(bmain, collection, ob, 0, true)) {
+ return false;
+ }
- if (BKE_collection_is_in_scene(collection)) {
- BKE_main_collection_sync(bmain);
- }
+ if (BKE_collection_is_in_scene(collection)) {
+ BKE_main_collection_sync(bmain);
+ }
- return true;
+ return true;
}
/**
@@ -677,61 +703,62 @@ bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob)
*/
void BKE_collection_object_add_from(Main *bmain, Scene *scene, Object *ob_src, Object *ob_dst)
{
- FOREACH_SCENE_COLLECTION_BEGIN(scene, collection)
- {
- if (BKE_collection_has_object(collection, ob_src)) {
- collection_object_add(bmain, collection, ob_dst, 0, true);
- }
- }
- FOREACH_SCENE_COLLECTION_END;
+ FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
+ if (BKE_collection_has_object(collection, ob_src)) {
+ collection_object_add(bmain, collection, ob_dst, 0, true);
+ }
+ }
+ FOREACH_SCENE_COLLECTION_END;
- BKE_main_collection_sync(bmain);
+ BKE_main_collection_sync(bmain);
}
/**
* Remove object from collection.
*/
-bool BKE_collection_object_remove(Main *bmain, Collection *collection, Object *ob, const bool free_us)
+bool BKE_collection_object_remove(Main *bmain,
+ Collection *collection,
+ Object *ob,
+ const bool free_us)
{
- if (ELEM(NULL, collection, ob)) {
- return false;
- }
+ if (ELEM(NULL, collection, ob)) {
+ return false;
+ }
- if (!collection_object_remove(bmain, collection, ob, free_us)) {
- return false;
- }
+ if (!collection_object_remove(bmain, collection, ob, free_us)) {
+ return false;
+ }
- if (BKE_collection_is_in_scene(collection)) {
- BKE_main_collection_sync(bmain);
- }
+ if (BKE_collection_is_in_scene(collection)) {
+ BKE_main_collection_sync(bmain);
+ }
- return true;
+ return true;
}
/**
* Remove object from all collections of scene
* \param scene_collection_skip: Don't remove base from this collection.
*/
-static bool scene_collections_object_remove(Main *bmain, Scene *scene, Object *ob, const bool free_us,
- Collection *collection_skip)
+static bool scene_collections_object_remove(
+ Main *bmain, Scene *scene, Object *ob, const bool free_us, Collection *collection_skip)
{
- bool removed = false;
+ bool removed = false;
- if (collection_skip == NULL) {
- BKE_scene_remove_rigidbody_object(bmain, scene, ob);
- }
+ if (collection_skip == NULL) {
+ BKE_scene_remove_rigidbody_object(bmain, scene, ob);
+ }
- FOREACH_SCENE_COLLECTION_BEGIN(scene, collection)
- {
- if (collection != collection_skip) {
- removed |= collection_object_remove(bmain, collection, ob, free_us);
- }
- }
- FOREACH_SCENE_COLLECTION_END;
+ FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
+ if (collection != collection_skip) {
+ removed |= collection_object_remove(bmain, collection, ob, free_us);
+ }
+ }
+ FOREACH_SCENE_COLLECTION_END;
- BKE_main_collection_sync(bmain);
+ BKE_main_collection_sync(bmain);
- return removed;
+ return removed;
}
/**
@@ -739,7 +766,7 @@ static bool scene_collections_object_remove(Main *bmain, Scene *scene, Object *o
*/
bool BKE_scene_collections_object_remove(Main *bmain, Scene *scene, Object *ob, const bool free_us)
{
- return scene_collections_object_remove(bmain, scene, ob, free_us, NULL);
+ return scene_collections_object_remove(bmain, scene, ob, free_us, NULL);
}
/*
@@ -749,54 +776,55 @@ bool BKE_scene_collections_object_remove(Main *bmain, Scene *scene, Object *ob,
*/
static void collection_object_remove_nulls(Collection *collection)
{
- bool changed = false;
+ bool changed = false;
- for (CollectionObject *cob = collection->gobject.first, *cob_next = NULL; cob; cob = cob_next) {
- cob_next = cob->next;
+ for (CollectionObject *cob = collection->gobject.first, *cob_next = NULL; cob; cob = cob_next) {
+ cob_next = cob->next;
- if (cob->ob == NULL) {
- BLI_freelinkN(&collection->gobject, cob);
- changed = true;
- }
- }
+ if (cob->ob == NULL) {
+ BLI_freelinkN(&collection->gobject, cob);
+ changed = true;
+ }
+ }
- if (changed) {
- BKE_collection_object_cache_free(collection);
- }
+ if (changed) {
+ BKE_collection_object_cache_free(collection);
+ }
}
void BKE_collections_object_remove_nulls(Main *bmain)
{
- for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
- collection_object_remove_nulls(scene->master_collection);
- }
+ for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
+ collection_object_remove_nulls(scene->master_collection);
+ }
- for (Collection *collection = bmain->collections.first; collection; collection = collection->id.next) {
- collection_object_remove_nulls(collection);
- }
+ for (Collection *collection = bmain->collections.first; collection;
+ collection = collection->id.next) {
+ collection_object_remove_nulls(collection);
+ }
}
static void collection_null_children_remove(Collection *collection)
{
- for (CollectionChild *child = collection->children.first, *child_next = NULL; child; child = child_next) {
- child_next = child->next;
+ for (CollectionChild *child = collection->children.first, *child_next = NULL; child;
+ child = child_next) {
+ child_next = child->next;
- if (child->collection == NULL) {
- BLI_freelinkN(&collection->children, child);
- }
- }
+ if (child->collection == NULL) {
+ BLI_freelinkN(&collection->children, child);
+ }
+ }
}
static void collection_missing_parents_remove(Collection *collection)
{
- for (CollectionParent *parent = collection->parents.first, *parent_next; parent != NULL; parent = parent_next) {
- parent_next = parent->next;
- if ((parent->collection == NULL) ||
- !collection_find_child(parent->collection, collection))
- {
- BLI_freelinkN(&collection->parents, parent);
- }
- }
+ for (CollectionParent *parent = collection->parents.first, *parent_next; parent != NULL;
+ parent = parent_next) {
+ parent_next = parent->next;
+ if ((parent->collection == NULL) || !collection_find_child(parent->collection, collection)) {
+ BLI_freelinkN(&collection->parents, parent);
+ }
+ }
}
/**
@@ -810,36 +838,39 @@ static void collection_missing_parents_remove(Collection *collection)
*/
void BKE_collections_child_remove_nulls(Main *bmain, Collection *collection)
{
- if (collection == NULL) {
- /* We need to do the checks in two steps when more than one collection may be involved,
- * otherwise we can miss some cases...
- * Also, master collections are not in bmain, so we also need to loop over scenes.
- */
- for (collection = bmain->collections.first; collection != NULL; collection = collection->id.next) {
- collection_null_children_remove(collection);
- }
- for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
- collection_null_children_remove(BKE_collection_master(scene));
- }
-
- for (collection = bmain->collections.first; collection != NULL; collection = collection->id.next) {
- collection_missing_parents_remove(collection);
- }
- for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
- collection_missing_parents_remove(BKE_collection_master(scene));
- }
- }
- else {
- for (CollectionParent *parent = collection->parents.first, *parent_next; parent; parent = parent_next) {
- parent_next = parent->next;
-
- collection_null_children_remove(parent->collection);
-
- if (!collection_find_child(parent->collection, collection)) {
- BLI_freelinkN(&collection->parents, parent);
- }
- }
- }
+ if (collection == NULL) {
+ /* We need to do the checks in two steps when more than one collection may be involved,
+ * otherwise we can miss some cases...
+ * Also, master collections are not in bmain, so we also need to loop over scenes.
+ */
+ for (collection = bmain->collections.first; collection != NULL;
+ collection = collection->id.next) {
+ collection_null_children_remove(collection);
+ }
+ for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
+ collection_null_children_remove(BKE_collection_master(scene));
+ }
+
+ for (collection = bmain->collections.first; collection != NULL;
+ collection = collection->id.next) {
+ collection_missing_parents_remove(collection);
+ }
+ for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
+ collection_missing_parents_remove(BKE_collection_master(scene));
+ }
+ }
+ else {
+ for (CollectionParent *parent = collection->parents.first, *parent_next; parent;
+ parent = parent_next) {
+ parent_next = parent->next;
+
+ collection_null_children_remove(parent->collection);
+
+ if (!collection_find_child(parent->collection, collection)) {
+ BLI_freelinkN(&collection->parents, parent);
+ }
+ }
+ }
}
/**
@@ -848,175 +879,180 @@ void BKE_collections_child_remove_nulls(Main *bmain, Collection *collection)
* If source collection is NULL move it from all the existing collections.
*/
void BKE_collection_object_move(
- Main *bmain, Scene *scene, Collection *collection_dst, Collection *collection_src, Object *ob)
-{
- /* In both cases we first add the object, then remove it from the other collections.
- * Otherwise we lose the original base and whether it was active and selected. */
- if (collection_src != NULL) {
- if (BKE_collection_object_add(bmain, collection_dst, ob)) {
- BKE_collection_object_remove(bmain, collection_src, ob, false);
- }
- }
- else {
- /* Adding will fail if object is already in collection.
- * However we still need to remove it from the other collections. */
- BKE_collection_object_add(bmain, collection_dst, ob);
- scene_collections_object_remove(bmain, scene, ob, false, collection_dst);
- }
+ Main *bmain, Scene *scene, Collection *collection_dst, Collection *collection_src, Object *ob)
+{
+ /* In both cases we first add the object, then remove it from the other collections.
+ * Otherwise we lose the original base and whether it was active and selected. */
+ if (collection_src != NULL) {
+ if (BKE_collection_object_add(bmain, collection_dst, ob)) {
+ BKE_collection_object_remove(bmain, collection_src, ob, false);
+ }
+ }
+ else {
+ /* Adding will fail if object is already in collection.
+ * However we still need to remove it from the other collections. */
+ BKE_collection_object_add(bmain, collection_dst, ob);
+ scene_collections_object_remove(bmain, scene, ob, false, collection_dst);
+ }
}
/***************** Collection Scene Membership ****************/
bool BKE_collection_is_in_scene(Collection *collection)
{
- if (collection->flag & COLLECTION_IS_MASTER) {
- return true;
- }
+ if (collection->flag & COLLECTION_IS_MASTER) {
+ return true;
+ }
- for (CollectionParent *cparent = collection->parents.first; cparent; cparent = cparent->next) {
- if (BKE_collection_is_in_scene(cparent->collection)) {
- return true;
- }
- }
+ for (CollectionParent *cparent = collection->parents.first; cparent; cparent = cparent->next) {
+ if (BKE_collection_is_in_scene(cparent->collection)) {
+ return true;
+ }
+ }
- return false;
+ return false;
}
void BKE_collections_after_lib_link(Main *bmain)
{
- /* Need to update layer collections because objects might have changed
- * in linked files, and because undo push does not include updated base
- * flags since those are refreshed after the operator completes. */
- BKE_main_collection_sync(bmain);
+ /* Need to update layer collections because objects might have changed
+ * in linked files, and because undo push does not include updated base
+ * flags since those are refreshed after the operator completes. */
+ BKE_main_collection_sync(bmain);
}
/********************** Collection Children *******************/
bool BKE_collection_find_cycle(Collection *new_ancestor, Collection *collection)
{
- if (collection == new_ancestor) {
- return true;
- }
+ if (collection == new_ancestor) {
+ return true;
+ }
- for (CollectionParent *parent = new_ancestor->parents.first; parent; parent = parent->next) {
- if (BKE_collection_find_cycle(parent->collection, collection)) {
- return true;
- }
- }
+ for (CollectionParent *parent = new_ancestor->parents.first; parent; parent = parent->next) {
+ if (BKE_collection_find_cycle(parent->collection, collection)) {
+ return true;
+ }
+ }
- return false;
+ return false;
}
static CollectionChild *collection_find_child(Collection *parent, Collection *collection)
{
- return BLI_findptr(&parent->children, collection, offsetof(CollectionChild, collection));
+ return BLI_findptr(&parent->children, collection, offsetof(CollectionChild, collection));
}
static bool collection_find_child_recursive(Collection *parent, Collection *collection)
{
- for (CollectionChild *child = parent->children.first; child; child = child->next) {
- if (child->collection == collection) {
- return true;
- }
+ for (CollectionChild *child = parent->children.first; child; child = child->next) {
+ if (child->collection == collection) {
+ return true;
+ }
- if (collection_find_child_recursive(child->collection, collection)) {
- return true;
- }
- }
+ if (collection_find_child_recursive(child->collection, collection)) {
+ return true;
+ }
+ }
- return false;
+ return false;
}
static CollectionParent *collection_find_parent(Collection *child, Collection *collection)
{
- return BLI_findptr(&child->parents, collection, offsetof(CollectionParent, collection));
+ return BLI_findptr(&child->parents, collection, offsetof(CollectionParent, collection));
}
-static bool collection_child_add(Collection *parent, Collection *collection, const int flag, const bool add_us)
+static bool collection_child_add(Collection *parent,
+ Collection *collection,
+ const int flag,
+ const bool add_us)
{
- CollectionChild *child = collection_find_child(parent, collection);
- if (child) {
- return false;
- }
- if (BKE_collection_find_cycle(parent, collection)) {
- return false;
- }
+ CollectionChild *child = collection_find_child(parent, collection);
+ if (child) {
+ return false;
+ }
+ if (BKE_collection_find_cycle(parent, collection)) {
+ return false;
+ }
- child = MEM_callocN(sizeof(CollectionChild), "CollectionChild");
- child->collection = collection;
- BLI_addtail(&parent->children, child);
+ child = MEM_callocN(sizeof(CollectionChild), "CollectionChild");
+ child->collection = collection;
+ BLI_addtail(&parent->children, child);
- /* Don't add parent links for depsgraph datablocks, these are not kept in sync. */
- if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
- CollectionParent *cparent = MEM_callocN(sizeof(CollectionParent), "CollectionParent");
- cparent->collection = parent;
- BLI_addtail(&collection->parents, cparent);
- }
+ /* Don't add parent links for depsgraph datablocks, these are not kept in sync. */
+ if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
+ CollectionParent *cparent = MEM_callocN(sizeof(CollectionParent), "CollectionParent");
+ cparent->collection = parent;
+ BLI_addtail(&collection->parents, cparent);
+ }
- if (add_us) {
- id_us_plus(&collection->id);
- }
+ if (add_us) {
+ id_us_plus(&collection->id);
+ }
- BKE_collection_object_cache_free(parent);
+ BKE_collection_object_cache_free(parent);
- return true;
+ return true;
}
static bool collection_child_remove(Collection *parent, Collection *collection)
{
- CollectionChild *child = collection_find_child(parent, collection);
- if (child == NULL) {
- return false;
- }
+ CollectionChild *child = collection_find_child(parent, collection);
+ if (child == NULL) {
+ return false;
+ }
- CollectionParent *cparent = collection_find_parent(collection, parent);
- BLI_freelinkN(&collection->parents, cparent);
- BLI_freelinkN(&parent->children, child);
+ CollectionParent *cparent = collection_find_parent(collection, parent);
+ BLI_freelinkN(&collection->parents, cparent);
+ BLI_freelinkN(&parent->children, child);
- id_us_min(&collection->id);
+ id_us_min(&collection->id);
- BKE_collection_object_cache_free(parent);
+ BKE_collection_object_cache_free(parent);
- return true;
+ return true;
}
bool BKE_collection_child_add(Main *bmain, Collection *parent, Collection *child)
{
- if (!collection_child_add(parent, child, 0, true)) {
- return false;
- }
+ if (!collection_child_add(parent, child, 0, true)) {
+ return false;
+ }
- BKE_main_collection_sync(bmain);
- return true;
+ BKE_main_collection_sync(bmain);
+ return true;
}
bool BKE_collection_child_remove(Main *bmain, Collection *parent, Collection *child)
{
- if (!collection_child_remove(parent, child)) {
- return false;
- }
+ if (!collection_child_remove(parent, child)) {
+ return false;
+ }
- BKE_main_collection_sync(bmain);
- return true;
+ BKE_main_collection_sync(bmain);
+ return true;
}
/********************** Collection index *********************/
-static Collection *collection_from_index_recursive(Collection *collection, const int index, int *index_current)
+static Collection *collection_from_index_recursive(Collection *collection,
+ const int index,
+ int *index_current)
{
- if (index == (*index_current)) {
- return collection;
- }
+ if (index == (*index_current)) {
+ return collection;
+ }
- (*index_current)++;
+ (*index_current)++;
- for (CollectionChild *child = collection->children.first; child; child = child->next) {
- Collection *nested = collection_from_index_recursive(child->collection, index, index_current);
- if (nested != NULL) {
- return nested;
- }
- }
- return NULL;
+ for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ Collection *nested = collection_from_index_recursive(child->collection, index, index_current);
+ if (nested != NULL) {
+ return nested;
+ }
+ }
+ return NULL;
}
/**
@@ -1026,45 +1062,45 @@ static Collection *collection_from_index_recursive(Collection *collection, const
*/
Collection *BKE_collection_from_index(Scene *scene, const int index)
{
- int index_current = 0;
- Collection *master_collection = BKE_collection_master(scene);
- return collection_from_index_recursive(master_collection, index, &index_current);
+ int index_current = 0;
+ Collection *master_collection = BKE_collection_master(scene);
+ return collection_from_index_recursive(master_collection, index, &index_current);
}
static bool collection_objects_select(ViewLayer *view_layer, Collection *collection, bool deselect)
{
- bool changed = false;
+ bool changed = false;
- if (collection->flag & COLLECTION_RESTRICT_SELECT) {
- return false;
- }
+ if (collection->flag & COLLECTION_RESTRICT_SELECT) {
+ return false;
+ }
- for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
- Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
+ for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
- if (base) {
- if (deselect) {
- if (base->flag & BASE_SELECTED) {
- base->flag &= ~BASE_SELECTED;
- changed = true;
- }
- }
- else {
- if ((base->flag & BASE_SELECTABLE) && !(base->flag & BASE_SELECTED)) {
- base->flag |= BASE_SELECTED;
- changed = true;
- }
- }
- }
- }
+ if (base) {
+ if (deselect) {
+ if (base->flag & BASE_SELECTED) {
+ base->flag &= ~BASE_SELECTED;
+ changed = true;
+ }
+ }
+ else {
+ if ((base->flag & BASE_SELECTABLE) && !(base->flag & BASE_SELECTED)) {
+ base->flag |= BASE_SELECTED;
+ changed = true;
+ }
+ }
+ }
+ }
- for (CollectionChild *child = collection->children.first; child; child = child->next) {
- if (collection_objects_select(view_layer, collection, deselect)) {
- changed = true;
- }
- }
+ for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ if (collection_objects_select(view_layer, collection, deselect)) {
+ changed = true;
+ }
+ }
- return changed;
+ return changed;
}
/**
@@ -1073,14 +1109,15 @@ static bool collection_objects_select(ViewLayer *view_layer, Collection *collect
*/
bool BKE_collection_objects_select(ViewLayer *view_layer, Collection *collection, bool deselect)
{
- LayerCollection *layer_collection = BKE_layer_collection_first_from_scene_collection(view_layer, collection);
+ LayerCollection *layer_collection = BKE_layer_collection_first_from_scene_collection(view_layer,
+ collection);
- if (layer_collection != NULL) {
- return BKE_layer_collection_objects_select(view_layer, layer_collection, deselect);
- }
- else {
- return collection_objects_select(view_layer, collection, deselect);
- }
+ if (layer_collection != NULL) {
+ return BKE_layer_collection_objects_select(view_layer, layer_collection, deselect);
+ }
+ else {
+ return collection_objects_select(view_layer, collection, deselect);
+ }
}
/***************** Collection move (outliner drag & drop) *********************/
@@ -1092,42 +1129,42 @@ bool BKE_collection_move(Main *bmain,
bool relative_after,
Collection *collection)
{
- if (collection->flag & COLLECTION_IS_MASTER) {
- return false;
- }
- if (BKE_collection_find_cycle(to_parent, collection)) {
- return false;
- }
+ if (collection->flag & COLLECTION_IS_MASTER) {
+ return false;
+ }
+ if (BKE_collection_find_cycle(to_parent, collection)) {
+ return false;
+ }
- /* Move to new parent collection */
- if (from_parent) {
- collection_child_remove(from_parent, collection);
- }
+ /* Move to new parent collection */
+ if (from_parent) {
+ collection_child_remove(from_parent, collection);
+ }
- collection_child_add(to_parent, collection, 0, true);
+ collection_child_add(to_parent, collection, 0, true);
- /* Move to specified location under parent. */
- if (relative) {
- CollectionChild *child = collection_find_child(to_parent, collection);
- CollectionChild *relative_child = collection_find_child(to_parent, relative);
+ /* Move to specified location under parent. */
+ if (relative) {
+ CollectionChild *child = collection_find_child(to_parent, collection);
+ CollectionChild *relative_child = collection_find_child(to_parent, relative);
- if (relative_child) {
- BLI_remlink(&to_parent->children, child);
+ if (relative_child) {
+ BLI_remlink(&to_parent->children, child);
- if (relative_after) {
- BLI_insertlinkafter(&to_parent->children, relative_child, child);
- }
- else {
- BLI_insertlinkbefore(&to_parent->children, relative_child, child);
- }
+ if (relative_after) {
+ BLI_insertlinkafter(&to_parent->children, relative_child, child);
+ }
+ else {
+ BLI_insertlinkbefore(&to_parent->children, relative_child, child);
+ }
- BKE_collection_object_cache_free(to_parent);
- }
- }
+ BKE_collection_object_cache_free(to_parent);
+ }
+ }
- BKE_main_collection_sync(bmain);
+ BKE_main_collection_sync(bmain);
- return true;
+ return true;
}
/**************************** Iterators ******************************/
@@ -1135,54 +1172,56 @@ bool BKE_collection_move(Main *bmain,
/* scene collection iteractor */
typedef struct CollectionsIteratorData {
- Scene *scene;
- void **array;
- int tot, cur;
+ Scene *scene;
+ void **array;
+ int tot, cur;
} CollectionsIteratorData;
-static void scene_collection_callback(Collection *collection, BKE_scene_collections_Cb callback, void *data)
+static void scene_collection_callback(Collection *collection,
+ BKE_scene_collections_Cb callback,
+ void *data)
{
- callback(collection, data);
+ callback(collection, data);
- for (CollectionChild *child = collection->children.first; child; child = child->next) {
- scene_collection_callback(child->collection, callback, data);
- }
+ for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ scene_collection_callback(child->collection, callback, data);
+ }
}
static void scene_collections_count(Collection *UNUSED(collection), void *data)
{
- int *tot = data;
- (*tot)++;
+ int *tot = data;
+ (*tot)++;
}
static void scene_collections_build_array(Collection *collection, void *data)
{
- Collection ***array = data;
- **array = collection;
- (*array)++;
+ Collection ***array = data;
+ **array = collection;
+ (*array)++;
}
static void scene_collections_array(Scene *scene, Collection ***collections_array, int *tot)
{
- Collection *collection;
- Collection **array;
+ Collection *collection;
+ Collection **array;
- *collections_array = NULL;
- *tot = 0;
+ *collections_array = NULL;
+ *tot = 0;
- if (scene == NULL) {
- return;
- }
+ if (scene == NULL) {
+ return;
+ }
- collection = BKE_collection_master(scene);
- BLI_assert(collection != NULL);
- scene_collection_callback(collection, scene_collections_count, tot);
+ collection = BKE_collection_master(scene);
+ BLI_assert(collection != NULL);
+ scene_collection_callback(collection, scene_collections_count, tot);
- if (*tot == 0)
- return;
+ if (*tot == 0)
+ return;
- *collections_array = array = MEM_mallocN(sizeof(Collection *) * (*tot), "CollectionArray");
- scene_collection_callback(collection, scene_collections_build_array, &array);
+ *collections_array = array = MEM_mallocN(sizeof(Collection *) * (*tot), "CollectionArray");
+ scene_collection_callback(collection, scene_collections_build_array, &array);
}
/**
@@ -1191,70 +1230,69 @@ static void scene_collections_array(Scene *scene, Collection ***collections_arra
*/
void BKE_scene_collections_iterator_begin(BLI_Iterator *iter, void *data_in)
{
- Scene *scene = data_in;
- CollectionsIteratorData *data = MEM_callocN(sizeof(CollectionsIteratorData), __func__);
+ Scene *scene = data_in;
+ CollectionsIteratorData *data = MEM_callocN(sizeof(CollectionsIteratorData), __func__);
- data->scene = scene;
- iter->data = data;
- iter->valid = true;
+ data->scene = scene;
+ iter->data = data;
+ iter->valid = true;
- scene_collections_array(scene, (Collection ***)&data->array, &data->tot);
- BLI_assert(data->tot != 0);
+ scene_collections_array(scene, (Collection ***)&data->array, &data->tot);
+ BLI_assert(data->tot != 0);
- data->cur = 0;
- iter->current = data->array[data->cur];
+ data->cur = 0;
+ iter->current = data->array[data->cur];
}
void BKE_scene_collections_iterator_next(struct BLI_Iterator *iter)
{
- CollectionsIteratorData *data = iter->data;
+ CollectionsIteratorData *data = iter->data;
- if (++data->cur < data->tot) {
- iter->current = data->array[data->cur];
- }
- else {
- iter->valid = false;
- }
+ if (++data->cur < data->tot) {
+ iter->current = data->array[data->cur];
+ }
+ else {
+ iter->valid = false;
+ }
}
void BKE_scene_collections_iterator_end(struct BLI_Iterator *iter)
{
- CollectionsIteratorData *data = iter->data;
+ CollectionsIteratorData *data = iter->data;
- if (data) {
- if (data->array) {
- MEM_freeN(data->array);
- }
- MEM_freeN(data);
- }
- iter->valid = false;
+ if (data) {
+ if (data->array) {
+ MEM_freeN(data->array);
+ }
+ MEM_freeN(data);
+ }
+ iter->valid = false;
}
-
/* scene objects iterator */
typedef struct SceneObjectsIteratorData {
- GSet *visited;
- CollectionObject *cob_next;
- BLI_Iterator scene_collection_iter;
+ GSet *visited;
+ CollectionObject *cob_next;
+ BLI_Iterator scene_collection_iter;
} SceneObjectsIteratorData;
void BKE_scene_objects_iterator_begin(BLI_Iterator *iter, void *data_in)
{
- Scene *scene = data_in;
- SceneObjectsIteratorData *data = MEM_callocN(sizeof(SceneObjectsIteratorData), __func__);
- iter->data = data;
+ Scene *scene = data_in;
+ SceneObjectsIteratorData *data = MEM_callocN(sizeof(SceneObjectsIteratorData), __func__);
+ iter->data = data;
- /* lookup list ot make sure each object is object called once */
- data->visited = BLI_gset_ptr_new(__func__);
+ /* lookup list ot make sure each object is object called once */
+ data->visited = BLI_gset_ptr_new(__func__);
- /* we wrap the scenecollection iterator here to go over the scene collections */
- BKE_scene_collections_iterator_begin(&data->scene_collection_iter, scene);
+ /* we wrap the scenecollection iterator here to go over the scene collections */
+ BKE_scene_collections_iterator_begin(&data->scene_collection_iter, scene);
- Collection *collection = data->scene_collection_iter.current;
- data->cob_next = collection->gobject.first;
+ Collection *collection = data->scene_collection_iter.current;
+ data->cob_next = collection->gobject.first;
- BKE_scene_objects_iterator_next(iter);
+ BKE_scene_objects_iterator_next(iter);
}
/**
@@ -1262,54 +1300,55 @@ void BKE_scene_objects_iterator_begin(BLI_Iterator *iter, void *data_in)
*/
static CollectionObject *object_base_unique(GSet *gs, CollectionObject *cob)
{
- for (; cob != NULL; cob = cob->next) {
- Object *ob = cob->ob;
- void **ob_key_p;
- if (!BLI_gset_ensure_p_ex(gs, ob, &ob_key_p)) {
- *ob_key_p = ob;
- return cob;
- }
- }
- return NULL;
+ for (; cob != NULL; cob = cob->next) {
+ Object *ob = cob->ob;
+ void **ob_key_p;
+ if (!BLI_gset_ensure_p_ex(gs, ob, &ob_key_p)) {
+ *ob_key_p = ob;
+ return cob;
+ }
+ }
+ return NULL;
}
void BKE_scene_objects_iterator_next(BLI_Iterator *iter)
{
- SceneObjectsIteratorData *data = iter->data;
- CollectionObject *cob = data->cob_next ? object_base_unique(data->visited, data->cob_next) : NULL;
-
- if (cob) {
- data->cob_next = cob->next;
- iter->current = cob->ob;
- }
- else {
- /* if this is the last object of this ListBase look at the next Collection */
- Collection *collection;
- BKE_scene_collections_iterator_next(&data->scene_collection_iter);
- do {
- collection = data->scene_collection_iter.current;
- /* get the first unique object of this collection */
- CollectionObject *new_cob = object_base_unique(data->visited, collection->gobject.first);
- if (new_cob) {
- data->cob_next = new_cob->next;
- iter->current = new_cob->ob;
- return;
- }
- BKE_scene_collections_iterator_next(&data->scene_collection_iter);
- } while (data->scene_collection_iter.valid);
-
- if (!data->scene_collection_iter.valid) {
- iter->valid = false;
- }
- }
+ SceneObjectsIteratorData *data = iter->data;
+ CollectionObject *cob = data->cob_next ? object_base_unique(data->visited, data->cob_next) :
+ NULL;
+
+ if (cob) {
+ data->cob_next = cob->next;
+ iter->current = cob->ob;
+ }
+ else {
+ /* if this is the last object of this ListBase look at the next Collection */
+ Collection *collection;
+ BKE_scene_collections_iterator_next(&data->scene_collection_iter);
+ do {
+ collection = data->scene_collection_iter.current;
+ /* get the first unique object of this collection */
+ CollectionObject *new_cob = object_base_unique(data->visited, collection->gobject.first);
+ if (new_cob) {
+ data->cob_next = new_cob->next;
+ iter->current = new_cob->ob;
+ return;
+ }
+ BKE_scene_collections_iterator_next(&data->scene_collection_iter);
+ } while (data->scene_collection_iter.valid);
+
+ if (!data->scene_collection_iter.valid) {
+ iter->valid = false;
+ }
+ }
}
void BKE_scene_objects_iterator_end(BLI_Iterator *iter)
{
- SceneObjectsIteratorData *data = iter->data;
- if (data) {
- BKE_scene_collections_iterator_end(&data->scene_collection_iter);
- BLI_gset_free(data->visited, NULL);
- MEM_freeN(data);
- }
+ SceneObjectsIteratorData *data = iter->data;
+ if (data) {
+ BKE_scene_collections_iterator_end(&data->scene_collection_iter);
+ BLI_gset_free(data->visited, NULL);
+ MEM_freeN(data);
+ }
}
diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c
index a7ba143fc9d..67e1f36b222 100644
--- a/source/blender/blenkernel/intern/collision.c
+++ b/source/blender/blenkernel/intern/collision.c
@@ -21,7 +21,6 @@
* \ingroup bke
*/
-
#include "MEM_guardedalloc.h"
#include "DNA_cloth_types.h"
@@ -53,25 +52,24 @@
#include "DEG_depsgraph_query.h"
#ifdef WITH_ELTOPO
-#include "eltopo-capi.h"
+# include "eltopo-capi.h"
#endif
-
typedef struct ColDetectData {
- ClothModifierData *clmd;
- CollisionModifierData *collmd;
- BVHTreeOverlap *overlap;
- CollPair *collisions;
- bool culling;
- bool use_normal;
- bool collided;
+ ClothModifierData *clmd;
+ CollisionModifierData *collmd;
+ BVHTreeOverlap *overlap;
+ CollPair *collisions;
+ bool culling;
+ bool use_normal;
+ bool collided;
} ColDetectData;
typedef struct SelfColDetectData {
- ClothModifierData *clmd;
- BVHTreeOverlap *overlap;
- CollPair *collisions;
- bool collided;
+ ClothModifierData *clmd;
+ BVHTreeOverlap *overlap;
+ CollPair *collisions;
+ bool collided;
} SelfColDetectData;
/***********************************
@@ -81,103 +79,103 @@ Collision modifier code start
/* step is limited from 0 (frame start position) to 1 (frame end position) */
void collision_move_object(CollisionModifierData *collmd, float step, float prevstep)
{
- float oldx[3];
- unsigned int i = 0;
-
- /* the collider doesn't move this frame */
- if (collmd->is_static) {
- for (i = 0; i < collmd->mvert_num; i++) {
- zero_v3(collmd->current_v[i].co);
- }
-
- return;
- }
-
- for (i = 0; i < collmd->mvert_num; i++) {
- interp_v3_v3v3(oldx, collmd->x[i].co, collmd->xnew[i].co, prevstep);
- interp_v3_v3v3(collmd->current_x[i].co, collmd->x[i].co, collmd->xnew[i].co, step);
- sub_v3_v3v3(collmd->current_v[i].co, collmd->current_x[i].co, oldx);
- }
-
- bvhtree_update_from_mvert(
- collmd->bvhtree, collmd->current_x, NULL,
- collmd->tri, collmd->tri_num, false);
+ float oldx[3];
+ unsigned int i = 0;
+
+ /* the collider doesn't move this frame */
+ if (collmd->is_static) {
+ for (i = 0; i < collmd->mvert_num; i++) {
+ zero_v3(collmd->current_v[i].co);
+ }
+
+ return;
+ }
+
+ for (i = 0; i < collmd->mvert_num; i++) {
+ interp_v3_v3v3(oldx, collmd->x[i].co, collmd->xnew[i].co, prevstep);
+ interp_v3_v3v3(collmd->current_x[i].co, collmd->x[i].co, collmd->xnew[i].co, step);
+ sub_v3_v3v3(collmd->current_v[i].co, collmd->current_x[i].co, oldx);
+ }
+
+ bvhtree_update_from_mvert(
+ collmd->bvhtree, collmd->current_x, NULL, collmd->tri, collmd->tri_num, false);
}
-BVHTree *bvhtree_build_from_mvert(
- const MVert *mvert,
- const struct MVertTri *tri, int tri_num,
- float epsilon)
+BVHTree *bvhtree_build_from_mvert(const MVert *mvert,
+ const struct MVertTri *tri,
+ int tri_num,
+ float epsilon)
{
- BVHTree *tree;
- const MVertTri *vt;
- int i;
+ BVHTree *tree;
+ const MVertTri *vt;
+ int i;
- tree = BLI_bvhtree_new(tri_num, epsilon, 4, 26);
+ tree = BLI_bvhtree_new(tri_num, epsilon, 4, 26);
- /* fill tree */
- for (i = 0, vt = tri; i < tri_num; i++, vt++) {
- float co[3][3];
+ /* fill tree */
+ for (i = 0, vt = tri; i < tri_num; i++, vt++) {
+ float co[3][3];
- copy_v3_v3(co[0], mvert[vt->tri[0]].co);
- copy_v3_v3(co[1], mvert[vt->tri[1]].co);
- copy_v3_v3(co[2], mvert[vt->tri[2]].co);
+ copy_v3_v3(co[0], mvert[vt->tri[0]].co);
+ copy_v3_v3(co[1], mvert[vt->tri[1]].co);
+ copy_v3_v3(co[2], mvert[vt->tri[2]].co);
- BLI_bvhtree_insert(tree, i, co[0], 3);
- }
+ BLI_bvhtree_insert(tree, i, co[0], 3);
+ }
- /* balance tree */
- BLI_bvhtree_balance(tree);
+ /* balance tree */
+ BLI_bvhtree_balance(tree);
- return tree;
+ return tree;
}
-void bvhtree_update_from_mvert(
- BVHTree *bvhtree,
- const MVert *mvert, const MVert *mvert_moving,
- const MVertTri *tri, int tri_num,
- bool moving)
+void bvhtree_update_from_mvert(BVHTree *bvhtree,
+ const MVert *mvert,
+ const MVert *mvert_moving,
+ const MVertTri *tri,
+ int tri_num,
+ bool moving)
{
- const MVertTri *vt;
- int i;
-
- if ((bvhtree == NULL) || (mvert == NULL)) {
- return;
- }
-
- if (mvert_moving == NULL) {
- moving = false;
- }
-
- for (i = 0, vt = tri; i < tri_num; i++, vt++) {
- float co[3][3];
- bool ret;
-
- copy_v3_v3(co[0], mvert[vt->tri[0]].co);
- copy_v3_v3(co[1], mvert[vt->tri[1]].co);
- copy_v3_v3(co[2], mvert[vt->tri[2]].co);
-
- /* copy new locations into array */
- if (moving) {
- float co_moving[3][3];
- /* update moving positions */
- copy_v3_v3(co_moving[0], mvert_moving[vt->tri[0]].co);
- copy_v3_v3(co_moving[1], mvert_moving[vt->tri[1]].co);
- copy_v3_v3(co_moving[2], mvert_moving[vt->tri[2]].co);
-
- ret = BLI_bvhtree_update_node(bvhtree, i, &co[0][0], &co_moving[0][0], 3);
- }
- else {
- ret = BLI_bvhtree_update_node(bvhtree, i, &co[0][0], NULL, 3);
- }
-
- /* check if tree is already full */
- if (ret == false) {
- break;
- }
- }
-
- BLI_bvhtree_update_tree(bvhtree);
+ const MVertTri *vt;
+ int i;
+
+ if ((bvhtree == NULL) || (mvert == NULL)) {
+ return;
+ }
+
+ if (mvert_moving == NULL) {
+ moving = false;
+ }
+
+ for (i = 0, vt = tri; i < tri_num; i++, vt++) {
+ float co[3][3];
+ bool ret;
+
+ copy_v3_v3(co[0], mvert[vt->tri[0]].co);
+ copy_v3_v3(co[1], mvert[vt->tri[1]].co);
+ copy_v3_v3(co[2], mvert[vt->tri[2]].co);
+
+ /* copy new locations into array */
+ if (moving) {
+ float co_moving[3][3];
+ /* update moving positions */
+ copy_v3_v3(co_moving[0], mvert_moving[vt->tri[0]].co);
+ copy_v3_v3(co_moving[1], mvert_moving[vt->tri[1]].co);
+ copy_v3_v3(co_moving[2], mvert_moving[vt->tri[2]].co);
+
+ ret = BLI_bvhtree_update_node(bvhtree, i, &co[0][0], &co_moving[0][0], 3);
+ }
+ else {
+ ret = BLI_bvhtree_update_node(bvhtree, i, &co[0][0], NULL, 3);
+ }
+
+ /* check if tree is already full */
+ if (ret == false) {
+ break;
+ }
+ }
+
+ BLI_bvhtree_update_tree(bvhtree);
}
/***********************************
@@ -186,268 +184,277 @@ Collision modifier code end
BLI_INLINE int next_ind(int i)
{
- return (++i < 3) ? i : 0;
+ return (++i < 3) ? i : 0;
}
-static float compute_collision_point(float a1[3], float a2[3], float a3[3], float b1[3], float b2[3], float b3[3],
- bool culling, bool use_normal, float r_a[3], float r_b[3], float r_vec[3])
+static float compute_collision_point(float a1[3],
+ float a2[3],
+ float a3[3],
+ float b1[3],
+ float b2[3],
+ float b3[3],
+ bool culling,
+ bool use_normal,
+ float r_a[3],
+ float r_b[3],
+ float r_vec[3])
{
- float a[3][3];
- float b[3][3];
- float dist = FLT_MAX;
- float tmp_co1[3], tmp_co2[3];
- float isect_a[3], isect_b[3];
- int isect_count = 0;
- float tmp, tmp_vec[3];
- float normal[3], cent[3];
- bool backside = false;
-
- copy_v3_v3(a[0], a1);
- copy_v3_v3(a[1], a2);
- copy_v3_v3(a[2], a3);
-
- copy_v3_v3(b[0], b1);
- copy_v3_v3(b[1], b2);
- copy_v3_v3(b[2], b3);
-
- /* Find intersections. */
- for (int i = 0; i < 3; i++) {
- if (isect_line_segment_tri_v3(a[i], a[next_ind(i)], b[0], b[1], b[2], &tmp, NULL)) {
- interp_v3_v3v3(isect_a, a[i], a[next_ind(i)], tmp);
- isect_count++;
- }
- }
-
- if (isect_count == 0) {
- for (int i = 0; i < 3; i++) {
- if (isect_line_segment_tri_v3(b[i], b[next_ind(i)], a[0], a[1], a[2], &tmp, NULL)) {
- isect_count++;
- }
- }
- }
- else if (isect_count == 1) {
- for (int i = 0; i < 3; i++) {
- if (isect_line_segment_tri_v3(b[i], b[next_ind(i)], a[0], a[1], a[2], &tmp, NULL)) {
- interp_v3_v3v3(isect_b, b[i], b[next_ind(i)], tmp);
- break;
- }
- }
- }
-
- /* Determine collision side. */
- if (culling) {
- normal_tri_v3(normal, b[0], b[1], b[2]);
- mid_v3_v3v3v3(cent, b[0], b[1], b[2]);
-
- if (isect_count == 2) {
- backside = true;
- }
- else if (isect_count == 0) {
- for (int i = 0; i < 3; i++) {
- sub_v3_v3v3(tmp_vec, a[i], cent);
- if (dot_v3v3(tmp_vec, normal) < 0.0f) {
- backside = true;
- break;
- }
- }
- }
- }
- else if (use_normal) {
- normal_tri_v3(normal, b[0], b[1], b[2]);
- }
-
- if (isect_count == 1) {
- /* Edge intersection. */
- copy_v3_v3(r_a, isect_a);
- copy_v3_v3(r_b, isect_b);
-
- if (use_normal) {
- copy_v3_v3(r_vec, normal);
- }
- else {
- sub_v3_v3v3(r_vec, r_b, r_a);
- }
-
- return 0.0f;
- }
-
- if (backside) {
- float maxdist = 0.0f;
- bool found = false;
-
- /* Point projections. */
- for (int i = 0; i < 3; i++) {
- if (isect_ray_tri_v3(a[i], normal, b[0], b[1], b[2], &tmp, NULL)) {
- if (tmp > maxdist) {
- maxdist = tmp;
- copy_v3_v3(r_a, a[i]);
- madd_v3_v3v3fl(r_b, a[i], normal, tmp);
- found = true;
- }
- }
- }
-
- negate_v3(normal);
-
- for (int i = 0; i < 3; i++) {
- if (isect_ray_tri_v3(b[i], normal, a[0], a[1], a[2], &tmp, NULL)) {
- if (tmp > maxdist) {
- maxdist = tmp;
- madd_v3_v3v3fl(r_a, b[i], normal, tmp);
- copy_v3_v3(r_b, b[i]);
- found = true;
- }
- }
- }
-
- negate_v3(normal);
-
- /* Edge projections. */
- for (int i = 0; i < 3; i++) {
- float dir[3];
-
- sub_v3_v3v3(tmp_vec, b[next_ind(i)], b[i]);
- cross_v3_v3v3(dir, tmp_vec, normal);
-
- for (int j = 0; j < 3; j++) {
- if (isect_line_plane_v3(tmp_co1, a[j], a[next_ind(j)], b[i], dir) &&
- point_in_slice_seg(tmp_co1, a[j], a[next_ind(j)]) &&
- point_in_slice_seg(tmp_co1, b[i], b[next_ind(i)]))
- {
- closest_to_line_v3(tmp_co2, tmp_co1, b[i], b[next_ind(i)]);
- sub_v3_v3v3(tmp_vec, tmp_co1, tmp_co2);
- tmp = len_v3(tmp_vec);
-
- if ((tmp > maxdist) && (dot_v3v3(tmp_vec, normal) < 0.0f)) {
- maxdist = tmp;
- copy_v3_v3(r_a, tmp_co1);
- copy_v3_v3(r_b, tmp_co2);
- found = true;
- }
- }
- }
- }
-
- /* If no point is found, will fallback onto regular proximity test below. */
- if (found) {
- sub_v3_v3v3(r_vec, r_b, r_a);
-
- if (use_normal) {
- if (dot_v3v3(normal, r_vec) >= 0.0f) {
- copy_v3_v3(r_vec, normal);
- }
- else {
- negate_v3_v3(r_vec, normal);
- }
- }
-
- return 0.0f;
- }
- }
-
- /* Closest point. */
- for (int i = 0; i < 3; i++) {
- closest_on_tri_to_point_v3(tmp_co1, a[i], b[0], b[1], b[2]);
- tmp = len_squared_v3v3(tmp_co1, a[i]);
-
- if (tmp < dist) {
- dist = tmp;
- copy_v3_v3(r_a, a[i]);
- copy_v3_v3(r_b, tmp_co1);
- }
- }
-
- for (int i = 0; i < 3; i++) {
- closest_on_tri_to_point_v3(tmp_co1, b[i], a[0], a[1], a[2]);
- tmp = len_squared_v3v3(tmp_co1, b[i]);
-
- if (tmp < dist) {
- dist = tmp;
- copy_v3_v3(r_a, tmp_co1);
- copy_v3_v3(r_b, b[i]);
- }
- }
-
- /* Closest edge. */
- if (isect_count == 0) {
- for (int i = 0; i < 3; i++) {
- for (int j = 0; j < 3; j++) {
- isect_seg_seg_v3(a[i], a[next_ind(i)], b[j], b[next_ind(j)], tmp_co1, tmp_co2);
- tmp = len_squared_v3v3(tmp_co1, tmp_co2);
-
- if (tmp < dist) {
- dist = tmp;
- copy_v3_v3(r_a, tmp_co1);
- copy_v3_v3(r_b, tmp_co2);
- }
- }
- }
- }
-
- if (isect_count == 0) {
- sub_v3_v3v3(r_vec, r_a, r_b);
- dist = sqrtf(dist);
- }
- else {
- sub_v3_v3v3(r_vec, r_b, r_a);
- dist = 0.0f;
- }
-
- if (culling && use_normal) {
- copy_v3_v3(r_vec, normal);
- }
- else if (use_normal) {
- if (dot_v3v3(normal, r_vec) >= 0.0f) {
- copy_v3_v3(r_vec, normal);
- }
- else {
- negate_v3_v3(r_vec, normal);
- }
- }
- else if (culling && (dot_v3v3(r_vec, normal) < 0.0f)) {
- return FLT_MAX;
- }
-
- return dist;
+ float a[3][3];
+ float b[3][3];
+ float dist = FLT_MAX;
+ float tmp_co1[3], tmp_co2[3];
+ float isect_a[3], isect_b[3];
+ int isect_count = 0;
+ float tmp, tmp_vec[3];
+ float normal[3], cent[3];
+ bool backside = false;
+
+ copy_v3_v3(a[0], a1);
+ copy_v3_v3(a[1], a2);
+ copy_v3_v3(a[2], a3);
+
+ copy_v3_v3(b[0], b1);
+ copy_v3_v3(b[1], b2);
+ copy_v3_v3(b[2], b3);
+
+ /* Find intersections. */
+ for (int i = 0; i < 3; i++) {
+ if (isect_line_segment_tri_v3(a[i], a[next_ind(i)], b[0], b[1], b[2], &tmp, NULL)) {
+ interp_v3_v3v3(isect_a, a[i], a[next_ind(i)], tmp);
+ isect_count++;
+ }
+ }
+
+ if (isect_count == 0) {
+ for (int i = 0; i < 3; i++) {
+ if (isect_line_segment_tri_v3(b[i], b[next_ind(i)], a[0], a[1], a[2], &tmp, NULL)) {
+ isect_count++;
+ }
+ }
+ }
+ else if (isect_count == 1) {
+ for (int i = 0; i < 3; i++) {
+ if (isect_line_segment_tri_v3(b[i], b[next_ind(i)], a[0], a[1], a[2], &tmp, NULL)) {
+ interp_v3_v3v3(isect_b, b[i], b[next_ind(i)], tmp);
+ break;
+ }
+ }
+ }
+
+ /* Determine collision side. */
+ if (culling) {
+ normal_tri_v3(normal, b[0], b[1], b[2]);
+ mid_v3_v3v3v3(cent, b[0], b[1], b[2]);
+
+ if (isect_count == 2) {
+ backside = true;
+ }
+ else if (isect_count == 0) {
+ for (int i = 0; i < 3; i++) {
+ sub_v3_v3v3(tmp_vec, a[i], cent);
+ if (dot_v3v3(tmp_vec, normal) < 0.0f) {
+ backside = true;
+ break;
+ }
+ }
+ }
+ }
+ else if (use_normal) {
+ normal_tri_v3(normal, b[0], b[1], b[2]);
+ }
+
+ if (isect_count == 1) {
+ /* Edge intersection. */
+ copy_v3_v3(r_a, isect_a);
+ copy_v3_v3(r_b, isect_b);
+
+ if (use_normal) {
+ copy_v3_v3(r_vec, normal);
+ }
+ else {
+ sub_v3_v3v3(r_vec, r_b, r_a);
+ }
+
+ return 0.0f;
+ }
+
+ if (backside) {
+ float maxdist = 0.0f;
+ bool found = false;
+
+ /* Point projections. */
+ for (int i = 0; i < 3; i++) {
+ if (isect_ray_tri_v3(a[i], normal, b[0], b[1], b[2], &tmp, NULL)) {
+ if (tmp > maxdist) {
+ maxdist = tmp;
+ copy_v3_v3(r_a, a[i]);
+ madd_v3_v3v3fl(r_b, a[i], normal, tmp);
+ found = true;
+ }
+ }
+ }
+
+ negate_v3(normal);
+
+ for (int i = 0; i < 3; i++) {
+ if (isect_ray_tri_v3(b[i], normal, a[0], a[1], a[2], &tmp, NULL)) {
+ if (tmp > maxdist) {
+ maxdist = tmp;
+ madd_v3_v3v3fl(r_a, b[i], normal, tmp);
+ copy_v3_v3(r_b, b[i]);
+ found = true;
+ }
+ }
+ }
+
+ negate_v3(normal);
+
+ /* Edge projections. */
+ for (int i = 0; i < 3; i++) {
+ float dir[3];
+
+ sub_v3_v3v3(tmp_vec, b[next_ind(i)], b[i]);
+ cross_v3_v3v3(dir, tmp_vec, normal);
+
+ for (int j = 0; j < 3; j++) {
+ if (isect_line_plane_v3(tmp_co1, a[j], a[next_ind(j)], b[i], dir) &&
+ point_in_slice_seg(tmp_co1, a[j], a[next_ind(j)]) &&
+ point_in_slice_seg(tmp_co1, b[i], b[next_ind(i)])) {
+ closest_to_line_v3(tmp_co2, tmp_co1, b[i], b[next_ind(i)]);
+ sub_v3_v3v3(tmp_vec, tmp_co1, tmp_co2);
+ tmp = len_v3(tmp_vec);
+
+ if ((tmp > maxdist) && (dot_v3v3(tmp_vec, normal) < 0.0f)) {
+ maxdist = tmp;
+ copy_v3_v3(r_a, tmp_co1);
+ copy_v3_v3(r_b, tmp_co2);
+ found = true;
+ }
+ }
+ }
+ }
+
+ /* If no point is found, will fallback onto regular proximity test below. */
+ if (found) {
+ sub_v3_v3v3(r_vec, r_b, r_a);
+
+ if (use_normal) {
+ if (dot_v3v3(normal, r_vec) >= 0.0f) {
+ copy_v3_v3(r_vec, normal);
+ }
+ else {
+ negate_v3_v3(r_vec, normal);
+ }
+ }
+
+ return 0.0f;
+ }
+ }
+
+ /* Closest point. */
+ for (int i = 0; i < 3; i++) {
+ closest_on_tri_to_point_v3(tmp_co1, a[i], b[0], b[1], b[2]);
+ tmp = len_squared_v3v3(tmp_co1, a[i]);
+
+ if (tmp < dist) {
+ dist = tmp;
+ copy_v3_v3(r_a, a[i]);
+ copy_v3_v3(r_b, tmp_co1);
+ }
+ }
+
+ for (int i = 0; i < 3; i++) {
+ closest_on_tri_to_point_v3(tmp_co1, b[i], a[0], a[1], a[2]);
+ tmp = len_squared_v3v3(tmp_co1, b[i]);
+
+ if (tmp < dist) {
+ dist = tmp;
+ copy_v3_v3(r_a, tmp_co1);
+ copy_v3_v3(r_b, b[i]);
+ }
+ }
+
+ /* Closest edge. */
+ if (isect_count == 0) {
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ isect_seg_seg_v3(a[i], a[next_ind(i)], b[j], b[next_ind(j)], tmp_co1, tmp_co2);
+ tmp = len_squared_v3v3(tmp_co1, tmp_co2);
+
+ if (tmp < dist) {
+ dist = tmp;
+ copy_v3_v3(r_a, tmp_co1);
+ copy_v3_v3(r_b, tmp_co2);
+ }
+ }
+ }
+ }
+
+ if (isect_count == 0) {
+ sub_v3_v3v3(r_vec, r_a, r_b);
+ dist = sqrtf(dist);
+ }
+ else {
+ sub_v3_v3v3(r_vec, r_b, r_a);
+ dist = 0.0f;
+ }
+
+ if (culling && use_normal) {
+ copy_v3_v3(r_vec, normal);
+ }
+ else if (use_normal) {
+ if (dot_v3v3(normal, r_vec) >= 0.0f) {
+ copy_v3_v3(r_vec, normal);
+ }
+ else {
+ negate_v3_v3(r_vec, normal);
+ }
+ }
+ else if (culling && (dot_v3v3(r_vec, normal) < 0.0f)) {
+ return FLT_MAX;
+ }
+
+ return dist;
}
// w3 is not perfect
-static void collision_compute_barycentric ( float pv[3], float p1[3], float p2[3], float p3[3], float *w1, float *w2, float *w3 )
+static void collision_compute_barycentric(
+ float pv[3], float p1[3], float p2[3], float p3[3], float *w1, float *w2, float *w3)
{
- /* dot_v3v3 */
-#define INPR(v1, v2) ( (v1)[0] * (v2)[0] + (v1)[1] * (v2)[1] + (v1)[2] * (v2)[2])
+ /* dot_v3v3 */
+#define INPR(v1, v2) ((v1)[0] * (v2)[0] + (v1)[1] * (v2)[1] + (v1)[2] * (v2)[2])
- double tempV1[3], tempV2[3], tempV4[3];
- double a, b, c, d, e, f;
+ double tempV1[3], tempV2[3], tempV4[3];
+ double a, b, c, d, e, f;
- sub_v3db_v3fl_v3fl(tempV1, p1, p3);
- sub_v3db_v3fl_v3fl(tempV2, p2, p3);
- sub_v3db_v3fl_v3fl(tempV4, pv, p3);
+ sub_v3db_v3fl_v3fl(tempV1, p1, p3);
+ sub_v3db_v3fl_v3fl(tempV2, p2, p3);
+ sub_v3db_v3fl_v3fl(tempV4, pv, p3);
- a = INPR ( tempV1, tempV1 );
- b = INPR ( tempV1, tempV2 );
- c = INPR ( tempV2, tempV2 );
- e = INPR ( tempV1, tempV4 );
- f = INPR ( tempV2, tempV4 );
+ a = INPR(tempV1, tempV1);
+ b = INPR(tempV1, tempV2);
+ c = INPR(tempV2, tempV2);
+ e = INPR(tempV1, tempV4);
+ f = INPR(tempV2, tempV4);
- d = ( a * c - b * b );
+ d = (a * c - b * b);
- if ( ABS ( d ) < (double)ALMOST_ZERO ) {
- *w1 = *w2 = *w3 = 1.0 / 3.0;
- return;
- }
+ if (ABS(d) < (double)ALMOST_ZERO) {
+ *w1 = *w2 = *w3 = 1.0 / 3.0;
+ return;
+ }
- w1[0] = ( float ) ( ( e * c - b * f ) / d );
+ w1[0] = (float)((e * c - b * f) / d);
- if ( w1[0] < 0 )
- w1[0] = 0;
+ if (w1[0] < 0)
+ w1[0] = 0;
- w2[0] = ( float ) ( ( f - b * ( double ) w1[0] ) / c );
+ w2[0] = (float)((f - b * (double)w1[0]) / c);
- if ( w2[0] < 0 )
- w2[0] = 0;
+ if (w2[0] < 0)
+ w2[0] = 0;
- w3[0] = 1.0f - w1[0] - w2[0];
+ w3[0] = 1.0f - w1[0] - w2[0];
#undef INPR
}
@@ -457,1131 +464,1267 @@ static void collision_compute_barycentric ( float pv[3], float p1[3], float p2[3
# pragma GCC diagnostic ignored "-Wdouble-promotion"
#endif
-DO_INLINE void collision_interpolateOnTriangle ( float to[3], float v1[3], float v2[3], float v3[3], double w1, double w2, double w3 )
+DO_INLINE void collision_interpolateOnTriangle(
+ float to[3], float v1[3], float v2[3], float v3[3], double w1, double w2, double w3)
{
- zero_v3(to);
- VECADDMUL(to, v1, w1);
- VECADDMUL(to, v2, w2);
- VECADDMUL(to, v3, w3);
+ zero_v3(to);
+ VECADDMUL(to, v1, w1);
+ VECADDMUL(to, v2, w2);
+ VECADDMUL(to, v3, w3);
}
-static int cloth_collision_response_static(ClothModifierData *clmd, CollisionModifierData *collmd, Object *collob,
- CollPair *collpair, uint collision_count, const float dt)
+static int cloth_collision_response_static(ClothModifierData *clmd,
+ CollisionModifierData *collmd,
+ Object *collob,
+ CollPair *collpair,
+ uint collision_count,
+ const float dt)
{
- int result = 0;
- Cloth *cloth1;
- float w1, w2, w3, u1, u2, u3;
- float v1[3], v2[3], relativeVelocity[3];
- float magrelVel;
- float epsilon2 = BLI_bvhtree_get_epsilon(collmd->bvhtree);
-
- cloth1 = clmd->clothObject;
-
- for (int i = 0; i < collision_count; i++, collpair++) {
- float i1[3], i2[3], i3[3];
-
- zero_v3(i1);
- zero_v3(i2);
- zero_v3(i3);
-
- /* Only handle static collisions here. */
- if (collpair->flag & (COLLISION_IN_FUTURE | COLLISION_INACTIVE)) {
- continue;
- }
-
- /* Compute barycentric coordinates for both collision points. */
- collision_compute_barycentric(collpair->pa,
- cloth1->verts[collpair->ap1].tx,
- cloth1->verts[collpair->ap2].tx,
- cloth1->verts[collpair->ap3].tx,
- &w1, &w2, &w3);
-
- collision_compute_barycentric(collpair->pb,
- collmd->current_x[collpair->bp1].co,
- collmd->current_x[collpair->bp2].co,
- collmd->current_x[collpair->bp3].co,
- &u1, &u2, &u3);
-
- /* Calculate relative "velocity". */
- collision_interpolateOnTriangle(v1, cloth1->verts[collpair->ap1].tv, cloth1->verts[collpair->ap2].tv, cloth1->verts[collpair->ap3].tv, w1, w2, w3);
-
- collision_interpolateOnTriangle(v2, collmd->current_v[collpair->bp1].co, collmd->current_v[collpair->bp2].co, collmd->current_v[collpair->bp3].co, u1, u2, u3);
-
- sub_v3_v3v3(relativeVelocity, v2, v1);
-
- /* Calculate the normal component of the relative velocity (actually only the magnitude - the direction is stored in 'normal'). */
- magrelVel = dot_v3v3(relativeVelocity, collpair->normal);
-
- /* If magrelVel < 0 the edges are approaching each other. */
- if (magrelVel > 0.0f) {
- /* Calculate Impulse magnitude to stop all motion in normal direction. */
- float magtangent = 0, repulse = 0, d = 0;
- double impulse = 0.0;
- float vrel_t_pre[3];
- float temp[3];
- float time_multiplier;
-
- /* Calculate tangential velocity. */
- copy_v3_v3(temp, collpair->normal);
- mul_v3_fl(temp, magrelVel);
- sub_v3_v3v3(vrel_t_pre, relativeVelocity, temp);
-
- /* Decrease in magnitude of relative tangential velocity due to coulomb friction
- * in original formula "magrelVel" should be the "change of relative velocity in normal direction". */
- magtangent = min_ff(collob->pd->pdef_cfrict * 0.01f * magrelVel, len_v3(vrel_t_pre));
-
- /* Apply friction impulse. */
- if ( magtangent > ALMOST_ZERO ) {
- normalize_v3(vrel_t_pre);
-
- impulse = magtangent / 1.5;
-
- VECADDMUL(i1, vrel_t_pre, w1 * impulse);
- VECADDMUL(i2, vrel_t_pre, w2 * impulse);
- VECADDMUL(i3, vrel_t_pre, w3 * impulse);
- }
-
- /* Apply velocity stopping impulse. */
- impulse = magrelVel / 1.5f;
-
- VECADDMUL(i1, collpair->normal, w1 * impulse);
- cloth1->verts[collpair->ap1].impulse_count++;
-
- VECADDMUL(i2, collpair->normal, w2 * impulse);
- cloth1->verts[collpair->ap2].impulse_count++;
-
- VECADDMUL(i3, collpair->normal, w3 * impulse);
- cloth1->verts[collpair->ap3].impulse_count++;
-
- time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale);
+ int result = 0;
+ Cloth *cloth1;
+ float w1, w2, w3, u1, u2, u3;
+ float v1[3], v2[3], relativeVelocity[3];
+ float magrelVel;
+ float epsilon2 = BLI_bvhtree_get_epsilon(collmd->bvhtree);
+
+ cloth1 = clmd->clothObject;
+
+ for (int i = 0; i < collision_count; i++, collpair++) {
+ float i1[3], i2[3], i3[3];
+
+ zero_v3(i1);
+ zero_v3(i2);
+ zero_v3(i3);
+
+ /* Only handle static collisions here. */
+ if (collpair->flag & (COLLISION_IN_FUTURE | COLLISION_INACTIVE)) {
+ continue;
+ }
+
+ /* Compute barycentric coordinates for both collision points. */
+ collision_compute_barycentric(collpair->pa,
+ cloth1->verts[collpair->ap1].tx,
+ cloth1->verts[collpair->ap2].tx,
+ cloth1->verts[collpair->ap3].tx,
+ &w1,
+ &w2,
+ &w3);
+
+ collision_compute_barycentric(collpair->pb,
+ collmd->current_x[collpair->bp1].co,
+ collmd->current_x[collpair->bp2].co,
+ collmd->current_x[collpair->bp3].co,
+ &u1,
+ &u2,
+ &u3);
+
+ /* Calculate relative "velocity". */
+ collision_interpolateOnTriangle(v1,
+ cloth1->verts[collpair->ap1].tv,
+ cloth1->verts[collpair->ap2].tv,
+ cloth1->verts[collpair->ap3].tv,
+ w1,
+ w2,
+ w3);
+
+ collision_interpolateOnTriangle(v2,
+ collmd->current_v[collpair->bp1].co,
+ collmd->current_v[collpair->bp2].co,
+ collmd->current_v[collpair->bp3].co,
+ u1,
+ u2,
+ u3);
+
+ sub_v3_v3v3(relativeVelocity, v2, v1);
+
+ /* Calculate the normal component of the relative velocity (actually only the magnitude - the direction is stored in 'normal'). */
+ magrelVel = dot_v3v3(relativeVelocity, collpair->normal);
+
+ /* If magrelVel < 0 the edges are approaching each other. */
+ if (magrelVel > 0.0f) {
+ /* Calculate Impulse magnitude to stop all motion in normal direction. */
+ float magtangent = 0, repulse = 0, d = 0;
+ double impulse = 0.0;
+ float vrel_t_pre[3];
+ float temp[3];
+ float time_multiplier;
+
+ /* Calculate tangential velocity. */
+ copy_v3_v3(temp, collpair->normal);
+ mul_v3_fl(temp, magrelVel);
+ sub_v3_v3v3(vrel_t_pre, relativeVelocity, temp);
+
+ /* Decrease in magnitude of relative tangential velocity due to coulomb friction
+ * in original formula "magrelVel" should be the "change of relative velocity in normal direction". */
+ magtangent = min_ff(collob->pd->pdef_cfrict * 0.01f * magrelVel, len_v3(vrel_t_pre));
+
+ /* Apply friction impulse. */
+ if (magtangent > ALMOST_ZERO) {
+ normalize_v3(vrel_t_pre);
+
+ impulse = magtangent / 1.5;
+
+ VECADDMUL(i1, vrel_t_pre, w1 * impulse);
+ VECADDMUL(i2, vrel_t_pre, w2 * impulse);
+ VECADDMUL(i3, vrel_t_pre, w3 * impulse);
+ }
+
+ /* Apply velocity stopping impulse. */
+ impulse = magrelVel / 1.5f;
+
+ VECADDMUL(i1, collpair->normal, w1 * impulse);
+ cloth1->verts[collpair->ap1].impulse_count++;
+
+ VECADDMUL(i2, collpair->normal, w2 * impulse);
+ cloth1->verts[collpair->ap2].impulse_count++;
+
+ VECADDMUL(i3, collpair->normal, w3 * impulse);
+ cloth1->verts[collpair->ap3].impulse_count++;
+
+ time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale);
+
+ d = clmd->coll_parms->epsilon * 8.0f / 9.0f + epsilon2 * 8.0f / 9.0f - collpair->distance;
+
+ if ((magrelVel < 0.1f * d * time_multiplier) && (d > ALMOST_ZERO)) {
+ repulse = MIN2(d / time_multiplier, 0.1f * d * time_multiplier - magrelVel);
+
+ /* Stay on the safe side and clamp repulse. */
+ if (impulse > ALMOST_ZERO) {
+ repulse = min_ff(repulse, 5.0f * impulse);
+ }
+
+ repulse = max_ff(impulse, repulse);
+
+ impulse = repulse / 1.5f;
+
+ VECADDMUL(i1, collpair->normal, impulse);
+ VECADDMUL(i2, collpair->normal, impulse);
+ VECADDMUL(i3, collpair->normal, impulse);
+ }
+
+ result = 1;
+ }
+ else {
+ float time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale);
+ float d;
+
+ d = clmd->coll_parms->epsilon * 8.0f / 9.0f + epsilon2 * 8.0f / 9.0f - collpair->distance;
+
+ if (d > ALMOST_ZERO) {
+ /* Stay on the safe side and clamp repulse. */
+ float repulse = d / time_multiplier;
+ float impulse = repulse / 4.5f;
+
+ VECADDMUL(i1, collpair->normal, w1 * impulse);
+ VECADDMUL(i2, collpair->normal, w2 * impulse);
+ VECADDMUL(i3, collpair->normal, w3 * impulse);
+
+ cloth1->verts[collpair->ap1].impulse_count++;
+ cloth1->verts[collpair->ap2].impulse_count++;
+ cloth1->verts[collpair->ap3].impulse_count++;
- d = clmd->coll_parms->epsilon*8.0f/9.0f + epsilon2*8.0f/9.0f - collpair->distance;
+ result = 1;
+ }
+ }
- if ((magrelVel < 0.1f * d * time_multiplier) && (d > ALMOST_ZERO)) {
- repulse = MIN2(d / time_multiplier, 0.1f * d * time_multiplier - magrelVel);
+ if (result) {
+ float clamp = clmd->coll_parms->clamp * dt;
- /* Stay on the safe side and clamp repulse. */
- if (impulse > ALMOST_ZERO) {
- repulse = min_ff(repulse, 5.0f * impulse);
- }
+ if ((clamp > 0.0f) &&
+ ((len_v3(i1) > clamp) || (len_v3(i2) > clamp) || (len_v3(i3) > clamp))) {
+ return 0;
+ }
- repulse = max_ff(impulse, repulse);
+ for (int j = 0; j < 3; j++) {
+ if (cloth1->verts[collpair->ap1].impulse_count > 0 &&
+ ABS(cloth1->verts[collpair->ap1].impulse[j]) < ABS(i1[j]))
+ cloth1->verts[collpair->ap1].impulse[j] = i1[j];
- impulse = repulse / 1.5f;
+ if (cloth1->verts[collpair->ap2].impulse_count > 0 &&
+ ABS(cloth1->verts[collpair->ap2].impulse[j]) < ABS(i2[j]))
+ cloth1->verts[collpair->ap2].impulse[j] = i2[j];
- VECADDMUL(i1, collpair->normal, impulse);
- VECADDMUL(i2, collpair->normal, impulse);
- VECADDMUL(i3, collpair->normal, impulse);
- }
+ if (cloth1->verts[collpair->ap3].impulse_count > 0 &&
+ ABS(cloth1->verts[collpair->ap3].impulse[j]) < ABS(i3[j]))
+ cloth1->verts[collpair->ap3].impulse[j] = i3[j];
+ }
+ }
+ }
- result = 1;
- }
- else {
- float time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale);
- float d;
-
- d = clmd->coll_parms->epsilon*8.0f/9.0f + epsilon2*8.0f/9.0f - collpair->distance;
-
- if (d > ALMOST_ZERO) {
- /* Stay on the safe side and clamp repulse. */
- float repulse = d / time_multiplier;
- float impulse = repulse / 4.5f;
-
- VECADDMUL(i1, collpair->normal, w1 * impulse);
- VECADDMUL(i2, collpair->normal, w2 * impulse);
- VECADDMUL(i3, collpair->normal, w3 * impulse);
-
- cloth1->verts[collpair->ap1].impulse_count++;
- cloth1->verts[collpair->ap2].impulse_count++;
- cloth1->verts[collpair->ap3].impulse_count++;
-
- result = 1;
- }
- }
-
- if (result) {
- float clamp = clmd->coll_parms->clamp * dt;
-
- if ((clamp > 0.0f) &&
- ((len_v3(i1) > clamp) ||
- (len_v3(i2) > clamp) ||
- (len_v3(i3) > clamp)))
- {
- return 0;
- }
-
- for (int j = 0; j < 3; j++) {
- if (cloth1->verts[collpair->ap1].impulse_count > 0 && ABS(cloth1->verts[collpair->ap1].impulse[j]) < ABS(i1[j]))
- cloth1->verts[collpair->ap1].impulse[j] = i1[j];
-
- if (cloth1->verts[collpair->ap2].impulse_count > 0 && ABS(cloth1->verts[collpair->ap2].impulse[j]) < ABS(i2[j]))
- cloth1->verts[collpair->ap2].impulse[j] = i2[j];
-
- if (cloth1->verts[collpair->ap3].impulse_count > 0 && ABS(cloth1->verts[collpair->ap3].impulse[j]) < ABS(i3[j]))
- cloth1->verts[collpair->ap3].impulse[j] = i3[j];
- }
- }
- }
-
- return result;
+ return result;
}
-static int cloth_selfcollision_response_static(ClothModifierData *clmd, CollPair *collpair,
- uint collision_count, const float dt)
+static int cloth_selfcollision_response_static(ClothModifierData *clmd,
+ CollPair *collpair,
+ uint collision_count,
+ const float dt)
{
- int result = 0;
- Cloth *cloth1;
- float w1, w2, w3, u1, u2, u3;
- float v1[3], v2[3], relativeVelocity[3];
- float magrelVel;
-
- cloth1 = clmd->clothObject;
-
- for (int i = 0; i < collision_count; i++, collpair++) {
- float i1[3], i2[3], i3[3];
-
- zero_v3(i1);
- zero_v3(i2);
- zero_v3(i3);
-
- /* Only handle static collisions here. */
- if (collpair->flag & (COLLISION_IN_FUTURE | COLLISION_INACTIVE)) {
- continue;
- }
-
- /* Compute barycentric coordinates for both collision points. */
- collision_compute_barycentric(collpair->pa,
- cloth1->verts[collpair->ap1].tx,
- cloth1->verts[collpair->ap2].tx,
- cloth1->verts[collpair->ap3].tx,
- &w1, &w2, &w3);
-
- collision_compute_barycentric(collpair->pb,
- cloth1->verts[collpair->bp1].tx,
- cloth1->verts[collpair->bp2].tx,
- cloth1->verts[collpair->bp3].tx,
- &u1, &u2, &u3);
-
- /* Calculate relative "velocity". */
- collision_interpolateOnTriangle(v1, cloth1->verts[collpair->ap1].tv, cloth1->verts[collpair->ap2].tv, cloth1->verts[collpair->ap3].tv, w1, w2, w3);
-
- collision_interpolateOnTriangle(v2, cloth1->verts[collpair->bp1].tv, cloth1->verts[collpair->bp2].tv, cloth1->verts[collpair->bp3].tv, u1, u2, u3);
-
- sub_v3_v3v3(relativeVelocity, v2, v1);
-
- /* Calculate the normal component of the relative velocity (actually only the magnitude - the direction is stored in 'normal'). */
- magrelVel = dot_v3v3(relativeVelocity, collpair->normal);
-
- /* TODO: Impulses should be weighed by mass as this is self col,
- * this has to be done after mass distribution is implemented. */
-
- /* If magrelVel < 0 the edges are approaching each other. */
- if (magrelVel > 0.0f) {
- /* Calculate Impulse magnitude to stop all motion in normal direction. */
- float magtangent = 0, repulse = 0, d = 0;
- double impulse = 0.0;
- float vrel_t_pre[3];
- float temp[3], time_multiplier;
+ int result = 0;
+ Cloth *cloth1;
+ float w1, w2, w3, u1, u2, u3;
+ float v1[3], v2[3], relativeVelocity[3];
+ float magrelVel;
+
+ cloth1 = clmd->clothObject;
+
+ for (int i = 0; i < collision_count; i++, collpair++) {
+ float i1[3], i2[3], i3[3];
+
+ zero_v3(i1);
+ zero_v3(i2);
+ zero_v3(i3);
+
+ /* Only handle static collisions here. */
+ if (collpair->flag & (COLLISION_IN_FUTURE | COLLISION_INACTIVE)) {
+ continue;
+ }
+
+ /* Compute barycentric coordinates for both collision points. */
+ collision_compute_barycentric(collpair->pa,
+ cloth1->verts[collpair->ap1].tx,
+ cloth1->verts[collpair->ap2].tx,
+ cloth1->verts[collpair->ap3].tx,
+ &w1,
+ &w2,
+ &w3);
+
+ collision_compute_barycentric(collpair->pb,
+ cloth1->verts[collpair->bp1].tx,
+ cloth1->verts[collpair->bp2].tx,
+ cloth1->verts[collpair->bp3].tx,
+ &u1,
+ &u2,
+ &u3);
+
+ /* Calculate relative "velocity". */
+ collision_interpolateOnTriangle(v1,
+ cloth1->verts[collpair->ap1].tv,
+ cloth1->verts[collpair->ap2].tv,
+ cloth1->verts[collpair->ap3].tv,
+ w1,
+ w2,
+ w3);
+
+ collision_interpolateOnTriangle(v2,
+ cloth1->verts[collpair->bp1].tv,
+ cloth1->verts[collpair->bp2].tv,
+ cloth1->verts[collpair->bp3].tv,
+ u1,
+ u2,
+ u3);
+
+ sub_v3_v3v3(relativeVelocity, v2, v1);
+
+ /* Calculate the normal component of the relative velocity (actually only the magnitude - the direction is stored in 'normal'). */
+ magrelVel = dot_v3v3(relativeVelocity, collpair->normal);
+
+ /* TODO: Impulses should be weighed by mass as this is self col,
+ * this has to be done after mass distribution is implemented. */
+
+ /* If magrelVel < 0 the edges are approaching each other. */
+ if (magrelVel > 0.0f) {
+ /* Calculate Impulse magnitude to stop all motion in normal direction. */
+ float magtangent = 0, repulse = 0, d = 0;
+ double impulse = 0.0;
+ float vrel_t_pre[3];
+ float temp[3], time_multiplier;
+
+ /* Calculate tangential velocity. */
+ copy_v3_v3(temp, collpair->normal);
+ mul_v3_fl(temp, magrelVel);
+ sub_v3_v3v3(vrel_t_pre, relativeVelocity, temp);
+
+ /* Decrease in magnitude of relative tangential velocity due to coulomb friction
+ * in original formula "magrelVel" should be the "change of relative velocity in normal direction". */
+ magtangent = min_ff(clmd->coll_parms->self_friction * 0.01f * magrelVel, len_v3(vrel_t_pre));
+
+ /* Apply friction impulse. */
+ if (magtangent > ALMOST_ZERO) {
+ normalize_v3(vrel_t_pre);
+
+ impulse = magtangent / 1.5;
+
+ VECADDMUL(i1, vrel_t_pre, w1 * impulse);
+ VECADDMUL(i2, vrel_t_pre, w2 * impulse);
+ VECADDMUL(i3, vrel_t_pre, w3 * impulse);
+ }
+
+ /* Apply velocity stopping impulse. */
+ impulse = magrelVel / 3.0f;
+
+ VECADDMUL(i1, collpair->normal, w1 * impulse);
+ cloth1->verts[collpair->ap1].impulse_count++;
+
+ VECADDMUL(i2, collpair->normal, w2 * impulse);
+ cloth1->verts[collpair->ap2].impulse_count++;
+
+ VECADDMUL(i3, collpair->normal, w3 * impulse);
+ cloth1->verts[collpair->ap3].impulse_count++;
+
+ time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale);
+
+ d = clmd->coll_parms->selfepsilon * 8.0f / 9.0f * 2.0f - collpair->distance;
+
+ if ((magrelVel < 0.1f * d * time_multiplier) && (d > ALMOST_ZERO)) {
+ repulse = MIN2(d / time_multiplier, 0.1f * d * time_multiplier - magrelVel);
+
+ if (impulse > ALMOST_ZERO) {
+ repulse = min_ff(repulse, 5.0 * impulse);
+ }
+
+ repulse = max_ff(impulse, repulse);
+
+ impulse = repulse / 1.5f;
+
+ VECADDMUL(i1, collpair->normal, w1 * impulse);
+ VECADDMUL(i2, collpair->normal, w2 * impulse);
+ VECADDMUL(i3, collpair->normal, w3 * impulse);
+ }
+
+ result = 1;
+ }
+ else {
+ float time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale);
+ float d;
+
+ d = clmd->coll_parms->selfepsilon * 8.0f / 9.0f * 2.0f - collpair->distance;
+
+ if (d > ALMOST_ZERO) {
+ /* Stay on the safe side and clamp repulse. */
+ float repulse = d * 1.0f / time_multiplier;
+ float impulse = repulse / 9.0f;
- /* Calculate tangential velocity. */
- copy_v3_v3(temp, collpair->normal);
- mul_v3_fl(temp, magrelVel);
- sub_v3_v3v3(vrel_t_pre, relativeVelocity, temp);
+ VECADDMUL(i1, collpair->normal, w1 * impulse);
+ VECADDMUL(i2, collpair->normal, w2 * impulse);
+ VECADDMUL(i3, collpair->normal, w3 * impulse);
- /* Decrease in magnitude of relative tangential velocity due to coulomb friction
- * in original formula "magrelVel" should be the "change of relative velocity in normal direction". */
- magtangent = min_ff(clmd->coll_parms->self_friction * 0.01f * magrelVel, len_v3(vrel_t_pre));
+ cloth1->verts[collpair->ap1].impulse_count++;
+ cloth1->verts[collpair->ap2].impulse_count++;
+ cloth1->verts[collpair->ap3].impulse_count++;
- /* Apply friction impulse. */
- if (magtangent > ALMOST_ZERO) {
- normalize_v3(vrel_t_pre);
+ result = 1;
+ }
+ }
- impulse = magtangent / 1.5;
+ if (result) {
+ float clamp = clmd->coll_parms->self_clamp * dt;
- VECADDMUL(i1, vrel_t_pre, w1 * impulse);
- VECADDMUL(i2, vrel_t_pre, w2 * impulse);
- VECADDMUL(i3, vrel_t_pre, w3 * impulse);
- }
+ if ((clamp > 0.0f) &&
+ ((len_v3(i1) > clamp) || (len_v3(i2) > clamp) || (len_v3(i3) > clamp))) {
+ return 0;
+ }
- /* Apply velocity stopping impulse. */
- impulse = magrelVel / 3.0f;
+ for (int j = 0; j < 3; j++) {
+ if (cloth1->verts[collpair->ap1].impulse_count > 0 &&
+ ABS(cloth1->verts[collpair->ap1].impulse[j]) < ABS(i1[j]))
+ cloth1->verts[collpair->ap1].impulse[j] = i1[j];
- VECADDMUL(i1, collpair->normal, w1 * impulse);
- cloth1->verts[collpair->ap1].impulse_count++;
+ if (cloth1->verts[collpair->ap2].impulse_count > 0 &&
+ ABS(cloth1->verts[collpair->ap2].impulse[j]) < ABS(i2[j]))
+ cloth1->verts[collpair->ap2].impulse[j] = i2[j];
- VECADDMUL(i2, collpair->normal, w2 * impulse);
- cloth1->verts[collpair->ap2].impulse_count++;
+ if (cloth1->verts[collpair->ap3].impulse_count > 0 &&
+ ABS(cloth1->verts[collpair->ap3].impulse[j]) < ABS(i3[j]))
+ cloth1->verts[collpair->ap3].impulse[j] = i3[j];
+ }
+ }
+ }
- VECADDMUL(i3, collpair->normal, w3 * impulse);
- cloth1->verts[collpair->ap3].impulse_count++;
-
- time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale);
-
- d = clmd->coll_parms->selfepsilon * 8.0f / 9.0f * 2.0f - collpair->distance;
-
- if ((magrelVel < 0.1f * d * time_multiplier) && (d > ALMOST_ZERO)) {
- repulse = MIN2 (d / time_multiplier, 0.1f * d * time_multiplier - magrelVel);
-
- if (impulse > ALMOST_ZERO) {
- repulse = min_ff(repulse, 5.0*impulse);
- }
-
- repulse = max_ff(impulse, repulse);
-
- impulse = repulse / 1.5f;
-
- VECADDMUL(i1, collpair->normal, w1 * impulse);
- VECADDMUL(i2, collpair->normal, w2 * impulse);
- VECADDMUL(i3, collpair->normal, w3 * impulse);
- }
-
- result = 1;
- }
- else {
- float time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale);
- float d;
-
- d = clmd->coll_parms->selfepsilon * 8.0f / 9.0f * 2.0f - collpair->distance;
-
- if ( d > ALMOST_ZERO) {
- /* Stay on the safe side and clamp repulse. */
- float repulse = d*1.0f/time_multiplier;
- float impulse = repulse / 9.0f;
-
- VECADDMUL(i1, collpair->normal, w1 * impulse);
- VECADDMUL(i2, collpair->normal, w2 * impulse);
- VECADDMUL(i3, collpair->normal, w3 * impulse);
-
- cloth1->verts[collpair->ap1].impulse_count++;
- cloth1->verts[collpair->ap2].impulse_count++;
- cloth1->verts[collpair->ap3].impulse_count++;
-
- result = 1;
- }
- }
-
- if (result) {
- float clamp = clmd->coll_parms->self_clamp * dt;
-
- if ((clamp > 0.0f) &&
- ((len_v3(i1) > clamp) ||
- (len_v3(i2) > clamp) ||
- (len_v3(i3) > clamp)))
- {
- return 0;
- }
-
- for (int j = 0; j < 3; j++) {
- if (cloth1->verts[collpair->ap1].impulse_count > 0 && ABS(cloth1->verts[collpair->ap1].impulse[j]) < ABS(i1[j]))
- cloth1->verts[collpair->ap1].impulse[j] = i1[j];
-
- if (cloth1->verts[collpair->ap2].impulse_count > 0 && ABS(cloth1->verts[collpair->ap2].impulse[j]) < ABS(i2[j]))
- cloth1->verts[collpair->ap2].impulse[j] = i2[j];
-
- if (cloth1->verts[collpair->ap3].impulse_count > 0 && ABS(cloth1->verts[collpair->ap3].impulse[j]) < ABS(i3[j]))
- cloth1->verts[collpair->ap3].impulse[j] = i3[j];
- }
- }
- }
-
- return result;
+ return result;
}
#ifdef __GNUC__
# pragma GCC diagnostic pop
#endif
-static void cloth_collision(
- void *__restrict userdata,
- const int index,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void cloth_collision(void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- ColDetectData *data = (ColDetectData *)userdata;
-
- ClothModifierData *clmd = data->clmd;
- CollisionModifierData *collmd = data->collmd;
- CollPair *collpair = data->collisions;
- const MVertTri *tri_a, *tri_b;
- ClothVertex *verts1 = clmd->clothObject->verts;
- float distance = 0.0f;
- float epsilon1 = clmd->coll_parms->epsilon;
- float epsilon2 = BLI_bvhtree_get_epsilon(collmd->bvhtree);
- float pa[3], pb[3], vect[3];
-
- tri_a = &clmd->clothObject->tri[data->overlap[index].indexA];
- tri_b = &collmd->tri[data->overlap[index].indexB];
-
- /* Compute distance and normal. */
- distance = compute_collision_point(verts1[tri_a->tri[0]].tx, verts1[tri_a->tri[1]].tx, verts1[tri_a->tri[2]].tx,
- collmd->current_x[tri_b->tri[0]].co, collmd->current_x[tri_b->tri[1]].co, collmd->current_x[tri_b->tri[2]].co,
- data->culling, data->use_normal, pa, pb, vect);
-
- if ((distance <= (epsilon1 + epsilon2 + ALMOST_ZERO)) && (len_squared_v3(vect) > ALMOST_ZERO)) {
- collpair[index].ap1 = tri_a->tri[0];
- collpair[index].ap2 = tri_a->tri[1];
- collpair[index].ap3 = tri_a->tri[2];
-
- collpair[index].bp1 = tri_b->tri[0];
- collpair[index].bp2 = tri_b->tri[1];
- collpair[index].bp3 = tri_b->tri[2];
-
- copy_v3_v3(collpair[index].pa, pa);
- copy_v3_v3(collpair[index].pb, pb);
- copy_v3_v3(collpair[index].vector, vect);
-
- normalize_v3_v3(collpair[index].normal, collpair[index].vector);
-
- collpair[index].distance = distance;
- collpair[index].flag = 0;
-
- data->collided = true;
- }
- else {
- collpair[index].flag = COLLISION_INACTIVE;
- }
+ ColDetectData *data = (ColDetectData *)userdata;
+
+ ClothModifierData *clmd = data->clmd;
+ CollisionModifierData *collmd = data->collmd;
+ CollPair *collpair = data->collisions;
+ const MVertTri *tri_a, *tri_b;
+ ClothVertex *verts1 = clmd->clothObject->verts;
+ float distance = 0.0f;
+ float epsilon1 = clmd->coll_parms->epsilon;
+ float epsilon2 = BLI_bvhtree_get_epsilon(collmd->bvhtree);
+ float pa[3], pb[3], vect[3];
+
+ tri_a = &clmd->clothObject->tri[data->overlap[index].indexA];
+ tri_b = &collmd->tri[data->overlap[index].indexB];
+
+ /* Compute distance and normal. */
+ distance = compute_collision_point(verts1[tri_a->tri[0]].tx,
+ verts1[tri_a->tri[1]].tx,
+ verts1[tri_a->tri[2]].tx,
+ collmd->current_x[tri_b->tri[0]].co,
+ collmd->current_x[tri_b->tri[1]].co,
+ collmd->current_x[tri_b->tri[2]].co,
+ data->culling,
+ data->use_normal,
+ pa,
+ pb,
+ vect);
+
+ if ((distance <= (epsilon1 + epsilon2 + ALMOST_ZERO)) && (len_squared_v3(vect) > ALMOST_ZERO)) {
+ collpair[index].ap1 = tri_a->tri[0];
+ collpair[index].ap2 = tri_a->tri[1];
+ collpair[index].ap3 = tri_a->tri[2];
+
+ collpair[index].bp1 = tri_b->tri[0];
+ collpair[index].bp2 = tri_b->tri[1];
+ collpair[index].bp3 = tri_b->tri[2];
+
+ copy_v3_v3(collpair[index].pa, pa);
+ copy_v3_v3(collpair[index].pb, pb);
+ copy_v3_v3(collpair[index].vector, vect);
+
+ normalize_v3_v3(collpair[index].normal, collpair[index].vector);
+
+ collpair[index].distance = distance;
+ collpair[index].flag = 0;
+
+ data->collided = true;
+ }
+ else {
+ collpair[index].flag = COLLISION_INACTIVE;
+ }
}
-static void cloth_selfcollision(
- void *__restrict userdata,
- const int index,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void cloth_selfcollision(void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- SelfColDetectData *data = (SelfColDetectData *)userdata;
-
- ClothModifierData *clmd = data->clmd;
- CollPair *collpair = data->collisions;
- const MVertTri *tri_a, *tri_b;
- ClothVertex *verts1 = clmd->clothObject->verts;
- float distance = 0.0f;
- float epsilon = clmd->coll_parms->selfepsilon;
- float pa[3], pb[3], vect[3];
-
- tri_a = &clmd->clothObject->tri[data->overlap[index].indexA];
- tri_b = &clmd->clothObject->tri[data->overlap[index].indexB];
-
- for (uint i = 0; i < 3; i++) {
- for (uint j = 0; j < 3; j++) {
- if (tri_a->tri[i] == tri_b->tri[j]) {
- collpair[index].flag = COLLISION_INACTIVE;
- return;
- }
- }
- }
-
- if (((verts1[tri_a->tri[0]].flags & verts1[tri_a->tri[1]].flags & verts1[tri_a->tri[2]].flags) |
- (verts1[tri_b->tri[0]].flags & verts1[tri_b->tri[1]].flags & verts1[tri_b->tri[2]].flags)) & CLOTH_VERT_FLAG_NOSELFCOLL)
- {
- collpair[index].flag = COLLISION_INACTIVE;
- return;
- }
-
- /* Compute distance and normal. */
- distance = compute_collision_point(verts1[tri_a->tri[0]].tx, verts1[tri_a->tri[1]].tx, verts1[tri_a->tri[2]].tx,
- verts1[tri_b->tri[0]].tx, verts1[tri_b->tri[1]].tx, verts1[tri_b->tri[2]].tx,
- false, false, pa, pb, vect);
-
- if ((distance <= (epsilon * 2.0f + ALMOST_ZERO)) && (len_squared_v3(vect) > ALMOST_ZERO)) {
- collpair[index].ap1 = tri_a->tri[0];
- collpair[index].ap2 = tri_a->tri[1];
- collpair[index].ap3 = tri_a->tri[2];
-
- collpair[index].bp1 = tri_b->tri[0];
- collpair[index].bp2 = tri_b->tri[1];
- collpair[index].bp3 = tri_b->tri[2];
-
- copy_v3_v3(collpair[index].pa, pa);
- copy_v3_v3(collpair[index].pb, pb);
- copy_v3_v3(collpair[index].vector, vect);
-
- normalize_v3_v3(collpair[index].normal, collpair[index].vector);
-
- collpair[index].distance = distance;
- collpair[index].flag = 0;
-
- data->collided = true;
- }
- else {
- collpair[index].flag = COLLISION_INACTIVE;
- }
+ SelfColDetectData *data = (SelfColDetectData *)userdata;
+
+ ClothModifierData *clmd = data->clmd;
+ CollPair *collpair = data->collisions;
+ const MVertTri *tri_a, *tri_b;
+ ClothVertex *verts1 = clmd->clothObject->verts;
+ float distance = 0.0f;
+ float epsilon = clmd->coll_parms->selfepsilon;
+ float pa[3], pb[3], vect[3];
+
+ tri_a = &clmd->clothObject->tri[data->overlap[index].indexA];
+ tri_b = &clmd->clothObject->tri[data->overlap[index].indexB];
+
+ for (uint i = 0; i < 3; i++) {
+ for (uint j = 0; j < 3; j++) {
+ if (tri_a->tri[i] == tri_b->tri[j]) {
+ collpair[index].flag = COLLISION_INACTIVE;
+ return;
+ }
+ }
+ }
+
+ if (((verts1[tri_a->tri[0]].flags & verts1[tri_a->tri[1]].flags & verts1[tri_a->tri[2]].flags) |
+ (verts1[tri_b->tri[0]].flags & verts1[tri_b->tri[1]].flags & verts1[tri_b->tri[2]].flags)) &
+ CLOTH_VERT_FLAG_NOSELFCOLL) {
+ collpair[index].flag = COLLISION_INACTIVE;
+ return;
+ }
+
+ /* Compute distance and normal. */
+ distance = compute_collision_point(verts1[tri_a->tri[0]].tx,
+ verts1[tri_a->tri[1]].tx,
+ verts1[tri_a->tri[2]].tx,
+ verts1[tri_b->tri[0]].tx,
+ verts1[tri_b->tri[1]].tx,
+ verts1[tri_b->tri[2]].tx,
+ false,
+ false,
+ pa,
+ pb,
+ vect);
+
+ if ((distance <= (epsilon * 2.0f + ALMOST_ZERO)) && (len_squared_v3(vect) > ALMOST_ZERO)) {
+ collpair[index].ap1 = tri_a->tri[0];
+ collpair[index].ap2 = tri_a->tri[1];
+ collpair[index].ap3 = tri_a->tri[2];
+
+ collpair[index].bp1 = tri_b->tri[0];
+ collpair[index].bp2 = tri_b->tri[1];
+ collpair[index].bp3 = tri_b->tri[2];
+
+ copy_v3_v3(collpair[index].pa, pa);
+ copy_v3_v3(collpair[index].pb, pb);
+ copy_v3_v3(collpair[index].vector, vect);
+
+ normalize_v3_v3(collpair[index].normal, collpair[index].vector);
+
+ collpair[index].distance = distance;
+ collpair[index].flag = 0;
+
+ data->collided = true;
+ }
+ else {
+ collpair[index].flag = COLLISION_INACTIVE;
+ }
}
-static void add_collision_object(ListBase *relations, Object *ob, int level, unsigned int modifier_type)
+static void add_collision_object(ListBase *relations,
+ Object *ob,
+ int level,
+ unsigned int modifier_type)
{
- CollisionModifierData *cmd= NULL;
-
- /* only get objects with collision modifier */
- if (((modifier_type == eModifierType_Collision) && ob->pd && ob->pd->deflect) || (modifier_type != eModifierType_Collision))
- cmd= (CollisionModifierData *)modifiers_findByType(ob, modifier_type);
-
- if (cmd) {
- CollisionRelation *relation = MEM_callocN(sizeof(CollisionRelation), "CollisionRelation");
- relation->ob = ob;
- BLI_addtail(relations, relation);
- }
-
- /* objects in dupli groups, one level only for now */
- /* TODO: this doesn't really work, we are not taking into account the
- * dupli transforms and can get objects in the list multiple times. */
- if (ob->instance_collection && level == 0) {
- Collection *collection= ob->instance_collection;
-
- /* add objects */
- FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(collection, object)
- {
- add_collision_object(relations, object, level+1, modifier_type);
- }
- FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
- }
+ CollisionModifierData *cmd = NULL;
+
+ /* only get objects with collision modifier */
+ if (((modifier_type == eModifierType_Collision) && ob->pd && ob->pd->deflect) ||
+ (modifier_type != eModifierType_Collision))
+ cmd = (CollisionModifierData *)modifiers_findByType(ob, modifier_type);
+
+ if (cmd) {
+ CollisionRelation *relation = MEM_callocN(sizeof(CollisionRelation), "CollisionRelation");
+ relation->ob = ob;
+ BLI_addtail(relations, relation);
+ }
+
+ /* objects in dupli groups, one level only for now */
+ /* TODO: this doesn't really work, we are not taking into account the
+ * dupli transforms and can get objects in the list multiple times. */
+ if (ob->instance_collection && level == 0) {
+ Collection *collection = ob->instance_collection;
+
+ /* add objects */
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection, object) {
+ add_collision_object(relations, object, level + 1, modifier_type);
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+ }
}
/* Create list of collision relations in the collection or entire scene.
* This is used by the depsgraph to build relations, as well as faster
* lookup of colliders during evaluation. */
-ListBase *BKE_collision_relations_create(Depsgraph *depsgraph, Collection *collection, unsigned int modifier_type)
+ListBase *BKE_collision_relations_create(Depsgraph *depsgraph,
+ Collection *collection,
+ unsigned int modifier_type)
{
- ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
- Base *base = BKE_collection_or_layer_objects(view_layer, collection);
- const bool for_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
- const int base_flag = (for_render) ? BASE_ENABLED_RENDER : BASE_ENABLED_VIEWPORT;
+ ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
+ Base *base = BKE_collection_or_layer_objects(view_layer, collection);
+ const bool for_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
+ const int base_flag = (for_render) ? BASE_ENABLED_RENDER : BASE_ENABLED_VIEWPORT;
- ListBase *relations = MEM_callocN(sizeof(ListBase), "CollisionRelation list");
+ ListBase *relations = MEM_callocN(sizeof(ListBase), "CollisionRelation list");
- for (; base; base = base->next) {
- if (base->flag & base_flag) {
- add_collision_object(relations, base->object, 0, modifier_type);
- }
- }
+ for (; base; base = base->next) {
+ if (base->flag & base_flag) {
+ add_collision_object(relations, base->object, 0, modifier_type);
+ }
+ }
- return relations;
+ return relations;
}
void BKE_collision_relations_free(ListBase *relations)
{
- if (relations) {
- BLI_freelistN(relations);
- MEM_freeN(relations);
- }
+ if (relations) {
+ BLI_freelistN(relations);
+ MEM_freeN(relations);
+ }
}
/* Create effective list of colliders from relations built beforehand.
* Self will be excluded. */
-Object **BKE_collision_objects_create(Depsgraph *depsgraph, Object *self, Collection *collection, unsigned int *numcollobj, unsigned int modifier_type)
+Object **BKE_collision_objects_create(Depsgraph *depsgraph,
+ Object *self,
+ Collection *collection,
+ unsigned int *numcollobj,
+ unsigned int modifier_type)
{
- ListBase *relations = DEG_get_collision_relations(depsgraph, collection, modifier_type);
-
- if (!relations) {
- *numcollobj = 0;
- return NULL;
- }
-
- int maxnum = BLI_listbase_count(relations);
- int num = 0;
- Object **objects = MEM_callocN(sizeof(Object*) * maxnum, __func__);
-
- for (CollisionRelation *relation = relations->first; relation; relation = relation->next) {
- /* Get evaluated object. */
- Object *ob = (Object*)DEG_get_evaluated_id(depsgraph, &relation->ob->id);
-
- if (ob != self) {
- objects[num] = ob;
- num++;
- }
- }
-
- if (num == 0) {
- MEM_freeN(objects);
- objects = NULL;
- }
-
- *numcollobj = num;
- return objects;
+ ListBase *relations = DEG_get_collision_relations(depsgraph, collection, modifier_type);
+
+ if (!relations) {
+ *numcollobj = 0;
+ return NULL;
+ }
+
+ int maxnum = BLI_listbase_count(relations);
+ int num = 0;
+ Object **objects = MEM_callocN(sizeof(Object *) * maxnum, __func__);
+
+ for (CollisionRelation *relation = relations->first; relation; relation = relation->next) {
+ /* Get evaluated object. */
+ Object *ob = (Object *)DEG_get_evaluated_id(depsgraph, &relation->ob->id);
+
+ if (ob != self) {
+ objects[num] = ob;
+ num++;
+ }
+ }
+
+ if (num == 0) {
+ MEM_freeN(objects);
+ objects = NULL;
+ }
+
+ *numcollobj = num;
+ return objects;
}
void BKE_collision_objects_free(Object **objects)
{
- if (objects) {
- MEM_freeN(objects);
- }
+ if (objects) {
+ MEM_freeN(objects);
+ }
}
/* Create effective list of colliders from relations built beforehand.
* Self will be excluded. */
ListBase *BKE_collider_cache_create(Depsgraph *depsgraph, Object *self, Collection *collection)
{
- ListBase *relations = DEG_get_collision_relations(depsgraph, collection, eModifierType_Collision);
- ListBase *cache = NULL;
-
- if (!relations) {
- return NULL;
- }
-
- for (CollisionRelation *relation = relations->first; relation; relation = relation->next) {
- /* Get evaluated object. */
- Object *ob = (Object*)DEG_get_evaluated_id(depsgraph, &relation->ob->id);
-
- if (ob == self) {
- continue;
- }
-
- CollisionModifierData *cmd = (CollisionModifierData *)modifiers_findByType(ob, eModifierType_Collision);
- if (cmd && cmd->bvhtree) {
- if (cache == NULL) {
- cache = MEM_callocN(sizeof(ListBase), "ColliderCache array");
- }
-
- ColliderCache *col = MEM_callocN(sizeof(ColliderCache), "ColliderCache");
- col->ob = ob;
- col->collmd = cmd;
- /* make sure collider is properly set up */
- collision_move_object(cmd, 1.0, 0.0);
- BLI_addtail(cache, col);
- }
- }
-
- return cache;
+ ListBase *relations = DEG_get_collision_relations(
+ depsgraph, collection, eModifierType_Collision);
+ ListBase *cache = NULL;
+
+ if (!relations) {
+ return NULL;
+ }
+
+ for (CollisionRelation *relation = relations->first; relation; relation = relation->next) {
+ /* Get evaluated object. */
+ Object *ob = (Object *)DEG_get_evaluated_id(depsgraph, &relation->ob->id);
+
+ if (ob == self) {
+ continue;
+ }
+
+ CollisionModifierData *cmd = (CollisionModifierData *)modifiers_findByType(
+ ob, eModifierType_Collision);
+ if (cmd && cmd->bvhtree) {
+ if (cache == NULL) {
+ cache = MEM_callocN(sizeof(ListBase), "ColliderCache array");
+ }
+
+ ColliderCache *col = MEM_callocN(sizeof(ColliderCache), "ColliderCache");
+ col->ob = ob;
+ col->collmd = cmd;
+ /* make sure collider is properly set up */
+ collision_move_object(cmd, 1.0, 0.0);
+ BLI_addtail(cache, col);
+ }
+ }
+
+ return cache;
}
void BKE_collider_cache_free(ListBase **colliders)
{
- if (*colliders) {
- BLI_freelistN(*colliders);
- MEM_freeN(*colliders);
- *colliders = NULL;
- }
+ if (*colliders) {
+ BLI_freelistN(*colliders);
+ MEM_freeN(*colliders);
+ *colliders = NULL;
+ }
}
-static bool cloth_bvh_objcollisions_nearcheck(ClothModifierData * clmd, CollisionModifierData *collmd,
- CollPair **collisions, int numresult,
- BVHTreeOverlap *overlap, bool culling, bool use_normal)
+static bool cloth_bvh_objcollisions_nearcheck(ClothModifierData *clmd,
+ CollisionModifierData *collmd,
+ CollPair **collisions,
+ int numresult,
+ BVHTreeOverlap *overlap,
+ bool culling,
+ bool use_normal)
{
- *collisions = (CollPair *)MEM_mallocN(sizeof(CollPair) * numresult, "collision array");
-
- ColDetectData data = {
- .clmd = clmd,
- .collmd = collmd,
- .overlap = overlap,
- .collisions = *collisions,
- .culling = culling,
- .use_normal = use_normal,
- .collided = false,
- };
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = true;
- BLI_task_parallel_range(0, numresult, &data, cloth_collision, &settings);
-
- return data.collided;
+ *collisions = (CollPair *)MEM_mallocN(sizeof(CollPair) * numresult, "collision array");
+
+ ColDetectData data = {
+ .clmd = clmd,
+ .collmd = collmd,
+ .overlap = overlap,
+ .collisions = *collisions,
+ .culling = culling,
+ .use_normal = use_normal,
+ .collided = false,
+ };
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = true;
+ BLI_task_parallel_range(0, numresult, &data, cloth_collision, &settings);
+
+ return data.collided;
}
-static bool cloth_bvh_selfcollisions_nearcheck(ClothModifierData * clmd, CollPair *collisions,
- int numresult, BVHTreeOverlap *overlap)
+static bool cloth_bvh_selfcollisions_nearcheck(ClothModifierData *clmd,
+ CollPair *collisions,
+ int numresult,
+ BVHTreeOverlap *overlap)
{
- SelfColDetectData data = {
- .clmd = clmd,
- .overlap = overlap,
- .collisions = collisions,
- .collided = false,
- };
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = true;
- BLI_task_parallel_range(0, numresult, &data, cloth_selfcollision, &settings);
-
- return data.collided;
+ SelfColDetectData data = {
+ .clmd = clmd,
+ .overlap = overlap,
+ .collisions = collisions,
+ .collided = false,
+ };
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = true;
+ BLI_task_parallel_range(0, numresult, &data, cloth_selfcollision, &settings);
+
+ return data.collided;
}
-static int cloth_bvh_objcollisions_resolve(ClothModifierData * clmd, Object **collobjs, CollPair **collisions,
- uint *collision_counts, const uint numcollobj, const float dt)
+static int cloth_bvh_objcollisions_resolve(ClothModifierData *clmd,
+ Object **collobjs,
+ CollPair **collisions,
+ uint *collision_counts,
+ const uint numcollobj,
+ const float dt)
{
- Cloth *cloth = clmd->clothObject;
- int i = 0, j = 0, mvert_num = 0;
- ClothVertex *verts = NULL;
- int ret = 0;
- int result = 0;
-
- mvert_num = clmd->clothObject->mvert_num;
- verts = cloth->verts;
-
- result = 1;
-
- for (j = 0; j < 2; j++) {
- result = 0;
-
- for (i = 0; i < numcollobj; i++) {
- Object *collob= collobjs[i];
- CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision);
-
- if ( collmd->bvhtree ) {
- result += cloth_collision_response_static(clmd, collmd, collob, collisions[i], collision_counts[i], dt);
- }
- }
-
- /* Apply impulses in parallel. */
- if (result) {
- for (i = 0; i < mvert_num; i++) {
- // calculate "velocities" (just xnew = xold + v; no dt in v)
- if (verts[i].impulse_count) {
- add_v3_v3(verts[i].tv, verts[i].impulse);
- add_v3_v3(verts[i].dcvel, verts[i].impulse);
- zero_v3(verts[i].impulse);
- verts[i].impulse_count = 0;
-
- ret++;
- }
- }
- }
- else {
- break;
- }
- }
- return ret;
+ Cloth *cloth = clmd->clothObject;
+ int i = 0, j = 0, mvert_num = 0;
+ ClothVertex *verts = NULL;
+ int ret = 0;
+ int result = 0;
+
+ mvert_num = clmd->clothObject->mvert_num;
+ verts = cloth->verts;
+
+ result = 1;
+
+ for (j = 0; j < 2; j++) {
+ result = 0;
+
+ for (i = 0; i < numcollobj; i++) {
+ Object *collob = collobjs[i];
+ CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(
+ collob, eModifierType_Collision);
+
+ if (collmd->bvhtree) {
+ result += cloth_collision_response_static(
+ clmd, collmd, collob, collisions[i], collision_counts[i], dt);
+ }
+ }
+
+ /* Apply impulses in parallel. */
+ if (result) {
+ for (i = 0; i < mvert_num; i++) {
+ // calculate "velocities" (just xnew = xold + v; no dt in v)
+ if (verts[i].impulse_count) {
+ add_v3_v3(verts[i].tv, verts[i].impulse);
+ add_v3_v3(verts[i].dcvel, verts[i].impulse);
+ zero_v3(verts[i].impulse);
+ verts[i].impulse_count = 0;
+
+ ret++;
+ }
+ }
+ }
+ else {
+ break;
+ }
+ }
+ return ret;
}
-static int cloth_bvh_selfcollisions_resolve(ClothModifierData * clmd, CollPair *collisions, int collision_count, const float dt)
+static int cloth_bvh_selfcollisions_resolve(ClothModifierData *clmd,
+ CollPair *collisions,
+ int collision_count,
+ const float dt)
{
- Cloth *cloth = clmd->clothObject;
- int i = 0, j = 0, mvert_num = 0;
- ClothVertex *verts = NULL;
- int ret = 0;
- int result = 0;
-
- mvert_num = clmd->clothObject->mvert_num;
- verts = cloth->verts;
-
- for (j = 0; j < 2; j++) {
- result = 0;
-
- result += cloth_selfcollision_response_static(clmd, collisions, collision_count, dt);
-
- /* Apply impulses in parallel. */
- if (result) {
- for (i = 0; i < mvert_num; i++) {
- if (verts[i].impulse_count) {
- // VECADDMUL ( verts[i].tv, verts[i].impulse, 1.0f / verts[i].impulse_count );
- add_v3_v3(verts[i].tv, verts[i].impulse);
- add_v3_v3(verts[i].dcvel, verts[i].impulse);
- zero_v3(verts[i].impulse);
- verts[i].impulse_count = 0;
-
- ret++;
- }
- }
- }
-
- if (!result) {
- break;
- }
- }
- return ret;
+ Cloth *cloth = clmd->clothObject;
+ int i = 0, j = 0, mvert_num = 0;
+ ClothVertex *verts = NULL;
+ int ret = 0;
+ int result = 0;
+
+ mvert_num = clmd->clothObject->mvert_num;
+ verts = cloth->verts;
+
+ for (j = 0; j < 2; j++) {
+ result = 0;
+
+ result += cloth_selfcollision_response_static(clmd, collisions, collision_count, dt);
+
+ /* Apply impulses in parallel. */
+ if (result) {
+ for (i = 0; i < mvert_num; i++) {
+ if (verts[i].impulse_count) {
+ // VECADDMUL ( verts[i].tv, verts[i].impulse, 1.0f / verts[i].impulse_count );
+ add_v3_v3(verts[i].tv, verts[i].impulse);
+ add_v3_v3(verts[i].dcvel, verts[i].impulse);
+ zero_v3(verts[i].impulse);
+ verts[i].impulse_count = 0;
+
+ ret++;
+ }
+ }
+ }
+
+ if (!result) {
+ break;
+ }
+ }
+ return ret;
}
-int cloth_bvh_collision(Depsgraph *depsgraph, Object *ob, ClothModifierData *clmd, float step, float dt)
+int cloth_bvh_collision(
+ Depsgraph *depsgraph, Object *ob, ClothModifierData *clmd, float step, float dt)
{
- Cloth *cloth = clmd->clothObject;
- BVHTree *cloth_bvh = cloth->bvhtree;
- uint i = 0, mvert_num = 0;
- int rounds = 0;
- ClothVertex *verts = NULL;
- int ret = 0, ret2 = 0;
- Object **collobjs = NULL;
- unsigned int numcollobj = 0;
- uint *coll_counts_obj = NULL;
- BVHTreeOverlap **overlap_obj = NULL;
- uint coll_count_self = 0;
- BVHTreeOverlap *overlap_self = NULL;
-
- if ((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_COLLOBJ) || cloth_bvh==NULL)
- return 0;
-
- verts = cloth->verts;
- mvert_num = cloth->mvert_num;
-
- if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) {
- bvhtree_update_from_cloth(clmd, false, false);
-
- collobjs = BKE_collision_objects_create(depsgraph, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision);
-
- if (collobjs) {
- coll_counts_obj = MEM_callocN(sizeof(uint) * numcollobj, "CollCounts");
- overlap_obj = MEM_callocN(sizeof(*overlap_obj) * numcollobj, "BVHOverlap");
-
- for (i = 0; i < numcollobj; i++) {
- Object *collob = collobjs[i];
- CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision);
-
- if (!collmd->bvhtree) {
- continue;
- }
-
- /* Move object to position (step) in time. */
- collision_move_object(collmd, step + dt, step);
-
- overlap_obj[i] = BLI_bvhtree_overlap(cloth_bvh, collmd->bvhtree, &coll_counts_obj[i], NULL, NULL);
- }
- }
- }
-
- if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF) {
- bvhtree_update_from_cloth(clmd, false, true);
-
- overlap_self = BLI_bvhtree_overlap(cloth->bvhselftree, cloth->bvhselftree, &coll_count_self, NULL, NULL);
- }
-
- do {
- ret2 = 0;
-
- /* Object collisions. */
- if ((clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) && collobjs) {
- CollPair **collisions;
- bool collided = false;
-
- collisions = MEM_callocN(sizeof(CollPair *) * numcollobj, "CollPair");
-
- for (i = 0; i < numcollobj; i++) {
- Object *collob = collobjs[i];
- CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision);
-
- if (!collmd->bvhtree) {
- continue;
- }
-
- if (coll_counts_obj[i] && overlap_obj[i]) {
- collided = cloth_bvh_objcollisions_nearcheck(clmd, collmd, &collisions[i], coll_counts_obj[i], overlap_obj[i],
- (collob->pd->flag & PFIELD_CLOTH_USE_CULLING),
- (collob->pd->flag & PFIELD_CLOTH_USE_NORMAL)) || collided;
- }
- }
-
- if (collided) {
- ret += cloth_bvh_objcollisions_resolve(clmd, collobjs, collisions, coll_counts_obj, numcollobj, dt);
- ret2 += ret;
- }
-
- for (i = 0; i < numcollobj; i++) {
- MEM_SAFE_FREE(collisions[i]);
- }
-
- MEM_freeN(collisions);
- }
-
- /* Self collisions. */
- if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF) {
- CollPair *collisions = NULL;
-
- verts = cloth->verts;
- mvert_num = cloth->mvert_num;
-
- if (cloth->bvhselftree) {
- if (coll_count_self && overlap_self) {
- collisions = (CollPair *)MEM_mallocN(sizeof(CollPair) * coll_count_self, "collision array");
-
- if (cloth_bvh_selfcollisions_nearcheck(clmd, collisions, coll_count_self, overlap_self)) {
- ret += cloth_bvh_selfcollisions_resolve(clmd, collisions, coll_count_self, dt);
- ret2 += ret;
- }
- }
-
- }
-
- MEM_SAFE_FREE(collisions);
- }
-
- /* Apply all collision resolution. */
- if (ret2) {
- for (i = 0; i < mvert_num; i++) {
- if (clmd->sim_parms->vgroup_mass > 0) {
- if (verts [i].flags & CLOTH_VERT_FLAG_PINNED) {
- continue;
- }
- }
-
- add_v3_v3v3(verts[i].tx, verts[i].txold, verts[i].tv);
- }
- }
-
- rounds++;
- }
- while (ret2 && (clmd->coll_parms->loop_count > rounds));
-
- if (overlap_obj) {
- for (i = 0; i < numcollobj; i++) {
- MEM_SAFE_FREE(overlap_obj[i]);
- }
-
- MEM_freeN(overlap_obj);
- }
-
- MEM_SAFE_FREE(coll_counts_obj);
-
- MEM_SAFE_FREE(overlap_self);
-
- BKE_collision_objects_free(collobjs);
-
- return MIN2(ret, 1);
+ Cloth *cloth = clmd->clothObject;
+ BVHTree *cloth_bvh = cloth->bvhtree;
+ uint i = 0, mvert_num = 0;
+ int rounds = 0;
+ ClothVertex *verts = NULL;
+ int ret = 0, ret2 = 0;
+ Object **collobjs = NULL;
+ unsigned int numcollobj = 0;
+ uint *coll_counts_obj = NULL;
+ BVHTreeOverlap **overlap_obj = NULL;
+ uint coll_count_self = 0;
+ BVHTreeOverlap *overlap_self = NULL;
+
+ if ((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_COLLOBJ) || cloth_bvh == NULL)
+ return 0;
+
+ verts = cloth->verts;
+ mvert_num = cloth->mvert_num;
+
+ if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) {
+ bvhtree_update_from_cloth(clmd, false, false);
+
+ collobjs = BKE_collision_objects_create(
+ depsgraph, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision);
+
+ if (collobjs) {
+ coll_counts_obj = MEM_callocN(sizeof(uint) * numcollobj, "CollCounts");
+ overlap_obj = MEM_callocN(sizeof(*overlap_obj) * numcollobj, "BVHOverlap");
+
+ for (i = 0; i < numcollobj; i++) {
+ Object *collob = collobjs[i];
+ CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(
+ collob, eModifierType_Collision);
+
+ if (!collmd->bvhtree) {
+ continue;
+ }
+
+ /* Move object to position (step) in time. */
+ collision_move_object(collmd, step + dt, step);
+
+ overlap_obj[i] = BLI_bvhtree_overlap(
+ cloth_bvh, collmd->bvhtree, &coll_counts_obj[i], NULL, NULL);
+ }
+ }
+ }
+
+ if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF) {
+ bvhtree_update_from_cloth(clmd, false, true);
+
+ overlap_self = BLI_bvhtree_overlap(
+ cloth->bvhselftree, cloth->bvhselftree, &coll_count_self, NULL, NULL);
+ }
+
+ do {
+ ret2 = 0;
+
+ /* Object collisions. */
+ if ((clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) && collobjs) {
+ CollPair **collisions;
+ bool collided = false;
+
+ collisions = MEM_callocN(sizeof(CollPair *) * numcollobj, "CollPair");
+
+ for (i = 0; i < numcollobj; i++) {
+ Object *collob = collobjs[i];
+ CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(
+ collob, eModifierType_Collision);
+
+ if (!collmd->bvhtree) {
+ continue;
+ }
+
+ if (coll_counts_obj[i] && overlap_obj[i]) {
+ collided = cloth_bvh_objcollisions_nearcheck(
+ clmd,
+ collmd,
+ &collisions[i],
+ coll_counts_obj[i],
+ overlap_obj[i],
+ (collob->pd->flag & PFIELD_CLOTH_USE_CULLING),
+ (collob->pd->flag & PFIELD_CLOTH_USE_NORMAL)) ||
+ collided;
+ }
+ }
+
+ if (collided) {
+ ret += cloth_bvh_objcollisions_resolve(
+ clmd, collobjs, collisions, coll_counts_obj, numcollobj, dt);
+ ret2 += ret;
+ }
+
+ for (i = 0; i < numcollobj; i++) {
+ MEM_SAFE_FREE(collisions[i]);
+ }
+
+ MEM_freeN(collisions);
+ }
+
+ /* Self collisions. */
+ if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF) {
+ CollPair *collisions = NULL;
+
+ verts = cloth->verts;
+ mvert_num = cloth->mvert_num;
+
+ if (cloth->bvhselftree) {
+ if (coll_count_self && overlap_self) {
+ collisions = (CollPair *)MEM_mallocN(sizeof(CollPair) * coll_count_self,
+ "collision array");
+
+ if (cloth_bvh_selfcollisions_nearcheck(
+ clmd, collisions, coll_count_self, overlap_self)) {
+ ret += cloth_bvh_selfcollisions_resolve(clmd, collisions, coll_count_self, dt);
+ ret2 += ret;
+ }
+ }
+ }
+
+ MEM_SAFE_FREE(collisions);
+ }
+
+ /* Apply all collision resolution. */
+ if (ret2) {
+ for (i = 0; i < mvert_num; i++) {
+ if (clmd->sim_parms->vgroup_mass > 0) {
+ if (verts[i].flags & CLOTH_VERT_FLAG_PINNED) {
+ continue;
+ }
+ }
+
+ add_v3_v3v3(verts[i].tx, verts[i].txold, verts[i].tv);
+ }
+ }
+
+ rounds++;
+ } while (ret2 && (clmd->coll_parms->loop_count > rounds));
+
+ if (overlap_obj) {
+ for (i = 0; i < numcollobj; i++) {
+ MEM_SAFE_FREE(overlap_obj[i]);
+ }
+
+ MEM_freeN(overlap_obj);
+ }
+
+ MEM_SAFE_FREE(coll_counts_obj);
+
+ MEM_SAFE_FREE(overlap_self);
+
+ BKE_collision_objects_free(collobjs);
+
+ return MIN2(ret, 1);
}
BLI_INLINE void max_v3_v3v3(float r[3], const float a[3], const float b[3])
{
- r[0] = max_ff(a[0], b[0]);
- r[1] = max_ff(a[1], b[1]);
- r[2] = max_ff(a[2], b[2]);
+ r[0] = max_ff(a[0], b[0]);
+ r[1] = max_ff(a[1], b[1]);
+ r[2] = max_ff(a[2], b[2]);
}
-void collision_get_collider_velocity(float vel_old[3], float vel_new[3], CollisionModifierData *collmd, CollPair *collpair)
+void collision_get_collider_velocity(float vel_old[3],
+ float vel_new[3],
+ CollisionModifierData *collmd,
+ CollPair *collpair)
{
- float u1, u2, u3;
-
- /* compute barycentric coordinates */
- collision_compute_barycentric(collpair->pb,
- collmd->current_x[collpair->bp1].co,
- collmd->current_x[collpair->bp2].co,
- collmd->current_x[collpair->bp3].co,
- &u1, &u2, &u3);
-
- collision_interpolateOnTriangle(vel_new, collmd->current_v[collpair->bp1].co, collmd->current_v[collpair->bp2].co, collmd->current_v[collpair->bp3].co, u1, u2, u3);
- /* XXX assume constant velocity of the collider for now */
- copy_v3_v3(vel_old, vel_new);
+ float u1, u2, u3;
+
+ /* compute barycentric coordinates */
+ collision_compute_barycentric(collpair->pb,
+ collmd->current_x[collpair->bp1].co,
+ collmd->current_x[collpair->bp2].co,
+ collmd->current_x[collpair->bp3].co,
+ &u1,
+ &u2,
+ &u3);
+
+ collision_interpolateOnTriangle(vel_new,
+ collmd->current_v[collpair->bp1].co,
+ collmd->current_v[collpair->bp2].co,
+ collmd->current_v[collpair->bp3].co,
+ u1,
+ u2,
+ u3);
+ /* XXX assume constant velocity of the collider for now */
+ copy_v3_v3(vel_old, vel_new);
}
-BLI_INLINE bool cloth_point_face_collision_params(const float p1[3], const float p2[3], const float v0[3], const float v1[3], const float v2[3],
- float r_nor[3], float *r_lambda, float r_w[3])
+BLI_INLINE bool cloth_point_face_collision_params(const float p1[3],
+ const float p2[3],
+ const float v0[3],
+ const float v1[3],
+ const float v2[3],
+ float r_nor[3],
+ float *r_lambda,
+ float r_w[3])
{
- float edge1[3], edge2[3], p2face[3], p1p2[3], v0p2[3];
- float nor_v0p2, nor_p1p2;
+ float edge1[3], edge2[3], p2face[3], p1p2[3], v0p2[3];
+ float nor_v0p2, nor_p1p2;
- sub_v3_v3v3(edge1, v1, v0);
- sub_v3_v3v3(edge2, v2, v0);
- cross_v3_v3v3(r_nor, edge1, edge2);
- normalize_v3(r_nor);
+ sub_v3_v3v3(edge1, v1, v0);
+ sub_v3_v3v3(edge2, v2, v0);
+ cross_v3_v3v3(r_nor, edge1, edge2);
+ normalize_v3(r_nor);
- sub_v3_v3v3(v0p2, p2, v0);
- nor_v0p2 = dot_v3v3(v0p2, r_nor);
- madd_v3_v3v3fl(p2face, p2, r_nor, -nor_v0p2);
- interp_weights_tri_v3(r_w, v0, v1, v2, p2face);
+ sub_v3_v3v3(v0p2, p2, v0);
+ nor_v0p2 = dot_v3v3(v0p2, r_nor);
+ madd_v3_v3v3fl(p2face, p2, r_nor, -nor_v0p2);
+ interp_weights_tri_v3(r_w, v0, v1, v2, p2face);
- sub_v3_v3v3(p1p2, p2, p1);
- nor_p1p2 = dot_v3v3(p1p2, r_nor);
- *r_lambda = (nor_p1p2 != 0.0f ? nor_v0p2 / nor_p1p2 : 0.0f);
+ sub_v3_v3v3(p1p2, p2, p1);
+ nor_p1p2 = dot_v3v3(p1p2, r_nor);
+ *r_lambda = (nor_p1p2 != 0.0f ? nor_v0p2 / nor_p1p2 : 0.0f);
- return r_w[1] >= 0.0f && r_w[2] >= 0.0f && r_w[1] + r_w[2] <= 1.0f;
+ return r_w[1] >= 0.0f && r_w[2] >= 0.0f && r_w[1] + r_w[2] <= 1.0f;
}
-static CollPair *cloth_point_collpair(
- float p1[3], float p2[3], const MVert *mverts, int bp1, int bp2, int bp3,
- int index_cloth, int index_coll, float epsilon, CollPair *collpair)
+static CollPair *cloth_point_collpair(float p1[3],
+ float p2[3],
+ const MVert *mverts,
+ int bp1,
+ int bp2,
+ int bp3,
+ int index_cloth,
+ int index_coll,
+ float epsilon,
+ CollPair *collpair)
{
- const float *co1 = mverts[bp1].co, *co2 = mverts[bp2].co, *co3 = mverts[bp3].co;
- float lambda /*, distance1 */, distance2;
- float facenor[3], v1p1[3], v1p2[3];
- float w[3];
-
- if (!cloth_point_face_collision_params(p1, p2, co1, co2, co3, facenor, &lambda, w))
- return collpair;
-
- sub_v3_v3v3(v1p1, p1, co1);
-// distance1 = dot_v3v3(v1p1, facenor);
- sub_v3_v3v3(v1p2, p2, co1);
- distance2 = dot_v3v3(v1p2, facenor);
-// if (distance2 > epsilon || (distance1 < 0.0f && distance2 < 0.0f))
- if (distance2 > epsilon)
- return collpair;
-
- collpair->face1 = index_cloth; /* XXX actually not a face, but equivalent index for point */
- collpair->face2 = index_coll;
- collpair->ap1 = index_cloth;
- collpair->ap2 = collpair->ap3 = -1; /* unused */
- collpair->bp1 = bp1;
- collpair->bp2 = bp2;
- collpair->bp3 = bp3;
-
- /* note: using the second point here, which is
- * the current updated position that needs to be corrected
- */
- copy_v3_v3(collpair->pa, p2);
- collpair->distance = distance2;
- mul_v3_v3fl(collpair->vector, facenor, -distance2);
-
- interp_v3_v3v3v3(collpair->pb, co1, co2, co3, w);
-
- copy_v3_v3(collpair->normal, facenor);
- collpair->time = lambda;
- collpair->flag = 0;
-
- collpair++;
- return collpair;
+ const float *co1 = mverts[bp1].co, *co2 = mverts[bp2].co, *co3 = mverts[bp3].co;
+ float lambda /*, distance1 */, distance2;
+ float facenor[3], v1p1[3], v1p2[3];
+ float w[3];
+
+ if (!cloth_point_face_collision_params(p1, p2, co1, co2, co3, facenor, &lambda, w))
+ return collpair;
+
+ sub_v3_v3v3(v1p1, p1, co1);
+ // distance1 = dot_v3v3(v1p1, facenor);
+ sub_v3_v3v3(v1p2, p2, co1);
+ distance2 = dot_v3v3(v1p2, facenor);
+ // if (distance2 > epsilon || (distance1 < 0.0f && distance2 < 0.0f))
+ if (distance2 > epsilon)
+ return collpair;
+
+ collpair->face1 = index_cloth; /* XXX actually not a face, but equivalent index for point */
+ collpair->face2 = index_coll;
+ collpair->ap1 = index_cloth;
+ collpair->ap2 = collpair->ap3 = -1; /* unused */
+ collpair->bp1 = bp1;
+ collpair->bp2 = bp2;
+ collpair->bp3 = bp3;
+
+ /* note: using the second point here, which is
+ * the current updated position that needs to be corrected
+ */
+ copy_v3_v3(collpair->pa, p2);
+ collpair->distance = distance2;
+ mul_v3_v3fl(collpair->vector, facenor, -distance2);
+
+ interp_v3_v3v3v3(collpair->pb, co1, co2, co3, w);
+
+ copy_v3_v3(collpair->normal, facenor);
+ collpair->time = lambda;
+ collpair->flag = 0;
+
+ collpair++;
+ return collpair;
}
//Determines collisions on overlap, collisions are written to collpair[i] and collision+number_collision_found is returned
-static CollPair *cloth_point_collision(
- ModifierData *md1, ModifierData *md2,
- BVHTreeOverlap *overlap, float epsilon, CollPair *collpair, float UNUSED(dt))
+static CollPair *cloth_point_collision(ModifierData *md1,
+ ModifierData *md2,
+ BVHTreeOverlap *overlap,
+ float epsilon,
+ CollPair *collpair,
+ float UNUSED(dt))
{
- ClothModifierData *clmd = (ClothModifierData *)md1;
- CollisionModifierData *collmd = (CollisionModifierData *) md2;
- /* Cloth *cloth = clmd->clothObject; */ /* UNUSED */
- ClothVertex *vert = NULL;
- const MVertTri *vt;
- const MVert *mverts = collmd->current_x;
-
- vert = &clmd->clothObject->verts[overlap->indexA];
- vt = &collmd->tri[overlap->indexB];
-
- collpair = cloth_point_collpair(
- vert->tx, vert->x, mverts,
- vt->tri[0], vt->tri[1], vt->tri[2],
- overlap->indexA, overlap->indexB,
- epsilon, collpair);
-
- return collpair;
+ ClothModifierData *clmd = (ClothModifierData *)md1;
+ CollisionModifierData *collmd = (CollisionModifierData *)md2;
+ /* Cloth *cloth = clmd->clothObject; */ /* UNUSED */
+ ClothVertex *vert = NULL;
+ const MVertTri *vt;
+ const MVert *mverts = collmd->current_x;
+
+ vert = &clmd->clothObject->verts[overlap->indexA];
+ vt = &collmd->tri[overlap->indexB];
+
+ collpair = cloth_point_collpair(vert->tx,
+ vert->x,
+ mverts,
+ vt->tri[0],
+ vt->tri[1],
+ vt->tri[2],
+ overlap->indexA,
+ overlap->indexB,
+ epsilon,
+ collpair);
+
+ return collpair;
}
-static void cloth_points_objcollisions_nearcheck(
- ClothModifierData *clmd, CollisionModifierData *collmd,
- CollPair **collisions, CollPair **collisions_index,
- int numresult, BVHTreeOverlap *overlap, float epsilon, double dt)
+static void cloth_points_objcollisions_nearcheck(ClothModifierData *clmd,
+ CollisionModifierData *collmd,
+ CollPair **collisions,
+ CollPair **collisions_index,
+ int numresult,
+ BVHTreeOverlap *overlap,
+ float epsilon,
+ double dt)
{
- int i;
+ int i;
- /* can return 2 collisions in total */
- *collisions = (CollPair *) MEM_mallocN(sizeof(CollPair) * numresult * 2, "collision array" );
- *collisions_index = *collisions;
+ /* can return 2 collisions in total */
+ *collisions = (CollPair *)MEM_mallocN(sizeof(CollPair) * numresult * 2, "collision array");
+ *collisions_index = *collisions;
- for ( i = 0; i < numresult; i++ ) {
- *collisions_index = cloth_point_collision((ModifierData *)clmd, (ModifierData *)collmd,
- overlap+i, epsilon, *collisions_index, dt);
- }
+ for (i = 0; i < numresult; i++) {
+ *collisions_index = cloth_point_collision(
+ (ModifierData *)clmd, (ModifierData *)collmd, overlap + i, epsilon, *collisions_index, dt);
+ }
}
-void cloth_find_point_contacts(Depsgraph *depsgraph, Object *ob, ClothModifierData *clmd, float step, float dt,
- ColliderContacts **r_collider_contacts, int *r_totcolliders)
+void cloth_find_point_contacts(Depsgraph *depsgraph,
+ Object *ob,
+ ClothModifierData *clmd,
+ float step,
+ float dt,
+ ColliderContacts **r_collider_contacts,
+ int *r_totcolliders)
{
- Cloth *cloth= clmd->clothObject;
- BVHTree *cloth_bvh;
- unsigned int i = 0, mvert_num = 0;
- ClothVertex *verts = NULL;
-
- ColliderContacts *collider_contacts;
-
- Object **collobjs = NULL;
- unsigned int numcollobj = 0;
-
- verts = cloth->verts;
- mvert_num = cloth->mvert_num;
-
- ////////////////////////////////////////////////////////////
- // static collisions
- ////////////////////////////////////////////////////////////
-
- /* Check we do have collision objects to test against, before doing anything else. */
- collobjs = BKE_collision_objects_create(depsgraph, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision);
- if (!collobjs) {
- *r_collider_contacts = NULL;
- *r_totcolliders = 0;
- return;
- }
-
- // create temporary cloth points bvh
- cloth_bvh = BLI_bvhtree_new(mvert_num, clmd->coll_parms->epsilon, 4, 6);
- /* fill tree */
- for (i = 0; i < mvert_num; i++) {
- float co[6];
-
- copy_v3_v3(&co[0*3], verts[i].x);
- copy_v3_v3(&co[1*3], verts[i].tx);
-
- BLI_bvhtree_insert(cloth_bvh, i, co, 2);
- }
- /* balance tree */
- BLI_bvhtree_balance(cloth_bvh);
-
- /* move object to position (step) in time */
- for (i = 0; i < numcollobj; i++) {
- Object *collob= collobjs[i];
- CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision);
- if (!collmd->bvhtree)
- continue;
-
- /* move object to position (step) in time */
- collision_move_object ( collmd, step + dt, step );
- }
-
- collider_contacts = MEM_callocN(sizeof(ColliderContacts) * numcollobj, "CollPair");
-
- // check all collision objects
- for (i = 0; i < numcollobj; i++) {
- ColliderContacts *ct = collider_contacts + i;
- Object *collob= collobjs[i];
- CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision);
- BVHTreeOverlap *overlap;
- unsigned int result = 0;
- float epsilon;
-
- ct->ob = collob;
- ct->collmd = collmd;
- ct->collisions = NULL;
- ct->totcollisions = 0;
-
- if (!collmd->bvhtree)
- continue;
-
- /* search for overlapping collision pairs */
- overlap = BLI_bvhtree_overlap(cloth_bvh, collmd->bvhtree, &result, NULL, NULL);
- epsilon = BLI_bvhtree_get_epsilon(collmd->bvhtree);
-
- // go to next object if no overlap is there
- if (result && overlap) {
- CollPair *collisions_index;
-
- /* check if collisions really happen (costly near check) */
- cloth_points_objcollisions_nearcheck(clmd, collmd, &ct->collisions, &collisions_index,
- result, overlap, epsilon, dt);
- ct->totcollisions = (int)(collisions_index - ct->collisions);
-
- // resolve nearby collisions
-// ret += cloth_points_objcollisions_resolve(clmd, collmd, collob->pd, collisions[i], collisions_index[i], dt);
- }
-
- if (overlap)
- MEM_freeN(overlap);
- }
-
- BKE_collision_objects_free(collobjs);
-
- BLI_bvhtree_free(cloth_bvh);
-
- ////////////////////////////////////////////////////////////
- // update positions
- // this is needed for bvh_calc_DOP_hull_moving() [kdop.c]
- ////////////////////////////////////////////////////////////
-
- // verts come from clmd
- for (i = 0; i < mvert_num; i++) {
- if (clmd->sim_parms->vgroup_mass > 0) {
- if (verts [i].flags & CLOTH_VERT_FLAG_PINNED) {
- continue;
- }
- }
-
- add_v3_v3v3(verts[i].tx, verts[i].txold, verts[i].tv);
- }
- ////////////////////////////////////////////////////////////
-
- *r_collider_contacts = collider_contacts;
- *r_totcolliders = numcollobj;
+ Cloth *cloth = clmd->clothObject;
+ BVHTree *cloth_bvh;
+ unsigned int i = 0, mvert_num = 0;
+ ClothVertex *verts = NULL;
+
+ ColliderContacts *collider_contacts;
+
+ Object **collobjs = NULL;
+ unsigned int numcollobj = 0;
+
+ verts = cloth->verts;
+ mvert_num = cloth->mvert_num;
+
+ ////////////////////////////////////////////////////////////
+ // static collisions
+ ////////////////////////////////////////////////////////////
+
+ /* Check we do have collision objects to test against, before doing anything else. */
+ collobjs = BKE_collision_objects_create(
+ depsgraph, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision);
+ if (!collobjs) {
+ *r_collider_contacts = NULL;
+ *r_totcolliders = 0;
+ return;
+ }
+
+ // create temporary cloth points bvh
+ cloth_bvh = BLI_bvhtree_new(mvert_num, clmd->coll_parms->epsilon, 4, 6);
+ /* fill tree */
+ for (i = 0; i < mvert_num; i++) {
+ float co[6];
+
+ copy_v3_v3(&co[0 * 3], verts[i].x);
+ copy_v3_v3(&co[1 * 3], verts[i].tx);
+
+ BLI_bvhtree_insert(cloth_bvh, i, co, 2);
+ }
+ /* balance tree */
+ BLI_bvhtree_balance(cloth_bvh);
+
+ /* move object to position (step) in time */
+ for (i = 0; i < numcollobj; i++) {
+ Object *collob = collobjs[i];
+ CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(
+ collob, eModifierType_Collision);
+ if (!collmd->bvhtree)
+ continue;
+
+ /* move object to position (step) in time */
+ collision_move_object(collmd, step + dt, step);
+ }
+
+ collider_contacts = MEM_callocN(sizeof(ColliderContacts) * numcollobj, "CollPair");
+
+ // check all collision objects
+ for (i = 0; i < numcollobj; i++) {
+ ColliderContacts *ct = collider_contacts + i;
+ Object *collob = collobjs[i];
+ CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(
+ collob, eModifierType_Collision);
+ BVHTreeOverlap *overlap;
+ unsigned int result = 0;
+ float epsilon;
+
+ ct->ob = collob;
+ ct->collmd = collmd;
+ ct->collisions = NULL;
+ ct->totcollisions = 0;
+
+ if (!collmd->bvhtree)
+ continue;
+
+ /* search for overlapping collision pairs */
+ overlap = BLI_bvhtree_overlap(cloth_bvh, collmd->bvhtree, &result, NULL, NULL);
+ epsilon = BLI_bvhtree_get_epsilon(collmd->bvhtree);
+
+ // go to next object if no overlap is there
+ if (result && overlap) {
+ CollPair *collisions_index;
+
+ /* check if collisions really happen (costly near check) */
+ cloth_points_objcollisions_nearcheck(
+ clmd, collmd, &ct->collisions, &collisions_index, result, overlap, epsilon, dt);
+ ct->totcollisions = (int)(collisions_index - ct->collisions);
+
+ // resolve nearby collisions
+ // ret += cloth_points_objcollisions_resolve(clmd, collmd, collob->pd, collisions[i], collisions_index[i], dt);
+ }
+
+ if (overlap)
+ MEM_freeN(overlap);
+ }
+
+ BKE_collision_objects_free(collobjs);
+
+ BLI_bvhtree_free(cloth_bvh);
+
+ ////////////////////////////////////////////////////////////
+ // update positions
+ // this is needed for bvh_calc_DOP_hull_moving() [kdop.c]
+ ////////////////////////////////////////////////////////////
+
+ // verts come from clmd
+ for (i = 0; i < mvert_num; i++) {
+ if (clmd->sim_parms->vgroup_mass > 0) {
+ if (verts[i].flags & CLOTH_VERT_FLAG_PINNED) {
+ continue;
+ }
+ }
+
+ add_v3_v3v3(verts[i].tx, verts[i].txold, verts[i].tv);
+ }
+ ////////////////////////////////////////////////////////////
+
+ *r_collider_contacts = collider_contacts;
+ *r_totcolliders = numcollobj;
}
void cloth_free_contacts(ColliderContacts *collider_contacts, int totcolliders)
{
- if (collider_contacts) {
- int i;
- for (i = 0; i < totcolliders; ++i) {
- ColliderContacts *ct = collider_contacts + i;
- if (ct->collisions) {
- MEM_freeN(ct->collisions);
- }
- }
- MEM_freeN(collider_contacts);
- }
+ if (collider_contacts) {
+ int i;
+ for (i = 0; i < totcolliders; ++i) {
+ ColliderContacts *ct = collider_contacts + i;
+ if (ct->collisions) {
+ MEM_freeN(ct->collisions);
+ }
+ }
+ MEM_freeN(collider_contacts);
+ }
}
diff --git a/source/blender/blenkernel/intern/colorband.c b/source/blender/blenkernel/intern/colorband.c
index 5630a3268e2..ffb60195f36 100644
--- a/source/blender/blenkernel/intern/colorband.c
+++ b/source/blender/blenkernel/intern/colorband.c
@@ -37,81 +37,80 @@
void BKE_colorband_init(ColorBand *coba, bool rangetype)
{
- int a;
-
- coba->data[0].pos = 0.0;
- coba->data[1].pos = 1.0;
-
- if (rangetype == 0) {
- coba->data[0].r = 0.0;
- coba->data[0].g = 0.0;
- coba->data[0].b = 0.0;
- coba->data[0].a = 0.0;
-
- coba->data[1].r = 1.0;
- coba->data[1].g = 1.0;
- coba->data[1].b = 1.0;
- coba->data[1].a = 1.0;
- }
- else {
- coba->data[0].r = 0.0;
- coba->data[0].g = 0.0;
- coba->data[0].b = 0.0;
- coba->data[0].a = 1.0;
-
- coba->data[1].r = 1.0;
- coba->data[1].g = 1.0;
- coba->data[1].b = 1.0;
- coba->data[1].a = 1.0;
- }
-
- for (a = 2; a < MAXCOLORBAND; a++) {
- coba->data[a].r = 0.5;
- coba->data[a].g = 0.5;
- coba->data[a].b = 0.5;
- coba->data[a].a = 1.0;
- coba->data[a].pos = 0.5;
- }
-
- coba->tot = 2;
- coba->cur = 0;
- coba->color_mode = COLBAND_BLEND_RGB;
- coba->ipotype = COLBAND_INTERP_LINEAR;
+ int a;
+
+ coba->data[0].pos = 0.0;
+ coba->data[1].pos = 1.0;
+
+ if (rangetype == 0) {
+ coba->data[0].r = 0.0;
+ coba->data[0].g = 0.0;
+ coba->data[0].b = 0.0;
+ coba->data[0].a = 0.0;
+
+ coba->data[1].r = 1.0;
+ coba->data[1].g = 1.0;
+ coba->data[1].b = 1.0;
+ coba->data[1].a = 1.0;
+ }
+ else {
+ coba->data[0].r = 0.0;
+ coba->data[0].g = 0.0;
+ coba->data[0].b = 0.0;
+ coba->data[0].a = 1.0;
+
+ coba->data[1].r = 1.0;
+ coba->data[1].g = 1.0;
+ coba->data[1].b = 1.0;
+ coba->data[1].a = 1.0;
+ }
+
+ for (a = 2; a < MAXCOLORBAND; a++) {
+ coba->data[a].r = 0.5;
+ coba->data[a].g = 0.5;
+ coba->data[a].b = 0.5;
+ coba->data[a].a = 1.0;
+ coba->data[a].pos = 0.5;
+ }
+
+ coba->tot = 2;
+ coba->cur = 0;
+ coba->color_mode = COLBAND_BLEND_RGB;
+ coba->ipotype = COLBAND_INTERP_LINEAR;
}
-static void colorband_init_from_table_rgba_simple(
- ColorBand *coba,
- const float (*array)[4], const int array_len)
+static void colorband_init_from_table_rgba_simple(ColorBand *coba,
+ const float (*array)[4],
+ const int array_len)
{
- /* No Re-sample, just de-duplicate. */
- const float eps = (1.0f / 255.0f) + 1e-6f;
- BLI_assert(array_len < MAXCOLORBAND);
- int stops = min_ii(MAXCOLORBAND, array_len);
- if (stops) {
- const float step_size = 1.0f / (float)max_ii(stops - 1, 1);
- int i_curr = -1;
- for (int i_step = 0; i_step < stops; i_step++) {
- if ((i_curr != -1) && compare_v4v4(&coba->data[i_curr].r, array[i_step], eps)) {
- continue;
- }
- i_curr += 1;
- copy_v4_v4(&coba->data[i_curr].r, array[i_step]);
- coba->data[i_curr].pos = i_step * step_size;
- coba->data[i_curr].cur = i_curr;
- }
- coba->tot = i_curr + 1;
- coba->cur = 0;
- }
- else {
- /* coba is empty, set 1 black stop */
- zero_v3(&coba->data[0].r);
- coba->data[0].a = 1.0f;
- coba->cur = 0;
- coba->tot = 1;
- }
+ /* No Re-sample, just de-duplicate. */
+ const float eps = (1.0f / 255.0f) + 1e-6f;
+ BLI_assert(array_len < MAXCOLORBAND);
+ int stops = min_ii(MAXCOLORBAND, array_len);
+ if (stops) {
+ const float step_size = 1.0f / (float)max_ii(stops - 1, 1);
+ int i_curr = -1;
+ for (int i_step = 0; i_step < stops; i_step++) {
+ if ((i_curr != -1) && compare_v4v4(&coba->data[i_curr].r, array[i_step], eps)) {
+ continue;
+ }
+ i_curr += 1;
+ copy_v4_v4(&coba->data[i_curr].r, array[i_step]);
+ coba->data[i_curr].pos = i_step * step_size;
+ coba->data[i_curr].cur = i_curr;
+ }
+ coba->tot = i_curr + 1;
+ coba->cur = 0;
+ }
+ else {
+ /* coba is empty, set 1 black stop */
+ zero_v3(&coba->data[0].r);
+ coba->data[0].a = 1.0f;
+ coba->cur = 0;
+ coba->tot = 1;
+ }
}
-
/* -------------------------------------------------------------------- */
/** \name Color Ramp Re-Sample
*
@@ -122,10 +121,10 @@ static void colorband_init_from_table_rgba_simple(
* Used for calculating which samples of a color-band to remove (when simplifying).
*/
struct ColorResampleElem {
- struct ColorResampleElem *next, *prev;
- HeapNode *node;
- float rgba[4];
- float pos;
+ struct ColorResampleElem *next, *prev;
+ HeapNode *node;
+ float rgba[4];
+ float pos;
};
/**
@@ -133,498 +132,512 @@ struct ColorResampleElem {
*/
static float color_sample_remove_cost(const struct ColorResampleElem *c)
{
- if (c->next == NULL || c->prev == NULL) {
- return -1.0f;
- }
- float area = 0.0f;
+ if (c->next == NULL || c->prev == NULL) {
+ return -1.0f;
+ }
+ float area = 0.0f;
#if 0
- float xy_prev[2], xy_curr[2], xy_next[2];
- xy_prev[0] = c->prev->pos;
- xy_curr[0] = c->pos;
- xy_next[0] = c->next->pos;
- for (int i = 0; i < 4; i++) {
- xy_prev[1] = c->prev->rgba[i];
- xy_curr[1] = c->rgba[i];
- xy_next[1] = c->next->rgba[i];
- area += fabsf(cross_tri_v2(xy_prev, xy_curr, xy_next));
- }
+ float xy_prev[2], xy_curr[2], xy_next[2];
+ xy_prev[0] = c->prev->pos;
+ xy_curr[0] = c->pos;
+ xy_next[0] = c->next->pos;
+ for (int i = 0; i < 4; i++) {
+ xy_prev[1] = c->prev->rgba[i];
+ xy_curr[1] = c->rgba[i];
+ xy_next[1] = c->next->rgba[i];
+ area += fabsf(cross_tri_v2(xy_prev, xy_curr, xy_next));
+ }
#else
- /* Above logic, optimized (p: previous, c: current, n: next). */
- const float xpc = c->prev->pos - c->pos;
- const float xnc = c->next->pos - c->pos;
- for (int i = 0; i < 4; i++) {
- const float ycn = c->rgba[i] - c->next->rgba[i];
- const float ypc = c->prev->rgba[i] - c->rgba[i];
- area += fabsf((xpc * ycn) + (ypc * xnc));
- }
+ /* Above logic, optimized (p: previous, c: current, n: next). */
+ const float xpc = c->prev->pos - c->pos;
+ const float xnc = c->next->pos - c->pos;
+ for (int i = 0; i < 4; i++) {
+ const float ycn = c->rgba[i] - c->next->rgba[i];
+ const float ypc = c->prev->rgba[i] - c->rgba[i];
+ area += fabsf((xpc * ycn) + (ypc * xnc));
+ }
#endif
- return area;
+ return area;
}
/* TODO(campbell): create BLI_math_filter? */
static float filter_gauss(float x)
{
- const float gaussfac = 1.6f;
- const float two_gaussfac2 = 2.0f * gaussfac * gaussfac;
- x *= 3.0f * gaussfac;
- return 1.0f / sqrtf((float)M_PI * two_gaussfac2) * expf(-x * x / two_gaussfac2);
+ const float gaussfac = 1.6f;
+ const float two_gaussfac2 = 2.0f * gaussfac * gaussfac;
+ x *= 3.0f * gaussfac;
+ return 1.0f / sqrtf((float)M_PI * two_gaussfac2) * expf(-x * x / two_gaussfac2);
}
-static void colorband_init_from_table_rgba_resample(
- ColorBand *coba,
- const float (*array)[4], const int array_len,
- bool filter_samples)
+static void colorband_init_from_table_rgba_resample(ColorBand *coba,
+ const float (*array)[4],
+ const int array_len,
+ bool filter_samples)
{
- BLI_assert(array_len >= 2);
- const float eps_2x = ((1.0f / 255.0f) + 1e-6f);
- struct ColorResampleElem *c, *carr = MEM_mallocN(sizeof(*carr) * array_len, __func__);
- int carr_len = array_len;
- c = carr;
- {
- const float step_size = 1.0f / (float)(array_len - 1);
- for (int i = 0; i < array_len; i++, c++) {
- copy_v4_v4(carr[i].rgba, array[i]);
- c->next = c + 1;
- c->prev = c - 1;
- c->pos = i * step_size;
- }
- }
- carr[0].prev = NULL;
- carr[array_len - 1].next = NULL;
-
- /* -2 to remove endpoints. */
- Heap *heap = BLI_heap_new_ex(array_len - 2);
- c = carr;
- for (int i = 0; i < array_len; i++, c++) {
- float cost = color_sample_remove_cost(c);
- if (cost != -1.0f) {
- c->node = BLI_heap_insert(heap, cost, c);
- }
- else {
- c->node = NULL;
- }
- }
-
- while ((carr_len > 1 && !BLI_heap_is_empty(heap)) &&
- ((carr_len >= MAXCOLORBAND) || (BLI_heap_top_value(heap) <= eps_2x)))
- {
- c = BLI_heap_pop_min(heap);
- struct ColorResampleElem *c_next = c->next, *c_prev = c->prev;
- c_prev->next = c_next;
- c_next->prev = c_prev;
- /* Clear data (not essential, avoid confusion). */
- c->prev = c->next = NULL;
- c->node = NULL;
-
- /* Update adjacent */
- for (int i = 0; i < 2; i++) {
- struct ColorResampleElem *c_other = i ? c_next : c_prev;
- if (c_other->node != NULL) {
- const float cost = color_sample_remove_cost(c_other);
- if (cost != -1.0) {
- BLI_heap_node_value_update(heap, c_other->node, cost);
- }
- else {
- BLI_heap_remove(heap, c_other->node);
- c_other->node = NULL;
- }
- }
- }
- carr_len -= 1;
- }
- BLI_heap_free(heap, NULL);
-
- /* First member is never removed. */
- int i = 0;
- BLI_assert(carr_len < MAXCOLORBAND);
- if (filter_samples == false) {
- for (c = carr; c != NULL; c = c->next, i++) {
- copy_v4_v4(&coba->data[i].r, c->rgba);
- coba->data[i].pos = c->pos;
- coba->data[i].cur = i;
- }
- }
- else {
- for (c = carr; c != NULL; c = c->next, i++) {
- const int steps_prev = c->prev ? (c - c->prev) - 1 : 0;
- const int steps_next = c->next ? (c->next - c) - 1 : 0;
- if (steps_prev == 0 && steps_next == 0) {
- copy_v4_v4(&coba->data[i].r, c->rgba);
- }
- else {
- float rgba[4];
- float rgba_accum = 1;
- copy_v4_v4(rgba, c->rgba);
-
- if (steps_prev) {
- const float step_size = 1.0 / (float)(steps_prev + 1);
- int j = steps_prev;
- for (struct ColorResampleElem *c_other = c - 1; c_other != c->prev; c_other--, j--) {
- const float step_pos = (float)j * step_size;
- BLI_assert(step_pos > 0.0f && step_pos < 1.0f);
- const float f = filter_gauss(step_pos);
- madd_v4_v4fl(rgba, c_other->rgba, f);
- rgba_accum += f;
- }
- }
- if (steps_next) {
- const float step_size = 1.0 / (float)(steps_next + 1);
- int j = steps_next;
- for (struct ColorResampleElem *c_other = c + 1; c_other != c->next; c_other++, j--) {
- const float step_pos = (float)j * step_size;
- BLI_assert(step_pos > 0.0f && step_pos < 1.0f);
- const float f = filter_gauss(step_pos);
- madd_v4_v4fl(rgba, c_other->rgba, f);
- rgba_accum += f;
- }
- }
-
- mul_v4_v4fl(&coba->data[i].r, rgba, 1.0f / rgba_accum);
- }
- coba->data[i].pos = c->pos;
- coba->data[i].cur = i;
- }
- }
- BLI_assert(i == carr_len);
- coba->tot = i;
- coba->cur = 0;
-
- MEM_freeN(carr);
+ BLI_assert(array_len >= 2);
+ const float eps_2x = ((1.0f / 255.0f) + 1e-6f);
+ struct ColorResampleElem *c, *carr = MEM_mallocN(sizeof(*carr) * array_len, __func__);
+ int carr_len = array_len;
+ c = carr;
+ {
+ const float step_size = 1.0f / (float)(array_len - 1);
+ for (int i = 0; i < array_len; i++, c++) {
+ copy_v4_v4(carr[i].rgba, array[i]);
+ c->next = c + 1;
+ c->prev = c - 1;
+ c->pos = i * step_size;
+ }
+ }
+ carr[0].prev = NULL;
+ carr[array_len - 1].next = NULL;
+
+ /* -2 to remove endpoints. */
+ Heap *heap = BLI_heap_new_ex(array_len - 2);
+ c = carr;
+ for (int i = 0; i < array_len; i++, c++) {
+ float cost = color_sample_remove_cost(c);
+ if (cost != -1.0f) {
+ c->node = BLI_heap_insert(heap, cost, c);
+ }
+ else {
+ c->node = NULL;
+ }
+ }
+
+ while ((carr_len > 1 && !BLI_heap_is_empty(heap)) &&
+ ((carr_len >= MAXCOLORBAND) || (BLI_heap_top_value(heap) <= eps_2x))) {
+ c = BLI_heap_pop_min(heap);
+ struct ColorResampleElem *c_next = c->next, *c_prev = c->prev;
+ c_prev->next = c_next;
+ c_next->prev = c_prev;
+ /* Clear data (not essential, avoid confusion). */
+ c->prev = c->next = NULL;
+ c->node = NULL;
+
+ /* Update adjacent */
+ for (int i = 0; i < 2; i++) {
+ struct ColorResampleElem *c_other = i ? c_next : c_prev;
+ if (c_other->node != NULL) {
+ const float cost = color_sample_remove_cost(c_other);
+ if (cost != -1.0) {
+ BLI_heap_node_value_update(heap, c_other->node, cost);
+ }
+ else {
+ BLI_heap_remove(heap, c_other->node);
+ c_other->node = NULL;
+ }
+ }
+ }
+ carr_len -= 1;
+ }
+ BLI_heap_free(heap, NULL);
+
+ /* First member is never removed. */
+ int i = 0;
+ BLI_assert(carr_len < MAXCOLORBAND);
+ if (filter_samples == false) {
+ for (c = carr; c != NULL; c = c->next, i++) {
+ copy_v4_v4(&coba->data[i].r, c->rgba);
+ coba->data[i].pos = c->pos;
+ coba->data[i].cur = i;
+ }
+ }
+ else {
+ for (c = carr; c != NULL; c = c->next, i++) {
+ const int steps_prev = c->prev ? (c - c->prev) - 1 : 0;
+ const int steps_next = c->next ? (c->next - c) - 1 : 0;
+ if (steps_prev == 0 && steps_next == 0) {
+ copy_v4_v4(&coba->data[i].r, c->rgba);
+ }
+ else {
+ float rgba[4];
+ float rgba_accum = 1;
+ copy_v4_v4(rgba, c->rgba);
+
+ if (steps_prev) {
+ const float step_size = 1.0 / (float)(steps_prev + 1);
+ int j = steps_prev;
+ for (struct ColorResampleElem *c_other = c - 1; c_other != c->prev; c_other--, j--) {
+ const float step_pos = (float)j * step_size;
+ BLI_assert(step_pos > 0.0f && step_pos < 1.0f);
+ const float f = filter_gauss(step_pos);
+ madd_v4_v4fl(rgba, c_other->rgba, f);
+ rgba_accum += f;
+ }
+ }
+ if (steps_next) {
+ const float step_size = 1.0 / (float)(steps_next + 1);
+ int j = steps_next;
+ for (struct ColorResampleElem *c_other = c + 1; c_other != c->next; c_other++, j--) {
+ const float step_pos = (float)j * step_size;
+ BLI_assert(step_pos > 0.0f && step_pos < 1.0f);
+ const float f = filter_gauss(step_pos);
+ madd_v4_v4fl(rgba, c_other->rgba, f);
+ rgba_accum += f;
+ }
+ }
+
+ mul_v4_v4fl(&coba->data[i].r, rgba, 1.0f / rgba_accum);
+ }
+ coba->data[i].pos = c->pos;
+ coba->data[i].cur = i;
+ }
+ }
+ BLI_assert(i == carr_len);
+ coba->tot = i;
+ coba->cur = 0;
+
+ MEM_freeN(carr);
}
-void BKE_colorband_init_from_table_rgba(
- ColorBand *coba,
- const float (*array)[4], const int array_len,
- bool filter_samples)
+void BKE_colorband_init_from_table_rgba(ColorBand *coba,
+ const float (*array)[4],
+ const int array_len,
+ bool filter_samples)
{
- /* Note, we could use MAXCOLORBAND here, but results of re-sampling are nicer,
- * avoid different behavior when limit is hit. */
- if (array_len < 2) {
- /* No Re-sample, just de-duplicate. */
- colorband_init_from_table_rgba_simple(coba, array, array_len);
- }
- else {
- /* Re-sample */
- colorband_init_from_table_rgba_resample(coba, array, array_len, filter_samples);
- }
+ /* Note, we could use MAXCOLORBAND here, but results of re-sampling are nicer,
+ * avoid different behavior when limit is hit. */
+ if (array_len < 2) {
+ /* No Re-sample, just de-duplicate. */
+ colorband_init_from_table_rgba_simple(coba, array, array_len);
+ }
+ else {
+ /* Re-sample */
+ colorband_init_from_table_rgba_resample(coba, array, array_len, filter_samples);
+ }
}
/** \} */
ColorBand *BKE_colorband_add(bool rangetype)
{
- ColorBand *coba;
+ ColorBand *coba;
- coba = MEM_callocN(sizeof(ColorBand), "colorband");
- BKE_colorband_init(coba, rangetype);
+ coba = MEM_callocN(sizeof(ColorBand), "colorband");
+ BKE_colorband_init(coba, rangetype);
- return coba;
+ return coba;
}
/* ------------------------------------------------------------------------- */
static float colorband_hue_interp(
- const int ipotype_hue,
- const float mfac, const float fac,
- float h1, float h2)
+ const int ipotype_hue, const float mfac, const float fac, float h1, float h2)
{
- float h_interp;
- int mode = 0;
+ float h_interp;
+ int mode = 0;
#define HUE_INTERP(h_a, h_b) ((mfac * (h_a)) + (fac * (h_b)))
-#define HUE_MOD(h) (((h) < 1.0f) ? (h) : (h) - 1.0f)
-
- h1 = HUE_MOD(h1);
- h2 = HUE_MOD(h2);
-
- BLI_assert(h1 >= 0.0f && h1 < 1.0f);
- BLI_assert(h2 >= 0.0f && h2 < 1.0f);
-
- switch (ipotype_hue) {
- case COLBAND_HUE_NEAR:
- {
- if ((h1 < h2) && (h2 - h1) > +0.5f) mode = 1;
- else if ((h1 > h2) && (h2 - h1) < -0.5f) mode = 2;
- else mode = 0;
- break;
- }
- case COLBAND_HUE_FAR:
- {
- /* Do full loop in Hue space in case both stops are the same... */
- if (h1 == h2) mode = 1;
- else if ((h1 < h2) && (h2 - h1) < +0.5f) mode = 1;
- else if ((h1 > h2) && (h2 - h1) > -0.5f) mode = 2;
- else mode = 0;
- break;
- }
- case COLBAND_HUE_CCW:
- {
- if (h1 > h2) mode = 2;
- else mode = 0;
- break;
- }
- case COLBAND_HUE_CW:
- {
- if (h1 < h2) mode = 1;
- else mode = 0;
- break;
- }
- }
-
- switch (mode) {
- case 0:
- h_interp = HUE_INTERP(h1, h2);
- break;
- case 1:
- h_interp = HUE_INTERP(h1 + 1.0f, h2);
- h_interp = HUE_MOD(h_interp);
- break;
- case 2:
- h_interp = HUE_INTERP(h1, h2 + 1.0f);
- h_interp = HUE_MOD(h_interp);
- break;
- }
-
- BLI_assert(h_interp >= 0.0f && h_interp < 1.0f);
+#define HUE_MOD(h) (((h) < 1.0f) ? (h) : (h)-1.0f)
+
+ h1 = HUE_MOD(h1);
+ h2 = HUE_MOD(h2);
+
+ BLI_assert(h1 >= 0.0f && h1 < 1.0f);
+ BLI_assert(h2 >= 0.0f && h2 < 1.0f);
+
+ switch (ipotype_hue) {
+ case COLBAND_HUE_NEAR: {
+ if ((h1 < h2) && (h2 - h1) > +0.5f)
+ mode = 1;
+ else if ((h1 > h2) && (h2 - h1) < -0.5f)
+ mode = 2;
+ else
+ mode = 0;
+ break;
+ }
+ case COLBAND_HUE_FAR: {
+ /* Do full loop in Hue space in case both stops are the same... */
+ if (h1 == h2)
+ mode = 1;
+ else if ((h1 < h2) && (h2 - h1) < +0.5f)
+ mode = 1;
+ else if ((h1 > h2) && (h2 - h1) > -0.5f)
+ mode = 2;
+ else
+ mode = 0;
+ break;
+ }
+ case COLBAND_HUE_CCW: {
+ if (h1 > h2)
+ mode = 2;
+ else
+ mode = 0;
+ break;
+ }
+ case COLBAND_HUE_CW: {
+ if (h1 < h2)
+ mode = 1;
+ else
+ mode = 0;
+ break;
+ }
+ }
+
+ switch (mode) {
+ case 0:
+ h_interp = HUE_INTERP(h1, h2);
+ break;
+ case 1:
+ h_interp = HUE_INTERP(h1 + 1.0f, h2);
+ h_interp = HUE_MOD(h_interp);
+ break;
+ case 2:
+ h_interp = HUE_INTERP(h1, h2 + 1.0f);
+ h_interp = HUE_MOD(h_interp);
+ break;
+ }
+
+ BLI_assert(h_interp >= 0.0f && h_interp < 1.0f);
#undef HUE_INTERP
#undef HUE_MOD
- return h_interp;
+ return h_interp;
}
bool BKE_colorband_evaluate(const ColorBand *coba, float in, float out[4])
{
- const CBData *cbd1, *cbd2, *cbd0, *cbd3;
- float fac;
- int ipotype;
- int a;
-
- if (coba == NULL || coba->tot == 0) return false;
-
- cbd1 = coba->data;
-
- /* Note: when ipotype >= COLBAND_INTERP_B_SPLINE, we cannot do early-out with a constant color before
- * first color stop and after last one, because interpolation starts before and ends after those... */
- ipotype = (coba->color_mode == COLBAND_BLEND_RGB) ? coba->ipotype : COLBAND_INTERP_LINEAR;
-
- if (coba->tot == 1) {
- out[0] = cbd1->r;
- out[1] = cbd1->g;
- out[2] = cbd1->b;
- out[3] = cbd1->a;
- }
- else if ((in <= cbd1->pos) && ELEM(ipotype, COLBAND_INTERP_LINEAR, COLBAND_INTERP_EASE, COLBAND_INTERP_CONSTANT)) {
- /* We are before first color stop. */
- out[0] = cbd1->r;
- out[1] = cbd1->g;
- out[2] = cbd1->b;
- out[3] = cbd1->a;
- }
- else {
- CBData left, right;
-
- /* we're looking for first pos > in */
- for (a = 0; a < coba->tot; a++, cbd1++) {
- if (cbd1->pos > in) {
- break;
- }
- }
-
- if (a == coba->tot) {
- cbd2 = cbd1 - 1;
- right = *cbd2;
- right.pos = 1.0f;
- cbd1 = &right;
- }
- else if (a == 0) {
- left = *cbd1;
- left.pos = 0.0f;
- cbd2 = &left;
- }
- else {
- cbd2 = cbd1 - 1;
- }
-
- if ((a == coba->tot) && ELEM(ipotype, COLBAND_INTERP_LINEAR, COLBAND_INTERP_EASE, COLBAND_INTERP_CONSTANT)) {
- /* We are after last color stop. */
- out[0] = cbd2->r;
- out[1] = cbd2->g;
- out[2] = cbd2->b;
- out[3] = cbd2->a;
- }
- else if (ipotype == COLBAND_INTERP_CONSTANT) {
- /* constant */
- out[0] = cbd2->r;
- out[1] = cbd2->g;
- out[2] = cbd2->b;
- out[3] = cbd2->a;
- }
- else {
- if (cbd2->pos != cbd1->pos) {
- fac = (in - cbd1->pos) / (cbd2->pos - cbd1->pos);
- }
- else {
- /* was setting to 0.0 in 2.56 & previous, but this
- * is incorrect for the last element, see [#26732] */
- fac = (a != coba->tot) ? 0.0f : 1.0f;
- }
-
- if (ELEM(ipotype, COLBAND_INTERP_B_SPLINE, COLBAND_INTERP_CARDINAL)) {
- /* ipo from right to left: 3 2 1 0 */
- float t[4];
-
- if (a >= coba->tot - 1) cbd0 = cbd1;
- else cbd0 = cbd1 + 1;
- if (a < 2) cbd3 = cbd2;
- else cbd3 = cbd2 - 1;
-
- CLAMP(fac, 0.0f, 1.0f);
-
- if (ipotype == COLBAND_INTERP_CARDINAL) {
- key_curve_position_weights(fac, t, KEY_CARDINAL);
- }
- else {
- key_curve_position_weights(fac, t, KEY_BSPLINE);
- }
-
- out[0] = t[3] * cbd3->r + t[2] * cbd2->r + t[1] * cbd1->r + t[0] * cbd0->r;
- out[1] = t[3] * cbd3->g + t[2] * cbd2->g + t[1] * cbd1->g + t[0] * cbd0->g;
- out[2] = t[3] * cbd3->b + t[2] * cbd2->b + t[1] * cbd1->b + t[0] * cbd0->b;
- out[3] = t[3] * cbd3->a + t[2] * cbd2->a + t[1] * cbd1->a + t[0] * cbd0->a;
- CLAMP(out[0], 0.0f, 1.0f);
- CLAMP(out[1], 0.0f, 1.0f);
- CLAMP(out[2], 0.0f, 1.0f);
- CLAMP(out[3], 0.0f, 1.0f);
- }
- else {
- if (ipotype == COLBAND_INTERP_EASE) {
- const float fac2 = fac * fac;
- fac = 3.0f * fac2 - 2.0f * fac2 * fac;
- }
- const float mfac = 1.0f - fac;
-
- if (UNLIKELY(coba->color_mode == COLBAND_BLEND_HSV)) {
- float col1[3], col2[3];
-
- rgb_to_hsv_v(&cbd1->r, col1);
- rgb_to_hsv_v(&cbd2->r, col2);
-
- out[0] = colorband_hue_interp(coba->ipotype_hue, mfac, fac, col1[0], col2[0]);
- out[1] = mfac * col1[1] + fac * col2[1];
- out[2] = mfac * col1[2] + fac * col2[2];
- out[3] = mfac * cbd1->a + fac * cbd2->a;
-
- hsv_to_rgb_v(out, out);
- }
- else if (UNLIKELY(coba->color_mode == COLBAND_BLEND_HSL)) {
- float col1[3], col2[3];
-
- rgb_to_hsl_v(&cbd1->r, col1);
- rgb_to_hsl_v(&cbd2->r, col2);
-
- out[0] = colorband_hue_interp(coba->ipotype_hue, mfac, fac, col1[0], col2[0]);
- out[1] = mfac * col1[1] + fac * col2[1];
- out[2] = mfac * col1[2] + fac * col2[2];
- out[3] = mfac * cbd1->a + fac * cbd2->a;
-
- hsl_to_rgb_v(out, out);
- }
- else {
- /* COLBAND_BLEND_RGB */
- out[0] = mfac * cbd1->r + fac * cbd2->r;
- out[1] = mfac * cbd1->g + fac * cbd2->g;
- out[2] = mfac * cbd1->b + fac * cbd2->b;
- out[3] = mfac * cbd1->a + fac * cbd2->a;
- }
- }
- }
- }
-
- return true; /* OK */
+ const CBData *cbd1, *cbd2, *cbd0, *cbd3;
+ float fac;
+ int ipotype;
+ int a;
+
+ if (coba == NULL || coba->tot == 0)
+ return false;
+
+ cbd1 = coba->data;
+
+ /* Note: when ipotype >= COLBAND_INTERP_B_SPLINE, we cannot do early-out with a constant color before
+ * first color stop and after last one, because interpolation starts before and ends after those... */
+ ipotype = (coba->color_mode == COLBAND_BLEND_RGB) ? coba->ipotype : COLBAND_INTERP_LINEAR;
+
+ if (coba->tot == 1) {
+ out[0] = cbd1->r;
+ out[1] = cbd1->g;
+ out[2] = cbd1->b;
+ out[3] = cbd1->a;
+ }
+ else if ((in <= cbd1->pos) &&
+ ELEM(ipotype, COLBAND_INTERP_LINEAR, COLBAND_INTERP_EASE, COLBAND_INTERP_CONSTANT)) {
+ /* We are before first color stop. */
+ out[0] = cbd1->r;
+ out[1] = cbd1->g;
+ out[2] = cbd1->b;
+ out[3] = cbd1->a;
+ }
+ else {
+ CBData left, right;
+
+ /* we're looking for first pos > in */
+ for (a = 0; a < coba->tot; a++, cbd1++) {
+ if (cbd1->pos > in) {
+ break;
+ }
+ }
+
+ if (a == coba->tot) {
+ cbd2 = cbd1 - 1;
+ right = *cbd2;
+ right.pos = 1.0f;
+ cbd1 = &right;
+ }
+ else if (a == 0) {
+ left = *cbd1;
+ left.pos = 0.0f;
+ cbd2 = &left;
+ }
+ else {
+ cbd2 = cbd1 - 1;
+ }
+
+ if ((a == coba->tot) &&
+ ELEM(ipotype, COLBAND_INTERP_LINEAR, COLBAND_INTERP_EASE, COLBAND_INTERP_CONSTANT)) {
+ /* We are after last color stop. */
+ out[0] = cbd2->r;
+ out[1] = cbd2->g;
+ out[2] = cbd2->b;
+ out[3] = cbd2->a;
+ }
+ else if (ipotype == COLBAND_INTERP_CONSTANT) {
+ /* constant */
+ out[0] = cbd2->r;
+ out[1] = cbd2->g;
+ out[2] = cbd2->b;
+ out[3] = cbd2->a;
+ }
+ else {
+ if (cbd2->pos != cbd1->pos) {
+ fac = (in - cbd1->pos) / (cbd2->pos - cbd1->pos);
+ }
+ else {
+ /* was setting to 0.0 in 2.56 & previous, but this
+ * is incorrect for the last element, see [#26732] */
+ fac = (a != coba->tot) ? 0.0f : 1.0f;
+ }
+
+ if (ELEM(ipotype, COLBAND_INTERP_B_SPLINE, COLBAND_INTERP_CARDINAL)) {
+ /* ipo from right to left: 3 2 1 0 */
+ float t[4];
+
+ if (a >= coba->tot - 1)
+ cbd0 = cbd1;
+ else
+ cbd0 = cbd1 + 1;
+ if (a < 2)
+ cbd3 = cbd2;
+ else
+ cbd3 = cbd2 - 1;
+
+ CLAMP(fac, 0.0f, 1.0f);
+
+ if (ipotype == COLBAND_INTERP_CARDINAL) {
+ key_curve_position_weights(fac, t, KEY_CARDINAL);
+ }
+ else {
+ key_curve_position_weights(fac, t, KEY_BSPLINE);
+ }
+
+ out[0] = t[3] * cbd3->r + t[2] * cbd2->r + t[1] * cbd1->r + t[0] * cbd0->r;
+ out[1] = t[3] * cbd3->g + t[2] * cbd2->g + t[1] * cbd1->g + t[0] * cbd0->g;
+ out[2] = t[3] * cbd3->b + t[2] * cbd2->b + t[1] * cbd1->b + t[0] * cbd0->b;
+ out[3] = t[3] * cbd3->a + t[2] * cbd2->a + t[1] * cbd1->a + t[0] * cbd0->a;
+ CLAMP(out[0], 0.0f, 1.0f);
+ CLAMP(out[1], 0.0f, 1.0f);
+ CLAMP(out[2], 0.0f, 1.0f);
+ CLAMP(out[3], 0.0f, 1.0f);
+ }
+ else {
+ if (ipotype == COLBAND_INTERP_EASE) {
+ const float fac2 = fac * fac;
+ fac = 3.0f * fac2 - 2.0f * fac2 * fac;
+ }
+ const float mfac = 1.0f - fac;
+
+ if (UNLIKELY(coba->color_mode == COLBAND_BLEND_HSV)) {
+ float col1[3], col2[3];
+
+ rgb_to_hsv_v(&cbd1->r, col1);
+ rgb_to_hsv_v(&cbd2->r, col2);
+
+ out[0] = colorband_hue_interp(coba->ipotype_hue, mfac, fac, col1[0], col2[0]);
+ out[1] = mfac * col1[1] + fac * col2[1];
+ out[2] = mfac * col1[2] + fac * col2[2];
+ out[3] = mfac * cbd1->a + fac * cbd2->a;
+
+ hsv_to_rgb_v(out, out);
+ }
+ else if (UNLIKELY(coba->color_mode == COLBAND_BLEND_HSL)) {
+ float col1[3], col2[3];
+
+ rgb_to_hsl_v(&cbd1->r, col1);
+ rgb_to_hsl_v(&cbd2->r, col2);
+
+ out[0] = colorband_hue_interp(coba->ipotype_hue, mfac, fac, col1[0], col2[0]);
+ out[1] = mfac * col1[1] + fac * col2[1];
+ out[2] = mfac * col1[2] + fac * col2[2];
+ out[3] = mfac * cbd1->a + fac * cbd2->a;
+
+ hsl_to_rgb_v(out, out);
+ }
+ else {
+ /* COLBAND_BLEND_RGB */
+ out[0] = mfac * cbd1->r + fac * cbd2->r;
+ out[1] = mfac * cbd1->g + fac * cbd2->g;
+ out[2] = mfac * cbd1->b + fac * cbd2->b;
+ out[3] = mfac * cbd1->a + fac * cbd2->a;
+ }
+ }
+ }
+ }
+
+ return true; /* OK */
}
void BKE_colorband_evaluate_table_rgba(const ColorBand *coba, float **array, int *size)
{
- int a;
+ int a;
- *size = CM_TABLE + 1;
- *array = MEM_callocN(sizeof(float) * (*size) * 4, "ColorBand");
+ *size = CM_TABLE + 1;
+ *array = MEM_callocN(sizeof(float) * (*size) * 4, "ColorBand");
- for (a = 0; a < *size; a++)
- BKE_colorband_evaluate(coba, (float)a / (float)CM_TABLE, &(*array)[a * 4]);
+ for (a = 0; a < *size; a++)
+ BKE_colorband_evaluate(coba, (float)a / (float)CM_TABLE, &(*array)[a * 4]);
}
static int vergcband(const void *a1, const void *a2)
{
- const CBData *x1 = a1, *x2 = a2;
+ const CBData *x1 = a1, *x2 = a2;
- if (x1->pos > x2->pos) return 1;
- else if (x1->pos < x2->pos) return -1;
- return 0;
+ if (x1->pos > x2->pos)
+ return 1;
+ else if (x1->pos < x2->pos)
+ return -1;
+ return 0;
}
void BKE_colorband_update_sort(ColorBand *coba)
{
- int a;
+ int a;
- if (coba->tot < 2)
- return;
+ if (coba->tot < 2)
+ return;
- for (a = 0; a < coba->tot; a++)
- coba->data[a].cur = a;
+ for (a = 0; a < coba->tot; a++)
+ coba->data[a].cur = a;
- qsort(coba->data, coba->tot, sizeof(CBData), vergcband);
+ qsort(coba->data, coba->tot, sizeof(CBData), vergcband);
- for (a = 0; a < coba->tot; a++) {
- if (coba->data[a].cur == coba->cur) {
- coba->cur = a;
- break;
- }
- }
+ for (a = 0; a < coba->tot; a++) {
+ if (coba->data[a].cur == coba->cur) {
+ coba->cur = a;
+ break;
+ }
+ }
}
CBData *BKE_colorband_element_add(struct ColorBand *coba, float position)
{
- if (coba->tot == MAXCOLORBAND) {
- return NULL;
- }
- else {
- CBData *xnew;
+ if (coba->tot == MAXCOLORBAND) {
+ return NULL;
+ }
+ else {
+ CBData *xnew;
- xnew = &coba->data[coba->tot];
- xnew->pos = position;
+ xnew = &coba->data[coba->tot];
+ xnew->pos = position;
- if (coba->tot != 0) {
- BKE_colorband_evaluate(coba, position, &xnew->r);
- }
- else {
- zero_v4(&xnew->r);
- }
- }
+ if (coba->tot != 0) {
+ BKE_colorband_evaluate(coba, position, &xnew->r);
+ }
+ else {
+ zero_v4(&xnew->r);
+ }
+ }
- coba->tot++;
- coba->cur = coba->tot - 1;
+ coba->tot++;
+ coba->cur = coba->tot - 1;
- BKE_colorband_update_sort(coba);
+ BKE_colorband_update_sort(coba);
- return coba->data + coba->cur;
+ return coba->data + coba->cur;
}
int BKE_colorband_element_remove(struct ColorBand *coba, int index)
{
- int a;
+ int a;
- if (coba->tot < 2)
- return 0;
+ if (coba->tot < 2)
+ return 0;
- if (index < 0 || index >= coba->tot)
- return 0;
+ if (index < 0 || index >= coba->tot)
+ return 0;
- coba->tot--;
- for (a = index; a < coba->tot; a++) {
- coba->data[a] = coba->data[a + 1];
- }
- if (coba->cur) coba->cur--;
- return 1;
+ coba->tot--;
+ for (a = index; a < coba->tot; a++) {
+ coba->data[a] = coba->data[a + 1];
+ }
+ if (coba->cur)
+ coba->cur--;
+ return 1;
}
diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c
index 8b92c42a286..96c098b37e9 100644
--- a/source/blender/blenkernel/intern/colortools.c
+++ b/source/blender/blenkernel/intern/colortools.c
@@ -21,7 +21,6 @@
* \ingroup bke
*/
-
#include <string.h>
#include <math.h>
#include <stdlib.h>
@@ -42,7 +41,6 @@
#include "BKE_curve.h"
#include "BKE_fcurve.h"
-
#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
@@ -50,125 +48,127 @@
/* ***************** operations on full struct ************* */
-void curvemapping_set_defaults(CurveMapping *cumap, int tot, float minx, float miny, float maxx, float maxy)
+void curvemapping_set_defaults(
+ CurveMapping *cumap, int tot, float minx, float miny, float maxx, float maxy)
{
- int a;
- float clipminx, clipminy, clipmaxx, clipmaxy;
+ int a;
+ float clipminx, clipminy, clipmaxx, clipmaxy;
- cumap->flag = CUMA_DO_CLIP;
- if (tot == 4) cumap->cur = 3; /* rhms, hack for 'col' curve? */
+ cumap->flag = CUMA_DO_CLIP;
+ if (tot == 4)
+ cumap->cur = 3; /* rhms, hack for 'col' curve? */
- clipminx = min_ff(minx, maxx);
- clipminy = min_ff(miny, maxy);
- clipmaxx = max_ff(minx, maxx);
- clipmaxy = max_ff(miny, maxy);
+ clipminx = min_ff(minx, maxx);
+ clipminy = min_ff(miny, maxy);
+ clipmaxx = max_ff(minx, maxx);
+ clipmaxy = max_ff(miny, maxy);
- BLI_rctf_init(&cumap->curr, clipminx, clipmaxx, clipminy, clipmaxy);
- cumap->clipr = cumap->curr;
+ BLI_rctf_init(&cumap->curr, clipminx, clipmaxx, clipminy, clipmaxy);
+ cumap->clipr = cumap->curr;
- cumap->white[0] = cumap->white[1] = cumap->white[2] = 1.0f;
- cumap->bwmul[0] = cumap->bwmul[1] = cumap->bwmul[2] = 1.0f;
+ cumap->white[0] = cumap->white[1] = cumap->white[2] = 1.0f;
+ cumap->bwmul[0] = cumap->bwmul[1] = cumap->bwmul[2] = 1.0f;
- for (a = 0; a < tot; a++) {
- cumap->cm[a].flag = CUMA_EXTEND_EXTRAPOLATE;
- cumap->cm[a].totpoint = 2;
- cumap->cm[a].curve = MEM_callocN(2 * sizeof(CurveMapPoint), "curve points");
+ for (a = 0; a < tot; a++) {
+ cumap->cm[a].flag = CUMA_EXTEND_EXTRAPOLATE;
+ cumap->cm[a].totpoint = 2;
+ cumap->cm[a].curve = MEM_callocN(2 * sizeof(CurveMapPoint), "curve points");
- cumap->cm[a].curve[0].x = minx;
- cumap->cm[a].curve[0].y = miny;
- cumap->cm[a].curve[1].x = maxx;
- cumap->cm[a].curve[1].y = maxy;
- }
+ cumap->cm[a].curve[0].x = minx;
+ cumap->cm[a].curve[0].y = miny;
+ cumap->cm[a].curve[1].x = maxx;
+ cumap->cm[a].curve[1].y = maxy;
+ }
- cumap->changed_timestamp = 0;
+ cumap->changed_timestamp = 0;
}
CurveMapping *curvemapping_add(int tot, float minx, float miny, float maxx, float maxy)
{
- CurveMapping *cumap;
+ CurveMapping *cumap;
- cumap = MEM_callocN(sizeof(CurveMapping), "new curvemap");
+ cumap = MEM_callocN(sizeof(CurveMapping), "new curvemap");
- curvemapping_set_defaults(cumap, tot, minx, miny, maxx, maxy);
+ curvemapping_set_defaults(cumap, tot, minx, miny, maxx, maxy);
- return cumap;
+ return cumap;
}
void curvemapping_free_data(CurveMapping *cumap)
{
- int a;
-
- for (a = 0; a < CM_TOT; a++) {
- if (cumap->cm[a].curve) {
- MEM_freeN(cumap->cm[a].curve);
- cumap->cm[a].curve = NULL;
- }
- if (cumap->cm[a].table) {
- MEM_freeN(cumap->cm[a].table);
- cumap->cm[a].table = NULL;
- }
- if (cumap->cm[a].premultable) {
- MEM_freeN(cumap->cm[a].premultable);
- cumap->cm[a].premultable = NULL;
- }
- }
+ int a;
+
+ for (a = 0; a < CM_TOT; a++) {
+ if (cumap->cm[a].curve) {
+ MEM_freeN(cumap->cm[a].curve);
+ cumap->cm[a].curve = NULL;
+ }
+ if (cumap->cm[a].table) {
+ MEM_freeN(cumap->cm[a].table);
+ cumap->cm[a].table = NULL;
+ }
+ if (cumap->cm[a].premultable) {
+ MEM_freeN(cumap->cm[a].premultable);
+ cumap->cm[a].premultable = NULL;
+ }
+ }
}
void curvemapping_free(CurveMapping *cumap)
{
- if (cumap) {
- curvemapping_free_data(cumap);
- MEM_freeN(cumap);
- }
+ if (cumap) {
+ curvemapping_free_data(cumap);
+ MEM_freeN(cumap);
+ }
}
void curvemapping_copy_data(CurveMapping *target, const CurveMapping *cumap)
{
- int a;
-
- *target = *cumap;
-
- for (a = 0; a < CM_TOT; a++) {
- if (cumap->cm[a].curve)
- target->cm[a].curve = MEM_dupallocN(cumap->cm[a].curve);
- if (cumap->cm[a].table)
- target->cm[a].table = MEM_dupallocN(cumap->cm[a].table);
- if (cumap->cm[a].premultable)
- target->cm[a].premultable = MEM_dupallocN(cumap->cm[a].premultable);
- }
+ int a;
+
+ *target = *cumap;
+
+ for (a = 0; a < CM_TOT; a++) {
+ if (cumap->cm[a].curve)
+ target->cm[a].curve = MEM_dupallocN(cumap->cm[a].curve);
+ if (cumap->cm[a].table)
+ target->cm[a].table = MEM_dupallocN(cumap->cm[a].table);
+ if (cumap->cm[a].premultable)
+ target->cm[a].premultable = MEM_dupallocN(cumap->cm[a].premultable);
+ }
}
CurveMapping *curvemapping_copy(const CurveMapping *cumap)
{
- if (cumap) {
- CurveMapping *cumapn = MEM_dupallocN(cumap);
- curvemapping_copy_data(cumapn, cumap);
- return cumapn;
- }
- return NULL;
+ if (cumap) {
+ CurveMapping *cumapn = MEM_dupallocN(cumap);
+ curvemapping_copy_data(cumapn, cumap);
+ return cumapn;
+ }
+ return NULL;
}
void curvemapping_set_black_white_ex(const float black[3], const float white[3], float r_bwmul[3])
{
- int a;
+ int a;
- for (a = 0; a < 3; a++) {
- const float delta = max_ff(white[a] - black[a], 1e-5f);
- r_bwmul[a] = 1.0f / delta;
- }
+ for (a = 0; a < 3; a++) {
+ const float delta = max_ff(white[a] - black[a], 1e-5f);
+ r_bwmul[a] = 1.0f / delta;
+ }
}
void curvemapping_set_black_white(CurveMapping *cumap, const float black[3], const float white[3])
{
- if (white) {
- copy_v3_v3(cumap->white, white);
- }
- if (black) {
- copy_v3_v3(cumap->black, black);
- }
-
- curvemapping_set_black_white_ex(cumap->black, cumap->white, cumap->bwmul);
- cumap->changed_timestamp++;
+ if (white) {
+ copy_v3_v3(cumap->white, white);
+ }
+ if (black) {
+ copy_v3_v3(cumap->black, black);
+ }
+
+ curvemapping_set_black_white_ex(cumap->black, cumap->white, cumap->bwmul);
+ cumap->changed_timestamp++;
}
/* ***************** operations on single curve ************* */
@@ -177,240 +177,257 @@ void curvemapping_set_black_white(CurveMapping *cumap, const float black[3], con
/* remove specified point */
bool curvemap_remove_point(CurveMap *cuma, CurveMapPoint *point)
{
- CurveMapPoint *cmp;
- int a, b, removed = 0;
-
- /* must have 2 points minimum */
- if (cuma->totpoint <= 2)
- return false;
-
- cmp = MEM_mallocN((cuma->totpoint) * sizeof(CurveMapPoint), "curve points");
-
- /* well, lets keep the two outer points! */
- for (a = 0, b = 0; a < cuma->totpoint; a++) {
- if (&cuma->curve[a] != point) {
- cmp[b] = cuma->curve[a];
- b++;
- }
- else {
- removed++;
- }
- }
-
- MEM_freeN(cuma->curve);
- cuma->curve = cmp;
- cuma->totpoint -= removed;
- return (removed != 0);
+ CurveMapPoint *cmp;
+ int a, b, removed = 0;
+
+ /* must have 2 points minimum */
+ if (cuma->totpoint <= 2)
+ return false;
+
+ cmp = MEM_mallocN((cuma->totpoint) * sizeof(CurveMapPoint), "curve points");
+
+ /* well, lets keep the two outer points! */
+ for (a = 0, b = 0; a < cuma->totpoint; a++) {
+ if (&cuma->curve[a] != point) {
+ cmp[b] = cuma->curve[a];
+ b++;
+ }
+ else {
+ removed++;
+ }
+ }
+
+ MEM_freeN(cuma->curve);
+ cuma->curve = cmp;
+ cuma->totpoint -= removed;
+ return (removed != 0);
}
/* removes with flag set */
void curvemap_remove(CurveMap *cuma, const short flag)
{
- CurveMapPoint *cmp = MEM_mallocN((cuma->totpoint) * sizeof(CurveMapPoint), "curve points");
- int a, b, removed = 0;
-
- /* well, lets keep the two outer points! */
- cmp[0] = cuma->curve[0];
- for (a = 1, b = 1; a < cuma->totpoint - 1; a++) {
- if (!(cuma->curve[a].flag & flag)) {
- cmp[b] = cuma->curve[a];
- b++;
- }
- else {
- removed++;
- }
- }
- cmp[b] = cuma->curve[a];
-
- MEM_freeN(cuma->curve);
- cuma->curve = cmp;
- cuma->totpoint -= removed;
+ CurveMapPoint *cmp = MEM_mallocN((cuma->totpoint) * sizeof(CurveMapPoint), "curve points");
+ int a, b, removed = 0;
+
+ /* well, lets keep the two outer points! */
+ cmp[0] = cuma->curve[0];
+ for (a = 1, b = 1; a < cuma->totpoint - 1; a++) {
+ if (!(cuma->curve[a].flag & flag)) {
+ cmp[b] = cuma->curve[a];
+ b++;
+ }
+ else {
+ removed++;
+ }
+ }
+ cmp[b] = cuma->curve[a];
+
+ MEM_freeN(cuma->curve);
+ cuma->curve = cmp;
+ cuma->totpoint -= removed;
}
CurveMapPoint *curvemap_insert(CurveMap *cuma, float x, float y)
{
- CurveMapPoint *cmp = MEM_callocN((cuma->totpoint + 1) * sizeof(CurveMapPoint), "curve points");
- CurveMapPoint *newcmp = NULL;
- int a, b;
- bool foundloc = false;
-
- /* insert fragments of the old one and the new point to the new curve */
- cuma->totpoint++;
- for (a = 0, b = 0; a < cuma->totpoint; a++) {
- if ((foundloc == false) && ((a + 1 == cuma->totpoint) || (x < cuma->curve[a].x))) {
- cmp[a].x = x;
- cmp[a].y = y;
- cmp[a].flag = CUMA_SELECT;
- foundloc = true;
- newcmp = &cmp[a];
- }
- else {
- cmp[a].x = cuma->curve[b].x;
- cmp[a].y = cuma->curve[b].y;
- /* make sure old points don't remain selected */
- cmp[a].flag = cuma->curve[b].flag & ~CUMA_SELECT;
- cmp[a].shorty = cuma->curve[b].shorty;
- b++;
- }
- }
-
- /* free old curve and replace it with new one */
- MEM_freeN(cuma->curve);
- cuma->curve = cmp;
-
- return newcmp;
+ CurveMapPoint *cmp = MEM_callocN((cuma->totpoint + 1) * sizeof(CurveMapPoint), "curve points");
+ CurveMapPoint *newcmp = NULL;
+ int a, b;
+ bool foundloc = false;
+
+ /* insert fragments of the old one and the new point to the new curve */
+ cuma->totpoint++;
+ for (a = 0, b = 0; a < cuma->totpoint; a++) {
+ if ((foundloc == false) && ((a + 1 == cuma->totpoint) || (x < cuma->curve[a].x))) {
+ cmp[a].x = x;
+ cmp[a].y = y;
+ cmp[a].flag = CUMA_SELECT;
+ foundloc = true;
+ newcmp = &cmp[a];
+ }
+ else {
+ cmp[a].x = cuma->curve[b].x;
+ cmp[a].y = cuma->curve[b].y;
+ /* make sure old points don't remain selected */
+ cmp[a].flag = cuma->curve[b].flag & ~CUMA_SELECT;
+ cmp[a].shorty = cuma->curve[b].shorty;
+ b++;
+ }
+ }
+
+ /* free old curve and replace it with new one */
+ MEM_freeN(cuma->curve);
+ cuma->curve = cmp;
+
+ return newcmp;
}
void curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope)
{
- if (cuma->curve)
- MEM_freeN(cuma->curve);
-
- switch (preset) {
- case CURVE_PRESET_LINE: cuma->totpoint = 2; break;
- case CURVE_PRESET_SHARP: cuma->totpoint = 4; break;
- case CURVE_PRESET_SMOOTH: cuma->totpoint = 4; break;
- case CURVE_PRESET_MAX: cuma->totpoint = 2; break;
- case CURVE_PRESET_MID9: cuma->totpoint = 9; break;
- case CURVE_PRESET_ROUND: cuma->totpoint = 4; break;
- case CURVE_PRESET_ROOT: cuma->totpoint = 4; break;
- case CURVE_PRESET_GAUSS: cuma->totpoint = 7; break;
- case CURVE_PRESET_BELL: cuma->totpoint = 3; break;
- }
-
- cuma->curve = MEM_callocN(cuma->totpoint * sizeof(CurveMapPoint), "curve points");
-
- switch (preset) {
- case CURVE_PRESET_LINE:
- cuma->curve[0].x = clipr->xmin;
- cuma->curve[0].y = clipr->ymax;
- cuma->curve[1].x = clipr->xmax;
- cuma->curve[1].y = clipr->ymin;
- if (slope == CURVEMAP_SLOPE_POS_NEG) {
- cuma->curve[0].flag |= CUMA_HANDLE_VECTOR;
- cuma->curve[1].flag |= CUMA_HANDLE_VECTOR;
- }
- break;
- case CURVE_PRESET_SHARP:
- cuma->curve[0].x = 0;
- cuma->curve[0].y = 1;
- cuma->curve[1].x = 0.25;
- cuma->curve[1].y = 0.50;
- cuma->curve[2].x = 0.75;
- cuma->curve[2].y = 0.04;
- cuma->curve[3].x = 1;
- cuma->curve[3].y = 0;
- break;
- case CURVE_PRESET_SMOOTH:
- cuma->curve[0].x = 0;
- cuma->curve[0].y = 1;
- cuma->curve[1].x = 0.25;
- cuma->curve[1].y = 0.94;
- cuma->curve[2].x = 0.75;
- cuma->curve[2].y = 0.06;
- cuma->curve[3].x = 1;
- cuma->curve[3].y = 0;
- break;
- case CURVE_PRESET_MAX:
- cuma->curve[0].x = 0;
- cuma->curve[0].y = 1;
- cuma->curve[1].x = 1;
- cuma->curve[1].y = 1;
- break;
- case CURVE_PRESET_MID9:
- {
- int i;
- for (i = 0; i < cuma->totpoint; i++) {
- cuma->curve[i].x = i / ((float)cuma->totpoint - 1);
- cuma->curve[i].y = 0.5;
- }
- break;
- }
- case CURVE_PRESET_ROUND:
- cuma->curve[0].x = 0;
- cuma->curve[0].y = 1;
- cuma->curve[1].x = 0.5;
- cuma->curve[1].y = 0.90;
- cuma->curve[2].x = 0.86;
- cuma->curve[2].y = 0.5;
- cuma->curve[3].x = 1;
- cuma->curve[3].y = 0;
- break;
- case CURVE_PRESET_ROOT:
- cuma->curve[0].x = 0;
- cuma->curve[0].y = 1;
- cuma->curve[1].x = 0.25;
- cuma->curve[1].y = 0.95;
- cuma->curve[2].x = 0.75;
- cuma->curve[2].y = 0.44;
- cuma->curve[3].x = 1;
- cuma->curve[3].y = 0;
- break;
- case CURVE_PRESET_GAUSS:
- cuma->curve[0].x = 0;
- cuma->curve[0].y = 0.025f;
- cuma->curve[1].x = 0.16f;
- cuma->curve[1].y = 0.135f;
- cuma->curve[2].x = 0.298f;
- cuma->curve[2].y = 0.36f;
-
- cuma->curve[3].x = 0.50f;
- cuma->curve[3].y = 1.0f;
-
- cuma->curve[4].x = 0.70f;
- cuma->curve[4].y = 0.36f;
- cuma->curve[5].x = 0.84f;
- cuma->curve[5].y = 0.135f;
- cuma->curve[6].x = 1.0f;
- cuma->curve[6].y = 0.025f;
- break;
- case CURVE_PRESET_BELL:
- cuma->curve[0].x = 0;
- cuma->curve[0].y = 0.025f;
-
- cuma->curve[1].x = 0.50f;
- cuma->curve[1].y = 1.0f;
-
- cuma->curve[2].x = 1.0f;
- cuma->curve[2].y = 0.025f;
- break;
- }
-
- /* mirror curve in x direction to have positive slope
- * rather than default negative slope */
- if (slope == CURVEMAP_SLOPE_POSITIVE) {
- int i, last = cuma->totpoint - 1;
- CurveMapPoint *newpoints = MEM_dupallocN(cuma->curve);
-
- for (i = 0; i < cuma->totpoint; i++) {
- newpoints[i].y = cuma->curve[last - i].y;
- }
-
- MEM_freeN(cuma->curve);
- cuma->curve = newpoints;
- }
- else if (slope == CURVEMAP_SLOPE_POS_NEG) {
- const int num_points = cuma->totpoint * 2 - 1;
- CurveMapPoint *new_points = MEM_mallocN(num_points * sizeof(CurveMapPoint),
- "curve symmetric points");
- int i;
- for (i = 0; i < cuma->totpoint; i++) {
- const int src_last_point = cuma->totpoint - i - 1;
- const int dst_last_point = num_points - i - 1;
- new_points[i] = cuma->curve[src_last_point];
- new_points[i].x = (1.0f - cuma->curve[src_last_point].x) * 0.5f;
- new_points[dst_last_point] = new_points[i];
- new_points[dst_last_point].x = 0.5f + cuma->curve[src_last_point].x * 0.5f;
- }
- cuma->totpoint = num_points;
- MEM_freeN(cuma->curve);
- cuma->curve = new_points;
- }
-
- if (cuma->table) {
- MEM_freeN(cuma->table);
- cuma->table = NULL;
- }
+ if (cuma->curve)
+ MEM_freeN(cuma->curve);
+
+ switch (preset) {
+ case CURVE_PRESET_LINE:
+ cuma->totpoint = 2;
+ break;
+ case CURVE_PRESET_SHARP:
+ cuma->totpoint = 4;
+ break;
+ case CURVE_PRESET_SMOOTH:
+ cuma->totpoint = 4;
+ break;
+ case CURVE_PRESET_MAX:
+ cuma->totpoint = 2;
+ break;
+ case CURVE_PRESET_MID9:
+ cuma->totpoint = 9;
+ break;
+ case CURVE_PRESET_ROUND:
+ cuma->totpoint = 4;
+ break;
+ case CURVE_PRESET_ROOT:
+ cuma->totpoint = 4;
+ break;
+ case CURVE_PRESET_GAUSS:
+ cuma->totpoint = 7;
+ break;
+ case CURVE_PRESET_BELL:
+ cuma->totpoint = 3;
+ break;
+ }
+
+ cuma->curve = MEM_callocN(cuma->totpoint * sizeof(CurveMapPoint), "curve points");
+
+ switch (preset) {
+ case CURVE_PRESET_LINE:
+ cuma->curve[0].x = clipr->xmin;
+ cuma->curve[0].y = clipr->ymax;
+ cuma->curve[1].x = clipr->xmax;
+ cuma->curve[1].y = clipr->ymin;
+ if (slope == CURVEMAP_SLOPE_POS_NEG) {
+ cuma->curve[0].flag |= CUMA_HANDLE_VECTOR;
+ cuma->curve[1].flag |= CUMA_HANDLE_VECTOR;
+ }
+ break;
+ case CURVE_PRESET_SHARP:
+ cuma->curve[0].x = 0;
+ cuma->curve[0].y = 1;
+ cuma->curve[1].x = 0.25;
+ cuma->curve[1].y = 0.50;
+ cuma->curve[2].x = 0.75;
+ cuma->curve[2].y = 0.04;
+ cuma->curve[3].x = 1;
+ cuma->curve[3].y = 0;
+ break;
+ case CURVE_PRESET_SMOOTH:
+ cuma->curve[0].x = 0;
+ cuma->curve[0].y = 1;
+ cuma->curve[1].x = 0.25;
+ cuma->curve[1].y = 0.94;
+ cuma->curve[2].x = 0.75;
+ cuma->curve[2].y = 0.06;
+ cuma->curve[3].x = 1;
+ cuma->curve[3].y = 0;
+ break;
+ case CURVE_PRESET_MAX:
+ cuma->curve[0].x = 0;
+ cuma->curve[0].y = 1;
+ cuma->curve[1].x = 1;
+ cuma->curve[1].y = 1;
+ break;
+ case CURVE_PRESET_MID9: {
+ int i;
+ for (i = 0; i < cuma->totpoint; i++) {
+ cuma->curve[i].x = i / ((float)cuma->totpoint - 1);
+ cuma->curve[i].y = 0.5;
+ }
+ break;
+ }
+ case CURVE_PRESET_ROUND:
+ cuma->curve[0].x = 0;
+ cuma->curve[0].y = 1;
+ cuma->curve[1].x = 0.5;
+ cuma->curve[1].y = 0.90;
+ cuma->curve[2].x = 0.86;
+ cuma->curve[2].y = 0.5;
+ cuma->curve[3].x = 1;
+ cuma->curve[3].y = 0;
+ break;
+ case CURVE_PRESET_ROOT:
+ cuma->curve[0].x = 0;
+ cuma->curve[0].y = 1;
+ cuma->curve[1].x = 0.25;
+ cuma->curve[1].y = 0.95;
+ cuma->curve[2].x = 0.75;
+ cuma->curve[2].y = 0.44;
+ cuma->curve[3].x = 1;
+ cuma->curve[3].y = 0;
+ break;
+ case CURVE_PRESET_GAUSS:
+ cuma->curve[0].x = 0;
+ cuma->curve[0].y = 0.025f;
+ cuma->curve[1].x = 0.16f;
+ cuma->curve[1].y = 0.135f;
+ cuma->curve[2].x = 0.298f;
+ cuma->curve[2].y = 0.36f;
+
+ cuma->curve[3].x = 0.50f;
+ cuma->curve[3].y = 1.0f;
+
+ cuma->curve[4].x = 0.70f;
+ cuma->curve[4].y = 0.36f;
+ cuma->curve[5].x = 0.84f;
+ cuma->curve[5].y = 0.135f;
+ cuma->curve[6].x = 1.0f;
+ cuma->curve[6].y = 0.025f;
+ break;
+ case CURVE_PRESET_BELL:
+ cuma->curve[0].x = 0;
+ cuma->curve[0].y = 0.025f;
+
+ cuma->curve[1].x = 0.50f;
+ cuma->curve[1].y = 1.0f;
+
+ cuma->curve[2].x = 1.0f;
+ cuma->curve[2].y = 0.025f;
+ break;
+ }
+
+ /* mirror curve in x direction to have positive slope
+ * rather than default negative slope */
+ if (slope == CURVEMAP_SLOPE_POSITIVE) {
+ int i, last = cuma->totpoint - 1;
+ CurveMapPoint *newpoints = MEM_dupallocN(cuma->curve);
+
+ for (i = 0; i < cuma->totpoint; i++) {
+ newpoints[i].y = cuma->curve[last - i].y;
+ }
+
+ MEM_freeN(cuma->curve);
+ cuma->curve = newpoints;
+ }
+ else if (slope == CURVEMAP_SLOPE_POS_NEG) {
+ const int num_points = cuma->totpoint * 2 - 1;
+ CurveMapPoint *new_points = MEM_mallocN(num_points * sizeof(CurveMapPoint),
+ "curve symmetric points");
+ int i;
+ for (i = 0; i < cuma->totpoint; i++) {
+ const int src_last_point = cuma->totpoint - i - 1;
+ const int dst_last_point = num_points - i - 1;
+ new_points[i] = cuma->curve[src_last_point];
+ new_points[i].x = (1.0f - cuma->curve[src_last_point].x) * 0.5f;
+ new_points[dst_last_point] = new_points[i];
+ new_points[dst_last_point].x = 0.5f + cuma->curve[src_last_point].x * 0.5f;
+ }
+ cuma->totpoint = num_points;
+ MEM_freeN(cuma->curve);
+ cuma->curve = new_points;
+ }
+
+ if (cuma->table) {
+ MEM_freeN(cuma->table);
+ cuma->table = NULL;
+ }
}
/**
@@ -418,22 +435,22 @@ void curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope)
*/
void curvemap_handle_set(CurveMap *cuma, int type)
{
- int a;
-
- for (a = 0; a < cuma->totpoint; a++) {
- if (cuma->curve[a].flag & CUMA_SELECT) {
- cuma->curve[a].flag &= ~(CUMA_HANDLE_VECTOR | CUMA_HANDLE_AUTO_ANIM);
- if (type == HD_VECT) {
- cuma->curve[a].flag |= CUMA_HANDLE_VECTOR;
- }
- else if (type == HD_AUTO_ANIM) {
- cuma->curve[a].flag |= CUMA_HANDLE_AUTO_ANIM;
- }
- else {
- /* pass */
- }
- }
- }
+ int a;
+
+ for (a = 0; a < cuma->totpoint; a++) {
+ if (cuma->curve[a].flag & CUMA_SELECT) {
+ cuma->curve[a].flag &= ~(CUMA_HANDLE_VECTOR | CUMA_HANDLE_AUTO_ANIM);
+ if (type == HD_VECT) {
+ cuma->curve[a].flag |= CUMA_HANDLE_VECTOR;
+ }
+ else if (type == HD_AUTO_ANIM) {
+ cuma->curve[a].flag |= CUMA_HANDLE_AUTO_ANIM;
+ }
+ else {
+ /* pass */
+ }
+ }
+ }
}
/* *********************** Making the tables and display ************** */
@@ -441,123 +458,120 @@ void curvemap_handle_set(CurveMap *cuma, int type)
/**
* reduced copy of #calchandleNurb_intern code in curve.c
*/
-static void calchandle_curvemap(
- BezTriple *bezt, const BezTriple *prev, const BezTriple *next)
+static void calchandle_curvemap(BezTriple *bezt, const BezTriple *prev, const BezTriple *next)
{
- /* defines to avoid confusion */
-#define p2_h1 ((p2) - 3)
+ /* defines to avoid confusion */
+#define p2_h1 ((p2)-3)
#define p2_h2 ((p2) + 3)
- const float *p1, *p3;
- float *p2;
- float pt[3];
- float len, len_a, len_b;
- float dvec_a[2], dvec_b[2];
-
- if (bezt->h1 == 0 && bezt->h2 == 0) {
- return;
- }
-
- p2 = bezt->vec[1];
-
- if (prev == NULL) {
- p3 = next->vec[1];
- pt[0] = 2.0f * p2[0] - p3[0];
- pt[1] = 2.0f * p2[1] - p3[1];
- p1 = pt;
- }
- else {
- p1 = prev->vec[1];
- }
-
- if (next == NULL) {
- p1 = prev->vec[1];
- pt[0] = 2.0f * p2[0] - p1[0];
- pt[1] = 2.0f * p2[1] - p1[1];
- p3 = pt;
- }
- else {
- p3 = next->vec[1];
- }
-
- sub_v2_v2v2(dvec_a, p2, p1);
- sub_v2_v2v2(dvec_b, p3, p2);
-
- len_a = len_v2(dvec_a);
- len_b = len_v2(dvec_b);
-
- if (len_a == 0.0f) len_a = 1.0f;
- if (len_b == 0.0f) len_b = 1.0f;
-
- if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) || ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) { /* auto */
- float tvec[2];
- tvec[0] = dvec_b[0] / len_b + dvec_a[0] / len_a;
- tvec[1] = dvec_b[1] / len_b + dvec_a[1] / len_a;
-
- len = len_v2(tvec) * 2.5614f;
- if (len != 0.0f) {
-
- if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM)) {
- len_a /= len;
- madd_v2_v2v2fl(p2_h1, p2, tvec, -len_a);
-
- if ((bezt->h1 == HD_AUTO_ANIM) && next && prev) { /* keep horizontal if extrema */
- const float ydiff1 = prev->vec[1][1] - bezt->vec[1][1];
- const float ydiff2 = next->vec[1][1] - bezt->vec[1][1];
- if ((ydiff1 <= 0.0f && ydiff2 <= 0.0f) ||
- (ydiff1 >= 0.0f && ydiff2 >= 0.0f))
- {
- bezt->vec[0][1] = bezt->vec[1][1];
- }
- else { /* handles should not be beyond y coord of two others */
- if (ydiff1 <= 0.0f) {
- if (prev->vec[1][1] > bezt->vec[0][1]) {
- bezt->vec[0][1] = prev->vec[1][1];
- }
- }
- else {
- if (prev->vec[1][1] < bezt->vec[0][1]) {
- bezt->vec[0][1] = prev->vec[1][1];
- }
- }
- }
- }
- }
- if (ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) {
- len_b /= len;
- madd_v2_v2v2fl(p2_h2, p2, tvec, len_b);
-
- if ((bezt->h2 == HD_AUTO_ANIM) && next && prev) { /* keep horizontal if extrema */
- const float ydiff1 = prev->vec[1][1] - bezt->vec[1][1];
- const float ydiff2 = next->vec[1][1] - bezt->vec[1][1];
- if ((ydiff1 <= 0.0f && ydiff2 <= 0.0f) ||
- (ydiff1 >= 0.0f && ydiff2 >= 0.0f))
- {
- bezt->vec[2][1] = bezt->vec[1][1];
- }
- else { /* handles should not be beyond y coord of two others */
- if (ydiff1 <= 0.0f) {
- if (next->vec[1][1] < bezt->vec[2][1]) {
- bezt->vec[2][1] = next->vec[1][1];
- }
- }
- else {
- if (next->vec[1][1] > bezt->vec[2][1]) {
- bezt->vec[2][1] = next->vec[1][1];
- }
- }
- }
- }
- }
- }
- }
-
- if (bezt->h1 == HD_VECT) { /* vector */
- madd_v2_v2v2fl(p2_h1, p2, dvec_a, -1.0f / 3.0f);
- }
- if (bezt->h2 == HD_VECT) {
- madd_v2_v2v2fl(p2_h2, p2, dvec_b, 1.0f / 3.0f);
- }
+ const float *p1, *p3;
+ float *p2;
+ float pt[3];
+ float len, len_a, len_b;
+ float dvec_a[2], dvec_b[2];
+
+ if (bezt->h1 == 0 && bezt->h2 == 0) {
+ return;
+ }
+
+ p2 = bezt->vec[1];
+
+ if (prev == NULL) {
+ p3 = next->vec[1];
+ pt[0] = 2.0f * p2[0] - p3[0];
+ pt[1] = 2.0f * p2[1] - p3[1];
+ p1 = pt;
+ }
+ else {
+ p1 = prev->vec[1];
+ }
+
+ if (next == NULL) {
+ p1 = prev->vec[1];
+ pt[0] = 2.0f * p2[0] - p1[0];
+ pt[1] = 2.0f * p2[1] - p1[1];
+ p3 = pt;
+ }
+ else {
+ p3 = next->vec[1];
+ }
+
+ sub_v2_v2v2(dvec_a, p2, p1);
+ sub_v2_v2v2(dvec_b, p3, p2);
+
+ len_a = len_v2(dvec_a);
+ len_b = len_v2(dvec_b);
+
+ if (len_a == 0.0f)
+ len_a = 1.0f;
+ if (len_b == 0.0f)
+ len_b = 1.0f;
+
+ if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) || ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) { /* auto */
+ float tvec[2];
+ tvec[0] = dvec_b[0] / len_b + dvec_a[0] / len_a;
+ tvec[1] = dvec_b[1] / len_b + dvec_a[1] / len_a;
+
+ len = len_v2(tvec) * 2.5614f;
+ if (len != 0.0f) {
+
+ if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM)) {
+ len_a /= len;
+ madd_v2_v2v2fl(p2_h1, p2, tvec, -len_a);
+
+ if ((bezt->h1 == HD_AUTO_ANIM) && next && prev) { /* keep horizontal if extrema */
+ const float ydiff1 = prev->vec[1][1] - bezt->vec[1][1];
+ const float ydiff2 = next->vec[1][1] - bezt->vec[1][1];
+ if ((ydiff1 <= 0.0f && ydiff2 <= 0.0f) || (ydiff1 >= 0.0f && ydiff2 >= 0.0f)) {
+ bezt->vec[0][1] = bezt->vec[1][1];
+ }
+ else { /* handles should not be beyond y coord of two others */
+ if (ydiff1 <= 0.0f) {
+ if (prev->vec[1][1] > bezt->vec[0][1]) {
+ bezt->vec[0][1] = prev->vec[1][1];
+ }
+ }
+ else {
+ if (prev->vec[1][1] < bezt->vec[0][1]) {
+ bezt->vec[0][1] = prev->vec[1][1];
+ }
+ }
+ }
+ }
+ }
+ if (ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) {
+ len_b /= len;
+ madd_v2_v2v2fl(p2_h2, p2, tvec, len_b);
+
+ if ((bezt->h2 == HD_AUTO_ANIM) && next && prev) { /* keep horizontal if extrema */
+ const float ydiff1 = prev->vec[1][1] - bezt->vec[1][1];
+ const float ydiff2 = next->vec[1][1] - bezt->vec[1][1];
+ if ((ydiff1 <= 0.0f && ydiff2 <= 0.0f) || (ydiff1 >= 0.0f && ydiff2 >= 0.0f)) {
+ bezt->vec[2][1] = bezt->vec[1][1];
+ }
+ else { /* handles should not be beyond y coord of two others */
+ if (ydiff1 <= 0.0f) {
+ if (next->vec[1][1] < bezt->vec[2][1]) {
+ bezt->vec[2][1] = next->vec[1][1];
+ }
+ }
+ else {
+ if (next->vec[1][1] > bezt->vec[2][1]) {
+ bezt->vec[2][1] = next->vec[1][1];
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (bezt->h1 == HD_VECT) { /* vector */
+ madd_v2_v2v2fl(p2_h1, p2, dvec_a, -1.0f / 3.0f);
+ }
+ if (bezt->h2 == HD_VECT) {
+ madd_v2_v2v2fl(p2_h2, p2, dvec_b, 1.0f / 3.0f);
+ }
#undef p2_h1
#undef p2_h2
@@ -565,237 +579,256 @@ static void calchandle_curvemap(
/* in X, out Y.
* X is presumed to be outside first or last */
-static float curvemap_calc_extend(const CurveMap *cuma, float x, const float first[2], const float last[2])
+static float curvemap_calc_extend(const CurveMap *cuma,
+ float x,
+ const float first[2],
+ const float last[2])
{
- if (x <= first[0]) {
- if ((cuma->flag & CUMA_EXTEND_EXTRAPOLATE) == 0) {
- /* no extrapolate */
- return first[1];
- }
- else {
- if (cuma->ext_in[0] == 0.0f)
- return first[1] + cuma->ext_in[1] * 10000.0f;
- else
- return first[1] + cuma->ext_in[1] * (x - first[0]) / cuma->ext_in[0];
- }
- }
- else if (x >= last[0]) {
- if ((cuma->flag & CUMA_EXTEND_EXTRAPOLATE) == 0) {
- /* no extrapolate */
- return last[1];
- }
- else {
- if (cuma->ext_out[0] == 0.0f)
- return last[1] - cuma->ext_out[1] * 10000.0f;
- else
- return last[1] + cuma->ext_out[1] * (x - last[0]) / cuma->ext_out[0];
- }
- }
- return 0.0f;
+ if (x <= first[0]) {
+ if ((cuma->flag & CUMA_EXTEND_EXTRAPOLATE) == 0) {
+ /* no extrapolate */
+ return first[1];
+ }
+ else {
+ if (cuma->ext_in[0] == 0.0f)
+ return first[1] + cuma->ext_in[1] * 10000.0f;
+ else
+ return first[1] + cuma->ext_in[1] * (x - first[0]) / cuma->ext_in[0];
+ }
+ }
+ else if (x >= last[0]) {
+ if ((cuma->flag & CUMA_EXTEND_EXTRAPOLATE) == 0) {
+ /* no extrapolate */
+ return last[1];
+ }
+ else {
+ if (cuma->ext_out[0] == 0.0f)
+ return last[1] - cuma->ext_out[1] * 10000.0f;
+ else
+ return last[1] + cuma->ext_out[1] * (x - last[0]) / cuma->ext_out[0];
+ }
+ }
+ return 0.0f;
}
/* only creates a table for a single channel in CurveMapping */
static void curvemap_make_table(CurveMap *cuma, const rctf *clipr)
{
- CurveMapPoint *cmp = cuma->curve;
- BezTriple *bezt;
- float *fp, *allpoints, *lastpoint, curf, range;
- int a, totpoint;
-
- if (cuma->curve == NULL) return;
-
- /* default rect also is table range */
- cuma->mintable = clipr->xmin;
- cuma->maxtable = clipr->xmax;
-
- /* hrmf... we now rely on blender ipo beziers, these are more advanced */
- bezt = MEM_callocN(cuma->totpoint * sizeof(BezTriple), "beztarr");
-
- for (a = 0; a < cuma->totpoint; a++) {
- cuma->mintable = min_ff(cuma->mintable, cmp[a].x);
- cuma->maxtable = max_ff(cuma->maxtable, cmp[a].x);
- bezt[a].vec[1][0] = cmp[a].x;
- bezt[a].vec[1][1] = cmp[a].y;
- if (cmp[a].flag & CUMA_HANDLE_VECTOR) {
- bezt[a].h1 = bezt[a].h2 = HD_VECT;
- }
- else if (cmp[a].flag & CUMA_HANDLE_AUTO_ANIM) {
- bezt[a].h1 = bezt[a].h2 = HD_AUTO_ANIM;
- }
- else {
- bezt[a].h1 = bezt[a].h2 = HD_AUTO;
- }
- }
-
- const BezTriple *bezt_prev = NULL;
- for (a = 0; a < cuma->totpoint; a++) {
- const BezTriple *bezt_next = (a != cuma->totpoint - 1) ? &bezt[a + 1] : NULL;
- calchandle_curvemap(&bezt[a], bezt_prev, bezt_next);
- bezt_prev = &bezt[a];
- }
-
- /* first and last handle need correction, instead of pointing to center of next/prev,
- * we let it point to the closest handle */
- if (cuma->totpoint > 2) {
- float hlen, nlen, vec[3];
-
- if (bezt[0].h2 == HD_AUTO) {
-
- hlen = len_v3v3(bezt[0].vec[1], bezt[0].vec[2]); /* original handle length */
- /* clip handle point */
- copy_v3_v3(vec, bezt[1].vec[0]);
- if (vec[0] < bezt[0].vec[1][0])
- vec[0] = bezt[0].vec[1][0];
-
- sub_v3_v3(vec, bezt[0].vec[1]);
- nlen = len_v3(vec);
- if (nlen > FLT_EPSILON) {
- mul_v3_fl(vec, hlen / nlen);
- add_v3_v3v3(bezt[0].vec[2], vec, bezt[0].vec[1]);
- sub_v3_v3v3(bezt[0].vec[0], bezt[0].vec[1], vec);
- }
- }
- a = cuma->totpoint - 1;
- if (bezt[a].h2 == HD_AUTO) {
-
- hlen = len_v3v3(bezt[a].vec[1], bezt[a].vec[0]); /* original handle length */
- /* clip handle point */
- copy_v3_v3(vec, bezt[a - 1].vec[2]);
- if (vec[0] > bezt[a].vec[1][0])
- vec[0] = bezt[a].vec[1][0];
-
- sub_v3_v3(vec, bezt[a].vec[1]);
- nlen = len_v3(vec);
- if (nlen > FLT_EPSILON) {
- mul_v3_fl(vec, hlen / nlen);
- add_v3_v3v3(bezt[a].vec[0], vec, bezt[a].vec[1]);
- sub_v3_v3v3(bezt[a].vec[2], bezt[a].vec[1], vec);
- }
- }
- }
- /* make the bezier curve */
- if (cuma->table)
- MEM_freeN(cuma->table);
- totpoint = (cuma->totpoint - 1) * CM_RESOL;
- fp = allpoints = MEM_callocN(totpoint * 2 * sizeof(float), "table");
-
- for (a = 0; a < cuma->totpoint - 1; a++, fp += 2 * CM_RESOL) {
- correct_bezpart(bezt[a].vec[1], bezt[a].vec[2], bezt[a + 1].vec[0], bezt[a + 1].vec[1]);
- BKE_curve_forward_diff_bezier(bezt[a].vec[1][0], bezt[a].vec[2][0], bezt[a + 1].vec[0][0], bezt[a + 1].vec[1][0], fp, CM_RESOL - 1, 2 * sizeof(float));
- BKE_curve_forward_diff_bezier(bezt[a].vec[1][1], bezt[a].vec[2][1], bezt[a + 1].vec[0][1], bezt[a + 1].vec[1][1], fp + 1, CM_RESOL - 1, 2 * sizeof(float));
- }
-
- /* store first and last handle for extrapolation, unit length */
- cuma->ext_in[0] = bezt[0].vec[0][0] - bezt[0].vec[1][0];
- cuma->ext_in[1] = bezt[0].vec[0][1] - bezt[0].vec[1][1];
- range = sqrtf(cuma->ext_in[0] * cuma->ext_in[0] + cuma->ext_in[1] * cuma->ext_in[1]);
- cuma->ext_in[0] /= range;
- cuma->ext_in[1] /= range;
-
- a = cuma->totpoint - 1;
- cuma->ext_out[0] = bezt[a].vec[1][0] - bezt[a].vec[2][0];
- cuma->ext_out[1] = bezt[a].vec[1][1] - bezt[a].vec[2][1];
- range = sqrtf(cuma->ext_out[0] * cuma->ext_out[0] + cuma->ext_out[1] * cuma->ext_out[1]);
- cuma->ext_out[0] /= range;
- cuma->ext_out[1] /= range;
-
- /* cleanup */
- MEM_freeN(bezt);
-
- range = CM_TABLEDIV * (cuma->maxtable - cuma->mintable);
- cuma->range = 1.0f / range;
-
- /* now make a table with CM_TABLE equal x distances */
- fp = allpoints;
- lastpoint = allpoints + 2 * (totpoint - 1);
- cmp = MEM_callocN((CM_TABLE + 1) * sizeof(CurveMapPoint), "dist table");
-
- for (a = 0; a <= CM_TABLE; a++) {
- curf = cuma->mintable + range * (float)a;
- cmp[a].x = curf;
-
- /* get the first x coordinate larger than curf */
- while (curf >= fp[0] && fp != lastpoint) {
- fp += 2;
- }
- if (fp == allpoints || (curf >= fp[0] && fp == lastpoint))
- cmp[a].y = curvemap_calc_extend(cuma, curf, allpoints, lastpoint);
- else {
- float fac1 = fp[0] - fp[-2];
- float fac2 = fp[0] - curf;
- if (fac1 > FLT_EPSILON)
- fac1 = fac2 / fac1;
- else
- fac1 = 0.0f;
- cmp[a].y = fac1 * fp[-1] + (1.0f - fac1) * fp[1];
- }
- }
-
- MEM_freeN(allpoints);
- cuma->table = cmp;
+ CurveMapPoint *cmp = cuma->curve;
+ BezTriple *bezt;
+ float *fp, *allpoints, *lastpoint, curf, range;
+ int a, totpoint;
+
+ if (cuma->curve == NULL)
+ return;
+
+ /* default rect also is table range */
+ cuma->mintable = clipr->xmin;
+ cuma->maxtable = clipr->xmax;
+
+ /* hrmf... we now rely on blender ipo beziers, these are more advanced */
+ bezt = MEM_callocN(cuma->totpoint * sizeof(BezTriple), "beztarr");
+
+ for (a = 0; a < cuma->totpoint; a++) {
+ cuma->mintable = min_ff(cuma->mintable, cmp[a].x);
+ cuma->maxtable = max_ff(cuma->maxtable, cmp[a].x);
+ bezt[a].vec[1][0] = cmp[a].x;
+ bezt[a].vec[1][1] = cmp[a].y;
+ if (cmp[a].flag & CUMA_HANDLE_VECTOR) {
+ bezt[a].h1 = bezt[a].h2 = HD_VECT;
+ }
+ else if (cmp[a].flag & CUMA_HANDLE_AUTO_ANIM) {
+ bezt[a].h1 = bezt[a].h2 = HD_AUTO_ANIM;
+ }
+ else {
+ bezt[a].h1 = bezt[a].h2 = HD_AUTO;
+ }
+ }
+
+ const BezTriple *bezt_prev = NULL;
+ for (a = 0; a < cuma->totpoint; a++) {
+ const BezTriple *bezt_next = (a != cuma->totpoint - 1) ? &bezt[a + 1] : NULL;
+ calchandle_curvemap(&bezt[a], bezt_prev, bezt_next);
+ bezt_prev = &bezt[a];
+ }
+
+ /* first and last handle need correction, instead of pointing to center of next/prev,
+ * we let it point to the closest handle */
+ if (cuma->totpoint > 2) {
+ float hlen, nlen, vec[3];
+
+ if (bezt[0].h2 == HD_AUTO) {
+
+ hlen = len_v3v3(bezt[0].vec[1], bezt[0].vec[2]); /* original handle length */
+ /* clip handle point */
+ copy_v3_v3(vec, bezt[1].vec[0]);
+ if (vec[0] < bezt[0].vec[1][0])
+ vec[0] = bezt[0].vec[1][0];
+
+ sub_v3_v3(vec, bezt[0].vec[1]);
+ nlen = len_v3(vec);
+ if (nlen > FLT_EPSILON) {
+ mul_v3_fl(vec, hlen / nlen);
+ add_v3_v3v3(bezt[0].vec[2], vec, bezt[0].vec[1]);
+ sub_v3_v3v3(bezt[0].vec[0], bezt[0].vec[1], vec);
+ }
+ }
+ a = cuma->totpoint - 1;
+ if (bezt[a].h2 == HD_AUTO) {
+
+ hlen = len_v3v3(bezt[a].vec[1], bezt[a].vec[0]); /* original handle length */
+ /* clip handle point */
+ copy_v3_v3(vec, bezt[a - 1].vec[2]);
+ if (vec[0] > bezt[a].vec[1][0])
+ vec[0] = bezt[a].vec[1][0];
+
+ sub_v3_v3(vec, bezt[a].vec[1]);
+ nlen = len_v3(vec);
+ if (nlen > FLT_EPSILON) {
+ mul_v3_fl(vec, hlen / nlen);
+ add_v3_v3v3(bezt[a].vec[0], vec, bezt[a].vec[1]);
+ sub_v3_v3v3(bezt[a].vec[2], bezt[a].vec[1], vec);
+ }
+ }
+ }
+ /* make the bezier curve */
+ if (cuma->table)
+ MEM_freeN(cuma->table);
+ totpoint = (cuma->totpoint - 1) * CM_RESOL;
+ fp = allpoints = MEM_callocN(totpoint * 2 * sizeof(float), "table");
+
+ for (a = 0; a < cuma->totpoint - 1; a++, fp += 2 * CM_RESOL) {
+ correct_bezpart(bezt[a].vec[1], bezt[a].vec[2], bezt[a + 1].vec[0], bezt[a + 1].vec[1]);
+ BKE_curve_forward_diff_bezier(bezt[a].vec[1][0],
+ bezt[a].vec[2][0],
+ bezt[a + 1].vec[0][0],
+ bezt[a + 1].vec[1][0],
+ fp,
+ CM_RESOL - 1,
+ 2 * sizeof(float));
+ BKE_curve_forward_diff_bezier(bezt[a].vec[1][1],
+ bezt[a].vec[2][1],
+ bezt[a + 1].vec[0][1],
+ bezt[a + 1].vec[1][1],
+ fp + 1,
+ CM_RESOL - 1,
+ 2 * sizeof(float));
+ }
+
+ /* store first and last handle for extrapolation, unit length */
+ cuma->ext_in[0] = bezt[0].vec[0][0] - bezt[0].vec[1][0];
+ cuma->ext_in[1] = bezt[0].vec[0][1] - bezt[0].vec[1][1];
+ range = sqrtf(cuma->ext_in[0] * cuma->ext_in[0] + cuma->ext_in[1] * cuma->ext_in[1]);
+ cuma->ext_in[0] /= range;
+ cuma->ext_in[1] /= range;
+
+ a = cuma->totpoint - 1;
+ cuma->ext_out[0] = bezt[a].vec[1][0] - bezt[a].vec[2][0];
+ cuma->ext_out[1] = bezt[a].vec[1][1] - bezt[a].vec[2][1];
+ range = sqrtf(cuma->ext_out[0] * cuma->ext_out[0] + cuma->ext_out[1] * cuma->ext_out[1]);
+ cuma->ext_out[0] /= range;
+ cuma->ext_out[1] /= range;
+
+ /* cleanup */
+ MEM_freeN(bezt);
+
+ range = CM_TABLEDIV * (cuma->maxtable - cuma->mintable);
+ cuma->range = 1.0f / range;
+
+ /* now make a table with CM_TABLE equal x distances */
+ fp = allpoints;
+ lastpoint = allpoints + 2 * (totpoint - 1);
+ cmp = MEM_callocN((CM_TABLE + 1) * sizeof(CurveMapPoint), "dist table");
+
+ for (a = 0; a <= CM_TABLE; a++) {
+ curf = cuma->mintable + range * (float)a;
+ cmp[a].x = curf;
+
+ /* get the first x coordinate larger than curf */
+ while (curf >= fp[0] && fp != lastpoint) {
+ fp += 2;
+ }
+ if (fp == allpoints || (curf >= fp[0] && fp == lastpoint))
+ cmp[a].y = curvemap_calc_extend(cuma, curf, allpoints, lastpoint);
+ else {
+ float fac1 = fp[0] - fp[-2];
+ float fac2 = fp[0] - curf;
+ if (fac1 > FLT_EPSILON)
+ fac1 = fac2 / fac1;
+ else
+ fac1 = 0.0f;
+ cmp[a].y = fac1 * fp[-1] + (1.0f - fac1) * fp[1];
+ }
+ }
+
+ MEM_freeN(allpoints);
+ cuma->table = cmp;
}
/* call when you do images etc, needs restore too. also verifies tables */
/* it uses a flag to prevent premul or free to happen twice */
void curvemapping_premultiply(CurveMapping *cumap, int restore)
{
- int a;
-
- if (restore) {
- if (cumap->flag & CUMA_PREMULLED) {
- for (a = 0; a < 3; a++) {
- MEM_freeN(cumap->cm[a].table);
- cumap->cm[a].table = cumap->cm[a].premultable;
- cumap->cm[a].premultable = NULL;
-
- copy_v2_v2(cumap->cm[a].ext_in, cumap->cm[a].premul_ext_in);
- copy_v2_v2(cumap->cm[a].ext_out, cumap->cm[a].premul_ext_out);
- zero_v2(cumap->cm[a].premul_ext_in);
- zero_v2(cumap->cm[a].premul_ext_out);
- }
-
- cumap->flag &= ~CUMA_PREMULLED;
- }
- }
- else {
- if ((cumap->flag & CUMA_PREMULLED) == 0) {
- /* verify and copy */
- for (a = 0; a < 3; a++) {
- if (cumap->cm[a].table == NULL)
- curvemap_make_table(cumap->cm + a, &cumap->clipr);
- cumap->cm[a].premultable = cumap->cm[a].table;
- cumap->cm[a].table = MEM_mallocN((CM_TABLE + 1) * sizeof(CurveMapPoint), "premul table");
- memcpy(cumap->cm[a].table, cumap->cm[a].premultable, (CM_TABLE + 1) * sizeof(CurveMapPoint));
- }
-
- if (cumap->cm[3].table == NULL)
- curvemap_make_table(cumap->cm + 3, &cumap->clipr);
-
- /* premul */
- for (a = 0; a < 3; a++) {
- int b;
- for (b = 0; b <= CM_TABLE; b++) {
- cumap->cm[a].table[b].y = curvemap_evaluateF(cumap->cm + 3, cumap->cm[a].table[b].y);
- }
-
- copy_v2_v2(cumap->cm[a].premul_ext_in, cumap->cm[a].ext_in);
- copy_v2_v2(cumap->cm[a].premul_ext_out, cumap->cm[a].ext_out);
- mul_v2_v2(cumap->cm[a].ext_in, cumap->cm[3].ext_in);
- mul_v2_v2(cumap->cm[a].ext_out, cumap->cm[3].ext_out);
- }
-
- cumap->flag |= CUMA_PREMULLED;
- }
- }
+ int a;
+
+ if (restore) {
+ if (cumap->flag & CUMA_PREMULLED) {
+ for (a = 0; a < 3; a++) {
+ MEM_freeN(cumap->cm[a].table);
+ cumap->cm[a].table = cumap->cm[a].premultable;
+ cumap->cm[a].premultable = NULL;
+
+ copy_v2_v2(cumap->cm[a].ext_in, cumap->cm[a].premul_ext_in);
+ copy_v2_v2(cumap->cm[a].ext_out, cumap->cm[a].premul_ext_out);
+ zero_v2(cumap->cm[a].premul_ext_in);
+ zero_v2(cumap->cm[a].premul_ext_out);
+ }
+
+ cumap->flag &= ~CUMA_PREMULLED;
+ }
+ }
+ else {
+ if ((cumap->flag & CUMA_PREMULLED) == 0) {
+ /* verify and copy */
+ for (a = 0; a < 3; a++) {
+ if (cumap->cm[a].table == NULL)
+ curvemap_make_table(cumap->cm + a, &cumap->clipr);
+ cumap->cm[a].premultable = cumap->cm[a].table;
+ cumap->cm[a].table = MEM_mallocN((CM_TABLE + 1) * sizeof(CurveMapPoint), "premul table");
+ memcpy(
+ cumap->cm[a].table, cumap->cm[a].premultable, (CM_TABLE + 1) * sizeof(CurveMapPoint));
+ }
+
+ if (cumap->cm[3].table == NULL)
+ curvemap_make_table(cumap->cm + 3, &cumap->clipr);
+
+ /* premul */
+ for (a = 0; a < 3; a++) {
+ int b;
+ for (b = 0; b <= CM_TABLE; b++) {
+ cumap->cm[a].table[b].y = curvemap_evaluateF(cumap->cm + 3, cumap->cm[a].table[b].y);
+ }
+
+ copy_v2_v2(cumap->cm[a].premul_ext_in, cumap->cm[a].ext_in);
+ copy_v2_v2(cumap->cm[a].premul_ext_out, cumap->cm[a].ext_out);
+ mul_v2_v2(cumap->cm[a].ext_in, cumap->cm[3].ext_in);
+ mul_v2_v2(cumap->cm[a].ext_out, cumap->cm[3].ext_out);
+ }
+
+ cumap->flag |= CUMA_PREMULLED;
+ }
+ }
}
static int sort_curvepoints(const void *a1, const void *a2)
{
- const struct CurveMapPoint *x1 = a1, *x2 = a2;
+ const struct CurveMapPoint *x1 = a1, *x2 = a2;
- if (x1->x > x2->x) return 1;
- else if (x1->x < x2->x) return -1;
- return 0;
+ if (x1->x > x2->x)
+ return 1;
+ else if (x1->x < x2->x)
+ return -1;
+ return 0;
}
/* ************************ more CurveMapping calls *************** */
@@ -803,158 +836,161 @@ static int sort_curvepoints(const void *a1, const void *a2)
/* note; only does current curvemap! */
void curvemapping_changed(CurveMapping *cumap, const bool rem_doubles)
{
- CurveMap *cuma = cumap->cm + cumap->cur;
- CurveMapPoint *cmp = cuma->curve;
- rctf *clipr = &cumap->clipr;
- float thresh = 0.01f * BLI_rctf_size_x(clipr);
- float dx = 0.0f, dy = 0.0f;
- int a;
-
- cumap->changed_timestamp++;
-
- /* clamp with clip */
- if (cumap->flag & CUMA_DO_CLIP) {
- for (a = 0; a < cuma->totpoint; a++) {
- if (cmp[a].flag & CUMA_SELECT) {
- if (cmp[a].x < clipr->xmin)
- dx = min_ff(dx, cmp[a].x - clipr->xmin);
- else if (cmp[a].x > clipr->xmax)
- dx = max_ff(dx, cmp[a].x - clipr->xmax);
- if (cmp[a].y < clipr->ymin)
- dy = min_ff(dy, cmp[a].y - clipr->ymin);
- else if (cmp[a].y > clipr->ymax)
- dy = max_ff(dy, cmp[a].y - clipr->ymax);
- }
- }
- for (a = 0; a < cuma->totpoint; a++) {
- if (cmp[a].flag & CUMA_SELECT) {
- cmp[a].x -= dx;
- cmp[a].y -= dy;
- }
- }
-
- /* ensure zoom-level respects clipping */
- if (BLI_rctf_size_x(&cumap->curr) > BLI_rctf_size_x(&cumap->clipr)) {
- cumap->curr.xmin = cumap->clipr.xmin;
- cumap->curr.xmax = cumap->clipr.xmax;
- }
- if (BLI_rctf_size_y(&cumap->curr) > BLI_rctf_size_y(&cumap->clipr)) {
- cumap->curr.ymin = cumap->clipr.ymin;
- cumap->curr.ymax = cumap->clipr.ymax;
- }
- }
-
-
- qsort(cmp, cuma->totpoint, sizeof(CurveMapPoint), sort_curvepoints);
-
- /* remove doubles, threshold set on 1% of default range */
- if (rem_doubles && cuma->totpoint > 2) {
- for (a = 0; a < cuma->totpoint - 1; a++) {
- dx = cmp[a].x - cmp[a + 1].x;
- dy = cmp[a].y - cmp[a + 1].y;
- if (sqrtf(dx * dx + dy * dy) < thresh) {
- if (a == 0) {
- cmp[a + 1].flag |= CUMA_HANDLE_VECTOR;
- if (cmp[a + 1].flag & CUMA_SELECT)
- cmp[a].flag |= CUMA_SELECT;
- }
- else {
- cmp[a].flag |= CUMA_HANDLE_VECTOR;
- if (cmp[a].flag & CUMA_SELECT)
- cmp[a + 1].flag |= CUMA_SELECT;
- }
- break; /* we assume 1 deletion per edit is ok */
- }
- }
- if (a != cuma->totpoint - 1)
- curvemap_remove(cuma, 2);
- }
- curvemap_make_table(cuma, clipr);
+ CurveMap *cuma = cumap->cm + cumap->cur;
+ CurveMapPoint *cmp = cuma->curve;
+ rctf *clipr = &cumap->clipr;
+ float thresh = 0.01f * BLI_rctf_size_x(clipr);
+ float dx = 0.0f, dy = 0.0f;
+ int a;
+
+ cumap->changed_timestamp++;
+
+ /* clamp with clip */
+ if (cumap->flag & CUMA_DO_CLIP) {
+ for (a = 0; a < cuma->totpoint; a++) {
+ if (cmp[a].flag & CUMA_SELECT) {
+ if (cmp[a].x < clipr->xmin)
+ dx = min_ff(dx, cmp[a].x - clipr->xmin);
+ else if (cmp[a].x > clipr->xmax)
+ dx = max_ff(dx, cmp[a].x - clipr->xmax);
+ if (cmp[a].y < clipr->ymin)
+ dy = min_ff(dy, cmp[a].y - clipr->ymin);
+ else if (cmp[a].y > clipr->ymax)
+ dy = max_ff(dy, cmp[a].y - clipr->ymax);
+ }
+ }
+ for (a = 0; a < cuma->totpoint; a++) {
+ if (cmp[a].flag & CUMA_SELECT) {
+ cmp[a].x -= dx;
+ cmp[a].y -= dy;
+ }
+ }
+
+ /* ensure zoom-level respects clipping */
+ if (BLI_rctf_size_x(&cumap->curr) > BLI_rctf_size_x(&cumap->clipr)) {
+ cumap->curr.xmin = cumap->clipr.xmin;
+ cumap->curr.xmax = cumap->clipr.xmax;
+ }
+ if (BLI_rctf_size_y(&cumap->curr) > BLI_rctf_size_y(&cumap->clipr)) {
+ cumap->curr.ymin = cumap->clipr.ymin;
+ cumap->curr.ymax = cumap->clipr.ymax;
+ }
+ }
+
+ qsort(cmp, cuma->totpoint, sizeof(CurveMapPoint), sort_curvepoints);
+
+ /* remove doubles, threshold set on 1% of default range */
+ if (rem_doubles && cuma->totpoint > 2) {
+ for (a = 0; a < cuma->totpoint - 1; a++) {
+ dx = cmp[a].x - cmp[a + 1].x;
+ dy = cmp[a].y - cmp[a + 1].y;
+ if (sqrtf(dx * dx + dy * dy) < thresh) {
+ if (a == 0) {
+ cmp[a + 1].flag |= CUMA_HANDLE_VECTOR;
+ if (cmp[a + 1].flag & CUMA_SELECT)
+ cmp[a].flag |= CUMA_SELECT;
+ }
+ else {
+ cmp[a].flag |= CUMA_HANDLE_VECTOR;
+ if (cmp[a].flag & CUMA_SELECT)
+ cmp[a + 1].flag |= CUMA_SELECT;
+ }
+ break; /* we assume 1 deletion per edit is ok */
+ }
+ }
+ if (a != cuma->totpoint - 1)
+ curvemap_remove(cuma, 2);
+ }
+ curvemap_make_table(cuma, clipr);
}
void curvemapping_changed_all(CurveMapping *cumap)
{
- int a, cur = cumap->cur;
+ int a, cur = cumap->cur;
- for (a = 0; a < CM_TOT; a++) {
- if (cumap->cm[a].curve) {
- cumap->cur = a;
- curvemapping_changed(cumap, false);
- }
- }
+ for (a = 0; a < CM_TOT; a++) {
+ if (cumap->cm[a].curve) {
+ cumap->cur = a;
+ curvemapping_changed(cumap, false);
+ }
+ }
- cumap->cur = cur;
+ cumap->cur = cur;
}
/* table should be verified */
float curvemap_evaluateF(const CurveMap *cuma, float value)
{
- float fi;
- int i;
-
- /* index in table */
- fi = (value - cuma->mintable) * cuma->range;
- i = (int)fi;
-
- /* fi is table float index and should check against table range i.e. [0.0 CM_TABLE] */
- if (fi < 0.0f || fi > CM_TABLE)
- return curvemap_calc_extend(cuma, value, &cuma->table[0].x, &cuma->table[CM_TABLE].x);
- else {
- if (i < 0) return cuma->table[0].y;
- if (i >= CM_TABLE) return cuma->table[CM_TABLE].y;
-
- fi = fi - (float)i;
- return (1.0f - fi) * cuma->table[i].y + (fi) * cuma->table[i + 1].y;
- }
+ float fi;
+ int i;
+
+ /* index in table */
+ fi = (value - cuma->mintable) * cuma->range;
+ i = (int)fi;
+
+ /* fi is table float index and should check against table range i.e. [0.0 CM_TABLE] */
+ if (fi < 0.0f || fi > CM_TABLE)
+ return curvemap_calc_extend(cuma, value, &cuma->table[0].x, &cuma->table[CM_TABLE].x);
+ else {
+ if (i < 0)
+ return cuma->table[0].y;
+ if (i >= CM_TABLE)
+ return cuma->table[CM_TABLE].y;
+
+ fi = fi - (float)i;
+ return (1.0f - fi) * cuma->table[i].y + (fi)*cuma->table[i + 1].y;
+ }
}
/* works with curve 'cur' */
float curvemapping_evaluateF(const CurveMapping *cumap, int cur, float value)
{
- const CurveMap *cuma = cumap->cm + cur;
- float val = curvemap_evaluateF(cuma, value);
-
- /* account for clipping */
- if (cumap->flag & CUMA_DO_CLIP) {
- if (val < cumap->curr.ymin)
- val = cumap->curr.ymin;
- else if (val > cumap->curr.ymax)
- val = cumap->curr.ymax;
- }
-
- return val;
+ const CurveMap *cuma = cumap->cm + cur;
+ float val = curvemap_evaluateF(cuma, value);
+
+ /* account for clipping */
+ if (cumap->flag & CUMA_DO_CLIP) {
+ if (val < cumap->curr.ymin)
+ val = cumap->curr.ymin;
+ else if (val > cumap->curr.ymax)
+ val = cumap->curr.ymax;
+ }
+
+ return val;
}
/* vector case */
void curvemapping_evaluate3F(const CurveMapping *cumap, float vecout[3], const float vecin[3])
{
- vecout[0] = curvemap_evaluateF(&cumap->cm[0], vecin[0]);
- vecout[1] = curvemap_evaluateF(&cumap->cm[1], vecin[1]);
- vecout[2] = curvemap_evaluateF(&cumap->cm[2], vecin[2]);
+ vecout[0] = curvemap_evaluateF(&cumap->cm[0], vecin[0]);
+ vecout[1] = curvemap_evaluateF(&cumap->cm[1], vecin[1]);
+ vecout[2] = curvemap_evaluateF(&cumap->cm[2], vecin[2]);
}
/* RGB case, no black/white points, no premult */
void curvemapping_evaluateRGBF(const CurveMapping *cumap, float vecout[3], const float vecin[3])
{
- vecout[0] = curvemap_evaluateF(&cumap->cm[0], curvemap_evaluateF(&cumap->cm[3], vecin[0]));
- vecout[1] = curvemap_evaluateF(&cumap->cm[1], curvemap_evaluateF(&cumap->cm[3], vecin[1]));
- vecout[2] = curvemap_evaluateF(&cumap->cm[2], curvemap_evaluateF(&cumap->cm[3], vecin[2]));
+ vecout[0] = curvemap_evaluateF(&cumap->cm[0], curvemap_evaluateF(&cumap->cm[3], vecin[0]));
+ vecout[1] = curvemap_evaluateF(&cumap->cm[1], curvemap_evaluateF(&cumap->cm[3], vecin[1]));
+ vecout[2] = curvemap_evaluateF(&cumap->cm[2], curvemap_evaluateF(&cumap->cm[3], vecin[2]));
}
-static void curvemapping_evaluateRGBF_filmlike(const CurveMapping *cumap, float vecout[3], const float vecin[3],
+static void curvemapping_evaluateRGBF_filmlike(const CurveMapping *cumap,
+ float vecout[3],
+ const float vecin[3],
const int channel_offset[3])
{
- const float v0in = vecin[channel_offset[0]];
- const float v1in = vecin[channel_offset[1]];
- const float v2in = vecin[channel_offset[2]];
+ const float v0in = vecin[channel_offset[0]];
+ const float v1in = vecin[channel_offset[1]];
+ const float v2in = vecin[channel_offset[2]];
- const float v0 = curvemap_evaluateF(&cumap->cm[channel_offset[0]], v0in);
- const float v2 = curvemap_evaluateF(&cumap->cm[channel_offset[2]], v2in);
- const float v1 = v2 + ((v0 - v2) * (v1in - v2in) / (v0in - v2in));
+ const float v0 = curvemap_evaluateF(&cumap->cm[channel_offset[0]], v0in);
+ const float v2 = curvemap_evaluateF(&cumap->cm[channel_offset[2]], v2in);
+ const float v1 = v2 + ((v0 - v2) * (v1in - v2in) / (v0in - v2in));
- vecout[channel_offset[0]] = v0;
- vecout[channel_offset[1]] = v1;
- vecout[channel_offset[2]] = v2;
+ vecout[channel_offset[0]] = v0;
+ vecout[channel_offset[1]] = v1;
+ vecout[channel_offset[2]] = v2;
}
/** same as #curvemapping_evaluate_premulRGBF
@@ -966,681 +1002,723 @@ static void curvemapping_evaluateRGBF_filmlike(const CurveMapping *cumap, float
* \param black: Use instead of cumap->black
* \param bwmul: Use instead of cumap->bwmul
*/
-void curvemapping_evaluate_premulRGBF_ex(
- const CurveMapping *cumap, float vecout[3], const float vecin[3],
- const float black[3], const float bwmul[3])
+void curvemapping_evaluate_premulRGBF_ex(const CurveMapping *cumap,
+ float vecout[3],
+ const float vecin[3],
+ const float black[3],
+ const float bwmul[3])
{
- const float r = (vecin[0] - black[0]) * bwmul[0];
- const float g = (vecin[1] - black[1]) * bwmul[1];
- const float b = (vecin[2] - black[2]) * bwmul[2];
-
- switch (cumap->tone) {
- default:
- case CURVE_TONE_STANDARD:
- {
- vecout[0] = curvemap_evaluateF(&cumap->cm[0], r);
- vecout[1] = curvemap_evaluateF(&cumap->cm[1], g);
- vecout[2] = curvemap_evaluateF(&cumap->cm[2], b);
- break;
- }
- case CURVE_TONE_FILMLIKE:
- {
- if (r >= g) {
- if (g > b) {
- /* Case 1: r >= g > b */
- const int shuffeled_channels[] = {0, 1, 2};
- curvemapping_evaluateRGBF_filmlike(cumap, vecout, vecin, shuffeled_channels);
- }
- else if (b > r) {
- /* Case 2: b > r >= g */
- const int shuffeled_channels[] = {2, 0, 1};
- curvemapping_evaluateRGBF_filmlike(cumap, vecout, vecin, shuffeled_channels);
- }
- else if (b > g) {
- /* Case 3: r >= b > g */
- const int shuffeled_channels[] = {0, 2, 1};
- curvemapping_evaluateRGBF_filmlike(cumap, vecout, vecin, shuffeled_channels);
- }
- else {
- /* Case 4: r >= g == b */
- copy_v2_fl2(vecout, curvemap_evaluateF(&cumap->cm[0], r), curvemap_evaluateF(&cumap->cm[1], g));
- vecout[2] = vecout[1];
- }
- }
- else {
- if (r >= b) {
- /* Case 5: g > r >= b */
- const int shuffeled_channels[] = {1, 0, 2};
- curvemapping_evaluateRGBF_filmlike(cumap, vecout, vecin, shuffeled_channels);
- }
- else if (b > g) {
- /* Case 6: b > g > r */
- const int shuffeled_channels[] = {2, 1, 0};
- curvemapping_evaluateRGBF_filmlike(cumap, vecout, vecin, shuffeled_channels);
- }
- else {
- /* Case 7: g >= b > r */
- const int shuffeled_channels[] = {1, 2, 0};
- curvemapping_evaluateRGBF_filmlike(cumap, vecout, vecin, shuffeled_channels);
- }
- }
- break;
- }
- }
+ const float r = (vecin[0] - black[0]) * bwmul[0];
+ const float g = (vecin[1] - black[1]) * bwmul[1];
+ const float b = (vecin[2] - black[2]) * bwmul[2];
+
+ switch (cumap->tone) {
+ default:
+ case CURVE_TONE_STANDARD: {
+ vecout[0] = curvemap_evaluateF(&cumap->cm[0], r);
+ vecout[1] = curvemap_evaluateF(&cumap->cm[1], g);
+ vecout[2] = curvemap_evaluateF(&cumap->cm[2], b);
+ break;
+ }
+ case CURVE_TONE_FILMLIKE: {
+ if (r >= g) {
+ if (g > b) {
+ /* Case 1: r >= g > b */
+ const int shuffeled_channels[] = {0, 1, 2};
+ curvemapping_evaluateRGBF_filmlike(cumap, vecout, vecin, shuffeled_channels);
+ }
+ else if (b > r) {
+ /* Case 2: b > r >= g */
+ const int shuffeled_channels[] = {2, 0, 1};
+ curvemapping_evaluateRGBF_filmlike(cumap, vecout, vecin, shuffeled_channels);
+ }
+ else if (b > g) {
+ /* Case 3: r >= b > g */
+ const int shuffeled_channels[] = {0, 2, 1};
+ curvemapping_evaluateRGBF_filmlike(cumap, vecout, vecin, shuffeled_channels);
+ }
+ else {
+ /* Case 4: r >= g == b */
+ copy_v2_fl2(
+ vecout, curvemap_evaluateF(&cumap->cm[0], r), curvemap_evaluateF(&cumap->cm[1], g));
+ vecout[2] = vecout[1];
+ }
+ }
+ else {
+ if (r >= b) {
+ /* Case 5: g > r >= b */
+ const int shuffeled_channels[] = {1, 0, 2};
+ curvemapping_evaluateRGBF_filmlike(cumap, vecout, vecin, shuffeled_channels);
+ }
+ else if (b > g) {
+ /* Case 6: b > g > r */
+ const int shuffeled_channels[] = {2, 1, 0};
+ curvemapping_evaluateRGBF_filmlike(cumap, vecout, vecin, shuffeled_channels);
+ }
+ else {
+ /* Case 7: g >= b > r */
+ const int shuffeled_channels[] = {1, 2, 0};
+ curvemapping_evaluateRGBF_filmlike(cumap, vecout, vecin, shuffeled_channels);
+ }
+ }
+ break;
+ }
+ }
}
/* RGB with black/white points and premult. tables are checked */
-void curvemapping_evaluate_premulRGBF(const CurveMapping *cumap, float vecout[3], const float vecin[3])
+void curvemapping_evaluate_premulRGBF(const CurveMapping *cumap,
+ float vecout[3],
+ const float vecin[3])
{
- curvemapping_evaluate_premulRGBF_ex(cumap, vecout, vecin, cumap->black, cumap->bwmul);
+ curvemapping_evaluate_premulRGBF_ex(cumap, vecout, vecin, cumap->black, cumap->bwmul);
}
/* same as above, byte version */
-void curvemapping_evaluate_premulRGB(const CurveMapping *cumap, unsigned char vecout_byte[3], const unsigned char vecin_byte[3])
+void curvemapping_evaluate_premulRGB(const CurveMapping *cumap,
+ unsigned char vecout_byte[3],
+ const unsigned char vecin_byte[3])
{
- float vecin[3], vecout[3];
+ float vecin[3], vecout[3];
- vecin[0] = (float) vecin_byte[0] / 255.0f;
- vecin[1] = (float) vecin_byte[1] / 255.0f;
- vecin[2] = (float) vecin_byte[2] / 255.0f;
+ vecin[0] = (float)vecin_byte[0] / 255.0f;
+ vecin[1] = (float)vecin_byte[1] / 255.0f;
+ vecin[2] = (float)vecin_byte[2] / 255.0f;
- curvemapping_evaluate_premulRGBF(cumap, vecout, vecin);
+ curvemapping_evaluate_premulRGBF(cumap, vecout, vecin);
- vecout_byte[0] = unit_float_to_uchar_clamp(vecout[0]);
- vecout_byte[1] = unit_float_to_uchar_clamp(vecout[1]);
- vecout_byte[2] = unit_float_to_uchar_clamp(vecout[2]);
+ vecout_byte[0] = unit_float_to_uchar_clamp(vecout[0]);
+ vecout_byte[1] = unit_float_to_uchar_clamp(vecout[1]);
+ vecout_byte[2] = unit_float_to_uchar_clamp(vecout[2]);
}
int curvemapping_RGBA_does_something(const CurveMapping *cumap)
{
- int a;
-
- if (cumap->black[0] != 0.0f) return 1;
- if (cumap->black[1] != 0.0f) return 1;
- if (cumap->black[2] != 0.0f) return 1;
- if (cumap->white[0] != 1.0f) return 1;
- if (cumap->white[1] != 1.0f) return 1;
- if (cumap->white[2] != 1.0f) return 1;
-
- for (a = 0; a < CM_TOT; a++) {
- if (cumap->cm[a].curve) {
- if (cumap->cm[a].totpoint != 2) return 1;
-
- if (cumap->cm[a].curve[0].x != 0.0f) return 1;
- if (cumap->cm[a].curve[0].y != 0.0f) return 1;
- if (cumap->cm[a].curve[1].x != 1.0f) return 1;
- if (cumap->cm[a].curve[1].y != 1.0f) return 1;
- }
- }
- return 0;
+ int a;
+
+ if (cumap->black[0] != 0.0f)
+ return 1;
+ if (cumap->black[1] != 0.0f)
+ return 1;
+ if (cumap->black[2] != 0.0f)
+ return 1;
+ if (cumap->white[0] != 1.0f)
+ return 1;
+ if (cumap->white[1] != 1.0f)
+ return 1;
+ if (cumap->white[2] != 1.0f)
+ return 1;
+
+ for (a = 0; a < CM_TOT; a++) {
+ if (cumap->cm[a].curve) {
+ if (cumap->cm[a].totpoint != 2)
+ return 1;
+
+ if (cumap->cm[a].curve[0].x != 0.0f)
+ return 1;
+ if (cumap->cm[a].curve[0].y != 0.0f)
+ return 1;
+ if (cumap->cm[a].curve[1].x != 1.0f)
+ return 1;
+ if (cumap->cm[a].curve[1].y != 1.0f)
+ return 1;
+ }
+ }
+ return 0;
}
void curvemapping_initialize(CurveMapping *cumap)
{
- int a;
+ int a;
- if (cumap == NULL) return;
+ if (cumap == NULL)
+ return;
- for (a = 0; a < CM_TOT; a++) {
- if (cumap->cm[a].table == NULL)
- curvemap_make_table(cumap->cm + a, &cumap->clipr);
- }
+ for (a = 0; a < CM_TOT; a++) {
+ if (cumap->cm[a].table == NULL)
+ curvemap_make_table(cumap->cm + a, &cumap->clipr);
+ }
}
void curvemapping_table_RGBA(const CurveMapping *cumap, float **array, int *size)
{
- int a;
-
- *size = CM_TABLE + 1;
- *array = MEM_callocN(sizeof(float) * (*size) * 4, "CurveMapping");
-
- for (a = 0; a < *size; a++) {
- if (cumap->cm[0].table)
- (*array)[a * 4 + 0] = cumap->cm[0].table[a].y;
- if (cumap->cm[1].table)
- (*array)[a * 4 + 1] = cumap->cm[1].table[a].y;
- if (cumap->cm[2].table)
- (*array)[a * 4 + 2] = cumap->cm[2].table[a].y;
- if (cumap->cm[3].table)
- (*array)[a * 4 + 3] = cumap->cm[3].table[a].y;
- }
+ int a;
+
+ *size = CM_TABLE + 1;
+ *array = MEM_callocN(sizeof(float) * (*size) * 4, "CurveMapping");
+
+ for (a = 0; a < *size; a++) {
+ if (cumap->cm[0].table)
+ (*array)[a * 4 + 0] = cumap->cm[0].table[a].y;
+ if (cumap->cm[1].table)
+ (*array)[a * 4 + 1] = cumap->cm[1].table[a].y;
+ if (cumap->cm[2].table)
+ (*array)[a * 4 + 2] = cumap->cm[2].table[a].y;
+ if (cumap->cm[3].table)
+ (*array)[a * 4 + 3] = cumap->cm[3].table[a].y;
+ }
}
/* ***************** Histogram **************** */
-#define INV_255 (1.f / 255.f)
+#define INV_255 (1.f / 255.f)
BLI_INLINE int get_bin_float(float f)
{
- int bin = (int)((f * 255.0f) + 0.5f); /* 0.5 to prevent quantisation differences */
+ int bin = (int)((f * 255.0f) + 0.5f); /* 0.5 to prevent quantisation differences */
- /* note: clamp integer instead of float to avoid problems with NaN */
- CLAMP(bin, 0, 255);
+ /* note: clamp integer instead of float to avoid problems with NaN */
+ CLAMP(bin, 0, 255);
- return bin;
+ return bin;
}
-static void save_sample_line(Scopes *scopes, const int idx, const float fx, const float rgb[3], const float ycc[3])
+static void save_sample_line(
+ Scopes *scopes, const int idx, const float fx, const float rgb[3], const float ycc[3])
{
- float yuv[3];
-
- /* vectorscope*/
- rgb_to_yuv(rgb[0], rgb[1], rgb[2], &yuv[0], &yuv[1], &yuv[2], BLI_YUV_ITU_BT709);
- scopes->vecscope[idx + 0] = yuv[1];
- scopes->vecscope[idx + 1] = yuv[2];
-
- /* waveform */
- switch (scopes->wavefrm_mode) {
- case SCOPES_WAVEFRM_RGB:
- case SCOPES_WAVEFRM_RGB_PARADE:
- scopes->waveform_1[idx + 0] = fx;
- scopes->waveform_1[idx + 1] = rgb[0];
- scopes->waveform_2[idx + 0] = fx;
- scopes->waveform_2[idx + 1] = rgb[1];
- scopes->waveform_3[idx + 0] = fx;
- scopes->waveform_3[idx + 1] = rgb[2];
- break;
- case SCOPES_WAVEFRM_LUMA:
- scopes->waveform_1[idx + 0] = fx;
- scopes->waveform_1[idx + 1] = ycc[0];
- break;
- case SCOPES_WAVEFRM_YCC_JPEG:
- case SCOPES_WAVEFRM_YCC_709:
- case SCOPES_WAVEFRM_YCC_601:
- scopes->waveform_1[idx + 0] = fx;
- scopes->waveform_1[idx + 1] = ycc[0];
- scopes->waveform_2[idx + 0] = fx;
- scopes->waveform_2[idx + 1] = ycc[1];
- scopes->waveform_3[idx + 0] = fx;
- scopes->waveform_3[idx + 1] = ycc[2];
- break;
- }
+ float yuv[3];
+
+ /* vectorscope*/
+ rgb_to_yuv(rgb[0], rgb[1], rgb[2], &yuv[0], &yuv[1], &yuv[2], BLI_YUV_ITU_BT709);
+ scopes->vecscope[idx + 0] = yuv[1];
+ scopes->vecscope[idx + 1] = yuv[2];
+
+ /* waveform */
+ switch (scopes->wavefrm_mode) {
+ case SCOPES_WAVEFRM_RGB:
+ case SCOPES_WAVEFRM_RGB_PARADE:
+ scopes->waveform_1[idx + 0] = fx;
+ scopes->waveform_1[idx + 1] = rgb[0];
+ scopes->waveform_2[idx + 0] = fx;
+ scopes->waveform_2[idx + 1] = rgb[1];
+ scopes->waveform_3[idx + 0] = fx;
+ scopes->waveform_3[idx + 1] = rgb[2];
+ break;
+ case SCOPES_WAVEFRM_LUMA:
+ scopes->waveform_1[idx + 0] = fx;
+ scopes->waveform_1[idx + 1] = ycc[0];
+ break;
+ case SCOPES_WAVEFRM_YCC_JPEG:
+ case SCOPES_WAVEFRM_YCC_709:
+ case SCOPES_WAVEFRM_YCC_601:
+ scopes->waveform_1[idx + 0] = fx;
+ scopes->waveform_1[idx + 1] = ycc[0];
+ scopes->waveform_2[idx + 0] = fx;
+ scopes->waveform_2[idx + 1] = ycc[1];
+ scopes->waveform_3[idx + 0] = fx;
+ scopes->waveform_3[idx + 1] = ycc[2];
+ break;
+ }
}
-void BKE_histogram_update_sample_line(Histogram *hist, ImBuf *ibuf, const ColorManagedViewSettings *view_settings,
+void BKE_histogram_update_sample_line(Histogram *hist,
+ ImBuf *ibuf,
+ const ColorManagedViewSettings *view_settings,
const ColorManagedDisplaySettings *display_settings)
{
- int i, x, y;
- const float *fp;
- unsigned char *cp;
-
- int x1 = 0.5f + hist->co[0][0] * ibuf->x;
- int x2 = 0.5f + hist->co[1][0] * ibuf->x;
- int y1 = 0.5f + hist->co[0][1] * ibuf->y;
- int y2 = 0.5f + hist->co[1][1] * ibuf->y;
-
- struct ColormanageProcessor *cm_processor = NULL;
-
- hist->channels = 3;
- hist->x_resolution = 256;
- hist->xmax = 1.0f;
- /* hist->ymax = 1.0f; */ /* now do this on the operator _only_ */
-
- if (ibuf->rect == NULL && ibuf->rect_float == NULL) return;
-
- if (ibuf->rect_float)
- cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
-
- for (i = 0; i < 256; i++) {
- x = (int)(0.5f + x1 + (float)i * (x2 - x1) / 255.0f);
- y = (int)(0.5f + y1 + (float)i * (y2 - y1) / 255.0f);
-
- if (x < 0 || y < 0 || x >= ibuf->x || y >= ibuf->y) {
- hist->data_luma[i] = hist->data_r[i] = hist->data_g[i] = hist->data_b[i] = hist->data_a[i] = 0.0f;
- }
- else {
- if (ibuf->rect_float) {
- float rgba[4];
- fp = (ibuf->rect_float + (ibuf->channels) * (y * ibuf->x + x));
-
- switch (ibuf->channels) {
- case 4:
- copy_v4_v4(rgba, fp);
- IMB_colormanagement_processor_apply_v4(cm_processor, rgba);
- break;
- case 3:
- copy_v3_v3(rgba, fp);
- IMB_colormanagement_processor_apply_v3(cm_processor, rgba);
- rgba[3] = 1.0f;
- break;
- case 2:
- copy_v3_fl(rgba, fp[0]);
- rgba[3] = fp[1];
- break;
- case 1:
- copy_v3_fl(rgba, fp[0]);
- rgba[3] = 1.0f;
- break;
- default:
- BLI_assert(0);
- }
-
- hist->data_luma[i] = IMB_colormanagement_get_luminance(rgba);
- hist->data_r[i] = rgba[0];
- hist->data_g[i] = rgba[1];
- hist->data_b[i] = rgba[2];
- hist->data_a[i] = rgba[3];
- }
- else if (ibuf->rect) {
- cp = (unsigned char *)(ibuf->rect + y * ibuf->x + x);
- hist->data_luma[i] = (float)IMB_colormanagement_get_luminance_byte(cp) / 255.0f;
- hist->data_r[i] = (float)cp[0] / 255.0f;
- hist->data_g[i] = (float)cp[1] / 255.0f;
- hist->data_b[i] = (float)cp[2] / 255.0f;
- hist->data_a[i] = (float)cp[3] / 255.0f;
- }
- }
- }
-
- if (cm_processor)
- IMB_colormanagement_processor_free(cm_processor);
+ int i, x, y;
+ const float *fp;
+ unsigned char *cp;
+
+ int x1 = 0.5f + hist->co[0][0] * ibuf->x;
+ int x2 = 0.5f + hist->co[1][0] * ibuf->x;
+ int y1 = 0.5f + hist->co[0][1] * ibuf->y;
+ int y2 = 0.5f + hist->co[1][1] * ibuf->y;
+
+ struct ColormanageProcessor *cm_processor = NULL;
+
+ hist->channels = 3;
+ hist->x_resolution = 256;
+ hist->xmax = 1.0f;
+ /* hist->ymax = 1.0f; */ /* now do this on the operator _only_ */
+
+ if (ibuf->rect == NULL && ibuf->rect_float == NULL)
+ return;
+
+ if (ibuf->rect_float)
+ cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
+
+ for (i = 0; i < 256; i++) {
+ x = (int)(0.5f + x1 + (float)i * (x2 - x1) / 255.0f);
+ y = (int)(0.5f + y1 + (float)i * (y2 - y1) / 255.0f);
+
+ if (x < 0 || y < 0 || x >= ibuf->x || y >= ibuf->y) {
+ hist->data_luma[i] = hist->data_r[i] = hist->data_g[i] = hist->data_b[i] = hist->data_a[i] =
+ 0.0f;
+ }
+ else {
+ if (ibuf->rect_float) {
+ float rgba[4];
+ fp = (ibuf->rect_float + (ibuf->channels) * (y * ibuf->x + x));
+
+ switch (ibuf->channels) {
+ case 4:
+ copy_v4_v4(rgba, fp);
+ IMB_colormanagement_processor_apply_v4(cm_processor, rgba);
+ break;
+ case 3:
+ copy_v3_v3(rgba, fp);
+ IMB_colormanagement_processor_apply_v3(cm_processor, rgba);
+ rgba[3] = 1.0f;
+ break;
+ case 2:
+ copy_v3_fl(rgba, fp[0]);
+ rgba[3] = fp[1];
+ break;
+ case 1:
+ copy_v3_fl(rgba, fp[0]);
+ rgba[3] = 1.0f;
+ break;
+ default:
+ BLI_assert(0);
+ }
+
+ hist->data_luma[i] = IMB_colormanagement_get_luminance(rgba);
+ hist->data_r[i] = rgba[0];
+ hist->data_g[i] = rgba[1];
+ hist->data_b[i] = rgba[2];
+ hist->data_a[i] = rgba[3];
+ }
+ else if (ibuf->rect) {
+ cp = (unsigned char *)(ibuf->rect + y * ibuf->x + x);
+ hist->data_luma[i] = (float)IMB_colormanagement_get_luminance_byte(cp) / 255.0f;
+ hist->data_r[i] = (float)cp[0] / 255.0f;
+ hist->data_g[i] = (float)cp[1] / 255.0f;
+ hist->data_b[i] = (float)cp[2] / 255.0f;
+ hist->data_a[i] = (float)cp[3] / 255.0f;
+ }
+ }
+ }
+
+ if (cm_processor)
+ IMB_colormanagement_processor_free(cm_processor);
}
/* if view_settings, it also applies this to byte buffers */
typedef struct ScopesUpdateData {
- Scopes *scopes;
- const ImBuf *ibuf;
- struct ColormanageProcessor *cm_processor;
- const unsigned char *display_buffer;
- const int ycc_mode;
+ Scopes *scopes;
+ const ImBuf *ibuf;
+ struct ColormanageProcessor *cm_processor;
+ const unsigned char *display_buffer;
+ const int ycc_mode;
- unsigned int *bin_lum, *bin_r, *bin_g, *bin_b, *bin_a;
+ unsigned int *bin_lum, *bin_r, *bin_g, *bin_b, *bin_a;
} ScopesUpdateData;
typedef struct ScopesUpdateDataChunk {
- unsigned int bin_lum[256];
- unsigned int bin_r[256];
- unsigned int bin_g[256];
- unsigned int bin_b[256];
- unsigned int bin_a[256];
- float min[3], max[3];
+ unsigned int bin_lum[256];
+ unsigned int bin_r[256];
+ unsigned int bin_g[256];
+ unsigned int bin_b[256];
+ unsigned int bin_a[256];
+ float min[3], max[3];
} ScopesUpdateDataChunk;
static void scopes_update_cb(void *__restrict userdata,
const int y,
const ParallelRangeTLS *__restrict tls)
{
- const ScopesUpdateData *data = userdata;
-
- Scopes *scopes = data->scopes;
- const ImBuf *ibuf = data->ibuf;
- struct ColormanageProcessor *cm_processor = data->cm_processor;
- const unsigned char *display_buffer = data->display_buffer;
- const int ycc_mode = data->ycc_mode;
-
- ScopesUpdateDataChunk *data_chunk = tls->userdata_chunk;
- unsigned int *bin_lum = data_chunk->bin_lum;
- unsigned int *bin_r = data_chunk->bin_r;
- unsigned int *bin_g = data_chunk->bin_g;
- unsigned int *bin_b = data_chunk->bin_b;
- unsigned int *bin_a = data_chunk->bin_a;
- float *min = data_chunk->min;
- float *max = data_chunk->max;
-
- const float *rf = NULL;
- const unsigned char *rc = NULL;
- const int rows_per_sample_line = ibuf->y / scopes->sample_lines;
- const int savedlines = y / rows_per_sample_line;
- const bool do_sample_line = (savedlines < scopes->sample_lines) && (y % rows_per_sample_line) == 0;
- const bool is_float = (ibuf->rect_float != NULL);
-
- if (is_float)
- rf = ibuf->rect_float + ((size_t)y) * ibuf->x * ibuf->channels;
- else {
- rc = display_buffer + ((size_t)y) * ibuf->x * ibuf->channels;
- }
-
- for (int x = 0; x < ibuf->x; x++) {
- float rgba[4], ycc[3], luma;
-
- if (is_float) {
- switch (ibuf->channels) {
- case 4:
- copy_v4_v4(rgba, rf);
- IMB_colormanagement_processor_apply_v4(cm_processor, rgba);
- break;
- case 3:
- copy_v3_v3(rgba, rf);
- IMB_colormanagement_processor_apply_v3(cm_processor, rgba);
- rgba[3] = 1.0f;
- break;
- case 2:
- copy_v3_fl(rgba, rf[0]);
- rgba[3] = rf[1];
- break;
- case 1:
- copy_v3_fl(rgba, rf[0]);
- rgba[3] = 1.0f;
- break;
- default:
- BLI_assert(0);
- }
- }
- else {
- for (int c = 4; c--;)
- rgba[c] = rc[c] * INV_255;
- }
-
- /* we still need luma for histogram */
- luma = IMB_colormanagement_get_luminance(rgba);
-
- /* check for min max */
- if (ycc_mode == -1) {
- minmax_v3v3_v3(min, max, rgba);
- }
- else {
- rgb_to_ycc(rgba[0], rgba[1], rgba[2], &ycc[0], &ycc[1], &ycc[2], ycc_mode);
- mul_v3_fl(ycc, INV_255);
- minmax_v3v3_v3(min, max, ycc);
- }
- /* increment count for histo*/
- bin_lum[get_bin_float(luma)]++;
- bin_r[get_bin_float(rgba[0])]++;
- bin_g[get_bin_float(rgba[1])]++;
- bin_b[get_bin_float(rgba[2])]++;
- bin_a[get_bin_float(rgba[3])]++;
-
- /* save sample if needed */
- if (do_sample_line) {
- const float fx = (float)x / (float)ibuf->x;
- const int idx = 2 * (ibuf->x * savedlines + x);
- save_sample_line(scopes, idx, fx, rgba, ycc);
- }
-
- rf += ibuf->channels;
- rc += ibuf->channels;
- }
+ const ScopesUpdateData *data = userdata;
+
+ Scopes *scopes = data->scopes;
+ const ImBuf *ibuf = data->ibuf;
+ struct ColormanageProcessor *cm_processor = data->cm_processor;
+ const unsigned char *display_buffer = data->display_buffer;
+ const int ycc_mode = data->ycc_mode;
+
+ ScopesUpdateDataChunk *data_chunk = tls->userdata_chunk;
+ unsigned int *bin_lum = data_chunk->bin_lum;
+ unsigned int *bin_r = data_chunk->bin_r;
+ unsigned int *bin_g = data_chunk->bin_g;
+ unsigned int *bin_b = data_chunk->bin_b;
+ unsigned int *bin_a = data_chunk->bin_a;
+ float *min = data_chunk->min;
+ float *max = data_chunk->max;
+
+ const float *rf = NULL;
+ const unsigned char *rc = NULL;
+ const int rows_per_sample_line = ibuf->y / scopes->sample_lines;
+ const int savedlines = y / rows_per_sample_line;
+ const bool do_sample_line = (savedlines < scopes->sample_lines) &&
+ (y % rows_per_sample_line) == 0;
+ const bool is_float = (ibuf->rect_float != NULL);
+
+ if (is_float)
+ rf = ibuf->rect_float + ((size_t)y) * ibuf->x * ibuf->channels;
+ else {
+ rc = display_buffer + ((size_t)y) * ibuf->x * ibuf->channels;
+ }
+
+ for (int x = 0; x < ibuf->x; x++) {
+ float rgba[4], ycc[3], luma;
+
+ if (is_float) {
+ switch (ibuf->channels) {
+ case 4:
+ copy_v4_v4(rgba, rf);
+ IMB_colormanagement_processor_apply_v4(cm_processor, rgba);
+ break;
+ case 3:
+ copy_v3_v3(rgba, rf);
+ IMB_colormanagement_processor_apply_v3(cm_processor, rgba);
+ rgba[3] = 1.0f;
+ break;
+ case 2:
+ copy_v3_fl(rgba, rf[0]);
+ rgba[3] = rf[1];
+ break;
+ case 1:
+ copy_v3_fl(rgba, rf[0]);
+ rgba[3] = 1.0f;
+ break;
+ default:
+ BLI_assert(0);
+ }
+ }
+ else {
+ for (int c = 4; c--;)
+ rgba[c] = rc[c] * INV_255;
+ }
+
+ /* we still need luma for histogram */
+ luma = IMB_colormanagement_get_luminance(rgba);
+
+ /* check for min max */
+ if (ycc_mode == -1) {
+ minmax_v3v3_v3(min, max, rgba);
+ }
+ else {
+ rgb_to_ycc(rgba[0], rgba[1], rgba[2], &ycc[0], &ycc[1], &ycc[2], ycc_mode);
+ mul_v3_fl(ycc, INV_255);
+ minmax_v3v3_v3(min, max, ycc);
+ }
+ /* increment count for histo*/
+ bin_lum[get_bin_float(luma)]++;
+ bin_r[get_bin_float(rgba[0])]++;
+ bin_g[get_bin_float(rgba[1])]++;
+ bin_b[get_bin_float(rgba[2])]++;
+ bin_a[get_bin_float(rgba[3])]++;
+
+ /* save sample if needed */
+ if (do_sample_line) {
+ const float fx = (float)x / (float)ibuf->x;
+ const int idx = 2 * (ibuf->x * savedlines + x);
+ save_sample_line(scopes, idx, fx, rgba, ycc);
+ }
+
+ rf += ibuf->channels;
+ rc += ibuf->channels;
+ }
}
-static void scopes_update_finalize(void *__restrict userdata,
- void *__restrict userdata_chunk)
+static void scopes_update_finalize(void *__restrict userdata, void *__restrict userdata_chunk)
{
- const ScopesUpdateData *data = userdata;
- const ScopesUpdateDataChunk *data_chunk = userdata_chunk;
-
- unsigned int *bin_lum = data->bin_lum;
- unsigned int *bin_r = data->bin_r;
- unsigned int *bin_g = data->bin_g;
- unsigned int *bin_b = data->bin_b;
- unsigned int *bin_a = data->bin_a;
- const unsigned int *bin_lum_c = data_chunk->bin_lum;
- const unsigned int *bin_r_c = data_chunk->bin_r;
- const unsigned int *bin_g_c = data_chunk->bin_g;
- const unsigned int *bin_b_c = data_chunk->bin_b;
- const unsigned int *bin_a_c = data_chunk->bin_a;
-
- float (*minmax)[2] = data->scopes->minmax;
- const float *min = data_chunk->min;
- const float *max = data_chunk->max;
-
- for (int b = 256; b--;) {
- bin_lum[b] += bin_lum_c[b];
- bin_r[b] += bin_r_c[b];
- bin_g[b] += bin_g_c[b];
- bin_b[b] += bin_b_c[b];
- bin_a[b] += bin_a_c[b];
- }
-
- for (int c = 3; c--;) {
- if (min[c] < minmax[c][0])
- minmax[c][0] = min[c];
- if (max[c] > minmax[c][1])
- minmax[c][1] = max[c];
- }
+ const ScopesUpdateData *data = userdata;
+ const ScopesUpdateDataChunk *data_chunk = userdata_chunk;
+
+ unsigned int *bin_lum = data->bin_lum;
+ unsigned int *bin_r = data->bin_r;
+ unsigned int *bin_g = data->bin_g;
+ unsigned int *bin_b = data->bin_b;
+ unsigned int *bin_a = data->bin_a;
+ const unsigned int *bin_lum_c = data_chunk->bin_lum;
+ const unsigned int *bin_r_c = data_chunk->bin_r;
+ const unsigned int *bin_g_c = data_chunk->bin_g;
+ const unsigned int *bin_b_c = data_chunk->bin_b;
+ const unsigned int *bin_a_c = data_chunk->bin_a;
+
+ float(*minmax)[2] = data->scopes->minmax;
+ const float *min = data_chunk->min;
+ const float *max = data_chunk->max;
+
+ for (int b = 256; b--;) {
+ bin_lum[b] += bin_lum_c[b];
+ bin_r[b] += bin_r_c[b];
+ bin_g[b] += bin_g_c[b];
+ bin_b[b] += bin_b_c[b];
+ bin_a[b] += bin_a_c[b];
+ }
+
+ for (int c = 3; c--;) {
+ if (min[c] < minmax[c][0])
+ minmax[c][0] = min[c];
+ if (max[c] > minmax[c][1])
+ minmax[c][1] = max[c];
+ }
}
-void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *view_settings,
+void scopes_update(Scopes *scopes,
+ ImBuf *ibuf,
+ const ColorManagedViewSettings *view_settings,
const ColorManagedDisplaySettings *display_settings)
{
- int a;
- unsigned int nl, na, nr, ng, nb;
- double divl, diva, divr, divg, divb;
- const unsigned char *display_buffer = NULL;
- unsigned int bin_lum[256] = {0},
- bin_r[256] = {0},
- bin_g[256] = {0},
- bin_b[256] = {0},
- bin_a[256] = {0};
- int ycc_mode = -1;
- void *cache_handle = NULL;
- struct ColormanageProcessor *cm_processor = NULL;
-
- if (ibuf->rect == NULL && ibuf->rect_float == NULL) return;
-
- if (scopes->ok == 1) return;
-
- if (scopes->hist.ymax == 0.f) scopes->hist.ymax = 1.f;
-
- /* hmmmm */
- if (!(ELEM(ibuf->channels, 3, 4))) return;
-
- scopes->hist.channels = 3;
- scopes->hist.x_resolution = 256;
-
- switch (scopes->wavefrm_mode) {
- case SCOPES_WAVEFRM_RGB:
- /* fall-through */
- case SCOPES_WAVEFRM_RGB_PARADE:
- ycc_mode = -1;
- break;
- case SCOPES_WAVEFRM_LUMA:
- case SCOPES_WAVEFRM_YCC_JPEG:
- ycc_mode = BLI_YCC_JFIF_0_255;
- break;
- case SCOPES_WAVEFRM_YCC_601:
- ycc_mode = BLI_YCC_ITU_BT601;
- break;
- case SCOPES_WAVEFRM_YCC_709:
- ycc_mode = BLI_YCC_ITU_BT709;
- break;
- }
-
- /* convert to number of lines with logarithmic scale */
- scopes->sample_lines = (scopes->accuracy * 0.01f) * (scopes->accuracy * 0.01f) * ibuf->y;
- CLAMP_MIN(scopes->sample_lines, 1);
-
- if (scopes->sample_full)
- scopes->sample_lines = ibuf->y;
-
- /* scan the image */
- for (a = 0; a < 3; a++) {
- scopes->minmax[a][0] = 25500.0f;
- scopes->minmax[a][1] = -25500.0f;
- }
-
- scopes->waveform_tot = ibuf->x * scopes->sample_lines;
-
- if (scopes->waveform_1)
- MEM_freeN(scopes->waveform_1);
- if (scopes->waveform_2)
- MEM_freeN(scopes->waveform_2);
- if (scopes->waveform_3)
- MEM_freeN(scopes->waveform_3);
- if (scopes->vecscope)
- MEM_freeN(scopes->vecscope);
-
- scopes->waveform_1 = MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "waveform point channel 1");
- scopes->waveform_2 = MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "waveform point channel 2");
- scopes->waveform_3 = MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "waveform point channel 3");
- scopes->vecscope = MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "vectorscope point channel");
-
- if (ibuf->rect_float) {
- cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
- }
- else {
- display_buffer = (const unsigned char *)IMB_display_buffer_acquire(
- ibuf, view_settings, display_settings, &cache_handle);
- }
-
- /* Keep number of threads in sync with the merge parts below. */
- ScopesUpdateData data = {
- .scopes = scopes, .ibuf = ibuf,
- .cm_processor = cm_processor, .display_buffer = display_buffer, .ycc_mode = ycc_mode,
- .bin_lum = bin_lum, .bin_r = bin_r, .bin_g = bin_g, .bin_b = bin_b, .bin_a = bin_a,
- };
- ScopesUpdateDataChunk data_chunk = {{0}};
- INIT_MINMAX(data_chunk.min, data_chunk.max);
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (ibuf->y > 256);
- settings.userdata_chunk = &data_chunk;
- settings.userdata_chunk_size = sizeof(data_chunk);
- settings.func_finalize = scopes_update_finalize;
- BLI_task_parallel_range(0, ibuf->y,
- &data,
- scopes_update_cb,
- &settings);
-
- /* convert hist data to float (proportional to max count) */
- nl = na = nr = nb = ng = 0;
- for (a = 0; a < 256; a++) {
- if (bin_lum[a] > nl) nl = bin_lum[a];
- if (bin_r[a] > nr) nr = bin_r[a];
- if (bin_g[a] > ng) ng = bin_g[a];
- if (bin_b[a] > nb) nb = bin_b[a];
- if (bin_a[a] > na) na = bin_a[a];
- }
- divl = nl ? 1.0 / (double)nl : 1.0;
- diva = na ? 1.0 / (double)na : 1.0;
- divr = nr ? 1.0 / (double)nr : 1.0;
- divg = ng ? 1.0 / (double)ng : 1.0;
- divb = nb ? 1.0 / (double)nb : 1.0;
-
- for (a = 0; a < 256; a++) {
- scopes->hist.data_luma[a] = bin_lum[a] * divl;
- scopes->hist.data_r[a] = bin_r[a] * divr;
- scopes->hist.data_g[a] = bin_g[a] * divg;
- scopes->hist.data_b[a] = bin_b[a] * divb;
- scopes->hist.data_a[a] = bin_a[a] * diva;
- }
-
- if (cm_processor)
- IMB_colormanagement_processor_free(cm_processor);
- if (cache_handle)
- IMB_display_buffer_release(cache_handle);
-
- scopes->ok = 1;
+ int a;
+ unsigned int nl, na, nr, ng, nb;
+ double divl, diva, divr, divg, divb;
+ const unsigned char *display_buffer = NULL;
+ unsigned int bin_lum[256] = {0}, bin_r[256] = {0}, bin_g[256] = {0}, bin_b[256] = {0},
+ bin_a[256] = {0};
+ int ycc_mode = -1;
+ void *cache_handle = NULL;
+ struct ColormanageProcessor *cm_processor = NULL;
+
+ if (ibuf->rect == NULL && ibuf->rect_float == NULL)
+ return;
+
+ if (scopes->ok == 1)
+ return;
+
+ if (scopes->hist.ymax == 0.f)
+ scopes->hist.ymax = 1.f;
+
+ /* hmmmm */
+ if (!(ELEM(ibuf->channels, 3, 4)))
+ return;
+
+ scopes->hist.channels = 3;
+ scopes->hist.x_resolution = 256;
+
+ switch (scopes->wavefrm_mode) {
+ case SCOPES_WAVEFRM_RGB:
+ /* fall-through */
+ case SCOPES_WAVEFRM_RGB_PARADE:
+ ycc_mode = -1;
+ break;
+ case SCOPES_WAVEFRM_LUMA:
+ case SCOPES_WAVEFRM_YCC_JPEG:
+ ycc_mode = BLI_YCC_JFIF_0_255;
+ break;
+ case SCOPES_WAVEFRM_YCC_601:
+ ycc_mode = BLI_YCC_ITU_BT601;
+ break;
+ case SCOPES_WAVEFRM_YCC_709:
+ ycc_mode = BLI_YCC_ITU_BT709;
+ break;
+ }
+
+ /* convert to number of lines with logarithmic scale */
+ scopes->sample_lines = (scopes->accuracy * 0.01f) * (scopes->accuracy * 0.01f) * ibuf->y;
+ CLAMP_MIN(scopes->sample_lines, 1);
+
+ if (scopes->sample_full)
+ scopes->sample_lines = ibuf->y;
+
+ /* scan the image */
+ for (a = 0; a < 3; a++) {
+ scopes->minmax[a][0] = 25500.0f;
+ scopes->minmax[a][1] = -25500.0f;
+ }
+
+ scopes->waveform_tot = ibuf->x * scopes->sample_lines;
+
+ if (scopes->waveform_1)
+ MEM_freeN(scopes->waveform_1);
+ if (scopes->waveform_2)
+ MEM_freeN(scopes->waveform_2);
+ if (scopes->waveform_3)
+ MEM_freeN(scopes->waveform_3);
+ if (scopes->vecscope)
+ MEM_freeN(scopes->vecscope);
+
+ scopes->waveform_1 = MEM_callocN(scopes->waveform_tot * 2 * sizeof(float),
+ "waveform point channel 1");
+ scopes->waveform_2 = MEM_callocN(scopes->waveform_tot * 2 * sizeof(float),
+ "waveform point channel 2");
+ scopes->waveform_3 = MEM_callocN(scopes->waveform_tot * 2 * sizeof(float),
+ "waveform point channel 3");
+ scopes->vecscope = MEM_callocN(scopes->waveform_tot * 2 * sizeof(float),
+ "vectorscope point channel");
+
+ if (ibuf->rect_float) {
+ cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
+ }
+ else {
+ display_buffer = (const unsigned char *)IMB_display_buffer_acquire(
+ ibuf, view_settings, display_settings, &cache_handle);
+ }
+
+ /* Keep number of threads in sync with the merge parts below. */
+ ScopesUpdateData data = {
+ .scopes = scopes,
+ .ibuf = ibuf,
+ .cm_processor = cm_processor,
+ .display_buffer = display_buffer,
+ .ycc_mode = ycc_mode,
+ .bin_lum = bin_lum,
+ .bin_r = bin_r,
+ .bin_g = bin_g,
+ .bin_b = bin_b,
+ .bin_a = bin_a,
+ };
+ ScopesUpdateDataChunk data_chunk = {{0}};
+ INIT_MINMAX(data_chunk.min, data_chunk.max);
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (ibuf->y > 256);
+ settings.userdata_chunk = &data_chunk;
+ settings.userdata_chunk_size = sizeof(data_chunk);
+ settings.func_finalize = scopes_update_finalize;
+ BLI_task_parallel_range(0, ibuf->y, &data, scopes_update_cb, &settings);
+
+ /* convert hist data to float (proportional to max count) */
+ nl = na = nr = nb = ng = 0;
+ for (a = 0; a < 256; a++) {
+ if (bin_lum[a] > nl)
+ nl = bin_lum[a];
+ if (bin_r[a] > nr)
+ nr = bin_r[a];
+ if (bin_g[a] > ng)
+ ng = bin_g[a];
+ if (bin_b[a] > nb)
+ nb = bin_b[a];
+ if (bin_a[a] > na)
+ na = bin_a[a];
+ }
+ divl = nl ? 1.0 / (double)nl : 1.0;
+ diva = na ? 1.0 / (double)na : 1.0;
+ divr = nr ? 1.0 / (double)nr : 1.0;
+ divg = ng ? 1.0 / (double)ng : 1.0;
+ divb = nb ? 1.0 / (double)nb : 1.0;
+
+ for (a = 0; a < 256; a++) {
+ scopes->hist.data_luma[a] = bin_lum[a] * divl;
+ scopes->hist.data_r[a] = bin_r[a] * divr;
+ scopes->hist.data_g[a] = bin_g[a] * divg;
+ scopes->hist.data_b[a] = bin_b[a] * divb;
+ scopes->hist.data_a[a] = bin_a[a] * diva;
+ }
+
+ if (cm_processor)
+ IMB_colormanagement_processor_free(cm_processor);
+ if (cache_handle)
+ IMB_display_buffer_release(cache_handle);
+
+ scopes->ok = 1;
}
void scopes_free(Scopes *scopes)
{
- if (scopes->waveform_1) {
- MEM_freeN(scopes->waveform_1);
- scopes->waveform_1 = NULL;
- }
- if (scopes->waveform_2) {
- MEM_freeN(scopes->waveform_2);
- scopes->waveform_2 = NULL;
- }
- if (scopes->waveform_3) {
- MEM_freeN(scopes->waveform_3);
- scopes->waveform_3 = NULL;
- }
- if (scopes->vecscope) {
- MEM_freeN(scopes->vecscope);
- scopes->vecscope = NULL;
- }
+ if (scopes->waveform_1) {
+ MEM_freeN(scopes->waveform_1);
+ scopes->waveform_1 = NULL;
+ }
+ if (scopes->waveform_2) {
+ MEM_freeN(scopes->waveform_2);
+ scopes->waveform_2 = NULL;
+ }
+ if (scopes->waveform_3) {
+ MEM_freeN(scopes->waveform_3);
+ scopes->waveform_3 = NULL;
+ }
+ if (scopes->vecscope) {
+ MEM_freeN(scopes->vecscope);
+ scopes->vecscope = NULL;
+ }
}
void scopes_new(Scopes *scopes)
{
- scopes->accuracy = 30.0;
- scopes->hist.mode = HISTO_MODE_RGB;
- scopes->wavefrm_alpha = 0.3;
- scopes->vecscope_alpha = 0.3;
- scopes->wavefrm_height = 100;
- scopes->vecscope_height = 100;
- scopes->hist.height = 100;
- scopes->ok = 0;
- scopes->waveform_1 = NULL;
- scopes->waveform_2 = NULL;
- scopes->waveform_3 = NULL;
- scopes->vecscope = NULL;
+ scopes->accuracy = 30.0;
+ scopes->hist.mode = HISTO_MODE_RGB;
+ scopes->wavefrm_alpha = 0.3;
+ scopes->vecscope_alpha = 0.3;
+ scopes->wavefrm_height = 100;
+ scopes->vecscope_height = 100;
+ scopes->hist.height = 100;
+ scopes->ok = 0;
+ scopes->waveform_1 = NULL;
+ scopes->waveform_2 = NULL;
+ scopes->waveform_3 = NULL;
+ scopes->vecscope = NULL;
}
void BKE_color_managed_display_settings_init(ColorManagedDisplaySettings *settings)
{
- const char *display_name = IMB_colormanagement_display_get_default_name();
+ const char *display_name = IMB_colormanagement_display_get_default_name();
- BLI_strncpy(settings->display_device, display_name, sizeof(settings->display_device));
+ BLI_strncpy(settings->display_device, display_name, sizeof(settings->display_device));
}
void BKE_color_managed_display_settings_copy(ColorManagedDisplaySettings *new_settings,
const ColorManagedDisplaySettings *settings)
{
- BLI_strncpy(new_settings->display_device, settings->display_device, sizeof(new_settings->display_device));
+ BLI_strncpy(new_settings->display_device,
+ settings->display_device,
+ sizeof(new_settings->display_device));
}
void BKE_color_managed_view_settings_init_render(
- ColorManagedViewSettings *view_settings,
- const ColorManagedDisplaySettings *display_settings,
- const char *view_transform)
+ ColorManagedViewSettings *view_settings,
+ const ColorManagedDisplaySettings *display_settings,
+ const char *view_transform)
{
- struct ColorManagedDisplay *display =
- IMB_colormanagement_display_get_named(
- display_settings->display_device);
+ struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(
+ display_settings->display_device);
- if (!view_transform) {
- view_transform = IMB_colormanagement_display_get_default_view_transform_name(display);
- }
+ if (!view_transform) {
+ view_transform = IMB_colormanagement_display_get_default_view_transform_name(display);
+ }
- /* TODO(sergey): Find a way to make look query more reliable with non
- * default configuration. */
- STRNCPY(view_settings->view_transform, view_transform);
- STRNCPY(view_settings->look, "None");
+ /* TODO(sergey): Find a way to make look query more reliable with non
+ * default configuration. */
+ STRNCPY(view_settings->view_transform, view_transform);
+ STRNCPY(view_settings->look, "None");
- view_settings->flag = 0;
- view_settings->gamma = 1.0f;
- view_settings->exposure = 0.0f;
- view_settings->curve_mapping = NULL;
+ view_settings->flag = 0;
+ view_settings->gamma = 1.0f;
+ view_settings->exposure = 0.0f;
+ view_settings->curve_mapping = NULL;
- IMB_colormanagement_validate_settings(display_settings, view_settings);
+ IMB_colormanagement_validate_settings(display_settings, view_settings);
}
void BKE_color_managed_view_settings_init_default(
- struct ColorManagedViewSettings *view_settings,
- const struct ColorManagedDisplaySettings *display_settings)
+ struct ColorManagedViewSettings *view_settings,
+ const struct ColorManagedDisplaySettings *display_settings)
{
- IMB_colormanagement_init_default_view_settings(
- view_settings, display_settings);
+ IMB_colormanagement_init_default_view_settings(view_settings, display_settings);
}
void BKE_color_managed_view_settings_copy(ColorManagedViewSettings *new_settings,
const ColorManagedViewSettings *settings)
{
- BLI_strncpy(new_settings->look, settings->look, sizeof(new_settings->look));
- BLI_strncpy(new_settings->view_transform, settings->view_transform, sizeof(new_settings->view_transform));
-
- new_settings->flag = settings->flag;
- new_settings->exposure = settings->exposure;
- new_settings->gamma = settings->gamma;
-
- if (settings->curve_mapping)
- new_settings->curve_mapping = curvemapping_copy(settings->curve_mapping);
- else
- new_settings->curve_mapping = NULL;
+ BLI_strncpy(new_settings->look, settings->look, sizeof(new_settings->look));
+ BLI_strncpy(new_settings->view_transform,
+ settings->view_transform,
+ sizeof(new_settings->view_transform));
+
+ new_settings->flag = settings->flag;
+ new_settings->exposure = settings->exposure;
+ new_settings->gamma = settings->gamma;
+
+ if (settings->curve_mapping)
+ new_settings->curve_mapping = curvemapping_copy(settings->curve_mapping);
+ else
+ new_settings->curve_mapping = NULL;
}
void BKE_color_managed_view_settings_free(ColorManagedViewSettings *settings)
{
- if (settings->curve_mapping)
- curvemapping_free(settings->curve_mapping);
+ if (settings->curve_mapping)
+ curvemapping_free(settings->curve_mapping);
}
-void BKE_color_managed_colorspace_settings_init(ColorManagedColorspaceSettings *colorspace_settings)
+void BKE_color_managed_colorspace_settings_init(
+ ColorManagedColorspaceSettings *colorspace_settings)
{
- BLI_strncpy(colorspace_settings->name, "", sizeof(colorspace_settings->name));
+ BLI_strncpy(colorspace_settings->name, "", sizeof(colorspace_settings->name));
}
-void BKE_color_managed_colorspace_settings_copy(ColorManagedColorspaceSettings *colorspace_settings,
- const ColorManagedColorspaceSettings *settings)
+void BKE_color_managed_colorspace_settings_copy(
+ ColorManagedColorspaceSettings *colorspace_settings,
+ const ColorManagedColorspaceSettings *settings)
{
- BLI_strncpy(colorspace_settings->name, settings->name, sizeof(colorspace_settings->name));
+ BLI_strncpy(colorspace_settings->name, settings->name, sizeof(colorspace_settings->name));
}
bool BKE_color_managed_colorspace_settings_equals(const ColorManagedColorspaceSettings *settings1,
const ColorManagedColorspaceSettings *settings2)
{
- return STREQ(settings1->name, settings2->name);
+ return STREQ(settings1->name, settings2->name);
}
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index 1ba29424def..114bf5ec1e6 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -21,7 +21,6 @@
* \ingroup bke
*/
-
#include <stdio.h>
#include <stddef.h>
#include <string.h>
@@ -52,7 +51,6 @@
#include "DNA_tracking_types.h"
#include "DNA_movieclip_types.h"
-
#include "BKE_action.h"
#include "BKE_anim.h" /* for the curve calculation part */
#include "BKE_armature.h"
@@ -105,7 +103,10 @@ static CLG_LogRef LOG = {"bke.constraint"};
static void damptrack_do_transform(float matrix[4][4], const float tarvec[3], int track_axis);
-static bConstraint *constraint_find_original(Object *ob, bPoseChannel *pchan, bConstraint *con, Object **r_orig_ob);
+static bConstraint *constraint_find_original(Object *ob,
+ bPoseChannel *pchan,
+ bConstraint *con,
+ Object **r_orig_ob);
static bConstraint *constraint_find_original_for_update(bConstraintOb *cob, bConstraint *con);
/* -------------- Naming -------------- */
@@ -113,136 +114,133 @@ static bConstraint *constraint_find_original_for_update(bConstraintOb *cob, bCon
/* Find the first available, non-duplicate name for a given constraint */
void BKE_constraint_unique_name(bConstraint *con, ListBase *list)
{
- BLI_uniquename(list, con, DATA_("Const"), '.', offsetof(bConstraint, name), sizeof(con->name));
+ BLI_uniquename(list, con, DATA_("Const"), '.', offsetof(bConstraint, name), sizeof(con->name));
}
/* ----------------- Evaluation Loop Preparation --------------- */
/* package an object/bone for use in constraint evaluation */
/* This function MEM_calloc's a bConstraintOb struct, that will need to be freed after evaluation */
-bConstraintOb *BKE_constraints_make_evalob(Depsgraph *depsgraph, Scene *scene, Object *ob, void *subdata, short datatype)
-{
- bConstraintOb *cob;
-
- /* create regardless of whether we have any data! */
- cob = MEM_callocN(sizeof(bConstraintOb), "bConstraintOb");
-
- /* for system time, part of deglobalization, code nicer later with local time (ton) */
- cob->scene = scene;
- cob->depsgraph = depsgraph;
-
- /* based on type of available data */
- switch (datatype) {
- case CONSTRAINT_OBTYPE_OBJECT:
- {
- /* disregard subdata... calloc should set other values right */
- if (ob) {
- cob->ob = ob;
- cob->type = datatype;
-
- if (cob->ob->rotmode > 0) {
- /* Should be some kind of Euler order, so use it */
- /* NOTE: Versions <= 2.76 assumed that "default" order
- * would always get used, so we may seem some rig
- * breakage as a result. However, this change here
- * is needed to fix T46599
- */
- cob->rotOrder = ob->rotmode;
- }
- else {
- /* Quats/Axis-Angle, so Eulers should just use default order */
- cob->rotOrder = EULER_ORDER_DEFAULT;
- }
- copy_m4_m4(cob->matrix, ob->obmat);
- }
- else
- unit_m4(cob->matrix);
-
- copy_m4_m4(cob->startmat, cob->matrix);
- break;
- }
- case CONSTRAINT_OBTYPE_BONE:
- {
- /* only set if we have valid bone, otherwise default */
- if (ob && subdata) {
- cob->ob = ob;
- cob->pchan = (bPoseChannel *)subdata;
- cob->type = datatype;
-
- if (cob->pchan->rotmode > 0) {
- /* should be some type of Euler order */
- cob->rotOrder = cob->pchan->rotmode;
- }
- else {
- /* Quats, so eulers should just use default order */
- cob->rotOrder = EULER_ORDER_DEFAULT;
- }
-
- /* matrix in world-space */
- mul_m4_m4m4(cob->matrix, ob->obmat, cob->pchan->pose_mat);
- }
- else
- unit_m4(cob->matrix);
-
- copy_m4_m4(cob->startmat, cob->matrix);
- break;
- }
- default: /* other types not yet handled */
- unit_m4(cob->matrix);
- unit_m4(cob->startmat);
- break;
- }
-
- return cob;
+bConstraintOb *BKE_constraints_make_evalob(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, void *subdata, short datatype)
+{
+ bConstraintOb *cob;
+
+ /* create regardless of whether we have any data! */
+ cob = MEM_callocN(sizeof(bConstraintOb), "bConstraintOb");
+
+ /* for system time, part of deglobalization, code nicer later with local time (ton) */
+ cob->scene = scene;
+ cob->depsgraph = depsgraph;
+
+ /* based on type of available data */
+ switch (datatype) {
+ case CONSTRAINT_OBTYPE_OBJECT: {
+ /* disregard subdata... calloc should set other values right */
+ if (ob) {
+ cob->ob = ob;
+ cob->type = datatype;
+
+ if (cob->ob->rotmode > 0) {
+ /* Should be some kind of Euler order, so use it */
+ /* NOTE: Versions <= 2.76 assumed that "default" order
+ * would always get used, so we may seem some rig
+ * breakage as a result. However, this change here
+ * is needed to fix T46599
+ */
+ cob->rotOrder = ob->rotmode;
+ }
+ else {
+ /* Quats/Axis-Angle, so Eulers should just use default order */
+ cob->rotOrder = EULER_ORDER_DEFAULT;
+ }
+ copy_m4_m4(cob->matrix, ob->obmat);
+ }
+ else
+ unit_m4(cob->matrix);
+
+ copy_m4_m4(cob->startmat, cob->matrix);
+ break;
+ }
+ case CONSTRAINT_OBTYPE_BONE: {
+ /* only set if we have valid bone, otherwise default */
+ if (ob && subdata) {
+ cob->ob = ob;
+ cob->pchan = (bPoseChannel *)subdata;
+ cob->type = datatype;
+
+ if (cob->pchan->rotmode > 0) {
+ /* should be some type of Euler order */
+ cob->rotOrder = cob->pchan->rotmode;
+ }
+ else {
+ /* Quats, so eulers should just use default order */
+ cob->rotOrder = EULER_ORDER_DEFAULT;
+ }
+
+ /* matrix in world-space */
+ mul_m4_m4m4(cob->matrix, ob->obmat, cob->pchan->pose_mat);
+ }
+ else
+ unit_m4(cob->matrix);
+
+ copy_m4_m4(cob->startmat, cob->matrix);
+ break;
+ }
+ default: /* other types not yet handled */
+ unit_m4(cob->matrix);
+ unit_m4(cob->startmat);
+ break;
+ }
+
+ return cob;
}
/* cleanup after constraint evaluation */
void BKE_constraints_clear_evalob(bConstraintOb *cob)
{
- float delta[4][4], imat[4][4];
-
- /* prevent crashes */
- if (cob == NULL)
- return;
-
- /* calculate delta of constraints evaluation */
- invert_m4_m4(imat, cob->startmat);
- /* XXX This would seem to be in wrong order. However, it does not work in 'right' order - would be nice to
- * understand why premul is needed here instead of usual postmul?
- * In any case, we **do not get a delta** here (e.g. startmat & matrix having same location, still gives
- * a 'delta' with non-null translation component :/ ).*/
- mul_m4_m4m4(delta, cob->matrix, imat);
-
- /* copy matrices back to source */
- switch (cob->type) {
- case CONSTRAINT_OBTYPE_OBJECT:
- {
- /* cob->ob might not exist! */
- if (cob->ob) {
- /* copy new ob-matrix back to owner */
- copy_m4_m4(cob->ob->obmat, cob->matrix);
-
- /* copy inverse of delta back to owner */
- invert_m4_m4(cob->ob->constinv, delta);
- }
- break;
- }
- case CONSTRAINT_OBTYPE_BONE:
- {
- /* cob->ob or cob->pchan might not exist */
- if (cob->ob && cob->pchan) {
- /* copy new pose-matrix back to owner */
- mul_m4_m4m4(cob->pchan->pose_mat, cob->ob->imat, cob->matrix);
-
- /* copy inverse of delta back to owner */
- invert_m4_m4(cob->pchan->constinv, delta);
- }
- break;
- }
- }
-
- /* free tempolary struct */
- MEM_freeN(cob);
+ float delta[4][4], imat[4][4];
+
+ /* prevent crashes */
+ if (cob == NULL)
+ return;
+
+ /* calculate delta of constraints evaluation */
+ invert_m4_m4(imat, cob->startmat);
+ /* XXX This would seem to be in wrong order. However, it does not work in 'right' order - would be nice to
+ * understand why premul is needed here instead of usual postmul?
+ * In any case, we **do not get a delta** here (e.g. startmat & matrix having same location, still gives
+ * a 'delta' with non-null translation component :/ ).*/
+ mul_m4_m4m4(delta, cob->matrix, imat);
+
+ /* copy matrices back to source */
+ switch (cob->type) {
+ case CONSTRAINT_OBTYPE_OBJECT: {
+ /* cob->ob might not exist! */
+ if (cob->ob) {
+ /* copy new ob-matrix back to owner */
+ copy_m4_m4(cob->ob->obmat, cob->matrix);
+
+ /* copy inverse of delta back to owner */
+ invert_m4_m4(cob->ob->constinv, delta);
+ }
+ break;
+ }
+ case CONSTRAINT_OBTYPE_BONE: {
+ /* cob->ob or cob->pchan might not exist */
+ if (cob->ob && cob->pchan) {
+ /* copy new pose-matrix back to owner */
+ mul_m4_m4m4(cob->pchan->pose_mat, cob->ob->imat, cob->matrix);
+
+ /* copy inverse of delta back to owner */
+ invert_m4_m4(cob->pchan->constinv, delta);
+ }
+ break;
+ }
+ }
+
+ /* free tempolary struct */
+ MEM_freeN(cob);
}
/* -------------- Space-Conversion API -------------- */
@@ -252,138 +250,140 @@ void BKE_constraints_clear_evalob(bConstraintOb *cob)
* For now, this is only implemented for Objects and PoseChannels.
*/
void BKE_constraint_mat_convertspace(
- Object *ob, bPoseChannel *pchan, float mat[4][4], short from, short to, const bool keep_scale)
-{
- float diff_mat[4][4];
- float imat[4][4];
-
- /* prevent crashes in these unlikely events */
- if (ob == NULL || mat == NULL) return;
- /* optimize trick - check if need to do anything */
- if (from == to) return;
-
- /* are we dealing with pose-channels or objects */
- if (pchan) {
- /* pose channels */
- switch (from) {
- case CONSTRAINT_SPACE_WORLD: /* ---------- FROM WORLDSPACE ---------- */
- {
- /* world to pose */
- invert_m4_m4(imat, ob->obmat);
- mul_m4_m4m4(mat, imat, mat);
-
- /* use pose-space as stepping stone for other spaces... */
- if (ELEM(to, CONSTRAINT_SPACE_LOCAL, CONSTRAINT_SPACE_PARLOCAL)) {
- /* call self with slightly different values */
- BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to, keep_scale);
- }
- break;
- }
- case CONSTRAINT_SPACE_POSE: /* ---------- FROM POSESPACE ---------- */
- {
- /* pose to world */
- if (to == CONSTRAINT_SPACE_WORLD) {
- mul_m4_m4m4(mat, ob->obmat, mat);
- }
- /* pose to local */
- else if (to == CONSTRAINT_SPACE_LOCAL) {
- if (pchan->bone) {
- BKE_armature_mat_pose_to_bone(pchan, mat, mat);
- }
- }
- /* pose to local with parent */
- else if (to == CONSTRAINT_SPACE_PARLOCAL) {
- if (pchan->bone) {
- invert_m4_m4(imat, pchan->bone->arm_mat);
- mul_m4_m4m4(mat, imat, mat);
- }
- }
- break;
- }
- case CONSTRAINT_SPACE_LOCAL: /* ------------ FROM LOCALSPACE --------- */
- {
- /* local to pose - do inverse procedure that was done for pose to local */
- if (pchan->bone) {
- /* we need the posespace_matrix = local_matrix + (parent_posespace_matrix + restpos) */
- BKE_armature_mat_bone_to_pose(pchan, mat, mat);
- }
-
- /* use pose-space as stepping stone for other spaces */
- if (ELEM(to, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_PARLOCAL)) {
- /* call self with slightly different values */
- BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to, keep_scale);
- }
- break;
- }
- case CONSTRAINT_SPACE_PARLOCAL: /* -------------- FROM LOCAL WITH PARENT ---------- */
- {
- /* local + parent to pose */
- if (pchan->bone) {
- mul_m4_m4m4(mat, pchan->bone->arm_mat, mat);
- }
-
- /* use pose-space as stepping stone for other spaces */
- if (ELEM(to, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL)) {
- /* call self with slightly different values */
- BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to, keep_scale);
- }
- break;
- }
- }
- }
- else {
- /* objects */
- if (from == CONSTRAINT_SPACE_WORLD && to == CONSTRAINT_SPACE_LOCAL) {
- /* check if object has a parent */
- if (ob->parent) {
- /* 'subtract' parent's effects from owner */
- mul_m4_m4m4(diff_mat, ob->parent->obmat, ob->parentinv);
- invert_m4_m4_safe(imat, diff_mat);
- mul_m4_m4m4(mat, imat, mat);
- }
- else {
- /* Local space in this case will have to be defined as local to the owner's
- * transform-property-rotated axes. So subtract this rotation component.
- */
- /* XXX This is actually an ugly hack, local space of a parent-less object *is* the same as
- * global space!
- * Think what we want actually here is some kind of 'Final Space', i.e. once transformations
- * are applied - users are often confused about this too, this is not consistent with bones
- * local space either... Meh :|
- * --mont29
- */
- BKE_object_to_mat4(ob, diff_mat);
- if (!keep_scale) {
- normalize_m4(diff_mat);
- }
- zero_v3(diff_mat[3]);
-
- invert_m4_m4_safe(imat, diff_mat);
- mul_m4_m4m4(mat, imat, mat);
- }
- }
- else if (from == CONSTRAINT_SPACE_LOCAL && to == CONSTRAINT_SPACE_WORLD) {
- /* check that object has a parent - otherwise this won't work */
- if (ob->parent) {
- /* 'add' parent's effect back to owner */
- mul_m4_m4m4(diff_mat, ob->parent->obmat, ob->parentinv);
- mul_m4_m4m4(mat, diff_mat, mat);
- }
- else {
- /* Local space in this case will have to be defined as local to the owner's
- * transform-property-rotated axes. So add back this rotation component.
- */
- /* XXX See comment above for world->local case... */
- BKE_object_to_mat4(ob, diff_mat);
- if (!keep_scale) {
- normalize_m4(diff_mat);
- }
- zero_v3(diff_mat[3]);
-
- mul_m4_m4m4(mat, diff_mat, mat);
- }
- }
- }
+ Object *ob, bPoseChannel *pchan, float mat[4][4], short from, short to, const bool keep_scale)
+{
+ float diff_mat[4][4];
+ float imat[4][4];
+
+ /* prevent crashes in these unlikely events */
+ if (ob == NULL || mat == NULL)
+ return;
+ /* optimize trick - check if need to do anything */
+ if (from == to)
+ return;
+
+ /* are we dealing with pose-channels or objects */
+ if (pchan) {
+ /* pose channels */
+ switch (from) {
+ case CONSTRAINT_SPACE_WORLD: /* ---------- FROM WORLDSPACE ---------- */
+ {
+ /* world to pose */
+ invert_m4_m4(imat, ob->obmat);
+ mul_m4_m4m4(mat, imat, mat);
+
+ /* use pose-space as stepping stone for other spaces... */
+ if (ELEM(to, CONSTRAINT_SPACE_LOCAL, CONSTRAINT_SPACE_PARLOCAL)) {
+ /* call self with slightly different values */
+ BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to, keep_scale);
+ }
+ break;
+ }
+ case CONSTRAINT_SPACE_POSE: /* ---------- FROM POSESPACE ---------- */
+ {
+ /* pose to world */
+ if (to == CONSTRAINT_SPACE_WORLD) {
+ mul_m4_m4m4(mat, ob->obmat, mat);
+ }
+ /* pose to local */
+ else if (to == CONSTRAINT_SPACE_LOCAL) {
+ if (pchan->bone) {
+ BKE_armature_mat_pose_to_bone(pchan, mat, mat);
+ }
+ }
+ /* pose to local with parent */
+ else if (to == CONSTRAINT_SPACE_PARLOCAL) {
+ if (pchan->bone) {
+ invert_m4_m4(imat, pchan->bone->arm_mat);
+ mul_m4_m4m4(mat, imat, mat);
+ }
+ }
+ break;
+ }
+ case CONSTRAINT_SPACE_LOCAL: /* ------------ FROM LOCALSPACE --------- */
+ {
+ /* local to pose - do inverse procedure that was done for pose to local */
+ if (pchan->bone) {
+ /* we need the posespace_matrix = local_matrix + (parent_posespace_matrix + restpos) */
+ BKE_armature_mat_bone_to_pose(pchan, mat, mat);
+ }
+
+ /* use pose-space as stepping stone for other spaces */
+ if (ELEM(to, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_PARLOCAL)) {
+ /* call self with slightly different values */
+ BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to, keep_scale);
+ }
+ break;
+ }
+ case CONSTRAINT_SPACE_PARLOCAL: /* -------------- FROM LOCAL WITH PARENT ---------- */
+ {
+ /* local + parent to pose */
+ if (pchan->bone) {
+ mul_m4_m4m4(mat, pchan->bone->arm_mat, mat);
+ }
+
+ /* use pose-space as stepping stone for other spaces */
+ if (ELEM(to, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL)) {
+ /* call self with slightly different values */
+ BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to, keep_scale);
+ }
+ break;
+ }
+ }
+ }
+ else {
+ /* objects */
+ if (from == CONSTRAINT_SPACE_WORLD && to == CONSTRAINT_SPACE_LOCAL) {
+ /* check if object has a parent */
+ if (ob->parent) {
+ /* 'subtract' parent's effects from owner */
+ mul_m4_m4m4(diff_mat, ob->parent->obmat, ob->parentinv);
+ invert_m4_m4_safe(imat, diff_mat);
+ mul_m4_m4m4(mat, imat, mat);
+ }
+ else {
+ /* Local space in this case will have to be defined as local to the owner's
+ * transform-property-rotated axes. So subtract this rotation component.
+ */
+ /* XXX This is actually an ugly hack, local space of a parent-less object *is* the same as
+ * global space!
+ * Think what we want actually here is some kind of 'Final Space', i.e. once transformations
+ * are applied - users are often confused about this too, this is not consistent with bones
+ * local space either... Meh :|
+ * --mont29
+ */
+ BKE_object_to_mat4(ob, diff_mat);
+ if (!keep_scale) {
+ normalize_m4(diff_mat);
+ }
+ zero_v3(diff_mat[3]);
+
+ invert_m4_m4_safe(imat, diff_mat);
+ mul_m4_m4m4(mat, imat, mat);
+ }
+ }
+ else if (from == CONSTRAINT_SPACE_LOCAL && to == CONSTRAINT_SPACE_WORLD) {
+ /* check that object has a parent - otherwise this won't work */
+ if (ob->parent) {
+ /* 'add' parent's effect back to owner */
+ mul_m4_m4m4(diff_mat, ob->parent->obmat, ob->parentinv);
+ mul_m4_m4m4(mat, diff_mat, mat);
+ }
+ else {
+ /* Local space in this case will have to be defined as local to the owner's
+ * transform-property-rotated axes. So add back this rotation component.
+ */
+ /* XXX See comment above for world->local case... */
+ BKE_object_to_mat4(ob, diff_mat);
+ if (!keep_scale) {
+ normalize_m4(diff_mat);
+ }
+ zero_v3(diff_mat[3]);
+
+ mul_m4_m4m4(mat, diff_mat, mat);
+ }
+ }
+ }
}
/* ------------ General Target Matrix Tools ---------- */
@@ -391,246 +391,259 @@ void BKE_constraint_mat_convertspace(
/* function that sets the given matrix based on given vertex group in mesh */
static void contarget_get_mesh_mat(Object *ob, const char *substring, float mat[4][4])
{
- /* when not in EditMode, use the 'final' evaluated mesh, depsgraph
- * ensures we build with CD_MDEFORMVERT layer
- */
- Mesh *me_eval = ob->runtime.mesh_eval;
- BMEditMesh *em = BKE_editmesh_from_object(ob);
- float plane[3];
- float imat[3][3], tmat[3][3];
- const int defgroup = defgroup_name_index(ob, substring);
-
- /* initialize target matrix using target matrix */
- copy_m4_m4(mat, ob->obmat);
-
- /* get index of vertex group */
- if (defgroup == -1) {
- return;
- }
-
- float vec[3] = {0.0f, 0.0f, 0.0f};
- float normal[3] = {0.0f, 0.0f, 0.0f};
- float weightsum = 0.0f;
- if (me_eval) {
- MDeformVert *dvert = CustomData_get_layer(&me_eval->vdata, CD_MDEFORMVERT);
- int numVerts = me_eval->totvert;
-
- /* check that dvert is a valid pointers (just in case) */
- if (dvert) {
- MDeformVert *dv = dvert;
- MVert *mv = me_eval->mvert;
-
- /* get the average of all verts with that are in the vertex-group */
- for (int i = 0; i < numVerts; i++, dv++, mv++) {
- MDeformWeight *dw = defvert_find_index(dv, defgroup);
-
- if (dw && dw->weight > 0.0f) {
- float nor[3];
- normal_short_to_float_v3(nor, mv->no);
- madd_v3_v3fl(vec, mv->co, dw->weight);
- madd_v3_v3fl(normal, nor, dw->weight);
- weightsum += dw->weight;
- }
- }
- }
- }
- else if (em) {
- if (CustomData_has_layer(&em->bm->vdata, CD_MDEFORMVERT)) {
- BMVert *v;
- BMIter iter;
-
- BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
- MDeformVert *dv = CustomData_bmesh_get(&em->bm->vdata, v->head.data, CD_MDEFORMVERT);
- MDeformWeight *dw = defvert_find_index(dv, defgroup);
-
- if (dw && dw->weight > 0.0f) {
- madd_v3_v3fl(vec, v->co, dw->weight);
- madd_v3_v3fl(normal, v->no, dw->weight);
- weightsum += dw->weight;
- }
- }
- }
- }
- else {
- /* No valid edit or evaluated mesh, just abort. */
- return;
- }
-
- /* calculate averages of normal and coordinates */
- if (weightsum > 0) {
- mul_v3_fl(vec, 1.0f / weightsum);
- mul_v3_fl(normal, 1.0f / weightsum);
- }
-
- /* derive the rotation from the average normal:
- * - code taken from transform_gizmo.c,
- * calc_gizmo_stats, V3D_ORIENT_NORMAL case
- */
- /* we need the transpose of the inverse for a normal... */
- copy_m3_m4(imat, ob->obmat);
-
- invert_m3_m3(tmat, imat);
- transpose_m3(tmat);
- mul_m3_v3(tmat, normal);
-
- normalize_v3(normal);
- copy_v3_v3(plane, tmat[1]);
-
- cross_v3_v3v3(mat[0], normal, plane);
- if (len_squared_v3(mat[0]) < SQUARE(1e-3f)) {
- copy_v3_v3(plane, tmat[0]);
- cross_v3_v3v3(mat[0], normal, plane);
- }
-
- copy_v3_v3(mat[2], normal);
- cross_v3_v3v3(mat[1], mat[2], mat[0]);
-
- normalize_m4(mat);
-
- /* apply the average coordinate as the new location */
- mul_v3_m4v3(mat[3], ob->obmat, vec);
+ /* when not in EditMode, use the 'final' evaluated mesh, depsgraph
+ * ensures we build with CD_MDEFORMVERT layer
+ */
+ Mesh *me_eval = ob->runtime.mesh_eval;
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ float plane[3];
+ float imat[3][3], tmat[3][3];
+ const int defgroup = defgroup_name_index(ob, substring);
+
+ /* initialize target matrix using target matrix */
+ copy_m4_m4(mat, ob->obmat);
+
+ /* get index of vertex group */
+ if (defgroup == -1) {
+ return;
+ }
+
+ float vec[3] = {0.0f, 0.0f, 0.0f};
+ float normal[3] = {0.0f, 0.0f, 0.0f};
+ float weightsum = 0.0f;
+ if (me_eval) {
+ MDeformVert *dvert = CustomData_get_layer(&me_eval->vdata, CD_MDEFORMVERT);
+ int numVerts = me_eval->totvert;
+
+ /* check that dvert is a valid pointers (just in case) */
+ if (dvert) {
+ MDeformVert *dv = dvert;
+ MVert *mv = me_eval->mvert;
+
+ /* get the average of all verts with that are in the vertex-group */
+ for (int i = 0; i < numVerts; i++, dv++, mv++) {
+ MDeformWeight *dw = defvert_find_index(dv, defgroup);
+
+ if (dw && dw->weight > 0.0f) {
+ float nor[3];
+ normal_short_to_float_v3(nor, mv->no);
+ madd_v3_v3fl(vec, mv->co, dw->weight);
+ madd_v3_v3fl(normal, nor, dw->weight);
+ weightsum += dw->weight;
+ }
+ }
+ }
+ }
+ else if (em) {
+ if (CustomData_has_layer(&em->bm->vdata, CD_MDEFORMVERT)) {
+ BMVert *v;
+ BMIter iter;
+
+ BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
+ MDeformVert *dv = CustomData_bmesh_get(&em->bm->vdata, v->head.data, CD_MDEFORMVERT);
+ MDeformWeight *dw = defvert_find_index(dv, defgroup);
+
+ if (dw && dw->weight > 0.0f) {
+ madd_v3_v3fl(vec, v->co, dw->weight);
+ madd_v3_v3fl(normal, v->no, dw->weight);
+ weightsum += dw->weight;
+ }
+ }
+ }
+ }
+ else {
+ /* No valid edit or evaluated mesh, just abort. */
+ return;
+ }
+
+ /* calculate averages of normal and coordinates */
+ if (weightsum > 0) {
+ mul_v3_fl(vec, 1.0f / weightsum);
+ mul_v3_fl(normal, 1.0f / weightsum);
+ }
+
+ /* derive the rotation from the average normal:
+ * - code taken from transform_gizmo.c,
+ * calc_gizmo_stats, V3D_ORIENT_NORMAL case
+ */
+ /* we need the transpose of the inverse for a normal... */
+ copy_m3_m4(imat, ob->obmat);
+
+ invert_m3_m3(tmat, imat);
+ transpose_m3(tmat);
+ mul_m3_v3(tmat, normal);
+
+ normalize_v3(normal);
+ copy_v3_v3(plane, tmat[1]);
+
+ cross_v3_v3v3(mat[0], normal, plane);
+ if (len_squared_v3(mat[0]) < SQUARE(1e-3f)) {
+ copy_v3_v3(plane, tmat[0]);
+ cross_v3_v3v3(mat[0], normal, plane);
+ }
+
+ copy_v3_v3(mat[2], normal);
+ cross_v3_v3v3(mat[1], mat[2], mat[0]);
+
+ normalize_m4(mat);
+
+ /* apply the average coordinate as the new location */
+ mul_v3_m4v3(mat[3], ob->obmat, vec);
}
/* function that sets the given matrix based on given vertex group in lattice */
static void contarget_get_lattice_mat(Object *ob, const char *substring, float mat[4][4])
{
- Lattice *lt = (Lattice *)ob->data;
-
- DispList *dl = ob->runtime.curve_cache ? BKE_displist_find(&ob->runtime.curve_cache->disp, DL_VERTS) : NULL;
- const float *co = dl ? dl->verts : NULL;
- BPoint *bp = lt->def;
-
- MDeformVert *dv = lt->dvert;
- int tot_verts = lt->pntsu * lt->pntsv * lt->pntsw;
- float vec[3] = {0.0f, 0.0f, 0.0f}, tvec[3];
- int grouped = 0;
- int i, n;
- const int defgroup = defgroup_name_index(ob, substring);
-
- /* initialize target matrix using target matrix */
- copy_m4_m4(mat, ob->obmat);
-
- /* get index of vertex group */
- if (defgroup == -1) return;
- if (dv == NULL) return;
-
- /* 1. Loop through control-points checking if in nominated vertex-group.
- * 2. If it is, add it to vec to find the average point.
- */
- for (i = 0; i < tot_verts; i++, dv++) {
- for (n = 0; n < dv->totweight; n++) {
- MDeformWeight *dw = defvert_find_index(dv, defgroup);
- if (dw && dw->weight > 0.0f) {
- /* copy coordinates of point to temporary vector, then add to find average */
- memcpy(tvec, co ? co : bp->vec, 3 * sizeof(float));
-
- add_v3_v3(vec, tvec);
- grouped++;
- }
- }
-
- /* advance pointer to coordinate data */
- if (co) co += 3;
- else bp++;
- }
-
- /* find average location, then multiply by ob->obmat to find world-space location */
- if (grouped)
- mul_v3_fl(vec, 1.0f / grouped);
- mul_v3_m4v3(tvec, ob->obmat, vec);
-
- /* copy new location to matrix */
- copy_v3_v3(mat[3], tvec);
+ Lattice *lt = (Lattice *)ob->data;
+
+ DispList *dl = ob->runtime.curve_cache ?
+ BKE_displist_find(&ob->runtime.curve_cache->disp, DL_VERTS) :
+ NULL;
+ const float *co = dl ? dl->verts : NULL;
+ BPoint *bp = lt->def;
+
+ MDeformVert *dv = lt->dvert;
+ int tot_verts = lt->pntsu * lt->pntsv * lt->pntsw;
+ float vec[3] = {0.0f, 0.0f, 0.0f}, tvec[3];
+ int grouped = 0;
+ int i, n;
+ const int defgroup = defgroup_name_index(ob, substring);
+
+ /* initialize target matrix using target matrix */
+ copy_m4_m4(mat, ob->obmat);
+
+ /* get index of vertex group */
+ if (defgroup == -1)
+ return;
+ if (dv == NULL)
+ return;
+
+ /* 1. Loop through control-points checking if in nominated vertex-group.
+ * 2. If it is, add it to vec to find the average point.
+ */
+ for (i = 0; i < tot_verts; i++, dv++) {
+ for (n = 0; n < dv->totweight; n++) {
+ MDeformWeight *dw = defvert_find_index(dv, defgroup);
+ if (dw && dw->weight > 0.0f) {
+ /* copy coordinates of point to temporary vector, then add to find average */
+ memcpy(tvec, co ? co : bp->vec, 3 * sizeof(float));
+
+ add_v3_v3(vec, tvec);
+ grouped++;
+ }
+ }
+
+ /* advance pointer to coordinate data */
+ if (co)
+ co += 3;
+ else
+ bp++;
+ }
+
+ /* find average location, then multiply by ob->obmat to find world-space location */
+ if (grouped)
+ mul_v3_fl(vec, 1.0f / grouped);
+ mul_v3_m4v3(tvec, ob->obmat, vec);
+
+ /* copy new location to matrix */
+ copy_v3_v3(mat[3], tvec);
}
/* generic function to get the appropriate matrix for most target cases */
/* The cases where the target can be object data have not been implemented */
-static void constraint_target_to_mat4(Object *ob, const char *substring, float mat[4][4], short from, short to, short flag, float headtail)
-{
- /* Case OBJECT */
- if (substring[0] == '\0') {
- copy_m4_m4(mat, ob->obmat);
- BKE_constraint_mat_convertspace(ob, NULL, mat, from, to, false);
- }
- /* Case VERTEXGROUP */
- /* Current method just takes the average location of all the points in the
- * VertexGroup, and uses that as the location value of the targets. Where
- * possible, the orientation will also be calculated, by calculating an
- * 'average' vertex normal, and deriving the rotation from that.
- *
- * NOTE: EditMode is not currently supported, and will most likely remain that
- * way as constraints can only really affect things on object/bone level.
- */
- else if (ob->type == OB_MESH) {
- contarget_get_mesh_mat(ob, substring, mat);
- BKE_constraint_mat_convertspace(ob, NULL, mat, from, to, false);
- }
- else if (ob->type == OB_LATTICE) {
- contarget_get_lattice_mat(ob, substring, mat);
- BKE_constraint_mat_convertspace(ob, NULL, mat, from, to, false);
- }
- /* Case BONE */
- else {
- bPoseChannel *pchan;
-
- pchan = BKE_pose_channel_find_name(ob->pose, substring);
- if (pchan) {
- /* Multiply the PoseSpace accumulation/final matrix for this
- * PoseChannel by the Armature Object's Matrix to get a worldspace
- * matrix.
- */
- bool is_bbone = (pchan->bone) && (pchan->bone->segments > 1) && (flag & CONSTRAINT_BBONE_SHAPE);
- bool full_bbone = (flag & CONSTRAINT_BBONE_SHAPE_FULL) != 0;
-
- if (headtail < 0.000001f && !(is_bbone && full_bbone)) {
- /* skip length interpolation if set to head */
- mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat);
- }
- else if (is_bbone && pchan->bone->segments == pchan->runtime.bbone_segments) {
- /* use point along bbone */
- Mat4 *bbone = pchan->runtime.bbone_pose_mats;
- float tempmat[4][4];
- float loc[3], fac;
- int index;
-
- /* figure out which segment(s) the headtail value falls in */
- BKE_pchan_bbone_deform_segment_index(pchan, headtail, &index, &fac);
-
- /* apply full transformation of the segment if requested */
- if (full_bbone) {
- interp_m4_m4m4(tempmat, bbone[index].mat, bbone[index + 1].mat, fac);
-
- mul_m4_m4m4(tempmat, pchan->pose_mat, tempmat);
- }
- /* only interpolate location */
- else {
- interp_v3_v3v3(loc, bbone[index].mat[3], bbone[index + 1].mat[3], fac);
-
- copy_m4_m4(tempmat, pchan->pose_mat);
- mul_v3_m4v3(tempmat[3], pchan->pose_mat, loc);
- }
-
- mul_m4_m4m4(mat, ob->obmat, tempmat);
- }
- else {
- float tempmat[4][4], loc[3];
-
- /* interpolate along length of bone */
- interp_v3_v3v3(loc, pchan->pose_head, pchan->pose_tail, headtail);
-
- /* use interpolated distance for subtarget */
- copy_m4_m4(tempmat, pchan->pose_mat);
- copy_v3_v3(tempmat[3], loc);
-
- mul_m4_m4m4(mat, ob->obmat, tempmat);
- }
- }
- else
- copy_m4_m4(mat, ob->obmat);
-
- /* convert matrix space as required */
- BKE_constraint_mat_convertspace(ob, pchan, mat, from, to, false);
- }
+static void constraint_target_to_mat4(Object *ob,
+ const char *substring,
+ float mat[4][4],
+ short from,
+ short to,
+ short flag,
+ float headtail)
+{
+ /* Case OBJECT */
+ if (substring[0] == '\0') {
+ copy_m4_m4(mat, ob->obmat);
+ BKE_constraint_mat_convertspace(ob, NULL, mat, from, to, false);
+ }
+ /* Case VERTEXGROUP */
+ /* Current method just takes the average location of all the points in the
+ * VertexGroup, and uses that as the location value of the targets. Where
+ * possible, the orientation will also be calculated, by calculating an
+ * 'average' vertex normal, and deriving the rotation from that.
+ *
+ * NOTE: EditMode is not currently supported, and will most likely remain that
+ * way as constraints can only really affect things on object/bone level.
+ */
+ else if (ob->type == OB_MESH) {
+ contarget_get_mesh_mat(ob, substring, mat);
+ BKE_constraint_mat_convertspace(ob, NULL, mat, from, to, false);
+ }
+ else if (ob->type == OB_LATTICE) {
+ contarget_get_lattice_mat(ob, substring, mat);
+ BKE_constraint_mat_convertspace(ob, NULL, mat, from, to, false);
+ }
+ /* Case BONE */
+ else {
+ bPoseChannel *pchan;
+
+ pchan = BKE_pose_channel_find_name(ob->pose, substring);
+ if (pchan) {
+ /* Multiply the PoseSpace accumulation/final matrix for this
+ * PoseChannel by the Armature Object's Matrix to get a worldspace
+ * matrix.
+ */
+ bool is_bbone = (pchan->bone) && (pchan->bone->segments > 1) &&
+ (flag & CONSTRAINT_BBONE_SHAPE);
+ bool full_bbone = (flag & CONSTRAINT_BBONE_SHAPE_FULL) != 0;
+
+ if (headtail < 0.000001f && !(is_bbone && full_bbone)) {
+ /* skip length interpolation if set to head */
+ mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat);
+ }
+ else if (is_bbone && pchan->bone->segments == pchan->runtime.bbone_segments) {
+ /* use point along bbone */
+ Mat4 *bbone = pchan->runtime.bbone_pose_mats;
+ float tempmat[4][4];
+ float loc[3], fac;
+ int index;
+
+ /* figure out which segment(s) the headtail value falls in */
+ BKE_pchan_bbone_deform_segment_index(pchan, headtail, &index, &fac);
+
+ /* apply full transformation of the segment if requested */
+ if (full_bbone) {
+ interp_m4_m4m4(tempmat, bbone[index].mat, bbone[index + 1].mat, fac);
+
+ mul_m4_m4m4(tempmat, pchan->pose_mat, tempmat);
+ }
+ /* only interpolate location */
+ else {
+ interp_v3_v3v3(loc, bbone[index].mat[3], bbone[index + 1].mat[3], fac);
+
+ copy_m4_m4(tempmat, pchan->pose_mat);
+ mul_v3_m4v3(tempmat[3], pchan->pose_mat, loc);
+ }
+
+ mul_m4_m4m4(mat, ob->obmat, tempmat);
+ }
+ else {
+ float tempmat[4][4], loc[3];
+
+ /* interpolate along length of bone */
+ interp_v3_v3v3(loc, pchan->pose_head, pchan->pose_tail, headtail);
+
+ /* use interpolated distance for subtarget */
+ copy_m4_m4(tempmat, pchan->pose_mat);
+ copy_v3_v3(tempmat[3], loc);
+
+ mul_m4_m4m4(mat, ob->obmat, tempmat);
+ }
+ }
+ else
+ copy_m4_m4(mat, ob->obmat);
+
+ /* convert matrix space as required */
+ BKE_constraint_mat_convertspace(ob, pchan, mat, from, to, false);
+ }
}
/* ************************* Specific Constraints ***************************** */
@@ -652,40 +665,60 @@ static void constraint_target_to_mat4(Object *ob, const char *substring, float m
*/
#if 0
static bConstraintTypeInfo CTI_CONSTRNAME = {
- CONSTRAINT_TYPE_CONSTRNAME, /* type */
- sizeof(bConstrNameConstraint), /* size */
- "ConstrName", /* name */
- "bConstrNameConstraint", /* struct name */
- constrname_free, /* free data */
- constrname_id_looper, /* id looper */
- constrname_copy, /* copy data */
- constrname_new_data, /* new data */
- constrname_get_tars, /* get constraint targets */
- constrname_flush_tars, /* flush constraint targets */
- constrname_get_tarmat, /* get target matrix */
- constrname_evaluate, /* evaluate */
+ CONSTRAINT_TYPE_CONSTRNAME, /* type */
+ sizeof(bConstrNameConstraint), /* size */
+ "ConstrName", /* name */
+ "bConstrNameConstraint", /* struct name */
+ constrname_free, /* free data */
+ constrname_id_looper, /* id looper */
+ constrname_copy, /* copy data */
+ constrname_new_data, /* new data */
+ constrname_get_tars, /* get constraint targets */
+ constrname_flush_tars, /* flush constraint targets */
+ constrname_get_tarmat, /* get target matrix */
+ constrname_evaluate, /* evaluate */
};
#endif
/* This function should be used for the get_target_matrix member of all
* constraints that are not picky about what happens to their target matrix.
*/
-static void default_get_tarmat(struct Depsgraph *UNUSED(depsgraph), bConstraint *con, bConstraintOb *UNUSED(cob), bConstraintTarget *ct, float UNUSED(ctime))
-{
- if (VALID_CONS_TARGET(ct))
- constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail);
- else if (ct)
- unit_m4(ct->matrix);
+static void default_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
+ bConstraint *con,
+ bConstraintOb *UNUSED(cob),
+ bConstraintTarget *ct,
+ float UNUSED(ctime))
+{
+ if (VALID_CONS_TARGET(ct))
+ constraint_target_to_mat4(ct->tar,
+ ct->subtarget,
+ ct->matrix,
+ CONSTRAINT_SPACE_WORLD,
+ ct->space,
+ con->flag,
+ con->headtail);
+ else if (ct)
+ unit_m4(ct->matrix);
}
/* This is a variant that extracts full transformation from B-Bone segments.
*/
-static void default_get_tarmat_full_bbone(struct Depsgraph *UNUSED(depsgraph), bConstraint *con, bConstraintOb *UNUSED(cob), bConstraintTarget *ct, float UNUSED(ctime))
-{
- if (VALID_CONS_TARGET(ct))
- constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->flag | CONSTRAINT_BBONE_SHAPE_FULL, con->headtail);
- else if (ct)
- unit_m4(ct->matrix);
+static void default_get_tarmat_full_bbone(struct Depsgraph *UNUSED(depsgraph),
+ bConstraint *con,
+ bConstraintOb *UNUSED(cob),
+ bConstraintTarget *ct,
+ float UNUSED(ctime))
+{
+ if (VALID_CONS_TARGET(ct))
+ constraint_target_to_mat4(ct->tar,
+ ct->subtarget,
+ ct->matrix,
+ CONSTRAINT_SPACE_WORLD,
+ ct->space,
+ con->flag | CONSTRAINT_BBONE_SHAPE_FULL,
+ con->headtail);
+ else if (ct)
+ unit_m4(ct->matrix);
}
/* This following macro should be used for all standard single-target *_get_tars functions
@@ -695,32 +728,33 @@ static void default_get_tarmat_full_bbone(struct Depsgraph *UNUSED(depsgraph), b
*/
// TODO: cope with getting rotation order...
#define SINGLETARGET_GET_TARS(con, datatar, datasubtarget, ct, list) \
- { \
- ct = MEM_callocN(sizeof(bConstraintTarget), "tempConstraintTarget"); \
- \
- ct->tar = datatar; \
- BLI_strncpy(ct->subtarget, datasubtarget, sizeof(ct->subtarget)); \
- ct->space = con->tarspace; \
- ct->flag = CONSTRAINT_TAR_TEMP; \
- \
- if (ct->tar) { \
- if ((ct->tar->type == OB_ARMATURE) && (ct->subtarget[0])) { \
- bPoseChannel *pchan = BKE_pose_channel_find_name(ct->tar->pose, ct->subtarget); \
- ct->type = CONSTRAINT_OBTYPE_BONE; \
- ct->rotOrder = (pchan) ? (pchan->rotmode) : EULER_ORDER_DEFAULT; \
- } \
- else if (OB_TYPE_SUPPORT_VGROUP(ct->tar->type) && (ct->subtarget[0])) { \
- ct->type = CONSTRAINT_OBTYPE_VERT; \
- ct->rotOrder = EULER_ORDER_DEFAULT; \
- } \
- else { \
- ct->type = CONSTRAINT_OBTYPE_OBJECT; \
- ct->rotOrder = ct->tar->rotmode; \
- } \
- } \
- \
- BLI_addtail(list, ct); \
- } (void)0
+ { \
+ ct = MEM_callocN(sizeof(bConstraintTarget), "tempConstraintTarget"); \
+\
+ ct->tar = datatar; \
+ BLI_strncpy(ct->subtarget, datasubtarget, sizeof(ct->subtarget)); \
+ ct->space = con->tarspace; \
+ ct->flag = CONSTRAINT_TAR_TEMP; \
+\
+ if (ct->tar) { \
+ if ((ct->tar->type == OB_ARMATURE) && (ct->subtarget[0])) { \
+ bPoseChannel *pchan = BKE_pose_channel_find_name(ct->tar->pose, ct->subtarget); \
+ ct->type = CONSTRAINT_OBTYPE_BONE; \
+ ct->rotOrder = (pchan) ? (pchan->rotmode) : EULER_ORDER_DEFAULT; \
+ } \
+ else if (OB_TYPE_SUPPORT_VGROUP(ct->tar->type) && (ct->subtarget[0])) { \
+ ct->type = CONSTRAINT_OBTYPE_VERT; \
+ ct->rotOrder = EULER_ORDER_DEFAULT; \
+ } \
+ else { \
+ ct->type = CONSTRAINT_OBTYPE_OBJECT; \
+ ct->rotOrder = ct->tar->rotmode; \
+ } \
+ } \
+\
+ BLI_addtail(list, ct); \
+ } \
+ (void)0
/* This following macro should be used for all standard single-target *_get_tars functions
* to save typing and reduce maintenance woes. It does not do the subtarget related operations
@@ -729,17 +763,19 @@ static void default_get_tarmat_full_bbone(struct Depsgraph *UNUSED(depsgraph), b
*/
// TODO: cope with getting rotation order...
#define SINGLETARGETNS_GET_TARS(con, datatar, ct, list) \
- { \
- ct = MEM_callocN(sizeof(bConstraintTarget), "tempConstraintTarget"); \
- \
- ct->tar = datatar; \
- ct->space = con->tarspace; \
- ct->flag = CONSTRAINT_TAR_TEMP; \
- \
- if (ct->tar) ct->type = CONSTRAINT_OBTYPE_OBJECT; \
- \
- BLI_addtail(list, ct); \
- } (void)0
+ { \
+ ct = MEM_callocN(sizeof(bConstraintTarget), "tempConstraintTarget"); \
+\
+ ct->tar = datatar; \
+ ct->space = con->tarspace; \
+ ct->flag = CONSTRAINT_TAR_TEMP; \
+\
+ if (ct->tar) \
+ ct->type = CONSTRAINT_OBTYPE_OBJECT; \
+\
+ BLI_addtail(list, ct); \
+ } \
+ (void)0
/* This following macro should be used for all standard single-target *_flush_tars functions
* to save typing and reduce maintenance woes.
@@ -748,19 +784,20 @@ static void default_get_tarmat_full_bbone(struct Depsgraph *UNUSED(depsgraph), b
* really just to help this code easier to read)
*/
#define SINGLETARGET_FLUSH_TARS(con, datatar, datasubtarget, ct, list, no_copy) \
- { \
- if (ct) { \
- bConstraintTarget *ctn = ct->next; \
- if (no_copy == 0) { \
- datatar = ct->tar; \
- BLI_strncpy(datasubtarget, ct->subtarget, sizeof(datasubtarget)); \
- con->tarspace = (char)ct->space; \
- } \
- \
- BLI_freelinkN(list, ct); \
- ct = ctn; \
- } \
- } (void)0
+ { \
+ if (ct) { \
+ bConstraintTarget *ctn = ct->next; \
+ if (no_copy == 0) { \
+ datatar = ct->tar; \
+ BLI_strncpy(datasubtarget, ct->subtarget, sizeof(datasubtarget)); \
+ con->tarspace = (char)ct->space; \
+ } \
+\
+ BLI_freelinkN(list, ct); \
+ ct = ctn; \
+ } \
+ } \
+ (void)0
/* This following macro should be used for all standard single-target *_flush_tars functions
* to save typing and reduce maintenance woes. It does not do the subtarget related operations.
@@ -769,3856 +806,3982 @@ static void default_get_tarmat_full_bbone(struct Depsgraph *UNUSED(depsgraph), b
* really just to help this code easier to read)
*/
#define SINGLETARGETNS_FLUSH_TARS(con, datatar, ct, list, no_copy) \
- { \
- if (ct) { \
- bConstraintTarget *ctn = ct->next; \
- if (no_copy == 0) { \
- datatar = ct->tar; \
- con->tarspace = (char)ct->space; \
- } \
- \
- BLI_freelinkN(list, ct); \
- ct = ctn; \
- } \
- } (void)0
+ { \
+ if (ct) { \
+ bConstraintTarget *ctn = ct->next; \
+ if (no_copy == 0) { \
+ datatar = ct->tar; \
+ con->tarspace = (char)ct->space; \
+ } \
+\
+ BLI_freelinkN(list, ct); \
+ ct = ctn; \
+ } \
+ } \
+ (void)0
/* --------- ChildOf Constraint ------------ */
static void childof_new_data(void *cdata)
{
- bChildOfConstraint *data = (bChildOfConstraint *)cdata;
+ bChildOfConstraint *data = (bChildOfConstraint *)cdata;
- data->flag = (CHILDOF_LOCX | CHILDOF_LOCY | CHILDOF_LOCZ |
- CHILDOF_ROTX | CHILDOF_ROTY | CHILDOF_ROTZ |
- CHILDOF_SIZEX | CHILDOF_SIZEY | CHILDOF_SIZEZ);
- unit_m4(data->invmat);
+ data->flag = (CHILDOF_LOCX | CHILDOF_LOCY | CHILDOF_LOCZ | CHILDOF_ROTX | CHILDOF_ROTY |
+ CHILDOF_ROTZ | CHILDOF_SIZEX | CHILDOF_SIZEY | CHILDOF_SIZEZ);
+ unit_m4(data->invmat);
}
static void childof_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
{
- bChildOfConstraint *data = con->data;
+ bChildOfConstraint *data = con->data;
- /* target only */
- func(con, (ID **)&data->tar, false, userdata);
+ /* target only */
+ func(con, (ID **)&data->tar, false, userdata);
}
static int childof_get_tars(bConstraint *con, ListBase *list)
{
- if (con && list) {
- bChildOfConstraint *data = con->data;
- bConstraintTarget *ct;
+ if (con && list) {
+ bChildOfConstraint *data = con->data;
+ bConstraintTarget *ct;
- /* standard target-getting macro for single-target constraints */
- SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
+ /* standard target-getting macro for single-target constraints */
+ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1;
- }
+ return 1;
+ }
- return 0;
+ return 0;
}
static void childof_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
{
- if (con && list) {
- bChildOfConstraint *data = con->data;
- bConstraintTarget *ct = list->first;
+ if (con && list) {
+ bChildOfConstraint *data = con->data;
+ bConstraintTarget *ct = list->first;
- /* the following macro is used for all standard single-target constraints */
- SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
- }
+ /* the following macro is used for all standard single-target constraints */
+ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
+ }
}
static void childof_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets)
{
- bChildOfConstraint *data = con->data;
- bConstraintTarget *ct = targets->first;
-
- /* only evaluate if there is a target */
- if (VALID_CONS_TARGET(ct)) {
- float parmat[4][4];
-
- /* simple matrix parenting */
- if (data->flag == CHILDOF_ALL) {
-
- /* multiply target (parent matrix) by offset (parent inverse) to get
- * the effect of the parent that will be exerted on the owner
- */
- mul_m4_m4m4(parmat, ct->matrix, data->invmat);
-
- /* now multiply the parent matrix by the owner matrix to get the
- * the effect of this constraint (i.e. owner is 'parented' to parent)
- */
- mul_m4_m4m4(cob->matrix, parmat, cob->matrix);
- }
- else {
- float invmat[4][4], tempmat[4][4];
- float loc[3], eul[3], size[3];
- float loco[3], eulo[3], sizo[3];
-
- /* get offset (parent-inverse) matrix */
- copy_m4_m4(invmat, data->invmat);
-
- /* extract components of both matrices */
- copy_v3_v3(loc, ct->matrix[3]);
- mat4_to_eulO(eul, ct->rotOrder, ct->matrix);
- mat4_to_size(size, ct->matrix);
-
- copy_v3_v3(loco, invmat[3]);
- mat4_to_eulO(eulo, cob->rotOrder, invmat);
- mat4_to_size(sizo, invmat);
-
- /* disable channels not enabled */
- if (!(data->flag & CHILDOF_LOCX)) loc[0] = loco[0] = 0.0f;
- if (!(data->flag & CHILDOF_LOCY)) loc[1] = loco[1] = 0.0f;
- if (!(data->flag & CHILDOF_LOCZ)) loc[2] = loco[2] = 0.0f;
- if (!(data->flag & CHILDOF_ROTX)) eul[0] = eulo[0] = 0.0f;
- if (!(data->flag & CHILDOF_ROTY)) eul[1] = eulo[1] = 0.0f;
- if (!(data->flag & CHILDOF_ROTZ)) eul[2] = eulo[2] = 0.0f;
- if (!(data->flag & CHILDOF_SIZEX)) size[0] = sizo[0] = 1.0f;
- if (!(data->flag & CHILDOF_SIZEY)) size[1] = sizo[1] = 1.0f;
- if (!(data->flag & CHILDOF_SIZEZ)) size[2] = sizo[2] = 1.0f;
-
- /* make new target mat and offset mat */
- loc_eulO_size_to_mat4(ct->matrix, loc, eul, size, ct->rotOrder);
- loc_eulO_size_to_mat4(invmat, loco, eulo, sizo, cob->rotOrder);
-
- /* multiply target (parent matrix) by offset (parent inverse) to get
- * the effect of the parent that will be exerted on the owner
- */
- mul_m4_m4m4(parmat, ct->matrix, invmat);
-
- /* now multiply the parent matrix by the owner matrix to get the
- * the effect of this constraint (i.e. owner is 'parented' to parent)
- */
- copy_m4_m4(tempmat, cob->matrix);
- mul_m4_m4m4(cob->matrix, parmat, tempmat);
-
- /* without this, changes to scale and rotation can change location
- * of a parentless bone or a disconnected bone. Even though its set
- * to zero above. */
- if (!(data->flag & CHILDOF_LOCX)) cob->matrix[3][0] = tempmat[3][0];
- if (!(data->flag & CHILDOF_LOCY)) cob->matrix[3][1] = tempmat[3][1];
- if (!(data->flag & CHILDOF_LOCZ)) cob->matrix[3][2] = tempmat[3][2];
- }
- }
+ bChildOfConstraint *data = con->data;
+ bConstraintTarget *ct = targets->first;
+
+ /* only evaluate if there is a target */
+ if (VALID_CONS_TARGET(ct)) {
+ float parmat[4][4];
+
+ /* simple matrix parenting */
+ if (data->flag == CHILDOF_ALL) {
+
+ /* multiply target (parent matrix) by offset (parent inverse) to get
+ * the effect of the parent that will be exerted on the owner
+ */
+ mul_m4_m4m4(parmat, ct->matrix, data->invmat);
+
+ /* now multiply the parent matrix by the owner matrix to get the
+ * the effect of this constraint (i.e. owner is 'parented' to parent)
+ */
+ mul_m4_m4m4(cob->matrix, parmat, cob->matrix);
+ }
+ else {
+ float invmat[4][4], tempmat[4][4];
+ float loc[3], eul[3], size[3];
+ float loco[3], eulo[3], sizo[3];
+
+ /* get offset (parent-inverse) matrix */
+ copy_m4_m4(invmat, data->invmat);
+
+ /* extract components of both matrices */
+ copy_v3_v3(loc, ct->matrix[3]);
+ mat4_to_eulO(eul, ct->rotOrder, ct->matrix);
+ mat4_to_size(size, ct->matrix);
+
+ copy_v3_v3(loco, invmat[3]);
+ mat4_to_eulO(eulo, cob->rotOrder, invmat);
+ mat4_to_size(sizo, invmat);
+
+ /* disable channels not enabled */
+ if (!(data->flag & CHILDOF_LOCX))
+ loc[0] = loco[0] = 0.0f;
+ if (!(data->flag & CHILDOF_LOCY))
+ loc[1] = loco[1] = 0.0f;
+ if (!(data->flag & CHILDOF_LOCZ))
+ loc[2] = loco[2] = 0.0f;
+ if (!(data->flag & CHILDOF_ROTX))
+ eul[0] = eulo[0] = 0.0f;
+ if (!(data->flag & CHILDOF_ROTY))
+ eul[1] = eulo[1] = 0.0f;
+ if (!(data->flag & CHILDOF_ROTZ))
+ eul[2] = eulo[2] = 0.0f;
+ if (!(data->flag & CHILDOF_SIZEX))
+ size[0] = sizo[0] = 1.0f;
+ if (!(data->flag & CHILDOF_SIZEY))
+ size[1] = sizo[1] = 1.0f;
+ if (!(data->flag & CHILDOF_SIZEZ))
+ size[2] = sizo[2] = 1.0f;
+
+ /* make new target mat and offset mat */
+ loc_eulO_size_to_mat4(ct->matrix, loc, eul, size, ct->rotOrder);
+ loc_eulO_size_to_mat4(invmat, loco, eulo, sizo, cob->rotOrder);
+
+ /* multiply target (parent matrix) by offset (parent inverse) to get
+ * the effect of the parent that will be exerted on the owner
+ */
+ mul_m4_m4m4(parmat, ct->matrix, invmat);
+
+ /* now multiply the parent matrix by the owner matrix to get the
+ * the effect of this constraint (i.e. owner is 'parented' to parent)
+ */
+ copy_m4_m4(tempmat, cob->matrix);
+ mul_m4_m4m4(cob->matrix, parmat, tempmat);
+
+ /* without this, changes to scale and rotation can change location
+ * of a parentless bone or a disconnected bone. Even though its set
+ * to zero above. */
+ if (!(data->flag & CHILDOF_LOCX))
+ cob->matrix[3][0] = tempmat[3][0];
+ if (!(data->flag & CHILDOF_LOCY))
+ cob->matrix[3][1] = tempmat[3][1];
+ if (!(data->flag & CHILDOF_LOCZ))
+ cob->matrix[3][2] = tempmat[3][2];
+ }
+ }
}
/* XXX note, con->flag should be CONSTRAINT_SPACEONCE for bone-childof, patched in readfile.c */
static bConstraintTypeInfo CTI_CHILDOF = {
- CONSTRAINT_TYPE_CHILDOF, /* type */
- sizeof(bChildOfConstraint), /* size */
- "Child Of", /* name */
- "bChildOfConstraint", /* struct name */
- NULL, /* free data */
- childof_id_looper, /* id looper */
- NULL, /* copy data */
- childof_new_data, /* new data */
- childof_get_tars, /* get constraint targets */
- childof_flush_tars, /* flush constraint targets */
- default_get_tarmat, /* get a target matrix */
- childof_evaluate, /* evaluate */
+ CONSTRAINT_TYPE_CHILDOF, /* type */
+ sizeof(bChildOfConstraint), /* size */
+ "Child Of", /* name */
+ "bChildOfConstraint", /* struct name */
+ NULL, /* free data */
+ childof_id_looper, /* id looper */
+ NULL, /* copy data */
+ childof_new_data, /* new data */
+ childof_get_tars, /* get constraint targets */
+ childof_flush_tars, /* flush constraint targets */
+ default_get_tarmat, /* get a target matrix */
+ childof_evaluate, /* evaluate */
};
/* -------- TrackTo Constraint ------- */
static void trackto_new_data(void *cdata)
{
- bTrackToConstraint *data = (bTrackToConstraint *)cdata;
+ bTrackToConstraint *data = (bTrackToConstraint *)cdata;
- data->reserved1 = TRACK_Y;
- data->reserved2 = UP_Z;
+ data->reserved1 = TRACK_Y;
+ data->reserved2 = UP_Z;
}
static void trackto_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
{
- bTrackToConstraint *data = con->data;
+ bTrackToConstraint *data = con->data;
- /* target only */
- func(con, (ID **)&data->tar, false, userdata);
+ /* target only */
+ func(con, (ID **)&data->tar, false, userdata);
}
static int trackto_get_tars(bConstraint *con, ListBase *list)
{
- if (con && list) {
- bTrackToConstraint *data = con->data;
- bConstraintTarget *ct;
+ if (con && list) {
+ bTrackToConstraint *data = con->data;
+ bConstraintTarget *ct;
- /* standard target-getting macro for single-target constraints */
- SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
+ /* standard target-getting macro for single-target constraints */
+ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1;
- }
+ return 1;
+ }
- return 0;
+ return 0;
}
static void trackto_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
{
- if (con && list) {
- bTrackToConstraint *data = con->data;
- bConstraintTarget *ct = list->first;
+ if (con && list) {
+ bTrackToConstraint *data = con->data;
+ bConstraintTarget *ct = list->first;
- /* the following macro is used for all standard single-target constraints */
- SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
- }
+ /* the following macro is used for all standard single-target constraints */
+ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
+ }
}
-
static int basis_cross(int n, int m)
{
- switch (n - m) {
- case 1:
- case -2:
- return 1;
-
- case -1:
- case 2:
- return -1;
-
- default:
- return 0;
- }
-}
-
-static void vectomat(const float vec[3], const float target_up[3], short axis, short upflag, short flags, float m[3][3])
-{
- float n[3];
- float u[3]; /* vector specifying the up axis */
- float proj[3];
- float right[3];
- float neg = -1;
- int right_index;
-
- if (normalize_v3_v3(n, vec) == 0.0f) {
- n[0] = 0.0f;
- n[1] = 0.0f;
- n[2] = 1.0f;
- }
- if (axis > 2) axis -= 3;
- else negate_v3(n);
-
- /* n specifies the transformation of the track axis */
- if (flags & TARGET_Z_UP) {
- /* target Z axis is the global up axis */
- copy_v3_v3(u, target_up);
- }
- else {
- /* world Z axis is the global up axis */
- u[0] = 0;
- u[1] = 0;
- u[2] = 1;
- }
-
- /* note: even though 'n' is normalized, don't use 'project_v3_v3v3_normalized' below
- * because precision issues cause a problem in near degenerate states, see: T53455. */
-
- /* project the up vector onto the plane specified by n */
- project_v3_v3v3(proj, u, n); /* first u onto n... */
- sub_v3_v3v3(proj, u, proj); /* then onto the plane */
- /* proj specifies the transformation of the up axis */
-
- if (normalize_v3(proj) == 0.0f) { /* degenerate projection */
- proj[0] = 0.0f;
- proj[1] = 1.0f;
- proj[2] = 0.0f;
- }
-
- /* Normalized cross product of n and proj specifies transformation of the right axis */
- cross_v3_v3v3(right, proj, n);
- normalize_v3(right);
-
- if (axis != upflag) {
- right_index = 3 - axis - upflag;
- neg = (float)basis_cross(axis, upflag);
-
- /* account for up direction, track direction */
- m[right_index][0] = neg * right[0];
- m[right_index][1] = neg * right[1];
- m[right_index][2] = neg * right[2];
-
- copy_v3_v3(m[upflag], proj);
-
- copy_v3_v3(m[axis], n);
- }
- /* identity matrix - don't do anything if the two axes are the same */
- else {
- unit_m3(m);
- }
+ switch (n - m) {
+ case 1:
+ case -2:
+ return 1;
+
+ case -1:
+ case 2:
+ return -1;
+
+ default:
+ return 0;
+ }
+}
+
+static void vectomat(const float vec[3],
+ const float target_up[3],
+ short axis,
+ short upflag,
+ short flags,
+ float m[3][3])
+{
+ float n[3];
+ float u[3]; /* vector specifying the up axis */
+ float proj[3];
+ float right[3];
+ float neg = -1;
+ int right_index;
+
+ if (normalize_v3_v3(n, vec) == 0.0f) {
+ n[0] = 0.0f;
+ n[1] = 0.0f;
+ n[2] = 1.0f;
+ }
+ if (axis > 2)
+ axis -= 3;
+ else
+ negate_v3(n);
+
+ /* n specifies the transformation of the track axis */
+ if (flags & TARGET_Z_UP) {
+ /* target Z axis is the global up axis */
+ copy_v3_v3(u, target_up);
+ }
+ else {
+ /* world Z axis is the global up axis */
+ u[0] = 0;
+ u[1] = 0;
+ u[2] = 1;
+ }
+
+ /* note: even though 'n' is normalized, don't use 'project_v3_v3v3_normalized' below
+ * because precision issues cause a problem in near degenerate states, see: T53455. */
+
+ /* project the up vector onto the plane specified by n */
+ project_v3_v3v3(proj, u, n); /* first u onto n... */
+ sub_v3_v3v3(proj, u, proj); /* then onto the plane */
+ /* proj specifies the transformation of the up axis */
+
+ if (normalize_v3(proj) == 0.0f) { /* degenerate projection */
+ proj[0] = 0.0f;
+ proj[1] = 1.0f;
+ proj[2] = 0.0f;
+ }
+
+ /* Normalized cross product of n and proj specifies transformation of the right axis */
+ cross_v3_v3v3(right, proj, n);
+ normalize_v3(right);
+
+ if (axis != upflag) {
+ right_index = 3 - axis - upflag;
+ neg = (float)basis_cross(axis, upflag);
+
+ /* account for up direction, track direction */
+ m[right_index][0] = neg * right[0];
+ m[right_index][1] = neg * right[1];
+ m[right_index][2] = neg * right[2];
+
+ copy_v3_v3(m[upflag], proj);
+
+ copy_v3_v3(m[axis], n);
+ }
+ /* identity matrix - don't do anything if the two axes are the same */
+ else {
+ unit_m3(m);
+ }
}
-
static void trackto_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets)
{
- bTrackToConstraint *data = con->data;
- bConstraintTarget *ct = targets->first;
+ bTrackToConstraint *data = con->data;
+ bConstraintTarget *ct = targets->first;
- if (VALID_CONS_TARGET(ct)) {
- float size[3], vec[3];
- float totmat[3][3];
+ if (VALID_CONS_TARGET(ct)) {
+ float size[3], vec[3];
+ float totmat[3][3];
- /* Get size property, since ob->scale is only the object's own relative size, not its global one */
- mat4_to_size(size, cob->matrix);
+ /* Get size property, since ob->scale is only the object's own relative size, not its global one */
+ mat4_to_size(size, cob->matrix);
- /* Clear the object's rotation */
- cob->matrix[0][0] = size[0];
- cob->matrix[0][1] = 0;
- cob->matrix[0][2] = 0;
- cob->matrix[1][0] = 0;
- cob->matrix[1][1] = size[1];
- cob->matrix[1][2] = 0;
- cob->matrix[2][0] = 0;
- cob->matrix[2][1] = 0;
- cob->matrix[2][2] = size[2];
+ /* Clear the object's rotation */
+ cob->matrix[0][0] = size[0];
+ cob->matrix[0][1] = 0;
+ cob->matrix[0][2] = 0;
+ cob->matrix[1][0] = 0;
+ cob->matrix[1][1] = size[1];
+ cob->matrix[1][2] = 0;
+ cob->matrix[2][0] = 0;
+ cob->matrix[2][1] = 0;
+ cob->matrix[2][2] = size[2];
- /* targetmat[2] instead of ownermat[2] is passed to vectomat
- * for backwards compatibility it seems... (Aligorith)
- */
- sub_v3_v3v3(vec, cob->matrix[3], ct->matrix[3]);
- vectomat(vec, ct->matrix[2],
- (short)data->reserved1, (short)data->reserved2,
- data->flags, totmat);
+ /* targetmat[2] instead of ownermat[2] is passed to vectomat
+ * for backwards compatibility it seems... (Aligorith)
+ */
+ sub_v3_v3v3(vec, cob->matrix[3], ct->matrix[3]);
+ vectomat(
+ vec, ct->matrix[2], (short)data->reserved1, (short)data->reserved2, data->flags, totmat);
- mul_m4_m3m4(cob->matrix, totmat, cob->matrix);
- }
+ mul_m4_m3m4(cob->matrix, totmat, cob->matrix);
+ }
}
static bConstraintTypeInfo CTI_TRACKTO = {
- CONSTRAINT_TYPE_TRACKTO, /* type */
- sizeof(bTrackToConstraint), /* size */
- "Track To", /* name */
- "bTrackToConstraint", /* struct name */
- NULL, /* free data */
- trackto_id_looper, /* id looper */
- NULL, /* copy data */
- trackto_new_data, /* new data */
- trackto_get_tars, /* get constraint targets */
- trackto_flush_tars, /* flush constraint targets */
- default_get_tarmat, /* get target matrix */
- trackto_evaluate, /* evaluate */
+ CONSTRAINT_TYPE_TRACKTO, /* type */
+ sizeof(bTrackToConstraint), /* size */
+ "Track To", /* name */
+ "bTrackToConstraint", /* struct name */
+ NULL, /* free data */
+ trackto_id_looper, /* id looper */
+ NULL, /* copy data */
+ trackto_new_data, /* new data */
+ trackto_get_tars, /* get constraint targets */
+ trackto_flush_tars, /* flush constraint targets */
+ default_get_tarmat, /* get target matrix */
+ trackto_evaluate, /* evaluate */
};
/* --------- Inverse-Kinematics --------- */
static void kinematic_new_data(void *cdata)
{
- bKinematicConstraint *data = (bKinematicConstraint *)cdata;
+ bKinematicConstraint *data = (bKinematicConstraint *)cdata;
- data->weight = 1.0f;
- data->orientweight = 1.0f;
- data->iterations = 500;
- data->dist = 1.0f;
- data->flag = CONSTRAINT_IK_TIP | CONSTRAINT_IK_STRETCH | CONSTRAINT_IK_POS;
+ data->weight = 1.0f;
+ data->orientweight = 1.0f;
+ data->iterations = 500;
+ data->dist = 1.0f;
+ data->flag = CONSTRAINT_IK_TIP | CONSTRAINT_IK_STRETCH | CONSTRAINT_IK_POS;
}
static void kinematic_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
{
- bKinematicConstraint *data = con->data;
+ bKinematicConstraint *data = con->data;
- /* chain target */
- func(con, (ID **)&data->tar, false, userdata);
+ /* chain target */
+ func(con, (ID **)&data->tar, false, userdata);
- /* poletarget */
- func(con, (ID **)&data->poletar, false, userdata);
+ /* poletarget */
+ func(con, (ID **)&data->poletar, false, userdata);
}
static int kinematic_get_tars(bConstraint *con, ListBase *list)
{
- if (con && list) {
- bKinematicConstraint *data = con->data;
- bConstraintTarget *ct;
+ if (con && list) {
+ bKinematicConstraint *data = con->data;
+ bConstraintTarget *ct;
- /* standard target-getting macro for single-target constraints is used twice here */
- SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- SINGLETARGET_GET_TARS(con, data->poletar, data->polesubtarget, ct, list);
+ /* standard target-getting macro for single-target constraints is used twice here */
+ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
+ SINGLETARGET_GET_TARS(con, data->poletar, data->polesubtarget, ct, list);
- return 2;
- }
+ return 2;
+ }
- return 0;
+ return 0;
}
static void kinematic_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
{
- if (con && list) {
- bKinematicConstraint *data = con->data;
- bConstraintTarget *ct = list->first;
-
- /* the following macro is used for all standard single-target constraints */
- SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
- SINGLETARGET_FLUSH_TARS(con, data->poletar, data->polesubtarget, ct, list, no_copy);
- }
-}
-
-static void kinematic_get_tarmat(struct Depsgraph *UNUSED(depsgraph), bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
-{
- bKinematicConstraint *data = con->data;
-
- if (VALID_CONS_TARGET(ct))
- constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail);
- else if (ct) {
- if (data->flag & CONSTRAINT_IK_AUTO) {
- Object *ob = cob->ob;
-
- if (ob == NULL) {
- unit_m4(ct->matrix);
- }
- else {
- float vec[3];
- /* move grabtarget into world space */
- mul_v3_m4v3(vec, ob->obmat, data->grabtarget);
- copy_m4_m4(ct->matrix, ob->obmat);
- copy_v3_v3(ct->matrix[3], vec);
- }
- }
- else
- unit_m4(ct->matrix);
- }
+ if (con && list) {
+ bKinematicConstraint *data = con->data;
+ bConstraintTarget *ct = list->first;
+
+ /* the following macro is used for all standard single-target constraints */
+ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
+ SINGLETARGET_FLUSH_TARS(con, data->poletar, data->polesubtarget, ct, list, no_copy);
+ }
+}
+
+static void kinematic_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
+ bConstraint *con,
+ bConstraintOb *cob,
+ bConstraintTarget *ct,
+ float UNUSED(ctime))
+{
+ bKinematicConstraint *data = con->data;
+
+ if (VALID_CONS_TARGET(ct))
+ constraint_target_to_mat4(ct->tar,
+ ct->subtarget,
+ ct->matrix,
+ CONSTRAINT_SPACE_WORLD,
+ ct->space,
+ con->flag,
+ con->headtail);
+ else if (ct) {
+ if (data->flag & CONSTRAINT_IK_AUTO) {
+ Object *ob = cob->ob;
+
+ if (ob == NULL) {
+ unit_m4(ct->matrix);
+ }
+ else {
+ float vec[3];
+ /* move grabtarget into world space */
+ mul_v3_m4v3(vec, ob->obmat, data->grabtarget);
+ copy_m4_m4(ct->matrix, ob->obmat);
+ copy_v3_v3(ct->matrix[3], vec);
+ }
+ }
+ else
+ unit_m4(ct->matrix);
+ }
}
static bConstraintTypeInfo CTI_KINEMATIC = {
- CONSTRAINT_TYPE_KINEMATIC, /* type */
- sizeof(bKinematicConstraint), /* size */
- "IK", /* name */
- "bKinematicConstraint", /* struct name */
- NULL, /* free data */
- kinematic_id_looper, /* id looper */
- NULL, /* copy data */
- kinematic_new_data, /* new data */
- kinematic_get_tars, /* get constraint targets */
- kinematic_flush_tars, /* flush constraint targets */
- kinematic_get_tarmat, /* get target matrix */
- NULL, /* evaluate - solved as separate loop */
+ CONSTRAINT_TYPE_KINEMATIC, /* type */
+ sizeof(bKinematicConstraint), /* size */
+ "IK", /* name */
+ "bKinematicConstraint", /* struct name */
+ NULL, /* free data */
+ kinematic_id_looper, /* id looper */
+ NULL, /* copy data */
+ kinematic_new_data, /* new data */
+ kinematic_get_tars, /* get constraint targets */
+ kinematic_flush_tars, /* flush constraint targets */
+ kinematic_get_tarmat, /* get target matrix */
+ NULL, /* evaluate - solved as separate loop */
};
/* -------- Follow-Path Constraint ---------- */
static void followpath_new_data(void *cdata)
{
- bFollowPathConstraint *data = (bFollowPathConstraint *)cdata;
+ bFollowPathConstraint *data = (bFollowPathConstraint *)cdata;
- data->trackflag = TRACK_Y;
- data->upflag = UP_Z;
- data->offset = 0;
- data->followflag = 0;
+ data->trackflag = TRACK_Y;
+ data->upflag = UP_Z;
+ data->offset = 0;
+ data->followflag = 0;
}
static void followpath_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
{
- bFollowPathConstraint *data = con->data;
+ bFollowPathConstraint *data = con->data;
- /* target only */
- func(con, (ID **)&data->tar, false, userdata);
+ /* target only */
+ func(con, (ID **)&data->tar, false, userdata);
}
static int followpath_get_tars(bConstraint *con, ListBase *list)
{
- if (con && list) {
- bFollowPathConstraint *data = con->data;
- bConstraintTarget *ct;
+ if (con && list) {
+ bFollowPathConstraint *data = con->data;
+ bConstraintTarget *ct;
- /* standard target-getting macro for single-target constraints without subtargets */
- SINGLETARGETNS_GET_TARS(con, data->tar, ct, list);
+ /* standard target-getting macro for single-target constraints without subtargets */
+ SINGLETARGETNS_GET_TARS(con, data->tar, ct, list);
- return 1;
- }
+ return 1;
+ }
- return 0;
+ return 0;
}
static void followpath_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
{
- if (con && list) {
- bFollowPathConstraint *data = con->data;
- bConstraintTarget *ct = list->first;
+ if (con && list) {
+ bFollowPathConstraint *data = con->data;
+ bConstraintTarget *ct = list->first;
- /* the following macro is used for all standard single-target constraints */
- SINGLETARGETNS_FLUSH_TARS(con, data->tar, ct, list, no_copy);
- }
+ /* the following macro is used for all standard single-target constraints */
+ SINGLETARGETNS_FLUSH_TARS(con, data->tar, ct, list, no_copy);
+ }
}
static void followpath_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
- bConstraint *con, bConstraintOb *UNUSED(cob),
- bConstraintTarget *ct, float UNUSED(ctime))
-{
- bFollowPathConstraint *data = con->data;
-
- if (VALID_CONS_TARGET(ct) && (ct->tar->type == OB_CURVE)) {
- Curve *cu = ct->tar->data;
- float vec[4], dir[3], radius;
- float curvetime;
-
- unit_m4(ct->matrix);
-
- /* note: when creating constraints that follow path, the curve gets the CU_PATH set now,
- * currently for paths to work it needs to go through the bevlist/displist system (ton)
- */
-
- if (ct->tar->runtime.curve_cache && ct->tar->runtime.curve_cache->path && ct->tar->runtime.curve_cache->path->data) {
- float quat[4];
- if ((data->followflag & FOLLOWPATH_STATIC) == 0) {
- /* animated position along curve depending on time */
- Nurb *nu = cu->nurb.first;
- curvetime = cu->ctime - data->offset;
-
- /* ctime is now a proper var setting of Curve which gets set by Animato like any other var that's animated,
- * but this will only work if it actually is animated...
- *
- * we divide the curvetime calculated in the previous step by the length of the path, to get a time
- * factor, which then gets clamped to lie within 0.0 - 1.0 range
- */
- curvetime /= cu->pathlen;
-
- if (nu && nu->flagu & CU_NURB_CYCLIC) {
- /* If the curve is cyclic, enable looping around if the time is
- * outside the bounds 0..1 */
- if ((curvetime < 0.0f) || (curvetime > 1.0f)) {
- curvetime -= floorf(curvetime);
- }
- }
- else {
- /* The curve is not cyclic, so clamp to the begin/end points. */
- CLAMP(curvetime, 0.0f, 1.0f);
- }
- }
- else {
- /* fixed position along curve */
- curvetime = data->offset_fac;
- }
-
- if (where_on_path(ct->tar, curvetime, vec, dir, (data->followflag & FOLLOWPATH_FOLLOW) ? quat : NULL, &radius, NULL) ) { /* quat_pt is quat or NULL*/
- float totmat[4][4];
- unit_m4(totmat);
-
- if (data->followflag & FOLLOWPATH_FOLLOW) {
- quat_apply_track(quat, data->trackflag, data->upflag);
- quat_to_mat4(totmat, quat);
- }
-
- if (data->followflag & FOLLOWPATH_RADIUS) {
- float tmat[4][4], rmat[4][4];
- scale_m4_fl(tmat, radius);
- mul_m4_m4m4(rmat, tmat, totmat);
- copy_m4_m4(totmat, rmat);
- }
-
- copy_v3_v3(totmat[3], vec);
-
- mul_m4_m4m4(ct->matrix, ct->tar->obmat, totmat);
- }
- }
- }
- else if (ct)
- unit_m4(ct->matrix);
+ bConstraint *con,
+ bConstraintOb *UNUSED(cob),
+ bConstraintTarget *ct,
+ float UNUSED(ctime))
+{
+ bFollowPathConstraint *data = con->data;
+
+ if (VALID_CONS_TARGET(ct) && (ct->tar->type == OB_CURVE)) {
+ Curve *cu = ct->tar->data;
+ float vec[4], dir[3], radius;
+ float curvetime;
+
+ unit_m4(ct->matrix);
+
+ /* note: when creating constraints that follow path, the curve gets the CU_PATH set now,
+ * currently for paths to work it needs to go through the bevlist/displist system (ton)
+ */
+
+ if (ct->tar->runtime.curve_cache && ct->tar->runtime.curve_cache->path &&
+ ct->tar->runtime.curve_cache->path->data) {
+ float quat[4];
+ if ((data->followflag & FOLLOWPATH_STATIC) == 0) {
+ /* animated position along curve depending on time */
+ Nurb *nu = cu->nurb.first;
+ curvetime = cu->ctime - data->offset;
+
+ /* ctime is now a proper var setting of Curve which gets set by Animato like any other var that's animated,
+ * but this will only work if it actually is animated...
+ *
+ * we divide the curvetime calculated in the previous step by the length of the path, to get a time
+ * factor, which then gets clamped to lie within 0.0 - 1.0 range
+ */
+ curvetime /= cu->pathlen;
+
+ if (nu && nu->flagu & CU_NURB_CYCLIC) {
+ /* If the curve is cyclic, enable looping around if the time is
+ * outside the bounds 0..1 */
+ if ((curvetime < 0.0f) || (curvetime > 1.0f)) {
+ curvetime -= floorf(curvetime);
+ }
+ }
+ else {
+ /* The curve is not cyclic, so clamp to the begin/end points. */
+ CLAMP(curvetime, 0.0f, 1.0f);
+ }
+ }
+ else {
+ /* fixed position along curve */
+ curvetime = data->offset_fac;
+ }
+
+ if (where_on_path(ct->tar,
+ curvetime,
+ vec,
+ dir,
+ (data->followflag & FOLLOWPATH_FOLLOW) ? quat : NULL,
+ &radius,
+ NULL)) { /* quat_pt is quat or NULL*/
+ float totmat[4][4];
+ unit_m4(totmat);
+
+ if (data->followflag & FOLLOWPATH_FOLLOW) {
+ quat_apply_track(quat, data->trackflag, data->upflag);
+ quat_to_mat4(totmat, quat);
+ }
+
+ if (data->followflag & FOLLOWPATH_RADIUS) {
+ float tmat[4][4], rmat[4][4];
+ scale_m4_fl(tmat, radius);
+ mul_m4_m4m4(rmat, tmat, totmat);
+ copy_m4_m4(totmat, rmat);
+ }
+
+ copy_v3_v3(totmat[3], vec);
+
+ mul_m4_m4m4(ct->matrix, ct->tar->obmat, totmat);
+ }
+ }
+ }
+ else if (ct)
+ unit_m4(ct->matrix);
}
static void followpath_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets)
{
- bConstraintTarget *ct = targets->first;
+ bConstraintTarget *ct = targets->first;
- /* only evaluate if there is a target */
- if (VALID_CONS_TARGET(ct)) {
- float obmat[4][4];
- float size[3];
- bFollowPathConstraint *data = con->data;
+ /* only evaluate if there is a target */
+ if (VALID_CONS_TARGET(ct)) {
+ float obmat[4][4];
+ float size[3];
+ bFollowPathConstraint *data = con->data;
- /* get Object transform (loc/rot/size) to determine transformation from path */
- /* TODO: this used to be local at one point, but is probably more useful as-is */
- copy_m4_m4(obmat, cob->matrix);
+ /* get Object transform (loc/rot/size) to determine transformation from path */
+ /* TODO: this used to be local at one point, but is probably more useful as-is */
+ copy_m4_m4(obmat, cob->matrix);
- /* get scaling of object before applying constraint */
- mat4_to_size(size, cob->matrix);
+ /* get scaling of object before applying constraint */
+ mat4_to_size(size, cob->matrix);
- /* apply targetmat - containing location on path, and rotation */
- mul_m4_m4m4(cob->matrix, ct->matrix, obmat);
+ /* apply targetmat - containing location on path, and rotation */
+ mul_m4_m4m4(cob->matrix, ct->matrix, obmat);
- /* un-apply scaling caused by path */
- if ((data->followflag & FOLLOWPATH_RADIUS) == 0) { /* XXX - assume that scale correction means that radius will have some scale error in it - Campbell */
- float obsize[3];
+ /* un-apply scaling caused by path */
+ if ((data->followflag & FOLLOWPATH_RADIUS) ==
+ 0) { /* XXX - assume that scale correction means that radius will have some scale error in it - Campbell */
+ float obsize[3];
- mat4_to_size(obsize, cob->matrix);
- if (obsize[0])
- mul_v3_fl(cob->matrix[0], size[0] / obsize[0]);
- if (obsize[1])
- mul_v3_fl(cob->matrix[1], size[1] / obsize[1]);
- if (obsize[2])
- mul_v3_fl(cob->matrix[2], size[2] / obsize[2]);
- }
- }
+ mat4_to_size(obsize, cob->matrix);
+ if (obsize[0])
+ mul_v3_fl(cob->matrix[0], size[0] / obsize[0]);
+ if (obsize[1])
+ mul_v3_fl(cob->matrix[1], size[1] / obsize[1]);
+ if (obsize[2])
+ mul_v3_fl(cob->matrix[2], size[2] / obsize[2]);
+ }
+ }
}
static bConstraintTypeInfo CTI_FOLLOWPATH = {
- CONSTRAINT_TYPE_FOLLOWPATH, /* type */
- sizeof(bFollowPathConstraint), /* size */
- "Follow Path", /* name */
- "bFollowPathConstraint", /* struct name */
- NULL, /* free data */
- followpath_id_looper, /* id looper */
- NULL, /* copy data */
- followpath_new_data, /* new data */
- followpath_get_tars, /* get constraint targets */
- followpath_flush_tars, /* flush constraint targets */
- followpath_get_tarmat, /* get target matrix */
- followpath_evaluate, /* evaluate */
+ CONSTRAINT_TYPE_FOLLOWPATH, /* type */
+ sizeof(bFollowPathConstraint), /* size */
+ "Follow Path", /* name */
+ "bFollowPathConstraint", /* struct name */
+ NULL, /* free data */
+ followpath_id_looper, /* id looper */
+ NULL, /* copy data */
+ followpath_new_data, /* new data */
+ followpath_get_tars, /* get constraint targets */
+ followpath_flush_tars, /* flush constraint targets */
+ followpath_get_tarmat, /* get target matrix */
+ followpath_evaluate, /* evaluate */
};
/* --------- Limit Location --------- */
-
static void loclimit_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UNUSED(targets))
{
- bLocLimitConstraint *data = con->data;
-
- if (data->flag & LIMIT_XMIN) {
- if (cob->matrix[3][0] < data->xmin)
- cob->matrix[3][0] = data->xmin;
- }
- if (data->flag & LIMIT_XMAX) {
- if (cob->matrix[3][0] > data->xmax)
- cob->matrix[3][0] = data->xmax;
- }
- if (data->flag & LIMIT_YMIN) {
- if (cob->matrix[3][1] < data->ymin)
- cob->matrix[3][1] = data->ymin;
- }
- if (data->flag & LIMIT_YMAX) {
- if (cob->matrix[3][1] > data->ymax)
- cob->matrix[3][1] = data->ymax;
- }
- if (data->flag & LIMIT_ZMIN) {
- if (cob->matrix[3][2] < data->zmin)
- cob->matrix[3][2] = data->zmin;
- }
- if (data->flag & LIMIT_ZMAX) {
- if (cob->matrix[3][2] > data->zmax)
- cob->matrix[3][2] = data->zmax;
- }
+ bLocLimitConstraint *data = con->data;
+
+ if (data->flag & LIMIT_XMIN) {
+ if (cob->matrix[3][0] < data->xmin)
+ cob->matrix[3][0] = data->xmin;
+ }
+ if (data->flag & LIMIT_XMAX) {
+ if (cob->matrix[3][0] > data->xmax)
+ cob->matrix[3][0] = data->xmax;
+ }
+ if (data->flag & LIMIT_YMIN) {
+ if (cob->matrix[3][1] < data->ymin)
+ cob->matrix[3][1] = data->ymin;
+ }
+ if (data->flag & LIMIT_YMAX) {
+ if (cob->matrix[3][1] > data->ymax)
+ cob->matrix[3][1] = data->ymax;
+ }
+ if (data->flag & LIMIT_ZMIN) {
+ if (cob->matrix[3][2] < data->zmin)
+ cob->matrix[3][2] = data->zmin;
+ }
+ if (data->flag & LIMIT_ZMAX) {
+ if (cob->matrix[3][2] > data->zmax)
+ cob->matrix[3][2] = data->zmax;
+ }
}
static bConstraintTypeInfo CTI_LOCLIMIT = {
- CONSTRAINT_TYPE_LOCLIMIT, /* type */
- sizeof(bLocLimitConstraint), /* size */
- "Limit Location", /* name */
- "bLocLimitConstraint", /* struct name */
- NULL, /* free data */
- NULL, /* id looper */
- NULL, /* copy data */
- NULL, /* new data */
- NULL, /* get constraint targets */
- NULL, /* flush constraint targets */
- NULL, /* get target matrix */
- loclimit_evaluate, /* evaluate */
+ CONSTRAINT_TYPE_LOCLIMIT, /* type */
+ sizeof(bLocLimitConstraint), /* size */
+ "Limit Location", /* name */
+ "bLocLimitConstraint", /* struct name */
+ NULL, /* free data */
+ NULL, /* id looper */
+ NULL, /* copy data */
+ NULL, /* new data */
+ NULL, /* get constraint targets */
+ NULL, /* flush constraint targets */
+ NULL, /* get target matrix */
+ loclimit_evaluate, /* evaluate */
};
/* -------- Limit Rotation --------- */
static void rotlimit_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UNUSED(targets))
{
- bRotLimitConstraint *data = con->data;
- float loc[3];
- float eul[3];
- float size[3];
+ bRotLimitConstraint *data = con->data;
+ float loc[3];
+ float eul[3];
+ float size[3];
- copy_v3_v3(loc, cob->matrix[3]);
- mat4_to_size(size, cob->matrix);
+ copy_v3_v3(loc, cob->matrix[3]);
+ mat4_to_size(size, cob->matrix);
- mat4_to_eulO(eul, cob->rotOrder, cob->matrix);
+ mat4_to_eulO(eul, cob->rotOrder, cob->matrix);
- /* constraint data uses radians internally */
+ /* constraint data uses radians internally */
- /* limiting of euler values... */
- if (data->flag & LIMIT_XROT) {
- if (eul[0] < data->xmin)
- eul[0] = data->xmin;
+ /* limiting of euler values... */
+ if (data->flag & LIMIT_XROT) {
+ if (eul[0] < data->xmin)
+ eul[0] = data->xmin;
- if (eul[0] > data->xmax)
- eul[0] = data->xmax;
- }
- if (data->flag & LIMIT_YROT) {
- if (eul[1] < data->ymin)
- eul[1] = data->ymin;
+ if (eul[0] > data->xmax)
+ eul[0] = data->xmax;
+ }
+ if (data->flag & LIMIT_YROT) {
+ if (eul[1] < data->ymin)
+ eul[1] = data->ymin;
- if (eul[1] > data->ymax)
- eul[1] = data->ymax;
- }
- if (data->flag & LIMIT_ZROT) {
- if (eul[2] < data->zmin)
- eul[2] = data->zmin;
+ if (eul[1] > data->ymax)
+ eul[1] = data->ymax;
+ }
+ if (data->flag & LIMIT_ZROT) {
+ if (eul[2] < data->zmin)
+ eul[2] = data->zmin;
- if (eul[2] > data->zmax)
- eul[2] = data->zmax;
- }
+ if (eul[2] > data->zmax)
+ eul[2] = data->zmax;
+ }
- loc_eulO_size_to_mat4(cob->matrix, loc, eul, size, cob->rotOrder);
+ loc_eulO_size_to_mat4(cob->matrix, loc, eul, size, cob->rotOrder);
}
static bConstraintTypeInfo CTI_ROTLIMIT = {
- CONSTRAINT_TYPE_ROTLIMIT, /* type */
- sizeof(bRotLimitConstraint), /* size */
- "Limit Rotation", /* name */
- "bRotLimitConstraint", /* struct name */
- NULL, /* free data */
- NULL, /* id looper */
- NULL, /* copy data */
- NULL, /* new data */
- NULL, /* get constraint targets */
- NULL, /* flush constraint targets */
- NULL, /* get target matrix */
- rotlimit_evaluate, /* evaluate */
+ CONSTRAINT_TYPE_ROTLIMIT, /* type */
+ sizeof(bRotLimitConstraint), /* size */
+ "Limit Rotation", /* name */
+ "bRotLimitConstraint", /* struct name */
+ NULL, /* free data */
+ NULL, /* id looper */
+ NULL, /* copy data */
+ NULL, /* new data */
+ NULL, /* get constraint targets */
+ NULL, /* flush constraint targets */
+ NULL, /* get target matrix */
+ rotlimit_evaluate, /* evaluate */
};
/* --------- Limit Scale --------- */
-
static void sizelimit_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UNUSED(targets))
{
- bSizeLimitConstraint *data = con->data;
- float obsize[3], size[3];
-
- mat4_to_size(size, cob->matrix);
- mat4_to_size(obsize, cob->matrix);
-
- if (data->flag & LIMIT_XMIN) {
- if (size[0] < data->xmin)
- size[0] = data->xmin;
- }
- if (data->flag & LIMIT_XMAX) {
- if (size[0] > data->xmax)
- size[0] = data->xmax;
- }
- if (data->flag & LIMIT_YMIN) {
- if (size[1] < data->ymin)
- size[1] = data->ymin;
- }
- if (data->flag & LIMIT_YMAX) {
- if (size[1] > data->ymax)
- size[1] = data->ymax;
- }
- if (data->flag & LIMIT_ZMIN) {
- if (size[2] < data->zmin)
- size[2] = data->zmin;
- }
- if (data->flag & LIMIT_ZMAX) {
- if (size[2] > data->zmax)
- size[2] = data->zmax;
- }
-
- if (obsize[0])
- mul_v3_fl(cob->matrix[0], size[0] / obsize[0]);
- if (obsize[1])
- mul_v3_fl(cob->matrix[1], size[1] / obsize[1]);
- if (obsize[2])
- mul_v3_fl(cob->matrix[2], size[2] / obsize[2]);
+ bSizeLimitConstraint *data = con->data;
+ float obsize[3], size[3];
+
+ mat4_to_size(size, cob->matrix);
+ mat4_to_size(obsize, cob->matrix);
+
+ if (data->flag & LIMIT_XMIN) {
+ if (size[0] < data->xmin)
+ size[0] = data->xmin;
+ }
+ if (data->flag & LIMIT_XMAX) {
+ if (size[0] > data->xmax)
+ size[0] = data->xmax;
+ }
+ if (data->flag & LIMIT_YMIN) {
+ if (size[1] < data->ymin)
+ size[1] = data->ymin;
+ }
+ if (data->flag & LIMIT_YMAX) {
+ if (size[1] > data->ymax)
+ size[1] = data->ymax;
+ }
+ if (data->flag & LIMIT_ZMIN) {
+ if (size[2] < data->zmin)
+ size[2] = data->zmin;
+ }
+ if (data->flag & LIMIT_ZMAX) {
+ if (size[2] > data->zmax)
+ size[2] = data->zmax;
+ }
+
+ if (obsize[0])
+ mul_v3_fl(cob->matrix[0], size[0] / obsize[0]);
+ if (obsize[1])
+ mul_v3_fl(cob->matrix[1], size[1] / obsize[1]);
+ if (obsize[2])
+ mul_v3_fl(cob->matrix[2], size[2] / obsize[2]);
}
static bConstraintTypeInfo CTI_SIZELIMIT = {
- CONSTRAINT_TYPE_SIZELIMIT, /* type */
- sizeof(bSizeLimitConstraint), /* size */
- "Limit Scale", /* name */
- "bSizeLimitConstraint", /* struct name */
- NULL, /* free data */
- NULL, /* id looper */
- NULL, /* copy data */
- NULL, /* new data */
- NULL, /* get constraint targets */
- NULL, /* flush constraint targets */
- NULL, /* get target matrix */
- sizelimit_evaluate, /* evaluate */
+ CONSTRAINT_TYPE_SIZELIMIT, /* type */
+ sizeof(bSizeLimitConstraint), /* size */
+ "Limit Scale", /* name */
+ "bSizeLimitConstraint", /* struct name */
+ NULL, /* free data */
+ NULL, /* id looper */
+ NULL, /* copy data */
+ NULL, /* new data */
+ NULL, /* get constraint targets */
+ NULL, /* flush constraint targets */
+ NULL, /* get target matrix */
+ sizelimit_evaluate, /* evaluate */
};
/* ----------- Copy Location ------------- */
static void loclike_new_data(void *cdata)
{
- bLocateLikeConstraint *data = (bLocateLikeConstraint *)cdata;
+ bLocateLikeConstraint *data = (bLocateLikeConstraint *)cdata;
- data->flag = LOCLIKE_X | LOCLIKE_Y | LOCLIKE_Z;
+ data->flag = LOCLIKE_X | LOCLIKE_Y | LOCLIKE_Z;
}
static void loclike_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
{
- bLocateLikeConstraint *data = con->data;
+ bLocateLikeConstraint *data = con->data;
- /* target only */
- func(con, (ID **)&data->tar, false, userdata);
+ /* target only */
+ func(con, (ID **)&data->tar, false, userdata);
}
static int loclike_get_tars(bConstraint *con, ListBase *list)
{
- if (con && list) {
- bLocateLikeConstraint *data = con->data;
- bConstraintTarget *ct;
+ if (con && list) {
+ bLocateLikeConstraint *data = con->data;
+ bConstraintTarget *ct;
- /* standard target-getting macro for single-target constraints */
- SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
+ /* standard target-getting macro for single-target constraints */
+ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1;
- }
+ return 1;
+ }
- return 0;
+ return 0;
}
static void loclike_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
{
- if (con && list) {
- bLocateLikeConstraint *data = con->data;
- bConstraintTarget *ct = list->first;
+ if (con && list) {
+ bLocateLikeConstraint *data = con->data;
+ bConstraintTarget *ct = list->first;
- /* the following macro is used for all standard single-target constraints */
- SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
- }
+ /* the following macro is used for all standard single-target constraints */
+ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
+ }
}
static void loclike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets)
{
- bLocateLikeConstraint *data = con->data;
- bConstraintTarget *ct = targets->first;
+ bLocateLikeConstraint *data = con->data;
+ bConstraintTarget *ct = targets->first;
- if (VALID_CONS_TARGET(ct)) {
- float offset[3] = {0.0f, 0.0f, 0.0f};
+ if (VALID_CONS_TARGET(ct)) {
+ float offset[3] = {0.0f, 0.0f, 0.0f};
- if (data->flag & LOCLIKE_OFFSET)
- copy_v3_v3(offset, cob->matrix[3]);
+ if (data->flag & LOCLIKE_OFFSET)
+ copy_v3_v3(offset, cob->matrix[3]);
- if (data->flag & LOCLIKE_X) {
- cob->matrix[3][0] = ct->matrix[3][0];
+ if (data->flag & LOCLIKE_X) {
+ cob->matrix[3][0] = ct->matrix[3][0];
- if (data->flag & LOCLIKE_X_INVERT) cob->matrix[3][0] *= -1;
- cob->matrix[3][0] += offset[0];
- }
- if (data->flag & LOCLIKE_Y) {
- cob->matrix[3][1] = ct->matrix[3][1];
+ if (data->flag & LOCLIKE_X_INVERT)
+ cob->matrix[3][0] *= -1;
+ cob->matrix[3][0] += offset[0];
+ }
+ if (data->flag & LOCLIKE_Y) {
+ cob->matrix[3][1] = ct->matrix[3][1];
- if (data->flag & LOCLIKE_Y_INVERT) cob->matrix[3][1] *= -1;
- cob->matrix[3][1] += offset[1];
- }
- if (data->flag & LOCLIKE_Z) {
- cob->matrix[3][2] = ct->matrix[3][2];
+ if (data->flag & LOCLIKE_Y_INVERT)
+ cob->matrix[3][1] *= -1;
+ cob->matrix[3][1] += offset[1];
+ }
+ if (data->flag & LOCLIKE_Z) {
+ cob->matrix[3][2] = ct->matrix[3][2];
- if (data->flag & LOCLIKE_Z_INVERT) cob->matrix[3][2] *= -1;
- cob->matrix[3][2] += offset[2];
- }
- }
+ if (data->flag & LOCLIKE_Z_INVERT)
+ cob->matrix[3][2] *= -1;
+ cob->matrix[3][2] += offset[2];
+ }
+ }
}
static bConstraintTypeInfo CTI_LOCLIKE = {
- CONSTRAINT_TYPE_LOCLIKE, /* type */
- sizeof(bLocateLikeConstraint), /* size */
- "Copy Location", /* name */
- "bLocateLikeConstraint", /* struct name */
- NULL, /* free data */
- loclike_id_looper, /* id looper */
- NULL, /* copy data */
- loclike_new_data, /* new data */
- loclike_get_tars, /* get constraint targets */
- loclike_flush_tars, /* flush constraint targets */
- default_get_tarmat, /* get target matrix */
- loclike_evaluate, /* evaluate */
+ CONSTRAINT_TYPE_LOCLIKE, /* type */
+ sizeof(bLocateLikeConstraint), /* size */
+ "Copy Location", /* name */
+ "bLocateLikeConstraint", /* struct name */
+ NULL, /* free data */
+ loclike_id_looper, /* id looper */
+ NULL, /* copy data */
+ loclike_new_data, /* new data */
+ loclike_get_tars, /* get constraint targets */
+ loclike_flush_tars, /* flush constraint targets */
+ default_get_tarmat, /* get target matrix */
+ loclike_evaluate, /* evaluate */
};
/* ----------- Copy Rotation ------------- */
static void rotlike_new_data(void *cdata)
{
- bRotateLikeConstraint *data = (bRotateLikeConstraint *)cdata;
+ bRotateLikeConstraint *data = (bRotateLikeConstraint *)cdata;
- data->flag = ROTLIKE_X | ROTLIKE_Y | ROTLIKE_Z;
+ data->flag = ROTLIKE_X | ROTLIKE_Y | ROTLIKE_Z;
}
static void rotlike_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
{
- bRotateLikeConstraint *data = con->data;
+ bRotateLikeConstraint *data = con->data;
- /* target only */
- func(con, (ID **)&data->tar, false, userdata);
+ /* target only */
+ func(con, (ID **)&data->tar, false, userdata);
}
static int rotlike_get_tars(bConstraint *con, ListBase *list)
{
- if (con && list) {
- bRotateLikeConstraint *data = con->data;
- bConstraintTarget *ct;
+ if (con && list) {
+ bRotateLikeConstraint *data = con->data;
+ bConstraintTarget *ct;
- /* standard target-getting macro for single-target constraints */
- SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
+ /* standard target-getting macro for single-target constraints */
+ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1;
- }
+ return 1;
+ }
- return 0;
+ return 0;
}
static void rotlike_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
{
- if (con && list) {
- bRotateLikeConstraint *data = con->data;
- bConstraintTarget *ct = list->first;
+ if (con && list) {
+ bRotateLikeConstraint *data = con->data;
+ bConstraintTarget *ct = list->first;
- /* the following macro is used for all standard single-target constraints */
- SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
- }
+ /* the following macro is used for all standard single-target constraints */
+ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
+ }
}
static void rotlike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets)
{
- bRotateLikeConstraint *data = con->data;
- bConstraintTarget *ct = targets->first;
+ bRotateLikeConstraint *data = con->data;
+ bConstraintTarget *ct = targets->first;
- if (VALID_CONS_TARGET(ct)) {
- float loc[3];
- float eul[3], obeul[3];
- float size[3];
+ if (VALID_CONS_TARGET(ct)) {
+ float loc[3];
+ float eul[3], obeul[3];
+ float size[3];
- copy_v3_v3(loc, cob->matrix[3]);
- mat4_to_size(size, cob->matrix);
+ copy_v3_v3(loc, cob->matrix[3]);
+ mat4_to_size(size, cob->matrix);
- /* to allow compatible rotations, must get both rotations in the order of the owner... */
- mat4_to_eulO(obeul, cob->rotOrder, cob->matrix);
- /* we must get compatible eulers from the beginning because some of them can be modified below (see bug #21875) */
- mat4_to_compatible_eulO(eul, obeul, cob->rotOrder, ct->matrix);
+ /* to allow compatible rotations, must get both rotations in the order of the owner... */
+ mat4_to_eulO(obeul, cob->rotOrder, cob->matrix);
+ /* we must get compatible eulers from the beginning because some of them can be modified below (see bug #21875) */
+ mat4_to_compatible_eulO(eul, obeul, cob->rotOrder, ct->matrix);
- if ((data->flag & ROTLIKE_X) == 0)
- eul[0] = obeul[0];
- else {
- if (data->flag & ROTLIKE_OFFSET)
- rotate_eulO(eul, cob->rotOrder, 'X', obeul[0]);
+ if ((data->flag & ROTLIKE_X) == 0)
+ eul[0] = obeul[0];
+ else {
+ if (data->flag & ROTLIKE_OFFSET)
+ rotate_eulO(eul, cob->rotOrder, 'X', obeul[0]);
- if (data->flag & ROTLIKE_X_INVERT)
- eul[0] *= -1;
- }
+ if (data->flag & ROTLIKE_X_INVERT)
+ eul[0] *= -1;
+ }
- if ((data->flag & ROTLIKE_Y) == 0)
- eul[1] = obeul[1];
- else {
- if (data->flag & ROTLIKE_OFFSET)
- rotate_eulO(eul, cob->rotOrder, 'Y', obeul[1]);
+ if ((data->flag & ROTLIKE_Y) == 0)
+ eul[1] = obeul[1];
+ else {
+ if (data->flag & ROTLIKE_OFFSET)
+ rotate_eulO(eul, cob->rotOrder, 'Y', obeul[1]);
- if (data->flag & ROTLIKE_Y_INVERT)
- eul[1] *= -1;
- }
+ if (data->flag & ROTLIKE_Y_INVERT)
+ eul[1] *= -1;
+ }
- if ((data->flag & ROTLIKE_Z) == 0)
- eul[2] = obeul[2];
- else {
- if (data->flag & ROTLIKE_OFFSET)
- rotate_eulO(eul, cob->rotOrder, 'Z', obeul[2]);
+ if ((data->flag & ROTLIKE_Z) == 0)
+ eul[2] = obeul[2];
+ else {
+ if (data->flag & ROTLIKE_OFFSET)
+ rotate_eulO(eul, cob->rotOrder, 'Z', obeul[2]);
- if (data->flag & ROTLIKE_Z_INVERT)
- eul[2] *= -1;
- }
+ if (data->flag & ROTLIKE_Z_INVERT)
+ eul[2] *= -1;
+ }
- /* good to make eulers compatible again, since we don't know how much they were changed above */
- compatible_eul(eul, obeul);
- loc_eulO_size_to_mat4(cob->matrix, loc, eul, size, cob->rotOrder);
- }
+ /* good to make eulers compatible again, since we don't know how much they were changed above */
+ compatible_eul(eul, obeul);
+ loc_eulO_size_to_mat4(cob->matrix, loc, eul, size, cob->rotOrder);
+ }
}
static bConstraintTypeInfo CTI_ROTLIKE = {
- CONSTRAINT_TYPE_ROTLIKE, /* type */
- sizeof(bRotateLikeConstraint), /* size */
- "Copy Rotation", /* name */
- "bRotateLikeConstraint", /* struct name */
- NULL, /* free data */
- rotlike_id_looper, /* id looper */
- NULL, /* copy data */
- rotlike_new_data, /* new data */
- rotlike_get_tars, /* get constraint targets */
- rotlike_flush_tars, /* flush constraint targets */
- default_get_tarmat, /* get target matrix */
- rotlike_evaluate, /* evaluate */
+ CONSTRAINT_TYPE_ROTLIKE, /* type */
+ sizeof(bRotateLikeConstraint), /* size */
+ "Copy Rotation", /* name */
+ "bRotateLikeConstraint", /* struct name */
+ NULL, /* free data */
+ rotlike_id_looper, /* id looper */
+ NULL, /* copy data */
+ rotlike_new_data, /* new data */
+ rotlike_get_tars, /* get constraint targets */
+ rotlike_flush_tars, /* flush constraint targets */
+ default_get_tarmat, /* get target matrix */
+ rotlike_evaluate, /* evaluate */
};
/* ---------- Copy Scale ---------- */
static void sizelike_new_data(void *cdata)
{
- bSizeLikeConstraint *data = (bSizeLikeConstraint *)cdata;
+ bSizeLikeConstraint *data = (bSizeLikeConstraint *)cdata;
- data->flag = SIZELIKE_X | SIZELIKE_Y | SIZELIKE_Z | SIZELIKE_MULTIPLY;
+ data->flag = SIZELIKE_X | SIZELIKE_Y | SIZELIKE_Z | SIZELIKE_MULTIPLY;
}
static void sizelike_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
{
- bSizeLikeConstraint *data = con->data;
+ bSizeLikeConstraint *data = con->data;
- /* target only */
- func(con, (ID **)&data->tar, false, userdata);
+ /* target only */
+ func(con, (ID **)&data->tar, false, userdata);
}
static int sizelike_get_tars(bConstraint *con, ListBase *list)
{
- if (con && list) {
- bSizeLikeConstraint *data = con->data;
- bConstraintTarget *ct;
+ if (con && list) {
+ bSizeLikeConstraint *data = con->data;
+ bConstraintTarget *ct;
- /* standard target-getting macro for single-target constraints */
- SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
+ /* standard target-getting macro for single-target constraints */
+ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1;
- }
+ return 1;
+ }
- return 0;
+ return 0;
}
static void sizelike_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
{
- if (con && list) {
- bSizeLikeConstraint *data = con->data;
- bConstraintTarget *ct = list->first;
+ if (con && list) {
+ bSizeLikeConstraint *data = con->data;
+ bConstraintTarget *ct = list->first;
- /* the following macro is used for all standard single-target constraints */
- SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
- }
+ /* the following macro is used for all standard single-target constraints */
+ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
+ }
}
static void sizelike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets)
{
- bSizeLikeConstraint *data = con->data;
- bConstraintTarget *ct = targets->first;
-
- if (VALID_CONS_TARGET(ct)) {
- float obsize[3], size[3];
-
- mat4_to_size(size, ct->matrix);
- mat4_to_size(obsize, cob->matrix);
-
- if (data->flag & SIZELIKE_OFFSET) {
- /* Scale is a multiplicative quantity, so adding it makes no sense.
- * However, the additive mode has to stay for backward compatibility. */
- if (data->flag & SIZELIKE_MULTIPLY) {
- /* size[i] *= obsize[i] */
- mul_v3_v3(size, obsize);
- }
- else {
- /* 2.7 compatibility mode: size[i] += (obsize[i] - 1.0f) */
- add_v3_v3(size, obsize);
- add_v3_fl(size, -1.0f);
- }
- }
-
- if ((data->flag & SIZELIKE_X) && (obsize[0] != 0)) {
- mul_v3_fl(cob->matrix[0], size[0] / obsize[0]);
- }
- if ((data->flag & SIZELIKE_Y) && (obsize[1] != 0)) {
- mul_v3_fl(cob->matrix[1], size[1] / obsize[1]);
- }
- if ((data->flag & SIZELIKE_Z) && (obsize[2] != 0)) {
- mul_v3_fl(cob->matrix[2], size[2] / obsize[2]);
- }
- }
+ bSizeLikeConstraint *data = con->data;
+ bConstraintTarget *ct = targets->first;
+
+ if (VALID_CONS_TARGET(ct)) {
+ float obsize[3], size[3];
+
+ mat4_to_size(size, ct->matrix);
+ mat4_to_size(obsize, cob->matrix);
+
+ if (data->flag & SIZELIKE_OFFSET) {
+ /* Scale is a multiplicative quantity, so adding it makes no sense.
+ * However, the additive mode has to stay for backward compatibility. */
+ if (data->flag & SIZELIKE_MULTIPLY) {
+ /* size[i] *= obsize[i] */
+ mul_v3_v3(size, obsize);
+ }
+ else {
+ /* 2.7 compatibility mode: size[i] += (obsize[i] - 1.0f) */
+ add_v3_v3(size, obsize);
+ add_v3_fl(size, -1.0f);
+ }
+ }
+
+ if ((data->flag & SIZELIKE_X) && (obsize[0] != 0)) {
+ mul_v3_fl(cob->matrix[0], size[0] / obsize[0]);
+ }
+ if ((data->flag & SIZELIKE_Y) && (obsize[1] != 0)) {
+ mul_v3_fl(cob->matrix[1], size[1] / obsize[1]);
+ }
+ if ((data->flag & SIZELIKE_Z) && (obsize[2] != 0)) {
+ mul_v3_fl(cob->matrix[2], size[2] / obsize[2]);
+ }
+ }
}
static bConstraintTypeInfo CTI_SIZELIKE = {
- CONSTRAINT_TYPE_SIZELIKE, /* type */
- sizeof(bSizeLikeConstraint), /* size */
- "Copy Scale", /* name */
- "bSizeLikeConstraint", /* struct name */
- NULL, /* free data */
- sizelike_id_looper, /* id looper */
- NULL, /* copy data */
- sizelike_new_data, /* new data */
- sizelike_get_tars, /* get constraint targets */
- sizelike_flush_tars, /* flush constraint targets */
- default_get_tarmat, /* get target matrix */
- sizelike_evaluate, /* evaluate */
+ CONSTRAINT_TYPE_SIZELIKE, /* type */
+ sizeof(bSizeLikeConstraint), /* size */
+ "Copy Scale", /* name */
+ "bSizeLikeConstraint", /* struct name */
+ NULL, /* free data */
+ sizelike_id_looper, /* id looper */
+ NULL, /* copy data */
+ sizelike_new_data, /* new data */
+ sizelike_get_tars, /* get constraint targets */
+ sizelike_flush_tars, /* flush constraint targets */
+ default_get_tarmat, /* get target matrix */
+ sizelike_evaluate, /* evaluate */
};
/* ----------- Copy Transforms ------------- */
static void translike_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
{
- bTransLikeConstraint *data = con->data;
+ bTransLikeConstraint *data = con->data;
- /* target only */
- func(con, (ID **)&data->tar, false, userdata);
+ /* target only */
+ func(con, (ID **)&data->tar, false, userdata);
}
static int translike_get_tars(bConstraint *con, ListBase *list)
{
- if (con && list) {
- bTransLikeConstraint *data = con->data;
- bConstraintTarget *ct;
+ if (con && list) {
+ bTransLikeConstraint *data = con->data;
+ bConstraintTarget *ct;
- /* standard target-getting macro for single-target constraints */
- SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
+ /* standard target-getting macro for single-target constraints */
+ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1;
- }
+ return 1;
+ }
- return 0;
+ return 0;
}
static void translike_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
{
- if (con && list) {
- bTransLikeConstraint *data = con->data;
- bConstraintTarget *ct = list->first;
+ if (con && list) {
+ bTransLikeConstraint *data = con->data;
+ bConstraintTarget *ct = list->first;
- /* the following macro is used for all standard single-target constraints */
- SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
- }
+ /* the following macro is used for all standard single-target constraints */
+ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
+ }
}
static void translike_evaluate(bConstraint *UNUSED(con), bConstraintOb *cob, ListBase *targets)
{
- bConstraintTarget *ct = targets->first;
+ bConstraintTarget *ct = targets->first;
- if (VALID_CONS_TARGET(ct)) {
- /* just copy the entire transform matrix of the target */
- copy_m4_m4(cob->matrix, ct->matrix);
- }
+ if (VALID_CONS_TARGET(ct)) {
+ /* just copy the entire transform matrix of the target */
+ copy_m4_m4(cob->matrix, ct->matrix);
+ }
}
static bConstraintTypeInfo CTI_TRANSLIKE = {
- CONSTRAINT_TYPE_TRANSLIKE, /* type */
- sizeof(bTransLikeConstraint), /* size */
- "Copy Transforms", /* name */
- "bTransLikeConstraint", /* struct name */
- NULL, /* free data */
- translike_id_looper, /* id looper */
- NULL, /* copy data */
- NULL, /* new data */
- translike_get_tars, /* get constraint targets */
- translike_flush_tars, /* flush constraint targets */
- default_get_tarmat_full_bbone, /* get target matrix */
- translike_evaluate, /* evaluate */
+ CONSTRAINT_TYPE_TRANSLIKE, /* type */
+ sizeof(bTransLikeConstraint), /* size */
+ "Copy Transforms", /* name */
+ "bTransLikeConstraint", /* struct name */
+ NULL, /* free data */
+ translike_id_looper, /* id looper */
+ NULL, /* copy data */
+ NULL, /* new data */
+ translike_get_tars, /* get constraint targets */
+ translike_flush_tars, /* flush constraint targets */
+ default_get_tarmat_full_bbone, /* get target matrix */
+ translike_evaluate, /* evaluate */
};
/* ---------- Maintain Volume ---------- */
static void samevolume_new_data(void *cdata)
{
- bSameVolumeConstraint *data = (bSameVolumeConstraint *)cdata;
+ bSameVolumeConstraint *data = (bSameVolumeConstraint *)cdata;
- data->flag = SAMEVOL_Y;
- data->volume = 1.0f;
+ data->flag = SAMEVOL_Y;
+ data->volume = 1.0f;
}
static void samevolume_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UNUSED(targets))
{
- bSameVolumeConstraint *data = con->data;
+ bSameVolumeConstraint *data = con->data;
- float volume = data->volume;
- float fac = 1.0f, total_scale;
- float obsize[3];
+ float volume = data->volume;
+ float fac = 1.0f, total_scale;
+ float obsize[3];
- mat4_to_size(obsize, cob->matrix);
+ mat4_to_size(obsize, cob->matrix);
- /* calculate normalizing scale factor for non-essential values */
- total_scale = obsize[0] * obsize[1] * obsize[2];
- if (total_scale != 0)
- fac = sqrtf(volume / total_scale);
+ /* calculate normalizing scale factor for non-essential values */
+ total_scale = obsize[0] * obsize[1] * obsize[2];
+ if (total_scale != 0)
+ fac = sqrtf(volume / total_scale);
- /* apply scaling factor to the channels not being kept */
- switch (data->flag) {
- case SAMEVOL_X:
- mul_v3_fl(cob->matrix[1], fac);
- mul_v3_fl(cob->matrix[2], fac);
- break;
- case SAMEVOL_Y:
- mul_v3_fl(cob->matrix[0], fac);
- mul_v3_fl(cob->matrix[2], fac);
- break;
- case SAMEVOL_Z:
- mul_v3_fl(cob->matrix[0], fac);
- mul_v3_fl(cob->matrix[1], fac);
- break;
- }
+ /* apply scaling factor to the channels not being kept */
+ switch (data->flag) {
+ case SAMEVOL_X:
+ mul_v3_fl(cob->matrix[1], fac);
+ mul_v3_fl(cob->matrix[2], fac);
+ break;
+ case SAMEVOL_Y:
+ mul_v3_fl(cob->matrix[0], fac);
+ mul_v3_fl(cob->matrix[2], fac);
+ break;
+ case SAMEVOL_Z:
+ mul_v3_fl(cob->matrix[0], fac);
+ mul_v3_fl(cob->matrix[1], fac);
+ break;
+ }
}
static bConstraintTypeInfo CTI_SAMEVOL = {
- CONSTRAINT_TYPE_SAMEVOL, /* type */
- sizeof(bSameVolumeConstraint), /* size */
- "Maintain Volume", /* name */
- "bSameVolumeConstraint", /* struct name */
- NULL, /* free data */
- NULL, /* id looper */
- NULL, /* copy data */
- samevolume_new_data, /* new data */
- NULL, /* get constraint targets */
- NULL, /* flush constraint targets */
- NULL, /* get target matrix */
- samevolume_evaluate, /* evaluate */
+ CONSTRAINT_TYPE_SAMEVOL, /* type */
+ sizeof(bSameVolumeConstraint), /* size */
+ "Maintain Volume", /* name */
+ "bSameVolumeConstraint", /* struct name */
+ NULL, /* free data */
+ NULL, /* id looper */
+ NULL, /* copy data */
+ samevolume_new_data, /* new data */
+ NULL, /* get constraint targets */
+ NULL, /* flush constraint targets */
+ NULL, /* get target matrix */
+ samevolume_evaluate, /* evaluate */
};
/* ----------- Python Constraint -------------- */
static void pycon_free(bConstraint *con)
{
- bPythonConstraint *data = con->data;
+ bPythonConstraint *data = con->data;
- /* id-properties */
- IDP_FreeProperty(data->prop);
- MEM_freeN(data->prop);
+ /* id-properties */
+ IDP_FreeProperty(data->prop);
+ MEM_freeN(data->prop);
- /* multiple targets */
- BLI_freelistN(&data->targets);
+ /* multiple targets */
+ BLI_freelistN(&data->targets);
}
static void pycon_copy(bConstraint *con, bConstraint *srccon)
{
- bPythonConstraint *pycon = (bPythonConstraint *)con->data;
- bPythonConstraint *opycon = (bPythonConstraint *)srccon->data;
+ bPythonConstraint *pycon = (bPythonConstraint *)con->data;
+ bPythonConstraint *opycon = (bPythonConstraint *)srccon->data;
- pycon->prop = IDP_CopyProperty(opycon->prop);
- BLI_duplicatelist(&pycon->targets, &opycon->targets);
+ pycon->prop = IDP_CopyProperty(opycon->prop);
+ BLI_duplicatelist(&pycon->targets, &opycon->targets);
}
static void pycon_new_data(void *cdata)
{
- bPythonConstraint *data = (bPythonConstraint *)cdata;
+ bPythonConstraint *data = (bPythonConstraint *)cdata;
- /* everything should be set correctly by calloc, except for the prop->type constant.*/
- data->prop = MEM_callocN(sizeof(IDProperty), "PyConstraintProps");
- data->prop->type = IDP_GROUP;
+ /* everything should be set correctly by calloc, except for the prop->type constant.*/
+ data->prop = MEM_callocN(sizeof(IDProperty), "PyConstraintProps");
+ data->prop->type = IDP_GROUP;
}
static int pycon_get_tars(bConstraint *con, ListBase *list)
{
- if (con && list) {
- bPythonConstraint *data = con->data;
+ if (con && list) {
+ bPythonConstraint *data = con->data;
- list->first = data->targets.first;
- list->last = data->targets.last;
+ list->first = data->targets.first;
+ list->last = data->targets.last;
- return data->tarnum;
- }
+ return data->tarnum;
+ }
- return 0;
+ return 0;
}
static void pycon_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
{
- bPythonConstraint *data = con->data;
- bConstraintTarget *ct;
+ bPythonConstraint *data = con->data;
+ bConstraintTarget *ct;
- /* targets */
- for (ct = data->targets.first; ct; ct = ct->next)
- func(con, (ID **)&ct->tar, false, userdata);
+ /* targets */
+ for (ct = data->targets.first; ct; ct = ct->next)
+ func(con, (ID **)&ct->tar, false, userdata);
- /* script */
- func(con, (ID **)&data->text, true, userdata);
+ /* script */
+ func(con, (ID **)&data->text, true, userdata);
}
/* Whether this approach is maintained remains to be seen (aligorith) */
static void pycon_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
- bConstraint *con, bConstraintOb *UNUSED(cob),
- bConstraintTarget *ct, float UNUSED(ctime))
+ bConstraint *con,
+ bConstraintOb *UNUSED(cob),
+ bConstraintTarget *ct,
+ float UNUSED(ctime))
{
#ifdef WITH_PYTHON
- bPythonConstraint *data = con->data;
+ bPythonConstraint *data = con->data;
#endif
- if (VALID_CONS_TARGET(ct)) {
- if (ct->tar->type == OB_CURVE && ct->tar->runtime.curve_cache == NULL) {
- unit_m4(ct->matrix);
- return;
- }
-
- /* firstly calculate the matrix the normal way, then let the py-function override
- * this matrix if it needs to do so
- */
- constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail);
-
- /* only execute target calculation if allowed */
+ if (VALID_CONS_TARGET(ct)) {
+ if (ct->tar->type == OB_CURVE && ct->tar->runtime.curve_cache == NULL) {
+ unit_m4(ct->matrix);
+ return;
+ }
+
+ /* firstly calculate the matrix the normal way, then let the py-function override
+ * this matrix if it needs to do so
+ */
+ constraint_target_to_mat4(ct->tar,
+ ct->subtarget,
+ ct->matrix,
+ CONSTRAINT_SPACE_WORLD,
+ ct->space,
+ con->flag,
+ con->headtail);
+
+ /* only execute target calculation if allowed */
#ifdef WITH_PYTHON
- if (G.f & G_FLAG_SCRIPT_AUTOEXEC)
- BPY_pyconstraint_target(data, ct);
+ if (G.f & G_FLAG_SCRIPT_AUTOEXEC)
+ BPY_pyconstraint_target(data, ct);
#endif
- }
- else if (ct)
- unit_m4(ct->matrix);
+ }
+ else if (ct)
+ unit_m4(ct->matrix);
}
static void pycon_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets)
{
#ifndef WITH_PYTHON
- UNUSED_VARS(con, cob, targets);
- return;
+ UNUSED_VARS(con, cob, targets);
+ return;
#else
- bPythonConstraint *data = con->data;
+ bPythonConstraint *data = con->data;
- /* only evaluate in python if we're allowed to do so */
- if ((G.f & G_FLAG_SCRIPT_AUTOEXEC) == 0) return;
+ /* only evaluate in python if we're allowed to do so */
+ if ((G.f & G_FLAG_SCRIPT_AUTOEXEC) == 0)
+ return;
- /* Now, run the actual 'constraint' function, which should only access the matrices */
- BPY_pyconstraint_exec(data, cob, targets);
+ /* Now, run the actual 'constraint' function, which should only access the matrices */
+ BPY_pyconstraint_exec(data, cob, targets);
#endif /* WITH_PYTHON */
}
static bConstraintTypeInfo CTI_PYTHON = {
- CONSTRAINT_TYPE_PYTHON, /* type */
- sizeof(bPythonConstraint), /* size */
- "Script", /* name */
- "bPythonConstraint", /* struct name */
- pycon_free, /* free data */
- pycon_id_looper, /* id looper */
- pycon_copy, /* copy data */
- pycon_new_data, /* new data */
- pycon_get_tars, /* get constraint targets */
- NULL, /* flush constraint targets */
- pycon_get_tarmat, /* get target matrix */
- pycon_evaluate, /* evaluate */
+ CONSTRAINT_TYPE_PYTHON, /* type */
+ sizeof(bPythonConstraint), /* size */
+ "Script", /* name */
+ "bPythonConstraint", /* struct name */
+ pycon_free, /* free data */
+ pycon_id_looper, /* id looper */
+ pycon_copy, /* copy data */
+ pycon_new_data, /* new data */
+ pycon_get_tars, /* get constraint targets */
+ NULL, /* flush constraint targets */
+ pycon_get_tarmat, /* get target matrix */
+ pycon_evaluate, /* evaluate */
};
/* ----------- Armature Constraint -------------- */
static void armdef_free(bConstraint *con)
{
- bArmatureConstraint *data = con->data;
+ bArmatureConstraint *data = con->data;
- /* Target list. */
- BLI_freelistN(&data->targets);
+ /* Target list. */
+ BLI_freelistN(&data->targets);
}
static void armdef_copy(bConstraint *con, bConstraint *srccon)
{
- bArmatureConstraint *pcon = (bArmatureConstraint *)con->data;
- bArmatureConstraint *opcon = (bArmatureConstraint *)srccon->data;
+ bArmatureConstraint *pcon = (bArmatureConstraint *)con->data;
+ bArmatureConstraint *opcon = (bArmatureConstraint *)srccon->data;
- BLI_duplicatelist(&pcon->targets, &opcon->targets);
+ BLI_duplicatelist(&pcon->targets, &opcon->targets);
}
static int armdef_get_tars(bConstraint *con, ListBase *list)
{
- if (con && list) {
- bArmatureConstraint *data = con->data;
+ if (con && list) {
+ bArmatureConstraint *data = con->data;
- *list = data->targets;
+ *list = data->targets;
- return BLI_listbase_count(&data->targets);
- }
+ return BLI_listbase_count(&data->targets);
+ }
- return 0;
+ return 0;
}
static void armdef_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
{
- bArmatureConstraint *data = con->data;
- bConstraintTarget *ct;
+ bArmatureConstraint *data = con->data;
+ bConstraintTarget *ct;
- /* Target list. */
- for (ct = data->targets.first; ct; ct = ct->next) {
- func(con, (ID **)&ct->tar, false, userdata);
- }
+ /* Target list. */
+ for (ct = data->targets.first; ct; ct = ct->next) {
+ func(con, (ID **)&ct->tar, false, userdata);
+ }
}
/* Compute the world space pose matrix of the target bone. */
static void armdef_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
- bConstraint *UNUSED(con), bConstraintOb *UNUSED(cob),
- bConstraintTarget *ct, float UNUSED(ctime))
+ bConstraint *UNUSED(con),
+ bConstraintOb *UNUSED(cob),
+ bConstraintTarget *ct,
+ float UNUSED(ctime))
{
- if (ct != NULL) {
- if (ct->tar && ct->tar->type == OB_ARMATURE) {
- bPoseChannel *pchan = BKE_pose_channel_find_name(ct->tar->pose, ct->subtarget);
+ if (ct != NULL) {
+ if (ct->tar && ct->tar->type == OB_ARMATURE) {
+ bPoseChannel *pchan = BKE_pose_channel_find_name(ct->tar->pose, ct->subtarget);
- if (pchan != NULL) {
- mul_m4_m4m4(ct->matrix, ct->tar->obmat, pchan->pose_mat);
- return;
- }
- }
+ if (pchan != NULL) {
+ mul_m4_m4m4(ct->matrix, ct->tar->obmat, pchan->pose_mat);
+ return;
+ }
+ }
- unit_m4(ct->matrix);
- }
+ unit_m4(ct->matrix);
+ }
}
-static void armdef_accumulate_matrix(float obmat[4][4], float iobmat[4][4], float basemat[4][4], float bonemat[4][4], float weight, float r_sum_mat[4][4], DualQuat *r_sum_dq)
+static void armdef_accumulate_matrix(float obmat[4][4],
+ float iobmat[4][4],
+ float basemat[4][4],
+ float bonemat[4][4],
+ float weight,
+ float r_sum_mat[4][4],
+ DualQuat *r_sum_dq)
{
- if (weight == 0.0f)
- return;
+ if (weight == 0.0f)
+ return;
- /* Convert the selected matrix into object space. */
- float mat[4][4];
- mul_m4_series(mat, obmat, bonemat, iobmat);
+ /* Convert the selected matrix into object space. */
+ float mat[4][4];
+ mul_m4_series(mat, obmat, bonemat, iobmat);
- /* Accumulate the transformation. */
- if (r_sum_dq != NULL) {
- DualQuat tmpdq;
+ /* Accumulate the transformation. */
+ if (r_sum_dq != NULL) {
+ DualQuat tmpdq;
- mat4_to_dquat(&tmpdq, basemat, mat);
- add_weighted_dq_dq(r_sum_dq, &tmpdq, weight);
- }
- else {
- madd_m4_m4m4fl(r_sum_mat, r_sum_mat, mat, weight);
- }
+ mat4_to_dquat(&tmpdq, basemat, mat);
+ add_weighted_dq_dq(r_sum_dq, &tmpdq, weight);
+ }
+ else {
+ madd_m4_m4m4fl(r_sum_mat, r_sum_mat, mat, weight);
+ }
}
/* Compute and accumulate transformation for a single target bone. */
-static void armdef_accumulate_bone(bConstraintTarget *ct, bPoseChannel *pchan, const float wco[3], bool force_envelope, float *r_totweight, float r_sum_mat[4][4], DualQuat *r_sum_dq)
-{
- float iobmat[4][4], basemat[4][4], co[3];
- Bone *bone = pchan->bone;
- float weight = ct->weight;
-
- /* Our object's location in target pose space. */
- invert_m4_m4(iobmat, ct->tar->obmat);
- mul_v3_m4v3(co, iobmat, wco);
-
- /* Multiply by the envelope weight when appropriate. */
- if (force_envelope || (bone->flag & BONE_MULT_VG_ENV)) {
- weight *= distfactor_to_bone(co, bone->arm_head, bone->arm_tail,
- bone->rad_head, bone->rad_tail, bone->dist);
- }
-
- /* Compute the quaternion base matrix. */
- if (r_sum_dq != NULL) {
- mul_m4_series(basemat, ct->tar->obmat, bone->arm_mat, iobmat);
- }
-
- /* Find the correct bone transform matrix in world space. */
- if (bone->segments > 1 && bone->segments == pchan->runtime.bbone_segments) {
- Mat4 *b_bone_mats = pchan->runtime.bbone_deform_mats;
- float (*iamat)[4] = b_bone_mats[0].mat;
-
- /* The target is a B-Bone:
- * FIRST: find the segment (see b_bone_deform in armature.c)
- * Need to transform co back to bonespace, only need y. */
- float y = iamat[0][1] * co[0] + iamat[1][1] * co[1] + iamat[2][1] * co[2] + iamat[3][1];
-
- /* Blend the matrix. */
- int index;
- float blend;
- BKE_pchan_bbone_deform_segment_index(pchan, y / bone->length, &index, &blend);
-
- armdef_accumulate_matrix(ct->tar->obmat, iobmat, basemat, b_bone_mats[index + 1].mat, weight * (1.0f - blend), r_sum_mat, r_sum_dq);
- armdef_accumulate_matrix(ct->tar->obmat, iobmat, basemat, b_bone_mats[index + 2].mat, weight * blend, r_sum_mat, r_sum_dq);
- }
- else {
- /* Simple bone. This requires DEG_OPCODE_BONE_DONE dependency due to chan_mat. */
- armdef_accumulate_matrix(ct->tar->obmat, iobmat, basemat, pchan->chan_mat, weight, r_sum_mat, r_sum_dq);
- }
-
- /* Accumulate the weight. */
- *r_totweight += weight;
+static void armdef_accumulate_bone(bConstraintTarget *ct,
+ bPoseChannel *pchan,
+ const float wco[3],
+ bool force_envelope,
+ float *r_totweight,
+ float r_sum_mat[4][4],
+ DualQuat *r_sum_dq)
+{
+ float iobmat[4][4], basemat[4][4], co[3];
+ Bone *bone = pchan->bone;
+ float weight = ct->weight;
+
+ /* Our object's location in target pose space. */
+ invert_m4_m4(iobmat, ct->tar->obmat);
+ mul_v3_m4v3(co, iobmat, wco);
+
+ /* Multiply by the envelope weight when appropriate. */
+ if (force_envelope || (bone->flag & BONE_MULT_VG_ENV)) {
+ weight *= distfactor_to_bone(
+ co, bone->arm_head, bone->arm_tail, bone->rad_head, bone->rad_tail, bone->dist);
+ }
+
+ /* Compute the quaternion base matrix. */
+ if (r_sum_dq != NULL) {
+ mul_m4_series(basemat, ct->tar->obmat, bone->arm_mat, iobmat);
+ }
+
+ /* Find the correct bone transform matrix in world space. */
+ if (bone->segments > 1 && bone->segments == pchan->runtime.bbone_segments) {
+ Mat4 *b_bone_mats = pchan->runtime.bbone_deform_mats;
+ float(*iamat)[4] = b_bone_mats[0].mat;
+
+ /* The target is a B-Bone:
+ * FIRST: find the segment (see b_bone_deform in armature.c)
+ * Need to transform co back to bonespace, only need y. */
+ float y = iamat[0][1] * co[0] + iamat[1][1] * co[1] + iamat[2][1] * co[2] + iamat[3][1];
+
+ /* Blend the matrix. */
+ int index;
+ float blend;
+ BKE_pchan_bbone_deform_segment_index(pchan, y / bone->length, &index, &blend);
+
+ armdef_accumulate_matrix(ct->tar->obmat,
+ iobmat,
+ basemat,
+ b_bone_mats[index + 1].mat,
+ weight * (1.0f - blend),
+ r_sum_mat,
+ r_sum_dq);
+ armdef_accumulate_matrix(ct->tar->obmat,
+ iobmat,
+ basemat,
+ b_bone_mats[index + 2].mat,
+ weight * blend,
+ r_sum_mat,
+ r_sum_dq);
+ }
+ else {
+ /* Simple bone. This requires DEG_OPCODE_BONE_DONE dependency due to chan_mat. */
+ armdef_accumulate_matrix(
+ ct->tar->obmat, iobmat, basemat, pchan->chan_mat, weight, r_sum_mat, r_sum_dq);
+ }
+
+ /* Accumulate the weight. */
+ *r_totweight += weight;
}
static void armdef_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets)
{
- bArmatureConstraint *data = con->data;
+ bArmatureConstraint *data = con->data;
- float sum_mat[4][4], input_co[3];
- DualQuat sum_dq;
- float weight = 0.0f;
+ float sum_mat[4][4], input_co[3];
+ DualQuat sum_dq;
+ float weight = 0.0f;
- /* Prepare for blending. */
- zero_m4(sum_mat);
- memset(&sum_dq, 0, sizeof(sum_dq));
+ /* Prepare for blending. */
+ zero_m4(sum_mat);
+ memset(&sum_dq, 0, sizeof(sum_dq));
- DualQuat *pdq = (data->flag & CONSTRAINT_ARMATURE_QUATERNION) ? &sum_dq : NULL;
- bool use_envelopes = (data->flag & CONSTRAINT_ARMATURE_ENVELOPE) != 0;
+ DualQuat *pdq = (data->flag & CONSTRAINT_ARMATURE_QUATERNION) ? &sum_dq : NULL;
+ bool use_envelopes = (data->flag & CONSTRAINT_ARMATURE_ENVELOPE) != 0;
- if (cob->pchan && cob->pchan->bone && !(data->flag & CONSTRAINT_ARMATURE_CUR_LOCATION)) {
- /* For constraints on bones, use the rest position to bind b-bone segments
- * and envelopes, to allow safely changing the bone location as if parented. */
- copy_v3_v3(input_co, cob->pchan->bone->arm_head);
- mul_m4_v3(cob->ob->obmat, input_co);
- }
- else {
- copy_v3_v3(input_co, cob->matrix[3]);
- }
+ if (cob->pchan && cob->pchan->bone && !(data->flag & CONSTRAINT_ARMATURE_CUR_LOCATION)) {
+ /* For constraints on bones, use the rest position to bind b-bone segments
+ * and envelopes, to allow safely changing the bone location as if parented. */
+ copy_v3_v3(input_co, cob->pchan->bone->arm_head);
+ mul_m4_v3(cob->ob->obmat, input_co);
+ }
+ else {
+ copy_v3_v3(input_co, cob->matrix[3]);
+ }
- /* Process all targets. */
- for (bConstraintTarget *ct = targets->first; ct; ct = ct->next) {
- if (ct->weight <= 0.0f) {
- continue;
- }
+ /* Process all targets. */
+ for (bConstraintTarget *ct = targets->first; ct; ct = ct->next) {
+ if (ct->weight <= 0.0f) {
+ continue;
+ }
- /* Lookup the bone and abort if failed. */
- if (!VALID_CONS_TARGET(ct) || ct->tar->type != OB_ARMATURE) {
- return;
- }
+ /* Lookup the bone and abort if failed. */
+ if (!VALID_CONS_TARGET(ct) || ct->tar->type != OB_ARMATURE) {
+ return;
+ }
- bPoseChannel *pchan = BKE_pose_channel_find_name(ct->tar->pose, ct->subtarget);
+ bPoseChannel *pchan = BKE_pose_channel_find_name(ct->tar->pose, ct->subtarget);
- if (pchan == NULL || pchan->bone == NULL) {
- return;
- }
+ if (pchan == NULL || pchan->bone == NULL) {
+ return;
+ }
- armdef_accumulate_bone(ct, pchan, input_co, use_envelopes, &weight, sum_mat, pdq);
- }
+ armdef_accumulate_bone(ct, pchan, input_co, use_envelopes, &weight, sum_mat, pdq);
+ }
- /* Compute the final transform. */
- if (weight > 0.0f) {
- if (pdq != NULL) {
- normalize_dq(pdq, weight);
- dquat_to_mat4(sum_mat, pdq);
- }
- else {
- mul_m4_fl(sum_mat, 1.0f / weight);
- }
+ /* Compute the final transform. */
+ if (weight > 0.0f) {
+ if (pdq != NULL) {
+ normalize_dq(pdq, weight);
+ dquat_to_mat4(sum_mat, pdq);
+ }
+ else {
+ mul_m4_fl(sum_mat, 1.0f / weight);
+ }
- /* Apply the transform to the result matrix. */
- mul_m4_m4m4(cob->matrix, sum_mat, cob->matrix);
- }
+ /* Apply the transform to the result matrix. */
+ mul_m4_m4m4(cob->matrix, sum_mat, cob->matrix);
+ }
}
static bConstraintTypeInfo CTI_ARMATURE = {
- CONSTRAINT_TYPE_ARMATURE, /* type */
- sizeof(bArmatureConstraint), /* size */
- "Armature", /* name */
- "bArmatureConstraint", /* struct name */
- armdef_free, /* free data */
- armdef_id_looper, /* id looper */
- armdef_copy, /* copy data */
- NULL, /* new data */
- armdef_get_tars, /* get constraint targets */
- NULL, /* flush constraint targets */
- armdef_get_tarmat, /* get target matrix */
- armdef_evaluate, /* evaluate */
+ CONSTRAINT_TYPE_ARMATURE, /* type */
+ sizeof(bArmatureConstraint), /* size */
+ "Armature", /* name */
+ "bArmatureConstraint", /* struct name */
+ armdef_free, /* free data */
+ armdef_id_looper, /* id looper */
+ armdef_copy, /* copy data */
+ NULL, /* new data */
+ armdef_get_tars, /* get constraint targets */
+ NULL, /* flush constraint targets */
+ armdef_get_tarmat, /* get target matrix */
+ armdef_evaluate, /* evaluate */
};
/* -------- Action Constraint ----------- */
static void actcon_new_data(void *cdata)
{
- bActionConstraint *data = (bActionConstraint *)cdata;
+ bActionConstraint *data = (bActionConstraint *)cdata;
- /* set type to 20 (Loc X), as 0 is Rot X for backwards compatibility */
- data->type = 20;
+ /* set type to 20 (Loc X), as 0 is Rot X for backwards compatibility */
+ data->type = 20;
}
static void actcon_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
{
- bActionConstraint *data = con->data;
+ bActionConstraint *data = con->data;
- /* target */
- func(con, (ID **)&data->tar, false, userdata);
+ /* target */
+ func(con, (ID **)&data->tar, false, userdata);
- /* action */
- func(con, (ID **)&data->act, true, userdata);
+ /* action */
+ func(con, (ID **)&data->act, true, userdata);
}
static int actcon_get_tars(bConstraint *con, ListBase *list)
{
- if (con && list) {
- bActionConstraint *data = con->data;
- bConstraintTarget *ct;
+ if (con && list) {
+ bActionConstraint *data = con->data;
+ bConstraintTarget *ct;
- /* standard target-getting macro for single-target constraints */
- SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
+ /* standard target-getting macro for single-target constraints */
+ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1;
- }
+ return 1;
+ }
- return 0;
+ return 0;
}
static void actcon_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
{
- if (con && list) {
- bActionConstraint *data = con->data;
- bConstraintTarget *ct = list->first;
-
- /* the following macro is used for all standard single-target constraints */
- SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
- }
-}
-
-static void actcon_get_tarmat(struct Depsgraph *UNUSED(depsgraph), bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
-{
- bActionConstraint *data = con->data;
-
- if (VALID_CONS_TARGET(ct)) {
- float tempmat[4][4], vec[3];
- float s, t;
- short axis;
-
- /* initialize return matrix */
- unit_m4(ct->matrix);
-
- /* get the transform matrix of the target */
- constraint_target_to_mat4(ct->tar, ct->subtarget, tempmat, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail);
-
- /* determine where in transform range target is */
- /* data->type is mapped as follows for backwards compatibility:
- * 00,01,02 - rotation (it used to be like this)
- * 10,11,12 - scaling
- * 20,21,22 - location
- */
- if (data->type < 10) {
- /* extract rotation (is in whatever space target should be in) */
- mat4_to_eul(vec, tempmat);
- mul_v3_fl(vec, RAD2DEGF(1.0f)); /* rad -> deg */
- axis = data->type;
- }
- else if (data->type < 20) {
- /* extract scaling (is in whatever space target should be in) */
- mat4_to_size(vec, tempmat);
- axis = data->type - 10;
- }
- else {
- /* extract location */
- copy_v3_v3(vec, tempmat[3]);
- axis = data->type - 20;
- }
-
- BLI_assert((unsigned int)axis < 3);
-
- /* Target defines the animation */
- s = (vec[axis] - data->min) / (data->max - data->min);
- CLAMP(s, 0, 1);
- t = (s * (data->end - data->start)) + data->start;
-
- if (G.debug & G_DEBUG)
- printf("do Action Constraint %s - Ob %s Pchan %s\n", con->name, cob->ob->id.name + 2, (cob->pchan) ? cob->pchan->name : NULL);
-
- /* Get the appropriate information from the action */
- if (cob->type == CONSTRAINT_OBTYPE_OBJECT || (data->flag & ACTCON_BONE_USE_OBJECT_ACTION)) {
- Object workob;
-
- /* evaluate using workob */
- /* FIXME: we don't have any consistent standards on limiting effects on object... */
- what_does_obaction(cob->ob, &workob, NULL, data->act, NULL, t);
- BKE_object_to_mat4(&workob, ct->matrix);
- }
- else if (cob->type == CONSTRAINT_OBTYPE_BONE) {
- Object workob;
- bPose pose = {{0}};
- bPoseChannel *pchan, *tchan;
-
- /* make a copy of the bone of interest in the temp pose before evaluating action, so that it can get set
- * - we need to manually copy over a few settings, including rotation order, otherwise this fails
- */
- pchan = cob->pchan;
-
- tchan = BKE_pose_channel_verify(&pose, pchan->name);
- tchan->rotmode = pchan->rotmode;
-
- /* evaluate action using workob (it will only set the PoseChannel in question) */
- what_does_obaction(cob->ob, &workob, &pose, data->act, pchan->name, t);
-
- /* convert animation to matrices for use here */
- BKE_pchan_calc_mat(tchan);
- copy_m4_m4(ct->matrix, tchan->chan_mat);
-
- /* Clean up */
- BKE_pose_free_data(&pose);
- }
- else {
- /* behavior undefined... */
- puts("Error: unknown owner type for Action Constraint");
- }
- }
+ if (con && list) {
+ bActionConstraint *data = con->data;
+ bConstraintTarget *ct = list->first;
+
+ /* the following macro is used for all standard single-target constraints */
+ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
+ }
+}
+
+static void actcon_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
+ bConstraint *con,
+ bConstraintOb *cob,
+ bConstraintTarget *ct,
+ float UNUSED(ctime))
+{
+ bActionConstraint *data = con->data;
+
+ if (VALID_CONS_TARGET(ct)) {
+ float tempmat[4][4], vec[3];
+ float s, t;
+ short axis;
+
+ /* initialize return matrix */
+ unit_m4(ct->matrix);
+
+ /* get the transform matrix of the target */
+ constraint_target_to_mat4(ct->tar,
+ ct->subtarget,
+ tempmat,
+ CONSTRAINT_SPACE_WORLD,
+ ct->space,
+ con->flag,
+ con->headtail);
+
+ /* determine where in transform range target is */
+ /* data->type is mapped as follows for backwards compatibility:
+ * 00,01,02 - rotation (it used to be like this)
+ * 10,11,12 - scaling
+ * 20,21,22 - location
+ */
+ if (data->type < 10) {
+ /* extract rotation (is in whatever space target should be in) */
+ mat4_to_eul(vec, tempmat);
+ mul_v3_fl(vec, RAD2DEGF(1.0f)); /* rad -> deg */
+ axis = data->type;
+ }
+ else if (data->type < 20) {
+ /* extract scaling (is in whatever space target should be in) */
+ mat4_to_size(vec, tempmat);
+ axis = data->type - 10;
+ }
+ else {
+ /* extract location */
+ copy_v3_v3(vec, tempmat[3]);
+ axis = data->type - 20;
+ }
+
+ BLI_assert((unsigned int)axis < 3);
+
+ /* Target defines the animation */
+ s = (vec[axis] - data->min) / (data->max - data->min);
+ CLAMP(s, 0, 1);
+ t = (s * (data->end - data->start)) + data->start;
+
+ if (G.debug & G_DEBUG)
+ printf("do Action Constraint %s - Ob %s Pchan %s\n",
+ con->name,
+ cob->ob->id.name + 2,
+ (cob->pchan) ? cob->pchan->name : NULL);
+
+ /* Get the appropriate information from the action */
+ if (cob->type == CONSTRAINT_OBTYPE_OBJECT || (data->flag & ACTCON_BONE_USE_OBJECT_ACTION)) {
+ Object workob;
+
+ /* evaluate using workob */
+ /* FIXME: we don't have any consistent standards on limiting effects on object... */
+ what_does_obaction(cob->ob, &workob, NULL, data->act, NULL, t);
+ BKE_object_to_mat4(&workob, ct->matrix);
+ }
+ else if (cob->type == CONSTRAINT_OBTYPE_BONE) {
+ Object workob;
+ bPose pose = {{0}};
+ bPoseChannel *pchan, *tchan;
+
+ /* make a copy of the bone of interest in the temp pose before evaluating action, so that it can get set
+ * - we need to manually copy over a few settings, including rotation order, otherwise this fails
+ */
+ pchan = cob->pchan;
+
+ tchan = BKE_pose_channel_verify(&pose, pchan->name);
+ tchan->rotmode = pchan->rotmode;
+
+ /* evaluate action using workob (it will only set the PoseChannel in question) */
+ what_does_obaction(cob->ob, &workob, &pose, data->act, pchan->name, t);
+
+ /* convert animation to matrices for use here */
+ BKE_pchan_calc_mat(tchan);
+ copy_m4_m4(ct->matrix, tchan->chan_mat);
+
+ /* Clean up */
+ BKE_pose_free_data(&pose);
+ }
+ else {
+ /* behavior undefined... */
+ puts("Error: unknown owner type for Action Constraint");
+ }
+ }
}
static void actcon_evaluate(bConstraint *UNUSED(con), bConstraintOb *cob, ListBase *targets)
{
- bConstraintTarget *ct = targets->first;
+ bConstraintTarget *ct = targets->first;
- if (VALID_CONS_TARGET(ct)) {
- float temp[4][4];
+ if (VALID_CONS_TARGET(ct)) {
+ float temp[4][4];
- /* Nice and simple... we just need to multiply the matrices, as the get_target_matrix
- * function has already taken care of everything else.
- */
- copy_m4_m4(temp, cob->matrix);
- mul_m4_m4m4(cob->matrix, temp, ct->matrix);
- }
+ /* Nice and simple... we just need to multiply the matrices, as the get_target_matrix
+ * function has already taken care of everything else.
+ */
+ copy_m4_m4(temp, cob->matrix);
+ mul_m4_m4m4(cob->matrix, temp, ct->matrix);
+ }
}
static bConstraintTypeInfo CTI_ACTION = {
- CONSTRAINT_TYPE_ACTION, /* type */
- sizeof(bActionConstraint), /* size */
- "Action", /* name */
- "bActionConstraint", /* struct name */
- NULL, /* free data */
- actcon_id_looper, /* id looper */
- NULL, /* copy data */
- actcon_new_data, /* new data */
- actcon_get_tars, /* get constraint targets */
- actcon_flush_tars, /* flush constraint targets */
- actcon_get_tarmat, /* get target matrix */
- actcon_evaluate, /* evaluate */
+ CONSTRAINT_TYPE_ACTION, /* type */
+ sizeof(bActionConstraint), /* size */
+ "Action", /* name */
+ "bActionConstraint", /* struct name */
+ NULL, /* free data */
+ actcon_id_looper, /* id looper */
+ NULL, /* copy data */
+ actcon_new_data, /* new data */
+ actcon_get_tars, /* get constraint targets */
+ actcon_flush_tars, /* flush constraint targets */
+ actcon_get_tarmat, /* get target matrix */
+ actcon_evaluate, /* evaluate */
};
/* --------- Locked Track ---------- */
static void locktrack_new_data(void *cdata)
{
- bLockTrackConstraint *data = (bLockTrackConstraint *)cdata;
+ bLockTrackConstraint *data = (bLockTrackConstraint *)cdata;
- data->trackflag = TRACK_Y;
- data->lockflag = LOCK_Z;
+ data->trackflag = TRACK_Y;
+ data->lockflag = LOCK_Z;
}
static void locktrack_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
{
- bLockTrackConstraint *data = con->data;
+ bLockTrackConstraint *data = con->data;
- /* target only */
- func(con, (ID **)&data->tar, false, userdata);
+ /* target only */
+ func(con, (ID **)&data->tar, false, userdata);
}
static int locktrack_get_tars(bConstraint *con, ListBase *list)
{
- if (con && list) {
- bLockTrackConstraint *data = con->data;
- bConstraintTarget *ct;
+ if (con && list) {
+ bLockTrackConstraint *data = con->data;
+ bConstraintTarget *ct;
- /* the following macro is used for all standard single-target constraints */
- SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
+ /* the following macro is used for all standard single-target constraints */
+ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1;
- }
+ return 1;
+ }
- return 0;
+ return 0;
}
static void locktrack_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
{
- if (con && list) {
- bLockTrackConstraint *data = con->data;
- bConstraintTarget *ct = list->first;
+ if (con && list) {
+ bLockTrackConstraint *data = con->data;
+ bConstraintTarget *ct = list->first;
- /* the following macro is used for all standard single-target constraints */
- SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
- }
+ /* the following macro is used for all standard single-target constraints */
+ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
+ }
}
static void locktrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets)
{
- bLockTrackConstraint *data = con->data;
- bConstraintTarget *ct = targets->first;
-
- if (VALID_CONS_TARGET(ct)) {
- float vec[3], vec2[3];
- float totmat[3][3];
- float tmpmat[3][3];
- float invmat[3][3];
- float mdet;
-
- /* Vector object -> target */
- sub_v3_v3v3(vec, ct->matrix[3], cob->matrix[3]);
- switch (data->lockflag) {
- case LOCK_X: /* LOCK X */
- {
- switch (data->trackflag) {
- case TRACK_Y: /* LOCK X TRACK Y */
- {
- /* Projection of Vector on the plane */
- project_v3_v3v3(vec2, vec, cob->matrix[0]);
- sub_v3_v3v3(totmat[1], vec, vec2);
- normalize_v3(totmat[1]);
-
- /* the x axis is fixed */
- normalize_v3_v3(totmat[0], cob->matrix[0]);
-
- /* the z axis gets mapped onto a third orthogonal vector */
- cross_v3_v3v3(totmat[2], totmat[0], totmat[1]);
- break;
- }
- case TRACK_Z: /* LOCK X TRACK Z */
- {
- /* Projection of Vector on the plane */
- project_v3_v3v3(vec2, vec, cob->matrix[0]);
- sub_v3_v3v3(totmat[2], vec, vec2);
- normalize_v3(totmat[2]);
-
- /* the x axis is fixed */
- normalize_v3_v3(totmat[0], cob->matrix[0]);
-
- /* the z axis gets mapped onto a third orthogonal vector */
- cross_v3_v3v3(totmat[1], totmat[2], totmat[0]);
- break;
- }
- case TRACK_nY: /* LOCK X TRACK -Y */
- {
- /* Projection of Vector on the plane */
- project_v3_v3v3(vec2, vec, cob->matrix[0]);
- sub_v3_v3v3(totmat[1], vec, vec2);
- normalize_v3(totmat[1]);
- negate_v3(totmat[1]);
-
- /* the x axis is fixed */
- normalize_v3_v3(totmat[0], cob->matrix[0]);
-
- /* the z axis gets mapped onto a third orthogonal vector */
- cross_v3_v3v3(totmat[2], totmat[0], totmat[1]);
- break;
- }
- case TRACK_nZ: /* LOCK X TRACK -Z */
- {
- /* Projection of Vector on the plane */
- project_v3_v3v3(vec2, vec, cob->matrix[0]);
- sub_v3_v3v3(totmat[2], vec, vec2);
- normalize_v3(totmat[2]);
- negate_v3(totmat[2]);
-
- /* the x axis is fixed */
- normalize_v3_v3(totmat[0], cob->matrix[0]);
-
- /* the z axis gets mapped onto a third orthogonal vector */
- cross_v3_v3v3(totmat[1], totmat[2], totmat[0]);
- break;
- }
- default:
- {
- unit_m3(totmat);
- break;
- }
- }
- break;
- }
- case LOCK_Y: /* LOCK Y */
- {
- switch (data->trackflag) {
- case TRACK_X: /* LOCK Y TRACK X */
- {
- /* Projection of Vector on the plane */
- project_v3_v3v3(vec2, vec, cob->matrix[1]);
- sub_v3_v3v3(totmat[0], vec, vec2);
- normalize_v3(totmat[0]);
-
- /* the y axis is fixed */
- normalize_v3_v3(totmat[1], cob->matrix[1]);
-
- /* the z axis gets mapped onto a third orthogonal vector */
- cross_v3_v3v3(totmat[2], totmat[0], totmat[1]);
- break;
- }
- case TRACK_Z: /* LOCK Y TRACK Z */
- {
- /* Projection of Vector on the plane */
- project_v3_v3v3(vec2, vec, cob->matrix[1]);
- sub_v3_v3v3(totmat[2], vec, vec2);
- normalize_v3(totmat[2]);
-
- /* the y axis is fixed */
- normalize_v3_v3(totmat[1], cob->matrix[1]);
-
- /* the z axis gets mapped onto a third orthogonal vector */
- cross_v3_v3v3(totmat[0], totmat[1], totmat[2]);
- break;
- }
- case TRACK_nX: /* LOCK Y TRACK -X */
- {
- /* Projection of Vector on the plane */
- project_v3_v3v3(vec2, vec, cob->matrix[1]);
- sub_v3_v3v3(totmat[0], vec, vec2);
- normalize_v3(totmat[0]);
- negate_v3(totmat[0]);
-
- /* the y axis is fixed */
- normalize_v3_v3(totmat[1], cob->matrix[1]);
-
- /* the z axis gets mapped onto a third orthogonal vector */
- cross_v3_v3v3(totmat[2], totmat[0], totmat[1]);
- break;
- }
- case TRACK_nZ: /* LOCK Y TRACK -Z */
- {
- /* Projection of Vector on the plane */
- project_v3_v3v3(vec2, vec, cob->matrix[1]);
- sub_v3_v3v3(totmat[2], vec, vec2);
- normalize_v3(totmat[2]);
- negate_v3(totmat[2]);
-
- /* the y axis is fixed */
- normalize_v3_v3(totmat[1], cob->matrix[1]);
-
- /* the z axis gets mapped onto a third orthogonal vector */
- cross_v3_v3v3(totmat[0], totmat[1], totmat[2]);
- break;
- }
- default:
- {
- unit_m3(totmat);
- break;
- }
- }
- break;
- }
- case LOCK_Z: /* LOCK Z */
- {
- switch (data->trackflag) {
- case TRACK_X: /* LOCK Z TRACK X */
- {
- /* Projection of Vector on the plane */
- project_v3_v3v3(vec2, vec, cob->matrix[2]);
- sub_v3_v3v3(totmat[0], vec, vec2);
- normalize_v3(totmat[0]);
-
- /* the z axis is fixed */
- normalize_v3_v3(totmat[2], cob->matrix[2]);
-
- /* the x axis gets mapped onto a third orthogonal vector */
- cross_v3_v3v3(totmat[1], totmat[2], totmat[0]);
- break;
- }
- case TRACK_Y: /* LOCK Z TRACK Y */
- {
- /* Projection of Vector on the plane */
- project_v3_v3v3(vec2, vec, cob->matrix[2]);
- sub_v3_v3v3(totmat[1], vec, vec2);
- normalize_v3(totmat[1]);
-
- /* the z axis is fixed */
- normalize_v3_v3(totmat[2], cob->matrix[2]);
-
- /* the x axis gets mapped onto a third orthogonal vector */
- cross_v3_v3v3(totmat[0], totmat[1], totmat[2]);
- break;
- }
- case TRACK_nX: /* LOCK Z TRACK -X */
- {
- /* Projection of Vector on the plane */
- project_v3_v3v3(vec2, vec, cob->matrix[2]);
- sub_v3_v3v3(totmat[0], vec, vec2);
- normalize_v3(totmat[0]);
- negate_v3(totmat[0]);
-
- /* the z axis is fixed */
- normalize_v3_v3(totmat[2], cob->matrix[2]);
-
- /* the x axis gets mapped onto a third orthogonal vector */
- cross_v3_v3v3(totmat[1], totmat[2], totmat[0]);
- break;
- }
- case TRACK_nY: /* LOCK Z TRACK -Y */
- {
- /* Projection of Vector on the plane */
- project_v3_v3v3(vec2, vec, cob->matrix[2]);
- sub_v3_v3v3(totmat[1], vec, vec2);
- normalize_v3(totmat[1]);
- negate_v3(totmat[1]);
-
- /* the z axis is fixed */
- normalize_v3_v3(totmat[2], cob->matrix[2]);
-
- /* the x axis gets mapped onto a third orthogonal vector */
- cross_v3_v3v3(totmat[0], totmat[1], totmat[2]);
- break;
- }
- default:
- {
- unit_m3(totmat);
- break;
- }
- }
- break;
- }
- default:
- {
- unit_m3(totmat);
- break;
- }
- }
- /* Block to keep matrix heading */
- copy_m3_m4(tmpmat, cob->matrix);
- normalize_m3(tmpmat);
- invert_m3_m3(invmat, tmpmat);
- mul_m3_m3m3(tmpmat, totmat, invmat);
- totmat[0][0] = tmpmat[0][0]; totmat[0][1] = tmpmat[0][1]; totmat[0][2] = tmpmat[0][2];
- totmat[1][0] = tmpmat[1][0]; totmat[1][1] = tmpmat[1][1]; totmat[1][2] = tmpmat[1][2];
- totmat[2][0] = tmpmat[2][0]; totmat[2][1] = tmpmat[2][1]; totmat[2][2] = tmpmat[2][2];
-
- mdet = determinant_m3(totmat[0][0], totmat[0][1], totmat[0][2],
- totmat[1][0], totmat[1][1], totmat[1][2],
- totmat[2][0], totmat[2][1], totmat[2][2]);
- if (mdet == 0) {
- unit_m3(totmat);
- }
-
- /* apply out transformation to the object */
- mul_m4_m3m4(cob->matrix, totmat, cob->matrix);
- }
+ bLockTrackConstraint *data = con->data;
+ bConstraintTarget *ct = targets->first;
+
+ if (VALID_CONS_TARGET(ct)) {
+ float vec[3], vec2[3];
+ float totmat[3][3];
+ float tmpmat[3][3];
+ float invmat[3][3];
+ float mdet;
+
+ /* Vector object -> target */
+ sub_v3_v3v3(vec, ct->matrix[3], cob->matrix[3]);
+ switch (data->lockflag) {
+ case LOCK_X: /* LOCK X */
+ {
+ switch (data->trackflag) {
+ case TRACK_Y: /* LOCK X TRACK Y */
+ {
+ /* Projection of Vector on the plane */
+ project_v3_v3v3(vec2, vec, cob->matrix[0]);
+ sub_v3_v3v3(totmat[1], vec, vec2);
+ normalize_v3(totmat[1]);
+
+ /* the x axis is fixed */
+ normalize_v3_v3(totmat[0], cob->matrix[0]);
+
+ /* the z axis gets mapped onto a third orthogonal vector */
+ cross_v3_v3v3(totmat[2], totmat[0], totmat[1]);
+ break;
+ }
+ case TRACK_Z: /* LOCK X TRACK Z */
+ {
+ /* Projection of Vector on the plane */
+ project_v3_v3v3(vec2, vec, cob->matrix[0]);
+ sub_v3_v3v3(totmat[2], vec, vec2);
+ normalize_v3(totmat[2]);
+
+ /* the x axis is fixed */
+ normalize_v3_v3(totmat[0], cob->matrix[0]);
+
+ /* the z axis gets mapped onto a third orthogonal vector */
+ cross_v3_v3v3(totmat[1], totmat[2], totmat[0]);
+ break;
+ }
+ case TRACK_nY: /* LOCK X TRACK -Y */
+ {
+ /* Projection of Vector on the plane */
+ project_v3_v3v3(vec2, vec, cob->matrix[0]);
+ sub_v3_v3v3(totmat[1], vec, vec2);
+ normalize_v3(totmat[1]);
+ negate_v3(totmat[1]);
+
+ /* the x axis is fixed */
+ normalize_v3_v3(totmat[0], cob->matrix[0]);
+
+ /* the z axis gets mapped onto a third orthogonal vector */
+ cross_v3_v3v3(totmat[2], totmat[0], totmat[1]);
+ break;
+ }
+ case TRACK_nZ: /* LOCK X TRACK -Z */
+ {
+ /* Projection of Vector on the plane */
+ project_v3_v3v3(vec2, vec, cob->matrix[0]);
+ sub_v3_v3v3(totmat[2], vec, vec2);
+ normalize_v3(totmat[2]);
+ negate_v3(totmat[2]);
+
+ /* the x axis is fixed */
+ normalize_v3_v3(totmat[0], cob->matrix[0]);
+
+ /* the z axis gets mapped onto a third orthogonal vector */
+ cross_v3_v3v3(totmat[1], totmat[2], totmat[0]);
+ break;
+ }
+ default: {
+ unit_m3(totmat);
+ break;
+ }
+ }
+ break;
+ }
+ case LOCK_Y: /* LOCK Y */
+ {
+ switch (data->trackflag) {
+ case TRACK_X: /* LOCK Y TRACK X */
+ {
+ /* Projection of Vector on the plane */
+ project_v3_v3v3(vec2, vec, cob->matrix[1]);
+ sub_v3_v3v3(totmat[0], vec, vec2);
+ normalize_v3(totmat[0]);
+
+ /* the y axis is fixed */
+ normalize_v3_v3(totmat[1], cob->matrix[1]);
+
+ /* the z axis gets mapped onto a third orthogonal vector */
+ cross_v3_v3v3(totmat[2], totmat[0], totmat[1]);
+ break;
+ }
+ case TRACK_Z: /* LOCK Y TRACK Z */
+ {
+ /* Projection of Vector on the plane */
+ project_v3_v3v3(vec2, vec, cob->matrix[1]);
+ sub_v3_v3v3(totmat[2], vec, vec2);
+ normalize_v3(totmat[2]);
+
+ /* the y axis is fixed */
+ normalize_v3_v3(totmat[1], cob->matrix[1]);
+
+ /* the z axis gets mapped onto a third orthogonal vector */
+ cross_v3_v3v3(totmat[0], totmat[1], totmat[2]);
+ break;
+ }
+ case TRACK_nX: /* LOCK Y TRACK -X */
+ {
+ /* Projection of Vector on the plane */
+ project_v3_v3v3(vec2, vec, cob->matrix[1]);
+ sub_v3_v3v3(totmat[0], vec, vec2);
+ normalize_v3(totmat[0]);
+ negate_v3(totmat[0]);
+
+ /* the y axis is fixed */
+ normalize_v3_v3(totmat[1], cob->matrix[1]);
+
+ /* the z axis gets mapped onto a third orthogonal vector */
+ cross_v3_v3v3(totmat[2], totmat[0], totmat[1]);
+ break;
+ }
+ case TRACK_nZ: /* LOCK Y TRACK -Z */
+ {
+ /* Projection of Vector on the plane */
+ project_v3_v3v3(vec2, vec, cob->matrix[1]);
+ sub_v3_v3v3(totmat[2], vec, vec2);
+ normalize_v3(totmat[2]);
+ negate_v3(totmat[2]);
+
+ /* the y axis is fixed */
+ normalize_v3_v3(totmat[1], cob->matrix[1]);
+
+ /* the z axis gets mapped onto a third orthogonal vector */
+ cross_v3_v3v3(totmat[0], totmat[1], totmat[2]);
+ break;
+ }
+ default: {
+ unit_m3(totmat);
+ break;
+ }
+ }
+ break;
+ }
+ case LOCK_Z: /* LOCK Z */
+ {
+ switch (data->trackflag) {
+ case TRACK_X: /* LOCK Z TRACK X */
+ {
+ /* Projection of Vector on the plane */
+ project_v3_v3v3(vec2, vec, cob->matrix[2]);
+ sub_v3_v3v3(totmat[0], vec, vec2);
+ normalize_v3(totmat[0]);
+
+ /* the z axis is fixed */
+ normalize_v3_v3(totmat[2], cob->matrix[2]);
+
+ /* the x axis gets mapped onto a third orthogonal vector */
+ cross_v3_v3v3(totmat[1], totmat[2], totmat[0]);
+ break;
+ }
+ case TRACK_Y: /* LOCK Z TRACK Y */
+ {
+ /* Projection of Vector on the plane */
+ project_v3_v3v3(vec2, vec, cob->matrix[2]);
+ sub_v3_v3v3(totmat[1], vec, vec2);
+ normalize_v3(totmat[1]);
+
+ /* the z axis is fixed */
+ normalize_v3_v3(totmat[2], cob->matrix[2]);
+
+ /* the x axis gets mapped onto a third orthogonal vector */
+ cross_v3_v3v3(totmat[0], totmat[1], totmat[2]);
+ break;
+ }
+ case TRACK_nX: /* LOCK Z TRACK -X */
+ {
+ /* Projection of Vector on the plane */
+ project_v3_v3v3(vec2, vec, cob->matrix[2]);
+ sub_v3_v3v3(totmat[0], vec, vec2);
+ normalize_v3(totmat[0]);
+ negate_v3(totmat[0]);
+
+ /* the z axis is fixed */
+ normalize_v3_v3(totmat[2], cob->matrix[2]);
+
+ /* the x axis gets mapped onto a third orthogonal vector */
+ cross_v3_v3v3(totmat[1], totmat[2], totmat[0]);
+ break;
+ }
+ case TRACK_nY: /* LOCK Z TRACK -Y */
+ {
+ /* Projection of Vector on the plane */
+ project_v3_v3v3(vec2, vec, cob->matrix[2]);
+ sub_v3_v3v3(totmat[1], vec, vec2);
+ normalize_v3(totmat[1]);
+ negate_v3(totmat[1]);
+
+ /* the z axis is fixed */
+ normalize_v3_v3(totmat[2], cob->matrix[2]);
+
+ /* the x axis gets mapped onto a third orthogonal vector */
+ cross_v3_v3v3(totmat[0], totmat[1], totmat[2]);
+ break;
+ }
+ default: {
+ unit_m3(totmat);
+ break;
+ }
+ }
+ break;
+ }
+ default: {
+ unit_m3(totmat);
+ break;
+ }
+ }
+ /* Block to keep matrix heading */
+ copy_m3_m4(tmpmat, cob->matrix);
+ normalize_m3(tmpmat);
+ invert_m3_m3(invmat, tmpmat);
+ mul_m3_m3m3(tmpmat, totmat, invmat);
+ totmat[0][0] = tmpmat[0][0];
+ totmat[0][1] = tmpmat[0][1];
+ totmat[0][2] = tmpmat[0][2];
+ totmat[1][0] = tmpmat[1][0];
+ totmat[1][1] = tmpmat[1][1];
+ totmat[1][2] = tmpmat[1][2];
+ totmat[2][0] = tmpmat[2][0];
+ totmat[2][1] = tmpmat[2][1];
+ totmat[2][2] = tmpmat[2][2];
+
+ mdet = determinant_m3(totmat[0][0],
+ totmat[0][1],
+ totmat[0][2],
+ totmat[1][0],
+ totmat[1][1],
+ totmat[1][2],
+ totmat[2][0],
+ totmat[2][1],
+ totmat[2][2]);
+ if (mdet == 0) {
+ unit_m3(totmat);
+ }
+
+ /* apply out transformation to the object */
+ mul_m4_m3m4(cob->matrix, totmat, cob->matrix);
+ }
}
static bConstraintTypeInfo CTI_LOCKTRACK = {
- CONSTRAINT_TYPE_LOCKTRACK, /* type */
- sizeof(bLockTrackConstraint), /* size */
- "Locked Track", /* name */
- "bLockTrackConstraint", /* struct name */
- NULL, /* free data */
- locktrack_id_looper, /* id looper */
- NULL, /* copy data */
- locktrack_new_data, /* new data */
- locktrack_get_tars, /* get constraint targets */
- locktrack_flush_tars, /* flush constraint targets */
- default_get_tarmat, /* get target matrix */
- locktrack_evaluate, /* evaluate */
+ CONSTRAINT_TYPE_LOCKTRACK, /* type */
+ sizeof(bLockTrackConstraint), /* size */
+ "Locked Track", /* name */
+ "bLockTrackConstraint", /* struct name */
+ NULL, /* free data */
+ locktrack_id_looper, /* id looper */
+ NULL, /* copy data */
+ locktrack_new_data, /* new data */
+ locktrack_get_tars, /* get constraint targets */
+ locktrack_flush_tars, /* flush constraint targets */
+ default_get_tarmat, /* get target matrix */
+ locktrack_evaluate, /* evaluate */
};
/* ---------- Limit Distance Constraint ----------- */
static void distlimit_new_data(void *cdata)
{
- bDistLimitConstraint *data = (bDistLimitConstraint *)cdata;
+ bDistLimitConstraint *data = (bDistLimitConstraint *)cdata;
- data->dist = 0.0f;
+ data->dist = 0.0f;
}
static void distlimit_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
{
- bDistLimitConstraint *data = con->data;
+ bDistLimitConstraint *data = con->data;
- /* target only */
- func(con, (ID **)&data->tar, false, userdata);
+ /* target only */
+ func(con, (ID **)&data->tar, false, userdata);
}
static int distlimit_get_tars(bConstraint *con, ListBase *list)
{
- if (con && list) {
- bDistLimitConstraint *data = con->data;
- bConstraintTarget *ct;
+ if (con && list) {
+ bDistLimitConstraint *data = con->data;
+ bConstraintTarget *ct;
- /* standard target-getting macro for single-target constraints */
- SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
+ /* standard target-getting macro for single-target constraints */
+ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1;
- }
+ return 1;
+ }
- return 0;
+ return 0;
}
static void distlimit_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
{
- if (con && list) {
- bDistLimitConstraint *data = con->data;
- bConstraintTarget *ct = list->first;
+ if (con && list) {
+ bDistLimitConstraint *data = con->data;
+ bConstraintTarget *ct = list->first;
- /* the following macro is used for all standard single-target constraints */
- SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
- }
+ /* the following macro is used for all standard single-target constraints */
+ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
+ }
}
static void distlimit_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets)
{
- bDistLimitConstraint *data = con->data;
- bConstraintTarget *ct = targets->first;
-
- /* only evaluate if there is a target */
- if (VALID_CONS_TARGET(ct)) {
- float dvec[3], dist, sfac = 1.0f;
- short clamp_surf = 0;
-
- /* calculate our current distance from the target */
- dist = len_v3v3(cob->matrix[3], ct->matrix[3]);
-
- /* set distance (flag is only set when user demands it) */
- if (data->dist == 0) {
- data->dist = dist;
-
- /* Write the computed distance back to the master copy if in COW evaluation. */
- bConstraint *orig_con = constraint_find_original_for_update(cob, con);
-
- if (orig_con != NULL) {
- bDistLimitConstraint *orig_data = orig_con->data;
-
- orig_data->dist = data->dist;
- }
- }
-
- /* check if we're which way to clamp from, and calculate interpolation factor (if needed) */
- if (data->mode == LIMITDIST_OUTSIDE) {
- /* if inside, then move to surface */
- if (dist <= data->dist) {
- clamp_surf = 1;
- if (dist != 0.0f) sfac = data->dist / dist;
- }
- /* if soft-distance is enabled, start fading once owner is dist+softdist from the target */
- else if (data->flag & LIMITDIST_USESOFT) {
- if (dist <= (data->dist + data->soft)) {
- /* pass */
- }
- }
- }
- else if (data->mode == LIMITDIST_INSIDE) {
- /* if outside, then move to surface */
- if (dist >= data->dist) {
- clamp_surf = 1;
- if (dist != 0.0f) sfac = data->dist / dist;
- }
- /* if soft-distance is enabled, start fading once owner is dist-soft from the target */
- else if (data->flag & LIMITDIST_USESOFT) {
- /* FIXME: there's a problem with "jumping" when this kicks in */
- if (dist >= (data->dist - data->soft)) {
- sfac = (float)(data->soft * (1.0f - expf(-(dist - data->dist) / data->soft)) + data->dist);
- if (dist != 0.0f) sfac /= dist;
-
- clamp_surf = 1;
- }
- }
- }
- else {
- if (IS_EQF(dist, data->dist) == 0) {
- clamp_surf = 1;
- if (dist != 0.0f) sfac = data->dist / dist;
- }
- }
-
- /* clamp to 'surface' (i.e. move owner so that dist == data->dist) */
- if (clamp_surf) {
- /* simply interpolate along line formed by target -> owner */
- interp_v3_v3v3(dvec, ct->matrix[3], cob->matrix[3], sfac);
-
- /* copy new vector onto owner */
- copy_v3_v3(cob->matrix[3], dvec);
- }
- }
+ bDistLimitConstraint *data = con->data;
+ bConstraintTarget *ct = targets->first;
+
+ /* only evaluate if there is a target */
+ if (VALID_CONS_TARGET(ct)) {
+ float dvec[3], dist, sfac = 1.0f;
+ short clamp_surf = 0;
+
+ /* calculate our current distance from the target */
+ dist = len_v3v3(cob->matrix[3], ct->matrix[3]);
+
+ /* set distance (flag is only set when user demands it) */
+ if (data->dist == 0) {
+ data->dist = dist;
+
+ /* Write the computed distance back to the master copy if in COW evaluation. */
+ bConstraint *orig_con = constraint_find_original_for_update(cob, con);
+
+ if (orig_con != NULL) {
+ bDistLimitConstraint *orig_data = orig_con->data;
+
+ orig_data->dist = data->dist;
+ }
+ }
+
+ /* check if we're which way to clamp from, and calculate interpolation factor (if needed) */
+ if (data->mode == LIMITDIST_OUTSIDE) {
+ /* if inside, then move to surface */
+ if (dist <= data->dist) {
+ clamp_surf = 1;
+ if (dist != 0.0f)
+ sfac = data->dist / dist;
+ }
+ /* if soft-distance is enabled, start fading once owner is dist+softdist from the target */
+ else if (data->flag & LIMITDIST_USESOFT) {
+ if (dist <= (data->dist + data->soft)) {
+ /* pass */
+ }
+ }
+ }
+ else if (data->mode == LIMITDIST_INSIDE) {
+ /* if outside, then move to surface */
+ if (dist >= data->dist) {
+ clamp_surf = 1;
+ if (dist != 0.0f)
+ sfac = data->dist / dist;
+ }
+ /* if soft-distance is enabled, start fading once owner is dist-soft from the target */
+ else if (data->flag & LIMITDIST_USESOFT) {
+ /* FIXME: there's a problem with "jumping" when this kicks in */
+ if (dist >= (data->dist - data->soft)) {
+ sfac = (float)(data->soft * (1.0f - expf(-(dist - data->dist) / data->soft)) +
+ data->dist);
+ if (dist != 0.0f)
+ sfac /= dist;
+
+ clamp_surf = 1;
+ }
+ }
+ }
+ else {
+ if (IS_EQF(dist, data->dist) == 0) {
+ clamp_surf = 1;
+ if (dist != 0.0f)
+ sfac = data->dist / dist;
+ }
+ }
+
+ /* clamp to 'surface' (i.e. move owner so that dist == data->dist) */
+ if (clamp_surf) {
+ /* simply interpolate along line formed by target -> owner */
+ interp_v3_v3v3(dvec, ct->matrix[3], cob->matrix[3], sfac);
+
+ /* copy new vector onto owner */
+ copy_v3_v3(cob->matrix[3], dvec);
+ }
+ }
}
static bConstraintTypeInfo CTI_DISTLIMIT = {
- CONSTRAINT_TYPE_DISTLIMIT, /* type */
- sizeof(bDistLimitConstraint), /* size */
- "Limit Distance", /* name */
- "bDistLimitConstraint", /* struct name */
- NULL, /* free data */
- distlimit_id_looper, /* id looper */
- NULL, /* copy data */
- distlimit_new_data, /* new data */
- distlimit_get_tars, /* get constraint targets */
- distlimit_flush_tars, /* flush constraint targets */
- default_get_tarmat, /* get a target matrix */
- distlimit_evaluate, /* evaluate */
+ CONSTRAINT_TYPE_DISTLIMIT, /* type */
+ sizeof(bDistLimitConstraint), /* size */
+ "Limit Distance", /* name */
+ "bDistLimitConstraint", /* struct name */
+ NULL, /* free data */
+ distlimit_id_looper, /* id looper */
+ NULL, /* copy data */
+ distlimit_new_data, /* new data */
+ distlimit_get_tars, /* get constraint targets */
+ distlimit_flush_tars, /* flush constraint targets */
+ default_get_tarmat, /* get a target matrix */
+ distlimit_evaluate, /* evaluate */
};
/* ---------- Stretch To ------------ */
static void stretchto_new_data(void *cdata)
{
- bStretchToConstraint *data = (bStretchToConstraint *)cdata;
+ bStretchToConstraint *data = (bStretchToConstraint *)cdata;
- data->volmode = 0;
- data->plane = 0;
- data->orglength = 0.0;
- data->bulge = 1.0;
- data->bulge_max = 1.0f;
- data->bulge_min = 1.0f;
+ data->volmode = 0;
+ data->plane = 0;
+ data->orglength = 0.0;
+ data->bulge = 1.0;
+ data->bulge_max = 1.0f;
+ data->bulge_min = 1.0f;
}
static void stretchto_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
{
- bStretchToConstraint *data = con->data;
+ bStretchToConstraint *data = con->data;
- /* target only */
- func(con, (ID **)&data->tar, false, userdata);
+ /* target only */
+ func(con, (ID **)&data->tar, false, userdata);
}
static int stretchto_get_tars(bConstraint *con, ListBase *list)
{
- if (con && list) {
- bStretchToConstraint *data = con->data;
- bConstraintTarget *ct;
+ if (con && list) {
+ bStretchToConstraint *data = con->data;
+ bConstraintTarget *ct;
- /* standard target-getting macro for single-target constraints */
- SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
+ /* standard target-getting macro for single-target constraints */
+ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1;
- }
+ return 1;
+ }
- return 0;
+ return 0;
}
static void stretchto_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
{
- if (con && list) {
- bStretchToConstraint *data = con->data;
- bConstraintTarget *ct = list->first;
+ if (con && list) {
+ bStretchToConstraint *data = con->data;
+ bConstraintTarget *ct = list->first;
- /* the following macro is used for all standard single-target constraints */
- SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
- }
+ /* the following macro is used for all standard single-target constraints */
+ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
+ }
}
static void stretchto_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets)
{
- bStretchToConstraint *data = con->data;
- bConstraintTarget *ct = targets->first;
+ bStretchToConstraint *data = con->data;
+ bConstraintTarget *ct = targets->first;
- /* only evaluate if there is a target */
- if (VALID_CONS_TARGET(ct)) {
- float size[3], scale[3], vec[3], xx[3], zz[3], orth[3];
- float totmat[3][3];
- float dist, bulge;
+ /* only evaluate if there is a target */
+ if (VALID_CONS_TARGET(ct)) {
+ float size[3], scale[3], vec[3], xx[3], zz[3], orth[3];
+ float totmat[3][3];
+ float dist, bulge;
- /* store scaling before destroying obmat */
- mat4_to_size(size, cob->matrix);
+ /* store scaling before destroying obmat */
+ mat4_to_size(size, cob->matrix);
- /* store X orientation before destroying obmat */
- normalize_v3_v3(xx, cob->matrix[0]);
+ /* store X orientation before destroying obmat */
+ normalize_v3_v3(xx, cob->matrix[0]);
- /* store Z orientation before destroying obmat */
- normalize_v3_v3(zz, cob->matrix[2]);
+ /* store Z orientation before destroying obmat */
+ normalize_v3_v3(zz, cob->matrix[2]);
- /* XXX That makes the constraint buggy with asymmetrically scaled objects, see #29940. */
+ /* XXX That makes the constraint buggy with asymmetrically scaled objects, see #29940. */
#if 0
- sub_v3_v3v3(vec, cob->matrix[3], ct->matrix[3]);
- vec[0] /= size[0];
- vec[1] /= size[1];
- vec[2] /= size[2];
+ sub_v3_v3v3(vec, cob->matrix[3], ct->matrix[3]);
+ vec[0] /= size[0];
+ vec[1] /= size[1];
+ vec[2] /= size[2];
- dist = normalize_v3(vec);
+ dist = normalize_v3(vec);
#endif
- dist = len_v3v3(cob->matrix[3], ct->matrix[3]);
- /* Only Y constrained object axis scale should be used, to keep same length when scaling it. */
- dist /= size[1];
-
- /* data->orglength==0 occurs on first run, and after 'R' button is clicked */
- if (data->orglength == 0) {
- data->orglength = dist;
-
- /* Write the computed length back to the master copy if in COW evaluation. */
- bConstraint *orig_con = constraint_find_original_for_update(cob, con);
-
- if (orig_con != NULL) {
- bStretchToConstraint *orig_data = orig_con->data;
-
- orig_data->orglength = data->orglength;
- }
- }
-
- scale[1] = dist / data->orglength;
-
- bulge = powf(data->orglength / dist, data->bulge);
-
- if (bulge > 1.0f) {
- if (data->flag & STRETCHTOCON_USE_BULGE_MAX) {
- float bulge_max = max_ff(data->bulge_max, 1.0f);
- float hard = min_ff(bulge, bulge_max);
-
- float range = bulge_max - 1.0f;
- float scale_fac = (range > 0.0f) ? 1.0f / range : 0.0f;
- float soft = 1.0f + range * atanf((bulge - 1.0f) * scale_fac) / (float)M_PI_2;
-
- bulge = interpf(soft, hard, data->bulge_smooth);
- }
- }
- if (bulge < 1.0f) {
- if (data->flag & STRETCHTOCON_USE_BULGE_MIN) {
- float bulge_min = CLAMPIS(data->bulge_min, 0.0f, 1.0f);
- float hard = max_ff(bulge, bulge_min);
-
- float range = 1.0f - bulge_min;
- float scale_fac = (range > 0.0f) ? 1.0f / range : 0.0f;
- float soft = 1.0f - range * atanf((1.0f - bulge) * scale_fac) / (float)M_PI_2;
-
- bulge = interpf(soft, hard, data->bulge_smooth);
- }
- }
-
- switch (data->volmode) {
- /* volume preserving scaling */
- case VOLUME_XZ:
- scale[0] = sqrtf(bulge);
- scale[2] = scale[0];
- break;
- case VOLUME_X:
- scale[0] = bulge;
- scale[2] = 1.0;
- break;
- case VOLUME_Z:
- scale[0] = 1.0;
- scale[2] = bulge;
- break;
- /* don't care for volume */
- case NO_VOLUME:
- scale[0] = 1.0;
- scale[2] = 1.0;
- break;
- default: /* should not happen, but in case*/
- return;
- } /* switch (data->volmode) */
-
- /* Clear the object's rotation and scale */
- cob->matrix[0][0] = size[0] * scale[0];
- cob->matrix[0][1] = 0;
- cob->matrix[0][2] = 0;
- cob->matrix[1][0] = 0;
- cob->matrix[1][1] = size[1] * scale[1];
- cob->matrix[1][2] = 0;
- cob->matrix[2][0] = 0;
- cob->matrix[2][1] = 0;
- cob->matrix[2][2] = size[2] * scale[2];
-
- sub_v3_v3v3(vec, cob->matrix[3], ct->matrix[3]);
- normalize_v3(vec);
-
- /* new Y aligns object target connection*/
- negate_v3_v3(totmat[1], vec);
- switch (data->plane) {
- case PLANE_X:
- /* build new Z vector */
- /* othogonal to "new Y" "old X! plane */
- cross_v3_v3v3(orth, vec, xx);
- normalize_v3(orth);
-
- /* new Z*/
- copy_v3_v3(totmat[2], orth);
-
- /* we decided to keep X plane*/
- cross_v3_v3v3(xx, orth, vec);
- normalize_v3_v3(totmat[0], xx);
- break;
- case PLANE_Z:
- /* build new X vector */
- /* othogonal to "new Y" "old Z! plane */
- cross_v3_v3v3(orth, vec, zz);
- normalize_v3(orth);
-
- /* new X */
- negate_v3_v3(totmat[0], orth);
-
- /* we decided to keep Z */
- cross_v3_v3v3(zz, orth, vec);
- normalize_v3_v3(totmat[2], zz);
- break;
- } /* switch (data->plane) */
-
- mul_m4_m3m4(cob->matrix, totmat, cob->matrix);
- }
+ dist = len_v3v3(cob->matrix[3], ct->matrix[3]);
+ /* Only Y constrained object axis scale should be used, to keep same length when scaling it. */
+ dist /= size[1];
+
+ /* data->orglength==0 occurs on first run, and after 'R' button is clicked */
+ if (data->orglength == 0) {
+ data->orglength = dist;
+
+ /* Write the computed length back to the master copy if in COW evaluation. */
+ bConstraint *orig_con = constraint_find_original_for_update(cob, con);
+
+ if (orig_con != NULL) {
+ bStretchToConstraint *orig_data = orig_con->data;
+
+ orig_data->orglength = data->orglength;
+ }
+ }
+
+ scale[1] = dist / data->orglength;
+
+ bulge = powf(data->orglength / dist, data->bulge);
+
+ if (bulge > 1.0f) {
+ if (data->flag & STRETCHTOCON_USE_BULGE_MAX) {
+ float bulge_max = max_ff(data->bulge_max, 1.0f);
+ float hard = min_ff(bulge, bulge_max);
+
+ float range = bulge_max - 1.0f;
+ float scale_fac = (range > 0.0f) ? 1.0f / range : 0.0f;
+ float soft = 1.0f + range * atanf((bulge - 1.0f) * scale_fac) / (float)M_PI_2;
+
+ bulge = interpf(soft, hard, data->bulge_smooth);
+ }
+ }
+ if (bulge < 1.0f) {
+ if (data->flag & STRETCHTOCON_USE_BULGE_MIN) {
+ float bulge_min = CLAMPIS(data->bulge_min, 0.0f, 1.0f);
+ float hard = max_ff(bulge, bulge_min);
+
+ float range = 1.0f - bulge_min;
+ float scale_fac = (range > 0.0f) ? 1.0f / range : 0.0f;
+ float soft = 1.0f - range * atanf((1.0f - bulge) * scale_fac) / (float)M_PI_2;
+
+ bulge = interpf(soft, hard, data->bulge_smooth);
+ }
+ }
+
+ switch (data->volmode) {
+ /* volume preserving scaling */
+ case VOLUME_XZ:
+ scale[0] = sqrtf(bulge);
+ scale[2] = scale[0];
+ break;
+ case VOLUME_X:
+ scale[0] = bulge;
+ scale[2] = 1.0;
+ break;
+ case VOLUME_Z:
+ scale[0] = 1.0;
+ scale[2] = bulge;
+ break;
+ /* don't care for volume */
+ case NO_VOLUME:
+ scale[0] = 1.0;
+ scale[2] = 1.0;
+ break;
+ default: /* should not happen, but in case*/
+ return;
+ } /* switch (data->volmode) */
+
+ /* Clear the object's rotation and scale */
+ cob->matrix[0][0] = size[0] * scale[0];
+ cob->matrix[0][1] = 0;
+ cob->matrix[0][2] = 0;
+ cob->matrix[1][0] = 0;
+ cob->matrix[1][1] = size[1] * scale[1];
+ cob->matrix[1][2] = 0;
+ cob->matrix[2][0] = 0;
+ cob->matrix[2][1] = 0;
+ cob->matrix[2][2] = size[2] * scale[2];
+
+ sub_v3_v3v3(vec, cob->matrix[3], ct->matrix[3]);
+ normalize_v3(vec);
+
+ /* new Y aligns object target connection*/
+ negate_v3_v3(totmat[1], vec);
+ switch (data->plane) {
+ case PLANE_X:
+ /* build new Z vector */
+ /* othogonal to "new Y" "old X! plane */
+ cross_v3_v3v3(orth, vec, xx);
+ normalize_v3(orth);
+
+ /* new Z*/
+ copy_v3_v3(totmat[2], orth);
+
+ /* we decided to keep X plane*/
+ cross_v3_v3v3(xx, orth, vec);
+ normalize_v3_v3(totmat[0], xx);
+ break;
+ case PLANE_Z:
+ /* build new X vector */
+ /* othogonal to "new Y" "old Z! plane */
+ cross_v3_v3v3(orth, vec, zz);
+ normalize_v3(orth);
+
+ /* new X */
+ negate_v3_v3(totmat[0], orth);
+
+ /* we decided to keep Z */
+ cross_v3_v3v3(zz, orth, vec);
+ normalize_v3_v3(totmat[2], zz);
+ break;
+ } /* switch (data->plane) */
+
+ mul_m4_m3m4(cob->matrix, totmat, cob->matrix);
+ }
}
static bConstraintTypeInfo CTI_STRETCHTO = {
- CONSTRAINT_TYPE_STRETCHTO, /* type */
- sizeof(bStretchToConstraint), /* size */
- "Stretch To", /* name */
- "bStretchToConstraint", /* struct name */
- NULL, /* free data */
- stretchto_id_looper, /* id looper */
- NULL, /* copy data */
- stretchto_new_data, /* new data */
- stretchto_get_tars, /* get constraint targets */
- stretchto_flush_tars, /* flush constraint targets */
- default_get_tarmat, /* get target matrix */
- stretchto_evaluate, /* evaluate */
+ CONSTRAINT_TYPE_STRETCHTO, /* type */
+ sizeof(bStretchToConstraint), /* size */
+ "Stretch To", /* name */
+ "bStretchToConstraint", /* struct name */
+ NULL, /* free data */
+ stretchto_id_looper, /* id looper */
+ NULL, /* copy data */
+ stretchto_new_data, /* new data */
+ stretchto_get_tars, /* get constraint targets */
+ stretchto_flush_tars, /* flush constraint targets */
+ default_get_tarmat, /* get target matrix */
+ stretchto_evaluate, /* evaluate */
};
/* ---------- Floor ------------ */
static void minmax_new_data(void *cdata)
{
- bMinMaxConstraint *data = (bMinMaxConstraint *)cdata;
+ bMinMaxConstraint *data = (bMinMaxConstraint *)cdata;
- data->minmaxflag = TRACK_Z;
- data->offset = 0.0f;
- zero_v3(data->cache);
- data->flag = 0;
+ data->minmaxflag = TRACK_Z;
+ data->offset = 0.0f;
+ zero_v3(data->cache);
+ data->flag = 0;
}
static void minmax_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
{
- bMinMaxConstraint *data = con->data;
+ bMinMaxConstraint *data = con->data;
- /* target only */
- func(con, (ID **)&data->tar, false, userdata);
+ /* target only */
+ func(con, (ID **)&data->tar, false, userdata);
}
static int minmax_get_tars(bConstraint *con, ListBase *list)
{
- if (con && list) {
- bMinMaxConstraint *data = con->data;
- bConstraintTarget *ct;
+ if (con && list) {
+ bMinMaxConstraint *data = con->data;
+ bConstraintTarget *ct;
- /* standard target-getting macro for single-target constraints */
- SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
+ /* standard target-getting macro for single-target constraints */
+ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1;
- }
+ return 1;
+ }
- return 0;
+ return 0;
}
static void minmax_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
{
- if (con && list) {
- bMinMaxConstraint *data = con->data;
- bConstraintTarget *ct = list->first;
+ if (con && list) {
+ bMinMaxConstraint *data = con->data;
+ bConstraintTarget *ct = list->first;
- /* the following macro is used for all standard single-target constraints */
- SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
- }
+ /* the following macro is used for all standard single-target constraints */
+ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
+ }
}
static void minmax_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets)
{
- bMinMaxConstraint *data = con->data;
- bConstraintTarget *ct = targets->first;
-
- /* only evaluate if there is a target */
- if (VALID_CONS_TARGET(ct)) {
- float obmat[4][4], imat[4][4], tarmat[4][4], tmat[4][4];
- float val1, val2;
- int index;
-
- copy_m4_m4(obmat, cob->matrix);
- copy_m4_m4(tarmat, ct->matrix);
-
- if (data->flag & MINMAX_USEROT) {
- /* take rotation of target into account by doing the transaction in target's localspace */
- invert_m4_m4(imat, tarmat);
- mul_m4_m4m4(tmat, imat, obmat);
- copy_m4_m4(obmat, tmat);
- unit_m4(tarmat);
- }
-
- switch (data->minmaxflag) {
- case TRACK_Z:
- val1 = tarmat[3][2];
- val2 = obmat[3][2] - data->offset;
- index = 2;
- break;
- case TRACK_Y:
- val1 = tarmat[3][1];
- val2 = obmat[3][1] - data->offset;
- index = 1;
- break;
- case TRACK_X:
- val1 = tarmat[3][0];
- val2 = obmat[3][0] - data->offset;
- index = 0;
- break;
- case TRACK_nZ:
- val2 = tarmat[3][2];
- val1 = obmat[3][2] - data->offset;
- index = 2;
- break;
- case TRACK_nY:
- val2 = tarmat[3][1];
- val1 = obmat[3][1] - data->offset;
- index = 1;
- break;
- case TRACK_nX:
- val2 = tarmat[3][0];
- val1 = obmat[3][0] - data->offset;
- index = 0;
- break;
- default:
- return;
- }
-
- if (val1 > val2) {
- obmat[3][index] = tarmat[3][index] + data->offset;
- if (data->flag & MINMAX_STICKY) {
- if (data->flag & MINMAX_STUCK) {
- copy_v3_v3(obmat[3], data->cache);
- }
- else {
- copy_v3_v3(data->cache, obmat[3]);
- data->flag |= MINMAX_STUCK;
- }
- }
- if (data->flag & MINMAX_USEROT) {
- /* get out of localspace */
- mul_m4_m4m4(tmat, ct->matrix, obmat);
- copy_m4_m4(cob->matrix, tmat);
- }
- else {
- copy_v3_v3(cob->matrix[3], obmat[3]);
- }
- }
- else {
- data->flag &= ~MINMAX_STUCK;
- }
- }
+ bMinMaxConstraint *data = con->data;
+ bConstraintTarget *ct = targets->first;
+
+ /* only evaluate if there is a target */
+ if (VALID_CONS_TARGET(ct)) {
+ float obmat[4][4], imat[4][4], tarmat[4][4], tmat[4][4];
+ float val1, val2;
+ int index;
+
+ copy_m4_m4(obmat, cob->matrix);
+ copy_m4_m4(tarmat, ct->matrix);
+
+ if (data->flag & MINMAX_USEROT) {
+ /* take rotation of target into account by doing the transaction in target's localspace */
+ invert_m4_m4(imat, tarmat);
+ mul_m4_m4m4(tmat, imat, obmat);
+ copy_m4_m4(obmat, tmat);
+ unit_m4(tarmat);
+ }
+
+ switch (data->minmaxflag) {
+ case TRACK_Z:
+ val1 = tarmat[3][2];
+ val2 = obmat[3][2] - data->offset;
+ index = 2;
+ break;
+ case TRACK_Y:
+ val1 = tarmat[3][1];
+ val2 = obmat[3][1] - data->offset;
+ index = 1;
+ break;
+ case TRACK_X:
+ val1 = tarmat[3][0];
+ val2 = obmat[3][0] - data->offset;
+ index = 0;
+ break;
+ case TRACK_nZ:
+ val2 = tarmat[3][2];
+ val1 = obmat[3][2] - data->offset;
+ index = 2;
+ break;
+ case TRACK_nY:
+ val2 = tarmat[3][1];
+ val1 = obmat[3][1] - data->offset;
+ index = 1;
+ break;
+ case TRACK_nX:
+ val2 = tarmat[3][0];
+ val1 = obmat[3][0] - data->offset;
+ index = 0;
+ break;
+ default:
+ return;
+ }
+
+ if (val1 > val2) {
+ obmat[3][index] = tarmat[3][index] + data->offset;
+ if (data->flag & MINMAX_STICKY) {
+ if (data->flag & MINMAX_STUCK) {
+ copy_v3_v3(obmat[3], data->cache);
+ }
+ else {
+ copy_v3_v3(data->cache, obmat[3]);
+ data->flag |= MINMAX_STUCK;
+ }
+ }
+ if (data->flag & MINMAX_USEROT) {
+ /* get out of localspace */
+ mul_m4_m4m4(tmat, ct->matrix, obmat);
+ copy_m4_m4(cob->matrix, tmat);
+ }
+ else {
+ copy_v3_v3(cob->matrix[3], obmat[3]);
+ }
+ }
+ else {
+ data->flag &= ~MINMAX_STUCK;
+ }
+ }
}
static bConstraintTypeInfo CTI_MINMAX = {
- CONSTRAINT_TYPE_MINMAX, /* type */
- sizeof(bMinMaxConstraint), /* size */
- "Floor", /* name */
- "bMinMaxConstraint", /* struct name */
- NULL, /* free data */
- minmax_id_looper, /* id looper */
- NULL, /* copy data */
- minmax_new_data, /* new data */
- minmax_get_tars, /* get constraint targets */
- minmax_flush_tars, /* flush constraint targets */
- default_get_tarmat, /* get target matrix */
- minmax_evaluate, /* evaluate */
+ CONSTRAINT_TYPE_MINMAX, /* type */
+ sizeof(bMinMaxConstraint), /* size */
+ "Floor", /* name */
+ "bMinMaxConstraint", /* struct name */
+ NULL, /* free data */
+ minmax_id_looper, /* id looper */
+ NULL, /* copy data */
+ minmax_new_data, /* new data */
+ minmax_get_tars, /* get constraint targets */
+ minmax_flush_tars, /* flush constraint targets */
+ default_get_tarmat, /* get target matrix */
+ minmax_evaluate, /* evaluate */
};
/* -------- Clamp To ---------- */
static void clampto_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
{
- bClampToConstraint *data = con->data;
+ bClampToConstraint *data = con->data;
- /* target only */
- func(con, (ID **)&data->tar, false, userdata);
+ /* target only */
+ func(con, (ID **)&data->tar, false, userdata);
}
static int clampto_get_tars(bConstraint *con, ListBase *list)
{
- if (con && list) {
- bClampToConstraint *data = con->data;
- bConstraintTarget *ct;
+ if (con && list) {
+ bClampToConstraint *data = con->data;
+ bConstraintTarget *ct;
- /* standard target-getting macro for single-target constraints without subtargets */
- SINGLETARGETNS_GET_TARS(con, data->tar, ct, list);
+ /* standard target-getting macro for single-target constraints without subtargets */
+ SINGLETARGETNS_GET_TARS(con, data->tar, ct, list);
- return 1;
- }
+ return 1;
+ }
- return 0;
+ return 0;
}
static void clampto_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
{
- if (con && list) {
- bClampToConstraint *data = con->data;
- bConstraintTarget *ct = list->first;
+ if (con && list) {
+ bClampToConstraint *data = con->data;
+ bConstraintTarget *ct = list->first;
- /* the following macro is used for all standard single-target constraints */
- SINGLETARGETNS_FLUSH_TARS(con, data->tar, ct, list, no_copy);
- }
+ /* the following macro is used for all standard single-target constraints */
+ SINGLETARGETNS_FLUSH_TARS(con, data->tar, ct, list, no_copy);
+ }
}
static void clampto_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
- bConstraint *UNUSED(con), bConstraintOb *UNUSED(cob),
- bConstraintTarget *ct, float UNUSED(ctime))
+ bConstraint *UNUSED(con),
+ bConstraintOb *UNUSED(cob),
+ bConstraintTarget *ct,
+ float UNUSED(ctime))
{
- /* technically, this isn't really needed for evaluation, but we don't know what else
- * might end up calling this...
- */
- if (ct)
- unit_m4(ct->matrix);
+ /* technically, this isn't really needed for evaluation, but we don't know what else
+ * might end up calling this...
+ */
+ if (ct)
+ unit_m4(ct->matrix);
}
static void clampto_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets)
{
- bClampToConstraint *data = con->data;
- bConstraintTarget *ct = targets->first;
-
- /* only evaluate if there is a target and it is a curve */
- if (VALID_CONS_TARGET(ct) && (ct->tar->type == OB_CURVE)) {
- float obmat[4][4], ownLoc[3];
- float curveMin[3], curveMax[3];
- float targetMatrix[4][4];
-
- copy_m4_m4(obmat, cob->matrix);
- copy_v3_v3(ownLoc, obmat[3]);
-
- unit_m4(targetMatrix);
- INIT_MINMAX(curveMin, curveMax);
- /* XXX - don't think this is good calling this here - campbell */
- BKE_object_minmax(ct->tar, curveMin, curveMax, true);
-
- /* get targetmatrix */
- if (data->tar->runtime.curve_cache && data->tar->runtime.curve_cache->path && data->tar->runtime.curve_cache->path->data) {
- float vec[4], dir[3], totmat[4][4];
- float curvetime;
- short clamp_axis;
-
- /* find best position on curve */
- /* 1. determine which axis to sample on? */
- if (data->flag == CLAMPTO_AUTO) {
- float size[3];
- sub_v3_v3v3(size, curveMax, curveMin);
-
- /* find axis along which the bounding box has the greatest
- * extent. Otherwise, default to the x-axis, as that is quite
- * frequently used.
- */
- if ((size[2] > size[0]) && (size[2] > size[1]))
- clamp_axis = CLAMPTO_Z - 1;
- else if ((size[1] > size[0]) && (size[1] > size[2]))
- clamp_axis = CLAMPTO_Y - 1;
- else
- clamp_axis = CLAMPTO_X - 1;
- }
- else
- clamp_axis = data->flag - 1;
-
- /* 2. determine position relative to curve on a 0-1 scale based on bounding box */
- if (data->flag2 & CLAMPTO_CYCLIC) {
- /* cyclic, so offset within relative bounding box is used */
- float len = (curveMax[clamp_axis] - curveMin[clamp_axis]);
- float offset;
-
- /* check to make sure len is not so close to zero that it'll cause errors */
- if (IS_EQF(len, 0.0f) == false) {
- /* find bounding-box range where target is located */
- if (ownLoc[clamp_axis] < curveMin[clamp_axis]) {
- /* bounding-box range is before */
- offset = curveMin[clamp_axis] - ceilf((curveMin[clamp_axis] - ownLoc[clamp_axis]) / len) * len;
-
- /* now, we calculate as per normal, except using offset instead of curveMin[clamp_axis] */
- curvetime = (ownLoc[clamp_axis] - offset) / (len);
- }
- else if (ownLoc[clamp_axis] > curveMax[clamp_axis]) {
- /* bounding-box range is after */
- offset = curveMax[clamp_axis] + (int)((ownLoc[clamp_axis] - curveMax[clamp_axis]) / len) * len;
-
- /* now, we calculate as per normal, except using offset instead of curveMax[clamp_axis] */
- curvetime = (ownLoc[clamp_axis] - offset) / (len);
- }
- else {
- /* as the location falls within bounds, just calculate */
- curvetime = (ownLoc[clamp_axis] - curveMin[clamp_axis]) / (len);
- }
- }
- else {
- /* as length is close to zero, curvetime by default should be 0 (i.e. the start) */
- curvetime = 0.0f;
- }
- }
- else {
- /* no cyclic, so position is clamped to within the bounding box */
- if (ownLoc[clamp_axis] <= curveMin[clamp_axis])
- curvetime = 0.0f;
- else if (ownLoc[clamp_axis] >= curveMax[clamp_axis])
- curvetime = 1.0f;
- else if (IS_EQF((curveMax[clamp_axis] - curveMin[clamp_axis]), 0.0f) == false)
- curvetime = (ownLoc[clamp_axis] - curveMin[clamp_axis]) / (curveMax[clamp_axis] - curveMin[clamp_axis]);
- else
- curvetime = 0.0f;
- }
-
- /* 3. position on curve */
- if (where_on_path(ct->tar, curvetime, vec, dir, NULL, NULL, NULL) ) {
- unit_m4(totmat);
- copy_v3_v3(totmat[3], vec);
-
- mul_m4_m4m4(targetMatrix, ct->tar->obmat, totmat);
- }
- }
-
- /* obtain final object position */
- copy_v3_v3(cob->matrix[3], targetMatrix[3]);
- }
+ bClampToConstraint *data = con->data;
+ bConstraintTarget *ct = targets->first;
+
+ /* only evaluate if there is a target and it is a curve */
+ if (VALID_CONS_TARGET(ct) && (ct->tar->type == OB_CURVE)) {
+ float obmat[4][4], ownLoc[3];
+ float curveMin[3], curveMax[3];
+ float targetMatrix[4][4];
+
+ copy_m4_m4(obmat, cob->matrix);
+ copy_v3_v3(ownLoc, obmat[3]);
+
+ unit_m4(targetMatrix);
+ INIT_MINMAX(curveMin, curveMax);
+ /* XXX - don't think this is good calling this here - campbell */
+ BKE_object_minmax(ct->tar, curveMin, curveMax, true);
+
+ /* get targetmatrix */
+ if (data->tar->runtime.curve_cache && data->tar->runtime.curve_cache->path &&
+ data->tar->runtime.curve_cache->path->data) {
+ float vec[4], dir[3], totmat[4][4];
+ float curvetime;
+ short clamp_axis;
+
+ /* find best position on curve */
+ /* 1. determine which axis to sample on? */
+ if (data->flag == CLAMPTO_AUTO) {
+ float size[3];
+ sub_v3_v3v3(size, curveMax, curveMin);
+
+ /* find axis along which the bounding box has the greatest
+ * extent. Otherwise, default to the x-axis, as that is quite
+ * frequently used.
+ */
+ if ((size[2] > size[0]) && (size[2] > size[1]))
+ clamp_axis = CLAMPTO_Z - 1;
+ else if ((size[1] > size[0]) && (size[1] > size[2]))
+ clamp_axis = CLAMPTO_Y - 1;
+ else
+ clamp_axis = CLAMPTO_X - 1;
+ }
+ else
+ clamp_axis = data->flag - 1;
+
+ /* 2. determine position relative to curve on a 0-1 scale based on bounding box */
+ if (data->flag2 & CLAMPTO_CYCLIC) {
+ /* cyclic, so offset within relative bounding box is used */
+ float len = (curveMax[clamp_axis] - curveMin[clamp_axis]);
+ float offset;
+
+ /* check to make sure len is not so close to zero that it'll cause errors */
+ if (IS_EQF(len, 0.0f) == false) {
+ /* find bounding-box range where target is located */
+ if (ownLoc[clamp_axis] < curveMin[clamp_axis]) {
+ /* bounding-box range is before */
+ offset = curveMin[clamp_axis] -
+ ceilf((curveMin[clamp_axis] - ownLoc[clamp_axis]) / len) * len;
+
+ /* now, we calculate as per normal, except using offset instead of curveMin[clamp_axis] */
+ curvetime = (ownLoc[clamp_axis] - offset) / (len);
+ }
+ else if (ownLoc[clamp_axis] > curveMax[clamp_axis]) {
+ /* bounding-box range is after */
+ offset = curveMax[clamp_axis] +
+ (int)((ownLoc[clamp_axis] - curveMax[clamp_axis]) / len) * len;
+
+ /* now, we calculate as per normal, except using offset instead of curveMax[clamp_axis] */
+ curvetime = (ownLoc[clamp_axis] - offset) / (len);
+ }
+ else {
+ /* as the location falls within bounds, just calculate */
+ curvetime = (ownLoc[clamp_axis] - curveMin[clamp_axis]) / (len);
+ }
+ }
+ else {
+ /* as length is close to zero, curvetime by default should be 0 (i.e. the start) */
+ curvetime = 0.0f;
+ }
+ }
+ else {
+ /* no cyclic, so position is clamped to within the bounding box */
+ if (ownLoc[clamp_axis] <= curveMin[clamp_axis])
+ curvetime = 0.0f;
+ else if (ownLoc[clamp_axis] >= curveMax[clamp_axis])
+ curvetime = 1.0f;
+ else if (IS_EQF((curveMax[clamp_axis] - curveMin[clamp_axis]), 0.0f) == false)
+ curvetime = (ownLoc[clamp_axis] - curveMin[clamp_axis]) /
+ (curveMax[clamp_axis] - curveMin[clamp_axis]);
+ else
+ curvetime = 0.0f;
+ }
+
+ /* 3. position on curve */
+ if (where_on_path(ct->tar, curvetime, vec, dir, NULL, NULL, NULL)) {
+ unit_m4(totmat);
+ copy_v3_v3(totmat[3], vec);
+
+ mul_m4_m4m4(targetMatrix, ct->tar->obmat, totmat);
+ }
+ }
+
+ /* obtain final object position */
+ copy_v3_v3(cob->matrix[3], targetMatrix[3]);
+ }
}
static bConstraintTypeInfo CTI_CLAMPTO = {
- CONSTRAINT_TYPE_CLAMPTO, /* type */
- sizeof(bClampToConstraint), /* size */
- "Clamp To", /* name */
- "bClampToConstraint", /* struct name */
- NULL, /* free data */
- clampto_id_looper, /* id looper */
- NULL, /* copy data */
- NULL, /* new data */
- clampto_get_tars, /* get constraint targets */
- clampto_flush_tars, /* flush constraint targets */
- clampto_get_tarmat, /* get target matrix */
- clampto_evaluate, /* evaluate */
+ CONSTRAINT_TYPE_CLAMPTO, /* type */
+ sizeof(bClampToConstraint), /* size */
+ "Clamp To", /* name */
+ "bClampToConstraint", /* struct name */
+ NULL, /* free data */
+ clampto_id_looper, /* id looper */
+ NULL, /* copy data */
+ NULL, /* new data */
+ clampto_get_tars, /* get constraint targets */
+ clampto_flush_tars, /* flush constraint targets */
+ clampto_get_tarmat, /* get target matrix */
+ clampto_evaluate, /* evaluate */
};
/* ---------- Transform Constraint ----------- */
static void transform_new_data(void *cdata)
{
- bTransformConstraint *data = (bTransformConstraint *)cdata;
+ bTransformConstraint *data = (bTransformConstraint *)cdata;
- data->map[0] = 0;
- data->map[1] = 1;
- data->map[2] = 2;
+ data->map[0] = 0;
+ data->map[1] = 1;
+ data->map[2] = 2;
}
static void transform_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
{
- bTransformConstraint *data = con->data;
+ bTransformConstraint *data = con->data;
- /* target only */
- func(con, (ID **)&data->tar, false, userdata);
+ /* target only */
+ func(con, (ID **)&data->tar, false, userdata);
}
static int transform_get_tars(bConstraint *con, ListBase *list)
{
- if (con && list) {
- bTransformConstraint *data = con->data;
- bConstraintTarget *ct;
+ if (con && list) {
+ bTransformConstraint *data = con->data;
+ bConstraintTarget *ct;
- /* standard target-getting macro for single-target constraints */
- SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
+ /* standard target-getting macro for single-target constraints */
+ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1;
- }
+ return 1;
+ }
- return 0;
+ return 0;
}
static void transform_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
{
- if (con && list) {
- bTransformConstraint *data = con->data;
- bConstraintTarget *ct = list->first;
+ if (con && list) {
+ bTransformConstraint *data = con->data;
+ bConstraintTarget *ct = list->first;
- /* the following macro is used for all standard single-target constraints */
- SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
- }
+ /* the following macro is used for all standard single-target constraints */
+ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
+ }
}
static void transform_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets)
{
- bTransformConstraint *data = con->data;
- bConstraintTarget *ct = targets->first;
-
- /* only evaluate if there is a target */
- if (VALID_CONS_TARGET(ct)) {
- float *from_min, *from_max, *to_min, *to_max;
- float loc[3], eul[3], size[3];
- float dvec[3], sval[3];
- int i;
-
- /* obtain target effect */
- switch (data->from) {
- case TRANS_SCALE:
- mat4_to_size(dvec, ct->matrix);
-
- if (is_negative_m4(ct->matrix)) {
- /* Bugfix [#27886]
- * We can't be sure which axis/axes are negative, though we know that something is negative.
- * Assume we don't care about negativity of separate axes. <--- This is a limitation that
- * riggers will have to live with for now.
- */
- negate_v3(dvec);
- }
- from_min = data->from_min_scale;
- from_max = data->from_max_scale;
- break;
- case TRANS_ROTATION:
- mat4_to_eulO(dvec, cob->rotOrder, ct->matrix);
- from_min = data->from_min_rot;
- from_max = data->from_max_rot;
- break;
- case TRANS_LOCATION:
- default:
- copy_v3_v3(dvec, ct->matrix[3]);
- from_min = data->from_min;
- from_max = data->from_max;
- break;
- }
-
- /* extract components of owner's matrix */
- copy_v3_v3(loc, cob->matrix[3]);
- mat4_to_eulO(eul, cob->rotOrder, cob->matrix);
- mat4_to_size(size, cob->matrix);
-
- /* determine where in range current transforms lie */
- if (data->expo) {
- for (i = 0; i < 3; i++) {
- if (from_max[i] - from_min[i])
- sval[i] = (dvec[i] - from_min[i]) / (from_max[i] - from_min[i]);
- else
- sval[i] = 0.0f;
- }
- }
- else {
- /* clamp transforms out of range */
- for (i = 0; i < 3; i++) {
- CLAMP(dvec[i], from_min[i], from_max[i]);
- if (from_max[i] - from_min[i])
- sval[i] = (dvec[i] - from_min[i]) / (from_max[i] - from_min[i]);
- else
- sval[i] = 0.0f;
- }
- }
-
-
- /* apply transforms */
- switch (data->to) {
- case TRANS_SCALE:
- to_min = data->to_min_scale;
- to_max = data->to_max_scale;
- for (i = 0; i < 3; i++) {
- /* multiply with original scale (so that it can still be scaled) */
- /* size[i] *= to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i])); */
- /* Stay absolute, else it breaks existing rigs... sigh. */
- size[i] = to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i]));
- }
- break;
- case TRANS_ROTATION:
- to_min = data->to_min_rot;
- to_max = data->to_max_rot;
- for (i = 0; i < 3; i++) {
- /* add to original rotation (so that it can still be rotated) */
- eul[i] += to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i]));
- }
- break;
- case TRANS_LOCATION:
- default:
- to_min = data->to_min;
- to_max = data->to_max;
- for (i = 0; i < 3; i++) {
- /* add to original location (so that it can still be moved) */
- loc[i] += (to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i])));
- }
- break;
- }
-
- /* apply to matrix */
- loc_eulO_size_to_mat4(cob->matrix, loc, eul, size, cob->rotOrder);
- }
+ bTransformConstraint *data = con->data;
+ bConstraintTarget *ct = targets->first;
+
+ /* only evaluate if there is a target */
+ if (VALID_CONS_TARGET(ct)) {
+ float *from_min, *from_max, *to_min, *to_max;
+ float loc[3], eul[3], size[3];
+ float dvec[3], sval[3];
+ int i;
+
+ /* obtain target effect */
+ switch (data->from) {
+ case TRANS_SCALE:
+ mat4_to_size(dvec, ct->matrix);
+
+ if (is_negative_m4(ct->matrix)) {
+ /* Bugfix [#27886]
+ * We can't be sure which axis/axes are negative, though we know that something is negative.
+ * Assume we don't care about negativity of separate axes. <--- This is a limitation that
+ * riggers will have to live with for now.
+ */
+ negate_v3(dvec);
+ }
+ from_min = data->from_min_scale;
+ from_max = data->from_max_scale;
+ break;
+ case TRANS_ROTATION:
+ mat4_to_eulO(dvec, cob->rotOrder, ct->matrix);
+ from_min = data->from_min_rot;
+ from_max = data->from_max_rot;
+ break;
+ case TRANS_LOCATION:
+ default:
+ copy_v3_v3(dvec, ct->matrix[3]);
+ from_min = data->from_min;
+ from_max = data->from_max;
+ break;
+ }
+
+ /* extract components of owner's matrix */
+ copy_v3_v3(loc, cob->matrix[3]);
+ mat4_to_eulO(eul, cob->rotOrder, cob->matrix);
+ mat4_to_size(size, cob->matrix);
+
+ /* determine where in range current transforms lie */
+ if (data->expo) {
+ for (i = 0; i < 3; i++) {
+ if (from_max[i] - from_min[i])
+ sval[i] = (dvec[i] - from_min[i]) / (from_max[i] - from_min[i]);
+ else
+ sval[i] = 0.0f;
+ }
+ }
+ else {
+ /* clamp transforms out of range */
+ for (i = 0; i < 3; i++) {
+ CLAMP(dvec[i], from_min[i], from_max[i]);
+ if (from_max[i] - from_min[i])
+ sval[i] = (dvec[i] - from_min[i]) / (from_max[i] - from_min[i]);
+ else
+ sval[i] = 0.0f;
+ }
+ }
+
+ /* apply transforms */
+ switch (data->to) {
+ case TRANS_SCALE:
+ to_min = data->to_min_scale;
+ to_max = data->to_max_scale;
+ for (i = 0; i < 3; i++) {
+ /* multiply with original scale (so that it can still be scaled) */
+ /* size[i] *= to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i])); */
+ /* Stay absolute, else it breaks existing rigs... sigh. */
+ size[i] = to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i]));
+ }
+ break;
+ case TRANS_ROTATION:
+ to_min = data->to_min_rot;
+ to_max = data->to_max_rot;
+ for (i = 0; i < 3; i++) {
+ /* add to original rotation (so that it can still be rotated) */
+ eul[i] += to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i]));
+ }
+ break;
+ case TRANS_LOCATION:
+ default:
+ to_min = data->to_min;
+ to_max = data->to_max;
+ for (i = 0; i < 3; i++) {
+ /* add to original location (so that it can still be moved) */
+ loc[i] += (to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i])));
+ }
+ break;
+ }
+
+ /* apply to matrix */
+ loc_eulO_size_to_mat4(cob->matrix, loc, eul, size, cob->rotOrder);
+ }
}
static bConstraintTypeInfo CTI_TRANSFORM = {
- CONSTRAINT_TYPE_TRANSFORM, /* type */
- sizeof(bTransformConstraint), /* size */
- "Transformation", /* name */
- "bTransformConstraint", /* struct name */
- NULL, /* free data */
- transform_id_looper, /* id looper */
- NULL, /* copy data */
- transform_new_data, /* new data */
- transform_get_tars, /* get constraint targets */
- transform_flush_tars, /* flush constraint targets */
- default_get_tarmat, /* get a target matrix */
- transform_evaluate, /* evaluate */
+ CONSTRAINT_TYPE_TRANSFORM, /* type */
+ sizeof(bTransformConstraint), /* size */
+ "Transformation", /* name */
+ "bTransformConstraint", /* struct name */
+ NULL, /* free data */
+ transform_id_looper, /* id looper */
+ NULL, /* copy data */
+ transform_new_data, /* new data */
+ transform_get_tars, /* get constraint targets */
+ transform_flush_tars, /* flush constraint targets */
+ default_get_tarmat, /* get a target matrix */
+ transform_evaluate, /* evaluate */
};
/* ---------- Shrinkwrap Constraint ----------- */
static void shrinkwrap_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
{
- bShrinkwrapConstraint *data = con->data;
+ bShrinkwrapConstraint *data = con->data;
- /* target only */
- func(con, (ID **)&data->target, false, userdata);
+ /* target only */
+ func(con, (ID **)&data->target, false, userdata);
}
static void shrinkwrap_new_data(void *cdata)
{
- bShrinkwrapConstraint *data = (bShrinkwrapConstraint *)cdata;
+ bShrinkwrapConstraint *data = (bShrinkwrapConstraint *)cdata;
- data->projAxis = OB_POSZ;
- data->projAxisSpace = CONSTRAINT_SPACE_LOCAL;
+ data->projAxis = OB_POSZ;
+ data->projAxisSpace = CONSTRAINT_SPACE_LOCAL;
}
static int shrinkwrap_get_tars(bConstraint *con, ListBase *list)
{
- if (con && list) {
- bShrinkwrapConstraint *data = con->data;
- bConstraintTarget *ct;
+ if (con && list) {
+ bShrinkwrapConstraint *data = con->data;
+ bConstraintTarget *ct;
- SINGLETARGETNS_GET_TARS(con, data->target, ct, list);
+ SINGLETARGETNS_GET_TARS(con, data->target, ct, list);
- return 1;
- }
+ return 1;
+ }
- return 0;
+ return 0;
}
-
static void shrinkwrap_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
{
- if (con && list) {
- bShrinkwrapConstraint *data = con->data;
- bConstraintTarget *ct = list->first;
-
- SINGLETARGETNS_FLUSH_TARS(con, data->target, ct, list, no_copy);
- }
-}
-
-
-static void shrinkwrap_get_tarmat(struct Depsgraph *UNUSED(depsgraph), bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
-{
- bShrinkwrapConstraint *scon = (bShrinkwrapConstraint *) con->data;
-
- if (VALID_CONS_TARGET(ct) && (ct->tar->type == OB_MESH) ) {
-
- bool fail = false;
- float co[3] = {0.0f, 0.0f, 0.0f};
- bool track_normal = false;
- float track_no[3] = {0.0f, 0.0f, 0.0f};
-
- SpaceTransform transform;
- Mesh *target_eval = ct->tar->runtime.mesh_eval;
-
- copy_m4_m4(ct->matrix, cob->matrix);
-
- bool do_track_normal = (scon->flag & CON_SHRINKWRAP_TRACK_NORMAL) != 0;
- ShrinkwrapTreeData tree;
-
- if (BKE_shrinkwrap_init_tree(&tree, target_eval, scon->shrinkType, scon->shrinkMode, do_track_normal)) {
- BLI_space_transform_from_matrices(&transform, cob->matrix, ct->tar->obmat);
-
- switch (scon->shrinkType) {
- case MOD_SHRINKWRAP_NEAREST_SURFACE:
- case MOD_SHRINKWRAP_NEAREST_VERTEX:
- case MOD_SHRINKWRAP_TARGET_PROJECT:
- {
- BVHTreeNearest nearest;
-
- nearest.index = -1;
- nearest.dist_sq = FLT_MAX;
-
- BLI_space_transform_apply(&transform, co);
-
- BKE_shrinkwrap_find_nearest_surface(&tree, &nearest, co, scon->shrinkType);
-
- if (nearest.index < 0) {
- fail = true;
- break;
- }
-
- if (scon->shrinkType != MOD_SHRINKWRAP_NEAREST_VERTEX) {
- if (do_track_normal) {
- track_normal = true;
- BKE_shrinkwrap_compute_smooth_normal(&tree, NULL, nearest.index, nearest.co, nearest.no, track_no);
- BLI_space_transform_invert_normal(&transform, track_no);
- }
-
- BKE_shrinkwrap_snap_point_to_surface(&tree, NULL, scon->shrinkMode, nearest.index, nearest.co, nearest.no, scon->dist, co, co);
- }
- else {
- const float dist = len_v3v3(co, nearest.co);
-
- if (dist != 0.0f) {
- interp_v3_v3v3(co, co, nearest.co, (dist - scon->dist) / dist); /* linear interpolation */
- }
- }
-
- BLI_space_transform_invert(&transform, co);
- break;
- }
- case MOD_SHRINKWRAP_PROJECT:
- {
- BVHTreeRayHit hit;
-
- float mat[4][4];
- float no[3] = {0.0f, 0.0f, 0.0f};
-
- /* TODO should use FLT_MAX.. but normal projection doenst yet supports it */
- hit.index = -1;
- hit.dist = (scon->projLimit == 0.0f) ? BVH_RAYCAST_DIST_MAX : scon->projLimit;
-
- switch (scon->projAxis) {
- case OB_POSX: case OB_POSY: case OB_POSZ:
- no[scon->projAxis - OB_POSX] = 1.0f;
- break;
- case OB_NEGX: case OB_NEGY: case OB_NEGZ:
- no[scon->projAxis - OB_NEGX] = -1.0f;
- break;
- }
-
- /* transform normal into requested space */
- /* Note that in this specific case, we need to keep scaling in non-parented 'local2world' object
- * case, because SpaceTransform also takes it into account when handling normals. See T42447. */
- unit_m4(mat);
- BKE_constraint_mat_convertspace(cob->ob, cob->pchan, mat,
- CONSTRAINT_SPACE_LOCAL, scon->projAxisSpace, true);
- invert_m4(mat);
- mul_mat3_m4_v3(mat, no);
-
- if (normalize_v3(no) < FLT_EPSILON) {
- fail = true;
- break;
- }
-
- char cull_mode = scon->flag & CON_SHRINKWRAP_PROJECT_CULL_MASK;
-
- BKE_shrinkwrap_project_normal(cull_mode, co, no, 0.0f, &transform, &tree, &hit);
-
- if (scon->flag & CON_SHRINKWRAP_PROJECT_OPPOSITE) {
- float inv_no[3];
- negate_v3_v3(inv_no, no);
-
- if ((scon->flag & CON_SHRINKWRAP_PROJECT_INVERT_CULL) && (cull_mode != 0)) {
- cull_mode ^= CON_SHRINKWRAP_PROJECT_CULL_MASK;
- }
-
- BKE_shrinkwrap_project_normal(cull_mode, co, inv_no, 0.0f, &transform, &tree, &hit);
- }
-
- if (hit.index < 0) {
- fail = true;
- break;
- }
-
- if (do_track_normal) {
- track_normal = true;
- BKE_shrinkwrap_compute_smooth_normal(&tree, &transform, hit.index, hit.co, hit.no, track_no);
- }
-
- BKE_shrinkwrap_snap_point_to_surface(&tree, &transform, scon->shrinkMode, hit.index, hit.co, hit.no, scon->dist, co, co);
- break;
- }
- }
-
- BKE_shrinkwrap_free_tree(&tree);
-
- if (fail == true) {
- /* Don't move the point */
- zero_v3(co);
- }
-
- /* co is in local object coordinates, change it to global and update target position */
- mul_m4_v3(cob->matrix, co);
- copy_v3_v3(ct->matrix[3], co);
-
- if (track_normal) {
- mul_mat3_m4_v3(cob->matrix, track_no);
- damptrack_do_transform(ct->matrix, track_no, scon->trackAxis);
- }
- }
- }
+ if (con && list) {
+ bShrinkwrapConstraint *data = con->data;
+ bConstraintTarget *ct = list->first;
+
+ SINGLETARGETNS_FLUSH_TARS(con, data->target, ct, list, no_copy);
+ }
+}
+
+static void shrinkwrap_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
+ bConstraint *con,
+ bConstraintOb *cob,
+ bConstraintTarget *ct,
+ float UNUSED(ctime))
+{
+ bShrinkwrapConstraint *scon = (bShrinkwrapConstraint *)con->data;
+
+ if (VALID_CONS_TARGET(ct) && (ct->tar->type == OB_MESH)) {
+
+ bool fail = false;
+ float co[3] = {0.0f, 0.0f, 0.0f};
+ bool track_normal = false;
+ float track_no[3] = {0.0f, 0.0f, 0.0f};
+
+ SpaceTransform transform;
+ Mesh *target_eval = ct->tar->runtime.mesh_eval;
+
+ copy_m4_m4(ct->matrix, cob->matrix);
+
+ bool do_track_normal = (scon->flag & CON_SHRINKWRAP_TRACK_NORMAL) != 0;
+ ShrinkwrapTreeData tree;
+
+ if (BKE_shrinkwrap_init_tree(
+ &tree, target_eval, scon->shrinkType, scon->shrinkMode, do_track_normal)) {
+ BLI_space_transform_from_matrices(&transform, cob->matrix, ct->tar->obmat);
+
+ switch (scon->shrinkType) {
+ case MOD_SHRINKWRAP_NEAREST_SURFACE:
+ case MOD_SHRINKWRAP_NEAREST_VERTEX:
+ case MOD_SHRINKWRAP_TARGET_PROJECT: {
+ BVHTreeNearest nearest;
+
+ nearest.index = -1;
+ nearest.dist_sq = FLT_MAX;
+
+ BLI_space_transform_apply(&transform, co);
+
+ BKE_shrinkwrap_find_nearest_surface(&tree, &nearest, co, scon->shrinkType);
+
+ if (nearest.index < 0) {
+ fail = true;
+ break;
+ }
+
+ if (scon->shrinkType != MOD_SHRINKWRAP_NEAREST_VERTEX) {
+ if (do_track_normal) {
+ track_normal = true;
+ BKE_shrinkwrap_compute_smooth_normal(
+ &tree, NULL, nearest.index, nearest.co, nearest.no, track_no);
+ BLI_space_transform_invert_normal(&transform, track_no);
+ }
+
+ BKE_shrinkwrap_snap_point_to_surface(&tree,
+ NULL,
+ scon->shrinkMode,
+ nearest.index,
+ nearest.co,
+ nearest.no,
+ scon->dist,
+ co,
+ co);
+ }
+ else {
+ const float dist = len_v3v3(co, nearest.co);
+
+ if (dist != 0.0f) {
+ interp_v3_v3v3(
+ co, co, nearest.co, (dist - scon->dist) / dist); /* linear interpolation */
+ }
+ }
+
+ BLI_space_transform_invert(&transform, co);
+ break;
+ }
+ case MOD_SHRINKWRAP_PROJECT: {
+ BVHTreeRayHit hit;
+
+ float mat[4][4];
+ float no[3] = {0.0f, 0.0f, 0.0f};
+
+ /* TODO should use FLT_MAX.. but normal projection doenst yet supports it */
+ hit.index = -1;
+ hit.dist = (scon->projLimit == 0.0f) ? BVH_RAYCAST_DIST_MAX : scon->projLimit;
+
+ switch (scon->projAxis) {
+ case OB_POSX:
+ case OB_POSY:
+ case OB_POSZ:
+ no[scon->projAxis - OB_POSX] = 1.0f;
+ break;
+ case OB_NEGX:
+ case OB_NEGY:
+ case OB_NEGZ:
+ no[scon->projAxis - OB_NEGX] = -1.0f;
+ break;
+ }
+
+ /* transform normal into requested space */
+ /* Note that in this specific case, we need to keep scaling in non-parented 'local2world' object
+ * case, because SpaceTransform also takes it into account when handling normals. See T42447. */
+ unit_m4(mat);
+ BKE_constraint_mat_convertspace(
+ cob->ob, cob->pchan, mat, CONSTRAINT_SPACE_LOCAL, scon->projAxisSpace, true);
+ invert_m4(mat);
+ mul_mat3_m4_v3(mat, no);
+
+ if (normalize_v3(no) < FLT_EPSILON) {
+ fail = true;
+ break;
+ }
+
+ char cull_mode = scon->flag & CON_SHRINKWRAP_PROJECT_CULL_MASK;
+
+ BKE_shrinkwrap_project_normal(cull_mode, co, no, 0.0f, &transform, &tree, &hit);
+
+ if (scon->flag & CON_SHRINKWRAP_PROJECT_OPPOSITE) {
+ float inv_no[3];
+ negate_v3_v3(inv_no, no);
+
+ if ((scon->flag & CON_SHRINKWRAP_PROJECT_INVERT_CULL) && (cull_mode != 0)) {
+ cull_mode ^= CON_SHRINKWRAP_PROJECT_CULL_MASK;
+ }
+
+ BKE_shrinkwrap_project_normal(cull_mode, co, inv_no, 0.0f, &transform, &tree, &hit);
+ }
+
+ if (hit.index < 0) {
+ fail = true;
+ break;
+ }
+
+ if (do_track_normal) {
+ track_normal = true;
+ BKE_shrinkwrap_compute_smooth_normal(
+ &tree, &transform, hit.index, hit.co, hit.no, track_no);
+ }
+
+ BKE_shrinkwrap_snap_point_to_surface(
+ &tree, &transform, scon->shrinkMode, hit.index, hit.co, hit.no, scon->dist, co, co);
+ break;
+ }
+ }
+
+ BKE_shrinkwrap_free_tree(&tree);
+
+ if (fail == true) {
+ /* Don't move the point */
+ zero_v3(co);
+ }
+
+ /* co is in local object coordinates, change it to global and update target position */
+ mul_m4_v3(cob->matrix, co);
+ copy_v3_v3(ct->matrix[3], co);
+
+ if (track_normal) {
+ mul_mat3_m4_v3(cob->matrix, track_no);
+ damptrack_do_transform(ct->matrix, track_no, scon->trackAxis);
+ }
+ }
+ }
}
static void shrinkwrap_evaluate(bConstraint *UNUSED(con), bConstraintOb *cob, ListBase *targets)
{
- bConstraintTarget *ct = targets->first;
+ bConstraintTarget *ct = targets->first;
- /* only evaluate if there is a target */
- if (VALID_CONS_TARGET(ct)) {
- copy_m4_m4(cob->matrix, ct->matrix);
- }
+ /* only evaluate if there is a target */
+ if (VALID_CONS_TARGET(ct)) {
+ copy_m4_m4(cob->matrix, ct->matrix);
+ }
}
static bConstraintTypeInfo CTI_SHRINKWRAP = {
- CONSTRAINT_TYPE_SHRINKWRAP, /* type */
- sizeof(bShrinkwrapConstraint), /* size */
- "Shrinkwrap", /* name */
- "bShrinkwrapConstraint", /* struct name */
- NULL, /* free data */
- shrinkwrap_id_looper, /* id looper */
- NULL, /* copy data */
- shrinkwrap_new_data, /* new data */
- shrinkwrap_get_tars, /* get constraint targets */
- shrinkwrap_flush_tars, /* flush constraint targets */
- shrinkwrap_get_tarmat, /* get a target matrix */
- shrinkwrap_evaluate, /* evaluate */
+ CONSTRAINT_TYPE_SHRINKWRAP, /* type */
+ sizeof(bShrinkwrapConstraint), /* size */
+ "Shrinkwrap", /* name */
+ "bShrinkwrapConstraint", /* struct name */
+ NULL, /* free data */
+ shrinkwrap_id_looper, /* id looper */
+ NULL, /* copy data */
+ shrinkwrap_new_data, /* new data */
+ shrinkwrap_get_tars, /* get constraint targets */
+ shrinkwrap_flush_tars, /* flush constraint targets */
+ shrinkwrap_get_tarmat, /* get a target matrix */
+ shrinkwrap_evaluate, /* evaluate */
};
/* --------- Damped Track ---------- */
static void damptrack_new_data(void *cdata)
{
- bDampTrackConstraint *data = (bDampTrackConstraint *)cdata;
+ bDampTrackConstraint *data = (bDampTrackConstraint *)cdata;
- data->trackflag = TRACK_Y;
+ data->trackflag = TRACK_Y;
}
static void damptrack_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
{
- bDampTrackConstraint *data = con->data;
+ bDampTrackConstraint *data = con->data;
- /* target only */
- func(con, (ID **)&data->tar, false, userdata);
+ /* target only */
+ func(con, (ID **)&data->tar, false, userdata);
}
static int damptrack_get_tars(bConstraint *con, ListBase *list)
{
- if (con && list) {
- bDampTrackConstraint *data = con->data;
- bConstraintTarget *ct;
+ if (con && list) {
+ bDampTrackConstraint *data = con->data;
+ bConstraintTarget *ct;
- /* the following macro is used for all standard single-target constraints */
- SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
+ /* the following macro is used for all standard single-target constraints */
+ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1;
- }
+ return 1;
+ }
- return 0;
+ return 0;
}
static void damptrack_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
{
- if (con && list) {
- bDampTrackConstraint *data = con->data;
- bConstraintTarget *ct = list->first;
+ if (con && list) {
+ bDampTrackConstraint *data = con->data;
+ bConstraintTarget *ct = list->first;
- /* the following macro is used for all standard single-target constraints */
- SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
- }
+ /* the following macro is used for all standard single-target constraints */
+ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
+ }
}
/* array of direction vectors for the tracking flags */
static const float track_dir_vecs[6][3] = {
- {+1, 0, 0}, {0, +1, 0}, {0, 0, +1}, /* TRACK_X, TRACK_Y, TRACK_Z */
- {-1, 0, 0}, {0, -1, 0}, {0, 0, -1} /* TRACK_NX, TRACK_NY, TRACK_NZ */
+ {+1, 0, 0},
+ {0, +1, 0},
+ {0, 0, +1}, /* TRACK_X, TRACK_Y, TRACK_Z */
+ {-1, 0, 0},
+ {0, -1, 0},
+ {0, 0, -1} /* TRACK_NX, TRACK_NY, TRACK_NZ */
};
static void damptrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets)
{
- bDampTrackConstraint *data = con->data;
- bConstraintTarget *ct = targets->first;
+ bDampTrackConstraint *data = con->data;
+ bConstraintTarget *ct = targets->first;
- if (VALID_CONS_TARGET(ct)) {
- float tarvec[3];
+ if (VALID_CONS_TARGET(ct)) {
+ float tarvec[3];
- /* find the (unit) direction vector going from the owner to the target */
- sub_v3_v3v3(tarvec, ct->matrix[3], cob->matrix[3]);
+ /* find the (unit) direction vector going from the owner to the target */
+ sub_v3_v3v3(tarvec, ct->matrix[3], cob->matrix[3]);
- damptrack_do_transform(cob->matrix, tarvec, data->trackflag);
- }
+ damptrack_do_transform(cob->matrix, tarvec, data->trackflag);
+ }
}
static void damptrack_do_transform(float matrix[4][4], const float tarvec_in[3], int track_axis)
{
- /* find the (unit) direction vector going from the owner to the target */
- float tarvec[3];
-
- if (normalize_v3_v3(tarvec, tarvec_in) != 0.0f) {
- float obvec[3], obloc[3];
- float raxis[3], rangle;
- float rmat[3][3], tmat[4][4];
-
- /* find the (unit) direction that the axis we're interested in currently points
- * - mul_mat3_m4_v3() only takes the 3x3 (rotation+scaling) components of the 4x4 matrix
- * - the normalization step at the end should take care of any unwanted scaling
- * left over in the 3x3 matrix we used
- */
- copy_v3_v3(obvec, track_dir_vecs[track_axis]);
- mul_mat3_m4_v3(matrix, obvec);
-
- if (normalize_v3(obvec) == 0.0f) {
- /* exceptional case - just use the track vector as appropriate */
- copy_v3_v3(obvec, track_dir_vecs[track_axis]);
- }
-
- copy_v3_v3(obloc, matrix[3]);
-
- /* determine the axis-angle rotation, which represents the smallest possible rotation
- * between the two rotation vectors (i.e. the 'damping' referred to in the name)
- * - we take this to be the rotation around the normal axis/vector to the plane defined
- * by the current and destination vectors, which will 'map' the current axis to the
- * destination vector
- * - the min/max wrappers around (obvec . tarvec) result (stored temporarily in rangle)
- * are used to ensure that the smallest angle is chosen
- */
- cross_v3_v3v3_hi_prec(raxis, obvec, tarvec);
-
- rangle = dot_v3v3(obvec, tarvec);
- rangle = acosf(max_ff(-1.0f, min_ff(1.0f, rangle)));
-
- /* construct rotation matrix from the axis-angle rotation found above
- * - this call takes care to make sure that the axis provided is a unit vector first
- */
- float norm = normalize_v3(raxis);
-
- if (norm < FLT_EPSILON) {
- /* if dot product is nonzero, while cross is zero, we have two opposite vectors!
- * - this is an ambiguity in the math that needs to be resolved arbitrarily,
- * or there will be a case where damped track strangely does nothing
- * - to do that, rotate around a different local axis
- */
- float tmpvec[3];
-
- if (fabsf(rangle) < M_PI - 0.01f) {
- return;
- }
-
- rangle = M_PI;
- copy_v3_v3(tmpvec, track_dir_vecs[(track_axis + 1) % 6]);
- mul_mat3_m4_v3(matrix, tmpvec);
- cross_v3_v3v3(raxis, obvec, tmpvec);
-
- if (normalize_v3(raxis) == 0.0f) {
- return;
- }
- }
- else if (norm < 0.1f) {
- /* near 0 and Pi arcsin has way better precision than arccos */
- rangle = (rangle > M_PI_2) ? M_PI - asinf(norm) : asinf(norm);
- }
-
- axis_angle_normalized_to_mat3(rmat, raxis, rangle);
-
- /* rotate the owner in the way defined by this rotation matrix, then reapply the location since
- * we may have destroyed that in the process of multiplying the matrix
- */
- unit_m4(tmat);
- mul_m4_m3m4(tmat, rmat, matrix); // m1, m3, m2
-
- copy_m4_m4(matrix, tmat);
- copy_v3_v3(matrix[3], obloc);
- }
+ /* find the (unit) direction vector going from the owner to the target */
+ float tarvec[3];
+
+ if (normalize_v3_v3(tarvec, tarvec_in) != 0.0f) {
+ float obvec[3], obloc[3];
+ float raxis[3], rangle;
+ float rmat[3][3], tmat[4][4];
+
+ /* find the (unit) direction that the axis we're interested in currently points
+ * - mul_mat3_m4_v3() only takes the 3x3 (rotation+scaling) components of the 4x4 matrix
+ * - the normalization step at the end should take care of any unwanted scaling
+ * left over in the 3x3 matrix we used
+ */
+ copy_v3_v3(obvec, track_dir_vecs[track_axis]);
+ mul_mat3_m4_v3(matrix, obvec);
+
+ if (normalize_v3(obvec) == 0.0f) {
+ /* exceptional case - just use the track vector as appropriate */
+ copy_v3_v3(obvec, track_dir_vecs[track_axis]);
+ }
+
+ copy_v3_v3(obloc, matrix[3]);
+
+ /* determine the axis-angle rotation, which represents the smallest possible rotation
+ * between the two rotation vectors (i.e. the 'damping' referred to in the name)
+ * - we take this to be the rotation around the normal axis/vector to the plane defined
+ * by the current and destination vectors, which will 'map' the current axis to the
+ * destination vector
+ * - the min/max wrappers around (obvec . tarvec) result (stored temporarily in rangle)
+ * are used to ensure that the smallest angle is chosen
+ */
+ cross_v3_v3v3_hi_prec(raxis, obvec, tarvec);
+
+ rangle = dot_v3v3(obvec, tarvec);
+ rangle = acosf(max_ff(-1.0f, min_ff(1.0f, rangle)));
+
+ /* construct rotation matrix from the axis-angle rotation found above
+ * - this call takes care to make sure that the axis provided is a unit vector first
+ */
+ float norm = normalize_v3(raxis);
+
+ if (norm < FLT_EPSILON) {
+ /* if dot product is nonzero, while cross is zero, we have two opposite vectors!
+ * - this is an ambiguity in the math that needs to be resolved arbitrarily,
+ * or there will be a case where damped track strangely does nothing
+ * - to do that, rotate around a different local axis
+ */
+ float tmpvec[3];
+
+ if (fabsf(rangle) < M_PI - 0.01f) {
+ return;
+ }
+
+ rangle = M_PI;
+ copy_v3_v3(tmpvec, track_dir_vecs[(track_axis + 1) % 6]);
+ mul_mat3_m4_v3(matrix, tmpvec);
+ cross_v3_v3v3(raxis, obvec, tmpvec);
+
+ if (normalize_v3(raxis) == 0.0f) {
+ return;
+ }
+ }
+ else if (norm < 0.1f) {
+ /* near 0 and Pi arcsin has way better precision than arccos */
+ rangle = (rangle > M_PI_2) ? M_PI - asinf(norm) : asinf(norm);
+ }
+
+ axis_angle_normalized_to_mat3(rmat, raxis, rangle);
+
+ /* rotate the owner in the way defined by this rotation matrix, then reapply the location since
+ * we may have destroyed that in the process of multiplying the matrix
+ */
+ unit_m4(tmat);
+ mul_m4_m3m4(tmat, rmat, matrix); // m1, m3, m2
+
+ copy_m4_m4(matrix, tmat);
+ copy_v3_v3(matrix[3], obloc);
+ }
}
static bConstraintTypeInfo CTI_DAMPTRACK = {
- CONSTRAINT_TYPE_DAMPTRACK, /* type */
- sizeof(bDampTrackConstraint), /* size */
- "Damped Track", /* name */
- "bDampTrackConstraint", /* struct name */
- NULL, /* free data */
- damptrack_id_looper, /* id looper */
- NULL, /* copy data */
- damptrack_new_data, /* new data */
- damptrack_get_tars, /* get constraint targets */
- damptrack_flush_tars, /* flush constraint targets */
- default_get_tarmat, /* get target matrix */
- damptrack_evaluate, /* evaluate */
+ CONSTRAINT_TYPE_DAMPTRACK, /* type */
+ sizeof(bDampTrackConstraint), /* size */
+ "Damped Track", /* name */
+ "bDampTrackConstraint", /* struct name */
+ NULL, /* free data */
+ damptrack_id_looper, /* id looper */
+ NULL, /* copy data */
+ damptrack_new_data, /* new data */
+ damptrack_get_tars, /* get constraint targets */
+ damptrack_flush_tars, /* flush constraint targets */
+ default_get_tarmat, /* get target matrix */
+ damptrack_evaluate, /* evaluate */
};
/* ----------- Spline IK ------------ */
static void splineik_free(bConstraint *con)
{
- bSplineIKConstraint *data = con->data;
+ bSplineIKConstraint *data = con->data;
- /* binding array */
- if (data->points)
- MEM_freeN(data->points);
+ /* binding array */
+ if (data->points)
+ MEM_freeN(data->points);
}
static void splineik_copy(bConstraint *con, bConstraint *srccon)
{
- bSplineIKConstraint *src = srccon->data;
- bSplineIKConstraint *dst = con->data;
+ bSplineIKConstraint *src = srccon->data;
+ bSplineIKConstraint *dst = con->data;
- /* copy the binding array */
- dst->points = MEM_dupallocN(src->points);
+ /* copy the binding array */
+ dst->points = MEM_dupallocN(src->points);
}
static void splineik_new_data(void *cdata)
{
- bSplineIKConstraint *data = (bSplineIKConstraint *)cdata;
+ bSplineIKConstraint *data = (bSplineIKConstraint *)cdata;
- data->chainlen = 1;
- data->bulge = 1.0;
- data->bulge_max = 1.0f;
- data->bulge_min = 1.0f;
+ data->chainlen = 1;
+ data->bulge = 1.0;
+ data->bulge_max = 1.0f;
+ data->bulge_min = 1.0f;
- data->yScaleMode = CONSTRAINT_SPLINEIK_YS_FIT_CURVE;
+ data->yScaleMode = CONSTRAINT_SPLINEIK_YS_FIT_CURVE;
}
static void splineik_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
{
- bSplineIKConstraint *data = con->data;
+ bSplineIKConstraint *data = con->data;
- /* target only */
- func(con, (ID **)&data->tar, false, userdata);
+ /* target only */
+ func(con, (ID **)&data->tar, false, userdata);
}
static int splineik_get_tars(bConstraint *con, ListBase *list)
{
- if (con && list) {
- bSplineIKConstraint *data = con->data;
- bConstraintTarget *ct;
+ if (con && list) {
+ bSplineIKConstraint *data = con->data;
+ bConstraintTarget *ct;
- /* standard target-getting macro for single-target constraints without subtargets */
- SINGLETARGETNS_GET_TARS(con, data->tar, ct, list);
+ /* standard target-getting macro for single-target constraints without subtargets */
+ SINGLETARGETNS_GET_TARS(con, data->tar, ct, list);
- return 1;
- }
+ return 1;
+ }
- return 0;
+ return 0;
}
static void splineik_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
{
- if (con && list) {
- bSplineIKConstraint *data = con->data;
- bConstraintTarget *ct = list->first;
+ if (con && list) {
+ bSplineIKConstraint *data = con->data;
+ bConstraintTarget *ct = list->first;
- /* the following macro is used for all standard single-target constraints */
- SINGLETARGETNS_FLUSH_TARS(con, data->tar, ct, list, no_copy);
- }
+ /* the following macro is used for all standard single-target constraints */
+ SINGLETARGETNS_FLUSH_TARS(con, data->tar, ct, list, no_copy);
+ }
}
static void splineik_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
- bConstraint *UNUSED(con), bConstraintOb *UNUSED(cob),
- bConstraintTarget *ct, float UNUSED(ctime))
+ bConstraint *UNUSED(con),
+ bConstraintOb *UNUSED(cob),
+ bConstraintTarget *ct,
+ float UNUSED(ctime))
{
- /* technically, this isn't really needed for evaluation, but we don't know what else
- * might end up calling this...
- */
- if (ct)
- unit_m4(ct->matrix);
+ /* technically, this isn't really needed for evaluation, but we don't know what else
+ * might end up calling this...
+ */
+ if (ct)
+ unit_m4(ct->matrix);
}
static bConstraintTypeInfo CTI_SPLINEIK = {
- CONSTRAINT_TYPE_SPLINEIK, /* type */
- sizeof(bSplineIKConstraint), /* size */
- "Spline IK", /* name */
- "bSplineIKConstraint", /* struct name */
- splineik_free, /* free data */
- splineik_id_looper, /* id looper */
- splineik_copy, /* copy data */
- splineik_new_data, /* new data */
- splineik_get_tars, /* get constraint targets */
- splineik_flush_tars, /* flush constraint targets */
- splineik_get_tarmat, /* get target matrix */
- NULL, /* evaluate - solved as separate loop */
+ CONSTRAINT_TYPE_SPLINEIK, /* type */
+ sizeof(bSplineIKConstraint), /* size */
+ "Spline IK", /* name */
+ "bSplineIKConstraint", /* struct name */
+ splineik_free, /* free data */
+ splineik_id_looper, /* id looper */
+ splineik_copy, /* copy data */
+ splineik_new_data, /* new data */
+ splineik_get_tars, /* get constraint targets */
+ splineik_flush_tars, /* flush constraint targets */
+ splineik_get_tarmat, /* get target matrix */
+ NULL, /* evaluate - solved as separate loop */
};
/* ----------- Pivot ------------- */
static void pivotcon_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
{
- bPivotConstraint *data = con->data;
+ bPivotConstraint *data = con->data;
- /* target only */
- func(con, (ID **)&data->tar, false, userdata);
+ /* target only */
+ func(con, (ID **)&data->tar, false, userdata);
}
static int pivotcon_get_tars(bConstraint *con, ListBase *list)
{
- if (con && list) {
- bPivotConstraint *data = con->data;
- bConstraintTarget *ct;
+ if (con && list) {
+ bPivotConstraint *data = con->data;
+ bConstraintTarget *ct;
- /* standard target-getting macro for single-target constraints */
- SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
+ /* standard target-getting macro for single-target constraints */
+ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1;
- }
+ return 1;
+ }
- return 0;
+ return 0;
}
static void pivotcon_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
{
- if (con && list) {
- bPivotConstraint *data = con->data;
- bConstraintTarget *ct = list->first;
+ if (con && list) {
+ bPivotConstraint *data = con->data;
+ bConstraintTarget *ct = list->first;
- /* the following macro is used for all standard single-target constraints */
- SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
- }
+ /* the following macro is used for all standard single-target constraints */
+ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
+ }
}
static void pivotcon_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets)
{
- bPivotConstraint *data = con->data;
- bConstraintTarget *ct = targets->first;
-
- float pivot[3], vec[3];
- float rotMat[3][3];
-
- /* pivot correction */
- float axis[3], angle;
-
- /* firstly, check if pivoting should take place based on the current rotation */
- if (data->rotAxis != PIVOTCON_AXIS_NONE) {
- float rot[3];
-
- /* extract euler-rotation of target */
- mat4_to_eulO(rot, cob->rotOrder, cob->matrix);
-
- /* check which range might be violated */
- if (data->rotAxis < PIVOTCON_AXIS_X) {
- /* negative rotations (data->rotAxis = 0 -> 2) */
- if (rot[data->rotAxis] > 0.0f)
- return;
- }
- else {
- /* positive rotations (data->rotAxis = 3 -> 5 */
- if (rot[data->rotAxis - PIVOTCON_AXIS_X] < 0.0f)
- return;
- }
- }
-
- /* find the pivot-point to use */
- if (VALID_CONS_TARGET(ct)) {
- /* apply offset to target location */
- add_v3_v3v3(pivot, ct->matrix[3], data->offset);
- }
- else {
- /* no targets to worry about... */
- if ((data->flag & PIVOTCON_FLAG_OFFSET_ABS) == 0) {
- /* offset is relative to owner */
- add_v3_v3v3(pivot, cob->matrix[3], data->offset);
- }
- else {
- /* directly use the 'offset' specified as an absolute position instead */
- copy_v3_v3(pivot, data->offset);
- }
- }
-
- /* get rotation matrix representing the rotation of the owner */
- /* TODO: perhaps we might want to include scaling based on the pivot too? */
- copy_m3_m4(rotMat, cob->matrix);
- normalize_m3(rotMat);
-
-
- /* correct the pivot by the rotation axis otherwise the pivot translates when it shouldnt */
- mat3_normalized_to_axis_angle(axis, &angle, rotMat);
- if (angle) {
- float dvec[3];
- sub_v3_v3v3(vec, pivot, cob->matrix[3]);
- project_v3_v3v3(dvec, vec, axis);
- sub_v3_v3(pivot, dvec);
- }
-
- /* perform the pivoting... */
- /* 1. take the vector from owner to the pivot */
- sub_v3_v3v3(vec, cob->matrix[3], pivot);
- /* 2. rotate this vector by the rotation of the object... */
- mul_m3_v3(rotMat, vec);
- /* 3. make the rotation in terms of the pivot now */
- add_v3_v3v3(cob->matrix[3], pivot, vec);
+ bPivotConstraint *data = con->data;
+ bConstraintTarget *ct = targets->first;
+
+ float pivot[3], vec[3];
+ float rotMat[3][3];
+
+ /* pivot correction */
+ float axis[3], angle;
+
+ /* firstly, check if pivoting should take place based on the current rotation */
+ if (data->rotAxis != PIVOTCON_AXIS_NONE) {
+ float rot[3];
+
+ /* extract euler-rotation of target */
+ mat4_to_eulO(rot, cob->rotOrder, cob->matrix);
+
+ /* check which range might be violated */
+ if (data->rotAxis < PIVOTCON_AXIS_X) {
+ /* negative rotations (data->rotAxis = 0 -> 2) */
+ if (rot[data->rotAxis] > 0.0f)
+ return;
+ }
+ else {
+ /* positive rotations (data->rotAxis = 3 -> 5 */
+ if (rot[data->rotAxis - PIVOTCON_AXIS_X] < 0.0f)
+ return;
+ }
+ }
+
+ /* find the pivot-point to use */
+ if (VALID_CONS_TARGET(ct)) {
+ /* apply offset to target location */
+ add_v3_v3v3(pivot, ct->matrix[3], data->offset);
+ }
+ else {
+ /* no targets to worry about... */
+ if ((data->flag & PIVOTCON_FLAG_OFFSET_ABS) == 0) {
+ /* offset is relative to owner */
+ add_v3_v3v3(pivot, cob->matrix[3], data->offset);
+ }
+ else {
+ /* directly use the 'offset' specified as an absolute position instead */
+ copy_v3_v3(pivot, data->offset);
+ }
+ }
+
+ /* get rotation matrix representing the rotation of the owner */
+ /* TODO: perhaps we might want to include scaling based on the pivot too? */
+ copy_m3_m4(rotMat, cob->matrix);
+ normalize_m3(rotMat);
+
+ /* correct the pivot by the rotation axis otherwise the pivot translates when it shouldnt */
+ mat3_normalized_to_axis_angle(axis, &angle, rotMat);
+ if (angle) {
+ float dvec[3];
+ sub_v3_v3v3(vec, pivot, cob->matrix[3]);
+ project_v3_v3v3(dvec, vec, axis);
+ sub_v3_v3(pivot, dvec);
+ }
+
+ /* perform the pivoting... */
+ /* 1. take the vector from owner to the pivot */
+ sub_v3_v3v3(vec, cob->matrix[3], pivot);
+ /* 2. rotate this vector by the rotation of the object... */
+ mul_m3_v3(rotMat, vec);
+ /* 3. make the rotation in terms of the pivot now */
+ add_v3_v3v3(cob->matrix[3], pivot, vec);
}
-
static bConstraintTypeInfo CTI_PIVOT = {
- CONSTRAINT_TYPE_PIVOT, /* type */
- sizeof(bPivotConstraint), /* size */
- "Pivot", /* name */
- "bPivotConstraint", /* struct name */
- NULL, /* free data */
- pivotcon_id_looper, /* id looper */
- NULL, /* copy data */
- NULL, /* new data */ // XXX: might be needed to get 'normal' pivot behavior...
- pivotcon_get_tars, /* get constraint targets */
- pivotcon_flush_tars, /* flush constraint targets */
- default_get_tarmat, /* get target matrix */
- pivotcon_evaluate, /* evaluate */
+ CONSTRAINT_TYPE_PIVOT, /* type */
+ sizeof(bPivotConstraint), /* size */
+ "Pivot", /* name */
+ "bPivotConstraint", /* struct name */
+ NULL, /* free data */
+ pivotcon_id_looper, /* id looper */
+ NULL, /* copy data */
+ NULL,
+ /* new data */ // XXX: might be needed to get 'normal' pivot behavior...
+ pivotcon_get_tars, /* get constraint targets */
+ pivotcon_flush_tars, /* flush constraint targets */
+ default_get_tarmat, /* get target matrix */
+ pivotcon_evaluate, /* evaluate */
};
/* ----------- Follow Track ------------- */
static void followtrack_new_data(void *cdata)
{
- bFollowTrackConstraint *data = (bFollowTrackConstraint *)cdata;
+ bFollowTrackConstraint *data = (bFollowTrackConstraint *)cdata;
- data->clip = NULL;
- data->flag |= FOLLOWTRACK_ACTIVECLIP;
+ data->clip = NULL;
+ data->flag |= FOLLOWTRACK_ACTIVECLIP;
}
static void followtrack_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
{
- bFollowTrackConstraint *data = con->data;
+ bFollowTrackConstraint *data = con->data;
- func(con, (ID **)&data->clip, true, userdata);
- func(con, (ID **)&data->camera, false, userdata);
- func(con, (ID **)&data->depth_ob, false, userdata);
+ func(con, (ID **)&data->clip, true, userdata);
+ func(con, (ID **)&data->camera, false, userdata);
+ func(con, (ID **)&data->depth_ob, false, userdata);
}
static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UNUSED(targets))
{
- Depsgraph *depsgraph = cob->depsgraph;
- Scene *scene = cob->scene;
- bFollowTrackConstraint *data = con->data;
- MovieClip *clip = data->clip;
- MovieTracking *tracking;
- MovieTrackingTrack *track;
- MovieTrackingObject *tracking_object;
-
- Object *camob_eval = DEG_get_evaluated_object(
- depsgraph,
- data->camera ? data->camera : scene->camera);
+ Depsgraph *depsgraph = cob->depsgraph;
+ Scene *scene = cob->scene;
+ bFollowTrackConstraint *data = con->data;
+ MovieClip *clip = data->clip;
+ MovieTracking *tracking;
+ MovieTrackingTrack *track;
+ MovieTrackingObject *tracking_object;
- float ctime = DEG_get_ctime(depsgraph);
- float framenr;
+ Object *camob_eval = DEG_get_evaluated_object(depsgraph,
+ data->camera ? data->camera : scene->camera);
- if (data->flag & FOLLOWTRACK_ACTIVECLIP)
- clip = scene->clip;
+ float ctime = DEG_get_ctime(depsgraph);
+ float framenr;
- if (!clip || !data->track[0] || !camob_eval)
- return;
+ if (data->flag & FOLLOWTRACK_ACTIVECLIP)
+ clip = scene->clip;
- tracking = &clip->tracking;
+ if (!clip || !data->track[0] || !camob_eval)
+ return;
- if (data->object[0])
- tracking_object = BKE_tracking_object_get_named(tracking, data->object);
- else
- tracking_object = BKE_tracking_object_get_camera(tracking);
+ tracking = &clip->tracking;
- if (!tracking_object)
- return;
+ if (data->object[0])
+ tracking_object = BKE_tracking_object_get_named(tracking, data->object);
+ else
+ tracking_object = BKE_tracking_object_get_camera(tracking);
- track = BKE_tracking_track_get_named(tracking, tracking_object, data->track);
+ if (!tracking_object)
+ return;
- if (!track)
- return;
+ track = BKE_tracking_track_get_named(tracking, tracking_object, data->track);
- framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, ctime);
+ if (!track)
+ return;
- if (data->flag & FOLLOWTRACK_USE_3D_POSITION) {
- if (track->flag & TRACK_HAS_BUNDLE) {
- float obmat[4][4], mat[4][4];
+ framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, ctime);
- copy_m4_m4(obmat, cob->matrix);
+ if (data->flag & FOLLOWTRACK_USE_3D_POSITION) {
+ if (track->flag & TRACK_HAS_BUNDLE) {
+ float obmat[4][4], mat[4][4];
- if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0) {
- float imat[4][4];
+ copy_m4_m4(obmat, cob->matrix);
- copy_m4_m4(mat, camob_eval->obmat);
+ if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0) {
+ float imat[4][4];
- BKE_tracking_camera_get_reconstructed_interpolate(tracking, tracking_object, framenr, imat);
- invert_m4(imat);
+ copy_m4_m4(mat, camob_eval->obmat);
- mul_m4_series(cob->matrix, obmat, mat, imat);
- translate_m4(cob->matrix, track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]);
- }
- else {
- BKE_tracking_get_camera_object_matrix(cob->scene, camob_eval, mat);
+ BKE_tracking_camera_get_reconstructed_interpolate(
+ tracking, tracking_object, framenr, imat);
+ invert_m4(imat);
- mul_m4_m4m4(cob->matrix, obmat, mat);
- translate_m4(cob->matrix, track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]);
- }
- }
- }
- else {
- float vec[3], disp[3], axis[3], mat[4][4];
- float aspect = (scene->r.xsch * scene->r.xasp) / (scene->r.ysch * scene->r.yasp);
- float len, d;
+ mul_m4_series(cob->matrix, obmat, mat, imat);
+ translate_m4(
+ cob->matrix, track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]);
+ }
+ else {
+ BKE_tracking_get_camera_object_matrix(cob->scene, camob_eval, mat);
- BKE_object_where_is_calc_mat4(camob_eval, mat);
+ mul_m4_m4m4(cob->matrix, obmat, mat);
+ translate_m4(
+ cob->matrix, track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]);
+ }
+ }
+ }
+ else {
+ float vec[3], disp[3], axis[3], mat[4][4];
+ float aspect = (scene->r.xsch * scene->r.xasp) / (scene->r.ysch * scene->r.yasp);
+ float len, d;
- /* camera axis */
- vec[0] = 0.0f;
- vec[1] = 0.0f;
- vec[2] = 1.0f;
- mul_v3_m4v3(axis, mat, vec);
+ BKE_object_where_is_calc_mat4(camob_eval, mat);
- /* distance to projection plane */
- copy_v3_v3(vec, cob->matrix[3]);
- sub_v3_v3(vec, mat[3]);
- project_v3_v3v3(disp, vec, axis);
+ /* camera axis */
+ vec[0] = 0.0f;
+ vec[1] = 0.0f;
+ vec[2] = 1.0f;
+ mul_v3_m4v3(axis, mat, vec);
- len = len_v3(disp);
+ /* distance to projection plane */
+ copy_v3_v3(vec, cob->matrix[3]);
+ sub_v3_v3(vec, mat[3]);
+ project_v3_v3v3(disp, vec, axis);
- if (len > FLT_EPSILON) {
- CameraParams params;
- int width, height;
- float pos[2], rmat[4][4];
+ len = len_v3(disp);
- BKE_movieclip_get_size(clip, NULL, &width, &height);
- BKE_tracking_marker_get_subframe_position(track, framenr, pos);
+ if (len > FLT_EPSILON) {
+ CameraParams params;
+ int width, height;
+ float pos[2], rmat[4][4];
- if (data->flag & FOLLOWTRACK_USE_UNDISTORTION) {
- /* Undistortion need to happen in pixel space. */
- pos[0] *= width;
- pos[1] *= height;
+ BKE_movieclip_get_size(clip, NULL, &width, &height);
+ BKE_tracking_marker_get_subframe_position(track, framenr, pos);
- BKE_tracking_undistort_v2(tracking, pos, pos);
+ if (data->flag & FOLLOWTRACK_USE_UNDISTORTION) {
+ /* Undistortion need to happen in pixel space. */
+ pos[0] *= width;
+ pos[1] *= height;
- /* Normalize pixel coordinates back. */
- pos[0] /= width;
- pos[1] /= height;
- }
+ BKE_tracking_undistort_v2(tracking, pos, pos);
- /* aspect correction */
- if (data->frame_method != FOLLOWTRACK_FRAME_STRETCH) {
- float w_src, h_src, w_dst, h_dst, asp_src, asp_dst;
+ /* Normalize pixel coordinates back. */
+ pos[0] /= width;
+ pos[1] /= height;
+ }
- /* apply clip display aspect */
- w_src = width * clip->aspx;
- h_src = height * clip->aspy;
+ /* aspect correction */
+ if (data->frame_method != FOLLOWTRACK_FRAME_STRETCH) {
+ float w_src, h_src, w_dst, h_dst, asp_src, asp_dst;
- w_dst = scene->r.xsch * scene->r.xasp;
- h_dst = scene->r.ysch * scene->r.yasp;
+ /* apply clip display aspect */
+ w_src = width * clip->aspx;
+ h_src = height * clip->aspy;
- asp_src = w_src / h_src;
- asp_dst = w_dst / h_dst;
+ w_dst = scene->r.xsch * scene->r.xasp;
+ h_dst = scene->r.ysch * scene->r.yasp;
- if (fabsf(asp_src - asp_dst) >= FLT_EPSILON) {
- if ((asp_src > asp_dst) == (data->frame_method == FOLLOWTRACK_FRAME_CROP)) {
- /* fit X */
- float div = asp_src / asp_dst;
- float cent = (float) width / 2.0f;
+ asp_src = w_src / h_src;
+ asp_dst = w_dst / h_dst;
- pos[0] = (((pos[0] * width - cent) * div) + cent) / width;
- }
- else {
- /* fit Y */
- float div = asp_dst / asp_src;
- float cent = (float) height / 2.0f;
+ if (fabsf(asp_src - asp_dst) >= FLT_EPSILON) {
+ if ((asp_src > asp_dst) == (data->frame_method == FOLLOWTRACK_FRAME_CROP)) {
+ /* fit X */
+ float div = asp_src / asp_dst;
+ float cent = (float)width / 2.0f;
- pos[1] = (((pos[1] * height - cent) * div) + cent) / height;
- }
- }
- }
+ pos[0] = (((pos[0] * width - cent) * div) + cent) / width;
+ }
+ else {
+ /* fit Y */
+ float div = asp_dst / asp_src;
+ float cent = (float)height / 2.0f;
- BKE_camera_params_init(&params);
- BKE_camera_params_from_object(&params, camob_eval);
+ pos[1] = (((pos[1] * height - cent) * div) + cent) / height;
+ }
+ }
+ }
- if (params.is_ortho) {
- vec[0] = params.ortho_scale * (pos[0] - 0.5f + params.shiftx);
- vec[1] = params.ortho_scale * (pos[1] - 0.5f + params.shifty);
- vec[2] = -len;
+ BKE_camera_params_init(&params);
+ BKE_camera_params_from_object(&params, camob_eval);
- if (aspect > 1.0f)
- vec[1] /= aspect;
- else
- vec[0] *= aspect;
+ if (params.is_ortho) {
+ vec[0] = params.ortho_scale * (pos[0] - 0.5f + params.shiftx);
+ vec[1] = params.ortho_scale * (pos[1] - 0.5f + params.shifty);
+ vec[2] = -len;
+
+ if (aspect > 1.0f)
+ vec[1] /= aspect;
+ else
+ vec[0] *= aspect;
+
+ mul_v3_m4v3(disp, camob_eval->obmat, vec);
+
+ copy_m4_m4(rmat, camob_eval->obmat);
+ zero_v3(rmat[3]);
+ mul_m4_m4m4(cob->matrix, cob->matrix, rmat);
+
+ copy_v3_v3(cob->matrix[3], disp);
+ }
+ else {
+ d = (len * params.sensor_x) / (2.0f * params.lens);
+
+ vec[0] = d * (2.0f * (pos[0] + params.shiftx) - 1.0f);
+ vec[1] = d * (2.0f * (pos[1] + params.shifty) - 1.0f);
+ vec[2] = -len;
- mul_v3_m4v3(disp, camob_eval->obmat, vec);
-
- copy_m4_m4(rmat, camob_eval->obmat);
- zero_v3(rmat[3]);
- mul_m4_m4m4(cob->matrix, cob->matrix, rmat);
-
- copy_v3_v3(cob->matrix[3], disp);
- }
- else {
- d = (len * params.sensor_x) / (2.0f * params.lens);
-
- vec[0] = d * (2.0f * (pos[0] + params.shiftx) - 1.0f);
- vec[1] = d * (2.0f * (pos[1] + params.shifty) - 1.0f);
- vec[2] = -len;
+ if (aspect > 1.0f)
+ vec[1] /= aspect;
+ else
+ vec[0] *= aspect;
- if (aspect > 1.0f)
- vec[1] /= aspect;
- else
- vec[0] *= aspect;
+ mul_v3_m4v3(disp, camob_eval->obmat, vec);
- mul_v3_m4v3(disp, camob_eval->obmat, vec);
+ /* apply camera rotation so Z-axis would be co-linear */
+ copy_m4_m4(rmat, camob_eval->obmat);
+ zero_v3(rmat[3]);
+ mul_m4_m4m4(cob->matrix, cob->matrix, rmat);
- /* apply camera rotation so Z-axis would be co-linear */
- copy_m4_m4(rmat, camob_eval->obmat);
- zero_v3(rmat[3]);
- mul_m4_m4m4(cob->matrix, cob->matrix, rmat);
+ copy_v3_v3(cob->matrix[3], disp);
+ }
- copy_v3_v3(cob->matrix[3], disp);
- }
+ if (data->depth_ob) {
+ Object *depth_ob = data->depth_ob;
+ Mesh *target_eval = depth_ob->runtime.mesh_eval;
+ if (target_eval) {
+ BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh;
+ BVHTreeRayHit hit;
+ float ray_start[3], ray_end[3], ray_nor[3], imat[4][4];
+ int result;
- if (data->depth_ob) {
- Object *depth_ob = data->depth_ob;
- Mesh *target_eval = depth_ob->runtime.mesh_eval;
- if (target_eval) {
- BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh;
- BVHTreeRayHit hit;
- float ray_start[3], ray_end[3], ray_nor[3], imat[4][4];
- int result;
+ invert_m4_m4(imat, depth_ob->obmat);
- invert_m4_m4(imat, depth_ob->obmat);
+ mul_v3_m4v3(ray_start, imat, camob_eval->obmat[3]);
+ mul_v3_m4v3(ray_end, imat, cob->matrix[3]);
- mul_v3_m4v3(ray_start, imat, camob_eval->obmat[3]);
- mul_v3_m4v3(ray_end, imat, cob->matrix[3]);
+ sub_v3_v3v3(ray_nor, ray_end, ray_start);
+ normalize_v3(ray_nor);
- sub_v3_v3v3(ray_nor, ray_end, ray_start);
- normalize_v3(ray_nor);
+ BKE_bvhtree_from_mesh_get(&treeData, target_eval, BVHTREE_FROM_LOOPTRI, 4);
- BKE_bvhtree_from_mesh_get(&treeData, target_eval, BVHTREE_FROM_LOOPTRI, 4);
+ hit.dist = BVH_RAYCAST_DIST_MAX;
+ hit.index = -1;
- hit.dist = BVH_RAYCAST_DIST_MAX;
- hit.index = -1;
+ result = BLI_bvhtree_ray_cast(
+ treeData.tree, ray_start, ray_nor, 0.0f, &hit, treeData.raycast_callback, &treeData);
- result = BLI_bvhtree_ray_cast(
- treeData.tree, ray_start, ray_nor, 0.0f, &hit, treeData.raycast_callback, &treeData);
+ if (result != -1) {
+ mul_v3_m4v3(cob->matrix[3], depth_ob->obmat, hit.co);
+ }
- if (result != -1) {
- mul_v3_m4v3(cob->matrix[3], depth_ob->obmat, hit.co);
- }
-
- free_bvhtree_from_mesh(&treeData);
- }
- }
- }
- }
+ free_bvhtree_from_mesh(&treeData);
+ }
+ }
+ }
+ }
}
static bConstraintTypeInfo CTI_FOLLOWTRACK = {
- CONSTRAINT_TYPE_FOLLOWTRACK, /* type */
- sizeof(bFollowTrackConstraint), /* size */
- "Follow Track", /* name */
- "bFollowTrackConstraint", /* struct name */
- NULL, /* free data */
- followtrack_id_looper, /* id looper */
- NULL, /* copy data */
- followtrack_new_data, /* new data */
- NULL, /* get constraint targets */
- NULL, /* flush constraint targets */
- NULL, /* get target matrix */
- followtrack_evaluate, /* evaluate */
+ CONSTRAINT_TYPE_FOLLOWTRACK, /* type */
+ sizeof(bFollowTrackConstraint), /* size */
+ "Follow Track", /* name */
+ "bFollowTrackConstraint", /* struct name */
+ NULL, /* free data */
+ followtrack_id_looper, /* id looper */
+ NULL, /* copy data */
+ followtrack_new_data, /* new data */
+ NULL, /* get constraint targets */
+ NULL, /* flush constraint targets */
+ NULL, /* get target matrix */
+ followtrack_evaluate, /* evaluate */
};
/* ----------- Camre Solver ------------- */
static void camerasolver_new_data(void *cdata)
{
- bCameraSolverConstraint *data = (bCameraSolverConstraint *)cdata;
+ bCameraSolverConstraint *data = (bCameraSolverConstraint *)cdata;
- data->clip = NULL;
- data->flag |= CAMERASOLVER_ACTIVECLIP;
+ data->clip = NULL;
+ data->flag |= CAMERASOLVER_ACTIVECLIP;
}
static void camerasolver_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
{
- bCameraSolverConstraint *data = con->data;
+ bCameraSolverConstraint *data = con->data;
- func(con, (ID **)&data->clip, true, userdata);
+ func(con, (ID **)&data->clip, true, userdata);
}
static void camerasolver_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UNUSED(targets))
{
- Depsgraph *depsgraph = cob->depsgraph;
- Scene *scene = cob->scene;
- bCameraSolverConstraint *data = con->data;
- MovieClip *clip = data->clip;
+ Depsgraph *depsgraph = cob->depsgraph;
+ Scene *scene = cob->scene;
+ bCameraSolverConstraint *data = con->data;
+ MovieClip *clip = data->clip;
- if (data->flag & CAMERASOLVER_ACTIVECLIP)
- clip = scene->clip;
+ if (data->flag & CAMERASOLVER_ACTIVECLIP)
+ clip = scene->clip;
- if (clip) {
- float mat[4][4], obmat[4][4];
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *object = BKE_tracking_object_get_camera(tracking);
- float ctime = DEG_get_ctime(depsgraph);
- float framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, ctime);
+ if (clip) {
+ float mat[4][4], obmat[4][4];
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingObject *object = BKE_tracking_object_get_camera(tracking);
+ float ctime = DEG_get_ctime(depsgraph);
+ float framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, ctime);
- BKE_tracking_camera_get_reconstructed_interpolate(tracking, object, framenr, mat);
+ BKE_tracking_camera_get_reconstructed_interpolate(tracking, object, framenr, mat);
- copy_m4_m4(obmat, cob->matrix);
+ copy_m4_m4(obmat, cob->matrix);
- mul_m4_m4m4(cob->matrix, obmat, mat);
- }
+ mul_m4_m4m4(cob->matrix, obmat, mat);
+ }
}
static bConstraintTypeInfo CTI_CAMERASOLVER = {
- CONSTRAINT_TYPE_CAMERASOLVER, /* type */
- sizeof(bCameraSolverConstraint), /* size */
- "Camera Solver", /* name */
- "bCameraSolverConstraint", /* struct name */
- NULL, /* free data */
- camerasolver_id_looper, /* id looper */
- NULL, /* copy data */
- camerasolver_new_data, /* new data */
- NULL, /* get constraint targets */
- NULL, /* flush constraint targets */
- NULL, /* get target matrix */
- camerasolver_evaluate, /* evaluate */
+ CONSTRAINT_TYPE_CAMERASOLVER, /* type */
+ sizeof(bCameraSolverConstraint), /* size */
+ "Camera Solver", /* name */
+ "bCameraSolverConstraint", /* struct name */
+ NULL, /* free data */
+ camerasolver_id_looper, /* id looper */
+ NULL, /* copy data */
+ camerasolver_new_data, /* new data */
+ NULL, /* get constraint targets */
+ NULL, /* flush constraint targets */
+ NULL, /* get target matrix */
+ camerasolver_evaluate, /* evaluate */
};
/* ----------- Object Solver ------------- */
static void objectsolver_new_data(void *cdata)
{
- bObjectSolverConstraint *data = (bObjectSolverConstraint *)cdata;
+ bObjectSolverConstraint *data = (bObjectSolverConstraint *)cdata;
- data->clip = NULL;
- data->flag |= OBJECTSOLVER_ACTIVECLIP;
- unit_m4(data->invmat);
+ data->clip = NULL;
+ data->flag |= OBJECTSOLVER_ACTIVECLIP;
+ unit_m4(data->invmat);
}
static void objectsolver_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
{
- bObjectSolverConstraint *data = con->data;
+ bObjectSolverConstraint *data = con->data;
- func(con, (ID **)&data->clip, false, userdata);
- func(con, (ID **)&data->camera, false, userdata);
+ func(con, (ID **)&data->clip, false, userdata);
+ func(con, (ID **)&data->camera, false, userdata);
}
static void objectsolver_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UNUSED(targets))
{
- Depsgraph *depsgraph = cob->depsgraph;
- Scene *scene = cob->scene;
- bObjectSolverConstraint *data = con->data;
- MovieClip *clip = data->clip;
- Object *camob = data->camera ? data->camera : scene->camera;
+ Depsgraph *depsgraph = cob->depsgraph;
+ Scene *scene = cob->scene;
+ bObjectSolverConstraint *data = con->data;
+ MovieClip *clip = data->clip;
+ Object *camob = data->camera ? data->camera : scene->camera;
- if (data->flag & OBJECTSOLVER_ACTIVECLIP)
- clip = scene->clip;
+ if (data->flag & OBJECTSOLVER_ACTIVECLIP)
+ clip = scene->clip;
- if (!camob || !clip)
- return;
+ if (!camob || !clip)
+ return;
- if (clip) {
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *object;
+ if (clip) {
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingObject *object;
- object = BKE_tracking_object_get_named(tracking, data->object);
+ object = BKE_tracking_object_get_named(tracking, data->object);
- if (object) {
- float mat[4][4], obmat[4][4], imat[4][4], cammat[4][4], camimat[4][4], parmat[4][4];
- float ctime = DEG_get_ctime(depsgraph);
- float framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, ctime);
+ if (object) {
+ float mat[4][4], obmat[4][4], imat[4][4], cammat[4][4], camimat[4][4], parmat[4][4];
+ float ctime = DEG_get_ctime(depsgraph);
+ float framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, ctime);
- BKE_object_where_is_calc_mat4(camob, cammat);
+ BKE_object_where_is_calc_mat4(camob, cammat);
- BKE_tracking_camera_get_reconstructed_interpolate(tracking, object, framenr, mat);
+ BKE_tracking_camera_get_reconstructed_interpolate(tracking, object, framenr, mat);
- invert_m4_m4(camimat, cammat);
- mul_m4_m4m4(parmat, cammat, data->invmat);
+ invert_m4_m4(camimat, cammat);
+ mul_m4_m4m4(parmat, cammat, data->invmat);
- copy_m4_m4(cammat, camob->obmat);
- copy_m4_m4(obmat, cob->matrix);
+ copy_m4_m4(cammat, camob->obmat);
+ copy_m4_m4(obmat, cob->matrix);
- invert_m4_m4(imat, mat);
+ invert_m4_m4(imat, mat);
- mul_m4_series(cob->matrix, cammat, imat, camimat, parmat, obmat);
- }
- }
+ mul_m4_series(cob->matrix, cammat, imat, camimat, parmat, obmat);
+ }
+ }
}
static bConstraintTypeInfo CTI_OBJECTSOLVER = {
- CONSTRAINT_TYPE_OBJECTSOLVER, /* type */
- sizeof(bObjectSolverConstraint), /* size */
- "Object Solver", /* name */
- "bObjectSolverConstraint", /* struct name */
- NULL, /* free data */
- objectsolver_id_looper, /* id looper */
- NULL, /* copy data */
- objectsolver_new_data, /* new data */
- NULL, /* get constraint targets */
- NULL, /* flush constraint targets */
- NULL, /* get target matrix */
- objectsolver_evaluate, /* evaluate */
+ CONSTRAINT_TYPE_OBJECTSOLVER, /* type */
+ sizeof(bObjectSolverConstraint), /* size */
+ "Object Solver", /* name */
+ "bObjectSolverConstraint", /* struct name */
+ NULL, /* free data */
+ objectsolver_id_looper, /* id looper */
+ NULL, /* copy data */
+ objectsolver_new_data, /* new data */
+ NULL, /* get constraint targets */
+ NULL, /* flush constraint targets */
+ NULL, /* get target matrix */
+ objectsolver_evaluate, /* evaluate */
};
/* ----------- Transform Cache ------------- */
static void transformcache_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
{
- bTransformCacheConstraint *data = con->data;
- func(con, (ID **)&data->cache_file, true, userdata);
+ bTransformCacheConstraint *data = con->data;
+ func(con, (ID **)&data->cache_file, true, userdata);
}
static void transformcache_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets)
{
#ifdef WITH_ALEMBIC
- bTransformCacheConstraint *data = con->data;
- Scene *scene = cob->scene;
+ bTransformCacheConstraint *data = con->data;
+ Scene *scene = cob->scene;
- CacheFile *cache_file = data->cache_file;
+ CacheFile *cache_file = data->cache_file;
- if (!cache_file) {
- return;
- }
+ if (!cache_file) {
+ return;
+ }
- const float frame = DEG_get_ctime(cob->depsgraph);
- const float time = BKE_cachefile_time_offset(cache_file, frame, FPS);
+ const float frame = DEG_get_ctime(cob->depsgraph);
+ const float time = BKE_cachefile_time_offset(cache_file, frame, FPS);
- /* Must always load ABC handle on original. */
- CacheFile *cache_file_orig = (CacheFile *)DEG_get_original_id(&cache_file->id);
- BKE_cachefile_ensure_handle(G.main, cache_file_orig);
+ /* Must always load ABC handle on original. */
+ CacheFile *cache_file_orig = (CacheFile *)DEG_get_original_id(&cache_file->id);
+ BKE_cachefile_ensure_handle(G.main, cache_file_orig);
- if (!data->reader) {
- data->reader = CacheReader_open_alembic_object(cache_file_orig->handle,
- data->reader,
- cob->ob,
- data->object_path);
- }
+ if (!data->reader) {
+ data->reader = CacheReader_open_alembic_object(
+ cache_file_orig->handle, data->reader, cob->ob, data->object_path);
+ }
- ABC_get_transform(data->reader, cob->matrix, time, cache_file->scale);
+ ABC_get_transform(data->reader, cob->matrix, time, cache_file->scale);
#else
- UNUSED_VARS(con, cob);
+ UNUSED_VARS(con, cob);
#endif
- UNUSED_VARS(targets);
+ UNUSED_VARS(targets);
}
static void transformcache_copy(bConstraint *con, bConstraint *srccon)
{
- bTransformCacheConstraint *src = srccon->data;
- bTransformCacheConstraint *dst = con->data;
+ bTransformCacheConstraint *src = srccon->data;
+ bTransformCacheConstraint *dst = con->data;
- BLI_strncpy(dst->object_path, src->object_path, sizeof(dst->object_path));
- dst->cache_file = src->cache_file;
+ BLI_strncpy(dst->object_path, src->object_path, sizeof(dst->object_path));
+ dst->cache_file = src->cache_file;
#ifdef WITH_ALEMBIC
- if (dst->reader) {
- CacheReader_incref(dst->reader);
- }
+ if (dst->reader) {
+ CacheReader_incref(dst->reader);
+ }
#endif
}
static void transformcache_free(bConstraint *con)
{
- bTransformCacheConstraint *data = con->data;
+ bTransformCacheConstraint *data = con->data;
- if (data->reader) {
+ if (data->reader) {
#ifdef WITH_ALEMBIC
- CacheReader_free(data->reader);
+ CacheReader_free(data->reader);
#endif
- data->reader = NULL;
- }
+ data->reader = NULL;
+ }
}
static void transformcache_new_data(void *cdata)
{
- bTransformCacheConstraint *data = (bTransformCacheConstraint *)cdata;
+ bTransformCacheConstraint *data = (bTransformCacheConstraint *)cdata;
- data->cache_file = NULL;
+ data->cache_file = NULL;
}
static bConstraintTypeInfo CTI_TRANSFORM_CACHE = {
- CONSTRAINT_TYPE_TRANSFORM_CACHE, /* type */
- sizeof(bTransformCacheConstraint), /* size */
- "Transform Cache", /* name */
- "bTransformCacheConstraint", /* struct name */
- transformcache_free, /* free data */
- transformcache_id_looper, /* id looper */
- transformcache_copy, /* copy data */
- transformcache_new_data, /* new data */
- NULL, /* get constraint targets */
- NULL, /* flush constraint targets */
- NULL, /* get target matrix */
- transformcache_evaluate, /* evaluate */
+ CONSTRAINT_TYPE_TRANSFORM_CACHE, /* type */
+ sizeof(bTransformCacheConstraint), /* size */
+ "Transform Cache", /* name */
+ "bTransformCacheConstraint", /* struct name */
+ transformcache_free, /* free data */
+ transformcache_id_looper, /* id looper */
+ transformcache_copy, /* copy data */
+ transformcache_new_data, /* new data */
+ NULL, /* get constraint targets */
+ NULL, /* flush constraint targets */
+ NULL, /* get target matrix */
+ transformcache_evaluate, /* evaluate */
};
/* ************************* Constraints Type-Info *************************** */
@@ -4633,37 +4796,37 @@ static short CTI_INIT = 1; /* when non-zero, the list needs to be updated */
/* This function only gets called when CTI_INIT is non-zero */
static void constraints_init_typeinfo(void)
{
- constraintsTypeInfo[0] = NULL; /* 'Null' Constraint */
- constraintsTypeInfo[1] = &CTI_CHILDOF; /* ChildOf Constraint */
- constraintsTypeInfo[2] = &CTI_TRACKTO; /* TrackTo Constraint */
- constraintsTypeInfo[3] = &CTI_KINEMATIC; /* IK Constraint */
- constraintsTypeInfo[4] = &CTI_FOLLOWPATH; /* Follow-Path Constraint */
- constraintsTypeInfo[5] = &CTI_ROTLIMIT; /* Limit Rotation Constraint */
- constraintsTypeInfo[6] = &CTI_LOCLIMIT; /* Limit Location Constraint */
- constraintsTypeInfo[7] = &CTI_SIZELIMIT; /* Limit Scale Constraint */
- constraintsTypeInfo[8] = &CTI_ROTLIKE; /* Copy Rotation Constraint */
- constraintsTypeInfo[9] = &CTI_LOCLIKE; /* Copy Location Constraint */
- constraintsTypeInfo[10] = &CTI_SIZELIKE; /* Copy Scale Constraint */
- constraintsTypeInfo[11] = &CTI_PYTHON; /* Python/Script Constraint */
- constraintsTypeInfo[12] = &CTI_ACTION; /* Action Constraint */
- constraintsTypeInfo[13] = &CTI_LOCKTRACK; /* Locked-Track Constraint */
- constraintsTypeInfo[14] = &CTI_DISTLIMIT; /* Limit Distance Constraint */
- constraintsTypeInfo[15] = &CTI_STRETCHTO; /* StretchTo Constaint */
- constraintsTypeInfo[16] = &CTI_MINMAX; /* Floor Constraint */
- /* constraintsTypeInfo[17] = &CTI_RIGIDBODYJOINT; */ /* RigidBody Constraint - Deprecated */
- constraintsTypeInfo[18] = &CTI_CLAMPTO; /* ClampTo Constraint */
- constraintsTypeInfo[19] = &CTI_TRANSFORM; /* Transformation Constraint */
- constraintsTypeInfo[20] = &CTI_SHRINKWRAP; /* Shrinkwrap Constraint */
- constraintsTypeInfo[21] = &CTI_DAMPTRACK; /* Damped TrackTo Constraint */
- constraintsTypeInfo[22] = &CTI_SPLINEIK; /* Spline IK Constraint */
- constraintsTypeInfo[23] = &CTI_TRANSLIKE; /* Copy Transforms Constraint */
- constraintsTypeInfo[24] = &CTI_SAMEVOL; /* Maintain Volume Constraint */
- constraintsTypeInfo[25] = &CTI_PIVOT; /* Pivot Constraint */
- constraintsTypeInfo[26] = &CTI_FOLLOWTRACK; /* Follow Track Constraint */
- constraintsTypeInfo[27] = &CTI_CAMERASOLVER; /* Camera Solver Constraint */
- constraintsTypeInfo[28] = &CTI_OBJECTSOLVER; /* Object Solver Constraint */
- constraintsTypeInfo[29] = &CTI_TRANSFORM_CACHE; /* Transform Cache Constraint */
- constraintsTypeInfo[30] = &CTI_ARMATURE; /* Armature Constraint */
+ constraintsTypeInfo[0] = NULL; /* 'Null' Constraint */
+ constraintsTypeInfo[1] = &CTI_CHILDOF; /* ChildOf Constraint */
+ constraintsTypeInfo[2] = &CTI_TRACKTO; /* TrackTo Constraint */
+ constraintsTypeInfo[3] = &CTI_KINEMATIC; /* IK Constraint */
+ constraintsTypeInfo[4] = &CTI_FOLLOWPATH; /* Follow-Path Constraint */
+ constraintsTypeInfo[5] = &CTI_ROTLIMIT; /* Limit Rotation Constraint */
+ constraintsTypeInfo[6] = &CTI_LOCLIMIT; /* Limit Location Constraint */
+ constraintsTypeInfo[7] = &CTI_SIZELIMIT; /* Limit Scale Constraint */
+ constraintsTypeInfo[8] = &CTI_ROTLIKE; /* Copy Rotation Constraint */
+ constraintsTypeInfo[9] = &CTI_LOCLIKE; /* Copy Location Constraint */
+ constraintsTypeInfo[10] = &CTI_SIZELIKE; /* Copy Scale Constraint */
+ constraintsTypeInfo[11] = &CTI_PYTHON; /* Python/Script Constraint */
+ constraintsTypeInfo[12] = &CTI_ACTION; /* Action Constraint */
+ constraintsTypeInfo[13] = &CTI_LOCKTRACK; /* Locked-Track Constraint */
+ constraintsTypeInfo[14] = &CTI_DISTLIMIT; /* Limit Distance Constraint */
+ constraintsTypeInfo[15] = &CTI_STRETCHTO; /* StretchTo Constaint */
+ constraintsTypeInfo[16] = &CTI_MINMAX; /* Floor Constraint */
+ /* constraintsTypeInfo[17] = &CTI_RIGIDBODYJOINT; */ /* RigidBody Constraint - Deprecated */
+ constraintsTypeInfo[18] = &CTI_CLAMPTO; /* ClampTo Constraint */
+ constraintsTypeInfo[19] = &CTI_TRANSFORM; /* Transformation Constraint */
+ constraintsTypeInfo[20] = &CTI_SHRINKWRAP; /* Shrinkwrap Constraint */
+ constraintsTypeInfo[21] = &CTI_DAMPTRACK; /* Damped TrackTo Constraint */
+ constraintsTypeInfo[22] = &CTI_SPLINEIK; /* Spline IK Constraint */
+ constraintsTypeInfo[23] = &CTI_TRANSLIKE; /* Copy Transforms Constraint */
+ constraintsTypeInfo[24] = &CTI_SAMEVOL; /* Maintain Volume Constraint */
+ constraintsTypeInfo[25] = &CTI_PIVOT; /* Pivot Constraint */
+ constraintsTypeInfo[26] = &CTI_FOLLOWTRACK; /* Follow Track Constraint */
+ constraintsTypeInfo[27] = &CTI_CAMERASOLVER; /* Camera Solver Constraint */
+ constraintsTypeInfo[28] = &CTI_OBJECTSOLVER; /* Object Solver Constraint */
+ constraintsTypeInfo[29] = &CTI_TRANSFORM_CACHE; /* Transform Cache Constraint */
+ constraintsTypeInfo[30] = &CTI_ARMATURE; /* Armature Constraint */
}
/* This function should be used for getting the appropriate type-info when only
@@ -4671,24 +4834,22 @@ static void constraints_init_typeinfo(void)
*/
const bConstraintTypeInfo *BKE_constraint_typeinfo_from_type(int type)
{
- /* initialize the type-info list? */
- if (CTI_INIT) {
- constraints_init_typeinfo();
- CTI_INIT = 0;
- }
+ /* initialize the type-info list? */
+ if (CTI_INIT) {
+ constraints_init_typeinfo();
+ CTI_INIT = 0;
+ }
- /* only return for valid types */
- if ((type >= CONSTRAINT_TYPE_NULL) &&
- (type < NUM_CONSTRAINT_TYPES))
- {
- /* there shouldn't be any segfaults here... */
- return constraintsTypeInfo[type];
- }
- else {
- CLOG_WARN(&LOG, "No valid constraint type-info data available. Type = %i", type);
- }
+ /* only return for valid types */
+ if ((type >= CONSTRAINT_TYPE_NULL) && (type < NUM_CONSTRAINT_TYPES)) {
+ /* there shouldn't be any segfaults here... */
+ return constraintsTypeInfo[type];
+ }
+ else {
+ CLOG_WARN(&LOG, "No valid constraint type-info data available. Type = %i", type);
+ }
- return NULL;
+ return NULL;
}
/* This function should always be used to get the appropriate type-info, as it
@@ -4696,11 +4857,11 @@ const bConstraintTypeInfo *BKE_constraint_typeinfo_from_type(int type)
*/
const bConstraintTypeInfo *BKE_constraint_typeinfo_get(bConstraint *con)
{
- /* only return typeinfo for valid constraints */
- if (con)
- return BKE_constraint_typeinfo_from_type(con->type);
- else
- return NULL;
+ /* only return typeinfo for valid constraints */
+ if (con)
+ return BKE_constraint_typeinfo_from_type(con->type);
+ else
+ return NULL;
}
/* ************************* General Constraints API ************************** */
@@ -4713,10 +4874,13 @@ const bConstraintTypeInfo *BKE_constraint_typeinfo_get(bConstraint *con)
/**
* Helper function for #BKE_constraint_free_data() - unlinks references.
*/
-static void con_unlink_refs_cb(bConstraint *UNUSED(con), ID **idpoin, bool is_reference, void *UNUSED(userData))
+static void con_unlink_refs_cb(bConstraint *UNUSED(con),
+ ID **idpoin,
+ bool is_reference,
+ void *UNUSED(userData))
{
- if (*idpoin && is_reference)
- id_us_min(*idpoin);
+ if (*idpoin && is_reference)
+ id_us_min(*idpoin);
}
/**
@@ -4726,73 +4890,73 @@ static void con_unlink_refs_cb(bConstraint *UNUSED(con), ID **idpoin, bool is_re
*/
void BKE_constraint_free_data_ex(bConstraint *con, bool do_id_user)
{
- if (con->data) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ if (con->data) {
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- if (cti) {
- /* perform any special freeing constraint may have */
- if (cti->free_data)
- cti->free_data(con);
+ if (cti) {
+ /* perform any special freeing constraint may have */
+ if (cti->free_data)
+ cti->free_data(con);
- /* unlink the referenced resources it uses */
- if (do_id_user && cti->id_looper)
- cti->id_looper(con, con_unlink_refs_cb, NULL);
- }
+ /* unlink the referenced resources it uses */
+ if (do_id_user && cti->id_looper)
+ cti->id_looper(con, con_unlink_refs_cb, NULL);
+ }
- /* free constraint data now */
- MEM_freeN(con->data);
- }
+ /* free constraint data now */
+ MEM_freeN(con->data);
+ }
}
void BKE_constraint_free_data(bConstraint *con)
{
- BKE_constraint_free_data_ex(con, true);
+ BKE_constraint_free_data_ex(con, true);
}
/* Free all constraints from a constraint-stack */
void BKE_constraints_free_ex(ListBase *list, bool do_id_user)
{
- bConstraint *con;
+ bConstraint *con;
- /* Free constraint data and also any extra data */
- for (con = list->first; con; con = con->next)
- BKE_constraint_free_data_ex(con, do_id_user);
+ /* Free constraint data and also any extra data */
+ for (con = list->first; con; con = con->next)
+ BKE_constraint_free_data_ex(con, do_id_user);
- /* Free the whole list */
- BLI_freelistN(list);
+ /* Free the whole list */
+ BLI_freelistN(list);
}
void BKE_constraints_free(ListBase *list)
{
- BKE_constraints_free_ex(list, true);
+ BKE_constraints_free_ex(list, true);
}
/* Remove the specified constraint from the given constraint stack */
bool BKE_constraint_remove(ListBase *list, bConstraint *con)
{
- if (con) {
- BKE_constraint_free_data(con);
- BLI_freelinkN(list, con);
- return true;
- }
- else {
- return false;
- }
+ if (con) {
+ BKE_constraint_free_data(con);
+ BLI_freelinkN(list, con);
+ return true;
+ }
+ else {
+ return false;
+ }
}
bool BKE_constraint_remove_ex(ListBase *list, Object *ob, bConstraint *con, bool clear_dep)
{
- const short type = con->type;
- if (BKE_constraint_remove(list, con)) {
- /* ITASC needs to be rebuilt once a constraint is removed [#26920] */
- if (clear_dep && ELEM(type, CONSTRAINT_TYPE_KINEMATIC, CONSTRAINT_TYPE_SPLINEIK)) {
- BIK_clear_data(ob->pose);
- }
- return true;
- }
- else {
- return false;
- }
+ const short type = con->type;
+ if (BKE_constraint_remove(list, con)) {
+ /* ITASC needs to be rebuilt once a constraint is removed [#26920] */
+ if (clear_dep && ELEM(type, CONSTRAINT_TYPE_KINEMATIC, CONSTRAINT_TYPE_SPLINEIK)) {
+ BIK_clear_data(ob->pose);
+ }
+ return true;
+ }
+ else {
+ return false;
+ }
}
/* ......... */
@@ -4800,108 +4964,114 @@ bool BKE_constraint_remove_ex(ListBase *list, Object *ob, bConstraint *con, bool
/* Creates a new constraint, initializes its data, and returns it */
static bConstraint *add_new_constraint_internal(const char *name, short type)
{
- bConstraint *con = MEM_callocN(sizeof(bConstraint), "Constraint");
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(type);
- const char *newName;
+ bConstraint *con = MEM_callocN(sizeof(bConstraint), "Constraint");
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(type);
+ const char *newName;
- /* Set up a generic constraint datablock */
- con->type = type;
- con->flag |= CONSTRAINT_EXPAND | CONSTRAINT_STATICOVERRIDE_LOCAL;
- con->enforce = 1.0f;
+ /* Set up a generic constraint datablock */
+ con->type = type;
+ con->flag |= CONSTRAINT_EXPAND | CONSTRAINT_STATICOVERRIDE_LOCAL;
+ con->enforce = 1.0f;
- /* Determine a basic name, and info */
- if (cti) {
- /* initialize constraint data */
- con->data = MEM_callocN(cti->size, cti->structName);
+ /* Determine a basic name, and info */
+ if (cti) {
+ /* initialize constraint data */
+ con->data = MEM_callocN(cti->size, cti->structName);
- /* only constraints that change any settings need this */
- if (cti->new_data)
- cti->new_data(con->data);
+ /* only constraints that change any settings need this */
+ if (cti->new_data)
+ cti->new_data(con->data);
- /* if no name is provided, use the type of the constraint as the name */
- newName = (name && name[0]) ? name : DATA_(cti->name);
- }
- else {
- /* if no name is provided, use the generic "Const" name */
- /* NOTE: any constraint type that gets here really shouldn't get added... */
- newName = (name && name[0]) ? name : DATA_("Const");
- }
+ /* if no name is provided, use the type of the constraint as the name */
+ newName = (name && name[0]) ? name : DATA_(cti->name);
+ }
+ else {
+ /* if no name is provided, use the generic "Const" name */
+ /* NOTE: any constraint type that gets here really shouldn't get added... */
+ newName = (name && name[0]) ? name : DATA_("Const");
+ }
- /* copy the name */
- BLI_strncpy(con->name, newName, sizeof(con->name));
+ /* copy the name */
+ BLI_strncpy(con->name, newName, sizeof(con->name));
- /* return the new constraint */
- return con;
+ /* return the new constraint */
+ return con;
}
/* if pchan is not NULL then assume we're adding a pose constraint */
-static bConstraint *add_new_constraint(Object *ob, bPoseChannel *pchan, const char *name, short type)
+static bConstraint *add_new_constraint(Object *ob,
+ bPoseChannel *pchan,
+ const char *name,
+ short type)
{
- bConstraint *con;
- ListBase *list;
+ bConstraint *con;
+ ListBase *list;
- /* add the constraint */
- con = add_new_constraint_internal(name, type);
+ /* add the constraint */
+ con = add_new_constraint_internal(name, type);
- /* find the constraint stack - bone or object? */
- list = (pchan) ? (&pchan->constraints) : (&ob->constraints);
+ /* find the constraint stack - bone or object? */
+ list = (pchan) ? (&pchan->constraints) : (&ob->constraints);
- if (list) {
- /* add new constraint to end of list of constraints before ensuring that it has a unique name
- * (otherwise unique-naming code will fail, since it assumes element exists in list)
- */
- BLI_addtail(list, con);
- BKE_constraint_unique_name(con, list);
+ if (list) {
+ /* add new constraint to end of list of constraints before ensuring that it has a unique name
+ * (otherwise unique-naming code will fail, since it assumes element exists in list)
+ */
+ BLI_addtail(list, con);
+ BKE_constraint_unique_name(con, list);
- /* if the target list is a list on some PoseChannel belonging to a proxy-protected
- * Armature layer, we must tag newly added constraints with a flag which allows them
- * to persist after proxy syncing has been done
- */
- if (BKE_constraints_proxylocked_owner(ob, pchan))
- con->flag |= CONSTRAINT_PROXY_LOCAL;
+ /* if the target list is a list on some PoseChannel belonging to a proxy-protected
+ * Armature layer, we must tag newly added constraints with a flag which allows them
+ * to persist after proxy syncing has been done
+ */
+ if (BKE_constraints_proxylocked_owner(ob, pchan))
+ con->flag |= CONSTRAINT_PROXY_LOCAL;
- /* make this constraint the active one */
- BKE_constraints_active_set(list, con);
- }
+ /* make this constraint the active one */
+ BKE_constraints_active_set(list, con);
+ }
- /* set type+owner specific immutable settings */
- /* TODO: does action constraint need anything here - i.e. spaceonce? */
- switch (type) {
- case CONSTRAINT_TYPE_CHILDOF:
- {
- /* if this constraint is being added to a posechannel, make sure
- * the constraint gets evaluated in pose-space */
- if (pchan) {
- con->ownspace = CONSTRAINT_SPACE_POSE;
- con->flag |= CONSTRAINT_SPACEONCE;
- }
- break;
- }
- }
+ /* set type+owner specific immutable settings */
+ /* TODO: does action constraint need anything here - i.e. spaceonce? */
+ switch (type) {
+ case CONSTRAINT_TYPE_CHILDOF: {
+ /* if this constraint is being added to a posechannel, make sure
+ * the constraint gets evaluated in pose-space */
+ if (pchan) {
+ con->ownspace = CONSTRAINT_SPACE_POSE;
+ con->flag |= CONSTRAINT_SPACEONCE;
+ }
+ break;
+ }
+ }
- return con;
+ return con;
}
-bool BKE_constraint_target_uses_bbone(struct bConstraint *con, struct bConstraintTarget *UNUSED(ct))
+bool BKE_constraint_target_uses_bbone(struct bConstraint *con,
+ struct bConstraintTarget *UNUSED(ct))
{
- return (con->flag & CONSTRAINT_BBONE_SHAPE) || (con->type == CONSTRAINT_TYPE_ARMATURE);
+ return (con->flag & CONSTRAINT_BBONE_SHAPE) || (con->type == CONSTRAINT_TYPE_ARMATURE);
}
/* ......... */
/* Add new constraint for the given bone */
-bConstraint *BKE_constraint_add_for_pose(Object *ob, bPoseChannel *pchan, const char *name, short type)
+bConstraint *BKE_constraint_add_for_pose(Object *ob,
+ bPoseChannel *pchan,
+ const char *name,
+ short type)
{
- if (pchan == NULL)
- return NULL;
+ if (pchan == NULL)
+ return NULL;
- return add_new_constraint(ob, pchan, name, type);
+ return add_new_constraint(ob, pchan, name, type);
}
/* Add new constraint for the given object */
bConstraint *BKE_constraint_add_for_object(Object *ob, const char *name, short type)
{
- return add_new_constraint(ob, NULL, name, type);
+ return add_new_constraint(ob, NULL, name, type);
}
/* ......... */
@@ -4909,240 +5079,255 @@ bConstraint *BKE_constraint_add_for_object(Object *ob, const char *name, short t
/* Run the given callback on all ID-blocks in list of constraints */
void BKE_constraints_id_loop(ListBase *conlist, ConstraintIDFunc func, void *userdata)
{
- bConstraint *con;
+ bConstraint *con;
- for (con = conlist->first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ for (con = conlist->first; con; con = con->next) {
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- if (cti) {
- if (cti->id_looper)
- cti->id_looper(con, func, userdata);
- }
- }
+ if (cti) {
+ if (cti->id_looper)
+ cti->id_looper(con, func, userdata);
+ }
+ }
}
/* ......... */
/* helper for BKE_constraints_copy(), to be used for making sure that ID's are valid */
-static void con_extern_cb(bConstraint *UNUSED(con), ID **idpoin, bool UNUSED(is_reference), void *UNUSED(userData))
+static void con_extern_cb(bConstraint *UNUSED(con),
+ ID **idpoin,
+ bool UNUSED(is_reference),
+ void *UNUSED(userData))
{
- if (*idpoin && ID_IS_LINKED(*idpoin))
- id_lib_extern(*idpoin);
+ if (*idpoin && ID_IS_LINKED(*idpoin))
+ id_lib_extern(*idpoin);
}
/* helper for BKE_constraints_copy(), to be used for making sure that usercounts of copied ID's are fixed up */
-static void con_fix_copied_refs_cb(bConstraint *UNUSED(con), ID **idpoin, bool is_reference, void *UNUSED(userData))
+static void con_fix_copied_refs_cb(bConstraint *UNUSED(con),
+ ID **idpoin,
+ bool is_reference,
+ void *UNUSED(userData))
{
- /* increment usercount if this is a reference type */
- if ((*idpoin) && (is_reference))
- id_us_plus(*idpoin);
+ /* increment usercount if this is a reference type */
+ if ((*idpoin) && (is_reference))
+ id_us_plus(*idpoin);
}
/** Copies a single constraint's data (\a dst must already be a shallow copy of \a src). */
-static void constraint_copy_data_ex(bConstraint *dst, bConstraint *src, const int flag, const bool do_extern)
+static void constraint_copy_data_ex(bConstraint *dst,
+ bConstraint *src,
+ const int flag,
+ const bool do_extern)
{
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(src);
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(src);
- /* make a new copy of the constraint's data */
- dst->data = MEM_dupallocN(dst->data);
+ /* make a new copy of the constraint's data */
+ dst->data = MEM_dupallocN(dst->data);
- /* only do specific constraints if required */
- if (cti) {
- /* perform custom copying operations if needed */
- if (cti->copy_data)
- cti->copy_data(dst, src);
+ /* only do specific constraints if required */
+ if (cti) {
+ /* perform custom copying operations if needed */
+ if (cti->copy_data)
+ cti->copy_data(dst, src);
- /* Fix usercounts for all referenced data that need it. */
- if (cti->id_looper && (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- cti->id_looper(dst, con_fix_copied_refs_cb, NULL);
- }
+ /* Fix usercounts for all referenced data that need it. */
+ if (cti->id_looper && (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ cti->id_looper(dst, con_fix_copied_refs_cb, NULL);
+ }
- /* for proxies we don't want to make extern */
- if (do_extern) {
- /* go over used ID-links for this constraint to ensure that they are valid for proxies */
- if (cti->id_looper)
- cti->id_looper(dst, con_extern_cb, NULL);
- }
- }
+ /* for proxies we don't want to make extern */
+ if (do_extern) {
+ /* go over used ID-links for this constraint to ensure that they are valid for proxies */
+ if (cti->id_looper)
+ cti->id_looper(dst, con_extern_cb, NULL);
+ }
+ }
}
/** Allocate and duplicate a single constraint, ouside of any object/pose context. */
bConstraint *BKE_constraint_duplicate_ex(bConstraint *src, const int flag, const bool do_extern)
{
- bConstraint *dst = MEM_dupallocN(src);
- constraint_copy_data_ex(dst, src, flag, do_extern);
- dst->next = dst->prev = NULL;
- return dst;
+ bConstraint *dst = MEM_dupallocN(src);
+ constraint_copy_data_ex(dst, src, flag, do_extern);
+ dst->next = dst->prev = NULL;
+ return dst;
}
/* duplicate all of the constraints in a constraint stack */
void BKE_constraints_copy_ex(ListBase *dst, const ListBase *src, const int flag, bool do_extern)
{
- bConstraint *con, *srccon;
+ bConstraint *con, *srccon;
- BLI_listbase_clear(dst);
- BLI_duplicatelist(dst, src);
+ BLI_listbase_clear(dst);
+ BLI_duplicatelist(dst, src);
- for (con = dst->first, srccon = src->first; con && srccon; srccon = srccon->next, con = con->next) {
- constraint_copy_data_ex(con, srccon, flag, do_extern);
- }
+ for (con = dst->first, srccon = src->first; con && srccon;
+ srccon = srccon->next, con = con->next) {
+ constraint_copy_data_ex(con, srccon, flag, do_extern);
+ }
}
void BKE_constraints_copy(ListBase *dst, const ListBase *src, bool do_extern)
{
- BKE_constraints_copy_ex(dst, src, 0, do_extern);
+ BKE_constraints_copy_ex(dst, src, 0, do_extern);
}
/* ......... */
bConstraint *BKE_constraints_find_name(ListBase *list, const char *name)
{
- return BLI_findstring(list, name, offsetof(bConstraint, name));
+ return BLI_findstring(list, name, offsetof(bConstraint, name));
}
/* finds the 'active' constraint in a constraint stack */
bConstraint *BKE_constraints_active_get(ListBase *list)
{
- bConstraint *con;
+ bConstraint *con;
- /* search for the first constraint with the 'active' flag set */
- if (list) {
- for (con = list->first; con; con = con->next) {
- if (con->flag & CONSTRAINT_ACTIVE)
- return con;
- }
- }
+ /* search for the first constraint with the 'active' flag set */
+ if (list) {
+ for (con = list->first; con; con = con->next) {
+ if (con->flag & CONSTRAINT_ACTIVE)
+ return con;
+ }
+ }
- /* no active constraint found */
- return NULL;
+ /* no active constraint found */
+ return NULL;
}
/* Set the given constraint as the active one (clearing all the others) */
void BKE_constraints_active_set(ListBase *list, bConstraint *con)
{
- bConstraint *c;
+ bConstraint *c;
- if (list) {
- for (c = list->first; c; c = c->next) {
- if (c == con)
- c->flag |= CONSTRAINT_ACTIVE;
- else
- c->flag &= ~CONSTRAINT_ACTIVE;
- }
- }
+ if (list) {
+ for (c = list->first; c; c = c->next) {
+ if (c == con)
+ c->flag |= CONSTRAINT_ACTIVE;
+ else
+ c->flag &= ~CONSTRAINT_ACTIVE;
+ }
+ }
}
static bConstraint *constraint_list_find_from_target(ListBase *constraints, bConstraintTarget *tgt)
{
- for (bConstraint *con = constraints->first; con; con = con->next) {
- ListBase *targets = NULL;
+ for (bConstraint *con = constraints->first; con; con = con->next) {
+ ListBase *targets = NULL;
- if (con->type == CONSTRAINT_TYPE_PYTHON) {
- targets = &((bPythonConstraint *)con->data)->targets;
- }
- else if (con->type == CONSTRAINT_TYPE_ARMATURE) {
- targets = &((bArmatureConstraint *)con->data)->targets;
- }
+ if (con->type == CONSTRAINT_TYPE_PYTHON) {
+ targets = &((bPythonConstraint *)con->data)->targets;
+ }
+ else if (con->type == CONSTRAINT_TYPE_ARMATURE) {
+ targets = &((bArmatureConstraint *)con->data)->targets;
+ }
- if (targets && BLI_findindex(targets, tgt) != -1) {
- return con;
- }
- }
+ if (targets && BLI_findindex(targets, tgt) != -1) {
+ return con;
+ }
+ }
- return NULL;
+ return NULL;
}
/* Finds the constraint that owns the given target within the object. */
-bConstraint *BKE_constraint_find_from_target(Object *ob, bConstraintTarget *tgt, bPoseChannel **r_pchan)
+bConstraint *BKE_constraint_find_from_target(Object *ob,
+ bConstraintTarget *tgt,
+ bPoseChannel **r_pchan)
{
- if (r_pchan != NULL) {
- *r_pchan = NULL;
- }
+ if (r_pchan != NULL) {
+ *r_pchan = NULL;
+ }
- bConstraint *result = constraint_list_find_from_target(&ob->constraints, tgt);
+ bConstraint *result = constraint_list_find_from_target(&ob->constraints, tgt);
- if (result != NULL) {
- return result;
- }
+ if (result != NULL) {
+ return result;
+ }
- if (ob->pose != NULL) {
- for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- result = constraint_list_find_from_target(&pchan->constraints, tgt);
+ if (ob->pose != NULL) {
+ for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ result = constraint_list_find_from_target(&pchan->constraints, tgt);
- if (result != NULL) {
- if (r_pchan != NULL) {
- *r_pchan = pchan;
- }
+ if (result != NULL) {
+ if (r_pchan != NULL) {
+ *r_pchan = pchan;
+ }
- return result;
- }
- }
- }
+ return result;
+ }
+ }
+ }
- return NULL;
+ return NULL;
}
/* Finds the original copy of the constraint based on a COW copy. */
-static bConstraint *constraint_find_original(Object *ob, bPoseChannel *pchan, bConstraint *con, Object **r_orig_ob)
+static bConstraint *constraint_find_original(Object *ob,
+ bPoseChannel *pchan,
+ bConstraint *con,
+ Object **r_orig_ob)
{
- Object *orig_ob = (Object *)DEG_get_original_id(&ob->id);
+ Object *orig_ob = (Object *)DEG_get_original_id(&ob->id);
- if (ELEM(orig_ob, NULL, ob)) {
- return NULL;
- }
+ if (ELEM(orig_ob, NULL, ob)) {
+ return NULL;
+ }
- /* Find which constraint list to use. */
- ListBase *constraints, *orig_constraints;
+ /* Find which constraint list to use. */
+ ListBase *constraints, *orig_constraints;
- if (pchan != NULL) {
- bPoseChannel *orig_pchan = pchan->orig_pchan;
+ if (pchan != NULL) {
+ bPoseChannel *orig_pchan = pchan->orig_pchan;
- if (orig_pchan == NULL) {
- return NULL;
- }
+ if (orig_pchan == NULL) {
+ return NULL;
+ }
- constraints = &pchan->constraints;
- orig_constraints = &orig_pchan->constraints;
- }
- else {
- constraints = &ob->constraints;
- orig_constraints = &orig_ob->constraints;
- }
+ constraints = &pchan->constraints;
+ orig_constraints = &orig_pchan->constraints;
+ }
+ else {
+ constraints = &ob->constraints;
+ orig_constraints = &orig_ob->constraints;
+ }
- /* Lookup the original constraint by index. */
- int index = BLI_findindex(constraints, con);
+ /* Lookup the original constraint by index. */
+ int index = BLI_findindex(constraints, con);
- if (index >= 0) {
- bConstraint *orig_con = BLI_findlink(orig_constraints, index);
+ if (index >= 0) {
+ bConstraint *orig_con = BLI_findlink(orig_constraints, index);
- /* Verify it has correct type and name. */
- if (orig_con && orig_con->type == con->type && STREQ(orig_con->name, con->name)) {
- if (r_orig_ob != NULL) {
- *r_orig_ob = orig_ob;
- }
+ /* Verify it has correct type and name. */
+ if (orig_con && orig_con->type == con->type && STREQ(orig_con->name, con->name)) {
+ if (r_orig_ob != NULL) {
+ *r_orig_ob = orig_ob;
+ }
- return orig_con;
- }
- }
+ return orig_con;
+ }
+ }
- return NULL;
+ return NULL;
}
static bConstraint *constraint_find_original_for_update(bConstraintOb *cob, bConstraint *con)
{
- /* Write the computed distance back to the master copy if in COW evaluation. */
- if (!DEG_is_active(cob->depsgraph)) {
- return NULL;
- }
+ /* Write the computed distance back to the master copy if in COW evaluation. */
+ if (!DEG_is_active(cob->depsgraph)) {
+ return NULL;
+ }
- Object *orig_ob = NULL;
- bConstraint *orig_con = constraint_find_original(cob->ob, cob->pchan, con, &orig_ob);
+ Object *orig_ob = NULL;
+ bConstraint *orig_con = constraint_find_original(cob->ob, cob->pchan, con, &orig_ob);
- if (orig_con != NULL) {
- DEG_id_tag_update(&orig_ob->id, ID_RECALC_COPY_ON_WRITE | ID_RECALC_TRANSFORM);
- }
+ if (orig_con != NULL) {
+ DEG_id_tag_update(&orig_ob->id, ID_RECALC_COPY_ON_WRITE | ID_RECALC_TRANSFORM);
+ }
- return orig_con;
+ return orig_con;
}
/* -------- Constraints and Proxies ------- */
@@ -5150,39 +5335,39 @@ static bConstraint *constraint_find_original_for_update(bConstraintOb *cob, bCon
/* Rescue all constraints tagged as being CONSTRAINT_PROXY_LOCAL (i.e. added to bone that's proxy-synced in this file) */
void BKE_constraints_proxylocal_extract(ListBase *dst, ListBase *src)
{
- bConstraint *con, *next;
+ bConstraint *con, *next;
- /* for each tagged constraint, remove from src and move to dst */
- for (con = src->first; con; con = next) {
- next = con->next;
+ /* for each tagged constraint, remove from src and move to dst */
+ for (con = src->first; con; con = next) {
+ next = con->next;
- /* check if tagged */
- if (con->flag & CONSTRAINT_PROXY_LOCAL) {
- BLI_remlink(src, con);
- BLI_addtail(dst, con);
- }
- }
+ /* check if tagged */
+ if (con->flag & CONSTRAINT_PROXY_LOCAL) {
+ BLI_remlink(src, con);
+ BLI_addtail(dst, con);
+ }
+ }
}
/* Returns if the owner of the constraint is proxy-protected */
bool BKE_constraints_proxylocked_owner(Object *ob, bPoseChannel *pchan)
{
- /* Currently, constraints can only be on object or bone level */
- if (ob && ob->proxy) {
- if (ob->pose && pchan) {
- bArmature *arm = ob->data;
+ /* Currently, constraints can only be on object or bone level */
+ if (ob && ob->proxy) {
+ if (ob->pose && pchan) {
+ bArmature *arm = ob->data;
- /* On bone-level, check if bone is on proxy-protected layer */
- if ((pchan->bone) && (pchan->bone->layer & arm->layer_protected))
- return true;
- }
- else {
- /* FIXME: constraints on object-level are not handled well yet */
- return true;
- }
- }
+ /* On bone-level, check if bone is on proxy-protected layer */
+ if ((pchan->bone) && (pchan->bone->layer & arm->layer_protected))
+ return true;
+ }
+ else {
+ /* FIXME: constraints on object-level are not handled well yet */
+ return true;
+ }
+ }
- return false;
+ return false;
}
/* -------- Target-Matrix Stuff ------- */
@@ -5194,99 +5379,110 @@ bool BKE_constraints_proxylocked_owner(Object *ob, bPoseChannel *pchan)
* None of the actual calculations of the matrices should be done here! Also, this function is
* not to be used by any new constraints, particularly any that have multiple targets.
*/
-void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph, Scene *scene, bConstraint *con, int index, short ownertype, void *ownerdata, float mat[4][4], float ctime)
-{
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- ListBase targets = {NULL, NULL};
- bConstraintOb *cob;
- bConstraintTarget *ct;
-
- if (cti && cti->get_constraint_targets) {
- /* make 'constraint-ob' */
- cob = MEM_callocN(sizeof(bConstraintOb), "tempConstraintOb");
- cob->type = ownertype;
- cob->scene = scene;
- cob->depsgraph = depsgraph;
- switch (ownertype) {
- case CONSTRAINT_OBTYPE_OBJECT: /* it is usually this case */
- {
- cob->ob = (Object *)ownerdata;
- cob->pchan = NULL;
- if (cob->ob) {
- copy_m4_m4(cob->matrix, cob->ob->obmat);
- copy_m4_m4(cob->startmat, cob->matrix);
- }
- else {
- unit_m4(cob->matrix);
- unit_m4(cob->startmat);
- }
- break;
- }
- case CONSTRAINT_OBTYPE_BONE: /* this may occur in some cases */
- {
- cob->ob = NULL; /* this might not work at all :/ */
- cob->pchan = (bPoseChannel *)ownerdata;
- if (cob->pchan) {
- copy_m4_m4(cob->matrix, cob->pchan->pose_mat);
- copy_m4_m4(cob->startmat, cob->matrix);
- }
- else {
- unit_m4(cob->matrix);
- unit_m4(cob->startmat);
- }
- break;
- }
- }
-
- /* get targets - we only need the first one though (and there should only be one) */
- cti->get_constraint_targets(con, &targets);
-
- /* only calculate the target matrix on the first target */
- ct = BLI_findlink(&targets, index);
-
- if (ct) {
- if (cti->get_target_matrix)
- cti->get_target_matrix(depsgraph, con, cob, ct, ctime);
- copy_m4_m4(mat, ct->matrix);
- }
-
- /* free targets + 'constraint-ob' */
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 1);
- MEM_freeN(cob);
- }
- else {
- /* invalid constraint - perhaps... */
- unit_m4(mat);
- }
+void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph,
+ Scene *scene,
+ bConstraint *con,
+ int index,
+ short ownertype,
+ void *ownerdata,
+ float mat[4][4],
+ float ctime)
+{
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintOb *cob;
+ bConstraintTarget *ct;
+
+ if (cti && cti->get_constraint_targets) {
+ /* make 'constraint-ob' */
+ cob = MEM_callocN(sizeof(bConstraintOb), "tempConstraintOb");
+ cob->type = ownertype;
+ cob->scene = scene;
+ cob->depsgraph = depsgraph;
+ switch (ownertype) {
+ case CONSTRAINT_OBTYPE_OBJECT: /* it is usually this case */
+ {
+ cob->ob = (Object *)ownerdata;
+ cob->pchan = NULL;
+ if (cob->ob) {
+ copy_m4_m4(cob->matrix, cob->ob->obmat);
+ copy_m4_m4(cob->startmat, cob->matrix);
+ }
+ else {
+ unit_m4(cob->matrix);
+ unit_m4(cob->startmat);
+ }
+ break;
+ }
+ case CONSTRAINT_OBTYPE_BONE: /* this may occur in some cases */
+ {
+ cob->ob = NULL; /* this might not work at all :/ */
+ cob->pchan = (bPoseChannel *)ownerdata;
+ if (cob->pchan) {
+ copy_m4_m4(cob->matrix, cob->pchan->pose_mat);
+ copy_m4_m4(cob->startmat, cob->matrix);
+ }
+ else {
+ unit_m4(cob->matrix);
+ unit_m4(cob->startmat);
+ }
+ break;
+ }
+ }
+
+ /* get targets - we only need the first one though (and there should only be one) */
+ cti->get_constraint_targets(con, &targets);
+
+ /* only calculate the target matrix on the first target */
+ ct = BLI_findlink(&targets, index);
+
+ if (ct) {
+ if (cti->get_target_matrix)
+ cti->get_target_matrix(depsgraph, con, cob, ct, ctime);
+ copy_m4_m4(mat, ct->matrix);
+ }
+
+ /* free targets + 'constraint-ob' */
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 1);
+ MEM_freeN(cob);
+ }
+ else {
+ /* invalid constraint - perhaps... */
+ unit_m4(mat);
+ }
}
/* Get the list of targets required for solving a constraint */
-void BKE_constraint_targets_for_solving_get(struct Depsgraph *depsgraph, bConstraint *con, bConstraintOb *cob, ListBase *targets, float ctime)
-{
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
-
- if (cti && cti->get_constraint_targets) {
- bConstraintTarget *ct;
-
- /* get targets
- * - constraints should use ct->matrix, not directly accessing values
- * - ct->matrix members have not yet been calculated here!
- */
- cti->get_constraint_targets(con, targets);
-
- /* set matrices
- * - calculate if possible, otherwise just initialize as identity matrix
- */
- if (cti->get_target_matrix) {
- for (ct = targets->first; ct; ct = ct->next)
- cti->get_target_matrix(depsgraph, con, cob, ct, ctime);
- }
- else {
- for (ct = targets->first; ct; ct = ct->next)
- unit_m4(ct->matrix);
- }
- }
+void BKE_constraint_targets_for_solving_get(struct Depsgraph *depsgraph,
+ bConstraint *con,
+ bConstraintOb *cob,
+ ListBase *targets,
+ float ctime)
+{
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+
+ if (cti && cti->get_constraint_targets) {
+ bConstraintTarget *ct;
+
+ /* get targets
+ * - constraints should use ct->matrix, not directly accessing values
+ * - ct->matrix members have not yet been calculated here!
+ */
+ cti->get_constraint_targets(con, targets);
+
+ /* set matrices
+ * - calculate if possible, otherwise just initialize as identity matrix
+ */
+ if (cti->get_target_matrix) {
+ for (ct = targets->first; ct; ct = ct->next)
+ cti->get_target_matrix(depsgraph, con, cob, ct, ctime);
+ }
+ else {
+ for (ct = targets->first; ct; ct = ct->next)
+ unit_m4(ct->matrix);
+ }
+ }
}
/* ---------- Evaluation ----------- */
@@ -5297,69 +5493,78 @@ void BKE_constraint_targets_for_solving_get(struct Depsgraph *depsgraph, bConstr
* BKE_constraints_make_evalob and BKE_constraints_clear_evalob should be called before and
* after running this function, to sort out cob
*/
-void BKE_constraints_solve(struct Depsgraph *depsgraph, ListBase *conlist, bConstraintOb *cob, float ctime)
-{
- bConstraint *con;
- float oldmat[4][4];
- float enf;
-
- /* check that there is a valid constraint object to evaluate */
- if (cob == NULL)
- return;
-
- /* loop over available constraints, solving and blending them */
- for (con = conlist->first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- ListBase targets = {NULL, NULL};
-
- /* these we can skip completely (invalid constraints...) */
- if (cti == NULL) continue;
- if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) continue;
- /* these constraints can't be evaluated anyway */
- if (cti->evaluate_constraint == NULL) continue;
- /* influence == 0 should be ignored */
- if (con->enforce == 0.0f) continue;
-
- /* influence of constraint
- * - value should have been set from animation data already
- */
- enf = con->enforce;
-
- /* make copy of worldspace matrix pre-constraint for use with blending later */
- copy_m4_m4(oldmat, cob->matrix);
-
- /* move owner matrix into right space */
- BKE_constraint_mat_convertspace(cob->ob, cob->pchan, cob->matrix, CONSTRAINT_SPACE_WORLD, con->ownspace, false);
-
- /* prepare targets for constraint solving */
- BKE_constraint_targets_for_solving_get(depsgraph, con, cob, &targets, ctime);
-
- /* Solve the constraint and put result in cob->matrix */
- cti->evaluate_constraint(con, cob, &targets);
-
- /* clear targets after use
- * - this should free temp targets but no data should be copied back
- * as constraints may have done some nasty things to it...
- */
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, 1);
- }
-
- /* move owner back into worldspace for next constraint/other business */
- if ((con->flag & CONSTRAINT_SPACEONCE) == 0)
- BKE_constraint_mat_convertspace(cob->ob, cob->pchan, cob->matrix, con->ownspace, CONSTRAINT_SPACE_WORLD, false);
-
- /* Interpolate the enforcement, to blend result of constraint into final owner transform
- * - all this happens in worldspace to prevent any weirdness creeping in ([#26014] and [#25725]),
- * since some constraints may not convert the solution back to the input space before blending
- * but all are guaranteed to end up in good "worldspace" result
- */
- /* Note: all kind of stuff here before (caused trouble), much easier to just interpolate,
- * or did I miss something? -jahka (r.32105) */
- if (enf < 1.0f) {
- float solution[4][4];
- copy_m4_m4(solution, cob->matrix);
- interp_m4_m4m4(cob->matrix, oldmat, solution, enf);
- }
- }
+void BKE_constraints_solve(struct Depsgraph *depsgraph,
+ ListBase *conlist,
+ bConstraintOb *cob,
+ float ctime)
+{
+ bConstraint *con;
+ float oldmat[4][4];
+ float enf;
+
+ /* check that there is a valid constraint object to evaluate */
+ if (cob == NULL)
+ return;
+
+ /* loop over available constraints, solving and blending them */
+ for (con = conlist->first; con; con = con->next) {
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ ListBase targets = {NULL, NULL};
+
+ /* these we can skip completely (invalid constraints...) */
+ if (cti == NULL)
+ continue;
+ if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF))
+ continue;
+ /* these constraints can't be evaluated anyway */
+ if (cti->evaluate_constraint == NULL)
+ continue;
+ /* influence == 0 should be ignored */
+ if (con->enforce == 0.0f)
+ continue;
+
+ /* influence of constraint
+ * - value should have been set from animation data already
+ */
+ enf = con->enforce;
+
+ /* make copy of worldspace matrix pre-constraint for use with blending later */
+ copy_m4_m4(oldmat, cob->matrix);
+
+ /* move owner matrix into right space */
+ BKE_constraint_mat_convertspace(
+ cob->ob, cob->pchan, cob->matrix, CONSTRAINT_SPACE_WORLD, con->ownspace, false);
+
+ /* prepare targets for constraint solving */
+ BKE_constraint_targets_for_solving_get(depsgraph, con, cob, &targets, ctime);
+
+ /* Solve the constraint and put result in cob->matrix */
+ cti->evaluate_constraint(con, cob, &targets);
+
+ /* clear targets after use
+ * - this should free temp targets but no data should be copied back
+ * as constraints may have done some nasty things to it...
+ */
+ if (cti->flush_constraint_targets) {
+ cti->flush_constraint_targets(con, &targets, 1);
+ }
+
+ /* move owner back into worldspace for next constraint/other business */
+ if ((con->flag & CONSTRAINT_SPACEONCE) == 0)
+ BKE_constraint_mat_convertspace(
+ cob->ob, cob->pchan, cob->matrix, con->ownspace, CONSTRAINT_SPACE_WORLD, false);
+
+ /* Interpolate the enforcement, to blend result of constraint into final owner transform
+ * - all this happens in worldspace to prevent any weirdness creeping in ([#26014] and [#25725]),
+ * since some constraints may not convert the solution back to the input space before blending
+ * but all are guaranteed to end up in good "worldspace" result
+ */
+ /* Note: all kind of stuff here before (caused trouble), much easier to just interpolate,
+ * or did I miss something? -jahka (r.32105) */
+ if (enf < 1.0f) {
+ float solution[4][4];
+ copy_m4_m4(solution, cob->matrix);
+ interp_m4_m4m4(cob->matrix, oldmat, solution, enf);
+ }
+ }
}
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index a16656253d3..d9ee3ab6d15 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -67,405 +67,412 @@ static CLG_LogRef LOG = {"bke.context"};
/* struct */
struct bContext {
- int thread;
-
- /* windowmanager context */
- struct {
- struct wmWindowManager *manager;
- struct wmWindow *window;
- struct WorkSpace *workspace;
- struct bScreen *screen;
- struct ScrArea *area;
- struct ARegion *region;
- struct ARegion *menu;
- struct wmGizmoGroup *gizmo_group;
- struct bContextStore *store;
- const char *operator_poll_msg; /* reason for poll failing */
- } wm;
-
- /* data context */
- struct {
- struct Main *main;
- struct Scene *scene;
-
- int recursion;
- int py_init; /* true if python is initialized */
- void *py_context;
- } data;
+ int thread;
+
+ /* windowmanager context */
+ struct {
+ struct wmWindowManager *manager;
+ struct wmWindow *window;
+ struct WorkSpace *workspace;
+ struct bScreen *screen;
+ struct ScrArea *area;
+ struct ARegion *region;
+ struct ARegion *menu;
+ struct wmGizmoGroup *gizmo_group;
+ struct bContextStore *store;
+ const char *operator_poll_msg; /* reason for poll failing */
+ } wm;
+
+ /* data context */
+ struct {
+ struct Main *main;
+ struct Scene *scene;
+
+ int recursion;
+ int py_init; /* true if python is initialized */
+ void *py_context;
+ } data;
};
/* context */
bContext *CTX_create(void)
{
- bContext *C;
+ bContext *C;
- C = MEM_callocN(sizeof(bContext), "bContext");
+ C = MEM_callocN(sizeof(bContext), "bContext");
- return C;
+ return C;
}
bContext *CTX_copy(const bContext *C)
{
- bContext *newC = MEM_dupallocN((void *)C);
+ bContext *newC = MEM_dupallocN((void *)C);
- return newC;
+ return newC;
}
void CTX_free(bContext *C)
{
- MEM_freeN(C);
+ MEM_freeN(C);
}
/* store */
bContextStore *CTX_store_add(ListBase *contexts, const char *name, PointerRNA *ptr)
{
- bContextStoreEntry *entry;
- bContextStore *ctx, *lastctx;
+ bContextStoreEntry *entry;
+ bContextStore *ctx, *lastctx;
- /* ensure we have a context to put the entry in, if it was already used
- * we have to copy the context to ensure */
- ctx = contexts->last;
+ /* ensure we have a context to put the entry in, if it was already used
+ * we have to copy the context to ensure */
+ ctx = contexts->last;
- if (!ctx || ctx->used) {
- if (ctx) {
- lastctx = ctx;
- ctx = MEM_dupallocN(lastctx);
- BLI_duplicatelist(&ctx->entries, &lastctx->entries);
- }
- else
- ctx = MEM_callocN(sizeof(bContextStore), "bContextStore");
+ if (!ctx || ctx->used) {
+ if (ctx) {
+ lastctx = ctx;
+ ctx = MEM_dupallocN(lastctx);
+ BLI_duplicatelist(&ctx->entries, &lastctx->entries);
+ }
+ else
+ ctx = MEM_callocN(sizeof(bContextStore), "bContextStore");
- BLI_addtail(contexts, ctx);
- }
+ BLI_addtail(contexts, ctx);
+ }
- entry = MEM_callocN(sizeof(bContextStoreEntry), "bContextStoreEntry");
- BLI_strncpy(entry->name, name, sizeof(entry->name));
- entry->ptr = *ptr;
+ entry = MEM_callocN(sizeof(bContextStoreEntry), "bContextStoreEntry");
+ BLI_strncpy(entry->name, name, sizeof(entry->name));
+ entry->ptr = *ptr;
- BLI_addtail(&ctx->entries, entry);
+ BLI_addtail(&ctx->entries, entry);
- return ctx;
+ return ctx;
}
bContextStore *CTX_store_add_all(ListBase *contexts, bContextStore *context)
{
- bContextStoreEntry *entry, *tentry;
- bContextStore *ctx, *lastctx;
+ bContextStoreEntry *entry, *tentry;
+ bContextStore *ctx, *lastctx;
- /* ensure we have a context to put the entries in, if it was already used
- * we have to copy the context to ensure */
- ctx = contexts->last;
+ /* ensure we have a context to put the entries in, if it was already used
+ * we have to copy the context to ensure */
+ ctx = contexts->last;
- if (!ctx || ctx->used) {
- if (ctx) {
- lastctx = ctx;
- ctx = MEM_dupallocN(lastctx);
- BLI_duplicatelist(&ctx->entries, &lastctx->entries);
- }
- else
- ctx = MEM_callocN(sizeof(bContextStore), "bContextStore");
+ if (!ctx || ctx->used) {
+ if (ctx) {
+ lastctx = ctx;
+ ctx = MEM_dupallocN(lastctx);
+ BLI_duplicatelist(&ctx->entries, &lastctx->entries);
+ }
+ else
+ ctx = MEM_callocN(sizeof(bContextStore), "bContextStore");
- BLI_addtail(contexts, ctx);
- }
+ BLI_addtail(contexts, ctx);
+ }
- for (tentry = context->entries.first; tentry; tentry = tentry->next) {
- entry = MEM_dupallocN(tentry);
- BLI_addtail(&ctx->entries, entry);
- }
+ for (tentry = context->entries.first; tentry; tentry = tentry->next) {
+ entry = MEM_dupallocN(tentry);
+ BLI_addtail(&ctx->entries, entry);
+ }
- return ctx;
+ return ctx;
}
void CTX_store_set(bContext *C, bContextStore *store)
{
- C->wm.store = store;
+ C->wm.store = store;
}
bContextStore *CTX_store_copy(bContextStore *store)
{
- bContextStore *ctx;
+ bContextStore *ctx;
- ctx = MEM_dupallocN(store);
- BLI_duplicatelist(&ctx->entries, &store->entries);
+ ctx = MEM_dupallocN(store);
+ BLI_duplicatelist(&ctx->entries, &store->entries);
- return ctx;
+ return ctx;
}
void CTX_store_free(bContextStore *store)
{
- BLI_freelistN(&store->entries);
- MEM_freeN(store);
+ BLI_freelistN(&store->entries);
+ MEM_freeN(store);
}
void CTX_store_free_list(ListBase *contexts)
{
- bContextStore *ctx;
+ bContextStore *ctx;
- while ((ctx = BLI_pophead(contexts))) {
- CTX_store_free(ctx);
- }
+ while ((ctx = BLI_pophead(contexts))) {
+ CTX_store_free(ctx);
+ }
}
/* is python initialized? */
int CTX_py_init_get(bContext *C)
{
- return C->data.py_init;
+ return C->data.py_init;
}
void CTX_py_init_set(bContext *C, int value)
{
- C->data.py_init = value;
+ C->data.py_init = value;
}
void *CTX_py_dict_get(const bContext *C)
{
- return C->data.py_context;
+ return C->data.py_context;
}
void CTX_py_dict_set(bContext *C, void *value)
{
- C->data.py_context = value;
+ C->data.py_context = value;
}
/* data context utility functions */
struct bContextDataResult {
- PointerRNA ptr;
- ListBase list;
- const char **dir;
- short type; /* 0: normal, 1: seq */
+ PointerRNA ptr;
+ ListBase list;
+ const char **dir;
+ short type; /* 0: normal, 1: seq */
};
-static void *ctx_wm_python_context_get(
- const bContext *C,
- const char *member, const StructRNA *member_type,
- void *fall_through)
+static void *ctx_wm_python_context_get(const bContext *C,
+ const char *member,
+ const StructRNA *member_type,
+ void *fall_through)
{
#ifdef WITH_PYTHON
- if (UNLIKELY(C && CTX_py_dict_get(C))) {
- bContextDataResult result;
- memset(&result, 0, sizeof(bContextDataResult));
- BPY_context_member_get((bContext *)C, member, &result);
-
- if (result.ptr.data) {
- if (RNA_struct_is_a(result.ptr.type, member_type)) {
- return result.ptr.data;
- }
- else {
- CLOG_WARN(&LOG, "PyContext '%s' is a '%s', expected a '%s'",
- member,
- RNA_struct_identifier(result.ptr.type),
- RNA_struct_identifier(member_type));
- }
- }
- }
+ if (UNLIKELY(C && CTX_py_dict_get(C))) {
+ bContextDataResult result;
+ memset(&result, 0, sizeof(bContextDataResult));
+ BPY_context_member_get((bContext *)C, member, &result);
+
+ if (result.ptr.data) {
+ if (RNA_struct_is_a(result.ptr.type, member_type)) {
+ return result.ptr.data;
+ }
+ else {
+ CLOG_WARN(&LOG,
+ "PyContext '%s' is a '%s', expected a '%s'",
+ member,
+ RNA_struct_identifier(result.ptr.type),
+ RNA_struct_identifier(member_type));
+ }
+ }
+ }
#else
- UNUSED_VARS(C, member, member_type);
+ UNUSED_VARS(C, member, member_type);
#endif
- /* don't allow UI context access from non-main threads */
- if (!BLI_thread_is_main())
- return NULL;
+ /* don't allow UI context access from non-main threads */
+ if (!BLI_thread_is_main())
+ return NULL;
- return fall_through;
+ return fall_through;
}
static int ctx_data_get(bContext *C, const char *member, bContextDataResult *result)
{
- bScreen *sc;
- ScrArea *sa;
- ARegion *ar;
- int done = 0, recursion = C->data.recursion;
- int ret = 0;
+ bScreen *sc;
+ ScrArea *sa;
+ ARegion *ar;
+ int done = 0, recursion = C->data.recursion;
+ int ret = 0;
- memset(result, 0, sizeof(bContextDataResult));
+ memset(result, 0, sizeof(bContextDataResult));
#ifdef WITH_PYTHON
- if (CTX_py_dict_get(C)) {
- if (BPY_context_member_get(C, member, result)) {
- return 1;
- }
- }
+ if (CTX_py_dict_get(C)) {
+ if (BPY_context_member_get(C, member, result)) {
+ return 1;
+ }
+ }
#endif
- /* don't allow UI context access from non-main threads */
- if (!BLI_thread_is_main())
- return done;
-
- /* we check recursion to ensure that we do not get infinite
- * loops requesting data from ourselves in a context callback */
-
- /* Ok, this looks evil...
- * if (ret) done = -(-ret | -done);
- *
- * Values in order of importance
- * (0, -1, 1) - Where 1 is highest priority
- * */
- if (done != 1 && recursion < 1 && C->wm.store) {
- bContextStoreEntry *entry;
-
- C->data.recursion = 1;
-
- entry = BLI_rfindstring(&C->wm.store->entries, member, offsetof(bContextStoreEntry, name));
- if (entry) {
- result->ptr = entry->ptr;
- done = 1;
- }
- }
- if (done != 1 && recursion < 2 && (ar = CTX_wm_region(C))) {
- C->data.recursion = 2;
- if (ar->type && ar->type->context) {
- ret = ar->type->context(C, member, result);
- if (ret) done = -(-ret | -done);
-
- }
- }
- if (done != 1 && recursion < 3 && (sa = CTX_wm_area(C))) {
- C->data.recursion = 3;
- if (sa->type && sa->type->context) {
- ret = sa->type->context(C, member, result);
- if (ret) done = -(-ret | -done);
- }
- }
- if (done != 1 && recursion < 4 && (sc = CTX_wm_screen(C))) {
- bContextDataCallback cb = sc->context;
- C->data.recursion = 4;
- if (cb) {
- ret = cb(C, member, result);
- if (ret) done = -(-ret | -done);
- }
- }
-
- C->data.recursion = recursion;
-
- return done;
+ /* don't allow UI context access from non-main threads */
+ if (!BLI_thread_is_main())
+ return done;
+
+ /* we check recursion to ensure that we do not get infinite
+ * loops requesting data from ourselves in a context callback */
+
+ /* Ok, this looks evil...
+ * if (ret) done = -(-ret | -done);
+ *
+ * Values in order of importance
+ * (0, -1, 1) - Where 1 is highest priority
+ * */
+ if (done != 1 && recursion < 1 && C->wm.store) {
+ bContextStoreEntry *entry;
+
+ C->data.recursion = 1;
+
+ entry = BLI_rfindstring(&C->wm.store->entries, member, offsetof(bContextStoreEntry, name));
+ if (entry) {
+ result->ptr = entry->ptr;
+ done = 1;
+ }
+ }
+ if (done != 1 && recursion < 2 && (ar = CTX_wm_region(C))) {
+ C->data.recursion = 2;
+ if (ar->type && ar->type->context) {
+ ret = ar->type->context(C, member, result);
+ if (ret)
+ done = -(-ret | -done);
+ }
+ }
+ if (done != 1 && recursion < 3 && (sa = CTX_wm_area(C))) {
+ C->data.recursion = 3;
+ if (sa->type && sa->type->context) {
+ ret = sa->type->context(C, member, result);
+ if (ret)
+ done = -(-ret | -done);
+ }
+ }
+ if (done != 1 && recursion < 4 && (sc = CTX_wm_screen(C))) {
+ bContextDataCallback cb = sc->context;
+ C->data.recursion = 4;
+ if (cb) {
+ ret = cb(C, member, result);
+ if (ret)
+ done = -(-ret | -done);
+ }
+ }
+
+ C->data.recursion = recursion;
+
+ return done;
}
static void *ctx_data_pointer_get(const bContext *C, const char *member)
{
- bContextDataResult result;
+ bContextDataResult result;
- if (C && ctx_data_get((bContext *)C, member, &result) == 1) {
- BLI_assert(result.type == CTX_DATA_TYPE_POINTER);
- return result.ptr.data;
- }
- else {
- return NULL;
- }
+ if (C && ctx_data_get((bContext *)C, member, &result) == 1) {
+ BLI_assert(result.type == CTX_DATA_TYPE_POINTER);
+ return result.ptr.data;
+ }
+ else {
+ return NULL;
+ }
}
static int ctx_data_pointer_verify(const bContext *C, const char *member, void **pointer)
{
- bContextDataResult result;
+ bContextDataResult result;
- /* if context is NULL, pointer must be NULL too and that is a valid return */
- if (C == NULL) {
- *pointer = NULL;
- return 1;
- }
- else if (ctx_data_get((bContext *)C, member, &result) == 1) {
- BLI_assert(result.type == CTX_DATA_TYPE_POINTER);
- *pointer = result.ptr.data;
- return 1;
- }
- else {
- *pointer = NULL;
- return 0;
- }
+ /* if context is NULL, pointer must be NULL too and that is a valid return */
+ if (C == NULL) {
+ *pointer = NULL;
+ return 1;
+ }
+ else if (ctx_data_get((bContext *)C, member, &result) == 1) {
+ BLI_assert(result.type == CTX_DATA_TYPE_POINTER);
+ *pointer = result.ptr.data;
+ return 1;
+ }
+ else {
+ *pointer = NULL;
+ return 0;
+ }
}
static int ctx_data_collection_get(const bContext *C, const char *member, ListBase *list)
{
- bContextDataResult result;
+ bContextDataResult result;
- if (ctx_data_get((bContext *)C, member, &result) == 1) {
- BLI_assert(result.type == CTX_DATA_TYPE_COLLECTION);
- *list = result.list;
- return 1;
- }
+ if (ctx_data_get((bContext *)C, member, &result) == 1) {
+ BLI_assert(result.type == CTX_DATA_TYPE_COLLECTION);
+ *list = result.list;
+ return 1;
+ }
- BLI_listbase_clear(list);
+ BLI_listbase_clear(list);
- return 0;
+ return 0;
}
PointerRNA CTX_data_pointer_get(const bContext *C, const char *member)
{
- bContextDataResult result;
+ bContextDataResult result;
- if (ctx_data_get((bContext *)C, member, &result) == 1) {
- BLI_assert(result.type == CTX_DATA_TYPE_POINTER);
- return result.ptr;
- }
- else {
- return PointerRNA_NULL;
- }
+ if (ctx_data_get((bContext *)C, member, &result) == 1) {
+ BLI_assert(result.type == CTX_DATA_TYPE_POINTER);
+ return result.ptr;
+ }
+ else {
+ return PointerRNA_NULL;
+ }
}
PointerRNA CTX_data_pointer_get_type(const bContext *C, const char *member, StructRNA *type)
{
- PointerRNA ptr = CTX_data_pointer_get(C, member);
+ PointerRNA ptr = CTX_data_pointer_get(C, member);
- if (ptr.data) {
- if (RNA_struct_is_a(ptr.type, type)) {
- return ptr;
- }
- else {
- CLOG_WARN(&LOG, "member '%s' is '%s', not '%s'",
- member, RNA_struct_identifier(ptr.type), RNA_struct_identifier(type));
- }
- }
+ if (ptr.data) {
+ if (RNA_struct_is_a(ptr.type, type)) {
+ return ptr;
+ }
+ else {
+ CLOG_WARN(&LOG,
+ "member '%s' is '%s', not '%s'",
+ member,
+ RNA_struct_identifier(ptr.type),
+ RNA_struct_identifier(type));
+ }
+ }
- return PointerRNA_NULL;
+ return PointerRNA_NULL;
}
ListBase CTX_data_collection_get(const bContext *C, const char *member)
{
- bContextDataResult result;
+ bContextDataResult result;
- if (ctx_data_get((bContext *)C, member, &result) == 1) {
- BLI_assert(result.type == CTX_DATA_TYPE_COLLECTION);
- return result.list;
- }
- else {
- ListBase list = {NULL, NULL};
- return list;
- }
+ if (ctx_data_get((bContext *)C, member, &result) == 1) {
+ BLI_assert(result.type == CTX_DATA_TYPE_COLLECTION);
+ return result.list;
+ }
+ else {
+ ListBase list = {NULL, NULL};
+ return list;
+ }
}
/* 1:found, -1:found but not set, 0:not found */
-int CTX_data_get(const bContext *C, const char *member, PointerRNA *r_ptr, ListBase *r_lb, short *r_type)
+int CTX_data_get(
+ const bContext *C, const char *member, PointerRNA *r_ptr, ListBase *r_lb, short *r_type)
{
- bContextDataResult result;
- int ret = ctx_data_get((bContext *)C, member, &result);
+ bContextDataResult result;
+ int ret = ctx_data_get((bContext *)C, member, &result);
- if (ret == 1) {
- *r_ptr = result.ptr;
- *r_lb = result.list;
- *r_type = result.type;
- }
- else {
- memset(r_ptr, 0, sizeof(*r_ptr));
- memset(r_lb, 0, sizeof(*r_lb));
- *r_type = 0;
- }
+ if (ret == 1) {
+ *r_ptr = result.ptr;
+ *r_lb = result.list;
+ *r_type = result.type;
+ }
+ else {
+ memset(r_ptr, 0, sizeof(*r_ptr));
+ memset(r_lb, 0, sizeof(*r_lb));
+ *r_type = 0;
+ }
- return ret;
+ return ret;
}
static void data_dir_add(ListBase *lb, const char *member, const bool use_all)
{
- LinkData *link;
+ LinkData *link;
- if ((use_all == false) && STREQ(member, "scene")) /* exception */
- return;
+ if ((use_all == false) && STREQ(member, "scene")) /* exception */
+ return;
- if (BLI_findstring(lb, member, offsetof(LinkData, data)))
- return;
+ if (BLI_findstring(lb, member, offsetof(LinkData, data)))
+ return;
- link = MEM_callocN(sizeof(LinkData), "LinkData");
- link->data = (void *)member;
- BLI_addtail(lb, link);
+ link = MEM_callocN(sizeof(LinkData), "LinkData");
+ link->data = (void *)member;
+ BLI_addtail(lb, link);
}
/**
@@ -474,466 +481,466 @@ static void data_dir_add(ListBase *lb, const char *member, const bool use_all)
* \param use_rna: Use Include the properties from 'RNA_Context'
* \param use_all: Don't skip values (currently only "scene")
*/
-ListBase CTX_data_dir_get_ex(const bContext *C, const bool use_store, const bool use_rna, const bool use_all)
-{
- bContextDataResult result;
- ListBase lb;
- bScreen *sc;
- ScrArea *sa;
- ARegion *ar;
- int a;
-
- memset(&lb, 0, sizeof(lb));
-
- if (use_rna) {
- char name[256], *nameptr;
- int namelen;
-
- PropertyRNA *iterprop;
- PointerRNA ctx_ptr;
- RNA_pointer_create(NULL, &RNA_Context, (void *)C, &ctx_ptr);
-
- iterprop = RNA_struct_iterator_property(ctx_ptr.type);
-
- RNA_PROP_BEGIN (&ctx_ptr, itemptr, iterprop)
- {
- nameptr = RNA_struct_name_get_alloc(&itemptr, name, sizeof(name), &namelen);
- data_dir_add(&lb, name, use_all);
- if (nameptr) {
- if (name != nameptr) {
- MEM_freeN(nameptr);
- }
- }
- }
- RNA_PROP_END;
- }
- if (use_store && C->wm.store) {
- bContextStoreEntry *entry;
-
- for (entry = C->wm.store->entries.first; entry; entry = entry->next)
- data_dir_add(&lb, entry->name, use_all);
- }
- if ((ar = CTX_wm_region(C)) && ar->type && ar->type->context) {
- memset(&result, 0, sizeof(result));
- ar->type->context(C, "", &result);
-
- if (result.dir)
- for (a = 0; result.dir[a]; a++)
- data_dir_add(&lb, result.dir[a], use_all);
- }
- if ((sa = CTX_wm_area(C)) && sa->type && sa->type->context) {
- memset(&result, 0, sizeof(result));
- sa->type->context(C, "", &result);
-
- if (result.dir)
- for (a = 0; result.dir[a]; a++)
- data_dir_add(&lb, result.dir[a], use_all);
- }
- if ((sc = CTX_wm_screen(C)) && sc->context) {
- bContextDataCallback cb = sc->context;
- memset(&result, 0, sizeof(result));
- cb(C, "", &result);
-
- if (result.dir)
- for (a = 0; result.dir[a]; a++)
- data_dir_add(&lb, result.dir[a], use_all);
- }
-
- return lb;
+ListBase CTX_data_dir_get_ex(const bContext *C,
+ const bool use_store,
+ const bool use_rna,
+ const bool use_all)
+{
+ bContextDataResult result;
+ ListBase lb;
+ bScreen *sc;
+ ScrArea *sa;
+ ARegion *ar;
+ int a;
+
+ memset(&lb, 0, sizeof(lb));
+
+ if (use_rna) {
+ char name[256], *nameptr;
+ int namelen;
+
+ PropertyRNA *iterprop;
+ PointerRNA ctx_ptr;
+ RNA_pointer_create(NULL, &RNA_Context, (void *)C, &ctx_ptr);
+
+ iterprop = RNA_struct_iterator_property(ctx_ptr.type);
+
+ RNA_PROP_BEGIN (&ctx_ptr, itemptr, iterprop) {
+ nameptr = RNA_struct_name_get_alloc(&itemptr, name, sizeof(name), &namelen);
+ data_dir_add(&lb, name, use_all);
+ if (nameptr) {
+ if (name != nameptr) {
+ MEM_freeN(nameptr);
+ }
+ }
+ }
+ RNA_PROP_END;
+ }
+ if (use_store && C->wm.store) {
+ bContextStoreEntry *entry;
+
+ for (entry = C->wm.store->entries.first; entry; entry = entry->next)
+ data_dir_add(&lb, entry->name, use_all);
+ }
+ if ((ar = CTX_wm_region(C)) && ar->type && ar->type->context) {
+ memset(&result, 0, sizeof(result));
+ ar->type->context(C, "", &result);
+
+ if (result.dir)
+ for (a = 0; result.dir[a]; a++)
+ data_dir_add(&lb, result.dir[a], use_all);
+ }
+ if ((sa = CTX_wm_area(C)) && sa->type && sa->type->context) {
+ memset(&result, 0, sizeof(result));
+ sa->type->context(C, "", &result);
+
+ if (result.dir)
+ for (a = 0; result.dir[a]; a++)
+ data_dir_add(&lb, result.dir[a], use_all);
+ }
+ if ((sc = CTX_wm_screen(C)) && sc->context) {
+ bContextDataCallback cb = sc->context;
+ memset(&result, 0, sizeof(result));
+ cb(C, "", &result);
+
+ if (result.dir)
+ for (a = 0; result.dir[a]; a++)
+ data_dir_add(&lb, result.dir[a], use_all);
+ }
+
+ return lb;
}
ListBase CTX_data_dir_get(const bContext *C)
{
- return CTX_data_dir_get_ex(C, true, false, false);
+ return CTX_data_dir_get_ex(C, true, false, false);
}
bool CTX_data_equals(const char *member, const char *str)
{
- return (STREQ(member, str));
+ return (STREQ(member, str));
}
bool CTX_data_dir(const char *member)
{
- return member[0] == '\0';
+ return member[0] == '\0';
}
void CTX_data_id_pointer_set(bContextDataResult *result, ID *id)
{
- RNA_id_pointer_create(id, &result->ptr);
+ RNA_id_pointer_create(id, &result->ptr);
}
void CTX_data_pointer_set(bContextDataResult *result, ID *id, StructRNA *type, void *data)
{
- RNA_pointer_create(id, type, data, &result->ptr);
+ RNA_pointer_create(id, type, data, &result->ptr);
}
void CTX_data_id_list_add(bContextDataResult *result, ID *id)
{
- CollectionPointerLink *link;
+ CollectionPointerLink *link;
- link = MEM_callocN(sizeof(CollectionPointerLink), "CTX_data_id_list_add");
- RNA_id_pointer_create(id, &link->ptr);
+ link = MEM_callocN(sizeof(CollectionPointerLink), "CTX_data_id_list_add");
+ RNA_id_pointer_create(id, &link->ptr);
- BLI_addtail(&result->list, link);
+ BLI_addtail(&result->list, link);
}
void CTX_data_list_add(bContextDataResult *result, ID *id, StructRNA *type, void *data)
{
- CollectionPointerLink *link;
+ CollectionPointerLink *link;
- link = MEM_callocN(sizeof(CollectionPointerLink), "CTX_data_list_add");
- RNA_pointer_create(id, type, data, &link->ptr);
+ link = MEM_callocN(sizeof(CollectionPointerLink), "CTX_data_list_add");
+ RNA_pointer_create(id, type, data, &link->ptr);
- BLI_addtail(&result->list, link);
+ BLI_addtail(&result->list, link);
}
int ctx_data_list_count(const bContext *C, int (*func)(const bContext *, ListBase *))
{
- ListBase list;
+ ListBase list;
- if (func(C, &list)) {
- int tot = BLI_listbase_count(&list);
- BLI_freelistN(&list);
- return tot;
- }
- else
- return 0;
+ if (func(C, &list)) {
+ int tot = BLI_listbase_count(&list);
+ BLI_freelistN(&list);
+ return tot;
+ }
+ else
+ return 0;
}
void CTX_data_dir_set(bContextDataResult *result, const char **dir)
{
- result->dir = dir;
+ result->dir = dir;
}
void CTX_data_type_set(bContextDataResult *result, short type)
{
- result->type = type;
+ result->type = type;
}
short CTX_data_type_get(bContextDataResult *result)
{
- return result->type;
+ return result->type;
}
-
-
/* window manager context */
wmWindowManager *CTX_wm_manager(const bContext *C)
{
- return C->wm.manager;
+ return C->wm.manager;
}
wmWindow *CTX_wm_window(const bContext *C)
{
- return ctx_wm_python_context_get(C, "window", &RNA_Window, C->wm.window);
+ return ctx_wm_python_context_get(C, "window", &RNA_Window, C->wm.window);
}
WorkSpace *CTX_wm_workspace(const bContext *C)
{
- return ctx_wm_python_context_get(C, "workspace", &RNA_WorkSpace, C->wm.workspace);
+ return ctx_wm_python_context_get(C, "workspace", &RNA_WorkSpace, C->wm.workspace);
}
bScreen *CTX_wm_screen(const bContext *C)
{
- return ctx_wm_python_context_get(C, "screen", &RNA_Screen, C->wm.screen);
+ return ctx_wm_python_context_get(C, "screen", &RNA_Screen, C->wm.screen);
}
ScrArea *CTX_wm_area(const bContext *C)
{
- return ctx_wm_python_context_get(C, "area", &RNA_Area, C->wm.area);
+ return ctx_wm_python_context_get(C, "area", &RNA_Area, C->wm.area);
}
SpaceLink *CTX_wm_space_data(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- return (sa) ? sa->spacedata.first : NULL;
+ ScrArea *sa = CTX_wm_area(C);
+ return (sa) ? sa->spacedata.first : NULL;
}
ARegion *CTX_wm_region(const bContext *C)
{
- return ctx_wm_python_context_get(C, "region", &RNA_Region, C->wm.region);
+ return ctx_wm_python_context_get(C, "region", &RNA_Region, C->wm.region);
}
void *CTX_wm_region_data(const bContext *C)
{
- ARegion *ar = CTX_wm_region(C);
- return (ar) ? ar->regiondata : NULL;
+ ARegion *ar = CTX_wm_region(C);
+ return (ar) ? ar->regiondata : NULL;
}
struct ARegion *CTX_wm_menu(const bContext *C)
{
- return C->wm.menu;
+ return C->wm.menu;
}
struct wmGizmoGroup *CTX_wm_gizmo_group(const bContext *C)
{
- return C->wm.gizmo_group;
+ return C->wm.gizmo_group;
}
struct wmMsgBus *CTX_wm_message_bus(const bContext *C)
{
- return C->wm.manager ? C->wm.manager->message_bus : NULL;
+ return C->wm.manager ? C->wm.manager->message_bus : NULL;
}
struct ReportList *CTX_wm_reports(const bContext *C)
{
- if (C->wm.manager)
- return &(C->wm.manager->reports);
+ if (C->wm.manager)
+ return &(C->wm.manager->reports);
- return NULL;
+ return NULL;
}
View3D *CTX_wm_view3d(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_VIEW3D)
- return sa->spacedata.first;
- return NULL;
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa && sa->spacetype == SPACE_VIEW3D)
+ return sa->spacedata.first;
+ return NULL;
}
RegionView3D *CTX_wm_region_view3d(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- ARegion *ar = CTX_wm_region(C);
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
- if (sa && sa->spacetype == SPACE_VIEW3D)
- if (ar)
- return ar->regiondata;
- return NULL;
+ if (sa && sa->spacetype == SPACE_VIEW3D)
+ if (ar)
+ return ar->regiondata;
+ return NULL;
}
struct SpaceText *CTX_wm_space_text(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_TEXT)
- return sa->spacedata.first;
- return NULL;
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa && sa->spacetype == SPACE_TEXT)
+ return sa->spacedata.first;
+ return NULL;
}
struct SpaceConsole *CTX_wm_space_console(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_CONSOLE)
- return sa->spacedata.first;
- return NULL;
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa && sa->spacetype == SPACE_CONSOLE)
+ return sa->spacedata.first;
+ return NULL;
}
struct SpaceImage *CTX_wm_space_image(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_IMAGE)
- return sa->spacedata.first;
- return NULL;
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa && sa->spacetype == SPACE_IMAGE)
+ return sa->spacedata.first;
+ return NULL;
}
struct SpaceProperties *CTX_wm_space_properties(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_PROPERTIES)
- return sa->spacedata.first;
- return NULL;
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa && sa->spacetype == SPACE_PROPERTIES)
+ return sa->spacedata.first;
+ return NULL;
}
struct SpaceFile *CTX_wm_space_file(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_FILE)
- return sa->spacedata.first;
- return NULL;
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa && sa->spacetype == SPACE_FILE)
+ return sa->spacedata.first;
+ return NULL;
}
struct SpaceSeq *CTX_wm_space_seq(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_SEQ)
- return sa->spacedata.first;
- return NULL;
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa && sa->spacetype == SPACE_SEQ)
+ return sa->spacedata.first;
+ return NULL;
}
struct SpaceOutliner *CTX_wm_space_outliner(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_OUTLINER)
- return sa->spacedata.first;
- return NULL;
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa && sa->spacetype == SPACE_OUTLINER)
+ return sa->spacedata.first;
+ return NULL;
}
struct SpaceNla *CTX_wm_space_nla(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_NLA)
- return sa->spacedata.first;
- return NULL;
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa && sa->spacetype == SPACE_NLA)
+ return sa->spacedata.first;
+ return NULL;
}
struct SpaceNode *CTX_wm_space_node(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_NODE)
- return sa->spacedata.first;
- return NULL;
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa && sa->spacetype == SPACE_NODE)
+ return sa->spacedata.first;
+ return NULL;
}
struct SpaceGraph *CTX_wm_space_graph(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_GRAPH)
- return sa->spacedata.first;
- return NULL;
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa && sa->spacetype == SPACE_GRAPH)
+ return sa->spacedata.first;
+ return NULL;
}
struct SpaceAction *CTX_wm_space_action(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_ACTION)
- return sa->spacedata.first;
- return NULL;
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa && sa->spacetype == SPACE_ACTION)
+ return sa->spacedata.first;
+ return NULL;
}
struct SpaceInfo *CTX_wm_space_info(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_INFO)
- return sa->spacedata.first;
- return NULL;
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa && sa->spacetype == SPACE_INFO)
+ return sa->spacedata.first;
+ return NULL;
}
struct SpaceUserPref *CTX_wm_space_userpref(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_USERPREF)
- return sa->spacedata.first;
- return NULL;
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa && sa->spacetype == SPACE_USERPREF)
+ return sa->spacedata.first;
+ return NULL;
}
struct SpaceClip *CTX_wm_space_clip(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_CLIP)
- return sa->spacedata.first;
- return NULL;
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa && sa->spacetype == SPACE_CLIP)
+ return sa->spacedata.first;
+ return NULL;
}
struct SpaceTopBar *CTX_wm_space_topbar(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_TOPBAR)
- return sa->spacedata.first;
- return NULL;
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa && sa->spacetype == SPACE_TOPBAR)
+ return sa->spacedata.first;
+ return NULL;
}
void CTX_wm_manager_set(bContext *C, wmWindowManager *wm)
{
- C->wm.manager = wm;
- C->wm.window = NULL;
- C->wm.screen = NULL;
- C->wm.area = NULL;
- C->wm.region = NULL;
+ C->wm.manager = wm;
+ C->wm.window = NULL;
+ C->wm.screen = NULL;
+ C->wm.area = NULL;
+ C->wm.region = NULL;
}
void CTX_wm_window_set(bContext *C, wmWindow *win)
{
- C->wm.window = win;
- if (win) {
- C->data.scene = win->scene;
- }
- C->wm.workspace = (win) ? BKE_workspace_active_get(win->workspace_hook) : NULL;
- C->wm.screen = (win) ? BKE_workspace_active_screen_get(win->workspace_hook) : NULL;
- C->wm.area = NULL;
- C->wm.region = NULL;
+ C->wm.window = win;
+ if (win) {
+ C->data.scene = win->scene;
+ }
+ C->wm.workspace = (win) ? BKE_workspace_active_get(win->workspace_hook) : NULL;
+ C->wm.screen = (win) ? BKE_workspace_active_screen_get(win->workspace_hook) : NULL;
+ C->wm.area = NULL;
+ C->wm.region = NULL;
}
void CTX_wm_screen_set(bContext *C, bScreen *screen)
{
- C->wm.screen = screen;
- C->wm.area = NULL;
- C->wm.region = NULL;
+ C->wm.screen = screen;
+ C->wm.area = NULL;
+ C->wm.region = NULL;
}
void CTX_wm_area_set(bContext *C, ScrArea *area)
{
- C->wm.area = area;
- C->wm.region = NULL;
+ C->wm.area = area;
+ C->wm.region = NULL;
}
void CTX_wm_region_set(bContext *C, ARegion *region)
{
- C->wm.region = region;
+ C->wm.region = region;
}
void CTX_wm_menu_set(bContext *C, ARegion *menu)
{
- C->wm.menu = menu;
+ C->wm.menu = menu;
}
void CTX_wm_gizmo_group_set(bContext *C, struct wmGizmoGroup *gzgroup)
{
- C->wm.gizmo_group = gzgroup;
+ C->wm.gizmo_group = gzgroup;
}
void CTX_wm_operator_poll_msg_set(bContext *C, const char *msg)
{
- C->wm.operator_poll_msg = msg;
+ C->wm.operator_poll_msg = msg;
}
const char *CTX_wm_operator_poll_msg_get(bContext *C)
{
- return IFACE_(C->wm.operator_poll_msg);
+ return IFACE_(C->wm.operator_poll_msg);
}
/* data context */
Main *CTX_data_main(const bContext *C)
{
- Main *bmain;
+ Main *bmain;
- if (ctx_data_pointer_verify(C, "blend_data", (void *)&bmain))
- return bmain;
- else
- return C->data.main;
+ if (ctx_data_pointer_verify(C, "blend_data", (void *)&bmain))
+ return bmain;
+ else
+ return C->data.main;
}
void CTX_data_main_set(bContext *C, Main *bmain)
{
- C->data.main = bmain;
- BKE_sound_init_main(bmain);
+ C->data.main = bmain;
+ BKE_sound_init_main(bmain);
}
Scene *CTX_data_scene(const bContext *C)
{
- Scene *scene;
+ Scene *scene;
- if (ctx_data_pointer_verify(C, "scene", (void *)&scene))
- return scene;
- else
- return C->data.scene;
+ if (ctx_data_pointer_verify(C, "scene", (void *)&scene))
+ return scene;
+ else
+ return C->data.scene;
}
ViewLayer *CTX_data_view_layer(const bContext *C)
{
- ViewLayer *view_layer;
+ ViewLayer *view_layer;
- if (ctx_data_pointer_verify(C, "view_layer", (void *)&view_layer)) {
- return view_layer;
- }
+ if (ctx_data_pointer_verify(C, "view_layer", (void *)&view_layer)) {
+ return view_layer;
+ }
- wmWindow *win = CTX_wm_window(C);
- Scene *scene = CTX_data_scene(C);
- if (win) {
- view_layer = BKE_view_layer_find(scene, win->view_layer_name);
- if (view_layer) {
- return view_layer;
- }
- }
+ wmWindow *win = CTX_wm_window(C);
+ Scene *scene = CTX_data_scene(C);
+ if (win) {
+ view_layer = BKE_view_layer_find(scene, win->view_layer_name);
+ if (view_layer) {
+ return view_layer;
+ }
+ }
- return BKE_view_layer_default_view(scene);
+ return BKE_view_layer_default_view(scene);
}
RenderEngineType *CTX_data_engine_type(const bContext *C)
{
- Scene *scene = CTX_data_scene(C);
- return RE_engines_find(scene->r.engine);
+ Scene *scene = CTX_data_scene(C);
+ return RE_engines_find(scene->r.engine);
}
/**
@@ -945,307 +952,320 @@ RenderEngineType *CTX_data_engine_type(const bContext *C)
*/
LayerCollection *CTX_data_layer_collection(const bContext *C)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- LayerCollection *layer_collection;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ LayerCollection *layer_collection;
- if (ctx_data_pointer_verify(C, "layer_collection", (void *)&layer_collection)) {
- if (BKE_view_layer_has_collection(view_layer, layer_collection->collection)) {
- return layer_collection;
- }
- }
+ if (ctx_data_pointer_verify(C, "layer_collection", (void *)&layer_collection)) {
+ if (BKE_view_layer_has_collection(view_layer, layer_collection->collection)) {
+ return layer_collection;
+ }
+ }
- /* fallback */
- return BKE_layer_collection_get_active(view_layer);
+ /* fallback */
+ return BKE_layer_collection_get_active(view_layer);
}
Collection *CTX_data_collection(const bContext *C)
{
- Collection *collection;
- if (ctx_data_pointer_verify(C, "collection", (void *)&collection)) {
- return collection;
- }
-
- LayerCollection *layer_collection = CTX_data_layer_collection(C);
- if (layer_collection) {
- return layer_collection->collection;
- }
-
- /* fallback */
- Scene *scene = CTX_data_scene(C);
- return BKE_collection_master(scene);
-}
-
-enum eContextObjectMode CTX_data_mode_enum_ex(const Object *obedit, const Object *ob, const eObjectMode object_mode)
-{
- // Object *obedit = CTX_data_edit_object(C);
- if (obedit) {
- switch (obedit->type) {
- case OB_MESH:
- return CTX_MODE_EDIT_MESH;
- case OB_CURVE:
- return CTX_MODE_EDIT_CURVE;
- case OB_SURF:
- return CTX_MODE_EDIT_SURFACE;
- case OB_FONT:
- return CTX_MODE_EDIT_TEXT;
- case OB_ARMATURE:
- return CTX_MODE_EDIT_ARMATURE;
- case OB_MBALL:
- return CTX_MODE_EDIT_METABALL;
- case OB_LATTICE:
- return CTX_MODE_EDIT_LATTICE;
- }
- }
- else {
- // Object *ob = CTX_data_active_object(C);
- if (ob) {
- if (object_mode & OB_MODE_POSE) return CTX_MODE_POSE;
- else if (object_mode & OB_MODE_SCULPT) return CTX_MODE_SCULPT;
- else if (object_mode & OB_MODE_WEIGHT_PAINT) return CTX_MODE_PAINT_WEIGHT;
- else if (object_mode & OB_MODE_VERTEX_PAINT) return CTX_MODE_PAINT_VERTEX;
- else if (object_mode & OB_MODE_TEXTURE_PAINT) return CTX_MODE_PAINT_TEXTURE;
- else if (object_mode & OB_MODE_PARTICLE_EDIT) return CTX_MODE_PARTICLE;
- else if (object_mode & OB_MODE_PAINT_GPENCIL) return CTX_MODE_PAINT_GPENCIL;
- else if (object_mode & OB_MODE_EDIT_GPENCIL) return CTX_MODE_EDIT_GPENCIL;
- else if (object_mode & OB_MODE_SCULPT_GPENCIL) return CTX_MODE_SCULPT_GPENCIL;
- else if (object_mode & OB_MODE_WEIGHT_GPENCIL) return CTX_MODE_WEIGHT_GPENCIL;
- }
- }
-
- return CTX_MODE_OBJECT;
+ Collection *collection;
+ if (ctx_data_pointer_verify(C, "collection", (void *)&collection)) {
+ return collection;
+ }
+
+ LayerCollection *layer_collection = CTX_data_layer_collection(C);
+ if (layer_collection) {
+ return layer_collection->collection;
+ }
+
+ /* fallback */
+ Scene *scene = CTX_data_scene(C);
+ return BKE_collection_master(scene);
+}
+
+enum eContextObjectMode CTX_data_mode_enum_ex(const Object *obedit,
+ const Object *ob,
+ const eObjectMode object_mode)
+{
+ // Object *obedit = CTX_data_edit_object(C);
+ if (obedit) {
+ switch (obedit->type) {
+ case OB_MESH:
+ return CTX_MODE_EDIT_MESH;
+ case OB_CURVE:
+ return CTX_MODE_EDIT_CURVE;
+ case OB_SURF:
+ return CTX_MODE_EDIT_SURFACE;
+ case OB_FONT:
+ return CTX_MODE_EDIT_TEXT;
+ case OB_ARMATURE:
+ return CTX_MODE_EDIT_ARMATURE;
+ case OB_MBALL:
+ return CTX_MODE_EDIT_METABALL;
+ case OB_LATTICE:
+ return CTX_MODE_EDIT_LATTICE;
+ }
+ }
+ else {
+ // Object *ob = CTX_data_active_object(C);
+ if (ob) {
+ if (object_mode & OB_MODE_POSE)
+ return CTX_MODE_POSE;
+ else if (object_mode & OB_MODE_SCULPT)
+ return CTX_MODE_SCULPT;
+ else if (object_mode & OB_MODE_WEIGHT_PAINT)
+ return CTX_MODE_PAINT_WEIGHT;
+ else if (object_mode & OB_MODE_VERTEX_PAINT)
+ return CTX_MODE_PAINT_VERTEX;
+ else if (object_mode & OB_MODE_TEXTURE_PAINT)
+ return CTX_MODE_PAINT_TEXTURE;
+ else if (object_mode & OB_MODE_PARTICLE_EDIT)
+ return CTX_MODE_PARTICLE;
+ else if (object_mode & OB_MODE_PAINT_GPENCIL)
+ return CTX_MODE_PAINT_GPENCIL;
+ else if (object_mode & OB_MODE_EDIT_GPENCIL)
+ return CTX_MODE_EDIT_GPENCIL;
+ else if (object_mode & OB_MODE_SCULPT_GPENCIL)
+ return CTX_MODE_SCULPT_GPENCIL;
+ else if (object_mode & OB_MODE_WEIGHT_GPENCIL)
+ return CTX_MODE_WEIGHT_GPENCIL;
+ }
+ }
+
+ return CTX_MODE_OBJECT;
}
enum eContextObjectMode CTX_data_mode_enum(const bContext *C)
{
- Object *obedit = CTX_data_edit_object(C);
- Object *obact = obedit ? NULL : CTX_data_active_object(C);
- return CTX_data_mode_enum_ex(obedit, obact, obact ? obact->mode : OB_MODE_OBJECT);
+ Object *obedit = CTX_data_edit_object(C);
+ Object *obact = obedit ? NULL : CTX_data_active_object(C);
+ return CTX_data_mode_enum_ex(obedit, obact, obact ? obact->mode : OB_MODE_OBJECT);
}
/* would prefer if we can use the enum version below over this one - Campbell */
/* must be aligned with above enum */
static const char *data_mode_strings[] = {
- "mesh_edit",
- "curve_edit",
- "surface_edit",
- "text_edit",
- "armature_edit",
- "mball_edit",
- "lattice_edit",
- "posemode",
- "sculpt_mode",
- "weightpaint",
- "vertexpaint",
- "imagepaint",
- "particlemode",
- "objectmode",
- "greasepencil_paint",
- "greasepencil_edit",
- "greasepencil_sculpt",
- "greasepencil_weight",
- NULL,
+ "mesh_edit",
+ "curve_edit",
+ "surface_edit",
+ "text_edit",
+ "armature_edit",
+ "mball_edit",
+ "lattice_edit",
+ "posemode",
+ "sculpt_mode",
+ "weightpaint",
+ "vertexpaint",
+ "imagepaint",
+ "particlemode",
+ "objectmode",
+ "greasepencil_paint",
+ "greasepencil_edit",
+ "greasepencil_sculpt",
+ "greasepencil_weight",
+ NULL,
};
-BLI_STATIC_ASSERT(ARRAY_SIZE(data_mode_strings) == CTX_MODE_NUM + 1, "Must have a string for each context mode")
+BLI_STATIC_ASSERT(ARRAY_SIZE(data_mode_strings) == CTX_MODE_NUM + 1,
+ "Must have a string for each context mode")
const char *CTX_data_mode_string(const bContext *C)
{
- return data_mode_strings[CTX_data_mode_enum(C)];
+ return data_mode_strings[CTX_data_mode_enum(C)];
}
void CTX_data_scene_set(bContext *C, Scene *scene)
{
- C->data.scene = scene;
+ C->data.scene = scene;
}
ToolSettings *CTX_data_tool_settings(const bContext *C)
{
- Scene *scene = CTX_data_scene(C);
+ Scene *scene = CTX_data_scene(C);
- if (scene)
- return scene->toolsettings;
- else
- return NULL;
+ if (scene)
+ return scene->toolsettings;
+ else
+ return NULL;
}
int CTX_data_selected_nodes(const bContext *C, ListBase *list)
{
- return ctx_data_collection_get(C, "selected_nodes", list);
+ return ctx_data_collection_get(C, "selected_nodes", list);
}
int CTX_data_selected_editable_objects(const bContext *C, ListBase *list)
{
- return ctx_data_collection_get(C, "selected_editable_objects", list);
+ return ctx_data_collection_get(C, "selected_editable_objects", list);
}
int CTX_data_selected_editable_bases(const bContext *C, ListBase *list)
{
- return ctx_data_collection_get(C, "selected_editable_bases", list);
+ return ctx_data_collection_get(C, "selected_editable_bases", list);
}
int CTX_data_editable_objects(const bContext *C, ListBase *list)
{
- return ctx_data_collection_get(C, "editable_objects", list);
+ return ctx_data_collection_get(C, "editable_objects", list);
}
int CTX_data_editable_bases(const bContext *C, ListBase *list)
{
- return ctx_data_collection_get(C, "editable_bases", list);
+ return ctx_data_collection_get(C, "editable_bases", list);
}
int CTX_data_selected_objects(const bContext *C, ListBase *list)
{
- return ctx_data_collection_get(C, "selected_objects", list);
+ return ctx_data_collection_get(C, "selected_objects", list);
}
int CTX_data_selected_bases(const bContext *C, ListBase *list)
{
- return ctx_data_collection_get(C, "selected_bases", list);
+ return ctx_data_collection_get(C, "selected_bases", list);
}
int CTX_data_visible_objects(const bContext *C, ListBase *list)
{
- return ctx_data_collection_get(C, "visible_objects", list);
+ return ctx_data_collection_get(C, "visible_objects", list);
}
int CTX_data_visible_bases(const bContext *C, ListBase *list)
{
- return ctx_data_collection_get(C, "visible_bases", list);
+ return ctx_data_collection_get(C, "visible_bases", list);
}
int CTX_data_selectable_objects(const bContext *C, ListBase *list)
{
- return ctx_data_collection_get(C, "selectable_objects", list);
+ return ctx_data_collection_get(C, "selectable_objects", list);
}
int CTX_data_selectable_bases(const bContext *C, ListBase *list)
{
- return ctx_data_collection_get(C, "selectable_bases", list);
+ return ctx_data_collection_get(C, "selectable_bases", list);
}
struct Object *CTX_data_active_object(const bContext *C)
{
- return ctx_data_pointer_get(C, "active_object");
+ return ctx_data_pointer_get(C, "active_object");
}
struct Base *CTX_data_active_base(const bContext *C)
{
- return ctx_data_pointer_get(C, "active_base");
+ return ctx_data_pointer_get(C, "active_base");
}
struct Object *CTX_data_edit_object(const bContext *C)
{
- return ctx_data_pointer_get(C, "edit_object");
+ return ctx_data_pointer_get(C, "edit_object");
}
struct Image *CTX_data_edit_image(const bContext *C)
{
- return ctx_data_pointer_get(C, "edit_image");
+ return ctx_data_pointer_get(C, "edit_image");
}
struct Text *CTX_data_edit_text(const bContext *C)
{
- return ctx_data_pointer_get(C, "edit_text");
+ return ctx_data_pointer_get(C, "edit_text");
}
struct MovieClip *CTX_data_edit_movieclip(const bContext *C)
{
- return ctx_data_pointer_get(C, "edit_movieclip");
+ return ctx_data_pointer_get(C, "edit_movieclip");
}
struct Mask *CTX_data_edit_mask(const bContext *C)
{
- return ctx_data_pointer_get(C, "edit_mask");
+ return ctx_data_pointer_get(C, "edit_mask");
}
struct EditBone *CTX_data_active_bone(const bContext *C)
{
- return ctx_data_pointer_get(C, "active_bone");
+ return ctx_data_pointer_get(C, "active_bone");
}
struct CacheFile *CTX_data_edit_cachefile(const bContext *C)
{
- return ctx_data_pointer_get(C, "edit_cachefile");
+ return ctx_data_pointer_get(C, "edit_cachefile");
}
int CTX_data_selected_bones(const bContext *C, ListBase *list)
{
- return ctx_data_collection_get(C, "selected_bones", list);
+ return ctx_data_collection_get(C, "selected_bones", list);
}
int CTX_data_selected_editable_bones(const bContext *C, ListBase *list)
{
- return ctx_data_collection_get(C, "selected_editable_bones", list);
+ return ctx_data_collection_get(C, "selected_editable_bones", list);
}
int CTX_data_visible_bones(const bContext *C, ListBase *list)
{
- return ctx_data_collection_get(C, "visible_bones", list);
+ return ctx_data_collection_get(C, "visible_bones", list);
}
int CTX_data_editable_bones(const bContext *C, ListBase *list)
{
- return ctx_data_collection_get(C, "editable_bones", list);
+ return ctx_data_collection_get(C, "editable_bones", list);
}
struct bPoseChannel *CTX_data_active_pose_bone(const bContext *C)
{
- return ctx_data_pointer_get(C, "active_pose_bone");
+ return ctx_data_pointer_get(C, "active_pose_bone");
}
int CTX_data_selected_pose_bones(const bContext *C, ListBase *list)
{
- return ctx_data_collection_get(C, "selected_pose_bones", list);
+ return ctx_data_collection_get(C, "selected_pose_bones", list);
}
int CTX_data_selected_pose_bones_from_active_object(const bContext *C, ListBase *list)
{
- return ctx_data_collection_get(C, "selected_pose_bones_from_active_object", list);
+ return ctx_data_collection_get(C, "selected_pose_bones_from_active_object", list);
}
int CTX_data_visible_pose_bones(const bContext *C, ListBase *list)
{
- return ctx_data_collection_get(C, "visible_pose_bones", list);
+ return ctx_data_collection_get(C, "visible_pose_bones", list);
}
bGPdata *CTX_data_gpencil_data(const bContext *C)
{
- return ctx_data_pointer_get(C, "gpencil_data");
+ return ctx_data_pointer_get(C, "gpencil_data");
}
bGPDlayer *CTX_data_active_gpencil_layer(const bContext *C)
{
- return ctx_data_pointer_get(C, "active_gpencil_layer");
+ return ctx_data_pointer_get(C, "active_gpencil_layer");
}
bGPDframe *CTX_data_active_gpencil_frame(const bContext *C)
{
- return ctx_data_pointer_get(C, "active_gpencil_frame");
+ return ctx_data_pointer_get(C, "active_gpencil_frame");
}
int CTX_data_visible_gpencil_layers(const bContext *C, ListBase *list)
{
- return ctx_data_collection_get(C, "visible_gpencil_layers", list);
+ return ctx_data_collection_get(C, "visible_gpencil_layers", list);
}
int CTX_data_editable_gpencil_layers(const bContext *C, ListBase *list)
{
- return ctx_data_collection_get(C, "editable_gpencil_layers", list);
+ return ctx_data_collection_get(C, "editable_gpencil_layers", list);
}
int CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list)
{
- return ctx_data_collection_get(C, "editable_gpencil_strokes", list);
+ return ctx_data_collection_get(C, "editable_gpencil_strokes", list);
}
Depsgraph *CTX_data_depsgraph(const bContext *C)
{
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- return BKE_scene_get_depsgraph(scene, view_layer, true);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ return BKE_scene_get_depsgraph(scene, view_layer, true);
}
Depsgraph *CTX_data_depsgraph_on_load(const bContext *C)
{
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- return BKE_scene_get_depsgraph(scene, view_layer, false);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ return BKE_scene_get_depsgraph(scene, view_layer, false);
}
diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c
index 4aa3b702693..465a9980579 100644
--- a/source/blender/blenkernel/intern/crazyspace.c
+++ b/source/blender/blenkernel/intern/crazyspace.c
@@ -21,7 +21,6 @@
* \ingroup bke
*/
-
#include "MEM_guardedalloc.h"
#include "DNA_scene_types.h"
@@ -44,265 +43,277 @@
#include "DEG_depsgraph_query.h"
-BLI_INLINE void tan_calc_quat_v3(
- float r_quat[4],
- const float co_1[3], const float co_2[3], const float co_3[3])
+BLI_INLINE void tan_calc_quat_v3(float r_quat[4],
+ const float co_1[3],
+ const float co_2[3],
+ const float co_3[3])
{
- float vec_u[3], vec_v[3];
- float nor[3];
+ float vec_u[3], vec_v[3];
+ float nor[3];
- sub_v3_v3v3(vec_u, co_1, co_2);
- sub_v3_v3v3(vec_v, co_1, co_3);
+ sub_v3_v3v3(vec_u, co_1, co_2);
+ sub_v3_v3v3(vec_v, co_1, co_3);
- cross_v3_v3v3(nor, vec_u, vec_v);
+ cross_v3_v3v3(nor, vec_u, vec_v);
- if (normalize_v3(nor) > FLT_EPSILON) {
- const float zero_vec[3] = {0.0f};
- tri_to_quat_ex(r_quat, zero_vec, vec_u, vec_v, nor);
- }
- else {
- unit_qt(r_quat);
- }
+ if (normalize_v3(nor) > FLT_EPSILON) {
+ const float zero_vec[3] = {0.0f};
+ tri_to_quat_ex(r_quat, zero_vec, vec_u, vec_v, nor);
+ }
+ else {
+ unit_qt(r_quat);
+ }
}
-static void set_crazy_vertex_quat(
- float r_quat[4],
- const float co_1[3], const float co_2[3], const float co_3[3],
- const float vd_1[3], const float vd_2[3], const float vd_3[3])
+static void set_crazy_vertex_quat(float r_quat[4],
+ const float co_1[3],
+ const float co_2[3],
+ const float co_3[3],
+ const float vd_1[3],
+ const float vd_2[3],
+ const float vd_3[3])
{
- float q1[4], q2[4];
+ float q1[4], q2[4];
- tan_calc_quat_v3(q1, co_1, co_2, co_3);
- tan_calc_quat_v3(q2, vd_1, vd_2, vd_3);
+ tan_calc_quat_v3(q1, co_1, co_2, co_3);
+ tan_calc_quat_v3(q2, vd_1, vd_2, vd_3);
- sub_qt_qtqt(r_quat, q2, q1);
+ sub_qt_qtqt(r_quat, q2, q1);
}
static int modifiers_disable_subsurf_temporary(Object *ob)
{
- ModifierData *md;
- int disabled = 0;
+ ModifierData *md;
+ int disabled = 0;
- for (md = ob->modifiers.first; md; md = md->next)
- if (md->type == eModifierType_Subsurf)
- if (md->mode & eModifierMode_OnCage) {
- md->mode ^= eModifierMode_DisableTemporary;
- disabled = 1;
- }
+ for (md = ob->modifiers.first; md; md = md->next)
+ if (md->type == eModifierType_Subsurf)
+ if (md->mode & eModifierMode_OnCage) {
+ md->mode ^= eModifierMode_DisableTemporary;
+ disabled = 1;
+ }
- return disabled;
+ return disabled;
}
/* disable subsurf temporal, get mapped cos, and enable it */
-float (*BKE_crazyspace_get_mapped_editverts(
- struct Depsgraph *depsgraph, Scene *scene, Object *obedit))[3]
+float (*BKE_crazyspace_get_mapped_editverts(struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *obedit))[3]
{
- Mesh *me = obedit->data;
- Mesh *me_eval;
- float (*vertexcos)[3];
- int nverts = me->edit_mesh->bm->totvert;
+ Mesh *me = obedit->data;
+ Mesh *me_eval;
+ float(*vertexcos)[3];
+ int nverts = me->edit_mesh->bm->totvert;
- /* disable subsurf temporal, get mapped cos, and enable it */
- if (modifiers_disable_subsurf_temporary(obedit)) {
- /* need to make new derivemesh */
- makeDerivedMesh(depsgraph, scene, obedit, me->edit_mesh, &CD_MASK_BAREMESH);
- }
+ /* disable subsurf temporal, get mapped cos, and enable it */
+ if (modifiers_disable_subsurf_temporary(obedit)) {
+ /* need to make new derivemesh */
+ makeDerivedMesh(depsgraph, scene, obedit, me->edit_mesh, &CD_MASK_BAREMESH);
+ }
- /* now get the cage */
- vertexcos = MEM_mallocN(sizeof(*vertexcos) * nverts, "vertexcos map");
+ /* now get the cage */
+ vertexcos = MEM_mallocN(sizeof(*vertexcos) * nverts, "vertexcos map");
- me_eval = editbmesh_get_eval_cage_from_orig(depsgraph, scene, obedit, me->edit_mesh, &CD_MASK_BAREMESH);
+ me_eval = editbmesh_get_eval_cage_from_orig(
+ depsgraph, scene, obedit, me->edit_mesh, &CD_MASK_BAREMESH);
- mesh_get_mapped_verts_coords(me_eval, vertexcos, nverts);
+ mesh_get_mapped_verts_coords(me_eval, vertexcos, nverts);
- /* set back the flag, no new cage needs to be built, transform does it */
- modifiers_disable_subsurf_temporary(obedit);
+ /* set back the flag, no new cage needs to be built, transform does it */
+ modifiers_disable_subsurf_temporary(obedit);
- return vertexcos;
+ return vertexcos;
}
-void BKE_crazyspace_set_quats_editmesh(BMEditMesh *em, float (*origcos)[3], float (*mappedcos)[3], float (*quats)[4],
- const bool use_select)
+void BKE_crazyspace_set_quats_editmesh(BMEditMesh *em,
+ float (*origcos)[3],
+ float (*mappedcos)[3],
+ float (*quats)[4],
+ const bool use_select)
{
- BMFace *f;
- BMIter iter;
- int index;
-
- {
- BMVert *v;
- BM_ITER_MESH_INDEX (v, &iter, em->bm, BM_VERTS_OF_MESH, index) {
- BM_elem_flag_disable(v, BM_ELEM_TAG);
- BM_elem_index_set(v, index); /* set_inline */
- }
- em->bm->elem_index_dirty &= ~BM_VERT;
- }
-
- BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
- BMLoop *l_iter, *l_first;
-
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- if (BM_elem_flag_test(l_iter->v, BM_ELEM_HIDDEN) ||
- BM_elem_flag_test(l_iter->v, BM_ELEM_TAG) ||
- (use_select && !BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)))
- {
- continue;
- }
-
- if (!BM_elem_flag_test(l_iter->v, BM_ELEM_TAG)) {
- const float *co_prev, *co_curr, *co_next; /* orig */
- const float *vd_prev, *vd_curr, *vd_next; /* deform */
-
- const int i_prev = BM_elem_index_get(l_iter->prev->v);
- const int i_curr = BM_elem_index_get(l_iter->v);
- const int i_next = BM_elem_index_get(l_iter->next->v);
-
- /* retrieve mapped coordinates */
- vd_prev = mappedcos[i_prev];
- vd_curr = mappedcos[i_curr];
- vd_next = mappedcos[i_next];
-
- if (origcos) {
- co_prev = origcos[i_prev];
- co_curr = origcos[i_curr];
- co_next = origcos[i_next];
- }
- else {
- co_prev = l_iter->prev->v->co;
- co_curr = l_iter->v->co;
- co_next = l_iter->next->v->co;
- }
-
- set_crazy_vertex_quat(quats[i_curr],
- co_curr, co_next, co_prev,
- vd_curr, vd_next, vd_prev);
-
- BM_elem_flag_enable(l_iter->v, BM_ELEM_TAG);
- }
- } while ((l_iter = l_iter->next) != l_first);
- }
+ BMFace *f;
+ BMIter iter;
+ int index;
+
+ {
+ BMVert *v;
+ BM_ITER_MESH_INDEX (v, &iter, em->bm, BM_VERTS_OF_MESH, index) {
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
+ BM_elem_index_set(v, index); /* set_inline */
+ }
+ em->bm->elem_index_dirty &= ~BM_VERT;
+ }
+
+ BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
+ BMLoop *l_iter, *l_first;
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if (BM_elem_flag_test(l_iter->v, BM_ELEM_HIDDEN) ||
+ BM_elem_flag_test(l_iter->v, BM_ELEM_TAG) ||
+ (use_select && !BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT))) {
+ continue;
+ }
+
+ if (!BM_elem_flag_test(l_iter->v, BM_ELEM_TAG)) {
+ const float *co_prev, *co_curr, *co_next; /* orig */
+ const float *vd_prev, *vd_curr, *vd_next; /* deform */
+
+ const int i_prev = BM_elem_index_get(l_iter->prev->v);
+ const int i_curr = BM_elem_index_get(l_iter->v);
+ const int i_next = BM_elem_index_get(l_iter->next->v);
+
+ /* retrieve mapped coordinates */
+ vd_prev = mappedcos[i_prev];
+ vd_curr = mappedcos[i_curr];
+ vd_next = mappedcos[i_next];
+
+ if (origcos) {
+ co_prev = origcos[i_prev];
+ co_curr = origcos[i_curr];
+ co_next = origcos[i_next];
+ }
+ else {
+ co_prev = l_iter->prev->v->co;
+ co_curr = l_iter->v->co;
+ co_next = l_iter->next->v->co;
+ }
+
+ set_crazy_vertex_quat(quats[i_curr], co_curr, co_next, co_prev, vd_curr, vd_next, vd_prev);
+
+ BM_elem_flag_enable(l_iter->v, BM_ELEM_TAG);
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
}
-void BKE_crazyspace_set_quats_mesh(Mesh *me, float (*origcos)[3], float (*mappedcos)[3], float (*quats)[4])
+void BKE_crazyspace_set_quats_mesh(Mesh *me,
+ float (*origcos)[3],
+ float (*mappedcos)[3],
+ float (*quats)[4])
{
- int i;
- MVert *mvert;
- MLoop *mloop;
- MPoly *mp;
-
- mvert = me->mvert;
- for (i = 0; i < me->totvert; i++, mvert++)
- mvert->flag &= ~ME_VERT_TMP_TAG;
-
- /* first store two sets of tangent vectors in vertices, we derive it just from the face-edges */
- mvert = me->mvert;
- mp = me->mpoly;
- mloop = me->mloop;
-
- for (i = 0; i < me->totpoly; i++, mp++) {
- MLoop *ml_prev, *ml_curr, *ml_next;
- int j;
-
- ml_next = &mloop[mp->loopstart];
- ml_curr = &ml_next[mp->totloop - 1];
- ml_prev = &ml_next[mp->totloop - 2];
-
- for (j = 0; j < mp->totloop; j++) {
- if ((mvert[ml_curr->v].flag & ME_VERT_TMP_TAG) == 0) {
- const float *co_prev, *co_curr, *co_next; /* orig */
- const float *vd_prev, *vd_curr, *vd_next; /* deform */
-
- /* retrieve mapped coordinates */
- vd_prev = mappedcos[ml_prev->v];
- vd_curr = mappedcos[ml_curr->v];
- vd_next = mappedcos[ml_next->v];
-
- if (origcos) {
- co_prev = origcos[ml_prev->v];
- co_curr = origcos[ml_curr->v];
- co_next = origcos[ml_next->v];
- }
- else {
- co_prev = mvert[ml_prev->v].co;
- co_curr = mvert[ml_curr->v].co;
- co_next = mvert[ml_next->v].co;
- }
-
- set_crazy_vertex_quat(quats[ml_curr->v],
- co_curr, co_next, co_prev,
- vd_curr, vd_next, vd_prev);
-
- mvert[ml_curr->v].flag |= ME_VERT_TMP_TAG;
- }
-
- ml_prev = ml_curr;
- ml_curr = ml_next;
- ml_next++;
- }
- }
+ int i;
+ MVert *mvert;
+ MLoop *mloop;
+ MPoly *mp;
+
+ mvert = me->mvert;
+ for (i = 0; i < me->totvert; i++, mvert++)
+ mvert->flag &= ~ME_VERT_TMP_TAG;
+
+ /* first store two sets of tangent vectors in vertices, we derive it just from the face-edges */
+ mvert = me->mvert;
+ mp = me->mpoly;
+ mloop = me->mloop;
+
+ for (i = 0; i < me->totpoly; i++, mp++) {
+ MLoop *ml_prev, *ml_curr, *ml_next;
+ int j;
+
+ ml_next = &mloop[mp->loopstart];
+ ml_curr = &ml_next[mp->totloop - 1];
+ ml_prev = &ml_next[mp->totloop - 2];
+
+ for (j = 0; j < mp->totloop; j++) {
+ if ((mvert[ml_curr->v].flag & ME_VERT_TMP_TAG) == 0) {
+ const float *co_prev, *co_curr, *co_next; /* orig */
+ const float *vd_prev, *vd_curr, *vd_next; /* deform */
+
+ /* retrieve mapped coordinates */
+ vd_prev = mappedcos[ml_prev->v];
+ vd_curr = mappedcos[ml_curr->v];
+ vd_next = mappedcos[ml_next->v];
+
+ if (origcos) {
+ co_prev = origcos[ml_prev->v];
+ co_curr = origcos[ml_curr->v];
+ co_next = origcos[ml_next->v];
+ }
+ else {
+ co_prev = mvert[ml_prev->v].co;
+ co_curr = mvert[ml_curr->v].co;
+ co_next = mvert[ml_next->v].co;
+ }
+
+ set_crazy_vertex_quat(
+ quats[ml_curr->v], co_curr, co_next, co_prev, vd_curr, vd_next, vd_prev);
+
+ mvert[ml_curr->v].flag |= ME_VERT_TMP_TAG;
+ }
+
+ ml_prev = ml_curr;
+ ml_curr = ml_next;
+ ml_next++;
+ }
+ }
}
/** returns an array of deform matrices for crazyspace correction, and the
* number of modifiers left */
-int BKE_crazyspace_get_first_deform_matrices_editbmesh(
- struct Depsgraph *depsgraph, Scene *scene, Object *ob, BMEditMesh *em,
- float (**deformmats)[3][3], float (**deformcos)[3])
+int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ BMEditMesh *em,
+ float (**deformmats)[3][3],
+ float (**deformcos)[3])
{
- ModifierData *md;
- Mesh *me;
- int i, a, numleft = 0, numVerts = 0;
- int cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1);
- float (*defmats)[3][3] = NULL, (*deformedVerts)[3] = NULL;
- VirtualModifierData virtualModifierData;
- ModifierEvalContext mectx = {depsgraph, ob, 0};
-
- modifiers_clearErrors(ob);
-
- me = NULL;
- md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
-
- /* compute the deformation matrices and coordinates for the first
- * modifiers with on cage editing that are enabled and support computing
- * deform matrices */
- for (i = 0; md && i <= cageIndex; i++, md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
-
- if (!editbmesh_modifier_is_enabled(scene, md, me != NULL))
- continue;
-
- if (mti->type == eModifierTypeType_OnlyDeform && mti->deformMatricesEM) {
- if (!defmats) {
- const int required_mode = eModifierMode_Realtime | eModifierMode_Editmode;
- CustomData_MeshMasks data_mask = CD_MASK_BAREMESH;
- CDMaskLink *datamasks = modifiers_calcDataMasks(scene, ob, md, &data_mask, required_mode, NULL, NULL);
- data_mask = datamasks->mask;
- BLI_linklist_free((LinkNode *)datamasks, NULL);
-
- me = BKE_mesh_from_editmesh_with_coords_thin_wrap(em, &data_mask, NULL);
- deformedVerts = editbmesh_get_vertex_cos(em, &numVerts);
- defmats = MEM_mallocN(sizeof(*defmats) * numVerts, "defmats");
-
- for (a = 0; a < numVerts; a++)
- unit_m3(defmats[a]);
- }
- mti->deformMatricesEM(md, &mectx, em, me, deformedVerts, defmats, numVerts);
- }
- else
- break;
- }
-
- for (; md && i <= cageIndex; md = md->next, i++)
- if (editbmesh_modifier_is_enabled(scene, md, me != NULL) && modifier_isCorrectableDeformed(md))
- numleft++;
-
- if (me) {
- BKE_id_free(NULL, me);
- }
-
- *deformmats = defmats;
- *deformcos = deformedVerts;
-
- return numleft;
+ ModifierData *md;
+ Mesh *me;
+ int i, a, numleft = 0, numVerts = 0;
+ int cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1);
+ float(*defmats)[3][3] = NULL, (*deformedVerts)[3] = NULL;
+ VirtualModifierData virtualModifierData;
+ ModifierEvalContext mectx = {depsgraph, ob, 0};
+
+ modifiers_clearErrors(ob);
+
+ me = NULL;
+ md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+
+ /* compute the deformation matrices and coordinates for the first
+ * modifiers with on cage editing that are enabled and support computing
+ * deform matrices */
+ for (i = 0; md && i <= cageIndex; i++, md = md->next) {
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if (!editbmesh_modifier_is_enabled(scene, md, me != NULL))
+ continue;
+
+ if (mti->type == eModifierTypeType_OnlyDeform && mti->deformMatricesEM) {
+ if (!defmats) {
+ const int required_mode = eModifierMode_Realtime | eModifierMode_Editmode;
+ CustomData_MeshMasks data_mask = CD_MASK_BAREMESH;
+ CDMaskLink *datamasks = modifiers_calcDataMasks(
+ scene, ob, md, &data_mask, required_mode, NULL, NULL);
+ data_mask = datamasks->mask;
+ BLI_linklist_free((LinkNode *)datamasks, NULL);
+
+ me = BKE_mesh_from_editmesh_with_coords_thin_wrap(em, &data_mask, NULL);
+ deformedVerts = editbmesh_get_vertex_cos(em, &numVerts);
+ defmats = MEM_mallocN(sizeof(*defmats) * numVerts, "defmats");
+
+ for (a = 0; a < numVerts; a++)
+ unit_m3(defmats[a]);
+ }
+ mti->deformMatricesEM(md, &mectx, em, me, deformedVerts, defmats, numVerts);
+ }
+ else
+ break;
+ }
+
+ for (; md && i <= cageIndex; md = md->next, i++)
+ if (editbmesh_modifier_is_enabled(scene, md, me != NULL) && modifier_isCorrectableDeformed(md))
+ numleft++;
+
+ if (me) {
+ BKE_id_free(NULL, me);
+ }
+
+ *deformmats = defmats;
+ *deformcos = deformedVerts;
+
+ return numleft;
}
/**
@@ -312,149 +323,157 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(
*
* Similar to #BKE_object_eval_reset(), but does not modify the actual evaluated object.
*/
-static void crazyspace_init_object_for_eval(
- struct Depsgraph *depsgraph,
- Object *object,
- Object *object_crazy)
+static void crazyspace_init_object_for_eval(struct Depsgraph *depsgraph,
+ Object *object,
+ Object *object_crazy)
{
- Object *object_eval = DEG_get_evaluated_object(depsgraph, object);
- *object_crazy = *object_eval;
- if (object_crazy->runtime.mesh_orig != NULL) {
- object_crazy->data = object_crazy->runtime.mesh_orig;
- }
+ Object *object_eval = DEG_get_evaluated_object(depsgraph, object);
+ *object_crazy = *object_eval;
+ if (object_crazy->runtime.mesh_orig != NULL) {
+ object_crazy->data = object_crazy->runtime.mesh_orig;
+ }
}
-int BKE_sculpt_get_first_deform_matrices(
- struct Depsgraph *depsgraph, Scene *scene,
- Object *object, float (**deformmats)[3][3], float (**deformcos)[3])
+int BKE_sculpt_get_first_deform_matrices(struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *object,
+ float (**deformmats)[3][3],
+ float (**deformcos)[3])
{
- ModifierData *md;
- Mesh *me_eval;
- int a, numVerts = 0;
- float (*defmats)[3][3] = NULL, (*deformedVerts)[3] = NULL;
- int numleft = 0;
- VirtualModifierData virtualModifierData;
- Object object_eval;
- crazyspace_init_object_for_eval(depsgraph, object, &object_eval);
- MultiresModifierData *mmd = get_multires_modifier(scene, &object_eval, 0);
- const bool has_multires = mmd != NULL && mmd->sculptlvl > 0;
- const ModifierEvalContext mectx = {depsgraph, &object_eval, 0};
-
- if (has_multires) {
- *deformmats = NULL;
- *deformcos = NULL;
- return numleft;
- }
-
- me_eval = NULL;
-
- md = modifiers_getVirtualModifierList(&object_eval, &virtualModifierData);
-
- for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
-
- if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue;
-
- if (mti->type == eModifierTypeType_OnlyDeform) {
- if (!defmats) {
- /* NOTE: Evaluated object si re-set to its original undeformed
- * state. */
- Mesh *me = object_eval.data;
- me_eval = BKE_mesh_copy_for_eval(me, true);
- deformedVerts = BKE_mesh_vertexCos_get(me, &numVerts);
- defmats = MEM_callocN(sizeof(*defmats) * numVerts, "defmats");
-
- for (a = 0; a < numVerts; a++)
- unit_m3(defmats[a]);
- }
-
- if (mti->deformMatrices) {
- mti->deformMatrices(md, &mectx, me_eval, deformedVerts, defmats, numVerts);
- }
- else break;
- }
- }
-
- for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
-
- if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue;
-
- if (mti->type == eModifierTypeType_OnlyDeform)
- numleft++;
- }
-
- if (me_eval) {
- BKE_id_free(NULL, me_eval);
- }
-
- *deformmats = defmats;
- *deformcos = deformedVerts;
-
- return numleft;
+ ModifierData *md;
+ Mesh *me_eval;
+ int a, numVerts = 0;
+ float(*defmats)[3][3] = NULL, (*deformedVerts)[3] = NULL;
+ int numleft = 0;
+ VirtualModifierData virtualModifierData;
+ Object object_eval;
+ crazyspace_init_object_for_eval(depsgraph, object, &object_eval);
+ MultiresModifierData *mmd = get_multires_modifier(scene, &object_eval, 0);
+ const bool has_multires = mmd != NULL && mmd->sculptlvl > 0;
+ const ModifierEvalContext mectx = {depsgraph, &object_eval, 0};
+
+ if (has_multires) {
+ *deformmats = NULL;
+ *deformcos = NULL;
+ return numleft;
+ }
+
+ me_eval = NULL;
+
+ md = modifiers_getVirtualModifierList(&object_eval, &virtualModifierData);
+
+ for (; md; md = md->next) {
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if (!modifier_isEnabled(scene, md, eModifierMode_Realtime))
+ continue;
+
+ if (mti->type == eModifierTypeType_OnlyDeform) {
+ if (!defmats) {
+ /* NOTE: Evaluated object si re-set to its original undeformed
+ * state. */
+ Mesh *me = object_eval.data;
+ me_eval = BKE_mesh_copy_for_eval(me, true);
+ deformedVerts = BKE_mesh_vertexCos_get(me, &numVerts);
+ defmats = MEM_callocN(sizeof(*defmats) * numVerts, "defmats");
+
+ for (a = 0; a < numVerts; a++)
+ unit_m3(defmats[a]);
+ }
+
+ if (mti->deformMatrices) {
+ mti->deformMatrices(md, &mectx, me_eval, deformedVerts, defmats, numVerts);
+ }
+ else
+ break;
+ }
+ }
+
+ for (; md; md = md->next) {
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if (!modifier_isEnabled(scene, md, eModifierMode_Realtime))
+ continue;
+
+ if (mti->type == eModifierTypeType_OnlyDeform)
+ numleft++;
+ }
+
+ if (me_eval) {
+ BKE_id_free(NULL, me_eval);
+ }
+
+ *deformmats = defmats;
+ *deformcos = deformedVerts;
+
+ return numleft;
}
-void BKE_crazyspace_build_sculpt(
- struct Depsgraph *depsgraph, Scene *scene, Object *object,
- float (**deformmats)[3][3], float (**deformcos)[3])
+void BKE_crazyspace_build_sculpt(struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *object,
+ float (**deformmats)[3][3],
+ float (**deformcos)[3])
{
- int totleft = BKE_sculpt_get_first_deform_matrices(depsgraph, scene, object, deformmats, deformcos);
-
- if (totleft) {
- /* there are deformation modifier which doesn't support deformation matrices
- * calculation. Need additional crazyspace correction */
-
- float (*deformedVerts)[3] = *deformcos;
- float (*origVerts)[3] = MEM_dupallocN(deformedVerts);
- float (*quats)[4];
- int i, deformed = 0;
- VirtualModifierData virtualModifierData;
- Object object_eval;
- crazyspace_init_object_for_eval(depsgraph, object, &object_eval);
- ModifierData *md = modifiers_getVirtualModifierList(&object_eval, &virtualModifierData);
- const ModifierEvalContext mectx = {depsgraph, &object_eval, 0};
- Mesh *mesh = (Mesh *)object->data;
-
- for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
-
- if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue;
-
- if (mti->type == eModifierTypeType_OnlyDeform) {
- /* skip leading modifiers which have been already
- * handled in sculpt_get_first_deform_matrices */
- if (mti->deformMatrices && !deformed)
- continue;
-
- mti->deformVerts(md, &mectx, NULL, deformedVerts, mesh->totvert);
- deformed = 1;
- }
- }
-
- quats = MEM_mallocN(mesh->totvert * sizeof(*quats), "crazy quats");
-
- BKE_crazyspace_set_quats_mesh(mesh, origVerts, deformedVerts, quats);
-
- for (i = 0; i < mesh->totvert; i++) {
- float qmat[3][3], tmat[3][3];
-
- quat_to_mat3(qmat, quats[i]);
- mul_m3_m3m3(tmat, qmat, (*deformmats)[i]);
- copy_m3_m3((*deformmats)[i], tmat);
- }
-
- MEM_freeN(origVerts);
- MEM_freeN(quats);
- }
-
- if (*deformmats == NULL) {
- int a, numVerts;
- Mesh *mesh = (Mesh *)object->data;
-
- *deformcos = BKE_mesh_vertexCos_get(mesh, &numVerts);
- *deformmats = MEM_callocN(sizeof(*(*deformmats)) * numVerts, "defmats");
-
- for (a = 0; a < numVerts; a++)
- unit_m3((*deformmats)[a]);
- }
+ int totleft = BKE_sculpt_get_first_deform_matrices(
+ depsgraph, scene, object, deformmats, deformcos);
+
+ if (totleft) {
+ /* there are deformation modifier which doesn't support deformation matrices
+ * calculation. Need additional crazyspace correction */
+
+ float(*deformedVerts)[3] = *deformcos;
+ float(*origVerts)[3] = MEM_dupallocN(deformedVerts);
+ float(*quats)[4];
+ int i, deformed = 0;
+ VirtualModifierData virtualModifierData;
+ Object object_eval;
+ crazyspace_init_object_for_eval(depsgraph, object, &object_eval);
+ ModifierData *md = modifiers_getVirtualModifierList(&object_eval, &virtualModifierData);
+ const ModifierEvalContext mectx = {depsgraph, &object_eval, 0};
+ Mesh *mesh = (Mesh *)object->data;
+
+ for (; md; md = md->next) {
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if (!modifier_isEnabled(scene, md, eModifierMode_Realtime))
+ continue;
+
+ if (mti->type == eModifierTypeType_OnlyDeform) {
+ /* skip leading modifiers which have been already
+ * handled in sculpt_get_first_deform_matrices */
+ if (mti->deformMatrices && !deformed)
+ continue;
+
+ mti->deformVerts(md, &mectx, NULL, deformedVerts, mesh->totvert);
+ deformed = 1;
+ }
+ }
+
+ quats = MEM_mallocN(mesh->totvert * sizeof(*quats), "crazy quats");
+
+ BKE_crazyspace_set_quats_mesh(mesh, origVerts, deformedVerts, quats);
+
+ for (i = 0; i < mesh->totvert; i++) {
+ float qmat[3][3], tmat[3][3];
+
+ quat_to_mat3(qmat, quats[i]);
+ mul_m3_m3m3(tmat, qmat, (*deformmats)[i]);
+ copy_m3_m3((*deformmats)[i], tmat);
+ }
+
+ MEM_freeN(origVerts);
+ MEM_freeN(quats);
+ }
+
+ if (*deformmats == NULL) {
+ int a, numVerts;
+ Mesh *mesh = (Mesh *)object->data;
+
+ *deformcos = BKE_mesh_vertexCos_get(mesh, &numVerts);
+ *deformmats = MEM_callocN(sizeof(*(*deformmats)) * numVerts, "defmats");
+
+ for (a = 0; a < numVerts; a++)
+ unit_m3((*deformmats)[a]);
+ }
}
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index 0ab5a6ca963..f28e14be512 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -21,7 +21,6 @@
* \ingroup bke
*/
-
#include <math.h> // floor
#include <string.h>
#include <stdlib.h>
@@ -63,128 +62,134 @@
/* local */
static CLG_LogRef LOG = {"bke.curve"};
-static int cu_isectLL(const float v1[3], const float v2[3], const float v3[3], const float v4[3],
- short cox, short coy,
- float *lambda, float *mu, float vec[3]);
+static int cu_isectLL(const float v1[3],
+ const float v2[3],
+ const float v3[3],
+ const float v4[3],
+ short cox,
+ short coy,
+ float *lambda,
+ float *mu,
+ float vec[3]);
/* frees editcurve entirely */
void BKE_curve_editfont_free(Curve *cu)
{
- if (cu->editfont) {
- EditFont *ef = cu->editfont;
+ if (cu->editfont) {
+ EditFont *ef = cu->editfont;
- if (ef->textbuf)
- MEM_freeN(ef->textbuf);
- if (ef->textbufinfo)
- MEM_freeN(ef->textbufinfo);
- if (ef->selboxes)
- MEM_freeN(ef->selboxes);
+ if (ef->textbuf)
+ MEM_freeN(ef->textbuf);
+ if (ef->textbufinfo)
+ MEM_freeN(ef->textbufinfo);
+ if (ef->selboxes)
+ MEM_freeN(ef->selboxes);
- MEM_freeN(ef);
- cu->editfont = NULL;
- }
+ MEM_freeN(ef);
+ cu->editfont = NULL;
+ }
}
static void curve_editNurb_keyIndex_cv_free_cb(void *val)
{
- CVKeyIndex *index = val;
- MEM_freeN(index->orig_cv);
- MEM_freeN(val);
+ CVKeyIndex *index = val;
+ MEM_freeN(index->orig_cv);
+ MEM_freeN(val);
}
void BKE_curve_editNurb_keyIndex_delCV(GHash *keyindex, const void *cv)
{
- BLI_assert(keyindex != NULL);
- BLI_ghash_remove(keyindex, cv, NULL, curve_editNurb_keyIndex_cv_free_cb);
+ BLI_assert(keyindex != NULL);
+ BLI_ghash_remove(keyindex, cv, NULL, curve_editNurb_keyIndex_cv_free_cb);
}
void BKE_curve_editNurb_keyIndex_free(GHash **keyindex)
{
- if (!(*keyindex)) {
- return;
- }
- BLI_ghash_free(*keyindex, NULL, curve_editNurb_keyIndex_cv_free_cb);
- *keyindex = NULL;
+ if (!(*keyindex)) {
+ return;
+ }
+ BLI_ghash_free(*keyindex, NULL, curve_editNurb_keyIndex_cv_free_cb);
+ *keyindex = NULL;
}
void BKE_curve_editNurb_free(Curve *cu)
{
- if (cu->editnurb) {
- BKE_nurbList_free(&cu->editnurb->nurbs);
- BKE_curve_editNurb_keyIndex_free(&cu->editnurb->keyindex);
- MEM_freeN(cu->editnurb);
- cu->editnurb = NULL;
- }
+ if (cu->editnurb) {
+ BKE_nurbList_free(&cu->editnurb->nurbs);
+ BKE_curve_editNurb_keyIndex_free(&cu->editnurb->keyindex);
+ MEM_freeN(cu->editnurb);
+ cu->editnurb = NULL;
+ }
}
/** Free (or release) any data used by this curve (does not free the curve itself). */
void BKE_curve_free(Curve *cu)
{
- BKE_animdata_free((ID *)cu, false);
+ BKE_animdata_free((ID *)cu, false);
- BKE_curve_batch_cache_free(cu);
+ BKE_curve_batch_cache_free(cu);
- BKE_nurbList_free(&cu->nurb);
- BKE_curve_editfont_free(cu);
+ BKE_nurbList_free(&cu->nurb);
+ BKE_curve_editfont_free(cu);
- BKE_curve_editNurb_free(cu);
+ BKE_curve_editNurb_free(cu);
- MEM_SAFE_FREE(cu->mat);
- MEM_SAFE_FREE(cu->str);
- MEM_SAFE_FREE(cu->strinfo);
- MEM_SAFE_FREE(cu->bb);
- MEM_SAFE_FREE(cu->tb);
+ MEM_SAFE_FREE(cu->mat);
+ MEM_SAFE_FREE(cu->str);
+ MEM_SAFE_FREE(cu->strinfo);
+ MEM_SAFE_FREE(cu->bb);
+ MEM_SAFE_FREE(cu->tb);
}
void BKE_curve_init(Curve *cu)
{
- /* BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(cu, id)); */ /* cu->type is already initialized... */
-
- copy_v3_fl(cu->size, 1.0f);
- cu->flag = CU_DEFORM_BOUNDS_OFF | CU_PATH_RADIUS;
- cu->pathlen = 100;
- cu->resolu = cu->resolv = (cu->type == OB_SURF) ? 4 : 12;
- cu->width = 1.0;
- cu->wordspace = 1.0;
- cu->spacing = cu->linedist = 1.0;
- cu->fsize = 1.0;
- cu->ulheight = 0.05;
- cu->texflag = CU_AUTOSPACE;
- cu->smallcaps_scale = 0.75f;
- /* XXX: this one seems to be the best one in most cases, at least for curve deform... */
- cu->twist_mode = CU_TWIST_MINIMUM;
- cu->bevfac1 = 0.0f;
- cu->bevfac2 = 1.0f;
- cu->bevfac1_mapping = CU_BEVFAC_MAP_RESOLU;
- cu->bevfac2_mapping = CU_BEVFAC_MAP_RESOLU;
- cu->bevresol = 4;
-
- cu->bb = BKE_boundbox_alloc_unit();
-
- if (cu->type == OB_FONT) {
- cu->flag |= CU_FRONT | CU_BACK;
- cu->vfont = cu->vfontb = cu->vfonti = cu->vfontbi = BKE_vfont_builtin_get();
- cu->vfont->id.us += 4;
- cu->str = MEM_malloc_arrayN(12, sizeof(unsigned char), "str");
- BLI_strncpy(cu->str, "Text", 12);
- cu->len = cu->len_wchar = cu->pos = 4;
- cu->strinfo = MEM_calloc_arrayN(12, sizeof(CharInfo), "strinfo new");
- cu->totbox = cu->actbox = 1;
- cu->tb = MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), "textbox");
- cu->tb[0].w = cu->tb[0].h = 0.0;
- }
+ /* BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(cu, id)); */ /* cu->type is already initialized... */
+
+ copy_v3_fl(cu->size, 1.0f);
+ cu->flag = CU_DEFORM_BOUNDS_OFF | CU_PATH_RADIUS;
+ cu->pathlen = 100;
+ cu->resolu = cu->resolv = (cu->type == OB_SURF) ? 4 : 12;
+ cu->width = 1.0;
+ cu->wordspace = 1.0;
+ cu->spacing = cu->linedist = 1.0;
+ cu->fsize = 1.0;
+ cu->ulheight = 0.05;
+ cu->texflag = CU_AUTOSPACE;
+ cu->smallcaps_scale = 0.75f;
+ /* XXX: this one seems to be the best one in most cases, at least for curve deform... */
+ cu->twist_mode = CU_TWIST_MINIMUM;
+ cu->bevfac1 = 0.0f;
+ cu->bevfac2 = 1.0f;
+ cu->bevfac1_mapping = CU_BEVFAC_MAP_RESOLU;
+ cu->bevfac2_mapping = CU_BEVFAC_MAP_RESOLU;
+ cu->bevresol = 4;
+
+ cu->bb = BKE_boundbox_alloc_unit();
+
+ if (cu->type == OB_FONT) {
+ cu->flag |= CU_FRONT | CU_BACK;
+ cu->vfont = cu->vfontb = cu->vfonti = cu->vfontbi = BKE_vfont_builtin_get();
+ cu->vfont->id.us += 4;
+ cu->str = MEM_malloc_arrayN(12, sizeof(unsigned char), "str");
+ BLI_strncpy(cu->str, "Text", 12);
+ cu->len = cu->len_wchar = cu->pos = 4;
+ cu->strinfo = MEM_calloc_arrayN(12, sizeof(CharInfo), "strinfo new");
+ cu->totbox = cu->actbox = 1;
+ cu->tb = MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), "textbox");
+ cu->tb[0].w = cu->tb[0].h = 0.0;
+ }
}
Curve *BKE_curve_add(Main *bmain, const char *name, int type)
{
- Curve *cu;
+ Curve *cu;
- cu = BKE_libblock_alloc(bmain, ID_CU, name, 0);
- cu->type = type;
+ cu = BKE_libblock_alloc(bmain, ID_CU, name, 0);
+ cu->type = type;
- BKE_curve_init(cu);
+ BKE_curve_init(cu);
- return cu;
+ return cu;
}
/**
@@ -197,240 +202,249 @@ Curve *BKE_curve_add(Main *bmain, const char *name, int type)
*/
void BKE_curve_copy_data(Main *bmain, Curve *cu_dst, const Curve *cu_src, const int flag)
{
- BLI_listbase_clear(&cu_dst->nurb);
- BKE_nurbList_duplicate(&(cu_dst->nurb), &(cu_src->nurb));
+ BLI_listbase_clear(&cu_dst->nurb);
+ BKE_nurbList_duplicate(&(cu_dst->nurb), &(cu_src->nurb));
- cu_dst->mat = MEM_dupallocN(cu_src->mat);
+ cu_dst->mat = MEM_dupallocN(cu_src->mat);
- cu_dst->str = MEM_dupallocN(cu_src->str);
- cu_dst->strinfo = MEM_dupallocN(cu_src->strinfo);
- cu_dst->tb = MEM_dupallocN(cu_src->tb);
- cu_dst->bb = MEM_dupallocN(cu_src->bb);
- cu_dst->batch_cache = NULL;
+ cu_dst->str = MEM_dupallocN(cu_src->str);
+ cu_dst->strinfo = MEM_dupallocN(cu_src->strinfo);
+ cu_dst->tb = MEM_dupallocN(cu_src->tb);
+ cu_dst->bb = MEM_dupallocN(cu_src->bb);
+ cu_dst->batch_cache = NULL;
- if (cu_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) {
- BKE_id_copy_ex(bmain, &cu_src->key->id, (ID **)&cu_dst->key, flag);
- }
+ if (cu_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) {
+ BKE_id_copy_ex(bmain, &cu_src->key->id, (ID **)&cu_dst->key, flag);
+ }
- cu_dst->editnurb = NULL;
- cu_dst->editfont = NULL;
+ cu_dst->editnurb = NULL;
+ cu_dst->editfont = NULL;
}
Curve *BKE_curve_copy(Main *bmain, const Curve *cu)
{
- Curve *cu_copy;
- BKE_id_copy(bmain, &cu->id, (ID **)&cu_copy);
- return cu_copy;
+ Curve *cu_copy;
+ BKE_id_copy(bmain, &cu->id, (ID **)&cu_copy);
+ return cu_copy;
}
void BKE_curve_make_local(Main *bmain, Curve *cu, const bool lib_local)
{
- BKE_id_make_local_generic(bmain, &cu->id, true, lib_local);
+ BKE_id_make_local_generic(bmain, &cu->id, true, lib_local);
}
/* Get list of nurbs from editnurbs structure */
ListBase *BKE_curve_editNurbs_get(Curve *cu)
{
- if (cu->editnurb) {
- return &cu->editnurb->nurbs;
- }
+ if (cu->editnurb) {
+ return &cu->editnurb->nurbs;
+ }
- return NULL;
+ return NULL;
}
short BKE_curve_type_get(Curve *cu)
{
- Nurb *nu;
- int type = cu->type;
+ Nurb *nu;
+ int type = cu->type;
- if (cu->vfont) {
- return OB_FONT;
- }
+ if (cu->vfont) {
+ return OB_FONT;
+ }
- if (!cu->type) {
- type = OB_CURVE;
+ if (!cu->type) {
+ type = OB_CURVE;
- for (nu = cu->nurb.first; nu; nu = nu->next) {
- if (nu->pntsv > 1) {
- type = OB_SURF;
- }
- }
- }
+ for (nu = cu->nurb.first; nu; nu = nu->next) {
+ if (nu->pntsv > 1) {
+ type = OB_SURF;
+ }
+ }
+ }
- return type;
+ return type;
}
void BKE_curve_curve_dimension_update(Curve *cu)
{
- ListBase *nurbs = BKE_curve_nurbs_get(cu);
- Nurb *nu = nurbs->first;
+ ListBase *nurbs = BKE_curve_nurbs_get(cu);
+ Nurb *nu = nurbs->first;
- if (cu->flag & CU_3D) {
- for (; nu; nu = nu->next) {
- nu->flag &= ~CU_2D;
- }
- }
- else {
- for (; nu; nu = nu->next) {
- nu->flag |= CU_2D;
- BKE_nurb_test_2d(nu);
+ if (cu->flag & CU_3D) {
+ for (; nu; nu = nu->next) {
+ nu->flag &= ~CU_2D;
+ }
+ }
+ else {
+ for (; nu; nu = nu->next) {
+ nu->flag |= CU_2D;
+ BKE_nurb_test_2d(nu);
- /* since the handles are moved they need to be auto-located again */
- if (nu->type == CU_BEZIER)
- BKE_nurb_handles_calc(nu);
- }
- }
+ /* since the handles are moved they need to be auto-located again */
+ if (nu->type == CU_BEZIER)
+ BKE_nurb_handles_calc(nu);
+ }
+ }
}
void BKE_curve_type_test(Object *ob)
{
- ob->type = BKE_curve_type_get(ob->data);
+ ob->type = BKE_curve_type_get(ob->data);
- if (ob->type == OB_CURVE)
- BKE_curve_curve_dimension_update((Curve *)ob->data);
+ if (ob->type == OB_CURVE)
+ BKE_curve_curve_dimension_update((Curve *)ob->data);
}
void BKE_curve_boundbox_calc(Curve *cu, float r_loc[3], float r_size[3])
{
- BoundBox *bb;
- float min[3], max[3];
- float mloc[3], msize[3];
+ BoundBox *bb;
+ float min[3], max[3];
+ float mloc[3], msize[3];
- if (cu->bb == NULL) cu->bb = MEM_callocN(sizeof(BoundBox), "boundbox");
- bb = cu->bb;
+ if (cu->bb == NULL)
+ cu->bb = MEM_callocN(sizeof(BoundBox), "boundbox");
+ bb = cu->bb;
- if (!r_loc) r_loc = mloc;
- if (!r_size) r_size = msize;
+ if (!r_loc)
+ r_loc = mloc;
+ if (!r_size)
+ r_size = msize;
- INIT_MINMAX(min, max);
- if (!BKE_curve_minmax(cu, true, min, max)) {
- min[0] = min[1] = min[2] = -1.0f;
- max[0] = max[1] = max[2] = 1.0f;
- }
+ INIT_MINMAX(min, max);
+ if (!BKE_curve_minmax(cu, true, min, max)) {
+ min[0] = min[1] = min[2] = -1.0f;
+ max[0] = max[1] = max[2] = 1.0f;
+ }
- mid_v3_v3v3(r_loc, min, max);
+ mid_v3_v3v3(r_loc, min, max);
- r_size[0] = (max[0] - min[0]) / 2.0f;
- r_size[1] = (max[1] - min[1]) / 2.0f;
- r_size[2] = (max[2] - min[2]) / 2.0f;
+ r_size[0] = (max[0] - min[0]) / 2.0f;
+ r_size[1] = (max[1] - min[1]) / 2.0f;
+ r_size[2] = (max[2] - min[2]) / 2.0f;
- BKE_boundbox_init_from_minmax(bb, min, max);
+ BKE_boundbox_init_from_minmax(bb, min, max);
- bb->flag &= ~BOUNDBOX_DIRTY;
+ bb->flag &= ~BOUNDBOX_DIRTY;
}
BoundBox *BKE_curve_boundbox_get(Object *ob)
{
- /* This is Object-level data access, DO NOT touch to Mesh's bb, would be totally thread-unsafe. */
- if (ob->runtime.bb == NULL || ob->runtime.bb->flag & BOUNDBOX_DIRTY) {
- Curve *cu = ob->data;
- float min[3], max[3];
+ /* This is Object-level data access, DO NOT touch to Mesh's bb, would be totally thread-unsafe. */
+ if (ob->runtime.bb == NULL || ob->runtime.bb->flag & BOUNDBOX_DIRTY) {
+ Curve *cu = ob->data;
+ float min[3], max[3];
- INIT_MINMAX(min, max);
- BKE_curve_minmax(cu, true, min, max);
+ INIT_MINMAX(min, max);
+ BKE_curve_minmax(cu, true, min, max);
- if (ob->runtime.bb == NULL) {
- ob->runtime.bb = MEM_mallocN(sizeof(*ob->runtime.bb), __func__);
- }
- BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
- ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
- }
+ if (ob->runtime.bb == NULL) {
+ ob->runtime.bb = MEM_mallocN(sizeof(*ob->runtime.bb), __func__);
+ }
+ BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
+ ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
+ }
- return ob->runtime.bb;
+ return ob->runtime.bb;
}
void BKE_curve_texspace_calc(Curve *cu)
{
- float loc[3], size[3];
- int a;
+ float loc[3], size[3];
+ int a;
- BKE_curve_boundbox_calc(cu, loc, size);
+ BKE_curve_boundbox_calc(cu, loc, size);
- if (cu->texflag & CU_AUTOSPACE) {
- for (a = 0; a < 3; a++) {
- if (size[a] == 0.0f) size[a] = 1.0f;
- else if (size[a] > 0.0f && size[a] < 0.00001f) size[a] = 0.00001f;
- else if (size[a] < 0.0f && size[a] > -0.00001f) size[a] = -0.00001f;
- }
+ if (cu->texflag & CU_AUTOSPACE) {
+ for (a = 0; a < 3; a++) {
+ if (size[a] == 0.0f)
+ size[a] = 1.0f;
+ else if (size[a] > 0.0f && size[a] < 0.00001f)
+ size[a] = 0.00001f;
+ else if (size[a] < 0.0f && size[a] > -0.00001f)
+ size[a] = -0.00001f;
+ }
- copy_v3_v3(cu->loc, loc);
- copy_v3_v3(cu->size, size);
- zero_v3(cu->rot);
- }
+ copy_v3_v3(cu->loc, loc);
+ copy_v3_v3(cu->size, size);
+ zero_v3(cu->rot);
+ }
}
BoundBox *BKE_curve_texspace_get(Curve *cu, float r_loc[3], float r_rot[3], float r_size[3])
{
- if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) {
- BKE_curve_texspace_calc(cu);
- }
+ if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) {
+ BKE_curve_texspace_calc(cu);
+ }
- if (r_loc) copy_v3_v3(r_loc, cu->loc);
- if (r_rot) copy_v3_v3(r_rot, cu->rot);
- if (r_size) copy_v3_v3(r_size, cu->size);
+ if (r_loc)
+ copy_v3_v3(r_loc, cu->loc);
+ if (r_rot)
+ copy_v3_v3(r_rot, cu->rot);
+ if (r_size)
+ copy_v3_v3(r_size, cu->size);
- return cu->bb;
+ return cu->bb;
}
bool BKE_nurbList_index_get_co(ListBase *nurb, const int index, float r_co[3])
{
- Nurb *nu;
- int tot = 0;
-
- for (nu = nurb->first; nu; nu = nu->next) {
- int tot_nu;
- if (nu->type == CU_BEZIER) {
- tot_nu = nu->pntsu;
- if (index - tot < tot_nu) {
- copy_v3_v3(r_co, nu->bezt[index - tot].vec[1]);
- return true;
- }
- }
- else {
- tot_nu = nu->pntsu * nu->pntsv;
- if (index - tot < tot_nu) {
- copy_v3_v3(r_co, nu->bp[index - tot].vec);
- return true;
- }
- }
- tot += tot_nu;
- }
-
- return false;
+ Nurb *nu;
+ int tot = 0;
+
+ for (nu = nurb->first; nu; nu = nu->next) {
+ int tot_nu;
+ if (nu->type == CU_BEZIER) {
+ tot_nu = nu->pntsu;
+ if (index - tot < tot_nu) {
+ copy_v3_v3(r_co, nu->bezt[index - tot].vec[1]);
+ return true;
+ }
+ }
+ else {
+ tot_nu = nu->pntsu * nu->pntsv;
+ if (index - tot < tot_nu) {
+ copy_v3_v3(r_co, nu->bp[index - tot].vec);
+ return true;
+ }
+ }
+ tot += tot_nu;
+ }
+
+ return false;
}
int BKE_nurbList_verts_count(ListBase *nurb)
{
- Nurb *nu;
- int tot = 0;
+ Nurb *nu;
+ int tot = 0;
- nu = nurb->first;
- while (nu) {
- if (nu->bezt)
- tot += 3 * nu->pntsu;
- else if (nu->bp)
- tot += nu->pntsu * nu->pntsv;
+ nu = nurb->first;
+ while (nu) {
+ if (nu->bezt)
+ tot += 3 * nu->pntsu;
+ else if (nu->bp)
+ tot += nu->pntsu * nu->pntsv;
- nu = nu->next;
- }
- return tot;
+ nu = nu->next;
+ }
+ return tot;
}
int BKE_nurbList_verts_count_without_handles(ListBase *nurb)
{
- Nurb *nu;
- int tot = 0;
+ Nurb *nu;
+ int tot = 0;
- nu = nurb->first;
- while (nu) {
- if (nu->bezt)
- tot += nu->pntsu;
- else if (nu->bp)
- tot += nu->pntsu * nu->pntsv;
+ nu = nurb->first;
+ while (nu) {
+ if (nu->bezt)
+ tot += nu->pntsu;
+ else if (nu->bp)
+ tot += nu->pntsu * nu->pntsv;
- nu = nu->next;
- }
- return tot;
+ nu = nu->next;
+ }
+ return tot;
}
/* **************** NURBS ROUTINES ******************** */
@@ -438,148 +452,148 @@ int BKE_nurbList_verts_count_without_handles(ListBase *nurb)
void BKE_nurb_free(Nurb *nu)
{
- if (nu == NULL) return;
-
- if (nu->bezt)
- MEM_freeN(nu->bezt);
- nu->bezt = NULL;
- if (nu->bp)
- MEM_freeN(nu->bp);
- nu->bp = NULL;
- if (nu->knotsu)
- MEM_freeN(nu->knotsu);
- nu->knotsu = NULL;
- if (nu->knotsv)
- MEM_freeN(nu->knotsv);
- nu->knotsv = NULL;
- /* if (nu->trim.first) freeNurblist(&(nu->trim)); */
+ if (nu == NULL)
+ return;
- MEM_freeN(nu);
+ if (nu->bezt)
+ MEM_freeN(nu->bezt);
+ nu->bezt = NULL;
+ if (nu->bp)
+ MEM_freeN(nu->bp);
+ nu->bp = NULL;
+ if (nu->knotsu)
+ MEM_freeN(nu->knotsu);
+ nu->knotsu = NULL;
+ if (nu->knotsv)
+ MEM_freeN(nu->knotsv);
+ nu->knotsv = NULL;
+ /* if (nu->trim.first) freeNurblist(&(nu->trim)); */
+ MEM_freeN(nu);
}
-
void BKE_nurbList_free(ListBase *lb)
{
- Nurb *nu, *next;
+ Nurb *nu, *next;
- if (lb == NULL) return;
+ if (lb == NULL)
+ return;
- nu = lb->first;
- while (nu) {
- next = nu->next;
- BKE_nurb_free(nu);
- nu = next;
- }
- BLI_listbase_clear(lb);
+ nu = lb->first;
+ while (nu) {
+ next = nu->next;
+ BKE_nurb_free(nu);
+ nu = next;
+ }
+ BLI_listbase_clear(lb);
}
Nurb *BKE_nurb_duplicate(const Nurb *nu)
{
- Nurb *newnu;
- int len;
-
- newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "duplicateNurb");
- if (newnu == NULL) return NULL;
- memcpy(newnu, nu, sizeof(Nurb));
-
- if (nu->bezt) {
- newnu->bezt =
- (BezTriple *)MEM_malloc_arrayN(nu->pntsu, sizeof(BezTriple), "duplicateNurb2");
- memcpy(newnu->bezt, nu->bezt, nu->pntsu * sizeof(BezTriple));
- }
- else {
- len = nu->pntsu * nu->pntsv;
- newnu->bp =
- (BPoint *)MEM_malloc_arrayN(len, sizeof(BPoint), "duplicateNurb3");
- memcpy(newnu->bp, nu->bp, len * sizeof(BPoint));
-
- newnu->knotsu = newnu->knotsv = NULL;
-
- if (nu->knotsu) {
- len = KNOTSU(nu);
- if (len) {
- newnu->knotsu = MEM_malloc_arrayN(len, sizeof(float), "duplicateNurb4");
- memcpy(newnu->knotsu, nu->knotsu, sizeof(float) * len);
- }
- }
- if (nu->pntsv > 1 && nu->knotsv) {
- len = KNOTSV(nu);
- if (len) {
- newnu->knotsv = MEM_malloc_arrayN(len, sizeof(float), "duplicateNurb5");
- memcpy(newnu->knotsv, nu->knotsv, sizeof(float) * len);
- }
- }
- }
- return newnu;
+ Nurb *newnu;
+ int len;
+
+ newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "duplicateNurb");
+ if (newnu == NULL)
+ return NULL;
+ memcpy(newnu, nu, sizeof(Nurb));
+
+ if (nu->bezt) {
+ newnu->bezt = (BezTriple *)MEM_malloc_arrayN(nu->pntsu, sizeof(BezTriple), "duplicateNurb2");
+ memcpy(newnu->bezt, nu->bezt, nu->pntsu * sizeof(BezTriple));
+ }
+ else {
+ len = nu->pntsu * nu->pntsv;
+ newnu->bp = (BPoint *)MEM_malloc_arrayN(len, sizeof(BPoint), "duplicateNurb3");
+ memcpy(newnu->bp, nu->bp, len * sizeof(BPoint));
+
+ newnu->knotsu = newnu->knotsv = NULL;
+
+ if (nu->knotsu) {
+ len = KNOTSU(nu);
+ if (len) {
+ newnu->knotsu = MEM_malloc_arrayN(len, sizeof(float), "duplicateNurb4");
+ memcpy(newnu->knotsu, nu->knotsu, sizeof(float) * len);
+ }
+ }
+ if (nu->pntsv > 1 && nu->knotsv) {
+ len = KNOTSV(nu);
+ if (len) {
+ newnu->knotsv = MEM_malloc_arrayN(len, sizeof(float), "duplicateNurb5");
+ memcpy(newnu->knotsv, nu->knotsv, sizeof(float) * len);
+ }
+ }
+ }
+ return newnu;
}
/* copy the nurb but allow for different number of points (to be copied after this) */
Nurb *BKE_nurb_copy(Nurb *src, int pntsu, int pntsv)
{
- Nurb *newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "copyNurb");
- memcpy(newnu, src, sizeof(Nurb));
+ Nurb *newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "copyNurb");
+ memcpy(newnu, src, sizeof(Nurb));
- if (pntsu == 1) SWAP(int, pntsu, pntsv);
- newnu->pntsu = pntsu;
- newnu->pntsv = pntsv;
+ if (pntsu == 1)
+ SWAP(int, pntsu, pntsv);
+ newnu->pntsu = pntsu;
+ newnu->pntsv = pntsv;
- /* caller can manually handle these arrays */
- newnu->knotsu = NULL;
- newnu->knotsv = NULL;
+ /* caller can manually handle these arrays */
+ newnu->knotsu = NULL;
+ newnu->knotsv = NULL;
- if (src->bezt) {
- newnu->bezt = (BezTriple *)MEM_malloc_arrayN(pntsu * pntsv, sizeof(BezTriple), "copyNurb2");
- }
- else {
- newnu->bp = (BPoint *)MEM_malloc_arrayN(pntsu * pntsv, sizeof(BPoint), "copyNurb3");
- }
+ if (src->bezt) {
+ newnu->bezt = (BezTriple *)MEM_malloc_arrayN(pntsu * pntsv, sizeof(BezTriple), "copyNurb2");
+ }
+ else {
+ newnu->bp = (BPoint *)MEM_malloc_arrayN(pntsu * pntsv, sizeof(BPoint), "copyNurb3");
+ }
- return newnu;
+ return newnu;
}
void BKE_nurbList_duplicate(ListBase *lb1, const ListBase *lb2)
{
- Nurb *nu, *nun;
+ Nurb *nu, *nun;
- BKE_nurbList_free(lb1);
+ BKE_nurbList_free(lb1);
- nu = lb2->first;
- while (nu) {
- nun = BKE_nurb_duplicate(nu);
- BLI_addtail(lb1, nun);
+ nu = lb2->first;
+ while (nu) {
+ nun = BKE_nurb_duplicate(nu);
+ BLI_addtail(lb1, nun);
- nu = nu->next;
- }
+ nu = nu->next;
+ }
}
void BKE_nurb_test_2d(Nurb *nu)
{
- BezTriple *bezt;
- BPoint *bp;
- int a;
-
- if ((nu->flag & CU_2D) == 0)
- return;
-
- if (nu->type == CU_BEZIER) {
- a = nu->pntsu;
- bezt = nu->bezt;
- while (a--) {
- bezt->vec[0][2] = 0.0;
- bezt->vec[1][2] = 0.0;
- bezt->vec[2][2] = 0.0;
- bezt++;
- }
- }
- else {
- a = nu->pntsu * nu->pntsv;
- bp = nu->bp;
- while (a--) {
- bp->vec[2] = 0.0;
- bp++;
- }
- }
+ BezTriple *bezt;
+ BPoint *bp;
+ int a;
+
+ if ((nu->flag & CU_2D) == 0)
+ return;
+
+ if (nu->type == CU_BEZIER) {
+ a = nu->pntsu;
+ bezt = nu->bezt;
+ while (a--) {
+ bezt->vec[0][2] = 0.0;
+ bezt->vec[1][2] = 0.0;
+ bezt->vec[2][2] = 0.0;
+ bezt++;
+ }
+ }
+ else {
+ a = nu->pntsu * nu->pntsv;
+ bp = nu->bp;
+ while (a--) {
+ bp->vec[2] = 0.0;
+ bp++;
+ }
+ }
}
/**
@@ -588,603 +602,599 @@ void BKE_nurb_test_2d(Nurb *nu)
*/
void BKE_nurb_minmax(Nurb *nu, bool use_radius, float min[3], float max[3])
{
- BezTriple *bezt;
- BPoint *bp;
- int a;
- float point[3];
-
- if (nu->type == CU_BEZIER) {
- a = nu->pntsu;
- bezt = nu->bezt;
- while (a--) {
- if (use_radius) {
- float radius_vector[3];
- radius_vector[0] = radius_vector[1] = radius_vector[2] = bezt->radius;
-
- add_v3_v3v3(point, bezt->vec[1], radius_vector);
- minmax_v3v3_v3(min, max, point);
-
- sub_v3_v3v3(point, bezt->vec[1], radius_vector);
- minmax_v3v3_v3(min, max, point);
- }
- else {
- minmax_v3v3_v3(min, max, bezt->vec[1]);
- }
- minmax_v3v3_v3(min, max, bezt->vec[0]);
- minmax_v3v3_v3(min, max, bezt->vec[2]);
- bezt++;
- }
- }
- else {
- a = nu->pntsu * nu->pntsv;
- bp = nu->bp;
- while (a--) {
- if (nu->pntsv == 1 && use_radius) {
- float radius_vector[3];
- radius_vector[0] = radius_vector[1] = radius_vector[2] = bp->radius;
-
- add_v3_v3v3(point, bp->vec, radius_vector);
- minmax_v3v3_v3(min, max, point);
-
- sub_v3_v3v3(point, bp->vec, radius_vector);
- minmax_v3v3_v3(min, max, point);
- }
- else {
- /* Surfaces doesn't use bevel, so no need to take radius into account. */
- minmax_v3v3_v3(min, max, bp->vec);
- }
- bp++;
- }
- }
+ BezTriple *bezt;
+ BPoint *bp;
+ int a;
+ float point[3];
+
+ if (nu->type == CU_BEZIER) {
+ a = nu->pntsu;
+ bezt = nu->bezt;
+ while (a--) {
+ if (use_radius) {
+ float radius_vector[3];
+ radius_vector[0] = radius_vector[1] = radius_vector[2] = bezt->radius;
+
+ add_v3_v3v3(point, bezt->vec[1], radius_vector);
+ minmax_v3v3_v3(min, max, point);
+
+ sub_v3_v3v3(point, bezt->vec[1], radius_vector);
+ minmax_v3v3_v3(min, max, point);
+ }
+ else {
+ minmax_v3v3_v3(min, max, bezt->vec[1]);
+ }
+ minmax_v3v3_v3(min, max, bezt->vec[0]);
+ minmax_v3v3_v3(min, max, bezt->vec[2]);
+ bezt++;
+ }
+ }
+ else {
+ a = nu->pntsu * nu->pntsv;
+ bp = nu->bp;
+ while (a--) {
+ if (nu->pntsv == 1 && use_radius) {
+ float radius_vector[3];
+ radius_vector[0] = radius_vector[1] = radius_vector[2] = bp->radius;
+
+ add_v3_v3v3(point, bp->vec, radius_vector);
+ minmax_v3v3_v3(min, max, point);
+
+ sub_v3_v3v3(point, bp->vec, radius_vector);
+ minmax_v3v3_v3(min, max, point);
+ }
+ else {
+ /* Surfaces doesn't use bevel, so no need to take radius into account. */
+ minmax_v3v3_v3(min, max, bp->vec);
+ }
+ bp++;
+ }
+ }
}
float BKE_nurb_calc_length(const Nurb *nu, int resolution)
{
- BezTriple *bezt, *prevbezt;
- BPoint *bp, *prevbp;
- int a, b;
- float length = 0.0f;
- int resolu = resolution ? resolution : nu->resolu;
- int pntsu = nu->pntsu;
- float *points, *pntsit, *prevpntsit;
-
- if (nu->type == CU_POLY) {
- a = nu->pntsu - 1;
- bp = nu->bp;
- if (nu->flagu & CU_NURB_CYCLIC) {
- ++a;
- prevbp = nu->bp + (nu->pntsu - 1);
- }
- else {
- prevbp = bp;
- bp++;
- }
-
- while (a--) {
- length += len_v3v3(prevbp->vec, bp->vec);
- prevbp = bp;
- ++bp;
- }
- }
- else if (nu->type == CU_BEZIER) {
- points = MEM_mallocN(sizeof(float[3]) * (resolu + 1), "getLength_bezier");
- a = nu->pntsu - 1;
- bezt = nu->bezt;
- if (nu->flagu & CU_NURB_CYCLIC) {
- ++a;
- prevbezt = nu->bezt + (nu->pntsu - 1);
- }
- else {
- prevbezt = bezt;
- ++bezt;
- }
-
- while (a--) {
- if (prevbezt->h2 == HD_VECT && bezt->h1 == HD_VECT) {
- length += len_v3v3(prevbezt->vec[1], bezt->vec[1]);
- }
- else {
- for (int j = 0; j < 3; j++) {
- BKE_curve_forward_diff_bezier(
- prevbezt->vec[1][j], prevbezt->vec[2][j],
- bezt->vec[0][j], bezt->vec[1][j],
- points + j, resolu, 3 * sizeof(float));
- }
-
- prevpntsit = pntsit = points;
- b = resolu;
- while (b--) {
- pntsit += 3;
- length += len_v3v3(prevpntsit, pntsit);
- prevpntsit = pntsit;
- }
- }
- prevbezt = bezt;
- ++bezt;
- }
-
- MEM_freeN(points);
- }
- else if (nu->type == CU_NURBS) {
- if (nu->pntsv == 1) {
- /* important to zero for BKE_nurb_makeCurve. */
- points = MEM_callocN(sizeof(float[3]) * pntsu * resolu, "getLength_nurbs");
-
- BKE_nurb_makeCurve(
- nu, points,
- NULL, NULL, NULL,
- resolu, sizeof(float[3]));
-
- if (nu->flagu & CU_NURB_CYCLIC) {
- b = pntsu * resolu + 1;
- prevpntsit = points + 3 * (pntsu * resolu - 1);
- pntsit = points;
- }
- else {
- b = (pntsu - 1) * resolu;
- prevpntsit = points;
- pntsit = points + 3;
- }
-
- while (--b) {
- length += len_v3v3(prevpntsit, pntsit);
- prevpntsit = pntsit;
- pntsit += 3;
- }
-
- MEM_freeN(points);
- }
- }
-
- return length;
+ BezTriple *bezt, *prevbezt;
+ BPoint *bp, *prevbp;
+ int a, b;
+ float length = 0.0f;
+ int resolu = resolution ? resolution : nu->resolu;
+ int pntsu = nu->pntsu;
+ float *points, *pntsit, *prevpntsit;
+
+ if (nu->type == CU_POLY) {
+ a = nu->pntsu - 1;
+ bp = nu->bp;
+ if (nu->flagu & CU_NURB_CYCLIC) {
+ ++a;
+ prevbp = nu->bp + (nu->pntsu - 1);
+ }
+ else {
+ prevbp = bp;
+ bp++;
+ }
+
+ while (a--) {
+ length += len_v3v3(prevbp->vec, bp->vec);
+ prevbp = bp;
+ ++bp;
+ }
+ }
+ else if (nu->type == CU_BEZIER) {
+ points = MEM_mallocN(sizeof(float[3]) * (resolu + 1), "getLength_bezier");
+ a = nu->pntsu - 1;
+ bezt = nu->bezt;
+ if (nu->flagu & CU_NURB_CYCLIC) {
+ ++a;
+ prevbezt = nu->bezt + (nu->pntsu - 1);
+ }
+ else {
+ prevbezt = bezt;
+ ++bezt;
+ }
+
+ while (a--) {
+ if (prevbezt->h2 == HD_VECT && bezt->h1 == HD_VECT) {
+ length += len_v3v3(prevbezt->vec[1], bezt->vec[1]);
+ }
+ else {
+ for (int j = 0; j < 3; j++) {
+ BKE_curve_forward_diff_bezier(prevbezt->vec[1][j],
+ prevbezt->vec[2][j],
+ bezt->vec[0][j],
+ bezt->vec[1][j],
+ points + j,
+ resolu,
+ 3 * sizeof(float));
+ }
+
+ prevpntsit = pntsit = points;
+ b = resolu;
+ while (b--) {
+ pntsit += 3;
+ length += len_v3v3(prevpntsit, pntsit);
+ prevpntsit = pntsit;
+ }
+ }
+ prevbezt = bezt;
+ ++bezt;
+ }
+
+ MEM_freeN(points);
+ }
+ else if (nu->type == CU_NURBS) {
+ if (nu->pntsv == 1) {
+ /* important to zero for BKE_nurb_makeCurve. */
+ points = MEM_callocN(sizeof(float[3]) * pntsu * resolu, "getLength_nurbs");
+
+ BKE_nurb_makeCurve(nu, points, NULL, NULL, NULL, resolu, sizeof(float[3]));
+
+ if (nu->flagu & CU_NURB_CYCLIC) {
+ b = pntsu * resolu + 1;
+ prevpntsit = points + 3 * (pntsu * resolu - 1);
+ pntsit = points;
+ }
+ else {
+ b = (pntsu - 1) * resolu;
+ prevpntsit = points;
+ pntsit = points + 3;
+ }
+
+ while (--b) {
+ length += len_v3v3(prevpntsit, pntsit);
+ prevpntsit = pntsit;
+ pntsit += 3;
+ }
+
+ MEM_freeN(points);
+ }
+ }
+
+ return length;
}
/* be sure to call makeknots after this */
void BKE_nurb_points_add(Nurb *nu, int number)
{
- BPoint *bp;
- int i;
+ BPoint *bp;
+ int i;
- nu->bp = MEM_recallocN(nu->bp, (nu->pntsu + number) * sizeof(BPoint));
+ nu->bp = MEM_recallocN(nu->bp, (nu->pntsu + number) * sizeof(BPoint));
- for (i = 0, bp = &nu->bp[nu->pntsu]; i < number; i++, bp++) {
- bp->radius = 1.0f;
- }
+ for (i = 0, bp = &nu->bp[nu->pntsu]; i < number; i++, bp++) {
+ bp->radius = 1.0f;
+ }
- nu->pntsu += number;
+ nu->pntsu += number;
}
void BKE_nurb_bezierPoints_add(Nurb *nu, int number)
{
- BezTriple *bezt;
- int i;
+ BezTriple *bezt;
+ int i;
- nu->bezt = MEM_recallocN(nu->bezt, (nu->pntsu + number) * sizeof(BezTriple));
+ nu->bezt = MEM_recallocN(nu->bezt, (nu->pntsu + number) * sizeof(BezTriple));
- for (i = 0, bezt = &nu->bezt[nu->pntsu]; i < number; i++, bezt++) {
- bezt->radius = 1.0f;
- }
+ for (i = 0, bezt = &nu->bezt[nu->pntsu]; i < number; i++, bezt++) {
+ bezt->radius = 1.0f;
+ }
- nu->pntsu += number;
+ nu->pntsu += number;
}
-
-int BKE_nurb_index_from_uv(
- Nurb *nu,
- int u, int v)
+int BKE_nurb_index_from_uv(Nurb *nu, int u, int v)
{
- const int totu = nu->pntsu;
- const int totv = nu->pntsv;
+ const int totu = nu->pntsu;
+ const int totv = nu->pntsv;
- if (nu->flagu & CU_NURB_CYCLIC) {
- u = mod_i(u, totu);
- }
- else if (u < 0 || u >= totu) {
- return -1;
- }
+ if (nu->flagu & CU_NURB_CYCLIC) {
+ u = mod_i(u, totu);
+ }
+ else if (u < 0 || u >= totu) {
+ return -1;
+ }
- if (nu->flagv & CU_NURB_CYCLIC) {
- v = mod_i(v, totv);
- }
- else if (v < 0 || v >= totv) {
- return -1;
- }
+ if (nu->flagv & CU_NURB_CYCLIC) {
+ v = mod_i(v, totv);
+ }
+ else if (v < 0 || v >= totv) {
+ return -1;
+ }
- return (v * totu) + u;
+ return (v * totu) + u;
}
-void BKE_nurb_index_to_uv(
- Nurb *nu, int index,
- int *r_u, int *r_v)
+void BKE_nurb_index_to_uv(Nurb *nu, int index, int *r_u, int *r_v)
{
- const int totu = nu->pntsu;
- const int totv = nu->pntsv;
- BLI_assert(index >= 0 && index < (nu->pntsu * nu->pntsv));
- *r_u = (index % totu);
- *r_v = (index / totu) % totv;
+ const int totu = nu->pntsu;
+ const int totv = nu->pntsv;
+ BLI_assert(index >= 0 && index < (nu->pntsu * nu->pntsv));
+ *r_u = (index % totu);
+ *r_v = (index / totu) % totv;
}
BezTriple *BKE_nurb_bezt_get_next(Nurb *nu, BezTriple *bezt)
{
- BezTriple *bezt_next;
+ BezTriple *bezt_next;
- BLI_assert(ARRAY_HAS_ITEM(bezt, nu->bezt, nu->pntsu));
+ BLI_assert(ARRAY_HAS_ITEM(bezt, nu->bezt, nu->pntsu));
- if (bezt == &nu->bezt[nu->pntsu - 1]) {
- if (nu->flagu & CU_NURB_CYCLIC) {
- bezt_next = nu->bezt;
- }
- else {
- bezt_next = NULL;
- }
- }
- else {
- bezt_next = bezt + 1;
- }
+ if (bezt == &nu->bezt[nu->pntsu - 1]) {
+ if (nu->flagu & CU_NURB_CYCLIC) {
+ bezt_next = nu->bezt;
+ }
+ else {
+ bezt_next = NULL;
+ }
+ }
+ else {
+ bezt_next = bezt + 1;
+ }
- return bezt_next;
+ return bezt_next;
}
BPoint *BKE_nurb_bpoint_get_next(Nurb *nu, BPoint *bp)
{
- BPoint *bp_next;
+ BPoint *bp_next;
- BLI_assert(ARRAY_HAS_ITEM(bp, nu->bp, nu->pntsu));
+ BLI_assert(ARRAY_HAS_ITEM(bp, nu->bp, nu->pntsu));
- if (bp == &nu->bp[nu->pntsu - 1]) {
- if (nu->flagu & CU_NURB_CYCLIC) {
- bp_next = nu->bp;
- }
- else {
- bp_next = NULL;
- }
- }
- else {
- bp_next = bp + 1;
- }
+ if (bp == &nu->bp[nu->pntsu - 1]) {
+ if (nu->flagu & CU_NURB_CYCLIC) {
+ bp_next = nu->bp;
+ }
+ else {
+ bp_next = NULL;
+ }
+ }
+ else {
+ bp_next = bp + 1;
+ }
- return bp_next;
+ return bp_next;
}
BezTriple *BKE_nurb_bezt_get_prev(Nurb *nu, BezTriple *bezt)
{
- BezTriple *bezt_prev;
+ BezTriple *bezt_prev;
- BLI_assert(ARRAY_HAS_ITEM(bezt, nu->bezt, nu->pntsu));
- BLI_assert(nu->pntsv <= 1);
+ BLI_assert(ARRAY_HAS_ITEM(bezt, nu->bezt, nu->pntsu));
+ BLI_assert(nu->pntsv <= 1);
- if (bezt == nu->bezt) {
- if (nu->flagu & CU_NURB_CYCLIC) {
- bezt_prev = &nu->bezt[nu->pntsu - 1];
- }
- else {
- bezt_prev = NULL;
- }
- }
- else {
- bezt_prev = bezt - 1;
- }
+ if (bezt == nu->bezt) {
+ if (nu->flagu & CU_NURB_CYCLIC) {
+ bezt_prev = &nu->bezt[nu->pntsu - 1];
+ }
+ else {
+ bezt_prev = NULL;
+ }
+ }
+ else {
+ bezt_prev = bezt - 1;
+ }
- return bezt_prev;
+ return bezt_prev;
}
BPoint *BKE_nurb_bpoint_get_prev(Nurb *nu, BPoint *bp)
{
- BPoint *bp_prev;
+ BPoint *bp_prev;
- BLI_assert(ARRAY_HAS_ITEM(bp, nu->bp, nu->pntsu));
- BLI_assert(nu->pntsv == 1);
+ BLI_assert(ARRAY_HAS_ITEM(bp, nu->bp, nu->pntsu));
+ BLI_assert(nu->pntsv == 1);
- if (bp == nu->bp) {
- if (nu->flagu & CU_NURB_CYCLIC) {
- bp_prev = &nu->bp[nu->pntsu - 1];
- }
- else {
- bp_prev = NULL;
- }
- }
- else {
- bp_prev = bp - 1;
- }
+ if (bp == nu->bp) {
+ if (nu->flagu & CU_NURB_CYCLIC) {
+ bp_prev = &nu->bp[nu->pntsu - 1];
+ }
+ else {
+ bp_prev = NULL;
+ }
+ }
+ else {
+ bp_prev = bp - 1;
+ }
- return bp_prev;
+ return bp_prev;
}
void BKE_nurb_bezt_calc_normal(struct Nurb *UNUSED(nu), BezTriple *bezt, float r_normal[3])
{
- /* calculate the axis matrix from the spline */
- float dir_prev[3], dir_next[3];
+ /* calculate the axis matrix from the spline */
+ float dir_prev[3], dir_next[3];
- sub_v3_v3v3(dir_prev, bezt->vec[0], bezt->vec[1]);
- sub_v3_v3v3(dir_next, bezt->vec[1], bezt->vec[2]);
+ sub_v3_v3v3(dir_prev, bezt->vec[0], bezt->vec[1]);
+ sub_v3_v3v3(dir_next, bezt->vec[1], bezt->vec[2]);
- normalize_v3(dir_prev);
- normalize_v3(dir_next);
+ normalize_v3(dir_prev);
+ normalize_v3(dir_next);
- add_v3_v3v3(r_normal, dir_prev, dir_next);
- normalize_v3(r_normal);
+ add_v3_v3v3(r_normal, dir_prev, dir_next);
+ normalize_v3(r_normal);
}
void BKE_nurb_bezt_calc_plane(struct Nurb *nu, BezTriple *bezt, float r_plane[3])
{
- float dir_prev[3], dir_next[3];
+ float dir_prev[3], dir_next[3];
- sub_v3_v3v3(dir_prev, bezt->vec[0], bezt->vec[1]);
- sub_v3_v3v3(dir_next, bezt->vec[1], bezt->vec[2]);
+ sub_v3_v3v3(dir_prev, bezt->vec[0], bezt->vec[1]);
+ sub_v3_v3v3(dir_next, bezt->vec[1], bezt->vec[2]);
- normalize_v3(dir_prev);
- normalize_v3(dir_next);
+ normalize_v3(dir_prev);
+ normalize_v3(dir_next);
- cross_v3_v3v3(r_plane, dir_prev, dir_next);
- if (normalize_v3(r_plane) < FLT_EPSILON) {
- BezTriple *bezt_prev = BKE_nurb_bezt_get_prev(nu, bezt);
- BezTriple *bezt_next = BKE_nurb_bezt_get_next(nu, bezt);
+ cross_v3_v3v3(r_plane, dir_prev, dir_next);
+ if (normalize_v3(r_plane) < FLT_EPSILON) {
+ BezTriple *bezt_prev = BKE_nurb_bezt_get_prev(nu, bezt);
+ BezTriple *bezt_next = BKE_nurb_bezt_get_next(nu, bezt);
- if (bezt_prev) {
- sub_v3_v3v3(dir_prev, bezt_prev->vec[1], bezt->vec[1]);
- normalize_v3(dir_prev);
- }
- if (bezt_next) {
- sub_v3_v3v3(dir_next, bezt->vec[1], bezt_next->vec[1]);
- normalize_v3(dir_next);
- }
- cross_v3_v3v3(r_plane, dir_prev, dir_next);
- }
+ if (bezt_prev) {
+ sub_v3_v3v3(dir_prev, bezt_prev->vec[1], bezt->vec[1]);
+ normalize_v3(dir_prev);
+ }
+ if (bezt_next) {
+ sub_v3_v3v3(dir_next, bezt->vec[1], bezt_next->vec[1]);
+ normalize_v3(dir_next);
+ }
+ cross_v3_v3v3(r_plane, dir_prev, dir_next);
+ }
- /* matches with bones more closely */
- {
- float dir_mid[3], tvec[3];
- add_v3_v3v3(dir_mid, dir_prev, dir_next);
- cross_v3_v3v3(tvec, r_plane, dir_mid);
- copy_v3_v3(r_plane, tvec);
- }
+ /* matches with bones more closely */
+ {
+ float dir_mid[3], tvec[3];
+ add_v3_v3v3(dir_mid, dir_prev, dir_next);
+ cross_v3_v3v3(tvec, r_plane, dir_mid);
+ copy_v3_v3(r_plane, tvec);
+ }
- normalize_v3(r_plane);
+ normalize_v3(r_plane);
}
void BKE_nurb_bpoint_calc_normal(struct Nurb *nu, BPoint *bp, float r_normal[3])
{
- BPoint *bp_prev = BKE_nurb_bpoint_get_prev(nu, bp);
- BPoint *bp_next = BKE_nurb_bpoint_get_next(nu, bp);
+ BPoint *bp_prev = BKE_nurb_bpoint_get_prev(nu, bp);
+ BPoint *bp_next = BKE_nurb_bpoint_get_next(nu, bp);
- zero_v3(r_normal);
+ zero_v3(r_normal);
- if (bp_prev) {
- float dir_prev[3];
- sub_v3_v3v3(dir_prev, bp_prev->vec, bp->vec);
- normalize_v3(dir_prev);
- add_v3_v3(r_normal, dir_prev);
- }
- if (bp_next) {
- float dir_next[3];
- sub_v3_v3v3(dir_next, bp->vec, bp_next->vec);
- normalize_v3(dir_next);
- add_v3_v3(r_normal, dir_next);
- }
+ if (bp_prev) {
+ float dir_prev[3];
+ sub_v3_v3v3(dir_prev, bp_prev->vec, bp->vec);
+ normalize_v3(dir_prev);
+ add_v3_v3(r_normal, dir_prev);
+ }
+ if (bp_next) {
+ float dir_next[3];
+ sub_v3_v3v3(dir_next, bp->vec, bp_next->vec);
+ normalize_v3(dir_next);
+ add_v3_v3(r_normal, dir_next);
+ }
- normalize_v3(r_normal);
+ normalize_v3(r_normal);
}
void BKE_nurb_bpoint_calc_plane(struct Nurb *nu, BPoint *bp, float r_plane[3])
{
- BPoint *bp_prev = BKE_nurb_bpoint_get_prev(nu, bp);
- BPoint *bp_next = BKE_nurb_bpoint_get_next(nu, bp);
+ BPoint *bp_prev = BKE_nurb_bpoint_get_prev(nu, bp);
+ BPoint *bp_next = BKE_nurb_bpoint_get_next(nu, bp);
- float dir_prev[3] = {0.0f}, dir_next[3] = {0.0f};
+ float dir_prev[3] = {0.0f}, dir_next[3] = {0.0f};
- if (bp_prev) {
- sub_v3_v3v3(dir_prev, bp_prev->vec, bp->vec);
- normalize_v3(dir_prev);
- }
- if (bp_next) {
- sub_v3_v3v3(dir_next, bp->vec, bp_next->vec);
- normalize_v3(dir_next);
- }
- cross_v3_v3v3(r_plane, dir_prev, dir_next);
+ if (bp_prev) {
+ sub_v3_v3v3(dir_prev, bp_prev->vec, bp->vec);
+ normalize_v3(dir_prev);
+ }
+ if (bp_next) {
+ sub_v3_v3v3(dir_next, bp->vec, bp_next->vec);
+ normalize_v3(dir_next);
+ }
+ cross_v3_v3v3(r_plane, dir_prev, dir_next);
- /* matches with bones more closely */
- {
- float dir_mid[3], tvec[3];
- add_v3_v3v3(dir_mid, dir_prev, dir_next);
- cross_v3_v3v3(tvec, r_plane, dir_mid);
- copy_v3_v3(r_plane, tvec);
- }
+ /* matches with bones more closely */
+ {
+ float dir_mid[3], tvec[3];
+ add_v3_v3v3(dir_mid, dir_prev, dir_next);
+ cross_v3_v3v3(tvec, r_plane, dir_mid);
+ copy_v3_v3(r_plane, tvec);
+ }
- normalize_v3(r_plane);
+ normalize_v3(r_plane);
}
/* ~~~~~~~~~~~~~~~~~~~~Non Uniform Rational B Spline calculations ~~~~~~~~~~~ */
-
static void calcknots(float *knots, const int pnts, const short order, const short flag)
{
- /* knots: number of pnts NOT corrected for cyclic */
- const int pnts_order = pnts + order;
- float k;
- int a;
-
- switch (flag & (CU_NURB_ENDPOINT | CU_NURB_BEZIER)) {
- case CU_NURB_ENDPOINT:
- k = 0.0;
- for (a = 1; a <= pnts_order; a++) {
- knots[a - 1] = k;
- if (a >= order && a <= pnts)
- k += 1.0f;
- }
- break;
- case CU_NURB_BEZIER:
- /* Warning, the order MUST be 2 or 4,
- * if this is not enforced, the displist will be corrupt */
- if (order == 4) {
- k = 0.34;
- for (a = 0; a < pnts_order; a++) {
- knots[a] = floorf(k);
- k += (1.0f / 3.0f);
- }
- }
- else if (order == 3) {
- k = 0.6f;
- for (a = 0; a < pnts_order; a++) {
- if (a >= order && a <= pnts)
- k += 0.5f;
- knots[a] = floorf(k);
- }
- }
- else {
- CLOG_ERROR(&LOG, "bez nurb curve order is not 3 or 4, should never happen");
- }
- break;
- default:
- for (a = 0; a < pnts_order; a++) {
- knots[a] = (float)a;
- }
- break;
- }
+ /* knots: number of pnts NOT corrected for cyclic */
+ const int pnts_order = pnts + order;
+ float k;
+ int a;
+
+ switch (flag & (CU_NURB_ENDPOINT | CU_NURB_BEZIER)) {
+ case CU_NURB_ENDPOINT:
+ k = 0.0;
+ for (a = 1; a <= pnts_order; a++) {
+ knots[a - 1] = k;
+ if (a >= order && a <= pnts)
+ k += 1.0f;
+ }
+ break;
+ case CU_NURB_BEZIER:
+ /* Warning, the order MUST be 2 or 4,
+ * if this is not enforced, the displist will be corrupt */
+ if (order == 4) {
+ k = 0.34;
+ for (a = 0; a < pnts_order; a++) {
+ knots[a] = floorf(k);
+ k += (1.0f / 3.0f);
+ }
+ }
+ else if (order == 3) {
+ k = 0.6f;
+ for (a = 0; a < pnts_order; a++) {
+ if (a >= order && a <= pnts)
+ k += 0.5f;
+ knots[a] = floorf(k);
+ }
+ }
+ else {
+ CLOG_ERROR(&LOG, "bez nurb curve order is not 3 or 4, should never happen");
+ }
+ break;
+ default:
+ for (a = 0; a < pnts_order; a++) {
+ knots[a] = (float)a;
+ }
+ break;
+ }
}
static void makecyclicknots(float *knots, int pnts, short order)
/* pnts, order: number of pnts NOT corrected for cyclic */
{
- int a, b, order2, c;
+ int a, b, order2, c;
- if (knots == NULL)
- return;
+ if (knots == NULL)
+ return;
- order2 = order - 1;
+ order2 = order - 1;
- /* do first long rows (order -1), remove identical knots at endpoints */
- if (order > 2) {
- b = pnts + order2;
- for (a = 1; a < order2; a++) {
- if (knots[b] != knots[b - a])
- break;
- }
- if (a == order2)
- knots[pnts + order - 2] += 1.0f;
- }
+ /* do first long rows (order -1), remove identical knots at endpoints */
+ if (order > 2) {
+ b = pnts + order2;
+ for (a = 1; a < order2; a++) {
+ if (knots[b] != knots[b - a])
+ break;
+ }
+ if (a == order2)
+ knots[pnts + order - 2] += 1.0f;
+ }
- b = order;
- c = pnts + order + order2;
- for (a = pnts + order2; a < c; a++) {
- knots[a] = knots[a - 1] + (knots[b] - knots[b - 1]);
- b--;
- }
+ b = order;
+ c = pnts + order + order2;
+ for (a = pnts + order2; a < c; a++) {
+ knots[a] = knots[a - 1] + (knots[b] - knots[b - 1]);
+ b--;
+ }
}
-
-
static void makeknots(Nurb *nu, short uv)
{
- if (nu->type == CU_NURBS) {
- if (uv == 1) {
- if (nu->knotsu)
- MEM_freeN(nu->knotsu);
- if (BKE_nurb_check_valid_u(nu)) {
- nu->knotsu = MEM_calloc_arrayN(KNOTSU(nu) + 1, sizeof(float), "makeknots");
- if (nu->flagu & CU_NURB_CYCLIC) {
- calcknots(nu->knotsu, nu->pntsu, nu->orderu, 0); /* cyclic should be uniform */
- makecyclicknots(nu->knotsu, nu->pntsu, nu->orderu);
- }
- else {
- calcknots(nu->knotsu, nu->pntsu, nu->orderu, nu->flagu);
- }
- }
- else
- nu->knotsu = NULL;
- }
- else if (uv == 2) {
- if (nu->knotsv)
- MEM_freeN(nu->knotsv);
- if (BKE_nurb_check_valid_v(nu)) {
- nu->knotsv = MEM_calloc_arrayN(KNOTSV(nu) + 1, sizeof(float), "makeknots");
- if (nu->flagv & CU_NURB_CYCLIC) {
- calcknots(nu->knotsv, nu->pntsv, nu->orderv, 0); /* cyclic should be uniform */
- makecyclicknots(nu->knotsv, nu->pntsv, nu->orderv);
- }
- else {
- calcknots(nu->knotsv, nu->pntsv, nu->orderv, nu->flagv);
- }
- }
- else {
- nu->knotsv = NULL;
- }
- }
- }
+ if (nu->type == CU_NURBS) {
+ if (uv == 1) {
+ if (nu->knotsu)
+ MEM_freeN(nu->knotsu);
+ if (BKE_nurb_check_valid_u(nu)) {
+ nu->knotsu = MEM_calloc_arrayN(KNOTSU(nu) + 1, sizeof(float), "makeknots");
+ if (nu->flagu & CU_NURB_CYCLIC) {
+ calcknots(nu->knotsu, nu->pntsu, nu->orderu, 0); /* cyclic should be uniform */
+ makecyclicknots(nu->knotsu, nu->pntsu, nu->orderu);
+ }
+ else {
+ calcknots(nu->knotsu, nu->pntsu, nu->orderu, nu->flagu);
+ }
+ }
+ else
+ nu->knotsu = NULL;
+ }
+ else if (uv == 2) {
+ if (nu->knotsv)
+ MEM_freeN(nu->knotsv);
+ if (BKE_nurb_check_valid_v(nu)) {
+ nu->knotsv = MEM_calloc_arrayN(KNOTSV(nu) + 1, sizeof(float), "makeknots");
+ if (nu->flagv & CU_NURB_CYCLIC) {
+ calcknots(nu->knotsv, nu->pntsv, nu->orderv, 0); /* cyclic should be uniform */
+ makecyclicknots(nu->knotsv, nu->pntsv, nu->orderv);
+ }
+ else {
+ calcknots(nu->knotsv, nu->pntsv, nu->orderv, nu->flagv);
+ }
+ }
+ else {
+ nu->knotsv = NULL;
+ }
+ }
+ }
}
void BKE_nurb_knot_calc_u(Nurb *nu)
{
- makeknots(nu, 1);
+ makeknots(nu, 1);
}
void BKE_nurb_knot_calc_v(Nurb *nu)
{
- makeknots(nu, 2);
-}
-
-static void basisNurb(float t, short order, int pnts, float *knots, float *basis, int *start, int *end)
-{
- float d, e;
- int i, i1 = 0, i2 = 0, j, orderpluspnts, opp2, o2;
-
- orderpluspnts = order + pnts;
- opp2 = orderpluspnts - 1;
-
- /* this is for float inaccuracy */
- if (t < knots[0])
- t = knots[0];
- else if (t > knots[opp2])
- t = knots[opp2];
-
- /* this part is order '1' */
- o2 = order + 1;
- for (i = 0; i < opp2; i++) {
- if (knots[i] != knots[i + 1] && t >= knots[i] && t <= knots[i + 1]) {
- basis[i] = 1.0;
- i1 = i - o2;
- if (i1 < 0) i1 = 0;
- i2 = i;
- i++;
- while (i < opp2) {
- basis[i] = 0.0;
- i++;
- }
- break;
- }
- else
- basis[i] = 0.0;
- }
- basis[i] = 0.0;
-
- /* this is order 2, 3, ... */
- for (j = 2; j <= order; j++) {
-
- if (i2 + j >= orderpluspnts) i2 = opp2 - j;
-
- for (i = i1; i <= i2; i++) {
- if (basis[i] != 0.0f)
- d = ((t - knots[i]) * basis[i]) / (knots[i + j - 1] - knots[i]);
- else
- d = 0.0f;
-
- if (basis[i + 1] != 0.0f)
- e = ((knots[i + j] - t) * basis[i + 1]) / (knots[i + j] - knots[i + 1]);
- else
- e = 0.0;
-
- basis[i] = d + e;
- }
- }
-
- *start = 1000;
- *end = 0;
-
- for (i = i1; i <= i2; i++) {
- if (basis[i] > 0.0f) {
- *end = i;
- if (*start == 1000) *start = i;
- }
- }
+ makeknots(nu, 2);
+}
+
+static void basisNurb(
+ float t, short order, int pnts, float *knots, float *basis, int *start, int *end)
+{
+ float d, e;
+ int i, i1 = 0, i2 = 0, j, orderpluspnts, opp2, o2;
+
+ orderpluspnts = order + pnts;
+ opp2 = orderpluspnts - 1;
+
+ /* this is for float inaccuracy */
+ if (t < knots[0])
+ t = knots[0];
+ else if (t > knots[opp2])
+ t = knots[opp2];
+
+ /* this part is order '1' */
+ o2 = order + 1;
+ for (i = 0; i < opp2; i++) {
+ if (knots[i] != knots[i + 1] && t >= knots[i] && t <= knots[i + 1]) {
+ basis[i] = 1.0;
+ i1 = i - o2;
+ if (i1 < 0)
+ i1 = 0;
+ i2 = i;
+ i++;
+ while (i < opp2) {
+ basis[i] = 0.0;
+ i++;
+ }
+ break;
+ }
+ else
+ basis[i] = 0.0;
+ }
+ basis[i] = 0.0;
+
+ /* this is order 2, 3, ... */
+ for (j = 2; j <= order; j++) {
+
+ if (i2 + j >= orderpluspnts)
+ i2 = opp2 - j;
+
+ for (i = i1; i <= i2; i++) {
+ if (basis[i] != 0.0f)
+ d = ((t - knots[i]) * basis[i]) / (knots[i + j - 1] - knots[i]);
+ else
+ d = 0.0f;
+
+ if (basis[i + 1] != 0.0f)
+ e = ((knots[i + j] - t) * basis[i + 1]) / (knots[i + j] - knots[i + 1]);
+ else
+ e = 0.0;
+
+ basis[i] = d + e;
+ }
+ }
+
+ *start = 1000;
+ *end = 0;
+
+ for (i = i1; i <= i2; i++) {
+ if (basis[i] > 0.0f) {
+ *end = i;
+ if (*start == 1000)
+ *start = i;
+ }
+ }
}
/**
@@ -1192,173 +1202,174 @@ static void basisNurb(float t, short order, int pnts, float *knots, float *basis
*/
void BKE_nurb_makeFaces(const Nurb *nu, float *coord_array, int rowstride, int resolu, int resolv)
{
- BPoint *bp;
- float *basisu, *basis, *basisv, *sum, *fp, *in;
- float u, v, ustart, uend, ustep, vstart, vend, vstep, sumdiv;
- int i, j, iofs, jofs, cycl, len, curu, curv;
- int istart, iend, jsta, jen, *jstart, *jend, ratcomp;
-
- int totu = nu->pntsu * resolu, totv = nu->pntsv * resolv;
-
- if (nu->knotsu == NULL || nu->knotsv == NULL)
- return;
- if (nu->orderu > nu->pntsu)
- return;
- if (nu->orderv > nu->pntsv)
- return;
- if (coord_array == NULL)
- return;
-
- /* allocate and initialize */
- len = totu * totv;
- if (len == 0)
- return;
-
- sum = (float *)MEM_calloc_arrayN(len, sizeof(float), "makeNurbfaces1");
-
- bp = nu->bp;
- i = nu->pntsu * nu->pntsv;
- ratcomp = 0;
- while (i--) {
- if (bp->vec[3] != 1.0f) {
- ratcomp = 1;
- break;
- }
- bp++;
- }
-
- fp = nu->knotsu;
- ustart = fp[nu->orderu - 1];
- if (nu->flagu & CU_NURB_CYCLIC)
- uend = fp[nu->pntsu + nu->orderu - 1];
- else
- uend = fp[nu->pntsu];
- ustep = (uend - ustart) / ((nu->flagu & CU_NURB_CYCLIC) ? totu : totu - 1);
-
- basisu = (float *)MEM_malloc_arrayN(KNOTSU(nu), sizeof(float), "makeNurbfaces3");
-
- fp = nu->knotsv;
- vstart = fp[nu->orderv - 1];
-
- if (nu->flagv & CU_NURB_CYCLIC)
- vend = fp[nu->pntsv + nu->orderv - 1];
- else
- vend = fp[nu->pntsv];
- vstep = (vend - vstart) / ((nu->flagv & CU_NURB_CYCLIC) ? totv : totv - 1);
-
- len = KNOTSV(nu);
- basisv = (float *)MEM_malloc_arrayN(len * totv, sizeof(float), "makeNurbfaces3");
- jstart = (int *)MEM_malloc_arrayN(totv, sizeof(float), "makeNurbfaces4");
- jend = (int *)MEM_malloc_arrayN(totv, sizeof(float), "makeNurbfaces5");
-
- /* precalculation of basisv and jstart, jend */
- if (nu->flagv & CU_NURB_CYCLIC)
- cycl = nu->orderv - 1;
- else cycl = 0;
- v = vstart;
- basis = basisv;
- curv = totv;
- while (curv--) {
- basisNurb(v, nu->orderv, nu->pntsv + cycl, nu->knotsv, basis, jstart + curv, jend + curv);
- basis += KNOTSV(nu);
- v += vstep;
- }
-
- if (nu->flagu & CU_NURB_CYCLIC)
- cycl = nu->orderu - 1;
- else
- cycl = 0;
- in = coord_array;
- u = ustart;
- curu = totu;
- while (curu--) {
- basisNurb(u, nu->orderu, nu->pntsu + cycl, nu->knotsu, basisu, &istart, &iend);
-
- basis = basisv;
- curv = totv;
- while (curv--) {
- jsta = jstart[curv];
- jen = jend[curv];
-
- /* calculate sum */
- sumdiv = 0.0;
- fp = sum;
-
- for (j = jsta; j <= jen; j++) {
-
- if (j >= nu->pntsv)
- jofs = (j - nu->pntsv);
- else
- jofs = j;
- bp = nu->bp + nu->pntsu * jofs + istart - 1;
-
- for (i = istart; i <= iend; i++, fp++) {
- if (i >= nu->pntsu) {
- iofs = i - nu->pntsu;
- bp = nu->bp + nu->pntsu * jofs + iofs;
- }
- else
- bp++;
-
- if (ratcomp) {
- *fp = basisu[i] * basis[j] * bp->vec[3];
- sumdiv += *fp;
- }
- else
- *fp = basisu[i] * basis[j];
- }
- }
-
- if (ratcomp) {
- fp = sum;
- for (j = jsta; j <= jen; j++) {
- for (i = istart; i <= iend; i++, fp++) {
- *fp /= sumdiv;
- }
- }
- }
-
- zero_v3(in);
-
- /* one! (1.0) real point now */
- fp = sum;
- for (j = jsta; j <= jen; j++) {
-
- if (j >= nu->pntsv)
- jofs = (j - nu->pntsv);
- else
- jofs = j;
- bp = nu->bp + nu->pntsu * jofs + istart - 1;
-
- for (i = istart; i <= iend; i++, fp++) {
- if (i >= nu->pntsu) {
- iofs = i - nu->pntsu;
- bp = nu->bp + nu->pntsu * jofs + iofs;
- }
- else
- bp++;
-
- if (*fp != 0.0f) {
- madd_v3_v3fl(in, bp->vec, *fp);
- }
- }
- }
-
- in += 3;
- basis += KNOTSV(nu);
- }
- u += ustep;
- if (rowstride != 0) {
- in = (float *)(((unsigned char *)in) + (rowstride - 3 * totv * sizeof(*in)));
- }
- }
-
- /* free */
- MEM_freeN(sum);
- MEM_freeN(basisu);
- MEM_freeN(basisv);
- MEM_freeN(jstart);
- MEM_freeN(jend);
+ BPoint *bp;
+ float *basisu, *basis, *basisv, *sum, *fp, *in;
+ float u, v, ustart, uend, ustep, vstart, vend, vstep, sumdiv;
+ int i, j, iofs, jofs, cycl, len, curu, curv;
+ int istart, iend, jsta, jen, *jstart, *jend, ratcomp;
+
+ int totu = nu->pntsu * resolu, totv = nu->pntsv * resolv;
+
+ if (nu->knotsu == NULL || nu->knotsv == NULL)
+ return;
+ if (nu->orderu > nu->pntsu)
+ return;
+ if (nu->orderv > nu->pntsv)
+ return;
+ if (coord_array == NULL)
+ return;
+
+ /* allocate and initialize */
+ len = totu * totv;
+ if (len == 0)
+ return;
+
+ sum = (float *)MEM_calloc_arrayN(len, sizeof(float), "makeNurbfaces1");
+
+ bp = nu->bp;
+ i = nu->pntsu * nu->pntsv;
+ ratcomp = 0;
+ while (i--) {
+ if (bp->vec[3] != 1.0f) {
+ ratcomp = 1;
+ break;
+ }
+ bp++;
+ }
+
+ fp = nu->knotsu;
+ ustart = fp[nu->orderu - 1];
+ if (nu->flagu & CU_NURB_CYCLIC)
+ uend = fp[nu->pntsu + nu->orderu - 1];
+ else
+ uend = fp[nu->pntsu];
+ ustep = (uend - ustart) / ((nu->flagu & CU_NURB_CYCLIC) ? totu : totu - 1);
+
+ basisu = (float *)MEM_malloc_arrayN(KNOTSU(nu), sizeof(float), "makeNurbfaces3");
+
+ fp = nu->knotsv;
+ vstart = fp[nu->orderv - 1];
+
+ if (nu->flagv & CU_NURB_CYCLIC)
+ vend = fp[nu->pntsv + nu->orderv - 1];
+ else
+ vend = fp[nu->pntsv];
+ vstep = (vend - vstart) / ((nu->flagv & CU_NURB_CYCLIC) ? totv : totv - 1);
+
+ len = KNOTSV(nu);
+ basisv = (float *)MEM_malloc_arrayN(len * totv, sizeof(float), "makeNurbfaces3");
+ jstart = (int *)MEM_malloc_arrayN(totv, sizeof(float), "makeNurbfaces4");
+ jend = (int *)MEM_malloc_arrayN(totv, sizeof(float), "makeNurbfaces5");
+
+ /* precalculation of basisv and jstart, jend */
+ if (nu->flagv & CU_NURB_CYCLIC)
+ cycl = nu->orderv - 1;
+ else
+ cycl = 0;
+ v = vstart;
+ basis = basisv;
+ curv = totv;
+ while (curv--) {
+ basisNurb(v, nu->orderv, nu->pntsv + cycl, nu->knotsv, basis, jstart + curv, jend + curv);
+ basis += KNOTSV(nu);
+ v += vstep;
+ }
+
+ if (nu->flagu & CU_NURB_CYCLIC)
+ cycl = nu->orderu - 1;
+ else
+ cycl = 0;
+ in = coord_array;
+ u = ustart;
+ curu = totu;
+ while (curu--) {
+ basisNurb(u, nu->orderu, nu->pntsu + cycl, nu->knotsu, basisu, &istart, &iend);
+
+ basis = basisv;
+ curv = totv;
+ while (curv--) {
+ jsta = jstart[curv];
+ jen = jend[curv];
+
+ /* calculate sum */
+ sumdiv = 0.0;
+ fp = sum;
+
+ for (j = jsta; j <= jen; j++) {
+
+ if (j >= nu->pntsv)
+ jofs = (j - nu->pntsv);
+ else
+ jofs = j;
+ bp = nu->bp + nu->pntsu * jofs + istart - 1;
+
+ for (i = istart; i <= iend; i++, fp++) {
+ if (i >= nu->pntsu) {
+ iofs = i - nu->pntsu;
+ bp = nu->bp + nu->pntsu * jofs + iofs;
+ }
+ else
+ bp++;
+
+ if (ratcomp) {
+ *fp = basisu[i] * basis[j] * bp->vec[3];
+ sumdiv += *fp;
+ }
+ else
+ *fp = basisu[i] * basis[j];
+ }
+ }
+
+ if (ratcomp) {
+ fp = sum;
+ for (j = jsta; j <= jen; j++) {
+ for (i = istart; i <= iend; i++, fp++) {
+ *fp /= sumdiv;
+ }
+ }
+ }
+
+ zero_v3(in);
+
+ /* one! (1.0) real point now */
+ fp = sum;
+ for (j = jsta; j <= jen; j++) {
+
+ if (j >= nu->pntsv)
+ jofs = (j - nu->pntsv);
+ else
+ jofs = j;
+ bp = nu->bp + nu->pntsu * jofs + istart - 1;
+
+ for (i = istart; i <= iend; i++, fp++) {
+ if (i >= nu->pntsu) {
+ iofs = i - nu->pntsu;
+ bp = nu->bp + nu->pntsu * jofs + iofs;
+ }
+ else
+ bp++;
+
+ if (*fp != 0.0f) {
+ madd_v3_v3fl(in, bp->vec, *fp);
+ }
+ }
+ }
+
+ in += 3;
+ basis += KNOTSV(nu);
+ }
+ u += ustep;
+ if (rowstride != 0) {
+ in = (float *)(((unsigned char *)in) + (rowstride - 3 * totv * sizeof(*in)));
+ }
+ }
+
+ /* free */
+ MEM_freeN(sum);
+ MEM_freeN(basisu);
+ MEM_freeN(basisv);
+ MEM_freeN(jstart);
+ MEM_freeN(jend);
}
/**
@@ -1366,129 +1377,136 @@ void BKE_nurb_makeFaces(const Nurb *nu, float *coord_array, int rowstride, int r
* \param tilt_array: set when non-NULL
* \param radius_array: set when non-NULL
*/
-void BKE_nurb_makeCurve(
- const Nurb *nu, float *coord_array, float *tilt_array, float *radius_array, float *weight_array,
- int resolu, int stride)
-{
- const float eps = 1e-6f;
- BPoint *bp;
- float u, ustart, uend, ustep, sumdiv;
- float *basisu, *sum, *fp;
- float *coord_fp = coord_array, *tilt_fp = tilt_array, *radius_fp = radius_array, *weight_fp = weight_array;
- int i, len, istart, iend, cycl;
-
- if (nu->knotsu == NULL)
- return;
- if (nu->orderu > nu->pntsu)
- return;
- if (coord_array == NULL)
- return;
-
- /* allocate and initialize */
- len = nu->pntsu;
- if (len == 0)
- return;
- sum = (float *)MEM_calloc_arrayN(len, sizeof(float), "makeNurbcurve1");
-
- resolu = (resolu * SEGMENTSU(nu));
-
- if (resolu == 0) {
- MEM_freeN(sum);
- return;
- }
-
- fp = nu->knotsu;
- ustart = fp[nu->orderu - 1];
- if (nu->flagu & CU_NURB_CYCLIC)
- uend = fp[nu->pntsu + nu->orderu - 1];
- else
- uend = fp[nu->pntsu];
- ustep = (uend - ustart) / (resolu - ((nu->flagu & CU_NURB_CYCLIC) ? 0 : 1));
-
- basisu = (float *)MEM_malloc_arrayN(KNOTSU(nu), sizeof(float), "makeNurbcurve3");
-
- if (nu->flagu & CU_NURB_CYCLIC)
- cycl = nu->orderu - 1;
- else
- cycl = 0;
-
- u = ustart;
- while (resolu--) {
- basisNurb(u, nu->orderu, nu->pntsu + cycl, nu->knotsu, basisu, &istart, &iend);
-
- /* calc sum */
- sumdiv = 0.0;
- fp = sum;
- bp = nu->bp + istart - 1;
- for (i = istart; i <= iend; i++, fp++) {
- if (i >= nu->pntsu)
- bp = nu->bp + (i - nu->pntsu);
- else
- bp++;
-
- *fp = basisu[i] * bp->vec[3];
- sumdiv += *fp;
- }
- if ((sumdiv != 0.0f) && (sumdiv < 1.0f - eps || sumdiv > 1.0f + eps)) {
- /* is normalizing needed? */
- fp = sum;
- for (i = istart; i <= iend; i++, fp++) {
- *fp /= sumdiv;
- }
- }
-
- zero_v3(coord_fp);
-
- /* one! (1.0) real point */
- fp = sum;
- bp = nu->bp + istart - 1;
- for (i = istart; i <= iend; i++, fp++) {
- if (i >= nu->pntsu)
- bp = nu->bp + (i - nu->pntsu);
- else
- bp++;
-
- if (*fp != 0.0f) {
- madd_v3_v3fl(coord_fp, bp->vec, *fp);
-
- if (tilt_fp)
- (*tilt_fp) += (*fp) * bp->tilt;
-
- if (radius_fp)
- (*radius_fp) += (*fp) * bp->radius;
-
- if (weight_fp)
- (*weight_fp) += (*fp) * bp->weight;
- }
- }
-
- coord_fp = POINTER_OFFSET(coord_fp, stride);
-
- if (tilt_fp)
- tilt_fp = POINTER_OFFSET(tilt_fp, stride);
- if (radius_fp)
- radius_fp = POINTER_OFFSET(radius_fp, stride);
- if (weight_fp)
- weight_fp = POINTER_OFFSET(weight_fp, stride);
-
- u += ustep;
- }
-
- /* free */
- MEM_freeN(sum);
- MEM_freeN(basisu);
+void BKE_nurb_makeCurve(const Nurb *nu,
+ float *coord_array,
+ float *tilt_array,
+ float *radius_array,
+ float *weight_array,
+ int resolu,
+ int stride)
+{
+ const float eps = 1e-6f;
+ BPoint *bp;
+ float u, ustart, uend, ustep, sumdiv;
+ float *basisu, *sum, *fp;
+ float *coord_fp = coord_array, *tilt_fp = tilt_array, *radius_fp = radius_array,
+ *weight_fp = weight_array;
+ int i, len, istart, iend, cycl;
+
+ if (nu->knotsu == NULL)
+ return;
+ if (nu->orderu > nu->pntsu)
+ return;
+ if (coord_array == NULL)
+ return;
+
+ /* allocate and initialize */
+ len = nu->pntsu;
+ if (len == 0)
+ return;
+ sum = (float *)MEM_calloc_arrayN(len, sizeof(float), "makeNurbcurve1");
+
+ resolu = (resolu * SEGMENTSU(nu));
+
+ if (resolu == 0) {
+ MEM_freeN(sum);
+ return;
+ }
+
+ fp = nu->knotsu;
+ ustart = fp[nu->orderu - 1];
+ if (nu->flagu & CU_NURB_CYCLIC)
+ uend = fp[nu->pntsu + nu->orderu - 1];
+ else
+ uend = fp[nu->pntsu];
+ ustep = (uend - ustart) / (resolu - ((nu->flagu & CU_NURB_CYCLIC) ? 0 : 1));
+
+ basisu = (float *)MEM_malloc_arrayN(KNOTSU(nu), sizeof(float), "makeNurbcurve3");
+
+ if (nu->flagu & CU_NURB_CYCLIC)
+ cycl = nu->orderu - 1;
+ else
+ cycl = 0;
+
+ u = ustart;
+ while (resolu--) {
+ basisNurb(u, nu->orderu, nu->pntsu + cycl, nu->knotsu, basisu, &istart, &iend);
+
+ /* calc sum */
+ sumdiv = 0.0;
+ fp = sum;
+ bp = nu->bp + istart - 1;
+ for (i = istart; i <= iend; i++, fp++) {
+ if (i >= nu->pntsu)
+ bp = nu->bp + (i - nu->pntsu);
+ else
+ bp++;
+
+ *fp = basisu[i] * bp->vec[3];
+ sumdiv += *fp;
+ }
+ if ((sumdiv != 0.0f) && (sumdiv < 1.0f - eps || sumdiv > 1.0f + eps)) {
+ /* is normalizing needed? */
+ fp = sum;
+ for (i = istart; i <= iend; i++, fp++) {
+ *fp /= sumdiv;
+ }
+ }
+
+ zero_v3(coord_fp);
+
+ /* one! (1.0) real point */
+ fp = sum;
+ bp = nu->bp + istart - 1;
+ for (i = istart; i <= iend; i++, fp++) {
+ if (i >= nu->pntsu)
+ bp = nu->bp + (i - nu->pntsu);
+ else
+ bp++;
+
+ if (*fp != 0.0f) {
+ madd_v3_v3fl(coord_fp, bp->vec, *fp);
+
+ if (tilt_fp)
+ (*tilt_fp) += (*fp) * bp->tilt;
+
+ if (radius_fp)
+ (*radius_fp) += (*fp) * bp->radius;
+
+ if (weight_fp)
+ (*weight_fp) += (*fp) * bp->weight;
+ }
+ }
+
+ coord_fp = POINTER_OFFSET(coord_fp, stride);
+
+ if (tilt_fp)
+ tilt_fp = POINTER_OFFSET(tilt_fp, stride);
+ if (radius_fp)
+ radius_fp = POINTER_OFFSET(radius_fp, stride);
+ if (weight_fp)
+ weight_fp = POINTER_OFFSET(weight_fp, stride);
+
+ u += ustep;
+ }
+
+ /* free */
+ MEM_freeN(sum);
+ MEM_freeN(basisu);
}
/**
* Calculate the length for arrays filled in by #BKE_curve_calc_coords_axis.
*/
-unsigned int BKE_curve_calc_coords_axis_len(
- const unsigned int bezt_array_len, const unsigned int resolu,
- const bool is_cyclic, const bool use_cyclic_duplicate_endpoint)
+unsigned int BKE_curve_calc_coords_axis_len(const unsigned int bezt_array_len,
+ const unsigned int resolu,
+ const bool is_cyclic,
+ const bool use_cyclic_duplicate_endpoint)
{
- const unsigned int segments = bezt_array_len - (is_cyclic ? 0 : 1);
- const unsigned int points_len = (segments * resolu) + (is_cyclic ? (use_cyclic_duplicate_endpoint) : 1);
- return points_len;
+ const unsigned int segments = bezt_array_len - (is_cyclic ? 0 : 1);
+ const unsigned int points_len = (segments * resolu) +
+ (is_cyclic ? (use_cyclic_duplicate_endpoint) : 1);
+ return points_len;
}
/**
@@ -1497,780 +1515,818 @@ unsigned int BKE_curve_calc_coords_axis_len(
*
* \param use_cyclic_duplicate_endpoint: Duplicate values at the beginning & end of the array.
*/
-void BKE_curve_calc_coords_axis(
- const BezTriple *bezt_array, const unsigned int bezt_array_len, const unsigned int resolu,
- const bool is_cyclic, const bool use_cyclic_duplicate_endpoint,
- /* array params */
- const unsigned int axis, const unsigned int stride,
- float *r_points)
-{
- const unsigned int points_len = BKE_curve_calc_coords_axis_len(
- bezt_array_len, resolu, is_cyclic, use_cyclic_duplicate_endpoint);
- float *r_points_offset = r_points;
-
- const unsigned int resolu_stride = resolu * stride;
- const unsigned int bezt_array_last = bezt_array_len - 1;
-
- for (unsigned int i = 0; i < bezt_array_last; i++) {
- const BezTriple *bezt_curr = &bezt_array[i];
- const BezTriple *bezt_next = &bezt_array[i + 1];
- BKE_curve_forward_diff_bezier(
- bezt_curr->vec[1][axis], bezt_curr->vec[2][axis],
- bezt_next->vec[0][axis], bezt_next->vec[1][axis],
- r_points_offset, (int)resolu, stride);
- r_points_offset = POINTER_OFFSET(r_points_offset, resolu_stride);
- }
-
- if (is_cyclic) {
- const BezTriple *bezt_curr = &bezt_array[bezt_array_last];
- const BezTriple *bezt_next = &bezt_array[0];
- BKE_curve_forward_diff_bezier(
- bezt_curr->vec[1][axis], bezt_curr->vec[2][axis],
- bezt_next->vec[0][axis], bezt_next->vec[1][axis],
- r_points_offset, (int)resolu, stride);
- r_points_offset = POINTER_OFFSET(r_points_offset, resolu_stride);
- if (use_cyclic_duplicate_endpoint) {
- *r_points_offset = *r_points;
- r_points_offset = POINTER_OFFSET(r_points_offset, stride);
- }
- }
- else {
- float *r_points_last = POINTER_OFFSET(r_points, bezt_array_last * resolu_stride);
- *r_points_last = bezt_array[bezt_array_last].vec[1][axis];
- r_points_offset = POINTER_OFFSET(r_points_offset, stride);
- }
-
- BLI_assert(POINTER_OFFSET(r_points, points_len * stride) == r_points_offset);
- UNUSED_VARS_NDEBUG(points_len);
+void BKE_curve_calc_coords_axis(const BezTriple *bezt_array,
+ const unsigned int bezt_array_len,
+ const unsigned int resolu,
+ const bool is_cyclic,
+ const bool use_cyclic_duplicate_endpoint,
+ /* array params */
+ const unsigned int axis,
+ const unsigned int stride,
+ float *r_points)
+{
+ const unsigned int points_len = BKE_curve_calc_coords_axis_len(
+ bezt_array_len, resolu, is_cyclic, use_cyclic_duplicate_endpoint);
+ float *r_points_offset = r_points;
+
+ const unsigned int resolu_stride = resolu * stride;
+ const unsigned int bezt_array_last = bezt_array_len - 1;
+
+ for (unsigned int i = 0; i < bezt_array_last; i++) {
+ const BezTriple *bezt_curr = &bezt_array[i];
+ const BezTriple *bezt_next = &bezt_array[i + 1];
+ BKE_curve_forward_diff_bezier(bezt_curr->vec[1][axis],
+ bezt_curr->vec[2][axis],
+ bezt_next->vec[0][axis],
+ bezt_next->vec[1][axis],
+ r_points_offset,
+ (int)resolu,
+ stride);
+ r_points_offset = POINTER_OFFSET(r_points_offset, resolu_stride);
+ }
+
+ if (is_cyclic) {
+ const BezTriple *bezt_curr = &bezt_array[bezt_array_last];
+ const BezTriple *bezt_next = &bezt_array[0];
+ BKE_curve_forward_diff_bezier(bezt_curr->vec[1][axis],
+ bezt_curr->vec[2][axis],
+ bezt_next->vec[0][axis],
+ bezt_next->vec[1][axis],
+ r_points_offset,
+ (int)resolu,
+ stride);
+ r_points_offset = POINTER_OFFSET(r_points_offset, resolu_stride);
+ if (use_cyclic_duplicate_endpoint) {
+ *r_points_offset = *r_points;
+ r_points_offset = POINTER_OFFSET(r_points_offset, stride);
+ }
+ }
+ else {
+ float *r_points_last = POINTER_OFFSET(r_points, bezt_array_last * resolu_stride);
+ *r_points_last = bezt_array[bezt_array_last].vec[1][axis];
+ r_points_offset = POINTER_OFFSET(r_points_offset, stride);
+ }
+
+ BLI_assert(POINTER_OFFSET(r_points, points_len * stride) == r_points_offset);
+ UNUSED_VARS_NDEBUG(points_len);
}
/* forward differencing method for bezier curve */
-void BKE_curve_forward_diff_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride)
-{
- float rt0, rt1, rt2, rt3, f;
- int a;
-
- f = (float)it;
- rt0 = q0;
- rt1 = 3.0f * (q1 - q0) / f;
- f *= f;
- rt2 = 3.0f * (q0 - 2.0f * q1 + q2) / f;
- f *= it;
- rt3 = (q3 - q0 + 3.0f * (q1 - q2)) / f;
-
- q0 = rt0;
- q1 = rt1 + rt2 + rt3;
- q2 = 2 * rt2 + 6 * rt3;
- q3 = 6 * rt3;
-
- for (a = 0; a <= it; a++) {
- *p = q0;
- p = POINTER_OFFSET(p, stride);
- q0 += q1;
- q1 += q2;
- q2 += q3;
- }
+void BKE_curve_forward_diff_bezier(
+ float q0, float q1, float q2, float q3, float *p, int it, int stride)
+{
+ float rt0, rt1, rt2, rt3, f;
+ int a;
+
+ f = (float)it;
+ rt0 = q0;
+ rt1 = 3.0f * (q1 - q0) / f;
+ f *= f;
+ rt2 = 3.0f * (q0 - 2.0f * q1 + q2) / f;
+ f *= it;
+ rt3 = (q3 - q0 + 3.0f * (q1 - q2)) / f;
+
+ q0 = rt0;
+ q1 = rt1 + rt2 + rt3;
+ q2 = 2 * rt2 + 6 * rt3;
+ q3 = 6 * rt3;
+
+ for (a = 0; a <= it; a++) {
+ *p = q0;
+ p = POINTER_OFFSET(p, stride);
+ q0 += q1;
+ q1 += q2;
+ q2 += q3;
+ }
}
/* forward differencing method for first derivative of cubic bezier curve */
-void BKE_curve_forward_diff_tangent_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride)
-{
- float rt0, rt1, rt2, f;
- int a;
-
- f = 1.0f / (float)it;
-
- rt0 = 3.0f * (q1 - q0);
- rt1 = f * (3.0f * (q3 - q0) + 9.0f * (q1 - q2));
- rt2 = 6.0f * (q0 + q2) - 12.0f * q1;
-
- q0 = rt0;
- q1 = f * (rt1 + rt2);
- q2 = 2.0f * f * rt1;
-
- for (a = 0; a <= it; a++) {
- *p = q0;
- p = POINTER_OFFSET(p, stride);
- q0 += q1;
- q1 += q2;
- }
-}
-
-static void forward_diff_bezier_cotangent(const float p0[3], const float p1[3], const float p2[3], const float p3[3],
- float p[3], int it, int stride)
-{
- /* note that these are not perpendicular to the curve
- * they need to be rotated for this,
- *
- * This could also be optimized like BKE_curve_forward_diff_bezier */
- int a;
- for (a = 0; a <= it; a++) {
- float t = (float)a / (float)it;
-
- int i;
- for (i = 0; i < 3; i++) {
- p[i] = (-6.0f * t + 6.0f) * p0[i] +
- ( 18.0f * t - 12.0f) * p1[i] +
- (-18.0f * t + 6.0f) * p2[i] +
- ( 6.0f * t) * p3[i];
- }
- normalize_v3(p);
- p = POINTER_OFFSET(p, stride);
- }
+void BKE_curve_forward_diff_tangent_bezier(
+ float q0, float q1, float q2, float q3, float *p, int it, int stride)
+{
+ float rt0, rt1, rt2, f;
+ int a;
+
+ f = 1.0f / (float)it;
+
+ rt0 = 3.0f * (q1 - q0);
+ rt1 = f * (3.0f * (q3 - q0) + 9.0f * (q1 - q2));
+ rt2 = 6.0f * (q0 + q2) - 12.0f * q1;
+
+ q0 = rt0;
+ q1 = f * (rt1 + rt2);
+ q2 = 2.0f * f * rt1;
+
+ for (a = 0; a <= it; a++) {
+ *p = q0;
+ p = POINTER_OFFSET(p, stride);
+ q0 += q1;
+ q1 += q2;
+ }
+}
+
+static void forward_diff_bezier_cotangent(const float p0[3],
+ const float p1[3],
+ const float p2[3],
+ const float p3[3],
+ float p[3],
+ int it,
+ int stride)
+{
+ /* note that these are not perpendicular to the curve
+ * they need to be rotated for this,
+ *
+ * This could also be optimized like BKE_curve_forward_diff_bezier */
+ int a;
+ for (a = 0; a <= it; a++) {
+ float t = (float)a / (float)it;
+
+ int i;
+ for (i = 0; i < 3; i++) {
+ p[i] = (-6.0f * t + 6.0f) * p0[i] + (18.0f * t - 12.0f) * p1[i] +
+ (-18.0f * t + 6.0f) * p2[i] + (6.0f * t) * p3[i];
+ }
+ normalize_v3(p);
+ p = POINTER_OFFSET(p, stride);
+ }
}
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
float *BKE_curve_surf_make_orco(Object *ob)
{
- /* Note: this function is used in convertblender only atm, so
- * suppose nonzero curve's render resolution should always be used */
- Curve *cu = ob->data;
- Nurb *nu;
- int a, b, tot = 0;
- int sizeu, sizev;
- int resolu, resolv;
- float *fp, *coord_array;
-
- /* first calculate the size of the datablock */
- nu = cu->nurb.first;
- while (nu) {
- /* as we want to avoid the seam in a cyclic nurbs
- * texture wrapping, reserve extra orco data space to save these extra needed
- * vertex based UV coordinates for the meridian vertices.
- * Vertices on the 0/2pi boundary are not duplicated inside the displist but later in
- * the renderface/vert construction.
- *
- * See also convertblender.c: init_render_surf()
- */
-
- resolu = cu->resolu_ren ? cu->resolu_ren : nu->resolu;
- resolv = cu->resolv_ren ? cu->resolv_ren : nu->resolv;
-
- sizeu = nu->pntsu * resolu;
- sizev = nu->pntsv * resolv;
- if (nu->flagu & CU_NURB_CYCLIC) sizeu++;
- if (nu->flagv & CU_NURB_CYCLIC) sizev++;
- if (nu->pntsv > 1) tot += sizeu * sizev;
-
- nu = nu->next;
- }
- /* makeNurbfaces wants zeros */
- fp = coord_array = MEM_calloc_arrayN(tot, 3 * sizeof(float), "make_orco");
-
- nu = cu->nurb.first;
- while (nu) {
- resolu = cu->resolu_ren ? cu->resolu_ren : nu->resolu;
- resolv = cu->resolv_ren ? cu->resolv_ren : nu->resolv;
-
- if (nu->pntsv > 1) {
- sizeu = nu->pntsu * resolu;
- sizev = nu->pntsv * resolv;
-
- if (nu->flagu & CU_NURB_CYCLIC)
- sizeu++;
- if (nu->flagv & CU_NURB_CYCLIC)
- sizev++;
-
- if (cu->flag & CU_UV_ORCO) {
- for (b = 0; b < sizeu; b++) {
- for (a = 0; a < sizev; a++) {
-
- if (sizev < 2)
- fp[0] = 0.0f;
- else
- fp[0] = -1.0f + 2.0f * ((float)a) / (sizev - 1);
-
- if (sizeu < 2)
- fp[1] = 0.0f;
- else
- fp[1] = -1.0f + 2.0f * ((float)b) / (sizeu - 1);
-
- fp[2] = 0.0;
-
- fp += 3;
- }
- }
- }
- else {
- int size = (nu->pntsu * resolu) * (nu->pntsv * resolv) * 3 * sizeof(float);
- float *_tdata = MEM_mallocN(size, "temp data");
- float *tdata = _tdata;
-
- BKE_nurb_makeFaces(nu, tdata, 0, resolu, resolv);
-
- for (b = 0; b < sizeu; b++) {
- int use_b = b;
- if (b == sizeu - 1 && (nu->flagu & CU_NURB_CYCLIC))
- use_b = false;
-
- for (a = 0; a < sizev; a++) {
- int use_a = a;
- if (a == sizev - 1 && (nu->flagv & CU_NURB_CYCLIC))
- use_a = false;
-
- tdata = _tdata + 3 * (use_b * (nu->pntsv * resolv) + use_a);
-
- fp[0] = (tdata[0] - cu->loc[0]) / cu->size[0];
- fp[1] = (tdata[1] - cu->loc[1]) / cu->size[1];
- fp[2] = (tdata[2] - cu->loc[2]) / cu->size[2];
- fp += 3;
- }
- }
-
- MEM_freeN(_tdata);
- }
- }
- nu = nu->next;
- }
-
- return coord_array;
+ /* Note: this function is used in convertblender only atm, so
+ * suppose nonzero curve's render resolution should always be used */
+ Curve *cu = ob->data;
+ Nurb *nu;
+ int a, b, tot = 0;
+ int sizeu, sizev;
+ int resolu, resolv;
+ float *fp, *coord_array;
+
+ /* first calculate the size of the datablock */
+ nu = cu->nurb.first;
+ while (nu) {
+ /* as we want to avoid the seam in a cyclic nurbs
+ * texture wrapping, reserve extra orco data space to save these extra needed
+ * vertex based UV coordinates for the meridian vertices.
+ * Vertices on the 0/2pi boundary are not duplicated inside the displist but later in
+ * the renderface/vert construction.
+ *
+ * See also convertblender.c: init_render_surf()
+ */
+
+ resolu = cu->resolu_ren ? cu->resolu_ren : nu->resolu;
+ resolv = cu->resolv_ren ? cu->resolv_ren : nu->resolv;
+
+ sizeu = nu->pntsu * resolu;
+ sizev = nu->pntsv * resolv;
+ if (nu->flagu & CU_NURB_CYCLIC)
+ sizeu++;
+ if (nu->flagv & CU_NURB_CYCLIC)
+ sizev++;
+ if (nu->pntsv > 1)
+ tot += sizeu * sizev;
+
+ nu = nu->next;
+ }
+ /* makeNurbfaces wants zeros */
+ fp = coord_array = MEM_calloc_arrayN(tot, 3 * sizeof(float), "make_orco");
+
+ nu = cu->nurb.first;
+ while (nu) {
+ resolu = cu->resolu_ren ? cu->resolu_ren : nu->resolu;
+ resolv = cu->resolv_ren ? cu->resolv_ren : nu->resolv;
+
+ if (nu->pntsv > 1) {
+ sizeu = nu->pntsu * resolu;
+ sizev = nu->pntsv * resolv;
+
+ if (nu->flagu & CU_NURB_CYCLIC)
+ sizeu++;
+ if (nu->flagv & CU_NURB_CYCLIC)
+ sizev++;
+
+ if (cu->flag & CU_UV_ORCO) {
+ for (b = 0; b < sizeu; b++) {
+ for (a = 0; a < sizev; a++) {
+
+ if (sizev < 2)
+ fp[0] = 0.0f;
+ else
+ fp[0] = -1.0f + 2.0f * ((float)a) / (sizev - 1);
+
+ if (sizeu < 2)
+ fp[1] = 0.0f;
+ else
+ fp[1] = -1.0f + 2.0f * ((float)b) / (sizeu - 1);
+
+ fp[2] = 0.0;
+
+ fp += 3;
+ }
+ }
+ }
+ else {
+ int size = (nu->pntsu * resolu) * (nu->pntsv * resolv) * 3 * sizeof(float);
+ float *_tdata = MEM_mallocN(size, "temp data");
+ float *tdata = _tdata;
+
+ BKE_nurb_makeFaces(nu, tdata, 0, resolu, resolv);
+
+ for (b = 0; b < sizeu; b++) {
+ int use_b = b;
+ if (b == sizeu - 1 && (nu->flagu & CU_NURB_CYCLIC))
+ use_b = false;
+
+ for (a = 0; a < sizev; a++) {
+ int use_a = a;
+ if (a == sizev - 1 && (nu->flagv & CU_NURB_CYCLIC))
+ use_a = false;
+
+ tdata = _tdata + 3 * (use_b * (nu->pntsv * resolv) + use_a);
+
+ fp[0] = (tdata[0] - cu->loc[0]) / cu->size[0];
+ fp[1] = (tdata[1] - cu->loc[1]) / cu->size[1];
+ fp[2] = (tdata[2] - cu->loc[2]) / cu->size[2];
+ fp += 3;
+ }
+ }
+
+ MEM_freeN(_tdata);
+ }
+ }
+ nu = nu->next;
+ }
+
+ return coord_array;
}
-
/* NOTE: This routine is tied to the order of vertex
* built by displist and as passed to the renderer.
*/
float *BKE_curve_make_orco(Depsgraph *depsgraph, Scene *scene, Object *ob, int *r_numVerts)
{
- Curve *cu = ob->data;
- DispList *dl;
- int u, v, numVerts;
- float *fp, *coord_array;
- ListBase disp = {NULL, NULL};
-
- BKE_displist_make_curveTypes_forOrco(depsgraph, scene, ob, &disp, NULL);
-
- numVerts = 0;
- for (dl = disp.first; dl; dl = dl->next) {
- if (dl->type == DL_INDEX3) {
- numVerts += dl->nr;
- }
- else if (dl->type == DL_SURF) {
- /* convertblender.c uses the Surface code for creating renderfaces when cyclic U only
- * (closed circle beveling)
- */
- if (dl->flag & DL_CYCL_U) {
- if (dl->flag & DL_CYCL_V)
- numVerts += (dl->parts + 1) * (dl->nr + 1);
- else
- numVerts += dl->parts * (dl->nr + 1);
- }
- else if (dl->flag & DL_CYCL_V) {
- numVerts += (dl->parts + 1) * dl->nr;
- }
- else
- numVerts += dl->parts * dl->nr;
- }
- }
-
- if (r_numVerts)
- *r_numVerts = numVerts;
-
- fp = coord_array = MEM_malloc_arrayN(numVerts, 3 * sizeof(float), "cu_orco");
- for (dl = disp.first; dl; dl = dl->next) {
- if (dl->type == DL_INDEX3) {
- for (u = 0; u < dl->nr; u++, fp += 3) {
- if (cu->flag & CU_UV_ORCO) {
- fp[0] = 2.0f * u / (dl->nr - 1) - 1.0f;
- fp[1] = 0.0;
- fp[2] = 0.0;
- }
- else {
- copy_v3_v3(fp, &dl->verts[u * 3]);
-
- fp[0] = (fp[0] - cu->loc[0]) / cu->size[0];
- fp[1] = (fp[1] - cu->loc[1]) / cu->size[1];
- fp[2] = (fp[2] - cu->loc[2]) / cu->size[2];
- }
- }
- }
- else if (dl->type == DL_SURF) {
- int sizeu = dl->nr, sizev = dl->parts;
-
- /* exception as handled in convertblender.c too */
- if (dl->flag & DL_CYCL_U) {
- sizeu++;
- if (dl->flag & DL_CYCL_V)
- sizev++;
- }
- else if (dl->flag & DL_CYCL_V) {
- sizev++;
- }
-
- for (u = 0; u < sizev; u++) {
- for (v = 0; v < sizeu; v++, fp += 3) {
- if (cu->flag & CU_UV_ORCO) {
- fp[0] = 2.0f * u / (sizev - 1) - 1.0f;
- fp[1] = 2.0f * v / (sizeu - 1) - 1.0f;
- fp[2] = 0.0;
- }
- else {
- const float *vert;
- int realv = v % dl->nr;
- int realu = u % dl->parts;
-
- vert = dl->verts + 3 * (dl->nr * realu + realv);
- copy_v3_v3(fp, vert);
-
- fp[0] = (fp[0] - cu->loc[0]) / cu->size[0];
- fp[1] = (fp[1] - cu->loc[1]) / cu->size[1];
- fp[2] = (fp[2] - cu->loc[2]) / cu->size[2];
- }
- }
- }
- }
- }
-
- BKE_displist_free(&disp);
-
- return coord_array;
+ Curve *cu = ob->data;
+ DispList *dl;
+ int u, v, numVerts;
+ float *fp, *coord_array;
+ ListBase disp = {NULL, NULL};
+
+ BKE_displist_make_curveTypes_forOrco(depsgraph, scene, ob, &disp, NULL);
+
+ numVerts = 0;
+ for (dl = disp.first; dl; dl = dl->next) {
+ if (dl->type == DL_INDEX3) {
+ numVerts += dl->nr;
+ }
+ else if (dl->type == DL_SURF) {
+ /* convertblender.c uses the Surface code for creating renderfaces when cyclic U only
+ * (closed circle beveling)
+ */
+ if (dl->flag & DL_CYCL_U) {
+ if (dl->flag & DL_CYCL_V)
+ numVerts += (dl->parts + 1) * (dl->nr + 1);
+ else
+ numVerts += dl->parts * (dl->nr + 1);
+ }
+ else if (dl->flag & DL_CYCL_V) {
+ numVerts += (dl->parts + 1) * dl->nr;
+ }
+ else
+ numVerts += dl->parts * dl->nr;
+ }
+ }
+
+ if (r_numVerts)
+ *r_numVerts = numVerts;
+
+ fp = coord_array = MEM_malloc_arrayN(numVerts, 3 * sizeof(float), "cu_orco");
+ for (dl = disp.first; dl; dl = dl->next) {
+ if (dl->type == DL_INDEX3) {
+ for (u = 0; u < dl->nr; u++, fp += 3) {
+ if (cu->flag & CU_UV_ORCO) {
+ fp[0] = 2.0f * u / (dl->nr - 1) - 1.0f;
+ fp[1] = 0.0;
+ fp[2] = 0.0;
+ }
+ else {
+ copy_v3_v3(fp, &dl->verts[u * 3]);
+
+ fp[0] = (fp[0] - cu->loc[0]) / cu->size[0];
+ fp[1] = (fp[1] - cu->loc[1]) / cu->size[1];
+ fp[2] = (fp[2] - cu->loc[2]) / cu->size[2];
+ }
+ }
+ }
+ else if (dl->type == DL_SURF) {
+ int sizeu = dl->nr, sizev = dl->parts;
+
+ /* exception as handled in convertblender.c too */
+ if (dl->flag & DL_CYCL_U) {
+ sizeu++;
+ if (dl->flag & DL_CYCL_V)
+ sizev++;
+ }
+ else if (dl->flag & DL_CYCL_V) {
+ sizev++;
+ }
+
+ for (u = 0; u < sizev; u++) {
+ for (v = 0; v < sizeu; v++, fp += 3) {
+ if (cu->flag & CU_UV_ORCO) {
+ fp[0] = 2.0f * u / (sizev - 1) - 1.0f;
+ fp[1] = 2.0f * v / (sizeu - 1) - 1.0f;
+ fp[2] = 0.0;
+ }
+ else {
+ const float *vert;
+ int realv = v % dl->nr;
+ int realu = u % dl->parts;
+
+ vert = dl->verts + 3 * (dl->nr * realu + realv);
+ copy_v3_v3(fp, vert);
+
+ fp[0] = (fp[0] - cu->loc[0]) / cu->size[0];
+ fp[1] = (fp[1] - cu->loc[1]) / cu->size[1];
+ fp[2] = (fp[2] - cu->loc[2]) / cu->size[2];
+ }
+ }
+ }
+ }
+ }
+
+ BKE_displist_free(&disp);
+
+ return coord_array;
}
-
/* ***************** BEVEL ****************** */
-void BKE_curve_bevel_make(
- Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *disp,
- const bool for_render, const bool use_render_resolution,
- LinkNode *ob_cyclic_list)
-{
- DispList *dl, *dlnew;
- Curve *bevcu, *cu;
- float *fp, facx, facy, angle, dangle;
- int nr, a;
-
- cu = ob->data;
- BLI_listbase_clear(disp);
-
- /* if a font object is being edited, then do nothing */
-// XXX if ( ob == obedit && ob->type == OB_FONT ) return;
-
- if (cu->bevobj) {
- if (cu->bevobj->type != OB_CURVE)
- return;
-
- bevcu = cu->bevobj->data;
- if (bevcu->ext1 == 0.0f && bevcu->ext2 == 0.0f) {
- ListBase bevdisp = {NULL, NULL};
- facx = cu->bevobj->scale[0];
- facy = cu->bevobj->scale[1];
-
- if (for_render) {
- if (BLI_linklist_index(ob_cyclic_list, cu->bevobj) == -1) {
- BKE_displist_make_curveTypes_forRender(
- depsgraph, scene, cu->bevobj, &bevdisp, NULL, false, use_render_resolution,
- &(LinkNode){ .link = ob, .next = ob_cyclic_list, });
- dl = bevdisp.first;
- }
- else {
- dl = NULL;
- }
- }
- else if (cu->bevobj->runtime.curve_cache) {
- dl = cu->bevobj->runtime.curve_cache->disp.first;
- }
- else {
- BLI_assert(cu->bevobj->runtime.curve_cache != NULL);
- dl = NULL;
- }
-
- while (dl) {
- if (ELEM(dl->type, DL_POLY, DL_SEGM)) {
- dlnew = MEM_mallocN(sizeof(DispList), "makebevelcurve1");
- *dlnew = *dl;
- dlnew->verts = MEM_malloc_arrayN(dl->parts * dl->nr, 3 * sizeof(float), "makebevelcurve1");
- memcpy(dlnew->verts, dl->verts, 3 * sizeof(float) * dl->parts * dl->nr);
-
- if (dlnew->type == DL_SEGM)
- dlnew->flag |= (DL_FRONT_CURVE | DL_BACK_CURVE);
-
- BLI_addtail(disp, dlnew);
- fp = dlnew->verts;
- nr = dlnew->parts * dlnew->nr;
- while (nr--) {
- fp[2] = fp[1] * facy;
- fp[1] = -fp[0] * facx;
- fp[0] = 0.0;
- fp += 3;
- }
- }
- dl = dl->next;
- }
-
- BKE_displist_free(&bevdisp);
- }
- }
- else if (cu->ext1 == 0.0f && cu->ext2 == 0.0f) {
- /* pass */
- }
- else if (cu->ext2 == 0.0f) {
- dl = MEM_callocN(sizeof(DispList), "makebevelcurve2");
- dl->verts = MEM_malloc_arrayN(2, sizeof(float[3]), "makebevelcurve2");
- BLI_addtail(disp, dl);
- dl->type = DL_SEGM;
- dl->parts = 1;
- dl->flag = DL_FRONT_CURVE | DL_BACK_CURVE;
- dl->nr = 2;
-
- fp = dl->verts;
- fp[0] = fp[1] = 0.0;
- fp[2] = -cu->ext1;
- fp[3] = fp[4] = 0.0;
- fp[5] = cu->ext1;
- }
- else if ((cu->flag & (CU_FRONT | CU_BACK)) == 0 && cu->ext1 == 0.0f) { /* we make a full round bevel in that case */
- nr = 4 + 2 * cu->bevresol;
-
- dl = MEM_callocN(sizeof(DispList), "makebevelcurve p1");
- dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p1");
- BLI_addtail(disp, dl);
- dl->type = DL_POLY;
- dl->parts = 1;
- dl->flag = DL_BACK_CURVE;
- dl->nr = nr;
-
- /* a circle */
- fp = dl->verts;
- dangle = (2.0f * (float)M_PI / (nr));
- angle = -(nr - 1) * dangle;
-
- for (a = 0; a < nr; a++) {
- fp[0] = 0.0;
- fp[1] = (cosf(angle) * (cu->ext2));
- fp[2] = (sinf(angle) * (cu->ext2)) - cu->ext1;
- angle += dangle;
- fp += 3;
- }
- }
- else {
- short dnr;
-
- /* bevel now in three parts, for proper vertex normals */
- /* part 1, back */
-
- if ((cu->flag & CU_BACK) || !(cu->flag & CU_FRONT)) {
- dnr = nr = 2 + cu->bevresol;
- if ((cu->flag & (CU_FRONT | CU_BACK)) == 0) {
- nr = 3 + 2 * cu->bevresol;
- }
- dl = MEM_callocN(sizeof(DispList), "makebevelcurve p1");
- dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p1");
- BLI_addtail(disp, dl);
- dl->type = DL_SEGM;
- dl->parts = 1;
- dl->flag = DL_BACK_CURVE;
- dl->nr = nr;
-
- /* half a circle */
- fp = dl->verts;
- dangle = ((float)M_PI_2 / (dnr - 1));
- angle = -(nr - 1) * dangle;
-
- for (a = 0; a < nr; a++) {
- fp[0] = 0.0;
- fp[1] = (float)(cosf(angle) * (cu->ext2));
- fp[2] = (float)(sinf(angle) * (cu->ext2)) - cu->ext1;
- angle += dangle;
- fp += 3;
- }
- }
-
- /* part 2, sidefaces */
- if (cu->ext1 != 0.0f) {
- nr = 2;
-
- dl = MEM_callocN(sizeof(DispList), "makebevelcurve p2");
- dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p2");
- BLI_addtail(disp, dl);
- dl->type = DL_SEGM;
- dl->parts = 1;
- dl->nr = nr;
-
- fp = dl->verts;
- fp[1] = cu->ext2;
- fp[2] = -cu->ext1;
- fp[4] = cu->ext2;
- fp[5] = cu->ext1;
-
- if ((cu->flag & (CU_FRONT | CU_BACK)) == 0) {
- dl = MEM_dupallocN(dl);
- dl->verts = MEM_dupallocN(dl->verts);
- BLI_addtail(disp, dl);
-
- fp = dl->verts;
- fp[1] = -fp[1];
- fp[2] = -fp[2];
- fp[4] = -fp[4];
- fp[5] = -fp[5];
- }
- }
-
- /* part 3, front */
- if ((cu->flag & CU_FRONT) || !(cu->flag & CU_BACK)) {
- dnr = nr = 2 + cu->bevresol;
- if ((cu->flag & (CU_FRONT | CU_BACK)) == 0) {
- nr = 3 + 2 * cu->bevresol;
- }
- dl = MEM_callocN(sizeof(DispList), "makebevelcurve p3");
- dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p3");
- BLI_addtail(disp, dl);
- dl->type = DL_SEGM;
- dl->flag = DL_FRONT_CURVE;
- dl->parts = 1;
- dl->nr = nr;
-
- /* half a circle */
- fp = dl->verts;
- angle = 0.0;
- dangle = ((float)M_PI_2 / (dnr - 1));
-
- for (a = 0; a < nr; a++) {
- fp[0] = 0.0;
- fp[1] = (float)(cosf(angle) * (cu->ext2));
- fp[2] = (float)(sinf(angle) * (cu->ext2)) + cu->ext1;
- angle += dangle;
- fp += 3;
- }
- }
- }
-}
-
-static int cu_isectLL(const float v1[3], const float v2[3], const float v3[3], const float v4[3],
- short cox, short coy,
- float *lambda, float *mu, float vec[3])
-{
- /* return:
- * -1: collinear
- * 0: no intersection of segments
- * 1: exact intersection of segments
- * 2: cross-intersection of segments
- */
- float deler;
-
- deler = (v1[cox] - v2[cox]) * (v3[coy] - v4[coy]) - (v3[cox] - v4[cox]) * (v1[coy] - v2[coy]);
- if (deler == 0.0f)
- return -1;
-
- *lambda = (v1[coy] - v3[coy]) * (v3[cox] - v4[cox]) - (v1[cox] - v3[cox]) * (v3[coy] - v4[coy]);
- *lambda = -(*lambda / deler);
-
- deler = v3[coy] - v4[coy];
- if (deler == 0) {
- deler = v3[cox] - v4[cox];
- *mu = -(*lambda * (v2[cox] - v1[cox]) + v1[cox] - v3[cox]) / deler;
- }
- else {
- *mu = -(*lambda * (v2[coy] - v1[coy]) + v1[coy] - v3[coy]) / deler;
- }
- vec[cox] = *lambda * (v2[cox] - v1[cox]) + v1[cox];
- vec[coy] = *lambda * (v2[coy] - v1[coy]) + v1[coy];
-
- if (*lambda >= 0.0f && *lambda <= 1.0f && *mu >= 0.0f && *mu <= 1.0f) {
- if (*lambda == 0.0f || *lambda == 1.0f || *mu == 0.0f || *mu == 1.0f)
- return 1;
- return 2;
- }
- return 0;
+void BKE_curve_bevel_make(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ ListBase *disp,
+ const bool for_render,
+ const bool use_render_resolution,
+ LinkNode *ob_cyclic_list)
+{
+ DispList *dl, *dlnew;
+ Curve *bevcu, *cu;
+ float *fp, facx, facy, angle, dangle;
+ int nr, a;
+
+ cu = ob->data;
+ BLI_listbase_clear(disp);
+
+ /* if a font object is being edited, then do nothing */
+ // XXX if ( ob == obedit && ob->type == OB_FONT ) return;
+
+ if (cu->bevobj) {
+ if (cu->bevobj->type != OB_CURVE)
+ return;
+
+ bevcu = cu->bevobj->data;
+ if (bevcu->ext1 == 0.0f && bevcu->ext2 == 0.0f) {
+ ListBase bevdisp = {NULL, NULL};
+ facx = cu->bevobj->scale[0];
+ facy = cu->bevobj->scale[1];
+
+ if (for_render) {
+ if (BLI_linklist_index(ob_cyclic_list, cu->bevobj) == -1) {
+ BKE_displist_make_curveTypes_forRender(depsgraph,
+ scene,
+ cu->bevobj,
+ &bevdisp,
+ NULL,
+ false,
+ use_render_resolution,
+ &(LinkNode){
+ .link = ob,
+ .next = ob_cyclic_list,
+ });
+ dl = bevdisp.first;
+ }
+ else {
+ dl = NULL;
+ }
+ }
+ else if (cu->bevobj->runtime.curve_cache) {
+ dl = cu->bevobj->runtime.curve_cache->disp.first;
+ }
+ else {
+ BLI_assert(cu->bevobj->runtime.curve_cache != NULL);
+ dl = NULL;
+ }
+
+ while (dl) {
+ if (ELEM(dl->type, DL_POLY, DL_SEGM)) {
+ dlnew = MEM_mallocN(sizeof(DispList), "makebevelcurve1");
+ *dlnew = *dl;
+ dlnew->verts = MEM_malloc_arrayN(
+ dl->parts * dl->nr, 3 * sizeof(float), "makebevelcurve1");
+ memcpy(dlnew->verts, dl->verts, 3 * sizeof(float) * dl->parts * dl->nr);
+
+ if (dlnew->type == DL_SEGM)
+ dlnew->flag |= (DL_FRONT_CURVE | DL_BACK_CURVE);
+
+ BLI_addtail(disp, dlnew);
+ fp = dlnew->verts;
+ nr = dlnew->parts * dlnew->nr;
+ while (nr--) {
+ fp[2] = fp[1] * facy;
+ fp[1] = -fp[0] * facx;
+ fp[0] = 0.0;
+ fp += 3;
+ }
+ }
+ dl = dl->next;
+ }
+
+ BKE_displist_free(&bevdisp);
+ }
+ }
+ else if (cu->ext1 == 0.0f && cu->ext2 == 0.0f) {
+ /* pass */
+ }
+ else if (cu->ext2 == 0.0f) {
+ dl = MEM_callocN(sizeof(DispList), "makebevelcurve2");
+ dl->verts = MEM_malloc_arrayN(2, sizeof(float[3]), "makebevelcurve2");
+ BLI_addtail(disp, dl);
+ dl->type = DL_SEGM;
+ dl->parts = 1;
+ dl->flag = DL_FRONT_CURVE | DL_BACK_CURVE;
+ dl->nr = 2;
+
+ fp = dl->verts;
+ fp[0] = fp[1] = 0.0;
+ fp[2] = -cu->ext1;
+ fp[3] = fp[4] = 0.0;
+ fp[5] = cu->ext1;
+ }
+ else if ((cu->flag & (CU_FRONT | CU_BACK)) == 0 &&
+ cu->ext1 == 0.0f) { /* we make a full round bevel in that case */
+ nr = 4 + 2 * cu->bevresol;
+
+ dl = MEM_callocN(sizeof(DispList), "makebevelcurve p1");
+ dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p1");
+ BLI_addtail(disp, dl);
+ dl->type = DL_POLY;
+ dl->parts = 1;
+ dl->flag = DL_BACK_CURVE;
+ dl->nr = nr;
+
+ /* a circle */
+ fp = dl->verts;
+ dangle = (2.0f * (float)M_PI / (nr));
+ angle = -(nr - 1) * dangle;
+
+ for (a = 0; a < nr; a++) {
+ fp[0] = 0.0;
+ fp[1] = (cosf(angle) * (cu->ext2));
+ fp[2] = (sinf(angle) * (cu->ext2)) - cu->ext1;
+ angle += dangle;
+ fp += 3;
+ }
+ }
+ else {
+ short dnr;
+
+ /* bevel now in three parts, for proper vertex normals */
+ /* part 1, back */
+
+ if ((cu->flag & CU_BACK) || !(cu->flag & CU_FRONT)) {
+ dnr = nr = 2 + cu->bevresol;
+ if ((cu->flag & (CU_FRONT | CU_BACK)) == 0) {
+ nr = 3 + 2 * cu->bevresol;
+ }
+ dl = MEM_callocN(sizeof(DispList), "makebevelcurve p1");
+ dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p1");
+ BLI_addtail(disp, dl);
+ dl->type = DL_SEGM;
+ dl->parts = 1;
+ dl->flag = DL_BACK_CURVE;
+ dl->nr = nr;
+
+ /* half a circle */
+ fp = dl->verts;
+ dangle = ((float)M_PI_2 / (dnr - 1));
+ angle = -(nr - 1) * dangle;
+
+ for (a = 0; a < nr; a++) {
+ fp[0] = 0.0;
+ fp[1] = (float)(cosf(angle) * (cu->ext2));
+ fp[2] = (float)(sinf(angle) * (cu->ext2)) - cu->ext1;
+ angle += dangle;
+ fp += 3;
+ }
+ }
+
+ /* part 2, sidefaces */
+ if (cu->ext1 != 0.0f) {
+ nr = 2;
+
+ dl = MEM_callocN(sizeof(DispList), "makebevelcurve p2");
+ dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p2");
+ BLI_addtail(disp, dl);
+ dl->type = DL_SEGM;
+ dl->parts = 1;
+ dl->nr = nr;
+
+ fp = dl->verts;
+ fp[1] = cu->ext2;
+ fp[2] = -cu->ext1;
+ fp[4] = cu->ext2;
+ fp[5] = cu->ext1;
+
+ if ((cu->flag & (CU_FRONT | CU_BACK)) == 0) {
+ dl = MEM_dupallocN(dl);
+ dl->verts = MEM_dupallocN(dl->verts);
+ BLI_addtail(disp, dl);
+
+ fp = dl->verts;
+ fp[1] = -fp[1];
+ fp[2] = -fp[2];
+ fp[4] = -fp[4];
+ fp[5] = -fp[5];
+ }
+ }
+
+ /* part 3, front */
+ if ((cu->flag & CU_FRONT) || !(cu->flag & CU_BACK)) {
+ dnr = nr = 2 + cu->bevresol;
+ if ((cu->flag & (CU_FRONT | CU_BACK)) == 0) {
+ nr = 3 + 2 * cu->bevresol;
+ }
+ dl = MEM_callocN(sizeof(DispList), "makebevelcurve p3");
+ dl->verts = MEM_malloc_arrayN(nr, sizeof(float[3]), "makebevelcurve p3");
+ BLI_addtail(disp, dl);
+ dl->type = DL_SEGM;
+ dl->flag = DL_FRONT_CURVE;
+ dl->parts = 1;
+ dl->nr = nr;
+
+ /* half a circle */
+ fp = dl->verts;
+ angle = 0.0;
+ dangle = ((float)M_PI_2 / (dnr - 1));
+
+ for (a = 0; a < nr; a++) {
+ fp[0] = 0.0;
+ fp[1] = (float)(cosf(angle) * (cu->ext2));
+ fp[2] = (float)(sinf(angle) * (cu->ext2)) + cu->ext1;
+ angle += dangle;
+ fp += 3;
+ }
+ }
+ }
+}
+
+static int cu_isectLL(const float v1[3],
+ const float v2[3],
+ const float v3[3],
+ const float v4[3],
+ short cox,
+ short coy,
+ float *lambda,
+ float *mu,
+ float vec[3])
+{
+ /* return:
+ * -1: collinear
+ * 0: no intersection of segments
+ * 1: exact intersection of segments
+ * 2: cross-intersection of segments
+ */
+ float deler;
+
+ deler = (v1[cox] - v2[cox]) * (v3[coy] - v4[coy]) - (v3[cox] - v4[cox]) * (v1[coy] - v2[coy]);
+ if (deler == 0.0f)
+ return -1;
+
+ *lambda = (v1[coy] - v3[coy]) * (v3[cox] - v4[cox]) - (v1[cox] - v3[cox]) * (v3[coy] - v4[coy]);
+ *lambda = -(*lambda / deler);
+
+ deler = v3[coy] - v4[coy];
+ if (deler == 0) {
+ deler = v3[cox] - v4[cox];
+ *mu = -(*lambda * (v2[cox] - v1[cox]) + v1[cox] - v3[cox]) / deler;
+ }
+ else {
+ *mu = -(*lambda * (v2[coy] - v1[coy]) + v1[coy] - v3[coy]) / deler;
+ }
+ vec[cox] = *lambda * (v2[cox] - v1[cox]) + v1[cox];
+ vec[coy] = *lambda * (v2[coy] - v1[coy]) + v1[coy];
+
+ if (*lambda >= 0.0f && *lambda <= 1.0f && *mu >= 0.0f && *mu <= 1.0f) {
+ if (*lambda == 0.0f || *lambda == 1.0f || *mu == 0.0f || *mu == 1.0f)
+ return 1;
+ return 2;
+ }
+ return 0;
}
-
static bool bevelinside(BevList *bl1, BevList *bl2)
{
- /* is bl2 INSIDE bl1 ? with left-right method and "lambda's" */
- /* returns '1' if correct hole */
- BevPoint *bevp, *prevbevp;
- float min, max, vec[3], hvec1[3], hvec2[3], lab, mu;
- int nr, links = 0, rechts = 0, mode;
-
- /* take first vertex of possible hole */
-
- bevp = bl2->bevpoints;
- hvec1[0] = bevp->vec[0];
- hvec1[1] = bevp->vec[1];
- hvec1[2] = 0.0;
- copy_v3_v3(hvec2, hvec1);
- hvec2[0] += 1000;
-
- /* test it with all edges of potential surrounding poly */
- /* count number of transitions left-right */
-
- bevp = bl1->bevpoints;
- nr = bl1->nr;
- prevbevp = bevp + (nr - 1);
-
- while (nr--) {
- min = prevbevp->vec[1];
- max = bevp->vec[1];
- if (max < min) {
- min = max;
- max = prevbevp->vec[1];
- }
- if (min != max) {
- if (min <= hvec1[1] && max >= hvec1[1]) {
- /* there's a transition, calc intersection point */
- mode = cu_isectLL(prevbevp->vec, bevp->vec, hvec1, hvec2, 0, 1, &lab, &mu, vec);
- /* if lab==0.0 or lab==1.0 then the edge intersects exactly a transition
- * only allow for one situation: we choose lab= 1.0
- */
- if (mode >= 0 && lab != 0.0f) {
- if (vec[0] < hvec1[0]) links++;
- else rechts++;
- }
- }
- }
- prevbevp = bevp;
- bevp++;
- }
-
- return (links & 1) && (rechts & 1);
+ /* is bl2 INSIDE bl1 ? with left-right method and "lambda's" */
+ /* returns '1' if correct hole */
+ BevPoint *bevp, *prevbevp;
+ float min, max, vec[3], hvec1[3], hvec2[3], lab, mu;
+ int nr, links = 0, rechts = 0, mode;
+
+ /* take first vertex of possible hole */
+
+ bevp = bl2->bevpoints;
+ hvec1[0] = bevp->vec[0];
+ hvec1[1] = bevp->vec[1];
+ hvec1[2] = 0.0;
+ copy_v3_v3(hvec2, hvec1);
+ hvec2[0] += 1000;
+
+ /* test it with all edges of potential surrounding poly */
+ /* count number of transitions left-right */
+
+ bevp = bl1->bevpoints;
+ nr = bl1->nr;
+ prevbevp = bevp + (nr - 1);
+
+ while (nr--) {
+ min = prevbevp->vec[1];
+ max = bevp->vec[1];
+ if (max < min) {
+ min = max;
+ max = prevbevp->vec[1];
+ }
+ if (min != max) {
+ if (min <= hvec1[1] && max >= hvec1[1]) {
+ /* there's a transition, calc intersection point */
+ mode = cu_isectLL(prevbevp->vec, bevp->vec, hvec1, hvec2, 0, 1, &lab, &mu, vec);
+ /* if lab==0.0 or lab==1.0 then the edge intersects exactly a transition
+ * only allow for one situation: we choose lab= 1.0
+ */
+ if (mode >= 0 && lab != 0.0f) {
+ if (vec[0] < hvec1[0])
+ links++;
+ else
+ rechts++;
+ }
+ }
+ }
+ prevbevp = bevp;
+ bevp++;
+ }
+
+ return (links & 1) && (rechts & 1);
}
-
struct BevelSort {
- BevList *bl;
- float left;
- int dir;
+ BevList *bl;
+ float left;
+ int dir;
};
static int vergxcobev(const void *a1, const void *a2)
{
- const struct BevelSort *x1 = a1, *x2 = a2;
+ const struct BevelSort *x1 = a1, *x2 = a2;
- if (x1->left > x2->left)
- return 1;
- else if (x1->left < x2->left)
- return -1;
- return 0;
+ if (x1->left > x2->left)
+ return 1;
+ else if (x1->left < x2->left)
+ return -1;
+ return 0;
}
/* this function cannot be replaced with atan2, but why? */
-static void calc_bevel_sin_cos(float x1, float y1, float x2, float y2,
- float *r_sina, float *r_cosa)
-{
- float t01, t02, x3, y3;
-
- t01 = sqrtf(x1 * x1 + y1 * y1);
- t02 = sqrtf(x2 * x2 + y2 * y2);
- if (t01 == 0.0f)
- t01 = 1.0f;
- if (t02 == 0.0f)
- t02 = 1.0f;
-
- x1 /= t01;
- y1 /= t01;
- x2 /= t02;
- y2 /= t02;
-
- t02 = x1 * x2 + y1 * y2;
- if (fabsf(t02) >= 1.0f)
- t02 = M_PI_2;
- else
- t02 = (saacos(t02)) / 2.0f;
-
- t02 = sinf(t02);
- if (t02 == 0.0f)
- t02 = 1.0f;
-
- x3 = x1 - x2;
- y3 = y1 - y2;
- if (x3 == 0 && y3 == 0) {
- x3 = y1;
- y3 = -x1;
- }
- else {
- t01 = sqrtf(x3 * x3 + y3 * y3);
- x3 /= t01;
- y3 /= t01;
- }
-
- *r_sina = -y3 / t02;
- *r_cosa = x3 / t02;
-
-}
-
-static void tilt_bezpart(
- BezTriple *prevbezt, BezTriple *bezt, Nurb *nu, float *tilt_array, float *radius_array,
- float *weight_array, int resolu, int stride)
-{
- BezTriple *pprev, *next, *last;
- float fac, dfac, t[4];
- int a;
-
- if (tilt_array == NULL && radius_array == NULL)
- return;
-
- last = nu->bezt + (nu->pntsu - 1);
-
- /* returns a point */
- if (prevbezt == nu->bezt) {
- if (nu->flagu & CU_NURB_CYCLIC)
- pprev = last;
- else
- pprev = prevbezt;
- }
- else
- pprev = prevbezt - 1;
-
- /* next point */
- if (bezt == last) {
- if (nu->flagu & CU_NURB_CYCLIC)
- next = nu->bezt;
- else
- next = bezt;
- }
- else
- next = bezt + 1;
-
- fac = 0.0;
- dfac = 1.0f / (float)resolu;
-
- for (a = 0; a < resolu; a++, fac += dfac) {
- if (tilt_array) {
- if (nu->tilt_interp == KEY_CU_EASE) { /* May as well support for tilt also 2.47 ease interp */
- *tilt_array = prevbezt->tilt +
- (bezt->tilt - prevbezt->tilt) * (3.0f * fac * fac - 2.0f * fac * fac * fac);
- }
- else {
- key_curve_position_weights(fac, t, nu->tilt_interp);
- *tilt_array = t[0] * pprev->tilt + t[1] * prevbezt->tilt + t[2] * bezt->tilt + t[3] * next->tilt;
- }
-
- tilt_array = POINTER_OFFSET(tilt_array, stride);
- }
-
- if (radius_array) {
- if (nu->radius_interp == KEY_CU_EASE) {
- /* Support 2.47 ease interp
- * Note! - this only takes the 2 points into account,
- * giving much more localized results to changes in radius, sometimes you want that */
- *radius_array = prevbezt->radius +
- (bezt->radius - prevbezt->radius) * (3.0f * fac * fac - 2.0f * fac * fac * fac);
- }
- else {
-
- /* reuse interpolation from tilt if we can */
- if (tilt_array == NULL || nu->tilt_interp != nu->radius_interp) {
- key_curve_position_weights(fac, t, nu->radius_interp);
- }
- *radius_array =
- t[0] * pprev->radius + t[1] * prevbezt->radius +
- t[2] * bezt->radius + t[3] * next->radius;
- }
-
- radius_array = POINTER_OFFSET(radius_array, stride);
- }
-
- if (weight_array) {
- /* basic interpolation for now, could copy tilt interp too */
- *weight_array =
- prevbezt->weight +
- (bezt->weight - prevbezt->weight) * (3.0f * fac * fac - 2.0f * fac * fac * fac);
-
- weight_array = POINTER_OFFSET(weight_array, stride);
- }
- }
+static void calc_bevel_sin_cos(
+ float x1, float y1, float x2, float y2, float *r_sina, float *r_cosa)
+{
+ float t01, t02, x3, y3;
+
+ t01 = sqrtf(x1 * x1 + y1 * y1);
+ t02 = sqrtf(x2 * x2 + y2 * y2);
+ if (t01 == 0.0f)
+ t01 = 1.0f;
+ if (t02 == 0.0f)
+ t02 = 1.0f;
+
+ x1 /= t01;
+ y1 /= t01;
+ x2 /= t02;
+ y2 /= t02;
+
+ t02 = x1 * x2 + y1 * y2;
+ if (fabsf(t02) >= 1.0f)
+ t02 = M_PI_2;
+ else
+ t02 = (saacos(t02)) / 2.0f;
+
+ t02 = sinf(t02);
+ if (t02 == 0.0f)
+ t02 = 1.0f;
+
+ x3 = x1 - x2;
+ y3 = y1 - y2;
+ if (x3 == 0 && y3 == 0) {
+ x3 = y1;
+ y3 = -x1;
+ }
+ else {
+ t01 = sqrtf(x3 * x3 + y3 * y3);
+ x3 /= t01;
+ y3 /= t01;
+ }
+
+ *r_sina = -y3 / t02;
+ *r_cosa = x3 / t02;
+}
+
+static void tilt_bezpart(BezTriple *prevbezt,
+ BezTriple *bezt,
+ Nurb *nu,
+ float *tilt_array,
+ float *radius_array,
+ float *weight_array,
+ int resolu,
+ int stride)
+{
+ BezTriple *pprev, *next, *last;
+ float fac, dfac, t[4];
+ int a;
+
+ if (tilt_array == NULL && radius_array == NULL)
+ return;
+
+ last = nu->bezt + (nu->pntsu - 1);
+
+ /* returns a point */
+ if (prevbezt == nu->bezt) {
+ if (nu->flagu & CU_NURB_CYCLIC)
+ pprev = last;
+ else
+ pprev = prevbezt;
+ }
+ else
+ pprev = prevbezt - 1;
+
+ /* next point */
+ if (bezt == last) {
+ if (nu->flagu & CU_NURB_CYCLIC)
+ next = nu->bezt;
+ else
+ next = bezt;
+ }
+ else
+ next = bezt + 1;
+
+ fac = 0.0;
+ dfac = 1.0f / (float)resolu;
+
+ for (a = 0; a < resolu; a++, fac += dfac) {
+ if (tilt_array) {
+ if (nu->tilt_interp ==
+ KEY_CU_EASE) { /* May as well support for tilt also 2.47 ease interp */
+ *tilt_array = prevbezt->tilt +
+ (bezt->tilt - prevbezt->tilt) * (3.0f * fac * fac - 2.0f * fac * fac * fac);
+ }
+ else {
+ key_curve_position_weights(fac, t, nu->tilt_interp);
+ *tilt_array = t[0] * pprev->tilt + t[1] * prevbezt->tilt + t[2] * bezt->tilt +
+ t[3] * next->tilt;
+ }
+
+ tilt_array = POINTER_OFFSET(tilt_array, stride);
+ }
+
+ if (radius_array) {
+ if (nu->radius_interp == KEY_CU_EASE) {
+ /* Support 2.47 ease interp
+ * Note! - this only takes the 2 points into account,
+ * giving much more localized results to changes in radius, sometimes you want that */
+ *radius_array = prevbezt->radius + (bezt->radius - prevbezt->radius) *
+ (3.0f * fac * fac - 2.0f * fac * fac * fac);
+ }
+ else {
+
+ /* reuse interpolation from tilt if we can */
+ if (tilt_array == NULL || nu->tilt_interp != nu->radius_interp) {
+ key_curve_position_weights(fac, t, nu->radius_interp);
+ }
+ *radius_array = t[0] * pprev->radius + t[1] * prevbezt->radius + t[2] * bezt->radius +
+ t[3] * next->radius;
+ }
+
+ radius_array = POINTER_OFFSET(radius_array, stride);
+ }
+
+ if (weight_array) {
+ /* basic interpolation for now, could copy tilt interp too */
+ *weight_array = prevbezt->weight + (bezt->weight - prevbezt->weight) *
+ (3.0f * fac * fac - 2.0f * fac * fac * fac);
+
+ weight_array = POINTER_OFFSET(weight_array, stride);
+ }
+ }
}
/* make_bevel_list_3D_* funcs, at a minimum these must
@@ -2279,1228 +2335,1248 @@ static void tilt_bezpart(
/* utility for make_bevel_list_3D_* funcs */
static void bevel_list_calc_bisect(BevList *bl)
{
- BevPoint *bevp2, *bevp1, *bevp0;
- int nr;
- bool is_cyclic = bl->poly != -1;
-
- if (is_cyclic) {
- bevp2 = bl->bevpoints;
- bevp1 = bevp2 + (bl->nr - 1);
- bevp0 = bevp1 - 1;
- nr = bl->nr;
- }
- else {
- /* If spline is not cyclic, direction of first and
- * last bevel points matches direction of CV handle.
- *
- * This is getting calculated earlier when we know
- * CV's handles and here we might simply skip evaluation
- * of direction for this guys.
- */
-
- bevp0 = bl->bevpoints;
- bevp1 = bevp0 + 1;
- bevp2 = bevp1 + 1;
-
- nr = bl->nr - 2;
- }
-
- while (nr--) {
- /* totally simple */
- bisect_v3_v3v3v3(bevp1->dir, bevp0->vec, bevp1->vec, bevp2->vec);
-
- bevp0 = bevp1;
- bevp1 = bevp2;
- bevp2++;
- }
+ BevPoint *bevp2, *bevp1, *bevp0;
+ int nr;
+ bool is_cyclic = bl->poly != -1;
+
+ if (is_cyclic) {
+ bevp2 = bl->bevpoints;
+ bevp1 = bevp2 + (bl->nr - 1);
+ bevp0 = bevp1 - 1;
+ nr = bl->nr;
+ }
+ else {
+ /* If spline is not cyclic, direction of first and
+ * last bevel points matches direction of CV handle.
+ *
+ * This is getting calculated earlier when we know
+ * CV's handles and here we might simply skip evaluation
+ * of direction for this guys.
+ */
+
+ bevp0 = bl->bevpoints;
+ bevp1 = bevp0 + 1;
+ bevp2 = bevp1 + 1;
+
+ nr = bl->nr - 2;
+ }
+
+ while (nr--) {
+ /* totally simple */
+ bisect_v3_v3v3v3(bevp1->dir, bevp0->vec, bevp1->vec, bevp2->vec);
+
+ bevp0 = bevp1;
+ bevp1 = bevp2;
+ bevp2++;
+ }
}
static void bevel_list_flip_tangents(BevList *bl)
{
- BevPoint *bevp2, *bevp1, *bevp0;
- int nr;
+ BevPoint *bevp2, *bevp1, *bevp0;
+ int nr;
- bevp2 = bl->bevpoints;
- bevp1 = bevp2 + (bl->nr - 1);
- bevp0 = bevp1 - 1;
+ bevp2 = bl->bevpoints;
+ bevp1 = bevp2 + (bl->nr - 1);
+ bevp0 = bevp1 - 1;
- nr = bl->nr;
- while (nr--) {
- if (angle_normalized_v3v3(bevp0->tan, bevp1->tan) > DEG2RADF(90.0f))
- negate_v3(bevp1->tan);
+ nr = bl->nr;
+ while (nr--) {
+ if (angle_normalized_v3v3(bevp0->tan, bevp1->tan) > DEG2RADF(90.0f))
+ negate_v3(bevp1->tan);
- bevp0 = bevp1;
- bevp1 = bevp2;
- bevp2++;
- }
+ bevp0 = bevp1;
+ bevp1 = bevp2;
+ bevp2++;
+ }
}
/* apply user tilt */
static void bevel_list_apply_tilt(BevList *bl)
{
- BevPoint *bevp2, *bevp1;
- int nr;
- float q[4];
+ BevPoint *bevp2, *bevp1;
+ int nr;
+ float q[4];
- bevp2 = bl->bevpoints;
- bevp1 = bevp2 + (bl->nr - 1);
+ bevp2 = bl->bevpoints;
+ bevp1 = bevp2 + (bl->nr - 1);
- nr = bl->nr;
- while (nr--) {
- axis_angle_to_quat(q, bevp1->dir, bevp1->tilt);
- mul_qt_qtqt(bevp1->quat, q, bevp1->quat);
- normalize_qt(bevp1->quat);
+ nr = bl->nr;
+ while (nr--) {
+ axis_angle_to_quat(q, bevp1->dir, bevp1->tilt);
+ mul_qt_qtqt(bevp1->quat, q, bevp1->quat);
+ normalize_qt(bevp1->quat);
- bevp1 = bevp2;
- bevp2++;
- }
+ bevp1 = bevp2;
+ bevp2++;
+ }
}
/* smooth quats, this function should be optimized, it can get slow with many iterations. */
static void bevel_list_smooth(BevList *bl, int smooth_iter)
{
- BevPoint *bevp2, *bevp1, *bevp0;
- int nr;
+ BevPoint *bevp2, *bevp1, *bevp0;
+ int nr;
- float q[4];
- float bevp0_quat[4];
- int a;
+ float q[4];
+ float bevp0_quat[4];
+ int a;
- for (a = 0; a < smooth_iter; a++) {
- bevp2 = bl->bevpoints;
- bevp1 = bevp2 + (bl->nr - 1);
- bevp0 = bevp1 - 1;
+ for (a = 0; a < smooth_iter; a++) {
+ bevp2 = bl->bevpoints;
+ bevp1 = bevp2 + (bl->nr - 1);
+ bevp0 = bevp1 - 1;
- nr = bl->nr;
+ nr = bl->nr;
- if (bl->poly == -1) { /* check its not cyclic */
- /* skip the first point */
- /* bevp0 = bevp1; */
- bevp1 = bevp2;
- bevp2++;
- nr--;
+ if (bl->poly == -1) { /* check its not cyclic */
+ /* skip the first point */
+ /* bevp0 = bevp1; */
+ bevp1 = bevp2;
+ bevp2++;
+ nr--;
- bevp0 = bevp1;
- bevp1 = bevp2;
- bevp2++;
- nr--;
- }
+ bevp0 = bevp1;
+ bevp1 = bevp2;
+ bevp2++;
+ nr--;
+ }
- copy_qt_qt(bevp0_quat, bevp0->quat);
+ copy_qt_qt(bevp0_quat, bevp0->quat);
- while (nr--) {
- /* interpolate quats */
- float zaxis[3] = {0, 0, 1}, cross[3], q2[4];
- interp_qt_qtqt(q, bevp0_quat, bevp2->quat, 0.5);
- normalize_qt(q);
+ while (nr--) {
+ /* interpolate quats */
+ float zaxis[3] = {0, 0, 1}, cross[3], q2[4];
+ interp_qt_qtqt(q, bevp0_quat, bevp2->quat, 0.5);
+ normalize_qt(q);
- mul_qt_v3(q, zaxis);
- cross_v3_v3v3(cross, zaxis, bevp1->dir);
- axis_angle_to_quat(q2, cross, angle_normalized_v3v3(zaxis, bevp1->dir));
- normalize_qt(q2);
+ mul_qt_v3(q, zaxis);
+ cross_v3_v3v3(cross, zaxis, bevp1->dir);
+ axis_angle_to_quat(q2, cross, angle_normalized_v3v3(zaxis, bevp1->dir));
+ normalize_qt(q2);
- copy_qt_qt(bevp0_quat, bevp1->quat);
- mul_qt_qtqt(q, q2, q);
- interp_qt_qtqt(bevp1->quat, bevp1->quat, q, 0.5);
- normalize_qt(bevp1->quat);
+ copy_qt_qt(bevp0_quat, bevp1->quat);
+ mul_qt_qtqt(q, q2, q);
+ interp_qt_qtqt(bevp1->quat, bevp1->quat, q, 0.5);
+ normalize_qt(bevp1->quat);
- /* bevp0 = bevp1; */ /* UNUSED */
- bevp1 = bevp2;
- bevp2++;
- }
- }
+ /* bevp0 = bevp1; */ /* UNUSED */
+ bevp1 = bevp2;
+ bevp2++;
+ }
+ }
}
static void make_bevel_list_3D_zup(BevList *bl)
{
- BevPoint *bevp = bl->bevpoints;
- int nr = bl->nr;
+ BevPoint *bevp = bl->bevpoints;
+ int nr = bl->nr;
- bevel_list_calc_bisect(bl);
+ bevel_list_calc_bisect(bl);
- while (nr--) {
- vec_to_quat(bevp->quat, bevp->dir, 5, 1);
- bevp++;
- }
+ while (nr--) {
+ vec_to_quat(bevp->quat, bevp->dir, 5, 1);
+ bevp++;
+ }
}
static void minimum_twist_between_two_points(BevPoint *current_point, BevPoint *previous_point)
{
- float angle = angle_normalized_v3v3(previous_point->dir, current_point->dir);
- float q[4];
+ float angle = angle_normalized_v3v3(previous_point->dir, current_point->dir);
+ float q[4];
- if (angle > 0.0f) { /* otherwise we can keep as is */
- float cross_tmp[3];
- cross_v3_v3v3(cross_tmp, previous_point->dir, current_point->dir);
- axis_angle_to_quat(q, cross_tmp, angle);
- mul_qt_qtqt(current_point->quat, q, previous_point->quat);
- }
- else {
- copy_qt_qt(current_point->quat, previous_point->quat);
- }
+ if (angle > 0.0f) { /* otherwise we can keep as is */
+ float cross_tmp[3];
+ cross_v3_v3v3(cross_tmp, previous_point->dir, current_point->dir);
+ axis_angle_to_quat(q, cross_tmp, angle);
+ mul_qt_qtqt(current_point->quat, q, previous_point->quat);
+ }
+ else {
+ copy_qt_qt(current_point->quat, previous_point->quat);
+ }
}
static void make_bevel_list_3D_minimum_twist(BevList *bl)
{
- BevPoint *bevp2, *bevp1, *bevp0; /* standard for all make_bevel_list_3D_* funcs */
- int nr;
- float q[4];
-
- bevel_list_calc_bisect(bl);
-
- bevp2 = bl->bevpoints;
- bevp1 = bevp2 + (bl->nr - 1);
- bevp0 = bevp1 - 1;
-
- nr = bl->nr;
- while (nr--) {
-
- if (nr + 4 > bl->nr) { /* first time and second time, otherwise first point adjusts last */
- vec_to_quat(bevp1->quat, bevp1->dir, 5, 1);
- }
- else {
- minimum_twist_between_two_points(bevp1, bevp0);
- }
-
- bevp0 = bevp1;
- bevp1 = bevp2;
- bevp2++;
- }
-
- if (bl->poly != -1) { /* check for cyclic */
-
- /* Need to correct for the start/end points not matching
- * do this by calculating the tilt angle difference, then apply
- * the rotation gradually over the entire curve
- *
- * note that the split is between last and second last, rather than first/last as youd expect.
- *
- * real order is like this
- * 0,1,2,3,4 --> 1,2,3,4,0
- *
- * this is why we compare last with second last
- * */
- float vec_1[3] = {0, 1, 0}, vec_2[3] = {0, 1, 0}, angle, ang_fac, cross_tmp[3];
-
- BevPoint *bevp_first;
- BevPoint *bevp_last;
-
-
- bevp_first = bl->bevpoints;
- bevp_first += bl->nr - 1;
- bevp_last = bevp_first;
- bevp_last--;
-
- /* quats and vec's are normalized, should not need to re-normalize */
- mul_qt_v3(bevp_first->quat, vec_1);
- mul_qt_v3(bevp_last->quat, vec_2);
- normalize_v3(vec_1);
- normalize_v3(vec_2);
-
- /* align the vector, can avoid this and it looks 98% OK but
- * better to align the angle quat roll's before comparing */
- {
- cross_v3_v3v3(cross_tmp, bevp_last->dir, bevp_first->dir);
- angle = angle_normalized_v3v3(bevp_first->dir, bevp_last->dir);
- axis_angle_to_quat(q, cross_tmp, angle);
- mul_qt_v3(q, vec_2);
- }
-
- angle = angle_normalized_v3v3(vec_1, vec_2);
-
- /* flip rotation if needs be */
- cross_v3_v3v3(cross_tmp, vec_1, vec_2);
- normalize_v3(cross_tmp);
- if (angle_normalized_v3v3(bevp_first->dir, cross_tmp) < DEG2RADF(90.0f))
- angle = -angle;
-
- bevp2 = bl->bevpoints;
- bevp1 = bevp2 + (bl->nr - 1);
- bevp0 = bevp1 - 1;
-
- nr = bl->nr;
- while (nr--) {
- ang_fac = angle * (1.0f - ((float)nr / bl->nr)); /* also works */
-
- axis_angle_to_quat(q, bevp1->dir, ang_fac);
- mul_qt_qtqt(bevp1->quat, q, bevp1->quat);
-
- bevp0 = bevp1;
- bevp1 = bevp2;
- bevp2++;
- }
- }
- else {
- /* Need to correct quat for the first/last point,
- * this is so because previously it was only calculated
- * using it's own direction, which might not correspond
- * the twist of neighbor point.
- */
- bevp1 = bl->bevpoints;
- bevp0 = bevp1 + 1;
- minimum_twist_between_two_points(bevp1, bevp0);
-
- bevp2 = bl->bevpoints;
- bevp1 = bevp2 + (bl->nr - 1);
- bevp0 = bevp1 - 1;
- minimum_twist_between_two_points(bevp1, bevp0);
- }
+ BevPoint *bevp2, *bevp1, *bevp0; /* standard for all make_bevel_list_3D_* funcs */
+ int nr;
+ float q[4];
+
+ bevel_list_calc_bisect(bl);
+
+ bevp2 = bl->bevpoints;
+ bevp1 = bevp2 + (bl->nr - 1);
+ bevp0 = bevp1 - 1;
+
+ nr = bl->nr;
+ while (nr--) {
+
+ if (nr + 4 > bl->nr) { /* first time and second time, otherwise first point adjusts last */
+ vec_to_quat(bevp1->quat, bevp1->dir, 5, 1);
+ }
+ else {
+ minimum_twist_between_two_points(bevp1, bevp0);
+ }
+
+ bevp0 = bevp1;
+ bevp1 = bevp2;
+ bevp2++;
+ }
+
+ if (bl->poly != -1) { /* check for cyclic */
+
+ /* Need to correct for the start/end points not matching
+ * do this by calculating the tilt angle difference, then apply
+ * the rotation gradually over the entire curve
+ *
+ * note that the split is between last and second last, rather than first/last as youd expect.
+ *
+ * real order is like this
+ * 0,1,2,3,4 --> 1,2,3,4,0
+ *
+ * this is why we compare last with second last
+ * */
+ float vec_1[3] = {0, 1, 0}, vec_2[3] = {0, 1, 0}, angle, ang_fac, cross_tmp[3];
+
+ BevPoint *bevp_first;
+ BevPoint *bevp_last;
+
+ bevp_first = bl->bevpoints;
+ bevp_first += bl->nr - 1;
+ bevp_last = bevp_first;
+ bevp_last--;
+
+ /* quats and vec's are normalized, should not need to re-normalize */
+ mul_qt_v3(bevp_first->quat, vec_1);
+ mul_qt_v3(bevp_last->quat, vec_2);
+ normalize_v3(vec_1);
+ normalize_v3(vec_2);
+
+ /* align the vector, can avoid this and it looks 98% OK but
+ * better to align the angle quat roll's before comparing */
+ {
+ cross_v3_v3v3(cross_tmp, bevp_last->dir, bevp_first->dir);
+ angle = angle_normalized_v3v3(bevp_first->dir, bevp_last->dir);
+ axis_angle_to_quat(q, cross_tmp, angle);
+ mul_qt_v3(q, vec_2);
+ }
+
+ angle = angle_normalized_v3v3(vec_1, vec_2);
+
+ /* flip rotation if needs be */
+ cross_v3_v3v3(cross_tmp, vec_1, vec_2);
+ normalize_v3(cross_tmp);
+ if (angle_normalized_v3v3(bevp_first->dir, cross_tmp) < DEG2RADF(90.0f))
+ angle = -angle;
+
+ bevp2 = bl->bevpoints;
+ bevp1 = bevp2 + (bl->nr - 1);
+ bevp0 = bevp1 - 1;
+
+ nr = bl->nr;
+ while (nr--) {
+ ang_fac = angle * (1.0f - ((float)nr / bl->nr)); /* also works */
+
+ axis_angle_to_quat(q, bevp1->dir, ang_fac);
+ mul_qt_qtqt(bevp1->quat, q, bevp1->quat);
+
+ bevp0 = bevp1;
+ bevp1 = bevp2;
+ bevp2++;
+ }
+ }
+ else {
+ /* Need to correct quat for the first/last point,
+ * this is so because previously it was only calculated
+ * using it's own direction, which might not correspond
+ * the twist of neighbor point.
+ */
+ bevp1 = bl->bevpoints;
+ bevp0 = bevp1 + 1;
+ minimum_twist_between_two_points(bevp1, bevp0);
+
+ bevp2 = bl->bevpoints;
+ bevp1 = bevp2 + (bl->nr - 1);
+ bevp0 = bevp1 - 1;
+ minimum_twist_between_two_points(bevp1, bevp0);
+ }
}
static void make_bevel_list_3D_tangent(BevList *bl)
{
- BevPoint *bevp2, *bevp1, *bevp0; /* standard for all make_bevel_list_3D_* funcs */
- int nr;
+ BevPoint *bevp2, *bevp1, *bevp0; /* standard for all make_bevel_list_3D_* funcs */
+ int nr;
- float bevp0_tan[3];
+ float bevp0_tan[3];
- bevel_list_calc_bisect(bl);
- bevel_list_flip_tangents(bl);
+ bevel_list_calc_bisect(bl);
+ bevel_list_flip_tangents(bl);
- /* correct the tangents */
- bevp2 = bl->bevpoints;
- bevp1 = bevp2 + (bl->nr - 1);
- bevp0 = bevp1 - 1;
+ /* correct the tangents */
+ bevp2 = bl->bevpoints;
+ bevp1 = bevp2 + (bl->nr - 1);
+ bevp0 = bevp1 - 1;
- nr = bl->nr;
- while (nr--) {
- float cross_tmp[3];
- cross_v3_v3v3(cross_tmp, bevp1->tan, bevp1->dir);
- cross_v3_v3v3(bevp1->tan, cross_tmp, bevp1->dir);
- normalize_v3(bevp1->tan);
+ nr = bl->nr;
+ while (nr--) {
+ float cross_tmp[3];
+ cross_v3_v3v3(cross_tmp, bevp1->tan, bevp1->dir);
+ cross_v3_v3v3(bevp1->tan, cross_tmp, bevp1->dir);
+ normalize_v3(bevp1->tan);
- bevp0 = bevp1;
- bevp1 = bevp2;
- bevp2++;
- }
+ bevp0 = bevp1;
+ bevp1 = bevp2;
+ bevp2++;
+ }
+ /* now for the real twist calc */
+ bevp2 = bl->bevpoints;
+ bevp1 = bevp2 + (bl->nr - 1);
+ bevp0 = bevp1 - 1;
- /* now for the real twist calc */
- bevp2 = bl->bevpoints;
- bevp1 = bevp2 + (bl->nr - 1);
- bevp0 = bevp1 - 1;
+ copy_v3_v3(bevp0_tan, bevp0->tan);
- copy_v3_v3(bevp0_tan, bevp0->tan);
+ nr = bl->nr;
+ while (nr--) {
+ /* make perpendicular, modify tan in place, is ok */
+ float cross_tmp[3];
+ float zero[3] = {0, 0, 0};
- nr = bl->nr;
- while (nr--) {
- /* make perpendicular, modify tan in place, is ok */
- float cross_tmp[3];
- float zero[3] = {0, 0, 0};
+ cross_v3_v3v3(cross_tmp, bevp1->tan, bevp1->dir);
+ normalize_v3(cross_tmp);
+ tri_to_quat(bevp1->quat, zero, cross_tmp, bevp1->tan); /* XXX - could be faster */
- cross_v3_v3v3(cross_tmp, bevp1->tan, bevp1->dir);
- normalize_v3(cross_tmp);
- tri_to_quat(bevp1->quat, zero, cross_tmp, bevp1->tan); /* XXX - could be faster */
-
- /* bevp0 = bevp1; */ /* UNUSED */
- bevp1 = bevp2;
- bevp2++;
- }
+ /* bevp0 = bevp1; */ /* UNUSED */
+ bevp1 = bevp2;
+ bevp2++;
+ }
}
static void make_bevel_list_3D(BevList *bl, int smooth_iter, int twist_mode)
{
- switch (twist_mode) {
- case CU_TWIST_TANGENT:
- make_bevel_list_3D_tangent(bl);
- break;
- case CU_TWIST_MINIMUM:
- make_bevel_list_3D_minimum_twist(bl);
- break;
- default: /* CU_TWIST_Z_UP default, pre 2.49c */
- make_bevel_list_3D_zup(bl);
- break;
- }
+ switch (twist_mode) {
+ case CU_TWIST_TANGENT:
+ make_bevel_list_3D_tangent(bl);
+ break;
+ case CU_TWIST_MINIMUM:
+ make_bevel_list_3D_minimum_twist(bl);
+ break;
+ default: /* CU_TWIST_Z_UP default, pre 2.49c */
+ make_bevel_list_3D_zup(bl);
+ break;
+ }
- if (smooth_iter)
- bevel_list_smooth(bl, smooth_iter);
+ if (smooth_iter)
+ bevel_list_smooth(bl, smooth_iter);
- bevel_list_apply_tilt(bl);
+ bevel_list_apply_tilt(bl);
}
/* only for 2 points */
static void make_bevel_list_segment_3D(BevList *bl)
{
- float q[4];
+ float q[4];
- BevPoint *bevp2 = bl->bevpoints;
- BevPoint *bevp1 = bevp2 + 1;
+ BevPoint *bevp2 = bl->bevpoints;
+ BevPoint *bevp1 = bevp2 + 1;
- /* simple quat/dir */
- sub_v3_v3v3(bevp1->dir, bevp1->vec, bevp2->vec);
- normalize_v3(bevp1->dir);
+ /* simple quat/dir */
+ sub_v3_v3v3(bevp1->dir, bevp1->vec, bevp2->vec);
+ normalize_v3(bevp1->dir);
- vec_to_quat(bevp1->quat, bevp1->dir, 5, 1);
+ vec_to_quat(bevp1->quat, bevp1->dir, 5, 1);
- axis_angle_to_quat(q, bevp1->dir, bevp1->tilt);
- mul_qt_qtqt(bevp1->quat, q, bevp1->quat);
- normalize_qt(bevp1->quat);
- copy_v3_v3(bevp2->dir, bevp1->dir);
- copy_qt_qt(bevp2->quat, bevp1->quat);
+ axis_angle_to_quat(q, bevp1->dir, bevp1->tilt);
+ mul_qt_qtqt(bevp1->quat, q, bevp1->quat);
+ normalize_qt(bevp1->quat);
+ copy_v3_v3(bevp2->dir, bevp1->dir);
+ copy_qt_qt(bevp2->quat, bevp1->quat);
}
/* only for 2 points */
static void make_bevel_list_segment_2D(BevList *bl)
{
- BevPoint *bevp2 = bl->bevpoints;
- BevPoint *bevp1 = bevp2 + 1;
+ BevPoint *bevp2 = bl->bevpoints;
+ BevPoint *bevp1 = bevp2 + 1;
- const float x1 = bevp1->vec[0] - bevp2->vec[0];
- const float y1 = bevp1->vec[1] - bevp2->vec[1];
+ const float x1 = bevp1->vec[0] - bevp2->vec[0];
+ const float y1 = bevp1->vec[1] - bevp2->vec[1];
- calc_bevel_sin_cos(x1, y1, -x1, -y1, &(bevp1->sina), &(bevp1->cosa));
- bevp2->sina = bevp1->sina;
- bevp2->cosa = bevp1->cosa;
+ calc_bevel_sin_cos(x1, y1, -x1, -y1, &(bevp1->sina), &(bevp1->cosa));
+ bevp2->sina = bevp1->sina;
+ bevp2->cosa = bevp1->cosa;
- /* fill in dir & quat */
- make_bevel_list_segment_3D(bl);
+ /* fill in dir & quat */
+ make_bevel_list_segment_3D(bl);
}
static void make_bevel_list_2D(BevList *bl)
{
- /* note: bevp->dir and bevp->quat are not needed for beveling but are
- * used when making a path from a 2D curve, therefore they need to be set - Campbell */
-
- BevPoint *bevp0, *bevp1, *bevp2;
- int nr;
-
- if (bl->poly != -1) {
- bevp2 = bl->bevpoints;
- bevp1 = bevp2 + (bl->nr - 1);
- bevp0 = bevp1 - 1;
- nr = bl->nr;
- }
- else {
- bevp0 = bl->bevpoints;
- bevp1 = bevp0 + 1;
- bevp2 = bevp1 + 1;
-
- nr = bl->nr - 2;
- }
-
- while (nr--) {
- const float x1 = bevp1->vec[0] - bevp0->vec[0];
- const float x2 = bevp1->vec[0] - bevp2->vec[0];
- const float y1 = bevp1->vec[1] - bevp0->vec[1];
- const float y2 = bevp1->vec[1] - bevp2->vec[1];
-
- calc_bevel_sin_cos(x1, y1, x2, y2, &(bevp1->sina), &(bevp1->cosa));
-
- /* from: make_bevel_list_3D_zup, could call but avoid a second loop.
- * no need for tricky tilt calculation as with 3D curves */
- bisect_v3_v3v3v3(bevp1->dir, bevp0->vec, bevp1->vec, bevp2->vec);
- vec_to_quat(bevp1->quat, bevp1->dir, 5, 1);
- /* done with inline make_bevel_list_3D_zup */
-
- bevp0 = bevp1;
- bevp1 = bevp2;
- bevp2++;
- }
-
- /* correct non-cyclic cases */
- if (bl->poly == -1) {
- BevPoint *bevp;
- float angle;
-
- /* first */
- bevp = bl->bevpoints;
- angle = atan2f(bevp->dir[0], bevp->dir[1]) - (float)M_PI_2;
- bevp->sina = sinf(angle);
- bevp->cosa = cosf(angle);
- vec_to_quat(bevp->quat, bevp->dir, 5, 1);
-
- /* last */
- bevp = bl->bevpoints;
- bevp += (bl->nr - 1);
- angle = atan2f(bevp->dir[0], bevp->dir[1]) - (float)M_PI_2;
- bevp->sina = sinf(angle);
- bevp->cosa = cosf(angle);
- vec_to_quat(bevp->quat, bevp->dir, 5, 1);
- }
+ /* note: bevp->dir and bevp->quat are not needed for beveling but are
+ * used when making a path from a 2D curve, therefore they need to be set - Campbell */
+
+ BevPoint *bevp0, *bevp1, *bevp2;
+ int nr;
+
+ if (bl->poly != -1) {
+ bevp2 = bl->bevpoints;
+ bevp1 = bevp2 + (bl->nr - 1);
+ bevp0 = bevp1 - 1;
+ nr = bl->nr;
+ }
+ else {
+ bevp0 = bl->bevpoints;
+ bevp1 = bevp0 + 1;
+ bevp2 = bevp1 + 1;
+
+ nr = bl->nr - 2;
+ }
+
+ while (nr--) {
+ const float x1 = bevp1->vec[0] - bevp0->vec[0];
+ const float x2 = bevp1->vec[0] - bevp2->vec[0];
+ const float y1 = bevp1->vec[1] - bevp0->vec[1];
+ const float y2 = bevp1->vec[1] - bevp2->vec[1];
+
+ calc_bevel_sin_cos(x1, y1, x2, y2, &(bevp1->sina), &(bevp1->cosa));
+
+ /* from: make_bevel_list_3D_zup, could call but avoid a second loop.
+ * no need for tricky tilt calculation as with 3D curves */
+ bisect_v3_v3v3v3(bevp1->dir, bevp0->vec, bevp1->vec, bevp2->vec);
+ vec_to_quat(bevp1->quat, bevp1->dir, 5, 1);
+ /* done with inline make_bevel_list_3D_zup */
+
+ bevp0 = bevp1;
+ bevp1 = bevp2;
+ bevp2++;
+ }
+
+ /* correct non-cyclic cases */
+ if (bl->poly == -1) {
+ BevPoint *bevp;
+ float angle;
+
+ /* first */
+ bevp = bl->bevpoints;
+ angle = atan2f(bevp->dir[0], bevp->dir[1]) - (float)M_PI_2;
+ bevp->sina = sinf(angle);
+ bevp->cosa = cosf(angle);
+ vec_to_quat(bevp->quat, bevp->dir, 5, 1);
+
+ /* last */
+ bevp = bl->bevpoints;
+ bevp += (bl->nr - 1);
+ angle = atan2f(bevp->dir[0], bevp->dir[1]) - (float)M_PI_2;
+ bevp->sina = sinf(angle);
+ bevp->cosa = cosf(angle);
+ vec_to_quat(bevp->quat, bevp->dir, 5, 1);
+ }
}
static void bevlist_firstlast_direction_calc_from_bpoint(Nurb *nu, BevList *bl)
{
- if (nu->pntsu > 1) {
- BPoint *first_bp = nu->bp, *last_bp = nu->bp + (nu->pntsu - 1);
- BevPoint *first_bevp, *last_bevp;
+ if (nu->pntsu > 1) {
+ BPoint *first_bp = nu->bp, *last_bp = nu->bp + (nu->pntsu - 1);
+ BevPoint *first_bevp, *last_bevp;
- first_bevp = bl->bevpoints;
- last_bevp = first_bevp + (bl->nr - 1);
+ first_bevp = bl->bevpoints;
+ last_bevp = first_bevp + (bl->nr - 1);
- sub_v3_v3v3(first_bevp->dir, (first_bp + 1)->vec, first_bp->vec);
- normalize_v3(first_bevp->dir);
+ sub_v3_v3v3(first_bevp->dir, (first_bp + 1)->vec, first_bp->vec);
+ normalize_v3(first_bevp->dir);
- sub_v3_v3v3(last_bevp->dir, last_bp->vec, (last_bp - 1)->vec);
- normalize_v3(last_bevp->dir);
- }
+ sub_v3_v3v3(last_bevp->dir, last_bp->vec, (last_bp - 1)->vec);
+ normalize_v3(last_bevp->dir);
+ }
}
void BKE_curve_bevelList_free(ListBase *bev)
{
- BevList *bl, *blnext;
- for (bl = bev->first; bl != NULL; bl = blnext) {
- blnext = bl->next;
- if (bl->seglen != NULL) {
- MEM_freeN(bl->seglen);
- }
- if (bl->segbevcount != NULL) {
- MEM_freeN(bl->segbevcount);
- }
- if (bl->bevpoints != NULL) {
- MEM_freeN(bl->bevpoints);
- }
- MEM_freeN(bl);
- }
+ BevList *bl, *blnext;
+ for (bl = bev->first; bl != NULL; bl = blnext) {
+ blnext = bl->next;
+ if (bl->seglen != NULL) {
+ MEM_freeN(bl->seglen);
+ }
+ if (bl->segbevcount != NULL) {
+ MEM_freeN(bl->segbevcount);
+ }
+ if (bl->bevpoints != NULL) {
+ MEM_freeN(bl->bevpoints);
+ }
+ MEM_freeN(bl);
+ }
- BLI_listbase_clear(bev);
+ BLI_listbase_clear(bev);
}
void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render)
{
- /*
- * - convert all curves to polys, with indication of resol and flags for double-vertices
- * - possibly; do a smart vertice removal (in case Nurb)
- * - separate in individual blocks with BoundBox
- * - AutoHole detection
- */
-
- /* this function needs an object, because of tflag and upflag */
- Curve *cu = ob->data;
- Nurb *nu;
- BezTriple *bezt, *prevbezt;
- BPoint *bp;
- BevList *bl, *blnew, *blnext;
- BevPoint *bevp2, *bevp1 = NULL, *bevp0;
- const float treshold = 0.00001f;
- float min, inp;
- float *seglen = NULL;
- struct BevelSort *sortdata, *sd, *sd1;
- int a, b, nr, poly, resolu = 0, len = 0, segcount;
- int *segbevcount;
- bool do_tilt, do_radius, do_weight;
- bool is_editmode = false;
- ListBase *bev;
-
- /* segbevcount alsp requires seglen. */
- const bool need_seglen =
- ELEM(cu->bevfac1_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE) ||
- ELEM(cu->bevfac2_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE);
-
-
- bev = &ob->runtime.curve_cache->bev;
-
- /* do we need to calculate the radius for each point? */
- /* do_radius = (cu->bevobj || cu->taperobj || (cu->flag & CU_FRONT) || (cu->flag & CU_BACK)) ? 0 : 1; */
-
- /* STEP 1: MAKE POLYS */
-
- BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev);
- nu = nurbs->first;
- if (cu->editnurb && ob->type != OB_FONT) {
- is_editmode = 1;
- }
-
- for (; nu; nu = nu->next) {
-
- if (nu->hide && is_editmode)
- continue;
-
- /* check if we will calculate tilt data */
- do_tilt = CU_DO_TILT(cu, nu);
- do_radius = CU_DO_RADIUS(cu, nu); /* normal display uses the radius, better just to calculate them */
- do_weight = true;
-
- /* check we are a single point? also check we are not a surface and that the orderu is sane,
- * enforced in the UI but can go wrong possibly */
- if (!BKE_nurb_check_valid_u(nu)) {
- bl = MEM_callocN(sizeof(BevList), "makeBevelList1");
- bl->bevpoints = MEM_calloc_arrayN(1, sizeof(BevPoint), "makeBevelPoints1");
- BLI_addtail(bev, bl);
- bl->nr = 0;
- bl->charidx = nu->charidx;
- }
- else {
- BevPoint *bevp;
-
- if (for_render && cu->resolu_ren != 0)
- resolu = cu->resolu_ren;
- else
- resolu = nu->resolu;
-
- segcount = SEGMENTSU(nu);
-
- if (nu->type == CU_POLY) {
- len = nu->pntsu;
- bl = MEM_callocN(sizeof(BevList), "makeBevelList2");
- bl->bevpoints = MEM_calloc_arrayN(len, sizeof(BevPoint), "makeBevelPoints2");
- if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) {
- bl->seglen = MEM_malloc_arrayN(segcount, sizeof(float), "makeBevelList2_seglen");
- bl->segbevcount = MEM_malloc_arrayN(segcount, sizeof(int), "makeBevelList2_segbevcount");
- }
- BLI_addtail(bev, bl);
-
- bl->poly = (nu->flagu & CU_NURB_CYCLIC) ? 0 : -1;
- bl->nr = len;
- bl->dupe_nr = 0;
- bl->charidx = nu->charidx;
- bevp = bl->bevpoints;
- bevp->offset = 0;
- bp = nu->bp;
- seglen = bl->seglen;
- segbevcount = bl->segbevcount;
-
- while (len--) {
- copy_v3_v3(bevp->vec, bp->vec);
- bevp->tilt = bp->tilt;
- bevp->radius = bp->radius;
- bevp->weight = bp->weight;
- bevp->split_tag = true;
- bp++;
- if (seglen != NULL && len != 0) {
- *seglen = len_v3v3(bevp->vec, bp->vec);
- bevp++;
- bevp->offset = *seglen;
- if (*seglen > treshold) *segbevcount = 1;
- else *segbevcount = 0;
- seglen++;
- segbevcount++;
- }
- else {
- bevp++;
- }
- }
-
- if ((nu->flagu & CU_NURB_CYCLIC) == 0) {
- bevlist_firstlast_direction_calc_from_bpoint(nu, bl);
- }
- }
- else if (nu->type == CU_BEZIER) {
- /* in case last point is not cyclic */
- len = segcount * resolu + 1;
-
- bl = MEM_callocN(sizeof(BevList), "makeBevelBPoints");
- bl->bevpoints = MEM_calloc_arrayN(len, sizeof(BevPoint), "makeBevelBPointsPoints");
- if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) {
- bl->seglen = MEM_malloc_arrayN(segcount, sizeof(float), "makeBevelBPoints_seglen");
- bl->segbevcount = MEM_malloc_arrayN(segcount, sizeof(int), "makeBevelBPoints_segbevcount");
- }
- BLI_addtail(bev, bl);
-
- bl->poly = (nu->flagu & CU_NURB_CYCLIC) ? 0 : -1;
- bl->charidx = nu->charidx;
-
- bevp = bl->bevpoints;
- seglen = bl->seglen;
- segbevcount = bl->segbevcount;
-
- bevp->offset = 0;
- if (seglen != NULL) {
- *seglen = 0;
- *segbevcount = 0;
- }
-
- a = nu->pntsu - 1;
- bezt = nu->bezt;
- if (nu->flagu & CU_NURB_CYCLIC) {
- a++;
- prevbezt = nu->bezt + (nu->pntsu - 1);
- }
- else {
- prevbezt = bezt;
- bezt++;
- }
-
- sub_v3_v3v3(bevp->dir, prevbezt->vec[2], prevbezt->vec[1]);
- normalize_v3(bevp->dir);
-
- BLI_assert(segcount >= a);
-
- while (a--) {
- if (prevbezt->h2 == HD_VECT && bezt->h1 == HD_VECT) {
-
- copy_v3_v3(bevp->vec, prevbezt->vec[1]);
- bevp->tilt = prevbezt->tilt;
- bevp->radius = prevbezt->radius;
- bevp->weight = prevbezt->weight;
- bevp->split_tag = true;
- bevp->dupe_tag = false;
- bevp++;
- bl->nr++;
- bl->dupe_nr = 1;
- if (seglen != NULL) {
- *seglen = len_v3v3(prevbezt->vec[1], bezt->vec[1]);
- bevp->offset = *seglen;
- seglen++;
- /* match segbevcount to the cleaned up bevel lists (see STEP 2) */
- if (bevp->offset > treshold) *segbevcount = 1;
- segbevcount++;
- }
- }
- else {
- /* always do all three, to prevent data hanging around */
- int j;
-
- /* BevPoint must stay aligned to 4 so sizeof(BevPoint)/sizeof(float) works */
- for (j = 0; j < 3; j++) {
- BKE_curve_forward_diff_bezier(prevbezt->vec[1][j], prevbezt->vec[2][j],
- bezt->vec[0][j], bezt->vec[1][j],
- &(bevp->vec[j]), resolu, sizeof(BevPoint));
- }
-
- /* if both arrays are NULL do nothiong */
- tilt_bezpart(prevbezt, bezt, nu,
- do_tilt ? &bevp->tilt : NULL,
- do_radius ? &bevp->radius : NULL,
- do_weight ? &bevp->weight : NULL,
- resolu, sizeof(BevPoint));
-
-
- if (cu->twist_mode == CU_TWIST_TANGENT) {
- forward_diff_bezier_cotangent(prevbezt->vec[1], prevbezt->vec[2],
- bezt->vec[0], bezt->vec[1],
- bevp->tan, resolu, sizeof(BevPoint));
- }
-
- /* indicate with handlecodes double points */
- if (prevbezt->h1 == prevbezt->h2) {
- if (prevbezt->h1 == 0 || prevbezt->h1 == HD_VECT)
- bevp->split_tag = true;
- }
- else {
- if (prevbezt->h1 == 0 || prevbezt->h1 == HD_VECT)
- bevp->split_tag = true;
- else if (prevbezt->h2 == 0 || prevbezt->h2 == HD_VECT)
- bevp->split_tag = true;
- }
-
- /* seglen */
- if (seglen != NULL) {
- *seglen = 0;
- *segbevcount = 0;
- for (j = 0; j < resolu; j++) {
- bevp0 = bevp;
- bevp++;
- bevp->offset = len_v3v3(bevp0->vec, bevp->vec);
- /* match seglen and segbevcount to the cleaned up bevel lists (see STEP 2) */
- if (bevp->offset > treshold) {
- *seglen += bevp->offset;
- *segbevcount += 1;
- }
- }
- seglen++;
- segbevcount++;
- }
- else {
- bevp += resolu;
- }
- bl->nr += resolu;
- }
- prevbezt = bezt;
- bezt++;
- }
-
- if ((nu->flagu & CU_NURB_CYCLIC) == 0) { /* not cyclic: endpoint */
- copy_v3_v3(bevp->vec, prevbezt->vec[1]);
- bevp->tilt = prevbezt->tilt;
- bevp->radius = prevbezt->radius;
- bevp->weight = prevbezt->weight;
-
- sub_v3_v3v3(bevp->dir, prevbezt->vec[1], prevbezt->vec[0]);
- normalize_v3(bevp->dir);
-
- bl->nr++;
- }
- }
- else if (nu->type == CU_NURBS) {
- if (nu->pntsv == 1) {
- len = (resolu * segcount);
-
- bl = MEM_callocN(sizeof(BevList), "makeBevelList3");
- bl->bevpoints = MEM_calloc_arrayN(len, sizeof(BevPoint), "makeBevelPoints3");
- if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) {
- bl->seglen = MEM_malloc_arrayN(segcount, sizeof(float), "makeBevelList3_seglen");
- bl->segbevcount = MEM_malloc_arrayN(segcount, sizeof(int), "makeBevelList3_segbevcount");
- }
- BLI_addtail(bev, bl);
- bl->nr = len;
- bl->dupe_nr = 0;
- bl->poly = (nu->flagu & CU_NURB_CYCLIC) ? 0 : -1;
- bl->charidx = nu->charidx;
-
- bevp = bl->bevpoints;
- seglen = bl->seglen;
- segbevcount = bl->segbevcount;
-
- BKE_nurb_makeCurve(nu, &bevp->vec[0],
- do_tilt ? &bevp->tilt : NULL,
- do_radius ? &bevp->radius : NULL,
- do_weight ? &bevp->weight : NULL,
- resolu, sizeof(BevPoint));
-
- /* match seglen and segbevcount to the cleaned up bevel lists (see STEP 2) */
- if (seglen != NULL) {
- nr = segcount;
- bevp0 = bevp;
- bevp++;
- while (nr) {
- int j;
- *seglen = 0;
- *segbevcount = 0;
- /* We keep last bevel segment zero-length. */
- for (j = 0; j < ((nr == 1) ? (resolu - 1) : resolu); j++) {
- bevp->offset = len_v3v3(bevp0->vec, bevp->vec);
- if (bevp->offset > treshold) {
- *seglen += bevp->offset;
- *segbevcount += 1;
- }
- bevp0 = bevp;
- bevp++;
- }
- seglen++;
- segbevcount++;
- nr--;
- }
- }
-
- if ((nu->flagu & CU_NURB_CYCLIC) == 0) {
- bevlist_firstlast_direction_calc_from_bpoint(nu, bl);
- }
- }
- }
- }
- }
-
- /* STEP 2: DOUBLE POINTS AND AUTOMATIC RESOLUTION, REDUCE DATABLOCKS */
- bl = bev->first;
- while (bl) {
- if (bl->nr) { /* null bevel items come from single points */
- bool is_cyclic = bl->poly != -1;
- nr = bl->nr;
- if (is_cyclic) {
- bevp1 = bl->bevpoints;
- bevp0 = bevp1 + (nr - 1);
- }
- else {
- bevp0 = bl->bevpoints;
- bevp0->offset = 0;
- bevp1 = bevp0 + 1;
- }
- nr--;
- while (nr--) {
- if (seglen != NULL) {
- if (fabsf(bevp1->offset) < treshold) {
- bevp0->dupe_tag = true;
- bl->dupe_nr++;
- }
- }
- else {
- if (fabsf(bevp0->vec[0] - bevp1->vec[0]) < 0.00001f) {
- if (fabsf(bevp0->vec[1] - bevp1->vec[1]) < 0.00001f) {
- if (fabsf(bevp0->vec[2] - bevp1->vec[2]) < 0.00001f) {
- bevp0->dupe_tag = true;
- bl->dupe_nr++;
- }
- }
- }
- }
- bevp0 = bevp1;
- bevp1++;
- }
- }
- bl = bl->next;
- }
- bl = bev->first;
- while (bl) {
- blnext = bl->next;
- if (bl->nr && bl->dupe_nr) {
- nr = bl->nr - bl->dupe_nr + 1; /* +1 because vectorbezier sets flag too */
- blnew = MEM_callocN(sizeof(BevList), "makeBevelList4");
- memcpy(blnew, bl, sizeof(BevList));
- blnew->bevpoints = MEM_calloc_arrayN(nr, sizeof(BevPoint), "makeBevelPoints4");
- if (!blnew->bevpoints) {
- MEM_freeN(blnew);
- break;
- }
- blnew->segbevcount = bl->segbevcount;
- blnew->seglen = bl->seglen;
- blnew->nr = 0;
- BLI_remlink(bev, bl);
- BLI_insertlinkbefore(bev, blnext, blnew); /* to make sure bevlijst is tuned with nurblist */
- bevp0 = bl->bevpoints;
- bevp1 = blnew->bevpoints;
- nr = bl->nr;
- while (nr--) {
- if (bevp0->dupe_tag == 0) {
- memcpy(bevp1, bevp0, sizeof(BevPoint));
- bevp1++;
- blnew->nr++;
- }
- bevp0++;
- }
- if (bl->bevpoints != NULL) {
- MEM_freeN(bl->bevpoints);
- }
- MEM_freeN(bl);
- blnew->dupe_nr = 0;
- }
- bl = blnext;
- }
-
- /* STEP 3: POLYS COUNT AND AUTOHOLE */
- bl = bev->first;
- poly = 0;
- while (bl) {
- if (bl->nr && bl->poly >= 0) {
- poly++;
- bl->poly = poly;
- bl->hole = 0;
- }
- bl = bl->next;
- }
-
- /* find extreme left points, also test (turning) direction */
- if (poly > 0) {
- sd = sortdata = MEM_malloc_arrayN(poly, sizeof(struct BevelSort), "makeBevelList5");
- bl = bev->first;
- while (bl) {
- if (bl->poly > 0) {
- BevPoint *bevp;
-
- min = 300000.0;
- bevp = bl->bevpoints;
- nr = bl->nr;
- while (nr--) {
- if (min > bevp->vec[0]) {
- min = bevp->vec[0];
- bevp1 = bevp;
- }
- bevp++;
- }
- sd->bl = bl;
- sd->left = min;
-
- bevp = bl->bevpoints;
- if (bevp1 == bevp)
- bevp0 = bevp + (bl->nr - 1);
- else
- bevp0 = bevp1 - 1;
- bevp = bevp + (bl->nr - 1);
- if (bevp1 == bevp)
- bevp2 = bl->bevpoints;
- else
- bevp2 = bevp1 + 1;
-
- inp = ((bevp1->vec[0] - bevp0->vec[0]) * (bevp0->vec[1] - bevp2->vec[1]) +
- (bevp0->vec[1] - bevp1->vec[1]) * (bevp0->vec[0] - bevp2->vec[0]));
-
- if (inp > 0.0f)
- sd->dir = 1;
- else
- sd->dir = 0;
-
- sd++;
- }
-
- bl = bl->next;
- }
- qsort(sortdata, poly, sizeof(struct BevelSort), vergxcobev);
-
- sd = sortdata + 1;
- for (a = 1; a < poly; a++, sd++) {
- bl = sd->bl; /* is bl a hole? */
- sd1 = sortdata + (a - 1);
- for (b = a - 1; b >= 0; b--, sd1--) { /* all polys to the left */
- if (sd1->bl->charidx == bl->charidx) { /* for text, only check matching char */
- if (bevelinside(sd1->bl, bl)) {
- bl->hole = 1 - sd1->bl->hole;
- break;
- }
- }
- }
- }
-
- /* turning direction */
- if ((cu->flag & CU_3D) == 0) {
- sd = sortdata;
- for (a = 0; a < poly; a++, sd++) {
- if (sd->bl->hole == sd->dir) {
- bl = sd->bl;
- bevp1 = bl->bevpoints;
- bevp2 = bevp1 + (bl->nr - 1);
- nr = bl->nr / 2;
- while (nr--) {
- SWAP(BevPoint, *bevp1, *bevp2);
- bevp1++;
- bevp2--;
- }
- }
- }
- }
- MEM_freeN(sortdata);
- }
-
- /* STEP 4: 2D-COSINES or 3D ORIENTATION */
- if ((cu->flag & CU_3D) == 0) {
- /* 2D Curves */
- for (bl = bev->first; bl; bl = bl->next) {
- if (bl->nr < 2) {
- BevPoint *bevp = bl->bevpoints;
- unit_qt(bevp->quat);
- }
- else if (bl->nr == 2) { /* 2 pnt, treat separate */
- make_bevel_list_segment_2D(bl);
- }
- else {
- make_bevel_list_2D(bl);
- }
- }
- }
- else {
- /* 3D Curves */
- for (bl = bev->first; bl; bl = bl->next) {
- if (bl->nr < 2) {
- BevPoint *bevp = bl->bevpoints;
- unit_qt(bevp->quat);
- }
- else if (bl->nr == 2) { /* 2 pnt, treat separate */
- make_bevel_list_segment_3D(bl);
- }
- else {
- make_bevel_list_3D(bl, (int)(resolu * cu->twist_smooth), cu->twist_mode);
- }
- }
- }
+ /*
+ * - convert all curves to polys, with indication of resol and flags for double-vertices
+ * - possibly; do a smart vertice removal (in case Nurb)
+ * - separate in individual blocks with BoundBox
+ * - AutoHole detection
+ */
+
+ /* this function needs an object, because of tflag and upflag */
+ Curve *cu = ob->data;
+ Nurb *nu;
+ BezTriple *bezt, *prevbezt;
+ BPoint *bp;
+ BevList *bl, *blnew, *blnext;
+ BevPoint *bevp2, *bevp1 = NULL, *bevp0;
+ const float treshold = 0.00001f;
+ float min, inp;
+ float *seglen = NULL;
+ struct BevelSort *sortdata, *sd, *sd1;
+ int a, b, nr, poly, resolu = 0, len = 0, segcount;
+ int *segbevcount;
+ bool do_tilt, do_radius, do_weight;
+ bool is_editmode = false;
+ ListBase *bev;
+
+ /* segbevcount alsp requires seglen. */
+ const bool need_seglen = ELEM(
+ cu->bevfac1_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE) ||
+ ELEM(cu->bevfac2_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE);
+
+ bev = &ob->runtime.curve_cache->bev;
+
+ /* do we need to calculate the radius for each point? */
+ /* do_radius = (cu->bevobj || cu->taperobj || (cu->flag & CU_FRONT) || (cu->flag & CU_BACK)) ? 0 : 1; */
+
+ /* STEP 1: MAKE POLYS */
+
+ BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev);
+ nu = nurbs->first;
+ if (cu->editnurb && ob->type != OB_FONT) {
+ is_editmode = 1;
+ }
+
+ for (; nu; nu = nu->next) {
+
+ if (nu->hide && is_editmode)
+ continue;
+
+ /* check if we will calculate tilt data */
+ do_tilt = CU_DO_TILT(cu, nu);
+ do_radius = CU_DO_RADIUS(
+ cu, nu); /* normal display uses the radius, better just to calculate them */
+ do_weight = true;
+
+ /* check we are a single point? also check we are not a surface and that the orderu is sane,
+ * enforced in the UI but can go wrong possibly */
+ if (!BKE_nurb_check_valid_u(nu)) {
+ bl = MEM_callocN(sizeof(BevList), "makeBevelList1");
+ bl->bevpoints = MEM_calloc_arrayN(1, sizeof(BevPoint), "makeBevelPoints1");
+ BLI_addtail(bev, bl);
+ bl->nr = 0;
+ bl->charidx = nu->charidx;
+ }
+ else {
+ BevPoint *bevp;
+
+ if (for_render && cu->resolu_ren != 0)
+ resolu = cu->resolu_ren;
+ else
+ resolu = nu->resolu;
+
+ segcount = SEGMENTSU(nu);
+
+ if (nu->type == CU_POLY) {
+ len = nu->pntsu;
+ bl = MEM_callocN(sizeof(BevList), "makeBevelList2");
+ bl->bevpoints = MEM_calloc_arrayN(len, sizeof(BevPoint), "makeBevelPoints2");
+ if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) {
+ bl->seglen = MEM_malloc_arrayN(segcount, sizeof(float), "makeBevelList2_seglen");
+ bl->segbevcount = MEM_malloc_arrayN(segcount, sizeof(int), "makeBevelList2_segbevcount");
+ }
+ BLI_addtail(bev, bl);
+
+ bl->poly = (nu->flagu & CU_NURB_CYCLIC) ? 0 : -1;
+ bl->nr = len;
+ bl->dupe_nr = 0;
+ bl->charidx = nu->charidx;
+ bevp = bl->bevpoints;
+ bevp->offset = 0;
+ bp = nu->bp;
+ seglen = bl->seglen;
+ segbevcount = bl->segbevcount;
+
+ while (len--) {
+ copy_v3_v3(bevp->vec, bp->vec);
+ bevp->tilt = bp->tilt;
+ bevp->radius = bp->radius;
+ bevp->weight = bp->weight;
+ bevp->split_tag = true;
+ bp++;
+ if (seglen != NULL && len != 0) {
+ *seglen = len_v3v3(bevp->vec, bp->vec);
+ bevp++;
+ bevp->offset = *seglen;
+ if (*seglen > treshold)
+ *segbevcount = 1;
+ else
+ *segbevcount = 0;
+ seglen++;
+ segbevcount++;
+ }
+ else {
+ bevp++;
+ }
+ }
+
+ if ((nu->flagu & CU_NURB_CYCLIC) == 0) {
+ bevlist_firstlast_direction_calc_from_bpoint(nu, bl);
+ }
+ }
+ else if (nu->type == CU_BEZIER) {
+ /* in case last point is not cyclic */
+ len = segcount * resolu + 1;
+
+ bl = MEM_callocN(sizeof(BevList), "makeBevelBPoints");
+ bl->bevpoints = MEM_calloc_arrayN(len, sizeof(BevPoint), "makeBevelBPointsPoints");
+ if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) {
+ bl->seglen = MEM_malloc_arrayN(segcount, sizeof(float), "makeBevelBPoints_seglen");
+ bl->segbevcount = MEM_malloc_arrayN(
+ segcount, sizeof(int), "makeBevelBPoints_segbevcount");
+ }
+ BLI_addtail(bev, bl);
+
+ bl->poly = (nu->flagu & CU_NURB_CYCLIC) ? 0 : -1;
+ bl->charidx = nu->charidx;
+
+ bevp = bl->bevpoints;
+ seglen = bl->seglen;
+ segbevcount = bl->segbevcount;
+
+ bevp->offset = 0;
+ if (seglen != NULL) {
+ *seglen = 0;
+ *segbevcount = 0;
+ }
+
+ a = nu->pntsu - 1;
+ bezt = nu->bezt;
+ if (nu->flagu & CU_NURB_CYCLIC) {
+ a++;
+ prevbezt = nu->bezt + (nu->pntsu - 1);
+ }
+ else {
+ prevbezt = bezt;
+ bezt++;
+ }
+
+ sub_v3_v3v3(bevp->dir, prevbezt->vec[2], prevbezt->vec[1]);
+ normalize_v3(bevp->dir);
+
+ BLI_assert(segcount >= a);
+
+ while (a--) {
+ if (prevbezt->h2 == HD_VECT && bezt->h1 == HD_VECT) {
+
+ copy_v3_v3(bevp->vec, prevbezt->vec[1]);
+ bevp->tilt = prevbezt->tilt;
+ bevp->radius = prevbezt->radius;
+ bevp->weight = prevbezt->weight;
+ bevp->split_tag = true;
+ bevp->dupe_tag = false;
+ bevp++;
+ bl->nr++;
+ bl->dupe_nr = 1;
+ if (seglen != NULL) {
+ *seglen = len_v3v3(prevbezt->vec[1], bezt->vec[1]);
+ bevp->offset = *seglen;
+ seglen++;
+ /* match segbevcount to the cleaned up bevel lists (see STEP 2) */
+ if (bevp->offset > treshold)
+ *segbevcount = 1;
+ segbevcount++;
+ }
+ }
+ else {
+ /* always do all three, to prevent data hanging around */
+ int j;
+
+ /* BevPoint must stay aligned to 4 so sizeof(BevPoint)/sizeof(float) works */
+ for (j = 0; j < 3; j++) {
+ BKE_curve_forward_diff_bezier(prevbezt->vec[1][j],
+ prevbezt->vec[2][j],
+ bezt->vec[0][j],
+ bezt->vec[1][j],
+ &(bevp->vec[j]),
+ resolu,
+ sizeof(BevPoint));
+ }
+
+ /* if both arrays are NULL do nothiong */
+ tilt_bezpart(prevbezt,
+ bezt,
+ nu,
+ do_tilt ? &bevp->tilt : NULL,
+ do_radius ? &bevp->radius : NULL,
+ do_weight ? &bevp->weight : NULL,
+ resolu,
+ sizeof(BevPoint));
+
+ if (cu->twist_mode == CU_TWIST_TANGENT) {
+ forward_diff_bezier_cotangent(prevbezt->vec[1],
+ prevbezt->vec[2],
+ bezt->vec[0],
+ bezt->vec[1],
+ bevp->tan,
+ resolu,
+ sizeof(BevPoint));
+ }
+
+ /* indicate with handlecodes double points */
+ if (prevbezt->h1 == prevbezt->h2) {
+ if (prevbezt->h1 == 0 || prevbezt->h1 == HD_VECT)
+ bevp->split_tag = true;
+ }
+ else {
+ if (prevbezt->h1 == 0 || prevbezt->h1 == HD_VECT)
+ bevp->split_tag = true;
+ else if (prevbezt->h2 == 0 || prevbezt->h2 == HD_VECT)
+ bevp->split_tag = true;
+ }
+
+ /* seglen */
+ if (seglen != NULL) {
+ *seglen = 0;
+ *segbevcount = 0;
+ for (j = 0; j < resolu; j++) {
+ bevp0 = bevp;
+ bevp++;
+ bevp->offset = len_v3v3(bevp0->vec, bevp->vec);
+ /* match seglen and segbevcount to the cleaned up bevel lists (see STEP 2) */
+ if (bevp->offset > treshold) {
+ *seglen += bevp->offset;
+ *segbevcount += 1;
+ }
+ }
+ seglen++;
+ segbevcount++;
+ }
+ else {
+ bevp += resolu;
+ }
+ bl->nr += resolu;
+ }
+ prevbezt = bezt;
+ bezt++;
+ }
+
+ if ((nu->flagu & CU_NURB_CYCLIC) == 0) { /* not cyclic: endpoint */
+ copy_v3_v3(bevp->vec, prevbezt->vec[1]);
+ bevp->tilt = prevbezt->tilt;
+ bevp->radius = prevbezt->radius;
+ bevp->weight = prevbezt->weight;
+
+ sub_v3_v3v3(bevp->dir, prevbezt->vec[1], prevbezt->vec[0]);
+ normalize_v3(bevp->dir);
+
+ bl->nr++;
+ }
+ }
+ else if (nu->type == CU_NURBS) {
+ if (nu->pntsv == 1) {
+ len = (resolu * segcount);
+
+ bl = MEM_callocN(sizeof(BevList), "makeBevelList3");
+ bl->bevpoints = MEM_calloc_arrayN(len, sizeof(BevPoint), "makeBevelPoints3");
+ if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) {
+ bl->seglen = MEM_malloc_arrayN(segcount, sizeof(float), "makeBevelList3_seglen");
+ bl->segbevcount = MEM_malloc_arrayN(
+ segcount, sizeof(int), "makeBevelList3_segbevcount");
+ }
+ BLI_addtail(bev, bl);
+ bl->nr = len;
+ bl->dupe_nr = 0;
+ bl->poly = (nu->flagu & CU_NURB_CYCLIC) ? 0 : -1;
+ bl->charidx = nu->charidx;
+
+ bevp = bl->bevpoints;
+ seglen = bl->seglen;
+ segbevcount = bl->segbevcount;
+
+ BKE_nurb_makeCurve(nu,
+ &bevp->vec[0],
+ do_tilt ? &bevp->tilt : NULL,
+ do_radius ? &bevp->radius : NULL,
+ do_weight ? &bevp->weight : NULL,
+ resolu,
+ sizeof(BevPoint));
+
+ /* match seglen and segbevcount to the cleaned up bevel lists (see STEP 2) */
+ if (seglen != NULL) {
+ nr = segcount;
+ bevp0 = bevp;
+ bevp++;
+ while (nr) {
+ int j;
+ *seglen = 0;
+ *segbevcount = 0;
+ /* We keep last bevel segment zero-length. */
+ for (j = 0; j < ((nr == 1) ? (resolu - 1) : resolu); j++) {
+ bevp->offset = len_v3v3(bevp0->vec, bevp->vec);
+ if (bevp->offset > treshold) {
+ *seglen += bevp->offset;
+ *segbevcount += 1;
+ }
+ bevp0 = bevp;
+ bevp++;
+ }
+ seglen++;
+ segbevcount++;
+ nr--;
+ }
+ }
+
+ if ((nu->flagu & CU_NURB_CYCLIC) == 0) {
+ bevlist_firstlast_direction_calc_from_bpoint(nu, bl);
+ }
+ }
+ }
+ }
+ }
+
+ /* STEP 2: DOUBLE POINTS AND AUTOMATIC RESOLUTION, REDUCE DATABLOCKS */
+ bl = bev->first;
+ while (bl) {
+ if (bl->nr) { /* null bevel items come from single points */
+ bool is_cyclic = bl->poly != -1;
+ nr = bl->nr;
+ if (is_cyclic) {
+ bevp1 = bl->bevpoints;
+ bevp0 = bevp1 + (nr - 1);
+ }
+ else {
+ bevp0 = bl->bevpoints;
+ bevp0->offset = 0;
+ bevp1 = bevp0 + 1;
+ }
+ nr--;
+ while (nr--) {
+ if (seglen != NULL) {
+ if (fabsf(bevp1->offset) < treshold) {
+ bevp0->dupe_tag = true;
+ bl->dupe_nr++;
+ }
+ }
+ else {
+ if (fabsf(bevp0->vec[0] - bevp1->vec[0]) < 0.00001f) {
+ if (fabsf(bevp0->vec[1] - bevp1->vec[1]) < 0.00001f) {
+ if (fabsf(bevp0->vec[2] - bevp1->vec[2]) < 0.00001f) {
+ bevp0->dupe_tag = true;
+ bl->dupe_nr++;
+ }
+ }
+ }
+ }
+ bevp0 = bevp1;
+ bevp1++;
+ }
+ }
+ bl = bl->next;
+ }
+ bl = bev->first;
+ while (bl) {
+ blnext = bl->next;
+ if (bl->nr && bl->dupe_nr) {
+ nr = bl->nr - bl->dupe_nr + 1; /* +1 because vectorbezier sets flag too */
+ blnew = MEM_callocN(sizeof(BevList), "makeBevelList4");
+ memcpy(blnew, bl, sizeof(BevList));
+ blnew->bevpoints = MEM_calloc_arrayN(nr, sizeof(BevPoint), "makeBevelPoints4");
+ if (!blnew->bevpoints) {
+ MEM_freeN(blnew);
+ break;
+ }
+ blnew->segbevcount = bl->segbevcount;
+ blnew->seglen = bl->seglen;
+ blnew->nr = 0;
+ BLI_remlink(bev, bl);
+ BLI_insertlinkbefore(bev, blnext, blnew); /* to make sure bevlijst is tuned with nurblist */
+ bevp0 = bl->bevpoints;
+ bevp1 = blnew->bevpoints;
+ nr = bl->nr;
+ while (nr--) {
+ if (bevp0->dupe_tag == 0) {
+ memcpy(bevp1, bevp0, sizeof(BevPoint));
+ bevp1++;
+ blnew->nr++;
+ }
+ bevp0++;
+ }
+ if (bl->bevpoints != NULL) {
+ MEM_freeN(bl->bevpoints);
+ }
+ MEM_freeN(bl);
+ blnew->dupe_nr = 0;
+ }
+ bl = blnext;
+ }
+
+ /* STEP 3: POLYS COUNT AND AUTOHOLE */
+ bl = bev->first;
+ poly = 0;
+ while (bl) {
+ if (bl->nr && bl->poly >= 0) {
+ poly++;
+ bl->poly = poly;
+ bl->hole = 0;
+ }
+ bl = bl->next;
+ }
+
+ /* find extreme left points, also test (turning) direction */
+ if (poly > 0) {
+ sd = sortdata = MEM_malloc_arrayN(poly, sizeof(struct BevelSort), "makeBevelList5");
+ bl = bev->first;
+ while (bl) {
+ if (bl->poly > 0) {
+ BevPoint *bevp;
+
+ min = 300000.0;
+ bevp = bl->bevpoints;
+ nr = bl->nr;
+ while (nr--) {
+ if (min > bevp->vec[0]) {
+ min = bevp->vec[0];
+ bevp1 = bevp;
+ }
+ bevp++;
+ }
+ sd->bl = bl;
+ sd->left = min;
+
+ bevp = bl->bevpoints;
+ if (bevp1 == bevp)
+ bevp0 = bevp + (bl->nr - 1);
+ else
+ bevp0 = bevp1 - 1;
+ bevp = bevp + (bl->nr - 1);
+ if (bevp1 == bevp)
+ bevp2 = bl->bevpoints;
+ else
+ bevp2 = bevp1 + 1;
+
+ inp = ((bevp1->vec[0] - bevp0->vec[0]) * (bevp0->vec[1] - bevp2->vec[1]) +
+ (bevp0->vec[1] - bevp1->vec[1]) * (bevp0->vec[0] - bevp2->vec[0]));
+
+ if (inp > 0.0f)
+ sd->dir = 1;
+ else
+ sd->dir = 0;
+
+ sd++;
+ }
+
+ bl = bl->next;
+ }
+ qsort(sortdata, poly, sizeof(struct BevelSort), vergxcobev);
+
+ sd = sortdata + 1;
+ for (a = 1; a < poly; a++, sd++) {
+ bl = sd->bl; /* is bl a hole? */
+ sd1 = sortdata + (a - 1);
+ for (b = a - 1; b >= 0; b--, sd1--) { /* all polys to the left */
+ if (sd1->bl->charidx == bl->charidx) { /* for text, only check matching char */
+ if (bevelinside(sd1->bl, bl)) {
+ bl->hole = 1 - sd1->bl->hole;
+ break;
+ }
+ }
+ }
+ }
+
+ /* turning direction */
+ if ((cu->flag & CU_3D) == 0) {
+ sd = sortdata;
+ for (a = 0; a < poly; a++, sd++) {
+ if (sd->bl->hole == sd->dir) {
+ bl = sd->bl;
+ bevp1 = bl->bevpoints;
+ bevp2 = bevp1 + (bl->nr - 1);
+ nr = bl->nr / 2;
+ while (nr--) {
+ SWAP(BevPoint, *bevp1, *bevp2);
+ bevp1++;
+ bevp2--;
+ }
+ }
+ }
+ }
+ MEM_freeN(sortdata);
+ }
+
+ /* STEP 4: 2D-COSINES or 3D ORIENTATION */
+ if ((cu->flag & CU_3D) == 0) {
+ /* 2D Curves */
+ for (bl = bev->first; bl; bl = bl->next) {
+ if (bl->nr < 2) {
+ BevPoint *bevp = bl->bevpoints;
+ unit_qt(bevp->quat);
+ }
+ else if (bl->nr == 2) { /* 2 pnt, treat separate */
+ make_bevel_list_segment_2D(bl);
+ }
+ else {
+ make_bevel_list_2D(bl);
+ }
+ }
+ }
+ else {
+ /* 3D Curves */
+ for (bl = bev->first; bl; bl = bl->next) {
+ if (bl->nr < 2) {
+ BevPoint *bevp = bl->bevpoints;
+ unit_qt(bevp->quat);
+ }
+ else if (bl->nr == 2) { /* 2 pnt, treat separate */
+ make_bevel_list_segment_3D(bl);
+ }
+ else {
+ make_bevel_list_3D(bl, (int)(resolu * cu->twist_smooth), cu->twist_mode);
+ }
+ }
+ }
}
/* ****************** HANDLES ************** */
-static void calchandleNurb_intern(
- BezTriple *bezt, const BezTriple *prev, const BezTriple *next,
- bool is_fcurve, bool skip_align, char fcurve_smoothing)
+static void calchandleNurb_intern(BezTriple *bezt,
+ const BezTriple *prev,
+ const BezTriple *next,
+ bool is_fcurve,
+ bool skip_align,
+ char fcurve_smoothing)
{
- /* defines to avoid confusion */
-#define p2_h1 ((p2) - 3)
+ /* defines to avoid confusion */
+#define p2_h1 ((p2)-3)
#define p2_h2 ((p2) + 3)
- const float *p1, *p3;
- float *p2;
- float pt[3];
- float dvec_a[3], dvec_b[3];
- float len, len_a, len_b;
- float len_ratio;
- const float eps = 1e-5;
-
- /* assume normal handle until we check */
- bezt->f5 = HD_AUTOTYPE_NORMAL;
-
- if (bezt->h1 == 0 && bezt->h2 == 0) {
- return;
- }
-
- p2 = bezt->vec[1];
-
- if (prev == NULL) {
- p3 = next->vec[1];
- pt[0] = 2.0f * p2[0] - p3[0];
- pt[1] = 2.0f * p2[1] - p3[1];
- pt[2] = 2.0f * p2[2] - p3[2];
- p1 = pt;
- }
- else {
- p1 = prev->vec[1];
- }
-
- if (next == NULL) {
- pt[0] = 2.0f * p2[0] - p1[0];
- pt[1] = 2.0f * p2[1] - p1[1];
- pt[2] = 2.0f * p2[2] - p1[2];
- p3 = pt;
- }
- else {
- p3 = next->vec[1];
- }
-
- sub_v3_v3v3(dvec_a, p2, p1);
- sub_v3_v3v3(dvec_b, p3, p2);
-
- if (is_fcurve) {
- len_a = dvec_a[0];
- len_b = dvec_b[0];
- }
- else {
- len_a = len_v3(dvec_a);
- len_b = len_v3(dvec_b);
- }
-
- if (len_a == 0.0f) len_a = 1.0f;
- if (len_b == 0.0f) len_b = 1.0f;
-
- len_ratio = len_a / len_b;
-
- if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) || ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) { /* auto */
- float tvec[3];
- tvec[0] = dvec_b[0] / len_b + dvec_a[0] / len_a;
- tvec[1] = dvec_b[1] / len_b + dvec_a[1] / len_a;
- tvec[2] = dvec_b[2] / len_b + dvec_a[2] / len_a;
-
- if (is_fcurve) {
- if (fcurve_smoothing != FCURVE_SMOOTH_NONE) {
- /* force the horizontal handle size to be 1/3 of the key interval so that
- * the X component of the parametric bezier curve is a linear spline */
- len = 6.0f / 2.5614f;
- }
- else {
- len = tvec[0];
- }
- }
- else {
- len = len_v3(tvec);
- }
- len *= 2.5614f;
-
- if (len != 0.0f) {
- /* only for fcurves */
- bool leftviolate = false, rightviolate = false;
-
- if (!is_fcurve || fcurve_smoothing == FCURVE_SMOOTH_NONE) {
- if (len_a > 5.0f * len_b)
- len_a = 5.0f * len_b;
- if (len_b > 5.0f * len_a)
- len_b = 5.0f * len_a;
- }
-
- if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM)) {
- len_a /= len;
- madd_v3_v3v3fl(p2_h1, p2, tvec, -len_a);
-
- if ((bezt->h1 == HD_AUTO_ANIM) && next && prev) { /* keep horizontal if extrema */
- float ydiff1 = prev->vec[1][1] - bezt->vec[1][1];
- float ydiff2 = next->vec[1][1] - bezt->vec[1][1];
- if ((ydiff1 <= 0.0f && ydiff2 <= 0.0f) || (ydiff1 >= 0.0f && ydiff2 >= 0.0f)) {
- bezt->vec[0][1] = bezt->vec[1][1];
- bezt->f5 = HD_AUTOTYPE_SPECIAL;
- }
- else { /* handles should not be beyond y coord of two others */
- if (ydiff1 <= 0.0f) {
- if (prev->vec[1][1] > bezt->vec[0][1]) {
- bezt->vec[0][1] = prev->vec[1][1];
- leftviolate = 1;
- }
- }
- else {
- if (prev->vec[1][1] < bezt->vec[0][1]) {
- bezt->vec[0][1] = prev->vec[1][1];
- leftviolate = 1;
- }
- }
- }
- }
- }
- if (ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) {
- len_b /= len;
- madd_v3_v3v3fl(p2_h2, p2, tvec, len_b);
-
- if ((bezt->h2 == HD_AUTO_ANIM) && next && prev) { /* keep horizontal if extrema */
- float ydiff1 = prev->vec[1][1] - bezt->vec[1][1];
- float ydiff2 = next->vec[1][1] - bezt->vec[1][1];
- if ((ydiff1 <= 0.0f && ydiff2 <= 0.0f) || (ydiff1 >= 0.0f && ydiff2 >= 0.0f)) {
- bezt->vec[2][1] = bezt->vec[1][1];
- bezt->f5 = HD_AUTOTYPE_SPECIAL;
- }
- else { /* handles should not be beyond y coord of two others */
- if (ydiff1 <= 0.0f) {
- if (next->vec[1][1] < bezt->vec[2][1]) {
- bezt->vec[2][1] = next->vec[1][1];
- rightviolate = 1;
- }
- }
- else {
- if (next->vec[1][1] > bezt->vec[2][1]) {
- bezt->vec[2][1] = next->vec[1][1];
- rightviolate = 1;
- }
- }
- }
- }
- }
- if (leftviolate || rightviolate) { /* align left handle */
- BLI_assert(is_fcurve);
- /* simple 2d calculation */
- float h1_x = p2_h1[0] - p2[0];
- float h2_x = p2[0] - p2_h2[0];
-
- if (leftviolate) {
- p2_h2[1] = p2[1] + ((p2[1] - p2_h1[1]) / h1_x) * h2_x;
- }
- else {
- p2_h1[1] = p2[1] + ((p2[1] - p2_h2[1]) / h2_x) * h1_x;
- }
- }
- }
- }
-
- if (bezt->h1 == HD_VECT) { /* vector */
- madd_v3_v3v3fl(p2_h1, p2, dvec_a, -1.0f / 3.0f);
- }
- if (bezt->h2 == HD_VECT) {
- madd_v3_v3v3fl(p2_h2, p2, dvec_b, 1.0f / 3.0f);
- }
-
- if (skip_align ||
- /* when one handle is free, alignming makes no sense, see: T35952 */
- (ELEM(HD_FREE, bezt->h1, bezt->h2)) ||
- /* also when no handles are aligned, skip this step */
- (!ELEM(HD_ALIGN, bezt->h1, bezt->h2) &&
- !ELEM(HD_ALIGN_DOUBLESIDE, bezt->h1, bezt->h2)))
- {
- /* handles need to be updated during animation and applying stuff like hooks,
- * but in such situations it's quite difficult to distinguish in which order
- * align handles should be aligned so skip them for now */
- return;
- }
-
- len_a = len_v3v3(p2, p2_h1);
- len_b = len_v3v3(p2, p2_h2);
-
- if (len_a == 0.0f) len_a = 1.0f;
- if (len_b == 0.0f) len_b = 1.0f;
-
- len_ratio = len_a / len_b;
-
- if (bezt->f1 & SELECT) { /* order of calculation */
- if (ELEM(bezt->h2, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) { /* aligned */
- if (len_a > eps) {
- len = 1.0f / len_ratio;
- p2_h2[0] = p2[0] + len * (p2[0] - p2_h1[0]);
- p2_h2[1] = p2[1] + len * (p2[1] - p2_h1[1]);
- p2_h2[2] = p2[2] + len * (p2[2] - p2_h1[2]);
- }
- }
- if (ELEM(bezt->h1, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) {
- if (len_b > eps) {
- len = len_ratio;
- p2_h1[0] = p2[0] + len * (p2[0] - p2_h2[0]);
- p2_h1[1] = p2[1] + len * (p2[1] - p2_h2[1]);
- p2_h1[2] = p2[2] + len * (p2[2] - p2_h2[2]);
- }
- }
- }
- else {
- if (ELEM(bezt->h1, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) {
- if (len_b > eps) {
- len = len_ratio;
- p2_h1[0] = p2[0] + len * (p2[0] - p2_h2[0]);
- p2_h1[1] = p2[1] + len * (p2[1] - p2_h2[1]);
- p2_h1[2] = p2[2] + len * (p2[2] - p2_h2[2]);
- }
- }
- if (ELEM(bezt->h2, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) { /* aligned */
- if (len_a > eps) {
- len = 1.0f / len_ratio;
- p2_h2[0] = p2[0] + len * (p2[0] - p2_h1[0]);
- p2_h2[1] = p2[1] + len * (p2[1] - p2_h1[1]);
- p2_h2[2] = p2[2] + len * (p2[2] - p2_h1[2]);
- }
- }
- }
+ const float *p1, *p3;
+ float *p2;
+ float pt[3];
+ float dvec_a[3], dvec_b[3];
+ float len, len_a, len_b;
+ float len_ratio;
+ const float eps = 1e-5;
+
+ /* assume normal handle until we check */
+ bezt->f5 = HD_AUTOTYPE_NORMAL;
+
+ if (bezt->h1 == 0 && bezt->h2 == 0) {
+ return;
+ }
+
+ p2 = bezt->vec[1];
+
+ if (prev == NULL) {
+ p3 = next->vec[1];
+ pt[0] = 2.0f * p2[0] - p3[0];
+ pt[1] = 2.0f * p2[1] - p3[1];
+ pt[2] = 2.0f * p2[2] - p3[2];
+ p1 = pt;
+ }
+ else {
+ p1 = prev->vec[1];
+ }
+
+ if (next == NULL) {
+ pt[0] = 2.0f * p2[0] - p1[0];
+ pt[1] = 2.0f * p2[1] - p1[1];
+ pt[2] = 2.0f * p2[2] - p1[2];
+ p3 = pt;
+ }
+ else {
+ p3 = next->vec[1];
+ }
+
+ sub_v3_v3v3(dvec_a, p2, p1);
+ sub_v3_v3v3(dvec_b, p3, p2);
+
+ if (is_fcurve) {
+ len_a = dvec_a[0];
+ len_b = dvec_b[0];
+ }
+ else {
+ len_a = len_v3(dvec_a);
+ len_b = len_v3(dvec_b);
+ }
+
+ if (len_a == 0.0f)
+ len_a = 1.0f;
+ if (len_b == 0.0f)
+ len_b = 1.0f;
+
+ len_ratio = len_a / len_b;
+
+ if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) || ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) { /* auto */
+ float tvec[3];
+ tvec[0] = dvec_b[0] / len_b + dvec_a[0] / len_a;
+ tvec[1] = dvec_b[1] / len_b + dvec_a[1] / len_a;
+ tvec[2] = dvec_b[2] / len_b + dvec_a[2] / len_a;
+
+ if (is_fcurve) {
+ if (fcurve_smoothing != FCURVE_SMOOTH_NONE) {
+ /* force the horizontal handle size to be 1/3 of the key interval so that
+ * the X component of the parametric bezier curve is a linear spline */
+ len = 6.0f / 2.5614f;
+ }
+ else {
+ len = tvec[0];
+ }
+ }
+ else {
+ len = len_v3(tvec);
+ }
+ len *= 2.5614f;
+
+ if (len != 0.0f) {
+ /* only for fcurves */
+ bool leftviolate = false, rightviolate = false;
+
+ if (!is_fcurve || fcurve_smoothing == FCURVE_SMOOTH_NONE) {
+ if (len_a > 5.0f * len_b)
+ len_a = 5.0f * len_b;
+ if (len_b > 5.0f * len_a)
+ len_b = 5.0f * len_a;
+ }
+
+ if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM)) {
+ len_a /= len;
+ madd_v3_v3v3fl(p2_h1, p2, tvec, -len_a);
+
+ if ((bezt->h1 == HD_AUTO_ANIM) && next && prev) { /* keep horizontal if extrema */
+ float ydiff1 = prev->vec[1][1] - bezt->vec[1][1];
+ float ydiff2 = next->vec[1][1] - bezt->vec[1][1];
+ if ((ydiff1 <= 0.0f && ydiff2 <= 0.0f) || (ydiff1 >= 0.0f && ydiff2 >= 0.0f)) {
+ bezt->vec[0][1] = bezt->vec[1][1];
+ bezt->f5 = HD_AUTOTYPE_SPECIAL;
+ }
+ else { /* handles should not be beyond y coord of two others */
+ if (ydiff1 <= 0.0f) {
+ if (prev->vec[1][1] > bezt->vec[0][1]) {
+ bezt->vec[0][1] = prev->vec[1][1];
+ leftviolate = 1;
+ }
+ }
+ else {
+ if (prev->vec[1][1] < bezt->vec[0][1]) {
+ bezt->vec[0][1] = prev->vec[1][1];
+ leftviolate = 1;
+ }
+ }
+ }
+ }
+ }
+ if (ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) {
+ len_b /= len;
+ madd_v3_v3v3fl(p2_h2, p2, tvec, len_b);
+
+ if ((bezt->h2 == HD_AUTO_ANIM) && next && prev) { /* keep horizontal if extrema */
+ float ydiff1 = prev->vec[1][1] - bezt->vec[1][1];
+ float ydiff2 = next->vec[1][1] - bezt->vec[1][1];
+ if ((ydiff1 <= 0.0f && ydiff2 <= 0.0f) || (ydiff1 >= 0.0f && ydiff2 >= 0.0f)) {
+ bezt->vec[2][1] = bezt->vec[1][1];
+ bezt->f5 = HD_AUTOTYPE_SPECIAL;
+ }
+ else { /* handles should not be beyond y coord of two others */
+ if (ydiff1 <= 0.0f) {
+ if (next->vec[1][1] < bezt->vec[2][1]) {
+ bezt->vec[2][1] = next->vec[1][1];
+ rightviolate = 1;
+ }
+ }
+ else {
+ if (next->vec[1][1] > bezt->vec[2][1]) {
+ bezt->vec[2][1] = next->vec[1][1];
+ rightviolate = 1;
+ }
+ }
+ }
+ }
+ }
+ if (leftviolate || rightviolate) { /* align left handle */
+ BLI_assert(is_fcurve);
+ /* simple 2d calculation */
+ float h1_x = p2_h1[0] - p2[0];
+ float h2_x = p2[0] - p2_h2[0];
+
+ if (leftviolate) {
+ p2_h2[1] = p2[1] + ((p2[1] - p2_h1[1]) / h1_x) * h2_x;
+ }
+ else {
+ p2_h1[1] = p2[1] + ((p2[1] - p2_h2[1]) / h2_x) * h1_x;
+ }
+ }
+ }
+ }
+
+ if (bezt->h1 == HD_VECT) { /* vector */
+ madd_v3_v3v3fl(p2_h1, p2, dvec_a, -1.0f / 3.0f);
+ }
+ if (bezt->h2 == HD_VECT) {
+ madd_v3_v3v3fl(p2_h2, p2, dvec_b, 1.0f / 3.0f);
+ }
+
+ if (skip_align ||
+ /* when one handle is free, alignming makes no sense, see: T35952 */
+ (ELEM(HD_FREE, bezt->h1, bezt->h2)) ||
+ /* also when no handles are aligned, skip this step */
+ (!ELEM(HD_ALIGN, bezt->h1, bezt->h2) && !ELEM(HD_ALIGN_DOUBLESIDE, bezt->h1, bezt->h2))) {
+ /* handles need to be updated during animation and applying stuff like hooks,
+ * but in such situations it's quite difficult to distinguish in which order
+ * align handles should be aligned so skip them for now */
+ return;
+ }
+
+ len_a = len_v3v3(p2, p2_h1);
+ len_b = len_v3v3(p2, p2_h2);
+
+ if (len_a == 0.0f)
+ len_a = 1.0f;
+ if (len_b == 0.0f)
+ len_b = 1.0f;
+
+ len_ratio = len_a / len_b;
+
+ if (bezt->f1 & SELECT) { /* order of calculation */
+ if (ELEM(bezt->h2, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) { /* aligned */
+ if (len_a > eps) {
+ len = 1.0f / len_ratio;
+ p2_h2[0] = p2[0] + len * (p2[0] - p2_h1[0]);
+ p2_h2[1] = p2[1] + len * (p2[1] - p2_h1[1]);
+ p2_h2[2] = p2[2] + len * (p2[2] - p2_h1[2]);
+ }
+ }
+ if (ELEM(bezt->h1, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) {
+ if (len_b > eps) {
+ len = len_ratio;
+ p2_h1[0] = p2[0] + len * (p2[0] - p2_h2[0]);
+ p2_h1[1] = p2[1] + len * (p2[1] - p2_h2[1]);
+ p2_h1[2] = p2[2] + len * (p2[2] - p2_h2[2]);
+ }
+ }
+ }
+ else {
+ if (ELEM(bezt->h1, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) {
+ if (len_b > eps) {
+ len = len_ratio;
+ p2_h1[0] = p2[0] + len * (p2[0] - p2_h2[0]);
+ p2_h1[1] = p2[1] + len * (p2[1] - p2_h2[1]);
+ p2_h1[2] = p2[2] + len * (p2[2] - p2_h2[2]);
+ }
+ }
+ if (ELEM(bezt->h2, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) { /* aligned */
+ if (len_a > eps) {
+ len = 1.0f / len_ratio;
+ p2_h2[0] = p2[0] + len * (p2[0] - p2_h1[0]);
+ p2_h2[1] = p2[1] + len * (p2[1] - p2_h1[1]);
+ p2_h2[2] = p2[2] + len * (p2[2] - p2_h1[2]);
+ }
+ }
+ }
#undef p2_h1
#undef p2_h2
@@ -3508,34 +3584,36 @@ static void calchandleNurb_intern(
static void calchandlesNurb_intern(Nurb *nu, bool skip_align)
{
- BezTriple *bezt, *prev, *next;
- int a;
-
- if (nu->type != CU_BEZIER)
- return;
- if (nu->pntsu < 2)
- return;
-
- a = nu->pntsu;
- bezt = nu->bezt;
- if (nu->flagu & CU_NURB_CYCLIC) prev = bezt + (a - 1);
- else prev = NULL;
- next = bezt + 1;
-
- while (a--) {
- calchandleNurb_intern(bezt, prev, next, 0, skip_align, 0);
- prev = bezt;
- if (a == 1) {
- if (nu->flagu & CU_NURB_CYCLIC)
- next = nu->bezt;
- else
- next = NULL;
- }
- else
- next++;
-
- bezt++;
- }
+ BezTriple *bezt, *prev, *next;
+ int a;
+
+ if (nu->type != CU_BEZIER)
+ return;
+ if (nu->pntsu < 2)
+ return;
+
+ a = nu->pntsu;
+ bezt = nu->bezt;
+ if (nu->flagu & CU_NURB_CYCLIC)
+ prev = bezt + (a - 1);
+ else
+ prev = NULL;
+ next = bezt + 1;
+
+ while (a--) {
+ calchandleNurb_intern(bezt, prev, next, 0, skip_align, 0);
+ prev = bezt;
+ if (a == 1) {
+ if (nu->flagu & CU_NURB_CYCLIC)
+ next = nu->bezt;
+ else
+ next = NULL;
+ }
+ else
+ next++;
+
+ bezt++;
+ }
}
/* A utility function for allocating a number of arrays of the same length
@@ -3548,146 +3626,146 @@ static void calchandlesNurb_intern(Nurb *nu, bool skip_align)
*/
static void *allocate_arrays(int count, float ***floats, char ***chars, const char *name)
{
- size_t num_floats = 0, num_chars = 0;
+ size_t num_floats = 0, num_chars = 0;
- while (floats && floats[num_floats]) {
- num_floats++;
- }
+ while (floats && floats[num_floats]) {
+ num_floats++;
+ }
- while (chars && chars[num_chars]) {
- num_chars++;
- }
+ while (chars && chars[num_chars]) {
+ num_chars++;
+ }
- void *buffer = (float *)MEM_malloc_arrayN(count, (sizeof(float) * num_floats + num_chars), name);
+ void *buffer = (float *)MEM_malloc_arrayN(count, (sizeof(float) * num_floats + num_chars), name);
- if (!buffer)
- return NULL;
+ if (!buffer)
+ return NULL;
- float *fptr = buffer;
+ float *fptr = buffer;
- for (int i = 0; i < num_floats; i++, fptr += count) {
- *floats[i] = fptr;
- }
+ for (int i = 0; i < num_floats; i++, fptr += count) {
+ *floats[i] = fptr;
+ }
- char *cptr = (char *)fptr;
+ char *cptr = (char *)fptr;
- for (int i = 0; i < num_chars; i++, cptr += count) {
- *chars[i] = cptr;
- }
+ for (int i = 0; i < num_chars; i++, cptr += count) {
+ *chars[i] = cptr;
+ }
- return buffer;
+ return buffer;
}
static void free_arrays(void *buffer)
{
- MEM_freeN(buffer);
+ MEM_freeN(buffer);
}
/* computes in which direction to change h[i] to satisfy conditions better */
-static float bezier_relax_direction(float *a, float *b, float *c, float *d, float *h, int i, int count)
+static float bezier_relax_direction(
+ float *a, float *b, float *c, float *d, float *h, int i, int count)
{
- /* current deviation between sides of the equation */
- float state = a[i] * h[(i + count - 1) % count] +
- b[i] * h[i] +
- c[i] * h[(i + 1) % count] -
- d[i];
+ /* current deviation between sides of the equation */
+ float state = a[i] * h[(i + count - 1) % count] + b[i] * h[i] + c[i] * h[(i + 1) % count] - d[i];
- /* only the sign is meaningful */
- return -state * b[i];
+ /* only the sign is meaningful */
+ return -state * b[i];
}
static void bezier_lock_unknown(float *a, float *b, float *c, float *d, int i, float value)
{
- a[i] = c[i] = 0.0f;
- b[i] = 1.0f;
- d[i] = value;
+ a[i] = c[i] = 0.0f;
+ b[i] = 1.0f;
+ d[i] = value;
}
-static void bezier_restore_equation(float *a, float *b, float *c, float *d, float *a0, float *b0, float *c0, float *d0, int i)
+static void bezier_restore_equation(
+ float *a, float *b, float *c, float *d, float *a0, float *b0, float *c0, float *d0, int i)
{
- a[i] = a0[i];
- b[i] = b0[i];
- c[i] = c0[i];
- d[i] = d0[i];
+ a[i] = a0[i];
+ b[i] = b0[i];
+ c[i] = c0[i];
+ d[i] = d0[i];
}
-static bool tridiagonal_solve_with_limits(float *a, float *b, float *c, float *d, float *h, float *hmin, float *hmax, int solve_count)
+static bool tridiagonal_solve_with_limits(
+ float *a, float *b, float *c, float *d, float *h, float *hmin, float *hmax, int solve_count)
{
- float *a0, *b0, *c0, *d0;
- float **arrays[] = { &a0, &b0, &c0, &d0, NULL };
- char *is_locked, *num_unlocks;
- char **flagarrays[] = { &is_locked, &num_unlocks, NULL };
+ float *a0, *b0, *c0, *d0;
+ float **arrays[] = {&a0, &b0, &c0, &d0, NULL};
+ char *is_locked, *num_unlocks;
+ char **flagarrays[] = {&is_locked, &num_unlocks, NULL};
- void *tmps = allocate_arrays(solve_count, arrays, flagarrays, "tridiagonal_solve_with_limits");
- if (!tmps)
- return false;
+ void *tmps = allocate_arrays(solve_count, arrays, flagarrays, "tridiagonal_solve_with_limits");
+ if (!tmps)
+ return false;
- memcpy(a0, a, sizeof(float) * solve_count);
- memcpy(b0, b, sizeof(float) * solve_count);
- memcpy(c0, c, sizeof(float) * solve_count);
- memcpy(d0, d, sizeof(float) * solve_count);
+ memcpy(a0, a, sizeof(float) * solve_count);
+ memcpy(b0, b, sizeof(float) * solve_count);
+ memcpy(c0, c, sizeof(float) * solve_count);
+ memcpy(d0, d, sizeof(float) * solve_count);
- memset(is_locked, 0, solve_count);
- memset(num_unlocks, 0, solve_count);
+ memset(is_locked, 0, solve_count);
+ memset(num_unlocks, 0, solve_count);
- bool overshoot, unlocked;
+ bool overshoot, unlocked;
- do {
- if (!BLI_tridiagonal_solve_cyclic(a, b, c, d, h, solve_count)) {
- free_arrays(tmps);
- return false;
- }
+ do {
+ if (!BLI_tridiagonal_solve_cyclic(a, b, c, d, h, solve_count)) {
+ free_arrays(tmps);
+ return false;
+ }
- /* first check if any handles overshoot the limits, and lock them */
- bool all = false, locked = false;
+ /* first check if any handles overshoot the limits, and lock them */
+ bool all = false, locked = false;
- overshoot = unlocked = false;
+ overshoot = unlocked = false;
- do {
- for (int i = 0; i < solve_count; i++) {
- if (h[i] >= hmin[i] && h[i] <= hmax[i])
- continue;
+ do {
+ for (int i = 0; i < solve_count; i++) {
+ if (h[i] >= hmin[i] && h[i] <= hmax[i])
+ continue;
- overshoot = true;
+ overshoot = true;
- float target = h[i] > hmax[i] ? hmax[i] : hmin[i];
+ float target = h[i] > hmax[i] ? hmax[i] : hmin[i];
- /* heuristically only lock handles that go in the right direction if there are such ones */
- if (target != 0.0f || all) {
- /* mark item locked */
- is_locked[i] = 1;
+ /* heuristically only lock handles that go in the right direction if there are such ones */
+ if (target != 0.0f || all) {
+ /* mark item locked */
+ is_locked[i] = 1;
- bezier_lock_unknown(a, b, c, d, i, target);
- locked = true;
- }
- }
+ bezier_lock_unknown(a, b, c, d, i, target);
+ locked = true;
+ }
+ }
- all = true;
- } while (overshoot && !locked);
+ all = true;
+ } while (overshoot && !locked);
- /* if no handles overshot and were locked, see if it may be a good idea to unlock some handles */
- if (!locked) {
- for (int i = 0; i < solve_count; i++) {
- // to definitely avoid infinite loops limit this to 2 times
- if (!is_locked[i] || num_unlocks[i] >= 2)
- continue;
+ /* if no handles overshot and were locked, see if it may be a good idea to unlock some handles */
+ if (!locked) {
+ for (int i = 0; i < solve_count; i++) {
+ // to definitely avoid infinite loops limit this to 2 times
+ if (!is_locked[i] || num_unlocks[i] >= 2)
+ continue;
- /* if the handle wants to move in allowable direction, release it */
- float relax = bezier_relax_direction(a0, b0, c0, d0, h, i, solve_count);
+ /* if the handle wants to move in allowable direction, release it */
+ float relax = bezier_relax_direction(a0, b0, c0, d0, h, i, solve_count);
- if ((relax > 0 && h[i] < hmax[i]) || (relax < 0 && h[i] > hmin[i])) {
- bezier_restore_equation(a, b, c, d, a0, b0, c0, d0, i);
+ if ((relax > 0 && h[i] < hmax[i]) || (relax < 0 && h[i] > hmin[i])) {
+ bezier_restore_equation(a, b, c, d, a0, b0, c0, d0, i);
- is_locked[i] = 0;
- num_unlocks[i]++;
- unlocked = true;
- }
- }
- }
- } while (overshoot || unlocked);
+ is_locked[i] = 0;
+ num_unlocks[i]++;
+ unlocked = true;
+ }
+ }
+ }
+ } while (overshoot || unlocked);
- free_arrays(tmps);
- return true;
+ free_arrays(tmps);
+ return true;
}
/*
@@ -3742,339 +3820,347 @@ static bool tridiagonal_solve_with_limits(float *a, float *b, float *c, float *d
* equation with parts omitted, so the handle size correction also applies.
*/
-
-static void bezier_eq_continuous(float *a, float *b, float *c, float *d, float *dy, float *l, int i)
+static void bezier_eq_continuous(
+ float *a, float *b, float *c, float *d, float *dy, float *l, int i)
{
- a[i] = l[i] * l[i];
- b[i] = 2.0f * (l[i] + 1);
- c[i] = 1.0f / l[i + 1];
- d[i] = dy[i] * l[i] * l[i] + dy[i + 1];
+ a[i] = l[i] * l[i];
+ b[i] = 2.0f * (l[i] + 1);
+ c[i] = 1.0f / l[i + 1];
+ d[i] = dy[i] * l[i] * l[i] + dy[i + 1];
}
-static void bezier_eq_noaccel_right(float *a, float *b, float *c, float *d, float *dy, float *l, int i)
+static void bezier_eq_noaccel_right(
+ float *a, float *b, float *c, float *d, float *dy, float *l, int i)
{
- a[i] = 0.0f;
- b[i] = 2.0f;
- c[i] = 1.0f / l[i + 1];
- d[i] = dy[i + 1];
+ a[i] = 0.0f;
+ b[i] = 2.0f;
+ c[i] = 1.0f / l[i + 1];
+ d[i] = dy[i + 1];
}
-static void bezier_eq_noaccel_left(float *a, float *b, float *c, float *d, float *dy, float *l, int i)
+static void bezier_eq_noaccel_left(
+ float *a, float *b, float *c, float *d, float *dy, float *l, int i)
{
- a[i] = l[i] * l[i];
- b[i] = 2.0f * l[i];
- c[i] = 0.0f;
- d[i] = dy[i] * l[i] * l[i];
+ a[i] = l[i] * l[i];
+ b[i] = 2.0f * l[i];
+ c[i] = 0.0f;
+ d[i] = dy[i] * l[i] * l[i];
}
/* auto clamp prevents its own point going the wrong way, and adjacent handles overshooting */
-static void bezier_clamp(float *hmax, float *hmin, int i, float dy, bool no_reverse, bool no_overshoot)
-{
- if (dy > 0) {
- if (no_overshoot)
- hmax[i] = min_ff(hmax[i], dy);
- if (no_reverse)
- hmin[i] = 0.0f;
- }
- else if (dy < 0) {
- if (no_reverse)
- hmax[i] = 0.0f;
- if (no_overshoot)
- hmin[i] = max_ff(hmin[i], dy);
- }
- else if (no_reverse || no_overshoot) {
- hmax[i] = hmin[i] = 0.0f;
- }
+static void bezier_clamp(
+ float *hmax, float *hmin, int i, float dy, bool no_reverse, bool no_overshoot)
+{
+ if (dy > 0) {
+ if (no_overshoot)
+ hmax[i] = min_ff(hmax[i], dy);
+ if (no_reverse)
+ hmin[i] = 0.0f;
+ }
+ else if (dy < 0) {
+ if (no_reverse)
+ hmax[i] = 0.0f;
+ if (no_overshoot)
+ hmin[i] = max_ff(hmin[i], dy);
+ }
+ else if (no_reverse || no_overshoot) {
+ hmax[i] = hmin[i] = 0.0f;
+ }
}
/* write changes to a bezier handle */
static void bezier_output_handle_inner(BezTriple *bezt, bool right, float newval[3], bool endpoint)
{
- float tmp[3];
+ float tmp[3];
- int idx = right ? 2 : 0;
- char hr = right ? bezt->h2 : bezt->h1;
- char hm = right ? bezt->h1 : bezt->h2;
+ int idx = right ? 2 : 0;
+ char hr = right ? bezt->h2 : bezt->h1;
+ char hm = right ? bezt->h1 : bezt->h2;
- /* only assign Auto/Vector handles */
- if (!ELEM(hr, HD_AUTO, HD_AUTO_ANIM, HD_VECT))
- return;
+ /* only assign Auto/Vector handles */
+ if (!ELEM(hr, HD_AUTO, HD_AUTO_ANIM, HD_VECT))
+ return;
- copy_v3_v3(bezt->vec[idx], newval);
+ copy_v3_v3(bezt->vec[idx], newval);
- /* fix up the Align handle if any */
- if (ELEM(hm, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) {
- float hlen = len_v3v3(bezt->vec[1], bezt->vec[2 - idx]);
- float h2len = len_v3v3(bezt->vec[1], bezt->vec[idx]);
+ /* fix up the Align handle if any */
+ if (ELEM(hm, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) {
+ float hlen = len_v3v3(bezt->vec[1], bezt->vec[2 - idx]);
+ float h2len = len_v3v3(bezt->vec[1], bezt->vec[idx]);
- sub_v3_v3v3(tmp, bezt->vec[1], bezt->vec[idx]);
- madd_v3_v3v3fl(bezt->vec[2 - idx], bezt->vec[1], tmp, hlen / h2len);
- }
- /* at end points of the curve, mirror handle to the other side */
- else if (endpoint && ELEM(hm, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) {
- sub_v3_v3v3(tmp, bezt->vec[1], bezt->vec[idx]);
- add_v3_v3v3(bezt->vec[2 - idx], bezt->vec[1], tmp);
- }
+ sub_v3_v3v3(tmp, bezt->vec[1], bezt->vec[idx]);
+ madd_v3_v3v3fl(bezt->vec[2 - idx], bezt->vec[1], tmp, hlen / h2len);
+ }
+ /* at end points of the curve, mirror handle to the other side */
+ else if (endpoint && ELEM(hm, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) {
+ sub_v3_v3v3(tmp, bezt->vec[1], bezt->vec[idx]);
+ add_v3_v3v3(bezt->vec[2 - idx], bezt->vec[1], tmp);
+ }
}
static void bezier_output_handle(BezTriple *bezt, bool right, float dy, bool endpoint)
{
- float tmp[3];
+ float tmp[3];
- copy_v3_v3(tmp, bezt->vec[right ? 2 : 0]);
+ copy_v3_v3(tmp, bezt->vec[right ? 2 : 0]);
- tmp[1] = bezt->vec[1][1] + dy;
+ tmp[1] = bezt->vec[1][1] + dy;
- bezier_output_handle_inner(bezt, right, tmp, endpoint);
+ bezier_output_handle_inner(bezt, right, tmp, endpoint);
}
static bool bezier_check_solve_end_handle(BezTriple *bezt, char htype, bool end)
{
- return (htype == HD_VECT) || (end && ELEM(htype, HD_AUTO, HD_AUTO_ANIM) && bezt->f5 == HD_AUTOTYPE_NORMAL);
+ return (htype == HD_VECT) ||
+ (end && ELEM(htype, HD_AUTO, HD_AUTO_ANIM) && bezt->f5 == HD_AUTOTYPE_NORMAL);
}
static float bezier_calc_handle_adj(float hsize[2], float dx)
{
- /* if handles intersect in x direction, they are scaled to fit */
- float fac = dx / (hsize[0] + dx / 3.0f);
- if (fac < 1.0f) {
- mul_v2_fl(hsize, fac);
- }
- return 1.0f - 3.0f * hsize[0] / dx;
+ /* if handles intersect in x direction, they are scaled to fit */
+ float fac = dx / (hsize[0] + dx / 3.0f);
+ if (fac < 1.0f) {
+ mul_v2_fl(hsize, fac);
+ }
+ return 1.0f - 3.0f * hsize[0] / dx;
}
-static void bezier_handle_calc_smooth_fcurve(BezTriple *bezt, int total, int start, int count, bool cycle)
+static void bezier_handle_calc_smooth_fcurve(
+ BezTriple *bezt, int total, int start, int count, bool cycle)
{
- float *dx, *dy, *l, *a, *b, *c, *d, *h, *hmax, *hmin;
- float **arrays[] = { &dx, &dy, &l, &a, &b, &c, &d, &h, &hmax, &hmin, NULL };
+ float *dx, *dy, *l, *a, *b, *c, *d, *h, *hmax, *hmin;
+ float **arrays[] = {&dx, &dy, &l, &a, &b, &c, &d, &h, &hmax, &hmin, NULL};
- int solve_count = count;
+ int solve_count = count;
- /* verify index ranges */
+ /* verify index ranges */
- if (count < 2)
- return;
+ if (count < 2)
+ return;
- BLI_assert(start < total - 1 && count <= total);
- BLI_assert(start + count <= total || cycle);
+ BLI_assert(start < total - 1 && count <= total);
+ BLI_assert(start + count <= total || cycle);
- bool full_cycle = (start == 0 && count == total && cycle);
+ bool full_cycle = (start == 0 && count == total && cycle);
- BezTriple *bezt_first = &bezt[start];
- BezTriple *bezt_last = &bezt[(start + count > total) ? start + count - total : start + count - 1];
+ BezTriple *bezt_first = &bezt[start];
+ BezTriple *bezt_last =
+ &bezt[(start + count > total) ? start + count - total : start + count - 1];
- bool solve_first = bezier_check_solve_end_handle(bezt_first, bezt_first->h2, start == 0);
- bool solve_last = bezier_check_solve_end_handle(bezt_last, bezt_last->h1, start + count == total);
+ bool solve_first = bezier_check_solve_end_handle(bezt_first, bezt_first->h2, start == 0);
+ bool solve_last = bezier_check_solve_end_handle(
+ bezt_last, bezt_last->h1, start + count == total);
- if (count == 2 && !full_cycle && solve_first == solve_last) {
- return;
- }
+ if (count == 2 && !full_cycle && solve_first == solve_last) {
+ return;
+ }
- /* allocate all */
+ /* allocate all */
- void *tmp_buffer = allocate_arrays(count, arrays, NULL, "bezier_calc_smooth_tmp");
- if (!tmp_buffer)
- return;
+ void *tmp_buffer = allocate_arrays(count, arrays, NULL, "bezier_calc_smooth_tmp");
+ if (!tmp_buffer)
+ return;
- /* point locations */
+ /* point locations */
- dx[0] = dy[0] = NAN_FLT;
+ dx[0] = dy[0] = NAN_FLT;
- for (int i = 1, j = start + 1; i < count; i++, j++) {
- dx[i] = bezt[j].vec[1][0] - bezt[j - 1].vec[1][0];
- dy[i] = bezt[j].vec[1][1] - bezt[j - 1].vec[1][1];
+ for (int i = 1, j = start + 1; i < count; i++, j++) {
+ dx[i] = bezt[j].vec[1][0] - bezt[j - 1].vec[1][0];
+ dy[i] = bezt[j].vec[1][1] - bezt[j - 1].vec[1][1];
- /* when cyclic, jump from last point to first */
- if (cycle && j == total - 1)
- j = 0;
- }
+ /* when cyclic, jump from last point to first */
+ if (cycle && j == total - 1)
+ j = 0;
+ }
- /* ratio of x intervals */
+ /* ratio of x intervals */
- l[0] = l[count - 1] = 1.0f;
+ l[0] = l[count - 1] = 1.0f;
- for (int i = 1; i < count - 1; i++) {
- l[i] = dx[i + 1] / dx[i];
- }
+ for (int i = 1; i < count - 1; i++) {
+ l[i] = dx[i + 1] / dx[i];
+ }
- /* compute handle clamp ranges */
+ /* compute handle clamp ranges */
- bool clamped_prev = false, clamped_cur = ELEM(HD_AUTO_ANIM, bezt_first->h1, bezt_first->h2);
+ bool clamped_prev = false, clamped_cur = ELEM(HD_AUTO_ANIM, bezt_first->h1, bezt_first->h2);
- for (int i = 0; i < count; i++) {
- hmax[i] = FLT_MAX;
- hmin[i] = -FLT_MAX;
- }
+ for (int i = 0; i < count; i++) {
+ hmax[i] = FLT_MAX;
+ hmin[i] = -FLT_MAX;
+ }
- for (int i = 1, j = start + 1; i < count; i++, j++) {
- clamped_prev = clamped_cur;
- clamped_cur = ELEM(HD_AUTO_ANIM, bezt[j].h1, bezt[j].h2);
+ for (int i = 1, j = start + 1; i < count; i++, j++) {
+ clamped_prev = clamped_cur;
+ clamped_cur = ELEM(HD_AUTO_ANIM, bezt[j].h1, bezt[j].h2);
- if (cycle && j == total - 1) {
- j = 0;
- clamped_cur = clamped_cur || ELEM(HD_AUTO_ANIM, bezt[j].h1, bezt[j].h2);
- }
+ if (cycle && j == total - 1) {
+ j = 0;
+ clamped_cur = clamped_cur || ELEM(HD_AUTO_ANIM, bezt[j].h1, bezt[j].h2);
+ }
- bezier_clamp(hmax, hmin, i - 1, dy[i], clamped_prev, clamped_prev);
- bezier_clamp(hmax, hmin, i, dy[i] * l[i], clamped_cur, clamped_cur);
- }
+ bezier_clamp(hmax, hmin, i - 1, dy[i], clamped_prev, clamped_prev);
+ bezier_clamp(hmax, hmin, i, dy[i] * l[i], clamped_cur, clamped_cur);
+ }
- /* full cycle merges first and last points into continuous loop */
+ /* full cycle merges first and last points into continuous loop */
- float first_handle_adj = 0.0f, last_handle_adj = 0.0f;
+ float first_handle_adj = 0.0f, last_handle_adj = 0.0f;
- if (full_cycle) {
- /* reduce the number of unknowns by one */
- int i = solve_count = count - 1;
+ if (full_cycle) {
+ /* reduce the number of unknowns by one */
+ int i = solve_count = count - 1;
- dx[0] = dx[i];
- dy[0] = dy[i];
+ dx[0] = dx[i];
+ dy[0] = dy[i];
- l[0] = l[i] = dx[1] / dx[0];
+ l[0] = l[i] = dx[1] / dx[0];
- hmin[0] = max_ff(hmin[0], hmin[i]);
- hmax[0] = min_ff(hmax[0], hmax[i]);
+ hmin[0] = max_ff(hmin[0], hmin[i]);
+ hmax[0] = min_ff(hmax[0], hmax[i]);
- solve_first = solve_last = true;
+ solve_first = solve_last = true;
- bezier_eq_continuous(a, b, c, d, dy, l, 0);
- }
- else {
- float tmp[2];
+ bezier_eq_continuous(a, b, c, d, dy, l, 0);
+ }
+ else {
+ float tmp[2];
- /* boundary condition: fixed handles or zero curvature */
- if (!solve_first) {
- sub_v2_v2v2(tmp, bezt_first->vec[2], bezt_first->vec[1]);
- first_handle_adj = bezier_calc_handle_adj(tmp, dx[1]);
+ /* boundary condition: fixed handles or zero curvature */
+ if (!solve_first) {
+ sub_v2_v2v2(tmp, bezt_first->vec[2], bezt_first->vec[1]);
+ first_handle_adj = bezier_calc_handle_adj(tmp, dx[1]);
- bezier_lock_unknown(a, b, c, d, 0, tmp[1]);
- }
- else {
- bezier_eq_noaccel_right(a, b, c, d, dy, l, 0);
- }
+ bezier_lock_unknown(a, b, c, d, 0, tmp[1]);
+ }
+ else {
+ bezier_eq_noaccel_right(a, b, c, d, dy, l, 0);
+ }
- if (!solve_last) {
- sub_v2_v2v2(tmp, bezt_last->vec[1], bezt_last->vec[0]);
- last_handle_adj = bezier_calc_handle_adj(tmp, dx[count - 1]);
+ if (!solve_last) {
+ sub_v2_v2v2(tmp, bezt_last->vec[1], bezt_last->vec[0]);
+ last_handle_adj = bezier_calc_handle_adj(tmp, dx[count - 1]);
- bezier_lock_unknown(a, b, c, d, count - 1, tmp[1]);
- }
- else {
- bezier_eq_noaccel_left(a, b, c, d, dy, l, count - 1);
- }
- }
+ bezier_lock_unknown(a, b, c, d, count - 1, tmp[1]);
+ }
+ else {
+ bezier_eq_noaccel_left(a, b, c, d, dy, l, count - 1);
+ }
+ }
- /* main tridiagonal system of equations */
+ /* main tridiagonal system of equations */
- for (int i = 1; i < count - 1; i++) {
- bezier_eq_continuous(a, b, c, d, dy, l, i);
- }
+ for (int i = 1; i < count - 1; i++) {
+ bezier_eq_continuous(a, b, c, d, dy, l, i);
+ }
- /* apply correction for user-defined handles with nonstandard x positions */
+ /* apply correction for user-defined handles with nonstandard x positions */
- if (!full_cycle) {
- if (count > 2 || solve_last) {
- b[1] += l[1] * first_handle_adj;
- }
+ if (!full_cycle) {
+ if (count > 2 || solve_last) {
+ b[1] += l[1] * first_handle_adj;
+ }
- if (count > 2 || solve_first) {
- b[count - 2] += last_handle_adj;
- }
- }
+ if (count > 2 || solve_first) {
+ b[count - 2] += last_handle_adj;
+ }
+ }
- /* solve and output results */
+ /* solve and output results */
- if (tridiagonal_solve_with_limits(a, b, c, d, h, hmin, hmax, solve_count)) {
- if (full_cycle) {
- h[count - 1] = h[0];
- }
+ if (tridiagonal_solve_with_limits(a, b, c, d, h, hmin, hmax, solve_count)) {
+ if (full_cycle) {
+ h[count - 1] = h[0];
+ }
- for (int i = 1, j = start + 1; i < count - 1; i++, j++) {
- bool end = (j == total - 1);
+ for (int i = 1, j = start + 1; i < count - 1; i++, j++) {
+ bool end = (j == total - 1);
- bezier_output_handle(&bezt[j], false, -h[i] / l[i], end);
+ bezier_output_handle(&bezt[j], false, -h[i] / l[i], end);
- if (end)
- j = 0;
+ if (end)
+ j = 0;
- bezier_output_handle(&bezt[j], true, h[i], end);
- }
+ bezier_output_handle(&bezt[j], true, h[i], end);
+ }
- if (solve_first) {
- bezier_output_handle(bezt_first, true, h[0], start == 0);
- }
+ if (solve_first) {
+ bezier_output_handle(bezt_first, true, h[0], start == 0);
+ }
- if (solve_last) {
- bezier_output_handle(bezt_last, false, -h[count - 1] / l[count - 1], start + count == total);
- }
- }
+ if (solve_last) {
+ bezier_output_handle(bezt_last, false, -h[count - 1] / l[count - 1], start + count == total);
+ }
+ }
- /* free all */
+ /* free all */
- free_arrays(tmp_buffer);
+ free_arrays(tmp_buffer);
}
static bool is_free_auto_point(BezTriple *bezt)
{
- return BEZT_IS_AUTOH(bezt) && bezt->f5 == HD_AUTOTYPE_NORMAL;
+ return BEZT_IS_AUTOH(bezt) && bezt->f5 == HD_AUTOTYPE_NORMAL;
}
void BKE_nurb_handle_smooth_fcurve(BezTriple *bezt, int total, bool cycle)
{
- /* ignore cyclic extrapolation if end points are locked */
- cycle = cycle && is_free_auto_point(&bezt[0]) && is_free_auto_point(&bezt[total - 1]);
+ /* ignore cyclic extrapolation if end points are locked */
+ cycle = cycle && is_free_auto_point(&bezt[0]) && is_free_auto_point(&bezt[total - 1]);
- /* if cyclic, try to find a sequence break point */
- int search_base = 0;
+ /* if cyclic, try to find a sequence break point */
+ int search_base = 0;
- if (cycle) {
- for (int i = 1; i < total - 1; i++) {
- if (!is_free_auto_point(&bezt[i])) {
- search_base = i;
- break;
- }
- }
+ if (cycle) {
+ for (int i = 1; i < total - 1; i++) {
+ if (!is_free_auto_point(&bezt[i])) {
+ search_base = i;
+ break;
+ }
+ }
- /* all points of the curve are freely changeable auto handles - solve as full cycle */
- if (search_base == 0) {
- bezier_handle_calc_smooth_fcurve(bezt, total, 0, total, cycle);
- return;
- }
- }
+ /* all points of the curve are freely changeable auto handles - solve as full cycle */
+ if (search_base == 0) {
+ bezier_handle_calc_smooth_fcurve(bezt, total, 0, total, cycle);
+ return;
+ }
+ }
- /* Find continuous subsequences of free auto handles and smooth them, starting at
- * search_base. In cyclic mode these subsequences can span the cycle boundary. */
- int start = search_base, count = 1;
+ /* Find continuous subsequences of free auto handles and smooth them, starting at
+ * search_base. In cyclic mode these subsequences can span the cycle boundary. */
+ int start = search_base, count = 1;
- for (int i = 1, j = start + 1; i < total; i++, j++) {
- /* in cyclic mode: jump from last to first point when necessary */
- if (j == total - 1 && cycle)
- j = 0;
+ for (int i = 1, j = start + 1; i < total; i++, j++) {
+ /* in cyclic mode: jump from last to first point when necessary */
+ if (j == total - 1 && cycle)
+ j = 0;
- /* non auto handle closes the list (we come here at least for the last handle, see above) */
- if (!is_free_auto_point(&bezt[j])) {
- bezier_handle_calc_smooth_fcurve(bezt, total, start, count + 1, cycle);
- start = j;
- count = 1;
- }
- else {
- count++;
- }
- }
+ /* non auto handle closes the list (we come here at least for the last handle, see above) */
+ if (!is_free_auto_point(&bezt[j])) {
+ bezier_handle_calc_smooth_fcurve(bezt, total, start, count + 1, cycle);
+ start = j;
+ count = 1;
+ }
+ else {
+ count++;
+ }
+ }
- if (count > 1) {
- bezier_handle_calc_smooth_fcurve(bezt, total, start, count, cycle);
- }
+ if (count > 1) {
+ bezier_handle_calc_smooth_fcurve(bezt, total, start, count, cycle);
+ }
}
-void BKE_nurb_handle_calc(BezTriple *bezt, BezTriple *prev, BezTriple *next, const bool is_fcurve, const char smoothing)
+void BKE_nurb_handle_calc(
+ BezTriple *bezt, BezTriple *prev, BezTriple *next, const bool is_fcurve, const char smoothing)
{
- calchandleNurb_intern(bezt, prev, next, is_fcurve, false, smoothing);
+ calchandleNurb_intern(bezt, prev, next, is_fcurve, false, smoothing);
}
void BKE_nurb_handles_calc(Nurb *nu) /* first, if needed, set handle flags */
{
- calchandlesNurb_intern(nu, false);
+ calchandlesNurb_intern(nu, false);
}
/**
@@ -4083,49 +4169,49 @@ void BKE_nurb_handles_calc(Nurb *nu) /* first, if needed, set handle flags */
*/
static void nurbList_handles_swap_select(Nurb *nu)
{
- BezTriple *bezt;
- int i;
+ BezTriple *bezt;
+ int i;
- for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
- if ((bezt->f1 & SELECT) != (bezt->f3 & SELECT)) {
- bezt->f1 ^= SELECT;
- bezt->f3 ^= SELECT;
- }
- }
+ for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
+ if ((bezt->f1 & SELECT) != (bezt->f3 & SELECT)) {
+ bezt->f1 ^= SELECT;
+ bezt->f3 ^= SELECT;
+ }
+ }
}
/* internal use only (weak) */
static void nurb_handles_calc__align_selected(Nurb *nu)
{
- nurbList_handles_swap_select(nu);
- BKE_nurb_handles_calc(nu);
- nurbList_handles_swap_select(nu);
+ nurbList_handles_swap_select(nu);
+ BKE_nurb_handles_calc(nu);
+ nurbList_handles_swap_select(nu);
}
/* similar to BKE_nurb_handle_calc but for curves and
* figures out the previous and next for us */
void BKE_nurb_handle_calc_simple(Nurb *nu, BezTriple *bezt)
{
- if (nu->pntsu > 1) {
- BezTriple *prev = BKE_nurb_bezt_get_prev(nu, bezt);
- BezTriple *next = BKE_nurb_bezt_get_next(nu, bezt);
- BKE_nurb_handle_calc(bezt, prev, next, 0, 0);
- }
+ if (nu->pntsu > 1) {
+ BezTriple *prev = BKE_nurb_bezt_get_prev(nu, bezt);
+ BezTriple *next = BKE_nurb_bezt_get_next(nu, bezt);
+ BKE_nurb_handle_calc(bezt, prev, next, 0, 0);
+ }
}
void BKE_nurb_handle_calc_simple_auto(Nurb *nu, BezTriple *bezt)
{
- if (nu->pntsu > 1) {
- const char h1_back = bezt->h1, h2_back = bezt->h2;
+ if (nu->pntsu > 1) {
+ const char h1_back = bezt->h1, h2_back = bezt->h2;
- bezt->h1 = bezt->h2 = HD_AUTO;
+ bezt->h1 = bezt->h2 = HD_AUTO;
- /* Override handle types to HD_AUTO and recalculate */
- BKE_nurb_handle_calc_simple(nu, bezt);
+ /* Override handle types to HD_AUTO and recalculate */
+ BKE_nurb_handle_calc_simple(nu, bezt);
- bezt->h1 = h1_back;
- bezt->h2 = h2_back;
- }
+ bezt->h1 = h1_back;
+ bezt->h2 = h2_back;
+ }
}
/**
@@ -4135,635 +4221,654 @@ void BKE_nurb_handle_calc_simple_auto(Nurb *nu, BezTriple *bezt)
*/
void BKE_nurb_bezt_handle_test(BezTriple *bezt, const bool use_handle)
{
- short flag = 0;
+ short flag = 0;
#define SEL_F1 (1 << 0)
#define SEL_F2 (1 << 1)
#define SEL_F3 (1 << 2)
- if (use_handle) {
- if (bezt->f1 & SELECT) flag |= SEL_F1;
- if (bezt->f2 & SELECT) flag |= SEL_F2;
- if (bezt->f3 & SELECT) flag |= SEL_F3;
- }
- else {
- flag = (bezt->f2 & SELECT) ? (SEL_F1 | SEL_F2 | SEL_F3) : 0;
- }
-
- /* check for partial selection */
- if (!ELEM(flag, 0, SEL_F1 | SEL_F2 | SEL_F3)) {
- if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM)) {
- bezt->h1 = HD_ALIGN;
- }
- if (ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) {
- bezt->h2 = HD_ALIGN;
- }
-
- if (bezt->h1 == HD_VECT) {
- if ((!(flag & SEL_F1)) != (!(flag & SEL_F2))) {
- bezt->h1 = HD_FREE;
- }
- }
- if (bezt->h2 == HD_VECT) {
- if ((!(flag & SEL_F3)) != (!(flag & SEL_F2))) {
- bezt->h2 = HD_FREE;
- }
- }
- }
+ if (use_handle) {
+ if (bezt->f1 & SELECT)
+ flag |= SEL_F1;
+ if (bezt->f2 & SELECT)
+ flag |= SEL_F2;
+ if (bezt->f3 & SELECT)
+ flag |= SEL_F3;
+ }
+ else {
+ flag = (bezt->f2 & SELECT) ? (SEL_F1 | SEL_F2 | SEL_F3) : 0;
+ }
+
+ /* check for partial selection */
+ if (!ELEM(flag, 0, SEL_F1 | SEL_F2 | SEL_F3)) {
+ if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM)) {
+ bezt->h1 = HD_ALIGN;
+ }
+ if (ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) {
+ bezt->h2 = HD_ALIGN;
+ }
+
+ if (bezt->h1 == HD_VECT) {
+ if ((!(flag & SEL_F1)) != (!(flag & SEL_F2))) {
+ bezt->h1 = HD_FREE;
+ }
+ }
+ if (bezt->h2 == HD_VECT) {
+ if ((!(flag & SEL_F3)) != (!(flag & SEL_F2))) {
+ bezt->h2 = HD_FREE;
+ }
+ }
+ }
#undef SEL_F1
#undef SEL_F2
#undef SEL_F3
-
}
void BKE_nurb_handles_test(Nurb *nu, const bool use_handle)
{
- BezTriple *bezt;
- int a;
+ BezTriple *bezt;
+ int a;
- if (nu->type != CU_BEZIER)
- return;
+ if (nu->type != CU_BEZIER)
+ return;
- bezt = nu->bezt;
- a = nu->pntsu;
- while (a--) {
- BKE_nurb_bezt_handle_test(bezt, use_handle);
- bezt++;
- }
+ bezt = nu->bezt;
+ a = nu->pntsu;
+ while (a--) {
+ BKE_nurb_bezt_handle_test(bezt, use_handle);
+ bezt++;
+ }
- BKE_nurb_handles_calc(nu);
+ BKE_nurb_handles_calc(nu);
}
void BKE_nurb_handles_autocalc(Nurb *nu, int flag)
{
- /* checks handle coordinates and calculates type */
- const float eps = 0.0001f;
- const float eps_sq = eps * eps;
-
- BezTriple *bezt2, *bezt1, *bezt0;
- int i;
-
- if (nu == NULL || nu->bezt == NULL)
- return;
-
- bezt2 = nu->bezt;
- bezt1 = bezt2 + (nu->pntsu - 1);
- bezt0 = bezt1 - 1;
- i = nu->pntsu;
-
- while (i--) {
- bool align = false, leftsmall = false, rightsmall = false;
-
- /* left handle: */
- if (flag == 0 || (bezt1->f1 & flag)) {
- bezt1->h1 = HD_FREE;
- /* distance too short: vectorhandle */
- if (len_squared_v3v3(bezt1->vec[1], bezt0->vec[1]) < eps_sq) {
- bezt1->h1 = HD_VECT;
- leftsmall = true;
- }
- else {
- /* aligned handle? */
- if (dist_squared_to_line_v3(bezt1->vec[1], bezt1->vec[0], bezt1->vec[2]) < eps_sq) {
- align = true;
- bezt1->h1 = HD_ALIGN;
- }
- /* or vector handle? */
- if (dist_squared_to_line_v3(bezt1->vec[0], bezt1->vec[1], bezt0->vec[1]) < eps_sq)
- bezt1->h1 = HD_VECT;
- }
- }
- /* right handle: */
- if (flag == 0 || (bezt1->f3 & flag)) {
- bezt1->h2 = HD_FREE;
- /* distance too short: vectorhandle */
- if (len_squared_v3v3(bezt1->vec[1], bezt2->vec[1]) < eps_sq) {
- bezt1->h2 = HD_VECT;
- rightsmall = true;
- }
- else {
- /* aligned handle? */
- if (align) bezt1->h2 = HD_ALIGN;
-
- /* or vector handle? */
- if (dist_squared_to_line_v3(bezt1->vec[2], bezt1->vec[1], bezt2->vec[1]) < eps_sq)
- bezt1->h2 = HD_VECT;
- }
- }
- if (leftsmall && bezt1->h2 == HD_ALIGN)
- bezt1->h2 = HD_FREE;
- if (rightsmall && bezt1->h1 == HD_ALIGN)
- bezt1->h1 = HD_FREE;
-
- /* undesired combination: */
- if (bezt1->h1 == HD_ALIGN && bezt1->h2 == HD_VECT)
- bezt1->h1 = HD_FREE;
- if (bezt1->h2 == HD_ALIGN && bezt1->h1 == HD_VECT)
- bezt1->h2 = HD_FREE;
-
- bezt0 = bezt1;
- bezt1 = bezt2;
- bezt2++;
- }
-
- BKE_nurb_handles_calc(nu);
+ /* checks handle coordinates and calculates type */
+ const float eps = 0.0001f;
+ const float eps_sq = eps * eps;
+
+ BezTriple *bezt2, *bezt1, *bezt0;
+ int i;
+
+ if (nu == NULL || nu->bezt == NULL)
+ return;
+
+ bezt2 = nu->bezt;
+ bezt1 = bezt2 + (nu->pntsu - 1);
+ bezt0 = bezt1 - 1;
+ i = nu->pntsu;
+
+ while (i--) {
+ bool align = false, leftsmall = false, rightsmall = false;
+
+ /* left handle: */
+ if (flag == 0 || (bezt1->f1 & flag)) {
+ bezt1->h1 = HD_FREE;
+ /* distance too short: vectorhandle */
+ if (len_squared_v3v3(bezt1->vec[1], bezt0->vec[1]) < eps_sq) {
+ bezt1->h1 = HD_VECT;
+ leftsmall = true;
+ }
+ else {
+ /* aligned handle? */
+ if (dist_squared_to_line_v3(bezt1->vec[1], bezt1->vec[0], bezt1->vec[2]) < eps_sq) {
+ align = true;
+ bezt1->h1 = HD_ALIGN;
+ }
+ /* or vector handle? */
+ if (dist_squared_to_line_v3(bezt1->vec[0], bezt1->vec[1], bezt0->vec[1]) < eps_sq)
+ bezt1->h1 = HD_VECT;
+ }
+ }
+ /* right handle: */
+ if (flag == 0 || (bezt1->f3 & flag)) {
+ bezt1->h2 = HD_FREE;
+ /* distance too short: vectorhandle */
+ if (len_squared_v3v3(bezt1->vec[1], bezt2->vec[1]) < eps_sq) {
+ bezt1->h2 = HD_VECT;
+ rightsmall = true;
+ }
+ else {
+ /* aligned handle? */
+ if (align)
+ bezt1->h2 = HD_ALIGN;
+
+ /* or vector handle? */
+ if (dist_squared_to_line_v3(bezt1->vec[2], bezt1->vec[1], bezt2->vec[1]) < eps_sq)
+ bezt1->h2 = HD_VECT;
+ }
+ }
+ if (leftsmall && bezt1->h2 == HD_ALIGN)
+ bezt1->h2 = HD_FREE;
+ if (rightsmall && bezt1->h1 == HD_ALIGN)
+ bezt1->h1 = HD_FREE;
+
+ /* undesired combination: */
+ if (bezt1->h1 == HD_ALIGN && bezt1->h2 == HD_VECT)
+ bezt1->h1 = HD_FREE;
+ if (bezt1->h2 == HD_ALIGN && bezt1->h1 == HD_VECT)
+ bezt1->h2 = HD_FREE;
+
+ bezt0 = bezt1;
+ bezt1 = bezt2;
+ bezt2++;
+ }
+
+ BKE_nurb_handles_calc(nu);
}
void BKE_nurbList_handles_autocalc(ListBase *editnurb, int flag)
{
- Nurb *nu;
+ Nurb *nu;
- nu = editnurb->first;
- while (nu) {
- BKE_nurb_handles_autocalc(nu, flag);
- nu = nu->next;
- }
+ nu = editnurb->first;
+ while (nu) {
+ BKE_nurb_handles_autocalc(nu, flag);
+ nu = nu->next;
+ }
}
void BKE_nurbList_handles_set(ListBase *editnurb, const char code)
{
- /* code==1: set autohandle */
- /* code==2: set vectorhandle */
- /* code==3 (HD_ALIGN) it toggle, vectorhandles become HD_FREE */
- /* code==4: sets icu flag to become IPO_AUTO_HORIZ, horizontal extremes on auto-handles */
- /* code==5: Set align, like 3 but no toggle */
- /* code==6: Clear align, like 3 but no toggle */
- Nurb *nu;
- BezTriple *bezt;
- int a;
-
- if (ELEM(code, HD_AUTO, HD_VECT)) {
- nu = editnurb->first;
- while (nu) {
- if (nu->type == CU_BEZIER) {
- bezt = nu->bezt;
- a = nu->pntsu;
- while (a--) {
- if ((bezt->f1 & SELECT) || (bezt->f3 & SELECT)) {
- if (bezt->f1 & SELECT)
- bezt->h1 = code;
- if (bezt->f3 & SELECT)
- bezt->h2 = code;
- if (bezt->h1 != bezt->h2) {
- if (ELEM(bezt->h1, HD_ALIGN, HD_AUTO))
- bezt->h1 = HD_FREE;
- if (ELEM(bezt->h2, HD_ALIGN, HD_AUTO))
- bezt->h2 = HD_FREE;
- }
- }
- bezt++;
- }
-
- /* like BKE_nurb_handles_calc but moves selected */
- nurb_handles_calc__align_selected(nu);
- }
- nu = nu->next;
- }
- }
- else {
- char h_new = HD_FREE;
-
- /* there is 1 handle not FREE: FREE it all, else make ALIGNED */
- if (code == 5) {
- h_new = HD_ALIGN;
- }
- else if (code == 6) {
- h_new = HD_FREE;
- }
- else {
- /* Toggle */
- for (nu = editnurb->first; nu; nu = nu->next) {
- if (nu->type == CU_BEZIER) {
- bezt = nu->bezt;
- a = nu->pntsu;
- while (a--) {
- if (((bezt->f1 & SELECT) && bezt->h1 != HD_FREE) ||
- ((bezt->f3 & SELECT) && bezt->h2 != HD_FREE))
- {
- h_new = HD_AUTO;
- break;
- }
- bezt++;
- }
- }
- }
- h_new = (h_new == HD_FREE) ? HD_ALIGN : HD_FREE;
- }
- for (nu = editnurb->first; nu; nu = nu->next) {
- if (nu->type == CU_BEZIER) {
- bezt = nu->bezt;
- a = nu->pntsu;
- while (a--) {
- if (bezt->f1 & SELECT) bezt->h1 = h_new;
- if (bezt->f3 & SELECT) bezt->h2 = h_new;
-
- bezt++;
- }
-
- /* like BKE_nurb_handles_calc but moves selected */
- nurb_handles_calc__align_selected(nu);
- }
- }
- }
+ /* code==1: set autohandle */
+ /* code==2: set vectorhandle */
+ /* code==3 (HD_ALIGN) it toggle, vectorhandles become HD_FREE */
+ /* code==4: sets icu flag to become IPO_AUTO_HORIZ, horizontal extremes on auto-handles */
+ /* code==5: Set align, like 3 but no toggle */
+ /* code==6: Clear align, like 3 but no toggle */
+ Nurb *nu;
+ BezTriple *bezt;
+ int a;
+
+ if (ELEM(code, HD_AUTO, HD_VECT)) {
+ nu = editnurb->first;
+ while (nu) {
+ if (nu->type == CU_BEZIER) {
+ bezt = nu->bezt;
+ a = nu->pntsu;
+ while (a--) {
+ if ((bezt->f1 & SELECT) || (bezt->f3 & SELECT)) {
+ if (bezt->f1 & SELECT)
+ bezt->h1 = code;
+ if (bezt->f3 & SELECT)
+ bezt->h2 = code;
+ if (bezt->h1 != bezt->h2) {
+ if (ELEM(bezt->h1, HD_ALIGN, HD_AUTO))
+ bezt->h1 = HD_FREE;
+ if (ELEM(bezt->h2, HD_ALIGN, HD_AUTO))
+ bezt->h2 = HD_FREE;
+ }
+ }
+ bezt++;
+ }
+
+ /* like BKE_nurb_handles_calc but moves selected */
+ nurb_handles_calc__align_selected(nu);
+ }
+ nu = nu->next;
+ }
+ }
+ else {
+ char h_new = HD_FREE;
+
+ /* there is 1 handle not FREE: FREE it all, else make ALIGNED */
+ if (code == 5) {
+ h_new = HD_ALIGN;
+ }
+ else if (code == 6) {
+ h_new = HD_FREE;
+ }
+ else {
+ /* Toggle */
+ for (nu = editnurb->first; nu; nu = nu->next) {
+ if (nu->type == CU_BEZIER) {
+ bezt = nu->bezt;
+ a = nu->pntsu;
+ while (a--) {
+ if (((bezt->f1 & SELECT) && bezt->h1 != HD_FREE) ||
+ ((bezt->f3 & SELECT) && bezt->h2 != HD_FREE)) {
+ h_new = HD_AUTO;
+ break;
+ }
+ bezt++;
+ }
+ }
+ }
+ h_new = (h_new == HD_FREE) ? HD_ALIGN : HD_FREE;
+ }
+ for (nu = editnurb->first; nu; nu = nu->next) {
+ if (nu->type == CU_BEZIER) {
+ bezt = nu->bezt;
+ a = nu->pntsu;
+ while (a--) {
+ if (bezt->f1 & SELECT)
+ bezt->h1 = h_new;
+ if (bezt->f3 & SELECT)
+ bezt->h2 = h_new;
+
+ bezt++;
+ }
+
+ /* like BKE_nurb_handles_calc but moves selected */
+ nurb_handles_calc__align_selected(nu);
+ }
+ }
+ }
}
void BKE_nurbList_handles_recalculate(ListBase *editnurb, const bool calc_length, const char flag)
{
- Nurb *nu;
- BezTriple *bezt;
- int a;
+ Nurb *nu;
+ BezTriple *bezt;
+ int a;
- for (nu = editnurb->first; nu; nu = nu->next) {
- if (nu->type == CU_BEZIER) {
- bool changed = false;
+ for (nu = editnurb->first; nu; nu = nu->next) {
+ if (nu->type == CU_BEZIER) {
+ bool changed = false;
- for (a = nu->pntsu, bezt = nu->bezt; a--; bezt++) {
+ for (a = nu->pntsu, bezt = nu->bezt; a--; bezt++) {
- const bool h1_select = (bezt->f1 & flag) == flag;
- const bool h2_select = (bezt->f3 & flag) == flag;
+ const bool h1_select = (bezt->f1 & flag) == flag;
+ const bool h2_select = (bezt->f3 & flag) == flag;
- if (h1_select || h2_select) {
+ if (h1_select || h2_select) {
- float co1_back[3], co2_back[3];
+ float co1_back[3], co2_back[3];
- copy_v3_v3(co1_back, bezt->vec[0]);
- copy_v3_v3(co2_back, bezt->vec[2]);
+ copy_v3_v3(co1_back, bezt->vec[0]);
+ copy_v3_v3(co2_back, bezt->vec[2]);
- BKE_nurb_handle_calc_simple_auto(nu, bezt);
+ BKE_nurb_handle_calc_simple_auto(nu, bezt);
- if (h1_select) {
- if (!calc_length) {
- dist_ensure_v3_v3fl(bezt->vec[0], bezt->vec[1], len_v3v3(co1_back, bezt->vec[1]));
- }
- }
- else {
- copy_v3_v3(bezt->vec[0], co1_back);
- }
+ if (h1_select) {
+ if (!calc_length) {
+ dist_ensure_v3_v3fl(bezt->vec[0], bezt->vec[1], len_v3v3(co1_back, bezt->vec[1]));
+ }
+ }
+ else {
+ copy_v3_v3(bezt->vec[0], co1_back);
+ }
- if (h2_select) {
- if (!calc_length) {
- dist_ensure_v3_v3fl(bezt->vec[2], bezt->vec[1], len_v3v3(co2_back, bezt->vec[1]));
- }
- }
- else {
- copy_v3_v3(bezt->vec[2], co2_back);
- }
+ if (h2_select) {
+ if (!calc_length) {
+ dist_ensure_v3_v3fl(bezt->vec[2], bezt->vec[1], len_v3v3(co2_back, bezt->vec[1]));
+ }
+ }
+ else {
+ copy_v3_v3(bezt->vec[2], co2_back);
+ }
- changed = true;
- }
- }
+ changed = true;
+ }
+ }
- if (changed) {
- /* Recalculate the whole curve */
- BKE_nurb_handles_calc(nu);
- }
- }
- }
+ if (changed) {
+ /* Recalculate the whole curve */
+ BKE_nurb_handles_calc(nu);
+ }
+ }
+ }
}
void BKE_nurbList_flag_set(ListBase *editnurb, short flag)
{
- Nurb *nu;
- BezTriple *bezt;
- BPoint *bp;
- int a;
-
- for (nu = editnurb->first; nu; nu = nu->next) {
- if (nu->type == CU_BEZIER) {
- a = nu->pntsu;
- bezt = nu->bezt;
- while (a--) {
- bezt->f1 = bezt->f2 = bezt->f3 = flag;
- bezt++;
- }
- }
- else {
- a = nu->pntsu * nu->pntsv;
- bp = nu->bp;
- while (a--) {
- bp->f1 = flag;
- bp++;
- }
- }
- }
+ Nurb *nu;
+ BezTriple *bezt;
+ BPoint *bp;
+ int a;
+
+ for (nu = editnurb->first; nu; nu = nu->next) {
+ if (nu->type == CU_BEZIER) {
+ a = nu->pntsu;
+ bezt = nu->bezt;
+ while (a--) {
+ bezt->f1 = bezt->f2 = bezt->f3 = flag;
+ bezt++;
+ }
+ }
+ else {
+ a = nu->pntsu * nu->pntsv;
+ bp = nu->bp;
+ while (a--) {
+ bp->f1 = flag;
+ bp++;
+ }
+ }
+ }
}
void BKE_nurb_direction_switch(Nurb *nu)
{
- BezTriple *bezt1, *bezt2;
- BPoint *bp1, *bp2;
- float *fp1, *fp2, *tempf;
- int a, b;
-
- if (nu->pntsu == 1 && nu->pntsv == 1) {
- return;
- }
-
- if (nu->type == CU_BEZIER) {
- a = nu->pntsu;
- bezt1 = nu->bezt;
- bezt2 = bezt1 + (a - 1);
- if (a & 1) a += 1; /* if odd, also swap middle content */
- a /= 2;
- while (a > 0) {
- if (bezt1 != bezt2) {
- SWAP(BezTriple, *bezt1, *bezt2);
- }
-
- swap_v3_v3(bezt1->vec[0], bezt1->vec[2]);
-
- if (bezt1 != bezt2) {
- swap_v3_v3(bezt2->vec[0], bezt2->vec[2]);
- }
-
- SWAP(char, bezt1->h1, bezt1->h2);
- SWAP(char, bezt1->f1, bezt1->f3);
-
- if (bezt1 != bezt2) {
- SWAP(char, bezt2->h1, bezt2->h2);
- SWAP(char, bezt2->f1, bezt2->f3);
- bezt1->tilt = -bezt1->tilt;
- bezt2->tilt = -bezt2->tilt;
- }
- else {
- bezt1->tilt = -bezt1->tilt;
- }
- a--;
- bezt1++;
- bezt2--;
- }
- }
- else if (nu->pntsv == 1) {
- a = nu->pntsu;
- bp1 = nu->bp;
- bp2 = bp1 + (a - 1);
- a /= 2;
- while (bp1 != bp2 && a > 0) {
- SWAP(BPoint, *bp1, *bp2);
- a--;
- bp1->tilt = -bp1->tilt;
- bp2->tilt = -bp2->tilt;
- bp1++;
- bp2--;
- }
- /* If there're odd number of points no need to touch coord of middle one,
- * but still need to change it's tilt.
- */
- if (nu->pntsu & 1) {
- bp1->tilt = -bp1->tilt;
- }
- if (nu->type == CU_NURBS) {
- /* no knots for too short paths */
- if (nu->knotsu) {
- /* inverse knots */
- a = KNOTSU(nu);
- fp1 = nu->knotsu;
- fp2 = fp1 + (a - 1);
- a /= 2;
- while (fp1 != fp2 && a > 0) {
- SWAP(float, *fp1, *fp2);
- a--;
- fp1++;
- fp2--;
- }
- /* and make in increasing order again */
- a = KNOTSU(nu);
- fp1 = nu->knotsu;
- fp2 = tempf = MEM_malloc_arrayN(a, sizeof(float), "switchdirect");
- a--;
- fp2[a] = fp1[a];
- while (a--) {
- fp2[0] = fabsf(fp1[1] - fp1[0]);
- fp1++;
- fp2++;
- }
-
- a = KNOTSU(nu) - 1;
- fp1 = nu->knotsu;
- fp2 = tempf;
- fp1[0] = 0.0;
- fp1++;
- while (a--) {
- fp1[0] = fp1[-1] + fp2[0];
- fp1++;
- fp2++;
- }
- MEM_freeN(tempf);
- }
- }
- }
- else {
- for (b = 0; b < nu->pntsv; b++) {
- bp1 = nu->bp + b * nu->pntsu;
- a = nu->pntsu;
- bp2 = bp1 + (a - 1);
- a /= 2;
-
- while (bp1 != bp2 && a > 0) {
- SWAP(BPoint, *bp1, *bp2);
- a--;
- bp1++;
- bp2--;
- }
- }
- }
+ BezTriple *bezt1, *bezt2;
+ BPoint *bp1, *bp2;
+ float *fp1, *fp2, *tempf;
+ int a, b;
+
+ if (nu->pntsu == 1 && nu->pntsv == 1) {
+ return;
+ }
+
+ if (nu->type == CU_BEZIER) {
+ a = nu->pntsu;
+ bezt1 = nu->bezt;
+ bezt2 = bezt1 + (a - 1);
+ if (a & 1)
+ a += 1; /* if odd, also swap middle content */
+ a /= 2;
+ while (a > 0) {
+ if (bezt1 != bezt2) {
+ SWAP(BezTriple, *bezt1, *bezt2);
+ }
+
+ swap_v3_v3(bezt1->vec[0], bezt1->vec[2]);
+
+ if (bezt1 != bezt2) {
+ swap_v3_v3(bezt2->vec[0], bezt2->vec[2]);
+ }
+
+ SWAP(char, bezt1->h1, bezt1->h2);
+ SWAP(char, bezt1->f1, bezt1->f3);
+
+ if (bezt1 != bezt2) {
+ SWAP(char, bezt2->h1, bezt2->h2);
+ SWAP(char, bezt2->f1, bezt2->f3);
+ bezt1->tilt = -bezt1->tilt;
+ bezt2->tilt = -bezt2->tilt;
+ }
+ else {
+ bezt1->tilt = -bezt1->tilt;
+ }
+ a--;
+ bezt1++;
+ bezt2--;
+ }
+ }
+ else if (nu->pntsv == 1) {
+ a = nu->pntsu;
+ bp1 = nu->bp;
+ bp2 = bp1 + (a - 1);
+ a /= 2;
+ while (bp1 != bp2 && a > 0) {
+ SWAP(BPoint, *bp1, *bp2);
+ a--;
+ bp1->tilt = -bp1->tilt;
+ bp2->tilt = -bp2->tilt;
+ bp1++;
+ bp2--;
+ }
+ /* If there're odd number of points no need to touch coord of middle one,
+ * but still need to change it's tilt.
+ */
+ if (nu->pntsu & 1) {
+ bp1->tilt = -bp1->tilt;
+ }
+ if (nu->type == CU_NURBS) {
+ /* no knots for too short paths */
+ if (nu->knotsu) {
+ /* inverse knots */
+ a = KNOTSU(nu);
+ fp1 = nu->knotsu;
+ fp2 = fp1 + (a - 1);
+ a /= 2;
+ while (fp1 != fp2 && a > 0) {
+ SWAP(float, *fp1, *fp2);
+ a--;
+ fp1++;
+ fp2--;
+ }
+ /* and make in increasing order again */
+ a = KNOTSU(nu);
+ fp1 = nu->knotsu;
+ fp2 = tempf = MEM_malloc_arrayN(a, sizeof(float), "switchdirect");
+ a--;
+ fp2[a] = fp1[a];
+ while (a--) {
+ fp2[0] = fabsf(fp1[1] - fp1[0]);
+ fp1++;
+ fp2++;
+ }
+
+ a = KNOTSU(nu) - 1;
+ fp1 = nu->knotsu;
+ fp2 = tempf;
+ fp1[0] = 0.0;
+ fp1++;
+ while (a--) {
+ fp1[0] = fp1[-1] + fp2[0];
+ fp1++;
+ fp2++;
+ }
+ MEM_freeN(tempf);
+ }
+ }
+ }
+ else {
+ for (b = 0; b < nu->pntsv; b++) {
+ bp1 = nu->bp + b * nu->pntsu;
+ a = nu->pntsu;
+ bp2 = bp1 + (a - 1);
+ a /= 2;
+
+ while (bp1 != bp2 && a > 0) {
+ SWAP(BPoint, *bp1, *bp2);
+ a--;
+ bp1++;
+ bp2--;
+ }
+ }
+ }
}
-
float (*BKE_curve_nurbs_vertexCos_get(ListBase *lb, int *r_numVerts))[3]
{
- int i, numVerts = *r_numVerts = BKE_nurbList_verts_count(lb);
- float *co, (*cos)[3] = MEM_malloc_arrayN(numVerts, sizeof(*cos), "cu_vcos");
- Nurb *nu;
-
- co = cos[0];
- for (nu = lb->first; nu; nu = nu->next) {
- if (nu->type == CU_BEZIER) {
- BezTriple *bezt = nu->bezt;
-
- for (i = 0; i < nu->pntsu; i++, bezt++) {
- copy_v3_v3(co, bezt->vec[0]); co += 3;
- copy_v3_v3(co, bezt->vec[1]); co += 3;
- copy_v3_v3(co, bezt->vec[2]); co += 3;
- }
- }
- else {
- BPoint *bp = nu->bp;
-
- for (i = 0; i < nu->pntsu * nu->pntsv; i++, bp++) {
- copy_v3_v3(co, bp->vec); co += 3;
- }
- }
- }
-
- return cos;
+ int i, numVerts = *r_numVerts = BKE_nurbList_verts_count(lb);
+ float *co, (*cos)[3] = MEM_malloc_arrayN(numVerts, sizeof(*cos), "cu_vcos");
+ Nurb *nu;
+
+ co = cos[0];
+ for (nu = lb->first; nu; nu = nu->next) {
+ if (nu->type == CU_BEZIER) {
+ BezTriple *bezt = nu->bezt;
+
+ for (i = 0; i < nu->pntsu; i++, bezt++) {
+ copy_v3_v3(co, bezt->vec[0]);
+ co += 3;
+ copy_v3_v3(co, bezt->vec[1]);
+ co += 3;
+ copy_v3_v3(co, bezt->vec[2]);
+ co += 3;
+ }
+ }
+ else {
+ BPoint *bp = nu->bp;
+
+ for (i = 0; i < nu->pntsu * nu->pntsv; i++, bp++) {
+ copy_v3_v3(co, bp->vec);
+ co += 3;
+ }
+ }
+ }
+
+ return cos;
}
void BK_curve_nurbs_vertexCos_apply(ListBase *lb, float (*vertexCos)[3])
{
- const float *co = vertexCos[0];
- Nurb *nu;
- int i;
+ const float *co = vertexCos[0];
+ Nurb *nu;
+ int i;
- for (nu = lb->first; nu; nu = nu->next) {
- if (nu->type == CU_BEZIER) {
- BezTriple *bezt = nu->bezt;
+ for (nu = lb->first; nu; nu = nu->next) {
+ if (nu->type == CU_BEZIER) {
+ BezTriple *bezt = nu->bezt;
- for (i = 0; i < nu->pntsu; i++, bezt++) {
- copy_v3_v3(bezt->vec[0], co); co += 3;
- copy_v3_v3(bezt->vec[1], co); co += 3;
- copy_v3_v3(bezt->vec[2], co); co += 3;
- }
- }
- else {
- BPoint *bp = nu->bp;
+ for (i = 0; i < nu->pntsu; i++, bezt++) {
+ copy_v3_v3(bezt->vec[0], co);
+ co += 3;
+ copy_v3_v3(bezt->vec[1], co);
+ co += 3;
+ copy_v3_v3(bezt->vec[2], co);
+ co += 3;
+ }
+ }
+ else {
+ BPoint *bp = nu->bp;
- for (i = 0; i < nu->pntsu * nu->pntsv; i++, bp++) {
- copy_v3_v3(bp->vec, co); co += 3;
- }
- }
+ for (i = 0; i < nu->pntsu * nu->pntsv; i++, bp++) {
+ copy_v3_v3(bp->vec, co);
+ co += 3;
+ }
+ }
- calchandlesNurb_intern(nu, true);
- }
+ calchandlesNurb_intern(nu, true);
+ }
}
float (*BKE_curve_nurbs_keyVertexCos_get(ListBase *lb, float *key))[3]
{
- int i, numVerts = BKE_nurbList_verts_count(lb);
- float *co, (*cos)[3] = MEM_malloc_arrayN(numVerts, sizeof(*cos), "cu_vcos");
- Nurb *nu;
-
- co = cos[0];
- for (nu = lb->first; nu; nu = nu->next) {
- if (nu->type == CU_BEZIER) {
- BezTriple *bezt = nu->bezt;
-
- for (i = 0; i < nu->pntsu; i++, bezt++) {
- copy_v3_v3(co, &key[0]); co += 3;
- copy_v3_v3(co, &key[3]); co += 3;
- copy_v3_v3(co, &key[6]); co += 3;
- key += KEYELEM_FLOAT_LEN_BEZTRIPLE;
- }
- }
- else {
- BPoint *bp = nu->bp;
-
- for (i = 0; i < nu->pntsu * nu->pntsv; i++, bp++) {
- copy_v3_v3(co, key); co += 3;
- key += KEYELEM_FLOAT_LEN_BPOINT;
- }
- }
- }
-
- return cos;
+ int i, numVerts = BKE_nurbList_verts_count(lb);
+ float *co, (*cos)[3] = MEM_malloc_arrayN(numVerts, sizeof(*cos), "cu_vcos");
+ Nurb *nu;
+
+ co = cos[0];
+ for (nu = lb->first; nu; nu = nu->next) {
+ if (nu->type == CU_BEZIER) {
+ BezTriple *bezt = nu->bezt;
+
+ for (i = 0; i < nu->pntsu; i++, bezt++) {
+ copy_v3_v3(co, &key[0]);
+ co += 3;
+ copy_v3_v3(co, &key[3]);
+ co += 3;
+ copy_v3_v3(co, &key[6]);
+ co += 3;
+ key += KEYELEM_FLOAT_LEN_BEZTRIPLE;
+ }
+ }
+ else {
+ BPoint *bp = nu->bp;
+
+ for (i = 0; i < nu->pntsu * nu->pntsv; i++, bp++) {
+ copy_v3_v3(co, key);
+ co += 3;
+ key += KEYELEM_FLOAT_LEN_BPOINT;
+ }
+ }
+ }
+
+ return cos;
}
void BKE_curve_nurbs_keyVertexTilts_apply(ListBase *lb, float *key)
{
- Nurb *nu;
- int i;
+ Nurb *nu;
+ int i;
- for (nu = lb->first; nu; nu = nu->next) {
- if (nu->type == CU_BEZIER) {
- BezTriple *bezt = nu->bezt;
+ for (nu = lb->first; nu; nu = nu->next) {
+ if (nu->type == CU_BEZIER) {
+ BezTriple *bezt = nu->bezt;
- for (i = 0; i < nu->pntsu; i++, bezt++) {
- bezt->tilt = key[9];
- bezt->radius = key[10];
- key += KEYELEM_FLOAT_LEN_BEZTRIPLE;
- }
- }
- else {
- BPoint *bp = nu->bp;
+ for (i = 0; i < nu->pntsu; i++, bezt++) {
+ bezt->tilt = key[9];
+ bezt->radius = key[10];
+ key += KEYELEM_FLOAT_LEN_BEZTRIPLE;
+ }
+ }
+ else {
+ BPoint *bp = nu->bp;
- for (i = 0; i < nu->pntsu * nu->pntsv; i++, bp++) {
- bp->tilt = key[3];
- bp->radius = key[4];
- key += KEYELEM_FLOAT_LEN_BPOINT;
- }
- }
- }
+ for (i = 0; i < nu->pntsu * nu->pntsv; i++, bp++) {
+ bp->tilt = key[3];
+ bp->radius = key[4];
+ key += KEYELEM_FLOAT_LEN_BPOINT;
+ }
+ }
+ }
}
bool BKE_nurb_check_valid_u(struct Nurb *nu)
{
- if (nu->pntsu <= 1)
- return false;
- if (nu->type != CU_NURBS)
- return true; /* not a nurb, lets assume its valid */
-
- if (nu->pntsu < nu->orderu) return false;
- if (((nu->flagu & CU_NURB_CYCLIC) == 0) && (nu->flagu & CU_NURB_BEZIER)) { /* Bezier U Endpoints */
- if (nu->orderu == 4) {
- if (nu->pntsu < 5)
- return false; /* bezier with 4 orderu needs 5 points */
- }
- else {
- if (nu->orderu != 3)
- return false; /* order must be 3 or 4 */
- }
- }
- return true;
+ if (nu->pntsu <= 1)
+ return false;
+ if (nu->type != CU_NURBS)
+ return true; /* not a nurb, lets assume its valid */
+
+ if (nu->pntsu < nu->orderu)
+ return false;
+ if (((nu->flagu & CU_NURB_CYCLIC) == 0) &&
+ (nu->flagu & CU_NURB_BEZIER)) { /* Bezier U Endpoints */
+ if (nu->orderu == 4) {
+ if (nu->pntsu < 5)
+ return false; /* bezier with 4 orderu needs 5 points */
+ }
+ else {
+ if (nu->orderu != 3)
+ return false; /* order must be 3 or 4 */
+ }
+ }
+ return true;
}
bool BKE_nurb_check_valid_v(struct Nurb *nu)
{
- if (nu->pntsv <= 1)
- return false;
- if (nu->type != CU_NURBS)
- return true; /* not a nurb, lets assume its valid */
-
- if (nu->pntsv < nu->orderv)
- return false;
- if (((nu->flagv & CU_NURB_CYCLIC) == 0) && (nu->flagv & CU_NURB_BEZIER)) { /* Bezier V Endpoints */
- if (nu->orderv == 4) {
- if (nu->pntsv < 5)
- return false; /* bezier with 4 orderu needs 5 points */
- }
- else {
- if (nu->orderv != 3)
- return false; /* order must be 3 or 4 */
- }
- }
- return true;
+ if (nu->pntsv <= 1)
+ return false;
+ if (nu->type != CU_NURBS)
+ return true; /* not a nurb, lets assume its valid */
+
+ if (nu->pntsv < nu->orderv)
+ return false;
+ if (((nu->flagv & CU_NURB_CYCLIC) == 0) &&
+ (nu->flagv & CU_NURB_BEZIER)) { /* Bezier V Endpoints */
+ if (nu->orderv == 4) {
+ if (nu->pntsv < 5)
+ return false; /* bezier with 4 orderu needs 5 points */
+ }
+ else {
+ if (nu->orderv != 3)
+ return false; /* order must be 3 or 4 */
+ }
+ }
+ return true;
}
bool BKE_nurb_check_valid_uv(struct Nurb *nu)
{
- if (!BKE_nurb_check_valid_u(nu))
- return false;
- if ((nu->pntsv > 1) && !BKE_nurb_check_valid_v(nu))
- return false;
+ if (!BKE_nurb_check_valid_u(nu))
+ return false;
+ if ((nu->pntsv > 1) && !BKE_nurb_check_valid_v(nu))
+ return false;
- return true;
+ return true;
}
bool BKE_nurb_order_clamp_u(struct Nurb *nu)
{
- bool changed = false;
- if (nu->pntsu < nu->orderu) {
- nu->orderu = max_ii(2, nu->pntsu);
- changed = true;
- }
- if (((nu->flagu & CU_NURB_CYCLIC) == 0) && (nu->flagu & CU_NURB_BEZIER)) {
- CLAMP(nu->orderu, 3, 4);
- changed = true;
- }
- return changed;
+ bool changed = false;
+ if (nu->pntsu < nu->orderu) {
+ nu->orderu = max_ii(2, nu->pntsu);
+ changed = true;
+ }
+ if (((nu->flagu & CU_NURB_CYCLIC) == 0) && (nu->flagu & CU_NURB_BEZIER)) {
+ CLAMP(nu->orderu, 3, 4);
+ changed = true;
+ }
+ return changed;
}
bool BKE_nurb_order_clamp_v(struct Nurb *nu)
{
- bool changed = false;
- if (nu->pntsv < nu->orderv) {
- nu->orderv = max_ii(2, nu->pntsv);
- changed = true;
- }
- if (((nu->flagv & CU_NURB_CYCLIC) == 0) && (nu->flagv & CU_NURB_BEZIER)) {
- CLAMP(nu->orderv, 3, 4);
- changed = true;
- }
- return changed;
+ bool changed = false;
+ if (nu->pntsv < nu->orderv) {
+ nu->orderv = max_ii(2, nu->pntsv);
+ changed = true;
+ }
+ if (((nu->flagv & CU_NURB_CYCLIC) == 0) && (nu->flagv & CU_NURB_BEZIER)) {
+ CLAMP(nu->orderv, 3, 4);
+ changed = true;
+ }
+ return changed;
}
/**
@@ -4771,608 +4876,608 @@ bool BKE_nurb_order_clamp_v(struct Nurb *nu)
*/
bool BKE_nurb_type_convert(Nurb *nu, const short type, const bool use_handles)
{
- BezTriple *bezt;
- BPoint *bp;
- int a, c, nr;
-
- if (nu->type == CU_POLY) {
- if (type == CU_BEZIER) { /* to Bezier with vecthandles */
- nr = nu->pntsu;
- bezt = (BezTriple *)MEM_calloc_arrayN(nr, sizeof(BezTriple), "setsplinetype2");
- nu->bezt = bezt;
- a = nr;
- bp = nu->bp;
- while (a--) {
- copy_v3_v3(bezt->vec[1], bp->vec);
- bezt->f1 = bezt->f2 = bezt->f3 = bp->f1;
- bezt->h1 = bezt->h2 = HD_VECT;
- bezt->weight = bp->weight;
- bezt->radius = bp->radius;
- bp++;
- bezt++;
- }
- MEM_freeN(nu->bp);
- nu->bp = NULL;
- nu->pntsu = nr;
- nu->pntsv = 0;
- nu->type = CU_BEZIER;
- BKE_nurb_handles_calc(nu);
- }
- else if (type == CU_NURBS) {
- nu->type = CU_NURBS;
- nu->orderu = 4;
- nu->flagu &= CU_NURB_CYCLIC; /* disable all flags except for cyclic */
- BKE_nurb_knot_calc_u(nu);
- a = nu->pntsu * nu->pntsv;
- bp = nu->bp;
- while (a--) {
- bp->vec[3] = 1.0;
- bp++;
- }
- }
- }
- else if (nu->type == CU_BEZIER) { /* Bezier */
- if (type == CU_POLY || type == CU_NURBS) {
- nr = use_handles ? (3 * nu->pntsu) : nu->pntsu;
- nu->bp = MEM_calloc_arrayN(nr, sizeof(BPoint), "setsplinetype");
- a = nu->pntsu;
- bezt = nu->bezt;
- bp = nu->bp;
- while (a--) {
- if ((type == CU_POLY && bezt->h1 == HD_VECT && bezt->h2 == HD_VECT) || (use_handles == false)) {
- /* vector handle becomes 1 poly vertice */
- copy_v3_v3(bp->vec, bezt->vec[1]);
- bp->vec[3] = 1.0;
- bp->f1 = bezt->f2;
- if (use_handles) nr -= 2;
- bp->radius = bezt->radius;
- bp->weight = bezt->weight;
- bp++;
- }
- else {
- const char *f = &bezt->f1;
- for (c = 0; c < 3; c++, f++) {
- copy_v3_v3(bp->vec, bezt->vec[c]);
- bp->vec[3] = 1.0;
- bp->f1 = *f;
- bp->radius = bezt->radius;
- bp->weight = bezt->weight;
- bp++;
- }
- }
- bezt++;
- }
- MEM_freeN(nu->bezt);
- nu->bezt = NULL;
- nu->pntsu = nr;
- nu->pntsv = 1;
- nu->orderu = 4;
- nu->orderv = 1;
- nu->type = type;
-
- if (type == CU_NURBS) {
- nu->flagu &= CU_NURB_CYCLIC; /* disable all flags except for cyclic */
- nu->flagu |= CU_NURB_BEZIER;
- BKE_nurb_knot_calc_u(nu);
- }
- }
- }
- else if (nu->type == CU_NURBS) {
- if (type == CU_POLY) {
- nu->type = CU_POLY;
- if (nu->knotsu) MEM_freeN(nu->knotsu); /* python created nurbs have a knotsu of zero */
- nu->knotsu = NULL;
- if (nu->knotsv) MEM_freeN(nu->knotsv);
- nu->knotsv = NULL;
- }
- else if (type == CU_BEZIER) { /* to Bezier */
- nr = nu->pntsu / 3;
-
- if (nr < 2) {
- return false; /* conversion impossible */
- }
- else {
- bezt = MEM_calloc_arrayN(nr, sizeof(BezTriple), "setsplinetype2");
- nu->bezt = bezt;
- a = nr;
- bp = nu->bp;
- while (a--) {
- copy_v3_v3(bezt->vec[0], bp->vec);
- bezt->f1 = bp->f1;
- bp++;
- copy_v3_v3(bezt->vec[1], bp->vec);
- bezt->f2 = bp->f1;
- bp++;
- copy_v3_v3(bezt->vec[2], bp->vec);
- bezt->f3 = bp->f1;
- bezt->radius = bp->radius;
- bezt->weight = bp->weight;
- bp++;
- bezt++;
- }
- MEM_freeN(nu->bp);
- nu->bp = NULL;
- MEM_freeN(nu->knotsu);
- nu->knotsu = NULL;
- nu->pntsu = nr;
- nu->type = CU_BEZIER;
- }
- }
- }
-
- return true;
+ BezTriple *bezt;
+ BPoint *bp;
+ int a, c, nr;
+
+ if (nu->type == CU_POLY) {
+ if (type == CU_BEZIER) { /* to Bezier with vecthandles */
+ nr = nu->pntsu;
+ bezt = (BezTriple *)MEM_calloc_arrayN(nr, sizeof(BezTriple), "setsplinetype2");
+ nu->bezt = bezt;
+ a = nr;
+ bp = nu->bp;
+ while (a--) {
+ copy_v3_v3(bezt->vec[1], bp->vec);
+ bezt->f1 = bezt->f2 = bezt->f3 = bp->f1;
+ bezt->h1 = bezt->h2 = HD_VECT;
+ bezt->weight = bp->weight;
+ bezt->radius = bp->radius;
+ bp++;
+ bezt++;
+ }
+ MEM_freeN(nu->bp);
+ nu->bp = NULL;
+ nu->pntsu = nr;
+ nu->pntsv = 0;
+ nu->type = CU_BEZIER;
+ BKE_nurb_handles_calc(nu);
+ }
+ else if (type == CU_NURBS) {
+ nu->type = CU_NURBS;
+ nu->orderu = 4;
+ nu->flagu &= CU_NURB_CYCLIC; /* disable all flags except for cyclic */
+ BKE_nurb_knot_calc_u(nu);
+ a = nu->pntsu * nu->pntsv;
+ bp = nu->bp;
+ while (a--) {
+ bp->vec[3] = 1.0;
+ bp++;
+ }
+ }
+ }
+ else if (nu->type == CU_BEZIER) { /* Bezier */
+ if (type == CU_POLY || type == CU_NURBS) {
+ nr = use_handles ? (3 * nu->pntsu) : nu->pntsu;
+ nu->bp = MEM_calloc_arrayN(nr, sizeof(BPoint), "setsplinetype");
+ a = nu->pntsu;
+ bezt = nu->bezt;
+ bp = nu->bp;
+ while (a--) {
+ if ((type == CU_POLY && bezt->h1 == HD_VECT && bezt->h2 == HD_VECT) ||
+ (use_handles == false)) {
+ /* vector handle becomes 1 poly vertice */
+ copy_v3_v3(bp->vec, bezt->vec[1]);
+ bp->vec[3] = 1.0;
+ bp->f1 = bezt->f2;
+ if (use_handles)
+ nr -= 2;
+ bp->radius = bezt->radius;
+ bp->weight = bezt->weight;
+ bp++;
+ }
+ else {
+ const char *f = &bezt->f1;
+ for (c = 0; c < 3; c++, f++) {
+ copy_v3_v3(bp->vec, bezt->vec[c]);
+ bp->vec[3] = 1.0;
+ bp->f1 = *f;
+ bp->radius = bezt->radius;
+ bp->weight = bezt->weight;
+ bp++;
+ }
+ }
+ bezt++;
+ }
+ MEM_freeN(nu->bezt);
+ nu->bezt = NULL;
+ nu->pntsu = nr;
+ nu->pntsv = 1;
+ nu->orderu = 4;
+ nu->orderv = 1;
+ nu->type = type;
+
+ if (type == CU_NURBS) {
+ nu->flagu &= CU_NURB_CYCLIC; /* disable all flags except for cyclic */
+ nu->flagu |= CU_NURB_BEZIER;
+ BKE_nurb_knot_calc_u(nu);
+ }
+ }
+ }
+ else if (nu->type == CU_NURBS) {
+ if (type == CU_POLY) {
+ nu->type = CU_POLY;
+ if (nu->knotsu)
+ MEM_freeN(nu->knotsu); /* python created nurbs have a knotsu of zero */
+ nu->knotsu = NULL;
+ if (nu->knotsv)
+ MEM_freeN(nu->knotsv);
+ nu->knotsv = NULL;
+ }
+ else if (type == CU_BEZIER) { /* to Bezier */
+ nr = nu->pntsu / 3;
+
+ if (nr < 2) {
+ return false; /* conversion impossible */
+ }
+ else {
+ bezt = MEM_calloc_arrayN(nr, sizeof(BezTriple), "setsplinetype2");
+ nu->bezt = bezt;
+ a = nr;
+ bp = nu->bp;
+ while (a--) {
+ copy_v3_v3(bezt->vec[0], bp->vec);
+ bezt->f1 = bp->f1;
+ bp++;
+ copy_v3_v3(bezt->vec[1], bp->vec);
+ bezt->f2 = bp->f1;
+ bp++;
+ copy_v3_v3(bezt->vec[2], bp->vec);
+ bezt->f3 = bp->f1;
+ bezt->radius = bp->radius;
+ bezt->weight = bp->weight;
+ bp++;
+ bezt++;
+ }
+ MEM_freeN(nu->bp);
+ nu->bp = NULL;
+ MEM_freeN(nu->knotsu);
+ nu->knotsu = NULL;
+ nu->pntsu = nr;
+ nu->type = CU_BEZIER;
+ }
+ }
+ }
+
+ return true;
}
/* Get edit nurbs or normal nurbs list */
ListBase *BKE_curve_nurbs_get(Curve *cu)
{
- if (cu->editnurb) {
- return BKE_curve_editNurbs_get(cu);
- }
+ if (cu->editnurb) {
+ return BKE_curve_editNurbs_get(cu);
+ }
- return &cu->nurb;
+ return &cu->nurb;
}
void BKE_curve_nurb_active_set(Curve *cu, const Nurb *nu)
{
- if (nu == NULL) {
- cu->actnu = CU_ACT_NONE;
- }
- else {
- BLI_assert(!nu->hide);
- ListBase *nurbs = BKE_curve_editNurbs_get(cu);
- cu->actnu = BLI_findindex(nurbs, nu);
- }
+ if (nu == NULL) {
+ cu->actnu = CU_ACT_NONE;
+ }
+ else {
+ BLI_assert(!nu->hide);
+ ListBase *nurbs = BKE_curve_editNurbs_get(cu);
+ cu->actnu = BLI_findindex(nurbs, nu);
+ }
}
Nurb *BKE_curve_nurb_active_get(Curve *cu)
{
- ListBase *nurbs = BKE_curve_editNurbs_get(cu);
- return BLI_findlink(nurbs, cu->actnu);
+ ListBase *nurbs = BKE_curve_editNurbs_get(cu);
+ return BLI_findlink(nurbs, cu->actnu);
}
/* Get active vert for curve */
void *BKE_curve_vert_active_get(Curve *cu)
{
- Nurb *nu = NULL;
- void *vert = NULL;
+ Nurb *nu = NULL;
+ void *vert = NULL;
- BKE_curve_nurb_vert_active_get(cu, &nu, &vert);
- return vert;
+ BKE_curve_nurb_vert_active_get(cu, &nu, &vert);
+ return vert;
}
int BKE_curve_nurb_vert_index_get(const Nurb *nu, const void *vert)
{
- if (nu->type == CU_BEZIER) {
- BLI_assert(ARRAY_HAS_ITEM((BezTriple *)vert, nu->bezt, nu->pntsu));
- return (BezTriple *)vert - nu->bezt;
- }
- else {
- BLI_assert(ARRAY_HAS_ITEM((BPoint *)vert, nu->bp, nu->pntsu * nu->pntsv));
- return (BPoint *)vert - nu->bp;
- }
+ if (nu->type == CU_BEZIER) {
+ BLI_assert(ARRAY_HAS_ITEM((BezTriple *)vert, nu->bezt, nu->pntsu));
+ return (BezTriple *)vert - nu->bezt;
+ }
+ else {
+ BLI_assert(ARRAY_HAS_ITEM((BPoint *)vert, nu->bp, nu->pntsu * nu->pntsv));
+ return (BPoint *)vert - nu->bp;
+ }
}
/* Set active nurb and active vert for curve */
void BKE_curve_nurb_vert_active_set(Curve *cu, const Nurb *nu, const void *vert)
{
- if (nu) {
- BKE_curve_nurb_active_set(cu, nu);
+ if (nu) {
+ BKE_curve_nurb_active_set(cu, nu);
- if (vert) {
- cu->actvert = BKE_curve_nurb_vert_index_get(nu, vert);
- }
- else {
- cu->actvert = CU_ACT_NONE;
- }
- }
- else {
- cu->actnu = cu->actvert = CU_ACT_NONE;
- }
+ if (vert) {
+ cu->actvert = BKE_curve_nurb_vert_index_get(nu, vert);
+ }
+ else {
+ cu->actvert = CU_ACT_NONE;
+ }
+ }
+ else {
+ cu->actnu = cu->actvert = CU_ACT_NONE;
+ }
}
/* Get points to active active nurb and active vert for curve */
bool BKE_curve_nurb_vert_active_get(Curve *cu, Nurb **r_nu, void **r_vert)
{
- Nurb *nu = NULL;
- void *vert = NULL;
+ Nurb *nu = NULL;
+ void *vert = NULL;
- if (cu->actvert != CU_ACT_NONE) {
- ListBase *nurbs = BKE_curve_editNurbs_get(cu);
- nu = BLI_findlink(nurbs, cu->actnu);
+ if (cu->actvert != CU_ACT_NONE) {
+ ListBase *nurbs = BKE_curve_editNurbs_get(cu);
+ nu = BLI_findlink(nurbs, cu->actnu);
- if (nu) {
- if (nu->type == CU_BEZIER) {
- BLI_assert(nu->pntsu > cu->actvert);
- vert = &nu->bezt[cu->actvert];
- }
- else {
- BLI_assert((nu->pntsu * nu->pntsv) > cu->actvert);
- vert = &nu->bp[cu->actvert];
- }
- }
- }
+ if (nu) {
+ if (nu->type == CU_BEZIER) {
+ BLI_assert(nu->pntsu > cu->actvert);
+ vert = &nu->bezt[cu->actvert];
+ }
+ else {
+ BLI_assert((nu->pntsu * nu->pntsv) > cu->actvert);
+ vert = &nu->bp[cu->actvert];
+ }
+ }
+ }
- *r_nu = nu;
- *r_vert = vert;
+ *r_nu = nu;
+ *r_vert = vert;
- return (*r_vert != NULL);
+ return (*r_vert != NULL);
}
void BKE_curve_nurb_vert_active_validate(Curve *cu)
{
- Nurb *nu;
- void *vert;
-
- if (BKE_curve_nurb_vert_active_get(cu, &nu, &vert)) {
- if (nu->type == CU_BEZIER) {
- BezTriple *bezt = vert;
- if (BEZT_ISSEL_ANY(bezt) == 0) {
- cu->actvert = CU_ACT_NONE;
- }
- }
- else {
- BPoint *bp = vert;
- if ((bp->f1 & SELECT) == 0) {
- cu->actvert = CU_ACT_NONE;
- }
- }
-
- if (nu->hide) {
- cu->actnu = CU_ACT_NONE;
- }
- }
+ Nurb *nu;
+ void *vert;
+
+ if (BKE_curve_nurb_vert_active_get(cu, &nu, &vert)) {
+ if (nu->type == CU_BEZIER) {
+ BezTriple *bezt = vert;
+ if (BEZT_ISSEL_ANY(bezt) == 0) {
+ cu->actvert = CU_ACT_NONE;
+ }
+ }
+ else {
+ BPoint *bp = vert;
+ if ((bp->f1 & SELECT) == 0) {
+ cu->actvert = CU_ACT_NONE;
+ }
+ }
+
+ if (nu->hide) {
+ cu->actnu = CU_ACT_NONE;
+ }
+ }
}
/* basic vertex data functions */
bool BKE_curve_minmax(Curve *cu, bool use_radius, float min[3], float max[3])
{
- ListBase *nurb_lb = BKE_curve_nurbs_get(cu);
- ListBase temp_nurb_lb = {NULL, NULL};
- const bool is_font = (BLI_listbase_is_empty(nurb_lb)) && (cu->len != 0);
- /* For font curves we generate temp list of splines.
- *
- * This is likely to be fine, this function is not supposed to be called
- * often, and it's the only way to get meaningful bounds for fonts.
- */
- if (is_font) {
- nurb_lb = &temp_nurb_lb;
- BKE_vfont_to_curve_ex(NULL, cu, FO_EDIT, nurb_lb,
- NULL, NULL, NULL, NULL);
- use_radius = false;
- }
- /* Do bounding box based on splines. */
- for (Nurb *nu = nurb_lb->first; nu; nu = nu->next) {
- BKE_nurb_minmax(nu, use_radius, min, max);
- }
- const bool result = (BLI_listbase_is_empty(nurb_lb) == false);
- /* Cleanup if needed. */
- BKE_nurbList_free(&temp_nurb_lb);
- return result;
+ ListBase *nurb_lb = BKE_curve_nurbs_get(cu);
+ ListBase temp_nurb_lb = {NULL, NULL};
+ const bool is_font = (BLI_listbase_is_empty(nurb_lb)) && (cu->len != 0);
+ /* For font curves we generate temp list of splines.
+ *
+ * This is likely to be fine, this function is not supposed to be called
+ * often, and it's the only way to get meaningful bounds for fonts.
+ */
+ if (is_font) {
+ nurb_lb = &temp_nurb_lb;
+ BKE_vfont_to_curve_ex(NULL, cu, FO_EDIT, nurb_lb, NULL, NULL, NULL, NULL);
+ use_radius = false;
+ }
+ /* Do bounding box based on splines. */
+ for (Nurb *nu = nurb_lb->first; nu; nu = nu->next) {
+ BKE_nurb_minmax(nu, use_radius, min, max);
+ }
+ const bool result = (BLI_listbase_is_empty(nurb_lb) == false);
+ /* Cleanup if needed. */
+ BKE_nurbList_free(&temp_nurb_lb);
+ return result;
}
bool BKE_curve_center_median(Curve *cu, float cent[3])
{
- ListBase *nurb_lb = BKE_curve_nurbs_get(cu);
- Nurb *nu;
- int total = 0;
-
- zero_v3(cent);
-
- for (nu = nurb_lb->first; nu; nu = nu->next) {
- int i;
-
- if (nu->type == CU_BEZIER) {
- BezTriple *bezt;
- i = nu->pntsu;
- total += i * 3;
- for (bezt = nu->bezt; i--; bezt++) {
- add_v3_v3(cent, bezt->vec[0]);
- add_v3_v3(cent, bezt->vec[1]);
- add_v3_v3(cent, bezt->vec[2]);
- }
- }
- else {
- BPoint *bp;
- i = nu->pntsu * nu->pntsv;
- total += i;
- for (bp = nu->bp; i--; bp++) {
- add_v3_v3(cent, bp->vec);
- }
- }
- }
-
- if (total) {
- mul_v3_fl(cent, 1.0f / (float)total);
- }
-
- return (total != 0);
+ ListBase *nurb_lb = BKE_curve_nurbs_get(cu);
+ Nurb *nu;
+ int total = 0;
+
+ zero_v3(cent);
+
+ for (nu = nurb_lb->first; nu; nu = nu->next) {
+ int i;
+
+ if (nu->type == CU_BEZIER) {
+ BezTriple *bezt;
+ i = nu->pntsu;
+ total += i * 3;
+ for (bezt = nu->bezt; i--; bezt++) {
+ add_v3_v3(cent, bezt->vec[0]);
+ add_v3_v3(cent, bezt->vec[1]);
+ add_v3_v3(cent, bezt->vec[2]);
+ }
+ }
+ else {
+ BPoint *bp;
+ i = nu->pntsu * nu->pntsv;
+ total += i;
+ for (bp = nu->bp; i--; bp++) {
+ add_v3_v3(cent, bp->vec);
+ }
+ }
+ }
+
+ if (total) {
+ mul_v3_fl(cent, 1.0f / (float)total);
+ }
+
+ return (total != 0);
}
bool BKE_curve_center_bounds(Curve *cu, float cent[3])
{
- float min[3], max[3];
- INIT_MINMAX(min, max);
- if (BKE_curve_minmax(cu, false, min, max)) {
- mid_v3_v3v3(cent, min, max);
- return true;
- }
+ float min[3], max[3];
+ INIT_MINMAX(min, max);
+ if (BKE_curve_minmax(cu, false, min, max)) {
+ mid_v3_v3v3(cent, min, max);
+ return true;
+ }
- return false;
+ return false;
}
-
void BKE_curve_transform_ex(
- Curve *cu, float mat[4][4],
- const bool do_keys, const bool do_props, const float unit_scale)
-{
- Nurb *nu;
- BPoint *bp;
- BezTriple *bezt;
- int i;
-
- for (nu = cu->nurb.first; nu; nu = nu->next) {
- if (nu->type == CU_BEZIER) {
- i = nu->pntsu;
- for (bezt = nu->bezt; i--; bezt++) {
- mul_m4_v3(mat, bezt->vec[0]);
- mul_m4_v3(mat, bezt->vec[1]);
- mul_m4_v3(mat, bezt->vec[2]);
- if (do_props) {
- bezt->radius *= unit_scale;
- }
- }
- BKE_nurb_handles_calc(nu);
- }
- else {
- i = nu->pntsu * nu->pntsv;
- for (bp = nu->bp; i--; bp++) {
- mul_m4_v3(mat, bp->vec);
- if (do_props) {
- bp->radius *= unit_scale;
- }
- }
- }
- }
-
- if (do_keys && cu->key) {
- KeyBlock *kb;
- for (kb = cu->key->block.first; kb; kb = kb->next) {
- float *fp = kb->data;
- int n = kb->totelem;
-
- for (nu = cu->nurb.first; nu; nu = nu->next) {
- if (nu->type == CU_BEZIER) {
- for (i = nu->pntsu; i && (n -= KEYELEM_ELEM_LEN_BEZTRIPLE) >= 0; i--) {
- mul_m4_v3(mat, &fp[0]);
- mul_m4_v3(mat, &fp[3]);
- mul_m4_v3(mat, &fp[6]);
- if (do_props) {
- fp[10] *= unit_scale; /* radius */
- }
- fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
- }
- }
- else {
- for (i = nu->pntsu * nu->pntsv; i && (n -= KEYELEM_ELEM_LEN_BPOINT) >= 0; i--) {
- mul_m4_v3(mat, fp);
- if (do_props) {
- fp[4] *= unit_scale; /* radius */
- }
- fp += KEYELEM_FLOAT_LEN_BPOINT;
- }
- }
- }
- }
- }
-}
-
-void BKE_curve_transform(
- Curve *cu, float mat[4][4],
- const bool do_keys, const bool do_props)
-{
- float unit_scale = mat4_to_scale(mat);
- BKE_curve_transform_ex(cu, mat, do_keys, do_props, unit_scale);
+ Curve *cu, float mat[4][4], const bool do_keys, const bool do_props, const float unit_scale)
+{
+ Nurb *nu;
+ BPoint *bp;
+ BezTriple *bezt;
+ int i;
+
+ for (nu = cu->nurb.first; nu; nu = nu->next) {
+ if (nu->type == CU_BEZIER) {
+ i = nu->pntsu;
+ for (bezt = nu->bezt; i--; bezt++) {
+ mul_m4_v3(mat, bezt->vec[0]);
+ mul_m4_v3(mat, bezt->vec[1]);
+ mul_m4_v3(mat, bezt->vec[2]);
+ if (do_props) {
+ bezt->radius *= unit_scale;
+ }
+ }
+ BKE_nurb_handles_calc(nu);
+ }
+ else {
+ i = nu->pntsu * nu->pntsv;
+ for (bp = nu->bp; i--; bp++) {
+ mul_m4_v3(mat, bp->vec);
+ if (do_props) {
+ bp->radius *= unit_scale;
+ }
+ }
+ }
+ }
+
+ if (do_keys && cu->key) {
+ KeyBlock *kb;
+ for (kb = cu->key->block.first; kb; kb = kb->next) {
+ float *fp = kb->data;
+ int n = kb->totelem;
+
+ for (nu = cu->nurb.first; nu; nu = nu->next) {
+ if (nu->type == CU_BEZIER) {
+ for (i = nu->pntsu; i && (n -= KEYELEM_ELEM_LEN_BEZTRIPLE) >= 0; i--) {
+ mul_m4_v3(mat, &fp[0]);
+ mul_m4_v3(mat, &fp[3]);
+ mul_m4_v3(mat, &fp[6]);
+ if (do_props) {
+ fp[10] *= unit_scale; /* radius */
+ }
+ fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
+ }
+ }
+ else {
+ for (i = nu->pntsu * nu->pntsv; i && (n -= KEYELEM_ELEM_LEN_BPOINT) >= 0; i--) {
+ mul_m4_v3(mat, fp);
+ if (do_props) {
+ fp[4] *= unit_scale; /* radius */
+ }
+ fp += KEYELEM_FLOAT_LEN_BPOINT;
+ }
+ }
+ }
+ }
+ }
+}
+
+void BKE_curve_transform(Curve *cu, float mat[4][4], const bool do_keys, const bool do_props)
+{
+ float unit_scale = mat4_to_scale(mat);
+ BKE_curve_transform_ex(cu, mat, do_keys, do_props, unit_scale);
}
void BKE_curve_translate(Curve *cu, float offset[3], const bool do_keys)
{
- ListBase *nurb_lb = BKE_curve_nurbs_get(cu);
- Nurb *nu;
- int i;
-
- for (nu = nurb_lb->first; nu; nu = nu->next) {
- BezTriple *bezt;
- BPoint *bp;
-
- if (nu->type == CU_BEZIER) {
- i = nu->pntsu;
- for (bezt = nu->bezt; i--; bezt++) {
- add_v3_v3(bezt->vec[0], offset);
- add_v3_v3(bezt->vec[1], offset);
- add_v3_v3(bezt->vec[2], offset);
- }
- }
- else {
- i = nu->pntsu * nu->pntsv;
- for (bp = nu->bp; i--; bp++) {
- add_v3_v3(bp->vec, offset);
- }
- }
- }
-
- if (do_keys && cu->key) {
- KeyBlock *kb;
- for (kb = cu->key->block.first; kb; kb = kb->next) {
- float *fp = kb->data;
- int n = kb->totelem;
-
- for (nu = cu->nurb.first; nu; nu = nu->next) {
- if (nu->type == CU_BEZIER) {
- for (i = nu->pntsu; i && (n -= KEYELEM_ELEM_LEN_BEZTRIPLE) >= 0; i--) {
- add_v3_v3(&fp[0], offset);
- add_v3_v3(&fp[3], offset);
- add_v3_v3(&fp[6], offset);
- fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
- }
- }
- else {
- for (i = nu->pntsu * nu->pntsv; i && (n -= KEYELEM_ELEM_LEN_BPOINT) >= 0; i--) {
- add_v3_v3(fp, offset);
- fp += KEYELEM_FLOAT_LEN_BPOINT;
- }
- }
- }
- }
- }
+ ListBase *nurb_lb = BKE_curve_nurbs_get(cu);
+ Nurb *nu;
+ int i;
+
+ for (nu = nurb_lb->first; nu; nu = nu->next) {
+ BezTriple *bezt;
+ BPoint *bp;
+
+ if (nu->type == CU_BEZIER) {
+ i = nu->pntsu;
+ for (bezt = nu->bezt; i--; bezt++) {
+ add_v3_v3(bezt->vec[0], offset);
+ add_v3_v3(bezt->vec[1], offset);
+ add_v3_v3(bezt->vec[2], offset);
+ }
+ }
+ else {
+ i = nu->pntsu * nu->pntsv;
+ for (bp = nu->bp; i--; bp++) {
+ add_v3_v3(bp->vec, offset);
+ }
+ }
+ }
+
+ if (do_keys && cu->key) {
+ KeyBlock *kb;
+ for (kb = cu->key->block.first; kb; kb = kb->next) {
+ float *fp = kb->data;
+ int n = kb->totelem;
+
+ for (nu = cu->nurb.first; nu; nu = nu->next) {
+ if (nu->type == CU_BEZIER) {
+ for (i = nu->pntsu; i && (n -= KEYELEM_ELEM_LEN_BEZTRIPLE) >= 0; i--) {
+ add_v3_v3(&fp[0], offset);
+ add_v3_v3(&fp[3], offset);
+ add_v3_v3(&fp[6], offset);
+ fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
+ }
+ }
+ else {
+ for (i = nu->pntsu * nu->pntsv; i && (n -= KEYELEM_ELEM_LEN_BPOINT) >= 0; i--) {
+ add_v3_v3(fp, offset);
+ fp += KEYELEM_FLOAT_LEN_BPOINT;
+ }
+ }
+ }
+ }
+ }
}
void BKE_curve_material_index_remove(Curve *cu, int index)
{
- const int curvetype = BKE_curve_type_get(cu);
+ const int curvetype = BKE_curve_type_get(cu);
- if (curvetype == OB_FONT) {
- struct CharInfo *info = cu->strinfo;
- int i;
- for (i = cu->len_wchar - 1; i >= 0; i--, info++) {
- if (info->mat_nr && info->mat_nr >= index) {
- info->mat_nr--;
- }
- }
- }
- else {
- Nurb *nu;
+ if (curvetype == OB_FONT) {
+ struct CharInfo *info = cu->strinfo;
+ int i;
+ for (i = cu->len_wchar - 1; i >= 0; i--, info++) {
+ if (info->mat_nr && info->mat_nr >= index) {
+ info->mat_nr--;
+ }
+ }
+ }
+ else {
+ Nurb *nu;
- for (nu = cu->nurb.first; nu; nu = nu->next) {
- if (nu->mat_nr && nu->mat_nr >= index) {
- nu->mat_nr--;
- }
- }
- }
+ for (nu = cu->nurb.first; nu; nu = nu->next) {
+ if (nu->mat_nr && nu->mat_nr >= index) {
+ nu->mat_nr--;
+ }
+ }
+ }
}
void BKE_curve_material_index_clear(Curve *cu)
{
- const int curvetype = BKE_curve_type_get(cu);
+ const int curvetype = BKE_curve_type_get(cu);
- if (curvetype == OB_FONT) {
- struct CharInfo *info = cu->strinfo;
- int i;
- for (i = cu->len_wchar - 1; i >= 0; i--, info++) {
- info->mat_nr = 0;
- }
- }
- else {
- Nurb *nu;
+ if (curvetype == OB_FONT) {
+ struct CharInfo *info = cu->strinfo;
+ int i;
+ for (i = cu->len_wchar - 1; i >= 0; i--, info++) {
+ info->mat_nr = 0;
+ }
+ }
+ else {
+ Nurb *nu;
- for (nu = cu->nurb.first; nu; nu = nu->next) {
- nu->mat_nr = 0;
- }
- }
+ for (nu = cu->nurb.first; nu; nu = nu->next) {
+ nu->mat_nr = 0;
+ }
+ }
}
bool BKE_curve_material_index_validate(Curve *cu)
{
- const int curvetype = BKE_curve_type_get(cu);
- bool is_valid = true;
-
- if (curvetype == OB_FONT) {
- CharInfo *info = cu->strinfo;
- const int max_idx = max_ii(0, cu->totcol); /* OB_FONT use 1 as first mat index, not 0!!! */
- int i;
- for (i = cu->len_wchar - 1; i >= 0; i--, info++) {
- if (info->mat_nr > max_idx) {
- info->mat_nr = 0;
- is_valid = false;
- }
- }
- }
- else {
- Nurb *nu;
- const int max_idx = max_ii(0, cu->totcol - 1);
- for (nu = cu->nurb.first; nu; nu = nu->next) {
- if (nu->mat_nr > max_idx) {
- nu->mat_nr = 0;
- is_valid = false;
- }
- }
- }
-
- if (!is_valid) {
- DEG_id_tag_update(&cu->id, ID_RECALC_GEOMETRY);
- return true;
- }
- else {
- return false;
- }
+ const int curvetype = BKE_curve_type_get(cu);
+ bool is_valid = true;
+
+ if (curvetype == OB_FONT) {
+ CharInfo *info = cu->strinfo;
+ const int max_idx = max_ii(0, cu->totcol); /* OB_FONT use 1 as first mat index, not 0!!! */
+ int i;
+ for (i = cu->len_wchar - 1; i >= 0; i--, info++) {
+ if (info->mat_nr > max_idx) {
+ info->mat_nr = 0;
+ is_valid = false;
+ }
+ }
+ }
+ else {
+ Nurb *nu;
+ const int max_idx = max_ii(0, cu->totcol - 1);
+ for (nu = cu->nurb.first; nu; nu = nu->next) {
+ if (nu->mat_nr > max_idx) {
+ nu->mat_nr = 0;
+ is_valid = false;
+ }
+ }
+ }
+
+ if (!is_valid) {
+ DEG_id_tag_update(&cu->id, ID_RECALC_GEOMETRY);
+ return true;
+ }
+ else {
+ return false;
+ }
}
void BKE_curve_material_remap(Curve *cu, const unsigned int *remap, unsigned int remap_len)
{
- const int curvetype = BKE_curve_type_get(cu);
- const short remap_len_short = (short)remap_len;
+ const int curvetype = BKE_curve_type_get(cu);
+ const short remap_len_short = (short)remap_len;
#define MAT_NR_REMAP(n) \
- if (n < remap_len_short) { \
- BLI_assert(n >= 0 && remap[n] < remap_len_short); \
- n = remap[n]; \
- } ((void)0)
-
- if (curvetype == OB_FONT) {
- struct CharInfo *strinfo;
- int charinfo_len, i;
-
- if (cu->editfont) {
- EditFont *ef = cu->editfont;
- strinfo = ef->textbufinfo;
- charinfo_len = ef->len;
- }
- else {
- strinfo = cu->strinfo;
- charinfo_len = cu->len_wchar;
- }
-
- for (i = 0; i <= charinfo_len; i++) {
- if (strinfo[i].mat_nr > 0) {
- strinfo[i].mat_nr -= 1;
- MAT_NR_REMAP(strinfo[i].mat_nr);
- strinfo[i].mat_nr += 1;
- }
- }
- }
- else {
- Nurb *nu;
- ListBase *nurbs = BKE_curve_editNurbs_get(cu);
-
- if (nurbs) {
- for (nu = nurbs->first; nu; nu = nu->next) {
- MAT_NR_REMAP(nu->mat_nr);
- }
- }
- }
+ if (n < remap_len_short) { \
+ BLI_assert(n >= 0 && remap[n] < remap_len_short); \
+ n = remap[n]; \
+ } \
+ ((void)0)
+
+ if (curvetype == OB_FONT) {
+ struct CharInfo *strinfo;
+ int charinfo_len, i;
+
+ if (cu->editfont) {
+ EditFont *ef = cu->editfont;
+ strinfo = ef->textbufinfo;
+ charinfo_len = ef->len;
+ }
+ else {
+ strinfo = cu->strinfo;
+ charinfo_len = cu->len_wchar;
+ }
+
+ for (i = 0; i <= charinfo_len; i++) {
+ if (strinfo[i].mat_nr > 0) {
+ strinfo[i].mat_nr -= 1;
+ MAT_NR_REMAP(strinfo[i].mat_nr);
+ strinfo[i].mat_nr += 1;
+ }
+ }
+ }
+ else {
+ Nurb *nu;
+ ListBase *nurbs = BKE_curve_editNurbs_get(cu);
+
+ if (nurbs) {
+ for (nu = nurbs->first; nu; nu = nu->next) {
+ MAT_NR_REMAP(nu->mat_nr);
+ }
+ }
+ }
#undef MAT_NR_REMAP
-
}
-void BKE_curve_rect_from_textbox(const struct Curve *cu, const struct TextBox *tb, struct rctf *r_rect)
+void BKE_curve_rect_from_textbox(const struct Curve *cu,
+ const struct TextBox *tb,
+ struct rctf *r_rect)
{
- r_rect->xmin = cu->xof + tb->x;
- r_rect->ymax = cu->yof + tb->y + cu->fsize;
+ r_rect->xmin = cu->xof + tb->x;
+ r_rect->ymax = cu->yof + tb->y + cu->fsize;
- r_rect->xmax = r_rect->xmin + tb->w;
- r_rect->ymin = r_rect->ymax - tb->h;
+ r_rect->xmax = r_rect->xmin + tb->w;
+ r_rect->ymin = r_rect->ymax - tb->h;
}
/* **** Depsgraph evaluation **** */
-void BKE_curve_eval_geometry(Depsgraph *depsgraph,
- Curve *curve)
+void BKE_curve_eval_geometry(Depsgraph *depsgraph, Curve *curve)
{
- DEG_debug_print_eval(depsgraph, __func__, curve->id.name, curve);
- if (curve->bb == NULL || (curve->bb->flag & BOUNDBOX_DIRTY)) {
- BKE_curve_texspace_calc(curve);
- }
+ DEG_debug_print_eval(depsgraph, __func__, curve->id.name, curve);
+ if (curve->bb == NULL || (curve->bb->flag & BOUNDBOX_DIRTY)) {
+ BKE_curve_texspace_calc(curve);
+ }
}
/* Draw Engine */
@@ -5381,13 +5486,13 @@ void (*BKE_curve_batch_cache_free_cb)(Curve *cu) = NULL;
void BKE_curve_batch_cache_dirty_tag(Curve *cu, int mode)
{
- if (cu->batch_cache) {
- BKE_curve_batch_cache_dirty_tag_cb(cu, mode);
- }
+ if (cu->batch_cache) {
+ BKE_curve_batch_cache_dirty_tag_cb(cu, mode);
+ }
}
void BKE_curve_batch_cache_free(Curve *cu)
{
- if (cu->batch_cache) {
- BKE_curve_batch_cache_free_cb(cu);
- }
+ if (cu->batch_cache) {
+ BKE_curve_batch_cache_free_cb(cu);
+ }
}
diff --git a/source/blender/blenkernel/intern/curve_decimate.c b/source/blender/blenkernel/intern/curve_decimate.c
index 4ac62578fa4..cccdf830854 100644
--- a/source/blender/blenkernel/intern/curve_decimate.c
+++ b/source/blender/blenkernel/intern/curve_decimate.c
@@ -31,305 +31,324 @@
#include "BLI_strict_flags.h"
struct Knot {
- struct Knot *next, *prev;
- uint point_index; /* index in point array */
- uint knot_index; /* index in knot array*/
- float tan[2][3];
- float handles[2];
+ struct Knot *next, *prev;
+ uint point_index; /* index in point array */
+ uint knot_index; /* index in knot array*/
+ float tan[2][3];
+ float handles[2];
- HeapNode *heap_node;
- uint can_remove : 1;
- uint is_removed : 1;
+ HeapNode *heap_node;
+ uint can_remove : 1;
+ uint is_removed : 1;
#ifndef NDEBUG
- const float *co;
+ const float *co;
#endif
};
struct Removal {
- uint knot_index;
- /* handles for prev/next knots */
- float handles[2];
+ uint knot_index;
+ /* handles for prev/next knots */
+ float handles[2];
};
-static float knot_remove_error_value(
- const float tan_l[3], const float tan_r[3],
- const float (*points)[3], const uint points_len,
- /* avoid having to re-calculate again */
- float r_handle_factors[2])
+static float knot_remove_error_value(const float tan_l[3],
+ const float tan_r[3],
+ const float (*points)[3],
+ const uint points_len,
+ /* avoid having to re-calculate again */
+ float r_handle_factors[2])
{
- const uint dims = 3;
- float error_sq = FLT_MAX;
- uint error_sq_index;
- float handle_factors[2][3];
-
- curve_fit_cubic_to_points_single_fl(
- &points[0][0], points_len, NULL, dims, 0.0f,
- tan_l, tan_r,
- handle_factors[0], handle_factors[1],
- &error_sq, &error_sq_index);
-
- sub_v3_v3(handle_factors[0], points[0]);
- r_handle_factors[0] = dot_v3v3(tan_l, handle_factors[0]);
-
- sub_v3_v3(handle_factors[1], points[points_len - 1]);
- r_handle_factors[1] = dot_v3v3(tan_r, handle_factors[1]);
-
- return error_sq;
+ const uint dims = 3;
+ float error_sq = FLT_MAX;
+ uint error_sq_index;
+ float handle_factors[2][3];
+
+ curve_fit_cubic_to_points_single_fl(&points[0][0],
+ points_len,
+ NULL,
+ dims,
+ 0.0f,
+ tan_l,
+ tan_r,
+ handle_factors[0],
+ handle_factors[1],
+ &error_sq,
+ &error_sq_index);
+
+ sub_v3_v3(handle_factors[0], points[0]);
+ r_handle_factors[0] = dot_v3v3(tan_l, handle_factors[0]);
+
+ sub_v3_v3(handle_factors[1], points[points_len - 1]);
+ r_handle_factors[1] = dot_v3v3(tan_r, handle_factors[1]);
+
+ return error_sq;
}
-static void knot_remove_error_recalculate(
- Heap *heap, const float (*points)[3], const uint points_len,
- struct Knot *k, const float error_sq_max)
+static void knot_remove_error_recalculate(Heap *heap,
+ const float (*points)[3],
+ const uint points_len,
+ struct Knot *k,
+ const float error_sq_max)
{
- BLI_assert(k->can_remove);
- float handles[2];
+ BLI_assert(k->can_remove);
+ float handles[2];
#ifndef NDEBUG
- BLI_assert(equals_v3v3(points[k->prev->point_index], k->prev->co));
- BLI_assert(equals_v3v3(points[k->next->point_index], k->next->co));
+ BLI_assert(equals_v3v3(points[k->prev->point_index], k->prev->co));
+ BLI_assert(equals_v3v3(points[k->next->point_index], k->next->co));
#endif
- const float (*points_offset)[3];
- uint points_offset_len;
-
- if (k->prev->point_index < k->next->point_index) {
- points_offset = &points[k->prev->point_index];
- points_offset_len = (k->next->point_index - k->prev->point_index) + 1;
- }
- else {
- points_offset = &points[k->prev->point_index];
- points_offset_len = ((k->next->point_index + points_len) - k->prev->point_index) + 1;
- }
-
- const float cost_sq = knot_remove_error_value(
- k->prev->tan[1], k->next->tan[0],
- points_offset, points_offset_len,
- handles);
-
- if (cost_sq < error_sq_max) {
- struct Removal *r;
- if (k->heap_node) {
- r = BLI_heap_node_ptr(k->heap_node);
- }
- else {
- r = MEM_mallocN(sizeof(*r), __func__);
- r->knot_index = k->knot_index;
- }
-
- copy_v2_v2(r->handles, handles);
-
- BLI_heap_insert_or_update(heap, &k->heap_node, cost_sq, r);
- }
- else {
- if (k->heap_node) {
- struct Removal *r;
- r = BLI_heap_node_ptr(k->heap_node);
- BLI_heap_remove(heap, k->heap_node);
-
- MEM_freeN(r);
-
- k->heap_node = NULL;
- }
- }
+ const float(*points_offset)[3];
+ uint points_offset_len;
+
+ if (k->prev->point_index < k->next->point_index) {
+ points_offset = &points[k->prev->point_index];
+ points_offset_len = (k->next->point_index - k->prev->point_index) + 1;
+ }
+ else {
+ points_offset = &points[k->prev->point_index];
+ points_offset_len = ((k->next->point_index + points_len) - k->prev->point_index) + 1;
+ }
+
+ const float cost_sq = knot_remove_error_value(
+ k->prev->tan[1], k->next->tan[0], points_offset, points_offset_len, handles);
+
+ if (cost_sq < error_sq_max) {
+ struct Removal *r;
+ if (k->heap_node) {
+ r = BLI_heap_node_ptr(k->heap_node);
+ }
+ else {
+ r = MEM_mallocN(sizeof(*r), __func__);
+ r->knot_index = k->knot_index;
+ }
+
+ copy_v2_v2(r->handles, handles);
+
+ BLI_heap_insert_or_update(heap, &k->heap_node, cost_sq, r);
+ }
+ else {
+ if (k->heap_node) {
+ struct Removal *r;
+ r = BLI_heap_node_ptr(k->heap_node);
+ BLI_heap_remove(heap, k->heap_node);
+
+ MEM_freeN(r);
+
+ k->heap_node = NULL;
+ }
+ }
}
-static void curve_decimate(
- const float (*points)[3], const uint points_len,
- struct Knot *knots, const uint knots_len,
- float error_sq_max, const uint error_target_len)
+static void curve_decimate(const float (*points)[3],
+ const uint points_len,
+ struct Knot *knots,
+ const uint knots_len,
+ float error_sq_max,
+ const uint error_target_len)
{
- Heap *heap = BLI_heap_new_ex(knots_len);
- for (uint i = 0; i < knots_len; i++) {
- struct Knot *k = &knots[i];
- if (k->can_remove) {
- knot_remove_error_recalculate(heap, points, points_len, k, error_sq_max);
- }
- }
-
- uint knots_len_remaining = knots_len;
-
- while ((knots_len_remaining > error_target_len) &&
- (BLI_heap_is_empty(heap) == false))
- {
- struct Knot *k;
-
- {
- struct Removal *r = BLI_heap_pop_min(heap);
- k = &knots[r->knot_index];
- k->heap_node = NULL;
- k->prev->handles[1] = r->handles[0];
- k->next->handles[0] = r->handles[1];
- MEM_freeN(r);
- }
-
- struct Knot *k_prev = k->prev;
- struct Knot *k_next = k->next;
-
- /* remove ourselves */
- k_next->prev = k_prev;
- k_prev->next = k_next;
-
- k->next = NULL;
- k->prev = NULL;
- k->is_removed = true;
-
- if (k_prev->can_remove) {
- knot_remove_error_recalculate(heap, points, points_len, k_prev, error_sq_max);
- }
-
- if (k_next->can_remove) {
- knot_remove_error_recalculate(heap, points, points_len, k_next, error_sq_max);
- }
-
- knots_len_remaining -= 1;
- }
-
- BLI_heap_free(heap, MEM_freeN);
+ Heap *heap = BLI_heap_new_ex(knots_len);
+ for (uint i = 0; i < knots_len; i++) {
+ struct Knot *k = &knots[i];
+ if (k->can_remove) {
+ knot_remove_error_recalculate(heap, points, points_len, k, error_sq_max);
+ }
+ }
+
+ uint knots_len_remaining = knots_len;
+
+ while ((knots_len_remaining > error_target_len) && (BLI_heap_is_empty(heap) == false)) {
+ struct Knot *k;
+
+ {
+ struct Removal *r = BLI_heap_pop_min(heap);
+ k = &knots[r->knot_index];
+ k->heap_node = NULL;
+ k->prev->handles[1] = r->handles[0];
+ k->next->handles[0] = r->handles[1];
+ MEM_freeN(r);
+ }
+
+ struct Knot *k_prev = k->prev;
+ struct Knot *k_next = k->next;
+
+ /* remove ourselves */
+ k_next->prev = k_prev;
+ k_prev->next = k_next;
+
+ k->next = NULL;
+ k->prev = NULL;
+ k->is_removed = true;
+
+ if (k_prev->can_remove) {
+ knot_remove_error_recalculate(heap, points, points_len, k_prev, error_sq_max);
+ }
+
+ if (k_next->can_remove) {
+ knot_remove_error_recalculate(heap, points, points_len, k_next, error_sq_max);
+ }
+
+ knots_len_remaining -= 1;
+ }
+
+ BLI_heap_free(heap, MEM_freeN);
}
-
-uint BKE_curve_decimate_bezt_array(
- BezTriple *bezt_array, const uint bezt_array_len,
- const uint resolu, const bool is_cyclic,
- const char flag_test, const char flag_set,
- const float error_sq_max, const uint error_target_len)
+uint BKE_curve_decimate_bezt_array(BezTriple *bezt_array,
+ const uint bezt_array_len,
+ const uint resolu,
+ const bool is_cyclic,
+ const char flag_test,
+ const char flag_set,
+ const float error_sq_max,
+ const uint error_target_len)
{
- const uint bezt_array_last = bezt_array_len - 1;
- const uint points_len = BKE_curve_calc_coords_axis_len(bezt_array_len, resolu, is_cyclic, true);
+ const uint bezt_array_last = bezt_array_len - 1;
+ const uint points_len = BKE_curve_calc_coords_axis_len(bezt_array_len, resolu, is_cyclic, true);
- float (*points)[3] = MEM_mallocN((sizeof(float[3]) * points_len * (is_cyclic ? 2 : 1)), __func__);
+ float(*points)[3] = MEM_mallocN((sizeof(float[3]) * points_len * (is_cyclic ? 2 : 1)), __func__);
- BKE_curve_calc_coords_axis(bezt_array, bezt_array_len, resolu, is_cyclic, false, 0, sizeof(float[3]), &points[0][0]);
- BKE_curve_calc_coords_axis(bezt_array, bezt_array_len, resolu, is_cyclic, false, 1, sizeof(float[3]), &points[0][1]);
- BKE_curve_calc_coords_axis(bezt_array, bezt_array_len, resolu, is_cyclic, false, 2, sizeof(float[3]), &points[0][2]);
+ BKE_curve_calc_coords_axis(
+ bezt_array, bezt_array_len, resolu, is_cyclic, false, 0, sizeof(float[3]), &points[0][0]);
+ BKE_curve_calc_coords_axis(
+ bezt_array, bezt_array_len, resolu, is_cyclic, false, 1, sizeof(float[3]), &points[0][1]);
+ BKE_curve_calc_coords_axis(
+ bezt_array, bezt_array_len, resolu, is_cyclic, false, 2, sizeof(float[3]), &points[0][2]);
- const uint knots_len = bezt_array_len;
- struct Knot *knots = MEM_mallocN((sizeof(*knots) * bezt_array_len), __func__);
+ const uint knots_len = bezt_array_len;
+ struct Knot *knots = MEM_mallocN((sizeof(*knots) * bezt_array_len), __func__);
- if (is_cyclic) {
- memcpy(points[points_len], points[0], sizeof(float[3]) * points_len);
- }
+ if (is_cyclic) {
+ memcpy(points[points_len], points[0], sizeof(float[3]) * points_len);
+ }
- for (uint i = 0; i < bezt_array_len; i++) {
- knots[i].heap_node = NULL;
- knots[i].can_remove = (bezt_array[i].f2 & flag_test) != 0;
- knots[i].is_removed = false;
- knots[i].next = &knots[i + 1];
- knots[i].prev = &knots[i - 1];
- knots[i].point_index = i * resolu;
- knots[i].knot_index = i;
+ for (uint i = 0; i < bezt_array_len; i++) {
+ knots[i].heap_node = NULL;
+ knots[i].can_remove = (bezt_array[i].f2 & flag_test) != 0;
+ knots[i].is_removed = false;
+ knots[i].next = &knots[i + 1];
+ knots[i].prev = &knots[i - 1];
+ knots[i].point_index = i * resolu;
+ knots[i].knot_index = i;
- sub_v3_v3v3(knots[i].tan[0], bezt_array[i].vec[0], bezt_array[i].vec[1]);
- knots[i].handles[0] = normalize_v3(knots[i].tan[0]);
+ sub_v3_v3v3(knots[i].tan[0], bezt_array[i].vec[0], bezt_array[i].vec[1]);
+ knots[i].handles[0] = normalize_v3(knots[i].tan[0]);
- sub_v3_v3v3(knots[i].tan[1], bezt_array[i].vec[1], bezt_array[i].vec[2]);
- knots[i].handles[1] = -normalize_v3(knots[i].tan[1]);
+ sub_v3_v3v3(knots[i].tan[1], bezt_array[i].vec[1], bezt_array[i].vec[2]);
+ knots[i].handles[1] = -normalize_v3(knots[i].tan[1]);
#ifndef NDEBUG
- knots[i].co = bezt_array[i].vec[1];
- BLI_assert(equals_v3v3(knots[i].co, points[knots[i].point_index]));
+ knots[i].co = bezt_array[i].vec[1];
+ BLI_assert(equals_v3v3(knots[i].co, points[knots[i].point_index]));
#endif
- }
+ }
- if (is_cyclic) {
- knots[0].prev = &knots[bezt_array_last];
- knots[bezt_array_last].next = &knots[0];
- }
- else {
- knots[0].prev = NULL;
- knots[bezt_array_last].next = NULL;
+ if (is_cyclic) {
+ knots[0].prev = &knots[bezt_array_last];
+ knots[bezt_array_last].next = &knots[0];
+ }
+ else {
+ knots[0].prev = NULL;
+ knots[bezt_array_last].next = NULL;
- /* always keep end-points */
- knots[0].can_remove = false;
- knots[bezt_array_last].can_remove = false;
- }
+ /* always keep end-points */
+ knots[0].can_remove = false;
+ knots[bezt_array_last].can_remove = false;
+ }
- curve_decimate(points, points_len, knots, knots_len, error_sq_max, error_target_len);
+ curve_decimate(points, points_len, knots, knots_len, error_sq_max, error_target_len);
- MEM_freeN(points);
+ MEM_freeN(points);
- uint knots_len_decimated = knots_len;
+ uint knots_len_decimated = knots_len;
- /* Update handle type on modifications. */
+ /* Update handle type on modifications. */
#define HANDLE_UPDATE(a, b) \
- { \
- if (a == HD_VECT) { \
- a = HD_FREE; \
- } \
- else if (a == HD_AUTO) { \
- a = HD_ALIGN; \
- } \
- /* opposite handle */ \
- if (b == HD_AUTO) { \
- b = HD_ALIGN; \
- } \
- } ((void)0)
-
- for (uint i = 0; i < bezt_array_len; i++) {
- if (knots[i].is_removed) {
- /* caller must remove */
- bezt_array[i].f2 |= flag_set;
- knots_len_decimated--;
- }
- else {
- bezt_array[i].f2 &= (char)~flag_set;
- if (is_cyclic || i != 0) {
- uint i_prev = (i != 0) ? i - 1 : bezt_array_last;
- if (knots[i_prev].is_removed) {
- madd_v3_v3v3fl(bezt_array[i].vec[0], bezt_array[i].vec[1], knots[i].tan[0], knots[i].handles[0]);
- HANDLE_UPDATE(bezt_array[i].h1, bezt_array[i].h2);
- }
- }
- if (is_cyclic || i != bezt_array_last) {
- uint i_next = (i != bezt_array_last) ? i + 1 : 0;
- if (knots[i_next].is_removed) {
- madd_v3_v3v3fl(bezt_array[i].vec[2], bezt_array[i].vec[1], knots[i].tan[1], knots[i].handles[1]);
- HANDLE_UPDATE(bezt_array[i].h2, bezt_array[i].h1);
- }
- }
- }
- }
+ { \
+ if (a == HD_VECT) { \
+ a = HD_FREE; \
+ } \
+ else if (a == HD_AUTO) { \
+ a = HD_ALIGN; \
+ } \
+ /* opposite handle */ \
+ if (b == HD_AUTO) { \
+ b = HD_ALIGN; \
+ } \
+ } \
+ ((void)0)
+
+ for (uint i = 0; i < bezt_array_len; i++) {
+ if (knots[i].is_removed) {
+ /* caller must remove */
+ bezt_array[i].f2 |= flag_set;
+ knots_len_decimated--;
+ }
+ else {
+ bezt_array[i].f2 &= (char)~flag_set;
+ if (is_cyclic || i != 0) {
+ uint i_prev = (i != 0) ? i - 1 : bezt_array_last;
+ if (knots[i_prev].is_removed) {
+ madd_v3_v3v3fl(
+ bezt_array[i].vec[0], bezt_array[i].vec[1], knots[i].tan[0], knots[i].handles[0]);
+ HANDLE_UPDATE(bezt_array[i].h1, bezt_array[i].h2);
+ }
+ }
+ if (is_cyclic || i != bezt_array_last) {
+ uint i_next = (i != bezt_array_last) ? i + 1 : 0;
+ if (knots[i_next].is_removed) {
+ madd_v3_v3v3fl(
+ bezt_array[i].vec[2], bezt_array[i].vec[1], knots[i].tan[1], knots[i].handles[1]);
+ HANDLE_UPDATE(bezt_array[i].h2, bezt_array[i].h1);
+ }
+ }
+ }
+ }
#undef HANDLE_UPDATE
- MEM_freeN(knots);
+ MEM_freeN(knots);
- return knots_len_decimated;
+ return knots_len_decimated;
}
#define SELECT 1
-
-void BKE_curve_decimate_nurb(
- Nurb *nu, const uint resolu,
- const float error_sq_max, const uint error_target_len)
+void BKE_curve_decimate_nurb(Nurb *nu,
+ const uint resolu,
+ const float error_sq_max,
+ const uint error_target_len)
{
- const char flag_test = BEZT_FLAG_TEMP_TAG;
-
- const uint pntsu_dst = BKE_curve_decimate_bezt_array(
- nu->bezt, (uint)nu->pntsu, resolu, (nu->flagu & CU_NURB_CYCLIC) != 0,
- SELECT, flag_test,
- error_sq_max, error_target_len);
-
- if (pntsu_dst == (uint)nu->pntsu) {
- return;
- }
-
- BezTriple *bezt_src = nu->bezt;
- BezTriple *bezt_dst = MEM_mallocN(sizeof(BezTriple) * pntsu_dst, __func__);
-
- int i_src = 0, i_dst = 0;
-
- while (i_src < nu->pntsu) {
- if ((bezt_src[i_src].f2 & flag_test) == 0) {
- bezt_dst[i_dst] = bezt_src[i_src];
- i_dst++;
- }
- i_src++;
- }
-
- MEM_freeN(bezt_src);
-
- nu->bezt = bezt_dst;
- nu->pntsu = i_dst;
+ const char flag_test = BEZT_FLAG_TEMP_TAG;
+
+ const uint pntsu_dst = BKE_curve_decimate_bezt_array(nu->bezt,
+ (uint)nu->pntsu,
+ resolu,
+ (nu->flagu & CU_NURB_CYCLIC) != 0,
+ SELECT,
+ flag_test,
+ error_sq_max,
+ error_target_len);
+
+ if (pntsu_dst == (uint)nu->pntsu) {
+ return;
+ }
+
+ BezTriple *bezt_src = nu->bezt;
+ BezTriple *bezt_dst = MEM_mallocN(sizeof(BezTriple) * pntsu_dst, __func__);
+
+ int i_src = 0, i_dst = 0;
+
+ while (i_src < nu->pntsu) {
+ if ((bezt_src[i_src].f2 & flag_test) == 0) {
+ bezt_dst[i_dst] = bezt_src[i_src];
+ i_dst++;
+ }
+ i_src++;
+ }
+
+ MEM_freeN(bezt_src);
+
+ nu->bezt = bezt_dst;
+ nu->pntsu = i_dst;
}
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index 1b1cc1fa30f..eff85f411ca 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -62,1335 +62,1579 @@ BLI_STATIC_ASSERT(ARRAY_SIZE(((CustomData *)NULL)->typemap) == CD_NUMTYPES, "siz
static CLG_LogRef LOG = {"bke.customdata"};
-
/** Update mask_dst with layers defined in mask_src (equivalent to a bitwise OR). */
-void CustomData_MeshMasks_update(CustomData_MeshMasks *mask_dst, const CustomData_MeshMasks *mask_src)
+void CustomData_MeshMasks_update(CustomData_MeshMasks *mask_dst,
+ const CustomData_MeshMasks *mask_src)
{
- mask_dst->vmask |= mask_src->vmask;
- mask_dst->emask |= mask_src->emask;
- mask_dst->fmask |= mask_src->fmask;
- mask_dst->pmask |= mask_src->pmask;
- mask_dst->lmask |= mask_src->lmask;
+ mask_dst->vmask |= mask_src->vmask;
+ mask_dst->emask |= mask_src->emask;
+ mask_dst->fmask |= mask_src->fmask;
+ mask_dst->pmask |= mask_src->pmask;
+ mask_dst->lmask |= mask_src->lmask;
}
/** Return True if all layers set in \a mask_required are also set in \a mask_ref */
-bool CustomData_MeshMasks_are_matching(const CustomData_MeshMasks *mask_ref, const CustomData_MeshMasks *mask_required)
+bool CustomData_MeshMasks_are_matching(const CustomData_MeshMasks *mask_ref,
+ const CustomData_MeshMasks *mask_required)
{
- return (((mask_required->vmask & mask_ref->vmask) == mask_required->vmask) &&
- ((mask_required->emask & mask_ref->emask) == mask_required->emask) &&
- ((mask_required->fmask & mask_ref->fmask) == mask_required->fmask) &&
- ((mask_required->pmask & mask_ref->pmask) == mask_required->pmask) &&
- ((mask_required->lmask & mask_ref->lmask) == mask_required->lmask));
+ return (((mask_required->vmask & mask_ref->vmask) == mask_required->vmask) &&
+ ((mask_required->emask & mask_ref->emask) == mask_required->emask) &&
+ ((mask_required->fmask & mask_ref->fmask) == mask_required->fmask) &&
+ ((mask_required->pmask & mask_ref->pmask) == mask_required->pmask) &&
+ ((mask_required->lmask & mask_ref->lmask) == mask_required->lmask));
}
-
/********************* Layer type information **********************/
typedef struct LayerTypeInfo {
- int size; /* the memory size of one element of this layer's data */
-
- /** name of the struct used, for file writing */
- const char *structname;
- /** number of structs per element, for file writing */
- int structnum;
-
- /**
- * default layer name.
- * note! when NULL this is a way to ensure there is only ever one item
- * see: CustomData_layertype_is_singleton() */
- const char *defaultname;
-
- /**
- * a function to copy count elements of this layer's data
- * (deep copy if appropriate)
- * if NULL, memcpy is used
- */
- cd_copy copy;
-
- /**
- * a function to free any dynamically allocated components of this
- * layer's data (note the data pointer itself should not be freed)
- * size should be the size of one element of this layer's data (e.g.
- * LayerTypeInfo.size)
- */
- void (*free)(void *data, int count, int size);
-
- /**
- * a function to interpolate between count source elements of this
- * layer's data and store the result in dest
- * if weights == NULL or sub_weights == NULL, they should default to 1
- *
- * weights gives the weight for each element in sources
- * sub_weights gives the sub-element weights for each element in sources
- * (there should be (sub element count)^2 weights per element)
- * count gives the number of elements in sources
- *
- * \note in some cases \a dest pointer is in \a sources
- * so all functions have to take this into account and delay
- * applying changes while reading from sources.
- * See bug [#32395] - Campbell.
- */
- cd_interp interp;
-
- /** a function to swap the data in corners of the element */
- void (*swap)(void *data, const int *corner_indices);
-
- /**
- * a function to set a layer's data to default values. if NULL, the
- * default is assumed to be all zeros */
- void (*set_default)(void *data, int count);
-
- /** A function used by mesh validating code, must ensures passed item has valid data. */
- cd_validate validate;
-
- /** functions necessary for geometry collapse */
- bool (*equal)(const void *data1, const void *data2);
- void (*multiply)(void *data, float fac);
- void (*initminmax)(void *min, void *max);
- void (*add)(void *data1, const void *data2);
- void (*dominmax)(const void *data1, void *min, void *max);
- void (*copyvalue)(const void *source, void *dest, const int mixmode, const float mixfactor);
-
- /** a function to read data from a cdf file */
- int (*read)(CDataFile *cdf, void *data, int count);
-
- /** a function to write data to a cdf file */
- int (*write)(CDataFile *cdf, const void *data, int count);
-
- /** a function to determine file size */
- size_t (*filesize)(CDataFile *cdf, const void *data, int count);
-
- /** a function to determine max allowed number of layers, should be NULL or return -1 if no limit */
- int (*layers_max)(void);
+ int size; /* the memory size of one element of this layer's data */
+
+ /** name of the struct used, for file writing */
+ const char *structname;
+ /** number of structs per element, for file writing */
+ int structnum;
+
+ /**
+ * default layer name.
+ * note! when NULL this is a way to ensure there is only ever one item
+ * see: CustomData_layertype_is_singleton() */
+ const char *defaultname;
+
+ /**
+ * a function to copy count elements of this layer's data
+ * (deep copy if appropriate)
+ * if NULL, memcpy is used
+ */
+ cd_copy copy;
+
+ /**
+ * a function to free any dynamically allocated components of this
+ * layer's data (note the data pointer itself should not be freed)
+ * size should be the size of one element of this layer's data (e.g.
+ * LayerTypeInfo.size)
+ */
+ void (*free)(void *data, int count, int size);
+
+ /**
+ * a function to interpolate between count source elements of this
+ * layer's data and store the result in dest
+ * if weights == NULL or sub_weights == NULL, they should default to 1
+ *
+ * weights gives the weight for each element in sources
+ * sub_weights gives the sub-element weights for each element in sources
+ * (there should be (sub element count)^2 weights per element)
+ * count gives the number of elements in sources
+ *
+ * \note in some cases \a dest pointer is in \a sources
+ * so all functions have to take this into account and delay
+ * applying changes while reading from sources.
+ * See bug [#32395] - Campbell.
+ */
+ cd_interp interp;
+
+ /** a function to swap the data in corners of the element */
+ void (*swap)(void *data, const int *corner_indices);
+
+ /**
+ * a function to set a layer's data to default values. if NULL, the
+ * default is assumed to be all zeros */
+ void (*set_default)(void *data, int count);
+
+ /** A function used by mesh validating code, must ensures passed item has valid data. */
+ cd_validate validate;
+
+ /** functions necessary for geometry collapse */
+ bool (*equal)(const void *data1, const void *data2);
+ void (*multiply)(void *data, float fac);
+ void (*initminmax)(void *min, void *max);
+ void (*add)(void *data1, const void *data2);
+ void (*dominmax)(const void *data1, void *min, void *max);
+ void (*copyvalue)(const void *source, void *dest, const int mixmode, const float mixfactor);
+
+ /** a function to read data from a cdf file */
+ int (*read)(CDataFile *cdf, void *data, int count);
+
+ /** a function to write data to a cdf file */
+ int (*write)(CDataFile *cdf, const void *data, int count);
+
+ /** a function to determine file size */
+ size_t (*filesize)(CDataFile *cdf, const void *data, int count);
+
+ /** a function to determine max allowed number of layers, should be NULL or return -1 if no limit */
+ int (*layers_max)(void);
} LayerTypeInfo;
-static void layerCopy_mdeformvert(const void *source, void *dest,
- int count)
+static void layerCopy_mdeformvert(const void *source, void *dest, int count)
{
- int i, size = sizeof(MDeformVert);
+ int i, size = sizeof(MDeformVert);
- memcpy(dest, source, count * size);
+ memcpy(dest, source, count * size);
- for (i = 0; i < count; ++i) {
- MDeformVert *dvert = POINTER_OFFSET(dest, i * size);
+ for (i = 0; i < count; ++i) {
+ MDeformVert *dvert = POINTER_OFFSET(dest, i * size);
- if (dvert->totweight) {
- MDeformWeight *dw = MEM_malloc_arrayN(dvert->totweight, sizeof(*dw),
- "layerCopy_mdeformvert dw");
+ if (dvert->totweight) {
+ MDeformWeight *dw = MEM_malloc_arrayN(
+ dvert->totweight, sizeof(*dw), "layerCopy_mdeformvert dw");
- memcpy(dw, dvert->dw, dvert->totweight * sizeof(*dw));
- dvert->dw = dw;
- }
- else
- dvert->dw = NULL;
- }
+ memcpy(dw, dvert->dw, dvert->totweight * sizeof(*dw));
+ dvert->dw = dw;
+ }
+ else
+ dvert->dw = NULL;
+ }
}
static void layerFree_mdeformvert(void *data, int count, int size)
{
- int i;
+ int i;
- for (i = 0; i < count; ++i) {
- MDeformVert *dvert = POINTER_OFFSET(data, i * size);
+ for (i = 0; i < count; ++i) {
+ MDeformVert *dvert = POINTER_OFFSET(data, i * size);
- if (dvert->dw) {
- MEM_freeN(dvert->dw);
- dvert->dw = NULL;
- dvert->totweight = 0;
- }
- }
+ if (dvert->dw) {
+ MEM_freeN(dvert->dw);
+ dvert->dw = NULL;
+ dvert->totweight = 0;
+ }
+ }
}
/* copy just zeros in this case */
-static void layerCopy_bmesh_elem_py_ptr(const void *UNUSED(source), void *dest,
- int count)
+static void layerCopy_bmesh_elem_py_ptr(const void *UNUSED(source), void *dest, int count)
{
- int i, size = sizeof(void *);
+ int i, size = sizeof(void *);
- for (i = 0; i < count; ++i) {
- void **ptr = POINTER_OFFSET(dest, i * size);
- *ptr = NULL;
- }
+ for (i = 0; i < count; ++i) {
+ void **ptr = POINTER_OFFSET(dest, i * size);
+ *ptr = NULL;
+ }
}
#ifndef WITH_PYTHON
void bpy_bm_generic_invalidate(struct BPy_BMGeneric *UNUSED(self))
{
- /* dummy */
+ /* dummy */
}
#endif
static void layerFree_bmesh_elem_py_ptr(void *data, int count, int size)
{
- int i;
-
- for (i = 0; i < count; ++i) {
- void **ptr = POINTER_OFFSET(data, i * size);
- if (*ptr) {
- bpy_bm_generic_invalidate(*ptr);
- }
- }
-}
-
-static void layerInterp_mdeformvert(
- const void **sources, const float *weights,
- const float *UNUSED(sub_weights), int count, void *dest)
-{
- /* a single linked list of MDeformWeight's
- * use this to avoid double allocs (which LinkNode would do) */
- struct MDeformWeight_Link {
- struct MDeformWeight_Link *next;
- MDeformWeight dw;
- };
-
- MDeformVert *dvert = dest;
- struct MDeformWeight_Link *dest_dwlink = NULL;
- struct MDeformWeight_Link *node;
- int i, j, totweight;
-
- if (count <= 0) return;
-
- /* build a list of unique def_nrs for dest */
- totweight = 0;
- for (i = 0; i < count; ++i) {
- const MDeformVert *source = sources[i];
- float interp_weight = weights ? weights[i] : 1.0f;
-
- for (j = 0; j < source->totweight; ++j) {
- MDeformWeight *dw = &source->dw[j];
- float weight = dw->weight * interp_weight;
-
- if (weight == 0.0f)
- continue;
-
- for (node = dest_dwlink; node; node = node->next) {
- MDeformWeight *tmp_dw = &node->dw;
-
- if (tmp_dw->def_nr == dw->def_nr) {
- tmp_dw->weight += weight;
- break;
- }
- }
-
- /* if this def_nr is not in the list, add it */
- if (!node) {
- struct MDeformWeight_Link *tmp_dwlink = alloca(sizeof(*tmp_dwlink));
- tmp_dwlink->dw.def_nr = dw->def_nr;
- tmp_dwlink->dw.weight = weight;
-
- /* inline linklist */
- tmp_dwlink->next = dest_dwlink;
- dest_dwlink = tmp_dwlink;
-
- totweight++;
- }
- }
- }
-
- /* delay writing to the destination incase dest is in sources */
-
- /* now we know how many unique deform weights there are, so realloc */
- if (dvert->dw && (dvert->totweight == totweight)) {
- /* pass (fastpath if we don't need to realloc) */
- }
- else {
- if (dvert->dw) {
- MEM_freeN(dvert->dw);
- }
-
- if (totweight) {
- dvert->dw = MEM_malloc_arrayN(totweight, sizeof(*dvert->dw), __func__);
- }
- }
-
- if (totweight) {
- dvert->totweight = totweight;
- for (i = 0, node = dest_dwlink; node; node = node->next, i++) {
- dvert->dw[i] = node->dw;
- }
- }
- else {
- memset(dvert, 0, sizeof(*dvert));
- }
-}
-
-static void layerInterp_normal(
- const void **sources, const float *weights,
- const float *UNUSED(sub_weights), int count, void *dest)
-{
- /* Note: This is linear interpolation, which is not optimal for vectors.
- * Unfortunately, spherical interpolation of more than two values is hairy, so for now it will do... */
- float no[3] = {0.0f};
-
- while (count--) {
- madd_v3_v3fl(no, (const float *)sources[count], weights[count]);
- }
-
- /* Weighted sum of normalized vectors will **not** be normalized, even if weights are. */
- normalize_v3_v3((float *)dest, no);
+ int i;
+
+ for (i = 0; i < count; ++i) {
+ void **ptr = POINTER_OFFSET(data, i * size);
+ if (*ptr) {
+ bpy_bm_generic_invalidate(*ptr);
+ }
+ }
+}
+
+static void layerInterp_mdeformvert(const void **sources,
+ const float *weights,
+ const float *UNUSED(sub_weights),
+ int count,
+ void *dest)
+{
+ /* a single linked list of MDeformWeight's
+ * use this to avoid double allocs (which LinkNode would do) */
+ struct MDeformWeight_Link {
+ struct MDeformWeight_Link *next;
+ MDeformWeight dw;
+ };
+
+ MDeformVert *dvert = dest;
+ struct MDeformWeight_Link *dest_dwlink = NULL;
+ struct MDeformWeight_Link *node;
+ int i, j, totweight;
+
+ if (count <= 0)
+ return;
+
+ /* build a list of unique def_nrs for dest */
+ totweight = 0;
+ for (i = 0; i < count; ++i) {
+ const MDeformVert *source = sources[i];
+ float interp_weight = weights ? weights[i] : 1.0f;
+
+ for (j = 0; j < source->totweight; ++j) {
+ MDeformWeight *dw = &source->dw[j];
+ float weight = dw->weight * interp_weight;
+
+ if (weight == 0.0f)
+ continue;
+
+ for (node = dest_dwlink; node; node = node->next) {
+ MDeformWeight *tmp_dw = &node->dw;
+
+ if (tmp_dw->def_nr == dw->def_nr) {
+ tmp_dw->weight += weight;
+ break;
+ }
+ }
+
+ /* if this def_nr is not in the list, add it */
+ if (!node) {
+ struct MDeformWeight_Link *tmp_dwlink = alloca(sizeof(*tmp_dwlink));
+ tmp_dwlink->dw.def_nr = dw->def_nr;
+ tmp_dwlink->dw.weight = weight;
+
+ /* inline linklist */
+ tmp_dwlink->next = dest_dwlink;
+ dest_dwlink = tmp_dwlink;
+
+ totweight++;
+ }
+ }
+ }
+
+ /* delay writing to the destination incase dest is in sources */
+
+ /* now we know how many unique deform weights there are, so realloc */
+ if (dvert->dw && (dvert->totweight == totweight)) {
+ /* pass (fastpath if we don't need to realloc) */
+ }
+ else {
+ if (dvert->dw) {
+ MEM_freeN(dvert->dw);
+ }
+
+ if (totweight) {
+ dvert->dw = MEM_malloc_arrayN(totweight, sizeof(*dvert->dw), __func__);
+ }
+ }
+
+ if (totweight) {
+ dvert->totweight = totweight;
+ for (i = 0, node = dest_dwlink; node; node = node->next, i++) {
+ dvert->dw[i] = node->dw;
+ }
+ }
+ else {
+ memset(dvert, 0, sizeof(*dvert));
+ }
+}
+
+static void layerInterp_normal(const void **sources,
+ const float *weights,
+ const float *UNUSED(sub_weights),
+ int count,
+ void *dest)
+{
+ /* Note: This is linear interpolation, which is not optimal for vectors.
+ * Unfortunately, spherical interpolation of more than two values is hairy, so for now it will do... */
+ float no[3] = {0.0f};
+
+ while (count--) {
+ madd_v3_v3fl(no, (const float *)sources[count], weights[count]);
+ }
+
+ /* Weighted sum of normalized vectors will **not** be normalized, even if weights are. */
+ normalize_v3_v3((float *)dest, no);
}
static bool layerValidate_normal(void *data, const uint totitems, const bool do_fixes)
{
- static const float no_default[3] = {0.0f, 0.0f, 1.0f}; /* Z-up default normal... */
- float (*no)[3] = data;
- bool has_errors = false;
-
- for (int i = 0; i < totitems; i++, no++) {
- if (!is_finite_v3((float *)no)) {
- has_errors = true;
- if (do_fixes) {
- copy_v3_v3((float *)no, no_default);
- }
- }
- else if (!compare_ff(len_squared_v3((float *)no), 1.0f, 1e-6f)) {
- has_errors = true;
- if (do_fixes) {
- normalize_v3((float *)no);
- }
- }
- }
-
- return has_errors;
-}
-
-static void layerCopyValue_normal(const void *source, void *dest, const int mixmode, const float mixfactor)
-{
- const float *no_src = source;
- float *no_dst = dest;
- float no_tmp[3];
-
- if (ELEM(mixmode, CDT_MIX_NOMIX, CDT_MIX_REPLACE_ABOVE_THRESHOLD, CDT_MIX_REPLACE_BELOW_THRESHOLD)) {
- /* Above/below threshold modes are not supported here, fallback to nomix (just in case). */
- copy_v3_v3(no_dst, no_src);
- }
- else { /* Modes that support 'real' mix factor. */
- /* Since we normalize in the end, MIX and ADD are the same op here. */
- if (ELEM(mixmode, CDT_MIX_MIX, CDT_MIX_ADD)) {
- add_v3_v3v3(no_tmp, no_dst, no_src);
- normalize_v3(no_tmp);
- }
- else if (mixmode == CDT_MIX_SUB) {
- sub_v3_v3v3(no_tmp, no_dst, no_src);
- normalize_v3(no_tmp);
- }
- else if (mixmode == CDT_MIX_MUL) {
- mul_v3_v3v3(no_tmp, no_dst, no_src);
- normalize_v3(no_tmp);
- }
- else {
- copy_v3_v3(no_tmp, no_src);
- }
- interp_v3_v3v3_slerp_safe(no_dst, no_dst, no_tmp, mixfactor);
- }
+ static const float no_default[3] = {0.0f, 0.0f, 1.0f}; /* Z-up default normal... */
+ float(*no)[3] = data;
+ bool has_errors = false;
+
+ for (int i = 0; i < totitems; i++, no++) {
+ if (!is_finite_v3((float *)no)) {
+ has_errors = true;
+ if (do_fixes) {
+ copy_v3_v3((float *)no, no_default);
+ }
+ }
+ else if (!compare_ff(len_squared_v3((float *)no), 1.0f, 1e-6f)) {
+ has_errors = true;
+ if (do_fixes) {
+ normalize_v3((float *)no);
+ }
+ }
+ }
+
+ return has_errors;
+}
+
+static void layerCopyValue_normal(const void *source,
+ void *dest,
+ const int mixmode,
+ const float mixfactor)
+{
+ const float *no_src = source;
+ float *no_dst = dest;
+ float no_tmp[3];
+
+ if (ELEM(mixmode,
+ CDT_MIX_NOMIX,
+ CDT_MIX_REPLACE_ABOVE_THRESHOLD,
+ CDT_MIX_REPLACE_BELOW_THRESHOLD)) {
+ /* Above/below threshold modes are not supported here, fallback to nomix (just in case). */
+ copy_v3_v3(no_dst, no_src);
+ }
+ else { /* Modes that support 'real' mix factor. */
+ /* Since we normalize in the end, MIX and ADD are the same op here. */
+ if (ELEM(mixmode, CDT_MIX_MIX, CDT_MIX_ADD)) {
+ add_v3_v3v3(no_tmp, no_dst, no_src);
+ normalize_v3(no_tmp);
+ }
+ else if (mixmode == CDT_MIX_SUB) {
+ sub_v3_v3v3(no_tmp, no_dst, no_src);
+ normalize_v3(no_tmp);
+ }
+ else if (mixmode == CDT_MIX_MUL) {
+ mul_v3_v3v3(no_tmp, no_dst, no_src);
+ normalize_v3(no_tmp);
+ }
+ else {
+ copy_v3_v3(no_tmp, no_src);
+ }
+ interp_v3_v3v3_slerp_safe(no_dst, no_dst, no_tmp, mixfactor);
+ }
}
static void layerCopy_tface(const void *source, void *dest, int count)
{
- const MTFace *source_tf = (const MTFace *)source;
- MTFace *dest_tf = (MTFace *)dest;
- int i;
+ const MTFace *source_tf = (const MTFace *)source;
+ MTFace *dest_tf = (MTFace *)dest;
+ int i;
- for (i = 0; i < count; ++i)
- dest_tf[i] = source_tf[i];
+ for (i = 0; i < count; ++i)
+ dest_tf[i] = source_tf[i];
}
static void layerInterp_tface(
- const void **sources, const float *weights,
- const float *sub_weights, int count, void *dest)
-{
- MTFace *tf = dest;
- int i, j, k;
- float uv[4][2] = {{0.0f}};
- const float *sub_weight;
-
- if (count <= 0) return;
-
- sub_weight = sub_weights;
- for (i = 0; i < count; ++i) {
- float weight = weights ? weights[i] : 1;
- const MTFace *src = sources[i];
-
- for (j = 0; j < 4; ++j) {
- if (sub_weights) {
- for (k = 0; k < 4; ++k, ++sub_weight) {
- madd_v2_v2fl(uv[j], src->uv[k], (*sub_weight) * weight);
- }
- }
- else {
- madd_v2_v2fl(uv[j], src->uv[j], weight);
- }
- }
- }
-
- /* delay writing to the destination incase dest is in sources */
- *tf = *(MTFace *)(*sources);
- memcpy(tf->uv, uv, sizeof(tf->uv));
+ const void **sources, const float *weights, const float *sub_weights, int count, void *dest)
+{
+ MTFace *tf = dest;
+ int i, j, k;
+ float uv[4][2] = {{0.0f}};
+ const float *sub_weight;
+
+ if (count <= 0)
+ return;
+
+ sub_weight = sub_weights;
+ for (i = 0; i < count; ++i) {
+ float weight = weights ? weights[i] : 1;
+ const MTFace *src = sources[i];
+
+ for (j = 0; j < 4; ++j) {
+ if (sub_weights) {
+ for (k = 0; k < 4; ++k, ++sub_weight) {
+ madd_v2_v2fl(uv[j], src->uv[k], (*sub_weight) * weight);
+ }
+ }
+ else {
+ madd_v2_v2fl(uv[j], src->uv[j], weight);
+ }
+ }
+ }
+
+ /* delay writing to the destination incase dest is in sources */
+ *tf = *(MTFace *)(*sources);
+ memcpy(tf->uv, uv, sizeof(tf->uv));
}
static void layerSwap_tface(void *data, const int *corner_indices)
{
- MTFace *tf = data;
- float uv[4][2];
- int j;
+ MTFace *tf = data;
+ float uv[4][2];
+ int j;
- for (j = 0; j < 4; ++j) {
- const int source_index = corner_indices[j];
- copy_v2_v2(uv[j], tf->uv[source_index]);
- }
+ for (j = 0; j < 4; ++j) {
+ const int source_index = corner_indices[j];
+ copy_v2_v2(uv[j], tf->uv[source_index]);
+ }
- memcpy(tf->uv, uv, sizeof(tf->uv));
+ memcpy(tf->uv, uv, sizeof(tf->uv));
}
static void layerDefault_tface(void *data, int count)
{
- static MTFace default_tf = {{{0, 0}, {1, 0}, {1, 1}, {0, 1}}};
- MTFace *tf = (MTFace *)data;
- int i;
+ static MTFace default_tf = {{{0, 0}, {1, 0}, {1, 1}, {0, 1}}};
+ MTFace *tf = (MTFace *)data;
+ int i;
- for (i = 0; i < count; i++)
- tf[i] = default_tf;
+ for (i = 0; i < count; i++)
+ tf[i] = default_tf;
}
static int layerMaxNum_tface(void)
{
- return MAX_MTFACE;
+ return MAX_MTFACE;
}
-static void layerCopy_propFloat(const void *source, void *dest,
- int count)
+static void layerCopy_propFloat(const void *source, void *dest, int count)
{
- memcpy(dest, source, sizeof(MFloatProperty) * count);
+ memcpy(dest, source, sizeof(MFloatProperty) * count);
}
static bool layerValidate_propFloat(void *data, const uint totitems, const bool do_fixes)
{
- MFloatProperty *fp = data;
- bool has_errors = false;
+ MFloatProperty *fp = data;
+ bool has_errors = false;
- for (int i = 0; i < totitems; i++, fp++) {
- if (!isfinite(fp->f)) {
- if (do_fixes) {
- fp->f = 0.0f;
- }
- has_errors = true;
- }
- }
+ for (int i = 0; i < totitems; i++, fp++) {
+ if (!isfinite(fp->f)) {
+ if (do_fixes) {
+ fp->f = 0.0f;
+ }
+ has_errors = true;
+ }
+ }
- return has_errors;
+ return has_errors;
}
-static void layerCopy_propInt(const void *source, void *dest,
- int count)
+static void layerCopy_propInt(const void *source, void *dest, int count)
{
- memcpy(dest, source, sizeof(MIntProperty) * count);
+ memcpy(dest, source, sizeof(MIntProperty) * count);
}
-static void layerCopy_propString(const void *source, void *dest,
- int count)
+static void layerCopy_propString(const void *source, void *dest, int count)
{
- memcpy(dest, source, sizeof(MStringProperty) * count);
+ memcpy(dest, source, sizeof(MStringProperty) * count);
}
static void layerCopy_origspace_face(const void *source, void *dest, int count)
{
- const OrigSpaceFace *source_tf = (const OrigSpaceFace *)source;
- OrigSpaceFace *dest_tf = (OrigSpaceFace *)dest;
- int i;
+ const OrigSpaceFace *source_tf = (const OrigSpaceFace *)source;
+ OrigSpaceFace *dest_tf = (OrigSpaceFace *)dest;
+ int i;
- for (i = 0; i < count; ++i)
- dest_tf[i] = source_tf[i];
+ for (i = 0; i < count; ++i)
+ dest_tf[i] = source_tf[i];
}
static void layerInterp_origspace_face(
- const void **sources, const float *weights,
- const float *sub_weights, int count, void *dest)
+ const void **sources, const float *weights, const float *sub_weights, int count, void *dest)
{
- OrigSpaceFace *osf = dest;
- int i, j, k;
- float uv[4][2] = {{0.0f}};
- const float *sub_weight;
+ OrigSpaceFace *osf = dest;
+ int i, j, k;
+ float uv[4][2] = {{0.0f}};
+ const float *sub_weight;
- if (count <= 0) return;
+ if (count <= 0)
+ return;
- sub_weight = sub_weights;
- for (i = 0; i < count; ++i) {
- float weight = weights ? weights[i] : 1;
- const OrigSpaceFace *src = sources[i];
+ sub_weight = sub_weights;
+ for (i = 0; i < count; ++i) {
+ float weight = weights ? weights[i] : 1;
+ const OrigSpaceFace *src = sources[i];
- for (j = 0; j < 4; ++j) {
- if (sub_weights) {
- for (k = 0; k < 4; ++k, ++sub_weight) {
- madd_v2_v2fl(uv[j], src->uv[k], (*sub_weight) * weight);
- }
- }
- else {
- madd_v2_v2fl(uv[j], src->uv[j], weight);
- }
- }
- }
+ for (j = 0; j < 4; ++j) {
+ if (sub_weights) {
+ for (k = 0; k < 4; ++k, ++sub_weight) {
+ madd_v2_v2fl(uv[j], src->uv[k], (*sub_weight) * weight);
+ }
+ }
+ else {
+ madd_v2_v2fl(uv[j], src->uv[j], weight);
+ }
+ }
+ }
- /* delay writing to the destination in case dest is in sources */
- memcpy(osf->uv, uv, sizeof(osf->uv));
+ /* delay writing to the destination in case dest is in sources */
+ memcpy(osf->uv, uv, sizeof(osf->uv));
}
static void layerSwap_origspace_face(void *data, const int *corner_indices)
{
- OrigSpaceFace *osf = data;
- float uv[4][2];
- int j;
+ OrigSpaceFace *osf = data;
+ float uv[4][2];
+ int j;
- for (j = 0; j < 4; ++j) {
- copy_v2_v2(uv[j], osf->uv[corner_indices[j]]);
- }
- memcpy(osf->uv, uv, sizeof(osf->uv));
+ for (j = 0; j < 4; ++j) {
+ copy_v2_v2(uv[j], osf->uv[corner_indices[j]]);
+ }
+ memcpy(osf->uv, uv, sizeof(osf->uv));
}
static void layerDefault_origspace_face(void *data, int count)
{
- static OrigSpaceFace default_osf = {{{0, 0}, {1, 0}, {1, 1}, {0, 1}}};
- OrigSpaceFace *osf = (OrigSpaceFace *)data;
- int i;
+ static OrigSpaceFace default_osf = {{{0, 0}, {1, 0}, {1, 1}, {0, 1}}};
+ OrigSpaceFace *osf = (OrigSpaceFace *)data;
+ int i;
- for (i = 0; i < count; i++)
- osf[i] = default_osf;
+ for (i = 0; i < count; i++)
+ osf[i] = default_osf;
}
static void layerSwap_mdisps(void *data, const int *ci)
{
- MDisps *s = data;
- float (*d)[3] = NULL;
- int corners, cornersize, S;
+ MDisps *s = data;
+ float(*d)[3] = NULL;
+ int corners, cornersize, S;
- if (s->disps) {
- int nverts = (ci[1] == 3) ? 4 : 3; /* silly way to know vertex count of face */
- corners = multires_mdisp_corners(s);
- cornersize = s->totdisp / corners;
+ if (s->disps) {
+ int nverts = (ci[1] == 3) ? 4 : 3; /* silly way to know vertex count of face */
+ corners = multires_mdisp_corners(s);
+ cornersize = s->totdisp / corners;
- if (corners != nverts) {
- /* happens when face changed vertex count in edit mode
- * if it happened, just forgot displacement */
+ if (corners != nverts) {
+ /* happens when face changed vertex count in edit mode
+ * if it happened, just forgot displacement */
- MEM_freeN(s->disps);
- s->totdisp = (s->totdisp / corners) * nverts;
- s->disps = MEM_calloc_arrayN(s->totdisp, sizeof(float) * 3, "mdisp swap");
- return;
- }
+ MEM_freeN(s->disps);
+ s->totdisp = (s->totdisp / corners) * nverts;
+ s->disps = MEM_calloc_arrayN(s->totdisp, sizeof(float) * 3, "mdisp swap");
+ return;
+ }
- d = MEM_calloc_arrayN(s->totdisp, 3 * sizeof(float), "mdisps swap");
+ d = MEM_calloc_arrayN(s->totdisp, 3 * sizeof(float), "mdisps swap");
- for (S = 0; S < corners; S++)
- memcpy(d + cornersize * S, s->disps + cornersize * ci[S], cornersize * 3 * sizeof(float));
+ for (S = 0; S < corners; S++)
+ memcpy(d + cornersize * S, s->disps + cornersize * ci[S], cornersize * 3 * sizeof(float));
- MEM_freeN(s->disps);
- s->disps = d;
- }
+ MEM_freeN(s->disps);
+ s->disps = d;
+ }
}
static void layerCopy_mdisps(const void *source, void *dest, int count)
{
- int i;
- const MDisps *s = source;
- MDisps *d = dest;
+ int i;
+ const MDisps *s = source;
+ MDisps *d = dest;
- for (i = 0; i < count; ++i) {
- if (s[i].disps) {
- d[i].disps = MEM_dupallocN(s[i].disps);
- d[i].hidden = MEM_dupallocN(s[i].hidden);
- }
- else {
- d[i].disps = NULL;
- d[i].hidden = NULL;
- }
+ for (i = 0; i < count; ++i) {
+ if (s[i].disps) {
+ d[i].disps = MEM_dupallocN(s[i].disps);
+ d[i].hidden = MEM_dupallocN(s[i].hidden);
+ }
+ else {
+ d[i].disps = NULL;
+ d[i].hidden = NULL;
+ }
- /* still copy even if not in memory, displacement can be external */
- d[i].totdisp = s[i].totdisp;
- d[i].level = s[i].level;
- }
+ /* still copy even if not in memory, displacement can be external */
+ d[i].totdisp = s[i].totdisp;
+ d[i].level = s[i].level;
+ }
}
static void layerFree_mdisps(void *data, int count, int UNUSED(size))
{
- int i;
- MDisps *d = data;
+ int i;
+ MDisps *d = data;
- for (i = 0; i < count; ++i) {
- if (d[i].disps)
- MEM_freeN(d[i].disps);
- if (d[i].hidden)
- MEM_freeN(d[i].hidden);
- d[i].disps = NULL;
- d[i].hidden = NULL;
- d[i].totdisp = 0;
- d[i].level = 0;
- }
+ for (i = 0; i < count; ++i) {
+ if (d[i].disps)
+ MEM_freeN(d[i].disps);
+ if (d[i].hidden)
+ MEM_freeN(d[i].hidden);
+ d[i].disps = NULL;
+ d[i].hidden = NULL;
+ d[i].totdisp = 0;
+ d[i].level = 0;
+ }
}
static int layerRead_mdisps(CDataFile *cdf, void *data, int count)
{
- MDisps *d = data;
- int i;
+ MDisps *d = data;
+ int i;
- for (i = 0; i < count; ++i) {
- if (!d[i].disps)
- d[i].disps = MEM_calloc_arrayN(d[i].totdisp, 3 * sizeof(float), "mdisps read");
+ for (i = 0; i < count; ++i) {
+ if (!d[i].disps)
+ d[i].disps = MEM_calloc_arrayN(d[i].totdisp, 3 * sizeof(float), "mdisps read");
- if (!cdf_read_data(cdf, d[i].totdisp * 3 * sizeof(float), d[i].disps)) {
- CLOG_ERROR(&LOG, "failed to read multires displacement %d/%d %d", i, count, d[i].totdisp);
- return 0;
- }
- }
+ if (!cdf_read_data(cdf, d[i].totdisp * 3 * sizeof(float), d[i].disps)) {
+ CLOG_ERROR(&LOG, "failed to read multires displacement %d/%d %d", i, count, d[i].totdisp);
+ return 0;
+ }
+ }
- return 1;
+ return 1;
}
static int layerWrite_mdisps(CDataFile *cdf, const void *data, int count)
{
- const MDisps *d = data;
- int i;
+ const MDisps *d = data;
+ int i;
- for (i = 0; i < count; ++i) {
- if (!cdf_write_data(cdf, d[i].totdisp * 3 * sizeof(float), d[i].disps)) {
- CLOG_ERROR(&LOG, "failed to write multires displacement %d/%d %d", i, count, d[i].totdisp);
- return 0;
- }
- }
+ for (i = 0; i < count; ++i) {
+ if (!cdf_write_data(cdf, d[i].totdisp * 3 * sizeof(float), d[i].disps)) {
+ CLOG_ERROR(&LOG, "failed to write multires displacement %d/%d %d", i, count, d[i].totdisp);
+ return 0;
+ }
+ }
- return 1;
+ return 1;
}
static size_t layerFilesize_mdisps(CDataFile *UNUSED(cdf), const void *data, int count)
{
- const MDisps *d = data;
- size_t size = 0;
- int i;
+ const MDisps *d = data;
+ size_t size = 0;
+ int i;
- for (i = 0; i < count; ++i)
- size += d[i].totdisp * 3 * sizeof(float);
+ for (i = 0; i < count; ++i)
+ size += d[i].totdisp * 3 * sizeof(float);
- return size;
+ return size;
}
static void layerCopy_grid_paint_mask(const void *source, void *dest, int count)
{
- int i;
- const GridPaintMask *s = source;
- GridPaintMask *d = dest;
+ int i;
+ const GridPaintMask *s = source;
+ GridPaintMask *d = dest;
- for (i = 0; i < count; ++i) {
- if (s[i].data) {
- d[i].data = MEM_dupallocN(s[i].data);
- d[i].level = s[i].level;
- }
- else {
- d[i].data = NULL;
- d[i].level = 0;
- }
-
- }
+ for (i = 0; i < count; ++i) {
+ if (s[i].data) {
+ d[i].data = MEM_dupallocN(s[i].data);
+ d[i].level = s[i].level;
+ }
+ else {
+ d[i].data = NULL;
+ d[i].level = 0;
+ }
+ }
}
static void layerFree_grid_paint_mask(void *data, int count, int UNUSED(size))
{
- int i;
- GridPaintMask *gpm = data;
+ int i;
+ GridPaintMask *gpm = data;
- for (i = 0; i < count; ++i) {
- if (gpm[i].data)
- MEM_freeN(gpm[i].data);
- gpm[i].data = NULL;
- gpm[i].level = 0;
- }
+ for (i = 0; i < count; ++i) {
+ if (gpm[i].data)
+ MEM_freeN(gpm[i].data);
+ gpm[i].data = NULL;
+ gpm[i].level = 0;
+ }
}
/* --------- */
-static void layerCopyValue_mloopcol(const void *source, void *dest, const int mixmode, const float mixfactor)
-{
- const MLoopCol *m1 = source;
- MLoopCol *m2 = dest;
- unsigned char tmp_col[4];
-
- if (ELEM(mixmode, CDT_MIX_NOMIX, CDT_MIX_REPLACE_ABOVE_THRESHOLD, CDT_MIX_REPLACE_BELOW_THRESHOLD)) {
- /* Modes that do a full copy or nothing. */
- if (ELEM(mixmode, CDT_MIX_REPLACE_ABOVE_THRESHOLD, CDT_MIX_REPLACE_BELOW_THRESHOLD)) {
- /* TODO: Check for a real valid way to get 'factor' value of our dest color? */
- const float f = ((float)m2->r + (float)m2->g + (float)m2->b) / 3.0f;
- if (mixmode == CDT_MIX_REPLACE_ABOVE_THRESHOLD && f < mixfactor) {
- return; /* Do Nothing! */
- }
- else if (mixmode == CDT_MIX_REPLACE_BELOW_THRESHOLD && f > mixfactor) {
- return; /* Do Nothing! */
- }
- }
- m2->r = m1->r;
- m2->g = m1->g;
- m2->b = m1->b;
- }
- else { /* Modes that support 'real' mix factor. */
- unsigned char src[4] = {m1->r, m1->g, m1->b, m1->a};
- unsigned char dst[4] = {m2->r, m2->g, m2->b, m2->a};
-
- if (mixmode == CDT_MIX_MIX) {
- blend_color_mix_byte(tmp_col, dst, src);
- }
- else if (mixmode == CDT_MIX_ADD) {
- blend_color_add_byte(tmp_col, dst, src);
- }
- else if (mixmode == CDT_MIX_SUB) {
- blend_color_sub_byte(tmp_col, dst, src);
- }
- else if (mixmode == CDT_MIX_MUL) {
- blend_color_mul_byte(tmp_col, dst, src);
- }
- else {
- memcpy(tmp_col, src, sizeof(tmp_col));
- }
- blend_color_interpolate_byte(dst, dst, tmp_col, mixfactor);
-
- m2->r = (char)dst[0];
- m2->g = (char)dst[1];
- m2->b = (char)dst[2];
- }
- m2->a = m1->a;
+static void layerCopyValue_mloopcol(const void *source,
+ void *dest,
+ const int mixmode,
+ const float mixfactor)
+{
+ const MLoopCol *m1 = source;
+ MLoopCol *m2 = dest;
+ unsigned char tmp_col[4];
+
+ if (ELEM(mixmode,
+ CDT_MIX_NOMIX,
+ CDT_MIX_REPLACE_ABOVE_THRESHOLD,
+ CDT_MIX_REPLACE_BELOW_THRESHOLD)) {
+ /* Modes that do a full copy or nothing. */
+ if (ELEM(mixmode, CDT_MIX_REPLACE_ABOVE_THRESHOLD, CDT_MIX_REPLACE_BELOW_THRESHOLD)) {
+ /* TODO: Check for a real valid way to get 'factor' value of our dest color? */
+ const float f = ((float)m2->r + (float)m2->g + (float)m2->b) / 3.0f;
+ if (mixmode == CDT_MIX_REPLACE_ABOVE_THRESHOLD && f < mixfactor) {
+ return; /* Do Nothing! */
+ }
+ else if (mixmode == CDT_MIX_REPLACE_BELOW_THRESHOLD && f > mixfactor) {
+ return; /* Do Nothing! */
+ }
+ }
+ m2->r = m1->r;
+ m2->g = m1->g;
+ m2->b = m1->b;
+ }
+ else { /* Modes that support 'real' mix factor. */
+ unsigned char src[4] = {m1->r, m1->g, m1->b, m1->a};
+ unsigned char dst[4] = {m2->r, m2->g, m2->b, m2->a};
+
+ if (mixmode == CDT_MIX_MIX) {
+ blend_color_mix_byte(tmp_col, dst, src);
+ }
+ else if (mixmode == CDT_MIX_ADD) {
+ blend_color_add_byte(tmp_col, dst, src);
+ }
+ else if (mixmode == CDT_MIX_SUB) {
+ blend_color_sub_byte(tmp_col, dst, src);
+ }
+ else if (mixmode == CDT_MIX_MUL) {
+ blend_color_mul_byte(tmp_col, dst, src);
+ }
+ else {
+ memcpy(tmp_col, src, sizeof(tmp_col));
+ }
+ blend_color_interpolate_byte(dst, dst, tmp_col, mixfactor);
+
+ m2->r = (char)dst[0];
+ m2->g = (char)dst[1];
+ m2->b = (char)dst[2];
+ }
+ m2->a = m1->a;
}
static bool layerEqual_mloopcol(const void *data1, const void *data2)
{
- const MLoopCol *m1 = data1, *m2 = data2;
- float r, g, b, a;
+ const MLoopCol *m1 = data1, *m2 = data2;
+ float r, g, b, a;
- r = m1->r - m2->r;
- g = m1->g - m2->g;
- b = m1->b - m2->b;
- a = m1->a - m2->a;
+ r = m1->r - m2->r;
+ g = m1->g - m2->g;
+ b = m1->b - m2->b;
+ a = m1->a - m2->a;
- return r * r + g * g + b * b + a * a < 0.001f;
+ return r * r + g * g + b * b + a * a < 0.001f;
}
static void layerMultiply_mloopcol(void *data, float fac)
{
- MLoopCol *m = data;
+ MLoopCol *m = data;
- m->r = (float)m->r * fac;
- m->g = (float)m->g * fac;
- m->b = (float)m->b * fac;
- m->a = (float)m->a * fac;
+ m->r = (float)m->r * fac;
+ m->g = (float)m->g * fac;
+ m->b = (float)m->b * fac;
+ m->a = (float)m->a * fac;
}
static void layerAdd_mloopcol(void *data1, const void *data2)
{
- MLoopCol *m = data1;
- const MLoopCol *m2 = data2;
+ MLoopCol *m = data1;
+ const MLoopCol *m2 = data2;
- m->r += m2->r;
- m->g += m2->g;
- m->b += m2->b;
- m->a += m2->a;
+ m->r += m2->r;
+ m->g += m2->g;
+ m->b += m2->b;
+ m->a += m2->a;
}
static void layerDoMinMax_mloopcol(const void *data, void *vmin, void *vmax)
{
- const MLoopCol *m = data;
- MLoopCol *min = vmin, *max = vmax;
+ const MLoopCol *m = data;
+ MLoopCol *min = vmin, *max = vmax;
- if (m->r < min->r) min->r = m->r;
- if (m->g < min->g) min->g = m->g;
- if (m->b < min->b) min->b = m->b;
- if (m->a < min->a) min->a = m->a;
+ if (m->r < min->r)
+ min->r = m->r;
+ if (m->g < min->g)
+ min->g = m->g;
+ if (m->b < min->b)
+ min->b = m->b;
+ if (m->a < min->a)
+ min->a = m->a;
- if (m->r > max->r) max->r = m->r;
- if (m->g > max->g) max->g = m->g;
- if (m->b > max->b) max->b = m->b;
- if (m->a > max->a) max->a = m->a;
+ if (m->r > max->r)
+ max->r = m->r;
+ if (m->g > max->g)
+ max->g = m->g;
+ if (m->b > max->b)
+ max->b = m->b;
+ if (m->a > max->a)
+ max->a = m->a;
}
static void layerInitMinMax_mloopcol(void *vmin, void *vmax)
{
- MLoopCol *min = vmin, *max = vmax;
+ MLoopCol *min = vmin, *max = vmax;
- min->r = 255;
- min->g = 255;
- min->b = 255;
- min->a = 255;
+ min->r = 255;
+ min->g = 255;
+ min->b = 255;
+ min->a = 255;
- max->r = 0;
- max->g = 0;
- max->b = 0;
- max->a = 0;
+ max->r = 0;
+ max->g = 0;
+ max->b = 0;
+ max->a = 0;
}
static void layerDefault_mloopcol(void *data, int count)
{
- MLoopCol default_mloopcol = {255, 255, 255, 255};
- MLoopCol *mlcol = (MLoopCol *)data;
- int i;
- for (i = 0; i < count; i++)
- mlcol[i] = default_mloopcol;
-
+ MLoopCol default_mloopcol = {255, 255, 255, 255};
+ MLoopCol *mlcol = (MLoopCol *)data;
+ int i;
+ for (i = 0; i < count; i++)
+ mlcol[i] = default_mloopcol;
}
static void layerInterp_mloopcol(
- const void **sources, const float *weights,
- const float *sub_weights, int count, void *dest)
-{
- MLoopCol *mc = dest;
- struct {
- float a;
- float r;
- float g;
- float b;
- } col = {0};
-
- const float *sub_weight = sub_weights;
- for (int i = 0; i < count; ++i) {
- float weight = weights ? weights[i] : 1;
- const MLoopCol *src = sources[i];
- if (sub_weights) {
- col.r += src->r * (*sub_weight) * weight;
- col.g += src->g * (*sub_weight) * weight;
- col.b += src->b * (*sub_weight) * weight;
- col.a += src->a * (*sub_weight) * weight;
- sub_weight++;
- }
- else {
- col.r += src->r * weight;
- col.g += src->g * weight;
- col.b += src->b * weight;
- col.a += src->a * weight;
- }
- }
-
-
- /* Subdivide smooth or fractal can cause problems without clamping
- * although weights should also not cause this situation */
-
- /* also delay writing to the destination incase dest is in sources */
- mc->r = round_fl_to_uchar_clamp(col.r);
- mc->g = round_fl_to_uchar_clamp(col.g);
- mc->b = round_fl_to_uchar_clamp(col.b);
- mc->a = round_fl_to_uchar_clamp(col.a);
+ const void **sources, const float *weights, const float *sub_weights, int count, void *dest)
+{
+ MLoopCol *mc = dest;
+ struct {
+ float a;
+ float r;
+ float g;
+ float b;
+ } col = {0};
+
+ const float *sub_weight = sub_weights;
+ for (int i = 0; i < count; ++i) {
+ float weight = weights ? weights[i] : 1;
+ const MLoopCol *src = sources[i];
+ if (sub_weights) {
+ col.r += src->r * (*sub_weight) * weight;
+ col.g += src->g * (*sub_weight) * weight;
+ col.b += src->b * (*sub_weight) * weight;
+ col.a += src->a * (*sub_weight) * weight;
+ sub_weight++;
+ }
+ else {
+ col.r += src->r * weight;
+ col.g += src->g * weight;
+ col.b += src->b * weight;
+ col.a += src->a * weight;
+ }
+ }
+
+ /* Subdivide smooth or fractal can cause problems without clamping
+ * although weights should also not cause this situation */
+
+ /* also delay writing to the destination incase dest is in sources */
+ mc->r = round_fl_to_uchar_clamp(col.r);
+ mc->g = round_fl_to_uchar_clamp(col.g);
+ mc->b = round_fl_to_uchar_clamp(col.b);
+ mc->a = round_fl_to_uchar_clamp(col.a);
}
static int layerMaxNum_mloopcol(void)
{
- return MAX_MCOL;
+ return MAX_MCOL;
}
-static void layerCopyValue_mloopuv(const void *source, void *dest, const int mixmode, const float mixfactor)
+static void layerCopyValue_mloopuv(const void *source,
+ void *dest,
+ const int mixmode,
+ const float mixfactor)
{
- const MLoopUV *luv1 = source;
- MLoopUV *luv2 = dest;
+ const MLoopUV *luv1 = source;
+ MLoopUV *luv2 = dest;
- /* We only support a limited subset of advanced mixing here - namely the mixfactor interpolation. */
+ /* We only support a limited subset of advanced mixing here - namely the mixfactor interpolation. */
- if (mixmode == CDT_MIX_NOMIX) {
- copy_v2_v2(luv2->uv, luv1->uv);
- }
- else {
- interp_v2_v2v2(luv2->uv, luv2->uv, luv1->uv, mixfactor);
- }
+ if (mixmode == CDT_MIX_NOMIX) {
+ copy_v2_v2(luv2->uv, luv1->uv);
+ }
+ else {
+ interp_v2_v2v2(luv2->uv, luv2->uv, luv1->uv, mixfactor);
+ }
}
static bool layerEqual_mloopuv(const void *data1, const void *data2)
{
- const MLoopUV *luv1 = data1, *luv2 = data2;
+ const MLoopUV *luv1 = data1, *luv2 = data2;
- return len_squared_v2v2(luv1->uv, luv2->uv) < 0.00001f;
+ return len_squared_v2v2(luv1->uv, luv2->uv) < 0.00001f;
}
static void layerMultiply_mloopuv(void *data, float fac)
{
- MLoopUV *luv = data;
+ MLoopUV *luv = data;
- mul_v2_fl(luv->uv, fac);
+ mul_v2_fl(luv->uv, fac);
}
static void layerInitMinMax_mloopuv(void *vmin, void *vmax)
{
- MLoopUV *min = vmin, *max = vmax;
+ MLoopUV *min = vmin, *max = vmax;
- INIT_MINMAX2(min->uv, max->uv);
+ INIT_MINMAX2(min->uv, max->uv);
}
static void layerDoMinMax_mloopuv(const void *data, void *vmin, void *vmax)
{
- const MLoopUV *luv = data;
- MLoopUV *min = vmin, *max = vmax;
+ const MLoopUV *luv = data;
+ MLoopUV *min = vmin, *max = vmax;
- minmax_v2v2_v2(min->uv, max->uv, luv->uv);
+ minmax_v2v2_v2(min->uv, max->uv, luv->uv);
}
static void layerAdd_mloopuv(void *data1, const void *data2)
{
- MLoopUV *l1 = data1;
- const MLoopUV *l2 = data2;
+ MLoopUV *l1 = data1;
+ const MLoopUV *l2 = data2;
- add_v2_v2(l1->uv, l2->uv);
+ add_v2_v2(l1->uv, l2->uv);
}
static void layerInterp_mloopuv(
- const void **sources, const float *weights,
- const float *sub_weights, int count, void *dest)
-{
- float uv[2];
- int flag = 0;
- int i;
-
- zero_v2(uv);
-
- if (sub_weights) {
- const float *sub_weight = sub_weights;
- for (i = 0; i < count; i++) {
- float weight = (weights ? weights[i] : 1.0f) * (*sub_weight);
- const MLoopUV *src = sources[i];
- madd_v2_v2fl(uv, src->uv, weight);
- if (weight > 0.0f) {
- flag |= src->flag;
- }
- sub_weight++;
- }
- }
- else {
- for (i = 0; i < count; i++) {
- float weight = weights ? weights[i] : 1;
- const MLoopUV *src = sources[i];
- madd_v2_v2fl(uv, src->uv, weight);
- if (weight > 0.0f) {
- flag |= src->flag;
- }
- }
- }
-
- /* delay writing to the destination incase dest is in sources */
- copy_v2_v2(((MLoopUV *)dest)->uv, uv);
- ((MLoopUV *)dest)->flag = flag;
+ const void **sources, const float *weights, const float *sub_weights, int count, void *dest)
+{
+ float uv[2];
+ int flag = 0;
+ int i;
+
+ zero_v2(uv);
+
+ if (sub_weights) {
+ const float *sub_weight = sub_weights;
+ for (i = 0; i < count; i++) {
+ float weight = (weights ? weights[i] : 1.0f) * (*sub_weight);
+ const MLoopUV *src = sources[i];
+ madd_v2_v2fl(uv, src->uv, weight);
+ if (weight > 0.0f) {
+ flag |= src->flag;
+ }
+ sub_weight++;
+ }
+ }
+ else {
+ for (i = 0; i < count; i++) {
+ float weight = weights ? weights[i] : 1;
+ const MLoopUV *src = sources[i];
+ madd_v2_v2fl(uv, src->uv, weight);
+ if (weight > 0.0f) {
+ flag |= src->flag;
+ }
+ }
+ }
+
+ /* delay writing to the destination incase dest is in sources */
+ copy_v2_v2(((MLoopUV *)dest)->uv, uv);
+ ((MLoopUV *)dest)->flag = flag;
}
static bool layerValidate_mloopuv(void *data, const uint totitems, const bool do_fixes)
{
- MLoopUV *uv = data;
- bool has_errors = false;
+ MLoopUV *uv = data;
+ bool has_errors = false;
- for (int i = 0; i < totitems; i++, uv++) {
- if (!is_finite_v2(uv->uv)) {
- if (do_fixes) {
- zero_v2(uv->uv);
- }
- has_errors = true;
- }
- }
+ for (int i = 0; i < totitems; i++, uv++) {
+ if (!is_finite_v2(uv->uv)) {
+ if (do_fixes) {
+ zero_v2(uv->uv);
+ }
+ has_errors = true;
+ }
+ }
- return has_errors;
+ return has_errors;
}
/* origspace is almost exact copy of mloopuv's, keep in sync */
-static void layerCopyValue_mloop_origspace(const void *source, void *dest,
- const int UNUSED(mixmode), const float UNUSED(mixfactor))
+static void layerCopyValue_mloop_origspace(const void *source,
+ void *dest,
+ const int UNUSED(mixmode),
+ const float UNUSED(mixfactor))
{
- const OrigSpaceLoop *luv1 = source;
- OrigSpaceLoop *luv2 = dest;
+ const OrigSpaceLoop *luv1 = source;
+ OrigSpaceLoop *luv2 = dest;
- copy_v2_v2(luv2->uv, luv1->uv);
+ copy_v2_v2(luv2->uv, luv1->uv);
}
static bool layerEqual_mloop_origspace(const void *data1, const void *data2)
{
- const OrigSpaceLoop *luv1 = data1, *luv2 = data2;
+ const OrigSpaceLoop *luv1 = data1, *luv2 = data2;
- return len_squared_v2v2(luv1->uv, luv2->uv) < 0.00001f;
+ return len_squared_v2v2(luv1->uv, luv2->uv) < 0.00001f;
}
static void layerMultiply_mloop_origspace(void *data, float fac)
{
- OrigSpaceLoop *luv = data;
+ OrigSpaceLoop *luv = data;
- mul_v2_fl(luv->uv, fac);
+ mul_v2_fl(luv->uv, fac);
}
static void layerInitMinMax_mloop_origspace(void *vmin, void *vmax)
{
- OrigSpaceLoop *min = vmin, *max = vmax;
+ OrigSpaceLoop *min = vmin, *max = vmax;
- INIT_MINMAX2(min->uv, max->uv);
+ INIT_MINMAX2(min->uv, max->uv);
}
static void layerDoMinMax_mloop_origspace(const void *data, void *vmin, void *vmax)
{
- const OrigSpaceLoop *luv = data;
- OrigSpaceLoop *min = vmin, *max = vmax;
+ const OrigSpaceLoop *luv = data;
+ OrigSpaceLoop *min = vmin, *max = vmax;
- minmax_v2v2_v2(min->uv, max->uv, luv->uv);
+ minmax_v2v2_v2(min->uv, max->uv, luv->uv);
}
static void layerAdd_mloop_origspace(void *data1, const void *data2)
{
- OrigSpaceLoop *l1 = data1;
- const OrigSpaceLoop *l2 = data2;
+ OrigSpaceLoop *l1 = data1;
+ const OrigSpaceLoop *l2 = data2;
- add_v2_v2(l1->uv, l2->uv);
+ add_v2_v2(l1->uv, l2->uv);
}
static void layerInterp_mloop_origspace(
- const void **sources, const float *weights,
- const float *sub_weights, int count, void *dest)
-{
- float uv[2];
- int i;
-
- zero_v2(uv);
-
- if (sub_weights) {
- const float *sub_weight = sub_weights;
- for (i = 0; i < count; i++) {
- float weight = weights ? weights[i] : 1.0f;
- const OrigSpaceLoop *src = sources[i];
- madd_v2_v2fl(uv, src->uv, (*sub_weight) * weight);
- sub_weight++;
- }
- }
- else {
- for (i = 0; i < count; i++) {
- float weight = weights ? weights[i] : 1.0f;
- const OrigSpaceLoop *src = sources[i];
- madd_v2_v2fl(uv, src->uv, weight);
- }
- }
-
- /* delay writing to the destination incase dest is in sources */
- copy_v2_v2(((OrigSpaceLoop *)dest)->uv, uv);
+ const void **sources, const float *weights, const float *sub_weights, int count, void *dest)
+{
+ float uv[2];
+ int i;
+
+ zero_v2(uv);
+
+ if (sub_weights) {
+ const float *sub_weight = sub_weights;
+ for (i = 0; i < count; i++) {
+ float weight = weights ? weights[i] : 1.0f;
+ const OrigSpaceLoop *src = sources[i];
+ madd_v2_v2fl(uv, src->uv, (*sub_weight) * weight);
+ sub_weight++;
+ }
+ }
+ else {
+ for (i = 0; i < count; i++) {
+ float weight = weights ? weights[i] : 1.0f;
+ const OrigSpaceLoop *src = sources[i];
+ madd_v2_v2fl(uv, src->uv, weight);
+ }
+ }
+
+ /* delay writing to the destination incase dest is in sources */
+ copy_v2_v2(((OrigSpaceLoop *)dest)->uv, uv);
}
/* --- end copy */
static void layerInterp_mcol(
- const void **sources, const float *weights,
- const float *sub_weights, int count, void *dest)
-{
- MCol *mc = dest;
- int i, j, k;
- struct {
- float a;
- float r;
- float g;
- float b;
- } col[4] = {{0.0f}};
-
- const float *sub_weight;
-
- if (count <= 0) return;
-
- sub_weight = sub_weights;
- for (i = 0; i < count; ++i) {
- float weight = weights ? weights[i] : 1;
-
- for (j = 0; j < 4; ++j) {
- if (sub_weights) {
- const MCol *src = sources[i];
- for (k = 0; k < 4; ++k, ++sub_weight, ++src) {
- const float w = (*sub_weight) * weight;
- col[j].a += src->a * w;
- col[j].r += src->r * w;
- col[j].g += src->g * w;
- col[j].b += src->b * w;
- }
- }
- else {
- const MCol *src = sources[i];
- col[j].a += src[j].a * weight;
- col[j].r += src[j].r * weight;
- col[j].g += src[j].g * weight;
- col[j].b += src[j].b * weight;
- }
- }
- }
-
- /* delay writing to the destination incase dest is in sources */
- for (j = 0; j < 4; ++j) {
-
- /* Subdivide smooth or fractal can cause problems without clamping
- * although weights should also not cause this situation */
- mc[j].a = round_fl_to_uchar_clamp(col[j].a);
- mc[j].r = round_fl_to_uchar_clamp(col[j].r);
- mc[j].g = round_fl_to_uchar_clamp(col[j].g);
- mc[j].b = round_fl_to_uchar_clamp(col[j].b);
- }
+ const void **sources, const float *weights, const float *sub_weights, int count, void *dest)
+{
+ MCol *mc = dest;
+ int i, j, k;
+ struct {
+ float a;
+ float r;
+ float g;
+ float b;
+ } col[4] = {{0.0f}};
+
+ const float *sub_weight;
+
+ if (count <= 0)
+ return;
+
+ sub_weight = sub_weights;
+ for (i = 0; i < count; ++i) {
+ float weight = weights ? weights[i] : 1;
+
+ for (j = 0; j < 4; ++j) {
+ if (sub_weights) {
+ const MCol *src = sources[i];
+ for (k = 0; k < 4; ++k, ++sub_weight, ++src) {
+ const float w = (*sub_weight) * weight;
+ col[j].a += src->a * w;
+ col[j].r += src->r * w;
+ col[j].g += src->g * w;
+ col[j].b += src->b * w;
+ }
+ }
+ else {
+ const MCol *src = sources[i];
+ col[j].a += src[j].a * weight;
+ col[j].r += src[j].r * weight;
+ col[j].g += src[j].g * weight;
+ col[j].b += src[j].b * weight;
+ }
+ }
+ }
+
+ /* delay writing to the destination incase dest is in sources */
+ for (j = 0; j < 4; ++j) {
+
+ /* Subdivide smooth or fractal can cause problems without clamping
+ * although weights should also not cause this situation */
+ mc[j].a = round_fl_to_uchar_clamp(col[j].a);
+ mc[j].r = round_fl_to_uchar_clamp(col[j].r);
+ mc[j].g = round_fl_to_uchar_clamp(col[j].g);
+ mc[j].b = round_fl_to_uchar_clamp(col[j].b);
+ }
}
static void layerSwap_mcol(void *data, const int *corner_indices)
{
- MCol *mcol = data;
- MCol col[4];
- int j;
+ MCol *mcol = data;
+ MCol col[4];
+ int j;
- for (j = 0; j < 4; ++j)
- col[j] = mcol[corner_indices[j]];
+ for (j = 0; j < 4; ++j)
+ col[j] = mcol[corner_indices[j]];
- memcpy(mcol, col, sizeof(col));
+ memcpy(mcol, col, sizeof(col));
}
static void layerDefault_mcol(void *data, int count)
{
- static MCol default_mcol = {255, 255, 255, 255};
- MCol *mcol = (MCol *)data;
- int i;
+ static MCol default_mcol = {255, 255, 255, 255};
+ MCol *mcol = (MCol *)data;
+ int i;
- for (i = 0; i < 4 * count; i++) {
- mcol[i] = default_mcol;
- }
+ for (i = 0; i < 4 * count; i++) {
+ mcol[i] = default_mcol;
+ }
}
static void layerDefault_origindex(void *data, int count)
{
- copy_vn_i((int *)data, count, ORIGINDEX_NONE);
+ copy_vn_i((int *)data, count, ORIGINDEX_NONE);
}
-static void layerInterp_bweight(
- const void **sources, const float *weights,
- const float *UNUSED(sub_weights), int count, void *dest)
+static void layerInterp_bweight(const void **sources,
+ const float *weights,
+ const float *UNUSED(sub_weights),
+ int count,
+ void *dest)
{
- float f;
- float **in = (float **)sources;
- int i;
+ float f;
+ float **in = (float **)sources;
+ int i;
- if (count <= 0) return;
+ if (count <= 0)
+ return;
- f = 0.0f;
+ f = 0.0f;
- if (weights) {
- for (i = 0; i < count; ++i) {
- f += *in[i] * weights[i];
- }
- }
- else {
- for (i = 0; i < count; ++i) {
- f += *in[i];
- }
- }
+ if (weights) {
+ for (i = 0; i < count; ++i) {
+ f += *in[i] * weights[i];
+ }
+ }
+ else {
+ for (i = 0; i < count; ++i) {
+ f += *in[i];
+ }
+ }
- /* delay writing to the destination incase dest is in sources */
- *((float *)dest) = f;
+ /* delay writing to the destination incase dest is in sources */
+ *((float *)dest) = f;
}
-static void layerInterp_shapekey(
- const void **sources, const float *weights,
- const float *UNUSED(sub_weights), int count, void *dest)
+static void layerInterp_shapekey(const void **sources,
+ const float *weights,
+ const float *UNUSED(sub_weights),
+ int count,
+ void *dest)
{
- float co[3];
- float **in = (float **)sources;
- int i;
+ float co[3];
+ float **in = (float **)sources;
+ int i;
- if (count <= 0) return;
+ if (count <= 0)
+ return;
- zero_v3(co);
+ zero_v3(co);
- if (weights) {
- for (i = 0; i < count; ++i) {
- madd_v3_v3fl(co, in[i], weights[i]);
- }
- }
- else {
- for (i = 0; i < count; ++i) {
- add_v3_v3(co, in[i]);
- }
- }
+ if (weights) {
+ for (i = 0; i < count; ++i) {
+ madd_v3_v3fl(co, in[i], weights[i]);
+ }
+ }
+ else {
+ for (i = 0; i < count; ++i) {
+ add_v3_v3(co, in[i]);
+ }
+ }
- /* delay writing to the destination incase dest is in sources */
- copy_v3_v3((float *)dest, co);
+ /* delay writing to the destination incase dest is in sources */
+ copy_v3_v3((float *)dest, co);
}
static void layerDefault_mvert_skin(void *data, int count)
{
- MVertSkin *vs = data;
- int i;
+ MVertSkin *vs = data;
+ int i;
- for (i = 0; i < count; i++) {
- copy_v3_fl(vs[i].radius, 0.25f);
- vs[i].flag = 0;
- }
+ for (i = 0; i < count; i++) {
+ copy_v3_fl(vs[i].radius, 0.25f);
+ vs[i].flag = 0;
+ }
}
-static void layerCopy_mvert_skin(const void *source, void *dest,
- int count)
+static void layerCopy_mvert_skin(const void *source, void *dest, int count)
{
- memcpy(dest, source, sizeof(MVertSkin) * count);
+ memcpy(dest, source, sizeof(MVertSkin) * count);
}
-static void layerInterp_mvert_skin(
- const void **sources, const float *weights,
- const float *UNUSED(sub_weights),
- int count, void *dest)
+static void layerInterp_mvert_skin(const void **sources,
+ const float *weights,
+ const float *UNUSED(sub_weights),
+ int count,
+ void *dest)
{
- MVertSkin *vs_dst = dest;
- float radius[3], w;
- int i;
+ MVertSkin *vs_dst = dest;
+ float radius[3], w;
+ int i;
- zero_v3(radius);
- for (i = 0; i < count; i++) {
- const MVertSkin *vs_src = sources[i];
- w = weights ? weights[i] : 1.0f;
+ zero_v3(radius);
+ for (i = 0; i < count; i++) {
+ const MVertSkin *vs_src = sources[i];
+ w = weights ? weights[i] : 1.0f;
- madd_v3_v3fl(radius, vs_src->radius, w);
- }
+ madd_v3_v3fl(radius, vs_src->radius, w);
+ }
- /* delay writing to the destination incase dest is in sources */
- vs_dst = dest;
- copy_v3_v3(vs_dst->radius, radius);
- vs_dst->flag &= ~MVERT_SKIN_ROOT;
+ /* delay writing to the destination incase dest is in sources */
+ vs_dst = dest;
+ copy_v3_v3(vs_dst->radius, radius);
+ vs_dst->flag &= ~MVERT_SKIN_ROOT;
}
static void layerSwap_flnor(void *data, const int *corner_indices)
{
- short (*flnors)[4][3] = data;
- short nors[4][3];
- int i = 4;
+ short(*flnors)[4][3] = data;
+ short nors[4][3];
+ int i = 4;
- while (i--) {
- copy_v3_v3_short(nors[i], (*flnors)[corner_indices[i]]);
- }
+ while (i--) {
+ copy_v3_v3_short(nors[i], (*flnors)[corner_indices[i]]);
+ }
- memcpy(flnors, nors, sizeof(nors));
+ memcpy(flnors, nors, sizeof(nors));
}
static void layerDefault_fmap(void *data, int count)
{
- int *fmap_num = (int *)data;
- for (int i = 0; i < count; i++) {
- fmap_num[i] = -1;
- }
+ int *fmap_num = (int *)data;
+ for (int i = 0; i < count; i++) {
+ fmap_num[i] = -1;
+ }
}
static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
- /* 0: CD_MVERT */
- {sizeof(MVert), "MVert", 1, NULL, NULL, NULL, NULL, NULL, NULL},
- /* 1: CD_MSTICKY */ /* DEPRECATED */
- {sizeof(float) * 2, "", 1, NULL, NULL, NULL, NULL, NULL, NULL},
- /* 2: CD_MDEFORMVERT */
- {sizeof(MDeformVert), "MDeformVert", 1, NULL, layerCopy_mdeformvert,
- layerFree_mdeformvert, layerInterp_mdeformvert, NULL, NULL},
- /* 3: CD_MEDGE */
- {sizeof(MEdge), "MEdge", 1, NULL, NULL, NULL, NULL, NULL, NULL},
- /* 4: CD_MFACE */
- {sizeof(MFace), "MFace", 1, NULL, NULL, NULL, NULL, NULL, NULL},
- /* 5: CD_MTFACE */
- {sizeof(MTFace), "MTFace", 1, N_("UVMap"), layerCopy_tface, NULL, layerInterp_tface, layerSwap_tface,
- layerDefault_tface, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, layerMaxNum_tface},
- /* 6: CD_MCOL */
- /* 4 MCol structs per face */
- {sizeof(MCol) * 4, "MCol", 4, N_("Col"), NULL, NULL, layerInterp_mcol, layerSwap_mcol,
- layerDefault_mcol, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, layerMaxNum_mloopcol},
- /* 7: CD_ORIGINDEX */
- {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, layerDefault_origindex},
- /* 8: CD_NORMAL */
- /* 3 floats per normal vector */
- {sizeof(float) * 3, "vec3f", 1, NULL, NULL, NULL, layerInterp_normal, NULL, NULL,
- layerValidate_normal, NULL, NULL, NULL, NULL, NULL, layerCopyValue_normal},
- /* 9: CD_FACEMAP */
- {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, layerDefault_fmap, NULL},
- /* 10: CD_PROP_FLT */
- {sizeof(MFloatProperty), "MFloatProperty", 1, N_("Float"), layerCopy_propFloat, NULL, NULL, NULL, NULL,
- layerValidate_propFloat},
- /* 11: CD_PROP_INT */
- {sizeof(MIntProperty), "MIntProperty", 1, N_("Int"), layerCopy_propInt, NULL, NULL, NULL},
- /* 12: CD_PROP_STR */
- {sizeof(MStringProperty), "MStringProperty", 1, N_("String"), layerCopy_propString, NULL, NULL, NULL},
- /* 13: CD_ORIGSPACE */
- {sizeof(OrigSpaceFace), "OrigSpaceFace", 1, N_("UVMap"), layerCopy_origspace_face, NULL,
- layerInterp_origspace_face, layerSwap_origspace_face, layerDefault_origspace_face},
- /* 14: CD_ORCO */
- {sizeof(float) * 3, "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
- /* 15: CD_MTEXPOLY */ /* DEPRECATED */
- /* note, when we expose the UV Map / TexFace split to the user, change this back to face Texture */
- {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
- /* 16: CD_MLOOPUV */
- {sizeof(MLoopUV), "MLoopUV", 1, N_("UVMap"), NULL, NULL, layerInterp_mloopuv, NULL, NULL,
- layerValidate_mloopuv, layerEqual_mloopuv, layerMultiply_mloopuv, layerInitMinMax_mloopuv,
- layerAdd_mloopuv, layerDoMinMax_mloopuv, layerCopyValue_mloopuv, NULL, NULL, NULL, layerMaxNum_tface},
- /* 17: CD_MLOOPCOL */
- {sizeof(MLoopCol), "MLoopCol", 1, N_("Col"), NULL, NULL, layerInterp_mloopcol, NULL,
- layerDefault_mloopcol, NULL, layerEqual_mloopcol, layerMultiply_mloopcol, layerInitMinMax_mloopcol,
- layerAdd_mloopcol, layerDoMinMax_mloopcol, layerCopyValue_mloopcol, NULL, NULL, NULL, layerMaxNum_mloopcol},
- /* 18: CD_TANGENT */
- {sizeof(float) * 4 * 4, "", 0, N_("Tangent"), NULL, NULL, NULL, NULL, NULL},
- /* 19: CD_MDISPS */
- {sizeof(MDisps), "MDisps", 1, NULL, layerCopy_mdisps,
- layerFree_mdisps, NULL, layerSwap_mdisps, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- layerRead_mdisps, layerWrite_mdisps, layerFilesize_mdisps},
- /* 20: CD_PREVIEW_MCOL */
- {sizeof(MCol) * 4, "MCol", 4, N_("PreviewCol"), NULL, NULL, layerInterp_mcol,
- layerSwap_mcol, layerDefault_mcol},
- /* 21: CD_ID_MCOL */ /* DEPRECATED */
- {sizeof(MCol) * 4, "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
- /* 22: CD_TEXTURE_MCOL */
- {sizeof(MCol) * 4, "MCol", 4, N_("TexturedCol"), NULL, NULL, layerInterp_mcol,
- layerSwap_mcol, layerDefault_mcol},
- /* 23: CD_CLOTH_ORCO */
- {sizeof(float) * 3, "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
- /* 24: CD_RECAST */
- {sizeof(MRecast), "MRecast", 1, N_("Recast"), NULL, NULL, NULL, NULL},
-
-/* BMESH ONLY */
- /* 25: CD_MPOLY */
- {sizeof(MPoly), "MPoly", 1, N_("NGon Face"), NULL, NULL, NULL, NULL, NULL},
- /* 26: CD_MLOOP */
- {sizeof(MLoop), "MLoop", 1, N_("NGon Face-Vertex"), NULL, NULL, NULL, NULL, NULL},
- /* 27: CD_SHAPE_KEYINDEX */
- {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
- /* 28: CD_SHAPEKEY */
- {sizeof(float) * 3, "", 0, N_("ShapeKey"), NULL, NULL, layerInterp_shapekey},
- /* 29: CD_BWEIGHT */
- {sizeof(float), "", 0, N_("BevelWeight"), NULL, NULL, layerInterp_bweight},
- /* 30: CD_CREASE */
- {sizeof(float), "", 0, N_("SubSurfCrease"), NULL, NULL, layerInterp_bweight},
- /* 31: CD_ORIGSPACE_MLOOP */
- {sizeof(OrigSpaceLoop), "OrigSpaceLoop", 1, N_("OS Loop"), NULL, NULL, layerInterp_mloop_origspace, NULL, NULL, NULL,
- layerEqual_mloop_origspace, layerMultiply_mloop_origspace, layerInitMinMax_mloop_origspace,
- layerAdd_mloop_origspace, layerDoMinMax_mloop_origspace, layerCopyValue_mloop_origspace},
- /* 32: CD_PREVIEW_MLOOPCOL */
- {sizeof(MLoopCol), "MLoopCol", 1, N_("PreviewLoopCol"), NULL, NULL, layerInterp_mloopcol, NULL,
- layerDefault_mloopcol, NULL, layerEqual_mloopcol, layerMultiply_mloopcol, layerInitMinMax_mloopcol,
- layerAdd_mloopcol, layerDoMinMax_mloopcol, layerCopyValue_mloopcol},
- /* 33: CD_BM_ELEM_PYPTR */
- {sizeof(void *), "", 1, NULL, layerCopy_bmesh_elem_py_ptr,
- layerFree_bmesh_elem_py_ptr, NULL, NULL, NULL},
-
-/* END BMESH ONLY */
-
- /* 34: CD_PAINT_MASK */
- {sizeof(float), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
- /* 35: CD_GRID_PAINT_MASK */
- {sizeof(GridPaintMask), "GridPaintMask", 1, NULL, layerCopy_grid_paint_mask,
- layerFree_grid_paint_mask, NULL, NULL, NULL},
- /* 36: CD_MVERT_SKIN */
- {sizeof(MVertSkin), "MVertSkin", 1, NULL, layerCopy_mvert_skin, NULL,
- layerInterp_mvert_skin, NULL, layerDefault_mvert_skin},
- /* 37: CD_FREESTYLE_EDGE */
- {sizeof(FreestyleEdge), "FreestyleEdge", 1, NULL, NULL, NULL, NULL, NULL, NULL},
- /* 38: CD_FREESTYLE_FACE */
- {sizeof(FreestyleFace), "FreestyleFace", 1, NULL, NULL, NULL, NULL, NULL, NULL},
- /* 39: CD_MLOOPTANGENT */
- {sizeof(float[4]), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
- /* 40: CD_TESSLOOPNORMAL */
- {sizeof(short[4][3]), "", 0, NULL, NULL, NULL, NULL, layerSwap_flnor, NULL},
- /* 41: CD_CUSTOMLOOPNORMAL */
- {sizeof(short[2]), "vec2s", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ /* 0: CD_MVERT */
+ {sizeof(MVert), "MVert", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ /* 1: CD_MSTICKY */ /* DEPRECATED */
+ {sizeof(float) * 2, "", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ /* 2: CD_MDEFORMVERT */
+ {sizeof(MDeformVert),
+ "MDeformVert",
+ 1,
+ NULL,
+ layerCopy_mdeformvert,
+ layerFree_mdeformvert,
+ layerInterp_mdeformvert,
+ NULL,
+ NULL},
+ /* 3: CD_MEDGE */
+ {sizeof(MEdge), "MEdge", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ /* 4: CD_MFACE */
+ {sizeof(MFace), "MFace", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ /* 5: CD_MTFACE */
+ {sizeof(MTFace),
+ "MTFace",
+ 1,
+ N_("UVMap"),
+ layerCopy_tface,
+ NULL,
+ layerInterp_tface,
+ layerSwap_tface,
+ layerDefault_tface,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ layerMaxNum_tface},
+ /* 6: CD_MCOL */
+ /* 4 MCol structs per face */
+ {sizeof(MCol) * 4,
+ "MCol",
+ 4,
+ N_("Col"),
+ NULL,
+ NULL,
+ layerInterp_mcol,
+ layerSwap_mcol,
+ layerDefault_mcol,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ layerMaxNum_mloopcol},
+ /* 7: CD_ORIGINDEX */
+ {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, layerDefault_origindex},
+ /* 8: CD_NORMAL */
+ /* 3 floats per normal vector */
+ {sizeof(float) * 3,
+ "vec3f",
+ 1,
+ NULL,
+ NULL,
+ NULL,
+ layerInterp_normal,
+ NULL,
+ NULL,
+ layerValidate_normal,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ layerCopyValue_normal},
+ /* 9: CD_FACEMAP */
+ {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, layerDefault_fmap, NULL},
+ /* 10: CD_PROP_FLT */
+ {sizeof(MFloatProperty),
+ "MFloatProperty",
+ 1,
+ N_("Float"),
+ layerCopy_propFloat,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ layerValidate_propFloat},
+ /* 11: CD_PROP_INT */
+ {sizeof(MIntProperty), "MIntProperty", 1, N_("Int"), layerCopy_propInt, NULL, NULL, NULL},
+ /* 12: CD_PROP_STR */
+ {sizeof(MStringProperty),
+ "MStringProperty",
+ 1,
+ N_("String"),
+ layerCopy_propString,
+ NULL,
+ NULL,
+ NULL},
+ /* 13: CD_ORIGSPACE */
+ {sizeof(OrigSpaceFace),
+ "OrigSpaceFace",
+ 1,
+ N_("UVMap"),
+ layerCopy_origspace_face,
+ NULL,
+ layerInterp_origspace_face,
+ layerSwap_origspace_face,
+ layerDefault_origspace_face},
+ /* 14: CD_ORCO */
+ {sizeof(float) * 3, "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ /* 15: CD_MTEXPOLY */ /* DEPRECATED */
+ /* note, when we expose the UV Map / TexFace split to the user, change this back to face Texture */
+ {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ /* 16: CD_MLOOPUV */
+ {sizeof(MLoopUV),
+ "MLoopUV",
+ 1,
+ N_("UVMap"),
+ NULL,
+ NULL,
+ layerInterp_mloopuv,
+ NULL,
+ NULL,
+ layerValidate_mloopuv,
+ layerEqual_mloopuv,
+ layerMultiply_mloopuv,
+ layerInitMinMax_mloopuv,
+ layerAdd_mloopuv,
+ layerDoMinMax_mloopuv,
+ layerCopyValue_mloopuv,
+ NULL,
+ NULL,
+ NULL,
+ layerMaxNum_tface},
+ /* 17: CD_MLOOPCOL */
+ {sizeof(MLoopCol),
+ "MLoopCol",
+ 1,
+ N_("Col"),
+ NULL,
+ NULL,
+ layerInterp_mloopcol,
+ NULL,
+ layerDefault_mloopcol,
+ NULL,
+ layerEqual_mloopcol,
+ layerMultiply_mloopcol,
+ layerInitMinMax_mloopcol,
+ layerAdd_mloopcol,
+ layerDoMinMax_mloopcol,
+ layerCopyValue_mloopcol,
+ NULL,
+ NULL,
+ NULL,
+ layerMaxNum_mloopcol},
+ /* 18: CD_TANGENT */
+ {sizeof(float) * 4 * 4, "", 0, N_("Tangent"), NULL, NULL, NULL, NULL, NULL},
+ /* 19: CD_MDISPS */
+ {sizeof(MDisps),
+ "MDisps",
+ 1,
+ NULL,
+ layerCopy_mdisps,
+ layerFree_mdisps,
+ NULL,
+ layerSwap_mdisps,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ layerRead_mdisps,
+ layerWrite_mdisps,
+ layerFilesize_mdisps},
+ /* 20: CD_PREVIEW_MCOL */
+ {sizeof(MCol) * 4,
+ "MCol",
+ 4,
+ N_("PreviewCol"),
+ NULL,
+ NULL,
+ layerInterp_mcol,
+ layerSwap_mcol,
+ layerDefault_mcol},
+ /* 21: CD_ID_MCOL */ /* DEPRECATED */
+ {sizeof(MCol) * 4, "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ /* 22: CD_TEXTURE_MCOL */
+ {sizeof(MCol) * 4,
+ "MCol",
+ 4,
+ N_("TexturedCol"),
+ NULL,
+ NULL,
+ layerInterp_mcol,
+ layerSwap_mcol,
+ layerDefault_mcol},
+ /* 23: CD_CLOTH_ORCO */
+ {sizeof(float) * 3, "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ /* 24: CD_RECAST */
+ {sizeof(MRecast), "MRecast", 1, N_("Recast"), NULL, NULL, NULL, NULL},
+
+ /* BMESH ONLY */
+ /* 25: CD_MPOLY */
+ {sizeof(MPoly), "MPoly", 1, N_("NGon Face"), NULL, NULL, NULL, NULL, NULL},
+ /* 26: CD_MLOOP */
+ {sizeof(MLoop), "MLoop", 1, N_("NGon Face-Vertex"), NULL, NULL, NULL, NULL, NULL},
+ /* 27: CD_SHAPE_KEYINDEX */
+ {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ /* 28: CD_SHAPEKEY */
+ {sizeof(float) * 3, "", 0, N_("ShapeKey"), NULL, NULL, layerInterp_shapekey},
+ /* 29: CD_BWEIGHT */
+ {sizeof(float), "", 0, N_("BevelWeight"), NULL, NULL, layerInterp_bweight},
+ /* 30: CD_CREASE */
+ {sizeof(float), "", 0, N_("SubSurfCrease"), NULL, NULL, layerInterp_bweight},
+ /* 31: CD_ORIGSPACE_MLOOP */
+ {sizeof(OrigSpaceLoop),
+ "OrigSpaceLoop",
+ 1,
+ N_("OS Loop"),
+ NULL,
+ NULL,
+ layerInterp_mloop_origspace,
+ NULL,
+ NULL,
+ NULL,
+ layerEqual_mloop_origspace,
+ layerMultiply_mloop_origspace,
+ layerInitMinMax_mloop_origspace,
+ layerAdd_mloop_origspace,
+ layerDoMinMax_mloop_origspace,
+ layerCopyValue_mloop_origspace},
+ /* 32: CD_PREVIEW_MLOOPCOL */
+ {sizeof(MLoopCol),
+ "MLoopCol",
+ 1,
+ N_("PreviewLoopCol"),
+ NULL,
+ NULL,
+ layerInterp_mloopcol,
+ NULL,
+ layerDefault_mloopcol,
+ NULL,
+ layerEqual_mloopcol,
+ layerMultiply_mloopcol,
+ layerInitMinMax_mloopcol,
+ layerAdd_mloopcol,
+ layerDoMinMax_mloopcol,
+ layerCopyValue_mloopcol},
+ /* 33: CD_BM_ELEM_PYPTR */
+ {sizeof(void *),
+ "",
+ 1,
+ NULL,
+ layerCopy_bmesh_elem_py_ptr,
+ layerFree_bmesh_elem_py_ptr,
+ NULL,
+ NULL,
+ NULL},
+
+ /* END BMESH ONLY */
+
+ /* 34: CD_PAINT_MASK */
+ {sizeof(float), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ /* 35: CD_GRID_PAINT_MASK */
+ {sizeof(GridPaintMask),
+ "GridPaintMask",
+ 1,
+ NULL,
+ layerCopy_grid_paint_mask,
+ layerFree_grid_paint_mask,
+ NULL,
+ NULL,
+ NULL},
+ /* 36: CD_MVERT_SKIN */
+ {sizeof(MVertSkin),
+ "MVertSkin",
+ 1,
+ NULL,
+ layerCopy_mvert_skin,
+ NULL,
+ layerInterp_mvert_skin,
+ NULL,
+ layerDefault_mvert_skin},
+ /* 37: CD_FREESTYLE_EDGE */
+ {sizeof(FreestyleEdge), "FreestyleEdge", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ /* 38: CD_FREESTYLE_FACE */
+ {sizeof(FreestyleFace), "FreestyleFace", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ /* 39: CD_MLOOPTANGENT */
+ {sizeof(float[4]), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ /* 40: CD_TESSLOOPNORMAL */
+ {sizeof(short[4][3]), "", 0, NULL, NULL, NULL, NULL, layerSwap_flnor, NULL},
+ /* 41: CD_CUSTOMLOOPNORMAL */
+ {sizeof(short[2]), "vec2s", 1, NULL, NULL, NULL, NULL, NULL, NULL},
};
-
static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
- /* 0-4 */ "CDMVert", "CDMSticky", "CDMDeformVert", "CDMEdge", "CDMFace",
- /* 5-9 */ "CDMTFace", "CDMCol", "CDOrigIndex", "CDNormal", "CDFaceMap",
- /* 10-14 */ "CDMFloatProperty", "CDMIntProperty", "CDMStringProperty", "CDOrigSpace", "CDOrco",
- /* 15-19 */ "CDMTexPoly", "CDMLoopUV", "CDMloopCol", "CDTangent", "CDMDisps",
- /* 20-24 */ "CDPreviewMCol", "CDIDMCol", "CDTextureMCol", "CDClothOrco", "CDMRecast",
-
-/* BMESH ONLY */
- /* 25-29 */ "CDMPoly", "CDMLoop", "CDShapeKeyIndex", "CDShapeKey", "CDBevelWeight",
- /* 30-34 */ "CDSubSurfCrease", "CDOrigSpaceLoop", "CDPreviewLoopCol", "CDBMElemPyPtr", "CDPaintMask",
- /* 35-36 */ "CDGridPaintMask", "CDMVertSkin",
- /* 37-38 */ "CDFreestyleEdge", "CDFreestyleFace",
- /* 39-41 */ "CDMLoopTangent", "CDTessLoopNormal", "CDCustomLoopNormal",
+ /* 0-4 */ "CDMVert",
+ "CDMSticky",
+ "CDMDeformVert",
+ "CDMEdge",
+ "CDMFace",
+ /* 5-9 */ "CDMTFace",
+ "CDMCol",
+ "CDOrigIndex",
+ "CDNormal",
+ "CDFaceMap",
+ /* 10-14 */ "CDMFloatProperty",
+ "CDMIntProperty",
+ "CDMStringProperty",
+ "CDOrigSpace",
+ "CDOrco",
+ /* 15-19 */ "CDMTexPoly",
+ "CDMLoopUV",
+ "CDMloopCol",
+ "CDTangent",
+ "CDMDisps",
+ /* 20-24 */ "CDPreviewMCol",
+ "CDIDMCol",
+ "CDTextureMCol",
+ "CDClothOrco",
+ "CDMRecast",
+
+ /* BMESH ONLY */
+ /* 25-29 */ "CDMPoly",
+ "CDMLoop",
+ "CDShapeKeyIndex",
+ "CDShapeKey",
+ "CDBevelWeight",
+ /* 30-34 */ "CDSubSurfCrease",
+ "CDOrigSpaceLoop",
+ "CDPreviewLoopCol",
+ "CDBMElemPyPtr",
+ "CDPaintMask",
+ /* 35-36 */ "CDGridPaintMask",
+ "CDMVertSkin",
+ /* 37-38 */ "CDFreestyleEdge",
+ "CDFreestyleFace",
+ /* 39-41 */ "CDMLoopTangent",
+ "CDTessLoopNormal",
+ "CDCustomLoopNormal",
};
-
const CustomData_MeshMasks CD_MASK_BAREMESH = {
.vmask = CD_MASK_MVERT | CD_MASK_BWEIGHT,
.emask = CD_MASK_MEDGE | CD_MASK_BWEIGHT,
@@ -1406,12 +1650,14 @@ const CustomData_MeshMasks CD_MASK_BAREMESH_ORIGINDEX = {
.pmask = CD_MASK_MPOLY | CD_MASK_FACEMAP | CD_MASK_ORIGINDEX,
};
const CustomData_MeshMasks CD_MASK_MESH = {
- .vmask = (CD_MASK_MVERT | CD_MASK_MDEFORMVERT | CD_MASK_MVERT_SKIN | CD_MASK_PAINT_MASK | CD_MASK_GENERIC_DATA),
+ .vmask = (CD_MASK_MVERT | CD_MASK_MDEFORMVERT | CD_MASK_MVERT_SKIN | CD_MASK_PAINT_MASK |
+ CD_MASK_GENERIC_DATA),
.emask = (CD_MASK_MEDGE | CD_MASK_FREESTYLE_EDGE | CD_MASK_GENERIC_DATA),
.fmask = 0,
- .lmask = (CD_MASK_MLOOP | CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL |
- CD_MASK_GRID_PAINT_MASK | CD_MASK_GENERIC_DATA),
- .pmask = (CD_MASK_MPOLY | CD_MASK_RECAST | CD_MASK_FACEMAP | CD_MASK_FREESTYLE_FACE | CD_MASK_GENERIC_DATA),
+ .lmask = (CD_MASK_MLOOP | CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL |
+ CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_GRID_PAINT_MASK | CD_MASK_GENERIC_DATA),
+ .pmask = (CD_MASK_MPOLY | CD_MASK_RECAST | CD_MASK_FACEMAP | CD_MASK_FREESTYLE_FACE |
+ CD_MASK_GENERIC_DATA),
};
const CustomData_MeshMasks CD_MASK_EDITMESH = {
.vmask = (CD_MASK_MDEFORMVERT | CD_MASK_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_SHAPEKEY |
@@ -1427,9 +1673,11 @@ const CustomData_MeshMasks CD_MASK_DERIVEDMESH = {
CD_MASK_ORCO | CD_MASK_CLOTH_ORCO | CD_MASK_GENERIC_DATA),
.emask = (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_EDGE | CD_MASK_GENERIC_DATA),
.fmask = (CD_MASK_ORIGINDEX | CD_MASK_ORIGSPACE | CD_MASK_PREVIEW_MCOL | CD_MASK_TANGENT),
- .lmask = (CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_PREVIEW_MLOOPCOL |
- CD_MASK_ORIGSPACE_MLOOP | CD_MASK_GENERIC_DATA), /* XXX MISSING CD_MASK_MLOOPTANGENT ? */
- .pmask = (CD_MASK_ORIGINDEX | CD_MASK_RECAST | CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP | CD_MASK_GENERIC_DATA),
+ .lmask = (CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL |
+ CD_MASK_PREVIEW_MLOOPCOL | CD_MASK_ORIGSPACE_MLOOP |
+ CD_MASK_GENERIC_DATA), /* XXX MISSING CD_MASK_MLOOPTANGENT ? */
+ .pmask = (CD_MASK_ORIGINDEX | CD_MASK_RECAST | CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP |
+ CD_MASK_GENERIC_DATA),
};
const CustomData_MeshMasks CD_MASK_BMESH = {
.vmask = (CD_MASK_MDEFORMVERT | CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_SHAPEKEY |
@@ -1448,298 +1696,315 @@ const CustomData_MeshMasks CD_MASK_FACECORNERS = {
.emask = 0,
.fmask = (CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_PREVIEW_MCOL | CD_MASK_ORIGSPACE |
CD_MASK_TESSLOOPNORMAL | CD_MASK_TANGENT),
- .lmask = (CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_PREVIEW_MLOOPCOL | CD_MASK_ORIGSPACE_MLOOP |
- CD_MASK_NORMAL | CD_MASK_MLOOPTANGENT),
+ .lmask = (CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_PREVIEW_MLOOPCOL |
+ CD_MASK_ORIGSPACE_MLOOP | CD_MASK_NORMAL | CD_MASK_MLOOPTANGENT),
.pmask = 0,
};
const CustomData_MeshMasks CD_MASK_EVERYTHING = {
- .vmask = (CD_MASK_MVERT | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_NORMAL | CD_MASK_MDEFORMVERT |
- CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_ORCO | CD_MASK_CLOTH_ORCO | CD_MASK_SHAPEKEY |
- CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK | CD_MASK_GENERIC_DATA),
- .emask = (CD_MASK_MEDGE | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_BWEIGHT | CD_MASK_CREASE |
- CD_MASK_FREESTYLE_EDGE | CD_MASK_GENERIC_DATA),
+ .vmask = (CD_MASK_MVERT | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_NORMAL |
+ CD_MASK_MDEFORMVERT | CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_ORCO |
+ CD_MASK_CLOTH_ORCO | CD_MASK_SHAPEKEY | CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK |
+ CD_MASK_GENERIC_DATA),
+ .emask = (CD_MASK_MEDGE | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_BWEIGHT |
+ CD_MASK_CREASE | CD_MASK_FREESTYLE_EDGE | CD_MASK_GENERIC_DATA),
.fmask = (CD_MASK_MFACE | CD_MASK_ORIGINDEX | CD_MASK_NORMAL | CD_MASK_MTFACE | CD_MASK_MCOL |
CD_MASK_ORIGSPACE | CD_MASK_TANGENT | CD_MASK_TESSLOOPNORMAL | CD_MASK_PREVIEW_MCOL |
CD_MASK_GENERIC_DATA),
- .lmask = (CD_MASK_MLOOP | CD_MASK_BM_ELEM_PYPTR | CD_MASK_MDISPS | CD_MASK_NORMAL | CD_MASK_MLOOPUV |
- CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_MLOOPTANGENT | CD_MASK_PREVIEW_MLOOPCOL |
- CD_MASK_ORIGSPACE_MLOOP | CD_MASK_GRID_PAINT_MASK | CD_MASK_GENERIC_DATA),
- .pmask = (CD_MASK_MPOLY | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_NORMAL | CD_MASK_RECAST |
- CD_MASK_FACEMAP | CD_MASK_FREESTYLE_FACE | CD_MASK_GENERIC_DATA),
+ .lmask = (CD_MASK_MLOOP | CD_MASK_BM_ELEM_PYPTR | CD_MASK_MDISPS | CD_MASK_NORMAL |
+ CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL |
+ CD_MASK_MLOOPTANGENT | CD_MASK_PREVIEW_MLOOPCOL | CD_MASK_ORIGSPACE_MLOOP |
+ CD_MASK_GRID_PAINT_MASK | CD_MASK_GENERIC_DATA),
+ .pmask = (CD_MASK_MPOLY | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_NORMAL |
+ CD_MASK_RECAST | CD_MASK_FACEMAP | CD_MASK_FREESTYLE_FACE | CD_MASK_GENERIC_DATA),
};
static const LayerTypeInfo *layerType_getInfo(int type)
{
- if (type < 0 || type >= CD_NUMTYPES) return NULL;
+ if (type < 0 || type >= CD_NUMTYPES)
+ return NULL;
- return &LAYERTYPEINFO[type];
+ return &LAYERTYPEINFO[type];
}
static const char *layerType_getName(int type)
{
- if (type < 0 || type >= CD_NUMTYPES) return NULL;
+ if (type < 0 || type >= CD_NUMTYPES)
+ return NULL;
- return LAYERTYPENAMES[type];
+ return LAYERTYPENAMES[type];
}
void customData_mask_layers__print(const CustomData_MeshMasks *mask)
{
- int i;
-
- printf("verts mask=0x%lx:\n", (long unsigned int)mask->vmask);
- for (i = 0; i < CD_NUMTYPES; i++) {
- if (mask->vmask & CD_TYPE_AS_MASK(i)) {
- printf(" %s\n", layerType_getName(i));
- }
- }
-
- printf("edges mask=0x%lx:\n", (long unsigned int)mask->emask);
- for (i = 0; i < CD_NUMTYPES; i++) {
- if (mask->emask & CD_TYPE_AS_MASK(i)) {
- printf(" %s\n", layerType_getName(i));
- }
- }
-
- printf("faces mask=0x%lx:\n", (long unsigned int)mask->fmask);
- for (i = 0; i < CD_NUMTYPES; i++) {
- if (mask->fmask & CD_TYPE_AS_MASK(i)) {
- printf(" %s\n", layerType_getName(i));
- }
- }
-
- printf("loops mask=0x%lx:\n", (long unsigned int)mask->lmask);
- for (i = 0; i < CD_NUMTYPES; i++) {
- if (mask->lmask & CD_TYPE_AS_MASK(i)) {
- printf(" %s\n", layerType_getName(i));
- }
- }
-
- printf("polys mask=0x%lx:\n", (long unsigned int)mask->pmask);
- for (i = 0; i < CD_NUMTYPES; i++) {
- if (mask->pmask & CD_TYPE_AS_MASK(i)) {
- printf(" %s\n", layerType_getName(i));
- }
- }
+ int i;
+
+ printf("verts mask=0x%lx:\n", (long unsigned int)mask->vmask);
+ for (i = 0; i < CD_NUMTYPES; i++) {
+ if (mask->vmask & CD_TYPE_AS_MASK(i)) {
+ printf(" %s\n", layerType_getName(i));
+ }
+ }
+
+ printf("edges mask=0x%lx:\n", (long unsigned int)mask->emask);
+ for (i = 0; i < CD_NUMTYPES; i++) {
+ if (mask->emask & CD_TYPE_AS_MASK(i)) {
+ printf(" %s\n", layerType_getName(i));
+ }
+ }
+
+ printf("faces mask=0x%lx:\n", (long unsigned int)mask->fmask);
+ for (i = 0; i < CD_NUMTYPES; i++) {
+ if (mask->fmask & CD_TYPE_AS_MASK(i)) {
+ printf(" %s\n", layerType_getName(i));
+ }
+ }
+
+ printf("loops mask=0x%lx:\n", (long unsigned int)mask->lmask);
+ for (i = 0; i < CD_NUMTYPES; i++) {
+ if (mask->lmask & CD_TYPE_AS_MASK(i)) {
+ printf(" %s\n", layerType_getName(i));
+ }
+ }
+
+ printf("polys mask=0x%lx:\n", (long unsigned int)mask->pmask);
+ for (i = 0; i < CD_NUMTYPES; i++) {
+ if (mask->pmask & CD_TYPE_AS_MASK(i)) {
+ printf(" %s\n", layerType_getName(i));
+ }
+ }
}
/********************* CustomData functions *********************/
static void customData_update_offsets(CustomData *data);
-static CustomDataLayer *customData_add_layer__internal(
- CustomData *data, int type, eCDAllocType alloctype, void *layerdata,
- int totelem, const char *name);
+static CustomDataLayer *customData_add_layer__internal(CustomData *data,
+ int type,
+ eCDAllocType alloctype,
+ void *layerdata,
+ int totelem,
+ const char *name);
void CustomData_update_typemap(CustomData *data)
{
- int i, lasttype = -1;
+ int i, lasttype = -1;
- for (i = 0; i < CD_NUMTYPES; i++) {
- data->typemap[i] = -1;
- }
+ for (i = 0; i < CD_NUMTYPES; i++) {
+ data->typemap[i] = -1;
+ }
- for (i = 0; i < data->totlayer; i++) {
- const int type = data->layers[i].type;
- if (type != lasttype) {
- data->typemap[type] = i;
- lasttype = type;
- }
- }
+ for (i = 0; i < data->totlayer; i++) {
+ const int type = data->layers[i].type;
+ if (type != lasttype) {
+ data->typemap[type] = i;
+ lasttype = type;
+ }
+ }
}
/* currently only used in BLI_assert */
#ifndef NDEBUG
static bool customdata_typemap_is_valid(const CustomData *data)
{
- CustomData data_copy = *data;
- CustomData_update_typemap(&data_copy);
- return (memcmp(data->typemap, data_copy.typemap, sizeof(data->typemap)) == 0);
+ CustomData data_copy = *data;
+ CustomData_update_typemap(&data_copy);
+ return (memcmp(data->typemap, data_copy.typemap, sizeof(data->typemap)) == 0);
}
#endif
-bool CustomData_merge(
- const struct CustomData *source, struct CustomData *dest,
- CustomDataMask mask, eCDAllocType alloctype, int totelem)
-{
- /*const LayerTypeInfo *typeInfo;*/
- CustomDataLayer *layer, *newlayer;
- void *data;
- int i, type, lasttype = -1, lastactive = 0, lastrender = 0, lastclone = 0, lastmask = 0, flag = 0;
- int number = 0, maxnumber = -1;
- bool changed = false;
-
- for (i = 0; i < source->totlayer; ++i) {
- layer = &source->layers[i];
- /*typeInfo = layerType_getInfo(layer->type);*/ /*UNUSED*/
-
- type = layer->type;
- flag = layer->flag;
-
- if (type != lasttype) {
- number = 0;
- maxnumber = CustomData_layertype_layers_max(type);
- lastactive = layer->active;
- lastrender = layer->active_rnd;
- lastclone = layer->active_clone;
- lastmask = layer->active_mask;
- lasttype = type;
- }
- else
- number++;
-
- if (flag & CD_FLAG_NOCOPY) continue;
- else if (!(mask & CD_TYPE_AS_MASK(type))) continue;
- else if ((maxnumber != -1) && (number >= maxnumber)) continue;
- else if (CustomData_get_layer_named(dest, type, layer->name)) continue;
-
- switch (alloctype) {
- case CD_ASSIGN:
- case CD_REFERENCE:
- case CD_DUPLICATE:
- data = layer->data;
- break;
- default:
- data = NULL;
- break;
- }
-
- if ((alloctype == CD_ASSIGN) && (flag & CD_FLAG_NOFREE)) {
- newlayer = customData_add_layer__internal(dest, type, CD_REFERENCE, data, totelem, layer->name);
- }
- else {
- newlayer = customData_add_layer__internal(dest, type, alloctype, data, totelem, layer->name);
- }
-
- if (newlayer) {
- newlayer->uid = layer->uid;
-
- newlayer->active = lastactive;
- newlayer->active_rnd = lastrender;
- newlayer->active_clone = lastclone;
- newlayer->active_mask = lastmask;
- newlayer->flag |= flag & (CD_FLAG_EXTERNAL | CD_FLAG_IN_MEMORY);
- changed = true;
- }
- }
-
- CustomData_update_typemap(dest);
- return changed;
+bool CustomData_merge(const struct CustomData *source,
+ struct CustomData *dest,
+ CustomDataMask mask,
+ eCDAllocType alloctype,
+ int totelem)
+{
+ /*const LayerTypeInfo *typeInfo;*/
+ CustomDataLayer *layer, *newlayer;
+ void *data;
+ int i, type, lasttype = -1, lastactive = 0, lastrender = 0, lastclone = 0, lastmask = 0,
+ flag = 0;
+ int number = 0, maxnumber = -1;
+ bool changed = false;
+
+ for (i = 0; i < source->totlayer; ++i) {
+ layer = &source->layers[i];
+ /*typeInfo = layerType_getInfo(layer->type);*/ /*UNUSED*/
+
+ type = layer->type;
+ flag = layer->flag;
+
+ if (type != lasttype) {
+ number = 0;
+ maxnumber = CustomData_layertype_layers_max(type);
+ lastactive = layer->active;
+ lastrender = layer->active_rnd;
+ lastclone = layer->active_clone;
+ lastmask = layer->active_mask;
+ lasttype = type;
+ }
+ else
+ number++;
+
+ if (flag & CD_FLAG_NOCOPY)
+ continue;
+ else if (!(mask & CD_TYPE_AS_MASK(type)))
+ continue;
+ else if ((maxnumber != -1) && (number >= maxnumber))
+ continue;
+ else if (CustomData_get_layer_named(dest, type, layer->name))
+ continue;
+
+ switch (alloctype) {
+ case CD_ASSIGN:
+ case CD_REFERENCE:
+ case CD_DUPLICATE:
+ data = layer->data;
+ break;
+ default:
+ data = NULL;
+ break;
+ }
+
+ if ((alloctype == CD_ASSIGN) && (flag & CD_FLAG_NOFREE)) {
+ newlayer = customData_add_layer__internal(
+ dest, type, CD_REFERENCE, data, totelem, layer->name);
+ }
+ else {
+ newlayer = customData_add_layer__internal(dest, type, alloctype, data, totelem, layer->name);
+ }
+
+ if (newlayer) {
+ newlayer->uid = layer->uid;
+
+ newlayer->active = lastactive;
+ newlayer->active_rnd = lastrender;
+ newlayer->active_clone = lastclone;
+ newlayer->active_mask = lastmask;
+ newlayer->flag |= flag & (CD_FLAG_EXTERNAL | CD_FLAG_IN_MEMORY);
+ changed = true;
+ }
+ }
+
+ CustomData_update_typemap(dest);
+ return changed;
}
/* NOTE: Take care of referenced layers by yourself! */
void CustomData_realloc(CustomData *data, int totelem)
{
- int i;
- for (i = 0; i < data->totlayer; ++i) {
- CustomDataLayer *layer = &data->layers[i];
- const LayerTypeInfo *typeInfo;
- if (layer->flag & CD_FLAG_NOFREE) {
- continue;
- }
- typeInfo = layerType_getInfo(layer->type);
- layer->data = MEM_reallocN(layer->data, (size_t)totelem * typeInfo->size);
- }
+ int i;
+ for (i = 0; i < data->totlayer; ++i) {
+ CustomDataLayer *layer = &data->layers[i];
+ const LayerTypeInfo *typeInfo;
+ if (layer->flag & CD_FLAG_NOFREE) {
+ continue;
+ }
+ typeInfo = layerType_getInfo(layer->type);
+ layer->data = MEM_reallocN(layer->data, (size_t)totelem * typeInfo->size);
+ }
}
-void CustomData_copy(
- const struct CustomData *source, struct CustomData *dest,
- CustomDataMask mask, eCDAllocType alloctype, int totelem)
+void CustomData_copy(const struct CustomData *source,
+ struct CustomData *dest,
+ CustomDataMask mask,
+ eCDAllocType alloctype,
+ int totelem)
{
- CustomData_reset(dest);
+ CustomData_reset(dest);
- if (source->external)
- dest->external = MEM_dupallocN(source->external);
+ if (source->external)
+ dest->external = MEM_dupallocN(source->external);
- CustomData_merge(source, dest, mask, alloctype, totelem);
+ CustomData_merge(source, dest, mask, alloctype, totelem);
}
static void customData_free_layer__internal(CustomDataLayer *layer, int totelem)
{
- const LayerTypeInfo *typeInfo;
+ const LayerTypeInfo *typeInfo;
- if (!(layer->flag & CD_FLAG_NOFREE) && layer->data) {
- typeInfo = layerType_getInfo(layer->type);
+ if (!(layer->flag & CD_FLAG_NOFREE) && layer->data) {
+ typeInfo = layerType_getInfo(layer->type);
- if (typeInfo->free)
- typeInfo->free(layer->data, totelem, typeInfo->size);
+ if (typeInfo->free)
+ typeInfo->free(layer->data, totelem, typeInfo->size);
- if (layer->data)
- MEM_freeN(layer->data);
- }
+ if (layer->data)
+ MEM_freeN(layer->data);
+ }
}
static void CustomData_external_free(CustomData *data)
{
- if (data->external) {
- MEM_freeN(data->external);
- data->external = NULL;
- }
+ if (data->external) {
+ MEM_freeN(data->external);
+ data->external = NULL;
+ }
}
void CustomData_reset(CustomData *data)
{
- memset(data, 0, sizeof(*data));
- copy_vn_i(data->typemap, CD_NUMTYPES, -1);
+ memset(data, 0, sizeof(*data));
+ copy_vn_i(data->typemap, CD_NUMTYPES, -1);
}
void CustomData_free(CustomData *data, int totelem)
{
- int i;
+ int i;
- for (i = 0; i < data->totlayer; ++i)
- customData_free_layer__internal(&data->layers[i], totelem);
+ for (i = 0; i < data->totlayer; ++i)
+ customData_free_layer__internal(&data->layers[i], totelem);
- if (data->layers)
- MEM_freeN(data->layers);
+ if (data->layers)
+ MEM_freeN(data->layers);
- CustomData_external_free(data);
- CustomData_reset(data);
+ CustomData_external_free(data);
+ CustomData_reset(data);
}
void CustomData_free_typemask(struct CustomData *data, int totelem, CustomDataMask mask)
{
- int i;
+ int i;
- for (i = 0; i < data->totlayer; ++i) {
- CustomDataLayer *layer = &data->layers[i];
- if (!(mask & CD_TYPE_AS_MASK(layer->type))) {
- continue;
- }
- customData_free_layer__internal(layer, totelem);
- }
+ for (i = 0; i < data->totlayer; ++i) {
+ CustomDataLayer *layer = &data->layers[i];
+ if (!(mask & CD_TYPE_AS_MASK(layer->type))) {
+ continue;
+ }
+ customData_free_layer__internal(layer, totelem);
+ }
- if (data->layers)
- MEM_freeN(data->layers);
+ if (data->layers)
+ MEM_freeN(data->layers);
- CustomData_external_free(data);
- CustomData_reset(data);
+ CustomData_external_free(data);
+ CustomData_reset(data);
}
static void customData_update_offsets(CustomData *data)
{
- const LayerTypeInfo *typeInfo;
- int i, offset = 0;
+ const LayerTypeInfo *typeInfo;
+ int i, offset = 0;
- for (i = 0; i < data->totlayer; ++i) {
- typeInfo = layerType_getInfo(data->layers[i].type);
+ for (i = 0; i < data->totlayer; ++i) {
+ typeInfo = layerType_getInfo(data->layers[i].type);
- data->layers[i].offset = offset;
- offset += typeInfo->size;
- }
+ data->layers[i].offset = offset;
+ offset += typeInfo->size;
+ }
- data->totsize = offset;
- CustomData_update_typemap(data);
+ data->totsize = offset;
+ CustomData_update_typemap(data);
}
/* to use when we're in the middle of modifying layers */
static int CustomData_get_layer_index__notypemap(const CustomData *data, int type)
{
- int i;
+ int i;
- for (i = 0; i < data->totlayer; ++i)
- if (data->layers[i].type == type)
- return i;
+ for (i = 0; i < data->totlayer; ++i)
+ if (data->layers[i].type == type)
+ return i;
- return -1;
+ return -1;
}
/* -------------------------------------------------------------------- */
@@ -1747,736 +2012,768 @@ static int CustomData_get_layer_index__notypemap(const CustomData *data, int typ
int CustomData_get_layer_index(const CustomData *data, int type)
{
- BLI_assert(customdata_typemap_is_valid(data));
- return data->typemap[type];
+ BLI_assert(customdata_typemap_is_valid(data));
+ return data->typemap[type];
}
int CustomData_get_layer_index_n(const struct CustomData *data, int type, int n)
{
- int i = CustomData_get_layer_index(data, type);
+ int i = CustomData_get_layer_index(data, type);
- if (i != -1) {
- BLI_assert(i + n < data->totlayer);
- i = (data->layers[i + n].type == type) ? (i + n) : (-1);
- }
+ if (i != -1) {
+ BLI_assert(i + n < data->totlayer);
+ i = (data->layers[i + n].type == type) ? (i + n) : (-1);
+ }
- return i;
+ return i;
}
int CustomData_get_named_layer_index(const CustomData *data, int type, const char *name)
{
- int i;
+ int i;
- for (i = 0; i < data->totlayer; ++i)
- if (data->layers[i].type == type)
- if (STREQ(data->layers[i].name, name))
- return i;
+ for (i = 0; i < data->totlayer; ++i)
+ if (data->layers[i].type == type)
+ if (STREQ(data->layers[i].name, name))
+ return i;
- return -1;
+ return -1;
}
int CustomData_get_active_layer_index(const CustomData *data, int type)
{
- const int layer_index = data->typemap[type];
- BLI_assert(customdata_typemap_is_valid(data));
- return (layer_index != -1) ? layer_index + data->layers[layer_index].active : -1;
+ const int layer_index = data->typemap[type];
+ BLI_assert(customdata_typemap_is_valid(data));
+ return (layer_index != -1) ? layer_index + data->layers[layer_index].active : -1;
}
int CustomData_get_render_layer_index(const CustomData *data, int type)
{
- const int layer_index = data->typemap[type];
- BLI_assert(customdata_typemap_is_valid(data));
- return (layer_index != -1) ? layer_index + data->layers[layer_index].active_rnd : -1;
+ const int layer_index = data->typemap[type];
+ BLI_assert(customdata_typemap_is_valid(data));
+ return (layer_index != -1) ? layer_index + data->layers[layer_index].active_rnd : -1;
}
int CustomData_get_clone_layer_index(const CustomData *data, int type)
{
- const int layer_index = data->typemap[type];
- BLI_assert(customdata_typemap_is_valid(data));
- return (layer_index != -1) ? layer_index + data->layers[layer_index].active_clone : -1;
+ const int layer_index = data->typemap[type];
+ BLI_assert(customdata_typemap_is_valid(data));
+ return (layer_index != -1) ? layer_index + data->layers[layer_index].active_clone : -1;
}
int CustomData_get_stencil_layer_index(const CustomData *data, int type)
{
- const int layer_index = data->typemap[type];
- BLI_assert(customdata_typemap_is_valid(data));
- return (layer_index != -1) ? layer_index + data->layers[layer_index].active_mask : -1;
+ const int layer_index = data->typemap[type];
+ BLI_assert(customdata_typemap_is_valid(data));
+ return (layer_index != -1) ? layer_index + data->layers[layer_index].active_mask : -1;
}
-
/* -------------------------------------------------------------------- */
/* index values per layer type */
int CustomData_get_named_layer(const struct CustomData *data, int type, const char *name)
{
- const int named_index = CustomData_get_named_layer_index(data, type, name);
- const int layer_index = data->typemap[type];
- BLI_assert(customdata_typemap_is_valid(data));
- return (named_index != -1) ? named_index - layer_index : -1;
+ const int named_index = CustomData_get_named_layer_index(data, type, name);
+ const int layer_index = data->typemap[type];
+ BLI_assert(customdata_typemap_is_valid(data));
+ return (named_index != -1) ? named_index - layer_index : -1;
}
int CustomData_get_active_layer(const CustomData *data, int type)
{
- const int layer_index = data->typemap[type];
- BLI_assert(customdata_typemap_is_valid(data));
- return (layer_index != -1) ? data->layers[layer_index].active : -1;
+ const int layer_index = data->typemap[type];
+ BLI_assert(customdata_typemap_is_valid(data));
+ return (layer_index != -1) ? data->layers[layer_index].active : -1;
}
int CustomData_get_render_layer(const CustomData *data, int type)
{
- const int layer_index = data->typemap[type];
- BLI_assert(customdata_typemap_is_valid(data));
- return (layer_index != -1) ? data->layers[layer_index].active_rnd : -1;
+ const int layer_index = data->typemap[type];
+ BLI_assert(customdata_typemap_is_valid(data));
+ return (layer_index != -1) ? data->layers[layer_index].active_rnd : -1;
}
int CustomData_get_clone_layer(const CustomData *data, int type)
{
- const int layer_index = data->typemap[type];
- BLI_assert(customdata_typemap_is_valid(data));
- return (layer_index != -1) ? data->layers[layer_index].active_clone : -1;
+ const int layer_index = data->typemap[type];
+ BLI_assert(customdata_typemap_is_valid(data));
+ return (layer_index != -1) ? data->layers[layer_index].active_clone : -1;
}
int CustomData_get_stencil_layer(const CustomData *data, int type)
{
- const int layer_index = data->typemap[type];
- BLI_assert(customdata_typemap_is_valid(data));
- return (layer_index != -1) ? data->layers[layer_index].active_mask : -1;
+ const int layer_index = data->typemap[type];
+ BLI_assert(customdata_typemap_is_valid(data));
+ return (layer_index != -1) ? data->layers[layer_index].active_mask : -1;
}
void CustomData_set_layer_active(CustomData *data, int type, int n)
{
- int i;
+ int i;
- for (i = 0; i < data->totlayer; ++i)
- if (data->layers[i].type == type)
- data->layers[i].active = n;
+ for (i = 0; i < data->totlayer; ++i)
+ if (data->layers[i].type == type)
+ data->layers[i].active = n;
}
void CustomData_set_layer_render(CustomData *data, int type, int n)
{
- int i;
+ int i;
- for (i = 0; i < data->totlayer; ++i)
- if (data->layers[i].type == type)
- data->layers[i].active_rnd = n;
+ for (i = 0; i < data->totlayer; ++i)
+ if (data->layers[i].type == type)
+ data->layers[i].active_rnd = n;
}
void CustomData_set_layer_clone(CustomData *data, int type, int n)
{
- int i;
+ int i;
- for (i = 0; i < data->totlayer; ++i)
- if (data->layers[i].type == type)
- data->layers[i].active_clone = n;
+ for (i = 0; i < data->totlayer; ++i)
+ if (data->layers[i].type == type)
+ data->layers[i].active_clone = n;
}
void CustomData_set_layer_stencil(CustomData *data, int type, int n)
{
- int i;
+ int i;
- for (i = 0; i < data->totlayer; ++i)
- if (data->layers[i].type == type)
- data->layers[i].active_mask = n;
+ for (i = 0; i < data->totlayer; ++i)
+ if (data->layers[i].type == type)
+ data->layers[i].active_mask = n;
}
/* for using with an index from CustomData_get_active_layer_index and CustomData_get_render_layer_index */
void CustomData_set_layer_active_index(CustomData *data, int type, int n)
{
- int i;
+ int i;
- for (i = 0; i < data->totlayer; ++i)
- if (data->layers[i].type == type)
- data->layers[i].active = n - i;
+ for (i = 0; i < data->totlayer; ++i)
+ if (data->layers[i].type == type)
+ data->layers[i].active = n - i;
}
void CustomData_set_layer_render_index(CustomData *data, int type, int n)
{
- int i;
+ int i;
- for (i = 0; i < data->totlayer; ++i)
- if (data->layers[i].type == type)
- data->layers[i].active_rnd = n - i;
+ for (i = 0; i < data->totlayer; ++i)
+ if (data->layers[i].type == type)
+ data->layers[i].active_rnd = n - i;
}
void CustomData_set_layer_clone_index(CustomData *data, int type, int n)
{
- int i;
+ int i;
- for (i = 0; i < data->totlayer; ++i)
- if (data->layers[i].type == type)
- data->layers[i].active_clone = n - i;
+ for (i = 0; i < data->totlayer; ++i)
+ if (data->layers[i].type == type)
+ data->layers[i].active_clone = n - i;
}
void CustomData_set_layer_stencil_index(CustomData *data, int type, int n)
{
- int i;
+ int i;
- for (i = 0; i < data->totlayer; ++i)
- if (data->layers[i].type == type)
- data->layers[i].active_mask = n - i;
+ for (i = 0; i < data->totlayer; ++i)
+ if (data->layers[i].type == type)
+ data->layers[i].active_mask = n - i;
}
void CustomData_set_layer_flag(struct CustomData *data, int type, int flag)
{
- int i;
+ int i;
- for (i = 0; i < data->totlayer; ++i)
- if (data->layers[i].type == type)
- data->layers[i].flag |= flag;
+ for (i = 0; i < data->totlayer; ++i)
+ if (data->layers[i].type == type)
+ data->layers[i].flag |= flag;
}
void CustomData_clear_layer_flag(struct CustomData *data, int type, int flag)
{
- const int nflag = ~flag;
+ const int nflag = ~flag;
- for (int i = 0; i < data->totlayer; ++i) {
- if (data->layers[i].type == type) {
- data->layers[i].flag &= nflag;
- }
- }
+ for (int i = 0; i < data->totlayer; ++i) {
+ if (data->layers[i].type == type) {
+ data->layers[i].flag &= nflag;
+ }
+ }
}
static int customData_resize(CustomData *data, int amount)
{
- CustomDataLayer *tmp = MEM_calloc_arrayN((data->maxlayer + amount), sizeof(*tmp),
- "CustomData->layers");
- if (!tmp) return 0;
-
- data->maxlayer += amount;
- if (data->layers) {
- memcpy(tmp, data->layers, sizeof(*tmp) * data->totlayer);
- MEM_freeN(data->layers);
- }
- data->layers = tmp;
-
- return 1;
-}
-
-static CustomDataLayer *customData_add_layer__internal(
- CustomData *data, int type, eCDAllocType alloctype, void *layerdata,
- int totelem, const char *name)
-{
- const LayerTypeInfo *typeInfo = layerType_getInfo(type);
- int flag = 0, index = data->totlayer;
- void *newlayerdata = NULL;
-
- /* Passing a layerdata to copy from with an alloctype that won't copy is
- * most likely a bug */
- BLI_assert(!layerdata ||
- (alloctype == CD_ASSIGN) ||
- (alloctype == CD_DUPLICATE) ||
- (alloctype == CD_REFERENCE));
-
- if (!typeInfo->defaultname && CustomData_has_layer(data, type))
- return &data->layers[CustomData_get_layer_index(data, type)];
-
- if ((alloctype == CD_ASSIGN) || (alloctype == CD_REFERENCE)) {
- newlayerdata = layerdata;
- }
- else if (totelem > 0 && typeInfo->size > 0) {
- if (alloctype == CD_DUPLICATE && layerdata) {
- newlayerdata = MEM_malloc_arrayN((size_t)totelem, typeInfo->size, layerType_getName(type));
- }
- else {
- newlayerdata = MEM_calloc_arrayN((size_t)totelem, typeInfo->size, layerType_getName(type));
- }
-
- if (!newlayerdata)
- return NULL;
- }
-
- if (alloctype == CD_DUPLICATE && layerdata) {
- if (typeInfo->copy)
- typeInfo->copy(layerdata, newlayerdata, totelem);
- else
- memcpy(newlayerdata, layerdata, (size_t)totelem * typeInfo->size);
- }
- else if (alloctype == CD_DEFAULT) {
- if (typeInfo->set_default)
- typeInfo->set_default(newlayerdata, totelem);
- }
- else if (alloctype == CD_REFERENCE)
- flag |= CD_FLAG_NOFREE;
-
- if (index >= data->maxlayer) {
- if (!customData_resize(data, CUSTOMDATA_GROW)) {
- if (newlayerdata != layerdata)
- MEM_freeN(newlayerdata);
- return NULL;
- }
- }
-
- data->totlayer++;
-
- /* keep layers ordered by type */
- for (; index > 0 && data->layers[index - 1].type > type; --index)
- data->layers[index] = data->layers[index - 1];
-
- data->layers[index].type = type;
- data->layers[index].flag = flag;
- data->layers[index].data = newlayerdata;
-
- /* Set default name if none exists. Note we only call DATA_() once
- * we know there is a default name, to avoid overhead of locale lookups
- * in the depsgraph. */
- if (!name && typeInfo->defaultname) {
- name = DATA_(typeInfo->defaultname);
- }
-
- if (name) {
- BLI_strncpy(data->layers[index].name, name, sizeof(data->layers[index].name));
- CustomData_set_layer_unique_name(data, index);
- }
- else
- data->layers[index].name[0] = '\0';
-
- if (index > 0 && data->layers[index - 1].type == type) {
- data->layers[index].active = data->layers[index - 1].active;
- data->layers[index].active_rnd = data->layers[index - 1].active_rnd;
- data->layers[index].active_clone = data->layers[index - 1].active_clone;
- data->layers[index].active_mask = data->layers[index - 1].active_mask;
- }
- else {
- data->layers[index].active = 0;
- data->layers[index].active_rnd = 0;
- data->layers[index].active_clone = 0;
- data->layers[index].active_mask = 0;
- }
-
- customData_update_offsets(data);
-
- return &data->layers[index];
+ CustomDataLayer *tmp = MEM_calloc_arrayN(
+ (data->maxlayer + amount), sizeof(*tmp), "CustomData->layers");
+ if (!tmp)
+ return 0;
+
+ data->maxlayer += amount;
+ if (data->layers) {
+ memcpy(tmp, data->layers, sizeof(*tmp) * data->totlayer);
+ MEM_freeN(data->layers);
+ }
+ data->layers = tmp;
+
+ return 1;
+}
+
+static CustomDataLayer *customData_add_layer__internal(CustomData *data,
+ int type,
+ eCDAllocType alloctype,
+ void *layerdata,
+ int totelem,
+ const char *name)
+{
+ const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+ int flag = 0, index = data->totlayer;
+ void *newlayerdata = NULL;
+
+ /* Passing a layerdata to copy from with an alloctype that won't copy is
+ * most likely a bug */
+ BLI_assert(!layerdata || (alloctype == CD_ASSIGN) || (alloctype == CD_DUPLICATE) ||
+ (alloctype == CD_REFERENCE));
+
+ if (!typeInfo->defaultname && CustomData_has_layer(data, type))
+ return &data->layers[CustomData_get_layer_index(data, type)];
+
+ if ((alloctype == CD_ASSIGN) || (alloctype == CD_REFERENCE)) {
+ newlayerdata = layerdata;
+ }
+ else if (totelem > 0 && typeInfo->size > 0) {
+ if (alloctype == CD_DUPLICATE && layerdata) {
+ newlayerdata = MEM_malloc_arrayN((size_t)totelem, typeInfo->size, layerType_getName(type));
+ }
+ else {
+ newlayerdata = MEM_calloc_arrayN((size_t)totelem, typeInfo->size, layerType_getName(type));
+ }
+
+ if (!newlayerdata)
+ return NULL;
+ }
+
+ if (alloctype == CD_DUPLICATE && layerdata) {
+ if (typeInfo->copy)
+ typeInfo->copy(layerdata, newlayerdata, totelem);
+ else
+ memcpy(newlayerdata, layerdata, (size_t)totelem * typeInfo->size);
+ }
+ else if (alloctype == CD_DEFAULT) {
+ if (typeInfo->set_default)
+ typeInfo->set_default(newlayerdata, totelem);
+ }
+ else if (alloctype == CD_REFERENCE)
+ flag |= CD_FLAG_NOFREE;
+
+ if (index >= data->maxlayer) {
+ if (!customData_resize(data, CUSTOMDATA_GROW)) {
+ if (newlayerdata != layerdata)
+ MEM_freeN(newlayerdata);
+ return NULL;
+ }
+ }
+
+ data->totlayer++;
+
+ /* keep layers ordered by type */
+ for (; index > 0 && data->layers[index - 1].type > type; --index)
+ data->layers[index] = data->layers[index - 1];
+
+ data->layers[index].type = type;
+ data->layers[index].flag = flag;
+ data->layers[index].data = newlayerdata;
+
+ /* Set default name if none exists. Note we only call DATA_() once
+ * we know there is a default name, to avoid overhead of locale lookups
+ * in the depsgraph. */
+ if (!name && typeInfo->defaultname) {
+ name = DATA_(typeInfo->defaultname);
+ }
+
+ if (name) {
+ BLI_strncpy(data->layers[index].name, name, sizeof(data->layers[index].name));
+ CustomData_set_layer_unique_name(data, index);
+ }
+ else
+ data->layers[index].name[0] = '\0';
+
+ if (index > 0 && data->layers[index - 1].type == type) {
+ data->layers[index].active = data->layers[index - 1].active;
+ data->layers[index].active_rnd = data->layers[index - 1].active_rnd;
+ data->layers[index].active_clone = data->layers[index - 1].active_clone;
+ data->layers[index].active_mask = data->layers[index - 1].active_mask;
+ }
+ else {
+ data->layers[index].active = 0;
+ data->layers[index].active_rnd = 0;
+ data->layers[index].active_clone = 0;
+ data->layers[index].active_mask = 0;
+ }
+
+ customData_update_offsets(data);
+
+ return &data->layers[index];
}
void *CustomData_add_layer(
- CustomData *data, int type, eCDAllocType alloctype,
- void *layerdata, int totelem)
+ CustomData *data, int type, eCDAllocType alloctype, void *layerdata, int totelem)
{
- CustomDataLayer *layer;
- const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+ CustomDataLayer *layer;
+ const LayerTypeInfo *typeInfo = layerType_getInfo(type);
- layer = customData_add_layer__internal(data, type, alloctype, layerdata,
- totelem, typeInfo->defaultname);
- CustomData_update_typemap(data);
+ layer = customData_add_layer__internal(
+ data, type, alloctype, layerdata, totelem, typeInfo->defaultname);
+ CustomData_update_typemap(data);
- if (layer)
- return layer->data;
+ if (layer)
+ return layer->data;
- return NULL;
+ return NULL;
}
/*same as above but accepts a name*/
-void *CustomData_add_layer_named(
- CustomData *data, int type, eCDAllocType alloctype,
- void *layerdata, int totelem, const char *name)
+void *CustomData_add_layer_named(CustomData *data,
+ int type,
+ eCDAllocType alloctype,
+ void *layerdata,
+ int totelem,
+ const char *name)
{
- CustomDataLayer *layer;
+ CustomDataLayer *layer;
- layer = customData_add_layer__internal(data, type, alloctype, layerdata,
- totelem, name);
- CustomData_update_typemap(data);
+ layer = customData_add_layer__internal(data, type, alloctype, layerdata, totelem, name);
+ CustomData_update_typemap(data);
- if (layer)
- return layer->data;
+ if (layer)
+ return layer->data;
- return NULL;
+ return NULL;
}
-
bool CustomData_free_layer(CustomData *data, int type, int totelem, int index)
{
- const int index_first = CustomData_get_layer_index(data, type);
- const int n = index - index_first;
- int i;
+ const int index_first = CustomData_get_layer_index(data, type);
+ const int n = index - index_first;
+ int i;
- BLI_assert(index >= index_first);
- if ((index_first == -1) || (n < 0)) {
- return false;
- }
- BLI_assert(data->layers[index].type == type);
+ BLI_assert(index >= index_first);
+ if ((index_first == -1) || (n < 0)) {
+ return false;
+ }
+ BLI_assert(data->layers[index].type == type);
- customData_free_layer__internal(&data->layers[index], totelem);
+ customData_free_layer__internal(&data->layers[index], totelem);
- for (i = index + 1; i < data->totlayer; ++i)
- data->layers[i - 1] = data->layers[i];
+ for (i = index + 1; i < data->totlayer; ++i)
+ data->layers[i - 1] = data->layers[i];
- data->totlayer--;
+ data->totlayer--;
- /* if layer was last of type in array, set new active layer */
- i = CustomData_get_layer_index__notypemap(data, type);
+ /* if layer was last of type in array, set new active layer */
+ i = CustomData_get_layer_index__notypemap(data, type);
- if (i != -1) {
- /* don't decrement zero index */
- const int index_nonzero = n ? n : 1;
- CustomDataLayer *layer;
+ if (i != -1) {
+ /* don't decrement zero index */
+ const int index_nonzero = n ? n : 1;
+ CustomDataLayer *layer;
- for (layer = &data->layers[i]; i < data->totlayer && layer->type == type; i++, layer++) {
- if (layer->active >= index_nonzero) layer->active--;
- if (layer->active_rnd >= index_nonzero) layer->active_rnd--;
- if (layer->active_clone >= index_nonzero) layer->active_clone--;
- if (layer->active_mask >= index_nonzero) layer->active_mask--;
- }
- }
+ for (layer = &data->layers[i]; i < data->totlayer && layer->type == type; i++, layer++) {
+ if (layer->active >= index_nonzero)
+ layer->active--;
+ if (layer->active_rnd >= index_nonzero)
+ layer->active_rnd--;
+ if (layer->active_clone >= index_nonzero)
+ layer->active_clone--;
+ if (layer->active_mask >= index_nonzero)
+ layer->active_mask--;
+ }
+ }
- if (data->totlayer <= data->maxlayer - CUSTOMDATA_GROW)
- customData_resize(data, -CUSTOMDATA_GROW);
+ if (data->totlayer <= data->maxlayer - CUSTOMDATA_GROW)
+ customData_resize(data, -CUSTOMDATA_GROW);
- customData_update_offsets(data);
+ customData_update_offsets(data);
- return true;
+ return true;
}
bool CustomData_free_layer_active(CustomData *data, int type, int totelem)
{
- int index = 0;
- index = CustomData_get_active_layer_index(data, type);
- if (index == -1)
- return false;
- return CustomData_free_layer(data, type, totelem, index);
+ int index = 0;
+ index = CustomData_get_active_layer_index(data, type);
+ if (index == -1)
+ return false;
+ return CustomData_free_layer(data, type, totelem, index);
}
-
void CustomData_free_layers(CustomData *data, int type, int totelem)
{
- const int index = CustomData_get_layer_index(data, type);
- while (CustomData_free_layer(data, type, totelem, index)) {
- /* pass */
- }
+ const int index = CustomData_get_layer_index(data, type);
+ while (CustomData_free_layer(data, type, totelem, index)) {
+ /* pass */
+ }
}
bool CustomData_has_layer(const CustomData *data, int type)
{
- return (CustomData_get_layer_index(data, type) != -1);
+ return (CustomData_get_layer_index(data, type) != -1);
}
int CustomData_number_of_layers(const CustomData *data, int type)
{
- int i, number = 0;
+ int i, number = 0;
- for (i = 0; i < data->totlayer; i++)
- if (data->layers[i].type == type)
- number++;
+ for (i = 0; i < data->totlayer; i++)
+ if (data->layers[i].type == type)
+ number++;
- return number;
+ return number;
}
int CustomData_number_of_layers_typemask(const CustomData *data, CustomDataMask mask)
{
- int i, number = 0;
+ int i, number = 0;
- for (i = 0; i < data->totlayer; i++)
- if (mask & CD_TYPE_AS_MASK(data->layers[i].type))
- number++;
+ for (i = 0; i < data->totlayer; i++)
+ if (mask & CD_TYPE_AS_MASK(data->layers[i].type))
+ number++;
- return number;
+ return number;
}
-static void *customData_duplicate_referenced_layer_index(CustomData *data, const int layer_index, const int totelem)
+static void *customData_duplicate_referenced_layer_index(CustomData *data,
+ const int layer_index,
+ const int totelem)
{
- CustomDataLayer *layer;
+ CustomDataLayer *layer;
- if (layer_index == -1) {
- return NULL;
- }
+ if (layer_index == -1) {
+ return NULL;
+ }
- layer = &data->layers[layer_index];
+ layer = &data->layers[layer_index];
- if (layer->flag & CD_FLAG_NOFREE) {
- /* MEM_dupallocN won't work in case of complex layers, like e.g.
- * CD_MDEFORMVERT, which has pointers to allocated data...
- * So in case a custom copy function is defined, use it!
- */
- const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
+ if (layer->flag & CD_FLAG_NOFREE) {
+ /* MEM_dupallocN won't work in case of complex layers, like e.g.
+ * CD_MDEFORMVERT, which has pointers to allocated data...
+ * So in case a custom copy function is defined, use it!
+ */
+ const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
- if (typeInfo->copy) {
- void *dst_data = MEM_malloc_arrayN((size_t)totelem, typeInfo->size, "CD duplicate ref layer");
- typeInfo->copy(layer->data, dst_data, totelem);
- layer->data = dst_data;
- }
- else {
- layer->data = MEM_dupallocN(layer->data);
- }
+ if (typeInfo->copy) {
+ void *dst_data = MEM_malloc_arrayN(
+ (size_t)totelem, typeInfo->size, "CD duplicate ref layer");
+ typeInfo->copy(layer->data, dst_data, totelem);
+ layer->data = dst_data;
+ }
+ else {
+ layer->data = MEM_dupallocN(layer->data);
+ }
- layer->flag &= ~CD_FLAG_NOFREE;
- }
+ layer->flag &= ~CD_FLAG_NOFREE;
+ }
- return layer->data;
+ return layer->data;
}
void *CustomData_duplicate_referenced_layer(CustomData *data, const int type, const int totelem)
{
- int layer_index;
+ int layer_index;
- /* get the layer index of the first layer of type */
- layer_index = CustomData_get_active_layer_index(data, type);
+ /* get the layer index of the first layer of type */
+ layer_index = CustomData_get_active_layer_index(data, type);
- return customData_duplicate_referenced_layer_index(data, layer_index, totelem);
+ return customData_duplicate_referenced_layer_index(data, layer_index, totelem);
}
-void *CustomData_duplicate_referenced_layer_n(CustomData *data, const int type, const int n, const int totelem)
+void *CustomData_duplicate_referenced_layer_n(CustomData *data,
+ const int type,
+ const int n,
+ const int totelem)
{
- int layer_index;
+ int layer_index;
- /* get the layer index of the desired layer */
- layer_index = CustomData_get_layer_index_n(data, type, n);
+ /* get the layer index of the desired layer */
+ layer_index = CustomData_get_layer_index_n(data, type, n);
- return customData_duplicate_referenced_layer_index(data, layer_index, totelem);
+ return customData_duplicate_referenced_layer_index(data, layer_index, totelem);
}
-void *CustomData_duplicate_referenced_layer_named(CustomData *data, const int type, const char *name, const int totelem)
+void *CustomData_duplicate_referenced_layer_named(CustomData *data,
+ const int type,
+ const char *name,
+ const int totelem)
{
- int layer_index;
+ int layer_index;
- /* get the layer index of the desired layer */
- layer_index = CustomData_get_named_layer_index(data, type, name);
+ /* get the layer index of the desired layer */
+ layer_index = CustomData_get_named_layer_index(data, type, name);
- return customData_duplicate_referenced_layer_index(data, layer_index, totelem);
+ return customData_duplicate_referenced_layer_index(data, layer_index, totelem);
}
bool CustomData_is_referenced_layer(struct CustomData *data, int type)
{
- CustomDataLayer *layer;
- int layer_index;
+ CustomDataLayer *layer;
+ int layer_index;
- /* get the layer index of the first layer of type */
- layer_index = CustomData_get_active_layer_index(data, type);
- if (layer_index == -1)
- return false;
+ /* get the layer index of the first layer of type */
+ layer_index = CustomData_get_active_layer_index(data, type);
+ if (layer_index == -1)
+ return false;
- layer = &data->layers[layer_index];
+ layer = &data->layers[layer_index];
- return (layer->flag & CD_FLAG_NOFREE) != 0;
+ return (layer->flag & CD_FLAG_NOFREE) != 0;
}
void CustomData_free_temporary(CustomData *data, int totelem)
{
- CustomDataLayer *layer;
- int i, j;
- bool changed = false;
+ CustomDataLayer *layer;
+ int i, j;
+ bool changed = false;
- for (i = 0, j = 0; i < data->totlayer; ++i) {
- layer = &data->layers[i];
+ for (i = 0, j = 0; i < data->totlayer; ++i) {
+ layer = &data->layers[i];
- if (i != j)
- data->layers[j] = data->layers[i];
+ if (i != j)
+ data->layers[j] = data->layers[i];
- if ((layer->flag & CD_FLAG_TEMPORARY) == CD_FLAG_TEMPORARY) {
- customData_free_layer__internal(layer, totelem);
- changed = true;
- }
- else
- j++;
- }
+ if ((layer->flag & CD_FLAG_TEMPORARY) == CD_FLAG_TEMPORARY) {
+ customData_free_layer__internal(layer, totelem);
+ changed = true;
+ }
+ else
+ j++;
+ }
- data->totlayer = j;
+ data->totlayer = j;
- if (data->totlayer <= data->maxlayer - CUSTOMDATA_GROW) {
- customData_resize(data, -CUSTOMDATA_GROW);
- changed = true;
- }
+ if (data->totlayer <= data->maxlayer - CUSTOMDATA_GROW) {
+ customData_resize(data, -CUSTOMDATA_GROW);
+ changed = true;
+ }
- if (changed) {
- customData_update_offsets(data);
- }
+ if (changed) {
+ customData_update_offsets(data);
+ }
}
-void CustomData_set_only_copy(const struct CustomData *data,
- CustomDataMask mask)
+void CustomData_set_only_copy(const struct CustomData *data, CustomDataMask mask)
{
- int i;
+ int i;
- for (i = 0; i < data->totlayer; ++i)
- if (!(mask & CD_TYPE_AS_MASK(data->layers[i].type)))
- data->layers[i].flag |= CD_FLAG_NOCOPY;
+ for (i = 0; i < data->totlayer; ++i)
+ if (!(mask & CD_TYPE_AS_MASK(data->layers[i].type)))
+ data->layers[i].flag |= CD_FLAG_NOCOPY;
}
void CustomData_copy_elements(int type, void *src_data_ofs, void *dst_data_ofs, int count)
{
- const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+ const LayerTypeInfo *typeInfo = layerType_getInfo(type);
- if (typeInfo->copy)
- typeInfo->copy(src_data_ofs, dst_data_ofs, count);
- else
- memcpy(dst_data_ofs, src_data_ofs, (size_t)count * typeInfo->size);
+ if (typeInfo->copy)
+ typeInfo->copy(src_data_ofs, dst_data_ofs, count);
+ else
+ memcpy(dst_data_ofs, src_data_ofs, (size_t)count * typeInfo->size);
}
-static void CustomData_copy_data_layer(
- const CustomData *source, CustomData *dest,
- int src_i, int dst_i,
- int src_index, int dst_index, int count)
+static void CustomData_copy_data_layer(const CustomData *source,
+ CustomData *dest,
+ int src_i,
+ int dst_i,
+ int src_index,
+ int dst_index,
+ int count)
{
- const LayerTypeInfo *typeInfo;
+ const LayerTypeInfo *typeInfo;
- const void *src_data = source->layers[src_i].data;
- void *dst_data = dest->layers[dst_i].data;
+ const void *src_data = source->layers[src_i].data;
+ void *dst_data = dest->layers[dst_i].data;
- typeInfo = layerType_getInfo(source->layers[src_i].type);
+ typeInfo = layerType_getInfo(source->layers[src_i].type);
- const size_t src_offset = (size_t)src_index * typeInfo->size;
- const size_t dst_offset = (size_t)dst_index * typeInfo->size;
+ const size_t src_offset = (size_t)src_index * typeInfo->size;
+ const size_t dst_offset = (size_t)dst_index * typeInfo->size;
- if (!count || !src_data || !dst_data) {
- if (count && !(src_data == NULL && dst_data == NULL)) {
- CLOG_WARN(&LOG, "null data for %s type (%p --> %p), skipping",
- layerType_getName(source->layers[src_i].type),
- (void *)src_data, (void *)dst_data);
- }
- return;
- }
+ if (!count || !src_data || !dst_data) {
+ if (count && !(src_data == NULL && dst_data == NULL)) {
+ CLOG_WARN(&LOG,
+ "null data for %s type (%p --> %p), skipping",
+ layerType_getName(source->layers[src_i].type),
+ (void *)src_data,
+ (void *)dst_data);
+ }
+ return;
+ }
- if (typeInfo->copy) {
- typeInfo->copy(POINTER_OFFSET(src_data, src_offset),
- POINTER_OFFSET(dst_data, dst_offset),
- count);
- }
- else {
- memcpy(POINTER_OFFSET(dst_data, dst_offset),
- POINTER_OFFSET(src_data, src_offset),
- (size_t)count * typeInfo->size);
- }
+ if (typeInfo->copy) {
+ typeInfo->copy(
+ POINTER_OFFSET(src_data, src_offset), POINTER_OFFSET(dst_data, dst_offset), count);
+ }
+ else {
+ memcpy(POINTER_OFFSET(dst_data, dst_offset),
+ POINTER_OFFSET(src_data, src_offset),
+ (size_t)count * typeInfo->size);
+ }
}
-void CustomData_copy_data_named(const CustomData *source, CustomData *dest,
- int source_index, int dest_index, int count)
+void CustomData_copy_data_named(
+ const CustomData *source, CustomData *dest, int source_index, int dest_index, int count)
{
- int src_i, dest_i;
+ int src_i, dest_i;
- /* copies a layer at a time */
- for (src_i = 0; src_i < source->totlayer; ++src_i) {
+ /* copies a layer at a time */
+ for (src_i = 0; src_i < source->totlayer; ++src_i) {
- dest_i = CustomData_get_named_layer_index(dest, source->layers[src_i].type, source->layers[src_i].name);
+ dest_i = CustomData_get_named_layer_index(
+ dest, source->layers[src_i].type, source->layers[src_i].name);
- /* if we found a matching layer, copy the data */
- if (dest_i != -1) {
- CustomData_copy_data_layer(source, dest, src_i, dest_i, source_index, dest_index, count);
- }
- }
+ /* if we found a matching layer, copy the data */
+ if (dest_i != -1) {
+ CustomData_copy_data_layer(source, dest, src_i, dest_i, source_index, dest_index, count);
+ }
+ }
}
-void CustomData_copy_data(const CustomData *source, CustomData *dest,
- int source_index, int dest_index, int count)
+void CustomData_copy_data(
+ const CustomData *source, CustomData *dest, int source_index, int dest_index, int count)
{
- int src_i, dest_i;
+ int src_i, dest_i;
- /* copies a layer at a time */
- dest_i = 0;
- for (src_i = 0; src_i < source->totlayer; ++src_i) {
+ /* copies a layer at a time */
+ dest_i = 0;
+ for (src_i = 0; src_i < source->totlayer; ++src_i) {
- /* find the first dest layer with type >= the source type
- * (this should work because layers are ordered by type)
- */
- while (dest_i < dest->totlayer && dest->layers[dest_i].type < source->layers[src_i].type) {
- dest_i++;
- }
+ /* find the first dest layer with type >= the source type
+ * (this should work because layers are ordered by type)
+ */
+ while (dest_i < dest->totlayer && dest->layers[dest_i].type < source->layers[src_i].type) {
+ dest_i++;
+ }
- /* if there are no more dest layers, we're done */
- if (dest_i >= dest->totlayer) return;
+ /* if there are no more dest layers, we're done */
+ if (dest_i >= dest->totlayer)
+ return;
- /* if we found a matching layer, copy the data */
- if (dest->layers[dest_i].type == source->layers[src_i].type) {
- CustomData_copy_data_layer(source, dest, src_i, dest_i, source_index, dest_index, count);
+ /* if we found a matching layer, copy the data */
+ if (dest->layers[dest_i].type == source->layers[src_i].type) {
+ CustomData_copy_data_layer(source, dest, src_i, dest_i, source_index, dest_index, count);
- /* if there are multiple source & dest layers of the same type,
- * we don't want to copy all source layers to the same dest, so
- * increment dest_i
- */
- dest_i++;
- }
- }
+ /* if there are multiple source & dest layers of the same type,
+ * we don't want to copy all source layers to the same dest, so
+ * increment dest_i
+ */
+ dest_i++;
+ }
+ }
}
void CustomData_copy_layer_type_data(const CustomData *source,
CustomData *destination,
int type,
- int source_index, int destination_index,
+ int source_index,
+ int destination_index,
int count)
{
- const int source_layer_index = CustomData_get_layer_index(source, type);
- if (source_layer_index == -1) {
- return;
- }
- const int destinaiton_layer_index =
- CustomData_get_layer_index(destination, type);
- if (destinaiton_layer_index == -1) {
- return;
- }
- CustomData_copy_data_layer(source, destination,
- source_layer_index, destinaiton_layer_index,
- source_index, destination_index,
- count);
+ const int source_layer_index = CustomData_get_layer_index(source, type);
+ if (source_layer_index == -1) {
+ return;
+ }
+ const int destinaiton_layer_index = CustomData_get_layer_index(destination, type);
+ if (destinaiton_layer_index == -1) {
+ return;
+ }
+ CustomData_copy_data_layer(source,
+ destination,
+ source_layer_index,
+ destinaiton_layer_index,
+ source_index,
+ destination_index,
+ count);
}
void CustomData_free_elem(CustomData *data, int index, int count)
{
- int i;
- const LayerTypeInfo *typeInfo;
+ int i;
+ const LayerTypeInfo *typeInfo;
- for (i = 0; i < data->totlayer; ++i) {
- if (!(data->layers[i].flag & CD_FLAG_NOFREE)) {
- typeInfo = layerType_getInfo(data->layers[i].type);
+ for (i = 0; i < data->totlayer; ++i) {
+ if (!(data->layers[i].flag & CD_FLAG_NOFREE)) {
+ typeInfo = layerType_getInfo(data->layers[i].type);
- if (typeInfo->free) {
- size_t offset = (size_t)index * typeInfo->size;
+ if (typeInfo->free) {
+ size_t offset = (size_t)index * typeInfo->size;
- typeInfo->free(POINTER_OFFSET(data->layers[i].data, offset), count, typeInfo->size);
- }
- }
- }
+ typeInfo->free(POINTER_OFFSET(data->layers[i].data, offset), count, typeInfo->size);
+ }
+ }
+ }
}
#define SOURCE_BUF_SIZE 100
-void CustomData_interp(const CustomData *source, CustomData *dest,
- const int *src_indices, const float *weights, const float *sub_weights,
- int count, int dest_index)
-{
- int src_i, dest_i;
- int j;
- const void *source_buf[SOURCE_BUF_SIZE];
- const void **sources = source_buf;
-
- /* slow fallback in case we're interpolating a ridiculous number of
- * elements
- */
- if (count > SOURCE_BUF_SIZE)
- sources = MEM_malloc_arrayN(count, sizeof(*sources), __func__);
-
- /* interpolates a layer at a time */
- dest_i = 0;
- for (src_i = 0; src_i < source->totlayer; ++src_i) {
- const LayerTypeInfo *typeInfo = layerType_getInfo(source->layers[src_i].type);
- if (!typeInfo->interp) continue;
-
- /* find the first dest layer with type >= the source type
- * (this should work because layers are ordered by type)
- */
- while (dest_i < dest->totlayer && dest->layers[dest_i].type < source->layers[src_i].type) {
- dest_i++;
- }
-
- /* if there are no more dest layers, we're done */
- if (dest_i >= dest->totlayer) break;
-
- /* if we found a matching layer, copy the data */
- if (dest->layers[dest_i].type == source->layers[src_i].type) {
- void *src_data = source->layers[src_i].data;
-
- for (j = 0; j < count; ++j) {
- sources[j] = POINTER_OFFSET(src_data, (size_t)src_indices[j] * typeInfo->size);
- }
-
- typeInfo->interp(sources, weights, sub_weights, count,
- POINTER_OFFSET(dest->layers[dest_i].data, (size_t)dest_index * typeInfo->size));
-
- /* if there are multiple source & dest layers of the same type,
- * we don't want to copy all source layers to the same dest, so
- * increment dest_i
- */
- dest_i++;
- }
- }
-
- if (count > SOURCE_BUF_SIZE) MEM_freeN((void *)sources);
+void CustomData_interp(const CustomData *source,
+ CustomData *dest,
+ const int *src_indices,
+ const float *weights,
+ const float *sub_weights,
+ int count,
+ int dest_index)
+{
+ int src_i, dest_i;
+ int j;
+ const void *source_buf[SOURCE_BUF_SIZE];
+ const void **sources = source_buf;
+
+ /* slow fallback in case we're interpolating a ridiculous number of
+ * elements
+ */
+ if (count > SOURCE_BUF_SIZE)
+ sources = MEM_malloc_arrayN(count, sizeof(*sources), __func__);
+
+ /* interpolates a layer at a time */
+ dest_i = 0;
+ for (src_i = 0; src_i < source->totlayer; ++src_i) {
+ const LayerTypeInfo *typeInfo = layerType_getInfo(source->layers[src_i].type);
+ if (!typeInfo->interp)
+ continue;
+
+ /* find the first dest layer with type >= the source type
+ * (this should work because layers are ordered by type)
+ */
+ while (dest_i < dest->totlayer && dest->layers[dest_i].type < source->layers[src_i].type) {
+ dest_i++;
+ }
+
+ /* if there are no more dest layers, we're done */
+ if (dest_i >= dest->totlayer)
+ break;
+
+ /* if we found a matching layer, copy the data */
+ if (dest->layers[dest_i].type == source->layers[src_i].type) {
+ void *src_data = source->layers[src_i].data;
+
+ for (j = 0; j < count; ++j) {
+ sources[j] = POINTER_OFFSET(src_data, (size_t)src_indices[j] * typeInfo->size);
+ }
+
+ typeInfo->interp(
+ sources,
+ weights,
+ sub_weights,
+ count,
+ POINTER_OFFSET(dest->layers[dest_i].data, (size_t)dest_index * typeInfo->size));
+
+ /* if there are multiple source & dest layers of the same type,
+ * we don't want to copy all source layers to the same dest, so
+ * increment dest_i
+ */
+ dest_i++;
+ }
+ }
+
+ if (count > SOURCE_BUF_SIZE)
+ MEM_freeN((void *)sources);
}
/**
@@ -2488,18 +2785,18 @@ void CustomData_interp(const CustomData *source, CustomData *dest,
*/
void CustomData_swap_corners(struct CustomData *data, int index, const int *corner_indices)
{
- const LayerTypeInfo *typeInfo;
- int i;
+ const LayerTypeInfo *typeInfo;
+ int i;
- for (i = 0; i < data->totlayer; ++i) {
- typeInfo = layerType_getInfo(data->layers[i].type);
+ for (i = 0; i < data->totlayer; ++i) {
+ typeInfo = layerType_getInfo(data->layers[i].type);
- if (typeInfo->swap) {
- const size_t offset = (size_t)index * typeInfo->size;
+ if (typeInfo->swap) {
+ const size_t offset = (size_t)index * typeInfo->size;
- typeInfo->swap(POINTER_OFFSET(data->layers[i].data, offset), corner_indices);
- }
- }
+ typeInfo->swap(POINTER_OFFSET(data->layers[i].data, offset), corner_indices);
+ }
+ }
}
/**
@@ -2507,211 +2804,228 @@ void CustomData_swap_corners(struct CustomData *data, int index, const int *corn
*/
void CustomData_swap(struct CustomData *data, const int index_a, const int index_b)
{
- int i;
- char buff_static[256];
+ int i;
+ char buff_static[256];
- if (index_a == index_b) {
- return;
- }
+ if (index_a == index_b) {
+ return;
+ }
- for (i = 0; i < data->totlayer; ++i) {
- const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[i].type);
- const size_t size = typeInfo->size;
- const size_t offset_a = size * index_a;
- const size_t offset_b = size * index_b;
+ for (i = 0; i < data->totlayer; ++i) {
+ const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[i].type);
+ const size_t size = typeInfo->size;
+ const size_t offset_a = size * index_a;
+ const size_t offset_b = size * index_b;
- void *buff = size <= sizeof(buff_static) ? buff_static : MEM_mallocN(size, __func__);
- memcpy(buff, POINTER_OFFSET(data->layers[i].data, offset_a), size);
- memcpy(POINTER_OFFSET(data->layers[i].data, offset_a), POINTER_OFFSET(data->layers[i].data, offset_b), size);
- memcpy(POINTER_OFFSET(data->layers[i].data, offset_b), buff, size);
+ void *buff = size <= sizeof(buff_static) ? buff_static : MEM_mallocN(size, __func__);
+ memcpy(buff, POINTER_OFFSET(data->layers[i].data, offset_a), size);
+ memcpy(POINTER_OFFSET(data->layers[i].data, offset_a),
+ POINTER_OFFSET(data->layers[i].data, offset_b),
+ size);
+ memcpy(POINTER_OFFSET(data->layers[i].data, offset_b), buff, size);
- if (buff != buff_static) {
- MEM_freeN(buff);
- }
- }
+ if (buff != buff_static) {
+ MEM_freeN(buff);
+ }
+ }
}
void *CustomData_get(const CustomData *data, int index, int type)
{
- int layer_index;
+ int layer_index;
- BLI_assert(index >= 0);
+ BLI_assert(index >= 0);
- /* get the layer index of the active layer of type */
- layer_index = CustomData_get_active_layer_index(data, type);
- if (layer_index == -1) return NULL;
+ /* get the layer index of the active layer of type */
+ layer_index = CustomData_get_active_layer_index(data, type);
+ if (layer_index == -1)
+ return NULL;
- /* get the offset of the desired element */
- const size_t offset = (size_t)index * layerType_getInfo(type)->size;
+ /* get the offset of the desired element */
+ const size_t offset = (size_t)index * layerType_getInfo(type)->size;
- return POINTER_OFFSET(data->layers[layer_index].data, offset);
+ return POINTER_OFFSET(data->layers[layer_index].data, offset);
}
void *CustomData_get_n(const CustomData *data, int type, int index, int n)
{
- int layer_index;
+ int layer_index;
- BLI_assert(index >= 0 && n >= 0);
+ BLI_assert(index >= 0 && n >= 0);
- /* get the layer index of the first layer of type */
- layer_index = data->typemap[type];
- if (layer_index == -1) return NULL;
+ /* get the layer index of the first layer of type */
+ layer_index = data->typemap[type];
+ if (layer_index == -1)
+ return NULL;
- const size_t offset = (size_t)index * layerType_getInfo(type)->size;
- return POINTER_OFFSET(data->layers[layer_index + n].data, offset);
+ const size_t offset = (size_t)index * layerType_getInfo(type)->size;
+ return POINTER_OFFSET(data->layers[layer_index + n].data, offset);
}
void *CustomData_get_layer(const CustomData *data, int type)
{
- /* get the layer index of the active layer of type */
- int layer_index = CustomData_get_active_layer_index(data, type);
- if (layer_index == -1) return NULL;
+ /* get the layer index of the active layer of type */
+ int layer_index = CustomData_get_active_layer_index(data, type);
+ if (layer_index == -1)
+ return NULL;
- return data->layers[layer_index].data;
+ return data->layers[layer_index].data;
}
void *CustomData_get_layer_n(const CustomData *data, int type, int n)
{
- /* get the layer index of the active layer of type */
- int layer_index = CustomData_get_layer_index_n(data, type, n);
- if (layer_index == -1) return NULL;
+ /* get the layer index of the active layer of type */
+ int layer_index = CustomData_get_layer_index_n(data, type, n);
+ if (layer_index == -1)
+ return NULL;
- return data->layers[layer_index].data;
+ return data->layers[layer_index].data;
}
-void *CustomData_get_layer_named(const struct CustomData *data, int type,
- const char *name)
+void *CustomData_get_layer_named(const struct CustomData *data, int type, const char *name)
{
- int layer_index = CustomData_get_named_layer_index(data, type, name);
- if (layer_index == -1) return NULL;
+ int layer_index = CustomData_get_named_layer_index(data, type, name);
+ if (layer_index == -1)
+ return NULL;
- return data->layers[layer_index].data;
+ return data->layers[layer_index].data;
}
int CustomData_get_offset(const CustomData *data, int type)
{
- /* get the layer index of the active layer of type */
- int layer_index = CustomData_get_active_layer_index(data, type);
- if (layer_index == -1) return -1;
+ /* get the layer index of the active layer of type */
+ int layer_index = CustomData_get_active_layer_index(data, type);
+ if (layer_index == -1)
+ return -1;
- return data->layers[layer_index].offset;
+ return data->layers[layer_index].offset;
}
int CustomData_get_n_offset(const CustomData *data, int type, int n)
{
- /* get the layer index of the active layer of type */
- int layer_index = CustomData_get_layer_index_n(data, type, n);
- if (layer_index == -1) return -1;
+ /* get the layer index of the active layer of type */
+ int layer_index = CustomData_get_layer_index_n(data, type, n);
+ if (layer_index == -1)
+ return -1;
- return data->layers[layer_index].offset;
+ return data->layers[layer_index].offset;
}
bool CustomData_set_layer_name(const CustomData *data, int type, int n, const char *name)
{
- /* get the layer index of the first layer of type */
- const int layer_index = CustomData_get_layer_index_n(data, type, n);
+ /* get the layer index of the first layer of type */
+ const int layer_index = CustomData_get_layer_index_n(data, type, n);
- if ((layer_index == -1) || !name)
- return false;
+ if ((layer_index == -1) || !name)
+ return false;
- BLI_strncpy(data->layers[layer_index].name, name, sizeof(data->layers[layer_index].name));
+ BLI_strncpy(data->layers[layer_index].name, name, sizeof(data->layers[layer_index].name));
- return true;
+ return true;
}
const char *CustomData_get_layer_name(const CustomData *data, int type, int n)
{
- const int layer_index = CustomData_get_layer_index_n(data, type, n);
+ const int layer_index = CustomData_get_layer_index_n(data, type, n);
- return (layer_index == -1) ? NULL : data->layers[layer_index].name;
+ return (layer_index == -1) ? NULL : data->layers[layer_index].name;
}
void *CustomData_set_layer(const CustomData *data, int type, void *ptr)
{
- /* get the layer index of the first layer of type */
- int layer_index = CustomData_get_active_layer_index(data, type);
+ /* get the layer index of the first layer of type */
+ int layer_index = CustomData_get_active_layer_index(data, type);
- if (layer_index == -1) return NULL;
+ if (layer_index == -1)
+ return NULL;
- data->layers[layer_index].data = ptr;
+ data->layers[layer_index].data = ptr;
- return ptr;
+ return ptr;
}
void *CustomData_set_layer_n(const struct CustomData *data, int type, int n, void *ptr)
{
- /* get the layer index of the first layer of type */
- int layer_index = CustomData_get_layer_index_n(data, type, n);
- if (layer_index == -1) return NULL;
+ /* get the layer index of the first layer of type */
+ int layer_index = CustomData_get_layer_index_n(data, type, n);
+ if (layer_index == -1)
+ return NULL;
- data->layers[layer_index].data = ptr;
+ data->layers[layer_index].data = ptr;
- return ptr;
+ return ptr;
}
void CustomData_set(const CustomData *data, int index, int type, const void *source)
{
- void *dest = CustomData_get(data, index, type);
- const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+ void *dest = CustomData_get(data, index, type);
+ const LayerTypeInfo *typeInfo = layerType_getInfo(type);
- if (!dest) return;
+ if (!dest)
+ return;
- if (typeInfo->copy)
- typeInfo->copy(source, dest, 1);
- else
- memcpy(dest, source, typeInfo->size);
+ if (typeInfo->copy)
+ typeInfo->copy(source, dest, 1);
+ else
+ memcpy(dest, source, typeInfo->size);
}
/* BMesh functions */
/* needed to convert to/from different face reps */
void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *ldata, int totloop)
{
- for (int i = 0; i < fdata->totlayer; i++) {
- if (fdata->layers[i].type == CD_MTFACE) {
- CustomData_add_layer_named(ldata, CD_MLOOPUV, CD_CALLOC, NULL, totloop, fdata->layers[i].name);
- }
- else if (fdata->layers[i].type == CD_MCOL) {
- CustomData_add_layer_named(ldata, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, fdata->layers[i].name);
- }
- else if (fdata->layers[i].type == CD_MDISPS) {
- CustomData_add_layer_named(ldata, CD_MDISPS, CD_CALLOC, NULL, totloop, fdata->layers[i].name);
- }
- else if (fdata->layers[i].type == CD_TESSLOOPNORMAL) {
- CustomData_add_layer_named(ldata, CD_NORMAL, CD_CALLOC, NULL, totloop, fdata->layers[i].name);
- }
- }
-}
-
-void CustomData_from_bmeshpoly(
- CustomData *fdata, CustomData *ldata, int total)
-{
- int i;
-
- /* avoid accumulating extra layers */
- BLI_assert(!CustomData_from_bmeshpoly_test(fdata, ldata, false));
-
- for (i = 0; i < ldata->totlayer; i++) {
- if (ldata->layers[i].type == CD_MLOOPUV) {
- CustomData_add_layer_named(fdata, CD_MTFACE, CD_CALLOC, NULL, total, ldata->layers[i].name);
- }
- if (ldata->layers[i].type == CD_MLOOPCOL) {
- CustomData_add_layer_named(fdata, CD_MCOL, CD_CALLOC, NULL, total, ldata->layers[i].name);
- }
- else if (ldata->layers[i].type == CD_PREVIEW_MLOOPCOL) {
- CustomData_add_layer_named(fdata, CD_PREVIEW_MCOL, CD_CALLOC, NULL, total, ldata->layers[i].name);
- }
- else if (ldata->layers[i].type == CD_ORIGSPACE_MLOOP) {
- CustomData_add_layer_named(fdata, CD_ORIGSPACE, CD_CALLOC, NULL, total, ldata->layers[i].name);
- }
- else if (ldata->layers[i].type == CD_NORMAL) {
- CustomData_add_layer_named(fdata, CD_TESSLOOPNORMAL, CD_CALLOC, NULL, total, ldata->layers[i].name);
- }
- else if (ldata->layers[i].type == CD_TANGENT) {
- CustomData_add_layer_named(fdata, CD_TANGENT, CD_CALLOC, NULL, total, ldata->layers[i].name);
- }
- }
-
- CustomData_bmesh_update_active_layers(fdata, ldata);
+ for (int i = 0; i < fdata->totlayer; i++) {
+ if (fdata->layers[i].type == CD_MTFACE) {
+ CustomData_add_layer_named(
+ ldata, CD_MLOOPUV, CD_CALLOC, NULL, totloop, fdata->layers[i].name);
+ }
+ else if (fdata->layers[i].type == CD_MCOL) {
+ CustomData_add_layer_named(
+ ldata, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, fdata->layers[i].name);
+ }
+ else if (fdata->layers[i].type == CD_MDISPS) {
+ CustomData_add_layer_named(
+ ldata, CD_MDISPS, CD_CALLOC, NULL, totloop, fdata->layers[i].name);
+ }
+ else if (fdata->layers[i].type == CD_TESSLOOPNORMAL) {
+ CustomData_add_layer_named(
+ ldata, CD_NORMAL, CD_CALLOC, NULL, totloop, fdata->layers[i].name);
+ }
+ }
+}
+
+void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *ldata, int total)
+{
+ int i;
+
+ /* avoid accumulating extra layers */
+ BLI_assert(!CustomData_from_bmeshpoly_test(fdata, ldata, false));
+
+ for (i = 0; i < ldata->totlayer; i++) {
+ if (ldata->layers[i].type == CD_MLOOPUV) {
+ CustomData_add_layer_named(fdata, CD_MTFACE, CD_CALLOC, NULL, total, ldata->layers[i].name);
+ }
+ if (ldata->layers[i].type == CD_MLOOPCOL) {
+ CustomData_add_layer_named(fdata, CD_MCOL, CD_CALLOC, NULL, total, ldata->layers[i].name);
+ }
+ else if (ldata->layers[i].type == CD_PREVIEW_MLOOPCOL) {
+ CustomData_add_layer_named(
+ fdata, CD_PREVIEW_MCOL, CD_CALLOC, NULL, total, ldata->layers[i].name);
+ }
+ else if (ldata->layers[i].type == CD_ORIGSPACE_MLOOP) {
+ CustomData_add_layer_named(
+ fdata, CD_ORIGSPACE, CD_CALLOC, NULL, total, ldata->layers[i].name);
+ }
+ else if (ldata->layers[i].type == CD_NORMAL) {
+ CustomData_add_layer_named(
+ fdata, CD_TESSLOOPNORMAL, CD_CALLOC, NULL, total, ldata->layers[i].name);
+ }
+ else if (ldata->layers[i].type == CD_TANGENT) {
+ CustomData_add_layer_named(fdata, CD_TANGENT, CD_CALLOC, NULL, total, ldata->layers[i].name);
+ }
+ }
+
+ CustomData_bmesh_update_active_layers(fdata, ldata);
}
#ifndef NDEBUG
@@ -2723,63 +3037,63 @@ void CustomData_from_bmeshpoly(
*/
bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *ldata, bool fallback)
{
- int a_num = 0, b_num = 0;
-#define LAYER_CMP(l_a, t_a, l_b, t_b) \
- ((a_num += CustomData_number_of_layers(l_a, t_a)) == (b_num += CustomData_number_of_layers(l_b, t_b)))
-
- if (!LAYER_CMP(ldata, CD_MLOOPUV, fdata, CD_MTFACE))
- return false;
- if (!LAYER_CMP(ldata, CD_MLOOPCOL, fdata, CD_MCOL))
- return false;
- if (!LAYER_CMP(ldata, CD_PREVIEW_MLOOPCOL, fdata, CD_PREVIEW_MCOL))
- return false;
- if (!LAYER_CMP(ldata, CD_ORIGSPACE_MLOOP, fdata, CD_ORIGSPACE))
- return false;
- if (!LAYER_CMP(ldata, CD_NORMAL, fdata, CD_TESSLOOPNORMAL))
- return false;
- if (!LAYER_CMP(ldata, CD_TANGENT, fdata, CD_TANGENT))
- return false;
-
-#undef LAYER_CMP
-
- /* if no layers are on either CustomData's,
- * then there was nothing to do... */
- return a_num ? true : fallback;
+ int a_num = 0, b_num = 0;
+# define LAYER_CMP(l_a, t_a, l_b, t_b) \
+ ((a_num += CustomData_number_of_layers(l_a, t_a)) == \
+ (b_num += CustomData_number_of_layers(l_b, t_b)))
+
+ if (!LAYER_CMP(ldata, CD_MLOOPUV, fdata, CD_MTFACE))
+ return false;
+ if (!LAYER_CMP(ldata, CD_MLOOPCOL, fdata, CD_MCOL))
+ return false;
+ if (!LAYER_CMP(ldata, CD_PREVIEW_MLOOPCOL, fdata, CD_PREVIEW_MCOL))
+ return false;
+ if (!LAYER_CMP(ldata, CD_ORIGSPACE_MLOOP, fdata, CD_ORIGSPACE))
+ return false;
+ if (!LAYER_CMP(ldata, CD_NORMAL, fdata, CD_TESSLOOPNORMAL))
+ return false;
+ if (!LAYER_CMP(ldata, CD_TANGENT, fdata, CD_TANGENT))
+ return false;
+
+# undef LAYER_CMP
+
+ /* if no layers are on either CustomData's,
+ * then there was nothing to do... */
+ return a_num ? true : fallback;
}
#endif
-
void CustomData_bmesh_update_active_layers(CustomData *fdata, CustomData *ldata)
{
- int act;
+ int act;
- if (CustomData_has_layer(ldata, CD_MLOOPUV)) {
- act = CustomData_get_active_layer(ldata, CD_MLOOPUV);
- CustomData_set_layer_active(fdata, CD_MTFACE, act);
+ if (CustomData_has_layer(ldata, CD_MLOOPUV)) {
+ act = CustomData_get_active_layer(ldata, CD_MLOOPUV);
+ CustomData_set_layer_active(fdata, CD_MTFACE, act);
- act = CustomData_get_render_layer(ldata, CD_MLOOPUV);
- CustomData_set_layer_render(fdata, CD_MTFACE, act);
+ act = CustomData_get_render_layer(ldata, CD_MLOOPUV);
+ CustomData_set_layer_render(fdata, CD_MTFACE, act);
- act = CustomData_get_clone_layer(ldata, CD_MLOOPUV);
- CustomData_set_layer_clone(fdata, CD_MTFACE, act);
+ act = CustomData_get_clone_layer(ldata, CD_MLOOPUV);
+ CustomData_set_layer_clone(fdata, CD_MTFACE, act);
- act = CustomData_get_stencil_layer(ldata, CD_MLOOPUV);
- CustomData_set_layer_stencil(fdata, CD_MTFACE, act);
- }
+ act = CustomData_get_stencil_layer(ldata, CD_MLOOPUV);
+ CustomData_set_layer_stencil(fdata, CD_MTFACE, act);
+ }
- if (CustomData_has_layer(ldata, CD_MLOOPCOL)) {
- act = CustomData_get_active_layer(ldata, CD_MLOOPCOL);
- CustomData_set_layer_active(fdata, CD_MCOL, act);
+ if (CustomData_has_layer(ldata, CD_MLOOPCOL)) {
+ act = CustomData_get_active_layer(ldata, CD_MLOOPCOL);
+ CustomData_set_layer_active(fdata, CD_MCOL, act);
- act = CustomData_get_render_layer(ldata, CD_MLOOPCOL);
- CustomData_set_layer_render(fdata, CD_MCOL, act);
+ act = CustomData_get_render_layer(ldata, CD_MLOOPCOL);
+ CustomData_set_layer_render(fdata, CD_MCOL, act);
- act = CustomData_get_clone_layer(ldata, CD_MLOOPCOL);
- CustomData_set_layer_clone(fdata, CD_MCOL, act);
+ act = CustomData_get_clone_layer(ldata, CD_MLOOPCOL);
+ CustomData_set_layer_clone(fdata, CD_MCOL, act);
- act = CustomData_get_stencil_layer(ldata, CD_MLOOPCOL);
- CustomData_set_layer_stencil(fdata, CD_MCOL, act);
- }
+ act = CustomData_get_stencil_layer(ldata, CD_MLOOPCOL);
+ CustomData_set_layer_stencil(fdata, CD_MCOL, act);
+ }
}
/* update active indices for active/render/clone/stencil custom data layers
@@ -2789,169 +3103,182 @@ void CustomData_bmesh_update_active_layers(CustomData *fdata, CustomData *ldata)
*/
void CustomData_bmesh_do_versions_update_active_layers(CustomData *fdata, CustomData *ldata)
{
- int act;
+ int act;
- if (CustomData_has_layer(fdata, CD_MTFACE)) {
- act = CustomData_get_active_layer(fdata, CD_MTFACE);
- CustomData_set_layer_active(ldata, CD_MLOOPUV, act);
+ if (CustomData_has_layer(fdata, CD_MTFACE)) {
+ act = CustomData_get_active_layer(fdata, CD_MTFACE);
+ CustomData_set_layer_active(ldata, CD_MLOOPUV, act);
- act = CustomData_get_render_layer(fdata, CD_MTFACE);
- CustomData_set_layer_render(ldata, CD_MLOOPUV, act);
+ act = CustomData_get_render_layer(fdata, CD_MTFACE);
+ CustomData_set_layer_render(ldata, CD_MLOOPUV, act);
- act = CustomData_get_clone_layer(fdata, CD_MTFACE);
- CustomData_set_layer_clone(ldata, CD_MLOOPUV, act);
+ act = CustomData_get_clone_layer(fdata, CD_MTFACE);
+ CustomData_set_layer_clone(ldata, CD_MLOOPUV, act);
- act = CustomData_get_stencil_layer(fdata, CD_MTFACE);
- CustomData_set_layer_stencil(ldata, CD_MLOOPUV, act);
- }
+ act = CustomData_get_stencil_layer(fdata, CD_MTFACE);
+ CustomData_set_layer_stencil(ldata, CD_MLOOPUV, act);
+ }
- if (CustomData_has_layer(fdata, CD_MCOL)) {
- act = CustomData_get_active_layer(fdata, CD_MCOL);
- CustomData_set_layer_active(ldata, CD_MLOOPCOL, act);
+ if (CustomData_has_layer(fdata, CD_MCOL)) {
+ act = CustomData_get_active_layer(fdata, CD_MCOL);
+ CustomData_set_layer_active(ldata, CD_MLOOPCOL, act);
- act = CustomData_get_render_layer(fdata, CD_MCOL);
- CustomData_set_layer_render(ldata, CD_MLOOPCOL, act);
+ act = CustomData_get_render_layer(fdata, CD_MCOL);
+ CustomData_set_layer_render(ldata, CD_MLOOPCOL, act);
- act = CustomData_get_clone_layer(fdata, CD_MCOL);
- CustomData_set_layer_clone(ldata, CD_MLOOPCOL, act);
+ act = CustomData_get_clone_layer(fdata, CD_MCOL);
+ CustomData_set_layer_clone(ldata, CD_MLOOPCOL, act);
- act = CustomData_get_stencil_layer(fdata, CD_MCOL);
- CustomData_set_layer_stencil(ldata, CD_MLOOPCOL, act);
- }
+ act = CustomData_get_stencil_layer(fdata, CD_MCOL);
+ CustomData_set_layer_stencil(ldata, CD_MLOOPCOL, act);
+ }
}
void CustomData_bmesh_init_pool(CustomData *data, int totelem, const char htype)
{
- int chunksize;
-
- /* Dispose old pools before calling here to avoid leaks */
- BLI_assert(data->pool == NULL);
-
- switch (htype) {
- case BM_VERT: chunksize = bm_mesh_chunksize_default.totvert; break;
- case BM_EDGE: chunksize = bm_mesh_chunksize_default.totedge; break;
- case BM_LOOP: chunksize = bm_mesh_chunksize_default.totloop; break;
- case BM_FACE: chunksize = bm_mesh_chunksize_default.totface; break;
- default:
- BLI_assert(0);
- chunksize = 512;
- break;
- }
-
- /* If there are no layers, no pool is needed just yet */
- if (data->totlayer) {
- data->pool = BLI_mempool_create(data->totsize, totelem, chunksize, BLI_MEMPOOL_NOP);
- }
-}
-
-bool CustomData_bmesh_merge(
- const CustomData *source, CustomData *dest,
- CustomDataMask mask, eCDAllocType alloctype, BMesh *bm, const char htype)
-{
- BMHeader *h;
- BMIter iter;
- CustomData destold;
- void *tmp;
- int iter_type;
- int totelem;
-
- if (CustomData_number_of_layers_typemask(source, mask) == 0) {
- return false;
- }
-
- /* copy old layer description so that old data can be copied into
- * the new allocation */
- destold = *dest;
- if (destold.layers) {
- destold.layers = MEM_dupallocN(destold.layers);
- }
-
- if (CustomData_merge(source, dest, mask, alloctype, 0) == false) {
- if (destold.layers)
- MEM_freeN(destold.layers);
- return false;
- }
-
- switch (htype) {
- case BM_VERT:
- iter_type = BM_VERTS_OF_MESH;
- totelem = bm->totvert;
- break;
- case BM_EDGE:
- iter_type = BM_EDGES_OF_MESH;
- totelem = bm->totedge;
- break;
- case BM_LOOP:
- iter_type = BM_LOOPS_OF_FACE;
- totelem = bm->totloop;
- break;
- case BM_FACE:
- iter_type = BM_FACES_OF_MESH;
- totelem = bm->totface;
- break;
- default: /* should never happen */
- BLI_assert(!"invalid type given");
- iter_type = BM_VERTS_OF_MESH;
- totelem = bm->totvert;
- break;
- }
-
- dest->pool = NULL;
- CustomData_bmesh_init_pool(dest, totelem, htype);
-
- if (iter_type != BM_LOOPS_OF_FACE) {
- /*ensure all current elements follow new customdata layout*/
- BM_ITER_MESH (h, &iter, bm, iter_type) {
- tmp = NULL;
- CustomData_bmesh_copy_data(&destold, dest, h->data, &tmp);
- CustomData_bmesh_free_block(&destold, &h->data);
- h->data = tmp;
- }
- }
- else {
- BMFace *f;
- BMLoop *l;
- BMIter liter;
-
- /*ensure all current elements follow new customdata layout*/
- BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- tmp = NULL;
- CustomData_bmesh_copy_data(&destold, dest, l->head.data, &tmp);
- CustomData_bmesh_free_block(&destold, &l->head.data);
- l->head.data = tmp;
- }
- }
- }
-
- if (destold.pool) BLI_mempool_destroy(destold.pool);
- if (destold.layers) MEM_freeN(destold.layers);
- return true;
+ int chunksize;
+
+ /* Dispose old pools before calling here to avoid leaks */
+ BLI_assert(data->pool == NULL);
+
+ switch (htype) {
+ case BM_VERT:
+ chunksize = bm_mesh_chunksize_default.totvert;
+ break;
+ case BM_EDGE:
+ chunksize = bm_mesh_chunksize_default.totedge;
+ break;
+ case BM_LOOP:
+ chunksize = bm_mesh_chunksize_default.totloop;
+ break;
+ case BM_FACE:
+ chunksize = bm_mesh_chunksize_default.totface;
+ break;
+ default:
+ BLI_assert(0);
+ chunksize = 512;
+ break;
+ }
+
+ /* If there are no layers, no pool is needed just yet */
+ if (data->totlayer) {
+ data->pool = BLI_mempool_create(data->totsize, totelem, chunksize, BLI_MEMPOOL_NOP);
+ }
+}
+
+bool CustomData_bmesh_merge(const CustomData *source,
+ CustomData *dest,
+ CustomDataMask mask,
+ eCDAllocType alloctype,
+ BMesh *bm,
+ const char htype)
+{
+ BMHeader *h;
+ BMIter iter;
+ CustomData destold;
+ void *tmp;
+ int iter_type;
+ int totelem;
+
+ if (CustomData_number_of_layers_typemask(source, mask) == 0) {
+ return false;
+ }
+
+ /* copy old layer description so that old data can be copied into
+ * the new allocation */
+ destold = *dest;
+ if (destold.layers) {
+ destold.layers = MEM_dupallocN(destold.layers);
+ }
+
+ if (CustomData_merge(source, dest, mask, alloctype, 0) == false) {
+ if (destold.layers)
+ MEM_freeN(destold.layers);
+ return false;
+ }
+
+ switch (htype) {
+ case BM_VERT:
+ iter_type = BM_VERTS_OF_MESH;
+ totelem = bm->totvert;
+ break;
+ case BM_EDGE:
+ iter_type = BM_EDGES_OF_MESH;
+ totelem = bm->totedge;
+ break;
+ case BM_LOOP:
+ iter_type = BM_LOOPS_OF_FACE;
+ totelem = bm->totloop;
+ break;
+ case BM_FACE:
+ iter_type = BM_FACES_OF_MESH;
+ totelem = bm->totface;
+ break;
+ default: /* should never happen */
+ BLI_assert(!"invalid type given");
+ iter_type = BM_VERTS_OF_MESH;
+ totelem = bm->totvert;
+ break;
+ }
+
+ dest->pool = NULL;
+ CustomData_bmesh_init_pool(dest, totelem, htype);
+
+ if (iter_type != BM_LOOPS_OF_FACE) {
+ /*ensure all current elements follow new customdata layout*/
+ BM_ITER_MESH (h, &iter, bm, iter_type) {
+ tmp = NULL;
+ CustomData_bmesh_copy_data(&destold, dest, h->data, &tmp);
+ CustomData_bmesh_free_block(&destold, &h->data);
+ h->data = tmp;
+ }
+ }
+ else {
+ BMFace *f;
+ BMLoop *l;
+ BMIter liter;
+
+ /*ensure all current elements follow new customdata layout*/
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
+ tmp = NULL;
+ CustomData_bmesh_copy_data(&destold, dest, l->head.data, &tmp);
+ CustomData_bmesh_free_block(&destold, &l->head.data);
+ l->head.data = tmp;
+ }
+ }
+ }
+
+ if (destold.pool)
+ BLI_mempool_destroy(destold.pool);
+ if (destold.layers)
+ MEM_freeN(destold.layers);
+ return true;
}
void CustomData_bmesh_free_block(CustomData *data, void **block)
{
- const LayerTypeInfo *typeInfo;
- int i;
+ const LayerTypeInfo *typeInfo;
+ int i;
- if (*block == NULL)
- return;
+ if (*block == NULL)
+ return;
- for (i = 0; i < data->totlayer; ++i) {
- if (!(data->layers[i].flag & CD_FLAG_NOFREE)) {
- typeInfo = layerType_getInfo(data->layers[i].type);
+ for (i = 0; i < data->totlayer; ++i) {
+ if (!(data->layers[i].flag & CD_FLAG_NOFREE)) {
+ typeInfo = layerType_getInfo(data->layers[i].type);
- if (typeInfo->free) {
- int offset = data->layers[i].offset;
- typeInfo->free(POINTER_OFFSET(*block, offset), 1, typeInfo->size);
- }
- }
- }
+ if (typeInfo->free) {
+ int offset = data->layers[i].offset;
+ typeInfo->free(POINTER_OFFSET(*block, offset), 1, typeInfo->size);
+ }
+ }
+ }
- if (data->totsize)
- BLI_mempool_free(data->pool, *block);
+ if (data->totsize)
+ BLI_mempool_free(data->pool, *block);
- *block = NULL;
+ *block = NULL;
}
/**
@@ -2959,386 +3286,398 @@ void CustomData_bmesh_free_block(CustomData *data, void **block)
*/
void CustomData_bmesh_free_block_data(CustomData *data, void *block)
{
- const LayerTypeInfo *typeInfo;
- int i;
+ const LayerTypeInfo *typeInfo;
+ int i;
- if (block == NULL)
- return;
+ if (block == NULL)
+ return;
- for (i = 0; i < data->totlayer; ++i) {
- if (!(data->layers[i].flag & CD_FLAG_NOFREE)) {
- typeInfo = layerType_getInfo(data->layers[i].type);
+ for (i = 0; i < data->totlayer; ++i) {
+ if (!(data->layers[i].flag & CD_FLAG_NOFREE)) {
+ typeInfo = layerType_getInfo(data->layers[i].type);
- if (typeInfo->free) {
- const size_t offset = data->layers[i].offset;
- typeInfo->free(POINTER_OFFSET(block, offset), 1, typeInfo->size);
- }
- }
- }
+ if (typeInfo->free) {
+ const size_t offset = data->layers[i].offset;
+ typeInfo->free(POINTER_OFFSET(block, offset), 1, typeInfo->size);
+ }
+ }
+ }
- if (data->totsize)
- memset(block, 0, data->totsize);
+ if (data->totsize)
+ memset(block, 0, data->totsize);
}
static void CustomData_bmesh_alloc_block(CustomData *data, void **block)
{
- if (*block)
- CustomData_bmesh_free_block(data, block);
+ if (*block)
+ CustomData_bmesh_free_block(data, block);
- if (data->totsize > 0)
- *block = BLI_mempool_alloc(data->pool);
- else
- *block = NULL;
+ if (data->totsize > 0)
+ *block = BLI_mempool_alloc(data->pool);
+ else
+ *block = NULL;
}
-void CustomData_bmesh_copy_data(const CustomData *source, CustomData *dest,
- void *src_block, void **dest_block)
+void CustomData_bmesh_copy_data(const CustomData *source,
+ CustomData *dest,
+ void *src_block,
+ void **dest_block)
{
- const LayerTypeInfo *typeInfo;
- int dest_i, src_i;
+ const LayerTypeInfo *typeInfo;
+ int dest_i, src_i;
- if (*dest_block == NULL) {
- CustomData_bmesh_alloc_block(dest, dest_block);
- if (*dest_block)
- memset(*dest_block, 0, dest->totsize);
- }
+ if (*dest_block == NULL) {
+ CustomData_bmesh_alloc_block(dest, dest_block);
+ if (*dest_block)
+ memset(*dest_block, 0, dest->totsize);
+ }
- /* copies a layer at a time */
- dest_i = 0;
- for (src_i = 0; src_i < source->totlayer; ++src_i) {
+ /* copies a layer at a time */
+ dest_i = 0;
+ for (src_i = 0; src_i < source->totlayer; ++src_i) {
- /* find the first dest layer with type >= the source type
- * (this should work because layers are ordered by type)
- */
- while (dest_i < dest->totlayer && dest->layers[dest_i].type < source->layers[src_i].type) {
- dest_i++;
- }
+ /* find the first dest layer with type >= the source type
+ * (this should work because layers are ordered by type)
+ */
+ while (dest_i < dest->totlayer && dest->layers[dest_i].type < source->layers[src_i].type) {
+ dest_i++;
+ }
- /* if there are no more dest layers, we're done */
- if (dest_i >= dest->totlayer) return;
+ /* if there are no more dest layers, we're done */
+ if (dest_i >= dest->totlayer)
+ return;
- /* if we found a matching layer, copy the data */
- if (dest->layers[dest_i].type == source->layers[src_i].type &&
- STREQ(dest->layers[dest_i].name, source->layers[src_i].name))
- {
- const void *src_data = POINTER_OFFSET(src_block, source->layers[src_i].offset);
- void *dest_data = POINTER_OFFSET(*dest_block, dest->layers[dest_i].offset);
+ /* if we found a matching layer, copy the data */
+ if (dest->layers[dest_i].type == source->layers[src_i].type &&
+ STREQ(dest->layers[dest_i].name, source->layers[src_i].name)) {
+ const void *src_data = POINTER_OFFSET(src_block, source->layers[src_i].offset);
+ void *dest_data = POINTER_OFFSET(*dest_block, dest->layers[dest_i].offset);
- typeInfo = layerType_getInfo(source->layers[src_i].type);
+ typeInfo = layerType_getInfo(source->layers[src_i].type);
- if (typeInfo->copy)
- typeInfo->copy(src_data, dest_data, 1);
- else
- memcpy(dest_data, src_data, typeInfo->size);
+ if (typeInfo->copy)
+ typeInfo->copy(src_data, dest_data, 1);
+ else
+ memcpy(dest_data, src_data, typeInfo->size);
- /* if there are multiple source & dest layers of the same type,
- * we don't want to copy all source layers to the same dest, so
- * increment dest_i
- */
- dest_i++;
- }
- }
+ /* if there are multiple source & dest layers of the same type,
+ * we don't want to copy all source layers to the same dest, so
+ * increment dest_i
+ */
+ dest_i++;
+ }
+ }
}
/*Bmesh Custom Data Functions. Should replace editmesh ones with these as well, due to more efficient memory alloc*/
void *CustomData_bmesh_get(const CustomData *data, void *block, int type)
{
- int layer_index;
+ int layer_index;
- /* get the layer index of the first layer of type */
- layer_index = CustomData_get_active_layer_index(data, type);
- if (layer_index == -1) return NULL;
+ /* get the layer index of the first layer of type */
+ layer_index = CustomData_get_active_layer_index(data, type);
+ if (layer_index == -1)
+ return NULL;
- return POINTER_OFFSET(block, data->layers[layer_index].offset);
+ return POINTER_OFFSET(block, data->layers[layer_index].offset);
}
void *CustomData_bmesh_get_n(const CustomData *data, void *block, int type, int n)
{
- int layer_index;
+ int layer_index;
- /* get the layer index of the first layer of type */
- layer_index = CustomData_get_layer_index(data, type);
- if (layer_index == -1) return NULL;
+ /* get the layer index of the first layer of type */
+ layer_index = CustomData_get_layer_index(data, type);
+ if (layer_index == -1)
+ return NULL;
- return POINTER_OFFSET(block, data->layers[layer_index + n].offset);
+ return POINTER_OFFSET(block, data->layers[layer_index + n].offset);
}
/*gets from the layer at physical index n, note: doesn't check type.*/
void *CustomData_bmesh_get_layer_n(const CustomData *data, void *block, int n)
{
- if (n < 0 || n >= data->totlayer) return NULL;
+ if (n < 0 || n >= data->totlayer)
+ return NULL;
- return POINTER_OFFSET(block, data->layers[n].offset);
+ return POINTER_OFFSET(block, data->layers[n].offset);
}
bool CustomData_layer_has_math(const struct CustomData *data, int layer_n)
{
- const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[layer_n].type);
+ const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[layer_n].type);
- if (typeInfo->equal && typeInfo->add && typeInfo->multiply &&
- typeInfo->initminmax && typeInfo->dominmax)
- {
- return true;
- }
+ if (typeInfo->equal && typeInfo->add && typeInfo->multiply && typeInfo->initminmax &&
+ typeInfo->dominmax) {
+ return true;
+ }
- return false;
+ return false;
}
bool CustomData_layer_has_interp(const struct CustomData *data, int layer_n)
{
- const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[layer_n].type);
+ const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[layer_n].type);
- if (typeInfo->interp) {
- return true;
- }
+ if (typeInfo->interp) {
+ return true;
+ }
- return false;
+ return false;
}
bool CustomData_has_math(const struct CustomData *data)
{
- int i;
+ int i;
- /* interpolates a layer at a time */
- for (i = 0; i < data->totlayer; ++i) {
- if (CustomData_layer_has_math(data, i)) {
- return true;
- }
- }
+ /* interpolates a layer at a time */
+ for (i = 0; i < data->totlayer; ++i) {
+ if (CustomData_layer_has_math(data, i)) {
+ return true;
+ }
+ }
- return false;
+ return false;
}
/* a non bmesh version would have to check layer->data */
bool CustomData_bmesh_has_free(const struct CustomData *data)
{
- const LayerTypeInfo *typeInfo;
- int i;
+ const LayerTypeInfo *typeInfo;
+ int i;
- for (i = 0; i < data->totlayer; ++i) {
- if (!(data->layers[i].flag & CD_FLAG_NOFREE)) {
- typeInfo = layerType_getInfo(data->layers[i].type);
- if (typeInfo->free) {
- return true;
- }
- }
- }
- return false;
+ for (i = 0; i < data->totlayer; ++i) {
+ if (!(data->layers[i].flag & CD_FLAG_NOFREE)) {
+ typeInfo = layerType_getInfo(data->layers[i].type);
+ if (typeInfo->free) {
+ return true;
+ }
+ }
+ }
+ return false;
}
bool CustomData_has_interp(const struct CustomData *data)
{
- int i;
+ int i;
- /* interpolates a layer at a time */
- for (i = 0; i < data->totlayer; ++i) {
- if (CustomData_layer_has_interp(data, i)) {
- return true;
- }
- }
+ /* interpolates a layer at a time */
+ for (i = 0; i < data->totlayer; ++i) {
+ if (CustomData_layer_has_interp(data, i)) {
+ return true;
+ }
+ }
- return false;
+ return false;
}
bool CustomData_has_referenced(const struct CustomData *data)
{
- int i;
- for (i = 0; i < data->totlayer; ++i) {
- if (data->layers[i].flag & CD_FLAG_NOFREE) {
- return true;
- }
- }
- return false;
+ int i;
+ for (i = 0; i < data->totlayer; ++i) {
+ if (data->layers[i].flag & CD_FLAG_NOFREE) {
+ return true;
+ }
+ }
+ return false;
}
/* copies the "value" (e.g. mloopuv uv or mloopcol colors) from one block to
* another, while not overwriting anything else (e.g. flags)*/
void CustomData_data_copy_value(int type, const void *source, void *dest)
{
- const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+ const LayerTypeInfo *typeInfo = layerType_getInfo(type);
- if (!dest) return;
+ if (!dest)
+ return;
- if (typeInfo->copyvalue)
- typeInfo->copyvalue(source, dest, CDT_MIX_NOMIX, 0.0f);
- else
- memcpy(dest, source, typeInfo->size);
+ if (typeInfo->copyvalue)
+ typeInfo->copyvalue(source, dest, CDT_MIX_NOMIX, 0.0f);
+ else
+ memcpy(dest, source, typeInfo->size);
}
/* Mixes the "value" (e.g. mloopuv uv or mloopcol colors) from one block into
* another, while not overwriting anything else (e.g. flags)*/
-void CustomData_data_mix_value(int type, const void *source, void *dest, const int mixmode, const float mixfactor)
+void CustomData_data_mix_value(
+ int type, const void *source, void *dest, const int mixmode, const float mixfactor)
{
- const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+ const LayerTypeInfo *typeInfo = layerType_getInfo(type);
- if (!dest) return;
+ if (!dest)
+ return;
- if (typeInfo->copyvalue) {
- typeInfo->copyvalue(source, dest, mixmode, mixfactor);
- }
- else {
- /* Mere copy if no advanced interpolation is supported. */
- memcpy(dest, source, typeInfo->size);
- }
+ if (typeInfo->copyvalue) {
+ typeInfo->copyvalue(source, dest, mixmode, mixfactor);
+ }
+ else {
+ /* Mere copy if no advanced interpolation is supported. */
+ memcpy(dest, source, typeInfo->size);
+ }
}
bool CustomData_data_equals(int type, const void *data1, const void *data2)
{
- const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+ const LayerTypeInfo *typeInfo = layerType_getInfo(type);
- if (typeInfo->equal)
- return typeInfo->equal(data1, data2);
- else return !memcmp(data1, data2, typeInfo->size);
+ if (typeInfo->equal)
+ return typeInfo->equal(data1, data2);
+ else
+ return !memcmp(data1, data2, typeInfo->size);
}
void CustomData_data_initminmax(int type, void *min, void *max)
{
- const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+ const LayerTypeInfo *typeInfo = layerType_getInfo(type);
- if (typeInfo->initminmax)
- typeInfo->initminmax(min, max);
+ if (typeInfo->initminmax)
+ typeInfo->initminmax(min, max);
}
-
void CustomData_data_dominmax(int type, const void *data, void *min, void *max)
{
- const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+ const LayerTypeInfo *typeInfo = layerType_getInfo(type);
- if (typeInfo->dominmax)
- typeInfo->dominmax(data, min, max);
+ if (typeInfo->dominmax)
+ typeInfo->dominmax(data, min, max);
}
-
void CustomData_data_multiply(int type, void *data, float fac)
{
- const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+ const LayerTypeInfo *typeInfo = layerType_getInfo(type);
- if (typeInfo->multiply)
- typeInfo->multiply(data, fac);
+ if (typeInfo->multiply)
+ typeInfo->multiply(data, fac);
}
-
void CustomData_data_add(int type, void *data1, const void *data2)
{
- const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+ const LayerTypeInfo *typeInfo = layerType_getInfo(type);
- if (typeInfo->add)
- typeInfo->add(data1, data2);
+ if (typeInfo->add)
+ typeInfo->add(data1, data2);
}
void CustomData_bmesh_set(const CustomData *data, void *block, int type, const void *source)
{
- void *dest = CustomData_bmesh_get(data, block, type);
- const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+ void *dest = CustomData_bmesh_get(data, block, type);
+ const LayerTypeInfo *typeInfo = layerType_getInfo(type);
- if (!dest) return;
+ if (!dest)
+ return;
- if (typeInfo->copy)
- typeInfo->copy(source, dest, 1);
- else
- memcpy(dest, source, typeInfo->size);
+ if (typeInfo->copy)
+ typeInfo->copy(source, dest, 1);
+ else
+ memcpy(dest, source, typeInfo->size);
}
void CustomData_bmesh_set_n(CustomData *data, void *block, int type, int n, const void *source)
{
- void *dest = CustomData_bmesh_get_n(data, block, type, n);
- const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+ void *dest = CustomData_bmesh_get_n(data, block, type, n);
+ const LayerTypeInfo *typeInfo = layerType_getInfo(type);
- if (!dest) return;
+ if (!dest)
+ return;
- if (typeInfo->copy)
- typeInfo->copy(source, dest, 1);
- else
- memcpy(dest, source, typeInfo->size);
+ if (typeInfo->copy)
+ typeInfo->copy(source, dest, 1);
+ else
+ memcpy(dest, source, typeInfo->size);
}
void CustomData_bmesh_set_layer_n(CustomData *data, void *block, int n, const void *source)
{
- void *dest = CustomData_bmesh_get_layer_n(data, block, n);
- const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[n].type);
+ void *dest = CustomData_bmesh_get_layer_n(data, block, n);
+ const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[n].type);
- if (!dest) return;
+ if (!dest)
+ return;
- if (typeInfo->copy)
- typeInfo->copy(source, dest, 1);
- else
- memcpy(dest, source, typeInfo->size);
+ if (typeInfo->copy)
+ typeInfo->copy(source, dest, 1);
+ else
+ memcpy(dest, source, typeInfo->size);
}
/**
* \note src_blocks_ofs & dst_block_ofs
* must be pointers to the data, offset by layer->offset already.
*/
-void CustomData_bmesh_interp_n(
- CustomData *data, const void **src_blocks_ofs,
- const float *weights, const float *sub_weights,
- int count, void *dst_block_ofs, int n)
-{
- CustomDataLayer *layer = &data->layers[n];
- const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
-
- typeInfo->interp(src_blocks_ofs, weights, sub_weights, count, dst_block_ofs);
-}
-
-void CustomData_bmesh_interp(
- CustomData *data, const void **src_blocks,
- const float *weights, const float *sub_weights,
- int count, void *dst_block)
-{
- int i, j;
- void *source_buf[SOURCE_BUF_SIZE];
- const void **sources = (const void **)source_buf;
-
- /* slow fallback in case we're interpolating a ridiculous number of
- * elements
- */
- if (count > SOURCE_BUF_SIZE)
- sources = MEM_malloc_arrayN(count, sizeof(*sources), __func__);
-
- /* interpolates a layer at a time */
- for (i = 0; i < data->totlayer; ++i) {
- CustomDataLayer *layer = &data->layers[i];
- const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
- if (typeInfo->interp) {
- for (j = 0; j < count; ++j) {
- sources[j] = POINTER_OFFSET(src_blocks[j], layer->offset);
- }
- CustomData_bmesh_interp_n(
- data, sources,
- weights, sub_weights, count,
- POINTER_OFFSET(dst_block, layer->offset), i);
- }
- }
-
- if (count > SOURCE_BUF_SIZE) MEM_freeN((void *)sources);
+void CustomData_bmesh_interp_n(CustomData *data,
+ const void **src_blocks_ofs,
+ const float *weights,
+ const float *sub_weights,
+ int count,
+ void *dst_block_ofs,
+ int n)
+{
+ CustomDataLayer *layer = &data->layers[n];
+ const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
+
+ typeInfo->interp(src_blocks_ofs, weights, sub_weights, count, dst_block_ofs);
+}
+
+void CustomData_bmesh_interp(CustomData *data,
+ const void **src_blocks,
+ const float *weights,
+ const float *sub_weights,
+ int count,
+ void *dst_block)
+{
+ int i, j;
+ void *source_buf[SOURCE_BUF_SIZE];
+ const void **sources = (const void **)source_buf;
+
+ /* slow fallback in case we're interpolating a ridiculous number of
+ * elements
+ */
+ if (count > SOURCE_BUF_SIZE)
+ sources = MEM_malloc_arrayN(count, sizeof(*sources), __func__);
+
+ /* interpolates a layer at a time */
+ for (i = 0; i < data->totlayer; ++i) {
+ CustomDataLayer *layer = &data->layers[i];
+ const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
+ if (typeInfo->interp) {
+ for (j = 0; j < count; ++j) {
+ sources[j] = POINTER_OFFSET(src_blocks[j], layer->offset);
+ }
+ CustomData_bmesh_interp_n(
+ data, sources, weights, sub_weights, count, POINTER_OFFSET(dst_block, layer->offset), i);
+ }
+ }
+
+ if (count > SOURCE_BUF_SIZE)
+ MEM_freeN((void *)sources);
}
static void CustomData_bmesh_set_default_n(CustomData *data, void **block, int n)
{
- const LayerTypeInfo *typeInfo;
- int offset = data->layers[n].offset;
+ const LayerTypeInfo *typeInfo;
+ int offset = data->layers[n].offset;
- typeInfo = layerType_getInfo(data->layers[n].type);
+ typeInfo = layerType_getInfo(data->layers[n].type);
- if (typeInfo->set_default) {
- typeInfo->set_default(POINTER_OFFSET(*block, offset), 1);
- }
- else {
- memset(POINTER_OFFSET(*block, offset), 0, typeInfo->size);
- }
+ if (typeInfo->set_default) {
+ typeInfo->set_default(POINTER_OFFSET(*block, offset), 1);
+ }
+ else {
+ memset(POINTER_OFFSET(*block, offset), 0, typeInfo->size);
+ }
}
void CustomData_bmesh_set_default(CustomData *data, void **block)
{
- int i;
+ int i;
- if (*block == NULL)
- CustomData_bmesh_alloc_block(data, block);
+ if (*block == NULL)
+ CustomData_bmesh_alloc_block(data, block);
- for (i = 0; i < data->totlayer; ++i) {
- CustomData_bmesh_set_default_n(data, block, i);
- }
+ for (i = 0; i < data->totlayer; ++i) {
+ CustomData_bmesh_set_default_n(data, block, i);
+ }
}
/**
@@ -3346,109 +3685,116 @@ void CustomData_bmesh_set_default(CustomData *data, void **block)
* typically you'll want to use this if the BM_xxx create function
* is called with BM_CREATE_SKIP_CD flag
*/
-void CustomData_to_bmesh_block(const CustomData *source, CustomData *dest,
- int src_index, void **dest_block, bool use_default_init)
-{
- const LayerTypeInfo *typeInfo;
- int dest_i, src_i;
-
- if (*dest_block == NULL)
- CustomData_bmesh_alloc_block(dest, dest_block);
-
- /* copies a layer at a time */
- dest_i = 0;
- for (src_i = 0; src_i < source->totlayer; ++src_i) {
-
- /* find the first dest layer with type >= the source type
- * (this should work because layers are ordered by type)
- */
- while (dest_i < dest->totlayer && dest->layers[dest_i].type < source->layers[src_i].type) {
- if (use_default_init) {
- CustomData_bmesh_set_default_n(dest, dest_block, dest_i);
- }
- dest_i++;
- }
-
- /* if there are no more dest layers, we're done */
- if (dest_i >= dest->totlayer) break;
-
- /* if we found a matching layer, copy the data */
- if (dest->layers[dest_i].type == source->layers[src_i].type) {
- int offset = dest->layers[dest_i].offset;
- const void *src_data = source->layers[src_i].data;
- void *dest_data = POINTER_OFFSET(*dest_block, offset);
-
- typeInfo = layerType_getInfo(dest->layers[dest_i].type);
- const size_t src_offset = (size_t)src_index * typeInfo->size;
-
- if (typeInfo->copy)
- typeInfo->copy(POINTER_OFFSET(src_data, src_offset), dest_data, 1);
- else
- memcpy(dest_data, POINTER_OFFSET(src_data, src_offset), typeInfo->size);
-
- /* if there are multiple source & dest layers of the same type,
- * we don't want to copy all source layers to the same dest, so
- * increment dest_i
- */
- dest_i++;
- }
- }
-
- if (use_default_init) {
- while (dest_i < dest->totlayer) {
- CustomData_bmesh_set_default_n(dest, dest_block, dest_i);
- dest_i++;
- }
- }
-}
-
-void CustomData_from_bmesh_block(const CustomData *source, CustomData *dest,
- void *src_block, int dst_index)
-{
- int dest_i, src_i;
-
- /* copies a layer at a time */
- dest_i = 0;
- for (src_i = 0; src_i < source->totlayer; ++src_i) {
-
- /* find the first dest layer with type >= the source type
- * (this should work because layers are ordered by type)
- */
- while (dest_i < dest->totlayer && dest->layers[dest_i].type < source->layers[src_i].type) {
- dest_i++;
- }
-
- /* if there are no more dest layers, we're done */
- if (dest_i >= dest->totlayer) return;
-
- /* if we found a matching layer, copy the data */
- if (dest->layers[dest_i].type == source->layers[src_i].type) {
- const LayerTypeInfo *typeInfo = layerType_getInfo(dest->layers[dest_i].type);
- int offset = source->layers[src_i].offset;
- const void *src_data = POINTER_OFFSET(src_block, offset);
- void *dst_data = POINTER_OFFSET(dest->layers[dest_i].data, (size_t)dst_index * typeInfo->size);
-
- if (typeInfo->copy)
- typeInfo->copy(src_data, dst_data, 1);
- else
- memcpy(dst_data, src_data, typeInfo->size);
-
- /* if there are multiple source & dest layers of the same type,
- * we don't want to copy all source layers to the same dest, so
- * increment dest_i
- */
- dest_i++;
- }
- }
-
+void CustomData_to_bmesh_block(const CustomData *source,
+ CustomData *dest,
+ int src_index,
+ void **dest_block,
+ bool use_default_init)
+{
+ const LayerTypeInfo *typeInfo;
+ int dest_i, src_i;
+
+ if (*dest_block == NULL)
+ CustomData_bmesh_alloc_block(dest, dest_block);
+
+ /* copies a layer at a time */
+ dest_i = 0;
+ for (src_i = 0; src_i < source->totlayer; ++src_i) {
+
+ /* find the first dest layer with type >= the source type
+ * (this should work because layers are ordered by type)
+ */
+ while (dest_i < dest->totlayer && dest->layers[dest_i].type < source->layers[src_i].type) {
+ if (use_default_init) {
+ CustomData_bmesh_set_default_n(dest, dest_block, dest_i);
+ }
+ dest_i++;
+ }
+
+ /* if there are no more dest layers, we're done */
+ if (dest_i >= dest->totlayer)
+ break;
+
+ /* if we found a matching layer, copy the data */
+ if (dest->layers[dest_i].type == source->layers[src_i].type) {
+ int offset = dest->layers[dest_i].offset;
+ const void *src_data = source->layers[src_i].data;
+ void *dest_data = POINTER_OFFSET(*dest_block, offset);
+
+ typeInfo = layerType_getInfo(dest->layers[dest_i].type);
+ const size_t src_offset = (size_t)src_index * typeInfo->size;
+
+ if (typeInfo->copy)
+ typeInfo->copy(POINTER_OFFSET(src_data, src_offset), dest_data, 1);
+ else
+ memcpy(dest_data, POINTER_OFFSET(src_data, src_offset), typeInfo->size);
+
+ /* if there are multiple source & dest layers of the same type,
+ * we don't want to copy all source layers to the same dest, so
+ * increment dest_i
+ */
+ dest_i++;
+ }
+ }
+
+ if (use_default_init) {
+ while (dest_i < dest->totlayer) {
+ CustomData_bmesh_set_default_n(dest, dest_block, dest_i);
+ dest_i++;
+ }
+ }
+}
+
+void CustomData_from_bmesh_block(const CustomData *source,
+ CustomData *dest,
+ void *src_block,
+ int dst_index)
+{
+ int dest_i, src_i;
+
+ /* copies a layer at a time */
+ dest_i = 0;
+ for (src_i = 0; src_i < source->totlayer; ++src_i) {
+
+ /* find the first dest layer with type >= the source type
+ * (this should work because layers are ordered by type)
+ */
+ while (dest_i < dest->totlayer && dest->layers[dest_i].type < source->layers[src_i].type) {
+ dest_i++;
+ }
+
+ /* if there are no more dest layers, we're done */
+ if (dest_i >= dest->totlayer)
+ return;
+
+ /* if we found a matching layer, copy the data */
+ if (dest->layers[dest_i].type == source->layers[src_i].type) {
+ const LayerTypeInfo *typeInfo = layerType_getInfo(dest->layers[dest_i].type);
+ int offset = source->layers[src_i].offset;
+ const void *src_data = POINTER_OFFSET(src_block, offset);
+ void *dst_data = POINTER_OFFSET(dest->layers[dest_i].data,
+ (size_t)dst_index * typeInfo->size);
+
+ if (typeInfo->copy)
+ typeInfo->copy(src_data, dst_data, 1);
+ else
+ memcpy(dst_data, src_data, typeInfo->size);
+
+ /* if there are multiple source & dest layers of the same type,
+ * we don't want to copy all source layers to the same dest, so
+ * increment dest_i
+ */
+ dest_i++;
+ }
+ }
}
void CustomData_file_write_info(int type, const char **r_struct_name, int *r_struct_num)
{
- const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+ const LayerTypeInfo *typeInfo = layerType_getInfo(type);
- *r_struct_name = typeInfo->structname;
- *r_struct_num = typeInfo->structnum;
+ *r_struct_name = typeInfo->structname;
+ *r_struct_num = typeInfo->structnum;
}
/**
@@ -3465,63 +3811,65 @@ void CustomData_file_write_info(int type, const char **r_struct_name, int *r_str
* \note data->typemap is not updated here, since it is always rebuilt on file read anyway. This means written
* typemap does not match written layers (as returned by \a r_write_layers). Trivial to fix is ever needed.
*/
-void CustomData_file_write_prepare(
- CustomData *data,
- CustomDataLayer **r_write_layers, CustomDataLayer *write_layers_buff, size_t write_layers_size)
-{
- CustomDataLayer *write_layers = write_layers_buff;
- const size_t chunk_size = (write_layers_size > 0) ? write_layers_size : CD_TEMP_CHUNK_SIZE;
-
- const int totlayer = data->totlayer;
- int i, j;
-
- for (i = 0, j = 0; i < totlayer; i++) {
- CustomDataLayer *layer = &data->layers[i];
- if (layer->flag & CD_FLAG_NOCOPY) { /* Layers with this flag set are not written to file. */
- data->totlayer--;
- /* CLOG_WARN(&LOG, "skipping layer %p (%s)", layer, layer->name); */
- }
- else {
- if (UNLIKELY((size_t)j >= write_layers_size)) {
- if (write_layers == write_layers_buff) {
- write_layers = MEM_malloc_arrayN((write_layers_size + chunk_size), sizeof(*write_layers), __func__);
- if (write_layers_buff) {
- memcpy(write_layers, write_layers_buff, sizeof(*write_layers) * write_layers_size);
- }
- }
- else {
- write_layers = MEM_reallocN(write_layers, sizeof(*write_layers) * (write_layers_size + chunk_size));
- }
- write_layers_size += chunk_size;
- }
- write_layers[j++] = *layer;
- }
- }
- BLI_assert(j == data->totlayer);
- data->maxlayer = data->totlayer; /* We only write that much of data! */
- *r_write_layers = write_layers;
+void CustomData_file_write_prepare(CustomData *data,
+ CustomDataLayer **r_write_layers,
+ CustomDataLayer *write_layers_buff,
+ size_t write_layers_size)
+{
+ CustomDataLayer *write_layers = write_layers_buff;
+ const size_t chunk_size = (write_layers_size > 0) ? write_layers_size : CD_TEMP_CHUNK_SIZE;
+
+ const int totlayer = data->totlayer;
+ int i, j;
+
+ for (i = 0, j = 0; i < totlayer; i++) {
+ CustomDataLayer *layer = &data->layers[i];
+ if (layer->flag & CD_FLAG_NOCOPY) { /* Layers with this flag set are not written to file. */
+ data->totlayer--;
+ /* CLOG_WARN(&LOG, "skipping layer %p (%s)", layer, layer->name); */
+ }
+ else {
+ if (UNLIKELY((size_t)j >= write_layers_size)) {
+ if (write_layers == write_layers_buff) {
+ write_layers = MEM_malloc_arrayN(
+ (write_layers_size + chunk_size), sizeof(*write_layers), __func__);
+ if (write_layers_buff) {
+ memcpy(write_layers, write_layers_buff, sizeof(*write_layers) * write_layers_size);
+ }
+ }
+ else {
+ write_layers = MEM_reallocN(write_layers,
+ sizeof(*write_layers) * (write_layers_size + chunk_size));
+ }
+ write_layers_size += chunk_size;
+ }
+ write_layers[j++] = *layer;
+ }
+ }
+ BLI_assert(j == data->totlayer);
+ data->maxlayer = data->totlayer; /* We only write that much of data! */
+ *r_write_layers = write_layers;
}
int CustomData_sizeof(int type)
{
- const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+ const LayerTypeInfo *typeInfo = layerType_getInfo(type);
- return typeInfo->size;
+ return typeInfo->size;
}
const char *CustomData_layertype_name(int type)
{
- return layerType_getName(type);
+ return layerType_getName(type);
}
-
/**
* Can only ever be one of these.
*/
bool CustomData_layertype_is_singleton(int type)
{
- const LayerTypeInfo *typeInfo = layerType_getInfo(type);
- return typeInfo->defaultname == NULL;
+ const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+ return typeInfo->defaultname == NULL;
}
/**
@@ -3529,139 +3877,148 @@ bool CustomData_layertype_is_singleton(int type)
*/
int CustomData_layertype_layers_max(const int type)
{
- const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+ const LayerTypeInfo *typeInfo = layerType_getInfo(type);
- /* Same test as for singleton above. */
- if (typeInfo->defaultname == NULL) {
- return 1;
- }
- else if (typeInfo->layers_max == NULL) {
- return -1;
- }
+ /* Same test as for singleton above. */
+ if (typeInfo->defaultname == NULL) {
+ return 1;
+ }
+ else if (typeInfo->layers_max == NULL) {
+ return -1;
+ }
- return typeInfo->layers_max();
+ return typeInfo->layers_max();
}
static bool CustomData_is_property_layer(int type)
{
- if ((type == CD_PROP_FLT) || (type == CD_PROP_INT) || (type == CD_PROP_STR))
- return true;
- return false;
+ if ((type == CD_PROP_FLT) || (type == CD_PROP_INT) || (type == CD_PROP_STR))
+ return true;
+ return false;
}
static bool cd_layer_find_dupe(CustomData *data, const char *name, int type, int index)
{
- int i;
- /* see if there is a duplicate */
- for (i = 0; i < data->totlayer; i++) {
- if (i != index) {
- CustomDataLayer *layer = &data->layers[i];
+ int i;
+ /* see if there is a duplicate */
+ for (i = 0; i < data->totlayer; i++) {
+ if (i != index) {
+ CustomDataLayer *layer = &data->layers[i];
- if (CustomData_is_property_layer(type)) {
- if (CustomData_is_property_layer(layer->type) && STREQ(layer->name, name)) {
- return true;
- }
- }
- else {
- if (i != index && layer->type == type && STREQ(layer->name, name)) {
- return true;
- }
- }
- }
- }
+ if (CustomData_is_property_layer(type)) {
+ if (CustomData_is_property_layer(layer->type) && STREQ(layer->name, name)) {
+ return true;
+ }
+ }
+ else {
+ if (i != index && layer->type == type && STREQ(layer->name, name)) {
+ return true;
+ }
+ }
+ }
+ }
- return false;
+ return false;
}
static bool customdata_unique_check(void *arg, const char *name)
{
- struct {CustomData *data; int type; int index; } *data_arg = arg;
- return cd_layer_find_dupe(data_arg->data, name, data_arg->type, data_arg->index);
+ struct {
+ CustomData *data;
+ int type;
+ int index;
+ } *data_arg = arg;
+ return cd_layer_find_dupe(data_arg->data, name, data_arg->type, data_arg->index);
}
void CustomData_set_layer_unique_name(CustomData *data, int index)
{
- CustomDataLayer *nlayer = &data->layers[index];
- const LayerTypeInfo *typeInfo = layerType_getInfo(nlayer->type);
+ CustomDataLayer *nlayer = &data->layers[index];
+ const LayerTypeInfo *typeInfo = layerType_getInfo(nlayer->type);
- struct {CustomData *data; int type; int index; } data_arg;
- data_arg.data = data;
- data_arg.type = nlayer->type;
- data_arg.index = index;
+ struct {
+ CustomData *data;
+ int type;
+ int index;
+ } data_arg;
+ data_arg.data = data;
+ data_arg.type = nlayer->type;
+ data_arg.index = index;
- if (!typeInfo->defaultname) {
- return;
- }
+ if (!typeInfo->defaultname) {
+ return;
+ }
- /* Set default name if none specified. Note we only call DATA_() when
- * needed to avoid overhead of locale lookups in the depsgraph. */
- if (nlayer->name[0] == '\0') {
- STRNCPY(nlayer->name, DATA_(typeInfo->defaultname));
- }
+ /* Set default name if none specified. Note we only call DATA_() when
+ * needed to avoid overhead of locale lookups in the depsgraph. */
+ if (nlayer->name[0] == '\0') {
+ STRNCPY(nlayer->name, DATA_(typeInfo->defaultname));
+ }
- BLI_uniquename_cb(customdata_unique_check, &data_arg, NULL, '.', nlayer->name, sizeof(nlayer->name));
+ BLI_uniquename_cb(
+ customdata_unique_check, &data_arg, NULL, '.', nlayer->name, sizeof(nlayer->name));
}
-void CustomData_validate_layer_name(const CustomData *data, int type, const char *name, char *outname)
+void CustomData_validate_layer_name(const CustomData *data,
+ int type,
+ const char *name,
+ char *outname)
{
- int index = -1;
+ int index = -1;
- /* if a layer name was given, try to find that layer */
- if (name[0])
- index = CustomData_get_named_layer_index(data, type, name);
+ /* if a layer name was given, try to find that layer */
+ if (name[0])
+ index = CustomData_get_named_layer_index(data, type, name);
- if (index == -1) {
- /* either no layer was specified, or the layer we want has been
- * deleted, so assign the active layer to name
- */
- index = CustomData_get_active_layer_index(data, type);
- BLI_strncpy(outname, data->layers[index].name, MAX_CUSTOMDATA_LAYER_NAME);
- }
- else {
- BLI_strncpy(outname, name, MAX_CUSTOMDATA_LAYER_NAME);
- }
+ if (index == -1) {
+ /* either no layer was specified, or the layer we want has been
+ * deleted, so assign the active layer to name
+ */
+ index = CustomData_get_active_layer_index(data, type);
+ BLI_strncpy(outname, data->layers[index].name, MAX_CUSTOMDATA_LAYER_NAME);
+ }
+ else {
+ BLI_strncpy(outname, name, MAX_CUSTOMDATA_LAYER_NAME);
+ }
}
bool CustomData_verify_versions(struct CustomData *data, int index)
{
- const LayerTypeInfo *typeInfo;
- CustomDataLayer *layer = &data->layers[index];
- bool keeplayer = true;
- int i;
-
- if (layer->type >= CD_NUMTYPES) {
- keeplayer = false; /* unknown layer type from future version */
- }
- else {
- typeInfo = layerType_getInfo(layer->type);
-
- if (!typeInfo->defaultname && (index > 0) &&
- data->layers[index - 1].type == layer->type)
- {
- keeplayer = false; /* multiple layers of which we only support one */
- }
- /* This is a pre-emptive fix for cases that should not happen (layers that should not be written
- * in .blend files), but can happen due to bugs (see e.g. T62318).
- * Also for forward compatibility, in future, we may put into .blend file some currently un-written data types,
- * this should cover that case as well.
- * Better to be safe here, and fix issue on the fly rather than crash... */
- /* 0 structnum is used in writing code to tag layer types that should not be written. */
- else if (typeInfo->structnum == 0 &&
- /* XXX Not sure why those two are exception, maybe that should be fixed? */
- !ELEM(layer->type, CD_PAINT_MASK, CD_FACEMAP))
- {
- keeplayer = false;
- CLOG_WARN(&LOG, ".blend file read: removing a data layer that should not have been written");
- }
- }
-
- if (!keeplayer) {
- for (i = index + 1; i < data->totlayer; ++i)
- data->layers[i - 1] = data->layers[i];
- data->totlayer--;
- }
-
- return keeplayer;
+ const LayerTypeInfo *typeInfo;
+ CustomDataLayer *layer = &data->layers[index];
+ bool keeplayer = true;
+ int i;
+
+ if (layer->type >= CD_NUMTYPES) {
+ keeplayer = false; /* unknown layer type from future version */
+ }
+ else {
+ typeInfo = layerType_getInfo(layer->type);
+
+ if (!typeInfo->defaultname && (index > 0) && data->layers[index - 1].type == layer->type) {
+ keeplayer = false; /* multiple layers of which we only support one */
+ }
+ /* This is a pre-emptive fix for cases that should not happen (layers that should not be written
+ * in .blend files), but can happen due to bugs (see e.g. T62318).
+ * Also for forward compatibility, in future, we may put into .blend file some currently un-written data types,
+ * this should cover that case as well.
+ * Better to be safe here, and fix issue on the fly rather than crash... */
+ /* 0 structnum is used in writing code to tag layer types that should not be written. */
+ else if (typeInfo->structnum == 0 &&
+ /* XXX Not sure why those two are exception, maybe that should be fixed? */
+ !ELEM(layer->type, CD_PAINT_MASK, CD_FACEMAP)) {
+ keeplayer = false;
+ CLOG_WARN(&LOG, ".blend file read: removing a data layer that should not have been written");
+ }
+ }
+
+ if (!keeplayer) {
+ for (i = index + 1; i < data->totlayer; ++i)
+ data->layers[i - 1] = data->layers[i];
+ data->totlayer--;
+ }
+
+ return keeplayer;
}
/**
@@ -3671,537 +4028,555 @@ bool CustomData_verify_versions(struct CustomData *data, int index)
*/
bool CustomData_layer_validate(CustomDataLayer *layer, const uint totitems, const bool do_fixes)
{
- const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
+ const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
- if (typeInfo->validate != NULL) {
- return typeInfo->validate(layer->data, totitems, do_fixes);
- }
+ if (typeInfo->validate != NULL) {
+ return typeInfo->validate(layer->data, totitems, do_fixes);
+ }
- return false;
+ return false;
}
/****************************** External Files *******************************/
-static void customdata_external_filename(char filename[FILE_MAX], ID *id, CustomDataExternal *external)
+static void customdata_external_filename(char filename[FILE_MAX],
+ ID *id,
+ CustomDataExternal *external)
{
- BLI_strncpy(filename, external->filename, FILE_MAX);
- BLI_path_abs(filename, ID_BLEND_PATH_FROM_GLOBAL(id));
+ BLI_strncpy(filename, external->filename, FILE_MAX);
+ BLI_path_abs(filename, ID_BLEND_PATH_FROM_GLOBAL(id));
}
void CustomData_external_reload(CustomData *data, ID *UNUSED(id), CustomDataMask mask, int totelem)
{
- CustomDataLayer *layer;
- const LayerTypeInfo *typeInfo;
- int i;
+ CustomDataLayer *layer;
+ const LayerTypeInfo *typeInfo;
+ int i;
- for (i = 0; i < data->totlayer; i++) {
- layer = &data->layers[i];
- typeInfo = layerType_getInfo(layer->type);
+ for (i = 0; i < data->totlayer; i++) {
+ layer = &data->layers[i];
+ typeInfo = layerType_getInfo(layer->type);
- if (!(mask & CD_TYPE_AS_MASK(layer->type))) {
- /* pass */
- }
- else if ((layer->flag & CD_FLAG_EXTERNAL) && (layer->flag & CD_FLAG_IN_MEMORY)) {
- if (typeInfo->free)
- typeInfo->free(layer->data, totelem, typeInfo->size);
- layer->flag &= ~CD_FLAG_IN_MEMORY;
- }
- }
+ if (!(mask & CD_TYPE_AS_MASK(layer->type))) {
+ /* pass */
+ }
+ else if ((layer->flag & CD_FLAG_EXTERNAL) && (layer->flag & CD_FLAG_IN_MEMORY)) {
+ if (typeInfo->free)
+ typeInfo->free(layer->data, totelem, typeInfo->size);
+ layer->flag &= ~CD_FLAG_IN_MEMORY;
+ }
+ }
}
void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int totelem)
{
- CustomDataExternal *external = data->external;
- CustomDataLayer *layer;
- CDataFile *cdf;
- CDataFileLayer *blay;
- char filename[FILE_MAX];
- const LayerTypeInfo *typeInfo;
- int i, update = 0;
-
- if (!external)
- return;
-
- for (i = 0; i < data->totlayer; i++) {
- layer = &data->layers[i];
- typeInfo = layerType_getInfo(layer->type);
-
- if (!(mask & CD_TYPE_AS_MASK(layer->type))) {
- /* pass */
- }
- else if (layer->flag & CD_FLAG_IN_MEMORY) {
- /* pass */
- }
- else if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->read) {
- update = 1;
- }
- }
-
- if (!update)
- return;
-
- customdata_external_filename(filename, id, external);
-
- cdf = cdf_create(CDF_TYPE_MESH);
- if (!cdf_read_open(cdf, filename)) {
- cdf_free(cdf);
- CLOG_ERROR(&LOG, "Failed to read %s layer from %s.", layerType_getName(layer->type), filename);
- return;
- }
-
- for (i = 0; i < data->totlayer; i++) {
- layer = &data->layers[i];
- typeInfo = layerType_getInfo(layer->type);
-
- if (!(mask & CD_TYPE_AS_MASK(layer->type))) {
- /* pass */
- }
- else if (layer->flag & CD_FLAG_IN_MEMORY) {
- /* pass */
- }
- else if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->read) {
- blay = cdf_layer_find(cdf, layer->type, layer->name);
-
- if (blay) {
- if (cdf_read_layer(cdf, blay)) {
- if (typeInfo->read(cdf, layer->data, totelem)) {
- /* pass */
- }
- else {
- break;
- }
- layer->flag |= CD_FLAG_IN_MEMORY;
- }
- else
- break;
- }
- }
- }
-
- cdf_read_close(cdf);
- cdf_free(cdf);
-}
-
-void CustomData_external_write(CustomData *data, ID *id, CustomDataMask mask, int totelem, int free)
-{
- CustomDataExternal *external = data->external;
- CustomDataLayer *layer;
- CDataFile *cdf;
- CDataFileLayer *blay;
- const LayerTypeInfo *typeInfo;
- int i, update = 0;
- char filename[FILE_MAX];
-
- if (!external)
- return;
-
- /* test if there is anything to write */
- for (i = 0; i < data->totlayer; i++) {
- layer = &data->layers[i];
- typeInfo = layerType_getInfo(layer->type);
-
- if (!(mask & CD_TYPE_AS_MASK(layer->type))) {
- /* pass */
- }
- else if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->write) {
- update = 1;
- }
- }
-
- if (!update)
- return;
-
- /* make sure data is read before we try to write */
- CustomData_external_read(data, id, mask, totelem);
- customdata_external_filename(filename, id, external);
-
- cdf = cdf_create(CDF_TYPE_MESH);
-
- for (i = 0; i < data->totlayer; i++) {
- layer = &data->layers[i];
- typeInfo = layerType_getInfo(layer->type);
-
- if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->filesize) {
- if (layer->flag & CD_FLAG_IN_MEMORY) {
- cdf_layer_add(cdf, layer->type, layer->name,
- typeInfo->filesize(cdf, layer->data, totelem));
- }
- else {
- cdf_free(cdf);
- return; /* read failed for a layer! */
- }
- }
- }
-
- if (!cdf_write_open(cdf, filename)) {
- CLOG_ERROR(&LOG, "Failed to open %s for writing.", filename);
- cdf_free(cdf);
- return;
- }
-
- for (i = 0; i < data->totlayer; i++) {
- layer = &data->layers[i];
- typeInfo = layerType_getInfo(layer->type);
-
- if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->write) {
- blay = cdf_layer_find(cdf, layer->type, layer->name);
-
- if (cdf_write_layer(cdf, blay)) {
- if (typeInfo->write(cdf, layer->data, totelem)) {
- /* pass */
- }
- else {
- break;
- }
- }
- else {
- break;
- }
- }
- }
-
- if (i != data->totlayer) {
- CLOG_ERROR(&LOG, "Failed to write data to %s.", filename);
- cdf_write_close(cdf);
- cdf_free(cdf);
- return;
- }
-
- for (i = 0; i < data->totlayer; i++) {
- layer = &data->layers[i];
- typeInfo = layerType_getInfo(layer->type);
-
- if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->write) {
- if (free) {
- if (typeInfo->free)
- typeInfo->free(layer->data, totelem, typeInfo->size);
- layer->flag &= ~CD_FLAG_IN_MEMORY;
- }
- }
- }
-
- cdf_write_close(cdf);
- cdf_free(cdf);
-}
-
-void CustomData_external_add(CustomData *data, ID *UNUSED(id), int type, int UNUSED(totelem), const char *filename)
-{
- CustomDataExternal *external = data->external;
- CustomDataLayer *layer;
- int layer_index;
-
- layer_index = CustomData_get_active_layer_index(data, type);
- if (layer_index == -1) return;
-
- layer = &data->layers[layer_index];
-
- if (layer->flag & CD_FLAG_EXTERNAL)
- return;
-
- if (!external) {
- external = MEM_callocN(sizeof(CustomDataExternal), "CustomDataExternal");
- data->external = external;
- }
- BLI_strncpy(external->filename, filename, sizeof(external->filename));
-
- layer->flag |= CD_FLAG_EXTERNAL | CD_FLAG_IN_MEMORY;
+ CustomDataExternal *external = data->external;
+ CustomDataLayer *layer;
+ CDataFile *cdf;
+ CDataFileLayer *blay;
+ char filename[FILE_MAX];
+ const LayerTypeInfo *typeInfo;
+ int i, update = 0;
+
+ if (!external)
+ return;
+
+ for (i = 0; i < data->totlayer; i++) {
+ layer = &data->layers[i];
+ typeInfo = layerType_getInfo(layer->type);
+
+ if (!(mask & CD_TYPE_AS_MASK(layer->type))) {
+ /* pass */
+ }
+ else if (layer->flag & CD_FLAG_IN_MEMORY) {
+ /* pass */
+ }
+ else if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->read) {
+ update = 1;
+ }
+ }
+
+ if (!update)
+ return;
+
+ customdata_external_filename(filename, id, external);
+
+ cdf = cdf_create(CDF_TYPE_MESH);
+ if (!cdf_read_open(cdf, filename)) {
+ cdf_free(cdf);
+ CLOG_ERROR(&LOG, "Failed to read %s layer from %s.", layerType_getName(layer->type), filename);
+ return;
+ }
+
+ for (i = 0; i < data->totlayer; i++) {
+ layer = &data->layers[i];
+ typeInfo = layerType_getInfo(layer->type);
+
+ if (!(mask & CD_TYPE_AS_MASK(layer->type))) {
+ /* pass */
+ }
+ else if (layer->flag & CD_FLAG_IN_MEMORY) {
+ /* pass */
+ }
+ else if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->read) {
+ blay = cdf_layer_find(cdf, layer->type, layer->name);
+
+ if (blay) {
+ if (cdf_read_layer(cdf, blay)) {
+ if (typeInfo->read(cdf, layer->data, totelem)) {
+ /* pass */
+ }
+ else {
+ break;
+ }
+ layer->flag |= CD_FLAG_IN_MEMORY;
+ }
+ else
+ break;
+ }
+ }
+ }
+
+ cdf_read_close(cdf);
+ cdf_free(cdf);
+}
+
+void CustomData_external_write(
+ CustomData *data, ID *id, CustomDataMask mask, int totelem, int free)
+{
+ CustomDataExternal *external = data->external;
+ CustomDataLayer *layer;
+ CDataFile *cdf;
+ CDataFileLayer *blay;
+ const LayerTypeInfo *typeInfo;
+ int i, update = 0;
+ char filename[FILE_MAX];
+
+ if (!external)
+ return;
+
+ /* test if there is anything to write */
+ for (i = 0; i < data->totlayer; i++) {
+ layer = &data->layers[i];
+ typeInfo = layerType_getInfo(layer->type);
+
+ if (!(mask & CD_TYPE_AS_MASK(layer->type))) {
+ /* pass */
+ }
+ else if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->write) {
+ update = 1;
+ }
+ }
+
+ if (!update)
+ return;
+
+ /* make sure data is read before we try to write */
+ CustomData_external_read(data, id, mask, totelem);
+ customdata_external_filename(filename, id, external);
+
+ cdf = cdf_create(CDF_TYPE_MESH);
+
+ for (i = 0; i < data->totlayer; i++) {
+ layer = &data->layers[i];
+ typeInfo = layerType_getInfo(layer->type);
+
+ if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->filesize) {
+ if (layer->flag & CD_FLAG_IN_MEMORY) {
+ cdf_layer_add(
+ cdf, layer->type, layer->name, typeInfo->filesize(cdf, layer->data, totelem));
+ }
+ else {
+ cdf_free(cdf);
+ return; /* read failed for a layer! */
+ }
+ }
+ }
+
+ if (!cdf_write_open(cdf, filename)) {
+ CLOG_ERROR(&LOG, "Failed to open %s for writing.", filename);
+ cdf_free(cdf);
+ return;
+ }
+
+ for (i = 0; i < data->totlayer; i++) {
+ layer = &data->layers[i];
+ typeInfo = layerType_getInfo(layer->type);
+
+ if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->write) {
+ blay = cdf_layer_find(cdf, layer->type, layer->name);
+
+ if (cdf_write_layer(cdf, blay)) {
+ if (typeInfo->write(cdf, layer->data, totelem)) {
+ /* pass */
+ }
+ else {
+ break;
+ }
+ }
+ else {
+ break;
+ }
+ }
+ }
+
+ if (i != data->totlayer) {
+ CLOG_ERROR(&LOG, "Failed to write data to %s.", filename);
+ cdf_write_close(cdf);
+ cdf_free(cdf);
+ return;
+ }
+
+ for (i = 0; i < data->totlayer; i++) {
+ layer = &data->layers[i];
+ typeInfo = layerType_getInfo(layer->type);
+
+ if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->write) {
+ if (free) {
+ if (typeInfo->free)
+ typeInfo->free(layer->data, totelem, typeInfo->size);
+ layer->flag &= ~CD_FLAG_IN_MEMORY;
+ }
+ }
+ }
+
+ cdf_write_close(cdf);
+ cdf_free(cdf);
+}
+
+void CustomData_external_add(
+ CustomData *data, ID *UNUSED(id), int type, int UNUSED(totelem), const char *filename)
+{
+ CustomDataExternal *external = data->external;
+ CustomDataLayer *layer;
+ int layer_index;
+
+ layer_index = CustomData_get_active_layer_index(data, type);
+ if (layer_index == -1)
+ return;
+
+ layer = &data->layers[layer_index];
+
+ if (layer->flag & CD_FLAG_EXTERNAL)
+ return;
+
+ if (!external) {
+ external = MEM_callocN(sizeof(CustomDataExternal), "CustomDataExternal");
+ data->external = external;
+ }
+ BLI_strncpy(external->filename, filename, sizeof(external->filename));
+
+ layer->flag |= CD_FLAG_EXTERNAL | CD_FLAG_IN_MEMORY;
}
void CustomData_external_remove(CustomData *data, ID *id, int type, int totelem)
{
- CustomDataExternal *external = data->external;
- CustomDataLayer *layer;
- //char filename[FILE_MAX];
- int layer_index; // i, remove_file;
+ CustomDataExternal *external = data->external;
+ CustomDataLayer *layer;
+ //char filename[FILE_MAX];
+ int layer_index; // i, remove_file;
- layer_index = CustomData_get_active_layer_index(data, type);
- if (layer_index == -1) return;
+ layer_index = CustomData_get_active_layer_index(data, type);
+ if (layer_index == -1)
+ return;
- layer = &data->layers[layer_index];
+ layer = &data->layers[layer_index];
- if (!external)
- return;
+ if (!external)
+ return;
- if (layer->flag & CD_FLAG_EXTERNAL) {
- if (!(layer->flag & CD_FLAG_IN_MEMORY))
- CustomData_external_read(data, id, CD_TYPE_AS_MASK(layer->type), totelem);
+ if (layer->flag & CD_FLAG_EXTERNAL) {
+ if (!(layer->flag & CD_FLAG_IN_MEMORY))
+ CustomData_external_read(data, id, CD_TYPE_AS_MASK(layer->type), totelem);
- layer->flag &= ~CD_FLAG_EXTERNAL;
- }
+ layer->flag &= ~CD_FLAG_EXTERNAL;
+ }
}
bool CustomData_external_test(CustomData *data, int type)
{
- CustomDataLayer *layer;
- int layer_index;
+ CustomDataLayer *layer;
+ int layer_index;
- layer_index = CustomData_get_active_layer_index(data, type);
- if (layer_index == -1) return false;
+ layer_index = CustomData_get_active_layer_index(data, type);
+ if (layer_index == -1)
+ return false;
- layer = &data->layers[layer_index];
- return (layer->flag & CD_FLAG_EXTERNAL) != 0;
+ layer = &data->layers[layer_index];
+ return (layer->flag & CD_FLAG_EXTERNAL) != 0;
}
/* ********** Mesh-to-mesh data transfer ********** */
static void copy_bit_flag(void *dst, const void *src, const size_t data_size, const uint64_t flag)
{
-#define COPY_BIT_FLAG(_type, _dst, _src, _f) \
-{ \
- const _type _val = *((_type *)(_src)) & ((_type)(_f)); \
- *((_type *)(_dst)) &= ~((_type)(_f)); \
- *((_type *)(_dst)) |= _val; \
-} (void) 0
-
- switch (data_size) {
- case 1:
- COPY_BIT_FLAG(uint8_t, dst, src, flag);
- break;
- case 2:
- COPY_BIT_FLAG(uint16_t, dst, src, flag);
- break;
- case 4:
- COPY_BIT_FLAG(uint32_t, dst, src, flag);
- break;
- case 8:
- COPY_BIT_FLAG(uint64_t, dst, src, flag);
- break;
- default:
- //CLOG_ERROR(&LOG, "Unknown flags-container size (%zu)", datasize);
- break;
- }
+#define COPY_BIT_FLAG(_type, _dst, _src, _f) \
+ { \
+ const _type _val = *((_type *)(_src)) & ((_type)(_f)); \
+ *((_type *)(_dst)) &= ~((_type)(_f)); \
+ *((_type *)(_dst)) |= _val; \
+ } \
+ (void)0
+
+ switch (data_size) {
+ case 1:
+ COPY_BIT_FLAG(uint8_t, dst, src, flag);
+ break;
+ case 2:
+ COPY_BIT_FLAG(uint16_t, dst, src, flag);
+ break;
+ case 4:
+ COPY_BIT_FLAG(uint32_t, dst, src, flag);
+ break;
+ case 8:
+ COPY_BIT_FLAG(uint64_t, dst, src, flag);
+ break;
+ default:
+ //CLOG_ERROR(&LOG, "Unknown flags-container size (%zu)", datasize);
+ break;
+ }
#undef COPY_BIT_FLAG
}
static bool check_bit_flag(const void *data, const size_t data_size, const uint64_t flag)
{
- switch (data_size) {
- case 1:
- return ((*((uint8_t *)data) & ((uint8_t)flag)) != 0);
- case 2:
- return ((*((uint16_t *)data) & ((uint16_t)flag)) != 0);
- case 4:
- return ((*((uint32_t *)data) & ((uint32_t)flag)) != 0);
- case 8:
- return ((*((uint64_t *)data) & ((uint64_t)flag)) != 0);
- default:
- //CLOG_ERROR(&LOG, "Unknown flags-container size (%zu)", datasize);
- return false;
- }
-}
-
-static void customdata_data_transfer_interp_generic(
- const CustomDataTransferLayerMap *laymap, void *data_dst,
- const void **sources, const float *weights, const int count,
- const float mix_factor)
-{
- /* Fake interpolation, we actually copy highest weighted source to dest.
- * Note we also handle bitflags here, in which case we rather choose to transfer value of elements totaling
- * more than 0.5 of weight. */
-
- int best_src_idx = 0;
-
- const int data_type = laymap->data_type;
- const int mix_mode = laymap->mix_mode;
-
- size_t data_size;
- const uint64_t data_flag = laymap->data_flag;
-
- cd_interp interp_cd = NULL;
- cd_copy copy_cd = NULL;
-
- void *tmp_dst;
-
- if (!sources) {
- /* Not supported here, abort. */
- return;
- }
-
- if (data_type & CD_FAKE) {
- data_size = laymap->data_size;
- }
- else {
- const LayerTypeInfo *type_info = layerType_getInfo(data_type);
-
- data_size = (size_t)type_info->size;
- interp_cd = type_info->interp;
- copy_cd = type_info->copy;
- }
-
- tmp_dst = MEM_mallocN(data_size, __func__);
-
- if (count > 1 && !interp_cd) {
- int i;
-
- if (data_flag) {
- /* Boolean case, we can 'interpolate' in two groups, and choose value from highest weighted group. */
- float tot_weight_true = 0.0f;
- int item_true_idx = -1, item_false_idx = -1;
-
- for (i = 0; i < count; i++) {
- if (check_bit_flag(sources[i], data_size, data_flag)) {
- tot_weight_true += weights[i];
- item_true_idx = i;
- }
- else {
- item_false_idx = i;
- }
- }
- best_src_idx = (tot_weight_true >= 0.5f) ? item_true_idx : item_false_idx;
- }
- else {
- /* We just choose highest weighted source. */
- float max_weight = 0.0f;
-
- for (i = 0; i < count; i++) {
- if (weights[i] > max_weight) {
- max_weight = weights[i];
- best_src_idx = i;
- }
- }
- }
- }
-
- BLI_assert(best_src_idx >= 0);
-
- if (interp_cd) {
- interp_cd(sources, weights, NULL, count, tmp_dst);
- }
- else if (data_flag) {
- copy_bit_flag(tmp_dst, sources[best_src_idx], data_size, data_flag);
- }
- /* No interpolation, just copy highest weight source element's data. */
- else if (copy_cd) {
- copy_cd(sources[best_src_idx], tmp_dst, 1);
- }
- else {
- memcpy(tmp_dst, sources[best_src_idx], data_size);
- }
-
- if (data_flag) {
- /* Bool flags, only copy if dest data is set (resp. unset) - only 'advanced' modes we can support here! */
- if (mix_factor >= 0.5f &&
- ((mix_mode == CDT_MIX_TRANSFER) ||
- (mix_mode == CDT_MIX_REPLACE_ABOVE_THRESHOLD && check_bit_flag(data_dst, data_size, data_flag)) ||
- (mix_mode == CDT_MIX_REPLACE_BELOW_THRESHOLD && !check_bit_flag(data_dst, data_size, data_flag))))
- {
- copy_bit_flag(data_dst, tmp_dst, data_size, data_flag);
- }
- }
- else if (!(data_type & CD_FAKE)) {
- CustomData_data_mix_value(data_type, tmp_dst, data_dst, mix_mode, mix_factor);
- }
- /* Else we can do nothing by default, needs custom interp func!
- * Note this is here only for sake of consistency, not expected to be used much actually? */
- else {
- if (mix_factor >= 0.5f) {
- memcpy(data_dst, tmp_dst, data_size);
- }
- }
-
- MEM_freeN(tmp_dst);
+ switch (data_size) {
+ case 1:
+ return ((*((uint8_t *)data) & ((uint8_t)flag)) != 0);
+ case 2:
+ return ((*((uint16_t *)data) & ((uint16_t)flag)) != 0);
+ case 4:
+ return ((*((uint32_t *)data) & ((uint32_t)flag)) != 0);
+ case 8:
+ return ((*((uint64_t *)data) & ((uint64_t)flag)) != 0);
+ default:
+ //CLOG_ERROR(&LOG, "Unknown flags-container size (%zu)", datasize);
+ return false;
+ }
+}
+
+static void customdata_data_transfer_interp_generic(const CustomDataTransferLayerMap *laymap,
+ void *data_dst,
+ const void **sources,
+ const float *weights,
+ const int count,
+ const float mix_factor)
+{
+ /* Fake interpolation, we actually copy highest weighted source to dest.
+ * Note we also handle bitflags here, in which case we rather choose to transfer value of elements totaling
+ * more than 0.5 of weight. */
+
+ int best_src_idx = 0;
+
+ const int data_type = laymap->data_type;
+ const int mix_mode = laymap->mix_mode;
+
+ size_t data_size;
+ const uint64_t data_flag = laymap->data_flag;
+
+ cd_interp interp_cd = NULL;
+ cd_copy copy_cd = NULL;
+
+ void *tmp_dst;
+
+ if (!sources) {
+ /* Not supported here, abort. */
+ return;
+ }
+
+ if (data_type & CD_FAKE) {
+ data_size = laymap->data_size;
+ }
+ else {
+ const LayerTypeInfo *type_info = layerType_getInfo(data_type);
+
+ data_size = (size_t)type_info->size;
+ interp_cd = type_info->interp;
+ copy_cd = type_info->copy;
+ }
+
+ tmp_dst = MEM_mallocN(data_size, __func__);
+
+ if (count > 1 && !interp_cd) {
+ int i;
+
+ if (data_flag) {
+ /* Boolean case, we can 'interpolate' in two groups, and choose value from highest weighted group. */
+ float tot_weight_true = 0.0f;
+ int item_true_idx = -1, item_false_idx = -1;
+
+ for (i = 0; i < count; i++) {
+ if (check_bit_flag(sources[i], data_size, data_flag)) {
+ tot_weight_true += weights[i];
+ item_true_idx = i;
+ }
+ else {
+ item_false_idx = i;
+ }
+ }
+ best_src_idx = (tot_weight_true >= 0.5f) ? item_true_idx : item_false_idx;
+ }
+ else {
+ /* We just choose highest weighted source. */
+ float max_weight = 0.0f;
+
+ for (i = 0; i < count; i++) {
+ if (weights[i] > max_weight) {
+ max_weight = weights[i];
+ best_src_idx = i;
+ }
+ }
+ }
+ }
+
+ BLI_assert(best_src_idx >= 0);
+
+ if (interp_cd) {
+ interp_cd(sources, weights, NULL, count, tmp_dst);
+ }
+ else if (data_flag) {
+ copy_bit_flag(tmp_dst, sources[best_src_idx], data_size, data_flag);
+ }
+ /* No interpolation, just copy highest weight source element's data. */
+ else if (copy_cd) {
+ copy_cd(sources[best_src_idx], tmp_dst, 1);
+ }
+ else {
+ memcpy(tmp_dst, sources[best_src_idx], data_size);
+ }
+
+ if (data_flag) {
+ /* Bool flags, only copy if dest data is set (resp. unset) - only 'advanced' modes we can support here! */
+ if (mix_factor >= 0.5f && ((mix_mode == CDT_MIX_TRANSFER) ||
+ (mix_mode == CDT_MIX_REPLACE_ABOVE_THRESHOLD &&
+ check_bit_flag(data_dst, data_size, data_flag)) ||
+ (mix_mode == CDT_MIX_REPLACE_BELOW_THRESHOLD &&
+ !check_bit_flag(data_dst, data_size, data_flag)))) {
+ copy_bit_flag(data_dst, tmp_dst, data_size, data_flag);
+ }
+ }
+ else if (!(data_type & CD_FAKE)) {
+ CustomData_data_mix_value(data_type, tmp_dst, data_dst, mix_mode, mix_factor);
+ }
+ /* Else we can do nothing by default, needs custom interp func!
+ * Note this is here only for sake of consistency, not expected to be used much actually? */
+ else {
+ if (mix_factor >= 0.5f) {
+ memcpy(data_dst, tmp_dst, data_size);
+ }
+ }
+
+ MEM_freeN(tmp_dst);
}
/* Normals are special, we need to take care of source & destination spaces... */
-void customdata_data_transfer_interp_normal_normals(
- const CustomDataTransferLayerMap *laymap, void *data_dst,
- const void **sources, const float *weights, const int count,
- const float mix_factor)
-{
- const int data_type = laymap->data_type;
- const int mix_mode = laymap->mix_mode;
-
- SpaceTransform *space_transform = laymap->interp_data;
-
- const LayerTypeInfo *type_info = layerType_getInfo(data_type);
- cd_interp interp_cd = type_info->interp;
-
- float tmp_dst[3];
-
- BLI_assert(data_type == CD_NORMAL);
-
- if (!sources) {
- /* Not supported here, abort. */
- return;
- }
-
- interp_cd(sources, weights, NULL, count, tmp_dst);
- if (space_transform) {
- /* tmp_dst is in source space so far, bring it back in destination space. */
- BLI_space_transform_invert_normal(space_transform, tmp_dst);
- }
-
- CustomData_data_mix_value(data_type, tmp_dst, data_dst, mix_mode, mix_factor);
-}
-
-void CustomData_data_transfer(const MeshPairRemap *me_remap, const CustomDataTransferLayerMap *laymap)
-{
- MeshPairRemapItem *mapit = me_remap->items;
- const int totelem = me_remap->items_num;
- int i;
-
- const int data_type = laymap->data_type;
- const void *data_src = laymap->data_src;
- void *data_dst = laymap->data_dst;
-
- size_t data_step;
- size_t data_size;
- size_t data_offset;
-
- cd_datatransfer_interp interp = NULL;
-
- size_t tmp_buff_size = 32;
- const void **tmp_data_src = NULL;
-
- /* Note: NULL data_src may happen and be valid (see vgroups...). */
- if (!data_dst) {
- return;
- }
-
- if (data_src) {
- tmp_data_src = MEM_malloc_arrayN(tmp_buff_size, sizeof(*tmp_data_src), __func__);
- }
-
- if (data_type & CD_FAKE) {
- data_step = laymap->elem_size;
- data_size = laymap->data_size;
- data_offset = laymap->data_offset;
- }
- else {
- const LayerTypeInfo *type_info = layerType_getInfo(data_type);
-
- /* Note: we can use 'fake' CDLayers, like e.g. for crease, bweight, etc. :/ */
- data_size = (size_t)type_info->size;
- data_step = laymap->elem_size ? laymap->elem_size : data_size;
- data_offset = laymap->data_offset;
- }
-
- interp = laymap->interp ? laymap->interp : customdata_data_transfer_interp_generic;
-
- for (i = 0; i < totelem; i++, data_dst = POINTER_OFFSET(data_dst, data_step), mapit++) {
- const int sources_num = mapit->sources_num;
- const float mix_factor = laymap->mix_weights ? laymap->mix_weights[i] : laymap->mix_factor;
- int j;
-
- if (!sources_num) {
- /* No sources for this element, skip it. */
- continue;
- }
-
- if (tmp_data_src) {
- if (UNLIKELY(sources_num > tmp_buff_size)) {
- tmp_buff_size = (size_t)sources_num;
- tmp_data_src = MEM_reallocN((void *)tmp_data_src, sizeof(*tmp_data_src) * tmp_buff_size);
- }
-
- for (j = 0; j < sources_num; j++) {
- const size_t src_idx = (size_t)mapit->indices_src[j];
- tmp_data_src[j] = POINTER_OFFSET(data_src, (data_step * src_idx) + data_offset);
- }
- }
-
- interp(laymap, POINTER_OFFSET(data_dst, data_offset), tmp_data_src, mapit->weights_src, sources_num, mix_factor);
- }
+void customdata_data_transfer_interp_normal_normals(const CustomDataTransferLayerMap *laymap,
+ void *data_dst,
+ const void **sources,
+ const float *weights,
+ const int count,
+ const float mix_factor)
+{
+ const int data_type = laymap->data_type;
+ const int mix_mode = laymap->mix_mode;
+
+ SpaceTransform *space_transform = laymap->interp_data;
+
+ const LayerTypeInfo *type_info = layerType_getInfo(data_type);
+ cd_interp interp_cd = type_info->interp;
+
+ float tmp_dst[3];
+
+ BLI_assert(data_type == CD_NORMAL);
+
+ if (!sources) {
+ /* Not supported here, abort. */
+ return;
+ }
+
+ interp_cd(sources, weights, NULL, count, tmp_dst);
+ if (space_transform) {
+ /* tmp_dst is in source space so far, bring it back in destination space. */
+ BLI_space_transform_invert_normal(space_transform, tmp_dst);
+ }
+
+ CustomData_data_mix_value(data_type, tmp_dst, data_dst, mix_mode, mix_factor);
+}
+
+void CustomData_data_transfer(const MeshPairRemap *me_remap,
+ const CustomDataTransferLayerMap *laymap)
+{
+ MeshPairRemapItem *mapit = me_remap->items;
+ const int totelem = me_remap->items_num;
+ int i;
+
+ const int data_type = laymap->data_type;
+ const void *data_src = laymap->data_src;
+ void *data_dst = laymap->data_dst;
+
+ size_t data_step;
+ size_t data_size;
+ size_t data_offset;
+
+ cd_datatransfer_interp interp = NULL;
+
+ size_t tmp_buff_size = 32;
+ const void **tmp_data_src = NULL;
+
+ /* Note: NULL data_src may happen and be valid (see vgroups...). */
+ if (!data_dst) {
+ return;
+ }
+
+ if (data_src) {
+ tmp_data_src = MEM_malloc_arrayN(tmp_buff_size, sizeof(*tmp_data_src), __func__);
+ }
+
+ if (data_type & CD_FAKE) {
+ data_step = laymap->elem_size;
+ data_size = laymap->data_size;
+ data_offset = laymap->data_offset;
+ }
+ else {
+ const LayerTypeInfo *type_info = layerType_getInfo(data_type);
+
+ /* Note: we can use 'fake' CDLayers, like e.g. for crease, bweight, etc. :/ */
+ data_size = (size_t)type_info->size;
+ data_step = laymap->elem_size ? laymap->elem_size : data_size;
+ data_offset = laymap->data_offset;
+ }
+
+ interp = laymap->interp ? laymap->interp : customdata_data_transfer_interp_generic;
+
+ for (i = 0; i < totelem; i++, data_dst = POINTER_OFFSET(data_dst, data_step), mapit++) {
+ const int sources_num = mapit->sources_num;
+ const float mix_factor = laymap->mix_weights ? laymap->mix_weights[i] : laymap->mix_factor;
+ int j;
+
+ if (!sources_num) {
+ /* No sources for this element, skip it. */
+ continue;
+ }
+
+ if (tmp_data_src) {
+ if (UNLIKELY(sources_num > tmp_buff_size)) {
+ tmp_buff_size = (size_t)sources_num;
+ tmp_data_src = MEM_reallocN((void *)tmp_data_src, sizeof(*tmp_data_src) * tmp_buff_size);
+ }
+
+ for (j = 0; j < sources_num; j++) {
+ const size_t src_idx = (size_t)mapit->indices_src[j];
+ tmp_data_src[j] = POINTER_OFFSET(data_src, (data_step * src_idx) + data_offset);
+ }
+ }
+
+ interp(laymap,
+ POINTER_OFFSET(data_dst, data_offset),
+ tmp_data_src,
+ mapit->weights_src,
+ sources_num,
+ mix_factor);
+ }
- MEM_SAFE_FREE(tmp_data_src);
+ MEM_SAFE_FREE(tmp_data_src);
}
diff --git a/source/blender/blenkernel/intern/customdata_file.c b/source/blender/blenkernel/intern/customdata_file.c
index 2facb0f1ad8..6e7d4d856d7 100644
--- a/source/blender/blenkernel/intern/customdata_file.c
+++ b/source/blender/blenkernel/intern/customdata_file.c
@@ -18,7 +18,6 @@
* \ingroup bke
*/
-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -33,405 +32,407 @@
#include "BKE_customdata_file.h"
#include "BKE_global.h"
-
/************************* File Format Definitions ***************************/
-#define CDF_ENDIAN_LITTLE 0
-#define CDF_ENDIAN_BIG 1
+#define CDF_ENDIAN_LITTLE 0
+#define CDF_ENDIAN_BIG 1
-#define CDF_DATA_FLOAT 0
+#define CDF_DATA_FLOAT 0
typedef struct CDataFileHeader {
- char ID[4]; /* "BCDF" */
- char endian; /* little, big */
- char version; /* non-compatible versions */
- char subversion; /* compatible sub versions */
- char pad; /* padding */
-
- int structbytes; /* size of this struct in bytes */
- int type; /* image, mesh */
- int totlayer; /* number of layers in the file */
+ char ID[4]; /* "BCDF" */
+ char endian; /* little, big */
+ char version; /* non-compatible versions */
+ char subversion; /* compatible sub versions */
+ char pad; /* padding */
+
+ int structbytes; /* size of this struct in bytes */
+ int type; /* image, mesh */
+ int totlayer; /* number of layers in the file */
} CDataFileHeader;
typedef struct CDataFileImageHeader {
- int structbytes; /* size of this struct in bytes */
- int width; /* image width */
- int height; /* image height */
- int tile_size; /* tile size (required power of 2) */
+ int structbytes; /* size of this struct in bytes */
+ int width; /* image width */
+ int height; /* image height */
+ int tile_size; /* tile size (required power of 2) */
} CDataFileImageHeader;
typedef struct CDataFileMeshHeader {
- int structbytes; /* size of this struct in bytes */
+ int structbytes; /* size of this struct in bytes */
} CDataFileMeshHeader;
struct CDataFileLayer {
- int structbytes; /* size of this struct in bytes */
- int datatype; /* only float for now */
- uint64_t datasize; /* size of data in layer */
- int type; /* layer type */
- char name[CDF_LAYER_NAME_MAX]; /* layer name */
+ int structbytes; /* size of this struct in bytes */
+ int datatype; /* only float for now */
+ uint64_t datasize; /* size of data in layer */
+ int type; /* layer type */
+ char name[CDF_LAYER_NAME_MAX]; /* layer name */
};
/**************************** Other Definitions ******************************/
-#define CDF_VERSION 0
-#define CDF_SUBVERSION 0
-#define CDF_TILE_SIZE 64
+#define CDF_VERSION 0
+#define CDF_SUBVERSION 0
+#define CDF_TILE_SIZE 64
struct CDataFile {
- int type;
+ int type;
- CDataFileHeader header;
- union {
- CDataFileImageHeader image;
- CDataFileMeshHeader mesh;
- } btype;
+ CDataFileHeader header;
+ union {
+ CDataFileImageHeader image;
+ CDataFileMeshHeader mesh;
+ } btype;
- CDataFileLayer *layer;
- int totlayer;
+ CDataFileLayer *layer;
+ int totlayer;
- FILE *readf;
- FILE *writef;
- int switchendian;
- size_t dataoffset;
+ FILE *readf;
+ FILE *writef;
+ int switchendian;
+ size_t dataoffset;
};
/********************************* Create/Free *******************************/
static int cdf_endian(void)
{
- if (ENDIAN_ORDER == L_ENDIAN)
- return CDF_ENDIAN_LITTLE;
- else
- return CDF_ENDIAN_BIG;
+ if (ENDIAN_ORDER == L_ENDIAN)
+ return CDF_ENDIAN_LITTLE;
+ else
+ return CDF_ENDIAN_BIG;
}
CDataFile *cdf_create(int type)
{
- CDataFile *cdf = MEM_callocN(sizeof(CDataFile), "CDataFile");
+ CDataFile *cdf = MEM_callocN(sizeof(CDataFile), "CDataFile");
- cdf->type = type;
+ cdf->type = type;
- return cdf;
+ return cdf;
}
void cdf_free(CDataFile *cdf)
{
- cdf_read_close(cdf);
- cdf_write_close(cdf);
+ cdf_read_close(cdf);
+ cdf_write_close(cdf);
- if (cdf->layer)
- MEM_freeN(cdf->layer);
+ if (cdf->layer)
+ MEM_freeN(cdf->layer);
- MEM_freeN(cdf);
+ MEM_freeN(cdf);
}
/********************************* Read/Write ********************************/
static int cdf_read_header(CDataFile *cdf)
{
- CDataFileHeader *header;
- CDataFileImageHeader *image;
- CDataFileMeshHeader *mesh;
- CDataFileLayer *layer;
- FILE *f = cdf->readf;
- size_t offset = 0;
- int a;
+ CDataFileHeader *header;
+ CDataFileImageHeader *image;
+ CDataFileMeshHeader *mesh;
+ CDataFileLayer *layer;
+ FILE *f = cdf->readf;
+ size_t offset = 0;
+ int a;
- header = &cdf->header;
+ header = &cdf->header;
- if (!fread(header, sizeof(CDataFileHeader), 1, cdf->readf))
- return 0;
+ if (!fread(header, sizeof(CDataFileHeader), 1, cdf->readf))
+ return 0;
- if (memcmp(header->ID, "BCDF", sizeof(header->ID)) != 0)
- return 0;
- if (header->version > CDF_VERSION)
- return 0;
+ if (memcmp(header->ID, "BCDF", sizeof(header->ID)) != 0)
+ return 0;
+ if (header->version > CDF_VERSION)
+ return 0;
- cdf->switchendian = header->endian != cdf_endian();
- header->endian = cdf_endian();
+ cdf->switchendian = header->endian != cdf_endian();
+ header->endian = cdf_endian();
- if (cdf->switchendian) {
- BLI_endian_switch_int32(&header->type);
- BLI_endian_switch_int32(&header->totlayer);
- BLI_endian_switch_int32(&header->structbytes);
- }
+ if (cdf->switchendian) {
+ BLI_endian_switch_int32(&header->type);
+ BLI_endian_switch_int32(&header->totlayer);
+ BLI_endian_switch_int32(&header->structbytes);
+ }
- if (!ELEM(header->type, CDF_TYPE_IMAGE, CDF_TYPE_MESH))
- return 0;
+ if (!ELEM(header->type, CDF_TYPE_IMAGE, CDF_TYPE_MESH))
+ return 0;
- offset += header->structbytes;
- header->structbytes = sizeof(CDataFileHeader);
+ offset += header->structbytes;
+ header->structbytes = sizeof(CDataFileHeader);
- if (fseek(f, offset, SEEK_SET) != 0)
- return 0;
+ if (fseek(f, offset, SEEK_SET) != 0)
+ return 0;
- if (header->type == CDF_TYPE_IMAGE) {
- image = &cdf->btype.image;
- if (!fread(image, sizeof(CDataFileImageHeader), 1, f))
- return 0;
+ if (header->type == CDF_TYPE_IMAGE) {
+ image = &cdf->btype.image;
+ if (!fread(image, sizeof(CDataFileImageHeader), 1, f))
+ return 0;
- if (cdf->switchendian) {
- BLI_endian_switch_int32(&image->width);
- BLI_endian_switch_int32(&image->height);
- BLI_endian_switch_int32(&image->tile_size);
- BLI_endian_switch_int32(&image->structbytes);
- }
+ if (cdf->switchendian) {
+ BLI_endian_switch_int32(&image->width);
+ BLI_endian_switch_int32(&image->height);
+ BLI_endian_switch_int32(&image->tile_size);
+ BLI_endian_switch_int32(&image->structbytes);
+ }
- offset += image->structbytes;
- image->structbytes = sizeof(CDataFileImageHeader);
- }
- else if (header->type == CDF_TYPE_MESH) {
- mesh = &cdf->btype.mesh;
- if (!fread(mesh, sizeof(CDataFileMeshHeader), 1, f))
- return 0;
+ offset += image->structbytes;
+ image->structbytes = sizeof(CDataFileImageHeader);
+ }
+ else if (header->type == CDF_TYPE_MESH) {
+ mesh = &cdf->btype.mesh;
+ if (!fread(mesh, sizeof(CDataFileMeshHeader), 1, f))
+ return 0;
- if (cdf->switchendian)
- BLI_endian_switch_int32(&mesh->structbytes);
+ if (cdf->switchendian)
+ BLI_endian_switch_int32(&mesh->structbytes);
- offset += mesh->structbytes;
- mesh->structbytes = sizeof(CDataFileMeshHeader);
- }
+ offset += mesh->structbytes;
+ mesh->structbytes = sizeof(CDataFileMeshHeader);
+ }
- if (fseek(f, offset, SEEK_SET) != 0)
- return 0;
+ if (fseek(f, offset, SEEK_SET) != 0)
+ return 0;
- cdf->layer = MEM_calloc_arrayN(header->totlayer, sizeof(CDataFileLayer), "CDataFileLayer");
- cdf->totlayer = header->totlayer;
+ cdf->layer = MEM_calloc_arrayN(header->totlayer, sizeof(CDataFileLayer), "CDataFileLayer");
+ cdf->totlayer = header->totlayer;
- if (!cdf->layer) {
- return 0;
- }
+ if (!cdf->layer) {
+ return 0;
+ }
- for (a = 0; a < header->totlayer; a++) {
- layer = &cdf->layer[a];
+ for (a = 0; a < header->totlayer; a++) {
+ layer = &cdf->layer[a];
- if (!fread(layer, sizeof(CDataFileLayer), 1, f))
- return 0;
+ if (!fread(layer, sizeof(CDataFileLayer), 1, f))
+ return 0;
- if (cdf->switchendian) {
- BLI_endian_switch_int32(&layer->type);
- BLI_endian_switch_int32(&layer->datatype);
- BLI_endian_switch_uint64(&layer->datasize);
- BLI_endian_switch_int32(&layer->structbytes);
- }
+ if (cdf->switchendian) {
+ BLI_endian_switch_int32(&layer->type);
+ BLI_endian_switch_int32(&layer->datatype);
+ BLI_endian_switch_uint64(&layer->datasize);
+ BLI_endian_switch_int32(&layer->structbytes);
+ }
- if (layer->datatype != CDF_DATA_FLOAT)
- return 0;
+ if (layer->datatype != CDF_DATA_FLOAT)
+ return 0;
- offset += layer->structbytes;
- layer->structbytes = sizeof(CDataFileLayer);
+ offset += layer->structbytes;
+ layer->structbytes = sizeof(CDataFileLayer);
- if (fseek(f, offset, SEEK_SET) != 0)
- return 0;
- }
+ if (fseek(f, offset, SEEK_SET) != 0)
+ return 0;
+ }
- cdf->dataoffset = offset;
+ cdf->dataoffset = offset;
- return 1;
+ return 1;
}
static int cdf_write_header(CDataFile *cdf)
{
- CDataFileHeader *header;
- CDataFileImageHeader *image;
- CDataFileMeshHeader *mesh;
- CDataFileLayer *layer;
- FILE *f = cdf->writef;
- int a;
-
- header = &cdf->header;
-
- if (!fwrite(header, sizeof(CDataFileHeader), 1, f))
- return 0;
-
- if (header->type == CDF_TYPE_IMAGE) {
- image = &cdf->btype.image;
- if (!fwrite(image, sizeof(CDataFileImageHeader), 1, f))
- return 0;
- }
- else if (header->type == CDF_TYPE_MESH) {
- mesh = &cdf->btype.mesh;
- if (!fwrite(mesh, sizeof(CDataFileMeshHeader), 1, f))
- return 0;
- }
-
- for (a = 0; a < header->totlayer; a++) {
- layer = &cdf->layer[a];
-
- if (!fwrite(layer, sizeof(CDataFileLayer), 1, f))
- return 0;
- }
-
- return 1;
+ CDataFileHeader *header;
+ CDataFileImageHeader *image;
+ CDataFileMeshHeader *mesh;
+ CDataFileLayer *layer;
+ FILE *f = cdf->writef;
+ int a;
+
+ header = &cdf->header;
+
+ if (!fwrite(header, sizeof(CDataFileHeader), 1, f))
+ return 0;
+
+ if (header->type == CDF_TYPE_IMAGE) {
+ image = &cdf->btype.image;
+ if (!fwrite(image, sizeof(CDataFileImageHeader), 1, f))
+ return 0;
+ }
+ else if (header->type == CDF_TYPE_MESH) {
+ mesh = &cdf->btype.mesh;
+ if (!fwrite(mesh, sizeof(CDataFileMeshHeader), 1, f))
+ return 0;
+ }
+
+ for (a = 0; a < header->totlayer; a++) {
+ layer = &cdf->layer[a];
+
+ if (!fwrite(layer, sizeof(CDataFileLayer), 1, f))
+ return 0;
+ }
+
+ return 1;
}
bool cdf_read_open(CDataFile *cdf, const char *filename)
{
- FILE *f;
+ FILE *f;
- f = BLI_fopen(filename, "rb");
- if (!f)
- return 0;
+ f = BLI_fopen(filename, "rb");
+ if (!f)
+ return 0;
- cdf->readf = f;
+ cdf->readf = f;
- if (!cdf_read_header(cdf)) {
- cdf_read_close(cdf);
- return 0;
- }
+ if (!cdf_read_header(cdf)) {
+ cdf_read_close(cdf);
+ return 0;
+ }
- if (cdf->header.type != cdf->type) {
- cdf_read_close(cdf);
- return 0;
- }
+ if (cdf->header.type != cdf->type) {
+ cdf_read_close(cdf);
+ return 0;
+ }
- return 1;
+ return 1;
}
bool cdf_read_layer(CDataFile *cdf, CDataFileLayer *blay)
{
- size_t offset;
- int a;
-
- /* seek to right location in file */
- offset = cdf->dataoffset;
- for (a = 0; a < cdf->totlayer; a++) {
- if (&cdf->layer[a] == blay)
- break;
- else
- offset += cdf->layer[a].datasize;
- }
-
- return (fseek(cdf->readf, offset, SEEK_SET) == 0);
+ size_t offset;
+ int a;
+
+ /* seek to right location in file */
+ offset = cdf->dataoffset;
+ for (a = 0; a < cdf->totlayer; a++) {
+ if (&cdf->layer[a] == blay)
+ break;
+ else
+ offset += cdf->layer[a].datasize;
+ }
+
+ return (fseek(cdf->readf, offset, SEEK_SET) == 0);
}
bool cdf_read_data(CDataFile *cdf, unsigned int size, void *data)
{
- /* read data */
- if (!fread(data, size, 1, cdf->readf))
- return 0;
+ /* read data */
+ if (!fread(data, size, 1, cdf->readf))
+ return 0;
- /* switch endian if necessary */
- if (cdf->switchendian) {
- BLI_endian_switch_float_array(data, size / sizeof(float));
- }
+ /* switch endian if necessary */
+ if (cdf->switchendian) {
+ BLI_endian_switch_float_array(data, size / sizeof(float));
+ }
- return 1;
+ return 1;
}
void cdf_read_close(CDataFile *cdf)
{
- if (cdf->readf) {
- fclose(cdf->readf);
- cdf->readf = NULL;
- }
+ if (cdf->readf) {
+ fclose(cdf->readf);
+ cdf->readf = NULL;
+ }
}
bool cdf_write_open(CDataFile *cdf, const char *filename)
{
- CDataFileHeader *header;
- CDataFileImageHeader *image;
- CDataFileMeshHeader *mesh;
- FILE *f;
-
- f = BLI_fopen(filename, "wb");
- if (!f)
- return 0;
-
- cdf->writef = f;
-
- /* fill header */
- header = &cdf->header;
- /* strcpy(, "BCDF"); // terminator out of range */
- header->ID[0] = 'B'; header->ID[1] = 'C'; header->ID[2] = 'D'; header->ID[3] = 'F';
- header->endian = cdf_endian();
- header->version = CDF_VERSION;
- header->subversion = CDF_SUBVERSION;
-
- header->structbytes = sizeof(CDataFileHeader);
- header->type = cdf->type;
- header->totlayer = cdf->totlayer;
-
- if (cdf->type == CDF_TYPE_IMAGE) {
- /* fill image header */
- image = &cdf->btype.image;
- image->structbytes = sizeof(CDataFileImageHeader);
- image->tile_size = CDF_TILE_SIZE;
- }
- else if (cdf->type == CDF_TYPE_MESH) {
- /* fill mesh header */
- mesh = &cdf->btype.mesh;
- mesh->structbytes = sizeof(CDataFileMeshHeader);
- }
-
- cdf_write_header(cdf);
-
- return 1;
+ CDataFileHeader *header;
+ CDataFileImageHeader *image;
+ CDataFileMeshHeader *mesh;
+ FILE *f;
+
+ f = BLI_fopen(filename, "wb");
+ if (!f)
+ return 0;
+
+ cdf->writef = f;
+
+ /* fill header */
+ header = &cdf->header;
+ /* strcpy(, "BCDF"); // terminator out of range */
+ header->ID[0] = 'B';
+ header->ID[1] = 'C';
+ header->ID[2] = 'D';
+ header->ID[3] = 'F';
+ header->endian = cdf_endian();
+ header->version = CDF_VERSION;
+ header->subversion = CDF_SUBVERSION;
+
+ header->structbytes = sizeof(CDataFileHeader);
+ header->type = cdf->type;
+ header->totlayer = cdf->totlayer;
+
+ if (cdf->type == CDF_TYPE_IMAGE) {
+ /* fill image header */
+ image = &cdf->btype.image;
+ image->structbytes = sizeof(CDataFileImageHeader);
+ image->tile_size = CDF_TILE_SIZE;
+ }
+ else if (cdf->type == CDF_TYPE_MESH) {
+ /* fill mesh header */
+ mesh = &cdf->btype.mesh;
+ mesh->structbytes = sizeof(CDataFileMeshHeader);
+ }
+
+ cdf_write_header(cdf);
+
+ return 1;
}
bool cdf_write_layer(CDataFile *UNUSED(cdf), CDataFileLayer *UNUSED(blay))
{
- return 1;
+ return 1;
}
bool cdf_write_data(CDataFile *cdf, unsigned int size, void *data)
{
- /* write data */
- if (!fwrite(data, size, 1, cdf->writef))
- return 0;
+ /* write data */
+ if (!fwrite(data, size, 1, cdf->writef))
+ return 0;
- return 1;
+ return 1;
}
void cdf_write_close(CDataFile *cdf)
{
- if (cdf->writef) {
- fclose(cdf->writef);
- cdf->writef = NULL;
- }
+ if (cdf->writef) {
+ fclose(cdf->writef);
+ cdf->writef = NULL;
+ }
}
void cdf_remove(const char *filename)
{
- BLI_delete(filename, false, false);
+ BLI_delete(filename, false, false);
}
/********************************** Layers ***********************************/
CDataFileLayer *cdf_layer_find(CDataFile *cdf, int type, const char *name)
{
- CDataFileLayer *layer;
- int a;
+ CDataFileLayer *layer;
+ int a;
- for (a = 0; a < cdf->totlayer; a++) {
- layer = &cdf->layer[a];
+ for (a = 0; a < cdf->totlayer; a++) {
+ layer = &cdf->layer[a];
- if (layer->type == type && STREQ(layer->name, name))
- return layer;
- }
+ if (layer->type == type && STREQ(layer->name, name))
+ return layer;
+ }
- return NULL;
+ return NULL;
}
CDataFileLayer *cdf_layer_add(CDataFile *cdf, int type, const char *name, size_t datasize)
{
- CDataFileLayer *newlayer, *layer;
+ CDataFileLayer *newlayer, *layer;
- /* expand array */
- newlayer = MEM_calloc_arrayN((cdf->totlayer + 1), sizeof(CDataFileLayer), "CDataFileLayer");
- memcpy(newlayer, cdf->layer, sizeof(CDataFileLayer) * cdf->totlayer);
- cdf->layer = newlayer;
+ /* expand array */
+ newlayer = MEM_calloc_arrayN((cdf->totlayer + 1), sizeof(CDataFileLayer), "CDataFileLayer");
+ memcpy(newlayer, cdf->layer, sizeof(CDataFileLayer) * cdf->totlayer);
+ cdf->layer = newlayer;
- cdf->totlayer++;
+ cdf->totlayer++;
- /* fill in new layer */
- layer = &cdf->layer[cdf->totlayer - 1];
- layer->structbytes = sizeof(CDataFileLayer);
- layer->datatype = CDF_DATA_FLOAT;
- layer->datasize = datasize;
- layer->type = type;
- BLI_strncpy(layer->name, name, CDF_LAYER_NAME_MAX);
+ /* fill in new layer */
+ layer = &cdf->layer[cdf->totlayer - 1];
+ layer->structbytes = sizeof(CDataFileLayer);
+ layer->datatype = CDF_DATA_FLOAT;
+ layer->datasize = datasize;
+ layer->type = type;
+ BLI_strncpy(layer->name, name, CDF_LAYER_NAME_MAX);
- return layer;
+ return layer;
}
diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c
index 779128bfb3f..41e8cfe188d 100644
--- a/source/blender/blenkernel/intern/data_transfer.c
+++ b/source/blender/blenkernel/intern/data_transfer.c
@@ -51,428 +51,490 @@
static CLG_LogRef LOG = {"bke.data_transfer"};
-void BKE_object_data_transfer_dttypes_to_cdmask(const int dtdata_types, CustomData_MeshMasks *r_data_masks)
+void BKE_object_data_transfer_dttypes_to_cdmask(const int dtdata_types,
+ CustomData_MeshMasks *r_data_masks)
{
- for (int i = 0; i < DT_TYPE_MAX; i++) {
- const int dtdata_type = 1 << i;
- int cddata_type;
-
- if (!(dtdata_types & dtdata_type)) {
- continue;
- }
-
- cddata_type = BKE_object_data_transfer_dttype_to_cdtype(dtdata_type);
- if (!(cddata_type & CD_FAKE)) {
- if (DT_DATATYPE_IS_VERT(dtdata_type)) {
- r_data_masks->vmask |= 1LL << cddata_type;
- }
- else if (DT_DATATYPE_IS_EDGE(dtdata_type)) {
- r_data_masks->emask |= 1LL << cddata_type;
- }
- else if (DT_DATATYPE_IS_LOOP(dtdata_type)) {
- r_data_masks->lmask |= 1LL << cddata_type;
- }
- else if (DT_DATATYPE_IS_POLY(dtdata_type)) {
- r_data_masks->pmask |= 1LL << cddata_type;
- }
- }
- else if (cddata_type == CD_FAKE_MDEFORMVERT) {
- r_data_masks->vmask |= CD_MASK_MDEFORMVERT; /* Exception for vgroups :/ */
- }
- else if (cddata_type == CD_FAKE_UV) {
- r_data_masks->lmask |= CD_MASK_MLOOPUV;
- }
- else if (cddata_type == CD_FAKE_LNOR) {
- r_data_masks->vmask |= CD_MASK_NORMAL;
- r_data_masks->lmask |= CD_MASK_NORMAL | CD_MASK_CUSTOMLOOPNORMAL;
- }
- }
+ for (int i = 0; i < DT_TYPE_MAX; i++) {
+ const int dtdata_type = 1 << i;
+ int cddata_type;
+
+ if (!(dtdata_types & dtdata_type)) {
+ continue;
+ }
+
+ cddata_type = BKE_object_data_transfer_dttype_to_cdtype(dtdata_type);
+ if (!(cddata_type & CD_FAKE)) {
+ if (DT_DATATYPE_IS_VERT(dtdata_type)) {
+ r_data_masks->vmask |= 1LL << cddata_type;
+ }
+ else if (DT_DATATYPE_IS_EDGE(dtdata_type)) {
+ r_data_masks->emask |= 1LL << cddata_type;
+ }
+ else if (DT_DATATYPE_IS_LOOP(dtdata_type)) {
+ r_data_masks->lmask |= 1LL << cddata_type;
+ }
+ else if (DT_DATATYPE_IS_POLY(dtdata_type)) {
+ r_data_masks->pmask |= 1LL << cddata_type;
+ }
+ }
+ else if (cddata_type == CD_FAKE_MDEFORMVERT) {
+ r_data_masks->vmask |= CD_MASK_MDEFORMVERT; /* Exception for vgroups :/ */
+ }
+ else if (cddata_type == CD_FAKE_UV) {
+ r_data_masks->lmask |= CD_MASK_MLOOPUV;
+ }
+ else if (cddata_type == CD_FAKE_LNOR) {
+ r_data_masks->vmask |= CD_MASK_NORMAL;
+ r_data_masks->lmask |= CD_MASK_NORMAL | CD_MASK_CUSTOMLOOPNORMAL;
+ }
+ }
}
/* Check what can do each layer type (if it is actually handled by transferdata, if it supports advanced mixing... */
-bool BKE_object_data_transfer_get_dttypes_capacity(
- const int dtdata_types, bool *r_advanced_mixing, bool *r_threshold)
+bool BKE_object_data_transfer_get_dttypes_capacity(const int dtdata_types,
+ bool *r_advanced_mixing,
+ bool *r_threshold)
{
- int i;
- bool ret = false;
-
- *r_advanced_mixing = false;
- *r_threshold = false;
-
- for (i = 0; (i < DT_TYPE_MAX) && !(ret && *r_advanced_mixing && *r_threshold); i++) {
- const int dtdata_type = 1 << i;
-
- if (!(dtdata_types & dtdata_type)) {
- continue;
- }
-
- switch (dtdata_type) {
- /* Vertex data */
- case DT_TYPE_MDEFORMVERT:
- *r_advanced_mixing = true;
- *r_threshold = true;
- ret = true;
- break;
- case DT_TYPE_SKIN:
- *r_threshold = true;
- ret = true;
- break;
- case DT_TYPE_BWEIGHT_VERT:
- ret = true;
- break;
- /* Edge data */
- case DT_TYPE_SHARP_EDGE:
- *r_threshold = true;
- ret = true;
- break;
- case DT_TYPE_SEAM:
- *r_threshold = true;
- ret = true;
- break;
- case DT_TYPE_CREASE:
- ret = true;
- break;
- case DT_TYPE_BWEIGHT_EDGE:
- ret = true;
- break;
- case DT_TYPE_FREESTYLE_EDGE:
- *r_threshold = true;
- ret = true;
- break;
- /* Loop/Poly data */
- case DT_TYPE_UV:
- ret = true;
- break;
- case DT_TYPE_VCOL:
- *r_advanced_mixing = true;
- *r_threshold = true;
- ret = true;
- break;
- case DT_TYPE_LNOR:
- *r_advanced_mixing = true;
- ret = true;
- break;
- case DT_TYPE_SHARP_FACE:
- *r_threshold = true;
- ret = true;
- break;
- case DT_TYPE_FREESTYLE_FACE:
- *r_threshold = true;
- ret = true;
- break;
- }
- }
-
- return ret;
+ int i;
+ bool ret = false;
+
+ *r_advanced_mixing = false;
+ *r_threshold = false;
+
+ for (i = 0; (i < DT_TYPE_MAX) && !(ret && *r_advanced_mixing && *r_threshold); i++) {
+ const int dtdata_type = 1 << i;
+
+ if (!(dtdata_types & dtdata_type)) {
+ continue;
+ }
+
+ switch (dtdata_type) {
+ /* Vertex data */
+ case DT_TYPE_MDEFORMVERT:
+ *r_advanced_mixing = true;
+ *r_threshold = true;
+ ret = true;
+ break;
+ case DT_TYPE_SKIN:
+ *r_threshold = true;
+ ret = true;
+ break;
+ case DT_TYPE_BWEIGHT_VERT:
+ ret = true;
+ break;
+ /* Edge data */
+ case DT_TYPE_SHARP_EDGE:
+ *r_threshold = true;
+ ret = true;
+ break;
+ case DT_TYPE_SEAM:
+ *r_threshold = true;
+ ret = true;
+ break;
+ case DT_TYPE_CREASE:
+ ret = true;
+ break;
+ case DT_TYPE_BWEIGHT_EDGE:
+ ret = true;
+ break;
+ case DT_TYPE_FREESTYLE_EDGE:
+ *r_threshold = true;
+ ret = true;
+ break;
+ /* Loop/Poly data */
+ case DT_TYPE_UV:
+ ret = true;
+ break;
+ case DT_TYPE_VCOL:
+ *r_advanced_mixing = true;
+ *r_threshold = true;
+ ret = true;
+ break;
+ case DT_TYPE_LNOR:
+ *r_advanced_mixing = true;
+ ret = true;
+ break;
+ case DT_TYPE_SHARP_FACE:
+ *r_threshold = true;
+ ret = true;
+ break;
+ case DT_TYPE_FREESTYLE_FACE:
+ *r_threshold = true;
+ ret = true;
+ break;
+ }
+ }
+
+ return ret;
}
int BKE_object_data_transfer_get_dttypes_item_types(const int dtdata_types)
{
- int i, ret = 0;
-
- for (i = 0; (i < DT_TYPE_MAX) && (ret ^ (ME_VERT | ME_EDGE | ME_LOOP | ME_POLY)); i++) {
- const int dtdata_type = 1 << i;
-
- if (!(dtdata_types & dtdata_type)) {
- continue;
- }
-
- if (DT_DATATYPE_IS_VERT(dtdata_type)) {
- ret |= ME_VERT;
- }
- if (DT_DATATYPE_IS_EDGE(dtdata_type)) {
- ret |= ME_EDGE;
- }
- if (DT_DATATYPE_IS_LOOP(dtdata_type)) {
- ret |= ME_LOOP;
- }
- if (DT_DATATYPE_IS_POLY(dtdata_type)) {
- ret |= ME_POLY;
- }
- }
-
- return ret;
+ int i, ret = 0;
+
+ for (i = 0; (i < DT_TYPE_MAX) && (ret ^ (ME_VERT | ME_EDGE | ME_LOOP | ME_POLY)); i++) {
+ const int dtdata_type = 1 << i;
+
+ if (!(dtdata_types & dtdata_type)) {
+ continue;
+ }
+
+ if (DT_DATATYPE_IS_VERT(dtdata_type)) {
+ ret |= ME_VERT;
+ }
+ if (DT_DATATYPE_IS_EDGE(dtdata_type)) {
+ ret |= ME_EDGE;
+ }
+ if (DT_DATATYPE_IS_LOOP(dtdata_type)) {
+ ret |= ME_LOOP;
+ }
+ if (DT_DATATYPE_IS_POLY(dtdata_type)) {
+ ret |= ME_POLY;
+ }
+ }
+
+ return ret;
}
int BKE_object_data_transfer_dttype_to_cdtype(const int dtdata_type)
{
- switch (dtdata_type) {
- case DT_TYPE_MDEFORMVERT:
- return CD_FAKE_MDEFORMVERT;
- case DT_TYPE_SHAPEKEY:
- return CD_FAKE_SHAPEKEY;
- case DT_TYPE_SKIN:
- return CD_MVERT_SKIN;
- case DT_TYPE_BWEIGHT_VERT:
- return CD_FAKE_BWEIGHT;
-
- case DT_TYPE_SHARP_EDGE:
- return CD_FAKE_SHARP;
- case DT_TYPE_SEAM:
- return CD_FAKE_SEAM;
- case DT_TYPE_CREASE:
- return CD_FAKE_CREASE;
- case DT_TYPE_BWEIGHT_EDGE:
- return CD_FAKE_BWEIGHT;
- case DT_TYPE_FREESTYLE_EDGE:
- return CD_FREESTYLE_EDGE;
-
- case DT_TYPE_UV:
- return CD_FAKE_UV;
- case DT_TYPE_SHARP_FACE:
- return CD_FAKE_SHARP;
- case DT_TYPE_FREESTYLE_FACE:
- return CD_FREESTYLE_FACE;
-
- case DT_TYPE_VCOL:
- return CD_MLOOPCOL;
- case DT_TYPE_LNOR:
- return CD_FAKE_LNOR;
-
- default:
- BLI_assert(0);
- }
- return 0; /* Should never be reached! */
+ switch (dtdata_type) {
+ case DT_TYPE_MDEFORMVERT:
+ return CD_FAKE_MDEFORMVERT;
+ case DT_TYPE_SHAPEKEY:
+ return CD_FAKE_SHAPEKEY;
+ case DT_TYPE_SKIN:
+ return CD_MVERT_SKIN;
+ case DT_TYPE_BWEIGHT_VERT:
+ return CD_FAKE_BWEIGHT;
+
+ case DT_TYPE_SHARP_EDGE:
+ return CD_FAKE_SHARP;
+ case DT_TYPE_SEAM:
+ return CD_FAKE_SEAM;
+ case DT_TYPE_CREASE:
+ return CD_FAKE_CREASE;
+ case DT_TYPE_BWEIGHT_EDGE:
+ return CD_FAKE_BWEIGHT;
+ case DT_TYPE_FREESTYLE_EDGE:
+ return CD_FREESTYLE_EDGE;
+
+ case DT_TYPE_UV:
+ return CD_FAKE_UV;
+ case DT_TYPE_SHARP_FACE:
+ return CD_FAKE_SHARP;
+ case DT_TYPE_FREESTYLE_FACE:
+ return CD_FREESTYLE_FACE;
+
+ case DT_TYPE_VCOL:
+ return CD_MLOOPCOL;
+ case DT_TYPE_LNOR:
+ return CD_FAKE_LNOR;
+
+ default:
+ BLI_assert(0);
+ }
+ return 0; /* Should never be reached! */
}
int BKE_object_data_transfer_dttype_to_srcdst_index(const int dtdata_type)
{
- switch (dtdata_type) {
- case DT_TYPE_MDEFORMVERT:
- return DT_MULTILAYER_INDEX_MDEFORMVERT;
- case DT_TYPE_SHAPEKEY:
- return DT_MULTILAYER_INDEX_SHAPEKEY;
- case DT_TYPE_UV:
- return DT_MULTILAYER_INDEX_UV;
- case DT_TYPE_VCOL:
- return DT_MULTILAYER_INDEX_VCOL;
- default:
- return DT_MULTILAYER_INDEX_INVALID;
- }
+ switch (dtdata_type) {
+ case DT_TYPE_MDEFORMVERT:
+ return DT_MULTILAYER_INDEX_MDEFORMVERT;
+ case DT_TYPE_SHAPEKEY:
+ return DT_MULTILAYER_INDEX_SHAPEKEY;
+ case DT_TYPE_UV:
+ return DT_MULTILAYER_INDEX_UV;
+ case DT_TYPE_VCOL:
+ return DT_MULTILAYER_INDEX_VCOL;
+ default:
+ return DT_MULTILAYER_INDEX_INVALID;
+ }
}
/* ********** */
/* Generic pre/post processing, only used by custom loop normals currently. */
-static void data_transfer_dtdata_type_preprocess(
- Mesh *me_src, Mesh *me_dst,
- const int dtdata_type, const bool dirty_nors_dst)
+static void data_transfer_dtdata_type_preprocess(Mesh *me_src,
+ Mesh *me_dst,
+ const int dtdata_type,
+ const bool dirty_nors_dst)
{
- if (dtdata_type == DT_TYPE_LNOR) {
- /* Compute custom normals into regular loop normals, which will be used for the transfer. */
- MVert *verts_dst = me_dst->mvert;
- const int num_verts_dst = me_dst->totvert;
- MEdge *edges_dst = me_dst->medge;
- const int num_edges_dst = me_dst->totedge;
- MPoly *polys_dst = me_dst->mpoly;
- const int num_polys_dst = me_dst->totpoly;
- MLoop *loops_dst = me_dst->mloop;
- const int num_loops_dst = me_dst->totloop;
- CustomData *pdata_dst = &me_dst->pdata;
- CustomData *ldata_dst = &me_dst->ldata;
-
- const bool use_split_nors_dst = (me_dst->flag & ME_AUTOSMOOTH) != 0;
- const float split_angle_dst = me_dst->smoothresh;
-
- /* This should be ensured by cddata_masks we pass to code generating/giving us me_src now. */
- BLI_assert(CustomData_get_layer(&me_src->ldata, CD_NORMAL) != NULL);
- BLI_assert(CustomData_get_layer(&me_src->pdata, CD_NORMAL) != NULL);
- (void)me_src;
-
- float (*poly_nors_dst)[3];
- float (*loop_nors_dst)[3];
- short (*custom_nors_dst)[2] = CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL);
-
- /* Cache poly nors into a temp CDLayer. */
- poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL);
- const bool do_poly_nors_dst = (poly_nors_dst == NULL);
- if (do_poly_nors_dst) {
- poly_nors_dst = CustomData_add_layer(pdata_dst, CD_NORMAL, CD_CALLOC, NULL, num_polys_dst);
- CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
- }
- if (dirty_nors_dst || do_poly_nors_dst) {
- BKE_mesh_calc_normals_poly(
- verts_dst, NULL, num_verts_dst, loops_dst, polys_dst,
- num_loops_dst, num_polys_dst, poly_nors_dst, true);
- }
- /* Cache loop nors into a temp CDLayer. */
- loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL);
- const bool do_loop_nors_dst = (loop_nors_dst == NULL);
- if (do_loop_nors_dst) {
- loop_nors_dst = CustomData_add_layer(ldata_dst, CD_NORMAL, CD_CALLOC, NULL, num_loops_dst);
- CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
- }
- if (dirty_nors_dst || do_loop_nors_dst) {
- BKE_mesh_normals_loop_split(
- verts_dst, num_verts_dst, edges_dst, num_edges_dst,
- loops_dst, loop_nors_dst, num_loops_dst,
- polys_dst, (const float (*)[3])poly_nors_dst, num_polys_dst,
- use_split_nors_dst, split_angle_dst, NULL, custom_nors_dst, NULL);
- }
- }
+ if (dtdata_type == DT_TYPE_LNOR) {
+ /* Compute custom normals into regular loop normals, which will be used for the transfer. */
+ MVert *verts_dst = me_dst->mvert;
+ const int num_verts_dst = me_dst->totvert;
+ MEdge *edges_dst = me_dst->medge;
+ const int num_edges_dst = me_dst->totedge;
+ MPoly *polys_dst = me_dst->mpoly;
+ const int num_polys_dst = me_dst->totpoly;
+ MLoop *loops_dst = me_dst->mloop;
+ const int num_loops_dst = me_dst->totloop;
+ CustomData *pdata_dst = &me_dst->pdata;
+ CustomData *ldata_dst = &me_dst->ldata;
+
+ const bool use_split_nors_dst = (me_dst->flag & ME_AUTOSMOOTH) != 0;
+ const float split_angle_dst = me_dst->smoothresh;
+
+ /* This should be ensured by cddata_masks we pass to code generating/giving us me_src now. */
+ BLI_assert(CustomData_get_layer(&me_src->ldata, CD_NORMAL) != NULL);
+ BLI_assert(CustomData_get_layer(&me_src->pdata, CD_NORMAL) != NULL);
+ (void)me_src;
+
+ float(*poly_nors_dst)[3];
+ float(*loop_nors_dst)[3];
+ short(*custom_nors_dst)[2] = CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL);
+
+ /* Cache poly nors into a temp CDLayer. */
+ poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL);
+ const bool do_poly_nors_dst = (poly_nors_dst == NULL);
+ if (do_poly_nors_dst) {
+ poly_nors_dst = CustomData_add_layer(pdata_dst, CD_NORMAL, CD_CALLOC, NULL, num_polys_dst);
+ CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
+ }
+ if (dirty_nors_dst || do_poly_nors_dst) {
+ BKE_mesh_calc_normals_poly(verts_dst,
+ NULL,
+ num_verts_dst,
+ loops_dst,
+ polys_dst,
+ num_loops_dst,
+ num_polys_dst,
+ poly_nors_dst,
+ true);
+ }
+ /* Cache loop nors into a temp CDLayer. */
+ loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL);
+ const bool do_loop_nors_dst = (loop_nors_dst == NULL);
+ if (do_loop_nors_dst) {
+ loop_nors_dst = CustomData_add_layer(ldata_dst, CD_NORMAL, CD_CALLOC, NULL, num_loops_dst);
+ CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
+ }
+ if (dirty_nors_dst || do_loop_nors_dst) {
+ BKE_mesh_normals_loop_split(verts_dst,
+ num_verts_dst,
+ edges_dst,
+ num_edges_dst,
+ loops_dst,
+ loop_nors_dst,
+ num_loops_dst,
+ polys_dst,
+ (const float(*)[3])poly_nors_dst,
+ num_polys_dst,
+ use_split_nors_dst,
+ split_angle_dst,
+ NULL,
+ custom_nors_dst,
+ NULL);
+ }
+ }
}
-static void data_transfer_dtdata_type_postprocess(
- Object *UNUSED(ob_src), Object *UNUSED(ob_dst), Mesh *UNUSED(me_src), Mesh *me_dst,
- const int dtdata_type, const bool changed)
+static void data_transfer_dtdata_type_postprocess(Object *UNUSED(ob_src),
+ Object *UNUSED(ob_dst),
+ Mesh *UNUSED(me_src),
+ Mesh *me_dst,
+ const int dtdata_type,
+ const bool changed)
{
- if (dtdata_type == DT_TYPE_LNOR) {
- /* Bake edited destination loop normals into custom normals again. */
- MVert *verts_dst = me_dst->mvert;
- const int num_verts_dst = me_dst->totvert;
- MEdge *edges_dst = me_dst->medge;
- const int num_edges_dst = me_dst->totedge;
- MPoly *polys_dst = me_dst->mpoly;
- const int num_polys_dst = me_dst->totpoly;
- MLoop *loops_dst = me_dst->mloop;
- const int num_loops_dst = me_dst->totloop;
- CustomData *pdata_dst = &me_dst->pdata;
- CustomData *ldata_dst = &me_dst->ldata;
-
- const float (*poly_nors_dst)[3] = CustomData_get_layer(pdata_dst, CD_NORMAL);
- float (*loop_nors_dst)[3] = CustomData_get_layer(ldata_dst, CD_NORMAL);
- short (*custom_nors_dst)[2] = CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL);
-
- BLI_assert(poly_nors_dst);
-
- if (!changed) {
- return;
- }
-
- if (!custom_nors_dst) {
- custom_nors_dst = CustomData_add_layer(ldata_dst, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL, num_loops_dst);
- }
-
- /* Note loop_nors_dst contains our custom normals as transferred from source... */
- BKE_mesh_normals_loop_custom_set(verts_dst, num_verts_dst, edges_dst, num_edges_dst,
- loops_dst, loop_nors_dst, num_loops_dst,
- polys_dst, poly_nors_dst, num_polys_dst,
- custom_nors_dst);
- }
+ if (dtdata_type == DT_TYPE_LNOR) {
+ /* Bake edited destination loop normals into custom normals again. */
+ MVert *verts_dst = me_dst->mvert;
+ const int num_verts_dst = me_dst->totvert;
+ MEdge *edges_dst = me_dst->medge;
+ const int num_edges_dst = me_dst->totedge;
+ MPoly *polys_dst = me_dst->mpoly;
+ const int num_polys_dst = me_dst->totpoly;
+ MLoop *loops_dst = me_dst->mloop;
+ const int num_loops_dst = me_dst->totloop;
+ CustomData *pdata_dst = &me_dst->pdata;
+ CustomData *ldata_dst = &me_dst->ldata;
+
+ const float(*poly_nors_dst)[3] = CustomData_get_layer(pdata_dst, CD_NORMAL);
+ float(*loop_nors_dst)[3] = CustomData_get_layer(ldata_dst, CD_NORMAL);
+ short(*custom_nors_dst)[2] = CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL);
+
+ BLI_assert(poly_nors_dst);
+
+ if (!changed) {
+ return;
+ }
+
+ if (!custom_nors_dst) {
+ custom_nors_dst = CustomData_add_layer(
+ ldata_dst, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL, num_loops_dst);
+ }
+
+ /* Note loop_nors_dst contains our custom normals as transferred from source... */
+ BKE_mesh_normals_loop_custom_set(verts_dst,
+ num_verts_dst,
+ edges_dst,
+ num_edges_dst,
+ loops_dst,
+ loop_nors_dst,
+ num_loops_dst,
+ polys_dst,
+ poly_nors_dst,
+ num_polys_dst,
+ custom_nors_dst);
+ }
}
/* ********** */
static MeshRemapIslandsCalc data_transfer_get_loop_islands_generator(const int cddata_type)
{
- switch (cddata_type) {
- case CD_FAKE_UV:
- return BKE_mesh_calc_islands_loop_poly_edgeseam;
- default:
- break;
- }
- return NULL;
+ switch (cddata_type) {
+ case CD_FAKE_UV:
+ return BKE_mesh_calc_islands_loop_poly_edgeseam;
+ default:
+ break;
+ }
+ return NULL;
}
-float data_transfer_interp_float_do(
- const int mix_mode, const float val_dst, const float val_src, const float mix_factor)
+float data_transfer_interp_float_do(const int mix_mode,
+ const float val_dst,
+ const float val_src,
+ const float mix_factor)
{
- float val_ret;
-
- if (((mix_mode == CDT_MIX_REPLACE_ABOVE_THRESHOLD && (val_dst < mix_factor)) ||
- (mix_mode == CDT_MIX_REPLACE_BELOW_THRESHOLD && (val_dst > mix_factor))))
- {
- return val_dst; /* Do not affect destination. */
- }
-
- switch (mix_mode) {
- case CDT_MIX_REPLACE_ABOVE_THRESHOLD:
- case CDT_MIX_REPLACE_BELOW_THRESHOLD:
- return val_src;
- case CDT_MIX_MIX:
- val_ret = (val_dst + val_src) * 0.5f;
- break;
- case CDT_MIX_ADD:
- val_ret = val_dst + val_src;
- break;
- case CDT_MIX_SUB:
- val_ret = val_dst - val_src;
- break;
- case CDT_MIX_MUL:
- val_ret = val_dst * val_src;
- break;
- case CDT_MIX_TRANSFER:
- default:
- val_ret = val_src;
- break;
- }
- return interpf(val_ret, val_dst, mix_factor);
+ float val_ret;
+
+ if (((mix_mode == CDT_MIX_REPLACE_ABOVE_THRESHOLD && (val_dst < mix_factor)) ||
+ (mix_mode == CDT_MIX_REPLACE_BELOW_THRESHOLD && (val_dst > mix_factor)))) {
+ return val_dst; /* Do not affect destination. */
+ }
+
+ switch (mix_mode) {
+ case CDT_MIX_REPLACE_ABOVE_THRESHOLD:
+ case CDT_MIX_REPLACE_BELOW_THRESHOLD:
+ return val_src;
+ case CDT_MIX_MIX:
+ val_ret = (val_dst + val_src) * 0.5f;
+ break;
+ case CDT_MIX_ADD:
+ val_ret = val_dst + val_src;
+ break;
+ case CDT_MIX_SUB:
+ val_ret = val_dst - val_src;
+ break;
+ case CDT_MIX_MUL:
+ val_ret = val_dst * val_src;
+ break;
+ case CDT_MIX_TRANSFER:
+ default:
+ val_ret = val_src;
+ break;
+ }
+ return interpf(val_ret, val_dst, mix_factor);
}
-static void data_transfer_interp_char(
- const CustomDataTransferLayerMap *laymap, void *dest,
- const void **sources, const float *weights, const int count, const float mix_factor)
+static void data_transfer_interp_char(const CustomDataTransferLayerMap *laymap,
+ void *dest,
+ const void **sources,
+ const float *weights,
+ const int count,
+ const float mix_factor)
{
- const char **data_src = (const char **)sources;
- char *data_dst = (char *)dest;
+ const char **data_src = (const char **)sources;
+ char *data_dst = (char *)dest;
- const int mix_mode = laymap->mix_mode;
- float val_src = 0.0f;
- const float val_dst = (float)(*data_dst) / 255.0f;
+ const int mix_mode = laymap->mix_mode;
+ float val_src = 0.0f;
+ const float val_dst = (float)(*data_dst) / 255.0f;
- int i;
+ int i;
- for (i = count; i--;) {
- val_src += ((float)(*data_src[i]) / 255.0f) * weights[i];
- }
+ for (i = count; i--;) {
+ val_src += ((float)(*data_src[i]) / 255.0f) * weights[i];
+ }
- val_src = data_transfer_interp_float_do(mix_mode, val_dst, val_src, mix_factor);
+ val_src = data_transfer_interp_float_do(mix_mode, val_dst, val_src, mix_factor);
- CLAMP(val_src, 0.0f, 1.0f);
+ CLAMP(val_src, 0.0f, 1.0f);
- *data_dst = (char)(val_src * 255.0f);
+ *data_dst = (char)(val_src * 255.0f);
}
/* Helpers to match sources and destinations data layers (also handles 'conversions' in CD_FAKE cases). */
-void data_transfer_layersmapping_add_item(
- ListBase *r_map, const int cddata_type, const int mix_mode, const float mix_factor, const float *mix_weights,
- const void *data_src, void *data_dst, const int data_src_n, const int data_dst_n,
- const size_t elem_size, const size_t data_size, const size_t data_offset, const uint64_t data_flag,
- cd_datatransfer_interp interp, void *interp_data)
+void data_transfer_layersmapping_add_item(ListBase *r_map,
+ const int cddata_type,
+ const int mix_mode,
+ const float mix_factor,
+ const float *mix_weights,
+ const void *data_src,
+ void *data_dst,
+ const int data_src_n,
+ const int data_dst_n,
+ const size_t elem_size,
+ const size_t data_size,
+ const size_t data_offset,
+ const uint64_t data_flag,
+ cd_datatransfer_interp interp,
+ void *interp_data)
{
- CustomDataTransferLayerMap *item = MEM_mallocN(sizeof(*item), __func__);
+ CustomDataTransferLayerMap *item = MEM_mallocN(sizeof(*item), __func__);
- BLI_assert(data_dst != NULL);
+ BLI_assert(data_dst != NULL);
- item->data_type = cddata_type;
- item->mix_mode = mix_mode;
- item->mix_factor = mix_factor;
- item->mix_weights = mix_weights;
+ item->data_type = cddata_type;
+ item->mix_mode = mix_mode;
+ item->mix_factor = mix_factor;
+ item->mix_weights = mix_weights;
- item->data_src = data_src;
- item->data_dst = data_dst;
- item->data_src_n = data_src_n;
- item->data_dst_n = data_dst_n;
- item->elem_size = elem_size;
+ item->data_src = data_src;
+ item->data_dst = data_dst;
+ item->data_src_n = data_src_n;
+ item->data_dst_n = data_dst_n;
+ item->elem_size = elem_size;
- item->data_size = data_size;
- item->data_offset = data_offset;
- item->data_flag = data_flag;
+ item->data_size = data_size;
+ item->data_offset = data_offset;
+ item->data_flag = data_flag;
- item->interp = interp;
- item->interp_data = interp_data;
+ item->interp = interp;
+ item->interp_data = interp_data;
- BLI_addtail(r_map, item);
+ BLI_addtail(r_map, item);
}
-static void data_transfer_layersmapping_add_item_cd(
- ListBase *r_map, const int cddata_type, const int mix_mode, const float mix_factor, const float *mix_weights,
- void *data_src, void *data_dst, cd_datatransfer_interp interp, void *interp_data)
+static void data_transfer_layersmapping_add_item_cd(ListBase *r_map,
+ const int cddata_type,
+ const int mix_mode,
+ const float mix_factor,
+ const float *mix_weights,
+ void *data_src,
+ void *data_dst,
+ cd_datatransfer_interp interp,
+ void *interp_data)
{
- uint64_t data_flag = 0;
-
- if (cddata_type == CD_FREESTYLE_EDGE) {
- data_flag = FREESTYLE_EDGE_MARK;
- }
- else if (cddata_type == CD_FREESTYLE_FACE) {
- data_flag = FREESTYLE_FACE_MARK;
- }
-
- data_transfer_layersmapping_add_item(
- r_map, cddata_type, mix_mode, mix_factor, mix_weights, data_src, data_dst,
- 0, 0, 0, 0, 0, data_flag, interp, interp_data);
+ uint64_t data_flag = 0;
+
+ if (cddata_type == CD_FREESTYLE_EDGE) {
+ data_flag = FREESTYLE_EDGE_MARK;
+ }
+ else if (cddata_type == CD_FREESTYLE_FACE) {
+ data_flag = FREESTYLE_FACE_MARK;
+ }
+
+ data_transfer_layersmapping_add_item(r_map,
+ cddata_type,
+ mix_mode,
+ mix_factor,
+ mix_weights,
+ data_src,
+ data_dst,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ data_flag,
+ interp,
+ interp_data);
}
/* Note: All those layer mapping handlers return false *only* if they were given invalid parameters.
@@ -481,506 +543,681 @@ static void data_transfer_layersmapping_add_item_cd(
* to given parameters.
*/
-static bool data_transfer_layersmapping_cdlayers_multisrc_to_dst(
- ListBase *r_map, const int cddata_type, const int mix_mode, const float mix_factor, const float *mix_weights,
- const int num_elem_dst, const bool use_create, const bool use_delete,
- CustomData *cd_src, CustomData *cd_dst, const bool use_dupref_dst,
- const int tolayers, bool *use_layers_src, const int num_layers_src,
- cd_datatransfer_interp interp, void *interp_data)
+static bool data_transfer_layersmapping_cdlayers_multisrc_to_dst(ListBase *r_map,
+ const int cddata_type,
+ const int mix_mode,
+ const float mix_factor,
+ const float *mix_weights,
+ const int num_elem_dst,
+ const bool use_create,
+ const bool use_delete,
+ CustomData *cd_src,
+ CustomData *cd_dst,
+ const bool use_dupref_dst,
+ const int tolayers,
+ bool *use_layers_src,
+ const int num_layers_src,
+ cd_datatransfer_interp interp,
+ void *interp_data)
{
- void *data_src, *data_dst = NULL;
- int idx_src = num_layers_src;
- int idx_dst, tot_dst = CustomData_number_of_layers(cd_dst, cddata_type);
- bool *data_dst_to_delete = NULL;
-
- if (!use_layers_src) {
- /* No source at all, we can only delete all dest if requested... */
- if (use_delete) {
- idx_dst = tot_dst;
- while (idx_dst--) {
- CustomData_free_layer(cd_dst, cddata_type, num_elem_dst, idx_dst);
- }
- }
- return true;
- }
-
- switch (tolayers) {
- case DT_LAYERS_INDEX_DST:
- idx_dst = tot_dst;
-
- /* Find last source actually used! */
- while (idx_src-- && !use_layers_src[idx_src]);
- idx_src++;
-
- if (idx_dst < idx_src) {
- if (use_create) {
- /* Create as much data layers as necessary! */
- for (; idx_dst < idx_src; idx_dst++) {
- CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst);
- }
- }
- else {
- /* Otherwise, just try to map what we can with existing dst data layers. */
- idx_src = idx_dst;
- }
- }
- else if (use_delete && idx_dst > idx_src) {
- while (idx_dst-- > idx_src) {
- CustomData_free_layer(cd_dst, cddata_type, num_elem_dst, idx_dst);
- }
- }
- if (r_map) {
- while (idx_src--) {
- if (!use_layers_src[idx_src]) {
- continue;
- }
- data_src = CustomData_get_layer_n(cd_src, cddata_type, idx_src);
- /* If dest is a evaluated mesh (fro; ;odifier), we do not want to overwrite cdlayers of orig mesh! */
- if (use_dupref_dst) {
- data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_src, num_elem_dst);
- }
- else {
- data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_src);
- }
- data_transfer_layersmapping_add_item_cd(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- data_src, data_dst, interp, interp_data);
- }
- }
- break;
- case DT_LAYERS_NAME_DST:
- if (use_delete) {
- if (tot_dst) {
- data_dst_to_delete = MEM_mallocN(sizeof(*data_dst_to_delete) * (size_t)tot_dst, __func__);
- memset(data_dst_to_delete, true, sizeof(*data_dst_to_delete) * (size_t)tot_dst);
- }
- }
-
- while (idx_src--) {
- const char *name;
-
- if (!use_layers_src[idx_src]) {
- continue;
- }
-
- name = CustomData_get_layer_name(cd_src, cddata_type, idx_src);
- data_src = CustomData_get_layer_n(cd_src, cddata_type, idx_src);
-
- if ((idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name)) == -1) {
- if (use_create) {
- CustomData_add_layer_named(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst, name);
- idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name);
- }
- else {
- /* If we are not allowed to create missing dst data layers, just skip matching src one. */
- continue;
- }
- }
- else if (data_dst_to_delete) {
- data_dst_to_delete[idx_dst] = false;
- }
- if (r_map) {
- /* If dest is a evaluated mesh (from modifier), we do not want to overwrite cdlayers of orig mesh! */
- if (use_dupref_dst) {
- data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst);
- }
- else {
- data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_dst);
- }
- data_transfer_layersmapping_add_item_cd(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- data_src, data_dst, interp, interp_data);
- }
- }
-
- if (data_dst_to_delete) {
- /* Note: This won't affect newly created layers, if any, since tot_dst has not been updated!
- * Also, looping backward ensures us we do not suffer from index shifting when deleting a layer.
- */
- for (idx_dst = tot_dst; idx_dst--;) {
- if (data_dst_to_delete[idx_dst]) {
- CustomData_free_layer(cd_dst, cddata_type, num_elem_dst, idx_dst);
- }
- }
-
- MEM_freeN(data_dst_to_delete);
- }
- break;
- default:
- return false;
- }
-
- return true;
+ void *data_src, *data_dst = NULL;
+ int idx_src = num_layers_src;
+ int idx_dst, tot_dst = CustomData_number_of_layers(cd_dst, cddata_type);
+ bool *data_dst_to_delete = NULL;
+
+ if (!use_layers_src) {
+ /* No source at all, we can only delete all dest if requested... */
+ if (use_delete) {
+ idx_dst = tot_dst;
+ while (idx_dst--) {
+ CustomData_free_layer(cd_dst, cddata_type, num_elem_dst, idx_dst);
+ }
+ }
+ return true;
+ }
+
+ switch (tolayers) {
+ case DT_LAYERS_INDEX_DST:
+ idx_dst = tot_dst;
+
+ /* Find last source actually used! */
+ while (idx_src-- && !use_layers_src[idx_src])
+ ;
+ idx_src++;
+
+ if (idx_dst < idx_src) {
+ if (use_create) {
+ /* Create as much data layers as necessary! */
+ for (; idx_dst < idx_src; idx_dst++) {
+ CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst);
+ }
+ }
+ else {
+ /* Otherwise, just try to map what we can with existing dst data layers. */
+ idx_src = idx_dst;
+ }
+ }
+ else if (use_delete && idx_dst > idx_src) {
+ while (idx_dst-- > idx_src) {
+ CustomData_free_layer(cd_dst, cddata_type, num_elem_dst, idx_dst);
+ }
+ }
+ if (r_map) {
+ while (idx_src--) {
+ if (!use_layers_src[idx_src]) {
+ continue;
+ }
+ data_src = CustomData_get_layer_n(cd_src, cddata_type, idx_src);
+ /* If dest is a evaluated mesh (fro; ;odifier), we do not want to overwrite cdlayers of orig mesh! */
+ if (use_dupref_dst) {
+ data_dst = CustomData_duplicate_referenced_layer_n(
+ cd_dst, cddata_type, idx_src, num_elem_dst);
+ }
+ else {
+ data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_src);
+ }
+ data_transfer_layersmapping_add_item_cd(r_map,
+ cddata_type,
+ mix_mode,
+ mix_factor,
+ mix_weights,
+ data_src,
+ data_dst,
+ interp,
+ interp_data);
+ }
+ }
+ break;
+ case DT_LAYERS_NAME_DST:
+ if (use_delete) {
+ if (tot_dst) {
+ data_dst_to_delete = MEM_mallocN(sizeof(*data_dst_to_delete) * (size_t)tot_dst,
+ __func__);
+ memset(data_dst_to_delete, true, sizeof(*data_dst_to_delete) * (size_t)tot_dst);
+ }
+ }
+
+ while (idx_src--) {
+ const char *name;
+
+ if (!use_layers_src[idx_src]) {
+ continue;
+ }
+
+ name = CustomData_get_layer_name(cd_src, cddata_type, idx_src);
+ data_src = CustomData_get_layer_n(cd_src, cddata_type, idx_src);
+
+ if ((idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name)) == -1) {
+ if (use_create) {
+ CustomData_add_layer_named(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst, name);
+ idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name);
+ }
+ else {
+ /* If we are not allowed to create missing dst data layers, just skip matching src one. */
+ continue;
+ }
+ }
+ else if (data_dst_to_delete) {
+ data_dst_to_delete[idx_dst] = false;
+ }
+ if (r_map) {
+ /* If dest is a evaluated mesh (from modifier), we do not want to overwrite cdlayers of orig mesh! */
+ if (use_dupref_dst) {
+ data_dst = CustomData_duplicate_referenced_layer_n(
+ cd_dst, cddata_type, idx_dst, num_elem_dst);
+ }
+ else {
+ data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_dst);
+ }
+ data_transfer_layersmapping_add_item_cd(r_map,
+ cddata_type,
+ mix_mode,
+ mix_factor,
+ mix_weights,
+ data_src,
+ data_dst,
+ interp,
+ interp_data);
+ }
+ }
+
+ if (data_dst_to_delete) {
+ /* Note: This won't affect newly created layers, if any, since tot_dst has not been updated!
+ * Also, looping backward ensures us we do not suffer from index shifting when deleting a layer.
+ */
+ for (idx_dst = tot_dst; idx_dst--;) {
+ if (data_dst_to_delete[idx_dst]) {
+ CustomData_free_layer(cd_dst, cddata_type, num_elem_dst, idx_dst);
+ }
+ }
+
+ MEM_freeN(data_dst_to_delete);
+ }
+ break;
+ default:
+ return false;
+ }
+
+ return true;
}
-static bool data_transfer_layersmapping_cdlayers(
- ListBase *r_map, const int cddata_type, const int mix_mode, const float mix_factor, const float *mix_weights,
- const int num_elem_dst, const bool use_create, const bool use_delete,
- CustomData *cd_src, CustomData *cd_dst, const bool use_dupref_dst,
- const int fromlayers, const int tolayers,
- cd_datatransfer_interp interp, void *interp_data)
+static bool data_transfer_layersmapping_cdlayers(ListBase *r_map,
+ const int cddata_type,
+ const int mix_mode,
+ const float mix_factor,
+ const float *mix_weights,
+ const int num_elem_dst,
+ const bool use_create,
+ const bool use_delete,
+ CustomData *cd_src,
+ CustomData *cd_dst,
+ const bool use_dupref_dst,
+ const int fromlayers,
+ const int tolayers,
+ cd_datatransfer_interp interp,
+ void *interp_data)
{
- int idx_src, idx_dst;
- void *data_src, *data_dst = NULL;
-
- if (CustomData_layertype_is_singleton(cddata_type)) {
- if (!(data_src = CustomData_get_layer(cd_src, cddata_type))) {
- if (use_delete) {
- CustomData_free_layer(cd_dst, cddata_type, num_elem_dst, 0);
- }
- return true;
- }
-
- data_dst = CustomData_get_layer(cd_dst, cddata_type);
- if (!data_dst) {
- if (!use_create) {
- return true;
- }
- data_dst = CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst);
- }
- else if (use_dupref_dst && r_map) {
- /* If dest is a evaluated mesh (from modifier), we do not want to overwrite cdlayers of orig mesh! */
- data_dst = CustomData_duplicate_referenced_layer(cd_dst, cddata_type, num_elem_dst);
- }
-
- if (r_map) {
- data_transfer_layersmapping_add_item_cd(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- data_src, data_dst, interp, interp_data);
- }
- }
- else if (fromlayers == DT_LAYERS_ACTIVE_SRC || fromlayers >= 0) {
- /* Note: use_delete has not much meaning in this case, ignored. */
-
- if (fromlayers >= 0) { /* Real-layer index */
- idx_src = fromlayers;
- }
- else {
- if ((idx_src = CustomData_get_active_layer(cd_src, cddata_type)) == -1) {
- return true;
- }
- }
- data_src = CustomData_get_layer_n(cd_src, cddata_type, idx_src);
- if (!data_src) {
- return true;
- }
-
- if (tolayers >= 0) { /* Real-layer index */
- idx_dst = tolayers;
- /* If dest is a evaluated mesh (from modifier), we do not want to overwrite cdlayers of orig mesh! */
- if (use_dupref_dst && r_map) {
- data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst);
- }
- else {
- data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_dst);
- }
- }
- else if (tolayers == DT_LAYERS_ACTIVE_DST) {
- if ((idx_dst = CustomData_get_active_layer(cd_dst, cddata_type)) == -1) {
- if (!use_create) {
- return true;
- }
- data_dst = CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst);
- }
- else {
- /* If dest is a evaluated mesh (from modifier), we do not want to overwrite cdlayers of orig mesh! */
- if (use_dupref_dst && r_map) {
- data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst);
- }
- else {
- data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_dst);
- }
- }
- }
- else if (tolayers == DT_LAYERS_INDEX_DST) {
- int num = CustomData_number_of_layers(cd_dst, cddata_type);
- idx_dst = idx_src;
- if (num <= idx_dst) {
- if (!use_create) {
- return true;
- }
- /* Create as much data layers as necessary! */
- for (; num <= idx_dst; num++) {
- CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst);
- }
- }
- /* If dest is a evaluated mesh (from modifier), we do not want to overwrite cdlayers of orig mesh! */
- if (use_dupref_dst && r_map) {
- data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst);
- }
- else {
- data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_dst);
- }
- }
- else if (tolayers == DT_LAYERS_NAME_DST) {
- const char *name = CustomData_get_layer_name(cd_src, cddata_type, idx_src);
- if ((idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name)) == -1) {
- if (!use_create) {
- return true;
- }
- CustomData_add_layer_named(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst, name);
- idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name);
- }
- /* If dest is a evaluated mesh (from modifier), we do not want to overwrite cdlayers of orig mesh! */
- if (use_dupref_dst && r_map) {
- data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst);
- }
- else {
- data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_dst);
- }
- }
- else {
- return false;
- }
-
- if (!data_dst) {
- return false;
- }
-
- if (r_map) {
- data_transfer_layersmapping_add_item_cd(
- r_map, cddata_type, mix_mode, mix_factor, mix_weights, data_src, data_dst, interp, interp_data);
- }
- }
- else if (fromlayers == DT_LAYERS_ALL_SRC) {
- int num_src = CustomData_number_of_layers(cd_src, cddata_type);
- bool *use_layers_src = num_src ? MEM_mallocN(sizeof(*use_layers_src) * (size_t)num_src, __func__) : NULL;
- bool ret;
-
- if (use_layers_src) {
- memset(use_layers_src, true, sizeof(*use_layers_src) * num_src);
- }
-
- ret = data_transfer_layersmapping_cdlayers_multisrc_to_dst(
- r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- num_elem_dst, use_create, use_delete, cd_src, cd_dst, use_dupref_dst,
- tolayers, use_layers_src, num_src,
- interp, interp_data);
-
- if (use_layers_src) {
- MEM_freeN(use_layers_src);
- }
- return ret;
- }
- else {
- return false;
- }
-
- return true;
+ int idx_src, idx_dst;
+ void *data_src, *data_dst = NULL;
+
+ if (CustomData_layertype_is_singleton(cddata_type)) {
+ if (!(data_src = CustomData_get_layer(cd_src, cddata_type))) {
+ if (use_delete) {
+ CustomData_free_layer(cd_dst, cddata_type, num_elem_dst, 0);
+ }
+ return true;
+ }
+
+ data_dst = CustomData_get_layer(cd_dst, cddata_type);
+ if (!data_dst) {
+ if (!use_create) {
+ return true;
+ }
+ data_dst = CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst);
+ }
+ else if (use_dupref_dst && r_map) {
+ /* If dest is a evaluated mesh (from modifier), we do not want to overwrite cdlayers of orig mesh! */
+ data_dst = CustomData_duplicate_referenced_layer(cd_dst, cddata_type, num_elem_dst);
+ }
+
+ if (r_map) {
+ data_transfer_layersmapping_add_item_cd(r_map,
+ cddata_type,
+ mix_mode,
+ mix_factor,
+ mix_weights,
+ data_src,
+ data_dst,
+ interp,
+ interp_data);
+ }
+ }
+ else if (fromlayers == DT_LAYERS_ACTIVE_SRC || fromlayers >= 0) {
+ /* Note: use_delete has not much meaning in this case, ignored. */
+
+ if (fromlayers >= 0) { /* Real-layer index */
+ idx_src = fromlayers;
+ }
+ else {
+ if ((idx_src = CustomData_get_active_layer(cd_src, cddata_type)) == -1) {
+ return true;
+ }
+ }
+ data_src = CustomData_get_layer_n(cd_src, cddata_type, idx_src);
+ if (!data_src) {
+ return true;
+ }
+
+ if (tolayers >= 0) { /* Real-layer index */
+ idx_dst = tolayers;
+ /* If dest is a evaluated mesh (from modifier), we do not want to overwrite cdlayers of orig mesh! */
+ if (use_dupref_dst && r_map) {
+ data_dst = CustomData_duplicate_referenced_layer_n(
+ cd_dst, cddata_type, idx_dst, num_elem_dst);
+ }
+ else {
+ data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_dst);
+ }
+ }
+ else if (tolayers == DT_LAYERS_ACTIVE_DST) {
+ if ((idx_dst = CustomData_get_active_layer(cd_dst, cddata_type)) == -1) {
+ if (!use_create) {
+ return true;
+ }
+ data_dst = CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst);
+ }
+ else {
+ /* If dest is a evaluated mesh (from modifier), we do not want to overwrite cdlayers of orig mesh! */
+ if (use_dupref_dst && r_map) {
+ data_dst = CustomData_duplicate_referenced_layer_n(
+ cd_dst, cddata_type, idx_dst, num_elem_dst);
+ }
+ else {
+ data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_dst);
+ }
+ }
+ }
+ else if (tolayers == DT_LAYERS_INDEX_DST) {
+ int num = CustomData_number_of_layers(cd_dst, cddata_type);
+ idx_dst = idx_src;
+ if (num <= idx_dst) {
+ if (!use_create) {
+ return true;
+ }
+ /* Create as much data layers as necessary! */
+ for (; num <= idx_dst; num++) {
+ CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst);
+ }
+ }
+ /* If dest is a evaluated mesh (from modifier), we do not want to overwrite cdlayers of orig mesh! */
+ if (use_dupref_dst && r_map) {
+ data_dst = CustomData_duplicate_referenced_layer_n(
+ cd_dst, cddata_type, idx_dst, num_elem_dst);
+ }
+ else {
+ data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_dst);
+ }
+ }
+ else if (tolayers == DT_LAYERS_NAME_DST) {
+ const char *name = CustomData_get_layer_name(cd_src, cddata_type, idx_src);
+ if ((idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name)) == -1) {
+ if (!use_create) {
+ return true;
+ }
+ CustomData_add_layer_named(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst, name);
+ idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name);
+ }
+ /* If dest is a evaluated mesh (from modifier), we do not want to overwrite cdlayers of orig mesh! */
+ if (use_dupref_dst && r_map) {
+ data_dst = CustomData_duplicate_referenced_layer_n(
+ cd_dst, cddata_type, idx_dst, num_elem_dst);
+ }
+ else {
+ data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_dst);
+ }
+ }
+ else {
+ return false;
+ }
+
+ if (!data_dst) {
+ return false;
+ }
+
+ if (r_map) {
+ data_transfer_layersmapping_add_item_cd(r_map,
+ cddata_type,
+ mix_mode,
+ mix_factor,
+ mix_weights,
+ data_src,
+ data_dst,
+ interp,
+ interp_data);
+ }
+ }
+ else if (fromlayers == DT_LAYERS_ALL_SRC) {
+ int num_src = CustomData_number_of_layers(cd_src, cddata_type);
+ bool *use_layers_src = num_src ?
+ MEM_mallocN(sizeof(*use_layers_src) * (size_t)num_src, __func__) :
+ NULL;
+ bool ret;
+
+ if (use_layers_src) {
+ memset(use_layers_src, true, sizeof(*use_layers_src) * num_src);
+ }
+
+ ret = data_transfer_layersmapping_cdlayers_multisrc_to_dst(r_map,
+ cddata_type,
+ mix_mode,
+ mix_factor,
+ mix_weights,
+ num_elem_dst,
+ use_create,
+ use_delete,
+ cd_src,
+ cd_dst,
+ use_dupref_dst,
+ tolayers,
+ use_layers_src,
+ num_src,
+ interp,
+ interp_data);
+
+ if (use_layers_src) {
+ MEM_freeN(use_layers_src);
+ }
+ return ret;
+ }
+ else {
+ return false;
+ }
+
+ return true;
}
-static bool data_transfer_layersmapping_generate(
- ListBase *r_map, Object *ob_src, Object *ob_dst, Mesh *me_src, Mesh *me_dst,
- const int elem_type, int cddata_type, int mix_mode, float mix_factor, const float *mix_weights,
- const int num_elem_dst, const bool use_create, const bool use_delete, const int fromlayers, const int tolayers,
- SpaceTransform *space_transform)
+static bool data_transfer_layersmapping_generate(ListBase *r_map,
+ Object *ob_src,
+ Object *ob_dst,
+ Mesh *me_src,
+ Mesh *me_dst,
+ const int elem_type,
+ int cddata_type,
+ int mix_mode,
+ float mix_factor,
+ const float *mix_weights,
+ const int num_elem_dst,
+ const bool use_create,
+ const bool use_delete,
+ const int fromlayers,
+ const int tolayers,
+ SpaceTransform *space_transform)
{
- CustomData *cd_src, *cd_dst;
-
- cd_datatransfer_interp interp = NULL;
- void *interp_data = NULL;
-
- if (elem_type == ME_VERT) {
- if (!(cddata_type & CD_FAKE)) {
- cd_src = &me_src->vdata;
- cd_dst = &me_dst->vdata;
-
- if (!data_transfer_layersmapping_cdlayers(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- num_elem_dst, use_create, use_delete,
- cd_src, cd_dst, me_dst != ob_dst->data,
- fromlayers, tolayers,
- interp, interp_data))
- {
- /* We handle specific source selection cases here. */
- return false;
- }
- return true;
- }
- else if (cddata_type == CD_FAKE_BWEIGHT) {
- const size_t elem_size = sizeof(*((MVert *)NULL));
- const size_t data_size = sizeof(((MVert *)NULL)->bweight);
- const size_t data_offset = offsetof(MVert, bweight);
- const uint64_t data_flag = 0;
-
- if (!(me_src->cd_flag & ME_CDFLAG_VERT_BWEIGHT)) {
- if (use_delete) {
- me_dst->cd_flag &= ~ME_CDFLAG_VERT_BWEIGHT;
- }
- return true;
- }
- me_dst->cd_flag |= ME_CDFLAG_VERT_BWEIGHT;
- if (r_map) {
- data_transfer_layersmapping_add_item(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- me_src->mvert, me_dst->mvert,
- me_src->totvert, me_dst->totvert,
- elem_size, data_size, data_offset, data_flag,
- data_transfer_interp_char, interp_data);
- }
- return true;
- }
- else if (cddata_type == CD_FAKE_MDEFORMVERT) {
- bool ret;
-
- cd_src = &me_src->vdata;
- cd_dst = &me_dst->vdata;
-
- ret = data_transfer_layersmapping_vgroups(r_map, mix_mode, mix_factor, mix_weights,
- num_elem_dst, use_create, use_delete,
- ob_src, ob_dst, cd_src, cd_dst, me_dst != ob_dst->data,
- fromlayers, tolayers);
-
- /* Mesh stores its dvert in a specific pointer too. :( */
- me_dst->dvert = CustomData_get_layer(&me_dst->vdata, CD_MDEFORMVERT);
- return ret;
- }
- else if (cddata_type == CD_FAKE_SHAPEKEY) {
- /* TODO: leaving shapekeys aside for now, quite specific case, since we can't access them from MVert :/ */
- return false;
- }
- }
- else if (elem_type == ME_EDGE) {
- if (!(cddata_type & CD_FAKE)) { /* Unused for edges, currently... */
- cd_src = &me_src->edata;
- cd_dst = &me_dst->edata;
-
- if (!data_transfer_layersmapping_cdlayers(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- num_elem_dst, use_create, use_delete,
- cd_src, cd_dst, me_dst != ob_dst->data,
- fromlayers, tolayers,
- interp, interp_data))
- {
- /* We handle specific source selection cases here. */
- return false;
- }
- return true;
- }
- else if (cddata_type == CD_FAKE_CREASE) {
- const size_t elem_size = sizeof(*((MEdge *)NULL));
- const size_t data_size = sizeof(((MEdge *)NULL)->crease);
- const size_t data_offset = offsetof(MEdge, crease);
- const uint64_t data_flag = 0;
-
- if (!(me_src->cd_flag & ME_CDFLAG_EDGE_CREASE)) {
- if (use_delete && !me_dst) {
- me_dst->cd_flag &= ~ME_CDFLAG_EDGE_CREASE;
- }
- return true;
- }
- me_dst->cd_flag |= ME_CDFLAG_EDGE_CREASE;
- if (r_map) {
- data_transfer_layersmapping_add_item(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- me_src->medge, me_dst->medge,
- me_src->totedge, me_dst->totedge,
- elem_size, data_size, data_offset, data_flag,
- data_transfer_interp_char, interp_data);
- }
- return true;
- }
- else if (cddata_type == CD_FAKE_BWEIGHT) {
- const size_t elem_size = sizeof(*((MEdge *)NULL));
- const size_t data_size = sizeof(((MEdge *)NULL)->bweight);
- const size_t data_offset = offsetof(MEdge, bweight);
- const uint64_t data_flag = 0;
-
- if (!(me_src->cd_flag & ME_CDFLAG_EDGE_BWEIGHT)) {
- if (use_delete && !me_dst) {
- me_dst->cd_flag &= ~ME_CDFLAG_EDGE_BWEIGHT;
- }
- return true;
- }
- me_dst->cd_flag |= ME_CDFLAG_EDGE_BWEIGHT;
- if (r_map) {
- data_transfer_layersmapping_add_item(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- me_src->medge, me_dst->medge,
- me_src->totedge, me_dst->totedge,
- elem_size, data_size, data_offset, data_flag,
- data_transfer_interp_char, interp_data);
- }
- return true;
- }
- else if (r_map && ELEM(cddata_type, CD_FAKE_SHARP, CD_FAKE_SEAM)) {
- const size_t elem_size = sizeof(*((MEdge *)NULL));
- const size_t data_size = sizeof(((MEdge *)NULL)->flag);
- const size_t data_offset = offsetof(MEdge, flag);
- const uint64_t data_flag = (cddata_type == CD_FAKE_SHARP) ? ME_SHARP : ME_SEAM;
-
- data_transfer_layersmapping_add_item(
- r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- me_src->medge, me_dst->medge,
- me_src->totedge, me_dst->totedge,
- elem_size, data_size, data_offset, data_flag, NULL, interp_data);
- return true;
- }
- else {
- return false;
- }
- }
- else if (elem_type == ME_LOOP) {
- if (cddata_type == CD_FAKE_UV) {
- cddata_type = CD_MLOOPUV;
- }
- else if (cddata_type == CD_FAKE_LNOR) {
- /* Preprocess should have generated it, Postprocess will convert it back to CD_CUSTOMLOOPNORMAL. */
- cddata_type = CD_NORMAL;
- interp_data = space_transform;
- interp = customdata_data_transfer_interp_normal_normals;
- }
-
- if (!(cddata_type & CD_FAKE)) {
- cd_src = &me_src->ldata;
- cd_dst = &me_dst->ldata;
-
- if (!data_transfer_layersmapping_cdlayers(
- r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- num_elem_dst, use_create, use_delete, cd_src, cd_dst, me_dst != ob_dst->data,
- fromlayers, tolayers,
- interp, interp_data))
- {
- /* We handle specific source selection cases here. */
- return false;
- }
- return true;
- }
- else {
- return false;
- }
- }
- else if (elem_type == ME_POLY) {
- if (cddata_type == CD_FAKE_UV) {
- cddata_type = CD_MLOOPUV;
- }
-
- if (!(cddata_type & CD_FAKE)) {
- cd_src = &me_src->pdata;
- cd_dst = &me_dst->pdata;
-
- if (!data_transfer_layersmapping_cdlayers(
- r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- num_elem_dst, use_create, use_delete, cd_src, cd_dst, me_dst != ob_dst->data,
- fromlayers, tolayers,
- interp, interp_data))
- {
- /* We handle specific source selection cases here. */
- return false;
- }
- return true;
- }
- else if (r_map && cddata_type == CD_FAKE_SHARP) {
- const size_t elem_size = sizeof(*((MPoly *)NULL));
- const size_t data_size = sizeof(((MPoly *)NULL)->flag);
- const size_t data_offset = offsetof(MPoly, flag);
- const uint64_t data_flag = ME_SMOOTH;
-
- data_transfer_layersmapping_add_item(
- r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- me_src->mpoly, me_dst->mpoly,
- me_src->totpoly, me_dst->totpoly,
- elem_size, data_size, data_offset, data_flag, NULL, interp_data);
- return true;
- }
- else {
- return false;
- }
- }
-
- return false;
+ CustomData *cd_src, *cd_dst;
+
+ cd_datatransfer_interp interp = NULL;
+ void *interp_data = NULL;
+
+ if (elem_type == ME_VERT) {
+ if (!(cddata_type & CD_FAKE)) {
+ cd_src = &me_src->vdata;
+ cd_dst = &me_dst->vdata;
+
+ if (!data_transfer_layersmapping_cdlayers(r_map,
+ cddata_type,
+ mix_mode,
+ mix_factor,
+ mix_weights,
+ num_elem_dst,
+ use_create,
+ use_delete,
+ cd_src,
+ cd_dst,
+ me_dst != ob_dst->data,
+ fromlayers,
+ tolayers,
+ interp,
+ interp_data)) {
+ /* We handle specific source selection cases here. */
+ return false;
+ }
+ return true;
+ }
+ else if (cddata_type == CD_FAKE_BWEIGHT) {
+ const size_t elem_size = sizeof(*((MVert *)NULL));
+ const size_t data_size = sizeof(((MVert *)NULL)->bweight);
+ const size_t data_offset = offsetof(MVert, bweight);
+ const uint64_t data_flag = 0;
+
+ if (!(me_src->cd_flag & ME_CDFLAG_VERT_BWEIGHT)) {
+ if (use_delete) {
+ me_dst->cd_flag &= ~ME_CDFLAG_VERT_BWEIGHT;
+ }
+ return true;
+ }
+ me_dst->cd_flag |= ME_CDFLAG_VERT_BWEIGHT;
+ if (r_map) {
+ data_transfer_layersmapping_add_item(r_map,
+ cddata_type,
+ mix_mode,
+ mix_factor,
+ mix_weights,
+ me_src->mvert,
+ me_dst->mvert,
+ me_src->totvert,
+ me_dst->totvert,
+ elem_size,
+ data_size,
+ data_offset,
+ data_flag,
+ data_transfer_interp_char,
+ interp_data);
+ }
+ return true;
+ }
+ else if (cddata_type == CD_FAKE_MDEFORMVERT) {
+ bool ret;
+
+ cd_src = &me_src->vdata;
+ cd_dst = &me_dst->vdata;
+
+ ret = data_transfer_layersmapping_vgroups(r_map,
+ mix_mode,
+ mix_factor,
+ mix_weights,
+ num_elem_dst,
+ use_create,
+ use_delete,
+ ob_src,
+ ob_dst,
+ cd_src,
+ cd_dst,
+ me_dst != ob_dst->data,
+ fromlayers,
+ tolayers);
+
+ /* Mesh stores its dvert in a specific pointer too. :( */
+ me_dst->dvert = CustomData_get_layer(&me_dst->vdata, CD_MDEFORMVERT);
+ return ret;
+ }
+ else if (cddata_type == CD_FAKE_SHAPEKEY) {
+ /* TODO: leaving shapekeys aside for now, quite specific case, since we can't access them from MVert :/ */
+ return false;
+ }
+ }
+ else if (elem_type == ME_EDGE) {
+ if (!(cddata_type & CD_FAKE)) { /* Unused for edges, currently... */
+ cd_src = &me_src->edata;
+ cd_dst = &me_dst->edata;
+
+ if (!data_transfer_layersmapping_cdlayers(r_map,
+ cddata_type,
+ mix_mode,
+ mix_factor,
+ mix_weights,
+ num_elem_dst,
+ use_create,
+ use_delete,
+ cd_src,
+ cd_dst,
+ me_dst != ob_dst->data,
+ fromlayers,
+ tolayers,
+ interp,
+ interp_data)) {
+ /* We handle specific source selection cases here. */
+ return false;
+ }
+ return true;
+ }
+ else if (cddata_type == CD_FAKE_CREASE) {
+ const size_t elem_size = sizeof(*((MEdge *)NULL));
+ const size_t data_size = sizeof(((MEdge *)NULL)->crease);
+ const size_t data_offset = offsetof(MEdge, crease);
+ const uint64_t data_flag = 0;
+
+ if (!(me_src->cd_flag & ME_CDFLAG_EDGE_CREASE)) {
+ if (use_delete && !me_dst) {
+ me_dst->cd_flag &= ~ME_CDFLAG_EDGE_CREASE;
+ }
+ return true;
+ }
+ me_dst->cd_flag |= ME_CDFLAG_EDGE_CREASE;
+ if (r_map) {
+ data_transfer_layersmapping_add_item(r_map,
+ cddata_type,
+ mix_mode,
+ mix_factor,
+ mix_weights,
+ me_src->medge,
+ me_dst->medge,
+ me_src->totedge,
+ me_dst->totedge,
+ elem_size,
+ data_size,
+ data_offset,
+ data_flag,
+ data_transfer_interp_char,
+ interp_data);
+ }
+ return true;
+ }
+ else if (cddata_type == CD_FAKE_BWEIGHT) {
+ const size_t elem_size = sizeof(*((MEdge *)NULL));
+ const size_t data_size = sizeof(((MEdge *)NULL)->bweight);
+ const size_t data_offset = offsetof(MEdge, bweight);
+ const uint64_t data_flag = 0;
+
+ if (!(me_src->cd_flag & ME_CDFLAG_EDGE_BWEIGHT)) {
+ if (use_delete && !me_dst) {
+ me_dst->cd_flag &= ~ME_CDFLAG_EDGE_BWEIGHT;
+ }
+ return true;
+ }
+ me_dst->cd_flag |= ME_CDFLAG_EDGE_BWEIGHT;
+ if (r_map) {
+ data_transfer_layersmapping_add_item(r_map,
+ cddata_type,
+ mix_mode,
+ mix_factor,
+ mix_weights,
+ me_src->medge,
+ me_dst->medge,
+ me_src->totedge,
+ me_dst->totedge,
+ elem_size,
+ data_size,
+ data_offset,
+ data_flag,
+ data_transfer_interp_char,
+ interp_data);
+ }
+ return true;
+ }
+ else if (r_map && ELEM(cddata_type, CD_FAKE_SHARP, CD_FAKE_SEAM)) {
+ const size_t elem_size = sizeof(*((MEdge *)NULL));
+ const size_t data_size = sizeof(((MEdge *)NULL)->flag);
+ const size_t data_offset = offsetof(MEdge, flag);
+ const uint64_t data_flag = (cddata_type == CD_FAKE_SHARP) ? ME_SHARP : ME_SEAM;
+
+ data_transfer_layersmapping_add_item(r_map,
+ cddata_type,
+ mix_mode,
+ mix_factor,
+ mix_weights,
+ me_src->medge,
+ me_dst->medge,
+ me_src->totedge,
+ me_dst->totedge,
+ elem_size,
+ data_size,
+ data_offset,
+ data_flag,
+ NULL,
+ interp_data);
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+ else if (elem_type == ME_LOOP) {
+ if (cddata_type == CD_FAKE_UV) {
+ cddata_type = CD_MLOOPUV;
+ }
+ else if (cddata_type == CD_FAKE_LNOR) {
+ /* Preprocess should have generated it, Postprocess will convert it back to CD_CUSTOMLOOPNORMAL. */
+ cddata_type = CD_NORMAL;
+ interp_data = space_transform;
+ interp = customdata_data_transfer_interp_normal_normals;
+ }
+
+ if (!(cddata_type & CD_FAKE)) {
+ cd_src = &me_src->ldata;
+ cd_dst = &me_dst->ldata;
+
+ if (!data_transfer_layersmapping_cdlayers(r_map,
+ cddata_type,
+ mix_mode,
+ mix_factor,
+ mix_weights,
+ num_elem_dst,
+ use_create,
+ use_delete,
+ cd_src,
+ cd_dst,
+ me_dst != ob_dst->data,
+ fromlayers,
+ tolayers,
+ interp,
+ interp_data)) {
+ /* We handle specific source selection cases here. */
+ return false;
+ }
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+ else if (elem_type == ME_POLY) {
+ if (cddata_type == CD_FAKE_UV) {
+ cddata_type = CD_MLOOPUV;
+ }
+
+ if (!(cddata_type & CD_FAKE)) {
+ cd_src = &me_src->pdata;
+ cd_dst = &me_dst->pdata;
+
+ if (!data_transfer_layersmapping_cdlayers(r_map,
+ cddata_type,
+ mix_mode,
+ mix_factor,
+ mix_weights,
+ num_elem_dst,
+ use_create,
+ use_delete,
+ cd_src,
+ cd_dst,
+ me_dst != ob_dst->data,
+ fromlayers,
+ tolayers,
+ interp,
+ interp_data)) {
+ /* We handle specific source selection cases here. */
+ return false;
+ }
+ return true;
+ }
+ else if (r_map && cddata_type == CD_FAKE_SHARP) {
+ const size_t elem_size = sizeof(*((MPoly *)NULL));
+ const size_t data_size = sizeof(((MPoly *)NULL)->flag);
+ const size_t data_offset = offsetof(MPoly, flag);
+ const uint64_t data_flag = ME_SMOOTH;
+
+ data_transfer_layersmapping_add_item(r_map,
+ cddata_type,
+ mix_mode,
+ mix_factor,
+ mix_weights,
+ me_src->mpoly,
+ me_dst->mpoly,
+ me_src->totpoly,
+ me_dst->totpoly,
+ elem_size,
+ data_size,
+ data_offset,
+ data_flag,
+ NULL,
+ interp_data);
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+
+ return false;
}
/**
@@ -989,90 +1226,161 @@ static bool data_transfer_layersmapping_generate(
* If \a use_delete is true, it will also delete data layers on \a ob_dst that do not match those from \a ob_src,
* to get (as much as possible) exact copy of source data layout.
*/
-void BKE_object_data_transfer_layout(
- struct Depsgraph *depsgraph, Scene *scene,
- Object *ob_src, Object *ob_dst, const int data_types, const bool use_delete,
- const int fromlayers_select[DT_MULTILAYER_INDEX_MAX], const int tolayers_select[DT_MULTILAYER_INDEX_MAX])
+void BKE_object_data_transfer_layout(struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob_src,
+ Object *ob_dst,
+ const int data_types,
+ const bool use_delete,
+ const int fromlayers_select[DT_MULTILAYER_INDEX_MAX],
+ const int tolayers_select[DT_MULTILAYER_INDEX_MAX])
{
- Mesh *me_src;
- Mesh *me_dst;
- int i;
-
- const bool use_create = true; /* We always create needed layers here. */
-
- CustomData_MeshMasks me_src_mask = CD_MASK_BAREMESH;
-
- BLI_assert((ob_src != ob_dst) && (ob_src->type == OB_MESH) && (ob_dst->type == OB_MESH));
-
- me_dst = ob_dst->data;
-
- /* Get source evaluated mesh.*/
- BKE_object_data_transfer_dttypes_to_cdmask(data_types, &me_src_mask);
- me_src = mesh_get_eval_final(depsgraph, scene, ob_src, &me_src_mask);
- if (!me_src) {
- return;
- }
-
- /* Check all possible data types. */
- for (i = 0; i < DT_TYPE_MAX; i++) {
- const int dtdata_type = 1 << i;
- int cddata_type;
- int fromlayers, tolayers, fromto_idx;
-
- if (!(data_types & dtdata_type)) {
- continue;
- }
-
- cddata_type = BKE_object_data_transfer_dttype_to_cdtype(dtdata_type);
-
- fromto_idx = BKE_object_data_transfer_dttype_to_srcdst_index(dtdata_type);
- if (fromto_idx != DT_MULTILAYER_INDEX_INVALID) {
- fromlayers = fromlayers_select[fromto_idx];
- tolayers = tolayers_select[fromto_idx];
- }
- else {
- fromlayers = tolayers = 0;
- }
-
- if (DT_DATATYPE_IS_VERT(dtdata_type)) {
- const int num_elem_dst = me_dst->totvert;
-
- data_transfer_layersmapping_generate(
- NULL, ob_src, ob_dst, me_src, me_dst, ME_VERT, cddata_type, 0, 0.0f, NULL,
- num_elem_dst, use_create, use_delete, fromlayers, tolayers, NULL);
- }
- if (DT_DATATYPE_IS_EDGE(dtdata_type)) {
- const int num_elem_dst = me_dst->totedge;
-
- data_transfer_layersmapping_generate(
- NULL, ob_src, ob_dst, me_src, me_dst, ME_EDGE, cddata_type, 0, 0.0f, NULL,
- num_elem_dst, use_create, use_delete, fromlayers, tolayers, NULL);
- }
- if (DT_DATATYPE_IS_LOOP(dtdata_type)) {
- const int num_elem_dst = me_dst->totloop;
-
- data_transfer_layersmapping_generate(
- NULL, ob_src, ob_dst, me_src, me_dst, ME_LOOP, cddata_type, 0, 0.0f, NULL,
- num_elem_dst, use_create, use_delete, fromlayers, tolayers, NULL);
- }
- if (DT_DATATYPE_IS_POLY(dtdata_type)) {
- const int num_elem_dst = me_dst->totpoly;
-
- data_transfer_layersmapping_generate(
- NULL, ob_src, ob_dst, me_src, me_dst, ME_POLY, cddata_type, 0, 0.0f, NULL,
- num_elem_dst, use_create, use_delete, fromlayers, tolayers, NULL);
- }
- }
+ Mesh *me_src;
+ Mesh *me_dst;
+ int i;
+
+ const bool use_create = true; /* We always create needed layers here. */
+
+ CustomData_MeshMasks me_src_mask = CD_MASK_BAREMESH;
+
+ BLI_assert((ob_src != ob_dst) && (ob_src->type == OB_MESH) && (ob_dst->type == OB_MESH));
+
+ me_dst = ob_dst->data;
+
+ /* Get source evaluated mesh.*/
+ BKE_object_data_transfer_dttypes_to_cdmask(data_types, &me_src_mask);
+ me_src = mesh_get_eval_final(depsgraph, scene, ob_src, &me_src_mask);
+ if (!me_src) {
+ return;
+ }
+
+ /* Check all possible data types. */
+ for (i = 0; i < DT_TYPE_MAX; i++) {
+ const int dtdata_type = 1 << i;
+ int cddata_type;
+ int fromlayers, tolayers, fromto_idx;
+
+ if (!(data_types & dtdata_type)) {
+ continue;
+ }
+
+ cddata_type = BKE_object_data_transfer_dttype_to_cdtype(dtdata_type);
+
+ fromto_idx = BKE_object_data_transfer_dttype_to_srcdst_index(dtdata_type);
+ if (fromto_idx != DT_MULTILAYER_INDEX_INVALID) {
+ fromlayers = fromlayers_select[fromto_idx];
+ tolayers = tolayers_select[fromto_idx];
+ }
+ else {
+ fromlayers = tolayers = 0;
+ }
+
+ if (DT_DATATYPE_IS_VERT(dtdata_type)) {
+ const int num_elem_dst = me_dst->totvert;
+
+ data_transfer_layersmapping_generate(NULL,
+ ob_src,
+ ob_dst,
+ me_src,
+ me_dst,
+ ME_VERT,
+ cddata_type,
+ 0,
+ 0.0f,
+ NULL,
+ num_elem_dst,
+ use_create,
+ use_delete,
+ fromlayers,
+ tolayers,
+ NULL);
+ }
+ if (DT_DATATYPE_IS_EDGE(dtdata_type)) {
+ const int num_elem_dst = me_dst->totedge;
+
+ data_transfer_layersmapping_generate(NULL,
+ ob_src,
+ ob_dst,
+ me_src,
+ me_dst,
+ ME_EDGE,
+ cddata_type,
+ 0,
+ 0.0f,
+ NULL,
+ num_elem_dst,
+ use_create,
+ use_delete,
+ fromlayers,
+ tolayers,
+ NULL);
+ }
+ if (DT_DATATYPE_IS_LOOP(dtdata_type)) {
+ const int num_elem_dst = me_dst->totloop;
+
+ data_transfer_layersmapping_generate(NULL,
+ ob_src,
+ ob_dst,
+ me_src,
+ me_dst,
+ ME_LOOP,
+ cddata_type,
+ 0,
+ 0.0f,
+ NULL,
+ num_elem_dst,
+ use_create,
+ use_delete,
+ fromlayers,
+ tolayers,
+ NULL);
+ }
+ if (DT_DATATYPE_IS_POLY(dtdata_type)) {
+ const int num_elem_dst = me_dst->totpoly;
+
+ data_transfer_layersmapping_generate(NULL,
+ ob_src,
+ ob_dst,
+ me_src,
+ me_dst,
+ ME_POLY,
+ cddata_type,
+ 0,
+ 0.0f,
+ NULL,
+ num_elem_dst,
+ use_create,
+ use_delete,
+ fromlayers,
+ tolayers,
+ NULL);
+ }
+ }
}
-bool BKE_object_data_transfer_ex(
- struct Depsgraph *depsgraph, Scene *scene, Object *ob_src, Object *ob_dst, Mesh *me_dst,
- const int data_types, bool use_create, const int map_vert_mode, const int map_edge_mode,
- const int map_loop_mode, const int map_poly_mode, SpaceTransform *space_transform, const bool auto_transform,
- const float max_distance, const float ray_radius, const float islands_handling_precision,
- const int fromlayers_select[DT_MULTILAYER_INDEX_MAX], const int tolayers_select[DT_MULTILAYER_INDEX_MAX],
- const int mix_mode, const float mix_factor, const char *vgroup_name, const bool invert_vgroup,
- ReportList *reports)
+bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob_src,
+ Object *ob_dst,
+ Mesh *me_dst,
+ const int data_types,
+ bool use_create,
+ const int map_vert_mode,
+ const int map_edge_mode,
+ const int map_loop_mode,
+ const int map_poly_mode,
+ SpaceTransform *space_transform,
+ const bool auto_transform,
+ const float max_distance,
+ const float ray_radius,
+ const float islands_handling_precision,
+ const int fromlayers_select[DT_MULTILAYER_INDEX_MAX],
+ const int tolayers_select[DT_MULTILAYER_INDEX_MAX],
+ const int mix_mode,
+ const float mix_factor,
+ const char *vgroup_name,
+ const bool invert_vgroup,
+ ReportList *reports)
{
#define VDATA 0
#define EDATA 1
@@ -1080,352 +1388,456 @@ bool BKE_object_data_transfer_ex(
#define PDATA 3
#define DATAMAX 4
- SpaceTransform auto_space_transform;
-
- Mesh *me_src;
- bool dirty_nors_dst = true; /* Assumed always true if not using an evaluated mesh as destination. */
- int i;
-
- MDeformVert *mdef = NULL;
- int vg_idx = -1;
- float *weights[DATAMAX] = {NULL};
-
- MeshPairRemap geom_map[DATAMAX] = {{0}};
- bool geom_map_init[DATAMAX] = {0};
- ListBase lay_map = {NULL};
- bool changed = false;
- bool is_modifier = false;
-
- const bool use_delete = false; /* We never delete data layers from destination here. */
-
- CustomData_MeshMasks me_src_mask = CD_MASK_BAREMESH;
-
- BLI_assert((ob_src != ob_dst) && (ob_src->type == OB_MESH) && (ob_dst->type == OB_MESH));
-
- if (me_dst) {
- dirty_nors_dst = (me_dst->runtime.cd_dirty_vert & CD_NORMAL) != 0;
- /* Never create needed custom layers on passed destination mesh
- * (assumed to *not* be ob_dst->data, aka modifier case). */
- use_create = false;
- is_modifier = true;
- }
- else {
- me_dst = ob_dst->data;
- }
-
- if (vgroup_name) {
- mdef = CustomData_get_layer(&me_dst->vdata, CD_MDEFORMVERT);
- if (mdef) {
- vg_idx = defgroup_name_index(ob_dst, vgroup_name);
- }
- }
-
- /* Get source evaluated mesh.*/
- BKE_object_data_transfer_dttypes_to_cdmask(data_types, &me_src_mask);
- BKE_mesh_remap_calc_source_cddata_masks_from_map_modes(
- map_vert_mode, map_edge_mode, map_loop_mode, map_poly_mode, &me_src_mask);
- if (is_modifier) {
- me_src = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_src, false);
-
- if (me_src == NULL || !CustomData_MeshMasks_are_matching(&ob_src->runtime.last_data_mask, &me_src_mask)) {
- CLOG_WARN(&LOG, "Data Transfer: source mesh data is not ready - dependency cycle?");
- return changed;
- }
- }
- else {
- me_src = mesh_get_eval_final(depsgraph, scene, ob_src, &me_src_mask);
- }
- if (!me_src) {
- return changed;
- }
-
- if (auto_transform) {
- if (space_transform == NULL) {
- space_transform = &auto_space_transform;
- }
-
- BKE_mesh_remap_find_best_match_from_mesh(me_dst->mvert, me_dst->totvert, me_src, space_transform);
- }
-
- /* Check all possible data types.
- * Note item mappings and dest mix weights are cached. */
- for (i = 0; i < DT_TYPE_MAX; i++) {
- const int dtdata_type = 1 << i;
- int cddata_type;
- int fromlayers, tolayers, fromto_idx;
-
- if (!(data_types & dtdata_type)) {
- continue;
- }
-
- data_transfer_dtdata_type_preprocess(me_src, me_dst, dtdata_type, dirty_nors_dst);
-
- cddata_type = BKE_object_data_transfer_dttype_to_cdtype(dtdata_type);
-
- fromto_idx = BKE_object_data_transfer_dttype_to_srcdst_index(dtdata_type);
- if (fromto_idx != DT_MULTILAYER_INDEX_INVALID) {
- fromlayers = fromlayers_select[fromto_idx];
- tolayers = tolayers_select[fromto_idx];
- }
- else {
- fromlayers = tolayers = 0;
- }
-
- if (DT_DATATYPE_IS_VERT(dtdata_type)) {
- MVert *verts_dst = me_dst->mvert;
- const int num_verts_dst = me_dst->totvert;
-
- if (!geom_map_init[VDATA]) {
- const int num_verts_src = me_src->totvert;
-
- if ((map_vert_mode == MREMAP_MODE_TOPOLOGY) && (num_verts_dst != num_verts_src)) {
- BKE_report(reports, RPT_ERROR,
- "Source and destination meshes do not have the same amount of vertices, "
- "'Topology' mapping cannot be used in this case");
- continue;
- }
- if ((map_vert_mode & MREMAP_USE_EDGE) && (me_src->totedge == 0)) {
- BKE_report(reports, RPT_ERROR,
- "Source mesh doesn't have any edges, "
- "None of the 'Edge' mappings can be used in this case");
- continue;
- }
- if ((map_vert_mode & MREMAP_USE_POLY) && (me_src->totpoly == 0)) {
- BKE_report(reports, RPT_ERROR,
- "Source mesh doesn't have any faces, "
- "None of the 'Face' mappings can be used in this case");
- continue;
- }
- if (ELEM(0, num_verts_dst, num_verts_src)) {
- BKE_report(reports, RPT_ERROR,
- "Source or destination meshes do not have any vertices, cannot transfer vertex data");
- continue;
- }
-
- BKE_mesh_remap_calc_verts_from_mesh(
- map_vert_mode, space_transform, max_distance, ray_radius,
- verts_dst, num_verts_dst, dirty_nors_dst, me_src, &geom_map[VDATA]);
- geom_map_init[VDATA] = true;
- }
-
- if (mdef && vg_idx != -1 && !weights[VDATA]) {
- weights[VDATA] = MEM_mallocN(sizeof(*(weights[VDATA])) * (size_t)num_verts_dst, __func__);
- BKE_defvert_extract_vgroup_to_vertweights(mdef, vg_idx, num_verts_dst, weights[VDATA], invert_vgroup);
- }
-
- if (data_transfer_layersmapping_generate(
- &lay_map, ob_src, ob_dst, me_src, me_dst, ME_VERT,
- cddata_type, mix_mode, mix_factor, weights[VDATA],
- num_verts_dst, use_create, use_delete, fromlayers, tolayers, space_transform))
- {
- CustomDataTransferLayerMap *lay_mapit;
-
- changed = (lay_map.first != NULL);
-
- for (lay_mapit = lay_map.first; lay_mapit; lay_mapit = lay_mapit->next) {
- CustomData_data_transfer(&geom_map[VDATA], lay_mapit);
- }
-
- BLI_freelistN(&lay_map);
- }
- }
- if (DT_DATATYPE_IS_EDGE(dtdata_type)) {
- MVert *verts_dst = me_dst->mvert;
- const int num_verts_dst = me_dst->totvert;
- MEdge *edges_dst = me_dst->medge;
- const int num_edges_dst = me_dst->totedge;
-
- if (!geom_map_init[EDATA]) {
- const int num_edges_src = me_src->totedge;
-
- if ((map_edge_mode == MREMAP_MODE_TOPOLOGY) && (num_edges_dst != num_edges_src)) {
- BKE_report(reports, RPT_ERROR,
- "Source and destination meshes do not have the same amount of edges, "
- "'Topology' mapping cannot be used in this case");
- continue;
- }
- if ((map_edge_mode & MREMAP_USE_POLY) && (me_src->totpoly == 0)) {
- BKE_report(reports, RPT_ERROR,
- "Source mesh doesn't have any faces, "
- "None of the 'Face' mappings can be used in this case");
- continue;
- }
- if (ELEM(0, num_edges_dst, num_edges_src)) {
- BKE_report(reports, RPT_ERROR,
- "Source or destination meshes do not have any edges, cannot transfer edge data");
- continue;
- }
-
- BKE_mesh_remap_calc_edges_from_mesh(
- map_edge_mode, space_transform, max_distance, ray_radius,
- verts_dst, num_verts_dst, edges_dst, num_edges_dst, dirty_nors_dst,
- me_src, &geom_map[EDATA]);
- geom_map_init[EDATA] = true;
- }
-
- if (mdef && vg_idx != -1 && !weights[EDATA]) {
- weights[EDATA] = MEM_mallocN(sizeof(*weights[EDATA]) * (size_t)num_edges_dst, __func__);
- BKE_defvert_extract_vgroup_to_edgeweights(
- mdef, vg_idx, num_verts_dst, edges_dst, num_edges_dst,
- weights[EDATA], invert_vgroup);
- }
-
- if (data_transfer_layersmapping_generate(
- &lay_map, ob_src, ob_dst, me_src, me_dst, ME_EDGE,
- cddata_type, mix_mode, mix_factor, weights[EDATA],
- num_edges_dst, use_create, use_delete, fromlayers, tolayers, space_transform))
- {
- CustomDataTransferLayerMap *lay_mapit;
-
- changed = (lay_map.first != NULL);
-
- for (lay_mapit = lay_map.first; lay_mapit; lay_mapit = lay_mapit->next) {
- CustomData_data_transfer(&geom_map[EDATA], lay_mapit);
- }
-
- BLI_freelistN(&lay_map);
- }
- }
- if (DT_DATATYPE_IS_LOOP(dtdata_type)) {
- MVert *verts_dst = me_dst->mvert;
- const int num_verts_dst = me_dst->totvert;
- MEdge *edges_dst = me_dst->medge;
- const int num_edges_dst = me_dst->totedge;
- MPoly *polys_dst = me_dst->mpoly;
- const int num_polys_dst = me_dst->totpoly;
- MLoop *loops_dst = me_dst->mloop;
- const int num_loops_dst = me_dst->totloop;
- CustomData *pdata_dst = &me_dst->pdata;
- CustomData *ldata_dst = &me_dst->ldata;
-
- MeshRemapIslandsCalc island_callback = data_transfer_get_loop_islands_generator(cddata_type);
-
- if (!geom_map_init[LDATA]) {
- const int num_loops_src = me_src->totloop;
-
- if ((map_loop_mode == MREMAP_MODE_TOPOLOGY) && (num_loops_dst != num_loops_src)) {
- BKE_report(reports, RPT_ERROR,
- "Source and destination meshes do not have the same amount of face corners, "
- "'Topology' mapping cannot be used in this case");
- continue;
- }
- if ((map_loop_mode & MREMAP_USE_EDGE) && (me_src->totedge == 0)) {
- BKE_report(reports, RPT_ERROR,
- "Source mesh doesn't have any edges, "
- "None of the 'Edge' mappings can be used in this case");
- continue;
- }
- if (ELEM(0, num_loops_dst, num_loops_src)) {
- BKE_report(reports, RPT_ERROR,
- "Source or destination meshes do not have any faces, cannot transfer corner data");
- continue;
- }
-
- BKE_mesh_remap_calc_loops_from_mesh(
- map_loop_mode, space_transform, max_distance, ray_radius,
- verts_dst, num_verts_dst, edges_dst, num_edges_dst,
- loops_dst, num_loops_dst, polys_dst, num_polys_dst,
- ldata_dst, pdata_dst,
- (me_dst->flag & ME_AUTOSMOOTH) != 0, me_dst->smoothresh, dirty_nors_dst,
- me_src,
- island_callback, islands_handling_precision, &geom_map[LDATA]);
- geom_map_init[LDATA] = true;
- }
-
- if (mdef && vg_idx != -1 && !weights[LDATA]) {
- weights[LDATA] = MEM_mallocN(sizeof(*weights[LDATA]) * (size_t)num_loops_dst, __func__);
- BKE_defvert_extract_vgroup_to_loopweights(
- mdef, vg_idx, num_verts_dst, loops_dst, num_loops_dst,
- weights[LDATA], invert_vgroup);
- }
-
- if (data_transfer_layersmapping_generate(
- &lay_map, ob_src, ob_dst, me_src, me_dst, ME_LOOP,
- cddata_type, mix_mode, mix_factor, weights[LDATA],
- num_loops_dst, use_create, use_delete, fromlayers, tolayers, space_transform))
- {
- CustomDataTransferLayerMap *lay_mapit;
-
- changed = (lay_map.first != NULL);
-
- for (lay_mapit = lay_map.first; lay_mapit; lay_mapit = lay_mapit->next) {
- CustomData_data_transfer(&geom_map[LDATA], lay_mapit);
- }
-
- BLI_freelistN(&lay_map);
- }
- }
- if (DT_DATATYPE_IS_POLY(dtdata_type)) {
- MVert *verts_dst = me_dst->mvert;
- const int num_verts_dst = me_dst->totvert;
- MPoly *polys_dst = me_dst->mpoly;
- const int num_polys_dst = me_dst->totpoly;
- MLoop *loops_dst = me_dst->mloop;
- const int num_loops_dst = me_dst->totloop;
- CustomData *pdata_dst = &me_dst->pdata;
-
- if (!geom_map_init[PDATA]) {
- const int num_polys_src = me_src->totpoly;
-
- if ((map_poly_mode == MREMAP_MODE_TOPOLOGY) && (num_polys_dst != num_polys_src)) {
- BKE_report(reports, RPT_ERROR,
- "Source and destination meshes do not have the same amount of faces, "
- "'Topology' mapping cannot be used in this case");
- continue;
- }
- if ((map_poly_mode & MREMAP_USE_EDGE) && (me_src->totedge == 0)) {
- BKE_report(reports, RPT_ERROR,
- "Source mesh doesn't have any edges, "
- "None of the 'Edge' mappings can be used in this case");
- continue;
- }
- if (ELEM(0, num_polys_dst, num_polys_src)) {
- BKE_report(reports, RPT_ERROR,
- "Source or destination meshes do not have any faces, cannot transfer face data");
- continue;
- }
-
- BKE_mesh_remap_calc_polys_from_mesh(
- map_poly_mode, space_transform, max_distance, ray_radius,
- verts_dst, num_verts_dst, loops_dst, num_loops_dst,
- polys_dst, num_polys_dst, pdata_dst, dirty_nors_dst,
- me_src, &geom_map[PDATA]);
- geom_map_init[PDATA] = true;
- }
-
- if (mdef && vg_idx != -1 && !weights[PDATA]) {
- weights[PDATA] = MEM_mallocN(sizeof(*weights[PDATA]) * (size_t)num_polys_dst, __func__);
- BKE_defvert_extract_vgroup_to_polyweights(
- mdef, vg_idx, num_verts_dst, loops_dst, num_loops_dst,
- polys_dst, num_polys_dst, weights[PDATA], invert_vgroup);
- }
-
- if (data_transfer_layersmapping_generate(
- &lay_map, ob_src, ob_dst, me_src, me_dst, ME_POLY,
- cddata_type, mix_mode, mix_factor, weights[PDATA],
- num_polys_dst, use_create, use_delete, fromlayers, tolayers, space_transform))
- {
- CustomDataTransferLayerMap *lay_mapit;
-
- changed = (lay_map.first != NULL);
-
- for (lay_mapit = lay_map.first; lay_mapit; lay_mapit = lay_mapit->next) {
- CustomData_data_transfer(&geom_map[PDATA], lay_mapit);
- }
-
- BLI_freelistN(&lay_map);
- }
- }
-
- data_transfer_dtdata_type_postprocess(ob_src, ob_dst, me_src, me_dst, dtdata_type, changed);
- }
-
- for (i = 0; i < DATAMAX; i++) {
- BKE_mesh_remap_free(&geom_map[i]);
- MEM_SAFE_FREE(weights[i]);
- }
-
- return changed;
+ SpaceTransform auto_space_transform;
+
+ Mesh *me_src;
+ bool dirty_nors_dst =
+ true; /* Assumed always true if not using an evaluated mesh as destination. */
+ int i;
+
+ MDeformVert *mdef = NULL;
+ int vg_idx = -1;
+ float *weights[DATAMAX] = {NULL};
+
+ MeshPairRemap geom_map[DATAMAX] = {{0}};
+ bool geom_map_init[DATAMAX] = {0};
+ ListBase lay_map = {NULL};
+ bool changed = false;
+ bool is_modifier = false;
+
+ const bool use_delete = false; /* We never delete data layers from destination here. */
+
+ CustomData_MeshMasks me_src_mask = CD_MASK_BAREMESH;
+
+ BLI_assert((ob_src != ob_dst) && (ob_src->type == OB_MESH) && (ob_dst->type == OB_MESH));
+
+ if (me_dst) {
+ dirty_nors_dst = (me_dst->runtime.cd_dirty_vert & CD_NORMAL) != 0;
+ /* Never create needed custom layers on passed destination mesh
+ * (assumed to *not* be ob_dst->data, aka modifier case). */
+ use_create = false;
+ is_modifier = true;
+ }
+ else {
+ me_dst = ob_dst->data;
+ }
+
+ if (vgroup_name) {
+ mdef = CustomData_get_layer(&me_dst->vdata, CD_MDEFORMVERT);
+ if (mdef) {
+ vg_idx = defgroup_name_index(ob_dst, vgroup_name);
+ }
+ }
+
+ /* Get source evaluated mesh.*/
+ BKE_object_data_transfer_dttypes_to_cdmask(data_types, &me_src_mask);
+ BKE_mesh_remap_calc_source_cddata_masks_from_map_modes(
+ map_vert_mode, map_edge_mode, map_loop_mode, map_poly_mode, &me_src_mask);
+ if (is_modifier) {
+ me_src = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_src, false);
+
+ if (me_src == NULL ||
+ !CustomData_MeshMasks_are_matching(&ob_src->runtime.last_data_mask, &me_src_mask)) {
+ CLOG_WARN(&LOG, "Data Transfer: source mesh data is not ready - dependency cycle?");
+ return changed;
+ }
+ }
+ else {
+ me_src = mesh_get_eval_final(depsgraph, scene, ob_src, &me_src_mask);
+ }
+ if (!me_src) {
+ return changed;
+ }
+
+ if (auto_transform) {
+ if (space_transform == NULL) {
+ space_transform = &auto_space_transform;
+ }
+
+ BKE_mesh_remap_find_best_match_from_mesh(
+ me_dst->mvert, me_dst->totvert, me_src, space_transform);
+ }
+
+ /* Check all possible data types.
+ * Note item mappings and dest mix weights are cached. */
+ for (i = 0; i < DT_TYPE_MAX; i++) {
+ const int dtdata_type = 1 << i;
+ int cddata_type;
+ int fromlayers, tolayers, fromto_idx;
+
+ if (!(data_types & dtdata_type)) {
+ continue;
+ }
+
+ data_transfer_dtdata_type_preprocess(me_src, me_dst, dtdata_type, dirty_nors_dst);
+
+ cddata_type = BKE_object_data_transfer_dttype_to_cdtype(dtdata_type);
+
+ fromto_idx = BKE_object_data_transfer_dttype_to_srcdst_index(dtdata_type);
+ if (fromto_idx != DT_MULTILAYER_INDEX_INVALID) {
+ fromlayers = fromlayers_select[fromto_idx];
+ tolayers = tolayers_select[fromto_idx];
+ }
+ else {
+ fromlayers = tolayers = 0;
+ }
+
+ if (DT_DATATYPE_IS_VERT(dtdata_type)) {
+ MVert *verts_dst = me_dst->mvert;
+ const int num_verts_dst = me_dst->totvert;
+
+ if (!geom_map_init[VDATA]) {
+ const int num_verts_src = me_src->totvert;
+
+ if ((map_vert_mode == MREMAP_MODE_TOPOLOGY) && (num_verts_dst != num_verts_src)) {
+ BKE_report(reports,
+ RPT_ERROR,
+ "Source and destination meshes do not have the same amount of vertices, "
+ "'Topology' mapping cannot be used in this case");
+ continue;
+ }
+ if ((map_vert_mode & MREMAP_USE_EDGE) && (me_src->totedge == 0)) {
+ BKE_report(reports,
+ RPT_ERROR,
+ "Source mesh doesn't have any edges, "
+ "None of the 'Edge' mappings can be used in this case");
+ continue;
+ }
+ if ((map_vert_mode & MREMAP_USE_POLY) && (me_src->totpoly == 0)) {
+ BKE_report(reports,
+ RPT_ERROR,
+ "Source mesh doesn't have any faces, "
+ "None of the 'Face' mappings can be used in this case");
+ continue;
+ }
+ if (ELEM(0, num_verts_dst, num_verts_src)) {
+ BKE_report(reports,
+ RPT_ERROR,
+ "Source or destination meshes do not have any vertices, cannot transfer "
+ "vertex data");
+ continue;
+ }
+
+ BKE_mesh_remap_calc_verts_from_mesh(map_vert_mode,
+ space_transform,
+ max_distance,
+ ray_radius,
+ verts_dst,
+ num_verts_dst,
+ dirty_nors_dst,
+ me_src,
+ &geom_map[VDATA]);
+ geom_map_init[VDATA] = true;
+ }
+
+ if (mdef && vg_idx != -1 && !weights[VDATA]) {
+ weights[VDATA] = MEM_mallocN(sizeof(*(weights[VDATA])) * (size_t)num_verts_dst, __func__);
+ BKE_defvert_extract_vgroup_to_vertweights(
+ mdef, vg_idx, num_verts_dst, weights[VDATA], invert_vgroup);
+ }
+
+ if (data_transfer_layersmapping_generate(&lay_map,
+ ob_src,
+ ob_dst,
+ me_src,
+ me_dst,
+ ME_VERT,
+ cddata_type,
+ mix_mode,
+ mix_factor,
+ weights[VDATA],
+ num_verts_dst,
+ use_create,
+ use_delete,
+ fromlayers,
+ tolayers,
+ space_transform)) {
+ CustomDataTransferLayerMap *lay_mapit;
+
+ changed = (lay_map.first != NULL);
+
+ for (lay_mapit = lay_map.first; lay_mapit; lay_mapit = lay_mapit->next) {
+ CustomData_data_transfer(&geom_map[VDATA], lay_mapit);
+ }
+
+ BLI_freelistN(&lay_map);
+ }
+ }
+ if (DT_DATATYPE_IS_EDGE(dtdata_type)) {
+ MVert *verts_dst = me_dst->mvert;
+ const int num_verts_dst = me_dst->totvert;
+ MEdge *edges_dst = me_dst->medge;
+ const int num_edges_dst = me_dst->totedge;
+
+ if (!geom_map_init[EDATA]) {
+ const int num_edges_src = me_src->totedge;
+
+ if ((map_edge_mode == MREMAP_MODE_TOPOLOGY) && (num_edges_dst != num_edges_src)) {
+ BKE_report(reports,
+ RPT_ERROR,
+ "Source and destination meshes do not have the same amount of edges, "
+ "'Topology' mapping cannot be used in this case");
+ continue;
+ }
+ if ((map_edge_mode & MREMAP_USE_POLY) && (me_src->totpoly == 0)) {
+ BKE_report(reports,
+ RPT_ERROR,
+ "Source mesh doesn't have any faces, "
+ "None of the 'Face' mappings can be used in this case");
+ continue;
+ }
+ if (ELEM(0, num_edges_dst, num_edges_src)) {
+ BKE_report(
+ reports,
+ RPT_ERROR,
+ "Source or destination meshes do not have any edges, cannot transfer edge data");
+ continue;
+ }
+
+ BKE_mesh_remap_calc_edges_from_mesh(map_edge_mode,
+ space_transform,
+ max_distance,
+ ray_radius,
+ verts_dst,
+ num_verts_dst,
+ edges_dst,
+ num_edges_dst,
+ dirty_nors_dst,
+ me_src,
+ &geom_map[EDATA]);
+ geom_map_init[EDATA] = true;
+ }
+
+ if (mdef && vg_idx != -1 && !weights[EDATA]) {
+ weights[EDATA] = MEM_mallocN(sizeof(*weights[EDATA]) * (size_t)num_edges_dst, __func__);
+ BKE_defvert_extract_vgroup_to_edgeweights(
+ mdef, vg_idx, num_verts_dst, edges_dst, num_edges_dst, weights[EDATA], invert_vgroup);
+ }
+
+ if (data_transfer_layersmapping_generate(&lay_map,
+ ob_src,
+ ob_dst,
+ me_src,
+ me_dst,
+ ME_EDGE,
+ cddata_type,
+ mix_mode,
+ mix_factor,
+ weights[EDATA],
+ num_edges_dst,
+ use_create,
+ use_delete,
+ fromlayers,
+ tolayers,
+ space_transform)) {
+ CustomDataTransferLayerMap *lay_mapit;
+
+ changed = (lay_map.first != NULL);
+
+ for (lay_mapit = lay_map.first; lay_mapit; lay_mapit = lay_mapit->next) {
+ CustomData_data_transfer(&geom_map[EDATA], lay_mapit);
+ }
+
+ BLI_freelistN(&lay_map);
+ }
+ }
+ if (DT_DATATYPE_IS_LOOP(dtdata_type)) {
+ MVert *verts_dst = me_dst->mvert;
+ const int num_verts_dst = me_dst->totvert;
+ MEdge *edges_dst = me_dst->medge;
+ const int num_edges_dst = me_dst->totedge;
+ MPoly *polys_dst = me_dst->mpoly;
+ const int num_polys_dst = me_dst->totpoly;
+ MLoop *loops_dst = me_dst->mloop;
+ const int num_loops_dst = me_dst->totloop;
+ CustomData *pdata_dst = &me_dst->pdata;
+ CustomData *ldata_dst = &me_dst->ldata;
+
+ MeshRemapIslandsCalc island_callback = data_transfer_get_loop_islands_generator(cddata_type);
+
+ if (!geom_map_init[LDATA]) {
+ const int num_loops_src = me_src->totloop;
+
+ if ((map_loop_mode == MREMAP_MODE_TOPOLOGY) && (num_loops_dst != num_loops_src)) {
+ BKE_report(reports,
+ RPT_ERROR,
+ "Source and destination meshes do not have the same amount of face corners, "
+ "'Topology' mapping cannot be used in this case");
+ continue;
+ }
+ if ((map_loop_mode & MREMAP_USE_EDGE) && (me_src->totedge == 0)) {
+ BKE_report(reports,
+ RPT_ERROR,
+ "Source mesh doesn't have any edges, "
+ "None of the 'Edge' mappings can be used in this case");
+ continue;
+ }
+ if (ELEM(0, num_loops_dst, num_loops_src)) {
+ BKE_report(
+ reports,
+ RPT_ERROR,
+ "Source or destination meshes do not have any faces, cannot transfer corner data");
+ continue;
+ }
+
+ BKE_mesh_remap_calc_loops_from_mesh(map_loop_mode,
+ space_transform,
+ max_distance,
+ ray_radius,
+ verts_dst,
+ num_verts_dst,
+ edges_dst,
+ num_edges_dst,
+ loops_dst,
+ num_loops_dst,
+ polys_dst,
+ num_polys_dst,
+ ldata_dst,
+ pdata_dst,
+ (me_dst->flag & ME_AUTOSMOOTH) != 0,
+ me_dst->smoothresh,
+ dirty_nors_dst,
+ me_src,
+ island_callback,
+ islands_handling_precision,
+ &geom_map[LDATA]);
+ geom_map_init[LDATA] = true;
+ }
+
+ if (mdef && vg_idx != -1 && !weights[LDATA]) {
+ weights[LDATA] = MEM_mallocN(sizeof(*weights[LDATA]) * (size_t)num_loops_dst, __func__);
+ BKE_defvert_extract_vgroup_to_loopweights(
+ mdef, vg_idx, num_verts_dst, loops_dst, num_loops_dst, weights[LDATA], invert_vgroup);
+ }
+
+ if (data_transfer_layersmapping_generate(&lay_map,
+ ob_src,
+ ob_dst,
+ me_src,
+ me_dst,
+ ME_LOOP,
+ cddata_type,
+ mix_mode,
+ mix_factor,
+ weights[LDATA],
+ num_loops_dst,
+ use_create,
+ use_delete,
+ fromlayers,
+ tolayers,
+ space_transform)) {
+ CustomDataTransferLayerMap *lay_mapit;
+
+ changed = (lay_map.first != NULL);
+
+ for (lay_mapit = lay_map.first; lay_mapit; lay_mapit = lay_mapit->next) {
+ CustomData_data_transfer(&geom_map[LDATA], lay_mapit);
+ }
+
+ BLI_freelistN(&lay_map);
+ }
+ }
+ if (DT_DATATYPE_IS_POLY(dtdata_type)) {
+ MVert *verts_dst = me_dst->mvert;
+ const int num_verts_dst = me_dst->totvert;
+ MPoly *polys_dst = me_dst->mpoly;
+ const int num_polys_dst = me_dst->totpoly;
+ MLoop *loops_dst = me_dst->mloop;
+ const int num_loops_dst = me_dst->totloop;
+ CustomData *pdata_dst = &me_dst->pdata;
+
+ if (!geom_map_init[PDATA]) {
+ const int num_polys_src = me_src->totpoly;
+
+ if ((map_poly_mode == MREMAP_MODE_TOPOLOGY) && (num_polys_dst != num_polys_src)) {
+ BKE_report(reports,
+ RPT_ERROR,
+ "Source and destination meshes do not have the same amount of faces, "
+ "'Topology' mapping cannot be used in this case");
+ continue;
+ }
+ if ((map_poly_mode & MREMAP_USE_EDGE) && (me_src->totedge == 0)) {
+ BKE_report(reports,
+ RPT_ERROR,
+ "Source mesh doesn't have any edges, "
+ "None of the 'Edge' mappings can be used in this case");
+ continue;
+ }
+ if (ELEM(0, num_polys_dst, num_polys_src)) {
+ BKE_report(
+ reports,
+ RPT_ERROR,
+ "Source or destination meshes do not have any faces, cannot transfer face data");
+ continue;
+ }
+
+ BKE_mesh_remap_calc_polys_from_mesh(map_poly_mode,
+ space_transform,
+ max_distance,
+ ray_radius,
+ verts_dst,
+ num_verts_dst,
+ loops_dst,
+ num_loops_dst,
+ polys_dst,
+ num_polys_dst,
+ pdata_dst,
+ dirty_nors_dst,
+ me_src,
+ &geom_map[PDATA]);
+ geom_map_init[PDATA] = true;
+ }
+
+ if (mdef && vg_idx != -1 && !weights[PDATA]) {
+ weights[PDATA] = MEM_mallocN(sizeof(*weights[PDATA]) * (size_t)num_polys_dst, __func__);
+ BKE_defvert_extract_vgroup_to_polyweights(mdef,
+ vg_idx,
+ num_verts_dst,
+ loops_dst,
+ num_loops_dst,
+ polys_dst,
+ num_polys_dst,
+ weights[PDATA],
+ invert_vgroup);
+ }
+
+ if (data_transfer_layersmapping_generate(&lay_map,
+ ob_src,
+ ob_dst,
+ me_src,
+ me_dst,
+ ME_POLY,
+ cddata_type,
+ mix_mode,
+ mix_factor,
+ weights[PDATA],
+ num_polys_dst,
+ use_create,
+ use_delete,
+ fromlayers,
+ tolayers,
+ space_transform)) {
+ CustomDataTransferLayerMap *lay_mapit;
+
+ changed = (lay_map.first != NULL);
+
+ for (lay_mapit = lay_map.first; lay_mapit; lay_mapit = lay_mapit->next) {
+ CustomData_data_transfer(&geom_map[PDATA], lay_mapit);
+ }
+
+ BLI_freelistN(&lay_map);
+ }
+ }
+
+ data_transfer_dtdata_type_postprocess(ob_src, ob_dst, me_src, me_dst, dtdata_type, changed);
+ }
+
+ for (i = 0; i < DATAMAX; i++) {
+ BKE_mesh_remap_free(&geom_map[i]);
+ MEM_SAFE_FREE(weights[i]);
+ }
+
+ return changed;
#undef VDATA
#undef EDATA
@@ -1434,20 +1846,50 @@ bool BKE_object_data_transfer_ex(
#undef DATAMAX
}
-bool BKE_object_data_transfer_mesh(
- struct Depsgraph *depsgraph, Scene *scene, Object *ob_src, Object *ob_dst, const int data_types,
- const bool use_create, const int map_vert_mode, const int map_edge_mode, const int map_loop_mode,
- const int map_poly_mode, SpaceTransform *space_transform, const bool auto_transform,
- const float max_distance, const float ray_radius, const float islands_handling_precision,
- const int fromlayers_select[DT_MULTILAYER_INDEX_MAX], const int tolayers_select[DT_MULTILAYER_INDEX_MAX],
- const int mix_mode, const float mix_factor, const char *vgroup_name, const bool invert_vgroup,
- ReportList *reports)
+bool BKE_object_data_transfer_mesh(struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob_src,
+ Object *ob_dst,
+ const int data_types,
+ const bool use_create,
+ const int map_vert_mode,
+ const int map_edge_mode,
+ const int map_loop_mode,
+ const int map_poly_mode,
+ SpaceTransform *space_transform,
+ const bool auto_transform,
+ const float max_distance,
+ const float ray_radius,
+ const float islands_handling_precision,
+ const int fromlayers_select[DT_MULTILAYER_INDEX_MAX],
+ const int tolayers_select[DT_MULTILAYER_INDEX_MAX],
+ const int mix_mode,
+ const float mix_factor,
+ const char *vgroup_name,
+ const bool invert_vgroup,
+ ReportList *reports)
{
- return BKE_object_data_transfer_ex(
- depsgraph, scene, ob_src, ob_dst, NULL, data_types, use_create,
- map_vert_mode, map_edge_mode, map_loop_mode, map_poly_mode,
- space_transform, auto_transform,
- max_distance, ray_radius, islands_handling_precision,
- fromlayers_select, tolayers_select,
- mix_mode, mix_factor, vgroup_name, invert_vgroup, reports);
+ return BKE_object_data_transfer_ex(depsgraph,
+ scene,
+ ob_src,
+ ob_dst,
+ NULL,
+ data_types,
+ use_create,
+ map_vert_mode,
+ map_edge_mode,
+ map_loop_mode,
+ map_poly_mode,
+ space_transform,
+ auto_transform,
+ max_distance,
+ ray_radius,
+ islands_handling_precision,
+ fromlayers_select,
+ tolayers_select,
+ mix_mode,
+ mix_factor,
+ vgroup_name,
+ invert_vgroup,
+ reports);
}
diff --git a/source/blender/blenkernel/intern/data_transfer_intern.h b/source/blender/blenkernel/intern/data_transfer_intern.h
index ca8e85c2363..68ded6e2bc4 100644
--- a/source/blender/blenkernel/intern/data_transfer_intern.h
+++ b/source/blender/blenkernel/intern/data_transfer_intern.h
@@ -24,34 +24,56 @@
#ifndef __DATA_TRANSFER_INTERN_H__
#define __DATA_TRANSFER_INTERN_H__
-#include "BKE_customdata.h" /* For cd_datatransfer_interp */
+#include "BKE_customdata.h" /* For cd_datatransfer_interp */
struct CustomData;
struct CustomDataTransferLayerMap;
struct ListBase;
-float data_transfer_interp_float_do(
- const int mix_mode, const float val_dst, const float val_src, const float mix_factor);
+float data_transfer_interp_float_do(const int mix_mode,
+ const float val_dst,
+ const float val_src,
+ const float mix_factor);
-void data_transfer_layersmapping_add_item(
- struct ListBase *r_map, const int data_type, const int mix_mode,
- const float mix_factor, const float *mix_weights,
- const void *data_src, void *data_dst, const int data_src_n, const int data_dst_n,
- const size_t elem_size, const size_t data_size, const size_t data_offset, const uint64_t data_flag,
- cd_datatransfer_interp interp, void *interp_data);
+void data_transfer_layersmapping_add_item(struct ListBase *r_map,
+ const int data_type,
+ const int mix_mode,
+ const float mix_factor,
+ const float *mix_weights,
+ const void *data_src,
+ void *data_dst,
+ const int data_src_n,
+ const int data_dst_n,
+ const size_t elem_size,
+ const size_t data_size,
+ const size_t data_offset,
+ const uint64_t data_flag,
+ cd_datatransfer_interp interp,
+ void *interp_data);
/* Type-specific. */
-bool data_transfer_layersmapping_vgroups(
- struct ListBase *r_map, const int mix_mode, const float mix_factor, const float *mix_weights,
- const int num_elem_dst, const bool use_create, const bool use_delete,
- struct Object *ob_src, struct Object *ob_dst, struct CustomData *cd_src, struct CustomData *cd_dst,
- const bool use_dupref_dst, const int fromlayers, const int tolayers);
+bool data_transfer_layersmapping_vgroups(struct ListBase *r_map,
+ const int mix_mode,
+ const float mix_factor,
+ const float *mix_weights,
+ const int num_elem_dst,
+ const bool use_create,
+ const bool use_delete,
+ struct Object *ob_src,
+ struct Object *ob_dst,
+ struct CustomData *cd_src,
+ struct CustomData *cd_dst,
+ const bool use_dupref_dst,
+ const int fromlayers,
+ const int tolayers);
/* Defined in customdata.c */
-void customdata_data_transfer_interp_normal_normals(
- const CustomDataTransferLayerMap *laymap, void *data_dst,
- const void **sources, const float *weights, const int count,
- const float mix_factor);
+void customdata_data_transfer_interp_normal_normals(const CustomDataTransferLayerMap *laymap,
+ void *data_dst,
+ const void **sources,
+ const float *weights,
+ const int count,
+ const float mix_factor);
-#endif /* __DATA_TRANSFER_INTERN_H__ */
+#endif /* __DATA_TRANSFER_INTERN_H__ */
diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c
index 3e6649085dd..7769f3aff86 100644
--- a/source/blender/blenkernel/intern/deform.c
+++ b/source/blender/blenkernel/intern/deform.c
@@ -21,7 +21,6 @@
* \ingroup bke
*/
-
#include <string.h>
#include <math.h>
#include <ctype.h>
@@ -45,7 +44,7 @@
#include "BKE_customdata.h"
#include "BKE_data_transfer.h"
-#include "BKE_deform.h" /* own include */
+#include "BKE_deform.h" /* own include */
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
#include "BKE_object.h"
@@ -53,54 +52,53 @@
#include "data_transfer_intern.h"
-
bDeformGroup *BKE_defgroup_new(Object *ob, const char *name)
{
- bDeformGroup *defgroup;
+ bDeformGroup *defgroup;
- BLI_assert(OB_TYPE_SUPPORT_VGROUP(ob->type));
+ BLI_assert(OB_TYPE_SUPPORT_VGROUP(ob->type));
- defgroup = MEM_callocN(sizeof(bDeformGroup), __func__);
+ defgroup = MEM_callocN(sizeof(bDeformGroup), __func__);
- BLI_strncpy(defgroup->name, name, sizeof(defgroup->name));
+ BLI_strncpy(defgroup->name, name, sizeof(defgroup->name));
- BLI_addtail(&ob->defbase, defgroup);
- defgroup_unique_name(defgroup, ob);
+ BLI_addtail(&ob->defbase, defgroup);
+ defgroup_unique_name(defgroup, ob);
- BKE_object_batch_cache_dirty_tag(ob);
+ BKE_object_batch_cache_dirty_tag(ob);
- return defgroup;
+ return defgroup;
}
void defgroup_copy_list(ListBase *outbase, const ListBase *inbase)
{
- bDeformGroup *defgroup, *defgroupn;
+ bDeformGroup *defgroup, *defgroupn;
- BLI_listbase_clear(outbase);
+ BLI_listbase_clear(outbase);
- for (defgroup = inbase->first; defgroup; defgroup = defgroup->next) {
- defgroupn = defgroup_duplicate(defgroup);
- BLI_addtail(outbase, defgroupn);
- }
+ for (defgroup = inbase->first; defgroup; defgroup = defgroup->next) {
+ defgroupn = defgroup_duplicate(defgroup);
+ BLI_addtail(outbase, defgroupn);
+ }
}
bDeformGroup *defgroup_duplicate(const bDeformGroup *ingroup)
{
- bDeformGroup *outgroup;
+ bDeformGroup *outgroup;
- if (!ingroup) {
- BLI_assert(0);
- return NULL;
- }
+ if (!ingroup) {
+ BLI_assert(0);
+ return NULL;
+ }
- outgroup = MEM_callocN(sizeof(bDeformGroup), "copy deformGroup");
+ outgroup = MEM_callocN(sizeof(bDeformGroup), "copy deformGroup");
- /* For now, just copy everything over. */
- memcpy(outgroup, ingroup, sizeof(bDeformGroup));
+ /* For now, just copy everything over. */
+ memcpy(outgroup, ingroup, sizeof(bDeformGroup));
- outgroup->next = outgroup->prev = NULL;
+ outgroup->next = outgroup->prev = NULL;
- return outgroup;
+ return outgroup;
}
/**
@@ -108,16 +106,17 @@ bDeformGroup *defgroup_duplicate(const bDeformGroup *ingroup)
* - do nothing if neither are set.
* - add destination weight if needed
*/
-void defvert_copy_subset(
- MDeformVert *dvert_dst, const MDeformVert *dvert_src,
- const bool *vgroup_subset, const int vgroup_tot)
+void defvert_copy_subset(MDeformVert *dvert_dst,
+ const MDeformVert *dvert_src,
+ const bool *vgroup_subset,
+ const int vgroup_tot)
{
- int defgroup;
- for (defgroup = 0; defgroup < vgroup_tot; defgroup++) {
- if (vgroup_subset[defgroup]) {
- defvert_copy_index(dvert_dst, defgroup, dvert_src, defgroup);
- }
- }
+ int defgroup;
+ for (defgroup = 0; defgroup < vgroup_tot; defgroup++) {
+ if (vgroup_subset[defgroup]) {
+ defvert_copy_index(dvert_dst, defgroup, dvert_src, defgroup);
+ }
+ }
}
/**
@@ -125,36 +124,38 @@ void defvert_copy_subset(
* - do nothing if neither are set.
* - add destination weight if needed
*/
-void defvert_mirror_subset(
- MDeformVert *dvert_dst, const MDeformVert *dvert_src,
- const bool *vgroup_subset, const int vgroup_tot,
- const int *flip_map, const int flip_map_len)
+void defvert_mirror_subset(MDeformVert *dvert_dst,
+ const MDeformVert *dvert_src,
+ const bool *vgroup_subset,
+ const int vgroup_tot,
+ const int *flip_map,
+ const int flip_map_len)
{
- int defgroup;
- for (defgroup = 0; defgroup < vgroup_tot && defgroup < flip_map_len; defgroup++) {
- if (vgroup_subset[defgroup] && (dvert_dst != dvert_src || flip_map[defgroup] != defgroup)) {
- defvert_copy_index(dvert_dst, flip_map[defgroup], dvert_src, defgroup);
- }
- }
+ int defgroup;
+ for (defgroup = 0; defgroup < vgroup_tot && defgroup < flip_map_len; defgroup++) {
+ if (vgroup_subset[defgroup] && (dvert_dst != dvert_src || flip_map[defgroup] != defgroup)) {
+ defvert_copy_index(dvert_dst, flip_map[defgroup], dvert_src, defgroup);
+ }
+ }
}
void defvert_copy(MDeformVert *dvert_dst, const MDeformVert *dvert_src)
{
- if (dvert_dst->totweight == dvert_src->totweight) {
- if (dvert_src->totweight)
- memcpy(dvert_dst->dw, dvert_src->dw, dvert_src->totweight * sizeof(MDeformWeight));
- }
- else {
- if (dvert_dst->dw)
- MEM_freeN(dvert_dst->dw);
-
- if (dvert_src->totweight)
- dvert_dst->dw = MEM_dupallocN(dvert_src->dw);
- else
- dvert_dst->dw = NULL;
-
- dvert_dst->totweight = dvert_src->totweight;
- }
+ if (dvert_dst->totweight == dvert_src->totweight) {
+ if (dvert_src->totweight)
+ memcpy(dvert_dst->dw, dvert_src->dw, dvert_src->totweight * sizeof(MDeformWeight));
+ }
+ else {
+ if (dvert_dst->dw)
+ MEM_freeN(dvert_dst->dw);
+
+ if (dvert_src->totweight)
+ dvert_dst->dw = MEM_dupallocN(dvert_src->dw);
+ else
+ dvert_dst->dw = NULL;
+
+ dvert_dst->totweight = dvert_src->totweight;
+ }
}
/**
@@ -162,27 +163,28 @@ void defvert_copy(MDeformVert *dvert_dst, const MDeformVert *dvert_src)
* - do nothing if neither are set.
* - add destination weight if needed.
*/
-void defvert_copy_index(
- MDeformVert *dvert_dst, const int defgroup_dst,
- const MDeformVert *dvert_src, const int defgroup_src)
+void defvert_copy_index(MDeformVert *dvert_dst,
+ const int defgroup_dst,
+ const MDeformVert *dvert_src,
+ const int defgroup_src)
{
- MDeformWeight *dw_src, *dw_dst;
-
- dw_src = defvert_find_index(dvert_src, defgroup_src);
-
- if (dw_src) {
- /* source is valid, verify destination */
- dw_dst = defvert_verify_index(dvert_dst, defgroup_dst);
- dw_dst->weight = dw_src->weight;
- }
- else {
- /* source was NULL, assign zero, could also remove */
- dw_dst = defvert_find_index(dvert_dst, defgroup_dst);
-
- if (dw_dst) {
- dw_dst->weight = 0.0f;
- }
- }
+ MDeformWeight *dw_src, *dw_dst;
+
+ dw_src = defvert_find_index(dvert_src, defgroup_src);
+
+ if (dw_src) {
+ /* source is valid, verify destination */
+ dw_dst = defvert_verify_index(dvert_dst, defgroup_dst);
+ dw_dst->weight = dw_src->weight;
+ }
+ else {
+ /* source was NULL, assign zero, could also remove */
+ dw_dst = defvert_find_index(dvert_dst, defgroup_dst);
+
+ if (dw_dst) {
+ dw_dst->weight = 0.0f;
+ }
+ }
}
/**
@@ -191,43 +193,49 @@ void defvert_copy_index(
*/
void defvert_sync(MDeformVert *dvert_dst, const MDeformVert *dvert_src, const bool use_verify)
{
- if (dvert_src->totweight && dvert_dst->totweight) {
- int i;
- MDeformWeight *dw_src;
- for (i = 0, dw_src = dvert_src->dw; i < dvert_src->totweight; i++, dw_src++) {
- MDeformWeight *dw_dst;
- if (use_verify) dw_dst = defvert_verify_index(dvert_dst, dw_src->def_nr);
- else dw_dst = defvert_find_index(dvert_dst, dw_src->def_nr);
-
- if (dw_dst) {
- dw_dst->weight = dw_src->weight;
- }
- }
- }
+ if (dvert_src->totweight && dvert_dst->totweight) {
+ int i;
+ MDeformWeight *dw_src;
+ for (i = 0, dw_src = dvert_src->dw; i < dvert_src->totweight; i++, dw_src++) {
+ MDeformWeight *dw_dst;
+ if (use_verify)
+ dw_dst = defvert_verify_index(dvert_dst, dw_src->def_nr);
+ else
+ dw_dst = defvert_find_index(dvert_dst, dw_src->def_nr);
+
+ if (dw_dst) {
+ dw_dst->weight = dw_src->weight;
+ }
+ }
+ }
}
/**
* be sure all flip_map values are valid
*/
-void defvert_sync_mapped(
- MDeformVert *dvert_dst, const MDeformVert *dvert_src,
- const int *flip_map, const int flip_map_len, const bool use_verify)
+void defvert_sync_mapped(MDeformVert *dvert_dst,
+ const MDeformVert *dvert_src,
+ const int *flip_map,
+ const int flip_map_len,
+ const bool use_verify)
{
- if (dvert_src->totweight && dvert_dst->totweight) {
- int i;
- MDeformWeight *dw_src;
- for (i = 0, dw_src = dvert_src->dw; i < dvert_src->totweight; i++, dw_src++) {
- if (dw_src->def_nr < flip_map_len) {
- MDeformWeight *dw_dst;
- if (use_verify) dw_dst = defvert_verify_index(dvert_dst, flip_map[dw_src->def_nr]);
- else dw_dst = defvert_find_index(dvert_dst, flip_map[dw_src->def_nr]);
-
- if (dw_dst) {
- dw_dst->weight = dw_src->weight;
- }
- }
- }
- }
+ if (dvert_src->totweight && dvert_dst->totweight) {
+ int i;
+ MDeformWeight *dw_src;
+ for (i = 0, dw_src = dvert_src->dw; i < dvert_src->totweight; i++, dw_src++) {
+ if (dw_src->def_nr < flip_map_len) {
+ MDeformWeight *dw_dst;
+ if (use_verify)
+ dw_dst = defvert_verify_index(dvert_dst, flip_map[dw_src->def_nr]);
+ else
+ dw_dst = defvert_find_index(dvert_dst, flip_map[dw_src->def_nr]);
+
+ if (dw_dst) {
+ dw_dst->weight = dw_src->weight;
+ }
+ }
+ }
+ }
}
/**
@@ -235,248 +243,252 @@ void defvert_sync_mapped(
*/
void defvert_remap(MDeformVert *dvert, int *map, const int map_len)
{
- MDeformWeight *dw = dvert->dw;
- unsigned int i;
- for (i = dvert->totweight; i != 0; i--, dw++) {
- if (dw->def_nr < map_len) {
- dw->def_nr = map[dw->def_nr];
-
- /* just in case */
- BLI_assert(dw->def_nr >= 0);
- }
- }
+ MDeformWeight *dw = dvert->dw;
+ unsigned int i;
+ for (i = dvert->totweight; i != 0; i--, dw++) {
+ if (dw->def_nr < map_len) {
+ dw->def_nr = map[dw->def_nr];
+
+ /* just in case */
+ BLI_assert(dw->def_nr >= 0);
+ }
+ }
}
/**
* Same as #defvert_normalize but takes a bool array.
*/
-void defvert_normalize_subset(MDeformVert *dvert,
- const bool *vgroup_subset, const int vgroup_tot)
+void defvert_normalize_subset(MDeformVert *dvert, const bool *vgroup_subset, const int vgroup_tot)
{
- if (dvert->totweight == 0) {
- /* nothing */
- }
- else if (dvert->totweight == 1) {
- MDeformWeight *dw = dvert->dw;
- if ((dw->def_nr < vgroup_tot) && vgroup_subset[dw->def_nr]) {
- dw->weight = 1.0f;
- }
- }
- else {
- MDeformWeight *dw;
- unsigned int i;
- float tot_weight = 0.0f;
-
- for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
- if ((dw->def_nr < vgroup_tot) && vgroup_subset[dw->def_nr]) {
- tot_weight += dw->weight;
- }
- }
-
- if (tot_weight > 0.0f) {
- float scalar = 1.0f / tot_weight;
- for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
- if ((dw->def_nr < vgroup_tot) && vgroup_subset[dw->def_nr]) {
- dw->weight *= scalar;
-
- /* in case of division errors with very low weights */
- CLAMP(dw->weight, 0.0f, 1.0f);
- }
- }
- }
- }
+ if (dvert->totweight == 0) {
+ /* nothing */
+ }
+ else if (dvert->totweight == 1) {
+ MDeformWeight *dw = dvert->dw;
+ if ((dw->def_nr < vgroup_tot) && vgroup_subset[dw->def_nr]) {
+ dw->weight = 1.0f;
+ }
+ }
+ else {
+ MDeformWeight *dw;
+ unsigned int i;
+ float tot_weight = 0.0f;
+
+ for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
+ if ((dw->def_nr < vgroup_tot) && vgroup_subset[dw->def_nr]) {
+ tot_weight += dw->weight;
+ }
+ }
+
+ if (tot_weight > 0.0f) {
+ float scalar = 1.0f / tot_weight;
+ for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
+ if ((dw->def_nr < vgroup_tot) && vgroup_subset[dw->def_nr]) {
+ dw->weight *= scalar;
+
+ /* in case of division errors with very low weights */
+ CLAMP(dw->weight, 0.0f, 1.0f);
+ }
+ }
+ }
+ }
}
void defvert_normalize(MDeformVert *dvert)
{
- if (dvert->totweight == 0) {
- /* nothing */
- }
- else if (dvert->totweight == 1) {
- dvert->dw[0].weight = 1.0f;
- }
- else {
- MDeformWeight *dw;
- unsigned int i;
- float tot_weight = 0.0f;
-
- for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
- tot_weight += dw->weight;
- }
-
- if (tot_weight > 0.0f) {
- float scalar = 1.0f / tot_weight;
- for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
- dw->weight *= scalar;
-
- /* in case of division errors with very low weights */
- CLAMP(dw->weight, 0.0f, 1.0f);
- }
- }
- }
+ if (dvert->totweight == 0) {
+ /* nothing */
+ }
+ else if (dvert->totweight == 1) {
+ dvert->dw[0].weight = 1.0f;
+ }
+ else {
+ MDeformWeight *dw;
+ unsigned int i;
+ float tot_weight = 0.0f;
+
+ for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
+ tot_weight += dw->weight;
+ }
+
+ if (tot_weight > 0.0f) {
+ float scalar = 1.0f / tot_weight;
+ for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
+ dw->weight *= scalar;
+
+ /* in case of division errors with very low weights */
+ CLAMP(dw->weight, 0.0f, 1.0f);
+ }
+ }
+ }
}
/**
* Same as defvert_normalize() if the locked vgroup is not a member of the subset
*/
-void defvert_normalize_lock_single(
- MDeformVert *dvert,
- const bool *vgroup_subset, const int vgroup_tot,
- const int def_nr_lock)
+void defvert_normalize_lock_single(MDeformVert *dvert,
+ const bool *vgroup_subset,
+ const int vgroup_tot,
+ const int def_nr_lock)
{
- if (dvert->totweight == 0) {
- /* nothing */
- }
- else if (dvert->totweight == 1) {
- MDeformWeight *dw = dvert->dw;
- if ((dw->def_nr < vgroup_tot) && vgroup_subset[dw->def_nr]) {
- if (def_nr_lock != 0) {
- dw->weight = 1.0f;
- }
- }
- }
- else {
- MDeformWeight *dw_lock = NULL;
- MDeformWeight *dw;
- unsigned int i;
- float tot_weight = 0.0f;
- float lock_iweight = 1.0f;
-
- for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
- if ((dw->def_nr < vgroup_tot) && vgroup_subset[dw->def_nr]) {
- if (dw->def_nr != def_nr_lock) {
- tot_weight += dw->weight;
- }
- else {
- dw_lock = dw;
- lock_iweight = (1.0f - dw_lock->weight);
- CLAMP(lock_iweight, 0.0f, 1.0f);
- }
- }
- }
-
- if (tot_weight > 0.0f) {
- /* paranoid, should be 1.0 but in case of float error clamp anyway */
-
- float scalar = (1.0f / tot_weight) * lock_iweight;
- for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
- if ((dw->def_nr < vgroup_tot) && vgroup_subset[dw->def_nr]) {
- if (dw != dw_lock) {
- dw->weight *= scalar;
-
- /* in case of division errors with very low weights */
- CLAMP(dw->weight, 0.0f, 1.0f);
- }
- }
- }
- }
- }
+ if (dvert->totweight == 0) {
+ /* nothing */
+ }
+ else if (dvert->totweight == 1) {
+ MDeformWeight *dw = dvert->dw;
+ if ((dw->def_nr < vgroup_tot) && vgroup_subset[dw->def_nr]) {
+ if (def_nr_lock != 0) {
+ dw->weight = 1.0f;
+ }
+ }
+ }
+ else {
+ MDeformWeight *dw_lock = NULL;
+ MDeformWeight *dw;
+ unsigned int i;
+ float tot_weight = 0.0f;
+ float lock_iweight = 1.0f;
+
+ for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
+ if ((dw->def_nr < vgroup_tot) && vgroup_subset[dw->def_nr]) {
+ if (dw->def_nr != def_nr_lock) {
+ tot_weight += dw->weight;
+ }
+ else {
+ dw_lock = dw;
+ lock_iweight = (1.0f - dw_lock->weight);
+ CLAMP(lock_iweight, 0.0f, 1.0f);
+ }
+ }
+ }
+
+ if (tot_weight > 0.0f) {
+ /* paranoid, should be 1.0 but in case of float error clamp anyway */
+
+ float scalar = (1.0f / tot_weight) * lock_iweight;
+ for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
+ if ((dw->def_nr < vgroup_tot) && vgroup_subset[dw->def_nr]) {
+ if (dw != dw_lock) {
+ dw->weight *= scalar;
+
+ /* in case of division errors with very low weights */
+ CLAMP(dw->weight, 0.0f, 1.0f);
+ }
+ }
+ }
+ }
+ }
}
/**
* Same as defvert_normalize() if no locked vgroup is a member of the subset
*/
-void defvert_normalize_lock_map(
- MDeformVert *dvert,
- const bool *vgroup_subset, const int vgroup_tot,
- const bool *lock_flags, const int defbase_tot)
+void defvert_normalize_lock_map(MDeformVert *dvert,
+ const bool *vgroup_subset,
+ const int vgroup_tot,
+ const bool *lock_flags,
+ const int defbase_tot)
{
- if (dvert->totweight == 0) {
- /* nothing */
- }
- else if (dvert->totweight == 1) {
- MDeformWeight *dw = dvert->dw;
- if ((dw->def_nr < vgroup_tot) && vgroup_subset[dw->def_nr]) {
- if ((dw->def_nr < defbase_tot) && (lock_flags[dw->def_nr] == false)) {
- dw->weight = 1.0f;
- }
- }
- }
- else {
- MDeformWeight *dw;
- unsigned int i;
- float tot_weight = 0.0f;
- float lock_iweight = 0.0f;
-
- for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
- if ((dw->def_nr < vgroup_tot) && vgroup_subset[dw->def_nr]) {
- if ((dw->def_nr < defbase_tot) && (lock_flags[dw->def_nr] == false)) {
- tot_weight += dw->weight;
- }
- else {
- /* invert after */
- lock_iweight += dw->weight;
- }
- }
- }
-
- lock_iweight = max_ff(0.0f, 1.0f - lock_iweight);
-
- if (tot_weight > 0.0f) {
- /* paranoid, should be 1.0 but in case of float error clamp anyway */
-
- float scalar = (1.0f / tot_weight) * lock_iweight;
- for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
- if ((dw->def_nr < vgroup_tot) && vgroup_subset[dw->def_nr]) {
- if ((dw->def_nr < defbase_tot) && (lock_flags[dw->def_nr] == false)) {
- dw->weight *= scalar;
-
- /* in case of division errors with very low weights */
- CLAMP(dw->weight, 0.0f, 1.0f);
- }
- }
- }
- }
- }
+ if (dvert->totweight == 0) {
+ /* nothing */
+ }
+ else if (dvert->totweight == 1) {
+ MDeformWeight *dw = dvert->dw;
+ if ((dw->def_nr < vgroup_tot) && vgroup_subset[dw->def_nr]) {
+ if ((dw->def_nr < defbase_tot) && (lock_flags[dw->def_nr] == false)) {
+ dw->weight = 1.0f;
+ }
+ }
+ }
+ else {
+ MDeformWeight *dw;
+ unsigned int i;
+ float tot_weight = 0.0f;
+ float lock_iweight = 0.0f;
+
+ for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
+ if ((dw->def_nr < vgroup_tot) && vgroup_subset[dw->def_nr]) {
+ if ((dw->def_nr < defbase_tot) && (lock_flags[dw->def_nr] == false)) {
+ tot_weight += dw->weight;
+ }
+ else {
+ /* invert after */
+ lock_iweight += dw->weight;
+ }
+ }
+ }
+
+ lock_iweight = max_ff(0.0f, 1.0f - lock_iweight);
+
+ if (tot_weight > 0.0f) {
+ /* paranoid, should be 1.0 but in case of float error clamp anyway */
+
+ float scalar = (1.0f / tot_weight) * lock_iweight;
+ for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
+ if ((dw->def_nr < vgroup_tot) && vgroup_subset[dw->def_nr]) {
+ if ((dw->def_nr < defbase_tot) && (lock_flags[dw->def_nr] == false)) {
+ dw->weight *= scalar;
+
+ /* in case of division errors with very low weights */
+ CLAMP(dw->weight, 0.0f, 1.0f);
+ }
+ }
+ }
+ }
+ }
}
void defvert_flip(MDeformVert *dvert, const int *flip_map, const int flip_map_len)
{
- MDeformWeight *dw;
- int i;
-
- for (dw = dvert->dw, i = 0; i < dvert->totweight; dw++, i++) {
- if (dw->def_nr < flip_map_len) {
- if (flip_map[dw->def_nr] >= 0) {
- dw->def_nr = flip_map[dw->def_nr];
- }
- }
- }
+ MDeformWeight *dw;
+ int i;
+
+ for (dw = dvert->dw, i = 0; i < dvert->totweight; dw++, i++) {
+ if (dw->def_nr < flip_map_len) {
+ if (flip_map[dw->def_nr] >= 0) {
+ dw->def_nr = flip_map[dw->def_nr];
+ }
+ }
+ }
}
void defvert_flip_merged(MDeformVert *dvert, const int *flip_map, const int flip_map_len)
{
- MDeformWeight *dw, *dw_cpy;
- float weight;
- int i, totweight = dvert->totweight;
-
- /* copy weights */
- for (dw = dvert->dw, i = 0; i < totweight; dw++, i++) {
- if (dw->def_nr < flip_map_len) {
- if (flip_map[dw->def_nr] >= 0) {
- /* error checkers complain of this but we'll never get NULL return */
- dw_cpy = defvert_verify_index(dvert, flip_map[dw->def_nr]);
- dw = &dvert->dw[i]; /* in case array got realloced */
-
- /* distribute weights: if only one of the vertex groups was
- * assigned this will halve the weights, otherwise it gets
- * evened out. this keeps it proportional to other groups */
- weight = 0.5f * (dw_cpy->weight + dw->weight);
- dw_cpy->weight = weight;
- dw->weight = weight;
- }
- }
- }
+ MDeformWeight *dw, *dw_cpy;
+ float weight;
+ int i, totweight = dvert->totweight;
+
+ /* copy weights */
+ for (dw = dvert->dw, i = 0; i < totweight; dw++, i++) {
+ if (dw->def_nr < flip_map_len) {
+ if (flip_map[dw->def_nr] >= 0) {
+ /* error checkers complain of this but we'll never get NULL return */
+ dw_cpy = defvert_verify_index(dvert, flip_map[dw->def_nr]);
+ dw = &dvert->dw[i]; /* in case array got realloced */
+
+ /* distribute weights: if only one of the vertex groups was
+ * assigned this will halve the weights, otherwise it gets
+ * evened out. this keeps it proportional to other groups */
+ weight = 0.5f * (dw_cpy->weight + dw->weight);
+ dw_cpy->weight = weight;
+ dw->weight = weight;
+ }
+ }
+ }
}
bDeformGroup *defgroup_find_name(Object *ob, const char *name)
{
- return (name && name[0] != '\0') ? BLI_findstring(&ob->defbase, name, offsetof(bDeformGroup, name)) : NULL;
+ return (name && name[0] != '\0') ?
+ BLI_findstring(&ob->defbase, name, offsetof(bDeformGroup, name)) :
+ NULL;
}
int defgroup_name_index(Object *ob, const char *name)
{
- return (name && name[0] != '\0') ? BLI_findstringindex(&ob->defbase, name, offsetof(bDeformGroup, name)) : -1;
+ return (name && name[0] != '\0') ?
+ BLI_findstringindex(&ob->defbase, name, offsetof(bDeformGroup, name)) :
+ -1;
}
/**
@@ -484,40 +496,40 @@ int defgroup_name_index(Object *ob, const char *name)
*/
int *defgroup_flip_map(Object *ob, int *flip_map_len, const bool use_default)
{
- int defbase_tot = *flip_map_len = BLI_listbase_count(&ob->defbase);
-
- if (defbase_tot == 0) {
- return NULL;
- }
- else {
- bDeformGroup *dg;
- char name_flip[sizeof(dg->name)];
- int i, flip_num, *map = MEM_mallocN(defbase_tot * sizeof(int), __func__);
-
- for (i = 0; i < defbase_tot; i++) {
- map[i] = -1;
- }
-
- for (dg = ob->defbase.first, i = 0; dg; dg = dg->next, i++) {
- if (map[i] == -1) { /* may be calculated previously */
-
- /* in case no valid value is found, use this */
- if (use_default)
- map[i] = i;
-
- BLI_string_flip_side_name(name_flip, dg->name, false, sizeof(name_flip));
-
- if (!STREQ(name_flip, dg->name)) {
- flip_num = defgroup_name_index(ob, name_flip);
- if (flip_num >= 0) {
- map[i] = flip_num;
- map[flip_num] = i; /* save an extra lookup */
- }
- }
- }
- }
- return map;
- }
+ int defbase_tot = *flip_map_len = BLI_listbase_count(&ob->defbase);
+
+ if (defbase_tot == 0) {
+ return NULL;
+ }
+ else {
+ bDeformGroup *dg;
+ char name_flip[sizeof(dg->name)];
+ int i, flip_num, *map = MEM_mallocN(defbase_tot * sizeof(int), __func__);
+
+ for (i = 0; i < defbase_tot; i++) {
+ map[i] = -1;
+ }
+
+ for (dg = ob->defbase.first, i = 0; dg; dg = dg->next, i++) {
+ if (map[i] == -1) { /* may be calculated previously */
+
+ /* in case no valid value is found, use this */
+ if (use_default)
+ map[i] = i;
+
+ BLI_string_flip_side_name(name_flip, dg->name, false, sizeof(name_flip));
+
+ if (!STREQ(name_flip, dg->name)) {
+ flip_num = defgroup_name_index(ob, name_flip);
+ if (flip_num >= 0) {
+ map[i] = flip_num;
+ map[flip_num] = i; /* save an extra lookup */
+ }
+ }
+ }
+ }
+ return map;
+ }
}
/**
@@ -525,87 +537,93 @@ int *defgroup_flip_map(Object *ob, int *flip_map_len, const bool use_default)
*/
int *defgroup_flip_map_single(Object *ob, int *flip_map_len, const bool use_default, int defgroup)
{
- int defbase_tot = *flip_map_len = BLI_listbase_count(&ob->defbase);
-
- if (defbase_tot == 0) {
- return NULL;
- }
- else {
- bDeformGroup *dg;
- char name_flip[sizeof(dg->name)];
- int i, flip_num, *map = MEM_mallocN(defbase_tot * sizeof(int), __func__);
-
- for (i = 0; i < defbase_tot; i++) {
- map[i] = use_default ? i : -1;
- }
-
- dg = BLI_findlink(&ob->defbase, defgroup);
-
- BLI_string_flip_side_name(name_flip, dg->name, false, sizeof(name_flip));
- if (!STREQ(name_flip, dg->name)) {
- flip_num = defgroup_name_index(ob, name_flip);
-
- if (flip_num != -1) {
- map[defgroup] = flip_num;
- map[flip_num] = defgroup;
- }
- }
-
- return map;
- }
+ int defbase_tot = *flip_map_len = BLI_listbase_count(&ob->defbase);
+
+ if (defbase_tot == 0) {
+ return NULL;
+ }
+ else {
+ bDeformGroup *dg;
+ char name_flip[sizeof(dg->name)];
+ int i, flip_num, *map = MEM_mallocN(defbase_tot * sizeof(int), __func__);
+
+ for (i = 0; i < defbase_tot; i++) {
+ map[i] = use_default ? i : -1;
+ }
+
+ dg = BLI_findlink(&ob->defbase, defgroup);
+
+ BLI_string_flip_side_name(name_flip, dg->name, false, sizeof(name_flip));
+ if (!STREQ(name_flip, dg->name)) {
+ flip_num = defgroup_name_index(ob, name_flip);
+
+ if (flip_num != -1) {
+ map[defgroup] = flip_num;
+ map[flip_num] = defgroup;
+ }
+ }
+
+ return map;
+ }
}
int defgroup_flip_index(Object *ob, int index, const bool use_default)
{
- bDeformGroup *dg = BLI_findlink(&ob->defbase, index);
- int flip_index = -1;
+ bDeformGroup *dg = BLI_findlink(&ob->defbase, index);
+ int flip_index = -1;
- if (dg) {
- char name_flip[sizeof(dg->name)];
- BLI_string_flip_side_name(name_flip, dg->name, false, sizeof(name_flip));
+ if (dg) {
+ char name_flip[sizeof(dg->name)];
+ BLI_string_flip_side_name(name_flip, dg->name, false, sizeof(name_flip));
- if (!STREQ(name_flip, dg->name)) {
- flip_index = defgroup_name_index(ob, name_flip);
- }
- }
+ if (!STREQ(name_flip, dg->name)) {
+ flip_index = defgroup_name_index(ob, name_flip);
+ }
+ }
- return (flip_index == -1 && use_default) ? index : flip_index;
+ return (flip_index == -1 && use_default) ? index : flip_index;
}
static bool defgroup_find_name_dupe(const char *name, bDeformGroup *dg, Object *ob)
{
- bDeformGroup *curdef;
+ bDeformGroup *curdef;
- for (curdef = ob->defbase.first; curdef; curdef = curdef->next) {
- if (dg != curdef) {
- if (STREQ(curdef->name, name)) {
- return true;
- }
- }
- }
+ for (curdef = ob->defbase.first; curdef; curdef = curdef->next) {
+ if (dg != curdef) {
+ if (STREQ(curdef->name, name)) {
+ return true;
+ }
+ }
+ }
- return false;
+ return false;
}
static bool defgroup_unique_check(void *arg, const char *name)
{
- struct {Object *ob; void *dg; } *data = arg;
- return defgroup_find_name_dupe(name, data->dg, data->ob);
+ struct {
+ Object *ob;
+ void *dg;
+ } *data = arg;
+ return defgroup_find_name_dupe(name, data->dg, data->ob);
}
void defgroup_unique_name(bDeformGroup *dg, Object *ob)
{
- struct {Object *ob; void *dg; } data;
- data.ob = ob;
- data.dg = dg;
-
- BLI_uniquename_cb(defgroup_unique_check, &data, DATA_("Group"), '.', dg->name, sizeof(dg->name));
+ struct {
+ Object *ob;
+ void *dg;
+ } data;
+ data.ob = ob;
+ data.dg = dg;
+
+ BLI_uniquename_cb(defgroup_unique_check, &data, DATA_("Group"), '.', dg->name, sizeof(dg->name));
}
float defvert_find_weight(const struct MDeformVert *dvert, const int defgroup)
{
- MDeformWeight *dw = defvert_find_index(dvert, defgroup);
- return dw ? dw->weight : 0.0f;
+ MDeformWeight *dw = defvert_find_index(dvert, defgroup);
+ return dw ? dw->weight : 0.0f;
}
/**
@@ -615,41 +633,42 @@ float defvert_find_weight(const struct MDeformVert *dvert, const int defgroup)
*
* This is a bit confusing, just saves some checks from the caller.
*/
-float defvert_array_find_weight_safe(const struct MDeformVert *dvert, const int index, const int defgroup)
+float defvert_array_find_weight_safe(const struct MDeformVert *dvert,
+ const int index,
+ const int defgroup)
{
- /* Invalid defgroup index means the vgroup selected is invalid, does not exist, in that case it is OK to return 1.0
- * (i.e. maximum weight, as if no vgroup was selected).
- * But in case of valid defgroup and NULL dvert data pointer, it means that vgroup **is** valid,
- * and just totally empty, so we shall return '0.0' value then!
- */
- if (defgroup == -1) {
- return 1.0f;
- }
- else if (dvert == NULL) {
- return 0.0f;
- }
-
- return defvert_find_weight(dvert + index, defgroup);
+ /* Invalid defgroup index means the vgroup selected is invalid, does not exist, in that case it is OK to return 1.0
+ * (i.e. maximum weight, as if no vgroup was selected).
+ * But in case of valid defgroup and NULL dvert data pointer, it means that vgroup **is** valid,
+ * and just totally empty, so we shall return '0.0' value then!
+ */
+ if (defgroup == -1) {
+ return 1.0f;
+ }
+ else if (dvert == NULL) {
+ return 0.0f;
+ }
+
+ return defvert_find_weight(dvert + index, defgroup);
}
-
MDeformWeight *defvert_find_index(const MDeformVert *dvert, const int defgroup)
{
- if (dvert && defgroup >= 0) {
- MDeformWeight *dw = dvert->dw;
- unsigned int i;
-
- for (i = dvert->totweight; i != 0; i--, dw++) {
- if (dw->def_nr == defgroup) {
- return dw;
- }
- }
- }
- else {
- BLI_assert(0);
- }
-
- return NULL;
+ if (dvert && defgroup >= 0) {
+ MDeformWeight *dw = dvert->dw;
+ unsigned int i;
+
+ for (i = dvert->totweight; i != 0; i--, dw++) {
+ if (dw->def_nr == defgroup) {
+ return dw;
+ }
+ }
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ return NULL;
}
/**
@@ -659,32 +678,32 @@ MDeformWeight *defvert_find_index(const MDeformVert *dvert, const int defgroup)
*/
MDeformWeight *defvert_verify_index(MDeformVert *dvert, const int defgroup)
{
- MDeformWeight *dw_new;
-
- /* do this check always, this function is used to check for it */
- if (!dvert || defgroup < 0) {
- BLI_assert(0);
- return NULL;
- }
-
- dw_new = defvert_find_index(dvert, defgroup);
- if (dw_new)
- return dw_new;
-
- dw_new = MEM_mallocN(sizeof(MDeformWeight) * (dvert->totweight + 1), "deformWeight");
- if (dvert->dw) {
- memcpy(dw_new, dvert->dw, sizeof(MDeformWeight) * dvert->totweight);
- MEM_freeN(dvert->dw);
- }
- dvert->dw = dw_new;
- dw_new += dvert->totweight;
- dw_new->weight = 0.0f;
- dw_new->def_nr = defgroup;
- /* Group index */
-
- dvert->totweight++;
-
- return dw_new;
+ MDeformWeight *dw_new;
+
+ /* do this check always, this function is used to check for it */
+ if (!dvert || defgroup < 0) {
+ BLI_assert(0);
+ return NULL;
+ }
+
+ dw_new = defvert_find_index(dvert, defgroup);
+ if (dw_new)
+ return dw_new;
+
+ dw_new = MEM_mallocN(sizeof(MDeformWeight) * (dvert->totweight + 1), "deformWeight");
+ if (dvert->dw) {
+ memcpy(dw_new, dvert->dw, sizeof(MDeformWeight) * dvert->totweight);
+ MEM_freeN(dvert->dw);
+ }
+ dvert->dw = dw_new;
+ dw_new += dvert->totweight;
+ dw_new->weight = 0.0f;
+ dw_new->def_nr = defgroup;
+ /* Group index */
+
+ dvert->totweight++;
+
+ return dw_new;
}
/* TODO. merge with code above! */
@@ -696,27 +715,27 @@ MDeformWeight *defvert_verify_index(MDeformVert *dvert, const int defgroup)
*/
void defvert_add_index_notest(MDeformVert *dvert, int defgroup, const float weight)
{
- MDeformWeight *dw_new;
-
- /* do this check always, this function is used to check for it */
- if (!dvert || defgroup < 0) {
- BLI_assert(0);
- return;
- }
-
- dw_new = MEM_callocN(sizeof(MDeformWeight) * (dvert->totweight + 1), "defvert_add_to group, new deformWeight");
- if (dvert->dw) {
- memcpy(dw_new, dvert->dw, sizeof(MDeformWeight) * dvert->totweight);
- MEM_freeN(dvert->dw);
- }
- dvert->dw = dw_new;
- dw_new += dvert->totweight;
- dw_new->weight = weight;
- dw_new->def_nr = defgroup;
- dvert->totweight++;
+ MDeformWeight *dw_new;
+
+ /* do this check always, this function is used to check for it */
+ if (!dvert || defgroup < 0) {
+ BLI_assert(0);
+ return;
+ }
+
+ dw_new = MEM_callocN(sizeof(MDeformWeight) * (dvert->totweight + 1),
+ "defvert_add_to group, new deformWeight");
+ if (dvert->dw) {
+ memcpy(dw_new, dvert->dw, sizeof(MDeformWeight) * dvert->totweight);
+ MEM_freeN(dvert->dw);
+ }
+ dvert->dw = dw_new;
+ dw_new += dvert->totweight;
+ dw_new->weight = weight;
+ dw_new->def_nr = defgroup;
+ dvert->totweight++;
}
-
/**
* Removes the given vertex from the vertex group.
*
@@ -724,43 +743,43 @@ void defvert_add_index_notest(MDeformVert *dvert, int defgroup, const float weig
*/
void defvert_remove_group(MDeformVert *dvert, MDeformWeight *dw)
{
- if (dvert && dw) {
- int i = dw - dvert->dw;
-
- /* Security check! */
- if (i < 0 || i >= dvert->totweight) {
- return;
- }
-
- dvert->totweight--;
- /* If there are still other deform weights attached to this vert then remove
- * this deform weight, and reshuffle the others.
- */
- if (dvert->totweight) {
- BLI_assert(dvert->dw != NULL);
-
- if (i != dvert->totweight) {
- dvert->dw[i] = dvert->dw[dvert->totweight];
- }
-
- dvert->dw = MEM_reallocN(dvert->dw, sizeof(MDeformWeight) * dvert->totweight);
- }
- else {
- /* If there are no other deform weights left then just remove this one. */
- MEM_freeN(dvert->dw);
- dvert->dw = NULL;
- }
- }
+ if (dvert && dw) {
+ int i = dw - dvert->dw;
+
+ /* Security check! */
+ if (i < 0 || i >= dvert->totweight) {
+ return;
+ }
+
+ dvert->totweight--;
+ /* If there are still other deform weights attached to this vert then remove
+ * this deform weight, and reshuffle the others.
+ */
+ if (dvert->totweight) {
+ BLI_assert(dvert->dw != NULL);
+
+ if (i != dvert->totweight) {
+ dvert->dw[i] = dvert->dw[dvert->totweight];
+ }
+
+ dvert->dw = MEM_reallocN(dvert->dw, sizeof(MDeformWeight) * dvert->totweight);
+ }
+ else {
+ /* If there are no other deform weights left then just remove this one. */
+ MEM_freeN(dvert->dw);
+ dvert->dw = NULL;
+ }
+ }
}
void defvert_clear(MDeformVert *dvert)
{
- if (dvert->dw) {
- MEM_freeN(dvert->dw);
- dvert->dw = NULL;
- }
+ if (dvert->dw) {
+ MEM_freeN(dvert->dw);
+ dvert->dw = NULL;
+ }
- dvert->totweight = 0;
+ dvert->totweight = 0;
}
/**
@@ -769,18 +788,18 @@ void defvert_clear(MDeformVert *dvert)
*/
int defvert_find_shared(const MDeformVert *dvert_a, const MDeformVert *dvert_b)
{
- if (dvert_a->totweight && dvert_b->totweight) {
- MDeformWeight *dw = dvert_a->dw;
- unsigned int i;
-
- for (i = dvert_a->totweight; i != 0; i--, dw++) {
- if (dw->weight > 0.0f && defvert_find_weight(dvert_b, dw->def_nr) > 0.0f) {
- return dw->def_nr;
- }
- }
- }
-
- return -1;
+ if (dvert_a->totweight && dvert_b->totweight) {
+ MDeformWeight *dw = dvert_a->dw;
+ unsigned int i;
+
+ for (i = dvert_a->totweight; i != 0; i--, dw++) {
+ if (dw->weight > 0.0f && defvert_find_weight(dvert_b, dw->def_nr) > 0.0f) {
+ return dw->def_nr;
+ }
+ }
+ }
+
+ return -1;
}
/**
@@ -788,20 +807,19 @@ int defvert_find_shared(const MDeformVert *dvert_a, const MDeformVert *dvert_b)
*/
bool defvert_is_weight_zero(const struct MDeformVert *dvert, const int defgroup_tot)
{
- MDeformWeight *dw = dvert->dw;
- unsigned int i;
- for (i = dvert->totweight; i != 0; i--, dw++) {
- if (dw->weight != 0.0f) {
- /* check the group is in-range, happens on rare situations */
- if (LIKELY(dw->def_nr < defgroup_tot)) {
- return false;
- }
- }
- }
- return true;
+ MDeformWeight *dw = dvert->dw;
+ unsigned int i;
+ for (i = dvert->totweight; i != 0; i--, dw++) {
+ if (dw->weight != 0.0f) {
+ /* check the group is in-range, happens on rare situations */
+ if (LIKELY(dw->def_nr < defgroup_tot)) {
+ return false;
+ }
+ }
+ }
+ return true;
}
-
/**
* \return The representative weight of a multipaint group, used for
* viewport colors and actual painting.
@@ -810,480 +828,570 @@ bool defvert_is_weight_zero(const struct MDeformVert *dvert, const int defgroup_
* Value is not clamped, since painting relies on multiplication being always
* commutative with the collective weight function.
*/
-float BKE_defvert_multipaint_collective_weight(
- const struct MDeformVert *dv, int defbase_tot,
- const bool *defbase_sel, int defbase_tot_sel, bool do_autonormalize)
+float BKE_defvert_multipaint_collective_weight(const struct MDeformVert *dv,
+ int defbase_tot,
+ const bool *defbase_sel,
+ int defbase_tot_sel,
+ bool do_autonormalize)
{
- int i;
- float total = 0.0f;
- const MDeformWeight *dw = dv->dw;
-
- for (i = dv->totweight; i != 0; i--, dw++) {
- /* in multipaint, get the average if auto normalize is inactive
- * get the sum if it is active */
- if (dw->def_nr < defbase_tot) {
- if (defbase_sel[dw->def_nr]) {
- total += dw->weight;
- }
- }
- }
-
- if (do_autonormalize == false) {
- total /= defbase_tot_sel;
- }
-
- return total;
+ int i;
+ float total = 0.0f;
+ const MDeformWeight *dw = dv->dw;
+
+ for (i = dv->totweight; i != 0; i--, dw++) {
+ /* in multipaint, get the average if auto normalize is inactive
+ * get the sum if it is active */
+ if (dw->def_nr < defbase_tot) {
+ if (defbase_sel[dw->def_nr]) {
+ total += dw->weight;
+ }
+ }
+ }
+
+ if (do_autonormalize == false) {
+ total /= defbase_tot_sel;
+ }
+
+ return total;
}
-
/* -------------------------------------------------------------------- */
/** \name Defvert Array functions
* \{ */
void BKE_defvert_array_copy(MDeformVert *dst, const MDeformVert *src, int copycount)
{
- /* Assumes dst is already set up */
- int i;
+ /* Assumes dst is already set up */
+ int i;
- if (!src || !dst)
- return;
+ if (!src || !dst)
+ return;
- memcpy(dst, src, copycount * sizeof(MDeformVert));
-
- for (i = 0; i < copycount; i++) {
- if (src[i].dw) {
- dst[i].dw = MEM_mallocN(sizeof(MDeformWeight) * src[i].totweight, "copy_deformWeight");
- memcpy(dst[i].dw, src[i].dw, sizeof(MDeformWeight) * src[i].totweight);
- }
- }
+ memcpy(dst, src, copycount * sizeof(MDeformVert));
+ for (i = 0; i < copycount; i++) {
+ if (src[i].dw) {
+ dst[i].dw = MEM_mallocN(sizeof(MDeformWeight) * src[i].totweight, "copy_deformWeight");
+ memcpy(dst[i].dw, src[i].dw, sizeof(MDeformWeight) * src[i].totweight);
+ }
+ }
}
void BKE_defvert_array_free_elems(MDeformVert *dvert, int totvert)
{
- /* Instead of freeing the verts directly,
- * call this function to delete any special
- * vert data */
- int i;
-
- if (!dvert)
- return;
-
- /* Free any special data from the verts */
- for (i = 0; i < totvert; i++) {
- if (dvert[i].dw) MEM_freeN(dvert[i].dw);
- }
+ /* Instead of freeing the verts directly,
+ * call this function to delete any special
+ * vert data */
+ int i;
+
+ if (!dvert)
+ return;
+
+ /* Free any special data from the verts */
+ for (i = 0; i < totvert; i++) {
+ if (dvert[i].dw)
+ MEM_freeN(dvert[i].dw);
+ }
}
void BKE_defvert_array_free(MDeformVert *dvert, int totvert)
{
- /* Instead of freeing the verts directly,
- * call this function to delete any special
- * vert data */
- if (!dvert)
- return;
+ /* Instead of freeing the verts directly,
+ * call this function to delete any special
+ * vert data */
+ if (!dvert)
+ return;
- /* Free any special data from the verts */
- BKE_defvert_array_free_elems(dvert, totvert);
+ /* Free any special data from the verts */
+ BKE_defvert_array_free_elems(dvert, totvert);
- MEM_freeN(dvert);
+ MEM_freeN(dvert);
}
-void BKE_defvert_extract_vgroup_to_vertweights(
- MDeformVert *dvert, const int defgroup, const int num_verts, float *r_weights, const bool invert_vgroup)
+void BKE_defvert_extract_vgroup_to_vertweights(MDeformVert *dvert,
+ const int defgroup,
+ const int num_verts,
+ float *r_weights,
+ const bool invert_vgroup)
{
- if (dvert && defgroup != -1) {
- int i = num_verts;
-
- while (i--) {
- const float w = defvert_find_weight(&dvert[i], defgroup);
- r_weights[i] = invert_vgroup ? (1.0f - w) : w;
- }
- }
- else {
- copy_vn_fl(r_weights, num_verts, invert_vgroup ? 1.0f : 0.0f);
- }
+ if (dvert && defgroup != -1) {
+ int i = num_verts;
+
+ while (i--) {
+ const float w = defvert_find_weight(&dvert[i], defgroup);
+ r_weights[i] = invert_vgroup ? (1.0f - w) : w;
+ }
+ }
+ else {
+ copy_vn_fl(r_weights, num_verts, invert_vgroup ? 1.0f : 0.0f);
+ }
}
/**
* The following three make basic interpolation,
* using temp vert_weights array to avoid looking up same weight several times.
*/
-void BKE_defvert_extract_vgroup_to_edgeweights(
- MDeformVert *dvert, const int defgroup, const int num_verts, MEdge *edges, const int num_edges,
- float *r_weights, const bool invert_vgroup)
+void BKE_defvert_extract_vgroup_to_edgeweights(MDeformVert *dvert,
+ const int defgroup,
+ const int num_verts,
+ MEdge *edges,
+ const int num_edges,
+ float *r_weights,
+ const bool invert_vgroup)
{
- if (dvert && defgroup != -1) {
- int i = num_edges;
- float *tmp_weights = MEM_mallocN(sizeof(*tmp_weights) * (size_t)num_verts, __func__);
+ if (dvert && defgroup != -1) {
+ int i = num_edges;
+ float *tmp_weights = MEM_mallocN(sizeof(*tmp_weights) * (size_t)num_verts, __func__);
- BKE_defvert_extract_vgroup_to_vertweights(dvert, defgroup, num_verts, tmp_weights, invert_vgroup);
+ BKE_defvert_extract_vgroup_to_vertweights(
+ dvert, defgroup, num_verts, tmp_weights, invert_vgroup);
- while (i--) {
- MEdge *me = &edges[i];
+ while (i--) {
+ MEdge *me = &edges[i];
- r_weights[i] = (tmp_weights[me->v1] + tmp_weights[me->v2]) * 0.5f;
- }
+ r_weights[i] = (tmp_weights[me->v1] + tmp_weights[me->v2]) * 0.5f;
+ }
- MEM_freeN(tmp_weights);
- }
- else {
- copy_vn_fl(r_weights, num_edges, 0.0f);
- }
+ MEM_freeN(tmp_weights);
+ }
+ else {
+ copy_vn_fl(r_weights, num_edges, 0.0f);
+ }
}
-void BKE_defvert_extract_vgroup_to_loopweights(
- MDeformVert *dvert, const int defgroup, const int num_verts, MLoop *loops, const int num_loops,
- float *r_weights, const bool invert_vgroup)
+void BKE_defvert_extract_vgroup_to_loopweights(MDeformVert *dvert,
+ const int defgroup,
+ const int num_verts,
+ MLoop *loops,
+ const int num_loops,
+ float *r_weights,
+ const bool invert_vgroup)
{
- if (dvert && defgroup != -1) {
- int i = num_loops;
- float *tmp_weights = MEM_mallocN(sizeof(*tmp_weights) * (size_t)num_verts, __func__);
+ if (dvert && defgroup != -1) {
+ int i = num_loops;
+ float *tmp_weights = MEM_mallocN(sizeof(*tmp_weights) * (size_t)num_verts, __func__);
- BKE_defvert_extract_vgroup_to_vertweights(dvert, defgroup, num_verts, tmp_weights, invert_vgroup);
+ BKE_defvert_extract_vgroup_to_vertweights(
+ dvert, defgroup, num_verts, tmp_weights, invert_vgroup);
- while (i--) {
- MLoop *ml = &loops[i];
+ while (i--) {
+ MLoop *ml = &loops[i];
- r_weights[i] = tmp_weights[ml->v];
- }
+ r_weights[i] = tmp_weights[ml->v];
+ }
- MEM_freeN(tmp_weights);
- }
- else {
- copy_vn_fl(r_weights, num_loops, 0.0f);
- }
+ MEM_freeN(tmp_weights);
+ }
+ else {
+ copy_vn_fl(r_weights, num_loops, 0.0f);
+ }
}
-void BKE_defvert_extract_vgroup_to_polyweights(
- MDeformVert *dvert, const int defgroup, const int num_verts, MLoop *loops, const int UNUSED(num_loops),
- MPoly *polys, const int num_polys, float *r_weights, const bool invert_vgroup)
+void BKE_defvert_extract_vgroup_to_polyweights(MDeformVert *dvert,
+ const int defgroup,
+ const int num_verts,
+ MLoop *loops,
+ const int UNUSED(num_loops),
+ MPoly *polys,
+ const int num_polys,
+ float *r_weights,
+ const bool invert_vgroup)
{
- if (dvert && defgroup != -1) {
- int i = num_polys;
- float *tmp_weights = MEM_mallocN(sizeof(*tmp_weights) * (size_t)num_verts, __func__);
-
- BKE_defvert_extract_vgroup_to_vertweights(dvert, defgroup, num_verts, tmp_weights, invert_vgroup);
-
- while (i--) {
- MPoly *mp = &polys[i];
- MLoop *ml = &loops[mp->loopstart];
- int j = mp->totloop;
- float w = 0.0f;
-
- for (; j--; ml++) {
- w += tmp_weights[ml->v];
- }
- r_weights[i] = w / (float)mp->totloop;
- }
-
- MEM_freeN(tmp_weights);
- }
- else {
- copy_vn_fl(r_weights, num_polys, 0.0f);
- }
+ if (dvert && defgroup != -1) {
+ int i = num_polys;
+ float *tmp_weights = MEM_mallocN(sizeof(*tmp_weights) * (size_t)num_verts, __func__);
+
+ BKE_defvert_extract_vgroup_to_vertweights(
+ dvert, defgroup, num_verts, tmp_weights, invert_vgroup);
+
+ while (i--) {
+ MPoly *mp = &polys[i];
+ MLoop *ml = &loops[mp->loopstart];
+ int j = mp->totloop;
+ float w = 0.0f;
+
+ for (; j--; ml++) {
+ w += tmp_weights[ml->v];
+ }
+ r_weights[i] = w / (float)mp->totloop;
+ }
+
+ MEM_freeN(tmp_weights);
+ }
+ else {
+ copy_vn_fl(r_weights, num_polys, 0.0f);
+ }
}
/** \} */
-
/* -------------------------------------------------------------------- */
/** \name Data Transfer
* \{ */
-static void vgroups_datatransfer_interp(
- const CustomDataTransferLayerMap *laymap, void *dest,
- const void **sources, const float *weights, const int count, const float mix_factor)
+static void vgroups_datatransfer_interp(const CustomDataTransferLayerMap *laymap,
+ void *dest,
+ const void **sources,
+ const float *weights,
+ const int count,
+ const float mix_factor)
{
- MDeformVert **data_src = (MDeformVert **)sources;
- MDeformVert *data_dst = (MDeformVert *)dest;
- const int idx_src = laymap->data_src_n;
- const int idx_dst = laymap->data_dst_n;
-
- const int mix_mode = laymap->mix_mode;
-
- int i, j;
-
- MDeformWeight *dw_src;
- MDeformWeight *dw_dst = defvert_find_index(data_dst, idx_dst);
- float weight_src = 0.0f, weight_dst = 0.0f;
-
- if (sources) {
- for (i = count; i--;) {
- for (j = data_src[i]->totweight; j--;) {
- if ((dw_src = &data_src[i]->dw[j])->def_nr == idx_src) {
- weight_src += dw_src->weight * weights[i];
- break;
- }
- }
- }
- }
-
- if (dw_dst) {
- weight_dst = dw_dst->weight;
- }
- else if (mix_mode == CDT_MIX_REPLACE_ABOVE_THRESHOLD) {
- return; /* Do not affect destination. */
- }
-
- weight_src = data_transfer_interp_float_do(mix_mode, weight_dst, weight_src, mix_factor);
-
- CLAMP(weight_src, 0.0f, 1.0f);
-
- if (!dw_dst) {
- defvert_add_index_notest(data_dst, idx_dst, weight_src);
- }
- else {
- dw_dst->weight = weight_src;
- }
+ MDeformVert **data_src = (MDeformVert **)sources;
+ MDeformVert *data_dst = (MDeformVert *)dest;
+ const int idx_src = laymap->data_src_n;
+ const int idx_dst = laymap->data_dst_n;
+
+ const int mix_mode = laymap->mix_mode;
+
+ int i, j;
+
+ MDeformWeight *dw_src;
+ MDeformWeight *dw_dst = defvert_find_index(data_dst, idx_dst);
+ float weight_src = 0.0f, weight_dst = 0.0f;
+
+ if (sources) {
+ for (i = count; i--;) {
+ for (j = data_src[i]->totweight; j--;) {
+ if ((dw_src = &data_src[i]->dw[j])->def_nr == idx_src) {
+ weight_src += dw_src->weight * weights[i];
+ break;
+ }
+ }
+ }
+ }
+
+ if (dw_dst) {
+ weight_dst = dw_dst->weight;
+ }
+ else if (mix_mode == CDT_MIX_REPLACE_ABOVE_THRESHOLD) {
+ return; /* Do not affect destination. */
+ }
+
+ weight_src = data_transfer_interp_float_do(mix_mode, weight_dst, weight_src, mix_factor);
+
+ CLAMP(weight_src, 0.0f, 1.0f);
+
+ if (!dw_dst) {
+ defvert_add_index_notest(data_dst, idx_dst, weight_src);
+ }
+ else {
+ dw_dst->weight = weight_src;
+ }
}
-static bool data_transfer_layersmapping_vgroups_multisrc_to_dst(
- ListBase *r_map, const int mix_mode, const float mix_factor, const float *mix_weights,
- const int num_elem_dst, const bool use_create, const bool use_delete,
- Object *ob_src, Object *ob_dst, MDeformVert *data_src, MDeformVert *data_dst,
- CustomData *UNUSED(cd_src), CustomData *cd_dst, const bool UNUSED(use_dupref_dst),
- const int tolayers, bool *use_layers_src, const int num_layers_src)
+static bool data_transfer_layersmapping_vgroups_multisrc_to_dst(ListBase *r_map,
+ const int mix_mode,
+ const float mix_factor,
+ const float *mix_weights,
+ const int num_elem_dst,
+ const bool use_create,
+ const bool use_delete,
+ Object *ob_src,
+ Object *ob_dst,
+ MDeformVert *data_src,
+ MDeformVert *data_dst,
+ CustomData *UNUSED(cd_src),
+ CustomData *cd_dst,
+ const bool UNUSED(use_dupref_dst),
+ const int tolayers,
+ bool *use_layers_src,
+ const int num_layers_src)
{
- int idx_src;
- int idx_dst;
- int tot_dst = BLI_listbase_count(&ob_dst->defbase);
-
- const size_t elem_size = sizeof(*((MDeformVert *)NULL));
-
- switch (tolayers) {
- case DT_LAYERS_INDEX_DST:
- idx_dst = tot_dst;
-
- /* Find last source actually used! */
- idx_src = num_layers_src;
- while (idx_src-- && !use_layers_src[idx_src]);
- idx_src++;
-
- if (idx_dst < idx_src) {
- if (use_create) {
- /* Create as much vgroups as necessary! */
- for (; idx_dst < idx_src; idx_dst++) {
- BKE_object_defgroup_add(ob_dst);
- }
- }
- else {
- /* Otherwise, just try to map what we can with existing dst vgroups. */
- idx_src = idx_dst;
- }
- }
- else if (use_delete && idx_dst > idx_src) {
- while (idx_dst-- > idx_src) {
- BKE_object_defgroup_remove(ob_dst, ob_dst->defbase.last);
- }
- }
- if (r_map) {
- /* At this stage, we **need** a valid CD_MDEFORMVERT layer on dest!
- * Again, use_create is not relevant in this case */
- if (!data_dst) {
- data_dst = CustomData_add_layer(cd_dst, CD_MDEFORMVERT, CD_CALLOC, NULL, num_elem_dst);
- }
-
- while (idx_src--) {
- if (!use_layers_src[idx_src]) {
- continue;
- }
- data_transfer_layersmapping_add_item(r_map, CD_FAKE_MDEFORMVERT, mix_mode, mix_factor, mix_weights,
- data_src, data_dst, idx_src, idx_src,
- elem_size, 0, 0, 0, vgroups_datatransfer_interp, NULL);
- }
- }
- break;
- case DT_LAYERS_NAME_DST:
- {
- bDeformGroup *dg_src, *dg_dst;
-
- if (use_delete) {
- /* Remove all unused dst vgroups first, simpler in this case. */
- for (dg_dst = ob_dst->defbase.first; dg_dst;) {
- bDeformGroup *dg_dst_next = dg_dst->next;
-
- if (defgroup_name_index(ob_src, dg_dst->name) == -1) {
- BKE_object_defgroup_remove(ob_dst, dg_dst);
- }
- dg_dst = dg_dst_next;
- }
- }
-
- for (idx_src = 0, dg_src = ob_src->defbase.first;
- idx_src < num_layers_src;
- idx_src++, dg_src = dg_src->next)
- {
- if (!use_layers_src[idx_src]) {
- continue;
- }
-
- if ((idx_dst = defgroup_name_index(ob_dst, dg_src->name)) == -1) {
- if (use_create) {
- BKE_object_defgroup_add_name(ob_dst, dg_src->name);
- idx_dst = ob_dst->actdef - 1;
- }
- else {
- /* If we are not allowed to create missing dst vgroups, just skip matching src one. */
- continue;
- }
- }
- if (r_map) {
- /* At this stage, we **need** a valid CD_MDEFORMVERT layer on dest!
- * use_create is not relevant in this case */
- if (!data_dst) {
- data_dst = CustomData_add_layer(cd_dst, CD_MDEFORMVERT, CD_CALLOC, NULL, num_elem_dst);
- }
-
- data_transfer_layersmapping_add_item(
- r_map, CD_FAKE_MDEFORMVERT, mix_mode, mix_factor, mix_weights,
- data_src, data_dst, idx_src, idx_dst,
- elem_size, 0, 0, 0, vgroups_datatransfer_interp, NULL);
- }
- }
- break;
- }
- default:
- return false;
- }
-
- return true;
+ int idx_src;
+ int idx_dst;
+ int tot_dst = BLI_listbase_count(&ob_dst->defbase);
+
+ const size_t elem_size = sizeof(*((MDeformVert *)NULL));
+
+ switch (tolayers) {
+ case DT_LAYERS_INDEX_DST:
+ idx_dst = tot_dst;
+
+ /* Find last source actually used! */
+ idx_src = num_layers_src;
+ while (idx_src-- && !use_layers_src[idx_src])
+ ;
+ idx_src++;
+
+ if (idx_dst < idx_src) {
+ if (use_create) {
+ /* Create as much vgroups as necessary! */
+ for (; idx_dst < idx_src; idx_dst++) {
+ BKE_object_defgroup_add(ob_dst);
+ }
+ }
+ else {
+ /* Otherwise, just try to map what we can with existing dst vgroups. */
+ idx_src = idx_dst;
+ }
+ }
+ else if (use_delete && idx_dst > idx_src) {
+ while (idx_dst-- > idx_src) {
+ BKE_object_defgroup_remove(ob_dst, ob_dst->defbase.last);
+ }
+ }
+ if (r_map) {
+ /* At this stage, we **need** a valid CD_MDEFORMVERT layer on dest!
+ * Again, use_create is not relevant in this case */
+ if (!data_dst) {
+ data_dst = CustomData_add_layer(cd_dst, CD_MDEFORMVERT, CD_CALLOC, NULL, num_elem_dst);
+ }
+
+ while (idx_src--) {
+ if (!use_layers_src[idx_src]) {
+ continue;
+ }
+ data_transfer_layersmapping_add_item(r_map,
+ CD_FAKE_MDEFORMVERT,
+ mix_mode,
+ mix_factor,
+ mix_weights,
+ data_src,
+ data_dst,
+ idx_src,
+ idx_src,
+ elem_size,
+ 0,
+ 0,
+ 0,
+ vgroups_datatransfer_interp,
+ NULL);
+ }
+ }
+ break;
+ case DT_LAYERS_NAME_DST: {
+ bDeformGroup *dg_src, *dg_dst;
+
+ if (use_delete) {
+ /* Remove all unused dst vgroups first, simpler in this case. */
+ for (dg_dst = ob_dst->defbase.first; dg_dst;) {
+ bDeformGroup *dg_dst_next = dg_dst->next;
+
+ if (defgroup_name_index(ob_src, dg_dst->name) == -1) {
+ BKE_object_defgroup_remove(ob_dst, dg_dst);
+ }
+ dg_dst = dg_dst_next;
+ }
+ }
+
+ for (idx_src = 0, dg_src = ob_src->defbase.first; idx_src < num_layers_src;
+ idx_src++, dg_src = dg_src->next) {
+ if (!use_layers_src[idx_src]) {
+ continue;
+ }
+
+ if ((idx_dst = defgroup_name_index(ob_dst, dg_src->name)) == -1) {
+ if (use_create) {
+ BKE_object_defgroup_add_name(ob_dst, dg_src->name);
+ idx_dst = ob_dst->actdef - 1;
+ }
+ else {
+ /* If we are not allowed to create missing dst vgroups, just skip matching src one. */
+ continue;
+ }
+ }
+ if (r_map) {
+ /* At this stage, we **need** a valid CD_MDEFORMVERT layer on dest!
+ * use_create is not relevant in this case */
+ if (!data_dst) {
+ data_dst = CustomData_add_layer(cd_dst, CD_MDEFORMVERT, CD_CALLOC, NULL, num_elem_dst);
+ }
+
+ data_transfer_layersmapping_add_item(r_map,
+ CD_FAKE_MDEFORMVERT,
+ mix_mode,
+ mix_factor,
+ mix_weights,
+ data_src,
+ data_dst,
+ idx_src,
+ idx_dst,
+ elem_size,
+ 0,
+ 0,
+ 0,
+ vgroups_datatransfer_interp,
+ NULL);
+ }
+ }
+ break;
+ }
+ default:
+ return false;
+ }
+
+ return true;
}
-bool data_transfer_layersmapping_vgroups(
- ListBase *r_map, const int mix_mode, const float mix_factor, const float *mix_weights,
- const int num_elem_dst, const bool use_create, const bool use_delete, Object *ob_src, Object *ob_dst,
- CustomData *cd_src, CustomData *cd_dst, const bool use_dupref_dst, const int fromlayers, const int tolayers)
+bool data_transfer_layersmapping_vgroups(ListBase *r_map,
+ const int mix_mode,
+ const float mix_factor,
+ const float *mix_weights,
+ const int num_elem_dst,
+ const bool use_create,
+ const bool use_delete,
+ Object *ob_src,
+ Object *ob_dst,
+ CustomData *cd_src,
+ CustomData *cd_dst,
+ const bool use_dupref_dst,
+ const int fromlayers,
+ const int tolayers)
{
- int idx_src, idx_dst;
- MDeformVert *data_src, *data_dst = NULL;
-
- const size_t elem_size = sizeof(*((MDeformVert *)NULL));
-
- /* Note: VGroups are a bit hairy, since their layout is defined on object level (ob->defbase), while their actual
- * data is a (mesh) CD layer.
- * This implies we may have to handle data layout itself while having NULL data itself,
- * and even have to support NULL data_src in transfer data code (we always create a data_dst, though).
- */
-
- if (BLI_listbase_is_empty(&ob_src->defbase)) {
- if (use_delete) {
- BKE_object_defgroup_remove_all(ob_dst);
- }
- return true;
- }
-
- data_src = CustomData_get_layer(cd_src, CD_MDEFORMVERT);
-
- data_dst = CustomData_get_layer(cd_dst, CD_MDEFORMVERT);
- if (data_dst && use_dupref_dst && r_map) {
- /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
- data_dst = CustomData_duplicate_referenced_layer(cd_dst, CD_MDEFORMVERT, num_elem_dst);
- }
-
- if (fromlayers == DT_LAYERS_ACTIVE_SRC || fromlayers >= 0) {
- /* Note: use_delete has not much meaning in this case, ignored. */
-
- if (fromlayers >= 0) {
- idx_src = fromlayers;
- if (idx_src >= BLI_listbase_count(&ob_src->defbase)) {
- /* This can happen when vgroups are removed from source object...
- * Remapping would be really tricky here, we'd need to go over all objects in
- * Main every time we delete a vgroup... for now, simpler and safer to abort. */
- return false;
- }
- }
- else if ((idx_src = ob_src->actdef - 1) == -1) {
- return false;
- }
-
- if (tolayers >= 0) {
- /* Note: in this case we assume layer exists! */
- idx_dst = tolayers;
- BLI_assert(idx_dst < BLI_listbase_count(&ob_dst->defbase));
- }
- else if (tolayers == DT_LAYERS_ACTIVE_DST) {
- if ((idx_dst = ob_dst->actdef - 1) == -1) {
- bDeformGroup *dg_src;
- if (!use_create) {
- return true;
- }
- dg_src = BLI_findlink(&ob_src->defbase, idx_src);
- BKE_object_defgroup_add_name(ob_dst, dg_src->name);
- idx_dst = ob_dst->actdef - 1;
- }
- }
- else if (tolayers == DT_LAYERS_INDEX_DST) {
- int num = BLI_listbase_count(&ob_src->defbase);
- idx_dst = idx_src;
- if (num <= idx_dst) {
- if (!use_create) {
- return true;
- }
- /* Create as much vgroups as necessary! */
- for (; num <= idx_dst; num++) {
- BKE_object_defgroup_add(ob_dst);
- }
- }
- }
- else if (tolayers == DT_LAYERS_NAME_DST) {
- bDeformGroup *dg_src = BLI_findlink(&ob_src->defbase, idx_src);
- if ((idx_dst = defgroup_name_index(ob_dst, dg_src->name)) == -1) {
- if (!use_create) {
- return true;
- }
- BKE_object_defgroup_add_name(ob_dst, dg_src->name);
- idx_dst = ob_dst->actdef - 1;
- }
- }
- else {
- return false;
- }
-
- if (r_map) {
- /* At this stage, we **need** a valid CD_MDEFORMVERT layer on dest!
- * use_create is not relevant in this case */
- if (!data_dst) {
- data_dst = CustomData_add_layer(cd_dst, CD_MDEFORMVERT, CD_CALLOC, NULL, num_elem_dst);
- }
-
- data_transfer_layersmapping_add_item(r_map, CD_FAKE_MDEFORMVERT, mix_mode, mix_factor, mix_weights,
- data_src, data_dst, idx_src, idx_dst,
- elem_size, 0, 0, 0, vgroups_datatransfer_interp, NULL);
- }
- }
- else {
- int num_src, num_sel_unused;
- bool *use_layers_src = NULL;
- bool ret = false;
-
- switch (fromlayers) {
- case DT_LAYERS_ALL_SRC:
- use_layers_src = BKE_object_defgroup_subset_from_select_type(ob_src, WT_VGROUP_ALL,
- &num_src, &num_sel_unused);
- break;
- case DT_LAYERS_VGROUP_SRC_BONE_SELECT:
- use_layers_src = BKE_object_defgroup_subset_from_select_type(ob_src, WT_VGROUP_BONE_SELECT,
- &num_src, &num_sel_unused);
- break;
- case DT_LAYERS_VGROUP_SRC_BONE_DEFORM:
- use_layers_src = BKE_object_defgroup_subset_from_select_type(ob_src, WT_VGROUP_BONE_DEFORM,
- &num_src, &num_sel_unused);
- break;
- }
-
- if (use_layers_src) {
- ret = data_transfer_layersmapping_vgroups_multisrc_to_dst(
- r_map, mix_mode, mix_factor, mix_weights, num_elem_dst, use_create, use_delete,
- ob_src, ob_dst, data_src, data_dst, cd_src, cd_dst, use_dupref_dst,
- tolayers, use_layers_src, num_src);
- }
-
- MEM_SAFE_FREE(use_layers_src);
- return ret;
- }
-
- return true;
+ int idx_src, idx_dst;
+ MDeformVert *data_src, *data_dst = NULL;
+
+ const size_t elem_size = sizeof(*((MDeformVert *)NULL));
+
+ /* Note: VGroups are a bit hairy, since their layout is defined on object level (ob->defbase), while their actual
+ * data is a (mesh) CD layer.
+ * This implies we may have to handle data layout itself while having NULL data itself,
+ * and even have to support NULL data_src in transfer data code (we always create a data_dst, though).
+ */
+
+ if (BLI_listbase_is_empty(&ob_src->defbase)) {
+ if (use_delete) {
+ BKE_object_defgroup_remove_all(ob_dst);
+ }
+ return true;
+ }
+
+ data_src = CustomData_get_layer(cd_src, CD_MDEFORMVERT);
+
+ data_dst = CustomData_get_layer(cd_dst, CD_MDEFORMVERT);
+ if (data_dst && use_dupref_dst && r_map) {
+ /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
+ data_dst = CustomData_duplicate_referenced_layer(cd_dst, CD_MDEFORMVERT, num_elem_dst);
+ }
+
+ if (fromlayers == DT_LAYERS_ACTIVE_SRC || fromlayers >= 0) {
+ /* Note: use_delete has not much meaning in this case, ignored. */
+
+ if (fromlayers >= 0) {
+ idx_src = fromlayers;
+ if (idx_src >= BLI_listbase_count(&ob_src->defbase)) {
+ /* This can happen when vgroups are removed from source object...
+ * Remapping would be really tricky here, we'd need to go over all objects in
+ * Main every time we delete a vgroup... for now, simpler and safer to abort. */
+ return false;
+ }
+ }
+ else if ((idx_src = ob_src->actdef - 1) == -1) {
+ return false;
+ }
+
+ if (tolayers >= 0) {
+ /* Note: in this case we assume layer exists! */
+ idx_dst = tolayers;
+ BLI_assert(idx_dst < BLI_listbase_count(&ob_dst->defbase));
+ }
+ else if (tolayers == DT_LAYERS_ACTIVE_DST) {
+ if ((idx_dst = ob_dst->actdef - 1) == -1) {
+ bDeformGroup *dg_src;
+ if (!use_create) {
+ return true;
+ }
+ dg_src = BLI_findlink(&ob_src->defbase, idx_src);
+ BKE_object_defgroup_add_name(ob_dst, dg_src->name);
+ idx_dst = ob_dst->actdef - 1;
+ }
+ }
+ else if (tolayers == DT_LAYERS_INDEX_DST) {
+ int num = BLI_listbase_count(&ob_src->defbase);
+ idx_dst = idx_src;
+ if (num <= idx_dst) {
+ if (!use_create) {
+ return true;
+ }
+ /* Create as much vgroups as necessary! */
+ for (; num <= idx_dst; num++) {
+ BKE_object_defgroup_add(ob_dst);
+ }
+ }
+ }
+ else if (tolayers == DT_LAYERS_NAME_DST) {
+ bDeformGroup *dg_src = BLI_findlink(&ob_src->defbase, idx_src);
+ if ((idx_dst = defgroup_name_index(ob_dst, dg_src->name)) == -1) {
+ if (!use_create) {
+ return true;
+ }
+ BKE_object_defgroup_add_name(ob_dst, dg_src->name);
+ idx_dst = ob_dst->actdef - 1;
+ }
+ }
+ else {
+ return false;
+ }
+
+ if (r_map) {
+ /* At this stage, we **need** a valid CD_MDEFORMVERT layer on dest!
+ * use_create is not relevant in this case */
+ if (!data_dst) {
+ data_dst = CustomData_add_layer(cd_dst, CD_MDEFORMVERT, CD_CALLOC, NULL, num_elem_dst);
+ }
+
+ data_transfer_layersmapping_add_item(r_map,
+ CD_FAKE_MDEFORMVERT,
+ mix_mode,
+ mix_factor,
+ mix_weights,
+ data_src,
+ data_dst,
+ idx_src,
+ idx_dst,
+ elem_size,
+ 0,
+ 0,
+ 0,
+ vgroups_datatransfer_interp,
+ NULL);
+ }
+ }
+ else {
+ int num_src, num_sel_unused;
+ bool *use_layers_src = NULL;
+ bool ret = false;
+
+ switch (fromlayers) {
+ case DT_LAYERS_ALL_SRC:
+ use_layers_src = BKE_object_defgroup_subset_from_select_type(
+ ob_src, WT_VGROUP_ALL, &num_src, &num_sel_unused);
+ break;
+ case DT_LAYERS_VGROUP_SRC_BONE_SELECT:
+ use_layers_src = BKE_object_defgroup_subset_from_select_type(
+ ob_src, WT_VGROUP_BONE_SELECT, &num_src, &num_sel_unused);
+ break;
+ case DT_LAYERS_VGROUP_SRC_BONE_DEFORM:
+ use_layers_src = BKE_object_defgroup_subset_from_select_type(
+ ob_src, WT_VGROUP_BONE_DEFORM, &num_src, &num_sel_unused);
+ break;
+ }
+
+ if (use_layers_src) {
+ ret = data_transfer_layersmapping_vgroups_multisrc_to_dst(r_map,
+ mix_mode,
+ mix_factor,
+ mix_weights,
+ num_elem_dst,
+ use_create,
+ use_delete,
+ ob_src,
+ ob_dst,
+ data_src,
+ data_dst,
+ cd_src,
+ cd_dst,
+ use_dupref_dst,
+ tolayers,
+ use_layers_src,
+ num_src);
+ }
+
+ MEM_SAFE_FREE(use_layers_src);
+ return ret;
+ }
+
+ return true;
}
/** \} */
@@ -1294,35 +1402,35 @@ bool data_transfer_layersmapping_vgroups(
void BKE_defvert_weight_to_rgb(float r_rgb[3], const float weight)
{
- const float blend = ((weight / 2.0f) + 0.5f);
-
- if (weight <= 0.25f) { /* blue->cyan */
- r_rgb[0] = 0.0f;
- r_rgb[1] = blend * weight * 4.0f;
- r_rgb[2] = blend;
- }
- else if (weight <= 0.50f) { /* cyan->green */
- r_rgb[0] = 0.0f;
- r_rgb[1] = blend;
- r_rgb[2] = blend * (1.0f - ((weight - 0.25f) * 4.0f));
- }
- else if (weight <= 0.75f) { /* green->yellow */
- r_rgb[0] = blend * ((weight - 0.50f) * 4.0f);
- r_rgb[1] = blend;
- r_rgb[2] = 0.0f;
- }
- else if (weight <= 1.0f) { /* yellow->red */
- r_rgb[0] = blend;
- r_rgb[1] = blend * (1.0f - ((weight - 0.75f) * 4.0f));
- r_rgb[2] = 0.0f;
- }
- else {
- /* exceptional value, unclamped or nan,
- * avoid uninitialized memory use */
- r_rgb[0] = 1.0f;
- r_rgb[1] = 0.0f;
- r_rgb[2] = 1.0f;
- }
+ const float blend = ((weight / 2.0f) + 0.5f);
+
+ if (weight <= 0.25f) { /* blue->cyan */
+ r_rgb[0] = 0.0f;
+ r_rgb[1] = blend * weight * 4.0f;
+ r_rgb[2] = blend;
+ }
+ else if (weight <= 0.50f) { /* cyan->green */
+ r_rgb[0] = 0.0f;
+ r_rgb[1] = blend;
+ r_rgb[2] = blend * (1.0f - ((weight - 0.25f) * 4.0f));
+ }
+ else if (weight <= 0.75f) { /* green->yellow */
+ r_rgb[0] = blend * ((weight - 0.50f) * 4.0f);
+ r_rgb[1] = blend;
+ r_rgb[2] = 0.0f;
+ }
+ else if (weight <= 1.0f) { /* yellow->red */
+ r_rgb[0] = blend;
+ r_rgb[1] = blend * (1.0f - ((weight - 0.75f) * 4.0f));
+ r_rgb[2] = 0.0f;
+ }
+ else {
+ /* exceptional value, unclamped or nan,
+ * avoid uninitialized memory use */
+ r_rgb[0] = 1.0f;
+ r_rgb[1] = 0.0f;
+ r_rgb[2] = 1.0f;
+ }
}
/** \} */
diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c
index f0b7431d989..2794a6e36e4 100644
--- a/source/blender/blenkernel/intern/displist.c
+++ b/source/blender/blenkernel/intern/displist.c
@@ -21,7 +21,6 @@
* \ingroup bke
*/
-
#include <math.h>
#include <stdio.h>
#include <string.h>
@@ -55,7 +54,7 @@
#include "BKE_lattice.h"
#include "BKE_modifier.h"
-#include "BLI_sys_types.h" // for intptr_t support
+#include "BLI_sys_types.h" // for intptr_t support
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
@@ -64,390 +63,401 @@ static void boundbox_displist_object(Object *ob);
void BKE_displist_elem_free(DispList *dl)
{
- if (dl) {
- if (dl->verts) MEM_freeN(dl->verts);
- if (dl->nors) MEM_freeN(dl->nors);
- if (dl->index) MEM_freeN(dl->index);
- if (dl->bevel_split) MEM_freeN(dl->bevel_split);
- MEM_freeN(dl);
- }
+ if (dl) {
+ if (dl->verts)
+ MEM_freeN(dl->verts);
+ if (dl->nors)
+ MEM_freeN(dl->nors);
+ if (dl->index)
+ MEM_freeN(dl->index);
+ if (dl->bevel_split)
+ MEM_freeN(dl->bevel_split);
+ MEM_freeN(dl);
+ }
}
void BKE_displist_free(ListBase *lb)
{
- DispList *dl;
+ DispList *dl;
- while ((dl = BLI_pophead(lb))) {
- BKE_displist_elem_free(dl);
- }
+ while ((dl = BLI_pophead(lb))) {
+ BKE_displist_elem_free(dl);
+ }
}
DispList *BKE_displist_find_or_create(ListBase *lb, int type)
{
- DispList *dl;
+ DispList *dl;
- dl = lb->first;
- while (dl) {
- if (dl->type == type)
- return dl;
- dl = dl->next;
- }
+ dl = lb->first;
+ while (dl) {
+ if (dl->type == type)
+ return dl;
+ dl = dl->next;
+ }
- dl = MEM_callocN(sizeof(DispList), "find_disp");
- dl->type = type;
- BLI_addtail(lb, dl);
+ dl = MEM_callocN(sizeof(DispList), "find_disp");
+ dl->type = type;
+ BLI_addtail(lb, dl);
- return dl;
+ return dl;
}
DispList *BKE_displist_find(ListBase *lb, int type)
{
- DispList *dl;
+ DispList *dl;
- dl = lb->first;
- while (dl) {
- if (dl->type == type)
- return dl;
- dl = dl->next;
- }
+ dl = lb->first;
+ while (dl) {
+ if (dl->type == type)
+ return dl;
+ dl = dl->next;
+ }
- return NULL;
+ return NULL;
}
bool BKE_displist_has_faces(ListBase *lb)
{
- DispList *dl;
+ DispList *dl;
- for (dl = lb->first; dl; dl = dl->next) {
- if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) {
- return true;
- }
- }
+ for (dl = lb->first; dl; dl = dl->next) {
+ if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) {
+ return true;
+ }
+ }
- return false;
+ return false;
}
void BKE_displist_copy(ListBase *lbn, ListBase *lb)
{
- DispList *dln, *dl;
+ DispList *dln, *dl;
- BKE_displist_free(lbn);
+ BKE_displist_free(lbn);
- dl = lb->first;
- while (dl) {
- dln = MEM_dupallocN(dl);
- BLI_addtail(lbn, dln);
- dln->verts = MEM_dupallocN(dl->verts);
- dln->nors = MEM_dupallocN(dl->nors);
- dln->index = MEM_dupallocN(dl->index);
+ dl = lb->first;
+ while (dl) {
+ dln = MEM_dupallocN(dl);
+ BLI_addtail(lbn, dln);
+ dln->verts = MEM_dupallocN(dl->verts);
+ dln->nors = MEM_dupallocN(dl->nors);
+ dln->index = MEM_dupallocN(dl->index);
- if (dl->bevel_split) {
- dln->bevel_split = MEM_dupallocN(dl->bevel_split);
- }
+ if (dl->bevel_split) {
+ dln->bevel_split = MEM_dupallocN(dl->bevel_split);
+ }
- dl = dl->next;
- }
+ dl = dl->next;
+ }
}
void BKE_displist_normals_add(ListBase *lb)
{
- DispList *dl = NULL;
- float *vdata, *ndata, nor[3];
- float *v1, *v2, *v3, *v4;
- float *n1, *n2, *n3, *n4;
- int a, b, p1, p2, p3, p4;
-
- dl = lb->first;
-
- while (dl) {
- if (dl->type == DL_INDEX3) {
- if (dl->nors == NULL) {
- dl->nors = MEM_callocN(sizeof(float) * 3, "dlnors");
-
- if (dl->flag & DL_BACK_CURVE) {
- dl->nors[2] = -1.0f;
- }
- else {
- dl->nors[2] = 1.0f;
- }
- }
- }
- else if (dl->type == DL_SURF) {
- if (dl->nors == NULL) {
- dl->nors = MEM_callocN(sizeof(float) * 3 * dl->nr * dl->parts, "dlnors");
-
- vdata = dl->verts;
- ndata = dl->nors;
-
- for (a = 0; a < dl->parts; a++) {
-
- if (BKE_displist_surfindex_get(dl, a, &b, &p1, &p2, &p3, &p4) == 0)
- break;
-
- v1 = vdata + 3 * p1;
- n1 = ndata + 3 * p1;
- v2 = vdata + 3 * p2;
- n2 = ndata + 3 * p2;
- v3 = vdata + 3 * p3;
- n3 = ndata + 3 * p3;
- v4 = vdata + 3 * p4;
- n4 = ndata + 3 * p4;
-
- for (; b < dl->nr; b++) {
- normal_quad_v3(nor, v1, v3, v4, v2);
-
- add_v3_v3(n1, nor);
- add_v3_v3(n2, nor);
- add_v3_v3(n3, nor);
- add_v3_v3(n4, nor);
-
- v2 = v1; v1 += 3;
- v4 = v3; v3 += 3;
- n2 = n1; n1 += 3;
- n4 = n3; n3 += 3;
- }
- }
- a = dl->parts * dl->nr;
- v1 = ndata;
- while (a--) {
- normalize_v3(v1);
- v1 += 3;
- }
- }
- }
- dl = dl->next;
- }
+ DispList *dl = NULL;
+ float *vdata, *ndata, nor[3];
+ float *v1, *v2, *v3, *v4;
+ float *n1, *n2, *n3, *n4;
+ int a, b, p1, p2, p3, p4;
+
+ dl = lb->first;
+
+ while (dl) {
+ if (dl->type == DL_INDEX3) {
+ if (dl->nors == NULL) {
+ dl->nors = MEM_callocN(sizeof(float) * 3, "dlnors");
+
+ if (dl->flag & DL_BACK_CURVE) {
+ dl->nors[2] = -1.0f;
+ }
+ else {
+ dl->nors[2] = 1.0f;
+ }
+ }
+ }
+ else if (dl->type == DL_SURF) {
+ if (dl->nors == NULL) {
+ dl->nors = MEM_callocN(sizeof(float) * 3 * dl->nr * dl->parts, "dlnors");
+
+ vdata = dl->verts;
+ ndata = dl->nors;
+
+ for (a = 0; a < dl->parts; a++) {
+
+ if (BKE_displist_surfindex_get(dl, a, &b, &p1, &p2, &p3, &p4) == 0)
+ break;
+
+ v1 = vdata + 3 * p1;
+ n1 = ndata + 3 * p1;
+ v2 = vdata + 3 * p2;
+ n2 = ndata + 3 * p2;
+ v3 = vdata + 3 * p3;
+ n3 = ndata + 3 * p3;
+ v4 = vdata + 3 * p4;
+ n4 = ndata + 3 * p4;
+
+ for (; b < dl->nr; b++) {
+ normal_quad_v3(nor, v1, v3, v4, v2);
+
+ add_v3_v3(n1, nor);
+ add_v3_v3(n2, nor);
+ add_v3_v3(n3, nor);
+ add_v3_v3(n4, nor);
+
+ v2 = v1;
+ v1 += 3;
+ v4 = v3;
+ v3 += 3;
+ n2 = n1;
+ n1 += 3;
+ n4 = n3;
+ n3 += 3;
+ }
+ }
+ a = dl->parts * dl->nr;
+ v1 = ndata;
+ while (a--) {
+ normalize_v3(v1);
+ v1 += 3;
+ }
+ }
+ }
+ dl = dl->next;
+ }
}
void BKE_displist_count(ListBase *lb, int *totvert, int *totface, int *tottri)
{
- DispList *dl;
-
- for (dl = lb->first; dl; dl = dl->next) {
- int vert_tot = 0;
- int face_tot = 0;
- int tri_tot = 0;
- bool cyclic_u = dl->flag & DL_CYCL_U;
- bool cyclic_v = dl->flag & DL_CYCL_V;
-
- switch (dl->type) {
- case DL_SURF:
- {
- int segments_u = dl->nr - (cyclic_u == false);
- int segments_v = dl->parts - (cyclic_v == false);
- vert_tot = dl->nr * dl->parts;
- face_tot = segments_u * segments_v;
- tri_tot = face_tot * 2;
- break;
- }
- case DL_INDEX3:
- {
- vert_tot = dl->nr;
- face_tot = dl->parts;
- tri_tot = face_tot;
- break;
- }
- case DL_INDEX4:
- {
- vert_tot = dl->nr;
- face_tot = dl->parts;
- tri_tot = face_tot * 2;
- break;
- }
- case DL_POLY:
- case DL_SEGM:
- {
- vert_tot = dl->nr * dl->parts;
- break;
- }
- }
-
- *totvert += vert_tot;
- *totface += face_tot;
- *tottri += tri_tot;
- }
+ DispList *dl;
+
+ for (dl = lb->first; dl; dl = dl->next) {
+ int vert_tot = 0;
+ int face_tot = 0;
+ int tri_tot = 0;
+ bool cyclic_u = dl->flag & DL_CYCL_U;
+ bool cyclic_v = dl->flag & DL_CYCL_V;
+
+ switch (dl->type) {
+ case DL_SURF: {
+ int segments_u = dl->nr - (cyclic_u == false);
+ int segments_v = dl->parts - (cyclic_v == false);
+ vert_tot = dl->nr * dl->parts;
+ face_tot = segments_u * segments_v;
+ tri_tot = face_tot * 2;
+ break;
+ }
+ case DL_INDEX3: {
+ vert_tot = dl->nr;
+ face_tot = dl->parts;
+ tri_tot = face_tot;
+ break;
+ }
+ case DL_INDEX4: {
+ vert_tot = dl->nr;
+ face_tot = dl->parts;
+ tri_tot = face_tot * 2;
+ break;
+ }
+ case DL_POLY:
+ case DL_SEGM: {
+ vert_tot = dl->nr * dl->parts;
+ break;
+ }
+ }
+
+ *totvert += vert_tot;
+ *totface += face_tot;
+ *tottri += tri_tot;
+ }
}
bool BKE_displist_surfindex_get(DispList *dl, int a, int *b, int *p1, int *p2, int *p3, int *p4)
{
- if ((dl->flag & DL_CYCL_V) == 0 && a == (dl->parts) - 1) {
- return false;
- }
-
- if (dl->flag & DL_CYCL_U) {
- (*p1) = dl->nr * a;
- (*p2) = (*p1) + dl->nr - 1;
- (*p3) = (*p1) + dl->nr;
- (*p4) = (*p2) + dl->nr;
- (*b) = 0;
- }
- else {
- (*p2) = dl->nr * a;
- (*p1) = (*p2) + 1;
- (*p4) = (*p2) + dl->nr;
- (*p3) = (*p1) + dl->nr;
- (*b) = 1;
- }
-
- if ((dl->flag & DL_CYCL_V) && a == dl->parts - 1) {
- (*p3) -= dl->nr * dl->parts;
- (*p4) -= dl->nr * dl->parts;
- }
-
- return true;
+ if ((dl->flag & DL_CYCL_V) == 0 && a == (dl->parts) - 1) {
+ return false;
+ }
+
+ if (dl->flag & DL_CYCL_U) {
+ (*p1) = dl->nr * a;
+ (*p2) = (*p1) + dl->nr - 1;
+ (*p3) = (*p1) + dl->nr;
+ (*p4) = (*p2) + dl->nr;
+ (*b) = 0;
+ }
+ else {
+ (*p2) = dl->nr * a;
+ (*p1) = (*p2) + 1;
+ (*p4) = (*p2) + dl->nr;
+ (*p3) = (*p1) + dl->nr;
+ (*b) = 1;
+ }
+
+ if ((dl->flag & DL_CYCL_V) && a == dl->parts - 1) {
+ (*p3) -= dl->nr * dl->parts;
+ (*p4) -= dl->nr * dl->parts;
+ }
+
+ return true;
}
/* ****************** make displists ********************* */
#ifdef __INTEL_COMPILER
/* ICC with the optimization -02 causes crashes. */
-# pragma intel optimization_level 1
+# pragma intel optimization_level 1
#endif
-static void curve_to_displist(Curve *cu, ListBase *nubase, ListBase *dispbase,
- const bool for_render, const bool use_render_resolution)
+static void curve_to_displist(Curve *cu,
+ ListBase *nubase,
+ ListBase *dispbase,
+ const bool for_render,
+ const bool use_render_resolution)
{
- Nurb *nu;
- DispList *dl;
- BezTriple *bezt, *prevbezt;
- BPoint *bp;
- float *data;
- int a, len, resolu;
- const bool editmode = (!for_render && (cu->editnurb || cu->editfont));
-
- nu = nubase->first;
- while (nu) {
- if (nu->hide == 0 || editmode == false) {
- if (use_render_resolution && cu->resolu_ren != 0)
- resolu = cu->resolu_ren;
- else
- resolu = nu->resolu;
-
- if (!BKE_nurb_check_valid_u(nu)) {
- /* pass */
- }
- else if (nu->type == CU_BEZIER) {
- /* count */
- len = 0;
- a = nu->pntsu - 1;
- if (nu->flagu & CU_NURB_CYCLIC) a++;
-
- prevbezt = nu->bezt;
- bezt = prevbezt + 1;
- while (a--) {
- if (a == 0 && (nu->flagu & CU_NURB_CYCLIC))
- bezt = nu->bezt;
-
- if (prevbezt->h2 == HD_VECT && bezt->h1 == HD_VECT)
- len++;
- else
- len += resolu;
-
- if (a == 0 && (nu->flagu & CU_NURB_CYCLIC) == 0)
- len++;
-
- prevbezt = bezt;
- bezt++;
- }
-
- dl = MEM_callocN(sizeof(DispList), "makeDispListbez");
- /* len+1 because of 'forward_diff_bezier' function */
- dl->verts = MEM_mallocN((len + 1) * sizeof(float[3]), "dlverts");
- BLI_addtail(dispbase, dl);
- dl->parts = 1;
- dl->nr = len;
- dl->col = nu->mat_nr;
- dl->charidx = nu->charidx;
-
- data = dl->verts;
-
- /* check that (len != 2) so we don't immediately loop back on ourselves */
- if (nu->flagu & CU_NURB_CYCLIC && (dl->nr != 2)) {
- dl->type = DL_POLY;
- a = nu->pntsu;
- }
- else {
- dl->type = DL_SEGM;
- a = nu->pntsu - 1;
- }
-
- prevbezt = nu->bezt;
- bezt = prevbezt + 1;
-
- while (a--) {
- if (a == 0 && dl->type == DL_POLY)
- bezt = nu->bezt;
-
- if (prevbezt->h2 == HD_VECT && bezt->h1 == HD_VECT) {
- copy_v3_v3(data, prevbezt->vec[1]);
- data += 3;
- }
- else {
- int j;
- for (j = 0; j < 3; j++) {
- BKE_curve_forward_diff_bezier(prevbezt->vec[1][j],
- prevbezt->vec[2][j],
- bezt->vec[0][j],
- bezt->vec[1][j],
- data + j, resolu, 3 * sizeof(float));
- }
-
- data += 3 * resolu;
- }
-
- if (a == 0 && dl->type == DL_SEGM) {
- copy_v3_v3(data, bezt->vec[1]);
- }
-
- prevbezt = bezt;
- bezt++;
- }
- }
- else if (nu->type == CU_NURBS) {
- len = (resolu * SEGMENTSU(nu));
-
- dl = MEM_callocN(sizeof(DispList), "makeDispListsurf");
- dl->verts = MEM_mallocN(len * sizeof(float[3]), "dlverts");
- BLI_addtail(dispbase, dl);
- dl->parts = 1;
-
- dl->nr = len;
- dl->col = nu->mat_nr;
- dl->charidx = nu->charidx;
-
- data = dl->verts;
- if (nu->flagu & CU_NURB_CYCLIC)
- dl->type = DL_POLY;
- else dl->type = DL_SEGM;
- BKE_nurb_makeCurve(nu, data, NULL, NULL, NULL, resolu, 3 * sizeof(float));
- }
- else if (nu->type == CU_POLY) {
- len = nu->pntsu;
- dl = MEM_callocN(sizeof(DispList), "makeDispListpoly");
- dl->verts = MEM_mallocN(len * sizeof(float[3]), "dlverts");
- BLI_addtail(dispbase, dl);
- dl->parts = 1;
- dl->nr = len;
- dl->col = nu->mat_nr;
- dl->charidx = nu->charidx;
-
- data = dl->verts;
- if ((nu->flagu & CU_NURB_CYCLIC) && (dl->nr != 2)) {
- dl->type = DL_POLY;
- }
- else {
- dl->type = DL_SEGM;
- }
-
- a = len;
- bp = nu->bp;
- while (a--) {
- copy_v3_v3(data, bp->vec);
- bp++;
- data += 3;
- }
- }
- }
- nu = nu->next;
- }
+ Nurb *nu;
+ DispList *dl;
+ BezTriple *bezt, *prevbezt;
+ BPoint *bp;
+ float *data;
+ int a, len, resolu;
+ const bool editmode = (!for_render && (cu->editnurb || cu->editfont));
+
+ nu = nubase->first;
+ while (nu) {
+ if (nu->hide == 0 || editmode == false) {
+ if (use_render_resolution && cu->resolu_ren != 0)
+ resolu = cu->resolu_ren;
+ else
+ resolu = nu->resolu;
+
+ if (!BKE_nurb_check_valid_u(nu)) {
+ /* pass */
+ }
+ else if (nu->type == CU_BEZIER) {
+ /* count */
+ len = 0;
+ a = nu->pntsu - 1;
+ if (nu->flagu & CU_NURB_CYCLIC)
+ a++;
+
+ prevbezt = nu->bezt;
+ bezt = prevbezt + 1;
+ while (a--) {
+ if (a == 0 && (nu->flagu & CU_NURB_CYCLIC))
+ bezt = nu->bezt;
+
+ if (prevbezt->h2 == HD_VECT && bezt->h1 == HD_VECT)
+ len++;
+ else
+ len += resolu;
+
+ if (a == 0 && (nu->flagu & CU_NURB_CYCLIC) == 0)
+ len++;
+
+ prevbezt = bezt;
+ bezt++;
+ }
+
+ dl = MEM_callocN(sizeof(DispList), "makeDispListbez");
+ /* len+1 because of 'forward_diff_bezier' function */
+ dl->verts = MEM_mallocN((len + 1) * sizeof(float[3]), "dlverts");
+ BLI_addtail(dispbase, dl);
+ dl->parts = 1;
+ dl->nr = len;
+ dl->col = nu->mat_nr;
+ dl->charidx = nu->charidx;
+
+ data = dl->verts;
+
+ /* check that (len != 2) so we don't immediately loop back on ourselves */
+ if (nu->flagu & CU_NURB_CYCLIC && (dl->nr != 2)) {
+ dl->type = DL_POLY;
+ a = nu->pntsu;
+ }
+ else {
+ dl->type = DL_SEGM;
+ a = nu->pntsu - 1;
+ }
+
+ prevbezt = nu->bezt;
+ bezt = prevbezt + 1;
+
+ while (a--) {
+ if (a == 0 && dl->type == DL_POLY)
+ bezt = nu->bezt;
+
+ if (prevbezt->h2 == HD_VECT && bezt->h1 == HD_VECT) {
+ copy_v3_v3(data, prevbezt->vec[1]);
+ data += 3;
+ }
+ else {
+ int j;
+ for (j = 0; j < 3; j++) {
+ BKE_curve_forward_diff_bezier(prevbezt->vec[1][j],
+ prevbezt->vec[2][j],
+ bezt->vec[0][j],
+ bezt->vec[1][j],
+ data + j,
+ resolu,
+ 3 * sizeof(float));
+ }
+
+ data += 3 * resolu;
+ }
+
+ if (a == 0 && dl->type == DL_SEGM) {
+ copy_v3_v3(data, bezt->vec[1]);
+ }
+
+ prevbezt = bezt;
+ bezt++;
+ }
+ }
+ else if (nu->type == CU_NURBS) {
+ len = (resolu * SEGMENTSU(nu));
+
+ dl = MEM_callocN(sizeof(DispList), "makeDispListsurf");
+ dl->verts = MEM_mallocN(len * sizeof(float[3]), "dlverts");
+ BLI_addtail(dispbase, dl);
+ dl->parts = 1;
+
+ dl->nr = len;
+ dl->col = nu->mat_nr;
+ dl->charidx = nu->charidx;
+
+ data = dl->verts;
+ if (nu->flagu & CU_NURB_CYCLIC)
+ dl->type = DL_POLY;
+ else
+ dl->type = DL_SEGM;
+ BKE_nurb_makeCurve(nu, data, NULL, NULL, NULL, resolu, 3 * sizeof(float));
+ }
+ else if (nu->type == CU_POLY) {
+ len = nu->pntsu;
+ dl = MEM_callocN(sizeof(DispList), "makeDispListpoly");
+ dl->verts = MEM_mallocN(len * sizeof(float[3]), "dlverts");
+ BLI_addtail(dispbase, dl);
+ dl->parts = 1;
+ dl->nr = len;
+ dl->col = nu->mat_nr;
+ dl->charidx = nu->charidx;
+
+ data = dl->verts;
+ if ((nu->flagu & CU_NURB_CYCLIC) && (dl->nr != 2)) {
+ dl->type = DL_POLY;
+ }
+ else {
+ dl->type = DL_SEGM;
+ }
+
+ a = len;
+ bp = nu->bp;
+ while (a--) {
+ copy_v3_v3(data, bp->vec);
+ bp++;
+ data += 3;
+ }
+ }
+ }
+ nu = nu->next;
+ }
}
/**
@@ -455,224 +465,225 @@ static void curve_to_displist(Curve *cu, ListBase *nubase, ListBase *dispbase,
* Pass this along if known since it saves time calculating the normal.
* \param flipnormal: Flip the normal (same as passing \a normal_proj negated)
*/
-void BKE_displist_fill(ListBase *dispbase, ListBase *to, const float normal_proj[3], const bool flipnormal)
+void BKE_displist_fill(ListBase *dispbase,
+ ListBase *to,
+ const float normal_proj[3],
+ const bool flipnormal)
{
- ScanFillContext sf_ctx;
- ScanFillVert *sf_vert, *sf_vert_new, *sf_vert_last;
- ScanFillFace *sf_tri;
- MemArena *sf_arena;
- DispList *dlnew = NULL, *dl;
- float *f1;
- int colnr = 0, charidx = 0, cont = 1, tot, a, *index, nextcol = 0;
- int totvert;
- const int scanfill_flag = BLI_SCANFILL_CALC_REMOVE_DOUBLES | BLI_SCANFILL_CALC_POLYS | BLI_SCANFILL_CALC_HOLES;
-
- if (dispbase == NULL)
- return;
- if (BLI_listbase_is_empty(dispbase))
- return;
-
- sf_arena = BLI_memarena_new(BLI_SCANFILL_ARENA_SIZE, __func__);
-
- while (cont) {
- int dl_flag_accum = 0;
- cont = 0;
- totvert = 0;
- nextcol = 0;
-
- BLI_scanfill_begin_arena(&sf_ctx, sf_arena);
-
- dl = dispbase->first;
- while (dl) {
- if (dl->type == DL_POLY) {
- if (charidx < dl->charidx)
- cont = 1;
- else if (charidx == dl->charidx) { /* character with needed index */
- if (colnr == dl->col) {
-
- sf_ctx.poly_nr++;
-
- /* make editverts and edges */
- f1 = dl->verts;
- a = dl->nr;
- sf_vert = sf_vert_new = NULL;
-
- while (a--) {
- sf_vert_last = sf_vert;
-
- sf_vert = BLI_scanfill_vert_add(&sf_ctx, f1);
- totvert++;
-
- if (sf_vert_last == NULL)
- sf_vert_new = sf_vert;
- else {
- BLI_scanfill_edge_add(&sf_ctx, sf_vert_last, sf_vert);
- }
- f1 += 3;
- }
-
- if (sf_vert != NULL && sf_vert_new != NULL) {
- BLI_scanfill_edge_add(&sf_ctx, sf_vert, sf_vert_new);
- }
- }
- else if (colnr < dl->col) {
- /* got poly with next material at current char */
- cont = 1;
- nextcol = 1;
- }
- }
- dl_flag_accum |= dl->flag;
- }
- dl = dl->next;
- }
-
- /* XXX (obedit && obedit->actcol) ? (obedit->actcol - 1) : 0)) { */
- if (totvert && (tot = BLI_scanfill_calc_ex(&sf_ctx,
- scanfill_flag,
- normal_proj)))
- {
- if (tot) {
- dlnew = MEM_callocN(sizeof(DispList), "filldisplist");
- dlnew->type = DL_INDEX3;
- dlnew->flag = (dl_flag_accum & (DL_BACK_CURVE | DL_FRONT_CURVE));
- dlnew->col = colnr;
- dlnew->nr = totvert;
- dlnew->parts = tot;
-
- dlnew->index = MEM_mallocN(tot * 3 * sizeof(int), "dlindex");
- dlnew->verts = MEM_mallocN(totvert * 3 * sizeof(float), "dlverts");
-
- /* vert data */
- f1 = dlnew->verts;
- totvert = 0;
-
- for (sf_vert = sf_ctx.fillvertbase.first; sf_vert; sf_vert = sf_vert->next) {
- copy_v3_v3(f1, sf_vert->co);
- f1 += 3;
-
- /* index number */
- sf_vert->tmp.i = totvert;
- totvert++;
- }
-
- /* index data */
-
- index = dlnew->index;
- for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) {
- index[0] = sf_tri->v1->tmp.i;
- index[1] = sf_tri->v2->tmp.i;
- index[2] = sf_tri->v3->tmp.i;
-
- if (flipnormal)
- SWAP(int, index[0], index[2]);
-
- index += 3;
- }
- }
-
- BLI_addhead(to, dlnew);
- }
- BLI_scanfill_end_arena(&sf_ctx, sf_arena);
-
- if (nextcol) {
- /* stay at current char but fill polys with next material */
- colnr++;
- }
- else {
- /* switch to next char and start filling from first material */
- charidx++;
- colnr = 0;
- }
- }
-
- BLI_memarena_free(sf_arena);
-
- /* do not free polys, needed for wireframe display */
+ ScanFillContext sf_ctx;
+ ScanFillVert *sf_vert, *sf_vert_new, *sf_vert_last;
+ ScanFillFace *sf_tri;
+ MemArena *sf_arena;
+ DispList *dlnew = NULL, *dl;
+ float *f1;
+ int colnr = 0, charidx = 0, cont = 1, tot, a, *index, nextcol = 0;
+ int totvert;
+ const int scanfill_flag = BLI_SCANFILL_CALC_REMOVE_DOUBLES | BLI_SCANFILL_CALC_POLYS |
+ BLI_SCANFILL_CALC_HOLES;
+
+ if (dispbase == NULL)
+ return;
+ if (BLI_listbase_is_empty(dispbase))
+ return;
+
+ sf_arena = BLI_memarena_new(BLI_SCANFILL_ARENA_SIZE, __func__);
+
+ while (cont) {
+ int dl_flag_accum = 0;
+ cont = 0;
+ totvert = 0;
+ nextcol = 0;
+
+ BLI_scanfill_begin_arena(&sf_ctx, sf_arena);
+
+ dl = dispbase->first;
+ while (dl) {
+ if (dl->type == DL_POLY) {
+ if (charidx < dl->charidx)
+ cont = 1;
+ else if (charidx == dl->charidx) { /* character with needed index */
+ if (colnr == dl->col) {
+
+ sf_ctx.poly_nr++;
+
+ /* make editverts and edges */
+ f1 = dl->verts;
+ a = dl->nr;
+ sf_vert = sf_vert_new = NULL;
+
+ while (a--) {
+ sf_vert_last = sf_vert;
+
+ sf_vert = BLI_scanfill_vert_add(&sf_ctx, f1);
+ totvert++;
+
+ if (sf_vert_last == NULL)
+ sf_vert_new = sf_vert;
+ else {
+ BLI_scanfill_edge_add(&sf_ctx, sf_vert_last, sf_vert);
+ }
+ f1 += 3;
+ }
+
+ if (sf_vert != NULL && sf_vert_new != NULL) {
+ BLI_scanfill_edge_add(&sf_ctx, sf_vert, sf_vert_new);
+ }
+ }
+ else if (colnr < dl->col) {
+ /* got poly with next material at current char */
+ cont = 1;
+ nextcol = 1;
+ }
+ }
+ dl_flag_accum |= dl->flag;
+ }
+ dl = dl->next;
+ }
+
+ /* XXX (obedit && obedit->actcol) ? (obedit->actcol - 1) : 0)) { */
+ if (totvert && (tot = BLI_scanfill_calc_ex(&sf_ctx, scanfill_flag, normal_proj))) {
+ if (tot) {
+ dlnew = MEM_callocN(sizeof(DispList), "filldisplist");
+ dlnew->type = DL_INDEX3;
+ dlnew->flag = (dl_flag_accum & (DL_BACK_CURVE | DL_FRONT_CURVE));
+ dlnew->col = colnr;
+ dlnew->nr = totvert;
+ dlnew->parts = tot;
+
+ dlnew->index = MEM_mallocN(tot * 3 * sizeof(int), "dlindex");
+ dlnew->verts = MEM_mallocN(totvert * 3 * sizeof(float), "dlverts");
+
+ /* vert data */
+ f1 = dlnew->verts;
+ totvert = 0;
+
+ for (sf_vert = sf_ctx.fillvertbase.first; sf_vert; sf_vert = sf_vert->next) {
+ copy_v3_v3(f1, sf_vert->co);
+ f1 += 3;
+
+ /* index number */
+ sf_vert->tmp.i = totvert;
+ totvert++;
+ }
+
+ /* index data */
+
+ index = dlnew->index;
+ for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) {
+ index[0] = sf_tri->v1->tmp.i;
+ index[1] = sf_tri->v2->tmp.i;
+ index[2] = sf_tri->v3->tmp.i;
+
+ if (flipnormal)
+ SWAP(int, index[0], index[2]);
+
+ index += 3;
+ }
+ }
+
+ BLI_addhead(to, dlnew);
+ }
+ BLI_scanfill_end_arena(&sf_ctx, sf_arena);
+
+ if (nextcol) {
+ /* stay at current char but fill polys with next material */
+ colnr++;
+ }
+ else {
+ /* switch to next char and start filling from first material */
+ charidx++;
+ colnr = 0;
+ }
+ }
+
+ BLI_memarena_free(sf_arena);
+
+ /* do not free polys, needed for wireframe display */
}
static void bevels_to_filledpoly(Curve *cu, ListBase *dispbase)
{
- const float z_up[3] = {0.0f, 0.0f, 1.0f};
- ListBase front, back;
- DispList *dl, *dlnew;
- float *fp, *fp1;
- int a, dpoly;
-
- BLI_listbase_clear(&front);
- BLI_listbase_clear(&back);
-
- dl = dispbase->first;
- while (dl) {
- if (dl->type == DL_SURF) {
- if ((dl->flag & DL_CYCL_V) && (dl->flag & DL_CYCL_U) == 0) {
- if ((cu->flag & CU_BACK) && (dl->flag & DL_BACK_CURVE)) {
- dlnew = MEM_callocN(sizeof(DispList), "filldisp");
- BLI_addtail(&front, dlnew);
- dlnew->verts = fp1 = MEM_mallocN(sizeof(float) * 3 * dl->parts, "filldisp1");
- dlnew->nr = dl->parts;
- dlnew->parts = 1;
- dlnew->type = DL_POLY;
- dlnew->flag = DL_BACK_CURVE;
- dlnew->col = dl->col;
- dlnew->charidx = dl->charidx;
-
- fp = dl->verts;
- dpoly = 3 * dl->nr;
-
- a = dl->parts;
- while (a--) {
- copy_v3_v3(fp1, fp);
- fp1 += 3;
- fp += dpoly;
- }
- }
- if ((cu->flag & CU_FRONT) && (dl->flag & DL_FRONT_CURVE)) {
- dlnew = MEM_callocN(sizeof(DispList), "filldisp");
- BLI_addtail(&back, dlnew);
- dlnew->verts = fp1 = MEM_mallocN(sizeof(float) * 3 * dl->parts, "filldisp1");
- dlnew->nr = dl->parts;
- dlnew->parts = 1;
- dlnew->type = DL_POLY;
- dlnew->flag = DL_FRONT_CURVE;
- dlnew->col = dl->col;
- dlnew->charidx = dl->charidx;
-
- fp = dl->verts + 3 * (dl->nr - 1);
- dpoly = 3 * dl->nr;
-
- a = dl->parts;
- while (a--) {
- copy_v3_v3(fp1, fp);
- fp1 += 3;
- fp += dpoly;
- }
- }
- }
- }
- dl = dl->next;
- }
-
- BKE_displist_fill(&front, dispbase, z_up, true);
- BKE_displist_fill(&back, dispbase, z_up, false);
-
- BKE_displist_free(&front);
- BKE_displist_free(&back);
-
- BKE_displist_fill(dispbase, dispbase, z_up, false);
+ const float z_up[3] = {0.0f, 0.0f, 1.0f};
+ ListBase front, back;
+ DispList *dl, *dlnew;
+ float *fp, *fp1;
+ int a, dpoly;
+
+ BLI_listbase_clear(&front);
+ BLI_listbase_clear(&back);
+
+ dl = dispbase->first;
+ while (dl) {
+ if (dl->type == DL_SURF) {
+ if ((dl->flag & DL_CYCL_V) && (dl->flag & DL_CYCL_U) == 0) {
+ if ((cu->flag & CU_BACK) && (dl->flag & DL_BACK_CURVE)) {
+ dlnew = MEM_callocN(sizeof(DispList), "filldisp");
+ BLI_addtail(&front, dlnew);
+ dlnew->verts = fp1 = MEM_mallocN(sizeof(float) * 3 * dl->parts, "filldisp1");
+ dlnew->nr = dl->parts;
+ dlnew->parts = 1;
+ dlnew->type = DL_POLY;
+ dlnew->flag = DL_BACK_CURVE;
+ dlnew->col = dl->col;
+ dlnew->charidx = dl->charidx;
+
+ fp = dl->verts;
+ dpoly = 3 * dl->nr;
+
+ a = dl->parts;
+ while (a--) {
+ copy_v3_v3(fp1, fp);
+ fp1 += 3;
+ fp += dpoly;
+ }
+ }
+ if ((cu->flag & CU_FRONT) && (dl->flag & DL_FRONT_CURVE)) {
+ dlnew = MEM_callocN(sizeof(DispList), "filldisp");
+ BLI_addtail(&back, dlnew);
+ dlnew->verts = fp1 = MEM_mallocN(sizeof(float) * 3 * dl->parts, "filldisp1");
+ dlnew->nr = dl->parts;
+ dlnew->parts = 1;
+ dlnew->type = DL_POLY;
+ dlnew->flag = DL_FRONT_CURVE;
+ dlnew->col = dl->col;
+ dlnew->charidx = dl->charidx;
+
+ fp = dl->verts + 3 * (dl->nr - 1);
+ dpoly = 3 * dl->nr;
+
+ a = dl->parts;
+ while (a--) {
+ copy_v3_v3(fp1, fp);
+ fp1 += 3;
+ fp += dpoly;
+ }
+ }
+ }
+ }
+ dl = dl->next;
+ }
+
+ BKE_displist_fill(&front, dispbase, z_up, true);
+ BKE_displist_fill(&back, dispbase, z_up, false);
+
+ BKE_displist_free(&front);
+ BKE_displist_free(&back);
+
+ BKE_displist_fill(dispbase, dispbase, z_up, false);
}
static void curve_to_filledpoly(Curve *cu, ListBase *UNUSED(nurb), ListBase *dispbase)
{
- if (!CU_DO_2DFILL(cu))
- return;
-
- if (dispbase->first && ((DispList *) dispbase->first)->type == DL_SURF) {
- bevels_to_filledpoly(cu, dispbase);
- }
- else {
- const float z_up[3] = {0.0f, 0.0f, 1.0f};
- BKE_displist_fill(dispbase, dispbase, z_up, false);
- }
+ if (!CU_DO_2DFILL(cu))
+ return;
+
+ if (dispbase->first && ((DispList *)dispbase->first)->type == DL_SURF) {
+ bevels_to_filledpoly(cu, dispbase);
+ }
+ else {
+ const float z_up[3] = {0.0f, 0.0f, 1.0f};
+ BKE_displist_fill(dispbase, dispbase, z_up, false);
+ }
}
/* taper rules:
@@ -682,1237 +693,1284 @@ static void curve_to_filledpoly(Curve *cu, ListBase *UNUSED(nurb), ListBase *dis
*/
static float displist_calc_taper(Depsgraph *depsgraph, Scene *scene, Object *taperobj, float fac)
{
- DispList *dl;
-
- if (taperobj == NULL || taperobj->type != OB_CURVE)
- return 1.0;
-
- dl = taperobj->runtime.curve_cache ? taperobj->runtime.curve_cache->disp.first : NULL;
- if (dl == NULL) {
- BKE_displist_make_curveTypes(depsgraph, scene, taperobj, false, false, NULL);
- dl = taperobj->runtime.curve_cache->disp.first;
- }
- if (dl) {
- float minx, dx, *fp;
- int a;
-
- /* horizontal size */
- minx = dl->verts[0];
- dx = dl->verts[3 * (dl->nr - 1)] - minx;
- if (dx > 0.0f) {
- fp = dl->verts;
- for (a = 0; a < dl->nr; a++, fp += 3) {
- if ((fp[0] - minx) / dx >= fac) {
- /* interpolate with prev */
- if (a > 0) {
- float fac1 = (fp[-3] - minx) / dx;
- float fac2 = (fp[0] - minx) / dx;
- if (fac1 != fac2)
- return fp[1] * (fac1 - fac) / (fac1 - fac2) + fp[-2] * (fac - fac2) / (fac1 - fac2);
- }
- return fp[1];
- }
- }
- return fp[-2]; // last y coord
- }
- }
-
- return 1.0;
+ DispList *dl;
+
+ if (taperobj == NULL || taperobj->type != OB_CURVE)
+ return 1.0;
+
+ dl = taperobj->runtime.curve_cache ? taperobj->runtime.curve_cache->disp.first : NULL;
+ if (dl == NULL) {
+ BKE_displist_make_curveTypes(depsgraph, scene, taperobj, false, false, NULL);
+ dl = taperobj->runtime.curve_cache->disp.first;
+ }
+ if (dl) {
+ float minx, dx, *fp;
+ int a;
+
+ /* horizontal size */
+ minx = dl->verts[0];
+ dx = dl->verts[3 * (dl->nr - 1)] - minx;
+ if (dx > 0.0f) {
+ fp = dl->verts;
+ for (a = 0; a < dl->nr; a++, fp += 3) {
+ if ((fp[0] - minx) / dx >= fac) {
+ /* interpolate with prev */
+ if (a > 0) {
+ float fac1 = (fp[-3] - minx) / dx;
+ float fac2 = (fp[0] - minx) / dx;
+ if (fac1 != fac2)
+ return fp[1] * (fac1 - fac) / (fac1 - fac2) + fp[-2] * (fac - fac2) / (fac1 - fac2);
+ }
+ return fp[1];
+ }
+ }
+ return fp[-2]; // last y coord
+ }
+ }
+
+ return 1.0;
}
-float BKE_displist_calc_taper(Depsgraph *depsgraph, Scene *scene, Object *taperobj, int cur, int tot)
+float BKE_displist_calc_taper(
+ Depsgraph *depsgraph, Scene *scene, Object *taperobj, int cur, int tot)
{
- float fac = ((float)cur) / (float)(tot - 1);
+ float fac = ((float)cur) / (float)(tot - 1);
- return displist_calc_taper(depsgraph, scene, taperobj, fac);
+ return displist_calc_taper(depsgraph, scene, taperobj, fac);
}
void BKE_displist_make_mball(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- if (!ob || ob->type != OB_MBALL)
- return;
+ if (!ob || ob->type != OB_MBALL)
+ return;
- if (ob == BKE_mball_basis_find(scene, ob)) {
- if (ob->runtime.curve_cache) {
- BKE_displist_free(&(ob->runtime.curve_cache->disp));
- }
- else {
- ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for MBall");
- }
+ if (ob == BKE_mball_basis_find(scene, ob)) {
+ if (ob->runtime.curve_cache) {
+ BKE_displist_free(&(ob->runtime.curve_cache->disp));
+ }
+ else {
+ ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for MBall");
+ }
- BKE_mball_polygonize(depsgraph, scene, ob, &ob->runtime.curve_cache->disp);
- BKE_mball_texspace_calc(ob);
+ BKE_mball_polygonize(depsgraph, scene, ob, &ob->runtime.curve_cache->disp);
+ BKE_mball_texspace_calc(ob);
- object_deform_mball(ob, &ob->runtime.curve_cache->disp);
+ object_deform_mball(ob, &ob->runtime.curve_cache->disp);
- /* NOP for MBALLs anyway... */
- boundbox_displist_object(ob);
- }
+ /* NOP for MBALLs anyway... */
+ boundbox_displist_object(ob);
+ }
}
-void BKE_displist_make_mball_forRender(Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase)
+void BKE_displist_make_mball_forRender(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ ListBase *dispbase)
{
- BKE_mball_polygonize(depsgraph, scene, ob, dispbase);
- BKE_mball_texspace_calc(ob);
+ BKE_mball_polygonize(depsgraph, scene, ob, dispbase);
+ BKE_mball_texspace_calc(ob);
- object_deform_mball(ob, dispbase);
+ object_deform_mball(ob, dispbase);
}
-static ModifierData *curve_get_tessellate_point(Scene *scene, Object *ob,
- const bool use_render_resolution, const bool editmode)
+static ModifierData *curve_get_tessellate_point(Scene *scene,
+ Object *ob,
+ const bool use_render_resolution,
+ const bool editmode)
{
- VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
- ModifierData *pretessellatePoint;
- int required_mode;
-
- if (use_render_resolution)
- required_mode = eModifierMode_Render;
- else
- required_mode = eModifierMode_Realtime;
-
- if (editmode)
- required_mode |= eModifierMode_Editmode;
-
- pretessellatePoint = NULL;
- for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
-
- if (!modifier_isEnabled(scene, md, required_mode))
- continue;
- if (mti->type == eModifierTypeType_Constructive)
- return pretessellatePoint;
-
- if (ELEM(md->type, eModifierType_Hook, eModifierType_Softbody, eModifierType_MeshDeform)) {
- pretessellatePoint = md;
-
- /* this modifiers are moving point of tessellation automatically
- * (some of them even can't be applied on tessellated curve), set flag
- * for information button in modifier's header
- */
- md->mode |= eModifierMode_ApplyOnSpline;
- }
- else if (md->mode & eModifierMode_ApplyOnSpline) {
- pretessellatePoint = md;
- }
- }
-
- return pretessellatePoint;
+ VirtualModifierData virtualModifierData;
+ ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ ModifierData *pretessellatePoint;
+ int required_mode;
+
+ if (use_render_resolution)
+ required_mode = eModifierMode_Render;
+ else
+ required_mode = eModifierMode_Realtime;
+
+ if (editmode)
+ required_mode |= eModifierMode_Editmode;
+
+ pretessellatePoint = NULL;
+ for (; md; md = md->next) {
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if (!modifier_isEnabled(scene, md, required_mode))
+ continue;
+ if (mti->type == eModifierTypeType_Constructive)
+ return pretessellatePoint;
+
+ if (ELEM(md->type, eModifierType_Hook, eModifierType_Softbody, eModifierType_MeshDeform)) {
+ pretessellatePoint = md;
+
+ /* this modifiers are moving point of tessellation automatically
+ * (some of them even can't be applied on tessellated curve), set flag
+ * for information button in modifier's header
+ */
+ md->mode |= eModifierMode_ApplyOnSpline;
+ }
+ else if (md->mode & eModifierMode_ApplyOnSpline) {
+ pretessellatePoint = md;
+ }
+ }
+
+ return pretessellatePoint;
}
-static void curve_calc_modifiers_pre(
- Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *nurb,
- const bool for_render, const bool use_render_resolution)
+static void curve_calc_modifiers_pre(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ ListBase *nurb,
+ const bool for_render,
+ const bool use_render_resolution)
{
- VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
- ModifierData *pretessellatePoint;
- Curve *cu = ob->data;
- int numElems = 0, numVerts = 0;
- const bool editmode = (!for_render && (cu->editnurb || cu->editfont));
- ModifierApplyFlag app_flag = 0;
- float (*deformedVerts)[3] = NULL;
- float *keyVerts = NULL;
- int required_mode;
-
- modifiers_clearErrors(ob);
-
- if (editmode)
- app_flag |= MOD_APPLY_USECACHE;
- if (use_render_resolution) {
- app_flag |= MOD_APPLY_RENDER;
- required_mode = eModifierMode_Render;
- }
- else
- required_mode = eModifierMode_Realtime;
-
- const ModifierEvalContext mectx = {depsgraph, ob, app_flag};
-
- pretessellatePoint = curve_get_tessellate_point(scene, ob, use_render_resolution, editmode);
-
- if (editmode)
- required_mode |= eModifierMode_Editmode;
-
- if (!editmode) {
- keyVerts = BKE_key_evaluate_object(ob, &numElems);
-
- if (keyVerts) {
- BLI_assert(BKE_keyblock_curve_element_count(nurb) == numElems);
-
- /* split coords from key data, the latter also includes
- * tilts, which is passed through in the modifier stack.
- * this is also the reason curves do not use a virtual
- * shape key modifier yet. */
- deformedVerts = BKE_curve_nurbs_keyVertexCos_get(nurb, keyVerts);
- numVerts = BKE_nurbList_verts_count(nurb);
- }
- }
-
- if (pretessellatePoint) {
- for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
-
- if (!modifier_isEnabled(scene, md, required_mode))
- continue;
- if (mti->type != eModifierTypeType_OnlyDeform)
- continue;
-
- if (!deformedVerts) {
- deformedVerts = BKE_curve_nurbs_vertexCos_get(nurb, &numVerts);
- }
-
- mti->deformVerts(md, &mectx, NULL, deformedVerts, numVerts);
-
- if (md == pretessellatePoint)
- break;
- }
- }
-
- if (deformedVerts) {
- BK_curve_nurbs_vertexCos_apply(nurb, deformedVerts);
- MEM_freeN(deformedVerts);
- }
- if (keyVerts) /* these are not passed through modifier stack */
- BKE_curve_nurbs_keyVertexTilts_apply(nurb, keyVerts);
-
- if (keyVerts)
- MEM_freeN(keyVerts);
+ VirtualModifierData virtualModifierData;
+ ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ ModifierData *pretessellatePoint;
+ Curve *cu = ob->data;
+ int numElems = 0, numVerts = 0;
+ const bool editmode = (!for_render && (cu->editnurb || cu->editfont));
+ ModifierApplyFlag app_flag = 0;
+ float(*deformedVerts)[3] = NULL;
+ float *keyVerts = NULL;
+ int required_mode;
+
+ modifiers_clearErrors(ob);
+
+ if (editmode)
+ app_flag |= MOD_APPLY_USECACHE;
+ if (use_render_resolution) {
+ app_flag |= MOD_APPLY_RENDER;
+ required_mode = eModifierMode_Render;
+ }
+ else
+ required_mode = eModifierMode_Realtime;
+
+ const ModifierEvalContext mectx = {depsgraph, ob, app_flag};
+
+ pretessellatePoint = curve_get_tessellate_point(scene, ob, use_render_resolution, editmode);
+
+ if (editmode)
+ required_mode |= eModifierMode_Editmode;
+
+ if (!editmode) {
+ keyVerts = BKE_key_evaluate_object(ob, &numElems);
+
+ if (keyVerts) {
+ BLI_assert(BKE_keyblock_curve_element_count(nurb) == numElems);
+
+ /* split coords from key data, the latter also includes
+ * tilts, which is passed through in the modifier stack.
+ * this is also the reason curves do not use a virtual
+ * shape key modifier yet. */
+ deformedVerts = BKE_curve_nurbs_keyVertexCos_get(nurb, keyVerts);
+ numVerts = BKE_nurbList_verts_count(nurb);
+ }
+ }
+
+ if (pretessellatePoint) {
+ for (; md; md = md->next) {
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if (!modifier_isEnabled(scene, md, required_mode))
+ continue;
+ if (mti->type != eModifierTypeType_OnlyDeform)
+ continue;
+
+ if (!deformedVerts) {
+ deformedVerts = BKE_curve_nurbs_vertexCos_get(nurb, &numVerts);
+ }
+
+ mti->deformVerts(md, &mectx, NULL, deformedVerts, numVerts);
+
+ if (md == pretessellatePoint)
+ break;
+ }
+ }
+
+ if (deformedVerts) {
+ BK_curve_nurbs_vertexCos_apply(nurb, deformedVerts);
+ MEM_freeN(deformedVerts);
+ }
+ if (keyVerts) /* these are not passed through modifier stack */
+ BKE_curve_nurbs_keyVertexTilts_apply(nurb, keyVerts);
+
+ if (keyVerts)
+ MEM_freeN(keyVerts);
}
static float (*displist_get_allverts(ListBase *dispbase, int *totvert))[3]
{
- DispList *dl;
- float (*allverts)[3], *fp;
+ DispList *dl;
+ float(*allverts)[3], *fp;
- *totvert = 0;
+ *totvert = 0;
- for (dl = dispbase->first; dl; dl = dl->next)
- *totvert += (dl->type == DL_INDEX3) ? dl->nr : dl->parts * dl->nr;
+ for (dl = dispbase->first; dl; dl = dl->next)
+ *totvert += (dl->type == DL_INDEX3) ? dl->nr : dl->parts * dl->nr;
- allverts = MEM_mallocN((*totvert) * sizeof(float) * 3, "displist_get_allverts allverts");
- fp = (float *)allverts;
- for (dl = dispbase->first; dl; dl = dl->next) {
- int offs = 3 * ((dl->type == DL_INDEX3) ? dl->nr : dl->parts * dl->nr);
- memcpy(fp, dl->verts, sizeof(float) * offs);
- fp += offs;
- }
+ allverts = MEM_mallocN((*totvert) * sizeof(float) * 3, "displist_get_allverts allverts");
+ fp = (float *)allverts;
+ for (dl = dispbase->first; dl; dl = dl->next) {
+ int offs = 3 * ((dl->type == DL_INDEX3) ? dl->nr : dl->parts * dl->nr);
+ memcpy(fp, dl->verts, sizeof(float) * offs);
+ fp += offs;
+ }
- return allverts;
+ return allverts;
}
static void displist_apply_allverts(ListBase *dispbase, float (*allverts)[3])
{
- DispList *dl;
- const float *fp;
-
- fp = (float *)allverts;
- for (dl = dispbase->first; dl; dl = dl->next) {
- int offs = 3 * ((dl->type == DL_INDEX3) ? dl->nr : dl->parts * dl->nr);
- memcpy(dl->verts, fp, sizeof(float) * offs);
- fp += offs;
- }
+ DispList *dl;
+ const float *fp;
+
+ fp = (float *)allverts;
+ for (dl = dispbase->first; dl; dl = dl->next) {
+ int offs = 3 * ((dl->type == DL_INDEX3) ? dl->nr : dl->parts * dl->nr);
+ memcpy(dl->verts, fp, sizeof(float) * offs);
+ fp += offs;
+ }
}
-static void curve_calc_modifiers_post(
- Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *nurb,
- ListBase *dispbase, Mesh **r_final,
- const bool for_render, const bool use_render_resolution)
+static void curve_calc_modifiers_post(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ ListBase *nurb,
+ ListBase *dispbase,
+ Mesh **r_final,
+ const bool for_render,
+ const bool use_render_resolution)
{
- VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
- ModifierData *pretessellatePoint;
- Curve *cu = ob->data;
- int required_mode = 0, totvert = 0;
- const bool editmode = (!for_render && (cu->editnurb || cu->editfont));
- Mesh *modified = NULL, *mesh_applied;
- float (*vertCos)[3] = NULL;
- int useCache = !for_render;
- ModifierApplyFlag app_flag = 0;
-
- if (use_render_resolution) {
- app_flag |= MOD_APPLY_RENDER;
- required_mode = eModifierMode_Render;
- }
- else
- required_mode = eModifierMode_Realtime;
-
- const ModifierEvalContext mectx_deform = {depsgraph, ob,
- editmode ? app_flag | MOD_APPLY_USECACHE : app_flag};
- const ModifierEvalContext mectx_apply = {depsgraph, ob,
- useCache ? app_flag | MOD_APPLY_USECACHE : app_flag};
-
- pretessellatePoint = curve_get_tessellate_point(scene, ob, use_render_resolution, editmode);
-
- if (editmode)
- required_mode |= eModifierMode_Editmode;
-
- if (pretessellatePoint) {
- md = pretessellatePoint->next;
- }
-
- if (r_final && *r_final) {
- BKE_id_free(NULL, r_final);
- }
-
- for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
-
- if (!modifier_isEnabled(scene, md, required_mode))
- continue;
-
- /* If we need normals, no choice, have to convert to mesh now. */
- if (mti->dependsOnNormals != NULL && mti->dependsOnNormals(md) && modified == NULL) {
- if (vertCos != NULL) {
- displist_apply_allverts(dispbase, vertCos);
- }
-
- if (ELEM(ob->type, OB_CURVE, OB_FONT) && (cu->flag & CU_DEFORM_FILL)) {
- curve_to_filledpoly(cu, nurb, dispbase);
- }
-
- modified = BKE_mesh_new_nomain_from_curve_displist(ob, dispbase);
- }
-
- if (mti->type == eModifierTypeType_OnlyDeform ||
- (mti->type == eModifierTypeType_DeformOrConstruct && !modified))
- {
- if (modified) {
- if (!vertCos) {
- vertCos = BKE_mesh_vertexCos_get(modified, &totvert);
- }
- if (mti->dependsOnNormals != NULL && mti->dependsOnNormals(md)) {
- BKE_mesh_ensure_normals(modified);
- }
- mti->deformVerts(md, &mectx_deform, modified, vertCos, totvert);
- }
- else {
- if (!vertCos) {
- vertCos = displist_get_allverts(dispbase, &totvert);
- }
- mti->deformVerts(md, &mectx_deform, NULL, vertCos, totvert);
- }
- }
- else {
- if (!r_final) {
- /* makeDisplistCurveTypes could be used for beveling, where derived mesh
- * is totally unnecessary, so we could stop modifiers applying
- * when we found constructive modifier but derived mesh is unwanted result
- */
- break;
- }
-
- if (modified) {
- if (vertCos) {
- Mesh *temp_mesh;
- BKE_id_copy_ex(NULL, &modified->id, (ID **)&temp_mesh, LIB_ID_COPY_LOCALIZE);
- BKE_id_free(NULL, modified);
- modified = temp_mesh;
-
- BKE_mesh_apply_vert_coords(modified, vertCos);
- }
- }
- else {
- if (vertCos) {
- displist_apply_allverts(dispbase, vertCos);
- }
-
- if (ELEM(ob->type, OB_CURVE, OB_FONT) && (cu->flag & CU_DEFORM_FILL)) {
- curve_to_filledpoly(cu, nurb, dispbase);
- }
-
- modified = BKE_mesh_new_nomain_from_curve_displist(ob, dispbase);
- }
-
- if (vertCos) {
- /* Vertex coordinates were applied to necessary data, could free it */
- MEM_freeN(vertCos);
- vertCos = NULL;
- }
-
- if (mti->dependsOnNormals != NULL && mti->dependsOnNormals(md)) {
- BKE_mesh_ensure_normals(modified);
- }
- mesh_applied = mti->applyModifier(md, &mectx_apply, modified);
-
- if (mesh_applied) {
- /* Modifier returned a new derived mesh */
-
- if (modified && modified != mesh_applied) /* Modifier */
- BKE_id_free(NULL, modified);
- modified = mesh_applied;
- }
- }
- }
-
- if (vertCos) {
- if (modified) {
- Mesh *temp_mesh;
- BKE_id_copy_ex(NULL, &modified->id, (ID **)&temp_mesh, LIB_ID_COPY_LOCALIZE);
- BKE_id_free(NULL, modified);
- modified = temp_mesh;
-
- BKE_mesh_apply_vert_coords(modified, vertCos);
- BKE_mesh_calc_normals_mapping_simple(modified);
-
- MEM_freeN(vertCos);
- }
- else {
- displist_apply_allverts(dispbase, vertCos);
- MEM_freeN(vertCos);
- vertCos = NULL;
- }
- }
-
- if (r_final) {
- if (modified) {
- /* see: mesh_calc_modifiers */
- if (modified->totface == 0) {
- BKE_mesh_tessface_calc(modified);
- }
- /* Even if tessellation is not needed, some modifiers might have modified CD layers
- * (like mloopcol or mloopuv), hence we have to update those. */
- else if (modified->runtime.cd_dirty_vert & CD_MASK_TESSLOOPNORMAL) {
- BKE_mesh_tessface_calc(modified);
- }
-
- /* XXX2.8(Sybren): make sure the face normals are recalculated as well */
- BKE_mesh_ensure_normals(modified);
-
- /* Special tweaks, needed since neither BKE_mesh_new_nomain_from_template() nor
- * BKE_mesh_new_nomain_from_curve_displist() properly duplicate mat info...
- */
- BLI_strncpy(modified->id.name, cu->id.name, sizeof(modified->id.name));
- *((short *)modified->id.name) = ID_ME;
- MEM_SAFE_FREE(modified->mat);
- /* Set flag which makes it easier to see what's going on in a debugger. */
- modified->id.tag |= LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT;
- modified->mat = MEM_dupallocN(cu->mat);
- modified->totcol = cu->totcol;
-
- (*r_final) = modified;
- }
- else {
- (*r_final) = NULL;
- }
- }
+ VirtualModifierData virtualModifierData;
+ ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ ModifierData *pretessellatePoint;
+ Curve *cu = ob->data;
+ int required_mode = 0, totvert = 0;
+ const bool editmode = (!for_render && (cu->editnurb || cu->editfont));
+ Mesh *modified = NULL, *mesh_applied;
+ float(*vertCos)[3] = NULL;
+ int useCache = !for_render;
+ ModifierApplyFlag app_flag = 0;
+
+ if (use_render_resolution) {
+ app_flag |= MOD_APPLY_RENDER;
+ required_mode = eModifierMode_Render;
+ }
+ else
+ required_mode = eModifierMode_Realtime;
+
+ const ModifierEvalContext mectx_deform = {
+ depsgraph, ob, editmode ? app_flag | MOD_APPLY_USECACHE : app_flag};
+ const ModifierEvalContext mectx_apply = {
+ depsgraph, ob, useCache ? app_flag | MOD_APPLY_USECACHE : app_flag};
+
+ pretessellatePoint = curve_get_tessellate_point(scene, ob, use_render_resolution, editmode);
+
+ if (editmode)
+ required_mode |= eModifierMode_Editmode;
+
+ if (pretessellatePoint) {
+ md = pretessellatePoint->next;
+ }
+
+ if (r_final && *r_final) {
+ BKE_id_free(NULL, r_final);
+ }
+
+ for (; md; md = md->next) {
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if (!modifier_isEnabled(scene, md, required_mode))
+ continue;
+
+ /* If we need normals, no choice, have to convert to mesh now. */
+ if (mti->dependsOnNormals != NULL && mti->dependsOnNormals(md) && modified == NULL) {
+ if (vertCos != NULL) {
+ displist_apply_allverts(dispbase, vertCos);
+ }
+
+ if (ELEM(ob->type, OB_CURVE, OB_FONT) && (cu->flag & CU_DEFORM_FILL)) {
+ curve_to_filledpoly(cu, nurb, dispbase);
+ }
+
+ modified = BKE_mesh_new_nomain_from_curve_displist(ob, dispbase);
+ }
+
+ if (mti->type == eModifierTypeType_OnlyDeform ||
+ (mti->type == eModifierTypeType_DeformOrConstruct && !modified)) {
+ if (modified) {
+ if (!vertCos) {
+ vertCos = BKE_mesh_vertexCos_get(modified, &totvert);
+ }
+ if (mti->dependsOnNormals != NULL && mti->dependsOnNormals(md)) {
+ BKE_mesh_ensure_normals(modified);
+ }
+ mti->deformVerts(md, &mectx_deform, modified, vertCos, totvert);
+ }
+ else {
+ if (!vertCos) {
+ vertCos = displist_get_allverts(dispbase, &totvert);
+ }
+ mti->deformVerts(md, &mectx_deform, NULL, vertCos, totvert);
+ }
+ }
+ else {
+ if (!r_final) {
+ /* makeDisplistCurveTypes could be used for beveling, where derived mesh
+ * is totally unnecessary, so we could stop modifiers applying
+ * when we found constructive modifier but derived mesh is unwanted result
+ */
+ break;
+ }
+
+ if (modified) {
+ if (vertCos) {
+ Mesh *temp_mesh;
+ BKE_id_copy_ex(NULL, &modified->id, (ID **)&temp_mesh, LIB_ID_COPY_LOCALIZE);
+ BKE_id_free(NULL, modified);
+ modified = temp_mesh;
+
+ BKE_mesh_apply_vert_coords(modified, vertCos);
+ }
+ }
+ else {
+ if (vertCos) {
+ displist_apply_allverts(dispbase, vertCos);
+ }
+
+ if (ELEM(ob->type, OB_CURVE, OB_FONT) && (cu->flag & CU_DEFORM_FILL)) {
+ curve_to_filledpoly(cu, nurb, dispbase);
+ }
+
+ modified = BKE_mesh_new_nomain_from_curve_displist(ob, dispbase);
+ }
+
+ if (vertCos) {
+ /* Vertex coordinates were applied to necessary data, could free it */
+ MEM_freeN(vertCos);
+ vertCos = NULL;
+ }
+
+ if (mti->dependsOnNormals != NULL && mti->dependsOnNormals(md)) {
+ BKE_mesh_ensure_normals(modified);
+ }
+ mesh_applied = mti->applyModifier(md, &mectx_apply, modified);
+
+ if (mesh_applied) {
+ /* Modifier returned a new derived mesh */
+
+ if (modified && modified != mesh_applied) /* Modifier */
+ BKE_id_free(NULL, modified);
+ modified = mesh_applied;
+ }
+ }
+ }
+
+ if (vertCos) {
+ if (modified) {
+ Mesh *temp_mesh;
+ BKE_id_copy_ex(NULL, &modified->id, (ID **)&temp_mesh, LIB_ID_COPY_LOCALIZE);
+ BKE_id_free(NULL, modified);
+ modified = temp_mesh;
+
+ BKE_mesh_apply_vert_coords(modified, vertCos);
+ BKE_mesh_calc_normals_mapping_simple(modified);
+
+ MEM_freeN(vertCos);
+ }
+ else {
+ displist_apply_allverts(dispbase, vertCos);
+ MEM_freeN(vertCos);
+ vertCos = NULL;
+ }
+ }
+
+ if (r_final) {
+ if (modified) {
+ /* see: mesh_calc_modifiers */
+ if (modified->totface == 0) {
+ BKE_mesh_tessface_calc(modified);
+ }
+ /* Even if tessellation is not needed, some modifiers might have modified CD layers
+ * (like mloopcol or mloopuv), hence we have to update those. */
+ else if (modified->runtime.cd_dirty_vert & CD_MASK_TESSLOOPNORMAL) {
+ BKE_mesh_tessface_calc(modified);
+ }
+
+ /* XXX2.8(Sybren): make sure the face normals are recalculated as well */
+ BKE_mesh_ensure_normals(modified);
+
+ /* Special tweaks, needed since neither BKE_mesh_new_nomain_from_template() nor
+ * BKE_mesh_new_nomain_from_curve_displist() properly duplicate mat info...
+ */
+ BLI_strncpy(modified->id.name, cu->id.name, sizeof(modified->id.name));
+ *((short *)modified->id.name) = ID_ME;
+ MEM_SAFE_FREE(modified->mat);
+ /* Set flag which makes it easier to see what's going on in a debugger. */
+ modified->id.tag |= LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT;
+ modified->mat = MEM_dupallocN(cu->mat);
+ modified->totcol = cu->totcol;
+
+ (*r_final) = modified;
+ }
+ else {
+ (*r_final) = NULL;
+ }
+ }
}
static void displist_surf_indices(DispList *dl)
{
- int a, b, p1, p2, p3, p4;
- int *index;
+ int a, b, p1, p2, p3, p4;
+ int *index;
- dl->totindex = 0;
+ dl->totindex = 0;
- index = dl->index = MEM_mallocN(4 * sizeof(int) * (dl->parts + 1) * (dl->nr + 1), "index array nurbs");
+ index = dl->index = MEM_mallocN(4 * sizeof(int) * (dl->parts + 1) * (dl->nr + 1),
+ "index array nurbs");
- for (a = 0; a < dl->parts; a++) {
+ for (a = 0; a < dl->parts; a++) {
- if (BKE_displist_surfindex_get(dl, a, &b, &p1, &p2, &p3, &p4) == 0)
- break;
+ if (BKE_displist_surfindex_get(dl, a, &b, &p1, &p2, &p3, &p4) == 0)
+ break;
- for (; b < dl->nr; b++, index += 4) {
- index[0] = p1;
- index[1] = p2;
- index[2] = p4;
- index[3] = p3;
+ for (; b < dl->nr; b++, index += 4) {
+ index[0] = p1;
+ index[1] = p2;
+ index[2] = p4;
+ index[3] = p3;
- dl->totindex++;
+ dl->totindex++;
- p2 = p1; p1++;
- p4 = p3; p3++;
- }
- }
+ p2 = p1;
+ p1++;
+ p4 = p3;
+ p3++;
+ }
+ }
}
/* XXX2.8(Sybren): unused function; impossible to test after porting to Mesh */
#ifdef WITH_DERIVEDMESH_DEPRECATED_FUNCS
static DerivedMesh *create_orco_dm(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- DerivedMesh *dm;
- ListBase disp = {NULL, NULL};
+ DerivedMesh *dm;
+ ListBase disp = {NULL, NULL};
- /* OrcoDM should be created from underformed disp lists */
- BKE_displist_make_curveTypes_forOrco(depsgraph, scene, ob, &disp);
- dm = CDDM_from_curve_displist(ob, &disp);
+ /* OrcoDM should be created from underformed disp lists */
+ BKE_displist_make_curveTypes_forOrco(depsgraph, scene, ob, &disp);
+ dm = CDDM_from_curve_displist(ob, &disp);
- BKE_displist_free(&disp);
+ BKE_displist_free(&disp);
- return dm;
+ return dm;
}
static void add_orco_dm(Object *ob, DerivedMesh *dm, DerivedMesh *orcodm)
{
- float (*orco)[3], (*layerorco)[3];
- int totvert, a;
- Curve *cu = ob->data;
-
- totvert = dm->getNumVerts(dm);
-
- orco = MEM_callocN(sizeof(float) * 3 * totvert, "dm orco");
-
- if (orcodm->getNumVerts(orcodm) == totvert)
- orcodm->getVertCos(orcodm, orco);
- else
- dm->getVertCos(dm, orco);
-
- for (a = 0; a < totvert; a++) {
- float *co = orco[a];
- co[0] = (co[0] - cu->loc[0]) / cu->size[0];
- co[1] = (co[1] - cu->loc[1]) / cu->size[1];
- co[2] = (co[2] - cu->loc[2]) / cu->size[2];
- }
-
- if ((layerorco = DM_get_vert_data_layer(dm, CD_ORCO))) {
- memcpy(layerorco, orco, sizeof(float) * totvert);
- MEM_freeN(orco);
- }
- else
- DM_add_vert_layer(dm, CD_ORCO, CD_ASSIGN, orco);
+ float(*orco)[3], (*layerorco)[3];
+ int totvert, a;
+ Curve *cu = ob->data;
+
+ totvert = dm->getNumVerts(dm);
+
+ orco = MEM_callocN(sizeof(float) * 3 * totvert, "dm orco");
+
+ if (orcodm->getNumVerts(orcodm) == totvert)
+ orcodm->getVertCos(orcodm, orco);
+ else
+ dm->getVertCos(dm, orco);
+
+ for (a = 0; a < totvert; a++) {
+ float *co = orco[a];
+ co[0] = (co[0] - cu->loc[0]) / cu->size[0];
+ co[1] = (co[1] - cu->loc[1]) / cu->size[1];
+ co[2] = (co[2] - cu->loc[2]) / cu->size[2];
+ }
+
+ if ((layerorco = DM_get_vert_data_layer(dm, CD_ORCO))) {
+ memcpy(layerorco, orco, sizeof(float) * totvert);
+ MEM_freeN(orco);
+ }
+ else
+ DM_add_vert_layer(dm, CD_ORCO, CD_ASSIGN, orco);
}
#endif
/* XXX2.8(Sybren): unused function; impossible to test after porting to Mesh */
#ifdef WITH_DERIVEDMESH_DEPRECATED_FUNCS
-static void curve_calc_orcodm(
- Depsgraph *depsgraph, Scene *scene, Object *ob, DerivedMesh *dm_final,
- const bool for_render, const bool use_render_resolution)
+static void curve_calc_orcodm(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ DerivedMesh *dm_final,
+ const bool for_render,
+ const bool use_render_resolution)
{
- /* this function represents logic of mesh's orcodm calculation
- * for displist-based objects
- */
- VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
- ModifierData *pretessellatePoint;
- Curve *cu = ob->data;
- int required_mode;
- const bool editmode = (!for_render && (cu->editnurb || cu->editfont));
- DerivedMesh *ndm, *orcodm = NULL;
- ModifierApplyFlag app_flag = MOD_APPLY_ORCO;
-
- if (use_render_resolution) {
- app_flag |= MOD_APPLY_RENDER;
- required_mode = eModifierMode_Render;
- }
- else
- required_mode = eModifierMode_Realtime;
-
- const ModifierEvalContext mectx = {depsgraph, ob, app_flag};
-
- pretessellatePoint = curve_get_tessellate_point(scene, ob, use_render_resolution, editmode);
-
- if (editmode)
- required_mode |= eModifierMode_Editmode;
-
- if (pretessellatePoint) {
- md = pretessellatePoint->next;
- }
-
- /* If modifiers are disabled, we wouldn't be here because
- * this function is only called if there're enabled constructive
- * modifiers applied on the curve.
- *
- * This means we can create ORCO DM in advance and assume it's
- * never NULL.
- */
- orcodm = create_orco_dm(depsgraph, scene, ob);
-
- for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
-
- md->scene = scene;
-
- if (!modifier_isEnabled(scene, md, required_mode))
- continue;
- if (mti->type != eModifierTypeType_Constructive)
- continue;
-
- ndm = modwrap_applyModifier(md, &mectx, orcodm);
-
- if (ndm) {
- /* if the modifier returned a new dm, release the old one */
- if (orcodm && orcodm != ndm) {
- orcodm->release(orcodm);
- }
- orcodm = ndm;
- }
- }
-
- /* add an orco layer if needed */
- add_orco_dm(ob, dm_final, orcodm);
-
- orcodm->release(orcodm);
+ /* this function represents logic of mesh's orcodm calculation
+ * for displist-based objects
+ */
+ VirtualModifierData virtualModifierData;
+ ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ ModifierData *pretessellatePoint;
+ Curve *cu = ob->data;
+ int required_mode;
+ const bool editmode = (!for_render && (cu->editnurb || cu->editfont));
+ DerivedMesh *ndm, *orcodm = NULL;
+ ModifierApplyFlag app_flag = MOD_APPLY_ORCO;
+
+ if (use_render_resolution) {
+ app_flag |= MOD_APPLY_RENDER;
+ required_mode = eModifierMode_Render;
+ }
+ else
+ required_mode = eModifierMode_Realtime;
+
+ const ModifierEvalContext mectx = {depsgraph, ob, app_flag};
+
+ pretessellatePoint = curve_get_tessellate_point(scene, ob, use_render_resolution, editmode);
+
+ if (editmode)
+ required_mode |= eModifierMode_Editmode;
+
+ if (pretessellatePoint) {
+ md = pretessellatePoint->next;
+ }
+
+ /* If modifiers are disabled, we wouldn't be here because
+ * this function is only called if there're enabled constructive
+ * modifiers applied on the curve.
+ *
+ * This means we can create ORCO DM in advance and assume it's
+ * never NULL.
+ */
+ orcodm = create_orco_dm(depsgraph, scene, ob);
+
+ for (; md; md = md->next) {
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ md->scene = scene;
+
+ if (!modifier_isEnabled(scene, md, required_mode))
+ continue;
+ if (mti->type != eModifierTypeType_Constructive)
+ continue;
+
+ ndm = modwrap_applyModifier(md, &mectx, orcodm);
+
+ if (ndm) {
+ /* if the modifier returned a new dm, release the old one */
+ if (orcodm && orcodm != ndm) {
+ orcodm->release(orcodm);
+ }
+ orcodm = ndm;
+ }
+ }
+
+ /* add an orco layer if needed */
+ add_orco_dm(ob, dm_final, orcodm);
+
+ orcodm->release(orcodm);
}
#endif
-void BKE_displist_make_surf(
- Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase,
- Mesh **r_final,
- const bool for_render, const bool for_orco, const bool use_render_resolution)
+void BKE_displist_make_surf(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ ListBase *dispbase,
+ Mesh **r_final,
+ const bool for_render,
+ const bool for_orco,
+ const bool use_render_resolution)
{
- ListBase nubase = {NULL, NULL};
- Nurb *nu;
- Curve *cu = ob->data;
- DispList *dl;
- float *data;
- int len;
-
- if (!for_render && cu->editnurb) {
- BKE_nurbList_duplicate(&nubase, BKE_curve_editNurbs_get(cu));
- }
- else {
- BKE_nurbList_duplicate(&nubase, &cu->nurb);
- }
-
- if (!for_orco)
- curve_calc_modifiers_pre(depsgraph, scene, ob, &nubase, for_render, use_render_resolution);
-
- for (nu = nubase.first; nu; nu = nu->next) {
- if ((for_render || nu->hide == 0) && BKE_nurb_check_valid_uv(nu)) {
- int resolu = nu->resolu, resolv = nu->resolv;
-
- if (use_render_resolution) {
- if (cu->resolu_ren)
- resolu = cu->resolu_ren;
- if (cu->resolv_ren)
- resolv = cu->resolv_ren;
- }
-
- if (nu->pntsv == 1) {
- len = SEGMENTSU(nu) * resolu;
-
- dl = MEM_callocN(sizeof(DispList), "makeDispListsurf");
- dl->verts = MEM_mallocN(len * sizeof(float[3]), "dlverts");
-
- BLI_addtail(dispbase, dl);
- dl->parts = 1;
- dl->nr = len;
- dl->col = nu->mat_nr;
- dl->charidx = nu->charidx;
-
- /* dl->rt will be used as flag for render face and */
- /* CU_2D conflicts with R_NOPUNOFLIP */
- dl->rt = nu->flag & ~CU_2D;
-
- data = dl->verts;
- if (nu->flagu & CU_NURB_CYCLIC) dl->type = DL_POLY;
- else dl->type = DL_SEGM;
-
- BKE_nurb_makeCurve(nu, data, NULL, NULL, NULL, resolu, 3 * sizeof(float));
- }
- else {
- len = (nu->pntsu * resolu) * (nu->pntsv * resolv);
-
- dl = MEM_callocN(sizeof(DispList), "makeDispListsurf");
- dl->verts = MEM_mallocN(len * sizeof(float[3]), "dlverts");
- BLI_addtail(dispbase, dl);
-
- dl->col = nu->mat_nr;
- dl->charidx = nu->charidx;
-
- /* dl->rt will be used as flag for render face and */
- /* CU_2D conflicts with R_NOPUNOFLIP */
- dl->rt = nu->flag & ~CU_2D;
-
- data = dl->verts;
- dl->type = DL_SURF;
-
- dl->parts = (nu->pntsu * resolu); /* in reverse, because makeNurbfaces works that way */
- dl->nr = (nu->pntsv * resolv);
- if (nu->flagv & CU_NURB_CYCLIC) dl->flag |= DL_CYCL_U; /* reverse too! */
- if (nu->flagu & CU_NURB_CYCLIC) dl->flag |= DL_CYCL_V;
-
- BKE_nurb_makeFaces(nu, data, 0, resolu, resolv);
-
- /* gl array drawing: using indices */
- displist_surf_indices(dl);
- }
- }
- }
-
- if (!for_orco) {
- BKE_nurbList_duplicate(&ob->runtime.curve_cache->deformed_nurbs, &nubase);
- curve_calc_modifiers_post(depsgraph, scene, ob, &nubase, dispbase, r_final,
- for_render, use_render_resolution);
- }
-
- BKE_nurbList_free(&nubase);
+ ListBase nubase = {NULL, NULL};
+ Nurb *nu;
+ Curve *cu = ob->data;
+ DispList *dl;
+ float *data;
+ int len;
+
+ if (!for_render && cu->editnurb) {
+ BKE_nurbList_duplicate(&nubase, BKE_curve_editNurbs_get(cu));
+ }
+ else {
+ BKE_nurbList_duplicate(&nubase, &cu->nurb);
+ }
+
+ if (!for_orco)
+ curve_calc_modifiers_pre(depsgraph, scene, ob, &nubase, for_render, use_render_resolution);
+
+ for (nu = nubase.first; nu; nu = nu->next) {
+ if ((for_render || nu->hide == 0) && BKE_nurb_check_valid_uv(nu)) {
+ int resolu = nu->resolu, resolv = nu->resolv;
+
+ if (use_render_resolution) {
+ if (cu->resolu_ren)
+ resolu = cu->resolu_ren;
+ if (cu->resolv_ren)
+ resolv = cu->resolv_ren;
+ }
+
+ if (nu->pntsv == 1) {
+ len = SEGMENTSU(nu) * resolu;
+
+ dl = MEM_callocN(sizeof(DispList), "makeDispListsurf");
+ dl->verts = MEM_mallocN(len * sizeof(float[3]), "dlverts");
+
+ BLI_addtail(dispbase, dl);
+ dl->parts = 1;
+ dl->nr = len;
+ dl->col = nu->mat_nr;
+ dl->charidx = nu->charidx;
+
+ /* dl->rt will be used as flag for render face and */
+ /* CU_2D conflicts with R_NOPUNOFLIP */
+ dl->rt = nu->flag & ~CU_2D;
+
+ data = dl->verts;
+ if (nu->flagu & CU_NURB_CYCLIC)
+ dl->type = DL_POLY;
+ else
+ dl->type = DL_SEGM;
+
+ BKE_nurb_makeCurve(nu, data, NULL, NULL, NULL, resolu, 3 * sizeof(float));
+ }
+ else {
+ len = (nu->pntsu * resolu) * (nu->pntsv * resolv);
+
+ dl = MEM_callocN(sizeof(DispList), "makeDispListsurf");
+ dl->verts = MEM_mallocN(len * sizeof(float[3]), "dlverts");
+ BLI_addtail(dispbase, dl);
+
+ dl->col = nu->mat_nr;
+ dl->charidx = nu->charidx;
+
+ /* dl->rt will be used as flag for render face and */
+ /* CU_2D conflicts with R_NOPUNOFLIP */
+ dl->rt = nu->flag & ~CU_2D;
+
+ data = dl->verts;
+ dl->type = DL_SURF;
+
+ dl->parts = (nu->pntsu * resolu); /* in reverse, because makeNurbfaces works that way */
+ dl->nr = (nu->pntsv * resolv);
+ if (nu->flagv & CU_NURB_CYCLIC)
+ dl->flag |= DL_CYCL_U; /* reverse too! */
+ if (nu->flagu & CU_NURB_CYCLIC)
+ dl->flag |= DL_CYCL_V;
+
+ BKE_nurb_makeFaces(nu, data, 0, resolu, resolv);
+
+ /* gl array drawing: using indices */
+ displist_surf_indices(dl);
+ }
+ }
+ }
+
+ if (!for_orco) {
+ BKE_nurbList_duplicate(&ob->runtime.curve_cache->deformed_nurbs, &nubase);
+ curve_calc_modifiers_post(
+ depsgraph, scene, ob, &nubase, dispbase, r_final, for_render, use_render_resolution);
+ }
+
+ BKE_nurbList_free(&nubase);
}
-static void rotateBevelPiece(Curve *cu, BevPoint *bevp, BevPoint *nbevp, DispList *dlb, float bev_blend, float widfac, float fac, float **r_data)
+static void rotateBevelPiece(Curve *cu,
+ BevPoint *bevp,
+ BevPoint *nbevp,
+ DispList *dlb,
+ float bev_blend,
+ float widfac,
+ float fac,
+ float **r_data)
{
- float *fp, *data = *r_data;
- int b;
-
- fp = dlb->verts;
- for (b = 0; b < dlb->nr; b++, fp += 3, data += 3) {
- if (cu->flag & CU_3D) {
- float vec[3], quat[4];
-
- vec[0] = fp[1] + widfac;
- vec[1] = fp[2];
- vec[2] = 0.0;
-
- if (nbevp == NULL) {
- copy_v3_v3(data, bevp->vec);
- copy_qt_qt(quat, bevp->quat);
- }
- else {
- interp_v3_v3v3(data, bevp->vec, nbevp->vec, bev_blend);
- interp_qt_qtqt(quat, bevp->quat, nbevp->quat, bev_blend);
- }
-
- mul_qt_v3(quat, vec);
-
- data[0] += fac * vec[0];
- data[1] += fac * vec[1];
- data[2] += fac * vec[2];
- }
- else {
- float sina, cosa;
-
- if (nbevp == NULL) {
- copy_v3_v3(data, bevp->vec);
- sina = bevp->sina;
- cosa = bevp->cosa;
- }
- else {
- interp_v3_v3v3(data, bevp->vec, nbevp->vec, bev_blend);
-
- /* perhaps we need to interpolate angles instead. but the thing is
- * cosa and sina are not actually sine and cosine
- */
- sina = nbevp->sina * bev_blend + bevp->sina * (1.0f - bev_blend);
- cosa = nbevp->cosa * bev_blend + bevp->cosa * (1.0f - bev_blend);
- }
-
- data[0] += fac * (widfac + fp[1]) * sina;
- data[1] += fac * (widfac + fp[1]) * cosa;
- data[2] += fac * fp[2];
- }
- }
-
- *r_data = data;
+ float *fp, *data = *r_data;
+ int b;
+
+ fp = dlb->verts;
+ for (b = 0; b < dlb->nr; b++, fp += 3, data += 3) {
+ if (cu->flag & CU_3D) {
+ float vec[3], quat[4];
+
+ vec[0] = fp[1] + widfac;
+ vec[1] = fp[2];
+ vec[2] = 0.0;
+
+ if (nbevp == NULL) {
+ copy_v3_v3(data, bevp->vec);
+ copy_qt_qt(quat, bevp->quat);
+ }
+ else {
+ interp_v3_v3v3(data, bevp->vec, nbevp->vec, bev_blend);
+ interp_qt_qtqt(quat, bevp->quat, nbevp->quat, bev_blend);
+ }
+
+ mul_qt_v3(quat, vec);
+
+ data[0] += fac * vec[0];
+ data[1] += fac * vec[1];
+ data[2] += fac * vec[2];
+ }
+ else {
+ float sina, cosa;
+
+ if (nbevp == NULL) {
+ copy_v3_v3(data, bevp->vec);
+ sina = bevp->sina;
+ cosa = bevp->cosa;
+ }
+ else {
+ interp_v3_v3v3(data, bevp->vec, nbevp->vec, bev_blend);
+
+ /* perhaps we need to interpolate angles instead. but the thing is
+ * cosa and sina are not actually sine and cosine
+ */
+ sina = nbevp->sina * bev_blend + bevp->sina * (1.0f - bev_blend);
+ cosa = nbevp->cosa * bev_blend + bevp->cosa * (1.0f - bev_blend);
+ }
+
+ data[0] += fac * (widfac + fp[1]) * sina;
+ data[1] += fac * (widfac + fp[1]) * cosa;
+ data[2] += fac * fp[2];
+ }
+ }
+
+ *r_data = data;
}
static void fillBevelCap(Nurb *nu, DispList *dlb, float *prev_fp, ListBase *dispbase)
{
- DispList *dl;
+ DispList *dl;
- dl = MEM_callocN(sizeof(DispList), "makeDispListbev2");
- dl->verts = MEM_mallocN(sizeof(float[3]) * dlb->nr, "dlverts");
- memcpy(dl->verts, prev_fp, 3 * sizeof(float) * dlb->nr);
+ dl = MEM_callocN(sizeof(DispList), "makeDispListbev2");
+ dl->verts = MEM_mallocN(sizeof(float[3]) * dlb->nr, "dlverts");
+ memcpy(dl->verts, prev_fp, 3 * sizeof(float) * dlb->nr);
- dl->type = DL_POLY;
+ dl->type = DL_POLY;
- dl->parts = 1;
- dl->nr = dlb->nr;
- dl->col = nu->mat_nr;
- dl->charidx = nu->charidx;
+ dl->parts = 1;
+ dl->nr = dlb->nr;
+ dl->col = nu->mat_nr;
+ dl->charidx = nu->charidx;
- /* dl->rt will be used as flag for render face and */
- /* CU_2D conflicts with R_NOPUNOFLIP */
- dl->rt = nu->flag & ~CU_2D;
+ /* dl->rt will be used as flag for render face and */
+ /* CU_2D conflicts with R_NOPUNOFLIP */
+ dl->rt = nu->flag & ~CU_2D;
- BLI_addtail(dispbase, dl);
+ BLI_addtail(dispbase, dl);
}
-static void calc_bevfac_segment_mapping(BevList *bl, float bevfac, float spline_length, int *r_bev, float *r_blend)
+static void calc_bevfac_segment_mapping(
+ BevList *bl, float bevfac, float spline_length, int *r_bev, float *r_blend)
{
- float normlen, normsum = 0.0f;
- float *seglen = bl->seglen;
- int *segbevcount = bl->segbevcount;
- int bevcount = 0, nr = bl->nr;
-
- float bev_fl = bevfac * (bl->nr - 1);
- *r_bev = (int)bev_fl;
-
- while (bevcount < nr - 1) {
- normlen = *seglen / spline_length;
- if (normsum + normlen > bevfac) {
- bev_fl = bevcount + (bevfac - normsum) / normlen * *segbevcount;
- *r_bev = (int) bev_fl;
- *r_blend = bev_fl - *r_bev;
- break;
- }
- normsum += normlen;
- bevcount += *segbevcount;
- segbevcount++;
- seglen++;
- }
+ float normlen, normsum = 0.0f;
+ float *seglen = bl->seglen;
+ int *segbevcount = bl->segbevcount;
+ int bevcount = 0, nr = bl->nr;
+
+ float bev_fl = bevfac * (bl->nr - 1);
+ *r_bev = (int)bev_fl;
+
+ while (bevcount < nr - 1) {
+ normlen = *seglen / spline_length;
+ if (normsum + normlen > bevfac) {
+ bev_fl = bevcount + (bevfac - normsum) / normlen * *segbevcount;
+ *r_bev = (int)bev_fl;
+ *r_blend = bev_fl - *r_bev;
+ break;
+ }
+ normsum += normlen;
+ bevcount += *segbevcount;
+ segbevcount++;
+ seglen++;
+ }
}
-static void calc_bevfac_spline_mapping(BevList *bl, float bevfac,
- float spline_length,
- int *r_bev, float *r_blend)
+static void calc_bevfac_spline_mapping(
+ BevList *bl, float bevfac, float spline_length, int *r_bev, float *r_blend)
{
- const float len_target = bevfac * spline_length;
- BevPoint *bevp = bl->bevpoints;
- float len_next = 0.0f, len = 0.0f;
- int i = 0, nr = bl->nr;
-
- while (nr--) {
- bevp++;
- len_next = len + bevp->offset;
- if (len_next > len_target) {
- break;
- }
- len = len_next;
- i++;
- }
-
- *r_bev = i;
- *r_blend = (len_target - len) / bevp->offset;
+ const float len_target = bevfac * spline_length;
+ BevPoint *bevp = bl->bevpoints;
+ float len_next = 0.0f, len = 0.0f;
+ int i = 0, nr = bl->nr;
+
+ while (nr--) {
+ bevp++;
+ len_next = len + bevp->offset;
+ if (len_next > len_target) {
+ break;
+ }
+ len = len_next;
+ i++;
+ }
+
+ *r_bev = i;
+ *r_blend = (len_target - len) / bevp->offset;
}
-static void calc_bevfac_mapping_default(BevList *bl,
- int *r_start, float *r_firstblend,
- int *r_steps, float *r_lastblend)
+static void calc_bevfac_mapping_default(
+ BevList *bl, int *r_start, float *r_firstblend, int *r_steps, float *r_lastblend)
{
- *r_start = 0;
- *r_steps = bl->nr;
- *r_firstblend = 1.0f;
- *r_lastblend = 1.0f;
+ *r_start = 0;
+ *r_steps = bl->nr;
+ *r_firstblend = 1.0f;
+ *r_lastblend = 1.0f;
}
-static void calc_bevfac_mapping(Curve *cu, BevList *bl, Nurb *nu,
- int *r_start, float *r_firstblend, int *r_steps, float *r_lastblend)
+static void calc_bevfac_mapping(Curve *cu,
+ BevList *bl,
+ Nurb *nu,
+ int *r_start,
+ float *r_firstblend,
+ int *r_steps,
+ float *r_lastblend)
{
- float tmpf, total_length = 0.0f;
- int end = 0, i;
-
- if ((BKE_nurb_check_valid_u(nu) == false) ||
- /* not essential, but skips unnecessary calculation */
- (min_ff(cu->bevfac1, cu->bevfac2) == 0.0f &&
- max_ff(cu->bevfac1, cu->bevfac2) == 1.0f))
- {
- calc_bevfac_mapping_default(bl, r_start, r_firstblend, r_steps, r_lastblend);
- return;
- }
-
- if (ELEM(cu->bevfac1_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE) ||
- ELEM(cu->bevfac2_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE))
- {
- for (i = 0; i < SEGMENTSU(nu); i++) {
- total_length += bl->seglen[i];
- }
- }
-
- switch (cu->bevfac1_mapping) {
- case CU_BEVFAC_MAP_RESOLU:
- {
- const float start_fl = cu->bevfac1 * (bl->nr - 1);
- *r_start = (int)start_fl;
- *r_firstblend = 1.0f - (start_fl - (*r_start));
- break;
- }
- case CU_BEVFAC_MAP_SEGMENT:
- {
- calc_bevfac_segment_mapping(bl, cu->bevfac1, total_length, r_start, r_firstblend);
- *r_firstblend = 1.0f - *r_firstblend;
- break;
- }
- case CU_BEVFAC_MAP_SPLINE:
- {
- calc_bevfac_spline_mapping(bl, cu->bevfac1, total_length, r_start, r_firstblend);
- *r_firstblend = 1.0f - *r_firstblend;
- break;
- }
- }
-
- switch (cu->bevfac2_mapping) {
- case CU_BEVFAC_MAP_RESOLU:
- {
- const float end_fl = cu->bevfac2 * (bl->nr - 1);
- end = (int)end_fl;
-
- *r_steps = 2 + end - *r_start;
- *r_lastblend = end_fl - end;
- break;
- }
- case CU_BEVFAC_MAP_SEGMENT:
- {
- calc_bevfac_segment_mapping(bl, cu->bevfac2, total_length, &end, r_lastblend);
- *r_steps = end - *r_start + 2;
- break;
- }
- case CU_BEVFAC_MAP_SPLINE:
- {
- calc_bevfac_spline_mapping(bl, cu->bevfac2, total_length, &end, r_lastblend);
- *r_steps = end - *r_start + 2;
- break;
- }
- }
-
- if (end < *r_start || (end == *r_start && *r_lastblend < 1.0f - *r_firstblend )) {
- SWAP(int, *r_start, end);
- tmpf = *r_lastblend;
- *r_lastblend = 1.0f - *r_firstblend;
- *r_firstblend = 1.0f - tmpf;
- *r_steps = end - *r_start + 2;
- }
-
- if (*r_start + *r_steps > bl->nr) {
- *r_steps = bl->nr - *r_start;
- *r_lastblend = 1.0f;
- }
+ float tmpf, total_length = 0.0f;
+ int end = 0, i;
+
+ if ((BKE_nurb_check_valid_u(nu) == false) ||
+ /* not essential, but skips unnecessary calculation */
+ (min_ff(cu->bevfac1, cu->bevfac2) == 0.0f && max_ff(cu->bevfac1, cu->bevfac2) == 1.0f)) {
+ calc_bevfac_mapping_default(bl, r_start, r_firstblend, r_steps, r_lastblend);
+ return;
+ }
+
+ if (ELEM(cu->bevfac1_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE) ||
+ ELEM(cu->bevfac2_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE)) {
+ for (i = 0; i < SEGMENTSU(nu); i++) {
+ total_length += bl->seglen[i];
+ }
+ }
+
+ switch (cu->bevfac1_mapping) {
+ case CU_BEVFAC_MAP_RESOLU: {
+ const float start_fl = cu->bevfac1 * (bl->nr - 1);
+ *r_start = (int)start_fl;
+ *r_firstblend = 1.0f - (start_fl - (*r_start));
+ break;
+ }
+ case CU_BEVFAC_MAP_SEGMENT: {
+ calc_bevfac_segment_mapping(bl, cu->bevfac1, total_length, r_start, r_firstblend);
+ *r_firstblend = 1.0f - *r_firstblend;
+ break;
+ }
+ case CU_BEVFAC_MAP_SPLINE: {
+ calc_bevfac_spline_mapping(bl, cu->bevfac1, total_length, r_start, r_firstblend);
+ *r_firstblend = 1.0f - *r_firstblend;
+ break;
+ }
+ }
+
+ switch (cu->bevfac2_mapping) {
+ case CU_BEVFAC_MAP_RESOLU: {
+ const float end_fl = cu->bevfac2 * (bl->nr - 1);
+ end = (int)end_fl;
+
+ *r_steps = 2 + end - *r_start;
+ *r_lastblend = end_fl - end;
+ break;
+ }
+ case CU_BEVFAC_MAP_SEGMENT: {
+ calc_bevfac_segment_mapping(bl, cu->bevfac2, total_length, &end, r_lastblend);
+ *r_steps = end - *r_start + 2;
+ break;
+ }
+ case CU_BEVFAC_MAP_SPLINE: {
+ calc_bevfac_spline_mapping(bl, cu->bevfac2, total_length, &end, r_lastblend);
+ *r_steps = end - *r_start + 2;
+ break;
+ }
+ }
+
+ if (end < *r_start || (end == *r_start && *r_lastblend < 1.0f - *r_firstblend)) {
+ SWAP(int, *r_start, end);
+ tmpf = *r_lastblend;
+ *r_lastblend = 1.0f - *r_firstblend;
+ *r_firstblend = 1.0f - tmpf;
+ *r_steps = end - *r_start + 2;
+ }
+
+ if (*r_start + *r_steps > bl->nr) {
+ *r_steps = bl->nr - *r_start;
+ *r_lastblend = 1.0f;
+ }
}
-static void do_makeDispListCurveTypes(
- Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase,
- const bool for_render, const bool for_orco, const bool use_render_resolution,
- LinkNode *ob_cyclic_list,
- Mesh **r_final)
+static void do_makeDispListCurveTypes(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ ListBase *dispbase,
+ const bool for_render,
+ const bool for_orco,
+ const bool use_render_resolution,
+ LinkNode *ob_cyclic_list,
+ Mesh **r_final)
{
- Curve *cu = ob->data;
-
- /* we do allow duplis... this is only displist on curve level */
- if (!ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT)) return;
-
- if (ob->type == OB_SURF) {
- BKE_displist_make_surf(depsgraph, scene, ob, dispbase, r_final, for_render, for_orco, use_render_resolution);
- }
- else if (ELEM(ob->type, OB_CURVE, OB_FONT)) {
- ListBase dlbev;
- ListBase nubase = {NULL, NULL};
-
- BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev);
-
- /* We only re-evaluate path if evaluation is not happening for orco.
- * If the calculation happens for orco, we should never free data which
- * was needed before and only not needed for orco calculation.
- */
- if (!for_orco) {
- if (ob->runtime.curve_cache->path) free_path(ob->runtime.curve_cache->path);
- ob->runtime.curve_cache->path = NULL;
- }
-
- if (ob->type == OB_FONT) {
- BKE_vfont_to_curve_nubase(ob, FO_EDIT, &nubase);
- }
- else {
- BKE_nurbList_duplicate(&nubase, BKE_curve_nurbs_get(cu));
- }
-
- if (!for_orco)
- curve_calc_modifiers_pre(depsgraph, scene, ob, &nubase, for_render, use_render_resolution);
-
- BKE_curve_bevelList_make(ob, &nubase, use_render_resolution);
-
- /* If curve has no bevel will return nothing */
- BKE_curve_bevel_make(
- depsgraph, scene, ob, &dlbev, for_render, use_render_resolution,
- ob_cyclic_list);
-
- /* no bevel or extrude, and no width correction? */
- if (!dlbev.first && cu->width == 1.0f) {
- curve_to_displist(cu, &nubase, dispbase, for_render, use_render_resolution);
- }
- else {
- float widfac = cu->width - 1.0f;
- BevList *bl = ob->runtime.curve_cache->bev.first;
- Nurb *nu = nubase.first;
-
- for (; bl && nu; bl = bl->next, nu = nu->next) {
- DispList *dl;
- float *data;
- int a;
-
- if (bl->nr) { /* blank bevel lists can happen */
-
- /* exception handling; curve without bevel or extrude, with width correction */
- if (BLI_listbase_is_empty(&dlbev)) {
- BevPoint *bevp;
- dl = MEM_callocN(sizeof(DispList), "makeDispListbev");
- dl->verts = MEM_mallocN(sizeof(float[3]) * bl->nr, "dlverts");
- BLI_addtail(dispbase, dl);
-
- if (bl->poly != -1) dl->type = DL_POLY;
- else dl->type = DL_SEGM;
-
- if (dl->type == DL_SEGM) dl->flag = (DL_FRONT_CURVE | DL_BACK_CURVE);
-
- dl->parts = 1;
- dl->nr = bl->nr;
- dl->col = nu->mat_nr;
- dl->charidx = nu->charidx;
-
- /* dl->rt will be used as flag for render face and */
- /* CU_2D conflicts with R_NOPUNOFLIP */
- dl->rt = nu->flag & ~CU_2D;
-
- a = dl->nr;
- bevp = bl->bevpoints;
- data = dl->verts;
- while (a--) {
- data[0] = bevp->vec[0] + widfac * bevp->sina;
- data[1] = bevp->vec[1] + widfac * bevp->cosa;
- data[2] = bevp->vec[2];
- bevp++;
- data += 3;
- }
- }
- else {
- DispList *dlb;
- ListBase bottom_capbase = {NULL, NULL};
- ListBase top_capbase = {NULL, NULL};
- float bottom_no[3] = {0.0f};
- float top_no[3] = {0.0f};
- float firstblend = 0.0f, lastblend = 0.0f;
- int i, start, steps = 0;
-
- if (nu->flagu & CU_NURB_CYCLIC) {
- calc_bevfac_mapping_default(bl,
- &start, &firstblend, &steps, &lastblend);
- }
- else {
- if (fabsf(cu->bevfac2 - cu->bevfac1) < FLT_EPSILON) {
- continue;
- }
-
- calc_bevfac_mapping(cu, bl, nu, &start, &firstblend, &steps, &lastblend);
- }
-
- for (dlb = dlbev.first; dlb; dlb = dlb->next) {
- BevPoint *bevp_first, *bevp_last;
- BevPoint *bevp;
-
- /* for each part of the bevel use a separate displblock */
- dl = MEM_callocN(sizeof(DispList), "makeDispListbev1");
- dl->verts = data = MEM_mallocN(sizeof(float[3]) * dlb->nr * steps, "dlverts");
- BLI_addtail(dispbase, dl);
-
- dl->type = DL_SURF;
-
- dl->flag = dlb->flag & (DL_FRONT_CURVE | DL_BACK_CURVE);
- if (dlb->type == DL_POLY) {
- dl->flag |= DL_CYCL_U;
- }
- if ((bl->poly >= 0) && (steps > 2)) {
- dl->flag |= DL_CYCL_V;
- }
-
- dl->parts = steps;
- dl->nr = dlb->nr;
- dl->col = nu->mat_nr;
- dl->charidx = nu->charidx;
-
- /* dl->rt will be used as flag for render face and */
- /* CU_2D conflicts with R_NOPUNOFLIP */
- dl->rt = nu->flag & ~CU_2D;
-
- dl->bevel_split = BLI_BITMAP_NEW(steps, "bevel_split");
-
- /* for each point of poly make a bevel piece */
- bevp_first = bl->bevpoints;
- bevp_last = &bl->bevpoints[bl->nr - 1];
- bevp = &bl->bevpoints[start];
- for (i = start, a = 0; a < steps; i++, bevp++, a++) {
- float fac = 1.0;
- float *cur_data = data;
-
- if (cu->taperobj == NULL) {
- fac = bevp->radius;
- }
- else {
- float len, taper_fac;
-
- if (cu->flag & CU_MAP_TAPER) {
- len = (steps - 3) + firstblend + lastblend;
-
- if (a == 0)
- taper_fac = 0.0f;
- else if (a == steps - 1)
- taper_fac = 1.0f;
- else
- taper_fac = ((float) a - (1.0f - firstblend)) / len;
- }
- else {
- len = bl->nr - 1;
- taper_fac = (float) i / len;
-
- if (a == 0)
- taper_fac += (1.0f - firstblend) / len;
- else if (a == steps - 1)
- taper_fac -= (1.0f - lastblend) / len;
- }
-
- fac = displist_calc_taper(depsgraph, scene, cu->taperobj, taper_fac);
- }
-
- if (bevp->split_tag) {
- BLI_BITMAP_ENABLE(dl->bevel_split, a);
- }
-
- /* rotate bevel piece and write in data */
- if ((a == 0) && (bevp != bevp_last)) {
- rotateBevelPiece(cu, bevp, bevp + 1, dlb, 1.0f - firstblend, widfac, fac, &data);
- }
- else if ((a == steps - 1) && (bevp != bevp_first) ) {
- rotateBevelPiece(cu, bevp, bevp - 1, dlb, 1.0f - lastblend, widfac, fac, &data);
- }
- else {
- rotateBevelPiece(cu, bevp, NULL, dlb, 0.0f, widfac, fac, &data);
- }
-
- if (cu->bevobj && (cu->flag & CU_FILL_CAPS) && !(nu->flagu & CU_NURB_CYCLIC)) {
- if (a == 1) {
- fillBevelCap(nu, dlb, cur_data - 3 * dlb->nr, &bottom_capbase);
- negate_v3_v3(bottom_no, bevp->dir);
- }
- if (a == steps - 1) {
- fillBevelCap(nu, dlb, cur_data, &top_capbase);
- copy_v3_v3(top_no, bevp->dir);
- }
- }
- }
-
- /* gl array drawing: using indices */
- displist_surf_indices(dl);
- }
-
- if (bottom_capbase.first) {
- BKE_displist_fill(&bottom_capbase, dispbase, bottom_no, false);
- BKE_displist_fill(&top_capbase, dispbase, top_no, false);
- BKE_displist_free(&bottom_capbase);
- BKE_displist_free(&top_capbase);
- }
- }
- }
-
- }
- BKE_displist_free(&dlbev);
- }
-
- if (!(cu->flag & CU_DEFORM_FILL)) {
- curve_to_filledpoly(cu, &nubase, dispbase);
- }
-
- if (!for_orco) {
- if ((cu->flag & CU_PATH) ||
- DEG_get_eval_flags_for_id(depsgraph, &ob->id) & DAG_EVAL_NEED_CURVE_PATH)
- {
- calc_curvepath(ob, &nubase);
- }
- }
-
- if (!for_orco) {
- BKE_nurbList_duplicate(&ob->runtime.curve_cache->deformed_nurbs, &nubase);
- curve_calc_modifiers_post(depsgraph, scene, ob, &nubase, dispbase, r_final, for_render, use_render_resolution);
- }
-
- if (cu->flag & CU_DEFORM_FILL && !ob->runtime.mesh_eval) {
- curve_to_filledpoly(cu, &nubase, dispbase);
- }
-
- BKE_nurbList_free(&nubase);
- }
+ Curve *cu = ob->data;
+
+ /* we do allow duplis... this is only displist on curve level */
+ if (!ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT))
+ return;
+
+ if (ob->type == OB_SURF) {
+ BKE_displist_make_surf(
+ depsgraph, scene, ob, dispbase, r_final, for_render, for_orco, use_render_resolution);
+ }
+ else if (ELEM(ob->type, OB_CURVE, OB_FONT)) {
+ ListBase dlbev;
+ ListBase nubase = {NULL, NULL};
+
+ BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev);
+
+ /* We only re-evaluate path if evaluation is not happening for orco.
+ * If the calculation happens for orco, we should never free data which
+ * was needed before and only not needed for orco calculation.
+ */
+ if (!for_orco) {
+ if (ob->runtime.curve_cache->path)
+ free_path(ob->runtime.curve_cache->path);
+ ob->runtime.curve_cache->path = NULL;
+ }
+
+ if (ob->type == OB_FONT) {
+ BKE_vfont_to_curve_nubase(ob, FO_EDIT, &nubase);
+ }
+ else {
+ BKE_nurbList_duplicate(&nubase, BKE_curve_nurbs_get(cu));
+ }
+
+ if (!for_orco)
+ curve_calc_modifiers_pre(depsgraph, scene, ob, &nubase, for_render, use_render_resolution);
+
+ BKE_curve_bevelList_make(ob, &nubase, use_render_resolution);
+
+ /* If curve has no bevel will return nothing */
+ BKE_curve_bevel_make(
+ depsgraph, scene, ob, &dlbev, for_render, use_render_resolution, ob_cyclic_list);
+
+ /* no bevel or extrude, and no width correction? */
+ if (!dlbev.first && cu->width == 1.0f) {
+ curve_to_displist(cu, &nubase, dispbase, for_render, use_render_resolution);
+ }
+ else {
+ float widfac = cu->width - 1.0f;
+ BevList *bl = ob->runtime.curve_cache->bev.first;
+ Nurb *nu = nubase.first;
+
+ for (; bl && nu; bl = bl->next, nu = nu->next) {
+ DispList *dl;
+ float *data;
+ int a;
+
+ if (bl->nr) { /* blank bevel lists can happen */
+
+ /* exception handling; curve without bevel or extrude, with width correction */
+ if (BLI_listbase_is_empty(&dlbev)) {
+ BevPoint *bevp;
+ dl = MEM_callocN(sizeof(DispList), "makeDispListbev");
+ dl->verts = MEM_mallocN(sizeof(float[3]) * bl->nr, "dlverts");
+ BLI_addtail(dispbase, dl);
+
+ if (bl->poly != -1)
+ dl->type = DL_POLY;
+ else
+ dl->type = DL_SEGM;
+
+ if (dl->type == DL_SEGM)
+ dl->flag = (DL_FRONT_CURVE | DL_BACK_CURVE);
+
+ dl->parts = 1;
+ dl->nr = bl->nr;
+ dl->col = nu->mat_nr;
+ dl->charidx = nu->charidx;
+
+ /* dl->rt will be used as flag for render face and */
+ /* CU_2D conflicts with R_NOPUNOFLIP */
+ dl->rt = nu->flag & ~CU_2D;
+
+ a = dl->nr;
+ bevp = bl->bevpoints;
+ data = dl->verts;
+ while (a--) {
+ data[0] = bevp->vec[0] + widfac * bevp->sina;
+ data[1] = bevp->vec[1] + widfac * bevp->cosa;
+ data[2] = bevp->vec[2];
+ bevp++;
+ data += 3;
+ }
+ }
+ else {
+ DispList *dlb;
+ ListBase bottom_capbase = {NULL, NULL};
+ ListBase top_capbase = {NULL, NULL};
+ float bottom_no[3] = {0.0f};
+ float top_no[3] = {0.0f};
+ float firstblend = 0.0f, lastblend = 0.0f;
+ int i, start, steps = 0;
+
+ if (nu->flagu & CU_NURB_CYCLIC) {
+ calc_bevfac_mapping_default(bl, &start, &firstblend, &steps, &lastblend);
+ }
+ else {
+ if (fabsf(cu->bevfac2 - cu->bevfac1) < FLT_EPSILON) {
+ continue;
+ }
+
+ calc_bevfac_mapping(cu, bl, nu, &start, &firstblend, &steps, &lastblend);
+ }
+
+ for (dlb = dlbev.first; dlb; dlb = dlb->next) {
+ BevPoint *bevp_first, *bevp_last;
+ BevPoint *bevp;
+
+ /* for each part of the bevel use a separate displblock */
+ dl = MEM_callocN(sizeof(DispList), "makeDispListbev1");
+ dl->verts = data = MEM_mallocN(sizeof(float[3]) * dlb->nr * steps, "dlverts");
+ BLI_addtail(dispbase, dl);
+
+ dl->type = DL_SURF;
+
+ dl->flag = dlb->flag & (DL_FRONT_CURVE | DL_BACK_CURVE);
+ if (dlb->type == DL_POLY) {
+ dl->flag |= DL_CYCL_U;
+ }
+ if ((bl->poly >= 0) && (steps > 2)) {
+ dl->flag |= DL_CYCL_V;
+ }
+
+ dl->parts = steps;
+ dl->nr = dlb->nr;
+ dl->col = nu->mat_nr;
+ dl->charidx = nu->charidx;
+
+ /* dl->rt will be used as flag for render face and */
+ /* CU_2D conflicts with R_NOPUNOFLIP */
+ dl->rt = nu->flag & ~CU_2D;
+
+ dl->bevel_split = BLI_BITMAP_NEW(steps, "bevel_split");
+
+ /* for each point of poly make a bevel piece */
+ bevp_first = bl->bevpoints;
+ bevp_last = &bl->bevpoints[bl->nr - 1];
+ bevp = &bl->bevpoints[start];
+ for (i = start, a = 0; a < steps; i++, bevp++, a++) {
+ float fac = 1.0;
+ float *cur_data = data;
+
+ if (cu->taperobj == NULL) {
+ fac = bevp->radius;
+ }
+ else {
+ float len, taper_fac;
+
+ if (cu->flag & CU_MAP_TAPER) {
+ len = (steps - 3) + firstblend + lastblend;
+
+ if (a == 0)
+ taper_fac = 0.0f;
+ else if (a == steps - 1)
+ taper_fac = 1.0f;
+ else
+ taper_fac = ((float)a - (1.0f - firstblend)) / len;
+ }
+ else {
+ len = bl->nr - 1;
+ taper_fac = (float)i / len;
+
+ if (a == 0)
+ taper_fac += (1.0f - firstblend) / len;
+ else if (a == steps - 1)
+ taper_fac -= (1.0f - lastblend) / len;
+ }
+
+ fac = displist_calc_taper(depsgraph, scene, cu->taperobj, taper_fac);
+ }
+
+ if (bevp->split_tag) {
+ BLI_BITMAP_ENABLE(dl->bevel_split, a);
+ }
+
+ /* rotate bevel piece and write in data */
+ if ((a == 0) && (bevp != bevp_last)) {
+ rotateBevelPiece(cu, bevp, bevp + 1, dlb, 1.0f - firstblend, widfac, fac, &data);
+ }
+ else if ((a == steps - 1) && (bevp != bevp_first)) {
+ rotateBevelPiece(cu, bevp, bevp - 1, dlb, 1.0f - lastblend, widfac, fac, &data);
+ }
+ else {
+ rotateBevelPiece(cu, bevp, NULL, dlb, 0.0f, widfac, fac, &data);
+ }
+
+ if (cu->bevobj && (cu->flag & CU_FILL_CAPS) && !(nu->flagu & CU_NURB_CYCLIC)) {
+ if (a == 1) {
+ fillBevelCap(nu, dlb, cur_data - 3 * dlb->nr, &bottom_capbase);
+ negate_v3_v3(bottom_no, bevp->dir);
+ }
+ if (a == steps - 1) {
+ fillBevelCap(nu, dlb, cur_data, &top_capbase);
+ copy_v3_v3(top_no, bevp->dir);
+ }
+ }
+ }
+
+ /* gl array drawing: using indices */
+ displist_surf_indices(dl);
+ }
+
+ if (bottom_capbase.first) {
+ BKE_displist_fill(&bottom_capbase, dispbase, bottom_no, false);
+ BKE_displist_fill(&top_capbase, dispbase, top_no, false);
+ BKE_displist_free(&bottom_capbase);
+ BKE_displist_free(&top_capbase);
+ }
+ }
+ }
+ }
+ BKE_displist_free(&dlbev);
+ }
+
+ if (!(cu->flag & CU_DEFORM_FILL)) {
+ curve_to_filledpoly(cu, &nubase, dispbase);
+ }
+
+ if (!for_orco) {
+ if ((cu->flag & CU_PATH) ||
+ DEG_get_eval_flags_for_id(depsgraph, &ob->id) & DAG_EVAL_NEED_CURVE_PATH) {
+ calc_curvepath(ob, &nubase);
+ }
+ }
+
+ if (!for_orco) {
+ BKE_nurbList_duplicate(&ob->runtime.curve_cache->deformed_nurbs, &nubase);
+ curve_calc_modifiers_post(
+ depsgraph, scene, ob, &nubase, dispbase, r_final, for_render, use_render_resolution);
+ }
+
+ if (cu->flag & CU_DEFORM_FILL && !ob->runtime.mesh_eval) {
+ curve_to_filledpoly(cu, &nubase, dispbase);
+ }
+
+ BKE_nurbList_free(&nubase);
+ }
}
-void BKE_displist_make_curveTypes(
- Depsgraph *depsgraph, Scene *scene, Object *ob, const bool for_render, const bool for_orco,
- LinkNode *ob_cyclic_list)
+void BKE_displist_make_curveTypes(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ const bool for_render,
+ const bool for_orco,
+ LinkNode *ob_cyclic_list)
{
- ListBase *dispbase;
+ ListBase *dispbase;
- /* The same check for duplis as in do_makeDispListCurveTypes.
- * Happens when curve used for constraint/bevel was converted to mesh.
- * check there is still needed for render displist and orco displists. */
- if (!ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT))
- return;
+ /* The same check for duplis as in do_makeDispListCurveTypes.
+ * Happens when curve used for constraint/bevel was converted to mesh.
+ * check there is still needed for render displist and orco displists. */
+ if (!ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT))
+ return;
- BKE_object_free_derived_caches(ob);
+ BKE_object_free_derived_caches(ob);
- if (!ob->runtime.curve_cache) {
- ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for curve types");
- }
+ if (!ob->runtime.curve_cache) {
+ ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for curve types");
+ }
- dispbase = &(ob->runtime.curve_cache->disp);
+ dispbase = &(ob->runtime.curve_cache->disp);
- do_makeDispListCurveTypes(
- depsgraph, scene, ob, dispbase, for_render, for_orco, false,
- ob_cyclic_list,
- &ob->runtime.mesh_eval);
+ do_makeDispListCurveTypes(depsgraph,
+ scene,
+ ob,
+ dispbase,
+ for_render,
+ for_orco,
+ false,
+ ob_cyclic_list,
+ &ob->runtime.mesh_eval);
- boundbox_displist_object(ob);
+ boundbox_displist_object(ob);
}
-void BKE_displist_make_curveTypes_forRender(
- Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase,
- Mesh **r_final, const bool for_orco,
- const bool use_render_resolution,
- LinkNode *ob_cyclic_list)
+void BKE_displist_make_curveTypes_forRender(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ ListBase *dispbase,
+ Mesh **r_final,
+ const bool for_orco,
+ const bool use_render_resolution,
+ LinkNode *ob_cyclic_list)
{
- if (ob->runtime.curve_cache == NULL) {
- ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve");
- }
-
- do_makeDispListCurveTypes(
- depsgraph, scene, ob, dispbase, true, for_orco, use_render_resolution,
- ob_cyclic_list,
- r_final);
+ if (ob->runtime.curve_cache == NULL) {
+ ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve");
+ }
+
+ do_makeDispListCurveTypes(depsgraph,
+ scene,
+ ob,
+ dispbase,
+ true,
+ for_orco,
+ use_render_resolution,
+ ob_cyclic_list,
+ r_final);
}
void BKE_displist_make_curveTypes_forOrco(
- Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase,
- LinkNode *ob_cyclic_list)
+ Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase, LinkNode *ob_cyclic_list)
{
- if (ob->runtime.curve_cache == NULL) {
- ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve");
- }
-
- do_makeDispListCurveTypes(
- depsgraph, scene, ob, dispbase, 1, 1, 1,
- ob_cyclic_list,
- NULL);
+ if (ob->runtime.curve_cache == NULL) {
+ ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve");
+ }
+
+ do_makeDispListCurveTypes(depsgraph, scene, ob, dispbase, 1, 1, 1, ob_cyclic_list, NULL);
}
void BKE_displist_minmax(ListBase *dispbase, float min[3], float max[3])
{
- DispList *dl;
- const float *vert;
- int a, tot = 0;
- int doit = 0;
-
- for (dl = dispbase->first; dl; dl = dl->next) {
- tot = (dl->type == DL_INDEX3) ? dl->nr : dl->nr * dl->parts;
- vert = dl->verts;
- for (a = 0; a < tot; a++, vert += 3) {
- minmax_v3v3_v3(min, max, vert);
- }
- doit |= (tot != 0);
- }
-
- if (!doit) {
- /* there's no geometry in displist, use zero-sized boundbox */
- zero_v3(min);
- zero_v3(max);
- }
+ DispList *dl;
+ const float *vert;
+ int a, tot = 0;
+ int doit = 0;
+
+ for (dl = dispbase->first; dl; dl = dl->next) {
+ tot = (dl->type == DL_INDEX3) ? dl->nr : dl->nr * dl->parts;
+ vert = dl->verts;
+ for (a = 0; a < tot; a++, vert += 3) {
+ minmax_v3v3_v3(min, max, vert);
+ }
+ doit |= (tot != 0);
+ }
+
+ if (!doit) {
+ /* there's no geometry in displist, use zero-sized boundbox */
+ zero_v3(min);
+ zero_v3(max);
+ }
}
/* this is confusing, there's also min_max_object, appplying the obmat... */
static void boundbox_displist_object(Object *ob)
{
- if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
- /* Curve's BB is already calculated as a part of modifier stack,
- * here we only calculate object BB based on final display list.
- */
-
- /* object's BB is calculated from final displist */
- if (ob->runtime.bb == NULL)
- ob->runtime.bb = MEM_callocN(sizeof(BoundBox), "boundbox");
-
- if (ob->runtime.mesh_eval) {
- BKE_object_boundbox_calc_from_mesh(ob, ob->runtime.mesh_eval);
- }
- else {
- float min[3], max[3];
-
- INIT_MINMAX(min, max);
- BKE_displist_minmax(&ob->runtime.curve_cache->disp, min, max);
- BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
-
- ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
- }
- }
+ if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
+ /* Curve's BB is already calculated as a part of modifier stack,
+ * here we only calculate object BB based on final display list.
+ */
+
+ /* object's BB is calculated from final displist */
+ if (ob->runtime.bb == NULL)
+ ob->runtime.bb = MEM_callocN(sizeof(BoundBox), "boundbox");
+
+ if (ob->runtime.mesh_eval) {
+ BKE_object_boundbox_calc_from_mesh(ob, ob->runtime.mesh_eval);
+ }
+ else {
+ float min[3], max[3];
+
+ INIT_MINMAX(min, max);
+ BKE_displist_minmax(&ob->runtime.curve_cache->disp, min, max);
+ BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
+
+ ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
+ }
+ }
}
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index aedc301af92..7bbdfa6c52d 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -48,7 +48,7 @@
#include "BKE_animsys.h"
#include "BKE_armature.h"
-#include "BKE_bvhutils.h" /* bvh tree */
+#include "BKE_bvhutils.h" /* bvh tree */
#include "BKE_collection.h"
#include "BKE_collision.h"
#include "BKE_colorband.h"
@@ -73,7 +73,7 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
-/* for image output */
+/* for image output */
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
@@ -107,8 +107,8 @@ static int neighX[8] = {1, 1, 0, -1, -1, -1, 0, 1};
static int neighY[8] = {0, 1, 1, 1, 0, -1, -1, -1};
/* Neighbor x/y list that prioritizes grid directions over diagonals */
-static int neighStraightX[8] = {1, 0, -1, 0, 1, -1, -1, 1};
-static int neighStraightY[8] = {0, 1, 0, -1, 1, 1, -1, -1};
+static int neighStraightX[8] = {1, 0, -1, 0, 1, -1, -1, 1};
+static int neighStraightY[8] = {0, 1, 0, -1, 1, 1, -1, -1};
/* subframe_updateObject() flags */
#define SUBFRAME_RECURSION 5
@@ -130,92 +130,94 @@ static int neighStraightY[8] = {0, 1, 0, -1, 1, 1, -1, -1};
#define MIN_WETNESS 0.001f
#define MAX_WETNESS 5.0f
-
/* dissolve inline function */
-BLI_INLINE void value_dissolve(float *r_value, const float time, const float scale, const bool is_log)
+BLI_INLINE void value_dissolve(float *r_value,
+ const float time,
+ const float scale,
+ const bool is_log)
{
- *r_value = (is_log) ?
- (*r_value) * (powf(MIN_WETNESS, 1.0f / (1.2f * time / scale))) :
- (*r_value) - 1.0f / time * scale;
+ *r_value = (is_log) ? (*r_value) * (powf(MIN_WETNESS, 1.0f / (1.2f * time / scale))) :
+ (*r_value) - 1.0f / time * scale;
}
-
/***************************** Internal Structs ***************************/
typedef struct Bounds2D {
- float min[2], max[2];
+ float min[2], max[2];
} Bounds2D;
typedef struct Bounds3D {
- float min[3], max[3];
- bool valid;
+ float min[3], max[3];
+ bool valid;
} Bounds3D;
typedef struct VolumeGrid {
- int dim[3];
- Bounds3D grid_bounds; /* whole grid bounds */
+ int dim[3];
+ Bounds3D grid_bounds; /* whole grid bounds */
- Bounds3D *bounds; /* (x*y*z) precalculated grid cell bounds */
- int *s_pos; /* (x*y*z) t_index begin id */
- int *s_num; /* (x*y*z) number of t_index points */
- int *t_index; /* actual surface point index, access: (s_pos + s_num) */
+ Bounds3D *bounds; /* (x*y*z) precalculated grid cell bounds */
+ int *s_pos; /* (x*y*z) t_index begin id */
+ int *s_num; /* (x*y*z) number of t_index points */
+ int *t_index; /* actual surface point index, access: (s_pos + s_num) */
- int *temp_t_index;
+ int *temp_t_index;
} VolumeGrid;
typedef struct Vec3f {
- float v[3];
+ float v[3];
} Vec3f;
typedef struct BakeAdjPoint {
- float dir[3]; /* vector pointing towards this neighbor */
- float dist; /* distance to */
+ float dir[3]; /* vector pointing towards this neighbor */
+ float dist; /* distance to */
} BakeAdjPoint;
/* Surface data used while processing a frame */
typedef struct PaintBakeNormal {
- float invNorm[3]; /* current pixel world-space inverted normal */
- float normal_scale; /* normal directional scale for displace mapping */
+ float invNorm[3]; /* current pixel world-space inverted normal */
+ float normal_scale; /* normal directional scale for displace mapping */
} PaintBakeNormal;
/* Temp surface data used to process a frame */
typedef struct PaintBakeData {
- /* point space data */
- PaintBakeNormal *bNormal;
- int *s_pos; /* index to start reading point sample realCoord */
- int *s_num; /* num of realCoord samples */
- Vec3f *realCoord; /* current pixel center world-space coordinates for each sample ordered as (s_pos + s_num) */
- Bounds3D mesh_bounds;
- float dim[3];
-
- /* adjacency info */
- BakeAdjPoint *bNeighs; /* current global neighbor distances and directions, if required */
- double average_dist;
- /* space partitioning */
- VolumeGrid *grid; /* space partitioning grid to optimize brush checks */
-
- /* velocity and movement */
- Vec3f *velocity; /* speed vector in global space movement per frame, if required */
- Vec3f *prev_velocity;
- float *brush_velocity; /* special temp data for post-p velocity based brushes like smudge
- * 3 float dir vec + 1 float str */
- MVert *prev_verts; /* copy of previous frame vertices. used to observe surface movement */
- float prev_obmat[4][4]; /* previous frame object matrix */
- int clear; /* flag to check if surface was cleared/reset -> have to redo velocity etc. */
+ /* point space data */
+ PaintBakeNormal *bNormal;
+ int *s_pos; /* index to start reading point sample realCoord */
+ int *s_num; /* num of realCoord samples */
+ Vec3f *
+ realCoord; /* current pixel center world-space coordinates for each sample ordered as (s_pos + s_num) */
+ Bounds3D mesh_bounds;
+ float dim[3];
+
+ /* adjacency info */
+ BakeAdjPoint *bNeighs; /* current global neighbor distances and directions, if required */
+ double average_dist;
+ /* space partitioning */
+ VolumeGrid *grid; /* space partitioning grid to optimize brush checks */
+
+ /* velocity and movement */
+ Vec3f *velocity; /* speed vector in global space movement per frame, if required */
+ Vec3f *prev_velocity;
+ float *brush_velocity; /* special temp data for post-p velocity based brushes like smudge
+ * 3 float dir vec + 1 float str */
+ MVert *prev_verts; /* copy of previous frame vertices. used to observe surface movement */
+ float prev_obmat[4][4]; /* previous frame object matrix */
+ int clear; /* flag to check if surface was cleared/reset -> have to redo velocity etc. */
} PaintBakeData;
/* UV Image sequence format point */
typedef struct PaintUVPoint {
- /* Pixel / mesh data */
- unsigned int tri_index, pixel_index; /* tri index on domain derived mesh */
- unsigned int v1, v2, v3; /* vertex indexes */
+ /* Pixel / mesh data */
+ unsigned int tri_index, pixel_index; /* tri index on domain derived mesh */
+ unsigned int v1, v2, v3; /* vertex indexes */
- unsigned int neighbour_pixel; /* If this pixel isn't uv mapped to any face, but it's neighboring pixel is */
+ unsigned int
+ neighbour_pixel; /* If this pixel isn't uv mapped to any face, but it's neighboring pixel is */
} PaintUVPoint;
typedef struct ImgSeqFormatData {
- PaintUVPoint *uv_p;
- Vec3f *barycentricWeights; /* b-weights for all pixel samples */
+ PaintUVPoint *uv_p;
+ Vec3f *barycentricWeights; /* b-weights for all pixel samples */
} ImgSeqFormatData;
/* adjacency data flags */
@@ -223,57 +225,56 @@ typedef struct ImgSeqFormatData {
#define ADJ_BORDER_PIXEL (1 << 1)
typedef struct PaintAdjData {
- int *n_target; /* array of neighboring point indexes, for single sample use (n_index + neigh_num) */
- int *n_index; /* index to start reading n_target for each point */
- int *n_num; /* num of neighs for each point */
- int *flags; /* vertex adjacency flags */
- int total_targets; /* size of n_target */
- int *border; /* indices of border pixels (only for texture paint) */
- int total_border; /* size of border */
+ int *
+ n_target; /* array of neighboring point indexes, for single sample use (n_index + neigh_num) */
+ int *n_index; /* index to start reading n_target for each point */
+ int *n_num; /* num of neighs for each point */
+ int *flags; /* vertex adjacency flags */
+ int total_targets; /* size of n_target */
+ int *border; /* indices of border pixels (only for texture paint) */
+ int total_border; /* size of border */
} PaintAdjData;
/************************* Runtime evaluation store ***************************/
void dynamicPaint_Modifier_free_runtime(DynamicPaintRuntime *runtime_data)
{
- if (runtime_data == NULL) {
- return;
- }
- if (runtime_data->canvas_mesh) {
- BKE_id_free(NULL, runtime_data->canvas_mesh);
- }
- if (runtime_data->brush_mesh) {
- BKE_id_free(NULL, runtime_data->brush_mesh);
- }
- MEM_freeN(runtime_data);
+ if (runtime_data == NULL) {
+ return;
+ }
+ if (runtime_data->canvas_mesh) {
+ BKE_id_free(NULL, runtime_data->canvas_mesh);
+ }
+ if (runtime_data->brush_mesh) {
+ BKE_id_free(NULL, runtime_data->brush_mesh);
+ }
+ MEM_freeN(runtime_data);
}
-static DynamicPaintRuntime *dynamicPaint_Modifier_runtime_ensure(
- DynamicPaintModifierData *pmd)
+static DynamicPaintRuntime *dynamicPaint_Modifier_runtime_ensure(DynamicPaintModifierData *pmd)
{
- if (pmd->modifier.runtime == NULL) {
- pmd->modifier.runtime = MEM_callocN(
- sizeof(DynamicPaintRuntime), "dynamic paint runtime");
- }
- return (DynamicPaintRuntime *)pmd->modifier.runtime;
+ if (pmd->modifier.runtime == NULL) {
+ pmd->modifier.runtime = MEM_callocN(sizeof(DynamicPaintRuntime), "dynamic paint runtime");
+ }
+ return (DynamicPaintRuntime *)pmd->modifier.runtime;
}
static Mesh *dynamicPaint_canvas_mesh_get(DynamicPaintCanvasSettings *canvas)
{
- if (canvas->pmd->modifier.runtime == NULL) {
- return NULL;
- }
- DynamicPaintRuntime *runtime_data = (DynamicPaintRuntime *)canvas->pmd->modifier.runtime;
- return runtime_data->canvas_mesh;
+ if (canvas->pmd->modifier.runtime == NULL) {
+ return NULL;
+ }
+ DynamicPaintRuntime *runtime_data = (DynamicPaintRuntime *)canvas->pmd->modifier.runtime;
+ return runtime_data->canvas_mesh;
}
static Mesh *dynamicPaint_brush_mesh_get(DynamicPaintBrushSettings *brush)
{
- if (brush->pmd->modifier.runtime == NULL) {
- return NULL;
- }
- DynamicPaintRuntime *runtime_data = (DynamicPaintRuntime *)brush->pmd->modifier.runtime;
- return runtime_data->brush_mesh;
+ if (brush->pmd->modifier.runtime == NULL) {
+ return NULL;
+ }
+ DynamicPaintRuntime *runtime_data = (DynamicPaintRuntime *)brush->pmd->modifier.runtime;
+ return runtime_data->brush_mesh;
}
/***************************** General Utils ******************************/
@@ -281,575 +282,580 @@ static Mesh *dynamicPaint_brush_mesh_get(DynamicPaintBrushSettings *brush)
/* Set canvas error string to display at the bake report */
static int setError(DynamicPaintCanvasSettings *canvas, const char *string)
{
- /* Add error to canvas ui info label */
- BLI_strncpy(canvas->error, string, sizeof(canvas->error));
- CLOG_STR_ERROR(&LOG, string);
- return 0;
+ /* Add error to canvas ui info label */
+ BLI_strncpy(canvas->error, string, sizeof(canvas->error));
+ CLOG_STR_ERROR(&LOG, string);
+ return 0;
}
/* Get number of surface points for cached types */
static int dynamicPaint_surfaceNumOfPoints(DynamicPaintSurface *surface)
{
- if (surface->format == MOD_DPAINT_SURFACE_F_PTEX) {
- return 0; /* not supported atm */
- }
- else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
- const Mesh *canvas_mesh = dynamicPaint_canvas_mesh_get(surface->canvas);
- return (canvas_mesh) ? canvas_mesh->totvert : 0;
- }
-
- return 0;
+ if (surface->format == MOD_DPAINT_SURFACE_F_PTEX) {
+ return 0; /* not supported atm */
+ }
+ else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
+ const Mesh *canvas_mesh = dynamicPaint_canvas_mesh_get(surface->canvas);
+ return (canvas_mesh) ? canvas_mesh->totvert : 0;
+ }
+
+ return 0;
}
/* checks whether surface's format/type has realtime preview */
bool dynamicPaint_surfaceHasColorPreview(DynamicPaintSurface *surface)
{
- if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
- return false;
- }
- else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
- return !ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE);
- }
-
- return true;
+ if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
+ return false;
+ }
+ else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
+ return !ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE);
+ }
+
+ return true;
}
/* get currently active surface (in user interface) */
DynamicPaintSurface *get_activeSurface(DynamicPaintCanvasSettings *canvas)
{
- return BLI_findlink(&canvas->surfaces, canvas->active_sur);
+ return BLI_findlink(&canvas->surfaces, canvas->active_sur);
}
/* set preview to first previewable surface */
void dynamicPaint_resetPreview(DynamicPaintCanvasSettings *canvas)
{
- DynamicPaintSurface *surface = canvas->surfaces.first;
- bool done = false;
-
- for (; surface; surface = surface->next) {
- if (!done && dynamicPaint_surfaceHasColorPreview(surface)) {
- surface->flags |= MOD_DPAINT_PREVIEW;
- done = true;
- }
- else {
- surface->flags &= ~MOD_DPAINT_PREVIEW;
- }
- }
+ DynamicPaintSurface *surface = canvas->surfaces.first;
+ bool done = false;
+
+ for (; surface; surface = surface->next) {
+ if (!done && dynamicPaint_surfaceHasColorPreview(surface)) {
+ surface->flags |= MOD_DPAINT_PREVIEW;
+ done = true;
+ }
+ else {
+ surface->flags &= ~MOD_DPAINT_PREVIEW;
+ }
+ }
}
/* set preview to defined surface */
static void dynamicPaint_setPreview(DynamicPaintSurface *t_surface)
{
- DynamicPaintSurface *surface = t_surface->canvas->surfaces.first;
- for (; surface; surface = surface->next) {
- if (surface == t_surface)
- surface->flags |= MOD_DPAINT_PREVIEW;
- else
- surface->flags &= ~MOD_DPAINT_PREVIEW;
- }
+ DynamicPaintSurface *surface = t_surface->canvas->surfaces.first;
+ for (; surface; surface = surface->next) {
+ if (surface == t_surface)
+ surface->flags |= MOD_DPAINT_PREVIEW;
+ else
+ surface->flags &= ~MOD_DPAINT_PREVIEW;
+ }
}
bool dynamicPaint_outputLayerExists(struct DynamicPaintSurface *surface, Object *ob, int output)
{
- const char *name;
-
- if (output == 0)
- name = surface->output_name;
- else if (output == 1)
- name = surface->output_name2;
- else
- return false;
-
- if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- Mesh *me = ob->data;
- return (CustomData_get_named_layer_index(&me->ldata, CD_MLOOPCOL, name) != -1);
- }
- else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
- return (defgroup_name_index(ob, name) != -1);
- }
- }
-
- return false;
+ const char *name;
+
+ if (output == 0)
+ name = surface->output_name;
+ else if (output == 1)
+ name = surface->output_name2;
+ else
+ return false;
+
+ if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ Mesh *me = ob->data;
+ return (CustomData_get_named_layer_index(&me->ldata, CD_MLOOPCOL, name) != -1);
+ }
+ else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
+ return (defgroup_name_index(ob, name) != -1);
+ }
+ }
+
+ return false;
}
static bool surface_duplicateOutputExists(void *arg, const char *name)
{
- DynamicPaintSurface *t_surface = arg;
- DynamicPaintSurface *surface = t_surface->canvas->surfaces.first;
-
- for (; surface; surface = surface->next) {
- if (surface != t_surface && surface->type == t_surface->type && surface->format == t_surface->format) {
- if ((surface->output_name[0] != '\0' && !BLI_path_cmp(name, surface->output_name)) ||
- (surface->output_name2[0] != '\0' && !BLI_path_cmp(name, surface->output_name2)))
- {
- return true;
- }
- }
- }
- return false;
+ DynamicPaintSurface *t_surface = arg;
+ DynamicPaintSurface *surface = t_surface->canvas->surfaces.first;
+
+ for (; surface; surface = surface->next) {
+ if (surface != t_surface && surface->type == t_surface->type &&
+ surface->format == t_surface->format) {
+ if ((surface->output_name[0] != '\0' && !BLI_path_cmp(name, surface->output_name)) ||
+ (surface->output_name2[0] != '\0' && !BLI_path_cmp(name, surface->output_name2))) {
+ return true;
+ }
+ }
+ }
+ return false;
}
static void surface_setUniqueOutputName(DynamicPaintSurface *surface, char *basename, int output)
{
- char name[64];
- BLI_strncpy(name, basename, sizeof(name)); /* in case basename is surface->name use a copy */
- if (output == 0) {
- BLI_uniquename_cb(surface_duplicateOutputExists, surface, name, '.',
- surface->output_name, sizeof(surface->output_name));
- }
- else if (output == 1) {
- BLI_uniquename_cb(surface_duplicateOutputExists, surface, name, '.',
- surface->output_name2, sizeof(surface->output_name2));
- }
+ char name[64];
+ BLI_strncpy(name, basename, sizeof(name)); /* in case basename is surface->name use a copy */
+ if (output == 0) {
+ BLI_uniquename_cb(surface_duplicateOutputExists,
+ surface,
+ name,
+ '.',
+ surface->output_name,
+ sizeof(surface->output_name));
+ }
+ else if (output == 1) {
+ BLI_uniquename_cb(surface_duplicateOutputExists,
+ surface,
+ name,
+ '.',
+ surface->output_name2,
+ sizeof(surface->output_name2));
+ }
}
-
static bool surface_duplicateNameExists(void *arg, const char *name)
{
- DynamicPaintSurface *t_surface = arg;
- DynamicPaintSurface *surface = t_surface->canvas->surfaces.first;
-
- for (; surface; surface = surface->next) {
- if (surface != t_surface && STREQ(name, surface->name))
- return true;
- }
- return false;
+ DynamicPaintSurface *t_surface = arg;
+ DynamicPaintSurface *surface = t_surface->canvas->surfaces.first;
+
+ for (; surface; surface = surface->next) {
+ if (surface != t_surface && STREQ(name, surface->name))
+ return true;
+ }
+ return false;
}
void dynamicPaintSurface_setUniqueName(DynamicPaintSurface *surface, const char *basename)
{
- char name[64];
- BLI_strncpy(name, basename, sizeof(name)); /* in case basename is surface->name use a copy */
- BLI_uniquename_cb(surface_duplicateNameExists, surface, name, '.', surface->name, sizeof(surface->name));
+ char name[64];
+ BLI_strncpy(name, basename, sizeof(name)); /* in case basename is surface->name use a copy */
+ BLI_uniquename_cb(
+ surface_duplicateNameExists, surface, name, '.', surface->name, sizeof(surface->name));
}
-
/* change surface data to defaults on new type */
void dynamicPaintSurface_updateType(struct DynamicPaintSurface *surface)
{
- if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
- surface->output_name[0] = '\0';
- surface->output_name2[0] = '\0';
- surface->flags |= MOD_DPAINT_ANTIALIAS;
- surface->depth_clamp = 1.0f;
- }
- else {
- strcpy(surface->output_name, "dp_");
- BLI_strncpy(surface->output_name2, surface->output_name, sizeof(surface->output_name2));
- surface->flags &= ~MOD_DPAINT_ANTIALIAS;
- surface->depth_clamp = 0.0f;
- }
-
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- strcat(surface->output_name, "paintmap");
- strcat(surface->output_name2, "wetmap");
- surface_setUniqueOutputName(surface, surface->output_name2, 1);
- }
- else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
- strcat(surface->output_name, "displace");
- }
- else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
- strcat(surface->output_name, "weight");
- }
- else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
- strcat(surface->output_name, "wave");
- }
-
- surface_setUniqueOutputName(surface, surface->output_name, 0);
-
- /* update preview */
- if (dynamicPaint_surfaceHasColorPreview(surface))
- dynamicPaint_setPreview(surface);
- else
- dynamicPaint_resetPreview(surface->canvas);
+ if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
+ surface->output_name[0] = '\0';
+ surface->output_name2[0] = '\0';
+ surface->flags |= MOD_DPAINT_ANTIALIAS;
+ surface->depth_clamp = 1.0f;
+ }
+ else {
+ strcpy(surface->output_name, "dp_");
+ BLI_strncpy(surface->output_name2, surface->output_name, sizeof(surface->output_name2));
+ surface->flags &= ~MOD_DPAINT_ANTIALIAS;
+ surface->depth_clamp = 0.0f;
+ }
+
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ strcat(surface->output_name, "paintmap");
+ strcat(surface->output_name2, "wetmap");
+ surface_setUniqueOutputName(surface, surface->output_name2, 1);
+ }
+ else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
+ strcat(surface->output_name, "displace");
+ }
+ else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
+ strcat(surface->output_name, "weight");
+ }
+ else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
+ strcat(surface->output_name, "wave");
+ }
+
+ surface_setUniqueOutputName(surface, surface->output_name, 0);
+
+ /* update preview */
+ if (dynamicPaint_surfaceHasColorPreview(surface))
+ dynamicPaint_setPreview(surface);
+ else
+ dynamicPaint_resetPreview(surface->canvas);
}
static int surface_totalSamples(DynamicPaintSurface *surface)
{
- if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ && surface->flags & MOD_DPAINT_ANTIALIAS) {
- return (surface->data->total_points * 5);
- }
- if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX &&
- surface->flags & MOD_DPAINT_ANTIALIAS && surface->data->adj_data)
- {
- return (surface->data->total_points + surface->data->adj_data->total_targets);
- }
-
- return surface->data->total_points;
+ if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ && surface->flags & MOD_DPAINT_ANTIALIAS) {
+ return (surface->data->total_points * 5);
+ }
+ if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX && surface->flags & MOD_DPAINT_ANTIALIAS &&
+ surface->data->adj_data) {
+ return (surface->data->total_points + surface->data->adj_data->total_targets);
+ }
+
+ return surface->data->total_points;
}
-static void blendColors(
- const float t_color[3], const float t_alpha, const float s_color[3], const float s_alpha, float result[4])
+static void blendColors(const float t_color[3],
+ const float t_alpha,
+ const float s_color[3],
+ const float s_alpha,
+ float result[4])
{
- /* Same thing as BLI's blend_color_mix_float(), but for non-premultiplied alpha. */
- int i;
- float i_alpha = 1.0f - s_alpha;
- float f_alpha = t_alpha * i_alpha + s_alpha;
-
- /* blend colors */
- if (f_alpha) {
- for (i = 0; i < 3; i++) {
- result[i] = (t_color[i] * t_alpha * i_alpha + s_color[i] * s_alpha) / f_alpha;
- }
- }
- else {
- copy_v3_v3(result, t_color);
- }
- /* return final alpha */
- result[3] = f_alpha;
+ /* Same thing as BLI's blend_color_mix_float(), but for non-premultiplied alpha. */
+ int i;
+ float i_alpha = 1.0f - s_alpha;
+ float f_alpha = t_alpha * i_alpha + s_alpha;
+
+ /* blend colors */
+ if (f_alpha) {
+ for (i = 0; i < 3; i++) {
+ result[i] = (t_color[i] * t_alpha * i_alpha + s_color[i] * s_alpha) / f_alpha;
+ }
+ }
+ else {
+ copy_v3_v3(result, t_color);
+ }
+ /* return final alpha */
+ result[3] = f_alpha;
}
/* Mix two alpha weighed colors by a defined ratio. output is saved at a_color */
-static float mixColors(float a_color[3], float a_weight, const float b_color[3], float b_weight, float ratio)
+static float mixColors(
+ float a_color[3], float a_weight, const float b_color[3], float b_weight, float ratio)
{
- float weight_ratio, factor;
- if (b_weight) {
- /* if first value has no weight just use b_color */
- if (!a_weight) {
- copy_v3_v3(a_color, b_color);
- return b_weight * ratio;
- }
- weight_ratio = b_weight / (a_weight + b_weight);
- }
- else {
- return a_weight * (1.0f - ratio);
- }
-
- /* calculate final interpolation factor */
- if (ratio <= 0.5f) {
- factor = weight_ratio * (ratio * 2.0f);
- }
- else {
- ratio = (ratio * 2.0f - 1.0f);
- factor = weight_ratio * (1.0f - ratio) + ratio;
- }
- /* mix final color */
- interp_v3_v3v3(a_color, a_color, b_color, factor);
- return (1.0f - factor) * a_weight + factor * b_weight;
+ float weight_ratio, factor;
+ if (b_weight) {
+ /* if first value has no weight just use b_color */
+ if (!a_weight) {
+ copy_v3_v3(a_color, b_color);
+ return b_weight * ratio;
+ }
+ weight_ratio = b_weight / (a_weight + b_weight);
+ }
+ else {
+ return a_weight * (1.0f - ratio);
+ }
+
+ /* calculate final interpolation factor */
+ if (ratio <= 0.5f) {
+ factor = weight_ratio * (ratio * 2.0f);
+ }
+ else {
+ ratio = (ratio * 2.0f - 1.0f);
+ factor = weight_ratio * (1.0f - ratio) + ratio;
+ }
+ /* mix final color */
+ interp_v3_v3v3(a_color, a_color, b_color, factor);
+ return (1.0f - factor) * a_weight + factor * b_weight;
}
static void scene_setSubframe(Scene *scene, float subframe)
{
- /* dynamic paint subframes must be done on previous frame */
- scene->r.cfra -= 1;
- scene->r.subframe = subframe;
+ /* dynamic paint subframes must be done on previous frame */
+ scene->r.cfra -= 1;
+ scene->r.subframe = subframe;
}
static int surface_getBrushFlags(DynamicPaintSurface *surface, Depsgraph *depsgraph)
{
- unsigned int numobjects;
- Object **objects = BKE_collision_objects_create(depsgraph, NULL, surface->brush_group, &numobjects, eModifierType_DynamicPaint);
+ unsigned int numobjects;
+ Object **objects = BKE_collision_objects_create(
+ depsgraph, NULL, surface->brush_group, &numobjects, eModifierType_DynamicPaint);
- int flags = 0;
+ int flags = 0;
- for (int i = 0; i < numobjects; i++) {
- Object *brushObj = objects[i];
+ for (int i = 0; i < numobjects; i++) {
+ Object *brushObj = objects[i];
- ModifierData *md = modifiers_findByType(brushObj, eModifierType_DynamicPaint);
- if (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) {
- DynamicPaintModifierData *pmd2 = (DynamicPaintModifierData *)md;
+ ModifierData *md = modifiers_findByType(brushObj, eModifierType_DynamicPaint);
+ if (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) {
+ DynamicPaintModifierData *pmd2 = (DynamicPaintModifierData *)md;
- if (pmd2->brush) {
- DynamicPaintBrushSettings *brush = pmd2->brush;
+ if (pmd2->brush) {
+ DynamicPaintBrushSettings *brush = pmd2->brush;
- if (brush->flags & MOD_DPAINT_USES_VELOCITY)
- flags |= BRUSH_USES_VELOCITY;
- }
- }
- }
+ if (brush->flags & MOD_DPAINT_USES_VELOCITY)
+ flags |= BRUSH_USES_VELOCITY;
+ }
+ }
+ }
- BKE_collision_objects_free(objects);
+ BKE_collision_objects_free(objects);
- return flags;
+ return flags;
}
/* check whether two bounds intersect */
static bool boundsIntersect(Bounds3D *b1, Bounds3D *b2)
{
- if (!b1->valid || !b2->valid)
- return false;
- for (int i = 2; i--;) {
- if (!(b1->min[i] <= b2->max[i] && b1->max[i] >= b2->min[i]))
- return false;
- }
- return true;
+ if (!b1->valid || !b2->valid)
+ return false;
+ for (int i = 2; i--;) {
+ if (!(b1->min[i] <= b2->max[i] && b1->max[i] >= b2->min[i]))
+ return false;
+ }
+ return true;
}
/* check whether two bounds intersect inside defined proximity */
static bool boundsIntersectDist(Bounds3D *b1, Bounds3D *b2, const float dist)
{
- if (!b1->valid || !b2->valid)
- return false;
- for (int i = 2; i--;) {
- if (!(b1->min[i] <= (b2->max[i] + dist) && b1->max[i] >= (b2->min[i] - dist)))
- return false;
- }
- return true;
+ if (!b1->valid || !b2->valid)
+ return false;
+ for (int i = 2; i--;) {
+ if (!(b1->min[i] <= (b2->max[i] + dist) && b1->max[i] >= (b2->min[i] - dist)))
+ return false;
+ }
+ return true;
}
/* check whether bounds intersects a point with given radius */
static bool boundIntersectPoint(Bounds3D *b, float point[3], const float radius)
{
- if (!b->valid)
- return false;
- for (int i = 2; i--;) {
- if (!(b->min[i] <= (point[i] + radius) && b->max[i] >= (point[i] - radius)))
- return false;
- }
- return true;
+ if (!b->valid)
+ return false;
+ for (int i = 2; i--;) {
+ if (!(b->min[i] <= (point[i] + radius) && b->max[i] >= (point[i] - radius)))
+ return false;
+ }
+ return true;
}
/* expand bounds by a new point */
static void boundInsert(Bounds3D *b, float point[3])
{
- if (!b->valid) {
- copy_v3_v3(b->min, point);
- copy_v3_v3(b->max, point);
- b->valid = true;
- return;
- }
-
- minmax_v3v3_v3(b->min, b->max, point);
+ if (!b->valid) {
+ copy_v3_v3(b->min, point);
+ copy_v3_v3(b->max, point);
+ b->valid = true;
+ return;
+ }
+
+ minmax_v3v3_v3(b->min, b->max, point);
}
static float getSurfaceDimension(PaintSurfaceData *sData)
{
- Bounds3D *mb = &sData->bData->mesh_bounds;
- return max_fff((mb->max[0] - mb->min[0]), (mb->max[1] - mb->min[1]), (mb->max[2] - mb->min[2]));
+ Bounds3D *mb = &sData->bData->mesh_bounds;
+ return max_fff((mb->max[0] - mb->min[0]), (mb->max[1] - mb->min[1]), (mb->max[2] - mb->min[2]));
}
static void freeGrid(PaintSurfaceData *data)
{
- PaintBakeData *bData = data->bData;
- VolumeGrid *grid = bData->grid;
-
- if (grid->bounds) MEM_freeN(grid->bounds);
- if (grid->s_pos) MEM_freeN(grid->s_pos);
- if (grid->s_num) MEM_freeN(grid->s_num);
- if (grid->t_index) MEM_freeN(grid->t_index);
-
- MEM_freeN(bData->grid);
- bData->grid = NULL;
+ PaintBakeData *bData = data->bData;
+ VolumeGrid *grid = bData->grid;
+
+ if (grid->bounds)
+ MEM_freeN(grid->bounds);
+ if (grid->s_pos)
+ MEM_freeN(grid->s_pos);
+ if (grid->s_num)
+ MEM_freeN(grid->s_num);
+ if (grid->t_index)
+ MEM_freeN(grid->t_index);
+
+ MEM_freeN(bData->grid);
+ bData->grid = NULL;
}
static void grid_bound_insert_cb_ex(void *__restrict userdata,
const int i,
const ParallelRangeTLS *__restrict tls)
{
- PaintBakeData *bData = userdata;
+ PaintBakeData *bData = userdata;
- Bounds3D *grid_bound = tls->userdata_chunk;
+ Bounds3D *grid_bound = tls->userdata_chunk;
- boundInsert(grid_bound, bData->realCoord[bData->s_pos[i]].v);
+ boundInsert(grid_bound, bData->realCoord[bData->s_pos[i]].v);
}
-static void grid_bound_insert_finalize(void *__restrict userdata,
- void *__restrict userdata_chunk)
+static void grid_bound_insert_finalize(void *__restrict userdata, void *__restrict userdata_chunk)
{
- PaintBakeData *bData = userdata;
- VolumeGrid *grid = bData->grid;
+ PaintBakeData *bData = userdata;
+ VolumeGrid *grid = bData->grid;
- Bounds3D *grid_bound = userdata_chunk;
+ Bounds3D *grid_bound = userdata_chunk;
- boundInsert(&grid->grid_bounds, grid_bound->min);
- boundInsert(&grid->grid_bounds, grid_bound->max);
+ boundInsert(&grid->grid_bounds, grid_bound->min);
+ boundInsert(&grid->grid_bounds, grid_bound->max);
}
static void grid_cell_points_cb_ex(void *__restrict userdata,
const int i,
const ParallelRangeTLS *__restrict tls)
{
- PaintBakeData *bData = userdata;
- VolumeGrid *grid = bData->grid;
- int *temp_t_index = grid->temp_t_index;
- int *s_num = tls->userdata_chunk;
+ PaintBakeData *bData = userdata;
+ VolumeGrid *grid = bData->grid;
+ int *temp_t_index = grid->temp_t_index;
+ int *s_num = tls->userdata_chunk;
- int co[3];
+ int co[3];
- for (int j = 3; j--;) {
- co[j] = (int)floorf((bData->realCoord[bData->s_pos[i]].v[j] - grid->grid_bounds.min[j]) /
- bData->dim[j] * grid->dim[j]);
- CLAMP(co[j], 0, grid->dim[j] - 1);
- }
+ for (int j = 3; j--;) {
+ co[j] = (int)floorf((bData->realCoord[bData->s_pos[i]].v[j] - grid->grid_bounds.min[j]) /
+ bData->dim[j] * grid->dim[j]);
+ CLAMP(co[j], 0, grid->dim[j] - 1);
+ }
- temp_t_index[i] = co[0] + co[1] * grid->dim[0] + co[2] * grid->dim[0] * grid->dim[1];
- s_num[temp_t_index[i]]++;
+ temp_t_index[i] = co[0] + co[1] * grid->dim[0] + co[2] * grid->dim[0] * grid->dim[1];
+ s_num[temp_t_index[i]]++;
}
-static void grid_cell_points_finalize(void *__restrict userdata,
- void *__restrict userdata_chunk)
+static void grid_cell_points_finalize(void *__restrict userdata, void *__restrict userdata_chunk)
{
- PaintBakeData *bData = userdata;
- VolumeGrid *grid = bData->grid;
- const int grid_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
+ PaintBakeData *bData = userdata;
+ VolumeGrid *grid = bData->grid;
+ const int grid_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
- int *s_num = userdata_chunk;
+ int *s_num = userdata_chunk;
- /* calculate grid indexes */
- for (int i = 0; i < grid_cells; i++) {
- grid->s_num[i] += s_num[i];
- }
+ /* calculate grid indexes */
+ for (int i = 0; i < grid_cells; i++) {
+ grid->s_num[i] += s_num[i];
+ }
}
static void grid_cell_bounds_cb(void *__restrict userdata,
const int x,
const ParallelRangeTLS *__restrict UNUSED(tls))
{
- PaintBakeData *bData = userdata;
- VolumeGrid *grid = bData->grid;
- float *dim = bData->dim;
- int *grid_dim = grid->dim;
-
- for (int y = 0; y < grid_dim[1]; y++) {
- for (int z = 0; z < grid_dim[2]; z++) {
- const int b_index = x + y * grid_dim[0] + z * grid_dim[0] * grid_dim[1];
- /* set bounds */
- for (int j = 3; j--;) {
- const int s = (j == 0) ? x : ((j == 1) ? y : z);
- grid->bounds[b_index].min[j] = grid->grid_bounds.min[j] + dim[j] / grid_dim[j] * s;
- grid->bounds[b_index].max[j] = grid->grid_bounds.min[j] + dim[j] / grid_dim[j] * (s + 1);
- }
- grid->bounds[b_index].valid = true;
- }
- }
+ PaintBakeData *bData = userdata;
+ VolumeGrid *grid = bData->grid;
+ float *dim = bData->dim;
+ int *grid_dim = grid->dim;
+
+ for (int y = 0; y < grid_dim[1]; y++) {
+ for (int z = 0; z < grid_dim[2]; z++) {
+ const int b_index = x + y * grid_dim[0] + z * grid_dim[0] * grid_dim[1];
+ /* set bounds */
+ for (int j = 3; j--;) {
+ const int s = (j == 0) ? x : ((j == 1) ? y : z);
+ grid->bounds[b_index].min[j] = grid->grid_bounds.min[j] + dim[j] / grid_dim[j] * s;
+ grid->bounds[b_index].max[j] = grid->grid_bounds.min[j] + dim[j] / grid_dim[j] * (s + 1);
+ }
+ grid->bounds[b_index].valid = true;
+ }
+ }
}
static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
{
- PaintSurfaceData *sData = surface->data;
- PaintBakeData *bData = sData->bData;
- VolumeGrid *grid;
- int grid_cells, axis = 3;
- int *temp_t_index = NULL;
- int *temp_s_num = NULL;
-
- if (bData->grid)
- freeGrid(sData);
-
- bData->grid = MEM_callocN(sizeof(VolumeGrid), "Surface Grid");
- grid = bData->grid;
-
- {
- int i, error = 0;
- float dim_factor, volume, dim[3];
- float td[3];
- float min_dim;
-
- /* calculate canvas dimensions */
- /* Important to init correctly our ref grid_bound... */
- boundInsert(&grid->grid_bounds, bData->realCoord[bData->s_pos[0]].v);
- {
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 1000);
- settings.userdata_chunk = &grid->grid_bounds;
- settings.userdata_chunk_size = sizeof(grid->grid_bounds);
- settings.func_finalize = grid_bound_insert_finalize;
- BLI_task_parallel_range(
- 0, sData->total_points,
- bData,
- grid_bound_insert_cb_ex,
- &settings);
- }
- /* get dimensions */
- sub_v3_v3v3(dim, grid->grid_bounds.max, grid->grid_bounds.min);
- copy_v3_v3(td, dim);
- copy_v3_v3(bData->dim, dim);
- min_dim = max_fff(td[0], td[1], td[2]) / 1000.f;
-
- /* deactivate zero axises */
- for (i = 0; i < 3; i++) {
- if (td[i] < min_dim) {
- td[i] = 1.0f;
- axis--;
- }
- }
-
- if (axis == 0 || max_fff(td[0], td[1], td[2]) < 0.0001f) {
- MEM_freeN(bData->grid);
- bData->grid = NULL;
- return;
- }
-
- /* now calculate grid volume/area/width depending on num of active axis */
- volume = td[0] * td[1] * td[2];
-
- /* determine final grid size by trying to fit average 10.000 points per grid cell */
- dim_factor = (float)pow((double)volume / ((double)sData->total_points / 10000.0), 1.0 / (double)axis);
-
- /* define final grid size using dim_factor, use min 3 for active axises */
- for (i = 0; i < 3; i++) {
- grid->dim[i] = (int)floor(td[i] / dim_factor);
- CLAMP(grid->dim[i], (dim[i] >= min_dim) ? 3 : 1, 100);
- }
- grid_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
-
- /* allocate memory for grids */
- grid->bounds = MEM_callocN(sizeof(Bounds3D) * grid_cells, "Surface Grid Bounds");
- grid->s_pos = MEM_callocN(sizeof(int) * grid_cells, "Surface Grid Position");
-
- grid->s_num = MEM_callocN(sizeof(int) * grid_cells, "Surface Grid Points");
- temp_s_num = MEM_callocN(sizeof(int) * grid_cells, "Temp Surface Grid Points");
- grid->t_index = MEM_callocN(sizeof(int) * sData->total_points, "Surface Grid Target Ids");
- grid->temp_t_index = temp_t_index = MEM_callocN(sizeof(int) * sData->total_points, "Temp Surface Grid Target Ids");
-
- /* in case of an allocation failure abort here */
- if (!grid->bounds || !grid->s_pos || !grid->s_num || !grid->t_index || !temp_s_num || !temp_t_index)
- error = 1;
-
- if (!error) {
- /* calculate number of points within each cell */
- {
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 1000);
- settings.userdata_chunk = grid->s_num;
- settings.userdata_chunk_size = sizeof(*grid->s_num) * grid_cells;
- settings.func_finalize = grid_cell_points_finalize;
- BLI_task_parallel_range(
- 0, sData->total_points,
- bData,
- grid_cell_points_cb_ex,
- &settings);
- }
-
- /* calculate grid indexes (not needed for first cell, which is zero). */
- for (i = 1; i < grid_cells; i++) {
- grid->s_pos[i] = grid->s_pos[i - 1] + grid->s_num[i - 1];
- }
-
- /* save point indexes to final array */
- for (i = 0; i < sData->total_points; i++) {
- int pos = grid->s_pos[temp_t_index[i]] + temp_s_num[temp_t_index[i]];
- grid->t_index[pos] = i;
-
- temp_s_num[temp_t_index[i]]++;
- }
-
- /* calculate cell bounds */
- {
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (grid_cells > 1000);
- BLI_task_parallel_range(0, grid->dim[0],
- bData,
- grid_cell_bounds_cb,
- &settings);
- }
- }
-
- if (temp_s_num)
- MEM_freeN(temp_s_num);
- if (temp_t_index)
- MEM_freeN(temp_t_index);
- grid->temp_t_index = NULL;
-
- if (error || !grid->s_num) {
- setError(surface->canvas, N_("Not enough free memory"));
- freeGrid(sData);
- }
- }
+ PaintSurfaceData *sData = surface->data;
+ PaintBakeData *bData = sData->bData;
+ VolumeGrid *grid;
+ int grid_cells, axis = 3;
+ int *temp_t_index = NULL;
+ int *temp_s_num = NULL;
+
+ if (bData->grid)
+ freeGrid(sData);
+
+ bData->grid = MEM_callocN(sizeof(VolumeGrid), "Surface Grid");
+ grid = bData->grid;
+
+ {
+ int i, error = 0;
+ float dim_factor, volume, dim[3];
+ float td[3];
+ float min_dim;
+
+ /* calculate canvas dimensions */
+ /* Important to init correctly our ref grid_bound... */
+ boundInsert(&grid->grid_bounds, bData->realCoord[bData->s_pos[0]].v);
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ settings.userdata_chunk = &grid->grid_bounds;
+ settings.userdata_chunk_size = sizeof(grid->grid_bounds);
+ settings.func_finalize = grid_bound_insert_finalize;
+ BLI_task_parallel_range(0, sData->total_points, bData, grid_bound_insert_cb_ex, &settings);
+ }
+ /* get dimensions */
+ sub_v3_v3v3(dim, grid->grid_bounds.max, grid->grid_bounds.min);
+ copy_v3_v3(td, dim);
+ copy_v3_v3(bData->dim, dim);
+ min_dim = max_fff(td[0], td[1], td[2]) / 1000.f;
+
+ /* deactivate zero axises */
+ for (i = 0; i < 3; i++) {
+ if (td[i] < min_dim) {
+ td[i] = 1.0f;
+ axis--;
+ }
+ }
+
+ if (axis == 0 || max_fff(td[0], td[1], td[2]) < 0.0001f) {
+ MEM_freeN(bData->grid);
+ bData->grid = NULL;
+ return;
+ }
+
+ /* now calculate grid volume/area/width depending on num of active axis */
+ volume = td[0] * td[1] * td[2];
+
+ /* determine final grid size by trying to fit average 10.000 points per grid cell */
+ dim_factor = (float)pow((double)volume / ((double)sData->total_points / 10000.0),
+ 1.0 / (double)axis);
+
+ /* define final grid size using dim_factor, use min 3 for active axises */
+ for (i = 0; i < 3; i++) {
+ grid->dim[i] = (int)floor(td[i] / dim_factor);
+ CLAMP(grid->dim[i], (dim[i] >= min_dim) ? 3 : 1, 100);
+ }
+ grid_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
+
+ /* allocate memory for grids */
+ grid->bounds = MEM_callocN(sizeof(Bounds3D) * grid_cells, "Surface Grid Bounds");
+ grid->s_pos = MEM_callocN(sizeof(int) * grid_cells, "Surface Grid Position");
+
+ grid->s_num = MEM_callocN(sizeof(int) * grid_cells, "Surface Grid Points");
+ temp_s_num = MEM_callocN(sizeof(int) * grid_cells, "Temp Surface Grid Points");
+ grid->t_index = MEM_callocN(sizeof(int) * sData->total_points, "Surface Grid Target Ids");
+ grid->temp_t_index = temp_t_index = MEM_callocN(sizeof(int) * sData->total_points,
+ "Temp Surface Grid Target Ids");
+
+ /* in case of an allocation failure abort here */
+ if (!grid->bounds || !grid->s_pos || !grid->s_num || !grid->t_index || !temp_s_num ||
+ !temp_t_index)
+ error = 1;
+
+ if (!error) {
+ /* calculate number of points within each cell */
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ settings.userdata_chunk = grid->s_num;
+ settings.userdata_chunk_size = sizeof(*grid->s_num) * grid_cells;
+ settings.func_finalize = grid_cell_points_finalize;
+ BLI_task_parallel_range(0, sData->total_points, bData, grid_cell_points_cb_ex, &settings);
+ }
+
+ /* calculate grid indexes (not needed for first cell, which is zero). */
+ for (i = 1; i < grid_cells; i++) {
+ grid->s_pos[i] = grid->s_pos[i - 1] + grid->s_num[i - 1];
+ }
+
+ /* save point indexes to final array */
+ for (i = 0; i < sData->total_points; i++) {
+ int pos = grid->s_pos[temp_t_index[i]] + temp_s_num[temp_t_index[i]];
+ grid->t_index[pos] = i;
+
+ temp_s_num[temp_t_index[i]]++;
+ }
+
+ /* calculate cell bounds */
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (grid_cells > 1000);
+ BLI_task_parallel_range(0, grid->dim[0], bData, grid_cell_bounds_cb, &settings);
+ }
+ }
+
+ if (temp_s_num)
+ MEM_freeN(temp_s_num);
+ if (temp_t_index)
+ MEM_freeN(temp_t_index);
+ grid->temp_t_index = NULL;
+
+ if (error || !grid->s_num) {
+ setError(surface->canvas, N_("Not enough free memory"));
+ freeGrid(sData);
+ }
+ }
}
/***************************** Freeing data ******************************/
@@ -857,149 +863,149 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
/* Free brush data */
void dynamicPaint_freeBrush(struct DynamicPaintModifierData *pmd)
{
- if (pmd->brush) {
- if (pmd->brush->paint_ramp)
- MEM_freeN(pmd->brush->paint_ramp);
- if (pmd->brush->vel_ramp)
- MEM_freeN(pmd->brush->vel_ramp);
-
- MEM_freeN(pmd->brush);
- pmd->brush = NULL;
- }
+ if (pmd->brush) {
+ if (pmd->brush->paint_ramp)
+ MEM_freeN(pmd->brush->paint_ramp);
+ if (pmd->brush->vel_ramp)
+ MEM_freeN(pmd->brush->vel_ramp);
+
+ MEM_freeN(pmd->brush);
+ pmd->brush = NULL;
+ }
}
static void dynamicPaint_freeAdjData(PaintSurfaceData *data)
{
- if (data->adj_data) {
- if (data->adj_data->n_index)
- MEM_freeN(data->adj_data->n_index);
- if (data->adj_data->n_num)
- MEM_freeN(data->adj_data->n_num);
- if (data->adj_data->n_target)
- MEM_freeN(data->adj_data->n_target);
- if (data->adj_data->flags)
- MEM_freeN(data->adj_data->flags);
- if (data->adj_data->border)
- MEM_freeN(data->adj_data->border);
- MEM_freeN(data->adj_data);
- data->adj_data = NULL;
- }
+ if (data->adj_data) {
+ if (data->adj_data->n_index)
+ MEM_freeN(data->adj_data->n_index);
+ if (data->adj_data->n_num)
+ MEM_freeN(data->adj_data->n_num);
+ if (data->adj_data->n_target)
+ MEM_freeN(data->adj_data->n_target);
+ if (data->adj_data->flags)
+ MEM_freeN(data->adj_data->flags);
+ if (data->adj_data->border)
+ MEM_freeN(data->adj_data->border);
+ MEM_freeN(data->adj_data);
+ data->adj_data = NULL;
+ }
}
static void free_bakeData(PaintSurfaceData *data)
{
- PaintBakeData *bData = data->bData;
- if (bData) {
- if (bData->bNormal)
- MEM_freeN(bData->bNormal);
- if (bData->s_pos)
- MEM_freeN(bData->s_pos);
- if (bData->s_num)
- MEM_freeN(bData->s_num);
- if (bData->realCoord)
- MEM_freeN(bData->realCoord);
- if (bData->bNeighs)
- MEM_freeN(bData->bNeighs);
- if (bData->grid)
- freeGrid(data);
- if (bData->prev_verts)
- MEM_freeN(bData->prev_verts);
- if (bData->velocity)
- MEM_freeN(bData->velocity);
- if (bData->prev_velocity)
- MEM_freeN(bData->prev_velocity);
-
- MEM_freeN(data->bData);
- data->bData = NULL;
- }
+ PaintBakeData *bData = data->bData;
+ if (bData) {
+ if (bData->bNormal)
+ MEM_freeN(bData->bNormal);
+ if (bData->s_pos)
+ MEM_freeN(bData->s_pos);
+ if (bData->s_num)
+ MEM_freeN(bData->s_num);
+ if (bData->realCoord)
+ MEM_freeN(bData->realCoord);
+ if (bData->bNeighs)
+ MEM_freeN(bData->bNeighs);
+ if (bData->grid)
+ freeGrid(data);
+ if (bData->prev_verts)
+ MEM_freeN(bData->prev_verts);
+ if (bData->velocity)
+ MEM_freeN(bData->velocity);
+ if (bData->prev_velocity)
+ MEM_freeN(bData->prev_velocity);
+
+ MEM_freeN(data->bData);
+ data->bData = NULL;
+ }
}
/* free surface data if it's not used anymore */
static void surface_freeUnusedData(DynamicPaintSurface *surface)
{
- if (!surface->data)
- return;
-
- /* free bakedata if not active or surface is baked */
- if (!(surface->flags & MOD_DPAINT_ACTIVE) || (surface->pointcache && surface->pointcache->flag & PTCACHE_BAKED)) {
- free_bakeData(surface->data);
- }
+ if (!surface->data)
+ return;
+
+ /* free bakedata if not active or surface is baked */
+ if (!(surface->flags & MOD_DPAINT_ACTIVE) ||
+ (surface->pointcache && surface->pointcache->flag & PTCACHE_BAKED)) {
+ free_bakeData(surface->data);
+ }
}
void dynamicPaint_freeSurfaceData(DynamicPaintSurface *surface)
{
- PaintSurfaceData *data = surface->data;
- if (!data)
- return;
-
- if (data->format_data) {
- /* format specific free */
- if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
- ImgSeqFormatData *format_data = (ImgSeqFormatData *)data->format_data;
- if (format_data->uv_p)
- MEM_freeN(format_data->uv_p);
- if (format_data->barycentricWeights)
- MEM_freeN(format_data->barycentricWeights);
- }
- MEM_freeN(data->format_data);
- }
- /* type data */
- if (data->type_data)
- MEM_freeN(data->type_data);
- dynamicPaint_freeAdjData(data);
- /* bake data */
- free_bakeData(data);
-
- MEM_freeN(surface->data);
- surface->data = NULL;
+ PaintSurfaceData *data = surface->data;
+ if (!data)
+ return;
+
+ if (data->format_data) {
+ /* format specific free */
+ if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
+ ImgSeqFormatData *format_data = (ImgSeqFormatData *)data->format_data;
+ if (format_data->uv_p)
+ MEM_freeN(format_data->uv_p);
+ if (format_data->barycentricWeights)
+ MEM_freeN(format_data->barycentricWeights);
+ }
+ MEM_freeN(data->format_data);
+ }
+ /* type data */
+ if (data->type_data)
+ MEM_freeN(data->type_data);
+ dynamicPaint_freeAdjData(data);
+ /* bake data */
+ free_bakeData(data);
+
+ MEM_freeN(surface->data);
+ surface->data = NULL;
}
-void dynamicPaint_freeSurface(const DynamicPaintModifierData *pmd,
- DynamicPaintSurface *surface)
+void dynamicPaint_freeSurface(const DynamicPaintModifierData *pmd, DynamicPaintSurface *surface)
{
- /* point cache */
- if ((pmd->modifier.flag & eModifierFlag_SharedCaches) == 0) {
- BKE_ptcache_free_list(&(surface->ptcaches));
- }
- surface->pointcache = NULL;
-
- if (surface->effector_weights)
- MEM_freeN(surface->effector_weights);
- surface->effector_weights = NULL;
-
- BLI_remlink(&(surface->canvas->surfaces), surface);
- dynamicPaint_freeSurfaceData(surface);
- MEM_freeN(surface);
+ /* point cache */
+ if ((pmd->modifier.flag & eModifierFlag_SharedCaches) == 0) {
+ BKE_ptcache_free_list(&(surface->ptcaches));
+ }
+ surface->pointcache = NULL;
+
+ if (surface->effector_weights)
+ MEM_freeN(surface->effector_weights);
+ surface->effector_weights = NULL;
+
+ BLI_remlink(&(surface->canvas->surfaces), surface);
+ dynamicPaint_freeSurfaceData(surface);
+ MEM_freeN(surface);
}
/* Free canvas data */
void dynamicPaint_freeCanvas(DynamicPaintModifierData *pmd)
{
- if (pmd->canvas) {
- /* Free surface data */
- DynamicPaintSurface *surface = pmd->canvas->surfaces.first;
- DynamicPaintSurface *next_surface = NULL;
-
- while (surface) {
- next_surface = surface->next;
- dynamicPaint_freeSurface(pmd, surface);
- surface = next_surface;
- }
-
- MEM_freeN(pmd->canvas);
- pmd->canvas = NULL;
- }
+ if (pmd->canvas) {
+ /* Free surface data */
+ DynamicPaintSurface *surface = pmd->canvas->surfaces.first;
+ DynamicPaintSurface *next_surface = NULL;
+
+ while (surface) {
+ next_surface = surface->next;
+ dynamicPaint_freeSurface(pmd, surface);
+ surface = next_surface;
+ }
+
+ MEM_freeN(pmd->canvas);
+ pmd->canvas = NULL;
+ }
}
/* Free whole dp modifier */
void dynamicPaint_Modifier_free(DynamicPaintModifierData *pmd)
{
- if (pmd == NULL) {
- return;
- }
- dynamicPaint_freeCanvas(pmd);
- dynamicPaint_freeBrush(pmd);
- dynamicPaint_Modifier_free_runtime(pmd->modifier.runtime);
+ if (pmd == NULL) {
+ return;
+ }
+ dynamicPaint_freeCanvas(pmd);
+ dynamicPaint_freeBrush(pmd);
+ dynamicPaint_Modifier_free_runtime(pmd->modifier.runtime);
}
/***************************** Initialize and reset ******************************/
@@ -1009,77 +1015,80 @@ void dynamicPaint_Modifier_free(DynamicPaintModifierData *pmd)
* If scene is null, frame range of 1-250 is used
* A pointer to this surface is returned
*/
-DynamicPaintSurface *dynamicPaint_createNewSurface(DynamicPaintCanvasSettings *canvas, Scene *scene)
+DynamicPaintSurface *dynamicPaint_createNewSurface(DynamicPaintCanvasSettings *canvas,
+ Scene *scene)
{
- DynamicPaintSurface *surface = MEM_callocN(sizeof(DynamicPaintSurface), "DynamicPaintSurface");
- if (!surface)
- return NULL;
-
- surface->canvas = canvas;
- surface->format = MOD_DPAINT_SURFACE_F_VERTEX;
- surface->type = MOD_DPAINT_SURFACE_T_PAINT;
-
- /* cache */
- surface->pointcache = BKE_ptcache_add(&(surface->ptcaches));
- surface->pointcache->flag |= PTCACHE_DISK_CACHE;
- surface->pointcache->step = 1;
-
- /* Set initial values */
- surface->flags = MOD_DPAINT_ANTIALIAS | MOD_DPAINT_MULALPHA | MOD_DPAINT_DRY_LOG | MOD_DPAINT_DISSOLVE_LOG |
- MOD_DPAINT_ACTIVE | MOD_DPAINT_PREVIEW | MOD_DPAINT_OUT1 | MOD_DPAINT_USE_DRYING;
- surface->effect = 0;
- surface->effect_ui = 1;
-
- surface->diss_speed = 250;
- surface->dry_speed = 500;
- surface->color_dry_threshold = 1.0f;
- surface->depth_clamp = 0.0f;
- surface->disp_factor = 1.0f;
- surface->disp_type = MOD_DPAINT_DISP_DISPLACE;
- surface->image_fileformat = MOD_DPAINT_IMGFORMAT_PNG;
-
- surface->influence_scale = 1.0f;
- surface->radius_scale = 1.0f;
-
- surface->init_color[0] = 1.0f;
- surface->init_color[1] = 1.0f;
- surface->init_color[2] = 1.0f;
- surface->init_color[3] = 1.0f;
-
- surface->image_resolution = 256;
- surface->substeps = 0;
-
- if (scene) {
- surface->start_frame = scene->r.sfra;
- surface->end_frame = scene->r.efra;
- }
- else {
- surface->start_frame = 1;
- surface->end_frame = 250;
- }
-
- surface->spread_speed = 1.0f;
- surface->color_spread_speed = 1.0f;
- surface->shrink_speed = 1.0f;
-
- surface->wave_damping = 0.04f;
- surface->wave_speed = 1.0f;
- surface->wave_timescale = 1.0f;
- surface->wave_spring = 0.20f;
- surface->wave_smoothness = 1.0f;
-
- modifier_path_init(surface->image_output_path, sizeof(surface->image_output_path), "cache_dynamicpaint");
-
- /* Using ID_BRUSH i18n context, as we have no physics/dpaint one for now... */
- dynamicPaintSurface_setUniqueName(surface, CTX_DATA_(BLT_I18NCONTEXT_ID_BRUSH, "Surface"));
-
- surface->effector_weights = BKE_effector_add_weights(NULL);
-
- dynamicPaintSurface_updateType(surface);
-
- BLI_addtail(&canvas->surfaces, surface);
-
- return surface;
+ DynamicPaintSurface *surface = MEM_callocN(sizeof(DynamicPaintSurface), "DynamicPaintSurface");
+ if (!surface)
+ return NULL;
+
+ surface->canvas = canvas;
+ surface->format = MOD_DPAINT_SURFACE_F_VERTEX;
+ surface->type = MOD_DPAINT_SURFACE_T_PAINT;
+
+ /* cache */
+ surface->pointcache = BKE_ptcache_add(&(surface->ptcaches));
+ surface->pointcache->flag |= PTCACHE_DISK_CACHE;
+ surface->pointcache->step = 1;
+
+ /* Set initial values */
+ surface->flags = MOD_DPAINT_ANTIALIAS | MOD_DPAINT_MULALPHA | MOD_DPAINT_DRY_LOG |
+ MOD_DPAINT_DISSOLVE_LOG | MOD_DPAINT_ACTIVE | MOD_DPAINT_PREVIEW |
+ MOD_DPAINT_OUT1 | MOD_DPAINT_USE_DRYING;
+ surface->effect = 0;
+ surface->effect_ui = 1;
+
+ surface->diss_speed = 250;
+ surface->dry_speed = 500;
+ surface->color_dry_threshold = 1.0f;
+ surface->depth_clamp = 0.0f;
+ surface->disp_factor = 1.0f;
+ surface->disp_type = MOD_DPAINT_DISP_DISPLACE;
+ surface->image_fileformat = MOD_DPAINT_IMGFORMAT_PNG;
+
+ surface->influence_scale = 1.0f;
+ surface->radius_scale = 1.0f;
+
+ surface->init_color[0] = 1.0f;
+ surface->init_color[1] = 1.0f;
+ surface->init_color[2] = 1.0f;
+ surface->init_color[3] = 1.0f;
+
+ surface->image_resolution = 256;
+ surface->substeps = 0;
+
+ if (scene) {
+ surface->start_frame = scene->r.sfra;
+ surface->end_frame = scene->r.efra;
+ }
+ else {
+ surface->start_frame = 1;
+ surface->end_frame = 250;
+ }
+
+ surface->spread_speed = 1.0f;
+ surface->color_spread_speed = 1.0f;
+ surface->shrink_speed = 1.0f;
+
+ surface->wave_damping = 0.04f;
+ surface->wave_speed = 1.0f;
+ surface->wave_timescale = 1.0f;
+ surface->wave_spring = 0.20f;
+ surface->wave_smoothness = 1.0f;
+
+ modifier_path_init(
+ surface->image_output_path, sizeof(surface->image_output_path), "cache_dynamicpaint");
+
+ /* Using ID_BRUSH i18n context, as we have no physics/dpaint one for now... */
+ dynamicPaintSurface_setUniqueName(surface, CTX_DATA_(BLT_I18NCONTEXT_ID_BRUSH, "Surface"));
+
+ surface->effector_weights = BKE_effector_add_weights(NULL);
+
+ dynamicPaintSurface_updateType(surface);
+
+ BLI_addtail(&canvas->surfaces, surface);
+
+ return surface;
}
/*
@@ -1087,1380 +1096,1378 @@ DynamicPaintSurface *dynamicPaint_createNewSurface(DynamicPaintCanvasSettings *c
*/
bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, struct Scene *scene)
{
- if (pmd) {
- if (type == MOD_DYNAMICPAINT_TYPE_CANVAS) {
- DynamicPaintCanvasSettings *canvas;
- if (pmd->canvas)
- dynamicPaint_freeCanvas(pmd);
-
- canvas = pmd->canvas = MEM_callocN(sizeof(DynamicPaintCanvasSettings), "DynamicPaint Canvas");
- if (!canvas)
- return false;
- canvas->pmd = pmd;
-
- /* Create one surface */
- if (!dynamicPaint_createNewSurface(canvas, scene))
- return false;
-
- }
- else if (type == MOD_DYNAMICPAINT_TYPE_BRUSH) {
- DynamicPaintBrushSettings *brush;
- if (pmd->brush)
- dynamicPaint_freeBrush(pmd);
-
- brush = pmd->brush = MEM_callocN(sizeof(DynamicPaintBrushSettings), "DynamicPaint Paint");
- if (!brush)
- return false;
- brush->pmd = pmd;
-
- brush->psys = NULL;
-
- brush->flags = MOD_DPAINT_ABS_ALPHA | MOD_DPAINT_RAMP_ALPHA;
- brush->collision = MOD_DPAINT_COL_VOLUME;
-
- brush->r = 0.15f;
- brush->g = 0.4f;
- brush->b = 0.8f;
- brush->alpha = 1.0f;
- brush->wetness = 1.0f;
-
- brush->paint_distance = 1.0f;
- brush->proximity_falloff = MOD_DPAINT_PRFALL_SMOOTH;
-
- brush->particle_radius = 0.2f;
- brush->particle_smooth = 0.05f;
-
- brush->wave_type = MOD_DPAINT_WAVEB_CHANGE;
- brush->wave_factor = 1.0f;
- brush->wave_clamp = 0.0f;
- brush->smudge_strength = 0.3f;
- brush->max_velocity = 1.0f;
-
- /* Paint proximity falloff colorramp. */
- {
- CBData *ramp;
-
- brush->paint_ramp = BKE_colorband_add(false);
- if (!brush->paint_ramp)
- return false;
- ramp = brush->paint_ramp->data;
- /* Add default smooth-falloff ramp. */
- ramp[0].r = ramp[0].g = ramp[0].b = ramp[0].a = 1.0f;
- ramp[0].pos = 0.0f;
- ramp[1].r = ramp[1].g = ramp[1].b = ramp[1].pos = 1.0f;
- ramp[1].a = 0.0f;
- pmd->brush->paint_ramp->tot = 2;
- }
-
- /* Brush velocity ramp. */
- {
- CBData *ramp;
-
- brush->vel_ramp = BKE_colorband_add(false);
- if (!brush->vel_ramp)
- return false;
- ramp = brush->vel_ramp->data;
- ramp[0].r = ramp[0].g = ramp[0].b = ramp[0].a = ramp[0].pos = 0.0f;
- ramp[1].r = ramp[1].g = ramp[1].b = ramp[1].a = ramp[1].pos = 1.0f;
- brush->paint_ramp->tot = 2;
- }
- }
- }
- else {
- return false;
- }
-
- return true;
+ if (pmd) {
+ if (type == MOD_DYNAMICPAINT_TYPE_CANVAS) {
+ DynamicPaintCanvasSettings *canvas;
+ if (pmd->canvas)
+ dynamicPaint_freeCanvas(pmd);
+
+ canvas = pmd->canvas = MEM_callocN(sizeof(DynamicPaintCanvasSettings),
+ "DynamicPaint Canvas");
+ if (!canvas)
+ return false;
+ canvas->pmd = pmd;
+
+ /* Create one surface */
+ if (!dynamicPaint_createNewSurface(canvas, scene))
+ return false;
+ }
+ else if (type == MOD_DYNAMICPAINT_TYPE_BRUSH) {
+ DynamicPaintBrushSettings *brush;
+ if (pmd->brush)
+ dynamicPaint_freeBrush(pmd);
+
+ brush = pmd->brush = MEM_callocN(sizeof(DynamicPaintBrushSettings), "DynamicPaint Paint");
+ if (!brush)
+ return false;
+ brush->pmd = pmd;
+
+ brush->psys = NULL;
+
+ brush->flags = MOD_DPAINT_ABS_ALPHA | MOD_DPAINT_RAMP_ALPHA;
+ brush->collision = MOD_DPAINT_COL_VOLUME;
+
+ brush->r = 0.15f;
+ brush->g = 0.4f;
+ brush->b = 0.8f;
+ brush->alpha = 1.0f;
+ brush->wetness = 1.0f;
+
+ brush->paint_distance = 1.0f;
+ brush->proximity_falloff = MOD_DPAINT_PRFALL_SMOOTH;
+
+ brush->particle_radius = 0.2f;
+ brush->particle_smooth = 0.05f;
+
+ brush->wave_type = MOD_DPAINT_WAVEB_CHANGE;
+ brush->wave_factor = 1.0f;
+ brush->wave_clamp = 0.0f;
+ brush->smudge_strength = 0.3f;
+ brush->max_velocity = 1.0f;
+
+ /* Paint proximity falloff colorramp. */
+ {
+ CBData *ramp;
+
+ brush->paint_ramp = BKE_colorband_add(false);
+ if (!brush->paint_ramp)
+ return false;
+ ramp = brush->paint_ramp->data;
+ /* Add default smooth-falloff ramp. */
+ ramp[0].r = ramp[0].g = ramp[0].b = ramp[0].a = 1.0f;
+ ramp[0].pos = 0.0f;
+ ramp[1].r = ramp[1].g = ramp[1].b = ramp[1].pos = 1.0f;
+ ramp[1].a = 0.0f;
+ pmd->brush->paint_ramp->tot = 2;
+ }
+
+ /* Brush velocity ramp. */
+ {
+ CBData *ramp;
+
+ brush->vel_ramp = BKE_colorband_add(false);
+ if (!brush->vel_ramp)
+ return false;
+ ramp = brush->vel_ramp->data;
+ ramp[0].r = ramp[0].g = ramp[0].b = ramp[0].a = ramp[0].pos = 0.0f;
+ ramp[1].r = ramp[1].g = ramp[1].b = ramp[1].a = ramp[1].pos = 1.0f;
+ brush->paint_ramp->tot = 2;
+ }
+ }
+ }
+ else {
+ return false;
+ }
+
+ return true;
}
void dynamicPaint_Modifier_copy(const struct DynamicPaintModifierData *pmd,
struct DynamicPaintModifierData *tpmd,
int flag)
{
- /* Init modifier */
- tpmd->type = pmd->type;
- if (pmd->canvas)
- dynamicPaint_createType(tpmd, MOD_DYNAMICPAINT_TYPE_CANVAS, NULL);
- if (pmd->brush)
- dynamicPaint_createType(tpmd, MOD_DYNAMICPAINT_TYPE_BRUSH, NULL);
-
- /* Copy data */
- if (tpmd->canvas) {
- DynamicPaintSurface *surface;
- tpmd->canvas->pmd = tpmd;
- /* free default surface */
- if (tpmd->canvas->surfaces.first)
- dynamicPaint_freeSurface(tpmd, tpmd->canvas->surfaces.first);
-
- /* copy existing surfaces */
- for (surface = pmd->canvas->surfaces.first; surface; surface = surface->next) {
- DynamicPaintSurface *t_surface = dynamicPaint_createNewSurface(tpmd->canvas, NULL);
- if (flag & LIB_ID_CREATE_NO_MAIN) {
- /* TODO(sergey): Consider passing some tips to the surface
- * creation to avoid this allocate-and-free cache behavior. */
- BKE_ptcache_free_list(&t_surface->ptcaches);
- tpmd->modifier.flag |= eModifierFlag_SharedCaches;
- t_surface->ptcaches = surface->ptcaches;
- t_surface->pointcache = surface->pointcache;
- }
-
- /* surface settings */
- t_surface->brush_group = surface->brush_group;
- MEM_freeN(t_surface->effector_weights);
- t_surface->effector_weights = MEM_dupallocN(surface->effector_weights);
-
- BLI_strncpy(t_surface->name, surface->name, sizeof(t_surface->name));
- t_surface->format = surface->format;
- t_surface->type = surface->type;
- t_surface->disp_type = surface->disp_type;
- t_surface->image_fileformat = surface->image_fileformat;
- t_surface->effect_ui = surface->effect_ui;
- t_surface->preview_id = surface->preview_id;
- t_surface->init_color_type = surface->init_color_type;
- t_surface->flags = surface->flags;
- t_surface->effect = surface->effect;
-
- t_surface->image_resolution = surface->image_resolution;
- t_surface->substeps = surface->substeps;
- t_surface->start_frame = surface->start_frame;
- t_surface->end_frame = surface->end_frame;
-
- copy_v4_v4(t_surface->init_color, surface->init_color);
- t_surface->init_texture = surface->init_texture;
- BLI_strncpy(t_surface->init_layername, surface->init_layername, sizeof(t_surface->init_layername));
-
- t_surface->dry_speed = surface->dry_speed;
- t_surface->diss_speed = surface->diss_speed;
- t_surface->color_dry_threshold = surface->color_dry_threshold;
- t_surface->depth_clamp = surface->depth_clamp;
- t_surface->disp_factor = surface->disp_factor;
-
-
- t_surface->spread_speed = surface->spread_speed;
- t_surface->color_spread_speed = surface->color_spread_speed;
- t_surface->shrink_speed = surface->shrink_speed;
- t_surface->drip_vel = surface->drip_vel;
- t_surface->drip_acc = surface->drip_acc;
-
- t_surface->influence_scale = surface->influence_scale;
- t_surface->radius_scale = surface->radius_scale;
-
- t_surface->wave_damping = surface->wave_damping;
- t_surface->wave_speed = surface->wave_speed;
- t_surface->wave_timescale = surface->wave_timescale;
- t_surface->wave_spring = surface->wave_spring;
- t_surface->wave_smoothness = surface->wave_smoothness;
-
- BLI_strncpy(t_surface->uvlayer_name, surface->uvlayer_name, sizeof(t_surface->uvlayer_name));
- BLI_strncpy(t_surface->image_output_path, surface->image_output_path, sizeof(t_surface->image_output_path));
- BLI_strncpy(t_surface->output_name, surface->output_name, sizeof(t_surface->output_name));
- BLI_strncpy(t_surface->output_name2, surface->output_name2, sizeof(t_surface->output_name2));
- }
- dynamicPaint_resetPreview(tpmd->canvas);
- }
- else if (tpmd->brush) {
- DynamicPaintBrushSettings *brush = pmd->brush, *t_brush = tpmd->brush;
- t_brush->pmd = tpmd;
-
- t_brush->flags = brush->flags;
- t_brush->collision = brush->collision;
-
- t_brush->r = brush->r;
- t_brush->g = brush->g;
- t_brush->b = brush->b;
- t_brush->alpha = brush->alpha;
- t_brush->wetness = brush->wetness;
-
- t_brush->particle_radius = brush->particle_radius;
- t_brush->particle_smooth = brush->particle_smooth;
- t_brush->paint_distance = brush->paint_distance;
- t_brush->psys = brush->psys;
-
- if (brush->paint_ramp)
- memcpy(t_brush->paint_ramp, brush->paint_ramp, sizeof(ColorBand));
- if (brush->vel_ramp)
- memcpy(t_brush->vel_ramp, brush->vel_ramp, sizeof(ColorBand));
-
- t_brush->proximity_falloff = brush->proximity_falloff;
- t_brush->wave_type = brush->wave_type;
- t_brush->ray_dir = brush->ray_dir;
-
- t_brush->wave_factor = brush->wave_factor;
- t_brush->wave_clamp = brush->wave_clamp;
- t_brush->max_velocity = brush->max_velocity;
- t_brush->smudge_strength = brush->smudge_strength;
- }
+ /* Init modifier */
+ tpmd->type = pmd->type;
+ if (pmd->canvas)
+ dynamicPaint_createType(tpmd, MOD_DYNAMICPAINT_TYPE_CANVAS, NULL);
+ if (pmd->brush)
+ dynamicPaint_createType(tpmd, MOD_DYNAMICPAINT_TYPE_BRUSH, NULL);
+
+ /* Copy data */
+ if (tpmd->canvas) {
+ DynamicPaintSurface *surface;
+ tpmd->canvas->pmd = tpmd;
+ /* free default surface */
+ if (tpmd->canvas->surfaces.first)
+ dynamicPaint_freeSurface(tpmd, tpmd->canvas->surfaces.first);
+
+ /* copy existing surfaces */
+ for (surface = pmd->canvas->surfaces.first; surface; surface = surface->next) {
+ DynamicPaintSurface *t_surface = dynamicPaint_createNewSurface(tpmd->canvas, NULL);
+ if (flag & LIB_ID_CREATE_NO_MAIN) {
+ /* TODO(sergey): Consider passing some tips to the surface
+ * creation to avoid this allocate-and-free cache behavior. */
+ BKE_ptcache_free_list(&t_surface->ptcaches);
+ tpmd->modifier.flag |= eModifierFlag_SharedCaches;
+ t_surface->ptcaches = surface->ptcaches;
+ t_surface->pointcache = surface->pointcache;
+ }
+
+ /* surface settings */
+ t_surface->brush_group = surface->brush_group;
+ MEM_freeN(t_surface->effector_weights);
+ t_surface->effector_weights = MEM_dupallocN(surface->effector_weights);
+
+ BLI_strncpy(t_surface->name, surface->name, sizeof(t_surface->name));
+ t_surface->format = surface->format;
+ t_surface->type = surface->type;
+ t_surface->disp_type = surface->disp_type;
+ t_surface->image_fileformat = surface->image_fileformat;
+ t_surface->effect_ui = surface->effect_ui;
+ t_surface->preview_id = surface->preview_id;
+ t_surface->init_color_type = surface->init_color_type;
+ t_surface->flags = surface->flags;
+ t_surface->effect = surface->effect;
+
+ t_surface->image_resolution = surface->image_resolution;
+ t_surface->substeps = surface->substeps;
+ t_surface->start_frame = surface->start_frame;
+ t_surface->end_frame = surface->end_frame;
+
+ copy_v4_v4(t_surface->init_color, surface->init_color);
+ t_surface->init_texture = surface->init_texture;
+ BLI_strncpy(
+ t_surface->init_layername, surface->init_layername, sizeof(t_surface->init_layername));
+
+ t_surface->dry_speed = surface->dry_speed;
+ t_surface->diss_speed = surface->diss_speed;
+ t_surface->color_dry_threshold = surface->color_dry_threshold;
+ t_surface->depth_clamp = surface->depth_clamp;
+ t_surface->disp_factor = surface->disp_factor;
+
+ t_surface->spread_speed = surface->spread_speed;
+ t_surface->color_spread_speed = surface->color_spread_speed;
+ t_surface->shrink_speed = surface->shrink_speed;
+ t_surface->drip_vel = surface->drip_vel;
+ t_surface->drip_acc = surface->drip_acc;
+
+ t_surface->influence_scale = surface->influence_scale;
+ t_surface->radius_scale = surface->radius_scale;
+
+ t_surface->wave_damping = surface->wave_damping;
+ t_surface->wave_speed = surface->wave_speed;
+ t_surface->wave_timescale = surface->wave_timescale;
+ t_surface->wave_spring = surface->wave_spring;
+ t_surface->wave_smoothness = surface->wave_smoothness;
+
+ BLI_strncpy(t_surface->uvlayer_name, surface->uvlayer_name, sizeof(t_surface->uvlayer_name));
+ BLI_strncpy(t_surface->image_output_path,
+ surface->image_output_path,
+ sizeof(t_surface->image_output_path));
+ BLI_strncpy(t_surface->output_name, surface->output_name, sizeof(t_surface->output_name));
+ BLI_strncpy(t_surface->output_name2, surface->output_name2, sizeof(t_surface->output_name2));
+ }
+ dynamicPaint_resetPreview(tpmd->canvas);
+ }
+ else if (tpmd->brush) {
+ DynamicPaintBrushSettings *brush = pmd->brush, *t_brush = tpmd->brush;
+ t_brush->pmd = tpmd;
+
+ t_brush->flags = brush->flags;
+ t_brush->collision = brush->collision;
+
+ t_brush->r = brush->r;
+ t_brush->g = brush->g;
+ t_brush->b = brush->b;
+ t_brush->alpha = brush->alpha;
+ t_brush->wetness = brush->wetness;
+
+ t_brush->particle_radius = brush->particle_radius;
+ t_brush->particle_smooth = brush->particle_smooth;
+ t_brush->paint_distance = brush->paint_distance;
+ t_brush->psys = brush->psys;
+
+ if (brush->paint_ramp)
+ memcpy(t_brush->paint_ramp, brush->paint_ramp, sizeof(ColorBand));
+ if (brush->vel_ramp)
+ memcpy(t_brush->vel_ramp, brush->vel_ramp, sizeof(ColorBand));
+
+ t_brush->proximity_falloff = brush->proximity_falloff;
+ t_brush->wave_type = brush->wave_type;
+ t_brush->ray_dir = brush->ray_dir;
+
+ t_brush->wave_factor = brush->wave_factor;
+ t_brush->wave_clamp = brush->wave_clamp;
+ t_brush->max_velocity = brush->max_velocity;
+ t_brush->smudge_strength = brush->smudge_strength;
+ }
}
/* allocates surface data depending on surface type */
static void dynamicPaint_allocateSurfaceType(DynamicPaintSurface *surface)
{
- PaintSurfaceData *sData = surface->data;
-
- switch (surface->type) {
- case MOD_DPAINT_SURFACE_T_PAINT:
- sData->type_data = MEM_callocN(sizeof(PaintPoint) * sData->total_points, "DynamicPaintSurface Data");
- break;
- case MOD_DPAINT_SURFACE_T_DISPLACE:
- sData->type_data = MEM_callocN(sizeof(float) * sData->total_points, "DynamicPaintSurface DepthData");
- break;
- case MOD_DPAINT_SURFACE_T_WEIGHT:
- sData->type_data = MEM_callocN(sizeof(float) * sData->total_points, "DynamicPaintSurface WeightData");
- break;
- case MOD_DPAINT_SURFACE_T_WAVE:
- sData->type_data = MEM_callocN(sizeof(PaintWavePoint) * sData->total_points, "DynamicPaintSurface WaveData");
- break;
- }
-
- if (sData->type_data == NULL)
- setError(surface->canvas, N_("Not enough free memory"));
+ PaintSurfaceData *sData = surface->data;
+
+ switch (surface->type) {
+ case MOD_DPAINT_SURFACE_T_PAINT:
+ sData->type_data = MEM_callocN(sizeof(PaintPoint) * sData->total_points,
+ "DynamicPaintSurface Data");
+ break;
+ case MOD_DPAINT_SURFACE_T_DISPLACE:
+ sData->type_data = MEM_callocN(sizeof(float) * sData->total_points,
+ "DynamicPaintSurface DepthData");
+ break;
+ case MOD_DPAINT_SURFACE_T_WEIGHT:
+ sData->type_data = MEM_callocN(sizeof(float) * sData->total_points,
+ "DynamicPaintSurface WeightData");
+ break;
+ case MOD_DPAINT_SURFACE_T_WAVE:
+ sData->type_data = MEM_callocN(sizeof(PaintWavePoint) * sData->total_points,
+ "DynamicPaintSurface WaveData");
+ break;
+ }
+
+ if (sData->type_data == NULL)
+ setError(surface->canvas, N_("Not enough free memory"));
}
static bool surface_usesAdjDistance(DynamicPaintSurface *surface)
{
- return ((surface->type == MOD_DPAINT_SURFACE_T_PAINT && surface->effect) ||
- (surface->type == MOD_DPAINT_SURFACE_T_WAVE));
+ return ((surface->type == MOD_DPAINT_SURFACE_T_PAINT && surface->effect) ||
+ (surface->type == MOD_DPAINT_SURFACE_T_WAVE));
}
static bool surface_usesAdjData(DynamicPaintSurface *surface)
{
- return (surface_usesAdjDistance(surface) ||
- (surface->format == MOD_DPAINT_SURFACE_F_VERTEX && surface->flags & MOD_DPAINT_ANTIALIAS));
+ return (surface_usesAdjDistance(surface) || (surface->format == MOD_DPAINT_SURFACE_F_VERTEX &&
+ surface->flags & MOD_DPAINT_ANTIALIAS));
}
/* initialize surface adjacency data */
static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, const bool force_init)
{
- PaintSurfaceData *sData = surface->data;
- Mesh *mesh = dynamicPaint_canvas_mesh_get(surface->canvas);
- PaintAdjData *ad;
- int *temp_data;
- int neigh_points = 0;
-
- if (!force_init && !surface_usesAdjData(surface))
- return;
-
- if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
- /* For vertex format, neighbors are connected by edges */
- neigh_points = 2 * mesh->totedge;
- }
- else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
- neigh_points = sData->total_points * 8;
- }
-
- if (!neigh_points)
- return;
-
- /* allocate memory */
- ad = sData->adj_data = MEM_callocN(sizeof(PaintAdjData), "Surface Adj Data");
- if (!ad)
- return;
- ad->n_index = MEM_callocN(sizeof(int) * sData->total_points, "Surface Adj Index");
- ad->n_num = MEM_callocN(sizeof(int) * sData->total_points, "Surface Adj Counts");
- temp_data = MEM_callocN(sizeof(int) * sData->total_points, "Temp Adj Data");
- ad->n_target = MEM_callocN(sizeof(int) * neigh_points, "Surface Adj Targets");
- ad->flags = MEM_callocN(sizeof(int) * sData->total_points, "Surface Adj Flags");
- ad->total_targets = neigh_points;
- ad->border = NULL;
- ad->total_border = 0;
-
- /* in case of allocation error, free memory */
- if (!ad->n_index || !ad->n_num || !ad->n_target || !temp_data) {
- dynamicPaint_freeAdjData(sData);
- if (temp_data)
- MEM_freeN(temp_data);
- setError(surface->canvas, N_("Not enough free memory"));
- return;
- }
-
- if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
- int i;
- int n_pos;
-
- /* For vertex format, count every vertex that is connected by an edge */
- int numOfEdges = mesh->totedge;
- int numOfPolys = mesh->totpoly;
- struct MEdge *edge = mesh->medge;
- struct MPoly *mpoly = mesh->mpoly;
- struct MLoop *mloop = mesh->mloop;
-
- /* count number of edges per vertex */
- for (i = 0; i < numOfEdges; i++) {
- ad->n_num[edge[i].v1]++;
- ad->n_num[edge[i].v2]++;
-
- temp_data[edge[i].v1]++;
- temp_data[edge[i].v2]++;
- }
-
- /* also add number of vertices to temp_data
- * to locate points on "mesh edge" */
- for (i = 0; i < numOfPolys; i++) {
- for (int j = 0; j < mpoly[i].totloop; j++) {
- temp_data[mloop[mpoly[i].loopstart + j].v]++;
- }
- }
-
- /* now check if total number of edges+faces for
- * each vertex is even, if not -> vertex is on mesh edge */
- for (i = 0; i < sData->total_points; i++) {
- if ((temp_data[i] % 2) || (temp_data[i] < 4)) {
- ad->flags[i] |= ADJ_ON_MESH_EDGE;
- }
-
- /* reset temp data */
- temp_data[i] = 0;
- }
-
- /* order n_index array */
- n_pos = 0;
- for (i = 0; i < sData->total_points; i++) {
- ad->n_index[i] = n_pos;
- n_pos += ad->n_num[i];
- }
-
- /* and now add neighbor data using that info */
- for (i = 0; i < numOfEdges; i++) {
- /* first vertex */
- int index = edge[i].v1;
- n_pos = ad->n_index[index] + temp_data[index];
- ad->n_target[n_pos] = edge[i].v2;
- temp_data[index]++;
-
- /* second vertex */
- index = edge[i].v2;
- n_pos = ad->n_index[index] + temp_data[index];
- ad->n_target[n_pos] = edge[i].v1;
- temp_data[index]++;
- }
- }
- else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
- /* for image sequences, only allocate memory.
- * bake initialization takes care of rest */
- }
-
- MEM_freeN(temp_data);
+ PaintSurfaceData *sData = surface->data;
+ Mesh *mesh = dynamicPaint_canvas_mesh_get(surface->canvas);
+ PaintAdjData *ad;
+ int *temp_data;
+ int neigh_points = 0;
+
+ if (!force_init && !surface_usesAdjData(surface))
+ return;
+
+ if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
+ /* For vertex format, neighbors are connected by edges */
+ neigh_points = 2 * mesh->totedge;
+ }
+ else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
+ neigh_points = sData->total_points * 8;
+ }
+
+ if (!neigh_points)
+ return;
+
+ /* allocate memory */
+ ad = sData->adj_data = MEM_callocN(sizeof(PaintAdjData), "Surface Adj Data");
+ if (!ad)
+ return;
+ ad->n_index = MEM_callocN(sizeof(int) * sData->total_points, "Surface Adj Index");
+ ad->n_num = MEM_callocN(sizeof(int) * sData->total_points, "Surface Adj Counts");
+ temp_data = MEM_callocN(sizeof(int) * sData->total_points, "Temp Adj Data");
+ ad->n_target = MEM_callocN(sizeof(int) * neigh_points, "Surface Adj Targets");
+ ad->flags = MEM_callocN(sizeof(int) * sData->total_points, "Surface Adj Flags");
+ ad->total_targets = neigh_points;
+ ad->border = NULL;
+ ad->total_border = 0;
+
+ /* in case of allocation error, free memory */
+ if (!ad->n_index || !ad->n_num || !ad->n_target || !temp_data) {
+ dynamicPaint_freeAdjData(sData);
+ if (temp_data)
+ MEM_freeN(temp_data);
+ setError(surface->canvas, N_("Not enough free memory"));
+ return;
+ }
+
+ if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
+ int i;
+ int n_pos;
+
+ /* For vertex format, count every vertex that is connected by an edge */
+ int numOfEdges = mesh->totedge;
+ int numOfPolys = mesh->totpoly;
+ struct MEdge *edge = mesh->medge;
+ struct MPoly *mpoly = mesh->mpoly;
+ struct MLoop *mloop = mesh->mloop;
+
+ /* count number of edges per vertex */
+ for (i = 0; i < numOfEdges; i++) {
+ ad->n_num[edge[i].v1]++;
+ ad->n_num[edge[i].v2]++;
+
+ temp_data[edge[i].v1]++;
+ temp_data[edge[i].v2]++;
+ }
+
+ /* also add number of vertices to temp_data
+ * to locate points on "mesh edge" */
+ for (i = 0; i < numOfPolys; i++) {
+ for (int j = 0; j < mpoly[i].totloop; j++) {
+ temp_data[mloop[mpoly[i].loopstart + j].v]++;
+ }
+ }
+
+ /* now check if total number of edges+faces for
+ * each vertex is even, if not -> vertex is on mesh edge */
+ for (i = 0; i < sData->total_points; i++) {
+ if ((temp_data[i] % 2) || (temp_data[i] < 4)) {
+ ad->flags[i] |= ADJ_ON_MESH_EDGE;
+ }
+
+ /* reset temp data */
+ temp_data[i] = 0;
+ }
+
+ /* order n_index array */
+ n_pos = 0;
+ for (i = 0; i < sData->total_points; i++) {
+ ad->n_index[i] = n_pos;
+ n_pos += ad->n_num[i];
+ }
+
+ /* and now add neighbor data using that info */
+ for (i = 0; i < numOfEdges; i++) {
+ /* first vertex */
+ int index = edge[i].v1;
+ n_pos = ad->n_index[index] + temp_data[index];
+ ad->n_target[n_pos] = edge[i].v2;
+ temp_data[index]++;
+
+ /* second vertex */
+ index = edge[i].v2;
+ n_pos = ad->n_index[index] + temp_data[index];
+ ad->n_target[n_pos] = edge[i].v1;
+ temp_data[index]++;
+ }
+ }
+ else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
+ /* for image sequences, only allocate memory.
+ * bake initialization takes care of rest */
+ }
+
+ MEM_freeN(temp_data);
}
typedef struct DynamicPaintSetInitColorData {
- const DynamicPaintSurface *surface;
+ const DynamicPaintSurface *surface;
- const MLoop *mloop;
- const MLoopUV *mloopuv;
- const MLoopTri *mlooptri;
- const MLoopCol *mloopcol;
- struct ImagePool *pool;
+ const MLoop *mloop;
+ const MLoopUV *mloopuv;
+ const MLoopTri *mlooptri;
+ const MLoopCol *mloopcol;
+ struct ImagePool *pool;
- const bool scene_color_manage;
+ const bool scene_color_manage;
} DynamicPaintSetInitColorData;
static void dynamic_paint_set_init_color_tex_to_vcol_cb(
- void *__restrict userdata,
- const int i,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+ void *__restrict userdata, const int i, const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintSetInitColorData *data = userdata;
+ const DynamicPaintSetInitColorData *data = userdata;
- const PaintSurfaceData *sData = data->surface->data;
- PaintPoint *pPoint = (PaintPoint *)sData->type_data;
+ const PaintSurfaceData *sData = data->surface->data;
+ PaintPoint *pPoint = (PaintPoint *)sData->type_data;
- const MLoop *mloop = data->mloop;
- const MLoopTri *mlooptri = data->mlooptri;
- const MLoopUV *mloopuv = data->mloopuv;
- struct ImagePool *pool = data->pool;
- Tex *tex = data->surface->init_texture;
+ const MLoop *mloop = data->mloop;
+ const MLoopTri *mlooptri = data->mlooptri;
+ const MLoopUV *mloopuv = data->mloopuv;
+ struct ImagePool *pool = data->pool;
+ Tex *tex = data->surface->init_texture;
- const bool scene_color_manage = data->scene_color_manage;
+ const bool scene_color_manage = data->scene_color_manage;
- float uv[3] = {0.0f};
+ float uv[3] = {0.0f};
- for (int j = 3; j--;) {
- TexResult texres = {0};
- const unsigned int vert = mloop[mlooptri[i].tri[j]].v;
+ for (int j = 3; j--;) {
+ TexResult texres = {0};
+ const unsigned int vert = mloop[mlooptri[i].tri[j]].v;
- /* remap to [-1.0, 1.0] */
- uv[0] = mloopuv[mlooptri[i].tri[j]].uv[0] * 2.0f - 1.0f;
- uv[1] = mloopuv[mlooptri[i].tri[j]].uv[1] * 2.0f - 1.0f;
+ /* remap to [-1.0, 1.0] */
+ uv[0] = mloopuv[mlooptri[i].tri[j]].uv[0] * 2.0f - 1.0f;
+ uv[1] = mloopuv[mlooptri[i].tri[j]].uv[1] * 2.0f - 1.0f;
- multitex_ext_safe(tex, uv, &texres, pool, scene_color_manage, false);
+ multitex_ext_safe(tex, uv, &texres, pool, scene_color_manage, false);
- if (texres.tin > pPoint[vert].color[3]) {
- copy_v3_v3(pPoint[vert].color, &texres.tr);
- pPoint[vert].color[3] = texres.tin;
- }
- }
+ if (texres.tin > pPoint[vert].color[3]) {
+ copy_v3_v3(pPoint[vert].color, &texres.tr);
+ pPoint[vert].color[3] = texres.tin;
+ }
+ }
}
static void dynamic_paint_set_init_color_tex_to_imseq_cb(
- void *__restrict userdata,
- const int i,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+ void *__restrict userdata, const int i, const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintSetInitColorData *data = userdata;
+ const DynamicPaintSetInitColorData *data = userdata;
- const PaintSurfaceData *sData = data->surface->data;
- PaintPoint *pPoint = (PaintPoint *)sData->type_data;
+ const PaintSurfaceData *sData = data->surface->data;
+ PaintPoint *pPoint = (PaintPoint *)sData->type_data;
- const MLoopTri *mlooptri = data->mlooptri;
- const MLoopUV *mloopuv = data->mloopuv;
- Tex *tex = data->surface->init_texture;
- ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
- const int samples = (data->surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
+ const MLoopTri *mlooptri = data->mlooptri;
+ const MLoopUV *mloopuv = data->mloopuv;
+ Tex *tex = data->surface->init_texture;
+ ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
+ const int samples = (data->surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
- const bool scene_color_manage = data->scene_color_manage;
+ const bool scene_color_manage = data->scene_color_manage;
- float uv[9] = {0.0f};
- float uv_final[3] = {0.0f};
+ float uv[9] = {0.0f};
+ float uv_final[3] = {0.0f};
- TexResult texres = {0};
+ TexResult texres = {0};
- /* collect all uvs */
- for (int j = 3; j--;) {
- copy_v2_v2(&uv[j * 3], mloopuv[mlooptri[f_data->uv_p[i].tri_index].tri[j]].uv);
- }
+ /* collect all uvs */
+ for (int j = 3; j--;) {
+ copy_v2_v2(&uv[j * 3], mloopuv[mlooptri[f_data->uv_p[i].tri_index].tri[j]].uv);
+ }
- /* interpolate final uv pos */
- interp_v3_v3v3v3(uv_final, &uv[0], &uv[3], &uv[6], f_data->barycentricWeights[i * samples].v);
- /* remap to [-1.0, 1.0] */
- uv_final[0] = uv_final[0] * 2.0f - 1.0f;
- uv_final[1] = uv_final[1] * 2.0f - 1.0f;
+ /* interpolate final uv pos */
+ interp_v3_v3v3v3(uv_final, &uv[0], &uv[3], &uv[6], f_data->barycentricWeights[i * samples].v);
+ /* remap to [-1.0, 1.0] */
+ uv_final[0] = uv_final[0] * 2.0f - 1.0f;
+ uv_final[1] = uv_final[1] * 2.0f - 1.0f;
- multitex_ext_safe(tex, uv_final, &texres, NULL, scene_color_manage, false);
+ multitex_ext_safe(tex, uv_final, &texres, NULL, scene_color_manage, false);
- /* apply color */
- copy_v3_v3(pPoint[i].color, &texres.tr);
- pPoint[i].color[3] = texres.tin;
+ /* apply color */
+ copy_v3_v3(pPoint[i].color, &texres.tr);
+ pPoint[i].color[3] = texres.tin;
}
static void dynamic_paint_set_init_color_vcol_to_imseq_cb(
- void *__restrict userdata,
- const int i,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+ void *__restrict userdata, const int i, const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintSetInitColorData *data = userdata;
+ const DynamicPaintSetInitColorData *data = userdata;
- const PaintSurfaceData *sData = data->surface->data;
- PaintPoint *pPoint = (PaintPoint *)sData->type_data;
+ const PaintSurfaceData *sData = data->surface->data;
+ PaintPoint *pPoint = (PaintPoint *)sData->type_data;
- const MLoopTri *mlooptri = data->mlooptri;
- const MLoopCol *mloopcol = data->mloopcol;
- ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
- const int samples = (data->surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
+ const MLoopTri *mlooptri = data->mlooptri;
+ const MLoopCol *mloopcol = data->mloopcol;
+ ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
+ const int samples = (data->surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
- const int tri_idx = f_data->uv_p[i].tri_index;
- float colors[3][4];
- float final_color[4];
+ const int tri_idx = f_data->uv_p[i].tri_index;
+ float colors[3][4];
+ float final_color[4];
- /* collect color values */
- for (int j = 3; j--;) {
- rgba_uchar_to_float(colors[j], (const unsigned char *)&mloopcol[mlooptri[tri_idx].tri[j]].r);
- }
+ /* collect color values */
+ for (int j = 3; j--;) {
+ rgba_uchar_to_float(colors[j], (const unsigned char *)&mloopcol[mlooptri[tri_idx].tri[j]].r);
+ }
- /* interpolate final color */
- interp_v4_v4v4v4(final_color, UNPACK3(colors), f_data->barycentricWeights[i * samples].v);
+ /* interpolate final color */
+ interp_v4_v4v4v4(final_color, UNPACK3(colors), f_data->barycentricWeights[i * samples].v);
- copy_v4_v4(pPoint[i].color, final_color);
+ copy_v4_v4(pPoint[i].color, final_color);
}
static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface *surface)
{
- PaintSurfaceData *sData = surface->data;
- PaintPoint *pPoint = (PaintPoint *)sData->type_data;
- Mesh *mesh = dynamicPaint_canvas_mesh_get(surface->canvas);
- int i;
- const bool scene_color_manage = BKE_scene_check_color_management_enabled(scene);
-
- if (surface->type != MOD_DPAINT_SURFACE_T_PAINT)
- return;
-
- if (surface->init_color_type == MOD_DPAINT_INITIAL_NONE)
- return;
-
- /* Single color */
- if (surface->init_color_type == MOD_DPAINT_INITIAL_COLOR) {
- /* apply color to every surface point */
- for (i = 0; i < sData->total_points; i++) {
- copy_v4_v4(pPoint[i].color, surface->init_color);
- }
- }
- /* UV mapped texture */
- else if (surface->init_color_type == MOD_DPAINT_INITIAL_TEXTURE) {
- Tex *tex = surface->init_texture;
-
- const MLoop *mloop = mesh->mloop;
- const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
- const int tottri = BKE_mesh_runtime_looptri_len(mesh);
- const MLoopUV *mloopuv = NULL;
-
- char uvname[MAX_CUSTOMDATA_LAYER_NAME];
-
- if (!tex)
- return;
-
- /* get uv map */
- CustomData_validate_layer_name(&mesh->ldata, CD_MLOOPUV, surface->init_layername, uvname);
- mloopuv = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvname);
- if (!mloopuv)
- return;
-
- /* for vertex surface loop through tfaces and find uv color
- * that provides highest alpha */
- if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
- struct ImagePool *pool = BKE_image_pool_new();
-
- DynamicPaintSetInitColorData data = {
- .surface = surface,
- .mloop = mloop, .mlooptri = mlooptri, .mloopuv = mloopuv, .pool = pool,
- .scene_color_manage = scene_color_manage,
- };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (tottri > 1000);
- BLI_task_parallel_range(0, tottri,
- &data,
- dynamic_paint_set_init_color_tex_to_vcol_cb,
- &settings);
- BKE_image_pool_free(pool);
- }
- else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
- DynamicPaintSetInitColorData data = {
- .surface = surface,
- .mlooptri = mlooptri, .mloopuv = mloopuv,
- .scene_color_manage = scene_color_manage,
- };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 1000);
- BLI_task_parallel_range(0, sData->total_points,
- &data,
- dynamic_paint_set_init_color_tex_to_imseq_cb,
- &settings);
- }
- }
- /* vertex color layer */
- else if (surface->init_color_type == MOD_DPAINT_INITIAL_VERTEXCOLOR) {
-
- /* for vertex surface, just copy colors from mcol */
- if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
- const MLoop *mloop = mesh->mloop;
- const int totloop = mesh->totloop;
- const MLoopCol *col = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPCOL, surface->init_layername);
- if (!col)
- return;
-
- for (i = 0; i < totloop; i++) {
- rgba_uchar_to_float(pPoint[mloop[i].v].color, (const unsigned char *)&col[mloop[i].v].r);
- }
- }
- else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
- const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
- MLoopCol *col = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPCOL, surface->init_layername);
- if (!col)
- return;
-
- DynamicPaintSetInitColorData data = {
- .surface = surface,
- .mlooptri = mlooptri, .mloopcol = col,
- };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 1000);
- BLI_task_parallel_range(0, sData->total_points,
- &data,
- dynamic_paint_set_init_color_vcol_to_imseq_cb,
- &settings);
- }
- }
+ PaintSurfaceData *sData = surface->data;
+ PaintPoint *pPoint = (PaintPoint *)sData->type_data;
+ Mesh *mesh = dynamicPaint_canvas_mesh_get(surface->canvas);
+ int i;
+ const bool scene_color_manage = BKE_scene_check_color_management_enabled(scene);
+
+ if (surface->type != MOD_DPAINT_SURFACE_T_PAINT)
+ return;
+
+ if (surface->init_color_type == MOD_DPAINT_INITIAL_NONE)
+ return;
+
+ /* Single color */
+ if (surface->init_color_type == MOD_DPAINT_INITIAL_COLOR) {
+ /* apply color to every surface point */
+ for (i = 0; i < sData->total_points; i++) {
+ copy_v4_v4(pPoint[i].color, surface->init_color);
+ }
+ }
+ /* UV mapped texture */
+ else if (surface->init_color_type == MOD_DPAINT_INITIAL_TEXTURE) {
+ Tex *tex = surface->init_texture;
+
+ const MLoop *mloop = mesh->mloop;
+ const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ const int tottri = BKE_mesh_runtime_looptri_len(mesh);
+ const MLoopUV *mloopuv = NULL;
+
+ char uvname[MAX_CUSTOMDATA_LAYER_NAME];
+
+ if (!tex)
+ return;
+
+ /* get uv map */
+ CustomData_validate_layer_name(&mesh->ldata, CD_MLOOPUV, surface->init_layername, uvname);
+ mloopuv = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvname);
+ if (!mloopuv)
+ return;
+
+ /* for vertex surface loop through tfaces and find uv color
+ * that provides highest alpha */
+ if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
+ struct ImagePool *pool = BKE_image_pool_new();
+
+ DynamicPaintSetInitColorData data = {
+ .surface = surface,
+ .mloop = mloop,
+ .mlooptri = mlooptri,
+ .mloopuv = mloopuv,
+ .pool = pool,
+ .scene_color_manage = scene_color_manage,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (tottri > 1000);
+ BLI_task_parallel_range(
+ 0, tottri, &data, dynamic_paint_set_init_color_tex_to_vcol_cb, &settings);
+ BKE_image_pool_free(pool);
+ }
+ else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
+ DynamicPaintSetInitColorData data = {
+ .surface = surface,
+ .mlooptri = mlooptri,
+ .mloopuv = mloopuv,
+ .scene_color_manage = scene_color_manage,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_set_init_color_tex_to_imseq_cb, &settings);
+ }
+ }
+ /* vertex color layer */
+ else if (surface->init_color_type == MOD_DPAINT_INITIAL_VERTEXCOLOR) {
+
+ /* for vertex surface, just copy colors from mcol */
+ if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
+ const MLoop *mloop = mesh->mloop;
+ const int totloop = mesh->totloop;
+ const MLoopCol *col = CustomData_get_layer_named(
+ &mesh->ldata, CD_MLOOPCOL, surface->init_layername);
+ if (!col)
+ return;
+
+ for (i = 0; i < totloop; i++) {
+ rgba_uchar_to_float(pPoint[mloop[i].v].color, (const unsigned char *)&col[mloop[i].v].r);
+ }
+ }
+ else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
+ const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ MLoopCol *col = CustomData_get_layer_named(
+ &mesh->ldata, CD_MLOOPCOL, surface->init_layername);
+ if (!col)
+ return;
+
+ DynamicPaintSetInitColorData data = {
+ .surface = surface,
+ .mlooptri = mlooptri,
+ .mloopcol = col,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_set_init_color_vcol_to_imseq_cb, &settings);
+ }
+ }
}
/* clears surface data back to zero */
void dynamicPaint_clearSurface(const Scene *scene, DynamicPaintSurface *surface)
{
- PaintSurfaceData *sData = surface->data;
- if (sData && sData->type_data) {
- unsigned int data_size;
-
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT)
- data_size = sizeof(PaintPoint);
- else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE)
- data_size = sizeof(PaintWavePoint);
- else
- data_size = sizeof(float);
-
- memset(sData->type_data, 0, data_size * sData->total_points);
-
- /* set initial color */
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT)
- dynamicPaint_setInitialColor(scene, surface);
-
- if (sData->bData)
- sData->bData->clear = 1;
- }
+ PaintSurfaceData *sData = surface->data;
+ if (sData && sData->type_data) {
+ unsigned int data_size;
+
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT)
+ data_size = sizeof(PaintPoint);
+ else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE)
+ data_size = sizeof(PaintWavePoint);
+ else
+ data_size = sizeof(float);
+
+ memset(sData->type_data, 0, data_size * sData->total_points);
+
+ /* set initial color */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT)
+ dynamicPaint_setInitialColor(scene, surface);
+
+ if (sData->bData)
+ sData->bData->clear = 1;
+ }
}
/* completely (re)initializes surface (only for point cache types)*/
bool dynamicPaint_resetSurface(const Scene *scene, DynamicPaintSurface *surface)
{
- int numOfPoints = dynamicPaint_surfaceNumOfPoints(surface);
- /* free existing data */
- if (surface->data)
- dynamicPaint_freeSurfaceData(surface);
-
- /* don't reallocate for image sequence types. they get handled only on bake */
- if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
- return true;
- if (numOfPoints < 1)
- return false;
-
- /* allocate memory */
- surface->data = MEM_callocN(sizeof(PaintSurfaceData), "PaintSurfaceData");
- if (!surface->data)
- return false;
-
- /* allocate data depending on surface type and format */
- surface->data->total_points = numOfPoints;
- dynamicPaint_allocateSurfaceType(surface);
- dynamicPaint_initAdjacencyData(surface, false);
-
- /* set initial color */
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT)
- dynamicPaint_setInitialColor(scene, surface);
-
- return true;
+ int numOfPoints = dynamicPaint_surfaceNumOfPoints(surface);
+ /* free existing data */
+ if (surface->data)
+ dynamicPaint_freeSurfaceData(surface);
+
+ /* don't reallocate for image sequence types. they get handled only on bake */
+ if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
+ return true;
+ if (numOfPoints < 1)
+ return false;
+
+ /* allocate memory */
+ surface->data = MEM_callocN(sizeof(PaintSurfaceData), "PaintSurfaceData");
+ if (!surface->data)
+ return false;
+
+ /* allocate data depending on surface type and format */
+ surface->data->total_points = numOfPoints;
+ dynamicPaint_allocateSurfaceType(surface);
+ dynamicPaint_initAdjacencyData(surface, false);
+
+ /* set initial color */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT)
+ dynamicPaint_setInitialColor(scene, surface);
+
+ return true;
}
/* make sure allocated surface size matches current requirements */
static bool dynamicPaint_checkSurfaceData(const Scene *scene, DynamicPaintSurface *surface)
{
- if (!surface->data || ((dynamicPaint_surfaceNumOfPoints(surface) != surface->data->total_points))) {
- return dynamicPaint_resetSurface(scene, surface);
- }
- return true;
+ if (!surface->data ||
+ ((dynamicPaint_surfaceNumOfPoints(surface) != surface->data->total_points))) {
+ return dynamicPaint_resetSurface(scene, surface);
+ }
+ return true;
}
-
/***************************** Modifier processing ******************************/
typedef struct DynamicPaintModifierApplyData {
- const DynamicPaintSurface *surface;
- Object *ob;
+ const DynamicPaintSurface *surface;
+ Object *ob;
- MVert *mvert;
- const MLoop *mloop;
- const MPoly *mpoly;
+ MVert *mvert;
+ const MLoop *mloop;
+ const MPoly *mpoly;
- float (*fcolor)[4];
- MLoopCol *mloopcol;
- MLoopCol *mloopcol_wet;
- MLoopCol *mloopcol_preview;
+ float (*fcolor)[4];
+ MLoopCol *mloopcol;
+ MLoopCol *mloopcol_wet;
+ MLoopCol *mloopcol_preview;
} DynamicPaintModifierApplyData;
-static void dynamic_paint_apply_surface_displace_cb(
- void *__restrict userdata,
- const int i,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void dynamic_paint_apply_surface_displace_cb(void *__restrict userdata,
+ const int i,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintModifierApplyData *data = userdata;
+ const DynamicPaintModifierApplyData *data = userdata;
- const DynamicPaintSurface *surface = data->surface;
- MVert *mvert = data->mvert;
+ const DynamicPaintSurface *surface = data->surface;
+ MVert *mvert = data->mvert;
- float normal[3];
- const float *value = (float *)surface->data->type_data;
- const float val = value[i] * surface->disp_factor;
+ float normal[3];
+ const float *value = (float *)surface->data->type_data;
+ const float val = value[i] * surface->disp_factor;
- normal_short_to_float_v3(normal, mvert[i].no);
+ normal_short_to_float_v3(normal, mvert[i].no);
- /* same as 'mvert[i].co[0] -= normal[0] * val' etc. */
- madd_v3_v3fl(mvert[i].co, normal, -val);
+ /* same as 'mvert[i].co[0] -= normal[0] * val' etc. */
+ madd_v3_v3fl(mvert[i].co, normal, -val);
}
/* apply displacing vertex surface to the derived mesh */
static void dynamicPaint_applySurfaceDisplace(DynamicPaintSurface *surface, Mesh *result)
{
- PaintSurfaceData *sData = surface->data;
-
- if (!sData || surface->format != MOD_DPAINT_SURFACE_F_VERTEX)
- return;
-
- /* displace paint */
- if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
- MVert *mvert = result->mvert;
-
- DynamicPaintModifierApplyData data = { .surface = surface, .mvert = mvert, };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 10000);
- BLI_task_parallel_range(0, sData->total_points,
- &data,
- dynamic_paint_apply_surface_displace_cb,
- &settings);
- }
+ PaintSurfaceData *sData = surface->data;
+
+ if (!sData || surface->format != MOD_DPAINT_SURFACE_F_VERTEX)
+ return;
+
+ /* displace paint */
+ if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
+ MVert *mvert = result->mvert;
+
+ DynamicPaintModifierApplyData data = {
+ .surface = surface,
+ .mvert = mvert,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 10000);
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_apply_surface_displace_cb, &settings);
+ }
}
static void dynamic_paint_apply_surface_vpaint_blend_cb(
- void *__restrict userdata,
- const int i,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+ void *__restrict userdata, const int i, const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintModifierApplyData *data = userdata;
+ const DynamicPaintModifierApplyData *data = userdata;
- PaintPoint *pPoint = (PaintPoint *)data->surface->data->type_data;
- float (*fcolor)[4] = data->fcolor;
+ PaintPoint *pPoint = (PaintPoint *)data->surface->data->type_data;
+ float(*fcolor)[4] = data->fcolor;
- /* blend dry and wet layer */
- blendColors(pPoint[i].color, pPoint[i].color[3], pPoint[i].e_color, pPoint[i].e_color[3], fcolor[i]);
+ /* blend dry and wet layer */
+ blendColors(
+ pPoint[i].color, pPoint[i].color[3], pPoint[i].e_color, pPoint[i].e_color[3], fcolor[i]);
}
-static void dynamic_paint_apply_surface_vpaint_cb(
- void *__restrict userdata,
- const int p_index,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void dynamic_paint_apply_surface_vpaint_cb(void *__restrict userdata,
+ const int p_index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintModifierApplyData *data = userdata;
- Object *ob = data->ob;
-
- const MLoop *mloop = data->mloop;
- const MPoly *mpoly = data->mpoly;
-
- const DynamicPaintSurface *surface = data->surface;
- PaintPoint *pPoint = (PaintPoint *)surface->data->type_data;
- float (*fcolor)[4] = data->fcolor;
-
- MLoopCol *mloopcol = data->mloopcol;
- MLoopCol *mloopcol_wet = data->mloopcol_wet;
- MLoopCol *mloopcol_preview = data->mloopcol_preview;
-
- const Material *material = mloopcol_preview ?
- give_current_material(ob, mpoly[p_index].mat_nr + 1) : NULL;
-
- for (int j = 0; j < mpoly[p_index].totloop; j++) {
- const int l_index = mpoly[p_index].loopstart + j;
- const int v_index = mloop[l_index].v;
-
- /* save layer data to output layer */
- /* apply color */
- if (mloopcol) {
- rgba_float_to_uchar((unsigned char *)&mloopcol[l_index].r, fcolor[v_index]);
- }
- /* apply wetness */
- if (mloopcol_wet) {
- const char c = unit_float_to_uchar_clamp(pPoint[v_index].wetness);
- mloopcol_wet[l_index].r = c;
- mloopcol_wet[l_index].g = c;
- mloopcol_wet[l_index].b = c;
- mloopcol_wet[l_index].a = 255;
- }
-
- /* viewport preview */
- if (mloopcol_preview) {
- if (surface->preview_id == MOD_DPAINT_SURFACE_PREV_PAINT) {
- float c[3];
-
- /* Apply material color as base vertex color for preview */
- mloopcol_preview[l_index].a = 255;
- if (material) {
- c[0] = material->r;
- c[1] = material->g;
- c[2] = material->b;
- }
- else { /* default gray */
- c[0] = 0.65f;
- c[1] = 0.65f;
- c[2] = 0.65f;
- }
- /* mix surface color */
- interp_v3_v3v3(c, c, fcolor[v_index], fcolor[v_index][3]);
-
- rgb_float_to_uchar((unsigned char *)&mloopcol_preview[l_index].r, c);
- }
- else {
- const char c = unit_float_to_uchar_clamp(pPoint[v_index].wetness);
- mloopcol_preview[l_index].r = c;
- mloopcol_preview[l_index].g = c;
- mloopcol_preview[l_index].b = c;
- mloopcol_preview[l_index].a = 255;
- }
- }
- }
+ const DynamicPaintModifierApplyData *data = userdata;
+ Object *ob = data->ob;
+
+ const MLoop *mloop = data->mloop;
+ const MPoly *mpoly = data->mpoly;
+
+ const DynamicPaintSurface *surface = data->surface;
+ PaintPoint *pPoint = (PaintPoint *)surface->data->type_data;
+ float(*fcolor)[4] = data->fcolor;
+
+ MLoopCol *mloopcol = data->mloopcol;
+ MLoopCol *mloopcol_wet = data->mloopcol_wet;
+ MLoopCol *mloopcol_preview = data->mloopcol_preview;
+
+ const Material *material = mloopcol_preview ?
+ give_current_material(ob, mpoly[p_index].mat_nr + 1) :
+ NULL;
+
+ for (int j = 0; j < mpoly[p_index].totloop; j++) {
+ const int l_index = mpoly[p_index].loopstart + j;
+ const int v_index = mloop[l_index].v;
+
+ /* save layer data to output layer */
+ /* apply color */
+ if (mloopcol) {
+ rgba_float_to_uchar((unsigned char *)&mloopcol[l_index].r, fcolor[v_index]);
+ }
+ /* apply wetness */
+ if (mloopcol_wet) {
+ const char c = unit_float_to_uchar_clamp(pPoint[v_index].wetness);
+ mloopcol_wet[l_index].r = c;
+ mloopcol_wet[l_index].g = c;
+ mloopcol_wet[l_index].b = c;
+ mloopcol_wet[l_index].a = 255;
+ }
+
+ /* viewport preview */
+ if (mloopcol_preview) {
+ if (surface->preview_id == MOD_DPAINT_SURFACE_PREV_PAINT) {
+ float c[3];
+
+ /* Apply material color as base vertex color for preview */
+ mloopcol_preview[l_index].a = 255;
+ if (material) {
+ c[0] = material->r;
+ c[1] = material->g;
+ c[2] = material->b;
+ }
+ else { /* default gray */
+ c[0] = 0.65f;
+ c[1] = 0.65f;
+ c[2] = 0.65f;
+ }
+ /* mix surface color */
+ interp_v3_v3v3(c, c, fcolor[v_index], fcolor[v_index][3]);
+
+ rgb_float_to_uchar((unsigned char *)&mloopcol_preview[l_index].r, c);
+ }
+ else {
+ const char c = unit_float_to_uchar_clamp(pPoint[v_index].wetness);
+ mloopcol_preview[l_index].r = c;
+ mloopcol_preview[l_index].g = c;
+ mloopcol_preview[l_index].b = c;
+ mloopcol_preview[l_index].a = 255;
+ }
+ }
+ }
}
-static void dynamic_paint_apply_surface_wave_cb(
- void *__restrict userdata,
- const int i,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void dynamic_paint_apply_surface_wave_cb(void *__restrict userdata,
+ const int i,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintModifierApplyData *data = userdata;
+ const DynamicPaintModifierApplyData *data = userdata;
- PaintWavePoint *wPoint = (PaintWavePoint *)data->surface->data->type_data;
- MVert *mvert = data->mvert;
- float normal[3];
+ PaintWavePoint *wPoint = (PaintWavePoint *)data->surface->data->type_data;
+ MVert *mvert = data->mvert;
+ float normal[3];
- normal_short_to_float_v3(normal, mvert[i].no);
- madd_v3_v3fl(mvert[i].co, normal, wPoint[i].height);
+ normal_short_to_float_v3(normal, mvert[i].no);
+ madd_v3_v3fl(mvert[i].co, normal, wPoint[i].height);
}
/*
* Apply canvas data to the object derived mesh
*/
-static Mesh *dynamicPaint_Modifier_apply(
- DynamicPaintModifierData *pmd, Object *ob, Mesh *mesh)
+static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object *ob, Mesh *mesh)
{
- Mesh *result = BKE_mesh_copy_for_eval(mesh, false);
-
- if (pmd->canvas && !(pmd->canvas->flags & MOD_DPAINT_BAKING)) {
-
- DynamicPaintSurface *surface;
- bool update_normals = false;
-
- /* loop through surfaces */
- for (surface = pmd->canvas->surfaces.first; surface; surface = surface->next) {
- PaintSurfaceData *sData = surface->data;
-
- if (surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ && sData) {
- if (!(surface->flags & MOD_DPAINT_ACTIVE))
- continue;
-
- /* process vertex surface previews */
- if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
-
- /* vertex color paint */
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- MLoop *mloop = result->mloop;
- const int totloop = result->totloop;
- MPoly *mpoly = result->mpoly;
- const int totpoly = result->totpoly;
-
- /* paint is stored on dry and wet layers, so mix final color first */
- float (*fcolor)[4] = MEM_callocN(sizeof(*fcolor) * sData->total_points, "Temp paint color");
-
- DynamicPaintModifierApplyData data = { .surface = surface, .fcolor = fcolor, };
- {
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 1000);
- BLI_task_parallel_range(
- 0, sData->total_points,
- &data,
- dynamic_paint_apply_surface_vpaint_blend_cb,
- &settings);
- }
-
- /* paint layer */
- MLoopCol *mloopcol = CustomData_get_layer_named(&result->ldata, CD_MLOOPCOL, surface->output_name);
- /* if output layer is lost from a constructive modifier, re-add it */
- if (!mloopcol && dynamicPaint_outputLayerExists(surface, ob, 0)) {
- mloopcol = CustomData_add_layer_named(
- &result->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name);
- }
-
- /* wet layer */
- MLoopCol *mloopcol_wet = CustomData_get_layer_named(&result->ldata, CD_MLOOPCOL, surface->output_name2);
- /* if output layer is lost from a constructive modifier, re-add it */
- if (!mloopcol_wet && dynamicPaint_outputLayerExists(surface, ob, 1)) {
- mloopcol_wet = CustomData_add_layer_named(
- &result->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name2);
- }
-
- /* Save preview results to weight layer to be able to share same drawing methods */
- MLoopCol *mloopcol_preview = NULL;
- if (surface->flags & MOD_DPAINT_PREVIEW) {
- mloopcol_preview = CustomData_get_layer(&result->ldata, CD_PREVIEW_MLOOPCOL);
- if (!mloopcol_preview) {
- mloopcol_preview = CustomData_add_layer(
- &result->ldata, CD_PREVIEW_MLOOPCOL, CD_CALLOC, NULL, totloop);
- }
- }
-
- data.ob = ob;
- data.mloop = mloop;
- data.mpoly = mpoly;
- data.mloopcol = mloopcol;
- data.mloopcol_wet = mloopcol_wet;
- data.mloopcol_preview = mloopcol_preview;
-
- {
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (totpoly > 1000);
- BLI_task_parallel_range(
- 0, totpoly,
- &data,
- dynamic_paint_apply_surface_vpaint_cb,
- &settings);
- }
-
- MEM_freeN(fcolor);
-
- /* Mark tessellated CD layers as dirty. */
- //result->dirty |= DM_DIRTY_TESS_CDLAYERS;
- }
- /* vertex group paint */
- else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
- int defgrp_index = defgroup_name_index(ob, surface->output_name);
- MDeformVert *dvert = CustomData_get_layer(&result->vdata, CD_MDEFORMVERT);
- float *weight = (float *)sData->type_data;
-
- /* viewport preview */
- if (surface->flags & MOD_DPAINT_PREVIEW) {
- /* Save preview results to weight layer to be
- * able to share same drawing methods.
- * Note this func also sets DM_DIRTY_TESS_CDLAYERS flag! */
- //TODO port this function
- //DM_update_weight_mcol(ob, result, 0, weight, 0, NULL);
- }
-
- /* apply weights into a vertex group, if doesn't exists add a new layer */
- if (defgrp_index != -1 && !dvert && (surface->output_name[0] != '\0')) {
- dvert = CustomData_add_layer(&result->vdata, CD_MDEFORMVERT, CD_CALLOC,
- NULL, sData->total_points);
- }
- if (defgrp_index != -1 && dvert) {
- int i;
- for (i = 0; i < sData->total_points; i++) {
- MDeformVert *dv = &dvert[i];
- MDeformWeight *def_weight = defvert_find_index(dv, defgrp_index);
-
- /* skip if weight value is 0 and no existing weight is found */
- if ((def_weight != NULL) || (weight[i] != 0.0f)) {
- /* if not found, add a weight for it */
- if (def_weight == NULL) {
- def_weight = defvert_verify_index(dv, defgrp_index);
- }
-
- /* set weight value */
- def_weight->weight = weight[i];
- }
- }
- }
- }
- /* wave simulation */
- else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
- MVert *mvert = result->mvert;
-
- DynamicPaintModifierApplyData data = { .surface = surface, .mvert = mvert, };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 1000);
- BLI_task_parallel_range(
- 0, sData->total_points,
- &data,
- dynamic_paint_apply_surface_wave_cb,
- &settings);
- update_normals = true;
- }
-
- /* displace */
- if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
- dynamicPaint_applySurfaceDisplace(surface, result);
- update_normals = true;
- }
- }
- }
- }
-
- if (update_normals) {
- //result->dirty |= DM_DIRTY_NORMALS;
- }
- }
- /* make a copy of mesh to use as brush data */
- if (pmd->brush) {
- DynamicPaintRuntime *runtime_data = dynamicPaint_Modifier_runtime_ensure(pmd);
- if (runtime_data->brush_mesh != NULL) {
- BKE_id_free(NULL, runtime_data->brush_mesh);
- }
- runtime_data->brush_mesh = BKE_mesh_copy_for_eval(result, false);
- }
-
- return result;
+ Mesh *result = BKE_mesh_copy_for_eval(mesh, false);
+
+ if (pmd->canvas && !(pmd->canvas->flags & MOD_DPAINT_BAKING)) {
+
+ DynamicPaintSurface *surface;
+ bool update_normals = false;
+
+ /* loop through surfaces */
+ for (surface = pmd->canvas->surfaces.first; surface; surface = surface->next) {
+ PaintSurfaceData *sData = surface->data;
+
+ if (surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ && sData) {
+ if (!(surface->flags & MOD_DPAINT_ACTIVE))
+ continue;
+
+ /* process vertex surface previews */
+ if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
+
+ /* vertex color paint */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ MLoop *mloop = result->mloop;
+ const int totloop = result->totloop;
+ MPoly *mpoly = result->mpoly;
+ const int totpoly = result->totpoly;
+
+ /* paint is stored on dry and wet layers, so mix final color first */
+ float(*fcolor)[4] = MEM_callocN(sizeof(*fcolor) * sData->total_points,
+ "Temp paint color");
+
+ DynamicPaintModifierApplyData data = {
+ .surface = surface,
+ .fcolor = fcolor,
+ };
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(0,
+ sData->total_points,
+ &data,
+ dynamic_paint_apply_surface_vpaint_blend_cb,
+ &settings);
+ }
+
+ /* paint layer */
+ MLoopCol *mloopcol = CustomData_get_layer_named(
+ &result->ldata, CD_MLOOPCOL, surface->output_name);
+ /* if output layer is lost from a constructive modifier, re-add it */
+ if (!mloopcol && dynamicPaint_outputLayerExists(surface, ob, 0)) {
+ mloopcol = CustomData_add_layer_named(
+ &result->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name);
+ }
+
+ /* wet layer */
+ MLoopCol *mloopcol_wet = CustomData_get_layer_named(
+ &result->ldata, CD_MLOOPCOL, surface->output_name2);
+ /* if output layer is lost from a constructive modifier, re-add it */
+ if (!mloopcol_wet && dynamicPaint_outputLayerExists(surface, ob, 1)) {
+ mloopcol_wet = CustomData_add_layer_named(
+ &result->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name2);
+ }
+
+ /* Save preview results to weight layer to be able to share same drawing methods */
+ MLoopCol *mloopcol_preview = NULL;
+ if (surface->flags & MOD_DPAINT_PREVIEW) {
+ mloopcol_preview = CustomData_get_layer(&result->ldata, CD_PREVIEW_MLOOPCOL);
+ if (!mloopcol_preview) {
+ mloopcol_preview = CustomData_add_layer(
+ &result->ldata, CD_PREVIEW_MLOOPCOL, CD_CALLOC, NULL, totloop);
+ }
+ }
+
+ data.ob = ob;
+ data.mloop = mloop;
+ data.mpoly = mpoly;
+ data.mloopcol = mloopcol;
+ data.mloopcol_wet = mloopcol_wet;
+ data.mloopcol_preview = mloopcol_preview;
+
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (totpoly > 1000);
+ BLI_task_parallel_range(
+ 0, totpoly, &data, dynamic_paint_apply_surface_vpaint_cb, &settings);
+ }
+
+ MEM_freeN(fcolor);
+
+ /* Mark tessellated CD layers as dirty. */
+ //result->dirty |= DM_DIRTY_TESS_CDLAYERS;
+ }
+ /* vertex group paint */
+ else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
+ int defgrp_index = defgroup_name_index(ob, surface->output_name);
+ MDeformVert *dvert = CustomData_get_layer(&result->vdata, CD_MDEFORMVERT);
+ float *weight = (float *)sData->type_data;
+
+ /* viewport preview */
+ if (surface->flags & MOD_DPAINT_PREVIEW) {
+ /* Save preview results to weight layer to be
+ * able to share same drawing methods.
+ * Note this func also sets DM_DIRTY_TESS_CDLAYERS flag! */
+ //TODO port this function
+ //DM_update_weight_mcol(ob, result, 0, weight, 0, NULL);
+ }
+
+ /* apply weights into a vertex group, if doesn't exists add a new layer */
+ if (defgrp_index != -1 && !dvert && (surface->output_name[0] != '\0')) {
+ dvert = CustomData_add_layer(
+ &result->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, sData->total_points);
+ }
+ if (defgrp_index != -1 && dvert) {
+ int i;
+ for (i = 0; i < sData->total_points; i++) {
+ MDeformVert *dv = &dvert[i];
+ MDeformWeight *def_weight = defvert_find_index(dv, defgrp_index);
+
+ /* skip if weight value is 0 and no existing weight is found */
+ if ((def_weight != NULL) || (weight[i] != 0.0f)) {
+ /* if not found, add a weight for it */
+ if (def_weight == NULL) {
+ def_weight = defvert_verify_index(dv, defgrp_index);
+ }
+
+ /* set weight value */
+ def_weight->weight = weight[i];
+ }
+ }
+ }
+ }
+ /* wave simulation */
+ else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
+ MVert *mvert = result->mvert;
+
+ DynamicPaintModifierApplyData data = {
+ .surface = surface,
+ .mvert = mvert,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_apply_surface_wave_cb, &settings);
+ update_normals = true;
+ }
+
+ /* displace */
+ if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
+ dynamicPaint_applySurfaceDisplace(surface, result);
+ update_normals = true;
+ }
+ }
+ }
+ }
+
+ if (update_normals) {
+ //result->dirty |= DM_DIRTY_NORMALS;
+ }
+ }
+ /* make a copy of mesh to use as brush data */
+ if (pmd->brush) {
+ DynamicPaintRuntime *runtime_data = dynamicPaint_Modifier_runtime_ensure(pmd);
+ if (runtime_data->brush_mesh != NULL) {
+ BKE_id_free(NULL, runtime_data->brush_mesh);
+ }
+ runtime_data->brush_mesh = BKE_mesh_copy_for_eval(result, false);
+ }
+
+ return result;
}
/* update cache frame range */
void dynamicPaint_cacheUpdateFrames(DynamicPaintSurface *surface)
{
- if (surface->pointcache) {
- surface->pointcache->startframe = surface->start_frame;
- surface->pointcache->endframe = surface->end_frame;
- }
+ if (surface->pointcache) {
+ surface->pointcache->startframe = surface->start_frame;
+ surface->pointcache->endframe = surface->end_frame;
+ }
}
static void canvas_copyMesh(DynamicPaintCanvasSettings *canvas, Mesh *mesh)
{
- DynamicPaintRuntime *runtime = dynamicPaint_Modifier_runtime_ensure(canvas->pmd);
- if (runtime->canvas_mesh != NULL) {
- BKE_id_free(NULL, runtime->canvas_mesh);
- }
+ DynamicPaintRuntime *runtime = dynamicPaint_Modifier_runtime_ensure(canvas->pmd);
+ if (runtime->canvas_mesh != NULL) {
+ BKE_id_free(NULL, runtime->canvas_mesh);
+ }
- runtime->canvas_mesh = BKE_mesh_copy_for_eval(mesh, false);
+ runtime->canvas_mesh = BKE_mesh_copy_for_eval(mesh, false);
}
/*
* Updates derived mesh copy and processes dynamic paint step / caches.
*/
-static void dynamicPaint_frameUpdate(
- DynamicPaintModifierData *pmd, struct Depsgraph *depsgraph, Scene *scene,
- Object *ob, Mesh *mesh)
+static void dynamicPaint_frameUpdate(DynamicPaintModifierData *pmd,
+ struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ Mesh *mesh)
{
- if (pmd->canvas) {
- DynamicPaintCanvasSettings *canvas = pmd->canvas;
- DynamicPaintSurface *surface = canvas->surfaces.first;
-
- /* update derived mesh copy */
- canvas_copyMesh(canvas, mesh);
-
- /* in case image sequence baking, stop here */
- if (canvas->flags & MOD_DPAINT_BAKING)
- return;
-
- /* loop through surfaces */
- for (; surface; surface = surface->next) {
- int current_frame = (int)scene->r.cfra;
- bool no_surface_data;
-
- /* free bake data if not required anymore */
- surface_freeUnusedData(surface);
-
- /* image sequences are handled by bake operator */
- if ((surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) || !(surface->flags & MOD_DPAINT_ACTIVE))
- continue;
-
- /* make sure surface is valid */
- no_surface_data = surface->data == NULL;
- if (!dynamicPaint_checkSurfaceData(scene, surface))
- continue;
-
- /* limit frame range */
- CLAMP(current_frame, surface->start_frame, surface->end_frame);
-
- if (no_surface_data || current_frame != surface->current_frame ||
- (int)scene->r.cfra == surface->start_frame)
- {
- PointCache *cache = surface->pointcache;
- PTCacheID pid;
- surface->current_frame = current_frame;
-
- /* read point cache */
- BKE_ptcache_id_from_dynamicpaint(&pid, ob, surface);
- pid.cache->startframe = surface->start_frame;
- pid.cache->endframe = surface->end_frame;
- BKE_ptcache_id_time(&pid, scene, (float)scene->r.cfra, NULL, NULL, NULL);
-
- /* reset non-baked cache at first frame */
- if ((int)scene->r.cfra == surface->start_frame && !(cache->flag & PTCACHE_BAKED)) {
- cache->flag |= PTCACHE_REDO_NEEDED;
- BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
- cache->flag &= ~PTCACHE_REDO_NEEDED;
- }
-
- /* try to read from cache */
- bool can_simulate = ((int)scene->r.cfra == current_frame) && !(cache->flag & PTCACHE_BAKED);
-
- if (BKE_ptcache_read(&pid, (float)scene->r.cfra, can_simulate)) {
- BKE_ptcache_validate(cache, (int)scene->r.cfra);
- }
- /* if read failed and we're on surface range do recalculate */
- else if (can_simulate) {
- /* calculate surface frame */
- canvas->flags |= MOD_DPAINT_BAKING;
- dynamicPaint_calculateFrame(surface, depsgraph, scene, ob, current_frame);
- canvas->flags &= ~MOD_DPAINT_BAKING;
-
- /* restore canvas mesh if required */
- if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE &&
- surface->flags & MOD_DPAINT_DISP_INCREMENTAL && surface->next)
- {
- canvas_copyMesh(canvas, mesh);
- }
-
- BKE_ptcache_validate(cache, surface->current_frame);
- BKE_ptcache_write(&pid, surface->current_frame);
- }
- }
- }
- }
+ if (pmd->canvas) {
+ DynamicPaintCanvasSettings *canvas = pmd->canvas;
+ DynamicPaintSurface *surface = canvas->surfaces.first;
+
+ /* update derived mesh copy */
+ canvas_copyMesh(canvas, mesh);
+
+ /* in case image sequence baking, stop here */
+ if (canvas->flags & MOD_DPAINT_BAKING)
+ return;
+
+ /* loop through surfaces */
+ for (; surface; surface = surface->next) {
+ int current_frame = (int)scene->r.cfra;
+ bool no_surface_data;
+
+ /* free bake data if not required anymore */
+ surface_freeUnusedData(surface);
+
+ /* image sequences are handled by bake operator */
+ if ((surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) ||
+ !(surface->flags & MOD_DPAINT_ACTIVE))
+ continue;
+
+ /* make sure surface is valid */
+ no_surface_data = surface->data == NULL;
+ if (!dynamicPaint_checkSurfaceData(scene, surface))
+ continue;
+
+ /* limit frame range */
+ CLAMP(current_frame, surface->start_frame, surface->end_frame);
+
+ if (no_surface_data || current_frame != surface->current_frame ||
+ (int)scene->r.cfra == surface->start_frame) {
+ PointCache *cache = surface->pointcache;
+ PTCacheID pid;
+ surface->current_frame = current_frame;
+
+ /* read point cache */
+ BKE_ptcache_id_from_dynamicpaint(&pid, ob, surface);
+ pid.cache->startframe = surface->start_frame;
+ pid.cache->endframe = surface->end_frame;
+ BKE_ptcache_id_time(&pid, scene, (float)scene->r.cfra, NULL, NULL, NULL);
+
+ /* reset non-baked cache at first frame */
+ if ((int)scene->r.cfra == surface->start_frame && !(cache->flag & PTCACHE_BAKED)) {
+ cache->flag |= PTCACHE_REDO_NEEDED;
+ BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
+ cache->flag &= ~PTCACHE_REDO_NEEDED;
+ }
+
+ /* try to read from cache */
+ bool can_simulate = ((int)scene->r.cfra == current_frame) &&
+ !(cache->flag & PTCACHE_BAKED);
+
+ if (BKE_ptcache_read(&pid, (float)scene->r.cfra, can_simulate)) {
+ BKE_ptcache_validate(cache, (int)scene->r.cfra);
+ }
+ /* if read failed and we're on surface range do recalculate */
+ else if (can_simulate) {
+ /* calculate surface frame */
+ canvas->flags |= MOD_DPAINT_BAKING;
+ dynamicPaint_calculateFrame(surface, depsgraph, scene, ob, current_frame);
+ canvas->flags &= ~MOD_DPAINT_BAKING;
+
+ /* restore canvas mesh if required */
+ if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE &&
+ surface->flags & MOD_DPAINT_DISP_INCREMENTAL && surface->next) {
+ canvas_copyMesh(canvas, mesh);
+ }
+
+ BKE_ptcache_validate(cache, surface->current_frame);
+ BKE_ptcache_write(&pid, surface->current_frame);
+ }
+ }
+ }
+ }
}
/* Modifier call. Processes dynamic paint modifier step. */
-Mesh *dynamicPaint_Modifier_do(
- DynamicPaintModifierData *pmd, struct Depsgraph *depsgraph, Scene *scene,
- Object *ob, Mesh *mesh)
+Mesh *dynamicPaint_Modifier_do(DynamicPaintModifierData *pmd,
+ struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ Mesh *mesh)
{
- if (pmd->canvas) {
- Mesh *ret;
+ if (pmd->canvas) {
+ Mesh *ret;
- /* Update canvas data for a new frame */
- dynamicPaint_frameUpdate(pmd, depsgraph, scene, ob, mesh);
+ /* Update canvas data for a new frame */
+ dynamicPaint_frameUpdate(pmd, depsgraph, scene, ob, mesh);
- /* Return output mesh */
- ret = dynamicPaint_Modifier_apply(pmd, ob, mesh);
+ /* Return output mesh */
+ ret = dynamicPaint_Modifier_apply(pmd, ob, mesh);
- return ret;
- }
- else {
- /* Update canvas data for a new frame */
- dynamicPaint_frameUpdate(pmd, depsgraph, scene, ob, mesh);
+ return ret;
+ }
+ else {
+ /* Update canvas data for a new frame */
+ dynamicPaint_frameUpdate(pmd, depsgraph, scene, ob, mesh);
- /* Return output mesh */
- return dynamicPaint_Modifier_apply(pmd, ob, mesh);
- }
+ /* Return output mesh */
+ return dynamicPaint_Modifier_apply(pmd, ob, mesh);
+ }
}
-
/***************************** Image Sequence / UV Image Surface Calls ******************************/
/*
* Create a surface for uv image sequence format
*/
-#define JITTER_SAMPLES { \
- 0.0f, 0.0f, \
- -0.2f, -0.4f, \
- 0.2f, 0.4f, \
- 0.4f, -0.2f, \
- -0.4f, 0.3f, \
-}
+#define JITTER_SAMPLES \
+ { \
+ 0.0f, 0.0f, -0.2f, -0.4f, 0.2f, 0.4f, 0.4f, -0.2f, -0.4f, 0.3f, \
+ }
typedef struct DynamicPaintCreateUVSurfaceData {
- const DynamicPaintSurface *surface;
+ const DynamicPaintSurface *surface;
- PaintUVPoint *tempPoints;
- Vec3f *tempWeights;
+ PaintUVPoint *tempPoints;
+ Vec3f *tempWeights;
- const MLoopTri *mlooptri;
- const MLoopUV *mloopuv;
- const MLoop *mloop;
- const int tottri;
+ const MLoopTri *mlooptri;
+ const MLoopUV *mloopuv;
+ const MLoop *mloop;
+ const int tottri;
- const Bounds2D *faceBB;
- uint32_t *active_points;
+ const Bounds2D *faceBB;
+ uint32_t *active_points;
} DynamicPaintCreateUVSurfaceData;
static void dynamic_paint_create_uv_surface_direct_cb(
- void *__restrict userdata,
- const int ty,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+ void *__restrict userdata, const int ty, const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintCreateUVSurfaceData *data = userdata;
-
- const DynamicPaintSurface *surface = data->surface;
- PaintUVPoint *tempPoints = data->tempPoints;
- Vec3f *tempWeights = data->tempWeights;
-
- const MLoopTri *mlooptri = data->mlooptri;
- const MLoopUV *mloopuv = data->mloopuv;
- const MLoop *mloop = data->mloop;
- const int tottri = data->tottri;
-
- const Bounds2D *faceBB = data->faceBB;
-
- const float jitter5sample[10] = JITTER_SAMPLES;
- const int aa_samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
- const int w = surface->image_resolution;
- const int h = w;
-
- for (int tx = 0; tx < w; tx++) {
- const int index = tx + w * ty;
- PaintUVPoint *tPoint = &tempPoints[index];
- float point[5][2];
-
- /* Init per pixel settings */
- tPoint->tri_index = -1;
- tPoint->neighbour_pixel = -1;
- tPoint->pixel_index = index;
-
- /* Actual pixel center, used when collision is found */
- point[0][0] = ((float)tx + 0.5f) / w;
- point[0][1] = ((float)ty + 0.5f) / h;
-
- /*
- * A pixel middle sample isn't enough to find very narrow polygons
- * So using 4 samples of each corner too
- */
- point[1][0] = ((float)tx) / w;
- point[1][1] = ((float)ty) / h;
-
- point[2][0] = ((float)tx + 1) / w;
- point[2][1] = ((float)ty) / h;
-
- point[3][0] = ((float)tx) / w;
- point[3][1] = ((float)ty + 1) / h;
-
- point[4][0] = ((float)tx + 1) / w;
- point[4][1] = ((float)ty + 1) / h;
-
-
- /* Loop through samples, starting from middle point */
- for (int sample = 0; sample < 5; sample++) {
- /* Loop through every face in the mesh */
- /* XXX TODO This is *horrible* with big meshes, should use a 2D BVHTree over UV tris here! */
- for (int i = 0; i < tottri; i++) {
- /* Check uv bb */
- if ((faceBB[i].min[0] > point[sample][0]) ||
- (faceBB[i].min[1] > point[sample][1]) ||
- (faceBB[i].max[0] < point[sample][0]) ||
- (faceBB[i].max[1] < point[sample][1]))
- {
- continue;
- }
-
- const float *uv1 = mloopuv[mlooptri[i].tri[0]].uv;
- const float *uv2 = mloopuv[mlooptri[i].tri[1]].uv;
- const float *uv3 = mloopuv[mlooptri[i].tri[2]].uv;
-
- /* If point is inside the face */
- if (isect_point_tri_v2(point[sample], uv1, uv2, uv3) != 0) {
- float uv[2];
-
- /* Add b-weights per anti-aliasing sample */
- for (int j = 0; j < aa_samples; j++) {
- uv[0] = point[0][0] + jitter5sample[j * 2] / w;
- uv[1] = point[0][1] + jitter5sample[j * 2 + 1] / h;
-
- barycentric_weights_v2(uv1, uv2, uv3, uv, tempWeights[index * aa_samples + j].v);
- }
-
- /* Set surface point face values */
- tPoint->tri_index = i;
-
- /* save vertex indexes */
- tPoint->v1 = mloop[mlooptri[i].tri[0]].v;
- tPoint->v2 = mloop[mlooptri[i].tri[1]].v;
- tPoint->v3 = mloop[mlooptri[i].tri[2]].v;
-
- sample = 5; /* make sure we exit sample loop as well */
- break;
- }
- }
- }
- }
+ const DynamicPaintCreateUVSurfaceData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ PaintUVPoint *tempPoints = data->tempPoints;
+ Vec3f *tempWeights = data->tempWeights;
+
+ const MLoopTri *mlooptri = data->mlooptri;
+ const MLoopUV *mloopuv = data->mloopuv;
+ const MLoop *mloop = data->mloop;
+ const int tottri = data->tottri;
+
+ const Bounds2D *faceBB = data->faceBB;
+
+ const float jitter5sample[10] = JITTER_SAMPLES;
+ const int aa_samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
+ const int w = surface->image_resolution;
+ const int h = w;
+
+ for (int tx = 0; tx < w; tx++) {
+ const int index = tx + w * ty;
+ PaintUVPoint *tPoint = &tempPoints[index];
+ float point[5][2];
+
+ /* Init per pixel settings */
+ tPoint->tri_index = -1;
+ tPoint->neighbour_pixel = -1;
+ tPoint->pixel_index = index;
+
+ /* Actual pixel center, used when collision is found */
+ point[0][0] = ((float)tx + 0.5f) / w;
+ point[0][1] = ((float)ty + 0.5f) / h;
+
+ /*
+ * A pixel middle sample isn't enough to find very narrow polygons
+ * So using 4 samples of each corner too
+ */
+ point[1][0] = ((float)tx) / w;
+ point[1][1] = ((float)ty) / h;
+
+ point[2][0] = ((float)tx + 1) / w;
+ point[2][1] = ((float)ty) / h;
+
+ point[3][0] = ((float)tx) / w;
+ point[3][1] = ((float)ty + 1) / h;
+
+ point[4][0] = ((float)tx + 1) / w;
+ point[4][1] = ((float)ty + 1) / h;
+
+ /* Loop through samples, starting from middle point */
+ for (int sample = 0; sample < 5; sample++) {
+ /* Loop through every face in the mesh */
+ /* XXX TODO This is *horrible* with big meshes, should use a 2D BVHTree over UV tris here! */
+ for (int i = 0; i < tottri; i++) {
+ /* Check uv bb */
+ if ((faceBB[i].min[0] > point[sample][0]) || (faceBB[i].min[1] > point[sample][1]) ||
+ (faceBB[i].max[0] < point[sample][0]) || (faceBB[i].max[1] < point[sample][1])) {
+ continue;
+ }
+
+ const float *uv1 = mloopuv[mlooptri[i].tri[0]].uv;
+ const float *uv2 = mloopuv[mlooptri[i].tri[1]].uv;
+ const float *uv3 = mloopuv[mlooptri[i].tri[2]].uv;
+
+ /* If point is inside the face */
+ if (isect_point_tri_v2(point[sample], uv1, uv2, uv3) != 0) {
+ float uv[2];
+
+ /* Add b-weights per anti-aliasing sample */
+ for (int j = 0; j < aa_samples; j++) {
+ uv[0] = point[0][0] + jitter5sample[j * 2] / w;
+ uv[1] = point[0][1] + jitter5sample[j * 2 + 1] / h;
+
+ barycentric_weights_v2(uv1, uv2, uv3, uv, tempWeights[index * aa_samples + j].v);
+ }
+
+ /* Set surface point face values */
+ tPoint->tri_index = i;
+
+ /* save vertex indexes */
+ tPoint->v1 = mloop[mlooptri[i].tri[0]].v;
+ tPoint->v2 = mloop[mlooptri[i].tri[1]].v;
+ tPoint->v3 = mloop[mlooptri[i].tri[2]].v;
+
+ sample = 5; /* make sure we exit sample loop as well */
+ break;
+ }
+ }
+ }
+ }
}
static void dynamic_paint_create_uv_surface_neighbor_cb(
- void *__restrict userdata,
- const int ty,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+ void *__restrict userdata, const int ty, const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintCreateUVSurfaceData *data = userdata;
-
- const DynamicPaintSurface *surface = data->surface;
- PaintUVPoint *tempPoints = data->tempPoints;
- Vec3f *tempWeights = data->tempWeights;
-
- const MLoopTri *mlooptri = data->mlooptri;
- const MLoopUV *mloopuv = data->mloopuv;
- const MLoop *mloop = data->mloop;
-
- uint32_t *active_points = data->active_points;
-
- const float jitter5sample[10] = JITTER_SAMPLES;
- const int aa_samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
- const int w = surface->image_resolution;
- const int h = w;
-
- for (int tx = 0; tx < w; tx++) {
- const int index = tx + w * ty;
- PaintUVPoint *tPoint = &tempPoints[index];
-
- /* If point isn't on canvas mesh */
- if (tPoint->tri_index == -1) {
- float point[2];
-
- /* get loop area */
- const int u_min = (tx > 0) ? -1 : 0;
- const int u_max = (tx < (w - 1)) ? 1 : 0;
- const int v_min = (ty > 0) ? -1 : 0;
- const int v_max = (ty < (h - 1)) ? 1 : 0;
-
- point[0] = ((float)tx + 0.5f) / w;
- point[1] = ((float)ty + 0.5f) / h;
-
- /* search through defined area for neighbor, checking grid directions first */
- for (int ni = 0; ni < 8; ni++) {
- int u = neighStraightX[ni];
- int v = neighStraightY[ni];
-
- if (u >= u_min && u <= u_max && v >= v_min && v <= v_max) {
- /* if not this pixel itself */
- if (u != 0 || v != 0) {
- const int ind = (tx + u) + w * (ty + v);
-
- /* if neighbor has index */
- if (tempPoints[ind].neighbour_pixel == -1 && tempPoints[ind].tri_index != -1) {
- float uv[2];
- const int i = tempPoints[ind].tri_index;
- const float *uv1 = mloopuv[mlooptri[i].tri[0]].uv;
- const float *uv2 = mloopuv[mlooptri[i].tri[1]].uv;
- const float *uv3 = mloopuv[mlooptri[i].tri[2]].uv;
-
- /* tri index */
- /* There is a low possibility of actually having a neighbor point which tri is
- * already set from another neighbor in a separate thread here.
- * Checking for both tri_index and neighbour_pixel above reduces that probability
- * but it remains possible.
- * That atomic op (and its memory fence) ensures tPoint->neighbour_pixel is set
- * to non--1 *before* its tri_index is set (i.e. that it cannot be used a neighbour).
- */
- tPoint->neighbour_pixel = ind - 1;
- atomic_add_and_fetch_uint32(&tPoint->neighbour_pixel, 1);
- tPoint->tri_index = i;
-
- /* Now calculate pixel data for this pixel as it was on polygon surface */
- /* Add b-weights per anti-aliasing sample */
- for (int j = 0; j < aa_samples; j++) {
- uv[0] = point[0] + jitter5sample[j * 2] / w;
- uv[1] = point[1] + jitter5sample[j * 2 + 1] / h;
- barycentric_weights_v2(uv1, uv2, uv3, uv, tempWeights[index * aa_samples + j].v);
- }
-
- /* save vertex indexes */
- tPoint->v1 = mloop[mlooptri[i].tri[0]].v;
- tPoint->v2 = mloop[mlooptri[i].tri[1]].v;
- tPoint->v3 = mloop[mlooptri[i].tri[2]].v;
-
- break;
- }
- }
- }
- }
- }
-
- /* Increase the final number of active surface points if relevant. */
- if (tPoint->tri_index != -1)
- atomic_add_and_fetch_uint32(active_points, 1);
- }
+ const DynamicPaintCreateUVSurfaceData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ PaintUVPoint *tempPoints = data->tempPoints;
+ Vec3f *tempWeights = data->tempWeights;
+
+ const MLoopTri *mlooptri = data->mlooptri;
+ const MLoopUV *mloopuv = data->mloopuv;
+ const MLoop *mloop = data->mloop;
+
+ uint32_t *active_points = data->active_points;
+
+ const float jitter5sample[10] = JITTER_SAMPLES;
+ const int aa_samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
+ const int w = surface->image_resolution;
+ const int h = w;
+
+ for (int tx = 0; tx < w; tx++) {
+ const int index = tx + w * ty;
+ PaintUVPoint *tPoint = &tempPoints[index];
+
+ /* If point isn't on canvas mesh */
+ if (tPoint->tri_index == -1) {
+ float point[2];
+
+ /* get loop area */
+ const int u_min = (tx > 0) ? -1 : 0;
+ const int u_max = (tx < (w - 1)) ? 1 : 0;
+ const int v_min = (ty > 0) ? -1 : 0;
+ const int v_max = (ty < (h - 1)) ? 1 : 0;
+
+ point[0] = ((float)tx + 0.5f) / w;
+ point[1] = ((float)ty + 0.5f) / h;
+
+ /* search through defined area for neighbor, checking grid directions first */
+ for (int ni = 0; ni < 8; ni++) {
+ int u = neighStraightX[ni];
+ int v = neighStraightY[ni];
+
+ if (u >= u_min && u <= u_max && v >= v_min && v <= v_max) {
+ /* if not this pixel itself */
+ if (u != 0 || v != 0) {
+ const int ind = (tx + u) + w * (ty + v);
+
+ /* if neighbor has index */
+ if (tempPoints[ind].neighbour_pixel == -1 && tempPoints[ind].tri_index != -1) {
+ float uv[2];
+ const int i = tempPoints[ind].tri_index;
+ const float *uv1 = mloopuv[mlooptri[i].tri[0]].uv;
+ const float *uv2 = mloopuv[mlooptri[i].tri[1]].uv;
+ const float *uv3 = mloopuv[mlooptri[i].tri[2]].uv;
+
+ /* tri index */
+ /* There is a low possibility of actually having a neighbor point which tri is
+ * already set from another neighbor in a separate thread here.
+ * Checking for both tri_index and neighbour_pixel above reduces that probability
+ * but it remains possible.
+ * That atomic op (and its memory fence) ensures tPoint->neighbour_pixel is set
+ * to non--1 *before* its tri_index is set (i.e. that it cannot be used a neighbour).
+ */
+ tPoint->neighbour_pixel = ind - 1;
+ atomic_add_and_fetch_uint32(&tPoint->neighbour_pixel, 1);
+ tPoint->tri_index = i;
+
+ /* Now calculate pixel data for this pixel as it was on polygon surface */
+ /* Add b-weights per anti-aliasing sample */
+ for (int j = 0; j < aa_samples; j++) {
+ uv[0] = point[0] + jitter5sample[j * 2] / w;
+ uv[1] = point[1] + jitter5sample[j * 2 + 1] / h;
+ barycentric_weights_v2(uv1, uv2, uv3, uv, tempWeights[index * aa_samples + j].v);
+ }
+
+ /* save vertex indexes */
+ tPoint->v1 = mloop[mlooptri[i].tri[0]].v;
+ tPoint->v2 = mloop[mlooptri[i].tri[1]].v;
+ tPoint->v3 = mloop[mlooptri[i].tri[2]].v;
+
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* Increase the final number of active surface points if relevant. */
+ if (tPoint->tri_index != -1)
+ atomic_add_and_fetch_uint32(active_points, 1);
+ }
}
#undef JITTER_SAMPLES
-static float dist_squared_to_looptri_uv_edges(const MLoopTri *mlooptri, const MLoopUV *mloopuv, int tri_index, const float point[2])
+static float dist_squared_to_looptri_uv_edges(const MLoopTri *mlooptri,
+ const MLoopUV *mloopuv,
+ int tri_index,
+ const float point[2])
{
- float min_distance = FLT_MAX;
+ float min_distance = FLT_MAX;
- for (int i = 0; i < 3; i++) {
- const float dist_squared = dist_squared_to_line_segment_v2(
- point,
- mloopuv[mlooptri[tri_index].tri[(i + 0)]].uv,
- mloopuv[mlooptri[tri_index].tri[(i + 1) % 3]].uv
- );
+ for (int i = 0; i < 3; i++) {
+ const float dist_squared = dist_squared_to_line_segment_v2(
+ point,
+ mloopuv[mlooptri[tri_index].tri[(i + 0)]].uv,
+ mloopuv[mlooptri[tri_index].tri[(i + 1) % 3]].uv);
- if (dist_squared < min_distance) {
- min_distance = dist_squared;
- }
- }
+ if (dist_squared < min_distance) {
+ min_distance = dist_squared;
+ }
+ }
- return min_distance;
+ return min_distance;
}
typedef struct DynamicPaintFindIslandBorderData {
- const MeshElemMap *vert_to_looptri_map;
- int w, h, px, py;
+ const MeshElemMap *vert_to_looptri_map;
+ int w, h, px, py;
- int best_index;
- float best_weight;
+ int best_index;
+ float best_weight;
} DynamicPaintFindIslandBorderData;
-static void dynamic_paint_find_island_border(
- const DynamicPaintCreateUVSurfaceData *data, DynamicPaintFindIslandBorderData *bdata,
- int tri_index, const float pixel[2], int in_edge, int depth);
+static void dynamic_paint_find_island_border(const DynamicPaintCreateUVSurfaceData *data,
+ DynamicPaintFindIslandBorderData *bdata,
+ int tri_index,
+ const float pixel[2],
+ int in_edge,
+ int depth);
/* Tries to find the neighboring pixel in given (uv space) direction.
* Result is used by effect system to move paint on the surface.
@@ -2468,936 +2475,956 @@ static void dynamic_paint_find_island_border(
* px, py : origin pixel x and y
* n_index : lookup direction index (use neighX, neighY to get final index)
*/
-static int dynamic_paint_find_neighbour_pixel(
- const DynamicPaintCreateUVSurfaceData *data, const MeshElemMap *vert_to_looptri_map,
- const int w, const int h, const int px, const int py, const int n_index)
+static int dynamic_paint_find_neighbour_pixel(const DynamicPaintCreateUVSurfaceData *data,
+ const MeshElemMap *vert_to_looptri_map,
+ const int w,
+ const int h,
+ const int px,
+ const int py,
+ const int n_index)
{
- /* Note: Current method only uses polygon edges to detect neighboring pixels.
- * -> It doesn't always lead to the optimum pixel but is accurate enough
- * and faster/simpler than including possible face tip point links)
- */
-
- /* shift position by given n_index */
- const int x = px + neighX[n_index];
- const int y = py + neighY[n_index];
-
- if (x < 0 || x >= w || y < 0 || y >= h)
- return OUT_OF_TEXTURE;
-
- const PaintUVPoint *tempPoints = data->tempPoints;
- const PaintUVPoint *tPoint = &tempPoints[x + w * y]; /* UV neighbor */
- const PaintUVPoint *cPoint = &tempPoints[px + w * py]; /* Origin point */
-
- /* Check if shifted point is on same face -> it's a correct neighbor (and if it isn't marked as an "edge pixel") */
- if ((tPoint->tri_index == cPoint->tri_index) && (tPoint->neighbour_pixel == -1))
- return (x + w * y);
-
- /* Even if shifted point is on another face
- * -> use this point.
- *
- * !! Replace with "is uv faces linked" check !!
- * This should work fine as long as uv island margin is > 1 pixel.
- */
- if ((tPoint->tri_index != -1) && (tPoint->neighbour_pixel == -1)) {
- return (x + w * y);
- }
-
- /* If we get here, the actual neighboring pixel is located on a non-linked uv face,
- * and we have to find its "real" position.
- *
- * Simple neighboring face finding algorithm:
- * - find closest uv edge to shifted pixel and get the another face that shares that edge
- * - find corresponding position of that new face edge in uv space
- *
- * TODO: Implement something more accurate / optimized?
- */
- {
- DynamicPaintFindIslandBorderData bdata = {
- .vert_to_looptri_map = vert_to_looptri_map,
- .w = w, .h = h, .px = px, .py = py,
- .best_index = NOT_FOUND, .best_weight = 1.0f,
- };
-
- float pixel[2];
-
- pixel[0] = ((float)(px + neighX[n_index]) + 0.5f) / (float)w;
- pixel[1] = ((float)(py + neighY[n_index]) + 0.5f) / (float)h;
-
- /* Do a small recursive search for the best island edge. */
- dynamic_paint_find_island_border(data, &bdata, cPoint->tri_index, pixel, -1, 5);
-
- return bdata.best_index;
- }
+ /* Note: Current method only uses polygon edges to detect neighboring pixels.
+ * -> It doesn't always lead to the optimum pixel but is accurate enough
+ * and faster/simpler than including possible face tip point links)
+ */
+
+ /* shift position by given n_index */
+ const int x = px + neighX[n_index];
+ const int y = py + neighY[n_index];
+
+ if (x < 0 || x >= w || y < 0 || y >= h)
+ return OUT_OF_TEXTURE;
+
+ const PaintUVPoint *tempPoints = data->tempPoints;
+ const PaintUVPoint *tPoint = &tempPoints[x + w * y]; /* UV neighbor */
+ const PaintUVPoint *cPoint = &tempPoints[px + w * py]; /* Origin point */
+
+ /* Check if shifted point is on same face -> it's a correct neighbor (and if it isn't marked as an "edge pixel") */
+ if ((tPoint->tri_index == cPoint->tri_index) && (tPoint->neighbour_pixel == -1))
+ return (x + w * y);
+
+ /* Even if shifted point is on another face
+ * -> use this point.
+ *
+ * !! Replace with "is uv faces linked" check !!
+ * This should work fine as long as uv island margin is > 1 pixel.
+ */
+ if ((tPoint->tri_index != -1) && (tPoint->neighbour_pixel == -1)) {
+ return (x + w * y);
+ }
+
+ /* If we get here, the actual neighboring pixel is located on a non-linked uv face,
+ * and we have to find its "real" position.
+ *
+ * Simple neighboring face finding algorithm:
+ * - find closest uv edge to shifted pixel and get the another face that shares that edge
+ * - find corresponding position of that new face edge in uv space
+ *
+ * TODO: Implement something more accurate / optimized?
+ */
+ {
+ DynamicPaintFindIslandBorderData bdata = {
+ .vert_to_looptri_map = vert_to_looptri_map,
+ .w = w,
+ .h = h,
+ .px = px,
+ .py = py,
+ .best_index = NOT_FOUND,
+ .best_weight = 1.0f,
+ };
+
+ float pixel[2];
+
+ pixel[0] = ((float)(px + neighX[n_index]) + 0.5f) / (float)w;
+ pixel[1] = ((float)(py + neighY[n_index]) + 0.5f) / (float)h;
+
+ /* Do a small recursive search for the best island edge. */
+ dynamic_paint_find_island_border(data, &bdata, cPoint->tri_index, pixel, -1, 5);
+
+ return bdata.best_index;
+ }
}
-static void dynamic_paint_find_island_border(
- const DynamicPaintCreateUVSurfaceData *data, DynamicPaintFindIslandBorderData *bdata,
- int tri_index, const float pixel[2], int in_edge, int depth)
+static void dynamic_paint_find_island_border(const DynamicPaintCreateUVSurfaceData *data,
+ DynamicPaintFindIslandBorderData *bdata,
+ int tri_index,
+ const float pixel[2],
+ int in_edge,
+ int depth)
{
- const MLoop *mloop = data->mloop;
- const MLoopTri *mlooptri = data->mlooptri;
- const MLoopUV *mloopuv = data->mloopuv;
-
- const unsigned int *loop_idx = mlooptri[tri_index].tri;
-
- /* Enumerate all edges of the triangle, rotating the vertex list accordingly. */
- for (int edge_idx = 0; edge_idx < 3; edge_idx++) {
- /* but not the edge we have just recursed through */
- if (edge_idx == in_edge)
- continue;
-
- float uv0[2], uv1[2], uv2[2];
-
- copy_v2_v2(uv0, mloopuv[loop_idx[(edge_idx + 0)]].uv);
- copy_v2_v2(uv1, mloopuv[loop_idx[(edge_idx + 1) % 3]].uv);
- copy_v2_v2(uv2, mloopuv[loop_idx[(edge_idx + 2) % 3]].uv);
+ const MLoop *mloop = data->mloop;
+ const MLoopTri *mlooptri = data->mlooptri;
+ const MLoopUV *mloopuv = data->mloopuv;
+
+ const unsigned int *loop_idx = mlooptri[tri_index].tri;
+
+ /* Enumerate all edges of the triangle, rotating the vertex list accordingly. */
+ for (int edge_idx = 0; edge_idx < 3; edge_idx++) {
+ /* but not the edge we have just recursed through */
+ if (edge_idx == in_edge)
+ continue;
+
+ float uv0[2], uv1[2], uv2[2];
+
+ copy_v2_v2(uv0, mloopuv[loop_idx[(edge_idx + 0)]].uv);
+ copy_v2_v2(uv1, mloopuv[loop_idx[(edge_idx + 1) % 3]].uv);
+ copy_v2_v2(uv2, mloopuv[loop_idx[(edge_idx + 2) % 3]].uv);
- /* Verify the target point is on the opposite side of the edge from the third triangle
- * vertex, to ensure that we always move closer to the goal point. */
- const float sidep = line_point_side_v2(uv0, uv1, pixel);
- const float side2 = line_point_side_v2(uv0, uv1, uv2);
+ /* Verify the target point is on the opposite side of the edge from the third triangle
+ * vertex, to ensure that we always move closer to the goal point. */
+ const float sidep = line_point_side_v2(uv0, uv1, pixel);
+ const float side2 = line_point_side_v2(uv0, uv1, uv2);
- if (side2 == 0.0f)
- continue;
+ if (side2 == 0.0f)
+ continue;
- /* Hack: allow all edges of the original triangle */
- const bool correct_side = (in_edge == -1) || (sidep < 0 && side2 > 0) || (sidep > 0 && side2 < 0);
+ /* Hack: allow all edges of the original triangle */
+ const bool correct_side = (in_edge == -1) || (sidep < 0 && side2 > 0) ||
+ (sidep > 0 && side2 < 0);
- /* Allow exactly on edge for the non-recursive case */
- if (!correct_side && sidep != 0.0f)
- continue;
+ /* Allow exactly on edge for the non-recursive case */
+ if (!correct_side && sidep != 0.0f)
+ continue;
- /* Now find another face that is linked to that edge. */
- const int vert0 = mloop[loop_idx[(edge_idx + 0)]].v;
- const int vert1 = mloop[loop_idx[(edge_idx + 1) % 3]].v;
+ /* Now find another face that is linked to that edge. */
+ const int vert0 = mloop[loop_idx[(edge_idx + 0)]].v;
+ const int vert1 = mloop[loop_idx[(edge_idx + 1) % 3]].v;
- /* Use a pre-computed vert-to-looptri mapping, speeds up things a lot compared to looping over all loopti. */
- const MeshElemMap *map = &bdata->vert_to_looptri_map[vert0];
+ /* Use a pre-computed vert-to-looptri mapping, speeds up things a lot compared to looping over all loopti. */
+ const MeshElemMap *map = &bdata->vert_to_looptri_map[vert0];
- bool found_other = false;
- int target_tri = -1;
- int target_edge = -1;
+ bool found_other = false;
+ int target_tri = -1;
+ int target_edge = -1;
- float ouv0[2], ouv1[2];
+ float ouv0[2], ouv1[2];
- for (int i = 0; i < map->count && !found_other; i++) {
- const int lt_index = map->indices[i];
+ for (int i = 0; i < map->count && !found_other; i++) {
+ const int lt_index = map->indices[i];
- if (lt_index == tri_index)
- continue;
-
- const unsigned int *other_loop_idx = mlooptri[lt_index].tri;
+ if (lt_index == tri_index)
+ continue;
+
+ const unsigned int *other_loop_idx = mlooptri[lt_index].tri;
- /* Check edges for match, looping in the same order as the outer loop. */
- for (int j = 0; j < 3; j++) {
- const int overt0 = mloop[other_loop_idx[(j + 0)]].v;
- const int overt1 = mloop[other_loop_idx[(j + 1) % 3]].v;
-
- /* Allow for swapped vertex order */
- if (overt0 == vert0 && overt1 == vert1) {
- found_other = true;
- copy_v2_v2(ouv0, mloopuv[other_loop_idx[(j + 0)]].uv);
- copy_v2_v2(ouv1, mloopuv[other_loop_idx[(j + 1) % 3]].uv);
- }
- else if (overt0 == vert1 && overt1 == vert0) {
- found_other = true;
- copy_v2_v2(ouv1, mloopuv[other_loop_idx[(j + 0)]].uv);
- copy_v2_v2(ouv0, mloopuv[other_loop_idx[(j + 1) % 3]].uv);
- }
-
- if (found_other) {
- target_tri = lt_index;
- target_edge = j;
- break;
- }
- }
- }
-
- if (!found_other) {
- if (bdata->best_index < 0)
- bdata->best_index = ON_MESH_EDGE;
-
- continue;
- }
-
- /* If this edge is connected in UV space too, recurse */
- if (equals_v2v2(uv0, ouv0) && equals_v2v2(uv1, ouv1)) {
- if (depth > 0 && correct_side) {
- dynamic_paint_find_island_border(data, bdata, target_tri, pixel, target_edge, depth - 1);
- }
-
- continue;
- }
-
- /* Otherwise try to map to the other side of the edge.
- * First check if there already is a better solution. */
- const float dist_squared = dist_squared_to_line_segment_v2(pixel, uv0, uv1);
-
- if (bdata->best_index >= 0 && dist_squared >= bdata->best_weight)
- continue;
+ /* Check edges for match, looping in the same order as the outer loop. */
+ for (int j = 0; j < 3; j++) {
+ const int overt0 = mloop[other_loop_idx[(j + 0)]].v;
+ const int overt1 = mloop[other_loop_idx[(j + 1) % 3]].v;
+
+ /* Allow for swapped vertex order */
+ if (overt0 == vert0 && overt1 == vert1) {
+ found_other = true;
+ copy_v2_v2(ouv0, mloopuv[other_loop_idx[(j + 0)]].uv);
+ copy_v2_v2(ouv1, mloopuv[other_loop_idx[(j + 1) % 3]].uv);
+ }
+ else if (overt0 == vert1 && overt1 == vert0) {
+ found_other = true;
+ copy_v2_v2(ouv1, mloopuv[other_loop_idx[(j + 0)]].uv);
+ copy_v2_v2(ouv0, mloopuv[other_loop_idx[(j + 1) % 3]].uv);
+ }
+
+ if (found_other) {
+ target_tri = lt_index;
+ target_edge = j;
+ break;
+ }
+ }
+ }
+
+ if (!found_other) {
+ if (bdata->best_index < 0)
+ bdata->best_index = ON_MESH_EDGE;
+
+ continue;
+ }
+
+ /* If this edge is connected in UV space too, recurse */
+ if (equals_v2v2(uv0, ouv0) && equals_v2v2(uv1, ouv1)) {
+ if (depth > 0 && correct_side) {
+ dynamic_paint_find_island_border(data, bdata, target_tri, pixel, target_edge, depth - 1);
+ }
+
+ continue;
+ }
+
+ /* Otherwise try to map to the other side of the edge.
+ * First check if there already is a better solution. */
+ const float dist_squared = dist_squared_to_line_segment_v2(pixel, uv0, uv1);
+
+ if (bdata->best_index >= 0 && dist_squared >= bdata->best_weight)
+ continue;
+
+ /*
+ * Find a point that is relatively at same edge position
+ * on this other face UV
+ */
+ float closest_point[2], dir_vec[2], tgt_pixel[2];
+
+ float lambda = closest_to_line_v2(closest_point, pixel, uv0, uv1);
+ CLAMP(lambda, 0.0f, 1.0f);
- /*
- * Find a point that is relatively at same edge position
- * on this other face UV
- */
- float closest_point[2], dir_vec[2], tgt_pixel[2];
-
- float lambda = closest_to_line_v2(closest_point, pixel, uv0, uv1);
- CLAMP(lambda, 0.0f, 1.0f);
-
- sub_v2_v2v2(dir_vec, ouv1, ouv0);
- madd_v2_v2v2fl(tgt_pixel, ouv0, dir_vec, lambda);
-
- int w = bdata->w, h = bdata->h, px = bdata->px, py = bdata->py;
-
- int final_pixel[2] = { (int)floorf(tgt_pixel[0] * w), (int)floorf(tgt_pixel[1] * h) };
-
- /* If current pixel uv is outside of texture */
- if (final_pixel[0] < 0 || final_pixel[0] >= w || final_pixel[1] < 0 || final_pixel[1] >= h) {
- if (bdata->best_index == NOT_FOUND)
- bdata->best_index = OUT_OF_TEXTURE;
-
- continue;
- }
-
- const PaintUVPoint *tempPoints = data->tempPoints;
- int final_index = final_pixel[0] + w * final_pixel[1];
-
- /* If we ended up to our origin point ( mesh has smaller than pixel sized faces) */
- if (final_index == (px + w * py))
- continue;
-
- /* If final point is an "edge pixel", use it's "real" neighbor instead */
- if (tempPoints[final_index].neighbour_pixel != -1) {
- final_index = tempPoints[final_index].neighbour_pixel;
-
- /* If we ended up to our origin point */
- if (final_index == (px + w * py))
- continue;
- }
-
- /* If found pixel still lies on wrong face ( mesh has smaller than pixel sized faces) */
- if (tempPoints[final_index].tri_index != target_tri) {
- /* Check if it's close enough to likely touch the intended triangle. Any triangle
- * becomes thinner than a pixel at its vertices, so robustness requires some margin. */
- const float final_pt[2] = { ((final_index % w) + 0.5f) / w, ((final_index / w) + 0.5f) / h };
- const float threshold = SQUARE(0.7f) / (w * h);
-
- if (dist_squared_to_looptri_uv_edges(mlooptri, mloopuv, tempPoints[final_index].tri_index, final_pt) > threshold)
- continue;
- }
-
- bdata->best_index = final_index;
- bdata->best_weight = dist_squared;
- }
+ sub_v2_v2v2(dir_vec, ouv1, ouv0);
+ madd_v2_v2v2fl(tgt_pixel, ouv0, dir_vec, lambda);
+
+ int w = bdata->w, h = bdata->h, px = bdata->px, py = bdata->py;
+
+ int final_pixel[2] = {(int)floorf(tgt_pixel[0] * w), (int)floorf(tgt_pixel[1] * h)};
+
+ /* If current pixel uv is outside of texture */
+ if (final_pixel[0] < 0 || final_pixel[0] >= w || final_pixel[1] < 0 || final_pixel[1] >= h) {
+ if (bdata->best_index == NOT_FOUND)
+ bdata->best_index = OUT_OF_TEXTURE;
+
+ continue;
+ }
+
+ const PaintUVPoint *tempPoints = data->tempPoints;
+ int final_index = final_pixel[0] + w * final_pixel[1];
+
+ /* If we ended up to our origin point ( mesh has smaller than pixel sized faces) */
+ if (final_index == (px + w * py))
+ continue;
+
+ /* If final point is an "edge pixel", use it's "real" neighbor instead */
+ if (tempPoints[final_index].neighbour_pixel != -1) {
+ final_index = tempPoints[final_index].neighbour_pixel;
+
+ /* If we ended up to our origin point */
+ if (final_index == (px + w * py))
+ continue;
+ }
+
+ /* If found pixel still lies on wrong face ( mesh has smaller than pixel sized faces) */
+ if (tempPoints[final_index].tri_index != target_tri) {
+ /* Check if it's close enough to likely touch the intended triangle. Any triangle
+ * becomes thinner than a pixel at its vertices, so robustness requires some margin. */
+ const float final_pt[2] = {((final_index % w) + 0.5f) / w, ((final_index / w) + 0.5f) / h};
+ const float threshold = SQUARE(0.7f) / (w * h);
+
+ if (dist_squared_to_looptri_uv_edges(
+ mlooptri, mloopuv, tempPoints[final_index].tri_index, final_pt) > threshold)
+ continue;
+ }
+
+ bdata->best_index = final_index;
+ bdata->best_weight = dist_squared;
+ }
}
static bool dynamicPaint_pointHasNeighbor(PaintAdjData *ed, int index, int neighbor)
{
- const int idx = ed->n_index[index];
+ const int idx = ed->n_index[index];
- for (int i = 0; i < ed->n_num[index]; i++) {
- if (ed->n_target[idx + i] == neighbor) {
- return true;
- }
- }
+ for (int i = 0; i < ed->n_num[index]; i++) {
+ if (ed->n_target[idx + i] == neighbor) {
+ return true;
+ }
+ }
- return false;
+ return false;
}
/* Makes the adjacency data symmetric, except for border pixels. I.e. if A is neighbor of B, B is neighbor of A. */
static bool dynamicPaint_symmetrizeAdjData(PaintAdjData *ed, int active_points)
{
- int *new_n_index = MEM_callocN(sizeof(int) * active_points, "Surface Adj Index");
- int *new_n_num = MEM_callocN(sizeof(int) * active_points, "Surface Adj Counts");
-
- if (new_n_num && new_n_index) {
- /* Count symmetrized neigbors */
- int total_targets = 0;
-
- for (int index = 0; index < active_points; index++) {
- total_targets += ed->n_num[index];
- new_n_num[index] = ed->n_num[index];
- }
-
- for (int index = 0; index < active_points; index++) {
- if (ed->flags[index] & ADJ_BORDER_PIXEL) {
- continue;
- }
-
- for (int i = 0, idx = ed->n_index[index]; i < ed->n_num[index]; i++) {
- const int target = ed->n_target[idx + i];
-
- assert(!(ed->flags[target] & ADJ_BORDER_PIXEL));
-
- if (!dynamicPaint_pointHasNeighbor(ed, target, index)) {
- new_n_num[target]++;
- total_targets++;
- }
- }
- }
-
- /* Allocate a new target map */
- int *new_n_target = MEM_callocN(sizeof(int) * total_targets, "Surface Adj Targets");
-
- if (new_n_target) {
- /* Copy existing neighbors to the new map */
- int n_pos = 0;
-
- for (int index = 0; index < active_points; index++) {
- new_n_index[index] = n_pos;
- memcpy(&new_n_target[n_pos], &ed->n_target[ed->n_index[index]], sizeof(int) * ed->n_num[index]);
-
- /* Reset count to old, but advance position by new, leaving a gap to fill below. */
- n_pos += new_n_num[index];
- new_n_num[index] = ed->n_num[index];
- }
-
- assert(n_pos == total_targets);
-
- /* Add symmetrized - this loop behavior must exactly match the count pass above */
- for (int index = 0; index < active_points; index++) {
- if (ed->flags[index] & ADJ_BORDER_PIXEL) {
- continue;
- }
-
- for (int i = 0, idx = ed->n_index[index]; i < ed->n_num[index]; i++) {
- const int target = ed->n_target[idx + i];
-
- if (!dynamicPaint_pointHasNeighbor(ed, target, index)) {
- const int num = new_n_num[target]++;
- new_n_target[new_n_index[target] + num] = index;
- }
- }
- }
-
- /* Swap maps */
- MEM_freeN(ed->n_target);
- ed->n_target = new_n_target;
-
- MEM_freeN(ed->n_index);
- ed->n_index = new_n_index;
-
- MEM_freeN(ed->n_num);
- ed->n_num = new_n_num;
-
- ed->total_targets = total_targets;
- return true;
- }
- }
-
- if (new_n_index)
- MEM_freeN(new_n_index);
- if (new_n_num)
- MEM_freeN(new_n_num);
-
- return false;
+ int *new_n_index = MEM_callocN(sizeof(int) * active_points, "Surface Adj Index");
+ int *new_n_num = MEM_callocN(sizeof(int) * active_points, "Surface Adj Counts");
+
+ if (new_n_num && new_n_index) {
+ /* Count symmetrized neigbors */
+ int total_targets = 0;
+
+ for (int index = 0; index < active_points; index++) {
+ total_targets += ed->n_num[index];
+ new_n_num[index] = ed->n_num[index];
+ }
+
+ for (int index = 0; index < active_points; index++) {
+ if (ed->flags[index] & ADJ_BORDER_PIXEL) {
+ continue;
+ }
+
+ for (int i = 0, idx = ed->n_index[index]; i < ed->n_num[index]; i++) {
+ const int target = ed->n_target[idx + i];
+
+ assert(!(ed->flags[target] & ADJ_BORDER_PIXEL));
+
+ if (!dynamicPaint_pointHasNeighbor(ed, target, index)) {
+ new_n_num[target]++;
+ total_targets++;
+ }
+ }
+ }
+
+ /* Allocate a new target map */
+ int *new_n_target = MEM_callocN(sizeof(int) * total_targets, "Surface Adj Targets");
+
+ if (new_n_target) {
+ /* Copy existing neighbors to the new map */
+ int n_pos = 0;
+
+ for (int index = 0; index < active_points; index++) {
+ new_n_index[index] = n_pos;
+ memcpy(&new_n_target[n_pos],
+ &ed->n_target[ed->n_index[index]],
+ sizeof(int) * ed->n_num[index]);
+
+ /* Reset count to old, but advance position by new, leaving a gap to fill below. */
+ n_pos += new_n_num[index];
+ new_n_num[index] = ed->n_num[index];
+ }
+
+ assert(n_pos == total_targets);
+
+ /* Add symmetrized - this loop behavior must exactly match the count pass above */
+ for (int index = 0; index < active_points; index++) {
+ if (ed->flags[index] & ADJ_BORDER_PIXEL) {
+ continue;
+ }
+
+ for (int i = 0, idx = ed->n_index[index]; i < ed->n_num[index]; i++) {
+ const int target = ed->n_target[idx + i];
+
+ if (!dynamicPaint_pointHasNeighbor(ed, target, index)) {
+ const int num = new_n_num[target]++;
+ new_n_target[new_n_index[target] + num] = index;
+ }
+ }
+ }
+
+ /* Swap maps */
+ MEM_freeN(ed->n_target);
+ ed->n_target = new_n_target;
+
+ MEM_freeN(ed->n_index);
+ ed->n_index = new_n_index;
+
+ MEM_freeN(ed->n_num);
+ ed->n_num = new_n_num;
+
+ ed->total_targets = total_targets;
+ return true;
+ }
+ }
+
+ if (new_n_index)
+ MEM_freeN(new_n_index);
+ if (new_n_num)
+ MEM_freeN(new_n_num);
+
+ return false;
}
-int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, float *progress, short *do_update)
+int dynamicPaint_createUVSurface(Scene *scene,
+ DynamicPaintSurface *surface,
+ float *progress,
+ short *do_update)
{
- /* Antialias jitter point relative coords */
- const int aa_samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
- char uvname[MAX_CUSTOMDATA_LAYER_NAME];
- uint32_t active_points = 0;
- bool error = false;
-
- PaintSurfaceData *sData;
- DynamicPaintCanvasSettings *canvas = surface->canvas;
- Mesh *mesh = dynamicPaint_canvas_mesh_get(canvas);
-
- PaintUVPoint *tempPoints = NULL;
- Vec3f *tempWeights = NULL;
- const MLoopTri *mlooptri = NULL;
- const MLoopUV *mloopuv = NULL;
- const MLoop *mloop = NULL;
-
- Bounds2D *faceBB = NULL;
- int *final_index;
-
- *progress = 0.0f;
- *do_update = true;
-
- if (!mesh)
- return setError(canvas, N_("Canvas mesh not updated"));
- if (surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ)
- return setError(canvas, N_("Cannot bake non-'image sequence' formats"));
-
- mloop = mesh->mloop;
- mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
- const int tottri = BKE_mesh_runtime_looptri_len(mesh);
-
- /* get uv map */
- if (CustomData_has_layer(&mesh->ldata, CD_MLOOPUV)) {
- CustomData_validate_layer_name(&mesh->ldata, CD_MLOOPUV, surface->uvlayer_name, uvname);
- mloopuv = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvname);
- }
-
- /* Check for validity */
- if (!mloopuv)
- return setError(canvas, N_("No UV data on canvas"));
- if (surface->image_resolution < 16 || surface->image_resolution > 8192)
- return setError(canvas, N_("Invalid resolution"));
-
- const int w = surface->image_resolution;
- const int h = w;
-
- /*
- * Start generating the surface
- */
- CLOG_INFO(&LOG, 1, "Preparing UV surface of %ix%i pixels and %i tris.", w, h, tottri);
-
- /* Init data struct */
- if (surface->data)
- dynamicPaint_freeSurfaceData(surface);
- sData = surface->data = MEM_callocN(sizeof(PaintSurfaceData), "PaintSurfaceData");
- if (!surface->data)
- return setError(canvas, N_("Not enough free memory"));
-
- tempPoints = MEM_callocN(w * h * sizeof(*tempPoints), "Temp PaintUVPoint");
- if (!tempPoints)
- error = true;
-
- final_index = MEM_callocN(w * h * sizeof(*final_index), "Temp UV Final Indexes");
- if (!final_index)
- error = true;
-
- tempWeights = MEM_mallocN(w * h * aa_samples * sizeof(*tempWeights), "Temp bWeights");
- if (!tempWeights)
- error = true;
-
- /*
- * Generate a temporary bounding box array for UV faces to optimize
- * the pixel-inside-a-face search.
- */
- if (!error) {
- faceBB = MEM_mallocN(tottri * sizeof(*faceBB), "MPCanvasFaceBB");
- if (!faceBB)
- error = true;
- }
-
- *progress = 0.01f;
- *do_update = true;
-
- if (!error) {
- for (int i = 0; i < tottri; i++) {
- copy_v2_v2(faceBB[i].min, mloopuv[mlooptri[i].tri[0]].uv);
- copy_v2_v2(faceBB[i].max, mloopuv[mlooptri[i].tri[0]].uv);
-
- for (int j = 1; j < 3; j++) {
- minmax_v2v2_v2(faceBB[i].min, faceBB[i].max, mloopuv[mlooptri[i].tri[j]].uv);
- }
- }
-
- *progress = 0.02f;
- *do_update = true;
-
- /* Loop through every pixel and check if pixel is uv-mapped on a canvas face. */
- DynamicPaintCreateUVSurfaceData data = {
- .surface = surface, .tempPoints = tempPoints, .tempWeights = tempWeights,
- .mlooptri = mlooptri, .mloopuv = mloopuv, .mloop = mloop, .tottri = tottri,
- .faceBB = faceBB,
- };
- {
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (h > 64 || tottri > 1000);
- BLI_task_parallel_range(0, h,
- &data,
- dynamic_paint_create_uv_surface_direct_cb,
- &settings);
- }
-
- *progress = 0.04f;
- *do_update = true;
-
- /*
- * Now loop through every pixel that was left without index
- * and find if they have neighboring pixels that have an index.
- * If so use that polygon as pixel surface.
- * (To avoid seams on uv island edges)
- */
- data.active_points = &active_points;
- {
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (h > 64);
- BLI_task_parallel_range(0, h,
- &data,
- dynamic_paint_create_uv_surface_neighbor_cb,
- &settings);
- }
-
- *progress = 0.06f;
- *do_update = true;
-
- /* Generate surface adjacency data. */
- {
- int cursor = 0;
-
- /* Create a temporary array of final indexes (before unassigned
- * pixels have been dropped) */
- for (int i = 0; i < w * h; i++) {
- if (tempPoints[i].tri_index != -1) {
- final_index[i] = cursor;
- cursor++;
- }
- }
- /* allocate memory */
- sData->total_points = w * h;
- dynamicPaint_initAdjacencyData(surface, true);
-
- if (sData->adj_data) {
- PaintAdjData *ed = sData->adj_data;
- int n_pos = 0;
-
- MeshElemMap *vert_to_looptri_map;
- int *vert_to_looptri_map_mem;
-
- BKE_mesh_vert_looptri_map_create(
- &vert_to_looptri_map, &vert_to_looptri_map_mem,
- mesh->mvert, mesh->totvert, mlooptri, tottri, mloop, mesh->totloop);
-
- int total_border = 0;
-
- for (int ty = 0; ty < h; ty++) {
- for (int tx = 0; tx < w; tx++) {
- const int index = tx + w * ty;
-
- if (tempPoints[index].tri_index != -1) {
- ed->n_index[final_index[index]] = n_pos;
- ed->n_num[final_index[index]] = 0;
-
- if (tempPoints[index].neighbour_pixel != -1) {
- ed->flags[final_index[index]] |= ADJ_BORDER_PIXEL;
- total_border++;
- }
-
- for (int i = 0; i < 8; i++) {
- /* Try to find a neighboring pixel in defined direction. If not found, -1 is returned */
- const int n_target = dynamic_paint_find_neighbour_pixel(
- &data, vert_to_looptri_map, w, h, tx, ty, i);
-
- if (n_target >= 0 && n_target != index) {
- if (!dynamicPaint_pointHasNeighbor(ed, final_index[index], final_index[n_target])) {
- ed->n_target[n_pos] = final_index[n_target];
- ed->n_num[final_index[index]]++;
- n_pos++;
- }
- }
- else if (n_target == ON_MESH_EDGE || n_target == OUT_OF_TEXTURE) {
- ed->flags[final_index[index]] |= ADJ_ON_MESH_EDGE;
- }
- }
- }
- }
- }
-
- MEM_freeN(vert_to_looptri_map);
- MEM_freeN(vert_to_looptri_map_mem);
-
- /* Make neighbors symmetric */
- if (!dynamicPaint_symmetrizeAdjData(ed, active_points)) {
- error = true;
- }
-
- /* Create a list of border pixels */
- ed->border = MEM_callocN(sizeof(int) * total_border, "Border Pixel Index");
-
- if (ed->border) {
- ed->total_border = total_border;
-
- for (int i = 0, next = 0; i < active_points; i++) {
- if (ed->flags[i] & ADJ_BORDER_PIXEL) {
- ed->border[next++] = i;
- }
- }
- }
+ /* Antialias jitter point relative coords */
+ const int aa_samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
+ char uvname[MAX_CUSTOMDATA_LAYER_NAME];
+ uint32_t active_points = 0;
+ bool error = false;
+
+ PaintSurfaceData *sData;
+ DynamicPaintCanvasSettings *canvas = surface->canvas;
+ Mesh *mesh = dynamicPaint_canvas_mesh_get(canvas);
+
+ PaintUVPoint *tempPoints = NULL;
+ Vec3f *tempWeights = NULL;
+ const MLoopTri *mlooptri = NULL;
+ const MLoopUV *mloopuv = NULL;
+ const MLoop *mloop = NULL;
+
+ Bounds2D *faceBB = NULL;
+ int *final_index;
+
+ *progress = 0.0f;
+ *do_update = true;
+
+ if (!mesh)
+ return setError(canvas, N_("Canvas mesh not updated"));
+ if (surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ)
+ return setError(canvas, N_("Cannot bake non-'image sequence' formats"));
+
+ mloop = mesh->mloop;
+ mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ const int tottri = BKE_mesh_runtime_looptri_len(mesh);
+
+ /* get uv map */
+ if (CustomData_has_layer(&mesh->ldata, CD_MLOOPUV)) {
+ CustomData_validate_layer_name(&mesh->ldata, CD_MLOOPUV, surface->uvlayer_name, uvname);
+ mloopuv = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvname);
+ }
+
+ /* Check for validity */
+ if (!mloopuv)
+ return setError(canvas, N_("No UV data on canvas"));
+ if (surface->image_resolution < 16 || surface->image_resolution > 8192)
+ return setError(canvas, N_("Invalid resolution"));
+
+ const int w = surface->image_resolution;
+ const int h = w;
+
+ /*
+ * Start generating the surface
+ */
+ CLOG_INFO(&LOG, 1, "Preparing UV surface of %ix%i pixels and %i tris.", w, h, tottri);
+
+ /* Init data struct */
+ if (surface->data)
+ dynamicPaint_freeSurfaceData(surface);
+ sData = surface->data = MEM_callocN(sizeof(PaintSurfaceData), "PaintSurfaceData");
+ if (!surface->data)
+ return setError(canvas, N_("Not enough free memory"));
+
+ tempPoints = MEM_callocN(w * h * sizeof(*tempPoints), "Temp PaintUVPoint");
+ if (!tempPoints)
+ error = true;
+
+ final_index = MEM_callocN(w * h * sizeof(*final_index), "Temp UV Final Indexes");
+ if (!final_index)
+ error = true;
+
+ tempWeights = MEM_mallocN(w * h * aa_samples * sizeof(*tempWeights), "Temp bWeights");
+ if (!tempWeights)
+ error = true;
+
+ /*
+ * Generate a temporary bounding box array for UV faces to optimize
+ * the pixel-inside-a-face search.
+ */
+ if (!error) {
+ faceBB = MEM_mallocN(tottri * sizeof(*faceBB), "MPCanvasFaceBB");
+ if (!faceBB)
+ error = true;
+ }
+
+ *progress = 0.01f;
+ *do_update = true;
+
+ if (!error) {
+ for (int i = 0; i < tottri; i++) {
+ copy_v2_v2(faceBB[i].min, mloopuv[mlooptri[i].tri[0]].uv);
+ copy_v2_v2(faceBB[i].max, mloopuv[mlooptri[i].tri[0]].uv);
+
+ for (int j = 1; j < 3; j++) {
+ minmax_v2v2_v2(faceBB[i].min, faceBB[i].max, mloopuv[mlooptri[i].tri[j]].uv);
+ }
+ }
+
+ *progress = 0.02f;
+ *do_update = true;
+
+ /* Loop through every pixel and check if pixel is uv-mapped on a canvas face. */
+ DynamicPaintCreateUVSurfaceData data = {
+ .surface = surface,
+ .tempPoints = tempPoints,
+ .tempWeights = tempWeights,
+ .mlooptri = mlooptri,
+ .mloopuv = mloopuv,
+ .mloop = mloop,
+ .tottri = tottri,
+ .faceBB = faceBB,
+ };
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (h > 64 || tottri > 1000);
+ BLI_task_parallel_range(0, h, &data, dynamic_paint_create_uv_surface_direct_cb, &settings);
+ }
+
+ *progress = 0.04f;
+ *do_update = true;
+
+ /*
+ * Now loop through every pixel that was left without index
+ * and find if they have neighboring pixels that have an index.
+ * If so use that polygon as pixel surface.
+ * (To avoid seams on uv island edges)
+ */
+ data.active_points = &active_points;
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (h > 64);
+ BLI_task_parallel_range(0, h, &data, dynamic_paint_create_uv_surface_neighbor_cb, &settings);
+ }
+
+ *progress = 0.06f;
+ *do_update = true;
+
+ /* Generate surface adjacency data. */
+ {
+ int cursor = 0;
+
+ /* Create a temporary array of final indexes (before unassigned
+ * pixels have been dropped) */
+ for (int i = 0; i < w * h; i++) {
+ if (tempPoints[i].tri_index != -1) {
+ final_index[i] = cursor;
+ cursor++;
+ }
+ }
+ /* allocate memory */
+ sData->total_points = w * h;
+ dynamicPaint_initAdjacencyData(surface, true);
+
+ if (sData->adj_data) {
+ PaintAdjData *ed = sData->adj_data;
+ int n_pos = 0;
+
+ MeshElemMap *vert_to_looptri_map;
+ int *vert_to_looptri_map_mem;
+
+ BKE_mesh_vert_looptri_map_create(&vert_to_looptri_map,
+ &vert_to_looptri_map_mem,
+ mesh->mvert,
+ mesh->totvert,
+ mlooptri,
+ tottri,
+ mloop,
+ mesh->totloop);
+
+ int total_border = 0;
+
+ for (int ty = 0; ty < h; ty++) {
+ for (int tx = 0; tx < w; tx++) {
+ const int index = tx + w * ty;
+
+ if (tempPoints[index].tri_index != -1) {
+ ed->n_index[final_index[index]] = n_pos;
+ ed->n_num[final_index[index]] = 0;
+
+ if (tempPoints[index].neighbour_pixel != -1) {
+ ed->flags[final_index[index]] |= ADJ_BORDER_PIXEL;
+ total_border++;
+ }
+
+ for (int i = 0; i < 8; i++) {
+ /* Try to find a neighboring pixel in defined direction. If not found, -1 is returned */
+ const int n_target = dynamic_paint_find_neighbour_pixel(
+ &data, vert_to_looptri_map, w, h, tx, ty, i);
+
+ if (n_target >= 0 && n_target != index) {
+ if (!dynamicPaint_pointHasNeighbor(
+ ed, final_index[index], final_index[n_target])) {
+ ed->n_target[n_pos] = final_index[n_target];
+ ed->n_num[final_index[index]]++;
+ n_pos++;
+ }
+ }
+ else if (n_target == ON_MESH_EDGE || n_target == OUT_OF_TEXTURE) {
+ ed->flags[final_index[index]] |= ADJ_ON_MESH_EDGE;
+ }
+ }
+ }
+ }
+ }
+
+ MEM_freeN(vert_to_looptri_map);
+ MEM_freeN(vert_to_looptri_map_mem);
+
+ /* Make neighbors symmetric */
+ if (!dynamicPaint_symmetrizeAdjData(ed, active_points)) {
+ error = true;
+ }
+
+ /* Create a list of border pixels */
+ ed->border = MEM_callocN(sizeof(int) * total_border, "Border Pixel Index");
+
+ if (ed->border) {
+ ed->total_border = total_border;
+
+ for (int i = 0, next = 0; i < active_points; i++) {
+ if (ed->flags[i] & ADJ_BORDER_PIXEL) {
+ ed->border[next++] = i;
+ }
+ }
+ }
#if 0
- /* -----------------------------------------------------------------
- * For debug, write a dump of adjacency data to a file.
- * -----------------------------------------------------------------*/
- FILE *dump_file = fopen("dynpaint-adj-data.txt", "w");
- int *tmp = MEM_callocN(sizeof(int) * active_points, "tmp");
- for (int ty = 0; ty < h; ty++) {
- for (int tx = 0; tx < w; tx++) {
- const int index = tx + w * ty;
- if (tempPoints[index].tri_index != -1)
- tmp[final_index[index]] = index;
- }
- }
- for (int ty = 0; ty < h; ty++) {
- for (int tx = 0; tx < w; tx++) {
- const int index = tx + w * ty;
- const int fidx = final_index[index];
-
- if (tempPoints[index].tri_index != -1) {
- int nidx = tempPoints[index].neighbour_pixel;
- fprintf(dump_file, "%d\t%d,%d\t%u\t%d,%d\t%d\t", fidx, tx, h-1-ty, tempPoints[index].tri_index, nidx<0?-1:(nidx%w), nidx<0?-1:h-1-(nidx/w), ed->flags[fidx]);
- for (int i = 0; i < ed->n_num[fidx]; i++) {
- int tgt = tmp[ed->n_target[ed->n_index[fidx]+i]];
- fprintf(dump_file, "%s%d,%d", i?" ":"", tgt%w, h-1-tgt/w);
- }
- fprintf(dump_file, "\n");
- }
- }
- }
- MEM_freeN(tmp);
- fclose(dump_file);
+ /* -----------------------------------------------------------------
+ * For debug, write a dump of adjacency data to a file.
+ * -----------------------------------------------------------------*/
+ FILE *dump_file = fopen("dynpaint-adj-data.txt", "w");
+ int *tmp = MEM_callocN(sizeof(int) * active_points, "tmp");
+ for (int ty = 0; ty < h; ty++) {
+ for (int tx = 0; tx < w; tx++) {
+ const int index = tx + w * ty;
+ if (tempPoints[index].tri_index != -1)
+ tmp[final_index[index]] = index;
+ }
+ }
+ for (int ty = 0; ty < h; ty++) {
+ for (int tx = 0; tx < w; tx++) {
+ const int index = tx + w * ty;
+ const int fidx = final_index[index];
+
+ if (tempPoints[index].tri_index != -1) {
+ int nidx = tempPoints[index].neighbour_pixel;
+ fprintf(dump_file, "%d\t%d,%d\t%u\t%d,%d\t%d\t", fidx, tx, h-1-ty, tempPoints[index].tri_index, nidx<0?-1:(nidx%w), nidx<0?-1:h-1-(nidx/w), ed->flags[fidx]);
+ for (int i = 0; i < ed->n_num[fidx]; i++) {
+ int tgt = tmp[ed->n_target[ed->n_index[fidx]+i]];
+ fprintf(dump_file, "%s%d,%d", i?" ":"", tgt%w, h-1-tgt/w);
+ }
+ fprintf(dump_file, "\n");
+ }
+ }
+ }
+ MEM_freeN(tmp);
+ fclose(dump_file);
#endif
- }
- }
-
- *progress = 0.08f;
- *do_update = true;
-
- /* Create final surface data without inactive points */
- ImgSeqFormatData *f_data = MEM_callocN(sizeof(*f_data), "ImgSeqFormatData");
- if (f_data) {
- f_data->uv_p = MEM_callocN(active_points * sizeof(*f_data->uv_p), "PaintUVPoint");
- f_data->barycentricWeights =
- MEM_callocN(active_points * aa_samples * sizeof(*f_data->barycentricWeights), "PaintUVPoint");
-
- if (!f_data->uv_p || !f_data->barycentricWeights)
- error = 1;
- }
- else {
- error = 1;
- }
-
- /* in case of allocation error, free everything */
- if (error) {
- if (f_data) {
- if (f_data->uv_p)
- MEM_freeN(f_data->uv_p);
- if (f_data->barycentricWeights)
- MEM_freeN(f_data->barycentricWeights);
- MEM_freeN(f_data);
- }
- sData->total_points = 0;
- }
- else {
- sData->total_points = (int)active_points;
- sData->format_data = f_data;
-
- for (int index = 0, cursor = 0; index < (w * h); index++) {
- if (tempPoints[index].tri_index != -1) {
- memcpy(&f_data->uv_p[cursor], &tempPoints[index], sizeof(PaintUVPoint));
- memcpy(&f_data->barycentricWeights[cursor * aa_samples], &tempWeights[index * aa_samples],
- sizeof(*tempWeights) * aa_samples);
- cursor++;
- }
- }
- }
- }
- if (error == 1)
- setError(canvas, N_("Not enough free memory"));
-
- if (faceBB)
- MEM_freeN(faceBB);
- if (tempPoints)
- MEM_freeN(tempPoints);
- if (tempWeights)
- MEM_freeN(tempWeights);
- if (final_index)
- MEM_freeN(final_index);
-
- /* Init surface type data */
- if (!error) {
- dynamicPaint_allocateSurfaceType(surface);
+ }
+ }
+
+ *progress = 0.08f;
+ *do_update = true;
+
+ /* Create final surface data without inactive points */
+ ImgSeqFormatData *f_data = MEM_callocN(sizeof(*f_data), "ImgSeqFormatData");
+ if (f_data) {
+ f_data->uv_p = MEM_callocN(active_points * sizeof(*f_data->uv_p), "PaintUVPoint");
+ f_data->barycentricWeights = MEM_callocN(
+ active_points * aa_samples * sizeof(*f_data->barycentricWeights), "PaintUVPoint");
+
+ if (!f_data->uv_p || !f_data->barycentricWeights)
+ error = 1;
+ }
+ else {
+ error = 1;
+ }
+
+ /* in case of allocation error, free everything */
+ if (error) {
+ if (f_data) {
+ if (f_data->uv_p)
+ MEM_freeN(f_data->uv_p);
+ if (f_data->barycentricWeights)
+ MEM_freeN(f_data->barycentricWeights);
+ MEM_freeN(f_data);
+ }
+ sData->total_points = 0;
+ }
+ else {
+ sData->total_points = (int)active_points;
+ sData->format_data = f_data;
+
+ for (int index = 0, cursor = 0; index < (w * h); index++) {
+ if (tempPoints[index].tri_index != -1) {
+ memcpy(&f_data->uv_p[cursor], &tempPoints[index], sizeof(PaintUVPoint));
+ memcpy(&f_data->barycentricWeights[cursor * aa_samples],
+ &tempWeights[index * aa_samples],
+ sizeof(*tempWeights) * aa_samples);
+ cursor++;
+ }
+ }
+ }
+ }
+ if (error == 1)
+ setError(canvas, N_("Not enough free memory"));
+
+ if (faceBB)
+ MEM_freeN(faceBB);
+ if (tempPoints)
+ MEM_freeN(tempPoints);
+ if (tempWeights)
+ MEM_freeN(tempWeights);
+ if (final_index)
+ MEM_freeN(final_index);
+
+ /* Init surface type data */
+ if (!error) {
+ dynamicPaint_allocateSurfaceType(surface);
#if 0
- /* -----------------------------------------------------------------
- * For debug, output pixel statuses to the color map
- * -----------------------------------------------------------------*/
- for (index = 0; index < sData->total_points; index++) {
- ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
- PaintUVPoint *uvPoint = &((PaintUVPoint *)f_data->uv_p)[index];
- PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
- pPoint->alpha = 1.0f;
-
- /* Every pixel that is assigned as "edge pixel" gets blue color */
- if (uvPoint->neighbour_pixel != -1)
- pPoint->color[2] = 1.0f;
- /* and every pixel that finally got an polygon gets red color */
- /* green color shows pixel face index hash */
- if (uvPoint->tri_index != -1) {
- pPoint->color[0] = 1.0f;
- pPoint->color[1] = (float)(uvPoint->tri_index % 255) / 256.0f;
- }
- }
+ /* -----------------------------------------------------------------
+ * For debug, output pixel statuses to the color map
+ * -----------------------------------------------------------------*/
+ for (index = 0; index < sData->total_points; index++) {
+ ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
+ PaintUVPoint *uvPoint = &((PaintUVPoint *)f_data->uv_p)[index];
+ PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
+ pPoint->alpha = 1.0f;
+
+ /* Every pixel that is assigned as "edge pixel" gets blue color */
+ if (uvPoint->neighbour_pixel != -1)
+ pPoint->color[2] = 1.0f;
+ /* and every pixel that finally got an polygon gets red color */
+ /* green color shows pixel face index hash */
+ if (uvPoint->tri_index != -1) {
+ pPoint->color[0] = 1.0f;
+ pPoint->color[1] = (float)(uvPoint->tri_index % 255) / 256.0f;
+ }
+ }
#endif
- dynamicPaint_setInitialColor(scene, surface);
- }
+ dynamicPaint_setInitialColor(scene, surface);
+ }
- *progress = 0.09f;
- *do_update = true;
+ *progress = 0.09f;
+ *do_update = true;
- return (error == 0);
+ return (error == 0);
}
/*
* Outputs an image file from uv surface data.
*/
typedef struct DynamicPaintOutputSurfaceImageData {
- const DynamicPaintSurface *surface;
- ImBuf *ibuf;
+ const DynamicPaintSurface *surface;
+ ImBuf *ibuf;
} DynamicPaintOutputSurfaceImageData;
static void dynamic_paint_output_surface_image_paint_cb(
- void *__restrict userdata,
- const int index,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+ void *__restrict userdata, const int index, const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintOutputSurfaceImageData *data = userdata;
+ const DynamicPaintOutputSurfaceImageData *data = userdata;
- const DynamicPaintSurface *surface = data->surface;
- const PaintPoint *point = &((PaintPoint *)surface->data->type_data)[index];
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintPoint *point = &((PaintPoint *)surface->data->type_data)[index];
- ImBuf *ibuf = data->ibuf;
- /* image buffer position */
- const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
+ ImBuf *ibuf = data->ibuf;
+ /* image buffer position */
+ const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
- /* blend wet and dry layers */
- blendColors(point->color, point->color[3], point->e_color, point->e_color[3], &ibuf->rect_float[pos]);
+ /* blend wet and dry layers */
+ blendColors(
+ point->color, point->color[3], point->e_color, point->e_color[3], &ibuf->rect_float[pos]);
- /* Multiply color by alpha if enabled */
- if (surface->flags & MOD_DPAINT_MULALPHA) {
- mul_v3_fl(&ibuf->rect_float[pos], ibuf->rect_float[pos + 3]);
- }
+ /* Multiply color by alpha if enabled */
+ if (surface->flags & MOD_DPAINT_MULALPHA) {
+ mul_v3_fl(&ibuf->rect_float[pos], ibuf->rect_float[pos + 3]);
+ }
}
static void dynamic_paint_output_surface_image_displace_cb(
- void *__restrict userdata,
- const int index,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+ void *__restrict userdata, const int index, const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintOutputSurfaceImageData *data = userdata;
+ const DynamicPaintOutputSurfaceImageData *data = userdata;
- const DynamicPaintSurface *surface = data->surface;
- float depth = ((float *)surface->data->type_data)[index];
+ const DynamicPaintSurface *surface = data->surface;
+ float depth = ((float *)surface->data->type_data)[index];
- ImBuf *ibuf = data->ibuf;
- /* image buffer position */
- const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
+ ImBuf *ibuf = data->ibuf;
+ /* image buffer position */
+ const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
- if (surface->depth_clamp)
- depth /= surface->depth_clamp;
+ if (surface->depth_clamp)
+ depth /= surface->depth_clamp;
- if (surface->disp_type == MOD_DPAINT_DISP_DISPLACE) {
- depth = (0.5f - depth / 2.0f);
- }
+ if (surface->disp_type == MOD_DPAINT_DISP_DISPLACE) {
+ depth = (0.5f - depth / 2.0f);
+ }
- CLAMP(depth, 0.0f, 1.0f);
+ CLAMP(depth, 0.0f, 1.0f);
- copy_v3_fl(&ibuf->rect_float[pos], depth);
- ibuf->rect_float[pos + 3] = 1.0f;
+ copy_v3_fl(&ibuf->rect_float[pos], depth);
+ ibuf->rect_float[pos + 3] = 1.0f;
}
static void dynamic_paint_output_surface_image_wave_cb(
- void *__restrict userdata,
- const int index,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+ void *__restrict userdata, const int index, const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintOutputSurfaceImageData *data = userdata;
+ const DynamicPaintOutputSurfaceImageData *data = userdata;
- const DynamicPaintSurface *surface = data->surface;
- const PaintWavePoint *wPoint = &((PaintWavePoint *)surface->data->type_data)[index];
- float depth = wPoint->height;
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintWavePoint *wPoint = &((PaintWavePoint *)surface->data->type_data)[index];
+ float depth = wPoint->height;
- ImBuf *ibuf = data->ibuf;
- /* image buffer position */
- const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
+ ImBuf *ibuf = data->ibuf;
+ /* image buffer position */
+ const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
- if (surface->depth_clamp)
- depth /= surface->depth_clamp;
+ if (surface->depth_clamp)
+ depth /= surface->depth_clamp;
- depth = (0.5f + depth / 2.0f);
- CLAMP(depth, 0.0f, 1.0f);
+ depth = (0.5f + depth / 2.0f);
+ CLAMP(depth, 0.0f, 1.0f);
- copy_v3_fl(&ibuf->rect_float[pos], depth);
- ibuf->rect_float[pos + 3] = 1.0f;
+ copy_v3_fl(&ibuf->rect_float[pos], depth);
+ ibuf->rect_float[pos + 3] = 1.0f;
}
static void dynamic_paint_output_surface_image_wetmap_cb(
- void *__restrict userdata,
- const int index,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+ void *__restrict userdata, const int index, const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintOutputSurfaceImageData *data = userdata;
+ const DynamicPaintOutputSurfaceImageData *data = userdata;
- const DynamicPaintSurface *surface = data->surface;
- const PaintPoint *point = &((PaintPoint *)surface->data->type_data)[index];
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintPoint *point = &((PaintPoint *)surface->data->type_data)[index];
- ImBuf *ibuf = data->ibuf;
- /* image buffer position */
- const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
+ ImBuf *ibuf = data->ibuf;
+ /* image buffer position */
+ const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
- copy_v3_fl(&ibuf->rect_float[pos], (point->wetness > 1.0f) ? 1.0f : point->wetness);
- ibuf->rect_float[pos + 3] = 1.0f;
+ copy_v3_fl(&ibuf->rect_float[pos], (point->wetness > 1.0f) ? 1.0f : point->wetness);
+ ibuf->rect_float[pos + 3] = 1.0f;
}
-void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char *filename, short output_layer)
+void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface,
+ char *filename,
+ short output_layer)
{
- ImBuf *ibuf = NULL;
- PaintSurfaceData *sData = surface->data;
- /* OpenEXR or PNG */
- int format = (surface->image_fileformat & MOD_DPAINT_IMGFORMAT_OPENEXR) ? R_IMF_IMTYPE_OPENEXR : R_IMF_IMTYPE_PNG;
- char output_file[FILE_MAX];
-
- if (!sData->type_data) {
- setError(surface->canvas, N_("Image save failed: invalid surface"));
- return;
- }
- /* if selected format is openexr, but current build doesn't support one */
+ ImBuf *ibuf = NULL;
+ PaintSurfaceData *sData = surface->data;
+ /* OpenEXR or PNG */
+ int format = (surface->image_fileformat & MOD_DPAINT_IMGFORMAT_OPENEXR) ? R_IMF_IMTYPE_OPENEXR :
+ R_IMF_IMTYPE_PNG;
+ char output_file[FILE_MAX];
+
+ if (!sData->type_data) {
+ setError(surface->canvas, N_("Image save failed: invalid surface"));
+ return;
+ }
+ /* if selected format is openexr, but current build doesn't support one */
#ifndef WITH_OPENEXR
- if (format == R_IMF_IMTYPE_OPENEXR)
- format = R_IMF_IMTYPE_PNG;
+ if (format == R_IMF_IMTYPE_OPENEXR)
+ format = R_IMF_IMTYPE_PNG;
#endif
- BLI_strncpy(output_file, filename, sizeof(output_file));
- BKE_image_path_ensure_ext_from_imtype(output_file, format);
-
- /* Validate output file path */
- BLI_path_abs(output_file, BKE_main_blendfile_path_from_global());
- BLI_make_existing_file(output_file);
-
- /* Init image buffer */
- ibuf = IMB_allocImBuf(surface->image_resolution, surface->image_resolution, 32, IB_rectfloat);
- if (ibuf == NULL) {
- setError(surface->canvas, N_("Image save failed: not enough free memory"));
- return;
- }
-
- DynamicPaintOutputSurfaceImageData data = { .surface = surface, .ibuf = ibuf, };
- switch (surface->type) {
- case MOD_DPAINT_SURFACE_T_PAINT:
- switch (output_layer) {
- case 0:
- {
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 10000);
- BLI_task_parallel_range(
- 0, sData->total_points,
- &data,
- dynamic_paint_output_surface_image_paint_cb,
- &settings);
- break;
- }
- case 1:
- {
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 10000);
- BLI_task_parallel_range(
- 0, sData->total_points,
- &data,
- dynamic_paint_output_surface_image_wetmap_cb,
- &settings);
- break;
- }
- default:
- BLI_assert(0);
- break;
- }
- break;
- case MOD_DPAINT_SURFACE_T_DISPLACE:
- switch (output_layer) {
- case 0:
- {
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 10000);
- BLI_task_parallel_range(
- 0, sData->total_points,
- &data,
- dynamic_paint_output_surface_image_displace_cb,
- &settings);
- break;
- }
- case 1:
- break;
- default:
- BLI_assert(0);
- break;
- }
- break;
- case MOD_DPAINT_SURFACE_T_WAVE:
- switch (output_layer) {
- case 0:
- {
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 10000);
- BLI_task_parallel_range(
- 0, sData->total_points,
- &data,
- dynamic_paint_output_surface_image_wave_cb,
- &settings);
- break;
- }
- case 1:
- break;
- default:
- BLI_assert(0);
- break;
- }
- break;
- default:
- BLI_assert(0);
- break;
- }
-
- /* Set output format, png in case exr isn't supported */
+ BLI_strncpy(output_file, filename, sizeof(output_file));
+ BKE_image_path_ensure_ext_from_imtype(output_file, format);
+
+ /* Validate output file path */
+ BLI_path_abs(output_file, BKE_main_blendfile_path_from_global());
+ BLI_make_existing_file(output_file);
+
+ /* Init image buffer */
+ ibuf = IMB_allocImBuf(surface->image_resolution, surface->image_resolution, 32, IB_rectfloat);
+ if (ibuf == NULL) {
+ setError(surface->canvas, N_("Image save failed: not enough free memory"));
+ return;
+ }
+
+ DynamicPaintOutputSurfaceImageData data = {
+ .surface = surface,
+ .ibuf = ibuf,
+ };
+ switch (surface->type) {
+ case MOD_DPAINT_SURFACE_T_PAINT:
+ switch (output_layer) {
+ case 0: {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 10000);
+ BLI_task_parallel_range(0,
+ sData->total_points,
+ &data,
+ dynamic_paint_output_surface_image_paint_cb,
+ &settings);
+ break;
+ }
+ case 1: {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 10000);
+ BLI_task_parallel_range(0,
+ sData->total_points,
+ &data,
+ dynamic_paint_output_surface_image_wetmap_cb,
+ &settings);
+ break;
+ }
+ default:
+ BLI_assert(0);
+ break;
+ }
+ break;
+ case MOD_DPAINT_SURFACE_T_DISPLACE:
+ switch (output_layer) {
+ case 0: {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 10000);
+ BLI_task_parallel_range(0,
+ sData->total_points,
+ &data,
+ dynamic_paint_output_surface_image_displace_cb,
+ &settings);
+ break;
+ }
+ case 1:
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+ break;
+ case MOD_DPAINT_SURFACE_T_WAVE:
+ switch (output_layer) {
+ case 0: {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 10000);
+ BLI_task_parallel_range(0,
+ sData->total_points,
+ &data,
+ dynamic_paint_output_surface_image_wave_cb,
+ &settings);
+ break;
+ }
+ case 1:
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+
+ /* Set output format, png in case exr isn't supported */
#ifdef WITH_OPENEXR
- if (format == R_IMF_IMTYPE_OPENEXR) { /* OpenEXR 32-bit float */
- ibuf->ftype = IMB_FTYPE_OPENEXR;
- ibuf->foptions.flag |= OPENEXR_COMPRESS;
- }
- else
+ if (format == R_IMF_IMTYPE_OPENEXR) { /* OpenEXR 32-bit float */
+ ibuf->ftype = IMB_FTYPE_OPENEXR;
+ ibuf->foptions.flag |= OPENEXR_COMPRESS;
+ }
+ else
#endif
- {
- ibuf->ftype = IMB_FTYPE_PNG;
- ibuf->foptions.quality = 15;
- }
-
- /* Save image */
- IMB_saveiff(ibuf, output_file, IB_rectfloat);
- IMB_freeImBuf(ibuf);
+ {
+ ibuf->ftype = IMB_FTYPE_PNG;
+ ibuf->foptions.quality = 15;
+ }
+
+ /* Save image */
+ IMB_saveiff(ibuf, output_file, IB_rectfloat);
+ IMB_freeImBuf(ibuf);
}
-
/***************************** Ray / Nearest Point Utils ******************************/
-
/* A modified callback to bvh tree raycast. The tree must have been built using bvhtree_from_mesh_looptri.
* userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree.
*
* To optimize brush detection speed this doesn't calculate hit coordinates or normal.
*/
-static void mesh_tris_spherecast_dp(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
+static void mesh_tris_spherecast_dp(void *userdata,
+ int index,
+ const BVHTreeRay *ray,
+ BVHTreeRayHit *hit)
{
- const BVHTreeFromMesh *data = (BVHTreeFromMesh *) userdata;
- const MVert *vert = data->vert;
- const MLoopTri *mlooptri = data->looptri;
- const MLoop *mloop = data->loop;
+ const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
+ const MVert *vert = data->vert;
+ const MLoopTri *mlooptri = data->looptri;
+ const MLoop *mloop = data->loop;
- const float *t0, *t1, *t2;
- float dist;
+ const float *t0, *t1, *t2;
+ float dist;
- t0 = vert[mloop[mlooptri[index].tri[0]].v].co;
- t1 = vert[mloop[mlooptri[index].tri[1]].v].co;
- t2 = vert[mloop[mlooptri[index].tri[2]].v].co;
+ t0 = vert[mloop[mlooptri[index].tri[0]].v].co;
+ t1 = vert[mloop[mlooptri[index].tri[1]].v].co;
+ t2 = vert[mloop[mlooptri[index].tri[2]].v].co;
- dist = bvhtree_ray_tri_intersection(ray, hit->dist, t0, t1, t2);
+ dist = bvhtree_ray_tri_intersection(ray, hit->dist, t0, t1, t2);
- if (dist >= 0 && dist < hit->dist) {
- hit->index = index;
- hit->dist = dist;
- hit->no[0] = 0.0f;
- }
+ if (dist >= 0 && dist < hit->dist) {
+ hit->index = index;
+ hit->dist = dist;
+ hit->no[0] = 0.0f;
+ }
}
/* A modified callback to bvh tree nearest point. The tree must have been built using bvhtree_from_mesh_looptri.
@@ -3405,31 +3432,33 @@ static void mesh_tris_spherecast_dp(void *userdata, int index, const BVHTreeRay
*
* To optimize brush detection speed this doesn't calculate hit normal.
*/
-static void mesh_tris_nearest_point_dp(void *userdata, int index, const float co[3], BVHTreeNearest *nearest)
+static void mesh_tris_nearest_point_dp(void *userdata,
+ int index,
+ const float co[3],
+ BVHTreeNearest *nearest)
{
- const BVHTreeFromMesh *data = (BVHTreeFromMesh *) userdata;
- const MVert *vert = data->vert;
- const MLoopTri *mlooptri = data->looptri;
- const MLoop *mloop = data->loop;
- float nearest_tmp[3], dist_sq;
-
- const float *t0, *t1, *t2;
- t0 = vert[mloop[mlooptri[index].tri[0]].v].co;
- t1 = vert[mloop[mlooptri[index].tri[1]].v].co;
- t2 = vert[mloop[mlooptri[index].tri[2]].v].co;
-
- closest_on_tri_to_point_v3(nearest_tmp, co, t0, t1, t2);
- dist_sq = len_squared_v3v3(co, nearest_tmp);
-
- if (dist_sq < nearest->dist_sq) {
- nearest->index = index;
- nearest->dist_sq = dist_sq;
- copy_v3_v3(nearest->co, nearest_tmp);
- nearest->no[0] = 0.0f;
- }
+ const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
+ const MVert *vert = data->vert;
+ const MLoopTri *mlooptri = data->looptri;
+ const MLoop *mloop = data->loop;
+ float nearest_tmp[3], dist_sq;
+
+ const float *t0, *t1, *t2;
+ t0 = vert[mloop[mlooptri[index].tri[0]].v].co;
+ t1 = vert[mloop[mlooptri[index].tri[1]].v].co;
+ t2 = vert[mloop[mlooptri[index].tri[2]].v].co;
+
+ closest_on_tri_to_point_v3(nearest_tmp, co, t0, t1, t2);
+ dist_sq = len_squared_v3v3(co, nearest_tmp);
+
+ if (dist_sq < nearest->dist_sq) {
+ nearest->index = index;
+ nearest->dist_sq = dist_sq;
+ copy_v3_v3(nearest->co, nearest_tmp);
+ nearest->no[0] = 0.0f;
+ }
}
-
/***************************** Brush Painting Calls ******************************/
/**
@@ -3442,986 +3471,1030 @@ static void mesh_tris_nearest_point_dp(void *userdata, int index, const float co
* \param timescale: Value used to adjust time dependent
* operations when using substeps
*/
-static void dynamicPaint_mixPaintColors(
- const DynamicPaintSurface *surface, const int index, const int paintFlags,
- const float paintColor[3], const float paintAlpha, const float paintWetness, const float timescale)
+static void dynamicPaint_mixPaintColors(const DynamicPaintSurface *surface,
+ const int index,
+ const int paintFlags,
+ const float paintColor[3],
+ const float paintAlpha,
+ const float paintWetness,
+ const float timescale)
{
- PaintPoint *pPoint = &((PaintPoint *)surface->data->type_data)[index];
-
- /* Add paint */
- if (!(paintFlags & MOD_DPAINT_ERASE)) {
- float mix[4];
- float temp_alpha = paintAlpha * ((paintFlags & MOD_DPAINT_ABS_ALPHA) ? 1.0f : timescale);
-
- /* mix brush color with wet layer color */
- blendColors(pPoint->e_color, pPoint->e_color[3], paintColor, temp_alpha, mix);
- copy_v3_v3(pPoint->e_color, mix);
-
- /* mix wetness and alpha depending on selected alpha mode */
- if (paintFlags & MOD_DPAINT_ABS_ALPHA) {
- /* update values to the brush level unless they're higher already */
- CLAMP_MIN(pPoint->e_color[3], paintAlpha);
- CLAMP_MIN(pPoint->wetness, paintWetness);
- }
- else {
- float wetness = paintWetness;
- CLAMP(wetness, 0.0f, 1.0f);
- pPoint->e_color[3] = mix[3];
- pPoint->wetness = pPoint->wetness * (1.0f - wetness) + wetness;
- }
-
- CLAMP_MIN(pPoint->wetness, MIN_WETNESS);
-
- pPoint->state = DPAINT_PAINT_NEW;
- }
- /* Erase paint */
- else {
- float a_ratio, a_highest;
- float wetness;
- float invFact = 1.0f - paintAlpha;
-
- /*
- * Make highest alpha to match erased value
- * but maintain alpha ratio
- */
- if (paintFlags & MOD_DPAINT_ABS_ALPHA) {
- a_highest = max_ff(pPoint->color[3], pPoint->e_color[3]);
- if (a_highest > invFact) {
- a_ratio = invFact / a_highest;
-
- pPoint->e_color[3] *= a_ratio;
- pPoint->color[3] *= a_ratio;
- }
- }
- else {
- pPoint->e_color[3] -= paintAlpha * timescale;
- CLAMP_MIN(pPoint->e_color[3], 0.0f);
- pPoint->color[3] -= paintAlpha * timescale;
- CLAMP_MIN(pPoint->color[3], 0.0f);
- }
-
- wetness = (1.0f - paintWetness) * pPoint->e_color[3];
- CLAMP_MAX(pPoint->wetness, wetness);
- }
+ PaintPoint *pPoint = &((PaintPoint *)surface->data->type_data)[index];
+
+ /* Add paint */
+ if (!(paintFlags & MOD_DPAINT_ERASE)) {
+ float mix[4];
+ float temp_alpha = paintAlpha * ((paintFlags & MOD_DPAINT_ABS_ALPHA) ? 1.0f : timescale);
+
+ /* mix brush color with wet layer color */
+ blendColors(pPoint->e_color, pPoint->e_color[3], paintColor, temp_alpha, mix);
+ copy_v3_v3(pPoint->e_color, mix);
+
+ /* mix wetness and alpha depending on selected alpha mode */
+ if (paintFlags & MOD_DPAINT_ABS_ALPHA) {
+ /* update values to the brush level unless they're higher already */
+ CLAMP_MIN(pPoint->e_color[3], paintAlpha);
+ CLAMP_MIN(pPoint->wetness, paintWetness);
+ }
+ else {
+ float wetness = paintWetness;
+ CLAMP(wetness, 0.0f, 1.0f);
+ pPoint->e_color[3] = mix[3];
+ pPoint->wetness = pPoint->wetness * (1.0f - wetness) + wetness;
+ }
+
+ CLAMP_MIN(pPoint->wetness, MIN_WETNESS);
+
+ pPoint->state = DPAINT_PAINT_NEW;
+ }
+ /* Erase paint */
+ else {
+ float a_ratio, a_highest;
+ float wetness;
+ float invFact = 1.0f - paintAlpha;
+
+ /*
+ * Make highest alpha to match erased value
+ * but maintain alpha ratio
+ */
+ if (paintFlags & MOD_DPAINT_ABS_ALPHA) {
+ a_highest = max_ff(pPoint->color[3], pPoint->e_color[3]);
+ if (a_highest > invFact) {
+ a_ratio = invFact / a_highest;
+
+ pPoint->e_color[3] *= a_ratio;
+ pPoint->color[3] *= a_ratio;
+ }
+ }
+ else {
+ pPoint->e_color[3] -= paintAlpha * timescale;
+ CLAMP_MIN(pPoint->e_color[3], 0.0f);
+ pPoint->color[3] -= paintAlpha * timescale;
+ CLAMP_MIN(pPoint->color[3], 0.0f);
+ }
+
+ wetness = (1.0f - paintWetness) * pPoint->e_color[3];
+ CLAMP_MAX(pPoint->wetness, wetness);
+ }
}
/* applies given brush intersection value for wave surface */
-static void dynamicPaint_mixWaveHeight(
- PaintWavePoint *wPoint, const DynamicPaintBrushSettings *brush, float isect_height)
+static void dynamicPaint_mixWaveHeight(PaintWavePoint *wPoint,
+ const DynamicPaintBrushSettings *brush,
+ float isect_height)
{
- const float isect_change = isect_height - wPoint->brush_isect;
- const float wave_factor = brush->wave_factor;
- bool hit = false;
-
- /* intersection marked regardless of brush type or hit */
- wPoint->brush_isect = isect_height;
- wPoint->state = DPAINT_WAVE_ISECT_CHANGED;
-
- isect_height *= wave_factor;
-
- /* determine hit depending on wave_factor */
- if (wave_factor > 0.0f && wPoint->height > isect_height)
- hit = true;
- else if (wave_factor < 0.0f && wPoint->height < isect_height)
- hit = true;
-
- if (hit) {
- switch (brush->wave_type) {
- case MOD_DPAINT_WAVEB_DEPTH:
- wPoint->height = isect_height;
- wPoint->state = DPAINT_WAVE_OBSTACLE;
- wPoint->velocity = 0.0f;
- break;
- case MOD_DPAINT_WAVEB_FORCE:
- wPoint->velocity = isect_height;
- break;
- case MOD_DPAINT_WAVEB_REFLECT:
- wPoint->state = DPAINT_WAVE_REFLECT_ONLY;
- break;
- case MOD_DPAINT_WAVEB_CHANGE:
- if (isect_change < 0.0f)
- wPoint->height += isect_change * wave_factor;
- break;
- default:
- BLI_assert(0);
- break;
- }
- }
+ const float isect_change = isect_height - wPoint->brush_isect;
+ const float wave_factor = brush->wave_factor;
+ bool hit = false;
+
+ /* intersection marked regardless of brush type or hit */
+ wPoint->brush_isect = isect_height;
+ wPoint->state = DPAINT_WAVE_ISECT_CHANGED;
+
+ isect_height *= wave_factor;
+
+ /* determine hit depending on wave_factor */
+ if (wave_factor > 0.0f && wPoint->height > isect_height)
+ hit = true;
+ else if (wave_factor < 0.0f && wPoint->height < isect_height)
+ hit = true;
+
+ if (hit) {
+ switch (brush->wave_type) {
+ case MOD_DPAINT_WAVEB_DEPTH:
+ wPoint->height = isect_height;
+ wPoint->state = DPAINT_WAVE_OBSTACLE;
+ wPoint->velocity = 0.0f;
+ break;
+ case MOD_DPAINT_WAVEB_FORCE:
+ wPoint->velocity = isect_height;
+ break;
+ case MOD_DPAINT_WAVEB_REFLECT:
+ wPoint->state = DPAINT_WAVE_REFLECT_ONLY;
+ break;
+ case MOD_DPAINT_WAVEB_CHANGE:
+ if (isect_change < 0.0f)
+ wPoint->height += isect_change * wave_factor;
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+ }
}
/*
* add brush results to the surface data depending on surface type
*/
-static void dynamicPaint_updatePointData(
- const DynamicPaintSurface *surface, const int index, const DynamicPaintBrushSettings *brush,
- float paint[3], float influence, float depth, float vel_factor, const float timescale)
+static void dynamicPaint_updatePointData(const DynamicPaintSurface *surface,
+ const int index,
+ const DynamicPaintBrushSettings *brush,
+ float paint[3],
+ float influence,
+ float depth,
+ float vel_factor,
+ const float timescale)
{
- PaintSurfaceData *sData = surface->data;
- float strength;
-
- /* apply influence scale */
- influence *= surface->influence_scale;
- depth *= surface->influence_scale;
-
- strength = influence * brush->alpha;
- CLAMP(strength, 0.0f, 1.0f);
-
- /* Sample velocity colorband if required */
- if (brush->flags & (MOD_DPAINT_VELOCITY_ALPHA | MOD_DPAINT_VELOCITY_COLOR | MOD_DPAINT_VELOCITY_DEPTH)) {
- float coba_res[4];
- vel_factor /= brush->max_velocity;
- CLAMP(vel_factor, 0.0f, 1.0f);
-
- if (BKE_colorband_evaluate(brush->vel_ramp, vel_factor, coba_res)) {
- if (brush->flags & MOD_DPAINT_VELOCITY_COLOR) {
- copy_v3_v3(paint, coba_res);
- }
- if (brush->flags & MOD_DPAINT_VELOCITY_ALPHA)
- strength *= coba_res[3];
- if (brush->flags & MOD_DPAINT_VELOCITY_DEPTH)
- depth *= coba_res[3];
- }
- }
-
- /* mix paint surface */
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- float paintWetness = brush->wetness * strength;
- float paintAlpha = strength;
-
- dynamicPaint_mixPaintColors(surface, index, brush->flags, paint, paintAlpha, paintWetness, timescale);
- }
- /* displace surface */
- else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
- float *value = (float *)sData->type_data;
-
- if (surface->flags & MOD_DPAINT_DISP_INCREMENTAL)
- depth = value[index] + depth;
-
- if (surface->depth_clamp) {
- CLAMP(depth, 0.0f - surface->depth_clamp, surface->depth_clamp);
- }
-
- if (brush->flags & MOD_DPAINT_ERASE) {
- value[index] *= (1.0f - strength);
- CLAMP_MIN(value[index], 0.0f);
- }
- else {
- CLAMP_MIN(value[index], depth);
- }
- }
- /* vertex weight group surface */
- else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
- float *value = (float *)sData->type_data;
-
- if (brush->flags & MOD_DPAINT_ERASE) {
- value[index] *= (1.0f - strength);
- CLAMP_MIN(value[index], 0.0f);
- }
- else {
- CLAMP_MIN(value[index], strength);
- }
- }
- /* wave surface */
- else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
- if (brush->wave_clamp) {
- CLAMP(depth, 0.0f - brush->wave_clamp, brush->wave_clamp);
- }
-
- dynamicPaint_mixWaveHeight(&((PaintWavePoint *)sData->type_data)[index], brush, 0.0f - depth);
- }
-
- /* doing velocity based painting */
- if (sData->bData->brush_velocity) {
- sData->bData->brush_velocity[index * 4 + 3] *= influence;
- }
+ PaintSurfaceData *sData = surface->data;
+ float strength;
+
+ /* apply influence scale */
+ influence *= surface->influence_scale;
+ depth *= surface->influence_scale;
+
+ strength = influence * brush->alpha;
+ CLAMP(strength, 0.0f, 1.0f);
+
+ /* Sample velocity colorband if required */
+ if (brush->flags &
+ (MOD_DPAINT_VELOCITY_ALPHA | MOD_DPAINT_VELOCITY_COLOR | MOD_DPAINT_VELOCITY_DEPTH)) {
+ float coba_res[4];
+ vel_factor /= brush->max_velocity;
+ CLAMP(vel_factor, 0.0f, 1.0f);
+
+ if (BKE_colorband_evaluate(brush->vel_ramp, vel_factor, coba_res)) {
+ if (brush->flags & MOD_DPAINT_VELOCITY_COLOR) {
+ copy_v3_v3(paint, coba_res);
+ }
+ if (brush->flags & MOD_DPAINT_VELOCITY_ALPHA)
+ strength *= coba_res[3];
+ if (brush->flags & MOD_DPAINT_VELOCITY_DEPTH)
+ depth *= coba_res[3];
+ }
+ }
+
+ /* mix paint surface */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ float paintWetness = brush->wetness * strength;
+ float paintAlpha = strength;
+
+ dynamicPaint_mixPaintColors(
+ surface, index, brush->flags, paint, paintAlpha, paintWetness, timescale);
+ }
+ /* displace surface */
+ else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
+ float *value = (float *)sData->type_data;
+
+ if (surface->flags & MOD_DPAINT_DISP_INCREMENTAL)
+ depth = value[index] + depth;
+
+ if (surface->depth_clamp) {
+ CLAMP(depth, 0.0f - surface->depth_clamp, surface->depth_clamp);
+ }
+
+ if (brush->flags & MOD_DPAINT_ERASE) {
+ value[index] *= (1.0f - strength);
+ CLAMP_MIN(value[index], 0.0f);
+ }
+ else {
+ CLAMP_MIN(value[index], depth);
+ }
+ }
+ /* vertex weight group surface */
+ else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
+ float *value = (float *)sData->type_data;
+
+ if (brush->flags & MOD_DPAINT_ERASE) {
+ value[index] *= (1.0f - strength);
+ CLAMP_MIN(value[index], 0.0f);
+ }
+ else {
+ CLAMP_MIN(value[index], strength);
+ }
+ }
+ /* wave surface */
+ else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
+ if (brush->wave_clamp) {
+ CLAMP(depth, 0.0f - brush->wave_clamp, brush->wave_clamp);
+ }
+
+ dynamicPaint_mixWaveHeight(&((PaintWavePoint *)sData->type_data)[index], brush, 0.0f - depth);
+ }
+
+ /* doing velocity based painting */
+ if (sData->bData->brush_velocity) {
+ sData->bData->brush_velocity[index * 4 + 3] *= influence;
+ }
}
/* checks whether surface and brush bounds intersect depending on brush type */
-static bool meshBrush_boundsIntersect(Bounds3D *b1, Bounds3D *b2, DynamicPaintBrushSettings *brush, float brush_radius)
+static bool meshBrush_boundsIntersect(Bounds3D *b1,
+ Bounds3D *b2,
+ DynamicPaintBrushSettings *brush,
+ float brush_radius)
{
- if (brush->collision == MOD_DPAINT_COL_VOLUME)
- return boundsIntersect(b1, b2);
- else if (brush->collision == MOD_DPAINT_COL_DIST || brush->collision == MOD_DPAINT_COL_VOLDIST)
- return boundsIntersectDist(b1, b2, brush_radius);
- return true;
+ if (brush->collision == MOD_DPAINT_COL_VOLUME)
+ return boundsIntersect(b1, b2);
+ else if (brush->collision == MOD_DPAINT_COL_DIST || brush->collision == MOD_DPAINT_COL_VOLDIST)
+ return boundsIntersectDist(b1, b2, brush_radius);
+ return true;
}
/* calculate velocity for mesh vertices */
typedef struct DynamicPaintBrushVelocityData {
- Vec3f *brush_vel;
+ Vec3f *brush_vel;
- const MVert *mvert_p;
- const MVert *mvert_c;
+ const MVert *mvert_p;
+ const MVert *mvert_c;
- float (*obmat)[4];
- float (*prev_obmat)[4];
+ float (*obmat)[4];
+ float (*prev_obmat)[4];
- const float timescale;
+ const float timescale;
} DynamicPaintBrushVelocityData;
-static void dynamic_paint_brush_velocity_compute_cb(
- void *__restrict userdata,
- const int i,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void dynamic_paint_brush_velocity_compute_cb(void *__restrict userdata,
+ const int i,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintBrushVelocityData *data = userdata;
+ const DynamicPaintBrushVelocityData *data = userdata;
- Vec3f *brush_vel = data->brush_vel;
+ Vec3f *brush_vel = data->brush_vel;
- const MVert *mvert_p = data->mvert_p;
- const MVert *mvert_c = data->mvert_c;
+ const MVert *mvert_p = data->mvert_p;
+ const MVert *mvert_c = data->mvert_c;
- float (*obmat)[4] = data->obmat;
- float (*prev_obmat)[4] = data->prev_obmat;
+ float(*obmat)[4] = data->obmat;
+ float(*prev_obmat)[4] = data->prev_obmat;
- const float timescale = data->timescale;
+ const float timescale = data->timescale;
- float p1[3], p2[3];
+ float p1[3], p2[3];
- copy_v3_v3(p1, mvert_p[i].co);
- mul_m4_v3(prev_obmat, p1);
+ copy_v3_v3(p1, mvert_p[i].co);
+ mul_m4_v3(prev_obmat, p1);
- copy_v3_v3(p2, mvert_c[i].co);
- mul_m4_v3(obmat, p2);
+ copy_v3_v3(p2, mvert_c[i].co);
+ mul_m4_v3(obmat, p2);
- sub_v3_v3v3(brush_vel[i].v, p2, p1);
- mul_v3_fl(brush_vel[i].v, 1.0f / timescale);
+ sub_v3_v3v3(brush_vel[i].v, p2, p1);
+ mul_v3_fl(brush_vel[i].v, 1.0f / timescale);
}
-static void dynamicPaint_brushMeshCalculateVelocity(
- Depsgraph *depsgraph, Scene *scene,
- Object *ob, DynamicPaintBrushSettings *brush, Vec3f **brushVel, float timescale)
+static void dynamicPaint_brushMeshCalculateVelocity(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ DynamicPaintBrushSettings *brush,
+ Vec3f **brushVel,
+ float timescale)
{
- float prev_obmat[4][4];
- Mesh *mesh_p, *mesh_c;
- MVert *mvert_p, *mvert_c;
- int numOfVerts_p, numOfVerts_c;
-
- float cur_sfra = scene->r.subframe;
- int cur_fra = scene->r.cfra;
- float prev_sfra = cur_sfra - timescale;
- int prev_fra = cur_fra;
-
- if (prev_sfra < 0.0f) {
- prev_sfra += 1.0f;
- prev_fra = cur_fra - 1;
- }
-
- /* previous frame mesh */
- scene->r.cfra = prev_fra;
- scene->r.subframe = prev_sfra;
-
- BKE_object_modifier_update_subframe(
- depsgraph, scene, ob, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
- mesh_p = BKE_mesh_copy_for_eval(dynamicPaint_brush_mesh_get(brush), false);
- numOfVerts_p = mesh_p->totvert;
- mvert_p = mesh_p->mvert;
- copy_m4_m4(prev_obmat, ob->obmat);
-
- /* current frame mesh */
- scene->r.cfra = cur_fra;
- scene->r.subframe = cur_sfra;
-
- BKE_object_modifier_update_subframe(
- depsgraph, scene, ob, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
- mesh_c = dynamicPaint_brush_mesh_get(brush);
- numOfVerts_c = mesh_c->totvert;
- mvert_c = mesh_c->mvert;
-
- (*brushVel) = (struct Vec3f *) MEM_mallocN(numOfVerts_c * sizeof(Vec3f), "Dynamic Paint brush velocity");
- if (!(*brushVel))
- return;
-
- /* if mesh is constructive -> num of verts has changed, only use current frame derived mesh */
- if (numOfVerts_p != numOfVerts_c)
- mvert_p = mvert_c;
-
- /* calculate speed */
- DynamicPaintBrushVelocityData data = {
- .brush_vel = *brushVel,
- .mvert_p = mvert_p, .mvert_c = mvert_c, .obmat = ob->obmat, .prev_obmat = prev_obmat,
- .timescale = timescale,
- };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (numOfVerts_c > 10000);
- BLI_task_parallel_range(0, numOfVerts_c,
- &data,
- dynamic_paint_brush_velocity_compute_cb,
- &settings);
-
- BKE_id_free(NULL, mesh_p);
+ float prev_obmat[4][4];
+ Mesh *mesh_p, *mesh_c;
+ MVert *mvert_p, *mvert_c;
+ int numOfVerts_p, numOfVerts_c;
+
+ float cur_sfra = scene->r.subframe;
+ int cur_fra = scene->r.cfra;
+ float prev_sfra = cur_sfra - timescale;
+ int prev_fra = cur_fra;
+
+ if (prev_sfra < 0.0f) {
+ prev_sfra += 1.0f;
+ prev_fra = cur_fra - 1;
+ }
+
+ /* previous frame mesh */
+ scene->r.cfra = prev_fra;
+ scene->r.subframe = prev_sfra;
+
+ BKE_object_modifier_update_subframe(depsgraph,
+ scene,
+ ob,
+ true,
+ SUBFRAME_RECURSION,
+ BKE_scene_frame_get(scene),
+ eModifierType_DynamicPaint);
+ mesh_p = BKE_mesh_copy_for_eval(dynamicPaint_brush_mesh_get(brush), false);
+ numOfVerts_p = mesh_p->totvert;
+ mvert_p = mesh_p->mvert;
+ copy_m4_m4(prev_obmat, ob->obmat);
+
+ /* current frame mesh */
+ scene->r.cfra = cur_fra;
+ scene->r.subframe = cur_sfra;
+
+ BKE_object_modifier_update_subframe(depsgraph,
+ scene,
+ ob,
+ true,
+ SUBFRAME_RECURSION,
+ BKE_scene_frame_get(scene),
+ eModifierType_DynamicPaint);
+ mesh_c = dynamicPaint_brush_mesh_get(brush);
+ numOfVerts_c = mesh_c->totvert;
+ mvert_c = mesh_c->mvert;
+
+ (*brushVel) = (struct Vec3f *)MEM_mallocN(numOfVerts_c * sizeof(Vec3f),
+ "Dynamic Paint brush velocity");
+ if (!(*brushVel))
+ return;
+
+ /* if mesh is constructive -> num of verts has changed, only use current frame derived mesh */
+ if (numOfVerts_p != numOfVerts_c)
+ mvert_p = mvert_c;
+
+ /* calculate speed */
+ DynamicPaintBrushVelocityData data = {
+ .brush_vel = *brushVel,
+ .mvert_p = mvert_p,
+ .mvert_c = mvert_c,
+ .obmat = ob->obmat,
+ .prev_obmat = prev_obmat,
+ .timescale = timescale,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (numOfVerts_c > 10000);
+ BLI_task_parallel_range(
+ 0, numOfVerts_c, &data, dynamic_paint_brush_velocity_compute_cb, &settings);
+
+ BKE_id_free(NULL, mesh_p);
}
/* calculate velocity for object center point */
static void dynamicPaint_brushObjectCalculateVelocity(
- Depsgraph *depsgraph, Scene *scene, Object *ob, Vec3f *brushVel, float timescale)
+ Depsgraph *depsgraph, Scene *scene, Object *ob, Vec3f *brushVel, float timescale)
{
- float prev_obmat[4][4];
- float cur_loc[3] = {0.0f}, prev_loc[3] = {0.0f};
-
- float cur_sfra = scene->r.subframe;
- int cur_fra = scene->r.cfra;
- float prev_sfra = cur_sfra - timescale;
- int prev_fra = cur_fra;
-
- if (prev_sfra < 0.0f) {
- prev_sfra += 1.0f;
- prev_fra = cur_fra - 1;
- }
-
- /* previous frame mesh */
- scene->r.cfra = prev_fra;
- scene->r.subframe = prev_sfra;
- BKE_object_modifier_update_subframe(
- depsgraph, scene, ob, false, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
- copy_m4_m4(prev_obmat, ob->obmat);
-
- /* current frame mesh */
- scene->r.cfra = cur_fra;
- scene->r.subframe = cur_sfra;
- BKE_object_modifier_update_subframe(
- depsgraph, scene, ob, false, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
-
- /* calculate speed */
- mul_m4_v3(prev_obmat, prev_loc);
- mul_m4_v3(ob->obmat, cur_loc);
-
- sub_v3_v3v3(brushVel->v, cur_loc, prev_loc);
- mul_v3_fl(brushVel->v, 1.0f / timescale);
+ float prev_obmat[4][4];
+ float cur_loc[3] = {0.0f}, prev_loc[3] = {0.0f};
+
+ float cur_sfra = scene->r.subframe;
+ int cur_fra = scene->r.cfra;
+ float prev_sfra = cur_sfra - timescale;
+ int prev_fra = cur_fra;
+
+ if (prev_sfra < 0.0f) {
+ prev_sfra += 1.0f;
+ prev_fra = cur_fra - 1;
+ }
+
+ /* previous frame mesh */
+ scene->r.cfra = prev_fra;
+ scene->r.subframe = prev_sfra;
+ BKE_object_modifier_update_subframe(depsgraph,
+ scene,
+ ob,
+ false,
+ SUBFRAME_RECURSION,
+ BKE_scene_frame_get(scene),
+ eModifierType_DynamicPaint);
+ copy_m4_m4(prev_obmat, ob->obmat);
+
+ /* current frame mesh */
+ scene->r.cfra = cur_fra;
+ scene->r.subframe = cur_sfra;
+ BKE_object_modifier_update_subframe(depsgraph,
+ scene,
+ ob,
+ false,
+ SUBFRAME_RECURSION,
+ BKE_scene_frame_get(scene),
+ eModifierType_DynamicPaint);
+
+ /* calculate speed */
+ mul_m4_v3(prev_obmat, prev_loc);
+ mul_m4_v3(ob->obmat, cur_loc);
+
+ sub_v3_v3v3(brushVel->v, cur_loc, prev_loc);
+ mul_v3_fl(brushVel->v, 1.0f / timescale);
}
typedef struct DynamicPaintPaintData {
- const DynamicPaintSurface *surface;
- const DynamicPaintBrushSettings *brush;
- Object *brushOb;
- const Scene *scene;
- const float timescale;
- const int c_index;
-
- Mesh *mesh;
- const MVert *mvert;
- const MLoop *mloop;
- const MLoopTri *mlooptri;
- const float brush_radius;
- const float *avg_brushNor;
- const Vec3f *brushVelocity;
-
- const ParticleSystem *psys;
- const float solidradius;
-
- void *treeData;
-
- float *pointCoord;
+ const DynamicPaintSurface *surface;
+ const DynamicPaintBrushSettings *brush;
+ Object *brushOb;
+ const Scene *scene;
+ const float timescale;
+ const int c_index;
+
+ Mesh *mesh;
+ const MVert *mvert;
+ const MLoop *mloop;
+ const MLoopTri *mlooptri;
+ const float brush_radius;
+ const float *avg_brushNor;
+ const Vec3f *brushVelocity;
+
+ const ParticleSystem *psys;
+ const float solidradius;
+
+ void *treeData;
+
+ float *pointCoord;
} DynamicPaintPaintData;
/*
* Paint a brush object mesh to the surface
*/
static void dynamic_paint_paint_mesh_cell_point_cb_ex(
- void *__restrict userdata,
- const int id,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+ void *__restrict userdata, const int id, const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintPaintData *data = userdata;
-
- const DynamicPaintSurface *surface = data->surface;
- const PaintSurfaceData *sData = surface->data;
- const PaintBakeData *bData = sData->bData;
- VolumeGrid *grid = bData->grid;
-
- const DynamicPaintBrushSettings *brush = data->brush;
-
- const float timescale = data->timescale;
- const int c_index = data->c_index;
-
- const MVert *mvert = data->mvert;
- const MLoop *mloop = data->mloop;
- const MLoopTri *mlooptri = data->mlooptri;
- const float brush_radius = data->brush_radius;
- const float *avg_brushNor = data->avg_brushNor;
- const Vec3f *brushVelocity = data->brushVelocity;
-
- BVHTreeFromMesh *treeData = data->treeData;
-
- const int index = grid->t_index[grid->s_pos[c_index] + id];
- const int samples = bData->s_num[index];
- int ss;
- float total_sample = (float)samples;
- float brushStrength = 0.0f; /* brush influence factor */
- float depth = 0.0f; /* brush intersection depth */
- float velocity_val = 0.0f;
-
- float paintColor[3] = {0.0f};
- int numOfHits = 0;
-
- /* for image sequence anti-aliasing, use gaussian factors */
- if (samples > 1 && surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
- total_sample = gaussianTotal;
-
- /* Supersampling */
- for (ss = 0; ss < samples; ss++) {
- float ray_start[3], ray_dir[3];
- float sample_factor = 0.0f;
- float sampleStrength = 0.0f;
- BVHTreeRayHit hit;
- BVHTreeNearest nearest;
- short hit_found = 0;
-
- /* volume sample */
- float volume_factor = 0.0f;
- /* proximity sample */
- float proximity_factor = 0.0f;
- float prox_colorband[4] = {0.0f};
- const bool inner_proximity = (brush->flags & MOD_DPAINT_INVERSE_PROX &&
- brush->collision == MOD_DPAINT_COL_VOLDIST);
-
- /* hit data */
- float hitCoord[3];
- int hitTri = -1;
-
- /* Supersampling factor */
- if (samples > 1 && surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
- sample_factor = gaussianFactors[ss];
- else
- sample_factor = 1.0f;
-
- /* Get current sample position in world coordinates */
- copy_v3_v3(ray_start, bData->realCoord[bData->s_pos[index] + ss].v);
- copy_v3_v3(ray_dir, bData->bNormal[index].invNorm);
-
- /* a simple hack to minimize chance of ray leaks at identical ray <-> edge locations */
- add_v3_fl(ray_start, 0.001f);
-
- hit.index = -1;
- hit.dist = BVH_RAYCAST_DIST_MAX;
- nearest.index = -1;
- nearest.dist_sq = brush_radius * brush_radius; /* find_nearest uses squared distance */
-
- /* Check volume collision */
- if (ELEM(brush->collision, MOD_DPAINT_COL_VOLUME, MOD_DPAINT_COL_VOLDIST)) {
- BLI_bvhtree_ray_cast(treeData->tree, ray_start, ray_dir, 0.0f, &hit, mesh_tris_spherecast_dp, treeData);
- if (hit.index != -1) {
- /* We hit a triangle, now check if collision point normal is facing the point */
-
- /* For optimization sake, hit point normal isn't calculated in ray cast loop */
- const int vtri[3] = {
- mloop[mlooptri[hit.index].tri[0]].v,
- mloop[mlooptri[hit.index].tri[1]].v,
- mloop[mlooptri[hit.index].tri[2]].v,
- };
- float dot;
-
- normal_tri_v3(hit.no, mvert[vtri[0]].co, mvert[vtri[1]].co, mvert[vtri[2]].co);
- dot = dot_v3v3(ray_dir, hit.no);
-
- /* If ray and hit face normal are facing same direction
- * hit point is inside a closed mesh. */
- if (dot >= 0.0f) {
- const float dist = hit.dist;
- const int f_index = hit.index;
-
- /* Also cast a ray in opposite direction to make sure
- * point is at least surrounded by two brush faces */
- negate_v3(ray_dir);
- hit.index = -1;
- hit.dist = BVH_RAYCAST_DIST_MAX;
-
- BLI_bvhtree_ray_cast(
- treeData->tree, ray_start, ray_dir, 0.0f, &hit, mesh_tris_spherecast_dp, treeData);
-
- if (hit.index != -1) {
- /* Add factor on supersample filter */
- volume_factor = 1.0f;
- hit_found = HIT_VOLUME;
-
- /* Mark hit info */
- madd_v3_v3v3fl(hitCoord, ray_start, ray_dir, hit.dist); /* Calculate final hit coordinates */
- depth += dist * sample_factor;
- hitTri = f_index;
- }
- }
- }
- }
-
- /* Check proximity collision */
- if (ELEM(brush->collision, MOD_DPAINT_COL_DIST, MOD_DPAINT_COL_VOLDIST) &&
- (!hit_found || (brush->flags & MOD_DPAINT_INVERSE_PROX)))
- {
- float proxDist = -1.0f;
- float hitCo[3] = {0.0f, 0.0f, 0.0f};
- int tri = 0;
-
- /* if inverse prox and no hit found, skip this sample */
- if (inner_proximity && !hit_found)
- continue;
-
- /* If pure distance proximity, find the nearest point on the mesh */
- if (!(brush->flags & MOD_DPAINT_PROX_PROJECT)) {
- BLI_bvhtree_find_nearest(treeData->tree, ray_start, &nearest, mesh_tris_nearest_point_dp, treeData);
- if (nearest.index != -1) {
- proxDist = sqrtf(nearest.dist_sq);
- copy_v3_v3(hitCo, nearest.co);
- tri = nearest.index;
- }
- }
- else { /* else cast a ray in defined projection direction */
- float proj_ray[3] = {0.0f};
-
- if (brush->ray_dir == MOD_DPAINT_RAY_CANVAS) {
- copy_v3_v3(proj_ray, bData->bNormal[index].invNorm);
- negate_v3(proj_ray);
- }
- else if (brush->ray_dir == MOD_DPAINT_RAY_BRUSH_AVG) {
- copy_v3_v3(proj_ray, avg_brushNor);
- }
- else { /* MOD_DPAINT_RAY_ZPLUS */
- proj_ray[2] = 1.0f;
- }
- hit.index = -1;
- hit.dist = brush_radius;
-
- /* Do a face normal directional raycast, and use that distance */
- BLI_bvhtree_ray_cast(
- treeData->tree, ray_start, proj_ray, 0.0f, &hit, mesh_tris_spherecast_dp, treeData);
- if (hit.index != -1) {
- proxDist = hit.dist;
- madd_v3_v3v3fl(hitCo, ray_start, proj_ray, hit.dist); /* Calculate final hit coordinates */
- tri = hit.index;
- }
- }
-
- /* If a hit was found, calculate required values */
- if (proxDist >= 0.0f && proxDist <= brush_radius) {
- proximity_factor = proxDist / brush_radius;
- CLAMP(proximity_factor, 0.0f, 1.0f);
- if (!inner_proximity)
- proximity_factor = 1.0f - proximity_factor;
-
- hit_found = HIT_PROXIMITY;
-
- /* if no volume hit, use prox point face info */
- if (hitTri == -1) {
- copy_v3_v3(hitCoord, hitCo);
- hitTri = tri;
- }
- }
- }
-
- /* mix final sample strength depending on brush settings */
- if (hit_found) {
- /* if "negate volume" enabled, negate all factors within volume*/
- if (brush->collision == MOD_DPAINT_COL_VOLDIST &&
- brush->flags & MOD_DPAINT_NEGATE_VOLUME)
- {
- volume_factor = 1.0f - volume_factor;
- if (inner_proximity)
- proximity_factor = 1.0f - proximity_factor;
- }
-
- /* apply final sample depending on final hit type */
- if (hit_found == HIT_VOLUME) {
- sampleStrength = volume_factor;
- }
- else if (hit_found == HIT_PROXIMITY) {
- /* apply falloff curve to the proximity_factor */
- if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP &&
- BKE_colorband_evaluate(brush->paint_ramp, (1.0f - proximity_factor), prox_colorband))
- {
- proximity_factor = prox_colorband[3];
- }
- else if (brush->proximity_falloff == MOD_DPAINT_PRFALL_CONSTANT) {
- proximity_factor = (!inner_proximity || brush->flags & MOD_DPAINT_NEGATE_VOLUME) ? 1.0f : 0.0f;
- }
- /* apply sample */
- sampleStrength = proximity_factor;
- }
-
- sampleStrength *= sample_factor;
- }
- else {
- continue;
- }
-
- /* velocity brush, only do on main sample */
- if (brush->flags & MOD_DPAINT_USES_VELOCITY && ss == 0 && brushVelocity) {
- float weights[3];
- float brushPointVelocity[3];
- float velocity[3];
-
- const int v1 = mloop[mlooptri[hitTri].tri[0]].v;
- const int v2 = mloop[mlooptri[hitTri].tri[1]].v;
- const int v3 = mloop[mlooptri[hitTri].tri[2]].v;
-
- /* calculate barycentric weights for hit point */
- interp_weights_tri_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, hitCoord);
-
- /* simple check based on brush surface velocity,
- * todo: perhaps implement something that handles volume movement as well. */
-
- /* interpolate vertex speed vectors to get hit point velocity */
- interp_v3_v3v3v3(brushPointVelocity,
- brushVelocity[v1].v,
- brushVelocity[v2].v,
- brushVelocity[v3].v, weights);
-
- /* substract canvas point velocity */
- if (bData->velocity) {
- sub_v3_v3v3(velocity, brushPointVelocity, bData->velocity[index].v);
- }
- else {
- copy_v3_v3(velocity, brushPointVelocity);
- }
- velocity_val = normalize_v3(velocity);
-
- /* if brush has smudge enabled store brush velocity */
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT &&
- brush->flags & MOD_DPAINT_DO_SMUDGE && bData->brush_velocity)
- {
- copy_v3_v3(&bData->brush_velocity[index * 4], velocity);
- bData->brush_velocity[index * 4 + 3] = velocity_val;
- }
- }
-
- /*
- * Process hit color and alpha
- */
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- float sampleColor[3];
- float alpha_factor = 1.0f;
-
- sampleColor[0] = brush->r;
- sampleColor[1] = brush->g;
- sampleColor[2] = brush->b;
-
- /* Sample proximity colorband if required */
- if ((hit_found == HIT_PROXIMITY) &&
- (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP))
- {
- if (!(brush->flags & MOD_DPAINT_RAMP_ALPHA)) {
- sampleColor[0] = prox_colorband[0];
- sampleColor[1] = prox_colorband[1];
- sampleColor[2] = prox_colorband[2];
- }
- }
-
- /* Add AA sample */
- paintColor[0] += sampleColor[0];
- paintColor[1] += sampleColor[1];
- paintColor[2] += sampleColor[2];
- sampleStrength *= alpha_factor;
- numOfHits++;
- }
-
- /* apply sample strength */
- brushStrength += sampleStrength;
- } // end supersampling
-
-
- /* if any sample was inside paint range */
- if (brushStrength > 0.0f || depth > 0.0f) {
- /* apply supersampling results */
- if (samples > 1) {
- brushStrength /= total_sample;
- }
- CLAMP(brushStrength, 0.0f, 1.0f);
-
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- /* Get final pixel color and alpha */
- paintColor[0] /= numOfHits;
- paintColor[1] /= numOfHits;
- paintColor[2] /= numOfHits;
- }
- /* get final object space depth */
- else if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
- depth /= bData->bNormal[index].normal_scale * total_sample;
- }
-
- dynamicPaint_updatePointData(surface, index, brush, paintColor, brushStrength, depth, velocity_val, timescale);
- }
+ const DynamicPaintPaintData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ const PaintBakeData *bData = sData->bData;
+ VolumeGrid *grid = bData->grid;
+
+ const DynamicPaintBrushSettings *brush = data->brush;
+
+ const float timescale = data->timescale;
+ const int c_index = data->c_index;
+
+ const MVert *mvert = data->mvert;
+ const MLoop *mloop = data->mloop;
+ const MLoopTri *mlooptri = data->mlooptri;
+ const float brush_radius = data->brush_radius;
+ const float *avg_brushNor = data->avg_brushNor;
+ const Vec3f *brushVelocity = data->brushVelocity;
+
+ BVHTreeFromMesh *treeData = data->treeData;
+
+ const int index = grid->t_index[grid->s_pos[c_index] + id];
+ const int samples = bData->s_num[index];
+ int ss;
+ float total_sample = (float)samples;
+ float brushStrength = 0.0f; /* brush influence factor */
+ float depth = 0.0f; /* brush intersection depth */
+ float velocity_val = 0.0f;
+
+ float paintColor[3] = {0.0f};
+ int numOfHits = 0;
+
+ /* for image sequence anti-aliasing, use gaussian factors */
+ if (samples > 1 && surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
+ total_sample = gaussianTotal;
+
+ /* Supersampling */
+ for (ss = 0; ss < samples; ss++) {
+ float ray_start[3], ray_dir[3];
+ float sample_factor = 0.0f;
+ float sampleStrength = 0.0f;
+ BVHTreeRayHit hit;
+ BVHTreeNearest nearest;
+ short hit_found = 0;
+
+ /* volume sample */
+ float volume_factor = 0.0f;
+ /* proximity sample */
+ float proximity_factor = 0.0f;
+ float prox_colorband[4] = {0.0f};
+ const bool inner_proximity = (brush->flags & MOD_DPAINT_INVERSE_PROX &&
+ brush->collision == MOD_DPAINT_COL_VOLDIST);
+
+ /* hit data */
+ float hitCoord[3];
+ int hitTri = -1;
+
+ /* Supersampling factor */
+ if (samples > 1 && surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
+ sample_factor = gaussianFactors[ss];
+ else
+ sample_factor = 1.0f;
+
+ /* Get current sample position in world coordinates */
+ copy_v3_v3(ray_start, bData->realCoord[bData->s_pos[index] + ss].v);
+ copy_v3_v3(ray_dir, bData->bNormal[index].invNorm);
+
+ /* a simple hack to minimize chance of ray leaks at identical ray <-> edge locations */
+ add_v3_fl(ray_start, 0.001f);
+
+ hit.index = -1;
+ hit.dist = BVH_RAYCAST_DIST_MAX;
+ nearest.index = -1;
+ nearest.dist_sq = brush_radius * brush_radius; /* find_nearest uses squared distance */
+
+ /* Check volume collision */
+ if (ELEM(brush->collision, MOD_DPAINT_COL_VOLUME, MOD_DPAINT_COL_VOLDIST)) {
+ BLI_bvhtree_ray_cast(
+ treeData->tree, ray_start, ray_dir, 0.0f, &hit, mesh_tris_spherecast_dp, treeData);
+ if (hit.index != -1) {
+ /* We hit a triangle, now check if collision point normal is facing the point */
+
+ /* For optimization sake, hit point normal isn't calculated in ray cast loop */
+ const int vtri[3] = {
+ mloop[mlooptri[hit.index].tri[0]].v,
+ mloop[mlooptri[hit.index].tri[1]].v,
+ mloop[mlooptri[hit.index].tri[2]].v,
+ };
+ float dot;
+
+ normal_tri_v3(hit.no, mvert[vtri[0]].co, mvert[vtri[1]].co, mvert[vtri[2]].co);
+ dot = dot_v3v3(ray_dir, hit.no);
+
+ /* If ray and hit face normal are facing same direction
+ * hit point is inside a closed mesh. */
+ if (dot >= 0.0f) {
+ const float dist = hit.dist;
+ const int f_index = hit.index;
+
+ /* Also cast a ray in opposite direction to make sure
+ * point is at least surrounded by two brush faces */
+ negate_v3(ray_dir);
+ hit.index = -1;
+ hit.dist = BVH_RAYCAST_DIST_MAX;
+
+ BLI_bvhtree_ray_cast(
+ treeData->tree, ray_start, ray_dir, 0.0f, &hit, mesh_tris_spherecast_dp, treeData);
+
+ if (hit.index != -1) {
+ /* Add factor on supersample filter */
+ volume_factor = 1.0f;
+ hit_found = HIT_VOLUME;
+
+ /* Mark hit info */
+ madd_v3_v3v3fl(
+ hitCoord, ray_start, ray_dir, hit.dist); /* Calculate final hit coordinates */
+ depth += dist * sample_factor;
+ hitTri = f_index;
+ }
+ }
+ }
+ }
+
+ /* Check proximity collision */
+ if (ELEM(brush->collision, MOD_DPAINT_COL_DIST, MOD_DPAINT_COL_VOLDIST) &&
+ (!hit_found || (brush->flags & MOD_DPAINT_INVERSE_PROX))) {
+ float proxDist = -1.0f;
+ float hitCo[3] = {0.0f, 0.0f, 0.0f};
+ int tri = 0;
+
+ /* if inverse prox and no hit found, skip this sample */
+ if (inner_proximity && !hit_found)
+ continue;
+
+ /* If pure distance proximity, find the nearest point on the mesh */
+ if (!(brush->flags & MOD_DPAINT_PROX_PROJECT)) {
+ BLI_bvhtree_find_nearest(
+ treeData->tree, ray_start, &nearest, mesh_tris_nearest_point_dp, treeData);
+ if (nearest.index != -1) {
+ proxDist = sqrtf(nearest.dist_sq);
+ copy_v3_v3(hitCo, nearest.co);
+ tri = nearest.index;
+ }
+ }
+ else { /* else cast a ray in defined projection direction */
+ float proj_ray[3] = {0.0f};
+
+ if (brush->ray_dir == MOD_DPAINT_RAY_CANVAS) {
+ copy_v3_v3(proj_ray, bData->bNormal[index].invNorm);
+ negate_v3(proj_ray);
+ }
+ else if (brush->ray_dir == MOD_DPAINT_RAY_BRUSH_AVG) {
+ copy_v3_v3(proj_ray, avg_brushNor);
+ }
+ else { /* MOD_DPAINT_RAY_ZPLUS */
+ proj_ray[2] = 1.0f;
+ }
+ hit.index = -1;
+ hit.dist = brush_radius;
+
+ /* Do a face normal directional raycast, and use that distance */
+ BLI_bvhtree_ray_cast(
+ treeData->tree, ray_start, proj_ray, 0.0f, &hit, mesh_tris_spherecast_dp, treeData);
+ if (hit.index != -1) {
+ proxDist = hit.dist;
+ madd_v3_v3v3fl(
+ hitCo, ray_start, proj_ray, hit.dist); /* Calculate final hit coordinates */
+ tri = hit.index;
+ }
+ }
+
+ /* If a hit was found, calculate required values */
+ if (proxDist >= 0.0f && proxDist <= brush_radius) {
+ proximity_factor = proxDist / brush_radius;
+ CLAMP(proximity_factor, 0.0f, 1.0f);
+ if (!inner_proximity)
+ proximity_factor = 1.0f - proximity_factor;
+
+ hit_found = HIT_PROXIMITY;
+
+ /* if no volume hit, use prox point face info */
+ if (hitTri == -1) {
+ copy_v3_v3(hitCoord, hitCo);
+ hitTri = tri;
+ }
+ }
+ }
+
+ /* mix final sample strength depending on brush settings */
+ if (hit_found) {
+ /* if "negate volume" enabled, negate all factors within volume*/
+ if (brush->collision == MOD_DPAINT_COL_VOLDIST && brush->flags & MOD_DPAINT_NEGATE_VOLUME) {
+ volume_factor = 1.0f - volume_factor;
+ if (inner_proximity)
+ proximity_factor = 1.0f - proximity_factor;
+ }
+
+ /* apply final sample depending on final hit type */
+ if (hit_found == HIT_VOLUME) {
+ sampleStrength = volume_factor;
+ }
+ else if (hit_found == HIT_PROXIMITY) {
+ /* apply falloff curve to the proximity_factor */
+ if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP &&
+ BKE_colorband_evaluate(brush->paint_ramp, (1.0f - proximity_factor), prox_colorband)) {
+ proximity_factor = prox_colorband[3];
+ }
+ else if (brush->proximity_falloff == MOD_DPAINT_PRFALL_CONSTANT) {
+ proximity_factor = (!inner_proximity || brush->flags & MOD_DPAINT_NEGATE_VOLUME) ? 1.0f :
+ 0.0f;
+ }
+ /* apply sample */
+ sampleStrength = proximity_factor;
+ }
+
+ sampleStrength *= sample_factor;
+ }
+ else {
+ continue;
+ }
+
+ /* velocity brush, only do on main sample */
+ if (brush->flags & MOD_DPAINT_USES_VELOCITY && ss == 0 && brushVelocity) {
+ float weights[3];
+ float brushPointVelocity[3];
+ float velocity[3];
+
+ const int v1 = mloop[mlooptri[hitTri].tri[0]].v;
+ const int v2 = mloop[mlooptri[hitTri].tri[1]].v;
+ const int v3 = mloop[mlooptri[hitTri].tri[2]].v;
+
+ /* calculate barycentric weights for hit point */
+ interp_weights_tri_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, hitCoord);
+
+ /* simple check based on brush surface velocity,
+ * todo: perhaps implement something that handles volume movement as well. */
+
+ /* interpolate vertex speed vectors to get hit point velocity */
+ interp_v3_v3v3v3(brushPointVelocity,
+ brushVelocity[v1].v,
+ brushVelocity[v2].v,
+ brushVelocity[v3].v,
+ weights);
+
+ /* substract canvas point velocity */
+ if (bData->velocity) {
+ sub_v3_v3v3(velocity, brushPointVelocity, bData->velocity[index].v);
+ }
+ else {
+ copy_v3_v3(velocity, brushPointVelocity);
+ }
+ velocity_val = normalize_v3(velocity);
+
+ /* if brush has smudge enabled store brush velocity */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT && brush->flags & MOD_DPAINT_DO_SMUDGE &&
+ bData->brush_velocity) {
+ copy_v3_v3(&bData->brush_velocity[index * 4], velocity);
+ bData->brush_velocity[index * 4 + 3] = velocity_val;
+ }
+ }
+
+ /*
+ * Process hit color and alpha
+ */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ float sampleColor[3];
+ float alpha_factor = 1.0f;
+
+ sampleColor[0] = brush->r;
+ sampleColor[1] = brush->g;
+ sampleColor[2] = brush->b;
+
+ /* Sample proximity colorband if required */
+ if ((hit_found == HIT_PROXIMITY) && (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP)) {
+ if (!(brush->flags & MOD_DPAINT_RAMP_ALPHA)) {
+ sampleColor[0] = prox_colorband[0];
+ sampleColor[1] = prox_colorband[1];
+ sampleColor[2] = prox_colorband[2];
+ }
+ }
+
+ /* Add AA sample */
+ paintColor[0] += sampleColor[0];
+ paintColor[1] += sampleColor[1];
+ paintColor[2] += sampleColor[2];
+ sampleStrength *= alpha_factor;
+ numOfHits++;
+ }
+
+ /* apply sample strength */
+ brushStrength += sampleStrength;
+ } // end supersampling
+
+ /* if any sample was inside paint range */
+ if (brushStrength > 0.0f || depth > 0.0f) {
+ /* apply supersampling results */
+ if (samples > 1) {
+ brushStrength /= total_sample;
+ }
+ CLAMP(brushStrength, 0.0f, 1.0f);
+
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ /* Get final pixel color and alpha */
+ paintColor[0] /= numOfHits;
+ paintColor[1] /= numOfHits;
+ paintColor[2] /= numOfHits;
+ }
+ /* get final object space depth */
+ else if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
+ depth /= bData->bNormal[index].normal_scale * total_sample;
+ }
+
+ dynamicPaint_updatePointData(
+ surface, index, brush, paintColor, brushStrength, depth, velocity_val, timescale);
+ }
}
-static int dynamicPaint_paintMesh(Depsgraph *depsgraph, DynamicPaintSurface *surface,
+static int dynamicPaint_paintMesh(Depsgraph *depsgraph,
+ DynamicPaintSurface *surface,
DynamicPaintBrushSettings *brush,
Object *brushOb,
Scene *scene,
float timescale)
{
- PaintSurfaceData *sData = surface->data;
- PaintBakeData *bData = sData->bData;
- Mesh *mesh = NULL;
- Vec3f *brushVelocity = NULL;
- MVert *mvert = NULL;
- const MLoopTri *mlooptri = NULL;
- const MLoop *mloop = NULL;
-
- if (brush->flags & MOD_DPAINT_USES_VELOCITY)
- dynamicPaint_brushMeshCalculateVelocity(depsgraph, scene, brushOb, brush, &brushVelocity, timescale);
-
- Mesh *brush_mesh = dynamicPaint_brush_mesh_get(brush);
- if (brush_mesh == NULL) {
- return 0;
- }
-
- {
- BVHTreeFromMesh treeData = {NULL};
- float avg_brushNor[3] = {0.0f};
- const float brush_radius = brush->paint_distance * surface->radius_scale;
- int numOfVerts;
- int ii;
- Bounds3D mesh_bb = {{0}};
- VolumeGrid *grid = bData->grid;
-
- mesh = BKE_mesh_copy_for_eval(brush_mesh, false);
- mvert = mesh->mvert;
- mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
- mloop = mesh->mloop;
- numOfVerts = mesh->totvert;
-
- /* Transform collider vertices to global space
- * (Faster than transforming per surface point
- * coordinates and normals to object space) */
- for (ii = 0; ii < numOfVerts; ii++) {
- mul_m4_v3(brushOb->obmat, mvert[ii].co);
- boundInsert(&mesh_bb, mvert[ii].co);
-
- /* for proximity project calculate average normal */
- if (brush->flags & MOD_DPAINT_PROX_PROJECT && brush->collision != MOD_DPAINT_COL_VOLUME) {
- float nor[3];
- normal_short_to_float_v3(nor, mvert[ii].no);
- mul_mat3_m4_v3(brushOb->obmat, nor);
- normalize_v3(nor);
-
- add_v3_v3(avg_brushNor, nor);
- }
- }
-
- if (brush->flags & MOD_DPAINT_PROX_PROJECT && brush->collision != MOD_DPAINT_COL_VOLUME) {
- mul_v3_fl(avg_brushNor, 1.0f / (float)numOfVerts);
- /* instead of null vector use positive z */
- if (UNLIKELY(normalize_v3(avg_brushNor) == 0.0f)) {
- avg_brushNor[2] = 1.0f;
- }
- }
-
- /* check bounding box collision */
- if (grid && meshBrush_boundsIntersect(&grid->grid_bounds, &mesh_bb, brush, brush_radius)) {
- /* Build a bvh tree from transformed vertices */
- if (BKE_bvhtree_from_mesh_get(&treeData, mesh, BVHTREE_FROM_LOOPTRI, 4)) {
- int c_index;
- int total_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
-
- /* loop through space partitioning grid */
- for (c_index = 0; c_index < total_cells; c_index++) {
- /* check grid cell bounding box */
- if (!grid->s_num[c_index] ||
- !meshBrush_boundsIntersect(&grid->bounds[c_index], &mesh_bb, brush, brush_radius))
- {
- continue;
- }
-
- /* loop through cell points and process brush */
- DynamicPaintPaintData data = {
- .surface = surface,
- .brush = brush, .brushOb = brushOb,
- .scene = scene, .timescale = timescale, .c_index = c_index,
- .mesh = mesh, .mvert = mvert, .mloop = mloop, .mlooptri = mlooptri,
- .brush_radius = brush_radius, .avg_brushNor = avg_brushNor, .brushVelocity = brushVelocity,
- .treeData = &treeData,
- };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (grid->s_num[c_index] > 250);
- BLI_task_parallel_range(0, grid->s_num[c_index],
- &data,
- dynamic_paint_paint_mesh_cell_point_cb_ex,
- &settings);
- }
- }
- }
- /* free bvh tree */
- free_bvhtree_from_mesh(&treeData);
- BKE_id_free(NULL, mesh);
-
- }
-
- /* free brush velocity data */
- if (brushVelocity)
- MEM_freeN(brushVelocity);
-
- return 1;
+ PaintSurfaceData *sData = surface->data;
+ PaintBakeData *bData = sData->bData;
+ Mesh *mesh = NULL;
+ Vec3f *brushVelocity = NULL;
+ MVert *mvert = NULL;
+ const MLoopTri *mlooptri = NULL;
+ const MLoop *mloop = NULL;
+
+ if (brush->flags & MOD_DPAINT_USES_VELOCITY)
+ dynamicPaint_brushMeshCalculateVelocity(
+ depsgraph, scene, brushOb, brush, &brushVelocity, timescale);
+
+ Mesh *brush_mesh = dynamicPaint_brush_mesh_get(brush);
+ if (brush_mesh == NULL) {
+ return 0;
+ }
+
+ {
+ BVHTreeFromMesh treeData = {NULL};
+ float avg_brushNor[3] = {0.0f};
+ const float brush_radius = brush->paint_distance * surface->radius_scale;
+ int numOfVerts;
+ int ii;
+ Bounds3D mesh_bb = {{0}};
+ VolumeGrid *grid = bData->grid;
+
+ mesh = BKE_mesh_copy_for_eval(brush_mesh, false);
+ mvert = mesh->mvert;
+ mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ mloop = mesh->mloop;
+ numOfVerts = mesh->totvert;
+
+ /* Transform collider vertices to global space
+ * (Faster than transforming per surface point
+ * coordinates and normals to object space) */
+ for (ii = 0; ii < numOfVerts; ii++) {
+ mul_m4_v3(brushOb->obmat, mvert[ii].co);
+ boundInsert(&mesh_bb, mvert[ii].co);
+
+ /* for proximity project calculate average normal */
+ if (brush->flags & MOD_DPAINT_PROX_PROJECT && brush->collision != MOD_DPAINT_COL_VOLUME) {
+ float nor[3];
+ normal_short_to_float_v3(nor, mvert[ii].no);
+ mul_mat3_m4_v3(brushOb->obmat, nor);
+ normalize_v3(nor);
+
+ add_v3_v3(avg_brushNor, nor);
+ }
+ }
+
+ if (brush->flags & MOD_DPAINT_PROX_PROJECT && brush->collision != MOD_DPAINT_COL_VOLUME) {
+ mul_v3_fl(avg_brushNor, 1.0f / (float)numOfVerts);
+ /* instead of null vector use positive z */
+ if (UNLIKELY(normalize_v3(avg_brushNor) == 0.0f)) {
+ avg_brushNor[2] = 1.0f;
+ }
+ }
+
+ /* check bounding box collision */
+ if (grid && meshBrush_boundsIntersect(&grid->grid_bounds, &mesh_bb, brush, brush_radius)) {
+ /* Build a bvh tree from transformed vertices */
+ if (BKE_bvhtree_from_mesh_get(&treeData, mesh, BVHTREE_FROM_LOOPTRI, 4)) {
+ int c_index;
+ int total_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
+
+ /* loop through space partitioning grid */
+ for (c_index = 0; c_index < total_cells; c_index++) {
+ /* check grid cell bounding box */
+ if (!grid->s_num[c_index] ||
+ !meshBrush_boundsIntersect(&grid->bounds[c_index], &mesh_bb, brush, brush_radius)) {
+ continue;
+ }
+
+ /* loop through cell points and process brush */
+ DynamicPaintPaintData data = {
+ .surface = surface,
+ .brush = brush,
+ .brushOb = brushOb,
+ .scene = scene,
+ .timescale = timescale,
+ .c_index = c_index,
+ .mesh = mesh,
+ .mvert = mvert,
+ .mloop = mloop,
+ .mlooptri = mlooptri,
+ .brush_radius = brush_radius,
+ .avg_brushNor = avg_brushNor,
+ .brushVelocity = brushVelocity,
+ .treeData = &treeData,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (grid->s_num[c_index] > 250);
+ BLI_task_parallel_range(0,
+ grid->s_num[c_index],
+ &data,
+ dynamic_paint_paint_mesh_cell_point_cb_ex,
+ &settings);
+ }
+ }
+ }
+ /* free bvh tree */
+ free_bvhtree_from_mesh(&treeData);
+ BKE_id_free(NULL, mesh);
+ }
+
+ /* free brush velocity data */
+ if (brushVelocity)
+ MEM_freeN(brushVelocity);
+
+ return 1;
}
/*
* Paint a particle system to the surface
*/
static void dynamic_paint_paint_particle_cell_point_cb_ex(
- void *__restrict userdata,
- const int id,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+ void *__restrict userdata, const int id, const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintPaintData *data = userdata;
-
- const DynamicPaintSurface *surface = data->surface;
- const PaintSurfaceData *sData = surface->data;
- const PaintBakeData *bData = sData->bData;
- VolumeGrid *grid = bData->grid;
-
- const DynamicPaintBrushSettings *brush = data->brush;
-
- const ParticleSystem *psys = data->psys;
-
- const float timescale = data->timescale;
- const int c_index = data->c_index;
-
- KDTree_3d *tree = data->treeData;
-
- const float solidradius = data->solidradius;
- const float smooth = brush->particle_smooth * surface->radius_scale;
- const float range = solidradius + smooth;
- const float particle_timestep = 0.04f * psys->part->timetweak;
-
- const int index = grid->t_index[grid->s_pos[c_index] + id];
- float disp_intersect = 0.0f;
- float radius = 0.0f;
- float strength = 0.0f;
- int part_index = -1;
-
- /*
- * With predefined radius, there is no variation between particles.
- * It's enough to just find the nearest one.
- */
- {
- KDTreeNearest_3d nearest;
- float smooth_range, part_solidradius;
-
- /* Find nearest particle and get distance to it */
- BLI_kdtree_3d_find_nearest(tree, bData->realCoord[bData->s_pos[index]].v, &nearest);
- /* if outside maximum range, no other particle can influence either */
- if (nearest.dist > range)
- return;
-
- if (brush->flags & MOD_DPAINT_PART_RAD) {
- /* use particles individual size */
- ParticleData *pa = psys->particles + nearest.index;
- part_solidradius = pa->size;
- }
- else {
- part_solidradius = solidradius;
- }
- radius = part_solidradius + smooth;
- if (nearest.dist < radius) {
- /* distances inside solid radius has maximum influence -> dist = 0 */
- smooth_range = max_ff(0.0f, (nearest.dist - part_solidradius));
- /* do smoothness if enabled */
- if (smooth)
- smooth_range /= smooth;
-
- strength = 1.0f - smooth_range;
- disp_intersect = radius - nearest.dist;
- part_index = nearest.index;
- }
- }
- /* If using random per particle radius and closest particle didn't give max influence */
- if (brush->flags & MOD_DPAINT_PART_RAD && strength < 1.0f && psys->part->randsize > 0.0f) {
- /*
- * If we use per particle radius, we have to sample all particles
- * within max radius range
- */
- KDTreeNearest_3d *nearest;
-
- float smooth_range = smooth * (1.0f - strength), dist;
- /* calculate max range that can have particles with higher influence than the nearest one */
- const float max_range = smooth - strength * smooth + solidradius;
- /* Make gcc happy! */
- dist = max_range;
-
- const int particles = BLI_kdtree_3d_range_search(
- tree, bData->realCoord[bData->s_pos[index]].v, &nearest, max_range);
-
- /* Find particle that produces highest influence */
- for (int n = 0; n < particles; n++) {
- ParticleData *pa = &psys->particles[nearest[n].index];
-
- /* skip if out of range */
- if (nearest[n].dist > (pa->size + smooth))
- continue;
-
- /* update hit data */
- const float s_range = nearest[n].dist - pa->size;
- /* skip if higher influence is already found */
- if (smooth_range < s_range)
- continue;
-
- /* update hit data */
- smooth_range = s_range;
- dist = nearest[n].dist;
- part_index = nearest[n].index;
-
- /* If inside solid range and no disp depth required, no need to seek further */
- if ((s_range < 0.0f) && !ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
- break;
- }
- }
-
- if (nearest)
- MEM_freeN(nearest);
-
- /* now calculate influence for this particle */
- const float rad = radius + smooth;
- if ((rad - dist) > disp_intersect) {
- disp_intersect = radius - dist;
- radius = rad;
- }
-
- /* do smoothness if enabled */
- CLAMP_MIN(smooth_range, 0.0f);
- if (smooth)
- smooth_range /= smooth;
-
- const float str = 1.0f - smooth_range;
- /* if influence is greater, use this one */
- if (str > strength)
- strength = str;
- }
-
- if (strength > 0.001f) {
- float paintColor[4] = {0.0f};
- float depth = 0.0f;
- float velocity_val = 0.0f;
-
- /* apply velocity */
- if ((brush->flags & MOD_DPAINT_USES_VELOCITY) && (part_index != -1)) {
- float velocity[3];
- ParticleData *pa = psys->particles + part_index;
- mul_v3_v3fl(velocity, pa->state.vel, particle_timestep);
-
- /* substract canvas point velocity */
- if (bData->velocity) {
- sub_v3_v3(velocity, bData->velocity[index].v);
- }
- velocity_val = normalize_v3(velocity);
-
- /* store brush velocity for smudge */
- if ((surface->type == MOD_DPAINT_SURFACE_T_PAINT) &&
- (brush->flags & MOD_DPAINT_DO_SMUDGE && bData->brush_velocity))
- {
- copy_v3_v3(&bData->brush_velocity[index * 4], velocity);
- bData->brush_velocity[index * 4 + 3] = velocity_val;
- }
- }
-
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- copy_v3_v3(paintColor, &brush->r);
- }
- else if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
- /* get displace depth */
- disp_intersect = (1.0f - sqrtf(disp_intersect / radius)) * radius;
- depth = max_ff(0.0f, (radius - disp_intersect) / bData->bNormal[index].normal_scale);
- }
-
- dynamicPaint_updatePointData(surface, index, brush, paintColor, strength, depth, velocity_val, timescale);
- }
+ const DynamicPaintPaintData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ const PaintBakeData *bData = sData->bData;
+ VolumeGrid *grid = bData->grid;
+
+ const DynamicPaintBrushSettings *brush = data->brush;
+
+ const ParticleSystem *psys = data->psys;
+
+ const float timescale = data->timescale;
+ const int c_index = data->c_index;
+
+ KDTree_3d *tree = data->treeData;
+
+ const float solidradius = data->solidradius;
+ const float smooth = brush->particle_smooth * surface->radius_scale;
+ const float range = solidradius + smooth;
+ const float particle_timestep = 0.04f * psys->part->timetweak;
+
+ const int index = grid->t_index[grid->s_pos[c_index] + id];
+ float disp_intersect = 0.0f;
+ float radius = 0.0f;
+ float strength = 0.0f;
+ int part_index = -1;
+
+ /*
+ * With predefined radius, there is no variation between particles.
+ * It's enough to just find the nearest one.
+ */
+ {
+ KDTreeNearest_3d nearest;
+ float smooth_range, part_solidradius;
+
+ /* Find nearest particle and get distance to it */
+ BLI_kdtree_3d_find_nearest(tree, bData->realCoord[bData->s_pos[index]].v, &nearest);
+ /* if outside maximum range, no other particle can influence either */
+ if (nearest.dist > range)
+ return;
+
+ if (brush->flags & MOD_DPAINT_PART_RAD) {
+ /* use particles individual size */
+ ParticleData *pa = psys->particles + nearest.index;
+ part_solidradius = pa->size;
+ }
+ else {
+ part_solidradius = solidradius;
+ }
+ radius = part_solidradius + smooth;
+ if (nearest.dist < radius) {
+ /* distances inside solid radius has maximum influence -> dist = 0 */
+ smooth_range = max_ff(0.0f, (nearest.dist - part_solidradius));
+ /* do smoothness if enabled */
+ if (smooth)
+ smooth_range /= smooth;
+
+ strength = 1.0f - smooth_range;
+ disp_intersect = radius - nearest.dist;
+ part_index = nearest.index;
+ }
+ }
+ /* If using random per particle radius and closest particle didn't give max influence */
+ if (brush->flags & MOD_DPAINT_PART_RAD && strength < 1.0f && psys->part->randsize > 0.0f) {
+ /*
+ * If we use per particle radius, we have to sample all particles
+ * within max radius range
+ */
+ KDTreeNearest_3d *nearest;
+
+ float smooth_range = smooth * (1.0f - strength), dist;
+ /* calculate max range that can have particles with higher influence than the nearest one */
+ const float max_range = smooth - strength * smooth + solidradius;
+ /* Make gcc happy! */
+ dist = max_range;
+
+ const int particles = BLI_kdtree_3d_range_search(
+ tree, bData->realCoord[bData->s_pos[index]].v, &nearest, max_range);
+
+ /* Find particle that produces highest influence */
+ for (int n = 0; n < particles; n++) {
+ ParticleData *pa = &psys->particles[nearest[n].index];
+
+ /* skip if out of range */
+ if (nearest[n].dist > (pa->size + smooth))
+ continue;
+
+ /* update hit data */
+ const float s_range = nearest[n].dist - pa->size;
+ /* skip if higher influence is already found */
+ if (smooth_range < s_range)
+ continue;
+
+ /* update hit data */
+ smooth_range = s_range;
+ dist = nearest[n].dist;
+ part_index = nearest[n].index;
+
+ /* If inside solid range and no disp depth required, no need to seek further */
+ if ((s_range < 0.0f) &&
+ !ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
+ break;
+ }
+ }
+
+ if (nearest)
+ MEM_freeN(nearest);
+
+ /* now calculate influence for this particle */
+ const float rad = radius + smooth;
+ if ((rad - dist) > disp_intersect) {
+ disp_intersect = radius - dist;
+ radius = rad;
+ }
+
+ /* do smoothness if enabled */
+ CLAMP_MIN(smooth_range, 0.0f);
+ if (smooth)
+ smooth_range /= smooth;
+
+ const float str = 1.0f - smooth_range;
+ /* if influence is greater, use this one */
+ if (str > strength)
+ strength = str;
+ }
+
+ if (strength > 0.001f) {
+ float paintColor[4] = {0.0f};
+ float depth = 0.0f;
+ float velocity_val = 0.0f;
+
+ /* apply velocity */
+ if ((brush->flags & MOD_DPAINT_USES_VELOCITY) && (part_index != -1)) {
+ float velocity[3];
+ ParticleData *pa = psys->particles + part_index;
+ mul_v3_v3fl(velocity, pa->state.vel, particle_timestep);
+
+ /* substract canvas point velocity */
+ if (bData->velocity) {
+ sub_v3_v3(velocity, bData->velocity[index].v);
+ }
+ velocity_val = normalize_v3(velocity);
+
+ /* store brush velocity for smudge */
+ if ((surface->type == MOD_DPAINT_SURFACE_T_PAINT) &&
+ (brush->flags & MOD_DPAINT_DO_SMUDGE && bData->brush_velocity)) {
+ copy_v3_v3(&bData->brush_velocity[index * 4], velocity);
+ bData->brush_velocity[index * 4 + 3] = velocity_val;
+ }
+ }
+
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ copy_v3_v3(paintColor, &brush->r);
+ }
+ else if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
+ /* get displace depth */
+ disp_intersect = (1.0f - sqrtf(disp_intersect / radius)) * radius;
+ depth = max_ff(0.0f, (radius - disp_intersect) / bData->bNormal[index].normal_scale);
+ }
+
+ dynamicPaint_updatePointData(
+ surface, index, brush, paintColor, strength, depth, velocity_val, timescale);
+ }
}
static int dynamicPaint_paintParticles(DynamicPaintSurface *surface,
@@ -4429,1678 +4502,1767 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface,
DynamicPaintBrushSettings *brush,
float timescale)
{
- ParticleSettings *part = psys->part;
- PaintSurfaceData *sData = surface->data;
- PaintBakeData *bData = sData->bData;
- VolumeGrid *grid = bData->grid;
-
- KDTree_3d *tree;
- int particlesAdded = 0;
- int invalidParticles = 0;
- int p = 0;
-
- const float solidradius = surface->radius_scale *
- ((brush->flags & MOD_DPAINT_PART_RAD) ? part->size : brush->particle_radius);
- const float smooth = brush->particle_smooth * surface->radius_scale;
-
- const float range = solidradius + smooth;
-
- Bounds3D part_bb = {{0}};
-
- if (psys->totpart < 1)
- return 1;
-
- /*
- * Build a kd-tree to optimize distance search
- */
- tree = BLI_kdtree_3d_new(psys->totpart);
-
- /* loop through particles and insert valid ones to the tree */
- p = 0;
- for (ParticleData *pa = psys->particles; p < psys->totpart; p++, pa++) {
- /* Proceed only if particle is active */
- if ((pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN) == 0) ||
- (pa->alive == PARS_DEAD && (part->flag & PART_DIED) == 0) ||
- (pa->flag & PARS_UNEXIST))
- {
- continue;
- }
-
- /* for debug purposes check if any NAN particle proceeds
- * For some reason they get past activity check, this should rule most of them out */
- if (isnan(pa->state.co[0]) || isnan(pa->state.co[1]) || isnan(pa->state.co[2])) {
- invalidParticles++;
- continue;
- }
-
- /* make sure particle is close enough to canvas */
- if (!boundIntersectPoint(&grid->grid_bounds, pa->state.co, range))
- continue;
-
- BLI_kdtree_3d_insert(tree, p, pa->state.co);
-
- /* calc particle system bounds */
- boundInsert(&part_bb, pa->state.co);
-
- particlesAdded++;
- }
- if (invalidParticles)
- CLOG_WARN(&LOG, "Invalid particle(s) found!");
-
- /* If no suitable particles were found, exit */
- if (particlesAdded < 1) {
- BLI_kdtree_3d_free(tree);
- return 1;
- }
-
- /* begin thread safe malloc */
- BLI_threaded_malloc_begin();
-
- /* only continue if particle bb is close enough to canvas bb */
- if (boundsIntersectDist(&grid->grid_bounds, &part_bb, range)) {
- int c_index;
- int total_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
-
- /* balance tree */
- BLI_kdtree_3d_balance(tree);
-
- /* loop through space partitioning grid */
- for (c_index = 0; c_index < total_cells; c_index++) {
- /* check cell bounding box */
- if (!grid->s_num[c_index] ||
- !boundsIntersectDist(&grid->bounds[c_index], &part_bb, range))
- {
- continue;
- }
-
- /* loop through cell points */
- DynamicPaintPaintData data = {
- .surface = surface,
- .brush = brush, .psys = psys,
- .solidradius = solidradius, .timescale = timescale, .c_index = c_index,
- .treeData = tree,
- };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (grid->s_num[c_index] > 250);
- BLI_task_parallel_range(0, grid->s_num[c_index],
- &data,
- dynamic_paint_paint_particle_cell_point_cb_ex,
- &settings);
- }
- }
- BLI_threaded_malloc_end();
- BLI_kdtree_3d_free(tree);
-
- return 1;
+ ParticleSettings *part = psys->part;
+ PaintSurfaceData *sData = surface->data;
+ PaintBakeData *bData = sData->bData;
+ VolumeGrid *grid = bData->grid;
+
+ KDTree_3d *tree;
+ int particlesAdded = 0;
+ int invalidParticles = 0;
+ int p = 0;
+
+ const float solidradius = surface->radius_scale * ((brush->flags & MOD_DPAINT_PART_RAD) ?
+ part->size :
+ brush->particle_radius);
+ const float smooth = brush->particle_smooth * surface->radius_scale;
+
+ const float range = solidradius + smooth;
+
+ Bounds3D part_bb = {{0}};
+
+ if (psys->totpart < 1)
+ return 1;
+
+ /*
+ * Build a kd-tree to optimize distance search
+ */
+ tree = BLI_kdtree_3d_new(psys->totpart);
+
+ /* loop through particles and insert valid ones to the tree */
+ p = 0;
+ for (ParticleData *pa = psys->particles; p < psys->totpart; p++, pa++) {
+ /* Proceed only if particle is active */
+ if ((pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN) == 0) ||
+ (pa->alive == PARS_DEAD && (part->flag & PART_DIED) == 0) || (pa->flag & PARS_UNEXIST)) {
+ continue;
+ }
+
+ /* for debug purposes check if any NAN particle proceeds
+ * For some reason they get past activity check, this should rule most of them out */
+ if (isnan(pa->state.co[0]) || isnan(pa->state.co[1]) || isnan(pa->state.co[2])) {
+ invalidParticles++;
+ continue;
+ }
+
+ /* make sure particle is close enough to canvas */
+ if (!boundIntersectPoint(&grid->grid_bounds, pa->state.co, range))
+ continue;
+
+ BLI_kdtree_3d_insert(tree, p, pa->state.co);
+
+ /* calc particle system bounds */
+ boundInsert(&part_bb, pa->state.co);
+
+ particlesAdded++;
+ }
+ if (invalidParticles)
+ CLOG_WARN(&LOG, "Invalid particle(s) found!");
+
+ /* If no suitable particles were found, exit */
+ if (particlesAdded < 1) {
+ BLI_kdtree_3d_free(tree);
+ return 1;
+ }
+
+ /* begin thread safe malloc */
+ BLI_threaded_malloc_begin();
+
+ /* only continue if particle bb is close enough to canvas bb */
+ if (boundsIntersectDist(&grid->grid_bounds, &part_bb, range)) {
+ int c_index;
+ int total_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
+
+ /* balance tree */
+ BLI_kdtree_3d_balance(tree);
+
+ /* loop through space partitioning grid */
+ for (c_index = 0; c_index < total_cells; c_index++) {
+ /* check cell bounding box */
+ if (!grid->s_num[c_index] || !boundsIntersectDist(&grid->bounds[c_index], &part_bb, range)) {
+ continue;
+ }
+
+ /* loop through cell points */
+ DynamicPaintPaintData data = {
+ .surface = surface,
+ .brush = brush,
+ .psys = psys,
+ .solidradius = solidradius,
+ .timescale = timescale,
+ .c_index = c_index,
+ .treeData = tree,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (grid->s_num[c_index] > 250);
+ BLI_task_parallel_range(0,
+ grid->s_num[c_index],
+ &data,
+ dynamic_paint_paint_particle_cell_point_cb_ex,
+ &settings);
+ }
+ }
+ BLI_threaded_malloc_end();
+ BLI_kdtree_3d_free(tree);
+
+ return 1;
}
/* paint a single point of defined proximity radius to the surface */
-static void dynamic_paint_paint_single_point_cb_ex(
- void *__restrict userdata,
- const int index,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void dynamic_paint_paint_single_point_cb_ex(void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintPaintData *data = userdata;
-
- const DynamicPaintSurface *surface = data->surface;
- const PaintSurfaceData *sData = surface->data;
- const PaintBakeData *bData = sData->bData;
-
- const DynamicPaintBrushSettings *brush = data->brush;
-
- const float timescale = data->timescale;
-
- const float brush_radius = data->brush_radius;
- const Vec3f *brushVelocity = data->brushVelocity;
-
- float *pointCoord = data->pointCoord;
-
- const float distance = len_v3v3(pointCoord, bData->realCoord[bData->s_pos[index]].v);
- float colorband[4] = {0.0f};
- float strength;
-
- if (distance > brush_radius)
- return;
-
- /* Smooth range or color ramp */
- if (brush->proximity_falloff == MOD_DPAINT_PRFALL_SMOOTH ||
- brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP)
- {
- strength = 1.0f - distance / brush_radius;
- CLAMP(strength, 0.0f, 1.0f);
- }
- else {
- strength = 1.0f;
- }
-
- if (strength >= 0.001f) {
- float paintColor[3] = {0.0f};
- float depth = 0.0f;
- float velocity_val = 0.0f;
-
- /* color ramp */
- if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP &&
- BKE_colorband_evaluate(brush->paint_ramp, (1.0f - strength), colorband))
- {
- strength = colorband[3];
- }
-
- if (brush->flags & MOD_DPAINT_USES_VELOCITY) {
- float velocity[3];
-
- /* substract canvas point velocity */
- if (bData->velocity) {
- sub_v3_v3v3(velocity, brushVelocity->v, bData->velocity[index].v);
- }
- else {
- copy_v3_v3(velocity, brushVelocity->v);
- }
- velocity_val = len_v3(velocity);
-
- /* store brush velocity for smudge */
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT &&
- brush->flags & MOD_DPAINT_DO_SMUDGE && bData->brush_velocity)
- {
- mul_v3_v3fl(&bData->brush_velocity[index * 4], velocity, 1.0f / velocity_val);
- bData->brush_velocity[index * 4 + 3] = velocity_val;
- }
- }
-
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP &&
- !(brush->flags & MOD_DPAINT_RAMP_ALPHA))
- {
- paintColor[0] = colorband[0];
- paintColor[1] = colorband[1];
- paintColor[2] = colorband[2];
- }
- else {
- paintColor[0] = brush->r;
- paintColor[1] = brush->g;
- paintColor[2] = brush->b;
- }
- }
- else if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
- /* get displace depth */
- const float disp_intersect = (1.0f - sqrtf((brush_radius - distance) / brush_radius)) * brush_radius;
- depth = max_ff(0.0f, (brush_radius - disp_intersect) / bData->bNormal[index].normal_scale);
- }
- dynamicPaint_updatePointData(surface, index, brush, paintColor, strength, depth, velocity_val, timescale);
- }
+ const DynamicPaintPaintData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ const PaintBakeData *bData = sData->bData;
+
+ const DynamicPaintBrushSettings *brush = data->brush;
+
+ const float timescale = data->timescale;
+
+ const float brush_radius = data->brush_radius;
+ const Vec3f *brushVelocity = data->brushVelocity;
+
+ float *pointCoord = data->pointCoord;
+
+ const float distance = len_v3v3(pointCoord, bData->realCoord[bData->s_pos[index]].v);
+ float colorband[4] = {0.0f};
+ float strength;
+
+ if (distance > brush_radius)
+ return;
+
+ /* Smooth range or color ramp */
+ if (brush->proximity_falloff == MOD_DPAINT_PRFALL_SMOOTH ||
+ brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP) {
+ strength = 1.0f - distance / brush_radius;
+ CLAMP(strength, 0.0f, 1.0f);
+ }
+ else {
+ strength = 1.0f;
+ }
+
+ if (strength >= 0.001f) {
+ float paintColor[3] = {0.0f};
+ float depth = 0.0f;
+ float velocity_val = 0.0f;
+
+ /* color ramp */
+ if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP &&
+ BKE_colorband_evaluate(brush->paint_ramp, (1.0f - strength), colorband)) {
+ strength = colorband[3];
+ }
+
+ if (brush->flags & MOD_DPAINT_USES_VELOCITY) {
+ float velocity[3];
+
+ /* substract canvas point velocity */
+ if (bData->velocity) {
+ sub_v3_v3v3(velocity, brushVelocity->v, bData->velocity[index].v);
+ }
+ else {
+ copy_v3_v3(velocity, brushVelocity->v);
+ }
+ velocity_val = len_v3(velocity);
+
+ /* store brush velocity for smudge */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT && brush->flags & MOD_DPAINT_DO_SMUDGE &&
+ bData->brush_velocity) {
+ mul_v3_v3fl(&bData->brush_velocity[index * 4], velocity, 1.0f / velocity_val);
+ bData->brush_velocity[index * 4 + 3] = velocity_val;
+ }
+ }
+
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP &&
+ !(brush->flags & MOD_DPAINT_RAMP_ALPHA)) {
+ paintColor[0] = colorband[0];
+ paintColor[1] = colorband[1];
+ paintColor[2] = colorband[2];
+ }
+ else {
+ paintColor[0] = brush->r;
+ paintColor[1] = brush->g;
+ paintColor[2] = brush->b;
+ }
+ }
+ else if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
+ /* get displace depth */
+ const float disp_intersect = (1.0f - sqrtf((brush_radius - distance) / brush_radius)) *
+ brush_radius;
+ depth = max_ff(0.0f, (brush_radius - disp_intersect) / bData->bNormal[index].normal_scale);
+ }
+ dynamicPaint_updatePointData(
+ surface, index, brush, paintColor, strength, depth, velocity_val, timescale);
+ }
}
-static int dynamicPaint_paintSinglePoint(
- Depsgraph *depsgraph, DynamicPaintSurface *surface, float *pointCoord, DynamicPaintBrushSettings *brush,
- Object *brushOb, Scene *scene, float timescale)
+static int dynamicPaint_paintSinglePoint(Depsgraph *depsgraph,
+ DynamicPaintSurface *surface,
+ float *pointCoord,
+ DynamicPaintBrushSettings *brush,
+ Object *brushOb,
+ Scene *scene,
+ float timescale)
{
- PaintSurfaceData *sData = surface->data;
- float brush_radius = brush->paint_distance * surface->radius_scale;
- Vec3f brushVel;
-
- if (brush->flags & MOD_DPAINT_USES_VELOCITY)
- dynamicPaint_brushObjectCalculateVelocity(depsgraph, scene, brushOb, &brushVel, timescale);
-
- const Mesh *brush_mesh = dynamicPaint_brush_mesh_get(brush);
- const MVert *mvert = brush_mesh->mvert;
-
- /*
- * Loop through every surface point
- */
- DynamicPaintPaintData data = {
- .surface = surface,
- .brush = brush, .brushOb = brushOb,
- .scene = scene, .timescale = timescale,
- .mvert = mvert,
- .brush_radius = brush_radius, .brushVelocity = &brushVel,
- .pointCoord = pointCoord,
- };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 1000);
- BLI_task_parallel_range(0, sData->total_points,
- &data,
- dynamic_paint_paint_single_point_cb_ex,
- &settings);
-
- return 1;
+ PaintSurfaceData *sData = surface->data;
+ float brush_radius = brush->paint_distance * surface->radius_scale;
+ Vec3f brushVel;
+
+ if (brush->flags & MOD_DPAINT_USES_VELOCITY)
+ dynamicPaint_brushObjectCalculateVelocity(depsgraph, scene, brushOb, &brushVel, timescale);
+
+ const Mesh *brush_mesh = dynamicPaint_brush_mesh_get(brush);
+ const MVert *mvert = brush_mesh->mvert;
+
+ /*
+ * Loop through every surface point
+ */
+ DynamicPaintPaintData data = {
+ .surface = surface,
+ .brush = brush,
+ .brushOb = brushOb,
+ .scene = scene,
+ .timescale = timescale,
+ .mvert = mvert,
+ .brush_radius = brush_radius,
+ .brushVelocity = &brushVel,
+ .pointCoord = pointCoord,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_paint_single_point_cb_ex, &settings);
+
+ return 1;
}
-
/***************************** Dynamic Paint Step / Baking ******************************/
/*
* Calculate current frame distances and directions for adjacency data
*/
-static void dynamic_paint_prepare_adjacency_cb(
- void *__restrict userdata,
- const int index,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void dynamic_paint_prepare_adjacency_cb(void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- PaintSurfaceData *sData = userdata;
- PaintBakeData *bData = sData->bData;
- BakeAdjPoint *bNeighs = bData->bNeighs;
- PaintAdjData *adj_data = sData->adj_data;
- Vec3f *realCoord = bData->realCoord;
-
- const int num_neighs = adj_data->n_num[index];
-
- for (int i = 0; i < num_neighs; i++) {
- const int n_index = adj_data->n_index[index] + i;
- const int t_index = adj_data->n_target[n_index];
-
- /* dir vec */
- sub_v3_v3v3(bNeighs[n_index].dir, realCoord[bData->s_pos[t_index]].v, realCoord[bData->s_pos[index]].v);
- /* dist */
- bNeighs[n_index].dist = normalize_v3(bNeighs[n_index].dir);
- }
+ PaintSurfaceData *sData = userdata;
+ PaintBakeData *bData = sData->bData;
+ BakeAdjPoint *bNeighs = bData->bNeighs;
+ PaintAdjData *adj_data = sData->adj_data;
+ Vec3f *realCoord = bData->realCoord;
+
+ const int num_neighs = adj_data->n_num[index];
+
+ for (int i = 0; i < num_neighs; i++) {
+ const int n_index = adj_data->n_index[index] + i;
+ const int t_index = adj_data->n_target[n_index];
+
+ /* dir vec */
+ sub_v3_v3v3(bNeighs[n_index].dir,
+ realCoord[bData->s_pos[t_index]].v,
+ realCoord[bData->s_pos[index]].v);
+ /* dist */
+ bNeighs[n_index].dist = normalize_v3(bNeighs[n_index].dir);
+ }
}
static void dynamicPaint_prepareAdjacencyData(DynamicPaintSurface *surface, const bool force_init)
{
- PaintSurfaceData *sData = surface->data;
- PaintBakeData *bData = sData->bData;
- BakeAdjPoint *bNeighs;
- PaintAdjData *adj_data = sData->adj_data;
-
- int index;
-
- if ((!surface_usesAdjDistance(surface) && !force_init) || !sData->adj_data)
- return;
-
- if (bData->bNeighs)
- MEM_freeN(bData->bNeighs);
- bNeighs = bData->bNeighs = MEM_mallocN(sData->adj_data->total_targets * sizeof(*bNeighs), "PaintEffectBake");
- if (!bNeighs)
- return;
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 1000);
- BLI_task_parallel_range(0, sData->total_points,
- sData,
- dynamic_paint_prepare_adjacency_cb,
- &settings);
-
- /* calculate average values (single thread).
- * Note: tried to put this in threaded callback (using _finalize feature), but gave ~30% slower result! */
- bData->average_dist = 0.0;
- for (index = 0; index < sData->total_points; index++) {
- int numOfNeighs = adj_data->n_num[index];
-
- for (int i = 0; i < numOfNeighs; i++) {
- bData->average_dist += (double)bNeighs[adj_data->n_index[index] + i].dist;
- }
- }
- bData->average_dist /= adj_data->total_targets;
+ PaintSurfaceData *sData = surface->data;
+ PaintBakeData *bData = sData->bData;
+ BakeAdjPoint *bNeighs;
+ PaintAdjData *adj_data = sData->adj_data;
+
+ int index;
+
+ if ((!surface_usesAdjDistance(surface) && !force_init) || !sData->adj_data)
+ return;
+
+ if (bData->bNeighs)
+ MEM_freeN(bData->bNeighs);
+ bNeighs = bData->bNeighs = MEM_mallocN(sData->adj_data->total_targets * sizeof(*bNeighs),
+ "PaintEffectBake");
+ if (!bNeighs)
+ return;
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(
+ 0, sData->total_points, sData, dynamic_paint_prepare_adjacency_cb, &settings);
+
+ /* calculate average values (single thread).
+ * Note: tried to put this in threaded callback (using _finalize feature), but gave ~30% slower result! */
+ bData->average_dist = 0.0;
+ for (index = 0; index < sData->total_points; index++) {
+ int numOfNeighs = adj_data->n_num[index];
+
+ for (int i = 0; i < numOfNeighs; i++) {
+ bData->average_dist += (double)bNeighs[adj_data->n_index[index] + i].dist;
+ }
+ }
+ bData->average_dist /= adj_data->total_targets;
}
/* find two adjacency points (closest_id) and influence (closest_d) to move paint towards when affected by a force */
-static void surface_determineForceTargetPoints(
- const PaintSurfaceData *sData, const int index, const float force[3], float closest_d[2], int closest_id[2])
+static void surface_determineForceTargetPoints(const PaintSurfaceData *sData,
+ const int index,
+ const float force[3],
+ float closest_d[2],
+ int closest_id[2])
{
- BakeAdjPoint *bNeighs = sData->bData->bNeighs;
- const int numOfNeighs = sData->adj_data->n_num[index];
- int i;
-
- closest_id[0] = closest_id[1] = -1;
- closest_d[0] = closest_d[1] = -1.0f;
-
- /* find closest neigh */
- for (i = 0; i < numOfNeighs; i++) {
- const int n_index = sData->adj_data->n_index[index] + i;
- const float dir_dot = dot_v3v3(bNeighs[n_index].dir, force);
-
- if (dir_dot > closest_d[0] && dir_dot > 0.0f) {
- closest_d[0] = dir_dot;
- closest_id[0] = n_index;
- }
- }
-
- if (closest_d[0] < 0.0f)
- return;
-
- /* find second closest neigh */
- for (i = 0; i < numOfNeighs; i++) {
- const int n_index = sData->adj_data->n_index[index] + i;
-
- if (n_index == closest_id[0])
- continue;
-
- const float dir_dot = dot_v3v3(bNeighs[n_index].dir, force);
- const float closest_dot = dot_v3v3(bNeighs[n_index].dir, bNeighs[closest_id[0]].dir);
-
- /* only accept neighbor at "other side" of the first one in relation to force dir
- * so make sure angle between this and closest neigh is greater than first angle. */
- if (dir_dot > closest_d[1] && closest_dot < closest_d[0] && dir_dot > 0.0f) {
- closest_d[1] = dir_dot;
- closest_id[1] = n_index;
- }
- }
-
- /* if two valid neighs found, calculate how force effect is divided evenly between them
- * (so that d[0] + d[1] = 1.0) */
- if (closest_id[1] != -1) {
- float force_proj[3];
- float tangent[3];
- const float neigh_diff = acosf(dot_v3v3(bNeighs[closest_id[0]].dir, bNeighs[closest_id[1]].dir));
- float force_intersect;
- float temp;
-
- /* project force vector on the plane determined by these two neighbor points
- * and calculate relative force angle from it. */
- cross_v3_v3v3(tangent, bNeighs[closest_id[0]].dir, bNeighs[closest_id[1]].dir);
- normalize_v3(tangent);
- force_intersect = dot_v3v3(force, tangent);
- madd_v3_v3v3fl(force_proj, force, tangent, (-1.0f) * force_intersect);
- normalize_v3(force_proj);
-
- /* get drip factor based on force dir in relation to angle between those neighbors */
- temp = dot_v3v3(bNeighs[closest_id[0]].dir, force_proj);
- CLAMP(temp, -1.0f, 1.0f); /* float precision might cause values > 1.0f that return infinite */
- closest_d[1] = acosf(temp) / neigh_diff;
- closest_d[0] = 1.0f - closest_d[1];
-
- /* and multiply depending on how deeply force intersects surface */
- temp = fabsf(force_intersect);
- CLAMP(temp, 0.0f, 1.0f);
- mul_v2_fl(closest_d, acosf(temp) / (float)M_PI_2);
- }
- else {
- /* if only single neighbor, still linearize force intersection effect */
- closest_d[0] = 1.0f - acosf(closest_d[0]) / (float)M_PI_2;
- }
+ BakeAdjPoint *bNeighs = sData->bData->bNeighs;
+ const int numOfNeighs = sData->adj_data->n_num[index];
+ int i;
+
+ closest_id[0] = closest_id[1] = -1;
+ closest_d[0] = closest_d[1] = -1.0f;
+
+ /* find closest neigh */
+ for (i = 0; i < numOfNeighs; i++) {
+ const int n_index = sData->adj_data->n_index[index] + i;
+ const float dir_dot = dot_v3v3(bNeighs[n_index].dir, force);
+
+ if (dir_dot > closest_d[0] && dir_dot > 0.0f) {
+ closest_d[0] = dir_dot;
+ closest_id[0] = n_index;
+ }
+ }
+
+ if (closest_d[0] < 0.0f)
+ return;
+
+ /* find second closest neigh */
+ for (i = 0; i < numOfNeighs; i++) {
+ const int n_index = sData->adj_data->n_index[index] + i;
+
+ if (n_index == closest_id[0])
+ continue;
+
+ const float dir_dot = dot_v3v3(bNeighs[n_index].dir, force);
+ const float closest_dot = dot_v3v3(bNeighs[n_index].dir, bNeighs[closest_id[0]].dir);
+
+ /* only accept neighbor at "other side" of the first one in relation to force dir
+ * so make sure angle between this and closest neigh is greater than first angle. */
+ if (dir_dot > closest_d[1] && closest_dot < closest_d[0] && dir_dot > 0.0f) {
+ closest_d[1] = dir_dot;
+ closest_id[1] = n_index;
+ }
+ }
+
+ /* if two valid neighs found, calculate how force effect is divided evenly between them
+ * (so that d[0] + d[1] = 1.0) */
+ if (closest_id[1] != -1) {
+ float force_proj[3];
+ float tangent[3];
+ const float neigh_diff = acosf(
+ dot_v3v3(bNeighs[closest_id[0]].dir, bNeighs[closest_id[1]].dir));
+ float force_intersect;
+ float temp;
+
+ /* project force vector on the plane determined by these two neighbor points
+ * and calculate relative force angle from it. */
+ cross_v3_v3v3(tangent, bNeighs[closest_id[0]].dir, bNeighs[closest_id[1]].dir);
+ normalize_v3(tangent);
+ force_intersect = dot_v3v3(force, tangent);
+ madd_v3_v3v3fl(force_proj, force, tangent, (-1.0f) * force_intersect);
+ normalize_v3(force_proj);
+
+ /* get drip factor based on force dir in relation to angle between those neighbors */
+ temp = dot_v3v3(bNeighs[closest_id[0]].dir, force_proj);
+ CLAMP(temp, -1.0f, 1.0f); /* float precision might cause values > 1.0f that return infinite */
+ closest_d[1] = acosf(temp) / neigh_diff;
+ closest_d[0] = 1.0f - closest_d[1];
+
+ /* and multiply depending on how deeply force intersects surface */
+ temp = fabsf(force_intersect);
+ CLAMP(temp, 0.0f, 1.0f);
+ mul_v2_fl(closest_d, acosf(temp) / (float)M_PI_2);
+ }
+ else {
+ /* if only single neighbor, still linearize force intersection effect */
+ closest_d[0] = 1.0f - acosf(closest_d[0]) / (float)M_PI_2;
+ }
}
-static void dynamicPaint_doSmudge(DynamicPaintSurface *surface, DynamicPaintBrushSettings *brush, float timescale)
+static void dynamicPaint_doSmudge(DynamicPaintSurface *surface,
+ DynamicPaintBrushSettings *brush,
+ float timescale)
{
- PaintSurfaceData *sData = surface->data;
- PaintBakeData *bData = sData->bData;
- BakeAdjPoint *bNeighs = sData->bData->bNeighs;
- int index, steps, step;
- float eff_scale, max_velocity = 0.0f;
-
- if (!sData->adj_data)
- return;
-
- /* find max velocity */
- for (index = 0; index < sData->total_points; index++) {
- float vel = bData->brush_velocity[index * 4 + 3];
- CLAMP_MIN(max_velocity, vel);
- }
-
- steps = (int)ceil((double)max_velocity / bData->average_dist * (double)timescale);
- CLAMP(steps, 0, 12);
- eff_scale = brush->smudge_strength / (float)steps * timescale;
-
- for (step = 0; step < steps; step++) {
- for (index = 0; index < sData->total_points; index++) {
- int i;
-
- if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL)
- continue;
-
- PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
- float smudge_str = bData->brush_velocity[index * 4 + 3];
-
- /* force targets */
- int closest_id[2];
- float closest_d[2];
-
- if (!smudge_str)
- continue;
-
- /* get force affect points */
- surface_determineForceTargetPoints(sData, index, &bData->brush_velocity[index * 4], closest_d, closest_id);
-
- /* Apply movement towards those two points */
- for (i = 0; i < 2; i++) {
- int n_index = closest_id[i];
- if (n_index != -1 && closest_d[i] > 0.0f) {
- float dir_dot = closest_d[i], dir_factor;
- float speed_scale = eff_scale * smudge_str / bNeighs[n_index].dist;
- PaintPoint *ePoint = &((PaintPoint *)sData->type_data)[sData->adj_data->n_target[n_index]];
-
- /* just skip if angle is too extreme */
- if (dir_dot <= 0.0f)
- continue;
-
- dir_factor = dir_dot * speed_scale;
- CLAMP_MAX(dir_factor, brush->smudge_strength);
-
- /* mix new color and alpha */
- mixColors(ePoint->color, ePoint->color[3], pPoint->color, pPoint->color[3], dir_factor);
- ePoint->color[3] = ePoint->color[3] * (1.0f - dir_factor) + pPoint->color[3] * dir_factor;
-
- /* smudge "wet layer" */
- mixColors(ePoint->e_color, ePoint->e_color[3], pPoint->e_color, pPoint->e_color[3], dir_factor);
- ePoint->e_color[3] = ePoint->e_color[3] * (1.0f - dir_factor) + pPoint->e_color[3] * dir_factor;
- pPoint->wetness *= (1.0f - dir_factor);
- }
- }
- }
- }
+ PaintSurfaceData *sData = surface->data;
+ PaintBakeData *bData = sData->bData;
+ BakeAdjPoint *bNeighs = sData->bData->bNeighs;
+ int index, steps, step;
+ float eff_scale, max_velocity = 0.0f;
+
+ if (!sData->adj_data)
+ return;
+
+ /* find max velocity */
+ for (index = 0; index < sData->total_points; index++) {
+ float vel = bData->brush_velocity[index * 4 + 3];
+ CLAMP_MIN(max_velocity, vel);
+ }
+
+ steps = (int)ceil((double)max_velocity / bData->average_dist * (double)timescale);
+ CLAMP(steps, 0, 12);
+ eff_scale = brush->smudge_strength / (float)steps * timescale;
+
+ for (step = 0; step < steps; step++) {
+ for (index = 0; index < sData->total_points; index++) {
+ int i;
+
+ if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL)
+ continue;
+
+ PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
+ float smudge_str = bData->brush_velocity[index * 4 + 3];
+
+ /* force targets */
+ int closest_id[2];
+ float closest_d[2];
+
+ if (!smudge_str)
+ continue;
+
+ /* get force affect points */
+ surface_determineForceTargetPoints(
+ sData, index, &bData->brush_velocity[index * 4], closest_d, closest_id);
+
+ /* Apply movement towards those two points */
+ for (i = 0; i < 2; i++) {
+ int n_index = closest_id[i];
+ if (n_index != -1 && closest_d[i] > 0.0f) {
+ float dir_dot = closest_d[i], dir_factor;
+ float speed_scale = eff_scale * smudge_str / bNeighs[n_index].dist;
+ PaintPoint *ePoint = &(
+ (PaintPoint *)sData->type_data)[sData->adj_data->n_target[n_index]];
+
+ /* just skip if angle is too extreme */
+ if (dir_dot <= 0.0f)
+ continue;
+
+ dir_factor = dir_dot * speed_scale;
+ CLAMP_MAX(dir_factor, brush->smudge_strength);
+
+ /* mix new color and alpha */
+ mixColors(ePoint->color, ePoint->color[3], pPoint->color, pPoint->color[3], dir_factor);
+ ePoint->color[3] = ePoint->color[3] * (1.0f - dir_factor) +
+ pPoint->color[3] * dir_factor;
+
+ /* smudge "wet layer" */
+ mixColors(ePoint->e_color,
+ ePoint->e_color[3],
+ pPoint->e_color,
+ pPoint->e_color[3],
+ dir_factor);
+ ePoint->e_color[3] = ePoint->e_color[3] * (1.0f - dir_factor) +
+ pPoint->e_color[3] * dir_factor;
+ pPoint->wetness *= (1.0f - dir_factor);
+ }
+ }
+ }
+ }
}
typedef struct DynamicPaintEffectData {
- const DynamicPaintSurface *surface;
- Scene *scene;
+ const DynamicPaintSurface *surface;
+ Scene *scene;
- float *force;
- ListBase *effectors;
- const void *prevPoint;
- const float eff_scale;
+ float *force;
+ ListBase *effectors;
+ const void *prevPoint;
+ const float eff_scale;
- uint8_t *point_locks;
+ uint8_t *point_locks;
- const float wave_speed;
- const float wave_scale;
- const float wave_max_slope;
+ const float wave_speed;
+ const float wave_scale;
+ const float wave_max_slope;
- const float dt;
- const float min_dist;
- const float damp_factor;
- const bool reset_wave;
+ const float dt;
+ const float min_dist;
+ const float damp_factor;
+ const bool reset_wave;
} DynamicPaintEffectData;
/*
* Prepare data required by effects for current frame.
* Returns number of steps required
*/
-static void dynamic_paint_prepare_effect_cb(
- void *__restrict userdata,
- const int index,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void dynamic_paint_prepare_effect_cb(void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintEffectData *data = userdata;
-
- const DynamicPaintSurface *surface = data->surface;
- const PaintSurfaceData *sData = surface->data;
- const PaintBakeData *bData = sData->bData;
- Vec3f *realCoord = bData->realCoord;
-
- Scene *scene = data->scene;
-
- float *force = data->force;
- ListBase *effectors = data->effectors;
-
- float forc[3] = {0};
- float vel[3] = {0};
-
- /* apply force fields */
- if (effectors) {
- EffectedPoint epoint;
- pd_point_from_loc(scene, realCoord[bData->s_pos[index]].v, vel, index, &epoint);
- epoint.vel_to_sec = 1.0f;
- BKE_effectors_apply(effectors, NULL, surface->effector_weights, &epoint, forc, NULL);
- }
-
- /* if global gravity is enabled, add it too */
- if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY)
- /* also divide by 10 to about match default grav
- * with default force strength (1.0). */
- madd_v3_v3fl(forc, scene->physics_settings.gravity,
- surface->effector_weights->global_gravity * surface->effector_weights->weight[0] / 10.f);
-
- /* add surface point velocity and acceleration if enabled */
- if (bData->velocity) {
- if (surface->drip_vel)
- madd_v3_v3fl(forc, bData->velocity[index].v, surface->drip_vel * (-1.0f));
-
- /* acceleration */
- if (bData->prev_velocity && surface->drip_acc) {
- float acc[3];
- copy_v3_v3(acc, bData->velocity[index].v);
- sub_v3_v3(acc, bData->prev_velocity[index].v);
- madd_v3_v3fl(forc, acc, surface->drip_acc * (-1.0f));
- }
- }
-
- /* force strength, and normalize force vec */
- force[index * 4 + 3] = normalize_v3_v3(&force[index * 4], forc);
+ const DynamicPaintEffectData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ const PaintBakeData *bData = sData->bData;
+ Vec3f *realCoord = bData->realCoord;
+
+ Scene *scene = data->scene;
+
+ float *force = data->force;
+ ListBase *effectors = data->effectors;
+
+ float forc[3] = {0};
+ float vel[3] = {0};
+
+ /* apply force fields */
+ if (effectors) {
+ EffectedPoint epoint;
+ pd_point_from_loc(scene, realCoord[bData->s_pos[index]].v, vel, index, &epoint);
+ epoint.vel_to_sec = 1.0f;
+ BKE_effectors_apply(effectors, NULL, surface->effector_weights, &epoint, forc, NULL);
+ }
+
+ /* if global gravity is enabled, add it too */
+ if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY)
+ /* also divide by 10 to about match default grav
+ * with default force strength (1.0). */
+ madd_v3_v3fl(forc,
+ scene->physics_settings.gravity,
+ surface->effector_weights->global_gravity * surface->effector_weights->weight[0] /
+ 10.f);
+
+ /* add surface point velocity and acceleration if enabled */
+ if (bData->velocity) {
+ if (surface->drip_vel)
+ madd_v3_v3fl(forc, bData->velocity[index].v, surface->drip_vel * (-1.0f));
+
+ /* acceleration */
+ if (bData->prev_velocity && surface->drip_acc) {
+ float acc[3];
+ copy_v3_v3(acc, bData->velocity[index].v);
+ sub_v3_v3(acc, bData->prev_velocity[index].v);
+ madd_v3_v3fl(forc, acc, surface->drip_acc * (-1.0f));
+ }
+ }
+
+ /* force strength, and normalize force vec */
+ force[index * 4 + 3] = normalize_v3_v3(&force[index * 4], forc);
}
-static int dynamicPaint_prepareEffectStep(
- struct Depsgraph *depsgraph, DynamicPaintSurface *surface, Scene *scene, Object *ob, float **force, float timescale)
+static int dynamicPaint_prepareEffectStep(struct Depsgraph *depsgraph,
+ DynamicPaintSurface *surface,
+ Scene *scene,
+ Object *ob,
+ float **force,
+ float timescale)
{
- double average_force = 0.0f;
- float shrink_speed = 0.0f, spread_speed = 0.0f;
- float fastest_effect, avg_dist;
- int steps;
- PaintSurfaceData *sData = surface->data;
- PaintBakeData *bData = sData->bData;
-
- /* Init force data if required */
- if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) {
- ListBase *effectors = BKE_effectors_create(depsgraph, ob, NULL, surface->effector_weights);
-
- /* allocate memory for force data (dir vector + strength) */
- *force = MEM_mallocN(sData->total_points * 4 * sizeof(float), "PaintEffectForces");
-
- if (*force) {
- DynamicPaintEffectData data = {
- .surface = surface, .scene = scene,
- .force = *force, .effectors = effectors,
- };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 1000);
- BLI_task_parallel_range(0, sData->total_points,
- &data,
- dynamic_paint_prepare_effect_cb,
- &settings);
-
- /* calculate average values (single thread) */
- for (int index = 0; index < sData->total_points; index++) {
- average_force += (double)(*force)[index * 4 + 3];
- }
- average_force /= sData->total_points;
- }
- BKE_effectors_free(effectors);
- }
-
- /* Get number of required steps using average point distance
- * so that just a few ultra close pixels wont up substeps to max. */
-
- /* adjust number of required substep by fastest active effect */
- if (surface->effect & MOD_DPAINT_EFFECT_DO_SPREAD)
- spread_speed = surface->spread_speed;
- if (surface->effect & MOD_DPAINT_EFFECT_DO_SHRINK)
- shrink_speed = surface->shrink_speed;
-
- fastest_effect = max_fff(spread_speed, shrink_speed, average_force);
- avg_dist = bData->average_dist * (double)CANVAS_REL_SIZE / (double)getSurfaceDimension(sData);
-
- steps = (int)ceilf(1.5f * EFF_MOVEMENT_PER_FRAME * fastest_effect / avg_dist * timescale);
- CLAMP(steps, 1, 20);
-
- return steps;
+ double average_force = 0.0f;
+ float shrink_speed = 0.0f, spread_speed = 0.0f;
+ float fastest_effect, avg_dist;
+ int steps;
+ PaintSurfaceData *sData = surface->data;
+ PaintBakeData *bData = sData->bData;
+
+ /* Init force data if required */
+ if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) {
+ ListBase *effectors = BKE_effectors_create(depsgraph, ob, NULL, surface->effector_weights);
+
+ /* allocate memory for force data (dir vector + strength) */
+ *force = MEM_mallocN(sData->total_points * 4 * sizeof(float), "PaintEffectForces");
+
+ if (*force) {
+ DynamicPaintEffectData data = {
+ .surface = surface,
+ .scene = scene,
+ .force = *force,
+ .effectors = effectors,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_prepare_effect_cb, &settings);
+
+ /* calculate average values (single thread) */
+ for (int index = 0; index < sData->total_points; index++) {
+ average_force += (double)(*force)[index * 4 + 3];
+ }
+ average_force /= sData->total_points;
+ }
+ BKE_effectors_free(effectors);
+ }
+
+ /* Get number of required steps using average point distance
+ * so that just a few ultra close pixels wont up substeps to max. */
+
+ /* adjust number of required substep by fastest active effect */
+ if (surface->effect & MOD_DPAINT_EFFECT_DO_SPREAD)
+ spread_speed = surface->spread_speed;
+ if (surface->effect & MOD_DPAINT_EFFECT_DO_SHRINK)
+ shrink_speed = surface->shrink_speed;
+
+ fastest_effect = max_fff(spread_speed, shrink_speed, average_force);
+ avg_dist = bData->average_dist * (double)CANVAS_REL_SIZE / (double)getSurfaceDimension(sData);
+
+ steps = (int)ceilf(1.5f * EFF_MOVEMENT_PER_FRAME * fastest_effect / avg_dist * timescale);
+ CLAMP(steps, 1, 20);
+
+ return steps;
}
/**
* Processes active effect step.
*/
-static void dynamic_paint_effect_spread_cb(
- void *__restrict userdata,
- const int index,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void dynamic_paint_effect_spread_cb(void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintEffectData *data = userdata;
-
- const DynamicPaintSurface *surface = data->surface;
- const PaintSurfaceData *sData = surface->data;
-
- if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL)
- return;
-
- const int numOfNeighs = sData->adj_data->n_num[index];
- BakeAdjPoint *bNeighs = sData->bData->bNeighs;
- PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
- const PaintPoint *prevPoint = data->prevPoint;
- const float eff_scale = data->eff_scale;
-
- const int *n_index = sData->adj_data->n_index;
- const int *n_target = sData->adj_data->n_target;
-
- /* Loop through neighboring points */
- for (int i = 0; i < numOfNeighs; i++) {
- const int n_idx = n_index[index] + i;
- float w_factor;
- const PaintPoint *pPoint_prev = &prevPoint[n_target[n_idx]];
- const float speed_scale = (bNeighs[n_idx].dist < eff_scale) ? 1.0f : eff_scale / bNeighs[n_idx].dist;
- const float color_mix = min_fff(pPoint_prev->wetness, pPoint->wetness, 1.0f) * 0.25f * surface->color_spread_speed;
-
- /* do color mixing */
- if (color_mix)
- mixColors(pPoint->e_color, pPoint->e_color[3], pPoint_prev->e_color, pPoint_prev->e_color[3], color_mix);
-
- /* Only continue if surrounding point has higher wetness */
- if (pPoint_prev->wetness < pPoint->wetness || pPoint_prev->wetness < MIN_WETNESS)
- continue;
-
- w_factor = 1.0f / numOfNeighs * min_ff(pPoint_prev->wetness, 1.0f) * speed_scale;
- CLAMP(w_factor, 0.0f, 1.0f);
-
- /* mix new wetness and color */
- pPoint->wetness = pPoint->wetness + w_factor * (pPoint_prev->wetness - pPoint->wetness);
- pPoint->e_color[3] = mixColors(pPoint->e_color, pPoint->e_color[3],
- pPoint_prev->e_color, pPoint_prev->e_color[3], w_factor);
- }
+ const DynamicPaintEffectData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+
+ if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL)
+ return;
+
+ const int numOfNeighs = sData->adj_data->n_num[index];
+ BakeAdjPoint *bNeighs = sData->bData->bNeighs;
+ PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
+ const PaintPoint *prevPoint = data->prevPoint;
+ const float eff_scale = data->eff_scale;
+
+ const int *n_index = sData->adj_data->n_index;
+ const int *n_target = sData->adj_data->n_target;
+
+ /* Loop through neighboring points */
+ for (int i = 0; i < numOfNeighs; i++) {
+ const int n_idx = n_index[index] + i;
+ float w_factor;
+ const PaintPoint *pPoint_prev = &prevPoint[n_target[n_idx]];
+ const float speed_scale = (bNeighs[n_idx].dist < eff_scale) ? 1.0f :
+ eff_scale / bNeighs[n_idx].dist;
+ const float color_mix = min_fff(pPoint_prev->wetness, pPoint->wetness, 1.0f) * 0.25f *
+ surface->color_spread_speed;
+
+ /* do color mixing */
+ if (color_mix)
+ mixColors(pPoint->e_color,
+ pPoint->e_color[3],
+ pPoint_prev->e_color,
+ pPoint_prev->e_color[3],
+ color_mix);
+
+ /* Only continue if surrounding point has higher wetness */
+ if (pPoint_prev->wetness < pPoint->wetness || pPoint_prev->wetness < MIN_WETNESS)
+ continue;
+
+ w_factor = 1.0f / numOfNeighs * min_ff(pPoint_prev->wetness, 1.0f) * speed_scale;
+ CLAMP(w_factor, 0.0f, 1.0f);
+
+ /* mix new wetness and color */
+ pPoint->wetness = pPoint->wetness + w_factor * (pPoint_prev->wetness - pPoint->wetness);
+ pPoint->e_color[3] = mixColors(pPoint->e_color,
+ pPoint->e_color[3],
+ pPoint_prev->e_color,
+ pPoint_prev->e_color[3],
+ w_factor);
+ }
}
-static void dynamic_paint_effect_shrink_cb(
- void *__restrict userdata,
- const int index,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void dynamic_paint_effect_shrink_cb(void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintEffectData *data = userdata;
-
- const DynamicPaintSurface *surface = data->surface;
- const PaintSurfaceData *sData = surface->data;
-
- if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL)
- return;
-
- const int numOfNeighs = sData->adj_data->n_num[index];
- BakeAdjPoint *bNeighs = sData->bData->bNeighs;
- PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
- const PaintPoint *prevPoint = data->prevPoint;
- const float eff_scale = data->eff_scale;
- float totalAlpha = 0.0f;
-
- const int *n_index = sData->adj_data->n_index;
- const int *n_target = sData->adj_data->n_target;
-
- /* Loop through neighboring points */
- for (int i = 0; i < numOfNeighs; i++) {
- const int n_idx = n_index[index] + i;
- const float speed_scale = (bNeighs[n_idx].dist < eff_scale) ? 1.0f : eff_scale / bNeighs[n_idx].dist;
- const PaintPoint *pPoint_prev = &prevPoint[n_target[n_idx]];
- float a_factor, ea_factor, w_factor;
-
- totalAlpha += pPoint_prev->e_color[3];
-
- /* Check if neighboring point has lower alpha,
- * if so, decrease this point's alpha as well. */
- if (pPoint->color[3] <= 0.0f && pPoint->e_color[3] <= 0.0f && pPoint->wetness <= 0.0f)
- continue;
-
- /* decrease factor for dry paint alpha */
- a_factor = max_ff((1.0f - pPoint_prev->color[3]) / numOfNeighs * (pPoint->color[3] - pPoint_prev->color[3]) * speed_scale, 0.0f);
- /* decrease factor for wet paint alpha */
- ea_factor = max_ff((1.0f - pPoint_prev->e_color[3]) / 8 * (pPoint->e_color[3] - pPoint_prev->e_color[3]) * speed_scale, 0.0f);
- /* decrease factor for paint wetness */
- w_factor = max_ff((1.0f - pPoint_prev->wetness) / 8 * (pPoint->wetness - pPoint_prev->wetness) * speed_scale, 0.0f);
-
- pPoint->color[3] -= a_factor;
- CLAMP_MIN(pPoint->color[3], 0.0f);
- pPoint->e_color[3] -= ea_factor;
- CLAMP_MIN(pPoint->e_color[3], 0.0f);
- pPoint->wetness -= w_factor;
- CLAMP_MIN(pPoint->wetness, 0.0f);
- }
+ const DynamicPaintEffectData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+
+ if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL)
+ return;
+
+ const int numOfNeighs = sData->adj_data->n_num[index];
+ BakeAdjPoint *bNeighs = sData->bData->bNeighs;
+ PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
+ const PaintPoint *prevPoint = data->prevPoint;
+ const float eff_scale = data->eff_scale;
+ float totalAlpha = 0.0f;
+
+ const int *n_index = sData->adj_data->n_index;
+ const int *n_target = sData->adj_data->n_target;
+
+ /* Loop through neighboring points */
+ for (int i = 0; i < numOfNeighs; i++) {
+ const int n_idx = n_index[index] + i;
+ const float speed_scale = (bNeighs[n_idx].dist < eff_scale) ? 1.0f :
+ eff_scale / bNeighs[n_idx].dist;
+ const PaintPoint *pPoint_prev = &prevPoint[n_target[n_idx]];
+ float a_factor, ea_factor, w_factor;
+
+ totalAlpha += pPoint_prev->e_color[3];
+
+ /* Check if neighboring point has lower alpha,
+ * if so, decrease this point's alpha as well. */
+ if (pPoint->color[3] <= 0.0f && pPoint->e_color[3] <= 0.0f && pPoint->wetness <= 0.0f)
+ continue;
+
+ /* decrease factor for dry paint alpha */
+ a_factor = max_ff((1.0f - pPoint_prev->color[3]) / numOfNeighs *
+ (pPoint->color[3] - pPoint_prev->color[3]) * speed_scale,
+ 0.0f);
+ /* decrease factor for wet paint alpha */
+ ea_factor = max_ff((1.0f - pPoint_prev->e_color[3]) / 8 *
+ (pPoint->e_color[3] - pPoint_prev->e_color[3]) * speed_scale,
+ 0.0f);
+ /* decrease factor for paint wetness */
+ w_factor = max_ff((1.0f - pPoint_prev->wetness) / 8 *
+ (pPoint->wetness - pPoint_prev->wetness) * speed_scale,
+ 0.0f);
+
+ pPoint->color[3] -= a_factor;
+ CLAMP_MIN(pPoint->color[3], 0.0f);
+ pPoint->e_color[3] -= ea_factor;
+ CLAMP_MIN(pPoint->e_color[3], 0.0f);
+ pPoint->wetness -= w_factor;
+ CLAMP_MIN(pPoint->wetness, 0.0f);
+ }
}
-static void dynamic_paint_effect_drip_cb(
- void *__restrict userdata,
- const int index,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void dynamic_paint_effect_drip_cb(void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintEffectData *data = userdata;
-
- const DynamicPaintSurface *surface = data->surface;
- const PaintSurfaceData *sData = surface->data;
-
- if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL)
- return;
-
- BakeAdjPoint *bNeighs = sData->bData->bNeighs;
- PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
- const PaintPoint *prevPoint = data->prevPoint;
- const PaintPoint *pPoint_prev = &prevPoint[index];
- const float *force = data->force;
- const float eff_scale = data->eff_scale;
-
- const int *n_target = sData->adj_data->n_target;
-
- uint8_t *point_locks = data->point_locks;
-
- int closest_id[2];
- float closest_d[2];
-
- /* adjust drip speed depending on wetness */
- float w_factor = pPoint_prev->wetness - 0.025f;
- if (w_factor <= 0)
- return;
- CLAMP(w_factor, 0.0f, 1.0f);
-
- float ppoint_wetness_diff = 0.0f;
-
- /* get force affect points */
- surface_determineForceTargetPoints(sData, index, &force[index * 4], closest_d, closest_id);
-
- /* Apply movement towards those two points */
- for (int i = 0; i < 2; i++) {
- const int n_idx = closest_id[i];
- if (n_idx != -1 && closest_d[i] > 0.0f) {
- const float dir_dot = closest_d[i];
-
- /* just skip if angle is too extreme */
- if (dir_dot <= 0.0f)
- continue;
-
- float dir_factor, a_factor;
- const float speed_scale = eff_scale * force[index * 4 + 3] / bNeighs[n_idx].dist;
-
- const unsigned int n_trgt = (unsigned int)n_target[n_idx];
-
- /* Sort of spinlock, but only for given ePoint.
- * Since the odds a same ePoint is modified at the same time by several threads is very low, this is
- * much more efficient than a global spin lock. */
- const unsigned int epointlock_idx = n_trgt / 8;
- const uint8_t epointlock_bitmask = 1 << (n_trgt & 7); /* 7 == 0b111 */
- while (atomic_fetch_and_or_uint8(&point_locks[epointlock_idx], epointlock_bitmask) & epointlock_bitmask);
-
- PaintPoint *ePoint = &((PaintPoint *)sData->type_data)[n_trgt];
- const float e_wet = ePoint->wetness;
-
- dir_factor = min_ff(0.5f, dir_dot * min_ff(speed_scale, 1.0f) * w_factor);
-
- /* mix new wetness */
- ePoint->wetness += dir_factor;
- CLAMP(ePoint->wetness, 0.0f, MAX_WETNESS);
-
- /* mix new color */
- a_factor = dir_factor / pPoint_prev->wetness;
- CLAMP(a_factor, 0.0f, 1.0f);
- mixColors(ePoint->e_color, ePoint->e_color[3], pPoint_prev->e_color, pPoint_prev->e_color[3], a_factor);
- /* dripping is supposed to preserve alpha level */
- if (pPoint_prev->e_color[3] > ePoint->e_color[3]) {
- ePoint->e_color[3] += a_factor * pPoint_prev->e_color[3];
- CLAMP_MAX(ePoint->e_color[3], pPoint_prev->e_color[3]);
- }
-
- /* Decrease paint wetness on current point
- * (just store diff here, that way we can only lock current point once at the end to apply it). */
- ppoint_wetness_diff += (ePoint->wetness - e_wet);
+ const DynamicPaintEffectData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+
+ if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL)
+ return;
+
+ BakeAdjPoint *bNeighs = sData->bData->bNeighs;
+ PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
+ const PaintPoint *prevPoint = data->prevPoint;
+ const PaintPoint *pPoint_prev = &prevPoint[index];
+ const float *force = data->force;
+ const float eff_scale = data->eff_scale;
+
+ const int *n_target = sData->adj_data->n_target;
+
+ uint8_t *point_locks = data->point_locks;
+
+ int closest_id[2];
+ float closest_d[2];
+
+ /* adjust drip speed depending on wetness */
+ float w_factor = pPoint_prev->wetness - 0.025f;
+ if (w_factor <= 0)
+ return;
+ CLAMP(w_factor, 0.0f, 1.0f);
+
+ float ppoint_wetness_diff = 0.0f;
+
+ /* get force affect points */
+ surface_determineForceTargetPoints(sData, index, &force[index * 4], closest_d, closest_id);
+
+ /* Apply movement towards those two points */
+ for (int i = 0; i < 2; i++) {
+ const int n_idx = closest_id[i];
+ if (n_idx != -1 && closest_d[i] > 0.0f) {
+ const float dir_dot = closest_d[i];
+
+ /* just skip if angle is too extreme */
+ if (dir_dot <= 0.0f)
+ continue;
+
+ float dir_factor, a_factor;
+ const float speed_scale = eff_scale * force[index * 4 + 3] / bNeighs[n_idx].dist;
+
+ const unsigned int n_trgt = (unsigned int)n_target[n_idx];
+
+ /* Sort of spinlock, but only for given ePoint.
+ * Since the odds a same ePoint is modified at the same time by several threads is very low, this is
+ * much more efficient than a global spin lock. */
+ const unsigned int epointlock_idx = n_trgt / 8;
+ const uint8_t epointlock_bitmask = 1 << (n_trgt & 7); /* 7 == 0b111 */
+ while (atomic_fetch_and_or_uint8(&point_locks[epointlock_idx], epointlock_bitmask) &
+ epointlock_bitmask)
+ ;
+
+ PaintPoint *ePoint = &((PaintPoint *)sData->type_data)[n_trgt];
+ const float e_wet = ePoint->wetness;
+
+ dir_factor = min_ff(0.5f, dir_dot * min_ff(speed_scale, 1.0f) * w_factor);
+
+ /* mix new wetness */
+ ePoint->wetness += dir_factor;
+ CLAMP(ePoint->wetness, 0.0f, MAX_WETNESS);
+
+ /* mix new color */
+ a_factor = dir_factor / pPoint_prev->wetness;
+ CLAMP(a_factor, 0.0f, 1.0f);
+ mixColors(ePoint->e_color,
+ ePoint->e_color[3],
+ pPoint_prev->e_color,
+ pPoint_prev->e_color[3],
+ a_factor);
+ /* dripping is supposed to preserve alpha level */
+ if (pPoint_prev->e_color[3] > ePoint->e_color[3]) {
+ ePoint->e_color[3] += a_factor * pPoint_prev->e_color[3];
+ CLAMP_MAX(ePoint->e_color[3], pPoint_prev->e_color[3]);
+ }
+
+ /* Decrease paint wetness on current point
+ * (just store diff here, that way we can only lock current point once at the end to apply it). */
+ ppoint_wetness_diff += (ePoint->wetness - e_wet);
#ifndef NDEBUG
- {
- uint8_t ret = atomic_fetch_and_and_uint8(&point_locks[epointlock_idx], ~epointlock_bitmask);
- BLI_assert(ret & epointlock_bitmask);
- }
+ {
+ uint8_t ret = atomic_fetch_and_and_uint8(&point_locks[epointlock_idx],
+ ~epointlock_bitmask);
+ BLI_assert(ret & epointlock_bitmask);
+ }
#else
- atomic_fetch_and_and_uint8(&point_locks[epointlock_idx], ~epointlock_bitmask);
+ atomic_fetch_and_and_uint8(&point_locks[epointlock_idx], ~epointlock_bitmask);
#endif
- }
- }
+ }
+ }
- {
- const unsigned int ppointlock_idx = index / 8;
- const uint8_t ppointlock_bitmask = 1 << (index & 7); /* 7 == 0b111 */
- while (atomic_fetch_and_or_uint8(&point_locks[ppointlock_idx], ppointlock_bitmask) & ppointlock_bitmask);
+ {
+ const unsigned int ppointlock_idx = index / 8;
+ const uint8_t ppointlock_bitmask = 1 << (index & 7); /* 7 == 0b111 */
+ while (atomic_fetch_and_or_uint8(&point_locks[ppointlock_idx], ppointlock_bitmask) &
+ ppointlock_bitmask)
+ ;
- pPoint->wetness -= ppoint_wetness_diff;
- CLAMP(pPoint->wetness, 0.0f, MAX_WETNESS);
+ pPoint->wetness -= ppoint_wetness_diff;
+ CLAMP(pPoint->wetness, 0.0f, MAX_WETNESS);
#ifndef NDEBUG
- {
- uint8_t ret = atomic_fetch_and_and_uint8(&point_locks[ppointlock_idx], ~ppointlock_bitmask);
- BLI_assert(ret & ppointlock_bitmask);
- }
+ {
+ uint8_t ret = atomic_fetch_and_and_uint8(&point_locks[ppointlock_idx], ~ppointlock_bitmask);
+ BLI_assert(ret & ppointlock_bitmask);
+ }
#else
- atomic_fetch_and_and_uint8(&point_locks[ppointlock_idx], ~ppointlock_bitmask);
+ atomic_fetch_and_and_uint8(&point_locks[ppointlock_idx], ~ppointlock_bitmask);
#endif
- }
+ }
}
-static void dynamicPaint_doEffectStep(
- DynamicPaintSurface *surface, float *force, PaintPoint *prevPoint, float timescale, float steps)
+static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface,
+ float *force,
+ PaintPoint *prevPoint,
+ float timescale,
+ float steps)
{
- PaintSurfaceData *sData = surface->data;
-
- const float distance_scale = getSurfaceDimension(sData) / CANVAS_REL_SIZE;
- timescale /= steps;
-
- if (!sData->adj_data)
- return;
-
- /*
- * Spread Effect
- */
- if (surface->effect & MOD_DPAINT_EFFECT_DO_SPREAD) {
- const float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * surface->spread_speed * timescale;
-
- /* Copy current surface to the previous points array to read unmodified values */
- memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(struct PaintPoint));
-
- DynamicPaintEffectData data = {
- .surface = surface, .prevPoint = prevPoint, .eff_scale = eff_scale,
- };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 1000);
- BLI_task_parallel_range(0, sData->total_points,
- &data,
- dynamic_paint_effect_spread_cb,
- &settings);
- }
-
- /*
- * Shrink Effect
- */
- if (surface->effect & MOD_DPAINT_EFFECT_DO_SHRINK) {
- const float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * surface->shrink_speed * timescale;
-
- /* Copy current surface to the previous points array to read unmodified values */
- memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(struct PaintPoint));
-
- DynamicPaintEffectData data = {
- .surface = surface, .prevPoint = prevPoint, .eff_scale = eff_scale,
- };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 1000);
- BLI_task_parallel_range(0, sData->total_points,
- &data,
- dynamic_paint_effect_shrink_cb,
- &settings);
- }
-
- /*
- * Drip Effect
- */
- if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP && force) {
- const float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * timescale / 2.0f;
-
- /* Same as BLI_bitmask, but handled atomicaly as 'ePoint' locks. */
- const size_t point_locks_size = (sData->total_points / 8) + 1;
- uint8_t *point_locks = MEM_callocN(sizeof(*point_locks) * point_locks_size, __func__);
-
- /* Copy current surface to the previous points array to read unmodified values */
- memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(struct PaintPoint));
-
- DynamicPaintEffectData data = {
- .surface = surface, .prevPoint = prevPoint,
- .eff_scale = eff_scale, .force = force,
- .point_locks = point_locks,
- };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 1000);
- BLI_task_parallel_range(0, sData->total_points,
- &data,
- dynamic_paint_effect_drip_cb,
- &settings);
-
- MEM_freeN(point_locks);
- }
+ PaintSurfaceData *sData = surface->data;
+
+ const float distance_scale = getSurfaceDimension(sData) / CANVAS_REL_SIZE;
+ timescale /= steps;
+
+ if (!sData->adj_data)
+ return;
+
+ /*
+ * Spread Effect
+ */
+ if (surface->effect & MOD_DPAINT_EFFECT_DO_SPREAD) {
+ const float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * surface->spread_speed *
+ timescale;
+
+ /* Copy current surface to the previous points array to read unmodified values */
+ memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(struct PaintPoint));
+
+ DynamicPaintEffectData data = {
+ .surface = surface,
+ .prevPoint = prevPoint,
+ .eff_scale = eff_scale,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_effect_spread_cb, &settings);
+ }
+
+ /*
+ * Shrink Effect
+ */
+ if (surface->effect & MOD_DPAINT_EFFECT_DO_SHRINK) {
+ const float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * surface->shrink_speed *
+ timescale;
+
+ /* Copy current surface to the previous points array to read unmodified values */
+ memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(struct PaintPoint));
+
+ DynamicPaintEffectData data = {
+ .surface = surface,
+ .prevPoint = prevPoint,
+ .eff_scale = eff_scale,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_effect_shrink_cb, &settings);
+ }
+
+ /*
+ * Drip Effect
+ */
+ if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP && force) {
+ const float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * timescale / 2.0f;
+
+ /* Same as BLI_bitmask, but handled atomicaly as 'ePoint' locks. */
+ const size_t point_locks_size = (sData->total_points / 8) + 1;
+ uint8_t *point_locks = MEM_callocN(sizeof(*point_locks) * point_locks_size, __func__);
+
+ /* Copy current surface to the previous points array to read unmodified values */
+ memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(struct PaintPoint));
+
+ DynamicPaintEffectData data = {
+ .surface = surface,
+ .prevPoint = prevPoint,
+ .eff_scale = eff_scale,
+ .force = force,
+ .point_locks = point_locks,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_effect_drip_cb, &settings);
+
+ MEM_freeN(point_locks);
+ }
}
-static void dynamic_paint_border_cb(
- void *__restrict userdata,
- const int b_index,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void dynamic_paint_border_cb(void *__restrict userdata,
+ const int b_index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintEffectData *data = userdata;
+ const DynamicPaintEffectData *data = userdata;
- const DynamicPaintSurface *surface = data->surface;
- const PaintSurfaceData *sData = surface->data;
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
- const int index = sData->adj_data->border[b_index];
+ const int index = sData->adj_data->border[b_index];
- const int numOfNeighs = sData->adj_data->n_num[index];
- PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
+ const int numOfNeighs = sData->adj_data->n_num[index];
+ PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
- const int *n_index = sData->adj_data->n_index;
- const int *n_target = sData->adj_data->n_target;
+ const int *n_index = sData->adj_data->n_index;
+ const int *n_target = sData->adj_data->n_target;
- /* Average neighboring points. Intermediaries use premultiplied alpha. */
- float mix_color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
- float mix_e_color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
- float mix_wetness = 0.0f;
+ /* Average neighboring points. Intermediaries use premultiplied alpha. */
+ float mix_color[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ float mix_e_color[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ float mix_wetness = 0.0f;
- for (int i = 0; i < numOfNeighs; i++) {
- const int n_idx = n_index[index] + i;
- const int target = n_target[n_idx];
+ for (int i = 0; i < numOfNeighs; i++) {
+ const int n_idx = n_index[index] + i;
+ const int target = n_target[n_idx];
- PaintPoint *pPoint2 = &((PaintPoint *)sData->type_data)[target];
+ PaintPoint *pPoint2 = &((PaintPoint *)sData->type_data)[target];
- assert(!(sData->adj_data->flags[target] & ADJ_BORDER_PIXEL));
+ assert(!(sData->adj_data->flags[target] & ADJ_BORDER_PIXEL));
- madd_v3_v3fl(mix_color, pPoint2->color, pPoint2->color[3]);
- mix_color[3] += pPoint2->color[3];
+ madd_v3_v3fl(mix_color, pPoint2->color, pPoint2->color[3]);
+ mix_color[3] += pPoint2->color[3];
- madd_v3_v3fl(mix_e_color, pPoint2->e_color, pPoint2->e_color[3]);
- mix_e_color[3] += pPoint2->e_color[3];
+ madd_v3_v3fl(mix_e_color, pPoint2->e_color, pPoint2->e_color[3]);
+ mix_e_color[3] += pPoint2->e_color[3];
- mix_wetness += pPoint2->wetness;
- }
+ mix_wetness += pPoint2->wetness;
+ }
- const float divisor = 1.0f / numOfNeighs;
+ const float divisor = 1.0f / numOfNeighs;
- if (mix_color[3]) {
- pPoint->color[3] = mix_color[3] * divisor;
- mul_v3_v3fl(pPoint->color, mix_color, divisor / pPoint->color[3]);
- }
- else {
- pPoint->color[3] = 0.0f;
- }
+ if (mix_color[3]) {
+ pPoint->color[3] = mix_color[3] * divisor;
+ mul_v3_v3fl(pPoint->color, mix_color, divisor / pPoint->color[3]);
+ }
+ else {
+ pPoint->color[3] = 0.0f;
+ }
- if (mix_e_color[3]) {
- pPoint->e_color[3] = mix_e_color[3] * divisor;
- mul_v3_v3fl(pPoint->e_color, mix_e_color, divisor / pPoint->e_color[3]);
- }
- else {
- pPoint->e_color[3] = 0.0f;
- }
+ if (mix_e_color[3]) {
+ pPoint->e_color[3] = mix_e_color[3] * divisor;
+ mul_v3_v3fl(pPoint->e_color, mix_e_color, divisor / pPoint->e_color[3]);
+ }
+ else {
+ pPoint->e_color[3] = 0.0f;
+ }
- pPoint->wetness = mix_wetness / numOfNeighs;
+ pPoint->wetness = mix_wetness / numOfNeighs;
}
static void dynamicPaint_doBorderStep(DynamicPaintSurface *surface)
{
- PaintSurfaceData *sData = surface->data;
-
- if (!sData->adj_data || !sData->adj_data->border)
- return;
-
- /* Don't use prevPoint, relying on the condition that neighbors are never border pixels. */
- DynamicPaintEffectData data = {
- .surface = surface,
- };
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->adj_data->total_border > 1000);
- BLI_task_parallel_range(0, sData->adj_data->total_border,
- &data,
- dynamic_paint_border_cb,
- &settings);
+ PaintSurfaceData *sData = surface->data;
+
+ if (!sData->adj_data || !sData->adj_data->border)
+ return;
+
+ /* Don't use prevPoint, relying on the condition that neighbors are never border pixels. */
+ DynamicPaintEffectData data = {
+ .surface = surface,
+ };
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->adj_data->total_border > 1000);
+ BLI_task_parallel_range(
+ 0, sData->adj_data->total_border, &data, dynamic_paint_border_cb, &settings);
}
-static void dynamic_paint_wave_step_cb(
- void *__restrict userdata,
- const int index,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void dynamic_paint_wave_step_cb(void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintEffectData *data = userdata;
-
- const DynamicPaintSurface *surface = data->surface;
- const PaintSurfaceData *sData = surface->data;
- BakeAdjPoint *bNeighs = sData->bData->bNeighs;
- const PaintWavePoint *prevPoint = data->prevPoint;
-
- const float wave_speed = data->wave_speed;
- const float wave_scale = data->wave_scale;
- const float wave_max_slope = data->wave_max_slope;
-
- const float dt = data->dt;
- const float min_dist = data->min_dist;
- const float damp_factor = data->damp_factor;
-
- PaintWavePoint *wPoint = &((PaintWavePoint *)sData->type_data)[index];
- const int numOfNeighs = sData->adj_data->n_num[index];
- float force = 0.0f, avg_dist = 0.0f, avg_height = 0.0f, avg_n_height = 0.0f;
- int numOfN = 0, numOfRN = 0;
-
- if (wPoint->state > 0)
- return;
-
- const int *n_index = sData->adj_data->n_index;
- const int *n_target = sData->adj_data->n_target;
- const int *adj_flags = sData->adj_data->flags;
-
- /* calculate force from surrounding points */
- for (int i = 0; i < numOfNeighs; i++) {
- const int n_idx = n_index[index] + i;
- float dist = bNeighs[n_idx].dist * wave_scale;
- const PaintWavePoint *tPoint = &prevPoint[n_target[n_idx]];
-
- if (!dist || tPoint->state > 0)
- continue;
-
- CLAMP_MIN(dist, min_dist);
- avg_dist += dist;
- numOfN++;
-
- /* count average height for edge points for open borders */
- if (!(adj_flags[n_target[n_idx]] & ADJ_ON_MESH_EDGE)) {
- avg_n_height += tPoint->height;
- numOfRN++;
- }
-
- force += (tPoint->height - wPoint->height) / (dist * dist);
- avg_height += tPoint->height;
- }
- avg_dist = (numOfN) ? avg_dist / numOfN : 0.0f;
-
- if (surface->flags & MOD_DPAINT_WAVE_OPEN_BORDERS && adj_flags[index] & ADJ_ON_MESH_EDGE) {
- /* if open borders, apply a fake height to keep waves going on */
- avg_n_height = (numOfRN) ? avg_n_height / numOfRN : 0.0f;
- wPoint->height = (dt * wave_speed * avg_n_height + wPoint->height * avg_dist) /
- (avg_dist + dt * wave_speed);
- }
- /* else do wave eq */
- else {
- /* add force towards zero height based on average dist */
- if (avg_dist)
- force += (0.0f - wPoint->height) * surface->wave_spring / (avg_dist * avg_dist) / 2.0f;
-
- /* change point velocity */
- wPoint->velocity += force * dt * wave_speed * wave_speed;
- /* damping */
- wPoint->velocity *= damp_factor;
- /* and new height */
- wPoint->height += wPoint->velocity * dt;
-
- /* limit wave slope steepness */
- if (wave_max_slope && avg_dist) {
- const float max_offset = wave_max_slope * avg_dist;
- const float offset = (numOfN) ? (avg_height / numOfN - wPoint->height) : 0.0f;
- if (offset > max_offset)
- wPoint->height += offset - max_offset;
- else if (offset < -max_offset)
- wPoint->height += offset + max_offset;
- }
- }
-
- if (data->reset_wave) {
- /* if there wasn't any brush intersection, clear isect height */
- if (wPoint->state == DPAINT_WAVE_NONE) {
- wPoint->brush_isect = 0.0f;
- }
- wPoint->state = DPAINT_WAVE_NONE;
- }
+ const DynamicPaintEffectData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ BakeAdjPoint *bNeighs = sData->bData->bNeighs;
+ const PaintWavePoint *prevPoint = data->prevPoint;
+
+ const float wave_speed = data->wave_speed;
+ const float wave_scale = data->wave_scale;
+ const float wave_max_slope = data->wave_max_slope;
+
+ const float dt = data->dt;
+ const float min_dist = data->min_dist;
+ const float damp_factor = data->damp_factor;
+
+ PaintWavePoint *wPoint = &((PaintWavePoint *)sData->type_data)[index];
+ const int numOfNeighs = sData->adj_data->n_num[index];
+ float force = 0.0f, avg_dist = 0.0f, avg_height = 0.0f, avg_n_height = 0.0f;
+ int numOfN = 0, numOfRN = 0;
+
+ if (wPoint->state > 0)
+ return;
+
+ const int *n_index = sData->adj_data->n_index;
+ const int *n_target = sData->adj_data->n_target;
+ const int *adj_flags = sData->adj_data->flags;
+
+ /* calculate force from surrounding points */
+ for (int i = 0; i < numOfNeighs; i++) {
+ const int n_idx = n_index[index] + i;
+ float dist = bNeighs[n_idx].dist * wave_scale;
+ const PaintWavePoint *tPoint = &prevPoint[n_target[n_idx]];
+
+ if (!dist || tPoint->state > 0)
+ continue;
+
+ CLAMP_MIN(dist, min_dist);
+ avg_dist += dist;
+ numOfN++;
+
+ /* count average height for edge points for open borders */
+ if (!(adj_flags[n_target[n_idx]] & ADJ_ON_MESH_EDGE)) {
+ avg_n_height += tPoint->height;
+ numOfRN++;
+ }
+
+ force += (tPoint->height - wPoint->height) / (dist * dist);
+ avg_height += tPoint->height;
+ }
+ avg_dist = (numOfN) ? avg_dist / numOfN : 0.0f;
+
+ if (surface->flags & MOD_DPAINT_WAVE_OPEN_BORDERS && adj_flags[index] & ADJ_ON_MESH_EDGE) {
+ /* if open borders, apply a fake height to keep waves going on */
+ avg_n_height = (numOfRN) ? avg_n_height / numOfRN : 0.0f;
+ wPoint->height = (dt * wave_speed * avg_n_height + wPoint->height * avg_dist) /
+ (avg_dist + dt * wave_speed);
+ }
+ /* else do wave eq */
+ else {
+ /* add force towards zero height based on average dist */
+ if (avg_dist)
+ force += (0.0f - wPoint->height) * surface->wave_spring / (avg_dist * avg_dist) / 2.0f;
+
+ /* change point velocity */
+ wPoint->velocity += force * dt * wave_speed * wave_speed;
+ /* damping */
+ wPoint->velocity *= damp_factor;
+ /* and new height */
+ wPoint->height += wPoint->velocity * dt;
+
+ /* limit wave slope steepness */
+ if (wave_max_slope && avg_dist) {
+ const float max_offset = wave_max_slope * avg_dist;
+ const float offset = (numOfN) ? (avg_height / numOfN - wPoint->height) : 0.0f;
+ if (offset > max_offset)
+ wPoint->height += offset - max_offset;
+ else if (offset < -max_offset)
+ wPoint->height += offset + max_offset;
+ }
+ }
+
+ if (data->reset_wave) {
+ /* if there wasn't any brush intersection, clear isect height */
+ if (wPoint->state == DPAINT_WAVE_NONE) {
+ wPoint->brush_isect = 0.0f;
+ }
+ wPoint->state = DPAINT_WAVE_NONE;
+ }
}
static void dynamicPaint_doWaveStep(DynamicPaintSurface *surface, float timescale)
{
- PaintSurfaceData *sData = surface->data;
- BakeAdjPoint *bNeighs = sData->bData->bNeighs;
- int index;
- int steps, ss;
- float dt, min_dist, damp_factor;
- const float wave_speed = surface->wave_speed;
- const float wave_max_slope = (surface->wave_smoothness >= 0.01f) ? (0.5f / surface->wave_smoothness) : 0.0f;
- double average_dist = 0.0f;
- const float canvas_size = getSurfaceDimension(sData);
- const float wave_scale = CANVAS_REL_SIZE / canvas_size;
-
- /* allocate memory */
- PaintWavePoint *prevPoint = MEM_mallocN(
- sData->total_points * sizeof(PaintWavePoint), __func__);
- if (!prevPoint)
- return;
-
- /* calculate average neigh distance (single thread) */
- for (index = 0; index < sData->total_points; index++) {
- int i;
- int numOfNeighs = sData->adj_data->n_num[index];
-
- for (i = 0; i < numOfNeighs; i++) {
- average_dist += (double)bNeighs[sData->adj_data->n_index[index] + i].dist;
- }
- }
- average_dist *= (double)wave_scale / sData->adj_data->total_targets;
-
- /* determine number of required steps */
- steps = (int)ceil((double)(WAVE_TIME_FAC * timescale * surface->wave_timescale) /
- (average_dist / (double)wave_speed / 3));
- CLAMP(steps, 1, 20);
- timescale /= steps;
-
- /* apply simulation values for final timescale */
- dt = WAVE_TIME_FAC * timescale * surface->wave_timescale;
- min_dist = wave_speed * dt * 1.5f;
- damp_factor = pow((1.0f - surface->wave_damping), timescale * surface->wave_timescale);
-
- for (ss = 0; ss < steps; ss++) {
- /* copy previous frame data */
- memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(PaintWavePoint));
-
- DynamicPaintEffectData data = {
- .surface = surface, .prevPoint = prevPoint,
- .wave_speed = wave_speed, .wave_scale = wave_scale, .wave_max_slope = wave_max_slope,
- .dt = dt, .min_dist = min_dist, .damp_factor = damp_factor, .reset_wave = (ss == steps - 1),
- };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 1000);
- BLI_task_parallel_range(0, sData->total_points,
- &data, dynamic_paint_wave_step_cb,
- &settings);
- }
-
- MEM_freeN(prevPoint);
+ PaintSurfaceData *sData = surface->data;
+ BakeAdjPoint *bNeighs = sData->bData->bNeighs;
+ int index;
+ int steps, ss;
+ float dt, min_dist, damp_factor;
+ const float wave_speed = surface->wave_speed;
+ const float wave_max_slope = (surface->wave_smoothness >= 0.01f) ?
+ (0.5f / surface->wave_smoothness) :
+ 0.0f;
+ double average_dist = 0.0f;
+ const float canvas_size = getSurfaceDimension(sData);
+ const float wave_scale = CANVAS_REL_SIZE / canvas_size;
+
+ /* allocate memory */
+ PaintWavePoint *prevPoint = MEM_mallocN(sData->total_points * sizeof(PaintWavePoint), __func__);
+ if (!prevPoint)
+ return;
+
+ /* calculate average neigh distance (single thread) */
+ for (index = 0; index < sData->total_points; index++) {
+ int i;
+ int numOfNeighs = sData->adj_data->n_num[index];
+
+ for (i = 0; i < numOfNeighs; i++) {
+ average_dist += (double)bNeighs[sData->adj_data->n_index[index] + i].dist;
+ }
+ }
+ average_dist *= (double)wave_scale / sData->adj_data->total_targets;
+
+ /* determine number of required steps */
+ steps = (int)ceil((double)(WAVE_TIME_FAC * timescale * surface->wave_timescale) /
+ (average_dist / (double)wave_speed / 3));
+ CLAMP(steps, 1, 20);
+ timescale /= steps;
+
+ /* apply simulation values for final timescale */
+ dt = WAVE_TIME_FAC * timescale * surface->wave_timescale;
+ min_dist = wave_speed * dt * 1.5f;
+ damp_factor = pow((1.0f - surface->wave_damping), timescale * surface->wave_timescale);
+
+ for (ss = 0; ss < steps; ss++) {
+ /* copy previous frame data */
+ memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(PaintWavePoint));
+
+ DynamicPaintEffectData data = {
+ .surface = surface,
+ .prevPoint = prevPoint,
+ .wave_speed = wave_speed,
+ .wave_scale = wave_scale,
+ .wave_max_slope = wave_max_slope,
+ .dt = dt,
+ .min_dist = min_dist,
+ .damp_factor = damp_factor,
+ .reset_wave = (ss == steps - 1),
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(0, sData->total_points, &data, dynamic_paint_wave_step_cb, &settings);
+ }
+
+ MEM_freeN(prevPoint);
}
/* Do dissolve and fading effects */
static bool dynamic_paint_surface_needs_dry_dissolve(DynamicPaintSurface *surface)
{
- return (((surface->type == MOD_DPAINT_SURFACE_T_PAINT) &&
- (surface->flags & (MOD_DPAINT_USE_DRYING | MOD_DPAINT_DISSOLVE))) ||
- (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WEIGHT) &&
- (surface->flags & MOD_DPAINT_DISSOLVE)));
+ return (((surface->type == MOD_DPAINT_SURFACE_T_PAINT) &&
+ (surface->flags & (MOD_DPAINT_USE_DRYING | MOD_DPAINT_DISSOLVE))) ||
+ (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WEIGHT) &&
+ (surface->flags & MOD_DPAINT_DISSOLVE)));
}
typedef struct DynamicPaintDissolveDryData {
- const DynamicPaintSurface *surface;
- const float timescale;
+ const DynamicPaintSurface *surface;
+ const float timescale;
} DynamicPaintDissolveDryData;
-static void dynamic_paint_surface_pre_step_cb(
- void *__restrict userdata,
- const int index,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void dynamic_paint_surface_pre_step_cb(void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintDissolveDryData *data = userdata;
-
- const DynamicPaintSurface *surface = data->surface;
- const PaintSurfaceData *sData = surface->data;
- const float timescale = data->timescale;
-
- /* Do drying dissolve effects */
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
- /* drying */
- if (surface->flags & MOD_DPAINT_USE_DRYING) {
- if (pPoint->wetness >= MIN_WETNESS) {
- int i;
- float dry_ratio, f_color[4];
- float p_wetness = pPoint->wetness;
-
- value_dissolve(&pPoint->wetness, surface->dry_speed, timescale,
- (surface->flags & MOD_DPAINT_DRY_LOG) != 0);
- CLAMP_MIN(pPoint->wetness, 0.0f);
-
- if (pPoint->wetness < surface->color_dry_threshold) {
- dry_ratio = pPoint->wetness / p_wetness;
-
- /*
- * Slowly "shift" paint from wet layer to dry layer as it drys:
- */
- /* make sure alpha values are within proper range */
- CLAMP(pPoint->color[3], 0.0f, 1.0f);
- CLAMP(pPoint->e_color[3], 0.0f, 1.0f);
-
- /* get current final blended color of these layers */
- blendColors(pPoint->color, pPoint->color[3], pPoint->e_color, pPoint->e_color[3], f_color);
- /* reduce wet layer alpha by dry factor */
- pPoint->e_color[3] *= dry_ratio;
-
- /* now calculate new alpha for dry layer that keeps final blended color unchanged */
- pPoint->color[3] = (f_color[3] - pPoint->e_color[3]) / (1.0f - pPoint->e_color[3]);
- /* for each rgb component, calculate a new dry layer color that keeps the final blend color
- * with these new alpha values. (wet layer color doesn't change)*/
- if (pPoint->color[3]) {
- for (i = 0; i < 3; i++) {
- pPoint->color[i] = (f_color[i] * f_color[3] - pPoint->e_color[i] * pPoint->e_color[3]) /
- (pPoint->color[3] * (1.0f - pPoint->e_color[3]));
- }
- }
- }
-
- pPoint->state = DPAINT_PAINT_WET;
- }
- /* in case of just dryed paint, just mix it to the dry layer and mark it empty */
- else if (pPoint->state > 0) {
- float f_color[4];
- blendColors(pPoint->color, pPoint->color[3], pPoint->e_color, pPoint->e_color[3], f_color);
- copy_v4_v4(pPoint->color, f_color);
- /* clear wet layer */
- pPoint->wetness = 0.0f;
- pPoint->e_color[3] = 0.0f;
- pPoint->state = DPAINT_PAINT_DRY;
- }
- }
-
- if (surface->flags & MOD_DPAINT_DISSOLVE) {
- value_dissolve(&pPoint->color[3], surface->diss_speed, timescale,
- (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0);
- CLAMP_MIN(pPoint->color[3], 0.0f);
-
- value_dissolve(&pPoint->e_color[3], surface->diss_speed, timescale,
- (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0);
- CLAMP_MIN(pPoint->e_color[3], 0.0f);
- }
- }
- /* dissolve for float types */
- else if (surface->flags & MOD_DPAINT_DISSOLVE &&
- (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE || surface->type == MOD_DPAINT_SURFACE_T_WEIGHT))
- {
- float *point = &((float *)sData->type_data)[index];
- /* log or linear */
- value_dissolve(point, surface->diss_speed, timescale, (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0);
- CLAMP_MIN(*point, 0.0f);
- }
+ const DynamicPaintDissolveDryData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ const float timescale = data->timescale;
+
+ /* Do drying dissolve effects */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
+ /* drying */
+ if (surface->flags & MOD_DPAINT_USE_DRYING) {
+ if (pPoint->wetness >= MIN_WETNESS) {
+ int i;
+ float dry_ratio, f_color[4];
+ float p_wetness = pPoint->wetness;
+
+ value_dissolve(&pPoint->wetness,
+ surface->dry_speed,
+ timescale,
+ (surface->flags & MOD_DPAINT_DRY_LOG) != 0);
+ CLAMP_MIN(pPoint->wetness, 0.0f);
+
+ if (pPoint->wetness < surface->color_dry_threshold) {
+ dry_ratio = pPoint->wetness / p_wetness;
+
+ /*
+ * Slowly "shift" paint from wet layer to dry layer as it drys:
+ */
+ /* make sure alpha values are within proper range */
+ CLAMP(pPoint->color[3], 0.0f, 1.0f);
+ CLAMP(pPoint->e_color[3], 0.0f, 1.0f);
+
+ /* get current final blended color of these layers */
+ blendColors(
+ pPoint->color, pPoint->color[3], pPoint->e_color, pPoint->e_color[3], f_color);
+ /* reduce wet layer alpha by dry factor */
+ pPoint->e_color[3] *= dry_ratio;
+
+ /* now calculate new alpha for dry layer that keeps final blended color unchanged */
+ pPoint->color[3] = (f_color[3] - pPoint->e_color[3]) / (1.0f - pPoint->e_color[3]);
+ /* for each rgb component, calculate a new dry layer color that keeps the final blend color
+ * with these new alpha values. (wet layer color doesn't change)*/
+ if (pPoint->color[3]) {
+ for (i = 0; i < 3; i++) {
+ pPoint->color[i] = (f_color[i] * f_color[3] -
+ pPoint->e_color[i] * pPoint->e_color[3]) /
+ (pPoint->color[3] * (1.0f - pPoint->e_color[3]));
+ }
+ }
+ }
+
+ pPoint->state = DPAINT_PAINT_WET;
+ }
+ /* in case of just dryed paint, just mix it to the dry layer and mark it empty */
+ else if (pPoint->state > 0) {
+ float f_color[4];
+ blendColors(pPoint->color, pPoint->color[3], pPoint->e_color, pPoint->e_color[3], f_color);
+ copy_v4_v4(pPoint->color, f_color);
+ /* clear wet layer */
+ pPoint->wetness = 0.0f;
+ pPoint->e_color[3] = 0.0f;
+ pPoint->state = DPAINT_PAINT_DRY;
+ }
+ }
+
+ if (surface->flags & MOD_DPAINT_DISSOLVE) {
+ value_dissolve(&pPoint->color[3],
+ surface->diss_speed,
+ timescale,
+ (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0);
+ CLAMP_MIN(pPoint->color[3], 0.0f);
+
+ value_dissolve(&pPoint->e_color[3],
+ surface->diss_speed,
+ timescale,
+ (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0);
+ CLAMP_MIN(pPoint->e_color[3], 0.0f);
+ }
+ }
+ /* dissolve for float types */
+ else if (surface->flags & MOD_DPAINT_DISSOLVE &&
+ (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE ||
+ surface->type == MOD_DPAINT_SURFACE_T_WEIGHT)) {
+ float *point = &((float *)sData->type_data)[index];
+ /* log or linear */
+ value_dissolve(
+ point, surface->diss_speed, timescale, (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0);
+ CLAMP_MIN(*point, 0.0f);
+ }
}
static bool dynamicPaint_surfaceHasMoved(DynamicPaintSurface *surface, Object *ob)
{
- PaintSurfaceData *sData = surface->data;
- PaintBakeData *bData = sData->bData;
- Mesh *mesh = dynamicPaint_canvas_mesh_get(surface->canvas);
- MVert *mvert = mesh->mvert;
+ PaintSurfaceData *sData = surface->data;
+ PaintBakeData *bData = sData->bData;
+ Mesh *mesh = dynamicPaint_canvas_mesh_get(surface->canvas);
+ MVert *mvert = mesh->mvert;
- int numOfVerts = mesh->totvert;
- int i;
+ int numOfVerts = mesh->totvert;
+ int i;
- if (!bData->prev_verts)
- return true;
+ if (!bData->prev_verts)
+ return true;
- /* matrix comparison */
- if (!equals_m4m4(bData->prev_obmat, ob->obmat))
- return true;
+ /* matrix comparison */
+ if (!equals_m4m4(bData->prev_obmat, ob->obmat))
+ return true;
- /* vertices */
- for (i = 0; i < numOfVerts; i++) {
- if (!equals_v3v3(bData->prev_verts[i].co, mvert[i].co)) {
- return true;
- }
- }
+ /* vertices */
+ for (i = 0; i < numOfVerts; i++) {
+ if (!equals_v3v3(bData->prev_verts[i].co, mvert[i].co)) {
+ return true;
+ }
+ }
- return false;
+ return false;
}
/* Prepare for surface step by creating PaintBakeNormal data */
typedef struct DynamicPaintGenerateBakeData {
- const DynamicPaintSurface *surface;
- Object *ob;
+ const DynamicPaintSurface *surface;
+ Object *ob;
- const MVert *mvert;
- const Vec3f *canvas_verts;
+ const MVert *mvert;
+ const Vec3f *canvas_verts;
- const bool do_velocity_data;
- const bool new_bdata;
+ const bool do_velocity_data;
+ const bool new_bdata;
} DynamicPaintGenerateBakeData;
-static void dynamic_paint_generate_bake_data_cb(
- void *__restrict userdata,
- const int index,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void dynamic_paint_generate_bake_data_cb(void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintGenerateBakeData *data = userdata;
-
- const DynamicPaintSurface *surface = data->surface;
- const PaintSurfaceData *sData = surface->data;
- const PaintAdjData *adj_data = sData->adj_data;
- const PaintBakeData *bData = sData->bData;
-
- Object *ob = data->ob;
-
- const MVert *mvert = data->mvert;
- const Vec3f *canvas_verts = data->canvas_verts;
-
- const bool do_velocity_data = data->do_velocity_data;
- const bool new_bdata = data->new_bdata;
-
- float prev_point[3] = {0.0f, 0.0f, 0.0f};
- float temp_nor[3];
-
- if (do_velocity_data && !new_bdata) {
- copy_v3_v3(prev_point, bData->realCoord[bData->s_pos[index]].v);
- }
-
- /*
- * Calculate current 3D-position and normal of each surface point
- */
- if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
- float n1[3], n2[3], n3[3];
- const ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
- const PaintUVPoint *tPoint = &((PaintUVPoint *)f_data->uv_p)[index];
-
- bData->s_num[index] = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
- bData->s_pos[index] = index * bData->s_num[index];
-
- /* per sample coordinates */
- for (int ss = 0; ss < bData->s_num[index]; ss++) {
- interp_v3_v3v3v3(bData->realCoord[bData->s_pos[index] + ss].v,
- canvas_verts[tPoint->v1].v,
- canvas_verts[tPoint->v2].v,
- canvas_verts[tPoint->v3].v,
- f_data->barycentricWeights[index * bData->s_num[index] + ss].v);
- }
-
- /* Calculate current pixel surface normal */
- normal_short_to_float_v3(n1, mvert[tPoint->v1].no);
- normal_short_to_float_v3(n2, mvert[tPoint->v2].no);
- normal_short_to_float_v3(n3, mvert[tPoint->v3].no);
-
- interp_v3_v3v3v3(temp_nor, n1, n2, n3, f_data->barycentricWeights[index * bData->s_num[index]].v);
- normalize_v3(temp_nor);
- if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
- /* Prepare surface normal directional scale to easily convert
- * brush intersection amount between global and local space */
- float scaled_nor[3];
- mul_v3_v3v3(scaled_nor, temp_nor, ob->scale);
- bData->bNormal[index].normal_scale = len_v3(scaled_nor);
- }
- mul_mat3_m4_v3(ob->obmat, temp_nor);
- normalize_v3(temp_nor);
- negate_v3_v3(bData->bNormal[index].invNorm, temp_nor);
- }
- else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
- int ss;
- if (surface->flags & MOD_DPAINT_ANTIALIAS && adj_data) {
- bData->s_num[index] = adj_data->n_num[index] + 1;
- bData->s_pos[index] = adj_data->n_index[index] + index;
- }
- else {
- bData->s_num[index] = 1;
- bData->s_pos[index] = index;
- }
-
- /* calculate position for each sample */
- for (ss = 0; ss < bData->s_num[index]; ss++) {
- /* first sample is always point center */
- copy_v3_v3(bData->realCoord[bData->s_pos[index] + ss].v, canvas_verts[index].v);
- if (ss > 0) {
- int t_index = adj_data->n_index[index] + (ss - 1);
- /* get vertex position at 1/3 of each neigh edge */
- mul_v3_fl(bData->realCoord[bData->s_pos[index] + ss].v, 2.0f / 3.0f);
- madd_v3_v3fl(bData->realCoord[bData->s_pos[index] + ss].v,
- canvas_verts[adj_data->n_target[t_index]].v, 1.0f / 3.0f);
- }
- }
-
- /* normal */
- normal_short_to_float_v3(temp_nor, mvert[index].no);
- if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
- /* Prepare surface normal directional scale to easily convert
- * brush intersection amount between global and local space */
- float scaled_nor[3];
- mul_v3_v3v3(scaled_nor, temp_nor, ob->scale);
- bData->bNormal[index].normal_scale = len_v3(scaled_nor);
- }
- mul_mat3_m4_v3(ob->obmat, temp_nor);
- normalize_v3(temp_nor);
- negate_v3_v3(bData->bNormal[index].invNorm, temp_nor);
- }
-
- /* calculate speed vector */
- if (do_velocity_data && !new_bdata && !bData->clear) {
- sub_v3_v3v3(bData->velocity[index].v, bData->realCoord[bData->s_pos[index]].v, prev_point);
- }
+ const DynamicPaintGenerateBakeData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ const PaintAdjData *adj_data = sData->adj_data;
+ const PaintBakeData *bData = sData->bData;
+
+ Object *ob = data->ob;
+
+ const MVert *mvert = data->mvert;
+ const Vec3f *canvas_verts = data->canvas_verts;
+
+ const bool do_velocity_data = data->do_velocity_data;
+ const bool new_bdata = data->new_bdata;
+
+ float prev_point[3] = {0.0f, 0.0f, 0.0f};
+ float temp_nor[3];
+
+ if (do_velocity_data && !new_bdata) {
+ copy_v3_v3(prev_point, bData->realCoord[bData->s_pos[index]].v);
+ }
+
+ /*
+ * Calculate current 3D-position and normal of each surface point
+ */
+ if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
+ float n1[3], n2[3], n3[3];
+ const ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
+ const PaintUVPoint *tPoint = &((PaintUVPoint *)f_data->uv_p)[index];
+
+ bData->s_num[index] = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
+ bData->s_pos[index] = index * bData->s_num[index];
+
+ /* per sample coordinates */
+ for (int ss = 0; ss < bData->s_num[index]; ss++) {
+ interp_v3_v3v3v3(bData->realCoord[bData->s_pos[index] + ss].v,
+ canvas_verts[tPoint->v1].v,
+ canvas_verts[tPoint->v2].v,
+ canvas_verts[tPoint->v3].v,
+ f_data->barycentricWeights[index * bData->s_num[index] + ss].v);
+ }
+
+ /* Calculate current pixel surface normal */
+ normal_short_to_float_v3(n1, mvert[tPoint->v1].no);
+ normal_short_to_float_v3(n2, mvert[tPoint->v2].no);
+ normal_short_to_float_v3(n3, mvert[tPoint->v3].no);
+
+ interp_v3_v3v3v3(
+ temp_nor, n1, n2, n3, f_data->barycentricWeights[index * bData->s_num[index]].v);
+ normalize_v3(temp_nor);
+ if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
+ /* Prepare surface normal directional scale to easily convert
+ * brush intersection amount between global and local space */
+ float scaled_nor[3];
+ mul_v3_v3v3(scaled_nor, temp_nor, ob->scale);
+ bData->bNormal[index].normal_scale = len_v3(scaled_nor);
+ }
+ mul_mat3_m4_v3(ob->obmat, temp_nor);
+ normalize_v3(temp_nor);
+ negate_v3_v3(bData->bNormal[index].invNorm, temp_nor);
+ }
+ else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
+ int ss;
+ if (surface->flags & MOD_DPAINT_ANTIALIAS && adj_data) {
+ bData->s_num[index] = adj_data->n_num[index] + 1;
+ bData->s_pos[index] = adj_data->n_index[index] + index;
+ }
+ else {
+ bData->s_num[index] = 1;
+ bData->s_pos[index] = index;
+ }
+
+ /* calculate position for each sample */
+ for (ss = 0; ss < bData->s_num[index]; ss++) {
+ /* first sample is always point center */
+ copy_v3_v3(bData->realCoord[bData->s_pos[index] + ss].v, canvas_verts[index].v);
+ if (ss > 0) {
+ int t_index = adj_data->n_index[index] + (ss - 1);
+ /* get vertex position at 1/3 of each neigh edge */
+ mul_v3_fl(bData->realCoord[bData->s_pos[index] + ss].v, 2.0f / 3.0f);
+ madd_v3_v3fl(bData->realCoord[bData->s_pos[index] + ss].v,
+ canvas_verts[adj_data->n_target[t_index]].v,
+ 1.0f / 3.0f);
+ }
+ }
+
+ /* normal */
+ normal_short_to_float_v3(temp_nor, mvert[index].no);
+ if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
+ /* Prepare surface normal directional scale to easily convert
+ * brush intersection amount between global and local space */
+ float scaled_nor[3];
+ mul_v3_v3v3(scaled_nor, temp_nor, ob->scale);
+ bData->bNormal[index].normal_scale = len_v3(scaled_nor);
+ }
+ mul_mat3_m4_v3(ob->obmat, temp_nor);
+ normalize_v3(temp_nor);
+ negate_v3_v3(bData->bNormal[index].invNorm, temp_nor);
+ }
+
+ /* calculate speed vector */
+ if (do_velocity_data && !new_bdata && !bData->clear) {
+ sub_v3_v3v3(bData->velocity[index].v, bData->realCoord[bData->s_pos[index]].v, prev_point);
+ }
}
-static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, Depsgraph *depsgraph, Object *ob)
+static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface,
+ Depsgraph *depsgraph,
+ Object *ob)
{
- PaintSurfaceData *sData = surface->data;
- PaintBakeData *bData = sData->bData;
- Mesh *mesh = dynamicPaint_canvas_mesh_get(surface->canvas);
- int index;
- bool new_bdata = false;
- const bool do_velocity_data = ((surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) ||
- (surface_getBrushFlags(surface, depsgraph) & BRUSH_USES_VELOCITY));
- const bool do_accel_data = (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) != 0;
-
- int canvasNumOfVerts = mesh->totvert;
- MVert *mvert = mesh->mvert;
- Vec3f *canvas_verts;
-
- if (bData) {
- const bool surface_moved = dynamicPaint_surfaceHasMoved(surface, ob);
-
- /* get previous speed for accelertaion */
- if (do_accel_data && bData->prev_velocity && bData->velocity)
- memcpy(bData->prev_velocity, bData->velocity, sData->total_points * sizeof(Vec3f));
-
- /* reset speed vectors */
- if (do_velocity_data && bData->velocity && (bData->clear || !surface_moved))
- memset(bData->velocity, 0, sData->total_points * sizeof(Vec3f));
-
- /* if previous data exists and mesh hasn't moved, no need to recalc */
- if (!surface_moved)
- return 1;
- }
-
- canvas_verts = (struct Vec3f *) MEM_mallocN(canvasNumOfVerts * sizeof(struct Vec3f), "Dynamic Paint transformed canvas verts");
- if (!canvas_verts)
- return 0;
-
- /* allocate memory if required */
- if (!bData) {
- sData->bData = bData = (struct PaintBakeData *) MEM_callocN(sizeof(struct PaintBakeData), "Dynamic Paint bake data");
- if (!bData) {
- if (canvas_verts)
- MEM_freeN(canvas_verts);
- return 0;
- }
-
- /* Init bdata */
- bData->bNormal = (struct PaintBakeNormal *) MEM_mallocN(sData->total_points * sizeof(struct PaintBakeNormal), "Dynamic Paint step data");
- bData->s_pos = MEM_mallocN(sData->total_points * sizeof(unsigned int), "Dynamic Paint bData s_pos");
- bData->s_num = MEM_mallocN(sData->total_points * sizeof(unsigned int), "Dynamic Paint bData s_num");
- bData->realCoord = (struct Vec3f *) MEM_mallocN(surface_totalSamples(surface) * sizeof(Vec3f), "Dynamic Paint point coords");
- bData->prev_verts = MEM_mallocN(canvasNumOfVerts * sizeof(MVert), "Dynamic Paint bData prev_verts");
-
- /* if any allocation failed, free everything */
- if (!bData->bNormal || !bData->s_pos || !bData->s_num || !bData->realCoord || !canvas_verts) {
- if (bData->bNormal)
- MEM_freeN(bData->bNormal);
- if (bData->s_pos)
- MEM_freeN(bData->s_pos);
- if (bData->s_num)
- MEM_freeN(bData->s_num);
- if (bData->realCoord)
- MEM_freeN(bData->realCoord);
- if (canvas_verts)
- MEM_freeN(canvas_verts);
-
- return setError(surface->canvas, N_("Not enough free memory"));
- }
-
- new_bdata = true;
- }
-
- if (do_velocity_data && !bData->velocity) {
- bData->velocity = (struct Vec3f *) MEM_callocN(sData->total_points * sizeof(Vec3f), "Dynamic Paint velocity");
- }
- if (do_accel_data && !bData->prev_velocity) {
- bData->prev_velocity = (struct Vec3f *) MEM_mallocN(sData->total_points * sizeof(Vec3f), "Dynamic Paint prev velocity");
- /* copy previous vel */
- if (bData->prev_velocity && bData->velocity)
- memcpy(bData->prev_velocity, bData->velocity, sData->total_points * sizeof(Vec3f));
- }
-
- /*
- * Make a transformed copy of canvas derived mesh vertices to avoid recalculation.
- */
- bData->mesh_bounds.valid = false;
- for (index = 0; index < canvasNumOfVerts; index++) {
- copy_v3_v3(canvas_verts[index].v, mvert[index].co);
- mul_m4_v3(ob->obmat, canvas_verts[index].v);
- boundInsert(&bData->mesh_bounds, canvas_verts[index].v);
- }
-
- /*
- * Prepare each surface point for a new step
- */
- DynamicPaintGenerateBakeData data = {
- .surface = surface, .ob = ob,
- .mvert = mvert, .canvas_verts = canvas_verts,
- .do_velocity_data = do_velocity_data, .new_bdata = new_bdata,
- };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 1000);
- BLI_task_parallel_range(0, sData->total_points,
- &data,
- dynamic_paint_generate_bake_data_cb,
- &settings);
-
- MEM_freeN(canvas_verts);
-
- /* generate surface space partitioning grid */
- surfaceGenerateGrid(surface);
- /* calculate current frame adjacency point distances and global dirs */
- dynamicPaint_prepareAdjacencyData(surface, false);
-
- /* Copy current frame vertices to check against in next frame */
- copy_m4_m4(bData->prev_obmat, ob->obmat);
- memcpy(bData->prev_verts, mvert, canvasNumOfVerts * sizeof(MVert));
-
- bData->clear = 0;
-
- return 1;
+ PaintSurfaceData *sData = surface->data;
+ PaintBakeData *bData = sData->bData;
+ Mesh *mesh = dynamicPaint_canvas_mesh_get(surface->canvas);
+ int index;
+ bool new_bdata = false;
+ const bool do_velocity_data = ((surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) ||
+ (surface_getBrushFlags(surface, depsgraph) &
+ BRUSH_USES_VELOCITY));
+ const bool do_accel_data = (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) != 0;
+
+ int canvasNumOfVerts = mesh->totvert;
+ MVert *mvert = mesh->mvert;
+ Vec3f *canvas_verts;
+
+ if (bData) {
+ const bool surface_moved = dynamicPaint_surfaceHasMoved(surface, ob);
+
+ /* get previous speed for accelertaion */
+ if (do_accel_data && bData->prev_velocity && bData->velocity)
+ memcpy(bData->prev_velocity, bData->velocity, sData->total_points * sizeof(Vec3f));
+
+ /* reset speed vectors */
+ if (do_velocity_data && bData->velocity && (bData->clear || !surface_moved))
+ memset(bData->velocity, 0, sData->total_points * sizeof(Vec3f));
+
+ /* if previous data exists and mesh hasn't moved, no need to recalc */
+ if (!surface_moved)
+ return 1;
+ }
+
+ canvas_verts = (struct Vec3f *)MEM_mallocN(canvasNumOfVerts * sizeof(struct Vec3f),
+ "Dynamic Paint transformed canvas verts");
+ if (!canvas_verts)
+ return 0;
+
+ /* allocate memory if required */
+ if (!bData) {
+ sData->bData = bData = (struct PaintBakeData *)MEM_callocN(sizeof(struct PaintBakeData),
+ "Dynamic Paint bake data");
+ if (!bData) {
+ if (canvas_verts)
+ MEM_freeN(canvas_verts);
+ return 0;
+ }
+
+ /* Init bdata */
+ bData->bNormal = (struct PaintBakeNormal *)MEM_mallocN(
+ sData->total_points * sizeof(struct PaintBakeNormal), "Dynamic Paint step data");
+ bData->s_pos = MEM_mallocN(sData->total_points * sizeof(unsigned int),
+ "Dynamic Paint bData s_pos");
+ bData->s_num = MEM_mallocN(sData->total_points * sizeof(unsigned int),
+ "Dynamic Paint bData s_num");
+ bData->realCoord = (struct Vec3f *)MEM_mallocN(surface_totalSamples(surface) * sizeof(Vec3f),
+ "Dynamic Paint point coords");
+ bData->prev_verts = MEM_mallocN(canvasNumOfVerts * sizeof(MVert),
+ "Dynamic Paint bData prev_verts");
+
+ /* if any allocation failed, free everything */
+ if (!bData->bNormal || !bData->s_pos || !bData->s_num || !bData->realCoord || !canvas_verts) {
+ if (bData->bNormal)
+ MEM_freeN(bData->bNormal);
+ if (bData->s_pos)
+ MEM_freeN(bData->s_pos);
+ if (bData->s_num)
+ MEM_freeN(bData->s_num);
+ if (bData->realCoord)
+ MEM_freeN(bData->realCoord);
+ if (canvas_verts)
+ MEM_freeN(canvas_verts);
+
+ return setError(surface->canvas, N_("Not enough free memory"));
+ }
+
+ new_bdata = true;
+ }
+
+ if (do_velocity_data && !bData->velocity) {
+ bData->velocity = (struct Vec3f *)MEM_callocN(sData->total_points * sizeof(Vec3f),
+ "Dynamic Paint velocity");
+ }
+ if (do_accel_data && !bData->prev_velocity) {
+ bData->prev_velocity = (struct Vec3f *)MEM_mallocN(sData->total_points * sizeof(Vec3f),
+ "Dynamic Paint prev velocity");
+ /* copy previous vel */
+ if (bData->prev_velocity && bData->velocity)
+ memcpy(bData->prev_velocity, bData->velocity, sData->total_points * sizeof(Vec3f));
+ }
+
+ /*
+ * Make a transformed copy of canvas derived mesh vertices to avoid recalculation.
+ */
+ bData->mesh_bounds.valid = false;
+ for (index = 0; index < canvasNumOfVerts; index++) {
+ copy_v3_v3(canvas_verts[index].v, mvert[index].co);
+ mul_m4_v3(ob->obmat, canvas_verts[index].v);
+ boundInsert(&bData->mesh_bounds, canvas_verts[index].v);
+ }
+
+ /*
+ * Prepare each surface point for a new step
+ */
+ DynamicPaintGenerateBakeData data = {
+ .surface = surface,
+ .ob = ob,
+ .mvert = mvert,
+ .canvas_verts = canvas_verts,
+ .do_velocity_data = do_velocity_data,
+ .new_bdata = new_bdata,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_generate_bake_data_cb, &settings);
+
+ MEM_freeN(canvas_verts);
+
+ /* generate surface space partitioning grid */
+ surfaceGenerateGrid(surface);
+ /* calculate current frame adjacency point distances and global dirs */
+ dynamicPaint_prepareAdjacencyData(surface, false);
+
+ /* Copy current frame vertices to check against in next frame */
+ copy_m4_m4(bData->prev_obmat, ob->obmat);
+ memcpy(bData->prev_verts, mvert, canvasNumOfVerts * sizeof(MVert));
+
+ bData->clear = 0;
+
+ return 1;
}
/*
* Do Dynamic Paint step. Paints scene brush objects of current state/frame to the surface.
*/
-static int dynamicPaint_doStep(
- Depsgraph *depsgraph, Scene *scene,
- Object *ob, DynamicPaintSurface *surface, float timescale, float subframe)
+static int dynamicPaint_doStep(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ DynamicPaintSurface *surface,
+ float timescale,
+ float subframe)
{
- PaintSurfaceData *sData = surface->data;
- PaintBakeData *bData = sData->bData;
- DynamicPaintCanvasSettings *canvas = surface->canvas;
- const bool for_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
- int ret = 1;
-
- if (sData->total_points < 1)
- return 0;
-
- if (dynamic_paint_surface_needs_dry_dissolve(surface)) {
- DynamicPaintDissolveDryData data = { .surface = surface, .timescale = timescale, };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 1000);
- BLI_task_parallel_range(0, sData->total_points,
- &data,
- dynamic_paint_surface_pre_step_cb,
- &settings);
- }
-
- /*
- * Loop through surface's target paint objects and do painting
- */
- {
- unsigned int numobjects;
- Object **objects = BKE_collision_objects_create(depsgraph, NULL, surface->brush_group, &numobjects, eModifierType_DynamicPaint);
-
- /* backup current scene frame */
- int scene_frame = scene->r.cfra;
- float scene_subframe = scene->r.subframe;
-
- for (int i = 0; i < numobjects; i++) {
- Object *brushObj = objects[i];
-
- /* check if target has an active dp modifier */
- ModifierData *md = modifiers_findByType(brushObj, eModifierType_DynamicPaint);
- if (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) {
- DynamicPaintModifierData *pmd2 = (DynamicPaintModifierData *)md;
- /* make sure we're dealing with a brush */
- if (pmd2->brush) {
- DynamicPaintBrushSettings *brush = pmd2->brush;
-
- /* calculate brush speed vectors if required */
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT && brush->flags & MOD_DPAINT_DO_SMUDGE) {
- bData->brush_velocity = MEM_callocN(sData->total_points * sizeof(float) * 4, "Dynamic Paint brush velocity");
- /* init adjacency data if not already */
- if (!sData->adj_data)
- dynamicPaint_initAdjacencyData(surface, true);
- if (!bData->bNeighs)
- dynamicPaint_prepareAdjacencyData(surface, true);
- }
-
- /* update object data on this subframe */
- if (subframe) {
- scene_setSubframe(scene, subframe);
- BKE_object_modifier_update_subframe(depsgraph, scene, brushObj, true, SUBFRAME_RECURSION,
- BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
- }
-
-
- /* Apply brush on the surface depending on it's collision type */
- if (brush->psys && brush->psys->part &&
- ELEM(brush->psys->part->type, PART_EMITTER, PART_FLUID) &&
- psys_check_enabled(brushObj, brush->psys, for_render))
- {
- /* Paint a particle system */
- dynamicPaint_paintParticles(surface, brush->psys, brush, timescale);
- }
- /* Object center distance: */
- if (brush->collision == MOD_DPAINT_COL_POINT && brushObj != ob) {
- dynamicPaint_paintSinglePoint(depsgraph, surface, brushObj->loc, brush, brushObj, scene, timescale);
- }
- /* Mesh volume/proximity: */
- else if (brushObj != ob) {
- dynamicPaint_paintMesh(depsgraph, surface, brush, brushObj, scene, timescale);
- }
-
- /* reset object to it's original state */
- if (subframe) {
- scene->r.cfra = scene_frame;
- scene->r.subframe = scene_subframe;
- BKE_object_modifier_update_subframe(depsgraph, scene, brushObj, true, SUBFRAME_RECURSION,
- BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
- }
-
- /* process special brush effects, like smudge */
- if (bData->brush_velocity) {
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT && brush->flags & MOD_DPAINT_DO_SMUDGE)
- dynamicPaint_doSmudge(surface, brush, timescale);
- MEM_freeN(bData->brush_velocity);
- bData->brush_velocity = NULL;
- }
- }
- }
- }
-
- BKE_collision_objects_free(objects);
- }
-
- /* surfaces operations that use adjacency data */
- if (sData->adj_data && bData->bNeighs) {
- /* wave type surface simulation step */
- if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
- dynamicPaint_doWaveStep(surface, timescale);
- }
-
- /* paint surface effects */
- if (surface->effect && surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- int steps = 1, s;
- PaintPoint *prevPoint;
- float *force = NULL;
-
- /* Allocate memory for surface previous points to read unchanged values from */
- prevPoint = MEM_mallocN(sData->total_points * sizeof(struct PaintPoint), "PaintSurfaceDataCopy");
- if (!prevPoint)
- return setError(canvas, N_("Not enough free memory"));
-
- /* Prepare effects and get number of required steps */
- steps = dynamicPaint_prepareEffectStep(depsgraph, surface, scene, ob, &force, timescale);
- for (s = 0; s < steps; s++) {
- dynamicPaint_doEffectStep(surface, force, prevPoint, timescale, (float)steps);
- }
-
- /* Free temporary effect data */
- if (prevPoint)
- MEM_freeN(prevPoint);
- if (force)
- MEM_freeN(force);
- }
-
- /* paint island border pixels */
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- dynamicPaint_doBorderStep(surface);
- }
- }
-
- return ret;
+ PaintSurfaceData *sData = surface->data;
+ PaintBakeData *bData = sData->bData;
+ DynamicPaintCanvasSettings *canvas = surface->canvas;
+ const bool for_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
+ int ret = 1;
+
+ if (sData->total_points < 1)
+ return 0;
+
+ if (dynamic_paint_surface_needs_dry_dissolve(surface)) {
+ DynamicPaintDissolveDryData data = {
+ .surface = surface,
+ .timescale = timescale,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_surface_pre_step_cb, &settings);
+ }
+
+ /*
+ * Loop through surface's target paint objects and do painting
+ */
+ {
+ unsigned int numobjects;
+ Object **objects = BKE_collision_objects_create(
+ depsgraph, NULL, surface->brush_group, &numobjects, eModifierType_DynamicPaint);
+
+ /* backup current scene frame */
+ int scene_frame = scene->r.cfra;
+ float scene_subframe = scene->r.subframe;
+
+ for (int i = 0; i < numobjects; i++) {
+ Object *brushObj = objects[i];
+
+ /* check if target has an active dp modifier */
+ ModifierData *md = modifiers_findByType(brushObj, eModifierType_DynamicPaint);
+ if (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) {
+ DynamicPaintModifierData *pmd2 = (DynamicPaintModifierData *)md;
+ /* make sure we're dealing with a brush */
+ if (pmd2->brush) {
+ DynamicPaintBrushSettings *brush = pmd2->brush;
+
+ /* calculate brush speed vectors if required */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT && brush->flags & MOD_DPAINT_DO_SMUDGE) {
+ bData->brush_velocity = MEM_callocN(sData->total_points * sizeof(float) * 4,
+ "Dynamic Paint brush velocity");
+ /* init adjacency data if not already */
+ if (!sData->adj_data)
+ dynamicPaint_initAdjacencyData(surface, true);
+ if (!bData->bNeighs)
+ dynamicPaint_prepareAdjacencyData(surface, true);
+ }
+
+ /* update object data on this subframe */
+ if (subframe) {
+ scene_setSubframe(scene, subframe);
+ BKE_object_modifier_update_subframe(depsgraph,
+ scene,
+ brushObj,
+ true,
+ SUBFRAME_RECURSION,
+ BKE_scene_frame_get(scene),
+ eModifierType_DynamicPaint);
+ }
+
+ /* Apply brush on the surface depending on it's collision type */
+ if (brush->psys && brush->psys->part &&
+ ELEM(brush->psys->part->type, PART_EMITTER, PART_FLUID) &&
+ psys_check_enabled(brushObj, brush->psys, for_render)) {
+ /* Paint a particle system */
+ dynamicPaint_paintParticles(surface, brush->psys, brush, timescale);
+ }
+ /* Object center distance: */
+ if (brush->collision == MOD_DPAINT_COL_POINT && brushObj != ob) {
+ dynamicPaint_paintSinglePoint(
+ depsgraph, surface, brushObj->loc, brush, brushObj, scene, timescale);
+ }
+ /* Mesh volume/proximity: */
+ else if (brushObj != ob) {
+ dynamicPaint_paintMesh(depsgraph, surface, brush, brushObj, scene, timescale);
+ }
+
+ /* reset object to it's original state */
+ if (subframe) {
+ scene->r.cfra = scene_frame;
+ scene->r.subframe = scene_subframe;
+ BKE_object_modifier_update_subframe(depsgraph,
+ scene,
+ brushObj,
+ true,
+ SUBFRAME_RECURSION,
+ BKE_scene_frame_get(scene),
+ eModifierType_DynamicPaint);
+ }
+
+ /* process special brush effects, like smudge */
+ if (bData->brush_velocity) {
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT && brush->flags & MOD_DPAINT_DO_SMUDGE)
+ dynamicPaint_doSmudge(surface, brush, timescale);
+ MEM_freeN(bData->brush_velocity);
+ bData->brush_velocity = NULL;
+ }
+ }
+ }
+ }
+
+ BKE_collision_objects_free(objects);
+ }
+
+ /* surfaces operations that use adjacency data */
+ if (sData->adj_data && bData->bNeighs) {
+ /* wave type surface simulation step */
+ if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
+ dynamicPaint_doWaveStep(surface, timescale);
+ }
+
+ /* paint surface effects */
+ if (surface->effect && surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ int steps = 1, s;
+ PaintPoint *prevPoint;
+ float *force = NULL;
+
+ /* Allocate memory for surface previous points to read unchanged values from */
+ prevPoint = MEM_mallocN(sData->total_points * sizeof(struct PaintPoint),
+ "PaintSurfaceDataCopy");
+ if (!prevPoint)
+ return setError(canvas, N_("Not enough free memory"));
+
+ /* Prepare effects and get number of required steps */
+ steps = dynamicPaint_prepareEffectStep(depsgraph, surface, scene, ob, &force, timescale);
+ for (s = 0; s < steps; s++) {
+ dynamicPaint_doEffectStep(surface, force, prevPoint, timescale, (float)steps);
+ }
+
+ /* Free temporary effect data */
+ if (prevPoint)
+ MEM_freeN(prevPoint);
+ if (force)
+ MEM_freeN(force);
+ }
+
+ /* paint island border pixels */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ dynamicPaint_doBorderStep(surface);
+ }
+ }
+
+ return ret;
}
/*
* Calculate a single frame and included subframes for surface
*/
-int dynamicPaint_calculateFrame(
- DynamicPaintSurface *surface, struct Depsgraph *depsgraph,
- Scene *scene, Object *cObject, int frame)
+int dynamicPaint_calculateFrame(DynamicPaintSurface *surface,
+ struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *cObject,
+ int frame)
{
- float timescale = 1.0f;
+ float timescale = 1.0f;
- /* apply previous displace on derivedmesh if incremental surface */
- if (surface->flags & MOD_DPAINT_DISP_INCREMENTAL) {
- dynamicPaint_applySurfaceDisplace(surface, dynamicPaint_canvas_mesh_get(surface->canvas));
- }
+ /* apply previous displace on derivedmesh if incremental surface */
+ if (surface->flags & MOD_DPAINT_DISP_INCREMENTAL) {
+ dynamicPaint_applySurfaceDisplace(surface, dynamicPaint_canvas_mesh_get(surface->canvas));
+ }
- /* update bake data */
- dynamicPaint_generateBakeData(surface, depsgraph, cObject);
+ /* update bake data */
+ dynamicPaint_generateBakeData(surface, depsgraph, cObject);
- /* don't do substeps for first frame */
- if (surface->substeps && (frame != surface->start_frame)) {
- int st;
- timescale = 1.0f / (surface->substeps + 1);
+ /* don't do substeps for first frame */
+ if (surface->substeps && (frame != surface->start_frame)) {
+ int st;
+ timescale = 1.0f / (surface->substeps + 1);
- for (st = 1; st <= surface->substeps; st++) {
- float subframe = ((float) st) / (surface->substeps + 1);
- if (!dynamicPaint_doStep(depsgraph, scene, cObject, surface, timescale, subframe))
- return 0;
- }
- }
+ for (st = 1; st <= surface->substeps; st++) {
+ float subframe = ((float)st) / (surface->substeps + 1);
+ if (!dynamicPaint_doStep(depsgraph, scene, cObject, surface, timescale, subframe))
+ return 0;
+ }
+ }
- return dynamicPaint_doStep(depsgraph, scene, cObject, surface, timescale, 0.0f);
+ return dynamicPaint_doStep(depsgraph, scene, cObject, surface, timescale, 0.0f);
}
diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c
index c46691901f0..e2b63b650fb 100644
--- a/source/blender/blenkernel/intern/editderivedmesh.c
+++ b/source/blender/blenkernel/intern/editderivedmesh.c
@@ -60,490 +60,487 @@
static void axis_from_enum_v3(float v[3], const char axis)
{
- zero_v3(v);
- if (axis < 3) v[axis] = 1.0f;
- else v[axis - 3] = -1.0f;
+ zero_v3(v);
+ if (axis < 3)
+ v[axis] = 1.0f;
+ else
+ v[axis - 3] = -1.0f;
}
-static void statvis_calc_overhang(
- BMEditMesh *em,
- const float (*polyNos)[3],
- /* values for calculating */
- const float min, const float max, const char axis,
- /* result */
- unsigned char (*r_face_colors)[4])
+static void statvis_calc_overhang(BMEditMesh *em,
+ const float (*polyNos)[3],
+ /* values for calculating */
+ const float min,
+ const float max,
+ const char axis,
+ /* result */
+ unsigned char (*r_face_colors)[4])
{
- BMIter iter;
- BMesh *bm = em->bm;
- BMFace *f;
- float dir[3];
- int index;
- const float minmax_irange = 1.0f / (max - min);
- bool is_max;
-
- /* fallback */
- unsigned char col_fallback[4] = {64, 64, 64, 255}; /* gray */
- unsigned char col_fallback_max[4] = {0, 0, 0, 255}; /* max color */
-
- BLI_assert(min <= max);
-
- axis_from_enum_v3(dir, axis);
-
- if (LIKELY(em->ob)) {
- mul_transposed_mat3_m4_v3(em->ob->obmat, dir);
- normalize_v3(dir);
- }
-
- /* fallback max */
- {
- float fcol[3];
- BKE_defvert_weight_to_rgb(fcol, 1.0f);
- rgb_float_to_uchar(col_fallback_max, fcol);
- }
-
- /* now convert into global space */
- BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, index) {
- float fac = angle_normalized_v3v3(polyNos ? polyNos[index] : f->no, dir) / (float)M_PI;
-
- /* remap */
- if ((is_max = (fac <= max)) && (fac >= min)) {
- float fcol[3];
- fac = (fac - min) * minmax_irange;
- fac = 1.0f - fac;
- CLAMP(fac, 0.0f, 1.0f);
- BKE_defvert_weight_to_rgb(fcol, fac);
- rgb_float_to_uchar(r_face_colors[index], fcol);
- }
- else {
- const unsigned char *fallback = is_max ? col_fallback_max : col_fallback;
- copy_v4_v4_uchar(r_face_colors[index], fallback);
- }
- }
+ BMIter iter;
+ BMesh *bm = em->bm;
+ BMFace *f;
+ float dir[3];
+ int index;
+ const float minmax_irange = 1.0f / (max - min);
+ bool is_max;
+
+ /* fallback */
+ unsigned char col_fallback[4] = {64, 64, 64, 255}; /* gray */
+ unsigned char col_fallback_max[4] = {0, 0, 0, 255}; /* max color */
+
+ BLI_assert(min <= max);
+
+ axis_from_enum_v3(dir, axis);
+
+ if (LIKELY(em->ob)) {
+ mul_transposed_mat3_m4_v3(em->ob->obmat, dir);
+ normalize_v3(dir);
+ }
+
+ /* fallback max */
+ {
+ float fcol[3];
+ BKE_defvert_weight_to_rgb(fcol, 1.0f);
+ rgb_float_to_uchar(col_fallback_max, fcol);
+ }
+
+ /* now convert into global space */
+ BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, index) {
+ float fac = angle_normalized_v3v3(polyNos ? polyNos[index] : f->no, dir) / (float)M_PI;
+
+ /* remap */
+ if ((is_max = (fac <= max)) && (fac >= min)) {
+ float fcol[3];
+ fac = (fac - min) * minmax_irange;
+ fac = 1.0f - fac;
+ CLAMP(fac, 0.0f, 1.0f);
+ BKE_defvert_weight_to_rgb(fcol, fac);
+ rgb_float_to_uchar(r_face_colors[index], fcol);
+ }
+ else {
+ const unsigned char *fallback = is_max ? col_fallback_max : col_fallback;
+ copy_v4_v4_uchar(r_face_colors[index], fallback);
+ }
+ }
}
/* so we can use jitter values for face interpolation */
static void uv_from_jitter_v2(float uv[2])
{
- uv[0] += 0.5f;
- uv[1] += 0.5f;
- if (uv[0] + uv[1] > 1.0f) {
- uv[0] = 1.0f - uv[0];
- uv[1] = 1.0f - uv[1];
- }
-
- CLAMP(uv[0], 0.0f, 1.0f);
- CLAMP(uv[1], 0.0f, 1.0f);
+ uv[0] += 0.5f;
+ uv[1] += 0.5f;
+ if (uv[0] + uv[1] > 1.0f) {
+ uv[0] = 1.0f - uv[0];
+ uv[1] = 1.0f - uv[1];
+ }
+
+ CLAMP(uv[0], 0.0f, 1.0f);
+ CLAMP(uv[1], 0.0f, 1.0f);
}
-static void statvis_calc_thickness(
- BMEditMesh *em,
- const float (*vertexCos)[3],
- /* values for calculating */
- const float min, const float max, const int samples,
- /* result */
- unsigned char (*r_face_colors)[4])
+static void statvis_calc_thickness(BMEditMesh *em,
+ const float (*vertexCos)[3],
+ /* values for calculating */
+ const float min,
+ const float max,
+ const int samples,
+ /* result */
+ unsigned char (*r_face_colors)[4])
{
- const float eps_offset = 0.00002f; /* values <= 0.00001 give errors */
- float *face_dists = (float *)r_face_colors; /* cheating */
- const bool use_jit = samples < 32;
- float jit_ofs[32][2];
- BMesh *bm = em->bm;
- const int tottri = em->tottri;
- const float minmax_irange = 1.0f / (max - min);
- int i;
-
- struct BMLoop *(*looptris)[3] = em->looptris;
-
- /* fallback */
- const unsigned char col_fallback[4] = {64, 64, 64, 255};
-
- struct BMBVHTree *bmtree;
-
- BLI_assert(min <= max);
-
- copy_vn_fl(face_dists, em->bm->totface, max);
-
- if (use_jit) {
- int j;
- BLI_assert(samples < 32);
- BLI_jitter_init(jit_ofs, samples);
-
- for (j = 0; j < samples; j++) {
- uv_from_jitter_v2(jit_ofs[j]);
- }
- }
-
- BM_mesh_elem_index_ensure(bm, BM_FACE);
- if (vertexCos) {
- BM_mesh_elem_index_ensure(bm, BM_VERT);
- }
-
- bmtree = BKE_bmbvh_new_from_editmesh(em, 0, vertexCos, false);
-
- for (i = 0; i < tottri; i++) {
- BMFace *f_hit;
- BMLoop **ltri = looptris[i];
- const int index = BM_elem_index_get(ltri[0]->f);
- const float *cos[3];
- float ray_co[3];
- float ray_no[3];
-
- if (vertexCos) {
- cos[0] = vertexCos[BM_elem_index_get(ltri[0]->v)];
- cos[1] = vertexCos[BM_elem_index_get(ltri[1]->v)];
- cos[2] = vertexCos[BM_elem_index_get(ltri[2]->v)];
- }
- else {
- cos[0] = ltri[0]->v->co;
- cos[1] = ltri[1]->v->co;
- cos[2] = ltri[2]->v->co;
- }
-
- normal_tri_v3(ray_no, cos[2], cos[1], cos[0]);
+ const float eps_offset = 0.00002f; /* values <= 0.00001 give errors */
+ float *face_dists = (float *)r_face_colors; /* cheating */
+ const bool use_jit = samples < 32;
+ float jit_ofs[32][2];
+ BMesh *bm = em->bm;
+ const int tottri = em->tottri;
+ const float minmax_irange = 1.0f / (max - min);
+ int i;
+
+ struct BMLoop *(*looptris)[3] = em->looptris;
+
+ /* fallback */
+ const unsigned char col_fallback[4] = {64, 64, 64, 255};
+
+ struct BMBVHTree *bmtree;
+
+ BLI_assert(min <= max);
+
+ copy_vn_fl(face_dists, em->bm->totface, max);
+
+ if (use_jit) {
+ int j;
+ BLI_assert(samples < 32);
+ BLI_jitter_init(jit_ofs, samples);
+
+ for (j = 0; j < samples; j++) {
+ uv_from_jitter_v2(jit_ofs[j]);
+ }
+ }
+
+ BM_mesh_elem_index_ensure(bm, BM_FACE);
+ if (vertexCos) {
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+ }
+
+ bmtree = BKE_bmbvh_new_from_editmesh(em, 0, vertexCos, false);
+
+ for (i = 0; i < tottri; i++) {
+ BMFace *f_hit;
+ BMLoop **ltri = looptris[i];
+ const int index = BM_elem_index_get(ltri[0]->f);
+ const float *cos[3];
+ float ray_co[3];
+ float ray_no[3];
+
+ if (vertexCos) {
+ cos[0] = vertexCos[BM_elem_index_get(ltri[0]->v)];
+ cos[1] = vertexCos[BM_elem_index_get(ltri[1]->v)];
+ cos[2] = vertexCos[BM_elem_index_get(ltri[2]->v)];
+ }
+ else {
+ cos[0] = ltri[0]->v->co;
+ cos[1] = ltri[1]->v->co;
+ cos[2] = ltri[2]->v->co;
+ }
+
+ normal_tri_v3(ray_no, cos[2], cos[1], cos[0]);
#define FACE_RAY_TEST_ANGLE \
- f_hit = BKE_bmbvh_ray_cast(bmtree, ray_co, ray_no, 0.0f, \
- &dist, NULL, NULL); \
- if (f_hit && dist < face_dists[index]) { \
- float angle_fac = fabsf(dot_v3v3(ltri[0]->f->no, f_hit->no)); \
- angle_fac = 1.0f - angle_fac; \
- angle_fac = angle_fac * angle_fac * angle_fac; \
- angle_fac = 1.0f - angle_fac; \
- dist /= angle_fac; \
- if (dist < face_dists[index]) { \
- face_dists[index] = dist; \
- } \
- } (void)0
-
- if (use_jit) {
- int j;
- for (j = 0; j < samples; j++) {
- float dist = face_dists[index];
- interp_v3_v3v3v3_uv(ray_co, cos[0], cos[1], cos[2], jit_ofs[j]);
- madd_v3_v3fl(ray_co, ray_no, eps_offset);
-
- FACE_RAY_TEST_ANGLE;
- }
- }
- else {
- float dist = face_dists[index];
- mid_v3_v3v3v3(ray_co, cos[0], cos[1], cos[2]);
- madd_v3_v3fl(ray_co, ray_no, eps_offset);
-
- FACE_RAY_TEST_ANGLE;
- }
- }
-
- BKE_bmbvh_free(bmtree);
-
- /* convert floats into color! */
- for (i = 0; i < bm->totface; i++) {
- float fac = face_dists[i];
-
- /* important not '<=' */
- if (fac < max) {
- float fcol[3];
- fac = (fac - min) * minmax_irange;
- fac = 1.0f - fac;
- CLAMP(fac, 0.0f, 1.0f);
- BKE_defvert_weight_to_rgb(fcol, fac);
- rgb_float_to_uchar(r_face_colors[i], fcol);
- }
- else {
- copy_v4_v4_uchar(r_face_colors[i], col_fallback);
- }
- }
+ f_hit = BKE_bmbvh_ray_cast(bmtree, ray_co, ray_no, 0.0f, &dist, NULL, NULL); \
+ if (f_hit && dist < face_dists[index]) { \
+ float angle_fac = fabsf(dot_v3v3(ltri[0]->f->no, f_hit->no)); \
+ angle_fac = 1.0f - angle_fac; \
+ angle_fac = angle_fac * angle_fac * angle_fac; \
+ angle_fac = 1.0f - angle_fac; \
+ dist /= angle_fac; \
+ if (dist < face_dists[index]) { \
+ face_dists[index] = dist; \
+ } \
+ } \
+ (void)0
+
+ if (use_jit) {
+ int j;
+ for (j = 0; j < samples; j++) {
+ float dist = face_dists[index];
+ interp_v3_v3v3v3_uv(ray_co, cos[0], cos[1], cos[2], jit_ofs[j]);
+ madd_v3_v3fl(ray_co, ray_no, eps_offset);
+
+ FACE_RAY_TEST_ANGLE;
+ }
+ }
+ else {
+ float dist = face_dists[index];
+ mid_v3_v3v3v3(ray_co, cos[0], cos[1], cos[2]);
+ madd_v3_v3fl(ray_co, ray_no, eps_offset);
+
+ FACE_RAY_TEST_ANGLE;
+ }
+ }
+
+ BKE_bmbvh_free(bmtree);
+
+ /* convert floats into color! */
+ for (i = 0; i < bm->totface; i++) {
+ float fac = face_dists[i];
+
+ /* important not '<=' */
+ if (fac < max) {
+ float fcol[3];
+ fac = (fac - min) * minmax_irange;
+ fac = 1.0f - fac;
+ CLAMP(fac, 0.0f, 1.0f);
+ BKE_defvert_weight_to_rgb(fcol, fac);
+ rgb_float_to_uchar(r_face_colors[i], fcol);
+ }
+ else {
+ copy_v4_v4_uchar(r_face_colors[i], col_fallback);
+ }
+ }
}
-static void statvis_calc_intersect(
- BMEditMesh *em,
- const float (*vertexCos)[3],
- /* result */
- unsigned char (*r_face_colors)[4])
+static void statvis_calc_intersect(BMEditMesh *em,
+ const float (*vertexCos)[3],
+ /* result */
+ unsigned char (*r_face_colors)[4])
{
- BMesh *bm = em->bm;
- int i;
+ BMesh *bm = em->bm;
+ int i;
- /* fallback */
- // const char col_fallback[4] = {64, 64, 64, 255};
- float fcol[3];
- unsigned char col[3];
+ /* fallback */
+ // const char col_fallback[4] = {64, 64, 64, 255};
+ float fcol[3];
+ unsigned char col[3];
- struct BMBVHTree *bmtree;
- BVHTreeOverlap *overlap;
- unsigned int overlap_len;
+ struct BMBVHTree *bmtree;
+ BVHTreeOverlap *overlap;
+ unsigned int overlap_len;
- memset(r_face_colors, 64, sizeof(int) * em->bm->totface);
+ memset(r_face_colors, 64, sizeof(int) * em->bm->totface);
- BM_mesh_elem_index_ensure(bm, BM_FACE);
- if (vertexCos) {
- BM_mesh_elem_index_ensure(bm, BM_VERT);
- }
+ BM_mesh_elem_index_ensure(bm, BM_FACE);
+ if (vertexCos) {
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+ }
- bmtree = BKE_bmbvh_new_from_editmesh(em, 0, vertexCos, false);
+ bmtree = BKE_bmbvh_new_from_editmesh(em, 0, vertexCos, false);
- overlap = BKE_bmbvh_overlap(bmtree, bmtree, &overlap_len);
+ overlap = BKE_bmbvh_overlap(bmtree, bmtree, &overlap_len);
- /* same for all faces */
- BKE_defvert_weight_to_rgb(fcol, 1.0f);
- rgb_float_to_uchar(col, fcol);
+ /* same for all faces */
+ BKE_defvert_weight_to_rgb(fcol, 1.0f);
+ rgb_float_to_uchar(col, fcol);
- if (overlap) {
- for (i = 0; i < overlap_len; i++) {
- BMFace *f_hit_pair[2] = {
- em->looptris[overlap[i].indexA][0]->f,
- em->looptris[overlap[i].indexB][0]->f,
- };
- int j;
+ if (overlap) {
+ for (i = 0; i < overlap_len; i++) {
+ BMFace *f_hit_pair[2] = {
+ em->looptris[overlap[i].indexA][0]->f,
+ em->looptris[overlap[i].indexB][0]->f,
+ };
+ int j;
- for (j = 0; j < 2; j++) {
- BMFace *f_hit = f_hit_pair[j];
- int index;
+ for (j = 0; j < 2; j++) {
+ BMFace *f_hit = f_hit_pair[j];
+ int index;
- index = BM_elem_index_get(f_hit);
+ index = BM_elem_index_get(f_hit);
- copy_v3_v3_uchar(r_face_colors[index], col);
- }
- }
- MEM_freeN(overlap);
- }
+ copy_v3_v3_uchar(r_face_colors[index], col);
+ }
+ }
+ MEM_freeN(overlap);
+ }
- BKE_bmbvh_free(bmtree);
+ BKE_bmbvh_free(bmtree);
}
-static void statvis_calc_distort(
- BMEditMesh *em,
- const float (*vertexCos)[3], const float (*polyNos)[3],
- /* values for calculating */
- const float min, const float max,
- /* result */
- unsigned char (*r_face_colors)[4])
+static void statvis_calc_distort(BMEditMesh *em,
+ const float (*vertexCos)[3],
+ const float (*polyNos)[3],
+ /* values for calculating */
+ const float min,
+ const float max,
+ /* result */
+ unsigned char (*r_face_colors)[4])
{
- BMIter iter;
- BMesh *bm = em->bm;
- BMFace *f;
- const float *f_no;
- int index;
- const float minmax_irange = 1.0f / (max - min);
-
- /* fallback */
- const unsigned char col_fallback[4] = {64, 64, 64, 255};
-
- /* now convert into global space */
- BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, index) {
- float fac;
-
- if (f->len == 3) {
- fac = -1.0f;
- }
- else {
- BMLoop *l_iter, *l_first;
- if (vertexCos) {
- f_no = polyNos[index];
- }
- else {
- f_no = f->no;
- }
-
- fac = 0.0f;
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- float no_corner[3];
- if (vertexCos) {
- normal_tri_v3(no_corner,
- vertexCos[BM_elem_index_get(l_iter->prev->v)],
- vertexCos[BM_elem_index_get(l_iter->v)],
- vertexCos[BM_elem_index_get(l_iter->next->v)]);
- }
- else {
- BM_loop_calc_face_normal_safe(l_iter, no_corner);
- }
- /* simple way to detect (what is most likely) concave */
- if (dot_v3v3(f_no, no_corner) < 0.0f) {
- negate_v3(no_corner);
- }
- fac = max_ff(fac, angle_normalized_v3v3(f_no, no_corner));
- } while ((l_iter = l_iter->next) != l_first);
- fac *= 2.0f;
- }
-
- /* remap */
- if (fac >= min) {
- float fcol[3];
- fac = (fac - min) * minmax_irange;
- CLAMP(fac, 0.0f, 1.0f);
- BKE_defvert_weight_to_rgb(fcol, fac);
- rgb_float_to_uchar(r_face_colors[index], fcol);
- }
- else {
- copy_v4_v4_uchar(r_face_colors[index], col_fallback);
- }
- }
+ BMIter iter;
+ BMesh *bm = em->bm;
+ BMFace *f;
+ const float *f_no;
+ int index;
+ const float minmax_irange = 1.0f / (max - min);
+
+ /* fallback */
+ const unsigned char col_fallback[4] = {64, 64, 64, 255};
+
+ /* now convert into global space */
+ BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, index) {
+ float fac;
+
+ if (f->len == 3) {
+ fac = -1.0f;
+ }
+ else {
+ BMLoop *l_iter, *l_first;
+ if (vertexCos) {
+ f_no = polyNos[index];
+ }
+ else {
+ f_no = f->no;
+ }
+
+ fac = 0.0f;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ float no_corner[3];
+ if (vertexCos) {
+ normal_tri_v3(no_corner,
+ vertexCos[BM_elem_index_get(l_iter->prev->v)],
+ vertexCos[BM_elem_index_get(l_iter->v)],
+ vertexCos[BM_elem_index_get(l_iter->next->v)]);
+ }
+ else {
+ BM_loop_calc_face_normal_safe(l_iter, no_corner);
+ }
+ /* simple way to detect (what is most likely) concave */
+ if (dot_v3v3(f_no, no_corner) < 0.0f) {
+ negate_v3(no_corner);
+ }
+ fac = max_ff(fac, angle_normalized_v3v3(f_no, no_corner));
+ } while ((l_iter = l_iter->next) != l_first);
+ fac *= 2.0f;
+ }
+
+ /* remap */
+ if (fac >= min) {
+ float fcol[3];
+ fac = (fac - min) * minmax_irange;
+ CLAMP(fac, 0.0f, 1.0f);
+ BKE_defvert_weight_to_rgb(fcol, fac);
+ rgb_float_to_uchar(r_face_colors[index], fcol);
+ }
+ else {
+ copy_v4_v4_uchar(r_face_colors[index], col_fallback);
+ }
+ }
}
-static void statvis_calc_sharp(
- BMEditMesh *em,
- const float (*vertexCos)[3],
- /* values for calculating */
- const float min, const float max,
- /* result */
- unsigned char (*r_vert_colors)[4])
+static void statvis_calc_sharp(BMEditMesh *em,
+ const float (*vertexCos)[3],
+ /* values for calculating */
+ const float min,
+ const float max,
+ /* result */
+ unsigned char (*r_vert_colors)[4])
{
- float *vert_angles = (float *)r_vert_colors; /* cheating */
- BMIter iter;
- BMesh *bm = em->bm;
- BMEdge *e;
- //float f_no[3];
- const float minmax_irange = 1.0f / (max - min);
- int i;
-
- /* fallback */
- const unsigned char col_fallback[4] = {64, 64, 64, 255};
-
- (void)vertexCos; /* TODO */
-
- copy_vn_fl(vert_angles, em->bm->totvert, -M_PI);
-
- /* first assign float values to verts */
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- float angle = BM_edge_calc_face_angle_signed(e);
- float *col1 = &vert_angles[BM_elem_index_get(e->v1)];
- float *col2 = &vert_angles[BM_elem_index_get(e->v2)];
- *col1 = max_ff(*col1, angle);
- *col2 = max_ff(*col2, angle);
- }
-
- /* convert floats into color! */
- for (i = 0; i < bm->totvert; i++) {
- float fac = vert_angles[i];
-
- /* important not '<=' */
- if (fac > min) {
- float fcol[3];
- fac = (fac - min) * minmax_irange;
- CLAMP(fac, 0.0f, 1.0f);
- BKE_defvert_weight_to_rgb(fcol, fac);
- rgb_float_to_uchar(r_vert_colors[i], fcol);
- }
- else {
- copy_v4_v4_uchar(r_vert_colors[i], col_fallback);
- }
- }
+ float *vert_angles = (float *)r_vert_colors; /* cheating */
+ BMIter iter;
+ BMesh *bm = em->bm;
+ BMEdge *e;
+ //float f_no[3];
+ const float minmax_irange = 1.0f / (max - min);
+ int i;
+
+ /* fallback */
+ const unsigned char col_fallback[4] = {64, 64, 64, 255};
+
+ (void)vertexCos; /* TODO */
+
+ copy_vn_fl(vert_angles, em->bm->totvert, -M_PI);
+
+ /* first assign float values to verts */
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ float angle = BM_edge_calc_face_angle_signed(e);
+ float *col1 = &vert_angles[BM_elem_index_get(e->v1)];
+ float *col2 = &vert_angles[BM_elem_index_get(e->v2)];
+ *col1 = max_ff(*col1, angle);
+ *col2 = max_ff(*col2, angle);
+ }
+
+ /* convert floats into color! */
+ for (i = 0; i < bm->totvert; i++) {
+ float fac = vert_angles[i];
+
+ /* important not '<=' */
+ if (fac > min) {
+ float fcol[3];
+ fac = (fac - min) * minmax_irange;
+ CLAMP(fac, 0.0f, 1.0f);
+ BKE_defvert_weight_to_rgb(fcol, fac);
+ rgb_float_to_uchar(r_vert_colors[i], fcol);
+ }
+ else {
+ copy_v4_v4_uchar(r_vert_colors[i], col_fallback);
+ }
+ }
}
-void BKE_editmesh_statvis_calc(
- BMEditMesh *em, EditMeshData *emd,
- const MeshStatVis *statvis)
+void BKE_editmesh_statvis_calc(BMEditMesh *em, EditMeshData *emd, const MeshStatVis *statvis)
{
- switch (statvis->type) {
- case SCE_STATVIS_OVERHANG:
- {
- BKE_editmesh_color_ensure(em, BM_FACE);
- statvis_calc_overhang(
- em, emd ? emd->polyNos : NULL,
- statvis->overhang_min / (float)M_PI,
- statvis->overhang_max / (float)M_PI,
- statvis->overhang_axis,
- em->derivedFaceColor);
- break;
- }
- case SCE_STATVIS_THICKNESS:
- {
- const float scale = 1.0f / mat4_to_scale(em->ob->obmat);
- BKE_editmesh_color_ensure(em, BM_FACE);
- statvis_calc_thickness(
- em, emd ? emd->vertexCos : NULL,
- statvis->thickness_min * scale,
- statvis->thickness_max * scale,
- statvis->thickness_samples,
- em->derivedFaceColor);
- break;
- }
- case SCE_STATVIS_INTERSECT:
- {
- BKE_editmesh_color_ensure(em, BM_FACE);
- statvis_calc_intersect(
- em, emd ? emd->vertexCos : NULL,
- em->derivedFaceColor);
- break;
- }
- case SCE_STATVIS_DISTORT:
- {
- BKE_editmesh_color_ensure(em, BM_FACE);
-
- if (emd) {
- BKE_editmesh_cache_ensure_poly_normals(em, emd);
- }
-
- statvis_calc_distort(
- em, emd ? emd->vertexCos : NULL, emd ? emd->polyNos : NULL,
- statvis->distort_min,
- statvis->distort_max,
- em->derivedFaceColor);
- break;
- }
- case SCE_STATVIS_SHARP:
- {
- BKE_editmesh_color_ensure(em, BM_VERT);
- statvis_calc_sharp(
- em, emd ? emd->vertexCos : NULL,
- statvis->sharp_min,
- statvis->sharp_max,
- /* in this case they are vertex colors */
- em->derivedVertColor);
- break;
- }
- }
+ switch (statvis->type) {
+ case SCE_STATVIS_OVERHANG: {
+ BKE_editmesh_color_ensure(em, BM_FACE);
+ statvis_calc_overhang(em,
+ emd ? emd->polyNos : NULL,
+ statvis->overhang_min / (float)M_PI,
+ statvis->overhang_max / (float)M_PI,
+ statvis->overhang_axis,
+ em->derivedFaceColor);
+ break;
+ }
+ case SCE_STATVIS_THICKNESS: {
+ const float scale = 1.0f / mat4_to_scale(em->ob->obmat);
+ BKE_editmesh_color_ensure(em, BM_FACE);
+ statvis_calc_thickness(em,
+ emd ? emd->vertexCos : NULL,
+ statvis->thickness_min * scale,
+ statvis->thickness_max * scale,
+ statvis->thickness_samples,
+ em->derivedFaceColor);
+ break;
+ }
+ case SCE_STATVIS_INTERSECT: {
+ BKE_editmesh_color_ensure(em, BM_FACE);
+ statvis_calc_intersect(em, emd ? emd->vertexCos : NULL, em->derivedFaceColor);
+ break;
+ }
+ case SCE_STATVIS_DISTORT: {
+ BKE_editmesh_color_ensure(em, BM_FACE);
+
+ if (emd) {
+ BKE_editmesh_cache_ensure_poly_normals(em, emd);
+ }
+
+ statvis_calc_distort(em,
+ emd ? emd->vertexCos : NULL,
+ emd ? emd->polyNos : NULL,
+ statvis->distort_min,
+ statvis->distort_max,
+ em->derivedFaceColor);
+ break;
+ }
+ case SCE_STATVIS_SHARP: {
+ BKE_editmesh_color_ensure(em, BM_VERT);
+ statvis_calc_sharp(em,
+ emd ? emd->vertexCos : NULL,
+ statvis->sharp_min,
+ statvis->sharp_max,
+ /* in this case they are vertex colors */
+ em->derivedVertColor);
+ break;
+ }
+ }
}
-
-
/* -------------------------------------------------------------------- */
/* Editmesh Vert Coords */
struct CageUserData {
- int totvert;
- float (*cos_cage)[3];
- BLI_bitmap *visit_bitmap;
+ int totvert;
+ float (*cos_cage)[3];
+ BLI_bitmap *visit_bitmap;
};
-static void cage_mapped_verts_callback(
- void *userData, int index, const float co[3],
- const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
+static void cage_mapped_verts_callback(void *userData,
+ int index,
+ const float co[3],
+ const float UNUSED(no_f[3]),
+ const short UNUSED(no_s[3]))
{
- struct CageUserData *data = userData;
+ struct CageUserData *data = userData;
- if ((index >= 0 && index < data->totvert) && (!BLI_BITMAP_TEST(data->visit_bitmap, index))) {
- BLI_BITMAP_ENABLE(data->visit_bitmap, index);
- copy_v3_v3(data->cos_cage[index], co);
- }
+ if ((index >= 0 && index < data->totvert) && (!BLI_BITMAP_TEST(data->visit_bitmap, index))) {
+ BLI_BITMAP_ENABLE(data->visit_bitmap, index);
+ copy_v3_v3(data->cos_cage[index], co);
+ }
}
-float (*BKE_editmesh_vertexCos_get(struct Depsgraph *depsgraph, BMEditMesh *em, Scene *scene, int *r_numVerts))[3]
+float (*BKE_editmesh_vertexCos_get(
+ struct Depsgraph *depsgraph, BMEditMesh *em, Scene *scene, int *r_numVerts))[3]
{
- Mesh *cage;
- BLI_bitmap *visit_bitmap;
- struct CageUserData data;
- float (*cos_cage)[3];
+ Mesh *cage;
+ BLI_bitmap *visit_bitmap;
+ struct CageUserData data;
+ float(*cos_cage)[3];
- cage = editbmesh_get_eval_cage(depsgraph, scene, em->ob, em, &CD_MASK_BAREMESH);
- cos_cage = MEM_callocN(sizeof(*cos_cage) * em->bm->totvert, "bmbvh cos_cage");
+ cage = editbmesh_get_eval_cage(depsgraph, scene, em->ob, em, &CD_MASK_BAREMESH);
+ cos_cage = MEM_callocN(sizeof(*cos_cage) * em->bm->totvert, "bmbvh cos_cage");
- /* when initializing cage verts, we only want the first cage coordinate for each vertex,
- * so that e.g. mirror or array use original vertex coordinates and not mirrored or duplicate */
- visit_bitmap = BLI_BITMAP_NEW(em->bm->totvert, __func__);
+ /* when initializing cage verts, we only want the first cage coordinate for each vertex,
+ * so that e.g. mirror or array use original vertex coordinates and not mirrored or duplicate */
+ visit_bitmap = BLI_BITMAP_NEW(em->bm->totvert, __func__);
- data.totvert = em->bm->totvert;
- data.cos_cage = cos_cage;
- data.visit_bitmap = visit_bitmap;
+ data.totvert = em->bm->totvert;
+ data.cos_cage = cos_cage;
+ data.visit_bitmap = visit_bitmap;
- BKE_mesh_foreach_mapped_vert(cage, cage_mapped_verts_callback, &data, MESH_FOREACH_NOP);
+ BKE_mesh_foreach_mapped_vert(cage, cage_mapped_verts_callback, &data, MESH_FOREACH_NOP);
- MEM_freeN(visit_bitmap);
+ MEM_freeN(visit_bitmap);
- if (r_numVerts) {
- *r_numVerts = em->bm->totvert;
- }
+ if (r_numVerts) {
+ *r_numVerts = em->bm->totvert;
+ }
- return cos_cage;
+ return cos_cage;
}
diff --git a/source/blender/blenkernel/intern/editlattice.c b/source/blender/blenkernel/intern/editlattice.c
index d5b34b27207..12e737bbaa8 100644
--- a/source/blender/blenkernel/intern/editlattice.c
+++ b/source/blender/blenkernel/intern/editlattice.c
@@ -37,107 +37,107 @@
void BKE_editlattice_free(Object *ob)
{
- Lattice *lt = ob->data;
-
- if (lt->editlatt) {
- Lattice *editlt = lt->editlatt->latt;
-
- if (editlt->def) {
- MEM_freeN(editlt->def);
- }
- if (editlt->dvert) {
- BKE_defvert_array_free(editlt->dvert, editlt->pntsu * editlt->pntsv * editlt->pntsw);
- }
- MEM_freeN(editlt);
- MEM_freeN(lt->editlatt);
-
- lt->editlatt = NULL;
- }
+ Lattice *lt = ob->data;
+
+ if (lt->editlatt) {
+ Lattice *editlt = lt->editlatt->latt;
+
+ if (editlt->def) {
+ MEM_freeN(editlt->def);
+ }
+ if (editlt->dvert) {
+ BKE_defvert_array_free(editlt->dvert, editlt->pntsu * editlt->pntsv * editlt->pntsw);
+ }
+ MEM_freeN(editlt);
+ MEM_freeN(lt->editlatt);
+
+ lt->editlatt = NULL;
+ }
}
void BKE_editlattice_make(Object *obedit)
{
- Lattice *lt = obedit->data;
- KeyBlock *actkey;
-
- BKE_editlattice_free(obedit);
-
- actkey = BKE_keyblock_from_object(obedit);
- if (actkey) {
- BKE_keyblock_convert_to_lattice(actkey, lt);
- }
- lt->editlatt = MEM_callocN(sizeof(EditLatt), "editlatt");
- lt->editlatt->latt = MEM_dupallocN(lt);
- lt->editlatt->latt->def = MEM_dupallocN(lt->def);
-
- if (lt->dvert) {
- int tot = lt->pntsu * lt->pntsv * lt->pntsw;
- lt->editlatt->latt->dvert = MEM_mallocN(sizeof(MDeformVert) * tot, "Lattice MDeformVert");
- BKE_defvert_array_copy(lt->editlatt->latt->dvert, lt->dvert, tot);
- }
-
- if (lt->key) {
- lt->editlatt->shapenr = obedit->shapenr;
- }
+ Lattice *lt = obedit->data;
+ KeyBlock *actkey;
+
+ BKE_editlattice_free(obedit);
+
+ actkey = BKE_keyblock_from_object(obedit);
+ if (actkey) {
+ BKE_keyblock_convert_to_lattice(actkey, lt);
+ }
+ lt->editlatt = MEM_callocN(sizeof(EditLatt), "editlatt");
+ lt->editlatt->latt = MEM_dupallocN(lt);
+ lt->editlatt->latt->def = MEM_dupallocN(lt->def);
+
+ if (lt->dvert) {
+ int tot = lt->pntsu * lt->pntsv * lt->pntsw;
+ lt->editlatt->latt->dvert = MEM_mallocN(sizeof(MDeformVert) * tot, "Lattice MDeformVert");
+ BKE_defvert_array_copy(lt->editlatt->latt->dvert, lt->dvert, tot);
+ }
+
+ if (lt->key) {
+ lt->editlatt->shapenr = obedit->shapenr;
+ }
}
void BKE_editlattice_load(Object *obedit)
{
- Lattice *lt, *editlt;
- KeyBlock *actkey;
- BPoint *bp;
- float *fp;
- int tot;
-
- lt = obedit->data;
- editlt = lt->editlatt->latt;
-
- if (lt->editlatt->shapenr) {
- actkey = BLI_findlink(&lt->key->block, lt->editlatt->shapenr - 1);
-
- /* active key: vertices */
- tot = editlt->pntsu * editlt->pntsv * editlt->pntsw;
-
- if (actkey->data) {
- MEM_freeN(actkey->data);
- }
-
- fp = actkey->data = MEM_callocN(lt->key->elemsize * tot, "actkey->data");
- actkey->totelem = tot;
-
- bp = editlt->def;
- while (tot--) {
- copy_v3_v3(fp, bp->vec);
- fp += 3;
- bp++;
- }
- }
- else {
- MEM_freeN(lt->def);
-
- lt->def = MEM_dupallocN(editlt->def);
-
- lt->flag = editlt->flag;
-
- lt->pntsu = editlt->pntsu;
- lt->pntsv = editlt->pntsv;
- lt->pntsw = editlt->pntsw;
-
- lt->typeu = editlt->typeu;
- lt->typev = editlt->typev;
- lt->typew = editlt->typew;
- lt->actbp = editlt->actbp;
- }
-
- if (lt->dvert) {
- BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw);
- lt->dvert = NULL;
- }
-
- if (editlt->dvert) {
- tot = lt->pntsu * lt->pntsv * lt->pntsw;
-
- lt->dvert = MEM_mallocN(sizeof(MDeformVert) * tot, "Lattice MDeformVert");
- BKE_defvert_array_copy(lt->dvert, editlt->dvert, tot);
- }
+ Lattice *lt, *editlt;
+ KeyBlock *actkey;
+ BPoint *bp;
+ float *fp;
+ int tot;
+
+ lt = obedit->data;
+ editlt = lt->editlatt->latt;
+
+ if (lt->editlatt->shapenr) {
+ actkey = BLI_findlink(&lt->key->block, lt->editlatt->shapenr - 1);
+
+ /* active key: vertices */
+ tot = editlt->pntsu * editlt->pntsv * editlt->pntsw;
+
+ if (actkey->data) {
+ MEM_freeN(actkey->data);
+ }
+
+ fp = actkey->data = MEM_callocN(lt->key->elemsize * tot, "actkey->data");
+ actkey->totelem = tot;
+
+ bp = editlt->def;
+ while (tot--) {
+ copy_v3_v3(fp, bp->vec);
+ fp += 3;
+ bp++;
+ }
+ }
+ else {
+ MEM_freeN(lt->def);
+
+ lt->def = MEM_dupallocN(editlt->def);
+
+ lt->flag = editlt->flag;
+
+ lt->pntsu = editlt->pntsu;
+ lt->pntsv = editlt->pntsv;
+ lt->pntsw = editlt->pntsw;
+
+ lt->typeu = editlt->typeu;
+ lt->typev = editlt->typev;
+ lt->typew = editlt->typew;
+ lt->actbp = editlt->actbp;
+ }
+
+ if (lt->dvert) {
+ BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw);
+ lt->dvert = NULL;
+ }
+
+ if (editlt->dvert) {
+ tot = lt->pntsu * lt->pntsv * lt->pntsw;
+
+ lt->dvert = MEM_mallocN(sizeof(MDeformVert) * tot, "Lattice MDeformVert");
+ BKE_defvert_array_copy(lt->dvert, editlt->dvert, tot);
+ }
}
diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c
index c1f5d30cad7..9c412c3c1b0 100644
--- a/source/blender/blenkernel/intern/editmesh.c
+++ b/source/blender/blenkernel/intern/editmesh.c
@@ -33,43 +33,42 @@
#include "BKE_cdderivedmesh.h"
#include "BKE_library.h"
-
BMEditMesh *BKE_editmesh_create(BMesh *bm, const bool do_tessellate)
{
- BMEditMesh *em = MEM_callocN(sizeof(BMEditMesh), __func__);
+ BMEditMesh *em = MEM_callocN(sizeof(BMEditMesh), __func__);
- em->bm = bm;
- if (do_tessellate) {
- BKE_editmesh_tessface_calc(em);
- }
+ em->bm = bm;
+ if (do_tessellate) {
+ BKE_editmesh_tessface_calc(em);
+ }
- return em;
+ return em;
}
BMEditMesh *BKE_editmesh_copy(BMEditMesh *em)
{
- BMEditMesh *em_copy = MEM_callocN(sizeof(BMEditMesh), __func__);
- *em_copy = *em;
+ BMEditMesh *em_copy = MEM_callocN(sizeof(BMEditMesh), __func__);
+ *em_copy = *em;
- em_copy->mesh_eval_cage = em_copy->mesh_eval_final = NULL;
+ em_copy->mesh_eval_cage = em_copy->mesh_eval_final = NULL;
- em_copy->derivedVertColor = NULL;
- em_copy->derivedVertColorLen = 0;
- em_copy->derivedFaceColor = NULL;
- em_copy->derivedFaceColorLen = 0;
+ em_copy->derivedVertColor = NULL;
+ em_copy->derivedVertColorLen = 0;
+ em_copy->derivedFaceColor = NULL;
+ em_copy->derivedFaceColorLen = 0;
- em_copy->bm = BM_mesh_copy(em->bm);
+ em_copy->bm = BM_mesh_copy(em->bm);
- /* The tessellation is NOT calculated on the copy here,
- * because currently all the callers of this function use
- * it to make a backup copy of the BMEditMesh to restore
- * it in the case of errors in an operation. For perf
- * reasons, in that case it makes more sense to do the
- * tessellation only when/if that copy ends up getting
- * used.*/
- em_copy->looptris = NULL;
+ /* The tessellation is NOT calculated on the copy here,
+ * because currently all the callers of this function use
+ * it to make a backup copy of the BMEditMesh to restore
+ * it in the case of errors in an operation. For perf
+ * reasons, in that case it makes more sense to do the
+ * tessellation only when/if that copy ends up getting
+ * used.*/
+ em_copy->looptris = NULL;
- return em_copy;
+ return em_copy;
}
/**
@@ -80,163 +79,167 @@ BMEditMesh *BKE_editmesh_copy(BMEditMesh *em)
*/
BMEditMesh *BKE_editmesh_from_object(Object *ob)
{
- BLI_assert(ob->type == OB_MESH);
- /* sanity check */
+ BLI_assert(ob->type == OB_MESH);
+ /* sanity check */
#if 0 /* disable in mutlti-object edit. */
-#ifndef NDEBUG
- if (((Mesh *)ob->data)->edit_mesh) {
- BLI_assert(((Mesh *)ob->data)->edit_mesh->ob == ob);
- }
-#endif
+# ifndef NDEBUG
+ if (((Mesh *)ob->data)->edit_mesh) {
+ BLI_assert(((Mesh *)ob->data)->edit_mesh->ob == ob);
+ }
+# endif
#endif
- return ((Mesh *)ob->data)->edit_mesh;
+ return ((Mesh *)ob->data)->edit_mesh;
}
-
static void editmesh_tessface_calc_intern(BMEditMesh *em)
{
- /* allocating space before calculating the tessellation */
-
-
- BMesh *bm = em->bm;
-
- /* this assumes all faces can be scan-filled, which isn't always true,
- * worst case we over alloc a little which is acceptable */
- const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
- const int looptris_tot_prev_alloc = em->looptris ? (MEM_allocN_len(em->looptris) / sizeof(*em->looptris)) : 0;
-
- BMLoop *(*looptris)[3];
-
- /* this means no reallocs for quad dominant models, for */
- if ((em->looptris != NULL) &&
- /* (*em->tottri >= looptris_tot)) */
- /* check against alloc'd size incase we over alloc'd a little */
- ((looptris_tot_prev_alloc >= looptris_tot) && (looptris_tot_prev_alloc <= looptris_tot * 2)))
- {
- looptris = em->looptris;
- }
- else {
- if (em->looptris) MEM_freeN(em->looptris);
- looptris = MEM_mallocN(sizeof(*looptris) * looptris_tot, __func__);
- }
-
- em->looptris = looptris;
-
- /* after allocating the em->looptris, we're ready to tessellate */
- BM_mesh_calc_tessellation(em->bm, em->looptris, &em->tottri);
-
+ /* allocating space before calculating the tessellation */
+
+ BMesh *bm = em->bm;
+
+ /* this assumes all faces can be scan-filled, which isn't always true,
+ * worst case we over alloc a little which is acceptable */
+ const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
+ const int looptris_tot_prev_alloc = em->looptris ?
+ (MEM_allocN_len(em->looptris) / sizeof(*em->looptris)) :
+ 0;
+
+ BMLoop *(*looptris)[3];
+
+ /* this means no reallocs for quad dominant models, for */
+ if ((em->looptris != NULL) &&
+ /* (*em->tottri >= looptris_tot)) */
+ /* check against alloc'd size incase we over alloc'd a little */
+ ((looptris_tot_prev_alloc >= looptris_tot) &&
+ (looptris_tot_prev_alloc <= looptris_tot * 2))) {
+ looptris = em->looptris;
+ }
+ else {
+ if (em->looptris)
+ MEM_freeN(em->looptris);
+ looptris = MEM_mallocN(sizeof(*looptris) * looptris_tot, __func__);
+ }
+
+ em->looptris = looptris;
+
+ /* after allocating the em->looptris, we're ready to tessellate */
+ BM_mesh_calc_tessellation(em->bm, em->looptris, &em->tottri);
}
void BKE_editmesh_tessface_calc(BMEditMesh *em)
{
- editmesh_tessface_calc_intern(em);
+ editmesh_tessface_calc_intern(em);
- /* commented because editbmesh_build_data() ensures we get tessfaces */
+ /* commented because editbmesh_build_data() ensures we get tessfaces */
#if 0
- if (em->mesh_eval_final && em->mesh_eval_final == em->mesh_eval_cage) {
- BKE_mesh_runtime_looptri_ensure(em->mesh_eval_final);
- }
- else if (em->mesh_eval_final) {
- BKE_mesh_runtime_looptri_ensure(em->mesh_eval_final);
- BKE_mesh_runtime_looptri_ensure(em->mesh_eval_cage);
- }
+ if (em->mesh_eval_final && em->mesh_eval_final == em->mesh_eval_cage) {
+ BKE_mesh_runtime_looptri_ensure(em->mesh_eval_final);
+ }
+ else if (em->mesh_eval_final) {
+ BKE_mesh_runtime_looptri_ensure(em->mesh_eval_final);
+ BKE_mesh_runtime_looptri_ensure(em->mesh_eval_cage);
+ }
#endif
}
void BKE_editmesh_free_derivedmesh(BMEditMesh *em)
{
- if (em->mesh_eval_cage) {
- BKE_id_free(NULL, em->mesh_eval_cage);
- }
- if (em->mesh_eval_final && em->mesh_eval_final != em->mesh_eval_cage) {
- BKE_id_free(NULL, em->mesh_eval_final);
- }
- em->mesh_eval_cage = em->mesh_eval_final = NULL;
+ if (em->mesh_eval_cage) {
+ BKE_id_free(NULL, em->mesh_eval_cage);
+ }
+ if (em->mesh_eval_final && em->mesh_eval_final != em->mesh_eval_cage) {
+ BKE_id_free(NULL, em->mesh_eval_final);
+ }
+ em->mesh_eval_cage = em->mesh_eval_final = NULL;
}
/*does not free the BMEditMesh struct itself*/
void BKE_editmesh_free(BMEditMesh *em)
{
- BKE_editmesh_free_derivedmesh(em);
+ BKE_editmesh_free_derivedmesh(em);
- BKE_editmesh_color_free(em);
+ BKE_editmesh_color_free(em);
- if (em->looptris) MEM_freeN(em->looptris);
+ if (em->looptris)
+ MEM_freeN(em->looptris);
- if (em->bm)
- BM_mesh_free(em->bm);
+ if (em->bm)
+ BM_mesh_free(em->bm);
}
void BKE_editmesh_color_free(BMEditMesh *em)
{
- if (em->derivedVertColor) MEM_freeN(em->derivedVertColor);
- if (em->derivedFaceColor) MEM_freeN(em->derivedFaceColor);
- em->derivedVertColor = NULL;
- em->derivedFaceColor = NULL;
-
- em->derivedVertColorLen = 0;
- em->derivedFaceColorLen = 0;
-
+ if (em->derivedVertColor)
+ MEM_freeN(em->derivedVertColor);
+ if (em->derivedFaceColor)
+ MEM_freeN(em->derivedFaceColor);
+ em->derivedVertColor = NULL;
+ em->derivedFaceColor = NULL;
+
+ em->derivedVertColorLen = 0;
+ em->derivedFaceColorLen = 0;
}
void BKE_editmesh_color_ensure(BMEditMesh *em, const char htype)
{
- switch (htype) {
- case BM_VERT:
- if (em->derivedVertColorLen != em->bm->totvert) {
- BKE_editmesh_color_free(em);
- em->derivedVertColor = MEM_mallocN(sizeof(*em->derivedVertColor) * em->bm->totvert, __func__);
- em->derivedVertColorLen = em->bm->totvert;
- }
- break;
- case BM_FACE:
- if (em->derivedFaceColorLen != em->bm->totface) {
- BKE_editmesh_color_free(em);
- em->derivedFaceColor = MEM_mallocN(sizeof(*em->derivedFaceColor) * em->bm->totface, __func__);
- em->derivedFaceColorLen = em->bm->totface;
- }
- break;
- default:
- BLI_assert(0);
- break;
- }
+ switch (htype) {
+ case BM_VERT:
+ if (em->derivedVertColorLen != em->bm->totvert) {
+ BKE_editmesh_color_free(em);
+ em->derivedVertColor = MEM_mallocN(sizeof(*em->derivedVertColor) * em->bm->totvert,
+ __func__);
+ em->derivedVertColorLen = em->bm->totvert;
+ }
+ break;
+ case BM_FACE:
+ if (em->derivedFaceColorLen != em->bm->totface) {
+ BKE_editmesh_color_free(em);
+ em->derivedFaceColor = MEM_mallocN(sizeof(*em->derivedFaceColor) * em->bm->totface,
+ __func__);
+ em->derivedFaceColorLen = em->bm->totface;
+ }
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
}
float (*BKE_editmesh_vertexCos_get_orco(BMEditMesh *em, int *r_numVerts))[3]
{
- BMIter iter;
- BMVert *eve;
- float (*orco)[3];
- int i;
+ BMIter iter;
+ BMVert *eve;
+ float(*orco)[3];
+ int i;
- orco = MEM_mallocN(em->bm->totvert * sizeof(*orco), __func__);
+ orco = MEM_mallocN(em->bm->totvert * sizeof(*orco), __func__);
- BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
- copy_v3_v3(orco[i], eve->co);
- }
+ BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
+ copy_v3_v3(orco[i], eve->co);
+ }
- *r_numVerts = em->bm->totvert;
+ *r_numVerts = em->bm->totvert;
- return orco;
+ return orco;
}
void BKE_editmesh_lnorspace_update(BMEditMesh *em)
{
- BMesh *bm = em->bm;
-
- /* We need to create clnors data if none exist yet, otherwise there is no way to edit them.
- * Similar code to MESH_OT_customdata_custom_splitnormals_add operator, we want to keep same shading
- * in case we were using autosmooth so far...
- * Note: there is a problem here, which is that if someone starts a normal editing operation on previously
- * autosmooth-ed mesh, and cancel that operation, generated clnors data remain, with related sharp edges
- * (and hence autosmooth is 'lost').
- * Not sure how critical this is, and how to fix that issue? */
- if (!CustomData_has_layer(&bm->ldata, CD_CUSTOMLOOPNORMAL)) {
- Mesh *me = em->ob->data;
- if (me->flag & ME_AUTOSMOOTH) {
- BM_edges_sharp_from_angle_set(bm, me->smoothresh);
- }
- }
-
- BM_lnorspace_update(bm);
+ BMesh *bm = em->bm;
+
+ /* We need to create clnors data if none exist yet, otherwise there is no way to edit them.
+ * Similar code to MESH_OT_customdata_custom_splitnormals_add operator, we want to keep same shading
+ * in case we were using autosmooth so far...
+ * Note: there is a problem here, which is that if someone starts a normal editing operation on previously
+ * autosmooth-ed mesh, and cancel that operation, generated clnors data remain, with related sharp edges
+ * (and hence autosmooth is 'lost').
+ * Not sure how critical this is, and how to fix that issue? */
+ if (!CustomData_has_layer(&bm->ldata, CD_CUSTOMLOOPNORMAL)) {
+ Mesh *me = em->ob->data;
+ if (me->flag & ME_AUTOSMOOTH) {
+ BM_edges_sharp_from_angle_set(bm, me->smoothresh);
+ }
+ }
+
+ BM_lnorspace_update(bm);
}
diff --git a/source/blender/blenkernel/intern/editmesh_bvh.c b/source/blender/blenkernel/intern/editmesh_bvh.c
index 9cb241ed8f0..31ea8fe581d 100644
--- a/source/blender/blenkernel/intern/editmesh_bvh.c
+++ b/source/blender/blenkernel/intern/editmesh_bvh.c
@@ -28,173 +28,178 @@
#include "BKE_editmesh.h"
-#include "BKE_editmesh_bvh.h" /* own include */
-
+#include "BKE_editmesh_bvh.h" /* own include */
struct BMBVHTree {
- BVHTree *tree;
+ BVHTree *tree;
- BMLoop *(*looptris)[3];
- int looptris_tot;
+ BMLoop *(*looptris)[3];
+ int looptris_tot;
- BMesh *bm;
+ BMesh *bm;
- const float (*cos_cage)[3];
- bool cos_cage_free;
+ const float (*cos_cage)[3];
+ bool cos_cage_free;
- int flag;
+ int flag;
};
-BMBVHTree *BKE_bmbvh_new_from_editmesh(
- BMEditMesh *em, int flag,
- const float (*cos_cage)[3], const bool cos_cage_free)
+BMBVHTree *BKE_bmbvh_new_from_editmesh(BMEditMesh *em,
+ int flag,
+ const float (*cos_cage)[3],
+ const bool cos_cage_free)
{
- return BKE_bmbvh_new(em->bm, em->looptris, em->tottri, flag, cos_cage, cos_cage_free);
+ return BKE_bmbvh_new(em->bm, em->looptris, em->tottri, flag, cos_cage, cos_cage_free);
}
-BMBVHTree *BKE_bmbvh_new_ex(
- BMesh *bm, BMLoop *(*looptris)[3], int looptris_tot, int flag,
- const float (*cos_cage)[3], const bool cos_cage_free,
- bool (*test_fn)(BMFace *, void *user_data), void *user_data)
+BMBVHTree *BKE_bmbvh_new_ex(BMesh *bm,
+ BMLoop *(*looptris)[3],
+ int looptris_tot,
+ int flag,
+ const float (*cos_cage)[3],
+ const bool cos_cage_free,
+ bool (*test_fn)(BMFace *, void *user_data),
+ void *user_data)
{
- /* could become argument */
- const float epsilon = FLT_EPSILON * 2.0f;
-
- BMBVHTree *bmtree = MEM_callocN(sizeof(*bmtree), "BMBVHTree");
- float cos[3][3];
- int i;
- int tottri;
-
- /* avoid testing every tri */
- BMFace *f_test, *f_test_prev;
- bool test_fn_ret;
-
- /* BKE_editmesh_tessface_calc() must be called already */
- BLI_assert(looptris_tot != 0 || bm->totface == 0);
-
- if (cos_cage) {
- BM_mesh_elem_index_ensure(bm, BM_VERT);
- }
-
- bmtree->looptris = looptris;
- bmtree->looptris_tot = looptris_tot;
- bmtree->bm = bm;
- bmtree->cos_cage = cos_cage;
- bmtree->cos_cage_free = cos_cage_free;
- bmtree->flag = flag;
-
- if (test_fn) {
- /* callback must do... */
- BLI_assert(!(flag & (BMBVH_RESPECT_SELECT | BMBVH_RESPECT_HIDDEN)));
-
- f_test_prev = NULL;
- test_fn_ret = false;
-
- tottri = 0;
- for (i = 0; i < looptris_tot; i++) {
- f_test = looptris[i][0]->f;
- if (f_test != f_test_prev) {
- test_fn_ret = test_fn(f_test, user_data);
- f_test_prev = f_test;
- }
-
- if (test_fn_ret) {
- tottri++;
- }
- }
- }
- else {
- tottri = looptris_tot;
- }
-
- bmtree->tree = BLI_bvhtree_new(tottri, epsilon, 8, 8);
-
- f_test_prev = NULL;
- test_fn_ret = false;
-
- for (i = 0; i < looptris_tot; i++) {
- if (test_fn) {
- /* note, the arrays wont align now! take care */
- f_test = looptris[i][0]->f;
- if (f_test != f_test_prev) {
- test_fn_ret = test_fn(f_test, user_data);
- f_test_prev = f_test;
- }
-
- if (!test_fn_ret) {
- continue;
- }
- }
-
- if (cos_cage) {
- copy_v3_v3(cos[0], cos_cage[BM_elem_index_get(looptris[i][0]->v)]);
- copy_v3_v3(cos[1], cos_cage[BM_elem_index_get(looptris[i][1]->v)]);
- copy_v3_v3(cos[2], cos_cage[BM_elem_index_get(looptris[i][2]->v)]);
- }
- else {
- copy_v3_v3(cos[0], looptris[i][0]->v->co);
- copy_v3_v3(cos[1], looptris[i][1]->v->co);
- copy_v3_v3(cos[2], looptris[i][2]->v->co);
- }
-
- BLI_bvhtree_insert(bmtree->tree, i, (float *)cos, 3);
- }
-
- BLI_bvhtree_balance(bmtree->tree);
-
- return bmtree;
+ /* could become argument */
+ const float epsilon = FLT_EPSILON * 2.0f;
+
+ BMBVHTree *bmtree = MEM_callocN(sizeof(*bmtree), "BMBVHTree");
+ float cos[3][3];
+ int i;
+ int tottri;
+
+ /* avoid testing every tri */
+ BMFace *f_test, *f_test_prev;
+ bool test_fn_ret;
+
+ /* BKE_editmesh_tessface_calc() must be called already */
+ BLI_assert(looptris_tot != 0 || bm->totface == 0);
+
+ if (cos_cage) {
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+ }
+
+ bmtree->looptris = looptris;
+ bmtree->looptris_tot = looptris_tot;
+ bmtree->bm = bm;
+ bmtree->cos_cage = cos_cage;
+ bmtree->cos_cage_free = cos_cage_free;
+ bmtree->flag = flag;
+
+ if (test_fn) {
+ /* callback must do... */
+ BLI_assert(!(flag & (BMBVH_RESPECT_SELECT | BMBVH_RESPECT_HIDDEN)));
+
+ f_test_prev = NULL;
+ test_fn_ret = false;
+
+ tottri = 0;
+ for (i = 0; i < looptris_tot; i++) {
+ f_test = looptris[i][0]->f;
+ if (f_test != f_test_prev) {
+ test_fn_ret = test_fn(f_test, user_data);
+ f_test_prev = f_test;
+ }
+
+ if (test_fn_ret) {
+ tottri++;
+ }
+ }
+ }
+ else {
+ tottri = looptris_tot;
+ }
+
+ bmtree->tree = BLI_bvhtree_new(tottri, epsilon, 8, 8);
+
+ f_test_prev = NULL;
+ test_fn_ret = false;
+
+ for (i = 0; i < looptris_tot; i++) {
+ if (test_fn) {
+ /* note, the arrays wont align now! take care */
+ f_test = looptris[i][0]->f;
+ if (f_test != f_test_prev) {
+ test_fn_ret = test_fn(f_test, user_data);
+ f_test_prev = f_test;
+ }
+
+ if (!test_fn_ret) {
+ continue;
+ }
+ }
+
+ if (cos_cage) {
+ copy_v3_v3(cos[0], cos_cage[BM_elem_index_get(looptris[i][0]->v)]);
+ copy_v3_v3(cos[1], cos_cage[BM_elem_index_get(looptris[i][1]->v)]);
+ copy_v3_v3(cos[2], cos_cage[BM_elem_index_get(looptris[i][2]->v)]);
+ }
+ else {
+ copy_v3_v3(cos[0], looptris[i][0]->v->co);
+ copy_v3_v3(cos[1], looptris[i][1]->v->co);
+ copy_v3_v3(cos[2], looptris[i][2]->v->co);
+ }
+
+ BLI_bvhtree_insert(bmtree->tree, i, (float *)cos, 3);
+ }
+
+ BLI_bvhtree_balance(bmtree->tree);
+
+ return bmtree;
}
static bool bm_face_is_select(BMFace *f, void *UNUSED(user_data))
{
- return (BM_elem_flag_test(f, BM_ELEM_SELECT) != 0);
+ return (BM_elem_flag_test(f, BM_ELEM_SELECT) != 0);
}
static bool bm_face_is_not_hidden(BMFace *f, void *UNUSED(user_data))
{
- return (BM_elem_flag_test(f, BM_ELEM_HIDDEN) == 0);
+ return (BM_elem_flag_test(f, BM_ELEM_HIDDEN) == 0);
}
-BMBVHTree *BKE_bmbvh_new(
- BMesh *bm, BMLoop *(*looptris)[3], int looptris_tot, int flag,
- const float (*cos_cage)[3], const bool cos_cage_free)
+BMBVHTree *BKE_bmbvh_new(BMesh *bm,
+ BMLoop *(*looptris)[3],
+ int looptris_tot,
+ int flag,
+ const float (*cos_cage)[3],
+ const bool cos_cage_free)
{
- bool (*test_fn)(BMFace *, void *user_data);
-
- if (flag & BMBVH_RESPECT_SELECT) {
- test_fn = bm_face_is_select;
- }
- else if (flag & BMBVH_RESPECT_HIDDEN) {
- test_fn = bm_face_is_not_hidden;
- }
- else {
- test_fn = NULL;
- }
-
- flag &= ~(BMBVH_RESPECT_SELECT | BMBVH_RESPECT_HIDDEN);
-
- return BKE_bmbvh_new_ex(bm, looptris, looptris_tot, flag, cos_cage, cos_cage_free, test_fn, NULL);
+ bool (*test_fn)(BMFace *, void *user_data);
+
+ if (flag & BMBVH_RESPECT_SELECT) {
+ test_fn = bm_face_is_select;
+ }
+ else if (flag & BMBVH_RESPECT_HIDDEN) {
+ test_fn = bm_face_is_not_hidden;
+ }
+ else {
+ test_fn = NULL;
+ }
+
+ flag &= ~(BMBVH_RESPECT_SELECT | BMBVH_RESPECT_HIDDEN);
+
+ return BKE_bmbvh_new_ex(
+ bm, looptris, looptris_tot, flag, cos_cage, cos_cage_free, test_fn, NULL);
}
-
void BKE_bmbvh_free(BMBVHTree *bmtree)
{
- BLI_bvhtree_free(bmtree->tree);
+ BLI_bvhtree_free(bmtree->tree);
- if (bmtree->cos_cage && bmtree->cos_cage_free) {
- MEM_freeN((void *)bmtree->cos_cage);
- }
+ if (bmtree->cos_cage && bmtree->cos_cage_free) {
+ MEM_freeN((void *)bmtree->cos_cage);
+ }
- MEM_freeN(bmtree);
+ MEM_freeN(bmtree);
}
BVHTree *BKE_bmbvh_tree_get(BMBVHTree *bmtree)
{
- return bmtree->tree;
+ return bmtree->tree;
}
-
-
/* -------------------------------------------------------------------- */
/* Utility BMesh cast/intersect functions */
@@ -202,117 +207,132 @@ BVHTree *BKE_bmbvh_tree_get(BMBVHTree *bmtree)
* Return the coords from a triangle.
*/
static void bmbvh_tri_from_face(const float *cos[3],
- const BMLoop **ltri, const float (*cos_cage)[3])
+ const BMLoop **ltri,
+ const float (*cos_cage)[3])
{
- if (cos_cage == NULL) {
- cos[0] = ltri[0]->v->co;
- cos[1] = ltri[1]->v->co;
- cos[2] = ltri[2]->v->co;
- }
- else {
- cos[0] = cos_cage[BM_elem_index_get(ltri[0]->v)];
- cos[1] = cos_cage[BM_elem_index_get(ltri[1]->v)];
- cos[2] = cos_cage[BM_elem_index_get(ltri[2]->v)];
- }
+ if (cos_cage == NULL) {
+ cos[0] = ltri[0]->v->co;
+ cos[1] = ltri[1]->v->co;
+ cos[2] = ltri[2]->v->co;
+ }
+ else {
+ cos[0] = cos_cage[BM_elem_index_get(ltri[0]->v)];
+ cos[1] = cos_cage[BM_elem_index_get(ltri[1]->v)];
+ cos[2] = cos_cage[BM_elem_index_get(ltri[2]->v)];
+ }
}
-
/* taken from bvhutils.c */
/* -------------------------------------------------------------------- */
/* BKE_bmbvh_ray_cast */
struct RayCastUserData {
- /* from the bmtree */
- const BMLoop *(*looptris)[3];
- const float (*cos_cage)[3];
+ /* from the bmtree */
+ const BMLoop *(*looptris)[3];
+ const float (*cos_cage)[3];
- /* from the hit */
- float uv[2];
+ /* from the hit */
+ float uv[2];
};
-
-static BMFace *bmbvh_ray_cast_handle_hit(
- BMBVHTree *bmtree, struct RayCastUserData *bmcb_data, const BVHTreeRayHit *hit,
- float *r_dist, float r_hitout[3], float r_cagehit[3])
+static BMFace *bmbvh_ray_cast_handle_hit(BMBVHTree *bmtree,
+ struct RayCastUserData *bmcb_data,
+ const BVHTreeRayHit *hit,
+ float *r_dist,
+ float r_hitout[3],
+ float r_cagehit[3])
{
- if (r_hitout) {
- if (bmtree->flag & BMBVH_RETURN_ORIG) {
- BMLoop **ltri = bmtree->looptris[hit->index];
- interp_v3_v3v3v3_uv(r_hitout, ltri[0]->v->co, ltri[1]->v->co, ltri[2]->v->co, bmcb_data->uv);
- }
- else {
- copy_v3_v3(r_hitout, hit->co);
- }
-
- if (r_cagehit) {
- copy_v3_v3(r_cagehit, hit->co);
- }
- }
-
- if (r_dist) {
- *r_dist = hit->dist;
- }
-
- return bmtree->looptris[hit->index][0]->f;
+ if (r_hitout) {
+ if (bmtree->flag & BMBVH_RETURN_ORIG) {
+ BMLoop **ltri = bmtree->looptris[hit->index];
+ interp_v3_v3v3v3_uv(r_hitout, ltri[0]->v->co, ltri[1]->v->co, ltri[2]->v->co, bmcb_data->uv);
+ }
+ else {
+ copy_v3_v3(r_hitout, hit->co);
+ }
+
+ if (r_cagehit) {
+ copy_v3_v3(r_cagehit, hit->co);
+ }
+ }
+
+ if (r_dist) {
+ *r_dist = hit->dist;
+ }
+
+ return bmtree->looptris[hit->index][0]->f;
}
static void bmbvh_ray_cast_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
{
- struct RayCastUserData *bmcb_data = userdata;
- const BMLoop **ltri = bmcb_data->looptris[index];
- float dist, uv[2];
- const float *tri_cos[3];
- bool isect;
-
- bmbvh_tri_from_face(tri_cos, ltri, bmcb_data->cos_cage);
-
- isect = (ray->radius > 0.0f ?
- isect_ray_tri_epsilon_v3(ray->origin, ray->direction,
- tri_cos[0], tri_cos[1], tri_cos[2], &dist, uv, ray->radius) :
+ struct RayCastUserData *bmcb_data = userdata;
+ const BMLoop **ltri = bmcb_data->looptris[index];
+ float dist, uv[2];
+ const float *tri_cos[3];
+ bool isect;
+
+ bmbvh_tri_from_face(tri_cos, ltri, bmcb_data->cos_cage);
+
+ isect =
+ (ray->radius > 0.0f ?
+ isect_ray_tri_epsilon_v3(ray->origin,
+ ray->direction,
+ tri_cos[0],
+ tri_cos[1],
+ tri_cos[2],
+ &dist,
+ uv,
+ ray->radius) :
#ifdef USE_KDOPBVH_WATERTIGHT
- isect_ray_tri_watertight_v3(ray->origin, ray->isect_precalc,
- tri_cos[0], tri_cos[1], tri_cos[2], &dist, uv));
+ isect_ray_tri_watertight_v3(
+ ray->origin, ray->isect_precalc, tri_cos[0], tri_cos[1], tri_cos[2], &dist, uv));
#else
- isect_ray_tri_v3(ray->origin, ray->direction,
- tri_cos[0], tri_cos[1], tri_cos[2], &dist, uv));
+ isect_ray_tri_v3(
+ ray->origin, ray->direction, tri_cos[0], tri_cos[1], tri_cos[2], &dist, uv));
#endif
- if (isect && dist < hit->dist) {
- hit->dist = dist;
- hit->index = index;
+ if (isect && dist < hit->dist) {
+ hit->dist = dist;
+ hit->index = index;
- copy_v3_v3(hit->no, ltri[0]->f->no);
+ copy_v3_v3(hit->no, ltri[0]->f->no);
- madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
+ madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
- copy_v2_v2(bmcb_data->uv, uv);
- }
+ copy_v2_v2(bmcb_data->uv, uv);
+ }
}
-BMFace *BKE_bmbvh_ray_cast(BMBVHTree *bmtree, const float co[3], const float dir[3], const float radius,
- float *r_dist, float r_hitout[3], float r_cagehit[3])
+BMFace *BKE_bmbvh_ray_cast(BMBVHTree *bmtree,
+ const float co[3],
+ const float dir[3],
+ const float radius,
+ float *r_dist,
+ float r_hitout[3],
+ float r_cagehit[3])
{
- BVHTreeRayHit hit;
- struct RayCastUserData bmcb_data;
- const float dist = r_dist ? *r_dist : FLT_MAX;
+ BVHTreeRayHit hit;
+ struct RayCastUserData bmcb_data;
+ const float dist = r_dist ? *r_dist : FLT_MAX;
- if (bmtree->cos_cage) BLI_assert(!(bmtree->bm->elem_index_dirty & BM_VERT));
+ if (bmtree->cos_cage)
+ BLI_assert(!(bmtree->bm->elem_index_dirty & BM_VERT));
- hit.dist = dist;
- hit.index = -1;
+ hit.dist = dist;
+ hit.index = -1;
- /* ok to leave 'uv' uninitialized */
- bmcb_data.looptris = (const BMLoop *(*)[3])bmtree->looptris;
- bmcb_data.cos_cage = (const float (*)[3])bmtree->cos_cage;
+ /* ok to leave 'uv' uninitialized */
+ bmcb_data.looptris = (const BMLoop *(*)[3])bmtree->looptris;
+ bmcb_data.cos_cage = (const float(*)[3])bmtree->cos_cage;
- BLI_bvhtree_ray_cast(bmtree->tree, co, dir, radius, &hit, bmbvh_ray_cast_cb, &bmcb_data);
+ BLI_bvhtree_ray_cast(bmtree->tree, co, dir, radius, &hit, bmbvh_ray_cast_cb, &bmcb_data);
- if (hit.index != -1 && hit.dist != dist) {
- return bmbvh_ray_cast_handle_hit(bmtree, &bmcb_data, &hit, r_dist, r_hitout, r_cagehit);
- }
+ if (hit.index != -1 && hit.dist != dist) {
+ return bmbvh_ray_cast_handle_hit(bmtree, &bmcb_data, &hit, r_dist, r_hitout, r_cagehit);
+ }
- return NULL;
+ return NULL;
}
/* -------------------------------------------------------------------- */
@@ -322,221 +342,243 @@ BMFace *BKE_bmbvh_ray_cast(BMBVHTree *bmtree, const float co[3], const float dir
*/
struct RayCastUserData_Filter {
- struct RayCastUserData bmcb_data;
+ struct RayCastUserData bmcb_data;
- BMBVHTree_FaceFilter filter_cb;
- void *filter_userdata;
+ BMBVHTree_FaceFilter filter_cb;
+ void *filter_userdata;
};
-static void bmbvh_ray_cast_cb_filter(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
+static void bmbvh_ray_cast_cb_filter(void *userdata,
+ int index,
+ const BVHTreeRay *ray,
+ BVHTreeRayHit *hit)
{
- struct RayCastUserData_Filter *bmcb_data_filter = userdata;
- struct RayCastUserData *bmcb_data = &bmcb_data_filter->bmcb_data;
- const BMLoop **ltri = bmcb_data->looptris[index];
- if (bmcb_data_filter->filter_cb(ltri[0]->f, bmcb_data_filter->filter_userdata)) {
- bmbvh_ray_cast_cb(bmcb_data, index, ray, hit);
- }
+ struct RayCastUserData_Filter *bmcb_data_filter = userdata;
+ struct RayCastUserData *bmcb_data = &bmcb_data_filter->bmcb_data;
+ const BMLoop **ltri = bmcb_data->looptris[index];
+ if (bmcb_data_filter->filter_cb(ltri[0]->f, bmcb_data_filter->filter_userdata)) {
+ bmbvh_ray_cast_cb(bmcb_data, index, ray, hit);
+ }
}
-BMFace *BKE_bmbvh_ray_cast_filter(
- BMBVHTree *bmtree, const float co[3], const float dir[3], const float radius,
- float *r_dist, float r_hitout[3], float r_cagehit[3],
- BMBVHTree_FaceFilter filter_cb, void *filter_userdata)
+BMFace *BKE_bmbvh_ray_cast_filter(BMBVHTree *bmtree,
+ const float co[3],
+ const float dir[3],
+ const float radius,
+ float *r_dist,
+ float r_hitout[3],
+ float r_cagehit[3],
+ BMBVHTree_FaceFilter filter_cb,
+ void *filter_userdata)
{
- BVHTreeRayHit hit;
- struct RayCastUserData_Filter bmcb_data_filter;
- struct RayCastUserData *bmcb_data = &bmcb_data_filter.bmcb_data;
+ BVHTreeRayHit hit;
+ struct RayCastUserData_Filter bmcb_data_filter;
+ struct RayCastUserData *bmcb_data = &bmcb_data_filter.bmcb_data;
- const float dist = r_dist ? *r_dist : FLT_MAX;
+ const float dist = r_dist ? *r_dist : FLT_MAX;
- bmcb_data_filter.filter_cb = filter_cb;
- bmcb_data_filter.filter_userdata = filter_userdata;
+ bmcb_data_filter.filter_cb = filter_cb;
+ bmcb_data_filter.filter_userdata = filter_userdata;
- if (bmtree->cos_cage) BLI_assert(!(bmtree->bm->elem_index_dirty & BM_VERT));
+ if (bmtree->cos_cage)
+ BLI_assert(!(bmtree->bm->elem_index_dirty & BM_VERT));
- hit.dist = dist;
- hit.index = -1;
+ hit.dist = dist;
+ hit.index = -1;
- /* ok to leave 'uv' uninitialized */
- bmcb_data->looptris = (const BMLoop *(*)[3])bmtree->looptris;
- bmcb_data->cos_cage = (const float (*)[3])bmtree->cos_cage;
+ /* ok to leave 'uv' uninitialized */
+ bmcb_data->looptris = (const BMLoop *(*)[3])bmtree->looptris;
+ bmcb_data->cos_cage = (const float(*)[3])bmtree->cos_cage;
- BLI_bvhtree_ray_cast(bmtree->tree, co, dir, radius, &hit, bmbvh_ray_cast_cb_filter, &bmcb_data_filter);
- if (hit.index != -1 && hit.dist != dist) {
- return bmbvh_ray_cast_handle_hit(bmtree, bmcb_data, &hit, r_dist, r_hitout, r_cagehit);
- }
+ BLI_bvhtree_ray_cast(
+ bmtree->tree, co, dir, radius, &hit, bmbvh_ray_cast_cb_filter, &bmcb_data_filter);
+ if (hit.index != -1 && hit.dist != dist) {
+ return bmbvh_ray_cast_handle_hit(bmtree, bmcb_data, &hit, r_dist, r_hitout, r_cagehit);
+ }
- return NULL;
+ return NULL;
}
-
/* -------------------------------------------------------------------- */
/* BKE_bmbvh_find_vert_closest */
struct VertSearchUserData {
- /* from the bmtree */
- const BMLoop *(*looptris)[3];
- const float (*cos_cage)[3];
+ /* from the bmtree */
+ const BMLoop *(*looptris)[3];
+ const float (*cos_cage)[3];
- /* from the hit */
- float dist_max_sq;
- int index_tri;
+ /* from the hit */
+ float dist_max_sq;
+ int index_tri;
};
-static void bmbvh_find_vert_closest_cb(void *userdata, int index, const float co[3], BVHTreeNearest *hit)
+static void bmbvh_find_vert_closest_cb(void *userdata,
+ int index,
+ const float co[3],
+ BVHTreeNearest *hit)
{
- struct VertSearchUserData *bmcb_data = userdata;
- const BMLoop **ltri = bmcb_data->looptris[index];
- const float dist_max_sq = bmcb_data->dist_max_sq;
- int i;
-
- const float *tri_cos[3];
-
- bmbvh_tri_from_face(tri_cos, ltri, bmcb_data->cos_cage);
-
- for (i = 0; i < 3; i++) {
- const float dist_sq = len_squared_v3v3(co, tri_cos[i]);
- if (dist_sq < hit->dist_sq && dist_sq < dist_max_sq) {
- copy_v3_v3(hit->co, tri_cos[i]);
- /* XXX, normal ignores cage */
- copy_v3_v3(hit->no, ltri[i]->v->no);
- hit->dist_sq = dist_sq;
- hit->index = index;
- bmcb_data->index_tri = i;
- }
- }
+ struct VertSearchUserData *bmcb_data = userdata;
+ const BMLoop **ltri = bmcb_data->looptris[index];
+ const float dist_max_sq = bmcb_data->dist_max_sq;
+ int i;
+
+ const float *tri_cos[3];
+
+ bmbvh_tri_from_face(tri_cos, ltri, bmcb_data->cos_cage);
+
+ for (i = 0; i < 3; i++) {
+ const float dist_sq = len_squared_v3v3(co, tri_cos[i]);
+ if (dist_sq < hit->dist_sq && dist_sq < dist_max_sq) {
+ copy_v3_v3(hit->co, tri_cos[i]);
+ /* XXX, normal ignores cage */
+ copy_v3_v3(hit->no, ltri[i]->v->no);
+ hit->dist_sq = dist_sq;
+ hit->index = index;
+ bmcb_data->index_tri = i;
+ }
+ }
}
BMVert *BKE_bmbvh_find_vert_closest(BMBVHTree *bmtree, const float co[3], const float dist_max)
{
- BVHTreeNearest hit;
- struct VertSearchUserData bmcb_data;
- const float dist_max_sq = dist_max * dist_max;
+ BVHTreeNearest hit;
+ struct VertSearchUserData bmcb_data;
+ const float dist_max_sq = dist_max * dist_max;
- if (bmtree->cos_cage) BLI_assert(!(bmtree->bm->elem_index_dirty & BM_VERT));
+ if (bmtree->cos_cage)
+ BLI_assert(!(bmtree->bm->elem_index_dirty & BM_VERT));
- hit.dist_sq = dist_max_sq;
- hit.index = -1;
+ hit.dist_sq = dist_max_sq;
+ hit.index = -1;
- bmcb_data.looptris = (const BMLoop *(*)[3])bmtree->looptris;
- bmcb_data.cos_cage = (const float (*)[3])bmtree->cos_cage;
- bmcb_data.dist_max_sq = dist_max_sq;
+ bmcb_data.looptris = (const BMLoop *(*)[3])bmtree->looptris;
+ bmcb_data.cos_cage = (const float(*)[3])bmtree->cos_cage;
+ bmcb_data.dist_max_sq = dist_max_sq;
- BLI_bvhtree_find_nearest(bmtree->tree, co, &hit, bmbvh_find_vert_closest_cb, &bmcb_data);
- if (hit.index != -1) {
- BMLoop **ltri = bmtree->looptris[hit.index];
- return ltri[bmcb_data.index_tri]->v;
- }
+ BLI_bvhtree_find_nearest(bmtree->tree, co, &hit, bmbvh_find_vert_closest_cb, &bmcb_data);
+ if (hit.index != -1) {
+ BMLoop **ltri = bmtree->looptris[hit.index];
+ return ltri[bmcb_data.index_tri]->v;
+ }
- return NULL;
+ return NULL;
}
struct FaceSearchUserData {
- /* from the bmtree */
- const BMLoop *(*looptris)[3];
- const float (*cos_cage)[3];
+ /* from the bmtree */
+ const BMLoop *(*looptris)[3];
+ const float (*cos_cage)[3];
- /* from the hit */
- float dist_max_sq;
+ /* from the hit */
+ float dist_max_sq;
};
-static void bmbvh_find_face_closest_cb(void *userdata, int index, const float co[3], BVHTreeNearest *hit)
+static void bmbvh_find_face_closest_cb(void *userdata,
+ int index,
+ const float co[3],
+ BVHTreeNearest *hit)
{
- struct FaceSearchUserData *bmcb_data = userdata;
- const BMLoop **ltri = bmcb_data->looptris[index];
- const float dist_max_sq = bmcb_data->dist_max_sq;
-
- const float *tri_cos[3];
-
- bmbvh_tri_from_face(tri_cos, ltri, bmcb_data->cos_cage);
-
- float co_close[3];
- closest_on_tri_to_point_v3(co_close, co, UNPACK3(tri_cos));
- const float dist_sq = len_squared_v3v3(co, co_close);
- if (dist_sq < hit->dist_sq && dist_sq < dist_max_sq) {
- /* XXX, normal ignores cage */
- copy_v3_v3(hit->no, ltri[0]->f->no);
- hit->dist_sq = dist_sq;
- hit->index = index;
- }
+ struct FaceSearchUserData *bmcb_data = userdata;
+ const BMLoop **ltri = bmcb_data->looptris[index];
+ const float dist_max_sq = bmcb_data->dist_max_sq;
+
+ const float *tri_cos[3];
+
+ bmbvh_tri_from_face(tri_cos, ltri, bmcb_data->cos_cage);
+
+ float co_close[3];
+ closest_on_tri_to_point_v3(co_close, co, UNPACK3(tri_cos));
+ const float dist_sq = len_squared_v3v3(co, co_close);
+ if (dist_sq < hit->dist_sq && dist_sq < dist_max_sq) {
+ /* XXX, normal ignores cage */
+ copy_v3_v3(hit->no, ltri[0]->f->no);
+ hit->dist_sq = dist_sq;
+ hit->index = index;
+ }
}
-struct BMFace *BKE_bmbvh_find_face_closest(BMBVHTree *bmtree, const float co[3], const float dist_max)
+struct BMFace *BKE_bmbvh_find_face_closest(BMBVHTree *bmtree,
+ const float co[3],
+ const float dist_max)
{
- BVHTreeNearest hit;
- struct FaceSearchUserData bmcb_data;
- const float dist_max_sq = dist_max * dist_max;
+ BVHTreeNearest hit;
+ struct FaceSearchUserData bmcb_data;
+ const float dist_max_sq = dist_max * dist_max;
- if (bmtree->cos_cage) BLI_assert(!(bmtree->bm->elem_index_dirty & BM_VERT));
+ if (bmtree->cos_cage)
+ BLI_assert(!(bmtree->bm->elem_index_dirty & BM_VERT));
- hit.dist_sq = dist_max_sq;
- hit.index = -1;
+ hit.dist_sq = dist_max_sq;
+ hit.index = -1;
- bmcb_data.looptris = (const BMLoop *(*)[3])bmtree->looptris;
- bmcb_data.cos_cage = (const float (*)[3])bmtree->cos_cage;
- bmcb_data.dist_max_sq = dist_max_sq;
+ bmcb_data.looptris = (const BMLoop *(*)[3])bmtree->looptris;
+ bmcb_data.cos_cage = (const float(*)[3])bmtree->cos_cage;
+ bmcb_data.dist_max_sq = dist_max_sq;
- BLI_bvhtree_find_nearest(bmtree->tree, co, &hit, bmbvh_find_face_closest_cb, &bmcb_data);
- if (hit.index != -1) {
- BMLoop **ltri = bmtree->looptris[hit.index];
- return ltri[0]->f;
- }
+ BLI_bvhtree_find_nearest(bmtree->tree, co, &hit, bmbvh_find_face_closest_cb, &bmcb_data);
+ if (hit.index != -1) {
+ BMLoop **ltri = bmtree->looptris[hit.index];
+ return ltri[0]->f;
+ }
- return NULL;
+ return NULL;
}
/* -------------------------------------------------------------------- */
/* BKE_bmbvh_overlap */
struct BMBVHTree_OverlapData {
- const BMBVHTree *tree_pair[2];
- float epsilon;
+ const BMBVHTree *tree_pair[2];
+ float epsilon;
};
static bool bmbvh_overlap_cb(void *userdata, int index_a, int index_b, int UNUSED(thread))
{
- struct BMBVHTree_OverlapData *data = userdata;
- const BMBVHTree *bmtree_a = data->tree_pair[0];
- const BMBVHTree *bmtree_b = data->tree_pair[1];
-
- BMLoop **tri_a = bmtree_a->looptris[index_a];
- BMLoop **tri_b = bmtree_b->looptris[index_b];
- const float *tri_a_co[3] = {tri_a[0]->v->co, tri_a[1]->v->co, tri_a[2]->v->co};
- const float *tri_b_co[3] = {tri_b[0]->v->co, tri_b[1]->v->co, tri_b[2]->v->co};
- float ix_pair[2][3];
- int verts_shared = 0;
-
- if (bmtree_a->looptris == bmtree_b->looptris) {
- if (UNLIKELY(tri_a[0]->f == tri_b[0]->f)) {
- return false;
- }
-
- verts_shared = (
- ELEM(tri_a_co[0], UNPACK3(tri_b_co)) +
- ELEM(tri_a_co[1], UNPACK3(tri_b_co)) +
- ELEM(tri_a_co[2], UNPACK3(tri_b_co)));
-
- /* if 2 points are shared, bail out */
- if (verts_shared >= 2) {
- return false;
- }
- }
-
- return (isect_tri_tri_epsilon_v3(UNPACK3(tri_a_co), UNPACK3(tri_b_co), ix_pair[0], ix_pair[1], data->epsilon) &&
- /* if we share a vertex, check the intersection isn't a 'point' */
- ((verts_shared == 0) || (len_squared_v3v3(ix_pair[0], ix_pair[1]) > data->epsilon)));
+ struct BMBVHTree_OverlapData *data = userdata;
+ const BMBVHTree *bmtree_a = data->tree_pair[0];
+ const BMBVHTree *bmtree_b = data->tree_pair[1];
+
+ BMLoop **tri_a = bmtree_a->looptris[index_a];
+ BMLoop **tri_b = bmtree_b->looptris[index_b];
+ const float *tri_a_co[3] = {tri_a[0]->v->co, tri_a[1]->v->co, tri_a[2]->v->co};
+ const float *tri_b_co[3] = {tri_b[0]->v->co, tri_b[1]->v->co, tri_b[2]->v->co};
+ float ix_pair[2][3];
+ int verts_shared = 0;
+
+ if (bmtree_a->looptris == bmtree_b->looptris) {
+ if (UNLIKELY(tri_a[0]->f == tri_b[0]->f)) {
+ return false;
+ }
+
+ verts_shared = (ELEM(tri_a_co[0], UNPACK3(tri_b_co)) + ELEM(tri_a_co[1], UNPACK3(tri_b_co)) +
+ ELEM(tri_a_co[2], UNPACK3(tri_b_co)));
+
+ /* if 2 points are shared, bail out */
+ if (verts_shared >= 2) {
+ return false;
+ }
+ }
+
+ return (isect_tri_tri_epsilon_v3(
+ UNPACK3(tri_a_co), UNPACK3(tri_b_co), ix_pair[0], ix_pair[1], data->epsilon) &&
+ /* if we share a vertex, check the intersection isn't a 'point' */
+ ((verts_shared == 0) || (len_squared_v3v3(ix_pair[0], ix_pair[1]) > data->epsilon)));
}
/**
* Overlap indices reference the looptri's
*/
-BVHTreeOverlap *BKE_bmbvh_overlap(const BMBVHTree *bmtree_a, const BMBVHTree *bmtree_b, unsigned int *r_overlap_tot)
+BVHTreeOverlap *BKE_bmbvh_overlap(const BMBVHTree *bmtree_a,
+ const BMBVHTree *bmtree_b,
+ unsigned int *r_overlap_tot)
{
- struct BMBVHTree_OverlapData data;
+ struct BMBVHTree_OverlapData data;
- data.tree_pair[0] = bmtree_a;
- data.tree_pair[1] = bmtree_b;
- data.epsilon = max_ff(BLI_bvhtree_get_epsilon(bmtree_a->tree), BLI_bvhtree_get_epsilon(bmtree_b->tree));
+ data.tree_pair[0] = bmtree_a;
+ data.tree_pair[1] = bmtree_b;
+ data.epsilon = max_ff(BLI_bvhtree_get_epsilon(bmtree_a->tree),
+ BLI_bvhtree_get_epsilon(bmtree_b->tree));
- return BLI_bvhtree_overlap(bmtree_a->tree, bmtree_b->tree, r_overlap_tot, bmbvh_overlap_cb, &data);
+ return BLI_bvhtree_overlap(
+ bmtree_a->tree, bmtree_b->tree, r_overlap_tot, bmbvh_overlap_cb, &data);
}
diff --git a/source/blender/blenkernel/intern/editmesh_cache.c b/source/blender/blenkernel/intern/editmesh_cache.c
index 0c890ad5741..8d3f1e84bcd 100644
--- a/source/blender/blenkernel/intern/editmesh_cache.c
+++ b/source/blender/blenkernel/intern/editmesh_cache.c
@@ -24,92 +24,91 @@
#include "DNA_mesh_types.h"
-
#include "BKE_editmesh.h"
-#include "BKE_editmesh_cache.h" /* own include */
+#include "BKE_editmesh_cache.h" /* own include */
void BKE_editmesh_cache_ensure_poly_normals(BMEditMesh *em, EditMeshData *emd)
{
- if (!(emd->vertexCos && (emd->polyNos == NULL))) {
- return;
- }
+ if (!(emd->vertexCos && (emd->polyNos == NULL))) {
+ return;
+ }
- BMesh *bm = em->bm;
- const float (*vertexCos)[3];
- float (*polyNos)[3];
+ BMesh *bm = em->bm;
+ const float(*vertexCos)[3];
+ float(*polyNos)[3];
- BMFace *efa;
- BMIter fiter;
- int i;
+ BMFace *efa;
+ BMIter fiter;
+ int i;
- BM_mesh_elem_index_ensure(bm, BM_VERT);
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
- polyNos = MEM_mallocN(sizeof(*polyNos) * bm->totface, __func__);
+ polyNos = MEM_mallocN(sizeof(*polyNos) * bm->totface, __func__);
- vertexCos = emd->vertexCos;
+ vertexCos = emd->vertexCos;
- BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) {
- BM_elem_index_set(efa, i); /* set_inline */
- BM_face_calc_normal_vcos(bm, efa, polyNos[i], vertexCos);
- }
- bm->elem_index_dirty &= ~BM_FACE;
+ BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) {
+ BM_elem_index_set(efa, i); /* set_inline */
+ BM_face_calc_normal_vcos(bm, efa, polyNos[i], vertexCos);
+ }
+ bm->elem_index_dirty &= ~BM_FACE;
- emd->polyNos = (const float (*)[3])polyNos;
+ emd->polyNos = (const float(*)[3])polyNos;
}
void BKE_editmesh_cache_ensure_vert_normals(BMEditMesh *em, EditMeshData *emd)
{
- if (!(emd->vertexCos && (emd->vertexNos == NULL))) {
- return;
- }
+ if (!(emd->vertexCos && (emd->vertexNos == NULL))) {
+ return;
+ }
- BMesh *bm = em->bm;
- const float (*vertexCos)[3], (*polyNos)[3];
- float (*vertexNos)[3];
+ BMesh *bm = em->bm;
+ const float(*vertexCos)[3], (*polyNos)[3];
+ float(*vertexNos)[3];
- /* calculate vertex normals from poly normals */
- BKE_editmesh_cache_ensure_poly_normals(em, emd);
+ /* calculate vertex normals from poly normals */
+ BKE_editmesh_cache_ensure_poly_normals(em, emd);
- BM_mesh_elem_index_ensure(bm, BM_FACE);
+ BM_mesh_elem_index_ensure(bm, BM_FACE);
- polyNos = emd->polyNos;
- vertexCos = emd->vertexCos;
- vertexNos = MEM_callocN(sizeof(*vertexNos) * bm->totvert, __func__);
+ polyNos = emd->polyNos;
+ vertexCos = emd->vertexCos;
+ vertexNos = MEM_callocN(sizeof(*vertexNos) * bm->totvert, __func__);
- BM_verts_calc_normal_vcos(bm, polyNos, vertexCos, vertexNos);
+ BM_verts_calc_normal_vcos(bm, polyNos, vertexCos, vertexNos);
- emd->vertexNos = (const float (*)[3])vertexNos;
+ emd->vertexNos = (const float(*)[3])vertexNos;
}
void BKE_editmesh_cache_ensure_poly_centers(BMEditMesh *em, EditMeshData *emd)
{
- if (emd->polyCos != NULL) {
- return;
- }
- BMesh *bm = em->bm;
- float (*polyCos)[3];
-
- BMFace *efa;
- BMIter fiter;
- int i;
-
- polyCos = MEM_mallocN(sizeof(*polyCos) * bm->totface, __func__);
-
- if (emd->vertexCos) {
- const float (*vertexCos)[3];
- vertexCos = emd->vertexCos;
-
- BM_mesh_elem_index_ensure(bm, BM_VERT);
-
- BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) {
- BM_face_calc_center_median_vcos(bm, efa, polyCos[i], vertexCos);
- }
- }
- else {
- BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) {
- BM_face_calc_center_median(efa, polyCos[i]);
- }
- }
-
- emd->polyCos = (const float (*)[3])polyCos;
+ if (emd->polyCos != NULL) {
+ return;
+ }
+ BMesh *bm = em->bm;
+ float(*polyCos)[3];
+
+ BMFace *efa;
+ BMIter fiter;
+ int i;
+
+ polyCos = MEM_mallocN(sizeof(*polyCos) * bm->totface, __func__);
+
+ if (emd->vertexCos) {
+ const float(*vertexCos)[3];
+ vertexCos = emd->vertexCos;
+
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+
+ BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) {
+ BM_face_calc_center_median_vcos(bm, efa, polyCos[i], vertexCos);
+ }
+ }
+ else {
+ BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) {
+ BM_face_calc_center_median(efa, polyCos[i]);
+ }
+ }
+
+ emd->polyCos = (const float(*)[3])polyCos;
}
diff --git a/source/blender/blenkernel/intern/editmesh_tangent.c b/source/blender/blenkernel/intern/editmesh_tangent.c
index b33fc2bb967..1bfd40c26af 100644
--- a/source/blender/blenkernel/intern/editmesh_tangent.c
+++ b/source/blender/blenkernel/intern/editmesh_tangent.c
@@ -26,7 +26,7 @@
#include "DNA_meshdata_types.h"
#include "BKE_mesh.h"
-#include "BKE_mesh_tangent.h" /* for utility functions */
+#include "BKE_mesh_tangent.h" /* for utility functions */
#include "BKE_editmesh.h"
#include "BKE_editmesh_tangent.h"
@@ -42,19 +42,19 @@
#define USE_LOOPTRI_DETECT_QUADS
typedef struct {
- const float (*precomputedFaceNormals)[3];
- const float (*precomputedLoopNormals)[3];
- const BMLoop *(*looptris)[3];
- int cd_loop_uv_offset; /* texture coordinates */
- const float (*orco)[3];
- float (*tangent)[4]; /* destination */
- int numTessFaces;
+ const float (*precomputedFaceNormals)[3];
+ const float (*precomputedLoopNormals)[3];
+ const BMLoop *(*looptris)[3];
+ int cd_loop_uv_offset; /* texture coordinates */
+ const float (*orco)[3];
+ float (*tangent)[4]; /* destination */
+ int numTessFaces;
#ifdef USE_LOOPTRI_DETECT_QUADS
- /* map from 'fake' face index to looptri,
- * quads will point to the first looptri of the quad */
- const int *face_as_quad_map;
- int num_face_as_quad_map;
+ /* map from 'fake' face index to looptri,
+ * quads will point to the first looptri of the quad */
+ const int *face_as_quad_map;
+ int num_face_as_quad_map;
#endif
} SGLSLEditMeshToTangent;
@@ -63,207 +63,214 @@ typedef struct {
/* seems weak but only used on quads */
static const BMLoop *bm_loop_at_face_index(const BMFace *f, int vert_index)
{
- const BMLoop *l = BM_FACE_FIRST_LOOP(f);
- while (vert_index--) {
- l = l->next;
- }
- return l;
+ const BMLoop *l = BM_FACE_FIRST_LOOP(f);
+ while (vert_index--) {
+ l = l->next;
+ }
+ return l;
}
#endif
static int emdm_ts_GetNumFaces(const SMikkTSpaceContext *pContext)
{
- SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
+ SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
#ifdef USE_LOOPTRI_DETECT_QUADS
- return pMesh->num_face_as_quad_map;
+ return pMesh->num_face_as_quad_map;
#else
- return pMesh->numTessFaces;
+ return pMesh->numTessFaces;
#endif
}
static int emdm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num)
{
#ifdef USE_LOOPTRI_DETECT_QUADS
- SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
- if (pMesh->face_as_quad_map) {
- const BMLoop **lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
- if (lt[0]->f->len == 4) {
- return 4;
- }
- }
- return 3;
+ SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
+ if (pMesh->face_as_quad_map) {
+ const BMLoop **lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
+ if (lt[0]->f->len == 4) {
+ return 4;
+ }
+ }
+ return 3;
#else
- UNUSED_VARS(pContext, face_num);
- return 3;
+ UNUSED_VARS(pContext, face_num);
+ return 3;
#endif
}
-static void emdm_ts_GetPosition(
- const SMikkTSpaceContext *pContext, float r_co[3],
- const int face_num, const int vert_index)
+static void emdm_ts_GetPosition(const SMikkTSpaceContext *pContext,
+ float r_co[3],
+ const int face_num,
+ const int vert_index)
{
- //assert(vert_index >= 0 && vert_index < 4);
- SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
- const BMLoop **lt;
- const BMLoop *l;
+ //assert(vert_index >= 0 && vert_index < 4);
+ SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
+ const BMLoop **lt;
+ const BMLoop *l;
#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
- if (lt[0]->f->len == 4) {
- l = bm_loop_at_face_index(lt[0]->f, vert_index);
- goto finally;
- }
- /* fall through to regular triangle */
- }
- else {
- lt = pMesh->looptris[face_num];
- }
+ if (pMesh->face_as_quad_map) {
+ lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
+ if (lt[0]->f->len == 4) {
+ l = bm_loop_at_face_index(lt[0]->f, vert_index);
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = pMesh->looptris[face_num];
+ }
#else
- lt = pMesh->looptris[face_num];
+ lt = pMesh->looptris[face_num];
#endif
- l = lt[vert_index];
+ l = lt[vert_index];
- const float *co;
+ const float *co;
finally:
- co = l->v->co;
- copy_v3_v3(r_co, co);
+ co = l->v->co;
+ copy_v3_v3(r_co, co);
}
-static void emdm_ts_GetTextureCoordinate(
- const SMikkTSpaceContext *pContext, float r_uv[2],
- const int face_num, const int vert_index)
+static void emdm_ts_GetTextureCoordinate(const SMikkTSpaceContext *pContext,
+ float r_uv[2],
+ const int face_num,
+ const int vert_index)
{
- //assert(vert_index >= 0 && vert_index < 4);
- SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
- const BMLoop **lt;
- const BMLoop *l;
+ //assert(vert_index >= 0 && vert_index < 4);
+ SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
+ const BMLoop **lt;
+ const BMLoop *l;
#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
- if (lt[0]->f->len == 4) {
- l = bm_loop_at_face_index(lt[0]->f, vert_index);
- goto finally;
- }
- /* fall through to regular triangle */
- }
- else {
- lt = pMesh->looptris[face_num];
- }
+ if (pMesh->face_as_quad_map) {
+ lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
+ if (lt[0]->f->len == 4) {
+ l = bm_loop_at_face_index(lt[0]->f, vert_index);
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = pMesh->looptris[face_num];
+ }
#else
- lt = pMesh->looptris[face_num];
+ lt = pMesh->looptris[face_num];
#endif
- l = lt[vert_index];
+ l = lt[vert_index];
finally:
- if (pMesh->cd_loop_uv_offset != -1) {
- const float *uv = BM_ELEM_CD_GET_VOID_P(l, pMesh->cd_loop_uv_offset);
- copy_v2_v2(r_uv, uv);
- }
- else {
- const float *orco = pMesh->orco[BM_elem_index_get(l->v)];
- map_to_sphere(&r_uv[0], &r_uv[1], orco[0], orco[1], orco[2]);
- }
+ if (pMesh->cd_loop_uv_offset != -1) {
+ const float *uv = BM_ELEM_CD_GET_VOID_P(l, pMesh->cd_loop_uv_offset);
+ copy_v2_v2(r_uv, uv);
+ }
+ else {
+ const float *orco = pMesh->orco[BM_elem_index_get(l->v)];
+ map_to_sphere(&r_uv[0], &r_uv[1], orco[0], orco[1], orco[2]);
+ }
}
-static void emdm_ts_GetNormal(
- const SMikkTSpaceContext *pContext, float r_no[3],
- const int face_num, const int vert_index)
+static void emdm_ts_GetNormal(const SMikkTSpaceContext *pContext,
+ float r_no[3],
+ const int face_num,
+ const int vert_index)
{
- //assert(vert_index >= 0 && vert_index < 4);
- SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
- const BMLoop **lt;
- const BMLoop *l;
+ //assert(vert_index >= 0 && vert_index < 4);
+ SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
+ const BMLoop **lt;
+ const BMLoop *l;
#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
- if (lt[0]->f->len == 4) {
- l = bm_loop_at_face_index(lt[0]->f, vert_index);
- goto finally;
- }
- /* fall through to regular triangle */
- }
- else {
- lt = pMesh->looptris[face_num];
- }
+ if (pMesh->face_as_quad_map) {
+ lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
+ if (lt[0]->f->len == 4) {
+ l = bm_loop_at_face_index(lt[0]->f, vert_index);
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = pMesh->looptris[face_num];
+ }
#else
- lt = pMesh->looptris[face_num];
+ lt = pMesh->looptris[face_num];
#endif
- l = lt[vert_index];
+ l = lt[vert_index];
finally:
- if (pMesh->precomputedLoopNormals) {
- copy_v3_v3(r_no, pMesh->precomputedLoopNormals[BM_elem_index_get(l)]);
- }
- else if (BM_elem_flag_test(l->f, BM_ELEM_SMOOTH) == 0) { /* flat */
- if (pMesh->precomputedFaceNormals) {
- copy_v3_v3(r_no, pMesh->precomputedFaceNormals[BM_elem_index_get(l->f)]);
- }
- else {
- copy_v3_v3(r_no, l->f->no);
- }
- }
- else {
- copy_v3_v3(r_no, l->v->no);
- }
+ if (pMesh->precomputedLoopNormals) {
+ copy_v3_v3(r_no, pMesh->precomputedLoopNormals[BM_elem_index_get(l)]);
+ }
+ else if (BM_elem_flag_test(l->f, BM_ELEM_SMOOTH) == 0) { /* flat */
+ if (pMesh->precomputedFaceNormals) {
+ copy_v3_v3(r_no, pMesh->precomputedFaceNormals[BM_elem_index_get(l->f)]);
+ }
+ else {
+ copy_v3_v3(r_no, l->f->no);
+ }
+ }
+ else {
+ copy_v3_v3(r_no, l->v->no);
+ }
}
-static void emdm_ts_SetTSpace(
- const SMikkTSpaceContext *pContext, const float fvTangent[3], const float fSign,
- const int face_num, const int vert_index)
+static void emdm_ts_SetTSpace(const SMikkTSpaceContext *pContext,
+ const float fvTangent[3],
+ const float fSign,
+ const int face_num,
+ const int vert_index)
{
- //assert(vert_index >= 0 && vert_index < 4);
- SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
- const BMLoop **lt;
- const BMLoop *l;
+ //assert(vert_index >= 0 && vert_index < 4);
+ SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
+ const BMLoop **lt;
+ const BMLoop *l;
#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
- if (lt[0]->f->len == 4) {
- l = bm_loop_at_face_index(lt[0]->f, vert_index);
- goto finally;
- }
- /* fall through to regular triangle */
- }
- else {
- lt = pMesh->looptris[face_num];
- }
+ if (pMesh->face_as_quad_map) {
+ lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
+ if (lt[0]->f->len == 4) {
+ l = bm_loop_at_face_index(lt[0]->f, vert_index);
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = pMesh->looptris[face_num];
+ }
#else
- lt = pMesh->looptris[face_num];
+ lt = pMesh->looptris[face_num];
#endif
- l = lt[vert_index];
+ l = lt[vert_index];
- float *pRes;
+ float *pRes;
finally:
- pRes = pMesh->tangent[BM_elem_index_get(l)];
- copy_v3_v3(pRes, fvTangent);
- pRes[3] = fSign;
+ pRes = pMesh->tangent[BM_elem_index_get(l)];
+ copy_v3_v3(pRes, fvTangent);
+ pRes[3] = fSign;
}
-static void emDM_calc_loop_tangents_thread(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
+static void emDM_calc_loop_tangents_thread(TaskPool *__restrict UNUSED(pool),
+ void *taskdata,
+ int UNUSED(threadid))
{
- struct SGLSLEditMeshToTangent *mesh2tangent = taskdata;
- /* new computation method */
- {
- SMikkTSpaceContext sContext = {NULL};
- SMikkTSpaceInterface sInterface = {NULL};
- sContext.m_pUserData = mesh2tangent;
- sContext.m_pInterface = &sInterface;
- sInterface.m_getNumFaces = emdm_ts_GetNumFaces;
- sInterface.m_getNumVerticesOfFace = emdm_ts_GetNumVertsOfFace;
- sInterface.m_getPosition = emdm_ts_GetPosition;
- sInterface.m_getTexCoord = emdm_ts_GetTextureCoordinate;
- sInterface.m_getNormal = emdm_ts_GetNormal;
- sInterface.m_setTSpaceBasic = emdm_ts_SetTSpace;
- /* 0 if failed */
- genTangSpaceDefault(&sContext);
- }
+ struct SGLSLEditMeshToTangent *mesh2tangent = taskdata;
+ /* new computation method */
+ {
+ SMikkTSpaceContext sContext = {NULL};
+ SMikkTSpaceInterface sInterface = {NULL};
+ sContext.m_pUserData = mesh2tangent;
+ sContext.m_pInterface = &sInterface;
+ sInterface.m_getNumFaces = emdm_ts_GetNumFaces;
+ sInterface.m_getNumVerticesOfFace = emdm_ts_GetNumVertsOfFace;
+ sInterface.m_getPosition = emdm_ts_GetPosition;
+ sInterface.m_getTexCoord = emdm_ts_GetTextureCoordinate;
+ sInterface.m_getNormal = emdm_ts_GetNormal;
+ sInterface.m_setTSpaceBasic = emdm_ts_SetTSpace;
+ /* 0 if failed */
+ genTangSpaceDefault(&sContext);
+ }
}
/**
@@ -272,158 +279,175 @@ static void emDM_calc_loop_tangents_thread(TaskPool * __restrict UNUSED(pool), v
* \note This function is not so normal, its using `bm->ldata` as input, but output's to `dm->loopData`.
* This is done because #CD_TANGENT is cache data used only for drawing.
*/
-void BKE_editmesh_loop_tangent_calc(
- BMEditMesh *em, bool calc_active_tangent,
- const char (*tangent_names)[MAX_NAME], int tangent_names_len,
- const float (*poly_normals)[3],
- const float (*loop_normals)[3],
- const float (*vert_orco)[3],
- /* result */
- CustomData *loopdata_out,
- const uint loopdata_out_len,
- short *tangent_mask_curr_p)
+void BKE_editmesh_loop_tangent_calc(BMEditMesh *em,
+ bool calc_active_tangent,
+ const char (*tangent_names)[MAX_NAME],
+ int tangent_names_len,
+ const float (*poly_normals)[3],
+ const float (*loop_normals)[3],
+ const float (*vert_orco)[3],
+ /* result */
+ CustomData *loopdata_out,
+ const uint loopdata_out_len,
+ short *tangent_mask_curr_p)
{
- BMesh *bm = em->bm;
-
- int act_uv_n = -1;
- int ren_uv_n = -1;
- bool calc_act = false;
- bool calc_ren = false;
- char act_uv_name[MAX_NAME];
- char ren_uv_name[MAX_NAME];
- short tangent_mask = 0;
- short tangent_mask_curr = *tangent_mask_curr_p;
-
- BKE_mesh_calc_loop_tangent_step_0(
- &bm->ldata, calc_active_tangent, tangent_names, tangent_names_len,
- &calc_act, &calc_ren, &act_uv_n, &ren_uv_n, act_uv_name, ren_uv_name, &tangent_mask);
-
- if ((tangent_mask_curr | tangent_mask) != tangent_mask_curr) {
- for (int i = 0; i < tangent_names_len; i++) {
- if (tangent_names[i][0]) {
- BKE_mesh_add_loop_tangent_named_layer_for_uv(
- &bm->ldata, loopdata_out, (int)loopdata_out_len, tangent_names[i]);
- }
- }
- if ((tangent_mask & DM_TANGENT_MASK_ORCO) && CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, "") == -1)
- CustomData_add_layer_named(loopdata_out, CD_TANGENT, CD_CALLOC, NULL, (int)loopdata_out_len, "");
- if (calc_act && act_uv_name[0])
- BKE_mesh_add_loop_tangent_named_layer_for_uv(&bm->ldata, loopdata_out, (int)loopdata_out_len, act_uv_name);
- if (calc_ren && ren_uv_name[0])
- BKE_mesh_add_loop_tangent_named_layer_for_uv(&bm->ldata, loopdata_out, (int)loopdata_out_len, ren_uv_name);
- int totface = em->tottri;
+ BMesh *bm = em->bm;
+
+ int act_uv_n = -1;
+ int ren_uv_n = -1;
+ bool calc_act = false;
+ bool calc_ren = false;
+ char act_uv_name[MAX_NAME];
+ char ren_uv_name[MAX_NAME];
+ short tangent_mask = 0;
+ short tangent_mask_curr = *tangent_mask_curr_p;
+
+ BKE_mesh_calc_loop_tangent_step_0(&bm->ldata,
+ calc_active_tangent,
+ tangent_names,
+ tangent_names_len,
+ &calc_act,
+ &calc_ren,
+ &act_uv_n,
+ &ren_uv_n,
+ act_uv_name,
+ ren_uv_name,
+ &tangent_mask);
+
+ if ((tangent_mask_curr | tangent_mask) != tangent_mask_curr) {
+ for (int i = 0; i < tangent_names_len; i++) {
+ if (tangent_names[i][0]) {
+ BKE_mesh_add_loop_tangent_named_layer_for_uv(
+ &bm->ldata, loopdata_out, (int)loopdata_out_len, tangent_names[i]);
+ }
+ }
+ if ((tangent_mask & DM_TANGENT_MASK_ORCO) &&
+ CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, "") == -1)
+ CustomData_add_layer_named(
+ loopdata_out, CD_TANGENT, CD_CALLOC, NULL, (int)loopdata_out_len, "");
+ if (calc_act && act_uv_name[0])
+ BKE_mesh_add_loop_tangent_named_layer_for_uv(
+ &bm->ldata, loopdata_out, (int)loopdata_out_len, act_uv_name);
+ if (calc_ren && ren_uv_name[0])
+ BKE_mesh_add_loop_tangent_named_layer_for_uv(
+ &bm->ldata, loopdata_out, (int)loopdata_out_len, ren_uv_name);
+ int totface = em->tottri;
#ifdef USE_LOOPTRI_DETECT_QUADS
- int num_face_as_quad_map;
- int *face_as_quad_map = NULL;
-
- /* map faces to quads */
- if (em->tottri != bm->totface) {
- /* over alloc, since we dont know how many ngon or quads we have */
-
- /* map fake face index to looptri */
- face_as_quad_map = MEM_mallocN(sizeof(int) * totface, __func__);
- int i, j;
- for (i = 0, j = 0; j < totface; i++, j++) {
- face_as_quad_map[i] = j;
- /* step over all quads */
- if (em->looptris[j][0]->f->len == 4) {
- j++; /* skips the nest looptri */
- }
- }
- num_face_as_quad_map = i;
- }
- else {
- num_face_as_quad_map = totface;
- }
+ int num_face_as_quad_map;
+ int *face_as_quad_map = NULL;
+
+ /* map faces to quads */
+ if (em->tottri != bm->totface) {
+ /* over alloc, since we dont know how many ngon or quads we have */
+
+ /* map fake face index to looptri */
+ face_as_quad_map = MEM_mallocN(sizeof(int) * totface, __func__);
+ int i, j;
+ for (i = 0, j = 0; j < totface; i++, j++) {
+ face_as_quad_map[i] = j;
+ /* step over all quads */
+ if (em->looptris[j][0]->f->len == 4) {
+ j++; /* skips the nest looptri */
+ }
+ }
+ num_face_as_quad_map = i;
+ }
+ else {
+ num_face_as_quad_map = totface;
+ }
#endif
- /* Calculation */
- if (em->tottri != 0) {
- TaskScheduler *scheduler = BLI_task_scheduler_get();
- TaskPool *task_pool;
- task_pool = BLI_task_pool_create(scheduler, NULL);
-
- tangent_mask_curr = 0;
- /* Calculate tangent layers */
- SGLSLEditMeshToTangent data_array[MAX_MTFACE];
- int index = 0;
- int n = 0;
- CustomData_update_typemap(loopdata_out);
- const int tangent_layer_num = CustomData_number_of_layers(loopdata_out, CD_TANGENT);
- for (n = 0; n < tangent_layer_num; n++) {
- index = CustomData_get_layer_index_n(loopdata_out, CD_TANGENT, n);
- BLI_assert(n < MAX_MTFACE);
- SGLSLEditMeshToTangent *mesh2tangent = &data_array[n];
- mesh2tangent->numTessFaces = em->tottri;
+ /* Calculation */
+ if (em->tottri != 0) {
+ TaskScheduler *scheduler = BLI_task_scheduler_get();
+ TaskPool *task_pool;
+ task_pool = BLI_task_pool_create(scheduler, NULL);
+
+ tangent_mask_curr = 0;
+ /* Calculate tangent layers */
+ SGLSLEditMeshToTangent data_array[MAX_MTFACE];
+ int index = 0;
+ int n = 0;
+ CustomData_update_typemap(loopdata_out);
+ const int tangent_layer_num = CustomData_number_of_layers(loopdata_out, CD_TANGENT);
+ for (n = 0; n < tangent_layer_num; n++) {
+ index = CustomData_get_layer_index_n(loopdata_out, CD_TANGENT, n);
+ BLI_assert(n < MAX_MTFACE);
+ SGLSLEditMeshToTangent *mesh2tangent = &data_array[n];
+ mesh2tangent->numTessFaces = em->tottri;
#ifdef USE_LOOPTRI_DETECT_QUADS
- mesh2tangent->face_as_quad_map = face_as_quad_map;
- mesh2tangent->num_face_as_quad_map = num_face_as_quad_map;
+ mesh2tangent->face_as_quad_map = face_as_quad_map;
+ mesh2tangent->num_face_as_quad_map = num_face_as_quad_map;
#endif
- mesh2tangent->precomputedFaceNormals = poly_normals;
- /* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled),
- * have to check this is valid...
- */
- mesh2tangent->precomputedLoopNormals = loop_normals;
- mesh2tangent->cd_loop_uv_offset = CustomData_get_n_offset(&bm->ldata, CD_MLOOPUV, n);
-
- /* needed for indexing loop-tangents */
- int htype_index = BM_LOOP;
- if (mesh2tangent->cd_loop_uv_offset == -1) {
- mesh2tangent->orco = vert_orco;
- if (!mesh2tangent->orco)
- continue;
- /* needed for orco lookups */
- htype_index |= BM_VERT;
- tangent_mask_curr |= DM_TANGENT_MASK_ORCO;
- }
- else {
- /* Fill the resulting tangent_mask */
- int uv_ind = CustomData_get_named_layer_index(&bm->ldata, CD_MLOOPUV, loopdata_out->layers[index].name);
- int uv_start = CustomData_get_layer_index(&bm->ldata, CD_MLOOPUV);
- BLI_assert(uv_ind != -1 && uv_start != -1);
- BLI_assert(uv_ind - uv_start < MAX_MTFACE);
- tangent_mask_curr |= 1 << (uv_ind - uv_start);
- }
- if (mesh2tangent->precomputedFaceNormals) {
- /* needed for face normal lookups */
- htype_index |= BM_FACE;
- }
- BM_mesh_elem_index_ensure(bm, htype_index);
-
- mesh2tangent->looptris = (const BMLoop *(*)[3])em->looptris;
- mesh2tangent->tangent = loopdata_out->layers[index].data;
-
- BLI_task_pool_push(task_pool, emDM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW);
- }
-
- BLI_assert(tangent_mask_curr == tangent_mask);
- BLI_task_pool_work_and_wait(task_pool);
- BLI_task_pool_free(task_pool);
- }
- else {
- tangent_mask_curr = tangent_mask;
- }
+ mesh2tangent->precomputedFaceNormals = poly_normals;
+ /* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled),
+ * have to check this is valid...
+ */
+ mesh2tangent->precomputedLoopNormals = loop_normals;
+ mesh2tangent->cd_loop_uv_offset = CustomData_get_n_offset(&bm->ldata, CD_MLOOPUV, n);
+
+ /* needed for indexing loop-tangents */
+ int htype_index = BM_LOOP;
+ if (mesh2tangent->cd_loop_uv_offset == -1) {
+ mesh2tangent->orco = vert_orco;
+ if (!mesh2tangent->orco)
+ continue;
+ /* needed for orco lookups */
+ htype_index |= BM_VERT;
+ tangent_mask_curr |= DM_TANGENT_MASK_ORCO;
+ }
+ else {
+ /* Fill the resulting tangent_mask */
+ int uv_ind = CustomData_get_named_layer_index(
+ &bm->ldata, CD_MLOOPUV, loopdata_out->layers[index].name);
+ int uv_start = CustomData_get_layer_index(&bm->ldata, CD_MLOOPUV);
+ BLI_assert(uv_ind != -1 && uv_start != -1);
+ BLI_assert(uv_ind - uv_start < MAX_MTFACE);
+ tangent_mask_curr |= 1 << (uv_ind - uv_start);
+ }
+ if (mesh2tangent->precomputedFaceNormals) {
+ /* needed for face normal lookups */
+ htype_index |= BM_FACE;
+ }
+ BM_mesh_elem_index_ensure(bm, htype_index);
+
+ mesh2tangent->looptris = (const BMLoop *(*)[3])em->looptris;
+ mesh2tangent->tangent = loopdata_out->layers[index].data;
+
+ BLI_task_pool_push(
+ task_pool, emDM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW);
+ }
+
+ BLI_assert(tangent_mask_curr == tangent_mask);
+ BLI_task_pool_work_and_wait(task_pool);
+ BLI_task_pool_free(task_pool);
+ }
+ else {
+ tangent_mask_curr = tangent_mask;
+ }
#ifdef USE_LOOPTRI_DETECT_QUADS
- if (face_as_quad_map) {
- MEM_freeN(face_as_quad_map);
- }
-#undef USE_LOOPTRI_DETECT_QUADS
+ if (face_as_quad_map) {
+ MEM_freeN(face_as_quad_map);
+ }
+# undef USE_LOOPTRI_DETECT_QUADS
#endif
- }
-
- *tangent_mask_curr_p = tangent_mask_curr;
-
- int act_uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, act_uv_n);
- if (act_uv_index >= 0) {
- int tan_index = CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, bm->ldata.layers[act_uv_index].name);
- CustomData_set_layer_active_index(loopdata_out, CD_TANGENT, tan_index);
- } /* else tangent has been built from orco */
-
- /* Update render layer index */
- int ren_uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, ren_uv_n);
- if (ren_uv_index >= 0) {
- int tan_index = CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, bm->ldata.layers[ren_uv_index].name);
- CustomData_set_layer_render_index(loopdata_out, CD_TANGENT, tan_index);
- } /* else tangent has been built from orco */
+ }
+
+ *tangent_mask_curr_p = tangent_mask_curr;
+
+ int act_uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, act_uv_n);
+ if (act_uv_index >= 0) {
+ int tan_index = CustomData_get_named_layer_index(
+ loopdata_out, CD_TANGENT, bm->ldata.layers[act_uv_index].name);
+ CustomData_set_layer_active_index(loopdata_out, CD_TANGENT, tan_index);
+ } /* else tangent has been built from orco */
+
+ /* Update render layer index */
+ int ren_uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, ren_uv_n);
+ if (ren_uv_index >= 0) {
+ int tan_index = CustomData_get_named_layer_index(
+ loopdata_out, CD_TANGENT, bm->ldata.layers[ren_uv_index].name);
+ CustomData_set_layer_render_index(loopdata_out, CD_TANGENT, tan_index);
+ } /* else tangent has been built from orco */
}
/** \} */
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index 5628fce226c..67b57d6f613 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -49,7 +49,7 @@
#include "PIL_time.h"
-#include "BKE_anim.h" /* needed for where_on_path */
+#include "BKE_anim.h" /* needed for where_on_path */
#include "BKE_bvhutils.h"
#include "BKE_collection.h"
#include "BKE_collision.h"
@@ -73,1002 +73,1062 @@
/* fluid sim particle import */
#ifdef WITH_MOD_FLUID
-#include "LBM_fluidsim.h"
-#include <zlib.h>
-#include <string.h>
-#endif // WITH_MOD_FLUID
+# include "LBM_fluidsim.h"
+# include <zlib.h>
+# include <string.h>
+#endif // WITH_MOD_FLUID
EffectorWeights *BKE_effector_add_weights(Collection *collection)
{
- EffectorWeights *weights = MEM_callocN(sizeof(EffectorWeights), "EffectorWeights");
- int i;
+ EffectorWeights *weights = MEM_callocN(sizeof(EffectorWeights), "EffectorWeights");
+ int i;
- for (i = 0; i < NUM_PFIELD_TYPES; i++) {
- weights->weight[i] = 1.0f;
- }
+ for (i = 0; i < NUM_PFIELD_TYPES; i++) {
+ weights->weight[i] = 1.0f;
+ }
- weights->global_gravity = 1.0f;
+ weights->global_gravity = 1.0f;
- weights->group = collection;
+ weights->group = collection;
- return weights;
+ return weights;
}
PartDeflect *BKE_partdeflect_new(int type)
{
- PartDeflect *pd;
-
- pd = MEM_callocN(sizeof(PartDeflect), "PartDeflect");
-
- pd->forcefield = type;
- pd->pdef_sbdamp = 0.1f;
- pd->pdef_sbift = 0.2f;
- pd->pdef_sboft = 0.02f;
- pd->pdef_cfrict = 5.0f;
- pd->seed = ((uint)(ceil(PIL_check_seconds_timer())) + 1) % 128;
- pd->f_strength = 1.0f;
- pd->f_damp = 1.0f;
-
- /* set sensible defaults based on type */
- switch (type) {
- case PFIELD_VORTEX:
- pd->shape = PFIELD_SHAPE_PLANE;
- break;
- case PFIELD_WIND:
- pd->shape = PFIELD_SHAPE_PLANE;
- pd->f_flow = 1.0f; /* realistic wind behavior */
- break;
- case PFIELD_TEXTURE:
- pd->f_size = 1.0f;
- break;
- case PFIELD_SMOKEFLOW:
- pd->f_flow = 1.0f;
- break;
- }
- pd->flag = PFIELD_DO_LOCATION | PFIELD_DO_ROTATION | PFIELD_CLOTH_USE_CULLING;
-
- return pd;
+ PartDeflect *pd;
+
+ pd = MEM_callocN(sizeof(PartDeflect), "PartDeflect");
+
+ pd->forcefield = type;
+ pd->pdef_sbdamp = 0.1f;
+ pd->pdef_sbift = 0.2f;
+ pd->pdef_sboft = 0.02f;
+ pd->pdef_cfrict = 5.0f;
+ pd->seed = ((uint)(ceil(PIL_check_seconds_timer())) + 1) % 128;
+ pd->f_strength = 1.0f;
+ pd->f_damp = 1.0f;
+
+ /* set sensible defaults based on type */
+ switch (type) {
+ case PFIELD_VORTEX:
+ pd->shape = PFIELD_SHAPE_PLANE;
+ break;
+ case PFIELD_WIND:
+ pd->shape = PFIELD_SHAPE_PLANE;
+ pd->f_flow = 1.0f; /* realistic wind behavior */
+ break;
+ case PFIELD_TEXTURE:
+ pd->f_size = 1.0f;
+ break;
+ case PFIELD_SMOKEFLOW:
+ pd->f_flow = 1.0f;
+ break;
+ }
+ pd->flag = PFIELD_DO_LOCATION | PFIELD_DO_ROTATION | PFIELD_CLOTH_USE_CULLING;
+
+ return pd;
}
/************************ PARTICLES ***************************/
PartDeflect *BKE_partdeflect_copy(const struct PartDeflect *pd_src)
{
- if (pd_src == NULL) {
- return NULL;
- }
- PartDeflect *pd_dst = MEM_dupallocN(pd_src);
- if (pd_dst->rng != NULL) {
- pd_dst->rng = BLI_rng_copy(pd_dst->rng);
- }
- return pd_dst;
+ if (pd_src == NULL) {
+ return NULL;
+ }
+ PartDeflect *pd_dst = MEM_dupallocN(pd_src);
+ if (pd_dst->rng != NULL) {
+ pd_dst->rng = BLI_rng_copy(pd_dst->rng);
+ }
+ return pd_dst;
}
void BKE_partdeflect_free(PartDeflect *pd)
{
- if (!pd) {
- return;
- }
- if (pd->rng) {
- BLI_rng_free(pd->rng);
- }
- MEM_freeN(pd);
+ if (!pd) {
+ return;
+ }
+ if (pd->rng) {
+ BLI_rng_free(pd->rng);
+ }
+ MEM_freeN(pd);
}
/******************** EFFECTOR RELATIONS ***********************/
static void precalculate_effector(struct Depsgraph *depsgraph, EffectorCache *eff)
{
- float ctime = DEG_get_ctime(depsgraph);
- uint cfra = (uint)(ctime >= 0 ? ctime : -ctime);
- if (!eff->pd->rng) {
- eff->pd->rng = BLI_rng_new(eff->pd->seed + cfra);
- }
- else {
- BLI_rng_srandom(eff->pd->rng, eff->pd->seed + cfra);
- }
-
- if (eff->pd->forcefield == PFIELD_GUIDE && eff->ob->type == OB_CURVE) {
- Curve *cu = eff->ob->data;
- if (cu->flag & CU_PATH) {
- if (eff->ob->runtime.curve_cache == NULL || eff->ob->runtime.curve_cache->path == NULL || eff->ob->runtime.curve_cache->path->data == NULL)
- BKE_displist_make_curveTypes(depsgraph, eff->scene, eff->ob, false, false, NULL);
-
- if (eff->ob->runtime.curve_cache->path && eff->ob->runtime.curve_cache->path->data) {
- where_on_path(eff->ob, 0.0, eff->guide_loc, eff->guide_dir, NULL, &eff->guide_radius, NULL);
- mul_m4_v3(eff->ob->obmat, eff->guide_loc);
- mul_mat3_m4_v3(eff->ob->obmat, eff->guide_dir);
- }
- }
- }
- else if (eff->pd->shape == PFIELD_SHAPE_SURFACE) {
- eff->surmd = (SurfaceModifierData *)modifiers_findByType(eff->ob, eModifierType_Surface);
- if (eff->ob->type == OB_CURVE)
- eff->flag |= PE_USE_NORMAL_DATA;
- }
- else if (eff->psys)
- psys_update_particle_tree(eff->psys, ctime);
+ float ctime = DEG_get_ctime(depsgraph);
+ uint cfra = (uint)(ctime >= 0 ? ctime : -ctime);
+ if (!eff->pd->rng) {
+ eff->pd->rng = BLI_rng_new(eff->pd->seed + cfra);
+ }
+ else {
+ BLI_rng_srandom(eff->pd->rng, eff->pd->seed + cfra);
+ }
+
+ if (eff->pd->forcefield == PFIELD_GUIDE && eff->ob->type == OB_CURVE) {
+ Curve *cu = eff->ob->data;
+ if (cu->flag & CU_PATH) {
+ if (eff->ob->runtime.curve_cache == NULL || eff->ob->runtime.curve_cache->path == NULL ||
+ eff->ob->runtime.curve_cache->path->data == NULL)
+ BKE_displist_make_curveTypes(depsgraph, eff->scene, eff->ob, false, false, NULL);
+
+ if (eff->ob->runtime.curve_cache->path && eff->ob->runtime.curve_cache->path->data) {
+ where_on_path(
+ eff->ob, 0.0, eff->guide_loc, eff->guide_dir, NULL, &eff->guide_radius, NULL);
+ mul_m4_v3(eff->ob->obmat, eff->guide_loc);
+ mul_mat3_m4_v3(eff->ob->obmat, eff->guide_dir);
+ }
+ }
+ }
+ else if (eff->pd->shape == PFIELD_SHAPE_SURFACE) {
+ eff->surmd = (SurfaceModifierData *)modifiers_findByType(eff->ob, eModifierType_Surface);
+ if (eff->ob->type == OB_CURVE)
+ eff->flag |= PE_USE_NORMAL_DATA;
+ }
+ else if (eff->psys)
+ psys_update_particle_tree(eff->psys, ctime);
}
-static void add_effector_relation(ListBase *relations, Object *ob, ParticleSystem *psys, PartDeflect *pd)
+static void add_effector_relation(ListBase *relations,
+ Object *ob,
+ ParticleSystem *psys,
+ PartDeflect *pd)
{
- EffectorRelation *relation = MEM_callocN(sizeof(EffectorRelation), "EffectorRelation");
- relation->ob = ob;
- relation->psys = psys;
- relation->pd = pd;
+ EffectorRelation *relation = MEM_callocN(sizeof(EffectorRelation), "EffectorRelation");
+ relation->ob = ob;
+ relation->psys = psys;
+ relation->pd = pd;
- BLI_addtail(relations, relation);
+ BLI_addtail(relations, relation);
}
-static void add_effector_evaluation(ListBase **effectors, Depsgraph *depsgraph, Scene *scene, Object *ob, ParticleSystem *psys, PartDeflect *pd)
+static void add_effector_evaluation(ListBase **effectors,
+ Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ ParticleSystem *psys,
+ PartDeflect *pd)
{
- if (*effectors == NULL) {
- *effectors = MEM_callocN(sizeof(ListBase), "effector effectors");
- }
-
- EffectorCache *eff = MEM_callocN(sizeof(EffectorCache), "EffectorCache");
- eff->depsgraph = depsgraph;
- eff->scene = scene;
- eff->ob = ob;
- eff->psys = psys;
- eff->pd = pd;
- eff->frame = -1;
- BLI_addtail(*effectors, eff);
-
- precalculate_effector(depsgraph, eff);
+ if (*effectors == NULL) {
+ *effectors = MEM_callocN(sizeof(ListBase), "effector effectors");
+ }
+
+ EffectorCache *eff = MEM_callocN(sizeof(EffectorCache), "EffectorCache");
+ eff->depsgraph = depsgraph;
+ eff->scene = scene;
+ eff->ob = ob;
+ eff->psys = psys;
+ eff->pd = pd;
+ eff->frame = -1;
+ BLI_addtail(*effectors, eff);
+
+ precalculate_effector(depsgraph, eff);
}
/* Create list of effector relations in the collection or entire scene.
* This is used by the depsgraph to build relations, as well as faster
* lookup of effectors during evaluation. */
-ListBase *BKE_effector_relations_create(
- Depsgraph *depsgraph,
- ViewLayer *view_layer,
- Collection *collection)
+ListBase *BKE_effector_relations_create(Depsgraph *depsgraph,
+ ViewLayer *view_layer,
+ Collection *collection)
{
- Base *base = BKE_collection_or_layer_objects(view_layer, collection);
- const bool for_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
- const int base_flag = (for_render) ? BASE_ENABLED_RENDER : BASE_ENABLED_VIEWPORT;
-
- ListBase *relations = MEM_callocN(sizeof(ListBase), "effector relations");
-
- for (; base; base = base->next) {
- if (!(base->flag & base_flag)) {
- continue;
- }
-
- Object *ob = base->object;
-
- if (ob->pd && ob->pd->forcefield) {
- add_effector_relation(relations, ob, NULL, ob->pd);
- }
-
- for (ParticleSystem *psys = ob->particlesystem.first; psys; psys = psys->next) {
- ParticleSettings *part = psys->part;
-
- if (psys_check_enabled(ob, psys, for_render)) {
- if (part->pd && part->pd->forcefield) {
- add_effector_relation(relations, ob, psys, part->pd);
- }
- if (part->pd2 && part->pd2->forcefield) {
- add_effector_relation(relations, ob, psys, part->pd2);
- }
- }
- }
- }
-
- return relations;
+ Base *base = BKE_collection_or_layer_objects(view_layer, collection);
+ const bool for_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
+ const int base_flag = (for_render) ? BASE_ENABLED_RENDER : BASE_ENABLED_VIEWPORT;
+
+ ListBase *relations = MEM_callocN(sizeof(ListBase), "effector relations");
+
+ for (; base; base = base->next) {
+ if (!(base->flag & base_flag)) {
+ continue;
+ }
+
+ Object *ob = base->object;
+
+ if (ob->pd && ob->pd->forcefield) {
+ add_effector_relation(relations, ob, NULL, ob->pd);
+ }
+
+ for (ParticleSystem *psys = ob->particlesystem.first; psys; psys = psys->next) {
+ ParticleSettings *part = psys->part;
+
+ if (psys_check_enabled(ob, psys, for_render)) {
+ if (part->pd && part->pd->forcefield) {
+ add_effector_relation(relations, ob, psys, part->pd);
+ }
+ if (part->pd2 && part->pd2->forcefield) {
+ add_effector_relation(relations, ob, psys, part->pd2);
+ }
+ }
+ }
+ }
+
+ return relations;
}
void BKE_effector_relations_free(ListBase *lb)
{
- if (lb) {
- BLI_freelistN(lb);
- MEM_freeN(lb);
- }
+ if (lb) {
+ BLI_freelistN(lb);
+ MEM_freeN(lb);
+ }
}
/* Create effective list of effectors from relations built beforehand. */
-ListBase *BKE_effectors_create(
- Depsgraph *depsgraph,
- Object *ob_src,
- ParticleSystem *psys_src,
- EffectorWeights *weights)
+ListBase *BKE_effectors_create(Depsgraph *depsgraph,
+ Object *ob_src,
+ ParticleSystem *psys_src,
+ EffectorWeights *weights)
{
- Scene *scene = DEG_get_evaluated_scene(depsgraph);
- ListBase *relations = DEG_get_effector_relations(depsgraph, weights->group);
- ListBase *effectors = NULL;
-
- if (!relations) {
- return NULL;
- }
-
- for (EffectorRelation *relation = relations->first; relation; relation = relation->next) {
- /* Get evaluated object. */
- Object *ob = (Object *)DEG_get_evaluated_id(depsgraph, &relation->ob->id);
-
- if (relation->psys) {
- /* Get evaluated particle system. */
- ParticleSystem *psys = BLI_findstring(&ob->particlesystem,
- relation->psys->name, offsetof(ParticleSystem, name));
- ParticleSettings *part = psys->part;
-
- if (psys == psys_src && (part->flag & PART_SELF_EFFECT) == 0) {
- continue;
- }
-
- PartDeflect *pd = (relation->pd == relation->psys->part->pd) ? part->pd : part->pd2;
- if (weights->weight[pd->forcefield] == 0.0f) {
- continue;
- }
-
- add_effector_evaluation(&effectors, depsgraph, scene, ob, psys, pd);
- }
- else {
- /* Object effector. */
- if (ob == ob_src) {
- continue;
- }
- else if (weights->weight[ob->pd->forcefield] == 0.0f) {
- continue;
- }
- else if (ob->pd->shape == PFIELD_SHAPE_POINTS && ob->runtime.mesh_eval == NULL) {
- continue;
- }
-
- add_effector_evaluation(&effectors, depsgraph, scene, ob, NULL, ob->pd);
- }
- }
-
- return effectors;
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ ListBase *relations = DEG_get_effector_relations(depsgraph, weights->group);
+ ListBase *effectors = NULL;
+
+ if (!relations) {
+ return NULL;
+ }
+
+ for (EffectorRelation *relation = relations->first; relation; relation = relation->next) {
+ /* Get evaluated object. */
+ Object *ob = (Object *)DEG_get_evaluated_id(depsgraph, &relation->ob->id);
+
+ if (relation->psys) {
+ /* Get evaluated particle system. */
+ ParticleSystem *psys = BLI_findstring(
+ &ob->particlesystem, relation->psys->name, offsetof(ParticleSystem, name));
+ ParticleSettings *part = psys->part;
+
+ if (psys == psys_src && (part->flag & PART_SELF_EFFECT) == 0) {
+ continue;
+ }
+
+ PartDeflect *pd = (relation->pd == relation->psys->part->pd) ? part->pd : part->pd2;
+ if (weights->weight[pd->forcefield] == 0.0f) {
+ continue;
+ }
+
+ add_effector_evaluation(&effectors, depsgraph, scene, ob, psys, pd);
+ }
+ else {
+ /* Object effector. */
+ if (ob == ob_src) {
+ continue;
+ }
+ else if (weights->weight[ob->pd->forcefield] == 0.0f) {
+ continue;
+ }
+ else if (ob->pd->shape == PFIELD_SHAPE_POINTS && ob->runtime.mesh_eval == NULL) {
+ continue;
+ }
+
+ add_effector_evaluation(&effectors, depsgraph, scene, ob, NULL, ob->pd);
+ }
+ }
+
+ return effectors;
}
void BKE_effectors_free(ListBase *lb)
{
- if (lb) {
- for (EffectorCache *eff = lb->first; eff; eff = eff->next) {
- if (eff->guide_data) {
- MEM_freeN(eff->guide_data);
- }
- }
-
- BLI_freelistN(lb);
- MEM_freeN(lb);
- }
+ if (lb) {
+ for (EffectorCache *eff = lb->first; eff; eff = eff->next) {
+ if (eff->guide_data) {
+ MEM_freeN(eff->guide_data);
+ }
+ }
+
+ BLI_freelistN(lb);
+ MEM_freeN(lb);
+ }
}
-
-void pd_point_from_particle(ParticleSimulationData *sim, ParticleData *pa, ParticleKey *state, EffectedPoint *point)
+void pd_point_from_particle(ParticleSimulationData *sim,
+ ParticleData *pa,
+ ParticleKey *state,
+ EffectedPoint *point)
{
- ParticleSettings *part = sim->psys->part;
- point->loc = state->co;
- point->vel = state->vel;
- point->index = pa - sim->psys->particles;
- point->size = pa->size;
- point->charge = 0.0f;
+ ParticleSettings *part = sim->psys->part;
+ point->loc = state->co;
+ point->vel = state->vel;
+ point->index = pa - sim->psys->particles;
+ point->size = pa->size;
+ point->charge = 0.0f;
- if (part->pd && part->pd->forcefield == PFIELD_CHARGE)
- point->charge += part->pd->f_strength;
+ if (part->pd && part->pd->forcefield == PFIELD_CHARGE)
+ point->charge += part->pd->f_strength;
- if (part->pd2 && part->pd2->forcefield == PFIELD_CHARGE)
- point->charge += part->pd2->f_strength;
+ if (part->pd2 && part->pd2->forcefield == PFIELD_CHARGE)
+ point->charge += part->pd2->f_strength;
- point->vel_to_sec = 1.0f;
- point->vel_to_frame = psys_get_timestep(sim);
+ point->vel_to_sec = 1.0f;
+ point->vel_to_frame = psys_get_timestep(sim);
- point->flag = 0;
+ point->flag = 0;
- if (sim->psys->part->flag & PART_ROT_DYN) {
- point->ave = state->ave;
- point->rot = state->rot;
- }
- else
- point->ave = point->rot = NULL;
+ if (sim->psys->part->flag & PART_ROT_DYN) {
+ point->ave = state->ave;
+ point->rot = state->rot;
+ }
+ else
+ point->ave = point->rot = NULL;
- point->psys = sim->psys;
+ point->psys = sim->psys;
}
void pd_point_from_loc(Scene *scene, float *loc, float *vel, int index, EffectedPoint *point)
{
- point->loc = loc;
- point->vel = vel;
- point->index = index;
- point->size = 0.0f;
+ point->loc = loc;
+ point->vel = vel;
+ point->index = index;
+ point->size = 0.0f;
- point->vel_to_sec = (float)scene->r.frs_sec;
- point->vel_to_frame = 1.0f;
+ point->vel_to_sec = (float)scene->r.frs_sec;
+ point->vel_to_frame = 1.0f;
- point->flag = 0;
+ point->flag = 0;
- point->ave = point->rot = NULL;
- point->psys = NULL;
+ point->ave = point->rot = NULL;
+ point->psys = NULL;
}
void pd_point_from_soft(Scene *scene, float *loc, float *vel, int index, EffectedPoint *point)
{
- point->loc = loc;
- point->vel = vel;
- point->index = index;
- point->size = 0.0f;
+ point->loc = loc;
+ point->vel = vel;
+ point->index = index;
+ point->size = 0.0f;
- point->vel_to_sec = (float)scene->r.frs_sec;
- point->vel_to_frame = 1.0f;
+ point->vel_to_sec = (float)scene->r.frs_sec;
+ point->vel_to_frame = 1.0f;
- point->flag = PE_WIND_AS_SPEED;
+ point->flag = PE_WIND_AS_SPEED;
- point->ave = point->rot = NULL;
+ point->ave = point->rot = NULL;
- point->psys = NULL;
+ point->psys = NULL;
}
/************************************************/
-/* Effectors */
+/* Effectors */
/************************************************/
// triangle - ray callback function
-static void eff_tri_ray_hit(void *UNUSED(userData), int UNUSED(index), const BVHTreeRay *UNUSED(ray), BVHTreeRayHit *hit)
+static void eff_tri_ray_hit(void *UNUSED(userData),
+ int UNUSED(index),
+ const BVHTreeRay *UNUSED(ray),
+ BVHTreeRayHit *hit)
{
- /* whenever we hit a bounding box, we don't check further */
- hit->dist = -1;
- hit->index = 1;
+ /* whenever we hit a bounding box, we don't check further */
+ hit->dist = -1;
+ hit->index = 1;
}
// get visibility of a wind ray
-static float eff_calc_visibility(ListBase *colliders, EffectorCache *eff, EffectorData *efd, EffectedPoint *point)
+static float eff_calc_visibility(ListBase *colliders,
+ EffectorCache *eff,
+ EffectorData *efd,
+ EffectedPoint *point)
{
- const int raycast_flag = BVH_RAYCAST_DEFAULT & ~(BVH_RAYCAST_WATERTIGHT);
- ListBase *colls = colliders;
- ColliderCache *col;
- float norm[3], len = 0.0;
- float visibility = 1.0, absorption = 0.0;
-
- if (!(eff->pd->flag & PFIELD_VISIBILITY)) {
- return visibility;
- }
- if (!colls) {
- colls = BKE_collider_cache_create(eff->depsgraph, eff->ob, NULL);
- }
- if (!colls) {
- return visibility;
- }
-
- negate_v3_v3(norm, efd->vec_to_point);
- len = normalize_v3(norm);
-
- /* check all collision objects */
- for (col = colls->first; col; col = col->next) {
- CollisionModifierData *collmd = col->collmd;
-
- if (col->ob == eff->ob) {
- continue;
- }
- if (collmd->bvhtree) {
- BVHTreeRayHit hit;
-
- hit.index = -1;
- hit.dist = len + FLT_EPSILON;
-
- /* check if the way is blocked */
- if (BLI_bvhtree_ray_cast_ex(
- collmd->bvhtree, point->loc, norm, 0.0f, &hit,
- eff_tri_ray_hit, NULL, raycast_flag) != -1)
- {
- absorption = col->ob->pd->absorption;
-
- /* visibility is only between 0 and 1, calculated from 1-absorption */
- visibility *= CLAMPIS(1.0f - absorption, 0.0f, 1.0f);
-
- if (visibility <= 0.0f) {
- break;
- }
- }
- }
- }
-
- if (!colliders)
- BKE_collider_cache_free(&colls);
-
- return visibility;
+ const int raycast_flag = BVH_RAYCAST_DEFAULT & ~(BVH_RAYCAST_WATERTIGHT);
+ ListBase *colls = colliders;
+ ColliderCache *col;
+ float norm[3], len = 0.0;
+ float visibility = 1.0, absorption = 0.0;
+
+ if (!(eff->pd->flag & PFIELD_VISIBILITY)) {
+ return visibility;
+ }
+ if (!colls) {
+ colls = BKE_collider_cache_create(eff->depsgraph, eff->ob, NULL);
+ }
+ if (!colls) {
+ return visibility;
+ }
+
+ negate_v3_v3(norm, efd->vec_to_point);
+ len = normalize_v3(norm);
+
+ /* check all collision objects */
+ for (col = colls->first; col; col = col->next) {
+ CollisionModifierData *collmd = col->collmd;
+
+ if (col->ob == eff->ob) {
+ continue;
+ }
+ if (collmd->bvhtree) {
+ BVHTreeRayHit hit;
+
+ hit.index = -1;
+ hit.dist = len + FLT_EPSILON;
+
+ /* check if the way is blocked */
+ if (BLI_bvhtree_ray_cast_ex(collmd->bvhtree,
+ point->loc,
+ norm,
+ 0.0f,
+ &hit,
+ eff_tri_ray_hit,
+ NULL,
+ raycast_flag) != -1) {
+ absorption = col->ob->pd->absorption;
+
+ /* visibility is only between 0 and 1, calculated from 1-absorption */
+ visibility *= CLAMPIS(1.0f - absorption, 0.0f, 1.0f);
+
+ if (visibility <= 0.0f) {
+ break;
+ }
+ }
+ }
+ }
+
+ if (!colliders)
+ BKE_collider_cache_free(&colls);
+
+ return visibility;
}
// noise function for wind e.g.
static float wind_func(struct RNG *rng, float strength)
{
- int random = (BLI_rng_get_int(rng) + 1) % 128; /* max 2357 */
- float force = BLI_rng_get_float(rng) + 1.0f;
- float ret;
- float sign = 0;
+ int random = (BLI_rng_get_int(rng) + 1) % 128; /* max 2357 */
+ float force = BLI_rng_get_float(rng) + 1.0f;
+ float ret;
+ float sign = 0;
- /* Dividing by 2 is not giving equal sign distribution. */
- sign = ((float)random > 64.0f) ? 1.0f : -1.0f;
+ /* Dividing by 2 is not giving equal sign distribution. */
+ sign = ((float)random > 64.0f) ? 1.0f : -1.0f;
- ret = sign * ((float)random / force) * strength / 128.0f;
+ ret = sign * ((float)random / force) * strength / 128.0f;
- return ret;
+ return ret;
}
/* maxdist: zero effect from this distance outwards (if usemax) */
/* mindist: full effect up to this distance (if usemin) */
/* power: falloff with formula 1/r^power */
-static float falloff_func(float fac, int usemin, float mindist, int usemax, float maxdist, float power)
+static float falloff_func(
+ float fac, int usemin, float mindist, int usemax, float maxdist, float power)
{
- /* first quick checks */
- if (usemax && fac > maxdist)
- return 0.0f;
+ /* first quick checks */
+ if (usemax && fac > maxdist)
+ return 0.0f;
- if (usemin && fac < mindist)
- return 1.0f;
+ if (usemin && fac < mindist)
+ return 1.0f;
- if (!usemin)
- mindist = 0.0;
+ if (!usemin)
+ mindist = 0.0;
- return pow((double)(1.0f + fac - mindist), (double)(-power));
+ return pow((double)(1.0f + fac - mindist), (double)(-power));
}
static float falloff_func_dist(PartDeflect *pd, float fac)
{
- return falloff_func(fac, pd->flag & PFIELD_USEMIN, pd->mindist, pd->flag & PFIELD_USEMAX, pd->maxdist, pd->f_power);
+ return falloff_func(fac,
+ pd->flag & PFIELD_USEMIN,
+ pd->mindist,
+ pd->flag & PFIELD_USEMAX,
+ pd->maxdist,
+ pd->f_power);
}
static float falloff_func_rad(PartDeflect *pd, float fac)
{
- return falloff_func(fac, pd->flag & PFIELD_USEMINR, pd->minrad, pd->flag & PFIELD_USEMAXR, pd->maxrad, pd->f_power_r);
+ return falloff_func(fac,
+ pd->flag & PFIELD_USEMINR,
+ pd->minrad,
+ pd->flag & PFIELD_USEMAXR,
+ pd->maxrad,
+ pd->f_power_r);
}
-float effector_falloff(EffectorCache *eff, EffectorData *efd, EffectedPoint *UNUSED(point), EffectorWeights *weights)
+float effector_falloff(EffectorCache *eff,
+ EffectorData *efd,
+ EffectedPoint *UNUSED(point),
+ EffectorWeights *weights)
{
- float temp[3];
- float falloff = weights ? weights->weight[0] * weights->weight[eff->pd->forcefield] : 1.0f;
- float fac, r_fac;
-
- fac = dot_v3v3(efd->nor, efd->vec_to_point2);
-
- if (eff->pd->zdir == PFIELD_Z_POS && fac < 0.0f)
- falloff = 0.0f;
- else if (eff->pd->zdir == PFIELD_Z_NEG && fac > 0.0f)
- falloff = 0.0f;
- else {
- switch (eff->pd->falloff) {
- case PFIELD_FALL_SPHERE:
- falloff *= falloff_func_dist(eff->pd, efd->distance);
- break;
-
- case PFIELD_FALL_TUBE:
- falloff *= falloff_func_dist(eff->pd, ABS(fac));
- if (falloff == 0.0f)
- break;
-
- madd_v3_v3v3fl(temp, efd->vec_to_point2, efd->nor, -fac);
- r_fac = len_v3(temp);
- falloff *= falloff_func_rad(eff->pd, r_fac);
- break;
- case PFIELD_FALL_CONE:
- falloff *= falloff_func_dist(eff->pd, ABS(fac));
- if (falloff == 0.0f)
- break;
-
- r_fac = RAD2DEGF(saacos(fac / len_v3(efd->vec_to_point2)));
- falloff *= falloff_func_rad(eff->pd, r_fac);
-
- break;
- }
- }
-
- return falloff;
+ float temp[3];
+ float falloff = weights ? weights->weight[0] * weights->weight[eff->pd->forcefield] : 1.0f;
+ float fac, r_fac;
+
+ fac = dot_v3v3(efd->nor, efd->vec_to_point2);
+
+ if (eff->pd->zdir == PFIELD_Z_POS && fac < 0.0f)
+ falloff = 0.0f;
+ else if (eff->pd->zdir == PFIELD_Z_NEG && fac > 0.0f)
+ falloff = 0.0f;
+ else {
+ switch (eff->pd->falloff) {
+ case PFIELD_FALL_SPHERE:
+ falloff *= falloff_func_dist(eff->pd, efd->distance);
+ break;
+
+ case PFIELD_FALL_TUBE:
+ falloff *= falloff_func_dist(eff->pd, ABS(fac));
+ if (falloff == 0.0f)
+ break;
+
+ madd_v3_v3v3fl(temp, efd->vec_to_point2, efd->nor, -fac);
+ r_fac = len_v3(temp);
+ falloff *= falloff_func_rad(eff->pd, r_fac);
+ break;
+ case PFIELD_FALL_CONE:
+ falloff *= falloff_func_dist(eff->pd, ABS(fac));
+ if (falloff == 0.0f)
+ break;
+
+ r_fac = RAD2DEGF(saacos(fac / len_v3(efd->vec_to_point2)));
+ falloff *= falloff_func_rad(eff->pd, r_fac);
+
+ break;
+ }
+ }
+
+ return falloff;
}
-int closest_point_on_surface(SurfaceModifierData *surmd, const float co[3], float surface_co[3], float surface_nor[3], float surface_vel[3])
+int closest_point_on_surface(SurfaceModifierData *surmd,
+ const float co[3],
+ float surface_co[3],
+ float surface_nor[3],
+ float surface_vel[3])
{
- BVHTreeNearest nearest;
+ BVHTreeNearest nearest;
- nearest.index = -1;
- nearest.dist_sq = FLT_MAX;
+ nearest.index = -1;
+ nearest.dist_sq = FLT_MAX;
- BLI_bvhtree_find_nearest(surmd->bvhtree->tree, co, &nearest, surmd->bvhtree->nearest_callback, surmd->bvhtree);
+ BLI_bvhtree_find_nearest(
+ surmd->bvhtree->tree, co, &nearest, surmd->bvhtree->nearest_callback, surmd->bvhtree);
- if (nearest.index != -1) {
- copy_v3_v3(surface_co, nearest.co);
+ if (nearest.index != -1) {
+ copy_v3_v3(surface_co, nearest.co);
- if (surface_nor) {
- copy_v3_v3(surface_nor, nearest.no);
- }
+ if (surface_nor) {
+ copy_v3_v3(surface_nor, nearest.no);
+ }
- if (surface_vel) {
- const MLoop *mloop = surmd->bvhtree->loop;
- const MLoopTri *lt = &surmd->bvhtree->looptri[nearest.index];
+ if (surface_vel) {
+ const MLoop *mloop = surmd->bvhtree->loop;
+ const MLoopTri *lt = &surmd->bvhtree->looptri[nearest.index];
- copy_v3_v3(surface_vel, surmd->v[mloop[lt->tri[0]].v].co);
- add_v3_v3(surface_vel, surmd->v[mloop[lt->tri[1]].v].co);
- add_v3_v3(surface_vel, surmd->v[mloop[lt->tri[2]].v].co);
+ copy_v3_v3(surface_vel, surmd->v[mloop[lt->tri[0]].v].co);
+ add_v3_v3(surface_vel, surmd->v[mloop[lt->tri[1]].v].co);
+ add_v3_v3(surface_vel, surmd->v[mloop[lt->tri[2]].v].co);
- mul_v3_fl(surface_vel, (1.0f / 3.0f));
- }
- return 1;
- }
+ mul_v3_fl(surface_vel, (1.0f / 3.0f));
+ }
+ return 1;
+ }
- return 0;
+ return 0;
}
-int get_effector_data(EffectorCache *eff, EffectorData *efd, EffectedPoint *point, int real_velocity)
+int get_effector_data(EffectorCache *eff,
+ EffectorData *efd,
+ EffectedPoint *point,
+ int real_velocity)
{
- float cfra = DEG_get_ctime(eff->depsgraph);
- int ret = 0;
-
- /* 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];
-
- /* using velocity corrected location allows for easier sliding over effector surface */
- copy_v3_v3(vec, point->vel);
- mul_v3_fl(vec, point->vel_to_frame);
- add_v3_v3(vec, point->loc);
-
- ret = closest_point_on_surface(eff->surmd, vec, efd->loc, efd->nor, real_velocity ? efd->vel : NULL);
-
- efd->size = 0.0f;
- }
- else if (eff->pd && eff->pd->shape == PFIELD_SHAPE_POINTS) {
- Mesh *me_eval = eff->ob->runtime.mesh_eval;
- if (me_eval != NULL) {
- copy_v3_v3(efd->loc, me_eval->mvert[*efd->index].co);
- normal_short_to_float_v3(efd->nor, me_eval->mvert[*efd->index].no);
-
- mul_m4_v3(eff->ob->obmat, efd->loc);
- mul_mat3_m4_v3(eff->ob->obmat, efd->nor);
-
- normalize_v3(efd->nor);
-
- efd->size = 0.0f;
-
- ret = 1;
- }
- }
- else if (eff->psys) {
- ParticleData *pa = eff->psys->particles + *efd->index;
- ParticleKey state;
-
- /* exclude the particle itself for self effecting particles */
- if (eff->psys == point->psys && *efd->index == point->index) {
- /* pass */
- }
- else {
- ParticleSimulationData sim = {NULL};
- sim.depsgraph = eff->depsgraph;
- sim.scene = eff->scene;
- sim.ob = eff->ob;
- sim.psys = eff->psys;
-
- /* TODO: time from actual previous calculated frame (step might not be 1) */
- state.time = cfra - 1.0f;
- ret = psys_get_particle_state(&sim, *efd->index, &state, 0);
-
- /* TODO */
- //if (eff->pd->forcefiled == PFIELD_HARMONIC && ret==0) {
- // if (pa->dietime < eff->psys->cfra)
- // eff->flag |= PE_VELOCITY_TO_IMPULSE;
- //}
-
- copy_v3_v3(efd->loc, state.co);
-
- /* rather than use the velocity use rotated x-axis (defaults to velocity) */
- efd->nor[0] = 1.f;
- efd->nor[1] = efd->nor[2] = 0.f;
- mul_qt_v3(state.rot, efd->nor);
-
- if (real_velocity) {
- copy_v3_v3(efd->vel, state.vel);
- }
- efd->size = pa->size;
- }
- }
- else {
- /* use center of object for distance calculus */
- const Object *ob = eff->ob;
-
- /* use z-axis as normal*/
- normalize_v3_v3(efd->nor, ob->obmat[2]);
-
- if (eff->pd && ELEM(eff->pd->shape, PFIELD_SHAPE_PLANE, PFIELD_SHAPE_LINE)) {
- float temp[3], translate[3];
- sub_v3_v3v3(temp, point->loc, ob->obmat[3]);
- project_v3_v3v3(translate, temp, efd->nor);
-
- /* for vortex the shape chooses between old / new force */
- if (eff->pd->forcefield == PFIELD_VORTEX || eff->pd->shape == PFIELD_SHAPE_LINE) {
- add_v3_v3v3(efd->loc, ob->obmat[3], translate);
- }
- else { /* normally efd->loc is closest point on effector xy-plane */
- sub_v3_v3v3(efd->loc, point->loc, translate);
- }
- }
- else {
- copy_v3_v3(efd->loc, ob->obmat[3]);
- }
-
- zero_v3(efd->vel);
- efd->size = 0.0f;
-
- ret = 1;
- }
-
- if (ret) {
- sub_v3_v3v3(efd->vec_to_point, point->loc, efd->loc);
- efd->distance = len_v3(efd->vec_to_point);
-
- /* rest length for harmonic effector, will have to see later if this could be extended to other effectors */
- if (eff->pd && eff->pd->forcefield == PFIELD_HARMONIC && eff->pd->f_size)
- mul_v3_fl(efd->vec_to_point, (efd->distance - eff->pd->f_size) / efd->distance);
-
- if (eff->flag & PE_USE_NORMAL_DATA) {
- copy_v3_v3(efd->vec_to_point2, efd->vec_to_point);
- copy_v3_v3(efd->nor2, efd->nor);
- }
- else {
- /* for some effectors we need the object center every time */
- sub_v3_v3v3(efd->vec_to_point2, point->loc, eff->ob->obmat[3]);
- normalize_v3_v3(efd->nor2, eff->ob->obmat[2]);
- }
- }
-
- return ret;
+ float cfra = DEG_get_ctime(eff->depsgraph);
+ int ret = 0;
+
+ /* 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];
+
+ /* using velocity corrected location allows for easier sliding over effector surface */
+ copy_v3_v3(vec, point->vel);
+ mul_v3_fl(vec, point->vel_to_frame);
+ add_v3_v3(vec, point->loc);
+
+ ret = closest_point_on_surface(
+ eff->surmd, vec, efd->loc, efd->nor, real_velocity ? efd->vel : NULL);
+
+ efd->size = 0.0f;
+ }
+ else if (eff->pd && eff->pd->shape == PFIELD_SHAPE_POINTS) {
+ Mesh *me_eval = eff->ob->runtime.mesh_eval;
+ if (me_eval != NULL) {
+ copy_v3_v3(efd->loc, me_eval->mvert[*efd->index].co);
+ normal_short_to_float_v3(efd->nor, me_eval->mvert[*efd->index].no);
+
+ mul_m4_v3(eff->ob->obmat, efd->loc);
+ mul_mat3_m4_v3(eff->ob->obmat, efd->nor);
+
+ normalize_v3(efd->nor);
+
+ efd->size = 0.0f;
+
+ ret = 1;
+ }
+ }
+ else if (eff->psys) {
+ ParticleData *pa = eff->psys->particles + *efd->index;
+ ParticleKey state;
+
+ /* exclude the particle itself for self effecting particles */
+ if (eff->psys == point->psys && *efd->index == point->index) {
+ /* pass */
+ }
+ else {
+ ParticleSimulationData sim = {NULL};
+ sim.depsgraph = eff->depsgraph;
+ sim.scene = eff->scene;
+ sim.ob = eff->ob;
+ sim.psys = eff->psys;
+
+ /* TODO: time from actual previous calculated frame (step might not be 1) */
+ state.time = cfra - 1.0f;
+ ret = psys_get_particle_state(&sim, *efd->index, &state, 0);
+
+ /* TODO */
+ //if (eff->pd->forcefiled == PFIELD_HARMONIC && ret==0) {
+ // if (pa->dietime < eff->psys->cfra)
+ // eff->flag |= PE_VELOCITY_TO_IMPULSE;
+ //}
+
+ copy_v3_v3(efd->loc, state.co);
+
+ /* rather than use the velocity use rotated x-axis (defaults to velocity) */
+ efd->nor[0] = 1.f;
+ efd->nor[1] = efd->nor[2] = 0.f;
+ mul_qt_v3(state.rot, efd->nor);
+
+ if (real_velocity) {
+ copy_v3_v3(efd->vel, state.vel);
+ }
+ efd->size = pa->size;
+ }
+ }
+ else {
+ /* use center of object for distance calculus */
+ const Object *ob = eff->ob;
+
+ /* use z-axis as normal*/
+ normalize_v3_v3(efd->nor, ob->obmat[2]);
+
+ if (eff->pd && ELEM(eff->pd->shape, PFIELD_SHAPE_PLANE, PFIELD_SHAPE_LINE)) {
+ float temp[3], translate[3];
+ sub_v3_v3v3(temp, point->loc, ob->obmat[3]);
+ project_v3_v3v3(translate, temp, efd->nor);
+
+ /* for vortex the shape chooses between old / new force */
+ if (eff->pd->forcefield == PFIELD_VORTEX || eff->pd->shape == PFIELD_SHAPE_LINE) {
+ add_v3_v3v3(efd->loc, ob->obmat[3], translate);
+ }
+ else { /* normally efd->loc is closest point on effector xy-plane */
+ sub_v3_v3v3(efd->loc, point->loc, translate);
+ }
+ }
+ else {
+ copy_v3_v3(efd->loc, ob->obmat[3]);
+ }
+
+ zero_v3(efd->vel);
+ efd->size = 0.0f;
+
+ ret = 1;
+ }
+
+ if (ret) {
+ sub_v3_v3v3(efd->vec_to_point, point->loc, efd->loc);
+ efd->distance = len_v3(efd->vec_to_point);
+
+ /* rest length for harmonic effector, will have to see later if this could be extended to other effectors */
+ if (eff->pd && eff->pd->forcefield == PFIELD_HARMONIC && eff->pd->f_size)
+ mul_v3_fl(efd->vec_to_point, (efd->distance - eff->pd->f_size) / efd->distance);
+
+ if (eff->flag & PE_USE_NORMAL_DATA) {
+ copy_v3_v3(efd->vec_to_point2, efd->vec_to_point);
+ copy_v3_v3(efd->nor2, efd->nor);
+ }
+ else {
+ /* for some effectors we need the object center every time */
+ sub_v3_v3v3(efd->vec_to_point2, point->loc, eff->ob->obmat[3]);
+ normalize_v3_v3(efd->nor2, eff->ob->obmat[2]);
+ }
+ }
+
+ return ret;
}
-static void get_effector_tot(EffectorCache *eff, EffectorData *efd, EffectedPoint *point, int *tot, int *p, int *step)
+static void get_effector_tot(
+ EffectorCache *eff, EffectorData *efd, EffectedPoint *point, int *tot, int *p, int *step)
{
- *p = 0;
- efd->index = p;
-
- if (eff->pd->shape == PFIELD_SHAPE_POINTS) {
- Mesh *me_eval = eff->ob->runtime.mesh_eval;
- *tot = me_eval != NULL ? me_eval->totvert : 1;
-
- if (*tot && eff->pd->forcefield == PFIELD_HARMONIC && point->index >= 0) {
- *p = point->index % *tot;
- *tot = *p + 1;
- }
- }
- else if (eff->psys) {
- *tot = eff->psys->totpart;
-
- if (eff->pd->forcefield == PFIELD_CHARGE) {
- /* Only the charge of the effected particle is used for
- * interaction, not fall-offs. If the fall-offs aren't the
- * same this will be unphysical, but for animation this
- * could be the wanted behavior. If you want physical
- * correctness the fall-off should be spherical 2.0 anyways.
- */
- efd->charge = eff->pd->f_strength;
- }
- else if (eff->pd->forcefield == PFIELD_HARMONIC && (eff->pd->flag & PFIELD_MULTIPLE_SPRINGS) == 0) {
- /* every particle is mapped to only one harmonic effector particle */
- *p = point->index % eff->psys->totpart;
- *tot = *p + 1;
- }
-
- if (eff->psys->part->effector_amount) {
- int totpart = eff->psys->totpart;
- int amount = eff->psys->part->effector_amount;
-
- *step = (totpart > amount) ? totpart / amount : 1;
- }
- }
- else {
- *tot = 1;
- }
+ *p = 0;
+ efd->index = p;
+
+ if (eff->pd->shape == PFIELD_SHAPE_POINTS) {
+ Mesh *me_eval = eff->ob->runtime.mesh_eval;
+ *tot = me_eval != NULL ? me_eval->totvert : 1;
+
+ if (*tot && eff->pd->forcefield == PFIELD_HARMONIC && point->index >= 0) {
+ *p = point->index % *tot;
+ *tot = *p + 1;
+ }
+ }
+ else if (eff->psys) {
+ *tot = eff->psys->totpart;
+
+ if (eff->pd->forcefield == PFIELD_CHARGE) {
+ /* Only the charge of the effected particle is used for
+ * interaction, not fall-offs. If the fall-offs aren't the
+ * same this will be unphysical, but for animation this
+ * could be the wanted behavior. If you want physical
+ * correctness the fall-off should be spherical 2.0 anyways.
+ */
+ efd->charge = eff->pd->f_strength;
+ }
+ else if (eff->pd->forcefield == PFIELD_HARMONIC &&
+ (eff->pd->flag & PFIELD_MULTIPLE_SPRINGS) == 0) {
+ /* every particle is mapped to only one harmonic effector particle */
+ *p = point->index % eff->psys->totpart;
+ *tot = *p + 1;
+ }
+
+ if (eff->psys->part->effector_amount) {
+ int totpart = eff->psys->totpart;
+ int amount = eff->psys->part->effector_amount;
+
+ *step = (totpart > amount) ? totpart / amount : 1;
+ }
+ }
+ else {
+ *tot = 1;
+ }
}
-static void do_texture_effector(EffectorCache *eff, EffectorData *efd, EffectedPoint *point, float *total_force)
+static void do_texture_effector(EffectorCache *eff,
+ EffectorData *efd,
+ EffectedPoint *point,
+ float *total_force)
{
- TexResult result[4];
- float tex_co[3], strength, force[3];
- float nabla = eff->pd->tex_nabla;
- int hasrgb;
- short mode = eff->pd->tex_mode;
- bool scene_color_manage;
-
- if (!eff->pd->tex)
- return;
-
- result[0].nor = result[1].nor = result[2].nor = result[3].nor = NULL;
-
- strength = eff->pd->f_strength * efd->falloff;
-
- copy_v3_v3(tex_co, point->loc);
-
- if (eff->pd->flag & PFIELD_TEX_OBJECT) {
- mul_m4_v3(eff->ob->imat, tex_co);
-
- if (eff->pd->flag & PFIELD_TEX_2D)
- tex_co[2] = 0.0f;
- }
- else if (eff->pd->flag & PFIELD_TEX_2D) {
- float fac = -dot_v3v3(tex_co, efd->nor);
- madd_v3_v3fl(tex_co, efd->nor, fac);
- }
-
- scene_color_manage = BKE_scene_check_color_management_enabled(eff->scene);
-
- hasrgb = multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result, 0, NULL, scene_color_manage, false);
-
- if (hasrgb && mode == PFIELD_TEX_RGB) {
- force[0] = (0.5f - result->tr) * strength;
- force[1] = (0.5f - result->tg) * strength;
- force[2] = (0.5f - result->tb) * strength;
- }
- else if (nabla != 0) {
- strength /= nabla;
-
- tex_co[0] += nabla;
- multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result + 1, 0, NULL, scene_color_manage, false);
-
- tex_co[0] -= nabla;
- tex_co[1] += nabla;
- multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result + 2, 0, NULL, scene_color_manage, false);
-
- tex_co[1] -= nabla;
- tex_co[2] += nabla;
- multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result + 3, 0, NULL, scene_color_manage, false);
-
- if (mode == PFIELD_TEX_GRAD || !hasrgb) { /* if we don't have rgb fall back to grad */
- /* generate intensity if texture only has rgb value */
- if (hasrgb & TEX_RGB) {
- for (int i = 0; i < 4; i++) {
- result[i].tin = (1.0f / 3.0f) * (result[i].tr + result[i].tg + result[i].tb);
- }
- }
- force[0] = (result[0].tin - result[1].tin) * strength;
- force[1] = (result[0].tin - result[2].tin) * strength;
- force[2] = (result[0].tin - result[3].tin) * strength;
- }
- else { /*PFIELD_TEX_CURL*/
- float dbdy, dgdz, drdz, dbdx, dgdx, drdy;
-
- dbdy = result[2].tb - result[0].tb;
- dgdz = result[3].tg - result[0].tg;
- drdz = result[3].tr - result[0].tr;
- dbdx = result[1].tb - result[0].tb;
- dgdx = result[1].tg - result[0].tg;
- drdy = result[2].tr - result[0].tr;
-
- force[0] = (dbdy - dgdz) * strength;
- force[1] = (drdz - dbdx) * strength;
- force[2] = (dgdx - drdy) * strength;
- }
- }
- else {
- zero_v3(force);
- }
-
- if (eff->pd->flag & PFIELD_TEX_2D) {
- float fac = -dot_v3v3(force, efd->nor);
- madd_v3_v3fl(force, efd->nor, fac);
- }
-
- add_v3_v3(total_force, force);
+ TexResult result[4];
+ float tex_co[3], strength, force[3];
+ float nabla = eff->pd->tex_nabla;
+ int hasrgb;
+ short mode = eff->pd->tex_mode;
+ bool scene_color_manage;
+
+ if (!eff->pd->tex)
+ return;
+
+ result[0].nor = result[1].nor = result[2].nor = result[3].nor = NULL;
+
+ strength = eff->pd->f_strength * efd->falloff;
+
+ copy_v3_v3(tex_co, point->loc);
+
+ if (eff->pd->flag & PFIELD_TEX_OBJECT) {
+ mul_m4_v3(eff->ob->imat, tex_co);
+
+ if (eff->pd->flag & PFIELD_TEX_2D)
+ tex_co[2] = 0.0f;
+ }
+ else if (eff->pd->flag & PFIELD_TEX_2D) {
+ float fac = -dot_v3v3(tex_co, efd->nor);
+ madd_v3_v3fl(tex_co, efd->nor, fac);
+ }
+
+ scene_color_manage = BKE_scene_check_color_management_enabled(eff->scene);
+
+ hasrgb = multitex_ext(
+ eff->pd->tex, tex_co, NULL, NULL, 0, result, 0, NULL, scene_color_manage, false);
+
+ if (hasrgb && mode == PFIELD_TEX_RGB) {
+ force[0] = (0.5f - result->tr) * strength;
+ force[1] = (0.5f - result->tg) * strength;
+ force[2] = (0.5f - result->tb) * strength;
+ }
+ else if (nabla != 0) {
+ strength /= nabla;
+
+ tex_co[0] += nabla;
+ multitex_ext(
+ eff->pd->tex, tex_co, NULL, NULL, 0, result + 1, 0, NULL, scene_color_manage, false);
+
+ tex_co[0] -= nabla;
+ tex_co[1] += nabla;
+ multitex_ext(
+ eff->pd->tex, tex_co, NULL, NULL, 0, result + 2, 0, NULL, scene_color_manage, false);
+
+ tex_co[1] -= nabla;
+ tex_co[2] += nabla;
+ multitex_ext(
+ eff->pd->tex, tex_co, NULL, NULL, 0, result + 3, 0, NULL, scene_color_manage, false);
+
+ if (mode == PFIELD_TEX_GRAD || !hasrgb) { /* if we don't have rgb fall back to grad */
+ /* generate intensity if texture only has rgb value */
+ if (hasrgb & TEX_RGB) {
+ for (int i = 0; i < 4; i++) {
+ result[i].tin = (1.0f / 3.0f) * (result[i].tr + result[i].tg + result[i].tb);
+ }
+ }
+ force[0] = (result[0].tin - result[1].tin) * strength;
+ force[1] = (result[0].tin - result[2].tin) * strength;
+ force[2] = (result[0].tin - result[3].tin) * strength;
+ }
+ else { /*PFIELD_TEX_CURL*/
+ float dbdy, dgdz, drdz, dbdx, dgdx, drdy;
+
+ dbdy = result[2].tb - result[0].tb;
+ dgdz = result[3].tg - result[0].tg;
+ drdz = result[3].tr - result[0].tr;
+ dbdx = result[1].tb - result[0].tb;
+ dgdx = result[1].tg - result[0].tg;
+ drdy = result[2].tr - result[0].tr;
+
+ force[0] = (dbdy - dgdz) * strength;
+ force[1] = (drdz - dbdx) * strength;
+ force[2] = (dgdx - drdy) * strength;
+ }
+ }
+ else {
+ zero_v3(force);
+ }
+
+ if (eff->pd->flag & PFIELD_TEX_2D) {
+ float fac = -dot_v3v3(force, efd->nor);
+ madd_v3_v3fl(force, efd->nor, fac);
+ }
+
+ add_v3_v3(total_force, force);
}
-static void do_physical_effector(EffectorCache *eff, EffectorData *efd, EffectedPoint *point, float *total_force)
+static void do_physical_effector(EffectorCache *eff,
+ EffectorData *efd,
+ EffectedPoint *point,
+ float *total_force)
{
- PartDeflect *pd = eff->pd;
- RNG *rng = pd->rng;
- float force[3] = {0, 0, 0};
- float temp[3];
- float fac;
- float strength = pd->f_strength;
- float damp = pd->f_damp;
- float noise_factor = pd->f_noise;
-
- if (noise_factor > 0.0f) {
- strength += wind_func(rng, noise_factor);
-
- if (ELEM(pd->forcefield, PFIELD_HARMONIC, PFIELD_DRAG)) {
- damp += wind_func(rng, noise_factor);
- }
- }
-
- copy_v3_v3(force, efd->vec_to_point);
-
- switch (pd->forcefield) {
- case PFIELD_WIND:
- copy_v3_v3(force, efd->nor);
- mul_v3_fl(force, strength * efd->falloff);
- break;
- case PFIELD_FORCE:
- normalize_v3(force);
- if (pd->flag & PFIELD_GRAVITATION) { /* Option: Multiply by 1/distance^2 */
- if (efd->distance < FLT_EPSILON) {
- strength = 0.0f;
- }
- else {
- strength *= powf(efd->distance, -2.0f);
- }
- }
- mul_v3_fl(force, strength * efd->falloff);
- break;
- case PFIELD_VORTEX:
- /* old vortex force */
- if (pd->shape == PFIELD_SHAPE_POINT) {
- cross_v3_v3v3(force, efd->nor, efd->vec_to_point);
- normalize_v3(force);
- mul_v3_fl(force, strength * efd->distance * efd->falloff);
- }
- else {
- /* new vortex force */
- cross_v3_v3v3(temp, efd->nor2, efd->vec_to_point2);
- mul_v3_fl(temp, strength * efd->falloff);
-
- cross_v3_v3v3(force, efd->nor2, temp);
- mul_v3_fl(force, strength * efd->falloff);
-
- madd_v3_v3fl(temp, point->vel, -point->vel_to_sec);
- add_v3_v3(force, temp);
- }
- break;
- case PFIELD_MAGNET:
- if (ELEM(eff->pd->shape, PFIELD_SHAPE_POINT, PFIELD_SHAPE_LINE))
- /* magnetic field of a moving charge */
- cross_v3_v3v3(temp, efd->nor, efd->vec_to_point);
- else
- copy_v3_v3(temp, efd->nor);
-
- normalize_v3(temp);
- mul_v3_fl(temp, strength * efd->falloff);
- cross_v3_v3v3(force, point->vel, temp);
- mul_v3_fl(force, point->vel_to_sec);
- break;
- case PFIELD_HARMONIC:
- mul_v3_fl(force, -strength * efd->falloff);
- copy_v3_v3(temp, point->vel);
- mul_v3_fl(temp, -damp * 2.0f * sqrtf(fabsf(strength)) * point->vel_to_sec);
- add_v3_v3(force, temp);
- break;
- case PFIELD_CHARGE:
- mul_v3_fl(force, point->charge * strength * efd->falloff);
- break;
- case PFIELD_LENNARDJ:
- fac = pow((efd->size + point->size) / efd->distance, 6.0);
-
- fac = -fac * (1.0f - fac) / efd->distance;
-
- /* limit the repulsive term drastically to avoid huge forces */
- fac = ((fac > 2.0f) ? 2.0f : fac);
-
- mul_v3_fl(force, strength * fac);
- break;
- case PFIELD_BOID:
- /* Boid field is handled completely in boids code. */
- return;
- case PFIELD_TURBULENCE:
- if (pd->flag & PFIELD_GLOBAL_CO) {
- copy_v3_v3(temp, point->loc);
- }
- else {
- add_v3_v3v3(temp, efd->vec_to_point2, efd->nor2);
- }
- force[0] = -1.0f + 2.0f * BLI_gTurbulence(pd->f_size, temp[0], temp[1], temp[2], 2, 0, 2);
- force[1] = -1.0f + 2.0f * BLI_gTurbulence(pd->f_size, temp[1], temp[2], temp[0], 2, 0, 2);
- force[2] = -1.0f + 2.0f * BLI_gTurbulence(pd->f_size, temp[2], temp[0], temp[1], 2, 0, 2);
- mul_v3_fl(force, strength * efd->falloff);
- break;
- case PFIELD_DRAG:
- copy_v3_v3(force, point->vel);
- fac = normalize_v3(force) * point->vel_to_sec;
-
- strength = MIN2(strength, 2.0f);
- damp = MIN2(damp, 2.0f);
-
- mul_v3_fl(force, -efd->falloff * fac * (strength * fac + damp));
- break;
- case PFIELD_SMOKEFLOW:
- zero_v3(force);
- if (pd->f_source) {
- float density;
- if ((density = BKE_smoke_get_velocity_at(pd->f_source, point->loc, force)) >= 0.0f) {
- float influence = strength * efd->falloff;
- if (pd->flag & PFIELD_SMOKE_DENSITY) {
- influence *= density;
- }
- mul_v3_fl(force, influence);
- /* apply flow */
- madd_v3_v3fl(total_force, point->vel, -pd->f_flow * influence);
- }
- }
- break;
-
- }
-
- if (pd->flag & PFIELD_DO_LOCATION) {
- madd_v3_v3fl(total_force, force, 1.0f / point->vel_to_sec);
-
- if (ELEM(pd->forcefield, PFIELD_HARMONIC, PFIELD_DRAG, PFIELD_SMOKEFLOW) == 0 && pd->f_flow != 0.0f) {
- madd_v3_v3fl(total_force, point->vel, -pd->f_flow * efd->falloff);
- }
- }
-
- if (point->ave) {
- zero_v3(point->ave);
- }
- if (pd->flag & PFIELD_DO_ROTATION && point->ave && point->rot) {
- float xvec[3] = {1.0f, 0.0f, 0.0f};
- float dave[3];
- mul_qt_v3(point->rot, xvec);
- cross_v3_v3v3(dave, xvec, force);
- if (pd->f_flow != 0.0f) {
- madd_v3_v3fl(dave, point->ave, -pd->f_flow * efd->falloff);
- }
- add_v3_v3(point->ave, dave);
- }
+ PartDeflect *pd = eff->pd;
+ RNG *rng = pd->rng;
+ float force[3] = {0, 0, 0};
+ float temp[3];
+ float fac;
+ float strength = pd->f_strength;
+ float damp = pd->f_damp;
+ float noise_factor = pd->f_noise;
+
+ if (noise_factor > 0.0f) {
+ strength += wind_func(rng, noise_factor);
+
+ if (ELEM(pd->forcefield, PFIELD_HARMONIC, PFIELD_DRAG)) {
+ damp += wind_func(rng, noise_factor);
+ }
+ }
+
+ copy_v3_v3(force, efd->vec_to_point);
+
+ switch (pd->forcefield) {
+ case PFIELD_WIND:
+ copy_v3_v3(force, efd->nor);
+ mul_v3_fl(force, strength * efd->falloff);
+ break;
+ case PFIELD_FORCE:
+ normalize_v3(force);
+ if (pd->flag & PFIELD_GRAVITATION) { /* Option: Multiply by 1/distance^2 */
+ if (efd->distance < FLT_EPSILON) {
+ strength = 0.0f;
+ }
+ else {
+ strength *= powf(efd->distance, -2.0f);
+ }
+ }
+ mul_v3_fl(force, strength * efd->falloff);
+ break;
+ case PFIELD_VORTEX:
+ /* old vortex force */
+ if (pd->shape == PFIELD_SHAPE_POINT) {
+ cross_v3_v3v3(force, efd->nor, efd->vec_to_point);
+ normalize_v3(force);
+ mul_v3_fl(force, strength * efd->distance * efd->falloff);
+ }
+ else {
+ /* new vortex force */
+ cross_v3_v3v3(temp, efd->nor2, efd->vec_to_point2);
+ mul_v3_fl(temp, strength * efd->falloff);
+
+ cross_v3_v3v3(force, efd->nor2, temp);
+ mul_v3_fl(force, strength * efd->falloff);
+
+ madd_v3_v3fl(temp, point->vel, -point->vel_to_sec);
+ add_v3_v3(force, temp);
+ }
+ break;
+ case PFIELD_MAGNET:
+ if (ELEM(eff->pd->shape, PFIELD_SHAPE_POINT, PFIELD_SHAPE_LINE))
+ /* magnetic field of a moving charge */
+ cross_v3_v3v3(temp, efd->nor, efd->vec_to_point);
+ else
+ copy_v3_v3(temp, efd->nor);
+
+ normalize_v3(temp);
+ mul_v3_fl(temp, strength * efd->falloff);
+ cross_v3_v3v3(force, point->vel, temp);
+ mul_v3_fl(force, point->vel_to_sec);
+ break;
+ case PFIELD_HARMONIC:
+ mul_v3_fl(force, -strength * efd->falloff);
+ copy_v3_v3(temp, point->vel);
+ mul_v3_fl(temp, -damp * 2.0f * sqrtf(fabsf(strength)) * point->vel_to_sec);
+ add_v3_v3(force, temp);
+ break;
+ case PFIELD_CHARGE:
+ mul_v3_fl(force, point->charge * strength * efd->falloff);
+ break;
+ case PFIELD_LENNARDJ:
+ fac = pow((efd->size + point->size) / efd->distance, 6.0);
+
+ fac = -fac * (1.0f - fac) / efd->distance;
+
+ /* limit the repulsive term drastically to avoid huge forces */
+ fac = ((fac > 2.0f) ? 2.0f : fac);
+
+ mul_v3_fl(force, strength * fac);
+ break;
+ case PFIELD_BOID:
+ /* Boid field is handled completely in boids code. */
+ return;
+ case PFIELD_TURBULENCE:
+ if (pd->flag & PFIELD_GLOBAL_CO) {
+ copy_v3_v3(temp, point->loc);
+ }
+ else {
+ add_v3_v3v3(temp, efd->vec_to_point2, efd->nor2);
+ }
+ force[0] = -1.0f + 2.0f * BLI_gTurbulence(pd->f_size, temp[0], temp[1], temp[2], 2, 0, 2);
+ force[1] = -1.0f + 2.0f * BLI_gTurbulence(pd->f_size, temp[1], temp[2], temp[0], 2, 0, 2);
+ force[2] = -1.0f + 2.0f * BLI_gTurbulence(pd->f_size, temp[2], temp[0], temp[1], 2, 0, 2);
+ mul_v3_fl(force, strength * efd->falloff);
+ break;
+ case PFIELD_DRAG:
+ copy_v3_v3(force, point->vel);
+ fac = normalize_v3(force) * point->vel_to_sec;
+
+ strength = MIN2(strength, 2.0f);
+ damp = MIN2(damp, 2.0f);
+
+ mul_v3_fl(force, -efd->falloff * fac * (strength * fac + damp));
+ break;
+ case PFIELD_SMOKEFLOW:
+ zero_v3(force);
+ if (pd->f_source) {
+ float density;
+ if ((density = BKE_smoke_get_velocity_at(pd->f_source, point->loc, force)) >= 0.0f) {
+ float influence = strength * efd->falloff;
+ if (pd->flag & PFIELD_SMOKE_DENSITY) {
+ influence *= density;
+ }
+ mul_v3_fl(force, influence);
+ /* apply flow */
+ madd_v3_v3fl(total_force, point->vel, -pd->f_flow * influence);
+ }
+ }
+ break;
+ }
+
+ if (pd->flag & PFIELD_DO_LOCATION) {
+ madd_v3_v3fl(total_force, force, 1.0f / point->vel_to_sec);
+
+ if (ELEM(pd->forcefield, PFIELD_HARMONIC, PFIELD_DRAG, PFIELD_SMOKEFLOW) == 0 &&
+ pd->f_flow != 0.0f) {
+ madd_v3_v3fl(total_force, point->vel, -pd->f_flow * efd->falloff);
+ }
+ }
+
+ if (point->ave) {
+ zero_v3(point->ave);
+ }
+ if (pd->flag & PFIELD_DO_ROTATION && point->ave && point->rot) {
+ float xvec[3] = {1.0f, 0.0f, 0.0f};
+ float dave[3];
+ mul_qt_v3(point->rot, xvec);
+ cross_v3_v3v3(dave, xvec, force);
+ if (pd->f_flow != 0.0f) {
+ madd_v3_v3fl(dave, point->ave, -pd->f_flow * efd->falloff);
+ }
+ add_v3_v3(point->ave, dave);
+ }
}
/* -------- BKE_effectors_apply() --------
* generic force/speed system, now used for particles and softbodies
* scene = scene where it runs in, for time and stuff
- * lb = listbase with objects that take part in effecting
- * opco = global coord, as input
- * force = force accumulator
- * speed = actual current speed which can be altered
- * cur_time = "external" time in frames, is constant for static particles
- * loc_time = "local" time in frames, range <0-1> for the lifetime of particle
- * par_layer = layer the caller is in
- * flags = only used for softbody wind now
- * guide = old speed of particle
+ * lb = listbase with objects that take part in effecting
+ * opco = global coord, as input
+ * force = force accumulator
+ * speed = actual current speed which can be altered
+ * cur_time = "external" time in frames, is constant for static particles
+ * loc_time = "local" time in frames, range <0-1> for the lifetime of particle
+ * par_layer = layer the caller is in
+ * flags = only used for softbody wind now
+ * guide = old speed of particle
*/
-void BKE_effectors_apply(ListBase *effectors, ListBase *colliders, EffectorWeights *weights, EffectedPoint *point, float *force, float *impulse)
+void BKE_effectors_apply(ListBase *effectors,
+ ListBase *colliders,
+ EffectorWeights *weights,
+ EffectedPoint *point,
+ float *force,
+ float *impulse)
{
- /*
- * Modifies the force on a particle according to its
- * relation with the effector object
- * Different kind of effectors include:
- * Forcefields: Gravity-like attractor
- * (force power is related to the inverse of distance to the power of a falloff value)
- * Vortex fields: swirling effectors
- * (particles rotate around Z-axis of the object. otherwise, same relation as)
- * (Forcefields, but this is not done through a force/acceleration)
- * Guide: particles on a path
- * (particles are guided along a curve bezier or old nurbs)
- * (is independent of other effectors)
- */
- EffectorCache *eff;
- EffectorData efd;
- int p = 0, tot = 1, step = 1;
-
- /* Cycle through collected objects, get total of (1/(gravity_strength * dist^gravity_power)) */
- /* Check for min distance here? (yes would be cool to add that, ton) */
-
- if (effectors) {
- for (eff = effectors->first; eff; eff = eff->next) {
- /* object effectors were fully checked to be OK to evaluate! */
-
- get_effector_tot(eff, &efd, point, &tot, &p, &step);
-
- for (; p < tot; p += step) {
- if (get_effector_data(eff, &efd, point, 0)) {
- efd.falloff = effector_falloff(eff, &efd, point, weights);
-
- if (efd.falloff > 0.0f) {
- efd.falloff *= eff_calc_visibility(colliders, eff, &efd, point);
- }
- if (efd.falloff <= 0.0f) {
- /* don't do anything */
- }
- else if (eff->pd->forcefield == PFIELD_TEXTURE) {
- do_texture_effector(eff, &efd, point, force);
- }
- else {
- float temp1[3] = {0, 0, 0}, temp2[3];
- copy_v3_v3(temp1, force);
-
- do_physical_effector(eff, &efd, point, force);
-
- /* for softbody backward compatibility */
- if (point->flag & PE_WIND_AS_SPEED && impulse) {
- sub_v3_v3v3(temp2, force, temp1);
- sub_v3_v3v3(impulse, impulse, temp2);
- }
- }
- }
- else if (eff->flag & PE_VELOCITY_TO_IMPULSE && impulse) {
- /* special case for harmonic effector */
- add_v3_v3v3(impulse, impulse, efd.vel);
- }
- }
- }
- }
+ /*
+ * Modifies the force on a particle according to its
+ * relation with the effector object
+ * Different kind of effectors include:
+ * Forcefields: Gravity-like attractor
+ * (force power is related to the inverse of distance to the power of a falloff value)
+ * Vortex fields: swirling effectors
+ * (particles rotate around Z-axis of the object. otherwise, same relation as)
+ * (Forcefields, but this is not done through a force/acceleration)
+ * Guide: particles on a path
+ * (particles are guided along a curve bezier or old nurbs)
+ * (is independent of other effectors)
+ */
+ EffectorCache *eff;
+ EffectorData efd;
+ int p = 0, tot = 1, step = 1;
+
+ /* Cycle through collected objects, get total of (1/(gravity_strength * dist^gravity_power)) */
+ /* Check for min distance here? (yes would be cool to add that, ton) */
+
+ if (effectors) {
+ for (eff = effectors->first; eff; eff = eff->next) {
+ /* object effectors were fully checked to be OK to evaluate! */
+
+ get_effector_tot(eff, &efd, point, &tot, &p, &step);
+
+ for (; p < tot; p += step) {
+ if (get_effector_data(eff, &efd, point, 0)) {
+ efd.falloff = effector_falloff(eff, &efd, point, weights);
+
+ if (efd.falloff > 0.0f) {
+ efd.falloff *= eff_calc_visibility(colliders, eff, &efd, point);
+ }
+ if (efd.falloff <= 0.0f) {
+ /* don't do anything */
+ }
+ else if (eff->pd->forcefield == PFIELD_TEXTURE) {
+ do_texture_effector(eff, &efd, point, force);
+ }
+ else {
+ float temp1[3] = {0, 0, 0}, temp2[3];
+ copy_v3_v3(temp1, force);
+
+ do_physical_effector(eff, &efd, point, force);
+
+ /* for softbody backward compatibility */
+ if (point->flag & PE_WIND_AS_SPEED && impulse) {
+ sub_v3_v3v3(temp2, force, temp1);
+ sub_v3_v3v3(impulse, impulse, temp2);
+ }
+ }
+ }
+ else if (eff->flag & PE_VELOCITY_TO_IMPULSE && impulse) {
+ /* special case for harmonic effector */
+ add_v3_v3v3(impulse, impulse, efd.vel);
+ }
+ }
+ }
+ }
}
/* ======== Simulation Debugging ======== */
@@ -1077,176 +1137,193 @@ SimDebugData *_sim_debug_data = NULL;
uint BKE_sim_debug_data_hash(int i)
{
- return BLI_ghashutil_uinthash((uint)i);
+ return BLI_ghashutil_uinthash((uint)i);
}
uint BKE_sim_debug_data_hash_combine(uint kx, uint ky)
{
#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k))))
- uint a, b, c;
-
- a = b = c = 0xdeadbeef + (2 << 2) + 13;
- a += kx;
- b += ky;
-
- c ^= b; c -= rot(b, 14);
- a ^= c; a -= rot(c, 11);
- b ^= a; b -= rot(a, 25);
- c ^= b; c -= rot(b, 16);
- a ^= c; a -= rot(c, 4);
- b ^= a; b -= rot(a, 14);
- c ^= b; c -= rot(b, 24);
-
- return c;
+ uint a, b, c;
+
+ a = b = c = 0xdeadbeef + (2 << 2) + 13;
+ a += kx;
+ b += ky;
+
+ c ^= b;
+ c -= rot(b, 14);
+ a ^= c;
+ a -= rot(c, 11);
+ b ^= a;
+ b -= rot(a, 25);
+ c ^= b;
+ c -= rot(b, 16);
+ a ^= c;
+ a -= rot(c, 4);
+ b ^= a;
+ b -= rot(a, 14);
+ c ^= b;
+ c -= rot(b, 24);
+
+ return c;
#undef rot
}
static uint debug_element_hash(const void *key)
{
- const SimDebugElement *elem = key;
- return elem->hash;
+ const SimDebugElement *elem = key;
+ return elem->hash;
}
static bool debug_element_compare(const void *a, const void *b)
{
- const SimDebugElement *elem1 = a;
- const SimDebugElement *elem2 = b;
+ const SimDebugElement *elem1 = a;
+ const SimDebugElement *elem2 = b;
- if (elem1->hash == elem2->hash) {
- return 0;
- }
- return 1;
+ if (elem1->hash == elem2->hash) {
+ return 0;
+ }
+ return 1;
}
static void debug_element_free(void *val)
{
- SimDebugElement *elem = val;
- MEM_freeN(elem);
+ SimDebugElement *elem = val;
+ MEM_freeN(elem);
}
void BKE_sim_debug_data_set_enabled(bool enable)
{
- if (enable) {
- if (!_sim_debug_data) {
- _sim_debug_data = MEM_callocN(sizeof(SimDebugData), "sim debug data");
- _sim_debug_data->gh = BLI_ghash_new(debug_element_hash, debug_element_compare, "sim debug element hash");
- }
- }
- else {
- BKE_sim_debug_data_free();
- }
+ if (enable) {
+ if (!_sim_debug_data) {
+ _sim_debug_data = MEM_callocN(sizeof(SimDebugData), "sim debug data");
+ _sim_debug_data->gh = BLI_ghash_new(
+ debug_element_hash, debug_element_compare, "sim debug element hash");
+ }
+ }
+ else {
+ BKE_sim_debug_data_free();
+ }
}
bool BKE_sim_debug_data_get_enabled(void)
{
- return _sim_debug_data != NULL;
+ return _sim_debug_data != NULL;
}
void BKE_sim_debug_data_free(void)
{
- if (_sim_debug_data) {
- if (_sim_debug_data->gh) {
- BLI_ghash_free(_sim_debug_data->gh, NULL, debug_element_free);
- }
- MEM_freeN(_sim_debug_data);
- }
+ if (_sim_debug_data) {
+ if (_sim_debug_data->gh) {
+ BLI_ghash_free(_sim_debug_data->gh, NULL, debug_element_free);
+ }
+ MEM_freeN(_sim_debug_data);
+ }
}
static void debug_data_insert(SimDebugData *debug_data, SimDebugElement *elem)
{
- SimDebugElement *old_elem = BLI_ghash_lookup(debug_data->gh, elem);
- if (old_elem) {
- *old_elem = *elem;
- MEM_freeN(elem);
- }
- else {
- BLI_ghash_insert(debug_data->gh, elem, elem);
- }
+ SimDebugElement *old_elem = BLI_ghash_lookup(debug_data->gh, elem);
+ if (old_elem) {
+ *old_elem = *elem;
+ MEM_freeN(elem);
+ }
+ else {
+ BLI_ghash_insert(debug_data->gh, elem, elem);
+ }
}
-void BKE_sim_debug_data_add_element(int type, const float v1[3], const float v2[3], const char *str, float r, float g, float b, const char *category, uint hash)
+void BKE_sim_debug_data_add_element(int type,
+ const float v1[3],
+ const float v2[3],
+ const char *str,
+ float r,
+ float g,
+ float b,
+ const char *category,
+ uint hash)
{
- uint category_hash = BLI_ghashutil_strhash_p(category);
- SimDebugElement *elem;
-
- if (!_sim_debug_data) {
- if (G.debug & G_DEBUG_SIMDATA) {
- BKE_sim_debug_data_set_enabled(true);
- }
- else {
- return;
- }
- }
-
- elem = MEM_callocN(sizeof(SimDebugElement), "sim debug data element");
- elem->type = type;
- elem->category_hash = category_hash;
- elem->hash = hash;
- elem->color[0] = r;
- elem->color[1] = g;
- elem->color[2] = b;
- if (v1) {
- copy_v3_v3(elem->v1, v1);
- }
- else {
- zero_v3(elem->v1);
- }
- if (v2) {
- copy_v3_v3(elem->v2, v2);
- }
- else {
- zero_v3(elem->v2);
- }
- if (str) {
- BLI_strncpy(elem->str, str, sizeof(elem->str));
- }
- else {
- elem->str[0] = '\0';
- }
-
- debug_data_insert(_sim_debug_data, elem);
+ uint category_hash = BLI_ghashutil_strhash_p(category);
+ SimDebugElement *elem;
+
+ if (!_sim_debug_data) {
+ if (G.debug & G_DEBUG_SIMDATA) {
+ BKE_sim_debug_data_set_enabled(true);
+ }
+ else {
+ return;
+ }
+ }
+
+ elem = MEM_callocN(sizeof(SimDebugElement), "sim debug data element");
+ elem->type = type;
+ elem->category_hash = category_hash;
+ elem->hash = hash;
+ elem->color[0] = r;
+ elem->color[1] = g;
+ elem->color[2] = b;
+ if (v1) {
+ copy_v3_v3(elem->v1, v1);
+ }
+ else {
+ zero_v3(elem->v1);
+ }
+ if (v2) {
+ copy_v3_v3(elem->v2, v2);
+ }
+ else {
+ zero_v3(elem->v2);
+ }
+ if (str) {
+ BLI_strncpy(elem->str, str, sizeof(elem->str));
+ }
+ else {
+ elem->str[0] = '\0';
+ }
+
+ debug_data_insert(_sim_debug_data, elem);
}
void BKE_sim_debug_data_remove_element(uint hash)
{
- SimDebugElement dummy;
- if (!_sim_debug_data) {
- return;
- }
- dummy.hash = hash;
- BLI_ghash_remove(_sim_debug_data->gh, &dummy, NULL, debug_element_free);
+ SimDebugElement dummy;
+ if (!_sim_debug_data) {
+ return;
+ }
+ dummy.hash = hash;
+ BLI_ghash_remove(_sim_debug_data->gh, &dummy, NULL, debug_element_free);
}
void BKE_sim_debug_data_clear(void)
{
- if (!_sim_debug_data) {
- return;
- }
- if (_sim_debug_data->gh) {
- BLI_ghash_clear(_sim_debug_data->gh, NULL, debug_element_free);
- }
+ if (!_sim_debug_data) {
+ return;
+ }
+ if (_sim_debug_data->gh) {
+ BLI_ghash_clear(_sim_debug_data->gh, NULL, debug_element_free);
+ }
}
void BKE_sim_debug_data_clear_category(const char *category)
{
- int category_hash = (int)BLI_ghashutil_strhash_p(category);
-
- if (!_sim_debug_data) {
- return;
- }
-
- if (_sim_debug_data->gh) {
- GHashIterator iter;
- BLI_ghashIterator_init(&iter, _sim_debug_data->gh);
- while (!BLI_ghashIterator_done(&iter)) {
- const SimDebugElement *elem = BLI_ghashIterator_getValue(&iter);
- BLI_ghashIterator_step(&iter); /* removing invalidates the current iterator, so step before removing */
-
- if (elem->category_hash == category_hash) {
- BLI_ghash_remove(_sim_debug_data->gh, elem, NULL, debug_element_free);
- }
- }
- }
+ int category_hash = (int)BLI_ghashutil_strhash_p(category);
+
+ if (!_sim_debug_data) {
+ return;
+ }
+
+ if (_sim_debug_data->gh) {
+ GHashIterator iter;
+ BLI_ghashIterator_init(&iter, _sim_debug_data->gh);
+ while (!BLI_ghashIterator_done(&iter)) {
+ const SimDebugElement *elem = BLI_ghashIterator_getValue(&iter);
+ BLI_ghashIterator_step(
+ &iter); /* removing invalidates the current iterator, so step before removing */
+
+ if (elem->category_hash == category_hash) {
+ BLI_ghash_remove(_sim_debug_data->gh, elem, NULL, debug_element_free);
+ }
+ }
+ }
}
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index 78282ddb2b5..4a2a610918c 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -62,7 +62,7 @@
#include "CLG_log.h"
#ifdef WITH_PYTHON
-#include "BPY_extern.h"
+# include "BPY_extern.h"
#endif
#define SMALL -1.0e-10
@@ -81,44 +81,44 @@ static CLG_LogRef LOG = {"bke.fcurve"};
/* Frees the F-Curve itself too, so make sure BLI_remlink is called before calling this... */
void free_fcurve(FCurve *fcu)
{
- if (fcu == NULL)
- return;
+ if (fcu == NULL)
+ return;
- /* free curve data */
- MEM_SAFE_FREE(fcu->bezt);
- MEM_SAFE_FREE(fcu->fpt);
+ /* free curve data */
+ MEM_SAFE_FREE(fcu->bezt);
+ MEM_SAFE_FREE(fcu->fpt);
- /* free RNA-path, as this were allocated when getting the path string */
- MEM_SAFE_FREE(fcu->rna_path);
+ /* free RNA-path, as this were allocated when getting the path string */
+ MEM_SAFE_FREE(fcu->rna_path);
- /* free extra data - i.e. modifiers, and driver */
- fcurve_free_driver(fcu);
- free_fmodifiers(&fcu->modifiers);
+ /* free extra data - i.e. modifiers, and driver */
+ fcurve_free_driver(fcu);
+ free_fmodifiers(&fcu->modifiers);
- /* free f-curve itself */
- MEM_freeN(fcu);
+ /* free f-curve itself */
+ MEM_freeN(fcu);
}
/* Frees a list of F-Curves */
void free_fcurves(ListBase *list)
{
- FCurve *fcu, *fcn;
-
- /* sanity check */
- if (list == NULL)
- return;
-
- /* free data - no need to call remlink before freeing each curve,
- * as we store reference to next, and freeing only touches the curve
- * it's given
- */
- for (fcu = list->first; fcu; fcu = fcn) {
- fcn = fcu->next;
- free_fcurve(fcu);
- }
-
- /* clear pointers just in case */
- BLI_listbase_clear(list);
+ FCurve *fcu, *fcn;
+
+ /* sanity check */
+ if (list == NULL)
+ return;
+
+ /* free data - no need to call remlink before freeing each curve,
+ * as we store reference to next, and freeing only touches the curve
+ * it's given
+ */
+ for (fcu = list->first; fcu; fcu = fcn) {
+ fcn = fcu->next;
+ free_fcurve(fcu);
+ }
+
+ /* clear pointers just in case */
+ BLI_listbase_clear(list);
}
/* ---------------------- Copy --------------------------- */
@@ -126,144 +126,144 @@ void free_fcurves(ListBase *list)
/* duplicate an F-Curve */
FCurve *copy_fcurve(const FCurve *fcu)
{
- FCurve *fcu_d;
+ FCurve *fcu_d;
- /* sanity check */
- if (fcu == NULL)
- return NULL;
+ /* sanity check */
+ if (fcu == NULL)
+ return NULL;
- /* make a copy */
- fcu_d = MEM_dupallocN(fcu);
+ /* make a copy */
+ fcu_d = MEM_dupallocN(fcu);
- fcu_d->next = fcu_d->prev = NULL;
- fcu_d->grp = NULL;
+ fcu_d->next = fcu_d->prev = NULL;
+ fcu_d->grp = NULL;
- /* copy curve data */
- fcu_d->bezt = MEM_dupallocN(fcu_d->bezt);
- fcu_d->fpt = MEM_dupallocN(fcu_d->fpt);
+ /* copy curve data */
+ fcu_d->bezt = MEM_dupallocN(fcu_d->bezt);
+ fcu_d->fpt = MEM_dupallocN(fcu_d->fpt);
- /* copy rna-path */
- fcu_d->rna_path = MEM_dupallocN(fcu_d->rna_path);
+ /* copy rna-path */
+ fcu_d->rna_path = MEM_dupallocN(fcu_d->rna_path);
- /* copy driver */
- fcu_d->driver = fcurve_copy_driver(fcu_d->driver);
+ /* copy driver */
+ fcu_d->driver = fcurve_copy_driver(fcu_d->driver);
- /* copy modifiers */
- copy_fmodifiers(&fcu_d->modifiers, &fcu->modifiers);
+ /* copy modifiers */
+ copy_fmodifiers(&fcu_d->modifiers, &fcu->modifiers);
- /* return new data */
- return fcu_d;
+ /* return new data */
+ return fcu_d;
}
/* duplicate a list of F-Curves */
void copy_fcurves(ListBase *dst, ListBase *src)
{
- FCurve *dfcu, *sfcu;
+ FCurve *dfcu, *sfcu;
- /* sanity checks */
- if (ELEM(NULL, dst, src))
- return;
+ /* sanity checks */
+ if (ELEM(NULL, dst, src))
+ return;
- /* clear destination list first */
- BLI_listbase_clear(dst);
+ /* clear destination list first */
+ BLI_listbase_clear(dst);
- /* copy one-by-one */
- for (sfcu = src->first; sfcu; sfcu = sfcu->next) {
- dfcu = copy_fcurve(sfcu);
- BLI_addtail(dst, dfcu);
- }
+ /* copy one-by-one */
+ for (sfcu = src->first; sfcu; sfcu = sfcu->next) {
+ dfcu = copy_fcurve(sfcu);
+ BLI_addtail(dst, dfcu);
+ }
}
/* ----------------- Finding F-Curves -------------------------- */
/* high level function to get an fcurve from C without having the rna */
-FCurve *id_data_find_fcurve(ID *id, void *data, StructRNA *type, const char *prop_name, int index, bool *r_driven)
+FCurve *id_data_find_fcurve(
+ ID *id, void *data, StructRNA *type, const char *prop_name, int index, bool *r_driven)
{
- /* anim vars */
- AnimData *adt = BKE_animdata_from_id(id);
- FCurve *fcu = NULL;
-
- /* rna vars */
- PointerRNA ptr;
- PropertyRNA *prop;
- char *path;
-
- if (r_driven)
- *r_driven = false;
-
- /* only use the current action ??? */
- if (ELEM(NULL, adt, adt->action))
- return NULL;
-
- RNA_pointer_create(id, type, data, &ptr);
- prop = RNA_struct_find_property(&ptr, prop_name);
-
- if (prop) {
- path = RNA_path_from_ID_to_property(&ptr, prop);
-
- if (path) {
- /* animation takes priority over drivers */
- if ((adt->action) && (adt->action->curves.first))
- fcu = list_find_fcurve(&adt->action->curves, path, index);
-
- /* if not animated, check if driven */
- if ((fcu == NULL) && (adt->drivers.first)) {
- fcu = list_find_fcurve(&adt->drivers, path, index);
- if (fcu && r_driven)
- *r_driven = true;
- fcu = NULL;
- }
-
- MEM_freeN(path);
- }
- }
-
- return fcu;
+ /* anim vars */
+ AnimData *adt = BKE_animdata_from_id(id);
+ FCurve *fcu = NULL;
+
+ /* rna vars */
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ char *path;
+
+ if (r_driven)
+ *r_driven = false;
+
+ /* only use the current action ??? */
+ if (ELEM(NULL, adt, adt->action))
+ return NULL;
+
+ RNA_pointer_create(id, type, data, &ptr);
+ prop = RNA_struct_find_property(&ptr, prop_name);
+
+ if (prop) {
+ path = RNA_path_from_ID_to_property(&ptr, prop);
+
+ if (path) {
+ /* animation takes priority over drivers */
+ if ((adt->action) && (adt->action->curves.first))
+ fcu = list_find_fcurve(&adt->action->curves, path, index);
+
+ /* if not animated, check if driven */
+ if ((fcu == NULL) && (adt->drivers.first)) {
+ fcu = list_find_fcurve(&adt->drivers, path, index);
+ if (fcu && r_driven)
+ *r_driven = true;
+ fcu = NULL;
+ }
+
+ MEM_freeN(path);
+ }
+ }
+
+ return fcu;
}
-
/* Find the F-Curve affecting the given RNA-access path + index, in the list of F-Curves provided */
FCurve *list_find_fcurve(ListBase *list, const char rna_path[], const int array_index)
{
- FCurve *fcu;
-
- /* sanity checks */
- if (ELEM(NULL, list, rna_path) || (array_index < 0) )
- return NULL;
-
- /* check paths of curves, then array indices... */
- for (fcu = list->first; fcu; fcu = fcu->next) {
- /* simple string-compare (this assumes that they have the same root...) */
- if (fcu->rna_path && STREQ(fcu->rna_path, rna_path)) {
- /* now check indices */
- if (fcu->array_index == array_index)
- return fcu;
- }
- }
-
- /* return */
- return NULL;
+ FCurve *fcu;
+
+ /* sanity checks */
+ if (ELEM(NULL, list, rna_path) || (array_index < 0))
+ return NULL;
+
+ /* check paths of curves, then array indices... */
+ for (fcu = list->first; fcu; fcu = fcu->next) {
+ /* simple string-compare (this assumes that they have the same root...) */
+ if (fcu->rna_path && STREQ(fcu->rna_path, rna_path)) {
+ /* now check indices */
+ if (fcu->array_index == array_index)
+ return fcu;
+ }
+ }
+
+ /* return */
+ return NULL;
}
/* quick way to loop over all fcurves of a given 'path' */
FCurve *iter_step_fcurve(FCurve *fcu_iter, const char rna_path[])
{
- FCurve *fcu;
-
- /* sanity checks */
- if (ELEM(NULL, fcu_iter, rna_path))
- return NULL;
-
- /* check paths of curves, then array indices... */
- for (fcu = fcu_iter; fcu; fcu = fcu->next) {
- /* simple string-compare (this assumes that they have the same root...) */
- if (fcu->rna_path && STREQ(fcu->rna_path, rna_path)) {
- return fcu;
- }
- }
-
- /* return */
- return NULL;
+ FCurve *fcu;
+
+ /* sanity checks */
+ if (ELEM(NULL, fcu_iter, rna_path))
+ return NULL;
+
+ /* check paths of curves, then array indices... */
+ for (fcu = fcu_iter; fcu; fcu = fcu->next) {
+ /* simple string-compare (this assumes that they have the same root...) */
+ if (fcu->rna_path && STREQ(fcu->rna_path, rna_path)) {
+ return fcu;
+ }
+ }
+
+ /* return */
+ return NULL;
}
/* Get list of LinkData's containing pointers to the F-Curves which control the types of data indicated
@@ -275,141 +275,160 @@ FCurve *iter_step_fcurve(FCurve *fcu_iter, const char rna_path[])
* - dataPrefix: i.e. 'pose.bones[' or 'nodes['
* - dataName: name of entity within "" immediately following the prefix
*/
-int list_find_data_fcurves(ListBase *dst, ListBase *src, const char *dataPrefix, const char *dataName)
+int list_find_data_fcurves(ListBase *dst,
+ ListBase *src,
+ const char *dataPrefix,
+ const char *dataName)
{
- FCurve *fcu;
- int matches = 0;
-
- /* sanity checks */
- if (ELEM(NULL, dst, src, dataPrefix, dataName))
- return 0;
- else if ((dataPrefix[0] == 0) || (dataName[0] == 0))
- return 0;
-
- /* search each F-Curve one by one */
- for (fcu = src->first; fcu; fcu = fcu->next) {
- /* check if quoted string matches the path */
- if ((fcu->rna_path) && strstr(fcu->rna_path, dataPrefix)) {
- char *quotedName = BLI_str_quoted_substrN(fcu->rna_path, dataPrefix);
-
- if (quotedName) {
- /* check if the quoted name matches the required name */
- if (STREQ(quotedName, dataName)) {
- LinkData *ld = MEM_callocN(sizeof(LinkData), __func__);
-
- ld->data = fcu;
- BLI_addtail(dst, ld);
-
- matches++;
- }
-
- /* always free the quoted string, since it needs freeing */
- MEM_freeN(quotedName);
- }
- }
- }
-
- /* return the number of matches */
- return matches;
+ FCurve *fcu;
+ int matches = 0;
+
+ /* sanity checks */
+ if (ELEM(NULL, dst, src, dataPrefix, dataName))
+ return 0;
+ else if ((dataPrefix[0] == 0) || (dataName[0] == 0))
+ return 0;
+
+ /* search each F-Curve one by one */
+ for (fcu = src->first; fcu; fcu = fcu->next) {
+ /* check if quoted string matches the path */
+ if ((fcu->rna_path) && strstr(fcu->rna_path, dataPrefix)) {
+ char *quotedName = BLI_str_quoted_substrN(fcu->rna_path, dataPrefix);
+
+ if (quotedName) {
+ /* check if the quoted name matches the required name */
+ if (STREQ(quotedName, dataName)) {
+ LinkData *ld = MEM_callocN(sizeof(LinkData), __func__);
+
+ ld->data = fcu;
+ BLI_addtail(dst, ld);
+
+ matches++;
+ }
+
+ /* always free the quoted string, since it needs freeing */
+ MEM_freeN(quotedName);
+ }
+ }
+ }
+
+ /* return the number of matches */
+ return matches;
}
-FCurve *rna_get_fcurve(
- PointerRNA *ptr, PropertyRNA *prop, int rnaindex,
- AnimData **r_adt, bAction **r_action, bool *r_driven, bool *r_special)
+FCurve *rna_get_fcurve(PointerRNA *ptr,
+ PropertyRNA *prop,
+ int rnaindex,
+ AnimData **r_adt,
+ bAction **r_action,
+ bool *r_driven,
+ bool *r_special)
{
- return rna_get_fcurve_context_ui(NULL, ptr, prop, rnaindex, r_adt, r_action, r_driven, r_special);
+ return rna_get_fcurve_context_ui(
+ NULL, ptr, prop, rnaindex, r_adt, r_action, r_driven, r_special);
}
-FCurve *rna_get_fcurve_context_ui(
- bContext *C, PointerRNA *ptr, PropertyRNA *prop, int rnaindex,
- AnimData **r_animdata, bAction **r_action, bool *r_driven, bool *r_special)
+FCurve *rna_get_fcurve_context_ui(bContext *C,
+ PointerRNA *ptr,
+ PropertyRNA *prop,
+ int rnaindex,
+ AnimData **r_animdata,
+ bAction **r_action,
+ bool *r_driven,
+ bool *r_special)
{
- FCurve *fcu = NULL;
- PointerRNA tptr = *ptr;
-
- *r_driven = false;
- *r_special = false;
-
- if (r_animdata) *r_animdata = NULL;
- if (r_action) *r_action = NULL;
-
- /* Special case for NLA Control Curves... */
- if (BKE_nlastrip_has_curves_for_property(ptr, prop)) {
- NlaStrip *strip = (NlaStrip *)ptr->data;
-
- /* Set the special flag, since it cannot be a normal action/driver
- * if we've been told to start looking here...
- */
- *r_special = true;
-
- /* The F-Curve either exists or it doesn't here... */
- fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), rnaindex);
- return fcu;
- }
-
- /* there must be some RNA-pointer + property combon */
- if (prop && tptr.id.data && RNA_property_animateable(&tptr, prop)) {
- AnimData *adt = BKE_animdata_from_id(tptr.id.data);
- int step = C ? 2 : 1; /* Always 1 in case we have no context (can't check in 'ancestors' of given RNA ptr). */
- char *path = NULL;
-
- if (!adt && C) {
- path = BKE_animdata_driver_path_hack(C, &tptr, prop, NULL);
- adt = BKE_animdata_from_id(tptr.id.data);
- step--;
- }
-
- /* Standard F-Curve - Animation (Action) or Drivers */
- while (adt && step--) {
- if ((adt->action && adt->action->curves.first) || (adt->drivers.first)) {
- /* XXX this function call can become a performance bottleneck */
- if (step) {
- path = RNA_path_from_ID_to_property(&tptr, prop);
- }
-
- // XXX: the logic here is duplicated with a function up above
- if (path) {
- /* animation takes priority over drivers */
- if (adt->action && adt->action->curves.first) {
- fcu = list_find_fcurve(&adt->action->curves, path, rnaindex);
-
- if (fcu && r_action)
- *r_action = adt->action;
- }
-
- /* if not animated, check if driven */
- if (!fcu && (adt->drivers.first)) {
- fcu = list_find_fcurve(&adt->drivers, path, rnaindex);
-
- if (fcu) {
- if (r_animdata) *r_animdata = adt;
- *r_driven = true;
- }
- }
-
- if (fcu && r_action) {
- if (r_animdata) *r_animdata = adt;
- *r_action = adt->action;
- break;
- }
- else if (step) {
- char *tpath = BKE_animdata_driver_path_hack(C, &tptr, prop, path);
- if (tpath && tpath != path) {
- MEM_freeN(path);
- path = tpath;
- adt = BKE_animdata_from_id(tptr.id.data);
- }
- else {
- adt = NULL;
- }
- }
- }
- }
- }
- MEM_SAFE_FREE(path);
- }
-
- return fcu;
+ FCurve *fcu = NULL;
+ PointerRNA tptr = *ptr;
+
+ *r_driven = false;
+ *r_special = false;
+
+ if (r_animdata)
+ *r_animdata = NULL;
+ if (r_action)
+ *r_action = NULL;
+
+ /* Special case for NLA Control Curves... */
+ if (BKE_nlastrip_has_curves_for_property(ptr, prop)) {
+ NlaStrip *strip = (NlaStrip *)ptr->data;
+
+ /* Set the special flag, since it cannot be a normal action/driver
+ * if we've been told to start looking here...
+ */
+ *r_special = true;
+
+ /* The F-Curve either exists or it doesn't here... */
+ fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), rnaindex);
+ return fcu;
+ }
+
+ /* there must be some RNA-pointer + property combon */
+ if (prop && tptr.id.data && RNA_property_animateable(&tptr, prop)) {
+ AnimData *adt = BKE_animdata_from_id(tptr.id.data);
+ int step =
+ C ? 2 :
+ 1; /* Always 1 in case we have no context (can't check in 'ancestors' of given RNA ptr). */
+ char *path = NULL;
+
+ if (!adt && C) {
+ path = BKE_animdata_driver_path_hack(C, &tptr, prop, NULL);
+ adt = BKE_animdata_from_id(tptr.id.data);
+ step--;
+ }
+
+ /* Standard F-Curve - Animation (Action) or Drivers */
+ while (adt && step--) {
+ if ((adt->action && adt->action->curves.first) || (adt->drivers.first)) {
+ /* XXX this function call can become a performance bottleneck */
+ if (step) {
+ path = RNA_path_from_ID_to_property(&tptr, prop);
+ }
+
+ // XXX: the logic here is duplicated with a function up above
+ if (path) {
+ /* animation takes priority over drivers */
+ if (adt->action && adt->action->curves.first) {
+ fcu = list_find_fcurve(&adt->action->curves, path, rnaindex);
+
+ if (fcu && r_action)
+ *r_action = adt->action;
+ }
+
+ /* if not animated, check if driven */
+ if (!fcu && (adt->drivers.first)) {
+ fcu = list_find_fcurve(&adt->drivers, path, rnaindex);
+
+ if (fcu) {
+ if (r_animdata)
+ *r_animdata = adt;
+ *r_driven = true;
+ }
+ }
+
+ if (fcu && r_action) {
+ if (r_animdata)
+ *r_animdata = adt;
+ *r_action = adt->action;
+ break;
+ }
+ else if (step) {
+ char *tpath = BKE_animdata_driver_path_hack(C, &tptr, prop, path);
+ if (tpath && tpath != path) {
+ MEM_freeN(path);
+ path = tpath;
+ adt = BKE_animdata_from_id(tptr.id.data);
+ }
+ else {
+ adt = NULL;
+ }
+ }
+ }
+ }
+ }
+ MEM_SAFE_FREE(path);
+ }
+
+ return fcu;
}
/* ----------------- Finding Keyframes/Extents -------------------------- */
@@ -417,294 +436,312 @@ FCurve *rna_get_fcurve_context_ui(
/* Binary search algorithm for finding where to insert BezTriple, with optional argument for precision required.
* Returns the index to insert at (data already at that index will be offset if replace is 0)
*/
-static int binarysearch_bezt_index_ex(BezTriple array[], float frame, int arraylen, float threshold, bool *r_replace)
+static int binarysearch_bezt_index_ex(
+ BezTriple array[], float frame, int arraylen, float threshold, bool *r_replace)
{
- int start = 0, end = arraylen;
- int loopbreaker = 0, maxloop = arraylen * 2;
-
- /* initialize replace-flag first */
- *r_replace = false;
-
- /* sneaky optimizations (don't go through searching process if...):
- * - keyframe to be added is to be added out of current bounds
- * - keyframe to be added would replace one of the existing ones on bounds
- */
- if ((arraylen <= 0) || (array == NULL)) {
- CLOG_WARN(&LOG, "encountered invalid array");
- return 0;
- }
- else {
- /* check whether to add before/after/on */
- float framenum;
-
- /* 'First' Keyframe (when only one keyframe, this case is used) */
- framenum = array[0].vec[1][0];
- if (IS_EQT(frame, framenum, threshold)) {
- *r_replace = true;
- return 0;
- }
- else if (frame < framenum)
- return 0;
-
- /* 'Last' Keyframe */
- framenum = array[(arraylen - 1)].vec[1][0];
- if (IS_EQT(frame, framenum, threshold)) {
- *r_replace = true;
- return (arraylen - 1);
- }
- else if (frame > framenum)
- return arraylen;
- }
-
-
- /* most of the time, this loop is just to find where to put it
- * 'loopbreaker' is just here to prevent infinite loops
- */
- for (loopbreaker = 0; (start <= end) && (loopbreaker < maxloop); loopbreaker++) {
- /* compute and get midpoint */
- int mid = start + ((end - start) / 2); /* we calculate the midpoint this way to avoid int overflows... */
- float midfra = array[mid].vec[1][0];
-
- /* check if exactly equal to midpoint */
- if (IS_EQT(frame, midfra, threshold)) {
- *r_replace = true;
- return mid;
- }
-
- /* repeat in upper/lower half */
- if (frame > midfra)
- start = mid + 1;
- else if (frame < midfra)
- end = mid - 1;
- }
-
- /* print error if loop-limit exceeded */
- if (loopbreaker == (maxloop - 1)) {
- CLOG_ERROR(&LOG, "search taking too long");
-
- /* include debug info */
- CLOG_ERROR(&LOG, "\tround = %d: start = %d, end = %d, arraylen = %d", loopbreaker, start, end, arraylen);
- }
-
- /* not found, so return where to place it */
- return start;
+ int start = 0, end = arraylen;
+ int loopbreaker = 0, maxloop = arraylen * 2;
+
+ /* initialize replace-flag first */
+ *r_replace = false;
+
+ /* sneaky optimizations (don't go through searching process if...):
+ * - keyframe to be added is to be added out of current bounds
+ * - keyframe to be added would replace one of the existing ones on bounds
+ */
+ if ((arraylen <= 0) || (array == NULL)) {
+ CLOG_WARN(&LOG, "encountered invalid array");
+ return 0;
+ }
+ else {
+ /* check whether to add before/after/on */
+ float framenum;
+
+ /* 'First' Keyframe (when only one keyframe, this case is used) */
+ framenum = array[0].vec[1][0];
+ if (IS_EQT(frame, framenum, threshold)) {
+ *r_replace = true;
+ return 0;
+ }
+ else if (frame < framenum)
+ return 0;
+
+ /* 'Last' Keyframe */
+ framenum = array[(arraylen - 1)].vec[1][0];
+ if (IS_EQT(frame, framenum, threshold)) {
+ *r_replace = true;
+ return (arraylen - 1);
+ }
+ else if (frame > framenum)
+ return arraylen;
+ }
+
+ /* most of the time, this loop is just to find where to put it
+ * 'loopbreaker' is just here to prevent infinite loops
+ */
+ for (loopbreaker = 0; (start <= end) && (loopbreaker < maxloop); loopbreaker++) {
+ /* compute and get midpoint */
+ int mid = start + ((end - start) /
+ 2); /* we calculate the midpoint this way to avoid int overflows... */
+ float midfra = array[mid].vec[1][0];
+
+ /* check if exactly equal to midpoint */
+ if (IS_EQT(frame, midfra, threshold)) {
+ *r_replace = true;
+ return mid;
+ }
+
+ /* repeat in upper/lower half */
+ if (frame > midfra)
+ start = mid + 1;
+ else if (frame < midfra)
+ end = mid - 1;
+ }
+
+ /* print error if loop-limit exceeded */
+ if (loopbreaker == (maxloop - 1)) {
+ CLOG_ERROR(&LOG, "search taking too long");
+
+ /* include debug info */
+ CLOG_ERROR(&LOG,
+ "\tround = %d: start = %d, end = %d, arraylen = %d",
+ loopbreaker,
+ start,
+ end,
+ arraylen);
+ }
+
+ /* not found, so return where to place it */
+ return start;
}
-
/* Binary search algorithm for finding where to insert BezTriple. (for use by insert_bezt_fcurve)
* Returns the index to insert at (data already at that index will be offset if replace is 0)
*/
int binarysearch_bezt_index(BezTriple array[], float frame, int arraylen, bool *r_replace)
{
- /* this is just a wrapper which uses the default threshold */
- return binarysearch_bezt_index_ex(array, frame, arraylen, BEZT_BINARYSEARCH_THRESH, r_replace);
+ /* this is just a wrapper which uses the default threshold */
+ return binarysearch_bezt_index_ex(array, frame, arraylen, BEZT_BINARYSEARCH_THRESH, r_replace);
}
/* ...................................... */
/* helper for calc_fcurve_* functions -> find first and last BezTriple to be used */
-static short get_fcurve_end_keyframes(FCurve *fcu, BezTriple **first, BezTriple **last,
+static short get_fcurve_end_keyframes(FCurve *fcu,
+ BezTriple **first,
+ BezTriple **last,
const bool do_sel_only)
{
- bool found = false;
-
- /* init outputs */
- *first = NULL;
- *last = NULL;
-
- /* sanity checks */
- if (fcu->bezt == NULL)
- return found;
-
- /* only include selected items? */
- if (do_sel_only) {
- BezTriple *bezt;
- unsigned int i;
-
- /* find first selected */
- bezt = fcu->bezt;
- for (i = 0; i < fcu->totvert; bezt++, i++) {
- if (BEZT_ISSEL_ANY(bezt)) {
- *first = bezt;
- found = true;
- break;
- }
- }
-
- /* find last selected */
- bezt = ARRAY_LAST_ITEM(fcu->bezt, BezTriple, fcu->totvert);
- for (i = 0; i < fcu->totvert; bezt--, i++) {
- if (BEZT_ISSEL_ANY(bezt)) {
- *last = bezt;
- found = true;
- break;
- }
- }
- }
- else {
- /* just full array */
- *first = fcu->bezt;
- *last = ARRAY_LAST_ITEM(fcu->bezt, BezTriple, fcu->totvert);
- found = true;
- }
-
- return found;
+ bool found = false;
+
+ /* init outputs */
+ *first = NULL;
+ *last = NULL;
+
+ /* sanity checks */
+ if (fcu->bezt == NULL)
+ return found;
+
+ /* only include selected items? */
+ if (do_sel_only) {
+ BezTriple *bezt;
+ unsigned int i;
+
+ /* find first selected */
+ bezt = fcu->bezt;
+ for (i = 0; i < fcu->totvert; bezt++, i++) {
+ if (BEZT_ISSEL_ANY(bezt)) {
+ *first = bezt;
+ found = true;
+ break;
+ }
+ }
+
+ /* find last selected */
+ bezt = ARRAY_LAST_ITEM(fcu->bezt, BezTriple, fcu->totvert);
+ for (i = 0; i < fcu->totvert; bezt--, i++) {
+ if (BEZT_ISSEL_ANY(bezt)) {
+ *last = bezt;
+ found = true;
+ break;
+ }
+ }
+ }
+ else {
+ /* just full array */
+ *first = fcu->bezt;
+ *last = ARRAY_LAST_ITEM(fcu->bezt, BezTriple, fcu->totvert);
+ found = true;
+ }
+
+ return found;
}
-
/* Calculate the extents of F-Curve's data */
-bool calc_fcurve_bounds(FCurve *fcu, float *xmin, float *xmax, float *ymin, float *ymax,
- const bool do_sel_only, const bool include_handles)
+bool calc_fcurve_bounds(FCurve *fcu,
+ float *xmin,
+ float *xmax,
+ float *ymin,
+ float *ymax,
+ const bool do_sel_only,
+ const bool include_handles)
{
- float xminv = 999999999.0f, xmaxv = -999999999.0f;
- float yminv = 999999999.0f, ymaxv = -999999999.0f;
- bool foundvert = false;
- unsigned int i;
-
- if (fcu->totvert) {
- if (fcu->bezt) {
- BezTriple *bezt_first = NULL, *bezt_last = NULL;
-
- if (xmin || xmax) {
- /* get endpoint keyframes */
- foundvert = get_fcurve_end_keyframes(fcu, &bezt_first, &bezt_last, do_sel_only);
-
- if (bezt_first) {
- BLI_assert(bezt_last != NULL);
-
- if (include_handles) {
- xminv = min_fff(xminv, bezt_first->vec[0][0], bezt_first->vec[1][0]);
- xmaxv = max_fff(xmaxv, bezt_last->vec[1][0], bezt_last->vec[2][0]);
- }
- else {
- xminv = min_ff(xminv, bezt_first->vec[1][0]);
- xmaxv = max_ff(xmaxv, bezt_last->vec[1][0]);
- }
- }
- }
-
- /* only loop over keyframes to find extents for values if needed */
- if (ymin || ymax) {
- BezTriple *bezt, *prevbezt = NULL;
-
- for (bezt = fcu->bezt, i = 0; i < fcu->totvert; prevbezt = bezt, bezt++, i++) {
- if ((do_sel_only == false) || BEZT_ISSEL_ANY(bezt)) {
- /* keyframe itself */
- yminv = min_ff(yminv, bezt->vec[1][1]);
- ymaxv = max_ff(ymaxv, bezt->vec[1][1]);
-
- if (include_handles) {
- /* left handle - only if applicable
- * NOTE: for the very first keyframe, the left handle actually has no bearings on anything
- */
- if (prevbezt && (prevbezt->ipo == BEZT_IPO_BEZ)) {
- yminv = min_ff(yminv, bezt->vec[0][1]);
- ymaxv = max_ff(ymaxv, bezt->vec[0][1]);
- }
-
- /* right handle - only if applicable */
- if (bezt->ipo == BEZT_IPO_BEZ) {
- yminv = min_ff(yminv, bezt->vec[2][1]);
- ymaxv = max_ff(ymaxv, bezt->vec[2][1]);
- }
- }
-
- foundvert = true;
- }
- }
- }
- }
- else if (fcu->fpt) {
- /* frame range can be directly calculated from end verts */
- if (xmin || xmax) {
- xminv = min_ff(xminv, fcu->fpt[0].vec[0]);
- xmaxv = max_ff(xmaxv, fcu->fpt[fcu->totvert - 1].vec[0]);
- }
-
- /* only loop over keyframes to find extents for values if needed */
- if (ymin || ymax) {
- FPoint *fpt;
-
- for (fpt = fcu->fpt, i = 0; i < fcu->totvert; fpt++, i++) {
- if (fpt->vec[1] < yminv)
- yminv = fpt->vec[1];
- if (fpt->vec[1] > ymaxv)
- ymaxv = fpt->vec[1];
-
- foundvert = true;
- }
- }
- }
- }
-
- if (foundvert) {
- if (xmin) *xmin = xminv;
- if (xmax) *xmax = xmaxv;
-
- if (ymin) *ymin = yminv;
- if (ymax) *ymax = ymaxv;
- }
- else {
- if (G.debug & G_DEBUG)
- printf("F-Curve calc bounds didn't find anything, so assuming minimum bounds of 1.0\n");
-
- if (xmin) *xmin = 0.0f;
- if (xmax) *xmax = 1.0f;
-
- if (ymin) *ymin = 0.0f;
- if (ymax) *ymax = 1.0f;
- }
-
- return foundvert;
+ float xminv = 999999999.0f, xmaxv = -999999999.0f;
+ float yminv = 999999999.0f, ymaxv = -999999999.0f;
+ bool foundvert = false;
+ unsigned int i;
+
+ if (fcu->totvert) {
+ if (fcu->bezt) {
+ BezTriple *bezt_first = NULL, *bezt_last = NULL;
+
+ if (xmin || xmax) {
+ /* get endpoint keyframes */
+ foundvert = get_fcurve_end_keyframes(fcu, &bezt_first, &bezt_last, do_sel_only);
+
+ if (bezt_first) {
+ BLI_assert(bezt_last != NULL);
+
+ if (include_handles) {
+ xminv = min_fff(xminv, bezt_first->vec[0][0], bezt_first->vec[1][0]);
+ xmaxv = max_fff(xmaxv, bezt_last->vec[1][0], bezt_last->vec[2][0]);
+ }
+ else {
+ xminv = min_ff(xminv, bezt_first->vec[1][0]);
+ xmaxv = max_ff(xmaxv, bezt_last->vec[1][0]);
+ }
+ }
+ }
+
+ /* only loop over keyframes to find extents for values if needed */
+ if (ymin || ymax) {
+ BezTriple *bezt, *prevbezt = NULL;
+
+ for (bezt = fcu->bezt, i = 0; i < fcu->totvert; prevbezt = bezt, bezt++, i++) {
+ if ((do_sel_only == false) || BEZT_ISSEL_ANY(bezt)) {
+ /* keyframe itself */
+ yminv = min_ff(yminv, bezt->vec[1][1]);
+ ymaxv = max_ff(ymaxv, bezt->vec[1][1]);
+
+ if (include_handles) {
+ /* left handle - only if applicable
+ * NOTE: for the very first keyframe, the left handle actually has no bearings on anything
+ */
+ if (prevbezt && (prevbezt->ipo == BEZT_IPO_BEZ)) {
+ yminv = min_ff(yminv, bezt->vec[0][1]);
+ ymaxv = max_ff(ymaxv, bezt->vec[0][1]);
+ }
+
+ /* right handle - only if applicable */
+ if (bezt->ipo == BEZT_IPO_BEZ) {
+ yminv = min_ff(yminv, bezt->vec[2][1]);
+ ymaxv = max_ff(ymaxv, bezt->vec[2][1]);
+ }
+ }
+
+ foundvert = true;
+ }
+ }
+ }
+ }
+ else if (fcu->fpt) {
+ /* frame range can be directly calculated from end verts */
+ if (xmin || xmax) {
+ xminv = min_ff(xminv, fcu->fpt[0].vec[0]);
+ xmaxv = max_ff(xmaxv, fcu->fpt[fcu->totvert - 1].vec[0]);
+ }
+
+ /* only loop over keyframes to find extents for values if needed */
+ if (ymin || ymax) {
+ FPoint *fpt;
+
+ for (fpt = fcu->fpt, i = 0; i < fcu->totvert; fpt++, i++) {
+ if (fpt->vec[1] < yminv)
+ yminv = fpt->vec[1];
+ if (fpt->vec[1] > ymaxv)
+ ymaxv = fpt->vec[1];
+
+ foundvert = true;
+ }
+ }
+ }
+ }
+
+ if (foundvert) {
+ if (xmin)
+ *xmin = xminv;
+ if (xmax)
+ *xmax = xmaxv;
+
+ if (ymin)
+ *ymin = yminv;
+ if (ymax)
+ *ymax = ymaxv;
+ }
+ else {
+ if (G.debug & G_DEBUG)
+ printf("F-Curve calc bounds didn't find anything, so assuming minimum bounds of 1.0\n");
+
+ if (xmin)
+ *xmin = 0.0f;
+ if (xmax)
+ *xmax = 1.0f;
+
+ if (ymin)
+ *ymin = 0.0f;
+ if (ymax)
+ *ymax = 1.0f;
+ }
+
+ return foundvert;
}
/* Calculate the extents of F-Curve's keyframes */
-bool calc_fcurve_range(FCurve *fcu, float *start, float *end,
- const bool do_sel_only, const bool do_min_length)
+bool calc_fcurve_range(
+ FCurve *fcu, float *start, float *end, const bool do_sel_only, const bool do_min_length)
{
- float min = 999999999.0f, max = -999999999.0f;
- bool foundvert = false;
-
- if (fcu->totvert) {
- if (fcu->bezt) {
- BezTriple *bezt_first = NULL, *bezt_last = NULL;
+ float min = 999999999.0f, max = -999999999.0f;
+ bool foundvert = false;
- /* get endpoint keyframes */
- get_fcurve_end_keyframes(fcu, &bezt_first, &bezt_last, do_sel_only);
+ if (fcu->totvert) {
+ if (fcu->bezt) {
+ BezTriple *bezt_first = NULL, *bezt_last = NULL;
- if (bezt_first) {
- BLI_assert(bezt_last != NULL);
+ /* get endpoint keyframes */
+ get_fcurve_end_keyframes(fcu, &bezt_first, &bezt_last, do_sel_only);
- min = min_ff(min, bezt_first->vec[1][0]);
- max = max_ff(max, bezt_last->vec[1][0]);
+ if (bezt_first) {
+ BLI_assert(bezt_last != NULL);
- foundvert = true;
- }
- }
- else if (fcu->fpt) {
- min = min_ff(min, fcu->fpt[0].vec[0]);
- max = max_ff(max, fcu->fpt[fcu->totvert - 1].vec[0]);
+ min = min_ff(min, bezt_first->vec[1][0]);
+ max = max_ff(max, bezt_last->vec[1][0]);
- foundvert = true;
- }
+ foundvert = true;
+ }
+ }
+ else if (fcu->fpt) {
+ min = min_ff(min, fcu->fpt[0].vec[0]);
+ max = max_ff(max, fcu->fpt[fcu->totvert - 1].vec[0]);
- }
+ foundvert = true;
+ }
+ }
- if (foundvert == false) {
- min = max = 0.0f;
- }
+ if (foundvert == false) {
+ min = max = 0.0f;
+ }
- if (do_min_length) {
- /* minimum length is 1 frame */
- if (min == max) {
- max += 1.0f;
- }
- }
+ if (do_min_length) {
+ /* minimum length is 1 frame */
+ if (min == max) {
+ max += 1.0f;
+ }
+ }
- *start = min;
- *end = max;
+ *start = min;
+ *end = max;
- return foundvert;
+ return foundvert;
}
/* ----------------- Status Checks -------------------------- */
@@ -715,65 +752,62 @@ bool calc_fcurve_range(FCurve *fcu, float *start, float *end,
*/
bool fcurve_are_keyframes_usable(FCurve *fcu)
{
- /* F-Curve must exist */
- if (fcu == NULL)
- return false;
-
- /* F-Curve must not have samples - samples are mutually exclusive of keyframes */
- if (fcu->fpt)
- return false;
-
- /* if it has modifiers, none of these should "drastically" alter the curve */
- if (fcu->modifiers.first) {
- FModifier *fcm;
-
- /* check modifiers from last to first, as last will be more influential */
- /* TODO: optionally, only check modifier if it is the active one... */
- for (fcm = fcu->modifiers.last; fcm; fcm = fcm->prev) {
- /* ignore if muted/disabled */
- if (fcm->flag & (FMODIFIER_FLAG_DISABLED | FMODIFIER_FLAG_MUTED))
- continue;
-
- /* type checks */
- switch (fcm->type) {
- /* clearly harmless - do nothing */
- case FMODIFIER_TYPE_CYCLES:
- case FMODIFIER_TYPE_STEPPED:
- case FMODIFIER_TYPE_NOISE:
- break;
-
- /* sometimes harmful - depending on whether they're "additive" or not */
- case FMODIFIER_TYPE_GENERATOR:
- {
- FMod_Generator *data = (FMod_Generator *)fcm->data;
-
- if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
- return false;
- break;
- }
- case FMODIFIER_TYPE_FN_GENERATOR:
- {
- FMod_FunctionGenerator *data = (FMod_FunctionGenerator *)fcm->data;
-
- if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
- return false;
- break;
- }
- /* always harmful - cannot allow */
- default:
- return false;
- }
- }
- }
-
- /* keyframes are usable */
- return true;
+ /* F-Curve must exist */
+ if (fcu == NULL)
+ return false;
+
+ /* F-Curve must not have samples - samples are mutually exclusive of keyframes */
+ if (fcu->fpt)
+ return false;
+
+ /* if it has modifiers, none of these should "drastically" alter the curve */
+ if (fcu->modifiers.first) {
+ FModifier *fcm;
+
+ /* check modifiers from last to first, as last will be more influential */
+ /* TODO: optionally, only check modifier if it is the active one... */
+ for (fcm = fcu->modifiers.last; fcm; fcm = fcm->prev) {
+ /* ignore if muted/disabled */
+ if (fcm->flag & (FMODIFIER_FLAG_DISABLED | FMODIFIER_FLAG_MUTED))
+ continue;
+
+ /* type checks */
+ switch (fcm->type) {
+ /* clearly harmless - do nothing */
+ case FMODIFIER_TYPE_CYCLES:
+ case FMODIFIER_TYPE_STEPPED:
+ case FMODIFIER_TYPE_NOISE:
+ break;
+
+ /* sometimes harmful - depending on whether they're "additive" or not */
+ case FMODIFIER_TYPE_GENERATOR: {
+ FMod_Generator *data = (FMod_Generator *)fcm->data;
+
+ if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
+ return false;
+ break;
+ }
+ case FMODIFIER_TYPE_FN_GENERATOR: {
+ FMod_FunctionGenerator *data = (FMod_FunctionGenerator *)fcm->data;
+
+ if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
+ return false;
+ break;
+ }
+ /* always harmful - cannot allow */
+ default:
+ return false;
+ }
+ }
+ }
+
+ /* keyframes are usable */
+ return true;
}
bool BKE_fcurve_is_protected(FCurve *fcu)
{
- return ((fcu->flag & FCURVE_PROTECTED) ||
- ((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED)));
+ return ((fcu->flag & FCURVE_PROTECTED) || ((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED)));
}
/* Can keyframes be added to F-Curve?
@@ -781,16 +815,16 @@ bool BKE_fcurve_is_protected(FCurve *fcu)
*/
bool fcurve_is_keyframable(FCurve *fcu)
{
- /* F-Curve's keyframes must be "usable" (i.e. visible + have an effect on final result) */
- if (fcurve_are_keyframes_usable(fcu) == 0)
- return false;
+ /* F-Curve's keyframes must be "usable" (i.e. visible + have an effect on final result) */
+ if (fcurve_are_keyframes_usable(fcu) == 0)
+ return false;
- /* F-Curve must currently be editable too */
- if (BKE_fcurve_is_protected(fcu))
- return false;
+ /* F-Curve must currently be editable too */
+ if (BKE_fcurve_is_protected(fcu))
+ return false;
- /* F-Curve is keyframable */
- return true;
+ /* F-Curve is keyframable */
+ return true;
}
/* ***************************** Keyframe Column Tools ********************************* */
@@ -798,25 +832,29 @@ bool fcurve_is_keyframable(FCurve *fcu)
/* add a BezTriple to a column */
void bezt_add_to_cfra_elem(ListBase *lb, BezTriple *bezt)
{
- CfraElem *ce, *cen;
-
- for (ce = lb->first; ce; ce = ce->next) {
- /* double key? */
- if (IS_EQT(ce->cfra, bezt->vec[1][0], BEZT_BINARYSEARCH_THRESH)) {
- if (bezt->f2 & SELECT) ce->sel = bezt->f2;
- return;
- }
- /* should key be inserted before this column? */
- else if (ce->cfra > bezt->vec[1][0]) break;
- }
-
- /* create a new column */
- cen = MEM_callocN(sizeof(CfraElem), "add_to_cfra_elem");
- if (ce) BLI_insertlinkbefore(lb, ce, cen);
- else BLI_addtail(lb, cen);
-
- cen->cfra = bezt->vec[1][0];
- cen->sel = bezt->f2;
+ CfraElem *ce, *cen;
+
+ for (ce = lb->first; ce; ce = ce->next) {
+ /* double key? */
+ if (IS_EQT(ce->cfra, bezt->vec[1][0], BEZT_BINARYSEARCH_THRESH)) {
+ if (bezt->f2 & SELECT)
+ ce->sel = bezt->f2;
+ return;
+ }
+ /* should key be inserted before this column? */
+ else if (ce->cfra > bezt->vec[1][0])
+ break;
+ }
+
+ /* create a new column */
+ cen = MEM_callocN(sizeof(CfraElem), "add_to_cfra_elem");
+ if (ce)
+ BLI_insertlinkbefore(lb, ce, cen);
+ else
+ BLI_addtail(lb, cen);
+
+ cen->cfra = bezt->vec[1][0];
+ cen->sel = bezt->f2;
}
/* ***************************** Samples Utilities ******************************* */
@@ -825,53 +863,53 @@ void bezt_add_to_cfra_elem(ListBase *lb, BezTriple *bezt)
* which BezTriples/Keyframe data are ill equipped to do.
*/
-
/* Basic sampling callback which acts as a wrapper for evaluate_fcurve()
* 'data' arg here is unneeded here...
*/
float fcurve_samplingcb_evalcurve(FCurve *fcu, void *UNUSED(data), float evaltime)
{
- /* assume any interference from drivers on the curve is intended... */
- return evaluate_fcurve(fcu, evaltime);
+ /* assume any interference from drivers on the curve is intended... */
+ return evaluate_fcurve(fcu, evaltime);
}
-
/* Main API function for creating a set of sampled curve data, given some callback function
* used to retrieve the values to store.
*/
void fcurve_store_samples(FCurve *fcu, void *data, int start, int end, FcuSampleFunc sample_cb)
{
- FPoint *fpt, *new_fpt;
- int cfra;
-
- /* sanity checks */
- /* TODO: make these tests report errors using reports not CLOG's */
- if (ELEM(NULL, fcu, sample_cb)) {
- CLOG_ERROR(&LOG, "No F-Curve with F-Curve Modifiers to Bake");
- return;
- }
- if (start > end) {
- CLOG_ERROR(&LOG, "Error: Frame range for Sampled F-Curve creation is inappropriate");
- return;
- }
-
- /* set up sample data */
- fpt = new_fpt = MEM_callocN(sizeof(FPoint) * (end - start + 1), "FPoint Samples");
-
- /* use the sampling callback at 1-frame intervals from start to end frames */
- for (cfra = start; cfra <= end; cfra++, fpt++) {
- fpt->vec[0] = (float)cfra;
- fpt->vec[1] = sample_cb(fcu, data, (float)cfra);
- }
-
- /* free any existing sample/keyframe data on curve */
- if (fcu->bezt) MEM_freeN(fcu->bezt);
- if (fcu->fpt) MEM_freeN(fcu->fpt);
-
- /* store the samples */
- fcu->bezt = NULL;
- fcu->fpt = new_fpt;
- fcu->totvert = end - start + 1;
+ FPoint *fpt, *new_fpt;
+ int cfra;
+
+ /* sanity checks */
+ /* TODO: make these tests report errors using reports not CLOG's */
+ if (ELEM(NULL, fcu, sample_cb)) {
+ CLOG_ERROR(&LOG, "No F-Curve with F-Curve Modifiers to Bake");
+ return;
+ }
+ if (start > end) {
+ CLOG_ERROR(&LOG, "Error: Frame range for Sampled F-Curve creation is inappropriate");
+ return;
+ }
+
+ /* set up sample data */
+ fpt = new_fpt = MEM_callocN(sizeof(FPoint) * (end - start + 1), "FPoint Samples");
+
+ /* use the sampling callback at 1-frame intervals from start to end frames */
+ for (cfra = start; cfra <= end; cfra++, fpt++) {
+ fpt->vec[0] = (float)cfra;
+ fpt->vec[1] = sample_cb(fcu, data, (float)cfra);
+ }
+
+ /* free any existing sample/keyframe data on curve */
+ if (fcu->bezt)
+ MEM_freeN(fcu->bezt);
+ if (fcu->fpt)
+ MEM_freeN(fcu->fpt);
+
+ /* store the samples */
+ fcu->bezt = NULL;
+ fcu->fpt = new_fpt;
+ fcu->totvert = end - start + 1;
}
/* ***************************** F-Curve Sanity ********************************* */
@@ -883,60 +921,61 @@ void fcurve_store_samples(FCurve *fcu, void *data, int start, int end, FcuSample
/* Checks if the F-Curve has a Cycles modifier, and returns the type of the cycle behavior. */
eFCU_Cycle_Type BKE_fcurve_get_cycle_type(FCurve *fcu)
{
- FModifier *fcm = fcu->modifiers.first;
+ FModifier *fcm = fcu->modifiers.first;
- if (!fcm || fcm->type != FMODIFIER_TYPE_CYCLES) {
- return FCU_CYCLE_NONE;
- }
+ if (!fcm || fcm->type != FMODIFIER_TYPE_CYCLES) {
+ return FCU_CYCLE_NONE;
+ }
- if (fcm->flag & (FMODIFIER_FLAG_DISABLED | FMODIFIER_FLAG_MUTED)) {
- return FCU_CYCLE_NONE;
- }
+ if (fcm->flag & (FMODIFIER_FLAG_DISABLED | FMODIFIER_FLAG_MUTED)) {
+ return FCU_CYCLE_NONE;
+ }
- if (fcm->flag & (FMODIFIER_FLAG_RANGERESTRICT | FMODIFIER_FLAG_USEINFLUENCE)) {
- return FCU_CYCLE_NONE;
- }
+ if (fcm->flag & (FMODIFIER_FLAG_RANGERESTRICT | FMODIFIER_FLAG_USEINFLUENCE)) {
+ return FCU_CYCLE_NONE;
+ }
- FMod_Cycles *data = (FMod_Cycles *)fcm->data;
+ FMod_Cycles *data = (FMod_Cycles *)fcm->data;
- if (data && data->after_cycles == 0 && data->before_cycles == 0) {
- if (data->before_mode == FCM_EXTRAPOLATE_CYCLIC && data->after_mode == FCM_EXTRAPOLATE_CYCLIC) {
- return FCU_CYCLE_PERFECT;
- }
+ if (data && data->after_cycles == 0 && data->before_cycles == 0) {
+ if (data->before_mode == FCM_EXTRAPOLATE_CYCLIC &&
+ data->after_mode == FCM_EXTRAPOLATE_CYCLIC) {
+ return FCU_CYCLE_PERFECT;
+ }
- if (ELEM(data->before_mode, FCM_EXTRAPOLATE_CYCLIC, FCM_EXTRAPOLATE_CYCLIC_OFFSET) &&
- ELEM(data->after_mode, FCM_EXTRAPOLATE_CYCLIC, FCM_EXTRAPOLATE_CYCLIC_OFFSET))
- {
- return FCU_CYCLE_OFFSET;
- }
- }
+ if (ELEM(data->before_mode, FCM_EXTRAPOLATE_CYCLIC, FCM_EXTRAPOLATE_CYCLIC_OFFSET) &&
+ ELEM(data->after_mode, FCM_EXTRAPOLATE_CYCLIC, FCM_EXTRAPOLATE_CYCLIC_OFFSET)) {
+ return FCU_CYCLE_OFFSET;
+ }
+ }
- return FCU_CYCLE_NONE;
+ return FCU_CYCLE_NONE;
}
/* Checks if the F-Curve has a Cycles modifier with simple settings that warrant transition smoothing */
bool BKE_fcurve_is_cyclic(FCurve *fcu)
{
- return BKE_fcurve_get_cycle_type(fcu) != FCU_CYCLE_NONE;
+ return BKE_fcurve_get_cycle_type(fcu) != FCU_CYCLE_NONE;
}
/* Shifts 'in' by the difference in coordinates between 'to' and 'from', using 'out' as the output buffer.
* When 'to' and 'from' are end points of the loop, this moves the 'in' point one loop cycle.
*/
-static BezTriple *cycle_offset_triple(bool cycle, BezTriple *out, const BezTriple *in, const BezTriple *from, const BezTriple *to)
+static BezTriple *cycle_offset_triple(
+ bool cycle, BezTriple *out, const BezTriple *in, const BezTriple *from, const BezTriple *to)
{
- if (!cycle)
- return NULL;
+ if (!cycle)
+ return NULL;
- memcpy(out, in, sizeof(BezTriple));
+ memcpy(out, in, sizeof(BezTriple));
- float delta[3];
- sub_v3_v3v3(delta, to->vec[1], from->vec[1]);
+ float delta[3];
+ sub_v3_v3v3(delta, to->vec[1], from->vec[1]);
- for (int i = 0; i < 3; i++)
- add_v3_v3(out->vec[i], delta);
+ for (int i = 0; i < 3; i++)
+ add_v3_v3(out->vec[i], delta);
- return out;
+ return out;
}
/* This function recalculates the handles of an F-Curve
@@ -944,97 +983,99 @@ static BezTriple *cycle_offset_triple(bool cycle, BezTriple *out, const BezTripl
*/
void calchandles_fcurve(FCurve *fcu)
{
- BezTriple *bezt, *prev, *next;
- int a = fcu->totvert;
-
- /* Error checking:
- * - need at least two points
- * - need bezier keys
- * - only bezier-interpolation has handles (for now)
- */
- if (ELEM(NULL, fcu, fcu->bezt) || (a < 2) /*|| ELEM(fcu->ipo, BEZT_IPO_CONST, BEZT_IPO_LIN)*/)
- return;
-
- /* if the first modifier is Cycles, smooth the curve through the cycle */
- BezTriple *first = &fcu->bezt[0], *last = &fcu->bezt[fcu->totvert - 1];
- BezTriple tmp;
-
- bool cycle = BKE_fcurve_is_cyclic(fcu) && BEZT_IS_AUTOH(first) && BEZT_IS_AUTOH(last);
-
- /* get initial pointers */
- bezt = fcu->bezt;
- prev = cycle_offset_triple(cycle, &tmp, &fcu->bezt[fcu->totvert - 2], last, first);
- next = (bezt + 1);
-
- /* loop over all beztriples, adjusting handles */
- while (a--) {
- /* clamp timing of handles to be on either side of beztriple */
- if (bezt->vec[0][0] > bezt->vec[1][0]) bezt->vec[0][0] = bezt->vec[1][0];
- if (bezt->vec[2][0] < bezt->vec[1][0]) bezt->vec[2][0] = bezt->vec[1][0];
-
- /* calculate auto-handles */
- BKE_nurb_handle_calc(bezt, prev, next, true, fcu->auto_smoothing);
-
- /* for automatic ease in and out */
- if (BEZT_IS_AUTOH(bezt) && !cycle) {
- /* only do this on first or last beztriple */
- if ((a == 0) || (a == fcu->totvert - 1)) {
- /* set both handles to have same horizontal value as keyframe */
- if (fcu->extend == FCURVE_EXTRAPOLATE_CONSTANT) {
- bezt->vec[0][1] = bezt->vec[2][1] = bezt->vec[1][1];
- /* remember that these keyframes are special, they don't need to be adjusted */
- bezt->f5 = HD_AUTOTYPE_SPECIAL;
- }
- }
- }
-
- /* avoid total smoothing failure on duplicate keyframes (can happen during grab) */
- if (prev && prev->vec[1][0] >= bezt->vec[1][0]) {
- prev->f5 = bezt->f5 = HD_AUTOTYPE_SPECIAL;
- }
-
- /* advance pointers for next iteration */
- prev = bezt;
-
- if (a == 1) {
- next = cycle_offset_triple(cycle, &tmp, &fcu->bezt[1], first, last);
- }
- else {
- next++;
- }
-
- bezt++;
- }
-
- /* if cyclic extrapolation and Auto Clamp has triggered, ensure it is symmetric */
- if (cycle && (first->f5 != HD_AUTOTYPE_NORMAL || last->f5 != HD_AUTOTYPE_NORMAL)) {
- first->vec[0][1] = first->vec[2][1] = first->vec[1][1];
- last->vec[0][1] = last->vec[2][1] = last->vec[1][1];
- first->f5 = last->f5 = HD_AUTOTYPE_SPECIAL;
- }
-
- /* do a second pass for auto handle: compute the handle to have 0 accelaration step */
- if (fcu->auto_smoothing != FCURVE_SMOOTH_NONE) {
- BKE_nurb_handle_smooth_fcurve(fcu->bezt, fcu->totvert, cycle);
- }
+ BezTriple *bezt, *prev, *next;
+ int a = fcu->totvert;
+
+ /* Error checking:
+ * - need at least two points
+ * - need bezier keys
+ * - only bezier-interpolation has handles (for now)
+ */
+ if (ELEM(NULL, fcu, fcu->bezt) || (a < 2) /*|| ELEM(fcu->ipo, BEZT_IPO_CONST, BEZT_IPO_LIN)*/)
+ return;
+
+ /* if the first modifier is Cycles, smooth the curve through the cycle */
+ BezTriple *first = &fcu->bezt[0], *last = &fcu->bezt[fcu->totvert - 1];
+ BezTriple tmp;
+
+ bool cycle = BKE_fcurve_is_cyclic(fcu) && BEZT_IS_AUTOH(first) && BEZT_IS_AUTOH(last);
+
+ /* get initial pointers */
+ bezt = fcu->bezt;
+ prev = cycle_offset_triple(cycle, &tmp, &fcu->bezt[fcu->totvert - 2], last, first);
+ next = (bezt + 1);
+
+ /* loop over all beztriples, adjusting handles */
+ while (a--) {
+ /* clamp timing of handles to be on either side of beztriple */
+ if (bezt->vec[0][0] > bezt->vec[1][0])
+ bezt->vec[0][0] = bezt->vec[1][0];
+ if (bezt->vec[2][0] < bezt->vec[1][0])
+ bezt->vec[2][0] = bezt->vec[1][0];
+
+ /* calculate auto-handles */
+ BKE_nurb_handle_calc(bezt, prev, next, true, fcu->auto_smoothing);
+
+ /* for automatic ease in and out */
+ if (BEZT_IS_AUTOH(bezt) && !cycle) {
+ /* only do this on first or last beztriple */
+ if ((a == 0) || (a == fcu->totvert - 1)) {
+ /* set both handles to have same horizontal value as keyframe */
+ if (fcu->extend == FCURVE_EXTRAPOLATE_CONSTANT) {
+ bezt->vec[0][1] = bezt->vec[2][1] = bezt->vec[1][1];
+ /* remember that these keyframes are special, they don't need to be adjusted */
+ bezt->f5 = HD_AUTOTYPE_SPECIAL;
+ }
+ }
+ }
+
+ /* avoid total smoothing failure on duplicate keyframes (can happen during grab) */
+ if (prev && prev->vec[1][0] >= bezt->vec[1][0]) {
+ prev->f5 = bezt->f5 = HD_AUTOTYPE_SPECIAL;
+ }
+
+ /* advance pointers for next iteration */
+ prev = bezt;
+
+ if (a == 1) {
+ next = cycle_offset_triple(cycle, &tmp, &fcu->bezt[1], first, last);
+ }
+ else {
+ next++;
+ }
+
+ bezt++;
+ }
+
+ /* if cyclic extrapolation and Auto Clamp has triggered, ensure it is symmetric */
+ if (cycle && (first->f5 != HD_AUTOTYPE_NORMAL || last->f5 != HD_AUTOTYPE_NORMAL)) {
+ first->vec[0][1] = first->vec[2][1] = first->vec[1][1];
+ last->vec[0][1] = last->vec[2][1] = last->vec[1][1];
+ first->f5 = last->f5 = HD_AUTOTYPE_SPECIAL;
+ }
+
+ /* do a second pass for auto handle: compute the handle to have 0 accelaration step */
+ if (fcu->auto_smoothing != FCURVE_SMOOTH_NONE) {
+ BKE_nurb_handle_smooth_fcurve(fcu->bezt, fcu->totvert, cycle);
+ }
}
void testhandles_fcurve(FCurve *fcu, const bool use_handle)
{
- BezTriple *bezt;
- unsigned int a;
+ BezTriple *bezt;
+ unsigned int a;
- /* only beztriples have handles (bpoints don't though) */
- if (ELEM(NULL, fcu, fcu->bezt))
- return;
+ /* only beztriples have handles (bpoints don't though) */
+ if (ELEM(NULL, fcu, fcu->bezt))
+ return;
- /* loop over beztriples */
- for (a = 0, bezt = fcu->bezt; a < fcu->totvert; a++, bezt++) {
- BKE_nurb_bezt_handle_test(bezt, use_handle);
- }
+ /* loop over beztriples */
+ for (a = 0, bezt = fcu->bezt; a < fcu->totvert; a++, bezt++) {
+ BKE_nurb_bezt_handle_test(bezt, use_handle);
+ }
- /* recalculate handles */
- calchandles_fcurve(fcu);
+ /* recalculate handles */
+ calchandles_fcurve(fcu);
}
/* This function sorts BezTriples so that they are arranged in chronological order,
@@ -1042,74 +1083,74 @@ void testhandles_fcurve(FCurve *fcu, const bool use_handle)
*/
void sort_time_fcurve(FCurve *fcu)
{
- bool ok = true;
-
- /* keep adjusting order of beztriples until nothing moves (bubble-sort) */
- while (ok) {
- ok = 0;
-
- /* currently, will only be needed when there are beztriples */
- if (fcu->bezt) {
- BezTriple *bezt;
- unsigned int a;
-
- /* loop over ALL points to adjust position in array and recalculate handles */
- for (a = 0, bezt = fcu->bezt; a < fcu->totvert; a++, bezt++) {
- /* check if thee's a next beztriple which we could try to swap with current */
- if (a < (fcu->totvert - 1)) {
- /* swap if one is after the other (and indicate that order has changed) */
- if (bezt->vec[1][0] > (bezt + 1)->vec[1][0]) {
- SWAP(BezTriple, *bezt, *(bezt + 1));
- ok = 1;
- }
-
- /* if either one of both of the points exceeds crosses over the keyframe time... */
- if ( (bezt->vec[0][0] > bezt->vec[1][0]) && (bezt->vec[2][0] < bezt->vec[1][0]) ) {
- /* swap handles if they have switched sides for some reason */
- swap_v2_v2(bezt->vec[0], bezt->vec[2]);
- }
- else {
- /* clamp handles */
- CLAMP_MAX(bezt->vec[0][0], bezt->vec[1][0]);
- CLAMP_MIN(bezt->vec[2][0], bezt->vec[1][0]);
- }
- }
- }
- }
- }
+ bool ok = true;
+
+ /* keep adjusting order of beztriples until nothing moves (bubble-sort) */
+ while (ok) {
+ ok = 0;
+
+ /* currently, will only be needed when there are beztriples */
+ if (fcu->bezt) {
+ BezTriple *bezt;
+ unsigned int a;
+
+ /* loop over ALL points to adjust position in array and recalculate handles */
+ for (a = 0, bezt = fcu->bezt; a < fcu->totvert; a++, bezt++) {
+ /* check if thee's a next beztriple which we could try to swap with current */
+ if (a < (fcu->totvert - 1)) {
+ /* swap if one is after the other (and indicate that order has changed) */
+ if (bezt->vec[1][0] > (bezt + 1)->vec[1][0]) {
+ SWAP(BezTriple, *bezt, *(bezt + 1));
+ ok = 1;
+ }
+
+ /* if either one of both of the points exceeds crosses over the keyframe time... */
+ if ((bezt->vec[0][0] > bezt->vec[1][0]) && (bezt->vec[2][0] < bezt->vec[1][0])) {
+ /* swap handles if they have switched sides for some reason */
+ swap_v2_v2(bezt->vec[0], bezt->vec[2]);
+ }
+ else {
+ /* clamp handles */
+ CLAMP_MAX(bezt->vec[0][0], bezt->vec[1][0]);
+ CLAMP_MIN(bezt->vec[2][0], bezt->vec[1][0]);
+ }
+ }
+ }
+ }
+ }
}
/* This function tests if any BezTriples are out of order, thus requiring a sort */
short test_time_fcurve(FCurve *fcu)
{
- unsigned int a;
-
- /* sanity checks */
- if (fcu == NULL)
- return 0;
-
- /* currently, only need to test beztriples */
- if (fcu->bezt) {
- BezTriple *bezt;
-
- /* loop through all BezTriples, stopping when one exceeds the one after it */
- for (a = 0, bezt = fcu->bezt; a < (fcu->totvert - 1); a++, bezt++) {
- if (bezt->vec[1][0] > (bezt + 1)->vec[1][0])
- return 1;
- }
- }
- else if (fcu->fpt) {
- FPoint *fpt;
-
- /* loop through all FPoints, stopping when one exceeds the one after it */
- for (a = 0, fpt = fcu->fpt; a < (fcu->totvert - 1); a++, fpt++) {
- if (fpt->vec[0] > (fpt + 1)->vec[0])
- return 1;
- }
- }
-
- /* none need any swapping */
- return 0;
+ unsigned int a;
+
+ /* sanity checks */
+ if (fcu == NULL)
+ return 0;
+
+ /* currently, only need to test beztriples */
+ if (fcu->bezt) {
+ BezTriple *bezt;
+
+ /* loop through all BezTriples, stopping when one exceeds the one after it */
+ for (a = 0, bezt = fcu->bezt; a < (fcu->totvert - 1); a++, bezt++) {
+ if (bezt->vec[1][0] > (bezt + 1)->vec[1][0])
+ return 1;
+ }
+ }
+ else if (fcu->fpt) {
+ FPoint *fpt;
+
+ /* loop through all FPoints, stopping when one exceeds the one after it */
+ for (a = 0, fpt = fcu->fpt; a < (fcu->totvert - 1); a++, fpt++) {
+ if (fpt->vec[0] > (fpt + 1)->vec[0])
+ return 1;
+ }
+ }
+
+ /* none need any swapping */
+ return 0;
}
/* ***************************** Drivers ********************************* */
@@ -1118,216 +1159,224 @@ short test_time_fcurve(FCurve *fcu)
/* TypeInfo for Driver Variables (dvti) */
typedef struct DriverVarTypeInfo {
- /* evaluation callback */
- float (*get_value)(ChannelDriver *driver, DriverVar *dvar);
+ /* evaluation callback */
+ float (*get_value)(ChannelDriver *driver, DriverVar *dvar);
- /* allocation of target slots */
- int num_targets; /* number of target slots required */
- const char *target_names[MAX_DRIVER_TARGETS]; /* UI names that should be given to the slots */
- short target_flags[MAX_DRIVER_TARGETS]; /* flags defining the requirements for each slot */
+ /* allocation of target slots */
+ int num_targets; /* number of target slots required */
+ const char *target_names[MAX_DRIVER_TARGETS]; /* UI names that should be given to the slots */
+ short target_flags[MAX_DRIVER_TARGETS]; /* flags defining the requirements for each slot */
} DriverVarTypeInfo;
/* Macro to begin definitions */
-#define BEGIN_DVAR_TYPEDEF(type) \
- {
+#define BEGIN_DVAR_TYPEDEF(type) {
/* Macro to end definitions */
-#define END_DVAR_TYPEDEF \
- }
+#define END_DVAR_TYPEDEF }
/* ......... */
static ID *dtar_id_ensure_proxy_from(ID *id)
{
- if (id && GS(id->name) == ID_OB && ((Object *)id)->proxy_from)
- return (ID *)(((Object *)id)->proxy_from);
- return id;
+ if (id && GS(id->name) == ID_OB && ((Object *)id)->proxy_from)
+ return (ID *)(((Object *)id)->proxy_from);
+ return id;
}
/* Helper function to obtain a value using RNA from the specified source (for evaluating drivers) */
static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
{
- PointerRNA id_ptr, ptr;
- PropertyRNA *prop;
- ID *id;
- int index = -1;
- float value = 0.0f;
-
- /* sanity check */
- if (ELEM(NULL, driver, dtar))
- return 0.0f;
-
- id = dtar_id_ensure_proxy_from(dtar->id);
-
- /* error check for missing pointer... */
- if (id == NULL) {
- if (G.debug & G_DEBUG) {
- CLOG_ERROR(&LOG, "driver has an invalid target to use (path = %s)", dtar->rna_path);
- }
-
- driver->flag |= DRIVER_FLAG_INVALID;
- dtar->flag |= DTAR_FLAG_INVALID;
- return 0.0f;
- }
-
- /* get RNA-pointer for the ID-block given in target */
- RNA_id_pointer_create(id, &id_ptr);
-
- /* get property to read from, and get value as appropriate */
- if (RNA_path_resolve_property_full(&id_ptr, dtar->rna_path, &ptr, &prop, &index)) {
- if (RNA_property_array_check(prop)) {
- /* array */
- if ((index >= 0) && (index < RNA_property_array_length(&ptr, prop))) {
- switch (RNA_property_type(prop)) {
- case PROP_BOOLEAN:
- value = (float)RNA_property_boolean_get_index(&ptr, prop, index);
- break;
- case PROP_INT:
- value = (float)RNA_property_int_get_index(&ptr, prop, index);
- break;
- case PROP_FLOAT:
- value = RNA_property_float_get_index(&ptr, prop, index);
- break;
- default:
- break;
- }
- }
- else {
- /* out of bounds */
- if (G.debug & G_DEBUG) {
- CLOG_ERROR(&LOG, "Driver Evaluation Error: array index is out of bounds for %s -> %s (%d)",
- id->name, dtar->rna_path, index);
- }
-
- driver->flag |= DRIVER_FLAG_INVALID;
- dtar->flag |= DTAR_FLAG_INVALID;
- return 0.0f;
- }
- }
- else {
- /* not an array */
- switch (RNA_property_type(prop)) {
- case PROP_BOOLEAN:
- value = (float)RNA_property_boolean_get(&ptr, prop);
- break;
- case PROP_INT:
- value = (float)RNA_property_int_get(&ptr, prop);
- break;
- case PROP_FLOAT:
- value = RNA_property_float_get(&ptr, prop);
- break;
- case PROP_ENUM:
- value = (float)RNA_property_enum_get(&ptr, prop);
- break;
- default:
- break;
- }
- }
- }
- else {
- /* path couldn't be resolved */
- if (G.debug & G_DEBUG) {
- CLOG_ERROR(&LOG, "Driver Evaluation Error: cannot resolve target for %s -> %s", id->name, dtar->rna_path);
- }
-
- driver->flag |= DRIVER_FLAG_INVALID;
- dtar->flag |= DTAR_FLAG_INVALID;
- return 0.0f;
- }
-
- /* if we're still here, we should be ok... */
- dtar->flag &= ~DTAR_FLAG_INVALID;
- return value;
+ PointerRNA id_ptr, ptr;
+ PropertyRNA *prop;
+ ID *id;
+ int index = -1;
+ float value = 0.0f;
+
+ /* sanity check */
+ if (ELEM(NULL, driver, dtar))
+ return 0.0f;
+
+ id = dtar_id_ensure_proxy_from(dtar->id);
+
+ /* error check for missing pointer... */
+ if (id == NULL) {
+ if (G.debug & G_DEBUG) {
+ CLOG_ERROR(&LOG, "driver has an invalid target to use (path = %s)", dtar->rna_path);
+ }
+
+ driver->flag |= DRIVER_FLAG_INVALID;
+ dtar->flag |= DTAR_FLAG_INVALID;
+ return 0.0f;
+ }
+
+ /* get RNA-pointer for the ID-block given in target */
+ RNA_id_pointer_create(id, &id_ptr);
+
+ /* get property to read from, and get value as appropriate */
+ if (RNA_path_resolve_property_full(&id_ptr, dtar->rna_path, &ptr, &prop, &index)) {
+ if (RNA_property_array_check(prop)) {
+ /* array */
+ if ((index >= 0) && (index < RNA_property_array_length(&ptr, prop))) {
+ switch (RNA_property_type(prop)) {
+ case PROP_BOOLEAN:
+ value = (float)RNA_property_boolean_get_index(&ptr, prop, index);
+ break;
+ case PROP_INT:
+ value = (float)RNA_property_int_get_index(&ptr, prop, index);
+ break;
+ case PROP_FLOAT:
+ value = RNA_property_float_get_index(&ptr, prop, index);
+ break;
+ default:
+ break;
+ }
+ }
+ else {
+ /* out of bounds */
+ if (G.debug & G_DEBUG) {
+ CLOG_ERROR(&LOG,
+ "Driver Evaluation Error: array index is out of bounds for %s -> %s (%d)",
+ id->name,
+ dtar->rna_path,
+ index);
+ }
+
+ driver->flag |= DRIVER_FLAG_INVALID;
+ dtar->flag |= DTAR_FLAG_INVALID;
+ return 0.0f;
+ }
+ }
+ else {
+ /* not an array */
+ switch (RNA_property_type(prop)) {
+ case PROP_BOOLEAN:
+ value = (float)RNA_property_boolean_get(&ptr, prop);
+ break;
+ case PROP_INT:
+ value = (float)RNA_property_int_get(&ptr, prop);
+ break;
+ case PROP_FLOAT:
+ value = RNA_property_float_get(&ptr, prop);
+ break;
+ case PROP_ENUM:
+ value = (float)RNA_property_enum_get(&ptr, prop);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ else {
+ /* path couldn't be resolved */
+ if (G.debug & G_DEBUG) {
+ CLOG_ERROR(&LOG,
+ "Driver Evaluation Error: cannot resolve target for %s -> %s",
+ id->name,
+ dtar->rna_path);
+ }
+
+ driver->flag |= DRIVER_FLAG_INVALID;
+ dtar->flag |= DTAR_FLAG_INVALID;
+ return 0.0f;
+ }
+
+ /* if we're still here, we should be ok... */
+ dtar->flag &= ~DTAR_FLAG_INVALID;
+ return value;
}
/**
* Same as 'dtar_get_prop_val'. but get the RNA property.
*/
-bool driver_get_variable_property(
- ChannelDriver *driver, DriverTarget *dtar,
- PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
+bool driver_get_variable_property(ChannelDriver *driver,
+ DriverTarget *dtar,
+ PointerRNA *r_ptr,
+ PropertyRNA **r_prop,
+ int *r_index)
{
- PointerRNA id_ptr;
- PointerRNA ptr;
- PropertyRNA *prop;
- ID *id;
- int index = -1;
-
- /* sanity check */
- if (ELEM(NULL, driver, dtar))
- return false;
-
- id = dtar_id_ensure_proxy_from(dtar->id);
-
- /* error check for missing pointer... */
- if (id == NULL) {
- if (G.debug & G_DEBUG) {
- CLOG_ERROR(&LOG, "driver has an invalid target to use (path = %s)", dtar->rna_path);
- }
-
- driver->flag |= DRIVER_FLAG_INVALID;
- dtar->flag |= DTAR_FLAG_INVALID;
- return false;
- }
-
- /* get RNA-pointer for the ID-block given in target */
- RNA_id_pointer_create(id, &id_ptr);
-
- /* get property to read from, and get value as appropriate */
- if (dtar->rna_path == NULL || dtar->rna_path[0] == '\0') {
- ptr = PointerRNA_NULL;
- prop = NULL; /* ok */
- }
- else if (RNA_path_resolve_property_full(&id_ptr, dtar->rna_path, &ptr, &prop, &index)) {
- /* ok */
- }
- else {
- /* path couldn't be resolved */
- if (G.debug & G_DEBUG) {
- CLOG_ERROR(&LOG, "Driver Evaluation Error: cannot resolve target for %s -> %s", id->name, dtar->rna_path);
- }
-
- ptr = PointerRNA_NULL;
- *r_prop = NULL;
- *r_index = -1;
-
- driver->flag |= DRIVER_FLAG_INVALID;
- dtar->flag |= DTAR_FLAG_INVALID;
- return false;
- }
-
- *r_ptr = ptr;
- *r_prop = prop;
- *r_index = index;
-
- /* if we're still here, we should be ok... */
- dtar->flag &= ~DTAR_FLAG_INVALID;
- return true;
+ PointerRNA id_ptr;
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ ID *id;
+ int index = -1;
+
+ /* sanity check */
+ if (ELEM(NULL, driver, dtar))
+ return false;
+
+ id = dtar_id_ensure_proxy_from(dtar->id);
+
+ /* error check for missing pointer... */
+ if (id == NULL) {
+ if (G.debug & G_DEBUG) {
+ CLOG_ERROR(&LOG, "driver has an invalid target to use (path = %s)", dtar->rna_path);
+ }
+
+ driver->flag |= DRIVER_FLAG_INVALID;
+ dtar->flag |= DTAR_FLAG_INVALID;
+ return false;
+ }
+
+ /* get RNA-pointer for the ID-block given in target */
+ RNA_id_pointer_create(id, &id_ptr);
+
+ /* get property to read from, and get value as appropriate */
+ if (dtar->rna_path == NULL || dtar->rna_path[0] == '\0') {
+ ptr = PointerRNA_NULL;
+ prop = NULL; /* ok */
+ }
+ else if (RNA_path_resolve_property_full(&id_ptr, dtar->rna_path, &ptr, &prop, &index)) {
+ /* ok */
+ }
+ else {
+ /* path couldn't be resolved */
+ if (G.debug & G_DEBUG) {
+ CLOG_ERROR(&LOG,
+ "Driver Evaluation Error: cannot resolve target for %s -> %s",
+ id->name,
+ dtar->rna_path);
+ }
+
+ ptr = PointerRNA_NULL;
+ *r_prop = NULL;
+ *r_index = -1;
+
+ driver->flag |= DRIVER_FLAG_INVALID;
+ dtar->flag |= DTAR_FLAG_INVALID;
+ return false;
+ }
+
+ *r_ptr = ptr;
+ *r_prop = prop;
+ *r_index = index;
+
+ /* if we're still here, we should be ok... */
+ dtar->flag &= ~DTAR_FLAG_INVALID;
+ return true;
}
static short driver_check_valid_targets(ChannelDriver *driver, DriverVar *dvar)
{
- short valid_targets = 0;
-
- DRIVER_TARGETS_USED_LOOPER_BEGIN(dvar)
- {
- Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
-
- /* check if this target has valid data */
- if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) {
- /* invalid target, so will not have enough targets */
- driver->flag |= DRIVER_FLAG_INVALID;
- dtar->flag |= DTAR_FLAG_INVALID;
- }
- else {
- /* target seems to be OK now... */
- dtar->flag &= ~DTAR_FLAG_INVALID;
- valid_targets++;
- }
- }
- DRIVER_TARGETS_LOOPER_END;
-
- return valid_targets;
+ short valid_targets = 0;
+
+ DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
+ Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
+
+ /* check if this target has valid data */
+ if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) {
+ /* invalid target, so will not have enough targets */
+ driver->flag |= DRIVER_FLAG_INVALID;
+ dtar->flag |= DTAR_FLAG_INVALID;
+ }
+ else {
+ /* target seems to be OK now... */
+ dtar->flag &= ~DTAR_FLAG_INVALID;
+ valid_targets++;
+ }
+ }
+ DRIVER_TARGETS_LOOPER_END;
+
+ return valid_targets;
}
/* ......... */
@@ -1335,323 +1384,329 @@ static short driver_check_valid_targets(ChannelDriver *driver, DriverVar *dvar)
/* evaluate 'single prop' driver variable */
static float dvar_eval_singleProp(ChannelDriver *driver, DriverVar *dvar)
{
- /* just evaluate the first target slot */
- return dtar_get_prop_val(driver, &dvar->targets[0]);
+ /* just evaluate the first target slot */
+ return dtar_get_prop_val(driver, &dvar->targets[0]);
}
/* evaluate 'rotation difference' driver variable */
static float dvar_eval_rotDiff(ChannelDriver *driver, DriverVar *dvar)
{
- short valid_targets = driver_check_valid_targets(driver, dvar);
-
- /* make sure we have enough valid targets to use - all or nothing for now... */
- if (driver_check_valid_targets(driver, dvar) != 2) {
- if (G.debug & G_DEBUG) {
- CLOG_WARN(&LOG, "RotDiff DVar: not enough valid targets (n = %d) (a = %p, b = %p)",
- valid_targets, dvar->targets[0].id, dvar->targets[1].id);
- }
- return 0.0f;
- }
-
- float (*mat[2])[4];
-
- /* NOTE: for now, these are all just worldspace */
- for (int i = 0; i < 2; i++) {
- /* get pointer to loc values to store in */
- DriverTarget *dtar = &dvar->targets[i];
- Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
- bPoseChannel *pchan;
-
- /* after the checks above, the targets should be valid here... */
- BLI_assert((ob != NULL) && (GS(ob->id.name) == ID_OB));
-
- /* try to get posechannel */
- pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
-
- /* check if object or bone */
- if (pchan) {
- /* bone */
- mat[i] = pchan->pose_mat;
- }
- else {
- /* object */
- mat[i] = ob->obmat;
- }
- }
-
- float q1[4], q2[4], quat[4], angle;
-
- /* use the final posed locations */
- mat4_to_quat(q1, mat[0]);
- mat4_to_quat(q2, mat[1]);
-
- invert_qt_normalized(q1);
- mul_qt_qtqt(quat, q1, q2);
- angle = 2.0f * (saacos(quat[0]));
- angle = ABS(angle);
-
- return (angle > (float)M_PI) ? (float)((2.0f * (float)M_PI) - angle) : (float)(angle);
+ short valid_targets = driver_check_valid_targets(driver, dvar);
+
+ /* make sure we have enough valid targets to use - all or nothing for now... */
+ if (driver_check_valid_targets(driver, dvar) != 2) {
+ if (G.debug & G_DEBUG) {
+ CLOG_WARN(&LOG,
+ "RotDiff DVar: not enough valid targets (n = %d) (a = %p, b = %p)",
+ valid_targets,
+ dvar->targets[0].id,
+ dvar->targets[1].id);
+ }
+ return 0.0f;
+ }
+
+ float(*mat[2])[4];
+
+ /* NOTE: for now, these are all just worldspace */
+ for (int i = 0; i < 2; i++) {
+ /* get pointer to loc values to store in */
+ DriverTarget *dtar = &dvar->targets[i];
+ Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
+ bPoseChannel *pchan;
+
+ /* after the checks above, the targets should be valid here... */
+ BLI_assert((ob != NULL) && (GS(ob->id.name) == ID_OB));
+
+ /* try to get posechannel */
+ pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
+
+ /* check if object or bone */
+ if (pchan) {
+ /* bone */
+ mat[i] = pchan->pose_mat;
+ }
+ else {
+ /* object */
+ mat[i] = ob->obmat;
+ }
+ }
+
+ float q1[4], q2[4], quat[4], angle;
+
+ /* use the final posed locations */
+ mat4_to_quat(q1, mat[0]);
+ mat4_to_quat(q2, mat[1]);
+
+ invert_qt_normalized(q1);
+ mul_qt_qtqt(quat, q1, q2);
+ angle = 2.0f * (saacos(quat[0]));
+ angle = ABS(angle);
+
+ return (angle > (float)M_PI) ? (float)((2.0f * (float)M_PI) - angle) : (float)(angle);
}
/* evaluate 'location difference' driver variable */
/* TODO: this needs to take into account space conversions... */
static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar)
{
- float loc1[3] = {0.0f, 0.0f, 0.0f};
- float loc2[3] = {0.0f, 0.0f, 0.0f};
- short valid_targets = driver_check_valid_targets(driver, dvar);
-
- /* make sure we have enough valid targets to use - all or nothing for now... */
- if (valid_targets < dvar->num_targets) {
- if (G.debug & G_DEBUG) {
- CLOG_WARN(&LOG, "LocDiff DVar: not enough valid targets (n = %d) (a = %p, b = %p)",
- valid_targets, dvar->targets[0].id, dvar->targets[1].id);
- }
- return 0.0f;
- }
-
- /* SECOND PASS: get two location values */
- /* NOTE: for now, these are all just worldspace */
- DRIVER_TARGETS_USED_LOOPER_BEGIN(dvar)
- {
- /* get pointer to loc values to store in */
- Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
- bPoseChannel *pchan;
- float tmp_loc[3];
-
- /* after the checks above, the targets should be valid here... */
- BLI_assert((ob != NULL) && (GS(ob->id.name) == ID_OB));
-
- /* try to get posechannel */
- pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
-
- /* check if object or bone */
- if (pchan) {
- /* bone */
- if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
- if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
- float mat[4][4];
-
- /* extract transform just like how the constraints do it! */
- copy_m4_m4(mat, pchan->pose_mat);
- BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false);
-
- /* ... and from that, we get our transform */
- copy_v3_v3(tmp_loc, mat[3]);
- }
- else {
- /* transform space (use transform values directly) */
- copy_v3_v3(tmp_loc, pchan->loc);
- }
- }
- else {
- /* convert to worldspace */
- copy_v3_v3(tmp_loc, pchan->pose_head);
- mul_m4_v3(ob->obmat, tmp_loc);
- }
- }
- else {
- /* object */
- if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
- if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
- /* XXX: this should practically be the same as transform space... */
- float mat[4][4];
-
- /* extract transform just like how the constraints do it! */
- copy_m4_m4(mat, ob->obmat);
- BKE_constraint_mat_convertspace(ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false);
-
- /* ... and from that, we get our transform */
- copy_v3_v3(tmp_loc, mat[3]);
- }
- else {
- /* transform space (use transform values directly) */
- copy_v3_v3(tmp_loc, ob->loc);
- }
- }
- else {
- /* worldspace */
- copy_v3_v3(tmp_loc, ob->obmat[3]);
- }
- }
-
- /* copy the location to the right place */
- if (tarIndex) {
- copy_v3_v3(loc2, tmp_loc);
- }
- else {
- copy_v3_v3(loc1, tmp_loc);
- }
- }
- DRIVER_TARGETS_LOOPER_END;
-
-
- /* if we're still here, there should now be two targets to use,
- * so just take the length of the vector between these points
- */
- return len_v3v3(loc1, loc2);
+ float loc1[3] = {0.0f, 0.0f, 0.0f};
+ float loc2[3] = {0.0f, 0.0f, 0.0f};
+ short valid_targets = driver_check_valid_targets(driver, dvar);
+
+ /* make sure we have enough valid targets to use - all or nothing for now... */
+ if (valid_targets < dvar->num_targets) {
+ if (G.debug & G_DEBUG) {
+ CLOG_WARN(&LOG,
+ "LocDiff DVar: not enough valid targets (n = %d) (a = %p, b = %p)",
+ valid_targets,
+ dvar->targets[0].id,
+ dvar->targets[1].id);
+ }
+ return 0.0f;
+ }
+
+ /* SECOND PASS: get two location values */
+ /* NOTE: for now, these are all just worldspace */
+ DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
+ /* get pointer to loc values to store in */
+ Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
+ bPoseChannel *pchan;
+ float tmp_loc[3];
+
+ /* after the checks above, the targets should be valid here... */
+ BLI_assert((ob != NULL) && (GS(ob->id.name) == ID_OB));
+
+ /* try to get posechannel */
+ pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
+
+ /* check if object or bone */
+ if (pchan) {
+ /* bone */
+ if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
+ if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
+ float mat[4][4];
+
+ /* extract transform just like how the constraints do it! */
+ copy_m4_m4(mat, pchan->pose_mat);
+ BKE_constraint_mat_convertspace(
+ ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false);
+
+ /* ... and from that, we get our transform */
+ copy_v3_v3(tmp_loc, mat[3]);
+ }
+ else {
+ /* transform space (use transform values directly) */
+ copy_v3_v3(tmp_loc, pchan->loc);
+ }
+ }
+ else {
+ /* convert to worldspace */
+ copy_v3_v3(tmp_loc, pchan->pose_head);
+ mul_m4_v3(ob->obmat, tmp_loc);
+ }
+ }
+ else {
+ /* object */
+ if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
+ if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
+ /* XXX: this should practically be the same as transform space... */
+ float mat[4][4];
+
+ /* extract transform just like how the constraints do it! */
+ copy_m4_m4(mat, ob->obmat);
+ BKE_constraint_mat_convertspace(
+ ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false);
+
+ /* ... and from that, we get our transform */
+ copy_v3_v3(tmp_loc, mat[3]);
+ }
+ else {
+ /* transform space (use transform values directly) */
+ copy_v3_v3(tmp_loc, ob->loc);
+ }
+ }
+ else {
+ /* worldspace */
+ copy_v3_v3(tmp_loc, ob->obmat[3]);
+ }
+ }
+
+ /* copy the location to the right place */
+ if (tarIndex) {
+ copy_v3_v3(loc2, tmp_loc);
+ }
+ else {
+ copy_v3_v3(loc1, tmp_loc);
+ }
+ }
+ DRIVER_TARGETS_LOOPER_END;
+
+ /* if we're still here, there should now be two targets to use,
+ * so just take the length of the vector between these points
+ */
+ return len_v3v3(loc1, loc2);
}
/* evaluate 'transform channel' driver variable */
static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
{
- DriverTarget *dtar = &dvar->targets[0];
- Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
- bPoseChannel *pchan;
- float mat[4][4];
- float oldEul[3] = {0.0f, 0.0f, 0.0f};
- bool use_eulers = false;
- short rot_order = ROT_MODE_EUL;
-
- /* check if this target has valid data */
- if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) {
- /* invalid target, so will not have enough targets */
- driver->flag |= DRIVER_FLAG_INVALID;
- dtar->flag |= DTAR_FLAG_INVALID;
- return 0.0f;
- }
- else {
- /* target should be valid now */
- dtar->flag &= ~DTAR_FLAG_INVALID;
- }
-
- /* try to get posechannel */
- pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
-
- /* check if object or bone, and get transform matrix accordingly
- * - "useEulers" code is used to prevent the problems associated with non-uniqueness
- * of euler decomposition from matrices [#20870]
- * - localspace is for [#21384], where parent results are not wanted
- * but local-consts is for all the common "corrective-shapes-for-limbs" situations
- */
- if (pchan) {
- /* bone */
- if (pchan->rotmode > 0) {
- copy_v3_v3(oldEul, pchan->eul);
- rot_order = pchan->rotmode;
- use_eulers = true;
- }
-
- if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
- if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
- /* just like how the constraints do it! */
- copy_m4_m4(mat, pchan->pose_mat);
- BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false);
- }
- else {
- /* specially calculate local matrix, since chan_mat is not valid
- * since it stores delta transform of pose_mat so that deforms work
- * so it cannot be used here for "transform" space
- */
- BKE_pchan_to_mat4(pchan, mat);
- }
- }
- else {
- /* worldspace matrix */
- mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat);
- }
- }
- else {
- /* object */
- if (ob->rotmode > 0) {
- copy_v3_v3(oldEul, ob->rot);
- rot_order = ob->rotmode;
- use_eulers = true;
- }
-
- if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
- if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
- /* just like how the constraints do it! */
- copy_m4_m4(mat, ob->obmat);
- BKE_constraint_mat_convertspace(ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false);
- }
- else {
- /* transforms to matrix */
- BKE_object_to_mat4(ob, mat);
- }
- }
- else {
- /* worldspace matrix - just the good-old one */
- copy_m4_m4(mat, ob->obmat);
- }
- }
-
- /* check which transform */
- if (dtar->transChan >= MAX_DTAR_TRANSCHAN_TYPES) {
- /* not valid channel */
- return 0.0f;
- }
- else if (dtar->transChan >= DTAR_TRANSCHAN_SCALEX) {
- /* Extract scale, and choose the right axis,
- * inline 'mat4_to_size'. */
- return len_v3(mat[dtar->transChan - DTAR_TRANSCHAN_SCALEX]);
- }
- else if (dtar->transChan >= DTAR_TRANSCHAN_ROTX) {
- /* extract rotation as eulers (if needed)
- * - definitely if rotation order isn't eulers already
- * - if eulers, then we have 2 options:
- * a) decompose transform matrix as required, then try to make eulers from
- * there compatible with original values
- * b) [NOT USED] directly use the original values (no decomposition)
- * - only an option for "transform space", if quality is really bad with a)
- */
- float eul[3];
-
- mat4_to_eulO(eul, rot_order, mat);
-
- if (use_eulers) {
- compatible_eul(eul, oldEul);
- }
-
- return eul[dtar->transChan - DTAR_TRANSCHAN_ROTX];
- }
- else {
- /* extract location and choose right axis */
- return mat[3][dtar->transChan];
- }
+ DriverTarget *dtar = &dvar->targets[0];
+ Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
+ bPoseChannel *pchan;
+ float mat[4][4];
+ float oldEul[3] = {0.0f, 0.0f, 0.0f};
+ bool use_eulers = false;
+ short rot_order = ROT_MODE_EUL;
+
+ /* check if this target has valid data */
+ if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) {
+ /* invalid target, so will not have enough targets */
+ driver->flag |= DRIVER_FLAG_INVALID;
+ dtar->flag |= DTAR_FLAG_INVALID;
+ return 0.0f;
+ }
+ else {
+ /* target should be valid now */
+ dtar->flag &= ~DTAR_FLAG_INVALID;
+ }
+
+ /* try to get posechannel */
+ pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
+
+ /* check if object or bone, and get transform matrix accordingly
+ * - "useEulers" code is used to prevent the problems associated with non-uniqueness
+ * of euler decomposition from matrices [#20870]
+ * - localspace is for [#21384], where parent results are not wanted
+ * but local-consts is for all the common "corrective-shapes-for-limbs" situations
+ */
+ if (pchan) {
+ /* bone */
+ if (pchan->rotmode > 0) {
+ copy_v3_v3(oldEul, pchan->eul);
+ rot_order = pchan->rotmode;
+ use_eulers = true;
+ }
+
+ if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
+ if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
+ /* just like how the constraints do it! */
+ copy_m4_m4(mat, pchan->pose_mat);
+ BKE_constraint_mat_convertspace(
+ ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false);
+ }
+ else {
+ /* specially calculate local matrix, since chan_mat is not valid
+ * since it stores delta transform of pose_mat so that deforms work
+ * so it cannot be used here for "transform" space
+ */
+ BKE_pchan_to_mat4(pchan, mat);
+ }
+ }
+ else {
+ /* worldspace matrix */
+ mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat);
+ }
+ }
+ else {
+ /* object */
+ if (ob->rotmode > 0) {
+ copy_v3_v3(oldEul, ob->rot);
+ rot_order = ob->rotmode;
+ use_eulers = true;
+ }
+
+ if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
+ if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
+ /* just like how the constraints do it! */
+ copy_m4_m4(mat, ob->obmat);
+ BKE_constraint_mat_convertspace(
+ ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false);
+ }
+ else {
+ /* transforms to matrix */
+ BKE_object_to_mat4(ob, mat);
+ }
+ }
+ else {
+ /* worldspace matrix - just the good-old one */
+ copy_m4_m4(mat, ob->obmat);
+ }
+ }
+
+ /* check which transform */
+ if (dtar->transChan >= MAX_DTAR_TRANSCHAN_TYPES) {
+ /* not valid channel */
+ return 0.0f;
+ }
+ else if (dtar->transChan >= DTAR_TRANSCHAN_SCALEX) {
+ /* Extract scale, and choose the right axis,
+ * inline 'mat4_to_size'. */
+ return len_v3(mat[dtar->transChan - DTAR_TRANSCHAN_SCALEX]);
+ }
+ else if (dtar->transChan >= DTAR_TRANSCHAN_ROTX) {
+ /* extract rotation as eulers (if needed)
+ * - definitely if rotation order isn't eulers already
+ * - if eulers, then we have 2 options:
+ * a) decompose transform matrix as required, then try to make eulers from
+ * there compatible with original values
+ * b) [NOT USED] directly use the original values (no decomposition)
+ * - only an option for "transform space", if quality is really bad with a)
+ */
+ float eul[3];
+
+ mat4_to_eulO(eul, rot_order, mat);
+
+ if (use_eulers) {
+ compatible_eul(eul, oldEul);
+ }
+
+ return eul[dtar->transChan - DTAR_TRANSCHAN_ROTX];
+ }
+ else {
+ /* extract location and choose right axis */
+ return mat[3][dtar->transChan];
+ }
}
/* ......... */
/* Table of Driver Varaiable Type Info Data */
static DriverVarTypeInfo dvar_types[MAX_DVAR_TYPES] = {
- BEGIN_DVAR_TYPEDEF(DVAR_TYPE_SINGLE_PROP)
- dvar_eval_singleProp, /* eval callback */
- 1, /* number of targets used */
- {"Property"}, /* UI names for targets */
- {0} /* flags */
- END_DVAR_TYPEDEF,
-
- BEGIN_DVAR_TYPEDEF(DVAR_TYPE_ROT_DIFF)
- dvar_eval_rotDiff, /* eval callback */
- 2, /* number of targets used */
- {"Object/Bone 1", "Object/Bone 2"}, /* UI names for targets */
- {DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY, DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */
- END_DVAR_TYPEDEF,
-
- BEGIN_DVAR_TYPEDEF(DVAR_TYPE_LOC_DIFF)
- dvar_eval_locDiff, /* eval callback */
- 2, /* number of targets used */
- {"Object/Bone 1", "Object/Bone 2"}, /* UI names for targets */
- {DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY, DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */
- END_DVAR_TYPEDEF,
-
- BEGIN_DVAR_TYPEDEF(DVAR_TYPE_TRANSFORM_CHAN)
- dvar_eval_transChan, /* eval callback */
- 1, /* number of targets used */
- {"Object/Bone"}, /* UI names for targets */
- {DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */
- END_DVAR_TYPEDEF,
+ BEGIN_DVAR_TYPEDEF(DVAR_TYPE_SINGLE_PROP) dvar_eval_singleProp, /* eval callback */
+ 1, /* number of targets used */
+ {"Property"}, /* UI names for targets */
+ {0} /* flags */
+ END_DVAR_TYPEDEF,
+
+ BEGIN_DVAR_TYPEDEF(DVAR_TYPE_ROT_DIFF) dvar_eval_rotDiff, /* eval callback */
+ 2, /* number of targets used */
+ {"Object/Bone 1", "Object/Bone 2"}, /* UI names for targets */
+ {DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY,
+ DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */
+ END_DVAR_TYPEDEF,
+
+ BEGIN_DVAR_TYPEDEF(DVAR_TYPE_LOC_DIFF) dvar_eval_locDiff, /* eval callback */
+ 2, /* number of targets used */
+ {"Object/Bone 1", "Object/Bone 2"}, /* UI names for targets */
+ {DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY,
+ DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */
+ END_DVAR_TYPEDEF,
+
+ BEGIN_DVAR_TYPEDEF(DVAR_TYPE_TRANSFORM_CHAN) dvar_eval_transChan, /* eval callback */
+ 1, /* number of targets used */
+ {"Object/Bone"}, /* UI names for targets */
+ {DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */
+ END_DVAR_TYPEDEF,
};
/* Get driver variable typeinfo */
static const DriverVarTypeInfo *get_dvar_typeinfo(int type)
{
- /* check if valid type */
- if ((type >= 0) && (type < MAX_DVAR_TYPES))
- return &dvar_types[type];
- else
- return NULL;
+ /* check if valid type */
+ if ((type >= 0) && (type < MAX_DVAR_TYPES))
+ return &dvar_types[type];
+ else
+ return NULL;
}
/* Driver API --------------------------------- */
@@ -1659,345 +1714,355 @@ static const DriverVarTypeInfo *get_dvar_typeinfo(int type)
/* Perform actual freeing driver variable and remove it from the given list */
void driver_free_variable(ListBase *variables, DriverVar *dvar)
{
- /* sanity checks */
- if (dvar == NULL)
- return;
-
- /* free target vars
- * - need to go over all of them, not just up to the ones that are used
- * currently, since there may be some lingering RNA paths from
- * previous users needing freeing
- */
- DRIVER_TARGETS_LOOPER_BEGIN(dvar)
- {
- /* free RNA path if applicable */
- if (dtar->rna_path)
- MEM_freeN(dtar->rna_path);
- }
- DRIVER_TARGETS_LOOPER_END;
-
- /* remove the variable from the driver */
- BLI_freelinkN(variables, dvar);
+ /* sanity checks */
+ if (dvar == NULL)
+ return;
+
+ /* free target vars
+ * - need to go over all of them, not just up to the ones that are used
+ * currently, since there may be some lingering RNA paths from
+ * previous users needing freeing
+ */
+ DRIVER_TARGETS_LOOPER_BEGIN (dvar) {
+ /* free RNA path if applicable */
+ if (dtar->rna_path)
+ MEM_freeN(dtar->rna_path);
+ }
+ DRIVER_TARGETS_LOOPER_END;
+
+ /* remove the variable from the driver */
+ BLI_freelinkN(variables, dvar);
}
/* Free the driver variable and do extra updates */
void driver_free_variable_ex(ChannelDriver *driver, DriverVar *dvar)
{
- /* remove and free the driver variable */
- driver_free_variable(&driver->variables, dvar);
+ /* remove and free the driver variable */
+ driver_free_variable(&driver->variables, dvar);
- /* since driver variables are cached, the expression needs re-compiling too */
- BKE_driver_invalidate_expression(driver, false, true);
+ /* since driver variables are cached, the expression needs re-compiling too */
+ BKE_driver_invalidate_expression(driver, false, true);
}
/* Copy driver variables from src_vars list to dst_vars list */
void driver_variables_copy(ListBase *dst_vars, const ListBase *src_vars)
{
- BLI_assert(BLI_listbase_is_empty(dst_vars));
- BLI_duplicatelist(dst_vars, src_vars);
-
- for (DriverVar *dvar = dst_vars->first; dvar; dvar = dvar->next) {
- /* need to go over all targets so that we don't leave any dangling paths */
- DRIVER_TARGETS_LOOPER_BEGIN(dvar)
- {
- /* make a copy of target's rna path if available */
- if (dtar->rna_path)
- dtar->rna_path = MEM_dupallocN(dtar->rna_path);
- }
- DRIVER_TARGETS_LOOPER_END;
- }
+ BLI_assert(BLI_listbase_is_empty(dst_vars));
+ BLI_duplicatelist(dst_vars, src_vars);
+
+ for (DriverVar *dvar = dst_vars->first; dvar; dvar = dvar->next) {
+ /* need to go over all targets so that we don't leave any dangling paths */
+ DRIVER_TARGETS_LOOPER_BEGIN (dvar) {
+ /* make a copy of target's rna path if available */
+ if (dtar->rna_path)
+ dtar->rna_path = MEM_dupallocN(dtar->rna_path);
+ }
+ DRIVER_TARGETS_LOOPER_END;
+ }
}
/* Change the type of driver variable */
void driver_change_variable_type(DriverVar *dvar, int type)
{
- const DriverVarTypeInfo *dvti = get_dvar_typeinfo(type);
-
- /* sanity check */
- if (ELEM(NULL, dvar, dvti))
- return;
-
- /* set the new settings */
- dvar->type = type;
- dvar->num_targets = dvti->num_targets;
-
- /* make changes to the targets based on the defines for these types
- * NOTE: only need to make sure the ones we're using here are valid...
- */
- DRIVER_TARGETS_USED_LOOPER_BEGIN(dvar)
- {
- short flags = dvti->target_flags[tarIndex];
-
- /* store the flags */
- dtar->flag = flags;
-
- /* object ID types only, or idtype not yet initialized */
- if ((flags & DTAR_FLAG_ID_OB_ONLY) || (dtar->idtype == 0))
- dtar->idtype = ID_OB;
- }
- DRIVER_TARGETS_LOOPER_END;
+ const DriverVarTypeInfo *dvti = get_dvar_typeinfo(type);
+
+ /* sanity check */
+ if (ELEM(NULL, dvar, dvti))
+ return;
+
+ /* set the new settings */
+ dvar->type = type;
+ dvar->num_targets = dvti->num_targets;
+
+ /* make changes to the targets based on the defines for these types
+ * NOTE: only need to make sure the ones we're using here are valid...
+ */
+ DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
+ short flags = dvti->target_flags[tarIndex];
+
+ /* store the flags */
+ dtar->flag = flags;
+
+ /* object ID types only, or idtype not yet initialized */
+ if ((flags & DTAR_FLAG_ID_OB_ONLY) || (dtar->idtype == 0))
+ dtar->idtype = ID_OB;
+ }
+ DRIVER_TARGETS_LOOPER_END;
}
/* Validate driver name (after being renamed) */
void driver_variable_name_validate(DriverVar *dvar)
{
- /* Special character blacklist */
- const char special_char_blacklist[] = {
- '~', '`', '!', '@', '#', '$', '%', '^', '&', '*', '+', '=', '-',
- '/', '\\', '?', ':', ';', '<', '>', '{', '}', '[', ']', '|',
- ' ', '.', '\t', '\n', '\r',
- };
-
- /* sanity checks */
- if (dvar == NULL)
- return;
-
- /* clear all invalid-name flags */
- dvar->flag &= ~DVAR_ALL_INVALID_FLAGS;
-
- /* 0) Zero-length identifiers are not allowed */
- if (dvar->name[0] == '\0') {
- dvar->flag |= DVAR_FLAG_INVALID_EMPTY;
- }
-
- /* 1) Must start with a letter */
- /* XXX: We assume that valid unicode letters in other languages are ok too, hence the blacklisting */
- if (IN_RANGE_INCL(dvar->name[0], '0', '9')) {
- dvar->flag |= DVAR_FLAG_INVALID_START_NUM;
- }
- else if (dvar->name[0] == '_') {
- /* NOTE: We don't allow names to start with underscores (i.e. it helps when ruling out security risks) */
- dvar->flag |= DVAR_FLAG_INVALID_START_CHAR;
- }
-
- /* 2) Must not contain invalid stuff in the middle of the string */
- if (strchr(dvar->name, ' ')) {
- dvar->flag |= DVAR_FLAG_INVALID_HAS_SPACE;
- }
- if (strchr(dvar->name, '.')) {
- dvar->flag |= DVAR_FLAG_INVALID_HAS_DOT;
- }
-
- /* 3) Check for special characters - Either at start, or in the middle */
- for (int i = 0; i < sizeof(special_char_blacklist); i++) {
- char *match = strchr(dvar->name, special_char_blacklist[i]);
-
- if (match == dvar->name)
- dvar->flag |= DVAR_FLAG_INVALID_START_CHAR;
- else if (match != NULL)
- dvar->flag |= DVAR_FLAG_INVALID_HAS_SPECIAL;
- }
-
- /* 4) Check if the name is a reserved keyword
- * NOTE: These won't confuse Python, but it will be impossible to use the variable
- * in an expression without Python misinterpreting what these are for
- */
+ /* Special character blacklist */
+ const char special_char_blacklist[] = {
+ '~', '`', '!', '@', '#', '$', '%', '^', '&', '*', '+', '=', '-', '/', '\\',
+ '?', ':', ';', '<', '>', '{', '}', '[', ']', '|', ' ', '.', '\t', '\n', '\r',
+ };
+
+ /* sanity checks */
+ if (dvar == NULL)
+ return;
+
+ /* clear all invalid-name flags */
+ dvar->flag &= ~DVAR_ALL_INVALID_FLAGS;
+
+ /* 0) Zero-length identifiers are not allowed */
+ if (dvar->name[0] == '\0') {
+ dvar->flag |= DVAR_FLAG_INVALID_EMPTY;
+ }
+
+ /* 1) Must start with a letter */
+ /* XXX: We assume that valid unicode letters in other languages are ok too, hence the blacklisting */
+ if (IN_RANGE_INCL(dvar->name[0], '0', '9')) {
+ dvar->flag |= DVAR_FLAG_INVALID_START_NUM;
+ }
+ else if (dvar->name[0] == '_') {
+ /* NOTE: We don't allow names to start with underscores (i.e. it helps when ruling out security risks) */
+ dvar->flag |= DVAR_FLAG_INVALID_START_CHAR;
+ }
+
+ /* 2) Must not contain invalid stuff in the middle of the string */
+ if (strchr(dvar->name, ' ')) {
+ dvar->flag |= DVAR_FLAG_INVALID_HAS_SPACE;
+ }
+ if (strchr(dvar->name, '.')) {
+ dvar->flag |= DVAR_FLAG_INVALID_HAS_DOT;
+ }
+
+ /* 3) Check for special characters - Either at start, or in the middle */
+ for (int i = 0; i < sizeof(special_char_blacklist); i++) {
+ char *match = strchr(dvar->name, special_char_blacklist[i]);
+
+ if (match == dvar->name)
+ dvar->flag |= DVAR_FLAG_INVALID_START_CHAR;
+ else if (match != NULL)
+ dvar->flag |= DVAR_FLAG_INVALID_HAS_SPECIAL;
+ }
+
+ /* 4) Check if the name is a reserved keyword
+ * NOTE: These won't confuse Python, but it will be impossible to use the variable
+ * in an expression without Python misinterpreting what these are for
+ */
#ifdef WITH_PYTHON
- if (BPY_string_is_keyword(dvar->name)) {
- dvar->flag |= DVAR_FLAG_INVALID_PY_KEYWORD;
- }
+ if (BPY_string_is_keyword(dvar->name)) {
+ dvar->flag |= DVAR_FLAG_INVALID_PY_KEYWORD;
+ }
#endif
- /* If any these conditions match, the name is invalid */
- if (dvar->flag & DVAR_ALL_INVALID_FLAGS)
- dvar->flag |= DVAR_FLAG_INVALID_NAME;
+ /* If any these conditions match, the name is invalid */
+ if (dvar->flag & DVAR_ALL_INVALID_FLAGS)
+ dvar->flag |= DVAR_FLAG_INVALID_NAME;
}
/* Add a new driver variable */
DriverVar *driver_add_new_variable(ChannelDriver *driver)
{
- DriverVar *dvar;
+ DriverVar *dvar;
- /* sanity checks */
- if (driver == NULL)
- return NULL;
+ /* sanity checks */
+ if (driver == NULL)
+ return NULL;
- /* make a new variable */
- dvar = MEM_callocN(sizeof(DriverVar), "DriverVar");
- BLI_addtail(&driver->variables, dvar);
+ /* make a new variable */
+ dvar = MEM_callocN(sizeof(DriverVar), "DriverVar");
+ BLI_addtail(&driver->variables, dvar);
- /* give the variable a 'unique' name */
- strcpy(dvar->name, CTX_DATA_(BLT_I18NCONTEXT_ID_ACTION, "var"));
- BLI_uniquename(&driver->variables, dvar, CTX_DATA_(BLT_I18NCONTEXT_ID_ACTION, "var"), '_',
- offsetof(DriverVar, name), sizeof(dvar->name));
+ /* give the variable a 'unique' name */
+ strcpy(dvar->name, CTX_DATA_(BLT_I18NCONTEXT_ID_ACTION, "var"));
+ BLI_uniquename(&driver->variables,
+ dvar,
+ CTX_DATA_(BLT_I18NCONTEXT_ID_ACTION, "var"),
+ '_',
+ offsetof(DriverVar, name),
+ sizeof(dvar->name));
- /* set the default type to 'single prop' */
- driver_change_variable_type(dvar, DVAR_TYPE_SINGLE_PROP);
+ /* set the default type to 'single prop' */
+ driver_change_variable_type(dvar, DVAR_TYPE_SINGLE_PROP);
- /* since driver variables are cached, the expression needs re-compiling too */
- BKE_driver_invalidate_expression(driver, false, true);
+ /* since driver variables are cached, the expression needs re-compiling too */
+ BKE_driver_invalidate_expression(driver, false, true);
- /* return the target */
- return dvar;
+ /* return the target */
+ return dvar;
}
/* This frees the driver itself */
void fcurve_free_driver(FCurve *fcu)
{
- ChannelDriver *driver;
- DriverVar *dvar, *dvarn;
+ ChannelDriver *driver;
+ DriverVar *dvar, *dvarn;
- /* sanity checks */
- if (ELEM(NULL, fcu, fcu->driver))
- return;
- driver = fcu->driver;
+ /* sanity checks */
+ if (ELEM(NULL, fcu, fcu->driver))
+ return;
+ driver = fcu->driver;
- /* free driver targets */
- for (dvar = driver->variables.first; dvar; dvar = dvarn) {
- dvarn = dvar->next;
- driver_free_variable_ex(driver, dvar);
- }
+ /* free driver targets */
+ for (dvar = driver->variables.first; dvar; dvar = dvarn) {
+ dvarn = dvar->next;
+ driver_free_variable_ex(driver, dvar);
+ }
#ifdef WITH_PYTHON
- /* free compiled driver expression */
- if (driver->expr_comp)
- BPY_DECREF(driver->expr_comp);
+ /* free compiled driver expression */
+ if (driver->expr_comp)
+ BPY_DECREF(driver->expr_comp);
#endif
- BLI_expr_pylike_free(driver->expr_simple);
+ BLI_expr_pylike_free(driver->expr_simple);
- /* free driver itself, then set F-Curve's point to this to NULL (as the curve may still be used) */
- MEM_freeN(driver);
- fcu->driver = NULL;
+ /* free driver itself, then set F-Curve's point to this to NULL (as the curve may still be used) */
+ MEM_freeN(driver);
+ fcu->driver = NULL;
}
/* This makes a copy of the given driver */
ChannelDriver *fcurve_copy_driver(const ChannelDriver *driver)
{
- ChannelDriver *ndriver;
+ ChannelDriver *ndriver;
- /* sanity checks */
- if (driver == NULL)
- return NULL;
+ /* sanity checks */
+ if (driver == NULL)
+ return NULL;
- /* copy all data */
- ndriver = MEM_dupallocN(driver);
- ndriver->expr_comp = NULL;
- ndriver->expr_simple = NULL;
+ /* copy all data */
+ ndriver = MEM_dupallocN(driver);
+ ndriver->expr_comp = NULL;
+ ndriver->expr_simple = NULL;
- /* copy variables */
- BLI_listbase_clear(&ndriver->variables); /* to get rid of refs to non-copied data (that's still used on original) */
- driver_variables_copy(&ndriver->variables, &driver->variables);
+ /* copy variables */
+ BLI_listbase_clear(
+ &ndriver
+ ->variables); /* to get rid of refs to non-copied data (that's still used on original) */
+ driver_variables_copy(&ndriver->variables, &driver->variables);
- /* return the new driver */
- return ndriver;
+ /* return the new driver */
+ return ndriver;
}
/* Driver Expression Evaluation --------------- */
static ExprPyLike_Parsed *driver_compile_simple_expr_impl(ChannelDriver *driver)
{
- /* Prepare parameter names. */
- int names_len = BLI_listbase_count(&driver->variables);
- const char **names = BLI_array_alloca(names, names_len + 1);
- int i = 0;
+ /* Prepare parameter names. */
+ int names_len = BLI_listbase_count(&driver->variables);
+ const char **names = BLI_array_alloca(names, names_len + 1);
+ int i = 0;
- names[i++] = "frame";
+ names[i++] = "frame";
- for (DriverVar *dvar = driver->variables.first; dvar; dvar = dvar->next) {
- names[i++] = dvar->name;
- }
+ for (DriverVar *dvar = driver->variables.first; dvar; dvar = dvar->next) {
+ names[i++] = dvar->name;
+ }
- return BLI_expr_pylike_parse(driver->expression, names, names_len + 1);
+ return BLI_expr_pylike_parse(driver->expression, names, names_len + 1);
}
-static bool driver_evaluate_simple_expr(ChannelDriver *driver, ExprPyLike_Parsed *expr, float *result, float time)
+static bool driver_evaluate_simple_expr(ChannelDriver *driver,
+ ExprPyLike_Parsed *expr,
+ float *result,
+ float time)
{
- /* Prepare parameter values. */
- int vars_len = BLI_listbase_count(&driver->variables);
- double *vars = BLI_array_alloca(vars, vars_len + 1);
- int i = 0;
-
- vars[i++] = time;
-
- for (DriverVar *dvar = driver->variables.first; dvar; dvar = dvar->next) {
- vars[i++] = driver_get_variable_value(driver, dvar);
- }
-
- /* Evaluate expression. */
- double result_val;
- eExprPyLike_EvalStatus status = BLI_expr_pylike_eval(expr, vars, vars_len + 1, &result_val);
- const char *message;
-
- switch (status) {
- case EXPR_PYLIKE_SUCCESS:
- if (isfinite(result_val)) {
- *result = (float)result_val;
- }
- return true;
-
- case EXPR_PYLIKE_DIV_BY_ZERO:
- case EXPR_PYLIKE_MATH_ERROR:
- message = (status == EXPR_PYLIKE_DIV_BY_ZERO) ? "Division by Zero" : "Math Domain Error";
- CLOG_ERROR(&LOG, "%s in Driver: '%s'", message, driver->expression);
-
- driver->flag |= DRIVER_FLAG_INVALID;
- return true;
-
- default:
- /* arriving here means a bug, not user error */
- CLOG_ERROR(&LOG, "simple driver expression evaluation failed: '%s'", driver->expression);
- return false;
- }
+ /* Prepare parameter values. */
+ int vars_len = BLI_listbase_count(&driver->variables);
+ double *vars = BLI_array_alloca(vars, vars_len + 1);
+ int i = 0;
+
+ vars[i++] = time;
+
+ for (DriverVar *dvar = driver->variables.first; dvar; dvar = dvar->next) {
+ vars[i++] = driver_get_variable_value(driver, dvar);
+ }
+
+ /* Evaluate expression. */
+ double result_val;
+ eExprPyLike_EvalStatus status = BLI_expr_pylike_eval(expr, vars, vars_len + 1, &result_val);
+ const char *message;
+
+ switch (status) {
+ case EXPR_PYLIKE_SUCCESS:
+ if (isfinite(result_val)) {
+ *result = (float)result_val;
+ }
+ return true;
+
+ case EXPR_PYLIKE_DIV_BY_ZERO:
+ case EXPR_PYLIKE_MATH_ERROR:
+ message = (status == EXPR_PYLIKE_DIV_BY_ZERO) ? "Division by Zero" : "Math Domain Error";
+ CLOG_ERROR(&LOG, "%s in Driver: '%s'", message, driver->expression);
+
+ driver->flag |= DRIVER_FLAG_INVALID;
+ return true;
+
+ default:
+ /* arriving here means a bug, not user error */
+ CLOG_ERROR(&LOG, "simple driver expression evaluation failed: '%s'", driver->expression);
+ return false;
+ }
}
/* Compile and cache the driver expression if necessary, with thread safety. */
static bool driver_compile_simple_expr(ChannelDriver *driver)
{
- if (driver->expr_simple != NULL) {
- return true;
- }
+ if (driver->expr_simple != NULL) {
+ return true;
+ }
- if (driver->type != DRIVER_TYPE_PYTHON) {
- return false;
- }
+ if (driver->type != DRIVER_TYPE_PYTHON) {
+ return false;
+ }
- /* It's safe to parse in multiple threads; at worst it'll
- * waste some effort, but in return avoids mutex contention. */
- ExprPyLike_Parsed *expr = driver_compile_simple_expr_impl(driver);
+ /* It's safe to parse in multiple threads; at worst it'll
+ * waste some effort, but in return avoids mutex contention. */
+ ExprPyLike_Parsed *expr = driver_compile_simple_expr_impl(driver);
- /* Store the result if the field is still NULL, or discard
- * it if another thread got here first. */
- if (atomic_cas_ptr((void **)&driver->expr_simple, NULL, expr) != NULL) {
- BLI_expr_pylike_free(expr);
- }
+ /* Store the result if the field is still NULL, or discard
+ * it if another thread got here first. */
+ if (atomic_cas_ptr((void **)&driver->expr_simple, NULL, expr) != NULL) {
+ BLI_expr_pylike_free(expr);
+ }
- return true;
+ return true;
}
/* Try using the simple expression evaluator to compute the result of the driver.
* On success, stores the result and returns true; on failure result is set to 0. */
-static bool driver_try_evaluate_simple_expr(ChannelDriver *driver, ChannelDriver *driver_orig, float *result, float time)
+static bool driver_try_evaluate_simple_expr(ChannelDriver *driver,
+ ChannelDriver *driver_orig,
+ float *result,
+ float time)
{
- *result = 0.0f;
+ *result = 0.0f;
- return driver_compile_simple_expr(driver_orig) &&
- BLI_expr_pylike_is_valid(driver_orig->expr_simple) &&
- driver_evaluate_simple_expr(driver, driver_orig->expr_simple, result, time);
+ return driver_compile_simple_expr(driver_orig) &&
+ BLI_expr_pylike_is_valid(driver_orig->expr_simple) &&
+ driver_evaluate_simple_expr(driver, driver_orig->expr_simple, result, time);
}
/* Check if the expression in the driver conforms to the simple subset. */
bool BKE_driver_has_simple_expression(ChannelDriver *driver)
{
- return driver_compile_simple_expr(driver) && BLI_expr_pylike_is_valid(driver->expr_simple);
+ return driver_compile_simple_expr(driver) && BLI_expr_pylike_is_valid(driver->expr_simple);
}
/* Reset cached compiled expression data */
-void BKE_driver_invalidate_expression(ChannelDriver *driver, bool expr_changed, bool varname_changed)
+void BKE_driver_invalidate_expression(ChannelDriver *driver,
+ bool expr_changed,
+ bool varname_changed)
{
- if (expr_changed || varname_changed) {
- BLI_expr_pylike_free(driver->expr_simple);
- driver->expr_simple = NULL;
- }
+ if (expr_changed || varname_changed) {
+ BLI_expr_pylike_free(driver->expr_simple);
+ driver->expr_simple = NULL;
+ }
#ifdef WITH_PYTHON
- if (expr_changed) {
- driver->flag |= DRIVER_FLAG_RECOMPILE;
- }
+ if (expr_changed) {
+ driver->flag |= DRIVER_FLAG_RECOMPILE;
+ }
- if (varname_changed) {
- driver->flag |= DRIVER_FLAG_RENAMEVAR;
- }
+ if (varname_changed) {
+ driver->flag |= DRIVER_FLAG_RENAMEVAR;
+ }
#endif
}
@@ -2006,24 +2071,24 @@ void BKE_driver_invalidate_expression(ChannelDriver *driver, bool expr_changed,
/* Evaluate a Driver Variable to get a value that contributes to the final */
float driver_get_variable_value(ChannelDriver *driver, DriverVar *dvar)
{
- const DriverVarTypeInfo *dvti;
+ const DriverVarTypeInfo *dvti;
- /* sanity check */
- if (ELEM(NULL, driver, dvar))
- return 0.0f;
+ /* sanity check */
+ if (ELEM(NULL, driver, dvar))
+ return 0.0f;
- /* call the relevant callbacks to get the variable value
- * using the variable type info, storing the obtained value
- * in dvar->curval so that drivers can be debugged
- */
- dvti = get_dvar_typeinfo(dvar->type);
+ /* call the relevant callbacks to get the variable value
+ * using the variable type info, storing the obtained value
+ * in dvar->curval so that drivers can be debugged
+ */
+ dvti = get_dvar_typeinfo(dvar->type);
- if (dvti && dvti->get_value)
- dvar->curval = dvti->get_value(driver, dvar);
- else
- dvar->curval = 0.0f;
+ if (dvti && dvti->get_value)
+ dvar->curval = dvti->get_value(driver, dvar);
+ else
+ dvar->curval = 0.0f;
- return dvar->curval;
+ return dvar->curval;
}
/* Evaluate an Channel-Driver to get a 'time' value to use instead of "evaltime"
@@ -2031,113 +2096,113 @@ float driver_get_variable_value(ChannelDriver *driver, DriverVar *dvar)
* - has to return a float value
* - driver_orig is where we cache Python expressions, in case of COW
*/
-float evaluate_driver(PathResolvedRNA *anim_rna, ChannelDriver *driver, ChannelDriver *driver_orig, const float evaltime)
+float evaluate_driver(PathResolvedRNA *anim_rna,
+ ChannelDriver *driver,
+ ChannelDriver *driver_orig,
+ const float evaltime)
{
- DriverVar *dvar;
-
- /* check if driver can be evaluated */
- if (driver_orig->flag & DRIVER_FLAG_INVALID)
- return 0.0f;
-
- switch (driver->type) {
- case DRIVER_TYPE_AVERAGE: /* average values of driver targets */
- case DRIVER_TYPE_SUM: /* sum values of driver targets */
- {
- /* check how many variables there are first (i.e. just one?) */
- if (BLI_listbase_is_single(&driver->variables)) {
- /* just one target, so just use that */
- dvar = driver->variables.first;
- driver->curval = driver_get_variable_value(driver, dvar);
- }
- else {
- /* more than one target, so average the values of the targets */
- float value = 0.0f;
- int tot = 0;
-
- /* loop through targets, adding (hopefully we don't get any overflow!) */
- for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
- value += driver_get_variable_value(driver, dvar);
- tot++;
- }
-
- /* perform operations on the total if appropriate */
- if (driver->type == DRIVER_TYPE_AVERAGE)
- driver->curval = tot ? (value / (float)tot) : 0.0f;
- else
- driver->curval = value;
- }
- break;
- }
- case DRIVER_TYPE_MIN: /* smallest value */
- case DRIVER_TYPE_MAX: /* largest value */
- {
- float value = 0.0f;
-
- /* loop through the variables, getting the values and comparing them to existing ones */
- for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
- /* get value */
- float tmp_val = driver_get_variable_value(driver, dvar);
-
- /* store this value if appropriate */
- if (dvar->prev) {
- /* check if greater/smaller than the baseline */
- if (driver->type == DRIVER_TYPE_MAX) {
- /* max? */
- if (tmp_val > value)
- value = tmp_val;
- }
- else {
- /* min? */
- if (tmp_val < value)
- value = tmp_val;
- }
- }
- else {
- /* first item - make this the baseline for comparisons */
- value = tmp_val;
- }
- }
-
- /* store value in driver */
- driver->curval = value;
- break;
- }
- case DRIVER_TYPE_PYTHON: /* expression */
- {
- /* check for empty or invalid expression */
- if ( (driver_orig->expression[0] == '\0') ||
- (driver_orig->flag & DRIVER_FLAG_INVALID) )
- {
- driver->curval = 0.0f;
- }
- else if (!driver_try_evaluate_simple_expr(driver, driver_orig, &driver->curval, evaltime)) {
+ DriverVar *dvar;
+
+ /* check if driver can be evaluated */
+ if (driver_orig->flag & DRIVER_FLAG_INVALID)
+ return 0.0f;
+
+ switch (driver->type) {
+ case DRIVER_TYPE_AVERAGE: /* average values of driver targets */
+ case DRIVER_TYPE_SUM: /* sum values of driver targets */
+ {
+ /* check how many variables there are first (i.e. just one?) */
+ if (BLI_listbase_is_single(&driver->variables)) {
+ /* just one target, so just use that */
+ dvar = driver->variables.first;
+ driver->curval = driver_get_variable_value(driver, dvar);
+ }
+ else {
+ /* more than one target, so average the values of the targets */
+ float value = 0.0f;
+ int tot = 0;
+
+ /* loop through targets, adding (hopefully we don't get any overflow!) */
+ for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
+ value += driver_get_variable_value(driver, dvar);
+ tot++;
+ }
+
+ /* perform operations on the total if appropriate */
+ if (driver->type == DRIVER_TYPE_AVERAGE)
+ driver->curval = tot ? (value / (float)tot) : 0.0f;
+ else
+ driver->curval = value;
+ }
+ break;
+ }
+ case DRIVER_TYPE_MIN: /* smallest value */
+ case DRIVER_TYPE_MAX: /* largest value */
+ {
+ float value = 0.0f;
+
+ /* loop through the variables, getting the values and comparing them to existing ones */
+ for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
+ /* get value */
+ float tmp_val = driver_get_variable_value(driver, dvar);
+
+ /* store this value if appropriate */
+ if (dvar->prev) {
+ /* check if greater/smaller than the baseline */
+ if (driver->type == DRIVER_TYPE_MAX) {
+ /* max? */
+ if (tmp_val > value)
+ value = tmp_val;
+ }
+ else {
+ /* min? */
+ if (tmp_val < value)
+ value = tmp_val;
+ }
+ }
+ else {
+ /* first item - make this the baseline for comparisons */
+ value = tmp_val;
+ }
+ }
+
+ /* store value in driver */
+ driver->curval = value;
+ break;
+ }
+ case DRIVER_TYPE_PYTHON: /* expression */
+ {
+ /* check for empty or invalid expression */
+ if ((driver_orig->expression[0] == '\0') || (driver_orig->flag & DRIVER_FLAG_INVALID)) {
+ driver->curval = 0.0f;
+ }
+ else if (!driver_try_evaluate_simple_expr(driver, driver_orig, &driver->curval, evaltime)) {
#ifdef WITH_PYTHON
- /* this evaluates the expression using Python, and returns its result:
- * - on errors it reports, then returns 0.0f
- */
- BLI_mutex_lock(&python_driver_lock);
+ /* this evaluates the expression using Python, and returns its result:
+ * - on errors it reports, then returns 0.0f
+ */
+ BLI_mutex_lock(&python_driver_lock);
- driver->curval = BPY_driver_exec(anim_rna, driver, driver_orig, evaltime);
+ driver->curval = BPY_driver_exec(anim_rna, driver, driver_orig, evaltime);
- BLI_mutex_unlock(&python_driver_lock);
-#else /* WITH_PYTHON*/
- UNUSED_VARS(anim_rna, evaltime);
+ BLI_mutex_unlock(&python_driver_lock);
+#else /* WITH_PYTHON*/
+ UNUSED_VARS(anim_rna, evaltime);
#endif /* WITH_PYTHON*/
- }
- break;
- }
- default:
- {
- /* special 'hack' - just use stored value
- * This is currently used as the mechanism which allows animated settings to be able
- * to be changed via the UI.
- */
- break;
- }
- }
-
- /* return value for driver */
- return driver->curval;
+ }
+ break;
+ }
+ default: {
+ /* special 'hack' - just use stored value
+ * This is currently used as the mechanism which allows animated settings to be able
+ * to be changed via the UI.
+ */
+ break;
+ }
+ }
+
+ /* return value for driver */
+ return driver->curval;
}
/* ***************************** Curve Calculations ********************************* */
@@ -2148,606 +2213,635 @@ float evaluate_driver(PathResolvedRNA *anim_rna, ChannelDriver *driver, ChannelD
*/
void correct_bezpart(float v1[2], float v2[2], float v3[2], float v4[2])
{
- float h1[2], h2[2], len1, len2, len, fac;
-
- /* calculate handle deltas */
- h1[0] = v1[0] - v2[0];
- h1[1] = v1[1] - v2[1];
-
- h2[0] = v4[0] - v3[0];
- h2[1] = v4[1] - v3[1];
-
- /* calculate distances:
- * - len = span of time between keyframes
- * - len1 = length of handle of start key
- * - len2 = length of handle of end key
- */
- len = v4[0] - v1[0];
- len1 = fabsf(h1[0]);
- len2 = fabsf(h2[0]);
-
- /* if the handles have no length, no need to do any corrections */
- if ((len1 + len2) == 0.0f)
- return;
-
- /* the two handles cross over each other, so force them
- * apart using the proportion they overlap
- */
- if ((len1 + len2) > len) {
- fac = len / (len1 + len2);
-
- v2[0] = (v1[0] - fac * h1[0]);
- v2[1] = (v1[1] - fac * h1[1]);
-
- v3[0] = (v4[0] - fac * h2[0]);
- v3[1] = (v4[1] - fac * h2[1]);
- }
+ float h1[2], h2[2], len1, len2, len, fac;
+
+ /* calculate handle deltas */
+ h1[0] = v1[0] - v2[0];
+ h1[1] = v1[1] - v2[1];
+
+ h2[0] = v4[0] - v3[0];
+ h2[1] = v4[1] - v3[1];
+
+ /* calculate distances:
+ * - len = span of time between keyframes
+ * - len1 = length of handle of start key
+ * - len2 = length of handle of end key
+ */
+ len = v4[0] - v1[0];
+ len1 = fabsf(h1[0]);
+ len2 = fabsf(h2[0]);
+
+ /* if the handles have no length, no need to do any corrections */
+ if ((len1 + len2) == 0.0f)
+ return;
+
+ /* the two handles cross over each other, so force them
+ * apart using the proportion they overlap
+ */
+ if ((len1 + len2) > len) {
+ fac = len / (len1 + len2);
+
+ v2[0] = (v1[0] - fac * h1[0]);
+ v2[1] = (v1[1] - fac * h1[1]);
+
+ v3[0] = (v4[0] - fac * h2[0]);
+ v3[1] = (v4[1] - fac * h2[1]);
+ }
}
/* find root ('zero') */
static int findzero(float x, float q0, float q1, float q2, float q3, float *o)
{
- double c0, c1, c2, c3, a, b, c, p, q, d, t, phi;
- int nr = 0;
-
- c0 = q0 - x;
- c1 = 3.0f * (q1 - q0);
- c2 = 3.0f * (q0 - 2.0f * q1 + q2);
- c3 = q3 - q0 + 3.0f * (q1 - q2);
-
- if (c3 != 0.0) {
- a = c2 / c3;
- b = c1 / c3;
- c = c0 / c3;
- a = a / 3;
-
- p = b / 3 - a * a;
- q = (2 * a * a * a - a * b + c) / 2;
- d = q * q + p * p * p;
-
- if (d > 0.0) {
- t = sqrt(d);
- o[0] = (float)(sqrt3d(-q + t) + sqrt3d(-q - t) - a);
-
- if ((o[0] >= (float)SMALL) && (o[0] <= 1.000001f)) return 1;
- else return 0;
- }
- else if (d == 0.0) {
- t = sqrt3d(-q);
- o[0] = (float)(2 * t - a);
-
- if ((o[0] >= (float)SMALL) && (o[0] <= 1.000001f)) nr++;
- o[nr] = (float)(-t - a);
-
- if ((o[nr] >= (float)SMALL) && (o[nr] <= 1.000001f)) return nr + 1;
- else return nr;
- }
- else {
- phi = acos(-q / sqrt(-(p * p * p)));
- t = sqrt(-p);
- p = cos(phi / 3);
- q = sqrt(3 - 3 * p * p);
- o[0] = (float)(2 * t * p - a);
-
- if ((o[0] >= (float)SMALL) && (o[0] <= 1.000001f)) nr++;
- o[nr] = (float)(-t * (p + q) - a);
-
- if ((o[nr] >= (float)SMALL) && (o[nr] <= 1.000001f)) nr++;
- o[nr] = (float)(-t * (p - q) - a);
-
- if ((o[nr] >= (float)SMALL) && (o[nr] <= 1.000001f)) return nr + 1;
- else return nr;
- }
- }
- else {
- a = c2;
- b = c1;
- c = c0;
-
- if (a != 0.0) {
- /* discriminant */
- p = b * b - 4 * a * c;
-
- if (p > 0) {
- p = sqrt(p);
- o[0] = (float)((-b - p) / (2 * a));
-
- if ((o[0] >= (float)SMALL) && (o[0] <= 1.000001f)) nr++;
- o[nr] = (float)((-b + p) / (2 * a));
-
- if ((o[nr] >= (float)SMALL) && (o[nr] <= 1.000001f)) return nr + 1;
- else return nr;
- }
- else if (p == 0) {
- o[0] = (float)(-b / (2 * a));
- if ((o[0] >= (float)SMALL) && (o[0] <= 1.000001f)) return 1;
- else return 0;
- }
- }
- else if (b != 0.0) {
- o[0] = (float)(-c / b);
-
- if ((o[0] >= (float)SMALL) && (o[0] <= 1.000001f)) return 1;
- else return 0;
- }
- else if (c == 0.0) {
- o[0] = 0.0;
- return 1;
- }
-
- return 0;
- }
+ double c0, c1, c2, c3, a, b, c, p, q, d, t, phi;
+ int nr = 0;
+
+ c0 = q0 - x;
+ c1 = 3.0f * (q1 - q0);
+ c2 = 3.0f * (q0 - 2.0f * q1 + q2);
+ c3 = q3 - q0 + 3.0f * (q1 - q2);
+
+ if (c3 != 0.0) {
+ a = c2 / c3;
+ b = c1 / c3;
+ c = c0 / c3;
+ a = a / 3;
+
+ p = b / 3 - a * a;
+ q = (2 * a * a * a - a * b + c) / 2;
+ d = q * q + p * p * p;
+
+ if (d > 0.0) {
+ t = sqrt(d);
+ o[0] = (float)(sqrt3d(-q + t) + sqrt3d(-q - t) - a);
+
+ if ((o[0] >= (float)SMALL) && (o[0] <= 1.000001f))
+ return 1;
+ else
+ return 0;
+ }
+ else if (d == 0.0) {
+ t = sqrt3d(-q);
+ o[0] = (float)(2 * t - a);
+
+ if ((o[0] >= (float)SMALL) && (o[0] <= 1.000001f))
+ nr++;
+ o[nr] = (float)(-t - a);
+
+ if ((o[nr] >= (float)SMALL) && (o[nr] <= 1.000001f))
+ return nr + 1;
+ else
+ return nr;
+ }
+ else {
+ phi = acos(-q / sqrt(-(p * p * p)));
+ t = sqrt(-p);
+ p = cos(phi / 3);
+ q = sqrt(3 - 3 * p * p);
+ o[0] = (float)(2 * t * p - a);
+
+ if ((o[0] >= (float)SMALL) && (o[0] <= 1.000001f))
+ nr++;
+ o[nr] = (float)(-t * (p + q) - a);
+
+ if ((o[nr] >= (float)SMALL) && (o[nr] <= 1.000001f))
+ nr++;
+ o[nr] = (float)(-t * (p - q) - a);
+
+ if ((o[nr] >= (float)SMALL) && (o[nr] <= 1.000001f))
+ return nr + 1;
+ else
+ return nr;
+ }
+ }
+ else {
+ a = c2;
+ b = c1;
+ c = c0;
+
+ if (a != 0.0) {
+ /* discriminant */
+ p = b * b - 4 * a * c;
+
+ if (p > 0) {
+ p = sqrt(p);
+ o[0] = (float)((-b - p) / (2 * a));
+
+ if ((o[0] >= (float)SMALL) && (o[0] <= 1.000001f))
+ nr++;
+ o[nr] = (float)((-b + p) / (2 * a));
+
+ if ((o[nr] >= (float)SMALL) && (o[nr] <= 1.000001f))
+ return nr + 1;
+ else
+ return nr;
+ }
+ else if (p == 0) {
+ o[0] = (float)(-b / (2 * a));
+ if ((o[0] >= (float)SMALL) && (o[0] <= 1.000001f))
+ return 1;
+ else
+ return 0;
+ }
+ }
+ else if (b != 0.0) {
+ o[0] = (float)(-c / b);
+
+ if ((o[0] >= (float)SMALL) && (o[0] <= 1.000001f))
+ return 1;
+ else
+ return 0;
+ }
+ else if (c == 0.0) {
+ o[0] = 0.0;
+ return 1;
+ }
+
+ return 0;
+ }
}
static void berekeny(float f1, float f2, float f3, float f4, float *o, int b)
{
- float t, c0, c1, c2, c3;
- int a;
-
- c0 = f1;
- c1 = 3.0f * (f2 - f1);
- c2 = 3.0f * (f1 - 2.0f * f2 + f3);
- c3 = f4 - f1 + 3.0f * (f2 - f3);
-
- for (a = 0; a < b; a++) {
- t = o[a];
- o[a] = c0 + t * c1 + t * t * c2 + t * t * t * c3;
- }
+ float t, c0, c1, c2, c3;
+ int a;
+
+ c0 = f1;
+ c1 = 3.0f * (f2 - f1);
+ c2 = 3.0f * (f1 - 2.0f * f2 + f3);
+ c3 = f4 - f1 + 3.0f * (f2 - f3);
+
+ for (a = 0; a < b; a++) {
+ t = o[a];
+ o[a] = c0 + t * c1 + t * t * c2 + t * t * t * c3;
+ }
}
-
/* -------------------------- */
/* Calculate F-Curve value for 'evaltime' using BezTriple keyframes */
static float fcurve_eval_keyframes(FCurve *fcu, BezTriple *bezts, float evaltime)
{
- const float eps = 1.e-8f;
- BezTriple *bezt, *prevbezt, *lastbezt;
- float v1[2], v2[2], v3[2], v4[2], opl[32], dx, fac;
- unsigned int a;
- int b;
- float cvalue = 0.0f;
-
- /* get pointers */
- a = fcu->totvert - 1;
- prevbezt = bezts;
- bezt = prevbezt + 1;
- lastbezt = prevbezt + a;
-
- /* evaluation time at or past endpoints? */
- if (prevbezt->vec[1][0] >= evaltime) {
- /* before or on first keyframe */
- if ( (fcu->extend == FCURVE_EXTRAPOLATE_LINEAR) && (prevbezt->ipo != BEZT_IPO_CONST) &&
- !(fcu->flag & FCURVE_DISCRETE_VALUES) )
- {
- /* linear or bezier interpolation */
- if (prevbezt->ipo == BEZT_IPO_LIN) {
- /* Use the next center point instead of our own handle for
- * linear interpolated extrapolate
- */
- if (fcu->totvert == 1) {
- cvalue = prevbezt->vec[1][1];
- }
- else {
- bezt = prevbezt + 1;
- dx = prevbezt->vec[1][0] - evaltime;
- fac = bezt->vec[1][0] - prevbezt->vec[1][0];
-
- /* prevent division by zero */
- if (fac) {
- fac = (bezt->vec[1][1] - prevbezt->vec[1][1]) / fac;
- cvalue = prevbezt->vec[1][1] - (fac * dx);
- }
- else {
- cvalue = prevbezt->vec[1][1];
- }
- }
- }
- else {
- /* Use the first handle (earlier) of first BezTriple to calculate the
- * gradient and thus the value of the curve at evaltime
- */
- dx = prevbezt->vec[1][0] - evaltime;
- fac = prevbezt->vec[1][0] - prevbezt->vec[0][0];
-
- /* prevent division by zero */
- if (fac) {
- fac = (prevbezt->vec[1][1] - prevbezt->vec[0][1]) / fac;
- cvalue = prevbezt->vec[1][1] - (fac * dx);
- }
- else {
- cvalue = prevbezt->vec[1][1];
- }
- }
- }
- else {
- /* constant (BEZT_IPO_HORIZ) extrapolation or constant interpolation,
- * so just extend first keyframe's value
- */
- cvalue = prevbezt->vec[1][1];
- }
- }
- else if (lastbezt->vec[1][0] <= evaltime) {
- /* after or on last keyframe */
- if ( (fcu->extend == FCURVE_EXTRAPOLATE_LINEAR) && (lastbezt->ipo != BEZT_IPO_CONST) &&
- !(fcu->flag & FCURVE_DISCRETE_VALUES) )
- {
- /* linear or bezier interpolation */
- if (lastbezt->ipo == BEZT_IPO_LIN) {
- /* Use the next center point instead of our own handle for
- * linear interpolated extrapolate
- */
- if (fcu->totvert == 1) {
- cvalue = lastbezt->vec[1][1];
- }
- else {
- prevbezt = lastbezt - 1;
- dx = evaltime - lastbezt->vec[1][0];
- fac = lastbezt->vec[1][0] - prevbezt->vec[1][0];
-
- /* prevent division by zero */
- if (fac) {
- fac = (lastbezt->vec[1][1] - prevbezt->vec[1][1]) / fac;
- cvalue = lastbezt->vec[1][1] + (fac * dx);
- }
- else {
- cvalue = lastbezt->vec[1][1];
- }
- }
- }
- else {
- /* Use the gradient of the second handle (later) of last BezTriple to calculate the
- * gradient and thus the value of the curve at evaltime
- */
- dx = evaltime - lastbezt->vec[1][0];
- fac = lastbezt->vec[2][0] - lastbezt->vec[1][0];
-
- /* prevent division by zero */
- if (fac) {
- fac = (lastbezt->vec[2][1] - lastbezt->vec[1][1]) / fac;
- cvalue = lastbezt->vec[1][1] + (fac * dx);
- }
- else {
- cvalue = lastbezt->vec[1][1];
- }
- }
- }
- else {
- /* constant (BEZT_IPO_HORIZ) extrapolation or constant interpolation,
- * so just extend last keyframe's value
- */
- cvalue = lastbezt->vec[1][1];
- }
- }
- else {
- /* evaltime occurs somewhere in the middle of the curve */
- bool exact = false;
-
- /* Use binary search to find appropriate keyframes...
- *
- * The threshold here has the following constraints:
- * - 0.001 is too coarse -> We get artifacts with 2cm driver movements at 1BU = 1m (see T40332)
- * - 0.00001 is too fine -> Weird errors, like selecting the wrong keyframe range (see T39207), occur.
- * This lower bound was established in b888a32eee8147b028464336ad2404d8155c64dd
- */
- a = binarysearch_bezt_index_ex(bezts, evaltime, fcu->totvert, 0.0001, &exact);
- if (G.debug & G_DEBUG) printf("eval fcurve '%s' - %f => %u/%u, %d\n", fcu->rna_path, evaltime, a, fcu->totvert, exact);
-
- if (exact) {
- /* index returned must be interpreted differently when it sits on top of an existing keyframe
- * - that keyframe is the start of the segment we need (see action_bug_2.blend in T39207)
- */
- prevbezt = bezts + a;
- bezt = (a < fcu->totvert - 1) ? (prevbezt + 1) : prevbezt;
- }
- else {
- /* index returned refers to the keyframe that the eval-time occurs *before*
- * - hence, that keyframe marks the start of the segment we're dealing with
- */
- bezt = bezts + a;
- prevbezt = (a > 0) ? (bezt - 1) : bezt;
- }
-
- /* use if the key is directly on the frame, rare cases this is needed else we get 0.0 instead. */
- /* XXX: consult T39207 for examples of files where failure of these checks can cause issues */
- if (exact) {
- cvalue = prevbezt->vec[1][1];
- }
- else if (fabsf(bezt->vec[1][0] - evaltime) < eps) {
- cvalue = bezt->vec[1][1];
- }
- /* evaltime occurs within the interval defined by these two keyframes */
- else if ((prevbezt->vec[1][0] <= evaltime) && (bezt->vec[1][0] >= evaltime)) {
- const float begin = prevbezt->vec[1][1];
- const float change = bezt->vec[1][1] - prevbezt->vec[1][1];
- const float duration = bezt->vec[1][0] - prevbezt->vec[1][0];
- const float time = evaltime - prevbezt->vec[1][0];
- const float amplitude = prevbezt->amplitude;
- const float period = prevbezt->period;
-
- /* value depends on interpolation mode */
- if ((prevbezt->ipo == BEZT_IPO_CONST) || (fcu->flag & FCURVE_DISCRETE_VALUES) || (duration == 0)) {
- /* constant (evaltime not relevant, so no interpolation needed) */
- cvalue = prevbezt->vec[1][1];
- }
- else {
- switch (prevbezt->ipo) {
- /* interpolation ...................................... */
- case BEZT_IPO_BEZ:
- /* bezier interpolation */
- /* (v1, v2) are the first keyframe and its 2nd handle */
- v1[0] = prevbezt->vec[1][0];
- v1[1] = prevbezt->vec[1][1];
- v2[0] = prevbezt->vec[2][0];
- v2[1] = prevbezt->vec[2][1];
- /* (v3, v4) are the last keyframe's 1st handle + the last keyframe */
- v3[0] = bezt->vec[0][0];
- v3[1] = bezt->vec[0][1];
- v4[0] = bezt->vec[1][0];
- v4[1] = bezt->vec[1][1];
-
- if (fabsf(v1[1] - v4[1]) < FLT_EPSILON &&
- fabsf(v2[1] - v3[1]) < FLT_EPSILON &&
- fabsf(v3[1] - v4[1]) < FLT_EPSILON)
- {
- /* Optimisation: If all the handles are flat/at the same values,
- * the value is simply the shared value (see T40372 -> F91346)
- */
- cvalue = v1[1];
- }
- else {
- /* adjust handles so that they don't overlap (forming a loop) */
- correct_bezpart(v1, v2, v3, v4);
-
- /* try to get a value for this position - if failure, try another set of points */
- b = findzero(evaltime, v1[0], v2[0], v3[0], v4[0], opl);
- if (b) {
- berekeny(v1[1], v2[1], v3[1], v4[1], opl, 1);
- cvalue = opl[0];
- /* break; */
- }
- else {
- if (G.debug & G_DEBUG) printf(" ERROR: findzero() failed at %f with %f %f %f %f\n", evaltime, v1[0], v2[0], v3[0], v4[0]);
- }
- }
- break;
-
- case BEZT_IPO_LIN:
- /* linear - simply linearly interpolate between values of the two keyframes */
- cvalue = BLI_easing_linear_ease(time, begin, change, duration);
- break;
-
- /* easing ............................................ */
- case BEZT_IPO_BACK:
- switch (prevbezt->easing) {
- case BEZT_IPO_EASE_IN:
- cvalue = BLI_easing_back_ease_in(time, begin, change, duration, prevbezt->back);
- break;
- case BEZT_IPO_EASE_OUT:
- cvalue = BLI_easing_back_ease_out(time, begin, change, duration, prevbezt->back);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- cvalue = BLI_easing_back_ease_in_out(time, begin, change, duration, prevbezt->back);
- break;
-
- default: /* default/auto: same as ease out */
- cvalue = BLI_easing_back_ease_out(time, begin, change, duration, prevbezt->back);
- break;
- }
- break;
-
- case BEZT_IPO_BOUNCE:
- switch (prevbezt->easing) {
- case BEZT_IPO_EASE_IN:
- cvalue = BLI_easing_bounce_ease_in(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_OUT:
- cvalue = BLI_easing_bounce_ease_out(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- cvalue = BLI_easing_bounce_ease_in_out(time, begin, change, duration);
- break;
-
- default: /* default/auto: same as ease out */
- cvalue = BLI_easing_bounce_ease_out(time, begin, change, duration);
- break;
- }
- break;
-
- case BEZT_IPO_CIRC:
- switch (prevbezt->easing) {
- case BEZT_IPO_EASE_IN:
- cvalue = BLI_easing_circ_ease_in(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_OUT:
- cvalue = BLI_easing_circ_ease_out(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- cvalue = BLI_easing_circ_ease_in_out(time, begin, change, duration);
- break;
-
- default: /* default/auto: same as ease in */
- cvalue = BLI_easing_circ_ease_in(time, begin, change, duration);
- break;
- }
- break;
-
- case BEZT_IPO_CUBIC:
- switch (prevbezt->easing) {
- case BEZT_IPO_EASE_IN:
- cvalue = BLI_easing_cubic_ease_in(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_OUT:
- cvalue = BLI_easing_cubic_ease_out(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- cvalue = BLI_easing_cubic_ease_in_out(time, begin, change, duration);
- break;
-
- default: /* default/auto: same as ease in */
- cvalue = BLI_easing_cubic_ease_in(time, begin, change, duration);
- break;
- }
- break;
-
- case BEZT_IPO_ELASTIC:
- switch (prevbezt->easing) {
- case BEZT_IPO_EASE_IN:
- cvalue = BLI_easing_elastic_ease_in(time, begin, change, duration, amplitude, period);
- break;
- case BEZT_IPO_EASE_OUT:
- cvalue = BLI_easing_elastic_ease_out(time, begin, change, duration, amplitude, period);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- cvalue = BLI_easing_elastic_ease_in_out(time, begin, change, duration, amplitude, period);
- break;
-
- default: /* default/auto: same as ease out */
- cvalue = BLI_easing_elastic_ease_out(time, begin, change, duration, amplitude, period);
- break;
- }
- break;
-
- case BEZT_IPO_EXPO:
- switch (prevbezt->easing) {
- case BEZT_IPO_EASE_IN:
- cvalue = BLI_easing_expo_ease_in(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_OUT:
- cvalue = BLI_easing_expo_ease_out(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- cvalue = BLI_easing_expo_ease_in_out(time, begin, change, duration);
- break;
-
- default: /* default/auto: same as ease in */
- cvalue = BLI_easing_expo_ease_in(time, begin, change, duration);
- break;
- }
- break;
-
- case BEZT_IPO_QUAD:
- switch (prevbezt->easing) {
- case BEZT_IPO_EASE_IN:
- cvalue = BLI_easing_quad_ease_in(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_OUT:
- cvalue = BLI_easing_quad_ease_out(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- cvalue = BLI_easing_quad_ease_in_out(time, begin, change, duration);
- break;
-
- default: /* default/auto: same as ease in */
- cvalue = BLI_easing_quad_ease_in(time, begin, change, duration);
- break;
- }
- break;
-
- case BEZT_IPO_QUART:
- switch (prevbezt->easing) {
- case BEZT_IPO_EASE_IN:
- cvalue = BLI_easing_quart_ease_in(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_OUT:
- cvalue = BLI_easing_quart_ease_out(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- cvalue = BLI_easing_quart_ease_in_out(time, begin, change, duration);
- break;
-
- default: /* default/auto: same as ease in */
- cvalue = BLI_easing_quart_ease_in(time, begin, change, duration);
- break;
- }
- break;
-
- case BEZT_IPO_QUINT:
- switch (prevbezt->easing) {
- case BEZT_IPO_EASE_IN:
- cvalue = BLI_easing_quint_ease_in(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_OUT:
- cvalue = BLI_easing_quint_ease_out(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- cvalue = BLI_easing_quint_ease_in_out(time, begin, change, duration);
- break;
-
- default: /* default/auto: same as ease in */
- cvalue = BLI_easing_quint_ease_in(time, begin, change, duration);
- break;
- }
- break;
-
- case BEZT_IPO_SINE:
- switch (prevbezt->easing) {
- case BEZT_IPO_EASE_IN:
- cvalue = BLI_easing_sine_ease_in(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_OUT:
- cvalue = BLI_easing_sine_ease_out(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- cvalue = BLI_easing_sine_ease_in_out(time, begin, change, duration);
- break;
-
- default: /* default/auto: same as ease in */
- cvalue = BLI_easing_sine_ease_in(time, begin, change, duration);
- break;
- }
- break;
-
-
- default:
- cvalue = prevbezt->vec[1][1];
- break;
- }
- }
- }
- else {
- if (G.debug & G_DEBUG) printf(" ERROR: failed eval - p=%f b=%f, t=%f (%f)\n", prevbezt->vec[1][0], bezt->vec[1][0], evaltime, fabsf(bezt->vec[1][0] - evaltime));
- }
- }
-
- /* return value */
- return cvalue;
+ const float eps = 1.e-8f;
+ BezTriple *bezt, *prevbezt, *lastbezt;
+ float v1[2], v2[2], v3[2], v4[2], opl[32], dx, fac;
+ unsigned int a;
+ int b;
+ float cvalue = 0.0f;
+
+ /* get pointers */
+ a = fcu->totvert - 1;
+ prevbezt = bezts;
+ bezt = prevbezt + 1;
+ lastbezt = prevbezt + a;
+
+ /* evaluation time at or past endpoints? */
+ if (prevbezt->vec[1][0] >= evaltime) {
+ /* before or on first keyframe */
+ if ((fcu->extend == FCURVE_EXTRAPOLATE_LINEAR) && (prevbezt->ipo != BEZT_IPO_CONST) &&
+ !(fcu->flag & FCURVE_DISCRETE_VALUES)) {
+ /* linear or bezier interpolation */
+ if (prevbezt->ipo == BEZT_IPO_LIN) {
+ /* Use the next center point instead of our own handle for
+ * linear interpolated extrapolate
+ */
+ if (fcu->totvert == 1) {
+ cvalue = prevbezt->vec[1][1];
+ }
+ else {
+ bezt = prevbezt + 1;
+ dx = prevbezt->vec[1][0] - evaltime;
+ fac = bezt->vec[1][0] - prevbezt->vec[1][0];
+
+ /* prevent division by zero */
+ if (fac) {
+ fac = (bezt->vec[1][1] - prevbezt->vec[1][1]) / fac;
+ cvalue = prevbezt->vec[1][1] - (fac * dx);
+ }
+ else {
+ cvalue = prevbezt->vec[1][1];
+ }
+ }
+ }
+ else {
+ /* Use the first handle (earlier) of first BezTriple to calculate the
+ * gradient and thus the value of the curve at evaltime
+ */
+ dx = prevbezt->vec[1][0] - evaltime;
+ fac = prevbezt->vec[1][0] - prevbezt->vec[0][0];
+
+ /* prevent division by zero */
+ if (fac) {
+ fac = (prevbezt->vec[1][1] - prevbezt->vec[0][1]) / fac;
+ cvalue = prevbezt->vec[1][1] - (fac * dx);
+ }
+ else {
+ cvalue = prevbezt->vec[1][1];
+ }
+ }
+ }
+ else {
+ /* constant (BEZT_IPO_HORIZ) extrapolation or constant interpolation,
+ * so just extend first keyframe's value
+ */
+ cvalue = prevbezt->vec[1][1];
+ }
+ }
+ else if (lastbezt->vec[1][0] <= evaltime) {
+ /* after or on last keyframe */
+ if ((fcu->extend == FCURVE_EXTRAPOLATE_LINEAR) && (lastbezt->ipo != BEZT_IPO_CONST) &&
+ !(fcu->flag & FCURVE_DISCRETE_VALUES)) {
+ /* linear or bezier interpolation */
+ if (lastbezt->ipo == BEZT_IPO_LIN) {
+ /* Use the next center point instead of our own handle for
+ * linear interpolated extrapolate
+ */
+ if (fcu->totvert == 1) {
+ cvalue = lastbezt->vec[1][1];
+ }
+ else {
+ prevbezt = lastbezt - 1;
+ dx = evaltime - lastbezt->vec[1][0];
+ fac = lastbezt->vec[1][0] - prevbezt->vec[1][0];
+
+ /* prevent division by zero */
+ if (fac) {
+ fac = (lastbezt->vec[1][1] - prevbezt->vec[1][1]) / fac;
+ cvalue = lastbezt->vec[1][1] + (fac * dx);
+ }
+ else {
+ cvalue = lastbezt->vec[1][1];
+ }
+ }
+ }
+ else {
+ /* Use the gradient of the second handle (later) of last BezTriple to calculate the
+ * gradient and thus the value of the curve at evaltime
+ */
+ dx = evaltime - lastbezt->vec[1][0];
+ fac = lastbezt->vec[2][0] - lastbezt->vec[1][0];
+
+ /* prevent division by zero */
+ if (fac) {
+ fac = (lastbezt->vec[2][1] - lastbezt->vec[1][1]) / fac;
+ cvalue = lastbezt->vec[1][1] + (fac * dx);
+ }
+ else {
+ cvalue = lastbezt->vec[1][1];
+ }
+ }
+ }
+ else {
+ /* constant (BEZT_IPO_HORIZ) extrapolation or constant interpolation,
+ * so just extend last keyframe's value
+ */
+ cvalue = lastbezt->vec[1][1];
+ }
+ }
+ else {
+ /* evaltime occurs somewhere in the middle of the curve */
+ bool exact = false;
+
+ /* Use binary search to find appropriate keyframes...
+ *
+ * The threshold here has the following constraints:
+ * - 0.001 is too coarse -> We get artifacts with 2cm driver movements at 1BU = 1m (see T40332)
+ * - 0.00001 is too fine -> Weird errors, like selecting the wrong keyframe range (see T39207), occur.
+ * This lower bound was established in b888a32eee8147b028464336ad2404d8155c64dd
+ */
+ a = binarysearch_bezt_index_ex(bezts, evaltime, fcu->totvert, 0.0001, &exact);
+ if (G.debug & G_DEBUG)
+ printf(
+ "eval fcurve '%s' - %f => %u/%u, %d\n", fcu->rna_path, evaltime, a, fcu->totvert, exact);
+
+ if (exact) {
+ /* index returned must be interpreted differently when it sits on top of an existing keyframe
+ * - that keyframe is the start of the segment we need (see action_bug_2.blend in T39207)
+ */
+ prevbezt = bezts + a;
+ bezt = (a < fcu->totvert - 1) ? (prevbezt + 1) : prevbezt;
+ }
+ else {
+ /* index returned refers to the keyframe that the eval-time occurs *before*
+ * - hence, that keyframe marks the start of the segment we're dealing with
+ */
+ bezt = bezts + a;
+ prevbezt = (a > 0) ? (bezt - 1) : bezt;
+ }
+
+ /* use if the key is directly on the frame, rare cases this is needed else we get 0.0 instead. */
+ /* XXX: consult T39207 for examples of files where failure of these checks can cause issues */
+ if (exact) {
+ cvalue = prevbezt->vec[1][1];
+ }
+ else if (fabsf(bezt->vec[1][0] - evaltime) < eps) {
+ cvalue = bezt->vec[1][1];
+ }
+ /* evaltime occurs within the interval defined by these two keyframes */
+ else if ((prevbezt->vec[1][0] <= evaltime) && (bezt->vec[1][0] >= evaltime)) {
+ const float begin = prevbezt->vec[1][1];
+ const float change = bezt->vec[1][1] - prevbezt->vec[1][1];
+ const float duration = bezt->vec[1][0] - prevbezt->vec[1][0];
+ const float time = evaltime - prevbezt->vec[1][0];
+ const float amplitude = prevbezt->amplitude;
+ const float period = prevbezt->period;
+
+ /* value depends on interpolation mode */
+ if ((prevbezt->ipo == BEZT_IPO_CONST) || (fcu->flag & FCURVE_DISCRETE_VALUES) ||
+ (duration == 0)) {
+ /* constant (evaltime not relevant, so no interpolation needed) */
+ cvalue = prevbezt->vec[1][1];
+ }
+ else {
+ switch (prevbezt->ipo) {
+ /* interpolation ...................................... */
+ case BEZT_IPO_BEZ:
+ /* bezier interpolation */
+ /* (v1, v2) are the first keyframe and its 2nd handle */
+ v1[0] = prevbezt->vec[1][0];
+ v1[1] = prevbezt->vec[1][1];
+ v2[0] = prevbezt->vec[2][0];
+ v2[1] = prevbezt->vec[2][1];
+ /* (v3, v4) are the last keyframe's 1st handle + the last keyframe */
+ v3[0] = bezt->vec[0][0];
+ v3[1] = bezt->vec[0][1];
+ v4[0] = bezt->vec[1][0];
+ v4[1] = bezt->vec[1][1];
+
+ if (fabsf(v1[1] - v4[1]) < FLT_EPSILON && fabsf(v2[1] - v3[1]) < FLT_EPSILON &&
+ fabsf(v3[1] - v4[1]) < FLT_EPSILON) {
+ /* Optimisation: If all the handles are flat/at the same values,
+ * the value is simply the shared value (see T40372 -> F91346)
+ */
+ cvalue = v1[1];
+ }
+ else {
+ /* adjust handles so that they don't overlap (forming a loop) */
+ correct_bezpart(v1, v2, v3, v4);
+
+ /* try to get a value for this position - if failure, try another set of points */
+ b = findzero(evaltime, v1[0], v2[0], v3[0], v4[0], opl);
+ if (b) {
+ berekeny(v1[1], v2[1], v3[1], v4[1], opl, 1);
+ cvalue = opl[0];
+ /* break; */
+ }
+ else {
+ if (G.debug & G_DEBUG)
+ printf(" ERROR: findzero() failed at %f with %f %f %f %f\n",
+ evaltime,
+ v1[0],
+ v2[0],
+ v3[0],
+ v4[0]);
+ }
+ }
+ break;
+
+ case BEZT_IPO_LIN:
+ /* linear - simply linearly interpolate between values of the two keyframes */
+ cvalue = BLI_easing_linear_ease(time, begin, change, duration);
+ break;
+
+ /* easing ............................................ */
+ case BEZT_IPO_BACK:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ cvalue = BLI_easing_back_ease_in(time, begin, change, duration, prevbezt->back);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ cvalue = BLI_easing_back_ease_out(time, begin, change, duration, prevbezt->back);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ cvalue = BLI_easing_back_ease_in_out(
+ time, begin, change, duration, prevbezt->back);
+ break;
+
+ default: /* default/auto: same as ease out */
+ cvalue = BLI_easing_back_ease_out(time, begin, change, duration, prevbezt->back);
+ break;
+ }
+ break;
+
+ case BEZT_IPO_BOUNCE:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ cvalue = BLI_easing_bounce_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ cvalue = BLI_easing_bounce_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ cvalue = BLI_easing_bounce_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease out */
+ cvalue = BLI_easing_bounce_ease_out(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case BEZT_IPO_CIRC:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ cvalue = BLI_easing_circ_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ cvalue = BLI_easing_circ_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ cvalue = BLI_easing_circ_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease in */
+ cvalue = BLI_easing_circ_ease_in(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case BEZT_IPO_CUBIC:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ cvalue = BLI_easing_cubic_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ cvalue = BLI_easing_cubic_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ cvalue = BLI_easing_cubic_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease in */
+ cvalue = BLI_easing_cubic_ease_in(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case BEZT_IPO_ELASTIC:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ cvalue = BLI_easing_elastic_ease_in(
+ time, begin, change, duration, amplitude, period);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ cvalue = BLI_easing_elastic_ease_out(
+ time, begin, change, duration, amplitude, period);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ cvalue = BLI_easing_elastic_ease_in_out(
+ time, begin, change, duration, amplitude, period);
+ break;
+
+ default: /* default/auto: same as ease out */
+ cvalue = BLI_easing_elastic_ease_out(
+ time, begin, change, duration, amplitude, period);
+ break;
+ }
+ break;
+
+ case BEZT_IPO_EXPO:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ cvalue = BLI_easing_expo_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ cvalue = BLI_easing_expo_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ cvalue = BLI_easing_expo_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease in */
+ cvalue = BLI_easing_expo_ease_in(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case BEZT_IPO_QUAD:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ cvalue = BLI_easing_quad_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ cvalue = BLI_easing_quad_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ cvalue = BLI_easing_quad_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease in */
+ cvalue = BLI_easing_quad_ease_in(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case BEZT_IPO_QUART:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ cvalue = BLI_easing_quart_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ cvalue = BLI_easing_quart_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ cvalue = BLI_easing_quart_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease in */
+ cvalue = BLI_easing_quart_ease_in(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case BEZT_IPO_QUINT:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ cvalue = BLI_easing_quint_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ cvalue = BLI_easing_quint_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ cvalue = BLI_easing_quint_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease in */
+ cvalue = BLI_easing_quint_ease_in(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ case BEZT_IPO_SINE:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ cvalue = BLI_easing_sine_ease_in(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_OUT:
+ cvalue = BLI_easing_sine_ease_out(time, begin, change, duration);
+ break;
+ case BEZT_IPO_EASE_IN_OUT:
+ cvalue = BLI_easing_sine_ease_in_out(time, begin, change, duration);
+ break;
+
+ default: /* default/auto: same as ease in */
+ cvalue = BLI_easing_sine_ease_in(time, begin, change, duration);
+ break;
+ }
+ break;
+
+ default:
+ cvalue = prevbezt->vec[1][1];
+ break;
+ }
+ }
+ }
+ else {
+ if (G.debug & G_DEBUG)
+ printf(" ERROR: failed eval - p=%f b=%f, t=%f (%f)\n",
+ prevbezt->vec[1][0],
+ bezt->vec[1][0],
+ evaltime,
+ fabsf(bezt->vec[1][0] - evaltime));
+ }
+ }
+
+ /* return value */
+ return cvalue;
}
/* Calculate F-Curve value for 'evaltime' using FPoint samples */
static float fcurve_eval_samples(FCurve *fcu, FPoint *fpts, float evaltime)
{
- FPoint *prevfpt, *lastfpt, *fpt;
- float cvalue = 0.0f;
-
- /* get pointers */
- prevfpt = fpts;
- lastfpt = prevfpt + fcu->totvert - 1;
-
- /* evaluation time at or past endpoints? */
- if (prevfpt->vec[0] >= evaltime) {
- /* before or on first sample, so just extend value */
- cvalue = prevfpt->vec[1];
- }
- else if (lastfpt->vec[0] <= evaltime) {
- /* after or on last sample, so just extend value */
- cvalue = lastfpt->vec[1];
- }
- else {
- float t = fabsf(evaltime - floorf(evaltime));
-
- /* find the one on the right frame (assume that these are spaced on 1-frame intervals) */
- fpt = prevfpt + ((int)evaltime - (int)prevfpt->vec[0]);
-
- /* if not exactly on the frame, perform linear interpolation with the next one */
- if ((t != 0.0f) && (t < 1.0f))
- cvalue = interpf(fpt->vec[1], (fpt + 1)->vec[1], 1.0f - t);
- else
- cvalue = fpt->vec[1];
- }
-
- /* return value */
- return cvalue;
+ FPoint *prevfpt, *lastfpt, *fpt;
+ float cvalue = 0.0f;
+
+ /* get pointers */
+ prevfpt = fpts;
+ lastfpt = prevfpt + fcu->totvert - 1;
+
+ /* evaluation time at or past endpoints? */
+ if (prevfpt->vec[0] >= evaltime) {
+ /* before or on first sample, so just extend value */
+ cvalue = prevfpt->vec[1];
+ }
+ else if (lastfpt->vec[0] <= evaltime) {
+ /* after or on last sample, so just extend value */
+ cvalue = lastfpt->vec[1];
+ }
+ else {
+ float t = fabsf(evaltime - floorf(evaltime));
+
+ /* find the one on the right frame (assume that these are spaced on 1-frame intervals) */
+ fpt = prevfpt + ((int)evaltime - (int)prevfpt->vec[0]);
+
+ /* if not exactly on the frame, perform linear interpolation with the next one */
+ if ((t != 0.0f) && (t < 1.0f))
+ cvalue = interpf(fpt->vec[1], (fpt + 1)->vec[1], 1.0f - t);
+ else
+ cvalue = fpt->vec[1];
+ }
+
+ /* return value */
+ return cvalue;
}
/* ***************************** F-Curve - Evaluation ********************************* */
@@ -2757,118 +2851,119 @@ static float fcurve_eval_samples(FCurve *fcu, FPoint *fpts, float evaltime)
*/
static float evaluate_fcurve_ex(FCurve *fcu, float evaltime, float cvalue)
{
- FModifierStackStorage *storage;
- float devaltime;
-
- /* evaluate modifiers which modify time to evaluate the base curve at */
- storage = evaluate_fmodifiers_storage_new(&fcu->modifiers);
- devaltime = evaluate_time_fmodifiers(storage, &fcu->modifiers, fcu, cvalue, evaltime);
-
- /* evaluate curve-data
- * - 'devaltime' instead of 'evaltime', as this is the time that the last time-modifying
- * F-Curve modifier on the stack requested the curve to be evaluated at
- */
- if (fcu->bezt)
- cvalue = fcurve_eval_keyframes(fcu, fcu->bezt, devaltime);
- else if (fcu->fpt)
- cvalue = fcurve_eval_samples(fcu, fcu->fpt, devaltime);
-
- /* evaluate modifiers */
- evaluate_value_fmodifiers(storage, &fcu->modifiers, fcu, &cvalue, devaltime);
-
- evaluate_fmodifiers_storage_free(storage);
-
- /* if curve can only have integral values, perform truncation (i.e. drop the decimal part)
- * here so that the curve can be sampled correctly
- */
- if (fcu->flag & FCURVE_INT_VALUES)
- cvalue = floorf(cvalue + 0.5f);
-
- /* return evaluated value */
- return cvalue;
+ FModifierStackStorage *storage;
+ float devaltime;
+
+ /* evaluate modifiers which modify time to evaluate the base curve at */
+ storage = evaluate_fmodifiers_storage_new(&fcu->modifiers);
+ devaltime = evaluate_time_fmodifiers(storage, &fcu->modifiers, fcu, cvalue, evaltime);
+
+ /* evaluate curve-data
+ * - 'devaltime' instead of 'evaltime', as this is the time that the last time-modifying
+ * F-Curve modifier on the stack requested the curve to be evaluated at
+ */
+ if (fcu->bezt)
+ cvalue = fcurve_eval_keyframes(fcu, fcu->bezt, devaltime);
+ else if (fcu->fpt)
+ cvalue = fcurve_eval_samples(fcu, fcu->fpt, devaltime);
+
+ /* evaluate modifiers */
+ evaluate_value_fmodifiers(storage, &fcu->modifiers, fcu, &cvalue, devaltime);
+
+ evaluate_fmodifiers_storage_free(storage);
+
+ /* if curve can only have integral values, perform truncation (i.e. drop the decimal part)
+ * here so that the curve can be sampled correctly
+ */
+ if (fcu->flag & FCURVE_INT_VALUES)
+ cvalue = floorf(cvalue + 0.5f);
+
+ /* return evaluated value */
+ return cvalue;
}
float evaluate_fcurve(FCurve *fcu, float evaltime)
{
- BLI_assert(fcu->driver == NULL);
+ BLI_assert(fcu->driver == NULL);
- return evaluate_fcurve_ex(fcu, evaltime, 0.0);
+ return evaluate_fcurve_ex(fcu, evaltime, 0.0);
}
float evaluate_fcurve_only_curve(FCurve *fcu, float evaltime)
{
- /* Can be used to evaluate the (keyframed) fcurve only.
- * Also works for driver-fcurves when the driver itself is not relevant.
- * E.g. when inserting a keyframe in a driver fcurve. */
- return evaluate_fcurve_ex(fcu, evaltime, 0.0);
+ /* Can be used to evaluate the (keyframed) fcurve only.
+ * Also works for driver-fcurves when the driver itself is not relevant.
+ * E.g. when inserting a keyframe in a driver fcurve. */
+ return evaluate_fcurve_ex(fcu, evaltime, 0.0);
}
-float evaluate_fcurve_driver(PathResolvedRNA *anim_rna, FCurve *fcu, ChannelDriver *driver_orig, float evaltime)
+float evaluate_fcurve_driver(PathResolvedRNA *anim_rna,
+ FCurve *fcu,
+ ChannelDriver *driver_orig,
+ float evaltime)
{
- BLI_assert(fcu->driver != NULL);
- float cvalue = 0.0f;
-
- /* if there is a driver (only if this F-Curve is acting as 'driver'), evaluate it to find value to use as "evaltime"
- * since drivers essentially act as alternative input (i.e. in place of 'time') for F-Curves
- */
- if (fcu->driver) {
- /* evaltime now serves as input for the curve */
- evaltime = evaluate_driver(anim_rna, fcu->driver, driver_orig, evaltime);
-
- /* only do a default 1-1 mapping if it's unlikely that anything else will set a value... */
- if (fcu->totvert == 0) {
- FModifier *fcm;
- bool do_linear = true;
-
- /* out-of-range F-Modifiers will block, as will those which just plain overwrite the values
- * XXX: additive is a bit more dicey; it really depends then if things are in range or not...
- */
- for (fcm = fcu->modifiers.first; fcm; fcm = fcm->next) {
- /* if there are range-restrictions, we must definitely block [#36950] */
- if ((fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) == 0 ||
- ((fcm->sfra <= evaltime) && (fcm->efra >= evaltime)) )
- {
- /* within range: here it probably doesn't matter, though we'd want to check on additive... */
- }
- else {
- /* outside range: modifier shouldn't contribute to the curve here, though it does in other areas,
- * so neither should the driver!
- */
- do_linear = false;
- }
- }
-
- /* only copy over results if none of the modifiers disagreed with this */
- if (do_linear) {
- cvalue = evaltime;
- }
- }
- }
-
- return evaluate_fcurve_ex(fcu, evaltime, cvalue);
+ BLI_assert(fcu->driver != NULL);
+ float cvalue = 0.0f;
+
+ /* if there is a driver (only if this F-Curve is acting as 'driver'), evaluate it to find value to use as "evaltime"
+ * since drivers essentially act as alternative input (i.e. in place of 'time') for F-Curves
+ */
+ if (fcu->driver) {
+ /* evaltime now serves as input for the curve */
+ evaltime = evaluate_driver(anim_rna, fcu->driver, driver_orig, evaltime);
+
+ /* only do a default 1-1 mapping if it's unlikely that anything else will set a value... */
+ if (fcu->totvert == 0) {
+ FModifier *fcm;
+ bool do_linear = true;
+
+ /* out-of-range F-Modifiers will block, as will those which just plain overwrite the values
+ * XXX: additive is a bit more dicey; it really depends then if things are in range or not...
+ */
+ for (fcm = fcu->modifiers.first; fcm; fcm = fcm->next) {
+ /* if there are range-restrictions, we must definitely block [#36950] */
+ if ((fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) == 0 ||
+ ((fcm->sfra <= evaltime) && (fcm->efra >= evaltime))) {
+ /* within range: here it probably doesn't matter, though we'd want to check on additive... */
+ }
+ else {
+ /* outside range: modifier shouldn't contribute to the curve here, though it does in other areas,
+ * so neither should the driver!
+ */
+ do_linear = false;
+ }
+ }
+
+ /* only copy over results if none of the modifiers disagreed with this */
+ if (do_linear) {
+ cvalue = evaltime;
+ }
+ }
+ }
+
+ return evaluate_fcurve_ex(fcu, evaltime, cvalue);
}
/* Calculate the value of the given F-Curve at the given frame, and set its curval */
float calculate_fcurve(PathResolvedRNA *anim_rna, FCurve *fcu, float evaltime)
{
- /* only calculate + set curval (overriding the existing value) if curve has
- * any data which warrants this...
- */
- if ((fcu->totvert) || (fcu->driver && !(fcu->driver->flag & DRIVER_FLAG_INVALID)) ||
- list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE))
- {
- /* calculate and set curval (evaluates driver too if necessary) */
- float curval;
- if (fcu->driver) {
- curval = evaluate_fcurve_driver(anim_rna, fcu, fcu->driver, evaltime);
- }
- else {
- curval = evaluate_fcurve(fcu, evaltime);
- }
- fcu->curval = curval; /* debug display only, not thread safe! */
- return curval;
- }
- else {
- return 0.0f;
- }
+ /* only calculate + set curval (overriding the existing value) if curve has
+ * any data which warrants this...
+ */
+ if ((fcu->totvert) || (fcu->driver && !(fcu->driver->flag & DRIVER_FLAG_INVALID)) ||
+ list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE)) {
+ /* calculate and set curval (evaluates driver too if necessary) */
+ float curval;
+ if (fcu->driver) {
+ curval = evaluate_fcurve_driver(anim_rna, fcu, fcu->driver, evaltime);
+ }
+ else {
+ curval = evaluate_fcurve(fcu, evaltime);
+ }
+ fcu->curval = curval; /* debug display only, not thread safe! */
+ return curval;
+ }
+ else {
+ return 0.0f;
+ }
}
diff --git a/source/blender/blenkernel/intern/fluidsim.c b/source/blender/blenkernel/intern/fluidsim.c
index 2263c5f1a05..994e00f227a 100644
--- a/source/blender/blenkernel/intern/fluidsim.c
+++ b/source/blender/blenkernel/intern/fluidsim.c
@@ -21,7 +21,6 @@
* \ingroup bke
*/
-
#include "MEM_guardedalloc.h"
#include "DNA_mesh_types.h"
@@ -41,43 +40,51 @@
// file handling
//-------------------------------------------------------------------------------
-void initElbeemMesh(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob,
- int *numVertices, float **vertices,
- int *numTriangles, int **triangles,
- int useGlobalCoords, int modifierIndex)
+void initElbeemMesh(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct Object *ob,
+ int *numVertices,
+ float **vertices,
+ int *numTriangles,
+ int **triangles,
+ int useGlobalCoords,
+ int modifierIndex)
{
- Mesh *mesh;
- const MVert *mvert;
- const MLoop *mloop;
- const MLoopTri *looptri, *lt;
- int i, mvert_num, looptri_num;
- float *verts;
- int *tris;
+ Mesh *mesh;
+ const MVert *mvert;
+ const MLoop *mloop;
+ const MLoopTri *looptri, *lt;
+ int i, mvert_num, looptri_num;
+ float *verts;
+ int *tris;
- mesh = mesh_create_eval_final_index_render(depsgraph, scene, ob, &CD_MASK_BAREMESH, modifierIndex);
+ mesh = mesh_create_eval_final_index_render(
+ depsgraph, scene, ob, &CD_MASK_BAREMESH, modifierIndex);
- mvert = mesh->mvert;
- mloop = mesh->mloop;
- looptri = BKE_mesh_runtime_looptri_ensure(mesh);
- mvert_num = mesh->totvert;
- looptri_num = mesh->runtime.looptris.len;
+ mvert = mesh->mvert;
+ mloop = mesh->mloop;
+ looptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ mvert_num = mesh->totvert;
+ looptri_num = mesh->runtime.looptris.len;
- *numVertices = mvert_num;
- verts = MEM_mallocN(mvert_num * sizeof(float[3]), "elbeemmesh_vertices");
- for (i = 0; i < mvert_num; i++) {
- copy_v3_v3(&verts[i * 3], mvert[i].co);
- if (useGlobalCoords) { mul_m4_v3(ob->obmat, &verts[i * 3]); }
- }
- *vertices = verts;
+ *numVertices = mvert_num;
+ verts = MEM_mallocN(mvert_num * sizeof(float[3]), "elbeemmesh_vertices");
+ for (i = 0; i < mvert_num; i++) {
+ copy_v3_v3(&verts[i * 3], mvert[i].co);
+ if (useGlobalCoords) {
+ mul_m4_v3(ob->obmat, &verts[i * 3]);
+ }
+ }
+ *vertices = verts;
- *numTriangles = looptri_num;
- tris = MEM_mallocN(looptri_num * sizeof(int[3]), "elbeemmesh_triangles");
- for (i = 0, lt = looptri; i < looptri_num; i++, lt++) {
- tris[(i * 3) + 0] = mloop[lt->tri[0]].v;
- tris[(i * 3) + 1] = mloop[lt->tri[1]].v;
- tris[(i * 3) + 2] = mloop[lt->tri[2]].v;
- }
- *triangles = tris;
+ *numTriangles = looptri_num;
+ tris = MEM_mallocN(looptri_num * sizeof(int[3]), "elbeemmesh_triangles");
+ for (i = 0, lt = looptri; i < looptri_num; i++, lt++) {
+ tris[(i * 3) + 0] = mloop[lt->tri[0]].v;
+ tris[(i * 3) + 1] = mloop[lt->tri[1]].v;
+ tris[(i * 3) + 2] = mloop[lt->tri[2]].v;
+ }
+ *triangles = tris;
- BKE_id_free(NULL, mesh);
+ BKE_id_free(NULL, mesh);
}
diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c
index 1486455c750..d54a3bdaa37 100644
--- a/source/blender/blenkernel/intern/fmodifier.c
+++ b/source/blender/blenkernel/intern/fmodifier.c
@@ -79,21 +79,21 @@ void *fmodifiers_storage_get(FModifierStackStorage *storage, FModifier *fcm);
*/
#if 0
static FModifierTypeInfo FMI_MODNAME = {
- FMODIFIER_TYPE_MODNAME, /* type */
- sizeof(FMod_ModName), /* size */
- FMI_TYPE_SOME_ACTION, /* action type */
- FMI_REQUIRES_SOME_REQUIREMENT, /* requirements */
- "Modifier Name", /* name */
- "FMod_ModName", /* struct name */
- fcm_modname_free, /* free data */
- fcm_modname_relink, /* relink data */
- fcm_modname_copy, /* copy data */
- fcm_modname_new_data, /* new data */
- fcm_modname_verify, /* verify */
- fcm_modname_time, /* evaluate time */
- fcm_modname_evaluate, /* evaluate */
- fcm_modname_time_storage, /* evaluate time with storage */
- fcm_modname_evaluate_storage, /* evaluate with storage */
+ FMODIFIER_TYPE_MODNAME, /* type */
+ sizeof(FMod_ModName), /* size */
+ FMI_TYPE_SOME_ACTION, /* action type */
+ FMI_REQUIRES_SOME_REQUIREMENT, /* requirements */
+ "Modifier Name", /* name */
+ "FMod_ModName", /* struct name */
+ fcm_modname_free, /* free data */
+ fcm_modname_relink, /* relink data */
+ fcm_modname_copy, /* copy data */
+ fcm_modname_new_data, /* new data */
+ fcm_modname_verify, /* verify */
+ fcm_modname_time, /* evaluate time */
+ fcm_modname_evaluate, /* evaluate */
+ fcm_modname_time_storage, /* evaluate time with storage */
+ fcm_modname_evaluate_storage, /* evaluate with storage */
};
#endif
@@ -107,146 +107,148 @@ static FModifierTypeInfo FMI_MODNAME = {
static void fcm_generator_free(FModifier *fcm)
{
- FMod_Generator *data = (FMod_Generator *)fcm->data;
+ FMod_Generator *data = (FMod_Generator *)fcm->data;
- /* free polynomial coefficients array */
- if (data->coefficients)
- MEM_freeN(data->coefficients);
+ /* free polynomial coefficients array */
+ if (data->coefficients)
+ MEM_freeN(data->coefficients);
}
static void fcm_generator_copy(FModifier *fcm, const FModifier *src)
{
- FMod_Generator *gen = (FMod_Generator *)fcm->data;
- FMod_Generator *ogen = (FMod_Generator *)src->data;
+ FMod_Generator *gen = (FMod_Generator *)fcm->data;
+ FMod_Generator *ogen = (FMod_Generator *)src->data;
- /* copy coefficients array? */
- if (ogen->coefficients)
- gen->coefficients = MEM_dupallocN(ogen->coefficients);
+ /* copy coefficients array? */
+ if (ogen->coefficients)
+ gen->coefficients = MEM_dupallocN(ogen->coefficients);
}
static void fcm_generator_new_data(void *mdata)
{
- FMod_Generator *data = (FMod_Generator *)mdata;
- float *cp;
-
- /* set default generator to be linear 0-1 (gradient = 1, y-offset = 0) */
- data->poly_order = 1;
- data->arraysize = 2;
- cp = data->coefficients = MEM_callocN(sizeof(float) * 2, "FMod_Generator_Coefs");
- cp[0] = 0; // y-offset
- cp[1] = 1; // gradient
+ FMod_Generator *data = (FMod_Generator *)mdata;
+ float *cp;
+
+ /* set default generator to be linear 0-1 (gradient = 1, y-offset = 0) */
+ data->poly_order = 1;
+ data->arraysize = 2;
+ cp = data->coefficients = MEM_callocN(sizeof(float) * 2, "FMod_Generator_Coefs");
+ cp[0] = 0; // y-offset
+ cp[1] = 1; // gradient
}
static void fcm_generator_verify(FModifier *fcm)
{
- FMod_Generator *data = (FMod_Generator *)fcm->data;
-
- /* requirements depend on mode */
- switch (data->mode) {
- case FCM_GENERATOR_POLYNOMIAL: /* expanded polynomial expression */
- {
- const int arraysize_new = data->poly_order + 1;
- /* arraysize needs to be order+1, so resize if not */
- if (data->arraysize != arraysize_new) {
- data->coefficients = MEM_recallocN(data->coefficients,
- sizeof(float) * arraysize_new);
- data->arraysize = arraysize_new;
- }
- break;
- }
- case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* expanded polynomial expression */
- {
- const int arraysize_new = data->poly_order * 2;
- /* arraysize needs to be (2 * order), so resize if not */
- if (data->arraysize != arraysize_new) {
- data->coefficients = MEM_recallocN(data->coefficients,
- sizeof(float) * arraysize_new);
- data->arraysize = arraysize_new;
- }
- break;
- }
- }
+ FMod_Generator *data = (FMod_Generator *)fcm->data;
+
+ /* requirements depend on mode */
+ switch (data->mode) {
+ case FCM_GENERATOR_POLYNOMIAL: /* expanded polynomial expression */
+ {
+ const int arraysize_new = data->poly_order + 1;
+ /* arraysize needs to be order+1, so resize if not */
+ if (data->arraysize != arraysize_new) {
+ data->coefficients = MEM_recallocN(data->coefficients, sizeof(float) * arraysize_new);
+ data->arraysize = arraysize_new;
+ }
+ break;
+ }
+ case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* expanded polynomial expression */
+ {
+ const int arraysize_new = data->poly_order * 2;
+ /* arraysize needs to be (2 * order), so resize if not */
+ if (data->arraysize != arraysize_new) {
+ data->coefficients = MEM_recallocN(data->coefficients, sizeof(float) * arraysize_new);
+ data->arraysize = arraysize_new;
+ }
+ break;
+ }
+ }
}
-static void fcm_generator_evaluate(FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float evaltime)
+static void fcm_generator_evaluate(FCurve *UNUSED(fcu),
+ FModifier *fcm,
+ float *cvalue,
+ float evaltime)
{
- FMod_Generator *data = (FMod_Generator *)fcm->data;
-
- /* behavior depends on mode
- * NOTE: the data in its default state is fine too
- */
- switch (data->mode) {
- case FCM_GENERATOR_POLYNOMIAL: /* expanded polynomial expression */
- {
- /* we overwrite cvalue with the sum of the polynomial */
- float *powers = MEM_callocN(sizeof(float) * data->arraysize, "Poly Powers");
- float value = 0.0f;
- unsigned int i;
-
- /* for each x^n, precalculate value based on previous one first... this should be
- * faster that calling pow() for each entry
- */
- for (i = 0; i < data->arraysize; i++) {
- /* first entry is x^0 = 1, otherwise, calculate based on previous */
- if (i)
- powers[i] = powers[i - 1] * evaltime;
- else
- powers[0] = 1;
- }
-
- /* for each coefficient, add to value, which we'll write to *cvalue in one go */
- for (i = 0; i < data->arraysize; i++)
- value += data->coefficients[i] * powers[i];
-
- /* only if something changed, write *cvalue in one go */
- if (data->poly_order) {
- if (data->flag & FCM_GENERATOR_ADDITIVE)
- *cvalue += value;
- else
- *cvalue = value;
- }
-
- /* cleanup */
- if (powers)
- MEM_freeN(powers);
- break;
- }
- case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* Factorized polynomial */
- {
- float value = 1.0f, *cp = NULL;
- unsigned int i;
-
- /* for each coefficient pair, solve for that bracket before accumulating in value by multiplying */
- for (cp = data->coefficients, i = 0; (cp) && (i < (unsigned int)data->poly_order); cp += 2, i++)
- value *= (cp[0] * evaltime + cp[1]);
-
- /* only if something changed, write *cvalue in one go */
- if (data->poly_order) {
- if (data->flag & FCM_GENERATOR_ADDITIVE)
- *cvalue += value;
- else
- *cvalue = value;
- }
- break;
- }
- }
+ FMod_Generator *data = (FMod_Generator *)fcm->data;
+
+ /* behavior depends on mode
+ * NOTE: the data in its default state is fine too
+ */
+ switch (data->mode) {
+ case FCM_GENERATOR_POLYNOMIAL: /* expanded polynomial expression */
+ {
+ /* we overwrite cvalue with the sum of the polynomial */
+ float *powers = MEM_callocN(sizeof(float) * data->arraysize, "Poly Powers");
+ float value = 0.0f;
+ unsigned int i;
+
+ /* for each x^n, precalculate value based on previous one first... this should be
+ * faster that calling pow() for each entry
+ */
+ for (i = 0; i < data->arraysize; i++) {
+ /* first entry is x^0 = 1, otherwise, calculate based on previous */
+ if (i)
+ powers[i] = powers[i - 1] * evaltime;
+ else
+ powers[0] = 1;
+ }
+
+ /* for each coefficient, add to value, which we'll write to *cvalue in one go */
+ for (i = 0; i < data->arraysize; i++)
+ value += data->coefficients[i] * powers[i];
+
+ /* only if something changed, write *cvalue in one go */
+ if (data->poly_order) {
+ if (data->flag & FCM_GENERATOR_ADDITIVE)
+ *cvalue += value;
+ else
+ *cvalue = value;
+ }
+
+ /* cleanup */
+ if (powers)
+ MEM_freeN(powers);
+ break;
+ }
+ case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* Factorized polynomial */
+ {
+ float value = 1.0f, *cp = NULL;
+ unsigned int i;
+
+ /* for each coefficient pair, solve for that bracket before accumulating in value by multiplying */
+ for (cp = data->coefficients, i = 0; (cp) && (i < (unsigned int)data->poly_order);
+ cp += 2, i++)
+ value *= (cp[0] * evaltime + cp[1]);
+
+ /* only if something changed, write *cvalue in one go */
+ if (data->poly_order) {
+ if (data->flag & FCM_GENERATOR_ADDITIVE)
+ *cvalue += value;
+ else
+ *cvalue = value;
+ }
+ break;
+ }
+ }
}
static FModifierTypeInfo FMI_GENERATOR = {
- FMODIFIER_TYPE_GENERATOR, /* type */
- sizeof(FMod_Generator), /* size */
- FMI_TYPE_GENERATE_CURVE, /* action type */
- FMI_REQUIRES_NOTHING, /* requirements */
- N_("Generator"), /* name */
- "FMod_Generator", /* struct name */
- fcm_generator_free, /* free data */
- fcm_generator_copy, /* copy data */
- fcm_generator_new_data, /* new data */
- fcm_generator_verify, /* verify */
- NULL, /* evaluate time */
- fcm_generator_evaluate, /* evaluate */
- NULL, /* evaluate time with storage */
- NULL, /* evaluate with storage */
+ FMODIFIER_TYPE_GENERATOR, /* type */
+ sizeof(FMod_Generator), /* size */
+ FMI_TYPE_GENERATE_CURVE, /* action type */
+ FMI_REQUIRES_NOTHING, /* requirements */
+ N_("Generator"), /* name */
+ "FMod_Generator", /* struct name */
+ fcm_generator_free, /* free data */
+ fcm_generator_copy, /* copy data */
+ fcm_generator_new_data, /* new data */
+ fcm_generator_verify, /* verify */
+ NULL, /* evaluate time */
+ fcm_generator_evaluate, /* evaluate */
+ NULL, /* evaluate time with storage */
+ NULL, /* evaluate with storage */
};
/* Built-In Function Generator F-Curve Modifier --------------------------- */
@@ -263,11 +265,11 @@ static FModifierTypeInfo FMI_GENERATOR = {
static void fcm_fn_generator_new_data(void *mdata)
{
- FMod_FunctionGenerator *data = (FMod_FunctionGenerator *)mdata;
+ FMod_FunctionGenerator *data = (FMod_FunctionGenerator *)mdata;
- /* set amplitude and phase multiplier to 1.0f so that something is generated */
- data->amplitude = 1.0f;
- data->phase_multiplier = 1.0f;
+ /* set amplitude and phase multiplier to 1.0f so that something is generated */
+ data->amplitude = 1.0f;
+ data->phase_multiplier = 1.0f;
}
/* Unary 'normalized sine' function
@@ -276,210 +278,216 @@ static void fcm_fn_generator_new_data(void *mdata)
*/
static double sinc(double x)
{
- if (fabs(x) < 0.0001)
- return 1.0;
- else
- return sin(M_PI * x) / (M_PI * x);
+ if (fabs(x) < 0.0001)
+ return 1.0;
+ else
+ return sin(M_PI * x) / (M_PI * x);
}
-static void fcm_fn_generator_evaluate(FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float evaltime)
+static void fcm_fn_generator_evaluate(FCurve *UNUSED(fcu),
+ FModifier *fcm,
+ float *cvalue,
+ float evaltime)
{
- FMod_FunctionGenerator *data = (FMod_FunctionGenerator *)fcm->data;
- double arg = data->phase_multiplier * evaltime + data->phase_offset;
- double (*fn)(double v) = NULL;
-
- /* get function pointer to the func to use:
- * WARNING: must perform special argument validation hereto guard against crashes
- */
- switch (data->type) {
- /* simple ones */
- case FCM_GENERATOR_FN_SIN: /* sine wave */
- fn = sin;
- break;
- case FCM_GENERATOR_FN_COS: /* cosine wave */
- fn = cos;
- break;
- case FCM_GENERATOR_FN_SINC: /* normalized sine wave */
- fn = sinc;
- break;
-
- /* validation required */
- case FCM_GENERATOR_FN_TAN: /* tangent wave */
- {
- /* check that argument is not on one of the discontinuities (i.e. 90deg, 270 deg, etc) */
- if (IS_EQ(fmod((arg - M_PI_2), M_PI), 0.0)) {
- if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
- *cvalue = 0.0f; /* no value possible here */
- }
- else
- fn = tan;
- break;
- }
- case FCM_GENERATOR_FN_LN: /* natural log */
- {
- /* check that value is greater than 1? */
- if (arg > 1.0) {
- fn = log;
- }
- else {
- if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
- *cvalue = 0.0f; /* no value possible here */
- }
- break;
- }
- case FCM_GENERATOR_FN_SQRT: /* square root */
- {
- /* no negative numbers */
- if (arg > 0.0) {
- fn = sqrt;
- }
- else {
- if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
- *cvalue = 0.0f; /* no value possible here */
- }
- break;
- }
- default:
- CLOG_ERROR(&LOG, "Invalid Function-Generator for F-Modifier - %d", data->type);
- break;
-
- }
-
- /* execute function callback to set value if appropriate */
- if (fn) {
- float value = (float)(data->amplitude * (float)fn(arg) + data->value_offset);
-
- if (data->flag & FCM_GENERATOR_ADDITIVE)
- *cvalue += value;
- else
- *cvalue = value;
- }
+ FMod_FunctionGenerator *data = (FMod_FunctionGenerator *)fcm->data;
+ double arg = data->phase_multiplier * evaltime + data->phase_offset;
+ double (*fn)(double v) = NULL;
+
+ /* get function pointer to the func to use:
+ * WARNING: must perform special argument validation hereto guard against crashes
+ */
+ switch (data->type) {
+ /* simple ones */
+ case FCM_GENERATOR_FN_SIN: /* sine wave */
+ fn = sin;
+ break;
+ case FCM_GENERATOR_FN_COS: /* cosine wave */
+ fn = cos;
+ break;
+ case FCM_GENERATOR_FN_SINC: /* normalized sine wave */
+ fn = sinc;
+ break;
+
+ /* validation required */
+ case FCM_GENERATOR_FN_TAN: /* tangent wave */
+ {
+ /* check that argument is not on one of the discontinuities (i.e. 90deg, 270 deg, etc) */
+ if (IS_EQ(fmod((arg - M_PI_2), M_PI), 0.0)) {
+ if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
+ *cvalue = 0.0f; /* no value possible here */
+ }
+ else
+ fn = tan;
+ break;
+ }
+ case FCM_GENERATOR_FN_LN: /* natural log */
+ {
+ /* check that value is greater than 1? */
+ if (arg > 1.0) {
+ fn = log;
+ }
+ else {
+ if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
+ *cvalue = 0.0f; /* no value possible here */
+ }
+ break;
+ }
+ case FCM_GENERATOR_FN_SQRT: /* square root */
+ {
+ /* no negative numbers */
+ if (arg > 0.0) {
+ fn = sqrt;
+ }
+ else {
+ if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
+ *cvalue = 0.0f; /* no value possible here */
+ }
+ break;
+ }
+ default:
+ CLOG_ERROR(&LOG, "Invalid Function-Generator for F-Modifier - %d", data->type);
+ break;
+ }
+
+ /* execute function callback to set value if appropriate */
+ if (fn) {
+ float value = (float)(data->amplitude * (float)fn(arg) + data->value_offset);
+
+ if (data->flag & FCM_GENERATOR_ADDITIVE)
+ *cvalue += value;
+ else
+ *cvalue = value;
+ }
}
static FModifierTypeInfo FMI_FN_GENERATOR = {
- FMODIFIER_TYPE_FN_GENERATOR, /* type */
- sizeof(FMod_FunctionGenerator), /* size */
- FMI_TYPE_GENERATE_CURVE, /* action type */
- FMI_REQUIRES_NOTHING, /* requirements */
- N_("Built-In Function"), /* name */
- "FMod_FunctionGenerator", /* struct name */
- NULL, /* free data */
- NULL, /* copy data */
- fcm_fn_generator_new_data, /* new data */
- NULL, /* verify */
- NULL, /* evaluate time */
- fcm_fn_generator_evaluate, /* evaluate */
- NULL, /* evaluate time with storage */
- NULL, /* evaluate with storage */
+ FMODIFIER_TYPE_FN_GENERATOR, /* type */
+ sizeof(FMod_FunctionGenerator), /* size */
+ FMI_TYPE_GENERATE_CURVE, /* action type */
+ FMI_REQUIRES_NOTHING, /* requirements */
+ N_("Built-In Function"), /* name */
+ "FMod_FunctionGenerator", /* struct name */
+ NULL, /* free data */
+ NULL, /* copy data */
+ fcm_fn_generator_new_data, /* new data */
+ NULL, /* verify */
+ NULL, /* evaluate time */
+ fcm_fn_generator_evaluate, /* evaluate */
+ NULL, /* evaluate time with storage */
+ NULL, /* evaluate with storage */
};
/* Envelope F-Curve Modifier --------------------------- */
static void fcm_envelope_free(FModifier *fcm)
{
- FMod_Envelope *env = (FMod_Envelope *)fcm->data;
+ FMod_Envelope *env = (FMod_Envelope *)fcm->data;
- /* free envelope data array */
- if (env->data)
- MEM_freeN(env->data);
+ /* free envelope data array */
+ if (env->data)
+ MEM_freeN(env->data);
}
static void fcm_envelope_copy(FModifier *fcm, const FModifier *src)
{
- FMod_Envelope *env = (FMod_Envelope *)fcm->data;
- FMod_Envelope *oenv = (FMod_Envelope *)src->data;
+ FMod_Envelope *env = (FMod_Envelope *)fcm->data;
+ FMod_Envelope *oenv = (FMod_Envelope *)src->data;
- /* copy envelope data array */
- if (oenv->data)
- env->data = MEM_dupallocN(oenv->data);
+ /* copy envelope data array */
+ if (oenv->data)
+ env->data = MEM_dupallocN(oenv->data);
}
static void fcm_envelope_new_data(void *mdata)
{
- FMod_Envelope *env = (FMod_Envelope *)mdata;
+ FMod_Envelope *env = (FMod_Envelope *)mdata;
- /* set default min/max ranges */
- env->min = -1.0f;
- env->max = 1.0f;
+ /* set default min/max ranges */
+ env->min = -1.0f;
+ env->max = 1.0f;
}
static void fcm_envelope_verify(FModifier *fcm)
{
- FMod_Envelope *env = (FMod_Envelope *)fcm->data;
+ FMod_Envelope *env = (FMod_Envelope *)fcm->data;
- /* if the are points, perform bubble-sort on them, as user may have changed the order */
- if (env->data) {
- /* XXX todo... */
- }
+ /* if the are points, perform bubble-sort on them, as user may have changed the order */
+ if (env->data) {
+ /* XXX todo... */
+ }
}
-static void fcm_envelope_evaluate(FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float evaltime)
+static void fcm_envelope_evaluate(FCurve *UNUSED(fcu),
+ FModifier *fcm,
+ float *cvalue,
+ float evaltime)
{
- FMod_Envelope *env = (FMod_Envelope *)fcm->data;
- FCM_EnvelopeData *fed, *prevfed, *lastfed;
- float min = 0.0f, max = 0.0f, fac = 0.0f;
- int a;
-
- /* get pointers */
- if (env->data == NULL) return;
- prevfed = env->data;
- fed = prevfed + 1;
- lastfed = prevfed + (env->totvert - 1);
-
- /* get min/max values for envelope at evaluation time (relative to mid-value) */
- if (prevfed->time >= evaltime) {
- /* before or on first sample, so just extend value */
- min = prevfed->min;
- max = prevfed->max;
- }
- else if (lastfed->time <= evaltime) {
- /* after or on last sample, so just extend value */
- min = lastfed->min;
- max = lastfed->max;
- }
- else {
- /* evaltime occurs somewhere between segments */
- /* TODO: implement binary search for this to make it faster? */
- for (a = 0; prevfed && fed && (a < env->totvert - 1); a++, prevfed = fed, fed++) {
- /* evaltime occurs within the interval defined by these two envelope points */
- if ((prevfed->time <= evaltime) && (fed->time >= evaltime)) {
- float afac, bfac, diff;
-
- diff = fed->time - prevfed->time;
- afac = (evaltime - prevfed->time) / diff;
- bfac = (fed->time - evaltime) / diff;
-
- min = bfac * prevfed->min + afac * fed->min;
- max = bfac * prevfed->max + afac * fed->max;
-
- break;
- }
- }
- }
-
- /* adjust *cvalue
- * - fac is the ratio of how the current y-value corresponds to the reference range
- * - thus, the new value is found by mapping the old range to the new!
- */
- fac = (*cvalue - (env->midval + env->min)) / (env->max - env->min);
- *cvalue = min + fac * (max - min);
+ FMod_Envelope *env = (FMod_Envelope *)fcm->data;
+ FCM_EnvelopeData *fed, *prevfed, *lastfed;
+ float min = 0.0f, max = 0.0f, fac = 0.0f;
+ int a;
+
+ /* get pointers */
+ if (env->data == NULL)
+ return;
+ prevfed = env->data;
+ fed = prevfed + 1;
+ lastfed = prevfed + (env->totvert - 1);
+
+ /* get min/max values for envelope at evaluation time (relative to mid-value) */
+ if (prevfed->time >= evaltime) {
+ /* before or on first sample, so just extend value */
+ min = prevfed->min;
+ max = prevfed->max;
+ }
+ else if (lastfed->time <= evaltime) {
+ /* after or on last sample, so just extend value */
+ min = lastfed->min;
+ max = lastfed->max;
+ }
+ else {
+ /* evaltime occurs somewhere between segments */
+ /* TODO: implement binary search for this to make it faster? */
+ for (a = 0; prevfed && fed && (a < env->totvert - 1); a++, prevfed = fed, fed++) {
+ /* evaltime occurs within the interval defined by these two envelope points */
+ if ((prevfed->time <= evaltime) && (fed->time >= evaltime)) {
+ float afac, bfac, diff;
+
+ diff = fed->time - prevfed->time;
+ afac = (evaltime - prevfed->time) / diff;
+ bfac = (fed->time - evaltime) / diff;
+
+ min = bfac * prevfed->min + afac * fed->min;
+ max = bfac * prevfed->max + afac * fed->max;
+
+ break;
+ }
+ }
+ }
+
+ /* adjust *cvalue
+ * - fac is the ratio of how the current y-value corresponds to the reference range
+ * - thus, the new value is found by mapping the old range to the new!
+ */
+ fac = (*cvalue - (env->midval + env->min)) / (env->max - env->min);
+ *cvalue = min + fac * (max - min);
}
static FModifierTypeInfo FMI_ENVELOPE = {
- FMODIFIER_TYPE_ENVELOPE, /* type */
- sizeof(FMod_Envelope), /* size */
- FMI_TYPE_REPLACE_VALUES, /* action type */
- 0, /* requirements */
- N_("Envelope"), /* name */
- "FMod_Envelope", /* struct name */
- fcm_envelope_free, /* free data */
- fcm_envelope_copy, /* copy data */
- fcm_envelope_new_data, /* new data */
- fcm_envelope_verify, /* verify */
- NULL, /* evaluate time */
- fcm_envelope_evaluate, /* evaluate */
- NULL, /* evaluate time with storage */
- NULL, /* evaluate with storage */
+ FMODIFIER_TYPE_ENVELOPE, /* type */
+ sizeof(FMod_Envelope), /* size */
+ FMI_TYPE_REPLACE_VALUES, /* action type */
+ 0, /* requirements */
+ N_("Envelope"), /* name */
+ "FMod_Envelope", /* struct name */
+ fcm_envelope_free, /* free data */
+ fcm_envelope_copy, /* copy data */
+ fcm_envelope_new_data, /* new data */
+ fcm_envelope_verify, /* verify */
+ NULL, /* evaluate time */
+ fcm_envelope_evaluate, /* evaluate */
+ NULL, /* evaluate time with storage */
+ NULL, /* evaluate with storage */
};
/* exported function for finding points */
@@ -489,85 +497,92 @@ static FModifierTypeInfo FMI_ENVELOPE = {
*/
#define BINARYSEARCH_FRAMEEQ_THRESH 0.0001f
-int BKE_fcm_envelope_find_index(FCM_EnvelopeData array[], float frame, int arraylen, bool *r_exists)
+int BKE_fcm_envelope_find_index(FCM_EnvelopeData array[],
+ float frame,
+ int arraylen,
+ bool *r_exists)
{
- int start = 0, end = arraylen;
- int loopbreaker = 0, maxloop = arraylen * 2;
-
- /* initialize exists-flag first */
- *r_exists = false;
-
- /* sneaky optimizations (don't go through searching process if...):
- * - keyframe to be added is to be added out of current bounds
- * - keyframe to be added would replace one of the existing ones on bounds
- */
- if ((arraylen <= 0) || (array == NULL)) {
- CLOG_WARN(&LOG, "encountered invalid array");
- return 0;
- }
- else {
- /* check whether to add before/after/on */
- float framenum;
-
- /* 'First' Point (when only one point, this case is used) */
- framenum = array[0].time;
- if (IS_EQT(frame, framenum, BINARYSEARCH_FRAMEEQ_THRESH)) {
- *r_exists = true;
- return 0;
- }
- else if (frame < framenum) {
- return 0;
- }
-
- /* 'Last' Point */
- framenum = array[(arraylen - 1)].time;
- if (IS_EQT(frame, framenum, BINARYSEARCH_FRAMEEQ_THRESH)) {
- *r_exists = true;
- return (arraylen - 1);
- }
- else if (frame > framenum) {
- return arraylen;
- }
- }
-
-
- /* most of the time, this loop is just to find where to put it
- * - 'loopbreaker' is just here to prevent infinite loops
- */
- for (loopbreaker = 0; (start <= end) && (loopbreaker < maxloop); loopbreaker++) {
- /* compute and get midpoint */
- int mid = start + ((end - start) / 2); /* we calculate the midpoint this way to avoid int overflows... */
- float midfra = array[mid].time;
-
- /* check if exactly equal to midpoint */
- if (IS_EQT(frame, midfra, BINARYSEARCH_FRAMEEQ_THRESH)) {
- *r_exists = true;
- return mid;
- }
-
- /* repeat in upper/lower half */
- if (frame > midfra) {
- start = mid + 1;
- }
- else if (frame < midfra) {
- end = mid - 1;
- }
- }
-
- /* print error if loop-limit exceeded */
- if (loopbreaker == (maxloop - 1)) {
- CLOG_ERROR(&LOG, "binary search was taking too long");
-
- // include debug info
- CLOG_ERROR(&LOG, "\tround = %d: start = %d, end = %d, arraylen = %d", loopbreaker, start, end, arraylen);
- }
-
- /* not found, so return where to place it */
- return start;
+ int start = 0, end = arraylen;
+ int loopbreaker = 0, maxloop = arraylen * 2;
+
+ /* initialize exists-flag first */
+ *r_exists = false;
+
+ /* sneaky optimizations (don't go through searching process if...):
+ * - keyframe to be added is to be added out of current bounds
+ * - keyframe to be added would replace one of the existing ones on bounds
+ */
+ if ((arraylen <= 0) || (array == NULL)) {
+ CLOG_WARN(&LOG, "encountered invalid array");
+ return 0;
+ }
+ else {
+ /* check whether to add before/after/on */
+ float framenum;
+
+ /* 'First' Point (when only one point, this case is used) */
+ framenum = array[0].time;
+ if (IS_EQT(frame, framenum, BINARYSEARCH_FRAMEEQ_THRESH)) {
+ *r_exists = true;
+ return 0;
+ }
+ else if (frame < framenum) {
+ return 0;
+ }
+
+ /* 'Last' Point */
+ framenum = array[(arraylen - 1)].time;
+ if (IS_EQT(frame, framenum, BINARYSEARCH_FRAMEEQ_THRESH)) {
+ *r_exists = true;
+ return (arraylen - 1);
+ }
+ else if (frame > framenum) {
+ return arraylen;
+ }
+ }
+
+ /* most of the time, this loop is just to find where to put it
+ * - 'loopbreaker' is just here to prevent infinite loops
+ */
+ for (loopbreaker = 0; (start <= end) && (loopbreaker < maxloop); loopbreaker++) {
+ /* compute and get midpoint */
+ int mid = start + ((end - start) /
+ 2); /* we calculate the midpoint this way to avoid int overflows... */
+ float midfra = array[mid].time;
+
+ /* check if exactly equal to midpoint */
+ if (IS_EQT(frame, midfra, BINARYSEARCH_FRAMEEQ_THRESH)) {
+ *r_exists = true;
+ return mid;
+ }
+
+ /* repeat in upper/lower half */
+ if (frame > midfra) {
+ start = mid + 1;
+ }
+ else if (frame < midfra) {
+ end = mid - 1;
+ }
+ }
+
+ /* print error if loop-limit exceeded */
+ if (loopbreaker == (maxloop - 1)) {
+ CLOG_ERROR(&LOG, "binary search was taking too long");
+
+ // include debug info
+ CLOG_ERROR(&LOG,
+ "\tround = %d: start = %d, end = %d, arraylen = %d",
+ loopbreaker,
+ start,
+ end,
+ arraylen);
+ }
+
+ /* not found, so return where to place it */
+ return start;
}
#undef BINARYSEARCH_FRAMEEQ_THRESH
-
/* Cycles F-Curve Modifier --------------------------- */
/* This modifier changes evaltime to something that exists within the curve's frame-range,
@@ -584,410 +599,429 @@ int BKE_fcm_envelope_find_index(FCM_EnvelopeData array[], float frame, int array
/* temp data used during evaluation */
typedef struct tFCMED_Cycles {
- float cycyofs; /* y-offset to apply */
+ float cycyofs; /* y-offset to apply */
} tFCMED_Cycles;
static void fcm_cycles_new_data(void *mdata)
{
- FMod_Cycles *data = (FMod_Cycles *)mdata;
+ FMod_Cycles *data = (FMod_Cycles *)mdata;
- /* turn on cycles by default */
- data->before_mode = data->after_mode = FCM_EXTRAPOLATE_CYCLIC;
+ /* turn on cycles by default */
+ data->before_mode = data->after_mode = FCM_EXTRAPOLATE_CYCLIC;
}
-static float fcm_cycles_time(FModifierStackStorage *storage, FCurve *fcu, FModifier *fcm,
- float UNUSED(cvalue), float evaltime)
+static float fcm_cycles_time(FModifierStackStorage *storage,
+ FCurve *fcu,
+ FModifier *fcm,
+ float UNUSED(cvalue),
+ float evaltime)
{
- FMod_Cycles *data = (FMod_Cycles *)fcm->data;
- float prevkey[2], lastkey[2], cycyofs = 0.0f;
- short side = 0, mode = 0;
- int cycles = 0;
- float ofs = 0;
-
- /* check if modifier is first in stack, otherwise disable ourself... */
- /* FIXME... */
- if (fcm->prev) {
- fcm->flag |= FMODIFIER_FLAG_DISABLED;
- return evaltime;
- }
-
- /* calculate new evaltime due to cyclic interpolation */
- if (fcu && fcu->bezt) {
- BezTriple *prevbezt = fcu->bezt;
- BezTriple *lastbezt = prevbezt + fcu->totvert - 1;
-
- prevkey[0] = prevbezt->vec[1][0];
- prevkey[1] = prevbezt->vec[1][1];
-
- lastkey[0] = lastbezt->vec[1][0];
- lastkey[1] = lastbezt->vec[1][1];
- }
- else if (fcu && fcu->fpt) {
- FPoint *prevfpt = fcu->fpt;
- FPoint *lastfpt = prevfpt + fcu->totvert - 1;
-
- prevkey[0] = prevfpt->vec[0];
- prevkey[1] = prevfpt->vec[1];
-
- lastkey[0] = lastfpt->vec[0];
- lastkey[1] = lastfpt->vec[1];
- }
- else
- return evaltime;
-
- /* check if modifier will do anything
- * 1) if in data range, definitely don't do anything
- * 2) if before first frame or after last frame, make sure some cycling is in use
- */
- if (evaltime < prevkey[0]) {
- if (data->before_mode) {
- side = -1;
- mode = data->before_mode;
- cycles = data->before_cycles;
- ofs = prevkey[0];
- }
- }
- else if (evaltime > lastkey[0]) {
- if (data->after_mode) {
- side = 1;
- mode = data->after_mode;
- cycles = data->after_cycles;
- ofs = lastkey[0];
- }
- }
- if ((ELEM(0, side, mode)))
- return evaltime;
-
- /* find relative place within a cycle */
- {
- float cycdx = 0, cycdy = 0;
- float cycle = 0, cyct = 0;
-
- /* calculate period and amplitude (total height) of a cycle */
- cycdx = lastkey[0] - prevkey[0];
- cycdy = lastkey[1] - prevkey[1];
-
- /* check if cycle is infinitely small, to be point of being impossible to use */
- if (cycdx == 0)
- return evaltime;
-
- /* calculate the 'number' of the cycle */
- cycle = ((float)side * (evaltime - ofs) / cycdx);
-
- /* calculate the time inside the cycle */
- cyct = fmod(evaltime - ofs, cycdx);
-
- /* check that cyclic is still enabled for the specified time */
- if (cycles == 0) {
- /* catch this case so that we don't exit when we have (cycles = 0)
- * as this indicates infinite cycles...
- */
- }
- else if (cycle > cycles) {
- /* we are too far away from range to evaluate
- * TODO: but we should still hold last value...
- */
- return evaltime;
- }
-
- /* check if 'cyclic extrapolation', and thus calculate y-offset for this cycle */
- if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) {
- if (side < 0)
- cycyofs = (float)floor((evaltime - ofs) / cycdx);
- else
- cycyofs = (float)ceil((evaltime - ofs) / cycdx);
- cycyofs *= cycdy;
- }
-
- /* special case for cycle start/end */
- if (cyct == 0.0f) {
- evaltime = (side == 1 ? lastkey[0] : prevkey[0]);
-
- if ((mode == FCM_EXTRAPOLATE_MIRROR) && ((int)cycle % 2))
- evaltime = (side == 1 ? prevkey[0] : lastkey[0]);
- }
- /* calculate where in the cycle we are (overwrite evaltime to reflect this) */
- else if ((mode == FCM_EXTRAPOLATE_MIRROR) && ((int)(cycle + 1) % 2)) {
- /* when 'mirror' option is used and cycle number is odd, this cycle is played in reverse
- * - for 'before' extrapolation, we need to flip in a different way, otherwise values past
- * then end of the curve get referenced (result of fmod will be negative, and with different phase)
- */
- if (side < 0)
- evaltime = prevkey[0] - cyct;
- else
- evaltime = lastkey[0] - cyct;
- }
- else {
- /* the cycle is played normally... */
- evaltime = prevkey[0] + cyct;
- }
- if (evaltime < prevkey[0]) evaltime += cycdx;
- }
-
- /* store temp data if needed */
- if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) {
- tFCMED_Cycles *edata;
-
- /* for now, this is just a float, but we could get more stuff... */
- edata = MEM_callocN(sizeof(tFCMED_Cycles), "tFCMED_Cycles");
- edata->cycyofs = cycyofs;
-
- fmodifiers_storage_put(storage, fcm, edata);
- }
-
- /* return the new frame to evaluate */
- return evaltime;
+ FMod_Cycles *data = (FMod_Cycles *)fcm->data;
+ float prevkey[2], lastkey[2], cycyofs = 0.0f;
+ short side = 0, mode = 0;
+ int cycles = 0;
+ float ofs = 0;
+
+ /* check if modifier is first in stack, otherwise disable ourself... */
+ /* FIXME... */
+ if (fcm->prev) {
+ fcm->flag |= FMODIFIER_FLAG_DISABLED;
+ return evaltime;
+ }
+
+ /* calculate new evaltime due to cyclic interpolation */
+ if (fcu && fcu->bezt) {
+ BezTriple *prevbezt = fcu->bezt;
+ BezTriple *lastbezt = prevbezt + fcu->totvert - 1;
+
+ prevkey[0] = prevbezt->vec[1][0];
+ prevkey[1] = prevbezt->vec[1][1];
+
+ lastkey[0] = lastbezt->vec[1][0];
+ lastkey[1] = lastbezt->vec[1][1];
+ }
+ else if (fcu && fcu->fpt) {
+ FPoint *prevfpt = fcu->fpt;
+ FPoint *lastfpt = prevfpt + fcu->totvert - 1;
+
+ prevkey[0] = prevfpt->vec[0];
+ prevkey[1] = prevfpt->vec[1];
+
+ lastkey[0] = lastfpt->vec[0];
+ lastkey[1] = lastfpt->vec[1];
+ }
+ else
+ return evaltime;
+
+ /* check if modifier will do anything
+ * 1) if in data range, definitely don't do anything
+ * 2) if before first frame or after last frame, make sure some cycling is in use
+ */
+ if (evaltime < prevkey[0]) {
+ if (data->before_mode) {
+ side = -1;
+ mode = data->before_mode;
+ cycles = data->before_cycles;
+ ofs = prevkey[0];
+ }
+ }
+ else if (evaltime > lastkey[0]) {
+ if (data->after_mode) {
+ side = 1;
+ mode = data->after_mode;
+ cycles = data->after_cycles;
+ ofs = lastkey[0];
+ }
+ }
+ if ((ELEM(0, side, mode)))
+ return evaltime;
+
+ /* find relative place within a cycle */
+ {
+ float cycdx = 0, cycdy = 0;
+ float cycle = 0, cyct = 0;
+
+ /* calculate period and amplitude (total height) of a cycle */
+ cycdx = lastkey[0] - prevkey[0];
+ cycdy = lastkey[1] - prevkey[1];
+
+ /* check if cycle is infinitely small, to be point of being impossible to use */
+ if (cycdx == 0)
+ return evaltime;
+
+ /* calculate the 'number' of the cycle */
+ cycle = ((float)side * (evaltime - ofs) / cycdx);
+
+ /* calculate the time inside the cycle */
+ cyct = fmod(evaltime - ofs, cycdx);
+
+ /* check that cyclic is still enabled for the specified time */
+ if (cycles == 0) {
+ /* catch this case so that we don't exit when we have (cycles = 0)
+ * as this indicates infinite cycles...
+ */
+ }
+ else if (cycle > cycles) {
+ /* we are too far away from range to evaluate
+ * TODO: but we should still hold last value...
+ */
+ return evaltime;
+ }
+
+ /* check if 'cyclic extrapolation', and thus calculate y-offset for this cycle */
+ if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) {
+ if (side < 0)
+ cycyofs = (float)floor((evaltime - ofs) / cycdx);
+ else
+ cycyofs = (float)ceil((evaltime - ofs) / cycdx);
+ cycyofs *= cycdy;
+ }
+
+ /* special case for cycle start/end */
+ if (cyct == 0.0f) {
+ evaltime = (side == 1 ? lastkey[0] : prevkey[0]);
+
+ if ((mode == FCM_EXTRAPOLATE_MIRROR) && ((int)cycle % 2))
+ evaltime = (side == 1 ? prevkey[0] : lastkey[0]);
+ }
+ /* calculate where in the cycle we are (overwrite evaltime to reflect this) */
+ else if ((mode == FCM_EXTRAPOLATE_MIRROR) && ((int)(cycle + 1) % 2)) {
+ /* when 'mirror' option is used and cycle number is odd, this cycle is played in reverse
+ * - for 'before' extrapolation, we need to flip in a different way, otherwise values past
+ * then end of the curve get referenced (result of fmod will be negative, and with different phase)
+ */
+ if (side < 0)
+ evaltime = prevkey[0] - cyct;
+ else
+ evaltime = lastkey[0] - cyct;
+ }
+ else {
+ /* the cycle is played normally... */
+ evaltime = prevkey[0] + cyct;
+ }
+ if (evaltime < prevkey[0])
+ evaltime += cycdx;
+ }
+
+ /* store temp data if needed */
+ if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) {
+ tFCMED_Cycles *edata;
+
+ /* for now, this is just a float, but we could get more stuff... */
+ edata = MEM_callocN(sizeof(tFCMED_Cycles), "tFCMED_Cycles");
+ edata->cycyofs = cycyofs;
+
+ fmodifiers_storage_put(storage, fcm, edata);
+ }
+
+ /* return the new frame to evaluate */
+ return evaltime;
}
-static void fcm_cycles_evaluate(FModifierStackStorage *storage, FCurve *UNUSED(fcu),
- FModifier *fcm, float *cvalue, float UNUSED(evaltime))
+static void fcm_cycles_evaluate(FModifierStackStorage *storage,
+ FCurve *UNUSED(fcu),
+ FModifier *fcm,
+ float *cvalue,
+ float UNUSED(evaltime))
{
- tFCMED_Cycles *edata = fmodifiers_storage_get(storage, fcm);
+ tFCMED_Cycles *edata = fmodifiers_storage_get(storage, fcm);
- /* use temp data */
- if (edata) {
- /* add cyclic offset - no need to check for now, otherwise the data wouldn't exist! */
- *cvalue += edata->cycyofs;
+ /* use temp data */
+ if (edata) {
+ /* add cyclic offset - no need to check for now, otherwise the data wouldn't exist! */
+ *cvalue += edata->cycyofs;
- /* free temp data */
- MEM_freeN(edata);
- fmodifiers_storage_remove(storage, fcm);
- }
+ /* free temp data */
+ MEM_freeN(edata);
+ fmodifiers_storage_remove(storage, fcm);
+ }
}
static FModifierTypeInfo FMI_CYCLES = {
- FMODIFIER_TYPE_CYCLES, /* type */
- sizeof(FMod_Cycles), /* size */
- FMI_TYPE_EXTRAPOLATION, /* action type */
- FMI_REQUIRES_ORIGINAL_DATA | FMI_REQUIRES_STORAGE, /* requirements */
- N_("Cycles"), /* name */
- "FMod_Cycles", /* struct name */
- NULL, /* free data */
- NULL, /* copy data */
- fcm_cycles_new_data, /* new data */
- NULL /*fcm_cycles_verify*/, /* verify */
- NULL, /* evaluate time */
- NULL, /* evaluate */
- fcm_cycles_time, /* evaluate time with storage */
- fcm_cycles_evaluate, /* evaluate with storage */
+ FMODIFIER_TYPE_CYCLES, /* type */
+ sizeof(FMod_Cycles), /* size */
+ FMI_TYPE_EXTRAPOLATION, /* action type */
+ FMI_REQUIRES_ORIGINAL_DATA | FMI_REQUIRES_STORAGE, /* requirements */
+ N_("Cycles"), /* name */
+ "FMod_Cycles", /* struct name */
+ NULL, /* free data */
+ NULL, /* copy data */
+ fcm_cycles_new_data, /* new data */
+ NULL /*fcm_cycles_verify*/, /* verify */
+ NULL, /* evaluate time */
+ NULL, /* evaluate */
+ fcm_cycles_time, /* evaluate time with storage */
+ fcm_cycles_evaluate, /* evaluate with storage */
};
/* Noise F-Curve Modifier --------------------------- */
static void fcm_noise_new_data(void *mdata)
{
- FMod_Noise *data = (FMod_Noise *)mdata;
-
- /* defaults */
- data->size = 1.0f;
- data->strength = 1.0f;
- data->phase = 1.0f;
- data->offset = 0.0f;
- data->depth = 0;
- data->modification = FCM_NOISE_MODIF_REPLACE;
+ FMod_Noise *data = (FMod_Noise *)mdata;
+
+ /* defaults */
+ data->size = 1.0f;
+ data->strength = 1.0f;
+ data->phase = 1.0f;
+ data->offset = 0.0f;
+ data->depth = 0;
+ data->modification = FCM_NOISE_MODIF_REPLACE;
}
static void fcm_noise_evaluate(FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float evaltime)
{
- FMod_Noise *data = (FMod_Noise *)fcm->data;
- float noise;
-
- /* generate noise using good ol' Blender Noise
- * - 0.1 is passed as the 'z' value, otherwise evaluation fails for size = phase = 1
- * with evaltime being an integer (which happens when evaluating on frame by frame basis)
- */
- noise = BLI_turbulence(data->size, evaltime - data->offset, data->phase, 0.1f, data->depth);
-
- /* combine the noise with existing motion data */
- switch (data->modification) {
- case FCM_NOISE_MODIF_ADD:
- *cvalue = *cvalue + noise * data->strength;
- break;
- case FCM_NOISE_MODIF_SUBTRACT:
- *cvalue = *cvalue - noise * data->strength;
- break;
- case FCM_NOISE_MODIF_MULTIPLY:
- *cvalue = *cvalue * noise * data->strength;
- break;
- case FCM_NOISE_MODIF_REPLACE:
- default:
- *cvalue = *cvalue + (noise - 0.5f) * data->strength;
- break;
- }
+ FMod_Noise *data = (FMod_Noise *)fcm->data;
+ float noise;
+
+ /* generate noise using good ol' Blender Noise
+ * - 0.1 is passed as the 'z' value, otherwise evaluation fails for size = phase = 1
+ * with evaltime being an integer (which happens when evaluating on frame by frame basis)
+ */
+ noise = BLI_turbulence(data->size, evaltime - data->offset, data->phase, 0.1f, data->depth);
+
+ /* combine the noise with existing motion data */
+ switch (data->modification) {
+ case FCM_NOISE_MODIF_ADD:
+ *cvalue = *cvalue + noise * data->strength;
+ break;
+ case FCM_NOISE_MODIF_SUBTRACT:
+ *cvalue = *cvalue - noise * data->strength;
+ break;
+ case FCM_NOISE_MODIF_MULTIPLY:
+ *cvalue = *cvalue * noise * data->strength;
+ break;
+ case FCM_NOISE_MODIF_REPLACE:
+ default:
+ *cvalue = *cvalue + (noise - 0.5f) * data->strength;
+ break;
+ }
}
static FModifierTypeInfo FMI_NOISE = {
- FMODIFIER_TYPE_NOISE, /* type */
- sizeof(FMod_Noise), /* size */
- FMI_TYPE_REPLACE_VALUES, /* action type */
- 0, /* requirements */
- N_("Noise"), /* name */
- "FMod_Noise", /* struct name */
- NULL, /* free data */
- NULL, /* copy data */
- fcm_noise_new_data, /* new data */
- NULL /*fcm_noise_verify*/, /* verify */
- NULL, /* evaluate time */
- fcm_noise_evaluate, /* evaluate */
- NULL, /* evaluate time with storage */
- NULL, /* evaluate with storage */
+ FMODIFIER_TYPE_NOISE, /* type */
+ sizeof(FMod_Noise), /* size */
+ FMI_TYPE_REPLACE_VALUES, /* action type */
+ 0, /* requirements */
+ N_("Noise"), /* name */
+ "FMod_Noise", /* struct name */
+ NULL, /* free data */
+ NULL, /* copy data */
+ fcm_noise_new_data, /* new data */
+ NULL /*fcm_noise_verify*/, /* verify */
+ NULL, /* evaluate time */
+ fcm_noise_evaluate, /* evaluate */
+ NULL, /* evaluate time with storage */
+ NULL, /* evaluate with storage */
};
-
/* Python F-Curve Modifier --------------------------- */
static void fcm_python_free(FModifier *fcm)
{
- FMod_Python *data = (FMod_Python *)fcm->data;
+ FMod_Python *data = (FMod_Python *)fcm->data;
- /* id-properties */
- IDP_FreeProperty(data->prop);
- MEM_freeN(data->prop);
+ /* id-properties */
+ IDP_FreeProperty(data->prop);
+ MEM_freeN(data->prop);
}
static void fcm_python_new_data(void *mdata)
{
- FMod_Python *data = (FMod_Python *)mdata;
+ FMod_Python *data = (FMod_Python *)mdata;
- /* everything should be set correctly by calloc, except for the prop->type constant.*/
- data->prop = MEM_callocN(sizeof(IDProperty), "PyFModifierProps");
- data->prop->type = IDP_GROUP;
+ /* everything should be set correctly by calloc, except for the prop->type constant.*/
+ data->prop = MEM_callocN(sizeof(IDProperty), "PyFModifierProps");
+ data->prop->type = IDP_GROUP;
}
static void fcm_python_copy(FModifier *fcm, const FModifier *src)
{
- FMod_Python *pymod = (FMod_Python *)fcm->data;
- FMod_Python *opymod = (FMod_Python *)src->data;
+ FMod_Python *pymod = (FMod_Python *)fcm->data;
+ FMod_Python *opymod = (FMod_Python *)src->data;
- pymod->prop = IDP_CopyProperty(opymod->prop);
+ pymod->prop = IDP_CopyProperty(opymod->prop);
}
-static void fcm_python_evaluate(FCurve *UNUSED(fcu), FModifier *UNUSED(fcm), float *UNUSED(cvalue), float UNUSED(evaltime))
+static void fcm_python_evaluate(FCurve *UNUSED(fcu),
+ FModifier *UNUSED(fcm),
+ float *UNUSED(cvalue),
+ float UNUSED(evaltime))
{
#ifdef WITH_PYTHON
- //FMod_Python *data = (FMod_Python *)fcm->data;
+ //FMod_Python *data = (FMod_Python *)fcm->data;
- /* FIXME... need to implement this modifier...
- * It will need it execute a script using the custom properties
- */
+ /* FIXME... need to implement this modifier...
+ * It will need it execute a script using the custom properties
+ */
#endif /* WITH_PYTHON */
}
static FModifierTypeInfo FMI_PYTHON = {
- FMODIFIER_TYPE_PYTHON, /* type */
- sizeof(FMod_Python), /* size */
- FMI_TYPE_GENERATE_CURVE, /* action type */
- FMI_REQUIRES_RUNTIME_CHECK, /* requirements */
- N_("Python"), /* name */
- "FMod_Python", /* struct name */
- fcm_python_free, /* free data */
- fcm_python_copy, /* copy data */
- fcm_python_new_data, /* new data */
- NULL /*fcm_python_verify*/, /* verify */
- NULL /*fcm_python_time*/, /* evaluate time */
- fcm_python_evaluate, /* evaluate */
- NULL, /* evaluate time with storage */
- NULL, /* evaluate with storage */
+ FMODIFIER_TYPE_PYTHON, /* type */
+ sizeof(FMod_Python), /* size */
+ FMI_TYPE_GENERATE_CURVE, /* action type */
+ FMI_REQUIRES_RUNTIME_CHECK, /* requirements */
+ N_("Python"), /* name */
+ "FMod_Python", /* struct name */
+ fcm_python_free, /* free data */
+ fcm_python_copy, /* copy data */
+ fcm_python_new_data, /* new data */
+ NULL /*fcm_python_verify*/, /* verify */
+ NULL /*fcm_python_time*/, /* evaluate time */
+ fcm_python_evaluate, /* evaluate */
+ NULL, /* evaluate time with storage */
+ NULL, /* evaluate with storage */
};
-
/* Limits F-Curve Modifier --------------------------- */
-static float fcm_limits_time(FCurve *UNUSED(fcu), FModifier *fcm, float UNUSED(cvalue), float evaltime)
+static float fcm_limits_time(FCurve *UNUSED(fcu),
+ FModifier *fcm,
+ float UNUSED(cvalue),
+ float evaltime)
{
- FMod_Limits *data = (FMod_Limits *)fcm->data;
+ FMod_Limits *data = (FMod_Limits *)fcm->data;
- /* check for the time limits */
- if ((data->flag & FCM_LIMIT_XMIN) && (evaltime < data->rect.xmin))
- return data->rect.xmin;
- if ((data->flag & FCM_LIMIT_XMAX) && (evaltime > data->rect.xmax))
- return data->rect.xmax;
+ /* check for the time limits */
+ if ((data->flag & FCM_LIMIT_XMIN) && (evaltime < data->rect.xmin))
+ return data->rect.xmin;
+ if ((data->flag & FCM_LIMIT_XMAX) && (evaltime > data->rect.xmax))
+ return data->rect.xmax;
- /* modifier doesn't change time */
- return evaltime;
+ /* modifier doesn't change time */
+ return evaltime;
}
-static void fcm_limits_evaluate(FCurve *UNUSED(fcu), FModifier *fcm, float *cvalue, float UNUSED(evaltime))
+static void fcm_limits_evaluate(FCurve *UNUSED(fcu),
+ FModifier *fcm,
+ float *cvalue,
+ float UNUSED(evaltime))
{
- FMod_Limits *data = (FMod_Limits *)fcm->data;
+ FMod_Limits *data = (FMod_Limits *)fcm->data;
- /* value limits now */
- if ((data->flag & FCM_LIMIT_YMIN) && (*cvalue < data->rect.ymin))
- *cvalue = data->rect.ymin;
- if ((data->flag & FCM_LIMIT_YMAX) && (*cvalue > data->rect.ymax))
- *cvalue = data->rect.ymax;
+ /* value limits now */
+ if ((data->flag & FCM_LIMIT_YMIN) && (*cvalue < data->rect.ymin))
+ *cvalue = data->rect.ymin;
+ if ((data->flag & FCM_LIMIT_YMAX) && (*cvalue > data->rect.ymax))
+ *cvalue = data->rect.ymax;
}
static FModifierTypeInfo FMI_LIMITS = {
- FMODIFIER_TYPE_LIMITS, /* type */
- sizeof(FMod_Limits), /* size */
- FMI_TYPE_GENERATE_CURVE, /* action type */ /* XXX... err... */
- FMI_REQUIRES_RUNTIME_CHECK, /* requirements */
- N_("Limits"), /* name */
- "FMod_Limits", /* struct name */
- NULL, /* free data */
- NULL, /* copy data */
- NULL, /* new data */
- NULL, /* verify */
- fcm_limits_time, /* evaluate time */
- fcm_limits_evaluate, /* evaluate */
- NULL, /* evaluate time with storage */
- NULL, /* evaluate with storage */
+ FMODIFIER_TYPE_LIMITS, /* type */
+ sizeof(FMod_Limits), /* size */
+ FMI_TYPE_GENERATE_CURVE,
+ /* action type */ /* XXX... err... */
+ FMI_REQUIRES_RUNTIME_CHECK, /* requirements */
+ N_("Limits"), /* name */
+ "FMod_Limits", /* struct name */
+ NULL, /* free data */
+ NULL, /* copy data */
+ NULL, /* new data */
+ NULL, /* verify */
+ fcm_limits_time, /* evaluate time */
+ fcm_limits_evaluate, /* evaluate */
+ NULL, /* evaluate time with storage */
+ NULL, /* evaluate with storage */
};
/* Stepped F-Curve Modifier --------------------------- */
static void fcm_stepped_new_data(void *mdata)
{
- FMod_Stepped *data = (FMod_Stepped *)mdata;
+ FMod_Stepped *data = (FMod_Stepped *)mdata;
- /* just need to set the step-size to 2-frames by default */
- /* XXX: or would 5 be more normal? */
- data->step_size = 2.0f;
+ /* just need to set the step-size to 2-frames by default */
+ /* XXX: or would 5 be more normal? */
+ data->step_size = 2.0f;
}
-static float fcm_stepped_time(FCurve *UNUSED(fcu), FModifier *fcm, float UNUSED(cvalue), float evaltime)
+static float fcm_stepped_time(FCurve *UNUSED(fcu),
+ FModifier *fcm,
+ float UNUSED(cvalue),
+ float evaltime)
{
- FMod_Stepped *data = (FMod_Stepped *)fcm->data;
- int snapblock;
-
- /* check range clamping to see if we should alter the timing to achieve the desired results */
- if (data->flag & FCM_STEPPED_NO_BEFORE) {
- if (evaltime < data->start_frame)
- return evaltime;
- }
- if (data->flag & FCM_STEPPED_NO_AFTER) {
- if (evaltime > data->end_frame)
- return evaltime;
- }
-
- /* we snap to the start of the previous closest block of 'step_size' frames
- * after the start offset has been discarded
- * - i.e. round down
- */
- snapblock = (int)((evaltime - data->offset) / data->step_size);
-
- /* reapply the offset, and multiple the snapblock by the size of the steps to get
- * the new time to evaluate at
- */
- return ((float)snapblock * data->step_size) + data->offset;
+ FMod_Stepped *data = (FMod_Stepped *)fcm->data;
+ int snapblock;
+
+ /* check range clamping to see if we should alter the timing to achieve the desired results */
+ if (data->flag & FCM_STEPPED_NO_BEFORE) {
+ if (evaltime < data->start_frame)
+ return evaltime;
+ }
+ if (data->flag & FCM_STEPPED_NO_AFTER) {
+ if (evaltime > data->end_frame)
+ return evaltime;
+ }
+
+ /* we snap to the start of the previous closest block of 'step_size' frames
+ * after the start offset has been discarded
+ * - i.e. round down
+ */
+ snapblock = (int)((evaltime - data->offset) / data->step_size);
+
+ /* reapply the offset, and multiple the snapblock by the size of the steps to get
+ * the new time to evaluate at
+ */
+ return ((float)snapblock * data->step_size) + data->offset;
}
static FModifierTypeInfo FMI_STEPPED = {
- FMODIFIER_TYPE_STEPPED, /* type */
- sizeof(FMod_Limits), /* size */
- FMI_TYPE_GENERATE_CURVE, /* action type */ /* XXX... err... */
- FMI_REQUIRES_RUNTIME_CHECK, /* requirements */
- N_("Stepped"), /* name */
- "FMod_Stepped", /* struct name */
- NULL, /* free data */
- NULL, /* copy data */
- fcm_stepped_new_data, /* new data */
- NULL, /* verify */
- fcm_stepped_time, /* evaluate time */
- NULL, /* evaluate */
- NULL, /* evaluate time with storage */
- NULL, /* evaluate with storage */
+ FMODIFIER_TYPE_STEPPED, /* type */
+ sizeof(FMod_Limits), /* size */
+ FMI_TYPE_GENERATE_CURVE,
+ /* action type */ /* XXX... err... */
+ FMI_REQUIRES_RUNTIME_CHECK, /* requirements */
+ N_("Stepped"), /* name */
+ "FMod_Stepped", /* struct name */
+ NULL, /* free data */
+ NULL, /* copy data */
+ fcm_stepped_new_data, /* new data */
+ NULL, /* verify */
+ fcm_stepped_time, /* evaluate time */
+ NULL, /* evaluate */
+ NULL, /* evaluate time with storage */
+ NULL, /* evaluate with storage */
};
/* F-Curve Modifier API --------------------------- */
@@ -1002,16 +1036,16 @@ static short FMI_INIT = 1; /* when non-zero, the list needs to be updated */
/* This function only gets called when FMI_INIT is non-zero */
static void fmods_init_typeinfo(void)
{
- fmodifiersTypeInfo[0] = NULL; /* 'Null' F-Curve Modifier */
- fmodifiersTypeInfo[1] = &FMI_GENERATOR; /* Generator F-Curve Modifier */
- fmodifiersTypeInfo[2] = &FMI_FN_GENERATOR; /* Built-In Function Generator F-Curve Modifier */
- fmodifiersTypeInfo[3] = &FMI_ENVELOPE; /* Envelope F-Curve Modifier */
- fmodifiersTypeInfo[4] = &FMI_CYCLES; /* Cycles F-Curve Modifier */
- fmodifiersTypeInfo[5] = &FMI_NOISE; /* Apply-Noise F-Curve Modifier */
- fmodifiersTypeInfo[6] = NULL /*&FMI_FILTER*/; /* Filter F-Curve Modifier */ // XXX unimplemented
- fmodifiersTypeInfo[7] = &FMI_PYTHON; /* Custom Python F-Curve Modifier */
- fmodifiersTypeInfo[8] = &FMI_LIMITS; /* Limits F-Curve Modifier */
- fmodifiersTypeInfo[9] = &FMI_STEPPED; /* Stepped F-Curve Modifier */
+ fmodifiersTypeInfo[0] = NULL; /* 'Null' F-Curve Modifier */
+ fmodifiersTypeInfo[1] = &FMI_GENERATOR; /* Generator F-Curve Modifier */
+ fmodifiersTypeInfo[2] = &FMI_FN_GENERATOR; /* Built-In Function Generator F-Curve Modifier */
+ fmodifiersTypeInfo[3] = &FMI_ENVELOPE; /* Envelope F-Curve Modifier */
+ fmodifiersTypeInfo[4] = &FMI_CYCLES; /* Cycles F-Curve Modifier */
+ fmodifiersTypeInfo[5] = &FMI_NOISE; /* Apply-Noise F-Curve Modifier */
+ fmodifiersTypeInfo[6] = NULL /*&FMI_FILTER*/; /* Filter F-Curve Modifier */ // XXX unimplemented
+ fmodifiersTypeInfo[7] = &FMI_PYTHON; /* Custom Python F-Curve Modifier */
+ fmodifiersTypeInfo[8] = &FMI_LIMITS; /* Limits F-Curve Modifier */
+ fmodifiersTypeInfo[9] = &FMI_STEPPED; /* Stepped F-Curve Modifier */
}
/* This function should be used for getting the appropriate type-info when only
@@ -1019,24 +1053,22 @@ static void fmods_init_typeinfo(void)
*/
const FModifierTypeInfo *get_fmodifier_typeinfo(const int type)
{
- /* initialize the type-info list? */
- if (FMI_INIT) {
- fmods_init_typeinfo();
- FMI_INIT = 0;
- }
-
- /* only return for valid types */
- if ((type >= FMODIFIER_TYPE_NULL) &&
- (type < FMODIFIER_NUM_TYPES))
- {
- /* there shouldn't be any segfaults here... */
- return fmodifiersTypeInfo[type];
- }
- else {
- CLOG_ERROR(&LOG, "No valid F-Curve Modifier type-info data available. Type = %i", type);
- }
-
- return NULL;
+ /* initialize the type-info list? */
+ if (FMI_INIT) {
+ fmods_init_typeinfo();
+ FMI_INIT = 0;
+ }
+
+ /* only return for valid types */
+ if ((type >= FMODIFIER_TYPE_NULL) && (type < FMODIFIER_NUM_TYPES)) {
+ /* there shouldn't be any segfaults here... */
+ return fmodifiersTypeInfo[type];
+ }
+ else {
+ CLOG_ERROR(&LOG, "No valid F-Curve Modifier type-info data available. Type = %i", type);
+ }
+
+ return NULL;
}
/* This function should always be used to get the appropriate type-info, as it
@@ -1044,11 +1076,11 @@ const FModifierTypeInfo *get_fmodifier_typeinfo(const int type)
*/
const FModifierTypeInfo *fmodifier_get_typeinfo(const FModifier *fcm)
{
- /* only return typeinfo for valid modifiers */
- if (fcm)
- return get_fmodifier_typeinfo(fcm->type);
- else
- return NULL;
+ /* only return typeinfo for valid modifiers */
+ if (fcm)
+ return get_fmodifier_typeinfo(fcm->type);
+ else
+ return NULL;
}
/* API --------------------------- */
@@ -1056,188 +1088,191 @@ const FModifierTypeInfo *fmodifier_get_typeinfo(const FModifier *fcm)
/* Add a new F-Curve Modifier to the given F-Curve of a certain type */
FModifier *add_fmodifier(ListBase *modifiers, int type, FCurve *owner_fcu)
{
- const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(type);
- FModifier *fcm;
-
- /* sanity checks */
- if (ELEM(NULL, modifiers, fmi))
- return NULL;
-
- /* special checks for whether modifier can be added */
- if ((modifiers->first) && (type == FMODIFIER_TYPE_CYCLES)) {
- /* cycles modifier must be first in stack, so for now, don't add if it can't be */
- /* TODO: perhaps there is some better way, but for now, */
- CLOG_STR_ERROR(&LOG, "Cannot add 'Cycles' modifier to F-Curve, as 'Cycles' modifier can only be first in stack.");
- return NULL;
- }
-
- /* add modifier itself */
- fcm = MEM_callocN(sizeof(FModifier), "F-Curve Modifier");
- fcm->type = type;
- fcm->flag = FMODIFIER_FLAG_EXPANDED;
- fcm->curve = owner_fcu;
- fcm->influence = 1.0f;
- BLI_addtail(modifiers, fcm);
-
- /* tag modifier as "active" if no other modifiers exist in the stack yet */
- if (BLI_listbase_is_single(modifiers))
- fcm->flag |= FMODIFIER_FLAG_ACTIVE;
-
- /* add modifier's data */
- fcm->data = MEM_callocN(fmi->size, fmi->structName);
-
- /* init custom settings if necessary */
- if (fmi->new_data)
- fmi->new_data(fcm->data);
-
- /* update the fcurve if the Cycles modifier is added */
- if ((owner_fcu) && (type == FMODIFIER_TYPE_CYCLES))
- calchandles_fcurve(owner_fcu);
-
- /* return modifier for further editing */
- return fcm;
+ const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(type);
+ FModifier *fcm;
+
+ /* sanity checks */
+ if (ELEM(NULL, modifiers, fmi))
+ return NULL;
+
+ /* special checks for whether modifier can be added */
+ if ((modifiers->first) && (type == FMODIFIER_TYPE_CYCLES)) {
+ /* cycles modifier must be first in stack, so for now, don't add if it can't be */
+ /* TODO: perhaps there is some better way, but for now, */
+ CLOG_STR_ERROR(&LOG,
+ "Cannot add 'Cycles' modifier to F-Curve, as 'Cycles' modifier can only be "
+ "first in stack.");
+ return NULL;
+ }
+
+ /* add modifier itself */
+ fcm = MEM_callocN(sizeof(FModifier), "F-Curve Modifier");
+ fcm->type = type;
+ fcm->flag = FMODIFIER_FLAG_EXPANDED;
+ fcm->curve = owner_fcu;
+ fcm->influence = 1.0f;
+ BLI_addtail(modifiers, fcm);
+
+ /* tag modifier as "active" if no other modifiers exist in the stack yet */
+ if (BLI_listbase_is_single(modifiers))
+ fcm->flag |= FMODIFIER_FLAG_ACTIVE;
+
+ /* add modifier's data */
+ fcm->data = MEM_callocN(fmi->size, fmi->structName);
+
+ /* init custom settings if necessary */
+ if (fmi->new_data)
+ fmi->new_data(fcm->data);
+
+ /* update the fcurve if the Cycles modifier is added */
+ if ((owner_fcu) && (type == FMODIFIER_TYPE_CYCLES))
+ calchandles_fcurve(owner_fcu);
+
+ /* return modifier for further editing */
+ return fcm;
}
/* Make a copy of the specified F-Modifier */
FModifier *copy_fmodifier(const FModifier *src)
{
- const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(src);
- FModifier *dst;
+ const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(src);
+ FModifier *dst;
- /* sanity check */
- if (src == NULL)
- return NULL;
+ /* sanity check */
+ if (src == NULL)
+ return NULL;
- /* copy the base data, clearing the links */
- dst = MEM_dupallocN(src);
- dst->next = dst->prev = NULL;
- dst->curve = NULL;
+ /* copy the base data, clearing the links */
+ dst = MEM_dupallocN(src);
+ dst->next = dst->prev = NULL;
+ dst->curve = NULL;
- /* make a new copy of the F-Modifier's data */
- dst->data = MEM_dupallocN(src->data);
+ /* make a new copy of the F-Modifier's data */
+ dst->data = MEM_dupallocN(src->data);
- /* only do specific constraints if required */
- if (fmi && fmi->copy_data)
- fmi->copy_data(dst, src);
+ /* only do specific constraints if required */
+ if (fmi && fmi->copy_data)
+ fmi->copy_data(dst, src);
- /* return the new modifier */
- return dst;
+ /* return the new modifier */
+ return dst;
}
/* Duplicate all of the F-Modifiers in the Modifier stacks */
void copy_fmodifiers(ListBase *dst, const ListBase *src)
{
- FModifier *fcm, *srcfcm;
+ FModifier *fcm, *srcfcm;
- if (ELEM(NULL, dst, src))
- return;
+ if (ELEM(NULL, dst, src))
+ return;
- BLI_listbase_clear(dst);
- BLI_duplicatelist(dst, src);
+ BLI_listbase_clear(dst);
+ BLI_duplicatelist(dst, src);
- for (fcm = dst->first, srcfcm = src->first; fcm && srcfcm; srcfcm = srcfcm->next, fcm = fcm->next) {
- const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
+ for (fcm = dst->first, srcfcm = src->first; fcm && srcfcm;
+ srcfcm = srcfcm->next, fcm = fcm->next) {
+ const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
- /* make a new copy of the F-Modifier's data */
- fcm->data = MEM_dupallocN(fcm->data);
- fcm->curve = NULL;
+ /* make a new copy of the F-Modifier's data */
+ fcm->data = MEM_dupallocN(fcm->data);
+ fcm->curve = NULL;
- /* only do specific constraints if required */
- if (fmi && fmi->copy_data)
- fmi->copy_data(fcm, srcfcm);
- }
+ /* only do specific constraints if required */
+ if (fmi && fmi->copy_data)
+ fmi->copy_data(fcm, srcfcm);
+ }
}
/* Remove and free the given F-Modifier from the given stack */
bool remove_fmodifier(ListBase *modifiers, FModifier *fcm)
{
- const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
-
- /* sanity check */
- if (fcm == NULL)
- return false;
-
- /* removing the cycles modifier requires a handle update */
- FCurve *update_fcu = (fcm->type == FMODIFIER_TYPE_CYCLES) ? fcm->curve : NULL;
-
- /* free modifier's special data (stored inside fcm->data) */
- if (fcm->data) {
- if (fmi && fmi->free_data)
- fmi->free_data(fcm);
-
- /* free modifier's data (fcm->data) */
- MEM_freeN(fcm->data);
- }
-
- /* remove modifier from stack */
- if (modifiers) {
- BLI_freelinkN(modifiers, fcm);
-
- /* update the fcurve if the Cycles modifier is removed */
- if (update_fcu)
- calchandles_fcurve(update_fcu);
-
- return true;
- }
- else {
- /* XXX this case can probably be removed some day, as it shouldn't happen... */
- CLOG_STR_ERROR(&LOG, "no modifier stack given");
- MEM_freeN(fcm);
- return false;
- }
+ const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
+
+ /* sanity check */
+ if (fcm == NULL)
+ return false;
+
+ /* removing the cycles modifier requires a handle update */
+ FCurve *update_fcu = (fcm->type == FMODIFIER_TYPE_CYCLES) ? fcm->curve : NULL;
+
+ /* free modifier's special data (stored inside fcm->data) */
+ if (fcm->data) {
+ if (fmi && fmi->free_data)
+ fmi->free_data(fcm);
+
+ /* free modifier's data (fcm->data) */
+ MEM_freeN(fcm->data);
+ }
+
+ /* remove modifier from stack */
+ if (modifiers) {
+ BLI_freelinkN(modifiers, fcm);
+
+ /* update the fcurve if the Cycles modifier is removed */
+ if (update_fcu)
+ calchandles_fcurve(update_fcu);
+
+ return true;
+ }
+ else {
+ /* XXX this case can probably be removed some day, as it shouldn't happen... */
+ CLOG_STR_ERROR(&LOG, "no modifier stack given");
+ MEM_freeN(fcm);
+ return false;
+ }
}
/* Remove all of a given F-Curve's modifiers */
void free_fmodifiers(ListBase *modifiers)
{
- FModifier *fcm, *fmn;
+ FModifier *fcm, *fmn;
- /* sanity check */
- if (modifiers == NULL)
- return;
+ /* sanity check */
+ if (modifiers == NULL)
+ return;
- /* free each modifier in order - modifier is unlinked from list and freed */
- for (fcm = modifiers->first; fcm; fcm = fmn) {
- fmn = fcm->next;
- remove_fmodifier(modifiers, fcm);
- }
+ /* free each modifier in order - modifier is unlinked from list and freed */
+ for (fcm = modifiers->first; fcm; fcm = fmn) {
+ fmn = fcm->next;
+ remove_fmodifier(modifiers, fcm);
+ }
}
/* Find the active F-Modifier */
FModifier *find_active_fmodifier(ListBase *modifiers)
{
- FModifier *fcm;
+ FModifier *fcm;
- /* sanity checks */
- if (ELEM(NULL, modifiers, modifiers->first))
- return NULL;
+ /* sanity checks */
+ if (ELEM(NULL, modifiers, modifiers->first))
+ return NULL;
- /* loop over modifiers until 'active' one is found */
- for (fcm = modifiers->first; fcm; fcm = fcm->next) {
- if (fcm->flag & FMODIFIER_FLAG_ACTIVE)
- return fcm;
- }
+ /* loop over modifiers until 'active' one is found */
+ for (fcm = modifiers->first; fcm; fcm = fcm->next) {
+ if (fcm->flag & FMODIFIER_FLAG_ACTIVE)
+ return fcm;
+ }
- /* no modifier is active */
- return NULL;
+ /* no modifier is active */
+ return NULL;
}
/* Set the active F-Modifier */
void set_active_fmodifier(ListBase *modifiers, FModifier *fcm)
{
- FModifier *fm;
+ FModifier *fm;
- /* sanity checks */
- if (ELEM(NULL, modifiers, modifiers->first))
- return;
+ /* sanity checks */
+ if (ELEM(NULL, modifiers, modifiers->first))
+ return;
- /* deactivate all, and set current one active */
- for (fm = modifiers->first; fm; fm = fm->next)
- fm->flag &= ~FMODIFIER_FLAG_ACTIVE;
+ /* deactivate all, and set current one active */
+ for (fm = modifiers->first; fm; fm = fm->next)
+ fm->flag &= ~FMODIFIER_FLAG_ACTIVE;
- /* make given modifier active */
- if (fcm)
- fcm->flag |= FMODIFIER_FLAG_ACTIVE;
+ /* make given modifier active */
+ if (fcm)
+ fcm->flag |= FMODIFIER_FLAG_ACTIVE;
}
/* Do we have any modifiers which match certain criteria
@@ -1246,131 +1281,130 @@ void set_active_fmodifier(ListBase *modifiers, FModifier *fcm)
*/
bool list_has_suitable_fmodifier(ListBase *modifiers, int mtype, short acttype)
{
- FModifier *fcm;
-
- /* if there are no specific filtering criteria, just skip */
- if ((mtype == 0) && (acttype == 0))
- return (modifiers && modifiers->first);
-
- /* sanity checks */
- if (ELEM(NULL, modifiers, modifiers->first))
- return false;
-
- /* find the first mdifier fitting these criteria */
- for (fcm = modifiers->first; fcm; fcm = fcm->next) {
- const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
- short mOk = 1, aOk = 1; /* by default 1, so that when only one test, won't fail */
-
- /* check if applicable ones are fulfilled */
- if (mtype)
- mOk = (fcm->type == mtype);
- if (acttype > -1)
- aOk = (fmi->acttype == acttype);
-
- /* if both are ok, we've found a hit */
- if (mOk && aOk)
- return true;
- }
-
- /* no matches */
- return false;
+ FModifier *fcm;
+
+ /* if there are no specific filtering criteria, just skip */
+ if ((mtype == 0) && (acttype == 0))
+ return (modifiers && modifiers->first);
+
+ /* sanity checks */
+ if (ELEM(NULL, modifiers, modifiers->first))
+ return false;
+
+ /* find the first mdifier fitting these criteria */
+ for (fcm = modifiers->first; fcm; fcm = fcm->next) {
+ const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
+ short mOk = 1, aOk = 1; /* by default 1, so that when only one test, won't fail */
+
+ /* check if applicable ones are fulfilled */
+ if (mtype)
+ mOk = (fcm->type == mtype);
+ if (acttype > -1)
+ aOk = (fmi->acttype == acttype);
+
+ /* if both are ok, we've found a hit */
+ if (mOk && aOk)
+ return true;
+ }
+
+ /* no matches */
+ return false;
}
/* Evaluation API --------------------------- */
FModifierStackStorage *evaluate_fmodifiers_storage_new(ListBase *modifiers)
{
- FModifier *fcm;
+ FModifier *fcm;
- /* Sanity checks. */
- if (ELEM(NULL, modifiers, modifiers->last)) {
- return NULL;
- }
+ /* Sanity checks. */
+ if (ELEM(NULL, modifiers, modifiers->last)) {
+ return NULL;
+ }
- for (fcm = modifiers->last; fcm; fcm = fcm->prev) {
- const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
+ for (fcm = modifiers->last; fcm; fcm = fcm->prev) {
+ const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
- if (fmi == NULL) {
- continue;
- }
+ if (fmi == NULL) {
+ continue;
+ }
- if (fmi->requires & FMI_REQUIRES_STORAGE) {
- return (FModifierStackStorage *) BLI_ghash_new(BLI_ghashutil_ptrhash,
- BLI_ghashutil_ptrcmp,
- "fmodifier stack temp storage");
- }
- }
+ if (fmi->requires & FMI_REQUIRES_STORAGE) {
+ return (FModifierStackStorage *)BLI_ghash_new(
+ BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "fmodifier stack temp storage");
+ }
+ }
- return NULL;
+ return NULL;
}
void evaluate_fmodifiers_storage_free(FModifierStackStorage *storage)
{
- if (storage != NULL) {
- BLI_ghash_free((GHash *) storage, NULL, NULL);
- }
+ if (storage != NULL) {
+ BLI_ghash_free((GHash *)storage, NULL, NULL);
+ }
}
void fmodifiers_storage_put(FModifierStackStorage *storage, FModifier *fcm, void *data)
{
- BLI_assert(storage != NULL);
+ BLI_assert(storage != NULL);
- BLI_ghash_insert((GHash *) storage, fcm, data);
+ BLI_ghash_insert((GHash *)storage, fcm, data);
}
void fmodifiers_storage_remove(FModifierStackStorage *storage, FModifier *fcm)
{
- BLI_assert(storage != NULL);
+ BLI_assert(storage != NULL);
- BLI_ghash_remove((GHash *) storage, fcm, NULL, NULL);
+ BLI_ghash_remove((GHash *)storage, fcm, NULL, NULL);
}
void *fmodifiers_storage_get(FModifierStackStorage *storage, FModifier *fcm)
{
- BLI_assert(storage != NULL);
+ BLI_assert(storage != NULL);
- return BLI_ghash_lookup((GHash *) storage, fcm);
+ return BLI_ghash_lookup((GHash *)storage, fcm);
}
/* helper function - calculate influence of FModifier */
static float eval_fmodifier_influence(FModifier *fcm, float evaltime)
{
- float influence;
-
- /* sanity check */
- if (fcm == NULL)
- return 0.0f;
-
- /* should we use influence stored in modifier or not
- * NOTE: this is really just a hack so that we don't need to version patch old files ;)
- */
- if (fcm->flag & FMODIFIER_FLAG_USEINFLUENCE)
- influence = fcm->influence;
- else
- influence = 1.0f;
-
- /* restricted range or full range? */
- if (fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) {
- if ((evaltime <= fcm->sfra) || (evaltime >= fcm->efra)) {
- /* out of range */
- return 0.0f;
- }
- else if ((evaltime > fcm->sfra) && (evaltime < fcm->sfra + fcm->blendin)) {
- /* blend in range */
- float a = fcm->sfra;
- float b = fcm->sfra + fcm->blendin;
- return influence * (evaltime - a) / (b - a);
- }
- else if ((evaltime < fcm->efra) && (evaltime > fcm->efra - fcm->blendout)) {
- /* blend out range */
- float a = fcm->efra;
- float b = fcm->efra - fcm->blendout;
- return influence * (evaltime - a) / (b - a);
- }
- }
-
- /* just return the influence of the modifier */
- return influence;
+ float influence;
+
+ /* sanity check */
+ if (fcm == NULL)
+ return 0.0f;
+
+ /* should we use influence stored in modifier or not
+ * NOTE: this is really just a hack so that we don't need to version patch old files ;)
+ */
+ if (fcm->flag & FMODIFIER_FLAG_USEINFLUENCE)
+ influence = fcm->influence;
+ else
+ influence = 1.0f;
+
+ /* restricted range or full range? */
+ if (fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) {
+ if ((evaltime <= fcm->sfra) || (evaltime >= fcm->efra)) {
+ /* out of range */
+ return 0.0f;
+ }
+ else if ((evaltime > fcm->sfra) && (evaltime < fcm->sfra + fcm->blendin)) {
+ /* blend in range */
+ float a = fcm->sfra;
+ float b = fcm->sfra + fcm->blendin;
+ return influence * (evaltime - a) / (b - a);
+ }
+ else if ((evaltime < fcm->efra) && (evaltime > fcm->efra - fcm->blendout)) {
+ /* blend out range */
+ float a = fcm->efra;
+ float b = fcm->efra - fcm->blendout;
+ return influence * (evaltime - a) / (b - a);
+ }
+ }
+
+ /* just return the influence of the modifier */
+ return influence;
}
/* evaluate time modifications imposed by some F-Curve Modifiers
@@ -1384,106 +1418,107 @@ static float eval_fmodifier_influence(FModifier *fcm, float evaltime)
*
* Note: *fcu might be NULL
*/
-float evaluate_time_fmodifiers(FModifierStackStorage *storage, ListBase *modifiers,
- FCurve *fcu, float cvalue, float evaltime)
+float evaluate_time_fmodifiers(
+ FModifierStackStorage *storage, ListBase *modifiers, FCurve *fcu, float cvalue, float evaltime)
{
- FModifier *fcm;
-
- /* sanity checks */
- if (ELEM(NULL, modifiers, modifiers->last))
- return evaltime;
-
- if (fcu && fcu->flag & FCURVE_MOD_OFF)
- return evaltime;
-
- /* Starting from the end of the stack, calculate the time effects of various stacked modifiers
- * on the time the F-Curve should be evaluated at.
- *
- * This is done in reverse order to standard evaluation, as when this is done in standard
- * order, each modifier would cause jumps to other points in the curve, forcing all
- * previous ones to be evaluated again for them to be correct. However, if we did in the
- * reverse order as we have here, we can consider them a macro to micro type of waterfall
- * effect, which should get us the desired effects when using layered time manipulations
- * (such as multiple 'stepped' modifiers in sequence, causing different stepping rates)
- */
- for (fcm = modifiers->last; fcm; fcm = fcm->prev) {
- const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
-
- if (fmi == NULL)
- continue;
-
- /* if modifier cannot be applied on this frame (whatever scale it is on, it won't affect the results)
- * hence we shouldn't bother seeing what it would do given the chance
- */
- if ((fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) == 0 ||
- ((fcm->sfra <= evaltime) && (fcm->efra >= evaltime)) )
- {
- /* only evaluate if there's a callback for this */
- if (fmi->evaluate_modifier_time || fmi->evaluate_modifier_time_storage) {
- if ((fcm->flag & (FMODIFIER_FLAG_DISABLED | FMODIFIER_FLAG_MUTED)) == 0) {
- float influence = eval_fmodifier_influence(fcm, evaltime);
- float nval;
-
- if ((fmi->requires & FMI_REQUIRES_STORAGE) == 0) {
- nval = fmi->evaluate_modifier_time(fcu, fcm, cvalue, evaltime);
- }
- else {
- nval = fmi->evaluate_modifier_time_storage(storage, fcu, fcm, cvalue, evaltime);
- }
-
- evaltime = interpf(nval, evaltime, influence);
- }
- }
- }
- }
-
- /* return the modified evaltime */
- return evaltime;
+ FModifier *fcm;
+
+ /* sanity checks */
+ if (ELEM(NULL, modifiers, modifiers->last))
+ return evaltime;
+
+ if (fcu && fcu->flag & FCURVE_MOD_OFF)
+ return evaltime;
+
+ /* Starting from the end of the stack, calculate the time effects of various stacked modifiers
+ * on the time the F-Curve should be evaluated at.
+ *
+ * This is done in reverse order to standard evaluation, as when this is done in standard
+ * order, each modifier would cause jumps to other points in the curve, forcing all
+ * previous ones to be evaluated again for them to be correct. However, if we did in the
+ * reverse order as we have here, we can consider them a macro to micro type of waterfall
+ * effect, which should get us the desired effects when using layered time manipulations
+ * (such as multiple 'stepped' modifiers in sequence, causing different stepping rates)
+ */
+ for (fcm = modifiers->last; fcm; fcm = fcm->prev) {
+ const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
+
+ if (fmi == NULL)
+ continue;
+
+ /* if modifier cannot be applied on this frame (whatever scale it is on, it won't affect the results)
+ * hence we shouldn't bother seeing what it would do given the chance
+ */
+ if ((fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) == 0 ||
+ ((fcm->sfra <= evaltime) && (fcm->efra >= evaltime))) {
+ /* only evaluate if there's a callback for this */
+ if (fmi->evaluate_modifier_time || fmi->evaluate_modifier_time_storage) {
+ if ((fcm->flag & (FMODIFIER_FLAG_DISABLED | FMODIFIER_FLAG_MUTED)) == 0) {
+ float influence = eval_fmodifier_influence(fcm, evaltime);
+ float nval;
+
+ if ((fmi->requires & FMI_REQUIRES_STORAGE) == 0) {
+ nval = fmi->evaluate_modifier_time(fcu, fcm, cvalue, evaltime);
+ }
+ else {
+ nval = fmi->evaluate_modifier_time_storage(storage, fcu, fcm, cvalue, evaltime);
+ }
+
+ evaltime = interpf(nval, evaltime, influence);
+ }
+ }
+ }
+ }
+
+ /* return the modified evaltime */
+ return evaltime;
}
/* Evaluates the given set of F-Curve Modifiers using the given data
* Should only be called after evaluate_time_fmodifiers() has been called...
*/
-void evaluate_value_fmodifiers(FModifierStackStorage *storage, ListBase *modifiers,
- FCurve *fcu, float *cvalue, float evaltime)
+void evaluate_value_fmodifiers(FModifierStackStorage *storage,
+ ListBase *modifiers,
+ FCurve *fcu,
+ float *cvalue,
+ float evaltime)
{
- FModifier *fcm;
-
- /* sanity checks */
- if (ELEM(NULL, modifiers, modifiers->first))
- return;
-
- if (fcu->flag & FCURVE_MOD_OFF)
- return;
-
- /* evaluate modifiers */
- for (fcm = modifiers->first; fcm; fcm = fcm->next) {
- const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
-
- if (fmi == NULL)
- continue;
-
- /* only evaluate if there's a callback for this, and if F-Modifier can be evaluated on this frame */
- if ((fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) == 0 ||
- ((fcm->sfra <= evaltime) && (fcm->efra >= evaltime)) )
- {
- if (fmi->evaluate_modifier || fmi->evaluate_modifier_storage) {
- if ((fcm->flag & (FMODIFIER_FLAG_DISABLED | FMODIFIER_FLAG_MUTED)) == 0) {
- float influence = eval_fmodifier_influence(fcm, evaltime);
- float nval = *cvalue;
-
- if ((fmi->requires & FMI_REQUIRES_STORAGE) == 0) {
- fmi->evaluate_modifier(fcu, fcm, &nval, evaltime);
- }
- else {
- fmi->evaluate_modifier_storage(storage, fcu, fcm, &nval, evaltime);
- }
-
- *cvalue = interpf(nval, *cvalue, influence);
- }
- }
- }
- }
+ FModifier *fcm;
+
+ /* sanity checks */
+ if (ELEM(NULL, modifiers, modifiers->first))
+ return;
+
+ if (fcu->flag & FCURVE_MOD_OFF)
+ return;
+
+ /* evaluate modifiers */
+ for (fcm = modifiers->first; fcm; fcm = fcm->next) {
+ const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
+
+ if (fmi == NULL)
+ continue;
+
+ /* only evaluate if there's a callback for this, and if F-Modifier can be evaluated on this frame */
+ if ((fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) == 0 ||
+ ((fcm->sfra <= evaltime) && (fcm->efra >= evaltime))) {
+ if (fmi->evaluate_modifier || fmi->evaluate_modifier_storage) {
+ if ((fcm->flag & (FMODIFIER_FLAG_DISABLED | FMODIFIER_FLAG_MUTED)) == 0) {
+ float influence = eval_fmodifier_influence(fcm, evaltime);
+ float nval = *cvalue;
+
+ if ((fmi->requires & FMI_REQUIRES_STORAGE) == 0) {
+ fmi->evaluate_modifier(fcu, fcm, &nval, evaltime);
+ }
+ else {
+ fmi->evaluate_modifier_storage(storage, fcu, fcm, &nval, evaltime);
+ }
+
+ *cvalue = interpf(nval, *cvalue, influence);
+ }
+ }
+ }
+ }
}
/* ---------- */
@@ -1493,25 +1528,25 @@ void evaluate_value_fmodifiers(FModifierStackStorage *storage, ListBase *modifie
*/
void fcurve_bake_modifiers(FCurve *fcu, int start, int end)
{
- ChannelDriver *driver;
+ ChannelDriver *driver;
- /* sanity checks */
- /* TODO: make these tests report errors using reports not CLOG's */
- if (ELEM(NULL, fcu, fcu->modifiers.first)) {
- CLOG_ERROR(&LOG, "No F-Curve with F-Curve Modifiers to Bake");
- return;
- }
+ /* sanity checks */
+ /* TODO: make these tests report errors using reports not CLOG's */
+ if (ELEM(NULL, fcu, fcu->modifiers.first)) {
+ CLOG_ERROR(&LOG, "No F-Curve with F-Curve Modifiers to Bake");
+ return;
+ }
- /* temporarily, disable driver while we sample, so that they don't influence the outcome */
- driver = fcu->driver;
- fcu->driver = NULL;
+ /* temporarily, disable driver while we sample, so that they don't influence the outcome */
+ driver = fcu->driver;
+ fcu->driver = NULL;
- /* bake the modifiers, by sampling the curve at each frame */
- fcurve_store_samples(fcu, NULL, start, end, fcurve_samplingcb_evalcurve);
+ /* bake the modifiers, by sampling the curve at each frame */
+ fcurve_store_samples(fcu, NULL, start, end, fcurve_samplingcb_evalcurve);
- /* free the modifiers now */
- free_fmodifiers(&fcu->modifiers);
+ /* free the modifiers now */
+ free_fmodifiers(&fcu->modifiers);
- /* restore driver */
- fcu->driver = driver;
+ /* restore driver */
+ fcu->driver = driver;
}
diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c
index c779f05c0b0..4311402ef42 100644
--- a/source/blender/blenkernel/intern/font.c
+++ b/source/blender/blenkernel/intern/font.c
@@ -21,7 +21,6 @@
* \ingroup bke
*/
-
#include <stdio.h>
#include <string.h>
#include <math.h>
@@ -62,60 +61,64 @@ static ThreadRWMutex vfont_rwlock = BLI_RWLOCK_INITIALIZER;
/* The vfont code */
void BKE_vfont_free_data(struct VFont *vfont)
{
- if (vfont->data) {
- if (vfont->data->characters) {
- GHashIterator gh_iter;
- GHASH_ITER (gh_iter, vfont->data->characters) {
- VChar *che = BLI_ghashIterator_getValue(&gh_iter);
-
- while (che->nurbsbase.first) {
- Nurb *nu = che->nurbsbase.first;
- if (nu->bezt) MEM_freeN(nu->bezt);
- BLI_freelinkN(&che->nurbsbase, nu);
- }
-
- MEM_freeN(che);
- }
-
- BLI_ghash_free(vfont->data->characters, NULL, NULL);
- }
-
- MEM_freeN(vfont->data);
- vfont->data = NULL;
- }
-
- if (vfont->temp_pf) {
- freePackedFile(vfont->temp_pf); /* NULL when the font file can't be found on disk */
- vfont->temp_pf = NULL;
- }
+ if (vfont->data) {
+ if (vfont->data->characters) {
+ GHashIterator gh_iter;
+ GHASH_ITER (gh_iter, vfont->data->characters) {
+ VChar *che = BLI_ghashIterator_getValue(&gh_iter);
+
+ while (che->nurbsbase.first) {
+ Nurb *nu = che->nurbsbase.first;
+ if (nu->bezt)
+ MEM_freeN(nu->bezt);
+ BLI_freelinkN(&che->nurbsbase, nu);
+ }
+
+ MEM_freeN(che);
+ }
+
+ BLI_ghash_free(vfont->data->characters, NULL, NULL);
+ }
+
+ MEM_freeN(vfont->data);
+ vfont->data = NULL;
+ }
+
+ if (vfont->temp_pf) {
+ freePackedFile(vfont->temp_pf); /* NULL when the font file can't be found on disk */
+ vfont->temp_pf = NULL;
+ }
}
/** Free (or release) any data used by this font (does not free the font itself). */
void BKE_vfont_free(struct VFont *vf)
{
- BKE_vfont_free_data(vf);
+ BKE_vfont_free_data(vf);
- if (vf->packedfile) {
- freePackedFile(vf->packedfile);
- vf->packedfile = NULL;
- }
+ if (vf->packedfile) {
+ freePackedFile(vf->packedfile);
+ vf->packedfile = NULL;
+ }
}
-void BKE_vfont_copy_data(Main *UNUSED(bmain), VFont *vfont_dst, const VFont *UNUSED(vfont_src), const int flag)
+void BKE_vfont_copy_data(Main *UNUSED(bmain),
+ VFont *vfont_dst,
+ const VFont *UNUSED(vfont_src),
+ const int flag)
{
- /* We never handle usercount here for own data. */
- const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
+ /* We never handle usercount here for own data. */
+ const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
- /* Just to be sure, should not have any value actually after reading time. */
- vfont_dst->temp_pf = NULL;
+ /* Just to be sure, should not have any value actually after reading time. */
+ vfont_dst->temp_pf = NULL;
- if (vfont_dst->packedfile) {
- vfont_dst->packedfile = dupPackedFile(vfont_dst->packedfile);
- }
+ if (vfont_dst->packedfile) {
+ vfont_dst->packedfile = dupPackedFile(vfont_dst->packedfile);
+ }
- if (vfont_dst->data) {
- vfont_dst->data = BLI_vfontdata_copy(vfont_dst->data, flag_subdata);
- }
+ if (vfont_dst->data) {
+ vfont_dst->data = BLI_vfontdata_copy(vfont_dst->data, flag_subdata);
+ }
}
static void *builtin_font_data = NULL;
@@ -123,517 +126,532 @@ static int builtin_font_size = 0;
bool BKE_vfont_is_builtin(struct VFont *vfont)
{
- return STREQ(vfont->name, FO_BUILTIN_NAME);
+ return STREQ(vfont->name, FO_BUILTIN_NAME);
}
void BKE_vfont_builtin_register(void *mem, int size)
{
- builtin_font_data = mem;
- builtin_font_size = size;
+ builtin_font_data = mem;
+ builtin_font_size = size;
}
static PackedFile *get_builtin_packedfile(void)
{
- if (!builtin_font_data) {
- CLOG_ERROR(&LOG, "Internal error, builtin font not loaded");
+ if (!builtin_font_data) {
+ CLOG_ERROR(&LOG, "Internal error, builtin font not loaded");
- return NULL;
- }
- else {
- void *mem = MEM_mallocN(builtin_font_size, "vfd_builtin");
+ return NULL;
+ }
+ else {
+ void *mem = MEM_mallocN(builtin_font_size, "vfd_builtin");
- memcpy(mem, builtin_font_data, builtin_font_size);
+ memcpy(mem, builtin_font_data, builtin_font_size);
- return newPackedFileMemory(mem, builtin_font_size);
- }
+ return newPackedFileMemory(mem, builtin_font_size);
+ }
}
static VFontData *vfont_get_data(VFont *vfont)
{
- if (vfont == NULL) {
- return NULL;
- }
-
- /* And then set the data */
- if (!vfont->data) {
- PackedFile *pf;
-
- BLI_rw_mutex_lock(&vfont_rwlock, THREAD_LOCK_WRITE);
-
- if (vfont->data) {
- /* Check data again, since it might have been already
- * initialized from other thread (previous check is
- * not accurate or threading, just prevents unneeded
- * lock if all the data is here for sure).
- */
- BLI_rw_mutex_unlock(&vfont_rwlock);
- return vfont->data;
- }
-
- if (BKE_vfont_is_builtin(vfont)) {
- pf = get_builtin_packedfile();
- }
- else {
- if (vfont->packedfile) {
- pf = vfont->packedfile;
-
- /* We need to copy a tmp font to memory unless it is already there */
- if (vfont->temp_pf == NULL) {
- vfont->temp_pf = dupPackedFile(pf);
- }
- }
- else {
- pf = newPackedFile(NULL, vfont->name, ID_BLEND_PATH_FROM_GLOBAL(&vfont->id));
-
- if (vfont->temp_pf == NULL) {
- vfont->temp_pf = newPackedFile(NULL, vfont->name, ID_BLEND_PATH_FROM_GLOBAL(&vfont->id));
- }
- }
- if (!pf) {
- CLOG_WARN(&LOG, "Font file doesn't exist: %s", vfont->name);
-
- /* DON'T DO THIS
- * missing file shouldn't modify path! - campbell */
+ if (vfont == NULL) {
+ return NULL;
+ }
+
+ /* And then set the data */
+ if (!vfont->data) {
+ PackedFile *pf;
+
+ BLI_rw_mutex_lock(&vfont_rwlock, THREAD_LOCK_WRITE);
+
+ if (vfont->data) {
+ /* Check data again, since it might have been already
+ * initialized from other thread (previous check is
+ * not accurate or threading, just prevents unneeded
+ * lock if all the data is here for sure).
+ */
+ BLI_rw_mutex_unlock(&vfont_rwlock);
+ return vfont->data;
+ }
+
+ if (BKE_vfont_is_builtin(vfont)) {
+ pf = get_builtin_packedfile();
+ }
+ else {
+ if (vfont->packedfile) {
+ pf = vfont->packedfile;
+
+ /* We need to copy a tmp font to memory unless it is already there */
+ if (vfont->temp_pf == NULL) {
+ vfont->temp_pf = dupPackedFile(pf);
+ }
+ }
+ else {
+ pf = newPackedFile(NULL, vfont->name, ID_BLEND_PATH_FROM_GLOBAL(&vfont->id));
+
+ if (vfont->temp_pf == NULL) {
+ vfont->temp_pf = newPackedFile(NULL, vfont->name, ID_BLEND_PATH_FROM_GLOBAL(&vfont->id));
+ }
+ }
+ if (!pf) {
+ CLOG_WARN(&LOG, "Font file doesn't exist: %s", vfont->name);
+
+ /* DON'T DO THIS
+ * missing file shouldn't modify path! - campbell */
#if 0
- strcpy(vfont->name, FO_BUILTIN_NAME);
+ strcpy(vfont->name, FO_BUILTIN_NAME);
#endif
- pf = get_builtin_packedfile();
- }
- }
+ pf = get_builtin_packedfile();
+ }
+ }
- if (pf) {
- vfont->data = BLI_vfontdata_from_freetypefont(pf);
- if (pf != vfont->packedfile) {
- freePackedFile(pf);
- }
- }
+ if (pf) {
+ vfont->data = BLI_vfontdata_from_freetypefont(pf);
+ if (pf != vfont->packedfile) {
+ freePackedFile(pf);
+ }
+ }
- BLI_rw_mutex_unlock(&vfont_rwlock);
- }
+ BLI_rw_mutex_unlock(&vfont_rwlock);
+ }
- return vfont->data;
+ return vfont->data;
}
/* Bad naming actually in this case... */
void BKE_vfont_init(VFont *vfont)
{
- PackedFile *pf = get_builtin_packedfile();
+ PackedFile *pf = get_builtin_packedfile();
- if (pf) {
- VFontData *vfd;
+ if (pf) {
+ VFontData *vfd;
- vfd = BLI_vfontdata_from_freetypefont(pf);
- if (vfd) {
- vfont->data = vfd;
+ vfd = BLI_vfontdata_from_freetypefont(pf);
+ if (vfd) {
+ vfont->data = vfd;
- BLI_strncpy(vfont->name, FO_BUILTIN_NAME, sizeof(vfont->name));
- }
+ BLI_strncpy(vfont->name, FO_BUILTIN_NAME, sizeof(vfont->name));
+ }
- /* Free the packed file */
- freePackedFile(pf);
- }
+ /* Free the packed file */
+ freePackedFile(pf);
+ }
}
VFont *BKE_vfont_load(Main *bmain, const char *filepath)
{
- char filename[FILE_MAXFILE];
- VFont *vfont = NULL;
- PackedFile *pf;
- bool is_builtin;
-
- if (STREQ(filepath, FO_BUILTIN_NAME)) {
- BLI_strncpy(filename, filepath, sizeof(filename));
-
- pf = get_builtin_packedfile();
- is_builtin = true;
- }
- else {
- BLI_split_file_part(filepath, filename, sizeof(filename));
- pf = newPackedFile(NULL, filepath, BKE_main_blendfile_path(bmain));
-
- is_builtin = false;
- }
-
- if (pf) {
- VFontData *vfd;
-
- vfd = BLI_vfontdata_from_freetypefont(pf);
- if (vfd) {
- vfont = BKE_libblock_alloc(bmain, ID_VF, filename, 0);
- vfont->data = vfd;
-
- /* if there's a font name, use it for the ID name */
- if (vfd->name[0] != '\0') {
- BLI_strncpy(vfont->id.name + 2, vfd->name, sizeof(vfont->id.name) - 2);
- }
- BLI_strncpy(vfont->name, filepath, sizeof(vfont->name));
-
- /* if autopack is on store the packedfile in de font structure */
- if (!is_builtin && (G.fileflags & G_FILE_AUTOPACK)) {
- vfont->packedfile = pf;
- }
-
- /* Do not add FO_BUILTIN_NAME to temporary listbase */
- if (!STREQ(filename, FO_BUILTIN_NAME)) {
- vfont->temp_pf = newPackedFile(NULL, filepath, BKE_main_blendfile_path(bmain));
- }
- }
-
- /* Free the packed file */
- if (!vfont || vfont->packedfile != pf) {
- freePackedFile(pf);
- }
- }
-
- return vfont;
+ char filename[FILE_MAXFILE];
+ VFont *vfont = NULL;
+ PackedFile *pf;
+ bool is_builtin;
+
+ if (STREQ(filepath, FO_BUILTIN_NAME)) {
+ BLI_strncpy(filename, filepath, sizeof(filename));
+
+ pf = get_builtin_packedfile();
+ is_builtin = true;
+ }
+ else {
+ BLI_split_file_part(filepath, filename, sizeof(filename));
+ pf = newPackedFile(NULL, filepath, BKE_main_blendfile_path(bmain));
+
+ is_builtin = false;
+ }
+
+ if (pf) {
+ VFontData *vfd;
+
+ vfd = BLI_vfontdata_from_freetypefont(pf);
+ if (vfd) {
+ vfont = BKE_libblock_alloc(bmain, ID_VF, filename, 0);
+ vfont->data = vfd;
+
+ /* if there's a font name, use it for the ID name */
+ if (vfd->name[0] != '\0') {
+ BLI_strncpy(vfont->id.name + 2, vfd->name, sizeof(vfont->id.name) - 2);
+ }
+ BLI_strncpy(vfont->name, filepath, sizeof(vfont->name));
+
+ /* if autopack is on store the packedfile in de font structure */
+ if (!is_builtin && (G.fileflags & G_FILE_AUTOPACK)) {
+ vfont->packedfile = pf;
+ }
+
+ /* Do not add FO_BUILTIN_NAME to temporary listbase */
+ if (!STREQ(filename, FO_BUILTIN_NAME)) {
+ vfont->temp_pf = newPackedFile(NULL, filepath, BKE_main_blendfile_path(bmain));
+ }
+ }
+
+ /* Free the packed file */
+ if (!vfont || vfont->packedfile != pf) {
+ freePackedFile(pf);
+ }
+ }
+
+ return vfont;
}
VFont *BKE_vfont_load_exists_ex(struct Main *bmain, const char *filepath, bool *r_exists)
{
- VFont *vfont;
- char str[FILE_MAX], strtest[FILE_MAX];
-
- BLI_strncpy(str, filepath, sizeof(str));
- BLI_path_abs(str, BKE_main_blendfile_path(bmain));
-
- /* first search an identical filepath */
- for (vfont = bmain->fonts.first; vfont; vfont = vfont->id.next) {
- BLI_strncpy(strtest, vfont->name, sizeof(vfont->name));
- BLI_path_abs(strtest, ID_BLEND_PATH(bmain, &vfont->id));
-
- if (BLI_path_cmp(strtest, str) == 0) {
- id_us_plus(&vfont->id); /* officially should not, it doesn't link here! */
- if (r_exists)
- *r_exists = true;
- return vfont;
- }
- }
-
- if (r_exists)
- *r_exists = false;
- return BKE_vfont_load(bmain, filepath);
+ VFont *vfont;
+ char str[FILE_MAX], strtest[FILE_MAX];
+
+ BLI_strncpy(str, filepath, sizeof(str));
+ BLI_path_abs(str, BKE_main_blendfile_path(bmain));
+
+ /* first search an identical filepath */
+ for (vfont = bmain->fonts.first; vfont; vfont = vfont->id.next) {
+ BLI_strncpy(strtest, vfont->name, sizeof(vfont->name));
+ BLI_path_abs(strtest, ID_BLEND_PATH(bmain, &vfont->id));
+
+ if (BLI_path_cmp(strtest, str) == 0) {
+ id_us_plus(&vfont->id); /* officially should not, it doesn't link here! */
+ if (r_exists)
+ *r_exists = true;
+ return vfont;
+ }
+ }
+
+ if (r_exists)
+ *r_exists = false;
+ return BKE_vfont_load(bmain, filepath);
}
VFont *BKE_vfont_load_exists(struct Main *bmain, const char *filepath)
{
- return BKE_vfont_load_exists_ex(bmain, filepath, NULL);
+ return BKE_vfont_load_exists_ex(bmain, filepath, NULL);
}
void BKE_vfont_make_local(Main *bmain, VFont *vfont, const bool lib_local)
{
- BKE_id_make_local_generic(bmain, &vfont->id, true, lib_local);
+ BKE_id_make_local_generic(bmain, &vfont->id, true, lib_local);
}
static VFont *which_vfont(Curve *cu, CharInfo *info)
{
- switch (info->flag & (CU_CHINFO_BOLD | CU_CHINFO_ITALIC)) {
- case CU_CHINFO_BOLD:
- return cu->vfontb ? cu->vfontb : cu->vfont;
- case CU_CHINFO_ITALIC:
- return cu->vfonti ? cu->vfonti : cu->vfont;
- case (CU_CHINFO_BOLD | CU_CHINFO_ITALIC):
- return cu->vfontbi ? cu->vfontbi : cu->vfont;
- default:
- return cu->vfont;
- }
+ switch (info->flag & (CU_CHINFO_BOLD | CU_CHINFO_ITALIC)) {
+ case CU_CHINFO_BOLD:
+ return cu->vfontb ? cu->vfontb : cu->vfont;
+ case CU_CHINFO_ITALIC:
+ return cu->vfonti ? cu->vfonti : cu->vfont;
+ case (CU_CHINFO_BOLD | CU_CHINFO_ITALIC):
+ return cu->vfontbi ? cu->vfontbi : cu->vfont;
+ default:
+ return cu->vfont;
+ }
}
VFont *BKE_vfont_builtin_get(void)
{
- VFont *vfont;
+ VFont *vfont;
- for (vfont = G_MAIN->fonts.first; vfont; vfont = vfont->id.next) {
- if (BKE_vfont_is_builtin(vfont)) {
- return vfont;
- }
- }
+ for (vfont = G_MAIN->fonts.first; vfont; vfont = vfont->id.next) {
+ if (BKE_vfont_is_builtin(vfont)) {
+ return vfont;
+ }
+ }
- return BKE_vfont_load(G_MAIN, FO_BUILTIN_NAME);
+ return BKE_vfont_load(G_MAIN, FO_BUILTIN_NAME);
}
static VChar *find_vfont_char(VFontData *vfd, unsigned int character)
{
- return BLI_ghash_lookup(vfd->characters, POINTER_FROM_UINT(character));
+ return BLI_ghash_lookup(vfd->characters, POINTER_FROM_UINT(character));
}
-static void build_underline(Curve *cu, ListBase *nubase, const rctf *rect,
- float yofs, float rot, int charidx, short mat_nr,
+static void build_underline(Curve *cu,
+ ListBase *nubase,
+ const rctf *rect,
+ float yofs,
+ float rot,
+ int charidx,
+ short mat_nr,
const float font_size)
{
- Nurb *nu2;
- BPoint *bp;
-
- nu2 = (Nurb *) MEM_callocN(sizeof(Nurb), "underline_nurb");
- nu2->resolu = cu->resolu;
- nu2->bezt = NULL;
- nu2->knotsu = nu2->knotsv = NULL;
- nu2->flag = CU_2D;
- nu2->charidx = charidx + 1000;
- if (mat_nr > 0) nu2->mat_nr = mat_nr - 1;
- nu2->pntsu = 4;
- nu2->pntsv = 1;
- nu2->orderu = 4;
- nu2->orderv = 1;
- nu2->flagu = CU_NURB_CYCLIC;
-
- bp = (BPoint *)MEM_calloc_arrayN(4, sizeof(BPoint), "underline_bp");
-
- copy_v4_fl4(bp[0].vec, rect->xmin, (rect->ymax + yofs), 0.0f, 1.0f);
- copy_v4_fl4(bp[1].vec, rect->xmax, (rect->ymax + yofs), 0.0f, 1.0f);
- copy_v4_fl4(bp[2].vec, rect->xmax, (rect->ymin + yofs), 0.0f, 1.0f);
- copy_v4_fl4(bp[3].vec, rect->xmin, (rect->ymin + yofs), 0.0f, 1.0f);
-
- nu2->bp = bp;
- BLI_addtail(nubase, nu2);
-
- if (rot != 0.0f) {
- float si, co;
- int i;
-
- si = sinf(rot);
- co = cosf(rot);
-
- for (i = nu2->pntsu; i > 0; i--) {
- float *fp;
- float x, y;
-
- fp = bp->vec;
-
- x = fp[0] - rect->xmin;
- y = fp[1] - rect->ymin;
-
- fp[0] = (+co * x + si * y) + rect->xmin;
- fp[1] = (-si * x + co * y) + rect->ymin;
-
- bp++;
- }
-
- bp = nu2->bp;
- }
-
- mul_v2_fl(bp[0].vec, font_size);
- mul_v2_fl(bp[1].vec, font_size);
- mul_v2_fl(bp[2].vec, font_size);
- mul_v2_fl(bp[3].vec, font_size);
+ Nurb *nu2;
+ BPoint *bp;
+
+ nu2 = (Nurb *)MEM_callocN(sizeof(Nurb), "underline_nurb");
+ nu2->resolu = cu->resolu;
+ nu2->bezt = NULL;
+ nu2->knotsu = nu2->knotsv = NULL;
+ nu2->flag = CU_2D;
+ nu2->charidx = charidx + 1000;
+ if (mat_nr > 0)
+ nu2->mat_nr = mat_nr - 1;
+ nu2->pntsu = 4;
+ nu2->pntsv = 1;
+ nu2->orderu = 4;
+ nu2->orderv = 1;
+ nu2->flagu = CU_NURB_CYCLIC;
+
+ bp = (BPoint *)MEM_calloc_arrayN(4, sizeof(BPoint), "underline_bp");
+
+ copy_v4_fl4(bp[0].vec, rect->xmin, (rect->ymax + yofs), 0.0f, 1.0f);
+ copy_v4_fl4(bp[1].vec, rect->xmax, (rect->ymax + yofs), 0.0f, 1.0f);
+ copy_v4_fl4(bp[2].vec, rect->xmax, (rect->ymin + yofs), 0.0f, 1.0f);
+ copy_v4_fl4(bp[3].vec, rect->xmin, (rect->ymin + yofs), 0.0f, 1.0f);
+
+ nu2->bp = bp;
+ BLI_addtail(nubase, nu2);
+
+ if (rot != 0.0f) {
+ float si, co;
+ int i;
+
+ si = sinf(rot);
+ co = cosf(rot);
+
+ for (i = nu2->pntsu; i > 0; i--) {
+ float *fp;
+ float x, y;
+
+ fp = bp->vec;
+
+ x = fp[0] - rect->xmin;
+ y = fp[1] - rect->ymin;
+
+ fp[0] = (+co * x + si * y) + rect->xmin;
+ fp[1] = (-si * x + co * y) + rect->ymin;
+
+ bp++;
+ }
+
+ bp = nu2->bp;
+ }
+
+ mul_v2_fl(bp[0].vec, font_size);
+ mul_v2_fl(bp[1].vec, font_size);
+ mul_v2_fl(bp[2].vec, font_size);
+ mul_v2_fl(bp[3].vec, font_size);
}
-static void buildchar(Curve *cu, ListBase *nubase, unsigned int character, CharInfo *info,
- float ofsx, float ofsy, float rot, int charidx,
+static void buildchar(Curve *cu,
+ ListBase *nubase,
+ unsigned int character,
+ CharInfo *info,
+ float ofsx,
+ float ofsy,
+ float rot,
+ int charidx,
const float fsize)
{
- BezTriple *bezt1, *bezt2;
- Nurb *nu1 = NULL, *nu2 = NULL;
- float *fp, shear, x, si, co;
- VFontData *vfd = NULL;
- VChar *che = NULL;
- int i;
-
- vfd = vfont_get_data(which_vfont(cu, info));
- if (!vfd) return;
-
- /* make a copy at distance ofsx, ofsy with shear */
- shear = cu->shear;
- si = sinf(rot);
- co = cosf(rot);
-
- che = find_vfont_char(vfd, character);
-
- /* Select the glyph data */
- if (che)
- nu1 = che->nurbsbase.first;
-
- /* Create the character */
- while (nu1) {
- bezt1 = nu1->bezt;
- if (bezt1) {
- nu2 = (Nurb *) MEM_mallocN(sizeof(Nurb), "duplichar_nurb");
- if (nu2 == NULL) break;
- memcpy(nu2, nu1, sizeof(struct Nurb));
- nu2->resolu = cu->resolu;
- nu2->bp = NULL;
- nu2->knotsu = nu2->knotsv = NULL;
- nu2->flag = CU_SMOOTH;
- nu2->charidx = charidx;
- if (info->mat_nr > 0) {
- nu2->mat_nr = info->mat_nr - 1;
- }
- else {
- nu2->mat_nr = 0;
- }
- /* nu2->trim.first = 0; */
- /* nu2->trim.last = 0; */
- i = nu2->pntsu;
-
- bezt2 = (BezTriple *)MEM_malloc_arrayN(i, sizeof(BezTriple), "duplichar_bezt2");
- if (bezt2 == NULL) {
- MEM_freeN(nu2);
- break;
- }
- memcpy(bezt2, bezt1, i * sizeof(struct BezTriple));
- nu2->bezt = bezt2;
-
- if (shear != 0.0f) {
- bezt2 = nu2->bezt;
-
- for (i = nu2->pntsu; i > 0; i--) {
- bezt2->vec[0][0] += shear * bezt2->vec[0][1];
- bezt2->vec[1][0] += shear * bezt2->vec[1][1];
- bezt2->vec[2][0] += shear * bezt2->vec[2][1];
- bezt2++;
- }
- }
- if (rot != 0.0f) {
- bezt2 = nu2->bezt;
- for (i = nu2->pntsu; i > 0; i--) {
- fp = bezt2->vec[0];
-
- x = fp[0];
- fp[0] = co * x + si * fp[1];
- fp[1] = -si * x + co * fp[1];
- x = fp[3];
- fp[3] = co * x + si * fp[4];
- fp[4] = -si * x + co * fp[4];
- x = fp[6];
- fp[6] = co * x + si * fp[7];
- fp[7] = -si * x + co * fp[7];
-
- bezt2++;
- }
- }
- bezt2 = nu2->bezt;
-
- if (info->flag & CU_CHINFO_SMALLCAPS_CHECK) {
- const float sca = cu->smallcaps_scale;
- for (i = nu2->pntsu; i > 0; i--) {
- fp = bezt2->vec[0];
- fp[0] *= sca;
- fp[1] *= sca;
- fp[3] *= sca;
- fp[4] *= sca;
- fp[6] *= sca;
- fp[7] *= sca;
- bezt2++;
- }
- }
- bezt2 = nu2->bezt;
-
- for (i = nu2->pntsu; i > 0; i--) {
- fp = bezt2->vec[0];
- fp[0] = (fp[0] + ofsx) * fsize;
- fp[1] = (fp[1] + ofsy) * fsize;
- fp[3] = (fp[3] + ofsx) * fsize;
- fp[4] = (fp[4] + ofsy) * fsize;
- fp[6] = (fp[6] + ofsx) * fsize;
- fp[7] = (fp[7] + ofsy) * fsize;
- bezt2++;
- }
-
- BLI_addtail(nubase, nu2);
- }
-
- nu1 = nu1->next;
- }
+ BezTriple *bezt1, *bezt2;
+ Nurb *nu1 = NULL, *nu2 = NULL;
+ float *fp, shear, x, si, co;
+ VFontData *vfd = NULL;
+ VChar *che = NULL;
+ int i;
+
+ vfd = vfont_get_data(which_vfont(cu, info));
+ if (!vfd)
+ return;
+
+ /* make a copy at distance ofsx, ofsy with shear */
+ shear = cu->shear;
+ si = sinf(rot);
+ co = cosf(rot);
+
+ che = find_vfont_char(vfd, character);
+
+ /* Select the glyph data */
+ if (che)
+ nu1 = che->nurbsbase.first;
+
+ /* Create the character */
+ while (nu1) {
+ bezt1 = nu1->bezt;
+ if (bezt1) {
+ nu2 = (Nurb *)MEM_mallocN(sizeof(Nurb), "duplichar_nurb");
+ if (nu2 == NULL)
+ break;
+ memcpy(nu2, nu1, sizeof(struct Nurb));
+ nu2->resolu = cu->resolu;
+ nu2->bp = NULL;
+ nu2->knotsu = nu2->knotsv = NULL;
+ nu2->flag = CU_SMOOTH;
+ nu2->charidx = charidx;
+ if (info->mat_nr > 0) {
+ nu2->mat_nr = info->mat_nr - 1;
+ }
+ else {
+ nu2->mat_nr = 0;
+ }
+ /* nu2->trim.first = 0; */
+ /* nu2->trim.last = 0; */
+ i = nu2->pntsu;
+
+ bezt2 = (BezTriple *)MEM_malloc_arrayN(i, sizeof(BezTriple), "duplichar_bezt2");
+ if (bezt2 == NULL) {
+ MEM_freeN(nu2);
+ break;
+ }
+ memcpy(bezt2, bezt1, i * sizeof(struct BezTriple));
+ nu2->bezt = bezt2;
+
+ if (shear != 0.0f) {
+ bezt2 = nu2->bezt;
+
+ for (i = nu2->pntsu; i > 0; i--) {
+ bezt2->vec[0][0] += shear * bezt2->vec[0][1];
+ bezt2->vec[1][0] += shear * bezt2->vec[1][1];
+ bezt2->vec[2][0] += shear * bezt2->vec[2][1];
+ bezt2++;
+ }
+ }
+ if (rot != 0.0f) {
+ bezt2 = nu2->bezt;
+ for (i = nu2->pntsu; i > 0; i--) {
+ fp = bezt2->vec[0];
+
+ x = fp[0];
+ fp[0] = co * x + si * fp[1];
+ fp[1] = -si * x + co * fp[1];
+ x = fp[3];
+ fp[3] = co * x + si * fp[4];
+ fp[4] = -si * x + co * fp[4];
+ x = fp[6];
+ fp[6] = co * x + si * fp[7];
+ fp[7] = -si * x + co * fp[7];
+
+ bezt2++;
+ }
+ }
+ bezt2 = nu2->bezt;
+
+ if (info->flag & CU_CHINFO_SMALLCAPS_CHECK) {
+ const float sca = cu->smallcaps_scale;
+ for (i = nu2->pntsu; i > 0; i--) {
+ fp = bezt2->vec[0];
+ fp[0] *= sca;
+ fp[1] *= sca;
+ fp[3] *= sca;
+ fp[4] *= sca;
+ fp[6] *= sca;
+ fp[7] *= sca;
+ bezt2++;
+ }
+ }
+ bezt2 = nu2->bezt;
+
+ for (i = nu2->pntsu; i > 0; i--) {
+ fp = bezt2->vec[0];
+ fp[0] = (fp[0] + ofsx) * fsize;
+ fp[1] = (fp[1] + ofsy) * fsize;
+ fp[3] = (fp[3] + ofsx) * fsize;
+ fp[4] = (fp[4] + ofsy) * fsize;
+ fp[6] = (fp[6] + ofsx) * fsize;
+ fp[7] = (fp[7] + ofsy) * fsize;
+ bezt2++;
+ }
+
+ BLI_addtail(nubase, nu2);
+ }
+
+ nu1 = nu1->next;
+ }
}
int BKE_vfont_select_get(Object *ob, int *r_start, int *r_end)
{
- Curve *cu = ob->data;
- EditFont *ef = cu->editfont;
- int start, end, direction;
-
- if ((ob->type != OB_FONT) || (ef == NULL)) return 0;
-
- BLI_assert(ef->len >= 0);
- BLI_assert(ef->selstart >= 0 && ef->selstart <= ef->len + 1);
- BLI_assert(ef->selend >= 0 && ef->selend <= ef->len + 1);
- BLI_assert(ef->pos >= 0 && ef->pos <= ef->len);
-
- if (ef->selstart == 0) {
- return 0;
- }
-
- if (ef->selstart <= ef->selend) {
- start = ef->selstart - 1;
- end = ef->selend - 1;
- direction = 1;
- }
- else {
- start = ef->selend;
- end = ef->selstart - 2;
- direction = -1;
- }
-
- if (start == end + 1) {
- return 0;
- }
- else {
- BLI_assert(start < end + 1);
- *r_start = start;
- *r_end = end;
- return direction;
- }
+ Curve *cu = ob->data;
+ EditFont *ef = cu->editfont;
+ int start, end, direction;
+
+ if ((ob->type != OB_FONT) || (ef == NULL))
+ return 0;
+
+ BLI_assert(ef->len >= 0);
+ BLI_assert(ef->selstart >= 0 && ef->selstart <= ef->len + 1);
+ BLI_assert(ef->selend >= 0 && ef->selend <= ef->len + 1);
+ BLI_assert(ef->pos >= 0 && ef->pos <= ef->len);
+
+ if (ef->selstart == 0) {
+ return 0;
+ }
+
+ if (ef->selstart <= ef->selend) {
+ start = ef->selstart - 1;
+ end = ef->selend - 1;
+ direction = 1;
+ }
+ else {
+ start = ef->selend;
+ end = ef->selstart - 2;
+ direction = -1;
+ }
+
+ if (start == end + 1) {
+ return 0;
+ }
+ else {
+ BLI_assert(start < end + 1);
+ *r_start = start;
+ *r_end = end;
+ return direction;
+ }
}
void BKE_vfont_select_clamp(Object *ob)
{
- Curve *cu = ob->data;
- EditFont *ef = cu->editfont;
+ Curve *cu = ob->data;
+ EditFont *ef = cu->editfont;
- BLI_assert((ob->type == OB_FONT) && ef);
+ BLI_assert((ob->type == OB_FONT) && ef);
- CLAMP_MAX(ef->pos, ef->len);
- CLAMP_MAX(ef->selstart, ef->len + 1);
- CLAMP_MAX(ef->selend, ef->len);
+ CLAMP_MAX(ef->pos, ef->len);
+ CLAMP_MAX(ef->selstart, ef->len + 1);
+ CLAMP_MAX(ef->selend, ef->len);
}
static float char_width(Curve *cu, VChar *che, CharInfo *info)
{
- /* The character wasn't found, probably ascii = 0, then the width shall be 0 as well */
- if (che == NULL) {
- return 0.0f;
- }
- else if (info->flag & CU_CHINFO_SMALLCAPS_CHECK) {
- return che->width * cu->smallcaps_scale;
- }
- else {
- return che->width;
- }
+ /* The character wasn't found, probably ascii = 0, then the width shall be 0 as well */
+ if (che == NULL) {
+ return 0.0f;
+ }
+ else if (info->flag & CU_CHINFO_SMALLCAPS_CHECK) {
+ return che->width * cu->smallcaps_scale;
+ }
+ else {
+ return che->width;
+ }
}
static void textbox_scale(TextBox *tb_dst, const TextBox *tb_src, float scale)
{
- tb_dst->x = tb_src->x * scale;
- tb_dst->y = tb_src->y * scale;
- tb_dst->w = tb_src->w * scale;
- tb_dst->h = tb_src->h * scale;
+ tb_dst->x = tb_src->x * scale;
+ tb_dst->y = tb_src->y * scale;
+ tb_dst->w = tb_src->w * scale;
+ tb_dst->h = tb_src->h * scale;
}
/**
* Used for storing per-line data for alignment & wrapping.
*/
struct TempLineInfo {
- float x_min; /* left margin */
- float x_max; /* right margin */
- int char_nr; /* number of characters */
- int wspace_nr; /* number of whitespaces of line */
+ float x_min; /* left margin */
+ float x_max; /* right margin */
+ int char_nr; /* number of characters */
+ int wspace_nr; /* number of whitespaces of line */
};
typedef struct VFontToCurveIter {
- int iteraction;
- float scale_to_fit;
- struct {
- float min;
- float max;
- } bisect;
- bool ok;
- int status;
+ int iteraction;
+ float scale_to_fit;
+ struct {
+ float min;
+ float max;
+ } bisect;
+ bool ok;
+ int status;
} VFontToCurveIter;
enum {
- VFONT_TO_CURVE_INIT = 0,
- VFONT_TO_CURVE_BISECT,
- VFONT_TO_CURVE_SCALE_ONCE,
- VFONT_TO_CURVE_DONE,
+ VFONT_TO_CURVE_INIT = 0,
+ VFONT_TO_CURVE_BISECT,
+ VFONT_TO_CURVE_SCALE_ONCE,
+ VFONT_TO_CURVE_DONE,
};
#define FONT_TO_CURVE_SCALE_ITERATIONS 20
@@ -655,886 +673,893 @@ enum {
#define ASCENT(vfd) ((vfd)->ascender * (vfd)->em_height)
#define DESCENT(vfd) ((vfd)->em_height - ASCENT(vfd))
-static bool vfont_to_curve(Object *ob, Curve *cu, int mode,
+static bool vfont_to_curve(Object *ob,
+ Curve *cu,
+ int mode,
VFontToCurveIter *iter_data,
ListBase *r_nubase,
- const wchar_t **r_text, int *r_text_len, bool *r_text_free,
+ const wchar_t **r_text,
+ int *r_text_len,
+ bool *r_text_free,
struct CharTrans **r_chartransdata)
{
- EditFont *ef = cu->editfont;
- EditFontSelBox *selboxes = NULL;
- VFont *vfont, *oldvfont;
- VFontData *vfd = NULL;
- CharInfo *info = NULL, *custrinfo;
- TextBox tb_scale;
- bool use_textbox;
- VChar *che;
- struct CharTrans *chartransdata = NULL, *ct;
- struct TempLineInfo *lineinfo;
- float *f, xof, yof, xtrax, linedist;
- float twidth = 0, maxlen = 0;
- int i, slen, j;
- int curbox;
- int selstart, selend;
- int cnr = 0, lnr = 0, wsnr = 0;
- const wchar_t *mem = NULL;
- wchar_t ascii;
- bool ok = false;
- const float font_size = cu->fsize * iter_data->scale_to_fit;
- const float xof_scale = cu->xof / font_size;
- const float yof_scale = cu->yof / font_size;
- int last_line = -1;
- /* Length of the text disregarding \n breaks. */
- float current_line_length = 0.0f;
- float longest_line_length = 0.0f;
-
- /* Text at the beginning of the last used text-box (use for y-axis alignment).
- * We overallocate by one to simplify logic of getting last char. */
- int *i_textbox_array = MEM_callocN(sizeof(*i_textbox_array) * (cu->totbox + 1), "TextBox initial char index");
+ EditFont *ef = cu->editfont;
+ EditFontSelBox *selboxes = NULL;
+ VFont *vfont, *oldvfont;
+ VFontData *vfd = NULL;
+ CharInfo *info = NULL, *custrinfo;
+ TextBox tb_scale;
+ bool use_textbox;
+ VChar *che;
+ struct CharTrans *chartransdata = NULL, *ct;
+ struct TempLineInfo *lineinfo;
+ float *f, xof, yof, xtrax, linedist;
+ float twidth = 0, maxlen = 0;
+ int i, slen, j;
+ int curbox;
+ int selstart, selend;
+ int cnr = 0, lnr = 0, wsnr = 0;
+ const wchar_t *mem = NULL;
+ wchar_t ascii;
+ bool ok = false;
+ const float font_size = cu->fsize * iter_data->scale_to_fit;
+ const float xof_scale = cu->xof / font_size;
+ const float yof_scale = cu->yof / font_size;
+ int last_line = -1;
+ /* Length of the text disregarding \n breaks. */
+ float current_line_length = 0.0f;
+ float longest_line_length = 0.0f;
+
+ /* Text at the beginning of the last used text-box (use for y-axis alignment).
+ * We overallocate by one to simplify logic of getting last char. */
+ int *i_textbox_array = MEM_callocN(sizeof(*i_textbox_array) * (cu->totbox + 1),
+ "TextBox initial char index");
#define MARGIN_X_MIN (xof_scale + tb_scale.x)
#define MARGIN_Y_MIN (yof_scale + tb_scale.y)
- /* remark: do calculations including the trailing '\0' of a string
- * because the cursor can be at that location */
-
- BLI_assert(ob == NULL || ob->type == OB_FONT);
+ /* remark: do calculations including the trailing '\0' of a string
+ * because the cursor can be at that location */
- /* Set font data */
- vfont = cu->vfont;
+ BLI_assert(ob == NULL || ob->type == OB_FONT);
- if (cu->str == NULL) return ok;
- if (vfont == NULL) return ok;
+ /* Set font data */
+ vfont = cu->vfont;
- vfd = vfont_get_data(vfont);
+ if (cu->str == NULL)
+ return ok;
+ if (vfont == NULL)
+ return ok;
- /* The VFont Data can not be found */
- if (!vfd) return ok;
-
- if (ef) {
- slen = ef->len;
- mem = ef->textbuf;
- custrinfo = ef->textbufinfo;
- }
- else {
- wchar_t *mem_tmp;
- slen = cu->len_wchar;
-
- /* Create unicode string */
- mem_tmp = MEM_malloc_arrayN((slen + 1), sizeof(wchar_t), "convertedmem");
- if (!mem_tmp) {
- return ok;
- }
-
- BLI_strncpy_wchar_from_utf8(mem_tmp, cu->str, slen + 1);
-
- if (cu->strinfo == NULL) { /* old file */
- cu->strinfo = MEM_calloc_arrayN((slen + 4), sizeof(CharInfo), "strinfo compat");
- }
- custrinfo = cu->strinfo;
- if (!custrinfo) {
- return ok;
- }
-
- mem = mem_tmp;
- }
-
- if (cu->tb == NULL)
- cu->tb = MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), "TextBox compat");
-
- if (ef != NULL && ob != NULL) {
- if (ef->selboxes)
- MEM_freeN(ef->selboxes);
-
- if (BKE_vfont_select_get(ob, &selstart, &selend)) {
- ef->selboxes_len = (selend - selstart) + 1;
- ef->selboxes = MEM_calloc_arrayN(ef->selboxes_len, sizeof(EditFontSelBox), "font selboxes");
- }
- else {
- ef->selboxes_len = 0;
- ef->selboxes = NULL;
- }
-
- selboxes = ef->selboxes;
- }
-
- /* calc offset and rotation of each char */
- ct = chartransdata = MEM_calloc_arrayN((slen + 1), sizeof(struct CharTrans), "buildtext");
-
- /* We assume the worst case: 1 character per line (is freed at end anyway) */
- lineinfo = MEM_malloc_arrayN((slen * 2 + 1), sizeof(*lineinfo), "lineinfo");
-
- linedist = cu->linedist;
-
- curbox = 0;
- textbox_scale(&tb_scale, &cu->tb[curbox], 1.0f / font_size);
- use_textbox = (tb_scale.w != 0.0f);
-
-
- xof = MARGIN_X_MIN;
- yof = MARGIN_Y_MIN;
-
- xtrax = 0.5f * cu->spacing - 0.5f;
-
- oldvfont = NULL;
-
- for (i = 0; i < slen; i++) {
- custrinfo[i].flag &= ~(CU_CHINFO_WRAP | CU_CHINFO_SMALLCAPS_CHECK | CU_CHINFO_OVERFLOW);
- }
-
- for (i = 0; i <= slen; i++) {
-makebreak:
- /* Characters in the list */
- info = &custrinfo[i];
- ascii = mem[i];
- if (info->flag & CU_CHINFO_SMALLCAPS) {
- ascii = towupper(ascii);
- if (mem[i] != ascii) {
- info->flag |= CU_CHINFO_SMALLCAPS_CHECK;
- }
- }
-
- vfont = which_vfont(cu, info);
-
- if (vfont == NULL) break;
-
- if (vfont != oldvfont) {
- vfd = vfont_get_data(vfont);
- oldvfont = vfont;
- }
-
- /* VFont Data for VFont couldn't be found */
- if (!vfd) {
- MEM_freeN(chartransdata);
- chartransdata = NULL;
- MEM_freeN(lineinfo);
- goto finally;
- }
-
- if (!ELEM(ascii, '\n', '\0')) {
- BLI_rw_mutex_lock(&vfont_rwlock, THREAD_LOCK_READ);
- che = find_vfont_char(vfd, ascii);
- BLI_rw_mutex_unlock(&vfont_rwlock);
-
- /*
- * The character wasn't in the current curve base so load it
- * But if the font is built-in then do not try loading since
- * whole font is in the memory already
- */
- if (che == NULL && BKE_vfont_is_builtin(vfont) == false) {
- BLI_rw_mutex_lock(&vfont_rwlock, THREAD_LOCK_WRITE);
- /* Check it once again, char might have been already load
- * between previous BLI_rw_mutex_unlock() and this BLI_rw_mutex_lock().
- *
- * Such a check should not be a bottleneck since it wouldn't
- * happen often once all the chars are load.
- */
- if ((che = find_vfont_char(vfd, ascii)) == NULL) {
- che = BLI_vfontchar_from_freetypefont(vfont, ascii);
- }
- BLI_rw_mutex_unlock(&vfont_rwlock);
- }
- }
- else {
- che = NULL;
- }
-
- twidth = char_width(cu, che, info);
-
- /* Calculate positions */
- if ((tb_scale.w != 0.0f) &&
- (ct->dobreak == 0) &&
- (((xof - tb_scale.x) + twidth) > xof_scale + tb_scale.w))
- {
- // CLOG_WARN(&LOG, "linewidth exceeded: %c%c%c...", mem[i], mem[i+1], mem[i+2]);
- for (j = i; j && (mem[j] != '\n') && (chartransdata[j].dobreak == 0); j--) {
- bool dobreak = false;
- if (mem[j] == ' ' || mem[j] == '-') {
- ct -= (i - (j - 1));
- cnr -= (i - (j - 1));
- if (mem[j] == ' ') wsnr--;
- if (mem[j] == '-') wsnr++;
- i = j - 1;
- xof = ct->xof;
- ct[1].dobreak = 1;
- custrinfo[i + 1].flag |= CU_CHINFO_WRAP;
- dobreak = true;
- }
- else if (chartransdata[j].dobreak) {
- // CLOG_WARN(&LOG, "word too long: %c%c%c...", mem[j], mem[j+1], mem[j+2]);
- ct->dobreak = 1;
- custrinfo[i + 1].flag |= CU_CHINFO_WRAP;
- ct -= 1;
- cnr -= 1;
- i--;
- xof = ct->xof;
- dobreak = true;
- }
- if (dobreak) {
- if (tb_scale.h == 0.0f) {
- /* Note: If underlined text is truncated away, the extra space is also truncated. */
- custrinfo[i + 1].flag |= CU_CHINFO_OVERFLOW;
- }
- goto makebreak;
- }
- }
- }
-
- if (ascii == '\n' || ascii == 0 || ct->dobreak) {
- ct->xof = xof;
- ct->yof = yof;
- ct->linenr = lnr;
- ct->charnr = cnr;
-
- yof -= linedist;
-
- lineinfo[lnr].x_min = (xof - xtrax) - tb_scale.x;
- lineinfo[lnr].x_max = tb_scale.w;
- lineinfo[lnr].char_nr = cnr;
- lineinfo[lnr].wspace_nr = wsnr;
-
- CLAMP_MIN(maxlen, lineinfo[lnr].x_min);
-
- if ((tb_scale.h != 0.0f) &&
- ((-(yof - tb_scale.y)) > (tb_scale.h - linedist) - yof_scale))
- {
- if (cu->totbox > (curbox + 1)) {
- maxlen = 0;
- curbox++;
- i_textbox_array[curbox] = i + 1;
-
- textbox_scale(&tb_scale, &cu->tb[curbox], 1.0f / font_size);
-
- yof = MARGIN_Y_MIN;
- }
- else if (last_line == -1) {
- last_line = lnr + 1;
- info->flag |= CU_CHINFO_OVERFLOW;
- }
- }
-
- current_line_length += xof;
- if (ct->dobreak) {
- current_line_length += twidth;
- }
- else {
- longest_line_length = MAX2(current_line_length, longest_line_length);
- current_line_length = 0.0f;
- }
-
- /* XXX, has been unused for years, need to check if this is useful, r4613 r5282 - campbell */
+ vfd = vfont_get_data(vfont);
+
+ /* The VFont Data can not be found */
+ if (!vfd)
+ return ok;
+
+ if (ef) {
+ slen = ef->len;
+ mem = ef->textbuf;
+ custrinfo = ef->textbufinfo;
+ }
+ else {
+ wchar_t *mem_tmp;
+ slen = cu->len_wchar;
+
+ /* Create unicode string */
+ mem_tmp = MEM_malloc_arrayN((slen + 1), sizeof(wchar_t), "convertedmem");
+ if (!mem_tmp) {
+ return ok;
+ }
+
+ BLI_strncpy_wchar_from_utf8(mem_tmp, cu->str, slen + 1);
+
+ if (cu->strinfo == NULL) { /* old file */
+ cu->strinfo = MEM_calloc_arrayN((slen + 4), sizeof(CharInfo), "strinfo compat");
+ }
+ custrinfo = cu->strinfo;
+ if (!custrinfo) {
+ return ok;
+ }
+
+ mem = mem_tmp;
+ }
+
+ if (cu->tb == NULL)
+ cu->tb = MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), "TextBox compat");
+
+ if (ef != NULL && ob != NULL) {
+ if (ef->selboxes)
+ MEM_freeN(ef->selboxes);
+
+ if (BKE_vfont_select_get(ob, &selstart, &selend)) {
+ ef->selboxes_len = (selend - selstart) + 1;
+ ef->selboxes = MEM_calloc_arrayN(ef->selboxes_len, sizeof(EditFontSelBox), "font selboxes");
+ }
+ else {
+ ef->selboxes_len = 0;
+ ef->selboxes = NULL;
+ }
+
+ selboxes = ef->selboxes;
+ }
+
+ /* calc offset and rotation of each char */
+ ct = chartransdata = MEM_calloc_arrayN((slen + 1), sizeof(struct CharTrans), "buildtext");
+
+ /* We assume the worst case: 1 character per line (is freed at end anyway) */
+ lineinfo = MEM_malloc_arrayN((slen * 2 + 1), sizeof(*lineinfo), "lineinfo");
+
+ linedist = cu->linedist;
+
+ curbox = 0;
+ textbox_scale(&tb_scale, &cu->tb[curbox], 1.0f / font_size);
+ use_textbox = (tb_scale.w != 0.0f);
+
+ xof = MARGIN_X_MIN;
+ yof = MARGIN_Y_MIN;
+
+ xtrax = 0.5f * cu->spacing - 0.5f;
+
+ oldvfont = NULL;
+
+ for (i = 0; i < slen; i++) {
+ custrinfo[i].flag &= ~(CU_CHINFO_WRAP | CU_CHINFO_SMALLCAPS_CHECK | CU_CHINFO_OVERFLOW);
+ }
+
+ for (i = 0; i <= slen; i++) {
+ makebreak:
+ /* Characters in the list */
+ info = &custrinfo[i];
+ ascii = mem[i];
+ if (info->flag & CU_CHINFO_SMALLCAPS) {
+ ascii = towupper(ascii);
+ if (mem[i] != ascii) {
+ info->flag |= CU_CHINFO_SMALLCAPS_CHECK;
+ }
+ }
+
+ vfont = which_vfont(cu, info);
+
+ if (vfont == NULL)
+ break;
+
+ if (vfont != oldvfont) {
+ vfd = vfont_get_data(vfont);
+ oldvfont = vfont;
+ }
+
+ /* VFont Data for VFont couldn't be found */
+ if (!vfd) {
+ MEM_freeN(chartransdata);
+ chartransdata = NULL;
+ MEM_freeN(lineinfo);
+ goto finally;
+ }
+
+ if (!ELEM(ascii, '\n', '\0')) {
+ BLI_rw_mutex_lock(&vfont_rwlock, THREAD_LOCK_READ);
+ che = find_vfont_char(vfd, ascii);
+ BLI_rw_mutex_unlock(&vfont_rwlock);
+
+ /*
+ * The character wasn't in the current curve base so load it
+ * But if the font is built-in then do not try loading since
+ * whole font is in the memory already
+ */
+ if (che == NULL && BKE_vfont_is_builtin(vfont) == false) {
+ BLI_rw_mutex_lock(&vfont_rwlock, THREAD_LOCK_WRITE);
+ /* Check it once again, char might have been already load
+ * between previous BLI_rw_mutex_unlock() and this BLI_rw_mutex_lock().
+ *
+ * Such a check should not be a bottleneck since it wouldn't
+ * happen often once all the chars are load.
+ */
+ if ((che = find_vfont_char(vfd, ascii)) == NULL) {
+ che = BLI_vfontchar_from_freetypefont(vfont, ascii);
+ }
+ BLI_rw_mutex_unlock(&vfont_rwlock);
+ }
+ }
+ else {
+ che = NULL;
+ }
+
+ twidth = char_width(cu, che, info);
+
+ /* Calculate positions */
+ if ((tb_scale.w != 0.0f) && (ct->dobreak == 0) &&
+ (((xof - tb_scale.x) + twidth) > xof_scale + tb_scale.w)) {
+ // CLOG_WARN(&LOG, "linewidth exceeded: %c%c%c...", mem[i], mem[i+1], mem[i+2]);
+ for (j = i; j && (mem[j] != '\n') && (chartransdata[j].dobreak == 0); j--) {
+ bool dobreak = false;
+ if (mem[j] == ' ' || mem[j] == '-') {
+ ct -= (i - (j - 1));
+ cnr -= (i - (j - 1));
+ if (mem[j] == ' ')
+ wsnr--;
+ if (mem[j] == '-')
+ wsnr++;
+ i = j - 1;
+ xof = ct->xof;
+ ct[1].dobreak = 1;
+ custrinfo[i + 1].flag |= CU_CHINFO_WRAP;
+ dobreak = true;
+ }
+ else if (chartransdata[j].dobreak) {
+ // CLOG_WARN(&LOG, "word too long: %c%c%c...", mem[j], mem[j+1], mem[j+2]);
+ ct->dobreak = 1;
+ custrinfo[i + 1].flag |= CU_CHINFO_WRAP;
+ ct -= 1;
+ cnr -= 1;
+ i--;
+ xof = ct->xof;
+ dobreak = true;
+ }
+ if (dobreak) {
+ if (tb_scale.h == 0.0f) {
+ /* Note: If underlined text is truncated away, the extra space is also truncated. */
+ custrinfo[i + 1].flag |= CU_CHINFO_OVERFLOW;
+ }
+ goto makebreak;
+ }
+ }
+ }
+
+ if (ascii == '\n' || ascii == 0 || ct->dobreak) {
+ ct->xof = xof;
+ ct->yof = yof;
+ ct->linenr = lnr;
+ ct->charnr = cnr;
+
+ yof -= linedist;
+
+ lineinfo[lnr].x_min = (xof - xtrax) - tb_scale.x;
+ lineinfo[lnr].x_max = tb_scale.w;
+ lineinfo[lnr].char_nr = cnr;
+ lineinfo[lnr].wspace_nr = wsnr;
+
+ CLAMP_MIN(maxlen, lineinfo[lnr].x_min);
+
+ if ((tb_scale.h != 0.0f) && ((-(yof - tb_scale.y)) > (tb_scale.h - linedist) - yof_scale)) {
+ if (cu->totbox > (curbox + 1)) {
+ maxlen = 0;
+ curbox++;
+ i_textbox_array[curbox] = i + 1;
+
+ textbox_scale(&tb_scale, &cu->tb[curbox], 1.0f / font_size);
+
+ yof = MARGIN_Y_MIN;
+ }
+ else if (last_line == -1) {
+ last_line = lnr + 1;
+ info->flag |= CU_CHINFO_OVERFLOW;
+ }
+ }
+
+ current_line_length += xof;
+ if (ct->dobreak) {
+ current_line_length += twidth;
+ }
+ else {
+ longest_line_length = MAX2(current_line_length, longest_line_length);
+ current_line_length = 0.0f;
+ }
+
+ /* XXX, has been unused for years, need to check if this is useful, r4613 r5282 - campbell */
#if 0
- if (ascii == '\n')
- xof = xof_scale;
- else
- xof = MARGIN_X_MIN;
+ if (ascii == '\n')
+ xof = xof_scale;
+ else
+ xof = MARGIN_X_MIN;
#else
- xof = MARGIN_X_MIN;
+ xof = MARGIN_X_MIN;
#endif
- lnr++;
- cnr = 0;
- wsnr = 0;
- }
- else if (ascii == 9) { /* TAB */
- float tabfac;
-
- ct->xof = xof;
- ct->yof = yof;
- ct->linenr = lnr;
- ct->charnr = cnr++;
-
- tabfac = (xof - MARGIN_X_MIN + 0.01f);
- tabfac = 2.0f * ceilf(tabfac / 2.0f);
- xof = MARGIN_X_MIN + tabfac;
- }
- else {
- EditFontSelBox *sb = NULL;
- float wsfac;
-
- ct->xof = xof;
- ct->yof = yof;
- ct->linenr = lnr;
- ct->charnr = cnr++;
-
- if (selboxes && (i >= selstart) && (i <= selend)) {
- sb = &selboxes[i - selstart];
- sb->y = yof * font_size - linedist * font_size * 0.1f;
- sb->h = linedist * font_size;
- sb->w = xof * font_size;
- }
-
- if (ascii == 32) {
- wsfac = cu->wordspace;
- wsnr++;
- }
- else {
- wsfac = 1.0f;
- }
-
- /* Set the width of the character */
- twidth = char_width(cu, che, info);
-
- xof += (twidth * wsfac * (1.0f + (info->kern / 40.0f)) ) + xtrax;
-
- if (sb) {
- sb->w = (xof * font_size) - sb->w;
- }
- }
- ct++;
- }
- current_line_length += xof + twidth;
- longest_line_length = MAX2(current_line_length, longest_line_length);
-
- cu->lines = 1;
- for (i = 0; i <= slen; i++) {
- ascii = mem[i];
- ct = &chartransdata[i];
- if (ascii == '\n' || ct->dobreak) cu->lines++;
- }
-
- /* linedata is now: width of line */
-
- if (cu->spacemode != CU_ALIGN_X_LEFT) {
- ct = chartransdata;
-
- if (cu->spacemode == CU_ALIGN_X_RIGHT) {
- struct TempLineInfo *li;
-
- for (i = 0, li = lineinfo; i < lnr; i++, li++) {
- li->x_min = (li->x_max - li->x_min) + xof_scale;
- }
-
- for (i = 0; i <= slen; i++) {
- ct->xof += lineinfo[ct->linenr].x_min;
- ct++;
- }
- }
- else if (cu->spacemode == CU_ALIGN_X_MIDDLE) {
- struct TempLineInfo *li;
-
- for (i = 0, li = lineinfo; i < lnr; i++, li++) {
- li->x_min = ((li->x_max - li->x_min) + xof_scale) / 2.0f;
- }
-
- for (i = 0; i <= slen; i++) {
- ct->xof += lineinfo[ct->linenr].x_min;
- ct++;
- }
- }
- else if ((cu->spacemode == CU_ALIGN_X_FLUSH) && use_textbox) {
- struct TempLineInfo *li;
-
- for (i = 0, li = lineinfo; i < lnr; i++, li++) {
- li->x_min = ((li->x_max - li->x_min) + xof_scale);
-
- if (li->char_nr > 1) {
- li->x_min /= (float)(li->char_nr - 1);
- }
- }
- for (i = 0; i <= slen; i++) {
- for (j = i; (!ELEM(mem[j], '\0', '\n')) && (chartransdata[j].dobreak == 0) && (j < slen); j++) {
- /* do nothing */
- }
-
-// if ((mem[j] != '\n') && (mem[j])) {
- ct->xof += ct->charnr * lineinfo[ct->linenr].x_min;
-// }
- ct++;
- }
- }
- else if ((cu->spacemode == CU_ALIGN_X_JUSTIFY) && use_textbox) {
- float curofs = 0.0f;
- for (i = 0; i <= slen; i++) {
- for (j = i;
- (mem[j]) && (mem[j] != '\n') && (chartransdata[j].dobreak == 0) && (j < slen);
- j++)
- {
- /* pass */
- }
-
- if ((mem[j] != '\n') &&
- ((chartransdata[j].dobreak != 0)))
- {
- if (mem[i] == ' ') {
- struct TempLineInfo *li;
-
- li = &lineinfo[ct->linenr];
- curofs += ((li->x_max - li->x_min) + xof_scale) / (float)li->wspace_nr;
- }
- ct->xof += curofs;
- }
- if (mem[i] == '\n' || chartransdata[i].dobreak) curofs = 0;
- ct++;
- }
- }
- }
-
- /* top-baseline is default, in this case, do nothing */
- if (cu->align_y != CU_ALIGN_Y_TOP_BASELINE) {
- if (tb_scale.h != 0.0f) {
- /* We need to loop all the text-boxes even the "full" ones.
- * This way they all get the same vertical padding. */
- for (int tb_index = 0; tb_index < cu->totbox; tb_index++) {
- struct CharTrans *ct_first, *ct_last;
- const int i_textbox = i_textbox_array[tb_index];
- const int i_textbox_next = i_textbox_array[tb_index + 1];
- const bool is_last_filled_textbox = ELEM(i_textbox_next, 0, slen + 1);
- int lines;
-
- ct_first = chartransdata + i_textbox;
- ct_last = chartransdata + (is_last_filled_textbox ? slen: i_textbox_next - 1);
- lines = ct_last->linenr - ct_first->linenr + 1;
-
- textbox_scale(&tb_scale, &cu->tb[tb_index], 1.0f / font_size);
- /* The initial Y origin of the textbox is hardcoded to 1.0f * text scale. */
- const float textbox_y_origin = 1.0f;
- float yoff = 0.0f;
-
- switch (cu->align_y) {
- case CU_ALIGN_Y_TOP_BASELINE:
- break;
- case CU_ALIGN_Y_TOP:
- yoff = textbox_y_origin - ASCENT(vfd);
- break;
- case CU_ALIGN_Y_CENTER:
- yoff = ((((vfd->em_height + (lines - 1) * linedist) * 0.5f) - ASCENT(vfd)) -
- (tb_scale.h * 0.5f) + textbox_y_origin);
- break;
- case CU_ALIGN_Y_BOTTOM_BASELINE:
- yoff = textbox_y_origin + ((lines - 1) * linedist) - tb_scale.h;
- break;
- case CU_ALIGN_Y_BOTTOM:
- yoff = textbox_y_origin + ((lines - 1) * linedist) - tb_scale.h + DESCENT(vfd);
- break;
- }
-
- for (ct = ct_first; ct <= ct_last; ct++) {
- ct->yof += yoff;
- }
-
- if (is_last_filled_textbox) {
- break;
- }
- }
- }
- else {
- /* Non text-box case handled separately. */
- float yoff = 0.0f;
-
- switch (cu->align_y) {
- case CU_ALIGN_Y_TOP_BASELINE:
- break;
- case CU_ALIGN_Y_TOP:
- yoff = -ASCENT(vfd);
- break;
- case CU_ALIGN_Y_CENTER:
- yoff = ((vfd->em_height + (lnr - 1) * linedist) * 0.5f) - ASCENT(vfd);
- break;
- case CU_ALIGN_Y_BOTTOM_BASELINE:
- yoff = (lnr - 1) * linedist;
- break;
- case CU_ALIGN_Y_BOTTOM:
- yoff = (lnr - 1) * linedist + DESCENT(vfd);
- break;
- }
-
- ct = chartransdata;
- for (i = 0; i <= slen; i++) {
- ct->yof += yoff;
- ct++;
- }
- }
- }
-
- MEM_freeN(lineinfo);
- MEM_freeN(i_textbox_array);
-
- /* TEXT ON CURVE */
- /* Note: Only OB_CURVE objects could have a path */
- if (cu->textoncurve && cu->textoncurve->type == OB_CURVE) {
- BLI_assert(cu->textoncurve->runtime.curve_cache != NULL);
- if (cu->textoncurve->runtime.curve_cache != NULL && cu->textoncurve->runtime.curve_cache->path != NULL) {
- float distfac, imat[4][4], imat3[3][3], cmat[3][3];
- float minx, maxx, miny, maxy;
- float timeofs, sizefac;
-
- if (ob != NULL) {
- invert_m4_m4(imat, ob->obmat);
- }
- else {
- unit_m4(imat);
- }
- copy_m3_m4(imat3, imat);
-
- copy_m3_m4(cmat, cu->textoncurve->obmat);
- mul_m3_m3m3(cmat, cmat, imat3);
- sizefac = normalize_v3(cmat[0]) / font_size;
-
- minx = miny = 1.0e20f;
- maxx = maxy = -1.0e20f;
- ct = chartransdata;
- for (i = 0; i <= slen; i++, ct++) {
- if (minx > ct->xof) minx = ct->xof;
- if (maxx < ct->xof) maxx = ct->xof;
- if (miny > ct->yof) miny = ct->yof;
- if (maxy < ct->yof) maxy = ct->yof;
- }
-
- /* we put the x-coordinaat exact at the curve, the y is rotated */
-
- /* length correction */
- distfac = sizefac * cu->textoncurve->runtime.curve_cache->path->totdist / (maxx - minx);
- timeofs = 0.0f;
-
- if (distfac > 1.0f) {
- /* path longer than text: spacemode involves */
- distfac = 1.0f / distfac;
-
- if (cu->spacemode == CU_ALIGN_X_RIGHT) {
- timeofs = 1.0f - distfac;
- }
- else if (cu->spacemode == CU_ALIGN_X_MIDDLE) {
- timeofs = (1.0f - distfac) / 2.0f;
- }
- else if (cu->spacemode == CU_ALIGN_X_FLUSH) {
- distfac = 1.0f;
- }
- }
- else {
- distfac = 1.0;
- }
-
- distfac /= (maxx - minx);
-
- timeofs += distfac * cu->xof; /* not cyclic */
-
- ct = chartransdata;
- for (i = 0; i <= slen; i++, ct++) {
- float ctime, dtime, vec[4], tvec[4], rotvec[3];
- float si, co;
-
- /* rotate around center character */
- info = &custrinfo[i];
- ascii = mem[i];
- if (info->flag & CU_CHINFO_SMALLCAPS_CHECK) {
- ascii = towupper(ascii);
- }
-
- che = find_vfont_char(vfd, ascii);
-
- twidth = char_width(cu, che, info);
-
- dtime = distfac * 0.5f * twidth;
-
- ctime = timeofs + distfac * (ct->xof - minx);
- CLAMP(ctime, 0.0f, 1.0f);
-
- /* calc the right loc AND the right rot separately */
- /* vec, tvec need 4 items */
- where_on_path(cu->textoncurve, ctime, vec, tvec, NULL, NULL, NULL);
- where_on_path(cu->textoncurve, ctime + dtime, tvec, rotvec, NULL, NULL, NULL);
-
- mul_v3_fl(vec, sizefac);
-
- ct->rot = (float)M_PI - atan2f(rotvec[1], rotvec[0]);
-
- si = sinf(ct->rot);
- co = cosf(ct->rot);
-
- yof = ct->yof;
-
- ct->xof = vec[0] + si * yof;
- ct->yof = vec[1] + co * yof;
-
- if (selboxes && (i >= selstart) && (i <= selend)) {
- EditFontSelBox *sb;
- sb = &selboxes[i - selstart];
- sb->rot = -ct->rot;
- }
- }
- }
- }
-
- if (selboxes) {
- ct = chartransdata;
- for (i = 0; i <= selend; i++, ct++) {
- if (i >= selstart) {
- selboxes[i - selstart].x = ct->xof * font_size;
- selboxes[i - selstart].y = ct->yof * font_size;
- }
- }
- }
-
- if (ELEM(mode, FO_CURSUP, FO_CURSDOWN, FO_PAGEUP, FO_PAGEDOWN) &&
- iter_data->status == VFONT_TO_CURVE_INIT)
- {
- ct = &chartransdata[ef->pos];
-
- if (ELEM(mode, FO_CURSUP, FO_PAGEUP) && ct->linenr == 0) {
- /* pass */
- }
- else if (ELEM(mode, FO_CURSDOWN, FO_PAGEDOWN) && ct->linenr == lnr) {
- /* pass */
- }
- else {
- switch (mode) {
- case FO_CURSUP: lnr = ct->linenr - 1; break;
- case FO_CURSDOWN: lnr = ct->linenr + 1; break;
- case FO_PAGEUP: lnr = ct->linenr - 10; break;
- case FO_PAGEDOWN: lnr = ct->linenr + 10; break;
- }
- cnr = ct->charnr;
- /* seek for char with lnr en cnr */
- ef->pos = 0;
- ct = chartransdata;
- for (i = 0; i < slen; i++) {
- if (ct->linenr == lnr) {
- if ((ct->charnr == cnr) || ((ct + 1)->charnr == 0)) {
- break;
- }
- }
- else if (ct->linenr > lnr) {
- break;
- }
- ef->pos++;
- ct++;
- }
- }
- }
-
- /* cursor first */
- if (ef) {
- float si, co;
-
- ct = &chartransdata[ef->pos];
- si = sinf(ct->rot);
- co = cosf(ct->rot);
-
- f = ef->textcurs[0];
-
- f[0] = font_size * (-0.1f * co + ct->xof);
- f[1] = font_size * ( 0.1f * si + ct->yof);
-
- f[2] = font_size * ( 0.1f * co + ct->xof);
- f[3] = font_size * (-0.1f * si + ct->yof);
-
- f[4] = font_size * ( 0.1f * co + 0.8f * si + ct->xof);
- f[5] = font_size * (-0.1f * si + 0.8f * co + ct->yof);
-
- f[6] = font_size * (-0.1f * co + 0.8f * si + ct->xof);
- f[7] = font_size * ( 0.1f * si + 0.8f * co + ct->yof);
-
- }
-
- if (mode == FO_SELCHANGE) {
- MEM_freeN(chartransdata);
- chartransdata = NULL;
- }
- else if (mode == FO_EDIT) {
- /* make nurbdata */
- BKE_nurbList_free(r_nubase);
-
- ct = chartransdata;
- for (i = 0; i < slen; i++) {
- unsigned int cha = (unsigned int) mem[i];
- info = &(custrinfo[i]);
-
- if ((cu->overflow == CU_OVERFLOW_TRUNCATE) &&
- (ob && ob->mode != OB_MODE_EDIT) &&
- (info->flag & CU_CHINFO_OVERFLOW))
- {
- break;
- }
-
- if (info->flag & CU_CHINFO_SMALLCAPS_CHECK) {
- cha = towupper(cha);
- }
-
- if (ob == NULL || info->mat_nr > (ob->totcol)) {
- /* CLOG_ERROR(&LOG, "Illegal material index (%d) in text object, setting to 0", info->mat_nr); */
- info->mat_nr = 0;
- }
- /* We do not want to see any character for \n or \r */
- if (cha != '\n')
- buildchar(cu, r_nubase, cha, info, ct->xof, ct->yof, ct->rot, i, font_size);
-
- if ((info->flag & CU_CHINFO_UNDERLINE) && (cha != '\n')) {
- float ulwidth, uloverlap = 0.0f;
- rctf rect;
-
- if ((i < (slen - 1)) && (mem[i + 1] != '\n') &&
- ((mem[i + 1] != ' ') || (custrinfo[i + 1].flag & CU_CHINFO_UNDERLINE)) &&
- ((custrinfo[i + 1].flag & CU_CHINFO_WRAP) == 0))
- {
- uloverlap = xtrax + 0.1f;
- }
- /* Find the character, the characters has to be in the memory already
- * since character checking has been done earlier already. */
- che = find_vfont_char(vfd, cha);
-
- twidth = char_width(cu, che, info);
- ulwidth = (twidth * (1.0f + (info->kern / 40.0f))) + uloverlap;
-
- rect.xmin = ct->xof;
- rect.xmax = rect.xmin + ulwidth;
-
- rect.ymin = ct->yof;
- rect.ymax = rect.ymin - cu->ulheight;
-
- build_underline(cu, r_nubase,
- &rect, cu->ulpos - 0.05f,
- ct->rot, i, info->mat_nr,
- font_size);
- }
- ct++;
- }
- }
-
- if (iter_data->status == VFONT_TO_CURVE_SCALE_ONCE) {
- /* That means we were in a final run, just exit. */
- BLI_assert(cu->overflow == CU_OVERFLOW_SCALE);
- iter_data->status = VFONT_TO_CURVE_DONE;
- }
- else if (cu->overflow == CU_OVERFLOW_NONE) {
- /* Do nothing. */
- }
- else if ((tb_scale.h == 0.0f) && (tb_scale.w == 0.0f)) {
- /* Do nothing. */
- }
- else if (cu->overflow == CU_OVERFLOW_SCALE) {
- if ((cu->totbox == 1) && ((tb_scale.w == 0.0f) || (tb_scale.h == 0.0f))) {
- /* These are special cases, simpler to deal with. */
- if (tb_scale.w == 0.0f) {
- /* This is a potential vertical overflow.
- * Since there is no width limit, all the new lines are from line breaks. */
- if ((last_line != -1) && (lnr > last_line)) {
- const float total_text_height = lnr * linedist;
- iter_data->scale_to_fit = tb_scale.h / total_text_height;
- iter_data->status = VFONT_TO_CURVE_SCALE_ONCE;
- }
- }
- else if (tb_scale.h == 0.0f) {
- /* This is a horizontal overflow. */
- if (lnr > 1) {
- /* We make sure longest line before it broke can fit here. */
- float scale_to_fit = tb_scale.w / (longest_line_length);
- scale_to_fit -= FLT_EPSILON;
-
- iter_data->scale_to_fit = scale_to_fit;
- iter_data->status = VFONT_TO_CURVE_SCALE_ONCE;
- }
- }
- }
- else {
- /* This is the really complicated case, the best we can do is to iterate over
- * this function a few times until we get an acceptable result.
- *
- * Keep in mind that there is no single number that will make all fit to the end.
- * In a way, our ultimate goal is to get the highest scale that still leads to the
- * number of extra lines to zero.
- */
- if (iter_data->status == VFONT_TO_CURVE_INIT) {
- bool valid = true;
-
- for (int tb_index = 0; tb_index <= curbox; tb_index++) {
- TextBox *tb = &cu->tb[tb_index];
- if ((tb->w == 0.0f) || (tb->h == 0.0f)) {
- valid = false;
- break;
- }
- }
-
- if (valid && (last_line != -1) && (lnr > last_line)) {
- const float total_text_height = lnr * linedist;
- float scale_to_fit = tb_scale.h / total_text_height;
-
- iter_data->bisect.max = 1.0f;
- iter_data->bisect.min = scale_to_fit;
-
- iter_data->status = VFONT_TO_CURVE_BISECT;
- }
- }
- else {
- BLI_assert(iter_data->status == VFONT_TO_CURVE_BISECT);
- /* Try to get the highest scale that gives us the exactly
- * number of lines we need. */
- bool valid = false;
-
- if ((last_line != -1) && (lnr > last_line)) {
- /* It is overflowing, scale it down. */
- iter_data->bisect.max = iter_data->scale_to_fit;
- }
- else {
- /* It fits inside the textbox, scale it up. */
- iter_data->bisect.min = iter_data->scale_to_fit;
- valid = true;
- }
-
- /* Bisecting to try to find the best fit. */
- iter_data->scale_to_fit = (iter_data->bisect.max + iter_data->bisect.min) * 0.5f;
-
- /* We iterated enough or got a good enough result. */
- if ((!iter_data->iteraction--) ||
- ((iter_data->bisect.max - iter_data->bisect.min) < (cu->fsize * FONT_TO_CURVE_SCALE_THRESHOLD)))
- {
- if (valid) {
- iter_data->status = VFONT_TO_CURVE_DONE;
- }
- else {
- iter_data->scale_to_fit = iter_data->bisect.min;
- iter_data->status = VFONT_TO_CURVE_SCALE_ONCE;
- }
- }
- }
- }
- }
-
- /* Scale to fit only works for single text box layouts. */
- if (ELEM(iter_data->status,
- VFONT_TO_CURVE_SCALE_ONCE,
- VFONT_TO_CURVE_BISECT))
- {
- /* Always cleanup before going to the scale-to-fit repetition. */
- if (r_nubase != NULL) {
- BKE_nurbList_free(r_nubase);
- }
-
- if (chartransdata != NULL) {
- MEM_freeN(chartransdata);
- }
-
- if (ef == NULL) {
- MEM_freeN((void *)mem);
- }
- return true;
- }
- else {
- ok = true;
-finally:
- if (r_text) {
- *r_text = mem;
- *r_text_len = slen;
- *r_text_free = (ef == NULL);
- }
- else {
- if (ef == NULL) {
- MEM_freeN((void *)mem);
- }
- }
-
- if (chartransdata) {
- if (ok && r_chartransdata) {
- *r_chartransdata = chartransdata;
- }
- else {
- MEM_freeN(chartransdata);
- }
- }
-
- /* Store the effective scale, to use for the textbox lines. */
- cu->fsize_realtime = font_size;
- }
- return ok;
+ lnr++;
+ cnr = 0;
+ wsnr = 0;
+ }
+ else if (ascii == 9) { /* TAB */
+ float tabfac;
+
+ ct->xof = xof;
+ ct->yof = yof;
+ ct->linenr = lnr;
+ ct->charnr = cnr++;
+
+ tabfac = (xof - MARGIN_X_MIN + 0.01f);
+ tabfac = 2.0f * ceilf(tabfac / 2.0f);
+ xof = MARGIN_X_MIN + tabfac;
+ }
+ else {
+ EditFontSelBox *sb = NULL;
+ float wsfac;
+
+ ct->xof = xof;
+ ct->yof = yof;
+ ct->linenr = lnr;
+ ct->charnr = cnr++;
+
+ if (selboxes && (i >= selstart) && (i <= selend)) {
+ sb = &selboxes[i - selstart];
+ sb->y = yof * font_size - linedist * font_size * 0.1f;
+ sb->h = linedist * font_size;
+ sb->w = xof * font_size;
+ }
+
+ if (ascii == 32) {
+ wsfac = cu->wordspace;
+ wsnr++;
+ }
+ else {
+ wsfac = 1.0f;
+ }
+
+ /* Set the width of the character */
+ twidth = char_width(cu, che, info);
+
+ xof += (twidth * wsfac * (1.0f + (info->kern / 40.0f))) + xtrax;
+
+ if (sb) {
+ sb->w = (xof * font_size) - sb->w;
+ }
+ }
+ ct++;
+ }
+ current_line_length += xof + twidth;
+ longest_line_length = MAX2(current_line_length, longest_line_length);
+
+ cu->lines = 1;
+ for (i = 0; i <= slen; i++) {
+ ascii = mem[i];
+ ct = &chartransdata[i];
+ if (ascii == '\n' || ct->dobreak)
+ cu->lines++;
+ }
+
+ /* linedata is now: width of line */
+
+ if (cu->spacemode != CU_ALIGN_X_LEFT) {
+ ct = chartransdata;
+
+ if (cu->spacemode == CU_ALIGN_X_RIGHT) {
+ struct TempLineInfo *li;
+
+ for (i = 0, li = lineinfo; i < lnr; i++, li++) {
+ li->x_min = (li->x_max - li->x_min) + xof_scale;
+ }
+
+ for (i = 0; i <= slen; i++) {
+ ct->xof += lineinfo[ct->linenr].x_min;
+ ct++;
+ }
+ }
+ else if (cu->spacemode == CU_ALIGN_X_MIDDLE) {
+ struct TempLineInfo *li;
+
+ for (i = 0, li = lineinfo; i < lnr; i++, li++) {
+ li->x_min = ((li->x_max - li->x_min) + xof_scale) / 2.0f;
+ }
+
+ for (i = 0; i <= slen; i++) {
+ ct->xof += lineinfo[ct->linenr].x_min;
+ ct++;
+ }
+ }
+ else if ((cu->spacemode == CU_ALIGN_X_FLUSH) && use_textbox) {
+ struct TempLineInfo *li;
+
+ for (i = 0, li = lineinfo; i < lnr; i++, li++) {
+ li->x_min = ((li->x_max - li->x_min) + xof_scale);
+
+ if (li->char_nr > 1) {
+ li->x_min /= (float)(li->char_nr - 1);
+ }
+ }
+ for (i = 0; i <= slen; i++) {
+ for (j = i; (!ELEM(mem[j], '\0', '\n')) && (chartransdata[j].dobreak == 0) && (j < slen);
+ j++) {
+ /* do nothing */
+ }
+
+ // if ((mem[j] != '\n') && (mem[j])) {
+ ct->xof += ct->charnr * lineinfo[ct->linenr].x_min;
+ // }
+ ct++;
+ }
+ }
+ else if ((cu->spacemode == CU_ALIGN_X_JUSTIFY) && use_textbox) {
+ float curofs = 0.0f;
+ for (i = 0; i <= slen; i++) {
+ for (j = i; (mem[j]) && (mem[j] != '\n') && (chartransdata[j].dobreak == 0) && (j < slen);
+ j++) {
+ /* pass */
+ }
+
+ if ((mem[j] != '\n') && ((chartransdata[j].dobreak != 0))) {
+ if (mem[i] == ' ') {
+ struct TempLineInfo *li;
+
+ li = &lineinfo[ct->linenr];
+ curofs += ((li->x_max - li->x_min) + xof_scale) / (float)li->wspace_nr;
+ }
+ ct->xof += curofs;
+ }
+ if (mem[i] == '\n' || chartransdata[i].dobreak)
+ curofs = 0;
+ ct++;
+ }
+ }
+ }
+
+ /* top-baseline is default, in this case, do nothing */
+ if (cu->align_y != CU_ALIGN_Y_TOP_BASELINE) {
+ if (tb_scale.h != 0.0f) {
+ /* We need to loop all the text-boxes even the "full" ones.
+ * This way they all get the same vertical padding. */
+ for (int tb_index = 0; tb_index < cu->totbox; tb_index++) {
+ struct CharTrans *ct_first, *ct_last;
+ const int i_textbox = i_textbox_array[tb_index];
+ const int i_textbox_next = i_textbox_array[tb_index + 1];
+ const bool is_last_filled_textbox = ELEM(i_textbox_next, 0, slen + 1);
+ int lines;
+
+ ct_first = chartransdata + i_textbox;
+ ct_last = chartransdata + (is_last_filled_textbox ? slen : i_textbox_next - 1);
+ lines = ct_last->linenr - ct_first->linenr + 1;
+
+ textbox_scale(&tb_scale, &cu->tb[tb_index], 1.0f / font_size);
+ /* The initial Y origin of the textbox is hardcoded to 1.0f * text scale. */
+ const float textbox_y_origin = 1.0f;
+ float yoff = 0.0f;
+
+ switch (cu->align_y) {
+ case CU_ALIGN_Y_TOP_BASELINE:
+ break;
+ case CU_ALIGN_Y_TOP:
+ yoff = textbox_y_origin - ASCENT(vfd);
+ break;
+ case CU_ALIGN_Y_CENTER:
+ yoff = ((((vfd->em_height + (lines - 1) * linedist) * 0.5f) - ASCENT(vfd)) -
+ (tb_scale.h * 0.5f) + textbox_y_origin);
+ break;
+ case CU_ALIGN_Y_BOTTOM_BASELINE:
+ yoff = textbox_y_origin + ((lines - 1) * linedist) - tb_scale.h;
+ break;
+ case CU_ALIGN_Y_BOTTOM:
+ yoff = textbox_y_origin + ((lines - 1) * linedist) - tb_scale.h + DESCENT(vfd);
+ break;
+ }
+
+ for (ct = ct_first; ct <= ct_last; ct++) {
+ ct->yof += yoff;
+ }
+
+ if (is_last_filled_textbox) {
+ break;
+ }
+ }
+ }
+ else {
+ /* Non text-box case handled separately. */
+ float yoff = 0.0f;
+
+ switch (cu->align_y) {
+ case CU_ALIGN_Y_TOP_BASELINE:
+ break;
+ case CU_ALIGN_Y_TOP:
+ yoff = -ASCENT(vfd);
+ break;
+ case CU_ALIGN_Y_CENTER:
+ yoff = ((vfd->em_height + (lnr - 1) * linedist) * 0.5f) - ASCENT(vfd);
+ break;
+ case CU_ALIGN_Y_BOTTOM_BASELINE:
+ yoff = (lnr - 1) * linedist;
+ break;
+ case CU_ALIGN_Y_BOTTOM:
+ yoff = (lnr - 1) * linedist + DESCENT(vfd);
+ break;
+ }
+
+ ct = chartransdata;
+ for (i = 0; i <= slen; i++) {
+ ct->yof += yoff;
+ ct++;
+ }
+ }
+ }
+
+ MEM_freeN(lineinfo);
+ MEM_freeN(i_textbox_array);
+
+ /* TEXT ON CURVE */
+ /* Note: Only OB_CURVE objects could have a path */
+ if (cu->textoncurve && cu->textoncurve->type == OB_CURVE) {
+ BLI_assert(cu->textoncurve->runtime.curve_cache != NULL);
+ if (cu->textoncurve->runtime.curve_cache != NULL &&
+ cu->textoncurve->runtime.curve_cache->path != NULL) {
+ float distfac, imat[4][4], imat3[3][3], cmat[3][3];
+ float minx, maxx, miny, maxy;
+ float timeofs, sizefac;
+
+ if (ob != NULL) {
+ invert_m4_m4(imat, ob->obmat);
+ }
+ else {
+ unit_m4(imat);
+ }
+ copy_m3_m4(imat3, imat);
+
+ copy_m3_m4(cmat, cu->textoncurve->obmat);
+ mul_m3_m3m3(cmat, cmat, imat3);
+ sizefac = normalize_v3(cmat[0]) / font_size;
+
+ minx = miny = 1.0e20f;
+ maxx = maxy = -1.0e20f;
+ ct = chartransdata;
+ for (i = 0; i <= slen; i++, ct++) {
+ if (minx > ct->xof)
+ minx = ct->xof;
+ if (maxx < ct->xof)
+ maxx = ct->xof;
+ if (miny > ct->yof)
+ miny = ct->yof;
+ if (maxy < ct->yof)
+ maxy = ct->yof;
+ }
+
+ /* we put the x-coordinaat exact at the curve, the y is rotated */
+
+ /* length correction */
+ distfac = sizefac * cu->textoncurve->runtime.curve_cache->path->totdist / (maxx - minx);
+ timeofs = 0.0f;
+
+ if (distfac > 1.0f) {
+ /* path longer than text: spacemode involves */
+ distfac = 1.0f / distfac;
+
+ if (cu->spacemode == CU_ALIGN_X_RIGHT) {
+ timeofs = 1.0f - distfac;
+ }
+ else if (cu->spacemode == CU_ALIGN_X_MIDDLE) {
+ timeofs = (1.0f - distfac) / 2.0f;
+ }
+ else if (cu->spacemode == CU_ALIGN_X_FLUSH) {
+ distfac = 1.0f;
+ }
+ }
+ else {
+ distfac = 1.0;
+ }
+
+ distfac /= (maxx - minx);
+
+ timeofs += distfac * cu->xof; /* not cyclic */
+
+ ct = chartransdata;
+ for (i = 0; i <= slen; i++, ct++) {
+ float ctime, dtime, vec[4], tvec[4], rotvec[3];
+ float si, co;
+
+ /* rotate around center character */
+ info = &custrinfo[i];
+ ascii = mem[i];
+ if (info->flag & CU_CHINFO_SMALLCAPS_CHECK) {
+ ascii = towupper(ascii);
+ }
+
+ che = find_vfont_char(vfd, ascii);
+
+ twidth = char_width(cu, che, info);
+
+ dtime = distfac * 0.5f * twidth;
+
+ ctime = timeofs + distfac * (ct->xof - minx);
+ CLAMP(ctime, 0.0f, 1.0f);
+
+ /* calc the right loc AND the right rot separately */
+ /* vec, tvec need 4 items */
+ where_on_path(cu->textoncurve, ctime, vec, tvec, NULL, NULL, NULL);
+ where_on_path(cu->textoncurve, ctime + dtime, tvec, rotvec, NULL, NULL, NULL);
+
+ mul_v3_fl(vec, sizefac);
+
+ ct->rot = (float)M_PI - atan2f(rotvec[1], rotvec[0]);
+
+ si = sinf(ct->rot);
+ co = cosf(ct->rot);
+
+ yof = ct->yof;
+
+ ct->xof = vec[0] + si * yof;
+ ct->yof = vec[1] + co * yof;
+
+ if (selboxes && (i >= selstart) && (i <= selend)) {
+ EditFontSelBox *sb;
+ sb = &selboxes[i - selstart];
+ sb->rot = -ct->rot;
+ }
+ }
+ }
+ }
+
+ if (selboxes) {
+ ct = chartransdata;
+ for (i = 0; i <= selend; i++, ct++) {
+ if (i >= selstart) {
+ selboxes[i - selstart].x = ct->xof * font_size;
+ selboxes[i - selstart].y = ct->yof * font_size;
+ }
+ }
+ }
+
+ if (ELEM(mode, FO_CURSUP, FO_CURSDOWN, FO_PAGEUP, FO_PAGEDOWN) &&
+ iter_data->status == VFONT_TO_CURVE_INIT) {
+ ct = &chartransdata[ef->pos];
+
+ if (ELEM(mode, FO_CURSUP, FO_PAGEUP) && ct->linenr == 0) {
+ /* pass */
+ }
+ else if (ELEM(mode, FO_CURSDOWN, FO_PAGEDOWN) && ct->linenr == lnr) {
+ /* pass */
+ }
+ else {
+ switch (mode) {
+ case FO_CURSUP:
+ lnr = ct->linenr - 1;
+ break;
+ case FO_CURSDOWN:
+ lnr = ct->linenr + 1;
+ break;
+ case FO_PAGEUP:
+ lnr = ct->linenr - 10;
+ break;
+ case FO_PAGEDOWN:
+ lnr = ct->linenr + 10;
+ break;
+ }
+ cnr = ct->charnr;
+ /* seek for char with lnr en cnr */
+ ef->pos = 0;
+ ct = chartransdata;
+ for (i = 0; i < slen; i++) {
+ if (ct->linenr == lnr) {
+ if ((ct->charnr == cnr) || ((ct + 1)->charnr == 0)) {
+ break;
+ }
+ }
+ else if (ct->linenr > lnr) {
+ break;
+ }
+ ef->pos++;
+ ct++;
+ }
+ }
+ }
+
+ /* cursor first */
+ if (ef) {
+ float si, co;
+
+ ct = &chartransdata[ef->pos];
+ si = sinf(ct->rot);
+ co = cosf(ct->rot);
+
+ f = ef->textcurs[0];
+
+ f[0] = font_size * (-0.1f * co + ct->xof);
+ f[1] = font_size * (0.1f * si + ct->yof);
+
+ f[2] = font_size * (0.1f * co + ct->xof);
+ f[3] = font_size * (-0.1f * si + ct->yof);
+
+ f[4] = font_size * (0.1f * co + 0.8f * si + ct->xof);
+ f[5] = font_size * (-0.1f * si + 0.8f * co + ct->yof);
+
+ f[6] = font_size * (-0.1f * co + 0.8f * si + ct->xof);
+ f[7] = font_size * (0.1f * si + 0.8f * co + ct->yof);
+ }
+
+ if (mode == FO_SELCHANGE) {
+ MEM_freeN(chartransdata);
+ chartransdata = NULL;
+ }
+ else if (mode == FO_EDIT) {
+ /* make nurbdata */
+ BKE_nurbList_free(r_nubase);
+
+ ct = chartransdata;
+ for (i = 0; i < slen; i++) {
+ unsigned int cha = (unsigned int)mem[i];
+ info = &(custrinfo[i]);
+
+ if ((cu->overflow == CU_OVERFLOW_TRUNCATE) && (ob && ob->mode != OB_MODE_EDIT) &&
+ (info->flag & CU_CHINFO_OVERFLOW)) {
+ break;
+ }
+
+ if (info->flag & CU_CHINFO_SMALLCAPS_CHECK) {
+ cha = towupper(cha);
+ }
+
+ if (ob == NULL || info->mat_nr > (ob->totcol)) {
+ /* CLOG_ERROR(&LOG, "Illegal material index (%d) in text object, setting to 0", info->mat_nr); */
+ info->mat_nr = 0;
+ }
+ /* We do not want to see any character for \n or \r */
+ if (cha != '\n')
+ buildchar(cu, r_nubase, cha, info, ct->xof, ct->yof, ct->rot, i, font_size);
+
+ if ((info->flag & CU_CHINFO_UNDERLINE) && (cha != '\n')) {
+ float ulwidth, uloverlap = 0.0f;
+ rctf rect;
+
+ if ((i < (slen - 1)) && (mem[i + 1] != '\n') &&
+ ((mem[i + 1] != ' ') || (custrinfo[i + 1].flag & CU_CHINFO_UNDERLINE)) &&
+ ((custrinfo[i + 1].flag & CU_CHINFO_WRAP) == 0)) {
+ uloverlap = xtrax + 0.1f;
+ }
+ /* Find the character, the characters has to be in the memory already
+ * since character checking has been done earlier already. */
+ che = find_vfont_char(vfd, cha);
+
+ twidth = char_width(cu, che, info);
+ ulwidth = (twidth * (1.0f + (info->kern / 40.0f))) + uloverlap;
+
+ rect.xmin = ct->xof;
+ rect.xmax = rect.xmin + ulwidth;
+
+ rect.ymin = ct->yof;
+ rect.ymax = rect.ymin - cu->ulheight;
+
+ build_underline(
+ cu, r_nubase, &rect, cu->ulpos - 0.05f, ct->rot, i, info->mat_nr, font_size);
+ }
+ ct++;
+ }
+ }
+
+ if (iter_data->status == VFONT_TO_CURVE_SCALE_ONCE) {
+ /* That means we were in a final run, just exit. */
+ BLI_assert(cu->overflow == CU_OVERFLOW_SCALE);
+ iter_data->status = VFONT_TO_CURVE_DONE;
+ }
+ else if (cu->overflow == CU_OVERFLOW_NONE) {
+ /* Do nothing. */
+ }
+ else if ((tb_scale.h == 0.0f) && (tb_scale.w == 0.0f)) {
+ /* Do nothing. */
+ }
+ else if (cu->overflow == CU_OVERFLOW_SCALE) {
+ if ((cu->totbox == 1) && ((tb_scale.w == 0.0f) || (tb_scale.h == 0.0f))) {
+ /* These are special cases, simpler to deal with. */
+ if (tb_scale.w == 0.0f) {
+ /* This is a potential vertical overflow.
+ * Since there is no width limit, all the new lines are from line breaks. */
+ if ((last_line != -1) && (lnr > last_line)) {
+ const float total_text_height = lnr * linedist;
+ iter_data->scale_to_fit = tb_scale.h / total_text_height;
+ iter_data->status = VFONT_TO_CURVE_SCALE_ONCE;
+ }
+ }
+ else if (tb_scale.h == 0.0f) {
+ /* This is a horizontal overflow. */
+ if (lnr > 1) {
+ /* We make sure longest line before it broke can fit here. */
+ float scale_to_fit = tb_scale.w / (longest_line_length);
+ scale_to_fit -= FLT_EPSILON;
+
+ iter_data->scale_to_fit = scale_to_fit;
+ iter_data->status = VFONT_TO_CURVE_SCALE_ONCE;
+ }
+ }
+ }
+ else {
+ /* This is the really complicated case, the best we can do is to iterate over
+ * this function a few times until we get an acceptable result.
+ *
+ * Keep in mind that there is no single number that will make all fit to the end.
+ * In a way, our ultimate goal is to get the highest scale that still leads to the
+ * number of extra lines to zero.
+ */
+ if (iter_data->status == VFONT_TO_CURVE_INIT) {
+ bool valid = true;
+
+ for (int tb_index = 0; tb_index <= curbox; tb_index++) {
+ TextBox *tb = &cu->tb[tb_index];
+ if ((tb->w == 0.0f) || (tb->h == 0.0f)) {
+ valid = false;
+ break;
+ }
+ }
+
+ if (valid && (last_line != -1) && (lnr > last_line)) {
+ const float total_text_height = lnr * linedist;
+ float scale_to_fit = tb_scale.h / total_text_height;
+
+ iter_data->bisect.max = 1.0f;
+ iter_data->bisect.min = scale_to_fit;
+
+ iter_data->status = VFONT_TO_CURVE_BISECT;
+ }
+ }
+ else {
+ BLI_assert(iter_data->status == VFONT_TO_CURVE_BISECT);
+ /* Try to get the highest scale that gives us the exactly
+ * number of lines we need. */
+ bool valid = false;
+
+ if ((last_line != -1) && (lnr > last_line)) {
+ /* It is overflowing, scale it down. */
+ iter_data->bisect.max = iter_data->scale_to_fit;
+ }
+ else {
+ /* It fits inside the textbox, scale it up. */
+ iter_data->bisect.min = iter_data->scale_to_fit;
+ valid = true;
+ }
+
+ /* Bisecting to try to find the best fit. */
+ iter_data->scale_to_fit = (iter_data->bisect.max + iter_data->bisect.min) * 0.5f;
+
+ /* We iterated enough or got a good enough result. */
+ if ((!iter_data->iteraction--) || ((iter_data->bisect.max - iter_data->bisect.min) <
+ (cu->fsize * FONT_TO_CURVE_SCALE_THRESHOLD))) {
+ if (valid) {
+ iter_data->status = VFONT_TO_CURVE_DONE;
+ }
+ else {
+ iter_data->scale_to_fit = iter_data->bisect.min;
+ iter_data->status = VFONT_TO_CURVE_SCALE_ONCE;
+ }
+ }
+ }
+ }
+ }
+
+ /* Scale to fit only works for single text box layouts. */
+ if (ELEM(iter_data->status, VFONT_TO_CURVE_SCALE_ONCE, VFONT_TO_CURVE_BISECT)) {
+ /* Always cleanup before going to the scale-to-fit repetition. */
+ if (r_nubase != NULL) {
+ BKE_nurbList_free(r_nubase);
+ }
+
+ if (chartransdata != NULL) {
+ MEM_freeN(chartransdata);
+ }
+
+ if (ef == NULL) {
+ MEM_freeN((void *)mem);
+ }
+ return true;
+ }
+ else {
+ ok = true;
+ finally:
+ if (r_text) {
+ *r_text = mem;
+ *r_text_len = slen;
+ *r_text_free = (ef == NULL);
+ }
+ else {
+ if (ef == NULL) {
+ MEM_freeN((void *)mem);
+ }
+ }
+
+ if (chartransdata) {
+ if (ok && r_chartransdata) {
+ *r_chartransdata = chartransdata;
+ }
+ else {
+ MEM_freeN(chartransdata);
+ }
+ }
+
+ /* Store the effective scale, to use for the textbox lines. */
+ cu->fsize_realtime = font_size;
+ }
+ return ok;
#undef MARGIN_X_MIN
#undef MARGIN_Y_MIN
@@ -1543,32 +1568,28 @@ finally:
#undef DESCENT
#undef ASCENT
-bool BKE_vfont_to_curve_ex(Object *ob, Curve *cu, int mode, ListBase *r_nubase,
- const wchar_t **r_text, int *r_text_len, bool *r_text_free,
+bool BKE_vfont_to_curve_ex(Object *ob,
+ Curve *cu,
+ int mode,
+ ListBase *r_nubase,
+ const wchar_t **r_text,
+ int *r_text_len,
+ bool *r_text_free,
struct CharTrans **r_chartransdata)
{
- VFontToCurveIter data = {
- .iteraction = cu->totbox * FONT_TO_CURVE_SCALE_ITERATIONS,
- .scale_to_fit = 1.0f,
- .ok = true,
- .status = VFONT_TO_CURVE_INIT,
- };
-
- do {
- data.ok &= vfont_to_curve(ob,
- cu,
- mode,
- &data,
- r_nubase,
- r_text,
- r_text_len,
- r_text_free,
- r_chartransdata);
- } while (data.ok && ELEM(data.status,
- VFONT_TO_CURVE_SCALE_ONCE,
- VFONT_TO_CURVE_BISECT));
-
- return data.ok;
+ VFontToCurveIter data = {
+ .iteraction = cu->totbox * FONT_TO_CURVE_SCALE_ITERATIONS,
+ .scale_to_fit = 1.0f,
+ .ok = true,
+ .status = VFONT_TO_CURVE_INIT,
+ };
+
+ do {
+ data.ok &= vfont_to_curve(
+ ob, cu, mode, &data, r_nubase, r_text, r_text_len, r_text_free, r_chartransdata);
+ } while (data.ok && ELEM(data.status, VFONT_TO_CURVE_SCALE_ONCE, VFONT_TO_CURVE_BISECT));
+
+ return data.ok;
}
#undef FONT_TO_CURVE_SCALE_ITERATIONS
@@ -1576,89 +1597,88 @@ bool BKE_vfont_to_curve_ex(Object *ob, Curve *cu, int mode, ListBase *r_nubase,
bool BKE_vfont_to_curve_nubase(Object *ob, int mode, ListBase *r_nubase)
{
- BLI_assert(ob->type == OB_FONT);
+ BLI_assert(ob->type == OB_FONT);
- return BKE_vfont_to_curve_ex(ob, ob->data, mode, r_nubase,
- NULL, NULL, NULL, NULL);
+ return BKE_vfont_to_curve_ex(ob, ob->data, mode, r_nubase, NULL, NULL, NULL, NULL);
}
/** Warning: expects to have access to evaluated data (i.e. passed object should be evaluated one...). */
bool BKE_vfont_to_curve(Object *ob, int mode)
{
- Curve *cu = ob->data;
+ Curve *cu = ob->data;
- return BKE_vfont_to_curve_ex(ob, ob->data, mode, &cu->nurb, NULL, NULL, NULL, NULL);
+ return BKE_vfont_to_curve_ex(ob, ob->data, mode, &cu->nurb, NULL, NULL, NULL, NULL);
}
-
/* -------------------------------------------------------------------- */
/** \name VFont Clipboard
* \{ */
static struct {
- wchar_t *text_buffer;
- CharInfo *info_buffer;
- size_t len_wchar;
- size_t len_utf8;
+ wchar_t *text_buffer;
+ CharInfo *info_buffer;
+ size_t len_wchar;
+ size_t len_utf8;
} g_vfont_clipboard = {NULL};
void BKE_vfont_clipboard_free(void)
{
- MEM_SAFE_FREE(g_vfont_clipboard.text_buffer);
- MEM_SAFE_FREE(g_vfont_clipboard.info_buffer);
- g_vfont_clipboard.len_wchar = 0;
- g_vfont_clipboard.len_utf8 = 0;
+ MEM_SAFE_FREE(g_vfont_clipboard.text_buffer);
+ MEM_SAFE_FREE(g_vfont_clipboard.info_buffer);
+ g_vfont_clipboard.len_wchar = 0;
+ g_vfont_clipboard.len_utf8 = 0;
}
void BKE_vfont_clipboard_set(const wchar_t *text_buf, const CharInfo *info_buf, const size_t len)
{
- wchar_t *text;
- CharInfo *info;
-
- /* clean previous buffers*/
- BKE_vfont_clipboard_free();
-
- text = MEM_malloc_arrayN((len + 1), sizeof(wchar_t), __func__);
- if (text == NULL) {
- return;
- }
-
- info = MEM_malloc_arrayN(len, sizeof(CharInfo), __func__);
- if (info == NULL) {
- MEM_freeN(text);
- return;
- }
-
- memcpy(text, text_buf, len * sizeof(wchar_t));
- text[len] = '\0';
- memcpy(info, info_buf, len * sizeof(CharInfo));
-
- /* store new buffers */
- g_vfont_clipboard.text_buffer = text;
- g_vfont_clipboard.info_buffer = info;
- g_vfont_clipboard.len_utf8 = BLI_wstrlen_utf8(text);
- g_vfont_clipboard.len_wchar = len;
+ wchar_t *text;
+ CharInfo *info;
+
+ /* clean previous buffers*/
+ BKE_vfont_clipboard_free();
+
+ text = MEM_malloc_arrayN((len + 1), sizeof(wchar_t), __func__);
+ if (text == NULL) {
+ return;
+ }
+
+ info = MEM_malloc_arrayN(len, sizeof(CharInfo), __func__);
+ if (info == NULL) {
+ MEM_freeN(text);
+ return;
+ }
+
+ memcpy(text, text_buf, len * sizeof(wchar_t));
+ text[len] = '\0';
+ memcpy(info, info_buf, len * sizeof(CharInfo));
+
+ /* store new buffers */
+ g_vfont_clipboard.text_buffer = text;
+ g_vfont_clipboard.info_buffer = info;
+ g_vfont_clipboard.len_utf8 = BLI_wstrlen_utf8(text);
+ g_vfont_clipboard.len_wchar = len;
}
-void BKE_vfont_clipboard_get(
- wchar_t **r_text_buf, CharInfo **r_info_buf,
- size_t *r_len_utf8, size_t *r_len_wchar)
+void BKE_vfont_clipboard_get(wchar_t **r_text_buf,
+ CharInfo **r_info_buf,
+ size_t *r_len_utf8,
+ size_t *r_len_wchar)
{
- if (r_text_buf) {
- *r_text_buf = g_vfont_clipboard.text_buffer;
- }
+ if (r_text_buf) {
+ *r_text_buf = g_vfont_clipboard.text_buffer;
+ }
- if (r_info_buf) {
- *r_info_buf = g_vfont_clipboard.info_buffer;
- }
+ if (r_info_buf) {
+ *r_info_buf = g_vfont_clipboard.info_buffer;
+ }
- if (r_len_wchar) {
- *r_len_wchar = g_vfont_clipboard.len_wchar;
- }
+ if (r_len_wchar) {
+ *r_len_wchar = g_vfont_clipboard.len_wchar;
+ }
- if (r_len_utf8) {
- *r_len_utf8 = g_vfont_clipboard.len_utf8;
- }
+ if (r_len_utf8) {
+ *r_len_utf8 = g_vfont_clipboard.len_utf8;
+ }
}
/** \} */
diff --git a/source/blender/blenkernel/intern/freestyle.c b/source/blender/blenkernel/intern/freestyle.c
index 10fd2db187d..72b81651124 100644
--- a/source/blender/blenkernel/intern/freestyle.c
+++ b/source/blender/blenkernel/intern/freestyle.c
@@ -42,212 +42,226 @@ static void copy_module(FreestyleModuleConfig *new_module, FreestyleModuleConfig
void BKE_freestyle_config_init(FreestyleConfig *config)
{
- config->mode = FREESTYLE_CONTROL_EDITOR_MODE;
+ config->mode = FREESTYLE_CONTROL_EDITOR_MODE;
- BLI_listbase_clear(&config->modules);
- config->flags = 0;
- config->sphere_radius = 0.1f;
- config->dkr_epsilon = 0.0f;
- config->crease_angle = DEG2RADF(134.43f);
+ BLI_listbase_clear(&config->modules);
+ config->flags = 0;
+ config->sphere_radius = 0.1f;
+ config->dkr_epsilon = 0.0f;
+ config->crease_angle = DEG2RADF(134.43f);
- BLI_listbase_clear(&config->linesets);
+ BLI_listbase_clear(&config->linesets);
}
void BKE_freestyle_config_free(FreestyleConfig *config, const bool do_id_user)
{
- FreestyleLineSet *lineset;
-
- for (lineset = (FreestyleLineSet *)config->linesets.first; lineset; lineset = lineset->next) {
- if (lineset->group) {
- if (do_id_user) {
- id_us_min(&lineset->group->id);
- }
- lineset->group = NULL;
- }
- if (lineset->linestyle) {
- if (do_id_user) {
- id_us_min(&lineset->linestyle->id);
- }
- lineset->linestyle = NULL;
- }
- }
- BLI_freelistN(&config->linesets);
- BLI_freelistN(&config->modules);
-}
-
-void BKE_freestyle_config_copy(FreestyleConfig *new_config, const FreestyleConfig *config, const int flag)
-{
- FreestyleLineSet *lineset, *new_lineset;
- FreestyleModuleConfig *module, *new_module;
-
- new_config->mode = config->mode;
- new_config->flags = config->flags;
- new_config->sphere_radius = config->sphere_radius;
- new_config->dkr_epsilon = config->dkr_epsilon;
- new_config->crease_angle = config->crease_angle;
-
- BLI_listbase_clear(&new_config->linesets);
- for (lineset = (FreestyleLineSet *)config->linesets.first; lineset; lineset = lineset->next) {
- new_lineset = alloc_lineset();
- copy_lineset(new_lineset, lineset, flag);
- BLI_addtail(&new_config->linesets, (void *)new_lineset);
- }
-
- BLI_listbase_clear(&new_config->modules);
- for (module = (FreestyleModuleConfig *)config->modules.first; module; module = module->next) {
- new_module = alloc_module();
- copy_module(new_module, module);
- BLI_addtail(&new_config->modules, (void *)new_module);
- }
+ FreestyleLineSet *lineset;
+
+ for (lineset = (FreestyleLineSet *)config->linesets.first; lineset; lineset = lineset->next) {
+ if (lineset->group) {
+ if (do_id_user) {
+ id_us_min(&lineset->group->id);
+ }
+ lineset->group = NULL;
+ }
+ if (lineset->linestyle) {
+ if (do_id_user) {
+ id_us_min(&lineset->linestyle->id);
+ }
+ lineset->linestyle = NULL;
+ }
+ }
+ BLI_freelistN(&config->linesets);
+ BLI_freelistN(&config->modules);
}
-static void copy_lineset(FreestyleLineSet *new_lineset, FreestyleLineSet *lineset, const int flag)
+void BKE_freestyle_config_copy(FreestyleConfig *new_config,
+ const FreestyleConfig *config,
+ const int flag)
{
- new_lineset->linestyle = lineset->linestyle;
- new_lineset->flags = lineset->flags;
- new_lineset->selection = lineset->selection;
- new_lineset->qi = lineset->qi;
- new_lineset->qi_start = lineset->qi_start;
- new_lineset->qi_end = lineset->qi_end;
- new_lineset->edge_types = lineset->edge_types;
- new_lineset->exclude_edge_types = lineset->exclude_edge_types;
- new_lineset->group = lineset->group;
- strcpy(new_lineset->name, lineset->name);
+ FreestyleLineSet *lineset, *new_lineset;
+ FreestyleModuleConfig *module, *new_module;
+
+ new_config->mode = config->mode;
+ new_config->flags = config->flags;
+ new_config->sphere_radius = config->sphere_radius;
+ new_config->dkr_epsilon = config->dkr_epsilon;
+ new_config->crease_angle = config->crease_angle;
+
+ BLI_listbase_clear(&new_config->linesets);
+ for (lineset = (FreestyleLineSet *)config->linesets.first; lineset; lineset = lineset->next) {
+ new_lineset = alloc_lineset();
+ copy_lineset(new_lineset, lineset, flag);
+ BLI_addtail(&new_config->linesets, (void *)new_lineset);
+ }
+
+ BLI_listbase_clear(&new_config->modules);
+ for (module = (FreestyleModuleConfig *)config->modules.first; module; module = module->next) {
+ new_module = alloc_module();
+ copy_module(new_module, module);
+ BLI_addtail(&new_config->modules, (void *)new_module);
+ }
+}
- if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- id_us_plus((ID *)new_lineset->linestyle);
- id_us_plus((ID *)new_lineset->group);
- }
+static void copy_lineset(FreestyleLineSet *new_lineset, FreestyleLineSet *lineset, const int flag)
+{
+ new_lineset->linestyle = lineset->linestyle;
+ new_lineset->flags = lineset->flags;
+ new_lineset->selection = lineset->selection;
+ new_lineset->qi = lineset->qi;
+ new_lineset->qi_start = lineset->qi_start;
+ new_lineset->qi_end = lineset->qi_end;
+ new_lineset->edge_types = lineset->edge_types;
+ new_lineset->exclude_edge_types = lineset->exclude_edge_types;
+ new_lineset->group = lineset->group;
+ strcpy(new_lineset->name, lineset->name);
+
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id_us_plus((ID *)new_lineset->linestyle);
+ id_us_plus((ID *)new_lineset->group);
+ }
}
static FreestyleModuleConfig *alloc_module(void)
{
- return (FreestyleModuleConfig *)MEM_callocN(sizeof(FreestyleModuleConfig), "style module configuration");
+ return (FreestyleModuleConfig *)MEM_callocN(sizeof(FreestyleModuleConfig),
+ "style module configuration");
}
FreestyleModuleConfig *BKE_freestyle_module_add(FreestyleConfig *config)
{
- FreestyleModuleConfig *module_conf = alloc_module();
- BLI_addtail(&config->modules, (void *)module_conf);
- module_conf->script = NULL;
- module_conf->is_displayed = 1;
- return module_conf;
+ FreestyleModuleConfig *module_conf = alloc_module();
+ BLI_addtail(&config->modules, (void *)module_conf);
+ module_conf->script = NULL;
+ module_conf->is_displayed = 1;
+ return module_conf;
}
static void copy_module(FreestyleModuleConfig *new_module, FreestyleModuleConfig *module)
{
- new_module->script = module->script;
- new_module->is_displayed = module->is_displayed;
+ new_module->script = module->script;
+ new_module->is_displayed = module->is_displayed;
}
bool BKE_freestyle_module_delete(FreestyleConfig *config, FreestyleModuleConfig *module_conf)
{
- if (BLI_findindex(&config->modules, module_conf) == -1)
- return false;
- BLI_freelinkN(&config->modules, module_conf);
- return true;
+ if (BLI_findindex(&config->modules, module_conf) == -1)
+ return false;
+ BLI_freelinkN(&config->modules, module_conf);
+ return true;
}
/**
* Reinsert \a module_conf offset by \a direction from current position.
* \return if position of \a module_conf changed.
*/
-bool BKE_freestyle_module_move(FreestyleConfig *config, FreestyleModuleConfig *module_conf, int direction)
+bool BKE_freestyle_module_move(FreestyleConfig *config,
+ FreestyleModuleConfig *module_conf,
+ int direction)
{
- return ((BLI_findindex(&config->modules, module_conf) > -1) &&
- (BLI_listbase_link_move(&config->modules, module_conf, direction) == true));
+ return ((BLI_findindex(&config->modules, module_conf) > -1) &&
+ (BLI_listbase_link_move(&config->modules, module_conf, direction) == true));
}
void BKE_freestyle_lineset_unique_name(FreestyleConfig *config, FreestyleLineSet *lineset)
{
- BLI_uniquename(&config->linesets, lineset, "FreestyleLineSet", '.', offsetof(FreestyleLineSet, name),
- sizeof(lineset->name));
+ BLI_uniquename(&config->linesets,
+ lineset,
+ "FreestyleLineSet",
+ '.',
+ offsetof(FreestyleLineSet, name),
+ sizeof(lineset->name));
}
static FreestyleLineSet *alloc_lineset(void)
{
- return (FreestyleLineSet *)MEM_callocN(sizeof(FreestyleLineSet), "Freestyle line set");
+ return (FreestyleLineSet *)MEM_callocN(sizeof(FreestyleLineSet), "Freestyle line set");
}
-FreestyleLineSet *BKE_freestyle_lineset_add(struct Main *bmain, FreestyleConfig *config, const char *name)
+FreestyleLineSet *BKE_freestyle_lineset_add(struct Main *bmain,
+ FreestyleConfig *config,
+ const char *name)
{
- int lineset_index = BLI_listbase_count(&config->linesets);
-
- FreestyleLineSet *lineset = alloc_lineset();
- BLI_addtail(&config->linesets, (void *)lineset);
- BKE_freestyle_lineset_set_active_index(config, lineset_index);
-
- lineset->linestyle = BKE_linestyle_new(bmain, "LineStyle");
- lineset->flags |= FREESTYLE_LINESET_ENABLED;
- lineset->selection = FREESTYLE_SEL_VISIBILITY | FREESTYLE_SEL_EDGE_TYPES | FREESTYLE_SEL_IMAGE_BORDER;
- lineset->qi = FREESTYLE_QI_VISIBLE;
- lineset->qi_start = 0;
- lineset->qi_end = 100;
- lineset->edge_types = FREESTYLE_FE_SILHOUETTE | FREESTYLE_FE_BORDER | FREESTYLE_FE_CREASE;
- lineset->exclude_edge_types = 0;
- lineset->group = NULL;
- if (name) {
- BLI_strncpy(lineset->name, name, sizeof(lineset->name));
- }
- else if (lineset_index > 0) {
- sprintf(lineset->name, "LineSet %i", lineset_index + 1);
- }
- else {
- strcpy(lineset->name, "LineSet");
- }
- BKE_freestyle_lineset_unique_name(config, lineset);
-
- return lineset;
+ int lineset_index = BLI_listbase_count(&config->linesets);
+
+ FreestyleLineSet *lineset = alloc_lineset();
+ BLI_addtail(&config->linesets, (void *)lineset);
+ BKE_freestyle_lineset_set_active_index(config, lineset_index);
+
+ lineset->linestyle = BKE_linestyle_new(bmain, "LineStyle");
+ lineset->flags |= FREESTYLE_LINESET_ENABLED;
+ lineset->selection = FREESTYLE_SEL_VISIBILITY | FREESTYLE_SEL_EDGE_TYPES |
+ FREESTYLE_SEL_IMAGE_BORDER;
+ lineset->qi = FREESTYLE_QI_VISIBLE;
+ lineset->qi_start = 0;
+ lineset->qi_end = 100;
+ lineset->edge_types = FREESTYLE_FE_SILHOUETTE | FREESTYLE_FE_BORDER | FREESTYLE_FE_CREASE;
+ lineset->exclude_edge_types = 0;
+ lineset->group = NULL;
+ if (name) {
+ BLI_strncpy(lineset->name, name, sizeof(lineset->name));
+ }
+ else if (lineset_index > 0) {
+ sprintf(lineset->name, "LineSet %i", lineset_index + 1);
+ }
+ else {
+ strcpy(lineset->name, "LineSet");
+ }
+ BKE_freestyle_lineset_unique_name(config, lineset);
+
+ return lineset;
}
bool BKE_freestyle_lineset_delete(FreestyleConfig *config, FreestyleLineSet *lineset)
{
- if (BLI_findindex(&config->linesets, lineset) == -1)
- return false;
- if (lineset->group) {
- id_us_min(&lineset->group->id);
- }
- if (lineset->linestyle) {
- id_us_min(&lineset->linestyle->id);
- }
- BLI_remlink(&config->linesets, lineset);
- MEM_freeN(lineset);
- BKE_freestyle_lineset_set_active_index(config, 0);
- return true;
+ if (BLI_findindex(&config->linesets, lineset) == -1)
+ return false;
+ if (lineset->group) {
+ id_us_min(&lineset->group->id);
+ }
+ if (lineset->linestyle) {
+ id_us_min(&lineset->linestyle->id);
+ }
+ BLI_remlink(&config->linesets, lineset);
+ MEM_freeN(lineset);
+ BKE_freestyle_lineset_set_active_index(config, 0);
+ return true;
}
FreestyleLineSet *BKE_freestyle_lineset_get_active(FreestyleConfig *config)
{
- FreestyleLineSet *lineset;
+ FreestyleLineSet *lineset;
- for (lineset = (FreestyleLineSet *)config->linesets.first; lineset; lineset = lineset->next) {
- if (lineset->flags & FREESTYLE_LINESET_CURRENT)
- return lineset;
- }
- return NULL;
+ for (lineset = (FreestyleLineSet *)config->linesets.first; lineset; lineset = lineset->next) {
+ if (lineset->flags & FREESTYLE_LINESET_CURRENT)
+ return lineset;
+ }
+ return NULL;
}
short BKE_freestyle_lineset_get_active_index(FreestyleConfig *config)
{
- FreestyleLineSet *lineset;
- short i;
-
- for (lineset = (FreestyleLineSet *)config->linesets.first, i = 0; lineset; lineset = lineset->next, i++) {
- if (lineset->flags & FREESTYLE_LINESET_CURRENT)
- return i;
- }
- return 0;
+ FreestyleLineSet *lineset;
+ short i;
+
+ for (lineset = (FreestyleLineSet *)config->linesets.first, i = 0; lineset;
+ lineset = lineset->next, i++) {
+ if (lineset->flags & FREESTYLE_LINESET_CURRENT)
+ return i;
+ }
+ return 0;
}
void BKE_freestyle_lineset_set_active_index(FreestyleConfig *config, short index)
{
- FreestyleLineSet *lineset;
- short i;
-
- for (lineset = (FreestyleLineSet *)config->linesets.first, i = 0; lineset; lineset = lineset->next, i++) {
- if (i == index)
- lineset->flags |= FREESTYLE_LINESET_CURRENT;
- else
- lineset->flags &= ~FREESTYLE_LINESET_CURRENT;
- }
+ FreestyleLineSet *lineset;
+ short i;
+
+ for (lineset = (FreestyleLineSet *)config->linesets.first, i = 0; lineset;
+ lineset = lineset->next, i++) {
+ if (i == index)
+ lineset->flags |= FREESTYLE_LINESET_CURRENT;
+ else
+ lineset->flags &= ~FREESTYLE_LINESET_CURRENT;
+ }
}
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index d47b3f20a28..d1181eeb03d 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -21,7 +21,6 @@
* \ingroup bke
*/
-
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
@@ -65,22 +64,22 @@ static CLG_LogRef LOG = {"bke.gpencil"};
/* ************************************************** */
/* Draw Engine */
-void(*BKE_gpencil_batch_cache_dirty_tag_cb)(bGPdata *gpd) = NULL;
-void(*BKE_gpencil_batch_cache_free_cb)(bGPdata *gpd) = NULL;
+void (*BKE_gpencil_batch_cache_dirty_tag_cb)(bGPdata *gpd) = NULL;
+void (*BKE_gpencil_batch_cache_free_cb)(bGPdata *gpd) = NULL;
void BKE_gpencil_batch_cache_dirty_tag(bGPdata *gpd)
{
- if (gpd) {
- DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
- BKE_gpencil_batch_cache_dirty_tag_cb(gpd);
- }
+ if (gpd) {
+ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
+ BKE_gpencil_batch_cache_dirty_tag_cb(gpd);
+ }
}
void BKE_gpencil_batch_cache_free(bGPdata *gpd)
{
- if (gpd) {
- BKE_gpencil_batch_cache_free_cb(gpd);
- }
+ if (gpd) {
+ BKE_gpencil_batch_cache_free_cb(gpd);
+ }
}
/* ************************************************** */
@@ -89,138 +88,138 @@ void BKE_gpencil_batch_cache_free(bGPdata *gpd)
/* clean vertex groups weights */
void BKE_gpencil_free_point_weights(MDeformVert *dvert)
{
- if (dvert == NULL) {
- return;
- }
- MEM_SAFE_FREE(dvert->dw);
+ if (dvert == NULL) {
+ return;
+ }
+ MEM_SAFE_FREE(dvert->dw);
}
void BKE_gpencil_free_stroke_weights(bGPDstroke *gps)
{
- if (gps == NULL) {
- return;
- }
+ if (gps == NULL) {
+ return;
+ }
- if (gps->dvert == NULL) {
- return;
- }
+ if (gps->dvert == NULL) {
+ return;
+ }
- for (int i = 0; i < gps->totpoints; i++) {
- MDeformVert *dvert = &gps->dvert[i];
- BKE_gpencil_free_point_weights(dvert);
- }
+ for (int i = 0; i < gps->totpoints; i++) {
+ MDeformVert *dvert = &gps->dvert[i];
+ BKE_gpencil_free_point_weights(dvert);
+ }
}
/* free stroke, doesn't unlink from any listbase */
void BKE_gpencil_free_stroke(bGPDstroke *gps)
{
- if (gps == NULL) {
- return;
- }
- /* free stroke memory arrays, then stroke itself */
- if (gps->points) {
- MEM_freeN(gps->points);
- }
- if (gps->dvert) {
- BKE_gpencil_free_stroke_weights(gps);
- MEM_freeN(gps->dvert);
- }
- if (gps->triangles)
- MEM_freeN(gps->triangles);
+ if (gps == NULL) {
+ return;
+ }
+ /* free stroke memory arrays, then stroke itself */
+ if (gps->points) {
+ MEM_freeN(gps->points);
+ }
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
+ if (gps->triangles)
+ MEM_freeN(gps->triangles);
- MEM_freeN(gps);
+ MEM_freeN(gps);
}
/* Free strokes belonging to a gp-frame */
bool BKE_gpencil_free_strokes(bGPDframe *gpf)
{
- bGPDstroke *gps_next;
- bool changed = (BLI_listbase_is_empty(&gpf->strokes) == false);
+ bGPDstroke *gps_next;
+ bool changed = (BLI_listbase_is_empty(&gpf->strokes) == false);
- /* free strokes */
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps_next) {
- gps_next = gps->next;
- BKE_gpencil_free_stroke(gps);
- }
- BLI_listbase_clear(&gpf->strokes);
+ /* free strokes */
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps_next) {
+ gps_next = gps->next;
+ BKE_gpencil_free_stroke(gps);
+ }
+ BLI_listbase_clear(&gpf->strokes);
- return changed;
+ return changed;
}
/* Free strokes and colors belonging to a gp-frame */
bool BKE_gpencil_free_frame_runtime_data(bGPDframe *derived_gpf)
{
- bGPDstroke *gps_next;
- if (!derived_gpf) {
- return false;
- }
+ bGPDstroke *gps_next;
+ if (!derived_gpf) {
+ return false;
+ }
- /* free strokes */
- for (bGPDstroke *gps = derived_gpf->strokes.first; gps; gps = gps_next) {
- gps_next = gps->next;
- BKE_gpencil_free_stroke(gps);
- }
- BLI_listbase_clear(&derived_gpf->strokes);
+ /* free strokes */
+ for (bGPDstroke *gps = derived_gpf->strokes.first; gps; gps = gps_next) {
+ gps_next = gps->next;
+ BKE_gpencil_free_stroke(gps);
+ }
+ BLI_listbase_clear(&derived_gpf->strokes);
- return true;
+ return true;
}
/* Free all of a gp-layer's frames */
void BKE_gpencil_free_frames(bGPDlayer *gpl)
{
- bGPDframe *gpf_next;
+ bGPDframe *gpf_next;
- /* error checking */
- if (gpl == NULL) return;
+ /* error checking */
+ if (gpl == NULL)
+ return;
- /* free frames */
- for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf_next) {
- gpf_next = gpf->next;
+ /* free frames */
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf_next) {
+ gpf_next = gpf->next;
- /* free strokes and their associated memory */
- BKE_gpencil_free_strokes(gpf);
- BLI_freelinkN(&gpl->frames, gpf);
- }
- gpl->actframe = NULL;
+ /* free strokes and their associated memory */
+ BKE_gpencil_free_strokes(gpf);
+ BLI_freelinkN(&gpl->frames, gpf);
+ }
+ gpl->actframe = NULL;
}
-
-
/* Free all of the gp-layers for a viewport (list should be &gpd->layers or so) */
void BKE_gpencil_free_layers(ListBase *list)
{
- bGPDlayer *gpl_next;
+ bGPDlayer *gpl_next;
- /* error checking */
- if (list == NULL) return;
+ /* error checking */
+ if (list == NULL)
+ return;
- /* delete layers */
- for (bGPDlayer *gpl = list->first; gpl; gpl = gpl_next) {
- gpl_next = gpl->next;
+ /* delete layers */
+ for (bGPDlayer *gpl = list->first; gpl; gpl = gpl_next) {
+ gpl_next = gpl->next;
- /* free layers and their data */
- BKE_gpencil_free_frames(gpl);
- BLI_freelinkN(list, gpl);
- }
+ /* free layers and their data */
+ BKE_gpencil_free_frames(gpl);
+ BLI_freelinkN(list, gpl);
+ }
}
/** Free (or release) any data used by this grease pencil (does not free the gpencil itself). */
void BKE_gpencil_free(bGPdata *gpd, bool free_all)
{
- /* clear animation data */
- BKE_animdata_free(&gpd->id, false);
+ /* clear animation data */
+ BKE_animdata_free(&gpd->id, false);
- /* free layers */
- BKE_gpencil_free_layers(&gpd->layers);
+ /* free layers */
+ BKE_gpencil_free_layers(&gpd->layers);
- /* materials */
- MEM_SAFE_FREE(gpd->mat);
+ /* materials */
+ MEM_SAFE_FREE(gpd->mat);
- /* free all data */
- if (free_all) {
- /* clear cache */
- BKE_gpencil_batch_cache_free(gpd);
- }
+ /* free all data */
+ if (free_all) {
+ /* clear cache */
+ BKE_gpencil_batch_cache_free(gpd);
+ }
}
/* ************************************************** */
@@ -229,211 +228,211 @@ void BKE_gpencil_free(bGPdata *gpd, bool free_all)
/* add a new gp-frame to the given layer */
bGPDframe *BKE_gpencil_frame_addnew(bGPDlayer *gpl, int cframe)
{
- bGPDframe *gpf = NULL, *gf = NULL;
- short state = 0;
-
- /* error checking */
- if (gpl == NULL)
- return NULL;
-
- /* allocate memory for this frame */
- gpf = MEM_callocN(sizeof(bGPDframe), "bGPDframe");
- gpf->framenum = cframe;
-
- /* find appropriate place to add frame */
- if (gpl->frames.first) {
- for (gf = gpl->frames.first; gf; gf = gf->next) {
- /* check if frame matches one that is supposed to be added */
- if (gf->framenum == cframe) {
- state = -1;
- break;
- }
-
- /* if current frame has already exceeded the frame to add, add before */
- if (gf->framenum > cframe) {
- BLI_insertlinkbefore(&gpl->frames, gf, gpf);
- state = 1;
- break;
- }
- }
- }
-
- /* check whether frame was added successfully */
- if (state == -1) {
- CLOG_ERROR(&LOG, "Frame (%d) existed already for this layer. Using existing frame", cframe);
-
- /* free the newly created one, and use the old one instead */
- MEM_freeN(gpf);
-
- /* return existing frame instead... */
- BLI_assert(gf != NULL);
- gpf = gf;
- }
- else if (state == 0) {
- /* add to end then! */
- BLI_addtail(&gpl->frames, gpf);
- }
-
- /* return frame */
- return gpf;
+ bGPDframe *gpf = NULL, *gf = NULL;
+ short state = 0;
+
+ /* error checking */
+ if (gpl == NULL)
+ return NULL;
+
+ /* allocate memory for this frame */
+ gpf = MEM_callocN(sizeof(bGPDframe), "bGPDframe");
+ gpf->framenum = cframe;
+
+ /* find appropriate place to add frame */
+ if (gpl->frames.first) {
+ for (gf = gpl->frames.first; gf; gf = gf->next) {
+ /* check if frame matches one that is supposed to be added */
+ if (gf->framenum == cframe) {
+ state = -1;
+ break;
+ }
+
+ /* if current frame has already exceeded the frame to add, add before */
+ if (gf->framenum > cframe) {
+ BLI_insertlinkbefore(&gpl->frames, gf, gpf);
+ state = 1;
+ break;
+ }
+ }
+ }
+
+ /* check whether frame was added successfully */
+ if (state == -1) {
+ CLOG_ERROR(&LOG, "Frame (%d) existed already for this layer. Using existing frame", cframe);
+
+ /* free the newly created one, and use the old one instead */
+ MEM_freeN(gpf);
+
+ /* return existing frame instead... */
+ BLI_assert(gf != NULL);
+ gpf = gf;
+ }
+ else if (state == 0) {
+ /* add to end then! */
+ BLI_addtail(&gpl->frames, gpf);
+ }
+
+ /* return frame */
+ return gpf;
}
/* add a copy of the active gp-frame to the given layer */
bGPDframe *BKE_gpencil_frame_addcopy(bGPDlayer *gpl, int cframe)
{
- bGPDframe *new_frame;
- bool found = false;
-
- /* Error checking/handling */
- if (gpl == NULL) {
- /* no layer */
- return NULL;
- }
- else if (gpl->actframe == NULL) {
- /* no active frame, so just create a new one from scratch */
- return BKE_gpencil_frame_addnew(gpl, cframe);
- }
-
- /* Create a copy of the frame */
- new_frame = BKE_gpencil_frame_duplicate(gpl->actframe);
-
- /* Find frame to insert it before */
- for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- if (gpf->framenum > cframe) {
- /* Add it here */
- BLI_insertlinkbefore(&gpl->frames, gpf, new_frame);
-
- found = true;
- break;
- }
- else if (gpf->framenum == cframe) {
- /* This only happens when we're editing with framelock on...
- * - Delete the new frame and don't do anything else here...
- */
- BKE_gpencil_free_strokes(new_frame);
- MEM_freeN(new_frame);
- new_frame = NULL;
-
- found = true;
- break;
- }
- }
-
- if (found == false) {
- /* Add new frame to the end */
- BLI_addtail(&gpl->frames, new_frame);
- }
-
- /* Ensure that frame is set up correctly, and return it */
- if (new_frame) {
- new_frame->framenum = cframe;
- gpl->actframe = new_frame;
- }
-
- return new_frame;
+ bGPDframe *new_frame;
+ bool found = false;
+
+ /* Error checking/handling */
+ if (gpl == NULL) {
+ /* no layer */
+ return NULL;
+ }
+ else if (gpl->actframe == NULL) {
+ /* no active frame, so just create a new one from scratch */
+ return BKE_gpencil_frame_addnew(gpl, cframe);
+ }
+
+ /* Create a copy of the frame */
+ new_frame = BKE_gpencil_frame_duplicate(gpl->actframe);
+
+ /* Find frame to insert it before */
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ if (gpf->framenum > cframe) {
+ /* Add it here */
+ BLI_insertlinkbefore(&gpl->frames, gpf, new_frame);
+
+ found = true;
+ break;
+ }
+ else if (gpf->framenum == cframe) {
+ /* This only happens when we're editing with framelock on...
+ * - Delete the new frame and don't do anything else here...
+ */
+ BKE_gpencil_free_strokes(new_frame);
+ MEM_freeN(new_frame);
+ new_frame = NULL;
+
+ found = true;
+ break;
+ }
+ }
+
+ if (found == false) {
+ /* Add new frame to the end */
+ BLI_addtail(&gpl->frames, new_frame);
+ }
+
+ /* Ensure that frame is set up correctly, and return it */
+ if (new_frame) {
+ new_frame->framenum = cframe;
+ gpl->actframe = new_frame;
+ }
+
+ return new_frame;
}
/* add a new gp-layer and make it the active layer */
bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setactive)
{
- bGPDlayer *gpl = NULL;
- bGPDlayer *gpl_active = NULL;
-
- /* check that list is ok */
- if (gpd == NULL)
- return NULL;
-
- /* allocate memory for frame and add to end of list */
- gpl = MEM_callocN(sizeof(bGPDlayer), "bGPDlayer");
-
- gpl_active = BKE_gpencil_layer_getactive(gpd);
-
- /* add to datablock */
- if (gpl_active == NULL) {
- BLI_addtail(&gpd->layers, gpl);
- }
- else {
- /* if active layer, add after that layer */
- BLI_insertlinkafter(&gpd->layers, gpl_active, gpl);
- }
-
- /* annotation vs GP Object behavior is slightly different */
- if (gpd->flag & GP_DATA_ANNOTATIONS) {
- /* set default color of new strokes for this layer */
- copy_v4_v4(gpl->color, U.gpencil_new_layer_col);
- gpl->opacity = 1.0f;
-
- /* set default thickness of new strokes for this layer */
- gpl->thickness = 3;
-
- /* Onion colors */
- ARRAY_SET_ITEMS(gpl->gcolor_prev, 0.302f, 0.851f, 0.302f);
- ARRAY_SET_ITEMS(gpl->gcolor_next, 0.250f, 0.1f, 1.0f);
- }
- else {
- /* thickness parameter represents "thickness change", not absolute thickness */
- gpl->thickness = 0;
- gpl->opacity = 1.0f;
- /* default channel color */
- ARRAY_SET_ITEMS(gpl->color, 0.2f, 0.2f, 0.2f);
- }
-
- /* auto-name */
- BLI_strncpy(gpl->info, name, sizeof(gpl->info));
- BLI_uniquename(&gpd->layers, gpl,
- (gpd->flag & GP_DATA_ANNOTATIONS) ? DATA_("Note") : DATA_("GP_Layer"),
- '.',
- offsetof(bGPDlayer, info),
- sizeof(gpl->info));
-
- /* make this one the active one */
- if (setactive)
- BKE_gpencil_layer_setactive(gpd, gpl);
-
- /* return layer */
- return gpl;
+ bGPDlayer *gpl = NULL;
+ bGPDlayer *gpl_active = NULL;
+
+ /* check that list is ok */
+ if (gpd == NULL)
+ return NULL;
+
+ /* allocate memory for frame and add to end of list */
+ gpl = MEM_callocN(sizeof(bGPDlayer), "bGPDlayer");
+
+ gpl_active = BKE_gpencil_layer_getactive(gpd);
+
+ /* add to datablock */
+ if (gpl_active == NULL) {
+ BLI_addtail(&gpd->layers, gpl);
+ }
+ else {
+ /* if active layer, add after that layer */
+ BLI_insertlinkafter(&gpd->layers, gpl_active, gpl);
+ }
+
+ /* annotation vs GP Object behavior is slightly different */
+ if (gpd->flag & GP_DATA_ANNOTATIONS) {
+ /* set default color of new strokes for this layer */
+ copy_v4_v4(gpl->color, U.gpencil_new_layer_col);
+ gpl->opacity = 1.0f;
+
+ /* set default thickness of new strokes for this layer */
+ gpl->thickness = 3;
+
+ /* Onion colors */
+ ARRAY_SET_ITEMS(gpl->gcolor_prev, 0.302f, 0.851f, 0.302f);
+ ARRAY_SET_ITEMS(gpl->gcolor_next, 0.250f, 0.1f, 1.0f);
+ }
+ else {
+ /* thickness parameter represents "thickness change", not absolute thickness */
+ gpl->thickness = 0;
+ gpl->opacity = 1.0f;
+ /* default channel color */
+ ARRAY_SET_ITEMS(gpl->color, 0.2f, 0.2f, 0.2f);
+ }
+
+ /* auto-name */
+ BLI_strncpy(gpl->info, name, sizeof(gpl->info));
+ BLI_uniquename(&gpd->layers,
+ gpl,
+ (gpd->flag & GP_DATA_ANNOTATIONS) ? DATA_("Note") : DATA_("GP_Layer"),
+ '.',
+ offsetof(bGPDlayer, info),
+ sizeof(gpl->info));
+
+ /* make this one the active one */
+ if (setactive)
+ BKE_gpencil_layer_setactive(gpd, gpl);
+
+ /* return layer */
+ return gpl;
}
/* add a new gp-datablock */
bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[])
{
- bGPdata *gpd;
+ bGPdata *gpd;
- /* allocate memory for a new block */
- gpd = BKE_libblock_alloc(bmain, ID_GD, name, 0);
+ /* allocate memory for a new block */
+ gpd = BKE_libblock_alloc(bmain, ID_GD, name, 0);
- /* initial settings */
- gpd->flag = (GP_DATA_DISPINFO | GP_DATA_EXPAND);
+ /* initial settings */
+ gpd->flag = (GP_DATA_DISPINFO | GP_DATA_EXPAND);
- /* general flags */
- gpd->flag |= GP_DATA_VIEWALIGN;
- gpd->flag |= GP_DATA_STROKE_FORCE_RECALC;
- /* always enable object onion skin swith */
- gpd->flag |= GP_DATA_SHOW_ONIONSKINS;
- /* GP object specific settings */
- ARRAY_SET_ITEMS(gpd->line_color, 0.6f, 0.6f, 0.6f, 0.5f);
+ /* general flags */
+ gpd->flag |= GP_DATA_VIEWALIGN;
+ gpd->flag |= GP_DATA_STROKE_FORCE_RECALC;
+ /* always enable object onion skin swith */
+ gpd->flag |= GP_DATA_SHOW_ONIONSKINS;
+ /* GP object specific settings */
+ ARRAY_SET_ITEMS(gpd->line_color, 0.6f, 0.6f, 0.6f, 0.5f);
- gpd->pixfactor = GP_DEFAULT_PIX_FACTOR;
+ gpd->pixfactor = GP_DEFAULT_PIX_FACTOR;
- /* grid settings */
- ARRAY_SET_ITEMS(gpd->grid.color, 0.5f, 0.5f, 0.5f); // Color
- ARRAY_SET_ITEMS(gpd->grid.scale, 1.0f, 1.0f); // Scale
- gpd->grid.lines = GP_DEFAULT_GRID_LINES; // Number of lines
+ /* grid settings */
+ ARRAY_SET_ITEMS(gpd->grid.color, 0.5f, 0.5f, 0.5f); // Color
+ ARRAY_SET_ITEMS(gpd->grid.scale, 1.0f, 1.0f); // Scale
+ gpd->grid.lines = GP_DEFAULT_GRID_LINES; // Number of lines
- /* onion-skinning settings (datablock level) */
- gpd->onion_flag |= (GP_ONION_GHOST_PREVCOL | GP_ONION_GHOST_NEXTCOL);
- gpd->onion_flag |= GP_ONION_FADE;
- gpd->onion_mode = GP_ONION_MODE_RELATIVE;
- gpd->onion_factor = 0.5f;
- ARRAY_SET_ITEMS(gpd->gcolor_prev, 0.145098f, 0.419608f, 0.137255f); /* green */
- ARRAY_SET_ITEMS(gpd->gcolor_next, 0.125490f, 0.082353f, 0.529412f); /* blue */
- gpd->gstep = 1;
- gpd->gstep_next = 1;
+ /* onion-skinning settings (datablock level) */
+ gpd->onion_flag |= (GP_ONION_GHOST_PREVCOL | GP_ONION_GHOST_NEXTCOL);
+ gpd->onion_flag |= GP_ONION_FADE;
+ gpd->onion_mode = GP_ONION_MODE_RELATIVE;
+ gpd->onion_factor = 0.5f;
+ ARRAY_SET_ITEMS(gpd->gcolor_prev, 0.145098f, 0.419608f, 0.137255f); /* green */
+ ARRAY_SET_ITEMS(gpd->gcolor_next, 0.125490f, 0.082353f, 0.529412f); /* blue */
+ gpd->gstep = 1;
+ gpd->gstep_next = 1;
- return gpd;
+ return gpd;
}
-
/* ************************************************** */
/* Primitive Creation */
/* Utilities for easier bulk-creation of geometry */
@@ -444,173 +443,175 @@ bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[])
* \param array: Flat array of point data values. Each entry has GP_PRIM_DATABUF_SIZE values
* \param mat: 4x4 transform matrix to transform points into the right coordinate space
*/
-void BKE_gpencil_stroke_add_points(bGPDstroke *gps, const float *array, const int totpoints, const float mat[4][4])
+void BKE_gpencil_stroke_add_points(bGPDstroke *gps,
+ const float *array,
+ const int totpoints,
+ const float mat[4][4])
{
- for (int i = 0; i < totpoints; i++) {
- bGPDspoint *pt = &gps->points[i];
- const int x = GP_PRIM_DATABUF_SIZE * i;
+ for (int i = 0; i < totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ const int x = GP_PRIM_DATABUF_SIZE * i;
- pt->x = array[x];
- pt->y = array[x + 1];
- pt->z = array[x + 2];
- mul_m4_v3(mat, &pt->x);
+ pt->x = array[x];
+ pt->y = array[x + 1];
+ pt->z = array[x + 2];
+ mul_m4_v3(mat, &pt->x);
- pt->pressure = array[x + 3];
- pt->strength = array[x + 4];
- }
+ pt->pressure = array[x + 3];
+ pt->strength = array[x + 4];
+ }
}
/* Create a new stroke, with pre-allocated data buffers */
bGPDstroke *BKE_gpencil_add_stroke(bGPDframe *gpf, int mat_idx, int totpoints, short thickness)
{
- /* allocate memory for a new stroke */
- bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
+ /* allocate memory for a new stroke */
+ bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
- gps->thickness = thickness;
- gps->gradient_f = 1.0f;
- gps->gradient_s[0] = 1.0f;
- gps->gradient_s[1] = 1.0f;
+ gps->thickness = thickness;
+ gps->gradient_f = 1.0f;
+ gps->gradient_s[0] = 1.0f;
+ gps->gradient_s[1] = 1.0f;
- gps->inittime = 0;
+ gps->inittime = 0;
- /* enable recalculation flag by default */
- gps->flag = GP_STROKE_RECALC_GEOMETRY | GP_STROKE_3DSPACE;
+ /* enable recalculation flag by default */
+ gps->flag = GP_STROKE_RECALC_GEOMETRY | GP_STROKE_3DSPACE;
- gps->totpoints = totpoints;
- gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+ gps->totpoints = totpoints;
+ gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
- /* initialize triangle memory to dummy data */
- gps->triangles = MEM_callocN(sizeof(bGPDtriangle), "GP Stroke triangulation");
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
- gps->tot_triangles = 0;
+ /* initialize triangle memory to dummy data */
+ gps->triangles = MEM_callocN(sizeof(bGPDtriangle), "GP Stroke triangulation");
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+ gps->tot_triangles = 0;
- gps->mat_nr = mat_idx;
+ gps->mat_nr = mat_idx;
- /* add to frame */
- BLI_addtail(&gpf->strokes, gps);
+ /* add to frame */
+ BLI_addtail(&gpf->strokes, gps);
- return gps;
+ return gps;
}
-
/* ************************************************** */
/* Data Duplication */
/* make a copy of a given gpencil weights */
void BKE_gpencil_stroke_weights_duplicate(bGPDstroke *gps_src, bGPDstroke *gps_dst)
{
- if (gps_src == NULL) {
- return;
- }
- BLI_assert(gps_src->totpoints == gps_dst->totpoints);
+ if (gps_src == NULL) {
+ return;
+ }
+ BLI_assert(gps_src->totpoints == gps_dst->totpoints);
- BKE_defvert_array_copy(gps_dst->dvert, gps_src->dvert, gps_src->totpoints);
+ BKE_defvert_array_copy(gps_dst->dvert, gps_src->dvert, gps_src->totpoints);
}
/* make a copy of a given gpencil stroke */
bGPDstroke *BKE_gpencil_stroke_duplicate(bGPDstroke *gps_src)
{
- bGPDstroke *gps_dst = NULL;
+ bGPDstroke *gps_dst = NULL;
- gps_dst = MEM_dupallocN(gps_src);
- gps_dst->prev = gps_dst->next = NULL;
+ gps_dst = MEM_dupallocN(gps_src);
+ gps_dst->prev = gps_dst->next = NULL;
- gps_dst->points = MEM_dupallocN(gps_src->points);
+ gps_dst->points = MEM_dupallocN(gps_src->points);
- if (gps_src->dvert != NULL) {
- gps_dst->dvert = MEM_dupallocN(gps_src->dvert);
- BKE_gpencil_stroke_weights_duplicate(gps_src, gps_dst);
- }
- else {
- gps_dst->dvert = NULL;
- }
+ if (gps_src->dvert != NULL) {
+ gps_dst->dvert = MEM_dupallocN(gps_src->dvert);
+ BKE_gpencil_stroke_weights_duplicate(gps_src, gps_dst);
+ }
+ else {
+ gps_dst->dvert = NULL;
+ }
- /* Don't clear triangles, so that modifier evaluation can just use
- * this without extra work first. Most places that need to force
- * this data to get recalculated will destroy the data anyway though.
- */
- gps_dst->triangles = MEM_dupallocN(gps_dst->triangles);
- /* gps_dst->flag |= GP_STROKE_RECALC_GEOMETRY; */
+ /* Don't clear triangles, so that modifier evaluation can just use
+ * this without extra work first. Most places that need to force
+ * this data to get recalculated will destroy the data anyway though.
+ */
+ gps_dst->triangles = MEM_dupallocN(gps_dst->triangles);
+ /* gps_dst->flag |= GP_STROKE_RECALC_GEOMETRY; */
- /* return new stroke */
- return gps_dst;
+ /* return new stroke */
+ return gps_dst;
}
/* make a copy of a given gpencil frame */
bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src)
{
- bGPDstroke *gps_dst = NULL;
- bGPDframe *gpf_dst;
+ bGPDstroke *gps_dst = NULL;
+ bGPDframe *gpf_dst;
- /* error checking */
- if (gpf_src == NULL) {
- return NULL;
- }
+ /* error checking */
+ if (gpf_src == NULL) {
+ return NULL;
+ }
- /* make a copy of the source frame */
- gpf_dst = MEM_dupallocN(gpf_src);
- gpf_dst->prev = gpf_dst->next = NULL;
+ /* make a copy of the source frame */
+ gpf_dst = MEM_dupallocN(gpf_src);
+ gpf_dst->prev = gpf_dst->next = NULL;
- /* copy strokes */
- BLI_listbase_clear(&gpf_dst->strokes);
- for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; gps_src = gps_src->next) {
- /* make copy of source stroke */
- gps_dst = BKE_gpencil_stroke_duplicate(gps_src);
- BLI_addtail(&gpf_dst->strokes, gps_dst);
- }
+ /* copy strokes */
+ BLI_listbase_clear(&gpf_dst->strokes);
+ for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; gps_src = gps_src->next) {
+ /* make copy of source stroke */
+ gps_dst = BKE_gpencil_stroke_duplicate(gps_src);
+ BLI_addtail(&gpf_dst->strokes, gps_dst);
+ }
- /* return new frame */
- return gpf_dst;
+ /* return new frame */
+ return gpf_dst;
}
/* make a copy of strokes between gpencil frames */
void BKE_gpencil_frame_copy_strokes(bGPDframe *gpf_src, struct bGPDframe *gpf_dst)
{
- bGPDstroke *gps_dst = NULL;
- /* error checking */
- if ((gpf_src == NULL) || (gpf_dst == NULL)) {
- return;
- }
+ bGPDstroke *gps_dst = NULL;
+ /* error checking */
+ if ((gpf_src == NULL) || (gpf_dst == NULL)) {
+ return;
+ }
- /* copy strokes */
- BLI_listbase_clear(&gpf_dst->strokes);
- for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; gps_src = gps_src->next) {
- /* make copy of source stroke */
- gps_dst = BKE_gpencil_stroke_duplicate(gps_src);
- BLI_addtail(&gpf_dst->strokes, gps_dst);
- }
+ /* copy strokes */
+ BLI_listbase_clear(&gpf_dst->strokes);
+ for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; gps_src = gps_src->next) {
+ /* make copy of source stroke */
+ gps_dst = BKE_gpencil_stroke_duplicate(gps_src);
+ BLI_addtail(&gpf_dst->strokes, gps_dst);
+ }
}
/* make a copy of a given gpencil layer */
bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src)
{
- const bGPDframe *gpf_src;
- bGPDframe *gpf_dst;
- bGPDlayer *gpl_dst;
+ const bGPDframe *gpf_src;
+ bGPDframe *gpf_dst;
+ bGPDlayer *gpl_dst;
- /* error checking */
- if (gpl_src == NULL) {
- return NULL;
- }
+ /* error checking */
+ if (gpl_src == NULL) {
+ return NULL;
+ }
- /* make a copy of source layer */
- gpl_dst = MEM_dupallocN(gpl_src);
- gpl_dst->prev = gpl_dst->next = NULL;
+ /* make a copy of source layer */
+ gpl_dst = MEM_dupallocN(gpl_src);
+ gpl_dst->prev = gpl_dst->next = NULL;
- /* copy frames */
- BLI_listbase_clear(&gpl_dst->frames);
- for (gpf_src = gpl_src->frames.first; gpf_src; gpf_src = gpf_src->next) {
- /* make a copy of source frame */
- gpf_dst = BKE_gpencil_frame_duplicate(gpf_src);
- BLI_addtail(&gpl_dst->frames, gpf_dst);
+ /* copy frames */
+ BLI_listbase_clear(&gpl_dst->frames);
+ for (gpf_src = gpl_src->frames.first; gpf_src; gpf_src = gpf_src->next) {
+ /* make a copy of source frame */
+ gpf_dst = BKE_gpencil_frame_duplicate(gpf_src);
+ BLI_addtail(&gpl_dst->frames, gpf_dst);
- /* if source frame was the current layer's 'active' frame, reassign that too */
- if (gpf_src == gpl_dst->actframe)
- gpl_dst->actframe = gpf_dst;
- }
+ /* if source frame was the current layer's 'active' frame, reassign that too */
+ if (gpf_src == gpl_dst->actframe)
+ gpl_dst->actframe = gpf_dst;
+ }
- /* return new layer */
- return gpl_dst;
+ /* return new layer */
+ return gpl_dst;
}
/**
@@ -623,63 +624,63 @@ bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src)
*/
void BKE_gpencil_copy_data(bGPdata *gpd_dst, const bGPdata *gpd_src, const int UNUSED(flag))
{
- /* duplicate material array */
- if (gpd_src->mat) {
- gpd_dst->mat = MEM_dupallocN(gpd_src->mat);
- }
-
- /* copy layers */
- BLI_listbase_clear(&gpd_dst->layers);
- for (const bGPDlayer *gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) {
- /* make a copy of source layer and its data */
- bGPDlayer *gpl_dst = BKE_gpencil_layer_duplicate(gpl_src); /* TODO here too could add unused flags... */
- BLI_addtail(&gpd_dst->layers, gpl_dst);
- }
+ /* duplicate material array */
+ if (gpd_src->mat) {
+ gpd_dst->mat = MEM_dupallocN(gpd_src->mat);
+ }
+ /* copy layers */
+ BLI_listbase_clear(&gpd_dst->layers);
+ for (const bGPDlayer *gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) {
+ /* make a copy of source layer and its data */
+ bGPDlayer *gpl_dst = BKE_gpencil_layer_duplicate(
+ gpl_src); /* TODO here too could add unused flags... */
+ BLI_addtail(&gpd_dst->layers, gpl_dst);
+ }
}
/* Standard API to make a copy of GP datablock, separate from copying its data */
bGPdata *BKE_gpencil_copy(Main *bmain, const bGPdata *gpd)
{
- bGPdata *gpd_copy;
- BKE_id_copy(bmain, &gpd->id, (ID **)&gpd_copy);
- return gpd_copy;
+ bGPdata *gpd_copy;
+ BKE_id_copy(bmain, &gpd->id, (ID **)&gpd_copy);
+ return gpd_copy;
}
/* make a copy of a given gpencil datablock */
// XXX: Should this be deprecated?
bGPdata *BKE_gpencil_data_duplicate(Main *bmain, const bGPdata *gpd_src, bool internal_copy)
{
- bGPdata *gpd_dst;
+ bGPdata *gpd_dst;
- /* Yuck and super-uber-hyper yuck!!!
- * Should be replaceable with a no-main copy (LIB_ID_COPY_NO_MAIN etc.), but not sure about it,
- * so for now keep old code for that one. */
+ /* Yuck and super-uber-hyper yuck!!!
+ * Should be replaceable with a no-main copy (LIB_ID_COPY_NO_MAIN etc.), but not sure about it,
+ * so for now keep old code for that one. */
- /* error checking */
- if (gpd_src == NULL) {
- return NULL;
- }
+ /* error checking */
+ if (gpd_src == NULL) {
+ return NULL;
+ }
- if (internal_copy) {
- /* make a straight copy for undo buffers used during stroke drawing */
- gpd_dst = MEM_dupallocN(gpd_src);
- }
- else {
- BLI_assert(bmain != NULL);
- BKE_id_copy(bmain, &gpd_src->id, (ID **)&gpd_dst);
- }
+ if (internal_copy) {
+ /* make a straight copy for undo buffers used during stroke drawing */
+ gpd_dst = MEM_dupallocN(gpd_src);
+ }
+ else {
+ BLI_assert(bmain != NULL);
+ BKE_id_copy(bmain, &gpd_src->id, (ID **)&gpd_dst);
+ }
- /* Copy internal data (layers, etc.) */
- BKE_gpencil_copy_data(gpd_dst, gpd_src, 0);
+ /* Copy internal data (layers, etc.) */
+ BKE_gpencil_copy_data(gpd_dst, gpd_src, 0);
- /* return new */
- return gpd_dst;
+ /* return new */
+ return gpd_dst;
}
void BKE_gpencil_make_local(Main *bmain, bGPdata *gpd, const bool lib_local)
{
- BKE_id_make_local_generic(bmain, &gpd->id, true, lib_local);
+ BKE_id_make_local_generic(bmain, &gpd->id, true, lib_local);
}
/* ************************************************** */
@@ -688,24 +689,24 @@ void BKE_gpencil_make_local(Main *bmain, bGPdata *gpd, const bool lib_local)
/* ensure selection status of stroke is in sync with its points */
void BKE_gpencil_stroke_sync_selection(bGPDstroke *gps)
{
- bGPDspoint *pt;
- int i;
+ bGPDspoint *pt;
+ int i;
- /* error checking */
- if (gps == NULL)
- return;
+ /* error checking */
+ if (gps == NULL)
+ return;
- /* we'll stop when we find the first selected point,
- * so initially, we must deselect
- */
- gps->flag &= ~GP_STROKE_SELECT;
+ /* we'll stop when we find the first selected point,
+ * so initially, we must deselect
+ */
+ gps->flag &= ~GP_STROKE_SELECT;
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (pt->flag & GP_SPOINT_SELECT) {
- gps->flag |= GP_STROKE_SELECT;
- break;
- }
- }
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ gps->flag |= GP_STROKE_SELECT;
+ break;
+ }
+ }
}
/* ************************************************** */
@@ -714,29 +715,29 @@ void BKE_gpencil_stroke_sync_selection(bGPDstroke *gps)
/* delete the last stroke of the given frame */
void BKE_gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf)
{
- bGPDstroke *gps = (gpf) ? gpf->strokes.last : NULL;
- int cfra = (gpf) ? gpf->framenum : 0; /* assume that the current frame was not locked */
+ bGPDstroke *gps = (gpf) ? gpf->strokes.last : NULL;
+ int cfra = (gpf) ? gpf->framenum : 0; /* assume that the current frame was not locked */
- /* error checking */
- if (ELEM(NULL, gpf, gps))
- return;
+ /* error checking */
+ if (ELEM(NULL, gpf, gps))
+ return;
- /* free the stroke and its data */
- if (gps->points) {
- MEM_freeN(gps->points);
- }
- if (gps->dvert) {
- BKE_gpencil_free_stroke_weights(gps);
- MEM_freeN(gps->dvert);
- }
- MEM_freeN(gps->triangles);
- BLI_freelinkN(&gpf->strokes, gps);
+ /* free the stroke and its data */
+ if (gps->points) {
+ MEM_freeN(gps->points);
+ }
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
+ MEM_freeN(gps->triangles);
+ BLI_freelinkN(&gpf->strokes, gps);
- /* if frame has no strokes after this, delete it */
- if (BLI_listbase_is_empty(&gpf->strokes)) {
- BKE_gpencil_layer_delframe(gpl, gpf);
- BKE_gpencil_layer_getframe(gpl, cfra, GP_GETFRAME_USE_PREV);
- }
+ /* if frame has no strokes after this, delete it */
+ if (BLI_listbase_is_empty(&gpf->strokes)) {
+ BKE_gpencil_layer_delframe(gpl, gpf);
+ BKE_gpencil_layer_getframe(gpl, cfra, GP_GETFRAME_USE_PREV);
+ }
}
/* ************************************************** */
@@ -745,39 +746,39 @@ void BKE_gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf)
/* Check if the given layer is able to be edited or not */
bool gpencil_layer_is_editable(const bGPDlayer *gpl)
{
- /* Sanity check */
- if (gpl == NULL)
- return false;
+ /* Sanity check */
+ if (gpl == NULL)
+ return false;
- /* Layer must be: Visible + Editable */
- if ((gpl->flag & (GP_LAYER_HIDE | GP_LAYER_LOCKED)) == 0) {
- /* Opacity must be sufficiently high that it is still "visible"
- * Otherwise, it's not really "visible" to the user, so no point editing...
- */
- if (gpl->opacity > GPENCIL_ALPHA_OPACITY_THRESH) {
- return true;
- }
- }
+ /* Layer must be: Visible + Editable */
+ if ((gpl->flag & (GP_LAYER_HIDE | GP_LAYER_LOCKED)) == 0) {
+ /* Opacity must be sufficiently high that it is still "visible"
+ * Otherwise, it's not really "visible" to the user, so no point editing...
+ */
+ if (gpl->opacity > GPENCIL_ALPHA_OPACITY_THRESH) {
+ return true;
+ }
+ }
- /* Something failed */
- return false;
+ /* Something failed */
+ return false;
}
/* Look up the gp-frame on the requested frame number, but don't add a new one */
bGPDframe *BKE_gpencil_layer_find_frame(bGPDlayer *gpl, int cframe)
{
- bGPDframe *gpf;
+ bGPDframe *gpf;
- /* Search in reverse order, since this is often used for playback/adding,
- * where it's less likely that we're interested in the earlier frames
- */
- for (gpf = gpl->frames.last; gpf; gpf = gpf->prev) {
- if (gpf->framenum == cframe) {
- return gpf;
- }
- }
+ /* Search in reverse order, since this is often used for playback/adding,
+ * where it's less likely that we're interested in the earlier frames
+ */
+ for (gpf = gpl->frames.last; gpf; gpf = gpf->prev) {
+ if (gpf->framenum == cframe) {
+ return gpf;
+ }
+ }
- return NULL;
+ return NULL;
}
/* get the appropriate gp-frame from a given layer
@@ -786,270 +787,270 @@ bGPDframe *BKE_gpencil_layer_find_frame(bGPDlayer *gpl, int cframe)
*/
bGPDframe *BKE_gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew)
{
- bGPDframe *gpf = NULL;
- short found = 0;
-
- /* error checking */
- if (gpl == NULL) return NULL;
-
- /* check if there is already an active frame */
- if (gpl->actframe) {
- gpf = gpl->actframe;
-
- /* do not allow any changes to layer's active frame if layer is locked from changes
- * or if the layer has been set to stay on the current frame
- */
- if (gpl->flag & GP_LAYER_FRAMELOCK)
- return gpf;
- /* do not allow any changes to actframe if frame has painting tag attached to it */
- if (gpf->flag & GP_FRAME_PAINT)
- return gpf;
-
- /* try to find matching frame */
- if (gpf->framenum < cframe) {
- for (; gpf; gpf = gpf->next) {
- if (gpf->framenum == cframe) {
- found = 1;
- break;
- }
- else if ((gpf->next) && (gpf->next->framenum > cframe)) {
- found = 1;
- break;
- }
- }
-
- /* set the appropriate frame */
- if (addnew) {
- if ((found) && (gpf->framenum == cframe))
- gpl->actframe = gpf;
- else if (addnew == GP_GETFRAME_ADD_COPY)
- gpl->actframe = BKE_gpencil_frame_addcopy(gpl, cframe);
- else
- gpl->actframe = BKE_gpencil_frame_addnew(gpl, cframe);
- }
- else if (found)
- gpl->actframe = gpf;
- else
- gpl->actframe = gpl->frames.last;
- }
- else {
- for (; gpf; gpf = gpf->prev) {
- if (gpf->framenum <= cframe) {
- found = 1;
- break;
- }
- }
-
- /* set the appropriate frame */
- if (addnew) {
- if ((found) && (gpf->framenum == cframe))
- gpl->actframe = gpf;
- else if (addnew == GP_GETFRAME_ADD_COPY)
- gpl->actframe = BKE_gpencil_frame_addcopy(gpl, cframe);
- else
- gpl->actframe = BKE_gpencil_frame_addnew(gpl, cframe);
- }
- else if (found)
- gpl->actframe = gpf;
- else
- gpl->actframe = gpl->frames.first;
- }
- }
- else if (gpl->frames.first) {
- /* check which of the ends to start checking from */
- const int first = ((bGPDframe *)(gpl->frames.first))->framenum;
- const int last = ((bGPDframe *)(gpl->frames.last))->framenum;
-
- if (abs(cframe - first) > abs(cframe - last)) {
- /* find gp-frame which is less than or equal to cframe */
- for (gpf = gpl->frames.last; gpf; gpf = gpf->prev) {
- if (gpf->framenum <= cframe) {
- found = 1;
- break;
- }
- }
- }
- else {
- /* find gp-frame which is less than or equal to cframe */
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- if (gpf->framenum <= cframe) {
- found = 1;
- break;
- }
- }
- }
-
- /* set the appropriate frame */
- if (addnew) {
- if ((found) && (gpf->framenum == cframe))
- gpl->actframe = gpf;
- else
- gpl->actframe = BKE_gpencil_frame_addnew(gpl, cframe);
- }
- else if (found)
- gpl->actframe = gpf;
- else {
- /* unresolved errogenous situation! */
- CLOG_STR_ERROR(&LOG, "cannot find appropriate gp-frame");
- /* gpl->actframe should still be NULL */
- }
- }
- else {
- /* currently no frames (add if allowed to) */
- if (addnew)
- gpl->actframe = BKE_gpencil_frame_addnew(gpl, cframe);
- else {
- /* don't do anything... this may be when no frames yet! */
- /* gpl->actframe should still be NULL */
- }
- }
-
- /* return */
- return gpl->actframe;
+ bGPDframe *gpf = NULL;
+ short found = 0;
+
+ /* error checking */
+ if (gpl == NULL)
+ return NULL;
+
+ /* check if there is already an active frame */
+ if (gpl->actframe) {
+ gpf = gpl->actframe;
+
+ /* do not allow any changes to layer's active frame if layer is locked from changes
+ * or if the layer has been set to stay on the current frame
+ */
+ if (gpl->flag & GP_LAYER_FRAMELOCK)
+ return gpf;
+ /* do not allow any changes to actframe if frame has painting tag attached to it */
+ if (gpf->flag & GP_FRAME_PAINT)
+ return gpf;
+
+ /* try to find matching frame */
+ if (gpf->framenum < cframe) {
+ for (; gpf; gpf = gpf->next) {
+ if (gpf->framenum == cframe) {
+ found = 1;
+ break;
+ }
+ else if ((gpf->next) && (gpf->next->framenum > cframe)) {
+ found = 1;
+ break;
+ }
+ }
+
+ /* set the appropriate frame */
+ if (addnew) {
+ if ((found) && (gpf->framenum == cframe))
+ gpl->actframe = gpf;
+ else if (addnew == GP_GETFRAME_ADD_COPY)
+ gpl->actframe = BKE_gpencil_frame_addcopy(gpl, cframe);
+ else
+ gpl->actframe = BKE_gpencil_frame_addnew(gpl, cframe);
+ }
+ else if (found)
+ gpl->actframe = gpf;
+ else
+ gpl->actframe = gpl->frames.last;
+ }
+ else {
+ for (; gpf; gpf = gpf->prev) {
+ if (gpf->framenum <= cframe) {
+ found = 1;
+ break;
+ }
+ }
+
+ /* set the appropriate frame */
+ if (addnew) {
+ if ((found) && (gpf->framenum == cframe))
+ gpl->actframe = gpf;
+ else if (addnew == GP_GETFRAME_ADD_COPY)
+ gpl->actframe = BKE_gpencil_frame_addcopy(gpl, cframe);
+ else
+ gpl->actframe = BKE_gpencil_frame_addnew(gpl, cframe);
+ }
+ else if (found)
+ gpl->actframe = gpf;
+ else
+ gpl->actframe = gpl->frames.first;
+ }
+ }
+ else if (gpl->frames.first) {
+ /* check which of the ends to start checking from */
+ const int first = ((bGPDframe *)(gpl->frames.first))->framenum;
+ const int last = ((bGPDframe *)(gpl->frames.last))->framenum;
+
+ if (abs(cframe - first) > abs(cframe - last)) {
+ /* find gp-frame which is less than or equal to cframe */
+ for (gpf = gpl->frames.last; gpf; gpf = gpf->prev) {
+ if (gpf->framenum <= cframe) {
+ found = 1;
+ break;
+ }
+ }
+ }
+ else {
+ /* find gp-frame which is less than or equal to cframe */
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ if (gpf->framenum <= cframe) {
+ found = 1;
+ break;
+ }
+ }
+ }
+
+ /* set the appropriate frame */
+ if (addnew) {
+ if ((found) && (gpf->framenum == cframe))
+ gpl->actframe = gpf;
+ else
+ gpl->actframe = BKE_gpencil_frame_addnew(gpl, cframe);
+ }
+ else if (found)
+ gpl->actframe = gpf;
+ else {
+ /* unresolved errogenous situation! */
+ CLOG_STR_ERROR(&LOG, "cannot find appropriate gp-frame");
+ /* gpl->actframe should still be NULL */
+ }
+ }
+ else {
+ /* currently no frames (add if allowed to) */
+ if (addnew)
+ gpl->actframe = BKE_gpencil_frame_addnew(gpl, cframe);
+ else {
+ /* don't do anything... this may be when no frames yet! */
+ /* gpl->actframe should still be NULL */
+ }
+ }
+
+ /* return */
+ return gpl->actframe;
}
/* delete the given frame from a layer */
bool BKE_gpencil_layer_delframe(bGPDlayer *gpl, bGPDframe *gpf)
{
- bool changed = false;
+ bool changed = false;
- /* error checking */
- if (ELEM(NULL, gpl, gpf))
- return false;
+ /* error checking */
+ if (ELEM(NULL, gpl, gpf))
+ return false;
- /* if this frame was active, make the previous frame active instead
- * since it's tricky to set active frame otherwise
- */
- if (gpl->actframe == gpf)
- gpl->actframe = gpf->prev;
+ /* if this frame was active, make the previous frame active instead
+ * since it's tricky to set active frame otherwise
+ */
+ if (gpl->actframe == gpf)
+ gpl->actframe = gpf->prev;
- /* free the frame and its data */
- changed = BKE_gpencil_free_strokes(gpf);
- BLI_freelinkN(&gpl->frames, gpf);
+ /* free the frame and its data */
+ changed = BKE_gpencil_free_strokes(gpf);
+ BLI_freelinkN(&gpl->frames, gpf);
- return changed;
+ return changed;
}
/* get the active gp-layer for editing */
bGPDlayer *BKE_gpencil_layer_getactive(bGPdata *gpd)
{
- bGPDlayer *gpl;
+ bGPDlayer *gpl;
- /* error checking */
- if (ELEM(NULL, gpd, gpd->layers.first))
- return NULL;
+ /* error checking */
+ if (ELEM(NULL, gpd, gpd->layers.first))
+ return NULL;
- /* loop over layers until found (assume only one active) */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- if (gpl->flag & GP_LAYER_ACTIVE)
- return gpl;
- }
+ /* loop over layers until found (assume only one active) */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if (gpl->flag & GP_LAYER_ACTIVE)
+ return gpl;
+ }
- /* no active layer found */
- return NULL;
+ /* no active layer found */
+ return NULL;
}
/* set the active gp-layer */
void BKE_gpencil_layer_setactive(bGPdata *gpd, bGPDlayer *active)
{
- bGPDlayer *gpl;
+ bGPDlayer *gpl;
- /* error checking */
- if (ELEM(NULL, gpd, gpd->layers.first, active))
- return;
+ /* error checking */
+ if (ELEM(NULL, gpd, gpd->layers.first, active))
+ return;
- /* loop over layers deactivating all */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- gpl->flag &= ~GP_LAYER_ACTIVE;
- if (gpd->flag & GP_DATA_AUTOLOCK_LAYERS) {
- gpl->flag |= GP_LAYER_LOCKED;
- }
- }
+ /* loop over layers deactivating all */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ gpl->flag &= ~GP_LAYER_ACTIVE;
+ if (gpd->flag & GP_DATA_AUTOLOCK_LAYERS) {
+ gpl->flag |= GP_LAYER_LOCKED;
+ }
+ }
- /* set as active one */
- active->flag |= GP_LAYER_ACTIVE;
- if (gpd->flag & GP_DATA_AUTOLOCK_LAYERS) {
- active->flag &= ~GP_LAYER_LOCKED;
- }
+ /* set as active one */
+ active->flag |= GP_LAYER_ACTIVE;
+ if (gpd->flag & GP_DATA_AUTOLOCK_LAYERS) {
+ active->flag &= ~GP_LAYER_LOCKED;
+ }
}
/* delete the active gp-layer */
void BKE_gpencil_layer_delete(bGPdata *gpd, bGPDlayer *gpl)
{
- /* error checking */
- if (ELEM(NULL, gpd, gpl))
- return;
+ /* error checking */
+ if (ELEM(NULL, gpd, gpl))
+ return;
- /* free layer */
- BKE_gpencil_free_frames(gpl);
+ /* free layer */
+ BKE_gpencil_free_frames(gpl);
- /* free icon providing preview of icon color */
- BKE_icon_delete(gpl->runtime.icon_id);
+ /* free icon providing preview of icon color */
+ BKE_icon_delete(gpl->runtime.icon_id);
- BLI_freelinkN(&gpd->layers, gpl);
+ BLI_freelinkN(&gpd->layers, gpl);
}
Material *BKE_gpencil_brush_material_get(Brush *brush)
{
- Material *ma = NULL;
+ Material *ma = NULL;
- if ((brush != NULL) && (brush->gpencil_settings != NULL) &&
- (brush->gpencil_settings->material != NULL))
- {
- ma = brush->gpencil_settings->material;
- }
+ if ((brush != NULL) && (brush->gpencil_settings != NULL) &&
+ (brush->gpencil_settings->material != NULL)) {
+ ma = brush->gpencil_settings->material;
+ }
- return ma;
+ return ma;
}
void BKE_gpencil_brush_material_set(Brush *brush, Material *ma)
{
- BLI_assert(brush);
- BLI_assert(brush->gpencil_settings);
- if (brush->gpencil_settings->material != ma) {
- if (brush->gpencil_settings->material) {
- id_us_min(&brush->gpencil_settings->material->id);
- }
- if (ma) {
- id_us_plus(&ma->id);
- }
- brush->gpencil_settings->material = ma;
- }
+ BLI_assert(brush);
+ BLI_assert(brush->gpencil_settings);
+ if (brush->gpencil_settings->material != ma) {
+ if (brush->gpencil_settings->material) {
+ id_us_min(&brush->gpencil_settings->material->id);
+ }
+ if (ma) {
+ id_us_plus(&ma->id);
+ }
+ brush->gpencil_settings->material = ma;
+ }
}
/* Adds the pinned material to the object if necessary. */
Material *BKE_gpencil_object_material_ensure_from_brush(Main *bmain, Object *ob, Brush *brush)
{
- if (brush->gpencil_settings->flag & GP_BRUSH_MATERIAL_PINNED) {
- Material *ma = BKE_gpencil_brush_material_get(brush);
+ if (brush->gpencil_settings->flag & GP_BRUSH_MATERIAL_PINNED) {
+ Material *ma = BKE_gpencil_brush_material_get(brush);
- /* check if the material is already on object material slots and add it if missing */
- if (ma && BKE_gpencil_object_material_get_index(ob, ma) < 0) {
- BKE_object_material_slot_add(bmain, ob);
- assign_material(bmain, ob, ma, ob->totcol, BKE_MAT_ASSIGN_USERPREF);
- }
+ /* check if the material is already on object material slots and add it if missing */
+ if (ma && BKE_gpencil_object_material_get_index(ob, ma) < 0) {
+ BKE_object_material_slot_add(bmain, ob);
+ assign_material(bmain, ob, ma, ob->totcol, BKE_MAT_ASSIGN_USERPREF);
+ }
- return ma;
- }
- else {
- /* using active material instead */
- return give_current_material(ob, ob->actcol);
- }
+ return ma;
+ }
+ else {
+ /* using active material instead */
+ return give_current_material(ob, ob->actcol);
+ }
}
/* Assigns the material to object (if not already present) and returns its index (mat_nr). */
int BKE_gpencil_object_material_ensure(Main *bmain, Object *ob, Material *material)
{
- if (!material) {
- return -1;
- }
- int index = BKE_gpencil_object_material_get_index(ob, material);
- if (index < 0) {
- BKE_object_material_slot_add(bmain, ob);
- assign_material(bmain, ob, material, ob->totcol, BKE_MAT_ASSIGN_USERPREF);
- return ob->totcol - 1;
- }
- return index;
+ if (!material) {
+ return -1;
+ }
+ int index = BKE_gpencil_object_material_get_index(ob, material);
+ if (index < 0) {
+ BKE_object_material_slot_add(bmain, ob);
+ assign_material(bmain, ob, material, ob->totcol, BKE_MAT_ASSIGN_USERPREF);
+ return ob->totcol - 1;
+ }
+ return index;
}
/** Creates a new gpencil material and assigns it to object.
@@ -1058,93 +1059,98 @@ int BKE_gpencil_object_material_ensure(Main *bmain, Object *ob, Material *materi
*/
Material *BKE_gpencil_object_material_new(Main *bmain, Object *ob, const char *name, int *r_index)
{
- Material *ma = BKE_material_add_gpencil(bmain, name);
- id_us_min(&ma->id); /* no users yet */
+ Material *ma = BKE_material_add_gpencil(bmain, name);
+ id_us_min(&ma->id); /* no users yet */
- BKE_object_material_slot_add(bmain, ob);
- assign_material(bmain, ob, ma, ob->totcol, BKE_MAT_ASSIGN_USERPREF);
+ BKE_object_material_slot_add(bmain, ob);
+ assign_material(bmain, ob, ma, ob->totcol, BKE_MAT_ASSIGN_USERPREF);
- if (r_index) {
- *r_index = ob->actcol - 1;
- }
- return ma;
+ if (r_index) {
+ *r_index = ob->actcol - 1;
+ }
+ return ma;
}
/* Returns the material for a brush with respect to its pinned state. */
Material *BKE_gpencil_object_material_get_from_brush(Object *ob, Brush *brush)
{
- if ((brush) && (brush->gpencil_settings->flag & GP_BRUSH_MATERIAL_PINNED)) {
- Material *ma = BKE_gpencil_brush_material_get(brush);
- return ma;
- }
- else {
- return give_current_material(ob, ob->actcol);
- }
+ if ((brush) && (brush->gpencil_settings->flag & GP_BRUSH_MATERIAL_PINNED)) {
+ Material *ma = BKE_gpencil_brush_material_get(brush);
+ return ma;
+ }
+ else {
+ return give_current_material(ob, ob->actcol);
+ }
}
/* Returns the material index for a brush with respect to its pinned state. */
int BKE_gpencil_object_material_get_index_from_brush(Object *ob, Brush *brush)
{
- if ((brush) && (brush->gpencil_settings->flag & GP_BRUSH_MATERIAL_PINNED)) {
- return BKE_gpencil_object_material_get_index(ob, brush->gpencil_settings->material);
- }
- else {
- return ob->actcol - 1;
- }
+ if ((brush) && (brush->gpencil_settings->flag & GP_BRUSH_MATERIAL_PINNED)) {
+ return BKE_gpencil_object_material_get_index(ob, brush->gpencil_settings->material);
+ }
+ else {
+ return ob->actcol - 1;
+ }
}
/* Guaranteed to return a material assigned to object. Returns never NULL. */
-Material *BKE_gpencil_object_material_ensure_from_active_input_toolsettings(Main *bmain, Object *ob, ToolSettings *ts)
+Material *BKE_gpencil_object_material_ensure_from_active_input_toolsettings(Main *bmain,
+ Object *ob,
+ ToolSettings *ts)
{
- if (ts && ts->gp_paint && ts->gp_paint->paint.brush) {
- return BKE_gpencil_object_material_ensure_from_active_input_brush(bmain, ob, ts->gp_paint->paint.brush);
- }
- else {
- return BKE_gpencil_object_material_ensure_from_active_input_brush(bmain, ob, NULL);
- }
+ if (ts && ts->gp_paint && ts->gp_paint->paint.brush) {
+ return BKE_gpencil_object_material_ensure_from_active_input_brush(
+ bmain, ob, ts->gp_paint->paint.brush);
+ }
+ else {
+ return BKE_gpencil_object_material_ensure_from_active_input_brush(bmain, ob, NULL);
+ }
}
/* Guaranteed to return a material assigned to object. Returns never NULL. */
-Material *BKE_gpencil_object_material_ensure_from_active_input_brush(Main *bmain, Object *ob, Brush *brush)
-{
- if (brush) {
- Material *ma = BKE_gpencil_object_material_ensure_from_brush(bmain, ob, brush);
- if (ma) {
- return ma;
- }
- else if (brush->gpencil_settings->flag & GP_BRUSH_MATERIAL_PINNED) {
- /* it is easier to just unpin a NULL material, instead of setting a new one */
- brush->gpencil_settings->flag &= ~GP_BRUSH_MATERIAL_PINNED;
- }
- }
- return BKE_gpencil_object_material_ensure_from_active_input_material(bmain, ob);
+Material *BKE_gpencil_object_material_ensure_from_active_input_brush(Main *bmain,
+ Object *ob,
+ Brush *brush)
+{
+ if (brush) {
+ Material *ma = BKE_gpencil_object_material_ensure_from_brush(bmain, ob, brush);
+ if (ma) {
+ return ma;
+ }
+ else if (brush->gpencil_settings->flag & GP_BRUSH_MATERIAL_PINNED) {
+ /* it is easier to just unpin a NULL material, instead of setting a new one */
+ brush->gpencil_settings->flag &= ~GP_BRUSH_MATERIAL_PINNED;
+ }
+ }
+ return BKE_gpencil_object_material_ensure_from_active_input_material(bmain, ob);
}
/* Guaranteed to return a material assigned to object. Returns never NULL. Only use this for materials unrelated to user input */
Material *BKE_gpencil_object_material_ensure_from_active_input_material(Main *bmain, Object *ob)
{
- Material *ma = give_current_material(ob, ob->actcol);
- if (ma) {
- return ma;
- }
- return BKE_gpencil_object_material_new(bmain, ob, "Material", NULL);
+ Material *ma = give_current_material(ob, ob->actcol);
+ if (ma) {
+ return ma;
+ }
+ return BKE_gpencil_object_material_new(bmain, ob, "Material", NULL);
}
/* Get active color, and add all default settings if we don't find anything */
Material *BKE_gpencil_object_material_ensure_active(Main *bmain, Object *ob)
{
- Material *ma = NULL;
+ Material *ma = NULL;
- /* sanity checks */
- if (ELEM(NULL, bmain, ob))
- return NULL;
+ /* sanity checks */
+ if (ELEM(NULL, bmain, ob))
+ return NULL;
- ma = BKE_gpencil_object_material_ensure_from_active_input_material(bmain, ob);
- if (ma->gp_style == NULL) {
- BKE_material_init_gpencil_settings(ma);
- }
+ ma = BKE_gpencil_object_material_ensure_from_active_input_material(bmain, ob);
+ if (ma->gp_style == NULL) {
+ BKE_material_init_gpencil_settings(ma);
+ }
- return ma;
+ return ma;
}
/* ************************************************** */
@@ -1154,112 +1160,111 @@ Material *BKE_gpencil_object_material_ensure_active(Main *bmain, Object *ob)
* Get min/max coordinate bounds for single stroke
* \return Returns whether we found any selected points
*/
-bool BKE_gpencil_stroke_minmax(
- const bGPDstroke *gps, const bool use_select,
- float r_min[3], float r_max[3])
+bool BKE_gpencil_stroke_minmax(const bGPDstroke *gps,
+ const bool use_select,
+ float r_min[3],
+ float r_max[3])
{
- const bGPDspoint *pt;
- int i;
- bool changed = false;
+ const bGPDspoint *pt;
+ int i;
+ bool changed = false;
- if (ELEM(NULL, gps, r_min, r_max))
- return false;
+ if (ELEM(NULL, gps, r_min, r_max))
+ return false;
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if ((use_select == false) || (pt->flag & GP_SPOINT_SELECT)) {
- minmax_v3v3_v3(r_min, r_max, &pt->x);
- changed = true;
- }
- }
- return changed;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if ((use_select == false) || (pt->flag & GP_SPOINT_SELECT)) {
+ minmax_v3v3_v3(r_min, r_max, &pt->x);
+ changed = true;
+ }
+ }
+ return changed;
}
/* get min/max bounds of all strokes in GP datablock */
bool BKE_gpencil_data_minmax(const bGPdata *gpd, float r_min[3], float r_max[3])
{
- bool changed = false;
+ bool changed = false;
- INIT_MINMAX(r_min, r_max);
+ INIT_MINMAX(r_min, r_max);
- if (gpd == NULL)
- return changed;
+ if (gpd == NULL)
+ return changed;
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- bGPDframe *gpf = gpl->actframe;
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ bGPDframe *gpf = gpl->actframe;
- if (gpf != NULL) {
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- changed = BKE_gpencil_stroke_minmax(gps, false, r_min, r_max);
- }
- }
- }
+ if (gpf != NULL) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ changed = BKE_gpencil_stroke_minmax(gps, false, r_min, r_max);
+ }
+ }
+ }
- return changed;
+ return changed;
}
-bool BKE_gpencil_stroke_select_check(
- const bGPDstroke *gps)
+bool BKE_gpencil_stroke_select_check(const bGPDstroke *gps)
{
- const bGPDspoint *pt;
- int i;
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (pt->flag & GP_SPOINT_SELECT) {
- return true;
- }
- }
- return false;
+ const bGPDspoint *pt;
+ int i;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ return true;
+ }
+ }
+ return false;
}
/* compute center of bounding box */
void BKE_gpencil_centroid_3d(bGPdata *gpd, float r_centroid[3])
{
- float min[3], max[3], tot[3];
+ float min[3], max[3], tot[3];
- BKE_gpencil_data_minmax(gpd, min, max);
+ BKE_gpencil_data_minmax(gpd, min, max);
- add_v3_v3v3(tot, min, max);
- mul_v3_v3fl(r_centroid, tot, 0.5f);
+ add_v3_v3v3(tot, min, max);
+ mul_v3_v3fl(r_centroid, tot, 0.5f);
}
-
/* create bounding box values */
static void boundbox_gpencil(Object *ob)
{
- BoundBox *bb;
- bGPdata *gpd;
- float min[3], max[3];
+ BoundBox *bb;
+ bGPdata *gpd;
+ float min[3], max[3];
- if (ob->runtime.bb == NULL) {
- ob->runtime.bb = MEM_callocN(sizeof(BoundBox), "GPencil boundbox");
- }
+ if (ob->runtime.bb == NULL) {
+ ob->runtime.bb = MEM_callocN(sizeof(BoundBox), "GPencil boundbox");
+ }
- bb = ob->runtime.bb;
- gpd = ob->data;
+ bb = ob->runtime.bb;
+ gpd = ob->data;
- if (!BKE_gpencil_data_minmax(gpd, min, max)) {
- min[0] = min[1] = min[2] = -1.0f;
- max[0] = max[1] = max[2] = 1.0f;
- }
+ if (!BKE_gpencil_data_minmax(gpd, min, max)) {
+ min[0] = min[1] = min[2] = -1.0f;
+ max[0] = max[1] = max[2] = 1.0f;
+ }
- BKE_boundbox_init_from_minmax(bb, min, max);
+ BKE_boundbox_init_from_minmax(bb, min, max);
- bb->flag &= ~BOUNDBOX_DIRTY;
+ bb->flag &= ~BOUNDBOX_DIRTY;
}
/* get bounding box */
BoundBox *BKE_gpencil_boundbox_get(Object *ob)
{
- if (ELEM(NULL, ob, ob->data))
- return NULL;
+ if (ELEM(NULL, ob, ob->data))
+ return NULL;
- bGPdata *gpd = (bGPdata *)ob->data;
- if ((ob->runtime.bb) && ((gpd->flag & GP_DATA_CACHE_IS_DIRTY) == 0)) {
- return ob->runtime.bb;
- }
+ bGPdata *gpd = (bGPdata *)ob->data;
+ if ((ob->runtime.bb) && ((gpd->flag & GP_DATA_CACHE_IS_DIRTY) == 0)) {
+ return ob->runtime.bb;
+ }
- boundbox_gpencil(ob);
+ boundbox_gpencil(ob);
- return ob->runtime.bb;
+ return ob->runtime.bb;
}
/* ************************************************** */
@@ -1267,34 +1272,33 @@ BoundBox *BKE_gpencil_boundbox_get(Object *ob)
void BKE_gpencil_transform(bGPdata *gpd, float mat[4][4])
{
- if (gpd == NULL)
- return;
-
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- /* FIXME: For now, we just skip parented layers.
- * Otherwise, we have to update each frame to find
- * the current parent position/effects.
- */
- if (gpl->parent) {
- continue;
- }
+ if (gpd == NULL)
+ return;
- for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- bGPDspoint *pt;
- int i;
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* FIXME: For now, we just skip parented layers.
+ * Otherwise, we have to update each frame to find
+ * the current parent position/effects.
+ */
+ if (gpl->parent) {
+ continue;
+ }
- for (pt = gps->points, i = 0; i < gps->totpoints; pt++, i++) {
- mul_m4_v3(mat, &pt->x);
- }
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ bGPDspoint *pt;
+ int i;
- /* TODO: Do we need to do this? distortion may mean we need to re-triangulate */
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
- gps->tot_triangles = 0;
- }
- }
- }
+ for (pt = gps->points, i = 0; i < gps->totpoints; pt++, i++) {
+ mul_m4_v3(mat, &pt->x);
+ }
+ /* TODO: Do we need to do this? distortion may mean we need to re-triangulate */
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+ gps->tot_triangles = 0;
+ }
+ }
+ }
}
/* ************************************************** */
@@ -1303,49 +1307,48 @@ void BKE_gpencil_transform(bGPdata *gpd, float mat[4][4])
/* remove a vertex group */
void BKE_gpencil_vgroup_remove(Object *ob, bDeformGroup *defgroup)
{
- bGPdata *gpd = ob->data;
- MDeformVert *dvert = NULL;
- const int def_nr = BLI_findindex(&ob->defbase, defgroup);
-
- /* Remove points data */
- if (gpd) {
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- if (gps->dvert != NULL) {
- for (int i = 0; i < gps->totpoints; i++) {
- dvert = &gps->dvert[i];
- MDeformWeight *dw = defvert_find_index(dvert, def_nr);
- if (dw != NULL) {
- defvert_remove_group(dvert, dw);
- }
- else {
- /* reorganize weights in other strokes */
- for (int g = 0; g < gps->dvert->totweight; g++) {
- dw = &dvert->dw[g];
- if ((dw != NULL) && (dw->def_nr > def_nr)) {
- dw->def_nr--;
- }
- }
- }
- }
- }
- }
- }
- }
- }
-
- /* Remove the group */
- BLI_freelinkN(&ob->defbase, defgroup);
- DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ bGPdata *gpd = ob->data;
+ MDeformVert *dvert = NULL;
+ const int def_nr = BLI_findindex(&ob->defbase, defgroup);
+
+ /* Remove points data */
+ if (gpd) {
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ if (gps->dvert != NULL) {
+ for (int i = 0; i < gps->totpoints; i++) {
+ dvert = &gps->dvert[i];
+ MDeformWeight *dw = defvert_find_index(dvert, def_nr);
+ if (dw != NULL) {
+ defvert_remove_group(dvert, dw);
+ }
+ else {
+ /* reorganize weights in other strokes */
+ for (int g = 0; g < gps->dvert->totweight; g++) {
+ dw = &dvert->dw[g];
+ if ((dw != NULL) && (dw->def_nr > def_nr)) {
+ dw->def_nr--;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Remove the group */
+ BLI_freelinkN(&ob->defbase, defgroup);
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
}
-
void BKE_gpencil_dvert_ensure(bGPDstroke *gps)
{
- if (gps->dvert == NULL) {
- gps->dvert = MEM_callocN(sizeof(MDeformVert) * gps->totpoints, "gp_stroke_weights");
- }
+ if (gps->dvert == NULL) {
+ gps->dvert = MEM_callocN(sizeof(MDeformVert) * gps->totpoints, "gp_stroke_weights");
+ }
}
/* ************************************************** */
@@ -1358,134 +1361,133 @@ void BKE_gpencil_dvert_ensure(bGPDstroke *gps)
*/
bool BKE_gpencil_smooth_stroke(bGPDstroke *gps, int i, float inf)
{
- bGPDspoint *pt = &gps->points[i];
- // float pressure = 0.0f;
- float sco[3] = { 0.0f };
+ bGPDspoint *pt = &gps->points[i];
+ // float pressure = 0.0f;
+ float sco[3] = {0.0f};
- /* Do nothing if not enough points to smooth out */
- if (gps->totpoints <= 2) {
- return false;
- }
+ /* Do nothing if not enough points to smooth out */
+ if (gps->totpoints <= 2) {
+ return false;
+ }
- /* Only affect endpoints by a fraction of the normal strength,
- * to prevent the stroke from shrinking too much
- */
- if ((i == 0) || (i == gps->totpoints - 1)) {
- inf *= 0.1f;
- }
+ /* Only affect endpoints by a fraction of the normal strength,
+ * to prevent the stroke from shrinking too much
+ */
+ if ((i == 0) || (i == gps->totpoints - 1)) {
+ inf *= 0.1f;
+ }
- /* Compute smoothed coordinate by taking the ones nearby */
- /* XXX: This is potentially slow, and suffers from accumulation error as earlier points are handled before later ones */
- {
- // XXX: this is hardcoded to look at 2 points on either side of the current one (i.e. 5 items total)
- const int steps = 2;
- const float average_fac = 1.0f / (float)(steps * 2 + 1);
- int step;
+ /* Compute smoothed coordinate by taking the ones nearby */
+ /* XXX: This is potentially slow, and suffers from accumulation error as earlier points are handled before later ones */
+ {
+ // XXX: this is hardcoded to look at 2 points on either side of the current one (i.e. 5 items total)
+ const int steps = 2;
+ const float average_fac = 1.0f / (float)(steps * 2 + 1);
+ int step;
- /* add the point itself */
- madd_v3_v3fl(sco, &pt->x, average_fac);
+ /* add the point itself */
+ madd_v3_v3fl(sco, &pt->x, average_fac);
- /* n-steps before/after current point */
- // XXX: review how the endpoints are treated by this algorithm
- // XXX: falloff measures should also introduce some weighting variations, so that further-out points get less weight
- for (step = 1; step <= steps; step++) {
- bGPDspoint *pt1, *pt2;
- int before = i - step;
- int after = i + step;
+ /* n-steps before/after current point */
+ // XXX: review how the endpoints are treated by this algorithm
+ // XXX: falloff measures should also introduce some weighting variations, so that further-out points get less weight
+ for (step = 1; step <= steps; step++) {
+ bGPDspoint *pt1, *pt2;
+ int before = i - step;
+ int after = i + step;
- CLAMP_MIN(before, 0);
- CLAMP_MAX(after, gps->totpoints - 1);
+ CLAMP_MIN(before, 0);
+ CLAMP_MAX(after, gps->totpoints - 1);
- pt1 = &gps->points[before];
- pt2 = &gps->points[after];
+ pt1 = &gps->points[before];
+ pt2 = &gps->points[after];
- /* add both these points to the average-sum (s += p[i]/n) */
- madd_v3_v3fl(sco, &pt1->x, average_fac);
- madd_v3_v3fl(sco, &pt2->x, average_fac);
+ /* add both these points to the average-sum (s += p[i]/n) */
+ madd_v3_v3fl(sco, &pt1->x, average_fac);
+ madd_v3_v3fl(sco, &pt2->x, average_fac);
+ }
+ }
- }
- }
+ /* Based on influence factor, blend between original and optimal smoothed coordinate */
+ interp_v3_v3v3(&pt->x, &pt->x, sco, inf);
- /* Based on influence factor, blend between original and optimal smoothed coordinate */
- interp_v3_v3v3(&pt->x, &pt->x, sco, inf);
-
- return true;
+ return true;
}
/**
* Apply smooth for strength to stroke point */
bool BKE_gpencil_smooth_stroke_strength(bGPDstroke *gps, int point_index, float influence)
{
- bGPDspoint *ptb = &gps->points[point_index];
+ bGPDspoint *ptb = &gps->points[point_index];
- /* Do nothing if not enough points */
- if (gps->totpoints <= 2) {
- return false;
- }
+ /* Do nothing if not enough points */
+ if (gps->totpoints <= 2) {
+ return false;
+ }
- /* Compute theoretical optimal value using distances */
- bGPDspoint *pta, *ptc;
- int before = point_index - 1;
- int after = point_index + 1;
+ /* Compute theoretical optimal value using distances */
+ bGPDspoint *pta, *ptc;
+ int before = point_index - 1;
+ int after = point_index + 1;
- CLAMP_MIN(before, 0);
- CLAMP_MAX(after, gps->totpoints - 1);
+ CLAMP_MIN(before, 0);
+ CLAMP_MAX(after, gps->totpoints - 1);
- pta = &gps->points[before];
- ptc = &gps->points[after];
+ pta = &gps->points[before];
+ ptc = &gps->points[after];
- /* the optimal value is the corresponding to the interpolation of the strength
- * at the distance of point b
- */
- float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
- /* sometimes the factor can be wrong due stroke geometry, so use middle point */
- if ((fac < 0.0f) || (fac > 1.0f)) {
- fac = 0.5f;
- }
- const float optimal = (1.0f - fac) * pta->strength + fac * ptc->strength;
+ /* the optimal value is the corresponding to the interpolation of the strength
+ * at the distance of point b
+ */
+ float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
+ /* sometimes the factor can be wrong due stroke geometry, so use middle point */
+ if ((fac < 0.0f) || (fac > 1.0f)) {
+ fac = 0.5f;
+ }
+ const float optimal = (1.0f - fac) * pta->strength + fac * ptc->strength;
- /* Based on influence factor, blend between original and optimal */
- ptb->strength = (1.0f - influence) * ptb->strength + influence * optimal;
+ /* Based on influence factor, blend between original and optimal */
+ ptb->strength = (1.0f - influence) * ptb->strength + influence * optimal;
- return true;
+ return true;
}
/**
* Apply smooth for thickness to stroke point (use pressure) */
bool BKE_gpencil_smooth_stroke_thickness(bGPDstroke *gps, int point_index, float influence)
{
- bGPDspoint *ptb = &gps->points[point_index];
+ bGPDspoint *ptb = &gps->points[point_index];
- /* Do nothing if not enough points */
- if ((gps->totpoints <= 2) || (point_index < 1)) {
- return false;
- }
+ /* Do nothing if not enough points */
+ if ((gps->totpoints <= 2) || (point_index < 1)) {
+ return false;
+ }
- /* Compute theoretical optimal value using distances */
- bGPDspoint *pta, *ptc;
- int before = point_index - 1;
- int after = point_index + 1;
+ /* Compute theoretical optimal value using distances */
+ bGPDspoint *pta, *ptc;
+ int before = point_index - 1;
+ int after = point_index + 1;
- CLAMP_MIN(before, 0);
- CLAMP_MAX(after, gps->totpoints - 1);
+ CLAMP_MIN(before, 0);
+ CLAMP_MAX(after, gps->totpoints - 1);
- pta = &gps->points[before];
- ptc = &gps->points[after];
+ pta = &gps->points[before];
+ ptc = &gps->points[after];
- /* the optimal value is the corresponding to the interpolation of the pressure
- * at the distance of point b
- */
- float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
- /* sometimes the factor can be wrong due stroke geometry, so use middle point */
- if ((fac < 0.0f) || (fac > 1.0f)) {
- fac = 0.5f;
- }
- float optimal = interpf(ptc->pressure, pta->pressure, fac);
+ /* the optimal value is the corresponding to the interpolation of the pressure
+ * at the distance of point b
+ */
+ float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
+ /* sometimes the factor can be wrong due stroke geometry, so use middle point */
+ if ((fac < 0.0f) || (fac > 1.0f)) {
+ fac = 0.5f;
+ }
+ float optimal = interpf(ptc->pressure, pta->pressure, fac);
- /* Based on influence factor, blend between original and optimal */
- ptb->pressure = interpf(optimal, ptb->pressure, influence);
+ /* Based on influence factor, blend between original and optimal */
+ ptb->pressure = interpf(optimal, ptb->pressure, influence);
- return true;
+ return true;
}
/**
@@ -1493,39 +1495,39 @@ bool BKE_gpencil_smooth_stroke_thickness(bGPDstroke *gps, int point_index, float
*/
bool BKE_gpencil_smooth_stroke_uv(bGPDstroke *gps, int point_index, float influence)
{
- bGPDspoint *ptb = &gps->points[point_index];
+ bGPDspoint *ptb = &gps->points[point_index];
- /* Do nothing if not enough points */
- if (gps->totpoints <= 2) {
- return false;
- }
+ /* Do nothing if not enough points */
+ if (gps->totpoints <= 2) {
+ return false;
+ }
- /* Compute theoretical optimal value */
- bGPDspoint *pta, *ptc;
- int before = point_index - 1;
- int after = point_index + 1;
+ /* Compute theoretical optimal value */
+ bGPDspoint *pta, *ptc;
+ int before = point_index - 1;
+ int after = point_index + 1;
- CLAMP_MIN(before, 0);
- CLAMP_MAX(after, gps->totpoints - 1);
+ CLAMP_MIN(before, 0);
+ CLAMP_MAX(after, gps->totpoints - 1);
- pta = &gps->points[before];
- ptc = &gps->points[after];
+ pta = &gps->points[before];
+ ptc = &gps->points[after];
- /* the optimal value is the corresponding to the interpolation of the pressure
- * at the distance of point b
- */
- float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
- /* sometimes the factor can be wrong due stroke geometry, so use middle point */
- if ((fac < 0.0f) || (fac > 1.0f)) {
- fac = 0.5f;
- }
- float optimal = interpf(ptc->uv_rot, pta->uv_rot, fac);
+ /* the optimal value is the corresponding to the interpolation of the pressure
+ * at the distance of point b
+ */
+ float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
+ /* sometimes the factor can be wrong due stroke geometry, so use middle point */
+ if ((fac < 0.0f) || (fac > 1.0f)) {
+ fac = 0.5f;
+ }
+ float optimal = interpf(ptc->uv_rot, pta->uv_rot, fac);
- /* Based on influence factor, blend between original and optimal */
- ptb->uv_rot = interpf(optimal, ptb->uv_rot, influence);
- CLAMP(ptb->uv_rot, -M_PI_2, M_PI_2);
+ /* Based on influence factor, blend between original and optimal */
+ ptb->uv_rot = interpf(optimal, ptb->uv_rot, influence);
+ CLAMP(ptb->uv_rot, -M_PI_2, M_PI_2);
- return true;
+ return true;
}
/**
@@ -1538,19 +1540,19 @@ bool BKE_gpencil_smooth_stroke_uv(bGPDstroke *gps, int point_index, float influe
*/
void BKE_gpencil_get_range_selected(bGPDlayer *gpl, int *r_initframe, int *r_endframe)
{
- *r_initframe = gpl->actframe->framenum;
- *r_endframe = gpl->actframe->framenum;
+ *r_initframe = gpl->actframe->framenum;
+ *r_endframe = gpl->actframe->framenum;
- for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- if (gpf->flag & GP_FRAME_SELECT) {
- if (gpf->framenum < *r_initframe) {
- *r_initframe = gpf->framenum;
- }
- if (gpf->framenum > *r_endframe) {
- *r_endframe = gpf->framenum;
- }
- }
- }
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ if (gpf->flag & GP_FRAME_SELECT) {
+ if (gpf->framenum < *r_initframe) {
+ *r_initframe = gpf->framenum;
+ }
+ if (gpf->framenum > *r_endframe) {
+ *r_endframe = gpf->framenum;
+ }
+ }
+ }
}
/**
@@ -1561,261 +1563,270 @@ void BKE_gpencil_get_range_selected(bGPDlayer *gpl, int *r_initframe, int *r_end
* \param f_end: Number of last selected frame
* \param cur_falloff: Curve with falloff factors
*/
-float BKE_gpencil_multiframe_falloff_calc(bGPDframe *gpf, int actnum, int f_init, int f_end, CurveMapping *cur_falloff)
-{
- float fnum = 0.5f; /* default mid curve */
- float value;
-
- /* check curve is available */
- if (cur_falloff == NULL) {
- return 1.0f;
- }
-
- /* frames to the right of the active frame */
- if (gpf->framenum < actnum) {
- fnum = (float)(gpf->framenum - f_init) / (actnum - f_init);
- fnum *= 0.5f;
- value = curvemapping_evaluateF(cur_falloff, 0, fnum);
- }
- /* frames to the left of the active frame */
- else if (gpf->framenum > actnum) {
- fnum = (float)(gpf->framenum - actnum) / (f_end - actnum);
- fnum *= 0.5f;
- value = curvemapping_evaluateF(cur_falloff, 0, fnum + 0.5f);
- }
- else {
- value = 1.0f;
- }
-
- return value;
+float BKE_gpencil_multiframe_falloff_calc(
+ bGPDframe *gpf, int actnum, int f_init, int f_end, CurveMapping *cur_falloff)
+{
+ float fnum = 0.5f; /* default mid curve */
+ float value;
+
+ /* check curve is available */
+ if (cur_falloff == NULL) {
+ return 1.0f;
+ }
+
+ /* frames to the right of the active frame */
+ if (gpf->framenum < actnum) {
+ fnum = (float)(gpf->framenum - f_init) / (actnum - f_init);
+ fnum *= 0.5f;
+ value = curvemapping_evaluateF(cur_falloff, 0, fnum);
+ }
+ /* frames to the left of the active frame */
+ else if (gpf->framenum > actnum) {
+ fnum = (float)(gpf->framenum - actnum) / (f_end - actnum);
+ fnum *= 0.5f;
+ value = curvemapping_evaluateF(cur_falloff, 0, fnum + 0.5f);
+ }
+ else {
+ value = 1.0f;
+ }
+
+ return value;
}
/* remove strokes using a material */
void BKE_gpencil_material_index_remove(bGPdata *gpd, int index)
{
- bGPDstroke *gps, *gpsn;
-
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- for (gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
- if (gps->mat_nr == index) {
- if (gps->points) {
- MEM_freeN(gps->points);
- }
- if (gps->dvert) {
- BKE_gpencil_free_stroke_weights(gps);
- MEM_freeN(gps->dvert);
- }
- if (gps->triangles) MEM_freeN(gps->triangles);
- BLI_freelinkN(&gpf->strokes, gps);
- }
- else {
- /* reassign strokes */
- if (gps->mat_nr > index) {
- gps->mat_nr--;
- }
- }
- }
- }
- }
-}
-
-void BKE_gpencil_material_remap(struct bGPdata *gpd, const unsigned int *remap, unsigned int remap_len)
-{
- const short remap_len_short = (short)remap_len;
+ bGPDstroke *gps, *gpsn;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+ if (gps->mat_nr == index) {
+ if (gps->points) {
+ MEM_freeN(gps->points);
+ }
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
+ if (gps->triangles)
+ MEM_freeN(gps->triangles);
+ BLI_freelinkN(&gpf->strokes, gps);
+ }
+ else {
+ /* reassign strokes */
+ if (gps->mat_nr > index) {
+ gps->mat_nr--;
+ }
+ }
+ }
+ }
+ }
+}
+
+void BKE_gpencil_material_remap(struct bGPdata *gpd,
+ const unsigned int *remap,
+ unsigned int remap_len)
+{
+ const short remap_len_short = (short)remap_len;
#define MAT_NR_REMAP(n) \
- if (n < remap_len_short) { \
- BLI_assert(n >= 0 && remap[n] < remap_len_short); \
- n = remap[n]; \
- } ((void)0)
-
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- /* reassign strokes */
- MAT_NR_REMAP(gps->mat_nr);
- }
- }
- }
+ if (n < remap_len_short) { \
+ BLI_assert(n >= 0 && remap[n] < remap_len_short); \
+ n = remap[n]; \
+ } \
+ ((void)0)
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* reassign strokes */
+ MAT_NR_REMAP(gps->mat_nr);
+ }
+ }
+ }
#undef MAT_NR_REMAP
-
}
/* statistics functions */
void BKE_gpencil_stats_update(bGPdata *gpd)
{
- gpd->totlayer = 0;
- gpd->totframe = 0;
- gpd->totstroke = 0;
- gpd->totpoint = 0;
-
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- gpd->totlayer++;
- for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- gpd->totframe++;
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- gpd->totstroke++;
- gpd->totpoint += gps->totpoints;
- }
- }
- }
+ gpd->totlayer = 0;
+ gpd->totframe = 0;
+ gpd->totstroke = 0;
+ gpd->totpoint = 0;
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ gpd->totlayer++;
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ gpd->totframe++;
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ gpd->totstroke++;
+ gpd->totpoint += gps->totpoints;
+ }
+ }
+ }
}
/* get material index (0-based like mat_nr not actcol) */
int BKE_gpencil_object_material_get_index(Object *ob, Material *ma)
{
- short *totcol = give_totcolp(ob);
- Material *read_ma = NULL;
- for (short i = 0; i < *totcol; i++) {
- read_ma = give_current_material(ob, i + 1);
- if (ma == read_ma) {
- return i;
- }
- }
+ short *totcol = give_totcolp(ob);
+ Material *read_ma = NULL;
+ for (short i = 0; i < *totcol; i++) {
+ read_ma = give_current_material(ob, i + 1);
+ if (ma == read_ma) {
+ return i;
+ }
+ }
- return -1;
+ return -1;
}
/* Get points of stroke always flat to view not affected by camera view or view position */
-void BKE_gpencil_stroke_2d_flat(const bGPDspoint *points, int totpoints, float(*points2d)[2], int *r_direction)
+void BKE_gpencil_stroke_2d_flat(const bGPDspoint *points,
+ int totpoints,
+ float (*points2d)[2],
+ int *r_direction)
{
- BLI_assert(totpoints >= 2);
+ BLI_assert(totpoints >= 2);
- const bGPDspoint *pt0 = &points[0];
- const bGPDspoint *pt1 = &points[1];
- const bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)];
+ const bGPDspoint *pt0 = &points[0];
+ const bGPDspoint *pt1 = &points[1];
+ const bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)];
- float locx[3];
- float locy[3];
- float loc3[3];
- float normal[3];
+ float locx[3];
+ float locy[3];
+ float loc3[3];
+ float normal[3];
- /* local X axis (p0 -> p1) */
- sub_v3_v3v3(locx, &pt1->x, &pt0->x);
+ /* local X axis (p0 -> p1) */
+ sub_v3_v3v3(locx, &pt1->x, &pt0->x);
- /* point vector at 3/4 */
- float v3[3];
- if (totpoints == 2) {
- mul_v3_v3fl(v3, &pt3->x, 0.001f);
- }
- else {
- copy_v3_v3(v3, &pt3->x);
- }
+ /* point vector at 3/4 */
+ float v3[3];
+ if (totpoints == 2) {
+ mul_v3_v3fl(v3, &pt3->x, 0.001f);
+ }
+ else {
+ copy_v3_v3(v3, &pt3->x);
+ }
- sub_v3_v3v3(loc3, v3, &pt0->x);
+ sub_v3_v3v3(loc3, v3, &pt0->x);
- /* vector orthogonal to polygon plane */
- cross_v3_v3v3(normal, locx, loc3);
+ /* vector orthogonal to polygon plane */
+ cross_v3_v3v3(normal, locx, loc3);
- /* local Y axis (cross to normal/x axis) */
- cross_v3_v3v3(locy, normal, locx);
+ /* local Y axis (cross to normal/x axis) */
+ cross_v3_v3v3(locy, normal, locx);
- /* Normalize vectors */
- normalize_v3(locx);
- normalize_v3(locy);
+ /* Normalize vectors */
+ normalize_v3(locx);
+ normalize_v3(locy);
- /* Get all points in local space */
- for (int i = 0; i < totpoints; i++) {
- const bGPDspoint *pt = &points[i];
- float loc[3];
+ /* Get all points in local space */
+ for (int i = 0; i < totpoints; i++) {
+ const bGPDspoint *pt = &points[i];
+ float loc[3];
- /* Get local space using first point as origin */
- sub_v3_v3v3(loc, &pt->x, &pt0->x);
+ /* Get local space using first point as origin */
+ sub_v3_v3v3(loc, &pt->x, &pt0->x);
- points2d[i][0] = dot_v3v3(loc, locx);
- points2d[i][1] = dot_v3v3(loc, locy);
- }
+ points2d[i][0] = dot_v3v3(loc, locx);
+ points2d[i][1] = dot_v3v3(loc, locy);
+ }
- /* Concave (-1), Convex (1), or Autodetect (0)? */
- *r_direction = (int)locy[2];
+ /* Concave (-1), Convex (1), or Autodetect (0)? */
+ *r_direction = (int)locy[2];
}
/* Get points of stroke always flat to view not affected by camera view or view position
* using another stroke as reference
*/
-void BKE_gpencil_stroke_2d_flat_ref(
- const bGPDspoint *ref_points, int ref_totpoints,
- const bGPDspoint *points, int totpoints,
- float(*points2d)[2], const float scale, int *r_direction)
-{
- BLI_assert(totpoints >= 2);
-
- const bGPDspoint *pt0 = &ref_points[0];
- const bGPDspoint *pt1 = &ref_points[1];
- const bGPDspoint *pt3 = &ref_points[(int)(ref_totpoints * 0.75)];
-
- float locx[3];
- float locy[3];
- float loc3[3];
- float normal[3];
-
- /* local X axis (p0 -> p1) */
- sub_v3_v3v3(locx, &pt1->x, &pt0->x);
-
- /* point vector at 3/4 */
- float v3[3];
- if (totpoints == 2) {
- mul_v3_v3fl(v3, &pt3->x, 0.001f);
- }
- else {
- copy_v3_v3(v3, &pt3->x);
- }
-
- sub_v3_v3v3(loc3, v3, &pt0->x);
-
- /* vector orthogonal to polygon plane */
- cross_v3_v3v3(normal, locx, loc3);
-
- /* local Y axis (cross to normal/x axis) */
- cross_v3_v3v3(locy, normal, locx);
-
- /* Normalize vectors */
- normalize_v3(locx);
- normalize_v3(locy);
-
- /* Get all points in local space */
- for (int i = 0; i < totpoints; i++) {
- const bGPDspoint *pt = &points[i];
- float loc[3];
- float v1[3];
- float vn[3] = { 0.0f, 0.0f, 0.0f };
-
- /* apply scale to extremes of the stroke to get better collision detection
- * the scale is divided to get more control in the UI parameter
- */
- /* first point */
- if (i == 0) {
- const bGPDspoint *pt_next = &points[i + 1];
- sub_v3_v3v3(vn, &pt->x, &pt_next->x);
- normalize_v3(vn);
- mul_v3_fl(vn, scale / 10.0f);
- add_v3_v3v3(v1, &pt->x, vn);
- }
- /* last point */
- else if (i == totpoints - 1) {
- const bGPDspoint *pt_prev = &points[i - 1];
- sub_v3_v3v3(vn, &pt->x, &pt_prev->x);
- normalize_v3(vn);
- mul_v3_fl(vn, scale / 10.0f);
- add_v3_v3v3(v1, &pt->x, vn);
- }
- else {
- copy_v3_v3(v1, &pt->x);
- }
-
- /* Get local space using first point as origin (ref stroke) */
- sub_v3_v3v3(loc, v1, &pt0->x);
-
- points2d[i][0] = dot_v3v3(loc, locx);
- points2d[i][1] = dot_v3v3(loc, locy);
- }
-
- /* Concave (-1), Convex (1), or Autodetect (0)? */
- *r_direction = (int)locy[2];
+void BKE_gpencil_stroke_2d_flat_ref(const bGPDspoint *ref_points,
+ int ref_totpoints,
+ const bGPDspoint *points,
+ int totpoints,
+ float (*points2d)[2],
+ const float scale,
+ int *r_direction)
+{
+ BLI_assert(totpoints >= 2);
+
+ const bGPDspoint *pt0 = &ref_points[0];
+ const bGPDspoint *pt1 = &ref_points[1];
+ const bGPDspoint *pt3 = &ref_points[(int)(ref_totpoints * 0.75)];
+
+ float locx[3];
+ float locy[3];
+ float loc3[3];
+ float normal[3];
+
+ /* local X axis (p0 -> p1) */
+ sub_v3_v3v3(locx, &pt1->x, &pt0->x);
+
+ /* point vector at 3/4 */
+ float v3[3];
+ if (totpoints == 2) {
+ mul_v3_v3fl(v3, &pt3->x, 0.001f);
+ }
+ else {
+ copy_v3_v3(v3, &pt3->x);
+ }
+
+ sub_v3_v3v3(loc3, v3, &pt0->x);
+
+ /* vector orthogonal to polygon plane */
+ cross_v3_v3v3(normal, locx, loc3);
+
+ /* local Y axis (cross to normal/x axis) */
+ cross_v3_v3v3(locy, normal, locx);
+
+ /* Normalize vectors */
+ normalize_v3(locx);
+ normalize_v3(locy);
+
+ /* Get all points in local space */
+ for (int i = 0; i < totpoints; i++) {
+ const bGPDspoint *pt = &points[i];
+ float loc[3];
+ float v1[3];
+ float vn[3] = {0.0f, 0.0f, 0.0f};
+
+ /* apply scale to extremes of the stroke to get better collision detection
+ * the scale is divided to get more control in the UI parameter
+ */
+ /* first point */
+ if (i == 0) {
+ const bGPDspoint *pt_next = &points[i + 1];
+ sub_v3_v3v3(vn, &pt->x, &pt_next->x);
+ normalize_v3(vn);
+ mul_v3_fl(vn, scale / 10.0f);
+ add_v3_v3v3(v1, &pt->x, vn);
+ }
+ /* last point */
+ else if (i == totpoints - 1) {
+ const bGPDspoint *pt_prev = &points[i - 1];
+ sub_v3_v3v3(vn, &pt->x, &pt_prev->x);
+ normalize_v3(vn);
+ mul_v3_fl(vn, scale / 10.0f);
+ add_v3_v3v3(v1, &pt->x, vn);
+ }
+ else {
+ copy_v3_v3(v1, &pt->x);
+ }
+
+ /* Get local space using first point as origin (ref stroke) */
+ sub_v3_v3v3(loc, v1, &pt0->x);
+
+ points2d[i][0] = dot_v3v3(loc, locx);
+ points2d[i][1] = dot_v3v3(loc, locy);
+ }
+
+ /* Concave (-1), Convex (1), or Autodetect (0)? */
+ *r_direction = (int)locy[2];
}
/**
@@ -1824,91 +1835,91 @@ void BKE_gpencil_stroke_2d_flat_ref(
*/
bool BKE_gpencil_trim_stroke(bGPDstroke *gps)
{
- if (gps->totpoints < 4) {
- return false;
- }
- bool intersect = false;
- int start, end;
- float point[3];
- /* loop segments from start until we have an intersection */
- for (int i = 0; i < gps->totpoints - 2; i++) {
- start = i;
- bGPDspoint *a = &gps->points[start];
- bGPDspoint *b = &gps->points[start + 1];
- for (int j = start + 2; j < gps->totpoints - 1; j++) {
- end = j + 1;
- bGPDspoint *c = &gps->points[j];
- bGPDspoint *d = &gps->points[end];
- float pointb[3];
- /* get intersection */
- if (isect_line_line_v3(&a->x, &b->x, &c->x, &d->x, point, pointb)) {
- if (len_v3(point) > 0.0f) {
- float closest[3];
- /* check intersection is on both lines */
- float lambda = closest_to_line_v3(closest, point, &a->x, &b->x);
- if ((lambda <= 0.0f) || (lambda >= 1.0f)) {
- continue;
- }
- lambda = closest_to_line_v3(closest, point, &c->x, &d->x);
- if ((lambda <= 0.0f) || (lambda >= 1.0f)) {
- continue;
- }
- else {
- intersect = true;
- break;
- }
- }
- }
- }
- if (intersect) {
- break;
- }
- }
-
- /* trim unwanted points */
- if (intersect) {
-
- /* save points */
- bGPDspoint *old_points = MEM_dupallocN(gps->points);
- MDeformVert *old_dvert = NULL;
- MDeformVert *dvert_src = NULL;
-
- if (gps->dvert != NULL) {
- old_dvert = MEM_dupallocN(gps->dvert);
- }
-
- /* resize gps */
- int newtot = end - start + 1;
-
- gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * newtot);
- if (gps->dvert != NULL) {
- gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * newtot);
- }
-
- for (int i = 0; i < newtot; i++) {
- int idx = start + i;
- bGPDspoint *pt_src = &old_points[idx];
- bGPDspoint *pt_new = &gps->points[i];
- memcpy(pt_new, pt_src, sizeof(bGPDspoint));
- if (gps->dvert != NULL) {
- dvert_src = &old_dvert[idx];
- MDeformVert *dvert = &gps->dvert[i];
- memcpy(dvert, dvert_src, sizeof(MDeformVert));
- if (dvert_src->dw) {
- memcpy(dvert->dw, dvert_src->dw, sizeof(MDeformWeight));
- }
- }
- if (idx == start || idx == end) {
- copy_v3_v3(&pt_new->x, point);
- }
- }
-
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
- gps->tot_triangles = 0;
- gps->totpoints = newtot;
-
- MEM_SAFE_FREE(old_points);
- MEM_SAFE_FREE(old_dvert);
- }
- return intersect;
+ if (gps->totpoints < 4) {
+ return false;
+ }
+ bool intersect = false;
+ int start, end;
+ float point[3];
+ /* loop segments from start until we have an intersection */
+ for (int i = 0; i < gps->totpoints - 2; i++) {
+ start = i;
+ bGPDspoint *a = &gps->points[start];
+ bGPDspoint *b = &gps->points[start + 1];
+ for (int j = start + 2; j < gps->totpoints - 1; j++) {
+ end = j + 1;
+ bGPDspoint *c = &gps->points[j];
+ bGPDspoint *d = &gps->points[end];
+ float pointb[3];
+ /* get intersection */
+ if (isect_line_line_v3(&a->x, &b->x, &c->x, &d->x, point, pointb)) {
+ if (len_v3(point) > 0.0f) {
+ float closest[3];
+ /* check intersection is on both lines */
+ float lambda = closest_to_line_v3(closest, point, &a->x, &b->x);
+ if ((lambda <= 0.0f) || (lambda >= 1.0f)) {
+ continue;
+ }
+ lambda = closest_to_line_v3(closest, point, &c->x, &d->x);
+ if ((lambda <= 0.0f) || (lambda >= 1.0f)) {
+ continue;
+ }
+ else {
+ intersect = true;
+ break;
+ }
+ }
+ }
+ }
+ if (intersect) {
+ break;
+ }
+ }
+
+ /* trim unwanted points */
+ if (intersect) {
+
+ /* save points */
+ bGPDspoint *old_points = MEM_dupallocN(gps->points);
+ MDeformVert *old_dvert = NULL;
+ MDeformVert *dvert_src = NULL;
+
+ if (gps->dvert != NULL) {
+ old_dvert = MEM_dupallocN(gps->dvert);
+ }
+
+ /* resize gps */
+ int newtot = end - start + 1;
+
+ gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * newtot);
+ if (gps->dvert != NULL) {
+ gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * newtot);
+ }
+
+ for (int i = 0; i < newtot; i++) {
+ int idx = start + i;
+ bGPDspoint *pt_src = &old_points[idx];
+ bGPDspoint *pt_new = &gps->points[i];
+ memcpy(pt_new, pt_src, sizeof(bGPDspoint));
+ if (gps->dvert != NULL) {
+ dvert_src = &old_dvert[idx];
+ MDeformVert *dvert = &gps->dvert[i];
+ memcpy(dvert, dvert_src, sizeof(MDeformVert));
+ if (dvert_src->dw) {
+ memcpy(dvert->dw, dvert_src->dw, sizeof(MDeformWeight));
+ }
+ }
+ if (idx == start || idx == end) {
+ copy_v3_v3(&pt_new->x, point);
+ }
+ }
+
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+ gps->tot_triangles = 0;
+ gps->totpoints = newtot;
+
+ MEM_SAFE_FREE(old_points);
+ MEM_SAFE_FREE(old_dvert);
+ }
+ return intersect;
}
diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c
index 30bf30e2842..63f6fc6307b 100644
--- a/source/blender/blenkernel/intern/gpencil_modifier.c
+++ b/source/blender/blenkernel/intern/gpencil_modifier.c
@@ -50,7 +50,7 @@
#include "MOD_gpencil_modifiertypes.h"
-static GpencilModifierTypeInfo *modifier_gpencil_types[NUM_GREASEPENCIL_MODIFIER_TYPES] = { NULL };
+static GpencilModifierTypeInfo *modifier_gpencil_types[NUM_GREASEPENCIL_MODIFIER_TYPES] = {NULL};
/* *************************************************** */
/* Geometry Utilities */
@@ -58,75 +58,74 @@ static GpencilModifierTypeInfo *modifier_gpencil_types[NUM_GREASEPENCIL_MODIFIER
/* calculate stroke normal using some points */
void BKE_gpencil_stroke_normal(const bGPDstroke *gps, float r_normal[3])
{
- if (gps->totpoints < 3) {
- zero_v3(r_normal);
- return;
- }
+ if (gps->totpoints < 3) {
+ zero_v3(r_normal);
+ return;
+ }
- bGPDspoint *points = gps->points;
- int totpoints = gps->totpoints;
+ bGPDspoint *points = gps->points;
+ int totpoints = gps->totpoints;
- const bGPDspoint *pt0 = &points[0];
- const bGPDspoint *pt1 = &points[1];
- const bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)];
+ const bGPDspoint *pt0 = &points[0];
+ const bGPDspoint *pt1 = &points[1];
+ const bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)];
- float vec1[3];
- float vec2[3];
+ float vec1[3];
+ float vec2[3];
- /* initial vector (p0 -> p1) */
- sub_v3_v3v3(vec1, &pt1->x, &pt0->x);
+ /* initial vector (p0 -> p1) */
+ sub_v3_v3v3(vec1, &pt1->x, &pt0->x);
- /* point vector at 3/4 */
- sub_v3_v3v3(vec2, &pt3->x, &pt0->x);
+ /* point vector at 3/4 */
+ sub_v3_v3v3(vec2, &pt3->x, &pt0->x);
- /* vector orthogonal to polygon plane */
- cross_v3_v3v3(r_normal, vec1, vec2);
+ /* vector orthogonal to polygon plane */
+ cross_v3_v3v3(r_normal, vec1, vec2);
- /* Normalize vector */
- normalize_v3(r_normal);
+ /* Normalize vector */
+ normalize_v3(r_normal);
}
/* Get points of stroke always flat to view not affected by camera view or view position */
static void gpencil_stroke_project_2d(const bGPDspoint *points, int totpoints, vec2f *points2d)
{
- const bGPDspoint *pt0 = &points[0];
- const bGPDspoint *pt1 = &points[1];
- const bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)];
+ const bGPDspoint *pt0 = &points[0];
+ const bGPDspoint *pt1 = &points[1];
+ const bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)];
- float locx[3];
- float locy[3];
- float loc3[3];
- float normal[3];
+ float locx[3];
+ float locy[3];
+ float loc3[3];
+ float normal[3];
- /* local X axis (p0 -> p1) */
- sub_v3_v3v3(locx, &pt1->x, &pt0->x);
+ /* local X axis (p0 -> p1) */
+ sub_v3_v3v3(locx, &pt1->x, &pt0->x);
- /* point vector at 3/4 */
- sub_v3_v3v3(loc3, &pt3->x, &pt0->x);
+ /* point vector at 3/4 */
+ sub_v3_v3v3(loc3, &pt3->x, &pt0->x);
- /* vector orthogonal to polygon plane */
- cross_v3_v3v3(normal, locx, loc3);
+ /* vector orthogonal to polygon plane */
+ cross_v3_v3v3(normal, locx, loc3);
- /* local Y axis (cross to normal/x axis) */
- cross_v3_v3v3(locy, normal, locx);
+ /* local Y axis (cross to normal/x axis) */
+ cross_v3_v3v3(locy, normal, locx);
- /* Normalize vectors */
- normalize_v3(locx);
- normalize_v3(locy);
+ /* Normalize vectors */
+ normalize_v3(locx);
+ normalize_v3(locy);
- /* Get all points in local space */
- for (int i = 0; i < totpoints; i++) {
- const bGPDspoint *pt = &points[i];
- float loc[3];
+ /* Get all points in local space */
+ for (int i = 0; i < totpoints; i++) {
+ const bGPDspoint *pt = &points[i];
+ float loc[3];
- /* Get local space using first point as origin */
- sub_v3_v3v3(loc, &pt->x, &pt0->x);
-
- vec2f *point = &points2d[i];
- point->x = dot_v3v3(loc, locx);
- point->y = dot_v3v3(loc, locy);
- }
+ /* Get local space using first point as origin */
+ sub_v3_v3v3(loc, &pt->x, &pt0->x);
+ vec2f *point = &points2d[i];
+ point->x = dot_v3v3(loc, locx);
+ point->y = dot_v3v3(loc, locy);
+ }
}
/* Stroke Simplify ------------------------------------- */
@@ -139,194 +138,193 @@ static void gpencil_stroke_project_2d(const bGPDspoint *points, int totpoints, v
*/
static void gpencil_rdp_stroke(bGPDstroke *gps, vec2f *points2d, float epsilon)
{
- vec2f *old_points2d = points2d;
- int totpoints = gps->totpoints;
- char *marked = NULL;
- char work;
-
- int start = 1;
- int end = gps->totpoints - 2;
-
- marked = MEM_callocN(totpoints, "GP marked array");
- marked[start] = 1;
- marked[end] = 1;
-
- work = 1;
- int totmarked = 0;
- /* while still reducing */
- while (work) {
- int ls, le;
- work = 0;
-
- ls = start;
- le = start + 1;
-
- /* while not over interval */
- while (ls < end) {
- int max_i = 0;
- float v1[2];
- /* divided to get more control */
- float max_dist = epsilon / 10.0f;
-
- /* find the next marked point */
- while (marked[le] == 0) {
- le++;
- }
-
- /* perpendicular vector to ls-le */
- v1[1] = old_points2d[le].x - old_points2d[ls].x;
- v1[0] = old_points2d[ls].y - old_points2d[le].y;
-
- for (int i = ls + 1; i < le; i++) {
- float mul;
- float dist;
- float v2[2];
-
- v2[0] = old_points2d[i].x - old_points2d[ls].x;
- v2[1] = old_points2d[i].y - old_points2d[ls].y;
-
- if (v2[0] == 0 && v2[1] == 0) {
- continue;
- }
-
- mul = (float)(v1[0] * v2[0] + v1[1] * v2[1]) / (float)(v2[0] * v2[0] + v2[1] * v2[1]);
-
- dist = mul * mul * (v2[0] * v2[0] + v2[1] * v2[1]);
-
- if (dist > max_dist) {
- max_dist = dist;
- max_i = i;
- }
- }
-
- if (max_i != 0) {
- work = 1;
- marked[max_i] = 1;
- totmarked++;
- }
-
- ls = le;
- le = ls + 1;
- }
- }
-
- /* adding points marked */
- bGPDspoint *old_points = MEM_dupallocN(gps->points);
- MDeformVert *old_dvert = NULL;
- MDeformVert *dvert_src = NULL;
-
- if (gps->dvert != NULL) {
- old_dvert = MEM_dupallocN(gps->dvert);
- }
- /* resize gps */
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
- gps->tot_triangles = 0;
-
- int j = 0;
- for (int i = 0; i < totpoints; i++) {
- bGPDspoint *pt_src = &old_points[i];
- bGPDspoint *pt = &gps->points[j];
-
- if ((marked[i]) || (i == 0) || (i == totpoints - 1)) {
- memcpy(pt, pt_src, sizeof(bGPDspoint));
- if (gps->dvert != NULL) {
- dvert_src = &old_dvert[i];
- MDeformVert *dvert = &gps->dvert[j];
- memcpy(dvert, dvert_src, sizeof(MDeformVert));
- if (dvert_src->dw) {
- memcpy(dvert->dw, dvert_src->dw, sizeof(MDeformWeight));
- }
- }
- j++;
- }
- else {
- if (gps->dvert != NULL) {
- dvert_src = &old_dvert[i];
- BKE_gpencil_free_point_weights(dvert_src);
- }
- }
- }
-
- gps->totpoints = j;
-
- MEM_SAFE_FREE(old_points);
- MEM_SAFE_FREE(old_dvert);
- MEM_SAFE_FREE(marked);
+ vec2f *old_points2d = points2d;
+ int totpoints = gps->totpoints;
+ char *marked = NULL;
+ char work;
+
+ int start = 1;
+ int end = gps->totpoints - 2;
+
+ marked = MEM_callocN(totpoints, "GP marked array");
+ marked[start] = 1;
+ marked[end] = 1;
+
+ work = 1;
+ int totmarked = 0;
+ /* while still reducing */
+ while (work) {
+ int ls, le;
+ work = 0;
+
+ ls = start;
+ le = start + 1;
+
+ /* while not over interval */
+ while (ls < end) {
+ int max_i = 0;
+ float v1[2];
+ /* divided to get more control */
+ float max_dist = epsilon / 10.0f;
+
+ /* find the next marked point */
+ while (marked[le] == 0) {
+ le++;
+ }
+
+ /* perpendicular vector to ls-le */
+ v1[1] = old_points2d[le].x - old_points2d[ls].x;
+ v1[0] = old_points2d[ls].y - old_points2d[le].y;
+
+ for (int i = ls + 1; i < le; i++) {
+ float mul;
+ float dist;
+ float v2[2];
+
+ v2[0] = old_points2d[i].x - old_points2d[ls].x;
+ v2[1] = old_points2d[i].y - old_points2d[ls].y;
+
+ if (v2[0] == 0 && v2[1] == 0) {
+ continue;
+ }
+
+ mul = (float)(v1[0] * v2[0] + v1[1] * v2[1]) / (float)(v2[0] * v2[0] + v2[1] * v2[1]);
+
+ dist = mul * mul * (v2[0] * v2[0] + v2[1] * v2[1]);
+
+ if (dist > max_dist) {
+ max_dist = dist;
+ max_i = i;
+ }
+ }
+
+ if (max_i != 0) {
+ work = 1;
+ marked[max_i] = 1;
+ totmarked++;
+ }
+
+ ls = le;
+ le = ls + 1;
+ }
+ }
+
+ /* adding points marked */
+ bGPDspoint *old_points = MEM_dupallocN(gps->points);
+ MDeformVert *old_dvert = NULL;
+ MDeformVert *dvert_src = NULL;
+
+ if (gps->dvert != NULL) {
+ old_dvert = MEM_dupallocN(gps->dvert);
+ }
+ /* resize gps */
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+ gps->tot_triangles = 0;
+
+ int j = 0;
+ for (int i = 0; i < totpoints; i++) {
+ bGPDspoint *pt_src = &old_points[i];
+ bGPDspoint *pt = &gps->points[j];
+
+ if ((marked[i]) || (i == 0) || (i == totpoints - 1)) {
+ memcpy(pt, pt_src, sizeof(bGPDspoint));
+ if (gps->dvert != NULL) {
+ dvert_src = &old_dvert[i];
+ MDeformVert *dvert = &gps->dvert[j];
+ memcpy(dvert, dvert_src, sizeof(MDeformVert));
+ if (dvert_src->dw) {
+ memcpy(dvert->dw, dvert_src->dw, sizeof(MDeformWeight));
+ }
+ }
+ j++;
+ }
+ else {
+ if (gps->dvert != NULL) {
+ dvert_src = &old_dvert[i];
+ BKE_gpencil_free_point_weights(dvert_src);
+ }
+ }
+ }
+
+ gps->totpoints = j;
+
+ MEM_SAFE_FREE(old_points);
+ MEM_SAFE_FREE(old_dvert);
+ MEM_SAFE_FREE(marked);
}
/* Simplify stroke using Ramer-Douglas-Peucker algorithm */
void BKE_gpencil_simplify_stroke(bGPDstroke *gps, float factor)
{
- /* first create temp data and convert points to 2D */
- vec2f *points2d = MEM_mallocN(sizeof(vec2f) * gps->totpoints, "GP Stroke temp 2d points");
+ /* first create temp data and convert points to 2D */
+ vec2f *points2d = MEM_mallocN(sizeof(vec2f) * gps->totpoints, "GP Stroke temp 2d points");
- gpencil_stroke_project_2d(gps->points, gps->totpoints, points2d);
+ gpencil_stroke_project_2d(gps->points, gps->totpoints, points2d);
- gpencil_rdp_stroke(gps, points2d, factor);
+ gpencil_rdp_stroke(gps, points2d, factor);
- MEM_SAFE_FREE(points2d);
+ MEM_SAFE_FREE(points2d);
}
/* Simplify alternate vertex of stroke except extremes */
void BKE_gpencil_simplify_fixed(bGPDstroke *gps)
{
- if (gps->totpoints < 5) {
- return;
- }
-
- /* save points */
- bGPDspoint *old_points = MEM_dupallocN(gps->points);
- MDeformVert *old_dvert = NULL;
- MDeformVert *dvert_src = NULL;
-
- if (gps->dvert != NULL) {
- old_dvert = MEM_dupallocN(gps->dvert);
- }
-
- /* resize gps */
- int newtot = (gps->totpoints - 2) / 2;
- if (((gps->totpoints - 2) % 2) > 0) {
- newtot++;
- }
- newtot += 2;
-
- gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * newtot);
- if (gps->dvert != NULL) {
- gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * newtot);
- }
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
- gps->tot_triangles = 0;
-
- int j = 0;
- for (int i = 0; i < gps->totpoints; i++) {
- bGPDspoint *pt_src = &old_points[i];
- bGPDspoint *pt = &gps->points[j];
-
-
- if ((i == 0) || (i == gps->totpoints - 1) || ((i % 2) > 0.0)) {
- memcpy(pt, pt_src, sizeof(bGPDspoint));
- if (gps->dvert != NULL) {
- dvert_src = &old_dvert[i];
- MDeformVert *dvert = &gps->dvert[j];
- memcpy(dvert, dvert_src, sizeof(MDeformVert));
- if (dvert_src->dw) {
- memcpy(dvert->dw, dvert_src->dw, sizeof(MDeformWeight));
- }
- }
- j++;
- }
- else {
- if (gps->dvert != NULL) {
- dvert_src = &old_dvert[i];
- BKE_gpencil_free_point_weights(dvert_src);
- }
- }
- }
-
- gps->totpoints = j;
-
- MEM_SAFE_FREE(old_points);
- MEM_SAFE_FREE(old_dvert);
+ if (gps->totpoints < 5) {
+ return;
+ }
+
+ /* save points */
+ bGPDspoint *old_points = MEM_dupallocN(gps->points);
+ MDeformVert *old_dvert = NULL;
+ MDeformVert *dvert_src = NULL;
+
+ if (gps->dvert != NULL) {
+ old_dvert = MEM_dupallocN(gps->dvert);
+ }
+
+ /* resize gps */
+ int newtot = (gps->totpoints - 2) / 2;
+ if (((gps->totpoints - 2) % 2) > 0) {
+ newtot++;
+ }
+ newtot += 2;
+
+ gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * newtot);
+ if (gps->dvert != NULL) {
+ gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * newtot);
+ }
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+ gps->tot_triangles = 0;
+
+ int j = 0;
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt_src = &old_points[i];
+ bGPDspoint *pt = &gps->points[j];
+
+ if ((i == 0) || (i == gps->totpoints - 1) || ((i % 2) > 0.0)) {
+ memcpy(pt, pt_src, sizeof(bGPDspoint));
+ if (gps->dvert != NULL) {
+ dvert_src = &old_dvert[i];
+ MDeformVert *dvert = &gps->dvert[j];
+ memcpy(dvert, dvert_src, sizeof(MDeformVert));
+ if (dvert_src->dw) {
+ memcpy(dvert->dw, dvert_src->dw, sizeof(MDeformWeight));
+ }
+ }
+ j++;
+ }
+ else {
+ if (gps->dvert != NULL) {
+ dvert_src = &old_dvert[i];
+ BKE_gpencil_free_point_weights(dvert_src);
+ }
+ }
+ }
+
+ gps->totpoints = j;
+
+ MEM_SAFE_FREE(old_points);
+ MEM_SAFE_FREE(old_dvert);
}
/* *************************************************** */
@@ -339,42 +337,42 @@ void BKE_gpencil_simplify_fixed(bGPDstroke *gps)
* each loop over all the geometry being evaluated.
*/
- /* init lattice deform data */
+/* init lattice deform data */
void BKE_gpencil_lattice_init(Object *ob)
{
- GpencilModifierData *md;
- for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
- if (md->type == eGpencilModifierType_Lattice) {
- LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
- Object *latob = NULL;
-
- latob = mmd->object;
- if ((!latob) || (latob->type != OB_LATTICE)) {
- return;
- }
- if (mmd->cache_data) {
- end_latt_deform((struct LatticeDeformData *)mmd->cache_data);
- }
-
- /* init deform data */
- mmd->cache_data = (struct LatticeDeformData *)init_latt_deform(latob, ob);
- }
- }
+ GpencilModifierData *md;
+ for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ if (md->type == eGpencilModifierType_Lattice) {
+ LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
+ Object *latob = NULL;
+
+ latob = mmd->object;
+ if ((!latob) || (latob->type != OB_LATTICE)) {
+ return;
+ }
+ if (mmd->cache_data) {
+ end_latt_deform((struct LatticeDeformData *)mmd->cache_data);
+ }
+
+ /* init deform data */
+ mmd->cache_data = (struct LatticeDeformData *)init_latt_deform(latob, ob);
+ }
+ }
}
/* clear lattice deform data */
void BKE_gpencil_lattice_clear(Object *ob)
{
- GpencilModifierData *md;
- for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
- if (md->type == eGpencilModifierType_Lattice) {
- LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
- if ((mmd) && (mmd->cache_data)) {
- end_latt_deform((struct LatticeDeformData *)mmd->cache_data);
- mmd->cache_data = NULL;
- }
- }
- }
+ GpencilModifierData *md;
+ for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ if (md->type == eGpencilModifierType_Lattice) {
+ LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
+ if ((mmd) && (mmd->cache_data)) {
+ end_latt_deform((struct LatticeDeformData *)mmd->cache_data);
+ mmd->cache_data = NULL;
+ }
+ }
+ }
}
/* *************************************************** */
@@ -383,440 +381,463 @@ void BKE_gpencil_lattice_clear(Object *ob)
/* check if exist geometry modifiers */
bool BKE_gpencil_has_geometry_modifiers(Object *ob)
{
- GpencilModifierData *md;
- for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
-
- if (mti && mti->generateStrokes) {
- return true;
- }
- }
- return false;
+ GpencilModifierData *md;
+ for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ if (mti && mti->generateStrokes) {
+ return true;
+ }
+ }
+ return false;
}
/* check if exist time modifiers */
bool BKE_gpencil_has_time_modifiers(Object *ob)
{
- GpencilModifierData *md;
- for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
-
- if (mti && mti->remapTime) {
- return true;
- }
- }
- return false;
+ GpencilModifierData *md;
+ for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ if (mti && mti->remapTime) {
+ return true;
+ }
+ }
+ return false;
}
/* apply stroke modifiers */
-void BKE_gpencil_stroke_modifiers(Depsgraph *depsgraph, Object *ob, bGPDlayer *gpl, bGPDframe *UNUSED(gpf), bGPDstroke *gps, bool is_render)
+void BKE_gpencil_stroke_modifiers(Depsgraph *depsgraph,
+ Object *ob,
+ bGPDlayer *gpl,
+ bGPDframe *UNUSED(gpf),
+ bGPDstroke *gps,
+ bool is_render)
{
- GpencilModifierData *md;
- bGPdata *gpd = ob->data;
- const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd);
-
- for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
- if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) {
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
-
- if ((GPENCIL_MODIFIER_EDIT(md, is_edit)) && (!is_render)) {
- continue;
- }
-
- if (mti && mti->deformStroke) {
- mti->deformStroke(md, depsgraph, ob, gpl, gps);
- /* subdivide allways requires update */
- if (md->type == eGpencilModifierType_Subdiv) {
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
- }
- /* some modifiers could require a recalc of fill triangulation data */
- else if (gpd->flag & GP_DATA_STROKE_FORCE_RECALC) {
- if (ELEM(md->type,
- eGpencilModifierType_Armature,
- eGpencilModifierType_Hook,
- eGpencilModifierType_Lattice,
- eGpencilModifierType_Offset))
- {
-
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
- }
- }
- }
- }
- }
+ GpencilModifierData *md;
+ bGPdata *gpd = ob->data;
+ const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd);
+
+ for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ if ((GPENCIL_MODIFIER_EDIT(md, is_edit)) && (!is_render)) {
+ continue;
+ }
+
+ if (mti && mti->deformStroke) {
+ mti->deformStroke(md, depsgraph, ob, gpl, gps);
+ /* subdivide allways requires update */
+ if (md->type == eGpencilModifierType_Subdiv) {
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+ }
+ /* some modifiers could require a recalc of fill triangulation data */
+ else if (gpd->flag & GP_DATA_STROKE_FORCE_RECALC) {
+ if (ELEM(md->type,
+ eGpencilModifierType_Armature,
+ eGpencilModifierType_Hook,
+ eGpencilModifierType_Lattice,
+ eGpencilModifierType_Offset)) {
+
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+ }
+ }
+ }
+ }
+ }
}
/* apply stroke geometry modifiers */
-void BKE_gpencil_geometry_modifiers(Depsgraph *depsgraph, Object *ob, bGPDlayer *gpl, bGPDframe *gpf, bool is_render)
+void BKE_gpencil_geometry_modifiers(
+ Depsgraph *depsgraph, Object *ob, bGPDlayer *gpl, bGPDframe *gpf, bool is_render)
{
- GpencilModifierData *md;
- bGPdata *gpd = ob->data;
- const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd);
-
- for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
- if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) {
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
-
- if ((GPENCIL_MODIFIER_EDIT(md, is_edit)) && (!is_render)) {
- continue;
- }
-
- if (mti->generateStrokes) {
- mti->generateStrokes(md, depsgraph, ob, gpl, gpf);
- }
- }
- }
+ GpencilModifierData *md;
+ bGPdata *gpd = ob->data;
+ const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd);
+
+ for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ if ((GPENCIL_MODIFIER_EDIT(md, is_edit)) && (!is_render)) {
+ continue;
+ }
+
+ if (mti->generateStrokes) {
+ mti->generateStrokes(md, depsgraph, ob, gpl, gpf);
+ }
+ }
+ }
}
/* apply time modifiers */
-int BKE_gpencil_time_modifier(Depsgraph *depsgraph, Scene *scene, Object *ob,
- bGPDlayer *gpl, int cfra, bool is_render)
+int BKE_gpencil_time_modifier(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, bGPDlayer *gpl, int cfra, bool is_render)
{
- GpencilModifierData *md;
- bGPdata *gpd = ob->data;
- const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd);
- int nfra = cfra;
-
- for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
- if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) {
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
-
- if ((GPENCIL_MODIFIER_EDIT(md, is_edit)) && (!is_render)) {
- continue;
- }
-
- if (mti->remapTime) {
- nfra = mti->remapTime(md, depsgraph, scene, ob, gpl, cfra);
- /* if the frame number changed, don't evaluate more and return */
- if (nfra != cfra) {
- return nfra;
- }
- }
- }
- }
-
- /* if no time modifier, return original frame number */
- return nfra;
+ GpencilModifierData *md;
+ bGPdata *gpd = ob->data;
+ const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd);
+ int nfra = cfra;
+
+ for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ if ((GPENCIL_MODIFIER_EDIT(md, is_edit)) && (!is_render)) {
+ continue;
+ }
+
+ if (mti->remapTime) {
+ nfra = mti->remapTime(md, depsgraph, scene, ob, gpl, cfra);
+ /* if the frame number changed, don't evaluate more and return */
+ if (nfra != cfra) {
+ return nfra;
+ }
+ }
+ }
+ }
+
+ /* if no time modifier, return original frame number */
+ return nfra;
}
/* *************************************************** */
-void BKE_gpencil_eval_geometry(Depsgraph *depsgraph,
- bGPdata *gpd)
+void BKE_gpencil_eval_geometry(Depsgraph *depsgraph, bGPdata *gpd)
{
- DEG_debug_print_eval(depsgraph, __func__, gpd->id.name, gpd);
- int ctime = (int)DEG_get_ctime(depsgraph);
-
- /* update active frame */
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- gpl->actframe = BKE_gpencil_layer_getframe(gpl, ctime, GP_GETFRAME_USE_PREV);
- }
-
- /* TODO: Move "derived_gpf" logic here from DRW_gpencil_populate_datablock()?
- * This would be better than inventing our own logic for this stuff...
- */
-
- /* TODO: Move the following code to "BKE_gpencil_eval_done()" (marked as an exit node)
- * later when there's more happening here. For now, let's just keep this in here to avoid
- * needing to have one more node slowing down evaluation...
- */
- if (DEG_is_active(depsgraph)) {
- bGPdata *gpd_orig = (bGPdata *)DEG_get_original_id(&gpd->id);
-
- /* sync "actframe" changes back to main-db too,
- * so that editing tools work with copy-on-write
- * when the current frame changes
- */
- for (bGPDlayer *gpl = gpd_orig->layers.first; gpl; gpl = gpl->next) {
- gpl->actframe = BKE_gpencil_layer_getframe(gpl, ctime, GP_GETFRAME_USE_PREV);
- }
- }
+ DEG_debug_print_eval(depsgraph, __func__, gpd->id.name, gpd);
+ int ctime = (int)DEG_get_ctime(depsgraph);
+
+ /* update active frame */
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ gpl->actframe = BKE_gpencil_layer_getframe(gpl, ctime, GP_GETFRAME_USE_PREV);
+ }
+
+ /* TODO: Move "derived_gpf" logic here from DRW_gpencil_populate_datablock()?
+ * This would be better than inventing our own logic for this stuff...
+ */
+
+ /* TODO: Move the following code to "BKE_gpencil_eval_done()" (marked as an exit node)
+ * later when there's more happening here. For now, let's just keep this in here to avoid
+ * needing to have one more node slowing down evaluation...
+ */
+ if (DEG_is_active(depsgraph)) {
+ bGPdata *gpd_orig = (bGPdata *)DEG_get_original_id(&gpd->id);
+
+ /* sync "actframe" changes back to main-db too,
+ * so that editing tools work with copy-on-write
+ * when the current frame changes
+ */
+ for (bGPDlayer *gpl = gpd_orig->layers.first; gpl; gpl = gpl->next) {
+ gpl->actframe = BKE_gpencil_layer_getframe(gpl, ctime, GP_GETFRAME_USE_PREV);
+ }
+ }
}
void BKE_gpencil_modifier_init(void)
{
- /* Initialize modifier types */
- gpencil_modifier_type_init(modifier_gpencil_types); /* MOD_gpencil_util.c */
+ /* Initialize modifier types */
+ gpencil_modifier_type_init(modifier_gpencil_types); /* MOD_gpencil_util.c */
}
GpencilModifierData *BKE_gpencil_modifier_new(int type)
{
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(type);
- GpencilModifierData *md = MEM_callocN(mti->struct_size, mti->struct_name);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(type);
+ GpencilModifierData *md = MEM_callocN(mti->struct_size, mti->struct_name);
- /* note, this name must be made unique later */
- BLI_strncpy(md->name, DATA_(mti->name), sizeof(md->name));
+ /* note, this name must be made unique later */
+ BLI_strncpy(md->name, DATA_(mti->name), sizeof(md->name));
- md->type = type;
- md->mode = eGpencilModifierMode_Realtime | eGpencilModifierMode_Render | eGpencilModifierMode_Expanded;
- md->flag = eGpencilModifierFlag_StaticOverride_Local;
+ md->type = type;
+ md->mode = eGpencilModifierMode_Realtime | eGpencilModifierMode_Render |
+ eGpencilModifierMode_Expanded;
+ md->flag = eGpencilModifierFlag_StaticOverride_Local;
- if (mti->flags & eGpencilModifierTypeFlag_EnableInEditmode)
- md->mode |= eGpencilModifierMode_Editmode;
+ if (mti->flags & eGpencilModifierTypeFlag_EnableInEditmode)
+ md->mode |= eGpencilModifierMode_Editmode;
- if (mti->initData) mti->initData(md);
+ if (mti->initData)
+ mti->initData(md);
- return md;
+ return md;
}
-static void modifier_free_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag)
+static void modifier_free_data_id_us_cb(void *UNUSED(userData),
+ Object *UNUSED(ob),
+ ID **idpoin,
+ int cb_flag)
{
- ID *id = *idpoin;
- if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
- id_us_min(id);
- }
+ ID *id = *idpoin;
+ if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
+ id_us_min(id);
+ }
}
void BKE_gpencil_modifier_free_ex(GpencilModifierData *md, const int flag)
{
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
-
- if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- if (mti->foreachIDLink) {
- mti->foreachIDLink(md, NULL, modifier_free_data_id_us_cb, NULL);
- }
- else if (mti->foreachObjectLink) {
- mti->foreachObjectLink(md, NULL, (GreasePencilObjectWalkFunc)modifier_free_data_id_us_cb, NULL);
- }
- }
-
- if (mti->freeData) mti->freeData(md);
- if (md->error) MEM_freeN(md->error);
-
- MEM_freeN(md);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ if (mti->foreachIDLink) {
+ mti->foreachIDLink(md, NULL, modifier_free_data_id_us_cb, NULL);
+ }
+ else if (mti->foreachObjectLink) {
+ mti->foreachObjectLink(
+ md, NULL, (GreasePencilObjectWalkFunc)modifier_free_data_id_us_cb, NULL);
+ }
+ }
+
+ if (mti->freeData)
+ mti->freeData(md);
+ if (md->error)
+ MEM_freeN(md->error);
+
+ MEM_freeN(md);
}
void BKE_gpencil_modifier_free(GpencilModifierData *md)
{
- BKE_gpencil_modifier_free_ex(md, 0);
+ BKE_gpencil_modifier_free_ex(md, 0);
}
/* check unique name */
bool BKE_gpencil_modifier_unique_name(ListBase *modifiers, GpencilModifierData *gmd)
{
- if (modifiers && gmd) {
- const GpencilModifierTypeInfo *gmti = BKE_gpencil_modifierType_getInfo(gmd->type);
- return BLI_uniquename(modifiers, gmd, DATA_(gmti->name), '.', offsetof(GpencilModifierData, name), sizeof(gmd->name));
- }
- return false;
+ if (modifiers && gmd) {
+ const GpencilModifierTypeInfo *gmti = BKE_gpencil_modifierType_getInfo(gmd->type);
+ return BLI_uniquename(modifiers,
+ gmd,
+ DATA_(gmti->name),
+ '.',
+ offsetof(GpencilModifierData, name),
+ sizeof(gmd->name));
+ }
+ return false;
}
bool BKE_gpencil_modifier_dependsOnTime(GpencilModifierData *md)
{
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
- return mti->dependsOnTime && mti->dependsOnTime(md);
+ return mti->dependsOnTime && mti->dependsOnTime(md);
}
const GpencilModifierTypeInfo *BKE_gpencil_modifierType_getInfo(GpencilModifierType type)
{
- /* type unsigned, no need to check < 0 */
- if (type < NUM_GREASEPENCIL_MODIFIER_TYPES && modifier_gpencil_types[type]->name[0] != '\0') {
- return modifier_gpencil_types[type];
- }
- else {
- return NULL;
- }
+ /* type unsigned, no need to check < 0 */
+ if (type < NUM_GREASEPENCIL_MODIFIER_TYPES && modifier_gpencil_types[type]->name[0] != '\0') {
+ return modifier_gpencil_types[type];
+ }
+ else {
+ return NULL;
+ }
}
-void BKE_gpencil_modifier_copyData_generic(const GpencilModifierData *md_src, GpencilModifierData *md_dst)
+void BKE_gpencil_modifier_copyData_generic(const GpencilModifierData *md_src,
+ GpencilModifierData *md_dst)
{
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md_src->type);
-
- /* md_dst may have already be fully initialized with some extra allocated data,
- * we need to free it now to avoid memleak. */
- if (mti->freeData) {
- mti->freeData(md_dst);
- }
-
- const size_t data_size = sizeof(GpencilModifierData);
- const char *md_src_data = ((const char *)md_src) + data_size;
- char *md_dst_data = ((char *)md_dst) + data_size;
- BLI_assert(data_size <= (size_t)mti->struct_size);
- memcpy(md_dst_data, md_src_data, (size_t)mti->struct_size - data_size);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md_src->type);
+
+ /* md_dst may have already be fully initialized with some extra allocated data,
+ * we need to free it now to avoid memleak. */
+ if (mti->freeData) {
+ mti->freeData(md_dst);
+ }
+
+ const size_t data_size = sizeof(GpencilModifierData);
+ const char *md_src_data = ((const char *)md_src) + data_size;
+ char *md_dst_data = ((char *)md_dst) + data_size;
+ BLI_assert(data_size <= (size_t)mti->struct_size);
+ memcpy(md_dst_data, md_src_data, (size_t)mti->struct_size - data_size);
}
-static void gpencil_modifier_copy_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag)
+static void gpencil_modifier_copy_data_id_us_cb(void *UNUSED(userData),
+ Object *UNUSED(ob),
+ ID **idpoin,
+ int cb_flag)
{
- ID *id = *idpoin;
- if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
- id_us_plus(id);
- }
+ ID *id = *idpoin;
+ if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
+ id_us_plus(id);
+ }
}
-void BKE_gpencil_modifier_copyData_ex(GpencilModifierData *md, GpencilModifierData *target, const int flag)
+void BKE_gpencil_modifier_copyData_ex(GpencilModifierData *md,
+ GpencilModifierData *target,
+ const int flag)
{
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
-
- target->mode = md->mode;
- target->flag = md->flag;
-
- if (mti->copyData) {
- mti->copyData(md, target);
- }
-
- if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- if (mti->foreachIDLink) {
- mti->foreachIDLink(target, NULL, gpencil_modifier_copy_data_id_us_cb, NULL);
- }
- else if (mti->foreachObjectLink) {
- mti->foreachObjectLink(target, NULL, (GreasePencilObjectWalkFunc)gpencil_modifier_copy_data_id_us_cb, NULL);
- }
- }
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ target->mode = md->mode;
+ target->flag = md->flag;
+
+ if (mti->copyData) {
+ mti->copyData(md, target);
+ }
+
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ if (mti->foreachIDLink) {
+ mti->foreachIDLink(target, NULL, gpencil_modifier_copy_data_id_us_cb, NULL);
+ }
+ else if (mti->foreachObjectLink) {
+ mti->foreachObjectLink(
+ target, NULL, (GreasePencilObjectWalkFunc)gpencil_modifier_copy_data_id_us_cb, NULL);
+ }
+ }
}
void BKE_gpencil_modifier_copyData(GpencilModifierData *md, GpencilModifierData *target)
{
- BKE_gpencil_modifier_copyData_ex(md, target, 0);
+ BKE_gpencil_modifier_copyData_ex(md, target, 0);
}
GpencilModifierData *BKE_gpencil_modifiers_findByType(Object *ob, GpencilModifierType type)
{
- GpencilModifierData *md = ob->greasepencil_modifiers.first;
+ GpencilModifierData *md = ob->greasepencil_modifiers.first;
- for (; md; md = md->next)
- if (md->type == type)
- break;
+ for (; md; md = md->next)
+ if (md->type == type)
+ break;
- return md;
+ return md;
}
void BKE_gpencil_modifiers_foreachIDLink(Object *ob, GreasePencilIDWalkFunc walk, void *userData)
{
- GpencilModifierData *md = ob->greasepencil_modifiers.first;
-
- for (; md; md = md->next) {
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
-
- if (mti->foreachIDLink) {
- mti->foreachIDLink(md, ob, walk, userData);
- }
- else if (mti->foreachObjectLink) {
- /* each Object can masquerade as an ID, so this should be OK */
- GreasePencilObjectWalkFunc fp = (GreasePencilObjectWalkFunc)walk;
- mti->foreachObjectLink(md, ob, fp, userData);
- }
- }
+ GpencilModifierData *md = ob->greasepencil_modifiers.first;
+
+ for (; md; md = md->next) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ if (mti->foreachIDLink) {
+ mti->foreachIDLink(md, ob, walk, userData);
+ }
+ else if (mti->foreachObjectLink) {
+ /* each Object can masquerade as an ID, so this should be OK */
+ GreasePencilObjectWalkFunc fp = (GreasePencilObjectWalkFunc)walk;
+ mti->foreachObjectLink(md, ob, fp, userData);
+ }
+ }
}
void BKE_gpencil_modifiers_foreachTexLink(Object *ob, GreasePencilTexWalkFunc walk, void *userData)
{
- GpencilModifierData *md = ob->greasepencil_modifiers.first;
+ GpencilModifierData *md = ob->greasepencil_modifiers.first;
- for (; md; md = md->next) {
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ for (; md; md = md->next) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
- if (mti->foreachTexLink)
- mti->foreachTexLink(md, ob, walk, userData);
- }
+ if (mti->foreachTexLink)
+ mti->foreachTexLink(md, ob, walk, userData);
+ }
}
GpencilModifierData *BKE_gpencil_modifiers_findByName(Object *ob, const char *name)
{
- return BLI_findstring(&(ob->greasepencil_modifiers), name, offsetof(GpencilModifierData, name));
+ return BLI_findstring(&(ob->greasepencil_modifiers), name, offsetof(GpencilModifierData, name));
}
void BKE_gpencil_subdivide(bGPDstroke *gps, int level, int flag)
{
- bGPDspoint *temp_points;
- MDeformVert *temp_dverts = NULL;
- MDeformVert *dvert = NULL;
- MDeformVert *dvert_final = NULL;
- MDeformVert *dvert_next = NULL;
- int totnewpoints, oldtotpoints;
- int i2;
-
- for (int s = 0; s < level; s++) {
- totnewpoints = gps->totpoints - 1;
- /* duplicate points in a temp area */
- temp_points = MEM_dupallocN(gps->points);
- oldtotpoints = gps->totpoints;
-
- /* resize the points arrays */
- gps->totpoints += totnewpoints;
- gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints);
- if (gps->dvert != NULL) {
- temp_dverts = MEM_dupallocN(gps->dvert);
- gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints);
- }
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
- gps->tot_triangles = 0;
-
- /* move points from last to first to new place */
- i2 = gps->totpoints - 1;
- for (int i = oldtotpoints - 1; i > 0; i--) {
- bGPDspoint *pt = &temp_points[i];
- bGPDspoint *pt_final = &gps->points[i2];
-
- copy_v3_v3(&pt_final->x, &pt->x);
- pt_final->pressure = pt->pressure;
- pt_final->strength = pt->strength;
- pt_final->time = pt->time;
- pt_final->flag = pt->flag;
-
- if (gps->dvert != NULL) {
- dvert = &temp_dverts[i];
- dvert_final = &gps->dvert[i2];
- dvert_final->totweight = dvert->totweight;
- dvert_final->dw = dvert->dw;
- }
- i2 -= 2;
- }
- /* interpolate mid points */
- i2 = 1;
- for (int i = 0; i < oldtotpoints - 1; i++) {
- bGPDspoint *pt = &temp_points[i];
- bGPDspoint *next = &temp_points[i + 1];
- bGPDspoint *pt_final = &gps->points[i2];
-
- /* add a half way point */
- interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f);
- pt_final->pressure = interpf(pt->pressure, next->pressure, 0.5f);
- pt_final->strength = interpf(pt->strength, next->strength, 0.5f);
- CLAMP(pt_final->strength, GPENCIL_STRENGTH_MIN, 1.0f);
- pt_final->time = interpf(pt->time, next->time, 0.5f);
-
- if (gps->dvert != NULL) {
- dvert = &temp_dverts[i];
- dvert_next = &temp_dverts[i + 1];
- dvert_final = &gps->dvert[i2];
-
- dvert_final->totweight = dvert->totweight;
- dvert_final->dw = MEM_dupallocN(dvert->dw);
-
- /* interpolate weight values */
- for (int d = 0; d < dvert->totweight; d++) {
- MDeformWeight *dw_a = &dvert->dw[d];
- if (dvert_next->totweight > d) {
- MDeformWeight *dw_b = &dvert_next->dw[d];
- MDeformWeight *dw_final = &dvert_final->dw[d];
- dw_final->weight = interpf(dw_a->weight, dw_b->weight, 0.5f);
- }
- }
- }
-
- i2 += 2;
- }
-
- MEM_SAFE_FREE(temp_points);
- MEM_SAFE_FREE(temp_dverts);
-
- /* move points to smooth stroke (not simple flag )*/
- if ((flag & GP_SUBDIV_SIMPLE) == 0) {
- /* duplicate points in a temp area with the new subdivide data */
- temp_points = MEM_dupallocN(gps->points);
-
- /* extreme points are not changed */
- for (int i = 0; i < gps->totpoints - 2; i++) {
- bGPDspoint *pt = &temp_points[i];
- bGPDspoint *next = &temp_points[i + 1];
- bGPDspoint *pt_final = &gps->points[i + 1];
-
- /* move point */
- interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f);
- }
- /* free temp memory */
- MEM_SAFE_FREE(temp_points);
- }
-
- }
+ bGPDspoint *temp_points;
+ MDeformVert *temp_dverts = NULL;
+ MDeformVert *dvert = NULL;
+ MDeformVert *dvert_final = NULL;
+ MDeformVert *dvert_next = NULL;
+ int totnewpoints, oldtotpoints;
+ int i2;
+
+ for (int s = 0; s < level; s++) {
+ totnewpoints = gps->totpoints - 1;
+ /* duplicate points in a temp area */
+ temp_points = MEM_dupallocN(gps->points);
+ oldtotpoints = gps->totpoints;
+
+ /* resize the points arrays */
+ gps->totpoints += totnewpoints;
+ gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints);
+ if (gps->dvert != NULL) {
+ temp_dverts = MEM_dupallocN(gps->dvert);
+ gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints);
+ }
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+ gps->tot_triangles = 0;
+
+ /* move points from last to first to new place */
+ i2 = gps->totpoints - 1;
+ for (int i = oldtotpoints - 1; i > 0; i--) {
+ bGPDspoint *pt = &temp_points[i];
+ bGPDspoint *pt_final = &gps->points[i2];
+
+ copy_v3_v3(&pt_final->x, &pt->x);
+ pt_final->pressure = pt->pressure;
+ pt_final->strength = pt->strength;
+ pt_final->time = pt->time;
+ pt_final->flag = pt->flag;
+
+ if (gps->dvert != NULL) {
+ dvert = &temp_dverts[i];
+ dvert_final = &gps->dvert[i2];
+ dvert_final->totweight = dvert->totweight;
+ dvert_final->dw = dvert->dw;
+ }
+ i2 -= 2;
+ }
+ /* interpolate mid points */
+ i2 = 1;
+ for (int i = 0; i < oldtotpoints - 1; i++) {
+ bGPDspoint *pt = &temp_points[i];
+ bGPDspoint *next = &temp_points[i + 1];
+ bGPDspoint *pt_final = &gps->points[i2];
+
+ /* add a half way point */
+ interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f);
+ pt_final->pressure = interpf(pt->pressure, next->pressure, 0.5f);
+ pt_final->strength = interpf(pt->strength, next->strength, 0.5f);
+ CLAMP(pt_final->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ pt_final->time = interpf(pt->time, next->time, 0.5f);
+
+ if (gps->dvert != NULL) {
+ dvert = &temp_dverts[i];
+ dvert_next = &temp_dverts[i + 1];
+ dvert_final = &gps->dvert[i2];
+
+ dvert_final->totweight = dvert->totweight;
+ dvert_final->dw = MEM_dupallocN(dvert->dw);
+
+ /* interpolate weight values */
+ for (int d = 0; d < dvert->totweight; d++) {
+ MDeformWeight *dw_a = &dvert->dw[d];
+ if (dvert_next->totweight > d) {
+ MDeformWeight *dw_b = &dvert_next->dw[d];
+ MDeformWeight *dw_final = &dvert_final->dw[d];
+ dw_final->weight = interpf(dw_a->weight, dw_b->weight, 0.5f);
+ }
+ }
+ }
+
+ i2 += 2;
+ }
+
+ MEM_SAFE_FREE(temp_points);
+ MEM_SAFE_FREE(temp_dverts);
+
+ /* move points to smooth stroke (not simple flag )*/
+ if ((flag & GP_SUBDIV_SIMPLE) == 0) {
+ /* duplicate points in a temp area with the new subdivide data */
+ temp_points = MEM_dupallocN(gps->points);
+
+ /* extreme points are not changed */
+ for (int i = 0; i < gps->totpoints - 2; i++) {
+ bGPDspoint *pt = &temp_points[i];
+ bGPDspoint *next = &temp_points[i + 1];
+ bGPDspoint *pt_final = &gps->points[i + 1];
+
+ /* move point */
+ interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f);
+ }
+ /* free temp memory */
+ MEM_SAFE_FREE(temp_points);
+ }
+ }
}
diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c
index bad1e6620eb..7ddd99c0fc0 100644
--- a/source/blender/blenkernel/intern/icons.c
+++ b/source/blender/blenkernel/intern/icons.c
@@ -21,7 +21,6 @@
* \ingroup bke
*/
-
#include <math.h>
#include <stdlib.h>
#include <string.h>
@@ -52,7 +51,7 @@
#include "BKE_global.h" /* only for G.background test */
#include "BKE_studiolight.h"
-#include "BLI_sys_types.h" // for intptr_t support
+#include "BLI_sys_types.h" // for intptr_t support
#include "GPU_texture.h"
@@ -65,7 +64,7 @@
* Previews & ID's have their own functions to remove icons.
*/
enum {
- ICON_FLAG_MANAGED = (1 << 0),
+ ICON_FLAG_MANAGED = (1 << 0),
};
/* GLOBALS */
@@ -82,287 +81,290 @@ static GHash *gCachedPreviews = NULL;
/* Queue of icons for deferred deletion. */
typedef struct DeferredIconDeleteNode {
- struct DeferredIconDeleteNode *next;
- int icon_id;
+ struct DeferredIconDeleteNode *next;
+ int icon_id;
} DeferredIconDeleteNode;
static LockfreeLinkList g_icon_delete_queue;
static void icon_free(void *val)
{
- Icon *icon = val;
-
- if (icon) {
- if (icon->obj_type == ICON_DATA_GEOM) {
- struct Icon_Geom *obj = icon->obj;
- if (obj->mem) {
- /* coords & colors are part of this memory. */
- MEM_freeN((void *)obj->mem);
- }
- else {
- MEM_freeN((void *)obj->coords);
- MEM_freeN((void *)obj->colors);
- }
- MEM_freeN(icon->obj);
- }
-
- if (icon->drawinfo_free) {
- icon->drawinfo_free(icon->drawinfo);
- }
- else if (icon->drawinfo) {
- MEM_freeN(icon->drawinfo);
- }
- MEM_freeN(icon);
- }
+ Icon *icon = val;
+
+ if (icon) {
+ if (icon->obj_type == ICON_DATA_GEOM) {
+ struct Icon_Geom *obj = icon->obj;
+ if (obj->mem) {
+ /* coords & colors are part of this memory. */
+ MEM_freeN((void *)obj->mem);
+ }
+ else {
+ MEM_freeN((void *)obj->coords);
+ MEM_freeN((void *)obj->colors);
+ }
+ MEM_freeN(icon->obj);
+ }
+
+ if (icon->drawinfo_free) {
+ icon->drawinfo_free(icon->drawinfo);
+ }
+ else if (icon->drawinfo) {
+ MEM_freeN(icon->drawinfo);
+ }
+ MEM_freeN(icon);
+ }
}
static void icon_free_data(int icon_id, Icon *icon)
{
- if (icon->obj_type == ICON_DATA_ID) {
- ((ID *)(icon->obj))->icon_id = 0;
- }
- else if (icon->obj_type == ICON_DATA_PREVIEW) {
- ((PreviewImage *)(icon->obj))->icon_id = 0;
- }
- else if (icon->obj_type == ICON_DATA_GPLAYER) {
- ((bGPDlayer *)(icon->obj))->runtime.icon_id = 0;
- }
- else if (icon->obj_type == ICON_DATA_GEOM) {
- ((struct Icon_Geom *)(icon->obj))->icon_id = 0;
- }
- else if (icon->obj_type == ICON_DATA_STUDIOLIGHT) {
- StudioLight *sl = icon->obj;
- if (sl != NULL) {
- BKE_studiolight_unset_icon_id(sl, icon_id);
- }
- }
- else {
- BLI_assert(0);
- }
+ if (icon->obj_type == ICON_DATA_ID) {
+ ((ID *)(icon->obj))->icon_id = 0;
+ }
+ else if (icon->obj_type == ICON_DATA_PREVIEW) {
+ ((PreviewImage *)(icon->obj))->icon_id = 0;
+ }
+ else if (icon->obj_type == ICON_DATA_GPLAYER) {
+ ((bGPDlayer *)(icon->obj))->runtime.icon_id = 0;
+ }
+ else if (icon->obj_type == ICON_DATA_GEOM) {
+ ((struct Icon_Geom *)(icon->obj))->icon_id = 0;
+ }
+ else if (icon->obj_type == ICON_DATA_STUDIOLIGHT) {
+ StudioLight *sl = icon->obj;
+ if (sl != NULL) {
+ BKE_studiolight_unset_icon_id(sl, icon_id);
+ }
+ }
+ else {
+ BLI_assert(0);
+ }
}
/* create an id for a new icon and make sure that ids from deleted icons get reused
* after the integer number range is used up */
static int get_next_free_id(void)
{
- BLI_assert(BLI_thread_is_main());
- int startId = gFirstIconId;
+ BLI_assert(BLI_thread_is_main());
+ int startId = gFirstIconId;
- /* if we haven't used up the int number range, we just return the next int */
- if (gNextIconId >= gFirstIconId)
- return gNextIconId++;
+ /* if we haven't used up the int number range, we just return the next int */
+ if (gNextIconId >= gFirstIconId)
+ return gNextIconId++;
- /* now we try to find the smallest icon id not stored in the gIcons hash */
- while (BLI_ghash_lookup(gIcons, POINTER_FROM_INT(startId)) && startId >= gFirstIconId)
- startId++;
+ /* now we try to find the smallest icon id not stored in the gIcons hash */
+ while (BLI_ghash_lookup(gIcons, POINTER_FROM_INT(startId)) && startId >= gFirstIconId)
+ startId++;
- /* if we found a suitable one that isn't used yet, return it */
- if (startId >= gFirstIconId)
- return startId;
+ /* if we found a suitable one that isn't used yet, return it */
+ if (startId >= gFirstIconId)
+ return startId;
- /* fail */
- return 0;
+ /* fail */
+ return 0;
}
void BKE_icons_init(int first_dyn_id)
{
- BLI_assert(BLI_thread_is_main());
+ BLI_assert(BLI_thread_is_main());
- gNextIconId = first_dyn_id;
- gFirstIconId = first_dyn_id;
+ gNextIconId = first_dyn_id;
+ gFirstIconId = first_dyn_id;
- if (!gIcons) {
- gIcons = BLI_ghash_int_new(__func__);
- BLI_linklist_lockfree_init(&g_icon_delete_queue);
- }
+ if (!gIcons) {
+ gIcons = BLI_ghash_int_new(__func__);
+ BLI_linklist_lockfree_init(&g_icon_delete_queue);
+ }
- if (!gCachedPreviews) {
- gCachedPreviews = BLI_ghash_str_new(__func__);
- }
+ if (!gCachedPreviews) {
+ gCachedPreviews = BLI_ghash_str_new(__func__);
+ }
}
void BKE_icons_free(void)
{
- BLI_assert(BLI_thread_is_main());
+ BLI_assert(BLI_thread_is_main());
- if (gIcons) {
- BLI_ghash_free(gIcons, NULL, icon_free);
- gIcons = NULL;
- }
+ if (gIcons) {
+ BLI_ghash_free(gIcons, NULL, icon_free);
+ gIcons = NULL;
+ }
- if (gCachedPreviews) {
- BLI_ghash_free(gCachedPreviews, MEM_freeN, BKE_previewimg_freefunc);
- gCachedPreviews = NULL;
- }
+ if (gCachedPreviews) {
+ BLI_ghash_free(gCachedPreviews, MEM_freeN, BKE_previewimg_freefunc);
+ gCachedPreviews = NULL;
+ }
- BLI_linklist_lockfree_free(&g_icon_delete_queue, MEM_freeN);
+ BLI_linklist_lockfree_free(&g_icon_delete_queue, MEM_freeN);
}
void BKE_icons_deferred_free(void)
{
- BLI_assert(BLI_thread_is_main());
+ BLI_assert(BLI_thread_is_main());
- for (DeferredIconDeleteNode *node =
- (DeferredIconDeleteNode *)BLI_linklist_lockfree_begin(&g_icon_delete_queue);
- node != NULL;
- node = node->next)
- {
- BLI_ghash_remove(gIcons, POINTER_FROM_INT(node->icon_id), NULL, icon_free);
- }
- BLI_linklist_lockfree_clear(&g_icon_delete_queue, MEM_freeN);
+ for (DeferredIconDeleteNode *node =
+ (DeferredIconDeleteNode *)BLI_linklist_lockfree_begin(&g_icon_delete_queue);
+ node != NULL;
+ node = node->next) {
+ BLI_ghash_remove(gIcons, POINTER_FROM_INT(node->icon_id), NULL, icon_free);
+ }
+ BLI_linklist_lockfree_clear(&g_icon_delete_queue, MEM_freeN);
}
static PreviewImage *previewimg_create_ex(size_t deferred_data_size)
{
- PreviewImage *prv_img = NULL;
- int i;
+ PreviewImage *prv_img = NULL;
+ int i;
- prv_img = MEM_mallocN(sizeof(PreviewImage) + deferred_data_size, "img_prv");
- memset(prv_img, 0, sizeof(*prv_img)); /* leave deferred data dirty */
+ prv_img = MEM_mallocN(sizeof(PreviewImage) + deferred_data_size, "img_prv");
+ memset(prv_img, 0, sizeof(*prv_img)); /* leave deferred data dirty */
- if (deferred_data_size) {
- prv_img->tag |= PRV_TAG_DEFFERED;
- }
+ if (deferred_data_size) {
+ prv_img->tag |= PRV_TAG_DEFFERED;
+ }
- for (i = 0; i < NUM_ICON_SIZES; ++i) {
- prv_img->flag[i] |= PRV_CHANGED;
- prv_img->changed_timestamp[i] = 0;
- }
- return prv_img;
+ for (i = 0; i < NUM_ICON_SIZES; ++i) {
+ prv_img->flag[i] |= PRV_CHANGED;
+ prv_img->changed_timestamp[i] = 0;
+ }
+ return prv_img;
}
PreviewImage *BKE_previewimg_create(void)
{
- return previewimg_create_ex(0);
+ return previewimg_create_ex(0);
}
void BKE_previewimg_freefunc(void *link)
{
- PreviewImage *prv = (PreviewImage *)link;
- if (prv) {
- int i;
+ PreviewImage *prv = (PreviewImage *)link;
+ if (prv) {
+ int i;
- for (i = 0; i < NUM_ICON_SIZES; ++i) {
- if (prv->rect[i]) {
- MEM_freeN(prv->rect[i]);
- }
- if (prv->gputexture[i])
- GPU_texture_free(prv->gputexture[i]);
- }
+ for (i = 0; i < NUM_ICON_SIZES; ++i) {
+ if (prv->rect[i]) {
+ MEM_freeN(prv->rect[i]);
+ }
+ if (prv->gputexture[i])
+ GPU_texture_free(prv->gputexture[i]);
+ }
- MEM_freeN(prv);
- }
+ MEM_freeN(prv);
+ }
}
void BKE_previewimg_free(PreviewImage **prv)
{
- if (prv && (*prv)) {
- BKE_previewimg_freefunc(*prv);
- *prv = NULL;
- }
+ if (prv && (*prv)) {
+ BKE_previewimg_freefunc(*prv);
+ *prv = NULL;
+ }
}
void BKE_previewimg_clear_single(struct PreviewImage *prv, enum eIconSizes size)
{
- MEM_SAFE_FREE(prv->rect[size]);
- if (prv->gputexture[size]) {
- GPU_texture_free(prv->gputexture[size]);
- }
- prv->h[size] = prv->w[size] = 0;
- prv->flag[size] |= PRV_CHANGED;
- prv->flag[size] &= ~PRV_USER_EDITED;
- prv->changed_timestamp[size] = 0;
+ MEM_SAFE_FREE(prv->rect[size]);
+ if (prv->gputexture[size]) {
+ GPU_texture_free(prv->gputexture[size]);
+ }
+ prv->h[size] = prv->w[size] = 0;
+ prv->flag[size] |= PRV_CHANGED;
+ prv->flag[size] &= ~PRV_USER_EDITED;
+ prv->changed_timestamp[size] = 0;
}
void BKE_previewimg_clear(struct PreviewImage *prv)
{
- int i;
- for (i = 0; i < NUM_ICON_SIZES; ++i) {
- BKE_previewimg_clear_single(prv, i);
- }
+ int i;
+ for (i = 0; i < NUM_ICON_SIZES; ++i) {
+ BKE_previewimg_clear_single(prv, i);
+ }
}
PreviewImage *BKE_previewimg_copy(const PreviewImage *prv)
{
- PreviewImage *prv_img = NULL;
- int i;
+ PreviewImage *prv_img = NULL;
+ int i;
- if (prv) {
- prv_img = MEM_dupallocN(prv);
- for (i = 0; i < NUM_ICON_SIZES; ++i) {
- if (prv->rect[i]) {
- prv_img->rect[i] = MEM_dupallocN(prv->rect[i]);
- }
- prv_img->gputexture[i] = NULL;
- }
- }
- return prv_img;
+ if (prv) {
+ prv_img = MEM_dupallocN(prv);
+ for (i = 0; i < NUM_ICON_SIZES; ++i) {
+ if (prv->rect[i]) {
+ prv_img->rect[i] = MEM_dupallocN(prv->rect[i]);
+ }
+ prv_img->gputexture[i] = NULL;
+ }
+ }
+ return prv_img;
}
/** Duplicate preview image from \a id and clear icon_id, to be used by datablock copy functions. */
void BKE_previewimg_id_copy(ID *new_id, const ID *old_id)
{
- PreviewImage **old_prv_p = BKE_previewimg_id_get_p(old_id);
- PreviewImage **new_prv_p = BKE_previewimg_id_get_p(new_id);
+ PreviewImage **old_prv_p = BKE_previewimg_id_get_p(old_id);
+ PreviewImage **new_prv_p = BKE_previewimg_id_get_p(new_id);
- if (old_prv_p && *old_prv_p) {
- BLI_assert(new_prv_p != NULL && ELEM(*new_prv_p, NULL, *old_prv_p));
-// const int new_icon_id = get_next_free_id();
+ if (old_prv_p && *old_prv_p) {
+ BLI_assert(new_prv_p != NULL && ELEM(*new_prv_p, NULL, *old_prv_p));
+ // const int new_icon_id = get_next_free_id();
-// if (new_icon_id == 0) {
-// return; /* Failure. */
-// }
- *new_prv_p = BKE_previewimg_copy(*old_prv_p);
- new_id->icon_id = (*new_prv_p)->icon_id = 0;
- }
+ // if (new_icon_id == 0) {
+ // return; /* Failure. */
+ // }
+ *new_prv_p = BKE_previewimg_copy(*old_prv_p);
+ new_id->icon_id = (*new_prv_p)->icon_id = 0;
+ }
}
PreviewImage **BKE_previewimg_id_get_p(const ID *id)
{
- switch (GS(id->name)) {
-#define ID_PRV_CASE(id_code, id_struct) case id_code: { return &((id_struct *)id)->preview; } ((void)0)
- ID_PRV_CASE(ID_MA, Material);
- ID_PRV_CASE(ID_TE, Tex);
- ID_PRV_CASE(ID_WO, World);
- ID_PRV_CASE(ID_LA, Light);
- ID_PRV_CASE(ID_IM, Image);
- ID_PRV_CASE(ID_BR, Brush);
- ID_PRV_CASE(ID_OB, Object);
- ID_PRV_CASE(ID_GR, Collection);
- ID_PRV_CASE(ID_SCE, Scene);
- ID_PRV_CASE(ID_SCR, bScreen);
+ switch (GS(id->name)) {
+#define ID_PRV_CASE(id_code, id_struct) \
+ case id_code: { \
+ return &((id_struct *)id)->preview; \
+ } \
+ ((void)0)
+ ID_PRV_CASE(ID_MA, Material);
+ ID_PRV_CASE(ID_TE, Tex);
+ ID_PRV_CASE(ID_WO, World);
+ ID_PRV_CASE(ID_LA, Light);
+ ID_PRV_CASE(ID_IM, Image);
+ ID_PRV_CASE(ID_BR, Brush);
+ ID_PRV_CASE(ID_OB, Object);
+ ID_PRV_CASE(ID_GR, Collection);
+ ID_PRV_CASE(ID_SCE, Scene);
+ ID_PRV_CASE(ID_SCR, bScreen);
#undef ID_PRV_CASE
- default:
- break;
- }
+ default:
+ break;
+ }
- return NULL;
+ return NULL;
}
void BKE_previewimg_id_free(ID *id)
{
- PreviewImage **prv_p = BKE_previewimg_id_get_p(id);
- if (prv_p) {
- BKE_previewimg_free(prv_p);
- }
+ PreviewImage **prv_p = BKE_previewimg_id_get_p(id);
+ if (prv_p) {
+ BKE_previewimg_free(prv_p);
+ }
}
PreviewImage *BKE_previewimg_id_ensure(ID *id)
{
- PreviewImage **prv_p = BKE_previewimg_id_get_p(id);
+ PreviewImage **prv_p = BKE_previewimg_id_get_p(id);
- if (prv_p) {
- if (*prv_p == NULL) {
- *prv_p = BKE_previewimg_create();
- }
- return *prv_p;
- }
+ if (prv_p) {
+ if (*prv_p == NULL) {
+ *prv_p = BKE_previewimg_create();
+ }
+ return *prv_p;
+ }
- return NULL;
+ return NULL;
}
PreviewImage *BKE_previewimg_cached_get(const char *name)
{
- return BLI_ghash_lookup(gCachedPreviews, name);
+ return BLI_ghash_lookup(gCachedPreviews, name);
}
/**
@@ -370,269 +372,271 @@ PreviewImage *BKE_previewimg_cached_get(const char *name)
*/
PreviewImage *BKE_previewimg_cached_ensure(const char *name)
{
- PreviewImage *prv = NULL;
- void **key_p, **prv_p;
+ PreviewImage *prv = NULL;
+ void **key_p, **prv_p;
- if (!BLI_ghash_ensure_p_ex(gCachedPreviews, name, &key_p, &prv_p)) {
- *key_p = BLI_strdup(name);
- *prv_p = BKE_previewimg_create();
- }
- prv = *prv_p;
- BLI_assert(prv);
+ if (!BLI_ghash_ensure_p_ex(gCachedPreviews, name, &key_p, &prv_p)) {
+ *key_p = BLI_strdup(name);
+ *prv_p = BKE_previewimg_create();
+ }
+ prv = *prv_p;
+ BLI_assert(prv);
- return prv;
+ return prv;
}
/**
* Generate a PreviewImage from given file path, using thumbnails management, if not yet existing.
*/
-PreviewImage *BKE_previewimg_cached_thumbnail_read(
- const char *name, const char *path, const int source, bool force_update)
-{
- PreviewImage *prv = NULL;
- void **prv_p;
-
- prv_p = BLI_ghash_lookup_p(gCachedPreviews, name);
-
- if (prv_p) {
- prv = *prv_p;
- BLI_assert(prv);
- }
-
- if (prv && force_update) {
- const char *prv_deferred_data = PRV_DEFERRED_DATA(prv);
- if (((int)prv_deferred_data[0] == source) && STREQ(&prv_deferred_data[1], path)) {
- /* If same path, no need to re-allocate preview, just clear it up. */
- BKE_previewimg_clear(prv);
- }
- else {
- BKE_previewimg_free(&prv);
- }
- }
-
- if (!prv) {
- /* We pack needed data for lazy loading (source type, in a single char, and path). */
- const size_t deferred_data_size = strlen(path) + 2;
- char *deferred_data;
-
- prv = previewimg_create_ex(deferred_data_size);
- deferred_data = PRV_DEFERRED_DATA(prv);
- deferred_data[0] = source;
- memcpy(&deferred_data[1], path, deferred_data_size - 1);
-
- force_update = true;
- }
-
- if (force_update) {
- if (prv_p) {
- *prv_p = prv;
- }
- else {
- BLI_ghash_insert(gCachedPreviews, BLI_strdup(name), prv);
- }
- }
-
- return prv;
+PreviewImage *BKE_previewimg_cached_thumbnail_read(const char *name,
+ const char *path,
+ const int source,
+ bool force_update)
+{
+ PreviewImage *prv = NULL;
+ void **prv_p;
+
+ prv_p = BLI_ghash_lookup_p(gCachedPreviews, name);
+
+ if (prv_p) {
+ prv = *prv_p;
+ BLI_assert(prv);
+ }
+
+ if (prv && force_update) {
+ const char *prv_deferred_data = PRV_DEFERRED_DATA(prv);
+ if (((int)prv_deferred_data[0] == source) && STREQ(&prv_deferred_data[1], path)) {
+ /* If same path, no need to re-allocate preview, just clear it up. */
+ BKE_previewimg_clear(prv);
+ }
+ else {
+ BKE_previewimg_free(&prv);
+ }
+ }
+
+ if (!prv) {
+ /* We pack needed data for lazy loading (source type, in a single char, and path). */
+ const size_t deferred_data_size = strlen(path) + 2;
+ char *deferred_data;
+
+ prv = previewimg_create_ex(deferred_data_size);
+ deferred_data = PRV_DEFERRED_DATA(prv);
+ deferred_data[0] = source;
+ memcpy(&deferred_data[1], path, deferred_data_size - 1);
+
+ force_update = true;
+ }
+
+ if (force_update) {
+ if (prv_p) {
+ *prv_p = prv;
+ }
+ else {
+ BLI_ghash_insert(gCachedPreviews, BLI_strdup(name), prv);
+ }
+ }
+
+ return prv;
}
void BKE_previewimg_cached_release_pointer(PreviewImage *prv)
{
- if (prv) {
- if (prv->tag & PRV_TAG_DEFFERED_RENDERING) {
- /* We cannot delete the preview while it is being loaded in another thread... */
- prv->tag |= PRV_TAG_DEFFERED_DELETE;
- return;
- }
- if (prv->icon_id) {
- BKE_icon_delete(prv->icon_id);
- }
- BKE_previewimg_freefunc(prv);
- }
+ if (prv) {
+ if (prv->tag & PRV_TAG_DEFFERED_RENDERING) {
+ /* We cannot delete the preview while it is being loaded in another thread... */
+ prv->tag |= PRV_TAG_DEFFERED_DELETE;
+ return;
+ }
+ if (prv->icon_id) {
+ BKE_icon_delete(prv->icon_id);
+ }
+ BKE_previewimg_freefunc(prv);
+ }
}
void BKE_previewimg_cached_release(const char *name)
{
- PreviewImage *prv = BLI_ghash_popkey(gCachedPreviews, name, MEM_freeN);
+ PreviewImage *prv = BLI_ghash_popkey(gCachedPreviews, name, MEM_freeN);
- BKE_previewimg_cached_release_pointer(prv);
+ BKE_previewimg_cached_release_pointer(prv);
}
/** Handle deferred (lazy) loading/generation of preview image, if needed.
* For now, only used with file thumbnails. */
void BKE_previewimg_ensure(PreviewImage *prv, const int size)
{
- if ((prv->tag & PRV_TAG_DEFFERED) != 0) {
- const bool do_icon = ((size == ICON_SIZE_ICON) && !prv->rect[ICON_SIZE_ICON]);
- const bool do_preview = ((size == ICON_SIZE_PREVIEW) && !prv->rect[ICON_SIZE_PREVIEW]);
-
- if (do_icon || do_preview) {
- ImBuf *thumb;
- char *prv_deferred_data = PRV_DEFERRED_DATA(prv);
- int source = prv_deferred_data[0];
- char *path = &prv_deferred_data[1];
- int icon_w, icon_h;
-
- thumb = IMB_thumb_manage(path, THB_LARGE, source);
-
- if (thumb) {
- /* PreviewImage assumes premultiplied alhpa... */
- IMB_premultiply_alpha(thumb);
-
- if (do_preview) {
- prv->w[ICON_SIZE_PREVIEW] = thumb->x;
- prv->h[ICON_SIZE_PREVIEW] = thumb->y;
- prv->rect[ICON_SIZE_PREVIEW] = MEM_dupallocN(thumb->rect);
- prv->flag[ICON_SIZE_PREVIEW] &= ~(PRV_CHANGED | PRV_USER_EDITED);
- }
- if (do_icon) {
- if (thumb->x > thumb->y) {
- icon_w = ICON_RENDER_DEFAULT_HEIGHT;
- icon_h = (thumb->y * icon_w) / thumb->x + 1;
- }
- else if (thumb->x < thumb->y) {
- icon_h = ICON_RENDER_DEFAULT_HEIGHT;
- icon_w = (thumb->x * icon_h) / thumb->y + 1;
- }
- else {
- icon_w = icon_h = ICON_RENDER_DEFAULT_HEIGHT;
- }
-
- IMB_scaleImBuf(thumb, icon_w, icon_h);
- prv->w[ICON_SIZE_ICON] = icon_w;
- prv->h[ICON_SIZE_ICON] = icon_h;
- prv->rect[ICON_SIZE_ICON] = MEM_dupallocN(thumb->rect);
- prv->flag[ICON_SIZE_ICON] &= ~(PRV_CHANGED | PRV_USER_EDITED);
- }
- IMB_freeImBuf(thumb);
- }
- }
- }
+ if ((prv->tag & PRV_TAG_DEFFERED) != 0) {
+ const bool do_icon = ((size == ICON_SIZE_ICON) && !prv->rect[ICON_SIZE_ICON]);
+ const bool do_preview = ((size == ICON_SIZE_PREVIEW) && !prv->rect[ICON_SIZE_PREVIEW]);
+
+ if (do_icon || do_preview) {
+ ImBuf *thumb;
+ char *prv_deferred_data = PRV_DEFERRED_DATA(prv);
+ int source = prv_deferred_data[0];
+ char *path = &prv_deferred_data[1];
+ int icon_w, icon_h;
+
+ thumb = IMB_thumb_manage(path, THB_LARGE, source);
+
+ if (thumb) {
+ /* PreviewImage assumes premultiplied alhpa... */
+ IMB_premultiply_alpha(thumb);
+
+ if (do_preview) {
+ prv->w[ICON_SIZE_PREVIEW] = thumb->x;
+ prv->h[ICON_SIZE_PREVIEW] = thumb->y;
+ prv->rect[ICON_SIZE_PREVIEW] = MEM_dupallocN(thumb->rect);
+ prv->flag[ICON_SIZE_PREVIEW] &= ~(PRV_CHANGED | PRV_USER_EDITED);
+ }
+ if (do_icon) {
+ if (thumb->x > thumb->y) {
+ icon_w = ICON_RENDER_DEFAULT_HEIGHT;
+ icon_h = (thumb->y * icon_w) / thumb->x + 1;
+ }
+ else if (thumb->x < thumb->y) {
+ icon_h = ICON_RENDER_DEFAULT_HEIGHT;
+ icon_w = (thumb->x * icon_h) / thumb->y + 1;
+ }
+ else {
+ icon_w = icon_h = ICON_RENDER_DEFAULT_HEIGHT;
+ }
+
+ IMB_scaleImBuf(thumb, icon_w, icon_h);
+ prv->w[ICON_SIZE_ICON] = icon_w;
+ prv->h[ICON_SIZE_ICON] = icon_h;
+ prv->rect[ICON_SIZE_ICON] = MEM_dupallocN(thumb->rect);
+ prv->flag[ICON_SIZE_ICON] &= ~(PRV_CHANGED | PRV_USER_EDITED);
+ }
+ IMB_freeImBuf(thumb);
+ }
+ }
+ }
}
void BKE_icon_changed(const int icon_id)
{
- BLI_assert(BLI_thread_is_main());
+ BLI_assert(BLI_thread_is_main());
- Icon *icon = NULL;
+ Icon *icon = NULL;
- if (!icon_id || G.background) return;
+ if (!icon_id || G.background)
+ return;
- icon = BLI_ghash_lookup(gIcons, POINTER_FROM_INT(icon_id));
+ icon = BLI_ghash_lookup(gIcons, POINTER_FROM_INT(icon_id));
- if (icon) {
- /* We *only* expect ID-tied icons here, not non-ID icon/preview! */
- BLI_assert(icon->id_type != 0);
- BLI_assert(icon->obj_type == ICON_DATA_ID);
+ if (icon) {
+ /* We *only* expect ID-tied icons here, not non-ID icon/preview! */
+ BLI_assert(icon->id_type != 0);
+ BLI_assert(icon->obj_type == ICON_DATA_ID);
- /* Do not enforce creation of previews for valid ID types using BKE_previewimg_id_ensure() here ,
- * we only want to ensure *existing* preview images are properly tagged as changed/invalid, that's all. */
- PreviewImage **p_prv = BKE_previewimg_id_get_p((ID *)icon->obj);
+ /* Do not enforce creation of previews for valid ID types using BKE_previewimg_id_ensure() here ,
+ * we only want to ensure *existing* preview images are properly tagged as changed/invalid, that's all. */
+ PreviewImage **p_prv = BKE_previewimg_id_get_p((ID *)icon->obj);
- /* If we have previews, they all are now invalid changed. */
- if (p_prv && *p_prv) {
- int i;
- for (i = 0; i < NUM_ICON_SIZES; ++i) {
- (*p_prv)->flag[i] |= PRV_CHANGED;
- (*p_prv)->changed_timestamp[i]++;
- }
- }
- }
+ /* If we have previews, they all are now invalid changed. */
+ if (p_prv && *p_prv) {
+ int i;
+ for (i = 0; i < NUM_ICON_SIZES; ++i) {
+ (*p_prv)->flag[i] |= PRV_CHANGED;
+ (*p_prv)->changed_timestamp[i]++;
+ }
+ }
+ }
}
static Icon *icon_create(int icon_id, int obj_type, void *obj)
{
- Icon *new_icon = MEM_mallocN(sizeof(Icon), __func__);
+ Icon *new_icon = MEM_mallocN(sizeof(Icon), __func__);
- new_icon->obj_type = obj_type;
- new_icon->obj = obj;
- new_icon->id_type = 0;
- new_icon->flag = 0;
+ new_icon->obj_type = obj_type;
+ new_icon->obj = obj;
+ new_icon->id_type = 0;
+ new_icon->flag = 0;
- /* next two lines make sure image gets created */
- new_icon->drawinfo = NULL;
- new_icon->drawinfo_free = NULL;
+ /* next two lines make sure image gets created */
+ new_icon->drawinfo = NULL;
+ new_icon->drawinfo_free = NULL;
- BLI_ghash_insert(gIcons, POINTER_FROM_INT(icon_id), new_icon);
+ BLI_ghash_insert(gIcons, POINTER_FROM_INT(icon_id), new_icon);
- return new_icon;
+ return new_icon;
}
static int icon_id_ensure_create_icon(struct ID *id)
{
- BLI_assert(BLI_thread_is_main());
+ BLI_assert(BLI_thread_is_main());
- Icon *icon = icon_create(id->icon_id, ICON_DATA_ID, id);
- icon->id_type = GS(id->name);
- icon->flag = ICON_FLAG_MANAGED;
+ Icon *icon = icon_create(id->icon_id, ICON_DATA_ID, id);
+ icon->id_type = GS(id->name);
+ icon->flag = ICON_FLAG_MANAGED;
- return id->icon_id;
+ return id->icon_id;
}
int BKE_icon_id_ensure(struct ID *id)
{
- /* Never handle icons in non-main thread! */
- BLI_assert(BLI_thread_is_main());
+ /* Never handle icons in non-main thread! */
+ BLI_assert(BLI_thread_is_main());
- if (!id || G.background) {
- return 0;
- }
+ if (!id || G.background) {
+ return 0;
+ }
- if (id->icon_id)
- return id->icon_id;
+ if (id->icon_id)
+ return id->icon_id;
- id->icon_id = get_next_free_id();
+ id->icon_id = get_next_free_id();
- if (!id->icon_id) {
- CLOG_ERROR(&LOG, "not enough IDs");
- return 0;
- }
+ if (!id->icon_id) {
+ CLOG_ERROR(&LOG, "not enough IDs");
+ return 0;
+ }
- /* Ensure we synchronize ID icon_id with its previewimage if it has one. */
- PreviewImage **p_prv = BKE_previewimg_id_get_p(id);
- if (p_prv && *p_prv) {
- BLI_assert(ELEM((*p_prv)->icon_id, 0, id->icon_id));
- (*p_prv)->icon_id = id->icon_id;
- }
+ /* Ensure we synchronize ID icon_id with its previewimage if it has one. */
+ PreviewImage **p_prv = BKE_previewimg_id_get_p(id);
+ if (p_prv && *p_prv) {
+ BLI_assert(ELEM((*p_prv)->icon_id, 0, id->icon_id));
+ (*p_prv)->icon_id = id->icon_id;
+ }
- return icon_id_ensure_create_icon(id);
+ return icon_id_ensure_create_icon(id);
}
-
static int icon_gplayer_color_ensure_create_icon(bGPDlayer *gpl)
{
- BLI_assert(BLI_thread_is_main());
+ BLI_assert(BLI_thread_is_main());
- /* NOTE: The color previews for GP Layers don't really need
- * to be "rendered" to image per se (as it will just be a plain
- * colored rectangle), we need to define icon data here so that
- * we can store a pointer to the layer data in icon->obj.
- */
- Icon *icon = icon_create(gpl->runtime.icon_id, ICON_DATA_GPLAYER, gpl);
- icon->flag = ICON_FLAG_MANAGED;
+ /* NOTE: The color previews for GP Layers don't really need
+ * to be "rendered" to image per se (as it will just be a plain
+ * colored rectangle), we need to define icon data here so that
+ * we can store a pointer to the layer data in icon->obj.
+ */
+ Icon *icon = icon_create(gpl->runtime.icon_id, ICON_DATA_GPLAYER, gpl);
+ icon->flag = ICON_FLAG_MANAGED;
- return gpl->runtime.icon_id;
+ return gpl->runtime.icon_id;
}
int BKE_icon_gplayer_color_ensure(bGPDlayer *gpl)
{
- /* Never handle icons in non-main thread! */
- BLI_assert(BLI_thread_is_main());
+ /* Never handle icons in non-main thread! */
+ BLI_assert(BLI_thread_is_main());
- if (!gpl || G.background) {
- return 0;
- }
+ if (!gpl || G.background) {
+ return 0;
+ }
- if (gpl->runtime.icon_id)
- return gpl->runtime.icon_id;
+ if (gpl->runtime.icon_id)
+ return gpl->runtime.icon_id;
- gpl->runtime.icon_id = get_next_free_id();
+ gpl->runtime.icon_id = get_next_free_id();
- if (!gpl->runtime.icon_id) {
- CLOG_ERROR(&LOG, "not enough IDs");
- return 0;
- }
+ if (!gpl->runtime.icon_id) {
+ CLOG_ERROR(&LOG, "not enough IDs");
+ return 0;
+ }
- return icon_gplayer_color_ensure_create_icon(gpl);
+ return icon_gplayer_color_ensure_create_icon(gpl);
}
/**
@@ -640,94 +644,93 @@ int BKE_icon_gplayer_color_ensure(bGPDlayer *gpl)
*/
int BKE_icon_preview_ensure(ID *id, PreviewImage *preview)
{
- if (!preview || G.background)
- return 0;
+ if (!preview || G.background)
+ return 0;
- if (id) {
- BLI_assert(BKE_previewimg_id_ensure(id) == preview);
- }
+ if (id) {
+ BLI_assert(BKE_previewimg_id_ensure(id) == preview);
+ }
- if (preview->icon_id) {
- BLI_assert(!id || !id->icon_id || id->icon_id == preview->icon_id);
- return preview->icon_id;
- }
+ if (preview->icon_id) {
+ BLI_assert(!id || !id->icon_id || id->icon_id == preview->icon_id);
+ return preview->icon_id;
+ }
- if (id && id->icon_id) {
- preview->icon_id = id->icon_id;
- return preview->icon_id;
- }
+ if (id && id->icon_id) {
+ preview->icon_id = id->icon_id;
+ return preview->icon_id;
+ }
- preview->icon_id = get_next_free_id();
+ preview->icon_id = get_next_free_id();
- if (!preview->icon_id) {
- CLOG_ERROR(&LOG, "not enough IDs");
- return 0;
- }
+ if (!preview->icon_id) {
+ CLOG_ERROR(&LOG, "not enough IDs");
+ return 0;
+ }
- /* Ensure we synchronize ID icon_id with its previewimage if available, and generate suitable 'ID' icon. */
- if (id) {
- id->icon_id = preview->icon_id;
- return icon_id_ensure_create_icon(id);
- }
+ /* Ensure we synchronize ID icon_id with its previewimage if available, and generate suitable 'ID' icon. */
+ if (id) {
+ id->icon_id = preview->icon_id;
+ return icon_id_ensure_create_icon(id);
+ }
- Icon *icon = icon_create(preview->icon_id, ICON_DATA_PREVIEW, preview);
- icon->flag = ICON_FLAG_MANAGED;
+ Icon *icon = icon_create(preview->icon_id, ICON_DATA_PREVIEW, preview);
+ icon->flag = ICON_FLAG_MANAGED;
- return preview->icon_id;
+ return preview->icon_id;
}
Icon *BKE_icon_get(const int icon_id)
{
- BLI_assert(BLI_thread_is_main());
+ BLI_assert(BLI_thread_is_main());
- Icon *icon = NULL;
+ Icon *icon = NULL;
- icon = BLI_ghash_lookup(gIcons, POINTER_FROM_INT(icon_id));
+ icon = BLI_ghash_lookup(gIcons, POINTER_FROM_INT(icon_id));
- if (!icon) {
- CLOG_ERROR(&LOG, "no icon for icon ID: %d", icon_id);
- return NULL;
- }
+ if (!icon) {
+ CLOG_ERROR(&LOG, "no icon for icon ID: %d", icon_id);
+ return NULL;
+ }
- return icon;
+ return icon;
}
void BKE_icon_set(const int icon_id, struct Icon *icon)
{
- BLI_assert(BLI_thread_is_main());
+ BLI_assert(BLI_thread_is_main());
- void **val_p;
+ void **val_p;
- if (BLI_ghash_ensure_p(gIcons, POINTER_FROM_INT(icon_id), &val_p)) {
- CLOG_ERROR(&LOG, "icon already set: %d", icon_id);
- return;
- }
+ if (BLI_ghash_ensure_p(gIcons, POINTER_FROM_INT(icon_id), &val_p)) {
+ CLOG_ERROR(&LOG, "icon already set: %d", icon_id);
+ return;
+ }
- *val_p = icon;
+ *val_p = icon;
}
static void icon_add_to_deferred_delete_queue(int icon_id)
{
- DeferredIconDeleteNode *node =
- MEM_mallocN(sizeof(DeferredIconDeleteNode), __func__);
- node->icon_id = icon_id;
- BLI_linklist_lockfree_insert(&g_icon_delete_queue,
- (LockfreeLinkNode *)node);
+ DeferredIconDeleteNode *node = MEM_mallocN(sizeof(DeferredIconDeleteNode), __func__);
+ node->icon_id = icon_id;
+ BLI_linklist_lockfree_insert(&g_icon_delete_queue, (LockfreeLinkNode *)node);
}
void BKE_icon_id_delete(struct ID *id)
{
- const int icon_id = id->icon_id;
- if (!icon_id) return; /* no icon defined for library object */
- id->icon_id = 0;
+ const int icon_id = id->icon_id;
+ if (!icon_id)
+ return; /* no icon defined for library object */
+ id->icon_id = 0;
- if (!BLI_thread_is_main()) {
- icon_add_to_deferred_delete_queue(icon_id);
- return;
- }
+ if (!BLI_thread_is_main()) {
+ icon_add_to_deferred_delete_queue(icon_id);
+ return;
+ }
- BKE_icons_deferred_free();
- BLI_ghash_remove(gIcons, POINTER_FROM_INT(icon_id), NULL, icon_free);
+ BKE_icons_deferred_free();
+ BLI_ghash_remove(gIcons, POINTER_FROM_INT(icon_id), NULL, icon_free);
}
/**
@@ -735,44 +738,44 @@ void BKE_icon_id_delete(struct ID *id)
*/
bool BKE_icon_delete(const int icon_id)
{
- if (icon_id == 0) {
- /* no icon defined for library object */
- return false;
- }
+ if (icon_id == 0) {
+ /* no icon defined for library object */
+ return false;
+ }
- Icon *icon = BLI_ghash_popkey(gIcons, POINTER_FROM_INT(icon_id), NULL);
- if (icon) {
- icon_free_data(icon_id, icon);
- icon_free(icon);
- return true;
- }
- else {
- return false;
- }
+ Icon *icon = BLI_ghash_popkey(gIcons, POINTER_FROM_INT(icon_id), NULL);
+ if (icon) {
+ icon_free_data(icon_id, icon);
+ icon_free(icon);
+ return true;
+ }
+ else {
+ return false;
+ }
}
bool BKE_icon_delete_unmanaged(const int icon_id)
{
- if (icon_id == 0) {
- /* no icon defined for library object */
- return false;
- }
-
- Icon *icon = BLI_ghash_popkey(gIcons, POINTER_FROM_INT(icon_id), NULL);
- if (icon) {
- if (UNLIKELY(icon->flag & ICON_FLAG_MANAGED)) {
- BLI_ghash_insert(gIcons, POINTER_FROM_INT(icon_id), icon);
- return false;
- }
- else {
- icon_free_data(icon_id, icon);
- icon_free(icon);
- return true;
- }
- }
- else {
- return false;
- }
+ if (icon_id == 0) {
+ /* no icon defined for library object */
+ return false;
+ }
+
+ Icon *icon = BLI_ghash_popkey(gIcons, POINTER_FROM_INT(icon_id), NULL);
+ if (icon) {
+ if (UNLIKELY(icon->flag & ICON_FLAG_MANAGED)) {
+ BLI_ghash_insert(gIcons, POINTER_FROM_INT(icon_id), icon);
+ return false;
+ }
+ else {
+ icon_free_data(icon_id, icon);
+ icon_free(icon);
+ return true;
+ }
+ }
+ else {
+ return false;
+ }
}
/* -------------------------------------------------------------------- */
@@ -781,68 +784,68 @@ bool BKE_icon_delete_unmanaged(const int icon_id)
int BKE_icon_geom_ensure(struct Icon_Geom *geom)
{
- BLI_assert(BLI_thread_is_main());
+ BLI_assert(BLI_thread_is_main());
- if (geom->icon_id) {
- return geom->icon_id;
- }
+ if (geom->icon_id) {
+ return geom->icon_id;
+ }
- geom->icon_id = get_next_free_id();
+ geom->icon_id = get_next_free_id();
- icon_create(geom->icon_id, ICON_DATA_GEOM, geom);
- /* Not managed for now, we may want this to be configurable per icon). */
+ icon_create(geom->icon_id, ICON_DATA_GEOM, geom);
+ /* Not managed for now, we may want this to be configurable per icon). */
- return geom->icon_id;
+ return geom->icon_id;
}
struct Icon_Geom *BKE_icon_geom_from_memory(const uchar *data, size_t data_len)
{
- BLI_assert(BLI_thread_is_main());
- if (data_len <= 8) {
- goto fail;
- }
- /* Skip the header. */
- data_len -= 8;
- const int div = 3 * 2 * 3;
- const int coords_len = data_len / div;
- if (coords_len * div != data_len) {
- goto fail;
- }
-
- const uchar header[4] = {'V', 'C', 'O', 0};
- const uchar *p = data;
- if (memcmp(p, header, ARRAY_SIZE(header)) != 0) {
- goto fail;
- }
- p += 4;
-
- struct Icon_Geom *geom = MEM_mallocN(sizeof(*geom), __func__);
- geom->coords_range[0] = (int)*p++;
- geom->coords_range[1] = (int)*p++;
- /* x, y ignored for now */
- p += 2;
-
- geom->coords_len = coords_len;
- geom->coords = (const void *)p;
- geom->colors = (const void *)(p + (data_len / 3));
- geom->icon_id = 0;
- geom->mem = data;
- return geom;
+ BLI_assert(BLI_thread_is_main());
+ if (data_len <= 8) {
+ goto fail;
+ }
+ /* Skip the header. */
+ data_len -= 8;
+ const int div = 3 * 2 * 3;
+ const int coords_len = data_len / div;
+ if (coords_len * div != data_len) {
+ goto fail;
+ }
+
+ const uchar header[4] = {'V', 'C', 'O', 0};
+ const uchar *p = data;
+ if (memcmp(p, header, ARRAY_SIZE(header)) != 0) {
+ goto fail;
+ }
+ p += 4;
+
+ struct Icon_Geom *geom = MEM_mallocN(sizeof(*geom), __func__);
+ geom->coords_range[0] = (int)*p++;
+ geom->coords_range[1] = (int)*p++;
+ /* x, y ignored for now */
+ p += 2;
+
+ geom->coords_len = coords_len;
+ geom->coords = (const void *)p;
+ geom->colors = (const void *)(p + (data_len / 3));
+ geom->icon_id = 0;
+ geom->mem = data;
+ return geom;
fail:
- MEM_freeN((void *)data);
- return NULL;
+ MEM_freeN((void *)data);
+ return NULL;
}
struct Icon_Geom *BKE_icon_geom_from_file(const char *filename)
{
- BLI_assert(BLI_thread_is_main());
- size_t data_len;
- uchar *data = BLI_file_read_binary_as_mem(filename, 0, &data_len);
- if (data == NULL) {
- return NULL;
- }
- return BKE_icon_geom_from_memory(data, data_len);
+ BLI_assert(BLI_thread_is_main());
+ size_t data_len;
+ uchar *data = BLI_file_read_binary_as_mem(filename, 0, &data_len);
+ if (data == NULL) {
+ return NULL;
+ }
+ return BKE_icon_geom_from_memory(data, data_len);
}
/** \} */
@@ -851,9 +854,9 @@ struct Icon_Geom *BKE_icon_geom_from_file(const char *filename)
* \{ */
int BKE_icon_ensure_studio_light(struct StudioLight *sl, int id_type)
{
- int icon_id = get_next_free_id();
- Icon *icon = icon_create(icon_id, ICON_DATA_STUDIOLIGHT, sl);
- icon->id_type = id_type;
- return icon_id;
+ int icon_id = get_next_free_id();
+ Icon *icon = icon_create(icon_id, ICON_DATA_STUDIOLIGHT, sl);
+ icon->id_type = id_type;
+ return icon_id;
}
/** \} */
diff --git a/source/blender/blenkernel/intern/icons_rasterize.c b/source/blender/blenkernel/intern/icons_rasterize.c
index e4ef73d582c..e87180ce732 100644
--- a/source/blender/blenkernel/intern/icons_rasterize.c
+++ b/source/blender/blenkernel/intern/icons_rasterize.c
@@ -31,111 +31,111 @@
#include "BLI_strict_flags.h"
struct UserRasterInfo {
- int pt[3][2];
- const uint *color;
- /* only for smooth shading */
- struct {
- float pt_fl[3][2];
- uint color_u[3][4];
- } smooth;
- int rect_size[2];
- uint *rect;
+ int pt[3][2];
+ const uint *color;
+ /* only for smooth shading */
+ struct {
+ float pt_fl[3][2];
+ uint color_u[3][4];
+ } smooth;
+ int rect_size[2];
+ uint *rect;
};
static void tri_fill_flat(int x, int x_end, int y, void *user_data)
{
- struct UserRasterInfo *data = user_data;
- uint *p = &data->rect[(y * data->rect_size[1]) + x];
- uint col = data->color[0];
- while (x++ != x_end) {
- *p++ = col;
- }
+ struct UserRasterInfo *data = user_data;
+ uint *p = &data->rect[(y * data->rect_size[1]) + x];
+ uint col = data->color[0];
+ while (x++ != x_end) {
+ *p++ = col;
+ }
}
static void tri_fill_smooth(int x, int x_end, int y, void *user_data)
{
- struct UserRasterInfo *data = user_data;
- uint *p = &data->rect[(y * data->rect_size[1]) + x];
- float pt_step_fl[2] = {(float)x, (float)y};
- while (x++ != x_end) {
- float w[3];
- barycentric_weights_v2_clamped(UNPACK3(data->smooth.pt_fl), pt_step_fl, w);
-
- uint col_u[4] = {0, 0, 0, 0};
- for (uint corner = 0; corner < 3; corner++) {
- for (uint chan = 0; chan < 4; chan++) {
- col_u[chan] += data->smooth.color_u[corner][chan] * (uint)(w[corner] * 255.0f);
- }
- }
- union {
- uint as_u32;
- uchar as_bytes[4];
- } col;
- col.as_bytes[0] = (uchar)(col_u[0] / 255);
- col.as_bytes[1] = (uchar)(col_u[1] / 255);
- col.as_bytes[2] = (uchar)(col_u[2] / 255);
- col.as_bytes[3] = (uchar)(col_u[3] / 255);
- *p++ = col.as_u32;
-
- pt_step_fl[0] += 1.0f;
- }
+ struct UserRasterInfo *data = user_data;
+ uint *p = &data->rect[(y * data->rect_size[1]) + x];
+ float pt_step_fl[2] = {(float)x, (float)y};
+ while (x++ != x_end) {
+ float w[3];
+ barycentric_weights_v2_clamped(UNPACK3(data->smooth.pt_fl), pt_step_fl, w);
+
+ uint col_u[4] = {0, 0, 0, 0};
+ for (uint corner = 0; corner < 3; corner++) {
+ for (uint chan = 0; chan < 4; chan++) {
+ col_u[chan] += data->smooth.color_u[corner][chan] * (uint)(w[corner] * 255.0f);
+ }
+ }
+ union {
+ uint as_u32;
+ uchar as_bytes[4];
+ } col;
+ col.as_bytes[0] = (uchar)(col_u[0] / 255);
+ col.as_bytes[1] = (uchar)(col_u[1] / 255);
+ col.as_bytes[2] = (uchar)(col_u[2] / 255);
+ col.as_bytes[3] = (uchar)(col_u[3] / 255);
+ *p++ = col.as_u32;
+
+ pt_step_fl[0] += 1.0f;
+ }
}
-ImBuf *BKE_icon_geom_rasterize(
- const struct Icon_Geom *geom,
- const unsigned int size_x, const unsigned int size_y)
+ImBuf *BKE_icon_geom_rasterize(const struct Icon_Geom *geom,
+ const unsigned int size_x,
+ const unsigned int size_y)
{
- const int coords_len = geom->coords_len;
-
- const uchar (*pos)[2] = geom->coords;
- const uint *col = (void *)geom->colors;
-
- /* TODO(campbell): Currently rasterizes to fixed size, then scales.
- * Should rasterize to double size for eg instead. */
- const int rect_size[2] = {max_ii(256, (int)size_x * 2), max_ii(256, (int)size_y * 2)};
-
- ImBuf *ibuf = IMB_allocImBuf((uint)rect_size[0], (uint)rect_size[1], 32, IB_rect);
-
- struct UserRasterInfo data;
-
- data.rect_size[0] = rect_size[0];
- data.rect_size[1] = rect_size[1];
-
- data.rect = ibuf->rect;
-
- float scale[2];
- const bool use_scale = (rect_size[0] != 256) || (rect_size[1] != 256);
-
- if (use_scale) {
- scale[0] = ((float)rect_size[0] / 256.0f);
- scale[1] = ((float)rect_size[1] / 256.0f);
- }
-
- for (int t = 0; t < coords_len; t += 1, pos += 3, col += 3) {
- if (use_scale) {
- ARRAY_SET_ITEMS(data.pt[0], (int)(pos[0][0] * scale[0]), (int)(pos[0][1] * scale[1]));
- ARRAY_SET_ITEMS(data.pt[1], (int)(pos[1][0] * scale[0]), (int)(pos[1][1] * scale[1]));
- ARRAY_SET_ITEMS(data.pt[2], (int)(pos[2][0] * scale[0]), (int)(pos[2][1] * scale[1]));
- }
- else {
- ARRAY_SET_ITEMS(data.pt[0], UNPACK2(pos[0]));
- ARRAY_SET_ITEMS(data.pt[1], UNPACK2(pos[1]));
- ARRAY_SET_ITEMS(data.pt[2], UNPACK2(pos[2]));
- }
- data.color = col;
- if ((col[0] == col[1]) && (col[0] == col[2])) {
- BLI_bitmap_draw_2d_tri_v2i(UNPACK3(data.pt), tri_fill_flat, &data);
- }
- else {
- ARRAY_SET_ITEMS(data.smooth.pt_fl[0], UNPACK2_EX((float), data.pt[0], ));
- ARRAY_SET_ITEMS(data.smooth.pt_fl[1], UNPACK2_EX((float), data.pt[1], ));
- ARRAY_SET_ITEMS(data.smooth.pt_fl[2], UNPACK2_EX((float), data.pt[2], ));
- ARRAY_SET_ITEMS(data.smooth.color_u[0], UNPACK4_EX((uint), ((uchar *)(col + 0)), ));
- ARRAY_SET_ITEMS(data.smooth.color_u[1], UNPACK4_EX((uint), ((uchar *)(col + 1)), ));
- ARRAY_SET_ITEMS(data.smooth.color_u[2], UNPACK4_EX((uint), ((uchar *)(col + 2)), ));
- BLI_bitmap_draw_2d_tri_v2i(UNPACK3(data.pt), tri_fill_smooth, &data);
- }
- }
- IMB_scaleImBuf(ibuf, size_x, size_y);
- return ibuf;
+ const int coords_len = geom->coords_len;
+
+ const uchar(*pos)[2] = geom->coords;
+ const uint *col = (void *)geom->colors;
+
+ /* TODO(campbell): Currently rasterizes to fixed size, then scales.
+ * Should rasterize to double size for eg instead. */
+ const int rect_size[2] = {max_ii(256, (int)size_x * 2), max_ii(256, (int)size_y * 2)};
+
+ ImBuf *ibuf = IMB_allocImBuf((uint)rect_size[0], (uint)rect_size[1], 32, IB_rect);
+
+ struct UserRasterInfo data;
+
+ data.rect_size[0] = rect_size[0];
+ data.rect_size[1] = rect_size[1];
+
+ data.rect = ibuf->rect;
+
+ float scale[2];
+ const bool use_scale = (rect_size[0] != 256) || (rect_size[1] != 256);
+
+ if (use_scale) {
+ scale[0] = ((float)rect_size[0] / 256.0f);
+ scale[1] = ((float)rect_size[1] / 256.0f);
+ }
+
+ for (int t = 0; t < coords_len; t += 1, pos += 3, col += 3) {
+ if (use_scale) {
+ ARRAY_SET_ITEMS(data.pt[0], (int)(pos[0][0] * scale[0]), (int)(pos[0][1] * scale[1]));
+ ARRAY_SET_ITEMS(data.pt[1], (int)(pos[1][0] * scale[0]), (int)(pos[1][1] * scale[1]));
+ ARRAY_SET_ITEMS(data.pt[2], (int)(pos[2][0] * scale[0]), (int)(pos[2][1] * scale[1]));
+ }
+ else {
+ ARRAY_SET_ITEMS(data.pt[0], UNPACK2(pos[0]));
+ ARRAY_SET_ITEMS(data.pt[1], UNPACK2(pos[1]));
+ ARRAY_SET_ITEMS(data.pt[2], UNPACK2(pos[2]));
+ }
+ data.color = col;
+ if ((col[0] == col[1]) && (col[0] == col[2])) {
+ BLI_bitmap_draw_2d_tri_v2i(UNPACK3(data.pt), tri_fill_flat, &data);
+ }
+ else {
+ ARRAY_SET_ITEMS(data.smooth.pt_fl[0], UNPACK2_EX((float), data.pt[0], ));
+ ARRAY_SET_ITEMS(data.smooth.pt_fl[1], UNPACK2_EX((float), data.pt[1], ));
+ ARRAY_SET_ITEMS(data.smooth.pt_fl[2], UNPACK2_EX((float), data.pt[2], ));
+ ARRAY_SET_ITEMS(data.smooth.color_u[0], UNPACK4_EX((uint), ((uchar *)(col + 0)), ));
+ ARRAY_SET_ITEMS(data.smooth.color_u[1], UNPACK4_EX((uint), ((uchar *)(col + 1)), ));
+ ARRAY_SET_ITEMS(data.smooth.color_u[2], UNPACK4_EX((uint), ((uchar *)(col + 2)), ));
+ BLI_bitmap_draw_2d_tri_v2i(UNPACK3(data.pt), tri_fill_smooth, &data);
+ }
+ }
+ IMB_scaleImBuf(ibuf, size_x, size_y);
+ return ibuf;
}
diff --git a/source/blender/blenkernel/intern/idcode.c b/source/blender/blenkernel/intern/idcode.c
index 5e37f586a2a..0e9960755d8 100644
--- a/source/blender/blenkernel/intern/idcode.c
+++ b/source/blender/blenkernel/intern/idcode.c
@@ -35,12 +35,12 @@
#include "BKE_idcode.h"
typedef struct {
- unsigned short code;
- const char *name, *plural;
+ unsigned short code;
+ const char *name, *plural;
- const char *i18n_context;
+ const char *i18n_context;
- int flags;
+ int flags;
#define IDTYPE_FLAGS_ISLINKABLE (1 << 0)
} IDType;
@@ -52,48 +52,48 @@ typedef struct {
* - 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_CA, "Camera", "cameras", BLT_I18NCONTEXT_ID_CAMERA, IDTYPE_FLAGS_ISLINKABLE},
- {ID_CF, "CacheFile", "cache_files", BLT_I18NCONTEXT_ID_CACHEFILE, IDTYPE_FLAGS_ISLINKABLE},
- {ID_GR, "Collection", "collections", BLT_I18NCONTEXT_ID_COLLECTION, IDTYPE_FLAGS_ISLINKABLE},
- {ID_CU, "Curve", "curves", BLT_I18NCONTEXT_ID_CURVE, IDTYPE_FLAGS_ISLINKABLE},
- {ID_GD, "GPencil", "grease_pencils", BLT_I18NCONTEXT_ID_GPENCIL, IDTYPE_FLAGS_ISLINKABLE}, /* rename gpencil */
-
- {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_LA, "Light", "lights", BLT_I18NCONTEXT_ID_LIGHT, IDTYPE_FLAGS_ISLINKABLE},
- {ID_LI, "Library", "libraries", BLT_I18NCONTEXT_ID_LIBRARY, 0 },
- {ID_LS, "FreestyleLineStyle", "linestyles", BLT_I18NCONTEXT_ID_FREESTYLELINESTYLE, IDTYPE_FLAGS_ISLINKABLE},
- {ID_LT, "Lattice", "lattices", BLT_I18NCONTEXT_ID_LATTICE, IDTYPE_FLAGS_ISLINKABLE},
- {ID_MA, "Material", "materials", BLT_I18NCONTEXT_ID_MATERIAL, IDTYPE_FLAGS_ISLINKABLE},
- {ID_MB, "Metaball", "metaballs", BLT_I18NCONTEXT_ID_METABALL, IDTYPE_FLAGS_ISLINKABLE},
- {ID_MC, "MovieClip", "movieclips", BLT_I18NCONTEXT_ID_MOVIECLIP, IDTYPE_FLAGS_ISLINKABLE},
- {ID_ME, "Mesh", "meshes", BLT_I18NCONTEXT_ID_MESH, IDTYPE_FLAGS_ISLINKABLE},
- {ID_MSK, "Mask", "masks", BLT_I18NCONTEXT_ID_MASK, IDTYPE_FLAGS_ISLINKABLE},
- {ID_NT, "NodeTree", "node_groups", BLT_I18NCONTEXT_ID_NODETREE, IDTYPE_FLAGS_ISLINKABLE},
- {ID_OB, "Object", "objects", BLT_I18NCONTEXT_ID_OBJECT, IDTYPE_FLAGS_ISLINKABLE},
- {ID_PA, "ParticleSettings", "particles", BLT_I18NCONTEXT_ID_PARTICLESETTINGS, IDTYPE_FLAGS_ISLINKABLE},
- {ID_PAL, "Palettes", "palettes", BLT_I18NCONTEXT_ID_PALETTE, IDTYPE_FLAGS_ISLINKABLE},
- {ID_PC, "PaintCurve", "paint_curves", BLT_I18NCONTEXT_ID_PAINTCURVE, IDTYPE_FLAGS_ISLINKABLE},
- {ID_LP, "LightProbe", "lightprobes", BLT_I18NCONTEXT_ID_LIGHTPROBE, IDTYPE_FLAGS_ISLINKABLE},
- {ID_SCE, "Scene", "scenes", BLT_I18NCONTEXT_ID_SCENE, IDTYPE_FLAGS_ISLINKABLE},
- {ID_SCR, "Screen", "screens", BLT_I18NCONTEXT_ID_SCREEN, IDTYPE_FLAGS_ISLINKABLE},
- {ID_SEQ, "Sequence", "sequences", BLT_I18NCONTEXT_ID_SEQUENCE, 0 }, /* not actually ID data */
- {ID_SPK, "Speaker", "speakers", BLT_I18NCONTEXT_ID_SPEAKER, IDTYPE_FLAGS_ISLINKABLE},
- {ID_SO, "Sound", "sounds", BLT_I18NCONTEXT_ID_SOUND, IDTYPE_FLAGS_ISLINKABLE},
- {ID_TE, "Texture", "textures", BLT_I18NCONTEXT_ID_TEXTURE, IDTYPE_FLAGS_ISLINKABLE},
- {ID_TXT, "Text", "texts", BLT_I18NCONTEXT_ID_TEXT, IDTYPE_FLAGS_ISLINKABLE},
- {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 },
- {ID_WS, "WorkSpace", "workspaces", BLT_I18NCONTEXT_ID_WORKSPACE, IDTYPE_FLAGS_ISLINKABLE},
-
- /** Keep last, not an ID exactly, only include for completeness */
- {ID_LINK_PLACEHOLDER, "Link Placeholder", "link_placeholders", BLT_I18NCONTEXT_ID_ID, 0}, /* plural is fake */
+ /** 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_CA, "Camera", "cameras", BLT_I18NCONTEXT_ID_CAMERA, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_CF, "CacheFile", "cache_files", BLT_I18NCONTEXT_ID_CACHEFILE, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_GR, "Collection", "collections", BLT_I18NCONTEXT_ID_COLLECTION, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_CU, "Curve", "curves", BLT_I18NCONTEXT_ID_CURVE, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_GD, "GPencil", "grease_pencils", BLT_I18NCONTEXT_ID_GPENCIL, IDTYPE_FLAGS_ISLINKABLE}, /* rename gpencil */
+
+ {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_LA, "Light", "lights", BLT_I18NCONTEXT_ID_LIGHT, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_LI, "Library", "libraries", BLT_I18NCONTEXT_ID_LIBRARY, 0 },
+ {ID_LS, "FreestyleLineStyle", "linestyles", BLT_I18NCONTEXT_ID_FREESTYLELINESTYLE, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_LT, "Lattice", "lattices", BLT_I18NCONTEXT_ID_LATTICE, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_MA, "Material", "materials", BLT_I18NCONTEXT_ID_MATERIAL, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_MB, "Metaball", "metaballs", BLT_I18NCONTEXT_ID_METABALL, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_MC, "MovieClip", "movieclips", BLT_I18NCONTEXT_ID_MOVIECLIP, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_ME, "Mesh", "meshes", BLT_I18NCONTEXT_ID_MESH, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_MSK, "Mask", "masks", BLT_I18NCONTEXT_ID_MASK, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_NT, "NodeTree", "node_groups", BLT_I18NCONTEXT_ID_NODETREE, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_OB, "Object", "objects", BLT_I18NCONTEXT_ID_OBJECT, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_PA, "ParticleSettings", "particles", BLT_I18NCONTEXT_ID_PARTICLESETTINGS, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_PAL, "Palettes", "palettes", BLT_I18NCONTEXT_ID_PALETTE, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_PC, "PaintCurve", "paint_curves", BLT_I18NCONTEXT_ID_PAINTCURVE, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_LP, "LightProbe", "lightprobes", BLT_I18NCONTEXT_ID_LIGHTPROBE, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_SCE, "Scene", "scenes", BLT_I18NCONTEXT_ID_SCENE, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_SCR, "Screen", "screens", BLT_I18NCONTEXT_ID_SCREEN, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_SEQ, "Sequence", "sequences", BLT_I18NCONTEXT_ID_SEQUENCE, 0 }, /* not actually ID data */
+ {ID_SPK, "Speaker", "speakers", BLT_I18NCONTEXT_ID_SPEAKER, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_SO, "Sound", "sounds", BLT_I18NCONTEXT_ID_SOUND, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_TE, "Texture", "textures", BLT_I18NCONTEXT_ID_TEXTURE, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_TXT, "Text", "texts", BLT_I18NCONTEXT_ID_TEXT, IDTYPE_FLAGS_ISLINKABLE},
+ {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 },
+ {ID_WS, "WorkSpace", "workspaces", BLT_I18NCONTEXT_ID_WORKSPACE, IDTYPE_FLAGS_ISLINKABLE},
+
+ /** Keep last, not an ID exactly, only include for completeness */
+ {ID_LINK_PLACEHOLDER, "Link Placeholder", "link_placeholders", BLT_I18NCONTEXT_ID_ID, 0}, /* plural is fake */
};
/* clang-format on */
@@ -102,25 +102,25 @@ BLI_STATIC_ASSERT((ARRAY_SIZE(idtypes) - 1 == MAX_LIBARRAY), "Missing IDType");
static IDType *idtype_from_name(const char *str)
{
- int i = ARRAY_SIZE(idtypes);
+ int i = ARRAY_SIZE(idtypes);
- while (i--) {
- if (STREQ(str, idtypes[i].name)) {
- return &idtypes[i];
- }
- }
+ while (i--) {
+ if (STREQ(str, idtypes[i].name)) {
+ return &idtypes[i];
+ }
+ }
- return NULL;
+ return NULL;
}
static IDType *idtype_from_code(short idcode)
{
- int i = ARRAY_SIZE(idtypes);
+ int i = ARRAY_SIZE(idtypes);
- while (i--)
- if (idcode == idtypes[i].code)
- return &idtypes[i];
+ while (i--)
+ if (idcode == idtypes[i].code)
+ return &idtypes[i];
- return NULL;
+ return NULL;
}
/**
@@ -131,7 +131,7 @@ static IDType *idtype_from_code(short idcode)
*/
bool BKE_idcode_is_valid(short idcode)
{
- return idtype_from_code(idcode) ? true : false;
+ return idtype_from_code(idcode) ? true : false;
}
/**
@@ -142,9 +142,9 @@ bool BKE_idcode_is_valid(short idcode)
*/
bool BKE_idcode_is_linkable(short idcode)
{
- IDType *idt = idtype_from_code(idcode);
- BLI_assert(idt);
- return idt ? ((idt->flags & IDTYPE_FLAGS_ISLINKABLE) != 0) : false;
+ IDType *idt = idtype_from_code(idcode);
+ BLI_assert(idt);
+ return idt ? ((idt->flags & IDTYPE_FLAGS_ISLINKABLE) != 0) : false;
}
/**
@@ -156,9 +156,9 @@ bool BKE_idcode_is_linkable(short idcode)
*/
const char *BKE_idcode_to_name(short idcode)
{
- IDType *idt = idtype_from_code(idcode);
- BLI_assert(idt);
- return idt ? idt->name : NULL;
+ IDType *idt = idtype_from_code(idcode);
+ BLI_assert(idt);
+ return idt ? idt->name : NULL;
}
/**
@@ -169,9 +169,9 @@ const char *BKE_idcode_to_name(short idcode)
*/
short BKE_idcode_from_name(const char *name)
{
- IDType *idt = idtype_from_name(name);
- BLI_assert(idt);
- return idt ? idt->code : 0;
+ IDType *idt = idtype_from_name(name);
+ BLI_assert(idt);
+ return idt ? idt->code : 0;
}
/**
@@ -179,43 +179,45 @@ short BKE_idcode_from_name(const char *name)
*/
int BKE_idcode_to_idfilter(const short idcode)
{
-#define CASE_IDFILTER(_id) case ID_##_id: return FILTER_ID_##_id
-
- switch (idcode) {
- CASE_IDFILTER(AC);
- CASE_IDFILTER(AR);
- CASE_IDFILTER(BR);
- CASE_IDFILTER(CA);
- CASE_IDFILTER(CF);
- CASE_IDFILTER(CU);
- CASE_IDFILTER(GD);
- CASE_IDFILTER(GR);
- CASE_IDFILTER(IM);
- CASE_IDFILTER(LA);
- CASE_IDFILTER(LS);
- CASE_IDFILTER(LT);
- CASE_IDFILTER(MA);
- CASE_IDFILTER(MB);
- CASE_IDFILTER(MC);
- CASE_IDFILTER(ME);
- CASE_IDFILTER(MSK);
- CASE_IDFILTER(NT);
- CASE_IDFILTER(OB);
- CASE_IDFILTER(PA);
- CASE_IDFILTER(PAL);
- CASE_IDFILTER(PC);
- CASE_IDFILTER(LP);
- CASE_IDFILTER(SCE);
- CASE_IDFILTER(SPK);
- CASE_IDFILTER(SO);
- CASE_IDFILTER(TE);
- CASE_IDFILTER(TXT);
- CASE_IDFILTER(VF);
- CASE_IDFILTER(WO);
- CASE_IDFILTER(WS);
- default:
- return 0;
- }
+#define CASE_IDFILTER(_id) \
+ case ID_##_id: \
+ return FILTER_ID_##_id
+
+ switch (idcode) {
+ CASE_IDFILTER(AC);
+ CASE_IDFILTER(AR);
+ CASE_IDFILTER(BR);
+ CASE_IDFILTER(CA);
+ CASE_IDFILTER(CF);
+ CASE_IDFILTER(CU);
+ CASE_IDFILTER(GD);
+ CASE_IDFILTER(GR);
+ CASE_IDFILTER(IM);
+ CASE_IDFILTER(LA);
+ CASE_IDFILTER(LS);
+ CASE_IDFILTER(LT);
+ CASE_IDFILTER(MA);
+ CASE_IDFILTER(MB);
+ CASE_IDFILTER(MC);
+ CASE_IDFILTER(ME);
+ CASE_IDFILTER(MSK);
+ CASE_IDFILTER(NT);
+ CASE_IDFILTER(OB);
+ CASE_IDFILTER(PA);
+ CASE_IDFILTER(PAL);
+ CASE_IDFILTER(PC);
+ CASE_IDFILTER(LP);
+ CASE_IDFILTER(SCE);
+ CASE_IDFILTER(SPK);
+ CASE_IDFILTER(SO);
+ CASE_IDFILTER(TE);
+ CASE_IDFILTER(TXT);
+ CASE_IDFILTER(VF);
+ CASE_IDFILTER(WO);
+ CASE_IDFILTER(WS);
+ default:
+ return 0;
+ }
#undef CASE_IDFILTER
}
@@ -225,42 +227,44 @@ int BKE_idcode_to_idfilter(const short idcode)
*/
short BKE_idcode_from_idfilter(const int idfilter)
{
-#define CASE_IDFILTER(_id) case FILTER_ID_##_id: return ID_##_id
-
- switch (idfilter) {
- CASE_IDFILTER(AC);
- CASE_IDFILTER(AR);
- CASE_IDFILTER(BR);
- CASE_IDFILTER(CA);
- CASE_IDFILTER(CF);
- CASE_IDFILTER(CU);
- CASE_IDFILTER(GD);
- CASE_IDFILTER(GR);
- CASE_IDFILTER(IM);
- CASE_IDFILTER(LA);
- CASE_IDFILTER(LS);
- CASE_IDFILTER(LT);
- CASE_IDFILTER(MA);
- CASE_IDFILTER(MB);
- CASE_IDFILTER(MC);
- CASE_IDFILTER(ME);
- CASE_IDFILTER(MSK);
- CASE_IDFILTER(NT);
- CASE_IDFILTER(OB);
- CASE_IDFILTER(PA);
- CASE_IDFILTER(PAL);
- CASE_IDFILTER(PC);
- CASE_IDFILTER(LP);
- CASE_IDFILTER(SCE);
- CASE_IDFILTER(SPK);
- CASE_IDFILTER(SO);
- CASE_IDFILTER(TE);
- CASE_IDFILTER(TXT);
- CASE_IDFILTER(VF);
- CASE_IDFILTER(WO);
- default:
- return 0;
- }
+#define CASE_IDFILTER(_id) \
+ case FILTER_ID_##_id: \
+ return ID_##_id
+
+ switch (idfilter) {
+ CASE_IDFILTER(AC);
+ CASE_IDFILTER(AR);
+ CASE_IDFILTER(BR);
+ CASE_IDFILTER(CA);
+ CASE_IDFILTER(CF);
+ CASE_IDFILTER(CU);
+ CASE_IDFILTER(GD);
+ CASE_IDFILTER(GR);
+ CASE_IDFILTER(IM);
+ CASE_IDFILTER(LA);
+ CASE_IDFILTER(LS);
+ CASE_IDFILTER(LT);
+ CASE_IDFILTER(MA);
+ CASE_IDFILTER(MB);
+ CASE_IDFILTER(MC);
+ CASE_IDFILTER(ME);
+ CASE_IDFILTER(MSK);
+ CASE_IDFILTER(NT);
+ CASE_IDFILTER(OB);
+ CASE_IDFILTER(PA);
+ CASE_IDFILTER(PAL);
+ CASE_IDFILTER(PC);
+ CASE_IDFILTER(LP);
+ CASE_IDFILTER(SCE);
+ CASE_IDFILTER(SPK);
+ CASE_IDFILTER(SO);
+ CASE_IDFILTER(TE);
+ CASE_IDFILTER(TXT);
+ CASE_IDFILTER(VF);
+ CASE_IDFILTER(WO);
+ default:
+ return 0;
+ }
#undef CASE_IDFILTER
}
@@ -270,49 +274,51 @@ short BKE_idcode_from_idfilter(const int idfilter)
*/
int BKE_idcode_to_index(const short idcode)
{
-#define CASE_IDINDEX(_id) case ID_##_id: return INDEX_ID_##_id
-
- switch ((ID_Type)idcode) {
- CASE_IDINDEX(AC);
- CASE_IDINDEX(AR);
- CASE_IDINDEX(BR);
- CASE_IDINDEX(CA);
- CASE_IDINDEX(CF);
- CASE_IDINDEX(CU);
- CASE_IDINDEX(GD);
- CASE_IDINDEX(GR);
- CASE_IDINDEX(IM);
- CASE_IDINDEX(KE);
- CASE_IDINDEX(IP);
- CASE_IDINDEX(LA);
- CASE_IDINDEX(LI);
- CASE_IDINDEX(LS);
- CASE_IDINDEX(LT);
- CASE_IDINDEX(MA);
- CASE_IDINDEX(MB);
- CASE_IDINDEX(MC);
- CASE_IDINDEX(ME);
- CASE_IDINDEX(MSK);
- CASE_IDINDEX(NT);
- CASE_IDINDEX(OB);
- CASE_IDINDEX(PA);
- CASE_IDINDEX(PAL);
- CASE_IDINDEX(PC);
- CASE_IDINDEX(LP);
- CASE_IDINDEX(SCE);
- CASE_IDINDEX(SCR);
- CASE_IDINDEX(SPK);
- CASE_IDINDEX(SO);
- CASE_IDINDEX(TE);
- CASE_IDINDEX(TXT);
- CASE_IDINDEX(VF);
- CASE_IDINDEX(WM);
- CASE_IDINDEX(WO);
- CASE_IDINDEX(WS);
- }
-
- BLI_assert(0);
- return -1;
+#define CASE_IDINDEX(_id) \
+ case ID_##_id: \
+ return INDEX_ID_##_id
+
+ switch ((ID_Type)idcode) {
+ CASE_IDINDEX(AC);
+ CASE_IDINDEX(AR);
+ CASE_IDINDEX(BR);
+ CASE_IDINDEX(CA);
+ CASE_IDINDEX(CF);
+ CASE_IDINDEX(CU);
+ CASE_IDINDEX(GD);
+ CASE_IDINDEX(GR);
+ CASE_IDINDEX(IM);
+ CASE_IDINDEX(KE);
+ CASE_IDINDEX(IP);
+ CASE_IDINDEX(LA);
+ CASE_IDINDEX(LI);
+ CASE_IDINDEX(LS);
+ CASE_IDINDEX(LT);
+ CASE_IDINDEX(MA);
+ CASE_IDINDEX(MB);
+ CASE_IDINDEX(MC);
+ CASE_IDINDEX(ME);
+ CASE_IDINDEX(MSK);
+ CASE_IDINDEX(NT);
+ CASE_IDINDEX(OB);
+ CASE_IDINDEX(PA);
+ CASE_IDINDEX(PAL);
+ CASE_IDINDEX(PC);
+ CASE_IDINDEX(LP);
+ CASE_IDINDEX(SCE);
+ CASE_IDINDEX(SCR);
+ CASE_IDINDEX(SPK);
+ CASE_IDINDEX(SO);
+ CASE_IDINDEX(TE);
+ CASE_IDINDEX(TXT);
+ CASE_IDINDEX(VF);
+ CASE_IDINDEX(WM);
+ CASE_IDINDEX(WO);
+ CASE_IDINDEX(WS);
+ }
+
+ BLI_assert(0);
+ return -1;
#undef CASE_IDINDEX
}
@@ -322,49 +328,51 @@ int BKE_idcode_to_index(const short idcode)
*/
short BKE_idcode_from_index(const int index)
{
-#define CASE_IDCODE(_id) case INDEX_ID_##_id: return ID_##_id
-
- switch (index) {
- CASE_IDCODE(AC);
- CASE_IDCODE(AR);
- CASE_IDCODE(BR);
- CASE_IDCODE(CA);
- CASE_IDCODE(CF);
- CASE_IDCODE(CU);
- CASE_IDCODE(GD);
- CASE_IDCODE(GR);
- CASE_IDCODE(IM);
- CASE_IDCODE(KE);
- CASE_IDCODE(IP);
- CASE_IDCODE(LA);
- CASE_IDCODE(LI);
- CASE_IDCODE(LS);
- CASE_IDCODE(LT);
- CASE_IDCODE(MA);
- CASE_IDCODE(MB);
- CASE_IDCODE(MC);
- CASE_IDCODE(ME);
- CASE_IDCODE(MSK);
- CASE_IDCODE(NT);
- CASE_IDCODE(OB);
- CASE_IDCODE(PA);
- CASE_IDCODE(PAL);
- CASE_IDCODE(PC);
- CASE_IDCODE(LP);
- CASE_IDCODE(SCE);
- CASE_IDCODE(SCR);
- CASE_IDCODE(SPK);
- CASE_IDCODE(SO);
- CASE_IDCODE(TE);
- CASE_IDCODE(TXT);
- CASE_IDCODE(VF);
- CASE_IDCODE(WM);
- CASE_IDCODE(WO);
- CASE_IDCODE(WS);
- }
-
- BLI_assert(0);
- return -1;
+#define CASE_IDCODE(_id) \
+ case INDEX_ID_##_id: \
+ return ID_##_id
+
+ switch (index) {
+ CASE_IDCODE(AC);
+ CASE_IDCODE(AR);
+ CASE_IDCODE(BR);
+ CASE_IDCODE(CA);
+ CASE_IDCODE(CF);
+ CASE_IDCODE(CU);
+ CASE_IDCODE(GD);
+ CASE_IDCODE(GR);
+ CASE_IDCODE(IM);
+ CASE_IDCODE(KE);
+ CASE_IDCODE(IP);
+ CASE_IDCODE(LA);
+ CASE_IDCODE(LI);
+ CASE_IDCODE(LS);
+ CASE_IDCODE(LT);
+ CASE_IDCODE(MA);
+ CASE_IDCODE(MB);
+ CASE_IDCODE(MC);
+ CASE_IDCODE(ME);
+ CASE_IDCODE(MSK);
+ CASE_IDCODE(NT);
+ CASE_IDCODE(OB);
+ CASE_IDCODE(PA);
+ CASE_IDCODE(PAL);
+ CASE_IDCODE(PC);
+ CASE_IDCODE(LP);
+ CASE_IDCODE(SCE);
+ CASE_IDCODE(SCR);
+ CASE_IDCODE(SPK);
+ CASE_IDCODE(SO);
+ CASE_IDCODE(TE);
+ CASE_IDCODE(TXT);
+ CASE_IDCODE(VF);
+ CASE_IDCODE(WM);
+ CASE_IDCODE(WO);
+ CASE_IDCODE(WS);
+ }
+
+ BLI_assert(0);
+ return -1;
#undef CASE_IDCODE
}
@@ -378,9 +386,9 @@ short BKE_idcode_from_index(const int index)
*/
const char *BKE_idcode_to_name_plural(short idcode)
{
- IDType *idt = idtype_from_code(idcode);
- BLI_assert(idt);
- return idt ? idt->plural : NULL;
+ IDType *idt = idtype_from_code(idcode);
+ BLI_assert(idt);
+ return idt ? idt->plural : NULL;
}
/**
@@ -391,9 +399,9 @@ const char *BKE_idcode_to_name_plural(short idcode)
*/
const char *BKE_idcode_to_translation_context(short idcode)
{
- IDType *idt = idtype_from_code(idcode);
- BLI_assert(idt);
- return idt ? idt->i18n_context : BLT_I18NCONTEXT_DEFAULT;
+ IDType *idt = idtype_from_code(idcode);
+ BLI_assert(idt);
+ return idt ? idt->i18n_context : BLT_I18NCONTEXT_DEFAULT;
}
/**
@@ -404,5 +412,5 @@ const char *BKE_idcode_to_translation_context(short idcode)
*/
short BKE_idcode_iter_step(int *index)
{
- return (*index < ARRAY_SIZE(idtypes)) ? idtypes[(*index)++].code : 0;
+ return (*index < ARRAY_SIZE(idtypes)) ? idtypes[(*index)++].code : 0;
}
diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c
index 0d77ee21b76..378d551916c 100644
--- a/source/blender/blenkernel/intern/idprop.c
+++ b/source/blender/blenkernel/intern/idprop.c
@@ -52,18 +52,17 @@ static CLG_LogRef LOG = {"bke.idprop"};
/*local size table.*/
static size_t idp_size_table[] = {
- 1, /*strings*/
- sizeof(int),
- sizeof(float),
- sizeof(float) * 3, /*Vector type, deprecated*/
- sizeof(float) * 16, /*Matrix type, deprecated*/
- 0, /*arrays don't have a fixed size*/
- sizeof(ListBase), /*Group type*/
- sizeof(void *),
- sizeof(double),
+ 1, /*strings*/
+ sizeof(int),
+ sizeof(float),
+ sizeof(float) * 3, /*Vector type, deprecated*/
+ sizeof(float) * 16, /*Matrix type, deprecated*/
+ 0, /*arrays don't have a fixed size*/
+ sizeof(ListBase), /*Group type*/
+ sizeof(void *),
+ sizeof(double),
};
-
/* -------------------------------------------------------------------- */
/* Array Functions */
@@ -80,246 +79,244 @@ static size_t idp_size_table[] = {
*/
IDProperty *IDP_NewIDPArray(const char *name)
{
- IDProperty *prop = MEM_callocN(sizeof(IDProperty), "IDProperty prop array");
- prop->type = IDP_IDPARRAY;
- prop->len = 0;
- BLI_strncpy(prop->name, name, MAX_IDPROP_NAME);
+ IDProperty *prop = MEM_callocN(sizeof(IDProperty), "IDProperty prop array");
+ prop->type = IDP_IDPARRAY;
+ prop->len = 0;
+ BLI_strncpy(prop->name, name, MAX_IDPROP_NAME);
- return prop;
+ return prop;
}
IDProperty *IDP_CopyIDPArray(const IDProperty *array, const int flag)
{
- /* don't use MEM_dupallocN because this may be part of an array */
- IDProperty *narray, *tmp;
- int i;
-
- BLI_assert(array->type == IDP_IDPARRAY);
-
- narray = MEM_mallocN(sizeof(IDProperty), __func__);
- *narray = *array;
-
- narray->data.pointer = MEM_dupallocN(array->data.pointer);
- for (i = 0; i < narray->len; i++) {
- /* ok, the copy functions always allocate a new structure,
- * which doesn't work here. instead, simply copy the
- * contents of the new structure into the array cell,
- * then free it. this makes for more maintainable
- * code than simply reimplementing the copy functions
- * in this loop.*/
- tmp = IDP_CopyProperty_ex(GETPROP(narray, i), flag);
- memcpy(GETPROP(narray, i), tmp, sizeof(IDProperty));
- MEM_freeN(tmp);
- }
-
- return narray;
+ /* don't use MEM_dupallocN because this may be part of an array */
+ IDProperty *narray, *tmp;
+ int i;
+
+ BLI_assert(array->type == IDP_IDPARRAY);
+
+ narray = MEM_mallocN(sizeof(IDProperty), __func__);
+ *narray = *array;
+
+ narray->data.pointer = MEM_dupallocN(array->data.pointer);
+ for (i = 0; i < narray->len; i++) {
+ /* ok, the copy functions always allocate a new structure,
+ * which doesn't work here. instead, simply copy the
+ * contents of the new structure into the array cell,
+ * then free it. this makes for more maintainable
+ * code than simply reimplementing the copy functions
+ * in this loop.*/
+ tmp = IDP_CopyProperty_ex(GETPROP(narray, i), flag);
+ memcpy(GETPROP(narray, i), tmp, sizeof(IDProperty));
+ MEM_freeN(tmp);
+ }
+
+ return narray;
}
static void IDP_FreeIDPArray(IDProperty *prop, const bool do_id_user)
{
- int i;
+ int i;
- BLI_assert(prop->type == IDP_IDPARRAY);
+ BLI_assert(prop->type == IDP_IDPARRAY);
- for (i = 0; i < prop->len; i++)
- IDP_FreeProperty_ex(GETPROP(prop, i), do_id_user);
+ for (i = 0; i < prop->len; i++)
+ IDP_FreeProperty_ex(GETPROP(prop, i), do_id_user);
- if (prop->data.pointer)
- MEM_freeN(prop->data.pointer);
+ if (prop->data.pointer)
+ MEM_freeN(prop->data.pointer);
}
/* shallow copies item */
void IDP_SetIndexArray(IDProperty *prop, int index, IDProperty *item)
{
- IDProperty *old;
+ IDProperty *old;
- BLI_assert(prop->type == IDP_IDPARRAY);
+ BLI_assert(prop->type == IDP_IDPARRAY);
- if (index >= prop->len || index < 0)
- return;
+ if (index >= prop->len || index < 0)
+ return;
- old = GETPROP(prop, index);
- if (item != old) {
- IDP_FreeProperty(old);
+ old = GETPROP(prop, index);
+ if (item != old) {
+ IDP_FreeProperty(old);
- memcpy(old, item, sizeof(IDProperty));
- }
+ memcpy(old, item, sizeof(IDProperty));
+ }
}
IDProperty *IDP_GetIndexArray(IDProperty *prop, int index)
{
- BLI_assert(prop->type == IDP_IDPARRAY);
+ BLI_assert(prop->type == IDP_IDPARRAY);
- return GETPROP(prop, index);
+ return GETPROP(prop, index);
}
void IDP_AppendArray(IDProperty *prop, IDProperty *item)
{
- BLI_assert(prop->type == IDP_IDPARRAY);
+ BLI_assert(prop->type == IDP_IDPARRAY);
- IDP_ResizeIDPArray(prop, prop->len + 1);
- IDP_SetIndexArray(prop, prop->len - 1, item);
+ IDP_ResizeIDPArray(prop, prop->len + 1);
+ IDP_SetIndexArray(prop, prop->len - 1, item);
}
void IDP_ResizeIDPArray(IDProperty *prop, int newlen)
{
- int newsize;
-
- BLI_assert(prop->type == IDP_IDPARRAY);
-
- /* first check if the array buffer size has room */
- if (newlen <= prop->totallen) {
- if (newlen < prop->len && prop->totallen - newlen < IDP_ARRAY_REALLOC_LIMIT) {
- int i;
-
- for (i = newlen; i < prop->len; i++)
- IDP_FreeProperty(GETPROP(prop, i));
-
- prop->len = newlen;
- return;
- }
- else if (newlen >= prop->len) {
- prop->len = newlen;
- return;
- }
- }
-
- /* free trailing items */
- if (newlen < prop->len) {
- /* newlen is smaller */
- int i;
- for (i = newlen; i < prop->len; i++) {
- IDP_FreeProperty(GETPROP(prop, i));
- }
- }
-
- /* - Note: This code comes from python, here's the corresponding comment. - */
- /* This over-allocates proportional to the list size, making room
- * for additional growth. The over-allocation is mild, but is
- * enough to give linear-time amortized behavior over a long
- * sequence of appends() in the presence of a poorly-performing
- * system realloc().
- * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
- */
- newsize = newlen;
- newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize;
- prop->data.pointer = MEM_recallocN(prop->data.pointer, sizeof(IDProperty) * (size_t)newsize);
- prop->len = newlen;
- prop->totallen = newsize;
+ int newsize;
+
+ BLI_assert(prop->type == IDP_IDPARRAY);
+
+ /* first check if the array buffer size has room */
+ if (newlen <= prop->totallen) {
+ if (newlen < prop->len && prop->totallen - newlen < IDP_ARRAY_REALLOC_LIMIT) {
+ int i;
+
+ for (i = newlen; i < prop->len; i++)
+ IDP_FreeProperty(GETPROP(prop, i));
+
+ prop->len = newlen;
+ return;
+ }
+ else if (newlen >= prop->len) {
+ prop->len = newlen;
+ return;
+ }
+ }
+
+ /* free trailing items */
+ if (newlen < prop->len) {
+ /* newlen is smaller */
+ int i;
+ for (i = newlen; i < prop->len; i++) {
+ IDP_FreeProperty(GETPROP(prop, i));
+ }
+ }
+
+ /* - Note: This code comes from python, here's the corresponding comment. - */
+ /* This over-allocates proportional to the list size, making room
+ * for additional growth. The over-allocation is mild, but is
+ * enough to give linear-time amortized behavior over a long
+ * sequence of appends() in the presence of a poorly-performing
+ * system realloc().
+ * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
+ */
+ newsize = newlen;
+ newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize;
+ prop->data.pointer = MEM_recallocN(prop->data.pointer, sizeof(IDProperty) * (size_t)newsize);
+ prop->len = newlen;
+ prop->totallen = newsize;
}
/* ----------- Numerical Array Type ----------- */
static void idp_resize_group_array(IDProperty *prop, int newlen, void *newarr)
{
- if (prop->subtype != IDP_GROUP)
- return;
-
- if (newlen >= prop->len) {
- /* bigger */
- IDProperty **array = newarr;
- IDPropertyTemplate val;
- int a;
-
- for (a = prop->len; a < newlen; a++) {
- val.i = 0; /* silence MSVC warning about uninitialized var when debugging */
- array[a] = IDP_New(IDP_GROUP, &val, "IDP_ResizeArray group");
- }
- }
- else {
- /* smaller */
- IDProperty **array = prop->data.pointer;
- int a;
-
- for (a = newlen; a < prop->len; a++) {
- IDP_FreeProperty(array[a]);
- MEM_freeN(array[a]);
- }
- }
+ if (prop->subtype != IDP_GROUP)
+ return;
+
+ if (newlen >= prop->len) {
+ /* bigger */
+ IDProperty **array = newarr;
+ IDPropertyTemplate val;
+ int a;
+
+ for (a = prop->len; a < newlen; a++) {
+ val.i = 0; /* silence MSVC warning about uninitialized var when debugging */
+ array[a] = IDP_New(IDP_GROUP, &val, "IDP_ResizeArray group");
+ }
+ }
+ else {
+ /* smaller */
+ IDProperty **array = prop->data.pointer;
+ int a;
+
+ for (a = newlen; a < prop->len; a++) {
+ IDP_FreeProperty(array[a]);
+ MEM_freeN(array[a]);
+ }
+ }
}
/*this function works for strings too!*/
void IDP_ResizeArray(IDProperty *prop, int newlen)
{
- int newsize;
- const bool is_grow = newlen >= prop->len;
-
- /* first check if the array buffer size has room */
- if (newlen <= prop->totallen && prop->totallen - newlen < IDP_ARRAY_REALLOC_LIMIT) {
- idp_resize_group_array(prop, newlen, prop->data.pointer);
- prop->len = newlen;
- return;
- }
-
- /* - Note: This code comes from python, here's the corresponding comment. - */
- /* This over-allocates proportional to the list size, making room
- * for additional growth. The over-allocation is mild, but is
- * enough to give linear-time amortized behavior over a long
- * sequence of appends() in the presence of a poorly-performing
- * system realloc().
- * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
- */
- newsize = newlen;
- newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize;
-
- if (is_grow == false)
- idp_resize_group_array(prop, newlen, prop->data.pointer);
-
- prop->data.pointer = MEM_recallocN(
- prop->data.pointer, idp_size_table[(int)prop->subtype] * (size_t)newsize);
-
- if (is_grow == true)
- idp_resize_group_array(prop, newlen, prop->data.pointer);
-
- prop->len = newlen;
- prop->totallen = newsize;
+ int newsize;
+ const bool is_grow = newlen >= prop->len;
+
+ /* first check if the array buffer size has room */
+ if (newlen <= prop->totallen && prop->totallen - newlen < IDP_ARRAY_REALLOC_LIMIT) {
+ idp_resize_group_array(prop, newlen, prop->data.pointer);
+ prop->len = newlen;
+ return;
+ }
+
+ /* - Note: This code comes from python, here's the corresponding comment. - */
+ /* This over-allocates proportional to the list size, making room
+ * for additional growth. The over-allocation is mild, but is
+ * enough to give linear-time amortized behavior over a long
+ * sequence of appends() in the presence of a poorly-performing
+ * system realloc().
+ * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
+ */
+ newsize = newlen;
+ newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize;
+
+ if (is_grow == false)
+ idp_resize_group_array(prop, newlen, prop->data.pointer);
+
+ prop->data.pointer = MEM_recallocN(prop->data.pointer,
+ idp_size_table[(int)prop->subtype] * (size_t)newsize);
+
+ if (is_grow == true)
+ idp_resize_group_array(prop, newlen, prop->data.pointer);
+
+ prop->len = newlen;
+ prop->totallen = newsize;
}
void IDP_FreeArray(IDProperty *prop)
{
- if (prop->data.pointer) {
- idp_resize_group_array(prop, 0, NULL);
- MEM_freeN(prop->data.pointer);
- }
+ if (prop->data.pointer) {
+ idp_resize_group_array(prop, 0, NULL);
+ MEM_freeN(prop->data.pointer);
+ }
}
-
static IDProperty *idp_generic_copy(const IDProperty *prop, const int UNUSED(flag))
{
- IDProperty *newp = MEM_callocN(sizeof(IDProperty), __func__);
+ IDProperty *newp = MEM_callocN(sizeof(IDProperty), __func__);
- BLI_strncpy(newp->name, prop->name, MAX_IDPROP_NAME);
- newp->type = prop->type;
- newp->flag = prop->flag;
- newp->data.val = prop->data.val;
- newp->data.val2 = prop->data.val2;
+ BLI_strncpy(newp->name, prop->name, MAX_IDPROP_NAME);
+ newp->type = prop->type;
+ newp->flag = prop->flag;
+ newp->data.val = prop->data.val;
+ newp->data.val2 = prop->data.val2;
- return newp;
+ return newp;
}
static IDProperty *IDP_CopyArray(const IDProperty *prop, const int flag)
{
- IDProperty *newp = idp_generic_copy(prop, flag);
+ IDProperty *newp = idp_generic_copy(prop, flag);
- if (prop->data.pointer) {
- newp->data.pointer = MEM_dupallocN(prop->data.pointer);
+ if (prop->data.pointer) {
+ newp->data.pointer = MEM_dupallocN(prop->data.pointer);
- if (prop->type == IDP_GROUP) {
- IDProperty **array = newp->data.pointer;
- int a;
+ if (prop->type == IDP_GROUP) {
+ IDProperty **array = newp->data.pointer;
+ int a;
- for (a = 0; a < prop->len; a++)
- array[a] = IDP_CopyProperty_ex(array[a], flag);
- }
- }
- newp->len = prop->len;
- newp->subtype = prop->subtype;
- newp->totallen = prop->totallen;
+ for (a = 0; a < prop->len; a++)
+ array[a] = IDP_CopyProperty_ex(array[a], flag);
+ }
+ }
+ newp->len = prop->len;
+ newp->subtype = prop->subtype;
+ newp->totallen = prop->totallen;
- return newp;
+ return newp;
}
/** \} */
-
/* -------------------------------------------------------------------- */
/* String Functions */
@@ -335,105 +332,103 @@ static IDProperty *IDP_CopyArray(const IDProperty *prop, const int flag)
*/
IDProperty *IDP_NewString(const char *st, const char *name, int maxlen)
{
- IDProperty *prop = MEM_callocN(sizeof(IDProperty), "IDProperty string");
-
- if (st == NULL) {
- prop->data.pointer = MEM_mallocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1");
- *IDP_String(prop) = '\0';
- prop->totallen = DEFAULT_ALLOC_FOR_NULL_STRINGS;
- prop->len = 1; /* NULL string, has len of 1 to account for null byte. */
- }
- else {
- /* include null terminator '\0' */
- int stlen = (int)strlen(st) + 1;
-
- if (maxlen > 0 && maxlen < stlen)
- stlen = maxlen;
-
- prop->data.pointer = MEM_mallocN((size_t)stlen, "id property string 2");
- prop->len = prop->totallen = stlen;
- BLI_strncpy(prop->data.pointer, st, (size_t)stlen);
- }
-
- prop->type = IDP_STRING;
- BLI_strncpy(prop->name, name, MAX_IDPROP_NAME);
-
- return prop;
+ IDProperty *prop = MEM_callocN(sizeof(IDProperty), "IDProperty string");
+
+ if (st == NULL) {
+ prop->data.pointer = MEM_mallocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1");
+ *IDP_String(prop) = '\0';
+ prop->totallen = DEFAULT_ALLOC_FOR_NULL_STRINGS;
+ prop->len = 1; /* NULL string, has len of 1 to account for null byte. */
+ }
+ else {
+ /* include null terminator '\0' */
+ int stlen = (int)strlen(st) + 1;
+
+ if (maxlen > 0 && maxlen < stlen)
+ stlen = maxlen;
+
+ prop->data.pointer = MEM_mallocN((size_t)stlen, "id property string 2");
+ prop->len = prop->totallen = stlen;
+ BLI_strncpy(prop->data.pointer, st, (size_t)stlen);
+ }
+
+ prop->type = IDP_STRING;
+ BLI_strncpy(prop->name, name, MAX_IDPROP_NAME);
+
+ return prop;
}
static IDProperty *IDP_CopyString(const IDProperty *prop, const int flag)
{
- IDProperty *newp;
+ IDProperty *newp;
- BLI_assert(prop->type == IDP_STRING);
- newp = idp_generic_copy(prop, flag);
+ BLI_assert(prop->type == IDP_STRING);
+ newp = idp_generic_copy(prop, flag);
- if (prop->data.pointer)
- newp->data.pointer = MEM_dupallocN(prop->data.pointer);
- newp->len = prop->len;
- newp->subtype = prop->subtype;
- newp->totallen = prop->totallen;
+ if (prop->data.pointer)
+ newp->data.pointer = MEM_dupallocN(prop->data.pointer);
+ newp->len = prop->len;
+ newp->subtype = prop->subtype;
+ newp->totallen = prop->totallen;
- return newp;
+ return newp;
}
-
void IDP_AssignString(IDProperty *prop, const char *st, int maxlen)
{
- int stlen;
-
- BLI_assert(prop->type == IDP_STRING);
- stlen = (int)strlen(st);
- if (maxlen > 0 && maxlen < stlen)
- stlen = maxlen;
-
- if (prop->subtype == IDP_STRING_SUB_BYTE) {
- IDP_ResizeArray(prop, stlen);
- memcpy(prop->data.pointer, st, (size_t)stlen);
- }
- else {
- stlen++;
- IDP_ResizeArray(prop, stlen);
- BLI_strncpy(prop->data.pointer, st, (size_t)stlen);
- }
+ int stlen;
+
+ BLI_assert(prop->type == IDP_STRING);
+ stlen = (int)strlen(st);
+ if (maxlen > 0 && maxlen < stlen)
+ stlen = maxlen;
+
+ if (prop->subtype == IDP_STRING_SUB_BYTE) {
+ IDP_ResizeArray(prop, stlen);
+ memcpy(prop->data.pointer, st, (size_t)stlen);
+ }
+ else {
+ stlen++;
+ IDP_ResizeArray(prop, stlen);
+ BLI_strncpy(prop->data.pointer, st, (size_t)stlen);
+ }
}
void IDP_ConcatStringC(IDProperty *prop, const char *st)
{
- int newlen;
+ int newlen;
- BLI_assert(prop->type == IDP_STRING);
+ BLI_assert(prop->type == IDP_STRING);
- newlen = prop->len + (int)strlen(st);
- /* we have to remember that prop->len includes the null byte for strings.
- * so there's no need to add +1 to the resize function.*/
- IDP_ResizeArray(prop, newlen);
- strcat(prop->data.pointer, st);
+ newlen = prop->len + (int)strlen(st);
+ /* we have to remember that prop->len includes the null byte for strings.
+ * so there's no need to add +1 to the resize function.*/
+ IDP_ResizeArray(prop, newlen);
+ strcat(prop->data.pointer, st);
}
void IDP_ConcatString(IDProperty *str1, IDProperty *append)
{
- int newlen;
+ int newlen;
- BLI_assert(append->type == IDP_STRING);
+ BLI_assert(append->type == IDP_STRING);
- /* since ->len for strings includes the NULL byte, we have to subtract one or
- * we'll get an extra null byte after each concatenation operation.*/
- newlen = str1->len + append->len - 1;
- IDP_ResizeArray(str1, newlen);
- strcat(str1->data.pointer, append->data.pointer);
+ /* since ->len for strings includes the NULL byte, we have to subtract one or
+ * we'll get an extra null byte after each concatenation operation.*/
+ newlen = str1->len + append->len - 1;
+ IDP_ResizeArray(str1, newlen);
+ strcat(str1->data.pointer, append->data.pointer);
}
void IDP_FreeString(IDProperty *prop)
{
- BLI_assert(prop->type == IDP_STRING);
+ BLI_assert(prop->type == IDP_STRING);
- if (prop->data.pointer)
- MEM_freeN(prop->data.pointer);
+ if (prop->data.pointer)
+ MEM_freeN(prop->data.pointer);
}
/** \} */
-
/* -------------------------------------------------------------------- */
/* ID Type */
@@ -442,22 +437,21 @@ void IDP_FreeString(IDProperty *prop)
static IDProperty *IDP_CopyID(const IDProperty *prop, const int flag)
{
- IDProperty *newp;
+ IDProperty *newp;
- BLI_assert(prop->type == IDP_ID);
- newp = idp_generic_copy(prop, flag);
+ BLI_assert(prop->type == IDP_ID);
+ newp = idp_generic_copy(prop, flag);
- newp->data.pointer = prop->data.pointer;
- if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- id_us_plus(IDP_Id(newp));
- }
+ newp->data.pointer = prop->data.pointer;
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id_us_plus(IDP_Id(newp));
+ }
- return newp;
+ return newp;
}
/** \} */
-
/* -------------------------------------------------------------------- */
/* Group Functions */
@@ -469,77 +463,76 @@ static IDProperty *IDP_CopyID(const IDProperty *prop, const int flag)
*/
static IDProperty *IDP_CopyGroup(const IDProperty *prop, const int flag)
{
- IDProperty *newp, *link;
+ IDProperty *newp, *link;
- BLI_assert(prop->type == IDP_GROUP);
- newp = idp_generic_copy(prop, flag);
- newp->len = prop->len;
- newp->subtype = prop->subtype;
+ BLI_assert(prop->type == IDP_GROUP);
+ newp = idp_generic_copy(prop, flag);
+ newp->len = prop->len;
+ newp->subtype = prop->subtype;
- for (link = prop->data.group.first; link; link = link->next) {
- BLI_addtail(&newp->data.group, IDP_CopyProperty_ex(link, flag));
- }
+ for (link = prop->data.group.first; link; link = link->next) {
+ BLI_addtail(&newp->data.group, IDP_CopyProperty_ex(link, flag));
+ }
- return newp;
+ return newp;
}
/* use for syncing proxies.
* When values name and types match, copy the values, else ignore */
void IDP_SyncGroupValues(IDProperty *dest, const IDProperty *src)
{
- IDProperty *other, *prop;
-
- BLI_assert(dest->type == IDP_GROUP);
- BLI_assert(src->type == IDP_GROUP);
-
- for (prop = src->data.group.first; prop; prop = prop->next) {
- other = BLI_findstring(&dest->data.group, prop->name, offsetof(IDProperty, name));
- if (other && prop->type == other->type) {
- switch (prop->type) {
- case IDP_INT:
- case IDP_FLOAT:
- case IDP_DOUBLE:
- other->data = prop->data;
- break;
- case IDP_GROUP:
- IDP_SyncGroupValues(other, prop);
- break;
- default:
- {
- BLI_insertlinkreplace(&dest->data.group, other, IDP_CopyProperty(prop));
- IDP_FreeProperty(other);
- MEM_freeN(other);
- break;
- }
- }
- }
- }
+ IDProperty *other, *prop;
+
+ BLI_assert(dest->type == IDP_GROUP);
+ BLI_assert(src->type == IDP_GROUP);
+
+ for (prop = src->data.group.first; prop; prop = prop->next) {
+ other = BLI_findstring(&dest->data.group, prop->name, offsetof(IDProperty, name));
+ if (other && prop->type == other->type) {
+ switch (prop->type) {
+ case IDP_INT:
+ case IDP_FLOAT:
+ case IDP_DOUBLE:
+ other->data = prop->data;
+ break;
+ case IDP_GROUP:
+ IDP_SyncGroupValues(other, prop);
+ break;
+ default: {
+ BLI_insertlinkreplace(&dest->data.group, other, IDP_CopyProperty(prop));
+ IDP_FreeProperty(other);
+ MEM_freeN(other);
+ break;
+ }
+ }
+ }
+ }
}
void IDP_SyncGroupTypes(IDProperty *dst, const IDProperty *src, const bool do_arraylen)
{
- IDProperty *prop_dst, *prop_dst_next;
- const IDProperty *prop_src;
-
- for (prop_dst = dst->data.group.first; prop_dst; prop_dst = prop_dst_next) {
- prop_dst_next = prop_dst->next;
- if ((prop_src = IDP_GetPropertyFromGroup((IDProperty *)src, prop_dst->name))) {
- /* check of we should replace? */
- if ((prop_dst->type != prop_src->type || prop_dst->subtype != prop_src->subtype) ||
- (do_arraylen && ELEM(prop_dst->type, IDP_ARRAY, IDP_IDPARRAY) && (prop_src->len != prop_dst->len)))
- {
- BLI_insertlinkreplace(&dst->data.group, prop_dst, IDP_CopyProperty(prop_src));
- IDP_FreeProperty(prop_dst);
- MEM_freeN(prop_dst);
- }
- else if (prop_dst->type == IDP_GROUP) {
- IDP_SyncGroupTypes(prop_dst, prop_src, do_arraylen);
- }
- }
- else {
- IDP_FreeFromGroup(dst, prop_dst);
- }
- }
+ IDProperty *prop_dst, *prop_dst_next;
+ const IDProperty *prop_src;
+
+ for (prop_dst = dst->data.group.first; prop_dst; prop_dst = prop_dst_next) {
+ prop_dst_next = prop_dst->next;
+ if ((prop_src = IDP_GetPropertyFromGroup((IDProperty *)src, prop_dst->name))) {
+ /* check of we should replace? */
+ if ((prop_dst->type != prop_src->type || prop_dst->subtype != prop_src->subtype) ||
+ (do_arraylen && ELEM(prop_dst->type, IDP_ARRAY, IDP_IDPARRAY) &&
+ (prop_src->len != prop_dst->len))) {
+ BLI_insertlinkreplace(&dst->data.group, prop_dst, IDP_CopyProperty(prop_src));
+ IDP_FreeProperty(prop_dst);
+ MEM_freeN(prop_dst);
+ }
+ else if (prop_dst->type == IDP_GROUP) {
+ IDP_SyncGroupTypes(prop_dst, prop_src, do_arraylen);
+ }
+ }
+ else {
+ IDP_FreeFromGroup(dst, prop_dst);
+ }
+ }
}
/**
@@ -547,28 +540,28 @@ void IDP_SyncGroupTypes(IDProperty *dst, const IDProperty *src, const bool do_ar
*/
void IDP_ReplaceGroupInGroup(IDProperty *dest, const IDProperty *src)
{
- IDProperty *loop, *prop;
-
- BLI_assert(dest->type == IDP_GROUP);
- BLI_assert(src->type == IDP_GROUP);
-
- for (prop = src->data.group.first; prop; prop = prop->next) {
- for (loop = dest->data.group.first; loop; loop = loop->next) {
- if (STREQ(loop->name, prop->name)) {
- BLI_insertlinkreplace(&dest->data.group, loop, IDP_CopyProperty(prop));
- IDP_FreeProperty(loop);
- MEM_freeN(loop);
- break;
- }
- }
-
- /* only add at end if not added yet */
- if (loop == NULL) {
- IDProperty *copy = IDP_CopyProperty(prop);
- dest->len++;
- BLI_addtail(&dest->data.group, copy);
- }
- }
+ IDProperty *loop, *prop;
+
+ BLI_assert(dest->type == IDP_GROUP);
+ BLI_assert(src->type == IDP_GROUP);
+
+ for (prop = src->data.group.first; prop; prop = prop->next) {
+ for (loop = dest->data.group.first; loop; loop = loop->next) {
+ if (STREQ(loop->name, prop->name)) {
+ BLI_insertlinkreplace(&dest->data.group, loop, IDP_CopyProperty(prop));
+ IDP_FreeProperty(loop);
+ MEM_freeN(loop);
+ break;
+ }
+ }
+
+ /* only add at end if not added yet */
+ if (loop == NULL) {
+ IDProperty *copy = IDP_CopyProperty(prop);
+ dest->len++;
+ BLI_addtail(&dest->data.group, copy);
+ }
+ }
}
/**
@@ -577,69 +570,72 @@ void IDP_ReplaceGroupInGroup(IDProperty *dest, const IDProperty *src)
*/
void IDP_ReplaceInGroup_ex(IDProperty *group, IDProperty *prop, IDProperty *prop_exist)
{
- BLI_assert(group->type == IDP_GROUP);
- BLI_assert(prop_exist == IDP_GetPropertyFromGroup(group, prop->name));
-
- if (prop_exist != NULL) {
- BLI_insertlinkreplace(&group->data.group, prop_exist, prop);
- IDP_FreeProperty(prop_exist);
- MEM_freeN(prop_exist);
- }
- else {
- group->len++;
- BLI_addtail(&group->data.group, prop);
- }
+ BLI_assert(group->type == IDP_GROUP);
+ BLI_assert(prop_exist == IDP_GetPropertyFromGroup(group, prop->name));
+
+ if (prop_exist != NULL) {
+ BLI_insertlinkreplace(&group->data.group, prop_exist, prop);
+ IDP_FreeProperty(prop_exist);
+ MEM_freeN(prop_exist);
+ }
+ else {
+ group->len++;
+ BLI_addtail(&group->data.group, prop);
+ }
}
void IDP_ReplaceInGroup(IDProperty *group, IDProperty *prop)
{
- IDProperty *prop_exist = IDP_GetPropertyFromGroup(group, prop->name);
+ IDProperty *prop_exist = IDP_GetPropertyFromGroup(group, prop->name);
- IDP_ReplaceInGroup_ex(group, prop, prop_exist);
+ IDP_ReplaceInGroup_ex(group, prop, prop_exist);
}
/**
* If a property is missing in \a dest, add it.
* Do it recursively.
*/
-void IDP_MergeGroup_ex(IDProperty *dest, const IDProperty *src, const bool do_overwrite, const int flag)
+void IDP_MergeGroup_ex(IDProperty *dest,
+ const IDProperty *src,
+ const bool do_overwrite,
+ const int flag)
{
- IDProperty *prop;
-
- BLI_assert(dest->type == IDP_GROUP);
- BLI_assert(src->type == IDP_GROUP);
-
- if (do_overwrite) {
- for (prop = src->data.group.first; prop; prop = prop->next) {
- if (prop->type == IDP_GROUP) {
- IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name);
-
- if (prop_exist != NULL) {
- IDP_MergeGroup_ex(prop_exist, prop, do_overwrite, flag);
- continue;
- }
- }
-
- IDProperty *copy = IDP_CopyProperty_ex(prop, flag);
- IDP_ReplaceInGroup(dest, copy);
- }
- }
- else {
- for (prop = src->data.group.first; prop; prop = prop->next) {
- IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name);
- if (prop_exist != NULL) {
- if (prop->type == IDP_GROUP) {
- IDP_MergeGroup_ex(prop_exist, prop, do_overwrite, flag);
- continue;
- }
- }
- else {
- IDProperty *copy = IDP_CopyProperty_ex(prop, flag);
- dest->len++;
- BLI_addtail(&dest->data.group, copy);
- }
- }
- }
+ IDProperty *prop;
+
+ BLI_assert(dest->type == IDP_GROUP);
+ BLI_assert(src->type == IDP_GROUP);
+
+ if (do_overwrite) {
+ for (prop = src->data.group.first; prop; prop = prop->next) {
+ if (prop->type == IDP_GROUP) {
+ IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name);
+
+ if (prop_exist != NULL) {
+ IDP_MergeGroup_ex(prop_exist, prop, do_overwrite, flag);
+ continue;
+ }
+ }
+
+ IDProperty *copy = IDP_CopyProperty_ex(prop, flag);
+ IDP_ReplaceInGroup(dest, copy);
+ }
+ }
+ else {
+ for (prop = src->data.group.first; prop; prop = prop->next) {
+ IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name);
+ if (prop_exist != NULL) {
+ if (prop->type == IDP_GROUP) {
+ IDP_MergeGroup_ex(prop_exist, prop, do_overwrite, flag);
+ continue;
+ }
+ }
+ else {
+ IDProperty *copy = IDP_CopyProperty_ex(prop, flag);
+ dest->len++;
+ BLI_addtail(&dest->data.group, copy);
+ }
+ }
+ }
}
/**
@@ -648,7 +644,7 @@ void IDP_MergeGroup_ex(IDProperty *dest, const IDProperty *src, const bool do_ov
*/
void IDP_MergeGroup(IDProperty *dest, const IDProperty *src, const bool do_overwrite)
{
- IDP_MergeGroup_ex(dest, src, do_overwrite, 0);
+ IDP_MergeGroup_ex(dest, src, do_overwrite, 0);
}
/**
@@ -668,15 +664,15 @@ void IDP_MergeGroup(IDProperty *dest, const IDProperty *src, const bool do_overw
*/
bool IDP_AddToGroup(IDProperty *group, IDProperty *prop)
{
- BLI_assert(group->type == IDP_GROUP);
+ BLI_assert(group->type == IDP_GROUP);
- if (IDP_GetPropertyFromGroup(group, prop->name) == NULL) {
- group->len++;
- BLI_addtail(&group->data.group, prop);
- return true;
- }
+ if (IDP_GetPropertyFromGroup(group, prop->name) == NULL) {
+ group->len++;
+ BLI_addtail(&group->data.group, prop);
+ return true;
+ }
- return false;
+ return false;
}
/**
@@ -685,15 +681,15 @@ bool IDP_AddToGroup(IDProperty *group, IDProperty *prop)
*/
bool IDP_InsertToGroup(IDProperty *group, IDProperty *previous, IDProperty *pnew)
{
- BLI_assert(group->type == IDP_GROUP);
+ BLI_assert(group->type == IDP_GROUP);
- if (IDP_GetPropertyFromGroup(group, pnew->name) == NULL) {
- group->len++;
- BLI_insertlinkafter(&group->data.group, previous, pnew);
- return true;
- }
+ if (IDP_GetPropertyFromGroup(group, pnew->name) == NULL) {
+ group->len++;
+ BLI_insertlinkafter(&group->data.group, previous, pnew);
+ return true;
+ }
- return false;
+ return false;
}
/**
@@ -705,10 +701,10 @@ bool IDP_InsertToGroup(IDProperty *group, IDProperty *previous, IDProperty *pnew
*/
void IDP_RemoveFromGroup(IDProperty *group, IDProperty *prop)
{
- BLI_assert(group->type == IDP_GROUP);
+ BLI_assert(group->type == IDP_GROUP);
- group->len--;
- BLI_remlink(&group->data.group, prop);
+ group->len--;
+ BLI_remlink(&group->data.group, prop);
}
/**
@@ -716,22 +712,22 @@ void IDP_RemoveFromGroup(IDProperty *group, IDProperty *prop)
*/
void IDP_FreeFromGroup(IDProperty *group, IDProperty *prop)
{
- IDP_RemoveFromGroup(group, prop);
- IDP_FreeProperty(prop);
- MEM_freeN(prop);
+ IDP_RemoveFromGroup(group, prop);
+ IDP_FreeProperty(prop);
+ MEM_freeN(prop);
}
IDProperty *IDP_GetPropertyFromGroup(IDProperty *prop, const char *name)
{
- BLI_assert(prop->type == IDP_GROUP);
+ BLI_assert(prop->type == IDP_GROUP);
- return (IDProperty *)BLI_findstring(&prop->data.group, name, offsetof(IDProperty, name));
+ return (IDProperty *)BLI_findstring(&prop->data.group, name, offsetof(IDProperty, name));
}
/** same as above but ensure type match */
IDProperty *IDP_GetPropertyTypeFromGroup(IDProperty *prop, const char *name, const char type)
{
- IDProperty *idprop = IDP_GetPropertyFromGroup(prop, name);
- return (idprop && idprop->type == type) ? idprop : NULL;
+ IDProperty *idprop = IDP_GetPropertyFromGroup(prop, name);
+ return (idprop && idprop->type == type) ? idprop : NULL;
}
/* Ok, the way things work, Groups free the ID Property structs of their children.
@@ -740,17 +736,16 @@ IDProperty *IDP_GetPropertyTypeFromGroup(IDProperty *prop, const char *name, con
* direct data. */
static void IDP_FreeGroup(IDProperty *prop, const bool do_id_user)
{
- IDProperty *loop;
+ IDProperty *loop;
- BLI_assert(prop->type == IDP_GROUP);
- for (loop = prop->data.group.first; loop; loop = loop->next) {
- IDP_FreeProperty_ex(loop, do_id_user);
- }
- BLI_freelistN(&prop->data.group);
+ BLI_assert(prop->type == IDP_GROUP);
+ for (loop = prop->data.group.first; loop; loop = loop->next) {
+ IDP_FreeProperty_ex(loop, do_id_user);
+ }
+ BLI_freelistN(&prop->data.group);
}
/** \} */
-
/* -------------------------------------------------------------------- */
/* Main Functions */
@@ -758,57 +753,60 @@ static void IDP_FreeGroup(IDProperty *prop, const bool do_id_user)
* \{ */
IDProperty *IDP_CopyProperty_ex(const IDProperty *prop, const int flag)
{
- switch (prop->type) {
- case IDP_GROUP: return IDP_CopyGroup(prop, flag);
- case IDP_STRING: return IDP_CopyString(prop, flag);
- case IDP_ID: return IDP_CopyID(prop, flag);
- case IDP_ARRAY: return IDP_CopyArray(prop, flag);
- case IDP_IDPARRAY: return IDP_CopyIDPArray(prop, flag);
- default: return idp_generic_copy(prop, flag);
- }
+ switch (prop->type) {
+ case IDP_GROUP:
+ return IDP_CopyGroup(prop, flag);
+ case IDP_STRING:
+ return IDP_CopyString(prop, flag);
+ case IDP_ID:
+ return IDP_CopyID(prop, flag);
+ case IDP_ARRAY:
+ return IDP_CopyArray(prop, flag);
+ case IDP_IDPARRAY:
+ return IDP_CopyIDPArray(prop, flag);
+ default:
+ return idp_generic_copy(prop, flag);
+ }
}
IDProperty *IDP_CopyProperty(const IDProperty *prop)
{
- return IDP_CopyProperty_ex(prop, 0);
+ return IDP_CopyProperty_ex(prop, 0);
}
/* Updates ID pointers after an object has been copied */
/* TODO Nuke this once its only user has been correctly converted to use generic ID management from BKE_library! */
void IDP_RelinkProperty(struct IDProperty *prop)
{
- if (!prop)
- return;
-
- switch (prop->type) {
- case IDP_GROUP:
- {
- for (IDProperty *loop = prop->data.group.first; loop; loop = loop->next) {
- IDP_RelinkProperty(loop);
- }
- break;
- }
- case IDP_IDPARRAY:
- {
- IDProperty *idp_array = IDP_Array(prop);
- for (int i = 0; i < prop->len; i++) {
- IDP_RelinkProperty(&idp_array[i]);
- }
- break;
- }
- case IDP_ID:
- {
- ID *id = IDP_Id(prop);
- if (id && id->newid) {
- id_us_min(IDP_Id(prop));
- prop->data.pointer = id->newid;
- id_us_plus(IDP_Id(prop));
- }
- break;
- }
- default:
- break; /* Nothing to do for other IDProp types. */
- }
+ if (!prop)
+ return;
+
+ switch (prop->type) {
+ case IDP_GROUP: {
+ for (IDProperty *loop = prop->data.group.first; loop; loop = loop->next) {
+ IDP_RelinkProperty(loop);
+ }
+ break;
+ }
+ case IDP_IDPARRAY: {
+ IDProperty *idp_array = IDP_Array(prop);
+ for (int i = 0; i < prop->len; i++) {
+ IDP_RelinkProperty(&idp_array[i]);
+ }
+ break;
+ }
+ case IDP_ID: {
+ ID *id = IDP_Id(prop);
+ if (id && id->newid) {
+ id_us_min(IDP_Id(prop));
+ prop->data.pointer = id->newid;
+ id_us_plus(IDP_Id(prop));
+ }
+ break;
+ }
+ default:
+ break; /* Nothing to do for other IDProp types. */
+ }
}
/**
@@ -818,109 +816,110 @@ void IDP_RelinkProperty(struct IDProperty *prop)
*/
IDProperty *IDP_GetProperties(ID *id, const bool create_if_needed)
{
- if (id->properties) {
- return id->properties;
- }
- else {
- if (create_if_needed) {
- id->properties = MEM_callocN(sizeof(IDProperty), "IDProperty");
- id->properties->type = IDP_GROUP;
- /* don't overwrite the data's name and type
- * some functions might need this if they
- * don't have a real ID, should be named elsewhere - Campbell */
- /* strcpy(id->name, "top_level_group");*/
- }
- return id->properties;
- }
+ if (id->properties) {
+ return id->properties;
+ }
+ else {
+ if (create_if_needed) {
+ id->properties = MEM_callocN(sizeof(IDProperty), "IDProperty");
+ id->properties->type = IDP_GROUP;
+ /* don't overwrite the data's name and type
+ * some functions might need this if they
+ * don't have a real ID, should be named elsewhere - Campbell */
+ /* strcpy(id->name, "top_level_group");*/
+ }
+ return id->properties;
+ }
}
/**
* \param is_strict: When false treat missing items as a match */
bool IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const bool is_strict)
{
- if (prop1 == NULL && prop2 == NULL)
- return true;
- else if (prop1 == NULL || prop2 == NULL)
- return is_strict ? false : true;
- else if (prop1->type != prop2->type)
- return false;
-
- switch (prop1->type) {
- case IDP_INT:
- return (IDP_Int(prop1) == IDP_Int(prop2));
- case IDP_FLOAT:
+ if (prop1 == NULL && prop2 == NULL)
+ return true;
+ else if (prop1 == NULL || prop2 == NULL)
+ return is_strict ? false : true;
+ else if (prop1->type != prop2->type)
+ return false;
+
+ switch (prop1->type) {
+ case IDP_INT:
+ return (IDP_Int(prop1) == IDP_Int(prop2));
+ case IDP_FLOAT:
#if !defined(NDEBUG) && defined(WITH_PYTHON)
- {
- float p1 = IDP_Float(prop1);
- float p2 = IDP_Float(prop2);
- if ((p1 != p2) && ((fabsf(p1 - p2) / max_ff(p1, p2)) < 0.001f)) {
- printf("WARNING: Comparing two float properties that have nearly the same value (%f vs. %f)\n", p1, p2);
- printf(" p1: ");
- IDP_print(prop1);
- printf(" p2: ");
- IDP_print(prop2);
- }
- }
+ {
+ float p1 = IDP_Float(prop1);
+ float p2 = IDP_Float(prop2);
+ if ((p1 != p2) && ((fabsf(p1 - p2) / max_ff(p1, p2)) < 0.001f)) {
+ printf(
+ "WARNING: Comparing two float properties that have nearly the same value (%f vs. "
+ "%f)\n",
+ p1,
+ p2);
+ printf(" p1: ");
+ IDP_print(prop1);
+ printf(" p2: ");
+ IDP_print(prop2);
+ }
+ }
#endif
- return (IDP_Float(prop1) == IDP_Float(prop2));
- case IDP_DOUBLE:
- return (IDP_Double(prop1) == IDP_Double(prop2));
- case IDP_STRING:
- {
- return (((prop1->len == prop2->len) &&
- STREQLEN(IDP_String(prop1), IDP_String(prop2), (size_t)prop1->len)));
- }
- case IDP_ARRAY:
- if (prop1->len == prop2->len && prop1->subtype == prop2->subtype) {
- return (memcmp(IDP_Array(prop1),
- IDP_Array(prop2),
- idp_size_table[(int)prop1->subtype] * (size_t)prop1->len) == 0);
- }
- return false;
- case IDP_GROUP:
- {
- IDProperty *link1, *link2;
-
- if (is_strict && prop1->len != prop2->len)
- return false;
-
- for (link1 = prop1->data.group.first; link1; link1 = link1->next) {
- link2 = IDP_GetPropertyFromGroup(prop2, link1->name);
-
- if (!IDP_EqualsProperties_ex(link1, link2, is_strict))
- return false;
- }
-
- return true;
- }
- case IDP_IDPARRAY:
- {
- IDProperty *array1 = IDP_IDPArray(prop1);
- IDProperty *array2 = IDP_IDPArray(prop2);
- int i;
-
- if (prop1->len != prop2->len)
- return false;
-
- for (i = 0; i < prop1->len; i++) {
- if (!IDP_EqualsProperties_ex(&array1[i], &array2[i], is_strict))
- return false;
- }
- return true;
- }
- case IDP_ID:
- return (IDP_Id(prop1) == IDP_Id(prop2));
- default:
- BLI_assert(0);
- break;
- }
-
- return true;
+ return (IDP_Float(prop1) == IDP_Float(prop2));
+ case IDP_DOUBLE:
+ return (IDP_Double(prop1) == IDP_Double(prop2));
+ case IDP_STRING: {
+ return (((prop1->len == prop2->len) &&
+ STREQLEN(IDP_String(prop1), IDP_String(prop2), (size_t)prop1->len)));
+ }
+ case IDP_ARRAY:
+ if (prop1->len == prop2->len && prop1->subtype == prop2->subtype) {
+ return (memcmp(IDP_Array(prop1),
+ IDP_Array(prop2),
+ idp_size_table[(int)prop1->subtype] * (size_t)prop1->len) == 0);
+ }
+ return false;
+ case IDP_GROUP: {
+ IDProperty *link1, *link2;
+
+ if (is_strict && prop1->len != prop2->len)
+ return false;
+
+ for (link1 = prop1->data.group.first; link1; link1 = link1->next) {
+ link2 = IDP_GetPropertyFromGroup(prop2, link1->name);
+
+ if (!IDP_EqualsProperties_ex(link1, link2, is_strict))
+ return false;
+ }
+
+ return true;
+ }
+ case IDP_IDPARRAY: {
+ IDProperty *array1 = IDP_IDPArray(prop1);
+ IDProperty *array2 = IDP_IDPArray(prop2);
+ int i;
+
+ if (prop1->len != prop2->len)
+ return false;
+
+ for (i = 0; i < prop1->len; i++) {
+ if (!IDP_EqualsProperties_ex(&array1[i], &array2[i], is_strict))
+ return false;
+ }
+ return true;
+ }
+ case IDP_ID:
+ return (IDP_Id(prop1) == IDP_Id(prop2));
+ default:
+ BLI_assert(0);
+ break;
+ }
+
+ return true;
}
bool IDP_EqualsProperties(IDProperty *prop1, IDProperty *prop2)
{
- return IDP_EqualsProperties_ex(prop1, prop2, true);
+ return IDP_EqualsProperties_ex(prop1, prop2, true);
}
/**
@@ -952,105 +951,97 @@ bool IDP_EqualsProperties(IDProperty *prop1, IDProperty *prop2)
*/
IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char *name)
{
- IDProperty *prop = NULL;
-
- switch (type) {
- case IDP_INT:
- prop = MEM_callocN(sizeof(IDProperty), "IDProperty int");
- prop->data.val = val->i;
- break;
- case IDP_FLOAT:
- prop = MEM_callocN(sizeof(IDProperty), "IDProperty float");
- *(float *)&prop->data.val = val->f;
- break;
- case IDP_DOUBLE:
- prop = MEM_callocN(sizeof(IDProperty), "IDProperty double");
- *(double *)&prop->data.val = val->d;
- break;
- case IDP_ARRAY:
- {
- /* for now, we only support float and int and double arrays */
- if ( (val->array.type == IDP_FLOAT) ||
- (val->array.type == IDP_INT) ||
- (val->array.type == IDP_DOUBLE) ||
- (val->array.type == IDP_GROUP) )
- {
- prop = MEM_callocN(sizeof(IDProperty), "IDProperty array");
- prop->subtype = val->array.type;
- if (val->array.len) {
- prop->data.pointer = MEM_callocN(
- idp_size_table[val->array.type] * (size_t)val->array.len, "id property array");
- }
- prop->len = prop->totallen = val->array.len;
- break;
- }
- CLOG_ERROR(&LOG, "bad array type.");
- return NULL;
- }
- case IDP_STRING:
- {
- const char *st = val->string.str;
-
- prop = MEM_callocN(sizeof(IDProperty), "IDProperty string");
- if (val->string.subtype == IDP_STRING_SUB_BYTE) {
- /* note, intentionally not null terminated */
- if (st == NULL) {
- prop->data.pointer = MEM_mallocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1");
- *IDP_String(prop) = '\0';
- prop->totallen = DEFAULT_ALLOC_FOR_NULL_STRINGS;
- prop->len = 0;
- }
- else {
- prop->data.pointer = MEM_mallocN((size_t)val->string.len, "id property string 2");
- prop->len = prop->totallen = val->string.len;
- memcpy(prop->data.pointer, st, (size_t)val->string.len);
- }
- prop->subtype = IDP_STRING_SUB_BYTE;
- }
- else {
- if (st == NULL || val->string.len <= 1) {
- prop->data.pointer = MEM_mallocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1");
- *IDP_String(prop) = '\0';
- prop->totallen = DEFAULT_ALLOC_FOR_NULL_STRINGS;
- /* NULL string, has len of 1 to account for null byte. */
- prop->len = 1;
- }
- else {
- BLI_assert((int)val->string.len <= (int)strlen(st) + 1);
- prop->data.pointer = MEM_mallocN((size_t)val->string.len, "id property string 3");
- memcpy(prop->data.pointer, st, (size_t)val->string.len - 1);
- IDP_String(prop)[val->string.len - 1] = '\0';
- prop->len = prop->totallen = val->string.len;
- }
- prop->subtype = IDP_STRING_SUB_UTF8;
- }
- break;
- }
- case IDP_GROUP:
- {
- /* Values are set properly by calloc. */
- prop = MEM_callocN(sizeof(IDProperty), "IDProperty group");
- break;
- }
- case IDP_ID:
- {
- prop = MEM_callocN(sizeof(IDProperty), "IDProperty datablock");
- prop->data.pointer = (void *)val->id;
- prop->type = IDP_ID;
- id_us_plus(IDP_Id(prop));
- break;
- }
- default:
- {
- prop = MEM_callocN(sizeof(IDProperty), "IDProperty array");
- break;
- }
- }
-
- prop->type = type;
- BLI_strncpy(prop->name, name, MAX_IDPROP_NAME);
-
- return prop;
+ IDProperty *prop = NULL;
+
+ switch (type) {
+ case IDP_INT:
+ prop = MEM_callocN(sizeof(IDProperty), "IDProperty int");
+ prop->data.val = val->i;
+ break;
+ case IDP_FLOAT:
+ prop = MEM_callocN(sizeof(IDProperty), "IDProperty float");
+ *(float *)&prop->data.val = val->f;
+ break;
+ case IDP_DOUBLE:
+ prop = MEM_callocN(sizeof(IDProperty), "IDProperty double");
+ *(double *)&prop->data.val = val->d;
+ break;
+ case IDP_ARRAY: {
+ /* for now, we only support float and int and double arrays */
+ if ((val->array.type == IDP_FLOAT) || (val->array.type == IDP_INT) ||
+ (val->array.type == IDP_DOUBLE) || (val->array.type == IDP_GROUP)) {
+ prop = MEM_callocN(sizeof(IDProperty), "IDProperty array");
+ prop->subtype = val->array.type;
+ if (val->array.len) {
+ prop->data.pointer = MEM_callocN(
+ idp_size_table[val->array.type] * (size_t)val->array.len, "id property array");
+ }
+ prop->len = prop->totallen = val->array.len;
+ break;
+ }
+ CLOG_ERROR(&LOG, "bad array type.");
+ return NULL;
+ }
+ case IDP_STRING: {
+ const char *st = val->string.str;
+
+ prop = MEM_callocN(sizeof(IDProperty), "IDProperty string");
+ if (val->string.subtype == IDP_STRING_SUB_BYTE) {
+ /* note, intentionally not null terminated */
+ if (st == NULL) {
+ prop->data.pointer = MEM_mallocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1");
+ *IDP_String(prop) = '\0';
+ prop->totallen = DEFAULT_ALLOC_FOR_NULL_STRINGS;
+ prop->len = 0;
+ }
+ else {
+ prop->data.pointer = MEM_mallocN((size_t)val->string.len, "id property string 2");
+ prop->len = prop->totallen = val->string.len;
+ memcpy(prop->data.pointer, st, (size_t)val->string.len);
+ }
+ prop->subtype = IDP_STRING_SUB_BYTE;
+ }
+ else {
+ if (st == NULL || val->string.len <= 1) {
+ prop->data.pointer = MEM_mallocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1");
+ *IDP_String(prop) = '\0';
+ prop->totallen = DEFAULT_ALLOC_FOR_NULL_STRINGS;
+ /* NULL string, has len of 1 to account for null byte. */
+ prop->len = 1;
+ }
+ else {
+ BLI_assert((int)val->string.len <= (int)strlen(st) + 1);
+ prop->data.pointer = MEM_mallocN((size_t)val->string.len, "id property string 3");
+ memcpy(prop->data.pointer, st, (size_t)val->string.len - 1);
+ IDP_String(prop)[val->string.len - 1] = '\0';
+ prop->len = prop->totallen = val->string.len;
+ }
+ prop->subtype = IDP_STRING_SUB_UTF8;
+ }
+ break;
+ }
+ case IDP_GROUP: {
+ /* Values are set properly by calloc. */
+ prop = MEM_callocN(sizeof(IDProperty), "IDProperty group");
+ break;
+ }
+ case IDP_ID: {
+ prop = MEM_callocN(sizeof(IDProperty), "IDProperty datablock");
+ prop->data.pointer = (void *)val->id;
+ prop->type = IDP_ID;
+ id_us_plus(IDP_Id(prop));
+ break;
+ }
+ default: {
+ prop = MEM_callocN(sizeof(IDProperty), "IDProperty array");
+ break;
+ }
+ }
+
+ prop->type = type;
+ BLI_strncpy(prop->name, name, MAX_IDPROP_NAME);
+
+ return prop;
}
/**
@@ -1059,48 +1050,48 @@ IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char *
*/
void IDP_FreeProperty_ex(IDProperty *prop, const bool do_id_user)
{
- switch (prop->type) {
- case IDP_ARRAY:
- IDP_FreeArray(prop);
- break;
- case IDP_STRING:
- IDP_FreeString(prop);
- break;
- case IDP_GROUP:
- IDP_FreeGroup(prop, do_id_user);
- break;
- case IDP_IDPARRAY:
- IDP_FreeIDPArray(prop, do_id_user);
- break;
- case IDP_ID:
- if (do_id_user) {
- id_us_min(IDP_Id(prop));
- }
- break;
- }
+ switch (prop->type) {
+ case IDP_ARRAY:
+ IDP_FreeArray(prop);
+ break;
+ case IDP_STRING:
+ IDP_FreeString(prop);
+ break;
+ case IDP_GROUP:
+ IDP_FreeGroup(prop, do_id_user);
+ break;
+ case IDP_IDPARRAY:
+ IDP_FreeIDPArray(prop, do_id_user);
+ break;
+ case IDP_ID:
+ if (do_id_user) {
+ id_us_min(IDP_Id(prop));
+ }
+ break;
+ }
}
void IDP_FreeProperty(IDProperty *prop)
{
- IDP_FreeProperty_ex(prop, true);
+ IDP_FreeProperty_ex(prop, true);
}
void IDP_ClearProperty(IDProperty *prop)
{
- IDP_FreeProperty(prop);
- prop->data.pointer = NULL;
- prop->len = prop->totallen = 0;
+ IDP_FreeProperty(prop);
+ prop->data.pointer = NULL;
+ prop->len = prop->totallen = 0;
}
void IDP_Reset(IDProperty *prop, const IDProperty *reference)
{
- if (prop == NULL) {
- return;
- }
- IDP_ClearProperty(prop);
- if (reference != NULL) {
- IDP_MergeGroup(prop, reference, true);
- }
+ if (prop == NULL) {
+ return;
+ }
+ IDP_ClearProperty(prop);
+ if (reference != NULL) {
+ IDP_MergeGroup(prop, reference, true);
+ }
}
/** \} */
diff --git a/source/blender/blenkernel/intern/idprop_utils.c b/source/blender/blenkernel/intern/idprop_utils.c
index ab2df928814..312957c96ce 100644
--- a/source/blender/blenkernel/intern/idprop_utils.c
+++ b/source/blender/blenkernel/intern/idprop_utils.c
@@ -32,7 +32,6 @@
#include "BLI_strict_flags.h"
-
/* -------------------------------------------------------------------- */
/** \name IDProp Repr
*
@@ -43,209 +42,201 @@
* \{ */
struct ReprState {
- void (*str_append_fn)(void *user_data, const char *str, uint str_len);
- void *user_data;
- /* Big enough to format any primitive type. */
- char buf[128];
+ void (*str_append_fn)(void *user_data, const char *str, uint str_len);
+ void *user_data;
+ /* Big enough to format any primitive type. */
+ char buf[128];
};
-static void idp_str_append_escape(struct ReprState *state, const char *str, const uint str_len, bool quote)
+static void idp_str_append_escape(struct ReprState *state,
+ const char *str,
+ const uint str_len,
+ bool quote)
{
- if (quote) {
- state->str_append_fn(state->user_data, "\"", 1);
- }
- uint i_prev = 0, i = 0;
- while (i < str_len) {
- const char c = str[i];
- if (c == '"') {
- if (i_prev != i) {
- state->str_append_fn(state->user_data, str + i_prev, i - i_prev);
- }
- state->str_append_fn(state->user_data, "\\\"", 2);
- i_prev = i + 1;
- }
- else if (c == '\\') {
- if (i_prev != i) {
- state->str_append_fn(state->user_data, str + i_prev, i - i_prev);
- }
- state->str_append_fn(state->user_data, "\\\\", 2);
- i_prev = i + 1;
- }
- else if (c < 32) {
- if (i_prev != i) {
- state->str_append_fn(state->user_data, str + i_prev, i - i_prev);
- }
- char buf[5];
- uint len = (uint)BLI_snprintf_rlen(buf, sizeof(buf), "\\x%02x", c);
- BLI_assert(len == 4);
- state->str_append_fn(state->user_data, buf, len);
- i_prev = i + 1;
- }
- i++;
- }
- state->str_append_fn(state->user_data, str + i_prev, i - i_prev);
- if (quote) {
- state->str_append_fn(state->user_data, "\"", 1);
- }
+ if (quote) {
+ state->str_append_fn(state->user_data, "\"", 1);
+ }
+ uint i_prev = 0, i = 0;
+ while (i < str_len) {
+ const char c = str[i];
+ if (c == '"') {
+ if (i_prev != i) {
+ state->str_append_fn(state->user_data, str + i_prev, i - i_prev);
+ }
+ state->str_append_fn(state->user_data, "\\\"", 2);
+ i_prev = i + 1;
+ }
+ else if (c == '\\') {
+ if (i_prev != i) {
+ state->str_append_fn(state->user_data, str + i_prev, i - i_prev);
+ }
+ state->str_append_fn(state->user_data, "\\\\", 2);
+ i_prev = i + 1;
+ }
+ else if (c < 32) {
+ if (i_prev != i) {
+ state->str_append_fn(state->user_data, str + i_prev, i - i_prev);
+ }
+ char buf[5];
+ uint len = (uint)BLI_snprintf_rlen(buf, sizeof(buf), "\\x%02x", c);
+ BLI_assert(len == 4);
+ state->str_append_fn(state->user_data, buf, len);
+ i_prev = i + 1;
+ }
+ i++;
+ }
+ state->str_append_fn(state->user_data, str + i_prev, i - i_prev);
+ if (quote) {
+ state->str_append_fn(state->user_data, "\"", 1);
+ }
}
static void idp_repr_fn_recursive(struct ReprState *state, const IDProperty *prop)
{
- /* Note: 'strlen' will be calculated at compile time for literals. */
-#define STR_APPEND_STR(str) state->str_append_fn(state->user_data, str, (uint)strlen(str))
+ /* Note: 'strlen' will be calculated at compile time for literals. */
+#define STR_APPEND_STR(str) state->str_append_fn(state->user_data, str, (uint)strlen(str))
-#define STR_APPEND_STR_QUOTE(str) idp_str_append_escape(state, str, (uint)strlen(str), true)
-#define STR_APPEND_STR_LEN_QUOTE(str, str_len) idp_str_append_escape(state, str, str_len, true)
+#define STR_APPEND_STR_QUOTE(str) idp_str_append_escape(state, str, (uint)strlen(str), true)
+#define STR_APPEND_STR_LEN_QUOTE(str, str_len) idp_str_append_escape(state, str, str_len, true)
#define STR_APPEND_FMT(format, ...) \
- state->str_append_fn( \
- state->user_data, \
- state->buf, \
- (uint)BLI_snprintf_rlen(state->buf, sizeof(state->buf), format, __VA_ARGS__))
-
- switch (prop->type) {
- case IDP_STRING:
- {
- STR_APPEND_STR_LEN_QUOTE(IDP_String(prop), (uint)MAX2(0, prop->len - 1));
- break;
- }
- case IDP_INT:
- {
- STR_APPEND_FMT("%d", IDP_Int(prop));
- break;
- }
- case IDP_FLOAT:
- {
- STR_APPEND_FMT("%g", (double)IDP_Float(prop));
- break;
- }
- case IDP_DOUBLE:
- {
- STR_APPEND_FMT("%g", IDP_Double(prop));
- break;
- }
- case IDP_ARRAY:
- {
- STR_APPEND_STR("[");
- switch (prop->subtype) {
- case IDP_INT:
- for (const int *v = prop->data.pointer, *v_end = v + prop->len; v != v_end; v++) {
- if (v != prop->data.pointer) {
- STR_APPEND_STR(", ");
- }
- STR_APPEND_FMT("%d", *v);
- }
- break;
- case IDP_FLOAT:
- for (const float *v = prop->data.pointer, *v_end = v + prop->len; v != v_end; v++) {
- if (v != prop->data.pointer) {
- STR_APPEND_STR(", ");
- }
- STR_APPEND_FMT("%g", (double)*v);
- }
- break;
- case IDP_DOUBLE:
- for (const double *v = prop->data.pointer, *v_end = v + prop->len; v != v_end; v++) {
- if (v != prop->data.pointer) {
- STR_APPEND_STR(", ");
- }
- STR_APPEND_FMT("%g", *v);
- }
- break;
- }
- STR_APPEND_STR("]");
- break;
- }
- case IDP_IDPARRAY:
- {
- STR_APPEND_STR("[");
- for (const IDProperty *v = prop->data.pointer, *v_end = v + prop->len; v != v_end; v++) {
- if (v != prop->data.pointer) {
- STR_APPEND_STR(", ");
- }
- idp_repr_fn_recursive(state, v);
- }
- STR_APPEND_STR("]");
- break;
- }
- case IDP_GROUP:
- {
- STR_APPEND_STR("{");
- for (const IDProperty *subprop = prop->data.group.first; subprop; subprop = subprop->next) {
- if (subprop != prop->data.group.first) {
- STR_APPEND_STR(", ");
- }
- STR_APPEND_STR_QUOTE(subprop->name);
- STR_APPEND_STR(": ");
- idp_repr_fn_recursive(state, subprop);
- }
- STR_APPEND_STR("}");
- break;
- }
- case IDP_ID:
- {
- const ID *id = prop->data.pointer;
- if (id != NULL) {
- STR_APPEND_STR("bpy.data.");
- STR_APPEND_STR(BKE_idcode_to_name_plural(GS(id->name)));
- STR_APPEND_STR("[");
- STR_APPEND_STR_QUOTE(id->name + 2);
- STR_APPEND_STR("]");
- }
- else {
- STR_APPEND_STR("None");
- }
- break;
- }
- default:
- {
- BLI_assert(0);
- break;
- }
- }
+ state->str_append_fn( \
+ state->user_data, \
+ state->buf, \
+ (uint)BLI_snprintf_rlen(state->buf, sizeof(state->buf), format, __VA_ARGS__))
+
+ switch (prop->type) {
+ case IDP_STRING: {
+ STR_APPEND_STR_LEN_QUOTE(IDP_String(prop), (uint)MAX2(0, prop->len - 1));
+ break;
+ }
+ case IDP_INT: {
+ STR_APPEND_FMT("%d", IDP_Int(prop));
+ break;
+ }
+ case IDP_FLOAT: {
+ STR_APPEND_FMT("%g", (double)IDP_Float(prop));
+ break;
+ }
+ case IDP_DOUBLE: {
+ STR_APPEND_FMT("%g", IDP_Double(prop));
+ break;
+ }
+ case IDP_ARRAY: {
+ STR_APPEND_STR("[");
+ switch (prop->subtype) {
+ case IDP_INT:
+ for (const int *v = prop->data.pointer, *v_end = v + prop->len; v != v_end; v++) {
+ if (v != prop->data.pointer) {
+ STR_APPEND_STR(", ");
+ }
+ STR_APPEND_FMT("%d", *v);
+ }
+ break;
+ case IDP_FLOAT:
+ for (const float *v = prop->data.pointer, *v_end = v + prop->len; v != v_end; v++) {
+ if (v != prop->data.pointer) {
+ STR_APPEND_STR(", ");
+ }
+ STR_APPEND_FMT("%g", (double)*v);
+ }
+ break;
+ case IDP_DOUBLE:
+ for (const double *v = prop->data.pointer, *v_end = v + prop->len; v != v_end; v++) {
+ if (v != prop->data.pointer) {
+ STR_APPEND_STR(", ");
+ }
+ STR_APPEND_FMT("%g", *v);
+ }
+ break;
+ }
+ STR_APPEND_STR("]");
+ break;
+ }
+ case IDP_IDPARRAY: {
+ STR_APPEND_STR("[");
+ for (const IDProperty *v = prop->data.pointer, *v_end = v + prop->len; v != v_end; v++) {
+ if (v != prop->data.pointer) {
+ STR_APPEND_STR(", ");
+ }
+ idp_repr_fn_recursive(state, v);
+ }
+ STR_APPEND_STR("]");
+ break;
+ }
+ case IDP_GROUP: {
+ STR_APPEND_STR("{");
+ for (const IDProperty *subprop = prop->data.group.first; subprop; subprop = subprop->next) {
+ if (subprop != prop->data.group.first) {
+ STR_APPEND_STR(", ");
+ }
+ STR_APPEND_STR_QUOTE(subprop->name);
+ STR_APPEND_STR(": ");
+ idp_repr_fn_recursive(state, subprop);
+ }
+ STR_APPEND_STR("}");
+ break;
+ }
+ case IDP_ID: {
+ const ID *id = prop->data.pointer;
+ if (id != NULL) {
+ STR_APPEND_STR("bpy.data.");
+ STR_APPEND_STR(BKE_idcode_to_name_plural(GS(id->name)));
+ STR_APPEND_STR("[");
+ STR_APPEND_STR_QUOTE(id->name + 2);
+ STR_APPEND_STR("]");
+ }
+ else {
+ STR_APPEND_STR("None");
+ }
+ break;
+ }
+ default: {
+ BLI_assert(0);
+ break;
+ }
+ }
#undef STR_APPEND_STR
#undef STR_APPEND_STR_QUOTE
#undef STR_APPEND_STR_LEN_QUOTE
#undef STR_APPEND_FMT
-
}
-void IDP_repr_fn(
- const IDProperty *prop,
- void (*str_append_fn)(void *user_data, const char *str, uint str_len),
- void *user_data)
+void IDP_repr_fn(const IDProperty *prop,
+ void (*str_append_fn)(void *user_data, const char *str, uint str_len),
+ void *user_data)
{
- struct ReprState state = {
- .str_append_fn = str_append_fn,
- .user_data = user_data,
- };
- idp_repr_fn_recursive(&state, prop);
+ struct ReprState state = {
+ .str_append_fn = str_append_fn,
+ .user_data = user_data,
+ };
+ idp_repr_fn_recursive(&state, prop);
}
static void repr_str(void *user_data, const char *str, uint len)
{
- BLI_dynstr_nappend(user_data, str, (int)len);
+ BLI_dynstr_nappend(user_data, str, (int)len);
}
char *IDP_reprN(const IDProperty *prop, uint *r_len)
{
- DynStr *ds = BLI_dynstr_new();
- IDP_repr_fn(prop, repr_str, ds);
- char *cstring = BLI_dynstr_get_cstring(ds);
- if (r_len != NULL) {
- *r_len = (uint)BLI_dynstr_get_len(ds);
- }
- BLI_dynstr_free(ds);
- return cstring;
+ DynStr *ds = BLI_dynstr_new();
+ IDP_repr_fn(prop, repr_str, ds);
+ char *cstring = BLI_dynstr_get_cstring(ds);
+ if (r_len != NULL) {
+ *r_len = (uint)BLI_dynstr_get_len(ds);
+ }
+ BLI_dynstr_free(ds);
+ return cstring;
}
void IDP_print(const IDProperty *prop)
{
- char *repr = IDP_reprN(prop, NULL);
- printf("IDProperty(%p): ", prop);
- puts(repr);
- MEM_freeN(repr);
+ char *repr = IDP_reprN(prop, NULL);
+ printf("IDProperty(%p): ", prop);
+ puts(repr);
+ MEM_freeN(repr);
}
/** \} */
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 101798a40e3..75807ebbfa3 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -21,7 +21,6 @@
* \ingroup bke
*/
-
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
@@ -62,7 +61,7 @@
#include "BLI_mempool.h"
#include "BLI_system.h"
#include "BLI_threads.h"
-#include "BLI_timecode.h" /* for stamp timecode format */
+#include "BLI_timecode.h" /* for stamp timecode format */
#include "BLI_utildefines.h"
#include "BKE_colortools.h"
@@ -86,7 +85,7 @@
#include "GPU_draw.h"
-#include "BLI_sys_types.h" // for intptr_t support
+#include "BLI_sys_types.h" // for intptr_t support
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
@@ -107,126 +106,126 @@ static void image_update_views_format(Image *ima, ImageUser *iuser);
static void image_add_view(Image *ima, const char *viewname, const char *filepath);
/* max int, to indicate we don't store sequences in ibuf */
-#define IMA_NO_INDEX 0x7FEFEFEF
+#define IMA_NO_INDEX 0x7FEFEFEF
/* quick lookup: supports 1 million frames, thousand passes */
-#define IMA_MAKE_INDEX(frame, index) (((frame) << 10) + (index))
-#define IMA_INDEX_FRAME(index) ((index) >> 10)
+#define IMA_MAKE_INDEX(frame, index) (((frame) << 10) + (index))
+#define IMA_INDEX_FRAME(index) ((index) >> 10)
#if 0
-#define IMA_INDEX_PASS(index) (index & ~1023)
+# define IMA_INDEX_PASS(index) (index & ~1023)
#endif
/* ******** IMAGE CACHE ************* */
typedef struct ImageCacheKey {
- int index;
+ int index;
} ImageCacheKey;
static unsigned int imagecache_hashhash(const void *key_v)
{
- const ImageCacheKey *key = key_v;
- return key->index;
+ const ImageCacheKey *key = key_v;
+ return key->index;
}
static bool imagecache_hashcmp(const void *a_v, const void *b_v)
{
- const ImageCacheKey *a = a_v;
- const ImageCacheKey *b = b_v;
+ const ImageCacheKey *a = a_v;
+ const ImageCacheKey *b = b_v;
- return (a->index != b->index);
+ return (a->index != b->index);
}
static void imagecache_keydata(void *userkey, int *framenr, int *proxy, int *render_flags)
{
- ImageCacheKey *key = userkey;
+ ImageCacheKey *key = userkey;
- *framenr = IMA_INDEX_FRAME(key->index);
- *proxy = IMB_PROXY_NONE;
- *render_flags = 0;
+ *framenr = IMA_INDEX_FRAME(key->index);
+ *proxy = IMB_PROXY_NONE;
+ *render_flags = 0;
}
static void imagecache_put(Image *image, int index, ImBuf *ibuf)
{
- ImageCacheKey key;
+ ImageCacheKey key;
- if (image->cache == NULL) {
- // char cache_name[64];
- // SNPRINTF(cache_name, "Image Datablock %s", image->id.name);
+ if (image->cache == NULL) {
+ // char cache_name[64];
+ // SNPRINTF(cache_name, "Image Datablock %s", image->id.name);
- image->cache = IMB_moviecache_create("Image Datablock Cache", sizeof(ImageCacheKey),
- imagecache_hashhash, imagecache_hashcmp);
- IMB_moviecache_set_getdata_callback(image->cache, imagecache_keydata);
- }
+ image->cache = IMB_moviecache_create(
+ "Image Datablock Cache", sizeof(ImageCacheKey), imagecache_hashhash, imagecache_hashcmp);
+ IMB_moviecache_set_getdata_callback(image->cache, imagecache_keydata);
+ }
- key.index = index;
+ key.index = index;
- IMB_moviecache_put(image->cache, &key, ibuf);
+ IMB_moviecache_put(image->cache, &key, ibuf);
}
static struct ImBuf *imagecache_get(Image *image, int index)
{
- if (image->cache) {
- ImageCacheKey key;
- key.index = index;
- return IMB_moviecache_get(image->cache, &key);
- }
+ if (image->cache) {
+ ImageCacheKey key;
+ key.index = index;
+ return IMB_moviecache_get(image->cache, &key);
+ }
- return NULL;
+ return NULL;
}
void BKE_images_init(void)
{
- BLI_spin_init(&image_spin);
+ BLI_spin_init(&image_spin);
}
void BKE_images_exit(void)
{
- BLI_spin_end(&image_spin);
+ BLI_spin_end(&image_spin);
}
/* ***************** ALLOC & FREE, DATA MANAGING *************** */
static void image_free_cached_frames(Image *image)
{
- if (image->cache) {
- IMB_moviecache_free(image->cache);
- image->cache = NULL;
- }
+ if (image->cache) {
+ IMB_moviecache_free(image->cache);
+ image->cache = NULL;
+ }
}
static void image_free_packedfiles(Image *ima)
{
- while (ima->packedfiles.last) {
- ImagePackedFile *imapf = ima->packedfiles.last;
- if (imapf->packedfile) {
- freePackedFile(imapf->packedfile);
- }
- BLI_remlink(&ima->packedfiles, imapf);
- MEM_freeN(imapf);
- }
+ while (ima->packedfiles.last) {
+ ImagePackedFile *imapf = ima->packedfiles.last;
+ if (imapf->packedfile) {
+ freePackedFile(imapf->packedfile);
+ }
+ BLI_remlink(&ima->packedfiles, imapf);
+ MEM_freeN(imapf);
+ }
}
void BKE_image_free_packedfiles(Image *ima)
{
- image_free_packedfiles(ima);
+ image_free_packedfiles(ima);
}
void BKE_image_free_views(Image *image)
{
- BLI_freelistN(&image->views);
+ BLI_freelistN(&image->views);
}
static void image_free_anims(Image *ima)
{
- while (ima->anims.last) {
- ImageAnim *ia = ima->anims.last;
- if (ia->anim) {
- IMB_free_anim(ia->anim);
- ia->anim = NULL;
- }
- BLI_remlink(&ima->anims, ia);
- MEM_freeN(ia);
- }
+ while (ima->anims.last) {
+ ImageAnim *ia = ima->anims.last;
+ if (ia->anim) {
+ IMB_free_anim(ia->anim);
+ ia->anim = NULL;
+ }
+ BLI_remlink(&ima->anims, ia);
+ MEM_freeN(ia);
+ }
}
/**
@@ -235,105 +234,106 @@ static void image_free_anims(Image *ima)
*/
void BKE_image_free_buffers_ex(Image *ima, bool do_lock)
{
- if (do_lock) {
- BLI_spin_lock(&image_spin);
- }
- image_free_cached_frames(ima);
+ if (do_lock) {
+ BLI_spin_lock(&image_spin);
+ }
+ image_free_cached_frames(ima);
- image_free_anims(ima);
+ image_free_anims(ima);
- if (ima->rr) {
- RE_FreeRenderResult(ima->rr);
- ima->rr = NULL;
- }
+ if (ima->rr) {
+ RE_FreeRenderResult(ima->rr);
+ ima->rr = NULL;
+ }
- if (!G.background) {
- /* Background mode doesn't use opnegl,
- * so we can avoid freeing GPU images and save some
- * time by skipping mutex lock.
- */
- GPU_free_image(ima);
- }
+ if (!G.background) {
+ /* Background mode doesn't use opnegl,
+ * so we can avoid freeing GPU images and save some
+ * time by skipping mutex lock.
+ */
+ GPU_free_image(ima);
+ }
- ima->ok = IMA_OK;
+ ima->ok = IMA_OK;
- if (do_lock) {
- BLI_spin_unlock(&image_spin);
- }
+ if (do_lock) {
+ BLI_spin_unlock(&image_spin);
+ }
}
void BKE_image_free_buffers(Image *ima)
{
- BKE_image_free_buffers_ex(ima, false);
+ BKE_image_free_buffers_ex(ima, false);
}
/** Free (or release) any data used by this image (does not free the image itself). */
void BKE_image_free(Image *ima)
{
- /* Also frees animdata. */
- BKE_image_free_buffers(ima);
+ /* Also frees animdata. */
+ BKE_image_free_buffers(ima);
- image_free_packedfiles(ima);
+ image_free_packedfiles(ima);
- LISTBASE_FOREACH(RenderSlot *, slot, &ima->renderslots) {
- if (slot->render) {
- RE_FreeRenderResult(slot->render);
- slot->render = NULL;
- }
- }
- BLI_freelistN(&ima->renderslots);
+ LISTBASE_FOREACH (RenderSlot *, slot, &ima->renderslots) {
+ if (slot->render) {
+ RE_FreeRenderResult(slot->render);
+ slot->render = NULL;
+ }
+ }
+ BLI_freelistN(&ima->renderslots);
- BKE_image_free_views(ima);
- MEM_SAFE_FREE(ima->stereo3d_format);
+ BKE_image_free_views(ima);
+ MEM_SAFE_FREE(ima->stereo3d_format);
- BKE_icon_id_delete(&ima->id);
- BKE_previewimg_free(&ima->preview);
+ BKE_icon_id_delete(&ima->id);
+ BKE_previewimg_free(&ima->preview);
}
/* only image block itself */
static void image_init(Image *ima, short source, short type)
{
- BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(ima, id));
+ BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(ima, id));
- ima->ok = IMA_OK;
+ ima->ok = IMA_OK;
- ima->aspx = ima->aspy = 1.0;
- ima->gen_x = 1024; ima->gen_y = 1024;
- ima->gen_type = IMA_GENTYPE_GRID;
+ ima->aspx = ima->aspy = 1.0;
+ ima->gen_x = 1024;
+ ima->gen_y = 1024;
+ ima->gen_type = IMA_GENTYPE_GRID;
- ima->source = source;
- ima->type = type;
+ ima->source = source;
+ ima->type = type;
- if (source == IMA_SRC_VIEWER)
- ima->flag |= IMA_VIEW_AS_RENDER;
+ if (source == IMA_SRC_VIEWER)
+ ima->flag |= IMA_VIEW_AS_RENDER;
- if (type == IMA_TYPE_R_RESULT) {
- for (int i = 0; i < 8; i++) {
- BKE_image_add_renderslot(ima, NULL);
- }
- }
+ if (type == IMA_TYPE_R_RESULT) {
+ for (int i = 0; i < 8; i++) {
+ BKE_image_add_renderslot(ima, NULL);
+ }
+ }
- BKE_color_managed_colorspace_settings_init(&ima->colorspace_settings);
- ima->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Image Stereo Format");
+ BKE_color_managed_colorspace_settings_init(&ima->colorspace_settings);
+ ima->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Image Stereo Format");
}
void BKE_image_init(struct Image *image)
{
- if (image) {
- image_init(image, IMA_SRC_GENERATED, IMA_TYPE_UV_TEST);
- }
+ if (image) {
+ image_init(image, IMA_SRC_GENERATED, IMA_TYPE_UV_TEST);
+ }
}
static Image *image_alloc(Main *bmain, const char *name, short source, short type)
{
- Image *ima;
+ Image *ima;
- ima = BKE_libblock_alloc(bmain, ID_IM, name, 0);
- if (ima) {
- image_init(ima, source, type);
- }
+ ima = BKE_libblock_alloc(bmain, ID_IM, name, 0);
+ if (ima) {
+ image_init(ima, source, type);
+ }
- return ima;
+ return ima;
}
/* Get the ibuf from an image cache by it's index and frame.
@@ -345,38 +345,38 @@ static Image *image_alloc(Main *bmain, const char *name, short source, short typ
*/
static ImBuf *image_get_cached_ibuf_for_index_frame(Image *ima, int index, int frame)
{
- if (index != IMA_NO_INDEX) {
- index = IMA_MAKE_INDEX(frame, index);
- }
+ if (index != IMA_NO_INDEX) {
+ index = IMA_MAKE_INDEX(frame, index);
+ }
- return imagecache_get(ima, index);
+ return imagecache_get(ima, index);
}
/* no ima->ibuf anymore, but listbase */
static void image_assign_ibuf(Image *ima, ImBuf *ibuf, int index, int frame)
{
- if (ibuf) {
- if (index != IMA_NO_INDEX)
- index = IMA_MAKE_INDEX(frame, index);
+ if (ibuf) {
+ if (index != IMA_NO_INDEX)
+ index = IMA_MAKE_INDEX(frame, index);
- imagecache_put(ima, index, ibuf);
- }
+ imagecache_put(ima, index, ibuf);
+ }
}
static void copy_image_packedfiles(ListBase *lb_dst, const ListBase *lb_src)
{
- const ImagePackedFile *imapf_src;
+ const ImagePackedFile *imapf_src;
- BLI_listbase_clear(lb_dst);
- for (imapf_src = lb_src->first; imapf_src; imapf_src = imapf_src->next) {
- ImagePackedFile *imapf_dst = MEM_mallocN(sizeof(ImagePackedFile), "Image Packed Files (copy)");
- STRNCPY(imapf_dst->filepath, imapf_src->filepath);
+ BLI_listbase_clear(lb_dst);
+ for (imapf_src = lb_src->first; imapf_src; imapf_src = imapf_src->next) {
+ ImagePackedFile *imapf_dst = MEM_mallocN(sizeof(ImagePackedFile), "Image Packed Files (copy)");
+ STRNCPY(imapf_dst->filepath, imapf_src->filepath);
- if (imapf_src->packedfile)
- imapf_dst->packedfile = dupPackedFile(imapf_src->packedfile);
+ if (imapf_src->packedfile)
+ imapf_dst->packedfile = dupPackedFile(imapf_src->packedfile);
- BLI_addtail(lb_dst, imapf_dst);
- }
+ BLI_addtail(lb_dst, imapf_dst);
+ }
}
/**
@@ -389,158 +389,159 @@ static void copy_image_packedfiles(ListBase *lb_dst, const ListBase *lb_src)
*/
void BKE_image_copy_data(Main *UNUSED(bmain), Image *ima_dst, const Image *ima_src, const int flag)
{
- BKE_color_managed_colorspace_settings_copy(&ima_dst->colorspace_settings, &ima_src->colorspace_settings);
+ BKE_color_managed_colorspace_settings_copy(&ima_dst->colorspace_settings,
+ &ima_src->colorspace_settings);
- copy_image_packedfiles(&ima_dst->packedfiles, &ima_src->packedfiles);
+ copy_image_packedfiles(&ima_dst->packedfiles, &ima_src->packedfiles);
- ima_dst->stereo3d_format = MEM_dupallocN(ima_src->stereo3d_format);
- BLI_duplicatelist(&ima_dst->views, &ima_src->views);
+ ima_dst->stereo3d_format = MEM_dupallocN(ima_src->stereo3d_format);
+ BLI_duplicatelist(&ima_dst->views, &ima_src->views);
- /* Cleanup stuff that cannot be copied. */
- ima_dst->cache = NULL;
- ima_dst->rr = NULL;
+ /* Cleanup stuff that cannot be copied. */
+ ima_dst->cache = NULL;
+ ima_dst->rr = NULL;
- BLI_duplicatelist(&ima_dst->renderslots, &ima_src->renderslots);
- LISTBASE_FOREACH(RenderSlot *, slot, &ima_dst->renderslots) {
- slot->render = NULL;
- }
+ BLI_duplicatelist(&ima_dst->renderslots, &ima_src->renderslots);
+ LISTBASE_FOREACH (RenderSlot *, slot, &ima_dst->renderslots) {
+ slot->render = NULL;
+ }
- BLI_listbase_clear(&ima_dst->anims);
+ BLI_listbase_clear(&ima_dst->anims);
- for (int i = 0; i < TEXTARGET_COUNT; i++) {
- ima_dst->gputexture[i] = NULL;
- }
+ for (int i = 0; i < TEXTARGET_COUNT; i++) {
+ ima_dst->gputexture[i] = NULL;
+ }
- if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
- BKE_previewimg_id_copy(&ima_dst->id, &ima_src->id);
- }
- else {
- ima_dst->preview = NULL;
- }
+ if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
+ BKE_previewimg_id_copy(&ima_dst->id, &ima_src->id);
+ }
+ else {
+ ima_dst->preview = NULL;
+ }
}
/* empty image block, of similar type and filename */
Image *BKE_image_copy(Main *bmain, const Image *ima)
{
- Image *ima_copy;
- BKE_id_copy(bmain, &ima->id, (ID **)&ima_copy);
- return ima_copy;
+ Image *ima_copy;
+ BKE_id_copy(bmain, &ima->id, (ID **)&ima_copy);
+ return ima_copy;
}
void BKE_image_make_local(Main *bmain, Image *ima, const bool lib_local)
{
- BKE_id_make_local_generic(bmain, &ima->id, true, lib_local);
+ BKE_id_make_local_generic(bmain, &ima->id, true, lib_local);
}
void BKE_image_merge(Main *bmain, Image *dest, Image *source)
{
- /* sanity check */
- if (dest && source && dest != source) {
- BLI_spin_lock(&image_spin);
- if (source->cache != NULL) {
- struct MovieCacheIter *iter;
- iter = IMB_moviecacheIter_new(source->cache);
- while (!IMB_moviecacheIter_done(iter)) {
- ImBuf *ibuf = IMB_moviecacheIter_getImBuf(iter);
- ImageCacheKey *key = IMB_moviecacheIter_getUserKey(iter);
- imagecache_put(dest, key->index, ibuf);
- IMB_moviecacheIter_step(iter);
- }
- IMB_moviecacheIter_free(iter);
- }
- BLI_spin_unlock(&image_spin);
-
- BKE_id_free(bmain, source);
- }
+ /* sanity check */
+ if (dest && source && dest != source) {
+ BLI_spin_lock(&image_spin);
+ if (source->cache != NULL) {
+ struct MovieCacheIter *iter;
+ iter = IMB_moviecacheIter_new(source->cache);
+ while (!IMB_moviecacheIter_done(iter)) {
+ ImBuf *ibuf = IMB_moviecacheIter_getImBuf(iter);
+ ImageCacheKey *key = IMB_moviecacheIter_getUserKey(iter);
+ imagecache_put(dest, key->index, ibuf);
+ IMB_moviecacheIter_step(iter);
+ }
+ IMB_moviecacheIter_free(iter);
+ }
+ BLI_spin_unlock(&image_spin);
+
+ BKE_id_free(bmain, source);
+ }
}
/* note, we could be clever and scale all imbuf's but since some are mipmaps its not so simple */
bool BKE_image_scale(Image *image, int width, int height)
{
- ImBuf *ibuf;
- void *lock;
+ ImBuf *ibuf;
+ void *lock;
- ibuf = BKE_image_acquire_ibuf(image, NULL, &lock);
+ ibuf = BKE_image_acquire_ibuf(image, NULL, &lock);
- if (ibuf) {
- IMB_scaleImBuf(ibuf, width, height);
- ibuf->userflags |= IB_BITMAPDIRTY;
- }
+ if (ibuf) {
+ IMB_scaleImBuf(ibuf, width, height);
+ ibuf->userflags |= IB_BITMAPDIRTY;
+ }
- BKE_image_release_ibuf(image, ibuf, lock);
+ BKE_image_release_ibuf(image, ibuf, lock);
- return (ibuf != NULL);
+ return (ibuf != NULL);
}
bool BKE_image_has_opengl_texture(Image *ima)
{
- for (int i = 0; i < TEXTARGET_COUNT; i++) {
- if (ima->gputexture[i]) {
- return true;
- }
- }
- return false;
+ for (int i = 0; i < TEXTARGET_COUNT; i++) {
+ if (ima->gputexture[i]) {
+ return true;
+ }
+ }
+ return false;
}
static void image_init_color_management(Image *ima)
{
- ImBuf *ibuf;
- char name[FILE_MAX];
+ ImBuf *ibuf;
+ char name[FILE_MAX];
- BKE_image_user_file_path(NULL, ima, name);
+ BKE_image_user_file_path(NULL, ima, name);
- /* will set input color space to image format default's */
- ibuf = IMB_loadiffname(name, IB_test | IB_alphamode_detect, ima->colorspace_settings.name);
+ /* will set input color space to image format default's */
+ ibuf = IMB_loadiffname(name, IB_test | IB_alphamode_detect, ima->colorspace_settings.name);
- if (ibuf) {
- if (ibuf->flags & IB_alphamode_premul)
- ima->alpha_mode = IMA_ALPHA_PREMUL;
- else
- ima->alpha_mode = IMA_ALPHA_STRAIGHT;
+ if (ibuf) {
+ if (ibuf->flags & IB_alphamode_premul)
+ ima->alpha_mode = IMA_ALPHA_PREMUL;
+ else
+ ima->alpha_mode = IMA_ALPHA_STRAIGHT;
- IMB_freeImBuf(ibuf);
- }
+ IMB_freeImBuf(ibuf);
+ }
}
char BKE_image_alpha_mode_from_extension_ex(const char *filepath)
{
- if (BLI_path_extension_check_n(filepath, ".exr", ".cin", ".dpx", ".hdr", NULL)) {
- return IMA_ALPHA_PREMUL;
- }
- else {
- return IMA_ALPHA_STRAIGHT;
- }
+ if (BLI_path_extension_check_n(filepath, ".exr", ".cin", ".dpx", ".hdr", NULL)) {
+ return IMA_ALPHA_PREMUL;
+ }
+ else {
+ return IMA_ALPHA_STRAIGHT;
+ }
}
void BKE_image_alpha_mode_from_extension(Image *image)
{
- image->alpha_mode = BKE_image_alpha_mode_from_extension_ex(image->name);
+ image->alpha_mode = BKE_image_alpha_mode_from_extension_ex(image->name);
}
Image *BKE_image_load(Main *bmain, const char *filepath)
{
- Image *ima;
- int file;
- char str[FILE_MAX];
+ Image *ima;
+ int file;
+ char str[FILE_MAX];
- STRNCPY(str, filepath);
- BLI_path_abs(str, BKE_main_blendfile_path(bmain));
+ STRNCPY(str, filepath);
+ BLI_path_abs(str, BKE_main_blendfile_path(bmain));
- /* exists? */
- file = BLI_open(str, O_BINARY | O_RDONLY, 0);
- if (file == -1)
- return NULL;
- close(file);
+ /* exists? */
+ file = BLI_open(str, O_BINARY | O_RDONLY, 0);
+ if (file == -1)
+ return NULL;
+ close(file);
- ima = image_alloc(bmain, BLI_path_basename(filepath), IMA_SRC_FILE, IMA_TYPE_IMAGE);
- STRNCPY(ima->name, filepath);
+ ima = image_alloc(bmain, BLI_path_basename(filepath), IMA_SRC_FILE, IMA_TYPE_IMAGE);
+ STRNCPY(ima->name, filepath);
- if (BLI_path_extension_check_array(filepath, imb_ext_movie))
- ima->source = IMA_SRC_MOVIE;
+ if (BLI_path_extension_check_array(filepath, imb_ext_movie))
+ ima->source = IMA_SRC_MOVIE;
- image_init_color_management(ima);
+ image_init_color_management(ima);
- return ima;
+ return ima;
}
/* checks if image was already loaded, then returns same image */
@@ -549,137 +550,151 @@ Image *BKE_image_load(Main *bmain, const char *filepath)
/* pass on optional frame for #name images */
Image *BKE_image_load_exists_ex(Main *bmain, const char *filepath, bool *r_exists)
{
- Image *ima;
- char str[FILE_MAX], strtest[FILE_MAX];
-
- STRNCPY(str, filepath);
- BLI_path_abs(str, BKE_main_blendfile_path_from_global());
-
- /* first search an identical filepath */
- for (ima = bmain->images.first; ima; ima = ima->id.next) {
- if (ima->source != IMA_SRC_VIEWER && ima->source != IMA_SRC_GENERATED) {
- STRNCPY(strtest, ima->name);
- BLI_path_abs(strtest, ID_BLEND_PATH(bmain, &ima->id));
-
- if (BLI_path_cmp(strtest, str) == 0) {
- if ((BKE_image_has_anim(ima) == false) ||
- (ima->id.us == 0))
- {
- id_us_plus(&ima->id); /* officially should not, it doesn't link here! */
- if (ima->ok == 0)
- ima->ok = IMA_OK;
- if (r_exists)
- *r_exists = true;
- return ima;
- }
- }
- }
- }
-
- if (r_exists)
- *r_exists = false;
- return BKE_image_load(bmain, filepath);
+ Image *ima;
+ char str[FILE_MAX], strtest[FILE_MAX];
+
+ STRNCPY(str, filepath);
+ BLI_path_abs(str, BKE_main_blendfile_path_from_global());
+
+ /* first search an identical filepath */
+ for (ima = bmain->images.first; ima; ima = ima->id.next) {
+ if (ima->source != IMA_SRC_VIEWER && ima->source != IMA_SRC_GENERATED) {
+ STRNCPY(strtest, ima->name);
+ BLI_path_abs(strtest, ID_BLEND_PATH(bmain, &ima->id));
+
+ if (BLI_path_cmp(strtest, str) == 0) {
+ if ((BKE_image_has_anim(ima) == false) || (ima->id.us == 0)) {
+ id_us_plus(&ima->id); /* officially should not, it doesn't link here! */
+ if (ima->ok == 0)
+ ima->ok = IMA_OK;
+ if (r_exists)
+ *r_exists = true;
+ return ima;
+ }
+ }
+ }
+ }
+
+ if (r_exists)
+ *r_exists = false;
+ return BKE_image_load(bmain, filepath);
}
Image *BKE_image_load_exists(Main *bmain, const char *filepath)
{
- return BKE_image_load_exists_ex(bmain, filepath, NULL);
+ return BKE_image_load_exists_ex(bmain, filepath, NULL);
}
-static ImBuf *add_ibuf_size(unsigned int width, unsigned int height, const char *name, int depth, int floatbuf, short gen_type,
- const float color[4], ColorManagedColorspaceSettings *colorspace_settings)
+static ImBuf *add_ibuf_size(unsigned int width,
+ unsigned int height,
+ const char *name,
+ int depth,
+ int floatbuf,
+ short gen_type,
+ const float color[4],
+ ColorManagedColorspaceSettings *colorspace_settings)
{
- ImBuf *ibuf;
- unsigned char *rect = NULL;
- float *rect_float = NULL;
+ ImBuf *ibuf;
+ unsigned char *rect = NULL;
+ float *rect_float = NULL;
- if (floatbuf) {
- ibuf = IMB_allocImBuf(width, height, depth, IB_rectfloat);
+ if (floatbuf) {
+ ibuf = IMB_allocImBuf(width, height, depth, IB_rectfloat);
- if (colorspace_settings->name[0] == '\0') {
- const char *colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DEFAULT_FLOAT);
+ if (colorspace_settings->name[0] == '\0') {
+ const char *colorspace = IMB_colormanagement_role_colorspace_name_get(
+ COLOR_ROLE_DEFAULT_FLOAT);
- STRNCPY(colorspace_settings->name, colorspace);
- }
+ STRNCPY(colorspace_settings->name, colorspace);
+ }
- if (ibuf != NULL) {
- rect_float = ibuf->rect_float;
- IMB_colormanagement_check_is_data(ibuf, colorspace_settings->name);
- }
- }
- else {
- ibuf = IMB_allocImBuf(width, height, depth, IB_rect);
+ if (ibuf != NULL) {
+ rect_float = ibuf->rect_float;
+ IMB_colormanagement_check_is_data(ibuf, colorspace_settings->name);
+ }
+ }
+ else {
+ ibuf = IMB_allocImBuf(width, height, depth, IB_rect);
- if (colorspace_settings->name[0] == '\0') {
- const char *colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DEFAULT_BYTE);
+ if (colorspace_settings->name[0] == '\0') {
+ const char *colorspace = IMB_colormanagement_role_colorspace_name_get(
+ COLOR_ROLE_DEFAULT_BYTE);
- STRNCPY(colorspace_settings->name, colorspace);
- }
+ STRNCPY(colorspace_settings->name, colorspace);
+ }
- if (ibuf != NULL) {
- rect = (unsigned char *)ibuf->rect;
- IMB_colormanagement_assign_rect_colorspace(ibuf, colorspace_settings->name);
- }
- }
+ if (ibuf != NULL) {
+ rect = (unsigned char *)ibuf->rect;
+ IMB_colormanagement_assign_rect_colorspace(ibuf, colorspace_settings->name);
+ }
+ }
- if (!ibuf) {
- return NULL;
- }
+ if (!ibuf) {
+ return NULL;
+ }
- STRNCPY(ibuf->name, name);
- ibuf->userflags |= IB_BITMAPDIRTY;
+ STRNCPY(ibuf->name, name);
+ ibuf->userflags |= IB_BITMAPDIRTY;
- switch (gen_type) {
- case IMA_GENTYPE_GRID:
- BKE_image_buf_fill_checker(rect, rect_float, width, height);
- break;
- case IMA_GENTYPE_GRID_COLOR:
- BKE_image_buf_fill_checker_color(rect, rect_float, width, height);
- break;
- default:
- BKE_image_buf_fill_color(rect, rect_float, width, height, color);
- break;
- }
+ switch (gen_type) {
+ case IMA_GENTYPE_GRID:
+ BKE_image_buf_fill_checker(rect, rect_float, width, height);
+ break;
+ case IMA_GENTYPE_GRID_COLOR:
+ BKE_image_buf_fill_checker_color(rect, rect_float, width, height);
+ break;
+ default:
+ BKE_image_buf_fill_color(rect, rect_float, width, height, color);
+ break;
+ }
- return ibuf;
+ return ibuf;
}
/* adds new image block, creates ImBuf and initializes color */
-Image *BKE_image_add_generated(
- Main *bmain, unsigned int width, unsigned int height, const char *name,
- int depth, int floatbuf, short gen_type, const float color[4], const bool stereo3d)
-{
- /* on save, type is changed to FILE in editsima.c */
- Image *ima = image_alloc(bmain, name, IMA_SRC_GENERATED, IMA_TYPE_UV_TEST);
-
- if (ima) {
- int view_id;
- const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
-
- /* STRNCPY(ima->name, name); */ /* don't do this, this writes in ain invalid filepath! */
- ima->gen_x = width;
- ima->gen_y = height;
- ima->gen_type = gen_type;
- ima->gen_flag |= (floatbuf ? IMA_GEN_FLOAT : 0);
- ima->gen_depth = depth;
- copy_v4_v4(ima->gen_color, color);
-
- for (view_id = 0; view_id < 2; view_id++) {
- ImBuf *ibuf;
- ibuf = add_ibuf_size(width, height, ima->name, depth, floatbuf, gen_type, color, &ima->colorspace_settings);
- image_assign_ibuf(ima, ibuf, stereo3d ? view_id : IMA_NO_INDEX, 0);
-
- /* image_assign_ibuf puts buffer to the cache, which increments user counter. */
- IMB_freeImBuf(ibuf);
- if (!stereo3d) break;
-
- image_add_view(ima, names[view_id], "");
- }
-
- ima->ok = IMA_OK_LOADED;
- }
-
- return ima;
+Image *BKE_image_add_generated(Main *bmain,
+ unsigned int width,
+ unsigned int height,
+ const char *name,
+ int depth,
+ int floatbuf,
+ short gen_type,
+ const float color[4],
+ const bool stereo3d)
+{
+ /* on save, type is changed to FILE in editsima.c */
+ Image *ima = image_alloc(bmain, name, IMA_SRC_GENERATED, IMA_TYPE_UV_TEST);
+
+ if (ima) {
+ int view_id;
+ const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
+
+ /* STRNCPY(ima->name, name); */ /* don't do this, this writes in ain invalid filepath! */
+ ima->gen_x = width;
+ ima->gen_y = height;
+ ima->gen_type = gen_type;
+ ima->gen_flag |= (floatbuf ? IMA_GEN_FLOAT : 0);
+ ima->gen_depth = depth;
+ copy_v4_v4(ima->gen_color, color);
+
+ for (view_id = 0; view_id < 2; view_id++) {
+ ImBuf *ibuf;
+ ibuf = add_ibuf_size(
+ width, height, ima->name, depth, floatbuf, gen_type, color, &ima->colorspace_settings);
+ image_assign_ibuf(ima, ibuf, stereo3d ? view_id : IMA_NO_INDEX, 0);
+
+ /* image_assign_ibuf puts buffer to the cache, which increments user counter. */
+ IMB_freeImBuf(ibuf);
+ if (!stereo3d)
+ break;
+
+ image_add_view(ima, names[view_id], "");
+ }
+
+ ima->ok = IMA_OK_LOADED;
+ }
+
+ return ima;
}
/* Create an image image from ibuf. The refcount of ibuf is increased,
@@ -687,22 +702,22 @@ Image *BKE_image_add_generated(
* IMB_freeImBuf if needed. */
Image *BKE_image_add_from_imbuf(Main *bmain, ImBuf *ibuf, const char *name)
{
- /* on save, type is changed to FILE in editsima.c */
- Image *ima;
+ /* on save, type is changed to FILE in editsima.c */
+ Image *ima;
- if (name == NULL) {
- name = BLI_path_basename(ibuf->name);
- }
+ if (name == NULL) {
+ name = BLI_path_basename(ibuf->name);
+ }
- ima = image_alloc(bmain, name, IMA_SRC_FILE, IMA_TYPE_IMAGE);
+ ima = image_alloc(bmain, name, IMA_SRC_FILE, IMA_TYPE_IMAGE);
- if (ima) {
- STRNCPY(ima->name, ibuf->name);
- image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
- ima->ok = IMA_OK_LOADED;
- }
+ if (ima) {
+ STRNCPY(ima->name, ibuf->name);
+ image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
+ ima->ok = IMA_OK_LOADED;
+ }
- return ima;
+ return ima;
}
/* packs rects from memory as PNG
@@ -710,850 +725,876 @@ Image *BKE_image_add_from_imbuf(Main *bmain, ImBuf *ibuf, const char *name)
*/
static void image_memorypack_multiview(Image *ima)
{
- ImageView *iv;
- int i;
+ ImageView *iv;
+ int i;
- image_free_packedfiles(ima);
+ image_free_packedfiles(ima);
- for (i = 0, iv = ima->views.first; iv; iv = iv->next, i++) {
- ImBuf *ibuf = image_get_cached_ibuf_for_index_frame(ima, i, 0);
+ for (i = 0, iv = ima->views.first; iv; iv = iv->next, i++) {
+ ImBuf *ibuf = image_get_cached_ibuf_for_index_frame(ima, i, 0);
- ibuf->ftype = IMB_FTYPE_PNG;
- ibuf->planes = R_IMF_PLANES_RGBA;
+ ibuf->ftype = IMB_FTYPE_PNG;
+ ibuf->planes = R_IMF_PLANES_RGBA;
- /* if the image was a R_IMF_VIEWS_STEREO_3D we force _L, _R suffices */
- if (ima->views_format == R_IMF_VIEWS_STEREO_3D) {
- const char *suffix[2] = {STEREO_LEFT_SUFFIX, STEREO_RIGHT_SUFFIX};
- BLI_path_suffix(iv->filepath, FILE_MAX, suffix[i], "");
- }
+ /* if the image was a R_IMF_VIEWS_STEREO_3D we force _L, _R suffices */
+ if (ima->views_format == R_IMF_VIEWS_STEREO_3D) {
+ const char *suffix[2] = {STEREO_LEFT_SUFFIX, STEREO_RIGHT_SUFFIX};
+ BLI_path_suffix(iv->filepath, FILE_MAX, suffix[i], "");
+ }
- IMB_saveiff(ibuf, iv->filepath, IB_rect | IB_mem);
+ IMB_saveiff(ibuf, iv->filepath, IB_rect | IB_mem);
- if (ibuf->encodedbuffer == NULL) {
- CLOG_STR_ERROR(&LOG, "memory save for pack error");
- IMB_freeImBuf(ibuf);
- image_free_packedfiles(ima);
- return;
- }
- else {
- ImagePackedFile *imapf;
- PackedFile *pf = MEM_callocN(sizeof(*pf), "PackedFile");
+ if (ibuf->encodedbuffer == NULL) {
+ CLOG_STR_ERROR(&LOG, "memory save for pack error");
+ IMB_freeImBuf(ibuf);
+ image_free_packedfiles(ima);
+ return;
+ }
+ else {
+ ImagePackedFile *imapf;
+ PackedFile *pf = MEM_callocN(sizeof(*pf), "PackedFile");
- pf->data = ibuf->encodedbuffer;
- pf->size = ibuf->encodedsize;
+ pf->data = ibuf->encodedbuffer;
+ pf->size = ibuf->encodedsize;
- imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image PackedFile");
- STRNCPY(imapf->filepath, iv->filepath);
- imapf->packedfile = pf;
- BLI_addtail(&ima->packedfiles, imapf);
+ imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image PackedFile");
+ STRNCPY(imapf->filepath, iv->filepath);
+ imapf->packedfile = pf;
+ BLI_addtail(&ima->packedfiles, imapf);
- ibuf->encodedbuffer = NULL;
- ibuf->encodedsize = 0;
- ibuf->userflags &= ~IB_BITMAPDIRTY;
- }
- IMB_freeImBuf(ibuf);
- }
+ ibuf->encodedbuffer = NULL;
+ ibuf->encodedsize = 0;
+ ibuf->userflags &= ~IB_BITMAPDIRTY;
+ }
+ IMB_freeImBuf(ibuf);
+ }
- if (ima->source == IMA_SRC_GENERATED) {
- ima->source = IMA_SRC_FILE;
- ima->type = IMA_TYPE_IMAGE;
- }
- ima->views_format = R_IMF_VIEWS_INDIVIDUAL;
+ if (ima->source == IMA_SRC_GENERATED) {
+ ima->source = IMA_SRC_FILE;
+ ima->type = IMA_TYPE_IMAGE;
+ }
+ ima->views_format = R_IMF_VIEWS_INDIVIDUAL;
}
/* packs rect from memory as PNG */
void BKE_image_memorypack(Image *ima)
{
- ImBuf *ibuf;
+ ImBuf *ibuf;
- if (BKE_image_is_multiview(ima)) {
- image_memorypack_multiview(ima);
- return;
- }
+ if (BKE_image_is_multiview(ima)) {
+ image_memorypack_multiview(ima);
+ return;
+ }
- ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0);
+ ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0);
- if (ibuf == NULL)
- return;
+ if (ibuf == NULL)
+ return;
- image_free_packedfiles(ima);
+ image_free_packedfiles(ima);
- ibuf->ftype = IMB_FTYPE_PNG;
- ibuf->planes = R_IMF_PLANES_RGBA;
+ ibuf->ftype = IMB_FTYPE_PNG;
+ ibuf->planes = R_IMF_PLANES_RGBA;
- IMB_saveiff(ibuf, ibuf->name, IB_rect | IB_mem);
- if (ibuf->encodedbuffer == NULL) {
- CLOG_STR_ERROR(&LOG, "memory save for pack error");
- }
- else {
- ImagePackedFile *imapf;
- PackedFile *pf = MEM_callocN(sizeof(*pf), "PackedFile");
+ IMB_saveiff(ibuf, ibuf->name, IB_rect | IB_mem);
+ if (ibuf->encodedbuffer == NULL) {
+ CLOG_STR_ERROR(&LOG, "memory save for pack error");
+ }
+ else {
+ ImagePackedFile *imapf;
+ PackedFile *pf = MEM_callocN(sizeof(*pf), "PackedFile");
- pf->data = ibuf->encodedbuffer;
- pf->size = ibuf->encodedsize;
+ pf->data = ibuf->encodedbuffer;
+ pf->size = ibuf->encodedsize;
- imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image PackedFile");
- STRNCPY(imapf->filepath, ima->name);
- imapf->packedfile = pf;
- BLI_addtail(&ima->packedfiles, imapf);
+ imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image PackedFile");
+ STRNCPY(imapf->filepath, ima->name);
+ imapf->packedfile = pf;
+ BLI_addtail(&ima->packedfiles, imapf);
- ibuf->encodedbuffer = NULL;
- ibuf->encodedsize = 0;
- ibuf->userflags &= ~IB_BITMAPDIRTY;
+ ibuf->encodedbuffer = NULL;
+ ibuf->encodedsize = 0;
+ ibuf->userflags &= ~IB_BITMAPDIRTY;
- if (ima->source == IMA_SRC_GENERATED) {
- ima->source = IMA_SRC_FILE;
- ima->type = IMA_TYPE_IMAGE;
- }
- }
+ if (ima->source == IMA_SRC_GENERATED) {
+ ima->source = IMA_SRC_FILE;
+ ima->type = IMA_TYPE_IMAGE;
+ }
+ }
- IMB_freeImBuf(ibuf);
+ IMB_freeImBuf(ibuf);
}
void BKE_image_packfiles(ReportList *reports, Image *ima, const char *basepath)
{
- const int totfiles = image_num_files(ima);
-
- if (totfiles == 1) {
- ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image packed file");
- BLI_addtail(&ima->packedfiles, imapf);
- imapf->packedfile = newPackedFile(reports, ima->name, basepath);
- if (imapf->packedfile) {
- STRNCPY(imapf->filepath, ima->name);
- }
- else {
- BLI_freelinkN(&ima->packedfiles, imapf);
- }
- }
- else {
- ImageView *iv;
- for (iv = ima->views.first; iv; iv = iv->next) {
- ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image packed file");
- BLI_addtail(&ima->packedfiles, imapf);
-
- imapf->packedfile = newPackedFile(reports, iv->filepath, basepath);
- if (imapf->packedfile) {
- STRNCPY(imapf->filepath, iv->filepath);
- }
- else {
- BLI_freelinkN(&ima->packedfiles, imapf);
- }
- }
- }
-}
-
-void BKE_image_packfiles_from_mem(ReportList *reports, Image *ima, char *data, const size_t data_len)
-{
- const int totfiles = image_num_files(ima);
-
- if (totfiles != 1) {
- BKE_report(reports, RPT_ERROR, "Cannot pack multiview images from raw data currently...");
- }
- else {
- ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), __func__);
- BLI_addtail(&ima->packedfiles, imapf);
- imapf->packedfile = newPackedFileMemory(data, data_len);
- STRNCPY(imapf->filepath, ima->name);
- }
+ const int totfiles = image_num_files(ima);
+
+ if (totfiles == 1) {
+ ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image packed file");
+ BLI_addtail(&ima->packedfiles, imapf);
+ imapf->packedfile = newPackedFile(reports, ima->name, basepath);
+ if (imapf->packedfile) {
+ STRNCPY(imapf->filepath, ima->name);
+ }
+ else {
+ BLI_freelinkN(&ima->packedfiles, imapf);
+ }
+ }
+ else {
+ ImageView *iv;
+ for (iv = ima->views.first; iv; iv = iv->next) {
+ ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image packed file");
+ BLI_addtail(&ima->packedfiles, imapf);
+
+ imapf->packedfile = newPackedFile(reports, iv->filepath, basepath);
+ if (imapf->packedfile) {
+ STRNCPY(imapf->filepath, iv->filepath);
+ }
+ else {
+ BLI_freelinkN(&ima->packedfiles, imapf);
+ }
+ }
+ }
+}
+
+void BKE_image_packfiles_from_mem(ReportList *reports,
+ Image *ima,
+ char *data,
+ const size_t data_len)
+{
+ const int totfiles = image_num_files(ima);
+
+ if (totfiles != 1) {
+ BKE_report(reports, RPT_ERROR, "Cannot pack multiview images from raw data currently...");
+ }
+ else {
+ ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), __func__);
+ BLI_addtail(&ima->packedfiles, imapf);
+ imapf->packedfile = newPackedFileMemory(data, data_len);
+ STRNCPY(imapf->filepath, ima->name);
+ }
}
void BKE_image_tag_time(Image *ima)
{
- ima->lastused = PIL_check_seconds_timer_i();
+ ima->lastused = PIL_check_seconds_timer_i();
}
static uintptr_t image_mem_size(Image *image)
{
- uintptr_t size = 0;
-
- /* viewers have memory depending on other rules, has no valid rect pointer */
- if (image->source == IMA_SRC_VIEWER)
- return 0;
-
- BLI_spin_lock(&image_spin);
- if (image->cache != NULL) {
- struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache);
-
- while (!IMB_moviecacheIter_done(iter)) {
- ImBuf *ibuf = IMB_moviecacheIter_getImBuf(iter);
- ImBuf *ibufm;
- int level;
-
- if (ibuf->rect) {
- size += MEM_allocN_len(ibuf->rect);
- }
- if (ibuf->rect_float) {
- size += MEM_allocN_len(ibuf->rect_float);
- }
-
- for (level = 0; level < IMB_MIPMAP_LEVELS; level++) {
- ibufm = ibuf->mipmap[level];
- if (ibufm) {
- if (ibufm->rect) {
- size += MEM_allocN_len(ibufm->rect);
- }
- if (ibufm->rect_float) {
- size += MEM_allocN_len(ibufm->rect_float);
- }
- }
- }
-
- IMB_moviecacheIter_step(iter);
- }
- IMB_moviecacheIter_free(iter);
- }
- BLI_spin_unlock(&image_spin);
-
- return size;
+ uintptr_t size = 0;
+
+ /* viewers have memory depending on other rules, has no valid rect pointer */
+ if (image->source == IMA_SRC_VIEWER)
+ return 0;
+
+ BLI_spin_lock(&image_spin);
+ if (image->cache != NULL) {
+ struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache);
+
+ while (!IMB_moviecacheIter_done(iter)) {
+ ImBuf *ibuf = IMB_moviecacheIter_getImBuf(iter);
+ ImBuf *ibufm;
+ int level;
+
+ if (ibuf->rect) {
+ size += MEM_allocN_len(ibuf->rect);
+ }
+ if (ibuf->rect_float) {
+ size += MEM_allocN_len(ibuf->rect_float);
+ }
+
+ for (level = 0; level < IMB_MIPMAP_LEVELS; level++) {
+ ibufm = ibuf->mipmap[level];
+ if (ibufm) {
+ if (ibufm->rect) {
+ size += MEM_allocN_len(ibufm->rect);
+ }
+ if (ibufm->rect_float) {
+ size += MEM_allocN_len(ibufm->rect_float);
+ }
+ }
+ }
+
+ IMB_moviecacheIter_step(iter);
+ }
+ IMB_moviecacheIter_free(iter);
+ }
+ BLI_spin_unlock(&image_spin);
+
+ return size;
}
void BKE_image_print_memlist(Main *bmain)
{
- Image *ima;
- uintptr_t size, totsize = 0;
+ Image *ima;
+ uintptr_t size, totsize = 0;
- for (ima = bmain->images.first; ima; ima = ima->id.next)
- totsize += image_mem_size(ima);
+ for (ima = bmain->images.first; ima; ima = ima->id.next)
+ totsize += image_mem_size(ima);
- printf("\ntotal image memory len: %.3f MB\n", (double)totsize / (double)(1024 * 1024));
+ printf("\ntotal image memory len: %.3f MB\n", (double)totsize / (double)(1024 * 1024));
- for (ima = bmain->images.first; ima; ima = ima->id.next) {
- size = image_mem_size(ima);
+ for (ima = bmain->images.first; ima; ima = ima->id.next) {
+ size = image_mem_size(ima);
- if (size)
- printf("%s len: %.3f MB\n", ima->id.name + 2, (double)size / (double)(1024 * 1024));
- }
+ if (size)
+ printf("%s len: %.3f MB\n", ima->id.name + 2, (double)size / (double)(1024 * 1024));
+ }
}
static bool imagecache_check_dirty(ImBuf *ibuf, void *UNUSED(userkey), void *UNUSED(userdata))
{
- return (ibuf->userflags & IB_BITMAPDIRTY) == 0;
+ return (ibuf->userflags & IB_BITMAPDIRTY) == 0;
}
void BKE_image_free_all_textures(Main *bmain)
{
#undef CHECK_FREED_SIZE
- Tex *tex;
- Image *ima;
+ Tex *tex;
+ Image *ima;
#ifdef CHECK_FREED_SIZE
- uintptr_t tot_freed_size = 0;
+ uintptr_t tot_freed_size = 0;
#endif
- for (ima = bmain->images.first; ima; ima = ima->id.next)
- ima->id.tag &= ~LIB_TAG_DOIT;
+ for (ima = bmain->images.first; ima; ima = ima->id.next)
+ ima->id.tag &= ~LIB_TAG_DOIT;
- for (tex = bmain->textures.first; tex; tex = tex->id.next)
- if (tex->ima)
- tex->ima->id.tag |= LIB_TAG_DOIT;
+ for (tex = bmain->textures.first; tex; tex = tex->id.next)
+ if (tex->ima)
+ tex->ima->id.tag |= LIB_TAG_DOIT;
- for (ima = bmain->images.first; ima; ima = ima->id.next) {
- if (ima->cache && (ima->id.tag & LIB_TAG_DOIT)) {
+ for (ima = bmain->images.first; ima; ima = ima->id.next) {
+ if (ima->cache && (ima->id.tag & LIB_TAG_DOIT)) {
#ifdef CHECK_FREED_SIZE
- uintptr_t old_size = image_mem_size(ima);
+ uintptr_t old_size = image_mem_size(ima);
#endif
- IMB_moviecache_cleanup(ima->cache, imagecache_check_dirty, NULL);
+ IMB_moviecache_cleanup(ima->cache, imagecache_check_dirty, NULL);
#ifdef CHECK_FREED_SIZE
- tot_freed_size += old_size - image_mem_size(ima);
+ tot_freed_size += old_size - image_mem_size(ima);
#endif
- }
- }
+ }
+ }
#ifdef CHECK_FREED_SIZE
- printf("%s: freed total %lu MB\n", __func__, tot_freed_size / (1024 * 1024));
+ printf("%s: freed total %lu MB\n", __func__, tot_freed_size / (1024 * 1024));
#endif
}
static bool imagecache_check_free_anim(ImBuf *ibuf, void *UNUSED(userkey), void *userdata)
{
- int except_frame = *(int *)userdata;
- return (ibuf->userflags & IB_BITMAPDIRTY) == 0 &&
- (ibuf->index != IMA_NO_INDEX) &&
- (except_frame != IMA_INDEX_FRAME(ibuf->index));
+ int except_frame = *(int *)userdata;
+ return (ibuf->userflags & IB_BITMAPDIRTY) == 0 && (ibuf->index != IMA_NO_INDEX) &&
+ (except_frame != IMA_INDEX_FRAME(ibuf->index));
}
/* except_frame is weak, only works for seqs without offset... */
void BKE_image_free_anim_ibufs(Image *ima, int except_frame)
{
- BLI_spin_lock(&image_spin);
- if (ima->cache != NULL) {
- IMB_moviecache_cleanup(ima->cache, imagecache_check_free_anim, &except_frame);
- }
- BLI_spin_unlock(&image_spin);
+ BLI_spin_lock(&image_spin);
+ if (ima->cache != NULL) {
+ IMB_moviecache_cleanup(ima->cache, imagecache_check_free_anim, &except_frame);
+ }
+ BLI_spin_unlock(&image_spin);
}
void BKE_image_all_free_anim_ibufs(Main *bmain, int cfra)
{
- Image *ima;
+ Image *ima;
- for (ima = bmain->images.first; ima; ima = ima->id.next)
- if (BKE_image_is_animated(ima))
- BKE_image_free_anim_ibufs(ima, cfra);
+ for (ima = bmain->images.first; ima; ima = ima->id.next)
+ if (BKE_image_is_animated(ima))
+ BKE_image_free_anim_ibufs(ima, cfra);
}
-
/* *********** READ AND WRITE ************** */
int BKE_image_imtype_to_ftype(const char imtype, ImbFormatOptions *r_options)
{
- memset(r_options, 0, sizeof(*r_options));
-
- if (imtype == R_IMF_IMTYPE_TARGA) {
- return IMB_FTYPE_TGA;
- }
- else if (imtype == R_IMF_IMTYPE_RAWTGA) {
- r_options->flag = RAWTGA;
- return IMB_FTYPE_TGA;
- }
- else if (imtype == R_IMF_IMTYPE_IRIS) {
- return IMB_FTYPE_IMAGIC;
- }
+ memset(r_options, 0, sizeof(*r_options));
+
+ if (imtype == R_IMF_IMTYPE_TARGA) {
+ return IMB_FTYPE_TGA;
+ }
+ else if (imtype == R_IMF_IMTYPE_RAWTGA) {
+ r_options->flag = RAWTGA;
+ return IMB_FTYPE_TGA;
+ }
+ else if (imtype == R_IMF_IMTYPE_IRIS) {
+ return IMB_FTYPE_IMAGIC;
+ }
#ifdef WITH_HDR
- else if (imtype == R_IMF_IMTYPE_RADHDR) {
- return IMB_FTYPE_RADHDR;
- }
+ else if (imtype == R_IMF_IMTYPE_RADHDR) {
+ return IMB_FTYPE_RADHDR;
+ }
#endif
- else if (imtype == R_IMF_IMTYPE_PNG) {
- r_options->quality = 15;
- return IMB_FTYPE_PNG;
- }
+ else if (imtype == R_IMF_IMTYPE_PNG) {
+ r_options->quality = 15;
+ return IMB_FTYPE_PNG;
+ }
#ifdef WITH_DDS
- else if (imtype == R_IMF_IMTYPE_DDS) {
- return IMB_FTYPE_DDS;
- }
+ else if (imtype == R_IMF_IMTYPE_DDS) {
+ return IMB_FTYPE_DDS;
+ }
#endif
- else if (imtype == R_IMF_IMTYPE_BMP) {
- return IMB_FTYPE_BMP;
- }
+ else if (imtype == R_IMF_IMTYPE_BMP) {
+ return IMB_FTYPE_BMP;
+ }
#ifdef WITH_TIFF
- else if (imtype == R_IMF_IMTYPE_TIFF) {
- return IMB_FTYPE_TIF;
- }
+ else if (imtype == R_IMF_IMTYPE_TIFF) {
+ return IMB_FTYPE_TIF;
+ }
#endif
- else if (imtype == R_IMF_IMTYPE_OPENEXR || imtype == R_IMF_IMTYPE_MULTILAYER) {
- return IMB_FTYPE_OPENEXR;
- }
+ else if (imtype == R_IMF_IMTYPE_OPENEXR || imtype == R_IMF_IMTYPE_MULTILAYER) {
+ return IMB_FTYPE_OPENEXR;
+ }
#ifdef WITH_CINEON
- else if (imtype == R_IMF_IMTYPE_CINEON) {
- return IMB_FTYPE_CINEON;
- }
- else if (imtype == R_IMF_IMTYPE_DPX) {
- return IMB_FTYPE_DPX;
- }
+ else if (imtype == R_IMF_IMTYPE_CINEON) {
+ return IMB_FTYPE_CINEON;
+ }
+ else if (imtype == R_IMF_IMTYPE_DPX) {
+ return IMB_FTYPE_DPX;
+ }
#endif
#ifdef WITH_OPENJPEG
- else if (imtype == R_IMF_IMTYPE_JP2) {
- r_options->flag |= JP2_JP2;
- r_options->quality = 90;
- return IMB_FTYPE_JP2;
- }
+ else if (imtype == R_IMF_IMTYPE_JP2) {
+ r_options->flag |= JP2_JP2;
+ r_options->quality = 90;
+ return IMB_FTYPE_JP2;
+ }
#endif
- else {
- r_options->quality = 90;
- return IMB_FTYPE_JPG;
- }
+ else {
+ r_options->quality = 90;
+ return IMB_FTYPE_JPG;
+ }
}
char BKE_image_ftype_to_imtype(const int ftype, const ImbFormatOptions *options)
{
- if (ftype == 0) {
- return R_IMF_IMTYPE_TARGA;
- }
- else if (ftype == IMB_FTYPE_IMAGIC) {
- return R_IMF_IMTYPE_IRIS;
- }
+ if (ftype == 0) {
+ return R_IMF_IMTYPE_TARGA;
+ }
+ else if (ftype == IMB_FTYPE_IMAGIC) {
+ return R_IMF_IMTYPE_IRIS;
+ }
#ifdef WITH_HDR
- else if (ftype == IMB_FTYPE_RADHDR) {
- return R_IMF_IMTYPE_RADHDR;
- }
+ else if (ftype == IMB_FTYPE_RADHDR) {
+ return R_IMF_IMTYPE_RADHDR;
+ }
#endif
- else if (ftype == IMB_FTYPE_PNG) {
- return R_IMF_IMTYPE_PNG;
- }
+ else if (ftype == IMB_FTYPE_PNG) {
+ return R_IMF_IMTYPE_PNG;
+ }
#ifdef WITH_DDS
- else if (ftype == IMB_FTYPE_DDS) {
- return R_IMF_IMTYPE_DDS;
- }
+ else if (ftype == IMB_FTYPE_DDS) {
+ return R_IMF_IMTYPE_DDS;
+ }
#endif
- else if (ftype == IMB_FTYPE_BMP) {
- return R_IMF_IMTYPE_BMP;
- }
+ else if (ftype == IMB_FTYPE_BMP) {
+ return R_IMF_IMTYPE_BMP;
+ }
#ifdef WITH_TIFF
- else if (ftype == IMB_FTYPE_TIF) {
- return R_IMF_IMTYPE_TIFF;
- }
+ else if (ftype == IMB_FTYPE_TIF) {
+ return R_IMF_IMTYPE_TIFF;
+ }
#endif
- else if (ftype == IMB_FTYPE_OPENEXR) {
- return R_IMF_IMTYPE_OPENEXR;
- }
+ else if (ftype == IMB_FTYPE_OPENEXR) {
+ return R_IMF_IMTYPE_OPENEXR;
+ }
#ifdef WITH_CINEON
- else if (ftype == IMB_FTYPE_CINEON) {
- return R_IMF_IMTYPE_CINEON;
- }
- else if (ftype == IMB_FTYPE_DPX) {
- return R_IMF_IMTYPE_DPX;
- }
+ else if (ftype == IMB_FTYPE_CINEON) {
+ return R_IMF_IMTYPE_CINEON;
+ }
+ else if (ftype == IMB_FTYPE_DPX) {
+ return R_IMF_IMTYPE_DPX;
+ }
#endif
- else if (ftype == IMB_FTYPE_TGA) {
- if (options && (options->flag & RAWTGA)) {
- return R_IMF_IMTYPE_RAWTGA;
- }
- else {
- return R_IMF_IMTYPE_TARGA;
- }
- }
+ else if (ftype == IMB_FTYPE_TGA) {
+ if (options && (options->flag & RAWTGA)) {
+ return R_IMF_IMTYPE_RAWTGA;
+ }
+ else {
+ return R_IMF_IMTYPE_TARGA;
+ }
+ }
#ifdef WITH_OPENJPEG
- else if (ftype == IMB_FTYPE_JP2) {
- return R_IMF_IMTYPE_JP2;
- }
+ else if (ftype == IMB_FTYPE_JP2) {
+ return R_IMF_IMTYPE_JP2;
+ }
#endif
- else {
- return R_IMF_IMTYPE_JPEG90;
- }
+ else {
+ return R_IMF_IMTYPE_JPEG90;
+ }
}
-
bool BKE_imtype_is_movie(const char imtype)
{
- switch (imtype) {
- case R_IMF_IMTYPE_AVIRAW:
- case R_IMF_IMTYPE_AVIJPEG:
- case R_IMF_IMTYPE_FFMPEG:
- case R_IMF_IMTYPE_H264:
- case R_IMF_IMTYPE_THEORA:
- case R_IMF_IMTYPE_XVID:
- return true;
- }
- return false;
+ switch (imtype) {
+ case R_IMF_IMTYPE_AVIRAW:
+ case R_IMF_IMTYPE_AVIJPEG:
+ case R_IMF_IMTYPE_FFMPEG:
+ case R_IMF_IMTYPE_H264:
+ case R_IMF_IMTYPE_THEORA:
+ case R_IMF_IMTYPE_XVID:
+ return true;
+ }
+ return false;
}
int BKE_imtype_supports_zbuf(const char imtype)
{
- switch (imtype) {
- case R_IMF_IMTYPE_IRIZ:
- case R_IMF_IMTYPE_OPENEXR: /* but not R_IMF_IMTYPE_MULTILAYER */
- return 1;
- }
- return 0;
+ switch (imtype) {
+ case R_IMF_IMTYPE_IRIZ:
+ case R_IMF_IMTYPE_OPENEXR: /* but not R_IMF_IMTYPE_MULTILAYER */
+ return 1;
+ }
+ return 0;
}
int BKE_imtype_supports_compress(const char imtype)
{
- switch (imtype) {
- case R_IMF_IMTYPE_PNG:
- return 1;
- }
- return 0;
+ switch (imtype) {
+ case R_IMF_IMTYPE_PNG:
+ return 1;
+ }
+ return 0;
}
int BKE_imtype_supports_quality(const char imtype)
{
- switch (imtype) {
- case R_IMF_IMTYPE_JPEG90:
- case R_IMF_IMTYPE_JP2:
- case R_IMF_IMTYPE_AVIJPEG:
- return 1;
- }
- return 0;
+ switch (imtype) {
+ case R_IMF_IMTYPE_JPEG90:
+ case R_IMF_IMTYPE_JP2:
+ case R_IMF_IMTYPE_AVIJPEG:
+ return 1;
+ }
+ return 0;
}
int BKE_imtype_requires_linear_float(const char imtype)
{
- switch (imtype) {
- case R_IMF_IMTYPE_CINEON:
- case R_IMF_IMTYPE_DPX:
- case R_IMF_IMTYPE_RADHDR:
- case R_IMF_IMTYPE_OPENEXR:
- case R_IMF_IMTYPE_MULTILAYER:
- return true;
- }
- return 0;
+ switch (imtype) {
+ case R_IMF_IMTYPE_CINEON:
+ case R_IMF_IMTYPE_DPX:
+ case R_IMF_IMTYPE_RADHDR:
+ case R_IMF_IMTYPE_OPENEXR:
+ case R_IMF_IMTYPE_MULTILAYER:
+ return true;
+ }
+ return 0;
}
char BKE_imtype_valid_channels(const char imtype, bool write_file)
{
- char chan_flag = IMA_CHAN_FLAG_RGB; /* assume all support rgb */
-
- /* alpha */
- switch (imtype) {
- case R_IMF_IMTYPE_BMP:
- if (write_file) break;
- ATTR_FALLTHROUGH;
- case R_IMF_IMTYPE_TARGA:
- case R_IMF_IMTYPE_RAWTGA:
- case R_IMF_IMTYPE_IRIS:
- case R_IMF_IMTYPE_PNG:
- case R_IMF_IMTYPE_TIFF:
- case R_IMF_IMTYPE_OPENEXR:
- case R_IMF_IMTYPE_MULTILAYER:
- case R_IMF_IMTYPE_DDS:
- case R_IMF_IMTYPE_JP2:
- case R_IMF_IMTYPE_DPX:
- chan_flag |= IMA_CHAN_FLAG_ALPHA;
- break;
- }
-
- /* bw */
- switch (imtype) {
- case R_IMF_IMTYPE_PNG:
- case R_IMF_IMTYPE_JPEG90:
- case R_IMF_IMTYPE_TARGA:
- case R_IMF_IMTYPE_RAWTGA:
- case R_IMF_IMTYPE_TIFF:
- case R_IMF_IMTYPE_IRIS:
- chan_flag |= IMA_CHAN_FLAG_BW;
- break;
- }
-
- return chan_flag;
+ char chan_flag = IMA_CHAN_FLAG_RGB; /* assume all support rgb */
+
+ /* alpha */
+ switch (imtype) {
+ case R_IMF_IMTYPE_BMP:
+ if (write_file)
+ break;
+ ATTR_FALLTHROUGH;
+ case R_IMF_IMTYPE_TARGA:
+ case R_IMF_IMTYPE_RAWTGA:
+ case R_IMF_IMTYPE_IRIS:
+ case R_IMF_IMTYPE_PNG:
+ case R_IMF_IMTYPE_TIFF:
+ case R_IMF_IMTYPE_OPENEXR:
+ case R_IMF_IMTYPE_MULTILAYER:
+ case R_IMF_IMTYPE_DDS:
+ case R_IMF_IMTYPE_JP2:
+ case R_IMF_IMTYPE_DPX:
+ chan_flag |= IMA_CHAN_FLAG_ALPHA;
+ break;
+ }
+
+ /* bw */
+ switch (imtype) {
+ case R_IMF_IMTYPE_PNG:
+ case R_IMF_IMTYPE_JPEG90:
+ case R_IMF_IMTYPE_TARGA:
+ case R_IMF_IMTYPE_RAWTGA:
+ case R_IMF_IMTYPE_TIFF:
+ case R_IMF_IMTYPE_IRIS:
+ chan_flag |= IMA_CHAN_FLAG_BW;
+ break;
+ }
+
+ return chan_flag;
}
char BKE_imtype_valid_depths(const char imtype)
{
- switch (imtype) {
- case R_IMF_IMTYPE_RADHDR:
- return R_IMF_CHAN_DEPTH_32;
- case R_IMF_IMTYPE_TIFF:
- return R_IMF_CHAN_DEPTH_8 | R_IMF_CHAN_DEPTH_16;
- case R_IMF_IMTYPE_OPENEXR:
- return R_IMF_CHAN_DEPTH_16 | R_IMF_CHAN_DEPTH_32;
- case R_IMF_IMTYPE_MULTILAYER:
- return R_IMF_CHAN_DEPTH_16 | R_IMF_CHAN_DEPTH_32;
- /* eeh, cineon does some strange 10bits per channel */
- case R_IMF_IMTYPE_DPX:
- return R_IMF_CHAN_DEPTH_8 | R_IMF_CHAN_DEPTH_10 | R_IMF_CHAN_DEPTH_12 | R_IMF_CHAN_DEPTH_16;
- case R_IMF_IMTYPE_CINEON:
- return R_IMF_CHAN_DEPTH_10;
- case R_IMF_IMTYPE_JP2:
- return R_IMF_CHAN_DEPTH_8 | R_IMF_CHAN_DEPTH_12 | R_IMF_CHAN_DEPTH_16;
- case R_IMF_IMTYPE_PNG:
- return R_IMF_CHAN_DEPTH_8 | R_IMF_CHAN_DEPTH_16;
- /* most formats are 8bit only */
- default:
- return R_IMF_CHAN_DEPTH_8;
- }
+ switch (imtype) {
+ case R_IMF_IMTYPE_RADHDR:
+ return R_IMF_CHAN_DEPTH_32;
+ case R_IMF_IMTYPE_TIFF:
+ return R_IMF_CHAN_DEPTH_8 | R_IMF_CHAN_DEPTH_16;
+ case R_IMF_IMTYPE_OPENEXR:
+ return R_IMF_CHAN_DEPTH_16 | R_IMF_CHAN_DEPTH_32;
+ case R_IMF_IMTYPE_MULTILAYER:
+ return R_IMF_CHAN_DEPTH_16 | R_IMF_CHAN_DEPTH_32;
+ /* eeh, cineon does some strange 10bits per channel */
+ case R_IMF_IMTYPE_DPX:
+ return R_IMF_CHAN_DEPTH_8 | R_IMF_CHAN_DEPTH_10 | R_IMF_CHAN_DEPTH_12 | R_IMF_CHAN_DEPTH_16;
+ case R_IMF_IMTYPE_CINEON:
+ return R_IMF_CHAN_DEPTH_10;
+ case R_IMF_IMTYPE_JP2:
+ return R_IMF_CHAN_DEPTH_8 | R_IMF_CHAN_DEPTH_12 | R_IMF_CHAN_DEPTH_16;
+ case R_IMF_IMTYPE_PNG:
+ return R_IMF_CHAN_DEPTH_8 | R_IMF_CHAN_DEPTH_16;
+ /* most formats are 8bit only */
+ default:
+ return R_IMF_CHAN_DEPTH_8;
+ }
}
-
/* string is from command line --render-format arg, keep in sync with
* creator_args.c help info */
char BKE_imtype_from_arg(const char *imtype_arg)
{
- if (STREQ(imtype_arg, "TGA")) return R_IMF_IMTYPE_TARGA;
- else if (STREQ(imtype_arg, "IRIS")) return R_IMF_IMTYPE_IRIS;
+ if (STREQ(imtype_arg, "TGA"))
+ return R_IMF_IMTYPE_TARGA;
+ else if (STREQ(imtype_arg, "IRIS"))
+ return R_IMF_IMTYPE_IRIS;
#ifdef WITH_DDS
- else if (STREQ(imtype_arg, "DDS")) return R_IMF_IMTYPE_DDS;
+ else if (STREQ(imtype_arg, "DDS"))
+ return R_IMF_IMTYPE_DDS;
#endif
- else if (STREQ(imtype_arg, "JPEG")) return R_IMF_IMTYPE_JPEG90;
- else if (STREQ(imtype_arg, "IRIZ")) return R_IMF_IMTYPE_IRIZ;
- else if (STREQ(imtype_arg, "RAWTGA")) return R_IMF_IMTYPE_RAWTGA;
- else if (STREQ(imtype_arg, "AVIRAW")) return R_IMF_IMTYPE_AVIRAW;
- else if (STREQ(imtype_arg, "AVIJPEG")) return R_IMF_IMTYPE_AVIJPEG;
- else if (STREQ(imtype_arg, "PNG")) return R_IMF_IMTYPE_PNG;
- else if (STREQ(imtype_arg, "BMP")) return R_IMF_IMTYPE_BMP;
+ else if (STREQ(imtype_arg, "JPEG"))
+ return R_IMF_IMTYPE_JPEG90;
+ else if (STREQ(imtype_arg, "IRIZ"))
+ return R_IMF_IMTYPE_IRIZ;
+ else if (STREQ(imtype_arg, "RAWTGA"))
+ return R_IMF_IMTYPE_RAWTGA;
+ else if (STREQ(imtype_arg, "AVIRAW"))
+ return R_IMF_IMTYPE_AVIRAW;
+ else if (STREQ(imtype_arg, "AVIJPEG"))
+ return R_IMF_IMTYPE_AVIJPEG;
+ else if (STREQ(imtype_arg, "PNG"))
+ return R_IMF_IMTYPE_PNG;
+ else if (STREQ(imtype_arg, "BMP"))
+ return R_IMF_IMTYPE_BMP;
#ifdef WITH_HDR
- else if (STREQ(imtype_arg, "HDR")) return R_IMF_IMTYPE_RADHDR;
+ else if (STREQ(imtype_arg, "HDR"))
+ return R_IMF_IMTYPE_RADHDR;
#endif
#ifdef WITH_TIFF
- else if (STREQ(imtype_arg, "TIFF")) return R_IMF_IMTYPE_TIFF;
+ else if (STREQ(imtype_arg, "TIFF"))
+ return R_IMF_IMTYPE_TIFF;
#endif
#ifdef WITH_OPENEXR
- else if (STREQ(imtype_arg, "OPEN_EXR")) return R_IMF_IMTYPE_OPENEXR;
- else if (STREQ(imtype_arg, "OPEN_EXR_MULTILAYER")) return R_IMF_IMTYPE_MULTILAYER;
- else if (STREQ(imtype_arg, "EXR")) return R_IMF_IMTYPE_OPENEXR;
- else if (STREQ(imtype_arg, "MULTILAYER")) return R_IMF_IMTYPE_MULTILAYER;
+ else if (STREQ(imtype_arg, "OPEN_EXR"))
+ return R_IMF_IMTYPE_OPENEXR;
+ else if (STREQ(imtype_arg, "OPEN_EXR_MULTILAYER"))
+ return R_IMF_IMTYPE_MULTILAYER;
+ else if (STREQ(imtype_arg, "EXR"))
+ return R_IMF_IMTYPE_OPENEXR;
+ else if (STREQ(imtype_arg, "MULTILAYER"))
+ return R_IMF_IMTYPE_MULTILAYER;
#endif
- else if (STREQ(imtype_arg, "FFMPEG")) return R_IMF_IMTYPE_FFMPEG;
+ else if (STREQ(imtype_arg, "FFMPEG"))
+ return R_IMF_IMTYPE_FFMPEG;
#ifdef WITH_CINEON
- else if (STREQ(imtype_arg, "CINEON")) return R_IMF_IMTYPE_CINEON;
- else if (STREQ(imtype_arg, "DPX")) return R_IMF_IMTYPE_DPX;
+ else if (STREQ(imtype_arg, "CINEON"))
+ return R_IMF_IMTYPE_CINEON;
+ else if (STREQ(imtype_arg, "DPX"))
+ return R_IMF_IMTYPE_DPX;
#endif
#ifdef WITH_OPENJPEG
- else if (STREQ(imtype_arg, "JP2")) return R_IMF_IMTYPE_JP2;
+ else if (STREQ(imtype_arg, "JP2"))
+ return R_IMF_IMTYPE_JP2;
#endif
- else return R_IMF_IMTYPE_INVALID;
-}
-
-static bool do_add_image_extension(char *string, const char imtype, const ImageFormatData *im_format)
-{
- const char *extension = NULL;
- const char *extension_test;
- (void)im_format; /* may be unused, depends on build options */
-
- if (imtype == R_IMF_IMTYPE_IRIS) {
- if (!BLI_path_extension_check(string, extension_test = ".rgb"))
- extension = extension_test;
- }
- else if (imtype == R_IMF_IMTYPE_IRIZ) {
- if (!BLI_path_extension_check(string, extension_test = ".rgb"))
- extension = extension_test;
- }
+ else
+ return R_IMF_IMTYPE_INVALID;
+}
+
+static bool do_add_image_extension(char *string,
+ const char imtype,
+ const ImageFormatData *im_format)
+{
+ const char *extension = NULL;
+ const char *extension_test;
+ (void)im_format; /* may be unused, depends on build options */
+
+ if (imtype == R_IMF_IMTYPE_IRIS) {
+ if (!BLI_path_extension_check(string, extension_test = ".rgb"))
+ extension = extension_test;
+ }
+ else if (imtype == R_IMF_IMTYPE_IRIZ) {
+ if (!BLI_path_extension_check(string, extension_test = ".rgb"))
+ extension = extension_test;
+ }
#ifdef WITH_HDR
- else if (imtype == R_IMF_IMTYPE_RADHDR) {
- if (!BLI_path_extension_check(string, extension_test = ".hdr"))
- extension = extension_test;
- }
+ else if (imtype == R_IMF_IMTYPE_RADHDR) {
+ if (!BLI_path_extension_check(string, extension_test = ".hdr"))
+ extension = extension_test;
+ }
#endif
- else if (ELEM(imtype, R_IMF_IMTYPE_PNG, R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_THEORA, R_IMF_IMTYPE_XVID)) {
- if (!BLI_path_extension_check(string, extension_test = ".png"))
- extension = extension_test;
- }
+ else if (ELEM(imtype,
+ R_IMF_IMTYPE_PNG,
+ R_IMF_IMTYPE_FFMPEG,
+ R_IMF_IMTYPE_H264,
+ R_IMF_IMTYPE_THEORA,
+ R_IMF_IMTYPE_XVID)) {
+ if (!BLI_path_extension_check(string, extension_test = ".png"))
+ extension = extension_test;
+ }
#ifdef WITH_DDS
- else if (imtype == R_IMF_IMTYPE_DDS) {
- if (!BLI_path_extension_check(string, extension_test = ".dds"))
- extension = extension_test;
- }
+ else if (imtype == R_IMF_IMTYPE_DDS) {
+ if (!BLI_path_extension_check(string, extension_test = ".dds"))
+ extension = extension_test;
+ }
#endif
- else if (ELEM(imtype, R_IMF_IMTYPE_TARGA, R_IMF_IMTYPE_RAWTGA)) {
- if (!BLI_path_extension_check(string, extension_test = ".tga"))
- extension = extension_test;
- }
- else if (imtype == R_IMF_IMTYPE_BMP) {
- if (!BLI_path_extension_check(string, extension_test = ".bmp"))
- extension = extension_test;
- }
+ else if (ELEM(imtype, R_IMF_IMTYPE_TARGA, R_IMF_IMTYPE_RAWTGA)) {
+ if (!BLI_path_extension_check(string, extension_test = ".tga"))
+ extension = extension_test;
+ }
+ else if (imtype == R_IMF_IMTYPE_BMP) {
+ if (!BLI_path_extension_check(string, extension_test = ".bmp"))
+ extension = extension_test;
+ }
#ifdef WITH_TIFF
- else if (imtype == R_IMF_IMTYPE_TIFF) {
- if (!BLI_path_extension_check_n(string, extension_test = ".tif", ".tiff", NULL)) {
- extension = extension_test;
- }
- }
+ else if (imtype == R_IMF_IMTYPE_TIFF) {
+ if (!BLI_path_extension_check_n(string, extension_test = ".tif", ".tiff", NULL)) {
+ extension = extension_test;
+ }
+ }
#endif
#ifdef WITH_OPENIMAGEIO
- else if (imtype == R_IMF_IMTYPE_PSD) {
- if (!BLI_path_extension_check(string, extension_test = ".psd"))
- extension = extension_test;
- }
+ else if (imtype == R_IMF_IMTYPE_PSD) {
+ if (!BLI_path_extension_check(string, extension_test = ".psd"))
+ extension = extension_test;
+ }
#endif
#ifdef WITH_OPENEXR
- else if (imtype == R_IMF_IMTYPE_OPENEXR || imtype == R_IMF_IMTYPE_MULTILAYER) {
- if (!BLI_path_extension_check(string, extension_test = ".exr"))
- extension = extension_test;
- }
+ else if (imtype == R_IMF_IMTYPE_OPENEXR || imtype == R_IMF_IMTYPE_MULTILAYER) {
+ if (!BLI_path_extension_check(string, extension_test = ".exr"))
+ extension = extension_test;
+ }
#endif
#ifdef WITH_CINEON
- else if (imtype == R_IMF_IMTYPE_CINEON) {
- if (!BLI_path_extension_check(string, extension_test = ".cin"))
- extension = extension_test;
- }
- else if (imtype == R_IMF_IMTYPE_DPX) {
- if (!BLI_path_extension_check(string, extension_test = ".dpx"))
- extension = extension_test;
- }
+ else if (imtype == R_IMF_IMTYPE_CINEON) {
+ if (!BLI_path_extension_check(string, extension_test = ".cin"))
+ extension = extension_test;
+ }
+ else if (imtype == R_IMF_IMTYPE_DPX) {
+ if (!BLI_path_extension_check(string, extension_test = ".dpx"))
+ extension = extension_test;
+ }
#endif
#ifdef WITH_OPENJPEG
- else if (imtype == R_IMF_IMTYPE_JP2) {
- if (im_format) {
- if (im_format->jp2_codec == R_IMF_JP2_CODEC_JP2) {
- if (!BLI_path_extension_check(string, extension_test = ".jp2"))
- extension = extension_test;
- }
- else if (im_format->jp2_codec == R_IMF_JP2_CODEC_J2K) {
- if (!BLI_path_extension_check(string, extension_test = ".j2c"))
- extension = extension_test;
- }
- else
- BLI_assert(!"Unsupported jp2 codec was specified in im_format->jp2_codec");
- }
- else {
- if (!BLI_path_extension_check(string, extension_test = ".jp2"))
- extension = extension_test;
- }
- }
+ else if (imtype == R_IMF_IMTYPE_JP2) {
+ if (im_format) {
+ if (im_format->jp2_codec == R_IMF_JP2_CODEC_JP2) {
+ if (!BLI_path_extension_check(string, extension_test = ".jp2"))
+ extension = extension_test;
+ }
+ else if (im_format->jp2_codec == R_IMF_JP2_CODEC_J2K) {
+ if (!BLI_path_extension_check(string, extension_test = ".j2c"))
+ extension = extension_test;
+ }
+ else
+ BLI_assert(!"Unsupported jp2 codec was specified in im_format->jp2_codec");
+ }
+ else {
+ if (!BLI_path_extension_check(string, extension_test = ".jp2"))
+ extension = extension_test;
+ }
+ }
#endif
- else { // R_IMF_IMTYPE_AVIRAW, R_IMF_IMTYPE_AVIJPEG, R_IMF_IMTYPE_JPEG90 etc
- if (!(BLI_path_extension_check_n(string, extension_test = ".jpg", ".jpeg", NULL)))
- extension = extension_test;
- }
-
- if (extension) {
- /* prefer this in many cases to avoid .png.tga, but in certain cases it breaks */
- /* remove any other known image extension */
- if (BLI_path_extension_check_array(string, imb_ext_image)) {
- return BLI_path_extension_replace(string, FILE_MAX, extension);
- }
- else {
- return BLI_path_extension_ensure(string, FILE_MAX, extension);
- }
-
- }
- else {
- return false;
- }
+ else { // R_IMF_IMTYPE_AVIRAW, R_IMF_IMTYPE_AVIJPEG, R_IMF_IMTYPE_JPEG90 etc
+ if (!(BLI_path_extension_check_n(string, extension_test = ".jpg", ".jpeg", NULL)))
+ extension = extension_test;
+ }
+
+ if (extension) {
+ /* prefer this in many cases to avoid .png.tga, but in certain cases it breaks */
+ /* remove any other known image extension */
+ if (BLI_path_extension_check_array(string, imb_ext_image)) {
+ return BLI_path_extension_replace(string, FILE_MAX, extension);
+ }
+ else {
+ return BLI_path_extension_ensure(string, FILE_MAX, extension);
+ }
+ }
+ else {
+ return false;
+ }
}
int BKE_image_path_ensure_ext_from_imformat(char *string, const ImageFormatData *im_format)
{
- return do_add_image_extension(string, im_format->imtype, im_format);
+ return do_add_image_extension(string, im_format->imtype, im_format);
}
int BKE_image_path_ensure_ext_from_imtype(char *string, const char imtype)
{
- return do_add_image_extension(string, imtype, NULL);
+ return do_add_image_extension(string, imtype, NULL);
}
void BKE_imformat_defaults(ImageFormatData *im_format)
{
- memset(im_format, 0, sizeof(*im_format));
- im_format->planes = R_IMF_PLANES_RGBA;
- im_format->imtype = R_IMF_IMTYPE_PNG;
- im_format->depth = R_IMF_CHAN_DEPTH_8;
- im_format->quality = 90;
- im_format->compress = 15;
+ memset(im_format, 0, sizeof(*im_format));
+ im_format->planes = R_IMF_PLANES_RGBA;
+ im_format->imtype = R_IMF_IMTYPE_PNG;
+ im_format->depth = R_IMF_CHAN_DEPTH_8;
+ im_format->quality = 90;
+ im_format->compress = 15;
- BKE_color_managed_display_settings_init(&im_format->display_settings);
- BKE_color_managed_view_settings_init_default(&im_format->view_settings,
- &im_format->display_settings);
+ BKE_color_managed_display_settings_init(&im_format->display_settings);
+ BKE_color_managed_view_settings_init_default(&im_format->view_settings,
+ &im_format->display_settings);
}
void BKE_imbuf_to_image_format(struct ImageFormatData *im_format, const ImBuf *imbuf)
{
- int ftype = imbuf->ftype;
- int custom_flags = imbuf->foptions.flag;
- char quality = imbuf->foptions.quality;
+ int ftype = imbuf->ftype;
+ int custom_flags = imbuf->foptions.flag;
+ char quality = imbuf->foptions.quality;
- BKE_imformat_defaults(im_format);
+ BKE_imformat_defaults(im_format);
- /* file type */
+ /* file type */
- if (ftype == IMB_FTYPE_IMAGIC)
- im_format->imtype = R_IMF_IMTYPE_IRIS;
+ if (ftype == IMB_FTYPE_IMAGIC)
+ im_format->imtype = R_IMF_IMTYPE_IRIS;
#ifdef WITH_HDR
- else if (ftype == IMB_FTYPE_RADHDR)
- im_format->imtype = R_IMF_IMTYPE_RADHDR;
+ else if (ftype == IMB_FTYPE_RADHDR)
+ im_format->imtype = R_IMF_IMTYPE_RADHDR;
#endif
- else if (ftype == IMB_FTYPE_PNG) {
- im_format->imtype = R_IMF_IMTYPE_PNG;
+ else if (ftype == IMB_FTYPE_PNG) {
+ im_format->imtype = R_IMF_IMTYPE_PNG;
- if (custom_flags & PNG_16BIT)
- im_format->depth = R_IMF_CHAN_DEPTH_16;
+ if (custom_flags & PNG_16BIT)
+ im_format->depth = R_IMF_CHAN_DEPTH_16;
- im_format->compress = quality;
- }
+ im_format->compress = quality;
+ }
#ifdef WITH_DDS
- else if (ftype == IMB_FTYPE_DDS)
- im_format->imtype = R_IMF_IMTYPE_DDS;
+ else if (ftype == IMB_FTYPE_DDS)
+ im_format->imtype = R_IMF_IMTYPE_DDS;
#endif
- else if (ftype == IMB_FTYPE_BMP)
- im_format->imtype = R_IMF_IMTYPE_BMP;
+ else if (ftype == IMB_FTYPE_BMP)
+ im_format->imtype = R_IMF_IMTYPE_BMP;
#ifdef WITH_TIFF
- else if (ftype == IMB_FTYPE_TIF) {
- im_format->imtype = R_IMF_IMTYPE_TIFF;
- if (custom_flags & TIF_16BIT)
- im_format->depth = R_IMF_CHAN_DEPTH_16;
- if (custom_flags & TIF_COMPRESS_NONE)
- im_format->tiff_codec = R_IMF_TIFF_CODEC_NONE;
- if (custom_flags & TIF_COMPRESS_DEFLATE)
- im_format->tiff_codec = R_IMF_TIFF_CODEC_DEFLATE;
- if (custom_flags & TIF_COMPRESS_LZW)
- im_format->tiff_codec = R_IMF_TIFF_CODEC_LZW;
- if (custom_flags & TIF_COMPRESS_PACKBITS)
- im_format->tiff_codec = R_IMF_TIFF_CODEC_PACKBITS;
- }
+ else if (ftype == IMB_FTYPE_TIF) {
+ im_format->imtype = R_IMF_IMTYPE_TIFF;
+ if (custom_flags & TIF_16BIT)
+ im_format->depth = R_IMF_CHAN_DEPTH_16;
+ if (custom_flags & TIF_COMPRESS_NONE)
+ im_format->tiff_codec = R_IMF_TIFF_CODEC_NONE;
+ if (custom_flags & TIF_COMPRESS_DEFLATE)
+ im_format->tiff_codec = R_IMF_TIFF_CODEC_DEFLATE;
+ if (custom_flags & TIF_COMPRESS_LZW)
+ im_format->tiff_codec = R_IMF_TIFF_CODEC_LZW;
+ if (custom_flags & TIF_COMPRESS_PACKBITS)
+ im_format->tiff_codec = R_IMF_TIFF_CODEC_PACKBITS;
+ }
#endif
#ifdef WITH_OPENEXR
- else if (ftype == IMB_FTYPE_OPENEXR) {
- im_format->imtype = R_IMF_IMTYPE_OPENEXR;
- if (custom_flags & OPENEXR_HALF)
- im_format->depth = R_IMF_CHAN_DEPTH_16;
- if (custom_flags & OPENEXR_COMPRESS)
- im_format->exr_codec = R_IMF_EXR_CODEC_ZIP; // Can't determine compression
- if (imbuf->zbuf_float)
- im_format->flag |= R_IMF_FLAG_ZBUF;
- }
+ else if (ftype == IMB_FTYPE_OPENEXR) {
+ im_format->imtype = R_IMF_IMTYPE_OPENEXR;
+ if (custom_flags & OPENEXR_HALF)
+ im_format->depth = R_IMF_CHAN_DEPTH_16;
+ if (custom_flags & OPENEXR_COMPRESS)
+ im_format->exr_codec = R_IMF_EXR_CODEC_ZIP; // Can't determine compression
+ if (imbuf->zbuf_float)
+ im_format->flag |= R_IMF_FLAG_ZBUF;
+ }
#endif
#ifdef WITH_CINEON
- else if (ftype == IMB_FTYPE_CINEON)
- im_format->imtype = R_IMF_IMTYPE_CINEON;
- else if (ftype == IMB_FTYPE_DPX)
- im_format->imtype = R_IMF_IMTYPE_DPX;
+ else if (ftype == IMB_FTYPE_CINEON)
+ im_format->imtype = R_IMF_IMTYPE_CINEON;
+ else if (ftype == IMB_FTYPE_DPX)
+ im_format->imtype = R_IMF_IMTYPE_DPX;
#endif
- else if (ftype == IMB_FTYPE_TGA) {
- if (custom_flags & RAWTGA)
- im_format->imtype = R_IMF_IMTYPE_RAWTGA;
- else
- im_format->imtype = R_IMF_IMTYPE_TARGA;
- }
+ else if (ftype == IMB_FTYPE_TGA) {
+ if (custom_flags & RAWTGA)
+ im_format->imtype = R_IMF_IMTYPE_RAWTGA;
+ else
+ im_format->imtype = R_IMF_IMTYPE_TARGA;
+ }
#ifdef WITH_OPENJPEG
- else if (ftype == IMB_FTYPE_JP2) {
- im_format->imtype = R_IMF_IMTYPE_JP2;
- im_format->quality = quality;
-
- if (custom_flags & JP2_16BIT)
- im_format->depth = R_IMF_CHAN_DEPTH_16;
- else if (custom_flags & JP2_12BIT)
- im_format->depth = R_IMF_CHAN_DEPTH_12;
-
- if (custom_flags & JP2_YCC)
- im_format->jp2_flag |= R_IMF_JP2_FLAG_YCC;
-
- if (custom_flags & JP2_CINE) {
- im_format->jp2_flag |= R_IMF_JP2_FLAG_CINE_PRESET;
- if (custom_flags & JP2_CINE_48FPS)
- im_format->jp2_flag |= R_IMF_JP2_FLAG_CINE_48;
- }
-
- if (custom_flags & JP2_JP2)
- im_format->jp2_codec = R_IMF_JP2_CODEC_JP2;
- else if (custom_flags & JP2_J2K)
- im_format->jp2_codec = R_IMF_JP2_CODEC_J2K;
- else
- BLI_assert(!"Unsupported jp2 codec was specified in file type");
- }
+ else if (ftype == IMB_FTYPE_JP2) {
+ im_format->imtype = R_IMF_IMTYPE_JP2;
+ im_format->quality = quality;
+
+ if (custom_flags & JP2_16BIT)
+ im_format->depth = R_IMF_CHAN_DEPTH_16;
+ else if (custom_flags & JP2_12BIT)
+ im_format->depth = R_IMF_CHAN_DEPTH_12;
+
+ if (custom_flags & JP2_YCC)
+ im_format->jp2_flag |= R_IMF_JP2_FLAG_YCC;
+
+ if (custom_flags & JP2_CINE) {
+ im_format->jp2_flag |= R_IMF_JP2_FLAG_CINE_PRESET;
+ if (custom_flags & JP2_CINE_48FPS)
+ im_format->jp2_flag |= R_IMF_JP2_FLAG_CINE_48;
+ }
+
+ if (custom_flags & JP2_JP2)
+ im_format->jp2_codec = R_IMF_JP2_CODEC_JP2;
+ else if (custom_flags & JP2_J2K)
+ im_format->jp2_codec = R_IMF_JP2_CODEC_J2K;
+ else
+ BLI_assert(!"Unsupported jp2 codec was specified in file type");
+ }
#endif
- else {
- im_format->imtype = R_IMF_IMTYPE_JPEG90;
- im_format->quality = quality;
- }
+ else {
+ im_format->imtype = R_IMF_IMTYPE_JPEG90;
+ im_format->quality = quality;
+ }
- /* planes */
- im_format->planes = imbuf->planes;
+ /* planes */
+ im_format->planes = imbuf->planes;
}
-
#define STAMP_NAME_SIZE ((MAX_ID_NAME - 2) + 16)
/* could allow access externally - 512 is for long names,
* STAMP_NAME_SIZE is for id names, allowing them some room for description */
typedef struct StampDataCustomField {
- struct StampDataCustomField *next, *prev;
- /* TODO(sergey): Think of better size here, maybe dynamically allocated even. */
- char key[512];
- char *value;
- /* TODO(sergey): Support non-string values. */
+ struct StampDataCustomField *next, *prev;
+ /* TODO(sergey): Think of better size here, maybe dynamically allocated even. */
+ char key[512];
+ char *value;
+ /* TODO(sergey): Support non-string values. */
} StampDataCustomField;
typedef struct StampData {
- char file[512];
- char note[512];
- char date[512];
- char marker[512];
- char time[512];
- char frame[512];
- char frame_range[512];
- char camera[STAMP_NAME_SIZE];
- char cameralens[STAMP_NAME_SIZE];
- char scene[STAMP_NAME_SIZE];
- char strip[STAMP_NAME_SIZE];
- char rendertime[STAMP_NAME_SIZE];
- char memory[STAMP_NAME_SIZE];
- char hostname[512];
-
- /* Custom fields are used to put extra meta information header from render
- * engine to the result image.
- *
- * NOTE: This fields are not stamped onto the image. At least for now.
- */
- ListBase custom_fields;
+ char file[512];
+ char note[512];
+ char date[512];
+ char marker[512];
+ char time[512];
+ char frame[512];
+ char frame_range[512];
+ char camera[STAMP_NAME_SIZE];
+ char cameralens[STAMP_NAME_SIZE];
+ char scene[STAMP_NAME_SIZE];
+ char strip[STAMP_NAME_SIZE];
+ char rendertime[STAMP_NAME_SIZE];
+ char memory[STAMP_NAME_SIZE];
+ char hostname[512];
+
+ /* Custom fields are used to put extra meta information header from render
+ * engine to the result image.
+ *
+ * NOTE: This fields are not stamped onto the image. At least for now.
+ */
+ ListBase custom_fields;
} StampData;
#undef STAMP_NAME_SIZE
@@ -1561,161 +1602,177 @@ typedef struct StampData {
* \param do_prefix: Include a label like "File ", "Date ", etc. in the stamp data strings.
* \param use_dynamic: Also include data that can change on a per-frame basis.
*/
-static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int do_prefix,
- bool use_dynamic)
-{
- char text[256];
- struct tm *tl;
- time_t t;
-
- if (scene->r.stamp & R_STAMP_FILENAME) {
- SNPRINTF(stamp_data->file, do_prefix ? "File %s" : "%s",
- G.relbase_valid ? BKE_main_blendfile_path_from_global() : "<untitled>");
- }
- else {
- stamp_data->file[0] = '\0';
- }
-
- if (scene->r.stamp & R_STAMP_NOTE) {
- /* Never do prefix for Note */
- SNPRINTF(stamp_data->note, "%s", scene->r.stamp_udata);
- }
- else {
- stamp_data->note[0] = '\0';
- }
-
- if (scene->r.stamp & R_STAMP_DATE) {
- t = time(NULL);
- tl = localtime(&t);
- SNPRINTF(text, "%04d/%02d/%02d %02d:%02d:%02d",
- tl->tm_year + 1900, tl->tm_mon + 1, tl->tm_mday, tl->tm_hour, tl->tm_min, tl->tm_sec);
- SNPRINTF(stamp_data->date, do_prefix ? "Date %s" : "%s", text);
- }
- else {
- stamp_data->date[0] = '\0';
- }
-
- if (use_dynamic && scene->r.stamp & R_STAMP_MARKER) {
- const char *name = BKE_scene_find_last_marker_name(scene, CFRA);
-
- if (name) STRNCPY(text, name);
- else STRNCPY(text, "<none>");
-
- SNPRINTF(stamp_data->marker, do_prefix ? "Marker %s" : "%s", text);
- }
- else {
- stamp_data->marker[0] = '\0';
- }
-
- if (use_dynamic && scene->r.stamp & R_STAMP_TIME) {
- const short timecode_style = USER_TIMECODE_SMPTE_FULL;
- BLI_timecode_string_from_time(text, sizeof(text), 0, FRA2TIME(scene->r.cfra), FPS, timecode_style);
- SNPRINTF(stamp_data->time, do_prefix ? "Timecode %s" : "%s", text);
- }
- else {
- stamp_data->time[0] = '\0';
- }
-
- if (use_dynamic && scene->r.stamp & R_STAMP_FRAME) {
- char fmtstr[32];
- int digits = 1;
-
- if (scene->r.efra > 9)
- digits = integer_digits_i(scene->r.efra);
-
- SNPRINTF(fmtstr, do_prefix ? "Frame %%0%di" : "%%0%di", digits);
- SNPRINTF(stamp_data->frame, fmtstr, scene->r.cfra);
- }
- else {
- stamp_data->frame[0] = '\0';
- }
-
- if (scene->r.stamp & R_STAMP_FRAME_RANGE) {
- SNPRINTF(stamp_data->frame_range,
- do_prefix ? "Frame Range %d:%d" : "%d:%d",
- scene->r.sfra, scene->r.efra);
- }
- else {
- stamp_data->frame_range[0] = '\0';
- }
-
- if (use_dynamic && scene->r.stamp & R_STAMP_CAMERA) {
- SNPRINTF(stamp_data->camera, do_prefix ? "Camera %s" : "%s", camera ? camera->id.name + 2 : "<none>");
- }
- else {
- stamp_data->camera[0] = '\0';
- }
-
- if (use_dynamic && scene->r.stamp & R_STAMP_CAMERALENS) {
- if (camera && camera->type == OB_CAMERA) {
- SNPRINTF(text, "%.2f", ((Camera *)camera->data)->lens);
- }
- else {
- STRNCPY(text, "<none>");
- }
-
- SNPRINTF(stamp_data->cameralens, do_prefix ? "Lens %s" : "%s", text);
- }
- else {
- stamp_data->cameralens[0] = '\0';
- }
-
- if (scene->r.stamp & R_STAMP_SCENE) {
- SNPRINTF(stamp_data->scene, do_prefix ? "Scene %s" : "%s", scene->id.name + 2);
- }
- else {
- stamp_data->scene[0] = '\0';
- }
-
- if (use_dynamic && scene->r.stamp & R_STAMP_SEQSTRIP) {
- Sequence *seq = BKE_sequencer_foreground_frame_get(scene, scene->r.cfra);
-
- if (seq) STRNCPY(text, seq->name + 2);
- else STRNCPY(text, "<none>");
-
- SNPRINTF(stamp_data->strip, do_prefix ? "Strip %s" : "%s", text);
- }
- else {
- stamp_data->strip[0] = '\0';
- }
-
- {
- Render *re = RE_GetSceneRender(scene);
- RenderStats *stats = re ? RE_GetStats(re) : NULL;
-
- if (use_dynamic && stats && (scene->r.stamp & R_STAMP_RENDERTIME)) {
- BLI_timecode_string_from_time_simple(text, sizeof(text), stats->lastframetime);
-
- SNPRINTF(stamp_data->rendertime, do_prefix ? "RenderTime %s" : "%s", text);
- }
- else {
- stamp_data->rendertime[0] = '\0';
- }
-
- if (use_dynamic && stats && (scene->r.stamp & R_STAMP_MEMORY)) {
- SNPRINTF(stamp_data->memory, do_prefix ? "Peak Memory %.2fM" : "%.2fM", stats->mem_peak);
- }
- else {
- stamp_data->memory[0] = '\0';
- }
- }
- if (scene->r.stamp & R_STAMP_FRAME_RANGE) {
- SNPRINTF(stamp_data->frame_range,
- do_prefix ? "Frame Range %d:%d" : "%d:%d", scene->r.sfra, scene->r.efra);
- }
- else {
- stamp_data->frame_range[0] = '\0';
- }
-
- if (scene->r.stamp & R_STAMP_HOSTNAME) {
- char hostname[500]; /* sizeof(stamp_data->hostname) minus some bytes for a label. */
- BLI_hostname_get(hostname, sizeof(hostname));
- SNPRINTF(stamp_data->hostname, do_prefix ? "Hostname %s" : "%s", hostname);
- }
- else {
- stamp_data->hostname[0] = '\0';
- }
-
+static void stampdata(
+ Scene *scene, Object *camera, StampData *stamp_data, int do_prefix, bool use_dynamic)
+{
+ char text[256];
+ struct tm *tl;
+ time_t t;
+
+ if (scene->r.stamp & R_STAMP_FILENAME) {
+ SNPRINTF(stamp_data->file,
+ do_prefix ? "File %s" : "%s",
+ G.relbase_valid ? BKE_main_blendfile_path_from_global() : "<untitled>");
+ }
+ else {
+ stamp_data->file[0] = '\0';
+ }
+
+ if (scene->r.stamp & R_STAMP_NOTE) {
+ /* Never do prefix for Note */
+ SNPRINTF(stamp_data->note, "%s", scene->r.stamp_udata);
+ }
+ else {
+ stamp_data->note[0] = '\0';
+ }
+
+ if (scene->r.stamp & R_STAMP_DATE) {
+ t = time(NULL);
+ tl = localtime(&t);
+ SNPRINTF(text,
+ "%04d/%02d/%02d %02d:%02d:%02d",
+ tl->tm_year + 1900,
+ tl->tm_mon + 1,
+ tl->tm_mday,
+ tl->tm_hour,
+ tl->tm_min,
+ tl->tm_sec);
+ SNPRINTF(stamp_data->date, do_prefix ? "Date %s" : "%s", text);
+ }
+ else {
+ stamp_data->date[0] = '\0';
+ }
+
+ if (use_dynamic && scene->r.stamp & R_STAMP_MARKER) {
+ const char *name = BKE_scene_find_last_marker_name(scene, CFRA);
+
+ if (name)
+ STRNCPY(text, name);
+ else
+ STRNCPY(text, "<none>");
+
+ SNPRINTF(stamp_data->marker, do_prefix ? "Marker %s" : "%s", text);
+ }
+ else {
+ stamp_data->marker[0] = '\0';
+ }
+
+ if (use_dynamic && scene->r.stamp & R_STAMP_TIME) {
+ const short timecode_style = USER_TIMECODE_SMPTE_FULL;
+ BLI_timecode_string_from_time(
+ text, sizeof(text), 0, FRA2TIME(scene->r.cfra), FPS, timecode_style);
+ SNPRINTF(stamp_data->time, do_prefix ? "Timecode %s" : "%s", text);
+ }
+ else {
+ stamp_data->time[0] = '\0';
+ }
+
+ if (use_dynamic && scene->r.stamp & R_STAMP_FRAME) {
+ char fmtstr[32];
+ int digits = 1;
+
+ if (scene->r.efra > 9)
+ digits = integer_digits_i(scene->r.efra);
+
+ SNPRINTF(fmtstr, do_prefix ? "Frame %%0%di" : "%%0%di", digits);
+ SNPRINTF(stamp_data->frame, fmtstr, scene->r.cfra);
+ }
+ else {
+ stamp_data->frame[0] = '\0';
+ }
+
+ if (scene->r.stamp & R_STAMP_FRAME_RANGE) {
+ SNPRINTF(stamp_data->frame_range,
+ do_prefix ? "Frame Range %d:%d" : "%d:%d",
+ scene->r.sfra,
+ scene->r.efra);
+ }
+ else {
+ stamp_data->frame_range[0] = '\0';
+ }
+
+ if (use_dynamic && scene->r.stamp & R_STAMP_CAMERA) {
+ SNPRINTF(stamp_data->camera,
+ do_prefix ? "Camera %s" : "%s",
+ camera ? camera->id.name + 2 : "<none>");
+ }
+ else {
+ stamp_data->camera[0] = '\0';
+ }
+
+ if (use_dynamic && scene->r.stamp & R_STAMP_CAMERALENS) {
+ if (camera && camera->type == OB_CAMERA) {
+ SNPRINTF(text, "%.2f", ((Camera *)camera->data)->lens);
+ }
+ else {
+ STRNCPY(text, "<none>");
+ }
+
+ SNPRINTF(stamp_data->cameralens, do_prefix ? "Lens %s" : "%s", text);
+ }
+ else {
+ stamp_data->cameralens[0] = '\0';
+ }
+
+ if (scene->r.stamp & R_STAMP_SCENE) {
+ SNPRINTF(stamp_data->scene, do_prefix ? "Scene %s" : "%s", scene->id.name + 2);
+ }
+ else {
+ stamp_data->scene[0] = '\0';
+ }
+
+ if (use_dynamic && scene->r.stamp & R_STAMP_SEQSTRIP) {
+ Sequence *seq = BKE_sequencer_foreground_frame_get(scene, scene->r.cfra);
+
+ if (seq)
+ STRNCPY(text, seq->name + 2);
+ else
+ STRNCPY(text, "<none>");
+
+ SNPRINTF(stamp_data->strip, do_prefix ? "Strip %s" : "%s", text);
+ }
+ else {
+ stamp_data->strip[0] = '\0';
+ }
+
+ {
+ Render *re = RE_GetSceneRender(scene);
+ RenderStats *stats = re ? RE_GetStats(re) : NULL;
+
+ if (use_dynamic && stats && (scene->r.stamp & R_STAMP_RENDERTIME)) {
+ BLI_timecode_string_from_time_simple(text, sizeof(text), stats->lastframetime);
+
+ SNPRINTF(stamp_data->rendertime, do_prefix ? "RenderTime %s" : "%s", text);
+ }
+ else {
+ stamp_data->rendertime[0] = '\0';
+ }
+
+ if (use_dynamic && stats && (scene->r.stamp & R_STAMP_MEMORY)) {
+ SNPRINTF(stamp_data->memory, do_prefix ? "Peak Memory %.2fM" : "%.2fM", stats->mem_peak);
+ }
+ else {
+ stamp_data->memory[0] = '\0';
+ }
+ }
+ if (scene->r.stamp & R_STAMP_FRAME_RANGE) {
+ SNPRINTF(stamp_data->frame_range,
+ do_prefix ? "Frame Range %d:%d" : "%d:%d",
+ scene->r.sfra,
+ scene->r.efra);
+ }
+ else {
+ stamp_data->frame_range[0] = '\0';
+ }
+
+ if (scene->r.stamp & R_STAMP_HOSTNAME) {
+ char hostname[500]; /* sizeof(stamp_data->hostname) minus some bytes for a label. */
+ BLI_hostname_get(hostname, sizeof(hostname));
+ SNPRINTF(stamp_data->hostname, do_prefix ? "Hostname %s" : "%s", hostname);
+ }
+ else {
+ stamp_data->hostname[0] = '\0';
+ }
}
/* Will always add prefix. */
@@ -1723,339 +1780,449 @@ static void stampdata_from_template(StampData *stamp_data,
const Scene *scene,
const StampData *stamp_data_template)
{
- if (scene->r.stamp & R_STAMP_FILENAME) {
- SNPRINTF(stamp_data->file, "File %s", stamp_data_template->file);
- }
- else {
- stamp_data->file[0] = '\0';
- }
- if (scene->r.stamp & R_STAMP_NOTE) {
- SNPRINTF(stamp_data->note, "%s", stamp_data_template->note);
- }
- else {
- stamp_data->note[0] = '\0';
- }
- if (scene->r.stamp & R_STAMP_DATE) {
- SNPRINTF(stamp_data->date, "Date %s", stamp_data_template->date);
- }
- else {
- stamp_data->date[0] = '\0';
- }
- if (scene->r.stamp & R_STAMP_MARKER) {
- SNPRINTF(stamp_data->marker, "Marker %s", stamp_data_template->marker);
- }
- else {
- stamp_data->marker[0] = '\0';
- }
- if (scene->r.stamp & R_STAMP_TIME) {
- SNPRINTF(stamp_data->time, "Timecode %s", stamp_data_template->time);
- }
- else {
- stamp_data->time[0] = '\0';
- }
- if (scene->r.stamp & R_STAMP_FRAME) {
- SNPRINTF(stamp_data->frame, "Frame %s", stamp_data_template->frame);
- }
- else {
- stamp_data->frame[0] = '\0';
- }
- if (scene->r.stamp & R_STAMP_CAMERA) {
- SNPRINTF(stamp_data->camera, "Camera %s", stamp_data_template->camera);
- }
- else {
- stamp_data->camera[0] = '\0';
- }
- if (scene->r.stamp & R_STAMP_CAMERALENS) {
- SNPRINTF(stamp_data->cameralens, "Lens %s", stamp_data_template->cameralens);
- }
- else {
- stamp_data->cameralens[0] = '\0';
- }
- if (scene->r.stamp & R_STAMP_SCENE) {
- SNPRINTF(stamp_data->scene, "Scene %s", stamp_data_template->scene);
- }
- else {
- stamp_data->scene[0] = '\0';
- }
- if (scene->r.stamp & R_STAMP_SEQSTRIP) {
- SNPRINTF(stamp_data->strip, "Strip %s", stamp_data_template->strip);
- }
- else {
- stamp_data->strip[0] = '\0';
- }
- if (scene->r.stamp & R_STAMP_RENDERTIME) {
- SNPRINTF(stamp_data->rendertime, "RenderTime %s", stamp_data_template->rendertime);
- }
- else {
- stamp_data->rendertime[0] = '\0';
- }
- if (scene->r.stamp & R_STAMP_MEMORY) {
- SNPRINTF(stamp_data->memory, "Peak Memory %s", stamp_data_template->memory);
- }
- else {
- stamp_data->memory[0] = '\0';
- }
- if (scene->r.stamp & R_STAMP_HOSTNAME) {
- SNPRINTF(stamp_data->hostname, "Hostname %s", stamp_data_template->hostname);
- }
- else {
- stamp_data->hostname[0] = '\0';
- }
-}
-
-void BKE_image_stamp_buf(
- Scene *scene, Object *camera, const StampData *stamp_data_template,
- unsigned char *rect, float *rectf, int width, int height, int channels)
-{
- struct StampData stamp_data;
- float w, h, pad;
- int x, y, y_ofs;
- float h_fixed;
- const int mono = blf_mono_font_render; // XXX
- struct ColorManagedDisplay *display;
- const char *display_device;
-
- /* vars for calculating wordwrap */
- struct {
- struct ResultBLF info;
- rctf rect;
- } wrap;
-
- /* this could be an argument if we want to operate on non linear float imbuf's
- * for now though this is only used for renders which use scene settings */
+ if (scene->r.stamp & R_STAMP_FILENAME) {
+ SNPRINTF(stamp_data->file, "File %s", stamp_data_template->file);
+ }
+ else {
+ stamp_data->file[0] = '\0';
+ }
+ if (scene->r.stamp & R_STAMP_NOTE) {
+ SNPRINTF(stamp_data->note, "%s", stamp_data_template->note);
+ }
+ else {
+ stamp_data->note[0] = '\0';
+ }
+ if (scene->r.stamp & R_STAMP_DATE) {
+ SNPRINTF(stamp_data->date, "Date %s", stamp_data_template->date);
+ }
+ else {
+ stamp_data->date[0] = '\0';
+ }
+ if (scene->r.stamp & R_STAMP_MARKER) {
+ SNPRINTF(stamp_data->marker, "Marker %s", stamp_data_template->marker);
+ }
+ else {
+ stamp_data->marker[0] = '\0';
+ }
+ if (scene->r.stamp & R_STAMP_TIME) {
+ SNPRINTF(stamp_data->time, "Timecode %s", stamp_data_template->time);
+ }
+ else {
+ stamp_data->time[0] = '\0';
+ }
+ if (scene->r.stamp & R_STAMP_FRAME) {
+ SNPRINTF(stamp_data->frame, "Frame %s", stamp_data_template->frame);
+ }
+ else {
+ stamp_data->frame[0] = '\0';
+ }
+ if (scene->r.stamp & R_STAMP_CAMERA) {
+ SNPRINTF(stamp_data->camera, "Camera %s", stamp_data_template->camera);
+ }
+ else {
+ stamp_data->camera[0] = '\0';
+ }
+ if (scene->r.stamp & R_STAMP_CAMERALENS) {
+ SNPRINTF(stamp_data->cameralens, "Lens %s", stamp_data_template->cameralens);
+ }
+ else {
+ stamp_data->cameralens[0] = '\0';
+ }
+ if (scene->r.stamp & R_STAMP_SCENE) {
+ SNPRINTF(stamp_data->scene, "Scene %s", stamp_data_template->scene);
+ }
+ else {
+ stamp_data->scene[0] = '\0';
+ }
+ if (scene->r.stamp & R_STAMP_SEQSTRIP) {
+ SNPRINTF(stamp_data->strip, "Strip %s", stamp_data_template->strip);
+ }
+ else {
+ stamp_data->strip[0] = '\0';
+ }
+ if (scene->r.stamp & R_STAMP_RENDERTIME) {
+ SNPRINTF(stamp_data->rendertime, "RenderTime %s", stamp_data_template->rendertime);
+ }
+ else {
+ stamp_data->rendertime[0] = '\0';
+ }
+ if (scene->r.stamp & R_STAMP_MEMORY) {
+ SNPRINTF(stamp_data->memory, "Peak Memory %s", stamp_data_template->memory);
+ }
+ else {
+ stamp_data->memory[0] = '\0';
+ }
+ if (scene->r.stamp & R_STAMP_HOSTNAME) {
+ SNPRINTF(stamp_data->hostname, "Hostname %s", stamp_data_template->hostname);
+ }
+ else {
+ stamp_data->hostname[0] = '\0';
+ }
+}
+
+void BKE_image_stamp_buf(Scene *scene,
+ Object *camera,
+ const StampData *stamp_data_template,
+ unsigned char *rect,
+ float *rectf,
+ int width,
+ int height,
+ int channels)
+{
+ struct StampData stamp_data;
+ float w, h, pad;
+ int x, y, y_ofs;
+ float h_fixed;
+ const int mono = blf_mono_font_render; // XXX
+ struct ColorManagedDisplay *display;
+ const char *display_device;
+
+ /* vars for calculating wordwrap */
+ struct {
+ struct ResultBLF info;
+ rctf rect;
+ } wrap;
+
+ /* this could be an argument if we want to operate on non linear float imbuf's
+ * for now though this is only used for renders which use scene settings */
#define TEXT_SIZE_CHECK(str, w, h) \
- ((str[0]) && ((void)(h = h_fixed), (w = BLF_width(mono, str, sizeof(str)))))
+ ((str[0]) && ((void)(h = h_fixed), (w = BLF_width(mono, str, sizeof(str)))))
- /* must enable BLF_WORD_WRAP before using */
+ /* must enable BLF_WORD_WRAP before using */
#define TEXT_SIZE_CHECK_WORD_WRAP(str, w, h) \
- ((str[0]) && (BLF_boundbox_ex(mono, str, sizeof(str), &wrap.rect, &wrap.info), \
- (void)(h = h_fixed * wrap.info.lines), (w = BLI_rctf_size_x(&wrap.rect))))
+ ((str[0]) && (BLF_boundbox_ex(mono, str, sizeof(str), &wrap.rect, &wrap.info), \
+ (void)(h = h_fixed * wrap.info.lines), \
+ (w = BLI_rctf_size_x(&wrap.rect))))
#define BUFF_MARGIN_X 2
#define BUFF_MARGIN_Y 1
- if (!rect && !rectf)
- return;
-
- display_device = scene->display_settings.display_device;
- display = IMB_colormanagement_display_get_named(display_device);
-
- if (stamp_data_template == NULL) {
- stampdata(scene, camera, &stamp_data, (scene->r.stamp & R_STAMP_HIDE_LABELS) == 0, true);
- }
- else {
- stampdata_from_template(&stamp_data, scene, stamp_data_template);
- }
-
- /* TODO, do_versions */
- if (scene->r.stamp_font_id < 8)
- scene->r.stamp_font_id = 12;
-
- /* set before return */
- BLF_size(mono, scene->r.stamp_font_id, 72);
- BLF_wordwrap(mono, width - (BUFF_MARGIN_X * 2));
-
- BLF_buffer(mono, rectf, rect, width, height, channels, display);
- BLF_buffer_col(mono, scene->r.fg_stamp);
- pad = BLF_width_max(mono);
-
- /* use 'h_fixed' rather than 'h', aligns better */
- h_fixed = BLF_height_max(mono);
- y_ofs = -BLF_descender(mono);
-
- x = 0;
- y = height;
-
- if (TEXT_SIZE_CHECK(stamp_data.file, w, h)) {
- /* Top left corner */
- y -= h;
-
- /* also a little of space to the background. */
- buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display,
- x - BUFF_MARGIN_X, y - BUFF_MARGIN_Y, w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y);
-
- /* and draw the text. */
- BLF_position(mono, x, y + y_ofs, 0.0);
- BLF_draw_buffer(mono, stamp_data.file, BLF_DRAW_STR_DUMMY_MAX);
-
- /* the extra pixel for background. */
- y -= BUFF_MARGIN_Y * 2;
- }
-
- /* Top left corner, below File */
- if (TEXT_SIZE_CHECK(stamp_data.date, w, h)) {
- y -= h;
-
- /* and space for background. */
- buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display,
- 0, y - BUFF_MARGIN_Y, w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y);
-
- BLF_position(mono, x, y + y_ofs, 0.0);
- BLF_draw_buffer(mono, stamp_data.date, BLF_DRAW_STR_DUMMY_MAX);
-
- /* the extra pixel for background. */
- y -= BUFF_MARGIN_Y * 2;
- }
-
- /* Top left corner, below File, Date */
- if (TEXT_SIZE_CHECK(stamp_data.rendertime, w, h)) {
- y -= h;
-
- /* and space for background. */
- buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display,
- 0, y - BUFF_MARGIN_Y, w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y);
-
- BLF_position(mono, x, y + y_ofs, 0.0);
- BLF_draw_buffer(mono, stamp_data.rendertime, BLF_DRAW_STR_DUMMY_MAX);
-
- /* the extra pixel for background. */
- y -= BUFF_MARGIN_Y * 2;
- }
-
- /* Top left corner, below File, Date, Rendertime */
- if (TEXT_SIZE_CHECK(stamp_data.memory, w, h)) {
- y -= h;
-
- /* and space for background. */
- buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display,
- 0, y - BUFF_MARGIN_Y, w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y);
-
- BLF_position(mono, x, y + y_ofs, 0.0);
- BLF_draw_buffer(mono, stamp_data.memory, BLF_DRAW_STR_DUMMY_MAX);
-
- /* the extra pixel for background. */
- y -= BUFF_MARGIN_Y * 2;
- }
-
- /* Top left corner, below File, Date, Rendertime, Memory */
- if (TEXT_SIZE_CHECK(stamp_data.hostname, w, h)) {
- y -= h;
-
- /* and space for background. */
- buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display,
- 0, y - BUFF_MARGIN_Y, w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y);
-
- BLF_position(mono, x, y + y_ofs, 0.0);
- BLF_draw_buffer(mono, stamp_data.hostname, BLF_DRAW_STR_DUMMY_MAX);
-
- /* the extra pixel for background. */
- y -= BUFF_MARGIN_Y * 2;
- }
-
- /* Top left corner, below File, Date, Memory, Rendertime, Hostname */
- BLF_enable(mono, BLF_WORD_WRAP);
- if (TEXT_SIZE_CHECK_WORD_WRAP(stamp_data.note, w, h)) {
- y -= h;
-
- /* and space for background. */
- buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display,
- 0, y - BUFF_MARGIN_Y, w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y);
-
- BLF_position(mono, x, y + y_ofs + (h - h_fixed), 0.0);
- BLF_draw_buffer(mono, stamp_data.note, BLF_DRAW_STR_DUMMY_MAX);
- }
- BLF_disable(mono, BLF_WORD_WRAP);
-
- x = 0;
- y = 0;
-
- /* Bottom left corner, leaving space for timing */
- if (TEXT_SIZE_CHECK(stamp_data.marker, w, h)) {
-
- /* extra space for background. */
- buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display,
- x - BUFF_MARGIN_X, y - BUFF_MARGIN_Y, w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y);
-
- /* and pad the text. */
- BLF_position(mono, x, y + y_ofs, 0.0);
- BLF_draw_buffer(mono, stamp_data.marker, BLF_DRAW_STR_DUMMY_MAX);
-
- /* space width. */
- x += w + pad;
- }
-
- /* Left bottom corner */
- if (TEXT_SIZE_CHECK(stamp_data.time, w, h)) {
-
- /* extra space for background */
- buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display,
- x - BUFF_MARGIN_X, y, x + w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y);
-
- /* and pad the text. */
- BLF_position(mono, x, y + y_ofs, 0.0);
- BLF_draw_buffer(mono, stamp_data.time, BLF_DRAW_STR_DUMMY_MAX);
-
- /* space width. */
- x += w + pad;
- }
-
- if (TEXT_SIZE_CHECK(stamp_data.frame, w, h)) {
-
- /* extra space for background. */
- buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display,
- x - BUFF_MARGIN_X, y - BUFF_MARGIN_Y, x + w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y);
-
- /* and pad the text. */
- BLF_position(mono, x, y + y_ofs, 0.0);
- BLF_draw_buffer(mono, stamp_data.frame, BLF_DRAW_STR_DUMMY_MAX);
-
- /* space width. */
- x += w + pad;
- }
-
- if (TEXT_SIZE_CHECK(stamp_data.camera, w, h)) {
-
- /* extra space for background. */
- buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display,
- x - BUFF_MARGIN_X, y - BUFF_MARGIN_Y, x + w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y);
- BLF_position(mono, x, y + y_ofs, 0.0);
- BLF_draw_buffer(mono, stamp_data.camera, BLF_DRAW_STR_DUMMY_MAX);
-
- /* space width. */
- x += w + pad;
- }
-
- if (TEXT_SIZE_CHECK(stamp_data.cameralens, w, h)) {
-
- /* extra space for background. */
- buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display,
- x - BUFF_MARGIN_X, y - BUFF_MARGIN_Y, x + w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y);
- BLF_position(mono, x, y + y_ofs, 0.0);
- BLF_draw_buffer(mono, stamp_data.cameralens, BLF_DRAW_STR_DUMMY_MAX);
- }
-
- if (TEXT_SIZE_CHECK(stamp_data.scene, w, h)) {
-
- /* Bottom right corner, with an extra space because blenfont is too strict! */
- x = width - w - 2;
-
- /* extra space for background. */
- buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display,
- x - BUFF_MARGIN_X, y - BUFF_MARGIN_Y, x + w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y);
-
- /* and pad the text. */
- BLF_position(mono, x, y + y_ofs, 0.0);
- BLF_draw_buffer(mono, stamp_data.scene, BLF_DRAW_STR_DUMMY_MAX);
- }
-
- if (TEXT_SIZE_CHECK(stamp_data.strip, w, h)) {
-
- /* Top right corner, with an extra space because blenfont is too strict! */
- x = width - w - pad;
- y = height - h;
-
- /* extra space for background. */
- buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display,
- x - BUFF_MARGIN_X, y - BUFF_MARGIN_Y, x + w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y);
-
- BLF_position(mono, x, y + y_ofs, 0.0);
- BLF_draw_buffer(mono, stamp_data.strip, BLF_DRAW_STR_DUMMY_MAX);
- }
-
- /* cleanup the buffer. */
- BLF_buffer(mono, NULL, NULL, 0, 0, 0, NULL);
- BLF_wordwrap(mono, 0);
+ if (!rect && !rectf)
+ return;
+
+ display_device = scene->display_settings.display_device;
+ display = IMB_colormanagement_display_get_named(display_device);
+
+ if (stamp_data_template == NULL) {
+ stampdata(scene, camera, &stamp_data, (scene->r.stamp & R_STAMP_HIDE_LABELS) == 0, true);
+ }
+ else {
+ stampdata_from_template(&stamp_data, scene, stamp_data_template);
+ }
+
+ /* TODO, do_versions */
+ if (scene->r.stamp_font_id < 8)
+ scene->r.stamp_font_id = 12;
+
+ /* set before return */
+ BLF_size(mono, scene->r.stamp_font_id, 72);
+ BLF_wordwrap(mono, width - (BUFF_MARGIN_X * 2));
+
+ BLF_buffer(mono, rectf, rect, width, height, channels, display);
+ BLF_buffer_col(mono, scene->r.fg_stamp);
+ pad = BLF_width_max(mono);
+
+ /* use 'h_fixed' rather than 'h', aligns better */
+ h_fixed = BLF_height_max(mono);
+ y_ofs = -BLF_descender(mono);
+
+ x = 0;
+ y = height;
+
+ if (TEXT_SIZE_CHECK(stamp_data.file, w, h)) {
+ /* Top left corner */
+ y -= h;
+
+ /* also a little of space to the background. */
+ buf_rectfill_area(rect,
+ rectf,
+ width,
+ height,
+ scene->r.bg_stamp,
+ display,
+ x - BUFF_MARGIN_X,
+ y - BUFF_MARGIN_Y,
+ w + BUFF_MARGIN_X,
+ y + h + BUFF_MARGIN_Y);
+
+ /* and draw the text. */
+ BLF_position(mono, x, y + y_ofs, 0.0);
+ BLF_draw_buffer(mono, stamp_data.file, BLF_DRAW_STR_DUMMY_MAX);
+
+ /* the extra pixel for background. */
+ y -= BUFF_MARGIN_Y * 2;
+ }
+
+ /* Top left corner, below File */
+ if (TEXT_SIZE_CHECK(stamp_data.date, w, h)) {
+ y -= h;
+
+ /* and space for background. */
+ buf_rectfill_area(rect,
+ rectf,
+ width,
+ height,
+ scene->r.bg_stamp,
+ display,
+ 0,
+ y - BUFF_MARGIN_Y,
+ w + BUFF_MARGIN_X,
+ y + h + BUFF_MARGIN_Y);
+
+ BLF_position(mono, x, y + y_ofs, 0.0);
+ BLF_draw_buffer(mono, stamp_data.date, BLF_DRAW_STR_DUMMY_MAX);
+
+ /* the extra pixel for background. */
+ y -= BUFF_MARGIN_Y * 2;
+ }
+
+ /* Top left corner, below File, Date */
+ if (TEXT_SIZE_CHECK(stamp_data.rendertime, w, h)) {
+ y -= h;
+
+ /* and space for background. */
+ buf_rectfill_area(rect,
+ rectf,
+ width,
+ height,
+ scene->r.bg_stamp,
+ display,
+ 0,
+ y - BUFF_MARGIN_Y,
+ w + BUFF_MARGIN_X,
+ y + h + BUFF_MARGIN_Y);
+
+ BLF_position(mono, x, y + y_ofs, 0.0);
+ BLF_draw_buffer(mono, stamp_data.rendertime, BLF_DRAW_STR_DUMMY_MAX);
+
+ /* the extra pixel for background. */
+ y -= BUFF_MARGIN_Y * 2;
+ }
+
+ /* Top left corner, below File, Date, Rendertime */
+ if (TEXT_SIZE_CHECK(stamp_data.memory, w, h)) {
+ y -= h;
+
+ /* and space for background. */
+ buf_rectfill_area(rect,
+ rectf,
+ width,
+ height,
+ scene->r.bg_stamp,
+ display,
+ 0,
+ y - BUFF_MARGIN_Y,
+ w + BUFF_MARGIN_X,
+ y + h + BUFF_MARGIN_Y);
+
+ BLF_position(mono, x, y + y_ofs, 0.0);
+ BLF_draw_buffer(mono, stamp_data.memory, BLF_DRAW_STR_DUMMY_MAX);
+
+ /* the extra pixel for background. */
+ y -= BUFF_MARGIN_Y * 2;
+ }
+
+ /* Top left corner, below File, Date, Rendertime, Memory */
+ if (TEXT_SIZE_CHECK(stamp_data.hostname, w, h)) {
+ y -= h;
+
+ /* and space for background. */
+ buf_rectfill_area(rect,
+ rectf,
+ width,
+ height,
+ scene->r.bg_stamp,
+ display,
+ 0,
+ y - BUFF_MARGIN_Y,
+ w + BUFF_MARGIN_X,
+ y + h + BUFF_MARGIN_Y);
+
+ BLF_position(mono, x, y + y_ofs, 0.0);
+ BLF_draw_buffer(mono, stamp_data.hostname, BLF_DRAW_STR_DUMMY_MAX);
+
+ /* the extra pixel for background. */
+ y -= BUFF_MARGIN_Y * 2;
+ }
+
+ /* Top left corner, below File, Date, Memory, Rendertime, Hostname */
+ BLF_enable(mono, BLF_WORD_WRAP);
+ if (TEXT_SIZE_CHECK_WORD_WRAP(stamp_data.note, w, h)) {
+ y -= h;
+
+ /* and space for background. */
+ buf_rectfill_area(rect,
+ rectf,
+ width,
+ height,
+ scene->r.bg_stamp,
+ display,
+ 0,
+ y - BUFF_MARGIN_Y,
+ w + BUFF_MARGIN_X,
+ y + h + BUFF_MARGIN_Y);
+
+ BLF_position(mono, x, y + y_ofs + (h - h_fixed), 0.0);
+ BLF_draw_buffer(mono, stamp_data.note, BLF_DRAW_STR_DUMMY_MAX);
+ }
+ BLF_disable(mono, BLF_WORD_WRAP);
+
+ x = 0;
+ y = 0;
+
+ /* Bottom left corner, leaving space for timing */
+ if (TEXT_SIZE_CHECK(stamp_data.marker, w, h)) {
+
+ /* extra space for background. */
+ buf_rectfill_area(rect,
+ rectf,
+ width,
+ height,
+ scene->r.bg_stamp,
+ display,
+ x - BUFF_MARGIN_X,
+ y - BUFF_MARGIN_Y,
+ w + BUFF_MARGIN_X,
+ y + h + BUFF_MARGIN_Y);
+
+ /* and pad the text. */
+ BLF_position(mono, x, y + y_ofs, 0.0);
+ BLF_draw_buffer(mono, stamp_data.marker, BLF_DRAW_STR_DUMMY_MAX);
+
+ /* space width. */
+ x += w + pad;
+ }
+
+ /* Left bottom corner */
+ if (TEXT_SIZE_CHECK(stamp_data.time, w, h)) {
+
+ /* extra space for background */
+ buf_rectfill_area(rect,
+ rectf,
+ width,
+ height,
+ scene->r.bg_stamp,
+ display,
+ x - BUFF_MARGIN_X,
+ y,
+ x + w + BUFF_MARGIN_X,
+ y + h + BUFF_MARGIN_Y);
+
+ /* and pad the text. */
+ BLF_position(mono, x, y + y_ofs, 0.0);
+ BLF_draw_buffer(mono, stamp_data.time, BLF_DRAW_STR_DUMMY_MAX);
+
+ /* space width. */
+ x += w + pad;
+ }
+
+ if (TEXT_SIZE_CHECK(stamp_data.frame, w, h)) {
+
+ /* extra space for background. */
+ buf_rectfill_area(rect,
+ rectf,
+ width,
+ height,
+ scene->r.bg_stamp,
+ display,
+ x - BUFF_MARGIN_X,
+ y - BUFF_MARGIN_Y,
+ x + w + BUFF_MARGIN_X,
+ y + h + BUFF_MARGIN_Y);
+
+ /* and pad the text. */
+ BLF_position(mono, x, y + y_ofs, 0.0);
+ BLF_draw_buffer(mono, stamp_data.frame, BLF_DRAW_STR_DUMMY_MAX);
+
+ /* space width. */
+ x += w + pad;
+ }
+
+ if (TEXT_SIZE_CHECK(stamp_data.camera, w, h)) {
+
+ /* extra space for background. */
+ buf_rectfill_area(rect,
+ rectf,
+ width,
+ height,
+ scene->r.bg_stamp,
+ display,
+ x - BUFF_MARGIN_X,
+ y - BUFF_MARGIN_Y,
+ x + w + BUFF_MARGIN_X,
+ y + h + BUFF_MARGIN_Y);
+ BLF_position(mono, x, y + y_ofs, 0.0);
+ BLF_draw_buffer(mono, stamp_data.camera, BLF_DRAW_STR_DUMMY_MAX);
+
+ /* space width. */
+ x += w + pad;
+ }
+
+ if (TEXT_SIZE_CHECK(stamp_data.cameralens, w, h)) {
+
+ /* extra space for background. */
+ buf_rectfill_area(rect,
+ rectf,
+ width,
+ height,
+ scene->r.bg_stamp,
+ display,
+ x - BUFF_MARGIN_X,
+ y - BUFF_MARGIN_Y,
+ x + w + BUFF_MARGIN_X,
+ y + h + BUFF_MARGIN_Y);
+ BLF_position(mono, x, y + y_ofs, 0.0);
+ BLF_draw_buffer(mono, stamp_data.cameralens, BLF_DRAW_STR_DUMMY_MAX);
+ }
+
+ if (TEXT_SIZE_CHECK(stamp_data.scene, w, h)) {
+
+ /* Bottom right corner, with an extra space because blenfont is too strict! */
+ x = width - w - 2;
+
+ /* extra space for background. */
+ buf_rectfill_area(rect,
+ rectf,
+ width,
+ height,
+ scene->r.bg_stamp,
+ display,
+ x - BUFF_MARGIN_X,
+ y - BUFF_MARGIN_Y,
+ x + w + BUFF_MARGIN_X,
+ y + h + BUFF_MARGIN_Y);
+
+ /* and pad the text. */
+ BLF_position(mono, x, y + y_ofs, 0.0);
+ BLF_draw_buffer(mono, stamp_data.scene, BLF_DRAW_STR_DUMMY_MAX);
+ }
+
+ if (TEXT_SIZE_CHECK(stamp_data.strip, w, h)) {
+
+ /* Top right corner, with an extra space because blenfont is too strict! */
+ x = width - w - pad;
+ y = height - h;
+
+ /* extra space for background. */
+ buf_rectfill_area(rect,
+ rectf,
+ width,
+ height,
+ scene->r.bg_stamp,
+ display,
+ x - BUFF_MARGIN_X,
+ y - BUFF_MARGIN_Y,
+ x + w + BUFF_MARGIN_X,
+ y + h + BUFF_MARGIN_Y);
+
+ BLF_position(mono, x, y + y_ofs, 0.0);
+ BLF_draw_buffer(mono, stamp_data.strip, BLF_DRAW_STR_DUMMY_MAX);
+ }
+
+ /* cleanup the buffer. */
+ BLF_buffer(mono, NULL, NULL, 0, 0, 0, NULL);
+ BLF_wordwrap(mono, 0);
#undef TEXT_SIZE_CHECK
#undef TEXT_SIZE_CHECK_WORD_WRAP
@@ -2063,491 +2230,521 @@ void BKE_image_stamp_buf(
#undef BUFF_MARGIN_Y
}
-void BKE_render_result_stamp_info(Scene *scene, Object *camera, struct RenderResult *rr, bool allocate_only)
+void BKE_render_result_stamp_info(Scene *scene,
+ Object *camera,
+ struct RenderResult *rr,
+ bool allocate_only)
{
- struct StampData *stamp_data;
+ struct StampData *stamp_data;
- if (!(scene && (scene->r.stamp & R_STAMP_ALL)) && !allocate_only)
- return;
+ if (!(scene && (scene->r.stamp & R_STAMP_ALL)) && !allocate_only)
+ return;
- if (!rr->stamp_data) {
- stamp_data = MEM_callocN(sizeof(StampData), "RenderResult.stamp_data");
- }
- else {
- stamp_data = rr->stamp_data;
- }
+ if (!rr->stamp_data) {
+ stamp_data = MEM_callocN(sizeof(StampData), "RenderResult.stamp_data");
+ }
+ else {
+ stamp_data = rr->stamp_data;
+ }
- if (!allocate_only)
- stampdata(scene, camera, stamp_data, 0, true);
+ if (!allocate_only)
+ stampdata(scene, camera, stamp_data, 0, true);
- if (!rr->stamp_data) {
- rr->stamp_data = stamp_data;
- }
+ if (!rr->stamp_data) {
+ rr->stamp_data = stamp_data;
+ }
}
struct StampData *BKE_stamp_info_from_scene_static(Scene *scene)
{
- struct StampData *stamp_data;
+ struct StampData *stamp_data;
- if (!(scene && (scene->r.stamp & R_STAMP_ALL)))
- return NULL;
+ if (!(scene && (scene->r.stamp & R_STAMP_ALL)))
+ return NULL;
- /* Memory is allocated here (instead of by the caller) so that the caller
- * doesn't have to know the size of the StampData struct. */
- stamp_data = MEM_callocN(sizeof(StampData), __func__);
- stampdata(scene, NULL, stamp_data, 0, false);
+ /* Memory is allocated here (instead of by the caller) so that the caller
+ * doesn't have to know the size of the StampData struct. */
+ stamp_data = MEM_callocN(sizeof(StampData), __func__);
+ stampdata(scene, NULL, stamp_data, 0, false);
- return stamp_data;
+ return stamp_data;
}
static const char *stamp_metadata_fields[] = {
- "File",
- "Note",
- "Date",
- "Marker",
- "Time",
- "Frame",
- "FrameRange",
- "Camera",
- "Lens",
- "Scene",
- "Strip",
- "RenderTime",
- "Memory",
- "Hostname",
- NULL,
+ "File",
+ "Note",
+ "Date",
+ "Marker",
+ "Time",
+ "Frame",
+ "FrameRange",
+ "Camera",
+ "Lens",
+ "Scene",
+ "Strip",
+ "RenderTime",
+ "Memory",
+ "Hostname",
+ NULL,
};
/* Check whether the given metadata field name translates to a known field of
* a stamp. */
bool BKE_stamp_is_known_field(const char *field_name)
{
- int i = 0;
- while (stamp_metadata_fields[i] != NULL) {
- if (STREQ(field_name, stamp_metadata_fields[i])) {
- return true;
- }
- i++;
- }
- return false;
+ int i = 0;
+ while (stamp_metadata_fields[i] != NULL) {
+ if (STREQ(field_name, stamp_metadata_fields[i])) {
+ return true;
+ }
+ i++;
+ }
+ return false;
}
-void BKE_stamp_info_callback(void *data, struct StampData *stamp_data, StampCallback callback, bool noskip)
+void BKE_stamp_info_callback(void *data,
+ struct StampData *stamp_data,
+ StampCallback callback,
+ bool noskip)
{
- if ((callback == NULL) || (stamp_data == NULL)) {
- return;
- }
+ if ((callback == NULL) || (stamp_data == NULL)) {
+ return;
+ }
#define CALL(member, value_str) \
- if (noskip || stamp_data->member[0]) { \
- callback(data, value_str, stamp_data->member, sizeof(stamp_data->member)); \
- } ((void)0)
-
- /* TODO(sergey): Use stamp_metadata_fields somehow, or make it more generic
- * meta information to avoid duplication. */
- CALL(file, "File");
- CALL(note, "Note");
- CALL(date, "Date");
- CALL(marker, "Marker");
- CALL(time, "Time");
- CALL(frame, "Frame");
- CALL(frame_range, "FrameRange");
- CALL(camera, "Camera");
- CALL(cameralens, "Lens");
- CALL(scene, "Scene");
- CALL(strip, "Strip");
- CALL(rendertime, "RenderTime");
- CALL(memory, "Memory");
- CALL(hostname, "Hostname");
-
- LISTBASE_FOREACH(StampDataCustomField *, custom_field, &stamp_data->custom_fields) {
- if (noskip || custom_field->value[0]) {
- callback(data, custom_field->key, custom_field->value, strlen(custom_field->value) + 1);
- }
- }
+ if (noskip || stamp_data->member[0]) { \
+ callback(data, value_str, stamp_data->member, sizeof(stamp_data->member)); \
+ } \
+ ((void)0)
+
+ /* TODO(sergey): Use stamp_metadata_fields somehow, or make it more generic
+ * meta information to avoid duplication. */
+ CALL(file, "File");
+ CALL(note, "Note");
+ CALL(date, "Date");
+ CALL(marker, "Marker");
+ CALL(time, "Time");
+ CALL(frame, "Frame");
+ CALL(frame_range, "FrameRange");
+ CALL(camera, "Camera");
+ CALL(cameralens, "Lens");
+ CALL(scene, "Scene");
+ CALL(strip, "Strip");
+ CALL(rendertime, "RenderTime");
+ CALL(memory, "Memory");
+ CALL(hostname, "Hostname");
+
+ LISTBASE_FOREACH (StampDataCustomField *, custom_field, &stamp_data->custom_fields) {
+ if (noskip || custom_field->value[0]) {
+ callback(data, custom_field->key, custom_field->value, strlen(custom_field->value) + 1);
+ }
+ }
#undef CALL
}
void BKE_render_result_stamp_data(RenderResult *rr, const char *key, const char *value)
{
- StampData *stamp_data;
- if (rr->stamp_data == NULL) {
- rr->stamp_data = MEM_callocN(sizeof(StampData), "RenderResult.stamp_data");
- }
- stamp_data = rr->stamp_data;
- StampDataCustomField *field = MEM_mallocN(sizeof(StampDataCustomField),
- "StampData Custom Field");
- STRNCPY(field->key, key);
- field->value = BLI_strdup(value);
- BLI_addtail(&stamp_data->custom_fields, field);
+ StampData *stamp_data;
+ if (rr->stamp_data == NULL) {
+ rr->stamp_data = MEM_callocN(sizeof(StampData), "RenderResult.stamp_data");
+ }
+ stamp_data = rr->stamp_data;
+ StampDataCustomField *field = MEM_mallocN(sizeof(StampDataCustomField),
+ "StampData Custom Field");
+ STRNCPY(field->key, key);
+ field->value = BLI_strdup(value);
+ BLI_addtail(&stamp_data->custom_fields, field);
}
StampData *BKE_stamp_data_copy(const StampData *stamp_data)
{
- if (stamp_data == NULL) {
- return NULL;
- }
+ if (stamp_data == NULL) {
+ return NULL;
+ }
- StampData *stamp_datan = MEM_dupallocN(stamp_data);
- BLI_duplicatelist(&stamp_datan->custom_fields, &stamp_data->custom_fields);
+ StampData *stamp_datan = MEM_dupallocN(stamp_data);
+ BLI_duplicatelist(&stamp_datan->custom_fields, &stamp_data->custom_fields);
- LISTBASE_FOREACH(StampDataCustomField *, custom_fieldn, &stamp_datan->custom_fields) {
- custom_fieldn->value = MEM_dupallocN(custom_fieldn->value);
- }
+ LISTBASE_FOREACH (StampDataCustomField *, custom_fieldn, &stamp_datan->custom_fields) {
+ custom_fieldn->value = MEM_dupallocN(custom_fieldn->value);
+ }
- return stamp_datan;
+ return stamp_datan;
}
void BKE_stamp_data_free(StampData *stamp_data)
{
- if (stamp_data == NULL) {
- return;
- }
- LISTBASE_FOREACH(StampDataCustomField *, custom_field, &stamp_data->custom_fields) {
- MEM_freeN(custom_field->value);
- }
- BLI_freelistN(&stamp_data->custom_fields);
- MEM_freeN(stamp_data);
+ if (stamp_data == NULL) {
+ return;
+ }
+ LISTBASE_FOREACH (StampDataCustomField *, custom_field, &stamp_data->custom_fields) {
+ MEM_freeN(custom_field->value);
+ }
+ BLI_freelistN(&stamp_data->custom_fields);
+ MEM_freeN(stamp_data);
}
/* wrap for callback only */
static void metadata_set_field(void *data, const char *propname, char *propvalue, int UNUSED(len))
{
- /* We know it is an ImBuf* because that's what we pass to BKE_stamp_info_callback. */
- struct ImBuf *imbuf = data;
- IMB_metadata_set_field(imbuf->metadata, propname, propvalue);
+ /* We know it is an ImBuf* because that's what we pass to BKE_stamp_info_callback. */
+ struct ImBuf *imbuf = data;
+ IMB_metadata_set_field(imbuf->metadata, propname, propvalue);
}
static void metadata_get_field(void *data, const char *propname, char *propvalue, int len)
{
- /* We know it is an ImBuf* because that's what we pass to BKE_stamp_info_callback. */
- struct ImBuf *imbuf = data;
- IMB_metadata_get_field(imbuf->metadata, propname, propvalue, len);
+ /* We know it is an ImBuf* because that's what we pass to BKE_stamp_info_callback. */
+ struct ImBuf *imbuf = data;
+ IMB_metadata_get_field(imbuf->metadata, propname, propvalue, len);
}
void BKE_imbuf_stamp_info(RenderResult *rr, struct ImBuf *ibuf)
{
- struct StampData *stamp_data = rr->stamp_data;
- IMB_metadata_ensure(&ibuf->metadata);
- BKE_stamp_info_callback(ibuf, stamp_data, metadata_set_field, false);
+ struct StampData *stamp_data = rr->stamp_data;
+ IMB_metadata_ensure(&ibuf->metadata);
+ BKE_stamp_info_callback(ibuf, stamp_data, metadata_set_field, false);
}
-static void metadata_copy_custom_fields(
- const char *field,
- const char *value,
- void *rr_v)
+static void metadata_copy_custom_fields(const char *field, const char *value, void *rr_v)
{
- if (BKE_stamp_is_known_field(field)) {
- return;
- }
- RenderResult *rr = (RenderResult *)rr_v;
- BKE_render_result_stamp_data(rr, field, value);
+ if (BKE_stamp_is_known_field(field)) {
+ return;
+ }
+ RenderResult *rr = (RenderResult *)rr_v;
+ BKE_render_result_stamp_data(rr, field, value);
}
void BKE_stamp_info_from_imbuf(RenderResult *rr, struct ImBuf *ibuf)
{
- if (rr->stamp_data == NULL) {
- rr->stamp_data = MEM_callocN(sizeof(StampData), "RenderResult.stamp_data");
- }
- struct StampData *stamp_data = rr->stamp_data;
- IMB_metadata_ensure(&ibuf->metadata);
- BKE_stamp_info_callback(ibuf, stamp_data, metadata_get_field, true);
- /* Copy render engine specific settings. */
- IMB_metadata_foreach(ibuf, metadata_copy_custom_fields, rr);
+ if (rr->stamp_data == NULL) {
+ rr->stamp_data = MEM_callocN(sizeof(StampData), "RenderResult.stamp_data");
+ }
+ struct StampData *stamp_data = rr->stamp_data;
+ IMB_metadata_ensure(&ibuf->metadata);
+ BKE_stamp_info_callback(ibuf, stamp_data, metadata_get_field, true);
+ /* Copy render engine specific settings. */
+ IMB_metadata_foreach(ibuf, metadata_copy_custom_fields, rr);
}
bool BKE_imbuf_alpha_test(ImBuf *ibuf)
{
- int tot;
- if (ibuf->rect_float) {
- const float *buf = ibuf->rect_float;
- for (tot = ibuf->x * ibuf->y; tot--; buf += 4) {
- if (buf[3] < 1.0f) {
- return true;
- }
- }
- }
- else if (ibuf->rect) {
- unsigned char *buf = (unsigned char *)ibuf->rect;
- for (tot = ibuf->x * ibuf->y; tot--; buf += 4) {
- if (buf[3] != 255) {
- return true;
- }
- }
- }
-
- return false;
+ int tot;
+ if (ibuf->rect_float) {
+ const float *buf = ibuf->rect_float;
+ for (tot = ibuf->x * ibuf->y; tot--; buf += 4) {
+ if (buf[3] < 1.0f) {
+ return true;
+ }
+ }
+ }
+ else if (ibuf->rect) {
+ unsigned char *buf = (unsigned char *)ibuf->rect;
+ for (tot = ibuf->x * ibuf->y; tot--; buf += 4) {
+ if (buf[3] != 255) {
+ return true;
+ }
+ }
+ }
+
+ return false;
}
/* note: imf->planes is ignored here, its assumed the image channels
* are already set */
void BKE_imbuf_write_prepare(ImBuf *ibuf, const ImageFormatData *imf)
{
- char imtype = imf->imtype;
- char compress = imf->compress;
- char quality = imf->quality;
+ char imtype = imf->imtype;
+ char compress = imf->compress;
+ char quality = imf->quality;
- /* initialize all from image format */
- ibuf->foptions.flag = 0;
+ /* initialize all from image format */
+ ibuf->foptions.flag = 0;
- if (imtype == R_IMF_IMTYPE_IRIS) {
- ibuf->ftype = IMB_FTYPE_IMAGIC;
- }
+ if (imtype == R_IMF_IMTYPE_IRIS) {
+ ibuf->ftype = IMB_FTYPE_IMAGIC;
+ }
#ifdef WITH_HDR
- else if (imtype == R_IMF_IMTYPE_RADHDR) {
- ibuf->ftype = IMB_FTYPE_RADHDR;
- }
+ else if (imtype == R_IMF_IMTYPE_RADHDR) {
+ ibuf->ftype = IMB_FTYPE_RADHDR;
+ }
#endif
- else if (ELEM(imtype, R_IMF_IMTYPE_PNG, R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_THEORA, R_IMF_IMTYPE_XVID)) {
- ibuf->ftype = IMB_FTYPE_PNG;
-
- if (imtype == R_IMF_IMTYPE_PNG) {
- if (imf->depth == R_IMF_CHAN_DEPTH_16)
- ibuf->foptions.flag |= PNG_16BIT;
-
- ibuf->foptions.quality = compress;
- }
-
- }
+ else if (ELEM(imtype,
+ R_IMF_IMTYPE_PNG,
+ R_IMF_IMTYPE_FFMPEG,
+ R_IMF_IMTYPE_H264,
+ R_IMF_IMTYPE_THEORA,
+ R_IMF_IMTYPE_XVID)) {
+ ibuf->ftype = IMB_FTYPE_PNG;
+
+ if (imtype == R_IMF_IMTYPE_PNG) {
+ if (imf->depth == R_IMF_CHAN_DEPTH_16)
+ ibuf->foptions.flag |= PNG_16BIT;
+
+ ibuf->foptions.quality = compress;
+ }
+ }
#ifdef WITH_DDS
- else if (imtype == R_IMF_IMTYPE_DDS) {
- ibuf->ftype = IMB_FTYPE_DDS;
- }
+ else if (imtype == R_IMF_IMTYPE_DDS) {
+ ibuf->ftype = IMB_FTYPE_DDS;
+ }
#endif
- else if (imtype == R_IMF_IMTYPE_BMP) {
- ibuf->ftype = IMB_FTYPE_BMP;
- }
+ else if (imtype == R_IMF_IMTYPE_BMP) {
+ ibuf->ftype = IMB_FTYPE_BMP;
+ }
#ifdef WITH_TIFF
- else if (imtype == R_IMF_IMTYPE_TIFF) {
- ibuf->ftype = IMB_FTYPE_TIF;
-
- if (imf->depth == R_IMF_CHAN_DEPTH_16) {
- ibuf->foptions.flag |= TIF_16BIT;
- }
- if (imf->tiff_codec == R_IMF_TIFF_CODEC_NONE) {
- ibuf->foptions.flag |= TIF_COMPRESS_NONE;
- }
- else if (imf->tiff_codec == R_IMF_TIFF_CODEC_DEFLATE) {
- ibuf->foptions.flag |= TIF_COMPRESS_DEFLATE;
- }
- else if (imf->tiff_codec == R_IMF_TIFF_CODEC_LZW) {
- ibuf->foptions.flag |= TIF_COMPRESS_LZW;
- }
- else if (imf->tiff_codec == R_IMF_TIFF_CODEC_PACKBITS) {
- ibuf->foptions.flag |= TIF_COMPRESS_PACKBITS;
- }
- }
+ else if (imtype == R_IMF_IMTYPE_TIFF) {
+ ibuf->ftype = IMB_FTYPE_TIF;
+
+ if (imf->depth == R_IMF_CHAN_DEPTH_16) {
+ ibuf->foptions.flag |= TIF_16BIT;
+ }
+ if (imf->tiff_codec == R_IMF_TIFF_CODEC_NONE) {
+ ibuf->foptions.flag |= TIF_COMPRESS_NONE;
+ }
+ else if (imf->tiff_codec == R_IMF_TIFF_CODEC_DEFLATE) {
+ ibuf->foptions.flag |= TIF_COMPRESS_DEFLATE;
+ }
+ else if (imf->tiff_codec == R_IMF_TIFF_CODEC_LZW) {
+ ibuf->foptions.flag |= TIF_COMPRESS_LZW;
+ }
+ else if (imf->tiff_codec == R_IMF_TIFF_CODEC_PACKBITS) {
+ ibuf->foptions.flag |= TIF_COMPRESS_PACKBITS;
+ }
+ }
#endif
#ifdef WITH_OPENEXR
- else if (ELEM(imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER)) {
- ibuf->ftype = IMB_FTYPE_OPENEXR;
- if (imf->depth == R_IMF_CHAN_DEPTH_16)
- ibuf->foptions.flag |= OPENEXR_HALF;
- ibuf->foptions.flag |= (imf->exr_codec & OPENEXR_COMPRESS);
-
- if (!(imf->flag & R_IMF_FLAG_ZBUF)) {
- /* Signal for exr saving. */
- IMB_freezbuffloatImBuf(ibuf);
- }
-
- }
+ else if (ELEM(imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER)) {
+ ibuf->ftype = IMB_FTYPE_OPENEXR;
+ if (imf->depth == R_IMF_CHAN_DEPTH_16)
+ ibuf->foptions.flag |= OPENEXR_HALF;
+ ibuf->foptions.flag |= (imf->exr_codec & OPENEXR_COMPRESS);
+
+ if (!(imf->flag & R_IMF_FLAG_ZBUF)) {
+ /* Signal for exr saving. */
+ IMB_freezbuffloatImBuf(ibuf);
+ }
+ }
#endif
#ifdef WITH_CINEON
- else if (imtype == R_IMF_IMTYPE_CINEON) {
- ibuf->ftype = IMB_FTYPE_CINEON;
- if (imf->cineon_flag & R_IMF_CINEON_FLAG_LOG) {
- ibuf->foptions.flag |= CINEON_LOG;
- }
- if (imf->depth == R_IMF_CHAN_DEPTH_16) {
- ibuf->foptions.flag |= CINEON_16BIT;
- }
- else if (imf->depth == R_IMF_CHAN_DEPTH_12) {
- ibuf->foptions.flag |= CINEON_12BIT;
- }
- else if (imf->depth == R_IMF_CHAN_DEPTH_10) {
- ibuf->foptions.flag |= CINEON_10BIT;
- }
- }
- else if (imtype == R_IMF_IMTYPE_DPX) {
- ibuf->ftype = IMB_FTYPE_DPX;
- if (imf->cineon_flag & R_IMF_CINEON_FLAG_LOG) {
- ibuf->foptions.flag |= CINEON_LOG;
- }
- if (imf->depth == R_IMF_CHAN_DEPTH_16) {
- ibuf->foptions.flag |= CINEON_16BIT;
- }
- else if (imf->depth == R_IMF_CHAN_DEPTH_12) {
- ibuf->foptions.flag |= CINEON_12BIT;
- }
- else if (imf->depth == R_IMF_CHAN_DEPTH_10) {
- ibuf->foptions.flag |= CINEON_10BIT;
- }
- }
+ else if (imtype == R_IMF_IMTYPE_CINEON) {
+ ibuf->ftype = IMB_FTYPE_CINEON;
+ if (imf->cineon_flag & R_IMF_CINEON_FLAG_LOG) {
+ ibuf->foptions.flag |= CINEON_LOG;
+ }
+ if (imf->depth == R_IMF_CHAN_DEPTH_16) {
+ ibuf->foptions.flag |= CINEON_16BIT;
+ }
+ else if (imf->depth == R_IMF_CHAN_DEPTH_12) {
+ ibuf->foptions.flag |= CINEON_12BIT;
+ }
+ else if (imf->depth == R_IMF_CHAN_DEPTH_10) {
+ ibuf->foptions.flag |= CINEON_10BIT;
+ }
+ }
+ else if (imtype == R_IMF_IMTYPE_DPX) {
+ ibuf->ftype = IMB_FTYPE_DPX;
+ if (imf->cineon_flag & R_IMF_CINEON_FLAG_LOG) {
+ ibuf->foptions.flag |= CINEON_LOG;
+ }
+ if (imf->depth == R_IMF_CHAN_DEPTH_16) {
+ ibuf->foptions.flag |= CINEON_16BIT;
+ }
+ else if (imf->depth == R_IMF_CHAN_DEPTH_12) {
+ ibuf->foptions.flag |= CINEON_12BIT;
+ }
+ else if (imf->depth == R_IMF_CHAN_DEPTH_10) {
+ ibuf->foptions.flag |= CINEON_10BIT;
+ }
+ }
#endif
- else if (imtype == R_IMF_IMTYPE_TARGA) {
- ibuf->ftype = IMB_FTYPE_TGA;
- }
- else if (imtype == R_IMF_IMTYPE_RAWTGA) {
- ibuf->ftype = IMB_FTYPE_TGA;
- ibuf->foptions.flag = RAWTGA;
- }
+ else if (imtype == R_IMF_IMTYPE_TARGA) {
+ ibuf->ftype = IMB_FTYPE_TGA;
+ }
+ else if (imtype == R_IMF_IMTYPE_RAWTGA) {
+ ibuf->ftype = IMB_FTYPE_TGA;
+ ibuf->foptions.flag = RAWTGA;
+ }
#ifdef WITH_OPENJPEG
- else if (imtype == R_IMF_IMTYPE_JP2) {
- if (quality < 10) quality = 90;
- ibuf->ftype = IMB_FTYPE_JP2;
- ibuf->foptions.quality = quality;
-
- if (imf->depth == R_IMF_CHAN_DEPTH_16) {
- ibuf->foptions.flag |= JP2_16BIT;
- }
- else if (imf->depth == R_IMF_CHAN_DEPTH_12) {
- ibuf->foptions.flag |= JP2_12BIT;
- }
-
- if (imf->jp2_flag & R_IMF_JP2_FLAG_YCC) {
- ibuf->foptions.flag |= JP2_YCC;
- }
-
- if (imf->jp2_flag & R_IMF_JP2_FLAG_CINE_PRESET) {
- ibuf->foptions.flag |= JP2_CINE;
- if (imf->jp2_flag & R_IMF_JP2_FLAG_CINE_48)
- ibuf->foptions.flag |= JP2_CINE_48FPS;
- }
-
- if (imf->jp2_codec == R_IMF_JP2_CODEC_JP2)
- ibuf->foptions.flag |= JP2_JP2;
- else if (imf->jp2_codec == R_IMF_JP2_CODEC_J2K)
- ibuf->foptions.flag |= JP2_J2K;
- else
- BLI_assert(!"Unsupported jp2 codec was specified in im_format->jp2_codec");
- }
+ else if (imtype == R_IMF_IMTYPE_JP2) {
+ if (quality < 10)
+ quality = 90;
+ ibuf->ftype = IMB_FTYPE_JP2;
+ ibuf->foptions.quality = quality;
+
+ if (imf->depth == R_IMF_CHAN_DEPTH_16) {
+ ibuf->foptions.flag |= JP2_16BIT;
+ }
+ else if (imf->depth == R_IMF_CHAN_DEPTH_12) {
+ ibuf->foptions.flag |= JP2_12BIT;
+ }
+
+ if (imf->jp2_flag & R_IMF_JP2_FLAG_YCC) {
+ ibuf->foptions.flag |= JP2_YCC;
+ }
+
+ if (imf->jp2_flag & R_IMF_JP2_FLAG_CINE_PRESET) {
+ ibuf->foptions.flag |= JP2_CINE;
+ if (imf->jp2_flag & R_IMF_JP2_FLAG_CINE_48)
+ ibuf->foptions.flag |= JP2_CINE_48FPS;
+ }
+
+ if (imf->jp2_codec == R_IMF_JP2_CODEC_JP2)
+ ibuf->foptions.flag |= JP2_JP2;
+ else if (imf->jp2_codec == R_IMF_JP2_CODEC_J2K)
+ ibuf->foptions.flag |= JP2_J2K;
+ else
+ BLI_assert(!"Unsupported jp2 codec was specified in im_format->jp2_codec");
+ }
#endif
- else {
- /* R_IMF_IMTYPE_JPEG90, etc. default we save jpegs */
- if (quality < 10) quality = 90;
- ibuf->ftype = IMB_FTYPE_JPG;
- ibuf->foptions.quality = quality;
- }
+ else {
+ /* R_IMF_IMTYPE_JPEG90, etc. default we save jpegs */
+ if (quality < 10)
+ quality = 90;
+ ibuf->ftype = IMB_FTYPE_JPG;
+ ibuf->foptions.quality = quality;
+ }
}
int BKE_imbuf_write(ImBuf *ibuf, const char *name, const ImageFormatData *imf)
{
- int ok;
+ int ok;
- BKE_imbuf_write_prepare(ibuf, imf);
+ BKE_imbuf_write_prepare(ibuf, imf);
- BLI_make_existing_file(name);
+ BLI_make_existing_file(name);
- ok = IMB_saveiff(ibuf, name, IB_rect | IB_zbuf | IB_zbuffloat);
- if (ok == 0) {
- perror(name);
- }
+ ok = IMB_saveiff(ibuf, name, IB_rect | IB_zbuf | IB_zbuffloat);
+ if (ok == 0) {
+ perror(name);
+ }
- return(ok);
+ return (ok);
}
/* same as BKE_imbuf_write() but crappy workaround not to permanently modify
* _some_, values in the imbuf */
-int BKE_imbuf_write_as(ImBuf *ibuf, const char *name, ImageFormatData *imf,
- const bool save_copy)
+int BKE_imbuf_write_as(ImBuf *ibuf, const char *name, ImageFormatData *imf, const bool save_copy)
{
- ImBuf ibuf_back = *ibuf;
- int ok;
+ ImBuf ibuf_back = *ibuf;
+ int ok;
- /* all data is rgba anyway,
- * this just controls how to save for some formats */
- ibuf->planes = imf->planes;
+ /* all data is rgba anyway,
+ * this just controls how to save for some formats */
+ ibuf->planes = imf->planes;
- ok = BKE_imbuf_write(ibuf, name, imf);
+ ok = BKE_imbuf_write(ibuf, name, imf);
- if (save_copy) {
- /* note that we are not restoring _all_ settings */
- ibuf->planes = ibuf_back.planes;
- ibuf->ftype = ibuf_back.ftype;
- ibuf->foptions = ibuf_back.foptions;
- }
+ if (save_copy) {
+ /* note that we are not restoring _all_ settings */
+ ibuf->planes = ibuf_back.planes;
+ ibuf->ftype = ibuf_back.ftype;
+ ibuf->foptions = ibuf_back.foptions;
+ }
- return ok;
+ return ok;
}
-int BKE_imbuf_write_stamp(
- Scene *scene, struct RenderResult *rr, ImBuf *ibuf, const char *name,
- const struct ImageFormatData *imf)
+int BKE_imbuf_write_stamp(Scene *scene,
+ struct RenderResult *rr,
+ ImBuf *ibuf,
+ const char *name,
+ const struct ImageFormatData *imf)
{
- if (scene && scene->r.stamp & R_STAMP_ALL)
- BKE_imbuf_stamp_info(rr, ibuf);
+ if (scene && scene->r.stamp & R_STAMP_ALL)
+ BKE_imbuf_stamp_info(rr, ibuf);
- return BKE_imbuf_write(ibuf, name, imf);
+ return BKE_imbuf_write(ibuf, name, imf);
}
-static void do_makepicstring(
- char *string, const char *base, const char *relbase, int frame, const char imtype,
- const ImageFormatData *im_format, const short use_ext, const short use_frames,
- const char *suffix)
+static void do_makepicstring(char *string,
+ const char *base,
+ const char *relbase,
+ int frame,
+ const char imtype,
+ const ImageFormatData *im_format,
+ const short use_ext,
+ const short use_frames,
+ const char *suffix)
{
- if (string == NULL) return;
- BLI_strncpy(string, base, FILE_MAX - 10); /* weak assumption */
- BLI_path_abs(string, relbase);
+ if (string == NULL)
+ return;
+ BLI_strncpy(string, base, FILE_MAX - 10); /* weak assumption */
+ BLI_path_abs(string, relbase);
- if (use_frames)
- BLI_path_frame(string, frame, 4);
+ if (use_frames)
+ BLI_path_frame(string, frame, 4);
- if (suffix)
- BLI_path_suffix(string, FILE_MAX, suffix, "");
+ if (suffix)
+ BLI_path_suffix(string, FILE_MAX, suffix, "");
- if (use_ext)
- do_add_image_extension(string, imtype, im_format);
+ if (use_ext)
+ do_add_image_extension(string, imtype, im_format);
}
-void BKE_image_path_from_imformat(
- char *string, const char *base, const char *relbase, int frame,
- const ImageFormatData *im_format, const bool use_ext, const bool use_frames, const char *suffix)
+void BKE_image_path_from_imformat(char *string,
+ const char *base,
+ const char *relbase,
+ int frame,
+ const ImageFormatData *im_format,
+ const bool use_ext,
+ const bool use_frames,
+ const char *suffix)
{
- do_makepicstring(string, base, relbase, frame, im_format->imtype, im_format, use_ext, use_frames, suffix);
+ do_makepicstring(
+ string, base, relbase, frame, im_format->imtype, im_format, use_ext, use_frames, suffix);
}
-void BKE_image_path_from_imtype(
- char *string, const char *base, const char *relbase, int frame,
- const char imtype, const bool use_ext, const bool use_frames, const char *view)
+void BKE_image_path_from_imtype(char *string,
+ const char *base,
+ const char *relbase,
+ int frame,
+ const char imtype,
+ const bool use_ext,
+ const bool use_frames,
+ const char *view)
{
- do_makepicstring(string, base, relbase, frame, imtype, NULL, use_ext, use_frames, view);
+ do_makepicstring(string, base, relbase, frame, imtype, NULL, use_ext, use_frames, view);
}
-struct anim *openanim_noload(const char *name, int flags, int streamindex, char colorspace[IMA_MAX_SPACE])
+struct anim *openanim_noload(const char *name,
+ int flags,
+ int streamindex,
+ char colorspace[IMA_MAX_SPACE])
{
- struct anim *anim;
+ struct anim *anim;
- anim = IMB_open_anim(name, flags, streamindex, colorspace);
- return anim;
+ anim = IMB_open_anim(name, flags, streamindex, colorspace);
+ return anim;
}
/* used by sequencer too */
struct anim *openanim(const char *name, int flags, int streamindex, char colorspace[IMA_MAX_SPACE])
{
- struct anim *anim;
- struct ImBuf *ibuf;
+ struct anim *anim;
+ struct ImBuf *ibuf;
- anim = IMB_open_anim(name, flags, streamindex, colorspace);
- if (anim == NULL) return NULL;
+ anim = IMB_open_anim(name, flags, streamindex, colorspace);
+ if (anim == NULL)
+ return NULL;
- ibuf = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE);
- if (ibuf == NULL) {
- if (BLI_exists(name))
- printf("not an anim: %s\n", name);
- else
- printf("anim file doesn't exist: %s\n", name);
- IMB_free_anim(anim);
- return NULL;
- }
- IMB_freeImBuf(ibuf);
+ ibuf = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE);
+ if (ibuf == NULL) {
+ if (BLI_exists(name))
+ printf("not an anim: %s\n", name);
+ else
+ printf("anim file doesn't exist: %s\n", name);
+ IMB_free_anim(anim);
+ return NULL;
+ }
+ IMB_freeImBuf(ibuf);
- return(anim);
+ return (anim);
}
/* ************************* New Image API *************** */
-
/* Notes about Image storage
* - packedfile
* -> written in .blend
@@ -2565,466 +2762,462 @@ struct anim *openanim(const char *name, int flags, int streamindex, char colorsp
* -> comes from packedfile or filename or generated
*/
-
/* forces existence of 1 Image for renderout or nodes, returns Image */
/* name is only for default, when making new one */
Image *BKE_image_verify_viewer(Main *bmain, int type, const char *name)
{
- Image *ima;
+ Image *ima;
- for (ima = bmain->images.first; ima; ima = ima->id.next)
- if (ima->source == IMA_SRC_VIEWER)
- if (ima->type == type)
- break;
+ for (ima = bmain->images.first; ima; ima = ima->id.next)
+ if (ima->source == IMA_SRC_VIEWER)
+ if (ima->type == type)
+ break;
- if (ima == NULL)
- ima = image_alloc(bmain, name, IMA_SRC_VIEWER, type);
+ if (ima == NULL)
+ ima = image_alloc(bmain, name, IMA_SRC_VIEWER, type);
- /* happens on reload, imagewindow cannot be image user when hidden*/
- if (ima->id.us == 0)
- id_us_plus(&ima->id);
+ /* happens on reload, imagewindow cannot be image user when hidden*/
+ if (ima->id.us == 0)
+ id_us_plus(&ima->id);
- return ima;
+ return ima;
}
static void image_viewer_create_views(const RenderData *rd, Image *ima)
{
- if ((rd->scemode & R_MULTIVIEW) == 0) {
- image_add_view(ima, "", "");
- }
- else {
- SceneRenderView *srv;
- for (srv = rd->views.first; srv; srv = srv->next) {
- if (BKE_scene_multiview_is_render_view_active(rd, srv) == false)
- continue;
- image_add_view(ima, srv->name, "");
- }
- }
+ if ((rd->scemode & R_MULTIVIEW) == 0) {
+ image_add_view(ima, "", "");
+ }
+ else {
+ SceneRenderView *srv;
+ for (srv = rd->views.first; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(rd, srv) == false)
+ continue;
+ image_add_view(ima, srv->name, "");
+ }
+ }
}
/* Reset the image cache and views when the Viewer Nodes views don't match the scene views */
void BKE_image_verify_viewer_views(const RenderData *rd, Image *ima, ImageUser *iuser)
{
- bool do_reset;
- const bool is_multiview = (rd->scemode & R_MULTIVIEW) != 0;
-
- BLI_thread_lock(LOCK_DRAW_IMAGE);
-
- if (!BKE_scene_multiview_is_stereo3d(rd))
- iuser->flag &= ~IMA_SHOW_STEREO;
-
- /* see if all scene render views are in the image view list */
- do_reset = (BKE_scene_multiview_num_views_get(rd) != BLI_listbase_count(&ima->views));
-
- /* multiview also needs to be sure all the views are synced */
- if (is_multiview && !do_reset) {
- SceneRenderView *srv;
- ImageView *iv;
-
- for (iv = ima->views.first; iv; iv = iv->next) {
- srv = BLI_findstring(&rd->views, iv->name, offsetof(SceneRenderView, name));
- if ((srv == NULL) || (BKE_scene_multiview_is_render_view_active(rd, srv) == false)) {
- do_reset = true;
- break;
- }
- }
- }
-
- if (do_reset) {
- BLI_spin_lock(&image_spin);
-
- image_free_cached_frames(ima);
- BKE_image_free_views(ima);
-
- /* add new views */
- image_viewer_create_views(rd, ima);
-
- BLI_spin_unlock(&image_spin);
- }
-
- BLI_thread_unlock(LOCK_DRAW_IMAGE);
-}
-
-static void image_walk_ntree_all_users(bNodeTree *ntree, void *customdata,
- void callback(Image *ima, ImageUser *iuser, void *customdata))
-{
- switch (ntree->type) {
- case NTREE_SHADER:
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
- if (node->id) {
- if (node->type == SH_NODE_TEX_IMAGE) {
- NodeTexImage *tex = node->storage;
- Image *ima = (Image *)node->id;
- callback(ima, &tex->iuser, customdata);
- }
- if (node->type == SH_NODE_TEX_ENVIRONMENT) {
- NodeTexImage *tex = node->storage;
- Image *ima = (Image *)node->id;
- callback(ima, &tex->iuser, customdata);
- }
- }
- }
- break;
- case NTREE_TEXTURE:
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
- if (node->id && node->type == TEX_NODE_IMAGE) {
- Image *ima = (Image *)node->id;
- ImageUser *iuser = node->storage;
- callback(ima, iuser, customdata);
- }
- }
- break;
- case NTREE_COMPOSIT:
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
- if (node->id && node->type == CMP_NODE_IMAGE) {
- Image *ima = (Image *)node->id;
- ImageUser *iuser = node->storage;
- callback(ima, iuser, customdata);
- }
- }
- break;
- }
-}
-
-static void image_walk_id_all_users(ID *id, bool skip_nested_nodes, void *customdata,
+ bool do_reset;
+ const bool is_multiview = (rd->scemode & R_MULTIVIEW) != 0;
+
+ BLI_thread_lock(LOCK_DRAW_IMAGE);
+
+ if (!BKE_scene_multiview_is_stereo3d(rd))
+ iuser->flag &= ~IMA_SHOW_STEREO;
+
+ /* see if all scene render views are in the image view list */
+ do_reset = (BKE_scene_multiview_num_views_get(rd) != BLI_listbase_count(&ima->views));
+
+ /* multiview also needs to be sure all the views are synced */
+ if (is_multiview && !do_reset) {
+ SceneRenderView *srv;
+ ImageView *iv;
+
+ for (iv = ima->views.first; iv; iv = iv->next) {
+ srv = BLI_findstring(&rd->views, iv->name, offsetof(SceneRenderView, name));
+ if ((srv == NULL) || (BKE_scene_multiview_is_render_view_active(rd, srv) == false)) {
+ do_reset = true;
+ break;
+ }
+ }
+ }
+
+ if (do_reset) {
+ BLI_spin_lock(&image_spin);
+
+ image_free_cached_frames(ima);
+ BKE_image_free_views(ima);
+
+ /* add new views */
+ image_viewer_create_views(rd, ima);
+
+ BLI_spin_unlock(&image_spin);
+ }
+
+ BLI_thread_unlock(LOCK_DRAW_IMAGE);
+}
+
+static void image_walk_ntree_all_users(bNodeTree *ntree,
+ void *customdata,
+ void callback(Image *ima,
+ ImageUser *iuser,
+ void *customdata))
+{
+ switch (ntree->type) {
+ case NTREE_SHADER:
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->id) {
+ if (node->type == SH_NODE_TEX_IMAGE) {
+ NodeTexImage *tex = node->storage;
+ Image *ima = (Image *)node->id;
+ callback(ima, &tex->iuser, customdata);
+ }
+ if (node->type == SH_NODE_TEX_ENVIRONMENT) {
+ NodeTexImage *tex = node->storage;
+ Image *ima = (Image *)node->id;
+ callback(ima, &tex->iuser, customdata);
+ }
+ }
+ }
+ break;
+ case NTREE_TEXTURE:
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->id && node->type == TEX_NODE_IMAGE) {
+ Image *ima = (Image *)node->id;
+ ImageUser *iuser = node->storage;
+ callback(ima, iuser, customdata);
+ }
+ }
+ break;
+ case NTREE_COMPOSIT:
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->id && node->type == CMP_NODE_IMAGE) {
+ Image *ima = (Image *)node->id;
+ ImageUser *iuser = node->storage;
+ callback(ima, iuser, customdata);
+ }
+ }
+ break;
+ }
+}
+
+static void image_walk_id_all_users(ID *id,
+ bool skip_nested_nodes,
+ void *customdata,
void callback(Image *ima, ImageUser *iuser, void *customdata))
{
- switch (GS(id->name)) {
- case ID_OB:
- {
- Object *ob = (Object *)id;
- if (ob->empty_drawtype == OB_EMPTY_IMAGE && ob->data) {
- callback(ob->data, ob->iuser, customdata);
- }
- break;
- }
- case ID_MA:
- {
- Material *ma = (Material *)id;
- if (ma->nodetree && ma->use_nodes && !skip_nested_nodes) {
- image_walk_ntree_all_users(ma->nodetree, customdata, callback);
- }
- break;
- }
- case ID_LA:
- {
- Light *light = (Light *)id;
- if (light->nodetree && light->use_nodes && !skip_nested_nodes) {
- image_walk_ntree_all_users(light->nodetree, customdata, callback);
- }
- break;
- }
- case ID_WO:
- {
- World *world = (World *)id;
- if (world->nodetree && world->use_nodes && !skip_nested_nodes) {
- image_walk_ntree_all_users(world->nodetree, customdata, callback);
- }
- break;
- }
- case ID_TE:
- {
- Tex *tex = (Tex *)id;
- if (tex->type == TEX_IMAGE && tex->ima) {
- callback(tex->ima, &tex->iuser, customdata);
- }
- if (tex->nodetree && tex->use_nodes && !skip_nested_nodes) {
- image_walk_ntree_all_users(tex->nodetree, customdata, callback);
- }
- break;
- }
- case ID_NT:
- {
- bNodeTree *ntree = (bNodeTree *)id;
- image_walk_ntree_all_users(ntree, customdata, callback);
- break;
- }
- case ID_CA:
- {
- Camera *cam = (Camera *)id;
- for (CameraBGImage *bgpic = cam->bg_images.first; bgpic; bgpic = bgpic->next) {
- callback(bgpic->ima, &bgpic->iuser, customdata);
- }
- break;
- }
- case ID_WM:
- {
- wmWindowManager *wm = (wmWindowManager *)id;
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
- const bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
-
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = sa->spacedata.first;
- callback(sima->image, &sima->iuser, customdata);
- }
- }
- }
- break;
- }
- case ID_SCE:
- {
- Scene *scene = (Scene *)id;
- if (scene->nodetree && scene->use_nodes && !skip_nested_nodes) {
- image_walk_ntree_all_users(scene->nodetree, customdata, callback);
- }
- }
- default:
- break;
- }
-}
-
-void BKE_image_walk_all_users(const Main *mainp, void *customdata,
+ switch (GS(id->name)) {
+ case ID_OB: {
+ Object *ob = (Object *)id;
+ if (ob->empty_drawtype == OB_EMPTY_IMAGE && ob->data) {
+ callback(ob->data, ob->iuser, customdata);
+ }
+ break;
+ }
+ case ID_MA: {
+ Material *ma = (Material *)id;
+ if (ma->nodetree && ma->use_nodes && !skip_nested_nodes) {
+ image_walk_ntree_all_users(ma->nodetree, customdata, callback);
+ }
+ break;
+ }
+ case ID_LA: {
+ Light *light = (Light *)id;
+ if (light->nodetree && light->use_nodes && !skip_nested_nodes) {
+ image_walk_ntree_all_users(light->nodetree, customdata, callback);
+ }
+ break;
+ }
+ case ID_WO: {
+ World *world = (World *)id;
+ if (world->nodetree && world->use_nodes && !skip_nested_nodes) {
+ image_walk_ntree_all_users(world->nodetree, customdata, callback);
+ }
+ break;
+ }
+ case ID_TE: {
+ Tex *tex = (Tex *)id;
+ if (tex->type == TEX_IMAGE && tex->ima) {
+ callback(tex->ima, &tex->iuser, customdata);
+ }
+ if (tex->nodetree && tex->use_nodes && !skip_nested_nodes) {
+ image_walk_ntree_all_users(tex->nodetree, customdata, callback);
+ }
+ break;
+ }
+ case ID_NT: {
+ bNodeTree *ntree = (bNodeTree *)id;
+ image_walk_ntree_all_users(ntree, customdata, callback);
+ break;
+ }
+ case ID_CA: {
+ Camera *cam = (Camera *)id;
+ for (CameraBGImage *bgpic = cam->bg_images.first; bgpic; bgpic = bgpic->next) {
+ callback(bgpic->ima, &bgpic->iuser, customdata);
+ }
+ break;
+ }
+ case ID_WM: {
+ wmWindowManager *wm = (wmWindowManager *)id;
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ const bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
+
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ if (sa->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = sa->spacedata.first;
+ callback(sima->image, &sima->iuser, customdata);
+ }
+ }
+ }
+ break;
+ }
+ case ID_SCE: {
+ Scene *scene = (Scene *)id;
+ if (scene->nodetree && scene->use_nodes && !skip_nested_nodes) {
+ image_walk_ntree_all_users(scene->nodetree, customdata, callback);
+ }
+ }
+ default:
+ break;
+ }
+}
+
+void BKE_image_walk_all_users(const Main *mainp,
+ void *customdata,
void callback(Image *ima, ImageUser *iuser, void *customdata))
{
- for (Scene *scene = mainp->scenes.first; scene; scene = scene->id.next) {
- image_walk_id_all_users(&scene->id, false, customdata, callback);
- }
+ for (Scene *scene = mainp->scenes.first; scene; scene = scene->id.next) {
+ image_walk_id_all_users(&scene->id, false, customdata, callback);
+ }
- for (Object *ob = mainp->objects.first; ob; ob = ob->id.next) {
- image_walk_id_all_users(&ob->id, false, customdata, callback);
- }
+ for (Object *ob = mainp->objects.first; ob; ob = ob->id.next) {
+ image_walk_id_all_users(&ob->id, false, customdata, callback);
+ }
- for (bNodeTree *ntree = mainp->nodetrees.first; ntree; ntree = ntree->id.next) {
- image_walk_id_all_users(&ntree->id, false, customdata, callback);
- }
+ for (bNodeTree *ntree = mainp->nodetrees.first; ntree; ntree = ntree->id.next) {
+ image_walk_id_all_users(&ntree->id, false, customdata, callback);
+ }
- for (Material *ma = mainp->materials.first; ma; ma = ma->id.next) {
- image_walk_id_all_users(&ma->id, false, customdata, callback);
- }
+ for (Material *ma = mainp->materials.first; ma; ma = ma->id.next) {
+ image_walk_id_all_users(&ma->id, false, customdata, callback);
+ }
- for (Light *light = mainp->materials.first; light; light = light->id.next) {
- image_walk_id_all_users(&light->id, false, customdata, callback);
- }
+ for (Light *light = mainp->materials.first; light; light = light->id.next) {
+ image_walk_id_all_users(&light->id, false, customdata, callback);
+ }
- for (World *world = mainp->materials.first; world; world = world->id.next) {
- image_walk_id_all_users(&world->id, false, customdata, callback);
- }
+ for (World *world = mainp->materials.first; world; world = world->id.next) {
+ image_walk_id_all_users(&world->id, false, customdata, callback);
+ }
- for (Tex *tex = mainp->textures.first; tex; tex = tex->id.next) {
- image_walk_id_all_users(&tex->id, false, customdata, callback);
- }
+ for (Tex *tex = mainp->textures.first; tex; tex = tex->id.next) {
+ image_walk_id_all_users(&tex->id, false, customdata, callback);
+ }
- for (Camera *cam = mainp->cameras.first; cam; cam = cam->id.next) {
- image_walk_id_all_users(&cam->id, false, customdata, callback);
- }
+ for (Camera *cam = mainp->cameras.first; cam; cam = cam->id.next) {
+ image_walk_id_all_users(&cam->id, false, customdata, callback);
+ }
- for (wmWindowManager *wm = mainp->wm.first; wm; wm = wm->id.next) { /* only 1 wm */
- image_walk_id_all_users(&wm->id, false, customdata, callback);
- }
+ for (wmWindowManager *wm = mainp->wm.first; wm; wm = wm->id.next) { /* only 1 wm */
+ image_walk_id_all_users(&wm->id, false, customdata, callback);
+ }
}
static void image_tag_frame_recalc(Image *ima, ImageUser *iuser, void *customdata)
{
- Image *changed_image = customdata;
+ Image *changed_image = customdata;
- if (ima == changed_image && BKE_image_is_animated(ima)) {
- iuser->flag |= IMA_NEED_FRAME_RECALC;
- iuser->ok = 1;
- }
+ if (ima == changed_image && BKE_image_is_animated(ima)) {
+ iuser->flag |= IMA_NEED_FRAME_RECALC;
+ iuser->ok = 1;
+ }
}
static void image_tag_reload(Image *ima, ImageUser *iuser, void *customdata)
{
- Image *changed_image = customdata;
+ Image *changed_image = customdata;
- if (ima == changed_image) {
- iuser->ok = 1;
- if (iuser->scene) {
- image_update_views_format(ima, iuser);
- }
- }
+ if (ima == changed_image) {
+ iuser->ok = 1;
+ if (iuser->scene) {
+ image_update_views_format(ima, iuser);
+ }
+ }
}
static void image_init_imageuser(Image *ima, ImageUser *iuser)
{
- RenderResult *rr = ima->rr;
+ RenderResult *rr = ima->rr;
- iuser->multi_index = 0;
- iuser->layer = iuser->pass = iuser->view = 0;
+ iuser->multi_index = 0;
+ iuser->layer = iuser->pass = iuser->view = 0;
- if (rr)
- BKE_image_multilayer_index(rr, iuser);
+ if (rr)
+ BKE_image_multilayer_index(rr, iuser);
}
void BKE_image_init_imageuser(Image *ima, ImageUser *iuser)
{
- image_init_imageuser(ima, iuser);
+ image_init_imageuser(ima, iuser);
}
void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
{
- if (ima == NULL)
- return;
-
- BLI_spin_lock(&image_spin);
-
- switch (signal) {
- case IMA_SIGNAL_FREE:
- BKE_image_free_buffers(ima);
-
- if (iuser) {
- iuser->ok = 1;
- if (iuser->scene) {
- image_update_views_format(ima, iuser);
- }
- }
- break;
- case IMA_SIGNAL_SRC_CHANGE:
- if (ima->type == IMA_TYPE_UV_TEST)
- if (ima->source != IMA_SRC_GENERATED)
- ima->type = IMA_TYPE_IMAGE;
-
- if (ima->source == IMA_SRC_GENERATED) {
- if (ima->gen_x == 0 || ima->gen_y == 0) {
- ImBuf *ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0);
- if (ibuf) {
- ima->gen_x = ibuf->x;
- ima->gen_y = ibuf->y;
- IMB_freeImBuf(ibuf);
- }
- }
-
- /* Changing source type to generated will likely change file format
- * used by generated image buffer. Saving different file format to
- * the old name might confuse other applications.
- *
- * Here we ensure original image path wouldn't be used when saving
- * generated image.
- */
- ima->name[0] = '\0';
- }
-
- /* image buffers for non-sequence multilayer will share buffers with RenderResult,
- * however sequence multilayer will own buffers. Such logic makes switching from
- * single multilayer file to sequence completely unstable
- * since changes in nodes seems this workaround isn't needed anymore, all sockets
- * are nicely detecting anyway, but freeing buffers always here makes multilayer
- * sequences behave stable
- */
- BKE_image_free_buffers(ima);
-
- ima->ok = 1;
- if (iuser) {
- image_tag_frame_recalc(ima, iuser, ima);
- }
- BKE_image_walk_all_users(bmain, ima, image_tag_frame_recalc);
-
- break;
-
- case IMA_SIGNAL_RELOAD:
- /* try to repack file */
- if (BKE_image_has_packedfile(ima)) {
- const int totfiles = image_num_files(ima);
-
- if (totfiles != BLI_listbase_count_at_most(&ima->packedfiles, totfiles + 1)) {
- /* in case there are new available files to be loaded */
- image_free_packedfiles(ima);
- BKE_image_packfiles(NULL, ima, ID_BLEND_PATH(bmain, &ima->id));
- }
- else {
- ImagePackedFile *imapf;
- for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next) {
- PackedFile *pf;
- pf = newPackedFile(NULL, imapf->filepath, ID_BLEND_PATH(bmain, &ima->id));
- if (pf) {
- freePackedFile(imapf->packedfile);
- imapf->packedfile = pf;
- }
- else {
- printf("ERROR: Image \"%s\" not available. Keeping packed image\n", imapf->filepath);
- }
- }
- }
-
- if (BKE_image_has_packedfile(ima))
- BKE_image_free_buffers(ima);
- }
- else
- BKE_image_free_buffers(ima);
-
- if (iuser) {
- image_tag_reload(ima, iuser, ima);
- }
- BKE_image_walk_all_users(bmain, ima, image_tag_reload);
- break;
- case IMA_SIGNAL_USER_NEW_IMAGE:
- if (iuser) {
- iuser->ok = 1;
- if (ima->source == IMA_SRC_FILE || ima->source == IMA_SRC_SEQUENCE) {
- if (ima->type == IMA_TYPE_MULTILAYER) {
- image_init_imageuser(ima, iuser);
- }
- }
- }
- break;
- case IMA_SIGNAL_COLORMANAGE:
- BKE_image_free_buffers(ima);
-
- ima->ok = 1;
-
- if (iuser)
- iuser->ok = 1;
-
- break;
- }
-
- BLI_spin_unlock(&image_spin);
-
- /* don't use notifiers because they are not 100% sure to succeeded
- * this also makes sure all scenes are accounted for. */
- {
- Scene *scene;
- for (scene = bmain->scenes.first; scene; scene = scene->id.next) {
- if (scene->nodetree) {
- nodeUpdateID(scene->nodetree, &ima->id);
- }
- }
- }
+ if (ima == NULL)
+ return;
+
+ BLI_spin_lock(&image_spin);
+
+ switch (signal) {
+ case IMA_SIGNAL_FREE:
+ BKE_image_free_buffers(ima);
+
+ if (iuser) {
+ iuser->ok = 1;
+ if (iuser->scene) {
+ image_update_views_format(ima, iuser);
+ }
+ }
+ break;
+ case IMA_SIGNAL_SRC_CHANGE:
+ if (ima->type == IMA_TYPE_UV_TEST)
+ if (ima->source != IMA_SRC_GENERATED)
+ ima->type = IMA_TYPE_IMAGE;
+
+ if (ima->source == IMA_SRC_GENERATED) {
+ if (ima->gen_x == 0 || ima->gen_y == 0) {
+ ImBuf *ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0);
+ if (ibuf) {
+ ima->gen_x = ibuf->x;
+ ima->gen_y = ibuf->y;
+ IMB_freeImBuf(ibuf);
+ }
+ }
+
+ /* Changing source type to generated will likely change file format
+ * used by generated image buffer. Saving different file format to
+ * the old name might confuse other applications.
+ *
+ * Here we ensure original image path wouldn't be used when saving
+ * generated image.
+ */
+ ima->name[0] = '\0';
+ }
+
+ /* image buffers for non-sequence multilayer will share buffers with RenderResult,
+ * however sequence multilayer will own buffers. Such logic makes switching from
+ * single multilayer file to sequence completely unstable
+ * since changes in nodes seems this workaround isn't needed anymore, all sockets
+ * are nicely detecting anyway, but freeing buffers always here makes multilayer
+ * sequences behave stable
+ */
+ BKE_image_free_buffers(ima);
+
+ ima->ok = 1;
+ if (iuser) {
+ image_tag_frame_recalc(ima, iuser, ima);
+ }
+ BKE_image_walk_all_users(bmain, ima, image_tag_frame_recalc);
+
+ break;
+
+ case IMA_SIGNAL_RELOAD:
+ /* try to repack file */
+ if (BKE_image_has_packedfile(ima)) {
+ const int totfiles = image_num_files(ima);
+
+ if (totfiles != BLI_listbase_count_at_most(&ima->packedfiles, totfiles + 1)) {
+ /* in case there are new available files to be loaded */
+ image_free_packedfiles(ima);
+ BKE_image_packfiles(NULL, ima, ID_BLEND_PATH(bmain, &ima->id));
+ }
+ else {
+ ImagePackedFile *imapf;
+ for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next) {
+ PackedFile *pf;
+ pf = newPackedFile(NULL, imapf->filepath, ID_BLEND_PATH(bmain, &ima->id));
+ if (pf) {
+ freePackedFile(imapf->packedfile);
+ imapf->packedfile = pf;
+ }
+ else {
+ printf("ERROR: Image \"%s\" not available. Keeping packed image\n", imapf->filepath);
+ }
+ }
+ }
+
+ if (BKE_image_has_packedfile(ima))
+ BKE_image_free_buffers(ima);
+ }
+ else
+ BKE_image_free_buffers(ima);
+
+ if (iuser) {
+ image_tag_reload(ima, iuser, ima);
+ }
+ BKE_image_walk_all_users(bmain, ima, image_tag_reload);
+ break;
+ case IMA_SIGNAL_USER_NEW_IMAGE:
+ if (iuser) {
+ iuser->ok = 1;
+ if (ima->source == IMA_SRC_FILE || ima->source == IMA_SRC_SEQUENCE) {
+ if (ima->type == IMA_TYPE_MULTILAYER) {
+ image_init_imageuser(ima, iuser);
+ }
+ }
+ }
+ break;
+ case IMA_SIGNAL_COLORMANAGE:
+ BKE_image_free_buffers(ima);
+
+ ima->ok = 1;
+
+ if (iuser)
+ iuser->ok = 1;
+
+ break;
+ }
+
+ BLI_spin_unlock(&image_spin);
+
+ /* don't use notifiers because they are not 100% sure to succeeded
+ * this also makes sure all scenes are accounted for. */
+ {
+ Scene *scene;
+ for (scene = bmain->scenes.first; scene; scene = scene->id.next) {
+ if (scene->nodetree) {
+ nodeUpdateID(scene->nodetree, &ima->id);
+ }
+ }
+ }
}
/* return renderpass for a given pass index and active view */
/* fallback to available if there are missing passes for active view */
-static RenderPass *image_render_pass_get(RenderLayer *rl, const int pass, const int view, int *r_passindex)
-{
- RenderPass *rpass_ret = NULL;
- RenderPass *rpass;
-
- int rp_index = 0;
- const char *rp_name = "";
-
- for (rpass = rl->passes.first; rpass; rpass = rpass->next, rp_index++) {
- if (rp_index == pass) {
- rpass_ret = rpass;
- if (view == 0) {
- /* no multiview or left eye */
- break;
- }
- else {
- rp_name = rpass->name;
- }
- }
- /* multiview */
- else if (rp_name[0] &&
- STREQ(rpass->name, rp_name) &&
- (rpass->view_id == view))
- {
- rpass_ret = rpass;
- break;
- }
- }
-
- /* fallback to the first pass in the layer */
- if (rpass_ret == NULL) {
- rp_index = 0;
- rpass_ret = rl->passes.first;
- }
-
- if (r_passindex) {
- *r_passindex = (rpass == rpass_ret ? rp_index : pass);
- }
-
- return rpass_ret;
+static RenderPass *image_render_pass_get(RenderLayer *rl,
+ const int pass,
+ const int view,
+ int *r_passindex)
+{
+ RenderPass *rpass_ret = NULL;
+ RenderPass *rpass;
+
+ int rp_index = 0;
+ const char *rp_name = "";
+
+ for (rpass = rl->passes.first; rpass; rpass = rpass->next, rp_index++) {
+ if (rp_index == pass) {
+ rpass_ret = rpass;
+ if (view == 0) {
+ /* no multiview or left eye */
+ break;
+ }
+ else {
+ rp_name = rpass->name;
+ }
+ }
+ /* multiview */
+ else if (rp_name[0] && STREQ(rpass->name, rp_name) && (rpass->view_id == view)) {
+ rpass_ret = rpass;
+ break;
+ }
+ }
+
+ /* fallback to the first pass in the layer */
+ if (rpass_ret == NULL) {
+ rp_index = 0;
+ rpass_ret = rl->passes.first;
+ }
+
+ if (r_passindex) {
+ *r_passindex = (rpass == rpass_ret ? rp_index : pass);
+ }
+
+ return rpass_ret;
}
/* if layer or pass changes, we need an index for the imbufs list */
@@ -3032,51 +3225,53 @@ static RenderPass *image_render_pass_get(RenderLayer *rl, const int pass, const
/* and because rendered results use fake layer/passes, don't correct for wrong indices here */
RenderPass *BKE_image_multilayer_index(RenderResult *rr, ImageUser *iuser)
{
- RenderLayer *rl;
- RenderPass *rpass = NULL;
+ RenderLayer *rl;
+ RenderPass *rpass = NULL;
- if (rr == NULL)
- return NULL;
+ if (rr == NULL)
+ return NULL;
- if (iuser) {
- short index = 0, rv_index, rl_index = 0;
- bool is_stereo = (iuser->flag & IMA_SHOW_STEREO) && RE_RenderResult_is_stereo(rr);
+ if (iuser) {
+ short index = 0, rv_index, rl_index = 0;
+ bool is_stereo = (iuser->flag & IMA_SHOW_STEREO) && RE_RenderResult_is_stereo(rr);
- rv_index = is_stereo ? iuser->multiview_eye : iuser->view;
- if (RE_HasCombinedLayer(rr)) rl_index += 1;
+ rv_index = is_stereo ? iuser->multiview_eye : iuser->view;
+ if (RE_HasCombinedLayer(rr))
+ rl_index += 1;
- for (rl = rr->layers.first; rl; rl = rl->next, rl_index++) {
- if (iuser->layer == rl_index) {
- int rp_index;
- rpass = image_render_pass_get(rl, iuser->pass, rv_index, &rp_index);
- iuser->multi_index = index + rp_index;
- break;
- }
- else {
- index += BLI_listbase_count(&rl->passes);
- }
- }
- }
+ for (rl = rr->layers.first; rl; rl = rl->next, rl_index++) {
+ if (iuser->layer == rl_index) {
+ int rp_index;
+ rpass = image_render_pass_get(rl, iuser->pass, rv_index, &rp_index);
+ iuser->multi_index = index + rp_index;
+ break;
+ }
+ else {
+ index += BLI_listbase_count(&rl->passes);
+ }
+ }
+ }
- return rpass;
+ return rpass;
}
void BKE_image_multiview_index(Image *ima, ImageUser *iuser)
{
- if (iuser) {
- bool is_stereo = BKE_image_is_stereo(ima) && (iuser->flag & IMA_SHOW_STEREO);
- if (is_stereo) {
- iuser->multi_index = iuser->multiview_eye;
- }
- else {
- if ((iuser->view < 0) || (iuser->view >= BLI_listbase_count_at_most(&ima->views, iuser->view + 1))) {
- iuser->multi_index = iuser->view = 0;
- }
- else {
- iuser->multi_index = iuser->view;
- }
- }
- }
+ if (iuser) {
+ bool is_stereo = BKE_image_is_stereo(ima) && (iuser->flag & IMA_SHOW_STEREO);
+ if (is_stereo) {
+ iuser->multi_index = iuser->multiview_eye;
+ }
+ else {
+ if ((iuser->view < 0) ||
+ (iuser->view >= BLI_listbase_count_at_most(&ima->views, iuser->view + 1))) {
+ iuser->multi_index = iuser->view = 0;
+ }
+ else {
+ iuser->multi_index = iuser->view;
+ }
+ }
+ }
}
/* if layer or pass changes, we need an index for the imbufs list */
@@ -3084,170 +3279,169 @@ void BKE_image_multiview_index(Image *ima, ImageUser *iuser)
/* and because rendered results use fake layer/passes, don't correct for wrong indices here */
bool BKE_image_is_multilayer(Image *ima)
{
- if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_SEQUENCE)) {
- if (ima->type == IMA_TYPE_MULTILAYER) {
- return true;
- }
- }
- else if (ima->source == IMA_SRC_VIEWER) {
- if (ima->type == IMA_TYPE_R_RESULT) {
- return true;
- }
- }
- return false;
+ if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_SEQUENCE)) {
+ if (ima->type == IMA_TYPE_MULTILAYER) {
+ return true;
+ }
+ }
+ else if (ima->source == IMA_SRC_VIEWER) {
+ if (ima->type == IMA_TYPE_R_RESULT) {
+ return true;
+ }
+ }
+ return false;
}
bool BKE_image_is_multiview(Image *ima)
{
- ImageView *view = ima->views.first;
- return (view && (view->next || view->name[0]));
+ ImageView *view = ima->views.first;
+ return (view && (view->next || view->name[0]));
}
bool BKE_image_is_stereo(Image *ima)
{
- return BKE_image_is_multiview(ima) &&
- (BLI_findstring(&ima->views, STEREO_LEFT_NAME, offsetof(ImageView, name)) &&
- BLI_findstring(&ima->views, STEREO_RIGHT_NAME, offsetof(ImageView, name)));
+ return BKE_image_is_multiview(ima) &&
+ (BLI_findstring(&ima->views, STEREO_LEFT_NAME, offsetof(ImageView, name)) &&
+ BLI_findstring(&ima->views, STEREO_RIGHT_NAME, offsetof(ImageView, name)));
}
static void image_init_multilayer_multiview(Image *ima, RenderResult *rr)
{
- /* update image views from render views, but only if they actually changed,
- * to avoid invalid memory access during render. ideally these should always
- * be acquired with a mutex along with the render result, but there are still
- * some places with just an image pointer that need to access views */
- if (rr && BLI_listbase_count(&ima->views) == BLI_listbase_count(&rr->views)) {
- ImageView *iv = ima->views.first;
- RenderView *rv = rr->views.first;
- bool modified = false;
- for (; rv; rv = rv->next, iv = iv->next) {
- modified |= !STREQ(rv->name, iv->name);
- }
- if (!modified)
- return;
- }
-
- BKE_image_free_views(ima);
-
- if (rr) {
- for (RenderView *rv = rr->views.first; rv; rv = rv->next) {
- ImageView *iv = MEM_callocN(sizeof(ImageView), "Viewer Image View");
- STRNCPY(iv->name, rv->name);
- BLI_addtail(&ima->views, iv);
- }
- }
+ /* update image views from render views, but only if they actually changed,
+ * to avoid invalid memory access during render. ideally these should always
+ * be acquired with a mutex along with the render result, but there are still
+ * some places with just an image pointer that need to access views */
+ if (rr && BLI_listbase_count(&ima->views) == BLI_listbase_count(&rr->views)) {
+ ImageView *iv = ima->views.first;
+ RenderView *rv = rr->views.first;
+ bool modified = false;
+ for (; rv; rv = rv->next, iv = iv->next) {
+ modified |= !STREQ(rv->name, iv->name);
+ }
+ if (!modified)
+ return;
+ }
+
+ BKE_image_free_views(ima);
+
+ if (rr) {
+ for (RenderView *rv = rr->views.first; rv; rv = rv->next) {
+ ImageView *iv = MEM_callocN(sizeof(ImageView), "Viewer Image View");
+ STRNCPY(iv->name, rv->name);
+ BLI_addtail(&ima->views, iv);
+ }
+ }
}
-
RenderResult *BKE_image_acquire_renderresult(Scene *scene, Image *ima)
{
- RenderResult *rr = NULL;
- if (ima->rr) {
- rr = ima->rr;
- }
- else if (ima->type == IMA_TYPE_R_RESULT) {
- if (ima->render_slot == ima->last_render_slot)
- rr = RE_AcquireResultRead(RE_GetSceneRender(scene));
- else
- rr = BKE_image_get_renderslot(ima, ima->render_slot)->render;
+ RenderResult *rr = NULL;
+ if (ima->rr) {
+ rr = ima->rr;
+ }
+ else if (ima->type == IMA_TYPE_R_RESULT) {
+ if (ima->render_slot == ima->last_render_slot)
+ rr = RE_AcquireResultRead(RE_GetSceneRender(scene));
+ else
+ rr = BKE_image_get_renderslot(ima, ima->render_slot)->render;
- /* set proper views */
- image_init_multilayer_multiview(ima, rr);
- }
+ /* set proper views */
+ image_init_multilayer_multiview(ima, rr);
+ }
- return rr;
+ return rr;
}
void BKE_image_release_renderresult(Scene *scene, Image *ima)
{
- if (ima->rr) {
- /* pass */
- }
- else if (ima->type == IMA_TYPE_R_RESULT) {
- if (ima->render_slot == ima->last_render_slot)
- RE_ReleaseResult(RE_GetSceneRender(scene));
- }
+ if (ima->rr) {
+ /* pass */
+ }
+ else if (ima->type == IMA_TYPE_R_RESULT) {
+ if (ima->render_slot == ima->last_render_slot)
+ RE_ReleaseResult(RE_GetSceneRender(scene));
+ }
}
bool BKE_image_is_openexr(struct Image *ima)
{
#ifdef WITH_OPENEXR
- if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_SEQUENCE)) {
- return BLI_path_extension_check(ima->name, ".exr");
- }
+ if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_SEQUENCE)) {
+ return BLI_path_extension_check(ima->name, ".exr");
+ }
#else
- UNUSED_VARS(ima);
+ UNUSED_VARS(ima);
#endif
- return false;
+ return false;
}
void BKE_image_backup_render(Scene *scene, Image *ima, bool free_current_slot)
{
- /* called right before rendering, ima->renderslots contains render
- * result pointers for everything but the current render */
- Render *re = RE_GetSceneRender(scene);
-
- /* Ensure we always have a valid render slot. */
- if (!ima->renderslots.first) {
- BKE_image_add_renderslot(ima, NULL);
- ima->render_slot = 0;
- ima->last_render_slot = 0;
- }
- else if (ima->render_slot >= BLI_listbase_count(&ima->renderslots)) {
- ima->render_slot = 0;
- ima->last_render_slot = 0;
- }
-
- RenderSlot *last_slot = BKE_image_get_renderslot(ima, ima->last_render_slot);
- RenderSlot *cur_slot = BKE_image_get_renderslot(ima, ima->render_slot);
-
- if (last_slot && ima->render_slot != ima->last_render_slot) {
- last_slot->render = NULL;
- RE_SwapResult(re, &last_slot->render);
-
- if (cur_slot->render) {
- if (free_current_slot) {
- BKE_image_clear_renderslot(ima, NULL, ima->render_slot);
- }
- else {
- RE_SwapResult(re, &cur_slot->render);
- }
- }
- }
-
- ima->last_render_slot = ima->render_slot;
+ /* called right before rendering, ima->renderslots contains render
+ * result pointers for everything but the current render */
+ Render *re = RE_GetSceneRender(scene);
+
+ /* Ensure we always have a valid render slot. */
+ if (!ima->renderslots.first) {
+ BKE_image_add_renderslot(ima, NULL);
+ ima->render_slot = 0;
+ ima->last_render_slot = 0;
+ }
+ else if (ima->render_slot >= BLI_listbase_count(&ima->renderslots)) {
+ ima->render_slot = 0;
+ ima->last_render_slot = 0;
+ }
+
+ RenderSlot *last_slot = BKE_image_get_renderslot(ima, ima->last_render_slot);
+ RenderSlot *cur_slot = BKE_image_get_renderslot(ima, ima->render_slot);
+
+ if (last_slot && ima->render_slot != ima->last_render_slot) {
+ last_slot->render = NULL;
+ RE_SwapResult(re, &last_slot->render);
+
+ if (cur_slot->render) {
+ if (free_current_slot) {
+ BKE_image_clear_renderslot(ima, NULL, ima->render_slot);
+ }
+ else {
+ RE_SwapResult(re, &cur_slot->render);
+ }
+ }
+ }
+
+ ima->last_render_slot = ima->render_slot;
}
/**************************** multiview load openexr *********************************/
static void image_add_view(Image *ima, const char *viewname, const char *filepath)
{
- ImageView *iv;
+ ImageView *iv;
- iv = MEM_mallocN(sizeof(ImageView), "Viewer Image View");
- STRNCPY(iv->name, viewname);
- STRNCPY(iv->filepath, filepath);
+ iv = MEM_mallocN(sizeof(ImageView), "Viewer Image View");
+ STRNCPY(iv->name, viewname);
+ STRNCPY(iv->filepath, filepath);
- /* For stereo drawing we need to ensure:
- * STEREO_LEFT_NAME == STEREO_LEFT_ID and
- * STEREO_RIGHT_NAME == STEREO_RIGHT_ID */
+ /* For stereo drawing we need to ensure:
+ * STEREO_LEFT_NAME == STEREO_LEFT_ID and
+ * STEREO_RIGHT_NAME == STEREO_RIGHT_ID */
- if (STREQ(viewname, STEREO_LEFT_NAME)) {
- BLI_addhead(&ima->views, iv);
- }
- else if (STREQ(viewname, STEREO_RIGHT_NAME)) {
- ImageView *left_iv = BLI_findstring(&ima->views, STEREO_LEFT_NAME, offsetof(ImageView, name));
+ if (STREQ(viewname, STEREO_LEFT_NAME)) {
+ BLI_addhead(&ima->views, iv);
+ }
+ else if (STREQ(viewname, STEREO_RIGHT_NAME)) {
+ ImageView *left_iv = BLI_findstring(&ima->views, STEREO_LEFT_NAME, offsetof(ImageView, name));
- if (left_iv == NULL) {
- BLI_addhead(&ima->views, iv);
- }
- else {
- BLI_insertlinkafter(&ima->views, left_iv, iv);
- }
- }
- else {
- BLI_addtail(&ima->views, iv);
- }
+ if (left_iv == NULL) {
+ BLI_addhead(&ima->views, iv);
+ }
+ else {
+ BLI_insertlinkafter(&ima->views, left_iv, iv);
+ }
+ }
+ else {
+ BLI_addtail(&ima->views, iv);
+ }
}
/* after imbuf load, openexr type can return with a exrhandle open */
@@ -3255,431 +3449,430 @@ static void image_add_view(Image *ima, const char *viewname, const char *filepat
#ifdef WITH_OPENEXR
static void image_create_multilayer(Image *ima, ImBuf *ibuf, int framenr)
{
- const char *colorspace = ima->colorspace_settings.name;
- bool predivide = (ima->alpha_mode == IMA_ALPHA_PREMUL);
+ const char *colorspace = ima->colorspace_settings.name;
+ bool predivide = (ima->alpha_mode == IMA_ALPHA_PREMUL);
- /* only load rr once for multiview */
- if (!ima->rr)
- ima->rr = RE_MultilayerConvert(ibuf->userdata, colorspace, predivide, ibuf->x, ibuf->y);
+ /* only load rr once for multiview */
+ if (!ima->rr)
+ ima->rr = RE_MultilayerConvert(ibuf->userdata, colorspace, predivide, ibuf->x, ibuf->y);
- IMB_exr_close(ibuf->userdata);
+ IMB_exr_close(ibuf->userdata);
- ibuf->userdata = NULL;
- if (ima->rr != NULL) {
- ima->rr->framenr = framenr;
- BKE_stamp_info_from_imbuf(ima->rr, ibuf);
- }
+ ibuf->userdata = NULL;
+ if (ima->rr != NULL) {
+ ima->rr->framenr = framenr;
+ BKE_stamp_info_from_imbuf(ima->rr, ibuf);
+ }
- /* set proper views */
- image_init_multilayer_multiview(ima, ima->rr);
+ /* set proper views */
+ image_init_multilayer_multiview(ima, ima->rr);
}
-#endif /* WITH_OPENEXR */
+#endif /* WITH_OPENEXR */
/* common stuff to do with images after loading */
static void image_initialize_after_load(Image *ima, ImBuf *UNUSED(ibuf))
{
- /* Preview is NULL when it has never been used as an icon before.
- * Never handle previews/icons outside of main thread. */
- if (G.background == 0 && ima->preview == NULL && BLI_thread_is_main()) {
- BKE_icon_changed(BKE_icon_id_ensure(&ima->id));
- }
+ /* Preview is NULL when it has never been used as an icon before.
+ * Never handle previews/icons outside of main thread. */
+ if (G.background == 0 && ima->preview == NULL && BLI_thread_is_main()) {
+ BKE_icon_changed(BKE_icon_id_ensure(&ima->id));
+ }
- /* timer */
- BKE_image_tag_time(ima);
-
- ima->ok = IMA_OK_LOADED;
+ /* timer */
+ BKE_image_tag_time(ima);
+ ima->ok = IMA_OK_LOADED;
}
static int imbuf_alpha_flags_for_image(Image *ima)
{
- int flag = 0;
+ int flag = 0;
- if (ima->flag & IMA_IGNORE_ALPHA)
- flag |= IB_ignore_alpha;
- else if (ima->alpha_mode == IMA_ALPHA_PREMUL)
- flag |= IB_alphamode_premul;
+ if (ima->flag & IMA_IGNORE_ALPHA)
+ flag |= IB_ignore_alpha;
+ else if (ima->alpha_mode == IMA_ALPHA_PREMUL)
+ flag |= IB_alphamode_premul;
- return flag;
+ return flag;
}
/* the number of files will vary according to the stereo format */
static int image_num_files(Image *ima)
{
- const bool is_multiview = BKE_image_is_multiview(ima);
+ const bool is_multiview = BKE_image_is_multiview(ima);
- if (!is_multiview) {
- return 1;
- }
- else if (ima->views_format == R_IMF_VIEWS_STEREO_3D) {
- return 1;
- }
- /* R_IMF_VIEWS_INDIVIDUAL */
- else {
- return BLI_listbase_count(&ima->views);
- }
+ if (!is_multiview) {
+ return 1;
+ }
+ else if (ima->views_format == R_IMF_VIEWS_STEREO_3D) {
+ return 1;
+ }
+ /* R_IMF_VIEWS_INDIVIDUAL */
+ else {
+ return BLI_listbase_count(&ima->views);
+ }
}
-static ImBuf *load_sequence_single(Image *ima, ImageUser *iuser, int frame, const int view_id, bool *r_assign)
+static ImBuf *load_sequence_single(
+ Image *ima, ImageUser *iuser, int frame, const int view_id, bool *r_assign)
{
- struct ImBuf *ibuf;
- char name[FILE_MAX];
- int flag;
- ImageUser iuser_t = {0};
+ struct ImBuf *ibuf;
+ char name[FILE_MAX];
+ int flag;
+ ImageUser iuser_t = {0};
- ima->lastframe = frame;
+ ima->lastframe = frame;
- if (iuser) {
- iuser_t = *iuser;
- }
- else {
- /* TODO(sergey): Do we need to initialize something here? */
- }
+ if (iuser) {
+ iuser_t = *iuser;
+ }
+ else {
+ /* TODO(sergey): Do we need to initialize something here? */
+ }
- iuser_t.view = view_id;
- BKE_image_user_file_path(&iuser_t, ima, name);
+ iuser_t.view = view_id;
+ BKE_image_user_file_path(&iuser_t, ima, name);
- flag = IB_rect | IB_multilayer | IB_metadata;
- flag |= imbuf_alpha_flags_for_image(ima);
+ flag = IB_rect | IB_multilayer | IB_metadata;
+ flag |= imbuf_alpha_flags_for_image(ima);
- /* read ibuf */
- ibuf = IMB_loadiffname(name, flag, ima->colorspace_settings.name);
+ /* read ibuf */
+ ibuf = IMB_loadiffname(name, flag, ima->colorspace_settings.name);
#if 0
- if (ibuf) {
- printf(AT " loaded %s\n", name);
- }
- else {
- printf(AT " missed %s\n", name);
- }
+ if (ibuf) {
+ printf(AT " loaded %s\n", name);
+ }
+ else {
+ printf(AT " missed %s\n", name);
+ }
#endif
- if (ibuf) {
+ if (ibuf) {
#ifdef WITH_OPENEXR
- if (ibuf->ftype == IMB_FTYPE_OPENEXR && ibuf->userdata) {
- /* Handle multilayer and multiview cases, don't assign ibuf here.
- * will be set layer in BKE_image_acquire_ibuf from ima->rr. */
- if (IMB_exr_has_multilayer(ibuf->userdata)) {
- image_create_multilayer(ima, ibuf, frame);
- ima->type = IMA_TYPE_MULTILAYER;
- IMB_freeImBuf(ibuf);
- ibuf = NULL;
- }
- }
- else {
- image_initialize_after_load(ima, ibuf);
- *r_assign = true;
- }
+ if (ibuf->ftype == IMB_FTYPE_OPENEXR && ibuf->userdata) {
+ /* Handle multilayer and multiview cases, don't assign ibuf here.
+ * will be set layer in BKE_image_acquire_ibuf from ima->rr. */
+ if (IMB_exr_has_multilayer(ibuf->userdata)) {
+ image_create_multilayer(ima, ibuf, frame);
+ ima->type = IMA_TYPE_MULTILAYER;
+ IMB_freeImBuf(ibuf);
+ ibuf = NULL;
+ }
+ }
+ else {
+ image_initialize_after_load(ima, ibuf);
+ *r_assign = true;
+ }
#else
- image_initialize_after_load(ima, ibuf);
- *r_assign = true;
+ image_initialize_after_load(ima, ibuf);
+ *r_assign = true;
#endif
- }
+ }
- return ibuf;
+ return ibuf;
}
static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame)
{
- struct ImBuf *ibuf = NULL;
- const bool is_multiview = BKE_image_is_multiview(ima);
- const int totfiles = image_num_files(ima);
- bool assign = false;
+ struct ImBuf *ibuf = NULL;
+ const bool is_multiview = BKE_image_is_multiview(ima);
+ const int totfiles = image_num_files(ima);
+ bool assign = false;
- if (!is_multiview) {
- ibuf = load_sequence_single(ima, iuser, frame, 0, &assign);
- if (assign) {
- image_assign_ibuf(ima, ibuf, 0, frame);
- }
- }
- else {
- const int totviews = BLI_listbase_count(&ima->views);
- int i;
- struct ImBuf **ibuf_arr;
+ if (!is_multiview) {
+ ibuf = load_sequence_single(ima, iuser, frame, 0, &assign);
+ if (assign) {
+ image_assign_ibuf(ima, ibuf, 0, frame);
+ }
+ }
+ else {
+ const int totviews = BLI_listbase_count(&ima->views);
+ int i;
+ struct ImBuf **ibuf_arr;
- ibuf_arr = MEM_mallocN(sizeof(ImBuf *) * totviews, "Image Views Imbufs");
+ ibuf_arr = MEM_mallocN(sizeof(ImBuf *) * totviews, "Image Views Imbufs");
- for (i = 0; i < totfiles; i++)
- ibuf_arr[i] = load_sequence_single(ima, iuser, frame, i, &assign);
+ for (i = 0; i < totfiles; i++)
+ ibuf_arr[i] = load_sequence_single(ima, iuser, frame, i, &assign);
- if (BKE_image_is_stereo(ima) && ima->views_format == R_IMF_VIEWS_STEREO_3D)
- IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]);
+ if (BKE_image_is_stereo(ima) && ima->views_format == R_IMF_VIEWS_STEREO_3D)
+ IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]);
- /* return the original requested ImBuf */
- ibuf = ibuf_arr[(iuser ? iuser->multi_index : 0)];
+ /* return the original requested ImBuf */
+ ibuf = ibuf_arr[(iuser ? iuser->multi_index : 0)];
- if (assign) {
- for (i = 0; i < totviews; i++) {
- image_assign_ibuf(ima, ibuf_arr[i], i, frame);
- }
- }
+ if (assign) {
+ for (i = 0; i < totviews; i++) {
+ image_assign_ibuf(ima, ibuf_arr[i], i, frame);
+ }
+ }
- /* "remove" the others (decrease their refcount) */
- for (i = 0; i < totviews; i++) {
- if (ibuf_arr[i] != ibuf) {
- IMB_freeImBuf(ibuf_arr[i]);
- }
- }
+ /* "remove" the others (decrease their refcount) */
+ for (i = 0; i < totviews; i++) {
+ if (ibuf_arr[i] != ibuf) {
+ IMB_freeImBuf(ibuf_arr[i]);
+ }
+ }
- /* cleanup */
- MEM_freeN(ibuf_arr);
- }
+ /* cleanup */
+ MEM_freeN(ibuf_arr);
+ }
- return ibuf;
+ return ibuf;
}
static ImBuf *image_load_sequence_multilayer(Image *ima, ImageUser *iuser, int frame)
{
- struct ImBuf *ibuf = NULL;
-
- /* either we load from RenderResult, or we have to load a new one */
-
- /* check for new RenderResult */
- if (ima->rr == NULL || frame != ima->rr->framenr) {
- if (ima->rr) {
- /* Cached image buffers shares pointers with render result,
- * need to ensure there's no image buffers are hanging around
- * with dead links after freeing the render result.
- */
- image_free_cached_frames(ima);
- RE_FreeRenderResult(ima->rr);
- ima->rr = NULL;
- }
-
- ibuf = image_load_sequence_file(ima, iuser, frame);
-
- if (ibuf) { /* actually an error */
- ima->type = IMA_TYPE_IMAGE;
- printf("error, multi is normal image\n");
- }
- }
- if (ima->rr) {
- RenderPass *rpass = BKE_image_multilayer_index(ima->rr, iuser);
-
- if (rpass) {
- // printf("load from pass %s\n", rpass->name);
- /* since we free render results, we copy the rect */
- ibuf = IMB_allocImBuf(ima->rr->rectx, ima->rr->recty, 32, 0);
- ibuf->rect_float = MEM_dupallocN(rpass->rect);
- ibuf->flags |= IB_rectfloat;
- ibuf->mall = IB_rectfloat;
- ibuf->channels = rpass->channels;
-
- BKE_imbuf_stamp_info(ima->rr, ibuf);
-
- image_initialize_after_load(ima, ibuf);
- image_assign_ibuf(ima, ibuf, iuser ? iuser->multi_index : 0, frame);
-
- }
- // else printf("pass not found\n");
- }
- else
- ima->ok = 0;
-
- if (iuser)
- iuser->ok = ima->ok;
-
- return ibuf;
+ struct ImBuf *ibuf = NULL;
+
+ /* either we load from RenderResult, or we have to load a new one */
+
+ /* check for new RenderResult */
+ if (ima->rr == NULL || frame != ima->rr->framenr) {
+ if (ima->rr) {
+ /* Cached image buffers shares pointers with render result,
+ * need to ensure there's no image buffers are hanging around
+ * with dead links after freeing the render result.
+ */
+ image_free_cached_frames(ima);
+ RE_FreeRenderResult(ima->rr);
+ ima->rr = NULL;
+ }
+
+ ibuf = image_load_sequence_file(ima, iuser, frame);
+
+ if (ibuf) { /* actually an error */
+ ima->type = IMA_TYPE_IMAGE;
+ printf("error, multi is normal image\n");
+ }
+ }
+ if (ima->rr) {
+ RenderPass *rpass = BKE_image_multilayer_index(ima->rr, iuser);
+
+ if (rpass) {
+ // printf("load from pass %s\n", rpass->name);
+ /* since we free render results, we copy the rect */
+ ibuf = IMB_allocImBuf(ima->rr->rectx, ima->rr->recty, 32, 0);
+ ibuf->rect_float = MEM_dupallocN(rpass->rect);
+ ibuf->flags |= IB_rectfloat;
+ ibuf->mall = IB_rectfloat;
+ ibuf->channels = rpass->channels;
+
+ BKE_imbuf_stamp_info(ima->rr, ibuf);
+
+ image_initialize_after_load(ima, ibuf);
+ image_assign_ibuf(ima, ibuf, iuser ? iuser->multi_index : 0, frame);
+ }
+ // else printf("pass not found\n");
+ }
+ else
+ ima->ok = 0;
+
+ if (iuser)
+ iuser->ok = ima->ok;
+
+ return ibuf;
}
static ImBuf *load_movie_single(Image *ima, ImageUser *iuser, int frame, const int view_id)
{
- struct ImBuf *ibuf = NULL;
- ImageAnim *ia;
+ struct ImBuf *ibuf = NULL;
+ ImageAnim *ia;
- ia = BLI_findlink(&ima->anims, view_id);
+ ia = BLI_findlink(&ima->anims, view_id);
- if (ia->anim == NULL) {
- char str[FILE_MAX];
- int flags = IB_rect;
- ImageUser iuser_t;
+ if (ia->anim == NULL) {
+ char str[FILE_MAX];
+ int flags = IB_rect;
+ ImageUser iuser_t;
- if (ima->flag & IMA_DEINTERLACE) {
- flags |= IB_animdeinterlace;
- }
+ if (ima->flag & IMA_DEINTERLACE) {
+ flags |= IB_animdeinterlace;
+ }
- if (iuser)
- iuser_t = *iuser;
+ if (iuser)
+ iuser_t = *iuser;
- iuser_t.view = view_id;
+ iuser_t.view = view_id;
- BKE_image_user_file_path(&iuser_t, ima, str);
+ BKE_image_user_file_path(&iuser_t, ima, str);
- /* FIXME: make several stream accessible in image editor, too*/
- ia->anim = openanim(str, flags, 0, ima->colorspace_settings.name);
+ /* FIXME: make several stream accessible in image editor, too*/
+ ia->anim = openanim(str, flags, 0, ima->colorspace_settings.name);
- /* let's initialize this user */
- if (ia->anim && iuser && iuser->frames == 0)
- iuser->frames = IMB_anim_get_duration(ia->anim,
- IMB_TC_RECORD_RUN);
- }
+ /* let's initialize this user */
+ if (ia->anim && iuser && iuser->frames == 0)
+ iuser->frames = IMB_anim_get_duration(ia->anim, IMB_TC_RECORD_RUN);
+ }
- if (ia->anim) {
- int dur = IMB_anim_get_duration(ia->anim,
- IMB_TC_RECORD_RUN);
- int fra = frame - 1;
+ if (ia->anim) {
+ int dur = IMB_anim_get_duration(ia->anim, IMB_TC_RECORD_RUN);
+ int fra = frame - 1;
- if (fra < 0) fra = 0;
- if (fra > (dur - 1)) fra = dur - 1;
- ibuf = IMB_makeSingleUser(
- IMB_anim_absolute(ia->anim, fra,
- IMB_TC_RECORD_RUN,
- IMB_PROXY_NONE));
+ if (fra < 0)
+ fra = 0;
+ if (fra > (dur - 1))
+ fra = dur - 1;
+ ibuf = IMB_makeSingleUser(IMB_anim_absolute(ia->anim, fra, IMB_TC_RECORD_RUN, IMB_PROXY_NONE));
- if (ibuf) {
- image_initialize_after_load(ima, ibuf);
- }
- else
- ima->ok = 0;
- }
- else
- ima->ok = 0;
+ if (ibuf) {
+ image_initialize_after_load(ima, ibuf);
+ }
+ else
+ ima->ok = 0;
+ }
+ else
+ ima->ok = 0;
- return ibuf;
+ return ibuf;
}
static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame)
{
- struct ImBuf *ibuf = NULL;
- const bool is_multiview = BKE_image_is_multiview(ima);
- const int totfiles = image_num_files(ima);
- int i;
-
- if (totfiles != BLI_listbase_count_at_most(&ima->anims, totfiles + 1)) {
- image_free_anims(ima);
-
- for (i = 0; i < totfiles; i++) {
- /* allocate the ImageAnim */
- ImageAnim *ia = MEM_callocN(sizeof(ImageAnim), "Image Anim");
- BLI_addtail(&ima->anims, ia);
- }
- }
-
- if (!is_multiview) {
- ibuf = load_movie_single(ima, iuser, frame, 0);
- image_assign_ibuf(ima, ibuf, 0, frame);
- }
- else {
- struct ImBuf **ibuf_arr;
- const int totviews = BLI_listbase_count(&ima->views);
-
- ibuf_arr = MEM_mallocN(sizeof(ImBuf *) * totviews, "Image Views (movie) Imbufs");
-
- for (i = 0; i < totfiles; i++) {
- ibuf_arr[i] = load_movie_single(ima, iuser, frame, i);
- }
-
- if (BKE_image_is_stereo(ima) && ima->views_format == R_IMF_VIEWS_STEREO_3D)
- IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]);
-
- for (i = 0; i < totviews; i++) {
- if (ibuf_arr[i]) {
- image_assign_ibuf(ima, ibuf_arr[i], i, frame);
- }
- else {
- ima->ok = 0;
- }
- }
-
- /* return the original requested ImBuf */
- ibuf = ibuf_arr[(iuser ? iuser->multi_index : 0)];
-
- /* "remove" the others (decrease their refcount) */
- for (i = 0; i < totviews; i++) {
- if (ibuf_arr[i] != ibuf) {
- IMB_freeImBuf(ibuf_arr[i]);
- }
- }
-
- /* cleanup */
- MEM_freeN(ibuf_arr);
- }
-
- if (iuser)
- iuser->ok = ima->ok;
-
- return ibuf;
-}
-
-static ImBuf *load_image_single(
- Image *ima, ImageUser *iuser, int cfra,
- const int view_id,
- const bool has_packed,
- bool *r_assign)
-{
- char filepath[FILE_MAX];
- struct ImBuf *ibuf = NULL;
- int flag;
-
- /* is there a PackedFile with this image ? */
- if (has_packed) {
- ImagePackedFile *imapf;
-
- flag = IB_rect | IB_multilayer;
- flag |= imbuf_alpha_flags_for_image(ima);
-
- imapf = BLI_findlink(&ima->packedfiles, view_id);
- if (imapf->packedfile) {
- ibuf = IMB_ibImageFromMemory(
- (unsigned char *)imapf->packedfile->data, imapf->packedfile->size, flag,
- ima->colorspace_settings.name, "<packed data>");
- }
- }
- else {
- ImageUser iuser_t;
-
- flag = IB_rect | IB_multilayer | IB_metadata;
- flag |= imbuf_alpha_flags_for_image(ima);
-
- /* get the correct filepath */
- BKE_image_user_frame_calc(iuser, cfra);
-
- if (iuser)
- iuser_t = *iuser;
- else
- iuser_t.framenr = ima->lastframe;
-
- iuser_t.view = view_id;
-
- BKE_image_user_file_path(&iuser_t, ima, filepath);
-
- /* read ibuf */
- ibuf = IMB_loadiffname(filepath, flag, ima->colorspace_settings.name);
- }
-
- if (ibuf) {
+ struct ImBuf *ibuf = NULL;
+ const bool is_multiview = BKE_image_is_multiview(ima);
+ const int totfiles = image_num_files(ima);
+ int i;
+
+ if (totfiles != BLI_listbase_count_at_most(&ima->anims, totfiles + 1)) {
+ image_free_anims(ima);
+
+ for (i = 0; i < totfiles; i++) {
+ /* allocate the ImageAnim */
+ ImageAnim *ia = MEM_callocN(sizeof(ImageAnim), "Image Anim");
+ BLI_addtail(&ima->anims, ia);
+ }
+ }
+
+ if (!is_multiview) {
+ ibuf = load_movie_single(ima, iuser, frame, 0);
+ image_assign_ibuf(ima, ibuf, 0, frame);
+ }
+ else {
+ struct ImBuf **ibuf_arr;
+ const int totviews = BLI_listbase_count(&ima->views);
+
+ ibuf_arr = MEM_mallocN(sizeof(ImBuf *) * totviews, "Image Views (movie) Imbufs");
+
+ for (i = 0; i < totfiles; i++) {
+ ibuf_arr[i] = load_movie_single(ima, iuser, frame, i);
+ }
+
+ if (BKE_image_is_stereo(ima) && ima->views_format == R_IMF_VIEWS_STEREO_3D)
+ IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]);
+
+ for (i = 0; i < totviews; i++) {
+ if (ibuf_arr[i]) {
+ image_assign_ibuf(ima, ibuf_arr[i], i, frame);
+ }
+ else {
+ ima->ok = 0;
+ }
+ }
+
+ /* return the original requested ImBuf */
+ ibuf = ibuf_arr[(iuser ? iuser->multi_index : 0)];
+
+ /* "remove" the others (decrease their refcount) */
+ for (i = 0; i < totviews; i++) {
+ if (ibuf_arr[i] != ibuf) {
+ IMB_freeImBuf(ibuf_arr[i]);
+ }
+ }
+
+ /* cleanup */
+ MEM_freeN(ibuf_arr);
+ }
+
+ if (iuser)
+ iuser->ok = ima->ok;
+
+ return ibuf;
+}
+
+static ImBuf *load_image_single(Image *ima,
+ ImageUser *iuser,
+ int cfra,
+ const int view_id,
+ const bool has_packed,
+ bool *r_assign)
+{
+ char filepath[FILE_MAX];
+ struct ImBuf *ibuf = NULL;
+ int flag;
+
+ /* is there a PackedFile with this image ? */
+ if (has_packed) {
+ ImagePackedFile *imapf;
+
+ flag = IB_rect | IB_multilayer;
+ flag |= imbuf_alpha_flags_for_image(ima);
+
+ imapf = BLI_findlink(&ima->packedfiles, view_id);
+ if (imapf->packedfile) {
+ ibuf = IMB_ibImageFromMemory((unsigned char *)imapf->packedfile->data,
+ imapf->packedfile->size,
+ flag,
+ ima->colorspace_settings.name,
+ "<packed data>");
+ }
+ }
+ else {
+ ImageUser iuser_t;
+
+ flag = IB_rect | IB_multilayer | IB_metadata;
+ flag |= imbuf_alpha_flags_for_image(ima);
+
+ /* get the correct filepath */
+ BKE_image_user_frame_calc(iuser, cfra);
+
+ if (iuser)
+ iuser_t = *iuser;
+ else
+ iuser_t.framenr = ima->lastframe;
+
+ iuser_t.view = view_id;
+
+ BKE_image_user_file_path(&iuser_t, ima, filepath);
+
+ /* read ibuf */
+ ibuf = IMB_loadiffname(filepath, flag, ima->colorspace_settings.name);
+ }
+
+ if (ibuf) {
#ifdef WITH_OPENEXR
- if (ibuf->ftype == IMB_FTYPE_OPENEXR && ibuf->userdata) {
- /* Handle multilayer and multiview cases, don't assign ibuf here.
- * will be set layer in BKE_image_acquire_ibuf from ima->rr. */
- if (IMB_exr_has_multilayer(ibuf->userdata)) {
- image_create_multilayer(ima, ibuf, cfra);
- ima->type = IMA_TYPE_MULTILAYER;
- IMB_freeImBuf(ibuf);
- ibuf = NULL;
- }
- }
- else
+ if (ibuf->ftype == IMB_FTYPE_OPENEXR && ibuf->userdata) {
+ /* Handle multilayer and multiview cases, don't assign ibuf here.
+ * will be set layer in BKE_image_acquire_ibuf from ima->rr. */
+ if (IMB_exr_has_multilayer(ibuf->userdata)) {
+ image_create_multilayer(ima, ibuf, cfra);
+ ima->type = IMA_TYPE_MULTILAYER;
+ IMB_freeImBuf(ibuf);
+ ibuf = NULL;
+ }
+ }
+ else
#endif
- {
- image_initialize_after_load(ima, ibuf);
- *r_assign = true;
+ {
+ image_initialize_after_load(ima, ibuf);
+ *r_assign = true;
- /* make packed file for autopack */
- if ((has_packed == false) && (G.fileflags & G_FILE_AUTOPACK)) {
- ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image Packefile");
- BLI_addtail(&ima->packedfiles, imapf);
+ /* make packed file for autopack */
+ if ((has_packed == false) && (G.fileflags & G_FILE_AUTOPACK)) {
+ ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image Packefile");
+ BLI_addtail(&ima->packedfiles, imapf);
- STRNCPY(imapf->filepath, filepath);
- imapf->packedfile = newPackedFile(NULL, filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id));
- }
- }
- }
- else {
- ima->ok = 0;
- }
+ STRNCPY(imapf->filepath, filepath);
+ imapf->packedfile = newPackedFile(NULL, filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id));
+ }
+ }
+ }
+ else {
+ ima->ok = 0;
+ }
- return ibuf;
+ return ibuf;
}
/* warning, 'iuser' can be NULL
@@ -3687,358 +3880,357 @@ static ImBuf *load_image_single(
*/
static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra)
{
- struct ImBuf *ibuf = NULL;
- bool assign = false;
- const bool is_multiview = BKE_image_is_multiview(ima);
- const int totfiles = image_num_files(ima);
- bool has_packed = BKE_image_has_packedfile(ima);
-
- /* always ensure clean ima */
- BKE_image_free_buffers(ima);
-
- /* this should never happen, but just playing safe */
- if (has_packed) {
- if (totfiles != BLI_listbase_count_at_most(&ima->packedfiles, totfiles + 1)) {
- image_free_packedfiles(ima);
- has_packed = false;
- }
- }
-
- if (!is_multiview) {
- ibuf = load_image_single(ima, iuser, cfra, 0, has_packed, &assign);
- if (assign) {
- image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
- }
- }
- else {
- struct ImBuf **ibuf_arr;
- const int totviews = BLI_listbase_count(&ima->views);
- int i;
- BLI_assert(totviews > 0);
-
- ibuf_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Image Views Imbufs");
-
- for (i = 0; i < totfiles; i++)
- ibuf_arr[i] = load_image_single(ima, iuser, cfra, i, has_packed, &assign);
-
- /* multi-views/multi-layers OpenEXR files directly populate ima, and return NULL ibuf... */
- if (BKE_image_is_stereo(ima) && ima->views_format == R_IMF_VIEWS_STEREO_3D &&
- ibuf_arr[0] && totfiles == 1 && totviews >= 2)
- {
- IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]);
- }
-
- /* return the original requested ImBuf */
- i = (iuser && iuser->multi_index < totviews) ? iuser->multi_index : 0;
- ibuf = ibuf_arr[i];
-
- if (assign) {
- for (i = 0; i < totviews; i++) {
- image_assign_ibuf(ima, ibuf_arr[i], i, 0);
- }
- }
-
- /* "remove" the others (decrease their refcount) */
- for (i = 0; i < totviews; i++) {
- if (ibuf_arr[i] != ibuf) {
- IMB_freeImBuf(ibuf_arr[i]);
- }
- }
-
- /* cleanup */
- MEM_freeN(ibuf_arr);
- }
-
- if (iuser)
- iuser->ok = ima->ok;
-
- return ibuf;
+ struct ImBuf *ibuf = NULL;
+ bool assign = false;
+ const bool is_multiview = BKE_image_is_multiview(ima);
+ const int totfiles = image_num_files(ima);
+ bool has_packed = BKE_image_has_packedfile(ima);
+
+ /* always ensure clean ima */
+ BKE_image_free_buffers(ima);
+
+ /* this should never happen, but just playing safe */
+ if (has_packed) {
+ if (totfiles != BLI_listbase_count_at_most(&ima->packedfiles, totfiles + 1)) {
+ image_free_packedfiles(ima);
+ has_packed = false;
+ }
+ }
+
+ if (!is_multiview) {
+ ibuf = load_image_single(ima, iuser, cfra, 0, has_packed, &assign);
+ if (assign) {
+ image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
+ }
+ }
+ else {
+ struct ImBuf **ibuf_arr;
+ const int totviews = BLI_listbase_count(&ima->views);
+ int i;
+ BLI_assert(totviews > 0);
+
+ ibuf_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Image Views Imbufs");
+
+ for (i = 0; i < totfiles; i++)
+ ibuf_arr[i] = load_image_single(ima, iuser, cfra, i, has_packed, &assign);
+
+ /* multi-views/multi-layers OpenEXR files directly populate ima, and return NULL ibuf... */
+ if (BKE_image_is_stereo(ima) && ima->views_format == R_IMF_VIEWS_STEREO_3D && ibuf_arr[0] &&
+ totfiles == 1 && totviews >= 2) {
+ IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]);
+ }
+
+ /* return the original requested ImBuf */
+ i = (iuser && iuser->multi_index < totviews) ? iuser->multi_index : 0;
+ ibuf = ibuf_arr[i];
+
+ if (assign) {
+ for (i = 0; i < totviews; i++) {
+ image_assign_ibuf(ima, ibuf_arr[i], i, 0);
+ }
+ }
+
+ /* "remove" the others (decrease their refcount) */
+ for (i = 0; i < totviews; i++) {
+ if (ibuf_arr[i] != ibuf) {
+ IMB_freeImBuf(ibuf_arr[i]);
+ }
+ }
+
+ /* cleanup */
+ MEM_freeN(ibuf_arr);
+ }
+
+ if (iuser)
+ iuser->ok = ima->ok;
+
+ return ibuf;
}
static ImBuf *image_get_ibuf_multilayer(Image *ima, ImageUser *iuser)
{
- ImBuf *ibuf = NULL;
+ ImBuf *ibuf = NULL;
- if (ima->rr == NULL) {
- ibuf = image_load_image_file(ima, iuser, 0);
- if (ibuf) { /* actually an error */
- ima->type = IMA_TYPE_IMAGE;
- return ibuf;
- }
- }
- if (ima->rr) {
- RenderPass *rpass = BKE_image_multilayer_index(ima->rr, iuser);
+ if (ima->rr == NULL) {
+ ibuf = image_load_image_file(ima, iuser, 0);
+ if (ibuf) { /* actually an error */
+ ima->type = IMA_TYPE_IMAGE;
+ return ibuf;
+ }
+ }
+ if (ima->rr) {
+ RenderPass *rpass = BKE_image_multilayer_index(ima->rr, iuser);
- if (rpass) {
- ibuf = IMB_allocImBuf(ima->rr->rectx, ima->rr->recty, 32, 0);
+ if (rpass) {
+ ibuf = IMB_allocImBuf(ima->rr->rectx, ima->rr->recty, 32, 0);
- image_initialize_after_load(ima, ibuf);
+ image_initialize_after_load(ima, ibuf);
- ibuf->rect_float = rpass->rect;
- ibuf->flags |= IB_rectfloat;
- ibuf->channels = rpass->channels;
+ ibuf->rect_float = rpass->rect;
+ ibuf->flags |= IB_rectfloat;
+ ibuf->channels = rpass->channels;
- BKE_imbuf_stamp_info(ima->rr, ibuf);
+ BKE_imbuf_stamp_info(ima->rr, ibuf);
- image_assign_ibuf(ima, ibuf, iuser ? iuser->multi_index : IMA_NO_INDEX, 0);
- }
- }
+ image_assign_ibuf(ima, ibuf, iuser ? iuser->multi_index : IMA_NO_INDEX, 0);
+ }
+ }
- if (ibuf == NULL)
- ima->ok = 0;
- if (iuser)
- iuser->ok = ima->ok;
+ if (ibuf == NULL)
+ ima->ok = 0;
+ if (iuser)
+ iuser->ok = ima->ok;
- return ibuf;
+ return ibuf;
}
-
/* showing RGBA result itself (from compo/sequence) or
* like exr, using layers etc */
/* always returns a single ibuf, also during render progress */
static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_lock)
{
- Render *re;
- RenderResult rres;
- RenderView *rv;
- float *rectf, *rectz;
- unsigned int *rect;
- float dither;
- int channels, layer, pass;
- ImBuf *ibuf;
- int from_render = (ima->render_slot == ima->last_render_slot);
- int actview;
- bool byte_buffer_in_display_space = false;
-
- if (!(iuser && iuser->scene))
- return NULL;
-
- /* if we the caller is not going to release the lock, don't give the image */
- if (!r_lock)
- return NULL;
-
- re = RE_GetSceneRender(iuser->scene);
-
- channels = 4;
- layer = iuser->layer;
- pass = iuser->pass;
- actview = iuser->view;
-
- if (BKE_image_is_stereo(ima) && (iuser->flag & IMA_SHOW_STEREO))
- actview = iuser->multiview_eye;
-
- RenderSlot *slot;
- if (from_render) {
- RE_AcquireResultImage(re, &rres, actview);
- }
- else if ((slot = BKE_image_get_renderslot(ima, ima->render_slot))->render) {
- rres = *(slot->render);
- rres.have_combined = ((RenderView *)rres.views.first)->rectf != NULL;
- }
- else
- memset(&rres, 0, sizeof(RenderResult));
-
- if (!(rres.rectx > 0 && rres.recty > 0)) {
- if (from_render)
- RE_ReleaseResultImage(re);
- return NULL;
- }
-
- /* release is done in BKE_image_release_ibuf using r_lock */
- if (from_render) {
- BLI_thread_lock(LOCK_VIEWER);
- *r_lock = re;
- rv = NULL;
- }
- else {
- rv = BLI_findlink(&rres.views, actview);
- if (rv == NULL)
- rv = rres.views.first;
- }
-
- /* this gives active layer, composite or sequence result */
- if (rv == NULL) {
- rect = (unsigned int *)rres.rect32;
- rectf = rres.rectf;
- rectz = rres.rectz;
- }
- else {
- rect = (unsigned int *)rv->rect32;
- rectf = rv->rectf;
- rectz = rv->rectz;
- }
-
- dither = iuser->scene->r.dither_intensity;
-
- /* combined layer gets added as first layer */
- if (rres.have_combined && layer == 0) {
- /* pass */
- }
- else if (rect && layer == 0) {
- /* rect32 is set when there's a Sequence pass, this pass seems
- * to have layer=0 (this is from image_buttons.c)
- * in this case we ignore float buffer, because it could have
- * hung from previous pass which was float
- */
- rectf = NULL;
- }
- else if (rres.layers.first) {
- RenderLayer *rl = BLI_findlink(&rres.layers, layer - (rres.have_combined ? 1 : 0));
- if (rl) {
- RenderPass *rpass = image_render_pass_get(rl, pass, actview, NULL);
- if (rpass) {
- rectf = rpass->rect;
- if (pass == 0) {
- if (rectf == NULL) {
- /* Happens when Save Buffers is enabled.
- * Use display buffer stored in the render layer.
- */
- rect = (unsigned int *) rl->display_buffer;
- byte_buffer_in_display_space = true;
- }
- }
- else {
- channels = rpass->channels;
- dither = 0.0f; /* don't dither passes */
- }
- }
-
- for (rpass = rl->passes.first; rpass; rpass = rpass->next)
- if (STREQ(rpass->name, RE_PASSNAME_Z) && rpass->view_id == actview)
- rectz = rpass->rect;
- }
- }
-
- ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0);
-
- /* make ibuf if needed, and initialize it */
- if (ibuf == NULL) {
- ibuf = IMB_allocImBuf(rres.rectx, rres.recty, 32, 0);
- image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
- }
-
- /* Set color space settings for a byte buffer.
- *
- * This is mainly to make it so color management treats byte buffer
- * from render result with Save Buffers enabled as final display buffer
- * and doesn't apply any color management on it.
- *
- * For other cases we need to be sure it stays to default byte buffer space.
- */
- if (ibuf->rect != rect) {
- if (byte_buffer_in_display_space) {
- const char *colorspace =
- IMB_colormanagement_get_display_colorspace_name(&iuser->scene->view_settings,
- &iuser->scene->display_settings);
- IMB_colormanagement_assign_rect_colorspace(ibuf, colorspace);
- }
- else {
- const char *colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DEFAULT_BYTE);
- IMB_colormanagement_assign_rect_colorspace(ibuf, colorspace);
- }
- }
-
- /* invalidate color managed buffers if render result changed */
- BLI_thread_lock(LOCK_COLORMANAGE);
- if (ibuf->x != rres.rectx || ibuf->y != rres.recty || ibuf->rect_float != rectf) {
- ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
- }
-
- ibuf->x = rres.rectx;
- ibuf->y = rres.recty;
-
- if (rect) {
- imb_freerectImBuf(ibuf);
- ibuf->rect = rect;
- }
- else {
- /* byte buffer of render result has been freed, make sure image buffers
- * does not reference to this buffer anymore
- * need check for whether byte buffer was allocated and owned by image itself
- * or if it's reusing buffer from render result
- */
- if ((ibuf->mall & IB_rect) == 0)
- ibuf->rect = NULL;
- }
-
- if (rectf) {
- ibuf->rect_float = rectf;
- ibuf->flags |= IB_rectfloat;
- ibuf->channels = channels;
- }
- else {
- ibuf->rect_float = NULL;
- ibuf->flags &= ~IB_rectfloat;
- }
-
- if (rectz) {
- ibuf->zbuf_float = rectz;
- ibuf->flags |= IB_zbuffloat;
- }
- else {
- ibuf->zbuf_float = NULL;
- ibuf->flags &= ~IB_zbuffloat;
- }
-
- /* TODO(sergey): Make this faster by either simply referencing the stamp
- * or by changing both ImBug and RenderResult to use same data type to
- * store metadata. */
- if (ibuf->metadata != NULL) {
- IMB_metadata_free(ibuf->metadata);
- ibuf->metadata = NULL;
- }
- BKE_imbuf_stamp_info(&rres, ibuf);
-
- BLI_thread_unlock(LOCK_COLORMANAGE);
-
- ibuf->dither = dither;
-
- ima->ok = IMA_OK_LOADED;
-
- return ibuf;
+ Render *re;
+ RenderResult rres;
+ RenderView *rv;
+ float *rectf, *rectz;
+ unsigned int *rect;
+ float dither;
+ int channels, layer, pass;
+ ImBuf *ibuf;
+ int from_render = (ima->render_slot == ima->last_render_slot);
+ int actview;
+ bool byte_buffer_in_display_space = false;
+
+ if (!(iuser && iuser->scene))
+ return NULL;
+
+ /* if we the caller is not going to release the lock, don't give the image */
+ if (!r_lock)
+ return NULL;
+
+ re = RE_GetSceneRender(iuser->scene);
+
+ channels = 4;
+ layer = iuser->layer;
+ pass = iuser->pass;
+ actview = iuser->view;
+
+ if (BKE_image_is_stereo(ima) && (iuser->flag & IMA_SHOW_STEREO))
+ actview = iuser->multiview_eye;
+
+ RenderSlot *slot;
+ if (from_render) {
+ RE_AcquireResultImage(re, &rres, actview);
+ }
+ else if ((slot = BKE_image_get_renderslot(ima, ima->render_slot))->render) {
+ rres = *(slot->render);
+ rres.have_combined = ((RenderView *)rres.views.first)->rectf != NULL;
+ }
+ else
+ memset(&rres, 0, sizeof(RenderResult));
+
+ if (!(rres.rectx > 0 && rres.recty > 0)) {
+ if (from_render)
+ RE_ReleaseResultImage(re);
+ return NULL;
+ }
+
+ /* release is done in BKE_image_release_ibuf using r_lock */
+ if (from_render) {
+ BLI_thread_lock(LOCK_VIEWER);
+ *r_lock = re;
+ rv = NULL;
+ }
+ else {
+ rv = BLI_findlink(&rres.views, actview);
+ if (rv == NULL)
+ rv = rres.views.first;
+ }
+
+ /* this gives active layer, composite or sequence result */
+ if (rv == NULL) {
+ rect = (unsigned int *)rres.rect32;
+ rectf = rres.rectf;
+ rectz = rres.rectz;
+ }
+ else {
+ rect = (unsigned int *)rv->rect32;
+ rectf = rv->rectf;
+ rectz = rv->rectz;
+ }
+
+ dither = iuser->scene->r.dither_intensity;
+
+ /* combined layer gets added as first layer */
+ if (rres.have_combined && layer == 0) {
+ /* pass */
+ }
+ else if (rect && layer == 0) {
+ /* rect32 is set when there's a Sequence pass, this pass seems
+ * to have layer=0 (this is from image_buttons.c)
+ * in this case we ignore float buffer, because it could have
+ * hung from previous pass which was float
+ */
+ rectf = NULL;
+ }
+ else if (rres.layers.first) {
+ RenderLayer *rl = BLI_findlink(&rres.layers, layer - (rres.have_combined ? 1 : 0));
+ if (rl) {
+ RenderPass *rpass = image_render_pass_get(rl, pass, actview, NULL);
+ if (rpass) {
+ rectf = rpass->rect;
+ if (pass == 0) {
+ if (rectf == NULL) {
+ /* Happens when Save Buffers is enabled.
+ * Use display buffer stored in the render layer.
+ */
+ rect = (unsigned int *)rl->display_buffer;
+ byte_buffer_in_display_space = true;
+ }
+ }
+ else {
+ channels = rpass->channels;
+ dither = 0.0f; /* don't dither passes */
+ }
+ }
+
+ for (rpass = rl->passes.first; rpass; rpass = rpass->next)
+ if (STREQ(rpass->name, RE_PASSNAME_Z) && rpass->view_id == actview)
+ rectz = rpass->rect;
+ }
+ }
+
+ ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0);
+
+ /* make ibuf if needed, and initialize it */
+ if (ibuf == NULL) {
+ ibuf = IMB_allocImBuf(rres.rectx, rres.recty, 32, 0);
+ image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
+ }
+
+ /* Set color space settings for a byte buffer.
+ *
+ * This is mainly to make it so color management treats byte buffer
+ * from render result with Save Buffers enabled as final display buffer
+ * and doesn't apply any color management on it.
+ *
+ * For other cases we need to be sure it stays to default byte buffer space.
+ */
+ if (ibuf->rect != rect) {
+ if (byte_buffer_in_display_space) {
+ const char *colorspace = IMB_colormanagement_get_display_colorspace_name(
+ &iuser->scene->view_settings, &iuser->scene->display_settings);
+ IMB_colormanagement_assign_rect_colorspace(ibuf, colorspace);
+ }
+ else {
+ const char *colorspace = IMB_colormanagement_role_colorspace_name_get(
+ COLOR_ROLE_DEFAULT_BYTE);
+ IMB_colormanagement_assign_rect_colorspace(ibuf, colorspace);
+ }
+ }
+
+ /* invalidate color managed buffers if render result changed */
+ BLI_thread_lock(LOCK_COLORMANAGE);
+ if (ibuf->x != rres.rectx || ibuf->y != rres.recty || ibuf->rect_float != rectf) {
+ ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
+ }
+
+ ibuf->x = rres.rectx;
+ ibuf->y = rres.recty;
+
+ if (rect) {
+ imb_freerectImBuf(ibuf);
+ ibuf->rect = rect;
+ }
+ else {
+ /* byte buffer of render result has been freed, make sure image buffers
+ * does not reference to this buffer anymore
+ * need check for whether byte buffer was allocated and owned by image itself
+ * or if it's reusing buffer from render result
+ */
+ if ((ibuf->mall & IB_rect) == 0)
+ ibuf->rect = NULL;
+ }
+
+ if (rectf) {
+ ibuf->rect_float = rectf;
+ ibuf->flags |= IB_rectfloat;
+ ibuf->channels = channels;
+ }
+ else {
+ ibuf->rect_float = NULL;
+ ibuf->flags &= ~IB_rectfloat;
+ }
+
+ if (rectz) {
+ ibuf->zbuf_float = rectz;
+ ibuf->flags |= IB_zbuffloat;
+ }
+ else {
+ ibuf->zbuf_float = NULL;
+ ibuf->flags &= ~IB_zbuffloat;
+ }
+
+ /* TODO(sergey): Make this faster by either simply referencing the stamp
+ * or by changing both ImBug and RenderResult to use same data type to
+ * store metadata. */
+ if (ibuf->metadata != NULL) {
+ IMB_metadata_free(ibuf->metadata);
+ ibuf->metadata = NULL;
+ }
+ BKE_imbuf_stamp_info(&rres, ibuf);
+
+ BLI_thread_unlock(LOCK_COLORMANAGE);
+
+ ibuf->dither = dither;
+
+ ima->ok = IMA_OK_LOADED;
+
+ return ibuf;
}
static int image_get_multiview_index(Image *ima, ImageUser *iuser)
{
- const bool is_multilayer = BKE_image_is_multilayer(ima);
- const bool is_backdrop = (ima->source == IMA_SRC_VIEWER) && (ima->type == IMA_TYPE_COMPOSITE) && (iuser == NULL);
- int index = BKE_image_is_animated(ima) ? 0 : IMA_NO_INDEX;
+ const bool is_multilayer = BKE_image_is_multilayer(ima);
+ const bool is_backdrop = (ima->source == IMA_SRC_VIEWER) && (ima->type == IMA_TYPE_COMPOSITE) &&
+ (iuser == NULL);
+ int index = BKE_image_is_animated(ima) ? 0 : IMA_NO_INDEX;
- if (is_multilayer) {
- return iuser ? iuser->multi_index : index;
- }
- else if (is_backdrop) {
- if (BKE_image_is_stereo(ima)) {
- /* backdrop hackaround (since there is no iuser */
- return ima->eye;
- }
- }
- else if (BKE_image_is_multiview(ima)) {
- return iuser ? iuser->multi_index : index;
- }
+ if (is_multilayer) {
+ return iuser ? iuser->multi_index : index;
+ }
+ else if (is_backdrop) {
+ if (BKE_image_is_stereo(ima)) {
+ /* backdrop hackaround (since there is no iuser */
+ return ima->eye;
+ }
+ }
+ else if (BKE_image_is_multiview(ima)) {
+ return iuser ? iuser->multi_index : index;
+ }
- return index;
+ return index;
}
static void image_get_frame_and_index(Image *ima, ImageUser *iuser, int *r_frame, int *r_index)
{
- int frame = 0, index = image_get_multiview_index(ima, iuser);
+ int frame = 0, index = image_get_multiview_index(ima, iuser);
- /* see if we already have an appropriate ibuf, with image source and type */
- if (ima->source == IMA_SRC_MOVIE) {
- frame = iuser ? iuser->framenr : ima->lastframe;
- }
- else if (ima->source == IMA_SRC_SEQUENCE) {
- if (ima->type == IMA_TYPE_IMAGE) {
- frame = iuser ? iuser->framenr : ima->lastframe;
- }
- else if (ima->type == IMA_TYPE_MULTILAYER) {
- frame = iuser ? iuser->framenr : ima->lastframe;
- }
- }
+ /* see if we already have an appropriate ibuf, with image source and type */
+ if (ima->source == IMA_SRC_MOVIE) {
+ frame = iuser ? iuser->framenr : ima->lastframe;
+ }
+ else if (ima->source == IMA_SRC_SEQUENCE) {
+ if (ima->type == IMA_TYPE_IMAGE) {
+ frame = iuser ? iuser->framenr : ima->lastframe;
+ }
+ else if (ima->type == IMA_TYPE_MULTILAYER) {
+ frame = iuser ? iuser->framenr : ima->lastframe;
+ }
+ }
- *r_frame = frame;
- *r_index = index;
+ *r_frame = frame;
+ *r_index = index;
}
/* Get the ibuf from an image cache for a given image user.
@@ -4049,73 +4241,73 @@ static void image_get_frame_and_index(Image *ima, ImageUser *iuser, int *r_frame
*/
static ImBuf *image_get_cached_ibuf(Image *ima, ImageUser *iuser, int *r_frame, int *r_index)
{
- ImBuf *ibuf = NULL;
- int frame = 0, index = image_get_multiview_index(ima, iuser);
-
- /* see if we already have an appropriate ibuf, with image source and type */
- if (ima->source == IMA_SRC_MOVIE) {
- frame = iuser ? iuser->framenr : ima->lastframe;
- ibuf = image_get_cached_ibuf_for_index_frame(ima, index, frame);
- ima->lastframe = frame;
- }
- else if (ima->source == IMA_SRC_SEQUENCE) {
- if (ima->type == IMA_TYPE_IMAGE) {
- frame = iuser ? iuser->framenr : ima->lastframe;
- ibuf = image_get_cached_ibuf_for_index_frame(ima, index, frame);
- ima->lastframe = frame;
-
- /* counter the fact that image is set as invalid when loading a frame
- * that is not in the cache (through image_acquire_ibuf for instance),
- * yet we have valid frames in the cache loaded */
- if (ibuf) {
- ima->ok = IMA_OK_LOADED;
-
- if (iuser)
- iuser->ok = ima->ok;
- }
- }
- else if (ima->type == IMA_TYPE_MULTILAYER) {
- frame = iuser ? iuser->framenr : ima->lastframe;
- ibuf = image_get_cached_ibuf_for_index_frame(ima, index, frame);
- }
- }
- else if (ima->source == IMA_SRC_FILE) {
- if (ima->type == IMA_TYPE_IMAGE)
- ibuf = image_get_cached_ibuf_for_index_frame(ima, index, 0);
- else if (ima->type == IMA_TYPE_MULTILAYER)
- ibuf = image_get_cached_ibuf_for_index_frame(ima, index, 0);
- }
- else if (ima->source == IMA_SRC_GENERATED) {
- ibuf = image_get_cached_ibuf_for_index_frame(ima, index, 0);
- }
- else if (ima->source == IMA_SRC_VIEWER) {
- /* always verify entirely, not that this shouldn't happen
- * as part of texture sampling in rendering anyway, so not
- * a big bottleneck */
- }
-
- if (r_frame)
- *r_frame = frame;
-
- if (r_index)
- *r_index = index;
-
- return ibuf;
+ ImBuf *ibuf = NULL;
+ int frame = 0, index = image_get_multiview_index(ima, iuser);
+
+ /* see if we already have an appropriate ibuf, with image source and type */
+ if (ima->source == IMA_SRC_MOVIE) {
+ frame = iuser ? iuser->framenr : ima->lastframe;
+ ibuf = image_get_cached_ibuf_for_index_frame(ima, index, frame);
+ ima->lastframe = frame;
+ }
+ else if (ima->source == IMA_SRC_SEQUENCE) {
+ if (ima->type == IMA_TYPE_IMAGE) {
+ frame = iuser ? iuser->framenr : ima->lastframe;
+ ibuf = image_get_cached_ibuf_for_index_frame(ima, index, frame);
+ ima->lastframe = frame;
+
+ /* counter the fact that image is set as invalid when loading a frame
+ * that is not in the cache (through image_acquire_ibuf for instance),
+ * yet we have valid frames in the cache loaded */
+ if (ibuf) {
+ ima->ok = IMA_OK_LOADED;
+
+ if (iuser)
+ iuser->ok = ima->ok;
+ }
+ }
+ else if (ima->type == IMA_TYPE_MULTILAYER) {
+ frame = iuser ? iuser->framenr : ima->lastframe;
+ ibuf = image_get_cached_ibuf_for_index_frame(ima, index, frame);
+ }
+ }
+ else if (ima->source == IMA_SRC_FILE) {
+ if (ima->type == IMA_TYPE_IMAGE)
+ ibuf = image_get_cached_ibuf_for_index_frame(ima, index, 0);
+ else if (ima->type == IMA_TYPE_MULTILAYER)
+ ibuf = image_get_cached_ibuf_for_index_frame(ima, index, 0);
+ }
+ else if (ima->source == IMA_SRC_GENERATED) {
+ ibuf = image_get_cached_ibuf_for_index_frame(ima, index, 0);
+ }
+ else if (ima->source == IMA_SRC_VIEWER) {
+ /* always verify entirely, not that this shouldn't happen
+ * as part of texture sampling in rendering anyway, so not
+ * a big bottleneck */
+ }
+
+ if (r_frame)
+ *r_frame = frame;
+
+ if (r_index)
+ *r_index = index;
+
+ return ibuf;
}
BLI_INLINE bool image_quick_test(Image *ima, ImageUser *iuser)
{
- if (ima == NULL)
- return false;
+ if (ima == NULL)
+ return false;
- if (iuser) {
- if (iuser->ok == 0)
- return false;
- }
- else if (ima->ok == 0)
- return false;
+ if (iuser) {
+ if (iuser->ok == 0)
+ return false;
+ }
+ else if (ima->ok == 0)
+ return false;
- return true;
+ return true;
}
/* Checks optional ImageUser and verifies/creates ImBuf.
@@ -4124,91 +4316,100 @@ BLI_INLINE bool image_quick_test(Image *ima, ImageUser *iuser)
*/
static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
{
- ImBuf *ibuf = NULL;
- int frame = 0, index = 0;
-
- if (r_lock)
- *r_lock = NULL;
-
- /* quick reject tests */
- if (!image_quick_test(ima, iuser))
- return NULL;
-
- ibuf = image_get_cached_ibuf(ima, iuser, &frame, &index);
-
- if (ibuf == NULL) {
- /* we are sure we have to load the ibuf, using source and type */
- if (ima->source == IMA_SRC_MOVIE) {
- /* source is from single file, use flipbook to store ibuf */
- ibuf = image_load_movie_file(ima, iuser, frame);
- }
- else if (ima->source == IMA_SRC_SEQUENCE) {
- if (ima->type == IMA_TYPE_IMAGE) {
- /* regular files, ibufs in flipbook, allows saving */
- ibuf = image_load_sequence_file(ima, iuser, frame);
- }
- /* no else; on load the ima type can change */
- if (ima->type == IMA_TYPE_MULTILAYER) {
- /* only 1 layer/pass stored in imbufs, no exrhandle anim storage, no saving */
- ibuf = image_load_sequence_multilayer(ima, iuser, frame);
- }
- }
- else if (ima->source == IMA_SRC_FILE) {
-
- if (ima->type == IMA_TYPE_IMAGE)
- ibuf = image_load_image_file(ima, iuser, frame); /* cfra only for '#', this global is OK */
- /* no else; on load the ima type can change */
- if (ima->type == IMA_TYPE_MULTILAYER)
- /* keeps render result, stores ibufs in listbase, allows saving */
- ibuf = image_get_ibuf_multilayer(ima, iuser);
- }
- else if (ima->source == IMA_SRC_GENERATED) {
- /* generated is: ibuf is allocated dynamically */
- /* UV testgrid or black or solid etc */
- if (ima->gen_x == 0) ima->gen_x = 1024;
- if (ima->gen_y == 0) ima->gen_y = 1024;
- if (ima->gen_depth == 0) ima->gen_depth = 24;
- ibuf = add_ibuf_size(ima->gen_x, ima->gen_y, ima->name, ima->gen_depth, (ima->gen_flag & IMA_GEN_FLOAT) != 0, ima->gen_type,
- ima->gen_color, &ima->colorspace_settings);
- image_assign_ibuf(ima, ibuf, index, 0);
- ima->ok = IMA_OK_LOADED;
- }
- else if (ima->source == IMA_SRC_VIEWER) {
- if (ima->type == IMA_TYPE_R_RESULT) {
- /* always verify entirely, and potentially
- * returns pointer to release later */
- ibuf = image_get_render_result(ima, iuser, r_lock);
- }
- else if (ima->type == IMA_TYPE_COMPOSITE) {
- /* requires lock/unlock, otherwise don't return image */
- if (r_lock) {
- /* unlock in BKE_image_release_ibuf */
- BLI_thread_lock(LOCK_VIEWER);
- *r_lock = ima;
-
- /* XXX anim play for viewer nodes not yet supported */
- frame = 0; // XXX iuser ? iuser->framenr : 0;
- ibuf = image_get_cached_ibuf_for_index_frame(ima, index, frame);
-
- if (!ibuf) {
- /* Composite Viewer, all handled in compositor */
- /* fake ibuf, will be filled in compositor */
- ibuf = IMB_allocImBuf(256, 256, 32, IB_rect | IB_rectfloat);
- image_assign_ibuf(ima, ibuf, index, frame);
- }
- }
- }
- }
-
- /* We only want movies and sequences to be memory limited. */
- if (ibuf != NULL && !ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) {
- ibuf->userflags |= IB_PERSISTENT;
- }
- }
-
- BKE_image_tag_time(ima);
-
- return ibuf;
+ ImBuf *ibuf = NULL;
+ int frame = 0, index = 0;
+
+ if (r_lock)
+ *r_lock = NULL;
+
+ /* quick reject tests */
+ if (!image_quick_test(ima, iuser))
+ return NULL;
+
+ ibuf = image_get_cached_ibuf(ima, iuser, &frame, &index);
+
+ if (ibuf == NULL) {
+ /* we are sure we have to load the ibuf, using source and type */
+ if (ima->source == IMA_SRC_MOVIE) {
+ /* source is from single file, use flipbook to store ibuf */
+ ibuf = image_load_movie_file(ima, iuser, frame);
+ }
+ else if (ima->source == IMA_SRC_SEQUENCE) {
+ if (ima->type == IMA_TYPE_IMAGE) {
+ /* regular files, ibufs in flipbook, allows saving */
+ ibuf = image_load_sequence_file(ima, iuser, frame);
+ }
+ /* no else; on load the ima type can change */
+ if (ima->type == IMA_TYPE_MULTILAYER) {
+ /* only 1 layer/pass stored in imbufs, no exrhandle anim storage, no saving */
+ ibuf = image_load_sequence_multilayer(ima, iuser, frame);
+ }
+ }
+ else if (ima->source == IMA_SRC_FILE) {
+
+ if (ima->type == IMA_TYPE_IMAGE)
+ ibuf = image_load_image_file(ima, iuser, frame); /* cfra only for '#', this global is OK */
+ /* no else; on load the ima type can change */
+ if (ima->type == IMA_TYPE_MULTILAYER)
+ /* keeps render result, stores ibufs in listbase, allows saving */
+ ibuf = image_get_ibuf_multilayer(ima, iuser);
+ }
+ else if (ima->source == IMA_SRC_GENERATED) {
+ /* generated is: ibuf is allocated dynamically */
+ /* UV testgrid or black or solid etc */
+ if (ima->gen_x == 0)
+ ima->gen_x = 1024;
+ if (ima->gen_y == 0)
+ ima->gen_y = 1024;
+ if (ima->gen_depth == 0)
+ ima->gen_depth = 24;
+ ibuf = add_ibuf_size(ima->gen_x,
+ ima->gen_y,
+ ima->name,
+ ima->gen_depth,
+ (ima->gen_flag & IMA_GEN_FLOAT) != 0,
+ ima->gen_type,
+ ima->gen_color,
+ &ima->colorspace_settings);
+ image_assign_ibuf(ima, ibuf, index, 0);
+ ima->ok = IMA_OK_LOADED;
+ }
+ else if (ima->source == IMA_SRC_VIEWER) {
+ if (ima->type == IMA_TYPE_R_RESULT) {
+ /* always verify entirely, and potentially
+ * returns pointer to release later */
+ ibuf = image_get_render_result(ima, iuser, r_lock);
+ }
+ else if (ima->type == IMA_TYPE_COMPOSITE) {
+ /* requires lock/unlock, otherwise don't return image */
+ if (r_lock) {
+ /* unlock in BKE_image_release_ibuf */
+ BLI_thread_lock(LOCK_VIEWER);
+ *r_lock = ima;
+
+ /* XXX anim play for viewer nodes not yet supported */
+ frame = 0; // XXX iuser ? iuser->framenr : 0;
+ ibuf = image_get_cached_ibuf_for_index_frame(ima, index, frame);
+
+ if (!ibuf) {
+ /* Composite Viewer, all handled in compositor */
+ /* fake ibuf, will be filled in compositor */
+ ibuf = IMB_allocImBuf(256, 256, 32, IB_rect | IB_rectfloat);
+ image_assign_ibuf(ima, ibuf, index, frame);
+ }
+ }
+ }
+ }
+
+ /* We only want movies and sequences to be memory limited. */
+ if (ibuf != NULL && !ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) {
+ ibuf->userflags |= IB_PERSISTENT;
+ }
+ }
+
+ BKE_image_tag_time(ima);
+
+ return ibuf;
}
/* return image buffer for given image and user
@@ -4220,554 +4421,558 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
*/
ImBuf *BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
{
- ImBuf *ibuf;
+ ImBuf *ibuf;
- BLI_spin_lock(&image_spin);
+ BLI_spin_lock(&image_spin);
- ibuf = image_acquire_ibuf(ima, iuser, r_lock);
+ ibuf = image_acquire_ibuf(ima, iuser, r_lock);
- BLI_spin_unlock(&image_spin);
+ BLI_spin_unlock(&image_spin);
- return ibuf;
+ return ibuf;
}
void BKE_image_release_ibuf(Image *ima, ImBuf *ibuf, void *lock)
{
- if (lock != NULL) {
- /* for getting image during threaded render / compositing, need to release */
- if (lock == ima) {
- BLI_thread_unlock(LOCK_VIEWER); /* viewer image */
- }
- else {
- RE_ReleaseResultImage(lock); /* render result */
- BLI_thread_unlock(LOCK_VIEWER); /* view image imbuf */
- }
- }
+ if (lock != NULL) {
+ /* for getting image during threaded render / compositing, need to release */
+ if (lock == ima) {
+ BLI_thread_unlock(LOCK_VIEWER); /* viewer image */
+ }
+ else {
+ RE_ReleaseResultImage(lock); /* render result */
+ BLI_thread_unlock(LOCK_VIEWER); /* view image imbuf */
+ }
+ }
- if (ibuf) {
- BLI_spin_lock(&image_spin);
- IMB_freeImBuf(ibuf);
- BLI_spin_unlock(&image_spin);
- }
+ if (ibuf) {
+ BLI_spin_lock(&image_spin);
+ IMB_freeImBuf(ibuf);
+ BLI_spin_unlock(&image_spin);
+ }
}
/* checks whether there's an image buffer for given image and user */
bool BKE_image_has_ibuf(Image *ima, ImageUser *iuser)
{
- ImBuf *ibuf;
+ ImBuf *ibuf;
- /* quick reject tests */
- if (!image_quick_test(ima, iuser))
- return false;
+ /* quick reject tests */
+ if (!image_quick_test(ima, iuser))
+ return false;
- BLI_spin_lock(&image_spin);
+ BLI_spin_lock(&image_spin);
- ibuf = image_get_cached_ibuf(ima, iuser, NULL, NULL);
+ ibuf = image_get_cached_ibuf(ima, iuser, NULL, NULL);
- if (!ibuf)
- ibuf = image_acquire_ibuf(ima, iuser, NULL);
+ if (!ibuf)
+ ibuf = image_acquire_ibuf(ima, iuser, NULL);
- BLI_spin_unlock(&image_spin);
+ BLI_spin_unlock(&image_spin);
- IMB_freeImBuf(ibuf);
+ IMB_freeImBuf(ibuf);
- return ibuf != NULL;
+ return ibuf != NULL;
}
/* ******** Pool for image buffers ******** */
typedef struct ImagePoolEntry {
- struct ImagePoolEntry *next, *prev;
- Image *image;
- ImBuf *ibuf;
- int index;
- int frame;
+ struct ImagePoolEntry *next, *prev;
+ Image *image;
+ ImBuf *ibuf;
+ int index;
+ int frame;
} ImagePoolEntry;
typedef struct ImagePool {
- ListBase image_buffers;
- BLI_mempool *memory_pool;
+ ListBase image_buffers;
+ BLI_mempool *memory_pool;
} ImagePool;
ImagePool *BKE_image_pool_new(void)
{
- ImagePool *pool = MEM_callocN(sizeof(ImagePool), "Image Pool");
- pool->memory_pool = BLI_mempool_create(sizeof(ImagePoolEntry), 0, 128, BLI_MEMPOOL_NOP);
+ ImagePool *pool = MEM_callocN(sizeof(ImagePool), "Image Pool");
+ pool->memory_pool = BLI_mempool_create(sizeof(ImagePoolEntry), 0, 128, BLI_MEMPOOL_NOP);
- return pool;
+ return pool;
}
void BKE_image_pool_free(ImagePool *pool)
{
- /* Use single lock to dereference all the image buffers. */
- BLI_spin_lock(&image_spin);
- for (ImagePoolEntry *entry = pool->image_buffers.first;
- entry != NULL;
- entry = entry->next)
- {
- if (entry->ibuf) {
- IMB_freeImBuf(entry->ibuf);
- }
- }
- BLI_spin_unlock(&image_spin);
+ /* Use single lock to dereference all the image buffers. */
+ BLI_spin_lock(&image_spin);
+ for (ImagePoolEntry *entry = pool->image_buffers.first; entry != NULL; entry = entry->next) {
+ if (entry->ibuf) {
+ IMB_freeImBuf(entry->ibuf);
+ }
+ }
+ BLI_spin_unlock(&image_spin);
- BLI_mempool_destroy(pool->memory_pool);
- MEM_freeN(pool);
+ BLI_mempool_destroy(pool->memory_pool);
+ MEM_freeN(pool);
}
-BLI_INLINE ImBuf *image_pool_find_entry(ImagePool *pool, Image *image, int frame, int index, bool *found)
+BLI_INLINE ImBuf *image_pool_find_entry(
+ ImagePool *pool, Image *image, int frame, int index, bool *found)
{
- ImagePoolEntry *entry;
+ ImagePoolEntry *entry;
- *found = false;
+ *found = false;
- for (entry = pool->image_buffers.first; entry; entry = entry->next) {
- if (entry->image == image && entry->frame == frame && entry->index == index) {
- *found = true;
- return entry->ibuf;
- }
- }
+ for (entry = pool->image_buffers.first; entry; entry = entry->next) {
+ if (entry->image == image && entry->frame == frame && entry->index == index) {
+ *found = true;
+ return entry->ibuf;
+ }
+ }
- return NULL;
+ return NULL;
}
ImBuf *BKE_image_pool_acquire_ibuf(Image *ima, ImageUser *iuser, ImagePool *pool)
{
- ImBuf *ibuf;
- int index, frame;
- bool found;
+ ImBuf *ibuf;
+ int index, frame;
+ bool found;
- if (!image_quick_test(ima, iuser))
- return NULL;
+ if (!image_quick_test(ima, iuser))
+ return NULL;
- if (pool == NULL) {
- /* pool could be NULL, in this case use general acquire function */
- return BKE_image_acquire_ibuf(ima, iuser, NULL);
- }
+ if (pool == NULL) {
+ /* pool could be NULL, in this case use general acquire function */
+ return BKE_image_acquire_ibuf(ima, iuser, NULL);
+ }
- image_get_frame_and_index(ima, iuser, &frame, &index);
+ image_get_frame_and_index(ima, iuser, &frame, &index);
- ibuf = image_pool_find_entry(pool, ima, frame, index, &found);
- if (found)
- return ibuf;
+ ibuf = image_pool_find_entry(pool, ima, frame, index, &found);
+ if (found)
+ return ibuf;
- BLI_spin_lock(&image_spin);
+ BLI_spin_lock(&image_spin);
- ibuf = image_pool_find_entry(pool, ima, frame, index, &found);
+ ibuf = image_pool_find_entry(pool, ima, frame, index, &found);
- /* will also create entry even in cases image buffer failed to load,
- * prevents trying to load the same buggy file multiple times
- */
- if (!found) {
- ImagePoolEntry *entry;
+ /* will also create entry even in cases image buffer failed to load,
+ * prevents trying to load the same buggy file multiple times
+ */
+ if (!found) {
+ ImagePoolEntry *entry;
- ibuf = image_acquire_ibuf(ima, iuser, NULL);
+ ibuf = image_acquire_ibuf(ima, iuser, NULL);
- entry = BLI_mempool_alloc(pool->memory_pool);
- entry->image = ima;
- entry->frame = frame;
- entry->index = index;
- entry->ibuf = ibuf;
+ entry = BLI_mempool_alloc(pool->memory_pool);
+ entry->image = ima;
+ entry->frame = frame;
+ entry->index = index;
+ entry->ibuf = ibuf;
- BLI_addtail(&pool->image_buffers, entry);
- }
+ BLI_addtail(&pool->image_buffers, entry);
+ }
- BLI_spin_unlock(&image_spin);
+ BLI_spin_unlock(&image_spin);
- return ibuf;
+ return ibuf;
}
void BKE_image_pool_release_ibuf(Image *ima, ImBuf *ibuf, ImagePool *pool)
{
- /* if pool wasn't actually used, use general release stuff,
- * for pools image buffers will be dereferenced on pool free
- */
- if (pool == NULL) {
- BKE_image_release_ibuf(ima, ibuf, NULL);
- }
+ /* if pool wasn't actually used, use general release stuff,
+ * for pools image buffers will be dereferenced on pool free
+ */
+ if (pool == NULL) {
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ }
}
int BKE_image_user_frame_get(const ImageUser *iuser, int cfra, bool *r_is_in_range)
{
- const int len = iuser->frames;
-
- if (r_is_in_range) {
- *r_is_in_range = false;
- }
-
- if (len == 0) {
- return 0;
- }
- else {
- int framenr;
- cfra = cfra - iuser->sfra + 1;
-
- /* cyclic */
- if (iuser->cycl) {
- cfra = ((cfra) % len);
- if (cfra < 0) cfra += len;
- if (cfra == 0) cfra = len;
-
- if (r_is_in_range) {
- *r_is_in_range = true;
- }
- }
-
- if (cfra < 0) {
- cfra = 0;
- }
- else if (cfra > len) {
- cfra = len;
- }
- else {
- if (r_is_in_range) {
- *r_is_in_range = true;
- }
- }
-
- /* transform to images space */
- framenr = cfra;
- if (framenr > iuser->frames) framenr = iuser->frames;
-
- if (iuser->cycl) {
- framenr = ((framenr) % len);
- while (framenr < 0) framenr += len;
- if (framenr == 0) framenr = len;
- }
-
- /* important to apply after else we cant loop on frames 100 - 110 for eg. */
- framenr += iuser->offset;
-
- return framenr;
- }
+ const int len = iuser->frames;
+
+ if (r_is_in_range) {
+ *r_is_in_range = false;
+ }
+
+ if (len == 0) {
+ return 0;
+ }
+ else {
+ int framenr;
+ cfra = cfra - iuser->sfra + 1;
+
+ /* cyclic */
+ if (iuser->cycl) {
+ cfra = ((cfra) % len);
+ if (cfra < 0)
+ cfra += len;
+ if (cfra == 0)
+ cfra = len;
+
+ if (r_is_in_range) {
+ *r_is_in_range = true;
+ }
+ }
+
+ if (cfra < 0) {
+ cfra = 0;
+ }
+ else if (cfra > len) {
+ cfra = len;
+ }
+ else {
+ if (r_is_in_range) {
+ *r_is_in_range = true;
+ }
+ }
+
+ /* transform to images space */
+ framenr = cfra;
+ if (framenr > iuser->frames)
+ framenr = iuser->frames;
+
+ if (iuser->cycl) {
+ framenr = ((framenr) % len);
+ while (framenr < 0)
+ framenr += len;
+ if (framenr == 0)
+ framenr = len;
+ }
+
+ /* important to apply after else we cant loop on frames 100 - 110 for eg. */
+ framenr += iuser->offset;
+
+ return framenr;
+ }
}
void BKE_image_user_frame_calc(ImageUser *iuser, int cfra)
{
- if (iuser) {
- bool is_in_range;
- const int framenr = BKE_image_user_frame_get(iuser, cfra, &is_in_range);
+ if (iuser) {
+ bool is_in_range;
+ const int framenr = BKE_image_user_frame_get(iuser, cfra, &is_in_range);
- if (is_in_range) {
- iuser->flag |= IMA_USER_FRAME_IN_RANGE;
- }
- else {
- iuser->flag &= ~IMA_USER_FRAME_IN_RANGE;
- }
+ if (is_in_range) {
+ iuser->flag |= IMA_USER_FRAME_IN_RANGE;
+ }
+ else {
+ iuser->flag &= ~IMA_USER_FRAME_IN_RANGE;
+ }
- iuser->framenr = framenr;
- if (iuser->ok == 0) iuser->ok = 1;
- }
+ iuser->framenr = framenr;
+ if (iuser->ok == 0)
+ iuser->ok = 1;
+ }
}
/* goes over all ImageUsers, and sets frame numbers if auto-refresh is set */
-static void image_editors_update_frame(struct Image *ima, struct ImageUser *iuser, void *customdata)
+static void image_editors_update_frame(struct Image *ima,
+ struct ImageUser *iuser,
+ void *customdata)
{
- int cfra = *(int *)customdata;
+ int cfra = *(int *)customdata;
- if ((iuser->flag & IMA_ANIM_ALWAYS) ||
- (iuser->flag & IMA_NEED_FRAME_RECALC))
- {
- int framenr = iuser->framenr;
+ if ((iuser->flag & IMA_ANIM_ALWAYS) || (iuser->flag & IMA_NEED_FRAME_RECALC)) {
+ int framenr = iuser->framenr;
- BKE_image_user_frame_calc(iuser, cfra);
- iuser->flag &= ~IMA_NEED_FRAME_RECALC;
+ BKE_image_user_frame_calc(iuser, cfra);
+ iuser->flag &= ~IMA_NEED_FRAME_RECALC;
- if (ima && iuser->framenr != framenr) {
- ima->gpuflag |= IMA_GPU_REFRESH;
- }
- }
+ if (ima && iuser->framenr != framenr) {
+ ima->gpuflag |= IMA_GPU_REFRESH;
+ }
+ }
}
void BKE_image_editors_update_frame(const Main *bmain, int cfra)
{
- /* This only updates images used by the user interface. For others the
- * dependency graph will call BKE_image_user_id_eval_animation. */
- wmWindowManager *wm = bmain->wm.first;
- image_walk_id_all_users(&wm->id, false, &cfra, image_editors_update_frame);
+ /* This only updates images used by the user interface. For others the
+ * dependency graph will call BKE_image_user_id_eval_animation. */
+ wmWindowManager *wm = bmain->wm.first;
+ image_walk_id_all_users(&wm->id, false, &cfra, image_editors_update_frame);
}
-static void image_user_id_has_animation(struct Image *ima, struct ImageUser *UNUSED(iuser), void *customdata)
+static void image_user_id_has_animation(struct Image *ima,
+ struct ImageUser *UNUSED(iuser),
+ void *customdata)
{
- if (ima && BKE_image_is_animated(ima)) {
- *(bool *)customdata = true;
- }
+ if (ima && BKE_image_is_animated(ima)) {
+ *(bool *)customdata = true;
+ }
}
bool BKE_image_user_id_has_animation(ID *id)
{
- /* For the dependency graph, this does not consider nested node
- * trees as these are handled as their own datablock. */
- bool has_animation = false;
- bool skip_nested_nodes = true;
- image_walk_id_all_users(id, skip_nested_nodes, &has_animation, image_user_id_has_animation);
- return has_animation;
+ /* For the dependency graph, this does not consider nested node
+ * trees as these are handled as their own datablock. */
+ bool has_animation = false;
+ bool skip_nested_nodes = true;
+ image_walk_id_all_users(id, skip_nested_nodes, &has_animation, image_user_id_has_animation);
+ return has_animation;
}
-static void image_user_id_eval_animation(struct Image *ima, struct ImageUser *iuser, void *customdata)
+static void image_user_id_eval_animation(struct Image *ima,
+ struct ImageUser *iuser,
+ void *customdata)
{
- if (ima && BKE_image_is_animated(ima)) {
- Depsgraph *depsgraph = (Depsgraph *)customdata;
+ if (ima && BKE_image_is_animated(ima)) {
+ Depsgraph *depsgraph = (Depsgraph *)customdata;
- if ((iuser->flag & IMA_ANIM_ALWAYS) ||
- (iuser->flag & IMA_NEED_FRAME_RECALC) ||
- (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER))
- {
- int framenr = iuser->framenr;
- float cfra = DEG_get_ctime(depsgraph);
+ if ((iuser->flag & IMA_ANIM_ALWAYS) || (iuser->flag & IMA_NEED_FRAME_RECALC) ||
+ (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER)) {
+ int framenr = iuser->framenr;
+ float cfra = DEG_get_ctime(depsgraph);
- BKE_image_user_frame_calc(iuser, cfra);
- iuser->flag &= ~IMA_NEED_FRAME_RECALC;
+ BKE_image_user_frame_calc(iuser, cfra);
+ iuser->flag &= ~IMA_NEED_FRAME_RECALC;
- if (iuser->framenr != framenr) {
- /* Note: a single texture and refresh doesn't really work when
- * multiple image users may use different frames, this is to
- * be improved with perhaps a GPU texture cache. */
- ima->gpuflag |= IMA_GPU_REFRESH;
- }
- }
- }
+ if (iuser->framenr != framenr) {
+ /* Note: a single texture and refresh doesn't really work when
+ * multiple image users may use different frames, this is to
+ * be improved with perhaps a GPU texture cache. */
+ ima->gpuflag |= IMA_GPU_REFRESH;
+ }
+ }
+ }
}
void BKE_image_user_id_eval_animation(Depsgraph *depsgraph, ID *id)
{
- /* This is called from the dependency graph to update the image
- * users in datablocks. It computes the current frame number
- * and tags the image to be refreshed.
- * This does not consider nested node trees as these are handled
- * as their own datablock. */
- bool skip_nested_nodes = true;
- image_walk_id_all_users(id, skip_nested_nodes, depsgraph, image_user_id_eval_animation);
+ /* This is called from the dependency graph to update the image
+ * users in datablocks. It computes the current frame number
+ * and tags the image to be refreshed.
+ * This does not consider nested node trees as these are handled
+ * as their own datablock. */
+ bool skip_nested_nodes = true;
+ image_walk_id_all_users(id, skip_nested_nodes, depsgraph, image_user_id_eval_animation);
}
void BKE_image_user_file_path(ImageUser *iuser, Image *ima, char *filepath)
{
- if (BKE_image_is_multiview(ima)) {
- ImageView *iv = BLI_findlink(&ima->views, iuser->view);
- if (iv->filepath[0])
- BLI_strncpy(filepath, iv->filepath, FILE_MAX);
- else
- BLI_strncpy(filepath, ima->name, FILE_MAX);
- }
- else {
- BLI_strncpy(filepath, ima->name, FILE_MAX);
- }
+ if (BKE_image_is_multiview(ima)) {
+ ImageView *iv = BLI_findlink(&ima->views, iuser->view);
+ if (iv->filepath[0])
+ BLI_strncpy(filepath, iv->filepath, FILE_MAX);
+ else
+ BLI_strncpy(filepath, ima->name, FILE_MAX);
+ }
+ else {
+ BLI_strncpy(filepath, ima->name, FILE_MAX);
+ }
- if (ima->source == IMA_SRC_SEQUENCE) {
- char head[FILE_MAX], tail[FILE_MAX];
- unsigned short numlen;
- int frame = iuser ? iuser->framenr : ima->lastframe;
+ if (ima->source == IMA_SRC_SEQUENCE) {
+ char head[FILE_MAX], tail[FILE_MAX];
+ unsigned short numlen;
+ int frame = iuser ? iuser->framenr : ima->lastframe;
- BLI_stringdec(filepath, head, tail, &numlen);
- BLI_stringenc(filepath, head, tail, numlen, frame);
- }
+ BLI_stringdec(filepath, head, tail, &numlen);
+ BLI_stringenc(filepath, head, tail, numlen, frame);
+ }
- BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id));
+ BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id));
}
bool BKE_image_has_alpha(struct Image *image)
{
- ImBuf *ibuf;
- void *lock;
- int planes;
+ ImBuf *ibuf;
+ void *lock;
+ int planes;
- ibuf = BKE_image_acquire_ibuf(image, NULL, &lock);
- planes = (ibuf ? ibuf->planes : 0);
- BKE_image_release_ibuf(image, ibuf, lock);
+ ibuf = BKE_image_acquire_ibuf(image, NULL, &lock);
+ planes = (ibuf ? ibuf->planes : 0);
+ BKE_image_release_ibuf(image, ibuf, lock);
- if (planes == 32)
- return true;
- else
- return false;
+ if (planes == 32)
+ return true;
+ else
+ return false;
}
void BKE_image_get_size(Image *image, ImageUser *iuser, int *width, int *height)
{
- ImBuf *ibuf = NULL;
- void *lock;
-
- if (image != NULL) {
- ibuf = BKE_image_acquire_ibuf(image, iuser, &lock);
- }
-
- if (ibuf && ibuf->x > 0 && ibuf->y > 0) {
- *width = ibuf->x;
- *height = ibuf->y;
- }
- else if (image != NULL && image->type == IMA_TYPE_R_RESULT &&
- iuser != NULL && iuser->scene != NULL)
- {
- Scene *scene = iuser->scene;
- *width = (scene->r.xsch * scene->r.size) / 100;
- *height = (scene->r.ysch * scene->r.size) / 100;
- if ((scene->r.mode & R_BORDER) && (scene->r.mode & R_CROP)) {
- *width *= BLI_rctf_size_x(&scene->r.border);
- *height *= BLI_rctf_size_y(&scene->r.border);
- }
- }
- else {
- *width = IMG_SIZE_FALLBACK;
- *height = IMG_SIZE_FALLBACK;
- }
-
- if (image != NULL) {
- BKE_image_release_ibuf(image, ibuf, lock);
- }
+ ImBuf *ibuf = NULL;
+ void *lock;
+
+ if (image != NULL) {
+ ibuf = BKE_image_acquire_ibuf(image, iuser, &lock);
+ }
+
+ if (ibuf && ibuf->x > 0 && ibuf->y > 0) {
+ *width = ibuf->x;
+ *height = ibuf->y;
+ }
+ else if (image != NULL && image->type == IMA_TYPE_R_RESULT && iuser != NULL &&
+ iuser->scene != NULL) {
+ Scene *scene = iuser->scene;
+ *width = (scene->r.xsch * scene->r.size) / 100;
+ *height = (scene->r.ysch * scene->r.size) / 100;
+ if ((scene->r.mode & R_BORDER) && (scene->r.mode & R_CROP)) {
+ *width *= BLI_rctf_size_x(&scene->r.border);
+ *height *= BLI_rctf_size_y(&scene->r.border);
+ }
+ }
+ else {
+ *width = IMG_SIZE_FALLBACK;
+ *height = IMG_SIZE_FALLBACK;
+ }
+
+ if (image != NULL) {
+ BKE_image_release_ibuf(image, ibuf, lock);
+ }
}
void BKE_image_get_size_fl(Image *image, ImageUser *iuser, float size[2])
{
- int width, height;
- BKE_image_get_size(image, iuser, &width, &height);
-
- size[0] = (float)width;
- size[1] = (float)height;
+ int width, height;
+ BKE_image_get_size(image, iuser, &width, &height);
+ size[0] = (float)width;
+ size[1] = (float)height;
}
void BKE_image_get_aspect(Image *image, float *aspx, float *aspy)
{
- *aspx = 1.0;
+ *aspx = 1.0;
- /* x is always 1 */
- if (image)
- *aspy = image->aspy / image->aspx;
- else
- *aspy = 1.0f;
+ /* x is always 1 */
+ if (image)
+ *aspy = image->aspy / image->aspx;
+ else
+ *aspy = 1.0f;
}
unsigned char *BKE_image_get_pixels_for_frame(struct Image *image, int frame)
{
- ImageUser iuser = {NULL};
- void *lock;
- ImBuf *ibuf;
- unsigned char *pixels = NULL;
+ ImageUser iuser = {NULL};
+ void *lock;
+ ImBuf *ibuf;
+ unsigned char *pixels = NULL;
- iuser.framenr = frame;
- iuser.ok = true;
+ iuser.framenr = frame;
+ iuser.ok = true;
- ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
+ ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
- if (ibuf) {
- pixels = (unsigned char *) ibuf->rect;
+ if (ibuf) {
+ pixels = (unsigned char *)ibuf->rect;
- if (pixels)
- pixels = MEM_dupallocN(pixels);
+ if (pixels)
+ pixels = MEM_dupallocN(pixels);
- BKE_image_release_ibuf(image, ibuf, lock);
- }
+ BKE_image_release_ibuf(image, ibuf, lock);
+ }
- if (!pixels)
- return NULL;
+ if (!pixels)
+ return NULL;
- return pixels;
+ return pixels;
}
float *BKE_image_get_float_pixels_for_frame(struct Image *image, int frame)
{
- ImageUser iuser = {NULL};
- void *lock;
- ImBuf *ibuf;
- float *pixels = NULL;
+ ImageUser iuser = {NULL};
+ void *lock;
+ ImBuf *ibuf;
+ float *pixels = NULL;
- iuser.framenr = frame;
- iuser.ok = true;
+ iuser.framenr = frame;
+ iuser.ok = true;
- ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
+ ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
- if (ibuf) {
- pixels = ibuf->rect_float;
+ if (ibuf) {
+ pixels = ibuf->rect_float;
- if (pixels)
- pixels = MEM_dupallocN(pixels);
+ if (pixels)
+ pixels = MEM_dupallocN(pixels);
- BKE_image_release_ibuf(image, ibuf, lock);
- }
+ BKE_image_release_ibuf(image, ibuf, lock);
+ }
- if (!pixels)
- return NULL;
+ if (!pixels)
+ return NULL;
- return pixels;
+ return pixels;
}
int BKE_image_sequence_guess_offset(Image *image)
{
- return BLI_stringdec(image->name, NULL, NULL, NULL);
+ return BLI_stringdec(image->name, NULL, NULL, NULL);
}
bool BKE_image_has_anim(Image *ima)
{
- return (BLI_listbase_is_empty(&ima->anims) == false);
+ return (BLI_listbase_is_empty(&ima->anims) == false);
}
bool BKE_image_has_packedfile(Image *ima)
{
- return (BLI_listbase_is_empty(&ima->packedfiles) == false);
+ return (BLI_listbase_is_empty(&ima->packedfiles) == false);
}
/* Checks the image buffer changes with time (not keyframed values). */
bool BKE_image_is_animated(Image *image)
{
- return ELEM(image->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE);
+ return ELEM(image->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE);
}
bool BKE_image_is_dirty(Image *image)
{
- bool is_dirty = false;
+ bool is_dirty = false;
- BLI_spin_lock(&image_spin);
- if (image->cache != NULL) {
- struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache);
+ BLI_spin_lock(&image_spin);
+ if (image->cache != NULL) {
+ struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache);
- while (!IMB_moviecacheIter_done(iter)) {
- ImBuf *ibuf = IMB_moviecacheIter_getImBuf(iter);
- if (ibuf->userflags & IB_BITMAPDIRTY) {
- is_dirty = true;
- break;
- }
- IMB_moviecacheIter_step(iter);
- }
- IMB_moviecacheIter_free(iter);
- }
- BLI_spin_unlock(&image_spin);
+ while (!IMB_moviecacheIter_done(iter)) {
+ ImBuf *ibuf = IMB_moviecacheIter_getImBuf(iter);
+ if (ibuf->userflags & IB_BITMAPDIRTY) {
+ is_dirty = true;
+ break;
+ }
+ IMB_moviecacheIter_step(iter);
+ }
+ IMB_moviecacheIter_free(iter);
+ }
+ BLI_spin_unlock(&image_spin);
- return is_dirty;
+ return is_dirty;
}
void BKE_image_file_format_set(Image *image, int ftype, const ImbFormatOptions *options)
{
- BLI_spin_lock(&image_spin);
- if (image->cache != NULL) {
- struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache);
+ BLI_spin_lock(&image_spin);
+ if (image->cache != NULL) {
+ struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache);
- while (!IMB_moviecacheIter_done(iter)) {
- ImBuf *ibuf = IMB_moviecacheIter_getImBuf(iter);
- ibuf->ftype = ftype;
- ibuf->foptions = *options;
- IMB_moviecacheIter_step(iter);
- }
- IMB_moviecacheIter_free(iter);
- }
- BLI_spin_unlock(&image_spin);
+ while (!IMB_moviecacheIter_done(iter)) {
+ ImBuf *ibuf = IMB_moviecacheIter_getImBuf(iter);
+ ibuf->ftype = ftype;
+ ibuf->foptions = *options;
+ IMB_moviecacheIter_step(iter);
+ }
+ IMB_moviecacheIter_free(iter);
+ }
+ BLI_spin_unlock(&image_spin);
}
bool BKE_image_has_loaded_ibuf(Image *image)
{
- bool has_loaded_ibuf = false;
+ bool has_loaded_ibuf = false;
- BLI_spin_lock(&image_spin);
- if (image->cache != NULL) {
- struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache);
+ BLI_spin_lock(&image_spin);
+ if (image->cache != NULL) {
+ struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache);
- while (!IMB_moviecacheIter_done(iter)) {
- has_loaded_ibuf = true;
- break;
- }
- IMB_moviecacheIter_free(iter);
- }
- BLI_spin_unlock(&image_spin);
+ while (!IMB_moviecacheIter_done(iter)) {
+ has_loaded_ibuf = true;
+ break;
+ }
+ IMB_moviecacheIter_free(iter);
+ }
+ BLI_spin_unlock(&image_spin);
- return has_loaded_ibuf;
+ return has_loaded_ibuf;
}
/**
@@ -4776,26 +4981,26 @@ bool BKE_image_has_loaded_ibuf(Image *image)
*/
ImBuf *BKE_image_get_ibuf_with_name(Image *image, const char *name)
{
- ImBuf *ibuf = NULL;
+ ImBuf *ibuf = NULL;
- BLI_spin_lock(&image_spin);
- if (image->cache != NULL) {
- struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache);
+ BLI_spin_lock(&image_spin);
+ if (image->cache != NULL) {
+ struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache);
- while (!IMB_moviecacheIter_done(iter)) {
- ImBuf *current_ibuf = IMB_moviecacheIter_getImBuf(iter);
- if (STREQ(current_ibuf->name, name)) {
- ibuf = current_ibuf;
- IMB_refImBuf(ibuf);
- break;
- }
- IMB_moviecacheIter_step(iter);
- }
- IMB_moviecacheIter_free(iter);
- }
- BLI_spin_unlock(&image_spin);
+ while (!IMB_moviecacheIter_done(iter)) {
+ ImBuf *current_ibuf = IMB_moviecacheIter_getImBuf(iter);
+ if (STREQ(current_ibuf->name, name)) {
+ ibuf = current_ibuf;
+ IMB_refImBuf(ibuf);
+ break;
+ }
+ IMB_moviecacheIter_step(iter);
+ }
+ IMB_moviecacheIter_free(iter);
+ }
+ BLI_spin_unlock(&image_spin);
- return ibuf;
+ return ibuf;
}
/**
@@ -4809,189 +5014,195 @@ ImBuf *BKE_image_get_ibuf_with_name(Image *image, const char *name)
*/
ImBuf *BKE_image_get_first_ibuf(Image *image)
{
- ImBuf *ibuf = NULL;
+ ImBuf *ibuf = NULL;
- BLI_spin_lock(&image_spin);
- if (image->cache != NULL) {
- struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache);
+ BLI_spin_lock(&image_spin);
+ if (image->cache != NULL) {
+ struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache);
- while (!IMB_moviecacheIter_done(iter)) {
- ibuf = IMB_moviecacheIter_getImBuf(iter);
- IMB_refImBuf(ibuf);
- break;
- }
- IMB_moviecacheIter_free(iter);
- }
- BLI_spin_unlock(&image_spin);
+ while (!IMB_moviecacheIter_done(iter)) {
+ ibuf = IMB_moviecacheIter_getImBuf(iter);
+ IMB_refImBuf(ibuf);
+ break;
+ }
+ IMB_moviecacheIter_free(iter);
+ }
+ BLI_spin_unlock(&image_spin);
- return ibuf;
+ return ibuf;
}
static void image_update_views_format(Image *ima, ImageUser *iuser)
{
- SceneRenderView *srv;
- ImageView *iv;
- Scene *scene = iuser->scene;
- const bool is_multiview = ((scene->r.scemode & R_MULTIVIEW) != 0) &&
- ((ima->flag & IMA_USE_VIEWS) != 0);
-
- /* reset the image views */
- BKE_image_free_views(ima);
-
- if (!is_multiview) {
- /* nothing to do */
- }
- else if (ima->views_format == R_IMF_VIEWS_STEREO_3D) {
- int i;
- const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
-
- for (i = 0; i < 2; i++) {
- image_add_view(ima, names[i], ima->name);
- }
- return;
- }
- else {
- /* R_IMF_VIEWS_INDIVIDUAL */
- char prefix[FILE_MAX] = {'\0'};
- char *name = ima->name;
- const char *ext = NULL;
-
- BKE_scene_multiview_view_prefix_get(scene, name, prefix, &ext);
-
- if (prefix[0] == '\0') {
- BKE_image_free_views(ima);
- return;
- }
-
- /* create all the image views */
- for (srv = scene->r.views.first; srv; srv = srv->next) {
- if (BKE_scene_multiview_is_render_view_active(&scene->r, srv)) {
- char filepath[FILE_MAX];
- SNPRINTF(filepath, "%s%s%s", prefix, srv->suffix, ext);
- image_add_view(ima, srv->name, filepath);
- }
- }
-
- /* check if the files are all available */
- iv = ima->views.last;
- while (iv) {
- int file;
- char str[FILE_MAX];
-
- STRNCPY(str, iv->filepath);
- BLI_path_abs(str, BKE_main_blendfile_path_from_global());
-
- /* exists? */
- file = BLI_open(str, O_BINARY | O_RDONLY, 0);
- if (file == -1) {
- ImageView *iv_del = iv;
- iv = iv->prev;
- BLI_remlink(&ima->views, iv_del);
- MEM_freeN(iv_del);
- }
- else {
- iv = iv->prev;
- close(file);
- }
- }
-
- /* all good */
- if (!BKE_image_is_multiview(ima)) {
- BKE_image_free_views(ima);
- }
- }
+ SceneRenderView *srv;
+ ImageView *iv;
+ Scene *scene = iuser->scene;
+ const bool is_multiview = ((scene->r.scemode & R_MULTIVIEW) != 0) &&
+ ((ima->flag & IMA_USE_VIEWS) != 0);
+
+ /* reset the image views */
+ BKE_image_free_views(ima);
+
+ if (!is_multiview) {
+ /* nothing to do */
+ }
+ else if (ima->views_format == R_IMF_VIEWS_STEREO_3D) {
+ int i;
+ const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
+
+ for (i = 0; i < 2; i++) {
+ image_add_view(ima, names[i], ima->name);
+ }
+ return;
+ }
+ else {
+ /* R_IMF_VIEWS_INDIVIDUAL */
+ char prefix[FILE_MAX] = {'\0'};
+ char *name = ima->name;
+ const char *ext = NULL;
+
+ BKE_scene_multiview_view_prefix_get(scene, name, prefix, &ext);
+
+ if (prefix[0] == '\0') {
+ BKE_image_free_views(ima);
+ return;
+ }
+
+ /* create all the image views */
+ for (srv = scene->r.views.first; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(&scene->r, srv)) {
+ char filepath[FILE_MAX];
+ SNPRINTF(filepath, "%s%s%s", prefix, srv->suffix, ext);
+ image_add_view(ima, srv->name, filepath);
+ }
+ }
+
+ /* check if the files are all available */
+ iv = ima->views.last;
+ while (iv) {
+ int file;
+ char str[FILE_MAX];
+
+ STRNCPY(str, iv->filepath);
+ BLI_path_abs(str, BKE_main_blendfile_path_from_global());
+
+ /* exists? */
+ file = BLI_open(str, O_BINARY | O_RDONLY, 0);
+ if (file == -1) {
+ ImageView *iv_del = iv;
+ iv = iv->prev;
+ BLI_remlink(&ima->views, iv_del);
+ MEM_freeN(iv_del);
+ }
+ else {
+ iv = iv->prev;
+ close(file);
+ }
+ }
+
+ /* all good */
+ if (!BKE_image_is_multiview(ima)) {
+ BKE_image_free_views(ima);
+ }
+ }
}
/**************************** Render Slots ***************************/
RenderSlot *BKE_image_add_renderslot(Image *ima, const char *name)
{
- RenderSlot *slot = MEM_callocN(sizeof(RenderSlot), "Image new Render Slot");
- if (name && name[0]) {
- BLI_strncpy(slot->name, name, sizeof(slot->name));
- }
- else {
- int n = BLI_listbase_count(&ima->renderslots) + 1;
- BLI_snprintf(slot->name, sizeof(slot->name), "Slot %d", n);
- }
- BLI_addtail(&ima->renderslots, slot);
- return slot;
+ RenderSlot *slot = MEM_callocN(sizeof(RenderSlot), "Image new Render Slot");
+ if (name && name[0]) {
+ BLI_strncpy(slot->name, name, sizeof(slot->name));
+ }
+ else {
+ int n = BLI_listbase_count(&ima->renderslots) + 1;
+ BLI_snprintf(slot->name, sizeof(slot->name), "Slot %d", n);
+ }
+ BLI_addtail(&ima->renderslots, slot);
+ return slot;
}
bool BKE_image_remove_renderslot(Image *ima, ImageUser *iuser, int index)
{
- int num_slots = BLI_listbase_count(&ima->renderslots);
- if (index >= num_slots || num_slots == 1) {
- return false;
- }
-
- RenderSlot *remove_slot = BLI_findlink(&ima->renderslots, index);
- RenderSlot *current_slot = BLI_findlink(&ima->renderslots, ima->render_slot);
- RenderSlot *current_last_slot = BLI_findlink(&ima->renderslots, ima->last_render_slot);
-
- RenderSlot *next_slot;
- if (current_slot == remove_slot) {
- next_slot = BLI_findlink(&ima->renderslots, (index == num_slots - 1) ? index - 1 : index + 1);
- }
- else {
- next_slot = current_slot;
- }
-
- /* If the slot to be removed is the slot with the last render, make another slot the last render slot. */
- if (remove_slot == current_last_slot) {
- /* Choose the currently selected slot unless that one is being removed, in that case take the next one. */
- RenderSlot *next_last_slot;
- if (current_slot == remove_slot)
- next_last_slot = next_slot;
- else
- next_last_slot = current_slot;
-
- if (!iuser) return false;
- Render *re = RE_GetSceneRender(iuser->scene);
- if (!re) return false;
- RE_SwapResult(re, &current_last_slot->render);
- RE_SwapResult(re, &next_last_slot->render);
- current_last_slot = next_last_slot;
- }
-
- current_slot = next_slot;
-
- BLI_remlink(&ima->renderslots, remove_slot);
-
- ima->render_slot = BLI_findindex(&ima->renderslots, current_slot);
- ima->last_render_slot = BLI_findindex(&ima->renderslots, current_last_slot);
-
- if (remove_slot->render) {
- RE_FreeRenderResult(remove_slot->render);
- }
- MEM_freeN(remove_slot);
-
- return true;
+ int num_slots = BLI_listbase_count(&ima->renderslots);
+ if (index >= num_slots || num_slots == 1) {
+ return false;
+ }
+
+ RenderSlot *remove_slot = BLI_findlink(&ima->renderslots, index);
+ RenderSlot *current_slot = BLI_findlink(&ima->renderslots, ima->render_slot);
+ RenderSlot *current_last_slot = BLI_findlink(&ima->renderslots, ima->last_render_slot);
+
+ RenderSlot *next_slot;
+ if (current_slot == remove_slot) {
+ next_slot = BLI_findlink(&ima->renderslots, (index == num_slots - 1) ? index - 1 : index + 1);
+ }
+ else {
+ next_slot = current_slot;
+ }
+
+ /* If the slot to be removed is the slot with the last render, make another slot the last render slot. */
+ if (remove_slot == current_last_slot) {
+ /* Choose the currently selected slot unless that one is being removed, in that case take the next one. */
+ RenderSlot *next_last_slot;
+ if (current_slot == remove_slot)
+ next_last_slot = next_slot;
+ else
+ next_last_slot = current_slot;
+
+ if (!iuser)
+ return false;
+ Render *re = RE_GetSceneRender(iuser->scene);
+ if (!re)
+ return false;
+ RE_SwapResult(re, &current_last_slot->render);
+ RE_SwapResult(re, &next_last_slot->render);
+ current_last_slot = next_last_slot;
+ }
+
+ current_slot = next_slot;
+
+ BLI_remlink(&ima->renderslots, remove_slot);
+
+ ima->render_slot = BLI_findindex(&ima->renderslots, current_slot);
+ ima->last_render_slot = BLI_findindex(&ima->renderslots, current_last_slot);
+
+ if (remove_slot->render) {
+ RE_FreeRenderResult(remove_slot->render);
+ }
+ MEM_freeN(remove_slot);
+
+ return true;
}
bool BKE_image_clear_renderslot(Image *ima, ImageUser *iuser, int index)
{
- if (index == ima->last_render_slot) {
- if (!iuser) return false;
- if (G.is_rendering) return false;
- Render *re = RE_GetSceneRender(iuser->scene);
- if (!re) return false;
- RE_ClearResult(re);
- return true;
- }
- else {
- RenderSlot *slot = BLI_findlink(&ima->renderslots, index);
- if (!slot) return false;
- if (slot->render) {
- RE_FreeRenderResult(slot->render);
- slot->render = NULL;
- }
- return true;
- }
+ if (index == ima->last_render_slot) {
+ if (!iuser)
+ return false;
+ if (G.is_rendering)
+ return false;
+ Render *re = RE_GetSceneRender(iuser->scene);
+ if (!re)
+ return false;
+ RE_ClearResult(re);
+ return true;
+ }
+ else {
+ RenderSlot *slot = BLI_findlink(&ima->renderslots, index);
+ if (!slot)
+ return false;
+ if (slot->render) {
+ RE_FreeRenderResult(slot->render);
+ slot->render = NULL;
+ }
+ return true;
+ }
}
RenderSlot *BKE_image_get_renderslot(Image *ima, int index)
{
- /* Can be NULL for images without render slots. */
- return BLI_findlink(&ima->renderslots, index);
+ /* Can be NULL for images without render slots. */
+ return BLI_findlink(&ima->renderslots, index);
}
diff --git a/source/blender/blenkernel/intern/image_gen.c b/source/blender/blenkernel/intern/image_gen.c
index 2df3495b78e..9972e90dcdd 100644
--- a/source/blender/blenkernel/intern/image_gen.c
+++ b/source/blender/blenkernel/intern/image_gen.c
@@ -33,260 +33,237 @@
#include "BLF_api.h"
typedef struct FillColorThreadData {
- unsigned char *rect;
- float *rect_float;
- int width;
- float color[4];
+ unsigned char *rect;
+ float *rect_float;
+ int width;
+ float color[4];
} FillColorThreadData;
-static void image_buf_fill_color_slice(unsigned char *rect,
- float *rect_float,
- int width, int height,
- const float color[4])
+static void image_buf_fill_color_slice(
+ unsigned char *rect, float *rect_float, int width, int height, const float color[4])
{
- int x, y;
-
- /* blank image */
- if (rect_float) {
- float linear_color[4];
- srgb_to_linearrgb_v4(linear_color, color);
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x++) {
- copy_v4_v4(rect_float, linear_color);
- rect_float += 4;
- }
- }
- }
-
- if (rect) {
- unsigned char ccol[4];
- rgba_float_to_uchar(ccol, color);
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x++) {
- rect[0] = ccol[0];
- rect[1] = ccol[1];
- rect[2] = ccol[2];
- rect[3] = ccol[3];
- rect += 4;
- }
- }
- }
+ int x, y;
+
+ /* blank image */
+ if (rect_float) {
+ float linear_color[4];
+ srgb_to_linearrgb_v4(linear_color, color);
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ copy_v4_v4(rect_float, linear_color);
+ rect_float += 4;
+ }
+ }
+ }
+
+ if (rect) {
+ unsigned char ccol[4];
+ rgba_float_to_uchar(ccol, color);
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ rect[0] = ccol[0];
+ rect[1] = ccol[1];
+ rect[2] = ccol[2];
+ rect[3] = ccol[3];
+ rect += 4;
+ }
+ }
+ }
}
-static void image_buf_fill_color_thread_do(void *data_v,
- int start_scanline,
- int num_scanlines)
+static void image_buf_fill_color_thread_do(void *data_v, int start_scanline, int num_scanlines)
{
- FillColorThreadData *data = (FillColorThreadData *)data_v;
- size_t offset = ((size_t)start_scanline) * data->width * 4;
- unsigned char *rect = (data->rect != NULL) ? (data->rect + offset) : NULL;
- float *rect_float = (data->rect_float != NULL) ? (data->rect_float + offset) : NULL;
- image_buf_fill_color_slice(rect,
- rect_float,
- data->width,
- num_scanlines,
- data->color);
+ FillColorThreadData *data = (FillColorThreadData *)data_v;
+ size_t offset = ((size_t)start_scanline) * data->width * 4;
+ unsigned char *rect = (data->rect != NULL) ? (data->rect + offset) : NULL;
+ float *rect_float = (data->rect_float != NULL) ? (data->rect_float + offset) : NULL;
+ image_buf_fill_color_slice(rect, rect_float, data->width, num_scanlines, data->color);
}
-void BKE_image_buf_fill_color(unsigned char *rect,
- float *rect_float,
- int width, int height,
- const float color[4])
+void BKE_image_buf_fill_color(
+ unsigned char *rect, float *rect_float, int width, int height, const float color[4])
{
- if (((size_t)width) * height < 64 * 64) {
- image_buf_fill_color_slice(rect, rect_float, width, height, color);
- }
- else {
- FillColorThreadData data;
- data.rect = rect;
- data.rect_float = rect_float;
- data.width = width;
- copy_v4_v4(data.color, color);
- IMB_processor_apply_threaded_scanlines(
- height, image_buf_fill_color_thread_do, &data);
- }
+ if (((size_t)width) * height < 64 * 64) {
+ image_buf_fill_color_slice(rect, rect_float, width, height, color);
+ }
+ else {
+ FillColorThreadData data;
+ data.rect = rect;
+ data.rect_float = rect_float;
+ data.width = width;
+ copy_v4_v4(data.color, color);
+ IMB_processor_apply_threaded_scanlines(height, image_buf_fill_color_thread_do, &data);
+ }
}
-static void image_buf_fill_checker_slice(unsigned char *rect,
- float *rect_float,
- int width, int height,
- int offset)
+static void image_buf_fill_checker_slice(
+ unsigned char *rect, float *rect_float, int width, int height, int offset)
{
- /* these two passes could be combined into one, but it's more readable and
- * easy to tweak like this, speed isn't really that much of an issue in this situation... */
-
- int checkerwidth = 32, dark = 1;
- int x, y;
-
- unsigned char *rect_orig = rect;
- float *rect_float_orig = rect_float;
-
-
- float h = 0.0, hoffs = 0.0;
- float hsv[3] = {0.0f, 0.9f, 0.9f};
- float rgb[3];
-
- float dark_linear_color = 0.0f, bright_linear_color = 0.0f;
- if (rect_float != NULL) {
- dark_linear_color = srgb_to_linearrgb(0.25f);
- bright_linear_color = srgb_to_linearrgb(0.58f);
- }
-
- /* checkers */
- for (y = offset; y < height + offset; y++) {
- dark = powf(-1.0f, floorf(y / checkerwidth));
-
- for (x = 0; x < width; x++) {
- if (x % checkerwidth == 0) dark = -dark;
-
- if (rect_float) {
- if (dark > 0) {
- rect_float[0] = rect_float[1] = rect_float[2] = dark_linear_color;
- rect_float[3] = 1.0f;
- }
- else {
- rect_float[0] = rect_float[1] = rect_float[2] = bright_linear_color;
- rect_float[3] = 1.0f;
- }
- rect_float += 4;
- }
- else {
- if (dark > 0) {
- rect[0] = rect[1] = rect[2] = 64;
- rect[3] = 255;
- }
- else {
- rect[0] = rect[1] = rect[2] = 150;
- rect[3] = 255;
- }
- rect += 4;
- }
- }
- }
-
- rect = rect_orig;
- rect_float = rect_float_orig;
-
- /* 2nd pass, colored + */
- for (y = offset; y < height + offset; y++) {
- hoffs = 0.125f * floorf(y / checkerwidth);
-
- for (x = 0; x < width; x++) {
- h = 0.125f * floorf(x / checkerwidth);
-
- if ((abs((x % checkerwidth) - (checkerwidth / 2)) < 4) &&
- (abs((y % checkerwidth) - (checkerwidth / 2)) < 4))
- {
- if ((abs((x % checkerwidth) - (checkerwidth / 2)) < 1) ||
- (abs((y % checkerwidth) - (checkerwidth / 2)) < 1))
- {
- hsv[0] = fmodf(fabsf(h - hoffs), 1.0f);
- hsv_to_rgb_v(hsv, rgb);
-
- if (rect) {
- rect[0] = (char)(rgb[0] * 255.0f);
- rect[1] = (char)(rgb[1] * 255.0f);
- rect[2] = (char)(rgb[2] * 255.0f);
- rect[3] = 255;
- }
-
- if (rect_float) {
- srgb_to_linearrgb_v3_v3(rect_float, rgb);
- rect_float[3] = 1.0f;
- }
- }
- }
-
- if (rect_float) rect_float += 4;
- if (rect) rect += 4;
- }
- }
+ /* these two passes could be combined into one, but it's more readable and
+ * easy to tweak like this, speed isn't really that much of an issue in this situation... */
+
+ int checkerwidth = 32, dark = 1;
+ int x, y;
+
+ unsigned char *rect_orig = rect;
+ float *rect_float_orig = rect_float;
+
+ float h = 0.0, hoffs = 0.0;
+ float hsv[3] = {0.0f, 0.9f, 0.9f};
+ float rgb[3];
+
+ float dark_linear_color = 0.0f, bright_linear_color = 0.0f;
+ if (rect_float != NULL) {
+ dark_linear_color = srgb_to_linearrgb(0.25f);
+ bright_linear_color = srgb_to_linearrgb(0.58f);
+ }
+
+ /* checkers */
+ for (y = offset; y < height + offset; y++) {
+ dark = powf(-1.0f, floorf(y / checkerwidth));
+
+ for (x = 0; x < width; x++) {
+ if (x % checkerwidth == 0)
+ dark = -dark;
+
+ if (rect_float) {
+ if (dark > 0) {
+ rect_float[0] = rect_float[1] = rect_float[2] = dark_linear_color;
+ rect_float[3] = 1.0f;
+ }
+ else {
+ rect_float[0] = rect_float[1] = rect_float[2] = bright_linear_color;
+ rect_float[3] = 1.0f;
+ }
+ rect_float += 4;
+ }
+ else {
+ if (dark > 0) {
+ rect[0] = rect[1] = rect[2] = 64;
+ rect[3] = 255;
+ }
+ else {
+ rect[0] = rect[1] = rect[2] = 150;
+ rect[3] = 255;
+ }
+ rect += 4;
+ }
+ }
+ }
+
+ rect = rect_orig;
+ rect_float = rect_float_orig;
+
+ /* 2nd pass, colored + */
+ for (y = offset; y < height + offset; y++) {
+ hoffs = 0.125f * floorf(y / checkerwidth);
+
+ for (x = 0; x < width; x++) {
+ h = 0.125f * floorf(x / checkerwidth);
+
+ if ((abs((x % checkerwidth) - (checkerwidth / 2)) < 4) &&
+ (abs((y % checkerwidth) - (checkerwidth / 2)) < 4)) {
+ if ((abs((x % checkerwidth) - (checkerwidth / 2)) < 1) ||
+ (abs((y % checkerwidth) - (checkerwidth / 2)) < 1)) {
+ hsv[0] = fmodf(fabsf(h - hoffs), 1.0f);
+ hsv_to_rgb_v(hsv, rgb);
+
+ if (rect) {
+ rect[0] = (char)(rgb[0] * 255.0f);
+ rect[1] = (char)(rgb[1] * 255.0f);
+ rect[2] = (char)(rgb[2] * 255.0f);
+ rect[3] = 255;
+ }
+
+ if (rect_float) {
+ srgb_to_linearrgb_v3_v3(rect_float, rgb);
+ rect_float[3] = 1.0f;
+ }
+ }
+ }
+
+ if (rect_float)
+ rect_float += 4;
+ if (rect)
+ rect += 4;
+ }
+ }
}
typedef struct FillCheckerThreadData {
- unsigned char *rect;
- float *rect_float;
- int width;
+ unsigned char *rect;
+ float *rect_float;
+ int width;
} FillCheckerThreadData;
-static void image_buf_fill_checker_thread_do(void *data_v,
- int start_scanline,
- int num_scanlines)
+static void image_buf_fill_checker_thread_do(void *data_v, int start_scanline, int num_scanlines)
{
- FillCheckerThreadData *data = (FillCheckerThreadData *)data_v;
- size_t offset = ((size_t)start_scanline) * data->width * 4;
- unsigned char *rect = (data->rect != NULL) ? (data->rect + offset) : NULL;
- float *rect_float = (data->rect_float != NULL) ? (data->rect_float + offset) : NULL;
- image_buf_fill_checker_slice(rect,
- rect_float,
- data->width,
- num_scanlines,
- start_scanline);
+ FillCheckerThreadData *data = (FillCheckerThreadData *)data_v;
+ size_t offset = ((size_t)start_scanline) * data->width * 4;
+ unsigned char *rect = (data->rect != NULL) ? (data->rect + offset) : NULL;
+ float *rect_float = (data->rect_float != NULL) ? (data->rect_float + offset) : NULL;
+ image_buf_fill_checker_slice(rect, rect_float, data->width, num_scanlines, start_scanline);
}
-void BKE_image_buf_fill_checker(unsigned char *rect,
- float *rect_float,
- int width, int height)
+void BKE_image_buf_fill_checker(unsigned char *rect, float *rect_float, int width, int height)
{
- if (((size_t)width) * height < 64 * 64) {
- image_buf_fill_checker_slice(rect, rect_float, width, height, 0);
- }
- else {
- FillCheckerThreadData data;
- data.rect = rect;
- data.rect_float = rect_float;
- data.width = width;
- IMB_processor_apply_threaded_scanlines(
- height, image_buf_fill_checker_thread_do, &data);
- }
+ if (((size_t)width) * height < 64 * 64) {
+ image_buf_fill_checker_slice(rect, rect_float, width, height, 0);
+ }
+ else {
+ FillCheckerThreadData data;
+ data.rect = rect;
+ data.rect_float = rect_float;
+ data.width = width;
+ IMB_processor_apply_threaded_scanlines(height, image_buf_fill_checker_thread_do, &data);
+ }
}
/* Utility functions for BKE_image_buf_fill_checker_color */
-#define BLEND_FLOAT(real, add) (real + add <= 1.0f) ? (real + add) : 1.0f
-#define BLEND_CHAR(real, add) ((real + (char)(add * 255.0f)) <= 255) ? (real + (char)(add * 255.0f)) : 255
+#define BLEND_FLOAT(real, add) (real + add <= 1.0f) ? (real + add) : 1.0f
+#define BLEND_CHAR(real, add) \
+ ((real + (char)(add * 255.0f)) <= 255) ? (real + (char)(add * 255.0f)) : 255
-static void checker_board_color_fill(unsigned char *rect,
- float *rect_float,
- int width,
- int height,
- int offset,
- int total_height)
+static void checker_board_color_fill(
+ unsigned char *rect, float *rect_float, int width, int height, int offset, int total_height)
{
- int hue_step, y, x;
- float hsv[3], rgb[3];
-
- hsv[1] = 1.0;
-
- hue_step = power_of_2_max_i(width / 8);
- if (hue_step < 8) hue_step = 8;
-
- for (y = offset; y < height + offset; y++) {
-
- hsv[2] = 0.1 + (y * (0.4 / total_height)); /* use a number lower then 1.0 else its too bright */
- for (x = 0; x < width; x++) {
- hsv[0] = (float)((double)(x / hue_step) * 1.0 / width * hue_step);
- hsv_to_rgb_v(hsv, rgb);
-
- if (rect) {
- rect[0] = (char)(rgb[0] * 255.0f);
- rect[1] = (char)(rgb[1] * 255.0f);
- rect[2] = (char)(rgb[2] * 255.0f);
- rect[3] = 255;
-
- rect += 4;
- }
-
- if (rect_float) {
- rect_float[0] = rgb[0];
- rect_float[1] = rgb[1];
- rect_float[2] = rgb[2];
- rect_float[3] = 1.0f;
-
- rect_float += 4;
- }
- }
- }
+ int hue_step, y, x;
+ float hsv[3], rgb[3];
+
+ hsv[1] = 1.0;
+
+ hue_step = power_of_2_max_i(width / 8);
+ if (hue_step < 8)
+ hue_step = 8;
+
+ for (y = offset; y < height + offset; y++) {
+
+ hsv[2] = 0.1 +
+ (y * (0.4 / total_height)); /* use a number lower then 1.0 else its too bright */
+ for (x = 0; x < width; x++) {
+ hsv[0] = (float)((double)(x / hue_step) * 1.0 / width * hue_step);
+ hsv_to_rgb_v(hsv, rgb);
+
+ if (rect) {
+ rect[0] = (char)(rgb[0] * 255.0f);
+ rect[1] = (char)(rgb[1] * 255.0f);
+ rect[2] = (char)(rgb[2] * 255.0f);
+ rect[3] = 255;
+
+ rect += 4;
+ }
+
+ if (rect_float) {
+ rect_float[0] = rgb[0];
+ rect_float[1] = rgb[1];
+ rect_float[2] = rgb[2];
+ rect_float[3] = 1.0f;
+
+ rect_float += 4;
+ }
+ }
+ }
}
static void checker_board_color_tint(unsigned char *rect,
@@ -297,222 +274,211 @@ static void checker_board_color_tint(unsigned char *rect,
float blend,
int offset)
{
- int x, y;
- float blend_half = blend * 0.5f;
-
- for (y = offset; y < height + offset; y++) {
- for (x = 0; x < width; x++) {
- if (((y / size) % 2 == 1 && (x / size) % 2 == 1) ||
- ((y / size) % 2 == 0 && (x / size) % 2 == 0))
- {
- if (rect) {
- rect[0] = (char)BLEND_CHAR(rect[0], blend);
- rect[1] = (char)BLEND_CHAR(rect[1], blend);
- rect[2] = (char)BLEND_CHAR(rect[2], blend);
- rect[3] = 255;
-
- rect += 4;
- }
- if (rect_float) {
- rect_float[0] = BLEND_FLOAT(rect_float[0], blend);
- rect_float[1] = BLEND_FLOAT(rect_float[1], blend);
- rect_float[2] = BLEND_FLOAT(rect_float[2], blend);
- rect_float[3] = 1.0f;
-
- rect_float += 4;
- }
- }
- else {
- if (rect) {
- rect[0] = (char)BLEND_CHAR(rect[0], blend_half);
- rect[1] = (char)BLEND_CHAR(rect[1], blend_half);
- rect[2] = (char)BLEND_CHAR(rect[2], blend_half);
- rect[3] = 255;
-
- rect += 4;
- }
- if (rect_float) {
- rect_float[0] = BLEND_FLOAT(rect_float[0], blend_half);
- rect_float[1] = BLEND_FLOAT(rect_float[1], blend_half);
- rect_float[2] = BLEND_FLOAT(rect_float[2], blend_half);
- rect_float[3] = 1.0f;
-
- rect_float += 4;
- }
- }
-
- }
- }
+ int x, y;
+ float blend_half = blend * 0.5f;
+
+ for (y = offset; y < height + offset; y++) {
+ for (x = 0; x < width; x++) {
+ if (((y / size) % 2 == 1 && (x / size) % 2 == 1) ||
+ ((y / size) % 2 == 0 && (x / size) % 2 == 0)) {
+ if (rect) {
+ rect[0] = (char)BLEND_CHAR(rect[0], blend);
+ rect[1] = (char)BLEND_CHAR(rect[1], blend);
+ rect[2] = (char)BLEND_CHAR(rect[2], blend);
+ rect[3] = 255;
+
+ rect += 4;
+ }
+ if (rect_float) {
+ rect_float[0] = BLEND_FLOAT(rect_float[0], blend);
+ rect_float[1] = BLEND_FLOAT(rect_float[1], blend);
+ rect_float[2] = BLEND_FLOAT(rect_float[2], blend);
+ rect_float[3] = 1.0f;
+
+ rect_float += 4;
+ }
+ }
+ else {
+ if (rect) {
+ rect[0] = (char)BLEND_CHAR(rect[0], blend_half);
+ rect[1] = (char)BLEND_CHAR(rect[1], blend_half);
+ rect[2] = (char)BLEND_CHAR(rect[2], blend_half);
+ rect[3] = 255;
+
+ rect += 4;
+ }
+ if (rect_float) {
+ rect_float[0] = BLEND_FLOAT(rect_float[0], blend_half);
+ rect_float[1] = BLEND_FLOAT(rect_float[1], blend_half);
+ rect_float[2] = BLEND_FLOAT(rect_float[2], blend_half);
+ rect_float[3] = 1.0f;
+
+ rect_float += 4;
+ }
+ }
+ }
+ }
}
-static void checker_board_grid_fill(unsigned char *rect,
- float *rect_float,
- int width,
- int height,
- float blend,
- int offset)
+static void checker_board_grid_fill(
+ unsigned char *rect, float *rect_float, int width, int height, float blend, int offset)
{
- int x, y;
- for (y = offset; y < height + offset; y++) {
- for (x = 0; x < width; x++) {
- if (((y % 32) == 0) || ((x % 32) == 0) || x == 0) {
- if (rect) {
- rect[0] = BLEND_CHAR(rect[0], blend);
- rect[1] = BLEND_CHAR(rect[1], blend);
- rect[2] = BLEND_CHAR(rect[2], blend);
- rect[3] = 255;
-
- rect += 4;
- }
- if (rect_float) {
- rect_float[0] = BLEND_FLOAT(rect_float[0], blend);
- rect_float[1] = BLEND_FLOAT(rect_float[1], blend);
- rect_float[2] = BLEND_FLOAT(rect_float[2], blend);
- rect_float[3] = 1.0f;
-
- rect_float += 4;
- }
- }
- else {
- if (rect_float) rect_float += 4;
- if (rect) rect += 4;
- }
- }
- }
+ int x, y;
+ for (y = offset; y < height + offset; y++) {
+ for (x = 0; x < width; x++) {
+ if (((y % 32) == 0) || ((x % 32) == 0) || x == 0) {
+ if (rect) {
+ rect[0] = BLEND_CHAR(rect[0], blend);
+ rect[1] = BLEND_CHAR(rect[1], blend);
+ rect[2] = BLEND_CHAR(rect[2], blend);
+ rect[3] = 255;
+
+ rect += 4;
+ }
+ if (rect_float) {
+ rect_float[0] = BLEND_FLOAT(rect_float[0], blend);
+ rect_float[1] = BLEND_FLOAT(rect_float[1], blend);
+ rect_float[2] = BLEND_FLOAT(rect_float[2], blend);
+ rect_float[3] = 1.0f;
+
+ rect_float += 4;
+ }
+ }
+ else {
+ if (rect_float)
+ rect_float += 4;
+ if (rect)
+ rect += 4;
+ }
+ }
+ }
}
/* defined in image.c */
-static void checker_board_text(unsigned char *rect,
- float *rect_float,
- int width,
- int height,
- int step,
- int outline)
+static void checker_board_text(
+ unsigned char *rect, float *rect_float, int width, int height, int step, int outline)
{
- int x, y;
- int pen_x, pen_y;
- char text[3] = {'A', '1', '\0'};
- const int mono = blf_mono_font_render;
-
- BLF_size(mono, 54, 72); /* hard coded size! */
-
- /* OCIO_TODO: using NULL as display will assume using sRGB display
- * this is correct since currently generated images are assumed to be in sRGB space,
- * but this would probably needed to be fixed in some way
- */
- BLF_buffer(mono, rect_float, rect, width, height, 4, NULL);
-
- const float text_color[4] = {0.0, 0.0, 0.0, 1.0};
- const float text_outline[4] = {1.0, 1.0, 1.0, 1.0};
-
- for (y = 0; y < height; y += step) {
- text[1] = '1';
-
- for (x = 0; x < width; x += step) {
- /* hard coded offset */
- pen_x = x + 33;
- pen_y = y + 44;
-
- /* terribly crappy outline font! */
- BLF_buffer_col(mono, text_outline);
-
- BLF_position(mono, pen_x - outline, pen_y, 0.0);
- BLF_draw_buffer(mono, text, 2);
- BLF_position(mono, pen_x + outline, pen_y, 0.0);
- BLF_draw_buffer(mono, text, 2);
- BLF_position(mono, pen_x, pen_y - outline, 0.0);
- BLF_draw_buffer(mono, text, 2);
- BLF_position(mono, pen_x, pen_y + outline, 0.0);
- BLF_draw_buffer(mono, text, 2);
-
- BLF_position(mono, pen_x - outline, pen_y - outline, 0.0);
- BLF_draw_buffer(mono, text, 2);
- BLF_position(mono, pen_x + outline, pen_y + outline, 0.0);
- BLF_draw_buffer(mono, text, 2);
- BLF_position(mono, pen_x - outline, pen_y + outline, 0.0);
- BLF_draw_buffer(mono, text, 2);
- BLF_position(mono, pen_x + outline, pen_y - outline, 0.0);
- BLF_draw_buffer(mono, text, 2);
-
- BLF_buffer_col(mono, text_color);
- BLF_position(mono, pen_x, pen_y, 0.0);
- BLF_draw_buffer(mono, text, 2);
-
- text[1]++;
- }
- text[0]++;
- }
-
- /* cleanup the buffer. */
- BLF_buffer(mono, NULL, NULL, 0, 0, 0, NULL);
+ int x, y;
+ int pen_x, pen_y;
+ char text[3] = {'A', '1', '\0'};
+ const int mono = blf_mono_font_render;
+
+ BLF_size(mono, 54, 72); /* hard coded size! */
+
+ /* OCIO_TODO: using NULL as display will assume using sRGB display
+ * this is correct since currently generated images are assumed to be in sRGB space,
+ * but this would probably needed to be fixed in some way
+ */
+ BLF_buffer(mono, rect_float, rect, width, height, 4, NULL);
+
+ const float text_color[4] = {0.0, 0.0, 0.0, 1.0};
+ const float text_outline[4] = {1.0, 1.0, 1.0, 1.0};
+
+ for (y = 0; y < height; y += step) {
+ text[1] = '1';
+
+ for (x = 0; x < width; x += step) {
+ /* hard coded offset */
+ pen_x = x + 33;
+ pen_y = y + 44;
+
+ /* terribly crappy outline font! */
+ BLF_buffer_col(mono, text_outline);
+
+ BLF_position(mono, pen_x - outline, pen_y, 0.0);
+ BLF_draw_buffer(mono, text, 2);
+ BLF_position(mono, pen_x + outline, pen_y, 0.0);
+ BLF_draw_buffer(mono, text, 2);
+ BLF_position(mono, pen_x, pen_y - outline, 0.0);
+ BLF_draw_buffer(mono, text, 2);
+ BLF_position(mono, pen_x, pen_y + outline, 0.0);
+ BLF_draw_buffer(mono, text, 2);
+
+ BLF_position(mono, pen_x - outline, pen_y - outline, 0.0);
+ BLF_draw_buffer(mono, text, 2);
+ BLF_position(mono, pen_x + outline, pen_y + outline, 0.0);
+ BLF_draw_buffer(mono, text, 2);
+ BLF_position(mono, pen_x - outline, pen_y + outline, 0.0);
+ BLF_draw_buffer(mono, text, 2);
+ BLF_position(mono, pen_x + outline, pen_y - outline, 0.0);
+ BLF_draw_buffer(mono, text, 2);
+
+ BLF_buffer_col(mono, text_color);
+ BLF_position(mono, pen_x, pen_y, 0.0);
+ BLF_draw_buffer(mono, text, 2);
+
+ text[1]++;
+ }
+ text[0]++;
+ }
+
+ /* cleanup the buffer. */
+ BLF_buffer(mono, NULL, NULL, 0, 0, 0, NULL);
}
-static void checker_board_color_prepare_slice(unsigned char *rect,
- float *rect_float,
- int width,
- int height,
- int offset,
- int total_height)
+static void checker_board_color_prepare_slice(
+ unsigned char *rect, float *rect_float, int width, int height, int offset, int total_height)
{
- checker_board_color_fill(rect, rect_float, width, height, offset, total_height);
- checker_board_color_tint(rect, rect_float, width, height, 1, 0.03f, offset);
- checker_board_color_tint(rect, rect_float, width, height, 4, 0.05f, offset);
- checker_board_color_tint(rect, rect_float, width, height, 32, 0.07f, offset);
- checker_board_color_tint(rect, rect_float, width, height, 128, 0.15f, offset);
- checker_board_grid_fill(rect, rect_float, width, height, 1.0f / 4.0f, offset);
+ checker_board_color_fill(rect, rect_float, width, height, offset, total_height);
+ checker_board_color_tint(rect, rect_float, width, height, 1, 0.03f, offset);
+ checker_board_color_tint(rect, rect_float, width, height, 4, 0.05f, offset);
+ checker_board_color_tint(rect, rect_float, width, height, 32, 0.07f, offset);
+ checker_board_color_tint(rect, rect_float, width, height, 128, 0.15f, offset);
+ checker_board_grid_fill(rect, rect_float, width, height, 1.0f / 4.0f, offset);
}
typedef struct FillCheckerColorThreadData {
- unsigned char *rect;
- float *rect_float;
- int width, height;
+ unsigned char *rect;
+ float *rect_float;
+ int width, height;
} FillCheckerColorThreadData;
static void checker_board_color_prepare_thread_do(void *data_v,
int start_scanline,
int num_scanlines)
{
- FillCheckerColorThreadData *data = (FillCheckerColorThreadData *)data_v;
- size_t offset = ((size_t)data->width) * start_scanline * 4;
- unsigned char *rect = (data->rect != NULL) ? (data->rect + offset) : NULL;
- float *rect_float = (data->rect_float != NULL) ? (data->rect_float + offset) : NULL;
- checker_board_color_prepare_slice(rect,
- rect_float,
- data->width,
- num_scanlines,
- start_scanline,
- data->height);
+ FillCheckerColorThreadData *data = (FillCheckerColorThreadData *)data_v;
+ size_t offset = ((size_t)data->width) * start_scanline * 4;
+ unsigned char *rect = (data->rect != NULL) ? (data->rect + offset) : NULL;
+ float *rect_float = (data->rect_float != NULL) ? (data->rect_float + offset) : NULL;
+ checker_board_color_prepare_slice(
+ rect, rect_float, data->width, num_scanlines, start_scanline, data->height);
}
-void BKE_image_buf_fill_checker_color(unsigned char *rect, float *rect_float, int width, int height)
+void BKE_image_buf_fill_checker_color(unsigned char *rect,
+ float *rect_float,
+ int width,
+ int height)
{
- if (((size_t)width) * height < 64 * 64) {
- checker_board_color_prepare_slice(rect, rect_float, width, height, 0, height);
- }
- else {
- FillCheckerColorThreadData data;
- data.rect = rect;
- data.rect_float = rect_float;
- data.width = width;
- data.height = height;
- IMB_processor_apply_threaded_scanlines(
- height, checker_board_color_prepare_thread_do, &data);
- }
-
- checker_board_text(rect, rect_float, width, height, 128, 2);
-
- if (rect_float != NULL) {
- /* TODO(sergey): Currently it's easier to fill in form buffer and
- * linearize it afterwards. This could be optimized with some smart
- * trickery around blending factors and such.
- */
- IMB_buffer_float_from_float_threaded(rect_float, rect_float,
- 4,
- IB_PROFILE_LINEAR_RGB,
- IB_PROFILE_SRGB,
- true,
- width, height,
- width, width);
- }
+ if (((size_t)width) * height < 64 * 64) {
+ checker_board_color_prepare_slice(rect, rect_float, width, height, 0, height);
+ }
+ else {
+ FillCheckerColorThreadData data;
+ data.rect = rect;
+ data.rect_float = rect_float;
+ data.width = width;
+ data.height = height;
+ IMB_processor_apply_threaded_scanlines(height, checker_board_color_prepare_thread_do, &data);
+ }
+
+ checker_board_text(rect, rect_float, width, height, 128, 2);
+
+ if (rect_float != NULL) {
+ /* TODO(sergey): Currently it's easier to fill in form buffer and
+ * linearize it afterwards. This could be optimized with some smart
+ * trickery around blending factors and such.
+ */
+ IMB_buffer_float_from_float_threaded(rect_float,
+ rect_float,
+ 4,
+ IB_PROFILE_LINEAR_RGB,
+ IB_PROFILE_SRGB,
+ true,
+ width,
+ height,
+ width,
+ width);
+ }
}
diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c
index 954026ea560..8f3b1fed692 100644
--- a/source/blender/blenkernel/intern/ipo.c
+++ b/source/blender/blenkernel/intern/ipo.c
@@ -21,7 +21,6 @@
* \ingroup bke
*/
-
/* NOTE:
*
* This file is no longer used to provide tools for the deprecated IPO system. Instead, it
@@ -74,7 +73,7 @@
#include "MEM_guardedalloc.h"
#ifdef WIN32
-# include "BLI_math_base.h" /* M_PI */
+# include "BLI_math_base.h" /* M_PI */
#endif
static CLG_LogRef LOG = {"bke.ipo"};
@@ -86,22 +85,25 @@ static CLG_LogRef LOG = {"bke.ipo"};
// XXX this shouldn't be necessary anymore, but may occur while not all data is converted yet
void BKE_ipo_free(Ipo *ipo)
{
- IpoCurve *icu, *icn;
- int n = 0;
+ IpoCurve *icu, *icn;
+ int n = 0;
- for (icu = ipo->curve.first; icu; icu = icn) {
- icn = icu->next;
- n++;
+ for (icu = ipo->curve.first; icu; icu = icn) {
+ icn = icu->next;
+ n++;
- if (icu->bezt) MEM_freeN(icu->bezt);
- if (icu->bp) MEM_freeN(icu->bp);
- if (icu->driver) MEM_freeN(icu->driver);
+ if (icu->bezt)
+ MEM_freeN(icu->bezt);
+ if (icu->bp)
+ MEM_freeN(icu->bp);
+ if (icu->driver)
+ MEM_freeN(icu->driver);
- BLI_freelinkN(&ipo->curve, icu);
- }
+ BLI_freelinkN(&ipo->curve, icu);
+ }
- if (G.debug & G_DEBUG)
- printf("Freed %d (Unconverted) Ipo-Curves from IPO '%s'\n", n, ipo->id.name + 2);
+ if (G.debug & G_DEBUG)
+ printf("Freed %d (Unconverted) Ipo-Curves from IPO '%s'\n", n, ipo->id.name + 2);
}
/* *************************************************** */
@@ -109,9 +111,9 @@ void BKE_ipo_free(Ipo *ipo)
/* Mapping Table for bitflag <-> RNA path */
typedef struct AdrBit2Path {
- int bit;
- const char *path;
- int array_index;
+ int bit;
+ const char *path;
+ int array_index;
} AdrBit2Path;
/* ----------------- */
@@ -119,48 +121,36 @@ typedef struct AdrBit2Path {
/* Object layers */
static AdrBit2Path ob_layer_bits[] = {
- {(1 << 0), "layers", 0},
- {(1 << 1), "layers", 1},
- {(1 << 2), "layers", 2},
- {(1 << 3), "layers", 3},
- {(1 << 4), "layers", 4},
- {(1 << 5), "layers", 5},
- {(1 << 6), "layers", 6},
- {(1 << 7), "layers", 7},
- {(1 << 8), "layers", 8},
- {(1 << 9), "layers", 9},
- {(1 << 10), "layers", 10},
- {(1 << 11), "layers", 11},
- {(1 << 12), "layers", 12},
- {(1 << 13), "layers", 13},
- {(1 << 14), "layers", 14},
- {(1 << 15), "layers", 15},
- {(1 << 16), "layers", 16},
- {(1 << 17), "layers", 17},
- {(1 << 18), "layers", 18},
- {(1 << 19), "layers", 19},
+ {(1 << 0), "layers", 0}, {(1 << 1), "layers", 1}, {(1 << 2), "layers", 2},
+ {(1 << 3), "layers", 3}, {(1 << 4), "layers", 4}, {(1 << 5), "layers", 5},
+ {(1 << 6), "layers", 6}, {(1 << 7), "layers", 7}, {(1 << 8), "layers", 8},
+ {(1 << 9), "layers", 9}, {(1 << 10), "layers", 10}, {(1 << 11), "layers", 11},
+ {(1 << 12), "layers", 12}, {(1 << 13), "layers", 13}, {(1 << 14), "layers", 14},
+ {(1 << 15), "layers", 15}, {(1 << 16), "layers", 16}, {(1 << 17), "layers", 17},
+ {(1 << 18), "layers", 18}, {(1 << 19), "layers", 19},
};
/* ----------------- */
/* quick macro for returning the appropriate array for adrcode_bitmaps_to_paths() */
#define RET_ABP(items) \
- { \
- *tot = sizeof(items) / sizeof(AdrBit2Path); \
- return items; \
- } (void)0
+ { \
+ *tot = sizeof(items) / sizeof(AdrBit2Path); \
+ return items; \
+ } \
+ (void)0
/* This function checks if a Blocktype+Adrcode combo, returning a mapping table */
static AdrBit2Path *adrcode_bitmaps_to_paths(int blocktype, int adrcode, int *tot)
{
- /* Object layers */
- if ((blocktype == ID_OB) && (adrcode == OB_LAY)) {
- RET_ABP(ob_layer_bits);
- }
- // XXX TODO: add other types...
-
- /* Normal curve */
- return NULL;
+ /* Object layers */
+ if ((blocktype == ID_OB) && (adrcode == OB_LAY)) {
+ RET_ABP(ob_layer_bits);
+ }
+ // XXX TODO: add other types...
+
+ /* Normal curve */
+ return NULL;
}
#undef RET_ABP
@@ -170,80 +160,102 @@ static AdrBit2Path *adrcode_bitmaps_to_paths(int blocktype, int adrcode, int *to
/* Object types */
static const char *ob_adrcodes_to_paths(int adrcode, int *array_index)
{
- /* set array index like this in-case nothing sets it correctly */
- *array_index = 0;
-
- /* result depends on adrcode */
- switch (adrcode) {
- case OB_LOC_X:
- *array_index = 0; return "location";
- case OB_LOC_Y:
- *array_index = 1; return "location";
- case OB_LOC_Z:
- *array_index = 2; return "location";
- case OB_DLOC_X:
- *array_index = 0; return "delta_location";
- case OB_DLOC_Y:
- *array_index = 1; return "delta_location";
- case OB_DLOC_Z:
- *array_index = 2; return "delta_location";
-
- case OB_ROT_X:
- *array_index = 0; return "rotation_euler";
- case OB_ROT_Y:
- *array_index = 1; return "rotation_euler";
- case OB_ROT_Z:
- *array_index = 2; return "rotation_euler";
- case OB_DROT_X:
- *array_index = 0; return "delta_rotation_euler";
- case OB_DROT_Y:
- *array_index = 1; return "delta_rotation_euler";
- case OB_DROT_Z:
- *array_index = 2; return "delta_rotation_euler";
-
- case OB_SIZE_X:
- *array_index = 0; return "scale";
- case OB_SIZE_Y:
- *array_index = 1; return "scale";
- case OB_SIZE_Z:
- *array_index = 2; return "scale";
- case OB_DSIZE_X:
- *array_index = 0; return "delta_scale";
- case OB_DSIZE_Y:
- *array_index = 1; return "delta_scale";
- case OB_DSIZE_Z:
- *array_index = 2; return "delta_scale";
- case OB_COL_R:
- *array_index = 0; return "color";
- case OB_COL_G:
- *array_index = 1; return "color";
- case OB_COL_B:
- *array_index = 2; return "color";
- case OB_COL_A:
- *array_index = 3; return "color";
+ /* set array index like this in-case nothing sets it correctly */
+ *array_index = 0;
+
+ /* result depends on adrcode */
+ switch (adrcode) {
+ case OB_LOC_X:
+ *array_index = 0;
+ return "location";
+ case OB_LOC_Y:
+ *array_index = 1;
+ return "location";
+ case OB_LOC_Z:
+ *array_index = 2;
+ return "location";
+ case OB_DLOC_X:
+ *array_index = 0;
+ return "delta_location";
+ case OB_DLOC_Y:
+ *array_index = 1;
+ return "delta_location";
+ case OB_DLOC_Z:
+ *array_index = 2;
+ return "delta_location";
+
+ case OB_ROT_X:
+ *array_index = 0;
+ return "rotation_euler";
+ case OB_ROT_Y:
+ *array_index = 1;
+ return "rotation_euler";
+ case OB_ROT_Z:
+ *array_index = 2;
+ return "rotation_euler";
+ case OB_DROT_X:
+ *array_index = 0;
+ return "delta_rotation_euler";
+ case OB_DROT_Y:
+ *array_index = 1;
+ return "delta_rotation_euler";
+ case OB_DROT_Z:
+ *array_index = 2;
+ return "delta_rotation_euler";
+
+ case OB_SIZE_X:
+ *array_index = 0;
+ return "scale";
+ case OB_SIZE_Y:
+ *array_index = 1;
+ return "scale";
+ case OB_SIZE_Z:
+ *array_index = 2;
+ return "scale";
+ case OB_DSIZE_X:
+ *array_index = 0;
+ return "delta_scale";
+ case OB_DSIZE_Y:
+ *array_index = 1;
+ return "delta_scale";
+ case OB_DSIZE_Z:
+ *array_index = 2;
+ return "delta_scale";
+ case OB_COL_R:
+ *array_index = 0;
+ return "color";
+ case OB_COL_G:
+ *array_index = 1;
+ return "color";
+ case OB_COL_B:
+ *array_index = 2;
+ return "color";
+ case OB_COL_A:
+ *array_index = 3;
+ return "color";
#if 0
- case OB_PD_FSTR:
- if (ob->pd) poin = &(ob->pd->f_strength);
- break;
- case OB_PD_FFALL:
- if (ob->pd) poin = &(ob->pd->f_power);
- break;
- case OB_PD_SDAMP:
- if (ob->pd) poin = &(ob->pd->pdef_damp);
- break;
- case OB_PD_RDAMP:
- if (ob->pd) poin = &(ob->pd->pdef_rdamp);
- break;
- case OB_PD_PERM:
- if (ob->pd) poin = &(ob->pd->pdef_perm);
- break;
- case OB_PD_FMAXD:
- if (ob->pd) poin = &(ob->pd->maxdist);
- break;
+ case OB_PD_FSTR:
+ if (ob->pd) poin = &(ob->pd->f_strength);
+ break;
+ case OB_PD_FFALL:
+ if (ob->pd) poin = &(ob->pd->f_power);
+ break;
+ case OB_PD_SDAMP:
+ if (ob->pd) poin = &(ob->pd->pdef_damp);
+ break;
+ case OB_PD_RDAMP:
+ if (ob->pd) poin = &(ob->pd->pdef_rdamp);
+ break;
+ case OB_PD_PERM:
+ if (ob->pd) poin = &(ob->pd->pdef_perm);
+ break;
+ case OB_PD_FMAXD:
+ if (ob->pd) poin = &(ob->pd->maxdist);
+ break;
#endif
- }
+ }
- return NULL;
+ return NULL;
}
/* PoseChannel types
@@ -251,62 +263,75 @@ static const char *ob_adrcodes_to_paths(int adrcode, int *array_index)
*/
static const char *pchan_adrcodes_to_paths(int adrcode, int *array_index)
{
- /* set array index like this in-case nothing sets it correctly */
- *array_index = 0;
-
- /* result depends on adrcode */
- switch (adrcode) {
- case AC_QUAT_W:
- *array_index = 0; return "rotation_quaternion";
- case AC_QUAT_X:
- *array_index = 1; return "rotation_quaternion";
- case AC_QUAT_Y:
- *array_index = 2; return "rotation_quaternion";
- case AC_QUAT_Z:
- *array_index = 3; return "rotation_quaternion";
-
- case AC_EUL_X:
- *array_index = 0; return "rotation_euler";
- case AC_EUL_Y:
- *array_index = 1; return "rotation_euler";
- case AC_EUL_Z:
- *array_index = 2; return "rotation_euler";
-
- case AC_LOC_X:
- *array_index = 0; return "location";
- case AC_LOC_Y:
- *array_index = 1; return "location";
- case AC_LOC_Z:
- *array_index = 2; return "location";
-
- case AC_SIZE_X:
- *array_index = 0; return "scale";
- case AC_SIZE_Y:
- *array_index = 1; return "scale";
- case AC_SIZE_Z:
- *array_index = 2; return "scale";
- }
-
- /* for debugging only */
- CLOG_ERROR(&LOG, "unmatched PoseChannel setting (code %d)", adrcode);
- return NULL;
+ /* set array index like this in-case nothing sets it correctly */
+ *array_index = 0;
+
+ /* result depends on adrcode */
+ switch (adrcode) {
+ case AC_QUAT_W:
+ *array_index = 0;
+ return "rotation_quaternion";
+ case AC_QUAT_X:
+ *array_index = 1;
+ return "rotation_quaternion";
+ case AC_QUAT_Y:
+ *array_index = 2;
+ return "rotation_quaternion";
+ case AC_QUAT_Z:
+ *array_index = 3;
+ return "rotation_quaternion";
+
+ case AC_EUL_X:
+ *array_index = 0;
+ return "rotation_euler";
+ case AC_EUL_Y:
+ *array_index = 1;
+ return "rotation_euler";
+ case AC_EUL_Z:
+ *array_index = 2;
+ return "rotation_euler";
+
+ case AC_LOC_X:
+ *array_index = 0;
+ return "location";
+ case AC_LOC_Y:
+ *array_index = 1;
+ return "location";
+ case AC_LOC_Z:
+ *array_index = 2;
+ return "location";
+
+ case AC_SIZE_X:
+ *array_index = 0;
+ return "scale";
+ case AC_SIZE_Y:
+ *array_index = 1;
+ return "scale";
+ case AC_SIZE_Z:
+ *array_index = 2;
+ return "scale";
+ }
+
+ /* for debugging only */
+ CLOG_ERROR(&LOG, "unmatched PoseChannel setting (code %d)", adrcode);
+ return NULL;
}
/* Constraint types */
static const char *constraint_adrcodes_to_paths(int adrcode, int *array_index)
{
- /* set array index like this in-case nothing sets it correctly */
- *array_index = 0;
-
- /* result depends on adrcode */
- switch (adrcode) {
- case CO_ENFORCE:
- return "influence";
- case CO_HEADTAIL: // XXX this needs to be wrapped in RNA.. probably then this path will be invalid
- return "data.head_tail";
- }
-
- return NULL;
+ /* set array index like this in-case nothing sets it correctly */
+ *array_index = 0;
+
+ /* result depends on adrcode */
+ switch (adrcode) {
+ case CO_ENFORCE:
+ return "influence";
+ case CO_HEADTAIL: // XXX this needs to be wrapped in RNA.. probably then this path will be invalid
+ return "data.head_tail";
+ }
+
+ return NULL;
}
/* ShapeKey types
@@ -315,478 +340,524 @@ static const char *constraint_adrcodes_to_paths(int adrcode, int *array_index)
*/
static char *shapekey_adrcodes_to_paths(ID *id, int adrcode, int *UNUSED(array_index))
{
- static char buf[128];
-
- /* block will be attached to ID_KE block... */
- if (adrcode == 0) {
- /* adrcode=0 was the misnamed "speed" curve (now "evaluation time") */
- BLI_strncpy(buf, "eval_time", sizeof(buf));
- }
- else {
- /* Find the name of the ShapeKey (i.e. KeyBlock) to look for */
- Key *key = (Key *)id;
- KeyBlock *kb = BKE_keyblock_from_key(key, adrcode);
-
- /* setting that we alter is the "value" (i.e. keyblock.curval) */
- if (kb) {
- /* Use the keyblock name, escaped, so that path lookups for this will work */
- BLI_snprintf(buf, sizeof(buf), "key_blocks[\"%s\"].value", kb->name);
- }
- else {
- /* Fallback - Use the adrcode as index directly, so that this can be manually fixed */
- BLI_snprintf(buf, sizeof(buf), "key_blocks[%d].value", adrcode);
- }
- }
- return buf;
+ static char buf[128];
+
+ /* block will be attached to ID_KE block... */
+ if (adrcode == 0) {
+ /* adrcode=0 was the misnamed "speed" curve (now "evaluation time") */
+ BLI_strncpy(buf, "eval_time", sizeof(buf));
+ }
+ else {
+ /* Find the name of the ShapeKey (i.e. KeyBlock) to look for */
+ Key *key = (Key *)id;
+ KeyBlock *kb = BKE_keyblock_from_key(key, adrcode);
+
+ /* setting that we alter is the "value" (i.e. keyblock.curval) */
+ if (kb) {
+ /* Use the keyblock name, escaped, so that path lookups for this will work */
+ BLI_snprintf(buf, sizeof(buf), "key_blocks[\"%s\"].value", kb->name);
+ }
+ else {
+ /* Fallback - Use the adrcode as index directly, so that this can be manually fixed */
+ BLI_snprintf(buf, sizeof(buf), "key_blocks[%d].value", adrcode);
+ }
+ }
+ return buf;
}
/* MTex (Texture Slot) types */
static const char *mtex_adrcodes_to_paths(int adrcode, int *UNUSED(array_index))
{
- const char *base = NULL, *prop = NULL;
- static char buf[128];
-
- /* base part of path */
- if (adrcode & MA_MAP1) base = "textures[0]";
- else if (adrcode & MA_MAP2) base = "textures[1]";
- else if (adrcode & MA_MAP3) base = "textures[2]";
- else if (adrcode & MA_MAP4) base = "textures[3]";
- else if (adrcode & MA_MAP5) base = "textures[4]";
- else if (adrcode & MA_MAP6) base = "textures[5]";
- else if (adrcode & MA_MAP7) base = "textures[6]";
- else if (adrcode & MA_MAP8) base = "textures[7]";
- else if (adrcode & MA_MAP9) base = "textures[8]";
- else if (adrcode & MA_MAP10) base = "textures[9]";
- else if (adrcode & MA_MAP11) base = "textures[10]";
- else if (adrcode & MA_MAP12) base = "textures[11]";
- else if (adrcode & MA_MAP13) base = "textures[12]";
- else if (adrcode & MA_MAP14) base = "textures[13]";
- else if (adrcode & MA_MAP15) base = "textures[14]";
- else if (adrcode & MA_MAP16) base = "textures[15]";
- else if (adrcode & MA_MAP17) base = "textures[16]";
- else if (adrcode & MA_MAP18) base = "textures[17]";
-
- /* property identifier for path */
- adrcode = (adrcode & (MA_MAP1 - 1));
- switch (adrcode) {
-#if 0 // XXX these are not wrapped in RNA yet!
- case MAP_OFS_X:
- poin = &(mtex->ofs[0]); break;
- case MAP_OFS_Y:
- poin = &(mtex->ofs[1]); break;
- case MAP_OFS_Z:
- poin = &(mtex->ofs[2]); break;
- case MAP_SIZE_X:
- poin = &(mtex->size[0]); break;
- case MAP_SIZE_Y:
- poin = &(mtex->size[1]); break;
- case MAP_SIZE_Z:
- poin = &(mtex->size[2]); break;
- case MAP_R:
- poin = &(mtex->r); break;
- case MAP_G:
- poin = &(mtex->g); break;
- case MAP_B:
- poin = &(mtex->b); break;
- case MAP_DVAR:
- poin = &(mtex->def_var); break;
- case MAP_COLF:
- poin = &(mtex->colfac); break;
- case MAP_NORF:
- poin = &(mtex->norfac); break;
- case MAP_VARF:
- poin = &(mtex->varfac); break;
+ const char *base = NULL, *prop = NULL;
+ static char buf[128];
+
+ /* base part of path */
+ if (adrcode & MA_MAP1)
+ base = "textures[0]";
+ else if (adrcode & MA_MAP2)
+ base = "textures[1]";
+ else if (adrcode & MA_MAP3)
+ base = "textures[2]";
+ else if (adrcode & MA_MAP4)
+ base = "textures[3]";
+ else if (adrcode & MA_MAP5)
+ base = "textures[4]";
+ else if (adrcode & MA_MAP6)
+ base = "textures[5]";
+ else if (adrcode & MA_MAP7)
+ base = "textures[6]";
+ else if (adrcode & MA_MAP8)
+ base = "textures[7]";
+ else if (adrcode & MA_MAP9)
+ base = "textures[8]";
+ else if (adrcode & MA_MAP10)
+ base = "textures[9]";
+ else if (adrcode & MA_MAP11)
+ base = "textures[10]";
+ else if (adrcode & MA_MAP12)
+ base = "textures[11]";
+ else if (adrcode & MA_MAP13)
+ base = "textures[12]";
+ else if (adrcode & MA_MAP14)
+ base = "textures[13]";
+ else if (adrcode & MA_MAP15)
+ base = "textures[14]";
+ else if (adrcode & MA_MAP16)
+ base = "textures[15]";
+ else if (adrcode & MA_MAP17)
+ base = "textures[16]";
+ else if (adrcode & MA_MAP18)
+ base = "textures[17]";
+
+ /* property identifier for path */
+ adrcode = (adrcode & (MA_MAP1 - 1));
+ switch (adrcode) {
+#if 0 // XXX these are not wrapped in RNA yet!
+ case MAP_OFS_X:
+ poin = &(mtex->ofs[0]); break;
+ case MAP_OFS_Y:
+ poin = &(mtex->ofs[1]); break;
+ case MAP_OFS_Z:
+ poin = &(mtex->ofs[2]); break;
+ case MAP_SIZE_X:
+ poin = &(mtex->size[0]); break;
+ case MAP_SIZE_Y:
+ poin = &(mtex->size[1]); break;
+ case MAP_SIZE_Z:
+ poin = &(mtex->size[2]); break;
+ case MAP_R:
+ poin = &(mtex->r); break;
+ case MAP_G:
+ poin = &(mtex->g); break;
+ case MAP_B:
+ poin = &(mtex->b); break;
+ case MAP_DVAR:
+ poin = &(mtex->def_var); break;
+ case MAP_COLF:
+ poin = &(mtex->colfac); break;
+ case MAP_NORF:
+ poin = &(mtex->norfac); break;
+ case MAP_VARF:
+ poin = &(mtex->varfac); break;
#endif
- case MAP_DISP:
- prop = "warp_factor"; break;
- }
-
- /* only build and return path if there's a property */
- if (prop) {
- BLI_snprintf(buf, 128, "%s.%s", base, prop);
- return buf;
- }
- else
- return NULL;
+ case MAP_DISP:
+ prop = "warp_factor";
+ break;
+ }
+
+ /* only build and return path if there's a property */
+ if (prop) {
+ BLI_snprintf(buf, 128, "%s.%s", base, prop);
+ return buf;
+ }
+ else
+ return NULL;
}
/* Texture types */
static const char *texture_adrcodes_to_paths(int adrcode, int *array_index)
{
- /* set array index like this in-case nothing sets it correctly */
- *array_index = 0;
-
- /* result depends on adrcode */
- switch (adrcode) {
- case TE_NSIZE:
- return "noise_size";
- case TE_TURB:
- return "turbulence";
-
- case TE_NDEPTH: // XXX texture RNA undefined
- //poin= &(tex->noisedepth); *type= IPO_SHORT; break;
- break;
- case TE_NTYPE: // XXX texture RNA undefined
- //poin= &(tex->noisetype); *type= IPO_SHORT; break;
- break;
-
- case TE_N_BAS1:
- return "noise_basis";
- case TE_N_BAS2:
- return "noise_basis"; // XXX this is not yet defined in RNA...
-
- /* voronoi */
- case TE_VNW1:
- *array_index = 0; return "feature_weights";
- case TE_VNW2:
- *array_index = 1; return "feature_weights";
- case TE_VNW3:
- *array_index = 2; return "feature_weights";
- case TE_VNW4:
- *array_index = 3; return "feature_weights";
- case TE_VNMEXP:
- return "minkovsky_exponent";
- case TE_VN_DISTM:
- return "distance_metric";
- case TE_VN_COLT:
- return "color_type";
-
- /* distorted noise / voronoi */
- case TE_ISCA:
- return "noise_intensity";
-
- /* distorted noise */
- case TE_DISTA:
- return "distortion_amount";
-
- /* musgrave */
- case TE_MG_TYP: // XXX texture RNA undefined
- // poin= &(tex->stype); *type= IPO_SHORT; break;
- break;
- case TE_MGH:
- return "highest_dimension";
- case TE_MG_LAC:
- return "lacunarity";
- case TE_MG_OCT:
- return "octaves";
- case TE_MG_OFF:
- return "offset";
- case TE_MG_GAIN:
- return "gain";
-
- case TE_COL_R:
- *array_index = 0; return "rgb_factor";
- case TE_COL_G:
- *array_index = 1; return "rgb_factor";
- case TE_COL_B:
- *array_index = 2; return "rgb_factor";
-
- case TE_BRIGHT:
- return "brightness";
- case TE_CONTRA:
- return "contrast";
- }
-
- return NULL;
+ /* set array index like this in-case nothing sets it correctly */
+ *array_index = 0;
+
+ /* result depends on adrcode */
+ switch (adrcode) {
+ case TE_NSIZE:
+ return "noise_size";
+ case TE_TURB:
+ return "turbulence";
+
+ case TE_NDEPTH: // XXX texture RNA undefined
+ //poin= &(tex->noisedepth); *type= IPO_SHORT; break;
+ break;
+ case TE_NTYPE: // XXX texture RNA undefined
+ //poin= &(tex->noisetype); *type= IPO_SHORT; break;
+ break;
+
+ case TE_N_BAS1:
+ return "noise_basis";
+ case TE_N_BAS2:
+ return "noise_basis"; // XXX this is not yet defined in RNA...
+
+ /* voronoi */
+ case TE_VNW1:
+ *array_index = 0;
+ return "feature_weights";
+ case TE_VNW2:
+ *array_index = 1;
+ return "feature_weights";
+ case TE_VNW3:
+ *array_index = 2;
+ return "feature_weights";
+ case TE_VNW4:
+ *array_index = 3;
+ return "feature_weights";
+ case TE_VNMEXP:
+ return "minkovsky_exponent";
+ case TE_VN_DISTM:
+ return "distance_metric";
+ case TE_VN_COLT:
+ return "color_type";
+
+ /* distorted noise / voronoi */
+ case TE_ISCA:
+ return "noise_intensity";
+
+ /* distorted noise */
+ case TE_DISTA:
+ return "distortion_amount";
+
+ /* musgrave */
+ case TE_MG_TYP: // XXX texture RNA undefined
+ // poin= &(tex->stype); *type= IPO_SHORT; break;
+ break;
+ case TE_MGH:
+ return "highest_dimension";
+ case TE_MG_LAC:
+ return "lacunarity";
+ case TE_MG_OCT:
+ return "octaves";
+ case TE_MG_OFF:
+ return "offset";
+ case TE_MG_GAIN:
+ return "gain";
+
+ case TE_COL_R:
+ *array_index = 0;
+ return "rgb_factor";
+ case TE_COL_G:
+ *array_index = 1;
+ return "rgb_factor";
+ case TE_COL_B:
+ *array_index = 2;
+ return "rgb_factor";
+
+ case TE_BRIGHT:
+ return "brightness";
+ case TE_CONTRA:
+ return "contrast";
+ }
+
+ return NULL;
}
/* Material Types */
static const char *material_adrcodes_to_paths(int adrcode, int *array_index)
{
- /* set array index like this in-case nothing sets it correctly */
- *array_index = 0;
-
- /* result depends on adrcode */
- switch (adrcode) {
- case MA_COL_R:
- *array_index = 0; return "diffuse_color";
- case MA_COL_G:
- *array_index = 1; return "diffuse_color";
- case MA_COL_B:
- *array_index = 2; return "diffuse_color";
-
- case MA_SPEC_R:
- *array_index = 0; return "specular_color";
- case MA_SPEC_G:
- *array_index = 1; return "specular_color";
- case MA_SPEC_B:
- *array_index = 2; return "specular_color";
-
- case MA_MIR_R:
- *array_index = 0; return "mirror_color";
- case MA_MIR_G:
- *array_index = 1; return "mirror_color";
- case MA_MIR_B:
- *array_index = 2; return "mirror_color";
-
- case MA_ALPHA:
- return "alpha";
-
- case MA_REF:
- return "diffuse_intensity";
-
- case MA_EMIT:
- return "emit";
-
- case MA_AMB:
- return "ambient";
-
- case MA_SPEC:
- return "specular_intensity";
-
- case MA_HARD:
- return "specular_hardness";
-
- case MA_SPTR:
- return "specular_opacity";
-
- case MA_IOR:
- return "ior";
-
- case MA_HASIZE:
- return "halo.size";
-
- case MA_TRANSLU:
- return "translucency";
-
- case MA_RAYM:
- return "raytrace_mirror.reflect";
-
- case MA_FRESMIR:
- return "raytrace_mirror.fresnel";
-
- case MA_FRESMIRI:
- return "raytrace_mirror.fresnel_factor";
-
- case MA_FRESTRA:
- return "raytrace_transparency.fresnel";
-
- case MA_FRESTRAI:
- return "raytrace_transparency.fresnel_factor";
-
- case MA_ADD:
- return "halo.add";
-
- default: /* for now, we assume that the others were MTex channels */
- return mtex_adrcodes_to_paths(adrcode, array_index);
- }
-
- return NULL;
+ /* set array index like this in-case nothing sets it correctly */
+ *array_index = 0;
+
+ /* result depends on adrcode */
+ switch (adrcode) {
+ case MA_COL_R:
+ *array_index = 0;
+ return "diffuse_color";
+ case MA_COL_G:
+ *array_index = 1;
+ return "diffuse_color";
+ case MA_COL_B:
+ *array_index = 2;
+ return "diffuse_color";
+
+ case MA_SPEC_R:
+ *array_index = 0;
+ return "specular_color";
+ case MA_SPEC_G:
+ *array_index = 1;
+ return "specular_color";
+ case MA_SPEC_B:
+ *array_index = 2;
+ return "specular_color";
+
+ case MA_MIR_R:
+ *array_index = 0;
+ return "mirror_color";
+ case MA_MIR_G:
+ *array_index = 1;
+ return "mirror_color";
+ case MA_MIR_B:
+ *array_index = 2;
+ return "mirror_color";
+
+ case MA_ALPHA:
+ return "alpha";
+
+ case MA_REF:
+ return "diffuse_intensity";
+
+ case MA_EMIT:
+ return "emit";
+
+ case MA_AMB:
+ return "ambient";
+
+ case MA_SPEC:
+ return "specular_intensity";
+
+ case MA_HARD:
+ return "specular_hardness";
+
+ case MA_SPTR:
+ return "specular_opacity";
+
+ case MA_IOR:
+ return "ior";
+
+ case MA_HASIZE:
+ return "halo.size";
+
+ case MA_TRANSLU:
+ return "translucency";
+
+ case MA_RAYM:
+ return "raytrace_mirror.reflect";
+
+ case MA_FRESMIR:
+ return "raytrace_mirror.fresnel";
+
+ case MA_FRESMIRI:
+ return "raytrace_mirror.fresnel_factor";
+
+ case MA_FRESTRA:
+ return "raytrace_transparency.fresnel";
+
+ case MA_FRESTRAI:
+ return "raytrace_transparency.fresnel_factor";
+
+ case MA_ADD:
+ return "halo.add";
+
+ default: /* for now, we assume that the others were MTex channels */
+ return mtex_adrcodes_to_paths(adrcode, array_index);
+ }
+
+ return NULL;
}
/* Camera Types */
static const char *camera_adrcodes_to_paths(int adrcode, int *array_index)
{
- /* set array index like this in-case nothing sets it correctly */
- *array_index = 0;
-
- /* result depends on adrcode */
- switch (adrcode) {
- case CAM_LENS:
-#if 0 // XXX this cannot be resolved easily... perhaps we assume camera is perspective (works for most cases...
- if (ca->type == CAM_ORTHO)
- return "ortho_scale";
- else
- return "lens";
-#else // XXX lazy hack for now...
- return "lens";
-#endif // XXX this cannot be resolved easily
-
- case CAM_STA:
- return "clip_start";
- case CAM_END:
- return "clip_end";
-
-#if 0 // XXX these are not defined in RNA
- case CAM_YF_APERT:
- poin = &(ca->YF_aperture); break;
- case CAM_YF_FDIST:
- poin = &(ca->dof_distance); break;
-#endif // XXX these are not defined in RNA
-
- case CAM_SHIFT_X:
- return "shift_x";
- case CAM_SHIFT_Y:
- return "shift_y";
- }
-
- /* unrecognized adrcode, or not-yet-handled ones! */
- return NULL;
+ /* set array index like this in-case nothing sets it correctly */
+ *array_index = 0;
+
+ /* result depends on adrcode */
+ switch (adrcode) {
+ case CAM_LENS:
+#if 0 // XXX this cannot be resolved easily... perhaps we assume camera is perspective (works for most cases...
+ if (ca->type == CAM_ORTHO)
+ return "ortho_scale";
+ else
+ return "lens";
+#else // XXX lazy hack for now...
+ return "lens";
+#endif // XXX this cannot be resolved easily
+
+ case CAM_STA:
+ return "clip_start";
+ case CAM_END:
+ return "clip_end";
+
+#if 0 // XXX these are not defined in RNA
+ case CAM_YF_APERT:
+ poin = &(ca->YF_aperture); break;
+ case CAM_YF_FDIST:
+ poin = &(ca->dof_distance); break;
+#endif // XXX these are not defined in RNA
+
+ case CAM_SHIFT_X:
+ return "shift_x";
+ case CAM_SHIFT_Y:
+ return "shift_y";
+ }
+
+ /* unrecognized adrcode, or not-yet-handled ones! */
+ return NULL;
}
/* Light Types */
static const char *light_adrcodes_to_paths(int adrcode, int *array_index)
{
- /* set array index like this in-case nothing sets it correctly */
- *array_index = 0;
-
- /* result depends on adrcode */
- switch (adrcode) {
- case LA_ENERGY:
- return "energy";
-
- case LA_COL_R:
- *array_index = 0; return "color";
- case LA_COL_G:
- *array_index = 1; return "color";
- case LA_COL_B:
- *array_index = 2; return "color";
-
- case LA_DIST:
- return "distance";
-
- case LA_SPOTSI:
- return "spot_size";
- case LA_SPOTBL:
- return "spot_blend";
-
- case LA_QUAD1:
- return "linear_attenuation";
- case LA_QUAD2:
- return "quadratic_attenuation";
-
- case LA_HALOINT:
- return "halo_intensity";
-
- default: /* for now, we assume that the others were MTex channels */
- return mtex_adrcodes_to_paths(adrcode, array_index);
- }
-
- /* unrecognized adrcode, or not-yet-handled ones! */
- return NULL;
+ /* set array index like this in-case nothing sets it correctly */
+ *array_index = 0;
+
+ /* result depends on adrcode */
+ switch (adrcode) {
+ case LA_ENERGY:
+ return "energy";
+
+ case LA_COL_R:
+ *array_index = 0;
+ return "color";
+ case LA_COL_G:
+ *array_index = 1;
+ return "color";
+ case LA_COL_B:
+ *array_index = 2;
+ return "color";
+
+ case LA_DIST:
+ return "distance";
+
+ case LA_SPOTSI:
+ return "spot_size";
+ case LA_SPOTBL:
+ return "spot_blend";
+
+ case LA_QUAD1:
+ return "linear_attenuation";
+ case LA_QUAD2:
+ return "quadratic_attenuation";
+
+ case LA_HALOINT:
+ return "halo_intensity";
+
+ default: /* for now, we assume that the others were MTex channels */
+ return mtex_adrcodes_to_paths(adrcode, array_index);
+ }
+
+ /* unrecognized adrcode, or not-yet-handled ones! */
+ return NULL;
}
/* Sound Types */
static const char *sound_adrcodes_to_paths(int adrcode, int *array_index)
{
- /* set array index like this in-case nothing sets it correctly */
- *array_index = 0;
-
- /* result depends on adrcode */
- switch (adrcode) {
- case SND_VOLUME:
- return "volume";
- case SND_PITCH:
- return "pitch";
- /* XXX Joshua -- I had wrapped panning in rna, but someone commented out, calling it "unused" */
+ /* set array index like this in-case nothing sets it correctly */
+ *array_index = 0;
+
+ /* result depends on adrcode */
+ switch (adrcode) {
+ case SND_VOLUME:
+ return "volume";
+ case SND_PITCH:
+ return "pitch";
+ /* XXX Joshua -- I had wrapped panning in rna, but someone commented out, calling it "unused" */
#if 0
- case SND_PANNING:
- return "panning";
+ case SND_PANNING:
+ return "panning";
#endif
- case SND_ATTEN:
- return "attenuation";
- }
+ case SND_ATTEN:
+ return "attenuation";
+ }
- /* unrecognized adrcode, or not-yet-handled ones! */
- return NULL;
+ /* unrecognized adrcode, or not-yet-handled ones! */
+ return NULL;
}
/* World Types */
static const char *world_adrcodes_to_paths(int adrcode, int *array_index)
{
- /* set array index like this in-case nothing sets it correctly */
- *array_index = 0;
-
- /* result depends on adrcode */
- switch (adrcode) {
- case WO_HOR_R:
- *array_index = 0; return "horizon_color";
- case WO_HOR_G:
- *array_index = 1; return "horizon_color";
- case WO_HOR_B:
- *array_index = 2; return "horizon_color";
- case WO_ZEN_R:
- *array_index = 0; return "zenith_color";
- case WO_ZEN_G:
- *array_index = 1; return "zenith_color";
- case WO_ZEN_B:
- *array_index = 2; return "zenith_color";
-
- case WO_EXPOS:
- return "exposure";
-
- case WO_MISI:
- return "mist.intensity";
- case WO_MISTDI:
- return "mist.depth";
- case WO_MISTSTA:
- return "mist.start";
- case WO_MISTHI:
- return "mist.height";
-
- default: /* for now, we assume that the others were MTex channels */
- return mtex_adrcodes_to_paths(adrcode, array_index);
- }
-
- return NULL;
+ /* set array index like this in-case nothing sets it correctly */
+ *array_index = 0;
+
+ /* result depends on adrcode */
+ switch (adrcode) {
+ case WO_HOR_R:
+ *array_index = 0;
+ return "horizon_color";
+ case WO_HOR_G:
+ *array_index = 1;
+ return "horizon_color";
+ case WO_HOR_B:
+ *array_index = 2;
+ return "horizon_color";
+ case WO_ZEN_R:
+ *array_index = 0;
+ return "zenith_color";
+ case WO_ZEN_G:
+ *array_index = 1;
+ return "zenith_color";
+ case WO_ZEN_B:
+ *array_index = 2;
+ return "zenith_color";
+
+ case WO_EXPOS:
+ return "exposure";
+
+ case WO_MISI:
+ return "mist.intensity";
+ case WO_MISTDI:
+ return "mist.depth";
+ case WO_MISTSTA:
+ return "mist.start";
+ case WO_MISTHI:
+ return "mist.height";
+
+ default: /* for now, we assume that the others were MTex channels */
+ return mtex_adrcodes_to_paths(adrcode, array_index);
+ }
+
+ return NULL;
}
/* Particle Types */
static const char *particle_adrcodes_to_paths(int adrcode, int *array_index)
{
- /* set array index like this in-case nothing sets it correctly */
- *array_index = 0;
-
- /* result depends on adrcode */
- switch (adrcode) {
- case PART_CLUMP:
- return "settings.clump_factor";
- case PART_AVE:
- return "settings.angular_velocity_factor";
- case PART_SIZE:
- return "settings.particle_size";
- case PART_DRAG:
- return "settings.drag_factor";
- case PART_BROWN:
- return "settings.brownian_factor";
- case PART_DAMP:
- return "settings.damp_factor";
- case PART_LENGTH:
- return "settings.length";
- case PART_GRAV_X:
- *array_index = 0; return "settings.acceleration";
- case PART_GRAV_Y:
- *array_index = 1; return "settings.acceleration";
- case PART_GRAV_Z:
- *array_index = 2; return "settings.acceleration";
- case PART_KINK_AMP:
- return "settings.kink_amplitude";
- case PART_KINK_FREQ:
- return "settings.kink_frequency";
- case PART_KINK_SHAPE:
- return "settings.kink_shape";
- case PART_BB_TILT:
- return "settings.billboard_tilt";
-
- /* PartDeflect needs to be sorted out properly in rna_object_force;
- * If anyone else works on this, but is unfamiliar, these particular
- * settings reference the particles of the system themselves
- * being used as forces -- it will use the same rna structure
- * as the similar object forces */
+ /* set array index like this in-case nothing sets it correctly */
+ *array_index = 0;
+
+ /* result depends on adrcode */
+ switch (adrcode) {
+ case PART_CLUMP:
+ return "settings.clump_factor";
+ case PART_AVE:
+ return "settings.angular_velocity_factor";
+ case PART_SIZE:
+ return "settings.particle_size";
+ case PART_DRAG:
+ return "settings.drag_factor";
+ case PART_BROWN:
+ return "settings.brownian_factor";
+ case PART_DAMP:
+ return "settings.damp_factor";
+ case PART_LENGTH:
+ return "settings.length";
+ case PART_GRAV_X:
+ *array_index = 0;
+ return "settings.acceleration";
+ case PART_GRAV_Y:
+ *array_index = 1;
+ return "settings.acceleration";
+ case PART_GRAV_Z:
+ *array_index = 2;
+ return "settings.acceleration";
+ case PART_KINK_AMP:
+ return "settings.kink_amplitude";
+ case PART_KINK_FREQ:
+ return "settings.kink_frequency";
+ case PART_KINK_SHAPE:
+ return "settings.kink_shape";
+ case PART_BB_TILT:
+ return "settings.billboard_tilt";
+
+ /* PartDeflect needs to be sorted out properly in rna_object_force;
+ * If anyone else works on this, but is unfamiliar, these particular
+ * settings reference the particles of the system themselves
+ * being used as forces -- it will use the same rna structure
+ * as the similar object forces */
#if 0
- case PART_PD_FSTR:
- if (part->pd) poin = &(part->pd->f_strength);
- break;
- case PART_PD_FFALL:
- if (part->pd) poin = &(part->pd->f_power);
- break;
- case PART_PD_FMAXD:
- if (part->pd) poin = &(part->pd->maxdist);
- break;
- case PART_PD2_FSTR:
- if (part->pd2) poin = &(part->pd2->f_strength);
- break;
- case PART_PD2_FFALL:
- if (part->pd2) poin = &(part->pd2->f_power);
- break;
- case PART_PD2_FMAXD:
- if (part->pd2) poin = &(part->pd2->maxdist);
- break;
+ case PART_PD_FSTR:
+ if (part->pd) poin = &(part->pd->f_strength);
+ break;
+ case PART_PD_FFALL:
+ if (part->pd) poin = &(part->pd->f_power);
+ break;
+ case PART_PD_FMAXD:
+ if (part->pd) poin = &(part->pd->maxdist);
+ break;
+ case PART_PD2_FSTR:
+ if (part->pd2) poin = &(part->pd2->f_strength);
+ break;
+ case PART_PD2_FFALL:
+ if (part->pd2) poin = &(part->pd2->f_power);
+ break;
+ case PART_PD2_FMAXD:
+ if (part->pd2) poin = &(part->pd2->maxdist);
+ break;
#endif
+ }
- }
-
- return NULL;
+ return NULL;
}
/* ------- */
@@ -800,170 +871,176 @@ static const char *particle_adrcodes_to_paths(int adrcode, int *array_index)
* - array_index - index in property's array (if applicable) to use
* - return - the allocated path...
*/
-static char *get_rna_access(ID *id, int blocktype, int adrcode, char actname[], char constname[], Sequence *seq, int *array_index)
+static char *get_rna_access(ID *id,
+ int blocktype,
+ int adrcode,
+ char actname[],
+ char constname[],
+ Sequence *seq,
+ int *array_index)
{
- DynStr *path = BLI_dynstr_new();
- const char *propname = NULL;
- char *rpath = NULL;
- char buf[512];
- int dummy_index = 0;
-
- /* hack: if constname is set, we can only be dealing with an Constraint curve */
- if (constname)
- blocktype = ID_CO;
-
- /* get property name based on blocktype */
- switch (blocktype) {
- case ID_OB: /* object */
- propname = ob_adrcodes_to_paths(adrcode, &dummy_index);
- break;
-
- case ID_PO: /* pose channel */
- propname = pchan_adrcodes_to_paths(adrcode, &dummy_index);
- break;
-
- case ID_KE: /* shapekeys */
- propname = shapekey_adrcodes_to_paths(id, adrcode, &dummy_index);
- break;
-
- case ID_CO: /* constraint */
- propname = constraint_adrcodes_to_paths(adrcode, &dummy_index);
- break;
-
- case ID_TE: /* texture */
- propname = texture_adrcodes_to_paths(adrcode, &dummy_index);
- break;
-
- case ID_MA: /* material */
- propname = material_adrcodes_to_paths(adrcode, &dummy_index);
- break;
-
- case ID_CA: /* camera */
- propname = camera_adrcodes_to_paths(adrcode, &dummy_index);
- break;
-
- case ID_LA: /* light */
- propname = light_adrcodes_to_paths(adrcode, &dummy_index);
- break;
-
- case ID_SO: /* sound */
- propname = sound_adrcodes_to_paths(adrcode, &dummy_index);
- break;
-
- case ID_WO: /* world */
- propname = world_adrcodes_to_paths(adrcode, &dummy_index);
- break;
-
- case ID_PA: /* particle */
- propname = particle_adrcodes_to_paths(adrcode, &dummy_index);
- break;
-
- case ID_CU: /* curve */
- /* this used to be a 'dummy' curve which got evaluated on the fly...
- * now we've got real var for this!
- */
- propname = "eval_time";
- break;
-
- /* XXX problematic blocktypes */
- case ID_SEQ: /* sequencer strip */
- //SEQ_FAC1:
- switch (adrcode) {
- case SEQ_FAC1:
- propname = "effect_fader";
- break;
- case SEQ_FAC_SPEED:
- propname = "speed_fader";
- break;
- case SEQ_FAC_OPACITY:
- propname = "blend_opacity";
- break;
- }
- // poin= &(seq->facf0); // XXX this doesn't seem to be included anywhere in sequencer RNA...
- break;
-
- /* special hacks */
- case -1:
- /* special case for rotdiff drivers... we don't need a property for this... */
- break;
-
- /* TODO... add other blocktypes... */
- default:
- CLOG_WARN(&LOG, "No path for blocktype %d, adrcode %d yet", blocktype, adrcode);
- break;
- }
-
- /* check if any property found
- * - blocktype < 0 is special case for a specific type of driver, where we don't need a property name...
- */
- if ((propname == NULL) && (blocktype > 0)) {
- /* nothing was found, so exit */
- if (array_index)
- *array_index = 0;
-
- BLI_dynstr_free(path);
-
- return NULL;
- }
- else {
- if (array_index)
- *array_index = dummy_index;
- }
-
- /* 'buf' _must_ be initialized in this block */
- /* append preceding bits to path */
- /* note, strings are not escapted and they should be! */
- if ((actname && actname[0]) && (constname && constname[0])) {
- /* Constraint in Pose-Channel */
- BLI_snprintf(buf, sizeof(buf), "pose.bones[\"%s\"].constraints[\"%s\"]", actname, constname);
- }
- else if (actname && actname[0]) {
- if ((blocktype == ID_OB) && STREQ(actname, "Object")) {
- /* Actionified "Object" IPO's... no extra path stuff needed */
- buf[0] = '\0'; /* empty string */
- }
- else if ((blocktype == ID_KE) && STREQ(actname, "Shape")) {
- /* Actionified "Shape" IPO's - these are forced onto object level via the action container there... */
- strcpy(buf, "data.shape_keys");
- }
- else {
- /* Pose-Channel */
- BLI_snprintf(buf, sizeof(buf), "pose.bones[\"%s\"]", actname);
- }
- }
- else if (constname && constname[0]) {
- /* Constraint in Object */
- BLI_snprintf(buf, sizeof(buf), "constraints[\"%s\"]", constname);
- }
- else if (seq) {
- /* Sequence names in Scene */
- BLI_snprintf(buf, sizeof(buf), "sequence_editor.sequences_all[\"%s\"]", seq->name + 2);
- }
- else {
- buf[0] = '\0'; /* empty string */
- }
-
- BLI_dynstr_append(path, buf);
-
- /* need to add dot before property if there was anything precceding this */
- if (buf[0])
- BLI_dynstr_append(path, ".");
-
- /* now write name of property */
- BLI_dynstr_append(path, propname);
-
- /* if there was no array index pointer provided, add it to the path */
- if (array_index == NULL) {
- BLI_snprintf(buf, sizeof(buf), "[\"%d\"]", dummy_index);
- BLI_dynstr_append(path, buf);
- }
-
- /* convert to normal MEM_malloc'd string */
- rpath = BLI_dynstr_get_cstring(path);
- BLI_dynstr_free(path);
-
- /* return path... */
- return rpath;
+ DynStr *path = BLI_dynstr_new();
+ const char *propname = NULL;
+ char *rpath = NULL;
+ char buf[512];
+ int dummy_index = 0;
+
+ /* hack: if constname is set, we can only be dealing with an Constraint curve */
+ if (constname)
+ blocktype = ID_CO;
+
+ /* get property name based on blocktype */
+ switch (blocktype) {
+ case ID_OB: /* object */
+ propname = ob_adrcodes_to_paths(adrcode, &dummy_index);
+ break;
+
+ case ID_PO: /* pose channel */
+ propname = pchan_adrcodes_to_paths(adrcode, &dummy_index);
+ break;
+
+ case ID_KE: /* shapekeys */
+ propname = shapekey_adrcodes_to_paths(id, adrcode, &dummy_index);
+ break;
+
+ case ID_CO: /* constraint */
+ propname = constraint_adrcodes_to_paths(adrcode, &dummy_index);
+ break;
+
+ case ID_TE: /* texture */
+ propname = texture_adrcodes_to_paths(adrcode, &dummy_index);
+ break;
+
+ case ID_MA: /* material */
+ propname = material_adrcodes_to_paths(adrcode, &dummy_index);
+ break;
+
+ case ID_CA: /* camera */
+ propname = camera_adrcodes_to_paths(adrcode, &dummy_index);
+ break;
+
+ case ID_LA: /* light */
+ propname = light_adrcodes_to_paths(adrcode, &dummy_index);
+ break;
+
+ case ID_SO: /* sound */
+ propname = sound_adrcodes_to_paths(adrcode, &dummy_index);
+ break;
+
+ case ID_WO: /* world */
+ propname = world_adrcodes_to_paths(adrcode, &dummy_index);
+ break;
+
+ case ID_PA: /* particle */
+ propname = particle_adrcodes_to_paths(adrcode, &dummy_index);
+ break;
+
+ case ID_CU: /* curve */
+ /* this used to be a 'dummy' curve which got evaluated on the fly...
+ * now we've got real var for this!
+ */
+ propname = "eval_time";
+ break;
+
+ /* XXX problematic blocktypes */
+ case ID_SEQ: /* sequencer strip */
+ //SEQ_FAC1:
+ switch (adrcode) {
+ case SEQ_FAC1:
+ propname = "effect_fader";
+ break;
+ case SEQ_FAC_SPEED:
+ propname = "speed_fader";
+ break;
+ case SEQ_FAC_OPACITY:
+ propname = "blend_opacity";
+ break;
+ }
+ // poin= &(seq->facf0); // XXX this doesn't seem to be included anywhere in sequencer RNA...
+ break;
+
+ /* special hacks */
+ case -1:
+ /* special case for rotdiff drivers... we don't need a property for this... */
+ break;
+
+ /* TODO... add other blocktypes... */
+ default:
+ CLOG_WARN(&LOG, "No path for blocktype %d, adrcode %d yet", blocktype, adrcode);
+ break;
+ }
+
+ /* check if any property found
+ * - blocktype < 0 is special case for a specific type of driver, where we don't need a property name...
+ */
+ if ((propname == NULL) && (blocktype > 0)) {
+ /* nothing was found, so exit */
+ if (array_index)
+ *array_index = 0;
+
+ BLI_dynstr_free(path);
+
+ return NULL;
+ }
+ else {
+ if (array_index)
+ *array_index = dummy_index;
+ }
+
+ /* 'buf' _must_ be initialized in this block */
+ /* append preceding bits to path */
+ /* note, strings are not escapted and they should be! */
+ if ((actname && actname[0]) && (constname && constname[0])) {
+ /* Constraint in Pose-Channel */
+ BLI_snprintf(buf, sizeof(buf), "pose.bones[\"%s\"].constraints[\"%s\"]", actname, constname);
+ }
+ else if (actname && actname[0]) {
+ if ((blocktype == ID_OB) && STREQ(actname, "Object")) {
+ /* Actionified "Object" IPO's... no extra path stuff needed */
+ buf[0] = '\0'; /* empty string */
+ }
+ else if ((blocktype == ID_KE) && STREQ(actname, "Shape")) {
+ /* Actionified "Shape" IPO's - these are forced onto object level via the action container there... */
+ strcpy(buf, "data.shape_keys");
+ }
+ else {
+ /* Pose-Channel */
+ BLI_snprintf(buf, sizeof(buf), "pose.bones[\"%s\"]", actname);
+ }
+ }
+ else if (constname && constname[0]) {
+ /* Constraint in Object */
+ BLI_snprintf(buf, sizeof(buf), "constraints[\"%s\"]", constname);
+ }
+ else if (seq) {
+ /* Sequence names in Scene */
+ BLI_snprintf(buf, sizeof(buf), "sequence_editor.sequences_all[\"%s\"]", seq->name + 2);
+ }
+ else {
+ buf[0] = '\0'; /* empty string */
+ }
+
+ BLI_dynstr_append(path, buf);
+
+ /* need to add dot before property if there was anything precceding this */
+ if (buf[0])
+ BLI_dynstr_append(path, ".");
+
+ /* now write name of property */
+ BLI_dynstr_append(path, propname);
+
+ /* if there was no array index pointer provided, add it to the path */
+ if (array_index == NULL) {
+ BLI_snprintf(buf, sizeof(buf), "[\"%d\"]", dummy_index);
+ BLI_dynstr_append(path, buf);
+ }
+
+ /* convert to normal MEM_malloc'd string */
+ rpath = BLI_dynstr_get_cstring(path);
+ BLI_dynstr_free(path);
+
+ /* return path... */
+ return rpath;
}
/* *************************************************** */
@@ -972,164 +1049,171 @@ static char *get_rna_access(ID *id, int blocktype, int adrcode, char actname[],
/* Convert adrcodes to driver target transform channel types */
static short adrcode_to_dtar_transchan(short adrcode)
{
- switch (adrcode) {
- case OB_LOC_X:
- return DTAR_TRANSCHAN_LOCX;
- case OB_LOC_Y:
- return DTAR_TRANSCHAN_LOCY;
- case OB_LOC_Z:
- return DTAR_TRANSCHAN_LOCZ;
-
- case OB_ROT_X:
- return DTAR_TRANSCHAN_ROTX;
- case OB_ROT_Y:
- return DTAR_TRANSCHAN_ROTY;
- case OB_ROT_Z:
- return DTAR_TRANSCHAN_ROTZ;
-
- case OB_SIZE_X:
- return DTAR_TRANSCHAN_SCALEX;
- case OB_SIZE_Y:
- return DTAR_TRANSCHAN_SCALEX;
- case OB_SIZE_Z:
- return DTAR_TRANSCHAN_SCALEX;
-
- default:
- return 0;
- }
+ switch (adrcode) {
+ case OB_LOC_X:
+ return DTAR_TRANSCHAN_LOCX;
+ case OB_LOC_Y:
+ return DTAR_TRANSCHAN_LOCY;
+ case OB_LOC_Z:
+ return DTAR_TRANSCHAN_LOCZ;
+
+ case OB_ROT_X:
+ return DTAR_TRANSCHAN_ROTX;
+ case OB_ROT_Y:
+ return DTAR_TRANSCHAN_ROTY;
+ case OB_ROT_Z:
+ return DTAR_TRANSCHAN_ROTZ;
+
+ case OB_SIZE_X:
+ return DTAR_TRANSCHAN_SCALEX;
+ case OB_SIZE_Y:
+ return DTAR_TRANSCHAN_SCALEX;
+ case OB_SIZE_Z:
+ return DTAR_TRANSCHAN_SCALEX;
+
+ default:
+ return 0;
+ }
}
/* Convert IpoDriver to ChannelDriver - will free the old data (i.e. the old driver) */
static ChannelDriver *idriver_to_cdriver(IpoDriver *idriver)
{
- ChannelDriver *cdriver;
-
- /* allocate memory for new driver */
- cdriver = MEM_callocN(sizeof(ChannelDriver), "ChannelDriver");
-
- /* if 'pydriver', just copy data across */
- if (idriver->type == IPO_DRIVER_TYPE_PYTHON) {
- /* PyDriver only requires the expression to be copied */
- // FIXME: expression will be useless due to API changes, but at least not totally lost
- cdriver->type = DRIVER_TYPE_PYTHON;
- if (idriver->name[0])
- BLI_strncpy(cdriver->expression, idriver->name, sizeof(cdriver->expression));
- }
- else {
- DriverVar *dvar = NULL;
- DriverTarget *dtar = NULL;
-
- /* this should be ok for all types here... */
- cdriver->type = DRIVER_TYPE_AVERAGE;
-
- /* what to store depends on the 'blocktype' - object or posechannel */
- if (idriver->blocktype == ID_AR) { /* PoseChannel */
- if (idriver->adrcode == OB_ROT_DIFF) {
- /* Rotational Difference requires a special type of variable */
- dvar = driver_add_new_variable(cdriver);
- driver_change_variable_type(dvar, DVAR_TYPE_ROT_DIFF);
-
- /* first bone target */
- dtar = &dvar->targets[0];
- dtar->id = (ID *)idriver->ob;
- dtar->idtype = ID_OB;
- if (idriver->name[0])
- BLI_strncpy(dtar->pchan_name, idriver->name, sizeof(dtar->pchan_name));
-
- /* second bone target (name was stored in same var as the first one) */
- dtar = &dvar->targets[1];
- dtar->id = (ID *)idriver->ob;
- dtar->idtype = ID_OB;
- if (idriver->name[0]) // xxx... for safety
- BLI_strncpy(dtar->pchan_name, idriver->name + DRIVER_NAME_OFFS, sizeof(dtar->pchan_name));
- }
- else {
- /* only a single variable, of type 'transform channel' */
- dvar = driver_add_new_variable(cdriver);
- driver_change_variable_type(dvar, DVAR_TYPE_TRANSFORM_CHAN);
-
- /* only requires a single target */
- dtar = &dvar->targets[0];
- dtar->id = (ID *)idriver->ob;
- dtar->idtype = ID_OB;
- if (idriver->name[0])
- BLI_strncpy(dtar->pchan_name, idriver->name, sizeof(dtar->pchan_name));
- dtar->transChan = adrcode_to_dtar_transchan(idriver->adrcode);
- dtar->flag |= DTAR_FLAG_LOCALSPACE; /* old drivers took local space */
- }
- }
- else { /* Object */
- /* only a single variable, of type 'transform channel' */
- dvar = driver_add_new_variable(cdriver);
- driver_change_variable_type(dvar, DVAR_TYPE_TRANSFORM_CHAN);
-
- /* only requires single target */
- dtar = &dvar->targets[0];
- dtar->id = (ID *)idriver->ob;
- dtar->idtype = ID_OB;
- dtar->transChan = adrcode_to_dtar_transchan(idriver->adrcode);
- }
- }
-
- /* return the new one */
- return cdriver;
+ ChannelDriver *cdriver;
+
+ /* allocate memory for new driver */
+ cdriver = MEM_callocN(sizeof(ChannelDriver), "ChannelDriver");
+
+ /* if 'pydriver', just copy data across */
+ if (idriver->type == IPO_DRIVER_TYPE_PYTHON) {
+ /* PyDriver only requires the expression to be copied */
+ // FIXME: expression will be useless due to API changes, but at least not totally lost
+ cdriver->type = DRIVER_TYPE_PYTHON;
+ if (idriver->name[0])
+ BLI_strncpy(cdriver->expression, idriver->name, sizeof(cdriver->expression));
+ }
+ else {
+ DriverVar *dvar = NULL;
+ DriverTarget *dtar = NULL;
+
+ /* this should be ok for all types here... */
+ cdriver->type = DRIVER_TYPE_AVERAGE;
+
+ /* what to store depends on the 'blocktype' - object or posechannel */
+ if (idriver->blocktype == ID_AR) { /* PoseChannel */
+ if (idriver->adrcode == OB_ROT_DIFF) {
+ /* Rotational Difference requires a special type of variable */
+ dvar = driver_add_new_variable(cdriver);
+ driver_change_variable_type(dvar, DVAR_TYPE_ROT_DIFF);
+
+ /* first bone target */
+ dtar = &dvar->targets[0];
+ dtar->id = (ID *)idriver->ob;
+ dtar->idtype = ID_OB;
+ if (idriver->name[0])
+ BLI_strncpy(dtar->pchan_name, idriver->name, sizeof(dtar->pchan_name));
+
+ /* second bone target (name was stored in same var as the first one) */
+ dtar = &dvar->targets[1];
+ dtar->id = (ID *)idriver->ob;
+ dtar->idtype = ID_OB;
+ if (idriver->name[0]) // xxx... for safety
+ BLI_strncpy(
+ dtar->pchan_name, idriver->name + DRIVER_NAME_OFFS, sizeof(dtar->pchan_name));
+ }
+ else {
+ /* only a single variable, of type 'transform channel' */
+ dvar = driver_add_new_variable(cdriver);
+ driver_change_variable_type(dvar, DVAR_TYPE_TRANSFORM_CHAN);
+
+ /* only requires a single target */
+ dtar = &dvar->targets[0];
+ dtar->id = (ID *)idriver->ob;
+ dtar->idtype = ID_OB;
+ if (idriver->name[0])
+ BLI_strncpy(dtar->pchan_name, idriver->name, sizeof(dtar->pchan_name));
+ dtar->transChan = adrcode_to_dtar_transchan(idriver->adrcode);
+ dtar->flag |= DTAR_FLAG_LOCALSPACE; /* old drivers took local space */
+ }
+ }
+ else { /* Object */
+ /* only a single variable, of type 'transform channel' */
+ dvar = driver_add_new_variable(cdriver);
+ driver_change_variable_type(dvar, DVAR_TYPE_TRANSFORM_CHAN);
+
+ /* only requires single target */
+ dtar = &dvar->targets[0];
+ dtar->id = (ID *)idriver->ob;
+ dtar->idtype = ID_OB;
+ dtar->transChan = adrcode_to_dtar_transchan(idriver->adrcode);
+ }
+ }
+
+ /* return the new one */
+ return cdriver;
}
/* Add F-Curve to the correct list
* - grpname is needed to be used as group name where relevant, and is usually derived from actname
*/
-static void fcurve_add_to_list(ListBase *groups, ListBase *list, FCurve *fcu, char *grpname, int muteipo)
+static void fcurve_add_to_list(
+ ListBase *groups, ListBase *list, FCurve *fcu, char *grpname, int muteipo)
{
- /* If we're adding to an action, we will have groups to write to... */
- if (groups && grpname) {
- /* wrap the pointers given into a dummy action that we pass to the API func
- * and extract the resultant lists...
- */
- bAction tmp_act;
- bActionGroup *agrp = NULL;
-
- /* init the temp action */
- memset(&tmp_act, 0, sizeof(bAction)); // XXX only enable this line if we get errors
- tmp_act.groups.first = groups->first;
- tmp_act.groups.last = groups->last;
- tmp_act.curves.first = list->first;
- tmp_act.curves.last = list->last;
- /* ... xxx, the other vars don't need to be filled in */
-
- /* get the group to use */
- agrp = BKE_action_group_find_name(&tmp_act, grpname);
- /* no matching group, so add one */
- if (agrp == NULL) {
- /* Add a new group, and make it active */
- agrp = MEM_callocN(sizeof(bActionGroup), "bActionGroup");
-
- agrp->flag = AGRP_SELECTED;
- if (muteipo) agrp->flag |= AGRP_MUTED;
-
- BLI_strncpy(agrp->name, grpname, sizeof(agrp->name));
-
- BLI_addtail(&tmp_act.groups, agrp);
- BLI_uniquename(&tmp_act.groups, agrp, DATA_("Group"), '.', offsetof(bActionGroup, name),
- sizeof(agrp->name));
- }
-
- /* add F-Curve to group */
- /* WARNING: this func should only need to look at the stuff we initialized, if not, things may crash */
- action_groups_add_channel(&tmp_act, agrp, fcu);
-
- if (agrp->flag & AGRP_MUTED) /* flush down */
- fcu->flag |= FCURVE_MUTED;
-
- /* set the output lists based on the ones in the temp action */
- groups->first = tmp_act.groups.first;
- groups->last = tmp_act.groups.last;
- list->first = tmp_act.curves.first;
- list->last = tmp_act.curves.last;
- }
- else {
- /* simply add the F-Curve to the end of the given list */
- BLI_addtail(list, fcu);
- }
+ /* If we're adding to an action, we will have groups to write to... */
+ if (groups && grpname) {
+ /* wrap the pointers given into a dummy action that we pass to the API func
+ * and extract the resultant lists...
+ */
+ bAction tmp_act;
+ bActionGroup *agrp = NULL;
+
+ /* init the temp action */
+ memset(&tmp_act, 0, sizeof(bAction)); // XXX only enable this line if we get errors
+ tmp_act.groups.first = groups->first;
+ tmp_act.groups.last = groups->last;
+ tmp_act.curves.first = list->first;
+ tmp_act.curves.last = list->last;
+ /* ... xxx, the other vars don't need to be filled in */
+
+ /* get the group to use */
+ agrp = BKE_action_group_find_name(&tmp_act, grpname);
+ /* no matching group, so add one */
+ if (agrp == NULL) {
+ /* Add a new group, and make it active */
+ agrp = MEM_callocN(sizeof(bActionGroup), "bActionGroup");
+
+ agrp->flag = AGRP_SELECTED;
+ if (muteipo)
+ agrp->flag |= AGRP_MUTED;
+
+ BLI_strncpy(agrp->name, grpname, sizeof(agrp->name));
+
+ BLI_addtail(&tmp_act.groups, agrp);
+ BLI_uniquename(&tmp_act.groups,
+ agrp,
+ DATA_("Group"),
+ '.',
+ offsetof(bActionGroup, name),
+ sizeof(agrp->name));
+ }
+
+ /* add F-Curve to group */
+ /* WARNING: this func should only need to look at the stuff we initialized, if not, things may crash */
+ action_groups_add_channel(&tmp_act, agrp, fcu);
+
+ if (agrp->flag & AGRP_MUTED) /* flush down */
+ fcu->flag |= FCURVE_MUTED;
+
+ /* set the output lists based on the ones in the temp action */
+ groups->first = tmp_act.groups.first;
+ groups->last = tmp_act.groups.last;
+ list->first = tmp_act.curves.first;
+ list->last = tmp_act.curves.last;
+ }
+ else {
+ /* simply add the F-Curve to the end of the given list */
+ BLI_addtail(list, fcu);
+ }
}
/* Convert IPO-Curve to F-Curve (including Driver data), and free any of the old data that
@@ -1138,242 +1222,261 @@ static void fcurve_add_to_list(ListBase *groups, ListBase *list, FCurve *fcu, ch
* constname: name of Constraint-Channel (if applicable) that IPO-Curve's IPO-block belonged to
* seq: sequencer-strip (if applicable) that IPO-Curve's IPO-block belonged to
*/
-static void icu_to_fcurves(ID *id, ListBase *groups, ListBase *list, IpoCurve *icu, char *actname, char *constname, Sequence *seq, int muteipo)
+static void icu_to_fcurves(ID *id,
+ ListBase *groups,
+ ListBase *list,
+ IpoCurve *icu,
+ char *actname,
+ char *constname,
+ Sequence *seq,
+ int muteipo)
{
- AdrBit2Path *abp;
- FCurve *fcu;
- int totbits;
-
- /* allocate memory for a new F-Curve */
- fcu = MEM_callocN(sizeof(FCurve), "FCurve");
-
- /* convert driver */
- if (icu->driver)
- fcu->driver = idriver_to_cdriver(icu->driver);
-
- /* copy flags */
- if (icu->flag & IPO_VISIBLE) fcu->flag |= FCURVE_VISIBLE;
- if (icu->flag & IPO_SELECT) fcu->flag |= FCURVE_SELECTED;
- if (icu->flag & IPO_ACTIVE) fcu->flag |= FCURVE_ACTIVE;
- if (icu->flag & IPO_MUTE) fcu->flag |= FCURVE_MUTED;
- if (icu->flag & IPO_PROTECT) fcu->flag |= FCURVE_PROTECTED;
-
- /* set extrapolation */
- switch (icu->extrap) {
- case IPO_HORIZ: /* constant extrapolation */
- case IPO_DIR: /* linear extrapolation */
- {
- /* just copy, as the new defines match the old ones... */
- fcu->extend = icu->extrap;
- break;
- }
- case IPO_CYCL: /* cyclic extrapolation */
- case IPO_CYCLX: /* cyclic extrapolation + offset */
- {
- /* Add a new FModifier (Cyclic) instead of setting extend value
- * as that's the new equivalent of that option.
- */
- FModifier *fcm = add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_CYCLES, fcu);
- FMod_Cycles *data = (FMod_Cycles *)fcm->data;
-
- /* if 'offset' one is in use, set appropriate settings */
- if (icu->extrap == IPO_CYCLX)
- data->before_mode = data->after_mode = FCM_EXTRAPOLATE_CYCLIC_OFFSET;
- else
- data->before_mode = data->after_mode = FCM_EXTRAPOLATE_CYCLIC;
- break;
- }
- }
-
- /* -------- */
-
- /* get adrcode <-> bitflags mapping to handle nasty bitflag curves? */
- abp = adrcode_bitmaps_to_paths(icu->blocktype, icu->adrcode, &totbits);
- if (abp && totbits) {
- FCurve *fcurve;
- int b;
-
- if (G.debug & G_DEBUG) printf("\tconvert bitflag ipocurve, totbits = %d\n", totbits);
-
- /* add the 'only int values' flag */
- fcu->flag |= (FCURVE_INT_VALUES | FCURVE_DISCRETE_VALUES);
-
- /* for each bit we have to remap + check for:
- * 1) we need to make copy the existing F-Curve data (fcu -> fcurve),
- * except for the last one which will use the original
- * 2) copy the relevant path info across
- * 3) filter the keyframes for the flag of interest
- */
- for (b = 0; b < totbits; b++, abp++) {
- unsigned int i = 0;
-
- /* make a copy of existing base-data if not the last curve */
- if (b < (totbits - 1))
- fcurve = copy_fcurve(fcu);
- else
- fcurve = fcu;
-
- /* set path */
- fcurve->rna_path = BLI_strdup(abp->path);
- fcurve->array_index = abp->array_index;
-
- /* convert keyframes
- * - beztriples and bpoints are mutually exclusive, so we won't have both at the same time
- * - beztriples are more likely to be encountered as they are keyframes (the other type wasn't used yet)
- */
- fcurve->totvert = icu->totvert;
-
- if (icu->bezt) {
- BezTriple *dst, *src;
-
- /* allocate new array for keyframes/beztriples */
- fcurve->bezt = MEM_callocN(sizeof(BezTriple) * fcurve->totvert, "BezTriples");
-
- /* loop through copying all BezTriples individually, as we need to modify a few things */
- for (dst = fcurve->bezt, src = icu->bezt, i = 0; i < fcurve->totvert; i++, dst++, src++) {
- /* firstly, copy BezTriple data */
- *dst = *src;
-
- /* interpolation can only be constant... */
- dst->ipo = BEZT_IPO_CONST;
-
- /* 'hide' flag is now used for keytype - only 'keyframes' existed before */
- dst->hide = BEZT_KEYTYPE_KEYFRAME;
-
- /* auto-handles - per curve to per handle */
- if (icu->flag & IPO_AUTO_HORIZ) {
- if (dst->h1 == HD_AUTO) dst->h1 = HD_AUTO_ANIM;
- if (dst->h2 == HD_AUTO) dst->h2 = HD_AUTO_ANIM;
- }
-
- /* correct values, by checking if the flag of interest is set */
- if ( ((int)(dst->vec[1][1])) & (abp->bit) )
- dst->vec[0][1] = dst->vec[1][1] = dst->vec[2][1] = 1.0f;
- else
- dst->vec[0][1] = dst->vec[1][1] = dst->vec[2][1] = 0.0f;
- }
- }
- else if (icu->bp) {
- /* TODO: need to convert from BPoint type to the more compact FPoint type... but not priority, since no data used this */
- //BPoint *bp;
- //FPoint *fpt;
- }
-
- /* add new F-Curve to list */
- fcurve_add_to_list(groups, list, fcurve, actname, muteipo);
- }
- }
- else {
- unsigned int i = 0;
-
- /* get rna-path
- * - we will need to set the 'disabled' flag if no path is able to be made (for now)
- */
- fcu->rna_path = get_rna_access(id, icu->blocktype, icu->adrcode, actname, constname, seq, &fcu->array_index);
- if (fcu->rna_path == NULL)
- fcu->flag |= FCURVE_DISABLED;
-
- /* convert keyframes
- * - beztriples and bpoints are mutually exclusive, so we won't have both at the same time
- * - beztriples are more likely to be encountered as they are keyframes (the other type wasn't used yet)
- */
- fcu->totvert = icu->totvert;
-
- if (icu->bezt) {
- BezTriple *dst, *src;
-
- /* allocate new array for keyframes/beztriples */
- fcu->bezt = MEM_callocN(sizeof(BezTriple) * fcu->totvert, "BezTriples");
-
- /* loop through copying all BezTriples individually, as we need to modify a few things */
- for (dst = fcu->bezt, src = icu->bezt, i = 0; i < fcu->totvert; i++, dst++, src++) {
- /* firstly, copy BezTriple data */
- *dst = *src;
-
- /* now copy interpolation from curve (if not already set) */
- if (icu->ipo != IPO_MIXED)
- dst->ipo = icu->ipo;
-
- /* 'hide' flag is now used for keytype - only 'keyframes' existed before */
- dst->hide = BEZT_KEYTYPE_KEYFRAME;
-
- /* auto-handles - per curve to per handle */
- if (icu->flag & IPO_AUTO_HORIZ) {
- if (dst->h1 == HD_AUTO) dst->h1 = HD_AUTO_ANIM;
- if (dst->h2 == HD_AUTO) dst->h2 = HD_AUTO_ANIM;
- }
-
- /* correct values for euler rotation curves
- * - they were degrees/10
- * - we need radians for RNA to do the right thing
- */
- if ( ((icu->blocktype == ID_OB) && ELEM(icu->adrcode, OB_ROT_X, OB_ROT_Y, OB_ROT_Z)) ||
- ((icu->blocktype == ID_PO) && ELEM(icu->adrcode, AC_EUL_X, AC_EUL_Y, AC_EUL_Z)) )
- {
- const float fac = (float)M_PI / 18.0f; //10.0f * M_PI/180.0f;
-
- dst->vec[0][1] *= fac;
- dst->vec[1][1] *= fac;
- dst->vec[2][1] *= fac;
- }
-
- /* correct values for path speed curves
- * - their values were 0-1
- * - we now need as 'frames'
- */
- if ( (id) && (icu->blocktype == GS(id->name)) &&
- (fcu->rna_path && STREQ(fcu->rna_path, "eval_time")) )
- {
- Curve *cu = (Curve *)id;
-
- dst->vec[0][1] *= cu->pathlen;
- dst->vec[1][1] *= cu->pathlen;
- dst->vec[2][1] *= cu->pathlen;
- }
-
- /* correct times for rotation drivers
- * - need to go from degrees to radians...
- * - there's only really 1 target to worry about
- * - were also degrees/10
- */
- if (fcu->driver && fcu->driver->variables.first) {
- DriverVar *dvar = fcu->driver->variables.first;
- DriverTarget *dtar = &dvar->targets[0];
-
- if (ELEM(dtar->transChan, DTAR_TRANSCHAN_ROTX, DTAR_TRANSCHAN_ROTY, DTAR_TRANSCHAN_ROTZ)) {
- const float fac = (float)M_PI / 18.0f;
-
- dst->vec[0][0] *= fac;
- dst->vec[1][0] *= fac;
- dst->vec[2][0] *= fac;
- }
- }
-
- /* correct values for sequencer curves, that were not locked to frame */
- if (seq && (seq->flag & SEQ_IPO_FRAME_LOCKED) == 0) {
- const float mul = (seq->enddisp - seq->startdisp) / 100.0f;
- const float offset = seq->startdisp;
-
- dst->vec[0][0] *= mul;
- dst->vec[0][0] += offset;
-
- dst->vec[1][0] *= mul;
- dst->vec[1][0] += offset;
-
- dst->vec[2][0] *= mul;
- dst->vec[2][0] += offset;
- }
- }
- }
- else if (icu->bp) {
- /* TODO: need to convert from BPoint type to the more compact FPoint type... but not priority, since no data used this */
- //BPoint *bp;
- //FPoint *fpt;
- }
-
- /* add new F-Curve to list */
- fcurve_add_to_list(groups, list, fcu, actname, muteipo);
- }
+ AdrBit2Path *abp;
+ FCurve *fcu;
+ int totbits;
+
+ /* allocate memory for a new F-Curve */
+ fcu = MEM_callocN(sizeof(FCurve), "FCurve");
+
+ /* convert driver */
+ if (icu->driver)
+ fcu->driver = idriver_to_cdriver(icu->driver);
+
+ /* copy flags */
+ if (icu->flag & IPO_VISIBLE)
+ fcu->flag |= FCURVE_VISIBLE;
+ if (icu->flag & IPO_SELECT)
+ fcu->flag |= FCURVE_SELECTED;
+ if (icu->flag & IPO_ACTIVE)
+ fcu->flag |= FCURVE_ACTIVE;
+ if (icu->flag & IPO_MUTE)
+ fcu->flag |= FCURVE_MUTED;
+ if (icu->flag & IPO_PROTECT)
+ fcu->flag |= FCURVE_PROTECTED;
+
+ /* set extrapolation */
+ switch (icu->extrap) {
+ case IPO_HORIZ: /* constant extrapolation */
+ case IPO_DIR: /* linear extrapolation */
+ {
+ /* just copy, as the new defines match the old ones... */
+ fcu->extend = icu->extrap;
+ break;
+ }
+ case IPO_CYCL: /* cyclic extrapolation */
+ case IPO_CYCLX: /* cyclic extrapolation + offset */
+ {
+ /* Add a new FModifier (Cyclic) instead of setting extend value
+ * as that's the new equivalent of that option.
+ */
+ FModifier *fcm = add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_CYCLES, fcu);
+ FMod_Cycles *data = (FMod_Cycles *)fcm->data;
+
+ /* if 'offset' one is in use, set appropriate settings */
+ if (icu->extrap == IPO_CYCLX)
+ data->before_mode = data->after_mode = FCM_EXTRAPOLATE_CYCLIC_OFFSET;
+ else
+ data->before_mode = data->after_mode = FCM_EXTRAPOLATE_CYCLIC;
+ break;
+ }
+ }
+
+ /* -------- */
+
+ /* get adrcode <-> bitflags mapping to handle nasty bitflag curves? */
+ abp = adrcode_bitmaps_to_paths(icu->blocktype, icu->adrcode, &totbits);
+ if (abp && totbits) {
+ FCurve *fcurve;
+ int b;
+
+ if (G.debug & G_DEBUG)
+ printf("\tconvert bitflag ipocurve, totbits = %d\n", totbits);
+
+ /* add the 'only int values' flag */
+ fcu->flag |= (FCURVE_INT_VALUES | FCURVE_DISCRETE_VALUES);
+
+ /* for each bit we have to remap + check for:
+ * 1) we need to make copy the existing F-Curve data (fcu -> fcurve),
+ * except for the last one which will use the original
+ * 2) copy the relevant path info across
+ * 3) filter the keyframes for the flag of interest
+ */
+ for (b = 0; b < totbits; b++, abp++) {
+ unsigned int i = 0;
+
+ /* make a copy of existing base-data if not the last curve */
+ if (b < (totbits - 1))
+ fcurve = copy_fcurve(fcu);
+ else
+ fcurve = fcu;
+
+ /* set path */
+ fcurve->rna_path = BLI_strdup(abp->path);
+ fcurve->array_index = abp->array_index;
+
+ /* convert keyframes
+ * - beztriples and bpoints are mutually exclusive, so we won't have both at the same time
+ * - beztriples are more likely to be encountered as they are keyframes (the other type wasn't used yet)
+ */
+ fcurve->totvert = icu->totvert;
+
+ if (icu->bezt) {
+ BezTriple *dst, *src;
+
+ /* allocate new array for keyframes/beztriples */
+ fcurve->bezt = MEM_callocN(sizeof(BezTriple) * fcurve->totvert, "BezTriples");
+
+ /* loop through copying all BezTriples individually, as we need to modify a few things */
+ for (dst = fcurve->bezt, src = icu->bezt, i = 0; i < fcurve->totvert; i++, dst++, src++) {
+ /* firstly, copy BezTriple data */
+ *dst = *src;
+
+ /* interpolation can only be constant... */
+ dst->ipo = BEZT_IPO_CONST;
+
+ /* 'hide' flag is now used for keytype - only 'keyframes' existed before */
+ dst->hide = BEZT_KEYTYPE_KEYFRAME;
+
+ /* auto-handles - per curve to per handle */
+ if (icu->flag & IPO_AUTO_HORIZ) {
+ if (dst->h1 == HD_AUTO)
+ dst->h1 = HD_AUTO_ANIM;
+ if (dst->h2 == HD_AUTO)
+ dst->h2 = HD_AUTO_ANIM;
+ }
+
+ /* correct values, by checking if the flag of interest is set */
+ if (((int)(dst->vec[1][1])) & (abp->bit))
+ dst->vec[0][1] = dst->vec[1][1] = dst->vec[2][1] = 1.0f;
+ else
+ dst->vec[0][1] = dst->vec[1][1] = dst->vec[2][1] = 0.0f;
+ }
+ }
+ else if (icu->bp) {
+ /* TODO: need to convert from BPoint type to the more compact FPoint type... but not priority, since no data used this */
+ //BPoint *bp;
+ //FPoint *fpt;
+ }
+
+ /* add new F-Curve to list */
+ fcurve_add_to_list(groups, list, fcurve, actname, muteipo);
+ }
+ }
+ else {
+ unsigned int i = 0;
+
+ /* get rna-path
+ * - we will need to set the 'disabled' flag if no path is able to be made (for now)
+ */
+ fcu->rna_path = get_rna_access(
+ id, icu->blocktype, icu->adrcode, actname, constname, seq, &fcu->array_index);
+ if (fcu->rna_path == NULL)
+ fcu->flag |= FCURVE_DISABLED;
+
+ /* convert keyframes
+ * - beztriples and bpoints are mutually exclusive, so we won't have both at the same time
+ * - beztriples are more likely to be encountered as they are keyframes (the other type wasn't used yet)
+ */
+ fcu->totvert = icu->totvert;
+
+ if (icu->bezt) {
+ BezTriple *dst, *src;
+
+ /* allocate new array for keyframes/beztriples */
+ fcu->bezt = MEM_callocN(sizeof(BezTriple) * fcu->totvert, "BezTriples");
+
+ /* loop through copying all BezTriples individually, as we need to modify a few things */
+ for (dst = fcu->bezt, src = icu->bezt, i = 0; i < fcu->totvert; i++, dst++, src++) {
+ /* firstly, copy BezTriple data */
+ *dst = *src;
+
+ /* now copy interpolation from curve (if not already set) */
+ if (icu->ipo != IPO_MIXED)
+ dst->ipo = icu->ipo;
+
+ /* 'hide' flag is now used for keytype - only 'keyframes' existed before */
+ dst->hide = BEZT_KEYTYPE_KEYFRAME;
+
+ /* auto-handles - per curve to per handle */
+ if (icu->flag & IPO_AUTO_HORIZ) {
+ if (dst->h1 == HD_AUTO)
+ dst->h1 = HD_AUTO_ANIM;
+ if (dst->h2 == HD_AUTO)
+ dst->h2 = HD_AUTO_ANIM;
+ }
+
+ /* correct values for euler rotation curves
+ * - they were degrees/10
+ * - we need radians for RNA to do the right thing
+ */
+ if (((icu->blocktype == ID_OB) && ELEM(icu->adrcode, OB_ROT_X, OB_ROT_Y, OB_ROT_Z)) ||
+ ((icu->blocktype == ID_PO) && ELEM(icu->adrcode, AC_EUL_X, AC_EUL_Y, AC_EUL_Z))) {
+ const float fac = (float)M_PI / 18.0f; //10.0f * M_PI/180.0f;
+
+ dst->vec[0][1] *= fac;
+ dst->vec[1][1] *= fac;
+ dst->vec[2][1] *= fac;
+ }
+
+ /* correct values for path speed curves
+ * - their values were 0-1
+ * - we now need as 'frames'
+ */
+ if ((id) && (icu->blocktype == GS(id->name)) &&
+ (fcu->rna_path && STREQ(fcu->rna_path, "eval_time"))) {
+ Curve *cu = (Curve *)id;
+
+ dst->vec[0][1] *= cu->pathlen;
+ dst->vec[1][1] *= cu->pathlen;
+ dst->vec[2][1] *= cu->pathlen;
+ }
+
+ /* correct times for rotation drivers
+ * - need to go from degrees to radians...
+ * - there's only really 1 target to worry about
+ * - were also degrees/10
+ */
+ if (fcu->driver && fcu->driver->variables.first) {
+ DriverVar *dvar = fcu->driver->variables.first;
+ DriverTarget *dtar = &dvar->targets[0];
+
+ if (ELEM(dtar->transChan,
+ DTAR_TRANSCHAN_ROTX,
+ DTAR_TRANSCHAN_ROTY,
+ DTAR_TRANSCHAN_ROTZ)) {
+ const float fac = (float)M_PI / 18.0f;
+
+ dst->vec[0][0] *= fac;
+ dst->vec[1][0] *= fac;
+ dst->vec[2][0] *= fac;
+ }
+ }
+
+ /* correct values for sequencer curves, that were not locked to frame */
+ if (seq && (seq->flag & SEQ_IPO_FRAME_LOCKED) == 0) {
+ const float mul = (seq->enddisp - seq->startdisp) / 100.0f;
+ const float offset = seq->startdisp;
+
+ dst->vec[0][0] *= mul;
+ dst->vec[0][0] += offset;
+
+ dst->vec[1][0] *= mul;
+ dst->vec[1][0] += offset;
+
+ dst->vec[2][0] *= mul;
+ dst->vec[2][0] += offset;
+ }
+ }
+ }
+ else if (icu->bp) {
+ /* TODO: need to convert from BPoint type to the more compact FPoint type... but not priority, since no data used this */
+ //BPoint *bp;
+ //FPoint *fpt;
+ }
+
+ /* add new F-Curve to list */
+ fcurve_add_to_list(groups, list, fcu, actname, muteipo);
+ }
}
/* ------------------------- */
@@ -1382,68 +1485,78 @@ static void icu_to_fcurves(ID *id, ListBase *groups, ListBase *list, IpoCurve *i
* This does not assume that any ID or AnimData uses it, but does assume that
* it is given two lists, which it will perform driver/animation-data separation.
*/
-static void ipo_to_animato(ID *id, Ipo *ipo, char actname[], char constname[], Sequence *seq, ListBase *animgroups, ListBase *anim, ListBase *drivers)
+static void ipo_to_animato(ID *id,
+ Ipo *ipo,
+ char actname[],
+ char constname[],
+ Sequence *seq,
+ ListBase *animgroups,
+ ListBase *anim,
+ ListBase *drivers)
{
- IpoCurve *icu;
-
- /* sanity check */
- if (ELEM(NULL, ipo, anim, drivers))
- return;
-
- if (G.debug & G_DEBUG) printf("ipo_to_animato\n");
-
- /* validate actname and constname
- * - clear actname if it was one of the generic <builtin> ones (i.e. 'Object', or 'Shapes')
- * - actname can then be used to assign F-Curves in Action to Action Groups
- * (i.e. thus keeping the benefits that used to be provided by Action Channels for grouping
- * F-Curves for bones). This may be added later... for now let's just dump without them...
- */
- if (actname) {
- if ((ipo->blocktype == ID_OB) && STREQ(actname, "Object"))
- actname = NULL;
- else if ((ipo->blocktype == ID_OB) && STREQ(actname, "Shape"))
- actname = NULL;
- }
-
- /* loop over IPO-Curves, freeing as we progress */
- for (icu = ipo->curve.first; icu; icu = icu->next) {
- /* Since an IPO-Curve may end up being made into many F-Curves (i.e. bitflag curves),
- * we figure out the best place to put the channel, then tell the curve-converter to just dump there
- */
- if (icu->driver) {
- /* Blender 2.4x allowed empty drivers, but we don't now, since they cause more trouble than they're worth */
- if ((icu->driver->ob) || (icu->driver->type == IPO_DRIVER_TYPE_PYTHON)) {
- icu_to_fcurves(id, NULL, drivers, icu, actname, constname, seq, ipo->muteipo);
- }
- else {
- MEM_freeN(icu->driver);
- icu->driver = NULL;
- }
- }
- else
- icu_to_fcurves(id, animgroups, anim, icu, actname, constname, seq, ipo->muteipo);
- }
-
- /* if this IPO block doesn't have any users after this one, free... */
- id_us_min(&ipo->id);
- if (ID_REAL_USERS(ipo) <= 0) {
- IpoCurve *icn;
-
- for (icu = ipo->curve.first; icu; icu = icn) {
- icn = icu->next;
-
- /* free driver */
- if (icu->driver)
- MEM_freeN(icu->driver);
-
- /* free old data of curve now that it's no longer needed for converting any more curves */
- if (icu->bezt) MEM_freeN(icu->bezt);
- if (icu->bp) MEM_freeN(icu->bezt);
-
- /* free this IPO-Curve */
- BLI_freelinkN(&ipo->curve, icu);
- }
- }
+ IpoCurve *icu;
+
+ /* sanity check */
+ if (ELEM(NULL, ipo, anim, drivers))
+ return;
+
+ if (G.debug & G_DEBUG)
+ printf("ipo_to_animato\n");
+
+ /* validate actname and constname
+ * - clear actname if it was one of the generic <builtin> ones (i.e. 'Object', or 'Shapes')
+ * - actname can then be used to assign F-Curves in Action to Action Groups
+ * (i.e. thus keeping the benefits that used to be provided by Action Channels for grouping
+ * F-Curves for bones). This may be added later... for now let's just dump without them...
+ */
+ if (actname) {
+ if ((ipo->blocktype == ID_OB) && STREQ(actname, "Object"))
+ actname = NULL;
+ else if ((ipo->blocktype == ID_OB) && STREQ(actname, "Shape"))
+ actname = NULL;
+ }
+
+ /* loop over IPO-Curves, freeing as we progress */
+ for (icu = ipo->curve.first; icu; icu = icu->next) {
+ /* Since an IPO-Curve may end up being made into many F-Curves (i.e. bitflag curves),
+ * we figure out the best place to put the channel, then tell the curve-converter to just dump there
+ */
+ if (icu->driver) {
+ /* Blender 2.4x allowed empty drivers, but we don't now, since they cause more trouble than they're worth */
+ if ((icu->driver->ob) || (icu->driver->type == IPO_DRIVER_TYPE_PYTHON)) {
+ icu_to_fcurves(id, NULL, drivers, icu, actname, constname, seq, ipo->muteipo);
+ }
+ else {
+ MEM_freeN(icu->driver);
+ icu->driver = NULL;
+ }
+ }
+ else
+ icu_to_fcurves(id, animgroups, anim, icu, actname, constname, seq, ipo->muteipo);
+ }
+
+ /* if this IPO block doesn't have any users after this one, free... */
+ id_us_min(&ipo->id);
+ if (ID_REAL_USERS(ipo) <= 0) {
+ IpoCurve *icn;
+
+ for (icu = ipo->curve.first; icu; icu = icn) {
+ icn = icu->next;
+
+ /* free driver */
+ if (icu->driver)
+ MEM_freeN(icu->driver);
+
+ /* free old data of curve now that it's no longer needed for converting any more curves */
+ if (icu->bezt)
+ MEM_freeN(icu->bezt);
+ if (icu->bp)
+ MEM_freeN(icu->bezt);
+
+ /* free this IPO-Curve */
+ BLI_freelinkN(&ipo->curve, icu);
+ }
+ }
}
/* Convert Action-block to new system, separating animation and drivers
@@ -1451,109 +1564,118 @@ static void ipo_to_animato(ID *id, Ipo *ipo, char actname[], char constname[], S
* to Objects, where ob->ipo and ob->action need to be combined).
* NOTE: we need to be careful here, as same data-structs are used for new system too!
*/
-static void action_to_animato(ID *id, bAction *act, ListBase *groups, ListBase *curves, ListBase *drivers)
+static void action_to_animato(
+ ID *id, bAction *act, ListBase *groups, ListBase *curves, ListBase *drivers)
{
- bActionChannel *achan, *achann;
- bConstraintChannel *conchan, *conchann;
-
- /* only continue if there are Action Channels (indicating unconverted data) */
- if (BLI_listbase_is_empty(&act->chanbase))
- return;
-
- /* get rid of all Action Groups */
- // XXX this is risky if there's some old + some new data in the Action...
- if (act->groups.first)
- BLI_freelistN(&act->groups);
-
- /* loop through Action-Channels, converting data, freeing as we go */
- for (achan = act->chanbase.first; achan; achan = achann) {
- /* get pointer to next Action Channel */
- achann = achan->next;
-
- /* convert Action Channel's IPO data */
- if (achan->ipo) {
- ipo_to_animato(id, achan->ipo, achan->name, NULL, NULL, groups, curves, drivers);
- id_us_min(&achan->ipo->id);
- achan->ipo = NULL;
- }
-
- /* convert constraint channel IPO-data */
- for (conchan = achan->constraintChannels.first; conchan; conchan = conchann) {
- /* get pointer to next Constraint Channel */
- conchann = conchan->next;
-
- /* convert Constraint Channel's IPO data */
- if (conchan->ipo) {
- ipo_to_animato(id, conchan->ipo, achan->name, conchan->name, NULL, groups, curves, drivers);
- id_us_min(&conchan->ipo->id);
- conchan->ipo = NULL;
- }
-
- /* free Constraint Channel */
- BLI_freelinkN(&achan->constraintChannels, conchan);
- }
-
- /* free Action Channel */
- BLI_freelinkN(&act->chanbase, achan);
- }
+ bActionChannel *achan, *achann;
+ bConstraintChannel *conchan, *conchann;
+
+ /* only continue if there are Action Channels (indicating unconverted data) */
+ if (BLI_listbase_is_empty(&act->chanbase))
+ return;
+
+ /* get rid of all Action Groups */
+ // XXX this is risky if there's some old + some new data in the Action...
+ if (act->groups.first)
+ BLI_freelistN(&act->groups);
+
+ /* loop through Action-Channels, converting data, freeing as we go */
+ for (achan = act->chanbase.first; achan; achan = achann) {
+ /* get pointer to next Action Channel */
+ achann = achan->next;
+
+ /* convert Action Channel's IPO data */
+ if (achan->ipo) {
+ ipo_to_animato(id, achan->ipo, achan->name, NULL, NULL, groups, curves, drivers);
+ id_us_min(&achan->ipo->id);
+ achan->ipo = NULL;
+ }
+
+ /* convert constraint channel IPO-data */
+ for (conchan = achan->constraintChannels.first; conchan; conchan = conchann) {
+ /* get pointer to next Constraint Channel */
+ conchann = conchan->next;
+
+ /* convert Constraint Channel's IPO data */
+ if (conchan->ipo) {
+ ipo_to_animato(
+ id, conchan->ipo, achan->name, conchan->name, NULL, groups, curves, drivers);
+ id_us_min(&conchan->ipo->id);
+ conchan->ipo = NULL;
+ }
+
+ /* free Constraint Channel */
+ BLI_freelinkN(&achan->constraintChannels, conchan);
+ }
+
+ /* free Action Channel */
+ BLI_freelinkN(&act->chanbase, achan);
+ }
}
-
/* ------------------------- */
/* Convert IPO-block (i.e. all its IpoCurves) for some ID to the new system
* This assumes that AnimData has been added already. Separation of drivers
* from animation data is accomplished here too...
*/
-static void ipo_to_animdata(Main *bmain, ID *id, Ipo *ipo, char actname[], char constname[], Sequence *seq)
+static void ipo_to_animdata(
+ Main *bmain, ID *id, Ipo *ipo, char actname[], char constname[], Sequence *seq)
{
- AnimData *adt = BKE_animdata_from_id(id);
- ListBase anim = {NULL, NULL};
- ListBase drivers = {NULL, NULL};
-
- /* sanity check */
- if (ELEM(NULL, id, ipo))
- return;
- if (adt == NULL) {
- CLOG_ERROR(&LOG, "adt invalid");
- return;
- }
-
- if (G.debug & G_DEBUG) {
- printf("ipo to animdata - ID:%s, IPO:%s, actname:%s constname:%s seqname:%s curves:%d\n",
- id->name + 2, ipo->id.name + 2, (actname) ? actname : "<None>", (constname) ? constname : "<None>", (seq) ? (seq->name + 2) : "<None>",
- BLI_listbase_count(&ipo->curve));
- }
-
- /* Convert curves to animato system (separated into separate lists of F-Curves for animation and drivers),
- * and the try to put these lists in the right places, but do not free the lists here
- */
- // XXX there shouldn't be any need for the groups, so don't supply pointer for that now...
- ipo_to_animato(id, ipo, actname, constname, seq, NULL, &anim, &drivers);
-
- /* deal with animation first */
- if (anim.first) {
- if (G.debug & G_DEBUG) printf("\thas anim\n");
- /* try to get action */
- if (adt->action == NULL) {
- char nameBuf[MAX_ID_NAME];
-
- BLI_snprintf(nameBuf, sizeof(nameBuf), "CDA:%s", ipo->id.name + 2);
-
- adt->action = BKE_action_add(bmain, nameBuf);
- if (G.debug & G_DEBUG) printf("\t\tadded new action - '%s'\n", nameBuf);
- }
-
- /* add F-Curves to action */
- BLI_movelisttolist(&adt->action->curves, &anim);
- }
-
- /* deal with drivers */
- if (drivers.first) {
- if (G.debug & G_DEBUG) printf("\thas drivers\n");
- /* add drivers to end of driver stack */
- BLI_movelisttolist(&adt->drivers, &drivers);
- }
+ AnimData *adt = BKE_animdata_from_id(id);
+ ListBase anim = {NULL, NULL};
+ ListBase drivers = {NULL, NULL};
+
+ /* sanity check */
+ if (ELEM(NULL, id, ipo))
+ return;
+ if (adt == NULL) {
+ CLOG_ERROR(&LOG, "adt invalid");
+ return;
+ }
+
+ if (G.debug & G_DEBUG) {
+ printf("ipo to animdata - ID:%s, IPO:%s, actname:%s constname:%s seqname:%s curves:%d\n",
+ id->name + 2,
+ ipo->id.name + 2,
+ (actname) ? actname : "<None>",
+ (constname) ? constname : "<None>",
+ (seq) ? (seq->name + 2) : "<None>",
+ BLI_listbase_count(&ipo->curve));
+ }
+
+ /* Convert curves to animato system (separated into separate lists of F-Curves for animation and drivers),
+ * and the try to put these lists in the right places, but do not free the lists here
+ */
+ // XXX there shouldn't be any need for the groups, so don't supply pointer for that now...
+ ipo_to_animato(id, ipo, actname, constname, seq, NULL, &anim, &drivers);
+
+ /* deal with animation first */
+ if (anim.first) {
+ if (G.debug & G_DEBUG)
+ printf("\thas anim\n");
+ /* try to get action */
+ if (adt->action == NULL) {
+ char nameBuf[MAX_ID_NAME];
+
+ BLI_snprintf(nameBuf, sizeof(nameBuf), "CDA:%s", ipo->id.name + 2);
+
+ adt->action = BKE_action_add(bmain, nameBuf);
+ if (G.debug & G_DEBUG)
+ printf("\t\tadded new action - '%s'\n", nameBuf);
+ }
+
+ /* add F-Curves to action */
+ BLI_movelisttolist(&adt->action->curves, &anim);
+ }
+
+ /* deal with drivers */
+ if (drivers.first) {
+ if (G.debug & G_DEBUG)
+ printf("\thas drivers\n");
+ /* add drivers to end of driver stack */
+ BLI_movelisttolist(&adt->drivers, &drivers);
+ }
}
/* Convert Action-block to new system
@@ -1561,21 +1683,22 @@ static void ipo_to_animdata(Main *bmain, ID *id, Ipo *ipo, char actname[], char
*/
static void action_to_animdata(ID *id, bAction *act)
{
- AnimData *adt = BKE_animdata_from_id(id);
-
- /* only continue if there are Action Channels (indicating unconverted data) */
- if (ELEM(NULL, adt, act->chanbase.first))
- return;
-
- /* check if we need to set this Action as the AnimData's action */
- if (adt->action == NULL) {
- /* set this Action as AnimData's Action */
- if (G.debug & G_DEBUG) printf("act_to_adt - set adt action to act\n");
- adt->action = act;
- }
-
- /* convert Action data */
- action_to_animato(id, act, &adt->action->groups, &adt->action->curves, &adt->drivers);
+ AnimData *adt = BKE_animdata_from_id(id);
+
+ /* only continue if there are Action Channels (indicating unconverted data) */
+ if (ELEM(NULL, adt, act->chanbase.first))
+ return;
+
+ /* check if we need to set this Action as the AnimData's action */
+ if (adt->action == NULL) {
+ /* set this Action as AnimData's Action */
+ if (G.debug & G_DEBUG)
+ printf("act_to_adt - set adt action to act\n");
+ adt->action = act;
+ }
+
+ /* convert Action data */
+ action_to_animato(id, act, &adt->action->groups, &adt->action->curves, &adt->drivers);
}
/* ------------------------- */
@@ -1587,79 +1710,86 @@ static void action_to_animdata(ID *id, bAction *act)
/* Convert NLA-Strip to new system */
static void nlastrips_to_animdata(ID *id, ListBase *strips)
{
- AnimData *adt = BKE_animdata_from_id(id);
- NlaTrack *nlt = NULL;
- NlaStrip *strip;
- bActionStrip *as, *asn;
-
- /* for each one of the original strips, convert to a new strip and free the old... */
- for (as = strips->first; as; as = asn) {
- asn = as->next;
-
- /* this old strip is only worth something if it had an action... */
- if (as->act) {
- /* convert Action data (if not yet converted), storing the results in the same Action */
- action_to_animato(id, as->act, &as->act->groups, &as->act->curves, &adt->drivers);
-
- /* create a new-style NLA-strip which references this Action, then copy over relevant settings */
- {
- /* init a new strip, and assign the action to it
- * - no need to muck around with the user-counts, since this is just
- * passing over the ref to the new owner, not creating an additional ref
- */
- strip = MEM_callocN(sizeof(NlaStrip), "NlaStrip");
- strip->act = as->act;
-
- /* endpoints */
- strip->start = as->start;
- strip->end = as->end;
- strip->actstart = as->actstart;
- strip->actend = as->actend;
-
- /* action reuse */
- strip->repeat = as->repeat;
- strip->scale = as->scale;
- if (as->flag & ACTSTRIP_LOCK_ACTION) strip->flag |= NLASTRIP_FLAG_SYNC_LENGTH;
-
- /* blending */
- strip->blendin = as->blendin;
- strip->blendout = as->blendout;
- strip->blendmode = (as->mode == ACTSTRIPMODE_ADD) ? NLASTRIP_MODE_ADD : NLASTRIP_MODE_REPLACE;
- if (as->flag & ACTSTRIP_AUTO_BLENDS) strip->flag |= NLASTRIP_FLAG_AUTO_BLENDS;
-
- /* assorted setting flags */
- if (as->flag & ACTSTRIP_SELECT) strip->flag |= NLASTRIP_FLAG_SELECT;
- if (as->flag & ACTSTRIP_ACTIVE) strip->flag |= NLASTRIP_FLAG_ACTIVE;
-
- if (as->flag & ACTSTRIP_MUTE) strip->flag |= NLASTRIP_FLAG_MUTED;
- if (as->flag & ACTSTRIP_REVERSE) strip->flag |= NLASTRIP_FLAG_REVERSE;
-
- /* by default, we now always extrapolate, while in the past this was optional */
- if ((as->flag & ACTSTRIP_HOLDLASTFRAME) == 0)
- strip->extendmode = NLASTRIP_EXTEND_NOTHING;
- }
-
- /* try to add this strip to the current NLA-Track (i.e. the 'last' one on the stack atm) */
- if (BKE_nlatrack_add_strip(nlt, strip) == 0) {
- /* trying to add to the current failed (no space),
- * so add a new track to the stack, and add to that...
- */
- nlt = BKE_nlatrack_add(adt, NULL);
- BKE_nlatrack_add_strip(nlt, strip);
- }
-
- /* ensure that strip has a name */
- BKE_nlastrip_validate_name(adt, strip);
- }
-
- /* modifiers */
- // FIXME: for now, we just free them...
- if (as->modifiers.first)
- BLI_freelistN(&as->modifiers);
-
- /* free the old strip */
- BLI_freelinkN(strips, as);
- }
+ AnimData *adt = BKE_animdata_from_id(id);
+ NlaTrack *nlt = NULL;
+ NlaStrip *strip;
+ bActionStrip *as, *asn;
+
+ /* for each one of the original strips, convert to a new strip and free the old... */
+ for (as = strips->first; as; as = asn) {
+ asn = as->next;
+
+ /* this old strip is only worth something if it had an action... */
+ if (as->act) {
+ /* convert Action data (if not yet converted), storing the results in the same Action */
+ action_to_animato(id, as->act, &as->act->groups, &as->act->curves, &adt->drivers);
+
+ /* create a new-style NLA-strip which references this Action, then copy over relevant settings */
+ {
+ /* init a new strip, and assign the action to it
+ * - no need to muck around with the user-counts, since this is just
+ * passing over the ref to the new owner, not creating an additional ref
+ */
+ strip = MEM_callocN(sizeof(NlaStrip), "NlaStrip");
+ strip->act = as->act;
+
+ /* endpoints */
+ strip->start = as->start;
+ strip->end = as->end;
+ strip->actstart = as->actstart;
+ strip->actend = as->actend;
+
+ /* action reuse */
+ strip->repeat = as->repeat;
+ strip->scale = as->scale;
+ if (as->flag & ACTSTRIP_LOCK_ACTION)
+ strip->flag |= NLASTRIP_FLAG_SYNC_LENGTH;
+
+ /* blending */
+ strip->blendin = as->blendin;
+ strip->blendout = as->blendout;
+ strip->blendmode = (as->mode == ACTSTRIPMODE_ADD) ? NLASTRIP_MODE_ADD :
+ NLASTRIP_MODE_REPLACE;
+ if (as->flag & ACTSTRIP_AUTO_BLENDS)
+ strip->flag |= NLASTRIP_FLAG_AUTO_BLENDS;
+
+ /* assorted setting flags */
+ if (as->flag & ACTSTRIP_SELECT)
+ strip->flag |= NLASTRIP_FLAG_SELECT;
+ if (as->flag & ACTSTRIP_ACTIVE)
+ strip->flag |= NLASTRIP_FLAG_ACTIVE;
+
+ if (as->flag & ACTSTRIP_MUTE)
+ strip->flag |= NLASTRIP_FLAG_MUTED;
+ if (as->flag & ACTSTRIP_REVERSE)
+ strip->flag |= NLASTRIP_FLAG_REVERSE;
+
+ /* by default, we now always extrapolate, while in the past this was optional */
+ if ((as->flag & ACTSTRIP_HOLDLASTFRAME) == 0)
+ strip->extendmode = NLASTRIP_EXTEND_NOTHING;
+ }
+
+ /* try to add this strip to the current NLA-Track (i.e. the 'last' one on the stack atm) */
+ if (BKE_nlatrack_add_strip(nlt, strip) == 0) {
+ /* trying to add to the current failed (no space),
+ * so add a new track to the stack, and add to that...
+ */
+ nlt = BKE_nlatrack_add(adt, NULL);
+ BKE_nlatrack_add_strip(nlt, strip);
+ }
+
+ /* ensure that strip has a name */
+ BKE_nlastrip_validate_name(adt, strip);
+ }
+
+ /* modifiers */
+ // FIXME: for now, we just free them...
+ if (as->modifiers.first)
+ BLI_freelistN(&as->modifiers);
+
+ /* free the old strip */
+ BLI_freelinkN(strips, as);
+ }
}
/* *************************************************** */
@@ -1678,410 +1808,419 @@ static void nlastrips_to_animdata(ID *id, ListBase *strips)
// XXX currently done after all file reading...
void do_versions_ipos_to_animato(Main *bmain)
{
- ListBase drivers = {NULL, NULL};
- ID *id;
-
- if (bmain == NULL) {
- CLOG_ERROR(&LOG, "Argh! Main is NULL");
- return;
- }
-
- /* only convert if version is right */
- if (bmain->versionfile >= 250) {
- CLOG_WARN(&LOG, "Animation data too new to convert (Version %d)", bmain->versionfile);
- return;
- }
- else if (G.debug & G_DEBUG)
- printf("INFO: Converting to Animato...\n");
-
- /* ----------- Animation Attached to Data -------------- */
-
- /* objects */
- for (id = bmain->objects.first; id; id = id->next) {
- Object *ob = (Object *)id;
- bPoseChannel *pchan;
- bConstraint *con;
- bConstraintChannel *conchan, *conchann;
-
- if (G.debug & G_DEBUG) printf("\tconverting ob %s\n", id->name + 2);
-
- /* check if object has any animation data */
- if (ob->nlastrips.first) {
- /* Add AnimData block */
- BKE_animdata_add_id(id);
-
- /* IPO first to take into any non-NLA'd Object Animation */
- if (ob->ipo) {
- ipo_to_animdata(bmain, id, ob->ipo, NULL, NULL, NULL);
- /* No need to id_us_min ipo ID here, ipo_to_animdata already does it. */
- ob->ipo = NULL;
- }
-
- /* Action is skipped since it'll be used by some strip in the NLA anyway,
- * causing errors with evaluation in the new evaluation pipeline
- */
- if (ob->action) {
- id_us_min(&ob->action->id);
- ob->action = NULL;
- }
-
- /* finally NLA */
- nlastrips_to_animdata(id, &ob->nlastrips);
- }
- else if ((ob->ipo) || (ob->action)) {
- /* Add AnimData block */
- AnimData *adt = BKE_animdata_add_id(id);
-
- /* Action first - so that Action name get conserved */
- if (ob->action) {
- action_to_animdata(id, ob->action);
-
- /* only decrease usercount if this Action isn't now being used by AnimData */
- if (ob->action != adt->action) {
- id_us_min(&ob->action->id);
- ob->action = NULL;
- }
- }
-
- /* IPO second... */
- if (ob->ipo) {
- ipo_to_animdata(bmain, id, ob->ipo, NULL, NULL, NULL);
- /* No need to id_us_min ipo ID here, ipo_to_animdata already does it. */
- ob->ipo = NULL;
- }
- }
-
- /* check PoseChannels for constraints with local data */
- if (ob->pose) {
- /* Verify if there's AnimData block */
- BKE_animdata_add_id(id);
-
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- for (con = pchan->constraints.first; con; con = con->next) {
- /* if constraint has own IPO, convert add these to Object
- * (NOTE: they're most likely to be drivers too)
- */
- if (con->ipo) {
- /* although this was the constraint's local IPO, we still need to provide pchan + con
- * so that drivers can be added properly...
- */
- ipo_to_animdata(bmain, id, con->ipo, pchan->name, con->name, NULL);
- id_us_min(&con->ipo->id);
- con->ipo = NULL;
- }
- }
- }
- }
-
- /* check constraints for local IPO's */
- for (con = ob->constraints.first; con; con = con->next) {
- /* if constraint has own IPO, convert add these to Object
- * (NOTE: they're most likely to be drivers too)
- */
- if (con->ipo) {
- /* Verify if there's AnimData block, just in case */
- BKE_animdata_add_id(id);
-
- /* although this was the constraint's local IPO, we still need to provide con
- * so that drivers can be added properly...
- */
- ipo_to_animdata(bmain, id, con->ipo, NULL, con->name, NULL);
- id_us_min(&con->ipo->id);
- con->ipo = NULL;
- }
-
- /* check for Action Constraint */
- // XXX do we really want to do this here?
- }
-
- /* check constraint channels - we need to remove them anyway... */
- if (ob->constraintChannels.first) {
- /* Verify if there's AnimData block */
- BKE_animdata_add_id(id);
-
- for (conchan = ob->constraintChannels.first; conchan; conchan = conchann) {
- /* get pointer to next Constraint Channel */
- conchann = conchan->next;
-
- /* convert Constraint Channel's IPO data */
- if (conchan->ipo) {
- ipo_to_animdata(bmain, id, conchan->ipo, NULL, conchan->name, NULL);
- id_us_min(&conchan->ipo->id);
- conchan->ipo = NULL;
- }
-
- /* free Constraint Channel */
- BLI_freelinkN(&ob->constraintChannels, conchan);
- }
- }
-
- /* object's action will always be object-rooted */
- {
- AnimData *adt = BKE_animdata_from_id(id);
- if (adt && adt->action)
- adt->action->idroot = ID_OB;
- }
- }
-
- /* shapekeys */
- for (id = bmain->shapekeys.first; id; id = id->next) {
- Key *key = (Key *)id;
-
- if (G.debug & G_DEBUG) printf("\tconverting key %s\n", id->name + 2);
-
- /* we're only interested in the IPO
- * NOTE: for later, it might be good to port these over to Object instead, as many of these
- * are likely to be drivers, but it's hard to trace that from here, so move this to Ob loop?
- */
- if (key->ipo) {
- /* Add AnimData block */
- AnimData *adt = BKE_animdata_add_id(id);
-
- /* Convert Shapekey data... */
- ipo_to_animdata(bmain, id, key->ipo, NULL, NULL, NULL);
-
- if (adt->action)
- adt->action->idroot = key->ipo->blocktype;
-
- id_us_min(&key->ipo->id);
- key->ipo = NULL;
- }
- }
-
- /* materials */
- for (id = bmain->materials.first; id; id = id->next) {
- Material *ma = (Material *)id;
-
- if (G.debug & G_DEBUG) printf("\tconverting material %s\n", id->name + 2);
-
- /* we're only interested in the IPO */
- if (ma->ipo) {
- /* Add AnimData block */
- AnimData *adt = BKE_animdata_add_id(id);
-
- /* Convert Material data... */
- ipo_to_animdata(bmain, id, ma->ipo, NULL, NULL, NULL);
-
- if (adt->action)
- adt->action->idroot = ma->ipo->blocktype;
-
- id_us_min(&ma->ipo->id);
- ma->ipo = NULL;
- }
- }
-
- /* worlds */
- for (id = bmain->worlds.first; id; id = id->next) {
- World *wo = (World *)id;
-
- if (G.debug & G_DEBUG) printf("\tconverting world %s\n", id->name + 2);
-
- /* we're only interested in the IPO */
- if (wo->ipo) {
- /* Add AnimData block */
- AnimData *adt = BKE_animdata_add_id(id);
-
- /* Convert World data... */
- ipo_to_animdata(bmain, id, wo->ipo, NULL, NULL, NULL);
-
- if (adt->action)
- adt->action->idroot = wo->ipo->blocktype;
-
- id_us_min(&wo->ipo->id);
- wo->ipo = NULL;
- }
- }
-
- /* sequence strips */
- for (id = bmain->scenes.first; id; id = id->next) {
- Scene *scene = (Scene *)id;
- Editing *ed = scene->ed;
- if (ed && ed->seqbasep) {
- Sequence *seq;
-
- AnimData *adt = BKE_animdata_add_id(id);
-
- SEQ_BEGIN(ed, seq)
- {
- IpoCurve *icu = (seq->ipo) ? seq->ipo->curve.first : NULL;
- short adrcode = SEQ_FAC1;
-
- if (G.debug & G_DEBUG)
- printf("\tconverting sequence strip %s\n", seq->name + 2);
-
- if (ELEM(NULL, seq->ipo, icu)) {
- seq->flag |= SEQ_USE_EFFECT_DEFAULT_FADE;
- continue;
- }
-
- /* patch adrcode, so that we can map
- * to different DNA variables later
- * (semi-hack (tm) )
- */
- switch (seq->type) {
- case SEQ_TYPE_IMAGE:
- case SEQ_TYPE_META:
- case SEQ_TYPE_SCENE:
- case SEQ_TYPE_MOVIE:
- case SEQ_TYPE_COLOR:
- adrcode = SEQ_FAC_OPACITY;
- break;
- case SEQ_TYPE_SPEED:
- adrcode = SEQ_FAC_SPEED;
- break;
- }
- icu->adrcode = adrcode;
-
- /* convert IPO */
- ipo_to_animdata(bmain, (ID *)scene, seq->ipo, NULL, NULL, seq);
-
- if (adt->action)
- adt->action->idroot = ID_SCE; /* scene-rooted */
-
- id_us_min(&seq->ipo->id);
- seq->ipo = NULL;
- } SEQ_END;
- }
- }
-
-
- /* textures */
- for (id = bmain->textures.first; id; id = id->next) {
- Tex *te = (Tex *)id;
-
- if (G.debug & G_DEBUG) printf("\tconverting texture %s\n", id->name + 2);
-
- /* we're only interested in the IPO */
- if (te->ipo) {
- /* Add AnimData block */
- AnimData *adt = BKE_animdata_add_id(id);
-
- /* Convert Texture data... */
- ipo_to_animdata(bmain, id, te->ipo, NULL, NULL, NULL);
-
- if (adt->action)
- adt->action->idroot = te->ipo->blocktype;
-
- id_us_min(&te->ipo->id);
- te->ipo = NULL;
- }
- }
-
- /* cameras */
- for (id = bmain->cameras.first; id; id = id->next) {
- Camera *ca = (Camera *)id;
-
- if (G.debug & G_DEBUG) printf("\tconverting camera %s\n", id->name + 2);
-
- /* we're only interested in the IPO */
- if (ca->ipo) {
- /* Add AnimData block */
- AnimData *adt = BKE_animdata_add_id(id);
-
- /* Convert Camera data... */
- ipo_to_animdata(bmain, id, ca->ipo, NULL, NULL, NULL);
-
- if (adt->action)
- adt->action->idroot = ca->ipo->blocktype;
-
- id_us_min(&ca->ipo->id);
- ca->ipo = NULL;
- }
- }
-
- /* lights */
- for (id = bmain->lights.first; id; id = id->next) {
- Light *la = (Light *)id;
-
- if (G.debug & G_DEBUG) printf("\tconverting light %s\n", id->name + 2);
-
- /* we're only interested in the IPO */
- if (la->ipo) {
- /* Add AnimData block */
- AnimData *adt = BKE_animdata_add_id(id);
-
- /* Convert Light data... */
- ipo_to_animdata(bmain, id, la->ipo, NULL, NULL, NULL);
-
- if (adt->action)
- adt->action->idroot = la->ipo->blocktype;
-
- id_us_min(&la->ipo->id);
- la->ipo = NULL;
- }
- }
-
- /* curves */
- for (id = bmain->curves.first; id; id = id->next) {
- Curve *cu = (Curve *)id;
-
- if (G.debug & G_DEBUG) printf("\tconverting curve %s\n", id->name + 2);
-
- /* we're only interested in the IPO */
- if (cu->ipo) {
- /* Add AnimData block */
- AnimData *adt = BKE_animdata_add_id(id);
-
- /* Convert Curve data... */
- ipo_to_animdata(bmain, id, cu->ipo, NULL, NULL, NULL);
-
- if (adt->action)
- adt->action->idroot = cu->ipo->blocktype;
-
- id_us_min(&cu->ipo->id);
- cu->ipo = NULL;
- }
- }
-
- /* --------- Unconverted Animation Data ------------------ */
- /* For Animation data which may not be directly connected (i.e. not linked) to any other
- * data, we need to perform a separate pass to make sure that they are converted to standalone
- * Actions which may then be able to be reused. This does mean that we will be going over data that's
- * already been converted, but there are no problems with that.
- *
- * The most common case for this will be Action Constraints, or IPO's with Fake-Users.
- * We collect all drivers that were found into a temporary collection, and free them in one go, as they're
- * impossible to resolve.
- */
-
- /* actions */
- for (id = bmain->actions.first; id; id = id->next) {
- bAction *act = (bAction *)id;
-
- if (G.debug & G_DEBUG) printf("\tconverting action %s\n", id->name + 2);
-
- /* if old action, it will be object-only... */
- if (act->chanbase.first)
- act->idroot = ID_OB;
-
- /* be careful! some of the actions we encounter will be converted ones... */
- action_to_animato(NULL, act, &act->groups, &act->curves, &drivers);
- }
-
- /* ipo's */
- for (id = bmain->ipo.first; id; id = id->next) {
- Ipo *ipo = (Ipo *)id;
-
- if (G.debug & G_DEBUG) printf("\tconverting ipo %s\n", id->name + 2);
-
- /* most likely this IPO has already been processed, so check if any curves left to convert */
- if (ipo->curve.first) {
- bAction *new_act;
+ ListBase drivers = {NULL, NULL};
+ ID *id;
+
+ if (bmain == NULL) {
+ CLOG_ERROR(&LOG, "Argh! Main is NULL");
+ return;
+ }
+
+ /* only convert if version is right */
+ if (bmain->versionfile >= 250) {
+ CLOG_WARN(&LOG, "Animation data too new to convert (Version %d)", bmain->versionfile);
+ return;
+ }
+ else if (G.debug & G_DEBUG)
+ printf("INFO: Converting to Animato...\n");
+
+ /* ----------- Animation Attached to Data -------------- */
+
+ /* objects */
+ for (id = bmain->objects.first; id; id = id->next) {
+ Object *ob = (Object *)id;
+ bPoseChannel *pchan;
+ bConstraint *con;
+ bConstraintChannel *conchan, *conchann;
+
+ if (G.debug & G_DEBUG)
+ printf("\tconverting ob %s\n", id->name + 2);
+
+ /* check if object has any animation data */
+ if (ob->nlastrips.first) {
+ /* Add AnimData block */
+ BKE_animdata_add_id(id);
+
+ /* IPO first to take into any non-NLA'd Object Animation */
+ if (ob->ipo) {
+ ipo_to_animdata(bmain, id, ob->ipo, NULL, NULL, NULL);
+ /* No need to id_us_min ipo ID here, ipo_to_animdata already does it. */
+ ob->ipo = NULL;
+ }
+
+ /* Action is skipped since it'll be used by some strip in the NLA anyway,
+ * causing errors with evaluation in the new evaluation pipeline
+ */
+ if (ob->action) {
+ id_us_min(&ob->action->id);
+ ob->action = NULL;
+ }
+
+ /* finally NLA */
+ nlastrips_to_animdata(id, &ob->nlastrips);
+ }
+ else if ((ob->ipo) || (ob->action)) {
+ /* Add AnimData block */
+ AnimData *adt = BKE_animdata_add_id(id);
+
+ /* Action first - so that Action name get conserved */
+ if (ob->action) {
+ action_to_animdata(id, ob->action);
+
+ /* only decrease usercount if this Action isn't now being used by AnimData */
+ if (ob->action != adt->action) {
+ id_us_min(&ob->action->id);
+ ob->action = NULL;
+ }
+ }
+
+ /* IPO second... */
+ if (ob->ipo) {
+ ipo_to_animdata(bmain, id, ob->ipo, NULL, NULL, NULL);
+ /* No need to id_us_min ipo ID here, ipo_to_animdata already does it. */
+ ob->ipo = NULL;
+ }
+ }
+
+ /* check PoseChannels for constraints with local data */
+ if (ob->pose) {
+ /* Verify if there's AnimData block */
+ BKE_animdata_add_id(id);
+
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ for (con = pchan->constraints.first; con; con = con->next) {
+ /* if constraint has own IPO, convert add these to Object
+ * (NOTE: they're most likely to be drivers too)
+ */
+ if (con->ipo) {
+ /* although this was the constraint's local IPO, we still need to provide pchan + con
+ * so that drivers can be added properly...
+ */
+ ipo_to_animdata(bmain, id, con->ipo, pchan->name, con->name, NULL);
+ id_us_min(&con->ipo->id);
+ con->ipo = NULL;
+ }
+ }
+ }
+ }
+
+ /* check constraints for local IPO's */
+ for (con = ob->constraints.first; con; con = con->next) {
+ /* if constraint has own IPO, convert add these to Object
+ * (NOTE: they're most likely to be drivers too)
+ */
+ if (con->ipo) {
+ /* Verify if there's AnimData block, just in case */
+ BKE_animdata_add_id(id);
+
+ /* although this was the constraint's local IPO, we still need to provide con
+ * so that drivers can be added properly...
+ */
+ ipo_to_animdata(bmain, id, con->ipo, NULL, con->name, NULL);
+ id_us_min(&con->ipo->id);
+ con->ipo = NULL;
+ }
+
+ /* check for Action Constraint */
+ // XXX do we really want to do this here?
+ }
+
+ /* check constraint channels - we need to remove them anyway... */
+ if (ob->constraintChannels.first) {
+ /* Verify if there's AnimData block */
+ BKE_animdata_add_id(id);
+
+ for (conchan = ob->constraintChannels.first; conchan; conchan = conchann) {
+ /* get pointer to next Constraint Channel */
+ conchann = conchan->next;
+
+ /* convert Constraint Channel's IPO data */
+ if (conchan->ipo) {
+ ipo_to_animdata(bmain, id, conchan->ipo, NULL, conchan->name, NULL);
+ id_us_min(&conchan->ipo->id);
+ conchan->ipo = NULL;
+ }
+
+ /* free Constraint Channel */
+ BLI_freelinkN(&ob->constraintChannels, conchan);
+ }
+ }
+
+ /* object's action will always be object-rooted */
+ {
+ AnimData *adt = BKE_animdata_from_id(id);
+ if (adt && adt->action)
+ adt->action->idroot = ID_OB;
+ }
+ }
+
+ /* shapekeys */
+ for (id = bmain->shapekeys.first; id; id = id->next) {
+ Key *key = (Key *)id;
+
+ if (G.debug & G_DEBUG)
+ printf("\tconverting key %s\n", id->name + 2);
+
+ /* we're only interested in the IPO
+ * NOTE: for later, it might be good to port these over to Object instead, as many of these
+ * are likely to be drivers, but it's hard to trace that from here, so move this to Ob loop?
+ */
+ if (key->ipo) {
+ /* Add AnimData block */
+ AnimData *adt = BKE_animdata_add_id(id);
+
+ /* Convert Shapekey data... */
+ ipo_to_animdata(bmain, id, key->ipo, NULL, NULL, NULL);
+
+ if (adt->action)
+ adt->action->idroot = key->ipo->blocktype;
+
+ id_us_min(&key->ipo->id);
+ key->ipo = NULL;
+ }
+ }
+
+ /* materials */
+ for (id = bmain->materials.first; id; id = id->next) {
+ Material *ma = (Material *)id;
+
+ if (G.debug & G_DEBUG)
+ printf("\tconverting material %s\n", id->name + 2);
+
+ /* we're only interested in the IPO */
+ if (ma->ipo) {
+ /* Add AnimData block */
+ AnimData *adt = BKE_animdata_add_id(id);
+
+ /* Convert Material data... */
+ ipo_to_animdata(bmain, id, ma->ipo, NULL, NULL, NULL);
+
+ if (adt->action)
+ adt->action->idroot = ma->ipo->blocktype;
+
+ id_us_min(&ma->ipo->id);
+ ma->ipo = NULL;
+ }
+ }
+
+ /* worlds */
+ for (id = bmain->worlds.first; id; id = id->next) {
+ World *wo = (World *)id;
+
+ if (G.debug & G_DEBUG)
+ printf("\tconverting world %s\n", id->name + 2);
+
+ /* we're only interested in the IPO */
+ if (wo->ipo) {
+ /* Add AnimData block */
+ AnimData *adt = BKE_animdata_add_id(id);
+
+ /* Convert World data... */
+ ipo_to_animdata(bmain, id, wo->ipo, NULL, NULL, NULL);
+
+ if (adt->action)
+ adt->action->idroot = wo->ipo->blocktype;
+
+ id_us_min(&wo->ipo->id);
+ wo->ipo = NULL;
+ }
+ }
+
+ /* sequence strips */
+ for (id = bmain->scenes.first; id; id = id->next) {
+ Scene *scene = (Scene *)id;
+ Editing *ed = scene->ed;
+ if (ed && ed->seqbasep) {
+ Sequence *seq;
+
+ AnimData *adt = BKE_animdata_add_id(id);
+
+ SEQ_BEGIN (ed, seq) {
+ IpoCurve *icu = (seq->ipo) ? seq->ipo->curve.first : NULL;
+ short adrcode = SEQ_FAC1;
+
+ if (G.debug & G_DEBUG)
+ printf("\tconverting sequence strip %s\n", seq->name + 2);
+
+ if (ELEM(NULL, seq->ipo, icu)) {
+ seq->flag |= SEQ_USE_EFFECT_DEFAULT_FADE;
+ continue;
+ }
+
+ /* patch adrcode, so that we can map
+ * to different DNA variables later
+ * (semi-hack (tm) )
+ */
+ switch (seq->type) {
+ case SEQ_TYPE_IMAGE:
+ case SEQ_TYPE_META:
+ case SEQ_TYPE_SCENE:
+ case SEQ_TYPE_MOVIE:
+ case SEQ_TYPE_COLOR:
+ adrcode = SEQ_FAC_OPACITY;
+ break;
+ case SEQ_TYPE_SPEED:
+ adrcode = SEQ_FAC_SPEED;
+ break;
+ }
+ icu->adrcode = adrcode;
+
+ /* convert IPO */
+ ipo_to_animdata(bmain, (ID *)scene, seq->ipo, NULL, NULL, seq);
+
+ if (adt->action)
+ adt->action->idroot = ID_SCE; /* scene-rooted */
+
+ id_us_min(&seq->ipo->id);
+ seq->ipo = NULL;
+ }
+ SEQ_END;
+ }
+ }
+
+ /* textures */
+ for (id = bmain->textures.first; id; id = id->next) {
+ Tex *te = (Tex *)id;
+
+ if (G.debug & G_DEBUG)
+ printf("\tconverting texture %s\n", id->name + 2);
+
+ /* we're only interested in the IPO */
+ if (te->ipo) {
+ /* Add AnimData block */
+ AnimData *adt = BKE_animdata_add_id(id);
+
+ /* Convert Texture data... */
+ ipo_to_animdata(bmain, id, te->ipo, NULL, NULL, NULL);
+
+ if (adt->action)
+ adt->action->idroot = te->ipo->blocktype;
+
+ id_us_min(&te->ipo->id);
+ te->ipo = NULL;
+ }
+ }
+
+ /* cameras */
+ for (id = bmain->cameras.first; id; id = id->next) {
+ Camera *ca = (Camera *)id;
+
+ if (G.debug & G_DEBUG)
+ printf("\tconverting camera %s\n", id->name + 2);
+
+ /* we're only interested in the IPO */
+ if (ca->ipo) {
+ /* Add AnimData block */
+ AnimData *adt = BKE_animdata_add_id(id);
+
+ /* Convert Camera data... */
+ ipo_to_animdata(bmain, id, ca->ipo, NULL, NULL, NULL);
+
+ if (adt->action)
+ adt->action->idroot = ca->ipo->blocktype;
+
+ id_us_min(&ca->ipo->id);
+ ca->ipo = NULL;
+ }
+ }
+
+ /* lights */
+ for (id = bmain->lights.first; id; id = id->next) {
+ Light *la = (Light *)id;
+
+ if (G.debug & G_DEBUG)
+ printf("\tconverting light %s\n", id->name + 2);
+
+ /* we're only interested in the IPO */
+ if (la->ipo) {
+ /* Add AnimData block */
+ AnimData *adt = BKE_animdata_add_id(id);
+
+ /* Convert Light data... */
+ ipo_to_animdata(bmain, id, la->ipo, NULL, NULL, NULL);
+
+ if (adt->action)
+ adt->action->idroot = la->ipo->blocktype;
+
+ id_us_min(&la->ipo->id);
+ la->ipo = NULL;
+ }
+ }
+
+ /* curves */
+ for (id = bmain->curves.first; id; id = id->next) {
+ Curve *cu = (Curve *)id;
+
+ if (G.debug & G_DEBUG)
+ printf("\tconverting curve %s\n", id->name + 2);
+
+ /* we're only interested in the IPO */
+ if (cu->ipo) {
+ /* Add AnimData block */
+ AnimData *adt = BKE_animdata_add_id(id);
+
+ /* Convert Curve data... */
+ ipo_to_animdata(bmain, id, cu->ipo, NULL, NULL, NULL);
+
+ if (adt->action)
+ adt->action->idroot = cu->ipo->blocktype;
- /* add a new action for this, and convert all data into that action */
- new_act = BKE_action_add(bmain, id->name + 2);
- ipo_to_animato(NULL, ipo, NULL, NULL, NULL, NULL, &new_act->curves, &drivers);
- new_act->idroot = ipo->blocktype;
- }
+ id_us_min(&cu->ipo->id);
+ cu->ipo = NULL;
+ }
+ }
+
+ /* --------- Unconverted Animation Data ------------------ */
+ /* For Animation data which may not be directly connected (i.e. not linked) to any other
+ * data, we need to perform a separate pass to make sure that they are converted to standalone
+ * Actions which may then be able to be reused. This does mean that we will be going over data that's
+ * already been converted, but there are no problems with that.
+ *
+ * The most common case for this will be Action Constraints, or IPO's with Fake-Users.
+ * We collect all drivers that were found into a temporary collection, and free them in one go, as they're
+ * impossible to resolve.
+ */
- /* clear fake-users, and set user-count to zero to make sure it is cleared on file-save */
- ipo->id.us = 0;
- ipo->id.flag &= ~LIB_FAKEUSER;
- }
+ /* actions */
+ for (id = bmain->actions.first; id; id = id->next) {
+ bAction *act = (bAction *)id;
- /* free unused drivers from actions + ipos */
- free_fcurves(&drivers);
+ if (G.debug & G_DEBUG)
+ printf("\tconverting action %s\n", id->name + 2);
+
+ /* if old action, it will be object-only... */
+ if (act->chanbase.first)
+ act->idroot = ID_OB;
+
+ /* be careful! some of the actions we encounter will be converted ones... */
+ action_to_animato(NULL, act, &act->groups, &act->curves, &drivers);
+ }
+
+ /* ipo's */
+ for (id = bmain->ipo.first; id; id = id->next) {
+ Ipo *ipo = (Ipo *)id;
+
+ if (G.debug & G_DEBUG)
+ printf("\tconverting ipo %s\n", id->name + 2);
+
+ /* most likely this IPO has already been processed, so check if any curves left to convert */
+ if (ipo->curve.first) {
+ bAction *new_act;
+
+ /* add a new action for this, and convert all data into that action */
+ new_act = BKE_action_add(bmain, id->name + 2);
+ ipo_to_animato(NULL, ipo, NULL, NULL, NULL, NULL, &new_act->curves, &drivers);
+ new_act->idroot = ipo->blocktype;
+ }
- if (G.debug & G_DEBUG)
- printf("INFO: Animato convert done\n");
+ /* clear fake-users, and set user-count to zero to make sure it is cleared on file-save */
+ ipo->id.us = 0;
+ ipo->id.flag &= ~LIB_FAKEUSER;
+ }
+
+ /* free unused drivers from actions + ipos */
+ free_fcurves(&drivers);
+
+ if (G.debug & G_DEBUG)
+ printf("INFO: Animato convert done\n");
}
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index de1c3976b7b..1d1c04e173c 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -21,7 +21,6 @@
* \ingroup bke
*/
-
#include <math.h>
#include <string.h>
#include <stddef.h>
@@ -57,97 +56,96 @@
#include "RNA_access.h"
-#define KEY_MODE_DUMMY 0 /* use where mode isn't checked for */
-#define KEY_MODE_BPOINT 1
-#define KEY_MODE_BEZTRIPLE 2
+#define KEY_MODE_DUMMY 0 /* use where mode isn't checked for */
+#define KEY_MODE_BPOINT 1
+#define KEY_MODE_BEZTRIPLE 2
/* old defines from DNA_ipo_types.h for data-type, stored in DNA - don't modify! */
-#define IPO_FLOAT 4
-#define IPO_BEZTRIPLE 100
-#define IPO_BPOINT 101
+#define IPO_FLOAT 4
+#define IPO_BEZTRIPLE 100
+#define IPO_BPOINT 101
/* Internal use only. */
typedef struct WeightsArrayCache {
- int num_defgroup_weights;
- float **defgroup_weights;
+ int num_defgroup_weights;
+ float **defgroup_weights;
} WeightsArrayCache;
-
/** Free (or release) any data used by this shapekey (does not free the key itself). */
void BKE_key_free(Key *key)
{
- KeyBlock *kb;
+ KeyBlock *kb;
- BKE_animdata_free((ID *)key, false);
+ BKE_animdata_free((ID *)key, false);
- while ((kb = BLI_pophead(&key->block))) {
- if (kb->data)
- MEM_freeN(kb->data);
- MEM_freeN(kb);
- }
+ while ((kb = BLI_pophead(&key->block))) {
+ if (kb->data)
+ MEM_freeN(kb->data);
+ MEM_freeN(kb);
+ }
}
void BKE_key_free_nolib(Key *key)
{
- KeyBlock *kb;
+ KeyBlock *kb;
- while ((kb = BLI_pophead(&key->block))) {
- if (kb->data)
- MEM_freeN(kb->data);
- MEM_freeN(kb);
- }
+ while ((kb = BLI_pophead(&key->block))) {
+ if (kb->data)
+ MEM_freeN(kb->data);
+ MEM_freeN(kb);
+ }
}
-Key *BKE_key_add(Main *bmain, ID *id) /* common function */
+Key *BKE_key_add(Main *bmain, ID *id) /* common function */
{
- Key *key;
- char *el;
+ Key *key;
+ char *el;
- key = BKE_libblock_alloc(bmain, ID_KE, "Key", 0);
+ key = BKE_libblock_alloc(bmain, ID_KE, "Key", 0);
- key->type = KEY_NORMAL;
- key->from = id;
+ key->type = KEY_NORMAL;
+ key->from = id;
- key->uidgen = 1;
+ key->uidgen = 1;
- /* XXX the code here uses some defines which will soon be deprecated... */
- switch (GS(id->name)) {
- case ID_ME:
- el = key->elemstr;
+ /* XXX the code here uses some defines which will soon be deprecated... */
+ switch (GS(id->name)) {
+ case ID_ME:
+ el = key->elemstr;
- el[0] = KEYELEM_FLOAT_LEN_COORD;
- el[1] = IPO_FLOAT;
- el[2] = 0;
+ el[0] = KEYELEM_FLOAT_LEN_COORD;
+ el[1] = IPO_FLOAT;
+ el[2] = 0;
- key->elemsize = sizeof(float[KEYELEM_FLOAT_LEN_COORD]);
+ key->elemsize = sizeof(float[KEYELEM_FLOAT_LEN_COORD]);
- break;
- case ID_LT:
- el = key->elemstr;
+ break;
+ case ID_LT:
+ el = key->elemstr;
- el[0] = KEYELEM_FLOAT_LEN_COORD;
- el[1] = IPO_FLOAT;
- el[2] = 0;
+ el[0] = KEYELEM_FLOAT_LEN_COORD;
+ el[1] = IPO_FLOAT;
+ el[2] = 0;
- key->elemsize = sizeof(float[KEYELEM_FLOAT_LEN_COORD]);
+ key->elemsize = sizeof(float[KEYELEM_FLOAT_LEN_COORD]);
- break;
- case ID_CU:
- el = key->elemstr;
+ break;
+ case ID_CU:
+ el = key->elemstr;
- el[0] = KEYELEM_ELEM_SIZE_CURVE;
- el[1] = IPO_BPOINT;
- el[2] = 0;
+ el[0] = KEYELEM_ELEM_SIZE_CURVE;
+ el[1] = IPO_BPOINT;
+ el[2] = 0;
- key->elemsize = sizeof(float[KEYELEM_ELEM_SIZE_CURVE]);
+ key->elemsize = sizeof(float[KEYELEM_ELEM_SIZE_CURVE]);
- break;
+ break;
- default:
- break;
- }
+ default:
+ break;
+ }
- return key;
+ return key;
}
/**
@@ -158,55 +156,58 @@ Key *BKE_key_add(Main *bmain, ID *id) /* common function */
*
* \param flag: Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
*/
-void BKE_key_copy_data(Main *UNUSED(bmain), Key *key_dst, const Key *key_src, const int UNUSED(flag))
+void BKE_key_copy_data(Main *UNUSED(bmain),
+ Key *key_dst,
+ const Key *key_src,
+ const int UNUSED(flag))
{
- BLI_duplicatelist(&key_dst->block, &key_src->block);
-
- KeyBlock *kb_dst, *kb_src;
- for (kb_src = key_src->block.first, kb_dst = key_dst->block.first;
- kb_dst;
- kb_src = kb_src->next, kb_dst = kb_dst->next)
- {
- if (kb_dst->data) {
- kb_dst->data = MEM_dupallocN(kb_dst->data);
- }
- if (kb_src == key_src->refkey) {
- key_dst->refkey = kb_dst;
- }
- }
+ BLI_duplicatelist(&key_dst->block, &key_src->block);
+
+ KeyBlock *kb_dst, *kb_src;
+ for (kb_src = key_src->block.first, kb_dst = key_dst->block.first; kb_dst;
+ kb_src = kb_src->next, kb_dst = kb_dst->next) {
+ if (kb_dst->data) {
+ kb_dst->data = MEM_dupallocN(kb_dst->data);
+ }
+ if (kb_src == key_src->refkey) {
+ key_dst->refkey = kb_dst;
+ }
+ }
}
Key *BKE_key_copy(Main *bmain, const Key *key)
{
- Key *key_copy;
- BKE_id_copy(bmain, &key->id, (ID **)&key_copy);
- return key_copy;
+ Key *key_copy;
+ BKE_id_copy(bmain, &key->id, (ID **)&key_copy);
+ return key_copy;
}
/* XXX TODO get rid of this! */
Key *BKE_key_copy_nolib(Key *key)
{
- Key *keyn;
- KeyBlock *kbn, *kb;
+ Key *keyn;
+ KeyBlock *kbn, *kb;
- keyn = MEM_dupallocN(key);
+ keyn = MEM_dupallocN(key);
- keyn->adt = NULL;
+ keyn->adt = NULL;
- BLI_duplicatelist(&keyn->block, &key->block);
+ BLI_duplicatelist(&keyn->block, &key->block);
- kb = key->block.first;
- kbn = keyn->block.first;
- while (kbn) {
+ kb = key->block.first;
+ kbn = keyn->block.first;
+ while (kbn) {
- if (kbn->data) kbn->data = MEM_dupallocN(kbn->data);
- if (kb == key->refkey) keyn->refkey = kbn;
+ if (kbn->data)
+ kbn->data = MEM_dupallocN(kbn->data);
+ if (kb == key->refkey)
+ keyn->refkey = kbn;
- kbn = kbn->next;
- kb = kb->next;
- }
+ kbn = kbn->next;
+ kb = kb->next;
+ }
- return keyn;
+ return keyn;
}
/* Sort shape keys and Ipo curves after a change. This assumes that at most
@@ -216,1264 +217,1361 @@ Key *BKE_key_copy_nolib(Key *key)
void BKE_key_sort(Key *key)
{
- KeyBlock *kb;
- KeyBlock *kb2;
-
- /* locate the key which is out of position */
- for (kb = key->block.first; kb; kb = kb->next)
- if ((kb->next) && (kb->pos > kb->next->pos))
- break;
-
- /* if we find a key, move it */
- if (kb) {
- kb = kb->next; /* next key is the out-of-order one */
- BLI_remlink(&key->block, kb);
-
- /* find the right location and insert before */
- for (kb2 = key->block.first; kb2; kb2 = kb2->next) {
- if (kb2->pos > kb->pos) {
- BLI_insertlinkafter(&key->block, kb2->prev, kb);
- break;
- }
- }
- }
-
- /* new rule; first key is refkey, this to match drawing channels... */
- key->refkey = key->block.first;
+ KeyBlock *kb;
+ KeyBlock *kb2;
+
+ /* locate the key which is out of position */
+ for (kb = key->block.first; kb; kb = kb->next)
+ if ((kb->next) && (kb->pos > kb->next->pos))
+ break;
+
+ /* if we find a key, move it */
+ if (kb) {
+ kb = kb->next; /* next key is the out-of-order one */
+ BLI_remlink(&key->block, kb);
+
+ /* find the right location and insert before */
+ for (kb2 = key->block.first; kb2; kb2 = kb2->next) {
+ if (kb2->pos > kb->pos) {
+ BLI_insertlinkafter(&key->block, kb2->prev, kb);
+ break;
+ }
+ }
+ }
+
+ /* new rule; first key is refkey, this to match drawing channels... */
+ key->refkey = key->block.first;
}
/**************** do the key ****************/
void key_curve_position_weights(float t, float data[4], int type)
{
- float t2, t3, fc;
-
- if (type == KEY_LINEAR) {
- data[0] = 0.0f;
- data[1] = -t + 1.0f;
- data[2] = t;
- data[3] = 0.0f;
- }
- else if (type == KEY_CARDINAL) {
- t2 = t * t;
- t3 = t2 * t;
- fc = 0.71f;
-
- data[0] = -fc * t3 + 2.0f * fc * t2 - fc * t;
- data[1] = (2.0f - fc) * t3 + (fc - 3.0f) * t2 + 1.0f;
- data[2] = (fc - 2.0f) * t3 + (3.0f - 2.0f * fc) * t2 + fc * t;
- data[3] = fc * t3 - fc * t2;
- }
- else if (type == KEY_BSPLINE) {
- t2 = t * t;
- t3 = t2 * t;
-
- data[0] = -0.16666666f * t3 + 0.5f * t2 - 0.5f * t + 0.16666666f;
- data[1] = 0.5f * t3 - t2 + 0.66666666f;
- data[2] = -0.5f * t3 + 0.5f * t2 + 0.5f * t + 0.16666666f;
- data[3] = 0.16666666f * t3;
- }
- else if (type == KEY_CATMULL_ROM) {
- t2 = t * t;
- t3 = t2 * t;
- fc = 0.5f;
-
- data[0] = -fc * t3 + 2.0f * fc * t2 - fc * t;
- data[1] = (2.0f - fc) * t3 + (fc - 3.0f) * t2 + 1.0f;
- data[2] = (fc - 2.0f) * t3 + (3.0f - 2.0f * fc) * t2 + fc * t;
- data[3] = fc * t3 - fc * t2;
- }
+ float t2, t3, fc;
+
+ if (type == KEY_LINEAR) {
+ data[0] = 0.0f;
+ data[1] = -t + 1.0f;
+ data[2] = t;
+ data[3] = 0.0f;
+ }
+ else if (type == KEY_CARDINAL) {
+ t2 = t * t;
+ t3 = t2 * t;
+ fc = 0.71f;
+
+ data[0] = -fc * t3 + 2.0f * fc * t2 - fc * t;
+ data[1] = (2.0f - fc) * t3 + (fc - 3.0f) * t2 + 1.0f;
+ data[2] = (fc - 2.0f) * t3 + (3.0f - 2.0f * fc) * t2 + fc * t;
+ data[3] = fc * t3 - fc * t2;
+ }
+ else if (type == KEY_BSPLINE) {
+ t2 = t * t;
+ t3 = t2 * t;
+
+ data[0] = -0.16666666f * t3 + 0.5f * t2 - 0.5f * t + 0.16666666f;
+ data[1] = 0.5f * t3 - t2 + 0.66666666f;
+ data[2] = -0.5f * t3 + 0.5f * t2 + 0.5f * t + 0.16666666f;
+ data[3] = 0.16666666f * t3;
+ }
+ else if (type == KEY_CATMULL_ROM) {
+ t2 = t * t;
+ t3 = t2 * t;
+ fc = 0.5f;
+
+ data[0] = -fc * t3 + 2.0f * fc * t2 - fc * t;
+ data[1] = (2.0f - fc) * t3 + (fc - 3.0f) * t2 + 1.0f;
+ data[2] = (fc - 2.0f) * t3 + (3.0f - 2.0f * fc) * t2 + fc * t;
+ data[3] = fc * t3 - fc * t2;
+ }
}
/* first derivative */
void key_curve_tangent_weights(float t, float data[4], int type)
{
- float t2, fc;
-
- if (type == KEY_LINEAR) {
- data[0] = 0.0f;
- data[1] = -1.0f;
- data[2] = 1.0f;
- data[3] = 0.0f;
- }
- else if (type == KEY_CARDINAL) {
- t2 = t * t;
- fc = 0.71f;
-
- data[0] = -3.0f * fc * t2 + 4.0f * fc * t - fc;
- data[1] = 3.0f * (2.0f - fc) * t2 + 2.0f * (fc - 3.0f) * t;
- data[2] = 3.0f * (fc - 2.0f) * t2 + 2.0f * (3.0f - 2.0f * fc) * t + fc;
- data[3] = 3.0f * fc * t2 - 2.0f * fc * t;
- }
- else if (type == KEY_BSPLINE) {
- t2 = t * t;
-
- data[0] = -0.5f * t2 + t - 0.5f;
- data[1] = 1.5f * t2 - t * 2.0f;
- data[2] = -1.5f * t2 + t + 0.5f;
- data[3] = 0.5f * t2;
- }
- else if (type == KEY_CATMULL_ROM) {
- t2 = t * t;
- fc = 0.5f;
-
- data[0] = -3.0f * fc * t2 + 4.0f * fc * t - fc;
- data[1] = 3.0f * (2.0f - fc) * t2 + 2.0f * (fc - 3.0f) * t;
- data[2] = 3.0f * (fc - 2.0f) * t2 + 2.0f * (3.0f - 2.0f * fc) * t + fc;
- data[3] = 3.0f * fc * t2 - 2.0f * fc * t;
- }
+ float t2, fc;
+
+ if (type == KEY_LINEAR) {
+ data[0] = 0.0f;
+ data[1] = -1.0f;
+ data[2] = 1.0f;
+ data[3] = 0.0f;
+ }
+ else if (type == KEY_CARDINAL) {
+ t2 = t * t;
+ fc = 0.71f;
+
+ data[0] = -3.0f * fc * t2 + 4.0f * fc * t - fc;
+ data[1] = 3.0f * (2.0f - fc) * t2 + 2.0f * (fc - 3.0f) * t;
+ data[2] = 3.0f * (fc - 2.0f) * t2 + 2.0f * (3.0f - 2.0f * fc) * t + fc;
+ data[3] = 3.0f * fc * t2 - 2.0f * fc * t;
+ }
+ else if (type == KEY_BSPLINE) {
+ t2 = t * t;
+
+ data[0] = -0.5f * t2 + t - 0.5f;
+ data[1] = 1.5f * t2 - t * 2.0f;
+ data[2] = -1.5f * t2 + t + 0.5f;
+ data[3] = 0.5f * t2;
+ }
+ else if (type == KEY_CATMULL_ROM) {
+ t2 = t * t;
+ fc = 0.5f;
+
+ data[0] = -3.0f * fc * t2 + 4.0f * fc * t - fc;
+ data[1] = 3.0f * (2.0f - fc) * t2 + 2.0f * (fc - 3.0f) * t;
+ data[2] = 3.0f * (fc - 2.0f) * t2 + 2.0f * (3.0f - 2.0f * fc) * t + fc;
+ data[3] = 3.0f * fc * t2 - 2.0f * fc * t;
+ }
}
/* second derivative */
void key_curve_normal_weights(float t, float data[4], int type)
{
- float fc;
-
- if (type == KEY_LINEAR) {
- data[0] = 0.0f;
- data[1] = 0.0f;
- data[2] = 0.0f;
- data[3] = 0.0f;
- }
- else if (type == KEY_CARDINAL) {
- fc = 0.71f;
-
- data[0] = -6.0f * fc * t + 4.0f * fc;
- data[1] = 6.0f * (2.0f - fc) * t + 2.0f * (fc - 3.0f);
- data[2] = 6.0f * (fc - 2.0f) * t + 2.0f * (3.0f - 2.0f * fc);
- data[3] = 6.0f * fc * t - 2.0f * fc;
- }
- else if (type == KEY_BSPLINE) {
- data[0] = -1.0f * t + 1.0f;
- data[1] = 3.0f * t - 2.0f;
- data[2] = -3.0f * t + 1.0f;
- data[3] = 1.0f * t;
- }
- else if (type == KEY_CATMULL_ROM) {
- fc = 0.5f;
-
- data[0] = -6.0f * fc * t + 4.0f * fc;
- data[1] = 6.0f * (2.0f - fc) * t + 2.0f * (fc - 3.0f);
- data[2] = 6.0f * (fc - 2.0f) * t + 2.0f * (3.0f - 2.0f * fc);
- data[3] = 6.0f * fc * t - 2.0f * fc;
- }
+ float fc;
+
+ if (type == KEY_LINEAR) {
+ data[0] = 0.0f;
+ data[1] = 0.0f;
+ data[2] = 0.0f;
+ data[3] = 0.0f;
+ }
+ else if (type == KEY_CARDINAL) {
+ fc = 0.71f;
+
+ data[0] = -6.0f * fc * t + 4.0f * fc;
+ data[1] = 6.0f * (2.0f - fc) * t + 2.0f * (fc - 3.0f);
+ data[2] = 6.0f * (fc - 2.0f) * t + 2.0f * (3.0f - 2.0f * fc);
+ data[3] = 6.0f * fc * t - 2.0f * fc;
+ }
+ else if (type == KEY_BSPLINE) {
+ data[0] = -1.0f * t + 1.0f;
+ data[1] = 3.0f * t - 2.0f;
+ data[2] = -3.0f * t + 1.0f;
+ data[3] = 1.0f * t;
+ }
+ else if (type == KEY_CATMULL_ROM) {
+ fc = 0.5f;
+
+ data[0] = -6.0f * fc * t + 4.0f * fc;
+ data[1] = 6.0f * (2.0f - fc) * t + 2.0f * (fc - 3.0f);
+ data[2] = 6.0f * (fc - 2.0f) * t + 2.0f * (3.0f - 2.0f * fc);
+ data[3] = 6.0f * fc * t - 2.0f * fc;
+ }
}
static int setkeys(float fac, ListBase *lb, KeyBlock *k[], float t[4], int cycl)
{
- /* return 1 means k[2] is the position, return 0 means interpolate */
- KeyBlock *k1, *firstkey;
- float d, dpos, ofs = 0, lastpos;
- short bsplinetype;
-
- firstkey = lb->first;
- k1 = lb->last;
- lastpos = k1->pos;
- dpos = lastpos - firstkey->pos;
-
- if (fac < firstkey->pos) fac = firstkey->pos;
- else if (fac > k1->pos) fac = k1->pos;
-
- k1 = k[0] = k[1] = k[2] = k[3] = firstkey;
- t[0] = t[1] = t[2] = t[3] = k1->pos;
-
- /* if (fac < 0.0 || fac > 1.0) return 1; */
-
- if (k1->next == NULL) return 1;
-
- if (cycl) { /* pre-sort */
- k[2] = k1->next;
- k[3] = k[2]->next;
- if (k[3] == NULL) k[3] = k1;
- while (k1) {
- if (k1->next == NULL) k[0] = k1;
- k1 = k1->next;
- }
- /* k1 = k[1]; */ /* UNUSED */
- t[0] = k[0]->pos;
- t[1] += dpos;
- t[2] = k[2]->pos + dpos;
- t[3] = k[3]->pos + dpos;
- fac += dpos;
- ofs = dpos;
- if (k[3] == k[1]) {
- t[3] += dpos;
- ofs = 2.0f * dpos;
- }
- if (fac < t[1]) fac += dpos;
- k1 = k[3];
- }
- else { /* pre-sort */
- k[2] = k1->next;
- t[2] = k[2]->pos;
- k[3] = k[2]->next;
- if (k[3] == NULL) k[3] = k[2];
- t[3] = k[3]->pos;
- k1 = k[3];
- }
-
- while (t[2] < fac) { /* find correct location */
- if (k1->next == NULL) {
- if (cycl) {
- k1 = firstkey;
- ofs += dpos;
- }
- else if (t[2] == t[3]) {
- break;
- }
- }
- else {
- k1 = k1->next;
- }
-
- t[0] = t[1];
- k[0] = k[1];
- t[1] = t[2];
- k[1] = k[2];
- t[2] = t[3];
- k[2] = k[3];
- t[3] = k1->pos + ofs;
- k[3] = k1;
-
- if (ofs > 2.1f + lastpos) break;
- }
-
- bsplinetype = 0;
- if (k[1]->type == KEY_BSPLINE || k[2]->type == KEY_BSPLINE) bsplinetype = 1;
-
-
- if (cycl == 0) {
- if (bsplinetype == 0) { /* B spline doesn't go through the control points */
- if (fac <= t[1]) { /* fac for 1st key */
- t[2] = t[1];
- k[2] = k[1];
- return 1;
- }
- if (fac >= t[2]) { /* fac after 2nd key */
- return 1;
- }
- }
- else if (fac > t[2]) { /* last key */
- fac = t[2];
- k[3] = k[2];
- t[3] = t[2];
- }
- }
-
- d = t[2] - t[1];
- if (d == 0.0f) {
- if (bsplinetype == 0) {
- return 1; /* both keys equal */
- }
- }
- else {
- d = (fac - t[1]) / d;
- }
-
- /* interpolation */
- key_curve_position_weights(d, t, k[1]->type);
-
- if (k[1]->type != k[2]->type) {
- float t_other[4];
- key_curve_position_weights(d, t_other, k[2]->type);
- interp_v4_v4v4(t, t, t_other, d);
- }
-
- return 0;
-
+ /* return 1 means k[2] is the position, return 0 means interpolate */
+ KeyBlock *k1, *firstkey;
+ float d, dpos, ofs = 0, lastpos;
+ short bsplinetype;
+
+ firstkey = lb->first;
+ k1 = lb->last;
+ lastpos = k1->pos;
+ dpos = lastpos - firstkey->pos;
+
+ if (fac < firstkey->pos)
+ fac = firstkey->pos;
+ else if (fac > k1->pos)
+ fac = k1->pos;
+
+ k1 = k[0] = k[1] = k[2] = k[3] = firstkey;
+ t[0] = t[1] = t[2] = t[3] = k1->pos;
+
+ /* if (fac < 0.0 || fac > 1.0) return 1; */
+
+ if (k1->next == NULL)
+ return 1;
+
+ if (cycl) { /* pre-sort */
+ k[2] = k1->next;
+ k[3] = k[2]->next;
+ if (k[3] == NULL)
+ k[3] = k1;
+ while (k1) {
+ if (k1->next == NULL)
+ k[0] = k1;
+ k1 = k1->next;
+ }
+ /* k1 = k[1]; */ /* UNUSED */
+ t[0] = k[0]->pos;
+ t[1] += dpos;
+ t[2] = k[2]->pos + dpos;
+ t[3] = k[3]->pos + dpos;
+ fac += dpos;
+ ofs = dpos;
+ if (k[3] == k[1]) {
+ t[3] += dpos;
+ ofs = 2.0f * dpos;
+ }
+ if (fac < t[1])
+ fac += dpos;
+ k1 = k[3];
+ }
+ else { /* pre-sort */
+ k[2] = k1->next;
+ t[2] = k[2]->pos;
+ k[3] = k[2]->next;
+ if (k[3] == NULL)
+ k[3] = k[2];
+ t[3] = k[3]->pos;
+ k1 = k[3];
+ }
+
+ while (t[2] < fac) { /* find correct location */
+ if (k1->next == NULL) {
+ if (cycl) {
+ k1 = firstkey;
+ ofs += dpos;
+ }
+ else if (t[2] == t[3]) {
+ break;
+ }
+ }
+ else {
+ k1 = k1->next;
+ }
+
+ t[0] = t[1];
+ k[0] = k[1];
+ t[1] = t[2];
+ k[1] = k[2];
+ t[2] = t[3];
+ k[2] = k[3];
+ t[3] = k1->pos + ofs;
+ k[3] = k1;
+
+ if (ofs > 2.1f + lastpos)
+ break;
+ }
+
+ bsplinetype = 0;
+ if (k[1]->type == KEY_BSPLINE || k[2]->type == KEY_BSPLINE)
+ bsplinetype = 1;
+
+ if (cycl == 0) {
+ if (bsplinetype == 0) { /* B spline doesn't go through the control points */
+ if (fac <= t[1]) { /* fac for 1st key */
+ t[2] = t[1];
+ k[2] = k[1];
+ return 1;
+ }
+ if (fac >= t[2]) { /* fac after 2nd key */
+ return 1;
+ }
+ }
+ else if (fac > t[2]) { /* last key */
+ fac = t[2];
+ k[3] = k[2];
+ t[3] = t[2];
+ }
+ }
+
+ d = t[2] - t[1];
+ if (d == 0.0f) {
+ if (bsplinetype == 0) {
+ return 1; /* both keys equal */
+ }
+ }
+ else {
+ d = (fac - t[1]) / d;
+ }
+
+ /* interpolation */
+ key_curve_position_weights(d, t, k[1]->type);
+
+ if (k[1]->type != k[2]->type) {
+ float t_other[4];
+ key_curve_position_weights(d, t_other, k[2]->type);
+ interp_v4_v4v4(t, t, t_other, d);
+ }
+
+ return 0;
}
static void flerp(int tot, float *in, float *f0, float *f1, float *f2, float *f3, float *t)
{
- int a;
+ int a;
- for (a = 0; a < tot; a++) {
- in[a] = t[0] * f0[a] + t[1] * f1[a] + t[2] * f2[a] + t[3] * f3[a];
- }
+ for (a = 0; a < tot; a++) {
+ in[a] = t[0] * f0[a] + t[1] * f1[a] + t[2] * f2[a] + t[3] * f3[a];
+ }
}
static void rel_flerp(int tot, float *in, float *ref, float *out, float fac)
{
- int a;
+ int a;
- for (a = 0; a < tot; a++) {
- in[a] -= fac * (ref[a] - out[a]);
- }
+ for (a = 0; a < tot; a++) {
+ in[a] -= fac * (ref[a] - out[a]);
+ }
}
static char *key_block_get_data(Key *key, KeyBlock *actkb, KeyBlock *kb, char **freedata)
{
- if (kb == actkb) {
- /* this hack makes it possible to edit shape keys in
- * edit mode with shape keys blending applied */
- if (GS(key->from->name) == ID_ME) {
- Mesh *me;
- BMVert *eve;
- BMIter iter;
- float (*co)[3];
- int a;
-
- me = (Mesh *)key->from;
-
- if (me->edit_mesh && me->edit_mesh->bm->totvert == kb->totelem) {
- a = 0;
- co = MEM_mallocN(sizeof(float) * 3 * me->edit_mesh->bm->totvert, "key_block_get_data");
-
- BM_ITER_MESH (eve, &iter, me->edit_mesh->bm, BM_VERTS_OF_MESH) {
- copy_v3_v3(co[a], eve->co);
- a++;
- }
-
- *freedata = (char *)co;
- return (char *)co;
- }
- }
- }
-
- *freedata = NULL;
- return kb->data;
+ if (kb == actkb) {
+ /* this hack makes it possible to edit shape keys in
+ * edit mode with shape keys blending applied */
+ if (GS(key->from->name) == ID_ME) {
+ Mesh *me;
+ BMVert *eve;
+ BMIter iter;
+ float(*co)[3];
+ int a;
+
+ me = (Mesh *)key->from;
+
+ if (me->edit_mesh && me->edit_mesh->bm->totvert == kb->totelem) {
+ a = 0;
+ co = MEM_mallocN(sizeof(float) * 3 * me->edit_mesh->bm->totvert, "key_block_get_data");
+
+ BM_ITER_MESH (eve, &iter, me->edit_mesh->bm, BM_VERTS_OF_MESH) {
+ copy_v3_v3(co[a], eve->co);
+ a++;
+ }
+
+ *freedata = (char *)co;
+ return (char *)co;
+ }
+ }
+ }
+
+ *freedata = NULL;
+ return kb->data;
}
-
/* currently only the first value of 'ofs' may be set. */
static bool key_pointer_size(const Key *key, const int mode, int *poinsize, int *ofs, int *step)
{
- if (key->from == NULL) {
- return false;
- }
-
- *step = 1;
-
- switch (GS(key->from->name)) {
- case ID_ME:
- *ofs = sizeof(float[KEYELEM_FLOAT_LEN_COORD]);
- *poinsize = *ofs;
- break;
- case ID_LT:
- *ofs = sizeof(float[KEYELEM_FLOAT_LEN_COORD]);
- *poinsize = *ofs;
- break;
- case ID_CU:
- if (mode == KEY_MODE_BPOINT) {
- *ofs = sizeof(float[KEYELEM_FLOAT_LEN_BPOINT]);
- *step = KEYELEM_ELEM_LEN_BPOINT;
- }
- else {
- *ofs = sizeof(float[KEYELEM_FLOAT_LEN_BEZTRIPLE]);
- *step = KEYELEM_ELEM_LEN_BEZTRIPLE;
- }
- *poinsize = sizeof(float[KEYELEM_ELEM_SIZE_CURVE]);
- break;
- default:
- BLI_assert(!"invalid 'key->from' ID type");
- return false;
- }
-
- return true;
+ if (key->from == NULL) {
+ return false;
+ }
+
+ *step = 1;
+
+ switch (GS(key->from->name)) {
+ case ID_ME:
+ *ofs = sizeof(float[KEYELEM_FLOAT_LEN_COORD]);
+ *poinsize = *ofs;
+ break;
+ case ID_LT:
+ *ofs = sizeof(float[KEYELEM_FLOAT_LEN_COORD]);
+ *poinsize = *ofs;
+ break;
+ case ID_CU:
+ if (mode == KEY_MODE_BPOINT) {
+ *ofs = sizeof(float[KEYELEM_FLOAT_LEN_BPOINT]);
+ *step = KEYELEM_ELEM_LEN_BPOINT;
+ }
+ else {
+ *ofs = sizeof(float[KEYELEM_FLOAT_LEN_BEZTRIPLE]);
+ *step = KEYELEM_ELEM_LEN_BEZTRIPLE;
+ }
+ *poinsize = sizeof(float[KEYELEM_ELEM_SIZE_CURVE]);
+ break;
+ default:
+ BLI_assert(!"invalid 'key->from' ID type");
+ return false;
+ }
+
+ return true;
}
-static void cp_key(const int start, int end, const int tot, char *poin, Key *key, KeyBlock *actkb, KeyBlock *kb, float *weights, const int mode)
+static void cp_key(const int start,
+ int end,
+ const int tot,
+ char *poin,
+ Key *key,
+ KeyBlock *actkb,
+ KeyBlock *kb,
+ float *weights,
+ const int mode)
{
- float ktot = 0.0, kd = 0.0;
- int elemsize, poinsize = 0, a, step, *ofsp, ofs[32], flagflo = 0;
- char *k1, *kref, *freek1, *freekref;
- char *cp, elemstr[8];
-
- /* currently always 0, in future key_pointer_size may assign */
- ofs[1] = 0;
-
- if (!key_pointer_size(key, mode, &poinsize, &ofs[0], &step))
- return;
-
- if (end > tot) end = tot;
-
- if (tot != kb->totelem) {
- ktot = 0.0;
- flagflo = 1;
- if (kb->totelem) {
- kd = kb->totelem / (float)tot;
- }
- else {
- return;
- }
- }
-
- k1 = key_block_get_data(key, actkb, kb, &freek1);
- kref = key_block_get_data(key, actkb, key->refkey, &freekref);
-
- /* this exception is needed curves with multiple splines */
- if (start != 0) {
-
- poin += poinsize * start;
-
- if (flagflo) {
- ktot += start * kd;
- a = (int)floor(ktot);
- if (a) {
- ktot -= a;
- k1 += a * key->elemsize;
- }
- }
- else {
- k1 += start * key->elemsize;
- }
- }
-
- if (mode == KEY_MODE_BEZTRIPLE) {
- elemstr[0] = 1;
- elemstr[1] = IPO_BEZTRIPLE;
- elemstr[2] = 0;
- }
-
- /* just do it here, not above! */
- elemsize = key->elemsize * step;
-
- for (a = start; a < end; a += step) {
- cp = key->elemstr;
- if (mode == KEY_MODE_BEZTRIPLE) cp = elemstr;
-
- ofsp = ofs;
-
- while (cp[0]) {
-
- switch (cp[1]) {
- case IPO_FLOAT:
- if (weights) {
- memcpy(poin, kref, sizeof(float[KEYELEM_FLOAT_LEN_COORD]));
- if (*weights != 0.0f)
- rel_flerp(KEYELEM_FLOAT_LEN_COORD, (float *)poin, (float *)kref, (float *)k1, *weights);
- weights++;
- }
- else {
- memcpy(poin, k1, sizeof(float[KEYELEM_FLOAT_LEN_COORD]));
- }
- break;
- case IPO_BPOINT:
- memcpy(poin, k1, sizeof(float[KEYELEM_FLOAT_LEN_BPOINT]));
- break;
- case IPO_BEZTRIPLE:
- memcpy(poin, k1, sizeof(float[KEYELEM_FLOAT_LEN_BEZTRIPLE]));
- break;
- default:
- /* should never happen */
- if (freek1) MEM_freeN(freek1);
- if (freekref) MEM_freeN(freekref);
- BLI_assert(!"invalid 'cp[1]'");
- return;
- }
-
- poin += *ofsp;
- cp += 2; ofsp++;
- }
-
- /* are we going to be nasty? */
- if (flagflo) {
- ktot += kd;
- while (ktot >= 1.0f) {
- ktot -= 1.0f;
- k1 += elemsize;
- kref += elemsize;
- }
- }
- else {
- k1 += elemsize;
- kref += elemsize;
- }
- }
-
- if (freek1) MEM_freeN(freek1);
- if (freekref) MEM_freeN(freekref);
+ float ktot = 0.0, kd = 0.0;
+ int elemsize, poinsize = 0, a, step, *ofsp, ofs[32], flagflo = 0;
+ char *k1, *kref, *freek1, *freekref;
+ char *cp, elemstr[8];
+
+ /* currently always 0, in future key_pointer_size may assign */
+ ofs[1] = 0;
+
+ if (!key_pointer_size(key, mode, &poinsize, &ofs[0], &step))
+ return;
+
+ if (end > tot)
+ end = tot;
+
+ if (tot != kb->totelem) {
+ ktot = 0.0;
+ flagflo = 1;
+ if (kb->totelem) {
+ kd = kb->totelem / (float)tot;
+ }
+ else {
+ return;
+ }
+ }
+
+ k1 = key_block_get_data(key, actkb, kb, &freek1);
+ kref = key_block_get_data(key, actkb, key->refkey, &freekref);
+
+ /* this exception is needed curves with multiple splines */
+ if (start != 0) {
+
+ poin += poinsize * start;
+
+ if (flagflo) {
+ ktot += start * kd;
+ a = (int)floor(ktot);
+ if (a) {
+ ktot -= a;
+ k1 += a * key->elemsize;
+ }
+ }
+ else {
+ k1 += start * key->elemsize;
+ }
+ }
+
+ if (mode == KEY_MODE_BEZTRIPLE) {
+ elemstr[0] = 1;
+ elemstr[1] = IPO_BEZTRIPLE;
+ elemstr[2] = 0;
+ }
+
+ /* just do it here, not above! */
+ elemsize = key->elemsize * step;
+
+ for (a = start; a < end; a += step) {
+ cp = key->elemstr;
+ if (mode == KEY_MODE_BEZTRIPLE)
+ cp = elemstr;
+
+ ofsp = ofs;
+
+ while (cp[0]) {
+
+ switch (cp[1]) {
+ case IPO_FLOAT:
+ if (weights) {
+ memcpy(poin, kref, sizeof(float[KEYELEM_FLOAT_LEN_COORD]));
+ if (*weights != 0.0f)
+ rel_flerp(
+ KEYELEM_FLOAT_LEN_COORD, (float *)poin, (float *)kref, (float *)k1, *weights);
+ weights++;
+ }
+ else {
+ memcpy(poin, k1, sizeof(float[KEYELEM_FLOAT_LEN_COORD]));
+ }
+ break;
+ case IPO_BPOINT:
+ memcpy(poin, k1, sizeof(float[KEYELEM_FLOAT_LEN_BPOINT]));
+ break;
+ case IPO_BEZTRIPLE:
+ memcpy(poin, k1, sizeof(float[KEYELEM_FLOAT_LEN_BEZTRIPLE]));
+ break;
+ default:
+ /* should never happen */
+ if (freek1)
+ MEM_freeN(freek1);
+ if (freekref)
+ MEM_freeN(freekref);
+ BLI_assert(!"invalid 'cp[1]'");
+ return;
+ }
+
+ poin += *ofsp;
+ cp += 2;
+ ofsp++;
+ }
+
+ /* are we going to be nasty? */
+ if (flagflo) {
+ ktot += kd;
+ while (ktot >= 1.0f) {
+ ktot -= 1.0f;
+ k1 += elemsize;
+ kref += elemsize;
+ }
+ }
+ else {
+ k1 += elemsize;
+ kref += elemsize;
+ }
+ }
+
+ if (freek1)
+ MEM_freeN(freek1);
+ if (freekref)
+ MEM_freeN(freekref);
}
-static void cp_cu_key(Curve *cu, Key *key, KeyBlock *actkb, KeyBlock *kb, const int start, int end, char *out, const int tot)
+static void cp_cu_key(Curve *cu,
+ Key *key,
+ KeyBlock *actkb,
+ KeyBlock *kb,
+ const int start,
+ int end,
+ char *out,
+ const int tot)
{
- Nurb *nu;
- int a, step, a1, a2;
-
- for (a = 0, nu = cu->nurb.first; nu; nu = nu->next, a += step) {
- if (nu->bp) {
- step = KEYELEM_ELEM_LEN_BPOINT * nu->pntsu * nu->pntsv;
-
- a1 = max_ii(a, start);
- a2 = min_ii(a + step, end);
-
- if (a1 < a2) cp_key(a1, a2, tot, out, key, actkb, kb, NULL, KEY_MODE_BPOINT);
- }
- else if (nu->bezt) {
- step = KEYELEM_ELEM_LEN_BEZTRIPLE * nu->pntsu;
-
- /* exception because keys prefer to work with complete blocks */
- a1 = max_ii(a, start);
- a2 = min_ii(a + step, end);
-
- if (a1 < a2) cp_key(a1, a2, tot, out, key, actkb, kb, NULL, KEY_MODE_BEZTRIPLE);
- }
- else {
- step = 0;
- }
- }
+ Nurb *nu;
+ int a, step, a1, a2;
+
+ for (a = 0, nu = cu->nurb.first; nu; nu = nu->next, a += step) {
+ if (nu->bp) {
+ step = KEYELEM_ELEM_LEN_BPOINT * nu->pntsu * nu->pntsv;
+
+ a1 = max_ii(a, start);
+ a2 = min_ii(a + step, end);
+
+ if (a1 < a2)
+ cp_key(a1, a2, tot, out, key, actkb, kb, NULL, KEY_MODE_BPOINT);
+ }
+ else if (nu->bezt) {
+ step = KEYELEM_ELEM_LEN_BEZTRIPLE * nu->pntsu;
+
+ /* exception because keys prefer to work with complete blocks */
+ a1 = max_ii(a, start);
+ a2 = min_ii(a + step, end);
+
+ if (a1 < a2)
+ cp_key(a1, a2, tot, out, key, actkb, kb, NULL, KEY_MODE_BEZTRIPLE);
+ }
+ else {
+ step = 0;
+ }
+ }
}
-static void key_evaluate_relative(
- const int start, int end, const int tot, char *basispoin, Key *key, KeyBlock *actkb,
- float **per_keyblock_weights, const int mode)
+static void key_evaluate_relative(const int start,
+ int end,
+ const int tot,
+ char *basispoin,
+ Key *key,
+ KeyBlock *actkb,
+ float **per_keyblock_weights,
+ const int mode)
{
- KeyBlock *kb;
- int *ofsp, ofs[3], elemsize, b, step;
- char *cp, *poin, *reffrom, *from, elemstr[8];
- int poinsize, keyblock_index;
-
- /* currently always 0, in future key_pointer_size may assign */
- ofs[1] = 0;
-
- if (!key_pointer_size(key, mode, &poinsize, &ofs[0], &step))
- return;
-
- if (end > tot) end = tot;
-
- /* in case of beztriple */
- elemstr[0] = 1; /* nr of ipofloats */
- elemstr[1] = IPO_BEZTRIPLE;
- elemstr[2] = 0;
-
- /* just here, not above! */
- elemsize = key->elemsize * step;
-
- /* step 1 init */
- cp_key(start, end, tot, basispoin, key, actkb, key->refkey, NULL, mode);
-
- /* step 2: do it */
-
- for (kb = key->block.first, keyblock_index = 0; kb; kb = kb->next, keyblock_index++) {
- if (kb != key->refkey) {
- float icuval = kb->curval;
-
- /* only with value, and no difference allowed */
- if (!(kb->flag & KEYBLOCK_MUTE) && icuval != 0.0f && kb->totelem == tot) {
- KeyBlock *refb;
- float weight, *weights = per_keyblock_weights ? per_keyblock_weights[keyblock_index] : NULL;
- char *freefrom = NULL, *freereffrom = NULL;
-
- /* reference now can be any block */
- refb = BLI_findlink(&key->block, kb->relative);
- if (refb == NULL) continue;
-
- poin = basispoin;
- from = key_block_get_data(key, actkb, kb, &freefrom);
- reffrom = key_block_get_data(key, actkb, refb, &freereffrom);
-
- poin += start * poinsize;
- reffrom += key->elemsize * start; // key elemsize yes!
- from += key->elemsize * start;
-
- for (b = start; b < end; b += step) {
-
- weight = weights ? (*weights * icuval) : icuval;
-
- cp = key->elemstr;
- if (mode == KEY_MODE_BEZTRIPLE) cp = elemstr;
-
- ofsp = ofs;
-
- while (cp[0]) { /* (cp[0] == amount) */
-
- switch (cp[1]) {
- case IPO_FLOAT:
- rel_flerp(KEYELEM_FLOAT_LEN_COORD, (float *)poin, (float *)reffrom, (float *)from, weight);
- break;
- case IPO_BPOINT:
- rel_flerp(KEYELEM_FLOAT_LEN_BPOINT, (float *)poin, (float *)reffrom, (float *)from, weight);
- break;
- case IPO_BEZTRIPLE:
- rel_flerp(KEYELEM_FLOAT_LEN_BEZTRIPLE, (float *)poin, (float *)reffrom, (float *)from, weight);
- break;
- default:
- /* should never happen */
- if (freefrom) MEM_freeN(freefrom);
- if (freereffrom) MEM_freeN(freereffrom);
- BLI_assert(!"invalid 'cp[1]'");
- return;
- }
-
- poin += *ofsp;
-
- cp += 2;
- ofsp++;
- }
-
- reffrom += elemsize;
- from += elemsize;
-
- if (weights) weights++;
- }
-
- if (freefrom) MEM_freeN(freefrom);
- if (freereffrom) MEM_freeN(freereffrom);
- }
- }
- }
+ KeyBlock *kb;
+ int *ofsp, ofs[3], elemsize, b, step;
+ char *cp, *poin, *reffrom, *from, elemstr[8];
+ int poinsize, keyblock_index;
+
+ /* currently always 0, in future key_pointer_size may assign */
+ ofs[1] = 0;
+
+ if (!key_pointer_size(key, mode, &poinsize, &ofs[0], &step))
+ return;
+
+ if (end > tot)
+ end = tot;
+
+ /* in case of beztriple */
+ elemstr[0] = 1; /* nr of ipofloats */
+ elemstr[1] = IPO_BEZTRIPLE;
+ elemstr[2] = 0;
+
+ /* just here, not above! */
+ elemsize = key->elemsize * step;
+
+ /* step 1 init */
+ cp_key(start, end, tot, basispoin, key, actkb, key->refkey, NULL, mode);
+
+ /* step 2: do it */
+
+ for (kb = key->block.first, keyblock_index = 0; kb; kb = kb->next, keyblock_index++) {
+ if (kb != key->refkey) {
+ float icuval = kb->curval;
+
+ /* only with value, and no difference allowed */
+ if (!(kb->flag & KEYBLOCK_MUTE) && icuval != 0.0f && kb->totelem == tot) {
+ KeyBlock *refb;
+ float weight,
+ *weights = per_keyblock_weights ? per_keyblock_weights[keyblock_index] : NULL;
+ char *freefrom = NULL, *freereffrom = NULL;
+
+ /* reference now can be any block */
+ refb = BLI_findlink(&key->block, kb->relative);
+ if (refb == NULL)
+ continue;
+
+ poin = basispoin;
+ from = key_block_get_data(key, actkb, kb, &freefrom);
+ reffrom = key_block_get_data(key, actkb, refb, &freereffrom);
+
+ poin += start * poinsize;
+ reffrom += key->elemsize * start; // key elemsize yes!
+ from += key->elemsize * start;
+
+ for (b = start; b < end; b += step) {
+
+ weight = weights ? (*weights * icuval) : icuval;
+
+ cp = key->elemstr;
+ if (mode == KEY_MODE_BEZTRIPLE)
+ cp = elemstr;
+
+ ofsp = ofs;
+
+ while (cp[0]) { /* (cp[0] == amount) */
+
+ switch (cp[1]) {
+ case IPO_FLOAT:
+ rel_flerp(KEYELEM_FLOAT_LEN_COORD,
+ (float *)poin,
+ (float *)reffrom,
+ (float *)from,
+ weight);
+ break;
+ case IPO_BPOINT:
+ rel_flerp(KEYELEM_FLOAT_LEN_BPOINT,
+ (float *)poin,
+ (float *)reffrom,
+ (float *)from,
+ weight);
+ break;
+ case IPO_BEZTRIPLE:
+ rel_flerp(KEYELEM_FLOAT_LEN_BEZTRIPLE,
+ (float *)poin,
+ (float *)reffrom,
+ (float *)from,
+ weight);
+ break;
+ default:
+ /* should never happen */
+ if (freefrom)
+ MEM_freeN(freefrom);
+ if (freereffrom)
+ MEM_freeN(freereffrom);
+ BLI_assert(!"invalid 'cp[1]'");
+ return;
+ }
+
+ poin += *ofsp;
+
+ cp += 2;
+ ofsp++;
+ }
+
+ reffrom += elemsize;
+ from += elemsize;
+
+ if (weights)
+ weights++;
+ }
+
+ if (freefrom)
+ MEM_freeN(freefrom);
+ if (freereffrom)
+ MEM_freeN(freereffrom);
+ }
+ }
+ }
}
-
-static void do_key(const int start, int end, const int tot, char *poin, Key *key, KeyBlock *actkb, KeyBlock **k, float *t, const int mode)
+static void do_key(const int start,
+ int end,
+ const int tot,
+ char *poin,
+ Key *key,
+ KeyBlock *actkb,
+ KeyBlock **k,
+ float *t,
+ const int mode)
{
- float k1tot = 0.0, k2tot = 0.0, k3tot = 0.0, k4tot = 0.0;
- float k1d = 0.0, k2d = 0.0, k3d = 0.0, k4d = 0.0;
- int a, step, ofs[32], *ofsp;
- int flagdo = 15, flagflo = 0, elemsize, poinsize = 0;
- char *k1, *k2, *k3, *k4, *freek1, *freek2, *freek3, *freek4;
- char *cp, elemstr[8];
-
- /* currently always 0, in future key_pointer_size may assign */
- ofs[1] = 0;
-
- if (!key_pointer_size(key, mode, &poinsize, &ofs[0], &step))
- return;
-
- if (end > tot) end = tot;
-
- k1 = key_block_get_data(key, actkb, k[0], &freek1);
- k2 = key_block_get_data(key, actkb, k[1], &freek2);
- k3 = key_block_get_data(key, actkb, k[2], &freek3);
- k4 = key_block_get_data(key, actkb, k[3], &freek4);
-
- /* test for more or less points (per key!) */
- if (tot != k[0]->totelem) {
- k1tot = 0.0;
- flagflo |= 1;
- if (k[0]->totelem) {
- k1d = k[0]->totelem / (float)tot;
- }
- else {
- flagdo -= 1;
- }
- }
- if (tot != k[1]->totelem) {
- k2tot = 0.0;
- flagflo |= 2;
- if (k[0]->totelem) {
- k2d = k[1]->totelem / (float)tot;
- }
- else {
- flagdo -= 2;
- }
- }
- if (tot != k[2]->totelem) {
- k3tot = 0.0;
- flagflo |= 4;
- if (k[0]->totelem) {
- k3d = k[2]->totelem / (float)tot;
- }
- else {
- flagdo -= 4;
- }
- }
- if (tot != k[3]->totelem) {
- k4tot = 0.0;
- flagflo |= 8;
- if (k[0]->totelem) {
- k4d = k[3]->totelem / (float)tot;
- }
- else {
- flagdo -= 8;
- }
- }
-
- /* this exception is needed for curves with multiple splines */
- if (start != 0) {
-
- poin += poinsize * start;
-
- if (flagdo & 1) {
- if (flagflo & 1) {
- k1tot += start * k1d;
- a = (int)floor(k1tot);
- if (a) {
- k1tot -= a;
- k1 += a * key->elemsize;
- }
- }
- else {
- k1 += start * key->elemsize;
- }
- }
- if (flagdo & 2) {
- if (flagflo & 2) {
- k2tot += start * k2d;
- a = (int)floor(k2tot);
- if (a) {
- k2tot -= a;
- k2 += a * key->elemsize;
- }
- }
- else {
- k2 += start * key->elemsize;
- }
- }
- if (flagdo & 4) {
- if (flagflo & 4) {
- k3tot += start * k3d;
- a = (int)floor(k3tot);
- if (a) {
- k3tot -= a;
- k3 += a * key->elemsize;
- }
- }
- else {
- k3 += start * key->elemsize;
- }
- }
- if (flagdo & 8) {
- if (flagflo & 8) {
- k4tot += start * k4d;
- a = (int)floor(k4tot);
- if (a) {
- k4tot -= a;
- k4 += a * key->elemsize;
- }
- }
- else {
- k4 += start * key->elemsize;
- }
- }
-
- }
-
- /* in case of beztriple */
- elemstr[0] = 1; /* nr of ipofloats */
- elemstr[1] = IPO_BEZTRIPLE;
- elemstr[2] = 0;
-
- /* only here, not above! */
- elemsize = key->elemsize * step;
-
- for (a = start; a < end; a += step) {
- cp = key->elemstr;
- if (mode == KEY_MODE_BEZTRIPLE) cp = elemstr;
-
- ofsp = ofs;
-
- while (cp[0]) { /* (cp[0] == amount) */
-
- switch (cp[1]) {
- case IPO_FLOAT:
- flerp(KEYELEM_FLOAT_LEN_COORD, (float *)poin, (float *)k1, (float *)k2, (float *)k3, (float *)k4, t);
- break;
- case IPO_BPOINT:
- flerp(KEYELEM_FLOAT_LEN_BPOINT, (float *)poin, (float *)k1, (float *)k2, (float *)k3, (float *)k4, t);
- break;
- case IPO_BEZTRIPLE:
- flerp(KEYELEM_FLOAT_LEN_BEZTRIPLE, (void *)poin, (void *)k1, (void *)k2, (void *)k3, (void *)k4, t);
- break;
- default:
- /* should never happen */
- if (freek1) MEM_freeN(freek1);
- if (freek2) MEM_freeN(freek2);
- if (freek3) MEM_freeN(freek3);
- if (freek4) MEM_freeN(freek4);
- BLI_assert(!"invalid 'cp[1]'");
- return;
- }
-
- poin += *ofsp;
- cp += 2;
- ofsp++;
- }
- /* lets do it the difficult way: when keys have a different size */
- if (flagdo & 1) {
- if (flagflo & 1) {
- k1tot += k1d;
- while (k1tot >= 1.0f) {
- k1tot -= 1.0f;
- k1 += elemsize;
- }
- }
- else {
- k1 += elemsize;
- }
- }
- if (flagdo & 2) {
- if (flagflo & 2) {
- k2tot += k2d;
- while (k2tot >= 1.0f) {
- k2tot -= 1.0f;
- k2 += elemsize;
- }
- }
- else {
- k2 += elemsize;
- }
- }
- if (flagdo & 4) {
- if (flagflo & 4) {
- k3tot += k3d;
- while (k3tot >= 1.0f) {
- k3tot -= 1.0f;
- k3 += elemsize;
- }
- }
- else {
- k3 += elemsize;
- }
- }
- if (flagdo & 8) {
- if (flagflo & 8) {
- k4tot += k4d;
- while (k4tot >= 1.0f) {
- k4tot -= 1.0f;
- k4 += elemsize;
- }
- }
- else {
- k4 += elemsize;
- }
- }
- }
-
- if (freek1) MEM_freeN(freek1);
- if (freek2) MEM_freeN(freek2);
- if (freek3) MEM_freeN(freek3);
- if (freek4) MEM_freeN(freek4);
+ float k1tot = 0.0, k2tot = 0.0, k3tot = 0.0, k4tot = 0.0;
+ float k1d = 0.0, k2d = 0.0, k3d = 0.0, k4d = 0.0;
+ int a, step, ofs[32], *ofsp;
+ int flagdo = 15, flagflo = 0, elemsize, poinsize = 0;
+ char *k1, *k2, *k3, *k4, *freek1, *freek2, *freek3, *freek4;
+ char *cp, elemstr[8];
+
+ /* currently always 0, in future key_pointer_size may assign */
+ ofs[1] = 0;
+
+ if (!key_pointer_size(key, mode, &poinsize, &ofs[0], &step))
+ return;
+
+ if (end > tot)
+ end = tot;
+
+ k1 = key_block_get_data(key, actkb, k[0], &freek1);
+ k2 = key_block_get_data(key, actkb, k[1], &freek2);
+ k3 = key_block_get_data(key, actkb, k[2], &freek3);
+ k4 = key_block_get_data(key, actkb, k[3], &freek4);
+
+ /* test for more or less points (per key!) */
+ if (tot != k[0]->totelem) {
+ k1tot = 0.0;
+ flagflo |= 1;
+ if (k[0]->totelem) {
+ k1d = k[0]->totelem / (float)tot;
+ }
+ else {
+ flagdo -= 1;
+ }
+ }
+ if (tot != k[1]->totelem) {
+ k2tot = 0.0;
+ flagflo |= 2;
+ if (k[0]->totelem) {
+ k2d = k[1]->totelem / (float)tot;
+ }
+ else {
+ flagdo -= 2;
+ }
+ }
+ if (tot != k[2]->totelem) {
+ k3tot = 0.0;
+ flagflo |= 4;
+ if (k[0]->totelem) {
+ k3d = k[2]->totelem / (float)tot;
+ }
+ else {
+ flagdo -= 4;
+ }
+ }
+ if (tot != k[3]->totelem) {
+ k4tot = 0.0;
+ flagflo |= 8;
+ if (k[0]->totelem) {
+ k4d = k[3]->totelem / (float)tot;
+ }
+ else {
+ flagdo -= 8;
+ }
+ }
+
+ /* this exception is needed for curves with multiple splines */
+ if (start != 0) {
+
+ poin += poinsize * start;
+
+ if (flagdo & 1) {
+ if (flagflo & 1) {
+ k1tot += start * k1d;
+ a = (int)floor(k1tot);
+ if (a) {
+ k1tot -= a;
+ k1 += a * key->elemsize;
+ }
+ }
+ else {
+ k1 += start * key->elemsize;
+ }
+ }
+ if (flagdo & 2) {
+ if (flagflo & 2) {
+ k2tot += start * k2d;
+ a = (int)floor(k2tot);
+ if (a) {
+ k2tot -= a;
+ k2 += a * key->elemsize;
+ }
+ }
+ else {
+ k2 += start * key->elemsize;
+ }
+ }
+ if (flagdo & 4) {
+ if (flagflo & 4) {
+ k3tot += start * k3d;
+ a = (int)floor(k3tot);
+ if (a) {
+ k3tot -= a;
+ k3 += a * key->elemsize;
+ }
+ }
+ else {
+ k3 += start * key->elemsize;
+ }
+ }
+ if (flagdo & 8) {
+ if (flagflo & 8) {
+ k4tot += start * k4d;
+ a = (int)floor(k4tot);
+ if (a) {
+ k4tot -= a;
+ k4 += a * key->elemsize;
+ }
+ }
+ else {
+ k4 += start * key->elemsize;
+ }
+ }
+ }
+
+ /* in case of beztriple */
+ elemstr[0] = 1; /* nr of ipofloats */
+ elemstr[1] = IPO_BEZTRIPLE;
+ elemstr[2] = 0;
+
+ /* only here, not above! */
+ elemsize = key->elemsize * step;
+
+ for (a = start; a < end; a += step) {
+ cp = key->elemstr;
+ if (mode == KEY_MODE_BEZTRIPLE)
+ cp = elemstr;
+
+ ofsp = ofs;
+
+ while (cp[0]) { /* (cp[0] == amount) */
+
+ switch (cp[1]) {
+ case IPO_FLOAT:
+ flerp(KEYELEM_FLOAT_LEN_COORD,
+ (float *)poin,
+ (float *)k1,
+ (float *)k2,
+ (float *)k3,
+ (float *)k4,
+ t);
+ break;
+ case IPO_BPOINT:
+ flerp(KEYELEM_FLOAT_LEN_BPOINT,
+ (float *)poin,
+ (float *)k1,
+ (float *)k2,
+ (float *)k3,
+ (float *)k4,
+ t);
+ break;
+ case IPO_BEZTRIPLE:
+ flerp(KEYELEM_FLOAT_LEN_BEZTRIPLE,
+ (void *)poin,
+ (void *)k1,
+ (void *)k2,
+ (void *)k3,
+ (void *)k4,
+ t);
+ break;
+ default:
+ /* should never happen */
+ if (freek1)
+ MEM_freeN(freek1);
+ if (freek2)
+ MEM_freeN(freek2);
+ if (freek3)
+ MEM_freeN(freek3);
+ if (freek4)
+ MEM_freeN(freek4);
+ BLI_assert(!"invalid 'cp[1]'");
+ return;
+ }
+
+ poin += *ofsp;
+ cp += 2;
+ ofsp++;
+ }
+ /* lets do it the difficult way: when keys have a different size */
+ if (flagdo & 1) {
+ if (flagflo & 1) {
+ k1tot += k1d;
+ while (k1tot >= 1.0f) {
+ k1tot -= 1.0f;
+ k1 += elemsize;
+ }
+ }
+ else {
+ k1 += elemsize;
+ }
+ }
+ if (flagdo & 2) {
+ if (flagflo & 2) {
+ k2tot += k2d;
+ while (k2tot >= 1.0f) {
+ k2tot -= 1.0f;
+ k2 += elemsize;
+ }
+ }
+ else {
+ k2 += elemsize;
+ }
+ }
+ if (flagdo & 4) {
+ if (flagflo & 4) {
+ k3tot += k3d;
+ while (k3tot >= 1.0f) {
+ k3tot -= 1.0f;
+ k3 += elemsize;
+ }
+ }
+ else {
+ k3 += elemsize;
+ }
+ }
+ if (flagdo & 8) {
+ if (flagflo & 8) {
+ k4tot += k4d;
+ while (k4tot >= 1.0f) {
+ k4tot -= 1.0f;
+ k4 += elemsize;
+ }
+ }
+ else {
+ k4 += elemsize;
+ }
+ }
+ }
+
+ if (freek1)
+ MEM_freeN(freek1);
+ if (freek2)
+ MEM_freeN(freek2);
+ if (freek3)
+ MEM_freeN(freek3);
+ if (freek4)
+ MEM_freeN(freek4);
}
static float *get_weights_array(Object *ob, char *vgroup, WeightsArrayCache *cache)
{
- MDeformVert *dvert = NULL;
- BMEditMesh *em = NULL;
- BMIter iter;
- BMVert *eve;
- int totvert = 0, defgrp_index = 0;
-
- /* no vgroup string set? */
- if (vgroup[0] == 0) return NULL;
-
- /* gather dvert and totvert */
- if (ob->type == OB_MESH) {
- Mesh *me = ob->data;
- dvert = me->dvert;
- totvert = me->totvert;
-
- if (me->edit_mesh && me->edit_mesh->bm->totvert == totvert)
- em = me->edit_mesh;
- }
- else if (ob->type == OB_LATTICE) {
- Lattice *lt = ob->data;
- dvert = lt->dvert;
- totvert = lt->pntsu * lt->pntsv * lt->pntsw;
- }
-
- if (dvert == NULL) return NULL;
-
- /* find the group (weak loop-in-loop) */
- defgrp_index = defgroup_name_index(ob, vgroup);
- if (defgrp_index != -1) {
- float *weights;
- int i;
-
- if (cache) {
- if (cache->defgroup_weights == NULL) {
- int num_defgroup = BLI_listbase_count(&ob->defbase);
- cache->defgroup_weights =
- MEM_callocN(sizeof(*cache->defgroup_weights) * num_defgroup,
- "cached defgroup weights");
- cache->num_defgroup_weights = num_defgroup;
- }
-
- if (cache->defgroup_weights[defgrp_index]) {
- return cache->defgroup_weights[defgrp_index];
- }
- }
-
- weights = MEM_mallocN(totvert * sizeof(float), "weights");
-
- if (em) {
- const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
- BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
- dvert = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
- weights[i] = defvert_find_weight(dvert, defgrp_index);
- }
- }
- else {
- for (i = 0; i < totvert; i++, dvert++) {
- weights[i] = defvert_find_weight(dvert, defgrp_index);
- }
- }
-
- if (cache) {
- cache->defgroup_weights[defgrp_index] = weights;
- }
-
- return weights;
- }
- return NULL;
+ MDeformVert *dvert = NULL;
+ BMEditMesh *em = NULL;
+ BMIter iter;
+ BMVert *eve;
+ int totvert = 0, defgrp_index = 0;
+
+ /* no vgroup string set? */
+ if (vgroup[0] == 0)
+ return NULL;
+
+ /* gather dvert and totvert */
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+ dvert = me->dvert;
+ totvert = me->totvert;
+
+ if (me->edit_mesh && me->edit_mesh->bm->totvert == totvert)
+ em = me->edit_mesh;
+ }
+ else if (ob->type == OB_LATTICE) {
+ Lattice *lt = ob->data;
+ dvert = lt->dvert;
+ totvert = lt->pntsu * lt->pntsv * lt->pntsw;
+ }
+
+ if (dvert == NULL)
+ return NULL;
+
+ /* find the group (weak loop-in-loop) */
+ defgrp_index = defgroup_name_index(ob, vgroup);
+ if (defgrp_index != -1) {
+ float *weights;
+ int i;
+
+ if (cache) {
+ if (cache->defgroup_weights == NULL) {
+ int num_defgroup = BLI_listbase_count(&ob->defbase);
+ cache->defgroup_weights = MEM_callocN(sizeof(*cache->defgroup_weights) * num_defgroup,
+ "cached defgroup weights");
+ cache->num_defgroup_weights = num_defgroup;
+ }
+
+ if (cache->defgroup_weights[defgrp_index]) {
+ return cache->defgroup_weights[defgrp_index];
+ }
+ }
+
+ weights = MEM_mallocN(totvert * sizeof(float), "weights");
+
+ if (em) {
+ const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
+ BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
+ dvert = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
+ weights[i] = defvert_find_weight(dvert, defgrp_index);
+ }
+ }
+ else {
+ for (i = 0; i < totvert; i++, dvert++) {
+ weights[i] = defvert_find_weight(dvert, defgrp_index);
+ }
+ }
+
+ if (cache) {
+ cache->defgroup_weights[defgrp_index] = weights;
+ }
+
+ return weights;
+ }
+ return NULL;
}
static float **keyblock_get_per_block_weights(Object *ob, Key *key, WeightsArrayCache *cache)
{
- KeyBlock *keyblock;
- float **per_keyblock_weights;
- int keyblock_index;
-
- per_keyblock_weights =
- MEM_mallocN(sizeof(*per_keyblock_weights) * key->totkey,
- "per keyblock weights");
-
- for (keyblock = key->block.first, keyblock_index = 0;
- keyblock;
- keyblock = keyblock->next, keyblock_index++)
- {
- per_keyblock_weights[keyblock_index] = get_weights_array(ob, keyblock->vgroup, cache);
- }
-
- return per_keyblock_weights;
+ KeyBlock *keyblock;
+ float **per_keyblock_weights;
+ int keyblock_index;
+
+ per_keyblock_weights = MEM_mallocN(sizeof(*per_keyblock_weights) * key->totkey,
+ "per keyblock weights");
+
+ for (keyblock = key->block.first, keyblock_index = 0; keyblock;
+ keyblock = keyblock->next, keyblock_index++) {
+ per_keyblock_weights[keyblock_index] = get_weights_array(ob, keyblock->vgroup, cache);
+ }
+
+ return per_keyblock_weights;
}
-static void keyblock_free_per_block_weights(Key *key, float **per_keyblock_weights, WeightsArrayCache *cache)
+static void keyblock_free_per_block_weights(Key *key,
+ float **per_keyblock_weights,
+ WeightsArrayCache *cache)
{
- int a;
-
- if (cache) {
- if (cache->num_defgroup_weights) {
- for (a = 0; a < cache->num_defgroup_weights; a++) {
- if (cache->defgroup_weights[a]) {
- MEM_freeN(cache->defgroup_weights[a]);
- }
- }
- MEM_freeN(cache->defgroup_weights);
- }
- cache->defgroup_weights = NULL;
- }
- else {
- for (a = 0; a < key->totkey; a++) {
- if (per_keyblock_weights[a]) {
- MEM_freeN(per_keyblock_weights[a]);
- }
- }
- }
-
- MEM_freeN(per_keyblock_weights);
+ int a;
+
+ if (cache) {
+ if (cache->num_defgroup_weights) {
+ for (a = 0; a < cache->num_defgroup_weights; a++) {
+ if (cache->defgroup_weights[a]) {
+ MEM_freeN(cache->defgroup_weights[a]);
+ }
+ }
+ MEM_freeN(cache->defgroup_weights);
+ }
+ cache->defgroup_weights = NULL;
+ }
+ else {
+ for (a = 0; a < key->totkey; a++) {
+ if (per_keyblock_weights[a]) {
+ MEM_freeN(per_keyblock_weights[a]);
+ }
+ }
+ }
+
+ MEM_freeN(per_keyblock_weights);
}
static void do_mesh_key(Object *ob, Key *key, char *out, const int tot)
{
- KeyBlock *k[4], *actkb = BKE_keyblock_from_object(ob);
- float t[4];
- int flag = 0;
-
- if (key->type == KEY_RELATIVE) {
- WeightsArrayCache cache = {0, NULL};
- float **per_keyblock_weights;
- per_keyblock_weights = keyblock_get_per_block_weights(ob, key, &cache);
- key_evaluate_relative(0, tot, tot, (char *)out, key, actkb, per_keyblock_weights, KEY_MODE_DUMMY);
- keyblock_free_per_block_weights(key, per_keyblock_weights, &cache);
- }
- else {
- const float ctime_scaled = key->ctime / 100.0f;
-
- flag = setkeys(ctime_scaled, &key->block, k, t, 0);
-
- if (flag == 0) {
- do_key(0, tot, tot, (char *)out, key, actkb, k, t, KEY_MODE_DUMMY);
- }
- else {
- cp_key(0, tot, tot, (char *)out, key, actkb, k[2], NULL, KEY_MODE_DUMMY);
- }
- }
+ KeyBlock *k[4], *actkb = BKE_keyblock_from_object(ob);
+ float t[4];
+ int flag = 0;
+
+ if (key->type == KEY_RELATIVE) {
+ WeightsArrayCache cache = {0, NULL};
+ float **per_keyblock_weights;
+ per_keyblock_weights = keyblock_get_per_block_weights(ob, key, &cache);
+ key_evaluate_relative(
+ 0, tot, tot, (char *)out, key, actkb, per_keyblock_weights, KEY_MODE_DUMMY);
+ keyblock_free_per_block_weights(key, per_keyblock_weights, &cache);
+ }
+ else {
+ const float ctime_scaled = key->ctime / 100.0f;
+
+ flag = setkeys(ctime_scaled, &key->block, k, t, 0);
+
+ if (flag == 0) {
+ do_key(0, tot, tot, (char *)out, key, actkb, k, t, KEY_MODE_DUMMY);
+ }
+ else {
+ cp_key(0, tot, tot, (char *)out, key, actkb, k[2], NULL, KEY_MODE_DUMMY);
+ }
+ }
}
-static void do_cu_key(Curve *cu, Key *key, KeyBlock *actkb, KeyBlock **k, float *t, char *out, const int tot)
+static void do_cu_key(
+ Curve *cu, Key *key, KeyBlock *actkb, KeyBlock **k, float *t, char *out, const int tot)
{
- Nurb *nu;
- int a, step;
-
- for (a = 0, nu = cu->nurb.first; nu; nu = nu->next, a += step) {
- if (nu->bp) {
- step = KEYELEM_ELEM_LEN_BPOINT * nu->pntsu * nu->pntsv;
- do_key(a, a + step, tot, out, key, actkb, k, t, KEY_MODE_BPOINT);
- }
- else if (nu->bezt) {
- step = KEYELEM_ELEM_LEN_BEZTRIPLE * nu->pntsu;
- do_key(a, a + step, tot, out, key, actkb, k, t, KEY_MODE_BEZTRIPLE);
- }
- else {
- step = 0;
- }
- }
+ Nurb *nu;
+ int a, step;
+
+ for (a = 0, nu = cu->nurb.first; nu; nu = nu->next, a += step) {
+ if (nu->bp) {
+ step = KEYELEM_ELEM_LEN_BPOINT * nu->pntsu * nu->pntsv;
+ do_key(a, a + step, tot, out, key, actkb, k, t, KEY_MODE_BPOINT);
+ }
+ else if (nu->bezt) {
+ step = KEYELEM_ELEM_LEN_BEZTRIPLE * nu->pntsu;
+ do_key(a, a + step, tot, out, key, actkb, k, t, KEY_MODE_BEZTRIPLE);
+ }
+ else {
+ step = 0;
+ }
+ }
}
static void do_rel_cu_key(Curve *cu, Key *key, KeyBlock *actkb, char *out, const int tot)
{
- Nurb *nu;
- int a, step;
-
- for (a = 0, nu = cu->nurb.first; nu; nu = nu->next, a += step) {
- if (nu->bp) {
- step = KEYELEM_ELEM_LEN_BPOINT * nu->pntsu * nu->pntsv;
- key_evaluate_relative(a, a + step, tot, out, key, actkb, NULL, KEY_MODE_BPOINT);
- }
- else if (nu->bezt) {
- step = KEYELEM_ELEM_LEN_BEZTRIPLE * nu->pntsu;
- key_evaluate_relative(a, a + step, tot, out, key, actkb, NULL, KEY_MODE_BEZTRIPLE);
- }
- else {
- step = 0;
- }
- }
+ Nurb *nu;
+ int a, step;
+
+ for (a = 0, nu = cu->nurb.first; nu; nu = nu->next, a += step) {
+ if (nu->bp) {
+ step = KEYELEM_ELEM_LEN_BPOINT * nu->pntsu * nu->pntsv;
+ key_evaluate_relative(a, a + step, tot, out, key, actkb, NULL, KEY_MODE_BPOINT);
+ }
+ else if (nu->bezt) {
+ step = KEYELEM_ELEM_LEN_BEZTRIPLE * nu->pntsu;
+ key_evaluate_relative(a, a + step, tot, out, key, actkb, NULL, KEY_MODE_BEZTRIPLE);
+ }
+ else {
+ step = 0;
+ }
+ }
}
static void do_curve_key(Object *ob, Key *key, char *out, const int tot)
{
- Curve *cu = ob->data;
- KeyBlock *k[4], *actkb = BKE_keyblock_from_object(ob);
- float t[4];
- int flag = 0;
-
- if (key->type == KEY_RELATIVE) {
- do_rel_cu_key(cu, cu->key, actkb, out, tot);
- }
- else {
- const float ctime_scaled = key->ctime / 100.0f;
-
- flag = setkeys(ctime_scaled, &key->block, k, t, 0);
-
- if (flag == 0) {
- do_cu_key(cu, key, actkb, k, t, out, tot);
- }
- else {
- cp_cu_key(cu, key, actkb, k[2], 0, tot, out, tot);
- }
- }
+ Curve *cu = ob->data;
+ KeyBlock *k[4], *actkb = BKE_keyblock_from_object(ob);
+ float t[4];
+ int flag = 0;
+
+ if (key->type == KEY_RELATIVE) {
+ do_rel_cu_key(cu, cu->key, actkb, out, tot);
+ }
+ else {
+ const float ctime_scaled = key->ctime / 100.0f;
+
+ flag = setkeys(ctime_scaled, &key->block, k, t, 0);
+
+ if (flag == 0) {
+ do_cu_key(cu, key, actkb, k, t, out, tot);
+ }
+ else {
+ cp_cu_key(cu, key, actkb, k[2], 0, tot, out, tot);
+ }
+ }
}
static void do_latt_key(Object *ob, Key *key, char *out, const int tot)
{
- Lattice *lt = ob->data;
- KeyBlock *k[4], *actkb = BKE_keyblock_from_object(ob);
- float t[4];
- int flag;
-
- if (key->type == KEY_RELATIVE) {
- float **per_keyblock_weights;
- per_keyblock_weights = keyblock_get_per_block_weights(ob, key, NULL);
- key_evaluate_relative(0, tot, tot, (char *)out, key, actkb, per_keyblock_weights, KEY_MODE_DUMMY);
- keyblock_free_per_block_weights(key, per_keyblock_weights, NULL);
- }
- else {
- const float ctime_scaled = key->ctime / 100.0f;
-
- flag = setkeys(ctime_scaled, &key->block, k, t, 0);
-
- if (flag == 0) {
- do_key(0, tot, tot, (char *)out, key, actkb, k, t, KEY_MODE_DUMMY);
- }
- else {
- cp_key(0, tot, tot, (char *)out, key, actkb, k[2], NULL, KEY_MODE_DUMMY);
- }
- }
-
- if (lt->flag & LT_OUTSIDE) outside_lattice(lt);
+ Lattice *lt = ob->data;
+ KeyBlock *k[4], *actkb = BKE_keyblock_from_object(ob);
+ float t[4];
+ int flag;
+
+ if (key->type == KEY_RELATIVE) {
+ float **per_keyblock_weights;
+ per_keyblock_weights = keyblock_get_per_block_weights(ob, key, NULL);
+ key_evaluate_relative(
+ 0, tot, tot, (char *)out, key, actkb, per_keyblock_weights, KEY_MODE_DUMMY);
+ keyblock_free_per_block_weights(key, per_keyblock_weights, NULL);
+ }
+ else {
+ const float ctime_scaled = key->ctime / 100.0f;
+
+ flag = setkeys(ctime_scaled, &key->block, k, t, 0);
+
+ if (flag == 0) {
+ do_key(0, tot, tot, (char *)out, key, actkb, k, t, KEY_MODE_DUMMY);
+ }
+ else {
+ cp_key(0, tot, tot, (char *)out, key, actkb, k[2], NULL, KEY_MODE_DUMMY);
+ }
+ }
+
+ if (lt->flag & LT_OUTSIDE)
+ outside_lattice(lt);
}
/* returns key coordinates (+ tilt) when key applied, NULL otherwise */
-float *BKE_key_evaluate_object_ex(
- Object *ob, int *r_totelem,
- float *arr, size_t arr_size)
+float *BKE_key_evaluate_object_ex(Object *ob, int *r_totelem, float *arr, size_t arr_size)
{
- Key *key = BKE_key_from_object(ob);
- KeyBlock *actkb = BKE_keyblock_from_object(ob);
- char *out;
- int tot = 0, size = 0;
-
- if (key == NULL || BLI_listbase_is_empty(&key->block))
- return NULL;
-
- /* compute size of output array */
- if (ob->type == OB_MESH) {
- Mesh *me = ob->data;
-
- tot = me->totvert;
- size = tot * sizeof(float[KEYELEM_FLOAT_LEN_COORD]);
- }
- else if (ob->type == OB_LATTICE) {
- Lattice *lt = ob->data;
-
- tot = lt->pntsu * lt->pntsv * lt->pntsw;
- size = tot * sizeof(float[KEYELEM_FLOAT_LEN_COORD]);
- }
- else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
- Curve *cu = ob->data;
-
- tot = BKE_keyblock_curve_element_count(&cu->nurb);
- size = tot * sizeof(float[KEYELEM_ELEM_SIZE_CURVE]);
- }
-
- /* if nothing to interpolate, cancel */
- if (tot == 0 || size == 0)
- return NULL;
-
- /* allocate array */
- if (arr == NULL) {
- out = MEM_callocN(size, "BKE_key_evaluate_object out");
- }
- else {
- if (arr_size != size) {
- return NULL;
- }
-
- out = (char *)arr;
- }
-
- if (ob->shapeflag & OB_SHAPE_LOCK) {
- /* shape locked, copy the locked shape instead of blending */
- KeyBlock *kb = BLI_findlink(&key->block, ob->shapenr - 1);
-
- if (kb && (kb->flag & KEYBLOCK_MUTE))
- kb = key->refkey;
-
- if (kb == NULL) {
- kb = key->block.first;
- ob->shapenr = 1;
- }
-
- if (OB_TYPE_SUPPORT_VGROUP(ob->type)) {
- float *weights = get_weights_array(ob, kb->vgroup, NULL);
-
- cp_key(0, tot, tot, out, key, actkb, kb, weights, 0);
-
- if (weights) MEM_freeN(weights);
- }
- else if (ELEM(ob->type, OB_CURVE, OB_SURF))
- cp_cu_key(ob->data, key, actkb, kb, 0, tot, out, tot);
- }
- else {
-
- if (ob->type == OB_MESH) do_mesh_key(ob, key, out, tot);
- else if (ob->type == OB_LATTICE) do_latt_key(ob, key, out, tot);
- else if (ob->type == OB_CURVE) do_curve_key(ob, key, out, tot);
- else if (ob->type == OB_SURF) do_curve_key(ob, key, out, tot);
- }
-
- if (r_totelem) {
- *r_totelem = tot;
- }
- return (float *)out;
+ Key *key = BKE_key_from_object(ob);
+ KeyBlock *actkb = BKE_keyblock_from_object(ob);
+ char *out;
+ int tot = 0, size = 0;
+
+ if (key == NULL || BLI_listbase_is_empty(&key->block))
+ return NULL;
+
+ /* compute size of output array */
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+
+ tot = me->totvert;
+ size = tot * sizeof(float[KEYELEM_FLOAT_LEN_COORD]);
+ }
+ else if (ob->type == OB_LATTICE) {
+ Lattice *lt = ob->data;
+
+ tot = lt->pntsu * lt->pntsv * lt->pntsw;
+ size = tot * sizeof(float[KEYELEM_FLOAT_LEN_COORD]);
+ }
+ else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
+ Curve *cu = ob->data;
+
+ tot = BKE_keyblock_curve_element_count(&cu->nurb);
+ size = tot * sizeof(float[KEYELEM_ELEM_SIZE_CURVE]);
+ }
+
+ /* if nothing to interpolate, cancel */
+ if (tot == 0 || size == 0)
+ return NULL;
+
+ /* allocate array */
+ if (arr == NULL) {
+ out = MEM_callocN(size, "BKE_key_evaluate_object out");
+ }
+ else {
+ if (arr_size != size) {
+ return NULL;
+ }
+
+ out = (char *)arr;
+ }
+
+ if (ob->shapeflag & OB_SHAPE_LOCK) {
+ /* shape locked, copy the locked shape instead of blending */
+ KeyBlock *kb = BLI_findlink(&key->block, ob->shapenr - 1);
+
+ if (kb && (kb->flag & KEYBLOCK_MUTE))
+ kb = key->refkey;
+
+ if (kb == NULL) {
+ kb = key->block.first;
+ ob->shapenr = 1;
+ }
+
+ if (OB_TYPE_SUPPORT_VGROUP(ob->type)) {
+ float *weights = get_weights_array(ob, kb->vgroup, NULL);
+
+ cp_key(0, tot, tot, out, key, actkb, kb, weights, 0);
+
+ if (weights)
+ MEM_freeN(weights);
+ }
+ else if (ELEM(ob->type, OB_CURVE, OB_SURF))
+ cp_cu_key(ob->data, key, actkb, kb, 0, tot, out, tot);
+ }
+ else {
+
+ if (ob->type == OB_MESH)
+ do_mesh_key(ob, key, out, tot);
+ else if (ob->type == OB_LATTICE)
+ do_latt_key(ob, key, out, tot);
+ else if (ob->type == OB_CURVE)
+ do_curve_key(ob, key, out, tot);
+ else if (ob->type == OB_SURF)
+ do_curve_key(ob, key, out, tot);
+ }
+
+ if (r_totelem) {
+ *r_totelem = tot;
+ }
+ return (float *)out;
}
float *BKE_key_evaluate_object(Object *ob, int *r_totelem)
{
- return BKE_key_evaluate_object_ex(ob, r_totelem, NULL, 0);
+ return BKE_key_evaluate_object_ex(ob, r_totelem, NULL, 0);
}
bool BKE_key_idtype_support(const short id_type)
{
- switch (id_type) {
- case ID_ME:
- case ID_CU:
- case ID_LT:
- return true;
- default:
- return false;
- }
+ switch (id_type) {
+ case ID_ME:
+ case ID_CU:
+ case ID_LT:
+ return true;
+ default:
+ return false;
+ }
}
Key **BKE_key_from_id_p(ID *id)
{
- switch (GS(id->name)) {
- case ID_ME:
- {
- Mesh *me = (Mesh *)id;
- return &me->key;
- }
- case ID_CU:
- {
- Curve *cu = (Curve *)id;
- if (cu->vfont == NULL) {
- return &cu->key;
- }
- break;
- }
- case ID_LT:
- {
- Lattice *lt = (Lattice *)id;
- return &lt->key;
- }
- default:
- break;
- }
-
- return NULL;
+ switch (GS(id->name)) {
+ case ID_ME: {
+ Mesh *me = (Mesh *)id;
+ return &me->key;
+ }
+ case ID_CU: {
+ Curve *cu = (Curve *)id;
+ if (cu->vfont == NULL) {
+ return &cu->key;
+ }
+ break;
+ }
+ case ID_LT: {
+ Lattice *lt = (Lattice *)id;
+ return &lt->key;
+ }
+ default:
+ break;
+ }
+
+ return NULL;
}
Key *BKE_key_from_id(ID *id)
{
- Key **key_p;
- key_p = BKE_key_from_id_p(id);
- if (key_p) {
- return *key_p;
- }
+ Key **key_p;
+ key_p = BKE_key_from_id_p(id);
+ if (key_p) {
+ return *key_p;
+ }
- return NULL;
+ return NULL;
}
Key **BKE_key_from_object_p(const Object *ob)
{
- if (ob == NULL || ob->data == NULL)
- return NULL;
+ if (ob == NULL || ob->data == NULL)
+ return NULL;
- return BKE_key_from_id_p(ob->data);
+ return BKE_key_from_id_p(ob->data);
}
Key *BKE_key_from_object(const Object *ob)
{
- Key **key_p;
- key_p = BKE_key_from_object_p(ob);
- if (key_p) {
- return *key_p;
- }
+ Key **key_p;
+ key_p = BKE_key_from_object_p(ob);
+ if (key_p) {
+ return *key_p;
+ }
- return NULL;
+ return NULL;
}
KeyBlock *BKE_keyblock_add(Key *key, const char *name)
{
- KeyBlock *kb;
- float curpos = -0.1;
- int tot;
-
- kb = key->block.last;
- if (kb) curpos = kb->pos;
-
- kb = MEM_callocN(sizeof(KeyBlock), "Keyblock");
- BLI_addtail(&key->block, kb);
- kb->type = KEY_LINEAR;
-
- tot = BLI_listbase_count(&key->block);
- if (name) {
- BLI_strncpy(kb->name, name, sizeof(kb->name));
- }
- else {
- if (tot == 1)
- BLI_strncpy(kb->name, DATA_("Basis"), sizeof(kb->name));
- else
- BLI_snprintf(kb->name, sizeof(kb->name), DATA_("Key %d"), tot - 1);
- }
-
- BLI_uniquename(&key->block, kb, DATA_("Key"), '.', offsetof(KeyBlock, name), sizeof(kb->name));
-
- kb->uid = key->uidgen++;
-
- key->totkey++;
- if (key->totkey == 1) key->refkey = kb;
-
- kb->slidermin = 0.0f;
- kb->slidermax = 1.0f;
-
- /**
- * \note caller may want to set this to current time, but don't do it here since we need to sort
- * which could cause problems in some cases, see #BKE_keyblock_add_ctime */
- kb->pos = curpos + 0.1f; /* only used for absolute shape keys */
-
- return kb;
+ KeyBlock *kb;
+ float curpos = -0.1;
+ int tot;
+
+ kb = key->block.last;
+ if (kb)
+ curpos = kb->pos;
+
+ kb = MEM_callocN(sizeof(KeyBlock), "Keyblock");
+ BLI_addtail(&key->block, kb);
+ kb->type = KEY_LINEAR;
+
+ tot = BLI_listbase_count(&key->block);
+ if (name) {
+ BLI_strncpy(kb->name, name, sizeof(kb->name));
+ }
+ else {
+ if (tot == 1)
+ BLI_strncpy(kb->name, DATA_("Basis"), sizeof(kb->name));
+ else
+ BLI_snprintf(kb->name, sizeof(kb->name), DATA_("Key %d"), tot - 1);
+ }
+
+ BLI_uniquename(&key->block, kb, DATA_("Key"), '.', offsetof(KeyBlock, name), sizeof(kb->name));
+
+ kb->uid = key->uidgen++;
+
+ key->totkey++;
+ if (key->totkey == 1)
+ key->refkey = kb;
+
+ kb->slidermin = 0.0f;
+ kb->slidermax = 1.0f;
+
+ /**
+ * \note caller may want to set this to current time, but don't do it here since we need to sort
+ * which could cause problems in some cases, see #BKE_keyblock_add_ctime */
+ kb->pos = curpos + 0.1f; /* only used for absolute shape keys */
+
+ return kb;
}
/**
@@ -1486,79 +1584,79 @@ KeyBlock *BKE_keyblock_add(Key *key, const char *name)
*/
KeyBlock *BKE_keyblock_add_ctime(Key *key, const char *name, const bool do_force)
{
- KeyBlock *kb = BKE_keyblock_add(key, name);
- const float cpos = key->ctime / 100.0f;
-
- /* In case of absolute keys, there is no point in adding more than one key with the same pos.
- * Hence only set new keybloc pos to current time if none previous one already use it.
- * Now at least people just adding absolute keys without touching to ctime
- * won't have to systematically use retiming func (and have ordering issues, too). See T39897.
- */
- if (!do_force && (key->type != KEY_RELATIVE)) {
- KeyBlock *it_kb;
- for (it_kb = key->block.first; it_kb; it_kb = it_kb->next) {
- /* Use epsilon to avoid floating point precision issues.
- * 1e-3 because the position is stored as frame * 1e-2. */
- if (compare_ff(it_kb->pos, cpos, 1e-3f)) {
- return kb;
- }
- }
- }
- if (do_force || (key->type != KEY_RELATIVE)) {
- kb->pos = cpos;
- BKE_key_sort(key);
- }
-
- return kb;
+ KeyBlock *kb = BKE_keyblock_add(key, name);
+ const float cpos = key->ctime / 100.0f;
+
+ /* In case of absolute keys, there is no point in adding more than one key with the same pos.
+ * Hence only set new keybloc pos to current time if none previous one already use it.
+ * Now at least people just adding absolute keys without touching to ctime
+ * won't have to systematically use retiming func (and have ordering issues, too). See T39897.
+ */
+ if (!do_force && (key->type != KEY_RELATIVE)) {
+ KeyBlock *it_kb;
+ for (it_kb = key->block.first; it_kb; it_kb = it_kb->next) {
+ /* Use epsilon to avoid floating point precision issues.
+ * 1e-3 because the position is stored as frame * 1e-2. */
+ if (compare_ff(it_kb->pos, cpos, 1e-3f)) {
+ return kb;
+ }
+ }
+ }
+ if (do_force || (key->type != KEY_RELATIVE)) {
+ kb->pos = cpos;
+ BKE_key_sort(key);
+ }
+
+ return kb;
}
/* only the active keyblock */
KeyBlock *BKE_keyblock_from_object(Object *ob)
{
- Key *key = BKE_key_from_object(ob);
+ Key *key = BKE_key_from_object(ob);
- if (key) {
- KeyBlock *kb = BLI_findlink(&key->block, ob->shapenr - 1);
- return kb;
- }
+ if (key) {
+ KeyBlock *kb = BLI_findlink(&key->block, ob->shapenr - 1);
+ return kb;
+ }
- return NULL;
+ return NULL;
}
KeyBlock *BKE_keyblock_from_object_reference(Object *ob)
{
- Key *key = BKE_key_from_object(ob);
+ Key *key = BKE_key_from_object(ob);
- if (key)
- return key->refkey;
+ if (key)
+ return key->refkey;
- return NULL;
+ return NULL;
}
/* get the appropriate KeyBlock given an index */
KeyBlock *BKE_keyblock_from_key(Key *key, int index)
{
- KeyBlock *kb;
- int i;
+ KeyBlock *kb;
+ int i;
- if (key) {
- kb = key->block.first;
+ if (key) {
+ kb = key->block.first;
- for (i = 1; i < key->totkey; i++) {
- kb = kb->next;
+ for (i = 1; i < key->totkey; i++) {
+ kb = kb->next;
- if (index == i)
- return kb;
- }
- }
+ if (index == i)
+ return kb;
+ }
+ }
- return NULL;
+ return NULL;
}
/* get the appropriate KeyBlock given a name to search for */
KeyBlock *BKE_keyblock_find_name(Key *key, const char name[])
{
- return BLI_findstring(&key->block, name, offsetof(KeyBlock, name));
+ return BLI_findstring(&key->block, name, offsetof(KeyBlock, name));
}
/**
@@ -1566,13 +1664,13 @@ KeyBlock *BKE_keyblock_find_name(Key *key, const char name[])
*/
void BKE_keyblock_copy_settings(KeyBlock *kb_dst, const KeyBlock *kb_src)
{
- kb_dst->pos = kb_src->pos;
- kb_dst->curval = kb_src->curval;
- kb_dst->type = kb_src->type;
- kb_dst->relative = kb_src->relative;
- BLI_strncpy(kb_dst->vgroup, kb_src->vgroup, sizeof(kb_dst->vgroup));
- kb_dst->slidermin = kb_src->slidermin;
- kb_dst->slidermax = kb_src->slidermax;
+ kb_dst->pos = kb_src->pos;
+ kb_dst->curval = kb_src->curval;
+ kb_dst->type = kb_src->type;
+ kb_dst->relative = kb_src->relative;
+ BLI_strncpy(kb_dst->vgroup, kb_src->vgroup, sizeof(kb_dst->vgroup));
+ kb_dst->slidermin = kb_src->slidermin;
+ kb_dst->slidermax = kb_src->slidermax;
}
/* Get RNA-Path for 'value' setting of the given ShapeKey
@@ -1580,229 +1678,236 @@ void BKE_keyblock_copy_settings(KeyBlock *kb_dst, const KeyBlock *kb_src)
*/
char *BKE_keyblock_curval_rnapath_get(Key *key, KeyBlock *kb)
{
- PointerRNA ptr;
- PropertyRNA *prop;
+ PointerRNA ptr;
+ PropertyRNA *prop;
- /* sanity checks */
- if (ELEM(NULL, key, kb))
- return NULL;
+ /* sanity checks */
+ if (ELEM(NULL, key, kb))
+ return NULL;
- /* create the RNA pointer */
- RNA_pointer_create(&key->id, &RNA_ShapeKey, kb, &ptr);
- /* get pointer to the property too */
- prop = RNA_struct_find_property(&ptr, "value");
+ /* create the RNA pointer */
+ RNA_pointer_create(&key->id, &RNA_ShapeKey, kb, &ptr);
+ /* get pointer to the property too */
+ prop = RNA_struct_find_property(&ptr, "value");
- /* return the path */
- return RNA_path_from_ID_to_property(&ptr, prop);
+ /* return the path */
+ return RNA_path_from_ID_to_property(&ptr, prop);
}
-
/* conversion functions */
/************************* Lattice ************************/
void BKE_keyblock_update_from_lattice(Lattice *lt, KeyBlock *kb)
{
- BPoint *bp;
- float (*fp)[3];
- int a, tot;
+ BPoint *bp;
+ float(*fp)[3];
+ int a, tot;
- BLI_assert(kb->totelem == lt->pntsu * lt->pntsv * lt->pntsw);
+ BLI_assert(kb->totelem == lt->pntsu * lt->pntsv * lt->pntsw);
- tot = kb->totelem;
- if (tot == 0) return;
+ tot = kb->totelem;
+ if (tot == 0)
+ return;
- bp = lt->def;
- fp = kb->data;
- for (a = 0; a < kb->totelem; a++, fp++, bp++) {
- copy_v3_v3(*fp, bp->vec);
- }
+ bp = lt->def;
+ fp = kb->data;
+ for (a = 0; a < kb->totelem; a++, fp++, bp++) {
+ copy_v3_v3(*fp, bp->vec);
+ }
}
void BKE_keyblock_convert_from_lattice(Lattice *lt, KeyBlock *kb)
{
- int tot;
+ int tot;
- tot = lt->pntsu * lt->pntsv * lt->pntsw;
- if (tot == 0) return;
+ tot = lt->pntsu * lt->pntsv * lt->pntsw;
+ if (tot == 0)
+ return;
- MEM_SAFE_FREE(kb->data);
+ MEM_SAFE_FREE(kb->data);
- kb->data = MEM_mallocN(lt->key->elemsize * tot, __func__);
- kb->totelem = tot;
+ kb->data = MEM_mallocN(lt->key->elemsize * tot, __func__);
+ kb->totelem = tot;
- BKE_keyblock_update_from_lattice(lt, kb);
+ BKE_keyblock_update_from_lattice(lt, kb);
}
void BKE_keyblock_convert_to_lattice(KeyBlock *kb, Lattice *lt)
{
- BPoint *bp;
- const float (*fp)[3];
- int a, tot;
+ BPoint *bp;
+ const float(*fp)[3];
+ int a, tot;
- bp = lt->def;
- fp = kb->data;
+ bp = lt->def;
+ fp = kb->data;
- tot = lt->pntsu * lt->pntsv * lt->pntsw;
- tot = min_ii(kb->totelem, tot);
+ tot = lt->pntsu * lt->pntsv * lt->pntsw;
+ tot = min_ii(kb->totelem, tot);
- for (a = 0; a < tot; a++, fp++, bp++) {
- copy_v3_v3(bp->vec, *fp);
- }
+ for (a = 0; a < tot; a++, fp++, bp++) {
+ copy_v3_v3(bp->vec, *fp);
+ }
}
/************************* Curve ************************/
int BKE_keyblock_curve_element_count(ListBase *nurb)
{
- Nurb *nu;
- int tot = 0;
-
- nu = nurb->first;
- while (nu) {
- if (nu->bezt)
- tot += KEYELEM_ELEM_LEN_BEZTRIPLE * nu->pntsu;
- else if (nu->bp)
- tot += KEYELEM_ELEM_LEN_BPOINT * nu->pntsu * nu->pntsv;
-
- nu = nu->next;
- }
- return tot;
+ Nurb *nu;
+ int tot = 0;
+
+ nu = nurb->first;
+ while (nu) {
+ if (nu->bezt)
+ tot += KEYELEM_ELEM_LEN_BEZTRIPLE * nu->pntsu;
+ else if (nu->bp)
+ tot += KEYELEM_ELEM_LEN_BPOINT * nu->pntsu * nu->pntsv;
+
+ nu = nu->next;
+ }
+ return tot;
}
void BKE_keyblock_update_from_curve(Curve *UNUSED(cu), KeyBlock *kb, ListBase *nurb)
{
- Nurb *nu;
- BezTriple *bezt;
- BPoint *bp;
- float *fp;
- int a, tot;
-
- /* count */
- BLI_assert(BKE_keyblock_curve_element_count(nurb) == kb->totelem);
-
- tot = kb->totelem;
- if (tot == 0) return;
-
- fp = kb->data;
- for (nu = nurb->first; nu; nu = nu->next) {
- if (nu->bezt) {
- for (a = nu->pntsu, bezt = nu->bezt; a; a--, bezt++) {
- for (int i = 0; i < 3; i++) {
- copy_v3_v3(&fp[i * 3], bezt->vec[i]);
- }
- fp[9] = bezt->tilt;
- fp[10] = bezt->radius;
- fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
- }
- }
- else {
- for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a; a--, bp++) {
- copy_v3_v3(fp, bp->vec);
- fp[3] = bp->tilt;
- fp[4] = bp->radius;
- fp += KEYELEM_FLOAT_LEN_BPOINT;
- }
- }
- }
+ Nurb *nu;
+ BezTriple *bezt;
+ BPoint *bp;
+ float *fp;
+ int a, tot;
+
+ /* count */
+ BLI_assert(BKE_keyblock_curve_element_count(nurb) == kb->totelem);
+
+ tot = kb->totelem;
+ if (tot == 0)
+ return;
+
+ fp = kb->data;
+ for (nu = nurb->first; nu; nu = nu->next) {
+ if (nu->bezt) {
+ for (a = nu->pntsu, bezt = nu->bezt; a; a--, bezt++) {
+ for (int i = 0; i < 3; i++) {
+ copy_v3_v3(&fp[i * 3], bezt->vec[i]);
+ }
+ fp[9] = bezt->tilt;
+ fp[10] = bezt->radius;
+ fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
+ }
+ }
+ else {
+ for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a; a--, bp++) {
+ copy_v3_v3(fp, bp->vec);
+ fp[3] = bp->tilt;
+ fp[4] = bp->radius;
+ fp += KEYELEM_FLOAT_LEN_BPOINT;
+ }
+ }
+ }
}
void BKE_keyblock_convert_from_curve(Curve *cu, KeyBlock *kb, ListBase *nurb)
{
- int tot;
+ int tot;
- /* count */
- tot = BKE_keyblock_curve_element_count(nurb);
- if (tot == 0) return;
+ /* count */
+ tot = BKE_keyblock_curve_element_count(nurb);
+ if (tot == 0)
+ return;
- MEM_SAFE_FREE(kb->data);
+ MEM_SAFE_FREE(kb->data);
- kb->data = MEM_mallocN(cu->key->elemsize * tot, __func__);
- kb->totelem = tot;
+ kb->data = MEM_mallocN(cu->key->elemsize * tot, __func__);
+ kb->totelem = tot;
- BKE_keyblock_update_from_curve(cu, kb, nurb);
+ BKE_keyblock_update_from_curve(cu, kb, nurb);
}
void BKE_keyblock_convert_to_curve(KeyBlock *kb, Curve *UNUSED(cu), ListBase *nurb)
{
- Nurb *nu;
- BezTriple *bezt;
- BPoint *bp;
- const float *fp;
- int a, tot;
-
- tot = BKE_keyblock_curve_element_count(nurb);
- tot = min_ii(kb->totelem, tot);
-
- fp = kb->data;
- for (nu = nurb->first; nu && tot > 0; nu = nu->next) {
- if (nu->bezt) {
- for (a = nu->pntsu, bezt = nu->bezt; a && (tot -= KEYELEM_ELEM_LEN_BEZTRIPLE) >= 0; a--, bezt++) {
- for (int i = 0; i < 3; i++) {
- copy_v3_v3(bezt->vec[i], &fp[i * 3]);
- }
- bezt->tilt = fp[9];
- bezt->radius = fp[10];
- fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
- }
- }
- else {
- for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a && (tot -= KEYELEM_ELEM_LEN_BPOINT) >= 0; a--, bp++) {
- copy_v3_v3(bp->vec, fp);
- bp->tilt = fp[3];
- bp->radius = fp[4];
- fp += KEYELEM_FLOAT_LEN_BPOINT;
- }
- }
- }
+ Nurb *nu;
+ BezTriple *bezt;
+ BPoint *bp;
+ const float *fp;
+ int a, tot;
+
+ tot = BKE_keyblock_curve_element_count(nurb);
+ tot = min_ii(kb->totelem, tot);
+
+ fp = kb->data;
+ for (nu = nurb->first; nu && tot > 0; nu = nu->next) {
+ if (nu->bezt) {
+ for (a = nu->pntsu, bezt = nu->bezt; a && (tot -= KEYELEM_ELEM_LEN_BEZTRIPLE) >= 0;
+ a--, bezt++) {
+ for (int i = 0; i < 3; i++) {
+ copy_v3_v3(bezt->vec[i], &fp[i * 3]);
+ }
+ bezt->tilt = fp[9];
+ bezt->radius = fp[10];
+ fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
+ }
+ }
+ else {
+ for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a && (tot -= KEYELEM_ELEM_LEN_BPOINT) >= 0;
+ a--, bp++) {
+ copy_v3_v3(bp->vec, fp);
+ bp->tilt = fp[3];
+ bp->radius = fp[4];
+ fp += KEYELEM_FLOAT_LEN_BPOINT;
+ }
+ }
+ }
}
/************************* Mesh ************************/
void BKE_keyblock_update_from_mesh(Mesh *me, KeyBlock *kb)
{
- MVert *mvert;
- float (*fp)[3];
- int a, tot;
+ MVert *mvert;
+ float(*fp)[3];
+ int a, tot;
- BLI_assert(me->totvert == kb->totelem);
+ BLI_assert(me->totvert == kb->totelem);
- tot = me->totvert;
- if (tot == 0) return;
+ tot = me->totvert;
+ if (tot == 0)
+ return;
- mvert = me->mvert;
- fp = kb->data;
- for (a = 0; a < tot; a++, fp++, mvert++) {
- copy_v3_v3(*fp, mvert->co);
- }
+ mvert = me->mvert;
+ fp = kb->data;
+ for (a = 0; a < tot; a++, fp++, mvert++) {
+ copy_v3_v3(*fp, mvert->co);
+ }
}
void BKE_keyblock_convert_from_mesh(Mesh *me, Key *key, KeyBlock *kb)
{
- const int len = me->totvert;
+ const int len = me->totvert;
- if (me->totvert == 0) return;
+ if (me->totvert == 0)
+ return;
- MEM_SAFE_FREE(kb->data);
+ MEM_SAFE_FREE(kb->data);
- kb->data = MEM_malloc_arrayN((size_t)len, (size_t)key->elemsize, __func__);
- kb->totelem = len;
+ kb->data = MEM_malloc_arrayN((size_t)len, (size_t)key->elemsize, __func__);
+ kb->totelem = len;
- BKE_keyblock_update_from_mesh(me, kb);
+ BKE_keyblock_update_from_mesh(me, kb);
}
void BKE_keyblock_convert_to_mesh(KeyBlock *kb, Mesh *me)
{
- MVert *mvert;
- const float (*fp)[3];
- int a, tot;
+ MVert *mvert;
+ const float(*fp)[3];
+ int a, tot;
- mvert = me->mvert;
- fp = kb->data;
+ mvert = me->mvert;
+ fp = kb->data;
- tot = min_ii(kb->totelem, me->totvert);
+ tot = min_ii(kb->totelem, me->totvert);
- for (a = 0; a < tot; a++, fp++, mvert++) {
- copy_v3_v3(mvert->co, *fp);
- }
+ for (a = 0; a < tot; a++, fp++, mvert++) {
+ copy_v3_v3(mvert->co, *fp);
+ }
}
/**
@@ -1814,238 +1919,260 @@ void BKE_keyblock_convert_to_mesh(KeyBlock *kb, Mesh *me)
* \param r_polynors: if non-NULL, an array of vectors, same length as number of polygons.
* \param r_loopnors: if non-NULL, an array of vectors, same length as number of loops.
*/
-void BKE_keyblock_mesh_calc_normals(
- struct KeyBlock *kb, struct Mesh *mesh,
- float (*r_vertnors)[3], float (*r_polynors)[3], float (*r_loopnors)[3])
+void BKE_keyblock_mesh_calc_normals(struct KeyBlock *kb,
+ struct Mesh *mesh,
+ float (*r_vertnors)[3],
+ float (*r_polynors)[3],
+ float (*r_loopnors)[3])
{
- /* We use a temp, shallow copy of mesh to work. */
- Mesh me;
- bool free_polynors = false;
-
- if (r_vertnors == NULL && r_polynors == NULL && r_loopnors == NULL) {
- return;
- }
-
- me = *mesh;
- me.mvert = MEM_dupallocN(mesh->mvert);
- CustomData_reset(&me.vdata);
- CustomData_reset(&me.edata);
- CustomData_reset(&me.pdata);
- CustomData_reset(&me.ldata);
- CustomData_reset(&me.fdata);
-
- BKE_keyblock_convert_to_mesh(kb, &me);
-
- if (r_polynors == NULL && r_loopnors != NULL) {
- r_polynors = MEM_mallocN(sizeof(float[3]) * me.totpoly, __func__);
- free_polynors = true;
- }
- BKE_mesh_calc_normals_poly(
- me.mvert, r_vertnors, me.totvert, me.mloop, me.mpoly, me.totloop, me.totpoly, r_polynors, false);
-
- if (r_loopnors) {
- short (*clnors)[2] = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL); /* May be NULL. */
-
- BKE_mesh_normals_loop_split(
- me.mvert, me.totvert, me.medge, me.totedge,
- me.mloop, r_loopnors, me.totloop, me.mpoly, r_polynors, me.totpoly,
- (me.flag & ME_AUTOSMOOTH) != 0, me.smoothresh, NULL, clnors, NULL);
- }
-
- CustomData_free(&me.vdata, me.totvert);
- CustomData_free(&me.edata, me.totedge);
- CustomData_free(&me.pdata, me.totpoly);
- CustomData_free(&me.ldata, me.totloop);
- CustomData_free(&me.fdata, me.totface);
- MEM_freeN(me.mvert);
-
- if (free_polynors) {
- MEM_freeN(r_polynors);
- }
+ /* We use a temp, shallow copy of mesh to work. */
+ Mesh me;
+ bool free_polynors = false;
+
+ if (r_vertnors == NULL && r_polynors == NULL && r_loopnors == NULL) {
+ return;
+ }
+
+ me = *mesh;
+ me.mvert = MEM_dupallocN(mesh->mvert);
+ CustomData_reset(&me.vdata);
+ CustomData_reset(&me.edata);
+ CustomData_reset(&me.pdata);
+ CustomData_reset(&me.ldata);
+ CustomData_reset(&me.fdata);
+
+ BKE_keyblock_convert_to_mesh(kb, &me);
+
+ if (r_polynors == NULL && r_loopnors != NULL) {
+ r_polynors = MEM_mallocN(sizeof(float[3]) * me.totpoly, __func__);
+ free_polynors = true;
+ }
+ BKE_mesh_calc_normals_poly(me.mvert,
+ r_vertnors,
+ me.totvert,
+ me.mloop,
+ me.mpoly,
+ me.totloop,
+ me.totpoly,
+ r_polynors,
+ false);
+
+ if (r_loopnors) {
+ short(*clnors)[2] = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL); /* May be NULL. */
+
+ BKE_mesh_normals_loop_split(me.mvert,
+ me.totvert,
+ me.medge,
+ me.totedge,
+ me.mloop,
+ r_loopnors,
+ me.totloop,
+ me.mpoly,
+ r_polynors,
+ me.totpoly,
+ (me.flag & ME_AUTOSMOOTH) != 0,
+ me.smoothresh,
+ NULL,
+ clnors,
+ NULL);
+ }
+
+ CustomData_free(&me.vdata, me.totvert);
+ CustomData_free(&me.edata, me.totedge);
+ CustomData_free(&me.pdata, me.totpoly);
+ CustomData_free(&me.ldata, me.totloop);
+ CustomData_free(&me.fdata, me.totface);
+ MEM_freeN(me.mvert);
+
+ if (free_polynors) {
+ MEM_freeN(r_polynors);
+ }
}
-
/************************* raw coords ************************/
void BKE_keyblock_update_from_vertcos(Object *ob, KeyBlock *kb, float (*vertCos)[3])
{
- float (*co)[3] = vertCos;
- float *fp = kb->data;
- int tot, a;
+ float(*co)[3] = vertCos;
+ float *fp = kb->data;
+ int tot, a;
#ifndef NDEBUG
- if (ob->type == OB_LATTICE) {
- Lattice *lt = ob->data;
- BLI_assert((lt->pntsu * lt->pntsv * lt->pntsw) == kb->totelem);
- }
- else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
- Curve *cu = ob->data;
- BLI_assert(BKE_keyblock_curve_element_count(&cu->nurb) == kb->totelem);
- }
- else if (ob->type == OB_MESH) {
- Mesh *me = ob->data;
- BLI_assert(me->totvert == kb->totelem);
- }
- else {
- BLI_assert(0 == kb->totelem);
- }
+ if (ob->type == OB_LATTICE) {
+ Lattice *lt = ob->data;
+ BLI_assert((lt->pntsu * lt->pntsv * lt->pntsw) == kb->totelem);
+ }
+ else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
+ Curve *cu = ob->data;
+ BLI_assert(BKE_keyblock_curve_element_count(&cu->nurb) == kb->totelem);
+ }
+ else if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+ BLI_assert(me->totvert == kb->totelem);
+ }
+ else {
+ BLI_assert(0 == kb->totelem);
+ }
#endif
- tot = kb->totelem;
- if (tot == 0) return;
-
- /* Copy coords to keyblock */
- if (ELEM(ob->type, OB_MESH, OB_LATTICE)) {
- for (a = 0; a < tot; a++, fp += 3, co++) {
- copy_v3_v3(fp, *co);
- }
- }
- else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
- Curve *cu = (Curve *)ob->data;
- Nurb *nu;
- BezTriple *bezt;
- BPoint *bp;
-
- for (nu = cu->nurb.first; nu; nu = nu->next) {
- if (nu->bezt) {
- for (a = nu->pntsu, bezt = nu->bezt; a; a--, bezt++) {
- for (int i = 0; i < 3; i++, co++) {
- copy_v3_v3(&fp[i * 3], *co);
- }
- fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
- }
- }
- else {
- for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a; a--, bp++, co++) {
- copy_v3_v3(fp, *co);
- fp += KEYELEM_FLOAT_LEN_BPOINT;
- }
- }
- }
- }
+ tot = kb->totelem;
+ if (tot == 0)
+ return;
+
+ /* Copy coords to keyblock */
+ if (ELEM(ob->type, OB_MESH, OB_LATTICE)) {
+ for (a = 0; a < tot; a++, fp += 3, co++) {
+ copy_v3_v3(fp, *co);
+ }
+ }
+ else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
+ Curve *cu = (Curve *)ob->data;
+ Nurb *nu;
+ BezTriple *bezt;
+ BPoint *bp;
+
+ for (nu = cu->nurb.first; nu; nu = nu->next) {
+ if (nu->bezt) {
+ for (a = nu->pntsu, bezt = nu->bezt; a; a--, bezt++) {
+ for (int i = 0; i < 3; i++, co++) {
+ copy_v3_v3(&fp[i * 3], *co);
+ }
+ fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
+ }
+ }
+ else {
+ for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a; a--, bp++, co++) {
+ copy_v3_v3(fp, *co);
+ fp += KEYELEM_FLOAT_LEN_BPOINT;
+ }
+ }
+ }
+ }
}
void BKE_keyblock_convert_from_vertcos(Object *ob, KeyBlock *kb, float (*vertCos)[3])
{
- int tot = 0, elemsize;
-
- MEM_SAFE_FREE(kb->data);
-
- /* Count of vertex coords in array */
- if (ob->type == OB_MESH) {
- Mesh *me = (Mesh *)ob->data;
- tot = me->totvert;
- elemsize = me->key->elemsize;
- }
- else if (ob->type == OB_LATTICE) {
- Lattice *lt = (Lattice *)ob->data;
- tot = lt->pntsu * lt->pntsv * lt->pntsw;
- elemsize = lt->key->elemsize;
- }
- else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
- Curve *cu = (Curve *)ob->data;
- elemsize = cu->key->elemsize;
- tot = BKE_keyblock_curve_element_count(&cu->nurb);
- }
-
- if (tot == 0) return;
-
- kb->data = MEM_mallocN(tot * elemsize, __func__);
-
- /* Copy coords to keyblock */
- BKE_keyblock_update_from_vertcos(ob, kb, vertCos);
+ int tot = 0, elemsize;
+
+ MEM_SAFE_FREE(kb->data);
+
+ /* Count of vertex coords in array */
+ if (ob->type == OB_MESH) {
+ Mesh *me = (Mesh *)ob->data;
+ tot = me->totvert;
+ elemsize = me->key->elemsize;
+ }
+ else if (ob->type == OB_LATTICE) {
+ Lattice *lt = (Lattice *)ob->data;
+ tot = lt->pntsu * lt->pntsv * lt->pntsw;
+ elemsize = lt->key->elemsize;
+ }
+ else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
+ Curve *cu = (Curve *)ob->data;
+ elemsize = cu->key->elemsize;
+ tot = BKE_keyblock_curve_element_count(&cu->nurb);
+ }
+
+ if (tot == 0)
+ return;
+
+ kb->data = MEM_mallocN(tot * elemsize, __func__);
+
+ /* Copy coords to keyblock */
+ BKE_keyblock_update_from_vertcos(ob, kb, vertCos);
}
float (*BKE_keyblock_convert_to_vertcos(Object *ob, KeyBlock *kb))[3]
{
- float (*vertCos)[3], (*co)[3];
- const float *fp = kb->data;
- int tot = 0, a;
-
- /* Count of vertex coords in array */
- if (ob->type == OB_MESH) {
- Mesh *me = (Mesh *)ob->data;
- tot = me->totvert;
- }
- else if (ob->type == OB_LATTICE) {
- Lattice *lt = (Lattice *)ob->data;
- tot = lt->pntsu * lt->pntsv * lt->pntsw;
- }
- else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
- Curve *cu = (Curve *)ob->data;
- tot = BKE_nurbList_verts_count(&cu->nurb);
- }
-
- if (tot == 0) return NULL;
-
- co = vertCos = MEM_mallocN(tot * sizeof(*vertCos), __func__);
-
- /* Copy coords to array */
- if (ELEM(ob->type, OB_MESH, OB_LATTICE)) {
- for (a = 0; a < tot; a++, fp += 3, co++) {
- copy_v3_v3(*co, fp);
- }
- }
- else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
- Curve *cu = (Curve *)ob->data;
- Nurb *nu;
- BezTriple *bezt;
- BPoint *bp;
-
- for (nu = cu->nurb.first; nu; nu = nu->next) {
- if (nu->bezt) {
- for (a = nu->pntsu, bezt = nu->bezt; a; a--, bezt++) {
- for (int i = 0; i < 3; i++, co++) {
- copy_v3_v3(*co, &fp[i * 3]);
- }
- fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
- }
- }
- else {
- for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a; a--, bp++, co++) {
- copy_v3_v3(*co, fp);
- fp += KEYELEM_FLOAT_LEN_BPOINT;
- }
- }
- }
- }
-
- return vertCos;
+ float(*vertCos)[3], (*co)[3];
+ const float *fp = kb->data;
+ int tot = 0, a;
+
+ /* Count of vertex coords in array */
+ if (ob->type == OB_MESH) {
+ Mesh *me = (Mesh *)ob->data;
+ tot = me->totvert;
+ }
+ else if (ob->type == OB_LATTICE) {
+ Lattice *lt = (Lattice *)ob->data;
+ tot = lt->pntsu * lt->pntsv * lt->pntsw;
+ }
+ else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
+ Curve *cu = (Curve *)ob->data;
+ tot = BKE_nurbList_verts_count(&cu->nurb);
+ }
+
+ if (tot == 0)
+ return NULL;
+
+ co = vertCos = MEM_mallocN(tot * sizeof(*vertCos), __func__);
+
+ /* Copy coords to array */
+ if (ELEM(ob->type, OB_MESH, OB_LATTICE)) {
+ for (a = 0; a < tot; a++, fp += 3, co++) {
+ copy_v3_v3(*co, fp);
+ }
+ }
+ else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
+ Curve *cu = (Curve *)ob->data;
+ Nurb *nu;
+ BezTriple *bezt;
+ BPoint *bp;
+
+ for (nu = cu->nurb.first; nu; nu = nu->next) {
+ if (nu->bezt) {
+ for (a = nu->pntsu, bezt = nu->bezt; a; a--, bezt++) {
+ for (int i = 0; i < 3; i++, co++) {
+ copy_v3_v3(*co, &fp[i * 3]);
+ }
+ fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
+ }
+ }
+ else {
+ for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a; a--, bp++, co++) {
+ copy_v3_v3(*co, fp);
+ fp += KEYELEM_FLOAT_LEN_BPOINT;
+ }
+ }
+ }
+ }
+
+ return vertCos;
}
/************************* raw coord offsets ************************/
void BKE_keyblock_update_from_offset(Object *ob, KeyBlock *kb, float (*ofs)[3])
{
- int a;
- float *fp = kb->data;
-
- if (ELEM(ob->type, OB_MESH, OB_LATTICE)) {
- for (a = 0; a < kb->totelem; a++, fp += 3, ofs++) {
- add_v3_v3(fp, *ofs);
- }
- }
- else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
- Curve *cu = (Curve *)ob->data;
- Nurb *nu;
- BezTriple *bezt;
- BPoint *bp;
-
- for (nu = cu->nurb.first; nu; nu = nu->next) {
- if (nu->bezt) {
- for (a = nu->pntsu, bezt = nu->bezt; a; a--, bezt++) {
- for (int i = 0; i < 3; i++, ofs++) {
- add_v3_v3(&fp[i * 3], *ofs);
- }
- fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
- }
- }
- else {
- for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a; a--, bp++, ofs++) {
- add_v3_v3(fp, *ofs);
- fp += KEYELEM_FLOAT_LEN_BPOINT;
- }
- }
- }
- }
+ int a;
+ float *fp = kb->data;
+
+ if (ELEM(ob->type, OB_MESH, OB_LATTICE)) {
+ for (a = 0; a < kb->totelem; a++, fp += 3, ofs++) {
+ add_v3_v3(fp, *ofs);
+ }
+ }
+ else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
+ Curve *cu = (Curve *)ob->data;
+ Nurb *nu;
+ BezTriple *bezt;
+ BPoint *bp;
+
+ for (nu = cu->nurb.first; nu; nu = nu->next) {
+ if (nu->bezt) {
+ for (a = nu->pntsu, bezt = nu->bezt; a; a--, bezt++) {
+ for (int i = 0; i < 3; i++, ofs++) {
+ add_v3_v3(&fp[i * 3], *ofs);
+ }
+ fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
+ }
+ }
+ else {
+ for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a; a--, bp++, ofs++) {
+ add_v3_v3(fp, *ofs);
+ fp += KEYELEM_FLOAT_LEN_BPOINT;
+ }
+ }
+ }
+ }
}
/* ==========================================================*/
@@ -2059,81 +2186,79 @@ void BKE_keyblock_update_from_offset(Object *ob, KeyBlock *kb, float (*ofs)[3])
*/
bool BKE_keyblock_move(Object *ob, int org_index, int new_index)
{
- Key *key = BKE_key_from_object(ob);
- KeyBlock *kb;
- const int act_index = ob->shapenr - 1;
- const int totkey = key->totkey;
- int i;
- bool rev, in_range = false;
-
- if (org_index < 0) {
- org_index = act_index;
- }
-
- CLAMP(new_index, 0, key->totkey - 1);
- CLAMP(org_index, 0, key->totkey - 1);
-
- if (new_index == org_index) {
- return false;
- }
-
- rev = ((new_index - org_index) < 0) ? true : false;
-
- /* We swap 'org' element with its previous/next neighbor (depending on direction of the move) repeatedly,
- * until we reach final position.
- * This allows us to only loop on the list once! */
- for (kb = (rev ? key->block.last : key->block.first), i = (rev ? totkey - 1 : 0);
- kb;
- kb = (rev ? kb->prev : kb->next), rev ? i-- : i++)
- {
- if (i == org_index) {
- in_range = true; /* Start list items swapping... */
- }
- else if (i == new_index) {
- in_range = false; /* End list items swapping. */
- }
-
- if (in_range) {
- KeyBlock *other_kb = rev ? kb->prev : kb->next;
-
- /* Swap with previous/next list item. */
- BLI_listbase_swaplinks(&key->block, kb, other_kb);
-
- /* Swap absolute positions. */
- SWAP(float, kb->pos, other_kb->pos);
-
- kb = other_kb;
- }
-
- /* Adjust relative indices, this has to be done on the whole list! */
- if (kb->relative == org_index) {
- kb->relative = new_index;
- }
- else if (kb->relative < org_index && kb->relative >= new_index) {
- /* remove after, insert before this index */
- kb->relative++;
- }
- else if (kb->relative > org_index && kb->relative <= new_index) {
- /* remove before, insert after this index */
- kb->relative--;
- }
- }
-
- /* Need to update active shape number if it's affected, same principle as for relative indices above. */
- if (org_index == act_index) {
- ob->shapenr = new_index + 1;
- }
- else if (act_index < org_index && act_index >= new_index) {
- ob->shapenr++;
- }
- else if (act_index > org_index && act_index <= new_index) {
- ob->shapenr--;
- }
-
- /* First key is always refkey, matches interface and BKE_key_sort */
- key->refkey = key->block.first;
-
- return true;
+ Key *key = BKE_key_from_object(ob);
+ KeyBlock *kb;
+ const int act_index = ob->shapenr - 1;
+ const int totkey = key->totkey;
+ int i;
+ bool rev, in_range = false;
+
+ if (org_index < 0) {
+ org_index = act_index;
+ }
+
+ CLAMP(new_index, 0, key->totkey - 1);
+ CLAMP(org_index, 0, key->totkey - 1);
+
+ if (new_index == org_index) {
+ return false;
+ }
+
+ rev = ((new_index - org_index) < 0) ? true : false;
+
+ /* We swap 'org' element with its previous/next neighbor (depending on direction of the move) repeatedly,
+ * until we reach final position.
+ * This allows us to only loop on the list once! */
+ for (kb = (rev ? key->block.last : key->block.first), i = (rev ? totkey - 1 : 0); kb;
+ kb = (rev ? kb->prev : kb->next), rev ? i-- : i++) {
+ if (i == org_index) {
+ in_range = true; /* Start list items swapping... */
+ }
+ else if (i == new_index) {
+ in_range = false; /* End list items swapping. */
+ }
+
+ if (in_range) {
+ KeyBlock *other_kb = rev ? kb->prev : kb->next;
+
+ /* Swap with previous/next list item. */
+ BLI_listbase_swaplinks(&key->block, kb, other_kb);
+
+ /* Swap absolute positions. */
+ SWAP(float, kb->pos, other_kb->pos);
+
+ kb = other_kb;
+ }
+
+ /* Adjust relative indices, this has to be done on the whole list! */
+ if (kb->relative == org_index) {
+ kb->relative = new_index;
+ }
+ else if (kb->relative < org_index && kb->relative >= new_index) {
+ /* remove after, insert before this index */
+ kb->relative++;
+ }
+ else if (kb->relative > org_index && kb->relative <= new_index) {
+ /* remove before, insert after this index */
+ kb->relative--;
+ }
+ }
+
+ /* Need to update active shape number if it's affected, same principle as for relative indices above. */
+ if (org_index == act_index) {
+ ob->shapenr = new_index + 1;
+ }
+ else if (act_index < org_index && act_index >= new_index) {
+ ob->shapenr++;
+ }
+ else if (act_index > org_index && act_index <= new_index) {
+ ob->shapenr--;
+ }
+
+ /* First key is always refkey, matches interface and BKE_key_sort */
+ key->refkey = key->block.first;
+
+ return true;
}
/**
@@ -2141,16 +2266,16 @@ bool BKE_keyblock_move(Object *ob, int org_index, int new_index)
*/
bool BKE_keyblock_is_basis(Key *key, const int index)
{
- KeyBlock *kb;
- int i;
-
- if (key->type == KEY_RELATIVE) {
- for (i = 0, kb = key->block.first; kb; i++, kb = kb->next) {
- if ((i != index) && (kb->relative == index)) {
- return true;
- }
- }
- }
-
- return false;
+ KeyBlock *kb;
+ int i;
+
+ if (key->type == KEY_RELATIVE) {
+ for (i = 0, kb = key->block.first; kb; i++, kb = kb->next) {
+ if ((i != index) && (kb->relative == index)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
}
diff --git a/source/blender/blenkernel/intern/keyconfig.c b/source/blender/blenkernel/intern/keyconfig.c
index 6a37a550bc0..c6f2727df08 100644
--- a/source/blender/blenkernel/intern/keyconfig.c
+++ b/source/blender/blenkernel/intern/keyconfig.c
@@ -32,12 +32,11 @@
#include "DNA_userdef_types.h"
#include "DNA_windowmanager_types.h"
-#include "BKE_keyconfig.h" /* own include */
+#include "BKE_keyconfig.h" /* own include */
#include "BKE_idprop.h"
#include "MEM_guardedalloc.h"
-
/* -------------------------------------------------------------------- */
/** \name Key-Config Preference (UserDef) API
*
@@ -46,18 +45,18 @@
wmKeyConfigPref *BKE_keyconfig_pref_ensure(UserDef *userdef, const char *kc_idname)
{
- wmKeyConfigPref *kpt = BLI_findstring(
- &userdef->user_keyconfig_prefs, kc_idname, offsetof(wmKeyConfigPref, idname));
- if (kpt == NULL) {
- kpt = MEM_callocN(sizeof(*kpt), __func__);
- STRNCPY(kpt->idname, kc_idname);
- BLI_addtail(&userdef->user_keyconfig_prefs, kpt);
- }
- if (kpt->prop == NULL) {
- IDPropertyTemplate val = {0};
- kpt->prop = IDP_New(IDP_GROUP, &val, kc_idname); /* name is unimportant */
- }
- return kpt;
+ wmKeyConfigPref *kpt = BLI_findstring(
+ &userdef->user_keyconfig_prefs, kc_idname, offsetof(wmKeyConfigPref, idname));
+ if (kpt == NULL) {
+ kpt = MEM_callocN(sizeof(*kpt), __func__);
+ STRNCPY(kpt->idname, kc_idname);
+ BLI_addtail(&userdef->user_keyconfig_prefs, kpt);
+ }
+ if (kpt->prop == NULL) {
+ IDPropertyTemplate val = {0};
+ kpt->prop = IDP_New(IDP_GROUP, &val, kc_idname); /* name is unimportant */
+ }
+ return kpt;
}
/** \} */
@@ -70,64 +69,65 @@ wmKeyConfigPref *BKE_keyconfig_pref_ensure(UserDef *userdef, const char *kc_idna
static GHash *global_keyconfigpreftype_hash = NULL;
-
wmKeyConfigPrefType_Runtime *BKE_keyconfig_pref_type_find(const char *idname, bool quiet)
{
- if (idname[0]) {
- wmKeyConfigPrefType_Runtime *kpt_rt;
-
- kpt_rt = BLI_ghash_lookup(global_keyconfigpreftype_hash, idname);
- if (kpt_rt) {
- return kpt_rt;
- }
-
- if (!quiet) {
- printf("search for unknown keyconfig-pref '%s'\n", idname);
- }
- }
- else {
- if (!quiet) {
- printf("search for empty keyconfig-pref\n");
- }
- }
-
- return NULL;
+ if (idname[0]) {
+ wmKeyConfigPrefType_Runtime *kpt_rt;
+
+ kpt_rt = BLI_ghash_lookup(global_keyconfigpreftype_hash, idname);
+ if (kpt_rt) {
+ return kpt_rt;
+ }
+
+ if (!quiet) {
+ printf("search for unknown keyconfig-pref '%s'\n", idname);
+ }
+ }
+ else {
+ if (!quiet) {
+ printf("search for empty keyconfig-pref\n");
+ }
+ }
+
+ return NULL;
}
void BKE_keyconfig_pref_type_add(wmKeyConfigPrefType_Runtime *kpt_rt)
{
- BLI_ghash_insert(global_keyconfigpreftype_hash, kpt_rt->idname, kpt_rt);
+ BLI_ghash_insert(global_keyconfigpreftype_hash, kpt_rt->idname, kpt_rt);
}
void BKE_keyconfig_pref_type_remove(const wmKeyConfigPrefType_Runtime *kpt_rt)
{
- BLI_ghash_remove(global_keyconfigpreftype_hash, kpt_rt->idname, NULL, MEM_freeN);
+ BLI_ghash_remove(global_keyconfigpreftype_hash, kpt_rt->idname, NULL, MEM_freeN);
}
void BKE_keyconfig_pref_type_init(void)
{
- BLI_assert(global_keyconfigpreftype_hash == NULL);
- global_keyconfigpreftype_hash = BLI_ghash_str_new(__func__);
+ BLI_assert(global_keyconfigpreftype_hash == NULL);
+ global_keyconfigpreftype_hash = BLI_ghash_str_new(__func__);
}
void BKE_keyconfig_pref_type_free(void)
{
- BLI_ghash_free(global_keyconfigpreftype_hash, NULL, MEM_freeN);
- global_keyconfigpreftype_hash = NULL;
+ BLI_ghash_free(global_keyconfigpreftype_hash, NULL, MEM_freeN);
+ global_keyconfigpreftype_hash = NULL;
}
/* Set select mouse, for versioning code. */
void BKE_keyconfig_pref_set_select_mouse(UserDef *userdef, int value, bool override)
{
- wmKeyConfigPref *kpt = BKE_keyconfig_pref_ensure(userdef, WM_KEYCONFIG_STR_DEFAULT);
- IDProperty *idprop = IDP_GetPropertyFromGroup(kpt->prop, "select_mouse");
- if (!idprop) {
- IDPropertyTemplate tmp = { .i = value, };
- IDP_AddToGroup(kpt->prop, IDP_New(IDP_INT, &tmp, "select_mouse"));
- }
- else if (override) {
- IDP_Int(idprop) = value;
- }
+ wmKeyConfigPref *kpt = BKE_keyconfig_pref_ensure(userdef, WM_KEYCONFIG_STR_DEFAULT);
+ IDProperty *idprop = IDP_GetPropertyFromGroup(kpt->prop, "select_mouse");
+ if (!idprop) {
+ IDPropertyTemplate tmp = {
+ .i = value,
+ };
+ IDP_AddToGroup(kpt->prop, IDP_New(IDP_INT, &tmp, "select_mouse"));
+ }
+ else if (override) {
+ IDP_Int(idprop) = value;
+ }
}
/** \} */
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index f8ccddbe691..d301405bdb4 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -57,211 +57,211 @@
#include "DEG_depsgraph_query.h"
-int BKE_lattice_index_from_uvw(Lattice *lt,
- const int u, const int v, const int w)
+int BKE_lattice_index_from_uvw(Lattice *lt, const int u, const int v, const int w)
{
- const int totu = lt->pntsu;
- const int totv = lt->pntsv;
+ const int totu = lt->pntsu;
+ const int totv = lt->pntsv;
- return (w * (totu * totv) + (v * totu) + u);
+ return (w * (totu * totv) + (v * totu) + u);
}
-void BKE_lattice_index_to_uvw(Lattice *lt, const int index,
- int *r_u, int *r_v, int *r_w)
+void BKE_lattice_index_to_uvw(Lattice *lt, const int index, int *r_u, int *r_v, int *r_w)
{
- const int totu = lt->pntsu;
- const int totv = lt->pntsv;
+ const int totu = lt->pntsu;
+ const int totv = lt->pntsv;
- *r_u = (index % totu);
- *r_v = (index / totu) % totv;
- *r_w = (index / (totu * totv));
+ *r_u = (index % totu);
+ *r_v = (index / totu) % totv;
+ *r_w = (index / (totu * totv));
}
-int BKE_lattice_index_flip(Lattice *lt, const int index,
- const bool flip_u, const bool flip_v, const bool flip_w)
+int BKE_lattice_index_flip(
+ Lattice *lt, const int index, const bool flip_u, const bool flip_v, const bool flip_w)
{
- int u, v, w;
+ int u, v, w;
- BKE_lattice_index_to_uvw(lt, index, &u, &v, &w);
+ BKE_lattice_index_to_uvw(lt, index, &u, &v, &w);
- if (flip_u) {
- u = (lt->pntsu - 1) - u;
- }
+ if (flip_u) {
+ u = (lt->pntsu - 1) - u;
+ }
- if (flip_v) {
- v = (lt->pntsv - 1) - v;
- }
+ if (flip_v) {
+ v = (lt->pntsv - 1) - v;
+ }
- if (flip_w) {
- w = (lt->pntsw - 1) - w;
- }
+ if (flip_w) {
+ w = (lt->pntsw - 1) - w;
+ }
- return BKE_lattice_index_from_uvw(lt, u, v, w);
+ return BKE_lattice_index_from_uvw(lt, u, v, w);
}
-void BKE_lattice_bitmap_from_flag(Lattice *lt, BLI_bitmap *bitmap, const short flag,
- const bool clear, const bool respecthide)
+void BKE_lattice_bitmap_from_flag(
+ Lattice *lt, BLI_bitmap *bitmap, const short flag, const bool clear, const bool respecthide)
{
- const unsigned int tot = lt->pntsu * lt->pntsv * lt->pntsw;
- unsigned int i;
- BPoint *bp;
-
- bp = lt->def;
- for (i = 0; i < tot; i++, bp++) {
- if ((bp->f1 & flag) && (!respecthide || !bp->hide)) {
- BLI_BITMAP_ENABLE(bitmap, i);
- }
- else {
- if (clear) {
- BLI_BITMAP_DISABLE(bitmap, i);
- }
- }
- }
-
+ const unsigned int tot = lt->pntsu * lt->pntsv * lt->pntsw;
+ unsigned int i;
+ BPoint *bp;
+
+ bp = lt->def;
+ for (i = 0; i < tot; i++, bp++) {
+ if ((bp->f1 & flag) && (!respecthide || !bp->hide)) {
+ BLI_BITMAP_ENABLE(bitmap, i);
+ }
+ else {
+ if (clear) {
+ BLI_BITMAP_DISABLE(bitmap, i);
+ }
+ }
+ }
}
void calc_lat_fudu(int flag, int res, float *r_fu, float *r_du)
{
- if (res == 1) {
- *r_fu = 0.0;
- *r_du = 0.0;
- }
- else if (flag & LT_GRID) {
- *r_fu = -0.5f * (res - 1);
- *r_du = 1.0f;
- }
- else {
- *r_fu = -1.0f;
- *r_du = 2.0f / (res - 1);
- }
+ if (res == 1) {
+ *r_fu = 0.0;
+ *r_du = 0.0;
+ }
+ else if (flag & LT_GRID) {
+ *r_fu = -0.5f * (res - 1);
+ *r_du = 1.0f;
+ }
+ else {
+ *r_fu = -1.0f;
+ *r_du = 2.0f / (res - 1);
+ }
}
void BKE_lattice_resize(Lattice *lt, int uNew, int vNew, int wNew, Object *ltOb)
{
- BPoint *bp;
- int i, u, v, w;
- float fu, fv, fw, uc, vc, wc, du = 0.0, dv = 0.0, dw = 0.0;
- float *co, (*vertexCos)[3] = NULL;
-
- /* vertex weight groups are just freed all for now */
- if (lt->dvert) {
- BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw);
- lt->dvert = NULL;
- }
-
- while (uNew * vNew * wNew > 32000) {
- if (uNew >= vNew && uNew >= wNew) uNew--;
- else if (vNew >= uNew && vNew >= wNew) vNew--;
- else wNew--;
- }
-
- vertexCos = MEM_mallocN(sizeof(*vertexCos) * uNew * vNew * wNew, "tmp_vcos");
-
- calc_lat_fudu(lt->flag, uNew, &fu, &du);
- calc_lat_fudu(lt->flag, vNew, &fv, &dv);
- calc_lat_fudu(lt->flag, wNew, &fw, &dw);
-
- /* If old size is different then resolution changed in interface,
- * try to do clever reinit of points. Pretty simply idea, we just
- * deform new verts by old lattice, but scaling them to match old
- * size first.
- */
- if (ltOb) {
- if (uNew != 1 && lt->pntsu != 1) {
- fu = lt->fu;
- du = (lt->pntsu - 1) * lt->du / (uNew - 1);
- }
-
- if (vNew != 1 && lt->pntsv != 1) {
- fv = lt->fv;
- dv = (lt->pntsv - 1) * lt->dv / (vNew - 1);
- }
-
- if (wNew != 1 && lt->pntsw != 1) {
- fw = lt->fw;
- dw = (lt->pntsw - 1) * lt->dw / (wNew - 1);
- }
- }
-
- co = vertexCos[0];
- for (w = 0, wc = fw; w < wNew; w++, wc += dw) {
- for (v = 0, vc = fv; v < vNew; v++, vc += dv) {
- for (u = 0, uc = fu; u < uNew; u++, co += 3, uc += du) {
- co[0] = uc;
- co[1] = vc;
- co[2] = wc;
- }
- }
- }
-
- if (ltOb) {
- float mat[4][4];
- int typeu = lt->typeu, typev = lt->typev, typew = lt->typew;
-
- /* works best if we force to linear type (endpoints match) */
- lt->typeu = lt->typev = lt->typew = KEY_LINEAR;
-
- if (ltOb->runtime.curve_cache) {
- /* prevent using deformed locations */
- BKE_displist_free(&ltOb->runtime.curve_cache->disp);
- }
-
- copy_m4_m4(mat, ltOb->obmat);
- unit_m4(ltOb->obmat);
- lattice_deform_verts(ltOb, NULL, NULL, vertexCos, uNew * vNew * wNew, NULL, 1.0f);
- copy_m4_m4(ltOb->obmat, mat);
-
- lt->typeu = typeu;
- lt->typev = typev;
- lt->typew = typew;
- }
-
- lt->fu = fu;
- lt->fv = fv;
- lt->fw = fw;
- lt->du = du;
- lt->dv = dv;
- lt->dw = dw;
-
- lt->pntsu = uNew;
- lt->pntsv = vNew;
- lt->pntsw = wNew;
-
- lt->actbp = LT_ACTBP_NONE;
- MEM_freeN(lt->def);
- lt->def = MEM_callocN(lt->pntsu * lt->pntsv * lt->pntsw * sizeof(BPoint), "lattice bp");
-
- bp = lt->def;
-
- for (i = 0; i < lt->pntsu * lt->pntsv * lt->pntsw; i++, bp++) {
- copy_v3_v3(bp->vec, vertexCos[i]);
- }
-
- MEM_freeN(vertexCos);
+ BPoint *bp;
+ int i, u, v, w;
+ float fu, fv, fw, uc, vc, wc, du = 0.0, dv = 0.0, dw = 0.0;
+ float *co, (*vertexCos)[3] = NULL;
+
+ /* vertex weight groups are just freed all for now */
+ if (lt->dvert) {
+ BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw);
+ lt->dvert = NULL;
+ }
+
+ while (uNew * vNew * wNew > 32000) {
+ if (uNew >= vNew && uNew >= wNew)
+ uNew--;
+ else if (vNew >= uNew && vNew >= wNew)
+ vNew--;
+ else
+ wNew--;
+ }
+
+ vertexCos = MEM_mallocN(sizeof(*vertexCos) * uNew * vNew * wNew, "tmp_vcos");
+
+ calc_lat_fudu(lt->flag, uNew, &fu, &du);
+ calc_lat_fudu(lt->flag, vNew, &fv, &dv);
+ calc_lat_fudu(lt->flag, wNew, &fw, &dw);
+
+ /* If old size is different then resolution changed in interface,
+ * try to do clever reinit of points. Pretty simply idea, we just
+ * deform new verts by old lattice, but scaling them to match old
+ * size first.
+ */
+ if (ltOb) {
+ if (uNew != 1 && lt->pntsu != 1) {
+ fu = lt->fu;
+ du = (lt->pntsu - 1) * lt->du / (uNew - 1);
+ }
+
+ if (vNew != 1 && lt->pntsv != 1) {
+ fv = lt->fv;
+ dv = (lt->pntsv - 1) * lt->dv / (vNew - 1);
+ }
+
+ if (wNew != 1 && lt->pntsw != 1) {
+ fw = lt->fw;
+ dw = (lt->pntsw - 1) * lt->dw / (wNew - 1);
+ }
+ }
+
+ co = vertexCos[0];
+ for (w = 0, wc = fw; w < wNew; w++, wc += dw) {
+ for (v = 0, vc = fv; v < vNew; v++, vc += dv) {
+ for (u = 0, uc = fu; u < uNew; u++, co += 3, uc += du) {
+ co[0] = uc;
+ co[1] = vc;
+ co[2] = wc;
+ }
+ }
+ }
+
+ if (ltOb) {
+ float mat[4][4];
+ int typeu = lt->typeu, typev = lt->typev, typew = lt->typew;
+
+ /* works best if we force to linear type (endpoints match) */
+ lt->typeu = lt->typev = lt->typew = KEY_LINEAR;
+
+ if (ltOb->runtime.curve_cache) {
+ /* prevent using deformed locations */
+ BKE_displist_free(&ltOb->runtime.curve_cache->disp);
+ }
+
+ copy_m4_m4(mat, ltOb->obmat);
+ unit_m4(ltOb->obmat);
+ lattice_deform_verts(ltOb, NULL, NULL, vertexCos, uNew * vNew * wNew, NULL, 1.0f);
+ copy_m4_m4(ltOb->obmat, mat);
+
+ lt->typeu = typeu;
+ lt->typev = typev;
+ lt->typew = typew;
+ }
+
+ lt->fu = fu;
+ lt->fv = fv;
+ lt->fw = fw;
+ lt->du = du;
+ lt->dv = dv;
+ lt->dw = dw;
+
+ lt->pntsu = uNew;
+ lt->pntsv = vNew;
+ lt->pntsw = wNew;
+
+ lt->actbp = LT_ACTBP_NONE;
+ MEM_freeN(lt->def);
+ lt->def = MEM_callocN(lt->pntsu * lt->pntsv * lt->pntsw * sizeof(BPoint), "lattice bp");
+
+ bp = lt->def;
+
+ for (i = 0; i < lt->pntsu * lt->pntsv * lt->pntsw; i++, bp++) {
+ copy_v3_v3(bp->vec, vertexCos[i]);
+ }
+
+ MEM_freeN(vertexCos);
}
void BKE_lattice_init(Lattice *lt)
{
- BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(lt, id));
+ BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(lt, id));
- lt->flag = LT_GRID;
+ lt->flag = LT_GRID;
- lt->typeu = lt->typev = lt->typew = KEY_BSPLINE;
+ lt->typeu = lt->typev = lt->typew = KEY_BSPLINE;
- lt->def = MEM_callocN(sizeof(BPoint), "lattvert"); /* temporary */
- BKE_lattice_resize(lt, 2, 2, 2, NULL); /* creates a uniform lattice */
- lt->actbp = LT_ACTBP_NONE;
+ lt->def = MEM_callocN(sizeof(BPoint), "lattvert"); /* temporary */
+ BKE_lattice_resize(lt, 2, 2, 2, NULL); /* creates a uniform lattice */
+ lt->actbp = LT_ACTBP_NONE;
}
Lattice *BKE_lattice_add(Main *bmain, const char *name)
{
- Lattice *lt;
+ Lattice *lt;
- lt = BKE_libblock_alloc(bmain, ID_LT, name, 0);
+ lt = BKE_libblock_alloc(bmain, ID_LT, name, 0);
- BKE_lattice_init(lt);
+ BKE_lattice_init(lt);
- return lt;
+ return lt;
}
/**
@@ -274,317 +274,336 @@ Lattice *BKE_lattice_add(Main *bmain, const char *name)
*/
void BKE_lattice_copy_data(Main *bmain, Lattice *lt_dst, const Lattice *lt_src, const int flag)
{
- lt_dst->def = MEM_dupallocN(lt_src->def);
+ lt_dst->def = MEM_dupallocN(lt_src->def);
- if (lt_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) {
- BKE_id_copy_ex(bmain, &lt_src->key->id, (ID **)&lt_dst->key, flag);
- }
+ if (lt_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) {
+ BKE_id_copy_ex(bmain, &lt_src->key->id, (ID **)&lt_dst->key, flag);
+ }
- if (lt_src->dvert) {
- int tot = lt_src->pntsu * lt_src->pntsv * lt_src->pntsw;
- lt_dst->dvert = MEM_mallocN(sizeof(MDeformVert) * tot, "Lattice MDeformVert");
- BKE_defvert_array_copy(lt_dst->dvert, lt_src->dvert, tot);
- }
+ if (lt_src->dvert) {
+ int tot = lt_src->pntsu * lt_src->pntsv * lt_src->pntsw;
+ lt_dst->dvert = MEM_mallocN(sizeof(MDeformVert) * tot, "Lattice MDeformVert");
+ BKE_defvert_array_copy(lt_dst->dvert, lt_src->dvert, tot);
+ }
- lt_dst->editlatt = NULL;
+ lt_dst->editlatt = NULL;
}
Lattice *BKE_lattice_copy(Main *bmain, const Lattice *lt)
{
- Lattice *lt_copy;
- BKE_id_copy(bmain, &lt->id, (ID **)&lt_copy);
- return lt_copy;
+ Lattice *lt_copy;
+ BKE_id_copy(bmain, &lt->id, (ID **)&lt_copy);
+ return lt_copy;
}
- /** Free (or release) any data used by this lattice (does not free the lattice itself). */
+/** Free (or release) any data used by this lattice (does not free the lattice itself). */
void BKE_lattice_free(Lattice *lt)
{
- BKE_animdata_free(&lt->id, false);
-
- BKE_lattice_batch_cache_free(lt);
-
- MEM_SAFE_FREE(lt->def);
- if (lt->dvert) {
- BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw);
- lt->dvert = NULL;
- }
- if (lt->editlatt) {
- Lattice *editlt = lt->editlatt->latt;
-
- if (editlt->def)
- MEM_freeN(editlt->def);
- if (editlt->dvert)
- BKE_defvert_array_free(editlt->dvert, lt->pntsu * lt->pntsv * lt->pntsw);
-
- MEM_freeN(editlt);
- MEM_freeN(lt->editlatt);
- lt->editlatt = NULL;
- }
+ BKE_animdata_free(&lt->id, false);
+
+ BKE_lattice_batch_cache_free(lt);
+
+ MEM_SAFE_FREE(lt->def);
+ if (lt->dvert) {
+ BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw);
+ lt->dvert = NULL;
+ }
+ if (lt->editlatt) {
+ Lattice *editlt = lt->editlatt->latt;
+
+ if (editlt->def)
+ MEM_freeN(editlt->def);
+ if (editlt->dvert)
+ BKE_defvert_array_free(editlt->dvert, lt->pntsu * lt->pntsv * lt->pntsw);
+
+ MEM_freeN(editlt);
+ MEM_freeN(lt->editlatt);
+ lt->editlatt = NULL;
+ }
}
-
void BKE_lattice_make_local(Main *bmain, Lattice *lt, const bool lib_local)
{
- BKE_id_make_local_generic(bmain, &lt->id, true, lib_local);
+ BKE_id_make_local_generic(bmain, &lt->id, true, lib_local);
}
typedef struct LatticeDeformData {
- Object *object;
- float *latticedata;
- float latmat[4][4];
+ Object *object;
+ float *latticedata;
+ float latmat[4][4];
} LatticeDeformData;
LatticeDeformData *init_latt_deform(Object *oblatt, Object *ob)
{
- /* we make an array with all differences */
- Lattice *lt = oblatt->data;
- BPoint *bp;
- DispList *dl = oblatt->runtime.curve_cache ? BKE_displist_find(&oblatt->runtime.curve_cache->disp, DL_VERTS) : NULL;
- const float *co = dl ? dl->verts : NULL;
- float *fp, imat[4][4];
- float fu, fv, fw;
- int u, v, w;
- float *latticedata;
- float latmat[4][4];
- LatticeDeformData *lattice_deform_data;
-
- if (lt->editlatt) lt = lt->editlatt->latt;
- bp = lt->def;
-
- fp = latticedata = MEM_mallocN(sizeof(float) * 3 * lt->pntsu * lt->pntsv * lt->pntsw, "latticedata");
-
- /* for example with a particle system: (ob == NULL) */
- if (ob == NULL) {
- /* in deformspace, calc matrix */
- invert_m4_m4(latmat, oblatt->obmat);
-
- /* back: put in deform array */
- invert_m4_m4(imat, latmat);
- }
- else {
- /* in deformspace, calc matrix */
- invert_m4_m4(imat, oblatt->obmat);
- mul_m4_m4m4(latmat, imat, ob->obmat);
-
- /* back: put in deform array */
- invert_m4_m4(imat, latmat);
- }
-
- for (w = 0, fw = lt->fw; w < lt->pntsw; w++, fw += lt->dw) {
- for (v = 0, fv = lt->fv; v < lt->pntsv; v++, fv += lt->dv) {
- for (u = 0, fu = lt->fu; u < lt->pntsu; u++, bp++, co += 3, fp += 3, fu += lt->du) {
- if (dl) {
- fp[0] = co[0] - fu;
- fp[1] = co[1] - fv;
- fp[2] = co[2] - fw;
- }
- else {
- fp[0] = bp->vec[0] - fu;
- fp[1] = bp->vec[1] - fv;
- fp[2] = bp->vec[2] - fw;
- }
-
- mul_mat3_m4_v3(imat, fp);
- }
- }
- }
-
- lattice_deform_data = MEM_mallocN(sizeof(LatticeDeformData), "Lattice Deform Data");
- lattice_deform_data->latticedata = latticedata;
- lattice_deform_data->object = oblatt;
- copy_m4_m4(lattice_deform_data->latmat, latmat);
-
- return lattice_deform_data;
+ /* we make an array with all differences */
+ Lattice *lt = oblatt->data;
+ BPoint *bp;
+ DispList *dl = oblatt->runtime.curve_cache ?
+ BKE_displist_find(&oblatt->runtime.curve_cache->disp, DL_VERTS) :
+ NULL;
+ const float *co = dl ? dl->verts : NULL;
+ float *fp, imat[4][4];
+ float fu, fv, fw;
+ int u, v, w;
+ float *latticedata;
+ float latmat[4][4];
+ LatticeDeformData *lattice_deform_data;
+
+ if (lt->editlatt)
+ lt = lt->editlatt->latt;
+ bp = lt->def;
+
+ fp = latticedata = MEM_mallocN(sizeof(float) * 3 * lt->pntsu * lt->pntsv * lt->pntsw,
+ "latticedata");
+
+ /* for example with a particle system: (ob == NULL) */
+ if (ob == NULL) {
+ /* in deformspace, calc matrix */
+ invert_m4_m4(latmat, oblatt->obmat);
+
+ /* back: put in deform array */
+ invert_m4_m4(imat, latmat);
+ }
+ else {
+ /* in deformspace, calc matrix */
+ invert_m4_m4(imat, oblatt->obmat);
+ mul_m4_m4m4(latmat, imat, ob->obmat);
+
+ /* back: put in deform array */
+ invert_m4_m4(imat, latmat);
+ }
+
+ for (w = 0, fw = lt->fw; w < lt->pntsw; w++, fw += lt->dw) {
+ for (v = 0, fv = lt->fv; v < lt->pntsv; v++, fv += lt->dv) {
+ for (u = 0, fu = lt->fu; u < lt->pntsu; u++, bp++, co += 3, fp += 3, fu += lt->du) {
+ if (dl) {
+ fp[0] = co[0] - fu;
+ fp[1] = co[1] - fv;
+ fp[2] = co[2] - fw;
+ }
+ else {
+ fp[0] = bp->vec[0] - fu;
+ fp[1] = bp->vec[1] - fv;
+ fp[2] = bp->vec[2] - fw;
+ }
+
+ mul_mat3_m4_v3(imat, fp);
+ }
+ }
+ }
+
+ lattice_deform_data = MEM_mallocN(sizeof(LatticeDeformData), "Lattice Deform Data");
+ lattice_deform_data->latticedata = latticedata;
+ lattice_deform_data->object = oblatt;
+ copy_m4_m4(lattice_deform_data->latmat, latmat);
+
+ return lattice_deform_data;
}
void calc_latt_deform(LatticeDeformData *lattice_deform_data, float co[3], float weight)
{
- Object *ob = lattice_deform_data->object;
- Lattice *lt = ob->data;
- float u, v, w, tu[4], tv[4], tw[4];
- float vec[3];
- int idx_w, idx_v, idx_u;
- int ui, vi, wi, uu, vv, ww;
-
- /* vgroup influence */
- int defgrp_index = -1;
- float co_prev[3], weight_blend = 0.0f;
- MDeformVert *dvert = BKE_lattice_deform_verts_get(ob);
- float *__restrict latticedata = lattice_deform_data->latticedata;
-
-
- if (lt->editlatt) lt = lt->editlatt->latt;
- if (latticedata == NULL) return;
-
- if (lt->vgroup[0] && dvert) {
- defgrp_index = defgroup_name_index(ob, lt->vgroup);
- copy_v3_v3(co_prev, co);
- }
-
- /* co is in local coords, treat with latmat */
- mul_v3_m4v3(vec, lattice_deform_data->latmat, co);
-
- /* u v w coords */
-
- if (lt->pntsu > 1) {
- u = (vec[0] - lt->fu) / lt->du;
- ui = (int)floor(u);
- u -= ui;
- key_curve_position_weights(u, tu, lt->typeu);
- }
- else {
- tu[0] = tu[2] = tu[3] = 0.0; tu[1] = 1.0;
- ui = 0;
- }
-
- if (lt->pntsv > 1) {
- v = (vec[1] - lt->fv) / lt->dv;
- vi = (int)floor(v);
- v -= vi;
- key_curve_position_weights(v, tv, lt->typev);
- }
- else {
- tv[0] = tv[2] = tv[3] = 0.0; tv[1] = 1.0;
- vi = 0;
- }
-
- if (lt->pntsw > 1) {
- w = (vec[2] - lt->fw) / lt->dw;
- wi = (int)floor(w);
- w -= wi;
- key_curve_position_weights(w, tw, lt->typew);
- }
- else {
- tw[0] = tw[2] = tw[3] = 0.0; tw[1] = 1.0;
- wi = 0;
- }
-
- for (ww = wi - 1; ww <= wi + 2; ww++) {
- w = tw[ww - wi + 1];
-
- if (w != 0.0f) {
- if (ww > 0) {
- if (ww < lt->pntsw) idx_w = ww * lt->pntsu * lt->pntsv;
- else idx_w = (lt->pntsw - 1) * lt->pntsu * lt->pntsv;
- }
- else {
- idx_w = 0;
- }
-
- for (vv = vi - 1; vv <= vi + 2; vv++) {
- v = w * tv[vv - vi + 1];
-
- if (v != 0.0f) {
- if (vv > 0) {
- if (vv < lt->pntsv) idx_v = idx_w + vv * lt->pntsu;
- else idx_v = idx_w + (lt->pntsv - 1) * lt->pntsu;
- }
- else {
- idx_v = idx_w;
- }
-
- for (uu = ui - 1; uu <= ui + 2; uu++) {
- u = weight * v * tu[uu - ui + 1];
-
- if (u != 0.0f) {
- if (uu > 0) {
- if (uu < lt->pntsu) idx_u = idx_v + uu;
- else idx_u = idx_v + (lt->pntsu - 1);
- }
- else {
- idx_u = idx_v;
- }
-
- madd_v3_v3fl(co, &latticedata[idx_u * 3], u);
-
- if (defgrp_index != -1)
- weight_blend += (u * defvert_find_weight(dvert + idx_u, defgrp_index));
- }
- }
- }
- }
- }
- }
-
- if (defgrp_index != -1)
- interp_v3_v3v3(co, co_prev, co, weight_blend);
-
+ Object *ob = lattice_deform_data->object;
+ Lattice *lt = ob->data;
+ float u, v, w, tu[4], tv[4], tw[4];
+ float vec[3];
+ int idx_w, idx_v, idx_u;
+ int ui, vi, wi, uu, vv, ww;
+
+ /* vgroup influence */
+ int defgrp_index = -1;
+ float co_prev[3], weight_blend = 0.0f;
+ MDeformVert *dvert = BKE_lattice_deform_verts_get(ob);
+ float *__restrict latticedata = lattice_deform_data->latticedata;
+
+ if (lt->editlatt)
+ lt = lt->editlatt->latt;
+ if (latticedata == NULL)
+ return;
+
+ if (lt->vgroup[0] && dvert) {
+ defgrp_index = defgroup_name_index(ob, lt->vgroup);
+ copy_v3_v3(co_prev, co);
+ }
+
+ /* co is in local coords, treat with latmat */
+ mul_v3_m4v3(vec, lattice_deform_data->latmat, co);
+
+ /* u v w coords */
+
+ if (lt->pntsu > 1) {
+ u = (vec[0] - lt->fu) / lt->du;
+ ui = (int)floor(u);
+ u -= ui;
+ key_curve_position_weights(u, tu, lt->typeu);
+ }
+ else {
+ tu[0] = tu[2] = tu[3] = 0.0;
+ tu[1] = 1.0;
+ ui = 0;
+ }
+
+ if (lt->pntsv > 1) {
+ v = (vec[1] - lt->fv) / lt->dv;
+ vi = (int)floor(v);
+ v -= vi;
+ key_curve_position_weights(v, tv, lt->typev);
+ }
+ else {
+ tv[0] = tv[2] = tv[3] = 0.0;
+ tv[1] = 1.0;
+ vi = 0;
+ }
+
+ if (lt->pntsw > 1) {
+ w = (vec[2] - lt->fw) / lt->dw;
+ wi = (int)floor(w);
+ w -= wi;
+ key_curve_position_weights(w, tw, lt->typew);
+ }
+ else {
+ tw[0] = tw[2] = tw[3] = 0.0;
+ tw[1] = 1.0;
+ wi = 0;
+ }
+
+ for (ww = wi - 1; ww <= wi + 2; ww++) {
+ w = tw[ww - wi + 1];
+
+ if (w != 0.0f) {
+ if (ww > 0) {
+ if (ww < lt->pntsw)
+ idx_w = ww * lt->pntsu * lt->pntsv;
+ else
+ idx_w = (lt->pntsw - 1) * lt->pntsu * lt->pntsv;
+ }
+ else {
+ idx_w = 0;
+ }
+
+ for (vv = vi - 1; vv <= vi + 2; vv++) {
+ v = w * tv[vv - vi + 1];
+
+ if (v != 0.0f) {
+ if (vv > 0) {
+ if (vv < lt->pntsv)
+ idx_v = idx_w + vv * lt->pntsu;
+ else
+ idx_v = idx_w + (lt->pntsv - 1) * lt->pntsu;
+ }
+ else {
+ idx_v = idx_w;
+ }
+
+ for (uu = ui - 1; uu <= ui + 2; uu++) {
+ u = weight * v * tu[uu - ui + 1];
+
+ if (u != 0.0f) {
+ if (uu > 0) {
+ if (uu < lt->pntsu)
+ idx_u = idx_v + uu;
+ else
+ idx_u = idx_v + (lt->pntsu - 1);
+ }
+ else {
+ idx_u = idx_v;
+ }
+
+ madd_v3_v3fl(co, &latticedata[idx_u * 3], u);
+
+ if (defgrp_index != -1)
+ weight_blend += (u * defvert_find_weight(dvert + idx_u, defgrp_index));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (defgrp_index != -1)
+ interp_v3_v3v3(co, co_prev, co, weight_blend);
}
void end_latt_deform(LatticeDeformData *lattice_deform_data)
{
- if (lattice_deform_data->latticedata)
- MEM_freeN(lattice_deform_data->latticedata);
+ if (lattice_deform_data->latticedata)
+ MEM_freeN(lattice_deform_data->latticedata);
- MEM_freeN(lattice_deform_data);
+ MEM_freeN(lattice_deform_data);
}
/* calculations is in local space of deformed object
* so we store in latmat transform from path coord inside object
*/
typedef struct {
- float dmin[3], dmax[3];
- float curvespace[4][4], objectspace[4][4], objectspace3[3][3];
- int no_rot_axis;
+ float dmin[3], dmax[3];
+ float curvespace[4][4], objectspace[4][4], objectspace3[3][3];
+ int no_rot_axis;
} CurveDeform;
static void init_curve_deform(Object *par, Object *ob, CurveDeform *cd)
{
- invert_m4_m4(ob->imat, ob->obmat);
- mul_m4_m4m4(cd->objectspace, ob->imat, par->obmat);
- invert_m4_m4(cd->curvespace, cd->objectspace);
- copy_m3_m4(cd->objectspace3, cd->objectspace);
- cd->no_rot_axis = 0;
+ invert_m4_m4(ob->imat, ob->obmat);
+ mul_m4_m4m4(cd->objectspace, ob->imat, par->obmat);
+ invert_m4_m4(cd->curvespace, cd->objectspace);
+ copy_m3_m4(cd->objectspace3, cd->objectspace);
+ cd->no_rot_axis = 0;
}
/* this makes sure we can extend for non-cyclic.
*
* returns OK: 1/0
*/
-static bool where_on_path_deform(Object *ob, float ctime, float vec[4], float dir[3], float quat[4], float *radius)
+static bool where_on_path_deform(
+ Object *ob, float ctime, float vec[4], float dir[3], float quat[4], float *radius)
{
- BevList *bl;
- float ctime1;
- int cycl = 0;
-
- /* test for cyclic */
- bl = ob->runtime.curve_cache->bev.first;
- if (!bl->nr) return false;
- if (bl->poly > -1) cycl = 1;
-
- if (cycl == 0) {
- ctime1 = CLAMPIS(ctime, 0.0f, 1.0f);
- }
- else {
- ctime1 = ctime;
- }
-
- /* vec needs 4 items */
- if (where_on_path(ob, ctime1, vec, dir, quat, radius, NULL)) {
-
- if (cycl == 0) {
- Path *path = ob->runtime.curve_cache->path;
- float dvec[3];
-
- if (ctime < 0.0f) {
- sub_v3_v3v3(dvec, path->data[1].vec, path->data[0].vec);
- mul_v3_fl(dvec, ctime * (float)path->len);
- add_v3_v3(vec, dvec);
- if (quat) copy_qt_qt(quat, path->data[0].quat);
- if (radius) *radius = path->data[0].radius;
- }
- else if (ctime > 1.0f) {
- sub_v3_v3v3(dvec, path->data[path->len - 1].vec, path->data[path->len - 2].vec);
- mul_v3_fl(dvec, (ctime - 1.0f) * (float)path->len);
- add_v3_v3(vec, dvec);
- if (quat) copy_qt_qt(quat, path->data[path->len - 1].quat);
- if (radius) *radius = path->data[path->len - 1].radius;
- /* weight - not used but could be added */
- }
- }
- return true;
- }
- return false;
+ BevList *bl;
+ float ctime1;
+ int cycl = 0;
+
+ /* test for cyclic */
+ bl = ob->runtime.curve_cache->bev.first;
+ if (!bl->nr)
+ return false;
+ if (bl->poly > -1)
+ cycl = 1;
+
+ if (cycl == 0) {
+ ctime1 = CLAMPIS(ctime, 0.0f, 1.0f);
+ }
+ else {
+ ctime1 = ctime;
+ }
+
+ /* vec needs 4 items */
+ if (where_on_path(ob, ctime1, vec, dir, quat, radius, NULL)) {
+
+ if (cycl == 0) {
+ Path *path = ob->runtime.curve_cache->path;
+ float dvec[3];
+
+ if (ctime < 0.0f) {
+ sub_v3_v3v3(dvec, path->data[1].vec, path->data[0].vec);
+ mul_v3_fl(dvec, ctime * (float)path->len);
+ add_v3_v3(vec, dvec);
+ if (quat)
+ copy_qt_qt(quat, path->data[0].quat);
+ if (radius)
+ *radius = path->data[0].radius;
+ }
+ else if (ctime > 1.0f) {
+ sub_v3_v3v3(dvec, path->data[path->len - 1].vec, path->data[path->len - 2].vec);
+ mul_v3_fl(dvec, (ctime - 1.0f) * (float)path->len);
+ add_v3_v3(vec, dvec);
+ if (quat)
+ copy_qt_qt(quat, path->data[path->len - 1].quat);
+ if (radius)
+ *radius = path->data[path->len - 1].radius;
+ /* weight - not used but could be added */
+ }
+ }
+ return true;
+ }
+ return false;
}
/* for each point, rotate & translate to curve */
@@ -592,632 +611,654 @@ static bool where_on_path_deform(Object *ob, float ctime, float vec[4], float di
/* co: local coord, result local too */
/* returns quaternion for rotation, using cd->no_rot_axis */
/* axis is using another define!!! */
-static bool calc_curve_deform(Object *par, float co[3],
- const short axis, CurveDeform *cd, float r_quat[4])
+static bool calc_curve_deform(
+ Object *par, float co[3], const short axis, CurveDeform *cd, float r_quat[4])
{
- Curve *cu = par->data;
- float fac, loc[4], dir[3], new_quat[4], radius;
- short index;
- const bool is_neg_axis = (axis > 2);
-
- if (par->runtime.curve_cache == NULL) {
- /* Happens with a cyclic dependencies. */
- return false;
- }
-
- if (par->runtime.curve_cache->path == NULL) {
- return false; /* happens on append, cyclic dependencies and empty curves */
- }
-
- /* options */
- if (is_neg_axis) {
- index = axis - 3;
- if (cu->flag & CU_STRETCH)
- fac = -(co[index] - cd->dmax[index]) / (cd->dmax[index] - cd->dmin[index]);
- else
- fac = -(co[index] - cd->dmax[index]) / (par->runtime.curve_cache->path->totdist);
- }
- else {
- index = axis;
- if (cu->flag & CU_STRETCH) {
- fac = (co[index] - cd->dmin[index]) / (cd->dmax[index] - cd->dmin[index]);
- }
- else {
- if (LIKELY(par->runtime.curve_cache->path->totdist > FLT_EPSILON)) {
- fac = +(co[index] - cd->dmin[index]) / (par->runtime.curve_cache->path->totdist);
- }
- else {
- fac = 0.0f;
- }
- }
- }
-
- if (where_on_path_deform(par, fac, loc, dir, new_quat, &radius)) { /* returns OK */
- float quat[4], cent[3];
-
- if (cd->no_rot_axis) { /* set by caller */
-
- /* this is not exactly the same as 2.4x, since the axis is having rotation removed rather than
- * changing the axis before calculating the tilt but serves much the same purpose */
- float dir_flat[3] = {0, 0, 0}, q[4];
- copy_v3_v3(dir_flat, dir);
- dir_flat[cd->no_rot_axis - 1] = 0.0f;
-
- normalize_v3(dir);
- normalize_v3(dir_flat);
-
- rotation_between_vecs_to_quat(q, dir, dir_flat); /* Could this be done faster? */
-
- mul_qt_qtqt(new_quat, q, new_quat);
- }
-
-
- /* Logic for 'cent' orientation *
- *
- * The way 'co' is copied to 'cent' may seem to have no meaning, but it does.
- *
- * Use a curve modifier to stretch a cube out, color each side RGB, positive side light, negative dark.
- * view with X up (default), from the angle that you can see 3 faces RGB colors (light), anti-clockwise
- * Notice X,Y,Z Up all have light colors and each ordered CCW.
- *
- * Now for Neg Up XYZ, the colors are all dark, and ordered clockwise - Campbell
- *
- * note: moved functions into quat_apply_track/vec_apply_track
- * */
- copy_qt_qt(quat, new_quat);
- copy_v3_v3(cent, co);
-
- /* zero the axis which is not used,
- * the big block of text above now applies to these 3 lines */
- quat_apply_track(quat, axis, (axis == 0 || axis == 2) ? 1 : 0); /* up flag is a dummy, set so no rotation is done */
- vec_apply_track(cent, axis);
- cent[index] = 0.0f;
-
-
- /* scale if enabled */
- if (cu->flag & CU_PATH_RADIUS)
- mul_v3_fl(cent, radius);
-
- /* local rotation */
- normalize_qt(quat);
- mul_qt_v3(quat, cent);
-
- /* translation */
- add_v3_v3v3(co, cent, loc);
-
- if (r_quat)
- copy_qt_qt(r_quat, quat);
-
- return true;
- }
- return false;
+ Curve *cu = par->data;
+ float fac, loc[4], dir[3], new_quat[4], radius;
+ short index;
+ const bool is_neg_axis = (axis > 2);
+
+ if (par->runtime.curve_cache == NULL) {
+ /* Happens with a cyclic dependencies. */
+ return false;
+ }
+
+ if (par->runtime.curve_cache->path == NULL) {
+ return false; /* happens on append, cyclic dependencies and empty curves */
+ }
+
+ /* options */
+ if (is_neg_axis) {
+ index = axis - 3;
+ if (cu->flag & CU_STRETCH)
+ fac = -(co[index] - cd->dmax[index]) / (cd->dmax[index] - cd->dmin[index]);
+ else
+ fac = -(co[index] - cd->dmax[index]) / (par->runtime.curve_cache->path->totdist);
+ }
+ else {
+ index = axis;
+ if (cu->flag & CU_STRETCH) {
+ fac = (co[index] - cd->dmin[index]) / (cd->dmax[index] - cd->dmin[index]);
+ }
+ else {
+ if (LIKELY(par->runtime.curve_cache->path->totdist > FLT_EPSILON)) {
+ fac = +(co[index] - cd->dmin[index]) / (par->runtime.curve_cache->path->totdist);
+ }
+ else {
+ fac = 0.0f;
+ }
+ }
+ }
+
+ if (where_on_path_deform(par, fac, loc, dir, new_quat, &radius)) { /* returns OK */
+ float quat[4], cent[3];
+
+ if (cd->no_rot_axis) { /* set by caller */
+
+ /* this is not exactly the same as 2.4x, since the axis is having rotation removed rather than
+ * changing the axis before calculating the tilt but serves much the same purpose */
+ float dir_flat[3] = {0, 0, 0}, q[4];
+ copy_v3_v3(dir_flat, dir);
+ dir_flat[cd->no_rot_axis - 1] = 0.0f;
+
+ normalize_v3(dir);
+ normalize_v3(dir_flat);
+
+ rotation_between_vecs_to_quat(q, dir, dir_flat); /* Could this be done faster? */
+
+ mul_qt_qtqt(new_quat, q, new_quat);
+ }
+
+ /* Logic for 'cent' orientation *
+ *
+ * The way 'co' is copied to 'cent' may seem to have no meaning, but it does.
+ *
+ * Use a curve modifier to stretch a cube out, color each side RGB, positive side light, negative dark.
+ * view with X up (default), from the angle that you can see 3 faces RGB colors (light), anti-clockwise
+ * Notice X,Y,Z Up all have light colors and each ordered CCW.
+ *
+ * Now for Neg Up XYZ, the colors are all dark, and ordered clockwise - Campbell
+ *
+ * note: moved functions into quat_apply_track/vec_apply_track
+ * */
+ copy_qt_qt(quat, new_quat);
+ copy_v3_v3(cent, co);
+
+ /* zero the axis which is not used,
+ * the big block of text above now applies to these 3 lines */
+ quat_apply_track(
+ quat,
+ axis,
+ (axis == 0 || axis == 2) ? 1 : 0); /* up flag is a dummy, set so no rotation is done */
+ vec_apply_track(cent, axis);
+ cent[index] = 0.0f;
+
+ /* scale if enabled */
+ if (cu->flag & CU_PATH_RADIUS)
+ mul_v3_fl(cent, radius);
+
+ /* local rotation */
+ normalize_qt(quat);
+ mul_qt_v3(quat, cent);
+
+ /* translation */
+ add_v3_v3v3(co, cent, loc);
+
+ if (r_quat)
+ copy_qt_qt(r_quat, quat);
+
+ return true;
+ }
+ return false;
}
-void curve_deform_verts(
- Object *cuOb, Object *target, float (*vertexCos)[3],
- int numVerts, MDeformVert *dvert, const int defgrp_index, short defaxis)
+void curve_deform_verts(Object *cuOb,
+ Object *target,
+ float (*vertexCos)[3],
+ int numVerts,
+ MDeformVert *dvert,
+ const int defgrp_index,
+ short defaxis)
{
- Curve *cu;
- int a;
- CurveDeform cd;
- const bool is_neg_axis = (defaxis > 2);
-
- if (cuOb->type != OB_CURVE)
- return;
-
- cu = cuOb->data;
-
- init_curve_deform(cuOb, target, &cd);
-
- /* dummy bounds, keep if CU_DEFORM_BOUNDS_OFF is set */
- if (is_neg_axis == false) {
- cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = 0.0f;
- cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 1.0f;
- }
- else {
- /* negative, these bounds give a good rest position */
- cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = -1.0f;
- cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 0.0f;
- }
-
- if (dvert) {
- MDeformVert *dvert_iter;
- float vec[3];
-
- if (cu->flag & CU_DEFORM_BOUNDS_OFF) {
- for (a = 0, dvert_iter = dvert; a < numVerts; a++, dvert_iter++) {
- const float weight = defvert_find_weight(dvert_iter, defgrp_index);
-
- if (weight > 0.0f) {
- mul_m4_v3(cd.curvespace, vertexCos[a]);
- copy_v3_v3(vec, vertexCos[a]);
- calc_curve_deform(cuOb, vec, defaxis, &cd, NULL);
- interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight);
- mul_m4_v3(cd.objectspace, vertexCos[a]);
- }
- }
- }
- else {
- /* set mesh min/max bounds */
- INIT_MINMAX(cd.dmin, cd.dmax);
-
- for (a = 0, dvert_iter = dvert; a < numVerts; a++, dvert_iter++) {
- if (defvert_find_weight(dvert_iter, defgrp_index) > 0.0f) {
- mul_m4_v3(cd.curvespace, vertexCos[a]);
- minmax_v3v3_v3(cd.dmin, cd.dmax, vertexCos[a]);
- }
- }
-
- for (a = 0, dvert_iter = dvert; a < numVerts; a++, dvert_iter++) {
- const float weight = defvert_find_weight(dvert_iter, defgrp_index);
-
- if (weight > 0.0f) {
- /* already in 'cd.curvespace', prev for loop */
- copy_v3_v3(vec, vertexCos[a]);
- calc_curve_deform(cuOb, vec, defaxis, &cd, NULL);
- interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight);
- mul_m4_v3(cd.objectspace, vertexCos[a]);
- }
- }
- }
- }
- else {
- if (cu->flag & CU_DEFORM_BOUNDS_OFF) {
- for (a = 0; a < numVerts; a++) {
- mul_m4_v3(cd.curvespace, vertexCos[a]);
- calc_curve_deform(cuOb, vertexCos[a], defaxis, &cd, NULL);
- mul_m4_v3(cd.objectspace, vertexCos[a]);
- }
- }
- else {
- /* set mesh min max bounds */
- INIT_MINMAX(cd.dmin, cd.dmax);
-
- for (a = 0; a < numVerts; a++) {
- mul_m4_v3(cd.curvespace, vertexCos[a]);
- minmax_v3v3_v3(cd.dmin, cd.dmax, vertexCos[a]);
- }
-
- for (a = 0; a < numVerts; a++) {
- /* already in 'cd.curvespace', prev for loop */
- calc_curve_deform(cuOb, vertexCos[a], defaxis, &cd, NULL);
- mul_m4_v3(cd.objectspace, vertexCos[a]);
- }
- }
- }
+ Curve *cu;
+ int a;
+ CurveDeform cd;
+ const bool is_neg_axis = (defaxis > 2);
+
+ if (cuOb->type != OB_CURVE)
+ return;
+
+ cu = cuOb->data;
+
+ init_curve_deform(cuOb, target, &cd);
+
+ /* dummy bounds, keep if CU_DEFORM_BOUNDS_OFF is set */
+ if (is_neg_axis == false) {
+ cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = 0.0f;
+ cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 1.0f;
+ }
+ else {
+ /* negative, these bounds give a good rest position */
+ cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = -1.0f;
+ cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 0.0f;
+ }
+
+ if (dvert) {
+ MDeformVert *dvert_iter;
+ float vec[3];
+
+ if (cu->flag & CU_DEFORM_BOUNDS_OFF) {
+ for (a = 0, dvert_iter = dvert; a < numVerts; a++, dvert_iter++) {
+ const float weight = defvert_find_weight(dvert_iter, defgrp_index);
+
+ if (weight > 0.0f) {
+ mul_m4_v3(cd.curvespace, vertexCos[a]);
+ copy_v3_v3(vec, vertexCos[a]);
+ calc_curve_deform(cuOb, vec, defaxis, &cd, NULL);
+ interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight);
+ mul_m4_v3(cd.objectspace, vertexCos[a]);
+ }
+ }
+ }
+ else {
+ /* set mesh min/max bounds */
+ INIT_MINMAX(cd.dmin, cd.dmax);
+
+ for (a = 0, dvert_iter = dvert; a < numVerts; a++, dvert_iter++) {
+ if (defvert_find_weight(dvert_iter, defgrp_index) > 0.0f) {
+ mul_m4_v3(cd.curvespace, vertexCos[a]);
+ minmax_v3v3_v3(cd.dmin, cd.dmax, vertexCos[a]);
+ }
+ }
+
+ for (a = 0, dvert_iter = dvert; a < numVerts; a++, dvert_iter++) {
+ const float weight = defvert_find_weight(dvert_iter, defgrp_index);
+
+ if (weight > 0.0f) {
+ /* already in 'cd.curvespace', prev for loop */
+ copy_v3_v3(vec, vertexCos[a]);
+ calc_curve_deform(cuOb, vec, defaxis, &cd, NULL);
+ interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight);
+ mul_m4_v3(cd.objectspace, vertexCos[a]);
+ }
+ }
+ }
+ }
+ else {
+ if (cu->flag & CU_DEFORM_BOUNDS_OFF) {
+ for (a = 0; a < numVerts; a++) {
+ mul_m4_v3(cd.curvespace, vertexCos[a]);
+ calc_curve_deform(cuOb, vertexCos[a], defaxis, &cd, NULL);
+ mul_m4_v3(cd.objectspace, vertexCos[a]);
+ }
+ }
+ else {
+ /* set mesh min max bounds */
+ INIT_MINMAX(cd.dmin, cd.dmax);
+
+ for (a = 0; a < numVerts; a++) {
+ mul_m4_v3(cd.curvespace, vertexCos[a]);
+ minmax_v3v3_v3(cd.dmin, cd.dmax, vertexCos[a]);
+ }
+
+ for (a = 0; a < numVerts; a++) {
+ /* already in 'cd.curvespace', prev for loop */
+ calc_curve_deform(cuOb, vertexCos[a], defaxis, &cd, NULL);
+ mul_m4_v3(cd.objectspace, vertexCos[a]);
+ }
+ }
+ }
}
/* input vec and orco = local coord in armature space */
/* orco is original not-animated or deformed reference point */
/* result written in vec and mat */
-void curve_deform_vector(Object *cuOb, Object *target,
- float orco[3], float vec[3], float mat[3][3], int no_rot_axis)
+void curve_deform_vector(
+ Object *cuOb, Object *target, float orco[3], float vec[3], float mat[3][3], int no_rot_axis)
{
- CurveDeform cd;
- float quat[4];
+ CurveDeform cd;
+ float quat[4];
- if (cuOb->type != OB_CURVE) {
- unit_m3(mat);
- return;
- }
+ if (cuOb->type != OB_CURVE) {
+ unit_m3(mat);
+ return;
+ }
- init_curve_deform(cuOb, target, &cd);
- cd.no_rot_axis = no_rot_axis; /* option to only rotate for XY, for example */
+ init_curve_deform(cuOb, target, &cd);
+ cd.no_rot_axis = no_rot_axis; /* option to only rotate for XY, for example */
- copy_v3_v3(cd.dmin, orco);
- copy_v3_v3(cd.dmax, orco);
+ copy_v3_v3(cd.dmin, orco);
+ copy_v3_v3(cd.dmax, orco);
- mul_m4_v3(cd.curvespace, vec);
+ mul_m4_v3(cd.curvespace, vec);
- if (calc_curve_deform(cuOb, vec, target->trackflag, &cd, quat)) {
- float qmat[3][3];
+ if (calc_curve_deform(cuOb, vec, target->trackflag, &cd, quat)) {
+ float qmat[3][3];
- quat_to_mat3(qmat, quat);
- mul_m3_m3m3(mat, qmat, cd.objectspace3);
- }
- else
- unit_m3(mat);
-
- mul_m4_v3(cd.objectspace, vec);
+ quat_to_mat3(qmat, quat);
+ mul_m3_m3m3(mat, qmat, cd.objectspace3);
+ }
+ else
+ unit_m3(mat);
+ mul_m4_v3(cd.objectspace, vec);
}
-void lattice_deform_verts(Object *laOb, Object *target, Mesh *mesh,
- float (*vertexCos)[3], int numVerts, const char *vgroup, float fac)
+void lattice_deform_verts(Object *laOb,
+ Object *target,
+ Mesh *mesh,
+ float (*vertexCos)[3],
+ int numVerts,
+ const char *vgroup,
+ float fac)
{
- LatticeDeformData *lattice_deform_data;
- MDeformVert *dvert = NULL;
- int defgrp_index = -1;
- int a;
-
- if (laOb->type != OB_LATTICE)
- return;
-
- lattice_deform_data = init_latt_deform(laOb, target);
-
- /* Check whether to use vertex groups (only possible if target is a Mesh or Lattice).
- * We want either a Mesh/Lattice with no derived data, or derived data with deformverts.
- */
- if (vgroup && vgroup[0] && target && ELEM(target->type, OB_MESH, OB_LATTICE)) {
- defgrp_index = defgroup_name_index(target, vgroup);
-
- if (defgrp_index != -1) {
- /* if there's derived data without deformverts, don't use vgroups */
- if (mesh) {
- dvert = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT);
- }
- else if (target->type == OB_LATTICE) {
- dvert = ((Lattice *)target->data)->dvert;
- }
- else {
- dvert = ((Mesh *)target->data)->dvert;
- }
- }
- }
- if (dvert) {
- MDeformVert *dvert_iter;
- for (a = 0, dvert_iter = dvert; a < numVerts; a++, dvert_iter++) {
- const float weight = defvert_find_weight(dvert_iter, defgrp_index);
- if (weight > 0.0f) {
- calc_latt_deform(lattice_deform_data, vertexCos[a], weight * fac);
- }
- }
- }
- else {
- for (a = 0; a < numVerts; a++) {
- calc_latt_deform(lattice_deform_data, vertexCos[a], fac);
- }
- }
- end_latt_deform(lattice_deform_data);
+ LatticeDeformData *lattice_deform_data;
+ MDeformVert *dvert = NULL;
+ int defgrp_index = -1;
+ int a;
+
+ if (laOb->type != OB_LATTICE)
+ return;
+
+ lattice_deform_data = init_latt_deform(laOb, target);
+
+ /* Check whether to use vertex groups (only possible if target is a Mesh or Lattice).
+ * We want either a Mesh/Lattice with no derived data, or derived data with deformverts.
+ */
+ if (vgroup && vgroup[0] && target && ELEM(target->type, OB_MESH, OB_LATTICE)) {
+ defgrp_index = defgroup_name_index(target, vgroup);
+
+ if (defgrp_index != -1) {
+ /* if there's derived data without deformverts, don't use vgroups */
+ if (mesh) {
+ dvert = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT);
+ }
+ else if (target->type == OB_LATTICE) {
+ dvert = ((Lattice *)target->data)->dvert;
+ }
+ else {
+ dvert = ((Mesh *)target->data)->dvert;
+ }
+ }
+ }
+ if (dvert) {
+ MDeformVert *dvert_iter;
+ for (a = 0, dvert_iter = dvert; a < numVerts; a++, dvert_iter++) {
+ const float weight = defvert_find_weight(dvert_iter, defgrp_index);
+ if (weight > 0.0f) {
+ calc_latt_deform(lattice_deform_data, vertexCos[a], weight * fac);
+ }
+ }
+ }
+ else {
+ for (a = 0; a < numVerts; a++) {
+ calc_latt_deform(lattice_deform_data, vertexCos[a], fac);
+ }
+ }
+ end_latt_deform(lattice_deform_data);
}
bool object_deform_mball(Object *ob, ListBase *dispbase)
{
- if (ob->parent && ob->parent->type == OB_LATTICE && ob->partype == PARSKEL) {
- DispList *dl;
-
- for (dl = dispbase->first; dl; dl = dl->next) {
- lattice_deform_verts(ob->parent, ob, NULL,
- (float(*)[3])dl->verts, dl->nr, NULL, 1.0f);
- }
-
- return true;
- }
- else {
- return false;
- }
+ if (ob->parent && ob->parent->type == OB_LATTICE && ob->partype == PARSKEL) {
+ DispList *dl;
+
+ for (dl = dispbase->first; dl; dl = dl->next) {
+ lattice_deform_verts(ob->parent, ob, NULL, (float(*)[3])dl->verts, dl->nr, NULL, 1.0f);
+ }
+
+ return true;
+ }
+ else {
+ return false;
+ }
}
static BPoint *latt_bp(Lattice *lt, int u, int v, int w)
{
- return &lt->def[BKE_lattice_index_from_uvw(lt, u, v, w)];
+ return &lt->def[BKE_lattice_index_from_uvw(lt, u, v, w)];
}
void outside_lattice(Lattice *lt)
{
- BPoint *bp, *bp1, *bp2;
- int u, v, w;
- float fac1, du = 0.0, dv = 0.0, dw = 0.0;
-
- if (lt->flag & LT_OUTSIDE) {
- bp = lt->def;
-
- if (lt->pntsu > 1) du = 1.0f / ((float)lt->pntsu - 1);
- if (lt->pntsv > 1) dv = 1.0f / ((float)lt->pntsv - 1);
- if (lt->pntsw > 1) dw = 1.0f / ((float)lt->pntsw - 1);
-
- for (w = 0; w < lt->pntsw; w++) {
-
- for (v = 0; v < lt->pntsv; v++) {
-
- for (u = 0; u < lt->pntsu; u++, bp++) {
- if (u == 0 || v == 0 || w == 0 || u == lt->pntsu - 1 || v == lt->pntsv - 1 || w == lt->pntsw - 1) {
- /* pass */
- }
- else {
- bp->hide = 1;
- bp->f1 &= ~SELECT;
-
- /* u extrema */
- bp1 = latt_bp(lt, 0, v, w);
- bp2 = latt_bp(lt, lt->pntsu - 1, v, w);
-
- fac1 = du * u;
- bp->vec[0] = (1.0f - fac1) * bp1->vec[0] + fac1 * bp2->vec[0];
- bp->vec[1] = (1.0f - fac1) * bp1->vec[1] + fac1 * bp2->vec[1];
- bp->vec[2] = (1.0f - fac1) * bp1->vec[2] + fac1 * bp2->vec[2];
-
- /* v extrema */
- bp1 = latt_bp(lt, u, 0, w);
- bp2 = latt_bp(lt, u, lt->pntsv - 1, w);
-
- fac1 = dv * v;
- bp->vec[0] += (1.0f - fac1) * bp1->vec[0] + fac1 * bp2->vec[0];
- bp->vec[1] += (1.0f - fac1) * bp1->vec[1] + fac1 * bp2->vec[1];
- bp->vec[2] += (1.0f - fac1) * bp1->vec[2] + fac1 * bp2->vec[2];
-
- /* w extrema */
- bp1 = latt_bp(lt, u, v, 0);
- bp2 = latt_bp(lt, u, v, lt->pntsw - 1);
-
- fac1 = dw * w;
- bp->vec[0] += (1.0f - fac1) * bp1->vec[0] + fac1 * bp2->vec[0];
- bp->vec[1] += (1.0f - fac1) * bp1->vec[1] + fac1 * bp2->vec[1];
- bp->vec[2] += (1.0f - fac1) * bp1->vec[2] + fac1 * bp2->vec[2];
-
- mul_v3_fl(bp->vec, 1.0f / 3.0f);
-
- }
- }
-
- }
-
- }
- }
- else {
- bp = lt->def;
-
- for (w = 0; w < lt->pntsw; w++)
- for (v = 0; v < lt->pntsv; v++)
- for (u = 0; u < lt->pntsu; u++, bp++)
- bp->hide = 0;
- }
+ BPoint *bp, *bp1, *bp2;
+ int u, v, w;
+ float fac1, du = 0.0, dv = 0.0, dw = 0.0;
+
+ if (lt->flag & LT_OUTSIDE) {
+ bp = lt->def;
+
+ if (lt->pntsu > 1)
+ du = 1.0f / ((float)lt->pntsu - 1);
+ if (lt->pntsv > 1)
+ dv = 1.0f / ((float)lt->pntsv - 1);
+ if (lt->pntsw > 1)
+ dw = 1.0f / ((float)lt->pntsw - 1);
+
+ for (w = 0; w < lt->pntsw; w++) {
+
+ for (v = 0; v < lt->pntsv; v++) {
+
+ for (u = 0; u < lt->pntsu; u++, bp++) {
+ if (u == 0 || v == 0 || w == 0 || u == lt->pntsu - 1 || v == lt->pntsv - 1 ||
+ w == lt->pntsw - 1) {
+ /* pass */
+ }
+ else {
+ bp->hide = 1;
+ bp->f1 &= ~SELECT;
+
+ /* u extrema */
+ bp1 = latt_bp(lt, 0, v, w);
+ bp2 = latt_bp(lt, lt->pntsu - 1, v, w);
+
+ fac1 = du * u;
+ bp->vec[0] = (1.0f - fac1) * bp1->vec[0] + fac1 * bp2->vec[0];
+ bp->vec[1] = (1.0f - fac1) * bp1->vec[1] + fac1 * bp2->vec[1];
+ bp->vec[2] = (1.0f - fac1) * bp1->vec[2] + fac1 * bp2->vec[2];
+
+ /* v extrema */
+ bp1 = latt_bp(lt, u, 0, w);
+ bp2 = latt_bp(lt, u, lt->pntsv - 1, w);
+
+ fac1 = dv * v;
+ bp->vec[0] += (1.0f - fac1) * bp1->vec[0] + fac1 * bp2->vec[0];
+ bp->vec[1] += (1.0f - fac1) * bp1->vec[1] + fac1 * bp2->vec[1];
+ bp->vec[2] += (1.0f - fac1) * bp1->vec[2] + fac1 * bp2->vec[2];
+
+ /* w extrema */
+ bp1 = latt_bp(lt, u, v, 0);
+ bp2 = latt_bp(lt, u, v, lt->pntsw - 1);
+
+ fac1 = dw * w;
+ bp->vec[0] += (1.0f - fac1) * bp1->vec[0] + fac1 * bp2->vec[0];
+ bp->vec[1] += (1.0f - fac1) * bp1->vec[1] + fac1 * bp2->vec[1];
+ bp->vec[2] += (1.0f - fac1) * bp1->vec[2] + fac1 * bp2->vec[2];
+
+ mul_v3_fl(bp->vec, 1.0f / 3.0f);
+ }
+ }
+ }
+ }
+ }
+ else {
+ bp = lt->def;
+
+ for (w = 0; w < lt->pntsw; w++)
+ for (v = 0; v < lt->pntsv; v++)
+ for (u = 0; u < lt->pntsu; u++, bp++)
+ bp->hide = 0;
+ }
}
float (*BKE_lattice_vertexcos_get(struct Object *ob, int *r_numVerts))[3]
{
- Lattice *lt = ob->data;
- int i, numVerts;
- float (*vertexCos)[3];
+ Lattice *lt = ob->data;
+ int i, numVerts;
+ float(*vertexCos)[3];
- if (lt->editlatt) lt = lt->editlatt->latt;
- numVerts = *r_numVerts = lt->pntsu * lt->pntsv * lt->pntsw;
+ if (lt->editlatt)
+ lt = lt->editlatt->latt;
+ numVerts = *r_numVerts = lt->pntsu * lt->pntsv * lt->pntsw;
- vertexCos = MEM_mallocN(sizeof(*vertexCos) * numVerts, "lt_vcos");
+ vertexCos = MEM_mallocN(sizeof(*vertexCos) * numVerts, "lt_vcos");
- for (i = 0; i < numVerts; i++) {
- copy_v3_v3(vertexCos[i], lt->def[i].vec);
- }
+ for (i = 0; i < numVerts; i++) {
+ copy_v3_v3(vertexCos[i], lt->def[i].vec);
+ }
- return vertexCos;
+ return vertexCos;
}
void BKE_lattice_vertexcos_apply(struct Object *ob, float (*vertexCos)[3])
{
- Lattice *lt = ob->data;
- int i, numVerts = lt->pntsu * lt->pntsv * lt->pntsw;
+ Lattice *lt = ob->data;
+ int i, numVerts = lt->pntsu * lt->pntsv * lt->pntsw;
- for (i = 0; i < numVerts; i++) {
- copy_v3_v3(lt->def[i].vec, vertexCos[i]);
- }
+ for (i = 0; i < numVerts; i++) {
+ copy_v3_v3(lt->def[i].vec, vertexCos[i]);
+ }
}
void BKE_lattice_modifiers_calc(struct Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- Lattice *lt = ob->data;
- /* Get vertex coordinates from the original copy; otherwise we get already-modified coordinates. */
- Object *ob_orig = DEG_get_original_object(ob);
- VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
- float (*vertexCos)[3] = NULL;
- int numVerts, editmode = (lt->editlatt != NULL);
- const ModifierEvalContext mectx = {depsgraph, ob, 0};
-
- if (ob->runtime.curve_cache) {
- BKE_displist_free(&ob->runtime.curve_cache->disp);
- }
- else {
- ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for lattice");
- }
-
- for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
-
- if (!(mti->flags & eModifierTypeFlag_AcceptsLattice)) continue;
- if (!(md->mode & eModifierMode_Realtime)) continue;
- if (editmode && !(md->mode & eModifierMode_Editmode)) continue;
- if (mti->isDisabled && mti->isDisabled(scene, md, 0)) continue;
- if (mti->type != eModifierTypeType_OnlyDeform) continue;
-
- if (!vertexCos) vertexCos = BKE_lattice_vertexcos_get(ob_orig, &numVerts);
- mti->deformVerts(md, &mectx, NULL, vertexCos, numVerts);
- }
-
- if (ob->id.tag & LIB_TAG_COPIED_ON_WRITE) {
- if (vertexCos) {
- BKE_lattice_vertexcos_apply(ob, vertexCos);
- MEM_freeN(vertexCos);
- }
- }
- else {
- /* Displist won't do anything; this is just for posterity's sake until we remove it. */
- if (!vertexCos) vertexCos = BKE_lattice_vertexcos_get(ob_orig, &numVerts);
-
- DispList *dl = MEM_callocN(sizeof(*dl), "lt_dl");
- dl->type = DL_VERTS;
- dl->parts = 1;
- dl->nr = numVerts;
- dl->verts = (float *) vertexCos;
-
- BLI_addtail(&ob->runtime.curve_cache->disp, dl);
- }
+ Lattice *lt = ob->data;
+ /* Get vertex coordinates from the original copy; otherwise we get already-modified coordinates. */
+ Object *ob_orig = DEG_get_original_object(ob);
+ VirtualModifierData virtualModifierData;
+ ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ float(*vertexCos)[3] = NULL;
+ int numVerts, editmode = (lt->editlatt != NULL);
+ const ModifierEvalContext mectx = {depsgraph, ob, 0};
+
+ if (ob->runtime.curve_cache) {
+ BKE_displist_free(&ob->runtime.curve_cache->disp);
+ }
+ else {
+ ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for lattice");
+ }
+
+ for (; md; md = md->next) {
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if (!(mti->flags & eModifierTypeFlag_AcceptsLattice))
+ continue;
+ if (!(md->mode & eModifierMode_Realtime))
+ continue;
+ if (editmode && !(md->mode & eModifierMode_Editmode))
+ continue;
+ if (mti->isDisabled && mti->isDisabled(scene, md, 0))
+ continue;
+ if (mti->type != eModifierTypeType_OnlyDeform)
+ continue;
+
+ if (!vertexCos)
+ vertexCos = BKE_lattice_vertexcos_get(ob_orig, &numVerts);
+ mti->deformVerts(md, &mectx, NULL, vertexCos, numVerts);
+ }
+
+ if (ob->id.tag & LIB_TAG_COPIED_ON_WRITE) {
+ if (vertexCos) {
+ BKE_lattice_vertexcos_apply(ob, vertexCos);
+ MEM_freeN(vertexCos);
+ }
+ }
+ else {
+ /* Displist won't do anything; this is just for posterity's sake until we remove it. */
+ if (!vertexCos)
+ vertexCos = BKE_lattice_vertexcos_get(ob_orig, &numVerts);
+
+ DispList *dl = MEM_callocN(sizeof(*dl), "lt_dl");
+ dl->type = DL_VERTS;
+ dl->parts = 1;
+ dl->nr = numVerts;
+ dl->verts = (float *)vertexCos;
+
+ BLI_addtail(&ob->runtime.curve_cache->disp, dl);
+ }
}
struct MDeformVert *BKE_lattice_deform_verts_get(struct Object *oblatt)
{
- Lattice *lt = (Lattice *)oblatt->data;
- BLI_assert(oblatt->type == OB_LATTICE);
- if (lt->editlatt) lt = lt->editlatt->latt;
- return lt->dvert;
+ Lattice *lt = (Lattice *)oblatt->data;
+ BLI_assert(oblatt->type == OB_LATTICE);
+ if (lt->editlatt)
+ lt = lt->editlatt->latt;
+ return lt->dvert;
}
struct BPoint *BKE_lattice_active_point_get(Lattice *lt)
{
- BLI_assert(GS(lt->id.name) == ID_LT);
+ BLI_assert(GS(lt->id.name) == ID_LT);
- if (lt->editlatt) {
- lt = lt->editlatt->latt;
- }
+ if (lt->editlatt) {
+ lt = lt->editlatt->latt;
+ }
- BLI_assert(lt->actbp < lt->pntsu * lt->pntsv * lt->pntsw);
+ BLI_assert(lt->actbp < lt->pntsu * lt->pntsv * lt->pntsw);
- if ((lt->actbp != LT_ACTBP_NONE) && (lt->actbp < lt->pntsu * lt->pntsv * lt->pntsw)) {
- return &lt->def[lt->actbp];
- }
- else {
- return NULL;
- }
+ if ((lt->actbp != LT_ACTBP_NONE) && (lt->actbp < lt->pntsu * lt->pntsv * lt->pntsw)) {
+ return &lt->def[lt->actbp];
+ }
+ else {
+ return NULL;
+ }
}
void BKE_lattice_center_median(Lattice *lt, float cent[3])
{
- int i, numVerts;
+ int i, numVerts;
- if (lt->editlatt) lt = lt->editlatt->latt;
- numVerts = lt->pntsu * lt->pntsv * lt->pntsw;
+ if (lt->editlatt)
+ lt = lt->editlatt->latt;
+ numVerts = lt->pntsu * lt->pntsv * lt->pntsw;
- zero_v3(cent);
+ zero_v3(cent);
- for (i = 0; i < numVerts; i++)
- add_v3_v3(cent, lt->def[i].vec);
+ for (i = 0; i < numVerts; i++)
+ add_v3_v3(cent, lt->def[i].vec);
- mul_v3_fl(cent, 1.0f / (float)numVerts);
+ mul_v3_fl(cent, 1.0f / (float)numVerts);
}
static void boundbox_lattice(Object *ob)
{
- BoundBox *bb;
- Lattice *lt;
- float min[3], max[3];
+ BoundBox *bb;
+ Lattice *lt;
+ float min[3], max[3];
- if (ob->runtime.bb == NULL) {
- ob->runtime.bb = MEM_callocN(sizeof(BoundBox), "Lattice boundbox");
- }
+ if (ob->runtime.bb == NULL) {
+ ob->runtime.bb = MEM_callocN(sizeof(BoundBox), "Lattice boundbox");
+ }
- bb = ob->runtime.bb;
- lt = ob->data;
+ bb = ob->runtime.bb;
+ lt = ob->data;
- INIT_MINMAX(min, max);
- BKE_lattice_minmax_dl(ob, lt, min, max);
- BKE_boundbox_init_from_minmax(bb, min, max);
+ INIT_MINMAX(min, max);
+ BKE_lattice_minmax_dl(ob, lt, min, max);
+ BKE_boundbox_init_from_minmax(bb, min, max);
- bb->flag &= ~BOUNDBOX_DIRTY;
+ bb->flag &= ~BOUNDBOX_DIRTY;
}
BoundBox *BKE_lattice_boundbox_get(Object *ob)
{
- boundbox_lattice(ob);
+ boundbox_lattice(ob);
- return ob->runtime.bb;
+ return ob->runtime.bb;
}
void BKE_lattice_minmax_dl(Object *ob, Lattice *lt, float min[3], float max[3])
{
- DispList *dl = ob->runtime.curve_cache ? BKE_displist_find(&ob->runtime.curve_cache->disp, DL_VERTS) : NULL;
-
- if (!dl) {
- BKE_lattice_minmax(lt, min, max);
- }
- else {
- int i, numVerts;
-
- if (lt->editlatt) lt = lt->editlatt->latt;
- numVerts = lt->pntsu * lt->pntsv * lt->pntsw;
-
- for (i = 0; i < numVerts; i++)
- minmax_v3v3_v3(min, max, &dl->verts[i * 3]);
- }
+ DispList *dl = ob->runtime.curve_cache ?
+ BKE_displist_find(&ob->runtime.curve_cache->disp, DL_VERTS) :
+ NULL;
+
+ if (!dl) {
+ BKE_lattice_minmax(lt, min, max);
+ }
+ else {
+ int i, numVerts;
+
+ if (lt->editlatt)
+ lt = lt->editlatt->latt;
+ numVerts = lt->pntsu * lt->pntsv * lt->pntsw;
+
+ for (i = 0; i < numVerts; i++)
+ minmax_v3v3_v3(min, max, &dl->verts[i * 3]);
+ }
}
void BKE_lattice_minmax(Lattice *lt, float min[3], float max[3])
{
- int i, numVerts;
+ int i, numVerts;
- if (lt->editlatt) lt = lt->editlatt->latt;
- numVerts = lt->pntsu * lt->pntsv * lt->pntsw;
+ if (lt->editlatt)
+ lt = lt->editlatt->latt;
+ numVerts = lt->pntsu * lt->pntsv * lt->pntsw;
- for (i = 0; i < numVerts; i++)
- minmax_v3v3_v3(min, max, lt->def[i].vec);
+ for (i = 0; i < numVerts; i++)
+ minmax_v3v3_v3(min, max, lt->def[i].vec);
}
void BKE_lattice_center_bounds(Lattice *lt, float cent[3])
{
- float min[3], max[3];
+ float min[3], max[3];
- INIT_MINMAX(min, max);
+ INIT_MINMAX(min, max);
- BKE_lattice_minmax(lt, min, max);
- mid_v3_v3v3(cent, min, max);
+ BKE_lattice_minmax(lt, min, max);
+ mid_v3_v3v3(cent, min, max);
}
void BKE_lattice_transform(Lattice *lt, float mat[4][4], bool do_keys)
{
- BPoint *bp = lt->def;
- int i = lt->pntsu * lt->pntsv * lt->pntsw;
-
- while (i--) {
- mul_m4_v3(mat, bp->vec);
- bp++;
- }
-
- if (do_keys && lt->key) {
- KeyBlock *kb;
-
- for (kb = lt->key->block.first; kb; kb = kb->next) {
- float *fp = kb->data;
- for (i = kb->totelem; i--; fp += 3) {
- mul_m4_v3(mat, fp);
- }
- }
- }
+ BPoint *bp = lt->def;
+ int i = lt->pntsu * lt->pntsv * lt->pntsw;
+
+ while (i--) {
+ mul_m4_v3(mat, bp->vec);
+ bp++;
+ }
+
+ if (do_keys && lt->key) {
+ KeyBlock *kb;
+
+ for (kb = lt->key->block.first; kb; kb = kb->next) {
+ float *fp = kb->data;
+ for (i = kb->totelem; i--; fp += 3) {
+ mul_m4_v3(mat, fp);
+ }
+ }
+ }
}
void BKE_lattice_translate(Lattice *lt, float offset[3], bool do_keys)
{
- int i, numVerts;
+ int i, numVerts;
- numVerts = lt->pntsu * lt->pntsv * lt->pntsw;
+ numVerts = lt->pntsu * lt->pntsv * lt->pntsw;
- if (lt->def)
- for (i = 0; i < numVerts; i++)
- add_v3_v3(lt->def[i].vec, offset);
+ if (lt->def)
+ for (i = 0; i < numVerts; i++)
+ add_v3_v3(lt->def[i].vec, offset);
- if (lt->editlatt)
- for (i = 0; i < numVerts; i++)
- add_v3_v3(lt->editlatt->latt->def[i].vec, offset);
+ if (lt->editlatt)
+ for (i = 0; i < numVerts; i++)
+ add_v3_v3(lt->editlatt->latt->def[i].vec, offset);
- if (do_keys && lt->key) {
- KeyBlock *kb;
+ if (do_keys && lt->key) {
+ KeyBlock *kb;
- for (kb = lt->key->block.first; kb; kb = kb->next) {
- float *fp = kb->data;
- for (i = kb->totelem; i--; fp += 3) {
- add_v3_v3(fp, offset);
- }
- }
- }
+ for (kb = lt->key->block.first; kb; kb = kb->next) {
+ float *fp = kb->data;
+ for (i = kb->totelem; i--; fp += 3) {
+ add_v3_v3(fp, offset);
+ }
+ }
+ }
}
bool BKE_lattice_is_any_selected(const Lattice *lt)
{
- /* Intentionally don't handle 'lt->editlatt' (caller must do this). */
- const BPoint *bp = lt->def;
- int a = lt->pntsu * lt->pntsv * lt->pntsw;
- while (a--) {
- if (bp->hide == 0) {
- if (bp->f1 & SELECT) {
- return true;
- }
- }
- bp++;
- }
- return false;
+ /* Intentionally don't handle 'lt->editlatt' (caller must do this). */
+ const BPoint *bp = lt->def;
+ int a = lt->pntsu * lt->pntsv * lt->pntsw;
+ while (a--) {
+ if (bp->hide == 0) {
+ if (bp->f1 & SELECT) {
+ return true;
+ }
+ }
+ bp++;
+ }
+ return false;
}
/* **** Depsgraph evaluation **** */
-void BKE_lattice_eval_geometry(struct Depsgraph *UNUSED(depsgraph),
- Lattice *UNUSED(latt))
+void BKE_lattice_eval_geometry(struct Depsgraph *UNUSED(depsgraph), Lattice *UNUSED(latt))
{
}
@@ -1227,13 +1268,13 @@ void (*BKE_lattice_batch_cache_free_cb)(Lattice *lt) = NULL;
void BKE_lattice_batch_cache_dirty_tag(Lattice *lt, int mode)
{
- if (lt->batch_cache) {
- BKE_lattice_batch_cache_dirty_tag_cb(lt, mode);
- }
+ if (lt->batch_cache) {
+ BKE_lattice_batch_cache_dirty_tag_cb(lt, mode);
+ }
}
void BKE_lattice_batch_cache_free(Lattice *lt)
{
- if (lt->batch_cache) {
- BKE_lattice_batch_cache_free_cb(lt);
- }
+ if (lt->batch_cache) {
+ BKE_lattice_batch_cache_free_cb(lt);
+ }
}
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c
index 95c8f9b7ee2..133deb13836 100644
--- a/source/blender/blenkernel/intern/layer.c
+++ b/source/blender/blenkernel/intern/layer.c
@@ -56,92 +56,89 @@
#include "MEM_guardedalloc.h"
/* Set of flags which are dependent on a collection settings. */
-static const short g_base_collection_flags = (
- BASE_VISIBLE |
- BASE_SELECTABLE |
- BASE_ENABLED_VIEWPORT |
- BASE_ENABLED_RENDER |
- BASE_HOLDOUT |
- BASE_INDIRECT_ONLY);
+static const short g_base_collection_flags = (BASE_VISIBLE | BASE_SELECTABLE |
+ BASE_ENABLED_VIEWPORT | BASE_ENABLED_RENDER |
+ BASE_HOLDOUT | BASE_INDIRECT_ONLY);
/* prototype */
static void object_bases_iterator_next(BLI_Iterator *iter, const int flag);
-
/*********************** Layer Collections and bases *************************/
static LayerCollection *layer_collection_add(ListBase *lb_parent, Collection *collection)
{
- LayerCollection *lc = MEM_callocN(sizeof(LayerCollection), "Collection Base");
- lc->collection = collection;
- BLI_addtail(lb_parent, lc);
+ LayerCollection *lc = MEM_callocN(sizeof(LayerCollection), "Collection Base");
+ lc->collection = collection;
+ BLI_addtail(lb_parent, lc);
- return lc;
+ return lc;
}
static void layer_collection_free(ViewLayer *view_layer, LayerCollection *lc)
{
- if (lc == view_layer->active_collection) {
- view_layer->active_collection = NULL;
- }
+ if (lc == view_layer->active_collection) {
+ view_layer->active_collection = NULL;
+ }
- for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) {
- layer_collection_free(view_layer, nlc);
- }
+ for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) {
+ layer_collection_free(view_layer, nlc);
+ }
- BLI_freelistN(&lc->layer_collections);
+ BLI_freelistN(&lc->layer_collections);
}
static Base *object_base_new(Object *ob)
{
- Base *base = MEM_callocN(sizeof(Base), "Object Base");
- base->object = ob;
- BKE_scene_object_base_flag_sync_from_object(base);
- return base;
+ Base *base = MEM_callocN(sizeof(Base), "Object Base");
+ base->object = ob;
+ BKE_scene_object_base_flag_sync_from_object(base);
+ return base;
}
/********************************* View Layer ********************************/
-
/* RenderLayer */
/* Returns the default view layer to view in workspaces if there is
* none linked to the workspace yet. */
ViewLayer *BKE_view_layer_default_view(const Scene *scene)
{
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
- if (!(view_layer->flag & VIEW_LAYER_RENDER)) {
- return view_layer;
- }
- }
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
+ view_layer = view_layer->next) {
+ if (!(view_layer->flag & VIEW_LAYER_RENDER)) {
+ return view_layer;
+ }
+ }
- BLI_assert(scene->view_layers.first);
- return scene->view_layers.first;
+ BLI_assert(scene->view_layers.first);
+ return scene->view_layers.first;
}
/* Returns the default view layer to render if we need to render just one. */
ViewLayer *BKE_view_layer_default_render(const Scene *scene)
{
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
- if (view_layer->flag & VIEW_LAYER_RENDER) {
- return view_layer;
- }
- }
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
+ view_layer = view_layer->next) {
+ if (view_layer->flag & VIEW_LAYER_RENDER) {
+ return view_layer;
+ }
+ }
- BLI_assert(scene->view_layers.first);
- return scene->view_layers.first;
+ BLI_assert(scene->view_layers.first);
+ return scene->view_layers.first;
}
/* Returns view layer with matching name, or NULL if not found. */
ViewLayer *BKE_view_layer_find(const Scene *scene, const char *layer_name)
{
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
- if (STREQ(view_layer->name, layer_name)) {
- return view_layer;
- }
- }
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
+ view_layer = view_layer->next) {
+ if (STREQ(view_layer->name, layer_name)) {
+ return view_layer;
+ }
+ }
- return NULL;
+ return NULL;
}
/**
@@ -151,28 +148,28 @@ ViewLayer *BKE_view_layer_find(const Scene *scene, const char *layer_name)
*/
ViewLayer *BKE_view_layer_context_active_PLACEHOLDER(const Scene *scene)
{
- BLI_assert(scene->view_layers.first);
- return scene->view_layers.first;
+ BLI_assert(scene->view_layers.first);
+ return scene->view_layers.first;
}
static ViewLayer *view_layer_add(const char *name)
{
- if (!name) {
- name = DATA_("View Layer");
- }
+ if (!name) {
+ name = DATA_("View Layer");
+ }
- ViewLayer *view_layer = MEM_callocN(sizeof(ViewLayer), "View Layer");
- view_layer->flag = VIEW_LAYER_RENDER | VIEW_LAYER_FREESTYLE;
+ ViewLayer *view_layer = MEM_callocN(sizeof(ViewLayer), "View Layer");
+ view_layer->flag = VIEW_LAYER_RENDER | VIEW_LAYER_FREESTYLE;
- BLI_strncpy_utf8(view_layer->name, name, sizeof(view_layer->name));
+ BLI_strncpy_utf8(view_layer->name, name, sizeof(view_layer->name));
- /* Pure rendering pipeline settings. */
- view_layer->layflag = 0x7FFF; /* solid ztra halo edge strand */
- view_layer->passflag = SCE_PASS_COMBINED | SCE_PASS_Z;
- view_layer->pass_alpha_threshold = 0.5f;
- BKE_freestyle_config_init(&view_layer->freestyle_config);
+ /* Pure rendering pipeline settings. */
+ view_layer->layflag = 0x7FFF; /* solid ztra halo edge strand */
+ view_layer->passflag = SCE_PASS_COMBINED | SCE_PASS_Z;
+ view_layer->pass_alpha_threshold = 0.5f;
+ BKE_freestyle_config_init(&view_layer->freestyle_config);
- return view_layer;
+ return view_layer;
}
/**
@@ -181,23 +178,26 @@ static ViewLayer *view_layer_add(const char *name)
*/
ViewLayer *BKE_view_layer_add(Scene *scene, const char *name)
{
- ViewLayer *view_layer = view_layer_add(name);
+ ViewLayer *view_layer = view_layer_add(name);
- BLI_addtail(&scene->view_layers, view_layer);
+ BLI_addtail(&scene->view_layers, view_layer);
- /* unique name */
- BLI_uniquename(
- &scene->view_layers, view_layer, DATA_("ViewLayer"), '.',
- offsetof(ViewLayer, name), sizeof(view_layer->name));
+ /* unique name */
+ BLI_uniquename(&scene->view_layers,
+ view_layer,
+ DATA_("ViewLayer"),
+ '.',
+ offsetof(ViewLayer, name),
+ sizeof(view_layer->name));
- BKE_layer_collection_sync(scene, view_layer);
+ BKE_layer_collection_sync(scene, view_layer);
- return view_layer;
+ return view_layer;
}
void BKE_view_layer_free(ViewLayer *view_layer)
{
- BKE_view_layer_free_ex(view_layer, true);
+ BKE_view_layer_free_ex(view_layer, true);
}
/**
@@ -205,41 +205,41 @@ void BKE_view_layer_free(ViewLayer *view_layer)
*/
void BKE_view_layer_free_ex(ViewLayer *view_layer, const bool do_id_user)
{
- view_layer->basact = NULL;
+ view_layer->basact = NULL;
- BLI_freelistN(&view_layer->object_bases);
+ BLI_freelistN(&view_layer->object_bases);
- if (view_layer->object_bases_hash) {
- BLI_ghash_free(view_layer->object_bases_hash, NULL, NULL);
- }
+ if (view_layer->object_bases_hash) {
+ BLI_ghash_free(view_layer->object_bases_hash, NULL, NULL);
+ }
- for (LayerCollection *lc = view_layer->layer_collections.first; lc; lc = lc->next) {
- layer_collection_free(view_layer, lc);
- }
- BLI_freelistN(&view_layer->layer_collections);
+ for (LayerCollection *lc = view_layer->layer_collections.first; lc; lc = lc->next) {
+ layer_collection_free(view_layer, lc);
+ }
+ BLI_freelistN(&view_layer->layer_collections);
- for (ViewLayerEngineData *sled = view_layer->drawdata.first; sled; sled = sled->next) {
- if (sled->storage) {
- if (sled->free) {
- sled->free(sled->storage);
- }
- MEM_freeN(sled->storage);
- }
- }
- BLI_freelistN(&view_layer->drawdata);
+ for (ViewLayerEngineData *sled = view_layer->drawdata.first; sled; sled = sled->next) {
+ if (sled->storage) {
+ if (sled->free) {
+ sled->free(sled->storage);
+ }
+ MEM_freeN(sled->storage);
+ }
+ }
+ BLI_freelistN(&view_layer->drawdata);
- MEM_SAFE_FREE(view_layer->stats);
+ MEM_SAFE_FREE(view_layer->stats);
- BKE_freestyle_config_free(&view_layer->freestyle_config, do_id_user);
+ BKE_freestyle_config_free(&view_layer->freestyle_config, do_id_user);
- if (view_layer->id_properties) {
- IDP_FreeProperty(view_layer->id_properties);
- MEM_freeN(view_layer->id_properties);
- }
+ if (view_layer->id_properties) {
+ IDP_FreeProperty(view_layer->id_properties);
+ MEM_freeN(view_layer->id_properties);
+ }
- MEM_SAFE_FREE(view_layer->object_bases_array);
+ MEM_SAFE_FREE(view_layer->object_bases_array);
- MEM_freeN(view_layer);
+ MEM_freeN(view_layer);
}
/**
@@ -247,27 +247,27 @@ void BKE_view_layer_free_ex(ViewLayer *view_layer, const bool do_id_user)
*/
void BKE_view_layer_selected_objects_tag(ViewLayer *view_layer, const int tag)
{
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
- if ((base->flag & BASE_SELECTED) != 0) {
- base->object->flag |= tag;
- }
- else {
- base->object->flag &= ~tag;
- }
- }
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if ((base->flag & BASE_SELECTED) != 0) {
+ base->object->flag |= tag;
+ }
+ else {
+ base->object->flag &= ~tag;
+ }
+ }
}
static bool find_scene_collection_in_scene_collections(ListBase *lb, const LayerCollection *lc)
{
- for (LayerCollection *lcn = lb->first; lcn; lcn = lcn->next) {
- if (lcn == lc) {
- return true;
- }
- if (find_scene_collection_in_scene_collections(&lcn->layer_collections, lc)) {
- return true;
- }
- }
- return false;
+ for (LayerCollection *lcn = lb->first; lcn; lcn = lcn->next) {
+ if (lcn == lc) {
+ return true;
+ }
+ if (find_scene_collection_in_scene_collections(&lcn->layer_collections, lc)) {
+ return true;
+ }
+ }
+ return false;
}
/**
@@ -279,13 +279,13 @@ static bool find_scene_collection_in_scene_collections(ListBase *lb, const Layer
*/
Object *BKE_view_layer_camera_find(ViewLayer *view_layer)
{
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
- if (base->object->type == OB_CAMERA) {
- return base->object;
- }
- }
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (base->object->type == OB_CAMERA) {
+ return base->object;
+ }
+ }
- return NULL;
+ return NULL;
}
/**
@@ -293,94 +293,96 @@ Object *BKE_view_layer_camera_find(ViewLayer *view_layer)
*/
ViewLayer *BKE_view_layer_find_from_collection(const Scene *scene, LayerCollection *lc)
{
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
- if (find_scene_collection_in_scene_collections(&view_layer->layer_collections, lc)) {
- return view_layer;
- }
- }
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
+ view_layer = view_layer->next) {
+ if (find_scene_collection_in_scene_collections(&view_layer->layer_collections, lc)) {
+ return view_layer;
+ }
+ }
- return NULL;
+ return NULL;
}
/* Base */
static void view_layer_bases_hash_create(ViewLayer *view_layer)
{
- static ThreadMutex hash_lock = BLI_MUTEX_INITIALIZER;
+ static ThreadMutex hash_lock = BLI_MUTEX_INITIALIZER;
- if (view_layer->object_bases_hash == NULL) {
- BLI_mutex_lock(&hash_lock);
+ if (view_layer->object_bases_hash == NULL) {
+ BLI_mutex_lock(&hash_lock);
- if (view_layer->object_bases_hash == NULL) {
- view_layer->object_bases_hash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+ if (view_layer->object_bases_hash == NULL) {
+ view_layer->object_bases_hash = BLI_ghash_new(
+ BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
- if (base->object) {
- BLI_ghash_insert(view_layer->object_bases_hash, base->object, base);
- }
- }
- }
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (base->object) {
+ BLI_ghash_insert(view_layer->object_bases_hash, base->object, base);
+ }
+ }
+ }
- BLI_mutex_unlock(&hash_lock);
- }
+ BLI_mutex_unlock(&hash_lock);
+ }
}
Base *BKE_view_layer_base_find(ViewLayer *view_layer, Object *ob)
{
- if (!view_layer->object_bases_hash) {
- view_layer_bases_hash_create(view_layer);
- }
+ if (!view_layer->object_bases_hash) {
+ view_layer_bases_hash_create(view_layer);
+ }
- return BLI_ghash_lookup(view_layer->object_bases_hash, ob);
+ return BLI_ghash_lookup(view_layer->object_bases_hash, ob);
}
void BKE_view_layer_base_deselect_all(ViewLayer *view_layer)
{
- Base *base;
+ Base *base;
- for (base = view_layer->object_bases.first; base; base = base->next) {
- base->flag &= ~BASE_SELECTED;
- }
+ for (base = view_layer->object_bases.first; base; base = base->next) {
+ base->flag &= ~BASE_SELECTED;
+ }
}
void BKE_view_layer_base_select(Base *selbase)
{
- if ((selbase->flag & BASE_SELECTABLE) != 0) {
- selbase->flag |= BASE_SELECTED;
- }
+ if ((selbase->flag & BASE_SELECTABLE) != 0) {
+ selbase->flag |= BASE_SELECTED;
+ }
}
void BKE_view_layer_base_select_and_set_active(struct ViewLayer *view_layer, Base *selbase)
{
- view_layer->basact = selbase;
- BKE_view_layer_base_select(selbase);
+ view_layer->basact = selbase;
+ BKE_view_layer_base_select(selbase);
}
/**************************** Copy View Layer and Layer Collections ***********************/
-static void layer_collections_copy_data(
- ViewLayer *view_layer_dst, const ViewLayer *view_layer_src,
- ListBase *layer_collections_dst, const ListBase *layer_collections_src)
+static void layer_collections_copy_data(ViewLayer *view_layer_dst,
+ const ViewLayer *view_layer_src,
+ ListBase *layer_collections_dst,
+ const ListBase *layer_collections_src)
{
- BLI_duplicatelist(layer_collections_dst, layer_collections_src);
+ BLI_duplicatelist(layer_collections_dst, layer_collections_src);
- LayerCollection *layer_collection_dst = layer_collections_dst->first;
- const LayerCollection *layer_collection_src = layer_collections_src->first;
+ LayerCollection *layer_collection_dst = layer_collections_dst->first;
+ const LayerCollection *layer_collection_src = layer_collections_src->first;
- while (layer_collection_dst != NULL) {
- layer_collections_copy_data(
- view_layer_dst,
- view_layer_src,
- &layer_collection_dst->layer_collections,
- &layer_collection_src->layer_collections);
+ while (layer_collection_dst != NULL) {
+ layer_collections_copy_data(view_layer_dst,
+ view_layer_src,
+ &layer_collection_dst->layer_collections,
+ &layer_collection_src->layer_collections);
- if (layer_collection_src == view_layer_src->active_collection) {
- view_layer_dst->active_collection = layer_collection_dst;
- }
+ if (layer_collection_src == view_layer_src->active_collection) {
+ view_layer_dst->active_collection = layer_collection_dst;
+ }
- layer_collection_dst = layer_collection_dst->next;
- layer_collection_src = layer_collection_src->next;
- }
+ layer_collection_dst = layer_collection_dst->next;
+ layer_collection_src = layer_collection_src->next;
+ }
}
/**
@@ -388,81 +390,87 @@ static void layer_collections_copy_data(
*
* \param flag: Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
*/
-void BKE_view_layer_copy_data(
- Scene *scene_dst, const Scene *UNUSED(scene_src),
- ViewLayer *view_layer_dst, const ViewLayer *view_layer_src,
- const int flag)
-{
- if (view_layer_dst->id_properties != NULL) {
- view_layer_dst->id_properties = IDP_CopyProperty_ex(view_layer_dst->id_properties, flag);
- }
- BKE_freestyle_config_copy(&view_layer_dst->freestyle_config, &view_layer_src->freestyle_config, flag);
-
- view_layer_dst->stats = NULL;
-
- /* Clear temporary data. */
- BLI_listbase_clear(&view_layer_dst->drawdata);
- view_layer_dst->object_bases_array = NULL;
- view_layer_dst->object_bases_hash = NULL;
-
- /* Copy layer collections and object bases. */
- /* Inline 'BLI_duplicatelist' and update the active base. */
- BLI_listbase_clear(&view_layer_dst->object_bases);
- for (Base *base_src = view_layer_src->object_bases.first; base_src; base_src = base_src->next) {
- Base *base_dst = MEM_dupallocN(base_src);
- BLI_addtail(&view_layer_dst->object_bases, base_dst);
- if (view_layer_src->basact == base_src) {
- view_layer_dst->basact = base_dst;
- }
- }
-
- view_layer_dst->active_collection = NULL;
- layer_collections_copy_data(
- view_layer_dst,
- view_layer_src,
- &view_layer_dst->layer_collections,
- &view_layer_src->layer_collections);
-
- LayerCollection *lc_scene_dst = view_layer_dst->layer_collections.first;
- lc_scene_dst->collection = scene_dst->master_collection;
+void BKE_view_layer_copy_data(Scene *scene_dst,
+ const Scene *UNUSED(scene_src),
+ ViewLayer *view_layer_dst,
+ const ViewLayer *view_layer_src,
+ const int flag)
+{
+ if (view_layer_dst->id_properties != NULL) {
+ view_layer_dst->id_properties = IDP_CopyProperty_ex(view_layer_dst->id_properties, flag);
+ }
+ BKE_freestyle_config_copy(
+ &view_layer_dst->freestyle_config, &view_layer_src->freestyle_config, flag);
+
+ view_layer_dst->stats = NULL;
+
+ /* Clear temporary data. */
+ BLI_listbase_clear(&view_layer_dst->drawdata);
+ view_layer_dst->object_bases_array = NULL;
+ view_layer_dst->object_bases_hash = NULL;
+
+ /* Copy layer collections and object bases. */
+ /* Inline 'BLI_duplicatelist' and update the active base. */
+ BLI_listbase_clear(&view_layer_dst->object_bases);
+ for (Base *base_src = view_layer_src->object_bases.first; base_src; base_src = base_src->next) {
+ Base *base_dst = MEM_dupallocN(base_src);
+ BLI_addtail(&view_layer_dst->object_bases, base_dst);
+ if (view_layer_src->basact == base_src) {
+ view_layer_dst->basact = base_dst;
+ }
+ }
+
+ view_layer_dst->active_collection = NULL;
+ layer_collections_copy_data(view_layer_dst,
+ view_layer_src,
+ &view_layer_dst->layer_collections,
+ &view_layer_src->layer_collections);
+
+ LayerCollection *lc_scene_dst = view_layer_dst->layer_collections.first;
+ lc_scene_dst->collection = scene_dst->master_collection;
}
void BKE_view_layer_rename(Main *bmain, Scene *scene, ViewLayer *view_layer, const char *newname)
{
- char oldname[sizeof(view_layer->name)];
+ char oldname[sizeof(view_layer->name)];
- BLI_strncpy(oldname, view_layer->name, sizeof(view_layer->name));
+ BLI_strncpy(oldname, view_layer->name, sizeof(view_layer->name));
- BLI_strncpy_utf8(view_layer->name, newname, sizeof(view_layer->name));
- BLI_uniquename(&scene->view_layers, view_layer, DATA_("ViewLayer"), '.', offsetof(ViewLayer, name), sizeof(view_layer->name));
+ BLI_strncpy_utf8(view_layer->name, newname, sizeof(view_layer->name));
+ BLI_uniquename(&scene->view_layers,
+ view_layer,
+ DATA_("ViewLayer"),
+ '.',
+ offsetof(ViewLayer, name),
+ sizeof(view_layer->name));
- if (scene->nodetree) {
- bNode *node;
- int index = BLI_findindex(&scene->view_layers, view_layer);
+ if (scene->nodetree) {
+ bNode *node;
+ int index = BLI_findindex(&scene->view_layers, view_layer);
- for (node = scene->nodetree->nodes.first; node; node = node->next) {
- if (node->type == CMP_NODE_R_LAYERS && node->id == NULL) {
- if (node->custom1 == index)
- BLI_strncpy(node->name, view_layer->name, NODE_MAXSTR);
- }
- }
- }
+ for (node = scene->nodetree->nodes.first; node; node = node->next) {
+ if (node->type == CMP_NODE_R_LAYERS && node->id == NULL) {
+ if (node->custom1 == index)
+ BLI_strncpy(node->name, view_layer->name, NODE_MAXSTR);
+ }
+ }
+ }
- /* Fix all the animation data and windows which may link to this. */
- BKE_animdata_fix_paths_rename_all(NULL, "view_layers", oldname, view_layer->name);
+ /* Fix all the animation data and windows which may link to this. */
+ BKE_animdata_fix_paths_rename_all(NULL, "view_layers", oldname, view_layer->name);
- /* WM can be missing on startup. */
- wmWindowManager *wm = bmain->wm.first;
- if (wm) {
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
- if (win->scene == scene && STREQ(win->view_layer_name, oldname)) {
- STRNCPY(win->view_layer_name, view_layer->name);
- }
- }
- }
+ /* WM can be missing on startup. */
+ wmWindowManager *wm = bmain->wm.first;
+ if (wm) {
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ if (win->scene == scene && STREQ(win->view_layer_name, oldname)) {
+ STRNCPY(win->view_layer_name, view_layer->name);
+ }
+ }
+ }
- /* Dependency graph uses view layer name based lookups. */
- DEG_id_tag_update(&scene->id, 0);
+ /* Dependency graph uses view layer name based lookups. */
+ DEG_id_tag_update(&scene->id, 0);
}
/* LayerCollection */
@@ -472,21 +480,21 @@ void BKE_view_layer_rename(Main *bmain, Scene *scene, ViewLayer *view_layer, con
*/
static LayerCollection *collection_from_index(ListBase *lb, const int number, int *i)
{
- for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
- if (*i == number) {
- return lc;
- }
+ for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
+ if (*i == number) {
+ return lc;
+ }
- (*i)++;
- }
+ (*i)++;
+ }
- for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
- LayerCollection *lc_nested = collection_from_index(&lc->layer_collections, number, i);
- if (lc_nested) {
- return lc_nested;
- }
- }
- return NULL;
+ for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
+ LayerCollection *lc_nested = collection_from_index(&lc->layer_collections, number, i);
+ if (lc_nested) {
+ return lc_nested;
+ }
+ }
+ return NULL;
}
/**
@@ -494,8 +502,8 @@ static LayerCollection *collection_from_index(ListBase *lb, const int number, in
*/
LayerCollection *BKE_layer_collection_from_index(ViewLayer *view_layer, const int index)
{
- int i = 0;
- return collection_from_index(&view_layer->layer_collections, index, &i);
+ int i = 0;
+ return collection_from_index(&view_layer->layer_collections, index, &i);
}
/**
@@ -503,7 +511,7 @@ LayerCollection *BKE_layer_collection_from_index(ViewLayer *view_layer, const in
*/
LayerCollection *BKE_layer_collection_get_active(ViewLayer *view_layer)
{
- return view_layer->active_collection;
+ return view_layer->active_collection;
}
/*
@@ -511,12 +519,12 @@ LayerCollection *BKE_layer_collection_get_active(ViewLayer *view_layer)
*/
bool BKE_layer_collection_activate(ViewLayer *view_layer, LayerCollection *lc)
{
- if (lc->flag & LAYER_COLLECTION_EXCLUDE) {
- return false;
- }
+ if (lc->flag & LAYER_COLLECTION_EXCLUDE) {
+ return false;
+ }
- view_layer->active_collection = lc;
- return true;
+ view_layer->active_collection = lc;
+ return true;
}
/**
@@ -524,26 +532,26 @@ bool BKE_layer_collection_activate(ViewLayer *view_layer, LayerCollection *lc)
*/
LayerCollection *BKE_layer_collection_activate_parent(ViewLayer *view_layer, LayerCollection *lc)
{
- CollectionParent *parent = lc->collection->parents.first;
+ CollectionParent *parent = lc->collection->parents.first;
- if (parent) {
- lc = BKE_layer_collection_first_from_scene_collection(view_layer, parent->collection);
- }
- else {
- lc = NULL;
- }
+ if (parent) {
+ lc = BKE_layer_collection_first_from_scene_collection(view_layer, parent->collection);
+ }
+ else {
+ lc = NULL;
+ }
- if (lc && (lc->flag & LAYER_COLLECTION_EXCLUDE)) {
- /* Don't activate excluded collections. */
- return BKE_layer_collection_activate_parent(view_layer, lc);
- }
+ if (lc && (lc->flag & LAYER_COLLECTION_EXCLUDE)) {
+ /* Don't activate excluded collections. */
+ return BKE_layer_collection_activate_parent(view_layer, lc);
+ }
- if (!lc) {
- lc = view_layer->layer_collections.first;
- }
+ if (!lc) {
+ lc = view_layer->layer_collections.first;
+ }
- view_layer->active_collection = lc;
- return lc;
+ view_layer->active_collection = lc;
+ return lc;
}
/**
@@ -551,11 +559,11 @@ LayerCollection *BKE_layer_collection_activate_parent(ViewLayer *view_layer, Lay
*/
static int collection_count(ListBase *lb)
{
- int i = 0;
- for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
- i += collection_count(&lc->layer_collections) + 1;
- }
- return i;
+ int i = 0;
+ for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
+ i += collection_count(&lc->layer_collections) + 1;
+ }
+ return i;
}
/**
@@ -564,7 +572,7 @@ static int collection_count(ListBase *lb)
*/
int BKE_layer_collection_count(ViewLayer *view_layer)
{
- return collection_count(&view_layer->layer_collections);
+ return collection_count(&view_layer->layer_collections);
}
/**
@@ -572,21 +580,21 @@ int BKE_layer_collection_count(ViewLayer *view_layer)
*/
static int index_from_collection(ListBase *lb, const LayerCollection *lc, int *i)
{
- for (LayerCollection *lcol = lb->first; lcol; lcol = lcol->next) {
- if (lcol == lc) {
- return *i;
- }
+ for (LayerCollection *lcol = lb->first; lcol; lcol = lcol->next) {
+ if (lcol == lc) {
+ return *i;
+ }
- (*i)++;
- }
+ (*i)++;
+ }
- for (LayerCollection *lcol = lb->first; lcol; lcol = lcol->next) {
- int i_nested = index_from_collection(&lcol->layer_collections, lc, i);
- if (i_nested != -1) {
- return i_nested;
- }
- }
- return -1;
+ for (LayerCollection *lcol = lb->first; lcol; lcol = lcol->next) {
+ int i_nested = index_from_collection(&lcol->layer_collections, lc, i);
+ if (i_nested != -1) {
+ return i_nested;
+ }
+ }
+ return -1;
}
/**
@@ -594,8 +602,8 @@ static int index_from_collection(ListBase *lb, const LayerCollection *lc, int *i
*/
int BKE_layer_collection_findindex(ViewLayer *view_layer, const LayerCollection *lc)
{
- int i = 0;
- return index_from_collection(&view_layer->layer_collections, lc, &i);
+ int i = 0;
+ return index_from_collection(&view_layer->layer_collections, lc, &i);
}
/*********************************** Syncing *********************************
@@ -610,142 +618,150 @@ int BKE_layer_collection_findindex(ViewLayer *view_layer, const LayerCollection
* in at least one layer collection. That list is also synchronized here, and
* stores state like selection. */
-static short layer_collection_sync(
- ViewLayer *view_layer, const ListBase *lb_scene,
- ListBase *lb_layer, ListBase *new_object_bases,
- short parent_exclude, short parent_restrict, short parent_layer_restrict)
-{
- /* TODO: support recovery after removal of intermediate collections, reordering, ..
- * For local edits we can make editing operating do the appropriate thing, but for
- * linking we can only sync after the fact. */
-
- /* Remove layer collections that no longer have a corresponding scene collection. */
- for (LayerCollection *lc = lb_layer->first; lc;) {
- /* Note ID remap can set lc->collection to NULL when deleting collections. */
- LayerCollection *lc_next = lc->next;
- Collection *collection = (lc->collection) ?
- BLI_findptr(lb_scene, lc->collection, offsetof(CollectionChild, collection)) : NULL;
-
- if (!collection) {
- if (lc == view_layer->active_collection) {
- view_layer->active_collection = NULL;
- }
-
- /* Free recursively. */
- layer_collection_free(view_layer, lc);
- BLI_freelinkN(lb_layer, lc);
- }
-
- lc = lc_next;
- }
-
- /* Add layer collections for any new scene collections, and ensure order is the same. */
- ListBase new_lb_layer = {NULL, NULL};
- short runtime_flag = 0;
-
- for (const CollectionChild *child = lb_scene->first; child; child = child->next) {
- Collection *collection = child->collection;
- LayerCollection *lc = BLI_findptr(lb_layer, collection, offsetof(LayerCollection, collection));
-
- if (lc) {
- BLI_remlink(lb_layer, lc);
- BLI_addtail(&new_lb_layer, lc);
- }
- else {
- lc = layer_collection_add(&new_lb_layer, collection);
- lc->flag = parent_exclude;
- }
-
- /* Collection restrict is inherited. */
- short child_restrict = parent_restrict;
- short child_layer_restrict = parent_layer_restrict;
- if (!(collection->flag & COLLECTION_IS_MASTER)) {
- child_restrict |= collection->flag;
- child_layer_restrict |= lc->flag;
- }
-
- /* Sync child collections. */
- short child_runtime_flag = layer_collection_sync(
- view_layer, &collection->children,
- &lc->layer_collections, new_object_bases,
- lc->flag, child_restrict, child_layer_restrict);
-
- /* Layer collection exclude is not inherited. */
- if (lc->flag & LAYER_COLLECTION_EXCLUDE) {
- lc->runtime_flag = 0;
- continue;
- }
- else {
- lc->runtime_flag = child_runtime_flag;
- }
-
- if (((child_restrict & COLLECTION_RESTRICT_VIEW) == 0) &&
- ((child_layer_restrict & LAYER_COLLECTION_RESTRICT_VIEW) == 0))
- {
- lc->runtime_flag |= LAYER_COLLECTION_VISIBLE;
- }
-
- /* Sync objects, except if collection was excluded. */
- for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
- if (cob->ob == NULL) {
- continue;
- }
-
- void **base_p;
- Base *base;
- if (BLI_ghash_ensure_p(view_layer->object_bases_hash, cob->ob, &base_p)) {
- /* Move from old base list to new base list. Base might have already
- * been moved to the new base list and the first/last test ensure that
- * case also works. */
- base = *base_p;
- if (!ELEM(base, new_object_bases->first, new_object_bases->last)) {
- BLI_remlink(&view_layer->object_bases, base);
- BLI_addtail(new_object_bases, base);
- }
- }
- else {
- /* Create new base. */
- base = object_base_new(cob->ob);
- *base_p = base;
- BLI_addtail(new_object_bases, base);
- }
-
- if ((child_restrict & COLLECTION_RESTRICT_VIEW) == 0) {
- base->flag_from_collection |= BASE_ENABLED_VIEWPORT;
- if ((child_layer_restrict & LAYER_COLLECTION_RESTRICT_VIEW) == 0) {
- base->flag_from_collection |= BASE_VISIBLE;
- if (((child_restrict & COLLECTION_RESTRICT_SELECT) == 0)) {
- base->flag_from_collection |= BASE_SELECTABLE;
- }
- }
- }
-
- if ((child_restrict & COLLECTION_RESTRICT_RENDER) == 0) {
- base->flag_from_collection |= BASE_ENABLED_RENDER;
- }
-
- /* Holdout and indirect only */
- if (lc->flag & LAYER_COLLECTION_HOLDOUT) {
- base->flag_from_collection |= BASE_HOLDOUT;
- }
- if (lc->flag & LAYER_COLLECTION_INDIRECT_ONLY) {
- base->flag_from_collection |= BASE_INDIRECT_ONLY;
- }
-
- lc->runtime_flag |= LAYER_COLLECTION_HAS_OBJECTS;
-
- /* Make sure flags on base are usable right away. */
- BKE_base_eval_flags(base);
- }
-
- runtime_flag |= lc->runtime_flag;
- }
-
- /* Replace layer collection list with new one. */
- *lb_layer = new_lb_layer;
- BLI_assert(BLI_listbase_count(lb_scene) == BLI_listbase_count(lb_layer));
-
- return runtime_flag;
+static short layer_collection_sync(ViewLayer *view_layer,
+ const ListBase *lb_scene,
+ ListBase *lb_layer,
+ ListBase *new_object_bases,
+ short parent_exclude,
+ short parent_restrict,
+ short parent_layer_restrict)
+{
+ /* TODO: support recovery after removal of intermediate collections, reordering, ..
+ * For local edits we can make editing operating do the appropriate thing, but for
+ * linking we can only sync after the fact. */
+
+ /* Remove layer collections that no longer have a corresponding scene collection. */
+ for (LayerCollection *lc = lb_layer->first; lc;) {
+ /* Note ID remap can set lc->collection to NULL when deleting collections. */
+ LayerCollection *lc_next = lc->next;
+ Collection *collection = (lc->collection) ?
+ BLI_findptr(lb_scene,
+ lc->collection,
+ offsetof(CollectionChild, collection)) :
+ NULL;
+
+ if (!collection) {
+ if (lc == view_layer->active_collection) {
+ view_layer->active_collection = NULL;
+ }
+
+ /* Free recursively. */
+ layer_collection_free(view_layer, lc);
+ BLI_freelinkN(lb_layer, lc);
+ }
+
+ lc = lc_next;
+ }
+
+ /* Add layer collections for any new scene collections, and ensure order is the same. */
+ ListBase new_lb_layer = {NULL, NULL};
+ short runtime_flag = 0;
+
+ for (const CollectionChild *child = lb_scene->first; child; child = child->next) {
+ Collection *collection = child->collection;
+ LayerCollection *lc = BLI_findptr(lb_layer, collection, offsetof(LayerCollection, collection));
+
+ if (lc) {
+ BLI_remlink(lb_layer, lc);
+ BLI_addtail(&new_lb_layer, lc);
+ }
+ else {
+ lc = layer_collection_add(&new_lb_layer, collection);
+ lc->flag = parent_exclude;
+ }
+
+ /* Collection restrict is inherited. */
+ short child_restrict = parent_restrict;
+ short child_layer_restrict = parent_layer_restrict;
+ if (!(collection->flag & COLLECTION_IS_MASTER)) {
+ child_restrict |= collection->flag;
+ child_layer_restrict |= lc->flag;
+ }
+
+ /* Sync child collections. */
+ short child_runtime_flag = layer_collection_sync(view_layer,
+ &collection->children,
+ &lc->layer_collections,
+ new_object_bases,
+ lc->flag,
+ child_restrict,
+ child_layer_restrict);
+
+ /* Layer collection exclude is not inherited. */
+ if (lc->flag & LAYER_COLLECTION_EXCLUDE) {
+ lc->runtime_flag = 0;
+ continue;
+ }
+ else {
+ lc->runtime_flag = child_runtime_flag;
+ }
+
+ if (((child_restrict & COLLECTION_RESTRICT_VIEW) == 0) &&
+ ((child_layer_restrict & LAYER_COLLECTION_RESTRICT_VIEW) == 0)) {
+ lc->runtime_flag |= LAYER_COLLECTION_VISIBLE;
+ }
+
+ /* Sync objects, except if collection was excluded. */
+ for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ if (cob->ob == NULL) {
+ continue;
+ }
+
+ void **base_p;
+ Base *base;
+ if (BLI_ghash_ensure_p(view_layer->object_bases_hash, cob->ob, &base_p)) {
+ /* Move from old base list to new base list. Base might have already
+ * been moved to the new base list and the first/last test ensure that
+ * case also works. */
+ base = *base_p;
+ if (!ELEM(base, new_object_bases->first, new_object_bases->last)) {
+ BLI_remlink(&view_layer->object_bases, base);
+ BLI_addtail(new_object_bases, base);
+ }
+ }
+ else {
+ /* Create new base. */
+ base = object_base_new(cob->ob);
+ *base_p = base;
+ BLI_addtail(new_object_bases, base);
+ }
+
+ if ((child_restrict & COLLECTION_RESTRICT_VIEW) == 0) {
+ base->flag_from_collection |= BASE_ENABLED_VIEWPORT;
+ if ((child_layer_restrict & LAYER_COLLECTION_RESTRICT_VIEW) == 0) {
+ base->flag_from_collection |= BASE_VISIBLE;
+ if (((child_restrict & COLLECTION_RESTRICT_SELECT) == 0)) {
+ base->flag_from_collection |= BASE_SELECTABLE;
+ }
+ }
+ }
+
+ if ((child_restrict & COLLECTION_RESTRICT_RENDER) == 0) {
+ base->flag_from_collection |= BASE_ENABLED_RENDER;
+ }
+
+ /* Holdout and indirect only */
+ if (lc->flag & LAYER_COLLECTION_HOLDOUT) {
+ base->flag_from_collection |= BASE_HOLDOUT;
+ }
+ if (lc->flag & LAYER_COLLECTION_INDIRECT_ONLY) {
+ base->flag_from_collection |= BASE_INDIRECT_ONLY;
+ }
+
+ lc->runtime_flag |= LAYER_COLLECTION_HAS_OBJECTS;
+
+ /* Make sure flags on base are usable right away. */
+ BKE_base_eval_flags(base);
+ }
+
+ runtime_flag |= lc->runtime_flag;
+ }
+
+ /* Replace layer collection list with new one. */
+ *lb_layer = new_lb_layer;
+ BLI_assert(BLI_listbase_count(lb_scene) == BLI_listbase_count(lb_layer));
+
+ return runtime_flag;
}
/**
@@ -755,102 +771,108 @@ static short layer_collection_sync(
*/
void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer)
{
- if (!scene->master_collection) {
- /* Happens for old files that don't have versioning applied yet. */
- return;
- }
-
- /* Free cache. */
- MEM_SAFE_FREE(view_layer->object_bases_array);
-
- /* Create object to base hash if it does not exist yet. */
- if (!view_layer->object_bases_hash) {
- view_layer_bases_hash_create(view_layer);
- }
-
- /* Clear visible and selectable flags to be reset. */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
- base->flag &= ~g_base_collection_flags;
- base->flag_from_collection &= ~g_base_collection_flags;
- }
-
- /* Generate new layer connections and object bases when collections changed. */
- CollectionChild child = {NULL, NULL, scene->master_collection};
- const ListBase collections = {&child, &child};
- ListBase new_object_bases = {NULL, NULL};
-
- const short parent_exclude = 0, parent_restrict = 0, parent_layer_restrict = 0;
- layer_collection_sync(
- view_layer, &collections,
- &view_layer->layer_collections, &new_object_bases,
- parent_exclude, parent_restrict, parent_layer_restrict);
-
- /* Any remaning object bases are to be removed. */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
- if (view_layer->basact == base) {
- view_layer->basact = NULL;
- }
-
- if (base->object) {
- BLI_ghash_remove(view_layer->object_bases_hash, base->object, NULL, NULL);
- }
- }
-
- BLI_freelistN(&view_layer->object_bases);
- view_layer->object_bases = new_object_bases;
-
- /* Always set a valid active collection. */
- LayerCollection *active = view_layer->active_collection;
-
- if (active && (active->flag & LAYER_COLLECTION_EXCLUDE)) {
- BKE_layer_collection_activate_parent(view_layer, active);
- }
- else if (active == NULL) {
- view_layer->active_collection = view_layer->layer_collections.first;
- }
+ if (!scene->master_collection) {
+ /* Happens for old files that don't have versioning applied yet. */
+ return;
+ }
+
+ /* Free cache. */
+ MEM_SAFE_FREE(view_layer->object_bases_array);
+
+ /* Create object to base hash if it does not exist yet. */
+ if (!view_layer->object_bases_hash) {
+ view_layer_bases_hash_create(view_layer);
+ }
+
+ /* Clear visible and selectable flags to be reset. */
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ base->flag &= ~g_base_collection_flags;
+ base->flag_from_collection &= ~g_base_collection_flags;
+ }
+
+ /* Generate new layer connections and object bases when collections changed. */
+ CollectionChild child = {NULL, NULL, scene->master_collection};
+ const ListBase collections = {&child, &child};
+ ListBase new_object_bases = {NULL, NULL};
+
+ const short parent_exclude = 0, parent_restrict = 0, parent_layer_restrict = 0;
+ layer_collection_sync(view_layer,
+ &collections,
+ &view_layer->layer_collections,
+ &new_object_bases,
+ parent_exclude,
+ parent_restrict,
+ parent_layer_restrict);
+
+ /* Any remaning object bases are to be removed. */
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (view_layer->basact == base) {
+ view_layer->basact = NULL;
+ }
+
+ if (base->object) {
+ BLI_ghash_remove(view_layer->object_bases_hash, base->object, NULL, NULL);
+ }
+ }
+
+ BLI_freelistN(&view_layer->object_bases);
+ view_layer->object_bases = new_object_bases;
+
+ /* Always set a valid active collection. */
+ LayerCollection *active = view_layer->active_collection;
+
+ if (active && (active->flag & LAYER_COLLECTION_EXCLUDE)) {
+ BKE_layer_collection_activate_parent(view_layer, active);
+ }
+ else if (active == NULL) {
+ view_layer->active_collection = view_layer->layer_collections.first;
+ }
}
void BKE_scene_collection_sync(const Scene *scene)
{
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
- BKE_layer_collection_sync(scene, view_layer);
- }
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
+ view_layer = view_layer->next) {
+ BKE_layer_collection_sync(scene, view_layer);
+ }
}
void BKE_main_collection_sync(const Main *bmain)
{
- /* TODO: if a single collection changed, figure out which
- * scenes it belongs to and only update those. */
+ /* TODO: if a single collection changed, figure out which
+ * scenes it belongs to and only update those. */
- /* TODO: optimize for file load so only linked collections get checked? */
+ /* TODO: optimize for file load so only linked collections get checked? */
- for (const Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
- BKE_scene_collection_sync(scene);
- }
+ for (const Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
+ BKE_scene_collection_sync(scene);
+ }
}
void BKE_main_collection_sync_remap(const Main *bmain)
{
- /* On remapping of object or collection pointers free caches. */
- /* TODO: try to make this faster */
+ /* On remapping of object or collection pointers free caches. */
+ /* TODO: try to make this faster */
- for (const Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
- MEM_SAFE_FREE(view_layer->object_bases_array);
+ for (const Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
+ view_layer = view_layer->next) {
+ MEM_SAFE_FREE(view_layer->object_bases_array);
- if (view_layer->object_bases_hash) {
- BLI_ghash_free(view_layer->object_bases_hash, NULL, NULL);
- view_layer->object_bases_hash = NULL;
- }
- }
- }
+ if (view_layer->object_bases_hash) {
+ BLI_ghash_free(view_layer->object_bases_hash, NULL, NULL);
+ view_layer->object_bases_hash = NULL;
+ }
+ }
+ }
- for (Collection *collection = bmain->collections.first; collection; collection = collection->id.next) {
- BKE_collection_object_cache_free(collection);
- DEG_id_tag_update_ex((Main *)bmain, &collection->id, ID_RECALC_COPY_ON_WRITE);
- }
+ for (Collection *collection = bmain->collections.first; collection;
+ collection = collection->id.next) {
+ BKE_collection_object_cache_free(collection);
+ DEG_id_tag_update_ex((Main *)bmain, &collection->id, ID_RECALC_COPY_ON_WRITE);
+ }
- BKE_main_collection_sync(bmain);
+ BKE_main_collection_sync(bmain);
}
/* ---------------------------------------------------------------------- */
@@ -863,77 +885,79 @@ void BKE_main_collection_sync_remap(const Main *bmain)
*/
bool BKE_layer_collection_objects_select(ViewLayer *view_layer, LayerCollection *lc, bool deselect)
{
- if (lc->collection->flag & COLLECTION_RESTRICT_SELECT) {
- return false;
- }
+ if (lc->collection->flag & COLLECTION_RESTRICT_SELECT) {
+ return false;
+ }
- bool changed = false;
+ bool changed = false;
- if (!(lc->flag & LAYER_COLLECTION_EXCLUDE)) {
- for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) {
- Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
+ if (!(lc->flag & LAYER_COLLECTION_EXCLUDE)) {
+ for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) {
+ Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
- if (base) {
- if (deselect) {
- if (base->flag & BASE_SELECTED) {
- base->flag &= ~BASE_SELECTED;
- changed = true;
- }
- }
- else {
- if ((base->flag & BASE_SELECTABLE) && !(base->flag & BASE_SELECTED)) {
- base->flag |= BASE_SELECTED;
- changed = true;
- }
- }
- }
- }
- }
+ if (base) {
+ if (deselect) {
+ if (base->flag & BASE_SELECTED) {
+ base->flag &= ~BASE_SELECTED;
+ changed = true;
+ }
+ }
+ else {
+ if ((base->flag & BASE_SELECTABLE) && !(base->flag & BASE_SELECTED)) {
+ base->flag |= BASE_SELECTED;
+ changed = true;
+ }
+ }
+ }
+ }
+ }
- for (LayerCollection *iter = lc->layer_collections.first; iter; iter = iter->next) {
- changed |= BKE_layer_collection_objects_select(view_layer, iter, deselect);
- }
+ for (LayerCollection *iter = lc->layer_collections.first; iter; iter = iter->next) {
+ changed |= BKE_layer_collection_objects_select(view_layer, iter, deselect);
+ }
- return changed;
+ return changed;
}
bool BKE_layer_collection_has_selected_objects(ViewLayer *view_layer, LayerCollection *lc)
{
- if (lc->collection->flag & COLLECTION_RESTRICT_SELECT) {
- return false;
- }
+ if (lc->collection->flag & COLLECTION_RESTRICT_SELECT) {
+ return false;
+ }
- if (!(lc->flag & LAYER_COLLECTION_EXCLUDE)) {
- for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) {
- Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
+ if (!(lc->flag & LAYER_COLLECTION_EXCLUDE)) {
+ for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) {
+ Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
- if (base && (base->flag & BASE_SELECTED) && (base->flag & BASE_VISIBLE)) {
- return true;
- }
- }
- }
+ if (base && (base->flag & BASE_SELECTED) && (base->flag & BASE_VISIBLE)) {
+ return true;
+ }
+ }
+ }
- for (LayerCollection *iter = lc->layer_collections.first; iter; iter = iter->next) {
- if (BKE_layer_collection_has_selected_objects(view_layer, iter)) {
- return true;
- }
- }
+ for (LayerCollection *iter = lc->layer_collections.first; iter; iter = iter->next) {
+ if (BKE_layer_collection_has_selected_objects(view_layer, iter)) {
+ return true;
+ }
+ }
- return false;
+ return false;
}
-bool BKE_layer_collection_has_layer_collection(LayerCollection *lc_parent, LayerCollection *lc_child)
+bool BKE_layer_collection_has_layer_collection(LayerCollection *lc_parent,
+ LayerCollection *lc_child)
{
- if (lc_parent == lc_child) {
- return true;
- }
+ if (lc_parent == lc_child) {
+ return true;
+ }
- for (LayerCollection *lc_iter = lc_parent->layer_collections.first; lc_iter; lc_iter = lc_iter->next) {
- if (BKE_layer_collection_has_layer_collection(lc_iter, lc_child)) {
- return true;
- }
- }
- return false;
+ for (LayerCollection *lc_iter = lc_parent->layer_collections.first; lc_iter;
+ lc_iter = lc_iter->next) {
+ if (BKE_layer_collection_has_layer_collection(lc_iter, lc_child)) {
+ return true;
+ }
+ }
+ return false;
}
/* ---------------------------------------------------------------------- */
@@ -941,36 +965,36 @@ bool BKE_layer_collection_has_layer_collection(LayerCollection *lc_parent, Layer
/* Update after toggling visibility of an object base. */
void BKE_base_set_visible(Scene *scene, ViewLayer *view_layer, Base *base, bool extend)
{
- if (!extend) {
- /* Make only one base visible. */
- for (Base *other = view_layer->object_bases.first; other; other = other->next) {
- other->flag |= BASE_HIDDEN;
- }
+ if (!extend) {
+ /* Make only one base visible. */
+ for (Base *other = view_layer->object_bases.first; other; other = other->next) {
+ other->flag |= BASE_HIDDEN;
+ }
- base->flag &= ~BASE_HIDDEN;
- }
- else {
- /* Toggle visibility of one base. */
- base->flag ^= BASE_HIDDEN;
- }
+ base->flag &= ~BASE_HIDDEN;
+ }
+ else {
+ /* Toggle visibility of one base. */
+ base->flag ^= BASE_HIDDEN;
+ }
- BKE_layer_collection_sync(scene, view_layer);
+ BKE_layer_collection_sync(scene, view_layer);
}
static void layer_collection_flag_set_recursive(LayerCollection *lc, const int flag)
{
- lc->flag |= flag;
- for (LayerCollection *lc_iter = lc->layer_collections.first; lc_iter; lc_iter = lc_iter->next) {
- layer_collection_flag_set_recursive(lc_iter, flag);
- }
+ lc->flag |= flag;
+ for (LayerCollection *lc_iter = lc->layer_collections.first; lc_iter; lc_iter = lc_iter->next) {
+ layer_collection_flag_set_recursive(lc_iter, flag);
+ }
}
static void layer_collection_flag_unset_recursive(LayerCollection *lc, const int flag)
{
- lc->flag &= ~flag;
- for (LayerCollection *lc_iter = lc->layer_collections.first; lc_iter; lc_iter = lc_iter->next) {
- layer_collection_flag_unset_recursive(lc_iter, flag);
- }
+ lc->flag &= ~flag;
+ for (LayerCollection *lc_iter = lc->layer_collections.first; lc_iter; lc_iter = lc_iter->next) {
+ layer_collection_flag_unset_recursive(lc_iter, flag);
+ }
}
/**
@@ -983,88 +1007,94 @@ static void layer_collection_flag_unset_recursive(LayerCollection *lc, const int
*
* Return whether depsgraph needs update.
*/
-bool BKE_layer_collection_isolate(Scene *scene, ViewLayer *view_layer, LayerCollection *lc, bool extend)
-{
- bool depsgraph_need_update = false;
- LayerCollection *lc_master = view_layer->layer_collections.first;
- bool hide_it = extend && (lc->runtime_flag & LAYER_COLLECTION_VISIBLE);
-
- if ((!ID_IS_LINKED(lc->collection) && !hide_it)) {
- if (lc->collection->flag & COLLECTION_RESTRICT_VIEW) {
- lc->collection->flag &= ~COLLECTION_RESTRICT_VIEW;
- depsgraph_need_update = true;
- }
- }
-
- if (!extend) {
- /* Hide all collections . */
- for (LayerCollection *lc_iter = lc_master->layer_collections.first; lc_iter; lc_iter = lc_iter->next) {
- layer_collection_flag_set_recursive(lc_iter, LAYER_COLLECTION_RESTRICT_VIEW);
- }
- }
-
- /* Make all the direct parents visible. */
- if (hide_it) {
- lc->flag |= LAYER_COLLECTION_RESTRICT_VIEW;
- }
- else {
- LayerCollection *lc_parent = lc;
- for (LayerCollection *lc_iter = lc_master->layer_collections.first; lc_iter; lc_iter = lc_iter->next) {
- if (BKE_layer_collection_has_layer_collection(lc_iter, lc)) {
- lc_parent = lc_iter;
- break;
- }
- }
-
- while (lc_parent != lc) {
- if (!ID_IS_LINKED(lc_parent->collection)) {
- if (lc_parent->collection->flag & COLLECTION_RESTRICT_VIEW) {
- lc_parent->collection->flag &= ~COLLECTION_RESTRICT_VIEW;
- depsgraph_need_update = true;
- }
- }
-
- lc_parent->flag &= ~LAYER_COLLECTION_RESTRICT_VIEW;
-
- for (LayerCollection *lc_iter = lc_parent->layer_collections.first; lc_iter; lc_iter = lc_iter->next) {
- if (BKE_layer_collection_has_layer_collection(lc_iter, lc)) {
- lc_parent = lc_iter;
- break;
- }
- }
- }
-
- /* Make all the children visible, but respect their disable state. */
- layer_collection_flag_unset_recursive(lc, LAYER_COLLECTION_RESTRICT_VIEW);
-
- BKE_layer_collection_activate(view_layer, lc);
- }
-
- BKE_layer_collection_sync(scene, view_layer);
-
- return depsgraph_need_update;
+bool BKE_layer_collection_isolate(Scene *scene,
+ ViewLayer *view_layer,
+ LayerCollection *lc,
+ bool extend)
+{
+ bool depsgraph_need_update = false;
+ LayerCollection *lc_master = view_layer->layer_collections.first;
+ bool hide_it = extend && (lc->runtime_flag & LAYER_COLLECTION_VISIBLE);
+
+ if ((!ID_IS_LINKED(lc->collection) && !hide_it)) {
+ if (lc->collection->flag & COLLECTION_RESTRICT_VIEW) {
+ lc->collection->flag &= ~COLLECTION_RESTRICT_VIEW;
+ depsgraph_need_update = true;
+ }
+ }
+
+ if (!extend) {
+ /* Hide all collections . */
+ for (LayerCollection *lc_iter = lc_master->layer_collections.first; lc_iter;
+ lc_iter = lc_iter->next) {
+ layer_collection_flag_set_recursive(lc_iter, LAYER_COLLECTION_RESTRICT_VIEW);
+ }
+ }
+
+ /* Make all the direct parents visible. */
+ if (hide_it) {
+ lc->flag |= LAYER_COLLECTION_RESTRICT_VIEW;
+ }
+ else {
+ LayerCollection *lc_parent = lc;
+ for (LayerCollection *lc_iter = lc_master->layer_collections.first; lc_iter;
+ lc_iter = lc_iter->next) {
+ if (BKE_layer_collection_has_layer_collection(lc_iter, lc)) {
+ lc_parent = lc_iter;
+ break;
+ }
+ }
+
+ while (lc_parent != lc) {
+ if (!ID_IS_LINKED(lc_parent->collection)) {
+ if (lc_parent->collection->flag & COLLECTION_RESTRICT_VIEW) {
+ lc_parent->collection->flag &= ~COLLECTION_RESTRICT_VIEW;
+ depsgraph_need_update = true;
+ }
+ }
+
+ lc_parent->flag &= ~LAYER_COLLECTION_RESTRICT_VIEW;
+
+ for (LayerCollection *lc_iter = lc_parent->layer_collections.first; lc_iter;
+ lc_iter = lc_iter->next) {
+ if (BKE_layer_collection_has_layer_collection(lc_iter, lc)) {
+ lc_parent = lc_iter;
+ break;
+ }
+ }
+ }
+
+ /* Make all the children visible, but respect their disable state. */
+ layer_collection_flag_unset_recursive(lc, LAYER_COLLECTION_RESTRICT_VIEW);
+
+ BKE_layer_collection_activate(view_layer, lc);
+ }
+
+ BKE_layer_collection_sync(scene, view_layer);
+
+ return depsgraph_need_update;
}
static void layer_collection_bases_show_recursive(ViewLayer *view_layer, LayerCollection *lc)
{
- for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) {
- Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
- base->flag &= ~BASE_HIDDEN;
- }
- for (LayerCollection *lc_iter = lc->layer_collections.first; lc_iter; lc_iter = lc_iter->next) {
- layer_collection_bases_show_recursive(view_layer, lc_iter);
- }
+ for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) {
+ Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
+ base->flag &= ~BASE_HIDDEN;
+ }
+ for (LayerCollection *lc_iter = lc->layer_collections.first; lc_iter; lc_iter = lc_iter->next) {
+ layer_collection_bases_show_recursive(view_layer, lc_iter);
+ }
}
static void layer_collection_bases_hide_recursive(ViewLayer *view_layer, LayerCollection *lc)
{
- for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) {
- Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
- base->flag |= BASE_HIDDEN;
- }
- for (LayerCollection *lc_iter = lc->layer_collections.first; lc_iter; lc_iter = lc_iter->next) {
- layer_collection_bases_hide_recursive(view_layer, lc_iter);
- }
+ for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) {
+ Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
+ base->flag |= BASE_HIDDEN;
+ }
+ for (LayerCollection *lc_iter = lc->layer_collections.first; lc_iter; lc_iter = lc_iter->next) {
+ layer_collection_bases_hide_recursive(view_layer, lc_iter);
+ }
}
/**
@@ -1073,72 +1103,75 @@ static void layer_collection_bases_hide_recursive(ViewLayer *view_layer, LayerCo
*
* Return true if depsgraph needs update.
*/
-bool BKE_layer_collection_set_visible(ViewLayer *view_layer, LayerCollection *lc, const bool visible, const bool hierarchy)
-{
- bool depsgraph_changed = false;
-
- if (visible &&
- (!ID_IS_LINKED(lc->collection)) &&
- ((lc->collection->flag & COLLECTION_RESTRICT_VIEW) != 0))
- {
- lc->collection->flag &= ~COLLECTION_RESTRICT_VIEW;
- depsgraph_changed = true;
- }
-
- if (hierarchy) {
- if (visible) {
- layer_collection_flag_unset_recursive(lc, LAYER_COLLECTION_RESTRICT_VIEW);
- layer_collection_bases_show_recursive(view_layer, lc);
- }
- else {
- layer_collection_flag_set_recursive(lc, LAYER_COLLECTION_RESTRICT_VIEW);
- layer_collection_bases_hide_recursive(view_layer, lc);
- }
- }
- else {
- if (visible) {
- lc->flag &= ~LAYER_COLLECTION_RESTRICT_VIEW;
- }
- else {
- lc->flag |= LAYER_COLLECTION_RESTRICT_VIEW;
- }
- }
- return depsgraph_changed;
+bool BKE_layer_collection_set_visible(ViewLayer *view_layer,
+ LayerCollection *lc,
+ const bool visible,
+ const bool hierarchy)
+{
+ bool depsgraph_changed = false;
+
+ if (visible && (!ID_IS_LINKED(lc->collection)) &&
+ ((lc->collection->flag & COLLECTION_RESTRICT_VIEW) != 0)) {
+ lc->collection->flag &= ~COLLECTION_RESTRICT_VIEW;
+ depsgraph_changed = true;
+ }
+
+ if (hierarchy) {
+ if (visible) {
+ layer_collection_flag_unset_recursive(lc, LAYER_COLLECTION_RESTRICT_VIEW);
+ layer_collection_bases_show_recursive(view_layer, lc);
+ }
+ else {
+ layer_collection_flag_set_recursive(lc, LAYER_COLLECTION_RESTRICT_VIEW);
+ layer_collection_bases_hide_recursive(view_layer, lc);
+ }
+ }
+ else {
+ if (visible) {
+ lc->flag &= ~LAYER_COLLECTION_RESTRICT_VIEW;
+ }
+ else {
+ lc->flag |= LAYER_COLLECTION_RESTRICT_VIEW;
+ }
+ }
+ return depsgraph_changed;
}
/* ---------------------------------------------------------------------- */
-static LayerCollection *find_layer_collection_by_scene_collection(LayerCollection *lc, const Collection *collection)
+static LayerCollection *find_layer_collection_by_scene_collection(LayerCollection *lc,
+ const Collection *collection)
{
- if (lc->collection == collection) {
- return lc;
- }
+ if (lc->collection == collection) {
+ return lc;
+ }
- for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) {
- LayerCollection *found = find_layer_collection_by_scene_collection(nlc, collection);
- if (found) {
- return found;
- }
- }
- return NULL;
+ for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) {
+ LayerCollection *found = find_layer_collection_by_scene_collection(nlc, collection);
+ if (found) {
+ return found;
+ }
+ }
+ return NULL;
}
/**
* Return the first matching LayerCollection in the ViewLayer for the Collection.
*/
-LayerCollection *BKE_layer_collection_first_from_scene_collection(ViewLayer *view_layer, const Collection *collection)
+LayerCollection *BKE_layer_collection_first_from_scene_collection(ViewLayer *view_layer,
+ const Collection *collection)
{
- for (LayerCollection *layer_collection = view_layer->layer_collections.first;
- layer_collection != NULL;
- layer_collection = layer_collection->next)
- {
- LayerCollection *found = find_layer_collection_by_scene_collection(layer_collection, collection);
+ for (LayerCollection *layer_collection = view_layer->layer_collections.first;
+ layer_collection != NULL;
+ layer_collection = layer_collection->next) {
+ LayerCollection *found = find_layer_collection_by_scene_collection(layer_collection,
+ collection);
- if (found != NULL) {
- return found;
- }
- }
- return NULL;
+ if (found != NULL) {
+ return found;
+ }
+ }
+ return NULL;
}
/**
@@ -1146,7 +1179,7 @@ LayerCollection *BKE_layer_collection_first_from_scene_collection(ViewLayer *vie
*/
bool BKE_view_layer_has_collection(ViewLayer *view_layer, const Collection *collection)
{
- return BKE_layer_collection_first_from_scene_collection(view_layer, collection) != NULL;
+ return BKE_layer_collection_first_from_scene_collection(view_layer, collection) != NULL;
}
/**
@@ -1154,13 +1187,14 @@ bool BKE_view_layer_has_collection(ViewLayer *view_layer, const Collection *coll
*/
bool BKE_scene_has_object(Scene *scene, Object *ob)
{
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
- Base *base = BKE_view_layer_base_find(view_layer, ob);
- if (base) {
- return true;
- }
- }
- return false;
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
+ view_layer = view_layer->next) {
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
+ if (base) {
+ return true;
+ }
+ }
+ return false;
}
/** \} */
@@ -1172,94 +1206,94 @@ bool BKE_scene_has_object(Scene *scene, Object *ob)
* \{ */
typedef struct LayerObjectBaseIteratorData {
- View3D *v3d;
- Base *base;
+ View3D *v3d;
+ Base *base;
} LayerObjectBaseIteratorData;
static bool object_bases_iterator_is_valid(View3D *v3d, Base *base, const int flag)
{
- BLI_assert((v3d == NULL) || (v3d->spacetype == SPACE_VIEW3D));
+ BLI_assert((v3d == NULL) || (v3d->spacetype == SPACE_VIEW3D));
- /* Any flag satisfies the condition. */
- if (flag == ~0) {
- return (base->flag != 0);
- }
+ /* Any flag satisfies the condition. */
+ if (flag == ~0) {
+ return (base->flag != 0);
+ }
- /* Flags may be more than one flag, so we can't check != 0. */
- return BASE_VISIBLE(v3d, base) && ((base->flag & flag) == flag);
+ /* Flags may be more than one flag, so we can't check != 0. */
+ return BASE_VISIBLE(v3d, base) && ((base->flag & flag) == flag);
}
static void object_bases_iterator_begin(BLI_Iterator *iter, void *data_in_v, const int flag)
{
- ObjectsVisibleIteratorData *data_in = data_in_v;
- ViewLayer *view_layer = data_in->view_layer;
- View3D *v3d = data_in->v3d;
- Base *base = view_layer->object_bases.first;
+ ObjectsVisibleIteratorData *data_in = data_in_v;
+ ViewLayer *view_layer = data_in->view_layer;
+ View3D *v3d = data_in->v3d;
+ Base *base = view_layer->object_bases.first;
- /* when there are no objects */
- if (base == NULL) {
- iter->data = NULL;
- iter->valid = false;
- return;
- }
+ /* when there are no objects */
+ if (base == NULL) {
+ iter->data = NULL;
+ iter->valid = false;
+ return;
+ }
- LayerObjectBaseIteratorData *data = MEM_callocN(sizeof(LayerObjectBaseIteratorData), __func__);
- iter->data = data;
+ LayerObjectBaseIteratorData *data = MEM_callocN(sizeof(LayerObjectBaseIteratorData), __func__);
+ iter->data = data;
- data->v3d = v3d;
- data->base = base;
+ data->v3d = v3d;
+ data->base = base;
- if (object_bases_iterator_is_valid(v3d, base, flag) == false) {
- object_bases_iterator_next(iter, flag);
- }
- else {
- iter->current = base;
- }
+ if (object_bases_iterator_is_valid(v3d, base, flag) == false) {
+ object_bases_iterator_next(iter, flag);
+ }
+ else {
+ iter->current = base;
+ }
}
static void object_bases_iterator_next(BLI_Iterator *iter, const int flag)
{
- LayerObjectBaseIteratorData *data = iter->data;
- Base *base = data->base->next;
+ LayerObjectBaseIteratorData *data = iter->data;
+ Base *base = data->base->next;
- while (base) {
- if (object_bases_iterator_is_valid(data->v3d, base, flag)) {
- iter->current = base;
- data->base = base;
- return;
- }
- base = base->next;
- }
+ while (base) {
+ if (object_bases_iterator_is_valid(data->v3d, base, flag)) {
+ iter->current = base;
+ data->base = base;
+ return;
+ }
+ base = base->next;
+ }
- iter->valid = false;
+ iter->valid = false;
}
static void object_bases_iterator_end(BLI_Iterator *iter)
{
- MEM_SAFE_FREE(iter->data);
+ MEM_SAFE_FREE(iter->data);
}
static void objects_iterator_begin(BLI_Iterator *iter, void *data_in, const int flag)
{
- object_bases_iterator_begin(iter, data_in, flag);
+ object_bases_iterator_begin(iter, data_in, flag);
- if (iter->valid) {
- iter->current = ((Base *)iter->current)->object;
- }
+ if (iter->valid) {
+ iter->current = ((Base *)iter->current)->object;
+ }
}
static void objects_iterator_next(BLI_Iterator *iter, const int flag)
{
- object_bases_iterator_next(iter, flag);
+ object_bases_iterator_next(iter, flag);
- if (iter->valid) {
- iter->current = ((Base *)iter->current)->object;
- }
+ if (iter->valid) {
+ iter->current = ((Base *)iter->current)->object;
+ }
}
static void objects_iterator_end(BLI_Iterator *iter)
{
- object_bases_iterator_end(iter);
+ object_bases_iterator_end(iter);
}
/* -------------------------------------------------------------------- */
@@ -1269,17 +1303,17 @@ static void objects_iterator_end(BLI_Iterator *iter)
void BKE_view_layer_selected_objects_iterator_begin(BLI_Iterator *iter, void *data_in)
{
- objects_iterator_begin(iter, data_in, BASE_VISIBLE | BASE_SELECTED);
+ objects_iterator_begin(iter, data_in, BASE_VISIBLE | BASE_SELECTED);
}
void BKE_view_layer_selected_objects_iterator_next(BLI_Iterator *iter)
{
- objects_iterator_next(iter, BASE_VISIBLE | BASE_SELECTED);
+ objects_iterator_next(iter, BASE_VISIBLE | BASE_SELECTED);
}
void BKE_view_layer_selected_objects_iterator_end(BLI_Iterator *iter)
{
- objects_iterator_end(iter);
+ objects_iterator_end(iter);
}
/** \} */
@@ -1290,17 +1324,17 @@ void BKE_view_layer_selected_objects_iterator_end(BLI_Iterator *iter)
void BKE_view_layer_visible_objects_iterator_begin(BLI_Iterator *iter, void *data_in)
{
- objects_iterator_begin(iter, data_in, 0);
+ objects_iterator_begin(iter, data_in, 0);
}
void BKE_view_layer_visible_objects_iterator_next(BLI_Iterator *iter)
{
- objects_iterator_next(iter, 0);
+ objects_iterator_next(iter, 0);
}
void BKE_view_layer_visible_objects_iterator_end(BLI_Iterator *iter)
{
- objects_iterator_end(iter);
+ objects_iterator_end(iter);
}
/** \} */
@@ -1311,30 +1345,30 @@ void BKE_view_layer_visible_objects_iterator_end(BLI_Iterator *iter)
void BKE_view_layer_selected_editable_objects_iterator_begin(BLI_Iterator *iter, void *data_in)
{
- objects_iterator_begin(iter, data_in, BASE_VISIBLE | BASE_SELECTED);
- if (iter->valid) {
- if (BKE_object_is_libdata((Object *)iter->current) == false) {
- // First object is valid (selectable and not libdata) -> all good.
- return;
- }
- else {
- // Object is selectable but not editable -> search for another one.
- BKE_view_layer_selected_editable_objects_iterator_next(iter);
- }
- }
+ objects_iterator_begin(iter, data_in, BASE_VISIBLE | BASE_SELECTED);
+ if (iter->valid) {
+ if (BKE_object_is_libdata((Object *)iter->current) == false) {
+ // First object is valid (selectable and not libdata) -> all good.
+ return;
+ }
+ else {
+ // Object is selectable but not editable -> search for another one.
+ BKE_view_layer_selected_editable_objects_iterator_next(iter);
+ }
+ }
}
void BKE_view_layer_selected_editable_objects_iterator_next(BLI_Iterator *iter)
{
- // Search while there are objects and the one we have is not editable (editable = not libdata).
- do {
- objects_iterator_next(iter, BASE_VISIBLE | BASE_SELECTED);
- } while (iter->valid && BKE_object_is_libdata((Object *)iter->current) != false);
+ // Search while there are objects and the one we have is not editable (editable = not libdata).
+ do {
+ objects_iterator_next(iter, BASE_VISIBLE | BASE_SELECTED);
+ } while (iter->valid && BKE_object_is_libdata((Object *)iter->current) != false);
}
void BKE_view_layer_selected_editable_objects_iterator_end(BLI_Iterator *iter)
{
- objects_iterator_end(iter);
+ objects_iterator_end(iter);
}
/** \} */
@@ -1345,17 +1379,17 @@ void BKE_view_layer_selected_editable_objects_iterator_end(BLI_Iterator *iter)
void BKE_view_layer_selected_bases_iterator_begin(BLI_Iterator *iter, void *data_in)
{
- objects_iterator_begin(iter, data_in, BASE_VISIBLE | BASE_SELECTED);
+ objects_iterator_begin(iter, data_in, BASE_VISIBLE | BASE_SELECTED);
}
void BKE_view_layer_selected_bases_iterator_next(BLI_Iterator *iter)
{
- object_bases_iterator_next(iter, BASE_VISIBLE | BASE_SELECTED);
+ object_bases_iterator_next(iter, BASE_VISIBLE | BASE_SELECTED);
}
void BKE_view_layer_selected_bases_iterator_end(BLI_Iterator *iter)
{
- object_bases_iterator_end(iter);
+ object_bases_iterator_end(iter);
}
/** \} */
@@ -1366,17 +1400,17 @@ void BKE_view_layer_selected_bases_iterator_end(BLI_Iterator *iter)
void BKE_view_layer_visible_bases_iterator_begin(BLI_Iterator *iter, void *data_in)
{
- object_bases_iterator_begin(iter, data_in, 0);
+ object_bases_iterator_begin(iter, data_in, 0);
}
void BKE_view_layer_visible_bases_iterator_next(BLI_Iterator *iter)
{
- object_bases_iterator_next(iter, 0);
+ object_bases_iterator_next(iter, 0);
}
void BKE_view_layer_visible_bases_iterator_end(BLI_Iterator *iter)
{
- object_bases_iterator_end(iter);
+ object_bases_iterator_end(iter);
}
/** \} */
@@ -1387,63 +1421,62 @@ void BKE_view_layer_visible_bases_iterator_end(BLI_Iterator *iter)
static bool base_is_in_mode(struct ObjectsInModeIteratorData *data, Base *base)
{
- return BASE_VISIBLE(data->v3d, base) &&
- (base->object->type == data->object_type) &&
- (base->object->mode & data->object_mode) != 0;
+ return BASE_VISIBLE(data->v3d, base) && (base->object->type == data->object_type) &&
+ (base->object->mode & data->object_mode) != 0;
}
void BKE_view_layer_bases_in_mode_iterator_begin(BLI_Iterator *iter, void *data_in)
{
- struct ObjectsInModeIteratorData *data = data_in;
- Base *base = data->base_active;
+ struct ObjectsInModeIteratorData *data = data_in;
+ Base *base = data->base_active;
- /* when there are no objects */
- if (base == NULL) {
- iter->valid = false;
- return;
- }
- iter->data = data_in;
- iter->current = base;
+ /* when there are no objects */
+ if (base == NULL) {
+ iter->valid = false;
+ return;
+ }
+ iter->data = data_in;
+ iter->current = base;
- /* default type is active object type */
- if (data->object_type < 0) {
- data->object_type = base->object->type;
- }
+ /* default type is active object type */
+ if (data->object_type < 0) {
+ data->object_type = base->object->type;
+ }
- if (!base_is_in_mode(data, base)) {
- BKE_view_layer_bases_in_mode_iterator_next(iter);
- }
+ if (!base_is_in_mode(data, base)) {
+ BKE_view_layer_bases_in_mode_iterator_next(iter);
+ }
}
void BKE_view_layer_bases_in_mode_iterator_next(BLI_Iterator *iter)
{
- struct ObjectsInModeIteratorData *data = iter->data;
- Base *base = iter->current;
-
- if (base == data->base_active) {
- /* first step */
- base = data->view_layer->object_bases.first;
- if (base == data->base_active) {
- base = base->next;
- }
- }
- else {
- base = base->next;
- }
-
- while (base) {
- if ((base != data->base_active) && base_is_in_mode(data, base)) {
- iter->current = base;
- return;
- }
- base = base->next;
- }
- iter->valid = false;
+ struct ObjectsInModeIteratorData *data = iter->data;
+ Base *base = iter->current;
+
+ if (base == data->base_active) {
+ /* first step */
+ base = data->view_layer->object_bases.first;
+ if (base == data->base_active) {
+ base = base->next;
+ }
+ }
+ else {
+ base = base->next;
+ }
+
+ while (base) {
+ if ((base != data->base_active) && base_is_in_mode(data, base)) {
+ iter->current = base;
+ return;
+ }
+ base = base->next;
+ }
+ iter->valid = false;
}
void BKE_view_layer_bases_in_mode_iterator_end(BLI_Iterator *UNUSED(iter))
{
- /* do nothing */
+ /* do nothing */
}
/** \} */
@@ -1454,60 +1487,58 @@ void BKE_view_layer_bases_in_mode_iterator_end(BLI_Iterator *UNUSED(iter))
* and stores those in base->flag. BASE_VISIBLE is based on viewport visibility. */
void BKE_base_eval_flags(Base *base)
{
- /* Apply collection flags. */
- base->flag &= ~g_base_collection_flags;
- base->flag |= (base->flag_from_collection & g_base_collection_flags);
-
- /* Apply object restrictions. */
- const int object_restrict = base->object->restrictflag;
- if (object_restrict & OB_RESTRICT_VIEW) {
- base->flag &= ~BASE_ENABLED_VIEWPORT;
- }
- if (object_restrict & OB_RESTRICT_RENDER) {
- base->flag &= ~BASE_ENABLED_RENDER;
- }
- if (object_restrict & OB_RESTRICT_SELECT) {
- base->flag &= ~BASE_SELECTABLE;
- }
-
- /* Apply viewport visibility by default. The dependency graph for render
- * can change these again, but for tools we always want the viewport
- * visibility to be in sync regardless if depsgraph was evaluated. */
- if (!(base->flag & BASE_ENABLED_VIEWPORT) || (base->flag & BASE_HIDDEN)) {
- base->flag &= ~(BASE_VISIBLE | BASE_SELECTABLE);
- }
-
- /* Deselect unselectable objects. */
- if (!(base->flag & BASE_SELECTABLE)) {
- base->flag &= ~BASE_SELECTED;
- }
-}
-
-static void layer_eval_view_layer(
- struct Depsgraph *depsgraph,
- struct Scene *UNUSED(scene),
- ViewLayer *view_layer)
-{
- DEG_debug_print_eval(depsgraph, __func__, view_layer->name, view_layer);
-
- /* Create array of bases, for fast index-based lookup. */
- const int num_object_bases = BLI_listbase_count(&view_layer->object_bases);
- MEM_SAFE_FREE(view_layer->object_bases_array);
- view_layer->object_bases_array = MEM_malloc_arrayN(
- num_object_bases, sizeof(Base *), "view_layer->object_bases_array");
- int base_index = 0;
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
- view_layer->object_bases_array[base_index++] = base;
- }
-}
-
-void BKE_layer_eval_view_layer_indexed(
- struct Depsgraph *depsgraph,
- struct Scene *scene,
- int view_layer_index)
-{
- BLI_assert(view_layer_index >= 0);
- ViewLayer *view_layer = BLI_findlink(&scene->view_layers, view_layer_index);
- BLI_assert(view_layer != NULL);
- layer_eval_view_layer(depsgraph, scene, view_layer);
+ /* Apply collection flags. */
+ base->flag &= ~g_base_collection_flags;
+ base->flag |= (base->flag_from_collection & g_base_collection_flags);
+
+ /* Apply object restrictions. */
+ const int object_restrict = base->object->restrictflag;
+ if (object_restrict & OB_RESTRICT_VIEW) {
+ base->flag &= ~BASE_ENABLED_VIEWPORT;
+ }
+ if (object_restrict & OB_RESTRICT_RENDER) {
+ base->flag &= ~BASE_ENABLED_RENDER;
+ }
+ if (object_restrict & OB_RESTRICT_SELECT) {
+ base->flag &= ~BASE_SELECTABLE;
+ }
+
+ /* Apply viewport visibility by default. The dependency graph for render
+ * can change these again, but for tools we always want the viewport
+ * visibility to be in sync regardless if depsgraph was evaluated. */
+ if (!(base->flag & BASE_ENABLED_VIEWPORT) || (base->flag & BASE_HIDDEN)) {
+ base->flag &= ~(BASE_VISIBLE | BASE_SELECTABLE);
+ }
+
+ /* Deselect unselectable objects. */
+ if (!(base->flag & BASE_SELECTABLE)) {
+ base->flag &= ~BASE_SELECTED;
+ }
+}
+
+static void layer_eval_view_layer(struct Depsgraph *depsgraph,
+ struct Scene *UNUSED(scene),
+ ViewLayer *view_layer)
+{
+ DEG_debug_print_eval(depsgraph, __func__, view_layer->name, view_layer);
+
+ /* Create array of bases, for fast index-based lookup. */
+ const int num_object_bases = BLI_listbase_count(&view_layer->object_bases);
+ MEM_SAFE_FREE(view_layer->object_bases_array);
+ view_layer->object_bases_array = MEM_malloc_arrayN(
+ num_object_bases, sizeof(Base *), "view_layer->object_bases_array");
+ int base_index = 0;
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ view_layer->object_bases_array[base_index++] = base;
+ }
+}
+
+void BKE_layer_eval_view_layer_indexed(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ int view_layer_index)
+{
+ BLI_assert(view_layer_index >= 0);
+ ViewLayer *view_layer = BLI_findlink(&scene->view_layers, view_layer_index);
+ BLI_assert(view_layer != NULL);
+ layer_eval_view_layer(depsgraph, scene, view_layer);
}
diff --git a/source/blender/blenkernel/intern/layer_utils.c b/source/blender/blenkernel/intern/layer_utils.c
index 9614a3ac70a..716fe63dc29 100644
--- a/source/blender/blenkernel/intern/layer_utils.c
+++ b/source/blender/blenkernel/intern/layer_utils.c
@@ -34,89 +34,93 @@
#include "MEM_guardedalloc.h"
-Base **BKE_view_layer_array_from_bases_in_mode_params(
- ViewLayer *view_layer, View3D *v3d, uint *r_len,
- const struct ObjectsInModeParams *params)
+Base **BKE_view_layer_array_from_bases_in_mode_params(ViewLayer *view_layer,
+ View3D *v3d,
+ uint *r_len,
+ const struct ObjectsInModeParams *params)
{
- if (params->no_dup_data) {
- FOREACH_BASE_IN_MODE_BEGIN(view_layer, v3d, -1, params->object_mode, base_iter) {
- ID *id = base_iter->object->data;
- if (id) {
- id->tag |= LIB_TAG_DOIT;
- }
- } FOREACH_BASE_IN_MODE_END;
- }
+ if (params->no_dup_data) {
+ FOREACH_BASE_IN_MODE_BEGIN (view_layer, v3d, -1, params->object_mode, base_iter) {
+ ID *id = base_iter->object->data;
+ if (id) {
+ id->tag |= LIB_TAG_DOIT;
+ }
+ }
+ FOREACH_BASE_IN_MODE_END;
+ }
- Base **base_array = NULL;
- BLI_array_declare(base_array);
+ Base **base_array = NULL;
+ BLI_array_declare(base_array);
- FOREACH_BASE_IN_MODE_BEGIN(view_layer, v3d, -1, params->object_mode, base_iter) {
- if (params->filter_fn) {
- if (!params->filter_fn(base_iter->object, params->filter_userdata)) {
- continue;
- }
- }
- if (params->no_dup_data) {
- ID *id = base_iter->object->data;
- if (id) {
- if (id->tag & LIB_TAG_DOIT) {
- id->tag &= ~LIB_TAG_DOIT;
- }
- else {
- continue;
- }
- }
- }
- BLI_array_append(base_array, base_iter);
- } FOREACH_BASE_IN_MODE_END;
+ FOREACH_BASE_IN_MODE_BEGIN (view_layer, v3d, -1, params->object_mode, base_iter) {
+ if (params->filter_fn) {
+ if (!params->filter_fn(base_iter->object, params->filter_userdata)) {
+ continue;
+ }
+ }
+ if (params->no_dup_data) {
+ ID *id = base_iter->object->data;
+ if (id) {
+ if (id->tag & LIB_TAG_DOIT) {
+ id->tag &= ~LIB_TAG_DOIT;
+ }
+ else {
+ continue;
+ }
+ }
+ }
+ BLI_array_append(base_array, base_iter);
+ }
+ FOREACH_BASE_IN_MODE_END;
- base_array = MEM_reallocN(base_array, sizeof(*base_array) * BLI_array_len(base_array));
- /* We always need a valid allocation (prevent crash on free). */
- if (base_array == NULL) {
- base_array = MEM_mallocN(0, __func__);
- }
- *r_len = BLI_array_len(base_array);
- return base_array;
+ base_array = MEM_reallocN(base_array, sizeof(*base_array) * BLI_array_len(base_array));
+ /* We always need a valid allocation (prevent crash on free). */
+ if (base_array == NULL) {
+ base_array = MEM_mallocN(0, __func__);
+ }
+ *r_len = BLI_array_len(base_array);
+ return base_array;
}
-Object **BKE_view_layer_array_from_objects_in_mode_params(
- ViewLayer *view_layer, View3D *v3d, uint *r_len,
- const struct ObjectsInModeParams *params)
+Object **BKE_view_layer_array_from_objects_in_mode_params(ViewLayer *view_layer,
+ View3D *v3d,
+ uint *r_len,
+ const struct ObjectsInModeParams *params)
{
- Base **base_array = BKE_view_layer_array_from_bases_in_mode_params(
- view_layer, v3d, r_len, params);
- if (base_array != NULL) {
- for (uint i = 0; i < *r_len; i++) {
- ((Object **)base_array)[i] = base_array[i]->object;
- }
- }
- return (Object **)base_array;
+ Base **base_array = BKE_view_layer_array_from_bases_in_mode_params(
+ view_layer, v3d, r_len, params);
+ if (base_array != NULL) {
+ for (uint i = 0; i < *r_len; i++) {
+ ((Object **)base_array)[i] = base_array[i]->object;
+ }
+ }
+ return (Object **)base_array;
}
bool BKE_view_layer_filter_edit_mesh_has_uvs(Object *ob, void *UNUSED(user_data))
{
- if (ob->type == OB_MESH) {
- Mesh *me = ob->data;
- BMEditMesh *em = me->edit_mesh;
- if (em != NULL) {
- if (CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV) != -1) {
- return true;
- }
- }
- }
- return false;
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+ BMEditMesh *em = me->edit_mesh;
+ if (em != NULL) {
+ if (CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV) != -1) {
+ return true;
+ }
+ }
+ }
+ return false;
}
bool BKE_view_layer_filter_edit_mesh_has_edges(Object *ob, void *UNUSED(user_data))
{
- if (ob->type == OB_MESH) {
- Mesh *me = ob->data;
- BMEditMesh *em = me->edit_mesh;
- if (em != NULL) {
- if (em->bm->totedge != 0) {
- return true;
- }
- }
- }
- return false;
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+ BMEditMesh *em = me->edit_mesh;
+ if (em != NULL) {
+ if (em->bm->totedge != 0) {
+ return true;
+ }
+ }
+ }
+ return false;
}
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index efd1e35f207..4230ab313d0 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -143,31 +143,31 @@ static CLG_LogRef LOG = {"bke.library"};
/* ************* general ************************ */
-
/* this has to be called from each make_local_* func, we could call
* from id_make_local() but then the make local functions would not be self
* contained.
* also note that the id _must_ have a library - campbell */
void BKE_id_lib_local_paths(Main *bmain, Library *lib, ID *id)
{
- const char *bpath_user_data[2] = {BKE_main_blendfile_path(bmain), lib->filepath};
+ const char *bpath_user_data[2] = {BKE_main_blendfile_path(bmain), lib->filepath};
- BKE_bpath_traverse_id(bmain, id,
- BKE_bpath_relocate_visitor,
- BKE_BPATH_TRAVERSE_SKIP_MULTIFILE,
- (void *)bpath_user_data);
+ BKE_bpath_traverse_id(bmain,
+ id,
+ BKE_bpath_relocate_visitor,
+ BKE_BPATH_TRAVERSE_SKIP_MULTIFILE,
+ (void *)bpath_user_data);
}
void id_lib_extern(ID *id)
{
- if (id && ID_IS_LINKED(id)) {
- BLI_assert(BKE_idcode_is_linkable(GS(id->name)));
- if (id->tag & LIB_TAG_INDIRECT) {
- id->tag &= ~LIB_TAG_INDIRECT;
- id->tag |= LIB_TAG_EXTERN;
- id->lib->parent = NULL;
- }
- }
+ if (id && ID_IS_LINKED(id)) {
+ BLI_assert(BKE_idcode_is_linkable(GS(id->name)));
+ if (id->tag & LIB_TAG_INDIRECT) {
+ id->tag &= ~LIB_TAG_INDIRECT;
+ id->tag |= LIB_TAG_EXTERN;
+ id->lib->parent = NULL;
+ }
+ }
}
/* ensure we have a real user */
@@ -177,29 +177,32 @@ void id_lib_extern(ID *id)
* to make this change... */
void id_us_ensure_real(ID *id)
{
- if (id) {
- const int limit = ID_FAKE_USERS(id);
- id->tag |= LIB_TAG_EXTRAUSER;
- if (id->us <= limit) {
- if (id->us < limit || ((id->us == limit) && (id->tag & LIB_TAG_EXTRAUSER_SET))) {
- CLOG_ERROR(&LOG, "ID user count error: %s (from '%s')", id->name, id->lib ? id->lib->filepath : "[Main]");
- BLI_assert(0);
- }
- id->us = limit + 1;
- id->tag |= LIB_TAG_EXTRAUSER_SET;
- }
- }
+ if (id) {
+ const int limit = ID_FAKE_USERS(id);
+ id->tag |= LIB_TAG_EXTRAUSER;
+ if (id->us <= limit) {
+ if (id->us < limit || ((id->us == limit) && (id->tag & LIB_TAG_EXTRAUSER_SET))) {
+ CLOG_ERROR(&LOG,
+ "ID user count error: %s (from '%s')",
+ id->name,
+ id->lib ? id->lib->filepath : "[Main]");
+ BLI_assert(0);
+ }
+ id->us = limit + 1;
+ id->tag |= LIB_TAG_EXTRAUSER_SET;
+ }
+ }
}
void id_us_clear_real(ID *id)
{
- if (id && (id->tag & LIB_TAG_EXTRAUSER)) {
- if (id->tag & LIB_TAG_EXTRAUSER_SET) {
- id->us--;
- BLI_assert(id->us >= ID_FAKE_USERS(id));
- }
- id->tag &= ~(LIB_TAG_EXTRAUSER | LIB_TAG_EXTRAUSER_SET);
- }
+ if (id && (id->tag & LIB_TAG_EXTRAUSER)) {
+ if (id->tag & LIB_TAG_EXTRAUSER_SET) {
+ id->us--;
+ BLI_assert(id->us >= ID_FAKE_USERS(id));
+ }
+ id->tag &= ~(LIB_TAG_EXTRAUSER | LIB_TAG_EXTRAUSER_SET);
+ }
}
/**
@@ -208,91 +211,96 @@ void id_us_clear_real(ID *id)
*/
void id_us_plus_no_lib(ID *id)
{
- if (id) {
- if ((id->tag & LIB_TAG_EXTRAUSER) && (id->tag & LIB_TAG_EXTRAUSER_SET)) {
- BLI_assert(id->us >= 1);
- /* No need to increase count, just tag extra user as no more set.
- * Avoids annoying & inconsistent +1 in user count. */
- id->tag &= ~LIB_TAG_EXTRAUSER_SET;
- }
- else {
- BLI_assert(id->us >= 0);
- id->us++;
- }
- }
+ if (id) {
+ if ((id->tag & LIB_TAG_EXTRAUSER) && (id->tag & LIB_TAG_EXTRAUSER_SET)) {
+ BLI_assert(id->us >= 1);
+ /* No need to increase count, just tag extra user as no more set.
+ * Avoids annoying & inconsistent +1 in user count. */
+ id->tag &= ~LIB_TAG_EXTRAUSER_SET;
+ }
+ else {
+ BLI_assert(id->us >= 0);
+ id->us++;
+ }
+ }
}
-
void id_us_plus(ID *id)
{
- if (id) {
- id_us_plus_no_lib(id);
- id_lib_extern(id);
- }
+ if (id) {
+ id_us_plus_no_lib(id);
+ id_lib_extern(id);
+ }
}
/* decrements the user count for *id. */
void id_us_min(ID *id)
{
- if (id) {
- const int limit = ID_FAKE_USERS(id);
-
- if (id->us <= limit) {
- CLOG_ERROR(&LOG, "ID user decrement error: %s (from '%s'): %d <= %d",
- id->name, id->lib ? id->lib->filepath : "[Main]", id->us, limit);
- BLI_assert(0);
- id->us = limit;
- }
- else {
- id->us--;
- }
-
- if ((id->us == limit) && (id->tag & LIB_TAG_EXTRAUSER)) {
- /* We need an extra user here, but never actually incremented user count for it so far, do it now. */
- id_us_ensure_real(id);
- }
- }
+ if (id) {
+ const int limit = ID_FAKE_USERS(id);
+
+ if (id->us <= limit) {
+ CLOG_ERROR(&LOG,
+ "ID user decrement error: %s (from '%s'): %d <= %d",
+ id->name,
+ id->lib ? id->lib->filepath : "[Main]",
+ id->us,
+ limit);
+ BLI_assert(0);
+ id->us = limit;
+ }
+ else {
+ id->us--;
+ }
+
+ if ((id->us == limit) && (id->tag & LIB_TAG_EXTRAUSER)) {
+ /* We need an extra user here, but never actually incremented user count for it so far, do it now. */
+ id_us_ensure_real(id);
+ }
+ }
}
void id_fake_user_set(ID *id)
{
- if (id && !(id->flag & LIB_FAKEUSER)) {
- id->flag |= LIB_FAKEUSER;
- id_us_plus(id);
- }
+ if (id && !(id->flag & LIB_FAKEUSER)) {
+ id->flag |= LIB_FAKEUSER;
+ id_us_plus(id);
+ }
}
void id_fake_user_clear(ID *id)
{
- if (id && (id->flag & LIB_FAKEUSER)) {
- id->flag &= ~LIB_FAKEUSER;
- id_us_min(id);
- }
+ if (id && (id->flag & LIB_FAKEUSER)) {
+ id->flag &= ~LIB_FAKEUSER;
+ id_us_min(id);
+ }
}
void BKE_id_clear_newpoin(ID *id)
{
- if (id->newid) {
- id->newid->tag &= ~LIB_TAG_NEW;
- }
- id->newid = NULL;
+ if (id->newid) {
+ id->newid->tag &= ~LIB_TAG_NEW;
+ }
+ id->newid = NULL;
}
-static int id_expand_local_callback(
- void *UNUSED(user_data), struct ID *id_self, struct ID **id_pointer, int cb_flag)
+static int id_expand_local_callback(void *UNUSED(user_data),
+ struct ID *id_self,
+ struct ID **id_pointer,
+ int cb_flag)
{
- if (cb_flag & IDWALK_CB_PRIVATE) {
- return IDWALK_RET_NOP;
- }
+ if (cb_flag & IDWALK_CB_PRIVATE) {
+ return IDWALK_RET_NOP;
+ }
- /* Can happen that we get unlinkable ID here, e.g. with shapekey referring to itself (through drivers)...
- * Just skip it, shape key can only be either indirectly linked, or fully local, period.
- * And let's curse one more time that stupid useless shapekey ID type! */
- if (*id_pointer && *id_pointer != id_self && BKE_idcode_is_linkable(GS((*id_pointer)->name))) {
- id_lib_extern(*id_pointer);
- }
+ /* Can happen that we get unlinkable ID here, e.g. with shapekey referring to itself (through drivers)...
+ * Just skip it, shape key can only be either indirectly linked, or fully local, period.
+ * And let's curse one more time that stupid useless shapekey ID type! */
+ if (*id_pointer && *id_pointer != id_self && BKE_idcode_is_linkable(GS((*id_pointer)->name))) {
+ id_lib_extern(*id_pointer);
+ }
- return IDWALK_RET_NOP;
+ return IDWALK_RET_NOP;
}
/**
@@ -300,7 +308,7 @@ static int id_expand_local_callback(
*/
void BKE_id_expand_local(Main *bmain, ID *id)
{
- BKE_library_foreach_ID_link(bmain, id, id_expand_local_callback, NULL, IDWALK_READONLY);
+ BKE_library_foreach_ID_link(bmain, id, id_expand_local_callback, NULL, IDWALK_READONLY);
}
/**
@@ -308,60 +316,63 @@ void BKE_id_expand_local(Main *bmain, ID *id)
*/
void BKE_id_copy_ensure_local(Main *bmain, const ID *old_id, ID *new_id)
{
- if (ID_IS_LINKED(old_id)) {
- BKE_id_expand_local(bmain, new_id);
- BKE_id_lib_local_paths(bmain, old_id->lib, new_id);
- }
+ if (ID_IS_LINKED(old_id)) {
+ BKE_id_expand_local(bmain, new_id);
+ BKE_id_lib_local_paths(bmain, old_id->lib, new_id);
+ }
}
/**
* Generic 'make local' function, works for most of datablock types...
*/
-void BKE_id_make_local_generic(Main *bmain, ID *id, const bool id_in_mainlist, const bool lib_local)
-{
- bool is_local = false, is_lib = false;
-
- /* - only lib users: do nothing (unless force_local is set)
- * - only local users: set flag
- * - mixed: make copy
- * In case we make a whole lib's content local, we always want to localize, and we skip remapping (done later).
- */
-
- if (!ID_IS_LINKED(id)) {
- return;
- }
-
- BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib);
-
- if (lib_local || is_local) {
- if (!is_lib) {
- id_clear_lib_data_ex(bmain, id, id_in_mainlist);
- BKE_id_expand_local(bmain, id);
- }
- else {
- ID *id_new;
-
- /* Should not fail in expected usecases, but a few ID types cannot be copied (LIB, WM, SCR...). */
- if (BKE_id_copy(bmain, id, &id_new)) {
- id_new->us = 0;
-
- /* setting newid is mandatory for complex make_lib_local logic... */
- ID_NEW_SET(id, id_new);
- Key *key = BKE_key_from_id(id), *key_new = BKE_key_from_id(id);
- if (key && key_new) {
- ID_NEW_SET(key, key_new);
- }
- bNodeTree *ntree = ntreeFromID(id), *ntree_new = ntreeFromID(id_new);
- if (ntree && ntree_new) {
- ID_NEW_SET(ntree, ntree_new);
- }
-
- if (!lib_local) {
- BKE_libblock_remap(bmain, id, id_new, ID_REMAP_SKIP_INDIRECT_USAGE);
- }
- }
- }
- }
+void BKE_id_make_local_generic(Main *bmain,
+ ID *id,
+ const bool id_in_mainlist,
+ const bool lib_local)
+{
+ bool is_local = false, is_lib = false;
+
+ /* - only lib users: do nothing (unless force_local is set)
+ * - only local users: set flag
+ * - mixed: make copy
+ * In case we make a whole lib's content local, we always want to localize, and we skip remapping (done later).
+ */
+
+ if (!ID_IS_LINKED(id)) {
+ return;
+ }
+
+ BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib);
+
+ if (lib_local || is_local) {
+ if (!is_lib) {
+ id_clear_lib_data_ex(bmain, id, id_in_mainlist);
+ BKE_id_expand_local(bmain, id);
+ }
+ else {
+ ID *id_new;
+
+ /* Should not fail in expected usecases, but a few ID types cannot be copied (LIB, WM, SCR...). */
+ if (BKE_id_copy(bmain, id, &id_new)) {
+ id_new->us = 0;
+
+ /* setting newid is mandatory for complex make_lib_local logic... */
+ ID_NEW_SET(id, id_new);
+ Key *key = BKE_key_from_id(id), *key_new = BKE_key_from_id(id);
+ if (key && key_new) {
+ ID_NEW_SET(key, key_new);
+ }
+ bNodeTree *ntree = ntreeFromID(id), *ntree_new = ntreeFromID(id_new);
+ if (ntree && ntree_new) {
+ ID_NEW_SET(ntree, ntree_new);
+ }
+
+ if (!lib_local) {
+ BKE_libblock_remap(bmain, id, id_new, ID_REMAP_SKIP_INDIRECT_USAGE);
+ }
+ }
+ }
+ }
}
/**
@@ -375,150 +386,184 @@ void BKE_id_make_local_generic(Main *bmain, ID *id, const bool id_in_mainlist, c
*/
bool id_make_local(Main *bmain, ID *id, const bool test, const bool lib_local)
{
- /* We don't care whether ID is directly or indirectly linked in case we are making a whole lib local... */
- if (!lib_local && (id->tag & LIB_TAG_INDIRECT)) {
- return false;
- }
-
- switch ((ID_Type)GS(id->name)) {
- case ID_SCE:
- if (!test) BKE_scene_make_local(bmain, (Scene *)id, lib_local);
- return true;
- case ID_OB:
- if (!test) BKE_object_make_local(bmain, (Object *)id, lib_local);
- return true;
- case ID_ME:
- if (!test) BKE_mesh_make_local(bmain, (Mesh *)id, lib_local);
- return true;
- case ID_CU:
- if (!test) BKE_curve_make_local(bmain, (Curve *)id, lib_local);
- return true;
- case ID_MB:
- if (!test) BKE_mball_make_local(bmain, (MetaBall *)id, lib_local);
- return true;
- case ID_MA:
- if (!test) BKE_material_make_local(bmain, (Material *)id, lib_local);
- return true;
- case ID_TE:
- if (!test) BKE_texture_make_local(bmain, (Tex *)id, lib_local);
- return true;
- case ID_IM:
- if (!test) BKE_image_make_local(bmain, (Image *)id, lib_local);
- return true;
- case ID_LT:
- if (!test) BKE_lattice_make_local(bmain, (Lattice *)id, lib_local);
- return true;
- case ID_LA:
- if (!test) BKE_light_make_local(bmain, (Light *)id, lib_local);
- return true;
- case ID_CA:
- if (!test) BKE_camera_make_local(bmain, (Camera *)id, lib_local);
- return true;
- case ID_SPK:
- if (!test) BKE_speaker_make_local(bmain, (Speaker *)id, lib_local);
- return true;
- case ID_LP:
- if (!test) BKE_lightprobe_make_local(bmain, (LightProbe *)id, lib_local);
- return true;
- case ID_WO:
- if (!test) BKE_world_make_local(bmain, (World *)id, lib_local);
- return true;
- case ID_VF:
- if (!test) BKE_vfont_make_local(bmain, (VFont *)id, lib_local);
- return true;
- case ID_TXT:
- if (!test) BKE_text_make_local(bmain, (Text *)id, lib_local);
- return true;
- case ID_SO:
- if (!test) BKE_sound_make_local(bmain, (bSound *)id, lib_local);
- return true;
- case ID_GR:
- if (!test) BKE_collection_make_local(bmain, (Collection *)id, lib_local);
- return true;
- case ID_AR:
- if (!test) BKE_armature_make_local(bmain, (bArmature *)id, lib_local);
- return true;
- case ID_AC:
- if (!test) BKE_action_make_local(bmain, (bAction *)id, lib_local);
- return true;
- case ID_NT:
- if (!test) ntreeMakeLocal(bmain, (bNodeTree *)id, true, lib_local);
- return true;
- case ID_BR:
- if (!test) BKE_brush_make_local(bmain, (Brush *)id, lib_local);
- return true;
- case ID_PA:
- if (!test) BKE_particlesettings_make_local(bmain, (ParticleSettings *)id, lib_local);
- return true;
- case ID_GD:
- if (!test) BKE_gpencil_make_local(bmain, (bGPdata *)id, lib_local);
- return true;
- case ID_MC:
- if (!test) BKE_movieclip_make_local(bmain, (MovieClip *)id, lib_local);
- return true;
- case ID_MSK:
- if (!test) BKE_mask_make_local(bmain, (Mask *)id, lib_local);
- return true;
- case ID_LS:
- if (!test) BKE_linestyle_make_local(bmain, (FreestyleLineStyle *)id, lib_local);
- return true;
- case ID_PAL:
- if (!test) BKE_palette_make_local(bmain, (Palette *)id, lib_local);
- return true;
- case ID_PC:
- if (!test) BKE_paint_curve_make_local(bmain, (PaintCurve *)id, lib_local);
- return true;
- case ID_CF:
- if (!test) BKE_cachefile_make_local(bmain, (CacheFile *)id, lib_local);
- return true;
- case ID_WS:
- case ID_SCR:
- /* A bit special: can be appended but not linked. Return false
- * since supporting make-local doesn't make much sense. */
- return false;
- case ID_LI:
- case ID_KE:
- case ID_WM:
- return false; /* can't be linked */
- case ID_IP:
- return false; /* deprecated */
- }
-
- return false;
+ /* We don't care whether ID is directly or indirectly linked in case we are making a whole lib local... */
+ if (!lib_local && (id->tag & LIB_TAG_INDIRECT)) {
+ return false;
+ }
+
+ switch ((ID_Type)GS(id->name)) {
+ case ID_SCE:
+ if (!test)
+ BKE_scene_make_local(bmain, (Scene *)id, lib_local);
+ return true;
+ case ID_OB:
+ if (!test)
+ BKE_object_make_local(bmain, (Object *)id, lib_local);
+ return true;
+ case ID_ME:
+ if (!test)
+ BKE_mesh_make_local(bmain, (Mesh *)id, lib_local);
+ return true;
+ case ID_CU:
+ if (!test)
+ BKE_curve_make_local(bmain, (Curve *)id, lib_local);
+ return true;
+ case ID_MB:
+ if (!test)
+ BKE_mball_make_local(bmain, (MetaBall *)id, lib_local);
+ return true;
+ case ID_MA:
+ if (!test)
+ BKE_material_make_local(bmain, (Material *)id, lib_local);
+ return true;
+ case ID_TE:
+ if (!test)
+ BKE_texture_make_local(bmain, (Tex *)id, lib_local);
+ return true;
+ case ID_IM:
+ if (!test)
+ BKE_image_make_local(bmain, (Image *)id, lib_local);
+ return true;
+ case ID_LT:
+ if (!test)
+ BKE_lattice_make_local(bmain, (Lattice *)id, lib_local);
+ return true;
+ case ID_LA:
+ if (!test)
+ BKE_light_make_local(bmain, (Light *)id, lib_local);
+ return true;
+ case ID_CA:
+ if (!test)
+ BKE_camera_make_local(bmain, (Camera *)id, lib_local);
+ return true;
+ case ID_SPK:
+ if (!test)
+ BKE_speaker_make_local(bmain, (Speaker *)id, lib_local);
+ return true;
+ case ID_LP:
+ if (!test)
+ BKE_lightprobe_make_local(bmain, (LightProbe *)id, lib_local);
+ return true;
+ case ID_WO:
+ if (!test)
+ BKE_world_make_local(bmain, (World *)id, lib_local);
+ return true;
+ case ID_VF:
+ if (!test)
+ BKE_vfont_make_local(bmain, (VFont *)id, lib_local);
+ return true;
+ case ID_TXT:
+ if (!test)
+ BKE_text_make_local(bmain, (Text *)id, lib_local);
+ return true;
+ case ID_SO:
+ if (!test)
+ BKE_sound_make_local(bmain, (bSound *)id, lib_local);
+ return true;
+ case ID_GR:
+ if (!test)
+ BKE_collection_make_local(bmain, (Collection *)id, lib_local);
+ return true;
+ case ID_AR:
+ if (!test)
+ BKE_armature_make_local(bmain, (bArmature *)id, lib_local);
+ return true;
+ case ID_AC:
+ if (!test)
+ BKE_action_make_local(bmain, (bAction *)id, lib_local);
+ return true;
+ case ID_NT:
+ if (!test)
+ ntreeMakeLocal(bmain, (bNodeTree *)id, true, lib_local);
+ return true;
+ case ID_BR:
+ if (!test)
+ BKE_brush_make_local(bmain, (Brush *)id, lib_local);
+ return true;
+ case ID_PA:
+ if (!test)
+ BKE_particlesettings_make_local(bmain, (ParticleSettings *)id, lib_local);
+ return true;
+ case ID_GD:
+ if (!test)
+ BKE_gpencil_make_local(bmain, (bGPdata *)id, lib_local);
+ return true;
+ case ID_MC:
+ if (!test)
+ BKE_movieclip_make_local(bmain, (MovieClip *)id, lib_local);
+ return true;
+ case ID_MSK:
+ if (!test)
+ BKE_mask_make_local(bmain, (Mask *)id, lib_local);
+ return true;
+ case ID_LS:
+ if (!test)
+ BKE_linestyle_make_local(bmain, (FreestyleLineStyle *)id, lib_local);
+ return true;
+ case ID_PAL:
+ if (!test)
+ BKE_palette_make_local(bmain, (Palette *)id, lib_local);
+ return true;
+ case ID_PC:
+ if (!test)
+ BKE_paint_curve_make_local(bmain, (PaintCurve *)id, lib_local);
+ return true;
+ case ID_CF:
+ if (!test)
+ BKE_cachefile_make_local(bmain, (CacheFile *)id, lib_local);
+ return true;
+ case ID_WS:
+ case ID_SCR:
+ /* A bit special: can be appended but not linked. Return false
+ * since supporting make-local doesn't make much sense. */
+ return false;
+ case ID_LI:
+ case ID_KE:
+ case ID_WM:
+ return false; /* can't be linked */
+ case ID_IP:
+ return false; /* deprecated */
+ }
+
+ return false;
}
struct IDCopyLibManagementData {
- const ID *id_src;
- ID *id_dst;
- int flag;
+ const ID *id_src;
+ ID *id_dst;
+ int flag;
};
/* Increases usercount as required, and remap self ID pointers. */
-static int id_copy_libmanagement_cb(void *user_data, ID *UNUSED(id_self), ID **id_pointer, int cb_flag)
+static int id_copy_libmanagement_cb(void *user_data,
+ ID *UNUSED(id_self),
+ ID **id_pointer,
+ int cb_flag)
{
- struct IDCopyLibManagementData *data = user_data;
- ID *id = *id_pointer;
+ struct IDCopyLibManagementData *data = user_data;
+ ID *id = *id_pointer;
- /* Remap self-references to new copied ID. */
- if (id == data->id_src) {
- /* We cannot use id_self here, it is not *always* id_dst (thanks to $£!+@#&/? nodetrees). */
- id = *id_pointer = data->id_dst;
- }
+ /* Remap self-references to new copied ID. */
+ if (id == data->id_src) {
+ /* We cannot use id_self here, it is not *always* id_dst (thanks to $£!+@#&/? nodetrees). */
+ id = *id_pointer = data->id_dst;
+ }
- /* Increase used IDs refcount if needed and required. */
- if ((data->flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0 && (cb_flag & IDWALK_CB_USER)) {
- id_us_plus(id);
- }
+ /* Increase used IDs refcount if needed and required. */
+ if ((data->flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0 && (cb_flag & IDWALK_CB_USER)) {
+ id_us_plus(id);
+ }
- return IDWALK_RET_NOP;
+ return IDWALK_RET_NOP;
}
bool BKE_id_copy_is_allowed(const ID *id)
{
-#define LIB_ID_TYPES_NOCOPY ID_LI, ID_SCR, ID_WM, ID_WS, /* Not supported */ \
- ID_IP /* Deprecated */
+#define LIB_ID_TYPES_NOCOPY \
+ ID_LI, ID_SCR, ID_WM, ID_WS, /* Not supported */ \
+ ID_IP /* Deprecated */
- return !ELEM(GS(id->name), LIB_ID_TYPES_NOCOPY);
+ return !ELEM(GS(id->name), LIB_ID_TYPES_NOCOPY);
#undef LIB_ID_TYPES_NOCOPY
}
@@ -539,147 +584,153 @@ bool BKE_id_copy_is_allowed(const ID *id)
*/
bool BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag)
{
- BLI_assert(r_newid != NULL);
- /* Make sure destination pointer is all good. */
- if ((flag & LIB_ID_CREATE_NO_ALLOCATE) == 0) {
- *r_newid = NULL;
- }
- else {
- if (*r_newid != NULL) {
- /* Allow some garbage non-initialized memory to go in, and clean it up here. */
- const size_t size = BKE_libblock_get_alloc_info(GS(id->name), NULL);
- memset(*r_newid, 0, size);
- }
- }
-
- /* Early output is source is NULL. */
- if (id == NULL) {
- return false;
- }
- if (!BKE_id_copy_is_allowed(id)) {
- return false;
- }
-
- BKE_libblock_copy_ex(bmain, id, r_newid, flag);
-
- switch ((ID_Type)GS(id->name)) {
- case ID_SCE:
- BKE_scene_copy_data(bmain, (Scene *)*r_newid, (Scene *)id, flag);
- break;
- case ID_OB:
- BKE_object_copy_data(bmain, (Object *)*r_newid, (Object *)id, flag);
- break;
- case ID_ME:
- BKE_mesh_copy_data(bmain, (Mesh *)*r_newid, (Mesh *)id, flag);
- break;
- case ID_CU:
- BKE_curve_copy_data(bmain, (Curve *)*r_newid, (Curve *)id, flag);
- break;
- case ID_MB:
- BKE_mball_copy_data(bmain, (MetaBall *)*r_newid, (MetaBall *)id, flag);
- break;
- case ID_MA:
- BKE_material_copy_data(bmain, (Material *)*r_newid, (Material *)id, flag);
- break;
- case ID_TE:
- BKE_texture_copy_data(bmain, (Tex *)*r_newid, (Tex *)id, flag);
- break;
- case ID_IM:
- BKE_image_copy_data(bmain, (Image *)*r_newid, (Image *)id, flag);
- break;
- case ID_LT:
- BKE_lattice_copy_data(bmain, (Lattice *)*r_newid, (Lattice *)id, flag);
- break;
- case ID_LA:
- BKE_light_copy_data(bmain, (Light *)*r_newid, (Light *)id, flag);
- break;
- case ID_SPK:
- BKE_speaker_copy_data(bmain, (Speaker *)*r_newid, (Speaker *)id, flag);
- break;
- case ID_LP:
- BKE_lightprobe_copy_data(bmain, (LightProbe *)*r_newid, (LightProbe *)id, flag);
- break;
- case ID_CA:
- BKE_camera_copy_data(bmain, (Camera *)*r_newid, (Camera *)id, flag);
- break;
- case ID_KE:
- BKE_key_copy_data(bmain, (Key *)*r_newid, (Key *)id, flag);
- break;
- case ID_WO:
- BKE_world_copy_data(bmain, (World *)*r_newid, (World *)id, flag);
- break;
- case ID_TXT:
- BKE_text_copy_data(bmain, (Text *)*r_newid, (Text *)id, flag);
- break;
- case ID_GR:
- BKE_collection_copy_data(bmain, (Collection *)*r_newid, (Collection *)id, flag);
- break;
- case ID_AR:
- BKE_armature_copy_data(bmain, (bArmature *)*r_newid, (bArmature *)id, flag);
- break;
- case ID_AC:
- BKE_action_copy_data(bmain, (bAction *)*r_newid, (bAction *)id, flag);
- break;
- case ID_NT:
- BKE_node_tree_copy_data(bmain, (bNodeTree *)*r_newid, (bNodeTree *)id, flag);
- break;
- case ID_BR:
- BKE_brush_copy_data(bmain, (Brush *)*r_newid, (Brush *)id, flag);
- break;
- case ID_PA:
- BKE_particlesettings_copy_data(bmain, (ParticleSettings *)*r_newid, (ParticleSettings *)id, flag);
- break;
- case ID_GD:
- BKE_gpencil_copy_data((bGPdata *)*r_newid, (bGPdata *)id, flag);
- break;
- case ID_MC:
- BKE_movieclip_copy_data(bmain, (MovieClip *)*r_newid, (MovieClip *)id, flag);
- break;
- case ID_MSK:
- BKE_mask_copy_data(bmain, (Mask *)*r_newid, (Mask *)id, flag);
- break;
- case ID_LS:
- BKE_linestyle_copy_data(bmain, (FreestyleLineStyle *)*r_newid, (FreestyleLineStyle *)id, flag);
- break;
- case ID_PAL:
- BKE_palette_copy_data(bmain, (Palette *)*r_newid, (Palette *)id, flag);
- break;
- case ID_PC:
- BKE_paint_curve_copy_data(bmain, (PaintCurve *)*r_newid, (PaintCurve *)id, flag);
- break;
- case ID_CF:
- BKE_cachefile_copy_data(bmain, (CacheFile *)*r_newid, (CacheFile *)id, flag);
- break;
- case ID_SO:
- BKE_sound_copy_data(bmain, (bSound *)*r_newid, (bSound *)id, flag);
- break;
- case ID_VF:
- BKE_vfont_copy_data(bmain, (VFont *)*r_newid, (VFont *)id, flag);
- break;
- case ID_LI:
- case ID_SCR:
- case ID_WM:
- case ID_WS:
- case ID_IP:
- BLI_assert(0); /* Should have been rejected at start of function! */
- break;
- }
-
- /* Update ID refcount, remap pointers to self in new ID. */
- struct IDCopyLibManagementData data = {.id_src = id, .id_dst = *r_newid, .flag = flag,};
- BKE_library_foreach_ID_link(bmain, *r_newid, id_copy_libmanagement_cb, &data, IDWALK_NOP);
-
- /* Do not make new copy local in case we are copying outside of main...
- * XXX TODO: is this behavior OK, or should we need own flag to control that? */
- if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
- BLI_assert((flag & LIB_ID_COPY_KEEP_LIB) == 0);
- BKE_id_copy_ensure_local(bmain, id, *r_newid);
- }
- else {
- (*r_newid)->lib = id->lib;
- }
-
- return true;
+ BLI_assert(r_newid != NULL);
+ /* Make sure destination pointer is all good. */
+ if ((flag & LIB_ID_CREATE_NO_ALLOCATE) == 0) {
+ *r_newid = NULL;
+ }
+ else {
+ if (*r_newid != NULL) {
+ /* Allow some garbage non-initialized memory to go in, and clean it up here. */
+ const size_t size = BKE_libblock_get_alloc_info(GS(id->name), NULL);
+ memset(*r_newid, 0, size);
+ }
+ }
+
+ /* Early output is source is NULL. */
+ if (id == NULL) {
+ return false;
+ }
+ if (!BKE_id_copy_is_allowed(id)) {
+ return false;
+ }
+
+ BKE_libblock_copy_ex(bmain, id, r_newid, flag);
+
+ switch ((ID_Type)GS(id->name)) {
+ case ID_SCE:
+ BKE_scene_copy_data(bmain, (Scene *)*r_newid, (Scene *)id, flag);
+ break;
+ case ID_OB:
+ BKE_object_copy_data(bmain, (Object *)*r_newid, (Object *)id, flag);
+ break;
+ case ID_ME:
+ BKE_mesh_copy_data(bmain, (Mesh *)*r_newid, (Mesh *)id, flag);
+ break;
+ case ID_CU:
+ BKE_curve_copy_data(bmain, (Curve *)*r_newid, (Curve *)id, flag);
+ break;
+ case ID_MB:
+ BKE_mball_copy_data(bmain, (MetaBall *)*r_newid, (MetaBall *)id, flag);
+ break;
+ case ID_MA:
+ BKE_material_copy_data(bmain, (Material *)*r_newid, (Material *)id, flag);
+ break;
+ case ID_TE:
+ BKE_texture_copy_data(bmain, (Tex *)*r_newid, (Tex *)id, flag);
+ break;
+ case ID_IM:
+ BKE_image_copy_data(bmain, (Image *)*r_newid, (Image *)id, flag);
+ break;
+ case ID_LT:
+ BKE_lattice_copy_data(bmain, (Lattice *)*r_newid, (Lattice *)id, flag);
+ break;
+ case ID_LA:
+ BKE_light_copy_data(bmain, (Light *)*r_newid, (Light *)id, flag);
+ break;
+ case ID_SPK:
+ BKE_speaker_copy_data(bmain, (Speaker *)*r_newid, (Speaker *)id, flag);
+ break;
+ case ID_LP:
+ BKE_lightprobe_copy_data(bmain, (LightProbe *)*r_newid, (LightProbe *)id, flag);
+ break;
+ case ID_CA:
+ BKE_camera_copy_data(bmain, (Camera *)*r_newid, (Camera *)id, flag);
+ break;
+ case ID_KE:
+ BKE_key_copy_data(bmain, (Key *)*r_newid, (Key *)id, flag);
+ break;
+ case ID_WO:
+ BKE_world_copy_data(bmain, (World *)*r_newid, (World *)id, flag);
+ break;
+ case ID_TXT:
+ BKE_text_copy_data(bmain, (Text *)*r_newid, (Text *)id, flag);
+ break;
+ case ID_GR:
+ BKE_collection_copy_data(bmain, (Collection *)*r_newid, (Collection *)id, flag);
+ break;
+ case ID_AR:
+ BKE_armature_copy_data(bmain, (bArmature *)*r_newid, (bArmature *)id, flag);
+ break;
+ case ID_AC:
+ BKE_action_copy_data(bmain, (bAction *)*r_newid, (bAction *)id, flag);
+ break;
+ case ID_NT:
+ BKE_node_tree_copy_data(bmain, (bNodeTree *)*r_newid, (bNodeTree *)id, flag);
+ break;
+ case ID_BR:
+ BKE_brush_copy_data(bmain, (Brush *)*r_newid, (Brush *)id, flag);
+ break;
+ case ID_PA:
+ BKE_particlesettings_copy_data(
+ bmain, (ParticleSettings *)*r_newid, (ParticleSettings *)id, flag);
+ break;
+ case ID_GD:
+ BKE_gpencil_copy_data((bGPdata *)*r_newid, (bGPdata *)id, flag);
+ break;
+ case ID_MC:
+ BKE_movieclip_copy_data(bmain, (MovieClip *)*r_newid, (MovieClip *)id, flag);
+ break;
+ case ID_MSK:
+ BKE_mask_copy_data(bmain, (Mask *)*r_newid, (Mask *)id, flag);
+ break;
+ case ID_LS:
+ BKE_linestyle_copy_data(
+ bmain, (FreestyleLineStyle *)*r_newid, (FreestyleLineStyle *)id, flag);
+ break;
+ case ID_PAL:
+ BKE_palette_copy_data(bmain, (Palette *)*r_newid, (Palette *)id, flag);
+ break;
+ case ID_PC:
+ BKE_paint_curve_copy_data(bmain, (PaintCurve *)*r_newid, (PaintCurve *)id, flag);
+ break;
+ case ID_CF:
+ BKE_cachefile_copy_data(bmain, (CacheFile *)*r_newid, (CacheFile *)id, flag);
+ break;
+ case ID_SO:
+ BKE_sound_copy_data(bmain, (bSound *)*r_newid, (bSound *)id, flag);
+ break;
+ case ID_VF:
+ BKE_vfont_copy_data(bmain, (VFont *)*r_newid, (VFont *)id, flag);
+ break;
+ case ID_LI:
+ case ID_SCR:
+ case ID_WM:
+ case ID_WS:
+ case ID_IP:
+ BLI_assert(0); /* Should have been rejected at start of function! */
+ break;
+ }
+
+ /* Update ID refcount, remap pointers to self in new ID. */
+ struct IDCopyLibManagementData data = {
+ .id_src = id,
+ .id_dst = *r_newid,
+ .flag = flag,
+ };
+ BKE_library_foreach_ID_link(bmain, *r_newid, id_copy_libmanagement_cb, &data, IDWALK_NOP);
+
+ /* Do not make new copy local in case we are copying outside of main...
+ * XXX TODO: is this behavior OK, or should we need own flag to control that? */
+ if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
+ BLI_assert((flag & LIB_ID_COPY_KEEP_LIB) == 0);
+ BKE_id_copy_ensure_local(bmain, id, *r_newid);
+ }
+ else {
+ (*r_newid)->lib = id->lib;
+ }
+
+ return true;
}
/**
@@ -688,210 +739,216 @@ bool BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag)
*/
bool BKE_id_copy(Main *bmain, const ID *id, ID **newid)
{
- return BKE_id_copy_ex(bmain, id, newid, LIB_ID_COPY_DEFAULT);
+ return BKE_id_copy_ex(bmain, id, newid, LIB_ID_COPY_DEFAULT);
}
/** Does a mere memory swap over the whole IDs data (including type-specific memory).
* \note Most internal ID data itself is not swapped (only IDProperties are). */
void BKE_id_swap(Main *bmain, ID *id_a, ID *id_b)
{
- BLI_assert(GS(id_a->name) == GS(id_b->name));
+ BLI_assert(GS(id_a->name) == GS(id_b->name));
- const ID id_a_back = *id_a;
- const ID id_b_back = *id_b;
+ const ID id_a_back = *id_a;
+ const ID id_b_back = *id_b;
#define CASE_SWAP(_gs, _type) \
- case _gs: \
- SWAP(_type, *(_type *)id_a, *(_type *)id_b); \
- break
-
- switch ((ID_Type)GS(id_a->name)) {
- CASE_SWAP(ID_SCE, Scene);
- CASE_SWAP(ID_LI, Library);
- CASE_SWAP(ID_OB, Object);
- CASE_SWAP(ID_ME, Mesh);
- CASE_SWAP(ID_CU, Curve);
- CASE_SWAP(ID_MB, MetaBall);
- CASE_SWAP(ID_MA, Material);
- CASE_SWAP(ID_TE, Tex);
- CASE_SWAP(ID_IM, Image);
- CASE_SWAP(ID_LT, Lattice);
- CASE_SWAP(ID_LA, Light);
- CASE_SWAP(ID_LP, LightProbe);
- CASE_SWAP(ID_CA, Camera);
- CASE_SWAP(ID_KE, Key);
- CASE_SWAP(ID_WO, World);
- CASE_SWAP(ID_SCR, bScreen);
- CASE_SWAP(ID_VF, VFont);
- CASE_SWAP(ID_TXT, Text);
- CASE_SWAP(ID_SPK, Speaker);
- CASE_SWAP(ID_SO, bSound);
- CASE_SWAP(ID_GR, Collection);
- CASE_SWAP(ID_AR, bArmature);
- CASE_SWAP(ID_AC, bAction);
- CASE_SWAP(ID_NT, bNodeTree);
- CASE_SWAP(ID_BR, Brush);
- CASE_SWAP(ID_PA, ParticleSettings);
- CASE_SWAP(ID_WM, wmWindowManager);
- CASE_SWAP(ID_WS, WorkSpace);
- CASE_SWAP(ID_GD, bGPdata);
- CASE_SWAP(ID_MC, MovieClip);
- CASE_SWAP(ID_MSK, Mask);
- CASE_SWAP(ID_LS, FreestyleLineStyle);
- CASE_SWAP(ID_PAL, Palette);
- CASE_SWAP(ID_PC, PaintCurve);
- CASE_SWAP(ID_CF, CacheFile);
- case ID_IP:
- break; /* Deprecated. */
- }
+ case _gs: \
+ SWAP(_type, *(_type *)id_a, *(_type *)id_b); \
+ break
+
+ switch ((ID_Type)GS(id_a->name)) {
+ CASE_SWAP(ID_SCE, Scene);
+ CASE_SWAP(ID_LI, Library);
+ CASE_SWAP(ID_OB, Object);
+ CASE_SWAP(ID_ME, Mesh);
+ CASE_SWAP(ID_CU, Curve);
+ CASE_SWAP(ID_MB, MetaBall);
+ CASE_SWAP(ID_MA, Material);
+ CASE_SWAP(ID_TE, Tex);
+ CASE_SWAP(ID_IM, Image);
+ CASE_SWAP(ID_LT, Lattice);
+ CASE_SWAP(ID_LA, Light);
+ CASE_SWAP(ID_LP, LightProbe);
+ CASE_SWAP(ID_CA, Camera);
+ CASE_SWAP(ID_KE, Key);
+ CASE_SWAP(ID_WO, World);
+ CASE_SWAP(ID_SCR, bScreen);
+ CASE_SWAP(ID_VF, VFont);
+ CASE_SWAP(ID_TXT, Text);
+ CASE_SWAP(ID_SPK, Speaker);
+ CASE_SWAP(ID_SO, bSound);
+ CASE_SWAP(ID_GR, Collection);
+ CASE_SWAP(ID_AR, bArmature);
+ CASE_SWAP(ID_AC, bAction);
+ CASE_SWAP(ID_NT, bNodeTree);
+ CASE_SWAP(ID_BR, Brush);
+ CASE_SWAP(ID_PA, ParticleSettings);
+ CASE_SWAP(ID_WM, wmWindowManager);
+ CASE_SWAP(ID_WS, WorkSpace);
+ CASE_SWAP(ID_GD, bGPdata);
+ CASE_SWAP(ID_MC, MovieClip);
+ CASE_SWAP(ID_MSK, Mask);
+ CASE_SWAP(ID_LS, FreestyleLineStyle);
+ CASE_SWAP(ID_PAL, Palette);
+ CASE_SWAP(ID_PC, PaintCurve);
+ CASE_SWAP(ID_CF, CacheFile);
+ case ID_IP:
+ break; /* Deprecated. */
+ }
#undef CASE_SWAP
- /* Restore original ID's internal data. */
- *id_a = id_a_back;
- *id_b = id_b_back;
+ /* Restore original ID's internal data. */
+ *id_a = id_a_back;
+ *id_b = id_b_back;
- /* Exception: IDProperties. */
- id_a->properties = id_b_back.properties;
- id_b->properties = id_a_back.properties;
+ /* Exception: IDProperties. */
+ id_a->properties = id_b_back.properties;
+ id_b->properties = id_a_back.properties;
- /* Swap will have broken internal references to itself, restore them. */
- BKE_libblock_relink_ex(bmain, id_a, id_b, id_a, false);
- BKE_libblock_relink_ex(bmain, id_b, id_a, id_b, false);
+ /* Swap will have broken internal references to itself, restore them. */
+ BKE_libblock_relink_ex(bmain, id_a, id_b, id_a, false);
+ BKE_libblock_relink_ex(bmain, id_b, id_a, id_b, false);
}
/** Does *not* set ID->newid pointer. */
bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop)
{
- ID *newid = NULL;
- PointerRNA idptr;
+ ID *newid = NULL;
+ PointerRNA idptr;
- if (id) {
- /* if property isn't editable, we're going to have an extra block hanging around until we save */
- if (RNA_property_editable(ptr, prop)) {
- Main *bmain = CTX_data_main(C);
- /* copy animation actions too */
- if (BKE_id_copy_ex(bmain, id, &newid, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS) && newid) {
- /* us is 1 by convention with new IDs, but RNA_property_pointer_set
- * will also increment it, decrement it here. */
- id_us_min(newid);
+ if (id) {
+ /* if property isn't editable, we're going to have an extra block hanging around until we save */
+ if (RNA_property_editable(ptr, prop)) {
+ Main *bmain = CTX_data_main(C);
+ /* copy animation actions too */
+ if (BKE_id_copy_ex(bmain, id, &newid, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS) && newid) {
+ /* us is 1 by convention with new IDs, but RNA_property_pointer_set
+ * will also increment it, decrement it here. */
+ id_us_min(newid);
- /* assign copy */
- RNA_id_pointer_create(newid, &idptr);
- RNA_property_pointer_set(ptr, prop, idptr);
- RNA_property_update(C, ptr, prop);
+ /* assign copy */
+ RNA_id_pointer_create(newid, &idptr);
+ RNA_property_pointer_set(ptr, prop, idptr);
+ RNA_property_update(C, ptr, prop);
- /* tag grease pencil datablock and disable onion */
- if (GS(id->name) == ID_GD) {
- DEG_id_tag_update(id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- DEG_id_tag_update(newid, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- bGPdata *gpd = (bGPdata *)newid;
- gpd->flag &= ~GP_DATA_SHOW_ONIONSKINS;
- }
+ /* tag grease pencil datablock and disable onion */
+ if (GS(id->name) == ID_GD) {
+ DEG_id_tag_update(id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ DEG_id_tag_update(newid, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ bGPdata *gpd = (bGPdata *)newid;
+ gpd->flag &= ~GP_DATA_SHOW_ONIONSKINS;
+ }
- return true;
- }
- }
- }
+ return true;
+ }
+ }
+ }
- return false;
+ return false;
}
-static int libblock_management_us_plus(void *UNUSED(user_data), ID *UNUSED(id_self), ID **id_pointer, int cb_flag)
+static int libblock_management_us_plus(void *UNUSED(user_data),
+ ID *UNUSED(id_self),
+ ID **id_pointer,
+ int cb_flag)
{
- if (cb_flag & IDWALK_CB_USER) {
- id_us_plus(*id_pointer);
- }
- if (cb_flag & IDWALK_CB_USER_ONE) {
- id_us_ensure_real(*id_pointer);
- }
+ if (cb_flag & IDWALK_CB_USER) {
+ id_us_plus(*id_pointer);
+ }
+ if (cb_flag & IDWALK_CB_USER_ONE) {
+ id_us_ensure_real(*id_pointer);
+ }
- return IDWALK_RET_NOP;
+ return IDWALK_RET_NOP;
}
-static int libblock_management_us_min(void *UNUSED(user_data), ID *UNUSED(id_self), ID **id_pointer, int cb_flag)
+static int libblock_management_us_min(void *UNUSED(user_data),
+ ID *UNUSED(id_self),
+ ID **id_pointer,
+ int cb_flag)
{
- if (cb_flag & IDWALK_CB_USER) {
- id_us_min(*id_pointer);
- }
- /* We can do nothing in IDWALK_CB_USER_ONE case! */
+ if (cb_flag & IDWALK_CB_USER) {
+ id_us_min(*id_pointer);
+ }
+ /* We can do nothing in IDWALK_CB_USER_ONE case! */
- return IDWALK_RET_NOP;
+ return IDWALK_RET_NOP;
}
/** Add a 'NO_MAIN' datablock to given main (also sets usercounts of its IDs if needed). */
void BKE_libblock_management_main_add(Main *bmain, void *idv)
{
- ID *id = idv;
+ ID *id = idv;
- BLI_assert(bmain != NULL);
- if ((id->tag & LIB_TAG_NO_MAIN) == 0) {
- return;
- }
+ BLI_assert(bmain != NULL);
+ if ((id->tag & LIB_TAG_NO_MAIN) == 0) {
+ return;
+ }
- if ((id->tag & LIB_TAG_NOT_ALLOCATED) != 0) {
- /* We cannot add non-allocated ID to Main! */
- return;
- }
+ if ((id->tag & LIB_TAG_NOT_ALLOCATED) != 0) {
+ /* We cannot add non-allocated ID to Main! */
+ return;
+ }
- /* We cannot allow non-userrefcounting IDs in Main database! */
- if ((id->tag & LIB_TAG_NO_USER_REFCOUNT) != 0) {
- BKE_library_foreach_ID_link(bmain, id, libblock_management_us_plus, NULL, IDWALK_NOP);
- }
+ /* We cannot allow non-userrefcounting IDs in Main database! */
+ if ((id->tag & LIB_TAG_NO_USER_REFCOUNT) != 0) {
+ BKE_library_foreach_ID_link(bmain, id, libblock_management_us_plus, NULL, IDWALK_NOP);
+ }
- ListBase *lb = which_libbase(bmain, GS(id->name));
- BKE_main_lock(bmain);
- BLI_addtail(lb, id);
- BKE_id_new_name_validate(lb, id, NULL);
- /* alphabetic insertion: is in new_id */
- id->tag &= ~(LIB_TAG_NO_MAIN | LIB_TAG_NO_USER_REFCOUNT);
- bmain->is_memfile_undo_written = false;
- BKE_main_unlock(bmain);
+ ListBase *lb = which_libbase(bmain, GS(id->name));
+ BKE_main_lock(bmain);
+ BLI_addtail(lb, id);
+ BKE_id_new_name_validate(lb, id, NULL);
+ /* alphabetic insertion: is in new_id */
+ id->tag &= ~(LIB_TAG_NO_MAIN | LIB_TAG_NO_USER_REFCOUNT);
+ bmain->is_memfile_undo_written = false;
+ BKE_main_unlock(bmain);
}
/** Remove a datablock from given main (set it to 'NO_MAIN' status). */
void BKE_libblock_management_main_remove(Main *bmain, void *idv)
{
- ID *id = idv;
+ ID *id = idv;
- BLI_assert(bmain != NULL);
- if ((id->tag & LIB_TAG_NO_MAIN) != 0) {
- return;
- }
+ BLI_assert(bmain != NULL);
+ if ((id->tag & LIB_TAG_NO_MAIN) != 0) {
+ return;
+ }
- /* For now, allow userrefcounting IDs to get out of Main - can be handy in some cases... */
+ /* For now, allow userrefcounting IDs to get out of Main - can be handy in some cases... */
- ListBase *lb = which_libbase(bmain, GS(id->name));
- BKE_main_lock(bmain);
- BLI_remlink(lb, id);
- id->tag |= LIB_TAG_NO_MAIN;
- bmain->is_memfile_undo_written = false;
- BKE_main_unlock(bmain);
+ ListBase *lb = which_libbase(bmain, GS(id->name));
+ BKE_main_lock(bmain);
+ BLI_remlink(lb, id);
+ id->tag |= LIB_TAG_NO_MAIN;
+ bmain->is_memfile_undo_written = false;
+ BKE_main_unlock(bmain);
}
void BKE_libblock_management_usercounts_set(Main *bmain, void *idv)
{
- ID *id = idv;
+ ID *id = idv;
- if ((id->tag & LIB_TAG_NO_USER_REFCOUNT) == 0) {
- return;
- }
+ if ((id->tag & LIB_TAG_NO_USER_REFCOUNT) == 0) {
+ return;
+ }
- BKE_library_foreach_ID_link(bmain, id, libblock_management_us_plus, NULL, IDWALK_NOP);
- id->tag &= ~LIB_TAG_NO_USER_REFCOUNT;
+ BKE_library_foreach_ID_link(bmain, id, libblock_management_us_plus, NULL, IDWALK_NOP);
+ id->tag &= ~LIB_TAG_NO_USER_REFCOUNT;
}
void BKE_libblock_management_usercounts_clear(Main *bmain, void *idv)
{
- ID *id = idv;
+ ID *id = idv;
- /* We do not allow IDs in Main database to not be userrefcounting. */
- if ((id->tag & LIB_TAG_NO_USER_REFCOUNT) != 0 || (id->tag & LIB_TAG_NO_MAIN) != 0) {
- return;
- }
+ /* We do not allow IDs in Main database to not be userrefcounting. */
+ if ((id->tag & LIB_TAG_NO_USER_REFCOUNT) != 0 || (id->tag & LIB_TAG_NO_MAIN) != 0) {
+ return;
+ }
- BKE_library_foreach_ID_link(bmain, id, libblock_management_us_min, NULL, IDWALK_NOP);
- id->tag |= LIB_TAG_NO_USER_REFCOUNT;
+ BKE_library_foreach_ID_link(bmain, id, libblock_management_us_min, NULL, IDWALK_NOP);
+ id->tag |= LIB_TAG_NO_USER_REFCOUNT;
}
/**
@@ -899,28 +956,31 @@ void BKE_libblock_management_usercounts_clear(Main *bmain, void *idv)
*/
void BKE_main_id_tag_listbase(ListBase *lb, const int tag, const bool value)
{
- ID *id;
- if (value) {
- for (id = lb->first; id; id = id->next) {
- id->tag |= tag;
- }
- }
- else {
- const int ntag = ~tag;
- for (id = lb->first; id; id = id->next) {
- id->tag &= ntag;
- }
- }
+ ID *id;
+ if (value) {
+ for (id = lb->first; id; id = id->next) {
+ id->tag |= tag;
+ }
+ }
+ else {
+ const int ntag = ~tag;
+ for (id = lb->first; id; id = id->next) {
+ id->tag &= ntag;
+ }
+ }
}
/**
* Clear or set given tags for all ids of given type in bmain (runtime tags).
*/
-void BKE_main_id_tag_idcode(struct Main *mainvar, const short type, const int tag, const bool value)
+void BKE_main_id_tag_idcode(struct Main *mainvar,
+ const short type,
+ const int tag,
+ const bool value)
{
- ListBase *lb = which_libbase(mainvar, type);
+ ListBase *lb = which_libbase(mainvar, type);
- BKE_main_id_tag_listbase(lb, tag, value);
+ BKE_main_id_tag_listbase(lb, tag, value);
}
/**
@@ -928,31 +988,30 @@ void BKE_main_id_tag_idcode(struct Main *mainvar, const short type, const int ta
*/
void BKE_main_id_tag_all(struct Main *mainvar, const int tag, const bool value)
{
- ListBase *lbarray[MAX_LIBARRAY];
- int a;
+ ListBase *lbarray[MAX_LIBARRAY];
+ int a;
- a = set_listbasepointers(mainvar, lbarray);
- while (a--) {
- BKE_main_id_tag_listbase(lbarray[a], tag, value);
- }
+ a = set_listbasepointers(mainvar, lbarray);
+ while (a--) {
+ BKE_main_id_tag_listbase(lbarray[a], tag, value);
+ }
}
-
/**
* Clear or set given flags for all ids in listbase (persistent flags).
*/
void BKE_main_id_flag_listbase(ListBase *lb, const int flag, const bool value)
{
- ID *id;
- if (value) {
- for (id = lb->first; id; id = id->next)
- id->tag |= flag;
- }
- else {
- const int nflag = ~flag;
- for (id = lb->first; id; id = id->next)
- id->tag &= nflag;
- }
+ ID *id;
+ if (value) {
+ for (id = lb->first; id; id = id->next)
+ id->tag |= flag;
+ }
+ else {
+ const int nflag = ~flag;
+ for (id = lb->first; id; id = id->next)
+ id->tag &= nflag;
+ }
}
/**
@@ -960,57 +1019,57 @@ void BKE_main_id_flag_listbase(ListBase *lb, const int flag, const bool value)
*/
void BKE_main_id_flag_all(Main *bmain, const int flag, const bool value)
{
- ListBase *lbarray[MAX_LIBARRAY];
- int a;
- a = set_listbasepointers(bmain, lbarray);
- while (a--) {
- BKE_main_id_flag_listbase(lbarray[a], flag, value);
- }
+ ListBase *lbarray[MAX_LIBARRAY];
+ int a;
+ a = set_listbasepointers(bmain, lbarray);
+ while (a--) {
+ BKE_main_id_flag_listbase(lbarray[a], flag, value);
+ }
}
void BKE_main_id_repair_duplicate_names_listbase(ListBase *lb)
{
- int lb_len = 0;
- for (ID *id = lb->first; id; id = id->next) {
- if (id->lib == NULL) {
- lb_len += 1;
- }
- }
- if (lb_len <= 1) {
- return;
- }
-
- /* Fill an array because renaming sorts. */
- ID **id_array = MEM_mallocN(sizeof(*id_array) * lb_len, __func__);
- GSet *gset = BLI_gset_str_new_ex(__func__, lb_len);
- int i = 0;
- for (ID *id = lb->first; id; id = id->next) {
- if (id->lib == NULL) {
- id_array[i] = id;
- i++;
- }
- }
- for (i = 0; i < lb_len; i++) {
- if (!BLI_gset_add(gset, id_array[i]->name + 2)) {
- BKE_id_new_name_validate(lb, id_array[i], NULL);
- }
- }
- BLI_gset_free(gset, NULL);
- MEM_freeN(id_array);
+ int lb_len = 0;
+ for (ID *id = lb->first; id; id = id->next) {
+ if (id->lib == NULL) {
+ lb_len += 1;
+ }
+ }
+ if (lb_len <= 1) {
+ return;
+ }
+
+ /* Fill an array because renaming sorts. */
+ ID **id_array = MEM_mallocN(sizeof(*id_array) * lb_len, __func__);
+ GSet *gset = BLI_gset_str_new_ex(__func__, lb_len);
+ int i = 0;
+ for (ID *id = lb->first; id; id = id->next) {
+ if (id->lib == NULL) {
+ id_array[i] = id;
+ i++;
+ }
+ }
+ for (i = 0; i < lb_len; i++) {
+ if (!BLI_gset_add(gset, id_array[i]->name + 2)) {
+ BKE_id_new_name_validate(lb, id_array[i], NULL);
+ }
+ }
+ BLI_gset_free(gset, NULL);
+ MEM_freeN(id_array);
}
void BKE_main_lib_objects_recalc_all(Main *bmain)
{
- Object *ob;
+ Object *ob;
- /* flag for full recalc */
- for (ob = bmain->objects.first; ob; ob = ob->id.next) {
- if (ID_IS_LINKED(ob)) {
- DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
- }
- }
+ /* flag for full recalc */
+ for (ob = bmain->objects.first; ob; ob = ob->id.next) {
+ if (ID_IS_LINKED(ob)) {
+ DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
+ }
+ }
- DEG_id_type_tag(bmain, ID_OB);
+ DEG_id_type_tag(bmain, ID_OB);
}
/* *********** ALLOC AND FREE *****************
@@ -1028,54 +1087,54 @@ void BKE_main_lib_objects_recalc_all(Main *bmain)
*/
size_t BKE_libblock_get_alloc_info(short type, const char **name)
{
-#define CASE_RETURN(id_code, type) \
- case id_code: \
- do { \
- if (name != NULL) { \
- *name = #type; \
- } \
- return sizeof(type); \
- } while(0)
-
- switch ((ID_Type)type) {
- CASE_RETURN(ID_SCE, Scene);
- CASE_RETURN(ID_LI, Library);
- CASE_RETURN(ID_OB, Object);
- CASE_RETURN(ID_ME, Mesh);
- CASE_RETURN(ID_CU, Curve);
- CASE_RETURN(ID_MB, MetaBall);
- CASE_RETURN(ID_MA, Material);
- CASE_RETURN(ID_TE, Tex);
- CASE_RETURN(ID_IM, Image);
- CASE_RETURN(ID_LT, Lattice);
- CASE_RETURN(ID_LA, Light);
- CASE_RETURN(ID_CA, Camera);
- CASE_RETURN(ID_IP, Ipo);
- CASE_RETURN(ID_KE, Key);
- CASE_RETURN(ID_WO, World);
- CASE_RETURN(ID_SCR, bScreen);
- CASE_RETURN(ID_VF, VFont);
- CASE_RETURN(ID_TXT, Text);
- CASE_RETURN(ID_SPK, Speaker);
- CASE_RETURN(ID_LP, LightProbe);
- CASE_RETURN(ID_SO, bSound);
- CASE_RETURN(ID_GR, Collection);
- CASE_RETURN(ID_AR, bArmature);
- CASE_RETURN(ID_AC, bAction);
- CASE_RETURN(ID_NT, bNodeTree);
- CASE_RETURN(ID_BR, Brush);
- CASE_RETURN(ID_PA, ParticleSettings);
- CASE_RETURN(ID_WM, wmWindowManager);
- CASE_RETURN(ID_GD, bGPdata);
- CASE_RETURN(ID_MC, MovieClip);
- CASE_RETURN(ID_MSK, Mask);
- CASE_RETURN(ID_LS, FreestyleLineStyle);
- CASE_RETURN(ID_PAL, Palette);
- CASE_RETURN(ID_PC, PaintCurve);
- CASE_RETURN(ID_CF, CacheFile);
- CASE_RETURN(ID_WS, WorkSpace);
- }
- return 0;
+#define CASE_RETURN(id_code, type) \
+ case id_code: \
+ do { \
+ if (name != NULL) { \
+ *name = #type; \
+ } \
+ return sizeof(type); \
+ } while (0)
+
+ switch ((ID_Type)type) {
+ CASE_RETURN(ID_SCE, Scene);
+ CASE_RETURN(ID_LI, Library);
+ CASE_RETURN(ID_OB, Object);
+ CASE_RETURN(ID_ME, Mesh);
+ CASE_RETURN(ID_CU, Curve);
+ CASE_RETURN(ID_MB, MetaBall);
+ CASE_RETURN(ID_MA, Material);
+ CASE_RETURN(ID_TE, Tex);
+ CASE_RETURN(ID_IM, Image);
+ CASE_RETURN(ID_LT, Lattice);
+ CASE_RETURN(ID_LA, Light);
+ CASE_RETURN(ID_CA, Camera);
+ CASE_RETURN(ID_IP, Ipo);
+ CASE_RETURN(ID_KE, Key);
+ CASE_RETURN(ID_WO, World);
+ CASE_RETURN(ID_SCR, bScreen);
+ CASE_RETURN(ID_VF, VFont);
+ CASE_RETURN(ID_TXT, Text);
+ CASE_RETURN(ID_SPK, Speaker);
+ CASE_RETURN(ID_LP, LightProbe);
+ CASE_RETURN(ID_SO, bSound);
+ CASE_RETURN(ID_GR, Collection);
+ CASE_RETURN(ID_AR, bArmature);
+ CASE_RETURN(ID_AC, bAction);
+ CASE_RETURN(ID_NT, bNodeTree);
+ CASE_RETURN(ID_BR, Brush);
+ CASE_RETURN(ID_PA, ParticleSettings);
+ CASE_RETURN(ID_WM, wmWindowManager);
+ CASE_RETURN(ID_GD, bGPdata);
+ CASE_RETURN(ID_MC, MovieClip);
+ CASE_RETURN(ID_MSK, Mask);
+ CASE_RETURN(ID_LS, FreestyleLineStyle);
+ CASE_RETURN(ID_PAL, Palette);
+ CASE_RETURN(ID_PC, PaintCurve);
+ CASE_RETURN(ID_CF, CacheFile);
+ CASE_RETURN(ID_WS, WorkSpace);
+ }
+ return 0;
#undef CASE_RETURN
}
@@ -1085,13 +1144,13 @@ size_t BKE_libblock_get_alloc_info(short type, const char **name)
*/
void *BKE_libblock_alloc_notest(short type)
{
- const char *name;
- size_t size = BKE_libblock_get_alloc_info(type, &name);
- if (size != 0) {
- return MEM_callocN(size, name);
- }
- BLI_assert(!"Request to allocate unknown data type");
- return NULL;
+ const char *name;
+ size_t size = BKE_libblock_get_alloc_info(type, &name);
+ if (size != 0) {
+ return MEM_callocN(size, name);
+ }
+ BLI_assert(!"Request to allocate unknown data type");
+ return NULL;
}
/**
@@ -1102,44 +1161,44 @@ void *BKE_libblock_alloc_notest(short type)
*/
void *BKE_libblock_alloc(Main *bmain, short type, const char *name, const int flag)
{
- BLI_assert((flag & LIB_ID_CREATE_NO_ALLOCATE) == 0);
-
- ID *id = BKE_libblock_alloc_notest(type);
-
- if (id) {
- if ((flag & LIB_ID_CREATE_NO_MAIN) != 0) {
- id->tag |= LIB_TAG_NO_MAIN;
- }
- if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) != 0) {
- id->tag |= LIB_TAG_NO_USER_REFCOUNT;
- }
-
- id->icon_id = 0;
- *((short *)id->name) = type;
- if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- id->us = 1;
- }
- if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
- ListBase *lb = which_libbase(bmain, type);
-
- BKE_main_lock(bmain);
- BLI_addtail(lb, id);
- BKE_id_new_name_validate(lb, id, name);
- bmain->is_memfile_undo_written = false;
- /* alphabetic insertion: is in new_id */
- BKE_main_unlock(bmain);
-
- /* TODO to be removed from here! */
- if ((flag & LIB_ID_CREATE_NO_DEG_TAG) == 0) {
- DEG_id_type_tag(bmain, type);
- }
- }
- else {
- BLI_strncpy(id->name + 2, name, sizeof(id->name) - 2);
- }
- }
-
- return id;
+ BLI_assert((flag & LIB_ID_CREATE_NO_ALLOCATE) == 0);
+
+ ID *id = BKE_libblock_alloc_notest(type);
+
+ if (id) {
+ if ((flag & LIB_ID_CREATE_NO_MAIN) != 0) {
+ id->tag |= LIB_TAG_NO_MAIN;
+ }
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) != 0) {
+ id->tag |= LIB_TAG_NO_USER_REFCOUNT;
+ }
+
+ id->icon_id = 0;
+ *((short *)id->name) = type;
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id->us = 1;
+ }
+ if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
+ ListBase *lb = which_libbase(bmain, type);
+
+ BKE_main_lock(bmain);
+ BLI_addtail(lb, id);
+ BKE_id_new_name_validate(lb, id, name);
+ bmain->is_memfile_undo_written = false;
+ /* alphabetic insertion: is in new_id */
+ BKE_main_unlock(bmain);
+
+ /* TODO to be removed from here! */
+ if ((flag & LIB_ID_CREATE_NO_DEG_TAG) == 0) {
+ DEG_id_type_tag(bmain, type);
+ }
+ }
+ else {
+ BLI_strncpy(id->name + 2, name, sizeof(id->name) - 2);
+ }
+ }
+
+ return id;
}
/**
@@ -1148,121 +1207,120 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name, const int fl
*/
void BKE_libblock_init_empty(ID *id)
{
- /* Note that only ID types that are not valid when filled of zero should have a callback here. */
- switch ((ID_Type)GS(id->name)) {
- case ID_SCE:
- BKE_scene_init((Scene *)id);
- break;
- case ID_LI:
- /* Nothing to do. */
- break;
- case ID_OB:
- {
- Object *ob = (Object *)id;
- ob->type = OB_EMPTY;
- BKE_object_init(ob);
- break;
- }
- case ID_ME:
- BKE_mesh_init((Mesh *)id);
- break;
- case ID_CU:
- BKE_curve_init((Curve *)id);
- break;
- case ID_MB:
- BKE_mball_init((MetaBall *)id);
- break;
- case ID_MA:
- BKE_material_init((Material *)id);
- break;
- case ID_TE:
- BKE_texture_default((Tex *)id);
- break;
- case ID_IM:
- BKE_image_init((Image *)id);
- break;
- case ID_LT:
- BKE_lattice_init((Lattice *)id);
- break;
- case ID_LA:
- BKE_light_init((Light *)id);
- break;
- case ID_SPK:
- BKE_speaker_init((Speaker *)id);
- break;
- case ID_LP:
- BKE_lightprobe_init((LightProbe *)id);
- break;
- case ID_CA:
- BKE_camera_init((Camera *)id);
- break;
- case ID_WO:
- BKE_world_init((World *)id);
- break;
- case ID_SCR:
- /* Nothing to do. */
- break;
- case ID_VF:
- BKE_vfont_init((VFont *)id);
- break;
- case ID_TXT:
- BKE_text_init((Text *)id);
- break;
- case ID_SO:
- /* Another fuzzy case, think NULLified content is OK here... */
- break;
- case ID_GR:
- /* Nothing to do. */
- break;
- case ID_AR:
- /* Nothing to do. */
- break;
- case ID_AC:
- /* Nothing to do. */
- break;
- case ID_NT:
- ntreeInitDefault((bNodeTree *)id);
- break;
- case ID_BR:
- BKE_brush_init((Brush *)id);
- break;
- case ID_PA:
- /* Nothing to do. */
- break;
- case ID_PC:
- /* Nothing to do. */
- break;
- case ID_GD:
- /* Nothing to do. */
- break;
- case ID_MSK:
- /* Nothing to do. */
- break;
- case ID_LS:
- BKE_linestyle_init((FreestyleLineStyle *)id);
- break;
- case ID_CF:
- BKE_cachefile_init((CacheFile *)id);
- break;
- case ID_KE:
- /* Shapekeys are a complex topic too - they depend on their 'user' data type...
- * They are not linkable, though, so it should never reach here anyway. */
- BLI_assert(0);
- break;
- case ID_WM:
- /* We should never reach this. */
- BLI_assert(0);
- break;
- case ID_IP:
- /* Should not be needed - animation from lib pre-2.5 is broken anyway. */
- BLI_assert(0);
- break;
- case ID_PAL:
- BKE_palette_init((Palette *)id);
- break;
- default:
- BLI_assert(0); /* Should never reach this point... */
- }
+ /* Note that only ID types that are not valid when filled of zero should have a callback here. */
+ switch ((ID_Type)GS(id->name)) {
+ case ID_SCE:
+ BKE_scene_init((Scene *)id);
+ break;
+ case ID_LI:
+ /* Nothing to do. */
+ break;
+ case ID_OB: {
+ Object *ob = (Object *)id;
+ ob->type = OB_EMPTY;
+ BKE_object_init(ob);
+ break;
+ }
+ case ID_ME:
+ BKE_mesh_init((Mesh *)id);
+ break;
+ case ID_CU:
+ BKE_curve_init((Curve *)id);
+ break;
+ case ID_MB:
+ BKE_mball_init((MetaBall *)id);
+ break;
+ case ID_MA:
+ BKE_material_init((Material *)id);
+ break;
+ case ID_TE:
+ BKE_texture_default((Tex *)id);
+ break;
+ case ID_IM:
+ BKE_image_init((Image *)id);
+ break;
+ case ID_LT:
+ BKE_lattice_init((Lattice *)id);
+ break;
+ case ID_LA:
+ BKE_light_init((Light *)id);
+ break;
+ case ID_SPK:
+ BKE_speaker_init((Speaker *)id);
+ break;
+ case ID_LP:
+ BKE_lightprobe_init((LightProbe *)id);
+ break;
+ case ID_CA:
+ BKE_camera_init((Camera *)id);
+ break;
+ case ID_WO:
+ BKE_world_init((World *)id);
+ break;
+ case ID_SCR:
+ /* Nothing to do. */
+ break;
+ case ID_VF:
+ BKE_vfont_init((VFont *)id);
+ break;
+ case ID_TXT:
+ BKE_text_init((Text *)id);
+ break;
+ case ID_SO:
+ /* Another fuzzy case, think NULLified content is OK here... */
+ break;
+ case ID_GR:
+ /* Nothing to do. */
+ break;
+ case ID_AR:
+ /* Nothing to do. */
+ break;
+ case ID_AC:
+ /* Nothing to do. */
+ break;
+ case ID_NT:
+ ntreeInitDefault((bNodeTree *)id);
+ break;
+ case ID_BR:
+ BKE_brush_init((Brush *)id);
+ break;
+ case ID_PA:
+ /* Nothing to do. */
+ break;
+ case ID_PC:
+ /* Nothing to do. */
+ break;
+ case ID_GD:
+ /* Nothing to do. */
+ break;
+ case ID_MSK:
+ /* Nothing to do. */
+ break;
+ case ID_LS:
+ BKE_linestyle_init((FreestyleLineStyle *)id);
+ break;
+ case ID_CF:
+ BKE_cachefile_init((CacheFile *)id);
+ break;
+ case ID_KE:
+ /* Shapekeys are a complex topic too - they depend on their 'user' data type...
+ * They are not linkable, though, so it should never reach here anyway. */
+ BLI_assert(0);
+ break;
+ case ID_WM:
+ /* We should never reach this. */
+ BLI_assert(0);
+ break;
+ case ID_IP:
+ /* Should not be needed - animation from lib pre-2.5 is broken anyway. */
+ BLI_assert(0);
+ break;
+ case ID_PAL:
+ BKE_palette_init((Palette *)id);
+ break;
+ default:
+ BLI_assert(0); /* Should never reach this point... */
+ }
}
/** Generic helper to create a new empty datablock of given type in given \a bmain database.
@@ -1270,16 +1328,16 @@ void BKE_libblock_init_empty(ID *id)
* \param name: can be NULL, in which case we get default name for this ID type. */
void *BKE_id_new(Main *bmain, const short type, const char *name)
{
- BLI_assert(bmain != NULL);
+ BLI_assert(bmain != NULL);
- if (name == NULL) {
- name = DATA_(BKE_idcode_to_name(type));
- }
+ if (name == NULL) {
+ name = DATA_(BKE_idcode_to_name(type));
+ }
- ID *id = BKE_libblock_alloc(bmain, type, name, 0);
- BKE_libblock_init_empty(id);
+ ID *id = BKE_libblock_alloc(bmain, type, name, 0);
+ BKE_libblock_init_empty(id);
- return id;
+ return id;
}
/** Generic helper to create a new temporary empty datablock of given type, *outside* of any Main database.
@@ -1287,143 +1345,146 @@ void *BKE_id_new(Main *bmain, const short type, const char *name)
* \param name: can be NULL, in which case we get default name for this ID type. */
void *BKE_id_new_nomain(const short type, const char *name)
{
- if (name == NULL) {
- name = DATA_(BKE_idcode_to_name(type));
- }
+ if (name == NULL) {
+ name = DATA_(BKE_idcode_to_name(type));
+ }
- ID *id = BKE_libblock_alloc(NULL, type, name,
- LIB_ID_CREATE_NO_MAIN |
- LIB_ID_CREATE_NO_USER_REFCOUNT |
- LIB_ID_CREATE_NO_DEG_TAG);
- BKE_libblock_init_empty(id);
+ ID *id = BKE_libblock_alloc(NULL,
+ type,
+ name,
+ LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG);
+ BKE_libblock_init_empty(id);
- return id;
+ return id;
}
void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag)
{
- ID *new_id = *r_newid;
-
- /* Grrrrrrrrr... Not adding 'root' nodetrees to bmain.... grrrrrrrrrrrrrrrrrrrr! */
- /* This is taken from original ntree copy code, might be weak actually? */
- const bool use_nodetree_alloc_exception = ((GS(id->name) == ID_NT) && (bmain != NULL) &&
- (BLI_findindex(&bmain->nodetrees, id) < 0));
-
- BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) != 0 || bmain != NULL);
- BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) != 0 || (flag & LIB_ID_CREATE_NO_ALLOCATE) == 0);
- BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) == 0 || (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) != 0);
- /* Never implicitly copy shapekeys when generating temp data outside of Main database. */
- BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) == 0 || (flag & LIB_ID_COPY_SHAPEKEY) == 0);
-
- if ((flag & LIB_ID_CREATE_NO_ALLOCATE) != 0) {
- /* r_newid already contains pointer to allocated memory. */
- /* TODO do we want to memset(0) whole mem before filling it? */
- BLI_strncpy(new_id->name, id->name, sizeof(new_id->name));
- new_id->us = 0;
- new_id->tag |= LIB_TAG_NOT_ALLOCATED | LIB_TAG_NO_MAIN | LIB_TAG_NO_USER_REFCOUNT;
- /* TODO Do we want/need to copy more from ID struct itself? */
- }
- else {
- new_id = BKE_libblock_alloc(bmain, GS(id->name), id->name + 2, flag | (use_nodetree_alloc_exception ? LIB_ID_CREATE_NO_MAIN : 0));
- }
- BLI_assert(new_id != NULL);
-
- const size_t id_len = BKE_libblock_get_alloc_info(GS(new_id->name), NULL);
- const size_t id_offset = sizeof(ID);
- if ((int)id_len - (int)id_offset > 0) { /* signed to allow neg result */ /* XXX ????? */
- const char *cp = (const char *)id;
- char *cpn = (char *)new_id;
-
- memcpy(cpn + id_offset, cp + id_offset, id_len - id_offset);
- }
-
- if (id->properties) {
- new_id->properties = IDP_CopyProperty_ex(id->properties, flag);
- }
-
- /* XXX Again... We need a way to control what we copy in a much more refined way.
- * We cannot always copy this, some internal copying will die on it! */
- /* For now, upper level code will have to do that itself when required. */
+ ID *new_id = *r_newid;
+
+ /* Grrrrrrrrr... Not adding 'root' nodetrees to bmain.... grrrrrrrrrrrrrrrrrrrr! */
+ /* This is taken from original ntree copy code, might be weak actually? */
+ const bool use_nodetree_alloc_exception = ((GS(id->name) == ID_NT) && (bmain != NULL) &&
+ (BLI_findindex(&bmain->nodetrees, id) < 0));
+
+ BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) != 0 || bmain != NULL);
+ BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) != 0 || (flag & LIB_ID_CREATE_NO_ALLOCATE) == 0);
+ BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) == 0 || (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) != 0);
+ /* Never implicitly copy shapekeys when generating temp data outside of Main database. */
+ BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) == 0 || (flag & LIB_ID_COPY_SHAPEKEY) == 0);
+
+ if ((flag & LIB_ID_CREATE_NO_ALLOCATE) != 0) {
+ /* r_newid already contains pointer to allocated memory. */
+ /* TODO do we want to memset(0) whole mem before filling it? */
+ BLI_strncpy(new_id->name, id->name, sizeof(new_id->name));
+ new_id->us = 0;
+ new_id->tag |= LIB_TAG_NOT_ALLOCATED | LIB_TAG_NO_MAIN | LIB_TAG_NO_USER_REFCOUNT;
+ /* TODO Do we want/need to copy more from ID struct itself? */
+ }
+ else {
+ new_id = BKE_libblock_alloc(bmain,
+ GS(id->name),
+ id->name + 2,
+ flag | (use_nodetree_alloc_exception ? LIB_ID_CREATE_NO_MAIN : 0));
+ }
+ BLI_assert(new_id != NULL);
+
+ const size_t id_len = BKE_libblock_get_alloc_info(GS(new_id->name), NULL);
+ const size_t id_offset = sizeof(ID);
+ if ((int)id_len - (int)id_offset > 0) { /* signed to allow neg result */ /* XXX ????? */
+ const char *cp = (const char *)id;
+ char *cpn = (char *)new_id;
+
+ memcpy(cpn + id_offset, cp + id_offset, id_len - id_offset);
+ }
+
+ if (id->properties) {
+ new_id->properties = IDP_CopyProperty_ex(id->properties, flag);
+ }
+
+ /* XXX Again... We need a way to control what we copy in a much more refined way.
+ * We cannot always copy this, some internal copying will die on it! */
+ /* For now, upper level code will have to do that itself when required. */
#if 0
- if (id->override != NULL) {
- BKE_override_copy(new_id, id);
- }
+ if (id->override != NULL) {
+ BKE_override_copy(new_id, id);
+ }
#endif
- if (id_can_have_animdata(new_id)) {
- IdAdtTemplate *iat = (IdAdtTemplate *)new_id;
+ if (id_can_have_animdata(new_id)) {
+ IdAdtTemplate *iat = (IdAdtTemplate *)new_id;
- /* the duplicate should get a copy of the animdata */
- if ((flag & LIB_ID_COPY_NO_ANIMDATA) == 0) {
- BLI_assert((flag & LIB_ID_COPY_ACTIONS) == 0 || (flag & LIB_ID_CREATE_NO_MAIN) == 0);
- iat->adt = BKE_animdata_copy(bmain, iat->adt, flag);
- }
- else {
- iat->adt = NULL;
- }
- }
+ /* the duplicate should get a copy of the animdata */
+ if ((flag & LIB_ID_COPY_NO_ANIMDATA) == 0) {
+ BLI_assert((flag & LIB_ID_COPY_ACTIONS) == 0 || (flag & LIB_ID_CREATE_NO_MAIN) == 0);
+ iat->adt = BKE_animdata_copy(bmain, iat->adt, flag);
+ }
+ else {
+ iat->adt = NULL;
+ }
+ }
- if ((flag & LIB_ID_CREATE_NO_DEG_TAG) == 0 && (flag & LIB_ID_CREATE_NO_MAIN) == 0) {
- DEG_id_type_tag(bmain, GS(new_id->name));
- }
+ if ((flag & LIB_ID_CREATE_NO_DEG_TAG) == 0 && (flag & LIB_ID_CREATE_NO_MAIN) == 0) {
+ DEG_id_type_tag(bmain, GS(new_id->name));
+ }
- *r_newid = new_id;
+ *r_newid = new_id;
}
/* used everywhere in blenkernel */
void *BKE_libblock_copy(Main *bmain, const ID *id)
{
- ID *idn;
+ ID *idn;
- BKE_libblock_copy_ex(bmain, id, &idn, 0);
+ BKE_libblock_copy_ex(bmain, id, &idn, 0);
- return idn;
+ return idn;
}
/* XXX TODO: get rid of this useless wrapper at some point... */
void *BKE_libblock_copy_for_localize(const ID *id)
{
- ID *idn;
- BKE_libblock_copy_ex(NULL, id, &idn, LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_NO_ANIMDATA);
- return idn;
+ ID *idn;
+ BKE_libblock_copy_ex(NULL, id, &idn, LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_NO_ANIMDATA);
+ return idn;
}
void BKE_library_free(Library *lib)
{
- if (lib->packedfile)
- freePackedFile(lib->packedfile);
+ if (lib->packedfile)
+ freePackedFile(lib->packedfile);
}
/* ***************** ID ************************ */
ID *BKE_libblock_find_name(struct Main *bmain, const short type, const char *name)
{
- ListBase *lb = which_libbase(bmain, type);
- BLI_assert(lb != NULL);
- return BLI_findstring(lb, name, offsetof(ID, name) + 2);
+ ListBase *lb = which_libbase(bmain, type);
+ BLI_assert(lb != NULL);
+ return BLI_findstring(lb, name, offsetof(ID, name) + 2);
}
void id_sort_by_name(ListBase *lb, ID *id)
{
- ID *idtest;
-
- /* insert alphabetically */
- if (lb->first != lb->last) {
- BLI_remlink(lb, id);
+ ID *idtest;
- idtest = lb->first;
- while (idtest) {
- if (BLI_strcasecmp(idtest->name, id->name) > 0 || (idtest->lib && !id->lib)) {
- BLI_insertlinkbefore(lb, idtest, id);
- break;
- }
- idtest = idtest->next;
- }
- /* as last */
- if (idtest == NULL) {
- BLI_addtail(lb, id);
- }
- }
+ /* insert alphabetically */
+ if (lb->first != lb->last) {
+ BLI_remlink(lb, id);
+ idtest = lb->first;
+ while (idtest) {
+ if (BLI_strcasecmp(idtest->name, id->name) > 0 || (idtest->lib && !id->lib)) {
+ BLI_insertlinkbefore(lb, idtest, id);
+ break;
+ }
+ idtest = idtest->next;
+ }
+ /* as last */
+ if (idtest == NULL) {
+ BLI_addtail(lb, id);
+ }
+ }
}
/**
@@ -1432,20 +1493,21 @@ void id_sort_by_name(ListBase *lb, ID *id)
*/
static ID *is_dupid(ListBase *lb, ID *id, const char *name)
{
- ID *idtest = NULL;
+ ID *idtest = NULL;
- for (idtest = lb->first; idtest; idtest = idtest->next) {
- /* if idtest is not a lib */
- if (id != idtest && !ID_IS_LINKED(idtest)) {
- /* do not test alphabetic! */
- /* optimized */
- if (idtest->name[2] == name[0]) {
- if (STREQ(name, idtest->name + 2)) break;
- }
- }
- }
+ for (idtest = lb->first; idtest; idtest = idtest->next) {
+ /* if idtest is not a lib */
+ if (id != idtest && !ID_IS_LINKED(idtest)) {
+ /* do not test alphabetic! */
+ /* optimized */
+ if (idtest->name[2] == name[0]) {
+ if (STREQ(name, idtest->name + 2))
+ break;
+ }
+ }
+ }
- return idtest;
+ return idtest;
}
/**
@@ -1460,112 +1522,111 @@ static ID *is_dupid(ListBase *lb, ID *id, const char *name)
static bool check_for_dupid(ListBase *lb, ID *id, char *name)
{
- ID *idtest;
- int nr = 0, a;
- size_t left_len;
+ ID *idtest;
+ int nr = 0, a;
+ size_t left_len;
#define MAX_IN_USE 64
- bool in_use[MAX_IN_USE];
- /* to speed up finding unused numbers within [1 .. MAX_IN_USE - 1] */
-
- char left[MAX_ID_NAME + 8], leftest[MAX_ID_NAME + 8];
-
- while (true) {
-
- /* phase 1: id already exists? */
- idtest = is_dupid(lb, id, name);
-
- /* if there is no double, done */
- if (idtest == NULL) return false;
-
- /* we have a dup; need to make a new name */
- /* quick check so we can reuse one of first MAX_IN_USE - 1 ids if vacant */
- memset(in_use, false, sizeof(in_use));
-
- /* get name portion, number portion ("name.number") */
- left_len = BLI_split_name_num(left, &nr, name, '.');
-
- /* if new name will be too long, truncate it */
- if (nr > 999 && left_len > (MAX_ID_NAME - 8)) { /* assumption: won't go beyond 9999 */
- left[MAX_ID_NAME - 8] = '\0';
- left_len = MAX_ID_NAME - 8;
- }
- else if (left_len > (MAX_ID_NAME - 7)) {
- left[MAX_ID_NAME - 7] = '\0';
- left_len = MAX_ID_NAME - 7;
- }
-
- /* Code above may have generated invalid utf-8 string, due to raw truncation.
- * Ensure we get a valid one now! */
- left_len -= (size_t)BLI_utf8_invalid_strip(left, left_len);
-
- for (idtest = lb->first; idtest; idtest = idtest->next) {
- int nrtest;
- if ( (id != idtest) &&
- !ID_IS_LINKED(idtest) &&
- (*name == *(idtest->name + 2)) &&
- STREQLEN(name, idtest->name + 2, left_len) &&
- (BLI_split_name_num(leftest, &nrtest, idtest->name + 2, '.') == left_len)
- )
- {
- /* will get here at least once, otherwise is_dupid call above would have returned NULL */
- if (nrtest < MAX_IN_USE)
- in_use[nrtest] = true; /* mark as used */
- if (nr <= nrtest)
- nr = nrtest + 1; /* track largest unused */
- }
- }
- /* At this point, 'nr' will typically be at least 1. (but not always) */
- // BLI_assert(nr >= 1);
-
- /* decide which value of nr to use */
- for (a = 0; a < MAX_IN_USE; a++) {
- if (a >= nr) break; /* stop when we've checked up to biggest */ /* redundant check */
- if (!in_use[a]) { /* found an unused value */
- nr = a;
- /* can only be zero if all potential duplicate names had
- * nonzero numeric suffixes, which means name itself has
- * nonzero numeric suffix (else no name conflict and wouldn't
- * have got here), which means name[left_len] is not a null */
- break;
- }
- }
- /* At this point, nr is either the lowest unused number within [0 .. MAX_IN_USE - 1],
- * or 1 greater than the largest used number if all those low ones are taken.
- * We can't be bothered to look for the lowest unused number beyond (MAX_IN_USE - 1). */
-
- /* If the original name has no numeric suffix,
- * rather than just chopping and adding numbers,
- * shave off the end chars until we have a unique name.
- * Check the null terminators match as well so we don't get Cube.000 -> Cube.00 */
- if (nr == 0 && name[left_len] == '\0') {
- size_t len;
- /* FIXME: this code will never be executed, because either nr will be
- * at least 1, or name will not end at left_len! */
- BLI_assert(0);
-
- len = left_len - 1;
- idtest = is_dupid(lb, id, name);
-
- while (idtest && len > 1) {
- name[len--] = '\0';
- idtest = is_dupid(lb, id, name);
- }
- if (idtest == NULL) return true;
- /* otherwise just continue and use a number suffix */
- }
-
- if (nr > 999 && left_len > (MAX_ID_NAME - 8)) {
- /* this would overflow name buffer */
- left[MAX_ID_NAME - 8] = 0;
- /* left_len = MAX_ID_NAME - 8; */ /* for now this isn't used again */
- memcpy(name, left, sizeof(char) * (MAX_ID_NAME - 7));
- continue;
- }
- /* this format specifier is from hell... */
- BLI_snprintf(name, sizeof(id->name) - 2, "%s.%.3d", left, nr);
-
- return true;
- }
+ bool in_use[MAX_IN_USE];
+ /* to speed up finding unused numbers within [1 .. MAX_IN_USE - 1] */
+
+ char left[MAX_ID_NAME + 8], leftest[MAX_ID_NAME + 8];
+
+ while (true) {
+
+ /* phase 1: id already exists? */
+ idtest = is_dupid(lb, id, name);
+
+ /* if there is no double, done */
+ if (idtest == NULL)
+ return false;
+
+ /* we have a dup; need to make a new name */
+ /* quick check so we can reuse one of first MAX_IN_USE - 1 ids if vacant */
+ memset(in_use, false, sizeof(in_use));
+
+ /* get name portion, number portion ("name.number") */
+ left_len = BLI_split_name_num(left, &nr, name, '.');
+
+ /* if new name will be too long, truncate it */
+ if (nr > 999 && left_len > (MAX_ID_NAME - 8)) { /* assumption: won't go beyond 9999 */
+ left[MAX_ID_NAME - 8] = '\0';
+ left_len = MAX_ID_NAME - 8;
+ }
+ else if (left_len > (MAX_ID_NAME - 7)) {
+ left[MAX_ID_NAME - 7] = '\0';
+ left_len = MAX_ID_NAME - 7;
+ }
+
+ /* Code above may have generated invalid utf-8 string, due to raw truncation.
+ * Ensure we get a valid one now! */
+ left_len -= (size_t)BLI_utf8_invalid_strip(left, left_len);
+
+ for (idtest = lb->first; idtest; idtest = idtest->next) {
+ int nrtest;
+ if ((id != idtest) && !ID_IS_LINKED(idtest) && (*name == *(idtest->name + 2)) &&
+ STREQLEN(name, idtest->name + 2, left_len) &&
+ (BLI_split_name_num(leftest, &nrtest, idtest->name + 2, '.') == left_len)) {
+ /* will get here at least once, otherwise is_dupid call above would have returned NULL */
+ if (nrtest < MAX_IN_USE)
+ in_use[nrtest] = true; /* mark as used */
+ if (nr <= nrtest)
+ nr = nrtest + 1; /* track largest unused */
+ }
+ }
+ /* At this point, 'nr' will typically be at least 1. (but not always) */
+ // BLI_assert(nr >= 1);
+
+ /* decide which value of nr to use */
+ for (a = 0; a < MAX_IN_USE; a++) {
+ if (a >= nr)
+ break; /* stop when we've checked up to biggest */ /* redundant check */
+ if (!in_use[a]) { /* found an unused value */
+ nr = a;
+ /* can only be zero if all potential duplicate names had
+ * nonzero numeric suffixes, which means name itself has
+ * nonzero numeric suffix (else no name conflict and wouldn't
+ * have got here), which means name[left_len] is not a null */
+ break;
+ }
+ }
+ /* At this point, nr is either the lowest unused number within [0 .. MAX_IN_USE - 1],
+ * or 1 greater than the largest used number if all those low ones are taken.
+ * We can't be bothered to look for the lowest unused number beyond (MAX_IN_USE - 1). */
+
+ /* If the original name has no numeric suffix,
+ * rather than just chopping and adding numbers,
+ * shave off the end chars until we have a unique name.
+ * Check the null terminators match as well so we don't get Cube.000 -> Cube.00 */
+ if (nr == 0 && name[left_len] == '\0') {
+ size_t len;
+ /* FIXME: this code will never be executed, because either nr will be
+ * at least 1, or name will not end at left_len! */
+ BLI_assert(0);
+
+ len = left_len - 1;
+ idtest = is_dupid(lb, id, name);
+
+ while (idtest && len > 1) {
+ name[len--] = '\0';
+ idtest = is_dupid(lb, id, name);
+ }
+ if (idtest == NULL)
+ return true;
+ /* otherwise just continue and use a number suffix */
+ }
+
+ if (nr > 999 && left_len > (MAX_ID_NAME - 8)) {
+ /* this would overflow name buffer */
+ left[MAX_ID_NAME - 8] = 0;
+ /* left_len = MAX_ID_NAME - 8; */ /* for now this isn't used again */
+ memcpy(name, left, sizeof(char) * (MAX_ID_NAME - 7));
+ continue;
+ }
+ /* this format specifier is from hell... */
+ BLI_snprintf(name, sizeof(id->name) - 2, "%s.%.3d", left, nr);
+
+ return true;
+ }
#undef MAX_IN_USE
}
@@ -1579,45 +1640,45 @@ static bool check_for_dupid(ListBase *lb, ID *id, char *name)
*/
bool BKE_id_new_name_validate(ListBase *lb, ID *id, const char *tname)
{
- bool result;
- char name[MAX_ID_NAME - 2];
-
- /* if library, don't rename */
- if (ID_IS_LINKED(id))
- return false;
-
- /* if no name given, use name of current ID
- * else make a copy (tname args can be const) */
- if (tname == NULL)
- tname = id->name + 2;
-
- BLI_strncpy(name, tname, sizeof(name));
-
- if (name[0] == '\0') {
- /* Disallow empty names. */
- BLI_strncpy(name, DATA_(BKE_idcode_to_name(GS(id->name))), sizeof(name));
- }
- else {
- /* disallow non utf8 chars,
- * the interface checks for this but new ID's based on file names don't */
- BLI_utf8_invalid_strip(name, strlen(name));
- }
-
- result = check_for_dupid(lb, id, name);
- strcpy(id->name + 2, name);
-
- /* This was in 2.43 and previous releases
- * however all data in blender should be sorted, not just duplicate names
- * sorting should not hurt, but noting just incase it alters the way other
- * functions work, so sort every time */
+ bool result;
+ char name[MAX_ID_NAME - 2];
+
+ /* if library, don't rename */
+ if (ID_IS_LINKED(id))
+ return false;
+
+ /* if no name given, use name of current ID
+ * else make a copy (tname args can be const) */
+ if (tname == NULL)
+ tname = id->name + 2;
+
+ BLI_strncpy(name, tname, sizeof(name));
+
+ if (name[0] == '\0') {
+ /* Disallow empty names. */
+ BLI_strncpy(name, DATA_(BKE_idcode_to_name(GS(id->name))), sizeof(name));
+ }
+ else {
+ /* disallow non utf8 chars,
+ * the interface checks for this but new ID's based on file names don't */
+ BLI_utf8_invalid_strip(name, strlen(name));
+ }
+
+ result = check_for_dupid(lb, id, name);
+ strcpy(id->name + 2, name);
+
+ /* This was in 2.43 and previous releases
+ * however all data in blender should be sorted, not just duplicate names
+ * sorting should not hurt, but noting just incase it alters the way other
+ * functions work, so sort every time */
#if 0
- if (result)
- id_sort_by_name(lb, id);
+ if (result)
+ id_sort_by_name(lb, id);
#endif
- id_sort_by_name(lb, id);
+ id_sort_by_name(lb, id);
- return result;
+ return result;
}
/**
@@ -1626,104 +1687,107 @@ bool BKE_id_new_name_validate(ListBase *lb, ID *id, const char *tname)
*/
void id_clear_lib_data_ex(Main *bmain, ID *id, const bool id_in_mainlist)
{
- bNodeTree *ntree = NULL;
- Key *key = NULL;
+ bNodeTree *ntree = NULL;
+ Key *key = NULL;
- BKE_id_lib_local_paths(bmain, id->lib, id);
+ BKE_id_lib_local_paths(bmain, id->lib, id);
- id_fake_user_clear(id);
+ id_fake_user_clear(id);
- id->lib = NULL;
- id->tag &= ~(LIB_TAG_INDIRECT | LIB_TAG_EXTERN);
- if (id_in_mainlist) {
- if (BKE_id_new_name_validate(which_libbase(bmain, GS(id->name)), id, NULL)) {
- bmain->is_memfile_undo_written = false;
- }
- }
+ id->lib = NULL;
+ id->tag &= ~(LIB_TAG_INDIRECT | LIB_TAG_EXTERN);
+ if (id_in_mainlist) {
+ if (BKE_id_new_name_validate(which_libbase(bmain, GS(id->name)), id, NULL)) {
+ bmain->is_memfile_undo_written = false;
+ }
+ }
- /* Internal bNodeTree blocks inside datablocks also stores id->lib, make sure this stays in sync. */
- if ((ntree = ntreeFromID(id))) {
- id_clear_lib_data_ex(bmain, &ntree->id, false); /* Datablocks' nodetree is never in Main. */
- }
+ /* Internal bNodeTree blocks inside datablocks also stores id->lib, make sure this stays in sync. */
+ if ((ntree = ntreeFromID(id))) {
+ id_clear_lib_data_ex(bmain, &ntree->id, false); /* Datablocks' nodetree is never in Main. */
+ }
- /* Same goes for shapekeys. */
- if ((key = BKE_key_from_id(id))) {
- id_clear_lib_data_ex(bmain, &key->id, id_in_mainlist); /* sigh, why are keys in Main? */
- }
+ /* Same goes for shapekeys. */
+ if ((key = BKE_key_from_id(id))) {
+ id_clear_lib_data_ex(bmain, &key->id, id_in_mainlist); /* sigh, why are keys in Main? */
+ }
}
void id_clear_lib_data(Main *bmain, ID *id)
{
- id_clear_lib_data_ex(bmain, id, true);
+ id_clear_lib_data_ex(bmain, id, true);
}
/* next to indirect usage in read/writefile also in editobject.c scene.c */
void BKE_main_id_clear_newpoins(Main *bmain)
{
- ID *id;
-
- FOREACH_MAIN_ID_BEGIN(bmain, id)
- {
- id->newid = NULL;
- id->tag &= ~LIB_TAG_NEW;
- }
- FOREACH_MAIN_ID_END;
-}
-
-
-static void library_make_local_copying_check(ID *id, GSet *loop_tags, MainIDRelations *id_relations, GSet *done_ids)
-{
- if (BLI_gset_haskey(done_ids, id)) {
- return; /* Already checked, nothing else to do. */
- }
-
- MainIDRelationsEntry *entry = BLI_ghash_lookup(id_relations->id_used_to_user, id);
- BLI_gset_insert(loop_tags, id);
- for (; entry != NULL; entry = entry->next) {
- ID *par_id = (ID *)entry->id_pointer; /* used_to_user stores ID pointer, not pointer to ID pointer... */
-
- /* Our oh-so-beloved 'from' pointers... */
- if (entry->usage_flag & IDWALK_CB_LOOPBACK) {
- /* We totally disregard Object->proxy_from 'usage' here, this one would only generate fake positives. */
- if (GS(par_id->name) == ID_OB) {
- BLI_assert(((Object *)par_id)->proxy_from == (Object *)id);
- continue;
- }
-
- /* Shapekeys are considered 'private' to their owner ID here, and never tagged (since they cannot be linked),
- * so we have to switch effective parent to their owner. */
- if (GS(par_id->name) == ID_KE) {
- par_id = ((Key *)par_id)->from;
- }
- }
-
- if (par_id->lib == NULL) {
- /* Local user, early out to avoid some gset querying... */
- continue;
- }
- if (!BLI_gset_haskey(done_ids, par_id)) {
- if (BLI_gset_haskey(loop_tags, par_id)) {
- /* We are in a 'dependency loop' of IDs, this does not say us anything, skip it.
- * Note that this is the situation that can lead to archipelagoes of linked data-blocks
- * (since all of them have non-local users, they would all be duplicated, leading to a loop of unused
- * linked data-blocks that cannot be freed since they all use each other...). */
- continue;
- }
- /* Else, recursively check that user ID. */
- library_make_local_copying_check(par_id, loop_tags, id_relations, done_ids);
- }
-
- if (par_id->tag & LIB_TAG_DOIT) {
- /* This user will be fully local in future, so far so good, nothing to do here but check next user. */
- }
- else {
- /* This user won't be fully local in future, so current ID won't be either. And we are done checking it. */
- id->tag &= ~LIB_TAG_DOIT;
- break;
- }
- }
- BLI_gset_add(done_ids, id);
- BLI_gset_remove(loop_tags, id, NULL);
+ ID *id;
+
+ FOREACH_MAIN_ID_BEGIN(bmain, id)
+ {
+ id->newid = NULL;
+ id->tag &= ~LIB_TAG_NEW;
+ }
+ FOREACH_MAIN_ID_END;
+}
+
+static void library_make_local_copying_check(ID *id,
+ GSet *loop_tags,
+ MainIDRelations *id_relations,
+ GSet *done_ids)
+{
+ if (BLI_gset_haskey(done_ids, id)) {
+ return; /* Already checked, nothing else to do. */
+ }
+
+ MainIDRelationsEntry *entry = BLI_ghash_lookup(id_relations->id_used_to_user, id);
+ BLI_gset_insert(loop_tags, id);
+ for (; entry != NULL; entry = entry->next) {
+ ID *par_id =
+ (ID *)entry->id_pointer; /* used_to_user stores ID pointer, not pointer to ID pointer... */
+
+ /* Our oh-so-beloved 'from' pointers... */
+ if (entry->usage_flag & IDWALK_CB_LOOPBACK) {
+ /* We totally disregard Object->proxy_from 'usage' here, this one would only generate fake positives. */
+ if (GS(par_id->name) == ID_OB) {
+ BLI_assert(((Object *)par_id)->proxy_from == (Object *)id);
+ continue;
+ }
+
+ /* Shapekeys are considered 'private' to their owner ID here, and never tagged (since they cannot be linked),
+ * so we have to switch effective parent to their owner. */
+ if (GS(par_id->name) == ID_KE) {
+ par_id = ((Key *)par_id)->from;
+ }
+ }
+
+ if (par_id->lib == NULL) {
+ /* Local user, early out to avoid some gset querying... */
+ continue;
+ }
+ if (!BLI_gset_haskey(done_ids, par_id)) {
+ if (BLI_gset_haskey(loop_tags, par_id)) {
+ /* We are in a 'dependency loop' of IDs, this does not say us anything, skip it.
+ * Note that this is the situation that can lead to archipelagoes of linked data-blocks
+ * (since all of them have non-local users, they would all be duplicated, leading to a loop of unused
+ * linked data-blocks that cannot be freed since they all use each other...). */
+ continue;
+ }
+ /* Else, recursively check that user ID. */
+ library_make_local_copying_check(par_id, loop_tags, id_relations, done_ids);
+ }
+
+ if (par_id->tag & LIB_TAG_DOIT) {
+ /* This user will be fully local in future, so far so good, nothing to do here but check next user. */
+ }
+ else {
+ /* This user won't be fully local in future, so current ID won't be either. And we are done checking it. */
+ id->tag &= ~LIB_TAG_DOIT;
+ break;
+ }
+ }
+ BLI_gset_add(done_ids, id);
+ BLI_gset_remove(loop_tags, id, NULL);
}
/** Make linked datablocks local.
@@ -1741,268 +1805,279 @@ static void library_make_local_copying_check(ID *id, GSet *loop_tags, MainIDRela
* This allows to avoid any unneeded duplication of IDs, and hence all time lost afterwards to remove
* orphaned linked data-blocks...
*/
-void BKE_library_make_local(
- Main *bmain, const Library *lib, GHash *old_to_new_ids, const bool untagged_only, const bool set_fake)
+void BKE_library_make_local(Main *bmain,
+ const Library *lib,
+ GHash *old_to_new_ids,
+ const bool untagged_only,
+ const bool set_fake)
{
- ListBase *lbarray[MAX_LIBARRAY];
+ ListBase *lbarray[MAX_LIBARRAY];
- LinkNode *todo_ids = NULL;
- LinkNode *copied_ids = NULL;
- MemArena *linklist_mem = BLI_memarena_new(512 * sizeof(*todo_ids), __func__);
+ LinkNode *todo_ids = NULL;
+ LinkNode *copied_ids = NULL;
+ MemArena *linklist_mem = BLI_memarena_new(512 * sizeof(*todo_ids), __func__);
- GSet *done_ids = BLI_gset_ptr_new(__func__);
+ GSet *done_ids = BLI_gset_ptr_new(__func__);
#ifdef DEBUG_TIME
- TIMEIT_START(make_local);
+ TIMEIT_START(make_local);
#endif
- BKE_main_relations_create(bmain);
+ BKE_main_relations_create(bmain);
#ifdef DEBUG_TIME
- printf("Pre-compute current ID relations: Done.\n");
- TIMEIT_VALUE_PRINT(make_local);
+ printf("Pre-compute current ID relations: Done.\n");
+ TIMEIT_VALUE_PRINT(make_local);
#endif
- /* Step 1: Detect datablocks to make local. */
- for (int a = set_listbasepointers(bmain, lbarray); a--; ) {
- ID *id = lbarray[a]->first;
-
- /* Do not explicitly make local non-linkable IDs (shapekeys, in fact), they are assumed to be handled
- * by real datablocks responsible of them. */
- const bool do_skip = (id && !BKE_idcode_is_linkable(GS(id->name)));
-
- for (; id; id = id->next) {
- ID *ntree = (ID *)ntreeFromID(id);
-
- id->tag &= ~LIB_TAG_DOIT;
- if (ntree != NULL) {
- ntree->tag &= ~LIB_TAG_DOIT;
- }
-
- if (id->lib == NULL) {
- id->tag &= ~(LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW);
- }
- /* The check on the fourth line (LIB_TAG_PRE_EXISTING) is done so its possible to tag data you don't want to
- * be made local, used for appending data, so any libdata already linked wont become local (very nasty
- * to discover all your links are lost after appending).
- * Also, never ever make proxified objects local, would not make any sense. */
- /* Some more notes:
- * - Shapekeys are never tagged here (since they are not linkable).
- * - Nodetrees used in materials etc. have to be tagged manually, since they do not exist in Main (!).
- * This is ok-ish on 'make local' side of things (since those are handled by their 'owner' IDs),
- * but complicates slightly the pre-processing of relations between IDs at step 2... */
- else if (!do_skip && id->tag & (LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW) &&
- ELEM(lib, NULL, id->lib) &&
- !(GS(id->name) == ID_OB && ((Object *)id)->proxy_from != NULL) &&
- ((untagged_only == false) || !(id->tag & LIB_TAG_PRE_EXISTING)))
- {
- BLI_linklist_prepend_arena(&todo_ids, id, linklist_mem);
- id->tag |= LIB_TAG_DOIT;
-
- /* Tag those nasty non-ID nodetrees, but do not add them to todo list, making them local is handled
- * by 'owner' ID. This is needed for library_make_local_copying_check() to work OK at step 2. */
- if (ntree != NULL) {
- ntree->tag |= LIB_TAG_DOIT;
- }
- }
- else {
- /* Linked ID that we won't be making local (needed info for step 2, see below). */
- BLI_gset_add(done_ids, id);
- }
- }
- }
+ /* Step 1: Detect datablocks to make local. */
+ for (int a = set_listbasepointers(bmain, lbarray); a--;) {
+ ID *id = lbarray[a]->first;
+
+ /* Do not explicitly make local non-linkable IDs (shapekeys, in fact), they are assumed to be handled
+ * by real datablocks responsible of them. */
+ const bool do_skip = (id && !BKE_idcode_is_linkable(GS(id->name)));
+
+ for (; id; id = id->next) {
+ ID *ntree = (ID *)ntreeFromID(id);
+
+ id->tag &= ~LIB_TAG_DOIT;
+ if (ntree != NULL) {
+ ntree->tag &= ~LIB_TAG_DOIT;
+ }
+
+ if (id->lib == NULL) {
+ id->tag &= ~(LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW);
+ }
+ /* The check on the fourth line (LIB_TAG_PRE_EXISTING) is done so its possible to tag data you don't want to
+ * be made local, used for appending data, so any libdata already linked wont become local (very nasty
+ * to discover all your links are lost after appending).
+ * Also, never ever make proxified objects local, would not make any sense. */
+ /* Some more notes:
+ * - Shapekeys are never tagged here (since they are not linkable).
+ * - Nodetrees used in materials etc. have to be tagged manually, since they do not exist in Main (!).
+ * This is ok-ish on 'make local' side of things (since those are handled by their 'owner' IDs),
+ * but complicates slightly the pre-processing of relations between IDs at step 2... */
+ else if (!do_skip && id->tag & (LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW) &&
+ ELEM(lib, NULL, id->lib) &&
+ !(GS(id->name) == ID_OB && ((Object *)id)->proxy_from != NULL) &&
+ ((untagged_only == false) || !(id->tag & LIB_TAG_PRE_EXISTING))) {
+ BLI_linklist_prepend_arena(&todo_ids, id, linklist_mem);
+ id->tag |= LIB_TAG_DOIT;
+
+ /* Tag those nasty non-ID nodetrees, but do not add them to todo list, making them local is handled
+ * by 'owner' ID. This is needed for library_make_local_copying_check() to work OK at step 2. */
+ if (ntree != NULL) {
+ ntree->tag |= LIB_TAG_DOIT;
+ }
+ }
+ else {
+ /* Linked ID that we won't be making local (needed info for step 2, see below). */
+ BLI_gset_add(done_ids, id);
+ }
+ }
+ }
#ifdef DEBUG_TIME
- printf("Step 1: Detect datablocks to make local: Done.\n");
- TIMEIT_VALUE_PRINT(make_local);
+ printf("Step 1: Detect datablocks to make local: Done.\n");
+ TIMEIT_VALUE_PRINT(make_local);
#endif
- /* Step 2: Check which datablocks we can directly make local (because they are only used by already, or future,
- * local data), others will need to be duplicated. */
- GSet *loop_tags = BLI_gset_ptr_new(__func__);
- for (LinkNode *it = todo_ids; it; it = it->next) {
- library_make_local_copying_check(it->link, loop_tags, bmain->relations, done_ids);
- BLI_assert(BLI_gset_len(loop_tags) == 0);
- }
- BLI_gset_free(loop_tags, NULL);
- BLI_gset_free(done_ids, NULL);
+ /* Step 2: Check which datablocks we can directly make local (because they are only used by already, or future,
+ * local data), others will need to be duplicated. */
+ GSet *loop_tags = BLI_gset_ptr_new(__func__);
+ for (LinkNode *it = todo_ids; it; it = it->next) {
+ library_make_local_copying_check(it->link, loop_tags, bmain->relations, done_ids);
+ BLI_assert(BLI_gset_len(loop_tags) == 0);
+ }
+ BLI_gset_free(loop_tags, NULL);
+ BLI_gset_free(done_ids, NULL);
- /* Next step will most likely add new IDs, better to get rid of this mapping now. */
- BKE_main_relations_free(bmain);
+ /* Next step will most likely add new IDs, better to get rid of this mapping now. */
+ BKE_main_relations_free(bmain);
#ifdef DEBUG_TIME
- printf("Step 2: Check which datablocks we can directly make local: Done.\n");
- TIMEIT_VALUE_PRINT(make_local);
+ printf("Step 2: Check which datablocks we can directly make local: Done.\n");
+ TIMEIT_VALUE_PRINT(make_local);
#endif
- /* Step 3: Make IDs local, either directly (quick and simple), or using generic process,
- * which involves more complex checks and might instead create a local copy of original linked ID. */
- for (LinkNode *it = todo_ids, *it_next; it; it = it_next) {
- it_next = it->next;
- ID *id = it->link;
-
- if (id->tag & LIB_TAG_DOIT) {
- /* We know all users of this object are local or will be made fully local, even if currently there are
- * some indirect usages. So instead of making a copy that we'll likely get rid of later, directly make
- * that data block local. Saves a tremendous amount of time with complex scenes... */
- id_clear_lib_data_ex(bmain, id, true);
- BKE_id_expand_local(bmain, id);
- id->tag &= ~LIB_TAG_DOIT;
- }
- else {
- /* In this specific case, we do want to make ID local even if it has no local usage yet... */
- if (GS(id->name) == ID_OB) {
- /* Special case for objects because we don't want proxy pointers to be
- * cleared yet. This will happen down the road in this function.
- */
- BKE_object_make_local_ex(bmain, (Object *)id, true, false);
- }
- else {
- id_make_local(bmain, id, false, true);
- }
-
- if (id->newid) {
- /* Reuse already allocated LinkNode (transferring it from todo_ids to copied_ids). */
- BLI_linklist_prepend_nlink(&copied_ids, id, it);
- }
- }
-
- if (set_fake) {
- if (!ELEM(GS(id->name), ID_OB, ID_GR)) {
- /* do not set fake user on objects, groups (instancing) */
- id_fake_user_set(id);
- }
- }
- }
+ /* Step 3: Make IDs local, either directly (quick and simple), or using generic process,
+ * which involves more complex checks and might instead create a local copy of original linked ID. */
+ for (LinkNode *it = todo_ids, *it_next; it; it = it_next) {
+ it_next = it->next;
+ ID *id = it->link;
+
+ if (id->tag & LIB_TAG_DOIT) {
+ /* We know all users of this object are local or will be made fully local, even if currently there are
+ * some indirect usages. So instead of making a copy that we'll likely get rid of later, directly make
+ * that data block local. Saves a tremendous amount of time with complex scenes... */
+ id_clear_lib_data_ex(bmain, id, true);
+ BKE_id_expand_local(bmain, id);
+ id->tag &= ~LIB_TAG_DOIT;
+ }
+ else {
+ /* In this specific case, we do want to make ID local even if it has no local usage yet... */
+ if (GS(id->name) == ID_OB) {
+ /* Special case for objects because we don't want proxy pointers to be
+ * cleared yet. This will happen down the road in this function.
+ */
+ BKE_object_make_local_ex(bmain, (Object *)id, true, false);
+ }
+ else {
+ id_make_local(bmain, id, false, true);
+ }
+
+ if (id->newid) {
+ /* Reuse already allocated LinkNode (transferring it from todo_ids to copied_ids). */
+ BLI_linklist_prepend_nlink(&copied_ids, id, it);
+ }
+ }
+
+ if (set_fake) {
+ if (!ELEM(GS(id->name), ID_OB, ID_GR)) {
+ /* do not set fake user on objects, groups (instancing) */
+ id_fake_user_set(id);
+ }
+ }
+ }
#ifdef DEBUG_TIME
- printf("Step 3: Make IDs local: Done.\n");
- TIMEIT_VALUE_PRINT(make_local);
+ printf("Step 3: Make IDs local: Done.\n");
+ TIMEIT_VALUE_PRINT(make_local);
#endif
- /* At this point, we are done with directly made local IDs. Now we have to handle duplicated ones, since their
- * remaining linked original counterpart may not be needed anymore... */
- todo_ids = NULL;
-
- /* Step 4: We have to remap local usages of old (linked) ID to new (local) ID in a separated loop,
- * as lbarray ordering is not enough to ensure us we did catch all dependencies
- * (e.g. if making local a parent object before its child...). See T48907. */
- /* TODO This is now the biggest step by far (in term of processing time). We may be able to gain here by
- * using again main->relations mapping, but... this implies BKE_libblock_remap & co to be able to update
- * main->relations on the fly. Have to think about it a bit more, and see whether new code is OK first, anyway. */
- for (LinkNode *it = copied_ids; it; it = it->next) {
- ID *id = it->link;
-
- BLI_assert(id->newid != NULL);
- BLI_assert(id->lib != NULL);
-
- BKE_libblock_remap(bmain, id, id->newid, ID_REMAP_SKIP_INDIRECT_USAGE);
- if (old_to_new_ids) {
- BLI_ghash_insert(old_to_new_ids, id, id->newid);
- }
-
- /* Special hack for groups... Thing is, since we can't instantiate them here, we need to ensure
- * they remain 'alive' (only instantiation is a real group 'user'... *sigh* See T49722. */
- if (GS(id->name) == ID_GR && (id->tag & LIB_TAG_INDIRECT) != 0) {
- id_us_ensure_real(id->newid);
- }
- }
+ /* At this point, we are done with directly made local IDs. Now we have to handle duplicated ones, since their
+ * remaining linked original counterpart may not be needed anymore... */
+ todo_ids = NULL;
+
+ /* Step 4: We have to remap local usages of old (linked) ID to new (local) ID in a separated loop,
+ * as lbarray ordering is not enough to ensure us we did catch all dependencies
+ * (e.g. if making local a parent object before its child...). See T48907. */
+ /* TODO This is now the biggest step by far (in term of processing time). We may be able to gain here by
+ * using again main->relations mapping, but... this implies BKE_libblock_remap & co to be able to update
+ * main->relations on the fly. Have to think about it a bit more, and see whether new code is OK first, anyway. */
+ for (LinkNode *it = copied_ids; it; it = it->next) {
+ ID *id = it->link;
+
+ BLI_assert(id->newid != NULL);
+ BLI_assert(id->lib != NULL);
+
+ BKE_libblock_remap(bmain, id, id->newid, ID_REMAP_SKIP_INDIRECT_USAGE);
+ if (old_to_new_ids) {
+ BLI_ghash_insert(old_to_new_ids, id, id->newid);
+ }
+
+ /* Special hack for groups... Thing is, since we can't instantiate them here, we need to ensure
+ * they remain 'alive' (only instantiation is a real group 'user'... *sigh* See T49722. */
+ if (GS(id->name) == ID_GR && (id->tag & LIB_TAG_INDIRECT) != 0) {
+ id_us_ensure_real(id->newid);
+ }
+ }
#ifdef DEBUG_TIME
- printf("Step 4: Remap local usages of old (linked) ID to new (local) ID: Done.\n");
- TIMEIT_VALUE_PRINT(make_local);
+ printf("Step 4: Remap local usages of old (linked) ID to new (local) ID: Done.\n");
+ TIMEIT_VALUE_PRINT(make_local);
#endif
- /* Step 5: proxy 'remapping' hack. */
- for (LinkNode *it = copied_ids; it; it = it->next) {
- ID *id = it->link;
-
- /* Attempt to re-link copied proxy objects. This allows appending of an entire scene
- * from another blend file into this one, even when that blend file contains proxified
- * armatures that have local references. Since the proxified object needs to be linked
- * (not local), this will only work when the "Localize all" checkbox is disabled.
- * TL;DR: this is a dirty hack on top of an already weak feature (proxies). */
- if (GS(id->name) == ID_OB && ((Object *)id)->proxy != NULL) {
- Object *ob = (Object *)id;
- Object *ob_new = (Object *)id->newid;
- bool is_local = false, is_lib = false;
-
- /* Proxies only work when the proxified object is linked-in from a library. */
- if (ob->proxy->id.lib == NULL) {
- CLOG_WARN(&LOG, "proxy object %s will loose its link to %s, because the "
- "proxified object is local.", id->newid->name, ob->proxy->id.name);
- continue;
- }
-
- BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib);
-
- /* We can only switch the proxy'ing to a made-local proxy if it is no longer
- * referred to from a library. Not checking for local use; if new local proxy
- * was not used locally would be a nasty bug! */
- if (is_local || is_lib) {
- CLOG_WARN(&LOG, "made-local proxy object %s will loose its link to %s, "
- "because the linked-in proxy is referenced (is_local=%i, is_lib=%i).",
- id->newid->name, ob->proxy->id.name, is_local, is_lib);
- }
- else {
- /* we can switch the proxy'ing from the linked-in to the made-local proxy.
- * BKE_object_make_proxy() shouldn't be used here, as it allocates memory that
- * was already allocated by BKE_object_make_local_ex() (which called BKE_object_copy). */
- ob_new->proxy = ob->proxy;
- ob_new->proxy_group = ob->proxy_group;
- ob_new->proxy_from = ob->proxy_from;
- ob_new->proxy->proxy_from = ob_new;
- ob->proxy = ob->proxy_from = ob->proxy_group = NULL;
- }
- }
- }
+ /* Step 5: proxy 'remapping' hack. */
+ for (LinkNode *it = copied_ids; it; it = it->next) {
+ ID *id = it->link;
+
+ /* Attempt to re-link copied proxy objects. This allows appending of an entire scene
+ * from another blend file into this one, even when that blend file contains proxified
+ * armatures that have local references. Since the proxified object needs to be linked
+ * (not local), this will only work when the "Localize all" checkbox is disabled.
+ * TL;DR: this is a dirty hack on top of an already weak feature (proxies). */
+ if (GS(id->name) == ID_OB && ((Object *)id)->proxy != NULL) {
+ Object *ob = (Object *)id;
+ Object *ob_new = (Object *)id->newid;
+ bool is_local = false, is_lib = false;
+
+ /* Proxies only work when the proxified object is linked-in from a library. */
+ if (ob->proxy->id.lib == NULL) {
+ CLOG_WARN(&LOG,
+ "proxy object %s will loose its link to %s, because the "
+ "proxified object is local.",
+ id->newid->name,
+ ob->proxy->id.name);
+ continue;
+ }
+
+ BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib);
+
+ /* We can only switch the proxy'ing to a made-local proxy if it is no longer
+ * referred to from a library. Not checking for local use; if new local proxy
+ * was not used locally would be a nasty bug! */
+ if (is_local || is_lib) {
+ CLOG_WARN(&LOG,
+ "made-local proxy object %s will loose its link to %s, "
+ "because the linked-in proxy is referenced (is_local=%i, is_lib=%i).",
+ id->newid->name,
+ ob->proxy->id.name,
+ is_local,
+ is_lib);
+ }
+ else {
+ /* we can switch the proxy'ing from the linked-in to the made-local proxy.
+ * BKE_object_make_proxy() shouldn't be used here, as it allocates memory that
+ * was already allocated by BKE_object_make_local_ex() (which called BKE_object_copy). */
+ ob_new->proxy = ob->proxy;
+ ob_new->proxy_group = ob->proxy_group;
+ ob_new->proxy_from = ob->proxy_from;
+ ob_new->proxy->proxy_from = ob_new;
+ ob->proxy = ob->proxy_from = ob->proxy_group = NULL;
+ }
+ }
+ }
#ifdef DEBUG_TIME
- printf("Step 5: Proxy 'remapping' hack: Done.\n");
- TIMEIT_VALUE_PRINT(make_local);
+ printf("Step 5: Proxy 'remapping' hack: Done.\n");
+ TIMEIT_VALUE_PRINT(make_local);
#endif
- /* This is probably more of a hack than something we should do here, but...
- * Issue is, the whole copying + remapping done in complex cases above may leave pose channels of armatures
- * in complete invalid state (more precisely, the bone pointers of the pchans - very crappy cross-datablocks
- * relationship), se we tag it to be fully recomputed, but this does not seems to be enough in some cases,
- * and evaluation code ends up trying to evaluate a not-yet-updated armature object's deformations.
- * Try "make all local" in 04_01_H.lighting.blend from Agent327 without this, e.g. */
- for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
- if (ob->data != NULL && ob->type == OB_ARMATURE && ob->pose != NULL && ob->pose->flag & POSE_RECALC) {
- BKE_pose_rebuild(bmain, ob, ob->data, true);
- }
- }
-
- /* Reset rigid body objects. */
- for (LinkNode *it = copied_ids; it; it = it->next) {
- ID *id = it->link;
- if (GS(id->name) == ID_OB) {
- Object *ob = (Object *)id;
-
- /* If there was ever any rigidbody settings in the object, we reset it. */
- if (ob->rigidbody_object) {
- for (Scene *scene_iter = bmain->scenes.first; scene_iter; scene_iter = scene_iter->id.next) {
- if (scene_iter->rigidbody_world) {
- BKE_rigidbody_remove_object(bmain, scene_iter, ob);
- }
- }
- BKE_rigidbody_free_object(ob, NULL);
- }
- }
- }
+ /* This is probably more of a hack than something we should do here, but...
+ * Issue is, the whole copying + remapping done in complex cases above may leave pose channels of armatures
+ * in complete invalid state (more precisely, the bone pointers of the pchans - very crappy cross-datablocks
+ * relationship), se we tag it to be fully recomputed, but this does not seems to be enough in some cases,
+ * and evaluation code ends up trying to evaluate a not-yet-updated armature object's deformations.
+ * Try "make all local" in 04_01_H.lighting.blend from Agent327 without this, e.g. */
+ for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
+ if (ob->data != NULL && ob->type == OB_ARMATURE && ob->pose != NULL &&
+ ob->pose->flag & POSE_RECALC) {
+ BKE_pose_rebuild(bmain, ob, ob->data, true);
+ }
+ }
+
+ /* Reset rigid body objects. */
+ for (LinkNode *it = copied_ids; it; it = it->next) {
+ ID *id = it->link;
+ if (GS(id->name) == ID_OB) {
+ Object *ob = (Object *)id;
+
+ /* If there was ever any rigidbody settings in the object, we reset it. */
+ if (ob->rigidbody_object) {
+ for (Scene *scene_iter = bmain->scenes.first; scene_iter;
+ scene_iter = scene_iter->id.next) {
+ if (scene_iter->rigidbody_world) {
+ BKE_rigidbody_remove_object(bmain, scene_iter, ob);
+ }
+ }
+ BKE_rigidbody_free_object(ob, NULL);
+ }
+ }
+ }
#ifdef DEBUG_TIME
- printf("Hack: Forcefully rebuild armature object poses: Done.\n");
- TIMEIT_VALUE_PRINT(make_local);
+ printf("Hack: Forcefully rebuild armature object poses: Done.\n");
+ TIMEIT_VALUE_PRINT(make_local);
#endif
- BKE_main_id_clear_newpoins(bmain);
- BLI_memarena_free(linklist_mem);
+ BKE_main_id_clear_newpoins(bmain);
+ BLI_memarena_free(linklist_mem);
#ifdef DEBUG_TIME
- printf("Cleanup and finish: Done.\n");
- TIMEIT_END(make_local);
+ printf("Cleanup and finish: Done.\n");
+ TIMEIT_END(make_local);
#endif
}
@@ -2012,19 +2087,20 @@ void BKE_library_make_local(
*/
void BLI_libblock_ensure_unique_name(Main *bmain, const char *name)
{
- ListBase *lb;
- ID *idtest;
+ ListBase *lb;
+ ID *idtest;
- lb = which_libbase(bmain, GS(name));
- if (lb == NULL) return;
+ lb = which_libbase(bmain, GS(name));
+ if (lb == NULL)
+ return;
- /* search for id */
- idtest = BLI_findstring(lb, name + 2, offsetof(ID, name) + 2);
- if (idtest != NULL) {
- /* BKE_id_new_name_validate also takes care of sorting. */
- BKE_id_new_name_validate(lb, idtest, NULL);
- bmain->is_memfile_undo_written = false;
- }
+ /* search for id */
+ idtest = BLI_findstring(lb, name + 2, offsetof(ID, name) + 2);
+ if (idtest != NULL) {
+ /* BKE_id_new_name_validate also takes care of sorting. */
+ BKE_id_new_name_validate(lb, idtest, NULL);
+ bmain->is_memfile_undo_written = false;
+ }
}
/**
@@ -2032,10 +2108,10 @@ void BLI_libblock_ensure_unique_name(Main *bmain, const char *name)
*/
void BKE_libblock_rename(Main *bmain, ID *id, const char *name)
{
- ListBase *lb = which_libbase(bmain, GS(id->name));
- if (BKE_id_new_name_validate(lb, id, name)) {
- bmain->is_memfile_undo_written = false;
- }
+ ListBase *lb = which_libbase(bmain, GS(id->name));
+ if (BKE_id_new_name_validate(lb, id, name)) {
+ bmain->is_memfile_undo_written = false;
+ }
}
/**
@@ -2047,18 +2123,18 @@ void BKE_libblock_rename(Main *bmain, ID *id, const char *name)
*/
void BKE_id_full_name_get(char name[MAX_ID_FULL_NAME], const ID *id)
{
- strcpy(name, id->name + 2);
+ strcpy(name, id->name + 2);
- if (id->lib != NULL) {
- const size_t idname_len = strlen(id->name + 2);
- const size_t libname_len = strlen(id->lib->id.name + 2);
+ if (id->lib != NULL) {
+ const size_t idname_len = strlen(id->name + 2);
+ const size_t libname_len = strlen(id->lib->id.name + 2);
- name[idname_len] = ' ';
- name[idname_len + 1] = '[';
- strcpy(name + idname_len + 2, id->lib->id.name + 2);
- name[idname_len + 2 + libname_len] = ']';
- name[idname_len + 2 + libname_len + 1] = '\0';
- }
+ name[idname_len] = ' ';
+ name[idname_len + 1] = '[';
+ strcpy(name + idname_len + 2, id->lib->id.name + 2);
+ name[idname_len + 2 + libname_len] = ']';
+ name[idname_len + 2 + libname_len + 1] = '\0';
+ }
}
/**
@@ -2071,11 +2147,11 @@ void BKE_id_full_name_get(char name[MAX_ID_FULL_NAME], const ID *id)
*/
void BKE_id_full_name_ui_prefix_get(char name[MAX_ID_FULL_NAME_UI], const ID *id)
{
- name[0] = id->lib ? (ID_MISSING(id) ? 'M' : 'L') : ID_IS_STATIC_OVERRIDE(id) ? 'O' : ' ';
- name[1] = (id->flag & LIB_FAKEUSER) ? 'F' : ((id->us == 0) ? '0' : ' ');
- name[2] = ' ';
+ name[0] = id->lib ? (ID_MISSING(id) ? 'M' : 'L') : ID_IS_STATIC_OVERRIDE(id) ? 'O' : ' ';
+ name[1] = (id->flag & LIB_FAKEUSER) ? 'F' : ((id->us == 0) ? '0' : ' ');
+ name[2] = ' ';
- BKE_id_full_name_get(name + 3, id);
+ BKE_id_full_name_get(name + 3, id);
}
/**
@@ -2085,92 +2161,92 @@ void BKE_id_full_name_ui_prefix_get(char name[MAX_ID_FULL_NAME_UI], const ID *id
*/
char *BKE_id_to_unique_string_key(const struct ID *id)
{
- if (id->lib == NULL) {
- return BLI_strdup(id->name);
- }
- else {
- /* Prefix with an ascii character in the range of 32..96 (visible)
- * this ensures we can't have a library ID pair that collide.
- * Where 'LIfooOBbarOBbaz' could be ('LIfoo, OBbarOBbaz') or ('LIfooOBbar', 'OBbaz'). */
- const char ascii_len = strlen(id->lib->id.name + 2) + 32;
- return BLI_sprintfN("%c%s%s", ascii_len, id->lib->id.name, id->name);
- }
+ if (id->lib == NULL) {
+ return BLI_strdup(id->name);
+ }
+ else {
+ /* Prefix with an ascii character in the range of 32..96 (visible)
+ * this ensures we can't have a library ID pair that collide.
+ * Where 'LIfooOBbarOBbaz' could be ('LIfoo, OBbarOBbaz') or ('LIfooOBbar', 'OBbaz'). */
+ const char ascii_len = strlen(id->lib->id.name + 2) + 32;
+ return BLI_sprintfN("%c%s%s", ascii_len, id->lib->id.name, id->name);
+ }
}
void BKE_library_filepath_set(Main *bmain, Library *lib, const char *filepath)
{
- /* in some cases this is used to update the absolute path from the
- * relative */
- if (lib->name != filepath) {
- BLI_strncpy(lib->name, filepath, sizeof(lib->name));
- }
-
- BLI_strncpy(lib->filepath, filepath, sizeof(lib->filepath));
-
- /* not essential but set filepath is an absolute copy of value which
- * is more useful if its kept in sync */
- if (BLI_path_is_rel(lib->filepath)) {
- /* note that the file may be unsaved, in this case, setting the
- * filepath on an indirectly linked path is not allowed from the
- * outliner, and its not really supported but allow from here for now
- * since making local could cause this to be directly linked - campbell
- */
- /* Never make paths relative to parent lib - reading code (blenloader) always set *all* lib->name relative to
- * current main, not to their parent for indirectly linked ones. */
- const char *basepath = BKE_main_blendfile_path(bmain);
- BLI_path_abs(lib->filepath, basepath);
- }
+ /* in some cases this is used to update the absolute path from the
+ * relative */
+ if (lib->name != filepath) {
+ BLI_strncpy(lib->name, filepath, sizeof(lib->name));
+ }
+
+ BLI_strncpy(lib->filepath, filepath, sizeof(lib->filepath));
+
+ /* not essential but set filepath is an absolute copy of value which
+ * is more useful if its kept in sync */
+ if (BLI_path_is_rel(lib->filepath)) {
+ /* note that the file may be unsaved, in this case, setting the
+ * filepath on an indirectly linked path is not allowed from the
+ * outliner, and its not really supported but allow from here for now
+ * since making local could cause this to be directly linked - campbell
+ */
+ /* Never make paths relative to parent lib - reading code (blenloader) always set *all* lib->name relative to
+ * current main, not to their parent for indirectly linked ones. */
+ const char *basepath = BKE_main_blendfile_path(bmain);
+ BLI_path_abs(lib->filepath, basepath);
+ }
}
void BKE_id_tag_set_atomic(ID *id, int tag)
{
- atomic_fetch_and_or_int32(&id->tag, tag);
+ atomic_fetch_and_or_int32(&id->tag, tag);
}
void BKE_id_tag_clear_atomic(ID *id, int tag)
{
- atomic_fetch_and_and_int32(&id->tag, ~tag);
+ atomic_fetch_and_and_int32(&id->tag, ~tag);
}
/** Check that given ID pointer actually is in G_MAIN.
* Main intended use is for debug asserts in places we cannot easily get rid of G_Main... */
bool BKE_id_is_in_global_main(ID *id)
{
- /* We do not want to fail when id is NULL here, even though this is a bit strange behavior... */
- return (id == NULL || BLI_findindex(which_libbase(G_MAIN, GS(id->name)), id) != -1);
+ /* We do not want to fail when id is NULL here, even though this is a bit strange behavior... */
+ return (id == NULL || BLI_findindex(which_libbase(G_MAIN, GS(id->name)), id) != -1);
}
/************************* Datablock order in UI **************************/
static int *id_order_get(ID *id)
{
- /* Only for workspace tabs currently. */
- switch (GS(id->name)) {
- case ID_WS:
- return &((WorkSpace *)id)->order;
- default:
- return NULL;
- }
+ /* Only for workspace tabs currently. */
+ switch (GS(id->name)) {
+ case ID_WS:
+ return &((WorkSpace *)id)->order;
+ default:
+ return NULL;
+ }
}
static int id_order_compare(const void *a, const void *b)
{
- ID *id_a = ((LinkData *)a)->data;
- ID *id_b = ((LinkData *)b)->data;
+ ID *id_a = ((LinkData *)a)->data;
+ ID *id_b = ((LinkData *)b)->data;
- int *order_a = id_order_get(id_a);
- int *order_b = id_order_get(id_b);
+ int *order_a = id_order_get(id_a);
+ int *order_b = id_order_get(id_b);
- if (order_a && order_b) {
- if (*order_a < *order_b) {
- return -1;
- }
- else if (*order_a > *order_b) {
- return 1;
- }
- }
+ if (order_a && order_b) {
+ if (*order_a < *order_b) {
+ return -1;
+ }
+ else if (*order_a > *order_b) {
+ return 1;
+ }
+ }
- return strcmp(id_a->name, id_b->name);
+ return strcmp(id_a->name, id_b->name);
}
/**
@@ -2179,21 +2255,21 @@ static int id_order_compare(const void *a, const void *b)
*/
void BKE_id_ordered_list(ListBase *ordered_lb, const ListBase *lb)
{
- BLI_listbase_clear(ordered_lb);
+ BLI_listbase_clear(ordered_lb);
- for (ID *id = lb->first; id; id = id->next) {
- BLI_addtail(ordered_lb, BLI_genericNodeN(id));
- }
+ for (ID *id = lb->first; id; id = id->next) {
+ BLI_addtail(ordered_lb, BLI_genericNodeN(id));
+ }
- BLI_listbase_sort(ordered_lb, id_order_compare);
+ BLI_listbase_sort(ordered_lb, id_order_compare);
- int num = 0;
- for (LinkData *link = ordered_lb->first; link; link = link->next) {
- int *order = id_order_get(link->data);
- if (order) {
- *order = num++;
- }
- }
+ int num = 0;
+ for (LinkData *link = ordered_lb->first; link; link = link->next) {
+ int *order = id_order_get(link->data);
+ if (order) {
+ *order = num++;
+ }
+ }
}
/**
@@ -2201,36 +2277,36 @@ void BKE_id_ordered_list(ListBase *ordered_lb, const ListBase *lb)
*/
void BKE_id_reorder(const ListBase *lb, ID *id, ID *relative, bool after)
{
- int *id_order = id_order_get(id);
- int relative_order;
-
- if (relative) {
- relative_order = *id_order_get(relative);
- }
- else {
- relative_order = (after) ? BLI_listbase_count(lb) : 0;
- }
-
- if (after) {
- /* Insert after. */
- for (ID *other = lb->first; other; other = other->next) {
- int *order = id_order_get(other);
- if (*order > relative_order) {
- (*order)++;
- }
- }
-
- *id_order = relative_order + 1;
- }
- else {
- /* Insert before. */
- for (ID *other = lb->first; other; other = other->next) {
- int *order = id_order_get(other);
- if (*order < relative_order) {
- (*order)--;
- }
- }
-
- *id_order = relative_order - 1;
- }
+ int *id_order = id_order_get(id);
+ int relative_order;
+
+ if (relative) {
+ relative_order = *id_order_get(relative);
+ }
+ else {
+ relative_order = (after) ? BLI_listbase_count(lb) : 0;
+ }
+
+ if (after) {
+ /* Insert after. */
+ for (ID *other = lb->first; other; other = other->next) {
+ int *order = id_order_get(other);
+ if (*order > relative_order) {
+ (*order)++;
+ }
+ }
+
+ *id_order = relative_order + 1;
+ }
+ else {
+ /* Insert before. */
+ for (ID *other = lb->first; other; other = other->next) {
+ int *order = id_order_get(other);
+ if (*order < relative_order) {
+ (*order)--;
+ }
+ }
+
+ *id_order = relative_order - 1;
+ }
}
diff --git a/source/blender/blenkernel/intern/library_idmap.c b/source/blender/blenkernel/intern/library_idmap.c
index f03fa63843b..d520df31a75 100644
--- a/source/blender/blenkernel/intern/library_idmap.c
+++ b/source/blender/blenkernel/intern/library_idmap.c
@@ -26,7 +26,7 @@
#include "DNA_ID.h"
#include "BKE_idcode.h"
-#include "BKE_library_idmap.h" /* own include */
+#include "BKE_library_idmap.h" /* own include */
#include "BKE_main.h"
/** \file
@@ -47,36 +47,37 @@
* \{ */
struct IDNameLib_Key {
- /** ``ID.name + 2``: without the ID type prefix, since each id type gets it's own 'map' */
- const char *name;
- /** ``ID.lib``: */
- const Library *lib;
+ /** ``ID.name + 2``: without the ID type prefix, since each id type gets it's own 'map' */
+ const char *name;
+ /** ``ID.lib``: */
+ const Library *lib;
};
struct IDNameLib_TypeMap {
- GHash *map;
- short id_type;
- /* only for storage of keys in the ghash, avoid many single allocs */
- struct IDNameLib_Key *keys;
+ GHash *map;
+ short id_type;
+ /* only for storage of keys in the ghash, avoid many single allocs */
+ struct IDNameLib_Key *keys;
};
/**
* Opaque structure, external API users only see this.
*/
struct IDNameLib_Map {
- struct IDNameLib_TypeMap type_maps[MAX_LIBARRAY];
- struct Main *bmain;
- struct GSet *valid_id_pointers;
+ struct IDNameLib_TypeMap type_maps[MAX_LIBARRAY];
+ struct Main *bmain;
+ struct GSet *valid_id_pointers;
};
-static struct IDNameLib_TypeMap *main_idmap_from_idcode(struct IDNameLib_Map *id_map, short id_type)
+static struct IDNameLib_TypeMap *main_idmap_from_idcode(struct IDNameLib_Map *id_map,
+ short id_type)
{
- for (int i = 0; i < MAX_LIBARRAY; i++) {
- if (id_map->type_maps[i].id_type == id_type) {
- return &id_map->type_maps[i];
- }
- }
- return NULL;
+ for (int i = 0; i < MAX_LIBARRAY; i++) {
+ if (id_map->type_maps[i].id_type == id_type) {
+ return &id_map->type_maps[i];
+ }
+ }
+ return NULL;
}
/**
@@ -91,118 +92,122 @@ static struct IDNameLib_TypeMap *main_idmap_from_idcode(struct IDNameLib_Map *id
* \param create_valid_ids_set: If \a true, generate a reference to prevent freed memory accesses.
* \param old_bmain: If not NULL, its IDs will be added the valid references set.
*/
-struct IDNameLib_Map *BKE_main_idmap_create(
- struct Main *bmain, const bool create_valid_ids_set, struct Main *old_bmain)
+struct IDNameLib_Map *BKE_main_idmap_create(struct Main *bmain,
+ const bool create_valid_ids_set,
+ struct Main *old_bmain)
{
- struct IDNameLib_Map *id_map = MEM_mallocN(sizeof(*id_map), __func__);
-
- int index = 0;
- while (index < MAX_LIBARRAY) {
- struct IDNameLib_TypeMap *type_map = &id_map->type_maps[index];
- type_map->map = NULL;
- type_map->id_type = BKE_idcode_iter_step(&index);
- BLI_assert(type_map->id_type != 0);
- }
- BLI_assert(index == MAX_LIBARRAY);
-
- id_map->bmain = bmain;
-
- if (create_valid_ids_set) {
- id_map->valid_id_pointers = BKE_main_gset_create(bmain, NULL);
- if (old_bmain != NULL) {
- id_map->valid_id_pointers = BKE_main_gset_create(old_bmain, id_map->valid_id_pointers);
- }
- }
- else {
- id_map->valid_id_pointers = NULL;
- }
-
- return id_map;
+ struct IDNameLib_Map *id_map = MEM_mallocN(sizeof(*id_map), __func__);
+
+ int index = 0;
+ while (index < MAX_LIBARRAY) {
+ struct IDNameLib_TypeMap *type_map = &id_map->type_maps[index];
+ type_map->map = NULL;
+ type_map->id_type = BKE_idcode_iter_step(&index);
+ BLI_assert(type_map->id_type != 0);
+ }
+ BLI_assert(index == MAX_LIBARRAY);
+
+ id_map->bmain = bmain;
+
+ if (create_valid_ids_set) {
+ id_map->valid_id_pointers = BKE_main_gset_create(bmain, NULL);
+ if (old_bmain != NULL) {
+ id_map->valid_id_pointers = BKE_main_gset_create(old_bmain, id_map->valid_id_pointers);
+ }
+ }
+ else {
+ id_map->valid_id_pointers = NULL;
+ }
+
+ return id_map;
}
struct Main *BKE_main_idmap_main_get(struct IDNameLib_Map *id_map)
{
- return id_map->bmain;
+ return id_map->bmain;
}
static unsigned int idkey_hash(const void *ptr)
{
- const struct IDNameLib_Key *idkey = ptr;
- unsigned int key = BLI_ghashutil_strhash(idkey->name);
- if (idkey->lib) {
- key ^= BLI_ghashutil_ptrhash(idkey->lib);
- }
- return key;
+ const struct IDNameLib_Key *idkey = ptr;
+ unsigned int key = BLI_ghashutil_strhash(idkey->name);
+ if (idkey->lib) {
+ key ^= BLI_ghashutil_ptrhash(idkey->lib);
+ }
+ return key;
}
static bool idkey_cmp(const void *a, const void *b)
{
- const struct IDNameLib_Key *idkey_a = a;
- const struct IDNameLib_Key *idkey_b = b;
- return strcmp(idkey_a->name, idkey_b->name) || (idkey_a->lib != idkey_b->lib);
+ const struct IDNameLib_Key *idkey_a = a;
+ const struct IDNameLib_Key *idkey_b = b;
+ return strcmp(idkey_a->name, idkey_b->name) || (idkey_a->lib != idkey_b->lib);
}
-ID *BKE_main_idmap_lookup(struct IDNameLib_Map *id_map, short id_type, const char *name, const Library *lib)
+ID *BKE_main_idmap_lookup(struct IDNameLib_Map *id_map,
+ short id_type,
+ const char *name,
+ const Library *lib)
{
- struct IDNameLib_TypeMap *type_map = main_idmap_from_idcode(id_map, id_type);
-
- if (UNLIKELY(type_map == NULL)) {
- return NULL;
- }
-
- /* lazy init */
- if (type_map->map == NULL) {
- ListBase *lb = which_libbase(id_map->bmain, id_type);
- const int lb_len = BLI_listbase_count(lb);
- if (lb_len == 0) {
- return NULL;
- }
- type_map->map = BLI_ghash_new_ex(idkey_hash, idkey_cmp, __func__, lb_len);
- type_map->keys = MEM_mallocN(sizeof(struct IDNameLib_Key) * lb_len, __func__);
-
- GHash *map = type_map->map;
- struct IDNameLib_Key *key = type_map->keys;
-
- for (ID *id = lb->first; id; id = id->next, key++) {
- key->name = id->name + 2;
- key->lib = id->lib;
- BLI_ghash_insert(map, key, id);
- }
- }
-
- const struct IDNameLib_Key key_lookup = {name, lib};
- return BLI_ghash_lookup(type_map->map, &key_lookup);
+ struct IDNameLib_TypeMap *type_map = main_idmap_from_idcode(id_map, id_type);
+
+ if (UNLIKELY(type_map == NULL)) {
+ return NULL;
+ }
+
+ /* lazy init */
+ if (type_map->map == NULL) {
+ ListBase *lb = which_libbase(id_map->bmain, id_type);
+ const int lb_len = BLI_listbase_count(lb);
+ if (lb_len == 0) {
+ return NULL;
+ }
+ type_map->map = BLI_ghash_new_ex(idkey_hash, idkey_cmp, __func__, lb_len);
+ type_map->keys = MEM_mallocN(sizeof(struct IDNameLib_Key) * lb_len, __func__);
+
+ GHash *map = type_map->map;
+ struct IDNameLib_Key *key = type_map->keys;
+
+ for (ID *id = lb->first; id; id = id->next, key++) {
+ key->name = id->name + 2;
+ key->lib = id->lib;
+ BLI_ghash_insert(map, key, id);
+ }
+ }
+
+ const struct IDNameLib_Key key_lookup = {name, lib};
+ return BLI_ghash_lookup(type_map->map, &key_lookup);
}
ID *BKE_main_idmap_lookup_id(struct IDNameLib_Map *id_map, const ID *id)
{
- /* When used during undo/redo, this function cannot assume that given id points to valid memory
- * (i.e. has not been freed), so it has to check that it does exist in 'old' (aka current) Main database.
- * Otherwise, we cannot provide new ID pointer that way (would crash accessing freed memory
- * when trying to get ID name).
- */
- if (id_map->valid_id_pointers == NULL || BLI_gset_haskey(id_map->valid_id_pointers, id)) {
- return BKE_main_idmap_lookup(id_map, GS(id->name), id->name + 2, id->lib);
- }
- return NULL;
+ /* When used during undo/redo, this function cannot assume that given id points to valid memory
+ * (i.e. has not been freed), so it has to check that it does exist in 'old' (aka current) Main database.
+ * Otherwise, we cannot provide new ID pointer that way (would crash accessing freed memory
+ * when trying to get ID name).
+ */
+ if (id_map->valid_id_pointers == NULL || BLI_gset_haskey(id_map->valid_id_pointers, id)) {
+ return BKE_main_idmap_lookup(id_map, GS(id->name), id->name + 2, id->lib);
+ }
+ return NULL;
}
void BKE_main_idmap_destroy(struct IDNameLib_Map *id_map)
{
- struct IDNameLib_TypeMap *type_map = id_map->type_maps;
- for (int i = 0; i < MAX_LIBARRAY; i++, type_map++) {
- if (type_map->map) {
- BLI_ghash_free(type_map->map, NULL, NULL);
- type_map->map = NULL;
- MEM_freeN(type_map->keys);
- }
- }
-
- if (id_map->valid_id_pointers != NULL) {
- BLI_gset_free(id_map->valid_id_pointers, NULL);
- }
-
- MEM_freeN(id_map);
+ struct IDNameLib_TypeMap *type_map = id_map->type_maps;
+ for (int i = 0; i < MAX_LIBARRAY; i++, type_map++) {
+ if (type_map->map) {
+ BLI_ghash_free(type_map->map, NULL, NULL);
+ type_map->map = NULL;
+ MEM_freeN(type_map->keys);
+ }
+ }
+
+ if (id_map->valid_id_pointers != NULL) {
+ BLI_gset_free(id_map->valid_id_pointers, NULL);
+ }
+
+ MEM_freeN(id_map);
}
/** \} */
diff --git a/source/blender/blenkernel/intern/library_override.c b/source/blender/blenkernel/intern/library_override.c
index c54f11934e1..7a29575dffe 100644
--- a/source/blender/blenkernel/intern/library_override.c
+++ b/source/blender/blenkernel/intern/library_override.c
@@ -45,10 +45,12 @@
#include "PIL_time.h"
#include "PIL_time_utildefines.h"
-#define OVERRIDE_AUTO_CHECK_DELAY 0.2 /* 200ms between auto-override checks. */
+#define OVERRIDE_AUTO_CHECK_DELAY 0.2 /* 200ms between auto-override checks. */
-static void bke_override_property_copy(IDOverrideStaticProperty *op_dst, IDOverrideStaticProperty *op_src);
-static void bke_override_property_operation_copy(IDOverrideStaticPropertyOperation *opop_dst, IDOverrideStaticPropertyOperation *opop_src);
+static void bke_override_property_copy(IDOverrideStaticProperty *op_dst,
+ IDOverrideStaticProperty *op_src);
+static void bke_override_property_operation_copy(IDOverrideStaticPropertyOperation *opop_dst,
+ IDOverrideStaticPropertyOperation *opop_src);
static void bke_override_property_clear(IDOverrideStaticProperty *op);
static void bke_override_property_operation_clear(IDOverrideStaticPropertyOperation *opop);
@@ -58,136 +60,139 @@ static bool _override_static_enabled = false;
void BKE_override_static_enable(const bool do_enable)
{
- _override_static_enabled = do_enable;
+ _override_static_enabled = do_enable;
}
bool BKE_override_static_is_enabled()
{
- return _override_static_enabled;
+ return _override_static_enabled;
}
/** Initialize empty overriding of \a reference_id by \a local_id. */
IDOverrideStatic *BKE_override_static_init(ID *local_id, ID *reference_id)
{
- /* If reference_id is NULL, we are creating an override template for purely local data.
- * Else, reference *must* be linked data. */
- BLI_assert(reference_id == NULL || reference_id->lib != NULL);
- BLI_assert(local_id->override_static == NULL);
-
- ID *ancestor_id;
- for (ancestor_id = reference_id;
- ancestor_id != NULL && ancestor_id->override_static != NULL && ancestor_id->override_static->reference != NULL;
- ancestor_id = ancestor_id->override_static->reference);
-
- if (ancestor_id != NULL && ancestor_id->override_static != NULL) {
- /* Original ID has a template, use it! */
- BKE_override_static_copy(local_id, ancestor_id);
- if (local_id->override_static->reference != reference_id) {
- id_us_min(local_id->override_static->reference);
- local_id->override_static->reference = reference_id;
- id_us_plus(local_id->override_static->reference);
- }
- return local_id->override_static;
- }
-
- /* Else, generate new empty override. */
- local_id->override_static = MEM_callocN(sizeof(*local_id->override_static), __func__);
- local_id->override_static->reference = reference_id;
- id_us_plus(local_id->override_static->reference);
- local_id->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK;
- /* TODO do we want to add tag or flag to referee to mark it as such? */
- return local_id->override_static;
+ /* If reference_id is NULL, we are creating an override template for purely local data.
+ * Else, reference *must* be linked data. */
+ BLI_assert(reference_id == NULL || reference_id->lib != NULL);
+ BLI_assert(local_id->override_static == NULL);
+
+ ID *ancestor_id;
+ for (ancestor_id = reference_id; ancestor_id != NULL && ancestor_id->override_static != NULL &&
+ ancestor_id->override_static->reference != NULL;
+ ancestor_id = ancestor_id->override_static->reference)
+ ;
+
+ if (ancestor_id != NULL && ancestor_id->override_static != NULL) {
+ /* Original ID has a template, use it! */
+ BKE_override_static_copy(local_id, ancestor_id);
+ if (local_id->override_static->reference != reference_id) {
+ id_us_min(local_id->override_static->reference);
+ local_id->override_static->reference = reference_id;
+ id_us_plus(local_id->override_static->reference);
+ }
+ return local_id->override_static;
+ }
+
+ /* Else, generate new empty override. */
+ local_id->override_static = MEM_callocN(sizeof(*local_id->override_static), __func__);
+ local_id->override_static->reference = reference_id;
+ id_us_plus(local_id->override_static->reference);
+ local_id->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK;
+ /* TODO do we want to add tag or flag to referee to mark it as such? */
+ return local_id->override_static;
}
/** Deep copy of a whole override from \a src_id to \a dst_id. */
void BKE_override_static_copy(ID *dst_id, const ID *src_id)
{
- BLI_assert(src_id->override_static != NULL);
-
- if (dst_id->override_static != NULL) {
- if (src_id->override_static == NULL) {
- BKE_override_static_free(&dst_id->override_static);
- return;
- }
- else {
- BKE_override_static_clear(dst_id->override_static);
- }
- }
- else if (src_id->override_static == NULL) {
- return;
- }
- else {
- BKE_override_static_init(dst_id, NULL);
- }
-
- /* Source is already overriding data, we copy it but reuse its reference for dest ID.
- * otherwise, source is only an override template, it then becomes reference of dest ID. */
- dst_id->override_static->reference = src_id->override_static->reference ? src_id->override_static->reference : (ID *)src_id;
- id_us_plus(dst_id->override_static->reference);
-
- BLI_duplicatelist(&dst_id->override_static->properties, &src_id->override_static->properties);
- for (IDOverrideStaticProperty *op_dst = dst_id->override_static->properties.first, *op_src = src_id->override_static->properties.first;
- op_dst;
- op_dst = op_dst->next, op_src = op_src->next)
- {
- bke_override_property_copy(op_dst, op_src);
- }
-
- dst_id->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK;
+ BLI_assert(src_id->override_static != NULL);
+
+ if (dst_id->override_static != NULL) {
+ if (src_id->override_static == NULL) {
+ BKE_override_static_free(&dst_id->override_static);
+ return;
+ }
+ else {
+ BKE_override_static_clear(dst_id->override_static);
+ }
+ }
+ else if (src_id->override_static == NULL) {
+ return;
+ }
+ else {
+ BKE_override_static_init(dst_id, NULL);
+ }
+
+ /* Source is already overriding data, we copy it but reuse its reference for dest ID.
+ * otherwise, source is only an override template, it then becomes reference of dest ID. */
+ dst_id->override_static->reference = src_id->override_static->reference ?
+ src_id->override_static->reference :
+ (ID *)src_id;
+ id_us_plus(dst_id->override_static->reference);
+
+ BLI_duplicatelist(&dst_id->override_static->properties, &src_id->override_static->properties);
+ for (IDOverrideStaticProperty *op_dst = dst_id->override_static->properties.first,
+ *op_src = src_id->override_static->properties.first;
+ op_dst;
+ op_dst = op_dst->next, op_src = op_src->next) {
+ bke_override_property_copy(op_dst, op_src);
+ }
+
+ dst_id->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK;
}
/** Clear any overriding data from given \a override. */
void BKE_override_static_clear(IDOverrideStatic *override)
{
- BLI_assert(override != NULL);
+ BLI_assert(override != NULL);
- for (IDOverrideStaticProperty *op = override->properties.first; op; op = op->next) {
- bke_override_property_clear(op);
- }
- BLI_freelistN(&override->properties);
+ for (IDOverrideStaticProperty *op = override->properties.first; op; op = op->next) {
+ bke_override_property_clear(op);
+ }
+ BLI_freelistN(&override->properties);
- id_us_min(override->reference);
- /* override->storage should never be refcounted... */
+ id_us_min(override->reference);
+ /* override->storage should never be refcounted... */
}
/** Free given \a override. */
void BKE_override_static_free(struct IDOverrideStatic **override)
{
- BLI_assert(*override != NULL);
+ BLI_assert(*override != NULL);
- BKE_override_static_clear(*override);
- MEM_freeN(*override);
- *override = NULL;
+ BKE_override_static_clear(*override);
+ MEM_freeN(*override);
+ *override = NULL;
}
static ID *override_static_create_from(Main *bmain, ID *reference_id)
{
- ID *local_id;
+ ID *local_id;
- if (!BKE_id_copy(bmain, reference_id, (ID **)&local_id)) {
- return NULL;
- }
- id_us_min(local_id);
+ if (!BKE_id_copy(bmain, reference_id, (ID **)&local_id)) {
+ return NULL;
+ }
+ id_us_min(local_id);
- BKE_override_static_init(local_id, reference_id);
- local_id->override_static->flag |= STATICOVERRIDE_AUTO;
+ BKE_override_static_init(local_id, reference_id);
+ local_id->override_static->flag |= STATICOVERRIDE_AUTO;
- return local_id;
+ return local_id;
}
-
/** Create an overridden local copy of linked reference. */
ID *BKE_override_static_create_from_id(Main *bmain, ID *reference_id)
{
- BLI_assert(reference_id != NULL);
- BLI_assert(reference_id->lib != NULL);
+ BLI_assert(reference_id != NULL);
+ BLI_assert(reference_id->lib != NULL);
- ID *local_id = override_static_create_from(bmain, reference_id);
+ ID *local_id = override_static_create_from(bmain, reference_id);
- /* Remapping, we obviously only want to affect local data (and not our own reference pointer to overridden ID). */
- BKE_libblock_remap(bmain, reference_id, local_id, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_STATIC_OVERRIDE);
+ /* Remapping, we obviously only want to affect local data (and not our own reference pointer to overridden ID). */
+ BKE_libblock_remap(
+ bmain, reference_id, local_id, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_STATIC_OVERRIDE);
- return local_id;
+ return local_id;
}
/** Create overridden local copies of all tagged data-blocks in given Main.
@@ -199,237 +204,272 @@ ID *BKE_override_static_create_from_id(Main *bmain, ID *reference_id)
*/
bool BKE_override_static_create_from_tag(Main *bmain)
{
- ID *reference_id;
- bool ret = true;
-
- FOREACH_MAIN_ID_BEGIN(bmain, reference_id)
- {
- if ((reference_id->tag & LIB_TAG_DOIT) != 0 && reference_id->lib != NULL) {
- if ((reference_id->newid = override_static_create_from(bmain, reference_id)) == NULL) {
- ret = false;
- }
- }
- }
- FOREACH_MAIN_ID_END;
-
- FOREACH_MAIN_ID_BEGIN(bmain, reference_id)
- {
- if ((reference_id->tag & LIB_TAG_DOIT) != 0 && reference_id->lib != NULL && reference_id->newid != NULL) {
- ID *local_id = reference_id->newid;
- BKE_libblock_remap(bmain, reference_id, local_id,
- ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_STATIC_OVERRIDE);
- }
- }
- FOREACH_MAIN_ID_END;
-
- return ret;
+ ID *reference_id;
+ bool ret = true;
+
+ FOREACH_MAIN_ID_BEGIN(bmain, reference_id)
+ {
+ if ((reference_id->tag & LIB_TAG_DOIT) != 0 && reference_id->lib != NULL) {
+ if ((reference_id->newid = override_static_create_from(bmain, reference_id)) == NULL) {
+ ret = false;
+ }
+ }
+ }
+ FOREACH_MAIN_ID_END;
+
+ FOREACH_MAIN_ID_BEGIN(bmain, reference_id)
+ {
+ if ((reference_id->tag & LIB_TAG_DOIT) != 0 && reference_id->lib != NULL &&
+ reference_id->newid != NULL) {
+ ID *local_id = reference_id->newid;
+ BKE_libblock_remap(bmain,
+ reference_id,
+ local_id,
+ ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_STATIC_OVERRIDE);
+ }
+ }
+ FOREACH_MAIN_ID_END;
+
+ return ret;
}
/**
* Find override property from given RNA path, if it exists.
*/
-IDOverrideStaticProperty *BKE_override_static_property_find(IDOverrideStatic *override, const char *rna_path)
+IDOverrideStaticProperty *BKE_override_static_property_find(IDOverrideStatic *override,
+ const char *rna_path)
{
- /* XXX TODO we'll most likely want a runtime ghash to store that mapping at some point. */
- return BLI_findstring_ptr(&override->properties, rna_path, offsetof(IDOverrideStaticProperty, rna_path));
+ /* XXX TODO we'll most likely want a runtime ghash to store that mapping at some point. */
+ return BLI_findstring_ptr(
+ &override->properties, rna_path, offsetof(IDOverrideStaticProperty, rna_path));
}
/**
* Find override property from given RNA path, or create it if it does not exist.
*/
-IDOverrideStaticProperty *BKE_override_static_property_get(IDOverrideStatic *override, const char *rna_path, bool *r_created)
+IDOverrideStaticProperty *BKE_override_static_property_get(IDOverrideStatic *override,
+ const char *rna_path,
+ bool *r_created)
{
- /* XXX TODO we'll most likely want a runtime ghash to store that mapping at some point. */
- IDOverrideStaticProperty *op = BKE_override_static_property_find(override, rna_path);
-
- if (op == NULL) {
- op = MEM_callocN(sizeof(IDOverrideStaticProperty), __func__);
- op->rna_path = BLI_strdup(rna_path);
- BLI_addtail(&override->properties, op);
-
- if (r_created) {
- *r_created = true;
- }
- }
- else if (r_created) {
- *r_created = false;
- }
-
- return op;
+ /* XXX TODO we'll most likely want a runtime ghash to store that mapping at some point. */
+ IDOverrideStaticProperty *op = BKE_override_static_property_find(override, rna_path);
+
+ if (op == NULL) {
+ op = MEM_callocN(sizeof(IDOverrideStaticProperty), __func__);
+ op->rna_path = BLI_strdup(rna_path);
+ BLI_addtail(&override->properties, op);
+
+ if (r_created) {
+ *r_created = true;
+ }
+ }
+ else if (r_created) {
+ *r_created = false;
+ }
+
+ return op;
}
void bke_override_property_copy(IDOverrideStaticProperty *op_dst, IDOverrideStaticProperty *op_src)
{
- op_dst->rna_path = BLI_strdup(op_src->rna_path);
- BLI_duplicatelist(&op_dst->operations, &op_src->operations);
-
- for (IDOverrideStaticPropertyOperation *opop_dst = op_dst->operations.first, *opop_src = op_src->operations.first;
- opop_dst;
- opop_dst = opop_dst->next, opop_src = opop_src->next)
- {
- bke_override_property_operation_copy(opop_dst, opop_src);
- }
+ op_dst->rna_path = BLI_strdup(op_src->rna_path);
+ BLI_duplicatelist(&op_dst->operations, &op_src->operations);
+
+ for (IDOverrideStaticPropertyOperation *opop_dst = op_dst->operations.first,
+ *opop_src = op_src->operations.first;
+ opop_dst;
+ opop_dst = opop_dst->next, opop_src = opop_src->next) {
+ bke_override_property_operation_copy(opop_dst, opop_src);
+ }
}
void bke_override_property_clear(IDOverrideStaticProperty *op)
{
- BLI_assert(op->rna_path != NULL);
+ BLI_assert(op->rna_path != NULL);
- MEM_freeN(op->rna_path);
+ MEM_freeN(op->rna_path);
- for (IDOverrideStaticPropertyOperation *opop = op->operations.first; opop; opop = opop->next) {
- bke_override_property_operation_clear(opop);
- }
- BLI_freelistN(&op->operations);
+ for (IDOverrideStaticPropertyOperation *opop = op->operations.first; opop; opop = opop->next) {
+ bke_override_property_operation_clear(opop);
+ }
+ BLI_freelistN(&op->operations);
}
/**
* Remove and free given \a override_property from given ID \a override.
*/
-void BKE_override_static_property_delete(IDOverrideStatic *override, IDOverrideStaticProperty *override_property)
+void BKE_override_static_property_delete(IDOverrideStatic *override,
+ IDOverrideStaticProperty *override_property)
{
- bke_override_property_clear(override_property);
- BLI_freelinkN(&override->properties, override_property);
+ bke_override_property_clear(override_property);
+ BLI_freelinkN(&override->properties, override_property);
}
/**
* Find override property operation from given sub-item(s), if it exists.
*/
IDOverrideStaticPropertyOperation *BKE_override_static_property_operation_find(
- IDOverrideStaticProperty *override_property,
- const char *subitem_refname, const char *subitem_locname,
- const int subitem_refindex, const int subitem_locindex, const bool strict, bool *r_strict)
+ IDOverrideStaticProperty *override_property,
+ const char *subitem_refname,
+ const char *subitem_locname,
+ const int subitem_refindex,
+ const int subitem_locindex,
+ const bool strict,
+ bool *r_strict)
{
- IDOverrideStaticPropertyOperation *opop;
- const int subitem_defindex = -1;
-
- if (r_strict) {
- *r_strict = true;
- }
-
- if (subitem_locname != NULL) {
- opop = BLI_findstring_ptr(&override_property->operations, subitem_locname,
- offsetof(IDOverrideStaticPropertyOperation, subitem_local_name));
-
- if (opop == NULL) {
- return NULL;
- }
-
- if (subitem_refname == NULL || opop->subitem_reference_name == NULL) {
- return subitem_refname == opop->subitem_reference_name ? opop : NULL;
- }
- return (subitem_refname != NULL && opop->subitem_reference_name != NULL &&
- STREQ(subitem_refname, opop->subitem_reference_name)) ? opop : NULL;
- }
-
- if (subitem_refname != NULL) {
- opop = BLI_findstring_ptr(&override_property->operations, subitem_refname,
- offsetof(IDOverrideStaticPropertyOperation, subitem_reference_name));
-
- if (opop == NULL) {
- return NULL;
- }
-
- if (subitem_locname == NULL || opop->subitem_local_name == NULL) {
- return subitem_locname == opop->subitem_local_name ? opop : NULL;
- }
- return (subitem_locname != NULL && opop->subitem_local_name != NULL &&
- STREQ(subitem_locname, opop->subitem_local_name)) ? opop : NULL;
- }
-
- if ((opop = BLI_listbase_bytes_find(&override_property->operations, &subitem_locindex, sizeof(subitem_locindex),
- offsetof(IDOverrideStaticPropertyOperation, subitem_local_index))))
- {
- return ELEM(subitem_refindex, -1, opop->subitem_reference_index) ? opop : NULL;
- }
-
- if ((opop = BLI_listbase_bytes_find(&override_property->operations, &subitem_refindex, sizeof(subitem_refindex),
- offsetof(IDOverrideStaticPropertyOperation, subitem_reference_index))))
- {
- return ELEM(subitem_locindex, -1, opop->subitem_local_index) ? opop : NULL;
- }
-
- /* index == -1 means all indices, that is valid fallback in case we requested specific index. */
- if (!strict && (subitem_locindex != subitem_defindex) &&
- (opop = BLI_listbase_bytes_find(&override_property->operations, &subitem_defindex, sizeof(subitem_defindex),
- offsetof(IDOverrideStaticPropertyOperation, subitem_local_index))))
- {
- if (r_strict) {
- *r_strict = false;
- }
- return opop;
- }
-
- return NULL;
+ IDOverrideStaticPropertyOperation *opop;
+ const int subitem_defindex = -1;
+
+ if (r_strict) {
+ *r_strict = true;
+ }
+
+ if (subitem_locname != NULL) {
+ opop = BLI_findstring_ptr(&override_property->operations,
+ subitem_locname,
+ offsetof(IDOverrideStaticPropertyOperation, subitem_local_name));
+
+ if (opop == NULL) {
+ return NULL;
+ }
+
+ if (subitem_refname == NULL || opop->subitem_reference_name == NULL) {
+ return subitem_refname == opop->subitem_reference_name ? opop : NULL;
+ }
+ return (subitem_refname != NULL && opop->subitem_reference_name != NULL &&
+ STREQ(subitem_refname, opop->subitem_reference_name)) ?
+ opop :
+ NULL;
+ }
+
+ if (subitem_refname != NULL) {
+ opop = BLI_findstring_ptr(&override_property->operations,
+ subitem_refname,
+ offsetof(IDOverrideStaticPropertyOperation, subitem_reference_name));
+
+ if (opop == NULL) {
+ return NULL;
+ }
+
+ if (subitem_locname == NULL || opop->subitem_local_name == NULL) {
+ return subitem_locname == opop->subitem_local_name ? opop : NULL;
+ }
+ return (subitem_locname != NULL && opop->subitem_local_name != NULL &&
+ STREQ(subitem_locname, opop->subitem_local_name)) ?
+ opop :
+ NULL;
+ }
+
+ if ((opop = BLI_listbase_bytes_find(
+ &override_property->operations,
+ &subitem_locindex,
+ sizeof(subitem_locindex),
+ offsetof(IDOverrideStaticPropertyOperation, subitem_local_index)))) {
+ return ELEM(subitem_refindex, -1, opop->subitem_reference_index) ? opop : NULL;
+ }
+
+ if ((opop = BLI_listbase_bytes_find(
+ &override_property->operations,
+ &subitem_refindex,
+ sizeof(subitem_refindex),
+ offsetof(IDOverrideStaticPropertyOperation, subitem_reference_index)))) {
+ return ELEM(subitem_locindex, -1, opop->subitem_local_index) ? opop : NULL;
+ }
+
+ /* index == -1 means all indices, that is valid fallback in case we requested specific index. */
+ if (!strict && (subitem_locindex != subitem_defindex) &&
+ (opop = BLI_listbase_bytes_find(
+ &override_property->operations,
+ &subitem_defindex,
+ sizeof(subitem_defindex),
+ offsetof(IDOverrideStaticPropertyOperation, subitem_local_index)))) {
+ if (r_strict) {
+ *r_strict = false;
+ }
+ return opop;
+ }
+
+ return NULL;
}
/**
* Find override property operation from given sub-item(s), or create it if it does not exist.
*/
IDOverrideStaticPropertyOperation *BKE_override_static_property_operation_get(
- IDOverrideStaticProperty *override_property, const short operation,
- const char *subitem_refname, const char *subitem_locname,
- const int subitem_refindex, const int subitem_locindex,
- const bool strict, bool *r_strict, bool *r_created)
+ IDOverrideStaticProperty *override_property,
+ const short operation,
+ const char *subitem_refname,
+ const char *subitem_locname,
+ const int subitem_refindex,
+ const int subitem_locindex,
+ const bool strict,
+ bool *r_strict,
+ bool *r_created)
{
- IDOverrideStaticPropertyOperation *opop = BKE_override_static_property_operation_find(override_property,
- subitem_refname, subitem_locname,
- subitem_refindex, subitem_locindex,
- strict, r_strict);
-
- if (opop == NULL) {
- opop = MEM_callocN(sizeof(IDOverrideStaticPropertyOperation), __func__);
- opop->operation = operation;
- if (subitem_locname) {
- opop->subitem_local_name = BLI_strdup(subitem_locname);
- }
- if (subitem_refname) {
- opop->subitem_reference_name = BLI_strdup(subitem_refname);
- }
- opop->subitem_local_index = subitem_locindex;
- opop->subitem_reference_index = subitem_refindex;
-
- BLI_addtail(&override_property->operations, opop);
-
- if (r_created) {
- *r_created = true;
- }
- }
- else if (r_created) {
- *r_created = false;
- }
-
- return opop;
+ IDOverrideStaticPropertyOperation *opop = BKE_override_static_property_operation_find(
+ override_property,
+ subitem_refname,
+ subitem_locname,
+ subitem_refindex,
+ subitem_locindex,
+ strict,
+ r_strict);
+
+ if (opop == NULL) {
+ opop = MEM_callocN(sizeof(IDOverrideStaticPropertyOperation), __func__);
+ opop->operation = operation;
+ if (subitem_locname) {
+ opop->subitem_local_name = BLI_strdup(subitem_locname);
+ }
+ if (subitem_refname) {
+ opop->subitem_reference_name = BLI_strdup(subitem_refname);
+ }
+ opop->subitem_local_index = subitem_locindex;
+ opop->subitem_reference_index = subitem_refindex;
+
+ BLI_addtail(&override_property->operations, opop);
+
+ if (r_created) {
+ *r_created = true;
+ }
+ }
+ else if (r_created) {
+ *r_created = false;
+ }
+
+ return opop;
}
-void bke_override_property_operation_copy(IDOverrideStaticPropertyOperation *opop_dst, IDOverrideStaticPropertyOperation *opop_src)
+void bke_override_property_operation_copy(IDOverrideStaticPropertyOperation *opop_dst,
+ IDOverrideStaticPropertyOperation *opop_src)
{
- if (opop_src->subitem_reference_name) {
- opop_dst->subitem_reference_name = BLI_strdup(opop_src->subitem_reference_name);
- }
- if (opop_src->subitem_local_name) {
- opop_dst->subitem_local_name = BLI_strdup(opop_src->subitem_local_name);
- }
+ if (opop_src->subitem_reference_name) {
+ opop_dst->subitem_reference_name = BLI_strdup(opop_src->subitem_reference_name);
+ }
+ if (opop_src->subitem_local_name) {
+ opop_dst->subitem_local_name = BLI_strdup(opop_src->subitem_local_name);
+ }
}
void bke_override_property_operation_clear(IDOverrideStaticPropertyOperation *opop)
{
- if (opop->subitem_reference_name) {
- MEM_freeN(opop->subitem_reference_name);
- }
- if (opop->subitem_local_name) {
- MEM_freeN(opop->subitem_local_name);
- }
+ if (opop->subitem_reference_name) {
+ MEM_freeN(opop->subitem_reference_name);
+ }
+ if (opop->subitem_local_name) {
+ MEM_freeN(opop->subitem_local_name);
+ }
}
/**
* Remove and free given \a override_property_operation from given ID \a override_property.
*/
void BKE_override_static_property_operation_delete(
- IDOverrideStaticProperty *override_property, IDOverrideStaticPropertyOperation *override_property_operation)
+ IDOverrideStaticProperty *override_property,
+ IDOverrideStaticPropertyOperation *override_property_operation)
{
- bke_override_property_operation_clear(override_property_operation);
- BLI_freelinkN(&override_property->operations, override_property_operation);
+ bke_override_property_operation_clear(override_property_operation);
+ BLI_freelinkN(&override_property->operations, override_property_operation);
}
/**
@@ -444,33 +484,36 @@ void BKE_override_static_property_operation_delete(
* \return true if status is OK, false otherwise. */
bool BKE_override_static_status_check_local(Main *bmain, ID *local)
{
- BLI_assert(local->override_static != NULL);
+ BLI_assert(local->override_static != NULL);
- ID *reference = local->override_static->reference;
+ ID *reference = local->override_static->reference;
- if (reference == NULL) {
- /* This is an override template, local status is always OK! */
- return true;
- }
+ if (reference == NULL) {
+ /* This is an override template, local status is always OK! */
+ return true;
+ }
- BLI_assert(GS(local->name) == GS(reference->name));
+ BLI_assert(GS(local->name) == GS(reference->name));
- /* Note that reference is assumed always valid, caller has to ensure that itself. */
+ /* Note that reference is assumed always valid, caller has to ensure that itself. */
- PointerRNA rnaptr_local, rnaptr_reference;
- RNA_id_pointer_create(local, &rnaptr_local);
- RNA_id_pointer_create(reference, &rnaptr_reference);
+ PointerRNA rnaptr_local, rnaptr_reference;
+ RNA_id_pointer_create(local, &rnaptr_local);
+ RNA_id_pointer_create(reference, &rnaptr_reference);
- if (!RNA_struct_override_matches(
- bmain,
- &rnaptr_local, &rnaptr_reference, NULL, local->override_static,
- RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE | RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN, NULL))
- {
- local->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK;
- return false;
- }
+ if (!RNA_struct_override_matches(bmain,
+ &rnaptr_local,
+ &rnaptr_reference,
+ NULL,
+ local->override_static,
+ RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE |
+ RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN,
+ NULL)) {
+ local->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK;
+ return false;
+ }
- return true;
+ return true;
}
/**
@@ -484,41 +527,43 @@ bool BKE_override_static_status_check_local(Main *bmain, ID *local)
* \return true if status is OK, false otherwise. */
bool BKE_override_static_status_check_reference(Main *bmain, ID *local)
{
- BLI_assert(local->override_static != NULL);
-
- ID *reference = local->override_static->reference;
-
- if (reference == NULL) {
- /* This is an override template, reference is virtual, so its status is always OK! */
- return true;
- }
-
- BLI_assert(GS(local->name) == GS(reference->name));
-
- if (reference->override_static && (reference->tag & LIB_TAG_OVERRIDESTATIC_REFOK) == 0) {
- if (!BKE_override_static_status_check_reference(bmain, reference)) {
- /* If reference is also override of another data-block, and its status is not OK,
- * then this override is not OK either.
- * Note that this should only happen when reloading libraries... */
- local->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK;
- return false;
- }
- }
-
- PointerRNA rnaptr_local, rnaptr_reference;
- RNA_id_pointer_create(local, &rnaptr_local);
- RNA_id_pointer_create(reference, &rnaptr_reference);
-
- if (!RNA_struct_override_matches(
- bmain,
- &rnaptr_local, &rnaptr_reference, NULL, local->override_static,
- RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN, NULL))
- {
- local->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK;
- return false;
- }
-
- return true;
+ BLI_assert(local->override_static != NULL);
+
+ ID *reference = local->override_static->reference;
+
+ if (reference == NULL) {
+ /* This is an override template, reference is virtual, so its status is always OK! */
+ return true;
+ }
+
+ BLI_assert(GS(local->name) == GS(reference->name));
+
+ if (reference->override_static && (reference->tag & LIB_TAG_OVERRIDESTATIC_REFOK) == 0) {
+ if (!BKE_override_static_status_check_reference(bmain, reference)) {
+ /* If reference is also override of another data-block, and its status is not OK,
+ * then this override is not OK either.
+ * Note that this should only happen when reloading libraries... */
+ local->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK;
+ return false;
+ }
+ }
+
+ PointerRNA rnaptr_local, rnaptr_reference;
+ RNA_id_pointer_create(local, &rnaptr_local);
+ RNA_id_pointer_create(reference, &rnaptr_reference);
+
+ if (!RNA_struct_override_matches(bmain,
+ &rnaptr_local,
+ &rnaptr_reference,
+ NULL,
+ local->override_static,
+ RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN,
+ NULL)) {
+ local->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK;
+ return false;
+ }
+
+ return true;
}
/**
@@ -535,132 +580,138 @@ bool BKE_override_static_status_check_reference(Main *bmain, ID *local)
* \return true if new overriding op was created, or some local data was reset. */
bool BKE_override_static_operations_create(Main *bmain, ID *local, const bool force_auto)
{
- BLI_assert(local->override_static != NULL);
- const bool is_template = (local->override_static->reference == NULL);
- bool ret = false;
-
- if (!is_template && (force_auto || local->override_static->flag & STATICOVERRIDE_AUTO)) {
- PointerRNA rnaptr_local, rnaptr_reference;
- RNA_id_pointer_create(local, &rnaptr_local);
- RNA_id_pointer_create(local->override_static->reference, &rnaptr_reference);
-
- eRNAOverrideMatchResult report_flags = 0;
- RNA_struct_override_matches(
- bmain,
- &rnaptr_local, &rnaptr_reference, NULL, local->override_static,
- RNA_OVERRIDE_COMPARE_CREATE | RNA_OVERRIDE_COMPARE_RESTORE, &report_flags);
- if (report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) {
- ret = true;
- }
+ BLI_assert(local->override_static != NULL);
+ const bool is_template = (local->override_static->reference == NULL);
+ bool ret = false;
+
+ if (!is_template && (force_auto || local->override_static->flag & STATICOVERRIDE_AUTO)) {
+ PointerRNA rnaptr_local, rnaptr_reference;
+ RNA_id_pointer_create(local, &rnaptr_local);
+ RNA_id_pointer_create(local->override_static->reference, &rnaptr_reference);
+
+ eRNAOverrideMatchResult report_flags = 0;
+ RNA_struct_override_matches(bmain,
+ &rnaptr_local,
+ &rnaptr_reference,
+ NULL,
+ local->override_static,
+ RNA_OVERRIDE_COMPARE_CREATE | RNA_OVERRIDE_COMPARE_RESTORE,
+ &report_flags);
+ if (report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) {
+ ret = true;
+ }
#ifndef NDEBUG
- if (report_flags & RNA_OVERRIDE_MATCH_RESULT_RESTORED) {
- printf("We did restore some properties of %s from its reference.\n", local->name);
- }
- if (ret) {
- printf("We did generate static override rules for %s\n", local->name);
- }
- else {
- printf("No new static override rules for %s\n", local->name);
- }
+ if (report_flags & RNA_OVERRIDE_MATCH_RESULT_RESTORED) {
+ printf("We did restore some properties of %s from its reference.\n", local->name);
+ }
+ if (ret) {
+ printf("We did generate static override rules for %s\n", local->name);
+ }
+ else {
+ printf("No new static override rules for %s\n", local->name);
+ }
#endif
- }
- return ret;
+ }
+ return ret;
}
/** Check all overrides from given \a bmain and create/update overriding operations as needed. */
void BKE_main_override_static_operations_create(Main *bmain, const bool force_auto)
{
- ID *id;
-
- FOREACH_MAIN_ID_BEGIN(bmain, id)
- {
- if (force_auto ||
- (ID_IS_STATIC_OVERRIDE_AUTO(id) && (id->tag & LIB_TAG_OVERRIDESTATIC_AUTOREFRESH)))
- {
- BKE_override_static_operations_create(bmain, id, force_auto);
- id->tag &= ~LIB_TAG_OVERRIDESTATIC_AUTOREFRESH;
- }
- }
- FOREACH_MAIN_ID_END;
+ ID *id;
+
+ FOREACH_MAIN_ID_BEGIN(bmain, id)
+ {
+ if (force_auto ||
+ (ID_IS_STATIC_OVERRIDE_AUTO(id) && (id->tag & LIB_TAG_OVERRIDESTATIC_AUTOREFRESH))) {
+ BKE_override_static_operations_create(bmain, id, force_auto);
+ id->tag &= ~LIB_TAG_OVERRIDESTATIC_AUTOREFRESH;
+ }
+ }
+ FOREACH_MAIN_ID_END;
}
/** Update given override from its reference (re-applying overridden properties). */
void BKE_override_static_update(Main *bmain, ID *local)
{
- if (local->override_static == NULL || local->override_static->reference == NULL) {
- return;
- }
-
- /* Recursively do 'ancestors' overrides first, if any. */
- if (local->override_static->reference->override_static && (local->override_static->reference->tag & LIB_TAG_OVERRIDESTATIC_REFOK) == 0) {
- BKE_override_static_update(bmain, local->override_static->reference);
- }
-
- /* We want to avoid having to remap here, however creating up-to-date override is much simpler if based
- * on reference than on current override.
- * So we work on temp copy of reference, and 'swap' its content with local. */
-
- /* XXX We need a way to get off-Main copies of IDs (similar to localized mats/texts/ etc.)!
- * However, this is whole bunch of code work in itself, so for now plain stupid ID copy will do,
- * as innefficient as it is. :/
- * Actually, maybe not! Since we are swapping with original ID's local content, we want to keep
- * usercount in correct state when freeing tmp_id (and that usercounts of IDs used by 'new' local data
- * also remain correct). */
- /* This would imply change in handling of usercout all over RNA (and possibly all over Blender code).
- * Not impossible to do, but would rather see first if extra useless usual user handling is actually
- * a (performances) issue here. */
-
- ID *tmp_id;
- BKE_id_copy(bmain, local->override_static->reference, &tmp_id);
-
- if (tmp_id == NULL) {
- return;
- }
-
- PointerRNA rnaptr_src, rnaptr_dst, rnaptr_storage_stack, *rnaptr_storage = NULL;
- RNA_id_pointer_create(local, &rnaptr_src);
- RNA_id_pointer_create(tmp_id, &rnaptr_dst);
- if (local->override_static->storage) {
- rnaptr_storage = &rnaptr_storage_stack;
- RNA_id_pointer_create(local->override_static->storage, rnaptr_storage);
- }
-
- RNA_struct_override_apply(bmain, &rnaptr_dst, &rnaptr_src, rnaptr_storage, local->override_static);
-
- /* This also transfers all pointers (memory) owned by local to tmp_id, and vice-versa. So when we'll free tmp_id,
- * we'll actually free old, outdated data from local. */
- BKE_id_swap(bmain, local, tmp_id);
-
- /* Again, horribly innefficient in our case, we need something off-Main (aka moar generic nolib copy/free stuff)! */
- /* XXX And crashing in complex cases (e.g. because depsgraph uses same data...). */
- BKE_id_free_ex(bmain, tmp_id, LIB_ID_FREE_NO_UI_USER, true);
-
- if (local->override_static->storage) {
- /* We know this datablock is not used anywhere besides local->override->storage. */
- /* XXX For until we get fully shadow copies, we still need to ensure storage releases
- * its usage of any ID pointers it may have. */
- BKE_id_free_ex(bmain, local->override_static->storage, LIB_ID_FREE_NO_UI_USER, true);
- local->override_static->storage = NULL;
- }
-
- local->tag |= LIB_TAG_OVERRIDESTATIC_REFOK;
-
- /* Full rebuild of Depsgraph! */
- DEG_on_visible_update(bmain, true); /* XXX Is this actual valid replacement for old DAG_relations_tag_update(bmain) ? */
+ if (local->override_static == NULL || local->override_static->reference == NULL) {
+ return;
+ }
+
+ /* Recursively do 'ancestors' overrides first, if any. */
+ if (local->override_static->reference->override_static &&
+ (local->override_static->reference->tag & LIB_TAG_OVERRIDESTATIC_REFOK) == 0) {
+ BKE_override_static_update(bmain, local->override_static->reference);
+ }
+
+ /* We want to avoid having to remap here, however creating up-to-date override is much simpler if based
+ * on reference than on current override.
+ * So we work on temp copy of reference, and 'swap' its content with local. */
+
+ /* XXX We need a way to get off-Main copies of IDs (similar to localized mats/texts/ etc.)!
+ * However, this is whole bunch of code work in itself, so for now plain stupid ID copy will do,
+ * as innefficient as it is. :/
+ * Actually, maybe not! Since we are swapping with original ID's local content, we want to keep
+ * usercount in correct state when freeing tmp_id (and that usercounts of IDs used by 'new' local data
+ * also remain correct). */
+ /* This would imply change in handling of usercout all over RNA (and possibly all over Blender code).
+ * Not impossible to do, but would rather see first if extra useless usual user handling is actually
+ * a (performances) issue here. */
+
+ ID *tmp_id;
+ BKE_id_copy(bmain, local->override_static->reference, &tmp_id);
+
+ if (tmp_id == NULL) {
+ return;
+ }
+
+ PointerRNA rnaptr_src, rnaptr_dst, rnaptr_storage_stack, *rnaptr_storage = NULL;
+ RNA_id_pointer_create(local, &rnaptr_src);
+ RNA_id_pointer_create(tmp_id, &rnaptr_dst);
+ if (local->override_static->storage) {
+ rnaptr_storage = &rnaptr_storage_stack;
+ RNA_id_pointer_create(local->override_static->storage, rnaptr_storage);
+ }
+
+ RNA_struct_override_apply(
+ bmain, &rnaptr_dst, &rnaptr_src, rnaptr_storage, local->override_static);
+
+ /* This also transfers all pointers (memory) owned by local to tmp_id, and vice-versa. So when we'll free tmp_id,
+ * we'll actually free old, outdated data from local. */
+ BKE_id_swap(bmain, local, tmp_id);
+
+ /* Again, horribly innefficient in our case, we need something off-Main (aka moar generic nolib copy/free stuff)! */
+ /* XXX And crashing in complex cases (e.g. because depsgraph uses same data...). */
+ BKE_id_free_ex(bmain, tmp_id, LIB_ID_FREE_NO_UI_USER, true);
+
+ if (local->override_static->storage) {
+ /* We know this datablock is not used anywhere besides local->override->storage. */
+ /* XXX For until we get fully shadow copies, we still need to ensure storage releases
+ * its usage of any ID pointers it may have. */
+ BKE_id_free_ex(bmain, local->override_static->storage, LIB_ID_FREE_NO_UI_USER, true);
+ local->override_static->storage = NULL;
+ }
+
+ local->tag |= LIB_TAG_OVERRIDESTATIC_REFOK;
+
+ /* Full rebuild of Depsgraph! */
+ DEG_on_visible_update(
+ bmain,
+ true); /* XXX Is this actual valid replacement for old DAG_relations_tag_update(bmain) ? */
}
/** Update all overrides from given \a bmain. */
void BKE_main_override_static_update(Main *bmain)
{
- ID *id;
-
- FOREACH_MAIN_ID_BEGIN(bmain, id)
- {
- if (id->override_static != NULL && id->lib == NULL) {
- BKE_override_static_update(bmain, id);
- }
- }
- FOREACH_MAIN_ID_END;
+ ID *id;
+
+ FOREACH_MAIN_ID_BEGIN(bmain, id)
+ {
+ if (id->override_static != NULL && id->lib == NULL) {
+ BKE_override_static_update(bmain, id);
+ }
+ }
+ FOREACH_MAIN_ID_END;
}
/***********************************************************************************************************************
@@ -680,82 +731,84 @@ void BKE_main_override_static_update(Main *bmain)
/** Initialize an override storage. */
OverrideStaticStorage *BKE_override_static_operations_store_initialize(void)
{
- return BKE_main_new();
+ return BKE_main_new();
}
/**
* Generate suitable 'write' data (this only affects differential override operations).
*
* Note that \a local ID is no more modified by this call, all extra data are stored in its temp \a storage_id copy. */
-ID *BKE_override_static_operations_store_start(Main *bmain, OverrideStaticStorage *override_storage, ID *local)
+ID *BKE_override_static_operations_store_start(Main *bmain,
+ OverrideStaticStorage *override_storage,
+ ID *local)
{
- BLI_assert(local->override_static != NULL);
- BLI_assert(override_storage != NULL);
- const bool is_template = (local->override_static->reference == NULL);
+ BLI_assert(local->override_static != NULL);
+ BLI_assert(override_storage != NULL);
+ const bool is_template = (local->override_static->reference == NULL);
- if (is_template) {
- /* This is actually purely local data with an override template, nothing to do here! */
- return NULL;
- }
+ if (is_template) {
+ /* This is actually purely local data with an override template, nothing to do here! */
+ return NULL;
+ }
- /* Forcefully ensure we know about all needed override operations. */
- BKE_override_static_operations_create(bmain, local, false);
+ /* Forcefully ensure we know about all needed override operations. */
+ BKE_override_static_operations_create(bmain, local, false);
- ID *storage_id;
+ ID *storage_id;
#ifdef DEBUG_OVERRIDE_TIMEIT
- TIMEIT_START_AVERAGED(BKE_override_operations_store_start);
+ TIMEIT_START_AVERAGED(BKE_override_operations_store_start);
#endif
- /* XXX TODO We may also want a specialized handling of things here too, to avoid copying heavy never-overridable
- * data (like Mesh geometry etc.)? And also maybe avoid lib refcounting completely (shallow copy...). */
- /* This would imply change in handling of usercout all over RNA (and possibly all over Blender code).
- * Not impossible to do, but would rather see first is extra useless usual user handling is actually
- * a (performances) issue here, before doing it. */
- BKE_id_copy((Main *)override_storage, local, &storage_id);
-
- if (storage_id != NULL) {
- PointerRNA rnaptr_reference, rnaptr_final, rnaptr_storage;
- RNA_id_pointer_create(local->override_static->reference, &rnaptr_reference);
- RNA_id_pointer_create(local, &rnaptr_final);
- RNA_id_pointer_create(storage_id, &rnaptr_storage);
-
- if (!RNA_struct_override_store(
- bmain, &rnaptr_final, &rnaptr_reference, &rnaptr_storage, local->override_static))
- {
- BKE_id_free_ex(override_storage, storage_id, LIB_ID_FREE_NO_UI_USER, true);
- storage_id = NULL;
- }
- }
-
- local->override_static->storage = storage_id;
+ /* XXX TODO We may also want a specialized handling of things here too, to avoid copying heavy never-overridable
+ * data (like Mesh geometry etc.)? And also maybe avoid lib refcounting completely (shallow copy...). */
+ /* This would imply change in handling of usercout all over RNA (and possibly all over Blender code).
+ * Not impossible to do, but would rather see first is extra useless usual user handling is actually
+ * a (performances) issue here, before doing it. */
+ BKE_id_copy((Main *)override_storage, local, &storage_id);
+
+ if (storage_id != NULL) {
+ PointerRNA rnaptr_reference, rnaptr_final, rnaptr_storage;
+ RNA_id_pointer_create(local->override_static->reference, &rnaptr_reference);
+ RNA_id_pointer_create(local, &rnaptr_final);
+ RNA_id_pointer_create(storage_id, &rnaptr_storage);
+
+ if (!RNA_struct_override_store(
+ bmain, &rnaptr_final, &rnaptr_reference, &rnaptr_storage, local->override_static)) {
+ BKE_id_free_ex(override_storage, storage_id, LIB_ID_FREE_NO_UI_USER, true);
+ storage_id = NULL;
+ }
+ }
+
+ local->override_static->storage = storage_id;
#ifdef DEBUG_OVERRIDE_TIMEIT
- TIMEIT_END_AVERAGED(BKE_override_operations_store_start);
+ TIMEIT_END_AVERAGED(BKE_override_operations_store_start);
#endif
- return storage_id;
+ return storage_id;
}
/** Restore given ID modified by \a BKE_override_operations_store_start, to its original state. */
-void BKE_override_static_operations_store_end(OverrideStaticStorage *UNUSED(override_storage), ID *local)
+void BKE_override_static_operations_store_end(OverrideStaticStorage *UNUSED(override_storage),
+ ID *local)
{
- BLI_assert(local->override_static != NULL);
+ BLI_assert(local->override_static != NULL);
- /* Nothing else to do here really, we need to keep all temp override storage data-blocks in memory until
- * whole file is written anyway (otherwise we'd get mem pointers overlap...). */
- local->override_static->storage = NULL;
+ /* Nothing else to do here really, we need to keep all temp override storage data-blocks in memory until
+ * whole file is written anyway (otherwise we'd get mem pointers overlap...). */
+ local->override_static->storage = NULL;
}
void BKE_override_static_operations_store_finalize(OverrideStaticStorage *override_storage)
{
- /* We cannot just call BKE_main_free(override_storage), not until we have option to make 'ghost' copies of IDs
- * without increasing usercount of used data-blocks... */
- ID *id;
+ /* We cannot just call BKE_main_free(override_storage), not until we have option to make 'ghost' copies of IDs
+ * without increasing usercount of used data-blocks... */
+ ID *id;
- FOREACH_MAIN_ID_BEGIN(override_storage, id)
- {
- BKE_id_free_ex(override_storage, id, LIB_ID_FREE_NO_UI_USER, true);
- }
- FOREACH_MAIN_ID_END;
+ FOREACH_MAIN_ID_BEGIN(override_storage, id)
+ {
+ BKE_id_free_ex(override_storage, id, LIB_ID_FREE_NO_UI_USER, true);
+ }
+ FOREACH_MAIN_ID_END;
- BKE_main_free(override_storage);
+ BKE_main_free(override_storage);
}
diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c
index b7ae8eea18d..7152c9786fb 100644
--- a/source/blender/blenkernel/intern/library_query.c
+++ b/source/blender/blenkernel/intern/library_query.c
@@ -79,971 +79,988 @@
#include "BKE_tracking.h"
#include "BKE_workspace.h"
-
#define FOREACH_FINALIZE _finalize
#define FOREACH_FINALIZE_VOID \
- if (0) { goto FOREACH_FINALIZE; } \
- FOREACH_FINALIZE: ((void)0)
+ if (0) { \
+ goto FOREACH_FINALIZE; \
+ } \
+ FOREACH_FINALIZE: \
+ ((void)0)
#define FOREACH_CALLBACK_INVOKE_ID_PP(_data, id_pp, _cb_flag) \
- CHECK_TYPE(id_pp, ID **); \
- if (!((_data)->status & IDWALK_STOP)) { \
- const int _flag = (_data)->flag; \
- ID *old_id = *(id_pp); \
- const int callback_return = (_data)->callback((_data)->user_data, \
- (_data)->self_id, \
- id_pp, \
- (_cb_flag | (_data)->cb_flag) & ~(_data)->cb_flag_clear); \
- if (_flag & IDWALK_READONLY) { \
- BLI_assert(*(id_pp) == old_id); \
- } \
- if (old_id && (_flag & IDWALK_RECURSE)) { \
- if (BLI_gset_add((_data)->ids_handled, old_id)) { \
- if (!(callback_return & IDWALK_RET_STOP_RECURSION)) { \
- BLI_LINKSTACK_PUSH((_data)->ids_todo, old_id); \
- } \
- } \
- } \
- if (callback_return & IDWALK_RET_STOP_ITER) { \
- (_data)->status |= IDWALK_STOP; \
- goto FOREACH_FINALIZE; \
- } \
- } \
- else { \
- goto FOREACH_FINALIZE; \
- } ((void)0)
+ CHECK_TYPE(id_pp, ID **); \
+ if (!((_data)->status & IDWALK_STOP)) { \
+ const int _flag = (_data)->flag; \
+ ID *old_id = *(id_pp); \
+ const int callback_return = (_data)->callback((_data)->user_data, \
+ (_data)->self_id, \
+ id_pp, \
+ (_cb_flag | (_data)->cb_flag) & \
+ ~(_data)->cb_flag_clear); \
+ if (_flag & IDWALK_READONLY) { \
+ BLI_assert(*(id_pp) == old_id); \
+ } \
+ if (old_id && (_flag & IDWALK_RECURSE)) { \
+ if (BLI_gset_add((_data)->ids_handled, old_id)) { \
+ if (!(callback_return & IDWALK_RET_STOP_RECURSION)) { \
+ BLI_LINKSTACK_PUSH((_data)->ids_todo, old_id); \
+ } \
+ } \
+ } \
+ if (callback_return & IDWALK_RET_STOP_ITER) { \
+ (_data)->status |= IDWALK_STOP; \
+ goto FOREACH_FINALIZE; \
+ } \
+ } \
+ else { \
+ goto FOREACH_FINALIZE; \
+ } \
+ ((void)0)
#define FOREACH_CALLBACK_INVOKE_ID(_data, id, cb_flag) \
- { \
- CHECK_TYPE_ANY(id, ID *, void *); \
- FOREACH_CALLBACK_INVOKE_ID_PP(_data, (ID **)&(id), cb_flag); \
- } ((void)0)
+ { \
+ CHECK_TYPE_ANY(id, ID *, void *); \
+ FOREACH_CALLBACK_INVOKE_ID_PP(_data, (ID **)&(id), cb_flag); \
+ } \
+ ((void)0)
#define FOREACH_CALLBACK_INVOKE(_data, id_super, cb_flag) \
- { \
- CHECK_TYPE(&((id_super)->id), ID *); \
- FOREACH_CALLBACK_INVOKE_ID_PP(_data, (ID **)&(id_super), cb_flag); \
- } ((void)0)
+ { \
+ CHECK_TYPE(&((id_super)->id), ID *); \
+ FOREACH_CALLBACK_INVOKE_ID_PP(_data, (ID **)&(id_super), cb_flag); \
+ } \
+ ((void)0)
/* status */
enum {
- IDWALK_STOP = 1 << 0,
+ IDWALK_STOP = 1 << 0,
};
typedef struct LibraryForeachIDData {
- ID *self_id;
- int flag;
- int cb_flag;
- int cb_flag_clear;
- LibraryIDLinkCallback callback;
- void *user_data;
- int status;
-
- /* To handle recursion. */
- GSet *ids_handled; /* All IDs that are either already done, or still in ids_todo stack. */
- BLI_LINKSTACK_DECLARE(ids_todo, ID *);
+ ID *self_id;
+ int flag;
+ int cb_flag;
+ int cb_flag_clear;
+ LibraryIDLinkCallback callback;
+ void *user_data;
+ int status;
+
+ /* To handle recursion. */
+ GSet *ids_handled; /* All IDs that are either already done, or still in ids_todo stack. */
+ BLI_LINKSTACK_DECLARE(ids_todo, ID *);
} LibraryForeachIDData;
-static void library_foreach_ID_link(
- Main *bmain, ID *id,
- LibraryIDLinkCallback callback, void *user_data, int flag,
- LibraryForeachIDData *inherit_data);
+static void library_foreach_ID_link(Main *bmain,
+ ID *id,
+ LibraryIDLinkCallback callback,
+ void *user_data,
+ int flag,
+ LibraryForeachIDData *inherit_data);
-static void library_foreach_idproperty_ID_link(LibraryForeachIDData *data, IDProperty *prop, int flag)
+static void library_foreach_idproperty_ID_link(LibraryForeachIDData *data,
+ IDProperty *prop,
+ int flag)
{
- if (!prop)
- return;
-
- switch (prop->type) {
- case IDP_GROUP:
- {
- for (IDProperty *loop = prop->data.group.first; loop; loop = loop->next) {
- library_foreach_idproperty_ID_link(data, loop, flag);
- }
- break;
- }
- case IDP_IDPARRAY:
- {
- IDProperty *loop = IDP_Array(prop);
- for (int i = 0; i < prop->len; i++) {
- library_foreach_idproperty_ID_link(data, &loop[i], flag);
- }
- break;
- }
- case IDP_ID:
- FOREACH_CALLBACK_INVOKE_ID(data, prop->data.pointer, flag);
- break;
- default:
- break; /* Nothing to do here with other types of IDProperties... */
- }
-
- FOREACH_FINALIZE_VOID;
+ if (!prop)
+ return;
+
+ switch (prop->type) {
+ case IDP_GROUP: {
+ for (IDProperty *loop = prop->data.group.first; loop; loop = loop->next) {
+ library_foreach_idproperty_ID_link(data, loop, flag);
+ }
+ break;
+ }
+ case IDP_IDPARRAY: {
+ IDProperty *loop = IDP_Array(prop);
+ for (int i = 0; i < prop->len; i++) {
+ library_foreach_idproperty_ID_link(data, &loop[i], flag);
+ }
+ break;
+ }
+ case IDP_ID:
+ FOREACH_CALLBACK_INVOKE_ID(data, prop->data.pointer, flag);
+ break;
+ default:
+ break; /* Nothing to do here with other types of IDProperties... */
+ }
+
+ FOREACH_FINALIZE_VOID;
}
-static void library_foreach_rigidbodyworldSceneLooper(
- struct RigidBodyWorld *UNUSED(rbw), ID **id_pointer, void *user_data, int cb_flag)
+static void library_foreach_rigidbodyworldSceneLooper(struct RigidBodyWorld *UNUSED(rbw),
+ ID **id_pointer,
+ void *user_data,
+ int cb_flag)
{
- LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
+ LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
- FOREACH_FINALIZE_VOID;
+ FOREACH_FINALIZE_VOID;
}
-static void library_foreach_modifiersForeachIDLink(
- void *user_data, Object *UNUSED(object), ID **id_pointer, int cb_flag)
+static void library_foreach_modifiersForeachIDLink(void *user_data,
+ Object *UNUSED(object),
+ ID **id_pointer,
+ int cb_flag)
{
- LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
+ LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
- FOREACH_FINALIZE_VOID;
+ FOREACH_FINALIZE_VOID;
}
-static void library_foreach_gpencil_modifiersForeachIDLink(
- void *user_data, Object *UNUSED(object), ID **id_pointer, int cb_flag)
+static void library_foreach_gpencil_modifiersForeachIDLink(void *user_data,
+ Object *UNUSED(object),
+ ID **id_pointer,
+ int cb_flag)
{
- LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
+ LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
- FOREACH_FINALIZE_VOID;
+ FOREACH_FINALIZE_VOID;
}
-static void library_foreach_shaderfxForeachIDLink(
- void *user_data, Object *UNUSED(object), ID **id_pointer, int cb_flag)
+static void library_foreach_shaderfxForeachIDLink(void *user_data,
+ Object *UNUSED(object),
+ ID **id_pointer,
+ int cb_flag)
{
- LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
+ LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
- FOREACH_FINALIZE_VOID;
+ FOREACH_FINALIZE_VOID;
}
-static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con), ID **id_pointer,
- bool is_reference, void *user_data)
+static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con),
+ ID **id_pointer,
+ bool is_reference,
+ void *user_data)
{
- LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- const int cb_flag = is_reference ? IDWALK_CB_USER : IDWALK_CB_NOP;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
+ LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
+ const int cb_flag = is_reference ? IDWALK_CB_USER : IDWALK_CB_NOP;
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
- FOREACH_FINALIZE_VOID;
+ FOREACH_FINALIZE_VOID;
}
-static void library_foreach_particlesystemsObjectLooper(
- ParticleSystem *UNUSED(psys), ID **id_pointer, void *user_data, int cb_flag)
+static void library_foreach_particlesystemsObjectLooper(ParticleSystem *UNUSED(psys),
+ ID **id_pointer,
+ void *user_data,
+ int cb_flag)
{
- LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
+ LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
- FOREACH_FINALIZE_VOID;
+ FOREACH_FINALIZE_VOID;
}
static void library_foreach_nla_strip(LibraryForeachIDData *data, NlaStrip *strip)
{
- NlaStrip *substrip;
+ NlaStrip *substrip;
- FOREACH_CALLBACK_INVOKE(data, strip->act, IDWALK_CB_USER);
+ FOREACH_CALLBACK_INVOKE(data, strip->act, IDWALK_CB_USER);
- for (substrip = strip->strips.first; substrip; substrip = substrip->next) {
- library_foreach_nla_strip(data, substrip);
- }
+ for (substrip = strip->strips.first; substrip; substrip = substrip->next) {
+ library_foreach_nla_strip(data, substrip);
+ }
- FOREACH_FINALIZE_VOID;
+ FOREACH_FINALIZE_VOID;
}
static void library_foreach_animationData(LibraryForeachIDData *data, AnimData *adt)
{
- FCurve *fcu;
- NlaTrack *nla_track;
- NlaStrip *nla_strip;
-
- for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
- ChannelDriver *driver = fcu->driver;
- DriverVar *dvar;
-
- for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
- /* only used targets */
- DRIVER_TARGETS_USED_LOOPER_BEGIN(dvar)
- {
- FOREACH_CALLBACK_INVOKE_ID(data, dtar->id, IDWALK_CB_NOP);
- }
- DRIVER_TARGETS_LOOPER_END;
- }
- }
-
- FOREACH_CALLBACK_INVOKE(data, adt->action, IDWALK_CB_USER);
- FOREACH_CALLBACK_INVOKE(data, adt->tmpact, IDWALK_CB_USER);
-
- for (nla_track = adt->nla_tracks.first; nla_track; nla_track = nla_track->next) {
- for (nla_strip = nla_track->strips.first; nla_strip; nla_strip = nla_strip->next) {
- library_foreach_nla_strip(data, nla_strip);
- }
- }
-
- FOREACH_FINALIZE_VOID;
+ FCurve *fcu;
+ NlaTrack *nla_track;
+ NlaStrip *nla_strip;
+
+ for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
+ ChannelDriver *driver = fcu->driver;
+ DriverVar *dvar;
+
+ for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
+ /* only used targets */
+ DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
+ FOREACH_CALLBACK_INVOKE_ID(data, dtar->id, IDWALK_CB_NOP);
+ }
+ DRIVER_TARGETS_LOOPER_END;
+ }
+ }
+
+ FOREACH_CALLBACK_INVOKE(data, adt->action, IDWALK_CB_USER);
+ FOREACH_CALLBACK_INVOKE(data, adt->tmpact, IDWALK_CB_USER);
+
+ for (nla_track = adt->nla_tracks.first; nla_track; nla_track = nla_track->next) {
+ for (nla_strip = nla_track->strips.first; nla_strip; nla_strip = nla_strip->next) {
+ library_foreach_nla_strip(data, nla_strip);
+ }
+ }
+
+ FOREACH_FINALIZE_VOID;
}
static void library_foreach_mtex(LibraryForeachIDData *data, MTex *mtex)
{
- FOREACH_CALLBACK_INVOKE(data, mtex->object, IDWALK_CB_NOP);
- FOREACH_CALLBACK_INVOKE(data, mtex->tex, IDWALK_CB_USER);
+ FOREACH_CALLBACK_INVOKE(data, mtex->object, IDWALK_CB_NOP);
+ FOREACH_CALLBACK_INVOKE(data, mtex->tex, IDWALK_CB_USER);
- FOREACH_FINALIZE_VOID;
+ FOREACH_FINALIZE_VOID;
}
static void library_foreach_paint(LibraryForeachIDData *data, Paint *paint)
{
- FOREACH_CALLBACK_INVOKE(data, paint->brush, IDWALK_CB_USER);
- for (int i = 0; i < paint->tool_slots_len; i++) {
- FOREACH_CALLBACK_INVOKE(data, paint->tool_slots[i].brush, IDWALK_CB_USER);
- }
- FOREACH_CALLBACK_INVOKE(data, paint->palette, IDWALK_CB_USER);
+ FOREACH_CALLBACK_INVOKE(data, paint->brush, IDWALK_CB_USER);
+ for (int i = 0; i < paint->tool_slots_len; i++) {
+ FOREACH_CALLBACK_INVOKE(data, paint->tool_slots[i].brush, IDWALK_CB_USER);
+ }
+ FOREACH_CALLBACK_INVOKE(data, paint->palette, IDWALK_CB_USER);
- FOREACH_FINALIZE_VOID;
+ FOREACH_FINALIZE_VOID;
}
static void library_foreach_bone(LibraryForeachIDData *data, Bone *bone)
{
- library_foreach_idproperty_ID_link(data, bone->prop, IDWALK_CB_USER);
+ library_foreach_idproperty_ID_link(data, bone->prop, IDWALK_CB_USER);
- for (Bone *curbone = bone->childbase.first; curbone; curbone = curbone->next) {
- library_foreach_bone(data, curbone);
- }
+ for (Bone *curbone = bone->childbase.first; curbone; curbone = curbone->next) {
+ library_foreach_bone(data, curbone);
+ }
- FOREACH_FINALIZE_VOID;
+ FOREACH_FINALIZE_VOID;
}
static void library_foreach_layer_collection(LibraryForeachIDData *data, ListBase *lb)
{
- for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
- FOREACH_CALLBACK_INVOKE(data, lc->collection, IDWALK_CB_NOP);
- library_foreach_layer_collection(data, &lc->layer_collections);
- }
+ for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
+ FOREACH_CALLBACK_INVOKE(data, lc->collection, IDWALK_CB_NOP);
+ library_foreach_layer_collection(data, &lc->layer_collections);
+ }
- FOREACH_FINALIZE_VOID;
+ FOREACH_FINALIZE_VOID;
}
-static void library_foreach_ID_as_subdata_link(
- ID **id_pp, LibraryIDLinkCallback callback, void *user_data, int flag, LibraryForeachIDData *data)
+static void library_foreach_ID_as_subdata_link(ID **id_pp,
+ LibraryIDLinkCallback callback,
+ void *user_data,
+ int flag,
+ LibraryForeachIDData *data)
{
- /* Needed e.g. for callbacks handling relationships... This call shall be absolutely readonly. */
- ID *id = *id_pp;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pp, IDWALK_CB_PRIVATE);
- BLI_assert(id == *id_pp);
-
- if (flag & IDWALK_RECURSE) {
- /* Defer handling into main loop, recursively calling BKE_library_foreach_ID_link in IDWALK_RECURSE case is
- * troublesome, see T49553. */
- if (BLI_gset_add(data->ids_handled, id)) {
- BLI_LINKSTACK_PUSH(data->ids_todo, id);
- }
- }
- else {
- library_foreach_ID_link(NULL, id, callback, user_data, flag, data);
- }
-
- FOREACH_FINALIZE_VOID;
+ /* Needed e.g. for callbacks handling relationships... This call shall be absolutely readonly. */
+ ID *id = *id_pp;
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pp, IDWALK_CB_PRIVATE);
+ BLI_assert(id == *id_pp);
+
+ if (flag & IDWALK_RECURSE) {
+ /* Defer handling into main loop, recursively calling BKE_library_foreach_ID_link in IDWALK_RECURSE case is
+ * troublesome, see T49553. */
+ if (BLI_gset_add(data->ids_handled, id)) {
+ BLI_LINKSTACK_PUSH(data->ids_todo, id);
+ }
+ }
+ else {
+ library_foreach_ID_link(NULL, id, callback, user_data, flag, data);
+ }
+
+ FOREACH_FINALIZE_VOID;
}
-static void library_foreach_ID_link(
- Main *bmain, ID *id,
- LibraryIDLinkCallback callback, void *user_data, int flag,
- LibraryForeachIDData *inherit_data)
+static void library_foreach_ID_link(Main *bmain,
+ ID *id,
+ LibraryIDLinkCallback callback,
+ void *user_data,
+ int flag,
+ LibraryForeachIDData *inherit_data)
{
- LibraryForeachIDData data;
- int i;
+ LibraryForeachIDData data;
+ int i;
- if (flag & IDWALK_RECURSE) {
- /* For now, recusion implies read-only. */
- flag |= IDWALK_READONLY;
+ if (flag & IDWALK_RECURSE) {
+ /* For now, recusion implies read-only. */
+ flag |= IDWALK_READONLY;
- data.ids_handled = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
- BLI_LINKSTACK_INIT(data.ids_todo);
+ data.ids_handled = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+ BLI_LINKSTACK_INIT(data.ids_todo);
- BLI_gset_add(data.ids_handled, id);
- }
- else {
- data.ids_handled = NULL;
- }
- data.flag = flag;
- data.status = 0;
- data.callback = callback;
- data.user_data = user_data;
+ BLI_gset_add(data.ids_handled, id);
+ }
+ else {
+ data.ids_handled = NULL;
+ }
+ data.flag = flag;
+ data.status = 0;
+ data.callback = callback;
+ data.user_data = user_data;
-#define CALLBACK_INVOKE_ID(check_id, cb_flag) \
- FOREACH_CALLBACK_INVOKE_ID(&data, check_id, cb_flag)
+#define CALLBACK_INVOKE_ID(check_id, cb_flag) FOREACH_CALLBACK_INVOKE_ID(&data, check_id, cb_flag)
#define CALLBACK_INVOKE(check_id_super, cb_flag) \
- FOREACH_CALLBACK_INVOKE(&data, check_id_super, cb_flag)
-
- for (; id != NULL; id = (flag & IDWALK_RECURSE) ? BLI_LINKSTACK_POP(data.ids_todo) : NULL) {
- data.self_id = id;
-
- /* inherit_data is non-NULL when this function is called for some sub-data ID
- * (like root nodetree of a material).
- * In that case, we do not want to generate those 'generic flags' from our current sub-data ID (the node tree),
- * but re-use those generated for the 'owner' ID (the material)... */
- if (inherit_data == NULL) {
- data.cb_flag = ID_IS_LINKED(id) ? IDWALK_CB_INDIRECT_USAGE : 0;
- /* When an ID is not in Main database, it should never refcount IDs it is using.
- * Exceptions: NodeTrees (yeeahhh!) directly used by Materials. */
- data.cb_flag_clear = (id->tag & LIB_TAG_NO_MAIN) ? IDWALK_CB_USER | IDWALK_CB_USER_ONE : 0;
- }
- else {
- data.cb_flag = inherit_data->cb_flag;
- data.cb_flag_clear = inherit_data->cb_flag_clear;
- }
-
- if (bmain != NULL && bmain->relations != NULL && (flag & IDWALK_READONLY)) {
- /* Note that this is minor optimization, even in worst cases (like id being an object with lots of
- * drivers and constraints and modifiers, or material etc. with huge node tree),
- * but we might as well use it (Main->relations is always assumed valid, it's responsibility of code
- * creating it to free it, especially if/when it starts modifying Main database). */
- MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->id_user_to_used, id);
- for (; entry != NULL; entry = entry->next) {
- FOREACH_CALLBACK_INVOKE_ID_PP(&data, entry->id_pointer, entry->usage_flag);
- }
- continue;
- }
-
- if (id->override_static != NULL) {
- CALLBACK_INVOKE_ID(id->override_static->reference, IDWALK_CB_USER | IDWALK_CB_STATIC_OVERRIDE_REFERENCE);
- CALLBACK_INVOKE_ID(id->override_static->storage, IDWALK_CB_USER | IDWALK_CB_STATIC_OVERRIDE_REFERENCE);
- }
-
- library_foreach_idproperty_ID_link(&data, id->properties, IDWALK_CB_USER);
-
- AnimData *adt = BKE_animdata_from_id(id);
- if (adt) {
- library_foreach_animationData(&data, adt);
- }
-
- switch ((ID_Type)GS(id->name)) {
- case ID_LI:
- {
- Library *lib = (Library *) id;
- CALLBACK_INVOKE(lib->parent, IDWALK_CB_NEVER_SELF);
- break;
- }
- case ID_SCE:
- {
- Scene *scene = (Scene *) id;
- ToolSettings *toolsett = scene->toolsettings;
-
- CALLBACK_INVOKE(scene->camera, IDWALK_CB_NOP);
- CALLBACK_INVOKE(scene->world, IDWALK_CB_USER);
- CALLBACK_INVOKE(scene->set, IDWALK_CB_NEVER_SELF);
- CALLBACK_INVOKE(scene->clip, IDWALK_CB_USER);
- CALLBACK_INVOKE(scene->r.bake.cage_object, IDWALK_CB_NOP);
- if (scene->nodetree) {
- /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
- library_foreach_ID_as_subdata_link((ID **)&scene->nodetree, callback, user_data, flag, &data);
- }
- if (scene->ed) {
- Sequence *seq;
- SEQP_BEGIN(scene->ed, seq)
- {
- CALLBACK_INVOKE(seq->scene, IDWALK_CB_NEVER_SELF);
- CALLBACK_INVOKE(seq->scene_camera, IDWALK_CB_NOP);
- CALLBACK_INVOKE(seq->clip, IDWALK_CB_USER);
- CALLBACK_INVOKE(seq->mask, IDWALK_CB_USER);
- CALLBACK_INVOKE(seq->sound, IDWALK_CB_USER);
- library_foreach_idproperty_ID_link(&data, seq->prop, IDWALK_CB_USER);
- for (SequenceModifierData *smd = seq->modifiers.first; smd; smd = smd->next) {
- CALLBACK_INVOKE(smd->mask_id, IDWALK_CB_USER);
- }
-
- if (seq->type == SEQ_TYPE_TEXT && seq->effectdata) {
- TextVars *text_data = seq->effectdata;
- CALLBACK_INVOKE(text_data->text_font, IDWALK_CB_USER);
- }
- } SEQ_END;
- }
-
-
- for (CollectionObject *cob = scene->master_collection->gobject.first; cob; cob = cob->next) {
- CALLBACK_INVOKE(cob->ob, IDWALK_CB_USER);
- }
- for (CollectionChild *child = scene->master_collection->children.first; child; child = child->next) {
- CALLBACK_INVOKE(child->collection, IDWALK_CB_USER);
- }
-
- ViewLayer *view_layer;
- for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
- CALLBACK_INVOKE(view_layer->mat_override, IDWALK_CB_USER);
-
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
- CALLBACK_INVOKE(base->object, IDWALK_CB_NOP);
- }
-
- library_foreach_layer_collection(&data, &view_layer->layer_collections);
-
- for (FreestyleModuleConfig *fmc = view_layer->freestyle_config.modules.first; fmc; fmc = fmc->next) {
- if (fmc->script) {
- CALLBACK_INVOKE(fmc->script, IDWALK_CB_NOP);
- }
- }
-
- for (FreestyleLineSet *fls = view_layer->freestyle_config.linesets.first; fls; fls = fls->next) {
- if (fls->group) {
- CALLBACK_INVOKE(fls->group, IDWALK_CB_USER);
- }
-
- if (fls->linestyle) {
- CALLBACK_INVOKE(fls->linestyle, IDWALK_CB_USER);
- }
- }
- }
-
- for (TimeMarker *marker = scene->markers.first; marker; marker = marker->next) {
- CALLBACK_INVOKE(marker->camera, IDWALK_CB_NOP);
- }
-
- if (toolsett) {
- CALLBACK_INVOKE(toolsett->particle.scene, IDWALK_CB_NOP);
- CALLBACK_INVOKE(toolsett->particle.object, IDWALK_CB_NOP);
- CALLBACK_INVOKE(toolsett->particle.shape_object, IDWALK_CB_NOP);
-
- library_foreach_paint(&data, &toolsett->imapaint.paint);
- CALLBACK_INVOKE(toolsett->imapaint.stencil, IDWALK_CB_USER);
- CALLBACK_INVOKE(toolsett->imapaint.clone, IDWALK_CB_USER);
- CALLBACK_INVOKE(toolsett->imapaint.canvas, IDWALK_CB_USER);
-
- if (toolsett->vpaint) {
- library_foreach_paint(&data, &toolsett->vpaint->paint);
- }
- if (toolsett->wpaint) {
- library_foreach_paint(&data, &toolsett->wpaint->paint);
- }
- if (toolsett->sculpt) {
- library_foreach_paint(&data, &toolsett->sculpt->paint);
- CALLBACK_INVOKE(toolsett->sculpt->gravity_object, IDWALK_CB_NOP);
- }
- if (toolsett->uvsculpt) {
- library_foreach_paint(&data, &toolsett->uvsculpt->paint);
- }
- if (toolsett->gp_paint) {
- library_foreach_paint(&data, &toolsett->gp_paint->paint);
- }
-
- CALLBACK_INVOKE(toolsett->gp_sculpt.guide.reference_object, IDWALK_CB_NOP);
-
- }
-
- if (scene->rigidbody_world) {
- BKE_rigidbody_world_id_loop(scene->rigidbody_world, library_foreach_rigidbodyworldSceneLooper, &data);
- }
-
- break;
- }
-
- case ID_OB:
- {
- Object *object = (Object *) id;
- ParticleSystem *psys;
-
- /* Object is special, proxies make things hard... */
- const int data_cb_flag = data.cb_flag;
- const int proxy_cb_flag = ((data.flag & IDWALK_NO_INDIRECT_PROXY_DATA_USAGE) == 0 && (object->proxy || object->proxy_group)) ?
- IDWALK_CB_INDIRECT_USAGE : 0;
-
- /* object data special case */
- data.cb_flag |= proxy_cb_flag;
- if (object->type == OB_EMPTY) {
- /* empty can have NULL or Image */
- CALLBACK_INVOKE_ID(object->data, IDWALK_CB_USER);
- }
- else {
- /* when set, this can't be NULL */
- if (object->data) {
- CALLBACK_INVOKE_ID(object->data, IDWALK_CB_USER | IDWALK_CB_NEVER_NULL);
- }
- }
- data.cb_flag = data_cb_flag;
-
- CALLBACK_INVOKE(object->parent, IDWALK_CB_NEVER_SELF);
- CALLBACK_INVOKE(object->track, IDWALK_CB_NEVER_SELF);
- /* object->proxy is refcounted, but not object->proxy_group... *sigh* */
- CALLBACK_INVOKE(object->proxy, IDWALK_CB_NEVER_SELF);
- CALLBACK_INVOKE(object->proxy_group, IDWALK_CB_NOP);
-
- /* Special case!
- * Since this field is set/owned by 'user' of this ID (and not ID itself), it is only indirect usage
- * if proxy object is linked... Twisted. */
- if (object->proxy_from) {
- data.cb_flag = ID_IS_LINKED(object->proxy_from) ? IDWALK_CB_INDIRECT_USAGE : 0;
- }
- CALLBACK_INVOKE(object->proxy_from, IDWALK_CB_LOOPBACK | IDWALK_CB_NEVER_SELF);
- data.cb_flag = data_cb_flag;
-
- CALLBACK_INVOKE(object->poselib, IDWALK_CB_USER);
-
- data.cb_flag |= proxy_cb_flag;
- for (i = 0; i < object->totcol; i++) {
- CALLBACK_INVOKE(object->mat[i], IDWALK_CB_USER);
- }
- data.cb_flag = data_cb_flag;
-
- /* Note that ob->gpd is deprecated, so no need to handle it here. */
- CALLBACK_INVOKE(object->instance_collection, IDWALK_CB_USER);
-
- if (object->pd) {
- CALLBACK_INVOKE(object->pd->tex, IDWALK_CB_USER);
- CALLBACK_INVOKE(object->pd->f_source, IDWALK_CB_NOP);
- }
- /* Note that ob->effect is deprecated, so no need to handle it here. */
-
- if (object->pose) {
- bPoseChannel *pchan;
-
- data.cb_flag |= proxy_cb_flag;
- for (pchan = object->pose->chanbase.first; pchan; pchan = pchan->next) {
- library_foreach_idproperty_ID_link(&data, pchan->prop, IDWALK_CB_USER);
- CALLBACK_INVOKE(pchan->custom, IDWALK_CB_USER);
- BKE_constraints_id_loop(&pchan->constraints, library_foreach_constraintObjectLooper, &data);
- }
- data.cb_flag = data_cb_flag;
- }
-
- if (object->rigidbody_constraint) {
- CALLBACK_INVOKE(object->rigidbody_constraint->ob1, IDWALK_CB_NEVER_SELF);
- CALLBACK_INVOKE(object->rigidbody_constraint->ob2, IDWALK_CB_NEVER_SELF);
- }
-
- if (object->lodlevels.first) {
- LodLevel *level;
- for (level = object->lodlevels.first; level; level = level->next) {
- CALLBACK_INVOKE(level->source, IDWALK_CB_NEVER_SELF);
- }
- }
-
- modifiers_foreachIDLink(object, library_foreach_modifiersForeachIDLink, &data);
- BKE_gpencil_modifiers_foreachIDLink(object, library_foreach_gpencil_modifiersForeachIDLink, &data);
- BKE_constraints_id_loop(&object->constraints, library_foreach_constraintObjectLooper, &data);
- BKE_shaderfx_foreachIDLink(object, library_foreach_shaderfxForeachIDLink, &data);
-
- for (psys = object->particlesystem.first; psys; psys = psys->next) {
- BKE_particlesystem_id_loop(psys, library_foreach_particlesystemsObjectLooper, &data);
- }
-
- if (object->soft) {
- CALLBACK_INVOKE(object->soft->collision_group, IDWALK_CB_NOP);
-
- if (object->soft->effector_weights) {
- CALLBACK_INVOKE(object->soft->effector_weights->group, IDWALK_CB_NOP);
- }
- }
- break;
- }
-
- case ID_AR:
- {
- bArmature *arm = (bArmature *)id;
-
- for (Bone *bone = arm->bonebase.first; bone; bone = bone->next) {
- library_foreach_bone(&data, bone);
- }
- break;
- }
-
- case ID_ME:
- {
- Mesh *mesh = (Mesh *) id;
- CALLBACK_INVOKE(mesh->texcomesh, IDWALK_CB_NEVER_SELF);
- CALLBACK_INVOKE(mesh->key, IDWALK_CB_USER);
- for (i = 0; i < mesh->totcol; i++) {
- CALLBACK_INVOKE(mesh->mat[i], IDWALK_CB_USER);
- }
- break;
- }
-
- case ID_CU:
- {
- Curve *curve = (Curve *) id;
- CALLBACK_INVOKE(curve->bevobj, IDWALK_CB_NOP);
- CALLBACK_INVOKE(curve->taperobj, IDWALK_CB_NOP);
- CALLBACK_INVOKE(curve->textoncurve, IDWALK_CB_NOP);
- CALLBACK_INVOKE(curve->key, IDWALK_CB_USER);
- for (i = 0; i < curve->totcol; i++) {
- CALLBACK_INVOKE(curve->mat[i], IDWALK_CB_USER);
- }
- CALLBACK_INVOKE(curve->vfont, IDWALK_CB_USER);
- CALLBACK_INVOKE(curve->vfontb, IDWALK_CB_USER);
- CALLBACK_INVOKE(curve->vfonti, IDWALK_CB_USER);
- CALLBACK_INVOKE(curve->vfontbi, IDWALK_CB_USER);
- break;
- }
-
- case ID_MB:
- {
- MetaBall *metaball = (MetaBall *) id;
- for (i = 0; i < metaball->totcol; i++) {
- CALLBACK_INVOKE(metaball->mat[i], IDWALK_CB_USER);
- }
- break;
- }
-
- case ID_MA:
- {
- Material *material = (Material *) id;
- if (material->nodetree) {
- /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
- library_foreach_ID_as_subdata_link((ID **)&material->nodetree, callback, user_data, flag, &data);
- }
- if (material->texpaintslot != NULL) {
- CALLBACK_INVOKE(material->texpaintslot->ima, IDWALK_CB_NOP);
- }
- if (material->gp_style != NULL) {
- CALLBACK_INVOKE(material->gp_style->sima, IDWALK_CB_USER);
- CALLBACK_INVOKE(material->gp_style->ima, IDWALK_CB_USER);
- }
- break;
- }
-
- case ID_TE:
- {
- Tex *texture = (Tex *) id;
- if (texture->nodetree) {
- /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
- library_foreach_ID_as_subdata_link((ID **)&texture->nodetree, callback, user_data, flag, &data);
- }
- CALLBACK_INVOKE(texture->ima, IDWALK_CB_USER);
- break;
- }
-
- case ID_LT:
- {
- Lattice *lattice = (Lattice *) id;
- CALLBACK_INVOKE(lattice->key, IDWALK_CB_USER);
- break;
- }
-
- case ID_LA:
- {
- Light *lamp = (Light *) id;
- if (lamp->nodetree) {
- /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
- library_foreach_ID_as_subdata_link((ID **)&lamp->nodetree, callback, user_data, flag, &data);
- }
- break;
- }
-
- case ID_CA:
- {
- Camera *camera = (Camera *) id;
- CALLBACK_INVOKE(camera->dof_ob, IDWALK_CB_NOP);
- for (CameraBGImage *bgpic = camera->bg_images.first; bgpic; bgpic = bgpic->next) {
- if (bgpic->source == CAM_BGIMG_SOURCE_IMAGE) {
- CALLBACK_INVOKE(bgpic->ima, IDWALK_CB_USER);
- }
- else if (bgpic->source == CAM_BGIMG_SOURCE_MOVIE) {
- CALLBACK_INVOKE(bgpic->clip, IDWALK_CB_USER);
- }
- }
-
- break;
- }
-
- case ID_KE:
- {
- Key *key = (Key *) id;
- CALLBACK_INVOKE_ID(key->from, IDWALK_CB_LOOPBACK);
- break;
- }
-
- case ID_WO:
- {
- World *world = (World *) id;
- if (world->nodetree) {
- /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
- library_foreach_ID_as_subdata_link((ID **)&world->nodetree, callback, user_data, flag, &data);
- }
- break;
- }
-
- case ID_SPK:
- {
- Speaker *speaker = (Speaker *) id;
- CALLBACK_INVOKE(speaker->sound, IDWALK_CB_USER);
- break;
- }
-
- case ID_LP:
- {
- LightProbe *probe = (LightProbe *) id;
- CALLBACK_INVOKE(probe->image, IDWALK_CB_USER);
- CALLBACK_INVOKE(probe->visibility_grp, IDWALK_CB_NOP);
- break;
- }
-
- case ID_GR:
- {
- Collection *collection = (Collection *) id;
- for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
- CALLBACK_INVOKE(cob->ob, IDWALK_CB_USER);
- }
- for (CollectionChild *child = collection->children.first; child; child = child->next) {
- CALLBACK_INVOKE(child->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_USER);
- }
- for (CollectionParent *parent = collection->parents.first; parent; parent = parent->next) {
- CALLBACK_INVOKE(parent->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_LOOPBACK);
- }
- break;
- }
-
- case ID_NT:
- {
- bNodeTree *ntree = (bNodeTree *) id;
- bNode *node;
- bNodeSocket *sock;
-
- CALLBACK_INVOKE(ntree->gpd, IDWALK_CB_USER);
-
- for (node = ntree->nodes.first; node; node = node->next) {
- CALLBACK_INVOKE_ID(node->id, IDWALK_CB_USER);
-
- library_foreach_idproperty_ID_link(&data, node->prop, IDWALK_CB_USER);
- for (sock = node->inputs.first; sock; sock = sock->next) {
- library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER);
- }
- for (sock = node->outputs.first; sock; sock = sock->next) {
- library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER);
- }
- }
-
- for (sock = ntree->inputs.first; sock; sock = sock->next) {
- library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER);
- }
- for (sock = ntree->outputs.first; sock; sock = sock->next) {
- library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER);
- }
- break;
- }
-
- case ID_BR:
- {
- Brush *brush = (Brush *) id;
- CALLBACK_INVOKE(brush->toggle_brush, IDWALK_CB_NOP);
- CALLBACK_INVOKE(brush->clone.image, IDWALK_CB_NOP);
- CALLBACK_INVOKE(brush->paint_curve, IDWALK_CB_USER);
- if (brush->gpencil_settings) {
- CALLBACK_INVOKE(brush->gpencil_settings->material, IDWALK_CB_USER);
- }
- library_foreach_mtex(&data, &brush->mtex);
- library_foreach_mtex(&data, &brush->mask_mtex);
- break;
- }
-
- case ID_PA:
- {
- ParticleSettings *psett = (ParticleSettings *) id;
- CALLBACK_INVOKE(psett->instance_collection, IDWALK_CB_USER);
- CALLBACK_INVOKE(psett->instance_object, IDWALK_CB_NOP);
- CALLBACK_INVOKE(psett->bb_ob, IDWALK_CB_NOP);
- CALLBACK_INVOKE(psett->collision_group, IDWALK_CB_NOP);
-
- for (i = 0; i < MAX_MTEX; i++) {
- if (psett->mtex[i]) {
- library_foreach_mtex(&data, psett->mtex[i]);
- }
- }
-
- if (psett->effector_weights) {
- CALLBACK_INVOKE(psett->effector_weights->group, IDWALK_CB_NOP);
- }
-
- if (psett->pd) {
- CALLBACK_INVOKE(psett->pd->tex, IDWALK_CB_USER);
- CALLBACK_INVOKE(psett->pd->f_source, IDWALK_CB_NOP);
- }
- if (psett->pd2) {
- CALLBACK_INVOKE(psett->pd2->tex, IDWALK_CB_USER);
- CALLBACK_INVOKE(psett->pd2->f_source, IDWALK_CB_NOP);
- }
-
- if (psett->boids) {
- BoidState *state;
- BoidRule *rule;
-
- for (state = psett->boids->states.first; state; state = state->next) {
- for (rule = state->rules.first; rule; rule = rule->next) {
- if (rule->type == eBoidRuleType_Avoid) {
- BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid *)rule;
- CALLBACK_INVOKE(gabr->ob, IDWALK_CB_NOP);
- }
- else if (rule->type == eBoidRuleType_FollowLeader) {
- BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader *)rule;
- CALLBACK_INVOKE(flbr->ob, IDWALK_CB_NOP);
- }
- }
- }
- }
-
- for (ParticleDupliWeight *dw = psett->instance_weights.first; dw; dw = dw->next) {
- CALLBACK_INVOKE(dw->ob, IDWALK_CB_NOP);
- }
- break;
- }
-
- case ID_MC:
- {
- MovieClip *clip = (MovieClip *) id;
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *object;
- MovieTrackingTrack *track;
- MovieTrackingPlaneTrack *plane_track;
-
- CALLBACK_INVOKE(clip->gpd, IDWALK_CB_USER);
-
- for (track = tracking->tracks.first; track; track = track->next) {
- CALLBACK_INVOKE(track->gpd, IDWALK_CB_USER);
- }
- for (object = tracking->objects.first; object; object = object->next) {
- for (track = object->tracks.first; track; track = track->next) {
- CALLBACK_INVOKE(track->gpd, IDWALK_CB_USER);
- }
- }
-
- for (plane_track = tracking->plane_tracks.first; plane_track; plane_track = plane_track->next) {
- CALLBACK_INVOKE(plane_track->image, IDWALK_CB_USER);
- }
- break;
- }
-
- case ID_MSK:
- {
- Mask *mask = (Mask *) id;
- MaskLayer *mask_layer;
- for (mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
- MaskSpline *mask_spline;
-
- for (mask_spline = mask_layer->splines.first; mask_spline; mask_spline = mask_spline->next) {
- for (i = 0; i < mask_spline->tot_point; i++) {
- MaskSplinePoint *point = &mask_spline->points[i];
- CALLBACK_INVOKE_ID(point->parent.id, IDWALK_CB_USER);
- }
- }
- }
- break;
- }
-
- case ID_LS:
- {
- FreestyleLineStyle *linestyle = (FreestyleLineStyle *) id;
- LineStyleModifier *lsm;
- for (i = 0; i < MAX_MTEX; i++) {
- if (linestyle->mtex[i]) {
- library_foreach_mtex(&data, linestyle->mtex[i]);
- }
- }
- if (linestyle->nodetree) {
- /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
- library_foreach_ID_as_subdata_link((ID **)&linestyle->nodetree, callback, user_data, flag, &data);
- }
-
- for (lsm = linestyle->color_modifiers.first; lsm; lsm = lsm->next) {
- if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
- LineStyleColorModifier_DistanceFromObject *p = (LineStyleColorModifier_DistanceFromObject *)lsm;
- if (p->target) {
- CALLBACK_INVOKE(p->target, IDWALK_CB_NOP);
- }
- }
- }
- for (lsm = linestyle->alpha_modifiers.first; lsm; lsm = lsm->next) {
- if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
- LineStyleAlphaModifier_DistanceFromObject *p = (LineStyleAlphaModifier_DistanceFromObject *)lsm;
- if (p->target) {
- CALLBACK_INVOKE(p->target, IDWALK_CB_NOP);
- }
- }
- }
- for (lsm = linestyle->thickness_modifiers.first; lsm; lsm = lsm->next) {
- if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
- LineStyleThicknessModifier_DistanceFromObject *p = (LineStyleThicknessModifier_DistanceFromObject *)lsm;
- if (p->target) {
- CALLBACK_INVOKE(p->target, IDWALK_CB_NOP);
- }
- }
- }
- break;
- }
- case ID_AC:
- {
- bAction *act = (bAction *) id;
-
- for (TimeMarker *marker = act->markers.first; marker; marker = marker->next) {
- CALLBACK_INVOKE(marker->camera, IDWALK_CB_NOP);
- }
- break;
- }
-
- case ID_WM:
- {
- wmWindowManager *wm = (wmWindowManager *)id;
-
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
- ID *workspace = (ID *)BKE_workspace_active_get(win->workspace_hook);
-
- CALLBACK_INVOKE(win->scene, IDWALK_CB_USER_ONE);
-
- CALLBACK_INVOKE_ID(workspace, IDWALK_CB_NOP);
- /* allow callback to set a different workspace */
- BKE_workspace_active_set(win->workspace_hook, (WorkSpace *)workspace);
- }
- break;
- }
-
- case ID_WS:
- {
- WorkSpace *workspace = (WorkSpace *)id;
- ListBase *layouts = BKE_workspace_layouts_get(workspace);
-
- for (WorkSpaceLayout *layout = layouts->first; layout; layout = layout->next) {
- bScreen *screen = BKE_workspace_layout_screen_get(layout);
-
- /* CALLBACK_INVOKE expects an actual pointer, not a variable holding the pointer.
- * However we can't access layout->screen here since we are outside the workspace project. */
- CALLBACK_INVOKE(screen, IDWALK_CB_USER);
- /* allow callback to set a different screen */
- BKE_workspace_layout_screen_set(layout, screen);
- }
- break;
- }
- case ID_GD:
- {
- bGPdata *gpencil = (bGPdata *) id;
- /* materials */
- for (i = 0; i < gpencil->totcol; i++) {
- CALLBACK_INVOKE(gpencil->mat[i], IDWALK_CB_USER);
- }
-
- for (bGPDlayer *gplayer = gpencil->layers.first; gplayer != NULL; gplayer = gplayer->next) {
- CALLBACK_INVOKE(gplayer->parent, IDWALK_CB_NOP);
- }
-
- break;
- }
-
- /* Nothing needed for those... */
- case ID_SCR:
- case ID_IM:
- case ID_VF:
- case ID_TXT:
- case ID_SO:
- case ID_PAL:
- case ID_PC:
- case ID_CF:
- break;
-
- /* Deprecated. */
- case ID_IP:
- break;
-
- }
- }
+ FOREACH_CALLBACK_INVOKE(&data, check_id_super, cb_flag)
+
+ for (; id != NULL; id = (flag & IDWALK_RECURSE) ? BLI_LINKSTACK_POP(data.ids_todo) : NULL) {
+ data.self_id = id;
+
+ /* inherit_data is non-NULL when this function is called for some sub-data ID
+ * (like root nodetree of a material).
+ * In that case, we do not want to generate those 'generic flags' from our current sub-data ID (the node tree),
+ * but re-use those generated for the 'owner' ID (the material)... */
+ if (inherit_data == NULL) {
+ data.cb_flag = ID_IS_LINKED(id) ? IDWALK_CB_INDIRECT_USAGE : 0;
+ /* When an ID is not in Main database, it should never refcount IDs it is using.
+ * Exceptions: NodeTrees (yeeahhh!) directly used by Materials. */
+ data.cb_flag_clear = (id->tag & LIB_TAG_NO_MAIN) ? IDWALK_CB_USER | IDWALK_CB_USER_ONE : 0;
+ }
+ else {
+ data.cb_flag = inherit_data->cb_flag;
+ data.cb_flag_clear = inherit_data->cb_flag_clear;
+ }
+
+ if (bmain != NULL && bmain->relations != NULL && (flag & IDWALK_READONLY)) {
+ /* Note that this is minor optimization, even in worst cases (like id being an object with lots of
+ * drivers and constraints and modifiers, or material etc. with huge node tree),
+ * but we might as well use it (Main->relations is always assumed valid, it's responsibility of code
+ * creating it to free it, especially if/when it starts modifying Main database). */
+ MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->id_user_to_used, id);
+ for (; entry != NULL; entry = entry->next) {
+ FOREACH_CALLBACK_INVOKE_ID_PP(&data, entry->id_pointer, entry->usage_flag);
+ }
+ continue;
+ }
+
+ if (id->override_static != NULL) {
+ CALLBACK_INVOKE_ID(id->override_static->reference,
+ IDWALK_CB_USER | IDWALK_CB_STATIC_OVERRIDE_REFERENCE);
+ CALLBACK_INVOKE_ID(id->override_static->storage,
+ IDWALK_CB_USER | IDWALK_CB_STATIC_OVERRIDE_REFERENCE);
+ }
+
+ library_foreach_idproperty_ID_link(&data, id->properties, IDWALK_CB_USER);
+
+ AnimData *adt = BKE_animdata_from_id(id);
+ if (adt) {
+ library_foreach_animationData(&data, adt);
+ }
+
+ switch ((ID_Type)GS(id->name)) {
+ case ID_LI: {
+ Library *lib = (Library *)id;
+ CALLBACK_INVOKE(lib->parent, IDWALK_CB_NEVER_SELF);
+ break;
+ }
+ case ID_SCE: {
+ Scene *scene = (Scene *)id;
+ ToolSettings *toolsett = scene->toolsettings;
+
+ CALLBACK_INVOKE(scene->camera, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(scene->world, IDWALK_CB_USER);
+ CALLBACK_INVOKE(scene->set, IDWALK_CB_NEVER_SELF);
+ CALLBACK_INVOKE(scene->clip, IDWALK_CB_USER);
+ CALLBACK_INVOKE(scene->r.bake.cage_object, IDWALK_CB_NOP);
+ if (scene->nodetree) {
+ /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ library_foreach_ID_as_subdata_link(
+ (ID **)&scene->nodetree, callback, user_data, flag, &data);
+ }
+ if (scene->ed) {
+ Sequence *seq;
+ SEQP_BEGIN (scene->ed, seq) {
+ CALLBACK_INVOKE(seq->scene, IDWALK_CB_NEVER_SELF);
+ CALLBACK_INVOKE(seq->scene_camera, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(seq->clip, IDWALK_CB_USER);
+ CALLBACK_INVOKE(seq->mask, IDWALK_CB_USER);
+ CALLBACK_INVOKE(seq->sound, IDWALK_CB_USER);
+ library_foreach_idproperty_ID_link(&data, seq->prop, IDWALK_CB_USER);
+ for (SequenceModifierData *smd = seq->modifiers.first; smd; smd = smd->next) {
+ CALLBACK_INVOKE(smd->mask_id, IDWALK_CB_USER);
+ }
+
+ if (seq->type == SEQ_TYPE_TEXT && seq->effectdata) {
+ TextVars *text_data = seq->effectdata;
+ CALLBACK_INVOKE(text_data->text_font, IDWALK_CB_USER);
+ }
+ }
+ SEQ_END;
+ }
+
+ for (CollectionObject *cob = scene->master_collection->gobject.first; cob;
+ cob = cob->next) {
+ CALLBACK_INVOKE(cob->ob, IDWALK_CB_USER);
+ }
+ for (CollectionChild *child = scene->master_collection->children.first; child;
+ child = child->next) {
+ CALLBACK_INVOKE(child->collection, IDWALK_CB_USER);
+ }
+
+ ViewLayer *view_layer;
+ for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ CALLBACK_INVOKE(view_layer->mat_override, IDWALK_CB_USER);
+
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ CALLBACK_INVOKE(base->object, IDWALK_CB_NOP);
+ }
+
+ library_foreach_layer_collection(&data, &view_layer->layer_collections);
+
+ for (FreestyleModuleConfig *fmc = view_layer->freestyle_config.modules.first; fmc;
+ fmc = fmc->next) {
+ if (fmc->script) {
+ CALLBACK_INVOKE(fmc->script, IDWALK_CB_NOP);
+ }
+ }
+
+ for (FreestyleLineSet *fls = view_layer->freestyle_config.linesets.first; fls;
+ fls = fls->next) {
+ if (fls->group) {
+ CALLBACK_INVOKE(fls->group, IDWALK_CB_USER);
+ }
+
+ if (fls->linestyle) {
+ CALLBACK_INVOKE(fls->linestyle, IDWALK_CB_USER);
+ }
+ }
+ }
+
+ for (TimeMarker *marker = scene->markers.first; marker; marker = marker->next) {
+ CALLBACK_INVOKE(marker->camera, IDWALK_CB_NOP);
+ }
+
+ if (toolsett) {
+ CALLBACK_INVOKE(toolsett->particle.scene, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(toolsett->particle.object, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(toolsett->particle.shape_object, IDWALK_CB_NOP);
+
+ library_foreach_paint(&data, &toolsett->imapaint.paint);
+ CALLBACK_INVOKE(toolsett->imapaint.stencil, IDWALK_CB_USER);
+ CALLBACK_INVOKE(toolsett->imapaint.clone, IDWALK_CB_USER);
+ CALLBACK_INVOKE(toolsett->imapaint.canvas, IDWALK_CB_USER);
+
+ if (toolsett->vpaint) {
+ library_foreach_paint(&data, &toolsett->vpaint->paint);
+ }
+ if (toolsett->wpaint) {
+ library_foreach_paint(&data, &toolsett->wpaint->paint);
+ }
+ if (toolsett->sculpt) {
+ library_foreach_paint(&data, &toolsett->sculpt->paint);
+ CALLBACK_INVOKE(toolsett->sculpt->gravity_object, IDWALK_CB_NOP);
+ }
+ if (toolsett->uvsculpt) {
+ library_foreach_paint(&data, &toolsett->uvsculpt->paint);
+ }
+ if (toolsett->gp_paint) {
+ library_foreach_paint(&data, &toolsett->gp_paint->paint);
+ }
+
+ CALLBACK_INVOKE(toolsett->gp_sculpt.guide.reference_object, IDWALK_CB_NOP);
+ }
+
+ if (scene->rigidbody_world) {
+ BKE_rigidbody_world_id_loop(
+ scene->rigidbody_world, library_foreach_rigidbodyworldSceneLooper, &data);
+ }
+
+ break;
+ }
+
+ case ID_OB: {
+ Object *object = (Object *)id;
+ ParticleSystem *psys;
+
+ /* Object is special, proxies make things hard... */
+ const int data_cb_flag = data.cb_flag;
+ const int proxy_cb_flag = ((data.flag & IDWALK_NO_INDIRECT_PROXY_DATA_USAGE) == 0 &&
+ (object->proxy || object->proxy_group)) ?
+ IDWALK_CB_INDIRECT_USAGE :
+ 0;
+
+ /* object data special case */
+ data.cb_flag |= proxy_cb_flag;
+ if (object->type == OB_EMPTY) {
+ /* empty can have NULL or Image */
+ CALLBACK_INVOKE_ID(object->data, IDWALK_CB_USER);
+ }
+ else {
+ /* when set, this can't be NULL */
+ if (object->data) {
+ CALLBACK_INVOKE_ID(object->data, IDWALK_CB_USER | IDWALK_CB_NEVER_NULL);
+ }
+ }
+ data.cb_flag = data_cb_flag;
+
+ CALLBACK_INVOKE(object->parent, IDWALK_CB_NEVER_SELF);
+ CALLBACK_INVOKE(object->track, IDWALK_CB_NEVER_SELF);
+ /* object->proxy is refcounted, but not object->proxy_group... *sigh* */
+ CALLBACK_INVOKE(object->proxy, IDWALK_CB_NEVER_SELF);
+ CALLBACK_INVOKE(object->proxy_group, IDWALK_CB_NOP);
+
+ /* Special case!
+ * Since this field is set/owned by 'user' of this ID (and not ID itself), it is only indirect usage
+ * if proxy object is linked... Twisted. */
+ if (object->proxy_from) {
+ data.cb_flag = ID_IS_LINKED(object->proxy_from) ? IDWALK_CB_INDIRECT_USAGE : 0;
+ }
+ CALLBACK_INVOKE(object->proxy_from, IDWALK_CB_LOOPBACK | IDWALK_CB_NEVER_SELF);
+ data.cb_flag = data_cb_flag;
+
+ CALLBACK_INVOKE(object->poselib, IDWALK_CB_USER);
+
+ data.cb_flag |= proxy_cb_flag;
+ for (i = 0; i < object->totcol; i++) {
+ CALLBACK_INVOKE(object->mat[i], IDWALK_CB_USER);
+ }
+ data.cb_flag = data_cb_flag;
+
+ /* Note that ob->gpd is deprecated, so no need to handle it here. */
+ CALLBACK_INVOKE(object->instance_collection, IDWALK_CB_USER);
+
+ if (object->pd) {
+ CALLBACK_INVOKE(object->pd->tex, IDWALK_CB_USER);
+ CALLBACK_INVOKE(object->pd->f_source, IDWALK_CB_NOP);
+ }
+ /* Note that ob->effect is deprecated, so no need to handle it here. */
+
+ if (object->pose) {
+ bPoseChannel *pchan;
+
+ data.cb_flag |= proxy_cb_flag;
+ for (pchan = object->pose->chanbase.first; pchan; pchan = pchan->next) {
+ library_foreach_idproperty_ID_link(&data, pchan->prop, IDWALK_CB_USER);
+ CALLBACK_INVOKE(pchan->custom, IDWALK_CB_USER);
+ BKE_constraints_id_loop(
+ &pchan->constraints, library_foreach_constraintObjectLooper, &data);
+ }
+ data.cb_flag = data_cb_flag;
+ }
+
+ if (object->rigidbody_constraint) {
+ CALLBACK_INVOKE(object->rigidbody_constraint->ob1, IDWALK_CB_NEVER_SELF);
+ CALLBACK_INVOKE(object->rigidbody_constraint->ob2, IDWALK_CB_NEVER_SELF);
+ }
+
+ if (object->lodlevels.first) {
+ LodLevel *level;
+ for (level = object->lodlevels.first; level; level = level->next) {
+ CALLBACK_INVOKE(level->source, IDWALK_CB_NEVER_SELF);
+ }
+ }
+
+ modifiers_foreachIDLink(object, library_foreach_modifiersForeachIDLink, &data);
+ BKE_gpencil_modifiers_foreachIDLink(
+ object, library_foreach_gpencil_modifiersForeachIDLink, &data);
+ BKE_constraints_id_loop(
+ &object->constraints, library_foreach_constraintObjectLooper, &data);
+ BKE_shaderfx_foreachIDLink(object, library_foreach_shaderfxForeachIDLink, &data);
+
+ for (psys = object->particlesystem.first; psys; psys = psys->next) {
+ BKE_particlesystem_id_loop(psys, library_foreach_particlesystemsObjectLooper, &data);
+ }
+
+ if (object->soft) {
+ CALLBACK_INVOKE(object->soft->collision_group, IDWALK_CB_NOP);
+
+ if (object->soft->effector_weights) {
+ CALLBACK_INVOKE(object->soft->effector_weights->group, IDWALK_CB_NOP);
+ }
+ }
+ break;
+ }
+
+ case ID_AR: {
+ bArmature *arm = (bArmature *)id;
+
+ for (Bone *bone = arm->bonebase.first; bone; bone = bone->next) {
+ library_foreach_bone(&data, bone);
+ }
+ break;
+ }
+
+ case ID_ME: {
+ Mesh *mesh = (Mesh *)id;
+ CALLBACK_INVOKE(mesh->texcomesh, IDWALK_CB_NEVER_SELF);
+ CALLBACK_INVOKE(mesh->key, IDWALK_CB_USER);
+ for (i = 0; i < mesh->totcol; i++) {
+ CALLBACK_INVOKE(mesh->mat[i], IDWALK_CB_USER);
+ }
+ break;
+ }
+
+ case ID_CU: {
+ Curve *curve = (Curve *)id;
+ CALLBACK_INVOKE(curve->bevobj, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(curve->taperobj, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(curve->textoncurve, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(curve->key, IDWALK_CB_USER);
+ for (i = 0; i < curve->totcol; i++) {
+ CALLBACK_INVOKE(curve->mat[i], IDWALK_CB_USER);
+ }
+ CALLBACK_INVOKE(curve->vfont, IDWALK_CB_USER);
+ CALLBACK_INVOKE(curve->vfontb, IDWALK_CB_USER);
+ CALLBACK_INVOKE(curve->vfonti, IDWALK_CB_USER);
+ CALLBACK_INVOKE(curve->vfontbi, IDWALK_CB_USER);
+ break;
+ }
+
+ case ID_MB: {
+ MetaBall *metaball = (MetaBall *)id;
+ for (i = 0; i < metaball->totcol; i++) {
+ CALLBACK_INVOKE(metaball->mat[i], IDWALK_CB_USER);
+ }
+ break;
+ }
+
+ case ID_MA: {
+ Material *material = (Material *)id;
+ if (material->nodetree) {
+ /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ library_foreach_ID_as_subdata_link(
+ (ID **)&material->nodetree, callback, user_data, flag, &data);
+ }
+ if (material->texpaintslot != NULL) {
+ CALLBACK_INVOKE(material->texpaintslot->ima, IDWALK_CB_NOP);
+ }
+ if (material->gp_style != NULL) {
+ CALLBACK_INVOKE(material->gp_style->sima, IDWALK_CB_USER);
+ CALLBACK_INVOKE(material->gp_style->ima, IDWALK_CB_USER);
+ }
+ break;
+ }
+
+ case ID_TE: {
+ Tex *texture = (Tex *)id;
+ if (texture->nodetree) {
+ /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ library_foreach_ID_as_subdata_link(
+ (ID **)&texture->nodetree, callback, user_data, flag, &data);
+ }
+ CALLBACK_INVOKE(texture->ima, IDWALK_CB_USER);
+ break;
+ }
+
+ case ID_LT: {
+ Lattice *lattice = (Lattice *)id;
+ CALLBACK_INVOKE(lattice->key, IDWALK_CB_USER);
+ break;
+ }
+
+ case ID_LA: {
+ Light *lamp = (Light *)id;
+ if (lamp->nodetree) {
+ /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ library_foreach_ID_as_subdata_link(
+ (ID **)&lamp->nodetree, callback, user_data, flag, &data);
+ }
+ break;
+ }
+
+ case ID_CA: {
+ Camera *camera = (Camera *)id;
+ CALLBACK_INVOKE(camera->dof_ob, IDWALK_CB_NOP);
+ for (CameraBGImage *bgpic = camera->bg_images.first; bgpic; bgpic = bgpic->next) {
+ if (bgpic->source == CAM_BGIMG_SOURCE_IMAGE) {
+ CALLBACK_INVOKE(bgpic->ima, IDWALK_CB_USER);
+ }
+ else if (bgpic->source == CAM_BGIMG_SOURCE_MOVIE) {
+ CALLBACK_INVOKE(bgpic->clip, IDWALK_CB_USER);
+ }
+ }
+
+ break;
+ }
+
+ case ID_KE: {
+ Key *key = (Key *)id;
+ CALLBACK_INVOKE_ID(key->from, IDWALK_CB_LOOPBACK);
+ break;
+ }
+
+ case ID_WO: {
+ World *world = (World *)id;
+ if (world->nodetree) {
+ /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ library_foreach_ID_as_subdata_link(
+ (ID **)&world->nodetree, callback, user_data, flag, &data);
+ }
+ break;
+ }
+
+ case ID_SPK: {
+ Speaker *speaker = (Speaker *)id;
+ CALLBACK_INVOKE(speaker->sound, IDWALK_CB_USER);
+ break;
+ }
+
+ case ID_LP: {
+ LightProbe *probe = (LightProbe *)id;
+ CALLBACK_INVOKE(probe->image, IDWALK_CB_USER);
+ CALLBACK_INVOKE(probe->visibility_grp, IDWALK_CB_NOP);
+ break;
+ }
+
+ case ID_GR: {
+ Collection *collection = (Collection *)id;
+ for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ CALLBACK_INVOKE(cob->ob, IDWALK_CB_USER);
+ }
+ for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ CALLBACK_INVOKE(child->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_USER);
+ }
+ for (CollectionParent *parent = collection->parents.first; parent; parent = parent->next) {
+ CALLBACK_INVOKE(parent->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_LOOPBACK);
+ }
+ break;
+ }
+
+ case ID_NT: {
+ bNodeTree *ntree = (bNodeTree *)id;
+ bNode *node;
+ bNodeSocket *sock;
+
+ CALLBACK_INVOKE(ntree->gpd, IDWALK_CB_USER);
+
+ for (node = ntree->nodes.first; node; node = node->next) {
+ CALLBACK_INVOKE_ID(node->id, IDWALK_CB_USER);
+
+ library_foreach_idproperty_ID_link(&data, node->prop, IDWALK_CB_USER);
+ for (sock = node->inputs.first; sock; sock = sock->next) {
+ library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER);
+ }
+ for (sock = node->outputs.first; sock; sock = sock->next) {
+ library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER);
+ }
+ }
+
+ for (sock = ntree->inputs.first; sock; sock = sock->next) {
+ library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER);
+ }
+ for (sock = ntree->outputs.first; sock; sock = sock->next) {
+ library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER);
+ }
+ break;
+ }
+
+ case ID_BR: {
+ Brush *brush = (Brush *)id;
+ CALLBACK_INVOKE(brush->toggle_brush, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(brush->clone.image, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(brush->paint_curve, IDWALK_CB_USER);
+ if (brush->gpencil_settings) {
+ CALLBACK_INVOKE(brush->gpencil_settings->material, IDWALK_CB_USER);
+ }
+ library_foreach_mtex(&data, &brush->mtex);
+ library_foreach_mtex(&data, &brush->mask_mtex);
+ break;
+ }
+
+ case ID_PA: {
+ ParticleSettings *psett = (ParticleSettings *)id;
+ CALLBACK_INVOKE(psett->instance_collection, IDWALK_CB_USER);
+ CALLBACK_INVOKE(psett->instance_object, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(psett->bb_ob, IDWALK_CB_NOP);
+ CALLBACK_INVOKE(psett->collision_group, IDWALK_CB_NOP);
+
+ for (i = 0; i < MAX_MTEX; i++) {
+ if (psett->mtex[i]) {
+ library_foreach_mtex(&data, psett->mtex[i]);
+ }
+ }
+
+ if (psett->effector_weights) {
+ CALLBACK_INVOKE(psett->effector_weights->group, IDWALK_CB_NOP);
+ }
+
+ if (psett->pd) {
+ CALLBACK_INVOKE(psett->pd->tex, IDWALK_CB_USER);
+ CALLBACK_INVOKE(psett->pd->f_source, IDWALK_CB_NOP);
+ }
+ if (psett->pd2) {
+ CALLBACK_INVOKE(psett->pd2->tex, IDWALK_CB_USER);
+ CALLBACK_INVOKE(psett->pd2->f_source, IDWALK_CB_NOP);
+ }
+
+ if (psett->boids) {
+ BoidState *state;
+ BoidRule *rule;
+
+ for (state = psett->boids->states.first; state; state = state->next) {
+ for (rule = state->rules.first; rule; rule = rule->next) {
+ if (rule->type == eBoidRuleType_Avoid) {
+ BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid *)rule;
+ CALLBACK_INVOKE(gabr->ob, IDWALK_CB_NOP);
+ }
+ else if (rule->type == eBoidRuleType_FollowLeader) {
+ BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader *)rule;
+ CALLBACK_INVOKE(flbr->ob, IDWALK_CB_NOP);
+ }
+ }
+ }
+ }
+
+ for (ParticleDupliWeight *dw = psett->instance_weights.first; dw; dw = dw->next) {
+ CALLBACK_INVOKE(dw->ob, IDWALK_CB_NOP);
+ }
+ break;
+ }
+
+ case ID_MC: {
+ MovieClip *clip = (MovieClip *)id;
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingObject *object;
+ MovieTrackingTrack *track;
+ MovieTrackingPlaneTrack *plane_track;
+
+ CALLBACK_INVOKE(clip->gpd, IDWALK_CB_USER);
+
+ for (track = tracking->tracks.first; track; track = track->next) {
+ CALLBACK_INVOKE(track->gpd, IDWALK_CB_USER);
+ }
+ for (object = tracking->objects.first; object; object = object->next) {
+ for (track = object->tracks.first; track; track = track->next) {
+ CALLBACK_INVOKE(track->gpd, IDWALK_CB_USER);
+ }
+ }
+
+ for (plane_track = tracking->plane_tracks.first; plane_track;
+ plane_track = plane_track->next) {
+ CALLBACK_INVOKE(plane_track->image, IDWALK_CB_USER);
+ }
+ break;
+ }
+
+ case ID_MSK: {
+ Mask *mask = (Mask *)id;
+ MaskLayer *mask_layer;
+ for (mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ MaskSpline *mask_spline;
+
+ for (mask_spline = mask_layer->splines.first; mask_spline;
+ mask_spline = mask_spline->next) {
+ for (i = 0; i < mask_spline->tot_point; i++) {
+ MaskSplinePoint *point = &mask_spline->points[i];
+ CALLBACK_INVOKE_ID(point->parent.id, IDWALK_CB_USER);
+ }
+ }
+ }
+ break;
+ }
+
+ case ID_LS: {
+ FreestyleLineStyle *linestyle = (FreestyleLineStyle *)id;
+ LineStyleModifier *lsm;
+ for (i = 0; i < MAX_MTEX; i++) {
+ if (linestyle->mtex[i]) {
+ library_foreach_mtex(&data, linestyle->mtex[i]);
+ }
+ }
+ if (linestyle->nodetree) {
+ /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ library_foreach_ID_as_subdata_link(
+ (ID **)&linestyle->nodetree, callback, user_data, flag, &data);
+ }
+
+ for (lsm = linestyle->color_modifiers.first; lsm; lsm = lsm->next) {
+ if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
+ LineStyleColorModifier_DistanceFromObject *p =
+ (LineStyleColorModifier_DistanceFromObject *)lsm;
+ if (p->target) {
+ CALLBACK_INVOKE(p->target, IDWALK_CB_NOP);
+ }
+ }
+ }
+ for (lsm = linestyle->alpha_modifiers.first; lsm; lsm = lsm->next) {
+ if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
+ LineStyleAlphaModifier_DistanceFromObject *p =
+ (LineStyleAlphaModifier_DistanceFromObject *)lsm;
+ if (p->target) {
+ CALLBACK_INVOKE(p->target, IDWALK_CB_NOP);
+ }
+ }
+ }
+ for (lsm = linestyle->thickness_modifiers.first; lsm; lsm = lsm->next) {
+ if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
+ LineStyleThicknessModifier_DistanceFromObject *p =
+ (LineStyleThicknessModifier_DistanceFromObject *)lsm;
+ if (p->target) {
+ CALLBACK_INVOKE(p->target, IDWALK_CB_NOP);
+ }
+ }
+ }
+ break;
+ }
+ case ID_AC: {
+ bAction *act = (bAction *)id;
+
+ for (TimeMarker *marker = act->markers.first; marker; marker = marker->next) {
+ CALLBACK_INVOKE(marker->camera, IDWALK_CB_NOP);
+ }
+ break;
+ }
+
+ case ID_WM: {
+ wmWindowManager *wm = (wmWindowManager *)id;
+
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ ID *workspace = (ID *)BKE_workspace_active_get(win->workspace_hook);
+
+ CALLBACK_INVOKE(win->scene, IDWALK_CB_USER_ONE);
+
+ CALLBACK_INVOKE_ID(workspace, IDWALK_CB_NOP);
+ /* allow callback to set a different workspace */
+ BKE_workspace_active_set(win->workspace_hook, (WorkSpace *)workspace);
+ }
+ break;
+ }
+
+ case ID_WS: {
+ WorkSpace *workspace = (WorkSpace *)id;
+ ListBase *layouts = BKE_workspace_layouts_get(workspace);
+
+ for (WorkSpaceLayout *layout = layouts->first; layout; layout = layout->next) {
+ bScreen *screen = BKE_workspace_layout_screen_get(layout);
+
+ /* CALLBACK_INVOKE expects an actual pointer, not a variable holding the pointer.
+ * However we can't access layout->screen here since we are outside the workspace project. */
+ CALLBACK_INVOKE(screen, IDWALK_CB_USER);
+ /* allow callback to set a different screen */
+ BKE_workspace_layout_screen_set(layout, screen);
+ }
+ break;
+ }
+ case ID_GD: {
+ bGPdata *gpencil = (bGPdata *)id;
+ /* materials */
+ for (i = 0; i < gpencil->totcol; i++) {
+ CALLBACK_INVOKE(gpencil->mat[i], IDWALK_CB_USER);
+ }
+
+ for (bGPDlayer *gplayer = gpencil->layers.first; gplayer != NULL;
+ gplayer = gplayer->next) {
+ CALLBACK_INVOKE(gplayer->parent, IDWALK_CB_NOP);
+ }
+
+ break;
+ }
+
+ /* Nothing needed for those... */
+ case ID_SCR:
+ case ID_IM:
+ case ID_VF:
+ case ID_TXT:
+ case ID_SO:
+ case ID_PAL:
+ case ID_PC:
+ case ID_CF:
+ break;
+
+ /* Deprecated. */
+ case ID_IP:
+ break;
+ }
+ }
FOREACH_FINALIZE:
- if (data.ids_handled) {
- BLI_gset_free(data.ids_handled, NULL);
- BLI_LINKSTACK_FREE(data.ids_todo);
- }
+ if (data.ids_handled) {
+ BLI_gset_free(data.ids_handled, NULL);
+ BLI_LINKSTACK_FREE(data.ids_todo);
+ }
#undef CALLBACK_INVOKE_ID
#undef CALLBACK_INVOKE
@@ -1055,9 +1072,10 @@ FOREACH_FINALIZE:
/**
* Loop over all of the ID's this datablock links to.
*/
-void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback callback, void *user_data, int flag)
+void BKE_library_foreach_ID_link(
+ Main *bmain, ID *id, LibraryIDLinkCallback callback, void *user_data, int flag)
{
- library_foreach_ID_link(bmain, id, callback, user_data, flag, NULL);
+ library_foreach_ID_link(bmain, id, callback, user_data, flag, NULL);
}
/**
@@ -1065,13 +1083,13 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
*/
void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cb_flag)
{
- if (cb_flag & IDWALK_CB_USER) {
- id_us_min(id_src);
- id_us_plus(id_dst);
- }
- else if (cb_flag & IDWALK_CB_USER_ONE) {
- id_us_ensure_real(id_dst);
- }
+ if (cb_flag & IDWALK_CB_USER) {
+ id_us_min(id_src);
+ id_us_plus(id_dst);
+ }
+ else if (cb_flag & IDWALK_CB_USER_ONE) {
+ id_us_ensure_real(id_dst);
+ }
}
/**
@@ -1084,140 +1102,159 @@ void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cb_flag)
* IDProps will support ID pointers), we'll have to do some quick checks on IDs themselves... */
bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
{
- /* any type of ID can be used in custom props. */
- if (id_owner->properties) {
- return true;
- }
-
- const short id_type_owner = GS(id_owner->name);
-
- /* IDProps of armature bones and nodes, and bNode->id can use virtually any type of ID. */
- if (ELEM(id_type_owner, ID_NT, ID_AR)) {
- return true;
- }
-
- if (ntreeFromID(id_owner)) {
- return true;
- }
-
- if (BKE_animdata_from_id(id_owner)) {
- return true; /* AnimationData can use virtually any kind of datablocks, through drivers especially. */
- }
-
- switch ((ID_Type)id_type_owner) {
- case ID_LI:
- return ELEM(id_type_used, ID_LI);
- case ID_SCE:
- return (ELEM(id_type_used, ID_OB, ID_WO, ID_SCE, ID_MC, ID_MA, ID_GR, ID_TXT,
- ID_LS, ID_MSK, ID_SO, ID_GD, ID_BR, ID_PAL, ID_IM, ID_NT));
- case ID_OB:
- /* Could be more specific, but simpler to just always say 'yes' here. */
- return true;
- case ID_ME:
- return ELEM(id_type_used, ID_ME, ID_KE, ID_MA, ID_IM);
- case ID_CU:
- return ELEM(id_type_used, ID_OB, ID_KE, ID_MA, ID_VF);
- case ID_MB:
- return ELEM(id_type_used, ID_MA);
- case ID_MA:
- return (ELEM(id_type_used, ID_TE, ID_GR));
- case ID_TE:
- return (ELEM(id_type_used, ID_IM, ID_OB));
- case ID_LT:
- return ELEM(id_type_used, ID_KE);
- case ID_LA:
- return (ELEM(id_type_used, ID_TE));
- case ID_CA:
- return ELEM(id_type_used, ID_OB);
- case ID_KE:
- return ELEM(id_type_used, ID_ME, ID_CU, ID_LT); /* Warning! key->from, could be more types in future? */
- case ID_SCR:
- return ELEM(id_type_used, ID_SCE);
- case ID_WO:
- return (ELEM(id_type_used, ID_TE));
- case ID_SPK:
- return ELEM(id_type_used, ID_SO);
- case ID_GR:
- return ELEM(id_type_used, ID_OB, ID_GR);
- case ID_NT:
- /* Could be more specific, but node.id has no type restriction... */
- return true;
- case ID_BR:
- return ELEM(id_type_used, ID_BR, ID_IM, ID_PC, ID_TE, ID_MA);
- case ID_PA:
- return ELEM(id_type_used, ID_OB, ID_GR, ID_TE);
- case ID_MC:
- return ELEM(id_type_used, ID_GD, ID_IM);
- case ID_MSK:
- return ELEM(id_type_used, ID_MC); /* WARNING! mask->parent.id, not typed. */
- case ID_LS:
- return (ELEM(id_type_used, ID_TE, ID_OB));
- case ID_LP:
- return ELEM(id_type_used, ID_IM);
- case ID_GD:
- return ELEM(id_type_used, ID_MA);
- case ID_WS:
- return ELEM(id_type_used, ID_SCR, ID_SCE);
- case ID_IM:
- case ID_VF:
- case ID_TXT:
- case ID_SO:
- case ID_AR:
- case ID_AC:
- case ID_WM:
- case ID_PAL:
- case ID_PC:
- case ID_CF:
- /* Those types never use/reference other IDs... */
- return false;
- case ID_IP:
- /* Deprecated... */
- return false;
- }
- return false;
+ /* any type of ID can be used in custom props. */
+ if (id_owner->properties) {
+ return true;
+ }
+
+ const short id_type_owner = GS(id_owner->name);
+
+ /* IDProps of armature bones and nodes, and bNode->id can use virtually any type of ID. */
+ if (ELEM(id_type_owner, ID_NT, ID_AR)) {
+ return true;
+ }
+
+ if (ntreeFromID(id_owner)) {
+ return true;
+ }
+
+ if (BKE_animdata_from_id(id_owner)) {
+ return true; /* AnimationData can use virtually any kind of datablocks, through drivers especially. */
+ }
+
+ switch ((ID_Type)id_type_owner) {
+ case ID_LI:
+ return ELEM(id_type_used, ID_LI);
+ case ID_SCE:
+ return (ELEM(id_type_used,
+ ID_OB,
+ ID_WO,
+ ID_SCE,
+ ID_MC,
+ ID_MA,
+ ID_GR,
+ ID_TXT,
+ ID_LS,
+ ID_MSK,
+ ID_SO,
+ ID_GD,
+ ID_BR,
+ ID_PAL,
+ ID_IM,
+ ID_NT));
+ case ID_OB:
+ /* Could be more specific, but simpler to just always say 'yes' here. */
+ return true;
+ case ID_ME:
+ return ELEM(id_type_used, ID_ME, ID_KE, ID_MA, ID_IM);
+ case ID_CU:
+ return ELEM(id_type_used, ID_OB, ID_KE, ID_MA, ID_VF);
+ case ID_MB:
+ return ELEM(id_type_used, ID_MA);
+ case ID_MA:
+ return (ELEM(id_type_used, ID_TE, ID_GR));
+ case ID_TE:
+ return (ELEM(id_type_used, ID_IM, ID_OB));
+ case ID_LT:
+ return ELEM(id_type_used, ID_KE);
+ case ID_LA:
+ return (ELEM(id_type_used, ID_TE));
+ case ID_CA:
+ return ELEM(id_type_used, ID_OB);
+ case ID_KE:
+ return ELEM(id_type_used,
+ ID_ME,
+ ID_CU,
+ ID_LT); /* Warning! key->from, could be more types in future? */
+ case ID_SCR:
+ return ELEM(id_type_used, ID_SCE);
+ case ID_WO:
+ return (ELEM(id_type_used, ID_TE));
+ case ID_SPK:
+ return ELEM(id_type_used, ID_SO);
+ case ID_GR:
+ return ELEM(id_type_used, ID_OB, ID_GR);
+ case ID_NT:
+ /* Could be more specific, but node.id has no type restriction... */
+ return true;
+ case ID_BR:
+ return ELEM(id_type_used, ID_BR, ID_IM, ID_PC, ID_TE, ID_MA);
+ case ID_PA:
+ return ELEM(id_type_used, ID_OB, ID_GR, ID_TE);
+ case ID_MC:
+ return ELEM(id_type_used, ID_GD, ID_IM);
+ case ID_MSK:
+ return ELEM(id_type_used, ID_MC); /* WARNING! mask->parent.id, not typed. */
+ case ID_LS:
+ return (ELEM(id_type_used, ID_TE, ID_OB));
+ case ID_LP:
+ return ELEM(id_type_used, ID_IM);
+ case ID_GD:
+ return ELEM(id_type_used, ID_MA);
+ case ID_WS:
+ return ELEM(id_type_used, ID_SCR, ID_SCE);
+ case ID_IM:
+ case ID_VF:
+ case ID_TXT:
+ case ID_SO:
+ case ID_AR:
+ case ID_AC:
+ case ID_WM:
+ case ID_PAL:
+ case ID_PC:
+ case ID_CF:
+ /* Those types never use/reference other IDs... */
+ return false;
+ case ID_IP:
+ /* Deprecated... */
+ return false;
+ }
+ return false;
}
-
/* ***** ID users iterator. ***** */
typedef struct IDUsersIter {
- ID *id;
+ ID *id;
- ListBase *lb_array[MAX_LIBARRAY];
- int lb_idx;
+ ListBase *lb_array[MAX_LIBARRAY];
+ int lb_idx;
- ID *curr_id;
- int count_direct, count_indirect; /* Set by callback. */
+ ID *curr_id;
+ int count_direct, count_indirect; /* Set by callback. */
} IDUsersIter;
-static int foreach_libblock_id_users_callback(void *user_data, ID *UNUSED(self_id), ID **id_p, int cb_flag)
+static int foreach_libblock_id_users_callback(void *user_data,
+ ID *UNUSED(self_id),
+ ID **id_p,
+ int cb_flag)
{
- IDUsersIter *iter = user_data;
+ IDUsersIter *iter = user_data;
- if (*id_p) {
- /* 'Loopback' ID pointers (the ugly 'from' ones, Object->proxy_from and Key->from).
- * Those are not actually ID usage, we can ignore them here.
- */
- if (cb_flag & IDWALK_CB_LOOPBACK) {
- return IDWALK_RET_NOP;
- }
+ if (*id_p) {
+ /* 'Loopback' ID pointers (the ugly 'from' ones, Object->proxy_from and Key->from).
+ * Those are not actually ID usage, we can ignore them here.
+ */
+ if (cb_flag & IDWALK_CB_LOOPBACK) {
+ return IDWALK_RET_NOP;
+ }
- if (*id_p == iter->id) {
+ if (*id_p == iter->id) {
#if 0
- printf("%s uses %s (refcounted: %d, userone: %d, used_one: %d, used_one_active: %d, indirect_usage: %d)\n",
- iter->curr_id->name, iter->id->name, (cb_flag & IDWALK_USER) ? 1 : 0, (cb_flag & IDWALK_USER_ONE) ? 1 : 0,
- (iter->id->tag & LIB_TAG_EXTRAUSER) ? 1 : 0, (iter->id->tag & LIB_TAG_EXTRAUSER_SET) ? 1 : 0,
- (cb_flag & IDWALK_INDIRECT_USAGE) ? 1 : 0);
+ printf("%s uses %s (refcounted: %d, userone: %d, used_one: %d, used_one_active: %d, indirect_usage: %d)\n",
+ iter->curr_id->name, iter->id->name, (cb_flag & IDWALK_USER) ? 1 : 0, (cb_flag & IDWALK_USER_ONE) ? 1 : 0,
+ (iter->id->tag & LIB_TAG_EXTRAUSER) ? 1 : 0, (iter->id->tag & LIB_TAG_EXTRAUSER_SET) ? 1 : 0,
+ (cb_flag & IDWALK_INDIRECT_USAGE) ? 1 : 0);
#endif
- if (cb_flag & IDWALK_CB_INDIRECT_USAGE) {
- iter->count_indirect++;
- }
- else {
- iter->count_direct++;
- }
- }
- }
-
- return IDWALK_RET_NOP;
+ if (cb_flag & IDWALK_CB_INDIRECT_USAGE) {
+ iter->count_indirect++;
+ }
+ else {
+ iter->count_direct++;
+ }
+ }
+ }
+
+ return IDWALK_RET_NOP;
}
/**
@@ -1232,49 +1269,50 @@ static int foreach_libblock_id_users_callback(void *user_data, ID *UNUSED(self_i
*/
int BKE_library_ID_use_ID(ID *id_user, ID *id_used)
{
- IDUsersIter iter;
+ IDUsersIter iter;
- /* We do not care about iter.lb_array/lb_idx here... */
- iter.id = id_used;
- iter.curr_id = id_user;
- iter.count_direct = iter.count_indirect = 0;
+ /* We do not care about iter.lb_array/lb_idx here... */
+ iter.id = id_used;
+ iter.curr_id = id_user;
+ iter.count_direct = iter.count_indirect = 0;
- BKE_library_foreach_ID_link(NULL, iter.curr_id, foreach_libblock_id_users_callback, (void *)&iter, IDWALK_READONLY);
+ BKE_library_foreach_ID_link(
+ NULL, iter.curr_id, foreach_libblock_id_users_callback, (void *)&iter, IDWALK_READONLY);
- return iter.count_direct + iter.count_indirect;
+ return iter.count_direct + iter.count_indirect;
}
static bool library_ID_is_used(Main *bmain, void *idv, const bool check_linked)
{
- IDUsersIter iter;
- ListBase *lb_array[MAX_LIBARRAY];
- ID *id = idv;
- int i = set_listbasepointers(bmain, lb_array);
- bool is_defined = false;
-
- iter.id = id;
- iter.count_direct = iter.count_indirect = 0;
- while (i-- && !is_defined) {
- ID *id_curr = lb_array[i]->first;
-
- if (!id_curr || !BKE_library_id_can_use_idtype(id_curr, GS(id->name))) {
- continue;
- }
-
- for (; id_curr && !is_defined; id_curr = id_curr->next) {
- if (id_curr == id) {
- /* We are not interested in self-usages (mostly from drivers or bone constraints...). */
- continue;
- }
- iter.curr_id = id_curr;
- BKE_library_foreach_ID_link(
- bmain, id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_READONLY);
-
- is_defined = ((check_linked ? iter.count_indirect : iter.count_direct) != 0);
- }
- }
-
- return is_defined;
+ IDUsersIter iter;
+ ListBase *lb_array[MAX_LIBARRAY];
+ ID *id = idv;
+ int i = set_listbasepointers(bmain, lb_array);
+ bool is_defined = false;
+
+ iter.id = id;
+ iter.count_direct = iter.count_indirect = 0;
+ while (i-- && !is_defined) {
+ ID *id_curr = lb_array[i]->first;
+
+ if (!id_curr || !BKE_library_id_can_use_idtype(id_curr, GS(id->name))) {
+ continue;
+ }
+
+ for (; id_curr && !is_defined; id_curr = id_curr->next) {
+ if (id_curr == id) {
+ /* We are not interested in self-usages (mostly from drivers or bone constraints...). */
+ continue;
+ }
+ iter.curr_id = id_curr;
+ BKE_library_foreach_ID_link(
+ bmain, id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_READONLY);
+
+ is_defined = ((check_linked ? iter.count_indirect : iter.count_direct) != 0);
+ }
+ }
+
+ return is_defined;
}
/**
@@ -1282,7 +1320,7 @@ static bool library_ID_is_used(Main *bmain, void *idv, const bool check_linked)
*/
bool BKE_library_ID_is_locally_used(Main *bmain, void *idv)
{
- return library_ID_is_used(bmain, idv, false);
+ return library_ID_is_used(bmain, idv, false);
}
/**
@@ -1290,7 +1328,7 @@ bool BKE_library_ID_is_locally_used(Main *bmain, void *idv)
*/
bool BKE_library_ID_is_indirectly_used(Main *bmain, void *idv)
{
- return library_ID_is_used(bmain, idv, true);
+ return library_ID_is_used(bmain, idv, true);
}
/**
@@ -1298,58 +1336,61 @@ bool BKE_library_ID_is_indirectly_used(Main *bmain, void *idv)
*/
void BKE_library_ID_test_usages(Main *bmain, void *idv, bool *is_used_local, bool *is_used_linked)
{
- IDUsersIter iter;
- ListBase *lb_array[MAX_LIBARRAY];
- ID *id = idv;
- int i = set_listbasepointers(bmain, lb_array);
- bool is_defined = false;
-
- iter.id = id;
- iter.count_direct = iter.count_indirect = 0;
- while (i-- && !is_defined) {
- ID *id_curr = lb_array[i]->first;
-
- if (!id_curr || !BKE_library_id_can_use_idtype(id_curr, GS(id->name))) {
- continue;
- }
-
- for (; id_curr && !is_defined; id_curr = id_curr->next) {
- if (id_curr == id) {
- /* We are not interested in self-usages (mostly from drivers or bone constraints...). */
- continue;
- }
- iter.curr_id = id_curr;
- BKE_library_foreach_ID_link(bmain, id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_READONLY);
-
- is_defined = (iter.count_direct != 0 && iter.count_indirect != 0);
- }
- }
-
- *is_used_local = (iter.count_direct != 0);
- *is_used_linked = (iter.count_indirect != 0);
+ IDUsersIter iter;
+ ListBase *lb_array[MAX_LIBARRAY];
+ ID *id = idv;
+ int i = set_listbasepointers(bmain, lb_array);
+ bool is_defined = false;
+
+ iter.id = id;
+ iter.count_direct = iter.count_indirect = 0;
+ while (i-- && !is_defined) {
+ ID *id_curr = lb_array[i]->first;
+
+ if (!id_curr || !BKE_library_id_can_use_idtype(id_curr, GS(id->name))) {
+ continue;
+ }
+
+ for (; id_curr && !is_defined; id_curr = id_curr->next) {
+ if (id_curr == id) {
+ /* We are not interested in self-usages (mostly from drivers or bone constraints...). */
+ continue;
+ }
+ iter.curr_id = id_curr;
+ BKE_library_foreach_ID_link(
+ bmain, id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_READONLY);
+
+ is_defined = (iter.count_direct != 0 && iter.count_indirect != 0);
+ }
+ }
+
+ *is_used_local = (iter.count_direct != 0);
+ *is_used_linked = (iter.count_indirect != 0);
}
/* ***** IDs usages.checking/tagging. ***** */
-static int foreach_libblock_used_linked_data_tag_clear_cb(
- void *user_data, ID *self_id, ID **id_p, int cb_flag)
+static int foreach_libblock_used_linked_data_tag_clear_cb(void *user_data,
+ ID *self_id,
+ ID **id_p,
+ int cb_flag)
{
- bool *is_changed = user_data;
-
- if (*id_p) {
- /* The infamous 'from' pointers (Key.from, Object.proxy_from, ...).
- * those are not actually ID usage, so we ignore them here. */
- if (cb_flag & IDWALK_CB_LOOPBACK) {
- return IDWALK_RET_NOP;
- }
-
- /* If checked id is used by an assumed used ID, then it is also used and not part of any linked archipelago. */
- if (!(self_id->tag & LIB_TAG_DOIT) && ((*id_p)->tag & LIB_TAG_DOIT)) {
- (*id_p)->tag &= ~LIB_TAG_DOIT;
- *is_changed = true;
- }
- }
-
- return IDWALK_RET_NOP;
+ bool *is_changed = user_data;
+
+ if (*id_p) {
+ /* The infamous 'from' pointers (Key.from, Object.proxy_from, ...).
+ * those are not actually ID usage, so we ignore them here. */
+ if (cb_flag & IDWALK_CB_LOOPBACK) {
+ return IDWALK_RET_NOP;
+ }
+
+ /* If checked id is used by an assumed used ID, then it is also used and not part of any linked archipelago. */
+ if (!(self_id->tag & LIB_TAG_DOIT) && ((*id_p)->tag & LIB_TAG_DOIT)) {
+ (*id_p)->tag &= ~LIB_TAG_DOIT;
+ *is_changed = true;
+ }
+ }
+
+ return IDWALK_RET_NOP;
}
/**
@@ -1362,33 +1403,33 @@ static int foreach_libblock_used_linked_data_tag_clear_cb(
*/
void BKE_library_unused_linked_data_set_tag(Main *bmain, const bool do_init_tag)
{
- ID *id;
-
- if (do_init_tag) {
- FOREACH_MAIN_ID_BEGIN(bmain, id)
- {
- if (id->lib && (id->tag & LIB_TAG_INDIRECT) != 0) {
- id->tag |= LIB_TAG_DOIT;
- }
- else {
- id->tag &= ~LIB_TAG_DOIT;
- }
- }
- FOREACH_MAIN_ID_END;
- }
-
- for (bool do_loop = true; do_loop; ) {
- do_loop = false;
- FOREACH_MAIN_ID_BEGIN(bmain, id)
- {
- /* We only want to check that ID if it is currently known as used... */
- if ((id->tag & LIB_TAG_DOIT) == 0) {
- BKE_library_foreach_ID_link(
- bmain, id, foreach_libblock_used_linked_data_tag_clear_cb, &do_loop, IDWALK_READONLY);
- }
- }
- FOREACH_MAIN_ID_END;
- }
+ ID *id;
+
+ if (do_init_tag) {
+ FOREACH_MAIN_ID_BEGIN(bmain, id)
+ {
+ if (id->lib && (id->tag & LIB_TAG_INDIRECT) != 0) {
+ id->tag |= LIB_TAG_DOIT;
+ }
+ else {
+ id->tag &= ~LIB_TAG_DOIT;
+ }
+ }
+ FOREACH_MAIN_ID_END;
+ }
+
+ for (bool do_loop = true; do_loop;) {
+ do_loop = false;
+ FOREACH_MAIN_ID_BEGIN(bmain, id)
+ {
+ /* We only want to check that ID if it is currently known as used... */
+ if ((id->tag & LIB_TAG_DOIT) == 0) {
+ BKE_library_foreach_ID_link(
+ bmain, id, foreach_libblock_used_linked_data_tag_clear_cb, &do_loop, IDWALK_READONLY);
+ }
+ }
+ FOREACH_MAIN_ID_END;
+ }
}
/**
@@ -1399,22 +1440,22 @@ void BKE_library_unused_linked_data_set_tag(Main *bmain, const bool do_init_tag)
*/
void BKE_library_indirectly_used_data_tag_clear(Main *bmain)
{
- ListBase *lb_array[MAX_LIBARRAY];
-
- bool do_loop = true;
- while (do_loop) {
- int i = set_listbasepointers(bmain, lb_array);
- do_loop = false;
-
- while (i--) {
- for (ID *id = lb_array[i]->first; id; id = id->next) {
- if (id->lib == NULL || id->tag & LIB_TAG_DOIT) {
- /* Local or non-indirectly-used ID (so far), no need to check it further. */
- continue;
- }
- BKE_library_foreach_ID_link(
- bmain, id, foreach_libblock_used_linked_data_tag_clear_cb, &do_loop, IDWALK_READONLY);
- }
- }
- }
+ ListBase *lb_array[MAX_LIBARRAY];
+
+ bool do_loop = true;
+ while (do_loop) {
+ int i = set_listbasepointers(bmain, lb_array);
+ do_loop = false;
+
+ while (i--) {
+ for (ID *id = lb_array[i]->first; id; id = id->next) {
+ if (id->lib == NULL || id->tag & LIB_TAG_DOIT) {
+ /* Local or non-indirectly-used ID (so far), no need to check it further. */
+ continue;
+ }
+ BKE_library_foreach_ID_link(
+ bmain, id, foreach_libblock_used_linked_data_tag_clear_cb, &do_loop, IDWALK_READONLY);
+ }
+ }
+ }
}
diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c
index 1f46286b831..9b6de945db8 100644
--- a/source/blender/blenkernel/intern/library_remap.c
+++ b/source/blender/blenkernel/intern/library_remap.c
@@ -114,7 +114,7 @@
#include "DEG_depsgraph_build.h"
#ifdef WITH_PYTHON
-#include "BPY_extern.h"
+# include "BPY_extern.h"
#endif
static CLG_LogRef LOG = {"bke.library_remap"};
@@ -123,263 +123,275 @@ static BKE_library_free_window_manager_cb free_windowmanager_cb = NULL;
void BKE_library_callback_free_window_manager_set(BKE_library_free_window_manager_cb func)
{
- free_windowmanager_cb = func;
+ free_windowmanager_cb = func;
}
static BKE_library_free_notifier_reference_cb free_notifier_reference_cb = NULL;
void BKE_library_callback_free_notifier_reference_set(BKE_library_free_notifier_reference_cb func)
{
- free_notifier_reference_cb = func;
+ free_notifier_reference_cb = func;
}
static BKE_library_remap_editor_id_reference_cb remap_editor_id_reference_cb = NULL;
-void BKE_library_callback_remap_editor_id_reference_set(BKE_library_remap_editor_id_reference_cb func)
+void BKE_library_callback_remap_editor_id_reference_set(
+ BKE_library_remap_editor_id_reference_cb func)
{
- remap_editor_id_reference_cb = func;
+ remap_editor_id_reference_cb = func;
}
typedef struct IDRemap {
- Main *bmain; /* Only used to trigger depsgraph updates in the right bmain. */
- ID *old_id;
- ID *new_id;
- ID *id; /* The ID in which we are replacing old_id by new_id usages. */
- short flag;
-
- /* 'Output' data. */
- short status;
- int skipped_direct; /* Number of direct usecases that could not be remapped (e.g.: obdata when in edit mode). */
- int skipped_indirect; /* Number of indirect usecases that could not be remapped. */
- int skipped_refcounted; /* Number of skipped usecases that refcount the datablock. */
+ Main *bmain; /* Only used to trigger depsgraph updates in the right bmain. */
+ ID *old_id;
+ ID *new_id;
+ ID *id; /* The ID in which we are replacing old_id by new_id usages. */
+ short flag;
+
+ /* 'Output' data. */
+ short status;
+ int skipped_direct; /* Number of direct usecases that could not be remapped (e.g.: obdata when in edit mode). */
+ int skipped_indirect; /* Number of indirect usecases that could not be remapped. */
+ int skipped_refcounted; /* Number of skipped usecases that refcount the datablock. */
} IDRemap;
/* IDRemap->flag enums defined in BKE_library.h */
/* IDRemap->status */
enum {
- /* *** Set by callback. *** */
- ID_REMAP_IS_LINKED_DIRECT = 1 << 0, /* new_id is directly linked in current .blend. */
- ID_REMAP_IS_USER_ONE_SKIPPED = 1 << 1, /* There was some skipped 'user_one' usages of old_id. */
+ /* *** Set by callback. *** */
+ ID_REMAP_IS_LINKED_DIRECT = 1 << 0, /* new_id is directly linked in current .blend. */
+ ID_REMAP_IS_USER_ONE_SKIPPED = 1 << 1, /* There was some skipped 'user_one' usages of old_id. */
};
static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id_p, int cb_flag)
{
- if (cb_flag & IDWALK_CB_PRIVATE) {
- return IDWALK_RET_NOP;
- }
-
- IDRemap *id_remap_data = user_data;
- ID *old_id = id_remap_data->old_id;
- ID *new_id = id_remap_data->new_id;
- ID *id = id_remap_data->id;
-
- if (!old_id) { /* Used to cleanup all IDs used by a specific one. */
- BLI_assert(!new_id);
- old_id = *id_p;
- }
-
- if (*id_p && (*id_p == old_id)) {
- /* Better remap to NULL than not remapping at all, then we can handle it as a regular remap-to-NULL case... */
- if ((cb_flag & IDWALK_CB_NEVER_SELF) && (new_id == id_self)) {
- new_id = NULL;
- }
-
- const bool is_reference = (cb_flag & IDWALK_CB_STATIC_OVERRIDE_REFERENCE) != 0;
- const bool is_indirect = (cb_flag & IDWALK_CB_INDIRECT_USAGE) != 0;
- const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0;
- /* Note: proxy usage implies LIB_TAG_EXTERN, so on this aspect it is direct,
- * on the other hand since they get reset to lib data on file open/reload it is indirect too...
- * Edit Mode is also a 'skip direct' case. */
- const bool is_obj = (GS(id->name) == ID_OB);
- const bool is_obj_proxy = (is_obj && (((Object *)id)->proxy || ((Object *)id)->proxy_group));
- const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id));
- const bool is_never_null = ((cb_flag & IDWALK_CB_NEVER_NULL) &&
- (new_id == NULL) &&
- (id_remap_data->flag & ID_REMAP_FORCE_NEVER_NULL_USAGE) == 0);
- const bool skip_reference = (id_remap_data->flag & ID_REMAP_SKIP_STATIC_OVERRIDE) != 0;
- const bool skip_never_null = (id_remap_data->flag & ID_REMAP_SKIP_NEVER_NULL_USAGE) != 0;
+ if (cb_flag & IDWALK_CB_PRIVATE) {
+ return IDWALK_RET_NOP;
+ }
+
+ IDRemap *id_remap_data = user_data;
+ ID *old_id = id_remap_data->old_id;
+ ID *new_id = id_remap_data->new_id;
+ ID *id = id_remap_data->id;
+
+ if (!old_id) { /* Used to cleanup all IDs used by a specific one. */
+ BLI_assert(!new_id);
+ old_id = *id_p;
+ }
+
+ if (*id_p && (*id_p == old_id)) {
+ /* Better remap to NULL than not remapping at all, then we can handle it as a regular remap-to-NULL case... */
+ if ((cb_flag & IDWALK_CB_NEVER_SELF) && (new_id == id_self)) {
+ new_id = NULL;
+ }
+
+ const bool is_reference = (cb_flag & IDWALK_CB_STATIC_OVERRIDE_REFERENCE) != 0;
+ const bool is_indirect = (cb_flag & IDWALK_CB_INDIRECT_USAGE) != 0;
+ const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0;
+ /* Note: proxy usage implies LIB_TAG_EXTERN, so on this aspect it is direct,
+ * on the other hand since they get reset to lib data on file open/reload it is indirect too...
+ * Edit Mode is also a 'skip direct' case. */
+ const bool is_obj = (GS(id->name) == ID_OB);
+ const bool is_obj_proxy = (is_obj && (((Object *)id)->proxy || ((Object *)id)->proxy_group));
+ const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id));
+ const bool is_never_null = ((cb_flag & IDWALK_CB_NEVER_NULL) && (new_id == NULL) &&
+ (id_remap_data->flag & ID_REMAP_FORCE_NEVER_NULL_USAGE) == 0);
+ const bool skip_reference = (id_remap_data->flag & ID_REMAP_SKIP_STATIC_OVERRIDE) != 0;
+ const bool skip_never_null = (id_remap_data->flag & ID_REMAP_SKIP_NEVER_NULL_USAGE) != 0;
#ifdef DEBUG_PRINT
- printf("In %s (lib %p): Remapping %s (%p) to %s (%p) "
- "(is_indirect: %d, skip_indirect: %d, is_reference: %d, skip_reference: %d)\n",
- id->name, id->lib, old_id->name, old_id, new_id ? new_id->name : "<NONE>", new_id,
- is_indirect, skip_indirect, is_reference, skip_reference);
+ printf(
+ "In %s (lib %p): Remapping %s (%p) to %s (%p) "
+ "(is_indirect: %d, skip_indirect: %d, is_reference: %d, skip_reference: %d)\n",
+ id->name,
+ id->lib,
+ old_id->name,
+ old_id,
+ new_id ? new_id->name : "<NONE>",
+ new_id,
+ is_indirect,
+ skip_indirect,
+ is_reference,
+ skip_reference);
#endif
- if ((id_remap_data->flag & ID_REMAP_FLAG_NEVER_NULL_USAGE) && (cb_flag & IDWALK_CB_NEVER_NULL)) {
- id->tag |= LIB_TAG_DOIT;
- }
-
- /* Special hack in case it's Object->data and we are in edit mode, and new_id is not NULL
- * (otherwise, we follow common NEVER_NULL flags).
- * (skipped_indirect too). */
- if ((is_never_null && skip_never_null) ||
- (is_obj_editmode && (((Object *)id)->data == *id_p) && new_id != NULL) ||
- (skip_indirect && is_indirect) ||
- (is_reference && skip_reference))
- {
- if (is_indirect) {
- id_remap_data->skipped_indirect++;
- if (is_obj) {
- Object *ob = (Object *)id;
- if (ob->data == *id_p && ob->proxy != NULL) {
- /* And another 'Proudly brought to you by Proxy Hell' hack!
- * This will allow us to avoid clearing 'LIB_EXTERN' flag of obdata of proxies... */
- id_remap_data->skipped_direct++;
- }
- }
- }
- else if (is_never_null || is_obj_editmode || is_reference) {
- id_remap_data->skipped_direct++;
- }
- else {
- BLI_assert(0);
- }
- if (cb_flag & IDWALK_CB_USER) {
- id_remap_data->skipped_refcounted++;
- }
- else if (cb_flag & IDWALK_CB_USER_ONE) {
- /* No need to count number of times this happens, just a flag is enough. */
- id_remap_data->status |= ID_REMAP_IS_USER_ONE_SKIPPED;
- }
- }
- else {
- if (!is_never_null) {
- *id_p = new_id;
- DEG_id_tag_update_ex(id_remap_data->bmain, id_self,
- ID_RECALC_COPY_ON_WRITE | ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- }
- if (cb_flag & IDWALK_CB_USER) {
- /* NOTE: We don't user-count IDs which are not in the main database.
- * This is because in certain conditions we can have datablocks in
- * the main which are referencing datablocks outside of it.
- * For example, BKE_mesh_new_from_object() called on an evaluated
- * object will cause such situation.
- */
- if ((old_id->tag & LIB_TAG_NO_MAIN) == 0) {
- id_us_min(old_id);
- }
- if (new_id != NULL && (new_id->tag & LIB_TAG_NO_MAIN) == 0) {
- /* We do not want to handle LIB_TAG_INDIRECT/LIB_TAG_EXTERN here. */
- new_id->us++;
- }
- }
- else if (cb_flag & IDWALK_CB_USER_ONE) {
- id_us_ensure_real(new_id);
- /* We cannot affect old_id->us directly, LIB_TAG_EXTRAUSER(_SET) are assumed to be set as needed,
- * that extra user is processed in final handling... */
- }
- if (!is_indirect || is_obj_proxy) {
- id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT;
- }
- }
- }
-
- return IDWALK_RET_NOP;
+ if ((id_remap_data->flag & ID_REMAP_FLAG_NEVER_NULL_USAGE) &&
+ (cb_flag & IDWALK_CB_NEVER_NULL)) {
+ id->tag |= LIB_TAG_DOIT;
+ }
+
+ /* Special hack in case it's Object->data and we are in edit mode, and new_id is not NULL
+ * (otherwise, we follow common NEVER_NULL flags).
+ * (skipped_indirect too). */
+ if ((is_never_null && skip_never_null) ||
+ (is_obj_editmode && (((Object *)id)->data == *id_p) && new_id != NULL) ||
+ (skip_indirect && is_indirect) || (is_reference && skip_reference)) {
+ if (is_indirect) {
+ id_remap_data->skipped_indirect++;
+ if (is_obj) {
+ Object *ob = (Object *)id;
+ if (ob->data == *id_p && ob->proxy != NULL) {
+ /* And another 'Proudly brought to you by Proxy Hell' hack!
+ * This will allow us to avoid clearing 'LIB_EXTERN' flag of obdata of proxies... */
+ id_remap_data->skipped_direct++;
+ }
+ }
+ }
+ else if (is_never_null || is_obj_editmode || is_reference) {
+ id_remap_data->skipped_direct++;
+ }
+ else {
+ BLI_assert(0);
+ }
+ if (cb_flag & IDWALK_CB_USER) {
+ id_remap_data->skipped_refcounted++;
+ }
+ else if (cb_flag & IDWALK_CB_USER_ONE) {
+ /* No need to count number of times this happens, just a flag is enough. */
+ id_remap_data->status |= ID_REMAP_IS_USER_ONE_SKIPPED;
+ }
+ }
+ else {
+ if (!is_never_null) {
+ *id_p = new_id;
+ DEG_id_tag_update_ex(id_remap_data->bmain,
+ id_self,
+ ID_RECALC_COPY_ON_WRITE | ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ }
+ if (cb_flag & IDWALK_CB_USER) {
+ /* NOTE: We don't user-count IDs which are not in the main database.
+ * This is because in certain conditions we can have datablocks in
+ * the main which are referencing datablocks outside of it.
+ * For example, BKE_mesh_new_from_object() called on an evaluated
+ * object will cause such situation.
+ */
+ if ((old_id->tag & LIB_TAG_NO_MAIN) == 0) {
+ id_us_min(old_id);
+ }
+ if (new_id != NULL && (new_id->tag & LIB_TAG_NO_MAIN) == 0) {
+ /* We do not want to handle LIB_TAG_INDIRECT/LIB_TAG_EXTERN here. */
+ new_id->us++;
+ }
+ }
+ else if (cb_flag & IDWALK_CB_USER_ONE) {
+ id_us_ensure_real(new_id);
+ /* We cannot affect old_id->us directly, LIB_TAG_EXTRAUSER(_SET) are assumed to be set as needed,
+ * that extra user is processed in final handling... */
+ }
+ if (!is_indirect || is_obj_proxy) {
+ id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT;
+ }
+ }
+ }
+
+ return IDWALK_RET_NOP;
}
static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data)
{
- switch (GS(r_id_remap_data->id->name)) {
- case ID_OB:
- {
- ID *old_id = r_id_remap_data->old_id;
- if (!old_id || GS(old_id->name) == ID_AR) {
- Object *ob = (Object *)r_id_remap_data->id;
- /* Object's pose holds reference to armature bones... sic */
- /* Note that in theory, we should have to bother about linked/non-linked/never-null/etc. flags/states.
- * Fortunately, this is just a tag, so we can accept to 'over-tag' a bit for pose recalc, and avoid
- * another complex and risky condition nightmare like the one we have in
- * foreach_libblock_remap_callback()... */
- if (ob->pose && (!old_id || ob->data == old_id)) {
- BLI_assert(ob->type == OB_ARMATURE);
- ob->pose->flag |= POSE_RECALC;
- /* We need to clear pose bone pointers immediately, things like undo writefile may be called
- * before pose is actually recomputed, can lead to segfault... */
- BKE_pose_clear_pointers(ob->pose);
- }
- }
- break;
- }
- default:
- break;
- }
+ switch (GS(r_id_remap_data->id->name)) {
+ case ID_OB: {
+ ID *old_id = r_id_remap_data->old_id;
+ if (!old_id || GS(old_id->name) == ID_AR) {
+ Object *ob = (Object *)r_id_remap_data->id;
+ /* Object's pose holds reference to armature bones... sic */
+ /* Note that in theory, we should have to bother about linked/non-linked/never-null/etc. flags/states.
+ * Fortunately, this is just a tag, so we can accept to 'over-tag' a bit for pose recalc, and avoid
+ * another complex and risky condition nightmare like the one we have in
+ * foreach_libblock_remap_callback()... */
+ if (ob->pose && (!old_id || ob->data == old_id)) {
+ BLI_assert(ob->type == OB_ARMATURE);
+ ob->pose->flag |= POSE_RECALC;
+ /* We need to clear pose bone pointers immediately, things like undo writefile may be called
+ * before pose is actually recomputed, can lead to segfault... */
+ BKE_pose_clear_pointers(ob->pose);
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
}
/* Can be called with both old_ob and new_ob being NULL, this means we have to check whole Main database then. */
-static void libblock_remap_data_postprocess_object_update(Main *bmain, Object *old_ob, Object *new_ob)
+static void libblock_remap_data_postprocess_object_update(Main *bmain,
+ Object *old_ob,
+ Object *new_ob)
{
- if (new_ob == NULL) {
- /* In case we unlinked old_ob (new_ob is NULL), the object has already
- * been removed from the scenes and their collections. We still have
- * to remove the NULL children from collections not used in any scene. */
- BKE_collections_object_remove_nulls(bmain);
- }
-
- BKE_main_collection_sync_remap(bmain);
-
- if (old_ob == NULL) {
- for (Object *ob = bmain->objects.first; ob != NULL; ob = ob->id.next) {
- if (ob->type == OB_MBALL && BKE_mball_is_basis(ob)) {
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- }
- }
- }
- else {
- for (Object *ob = bmain->objects.first; ob != NULL; ob = ob->id.next) {
- if (ob->type == OB_MBALL && BKE_mball_is_basis_for(ob, old_ob)) {
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- break; /* There is only one basis... */
- }
- }
- }
+ if (new_ob == NULL) {
+ /* In case we unlinked old_ob (new_ob is NULL), the object has already
+ * been removed from the scenes and their collections. We still have
+ * to remove the NULL children from collections not used in any scene. */
+ BKE_collections_object_remove_nulls(bmain);
+ }
+
+ BKE_main_collection_sync_remap(bmain);
+
+ if (old_ob == NULL) {
+ for (Object *ob = bmain->objects.first; ob != NULL; ob = ob->id.next) {
+ if (ob->type == OB_MBALL && BKE_mball_is_basis(ob)) {
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
+ }
+ }
+ else {
+ for (Object *ob = bmain->objects.first; ob != NULL; ob = ob->id.next) {
+ if (ob->type == OB_MBALL && BKE_mball_is_basis_for(ob, old_ob)) {
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ break; /* There is only one basis... */
+ }
+ }
+ }
}
/* Can be called with both old_collection and new_collection being NULL,
* this means we have to check whole Main database then. */
-static void libblock_remap_data_postprocess_collection_update(
- Main *bmain, Collection *UNUSED(old_collection), Collection *new_collection)
+static void libblock_remap_data_postprocess_collection_update(Main *bmain,
+ Collection *UNUSED(old_collection),
+ Collection *new_collection)
{
- if (new_collection == NULL) {
- /* XXX Complex cases can lead to NULL pointers in other collections than old_collection,
- * and BKE_main_collection_sync_remap() does not tolerate any of those, so for now always check whole
- * existing collections for NULL pointers.
- * I'd consider optimizing that whole collection remapping process a TODO for later. */
- BKE_collections_child_remove_nulls(bmain, NULL /*old_collection*/);
- }
-
- BKE_main_collection_sync_remap(bmain);
+ if (new_collection == NULL) {
+ /* XXX Complex cases can lead to NULL pointers in other collections than old_collection,
+ * and BKE_main_collection_sync_remap() does not tolerate any of those, so for now always check whole
+ * existing collections for NULL pointers.
+ * I'd consider optimizing that whole collection remapping process a TODO for later. */
+ BKE_collections_child_remove_nulls(bmain, NULL /*old_collection*/);
+ }
+
+ BKE_main_collection_sync_remap(bmain);
}
static void libblock_remap_data_postprocess_obdata_relink(Main *bmain, Object *ob, ID *new_id)
{
- if (ob->data == new_id) {
- switch (GS(new_id->name)) {
- case ID_ME:
- multires_force_update(ob);
- break;
- case ID_CU:
- BKE_curve_type_test(ob);
- break;
- default:
- break;
- }
- test_object_modifiers(ob);
- test_object_materials(bmain, ob, new_id);
- }
+ if (ob->data == new_id) {
+ switch (GS(new_id->name)) {
+ case ID_ME:
+ multires_force_update(ob);
+ break;
+ case ID_CU:
+ BKE_curve_type_test(ob);
+ break;
+ default:
+ break;
+ }
+ test_object_modifiers(ob);
+ test_object_materials(bmain, ob, new_id);
+ }
}
static void libblock_remap_data_postprocess_nodetree_update(Main *bmain, ID *new_id)
{
- /* Verify all nodetree user nodes. */
- ntreeVerifyNodes(bmain, new_id);
-
- /* Update node trees as necessary. */
- FOREACH_NODETREE_BEGIN(bmain, ntree, id) {
- /* make an update call for the tree */
- ntreeUpdateTree(bmain, ntree);
- } FOREACH_NODETREE_END;
+ /* Verify all nodetree user nodes. */
+ ntreeVerifyNodes(bmain, new_id);
+
+ /* Update node trees as necessary. */
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ /* make an update call for the tree */
+ ntreeUpdateTree(bmain, ntree);
+ }
+ FOREACH_NODETREE_END;
}
/**
@@ -400,71 +412,81 @@ static void libblock_remap_data_postprocess_nodetree_update(Main *bmain, ID *new
* \param new_id: the new datablock to replace \a old_id references with (may be NULL).
* \param r_id_remap_data: if non-NULL, the IDRemap struct to use (uselful to retrieve info about remapping process).
*/
-ATTR_NONNULL(1) static void libblock_remap_data(
- Main *bmain, ID *id, ID *old_id, ID *new_id, const short remap_flags, IDRemap *r_id_remap_data)
+ATTR_NONNULL(1)
+static void libblock_remap_data(
+ Main *bmain, ID *id, ID *old_id, ID *new_id, const short remap_flags, IDRemap *r_id_remap_data)
{
- IDRemap id_remap_data;
- const int foreach_id_flags = (remap_flags & ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE) != 0 ? IDWALK_NO_INDIRECT_PROXY_DATA_USAGE : IDWALK_NOP;
-
- if (r_id_remap_data == NULL) {
- r_id_remap_data = &id_remap_data;
- }
- r_id_remap_data->bmain = bmain;
- r_id_remap_data->old_id = old_id;
- r_id_remap_data->new_id = new_id;
- r_id_remap_data->id = NULL;
- r_id_remap_data->flag = remap_flags;
- r_id_remap_data->status = 0;
- r_id_remap_data->skipped_direct = 0;
- r_id_remap_data->skipped_indirect = 0;
- r_id_remap_data->skipped_refcounted = 0;
-
- if (id) {
+ IDRemap id_remap_data;
+ const int foreach_id_flags = (remap_flags & ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE) != 0 ?
+ IDWALK_NO_INDIRECT_PROXY_DATA_USAGE :
+ IDWALK_NOP;
+
+ if (r_id_remap_data == NULL) {
+ r_id_remap_data = &id_remap_data;
+ }
+ r_id_remap_data->bmain = bmain;
+ r_id_remap_data->old_id = old_id;
+ r_id_remap_data->new_id = new_id;
+ r_id_remap_data->id = NULL;
+ r_id_remap_data->flag = remap_flags;
+ r_id_remap_data->status = 0;
+ r_id_remap_data->skipped_direct = 0;
+ r_id_remap_data->skipped_indirect = 0;
+ r_id_remap_data->skipped_refcounted = 0;
+
+ if (id) {
#ifdef DEBUG_PRINT
- printf("\tchecking id %s (%p, %p)\n", id->name, id, id->lib);
+ printf("\tchecking id %s (%p, %p)\n", id->name, id, id->lib);
#endif
- r_id_remap_data->id = id;
- libblock_remap_data_preprocess(r_id_remap_data);
- BKE_library_foreach_ID_link(NULL, id, foreach_libblock_remap_callback, (void *)r_id_remap_data, foreach_id_flags);
- }
- else {
- /* Note that this is a very 'brute force' approach, maybe we could use some depsgraph to only process
- * objects actually using given old_id... sounds rather unlikely currently, though, so this will do for now. */
- ID *id_curr;
-
- FOREACH_MAIN_ID_BEGIN(bmain, id_curr)
- {
- if (BKE_library_id_can_use_idtype(id_curr, GS(old_id->name))) {
- /* Note that we cannot skip indirect usages of old_id here (if requested), we still need to check it for
- * the user count handling...
- * XXX No more true (except for debug usage of those skipping counters). */
- r_id_remap_data->id = id_curr;
- libblock_remap_data_preprocess(r_id_remap_data);
- BKE_library_foreach_ID_link(
- NULL, id_curr, foreach_libblock_remap_callback, (void *)r_id_remap_data, foreach_id_flags);
- }
- }
- FOREACH_MAIN_ID_END;
- }
-
- /* XXX We may not want to always 'transfer' fakeuser from old to new id... Think for now it's desired behavior
- * though, we can always add an option (flag) to control this later if needed. */
- if (old_id && (old_id->flag & LIB_FAKEUSER)) {
- id_fake_user_clear(old_id);
- id_fake_user_set(new_id);
- }
-
- id_us_clear_real(old_id);
-
- if (new_id && (new_id->tag & LIB_TAG_INDIRECT) && (r_id_remap_data->status & ID_REMAP_IS_LINKED_DIRECT)) {
- new_id->tag &= ~LIB_TAG_INDIRECT;
- new_id->tag |= LIB_TAG_EXTERN;
- }
+ r_id_remap_data->id = id;
+ libblock_remap_data_preprocess(r_id_remap_data);
+ BKE_library_foreach_ID_link(
+ NULL, id, foreach_libblock_remap_callback, (void *)r_id_remap_data, foreach_id_flags);
+ }
+ else {
+ /* Note that this is a very 'brute force' approach, maybe we could use some depsgraph to only process
+ * objects actually using given old_id... sounds rather unlikely currently, though, so this will do for now. */
+ ID *id_curr;
+
+ FOREACH_MAIN_ID_BEGIN(bmain, id_curr)
+ {
+ if (BKE_library_id_can_use_idtype(id_curr, GS(old_id->name))) {
+ /* Note that we cannot skip indirect usages of old_id here (if requested), we still need to check it for
+ * the user count handling...
+ * XXX No more true (except for debug usage of those skipping counters). */
+ r_id_remap_data->id = id_curr;
+ libblock_remap_data_preprocess(r_id_remap_data);
+ BKE_library_foreach_ID_link(NULL,
+ id_curr,
+ foreach_libblock_remap_callback,
+ (void *)r_id_remap_data,
+ foreach_id_flags);
+ }
+ }
+ FOREACH_MAIN_ID_END;
+ }
+
+ /* XXX We may not want to always 'transfer' fakeuser from old to new id... Think for now it's desired behavior
+ * though, we can always add an option (flag) to control this later if needed. */
+ if (old_id && (old_id->flag & LIB_FAKEUSER)) {
+ id_fake_user_clear(old_id);
+ id_fake_user_set(new_id);
+ }
+
+ id_us_clear_real(old_id);
+
+ if (new_id && (new_id->tag & LIB_TAG_INDIRECT) &&
+ (r_id_remap_data->status & ID_REMAP_IS_LINKED_DIRECT)) {
+ new_id->tag &= ~LIB_TAG_INDIRECT;
+ new_id->tag |= LIB_TAG_EXTERN;
+ }
#ifdef DEBUG_PRINT
- printf("%s: %d occurrences skipped (%d direct and %d indirect ones)\n", __func__,
- r_id_remap_data->skipped_direct + r_id_remap_data->skipped_indirect,
- r_id_remap_data->skipped_direct, r_id_remap_data->skipped_indirect);
+ printf("%s: %d occurrences skipped (%d direct and %d indirect ones)\n",
+ __func__,
+ r_id_remap_data->skipped_direct + r_id_remap_data->skipped_indirect,
+ r_id_remap_data->skipped_direct,
+ r_id_remap_data->skipped_indirect);
#endif
}
@@ -472,98 +494,103 @@ ATTR_NONNULL(1) static void libblock_remap_data(
* Replace all references in given Main to \a old_id by \a new_id
* (if \a new_id is NULL, it unlinks \a old_id).
*/
-void BKE_libblock_remap_locked(
- Main *bmain, void *old_idv, void *new_idv,
- const short remap_flags)
+void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const short remap_flags)
{
- IDRemap id_remap_data;
- ID *old_id = old_idv;
- ID *new_id = new_idv;
- int skipped_direct, skipped_refcounted;
-
- BLI_assert(old_id != NULL);
- BLI_assert((new_id == NULL) || GS(old_id->name) == GS(new_id->name));
- BLI_assert(old_id != new_id);
-
- libblock_remap_data(bmain, NULL, old_id, new_id, remap_flags, &id_remap_data);
-
- if (free_notifier_reference_cb) {
- free_notifier_reference_cb(old_id);
- }
-
- /* We assume editors do not hold references to their IDs... This is false in some cases
- * (Image is especially tricky here), editors' code is to handle refcount (id->us) itself then. */
- if (remap_editor_id_reference_cb) {
- remap_editor_id_reference_cb(old_id, new_id);
- }
-
- skipped_direct = id_remap_data.skipped_direct;
- skipped_refcounted = id_remap_data.skipped_refcounted;
-
- /* If old_id was used by some ugly 'user_one' stuff (like Image or Clip editors...), and user count has actually
- * been incremented for that, we have to decrease once more its user count... unless we had to skip
- * some 'user_one' cases. */
- if ((old_id->tag & LIB_TAG_EXTRAUSER_SET) && !(id_remap_data.status & ID_REMAP_IS_USER_ONE_SKIPPED)) {
- id_us_clear_real(old_id);
- }
-
- if (old_id->us - skipped_refcounted < 0) {
- CLOG_ERROR(&LOG, "Error in remapping process from '%s' (%p) to '%s' (%p): "
- "wrong user count in old ID after process (summing up to %d)",
- old_id->name, old_id, new_id ? new_id->name : "<NULL>", new_id, old_id->us - skipped_refcounted);
- BLI_assert(0);
- }
-
- if (skipped_direct == 0) {
- /* old_id is assumed to not be used directly anymore... */
- if (old_id->lib && (old_id->tag & LIB_TAG_EXTERN)) {
- old_id->tag &= ~LIB_TAG_EXTERN;
- old_id->tag |= LIB_TAG_INDIRECT;
- }
- }
-
- /* Some after-process updates.
- * This is a bit ugly, but cannot see a way to avoid it. Maybe we should do a per-ID callback for this instead?
- */
- switch (GS(old_id->name)) {
- case ID_OB:
- libblock_remap_data_postprocess_object_update(bmain, (Object *)old_id, (Object *)new_id);
- break;
- case ID_GR:
- libblock_remap_data_postprocess_collection_update(bmain, (Collection *)old_id, (Collection *)new_id);
- break;
- case ID_ME:
- case ID_CU:
- case ID_MB:
- if (new_id) { /* Only affects us in case obdata was relinked (changed). */
- for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
- libblock_remap_data_postprocess_obdata_relink(bmain, ob, new_id);
- }
- }
- break;
- default:
- break;
- }
-
- /* Node trees may virtually use any kind of data-block... */
- /* XXX Yuck!!!! nodetree update can do pretty much any thing when talking about py nodes,
- * including creating new data-blocks (see T50385), so we need to unlock main here. :(
- * Why can't we have re-entrent locks? */
- BKE_main_unlock(bmain);
- libblock_remap_data_postprocess_nodetree_update(bmain, new_id);
- BKE_main_lock(bmain);
-
- /* Full rebuild of DEG! */
- DEG_relations_tag_update(bmain);
+ IDRemap id_remap_data;
+ ID *old_id = old_idv;
+ ID *new_id = new_idv;
+ int skipped_direct, skipped_refcounted;
+
+ BLI_assert(old_id != NULL);
+ BLI_assert((new_id == NULL) || GS(old_id->name) == GS(new_id->name));
+ BLI_assert(old_id != new_id);
+
+ libblock_remap_data(bmain, NULL, old_id, new_id, remap_flags, &id_remap_data);
+
+ if (free_notifier_reference_cb) {
+ free_notifier_reference_cb(old_id);
+ }
+
+ /* We assume editors do not hold references to their IDs... This is false in some cases
+ * (Image is especially tricky here), editors' code is to handle refcount (id->us) itself then. */
+ if (remap_editor_id_reference_cb) {
+ remap_editor_id_reference_cb(old_id, new_id);
+ }
+
+ skipped_direct = id_remap_data.skipped_direct;
+ skipped_refcounted = id_remap_data.skipped_refcounted;
+
+ /* If old_id was used by some ugly 'user_one' stuff (like Image or Clip editors...), and user count has actually
+ * been incremented for that, we have to decrease once more its user count... unless we had to skip
+ * some 'user_one' cases. */
+ if ((old_id->tag & LIB_TAG_EXTRAUSER_SET) &&
+ !(id_remap_data.status & ID_REMAP_IS_USER_ONE_SKIPPED)) {
+ id_us_clear_real(old_id);
+ }
+
+ if (old_id->us - skipped_refcounted < 0) {
+ CLOG_ERROR(&LOG,
+ "Error in remapping process from '%s' (%p) to '%s' (%p): "
+ "wrong user count in old ID after process (summing up to %d)",
+ old_id->name,
+ old_id,
+ new_id ? new_id->name : "<NULL>",
+ new_id,
+ old_id->us - skipped_refcounted);
+ BLI_assert(0);
+ }
+
+ if (skipped_direct == 0) {
+ /* old_id is assumed to not be used directly anymore... */
+ if (old_id->lib && (old_id->tag & LIB_TAG_EXTERN)) {
+ old_id->tag &= ~LIB_TAG_EXTERN;
+ old_id->tag |= LIB_TAG_INDIRECT;
+ }
+ }
+
+ /* Some after-process updates.
+ * This is a bit ugly, but cannot see a way to avoid it. Maybe we should do a per-ID callback for this instead?
+ */
+ switch (GS(old_id->name)) {
+ case ID_OB:
+ libblock_remap_data_postprocess_object_update(bmain, (Object *)old_id, (Object *)new_id);
+ break;
+ case ID_GR:
+ libblock_remap_data_postprocess_collection_update(
+ bmain, (Collection *)old_id, (Collection *)new_id);
+ break;
+ case ID_ME:
+ case ID_CU:
+ case ID_MB:
+ if (new_id) { /* Only affects us in case obdata was relinked (changed). */
+ for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
+ libblock_remap_data_postprocess_obdata_relink(bmain, ob, new_id);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* Node trees may virtually use any kind of data-block... */
+ /* XXX Yuck!!!! nodetree update can do pretty much any thing when talking about py nodes,
+ * including creating new data-blocks (see T50385), so we need to unlock main here. :(
+ * Why can't we have re-entrent locks? */
+ BKE_main_unlock(bmain);
+ libblock_remap_data_postprocess_nodetree_update(bmain, new_id);
+ BKE_main_lock(bmain);
+
+ /* Full rebuild of DEG! */
+ DEG_relations_tag_update(bmain);
}
void BKE_libblock_remap(Main *bmain, void *old_idv, void *new_idv, const short remap_flags)
{
- BKE_main_lock(bmain);
+ BKE_main_lock(bmain);
- BKE_libblock_remap_locked(bmain, old_idv, new_idv, remap_flags);
+ BKE_libblock_remap_locked(bmain, old_idv, new_idv, remap_flags);
- BKE_main_unlock(bmain);
+ BKE_main_unlock(bmain);
}
/**
@@ -572,16 +599,19 @@ void BKE_libblock_remap(Main *bmain, void *old_idv, void *new_idv, const short r
* \param do_flag_never_null: If true, all IDs using \a idv in a 'non-NULL' way are flagged by \a LIB_TAG_DOIT flag
* (quite obviously, 'non-NULL' usages can never be unlinked by this function...).
*/
-void BKE_libblock_unlink(Main *bmain, void *idv, const bool do_flag_never_null, const bool do_skip_indirect)
+void BKE_libblock_unlink(Main *bmain,
+ void *idv,
+ const bool do_flag_never_null,
+ const bool do_skip_indirect)
{
- const short remap_flags = (do_skip_indirect ? ID_REMAP_SKIP_INDIRECT_USAGE : 0) |
- (do_flag_never_null ? ID_REMAP_FLAG_NEVER_NULL_USAGE : 0);
+ const short remap_flags = (do_skip_indirect ? ID_REMAP_SKIP_INDIRECT_USAGE : 0) |
+ (do_flag_never_null ? ID_REMAP_FLAG_NEVER_NULL_USAGE : 0);
- BKE_main_lock(bmain);
+ BKE_main_lock(bmain);
- BKE_libblock_remap_locked(bmain, idv, NULL, remap_flags);
+ BKE_libblock_remap_locked(bmain, idv, NULL, remap_flags);
- BKE_main_unlock(bmain);
+ BKE_main_unlock(bmain);
}
/** Similar to libblock_remap, but only affects IDs used by given \a idv ID.
@@ -601,80 +631,84 @@ void BKE_libblock_unlink(Main *bmain, void *idv, const bool do_flag_never_null,
* ... sigh
*/
void BKE_libblock_relink_ex(
- Main *bmain, void *idv, void *old_idv, void *new_idv, const bool us_min_never_null)
+ Main *bmain, void *idv, void *old_idv, void *new_idv, const bool us_min_never_null)
{
- ID *id = idv;
- ID *old_id = old_idv;
- ID *new_id = new_idv;
- int remap_flags = us_min_never_null ? 0 : ID_REMAP_SKIP_NEVER_NULL_USAGE;
-
- /* No need to lock here, we are only affecting given ID, not bmain database. */
-
- BLI_assert(id);
- if (old_id) {
- BLI_assert((new_id == NULL) || GS(old_id->name) == GS(new_id->name));
- BLI_assert(old_id != new_id);
- }
- else {
- BLI_assert(new_id == NULL);
- }
-
- libblock_remap_data(bmain, id, old_id, new_id, remap_flags, NULL);
-
- /* Some after-process updates.
- * This is a bit ugly, but cannot see a way to avoid it. Maybe we should do a per-ID callback for this instead?
- */
- switch (GS(id->name)) {
- case ID_SCE:
- {
- if (old_id) {
- switch (GS(old_id->name)) {
- case ID_OB:
- libblock_remap_data_postprocess_object_update(bmain, (Object *)old_id, (Object *)new_id);
- break;
- case ID_GR:
- libblock_remap_data_postprocess_collection_update(bmain, (Collection *)old_id, (Collection *)new_id);
- break;
- default:
- break;
- }
- }
- else {
- /* No choice but to check whole objects/collections. */
- libblock_remap_data_postprocess_collection_update(bmain, NULL, NULL);
- libblock_remap_data_postprocess_object_update(bmain, NULL, NULL);
- }
- break;
- }
- case ID_OB:
- if (new_id) { /* Only affects us in case obdata was relinked (changed). */
- libblock_remap_data_postprocess_obdata_relink(bmain, (Object *)id, new_id);
- }
- break;
- default:
- break;
- }
+ ID *id = idv;
+ ID *old_id = old_idv;
+ ID *new_id = new_idv;
+ int remap_flags = us_min_never_null ? 0 : ID_REMAP_SKIP_NEVER_NULL_USAGE;
+
+ /* No need to lock here, we are only affecting given ID, not bmain database. */
+
+ BLI_assert(id);
+ if (old_id) {
+ BLI_assert((new_id == NULL) || GS(old_id->name) == GS(new_id->name));
+ BLI_assert(old_id != new_id);
+ }
+ else {
+ BLI_assert(new_id == NULL);
+ }
+
+ libblock_remap_data(bmain, id, old_id, new_id, remap_flags, NULL);
+
+ /* Some after-process updates.
+ * This is a bit ugly, but cannot see a way to avoid it. Maybe we should do a per-ID callback for this instead?
+ */
+ switch (GS(id->name)) {
+ case ID_SCE: {
+ if (old_id) {
+ switch (GS(old_id->name)) {
+ case ID_OB:
+ libblock_remap_data_postprocess_object_update(
+ bmain, (Object *)old_id, (Object *)new_id);
+ break;
+ case ID_GR:
+ libblock_remap_data_postprocess_collection_update(
+ bmain, (Collection *)old_id, (Collection *)new_id);
+ break;
+ default:
+ break;
+ }
+ }
+ else {
+ /* No choice but to check whole objects/collections. */
+ libblock_remap_data_postprocess_collection_update(bmain, NULL, NULL);
+ libblock_remap_data_postprocess_object_update(bmain, NULL, NULL);
+ }
+ break;
+ }
+ case ID_OB:
+ if (new_id) { /* Only affects us in case obdata was relinked (changed). */
+ libblock_remap_data_postprocess_obdata_relink(bmain, (Object *)id, new_id);
+ }
+ break;
+ default:
+ break;
+ }
}
-static int id_relink_to_newid_looper(void *UNUSED(user_data), ID *UNUSED(self_id), ID **id_pointer, const int cb_flag)
+static int id_relink_to_newid_looper(void *UNUSED(user_data),
+ ID *UNUSED(self_id),
+ ID **id_pointer,
+ const int cb_flag)
{
- if (cb_flag & IDWALK_CB_PRIVATE) {
- return IDWALK_RET_NOP;
- }
-
- ID *id = *id_pointer;
- if (id) {
- /* See: NEW_ID macro */
- if (id->newid) {
- BKE_library_update_ID_link_user(id->newid, id, cb_flag);
- *id_pointer = id->newid;
- }
- else if (id->tag & LIB_TAG_NEW) {
- id->tag &= ~LIB_TAG_NEW;
- BKE_libblock_relink_to_newid(id);
- }
- }
- return IDWALK_RET_NOP;
+ if (cb_flag & IDWALK_CB_PRIVATE) {
+ return IDWALK_RET_NOP;
+ }
+
+ ID *id = *id_pointer;
+ if (id) {
+ /* See: NEW_ID macro */
+ if (id->newid) {
+ BKE_library_update_ID_link_user(id->newid, id, cb_flag);
+ *id_pointer = id->newid;
+ }
+ else if (id->tag & LIB_TAG_NEW) {
+ id->tag &= ~LIB_TAG_NEW;
+ BKE_libblock_relink_to_newid(id);
+ }
+ }
+ return IDWALK_RET_NOP;
}
/** Similar to libblock_relink_ex, but is remapping IDs to their newid value if non-NULL, in given \a id.
@@ -683,140 +717,140 @@ static int id_relink_to_newid_looper(void *UNUSED(user_data), ID *UNUSED(self_id
*/
void BKE_libblock_relink_to_newid(ID *id)
{
- if (ID_IS_LINKED(id))
- return;
+ if (ID_IS_LINKED(id))
+ return;
- BKE_library_foreach_ID_link(NULL, id, id_relink_to_newid_looper, NULL, 0);
+ BKE_library_foreach_ID_link(NULL, id, id_relink_to_newid_looper, NULL, 0);
}
void BKE_libblock_free_data(ID *id, const bool do_id_user)
{
- if (id->properties) {
- IDP_FreeProperty_ex(id->properties, do_id_user);
- MEM_freeN(id->properties);
- }
+ if (id->properties) {
+ IDP_FreeProperty_ex(id->properties, do_id_user);
+ MEM_freeN(id->properties);
+ }
- if (id->override_static) {
- BKE_override_static_free(&id->override_static);
- }
+ if (id->override_static) {
+ BKE_override_static_free(&id->override_static);
+ }
- /* XXX TODO remove animdata handling from each type's freeing func, and do it here, like for copy! */
+ /* XXX TODO remove animdata handling from each type's freeing func, and do it here, like for copy! */
}
void BKE_libblock_free_datablock(ID *id, const int UNUSED(flag))
{
- const short type = GS(id->name);
- switch (type) {
- case ID_SCE:
- BKE_scene_free_ex((Scene *)id, false);
- break;
- case ID_LI:
- BKE_library_free((Library *)id);
- break;
- case ID_OB:
- BKE_object_free((Object *)id);
- break;
- case ID_ME:
- BKE_mesh_free((Mesh *)id);
- break;
- case ID_CU:
- BKE_curve_free((Curve *)id);
- break;
- case ID_MB:
- BKE_mball_free((MetaBall *)id);
- break;
- case ID_MA:
- BKE_material_free((Material *)id);
- break;
- case ID_TE:
- BKE_texture_free((Tex *)id);
- break;
- case ID_IM:
- BKE_image_free((Image *)id);
- break;
- case ID_LT:
- BKE_lattice_free((Lattice *)id);
- break;
- case ID_LA:
- BKE_light_free((Light *)id);
- break;
- case ID_CA:
- BKE_camera_free((Camera *) id);
- break;
- case ID_IP: /* Deprecated. */
- BKE_ipo_free((Ipo *)id);
- break;
- case ID_KE:
- BKE_key_free((Key *)id);
- break;
- case ID_WO:
- BKE_world_free((World *)id);
- break;
- case ID_SCR:
- BKE_screen_free((bScreen *)id);
- break;
- case ID_VF:
- BKE_vfont_free((VFont *)id);
- break;
- case ID_TXT:
- BKE_text_free((Text *)id);
- break;
- case ID_SPK:
- BKE_speaker_free((Speaker *)id);
- break;
- case ID_LP:
- BKE_lightprobe_free((LightProbe *)id);
- break;
- case ID_SO:
- BKE_sound_free((bSound *)id);
- break;
- case ID_GR:
- BKE_collection_free((Collection *)id);
- break;
- case ID_AR:
- BKE_armature_free((bArmature *)id);
- break;
- case ID_AC:
- BKE_action_free((bAction *)id);
- break;
- case ID_NT:
- ntreeFreeTree((bNodeTree *)id);
- break;
- case ID_BR:
- BKE_brush_free((Brush *)id);
- break;
- case ID_PA:
- BKE_particlesettings_free((ParticleSettings *)id);
- break;
- case ID_WM:
- if (free_windowmanager_cb)
- free_windowmanager_cb(NULL, (wmWindowManager *)id);
- break;
- case ID_GD:
- BKE_gpencil_free((bGPdata *)id, true);
- break;
- case ID_MC:
- BKE_movieclip_free((MovieClip *)id);
- break;
- case ID_MSK:
- BKE_mask_free((Mask *)id);
- break;
- case ID_LS:
- BKE_linestyle_free((FreestyleLineStyle *)id);
- break;
- case ID_PAL:
- BKE_palette_free((Palette *)id);
- break;
- case ID_PC:
- BKE_paint_curve_free((PaintCurve *)id);
- break;
- case ID_CF:
- BKE_cachefile_free((CacheFile *)id);
- break;
- case ID_WS:
- BKE_workspace_free((WorkSpace *)id);
- break;
- }
+ const short type = GS(id->name);
+ switch (type) {
+ case ID_SCE:
+ BKE_scene_free_ex((Scene *)id, false);
+ break;
+ case ID_LI:
+ BKE_library_free((Library *)id);
+ break;
+ case ID_OB:
+ BKE_object_free((Object *)id);
+ break;
+ case ID_ME:
+ BKE_mesh_free((Mesh *)id);
+ break;
+ case ID_CU:
+ BKE_curve_free((Curve *)id);
+ break;
+ case ID_MB:
+ BKE_mball_free((MetaBall *)id);
+ break;
+ case ID_MA:
+ BKE_material_free((Material *)id);
+ break;
+ case ID_TE:
+ BKE_texture_free((Tex *)id);
+ break;
+ case ID_IM:
+ BKE_image_free((Image *)id);
+ break;
+ case ID_LT:
+ BKE_lattice_free((Lattice *)id);
+ break;
+ case ID_LA:
+ BKE_light_free((Light *)id);
+ break;
+ case ID_CA:
+ BKE_camera_free((Camera *)id);
+ break;
+ case ID_IP: /* Deprecated. */
+ BKE_ipo_free((Ipo *)id);
+ break;
+ case ID_KE:
+ BKE_key_free((Key *)id);
+ break;
+ case ID_WO:
+ BKE_world_free((World *)id);
+ break;
+ case ID_SCR:
+ BKE_screen_free((bScreen *)id);
+ break;
+ case ID_VF:
+ BKE_vfont_free((VFont *)id);
+ break;
+ case ID_TXT:
+ BKE_text_free((Text *)id);
+ break;
+ case ID_SPK:
+ BKE_speaker_free((Speaker *)id);
+ break;
+ case ID_LP:
+ BKE_lightprobe_free((LightProbe *)id);
+ break;
+ case ID_SO:
+ BKE_sound_free((bSound *)id);
+ break;
+ case ID_GR:
+ BKE_collection_free((Collection *)id);
+ break;
+ case ID_AR:
+ BKE_armature_free((bArmature *)id);
+ break;
+ case ID_AC:
+ BKE_action_free((bAction *)id);
+ break;
+ case ID_NT:
+ ntreeFreeTree((bNodeTree *)id);
+ break;
+ case ID_BR:
+ BKE_brush_free((Brush *)id);
+ break;
+ case ID_PA:
+ BKE_particlesettings_free((ParticleSettings *)id);
+ break;
+ case ID_WM:
+ if (free_windowmanager_cb)
+ free_windowmanager_cb(NULL, (wmWindowManager *)id);
+ break;
+ case ID_GD:
+ BKE_gpencil_free((bGPdata *)id, true);
+ break;
+ case ID_MC:
+ BKE_movieclip_free((MovieClip *)id);
+ break;
+ case ID_MSK:
+ BKE_mask_free((Mask *)id);
+ break;
+ case ID_LS:
+ BKE_linestyle_free((FreestyleLineStyle *)id);
+ break;
+ case ID_PAL:
+ BKE_palette_free((Palette *)id);
+ break;
+ case ID_PC:
+ BKE_paint_curve_free((PaintCurve *)id);
+ break;
+ case ID_CF:
+ BKE_cachefile_free((CacheFile *)id);
+ break;
+ case ID_WS:
+ BKE_workspace_free((WorkSpace *)id);
+ break;
+ }
}
/**
@@ -837,85 +871,85 @@ void BKE_libblock_free_datablock(ID *id, const int UNUSED(flag))
*/
void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_idtag)
{
- ID *id = idv;
-
- if (use_flag_from_idtag) {
- if ((id->tag & LIB_TAG_NO_MAIN) != 0) {
- flag |= LIB_ID_FREE_NO_MAIN | LIB_ID_FREE_NO_UI_USER | LIB_ID_FREE_NO_DEG_TAG;
- }
- else {
- flag &= ~LIB_ID_FREE_NO_MAIN;
- }
-
- if ((id->tag & LIB_TAG_NO_USER_REFCOUNT) != 0) {
- flag |= LIB_ID_FREE_NO_USER_REFCOUNT;
- }
- else {
- flag &= ~LIB_ID_FREE_NO_USER_REFCOUNT;
- }
-
- if ((id->tag & LIB_TAG_NOT_ALLOCATED) != 0) {
- flag |= LIB_ID_FREE_NOT_ALLOCATED;
- }
- else {
- flag &= ~LIB_ID_FREE_NOT_ALLOCATED;
- }
- }
-
- BLI_assert((flag & LIB_ID_FREE_NO_MAIN) != 0 || bmain != NULL);
- BLI_assert((flag & LIB_ID_FREE_NO_MAIN) != 0 || (flag & LIB_ID_FREE_NOT_ALLOCATED) == 0);
- BLI_assert((flag & LIB_ID_FREE_NO_MAIN) != 0 || (flag & LIB_ID_FREE_NO_USER_REFCOUNT) == 0);
-
- const short type = GS(id->name);
-
- if (bmain && (flag & LIB_ID_FREE_NO_DEG_TAG) == 0) {
- DEG_id_type_tag(bmain, type);
- }
+ ID *id = idv;
+
+ if (use_flag_from_idtag) {
+ if ((id->tag & LIB_TAG_NO_MAIN) != 0) {
+ flag |= LIB_ID_FREE_NO_MAIN | LIB_ID_FREE_NO_UI_USER | LIB_ID_FREE_NO_DEG_TAG;
+ }
+ else {
+ flag &= ~LIB_ID_FREE_NO_MAIN;
+ }
+
+ if ((id->tag & LIB_TAG_NO_USER_REFCOUNT) != 0) {
+ flag |= LIB_ID_FREE_NO_USER_REFCOUNT;
+ }
+ else {
+ flag &= ~LIB_ID_FREE_NO_USER_REFCOUNT;
+ }
+
+ if ((id->tag & LIB_TAG_NOT_ALLOCATED) != 0) {
+ flag |= LIB_ID_FREE_NOT_ALLOCATED;
+ }
+ else {
+ flag &= ~LIB_ID_FREE_NOT_ALLOCATED;
+ }
+ }
+
+ BLI_assert((flag & LIB_ID_FREE_NO_MAIN) != 0 || bmain != NULL);
+ BLI_assert((flag & LIB_ID_FREE_NO_MAIN) != 0 || (flag & LIB_ID_FREE_NOT_ALLOCATED) == 0);
+ BLI_assert((flag & LIB_ID_FREE_NO_MAIN) != 0 || (flag & LIB_ID_FREE_NO_USER_REFCOUNT) == 0);
+
+ const short type = GS(id->name);
+
+ if (bmain && (flag & LIB_ID_FREE_NO_DEG_TAG) == 0) {
+ DEG_id_type_tag(bmain, type);
+ }
#ifdef WITH_PYTHON
# ifdef WITH_PYTHON_SAFETY
- BPY_id_release(id);
+ BPY_id_release(id);
# endif
- if (id->py_instance) {
- BPY_DECREF_RNA_INVALIDATE(id->py_instance);
- }
+ if (id->py_instance) {
+ BPY_DECREF_RNA_INVALIDATE(id->py_instance);
+ }
#endif
- if ((flag & LIB_ID_FREE_NO_USER_REFCOUNT) == 0) {
- BKE_libblock_relink_ex(bmain, id, NULL, NULL, true);
- }
+ if ((flag & LIB_ID_FREE_NO_USER_REFCOUNT) == 0) {
+ BKE_libblock_relink_ex(bmain, id, NULL, NULL, true);
+ }
- BKE_libblock_free_datablock(id, flag);
+ BKE_libblock_free_datablock(id, flag);
- /* avoid notifying on removed data */
- if ((flag & LIB_ID_FREE_NO_MAIN) == 0) {
- BKE_main_lock(bmain);
- }
+ /* avoid notifying on removed data */
+ if ((flag & LIB_ID_FREE_NO_MAIN) == 0) {
+ BKE_main_lock(bmain);
+ }
- if ((flag & LIB_ID_FREE_NO_UI_USER) == 0) {
- if (free_notifier_reference_cb) {
- free_notifier_reference_cb(id);
- }
+ if ((flag & LIB_ID_FREE_NO_UI_USER) == 0) {
+ if (free_notifier_reference_cb) {
+ free_notifier_reference_cb(id);
+ }
- if (remap_editor_id_reference_cb) {
- remap_editor_id_reference_cb(id, NULL);
- }
- }
+ if (remap_editor_id_reference_cb) {
+ remap_editor_id_reference_cb(id, NULL);
+ }
+ }
- if ((flag & LIB_ID_FREE_NO_MAIN) == 0) {
- ListBase *lb = which_libbase(bmain, type);
- BLI_remlink(lb, id);
- }
+ if ((flag & LIB_ID_FREE_NO_MAIN) == 0) {
+ ListBase *lb = which_libbase(bmain, type);
+ BLI_remlink(lb, id);
+ }
- BKE_libblock_free_data(id, (flag & LIB_ID_FREE_NO_USER_REFCOUNT) == 0);
+ BKE_libblock_free_data(id, (flag & LIB_ID_FREE_NO_USER_REFCOUNT) == 0);
- if ((flag & LIB_ID_FREE_NO_MAIN) == 0) {
- BKE_main_unlock(bmain);
- }
+ if ((flag & LIB_ID_FREE_NO_MAIN) == 0) {
+ BKE_main_unlock(bmain);
+ }
- if ((flag & LIB_ID_FREE_NOT_ALLOCATED) == 0) {
- MEM_freeN(id);
- }
+ if ((flag & LIB_ID_FREE_NOT_ALLOCATED) == 0) {
+ MEM_freeN(id);
+ }
}
/**
@@ -928,158 +962,157 @@ void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_i
*/
void BKE_id_free(Main *bmain, void *idv)
{
- BKE_id_free_ex(bmain, idv, 0, true);
+ BKE_id_free_ex(bmain, idv, 0, true);
}
/**
* Not really a freeing function by itself, it decrements usercount of given id, and only frees it if it reaches 0.
*/
-void BKE_id_free_us(Main *bmain, void *idv) /* test users */
+void BKE_id_free_us(Main *bmain, void *idv) /* test users */
{
- ID *id = idv;
-
- id_us_min(id);
-
- /* XXX This is a temp (2.77) hack so that we keep same behavior as in 2.76 regarding collections when deleting an object.
- * Since only 'user_one' usage of objects is collections, and only 'real user' usage of objects is scenes,
- * removing that 'user_one' tag when there is no more real (scene) users of an object ensures it gets
- * fully unlinked.
- * But only for local objects, not linked ones!
- * Otherwise, there is no real way to get rid of an object anymore - better handling of this is TODO.
- */
- if ((GS(id->name) == ID_OB) && (id->us == 1) && (id->lib == NULL)) {
- id_us_clear_real(id);
- }
-
- if (id->us == 0) {
- BKE_libblock_unlink(bmain, id, false, false);
-
- BKE_id_free(bmain, id);
- }
+ ID *id = idv;
+
+ id_us_min(id);
+
+ /* XXX This is a temp (2.77) hack so that we keep same behavior as in 2.76 regarding collections when deleting an object.
+ * Since only 'user_one' usage of objects is collections, and only 'real user' usage of objects is scenes,
+ * removing that 'user_one' tag when there is no more real (scene) users of an object ensures it gets
+ * fully unlinked.
+ * But only for local objects, not linked ones!
+ * Otherwise, there is no real way to get rid of an object anymore - better handling of this is TODO.
+ */
+ if ((GS(id->name) == ID_OB) && (id->us == 1) && (id->lib == NULL)) {
+ id_us_clear_real(id);
+ }
+
+ if (id->us == 0) {
+ BKE_libblock_unlink(bmain, id, false, false);
+
+ BKE_id_free(bmain, id);
+ }
}
static void id_delete(Main *bmain, const bool do_tagged_deletion)
{
- const int tag = LIB_TAG_DOIT;
- ListBase *lbarray[MAX_LIBARRAY];
- Link dummy_link = {0};
- int base_count, i;
-
- /* Used by batch tagged deletion, when we call BKE_id_free then, id is no more in Main database,
- * and has already properly unlinked its other IDs usages.
- * UI users are always cleared in BKE_libblock_remap_locked() call, so we can always skip it. */
- const int free_flag = LIB_ID_FREE_NO_UI_USER |
- (do_tagged_deletion ? LIB_ID_FREE_NO_MAIN | LIB_ID_FREE_NO_USER_REFCOUNT : 0);
- ListBase tagged_deleted_ids = {NULL};
-
- base_count = set_listbasepointers(bmain, lbarray);
-
- BKE_main_lock(bmain);
- if (do_tagged_deletion) {
- /* Main idea of batch deletion is to remove all IDs to be deleted from Main database.
- * This means that we won't have to loop over all deleted IDs to remove usages
- * of other deleted IDs.
- * This gives tremendous speed-up when deleting a large amount of IDs from a Main
- * containing thousands of those.
- * This also means that we have to be very careful here, as we by-pass many 'common'
- * processing, hence risking to 'corrupt' at least user counts, if not IDs themselves. */
- bool keep_looping = true;
- while (keep_looping) {
- ID *id, *id_next;
- ID *last_remapped_id = tagged_deleted_ids.last;
- keep_looping = false;
-
- /* First tag and remove from Main all datablocks directly from target lib.
- * Note that we go forward here, since we want to check dependencies before users
- * (e.g. meshes before objects). Avoids to have to loop twice. */
- for (i = 0; i < base_count; i++) {
- ListBase *lb = lbarray[i];
-
- for (id = lb->first; id; id = id_next) {
- id_next = id->next;
- /* Note: in case we delete a library, we also delete all its datablocks! */
- if ((id->tag & tag) || (id->lib != NULL && (id->lib->id.tag & tag))) {
- BLI_remlink(lb, id);
- BLI_addtail(&tagged_deleted_ids, id);
- /* Do not tag as no_main now, we want to unlink it first (lower-level ID management code
- * has some specific handling of 'nom main' IDs that would be a problem in that case). */
- id->tag |= tag;
- keep_looping = true;
- }
- }
- }
- if (last_remapped_id == NULL) {
- dummy_link.next = tagged_deleted_ids.first;
- last_remapped_id = (ID *)(&dummy_link);
- }
- for (id = last_remapped_id->next; id; id = id->next) {
- /* Will tag 'never NULL' users of this ID too.
- * Note that we cannot use BKE_libblock_unlink() here, since it would ignore indirect (and proxy!)
- * links, this can lead to nasty crashing here in second, actual deleting loop.
- * Also, this will also flag users of deleted data that cannot be unlinked
- * (object using deleted obdata, etc.), so that they also get deleted. */
- BKE_libblock_remap_locked(
- bmain, id, NULL,
- ID_REMAP_FLAG_NEVER_NULL_USAGE | ID_REMAP_FORCE_NEVER_NULL_USAGE);
- /* Since we removed ID from Main, we also need to unlink its own other IDs usages ourself. */
- BKE_libblock_relink_ex(bmain, id, NULL, NULL, true);
- /* Now we can safely mark that ID as not being in Main database anymore. */
- id->tag |= LIB_TAG_NO_MAIN;
- /* This is needed because we may not have remapped usages of that ID by other deleted ones. */
-// id->us = 0; /* Is it actually? */
- }
- }
- }
- else {
- /* First tag all datablocks directly from target lib.
- * Note that we go forward here, since we want to check dependencies before users (e.g. meshes before objects).
- * Avoids to have to loop twice. */
- for (i = 0; i < base_count; i++) {
- ListBase *lb = lbarray[i];
- ID *id, *id_next;
-
- for (id = lb->first; id; id = id_next) {
- id_next = id->next;
- /* Note: in case we delete a library, we also delete all its datablocks! */
- if ((id->tag & tag) || (id->lib != NULL && (id->lib->id.tag & tag))) {
- id->tag |= tag;
-
- /* Will tag 'never NULL' users of this ID too.
- * Note that we cannot use BKE_libblock_unlink() here, since it would ignore indirect (and proxy!)
- * links, this can lead to nasty crashing here in second, actual deleting loop.
- * Also, this will also flag users of deleted data that cannot be unlinked
- * (object using deleted obdata, etc.), so that they also get deleted. */
- BKE_libblock_remap_locked(
- bmain, id, NULL,
- ID_REMAP_FLAG_NEVER_NULL_USAGE | ID_REMAP_FORCE_NEVER_NULL_USAGE);
- }
- }
- }
- }
- BKE_main_unlock(bmain);
-
- /* In usual reversed order, such that all usage of a given ID, even 'never NULL' ones, have been already cleared
- * when we reach it (e.g. Objects being processed before meshes, they'll have already released their 'reference'
- * over meshes when we come to freeing obdata). */
- for (i = do_tagged_deletion ? 1 : base_count; i--; ) {
- ListBase *lb = lbarray[i];
- ID *id, *id_next;
-
- for (id = do_tagged_deletion ? tagged_deleted_ids.first : lb->first; id; id = id_next) {
- id_next = id->next;
- if (id->tag & tag) {
- if (id->us != 0) {
+ const int tag = LIB_TAG_DOIT;
+ ListBase *lbarray[MAX_LIBARRAY];
+ Link dummy_link = {0};
+ int base_count, i;
+
+ /* Used by batch tagged deletion, when we call BKE_id_free then, id is no more in Main database,
+ * and has already properly unlinked its other IDs usages.
+ * UI users are always cleared in BKE_libblock_remap_locked() call, so we can always skip it. */
+ const int free_flag = LIB_ID_FREE_NO_UI_USER |
+ (do_tagged_deletion ? LIB_ID_FREE_NO_MAIN | LIB_ID_FREE_NO_USER_REFCOUNT :
+ 0);
+ ListBase tagged_deleted_ids = {NULL};
+
+ base_count = set_listbasepointers(bmain, lbarray);
+
+ BKE_main_lock(bmain);
+ if (do_tagged_deletion) {
+ /* Main idea of batch deletion is to remove all IDs to be deleted from Main database.
+ * This means that we won't have to loop over all deleted IDs to remove usages
+ * of other deleted IDs.
+ * This gives tremendous speed-up when deleting a large amount of IDs from a Main
+ * containing thousands of those.
+ * This also means that we have to be very careful here, as we by-pass many 'common'
+ * processing, hence risking to 'corrupt' at least user counts, if not IDs themselves. */
+ bool keep_looping = true;
+ while (keep_looping) {
+ ID *id, *id_next;
+ ID *last_remapped_id = tagged_deleted_ids.last;
+ keep_looping = false;
+
+ /* First tag and remove from Main all datablocks directly from target lib.
+ * Note that we go forward here, since we want to check dependencies before users
+ * (e.g. meshes before objects). Avoids to have to loop twice. */
+ for (i = 0; i < base_count; i++) {
+ ListBase *lb = lbarray[i];
+
+ for (id = lb->first; id; id = id_next) {
+ id_next = id->next;
+ /* Note: in case we delete a library, we also delete all its datablocks! */
+ if ((id->tag & tag) || (id->lib != NULL && (id->lib->id.tag & tag))) {
+ BLI_remlink(lb, id);
+ BLI_addtail(&tagged_deleted_ids, id);
+ /* Do not tag as no_main now, we want to unlink it first (lower-level ID management code
+ * has some specific handling of 'nom main' IDs that would be a problem in that case). */
+ id->tag |= tag;
+ keep_looping = true;
+ }
+ }
+ }
+ if (last_remapped_id == NULL) {
+ dummy_link.next = tagged_deleted_ids.first;
+ last_remapped_id = (ID *)(&dummy_link);
+ }
+ for (id = last_remapped_id->next; id; id = id->next) {
+ /* Will tag 'never NULL' users of this ID too.
+ * Note that we cannot use BKE_libblock_unlink() here, since it would ignore indirect (and proxy!)
+ * links, this can lead to nasty crashing here in second, actual deleting loop.
+ * Also, this will also flag users of deleted data that cannot be unlinked
+ * (object using deleted obdata, etc.), so that they also get deleted. */
+ BKE_libblock_remap_locked(
+ bmain, id, NULL, ID_REMAP_FLAG_NEVER_NULL_USAGE | ID_REMAP_FORCE_NEVER_NULL_USAGE);
+ /* Since we removed ID from Main, we also need to unlink its own other IDs usages ourself. */
+ BKE_libblock_relink_ex(bmain, id, NULL, NULL, true);
+ /* Now we can safely mark that ID as not being in Main database anymore. */
+ id->tag |= LIB_TAG_NO_MAIN;
+ /* This is needed because we may not have remapped usages of that ID by other deleted ones. */
+ // id->us = 0; /* Is it actually? */
+ }
+ }
+ }
+ else {
+ /* First tag all datablocks directly from target lib.
+ * Note that we go forward here, since we want to check dependencies before users (e.g. meshes before objects).
+ * Avoids to have to loop twice. */
+ for (i = 0; i < base_count; i++) {
+ ListBase *lb = lbarray[i];
+ ID *id, *id_next;
+
+ for (id = lb->first; id; id = id_next) {
+ id_next = id->next;
+ /* Note: in case we delete a library, we also delete all its datablocks! */
+ if ((id->tag & tag) || (id->lib != NULL && (id->lib->id.tag & tag))) {
+ id->tag |= tag;
+
+ /* Will tag 'never NULL' users of this ID too.
+ * Note that we cannot use BKE_libblock_unlink() here, since it would ignore indirect (and proxy!)
+ * links, this can lead to nasty crashing here in second, actual deleting loop.
+ * Also, this will also flag users of deleted data that cannot be unlinked
+ * (object using deleted obdata, etc.), so that they also get deleted. */
+ BKE_libblock_remap_locked(
+ bmain, id, NULL, ID_REMAP_FLAG_NEVER_NULL_USAGE | ID_REMAP_FORCE_NEVER_NULL_USAGE);
+ }
+ }
+ }
+ }
+ BKE_main_unlock(bmain);
+
+ /* In usual reversed order, such that all usage of a given ID, even 'never NULL' ones, have been already cleared
+ * when we reach it (e.g. Objects being processed before meshes, they'll have already released their 'reference'
+ * over meshes when we come to freeing obdata). */
+ for (i = do_tagged_deletion ? 1 : base_count; i--;) {
+ ListBase *lb = lbarray[i];
+ ID *id, *id_next;
+
+ for (id = do_tagged_deletion ? tagged_deleted_ids.first : lb->first; id; id = id_next) {
+ id_next = id->next;
+ if (id->tag & tag) {
+ if (id->us != 0) {
#ifdef DEBUG_PRINT
- printf("%s: deleting %s (%d)\n", __func__, id->name, id->us);
+ printf("%s: deleting %s (%d)\n", __func__, id->name, id->us);
#endif
- BLI_assert(id->us == 0);
- }
- BKE_id_free_ex(bmain, id, free_flag, !do_tagged_deletion);
- }
- }
- }
-
- bmain->is_memfile_undo_written = false;
+ BLI_assert(id->us == 0);
+ }
+ BKE_id_free_ex(bmain, id, free_flag, !do_tagged_deletion);
+ }
+ }
+ }
+
+ bmain->is_memfile_undo_written = false;
}
/**
@@ -1087,10 +1120,10 @@ static void id_delete(Main *bmain, const bool do_tagged_deletion)
*/
void BKE_id_delete(Main *bmain, void *idv)
{
- BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
- ((ID *)idv)->tag |= LIB_TAG_DOIT;
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+ ((ID *)idv)->tag |= LIB_TAG_DOIT;
- id_delete(bmain, false);
+ id_delete(bmain, false);
}
/**
@@ -1104,5 +1137,5 @@ void BKE_id_delete(Main *bmain, void *idv)
*/
void BKE_id_multi_tagged_delete(Main *bmain)
{
- id_delete(bmain, true);
+ id_delete(bmain, true);
}
diff --git a/source/blender/blenkernel/intern/light.c b/source/blender/blenkernel/intern/light.c
index ae68182c55a..f0943bc2749 100644
--- a/source/blender/blenkernel/intern/light.c
+++ b/source/blender/blenkernel/intern/light.c
@@ -46,53 +46,53 @@
void BKE_light_init(Light *la)
{
- BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(la, id));
-
- la->r = la->g = la->b = la->k = 1.0f;
- la->energy = 10.0f;
- la->dist = 25.0f;
- la->spotsize = DEG2RADF(45.0f);
- la->spotblend = 0.15f;
- la->att2 = 1.0f;
- la->mode = LA_SHADOW;
- la->bufsize = 512;
- la->clipsta = 0.5f;
- la->clipend = 40.0f;
- la->bleedexp = 2.5f;
- la->samp = 3;
- la->bias = 1.0f;
- la->soft = 3.0f;
- la->area_size = la->area_sizey = la->area_sizez = 0.25f;
- la->buffers = 1;
- la->preview = NULL;
- la->falloff_type = LA_FALLOFF_INVSQUARE;
- la->coeff_const = 1.0f;
- la->coeff_lin = 0.0f;
- la->coeff_quad = 0.0f;
- la->curfalloff = curvemapping_add(1, 0.0f, 1.0f, 1.0f, 0.0f);
- la->cascade_max_dist = 200.0f;
- la->cascade_count = 4;
- la->cascade_exponent = 0.8f;
- la->cascade_fade = 0.1f;
- la->contact_dist = 0.2f;
- la->contact_bias = 0.03f;
- la->contact_spread = 0.2f;
- la->contact_thickness = 0.2f;
- la->spec_fac = 1.0f;
- la->att_dist = 40.0f;
-
- curvemapping_initialize(la->curfalloff);
+ BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(la, id));
+
+ la->r = la->g = la->b = la->k = 1.0f;
+ la->energy = 10.0f;
+ la->dist = 25.0f;
+ la->spotsize = DEG2RADF(45.0f);
+ la->spotblend = 0.15f;
+ la->att2 = 1.0f;
+ la->mode = LA_SHADOW;
+ la->bufsize = 512;
+ la->clipsta = 0.5f;
+ la->clipend = 40.0f;
+ la->bleedexp = 2.5f;
+ la->samp = 3;
+ la->bias = 1.0f;
+ la->soft = 3.0f;
+ la->area_size = la->area_sizey = la->area_sizez = 0.25f;
+ la->buffers = 1;
+ la->preview = NULL;
+ la->falloff_type = LA_FALLOFF_INVSQUARE;
+ la->coeff_const = 1.0f;
+ la->coeff_lin = 0.0f;
+ la->coeff_quad = 0.0f;
+ la->curfalloff = curvemapping_add(1, 0.0f, 1.0f, 1.0f, 0.0f);
+ la->cascade_max_dist = 200.0f;
+ la->cascade_count = 4;
+ la->cascade_exponent = 0.8f;
+ la->cascade_fade = 0.1f;
+ la->contact_dist = 0.2f;
+ la->contact_bias = 0.03f;
+ la->contact_spread = 0.2f;
+ la->contact_thickness = 0.2f;
+ la->spec_fac = 1.0f;
+ la->att_dist = 40.0f;
+
+ curvemapping_initialize(la->curfalloff);
}
Light *BKE_light_add(Main *bmain, const char *name)
{
- Light *la;
+ Light *la;
- la = BKE_libblock_alloc(bmain, ID_LA, name, 0);
+ la = BKE_libblock_alloc(bmain, ID_LA, name, 0);
- BKE_light_init(la);
+ BKE_light_init(la);
- return la;
+ return la;
}
/**
@@ -105,74 +105,74 @@ Light *BKE_light_add(Main *bmain, const char *name)
*/
void BKE_light_copy_data(Main *bmain, Light *la_dst, const Light *la_src, const int flag)
{
- la_dst->curfalloff = curvemapping_copy(la_src->curfalloff);
-
- if (la_src->nodetree) {
- /* Note: nodetree is *not* in bmain, however this specific case is handled at lower level
- * (see BKE_libblock_copy_ex()). */
- BKE_id_copy_ex(bmain, (ID *)la_src->nodetree, (ID **)&la_dst->nodetree, flag);
- }
-
- if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
- BKE_previewimg_id_copy(&la_dst->id, &la_src->id);
- }
- else {
- la_dst->preview = NULL;
- }
+ la_dst->curfalloff = curvemapping_copy(la_src->curfalloff);
+
+ if (la_src->nodetree) {
+ /* Note: nodetree is *not* in bmain, however this specific case is handled at lower level
+ * (see BKE_libblock_copy_ex()). */
+ BKE_id_copy_ex(bmain, (ID *)la_src->nodetree, (ID **)&la_dst->nodetree, flag);
+ }
+
+ if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
+ BKE_previewimg_id_copy(&la_dst->id, &la_src->id);
+ }
+ else {
+ la_dst->preview = NULL;
+ }
}
Light *BKE_light_copy(Main *bmain, const Light *la)
{
- Light *la_copy;
- BKE_id_copy(bmain, &la->id, (ID **)&la_copy);
- return la_copy;
+ Light *la_copy;
+ BKE_id_copy(bmain, &la->id, (ID **)&la_copy);
+ return la_copy;
}
Light *BKE_light_localize(Light *la)
{
- /* TODO(bastien): Replace with something like:
- *
- * Light *la_copy;
- * BKE_id_copy_ex(bmain, &la->id, (ID **)&la_copy,
- * LIB_ID_COPY_NO_MAIN | LIB_ID_COPY_NO_PREVIEW | LIB_ID_COPY_NO_USER_REFCOUNT,
- * false);
- * return la_copy;
- *
- * NOTE: Only possible once nested node trees are fully converted to that too. */
+ /* TODO(bastien): Replace with something like:
+ *
+ * Light *la_copy;
+ * BKE_id_copy_ex(bmain, &la->id, (ID **)&la_copy,
+ * LIB_ID_COPY_NO_MAIN | LIB_ID_COPY_NO_PREVIEW | LIB_ID_COPY_NO_USER_REFCOUNT,
+ * false);
+ * return la_copy;
+ *
+ * NOTE: Only possible once nested node trees are fully converted to that too. */
- Light *lan = BKE_libblock_copy_for_localize(&la->id);
+ Light *lan = BKE_libblock_copy_for_localize(&la->id);
- lan->curfalloff = curvemapping_copy(la->curfalloff);
+ lan->curfalloff = curvemapping_copy(la->curfalloff);
- if (la->nodetree)
- lan->nodetree = ntreeLocalize(la->nodetree);
+ if (la->nodetree)
+ lan->nodetree = ntreeLocalize(la->nodetree);
- lan->preview = NULL;
+ lan->preview = NULL;
- lan->id.tag |= LIB_TAG_LOCALIZED;
+ lan->id.tag |= LIB_TAG_LOCALIZED;
- return lan;
+ return lan;
}
void BKE_light_make_local(Main *bmain, Light *la, const bool lib_local)
{
- BKE_id_make_local_generic(bmain, &la->id, true, lib_local);
+ BKE_id_make_local_generic(bmain, &la->id, true, lib_local);
}
void BKE_light_free(Light *la)
{
- BKE_animdata_free((ID *)la, false);
+ BKE_animdata_free((ID *)la, false);
- curvemapping_free(la->curfalloff);
+ curvemapping_free(la->curfalloff);
- /* is no lib link block, but light extension */
- if (la->nodetree) {
- ntreeFreeNestedTree(la->nodetree);
- MEM_freeN(la->nodetree);
- la->nodetree = NULL;
- }
+ /* is no lib link block, but light extension */
+ if (la->nodetree) {
+ ntreeFreeNestedTree(la->nodetree);
+ MEM_freeN(la->nodetree);
+ la->nodetree = NULL;
+ }
- BKE_previewimg_free(&la->preview);
- BKE_icon_id_delete(&la->id);
- la->id.icon_id = 0;
+ BKE_previewimg_free(&la->preview);
+ BKE_icon_id_delete(&la->id);
+ la->id.icon_id = 0;
}
diff --git a/source/blender/blenkernel/intern/lightprobe.c b/source/blender/blenkernel/intern/lightprobe.c
index 12568c9aa2a..6b1951498cc 100644
--- a/source/blender/blenkernel/intern/lightprobe.c
+++ b/source/blender/blenkernel/intern/lightprobe.c
@@ -33,30 +33,30 @@
void BKE_lightprobe_init(LightProbe *probe)
{
- BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(probe, id));
+ BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(probe, id));
- probe->grid_resolution_x = probe->grid_resolution_y = probe->grid_resolution_z = 4;
- probe->distinf = 2.5f;
- probe->distpar = 2.5f;
- probe->falloff = 0.2f;
- probe->clipsta = 0.8f;
- probe->clipend = 40.0f;
- probe->vis_bias = 1.0f;
- probe->vis_blur = 0.2f;
- probe->intensity = 1.0f;
+ probe->grid_resolution_x = probe->grid_resolution_y = probe->grid_resolution_z = 4;
+ probe->distinf = 2.5f;
+ probe->distpar = 2.5f;
+ probe->falloff = 0.2f;
+ probe->clipsta = 0.8f;
+ probe->clipend = 40.0f;
+ probe->vis_bias = 1.0f;
+ probe->vis_blur = 0.2f;
+ probe->intensity = 1.0f;
- probe->flag = LIGHTPROBE_FLAG_SHOW_INFLUENCE | LIGHTPROBE_FLAG_SHOW_DATA;
+ probe->flag = LIGHTPROBE_FLAG_SHOW_INFLUENCE | LIGHTPROBE_FLAG_SHOW_DATA;
}
void *BKE_lightprobe_add(Main *bmain, const char *name)
{
- LightProbe *probe;
+ LightProbe *probe;
- probe = BKE_libblock_alloc(bmain, ID_LP, name, 0);
+ probe = BKE_libblock_alloc(bmain, ID_LP, name, 0);
- BKE_lightprobe_init(probe);
+ BKE_lightprobe_init(probe);
- return probe;
+ return probe;
}
/**
@@ -67,25 +67,27 @@ void *BKE_lightprobe_add(Main *bmain, const char *name)
*
* \param flag: Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
*/
-void BKE_lightprobe_copy_data(
- Main *UNUSED(bmain), LightProbe *UNUSED(probe_dst), const LightProbe *UNUSED(probe_src), const int UNUSED(flag))
+void BKE_lightprobe_copy_data(Main *UNUSED(bmain),
+ LightProbe *UNUSED(probe_dst),
+ const LightProbe *UNUSED(probe_src),
+ const int UNUSED(flag))
{
- /* Nothing to do here. */
+ /* Nothing to do here. */
}
LightProbe *BKE_lightprobe_copy(Main *bmain, const LightProbe *probe)
{
- LightProbe *probe_copy;
- BKE_id_copy(bmain, &probe->id, (ID **)&probe_copy);
- return probe_copy;
+ LightProbe *probe_copy;
+ BKE_id_copy(bmain, &probe->id, (ID **)&probe_copy);
+ return probe_copy;
}
void BKE_lightprobe_make_local(Main *bmain, LightProbe *probe, const bool lib_local)
{
- BKE_id_make_local_generic(bmain, &probe->id, true, lib_local);
+ BKE_id_make_local_generic(bmain, &probe->id, true, lib_local);
}
void BKE_lightprobe_free(LightProbe *probe)
{
- BKE_animdata_free((ID *)probe, false);
+ BKE_animdata_free((ID *)probe, false);
}
diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c
index 47201d30b63..a0cfe7dfe41 100644
--- a/source/blender/blenkernel/intern/linestyle.c
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -46,104 +46,104 @@
#include "BKE_animsys.h"
static const char *modifier_name[LS_MODIFIER_NUM] = {
- NULL,
- "Along Stroke",
- "Distance from Camera",
- "Distance from Object",
- "Material",
- "Sampling",
- "Bezier Curve",
- "Sinus Displacement",
- "Spatial Noise",
- "Perlin Noise 1D",
- "Perlin Noise 2D",
- "Backbone Stretcher",
- "Tip Remover",
- "Calligraphy",
- "Polygonalization",
- "Guiding Lines",
- "Blueprint",
- "2D Offset",
- "2D Transform",
- "Tangent",
- "Noise",
- "Crease Angle",
- "Simplification",
- "3D Curvature",
+ NULL,
+ "Along Stroke",
+ "Distance from Camera",
+ "Distance from Object",
+ "Material",
+ "Sampling",
+ "Bezier Curve",
+ "Sinus Displacement",
+ "Spatial Noise",
+ "Perlin Noise 1D",
+ "Perlin Noise 2D",
+ "Backbone Stretcher",
+ "Tip Remover",
+ "Calligraphy",
+ "Polygonalization",
+ "Guiding Lines",
+ "Blueprint",
+ "2D Offset",
+ "2D Transform",
+ "Tangent",
+ "Noise",
+ "Crease Angle",
+ "Simplification",
+ "3D Curvature",
};
void BKE_linestyle_init(FreestyleLineStyle *linestyle)
{
- BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(linestyle, id));
-
- linestyle->panel = LS_PANEL_STROKES;
- linestyle->r = linestyle->g = linestyle->b = 0.0f;
- linestyle->alpha = 1.0f;
- linestyle->thickness = 3.0f;
- linestyle->thickness_position = LS_THICKNESS_CENTER;
- linestyle->thickness_ratio = 0.5f;
- linestyle->flag = LS_SAME_OBJECT | LS_NO_SORTING | LS_TEXTURE;
- linestyle->chaining = LS_CHAINING_PLAIN;
- linestyle->rounds = 3;
- linestyle->min_angle = DEG2RADF(0.0f);
- linestyle->max_angle = DEG2RADF(0.0f);
- linestyle->min_length = 0.0f;
- linestyle->max_length = 10000.0f;
- linestyle->split_length = 100;
- linestyle->chain_count = 10;
- linestyle->sort_key = LS_SORT_KEY_DISTANCE_FROM_CAMERA;
- linestyle->integration_type = LS_INTEGRATION_MEAN;
- linestyle->texstep = 1.0f;
- linestyle->pr_texture = TEX_PR_TEXTURE;
-
- BLI_listbase_clear(&linestyle->color_modifiers);
- BLI_listbase_clear(&linestyle->alpha_modifiers);
- BLI_listbase_clear(&linestyle->thickness_modifiers);
- BLI_listbase_clear(&linestyle->geometry_modifiers);
-
- BKE_linestyle_geometry_modifier_add(linestyle, NULL, LS_MODIFIER_SAMPLING);
-
- linestyle->caps = LS_CAPS_BUTT;
+ BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(linestyle, id));
+
+ linestyle->panel = LS_PANEL_STROKES;
+ linestyle->r = linestyle->g = linestyle->b = 0.0f;
+ linestyle->alpha = 1.0f;
+ linestyle->thickness = 3.0f;
+ linestyle->thickness_position = LS_THICKNESS_CENTER;
+ linestyle->thickness_ratio = 0.5f;
+ linestyle->flag = LS_SAME_OBJECT | LS_NO_SORTING | LS_TEXTURE;
+ linestyle->chaining = LS_CHAINING_PLAIN;
+ linestyle->rounds = 3;
+ linestyle->min_angle = DEG2RADF(0.0f);
+ linestyle->max_angle = DEG2RADF(0.0f);
+ linestyle->min_length = 0.0f;
+ linestyle->max_length = 10000.0f;
+ linestyle->split_length = 100;
+ linestyle->chain_count = 10;
+ linestyle->sort_key = LS_SORT_KEY_DISTANCE_FROM_CAMERA;
+ linestyle->integration_type = LS_INTEGRATION_MEAN;
+ linestyle->texstep = 1.0f;
+ linestyle->pr_texture = TEX_PR_TEXTURE;
+
+ BLI_listbase_clear(&linestyle->color_modifiers);
+ BLI_listbase_clear(&linestyle->alpha_modifiers);
+ BLI_listbase_clear(&linestyle->thickness_modifiers);
+ BLI_listbase_clear(&linestyle->geometry_modifiers);
+
+ BKE_linestyle_geometry_modifier_add(linestyle, NULL, LS_MODIFIER_SAMPLING);
+
+ linestyle->caps = LS_CAPS_BUTT;
}
FreestyleLineStyle *BKE_linestyle_new(struct Main *bmain, const char *name)
{
- FreestyleLineStyle *linestyle;
+ FreestyleLineStyle *linestyle;
- linestyle = (FreestyleLineStyle *)BKE_libblock_alloc(bmain, ID_LS, name, 0);
+ linestyle = (FreestyleLineStyle *)BKE_libblock_alloc(bmain, ID_LS, name, 0);
- BKE_linestyle_init(linestyle);
+ BKE_linestyle_init(linestyle);
- return linestyle;
+ return linestyle;
}
/** Free (or release) any data used by this linestyle (does not free the linestyle itself). */
void BKE_linestyle_free(FreestyleLineStyle *linestyle)
{
- LineStyleModifier *m;
- int a;
-
- BKE_animdata_free(&linestyle->id, false);
-
- for (a = 0; a < MAX_MTEX; a++) {
- MEM_SAFE_FREE(linestyle->mtex[a]);
- }
-
- /* is no lib link block, but linestyle extension */
- if (linestyle->nodetree) {
- ntreeFreeNestedTree(linestyle->nodetree);
- MEM_freeN(linestyle->nodetree);
- linestyle->nodetree = NULL;
- }
-
- while ((m = (LineStyleModifier *)linestyle->color_modifiers.first))
- BKE_linestyle_color_modifier_remove(linestyle, m);
- while ((m = (LineStyleModifier *)linestyle->alpha_modifiers.first))
- BKE_linestyle_alpha_modifier_remove(linestyle, m);
- while ((m = (LineStyleModifier *)linestyle->thickness_modifiers.first))
- BKE_linestyle_thickness_modifier_remove(linestyle, m);
- while ((m = (LineStyleModifier *)linestyle->geometry_modifiers.first))
- BKE_linestyle_geometry_modifier_remove(linestyle, m);
+ LineStyleModifier *m;
+ int a;
+
+ BKE_animdata_free(&linestyle->id, false);
+
+ for (a = 0; a < MAX_MTEX; a++) {
+ MEM_SAFE_FREE(linestyle->mtex[a]);
+ }
+
+ /* is no lib link block, but linestyle extension */
+ if (linestyle->nodetree) {
+ ntreeFreeNestedTree(linestyle->nodetree);
+ MEM_freeN(linestyle->nodetree);
+ linestyle->nodetree = NULL;
+ }
+
+ while ((m = (LineStyleModifier *)linestyle->color_modifiers.first))
+ BKE_linestyle_color_modifier_remove(linestyle, m);
+ while ((m = (LineStyleModifier *)linestyle->alpha_modifiers.first))
+ BKE_linestyle_alpha_modifier_remove(linestyle, m);
+ while ((m = (LineStyleModifier *)linestyle->thickness_modifiers.first))
+ BKE_linestyle_thickness_modifier_remove(linestyle, m);
+ while ((m = (LineStyleModifier *)linestyle->geometry_modifiers.first))
+ BKE_linestyle_geometry_modifier_remove(linestyle, m);
}
/**
@@ -154,1332 +154,1316 @@ void BKE_linestyle_free(FreestyleLineStyle *linestyle)
*
* \param flag: Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
*/
-void BKE_linestyle_copy_data(
- struct Main *bmain, FreestyleLineStyle *linestyle_dst, const FreestyleLineStyle *linestyle_src, const int flag)
+void BKE_linestyle_copy_data(struct Main *bmain,
+ FreestyleLineStyle *linestyle_dst,
+ const FreestyleLineStyle *linestyle_src,
+ const int flag)
{
- /* We never handle usercount here for own data. */
- const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
-
- for (int a = 0; a < MAX_MTEX; a++) {
- if (linestyle_src->mtex[a]) {
- linestyle_dst->mtex[a] = MEM_mallocN(sizeof(*linestyle_dst->mtex[a]), __func__);
- *linestyle_dst->mtex[a] = *linestyle_src->mtex[a];
- }
- }
-
- if (linestyle_src->nodetree) {
- /* Note: nodetree is *not* in bmain, however this specific case is handled at lower level
- * (see BKE_libblock_copy_ex()). */
- BKE_id_copy_ex(bmain, (ID *)linestyle_src->nodetree, (ID **)&linestyle_dst->nodetree, flag);
- }
-
- LineStyleModifier *m;
- BLI_listbase_clear(&linestyle_dst->color_modifiers);
- for (m = (LineStyleModifier *)linestyle_src->color_modifiers.first; m; m = m->next) {
- BKE_linestyle_color_modifier_copy(linestyle_dst, m, flag_subdata);
- }
- BLI_listbase_clear(&linestyle_dst->alpha_modifiers);
- for (m = (LineStyleModifier *)linestyle_src->alpha_modifiers.first; m; m = m->next) {
- BKE_linestyle_alpha_modifier_copy(linestyle_dst, m, flag_subdata);
- }
- BLI_listbase_clear(&linestyle_dst->thickness_modifiers);
- for (m = (LineStyleModifier *)linestyle_src->thickness_modifiers.first; m; m = m->next) {
- BKE_linestyle_thickness_modifier_copy(linestyle_dst, m, flag_subdata);
- }
- BLI_listbase_clear(&linestyle_dst->geometry_modifiers);
- for (m = (LineStyleModifier *)linestyle_src->geometry_modifiers.first; m; m = m->next) {
- BKE_linestyle_geometry_modifier_copy(linestyle_dst, m, flag_subdata);
- }
+ /* We never handle usercount here for own data. */
+ const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
+
+ for (int a = 0; a < MAX_MTEX; a++) {
+ if (linestyle_src->mtex[a]) {
+ linestyle_dst->mtex[a] = MEM_mallocN(sizeof(*linestyle_dst->mtex[a]), __func__);
+ *linestyle_dst->mtex[a] = *linestyle_src->mtex[a];
+ }
+ }
+
+ if (linestyle_src->nodetree) {
+ /* Note: nodetree is *not* in bmain, however this specific case is handled at lower level
+ * (see BKE_libblock_copy_ex()). */
+ BKE_id_copy_ex(bmain, (ID *)linestyle_src->nodetree, (ID **)&linestyle_dst->nodetree, flag);
+ }
+
+ LineStyleModifier *m;
+ BLI_listbase_clear(&linestyle_dst->color_modifiers);
+ for (m = (LineStyleModifier *)linestyle_src->color_modifiers.first; m; m = m->next) {
+ BKE_linestyle_color_modifier_copy(linestyle_dst, m, flag_subdata);
+ }
+ BLI_listbase_clear(&linestyle_dst->alpha_modifiers);
+ for (m = (LineStyleModifier *)linestyle_src->alpha_modifiers.first; m; m = m->next) {
+ BKE_linestyle_alpha_modifier_copy(linestyle_dst, m, flag_subdata);
+ }
+ BLI_listbase_clear(&linestyle_dst->thickness_modifiers);
+ for (m = (LineStyleModifier *)linestyle_src->thickness_modifiers.first; m; m = m->next) {
+ BKE_linestyle_thickness_modifier_copy(linestyle_dst, m, flag_subdata);
+ }
+ BLI_listbase_clear(&linestyle_dst->geometry_modifiers);
+ for (m = (LineStyleModifier *)linestyle_src->geometry_modifiers.first; m; m = m->next) {
+ BKE_linestyle_geometry_modifier_copy(linestyle_dst, m, flag_subdata);
+ }
}
FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, const FreestyleLineStyle *linestyle)
{
- FreestyleLineStyle *linestyle_copy;
- BKE_id_copy(bmain, &linestyle->id, (ID **)&linestyle_copy);
- return linestyle_copy;
+ FreestyleLineStyle *linestyle_copy;
+ BKE_id_copy(bmain, &linestyle->id, (ID **)&linestyle_copy);
+ return linestyle_copy;
}
-void BKE_linestyle_make_local(struct Main *bmain, FreestyleLineStyle *linestyle, const bool lib_local)
+void BKE_linestyle_make_local(struct Main *bmain,
+ FreestyleLineStyle *linestyle,
+ const bool lib_local)
{
- BKE_id_make_local_generic(bmain, &linestyle->id, true, lib_local);
+ BKE_id_make_local_generic(bmain, &linestyle->id, true, lib_local);
}
FreestyleLineStyle *BKE_linestyle_active_from_view_layer(ViewLayer *view_layer)
{
- FreestyleConfig *config = &view_layer->freestyle_config;
- FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(config);
- return (lineset) ? lineset->linestyle : NULL;
+ FreestyleConfig *config = &view_layer->freestyle_config;
+ FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(config);
+ return (lineset) ? lineset->linestyle : NULL;
}
static LineStyleModifier *new_modifier(const char *name, int type, size_t size)
{
- LineStyleModifier *m;
-
- if (!name) {
- name = modifier_name[type];
- }
- m = (LineStyleModifier *)MEM_callocN(size, "line style modifier");
- m->type = type;
- BLI_strncpy(m->name, name, sizeof(m->name));
- m->influence = 1.0f;
- m->flags = LS_MODIFIER_ENABLED | LS_MODIFIER_EXPANDED;
-
- return m;
+ LineStyleModifier *m;
+
+ if (!name) {
+ name = modifier_name[type];
+ }
+ m = (LineStyleModifier *)MEM_callocN(size, "line style modifier");
+ m->type = type;
+ BLI_strncpy(m->name, name, sizeof(m->name));
+ m->influence = 1.0f;
+ m->flags = LS_MODIFIER_ENABLED | LS_MODIFIER_EXPANDED;
+
+ return m;
}
static void add_to_modifier_list(ListBase *lb, LineStyleModifier *m)
{
- BLI_addtail(lb, (void *)m);
- BLI_uniquename(lb, m, modifier_name[m->type], '.', offsetof(LineStyleModifier, name), sizeof(m->name));
+ BLI_addtail(lb, (void *)m);
+ BLI_uniquename(
+ lb, m, modifier_name[m->type], '.', offsetof(LineStyleModifier, name), sizeof(m->name));
}
static LineStyleModifier *alloc_color_modifier(const char *name, int type)
{
- size_t size;
-
- switch (type) {
- case LS_MODIFIER_ALONG_STROKE:
- size = sizeof(LineStyleColorModifier_AlongStroke);
- break;
- case LS_MODIFIER_DISTANCE_FROM_CAMERA:
- size = sizeof(LineStyleColorModifier_DistanceFromCamera);
- break;
- case LS_MODIFIER_DISTANCE_FROM_OBJECT:
- size = sizeof(LineStyleColorModifier_DistanceFromObject);
- break;
- case LS_MODIFIER_MATERIAL:
- size = sizeof(LineStyleColorModifier_Material);
- break;
- case LS_MODIFIER_TANGENT:
- size = sizeof(LineStyleColorModifier_Tangent);
- break;
- case LS_MODIFIER_NOISE:
- size = sizeof(LineStyleColorModifier_Noise);
- break;
- case LS_MODIFIER_CREASE_ANGLE:
- size = sizeof(LineStyleColorModifier_CreaseAngle);
- break;
- case LS_MODIFIER_CURVATURE_3D:
- size = sizeof(LineStyleColorModifier_Curvature_3D);
- break;
- default:
- return NULL; /* unknown modifier type */
- }
-
- return new_modifier(name, type, size);
+ size_t size;
+
+ switch (type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ size = sizeof(LineStyleColorModifier_AlongStroke);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ size = sizeof(LineStyleColorModifier_DistanceFromCamera);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ size = sizeof(LineStyleColorModifier_DistanceFromObject);
+ break;
+ case LS_MODIFIER_MATERIAL:
+ size = sizeof(LineStyleColorModifier_Material);
+ break;
+ case LS_MODIFIER_TANGENT:
+ size = sizeof(LineStyleColorModifier_Tangent);
+ break;
+ case LS_MODIFIER_NOISE:
+ size = sizeof(LineStyleColorModifier_Noise);
+ break;
+ case LS_MODIFIER_CREASE_ANGLE:
+ size = sizeof(LineStyleColorModifier_CreaseAngle);
+ break;
+ case LS_MODIFIER_CURVATURE_3D:
+ size = sizeof(LineStyleColorModifier_Curvature_3D);
+ break;
+ default:
+ return NULL; /* unknown modifier type */
+ }
+
+ return new_modifier(name, type, size);
}
-LineStyleModifier *BKE_linestyle_color_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type)
+LineStyleModifier *BKE_linestyle_color_modifier_add(FreestyleLineStyle *linestyle,
+ const char *name,
+ int type)
{
- LineStyleModifier *m;
-
- m = alloc_color_modifier(name, type);
- if (UNLIKELY(m == NULL)) {
- return NULL;
- }
- m->blend = MA_RAMP_BLEND;
-
- switch (type) {
- case LS_MODIFIER_ALONG_STROKE:
- ((LineStyleColorModifier_AlongStroke *)m)->color_ramp = BKE_colorband_add(true);
- break;
- case LS_MODIFIER_DISTANCE_FROM_CAMERA:
- ((LineStyleColorModifier_DistanceFromCamera *)m)->color_ramp = BKE_colorband_add(true);
- ((LineStyleColorModifier_DistanceFromCamera *)m)->range_min = 0.0f;
- ((LineStyleColorModifier_DistanceFromCamera *)m)->range_max = 10000.0f;
- break;
- case LS_MODIFIER_DISTANCE_FROM_OBJECT:
- ((LineStyleColorModifier_DistanceFromObject *)m)->target = NULL;
- ((LineStyleColorModifier_DistanceFromObject *)m)->color_ramp = BKE_colorband_add(true);
- ((LineStyleColorModifier_DistanceFromObject *)m)->range_min = 0.0f;
- ((LineStyleColorModifier_DistanceFromObject *)m)->range_max = 10000.0f;
- break;
- case LS_MODIFIER_MATERIAL:
- ((LineStyleColorModifier_Material *)m)->color_ramp = BKE_colorband_add(true);
- ((LineStyleColorModifier_Material *)m)->mat_attr = LS_MODIFIER_MATERIAL_LINE;
- break;
- case LS_MODIFIER_TANGENT:
- ((LineStyleColorModifier_Tangent *)m)->color_ramp = BKE_colorband_add(true);
- break;
- case LS_MODIFIER_NOISE:
- ((LineStyleColorModifier_Noise *)m)->color_ramp = BKE_colorband_add(true);
- ((LineStyleColorModifier_Noise *)m)->amplitude = 10.0f;
- ((LineStyleColorModifier_Noise *)m)->period = 10.0f;
- ((LineStyleColorModifier_Noise *)m)->seed = 512;
- break;
- case LS_MODIFIER_CREASE_ANGLE:
- ((LineStyleColorModifier_CreaseAngle *)m)->color_ramp = BKE_colorband_add(true);
- ((LineStyleColorModifier_CreaseAngle *)m)->min_angle = 0.0f;
- ((LineStyleColorModifier_CreaseAngle *)m)->max_angle = DEG2RADF(180.0f);
- break;
- case LS_MODIFIER_CURVATURE_3D:
- ((LineStyleColorModifier_Curvature_3D *)m)->color_ramp = BKE_colorband_add(true);
- ((LineStyleColorModifier_Curvature_3D *)m)->min_curvature = 0.0f;
- ((LineStyleColorModifier_Curvature_3D *)m)->max_curvature = 0.5f;
- break;
- default:
- return NULL; /* unknown modifier type */
- }
- add_to_modifier_list(&linestyle->color_modifiers, m);
-
- return m;
+ LineStyleModifier *m;
+
+ m = alloc_color_modifier(name, type);
+ if (UNLIKELY(m == NULL)) {
+ return NULL;
+ }
+ m->blend = MA_RAMP_BLEND;
+
+ switch (type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ ((LineStyleColorModifier_AlongStroke *)m)->color_ramp = BKE_colorband_add(true);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ ((LineStyleColorModifier_DistanceFromCamera *)m)->color_ramp = BKE_colorband_add(true);
+ ((LineStyleColorModifier_DistanceFromCamera *)m)->range_min = 0.0f;
+ ((LineStyleColorModifier_DistanceFromCamera *)m)->range_max = 10000.0f;
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ ((LineStyleColorModifier_DistanceFromObject *)m)->target = NULL;
+ ((LineStyleColorModifier_DistanceFromObject *)m)->color_ramp = BKE_colorband_add(true);
+ ((LineStyleColorModifier_DistanceFromObject *)m)->range_min = 0.0f;
+ ((LineStyleColorModifier_DistanceFromObject *)m)->range_max = 10000.0f;
+ break;
+ case LS_MODIFIER_MATERIAL:
+ ((LineStyleColorModifier_Material *)m)->color_ramp = BKE_colorband_add(true);
+ ((LineStyleColorModifier_Material *)m)->mat_attr = LS_MODIFIER_MATERIAL_LINE;
+ break;
+ case LS_MODIFIER_TANGENT:
+ ((LineStyleColorModifier_Tangent *)m)->color_ramp = BKE_colorband_add(true);
+ break;
+ case LS_MODIFIER_NOISE:
+ ((LineStyleColorModifier_Noise *)m)->color_ramp = BKE_colorband_add(true);
+ ((LineStyleColorModifier_Noise *)m)->amplitude = 10.0f;
+ ((LineStyleColorModifier_Noise *)m)->period = 10.0f;
+ ((LineStyleColorModifier_Noise *)m)->seed = 512;
+ break;
+ case LS_MODIFIER_CREASE_ANGLE:
+ ((LineStyleColorModifier_CreaseAngle *)m)->color_ramp = BKE_colorband_add(true);
+ ((LineStyleColorModifier_CreaseAngle *)m)->min_angle = 0.0f;
+ ((LineStyleColorModifier_CreaseAngle *)m)->max_angle = DEG2RADF(180.0f);
+ break;
+ case LS_MODIFIER_CURVATURE_3D:
+ ((LineStyleColorModifier_Curvature_3D *)m)->color_ramp = BKE_colorband_add(true);
+ ((LineStyleColorModifier_Curvature_3D *)m)->min_curvature = 0.0f;
+ ((LineStyleColorModifier_Curvature_3D *)m)->max_curvature = 0.5f;
+ break;
+ default:
+ return NULL; /* unknown modifier type */
+ }
+ add_to_modifier_list(&linestyle->color_modifiers, m);
+
+ return m;
}
-LineStyleModifier *BKE_linestyle_color_modifier_copy(
- FreestyleLineStyle *linestyle, const LineStyleModifier *m, const int flag)
+LineStyleModifier *BKE_linestyle_color_modifier_copy(FreestyleLineStyle *linestyle,
+ const LineStyleModifier *m,
+ const int flag)
{
- LineStyleModifier *new_m;
-
- new_m = alloc_color_modifier(m->name, m->type);
- if (UNLIKELY(new_m == NULL)) {
- return NULL;
- }
- new_m->influence = m->influence;
- new_m->flags = m->flags;
- new_m->blend = m->blend;
-
- switch (m->type) {
- case LS_MODIFIER_ALONG_STROKE:
- {
- LineStyleColorModifier_AlongStroke *p = (LineStyleColorModifier_AlongStroke *)m;
- LineStyleColorModifier_AlongStroke *q = (LineStyleColorModifier_AlongStroke *)new_m;
- q->color_ramp = MEM_dupallocN(p->color_ramp);
- break;
- }
- case LS_MODIFIER_DISTANCE_FROM_CAMERA:
- {
- LineStyleColorModifier_DistanceFromCamera *p = (LineStyleColorModifier_DistanceFromCamera *)m;
- LineStyleColorModifier_DistanceFromCamera *q = (LineStyleColorModifier_DistanceFromCamera *)new_m;
- q->color_ramp = MEM_dupallocN(p->color_ramp);
- q->range_min = p->range_min;
- q->range_max = p->range_max;
- break;
- }
- case LS_MODIFIER_DISTANCE_FROM_OBJECT:
- {
- LineStyleColorModifier_DistanceFromObject *p = (LineStyleColorModifier_DistanceFromObject *)m;
- LineStyleColorModifier_DistanceFromObject *q = (LineStyleColorModifier_DistanceFromObject *)new_m;
- q->target = p->target;
- if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- id_us_plus((ID *)q->target);
- }
- q->color_ramp = MEM_dupallocN(p->color_ramp);
- q->range_min = p->range_min;
- q->range_max = p->range_max;
- break;
- }
- case LS_MODIFIER_MATERIAL:
- {
- LineStyleColorModifier_Material *p = (LineStyleColorModifier_Material *)m;
- LineStyleColorModifier_Material *q = (LineStyleColorModifier_Material *)new_m;
- q->color_ramp = MEM_dupallocN(p->color_ramp);
- q->flags = p->flags;
- q->mat_attr = p->mat_attr;
- break;
- }
- case LS_MODIFIER_TANGENT:
- {
- LineStyleColorModifier_Tangent *p = (LineStyleColorModifier_Tangent *)m;
- LineStyleColorModifier_Tangent *q = (LineStyleColorModifier_Tangent *)new_m;
- q->color_ramp = MEM_dupallocN(p->color_ramp);
- break;
- }
- case LS_MODIFIER_NOISE:
- {
- LineStyleColorModifier_Noise *p = (LineStyleColorModifier_Noise *)m;
- LineStyleColorModifier_Noise *q = (LineStyleColorModifier_Noise *)new_m;
- q->color_ramp = MEM_dupallocN(p->color_ramp);
- q->amplitude = p->amplitude;
- q->period = p->period;
- q->seed = p->seed;
- break;
- }
- case LS_MODIFIER_CREASE_ANGLE:
- {
- LineStyleColorModifier_CreaseAngle *p = (LineStyleColorModifier_CreaseAngle *)m;
- LineStyleColorModifier_CreaseAngle *q = (LineStyleColorModifier_CreaseAngle *)new_m;
- q->color_ramp = MEM_dupallocN(p->color_ramp);
- q->min_angle = p->min_angle;
- q->max_angle = p->max_angle;
- break;
- }
- case LS_MODIFIER_CURVATURE_3D:
- {
- LineStyleColorModifier_Curvature_3D *p = (LineStyleColorModifier_Curvature_3D *)m;
- LineStyleColorModifier_Curvature_3D *q = (LineStyleColorModifier_Curvature_3D *)new_m;
- q->color_ramp = MEM_dupallocN(p->color_ramp);
- q->min_curvature = p->min_curvature;
- q->max_curvature = p->max_curvature;
- break;
- }
- default:
- return NULL; /* unknown modifier type */
- }
- add_to_modifier_list(&linestyle->color_modifiers, new_m);
-
- return new_m;
+ LineStyleModifier *new_m;
+
+ new_m = alloc_color_modifier(m->name, m->type);
+ if (UNLIKELY(new_m == NULL)) {
+ return NULL;
+ }
+ new_m->influence = m->influence;
+ new_m->flags = m->flags;
+ new_m->blend = m->blend;
+
+ switch (m->type) {
+ case LS_MODIFIER_ALONG_STROKE: {
+ LineStyleColorModifier_AlongStroke *p = (LineStyleColorModifier_AlongStroke *)m;
+ LineStyleColorModifier_AlongStroke *q = (LineStyleColorModifier_AlongStroke *)new_m;
+ q->color_ramp = MEM_dupallocN(p->color_ramp);
+ break;
+ }
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA: {
+ LineStyleColorModifier_DistanceFromCamera *p = (LineStyleColorModifier_DistanceFromCamera *)
+ m;
+ LineStyleColorModifier_DistanceFromCamera *q = (LineStyleColorModifier_DistanceFromCamera *)
+ new_m;
+ q->color_ramp = MEM_dupallocN(p->color_ramp);
+ q->range_min = p->range_min;
+ q->range_max = p->range_max;
+ break;
+ }
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT: {
+ LineStyleColorModifier_DistanceFromObject *p = (LineStyleColorModifier_DistanceFromObject *)
+ m;
+ LineStyleColorModifier_DistanceFromObject *q = (LineStyleColorModifier_DistanceFromObject *)
+ new_m;
+ q->target = p->target;
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id_us_plus((ID *)q->target);
+ }
+ q->color_ramp = MEM_dupallocN(p->color_ramp);
+ q->range_min = p->range_min;
+ q->range_max = p->range_max;
+ break;
+ }
+ case LS_MODIFIER_MATERIAL: {
+ LineStyleColorModifier_Material *p = (LineStyleColorModifier_Material *)m;
+ LineStyleColorModifier_Material *q = (LineStyleColorModifier_Material *)new_m;
+ q->color_ramp = MEM_dupallocN(p->color_ramp);
+ q->flags = p->flags;
+ q->mat_attr = p->mat_attr;
+ break;
+ }
+ case LS_MODIFIER_TANGENT: {
+ LineStyleColorModifier_Tangent *p = (LineStyleColorModifier_Tangent *)m;
+ LineStyleColorModifier_Tangent *q = (LineStyleColorModifier_Tangent *)new_m;
+ q->color_ramp = MEM_dupallocN(p->color_ramp);
+ break;
+ }
+ case LS_MODIFIER_NOISE: {
+ LineStyleColorModifier_Noise *p = (LineStyleColorModifier_Noise *)m;
+ LineStyleColorModifier_Noise *q = (LineStyleColorModifier_Noise *)new_m;
+ q->color_ramp = MEM_dupallocN(p->color_ramp);
+ q->amplitude = p->amplitude;
+ q->period = p->period;
+ q->seed = p->seed;
+ break;
+ }
+ case LS_MODIFIER_CREASE_ANGLE: {
+ LineStyleColorModifier_CreaseAngle *p = (LineStyleColorModifier_CreaseAngle *)m;
+ LineStyleColorModifier_CreaseAngle *q = (LineStyleColorModifier_CreaseAngle *)new_m;
+ q->color_ramp = MEM_dupallocN(p->color_ramp);
+ q->min_angle = p->min_angle;
+ q->max_angle = p->max_angle;
+ break;
+ }
+ case LS_MODIFIER_CURVATURE_3D: {
+ LineStyleColorModifier_Curvature_3D *p = (LineStyleColorModifier_Curvature_3D *)m;
+ LineStyleColorModifier_Curvature_3D *q = (LineStyleColorModifier_Curvature_3D *)new_m;
+ q->color_ramp = MEM_dupallocN(p->color_ramp);
+ q->min_curvature = p->min_curvature;
+ q->max_curvature = p->max_curvature;
+ break;
+ }
+ default:
+ return NULL; /* unknown modifier type */
+ }
+ add_to_modifier_list(&linestyle->color_modifiers, new_m);
+
+ return new_m;
}
int BKE_linestyle_color_modifier_remove(FreestyleLineStyle *linestyle, LineStyleModifier *m)
{
- if (BLI_findindex(&linestyle->color_modifiers, m) == -1)
- return -1;
- switch (m->type) {
- case LS_MODIFIER_ALONG_STROKE:
- MEM_freeN(((LineStyleColorModifier_AlongStroke *)m)->color_ramp);
- break;
- case LS_MODIFIER_DISTANCE_FROM_CAMERA:
- MEM_freeN(((LineStyleColorModifier_DistanceFromCamera *)m)->color_ramp);
- break;
- case LS_MODIFIER_DISTANCE_FROM_OBJECT:
- MEM_freeN(((LineStyleColorModifier_DistanceFromObject *)m)->color_ramp);
- break;
- case LS_MODIFIER_MATERIAL:
- MEM_freeN(((LineStyleColorModifier_Material *)m)->color_ramp);
- break;
- case LS_MODIFIER_TANGENT:
- MEM_freeN(((LineStyleColorModifier_Tangent *)m)->color_ramp);
- break;
- case LS_MODIFIER_NOISE:
- MEM_freeN(((LineStyleColorModifier_Noise *)m)->color_ramp);
- break;
- case LS_MODIFIER_CREASE_ANGLE:
- MEM_freeN(((LineStyleColorModifier_CreaseAngle *)m)->color_ramp);
- break;
- case LS_MODIFIER_CURVATURE_3D:
- MEM_freeN(((LineStyleColorModifier_Curvature_3D *)m)->color_ramp);
- break;
- }
- BLI_freelinkN(&linestyle->color_modifiers, m);
- return 0;
+ if (BLI_findindex(&linestyle->color_modifiers, m) == -1)
+ return -1;
+ switch (m->type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ MEM_freeN(((LineStyleColorModifier_AlongStroke *)m)->color_ramp);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ MEM_freeN(((LineStyleColorModifier_DistanceFromCamera *)m)->color_ramp);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ MEM_freeN(((LineStyleColorModifier_DistanceFromObject *)m)->color_ramp);
+ break;
+ case LS_MODIFIER_MATERIAL:
+ MEM_freeN(((LineStyleColorModifier_Material *)m)->color_ramp);
+ break;
+ case LS_MODIFIER_TANGENT:
+ MEM_freeN(((LineStyleColorModifier_Tangent *)m)->color_ramp);
+ break;
+ case LS_MODIFIER_NOISE:
+ MEM_freeN(((LineStyleColorModifier_Noise *)m)->color_ramp);
+ break;
+ case LS_MODIFIER_CREASE_ANGLE:
+ MEM_freeN(((LineStyleColorModifier_CreaseAngle *)m)->color_ramp);
+ break;
+ case LS_MODIFIER_CURVATURE_3D:
+ MEM_freeN(((LineStyleColorModifier_Curvature_3D *)m)->color_ramp);
+ break;
+ }
+ BLI_freelinkN(&linestyle->color_modifiers, m);
+ return 0;
}
static LineStyleModifier *alloc_alpha_modifier(const char *name, int type)
{
- size_t size;
-
- switch (type) {
- case LS_MODIFIER_ALONG_STROKE:
- size = sizeof(LineStyleAlphaModifier_AlongStroke);
- break;
- case LS_MODIFIER_DISTANCE_FROM_CAMERA:
- size = sizeof(LineStyleAlphaModifier_DistanceFromCamera);
- break;
- case LS_MODIFIER_DISTANCE_FROM_OBJECT:
- size = sizeof(LineStyleAlphaModifier_DistanceFromObject);
- break;
- case LS_MODIFIER_MATERIAL:
- size = sizeof(LineStyleAlphaModifier_Material);
- break;
- case LS_MODIFIER_TANGENT:
- size = sizeof(LineStyleAlphaModifier_Tangent);
- break;
- case LS_MODIFIER_NOISE:
- size = sizeof(LineStyleAlphaModifier_Noise);
- break;
- case LS_MODIFIER_CREASE_ANGLE:
- size = sizeof(LineStyleAlphaModifier_CreaseAngle);
- break;
- case LS_MODIFIER_CURVATURE_3D:
- size = sizeof(LineStyleAlphaModifier_Curvature_3D);
- break;
- default:
- return NULL; /* unknown modifier type */
- }
- return new_modifier(name, type, size);
+ size_t size;
+
+ switch (type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ size = sizeof(LineStyleAlphaModifier_AlongStroke);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ size = sizeof(LineStyleAlphaModifier_DistanceFromCamera);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ size = sizeof(LineStyleAlphaModifier_DistanceFromObject);
+ break;
+ case LS_MODIFIER_MATERIAL:
+ size = sizeof(LineStyleAlphaModifier_Material);
+ break;
+ case LS_MODIFIER_TANGENT:
+ size = sizeof(LineStyleAlphaModifier_Tangent);
+ break;
+ case LS_MODIFIER_NOISE:
+ size = sizeof(LineStyleAlphaModifier_Noise);
+ break;
+ case LS_MODIFIER_CREASE_ANGLE:
+ size = sizeof(LineStyleAlphaModifier_CreaseAngle);
+ break;
+ case LS_MODIFIER_CURVATURE_3D:
+ size = sizeof(LineStyleAlphaModifier_Curvature_3D);
+ break;
+ default:
+ return NULL; /* unknown modifier type */
+ }
+ return new_modifier(name, type, size);
}
-LineStyleModifier *BKE_linestyle_alpha_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type)
+LineStyleModifier *BKE_linestyle_alpha_modifier_add(FreestyleLineStyle *linestyle,
+ const char *name,
+ int type)
{
- LineStyleModifier *m;
-
- m = alloc_alpha_modifier(name, type);
- m->blend = LS_VALUE_BLEND;
-
- switch (type) {
- case LS_MODIFIER_ALONG_STROKE:
- {
- LineStyleAlphaModifier_AlongStroke *p = (LineStyleAlphaModifier_AlongStroke *)m;
- p->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
- break;
- }
- case LS_MODIFIER_DISTANCE_FROM_CAMERA:
- {
- LineStyleAlphaModifier_DistanceFromCamera *p = (LineStyleAlphaModifier_DistanceFromCamera *)m;
- p->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
- p->range_min = 0.0f;
- p->range_max = 10000.0f;
- break;
- }
- case LS_MODIFIER_DISTANCE_FROM_OBJECT:
- {
- LineStyleAlphaModifier_DistanceFromObject *p = (LineStyleAlphaModifier_DistanceFromObject *)m;
- p->target = NULL;
- p->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
- p->range_min = 0.0f;
- p->range_max = 10000.0f;
- break;
- }
- case LS_MODIFIER_MATERIAL:
- {
- LineStyleAlphaModifier_Material *p = (LineStyleAlphaModifier_Material *)m;
- p->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
- p->mat_attr = LS_MODIFIER_MATERIAL_LINE_A;
- break;
- }
- case LS_MODIFIER_TANGENT:
- {
- LineStyleAlphaModifier_Tangent *p = (LineStyleAlphaModifier_Tangent *)m;
- p->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
- break;
- }
- case LS_MODIFIER_NOISE:
- {
- LineStyleAlphaModifier_Noise *p = (LineStyleAlphaModifier_Noise *)m;
- p->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
- ((LineStyleAlphaModifier_Noise *)m)->amplitude = 10.0f;
- ((LineStyleAlphaModifier_Noise *)m)->period = 10.0f;
- ((LineStyleAlphaModifier_Noise *)m)->seed = 512;
- break;
- }
- case LS_MODIFIER_CREASE_ANGLE:
- {
- LineStyleAlphaModifier_CreaseAngle *p = (LineStyleAlphaModifier_CreaseAngle *)m;
- p->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
- ((LineStyleAlphaModifier_CreaseAngle *)m)->min_angle = 0.0f;
- ((LineStyleAlphaModifier_CreaseAngle *)m)->max_angle = DEG2RADF(180.0f);
- break;
- }
- case LS_MODIFIER_CURVATURE_3D:
- {
- LineStyleAlphaModifier_Curvature_3D *p = (LineStyleAlphaModifier_Curvature_3D *)m;
- p->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
- ((LineStyleAlphaModifier_Curvature_3D *)m)->min_curvature = 0.0f;
- ((LineStyleAlphaModifier_Curvature_3D *)m)->max_curvature = 0.5f;
- break;
- }
- default:
- return NULL; /* unknown modifier type */
- }
- add_to_modifier_list(&linestyle->alpha_modifiers, m);
-
- return m;
+ LineStyleModifier *m;
+
+ m = alloc_alpha_modifier(name, type);
+ m->blend = LS_VALUE_BLEND;
+
+ switch (type) {
+ case LS_MODIFIER_ALONG_STROKE: {
+ LineStyleAlphaModifier_AlongStroke *p = (LineStyleAlphaModifier_AlongStroke *)m;
+ p->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ break;
+ }
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA: {
+ LineStyleAlphaModifier_DistanceFromCamera *p = (LineStyleAlphaModifier_DistanceFromCamera *)
+ m;
+ p->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ p->range_min = 0.0f;
+ p->range_max = 10000.0f;
+ break;
+ }
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT: {
+ LineStyleAlphaModifier_DistanceFromObject *p = (LineStyleAlphaModifier_DistanceFromObject *)
+ m;
+ p->target = NULL;
+ p->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ p->range_min = 0.0f;
+ p->range_max = 10000.0f;
+ break;
+ }
+ case LS_MODIFIER_MATERIAL: {
+ LineStyleAlphaModifier_Material *p = (LineStyleAlphaModifier_Material *)m;
+ p->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ p->mat_attr = LS_MODIFIER_MATERIAL_LINE_A;
+ break;
+ }
+ case LS_MODIFIER_TANGENT: {
+ LineStyleAlphaModifier_Tangent *p = (LineStyleAlphaModifier_Tangent *)m;
+ p->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ break;
+ }
+ case LS_MODIFIER_NOISE: {
+ LineStyleAlphaModifier_Noise *p = (LineStyleAlphaModifier_Noise *)m;
+ p->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ ((LineStyleAlphaModifier_Noise *)m)->amplitude = 10.0f;
+ ((LineStyleAlphaModifier_Noise *)m)->period = 10.0f;
+ ((LineStyleAlphaModifier_Noise *)m)->seed = 512;
+ break;
+ }
+ case LS_MODIFIER_CREASE_ANGLE: {
+ LineStyleAlphaModifier_CreaseAngle *p = (LineStyleAlphaModifier_CreaseAngle *)m;
+ p->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ ((LineStyleAlphaModifier_CreaseAngle *)m)->min_angle = 0.0f;
+ ((LineStyleAlphaModifier_CreaseAngle *)m)->max_angle = DEG2RADF(180.0f);
+ break;
+ }
+ case LS_MODIFIER_CURVATURE_3D: {
+ LineStyleAlphaModifier_Curvature_3D *p = (LineStyleAlphaModifier_Curvature_3D *)m;
+ p->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ ((LineStyleAlphaModifier_Curvature_3D *)m)->min_curvature = 0.0f;
+ ((LineStyleAlphaModifier_Curvature_3D *)m)->max_curvature = 0.5f;
+ break;
+ }
+ default:
+ return NULL; /* unknown modifier type */
+ }
+ add_to_modifier_list(&linestyle->alpha_modifiers, m);
+
+ return m;
}
-LineStyleModifier *BKE_linestyle_alpha_modifier_copy(
- FreestyleLineStyle *linestyle, const LineStyleModifier *m, const int UNUSED(flag))
+LineStyleModifier *BKE_linestyle_alpha_modifier_copy(FreestyleLineStyle *linestyle,
+ const LineStyleModifier *m,
+ const int UNUSED(flag))
{
- LineStyleModifier *new_m;
-
- new_m = alloc_alpha_modifier(m->name, m->type);
- new_m->influence = m->influence;
- new_m->flags = m->flags;
- new_m->blend = m->blend;
-
- switch (m->type) {
- case LS_MODIFIER_ALONG_STROKE:
- {
- LineStyleAlphaModifier_AlongStroke *p = (LineStyleAlphaModifier_AlongStroke *)m;
- LineStyleAlphaModifier_AlongStroke *q = (LineStyleAlphaModifier_AlongStroke *)new_m;
- q->curve = curvemapping_copy(p->curve);
- q->flags = p->flags;
- break;
- }
- case LS_MODIFIER_DISTANCE_FROM_CAMERA:
- {
- LineStyleAlphaModifier_DistanceFromCamera *p = (LineStyleAlphaModifier_DistanceFromCamera *)m;
- LineStyleAlphaModifier_DistanceFromCamera *q = (LineStyleAlphaModifier_DistanceFromCamera *)new_m;
- q->curve = curvemapping_copy(p->curve);
- q->flags = p->flags;
- q->range_min = p->range_min;
- q->range_max = p->range_max;
- break;
- }
- case LS_MODIFIER_DISTANCE_FROM_OBJECT:
- {
- LineStyleAlphaModifier_DistanceFromObject *p = (LineStyleAlphaModifier_DistanceFromObject *)m;
- LineStyleAlphaModifier_DistanceFromObject *q = (LineStyleAlphaModifier_DistanceFromObject *)new_m;
- if (p->target)
- id_us_plus(&p->target->id);
- q->target = p->target;
- q->curve = curvemapping_copy(p->curve);
- q->flags = p->flags;
- q->range_min = p->range_min;
- q->range_max = p->range_max;
- break;
- }
- case LS_MODIFIER_MATERIAL:
- {
- LineStyleAlphaModifier_Material *p = (LineStyleAlphaModifier_Material *)m;
- LineStyleAlphaModifier_Material *q = (LineStyleAlphaModifier_Material *)new_m;
- q->curve = curvemapping_copy(p->curve);
- q->flags = p->flags;
- q->mat_attr = p->mat_attr;
- break;
- }
- case LS_MODIFIER_TANGENT:
- {
- LineStyleAlphaModifier_Tangent *p = (LineStyleAlphaModifier_Tangent *)m;
- LineStyleAlphaModifier_Tangent *q = (LineStyleAlphaModifier_Tangent *)new_m;
- q->curve = curvemapping_copy(p->curve);
- q->flags = p->flags;
- break;
- }
- case LS_MODIFIER_NOISE:
- {
- LineStyleAlphaModifier_Noise *p = (LineStyleAlphaModifier_Noise *)m;
- LineStyleAlphaModifier_Noise *q = (LineStyleAlphaModifier_Noise *)new_m;
- q->curve = curvemapping_copy(p->curve);
- q->flags = p->flags;
- q->amplitude = p->amplitude;
- q->period = p->period;
- q->seed = p->seed;
- break;
- }
- case LS_MODIFIER_CREASE_ANGLE:
- {
- LineStyleAlphaModifier_CreaseAngle *p = (LineStyleAlphaModifier_CreaseAngle *)m;
- LineStyleAlphaModifier_CreaseAngle *q = (LineStyleAlphaModifier_CreaseAngle *)new_m;
- q->curve = curvemapping_copy(p->curve);
- q->flags = p->flags;
- q->min_angle = p->min_angle;
- q->max_angle = p->max_angle;
- break;
- }
- case LS_MODIFIER_CURVATURE_3D:
- {
- LineStyleAlphaModifier_Curvature_3D *p = (LineStyleAlphaModifier_Curvature_3D *)m;
- LineStyleAlphaModifier_Curvature_3D *q = (LineStyleAlphaModifier_Curvature_3D *)new_m;
- q->curve = curvemapping_copy(p->curve);
- q->flags = p->flags;
- q->min_curvature = p->min_curvature;
- q->max_curvature = p->max_curvature;
- break;
- }
- default:
- return NULL; /* unknown modifier type */
- }
- add_to_modifier_list(&linestyle->alpha_modifiers, new_m);
-
- return new_m;
+ LineStyleModifier *new_m;
+
+ new_m = alloc_alpha_modifier(m->name, m->type);
+ new_m->influence = m->influence;
+ new_m->flags = m->flags;
+ new_m->blend = m->blend;
+
+ switch (m->type) {
+ case LS_MODIFIER_ALONG_STROKE: {
+ LineStyleAlphaModifier_AlongStroke *p = (LineStyleAlphaModifier_AlongStroke *)m;
+ LineStyleAlphaModifier_AlongStroke *q = (LineStyleAlphaModifier_AlongStroke *)new_m;
+ q->curve = curvemapping_copy(p->curve);
+ q->flags = p->flags;
+ break;
+ }
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA: {
+ LineStyleAlphaModifier_DistanceFromCamera *p = (LineStyleAlphaModifier_DistanceFromCamera *)
+ m;
+ LineStyleAlphaModifier_DistanceFromCamera *q = (LineStyleAlphaModifier_DistanceFromCamera *)
+ new_m;
+ q->curve = curvemapping_copy(p->curve);
+ q->flags = p->flags;
+ q->range_min = p->range_min;
+ q->range_max = p->range_max;
+ break;
+ }
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT: {
+ LineStyleAlphaModifier_DistanceFromObject *p = (LineStyleAlphaModifier_DistanceFromObject *)
+ m;
+ LineStyleAlphaModifier_DistanceFromObject *q = (LineStyleAlphaModifier_DistanceFromObject *)
+ new_m;
+ if (p->target)
+ id_us_plus(&p->target->id);
+ q->target = p->target;
+ q->curve = curvemapping_copy(p->curve);
+ q->flags = p->flags;
+ q->range_min = p->range_min;
+ q->range_max = p->range_max;
+ break;
+ }
+ case LS_MODIFIER_MATERIAL: {
+ LineStyleAlphaModifier_Material *p = (LineStyleAlphaModifier_Material *)m;
+ LineStyleAlphaModifier_Material *q = (LineStyleAlphaModifier_Material *)new_m;
+ q->curve = curvemapping_copy(p->curve);
+ q->flags = p->flags;
+ q->mat_attr = p->mat_attr;
+ break;
+ }
+ case LS_MODIFIER_TANGENT: {
+ LineStyleAlphaModifier_Tangent *p = (LineStyleAlphaModifier_Tangent *)m;
+ LineStyleAlphaModifier_Tangent *q = (LineStyleAlphaModifier_Tangent *)new_m;
+ q->curve = curvemapping_copy(p->curve);
+ q->flags = p->flags;
+ break;
+ }
+ case LS_MODIFIER_NOISE: {
+ LineStyleAlphaModifier_Noise *p = (LineStyleAlphaModifier_Noise *)m;
+ LineStyleAlphaModifier_Noise *q = (LineStyleAlphaModifier_Noise *)new_m;
+ q->curve = curvemapping_copy(p->curve);
+ q->flags = p->flags;
+ q->amplitude = p->amplitude;
+ q->period = p->period;
+ q->seed = p->seed;
+ break;
+ }
+ case LS_MODIFIER_CREASE_ANGLE: {
+ LineStyleAlphaModifier_CreaseAngle *p = (LineStyleAlphaModifier_CreaseAngle *)m;
+ LineStyleAlphaModifier_CreaseAngle *q = (LineStyleAlphaModifier_CreaseAngle *)new_m;
+ q->curve = curvemapping_copy(p->curve);
+ q->flags = p->flags;
+ q->min_angle = p->min_angle;
+ q->max_angle = p->max_angle;
+ break;
+ }
+ case LS_MODIFIER_CURVATURE_3D: {
+ LineStyleAlphaModifier_Curvature_3D *p = (LineStyleAlphaModifier_Curvature_3D *)m;
+ LineStyleAlphaModifier_Curvature_3D *q = (LineStyleAlphaModifier_Curvature_3D *)new_m;
+ q->curve = curvemapping_copy(p->curve);
+ q->flags = p->flags;
+ q->min_curvature = p->min_curvature;
+ q->max_curvature = p->max_curvature;
+ break;
+ }
+ default:
+ return NULL; /* unknown modifier type */
+ }
+ add_to_modifier_list(&linestyle->alpha_modifiers, new_m);
+
+ return new_m;
}
int BKE_linestyle_alpha_modifier_remove(FreestyleLineStyle *linestyle, LineStyleModifier *m)
{
- if (BLI_findindex(&linestyle->alpha_modifiers, m) == -1)
- return -1;
- switch (m->type) {
- case LS_MODIFIER_ALONG_STROKE:
- curvemapping_free(((LineStyleAlphaModifier_AlongStroke *)m)->curve);
- break;
- case LS_MODIFIER_DISTANCE_FROM_CAMERA:
- curvemapping_free(((LineStyleAlphaModifier_DistanceFromCamera *)m)->curve);
- break;
- case LS_MODIFIER_DISTANCE_FROM_OBJECT:
- curvemapping_free(((LineStyleAlphaModifier_DistanceFromObject *)m)->curve);
- break;
- case LS_MODIFIER_MATERIAL:
- curvemapping_free(((LineStyleAlphaModifier_Material *)m)->curve);
- break;
- case LS_MODIFIER_TANGENT:
- curvemapping_free(((LineStyleAlphaModifier_Tangent *)m)->curve);
- break;
- case LS_MODIFIER_NOISE:
- curvemapping_free(((LineStyleAlphaModifier_Noise *)m)->curve);
- break;
- case LS_MODIFIER_CREASE_ANGLE:
- curvemapping_free(((LineStyleAlphaModifier_CreaseAngle *)m)->curve);
- break;
- case LS_MODIFIER_CURVATURE_3D:
- curvemapping_free(((LineStyleAlphaModifier_Curvature_3D *)m)->curve);
- break;
- }
- BLI_freelinkN(&linestyle->alpha_modifiers, m);
- return 0;
+ if (BLI_findindex(&linestyle->alpha_modifiers, m) == -1)
+ return -1;
+ switch (m->type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ curvemapping_free(((LineStyleAlphaModifier_AlongStroke *)m)->curve);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ curvemapping_free(((LineStyleAlphaModifier_DistanceFromCamera *)m)->curve);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ curvemapping_free(((LineStyleAlphaModifier_DistanceFromObject *)m)->curve);
+ break;
+ case LS_MODIFIER_MATERIAL:
+ curvemapping_free(((LineStyleAlphaModifier_Material *)m)->curve);
+ break;
+ case LS_MODIFIER_TANGENT:
+ curvemapping_free(((LineStyleAlphaModifier_Tangent *)m)->curve);
+ break;
+ case LS_MODIFIER_NOISE:
+ curvemapping_free(((LineStyleAlphaModifier_Noise *)m)->curve);
+ break;
+ case LS_MODIFIER_CREASE_ANGLE:
+ curvemapping_free(((LineStyleAlphaModifier_CreaseAngle *)m)->curve);
+ break;
+ case LS_MODIFIER_CURVATURE_3D:
+ curvemapping_free(((LineStyleAlphaModifier_Curvature_3D *)m)->curve);
+ break;
+ }
+ BLI_freelinkN(&linestyle->alpha_modifiers, m);
+ return 0;
}
static LineStyleModifier *alloc_thickness_modifier(const char *name, int type)
{
- size_t size;
-
- switch (type) {
- case LS_MODIFIER_ALONG_STROKE:
- size = sizeof(LineStyleThicknessModifier_AlongStroke);
- break;
- case LS_MODIFIER_DISTANCE_FROM_CAMERA:
- size = sizeof(LineStyleThicknessModifier_DistanceFromCamera);
- break;
- case LS_MODIFIER_DISTANCE_FROM_OBJECT:
- size = sizeof(LineStyleThicknessModifier_DistanceFromObject);
- break;
- case LS_MODIFIER_MATERIAL:
- size = sizeof(LineStyleThicknessModifier_Material);
- break;
- case LS_MODIFIER_CALLIGRAPHY:
- size = sizeof(LineStyleThicknessModifier_Calligraphy);
- break;
- case LS_MODIFIER_TANGENT:
- size = sizeof(LineStyleThicknessModifier_Tangent);
- break;
- case LS_MODIFIER_NOISE:
- size = sizeof(LineStyleThicknessModifier_Noise);
- break;
- case LS_MODIFIER_CREASE_ANGLE:
- size = sizeof(LineStyleThicknessModifier_CreaseAngle);
- break;
- case LS_MODIFIER_CURVATURE_3D:
- size = sizeof(LineStyleThicknessModifier_Curvature_3D);
- break;
- default:
- return NULL; /* unknown modifier type */
- }
-
- return new_modifier(name, type, size);
+ size_t size;
+
+ switch (type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ size = sizeof(LineStyleThicknessModifier_AlongStroke);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ size = sizeof(LineStyleThicknessModifier_DistanceFromCamera);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ size = sizeof(LineStyleThicknessModifier_DistanceFromObject);
+ break;
+ case LS_MODIFIER_MATERIAL:
+ size = sizeof(LineStyleThicknessModifier_Material);
+ break;
+ case LS_MODIFIER_CALLIGRAPHY:
+ size = sizeof(LineStyleThicknessModifier_Calligraphy);
+ break;
+ case LS_MODIFIER_TANGENT:
+ size = sizeof(LineStyleThicknessModifier_Tangent);
+ break;
+ case LS_MODIFIER_NOISE:
+ size = sizeof(LineStyleThicknessModifier_Noise);
+ break;
+ case LS_MODIFIER_CREASE_ANGLE:
+ size = sizeof(LineStyleThicknessModifier_CreaseAngle);
+ break;
+ case LS_MODIFIER_CURVATURE_3D:
+ size = sizeof(LineStyleThicknessModifier_Curvature_3D);
+ break;
+ default:
+ return NULL; /* unknown modifier type */
+ }
+
+ return new_modifier(name, type, size);
}
-LineStyleModifier *BKE_linestyle_thickness_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type)
+LineStyleModifier *BKE_linestyle_thickness_modifier_add(FreestyleLineStyle *linestyle,
+ const char *name,
+ int type)
{
- LineStyleModifier *m;
-
- m = alloc_thickness_modifier(name, type);
- m->blend = LS_VALUE_BLEND;
-
- switch (type) {
- case LS_MODIFIER_ALONG_STROKE:
- {
- LineStyleThicknessModifier_AlongStroke *p = (LineStyleThicknessModifier_AlongStroke *)m;
- p->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
- p->value_min = 0.0f;
- p->value_max = 1.0f;
- break;
- }
- case LS_MODIFIER_DISTANCE_FROM_CAMERA:
- {
- LineStyleThicknessModifier_DistanceFromCamera *p = (LineStyleThicknessModifier_DistanceFromCamera *)m;
- p->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
- p->range_min = 0.0f;
- p->range_max = 1000.0f;
- p->value_min = 0.0f;
- p->value_max = 1.0f;
- break;
- }
- case LS_MODIFIER_DISTANCE_FROM_OBJECT:
- {
- LineStyleThicknessModifier_DistanceFromObject *p = (LineStyleThicknessModifier_DistanceFromObject *)m;
- p->target = NULL;
- p->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
- p->range_min = 0.0f;
- p->range_max = 1000.0f;
- p->value_min = 0.0f;
- p->value_max = 1.0f;
- break;
- }
- case LS_MODIFIER_MATERIAL:
- {
- LineStyleThicknessModifier_Material *p = (LineStyleThicknessModifier_Material *)m;
- p->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
- p->mat_attr = LS_MODIFIER_MATERIAL_LINE;
- p->value_min = 0.0f;
- p->value_max = 1.0f;
- break;
- }
- case LS_MODIFIER_CALLIGRAPHY:
- {
- LineStyleThicknessModifier_Calligraphy *p = (LineStyleThicknessModifier_Calligraphy *)m;
- p->min_thickness = 1.0f;
- p->max_thickness = 10.0f;
- p->orientation = DEG2RADF(60.0f);
- break;
- }
- case LS_MODIFIER_TANGENT:
- {
- LineStyleThicknessModifier_Tangent *p = (LineStyleThicknessModifier_Tangent *)m;
- p->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
- p->min_thickness = 1.0f;
- p->max_thickness = 10.0f;
- break;
- }
- case LS_MODIFIER_NOISE:
- {
- LineStyleThicknessModifier_Noise *p = (LineStyleThicknessModifier_Noise *)m;
- p->period = 10.0f;
- p->amplitude = 10.0f;
- p->seed = 512;
- p->flags = LS_THICKNESS_ASYMMETRIC;
- break;
- }
- case LS_MODIFIER_CREASE_ANGLE:
- {
- LineStyleThicknessModifier_CreaseAngle *p = (LineStyleThicknessModifier_CreaseAngle *)m;
- p->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
- p->min_angle = 0.0f;
- p->max_angle = DEG2RADF(180.0f);
- p->min_thickness = 1.0f;
- p->max_thickness = 10.0f;
- break;
- }
- case LS_MODIFIER_CURVATURE_3D:
- {
- LineStyleThicknessModifier_Curvature_3D *p = (LineStyleThicknessModifier_Curvature_3D *)m;
- p->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
- p->min_curvature = 0.0f;
- p->max_curvature = 0.5f;
- p->min_thickness = 1.0f;
- p->max_thickness = 10.0f;
- break;
- }
- default:
- return NULL; /* unknown modifier type */
- }
- add_to_modifier_list(&linestyle->thickness_modifiers, m);
-
- return m;
+ LineStyleModifier *m;
+
+ m = alloc_thickness_modifier(name, type);
+ m->blend = LS_VALUE_BLEND;
+
+ switch (type) {
+ case LS_MODIFIER_ALONG_STROKE: {
+ LineStyleThicknessModifier_AlongStroke *p = (LineStyleThicknessModifier_AlongStroke *)m;
+ p->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ p->value_min = 0.0f;
+ p->value_max = 1.0f;
+ break;
+ }
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA: {
+ LineStyleThicknessModifier_DistanceFromCamera *p =
+ (LineStyleThicknessModifier_DistanceFromCamera *)m;
+ p->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ p->range_min = 0.0f;
+ p->range_max = 1000.0f;
+ p->value_min = 0.0f;
+ p->value_max = 1.0f;
+ break;
+ }
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT: {
+ LineStyleThicknessModifier_DistanceFromObject *p =
+ (LineStyleThicknessModifier_DistanceFromObject *)m;
+ p->target = NULL;
+ p->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ p->range_min = 0.0f;
+ p->range_max = 1000.0f;
+ p->value_min = 0.0f;
+ p->value_max = 1.0f;
+ break;
+ }
+ case LS_MODIFIER_MATERIAL: {
+ LineStyleThicknessModifier_Material *p = (LineStyleThicknessModifier_Material *)m;
+ p->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ p->mat_attr = LS_MODIFIER_MATERIAL_LINE;
+ p->value_min = 0.0f;
+ p->value_max = 1.0f;
+ break;
+ }
+ case LS_MODIFIER_CALLIGRAPHY: {
+ LineStyleThicknessModifier_Calligraphy *p = (LineStyleThicknessModifier_Calligraphy *)m;
+ p->min_thickness = 1.0f;
+ p->max_thickness = 10.0f;
+ p->orientation = DEG2RADF(60.0f);
+ break;
+ }
+ case LS_MODIFIER_TANGENT: {
+ LineStyleThicknessModifier_Tangent *p = (LineStyleThicknessModifier_Tangent *)m;
+ p->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ p->min_thickness = 1.0f;
+ p->max_thickness = 10.0f;
+ break;
+ }
+ case LS_MODIFIER_NOISE: {
+ LineStyleThicknessModifier_Noise *p = (LineStyleThicknessModifier_Noise *)m;
+ p->period = 10.0f;
+ p->amplitude = 10.0f;
+ p->seed = 512;
+ p->flags = LS_THICKNESS_ASYMMETRIC;
+ break;
+ }
+ case LS_MODIFIER_CREASE_ANGLE: {
+ LineStyleThicknessModifier_CreaseAngle *p = (LineStyleThicknessModifier_CreaseAngle *)m;
+ p->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ p->min_angle = 0.0f;
+ p->max_angle = DEG2RADF(180.0f);
+ p->min_thickness = 1.0f;
+ p->max_thickness = 10.0f;
+ break;
+ }
+ case LS_MODIFIER_CURVATURE_3D: {
+ LineStyleThicknessModifier_Curvature_3D *p = (LineStyleThicknessModifier_Curvature_3D *)m;
+ p->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ p->min_curvature = 0.0f;
+ p->max_curvature = 0.5f;
+ p->min_thickness = 1.0f;
+ p->max_thickness = 10.0f;
+ break;
+ }
+ default:
+ return NULL; /* unknown modifier type */
+ }
+ add_to_modifier_list(&linestyle->thickness_modifiers, m);
+
+ return m;
}
-LineStyleModifier *BKE_linestyle_thickness_modifier_copy(
- FreestyleLineStyle *linestyle, const LineStyleModifier *m, const int flag)
+LineStyleModifier *BKE_linestyle_thickness_modifier_copy(FreestyleLineStyle *linestyle,
+ const LineStyleModifier *m,
+ const int flag)
{
- LineStyleModifier *new_m;
-
- new_m = alloc_thickness_modifier(m->name, m->type);
- if (!new_m)
- return NULL;
- new_m->influence = m->influence;
- new_m->flags = m->flags;
- new_m->blend = m->blend;
-
- switch (m->type) {
- case LS_MODIFIER_ALONG_STROKE:
- {
- LineStyleThicknessModifier_AlongStroke *p = (LineStyleThicknessModifier_AlongStroke *)m;
- LineStyleThicknessModifier_AlongStroke *q = (LineStyleThicknessModifier_AlongStroke *)new_m;
- q->curve = curvemapping_copy(p->curve);
- q->flags = p->flags;
- q->value_min = p->value_min;
- q->value_max = p->value_max;
- break;
- }
- case LS_MODIFIER_DISTANCE_FROM_CAMERA:
- {
- LineStyleThicknessModifier_DistanceFromCamera *p = (LineStyleThicknessModifier_DistanceFromCamera *)m;
- LineStyleThicknessModifier_DistanceFromCamera *q = (LineStyleThicknessModifier_DistanceFromCamera *)new_m;
- q->curve = curvemapping_copy(p->curve);
- q->flags = p->flags;
- q->range_min = p->range_min;
- q->range_max = p->range_max;
- q->value_min = p->value_min;
- q->value_max = p->value_max;
- break;
- }
- case LS_MODIFIER_DISTANCE_FROM_OBJECT:
- {
- LineStyleThicknessModifier_DistanceFromObject *p = (LineStyleThicknessModifier_DistanceFromObject *)m;
- LineStyleThicknessModifier_DistanceFromObject *q = (LineStyleThicknessModifier_DistanceFromObject *)new_m;
- q->target = p->target;
- if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- id_us_plus((ID *)q->target);
- }
- q->curve = curvemapping_copy(p->curve);
- q->flags = p->flags;
- q->range_min = p->range_min;
- q->range_max = p->range_max;
- q->value_min = p->value_min;
- q->value_max = p->value_max;
- break;
- }
- case LS_MODIFIER_MATERIAL:
- {
- LineStyleThicknessModifier_Material *p = (LineStyleThicknessModifier_Material *)m;
- LineStyleThicknessModifier_Material *q = (LineStyleThicknessModifier_Material *)new_m;
- q->curve = curvemapping_copy(p->curve);
- q->flags = p->flags;
- q->mat_attr = p->mat_attr;
- q->value_min = p->value_min;
- q->value_max = p->value_max;
- break;
- }
- case LS_MODIFIER_CALLIGRAPHY:
- {
- LineStyleThicknessModifier_Calligraphy *p = (LineStyleThicknessModifier_Calligraphy *)m;
- LineStyleThicknessModifier_Calligraphy *q = (LineStyleThicknessModifier_Calligraphy *)new_m;
- q->min_thickness = p->min_thickness;
- q->max_thickness = p->max_thickness;
- q->orientation = p->orientation;
- break;
- }
- case LS_MODIFIER_TANGENT:
- {
- LineStyleThicknessModifier_Tangent *p = (LineStyleThicknessModifier_Tangent *)m;
- LineStyleThicknessModifier_Tangent *q = (LineStyleThicknessModifier_Tangent *)new_m;
- q->curve = curvemapping_copy(p->curve);
- q->flags = p->flags;
- q->min_thickness = p->min_thickness;
- q->max_thickness = p->max_thickness;
- break;
- }
- case LS_MODIFIER_NOISE:
- {
- LineStyleThicknessModifier_Noise *p = (LineStyleThicknessModifier_Noise *)m;
- LineStyleThicknessModifier_Noise *q = (LineStyleThicknessModifier_Noise *)new_m;
- q->amplitude = p->amplitude;
- q->period = p->period;
- q->seed = p->seed;
- q->flags = p->flags;
- break;
- }
- case LS_MODIFIER_CURVATURE_3D:
- {
- LineStyleThicknessModifier_Curvature_3D *p = (LineStyleThicknessModifier_Curvature_3D *)m;
- LineStyleThicknessModifier_Curvature_3D *q = (LineStyleThicknessModifier_Curvature_3D *)new_m;
- q->curve = curvemapping_copy(p->curve);
- q->flags = p->flags;
- q->min_curvature = p->min_curvature;
- q->max_curvature = p->max_curvature;
- q->min_thickness = p->min_thickness;
- q->max_thickness = p->max_thickness;
- break;
- }
- case LS_MODIFIER_CREASE_ANGLE:
- {
- LineStyleThicknessModifier_CreaseAngle *p = (LineStyleThicknessModifier_CreaseAngle *)m;
- LineStyleThicknessModifier_CreaseAngle *q = (LineStyleThicknessModifier_CreaseAngle *)new_m;
- q->curve = curvemapping_copy(p->curve);
- q->flags = p->flags;
- q->min_angle = p->min_angle;
- q->max_angle = p->max_angle;
- q->min_thickness = p->min_thickness;
- q->max_thickness = p->max_thickness;
- break;
- }
- default:
- return NULL; /* unknown modifier type */
- }
- add_to_modifier_list(&linestyle->thickness_modifiers, new_m);
-
- return new_m;
+ LineStyleModifier *new_m;
+
+ new_m = alloc_thickness_modifier(m->name, m->type);
+ if (!new_m)
+ return NULL;
+ new_m->influence = m->influence;
+ new_m->flags = m->flags;
+ new_m->blend = m->blend;
+
+ switch (m->type) {
+ case LS_MODIFIER_ALONG_STROKE: {
+ LineStyleThicknessModifier_AlongStroke *p = (LineStyleThicknessModifier_AlongStroke *)m;
+ LineStyleThicknessModifier_AlongStroke *q = (LineStyleThicknessModifier_AlongStroke *)new_m;
+ q->curve = curvemapping_copy(p->curve);
+ q->flags = p->flags;
+ q->value_min = p->value_min;
+ q->value_max = p->value_max;
+ break;
+ }
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA: {
+ LineStyleThicknessModifier_DistanceFromCamera *p =
+ (LineStyleThicknessModifier_DistanceFromCamera *)m;
+ LineStyleThicknessModifier_DistanceFromCamera *q =
+ (LineStyleThicknessModifier_DistanceFromCamera *)new_m;
+ q->curve = curvemapping_copy(p->curve);
+ q->flags = p->flags;
+ q->range_min = p->range_min;
+ q->range_max = p->range_max;
+ q->value_min = p->value_min;
+ q->value_max = p->value_max;
+ break;
+ }
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT: {
+ LineStyleThicknessModifier_DistanceFromObject *p =
+ (LineStyleThicknessModifier_DistanceFromObject *)m;
+ LineStyleThicknessModifier_DistanceFromObject *q =
+ (LineStyleThicknessModifier_DistanceFromObject *)new_m;
+ q->target = p->target;
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id_us_plus((ID *)q->target);
+ }
+ q->curve = curvemapping_copy(p->curve);
+ q->flags = p->flags;
+ q->range_min = p->range_min;
+ q->range_max = p->range_max;
+ q->value_min = p->value_min;
+ q->value_max = p->value_max;
+ break;
+ }
+ case LS_MODIFIER_MATERIAL: {
+ LineStyleThicknessModifier_Material *p = (LineStyleThicknessModifier_Material *)m;
+ LineStyleThicknessModifier_Material *q = (LineStyleThicknessModifier_Material *)new_m;
+ q->curve = curvemapping_copy(p->curve);
+ q->flags = p->flags;
+ q->mat_attr = p->mat_attr;
+ q->value_min = p->value_min;
+ q->value_max = p->value_max;
+ break;
+ }
+ case LS_MODIFIER_CALLIGRAPHY: {
+ LineStyleThicknessModifier_Calligraphy *p = (LineStyleThicknessModifier_Calligraphy *)m;
+ LineStyleThicknessModifier_Calligraphy *q = (LineStyleThicknessModifier_Calligraphy *)new_m;
+ q->min_thickness = p->min_thickness;
+ q->max_thickness = p->max_thickness;
+ q->orientation = p->orientation;
+ break;
+ }
+ case LS_MODIFIER_TANGENT: {
+ LineStyleThicknessModifier_Tangent *p = (LineStyleThicknessModifier_Tangent *)m;
+ LineStyleThicknessModifier_Tangent *q = (LineStyleThicknessModifier_Tangent *)new_m;
+ q->curve = curvemapping_copy(p->curve);
+ q->flags = p->flags;
+ q->min_thickness = p->min_thickness;
+ q->max_thickness = p->max_thickness;
+ break;
+ }
+ case LS_MODIFIER_NOISE: {
+ LineStyleThicknessModifier_Noise *p = (LineStyleThicknessModifier_Noise *)m;
+ LineStyleThicknessModifier_Noise *q = (LineStyleThicknessModifier_Noise *)new_m;
+ q->amplitude = p->amplitude;
+ q->period = p->period;
+ q->seed = p->seed;
+ q->flags = p->flags;
+ break;
+ }
+ case LS_MODIFIER_CURVATURE_3D: {
+ LineStyleThicknessModifier_Curvature_3D *p = (LineStyleThicknessModifier_Curvature_3D *)m;
+ LineStyleThicknessModifier_Curvature_3D *q = (LineStyleThicknessModifier_Curvature_3D *)
+ new_m;
+ q->curve = curvemapping_copy(p->curve);
+ q->flags = p->flags;
+ q->min_curvature = p->min_curvature;
+ q->max_curvature = p->max_curvature;
+ q->min_thickness = p->min_thickness;
+ q->max_thickness = p->max_thickness;
+ break;
+ }
+ case LS_MODIFIER_CREASE_ANGLE: {
+ LineStyleThicknessModifier_CreaseAngle *p = (LineStyleThicknessModifier_CreaseAngle *)m;
+ LineStyleThicknessModifier_CreaseAngle *q = (LineStyleThicknessModifier_CreaseAngle *)new_m;
+ q->curve = curvemapping_copy(p->curve);
+ q->flags = p->flags;
+ q->min_angle = p->min_angle;
+ q->max_angle = p->max_angle;
+ q->min_thickness = p->min_thickness;
+ q->max_thickness = p->max_thickness;
+ break;
+ }
+ default:
+ return NULL; /* unknown modifier type */
+ }
+ add_to_modifier_list(&linestyle->thickness_modifiers, new_m);
+
+ return new_m;
}
int BKE_linestyle_thickness_modifier_remove(FreestyleLineStyle *linestyle, LineStyleModifier *m)
{
- if (BLI_findindex(&linestyle->thickness_modifiers, m) == -1)
- return -1;
- switch (m->type) {
- case LS_MODIFIER_ALONG_STROKE:
- curvemapping_free(((LineStyleThicknessModifier_AlongStroke *)m)->curve);
- break;
- case LS_MODIFIER_DISTANCE_FROM_CAMERA:
- curvemapping_free(((LineStyleThicknessModifier_DistanceFromCamera *)m)->curve);
- break;
- case LS_MODIFIER_DISTANCE_FROM_OBJECT:
- curvemapping_free(((LineStyleThicknessModifier_DistanceFromObject *)m)->curve);
- break;
- case LS_MODIFIER_MATERIAL:
- curvemapping_free(((LineStyleThicknessModifier_Material *)m)->curve);
- break;
- case LS_MODIFIER_CALLIGRAPHY:
- break;
- case LS_MODIFIER_TANGENT:
- curvemapping_free(((LineStyleThicknessModifier_Tangent *)m)->curve);
- break;
- case LS_MODIFIER_NOISE:
- break;
- case LS_MODIFIER_CREASE_ANGLE:
- break;
- case LS_MODIFIER_CURVATURE_3D:
- break;
- }
- BLI_freelinkN(&linestyle->thickness_modifiers, m);
- return 0;
+ if (BLI_findindex(&linestyle->thickness_modifiers, m) == -1)
+ return -1;
+ switch (m->type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ curvemapping_free(((LineStyleThicknessModifier_AlongStroke *)m)->curve);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ curvemapping_free(((LineStyleThicknessModifier_DistanceFromCamera *)m)->curve);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ curvemapping_free(((LineStyleThicknessModifier_DistanceFromObject *)m)->curve);
+ break;
+ case LS_MODIFIER_MATERIAL:
+ curvemapping_free(((LineStyleThicknessModifier_Material *)m)->curve);
+ break;
+ case LS_MODIFIER_CALLIGRAPHY:
+ break;
+ case LS_MODIFIER_TANGENT:
+ curvemapping_free(((LineStyleThicknessModifier_Tangent *)m)->curve);
+ break;
+ case LS_MODIFIER_NOISE:
+ break;
+ case LS_MODIFIER_CREASE_ANGLE:
+ break;
+ case LS_MODIFIER_CURVATURE_3D:
+ break;
+ }
+ BLI_freelinkN(&linestyle->thickness_modifiers, m);
+ return 0;
}
static LineStyleModifier *alloc_geometry_modifier(const char *name, int type)
{
- size_t size;
-
- switch (type) {
- case LS_MODIFIER_SAMPLING:
- size = sizeof(LineStyleGeometryModifier_Sampling);
- break;
- case LS_MODIFIER_BEZIER_CURVE:
- size = sizeof(LineStyleGeometryModifier_BezierCurve);
- break;
- case LS_MODIFIER_SINUS_DISPLACEMENT:
- size = sizeof(LineStyleGeometryModifier_SinusDisplacement);
- break;
- case LS_MODIFIER_SPATIAL_NOISE:
- size = sizeof(LineStyleGeometryModifier_SpatialNoise);
- break;
- case LS_MODIFIER_PERLIN_NOISE_1D:
- size = sizeof(LineStyleGeometryModifier_PerlinNoise1D);
- break;
- case LS_MODIFIER_PERLIN_NOISE_2D:
- size = sizeof(LineStyleGeometryModifier_PerlinNoise2D);
- break;
- case LS_MODIFIER_BACKBONE_STRETCHER:
- size = sizeof(LineStyleGeometryModifier_BackboneStretcher);
- break;
- case LS_MODIFIER_TIP_REMOVER:
- size = sizeof(LineStyleGeometryModifier_TipRemover);
- break;
- case LS_MODIFIER_POLYGONIZATION:
- size = sizeof(LineStyleGeometryModifier_Polygonalization);
- break;
- case LS_MODIFIER_GUIDING_LINES:
- size = sizeof(LineStyleGeometryModifier_GuidingLines);
- break;
- case LS_MODIFIER_BLUEPRINT:
- size = sizeof(LineStyleGeometryModifier_Blueprint);
- break;
- case LS_MODIFIER_2D_OFFSET:
- size = sizeof(LineStyleGeometryModifier_2DOffset);
- break;
- case LS_MODIFIER_2D_TRANSFORM:
- size = sizeof(LineStyleGeometryModifier_2DTransform);
- break;
- case LS_MODIFIER_SIMPLIFICATION:
- size = sizeof(LineStyleGeometryModifier_Simplification);
- break;
- default:
- return NULL; /* unknown modifier type */
- }
-
- return new_modifier(name, type, size);
+ size_t size;
+
+ switch (type) {
+ case LS_MODIFIER_SAMPLING:
+ size = sizeof(LineStyleGeometryModifier_Sampling);
+ break;
+ case LS_MODIFIER_BEZIER_CURVE:
+ size = sizeof(LineStyleGeometryModifier_BezierCurve);
+ break;
+ case LS_MODIFIER_SINUS_DISPLACEMENT:
+ size = sizeof(LineStyleGeometryModifier_SinusDisplacement);
+ break;
+ case LS_MODIFIER_SPATIAL_NOISE:
+ size = sizeof(LineStyleGeometryModifier_SpatialNoise);
+ break;
+ case LS_MODIFIER_PERLIN_NOISE_1D:
+ size = sizeof(LineStyleGeometryModifier_PerlinNoise1D);
+ break;
+ case LS_MODIFIER_PERLIN_NOISE_2D:
+ size = sizeof(LineStyleGeometryModifier_PerlinNoise2D);
+ break;
+ case LS_MODIFIER_BACKBONE_STRETCHER:
+ size = sizeof(LineStyleGeometryModifier_BackboneStretcher);
+ break;
+ case LS_MODIFIER_TIP_REMOVER:
+ size = sizeof(LineStyleGeometryModifier_TipRemover);
+ break;
+ case LS_MODIFIER_POLYGONIZATION:
+ size = sizeof(LineStyleGeometryModifier_Polygonalization);
+ break;
+ case LS_MODIFIER_GUIDING_LINES:
+ size = sizeof(LineStyleGeometryModifier_GuidingLines);
+ break;
+ case LS_MODIFIER_BLUEPRINT:
+ size = sizeof(LineStyleGeometryModifier_Blueprint);
+ break;
+ case LS_MODIFIER_2D_OFFSET:
+ size = sizeof(LineStyleGeometryModifier_2DOffset);
+ break;
+ case LS_MODIFIER_2D_TRANSFORM:
+ size = sizeof(LineStyleGeometryModifier_2DTransform);
+ break;
+ case LS_MODIFIER_SIMPLIFICATION:
+ size = sizeof(LineStyleGeometryModifier_Simplification);
+ break;
+ default:
+ return NULL; /* unknown modifier type */
+ }
+
+ return new_modifier(name, type, size);
}
-LineStyleModifier *BKE_linestyle_geometry_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type)
+LineStyleModifier *BKE_linestyle_geometry_modifier_add(FreestyleLineStyle *linestyle,
+ const char *name,
+ int type)
{
- LineStyleModifier *m;
-
- m = alloc_geometry_modifier(name, type);
-
- switch (type) {
- case LS_MODIFIER_SAMPLING:
- {
- LineStyleGeometryModifier_Sampling *p = (LineStyleGeometryModifier_Sampling *)m;
- p->sampling = 10.0f;
- break;
- }
- case LS_MODIFIER_BEZIER_CURVE:
- {
- LineStyleGeometryModifier_BezierCurve *p = (LineStyleGeometryModifier_BezierCurve *)m;
- p->error = 10.0f;
- break;
- }
- case LS_MODIFIER_SINUS_DISPLACEMENT:
- {
- LineStyleGeometryModifier_SinusDisplacement *p = (LineStyleGeometryModifier_SinusDisplacement *)m;
- p->wavelength = 20.0f;
- p->amplitude = 5.0f;
- p->phase = 0.0f;
- break;
- }
- case LS_MODIFIER_SPATIAL_NOISE:
- {
- LineStyleGeometryModifier_SpatialNoise *p = (LineStyleGeometryModifier_SpatialNoise *)m;
- p->amplitude = 5.0f;
- p->scale = 20.0f;
- p->octaves = 4;
- p->flags = LS_MODIFIER_SPATIAL_NOISE_SMOOTH | LS_MODIFIER_SPATIAL_NOISE_PURERANDOM;
- break;
- }
- case LS_MODIFIER_PERLIN_NOISE_1D:
- {
- LineStyleGeometryModifier_PerlinNoise1D *p = (LineStyleGeometryModifier_PerlinNoise1D *)m;
- p->frequency = 10.0f;
- p->amplitude = 10.0f;
- p->octaves = 4;
- p->angle = DEG2RADF(45.0f);
- break;
- }
- case LS_MODIFIER_PERLIN_NOISE_2D:
- {
- LineStyleGeometryModifier_PerlinNoise2D *p = (LineStyleGeometryModifier_PerlinNoise2D *)m;
- p->frequency = 10.0f;
- p->amplitude = 10.0f;
- p->octaves = 4;
- p->angle = DEG2RADF(45.0f);
- break;
- }
- case LS_MODIFIER_BACKBONE_STRETCHER:
- {
- LineStyleGeometryModifier_BackboneStretcher *p = (LineStyleGeometryModifier_BackboneStretcher *)m;
- p->backbone_length = 10.0f;
- break;
- }
- case LS_MODIFIER_TIP_REMOVER:
- {
- LineStyleGeometryModifier_TipRemover *p = (LineStyleGeometryModifier_TipRemover *)m;
- p->tip_length = 10.0f;
- break;
- }
- case LS_MODIFIER_POLYGONIZATION:
- {
- LineStyleGeometryModifier_Polygonalization *p = (LineStyleGeometryModifier_Polygonalization *)m;
- p->error = 10.0f;
- break;
- }
- case LS_MODIFIER_GUIDING_LINES:
- {
- LineStyleGeometryModifier_GuidingLines *p = (LineStyleGeometryModifier_GuidingLines *)m;
- p->offset = 0.0f;
- break;
- }
- case LS_MODIFIER_BLUEPRINT:
- {
- LineStyleGeometryModifier_Blueprint *p = (LineStyleGeometryModifier_Blueprint *)m;
- p->flags = LS_MODIFIER_BLUEPRINT_CIRCLES;
- p->rounds = 1;
- p->backbone_length = 10.0f;
- p->random_radius = 3;
- p->random_center = 5;
- p->random_backbone = 5;
- break;
- }
- case LS_MODIFIER_2D_OFFSET:
- {
- LineStyleGeometryModifier_2DOffset *p = (LineStyleGeometryModifier_2DOffset *)m;
- p->start = 0.0f;
- p->end = 0.0f;
- p->x = 0.0f;
- p->y = 0.0f;
- break;
- }
- case LS_MODIFIER_2D_TRANSFORM:
- {
- LineStyleGeometryModifier_2DTransform *p = (LineStyleGeometryModifier_2DTransform *)m;
- p->pivot = LS_MODIFIER_2D_TRANSFORM_PIVOT_CENTER;
- p->scale_x = 1.0f;
- p->scale_y = 1.0f;
- p->angle = DEG2RADF(0.0f);
- p->pivot_u = 0.5f;
- p->pivot_x = 0.0f;
- p->pivot_y = 0.0f;
- break;
- }
- case LS_MODIFIER_SIMPLIFICATION:
- {
- LineStyleGeometryModifier_Simplification *p = (LineStyleGeometryModifier_Simplification *)m;
- p->tolerance = 0.1f;
- break;
- }
- default:
- return NULL; /* unknown modifier type */
- }
- add_to_modifier_list(&linestyle->geometry_modifiers, m);
-
- return m;
+ LineStyleModifier *m;
+
+ m = alloc_geometry_modifier(name, type);
+
+ switch (type) {
+ case LS_MODIFIER_SAMPLING: {
+ LineStyleGeometryModifier_Sampling *p = (LineStyleGeometryModifier_Sampling *)m;
+ p->sampling = 10.0f;
+ break;
+ }
+ case LS_MODIFIER_BEZIER_CURVE: {
+ LineStyleGeometryModifier_BezierCurve *p = (LineStyleGeometryModifier_BezierCurve *)m;
+ p->error = 10.0f;
+ break;
+ }
+ case LS_MODIFIER_SINUS_DISPLACEMENT: {
+ LineStyleGeometryModifier_SinusDisplacement *p =
+ (LineStyleGeometryModifier_SinusDisplacement *)m;
+ p->wavelength = 20.0f;
+ p->amplitude = 5.0f;
+ p->phase = 0.0f;
+ break;
+ }
+ case LS_MODIFIER_SPATIAL_NOISE: {
+ LineStyleGeometryModifier_SpatialNoise *p = (LineStyleGeometryModifier_SpatialNoise *)m;
+ p->amplitude = 5.0f;
+ p->scale = 20.0f;
+ p->octaves = 4;
+ p->flags = LS_MODIFIER_SPATIAL_NOISE_SMOOTH | LS_MODIFIER_SPATIAL_NOISE_PURERANDOM;
+ break;
+ }
+ case LS_MODIFIER_PERLIN_NOISE_1D: {
+ LineStyleGeometryModifier_PerlinNoise1D *p = (LineStyleGeometryModifier_PerlinNoise1D *)m;
+ p->frequency = 10.0f;
+ p->amplitude = 10.0f;
+ p->octaves = 4;
+ p->angle = DEG2RADF(45.0f);
+ break;
+ }
+ case LS_MODIFIER_PERLIN_NOISE_2D: {
+ LineStyleGeometryModifier_PerlinNoise2D *p = (LineStyleGeometryModifier_PerlinNoise2D *)m;
+ p->frequency = 10.0f;
+ p->amplitude = 10.0f;
+ p->octaves = 4;
+ p->angle = DEG2RADF(45.0f);
+ break;
+ }
+ case LS_MODIFIER_BACKBONE_STRETCHER: {
+ LineStyleGeometryModifier_BackboneStretcher *p =
+ (LineStyleGeometryModifier_BackboneStretcher *)m;
+ p->backbone_length = 10.0f;
+ break;
+ }
+ case LS_MODIFIER_TIP_REMOVER: {
+ LineStyleGeometryModifier_TipRemover *p = (LineStyleGeometryModifier_TipRemover *)m;
+ p->tip_length = 10.0f;
+ break;
+ }
+ case LS_MODIFIER_POLYGONIZATION: {
+ LineStyleGeometryModifier_Polygonalization *p =
+ (LineStyleGeometryModifier_Polygonalization *)m;
+ p->error = 10.0f;
+ break;
+ }
+ case LS_MODIFIER_GUIDING_LINES: {
+ LineStyleGeometryModifier_GuidingLines *p = (LineStyleGeometryModifier_GuidingLines *)m;
+ p->offset = 0.0f;
+ break;
+ }
+ case LS_MODIFIER_BLUEPRINT: {
+ LineStyleGeometryModifier_Blueprint *p = (LineStyleGeometryModifier_Blueprint *)m;
+ p->flags = LS_MODIFIER_BLUEPRINT_CIRCLES;
+ p->rounds = 1;
+ p->backbone_length = 10.0f;
+ p->random_radius = 3;
+ p->random_center = 5;
+ p->random_backbone = 5;
+ break;
+ }
+ case LS_MODIFIER_2D_OFFSET: {
+ LineStyleGeometryModifier_2DOffset *p = (LineStyleGeometryModifier_2DOffset *)m;
+ p->start = 0.0f;
+ p->end = 0.0f;
+ p->x = 0.0f;
+ p->y = 0.0f;
+ break;
+ }
+ case LS_MODIFIER_2D_TRANSFORM: {
+ LineStyleGeometryModifier_2DTransform *p = (LineStyleGeometryModifier_2DTransform *)m;
+ p->pivot = LS_MODIFIER_2D_TRANSFORM_PIVOT_CENTER;
+ p->scale_x = 1.0f;
+ p->scale_y = 1.0f;
+ p->angle = DEG2RADF(0.0f);
+ p->pivot_u = 0.5f;
+ p->pivot_x = 0.0f;
+ p->pivot_y = 0.0f;
+ break;
+ }
+ case LS_MODIFIER_SIMPLIFICATION: {
+ LineStyleGeometryModifier_Simplification *p = (LineStyleGeometryModifier_Simplification *)m;
+ p->tolerance = 0.1f;
+ break;
+ }
+ default:
+ return NULL; /* unknown modifier type */
+ }
+ add_to_modifier_list(&linestyle->geometry_modifiers, m);
+
+ return m;
}
-LineStyleModifier *BKE_linestyle_geometry_modifier_copy(
- FreestyleLineStyle *linestyle, const LineStyleModifier *m, const int UNUSED(flag))
+LineStyleModifier *BKE_linestyle_geometry_modifier_copy(FreestyleLineStyle *linestyle,
+ const LineStyleModifier *m,
+ const int UNUSED(flag))
{
- LineStyleModifier *new_m;
-
- new_m = alloc_geometry_modifier(m->name, m->type);
- new_m->flags = m->flags;
-
- switch (m->type) {
- case LS_MODIFIER_SAMPLING:
- {
- LineStyleGeometryModifier_Sampling *p = (LineStyleGeometryModifier_Sampling *)m;
- LineStyleGeometryModifier_Sampling *q = (LineStyleGeometryModifier_Sampling *)new_m;
- q->sampling = p->sampling;
- break;
- }
- case LS_MODIFIER_BEZIER_CURVE:
- {
- LineStyleGeometryModifier_BezierCurve *p = (LineStyleGeometryModifier_BezierCurve *)m;
- LineStyleGeometryModifier_BezierCurve *q = (LineStyleGeometryModifier_BezierCurve *)new_m;
- q->error = p->error;
- break;
- }
- case LS_MODIFIER_SINUS_DISPLACEMENT:
- {
- LineStyleGeometryModifier_SinusDisplacement *p = (LineStyleGeometryModifier_SinusDisplacement *)m;
- LineStyleGeometryModifier_SinusDisplacement *q = (LineStyleGeometryModifier_SinusDisplacement *)new_m;
- q->wavelength = p->wavelength;
- q->amplitude = p->amplitude;
- q->phase = p->phase;
- break;
- }
- case LS_MODIFIER_SPATIAL_NOISE:
- {
- LineStyleGeometryModifier_SpatialNoise *p = (LineStyleGeometryModifier_SpatialNoise *)m;
- LineStyleGeometryModifier_SpatialNoise *q = (LineStyleGeometryModifier_SpatialNoise *)new_m;
- q->amplitude = p->amplitude;
- q->scale = p->scale;
- q->octaves = p->octaves;
- q->flags = p->flags;
- break;
- }
- case LS_MODIFIER_PERLIN_NOISE_1D:
- {
- LineStyleGeometryModifier_PerlinNoise1D *p = (LineStyleGeometryModifier_PerlinNoise1D *)m;
- LineStyleGeometryModifier_PerlinNoise1D *q = (LineStyleGeometryModifier_PerlinNoise1D *)new_m;
- q->frequency = p->frequency;
- q->amplitude = p->amplitude;
- q->angle = p->angle;
- q->octaves = p->octaves;
- q->seed = p->seed;
- break;
- }
- case LS_MODIFIER_PERLIN_NOISE_2D:
- {
- LineStyleGeometryModifier_PerlinNoise2D *p = (LineStyleGeometryModifier_PerlinNoise2D *)m;
- LineStyleGeometryModifier_PerlinNoise2D *q = (LineStyleGeometryModifier_PerlinNoise2D *)new_m;
- q->frequency = p->frequency;
- q->amplitude = p->amplitude;
- q->angle = p->angle;
- q->octaves = p->octaves;
- q->seed = p->seed;
- break;
- }
- case LS_MODIFIER_BACKBONE_STRETCHER:
- {
- LineStyleGeometryModifier_BackboneStretcher *p = (LineStyleGeometryModifier_BackboneStretcher *)m;
- LineStyleGeometryModifier_BackboneStretcher *q = (LineStyleGeometryModifier_BackboneStretcher *)new_m;
- q->backbone_length = p->backbone_length;
- break;
- }
- case LS_MODIFIER_TIP_REMOVER:
- {
- LineStyleGeometryModifier_TipRemover *p = (LineStyleGeometryModifier_TipRemover *)m;
- LineStyleGeometryModifier_TipRemover *q = (LineStyleGeometryModifier_TipRemover *)new_m;
- q->tip_length = p->tip_length;
- break;
- }
- case LS_MODIFIER_POLYGONIZATION:
- {
- LineStyleGeometryModifier_Polygonalization *p = (LineStyleGeometryModifier_Polygonalization *)m;
- LineStyleGeometryModifier_Polygonalization *q = (LineStyleGeometryModifier_Polygonalization *)new_m;
- q->error = p->error;
- break;
- }
- case LS_MODIFIER_GUIDING_LINES:
- {
- LineStyleGeometryModifier_GuidingLines *p = (LineStyleGeometryModifier_GuidingLines *)m;
- LineStyleGeometryModifier_GuidingLines *q = (LineStyleGeometryModifier_GuidingLines *)new_m;
- q->offset = p->offset;
- break;
- }
- case LS_MODIFIER_BLUEPRINT:
- {
- LineStyleGeometryModifier_Blueprint *p = (LineStyleGeometryModifier_Blueprint *)m;
- LineStyleGeometryModifier_Blueprint *q = (LineStyleGeometryModifier_Blueprint *)new_m;
- q->flags = p->flags;
- q->rounds = p->rounds;
- q->backbone_length = p->backbone_length;
- q->random_radius = p->random_radius;
- q->random_center = p->random_center;
- q->random_backbone = p->random_backbone;
- break;
- }
- case LS_MODIFIER_2D_OFFSET:
- {
- LineStyleGeometryModifier_2DOffset *p = (LineStyleGeometryModifier_2DOffset *)m;
- LineStyleGeometryModifier_2DOffset *q = (LineStyleGeometryModifier_2DOffset *)new_m;
- q->start = p->start;
- q->end = p->end;
- q->x = p->x;
- q->y = p->y;
- break;
- }
- case LS_MODIFIER_2D_TRANSFORM:
- {
- LineStyleGeometryModifier_2DTransform *p = (LineStyleGeometryModifier_2DTransform *)m;
- LineStyleGeometryModifier_2DTransform *q = (LineStyleGeometryModifier_2DTransform *)new_m;
- q->pivot = p->pivot;
- q->scale_x = p->scale_x;
- q->scale_y = p->scale_y;
- q->angle = p->angle;
- q->pivot_u = p->pivot_u;
- q->pivot_x = p->pivot_x;
- q->pivot_y = p->pivot_y;
- break;
- }
- case LS_MODIFIER_SIMPLIFICATION:
- {
- LineStyleGeometryModifier_Simplification *p = (LineStyleGeometryModifier_Simplification *)m;
- LineStyleGeometryModifier_Simplification *q = (LineStyleGeometryModifier_Simplification *)new_m;
- q->tolerance = p->tolerance;
- break;
- }
- default:
- return NULL; /* unknown modifier type */
- }
- add_to_modifier_list(&linestyle->geometry_modifiers, new_m);
-
- return new_m;
+ LineStyleModifier *new_m;
+
+ new_m = alloc_geometry_modifier(m->name, m->type);
+ new_m->flags = m->flags;
+
+ switch (m->type) {
+ case LS_MODIFIER_SAMPLING: {
+ LineStyleGeometryModifier_Sampling *p = (LineStyleGeometryModifier_Sampling *)m;
+ LineStyleGeometryModifier_Sampling *q = (LineStyleGeometryModifier_Sampling *)new_m;
+ q->sampling = p->sampling;
+ break;
+ }
+ case LS_MODIFIER_BEZIER_CURVE: {
+ LineStyleGeometryModifier_BezierCurve *p = (LineStyleGeometryModifier_BezierCurve *)m;
+ LineStyleGeometryModifier_BezierCurve *q = (LineStyleGeometryModifier_BezierCurve *)new_m;
+ q->error = p->error;
+ break;
+ }
+ case LS_MODIFIER_SINUS_DISPLACEMENT: {
+ LineStyleGeometryModifier_SinusDisplacement *p =
+ (LineStyleGeometryModifier_SinusDisplacement *)m;
+ LineStyleGeometryModifier_SinusDisplacement *q =
+ (LineStyleGeometryModifier_SinusDisplacement *)new_m;
+ q->wavelength = p->wavelength;
+ q->amplitude = p->amplitude;
+ q->phase = p->phase;
+ break;
+ }
+ case LS_MODIFIER_SPATIAL_NOISE: {
+ LineStyleGeometryModifier_SpatialNoise *p = (LineStyleGeometryModifier_SpatialNoise *)m;
+ LineStyleGeometryModifier_SpatialNoise *q = (LineStyleGeometryModifier_SpatialNoise *)new_m;
+ q->amplitude = p->amplitude;
+ q->scale = p->scale;
+ q->octaves = p->octaves;
+ q->flags = p->flags;
+ break;
+ }
+ case LS_MODIFIER_PERLIN_NOISE_1D: {
+ LineStyleGeometryModifier_PerlinNoise1D *p = (LineStyleGeometryModifier_PerlinNoise1D *)m;
+ LineStyleGeometryModifier_PerlinNoise1D *q = (LineStyleGeometryModifier_PerlinNoise1D *)
+ new_m;
+ q->frequency = p->frequency;
+ q->amplitude = p->amplitude;
+ q->angle = p->angle;
+ q->octaves = p->octaves;
+ q->seed = p->seed;
+ break;
+ }
+ case LS_MODIFIER_PERLIN_NOISE_2D: {
+ LineStyleGeometryModifier_PerlinNoise2D *p = (LineStyleGeometryModifier_PerlinNoise2D *)m;
+ LineStyleGeometryModifier_PerlinNoise2D *q = (LineStyleGeometryModifier_PerlinNoise2D *)
+ new_m;
+ q->frequency = p->frequency;
+ q->amplitude = p->amplitude;
+ q->angle = p->angle;
+ q->octaves = p->octaves;
+ q->seed = p->seed;
+ break;
+ }
+ case LS_MODIFIER_BACKBONE_STRETCHER: {
+ LineStyleGeometryModifier_BackboneStretcher *p =
+ (LineStyleGeometryModifier_BackboneStretcher *)m;
+ LineStyleGeometryModifier_BackboneStretcher *q =
+ (LineStyleGeometryModifier_BackboneStretcher *)new_m;
+ q->backbone_length = p->backbone_length;
+ break;
+ }
+ case LS_MODIFIER_TIP_REMOVER: {
+ LineStyleGeometryModifier_TipRemover *p = (LineStyleGeometryModifier_TipRemover *)m;
+ LineStyleGeometryModifier_TipRemover *q = (LineStyleGeometryModifier_TipRemover *)new_m;
+ q->tip_length = p->tip_length;
+ break;
+ }
+ case LS_MODIFIER_POLYGONIZATION: {
+ LineStyleGeometryModifier_Polygonalization *p =
+ (LineStyleGeometryModifier_Polygonalization *)m;
+ LineStyleGeometryModifier_Polygonalization *q =
+ (LineStyleGeometryModifier_Polygonalization *)new_m;
+ q->error = p->error;
+ break;
+ }
+ case LS_MODIFIER_GUIDING_LINES: {
+ LineStyleGeometryModifier_GuidingLines *p = (LineStyleGeometryModifier_GuidingLines *)m;
+ LineStyleGeometryModifier_GuidingLines *q = (LineStyleGeometryModifier_GuidingLines *)new_m;
+ q->offset = p->offset;
+ break;
+ }
+ case LS_MODIFIER_BLUEPRINT: {
+ LineStyleGeometryModifier_Blueprint *p = (LineStyleGeometryModifier_Blueprint *)m;
+ LineStyleGeometryModifier_Blueprint *q = (LineStyleGeometryModifier_Blueprint *)new_m;
+ q->flags = p->flags;
+ q->rounds = p->rounds;
+ q->backbone_length = p->backbone_length;
+ q->random_radius = p->random_radius;
+ q->random_center = p->random_center;
+ q->random_backbone = p->random_backbone;
+ break;
+ }
+ case LS_MODIFIER_2D_OFFSET: {
+ LineStyleGeometryModifier_2DOffset *p = (LineStyleGeometryModifier_2DOffset *)m;
+ LineStyleGeometryModifier_2DOffset *q = (LineStyleGeometryModifier_2DOffset *)new_m;
+ q->start = p->start;
+ q->end = p->end;
+ q->x = p->x;
+ q->y = p->y;
+ break;
+ }
+ case LS_MODIFIER_2D_TRANSFORM: {
+ LineStyleGeometryModifier_2DTransform *p = (LineStyleGeometryModifier_2DTransform *)m;
+ LineStyleGeometryModifier_2DTransform *q = (LineStyleGeometryModifier_2DTransform *)new_m;
+ q->pivot = p->pivot;
+ q->scale_x = p->scale_x;
+ q->scale_y = p->scale_y;
+ q->angle = p->angle;
+ q->pivot_u = p->pivot_u;
+ q->pivot_x = p->pivot_x;
+ q->pivot_y = p->pivot_y;
+ break;
+ }
+ case LS_MODIFIER_SIMPLIFICATION: {
+ LineStyleGeometryModifier_Simplification *p = (LineStyleGeometryModifier_Simplification *)m;
+ LineStyleGeometryModifier_Simplification *q = (LineStyleGeometryModifier_Simplification *)
+ new_m;
+ q->tolerance = p->tolerance;
+ break;
+ }
+ default:
+ return NULL; /* unknown modifier type */
+ }
+ add_to_modifier_list(&linestyle->geometry_modifiers, new_m);
+
+ return new_m;
}
int BKE_linestyle_geometry_modifier_remove(FreestyleLineStyle *linestyle, LineStyleModifier *m)
{
- if (BLI_findindex(&linestyle->geometry_modifiers, m) == -1)
- return -1;
- BLI_freelinkN(&linestyle->geometry_modifiers, m);
- return 0;
+ if (BLI_findindex(&linestyle->geometry_modifiers, m) == -1)
+ return -1;
+ BLI_freelinkN(&linestyle->geometry_modifiers, m);
+ return 0;
}
/**
* Reinsert \a modifier in modifier list with an offset of \a direction.
* \return if position of \a modifier has changed.
*/
-bool BKE_linestyle_color_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction)
+bool BKE_linestyle_color_modifier_move(FreestyleLineStyle *linestyle,
+ LineStyleModifier *modifier,
+ int direction)
{
- return BLI_listbase_link_move(&linestyle->color_modifiers, modifier, direction);
+ return BLI_listbase_link_move(&linestyle->color_modifiers, modifier, direction);
}
-bool BKE_linestyle_alpha_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction)
+bool BKE_linestyle_alpha_modifier_move(FreestyleLineStyle *linestyle,
+ LineStyleModifier *modifier,
+ int direction)
{
- return BLI_listbase_link_move(&linestyle->alpha_modifiers, modifier, direction);
+ return BLI_listbase_link_move(&linestyle->alpha_modifiers, modifier, direction);
}
-bool BKE_linestyle_thickness_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction)
+bool BKE_linestyle_thickness_modifier_move(FreestyleLineStyle *linestyle,
+ LineStyleModifier *modifier,
+ int direction)
{
- return BLI_listbase_link_move(&linestyle->thickness_modifiers, modifier, direction);
+ return BLI_listbase_link_move(&linestyle->thickness_modifiers, modifier, direction);
}
-bool BKE_linestyle_geometry_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction)
+bool BKE_linestyle_geometry_modifier_move(FreestyleLineStyle *linestyle,
+ LineStyleModifier *modifier,
+ int direction)
{
- return BLI_listbase_link_move(&linestyle->geometry_modifiers, modifier, direction);
+ return BLI_listbase_link_move(&linestyle->geometry_modifiers, modifier, direction);
}
void BKE_linestyle_modifier_list_color_ramps(FreestyleLineStyle *linestyle, ListBase *listbase)
{
- LineStyleModifier *m;
- ColorBand *color_ramp;
- LinkData *link;
-
- BLI_listbase_clear(listbase);
-
- for (m = (LineStyleModifier *)linestyle->color_modifiers.first; m; m = m->next) {
- switch (m->type) {
- case LS_MODIFIER_ALONG_STROKE:
- color_ramp = ((LineStyleColorModifier_AlongStroke *)m)->color_ramp;
- break;
- case LS_MODIFIER_DISTANCE_FROM_CAMERA:
- color_ramp = ((LineStyleColorModifier_DistanceFromCamera *)m)->color_ramp;
- break;
- case LS_MODIFIER_DISTANCE_FROM_OBJECT:
- color_ramp = ((LineStyleColorModifier_DistanceFromObject *)m)->color_ramp;
- break;
- case LS_MODIFIER_MATERIAL:
- color_ramp = ((LineStyleColorModifier_Material *)m)->color_ramp;
- break;
- default:
- continue;
- }
- link = (LinkData *) MEM_callocN(sizeof(LinkData), "link to color ramp");
- link->data = color_ramp;
- BLI_addtail(listbase, link);
- }
+ LineStyleModifier *m;
+ ColorBand *color_ramp;
+ LinkData *link;
+
+ BLI_listbase_clear(listbase);
+
+ for (m = (LineStyleModifier *)linestyle->color_modifiers.first; m; m = m->next) {
+ switch (m->type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ color_ramp = ((LineStyleColorModifier_AlongStroke *)m)->color_ramp;
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ color_ramp = ((LineStyleColorModifier_DistanceFromCamera *)m)->color_ramp;
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ color_ramp = ((LineStyleColorModifier_DistanceFromObject *)m)->color_ramp;
+ break;
+ case LS_MODIFIER_MATERIAL:
+ color_ramp = ((LineStyleColorModifier_Material *)m)->color_ramp;
+ break;
+ default:
+ continue;
+ }
+ link = (LinkData *)MEM_callocN(sizeof(LinkData), "link to color ramp");
+ link->data = color_ramp;
+ BLI_addtail(listbase, link);
+ }
}
char *BKE_linestyle_path_to_color_ramp(FreestyleLineStyle *linestyle, ColorBand *color_ramp)
{
- LineStyleModifier *m;
- bool found = false;
-
- for (m = (LineStyleModifier *)linestyle->color_modifiers.first; m; m = m->next) {
- switch (m->type) {
- case LS_MODIFIER_ALONG_STROKE:
- if (color_ramp == ((LineStyleColorModifier_AlongStroke *)m)->color_ramp)
- found = true;
- break;
- case LS_MODIFIER_DISTANCE_FROM_CAMERA:
- if (color_ramp == ((LineStyleColorModifier_DistanceFromCamera *)m)->color_ramp)
- found = true;
- break;
- case LS_MODIFIER_DISTANCE_FROM_OBJECT:
- if (color_ramp == ((LineStyleColorModifier_DistanceFromObject *)m)->color_ramp)
- found = true;
- break;
- case LS_MODIFIER_MATERIAL:
- if (color_ramp == ((LineStyleColorModifier_Material *)m)->color_ramp)
- found = true;
- break;
- case LS_MODIFIER_TANGENT:
- if (color_ramp == ((LineStyleColorModifier_Tangent *)m)->color_ramp)
- found = true;
- break;
- case LS_MODIFIER_NOISE:
- if (color_ramp == ((LineStyleColorModifier_Noise *)m)->color_ramp)
- found = true;
- break;
- case LS_MODIFIER_CREASE_ANGLE:
- if (color_ramp == ((LineStyleColorModifier_CreaseAngle *)m)->color_ramp)
- found = true;
- break;
- case LS_MODIFIER_CURVATURE_3D:
- if (color_ramp == ((LineStyleColorModifier_Curvature_3D *)m)->color_ramp)
- found = true;
- break;
- }
-
- if (found) {
- char name_esc[sizeof(m->name) * 2];
- BLI_strescape(name_esc, m->name, sizeof(name_esc));
- return BLI_sprintfN("color_modifiers[\"%s\"].color_ramp", name_esc);
- }
- }
- printf("BKE_linestyle_path_to_color_ramp: No color ramps correspond to the given pointer.\n");
- return NULL;
+ LineStyleModifier *m;
+ bool found = false;
+
+ for (m = (LineStyleModifier *)linestyle->color_modifiers.first; m; m = m->next) {
+ switch (m->type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ if (color_ramp == ((LineStyleColorModifier_AlongStroke *)m)->color_ramp)
+ found = true;
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ if (color_ramp == ((LineStyleColorModifier_DistanceFromCamera *)m)->color_ramp)
+ found = true;
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ if (color_ramp == ((LineStyleColorModifier_DistanceFromObject *)m)->color_ramp)
+ found = true;
+ break;
+ case LS_MODIFIER_MATERIAL:
+ if (color_ramp == ((LineStyleColorModifier_Material *)m)->color_ramp)
+ found = true;
+ break;
+ case LS_MODIFIER_TANGENT:
+ if (color_ramp == ((LineStyleColorModifier_Tangent *)m)->color_ramp)
+ found = true;
+ break;
+ case LS_MODIFIER_NOISE:
+ if (color_ramp == ((LineStyleColorModifier_Noise *)m)->color_ramp)
+ found = true;
+ break;
+ case LS_MODIFIER_CREASE_ANGLE:
+ if (color_ramp == ((LineStyleColorModifier_CreaseAngle *)m)->color_ramp)
+ found = true;
+ break;
+ case LS_MODIFIER_CURVATURE_3D:
+ if (color_ramp == ((LineStyleColorModifier_Curvature_3D *)m)->color_ramp)
+ found = true;
+ break;
+ }
+
+ if (found) {
+ char name_esc[sizeof(m->name) * 2];
+ BLI_strescape(name_esc, m->name, sizeof(name_esc));
+ return BLI_sprintfN("color_modifiers[\"%s\"].color_ramp", name_esc);
+ }
+ }
+ printf("BKE_linestyle_path_to_color_ramp: No color ramps correspond to the given pointer.\n");
+ return NULL;
}
bool BKE_linestyle_use_textures(FreestyleLineStyle *linestyle, const bool use_shading_nodes)
{
- if (use_shading_nodes) {
- if (linestyle && linestyle->use_nodes && linestyle->nodetree) {
- bNode *node;
-
- for (node = linestyle->nodetree->nodes.first; node; node = node->next) {
- if (node->typeinfo->nclass == NODE_CLASS_TEXTURE) {
- return true;
- }
- }
- }
- }
- else {
- if (linestyle && (linestyle->flag & LS_TEXTURE)) {
- return (linestyle->mtex[0] != NULL);
- }
- }
- return false;
+ if (use_shading_nodes) {
+ if (linestyle && linestyle->use_nodes && linestyle->nodetree) {
+ bNode *node;
+
+ for (node = linestyle->nodetree->nodes.first; node; node = node->next) {
+ if (node->typeinfo->nclass == NODE_CLASS_TEXTURE) {
+ return true;
+ }
+ }
+ }
+ }
+ else {
+ if (linestyle && (linestyle->flag & LS_TEXTURE)) {
+ return (linestyle->mtex[0] != NULL);
+ }
+ }
+ return false;
}
void BKE_linestyle_default_shader(const bContext *C, FreestyleLineStyle *linestyle)
{
- bNode *uv_along_stroke, *input_texure, *output_linestyle;
- bNodeSocket *fromsock, *tosock;
- bNodeTree *ntree;
+ bNode *uv_along_stroke, *input_texure, *output_linestyle;
+ bNodeSocket *fromsock, *tosock;
+ bNodeTree *ntree;
- BLI_assert(linestyle->nodetree == NULL);
+ BLI_assert(linestyle->nodetree == NULL);
- ntree = ntreeAddTree(NULL, "stroke_shader", "ShaderNodeTree");
+ ntree = ntreeAddTree(NULL, "stroke_shader", "ShaderNodeTree");
- linestyle->nodetree = ntree;
+ linestyle->nodetree = ntree;
- uv_along_stroke = nodeAddStaticNode(C, ntree, SH_NODE_UVALONGSTROKE);
- uv_along_stroke->locx = 0.0f;
- uv_along_stroke->locy = 300.0f;
- uv_along_stroke->custom1 = 0; // use_tips
+ uv_along_stroke = nodeAddStaticNode(C, ntree, SH_NODE_UVALONGSTROKE);
+ uv_along_stroke->locx = 0.0f;
+ uv_along_stroke->locy = 300.0f;
+ uv_along_stroke->custom1 = 0; // use_tips
- input_texure = nodeAddStaticNode(C, ntree, SH_NODE_TEX_IMAGE);
- input_texure->locx = 200.0f;
- input_texure->locy = 300.0f;
+ input_texure = nodeAddStaticNode(C, ntree, SH_NODE_TEX_IMAGE);
+ input_texure->locx = 200.0f;
+ input_texure->locy = 300.0f;
- output_linestyle = nodeAddStaticNode(C, ntree, SH_NODE_OUTPUT_LINESTYLE);
- output_linestyle->locx = 400.0f;
- output_linestyle->locy = 300.0f;
- output_linestyle->custom1 = MA_RAMP_BLEND;
- output_linestyle->custom2 = 0; // use_clamp
+ output_linestyle = nodeAddStaticNode(C, ntree, SH_NODE_OUTPUT_LINESTYLE);
+ output_linestyle->locx = 400.0f;
+ output_linestyle->locy = 300.0f;
+ output_linestyle->custom1 = MA_RAMP_BLEND;
+ output_linestyle->custom2 = 0; // use_clamp
- nodeSetActive(ntree, input_texure);
+ nodeSetActive(ntree, input_texure);
- fromsock = BLI_findlink(&uv_along_stroke->outputs, 0); // UV
- tosock = BLI_findlink(&input_texure->inputs, 0); // UV
- nodeAddLink(ntree, uv_along_stroke, fromsock, input_texure, tosock);
+ fromsock = BLI_findlink(&uv_along_stroke->outputs, 0); // UV
+ tosock = BLI_findlink(&input_texure->inputs, 0); // UV
+ nodeAddLink(ntree, uv_along_stroke, fromsock, input_texure, tosock);
- fromsock = BLI_findlink(&input_texure->outputs, 0); // Color
- tosock = BLI_findlink(&output_linestyle->inputs, 0); // Color
- nodeAddLink(ntree, input_texure, fromsock, output_linestyle, tosock);
+ fromsock = BLI_findlink(&input_texure->outputs, 0); // Color
+ tosock = BLI_findlink(&output_linestyle->inputs, 0); // Color
+ nodeAddLink(ntree, input_texure, fromsock, output_linestyle, tosock);
- ntreeUpdateTree(CTX_data_main(C), ntree);
+ ntreeUpdateTree(CTX_data_main(C), ntree);
}
diff --git a/source/blender/blenkernel/intern/main.c b/source/blender/blenkernel/intern/main.c
index 1f65212135b..ef196430da7 100644
--- a/source/blender/blenkernel/intern/main.c
+++ b/source/blender/blenkernel/intern/main.c
@@ -44,169 +44,243 @@
Main *BKE_main_new(void)
{
- Main *bmain = MEM_callocN(sizeof(Main), "new main");
- bmain->lock = MEM_mallocN(sizeof(SpinLock), "main lock");
- BLI_spin_init((SpinLock *)bmain->lock);
- return bmain;
+ Main *bmain = MEM_callocN(sizeof(Main), "new main");
+ bmain->lock = MEM_mallocN(sizeof(SpinLock), "main lock");
+ BLI_spin_init((SpinLock *)bmain->lock);
+ return bmain;
}
void BKE_main_free(Main *mainvar)
{
- /* also call when reading a file, erase all, etc */
- ListBase *lbarray[MAX_LIBARRAY];
- int a;
+ /* also call when reading a file, erase all, etc */
+ ListBase *lbarray[MAX_LIBARRAY];
+ int a;
- /* Since we are removing whole main, no need to bother 'properly' (and slowly) removing each ID from it. */
- const int free_flag = (LIB_ID_FREE_NO_MAIN |
- LIB_ID_FREE_NO_UI_USER |
- LIB_ID_FREE_NO_USER_REFCOUNT |
- LIB_ID_FREE_NO_DEG_TAG);
+ /* Since we are removing whole main, no need to bother 'properly' (and slowly) removing each ID from it. */
+ const int free_flag = (LIB_ID_FREE_NO_MAIN | LIB_ID_FREE_NO_UI_USER |
+ LIB_ID_FREE_NO_USER_REFCOUNT | LIB_ID_FREE_NO_DEG_TAG);
- MEM_SAFE_FREE(mainvar->blen_thumb);
+ MEM_SAFE_FREE(mainvar->blen_thumb);
- a = set_listbasepointers(mainvar, lbarray);
- while (a--) {
- ListBase *lb = lbarray[a];
- ID *id, *id_next;
+ a = set_listbasepointers(mainvar, lbarray);
+ while (a--) {
+ ListBase *lb = lbarray[a];
+ ID *id, *id_next;
- for (id = lb->first; id != NULL; id = id_next) {
- id_next = id->next;
+ for (id = lb->first; id != NULL; id = id_next) {
+ id_next = id->next;
#if 1
- BKE_id_free_ex(mainvar, id, free_flag, false);
+ BKE_id_free_ex(mainvar, id, free_flag, false);
#else
- /* errors freeing ID's can be hard to track down,
- * enable this so valgrind will give the line number in its error log */
- switch (a) {
- case 0: BKE_id_free_ex(mainvar, id, free_flag, false); break;
- case 1: BKE_id_free_ex(mainvar, id, free_flag, false); break;
- case 2: BKE_id_free_ex(mainvar, id, free_flag, false); break;
- case 3: BKE_id_free_ex(mainvar, id, free_flag, false); break;
- case 4: BKE_id_free_ex(mainvar, id, free_flag, false); break;
- case 5: BKE_id_free_ex(mainvar, id, free_flag, false); break;
- case 6: BKE_id_free_ex(mainvar, id, free_flag, false); break;
- case 7: BKE_id_free_ex(mainvar, id, free_flag, false); break;
- case 8: BKE_id_free_ex(mainvar, id, free_flag, false); break;
- case 9: BKE_id_free_ex(mainvar, id, free_flag, false); break;
- case 10: BKE_id_free_ex(mainvar, id, free_flag, false); break;
- case 11: BKE_id_free_ex(mainvar, id, free_flag, false); break;
- case 12: BKE_id_free_ex(mainvar, id, free_flag, false); break;
- case 13: BKE_id_free_ex(mainvar, id, free_flag, false); break;
- case 14: BKE_id_free_ex(mainvar, id, free_flag, false); break;
- case 15: BKE_id_free_ex(mainvar, id, free_flag, false); break;
- case 16: BKE_id_free_ex(mainvar, id, free_flag, false); break;
- case 17: BKE_id_free_ex(mainvar, id, free_flag, false); break;
- case 18: BKE_id_free_ex(mainvar, id, free_flag, false); break;
- case 19: BKE_id_free_ex(mainvar, id, free_flag, false); break;
- case 20: BKE_id_free_ex(mainvar, id, free_flag, false); break;
- case 21: BKE_id_free_ex(mainvar, id, free_flag, false); break;
- case 22: BKE_id_free_ex(mainvar, id, free_flag, false); break;
- case 23: BKE_id_free_ex(mainvar, id, free_flag, false); break;
- case 24: BKE_id_free_ex(mainvar, id, free_flag, false); break;
- case 25: BKE_id_free_ex(mainvar, id, free_flag, false); break;
- case 26: BKE_id_free_ex(mainvar, id, free_flag, false); break;
- case 27: BKE_id_free_ex(mainvar, id, free_flag, false); break;
- case 28: BKE_id_free_ex(mainvar, id, free_flag, false); break;
- case 29: BKE_id_free_ex(mainvar, id, free_flag, false); break;
- case 30: BKE_id_free_ex(mainvar, id, free_flag, false); break;
- case 31: BKE_id_free_ex(mainvar, id, free_flag, false); break;
- case 32: BKE_id_free_ex(mainvar, id, free_flag, false); break;
- case 33: BKE_id_free_ex(mainvar, id, free_flag, false); break;
- case 34: BKE_id_free_ex(mainvar, id, free_flag, false); break;
- default:
- BLI_assert(0);
- break;
- }
+ /* errors freeing ID's can be hard to track down,
+ * enable this so valgrind will give the line number in its error log */
+ switch (a) {
+ case 0:
+ BKE_id_free_ex(mainvar, id, free_flag, false);
+ break;
+ case 1:
+ BKE_id_free_ex(mainvar, id, free_flag, false);
+ break;
+ case 2:
+ BKE_id_free_ex(mainvar, id, free_flag, false);
+ break;
+ case 3:
+ BKE_id_free_ex(mainvar, id, free_flag, false);
+ break;
+ case 4:
+ BKE_id_free_ex(mainvar, id, free_flag, false);
+ break;
+ case 5:
+ BKE_id_free_ex(mainvar, id, free_flag, false);
+ break;
+ case 6:
+ BKE_id_free_ex(mainvar, id, free_flag, false);
+ break;
+ case 7:
+ BKE_id_free_ex(mainvar, id, free_flag, false);
+ break;
+ case 8:
+ BKE_id_free_ex(mainvar, id, free_flag, false);
+ break;
+ case 9:
+ BKE_id_free_ex(mainvar, id, free_flag, false);
+ break;
+ case 10:
+ BKE_id_free_ex(mainvar, id, free_flag, false);
+ break;
+ case 11:
+ BKE_id_free_ex(mainvar, id, free_flag, false);
+ break;
+ case 12:
+ BKE_id_free_ex(mainvar, id, free_flag, false);
+ break;
+ case 13:
+ BKE_id_free_ex(mainvar, id, free_flag, false);
+ break;
+ case 14:
+ BKE_id_free_ex(mainvar, id, free_flag, false);
+ break;
+ case 15:
+ BKE_id_free_ex(mainvar, id, free_flag, false);
+ break;
+ case 16:
+ BKE_id_free_ex(mainvar, id, free_flag, false);
+ break;
+ case 17:
+ BKE_id_free_ex(mainvar, id, free_flag, false);
+ break;
+ case 18:
+ BKE_id_free_ex(mainvar, id, free_flag, false);
+ break;
+ case 19:
+ BKE_id_free_ex(mainvar, id, free_flag, false);
+ break;
+ case 20:
+ BKE_id_free_ex(mainvar, id, free_flag, false);
+ break;
+ case 21:
+ BKE_id_free_ex(mainvar, id, free_flag, false);
+ break;
+ case 22:
+ BKE_id_free_ex(mainvar, id, free_flag, false);
+ break;
+ case 23:
+ BKE_id_free_ex(mainvar, id, free_flag, false);
+ break;
+ case 24:
+ BKE_id_free_ex(mainvar, id, free_flag, false);
+ break;
+ case 25:
+ BKE_id_free_ex(mainvar, id, free_flag, false);
+ break;
+ case 26:
+ BKE_id_free_ex(mainvar, id, free_flag, false);
+ break;
+ case 27:
+ BKE_id_free_ex(mainvar, id, free_flag, false);
+ break;
+ case 28:
+ BKE_id_free_ex(mainvar, id, free_flag, false);
+ break;
+ case 29:
+ BKE_id_free_ex(mainvar, id, free_flag, false);
+ break;
+ case 30:
+ BKE_id_free_ex(mainvar, id, free_flag, false);
+ break;
+ case 31:
+ BKE_id_free_ex(mainvar, id, free_flag, false);
+ break;
+ case 32:
+ BKE_id_free_ex(mainvar, id, free_flag, false);
+ break;
+ case 33:
+ BKE_id_free_ex(mainvar, id, free_flag, false);
+ break;
+ case 34:
+ BKE_id_free_ex(mainvar, id, free_flag, false);
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
#endif
- }
- BLI_listbase_clear(lb);
- }
+ }
+ BLI_listbase_clear(lb);
+ }
- if (mainvar->relations) {
- BKE_main_relations_free(mainvar);
- }
+ if (mainvar->relations) {
+ BKE_main_relations_free(mainvar);
+ }
- BLI_spin_end((SpinLock *)mainvar->lock);
- MEM_freeN(mainvar->lock);
- MEM_freeN(mainvar);
+ BLI_spin_end((SpinLock *)mainvar->lock);
+ MEM_freeN(mainvar->lock);
+ MEM_freeN(mainvar);
}
void BKE_main_lock(struct Main *bmain)
{
- BLI_spin_lock((SpinLock *) bmain->lock);
+ BLI_spin_lock((SpinLock *)bmain->lock);
}
void BKE_main_unlock(struct Main *bmain)
{
- BLI_spin_unlock((SpinLock *) bmain->lock);
+ BLI_spin_unlock((SpinLock *)bmain->lock);
}
-
-static int main_relations_create_idlink_cb(void *user_data, ID *id_self, ID **id_pointer, int cb_flag)
+static int main_relations_create_idlink_cb(void *user_data,
+ ID *id_self,
+ ID **id_pointer,
+ int cb_flag)
{
- MainIDRelations *rel = user_data;
-
- if (*id_pointer) {
- MainIDRelationsEntry *entry, **entry_p;
-
- entry = BLI_mempool_alloc(rel->entry_pool);
- if (BLI_ghash_ensure_p(rel->id_user_to_used, id_self, (void ***)&entry_p)) {
- entry->next = *entry_p;
- }
- else {
- entry->next = NULL;
- }
- entry->id_pointer = id_pointer;
- entry->usage_flag = cb_flag;
- *entry_p = entry;
-
- entry = BLI_mempool_alloc(rel->entry_pool);
- if (BLI_ghash_ensure_p(rel->id_used_to_user, *id_pointer, (void ***)&entry_p)) {
- entry->next = *entry_p;
- }
- else {
- entry->next = NULL;
- }
- entry->id_pointer = (ID **)id_self;
- entry->usage_flag = cb_flag;
- *entry_p = entry;
- }
-
- return IDWALK_RET_NOP;
+ MainIDRelations *rel = user_data;
+
+ if (*id_pointer) {
+ MainIDRelationsEntry *entry, **entry_p;
+
+ entry = BLI_mempool_alloc(rel->entry_pool);
+ if (BLI_ghash_ensure_p(rel->id_user_to_used, id_self, (void ***)&entry_p)) {
+ entry->next = *entry_p;
+ }
+ else {
+ entry->next = NULL;
+ }
+ entry->id_pointer = id_pointer;
+ entry->usage_flag = cb_flag;
+ *entry_p = entry;
+
+ entry = BLI_mempool_alloc(rel->entry_pool);
+ if (BLI_ghash_ensure_p(rel->id_used_to_user, *id_pointer, (void ***)&entry_p)) {
+ entry->next = *entry_p;
+ }
+ else {
+ entry->next = NULL;
+ }
+ entry->id_pointer = (ID **)id_self;
+ entry->usage_flag = cb_flag;
+ *entry_p = entry;
+ }
+
+ return IDWALK_RET_NOP;
}
/** Generate the mappings between used IDs and their users, and vice-versa. */
void BKE_main_relations_create(Main *bmain)
{
- if (bmain->relations != NULL) {
- BKE_main_relations_free(bmain);
- }
-
- bmain->relations = MEM_mallocN(sizeof(*bmain->relations), __func__);
- bmain->relations->id_used_to_user = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
- bmain->relations->id_user_to_used = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
- bmain->relations->entry_pool = BLI_mempool_create(sizeof(MainIDRelationsEntry), 128, 128, BLI_MEMPOOL_NOP);
-
- ID *id;
- FOREACH_MAIN_ID_BEGIN(bmain, id)
- {
- BKE_library_foreach_ID_link(NULL, id, main_relations_create_idlink_cb, bmain->relations, IDWALK_READONLY);
- }
- FOREACH_MAIN_ID_END;
+ if (bmain->relations != NULL) {
+ BKE_main_relations_free(bmain);
+ }
+
+ bmain->relations = MEM_mallocN(sizeof(*bmain->relations), __func__);
+ bmain->relations->id_used_to_user = BLI_ghash_new(
+ BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+ bmain->relations->id_user_to_used = BLI_ghash_new(
+ BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+ bmain->relations->entry_pool = BLI_mempool_create(
+ sizeof(MainIDRelationsEntry), 128, 128, BLI_MEMPOOL_NOP);
+
+ ID *id;
+ FOREACH_MAIN_ID_BEGIN(bmain, id)
+ {
+ BKE_library_foreach_ID_link(
+ NULL, id, main_relations_create_idlink_cb, bmain->relations, IDWALK_READONLY);
+ }
+ FOREACH_MAIN_ID_END;
}
void BKE_main_relations_free(Main *bmain)
{
- if (bmain->relations) {
- if (bmain->relations->id_used_to_user) {
- BLI_ghash_free(bmain->relations->id_used_to_user, NULL, NULL);
- }
- if (bmain->relations->id_user_to_used) {
- BLI_ghash_free(bmain->relations->id_user_to_used, NULL, NULL);
- }
- BLI_mempool_destroy(bmain->relations->entry_pool);
- MEM_freeN(bmain->relations);
- bmain->relations = NULL;
- }
+ if (bmain->relations) {
+ if (bmain->relations->id_used_to_user) {
+ BLI_ghash_free(bmain->relations->id_used_to_user, NULL, NULL);
+ }
+ if (bmain->relations->id_user_to_used) {
+ BLI_ghash_free(bmain->relations->id_user_to_used, NULL, NULL);
+ }
+ BLI_mempool_destroy(bmain->relations->entry_pool);
+ MEM_freeN(bmain->relations);
+ bmain->relations = NULL;
+ }
}
/**
@@ -216,17 +290,17 @@ void BKE_main_relations_free(Main *bmain)
*/
GSet *BKE_main_gset_create(Main *bmain, GSet *gset)
{
- if (gset == NULL) {
- gset = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
- }
-
- ID *id;
- FOREACH_MAIN_ID_BEGIN(bmain, id)
- {
- BLI_gset_add(gset, id);
- }
- FOREACH_MAIN_ID_END;
- return gset;
+ if (gset == NULL) {
+ gset = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+ }
+
+ ID *id;
+ FOREACH_MAIN_ID_BEGIN(bmain, id)
+ {
+ BLI_gset_add(gset, id);
+ }
+ FOREACH_MAIN_ID_END;
+ return gset;
}
/**
@@ -238,26 +312,26 @@ GSet *BKE_main_gset_create(Main *bmain, GSet *gset)
*/
BlendThumbnail *BKE_main_thumbnail_from_imbuf(Main *bmain, ImBuf *img)
{
- BlendThumbnail *data = NULL;
-
- if (bmain) {
- MEM_SAFE_FREE(bmain->blen_thumb);
- }
-
- if (img) {
- const size_t sz = BLEN_THUMB_MEMSIZE(img->x, img->y);
- data = MEM_mallocN(sz, __func__);
-
- IMB_rect_from_float(img); /* Just in case... */
- data->width = img->x;
- data->height = img->y;
- memcpy(data->rect, img->rect, sz - sizeof(*data));
- }
-
- if (bmain) {
- bmain->blen_thumb = data;
- }
- return data;
+ BlendThumbnail *data = NULL;
+
+ if (bmain) {
+ MEM_SAFE_FREE(bmain->blen_thumb);
+ }
+
+ if (img) {
+ const size_t sz = BLEN_THUMB_MEMSIZE(img->x, img->y);
+ data = MEM_mallocN(sz, __func__);
+
+ IMB_rect_from_float(img); /* Just in case... */
+ data->width = img->x;
+ data->height = img->y;
+ memcpy(data->rect, img->rect, sz - sizeof(*data));
+ }
+
+ if (bmain) {
+ bmain->blen_thumb = data;
+ }
+ return data;
}
/**
@@ -269,20 +343,21 @@ BlendThumbnail *BKE_main_thumbnail_from_imbuf(Main *bmain, ImBuf *img)
*/
ImBuf *BKE_main_thumbnail_to_imbuf(Main *bmain, BlendThumbnail *data)
{
- ImBuf *img = NULL;
+ ImBuf *img = NULL;
- if (!data && bmain) {
- data = bmain->blen_thumb;
- }
+ if (!data && bmain) {
+ data = bmain->blen_thumb;
+ }
- if (data) {
- /* Note: we cannot use IMB_allocFromBuffer(), since it tries to dupalloc passed buffer, which will fail
- * here (we do not want to pass the first two ints!). */
- img = IMB_allocImBuf((unsigned int)data->width, (unsigned int)data->height, 32, IB_rect | IB_metadata);
- memcpy(img->rect, data->rect, BLEN_THUMB_MEMSIZE(data->width, data->height) - sizeof(*data));
- }
+ if (data) {
+ /* Note: we cannot use IMB_allocFromBuffer(), since it tries to dupalloc passed buffer, which will fail
+ * here (we do not want to pass the first two ints!). */
+ img = IMB_allocImBuf(
+ (unsigned int)data->width, (unsigned int)data->height, 32, IB_rect | IB_metadata);
+ memcpy(img->rect, data->rect, BLEN_THUMB_MEMSIZE(data->width, data->height) - sizeof(*data));
+ }
- return img;
+ return img;
}
/**
@@ -290,11 +365,11 @@ ImBuf *BKE_main_thumbnail_to_imbuf(Main *bmain, BlendThumbnail *data)
*/
void BKE_main_thumbnail_create(struct Main *bmain)
{
- MEM_SAFE_FREE(bmain->blen_thumb);
+ MEM_SAFE_FREE(bmain->blen_thumb);
- bmain->blen_thumb = MEM_callocN(BLEN_THUMB_MEMSIZE(BLEN_THUMB_SIZE, BLEN_THUMB_SIZE), __func__);
- bmain->blen_thumb->width = BLEN_THUMB_SIZE;
- bmain->blen_thumb->height = BLEN_THUMB_SIZE;
+ bmain->blen_thumb = MEM_callocN(BLEN_THUMB_MEMSIZE(BLEN_THUMB_SIZE, BLEN_THUMB_SIZE), __func__);
+ bmain->blen_thumb->width = BLEN_THUMB_SIZE;
+ bmain->blen_thumb->height = BLEN_THUMB_SIZE;
}
/**
@@ -302,7 +377,7 @@ void BKE_main_thumbnail_create(struct Main *bmain)
*/
const char *BKE_main_blendfile_path(const Main *bmain)
{
- return bmain->name;
+ return bmain->name;
}
/**
@@ -312,7 +387,7 @@ const char *BKE_main_blendfile_path(const Main *bmain)
*/
const char *BKE_main_blendfile_path_from_global(void)
{
- return BKE_main_blendfile_path(G_MAIN);
+ return BKE_main_blendfile_path(G_MAIN);
}
/**
@@ -320,81 +395,81 @@ const char *BKE_main_blendfile_path_from_global(void)
*/
ListBase *which_libbase(Main *bmain, short type)
{
- switch ((ID_Type)type) {
- case ID_SCE:
- return &(bmain->scenes);
- case ID_LI:
- return &(bmain->libraries);
- case ID_OB:
- return &(bmain->objects);
- case ID_ME:
- return &(bmain->meshes);
- case ID_CU:
- return &(bmain->curves);
- case ID_MB:
- return &(bmain->metaballs);
- case ID_MA:
- return &(bmain->materials);
- case ID_TE:
- return &(bmain->textures);
- case ID_IM:
- return &(bmain->images);
- case ID_LT:
- return &(bmain->lattices);
- case ID_LA:
- return &(bmain->lights);
- case ID_CA:
- return &(bmain->cameras);
- case ID_IP:
- return &(bmain->ipo);
- case ID_KE:
- return &(bmain->shapekeys);
- case ID_WO:
- return &(bmain->worlds);
- case ID_SCR:
- return &(bmain->screens);
- case ID_VF:
- return &(bmain->fonts);
- case ID_TXT:
- return &(bmain->texts);
- case ID_SPK:
- return &(bmain->speakers);
- case ID_LP:
- return &(bmain->lightprobes);
- case ID_SO:
- return &(bmain->sounds);
- case ID_GR:
- return &(bmain->collections);
- case ID_AR:
- return &(bmain->armatures);
- case ID_AC:
- return &(bmain->actions);
- case ID_NT:
- return &(bmain->nodetrees);
- case ID_BR:
- return &(bmain->brushes);
- case ID_PA:
- return &(bmain->particles);
- case ID_WM:
- return &(bmain->wm);
- case ID_GD:
- return &(bmain->gpencils);
- case ID_MC:
- return &(bmain->movieclips);
- case ID_MSK:
- return &(bmain->masks);
- case ID_LS:
- return &(bmain->linestyles);
- case ID_PAL:
- return &(bmain->palettes);
- case ID_PC:
- return &(bmain->paintcurves);
- case ID_CF:
- return &(bmain->cachefiles);
- case ID_WS:
- return &(bmain->workspaces);
- }
- return NULL;
+ switch ((ID_Type)type) {
+ case ID_SCE:
+ return &(bmain->scenes);
+ case ID_LI:
+ return &(bmain->libraries);
+ case ID_OB:
+ return &(bmain->objects);
+ case ID_ME:
+ return &(bmain->meshes);
+ case ID_CU:
+ return &(bmain->curves);
+ case ID_MB:
+ return &(bmain->metaballs);
+ case ID_MA:
+ return &(bmain->materials);
+ case ID_TE:
+ return &(bmain->textures);
+ case ID_IM:
+ return &(bmain->images);
+ case ID_LT:
+ return &(bmain->lattices);
+ case ID_LA:
+ return &(bmain->lights);
+ case ID_CA:
+ return &(bmain->cameras);
+ case ID_IP:
+ return &(bmain->ipo);
+ case ID_KE:
+ return &(bmain->shapekeys);
+ case ID_WO:
+ return &(bmain->worlds);
+ case ID_SCR:
+ return &(bmain->screens);
+ case ID_VF:
+ return &(bmain->fonts);
+ case ID_TXT:
+ return &(bmain->texts);
+ case ID_SPK:
+ return &(bmain->speakers);
+ case ID_LP:
+ return &(bmain->lightprobes);
+ case ID_SO:
+ return &(bmain->sounds);
+ case ID_GR:
+ return &(bmain->collections);
+ case ID_AR:
+ return &(bmain->armatures);
+ case ID_AC:
+ return &(bmain->actions);
+ case ID_NT:
+ return &(bmain->nodetrees);
+ case ID_BR:
+ return &(bmain->brushes);
+ case ID_PA:
+ return &(bmain->particles);
+ case ID_WM:
+ return &(bmain->wm);
+ case ID_GD:
+ return &(bmain->gpencils);
+ case ID_MC:
+ return &(bmain->movieclips);
+ case ID_MSK:
+ return &(bmain->masks);
+ case ID_LS:
+ return &(bmain->linestyles);
+ case ID_PAL:
+ return &(bmain->palettes);
+ case ID_PC:
+ return &(bmain->paintcurves);
+ case ID_CF:
+ return &(bmain->cachefiles);
+ case ID_WS:
+ return &(bmain->workspaces);
+ }
+ return NULL;
}
/**
@@ -406,57 +481,61 @@ ListBase *which_libbase(Main *bmain, short type)
* \note #MAX_LIBARRAY define should match this code */
int set_listbasepointers(Main *bmain, ListBase **lb)
{
- /* BACKWARDS! also watch order of free-ing! (mesh<->mat), first items freed last.
- * This is important because freeing data decreases usercounts of other datablocks,
- * if this data is its self freed it can crash. */
- lb[INDEX_ID_LI] = &(bmain->libraries); /* Libraries may be accessed from pretty much any other ID... */
- lb[INDEX_ID_IP] = &(bmain->ipo);
- lb[INDEX_ID_AC] = &(bmain->actions); /* moved here to avoid problems when freeing with animato (aligorith) */
- lb[INDEX_ID_KE] = &(bmain->shapekeys);
- lb[INDEX_ID_PAL] = &(bmain->palettes); /* referenced by gpencil, so needs to be before that to avoid crashes */
- lb[INDEX_ID_GD] = &(bmain->gpencils); /* referenced by nodes, objects, view, scene etc, before to free after. */
- lb[INDEX_ID_NT] = &(bmain->nodetrees);
- lb[INDEX_ID_IM] = &(bmain->images);
- lb[INDEX_ID_TE] = &(bmain->textures);
- lb[INDEX_ID_MA] = &(bmain->materials);
- lb[INDEX_ID_VF] = &(bmain->fonts);
-
- /* Important!: When adding a new object type,
- * the specific data should be inserted here
- */
-
- lb[INDEX_ID_AR] = &(bmain->armatures);
-
- lb[INDEX_ID_CF] = &(bmain->cachefiles);
- lb[INDEX_ID_ME] = &(bmain->meshes);
- lb[INDEX_ID_CU] = &(bmain->curves);
- lb[INDEX_ID_MB] = &(bmain->metaballs);
-
- lb[INDEX_ID_LT] = &(bmain->lattices);
- lb[INDEX_ID_LA] = &(bmain->lights);
- lb[INDEX_ID_CA] = &(bmain->cameras);
-
- lb[INDEX_ID_TXT] = &(bmain->texts);
- lb[INDEX_ID_SO] = &(bmain->sounds);
- lb[INDEX_ID_GR] = &(bmain->collections);
- lb[INDEX_ID_PAL] = &(bmain->palettes);
- lb[INDEX_ID_PC] = &(bmain->paintcurves);
- lb[INDEX_ID_BR] = &(bmain->brushes);
- lb[INDEX_ID_PA] = &(bmain->particles);
- lb[INDEX_ID_SPK] = &(bmain->speakers);
- lb[INDEX_ID_LP] = &(bmain->lightprobes);
-
- lb[INDEX_ID_WO] = &(bmain->worlds);
- lb[INDEX_ID_MC] = &(bmain->movieclips);
- lb[INDEX_ID_SCR] = &(bmain->screens);
- lb[INDEX_ID_OB] = &(bmain->objects);
- lb[INDEX_ID_LS] = &(bmain->linestyles); /* referenced by scenes */
- lb[INDEX_ID_SCE] = &(bmain->scenes);
- lb[INDEX_ID_WS] = &(bmain->workspaces); /* before wm, so it's freed after it! */
- lb[INDEX_ID_WM] = &(bmain->wm);
- lb[INDEX_ID_MSK] = &(bmain->masks);
-
- lb[INDEX_ID_NULL] = NULL;
-
- return (MAX_LIBARRAY - 1);
+ /* BACKWARDS! also watch order of free-ing! (mesh<->mat), first items freed last.
+ * This is important because freeing data decreases usercounts of other datablocks,
+ * if this data is its self freed it can crash. */
+ lb[INDEX_ID_LI] = &(
+ bmain->libraries); /* Libraries may be accessed from pretty much any other ID... */
+ lb[INDEX_ID_IP] = &(bmain->ipo);
+ lb[INDEX_ID_AC] = &(
+ bmain->actions); /* moved here to avoid problems when freeing with animato (aligorith) */
+ lb[INDEX_ID_KE] = &(bmain->shapekeys);
+ lb[INDEX_ID_PAL] = &(
+ bmain->palettes); /* referenced by gpencil, so needs to be before that to avoid crashes */
+ lb[INDEX_ID_GD] = &(
+ bmain->gpencils); /* referenced by nodes, objects, view, scene etc, before to free after. */
+ lb[INDEX_ID_NT] = &(bmain->nodetrees);
+ lb[INDEX_ID_IM] = &(bmain->images);
+ lb[INDEX_ID_TE] = &(bmain->textures);
+ lb[INDEX_ID_MA] = &(bmain->materials);
+ lb[INDEX_ID_VF] = &(bmain->fonts);
+
+ /* Important!: When adding a new object type,
+ * the specific data should be inserted here
+ */
+
+ lb[INDEX_ID_AR] = &(bmain->armatures);
+
+ lb[INDEX_ID_CF] = &(bmain->cachefiles);
+ lb[INDEX_ID_ME] = &(bmain->meshes);
+ lb[INDEX_ID_CU] = &(bmain->curves);
+ lb[INDEX_ID_MB] = &(bmain->metaballs);
+
+ lb[INDEX_ID_LT] = &(bmain->lattices);
+ lb[INDEX_ID_LA] = &(bmain->lights);
+ lb[INDEX_ID_CA] = &(bmain->cameras);
+
+ lb[INDEX_ID_TXT] = &(bmain->texts);
+ lb[INDEX_ID_SO] = &(bmain->sounds);
+ lb[INDEX_ID_GR] = &(bmain->collections);
+ lb[INDEX_ID_PAL] = &(bmain->palettes);
+ lb[INDEX_ID_PC] = &(bmain->paintcurves);
+ lb[INDEX_ID_BR] = &(bmain->brushes);
+ lb[INDEX_ID_PA] = &(bmain->particles);
+ lb[INDEX_ID_SPK] = &(bmain->speakers);
+ lb[INDEX_ID_LP] = &(bmain->lightprobes);
+
+ lb[INDEX_ID_WO] = &(bmain->worlds);
+ lb[INDEX_ID_MC] = &(bmain->movieclips);
+ lb[INDEX_ID_SCR] = &(bmain->screens);
+ lb[INDEX_ID_OB] = &(bmain->objects);
+ lb[INDEX_ID_LS] = &(bmain->linestyles); /* referenced by scenes */
+ lb[INDEX_ID_SCE] = &(bmain->scenes);
+ lb[INDEX_ID_WS] = &(bmain->workspaces); /* before wm, so it's freed after it! */
+ lb[INDEX_ID_WM] = &(bmain->wm);
+ lb[INDEX_ID_MSK] = &(bmain->masks);
+
+ lb[INDEX_ID_NULL] = NULL;
+
+ return (MAX_LIBARRAY - 1);
}
diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c
index a67f533ded5..e307ad6cac8 100644
--- a/source/blender/blenkernel/intern/mask.c
+++ b/source/blender/blenkernel/intern/mask.c
@@ -60,494 +60,503 @@
static CLG_LogRef LOG = {"bke.mask"};
static struct {
- ListBase splines;
- struct GHash *id_hash;
+ ListBase splines;
+ struct GHash *id_hash;
} mask_clipboard = {{NULL}};
-static MaskSplinePoint *mask_spline_point_next(MaskSpline *spline, MaskSplinePoint *points_array, MaskSplinePoint *point)
-{
- if (point == &points_array[spline->tot_point - 1]) {
- if (spline->flag & MASK_SPLINE_CYCLIC) {
- return &points_array[0];
- }
- else {
- return NULL;
- }
- }
- else {
- return point + 1;
- }
-}
-
-static MaskSplinePoint *mask_spline_point_prev(MaskSpline *spline, MaskSplinePoint *points_array, MaskSplinePoint *point)
-{
- if (point == points_array) {
- if (spline->flag & MASK_SPLINE_CYCLIC) {
- return &points_array[spline->tot_point - 1];
- }
- else {
- return NULL;
- }
- }
- else {
- return point - 1;
- }
-}
-
-BezTriple *BKE_mask_spline_point_next_bezt(MaskSpline *spline, MaskSplinePoint *points_array, MaskSplinePoint *point)
-{
- if (point == &points_array[spline->tot_point - 1]) {
- if (spline->flag & MASK_SPLINE_CYCLIC) {
- return &(points_array[0].bezt);
- }
- else {
- return NULL;
- }
- }
- else {
- return &((point + 1))->bezt;
- }
+static MaskSplinePoint *mask_spline_point_next(MaskSpline *spline,
+ MaskSplinePoint *points_array,
+ MaskSplinePoint *point)
+{
+ if (point == &points_array[spline->tot_point - 1]) {
+ if (spline->flag & MASK_SPLINE_CYCLIC) {
+ return &points_array[0];
+ }
+ else {
+ return NULL;
+ }
+ }
+ else {
+ return point + 1;
+ }
+}
+
+static MaskSplinePoint *mask_spline_point_prev(MaskSpline *spline,
+ MaskSplinePoint *points_array,
+ MaskSplinePoint *point)
+{
+ if (point == points_array) {
+ if (spline->flag & MASK_SPLINE_CYCLIC) {
+ return &points_array[spline->tot_point - 1];
+ }
+ else {
+ return NULL;
+ }
+ }
+ else {
+ return point - 1;
+ }
+}
+
+BezTriple *BKE_mask_spline_point_next_bezt(MaskSpline *spline,
+ MaskSplinePoint *points_array,
+ MaskSplinePoint *point)
+{
+ if (point == &points_array[spline->tot_point - 1]) {
+ if (spline->flag & MASK_SPLINE_CYCLIC) {
+ return &(points_array[0].bezt);
+ }
+ else {
+ return NULL;
+ }
+ }
+ else {
+ return &((point + 1))->bezt;
+ }
}
MaskSplinePoint *BKE_mask_spline_point_array(MaskSpline *spline)
{
- return spline->points_deform ? spline->points_deform : spline->points;
+ return spline->points_deform ? spline->points_deform : spline->points;
}
-MaskSplinePoint *BKE_mask_spline_point_array_from_point(MaskSpline *spline, const MaskSplinePoint *point_ref)
+MaskSplinePoint *BKE_mask_spline_point_array_from_point(MaskSpline *spline,
+ const MaskSplinePoint *point_ref)
{
- if ((point_ref >= spline->points) && (point_ref < &spline->points[spline->tot_point])) {
- return spline->points;
- }
+ if ((point_ref >= spline->points) && (point_ref < &spline->points[spline->tot_point])) {
+ return spline->points;
+ }
- if ((point_ref >= spline->points_deform) && (point_ref < &spline->points_deform[spline->tot_point])) {
- return spline->points_deform;
- }
+ if ((point_ref >= spline->points_deform) &&
+ (point_ref < &spline->points_deform[spline->tot_point])) {
+ return spline->points_deform;
+ }
- BLI_assert(!"wrong array");
- return NULL;
+ BLI_assert(!"wrong array");
+ return NULL;
}
/* mask layers */
MaskLayer *BKE_mask_layer_new(Mask *mask, const char *name)
{
- MaskLayer *masklay = MEM_callocN(sizeof(MaskLayer), __func__);
+ MaskLayer *masklay = MEM_callocN(sizeof(MaskLayer), __func__);
- if (name && name[0])
- BLI_strncpy(masklay->name, name, sizeof(masklay->name));
- else
- strcpy(masklay->name, "MaskLayer");
+ if (name && name[0])
+ BLI_strncpy(masklay->name, name, sizeof(masklay->name));
+ else
+ strcpy(masklay->name, "MaskLayer");
- BLI_addtail(&mask->masklayers, masklay);
+ BLI_addtail(&mask->masklayers, masklay);
- BKE_mask_layer_unique_name(mask, masklay);
+ BKE_mask_layer_unique_name(mask, masklay);
- mask->masklay_tot++;
+ mask->masklay_tot++;
- masklay->blend = MASK_BLEND_MERGE_ADD;
- masklay->alpha = 1.0f;
- masklay->flag = MASK_LAYERFLAG_FILL_DISCRETE | MASK_LAYERFLAG_FILL_OVERLAP;
+ masklay->blend = MASK_BLEND_MERGE_ADD;
+ masklay->alpha = 1.0f;
+ masklay->flag = MASK_LAYERFLAG_FILL_DISCRETE | MASK_LAYERFLAG_FILL_OVERLAP;
- return masklay;
+ return masklay;
}
/* note: may still be hidden, caller needs to check */
MaskLayer *BKE_mask_layer_active(Mask *mask)
{
- return BLI_findlink(&mask->masklayers, mask->masklay_act);
+ return BLI_findlink(&mask->masklayers, mask->masklay_act);
}
void BKE_mask_layer_active_set(Mask *mask, MaskLayer *masklay)
{
- mask->masklay_act = BLI_findindex(&mask->masklayers, masklay);
+ mask->masklay_act = BLI_findindex(&mask->masklayers, masklay);
}
void BKE_mask_layer_remove(Mask *mask, MaskLayer *masklay)
{
- BLI_remlink(&mask->masklayers, masklay);
- BKE_mask_layer_free(masklay);
+ BLI_remlink(&mask->masklayers, masklay);
+ BKE_mask_layer_free(masklay);
- mask->masklay_tot--;
+ mask->masklay_tot--;
- if (mask->masklay_act >= mask->masklay_tot)
- mask->masklay_act = mask->masklay_tot - 1;
+ if (mask->masklay_act >= mask->masklay_tot)
+ mask->masklay_act = mask->masklay_tot - 1;
}
void BKE_mask_layer_unique_name(Mask *mask, MaskLayer *masklay)
{
- BLI_uniquename(&mask->masklayers, masklay, DATA_("MaskLayer"), '.', offsetof(MaskLayer, name),
- sizeof(masklay->name));
+ BLI_uniquename(&mask->masklayers,
+ masklay,
+ DATA_("MaskLayer"),
+ '.',
+ offsetof(MaskLayer, name),
+ sizeof(masklay->name));
}
void BKE_mask_layer_rename(Mask *mask, MaskLayer *masklay, char *oldname, char *newname)
{
- BLI_strncpy(masklay->name, newname, sizeof(masklay->name));
+ BLI_strncpy(masklay->name, newname, sizeof(masklay->name));
- BKE_mask_layer_unique_name(mask, masklay);
+ BKE_mask_layer_unique_name(mask, masklay);
- /* now fix animation paths */
- BKE_animdata_fix_paths_rename_all(&mask->id, "layers", oldname, masklay->name);
+ /* now fix animation paths */
+ BKE_animdata_fix_paths_rename_all(&mask->id, "layers", oldname, masklay->name);
}
MaskLayer *BKE_mask_layer_copy(const MaskLayer *masklay)
{
- MaskLayer *masklay_new;
- MaskSpline *spline;
+ MaskLayer *masklay_new;
+ MaskSpline *spline;
- masklay_new = MEM_callocN(sizeof(MaskLayer), "new mask layer");
+ masklay_new = MEM_callocN(sizeof(MaskLayer), "new mask layer");
- BLI_strncpy(masklay_new->name, masklay->name, sizeof(masklay_new->name));
+ BLI_strncpy(masklay_new->name, masklay->name, sizeof(masklay_new->name));
- masklay_new->alpha = masklay->alpha;
- masklay_new->blend = masklay->blend;
- masklay_new->blend_flag = masklay->blend_flag;
- masklay_new->flag = masklay->flag;
- masklay_new->falloff = masklay->falloff;
- masklay_new->restrictflag = masklay->restrictflag;
+ masklay_new->alpha = masklay->alpha;
+ masklay_new->blend = masklay->blend;
+ masklay_new->blend_flag = masklay->blend_flag;
+ masklay_new->flag = masklay->flag;
+ masklay_new->falloff = masklay->falloff;
+ masklay_new->restrictflag = masklay->restrictflag;
- for (spline = masklay->splines.first; spline; spline = spline->next) {
- MaskSpline *spline_new = BKE_mask_spline_copy(spline);
+ for (spline = masklay->splines.first; spline; spline = spline->next) {
+ MaskSpline *spline_new = BKE_mask_spline_copy(spline);
- BLI_addtail(&masklay_new->splines, spline_new);
- }
+ BLI_addtail(&masklay_new->splines, spline_new);
+ }
- /* correct animation */
- if (masklay->splines_shapes.first) {
- MaskLayerShape *masklay_shape;
- MaskLayerShape *masklay_shape_new;
+ /* correct animation */
+ if (masklay->splines_shapes.first) {
+ MaskLayerShape *masklay_shape;
+ MaskLayerShape *masklay_shape_new;
- for (masklay_shape = masklay->splines_shapes.first;
- masklay_shape;
- masklay_shape = masklay_shape->next)
- {
- masklay_shape_new = MEM_callocN(sizeof(MaskLayerShape), "new mask layer shape");
+ for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
+ masklay_shape = masklay_shape->next) {
+ masklay_shape_new = MEM_callocN(sizeof(MaskLayerShape), "new mask layer shape");
- masklay_shape_new->data = MEM_dupallocN(masklay_shape->data);
- masklay_shape_new->tot_vert = masklay_shape->tot_vert;
- masklay_shape_new->flag = masklay_shape->flag;
- masklay_shape_new->frame = masklay_shape->frame;
+ masklay_shape_new->data = MEM_dupallocN(masklay_shape->data);
+ masklay_shape_new->tot_vert = masklay_shape->tot_vert;
+ masklay_shape_new->flag = masklay_shape->flag;
+ masklay_shape_new->frame = masklay_shape->frame;
- BLI_addtail(&masklay_new->splines_shapes, masklay_shape_new);
- }
- }
+ BLI_addtail(&masklay_new->splines_shapes, masklay_shape_new);
+ }
+ }
- return masklay_new;
+ return masklay_new;
}
void BKE_mask_layer_copy_list(ListBase *masklayers_new, const ListBase *masklayers)
{
- MaskLayer *layer;
+ MaskLayer *layer;
- for (layer = masklayers->first; layer; layer = layer->next) {
- MaskLayer *layer_new = BKE_mask_layer_copy(layer);
+ for (layer = masklayers->first; layer; layer = layer->next) {
+ MaskLayer *layer_new = BKE_mask_layer_copy(layer);
- BLI_addtail(masklayers_new, layer_new);
- }
+ BLI_addtail(masklayers_new, layer_new);
+ }
}
/* splines */
MaskSpline *BKE_mask_spline_add(MaskLayer *masklay)
{
- MaskSpline *spline;
+ MaskSpline *spline;
- spline = MEM_callocN(sizeof(MaskSpline), "new mask spline");
- BLI_addtail(&masklay->splines, spline);
+ spline = MEM_callocN(sizeof(MaskSpline), "new mask spline");
+ BLI_addtail(&masklay->splines, spline);
- /* spline shall have one point at least */
- spline->points = MEM_callocN(sizeof(MaskSplinePoint), "new mask spline point");
- spline->tot_point = 1;
+ /* spline shall have one point at least */
+ spline->points = MEM_callocN(sizeof(MaskSplinePoint), "new mask spline point");
+ spline->tot_point = 1;
- /* cyclic shapes are more usually used */
- // spline->flag |= MASK_SPLINE_CYCLIC; // disable because its not so nice for drawing. could be done differently
+ /* cyclic shapes are more usually used */
+ // spline->flag |= MASK_SPLINE_CYCLIC; // disable because its not so nice for drawing. could be done differently
- spline->weight_interp = MASK_SPLINE_INTERP_EASE;
+ spline->weight_interp = MASK_SPLINE_INTERP_EASE;
- BKE_mask_parent_init(&spline->parent);
+ BKE_mask_parent_init(&spline->parent);
- return spline;
+ return spline;
}
bool BKE_mask_spline_remove(MaskLayer *mask_layer, MaskSpline *spline)
{
- if (BLI_remlink_safe(&mask_layer->splines, spline) == false) {
- return false;
- }
+ if (BLI_remlink_safe(&mask_layer->splines, spline) == false) {
+ return false;
+ }
- BKE_mask_spline_free(spline);
+ BKE_mask_spline_free(spline);
- return true;
+ return true;
}
void BKE_mask_point_direction_switch(MaskSplinePoint *point)
{
- const int tot_uw = point->tot_uw;
- const int tot_uw_half = tot_uw / 2;
- int i;
+ const int tot_uw = point->tot_uw;
+ const int tot_uw_half = tot_uw / 2;
+ int i;
- float co_tmp[2];
+ float co_tmp[2];
- /* swap handles */
- copy_v2_v2(co_tmp, point->bezt.vec[0]);
- copy_v2_v2(point->bezt.vec[0], point->bezt.vec[2]);
- copy_v2_v2(point->bezt.vec[2], co_tmp);
- /* in this case the flags are unlikely to be different but swap anyway */
- SWAP(char, point->bezt.f1, point->bezt.f3);
- SWAP(char, point->bezt.h1, point->bezt.h2);
+ /* swap handles */
+ copy_v2_v2(co_tmp, point->bezt.vec[0]);
+ copy_v2_v2(point->bezt.vec[0], point->bezt.vec[2]);
+ copy_v2_v2(point->bezt.vec[2], co_tmp);
+ /* in this case the flags are unlikely to be different but swap anyway */
+ SWAP(char, point->bezt.f1, point->bezt.f3);
+ SWAP(char, point->bezt.h1, point->bezt.h2);
+ /* swap UW's */
+ if (tot_uw > 1) {
+ /* count */
+ for (i = 0; i < tot_uw_half; i++) {
+ MaskSplinePointUW *uw_a = &point->uw[i];
+ MaskSplinePointUW *uw_b = &point->uw[tot_uw - (i + 1)];
+ SWAP(MaskSplinePointUW, *uw_a, *uw_b);
+ }
+ }
- /* swap UW's */
- if (tot_uw > 1) {
- /* count */
- for (i = 0; i < tot_uw_half; i++) {
- MaskSplinePointUW *uw_a = &point->uw[i];
- MaskSplinePointUW *uw_b = &point->uw[tot_uw - (i + 1)];
- SWAP(MaskSplinePointUW, *uw_a, *uw_b);
- }
- }
-
- for (i = 0; i < tot_uw; i++) {
- MaskSplinePointUW *uw = &point->uw[i];
- uw->u = 1.0f - uw->u;
- }
+ for (i = 0; i < tot_uw; i++) {
+ MaskSplinePointUW *uw = &point->uw[i];
+ uw->u = 1.0f - uw->u;
+ }
}
void BKE_mask_spline_direction_switch(MaskLayer *masklay, MaskSpline *spline)
{
- const int tot_point = spline->tot_point;
- const int tot_point_half = tot_point / 2;
- int i, i_prev;
-
- if (tot_point < 2) {
- return;
- }
-
- /* count */
- for (i = 0; i < tot_point_half; i++) {
- MaskSplinePoint *point_a = &spline->points[i];
- MaskSplinePoint *point_b = &spline->points[tot_point - (i + 1)];
- SWAP(MaskSplinePoint, *point_a, *point_b);
- }
-
- /* correct UW's */
- i_prev = tot_point - 1;
- for (i = 0; i < tot_point; i++) {
-
- BKE_mask_point_direction_switch(&spline->points[i]);
-
- SWAP(MaskSplinePointUW *, spline->points[i].uw, spline->points[i_prev].uw);
- SWAP(int, spline->points[i].tot_uw, spline->points[i_prev].tot_uw);
-
- i_prev = i;
- }
-
- /* correct animation */
- if (masklay->splines_shapes.first) {
- MaskLayerShape *masklay_shape;
-
- const int spline_index = BKE_mask_layer_shape_spline_to_index(masklay, spline);
-
- for (masklay_shape = masklay->splines_shapes.first;
- masklay_shape;
- masklay_shape = masklay_shape->next)
- {
- MaskLayerShapeElem *fp_arr = (MaskLayerShapeElem *)masklay_shape->data;
-
- for (i = 0; i < tot_point_half; i++) {
- MaskLayerShapeElem *fp_a = &fp_arr[spline_index + (i) ];
- MaskLayerShapeElem *fp_b = &fp_arr[spline_index + (tot_point - (i + 1))];
- SWAP(MaskLayerShapeElem, *fp_a, *fp_b);
- }
- }
- }
-}
-
-
-float BKE_mask_spline_project_co(MaskSpline *spline, MaskSplinePoint *point,
- float start_u, const float co[2], const eMaskSign sign)
-{
- const float proj_eps = 1e-3;
- const float proj_eps_sq = proj_eps * proj_eps;
- const int N = 1000;
- float u = -1.0f, du = 1.0f / N, u1 = start_u, u2 = start_u;
- float ang = -1.0f;
-
- BLI_assert(ABS(sign) <= 1); /* (-1, 0, 1) */
-
- while (u1 > 0.0f || u2 < 1.0f) {
- float n1[2], n2[2], co1[2], co2[2];
- float v1[2], v2[2];
- float ang1, ang2;
-
- if (u1 >= 0.0f) {
- BKE_mask_point_segment_co(spline, point, u1, co1);
- BKE_mask_point_normal(spline, point, u1, n1);
- sub_v2_v2v2(v1, co, co1);
-
- if ((sign == MASK_PROJ_ANY) ||
- ((sign == MASK_PROJ_NEG) && (dot_v2v2(v1, n1) <= 0.0f)) ||
- ((sign == MASK_PROJ_POS) && (dot_v2v2(v1, n1) >= 0.0f)))
- {
-
- if (len_squared_v2(v1) > proj_eps_sq) {
- ang1 = angle_v2v2(v1, n1);
- if (ang1 > (float)M_PI / 2.0f)
- ang1 = (float)M_PI - ang1;
-
- if (ang < 0.0f || ang1 < ang) {
- ang = ang1;
- u = u1;
- }
- }
- else {
- u = u1;
- break;
- }
- }
- }
-
- if (u2 <= 1.0f) {
- BKE_mask_point_segment_co(spline, point, u2, co2);
- BKE_mask_point_normal(spline, point, u2, n2);
- sub_v2_v2v2(v2, co, co2);
-
- if ((sign == MASK_PROJ_ANY) ||
- ((sign == MASK_PROJ_NEG) && (dot_v2v2(v2, n2) <= 0.0f)) ||
- ((sign == MASK_PROJ_POS) && (dot_v2v2(v2, n2) >= 0.0f)))
- {
-
- if (len_squared_v2(v2) > proj_eps_sq) {
- ang2 = angle_v2v2(v2, n2);
- if (ang2 > (float)M_PI / 2.0f)
- ang2 = (float)M_PI - ang2;
-
- if (ang2 < ang) {
- ang = ang2;
- u = u2;
- }
- }
- else {
- u = u2;
- break;
- }
- }
- }
-
- u1 -= du;
- u2 += du;
- }
-
- return u;
+ const int tot_point = spline->tot_point;
+ const int tot_point_half = tot_point / 2;
+ int i, i_prev;
+
+ if (tot_point < 2) {
+ return;
+ }
+
+ /* count */
+ for (i = 0; i < tot_point_half; i++) {
+ MaskSplinePoint *point_a = &spline->points[i];
+ MaskSplinePoint *point_b = &spline->points[tot_point - (i + 1)];
+ SWAP(MaskSplinePoint, *point_a, *point_b);
+ }
+
+ /* correct UW's */
+ i_prev = tot_point - 1;
+ for (i = 0; i < tot_point; i++) {
+
+ BKE_mask_point_direction_switch(&spline->points[i]);
+
+ SWAP(MaskSplinePointUW *, spline->points[i].uw, spline->points[i_prev].uw);
+ SWAP(int, spline->points[i].tot_uw, spline->points[i_prev].tot_uw);
+
+ i_prev = i;
+ }
+
+ /* correct animation */
+ if (masklay->splines_shapes.first) {
+ MaskLayerShape *masklay_shape;
+
+ const int spline_index = BKE_mask_layer_shape_spline_to_index(masklay, spline);
+
+ for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
+ masklay_shape = masklay_shape->next) {
+ MaskLayerShapeElem *fp_arr = (MaskLayerShapeElem *)masklay_shape->data;
+
+ for (i = 0; i < tot_point_half; i++) {
+ MaskLayerShapeElem *fp_a = &fp_arr[spline_index + (i)];
+ MaskLayerShapeElem *fp_b = &fp_arr[spline_index + (tot_point - (i + 1))];
+ SWAP(MaskLayerShapeElem, *fp_a, *fp_b);
+ }
+ }
+ }
+}
+
+float BKE_mask_spline_project_co(MaskSpline *spline,
+ MaskSplinePoint *point,
+ float start_u,
+ const float co[2],
+ const eMaskSign sign)
+{
+ const float proj_eps = 1e-3;
+ const float proj_eps_sq = proj_eps * proj_eps;
+ const int N = 1000;
+ float u = -1.0f, du = 1.0f / N, u1 = start_u, u2 = start_u;
+ float ang = -1.0f;
+
+ BLI_assert(ABS(sign) <= 1); /* (-1, 0, 1) */
+
+ while (u1 > 0.0f || u2 < 1.0f) {
+ float n1[2], n2[2], co1[2], co2[2];
+ float v1[2], v2[2];
+ float ang1, ang2;
+
+ if (u1 >= 0.0f) {
+ BKE_mask_point_segment_co(spline, point, u1, co1);
+ BKE_mask_point_normal(spline, point, u1, n1);
+ sub_v2_v2v2(v1, co, co1);
+
+ if ((sign == MASK_PROJ_ANY) || ((sign == MASK_PROJ_NEG) && (dot_v2v2(v1, n1) <= 0.0f)) ||
+ ((sign == MASK_PROJ_POS) && (dot_v2v2(v1, n1) >= 0.0f))) {
+
+ if (len_squared_v2(v1) > proj_eps_sq) {
+ ang1 = angle_v2v2(v1, n1);
+ if (ang1 > (float)M_PI / 2.0f)
+ ang1 = (float)M_PI - ang1;
+
+ if (ang < 0.0f || ang1 < ang) {
+ ang = ang1;
+ u = u1;
+ }
+ }
+ else {
+ u = u1;
+ break;
+ }
+ }
+ }
+
+ if (u2 <= 1.0f) {
+ BKE_mask_point_segment_co(spline, point, u2, co2);
+ BKE_mask_point_normal(spline, point, u2, n2);
+ sub_v2_v2v2(v2, co, co2);
+
+ if ((sign == MASK_PROJ_ANY) || ((sign == MASK_PROJ_NEG) && (dot_v2v2(v2, n2) <= 0.0f)) ||
+ ((sign == MASK_PROJ_POS) && (dot_v2v2(v2, n2) >= 0.0f))) {
+
+ if (len_squared_v2(v2) > proj_eps_sq) {
+ ang2 = angle_v2v2(v2, n2);
+ if (ang2 > (float)M_PI / 2.0f)
+ ang2 = (float)M_PI - ang2;
+
+ if (ang2 < ang) {
+ ang = ang2;
+ u = u2;
+ }
+ }
+ else {
+ u = u2;
+ break;
+ }
+ }
+ }
+
+ u1 -= du;
+ u2 += du;
+ }
+
+ return u;
}
/* point */
eMaskhandleMode BKE_mask_point_handles_mode_get(MaskSplinePoint *point)
{
- BezTriple *bezt = &point->bezt;
+ BezTriple *bezt = &point->bezt;
- if (bezt->h1 == bezt->h2 && bezt->h1 == HD_ALIGN) {
- return MASK_HANDLE_MODE_STICK;
- }
+ if (bezt->h1 == bezt->h2 && bezt->h1 == HD_ALIGN) {
+ return MASK_HANDLE_MODE_STICK;
+ }
- return MASK_HANDLE_MODE_INDIVIDUAL_HANDLES;
+ return MASK_HANDLE_MODE_INDIVIDUAL_HANDLES;
}
void BKE_mask_point_handle(MaskSplinePoint *point, eMaskWhichHandle which_handle, float handle[2])
{
- BezTriple *bezt = &point->bezt;
-
- if (which_handle == MASK_WHICH_HANDLE_STICK) {
- float vec[2];
-
- sub_v2_v2v2(vec, bezt->vec[0], bezt->vec[1]);
-
- handle[0] = (bezt->vec[1][0] + vec[1]);
- handle[1] = (bezt->vec[1][1] - vec[0]);
- }
- else if (which_handle == MASK_WHICH_HANDLE_LEFT) {
- copy_v2_v2(handle, bezt->vec[0]);
- }
- else if (which_handle == MASK_WHICH_HANDLE_RIGHT) {
- copy_v2_v2(handle, bezt->vec[2]);
- }
- else {
- BLI_assert(!"Unknown handle passed to BKE_mask_point_handle");
- }
-}
-
-void BKE_mask_point_set_handle(MaskSplinePoint *point, eMaskWhichHandle which_handle,
- float loc[2], bool keep_direction,
- float orig_handle[2], float orig_vec[3][3])
-{
- BezTriple *bezt = &point->bezt;
-
- if (which_handle == MASK_WHICH_HANDLE_STICK) {
- float v1[2], v2[2], vec[2];
- if (keep_direction) {
- sub_v2_v2v2(v1, loc, orig_vec[1]);
- sub_v2_v2v2(v2, orig_handle, orig_vec[1]);
-
- project_v2_v2v2(vec, v1, v2);
-
- if (dot_v2v2(v2, vec) > 0) {
- float len = len_v2(vec);
-
- sub_v2_v2v2(v1, orig_vec[0], orig_vec[1]);
-
- mul_v2_fl(v1, len / len_v2(v1));
-
- add_v2_v2v2(bezt->vec[0], bezt->vec[1], v1);
- sub_v2_v2v2(bezt->vec[2], bezt->vec[1], v1);
- }
- else {
- copy_v3_v3(bezt->vec[0], bezt->vec[1]);
- copy_v3_v3(bezt->vec[2], bezt->vec[1]);
- }
- }
- else {
- sub_v2_v2v2(v1, loc, bezt->vec[1]);
-
- v2[0] = -v1[1];
- v2[1] = v1[0];
-
- add_v2_v2v2(bezt->vec[0], bezt->vec[1], v2);
- sub_v2_v2v2(bezt->vec[2], bezt->vec[1], v2);
- }
- }
- else if (which_handle == MASK_WHICH_HANDLE_LEFT) {
- copy_v2_v2(bezt->vec[0], loc);
- }
- else if (which_handle == MASK_WHICH_HANDLE_RIGHT) {
- copy_v2_v2(bezt->vec[2], loc);
- }
- else {
- BLI_assert(!"unknown handle passed to BKE_mask_point_set_handle");
- }
+ BezTriple *bezt = &point->bezt;
+
+ if (which_handle == MASK_WHICH_HANDLE_STICK) {
+ float vec[2];
+
+ sub_v2_v2v2(vec, bezt->vec[0], bezt->vec[1]);
+
+ handle[0] = (bezt->vec[1][0] + vec[1]);
+ handle[1] = (bezt->vec[1][1] - vec[0]);
+ }
+ else if (which_handle == MASK_WHICH_HANDLE_LEFT) {
+ copy_v2_v2(handle, bezt->vec[0]);
+ }
+ else if (which_handle == MASK_WHICH_HANDLE_RIGHT) {
+ copy_v2_v2(handle, bezt->vec[2]);
+ }
+ else {
+ BLI_assert(!"Unknown handle passed to BKE_mask_point_handle");
+ }
+}
+
+void BKE_mask_point_set_handle(MaskSplinePoint *point,
+ eMaskWhichHandle which_handle,
+ float loc[2],
+ bool keep_direction,
+ float orig_handle[2],
+ float orig_vec[3][3])
+{
+ BezTriple *bezt = &point->bezt;
+
+ if (which_handle == MASK_WHICH_HANDLE_STICK) {
+ float v1[2], v2[2], vec[2];
+ if (keep_direction) {
+ sub_v2_v2v2(v1, loc, orig_vec[1]);
+ sub_v2_v2v2(v2, orig_handle, orig_vec[1]);
+
+ project_v2_v2v2(vec, v1, v2);
+
+ if (dot_v2v2(v2, vec) > 0) {
+ float len = len_v2(vec);
+
+ sub_v2_v2v2(v1, orig_vec[0], orig_vec[1]);
+
+ mul_v2_fl(v1, len / len_v2(v1));
+
+ add_v2_v2v2(bezt->vec[0], bezt->vec[1], v1);
+ sub_v2_v2v2(bezt->vec[2], bezt->vec[1], v1);
+ }
+ else {
+ copy_v3_v3(bezt->vec[0], bezt->vec[1]);
+ copy_v3_v3(bezt->vec[2], bezt->vec[1]);
+ }
+ }
+ else {
+ sub_v2_v2v2(v1, loc, bezt->vec[1]);
+
+ v2[0] = -v1[1];
+ v2[1] = v1[0];
+
+ add_v2_v2v2(bezt->vec[0], bezt->vec[1], v2);
+ sub_v2_v2v2(bezt->vec[2], bezt->vec[1], v2);
+ }
+ }
+ else if (which_handle == MASK_WHICH_HANDLE_LEFT) {
+ copy_v2_v2(bezt->vec[0], loc);
+ }
+ else if (which_handle == MASK_WHICH_HANDLE_RIGHT) {
+ copy_v2_v2(bezt->vec[2], loc);
+ }
+ else {
+ BLI_assert(!"unknown handle passed to BKE_mask_point_set_handle");
+ }
}
void BKE_mask_point_segment_co(MaskSpline *spline, MaskSplinePoint *point, float u, float co[2])
{
- MaskSplinePoint *points_array = BKE_mask_spline_point_array_from_point(spline, point);
+ MaskSplinePoint *points_array = BKE_mask_spline_point_array_from_point(spline, point);
- BezTriple *bezt = &point->bezt, *bezt_next;
+ BezTriple *bezt = &point->bezt, *bezt_next;
- bezt_next = BKE_mask_spline_point_next_bezt(spline, points_array, point);
+ bezt_next = BKE_mask_spline_point_next_bezt(spline, points_array, point);
- if (!bezt_next) {
- copy_v2_v2(co, bezt->vec[1]);
- return;
- }
+ if (!bezt_next) {
+ copy_v2_v2(co, bezt->vec[1]);
+ return;
+ }
- interp_v2_v2v2v2v2_cubic(co, bezt->vec[1], bezt->vec[2], bezt_next->vec[0], bezt_next->vec[1], u);
+ interp_v2_v2v2v2v2_cubic(
+ co, bezt->vec[1], bezt->vec[2], bezt_next->vec[0], bezt_next->vec[1], u);
}
BLI_INLINE void orthogonal_direction_get(float vec[2], float result[2])
{
- result[0] = -vec[1];
- result[1] = vec[0];
- normalize_v2(result);
+ result[0] = -vec[1];
+ result[1] = vec[0];
+ normalize_v2(result);
}
/* TODO(sergey): This function will re-calculate loads of stuff again and again
@@ -557,289 +566,291 @@ BLI_INLINE void orthogonal_direction_get(float vec[2], float result[2])
void BKE_mask_point_normal(MaskSpline *spline, MaskSplinePoint *point, float u, float n[2])
{
- MaskSplinePoint *point_prev, *point_next;
+ MaskSplinePoint *point_prev, *point_next;
- /* TODO(sergey): This actually depends on a resolution. */
- const float du = 0.05f;
+ /* TODO(sergey): This actually depends on a resolution. */
+ const float du = 0.05f;
- BKE_mask_get_handle_point_adjacent(spline, point, &point_prev, &point_next);
+ BKE_mask_get_handle_point_adjacent(spline, point, &point_prev, &point_next);
- if (u - du < 0.0f && point_prev == NULL) {
- float co[2], dir[2];
- BKE_mask_point_segment_co(spline, point, u + du, co);
- sub_v2_v2v2(dir, co, point->bezt.vec[1]);
- orthogonal_direction_get(dir, n);
- }
- else if (u + du > 1.0f && point_next == NULL) {
- float co[2], dir[2];
- BKE_mask_point_segment_co(spline, point, u - du, co);
- sub_v2_v2v2(dir, point->bezt.vec[1], co);
- orthogonal_direction_get(dir, n);
- }
- else {
- float prev_co[2], next_co[2], co[2];
- float dir1[2], dir2[2], dir[2];
+ if (u - du < 0.0f && point_prev == NULL) {
+ float co[2], dir[2];
+ BKE_mask_point_segment_co(spline, point, u + du, co);
+ sub_v2_v2v2(dir, co, point->bezt.vec[1]);
+ orthogonal_direction_get(dir, n);
+ }
+ else if (u + du > 1.0f && point_next == NULL) {
+ float co[2], dir[2];
+ BKE_mask_point_segment_co(spline, point, u - du, co);
+ sub_v2_v2v2(dir, point->bezt.vec[1], co);
+ orthogonal_direction_get(dir, n);
+ }
+ else {
+ float prev_co[2], next_co[2], co[2];
+ float dir1[2], dir2[2], dir[2];
- if (u - du < 0.0f) {
- BKE_mask_point_segment_co(spline, point_prev, 1.0f + (u - du), prev_co);
- }
- else {
- BKE_mask_point_segment_co(spline, point, u - du, prev_co);
- }
+ if (u - du < 0.0f) {
+ BKE_mask_point_segment_co(spline, point_prev, 1.0f + (u - du), prev_co);
+ }
+ else {
+ BKE_mask_point_segment_co(spline, point, u - du, prev_co);
+ }
- BKE_mask_point_segment_co(spline, point, u, co);
+ BKE_mask_point_segment_co(spline, point, u, co);
- if (u + du > 1.0f) {
- BKE_mask_point_segment_co(spline, point_next, u + du - 1.0f, next_co);
- }
- else {
- BKE_mask_point_segment_co(spline, point, u + du, next_co);
- }
+ if (u + du > 1.0f) {
+ BKE_mask_point_segment_co(spline, point_next, u + du - 1.0f, next_co);
+ }
+ else {
+ BKE_mask_point_segment_co(spline, point, u + du, next_co);
+ }
- sub_v2_v2v2(dir1, co, prev_co);
- sub_v2_v2v2(dir2, next_co, co);
+ sub_v2_v2v2(dir1, co, prev_co);
+ sub_v2_v2v2(dir2, next_co, co);
- normalize_v2(dir1);
- normalize_v2(dir2);
- add_v2_v2v2(dir, dir1, dir2);
+ normalize_v2(dir1);
+ normalize_v2(dir2);
+ add_v2_v2v2(dir, dir1, dir2);
- orthogonal_direction_get(dir, n);
- }
+ orthogonal_direction_get(dir, n);
+ }
}
static float mask_point_interp_weight(BezTriple *bezt, BezTriple *bezt_next, const float u)
{
- return (bezt->weight * (1.0f - u)) + (bezt_next->weight * u);
+ return (bezt->weight * (1.0f - u)) + (bezt_next->weight * u);
}
float BKE_mask_point_weight_scalar(MaskSpline *spline, MaskSplinePoint *point, const float u)
{
- MaskSplinePoint *points_array = BKE_mask_spline_point_array_from_point(spline, point);
- BezTriple *bezt = &point->bezt, *bezt_next;
+ MaskSplinePoint *points_array = BKE_mask_spline_point_array_from_point(spline, point);
+ BezTriple *bezt = &point->bezt, *bezt_next;
- bezt_next = BKE_mask_spline_point_next_bezt(spline, points_array, point);
+ bezt_next = BKE_mask_spline_point_next_bezt(spline, points_array, point);
- if (!bezt_next) {
- return bezt->weight;
- }
- else if (u <= 0.0f) {
- return bezt->weight;
- }
- else if (u >= 1.0f) {
- return bezt_next->weight;
- }
- else {
- return mask_point_interp_weight(bezt, bezt_next, u);
- }
+ if (!bezt_next) {
+ return bezt->weight;
+ }
+ else if (u <= 0.0f) {
+ return bezt->weight;
+ }
+ else if (u >= 1.0f) {
+ return bezt_next->weight;
+ }
+ else {
+ return mask_point_interp_weight(bezt, bezt_next, u);
+ }
}
float BKE_mask_point_weight(MaskSpline *spline, MaskSplinePoint *point, const float u)
{
- MaskSplinePoint *points_array = BKE_mask_spline_point_array_from_point(spline, point);
- BezTriple *bezt = &point->bezt, *bezt_next;
-
- bezt_next = BKE_mask_spline_point_next_bezt(spline, points_array, point);
-
- if (!bezt_next) {
- return bezt->weight;
- }
- else if (u <= 0.0f) {
- return bezt->weight;
- }
- else if (u >= 1.0f) {
- return bezt_next->weight;
- }
- else {
- float cur_u = 0.0f, cur_w = 0.0f, next_u = 0.0f, next_w = 0.0f, fac; /* Quite warnings */
- int i;
-
- for (i = 0; i <= point->tot_uw; i++) {
-
- if (i == 0) {
- cur_u = 0.0f;
- cur_w = 1.0f; /* mask_point_interp_weight will scale it */
- }
- else {
- cur_u = point->uw[i - 1].u;
- cur_w = point->uw[i - 1].w;
- }
-
- if (i == point->tot_uw) {
- next_u = 1.0f;
- next_w = 1.0f; /* mask_point_interp_weight will scale it */
- }
- else {
- next_u = point->uw[i].u;
- next_w = point->uw[i].w;
- }
-
- if (u >= cur_u && u <= next_u) {
- break;
- }
- }
-
- fac = (u - cur_u) / (next_u - cur_u);
-
- cur_w *= mask_point_interp_weight(bezt, bezt_next, cur_u);
- next_w *= mask_point_interp_weight(bezt, bezt_next, next_u);
-
- if (spline->weight_interp == MASK_SPLINE_INTERP_EASE) {
- return cur_w + (next_w - cur_w) * (3.0f * fac * fac - 2.0f * fac * fac * fac);
- }
- else {
- return (1.0f - fac) * cur_w + fac * next_w;
- }
- }
+ MaskSplinePoint *points_array = BKE_mask_spline_point_array_from_point(spline, point);
+ BezTriple *bezt = &point->bezt, *bezt_next;
+
+ bezt_next = BKE_mask_spline_point_next_bezt(spline, points_array, point);
+
+ if (!bezt_next) {
+ return bezt->weight;
+ }
+ else if (u <= 0.0f) {
+ return bezt->weight;
+ }
+ else if (u >= 1.0f) {
+ return bezt_next->weight;
+ }
+ else {
+ float cur_u = 0.0f, cur_w = 0.0f, next_u = 0.0f, next_w = 0.0f, fac; /* Quite warnings */
+ int i;
+
+ for (i = 0; i <= point->tot_uw; i++) {
+
+ if (i == 0) {
+ cur_u = 0.0f;
+ cur_w = 1.0f; /* mask_point_interp_weight will scale it */
+ }
+ else {
+ cur_u = point->uw[i - 1].u;
+ cur_w = point->uw[i - 1].w;
+ }
+
+ if (i == point->tot_uw) {
+ next_u = 1.0f;
+ next_w = 1.0f; /* mask_point_interp_weight will scale it */
+ }
+ else {
+ next_u = point->uw[i].u;
+ next_w = point->uw[i].w;
+ }
+
+ if (u >= cur_u && u <= next_u) {
+ break;
+ }
+ }
+
+ fac = (u - cur_u) / (next_u - cur_u);
+
+ cur_w *= mask_point_interp_weight(bezt, bezt_next, cur_u);
+ next_w *= mask_point_interp_weight(bezt, bezt_next, next_u);
+
+ if (spline->weight_interp == MASK_SPLINE_INTERP_EASE) {
+ return cur_w + (next_w - cur_w) * (3.0f * fac * fac - 2.0f * fac * fac * fac);
+ }
+ else {
+ return (1.0f - fac) * cur_w + fac * next_w;
+ }
+ }
}
MaskSplinePointUW *BKE_mask_point_sort_uw(MaskSplinePoint *point, MaskSplinePointUW *uw)
{
- if (point->tot_uw > 1) {
- int idx = uw - point->uw;
+ if (point->tot_uw > 1) {
+ int idx = uw - point->uw;
- if (idx > 0 && point->uw[idx - 1].u > uw->u) {
- while (idx > 0 && point->uw[idx - 1].u > point->uw[idx].u) {
- SWAP(MaskSplinePointUW, point->uw[idx - 1], point->uw[idx]);
- idx--;
- }
- }
+ if (idx > 0 && point->uw[idx - 1].u > uw->u) {
+ while (idx > 0 && point->uw[idx - 1].u > point->uw[idx].u) {
+ SWAP(MaskSplinePointUW, point->uw[idx - 1], point->uw[idx]);
+ idx--;
+ }
+ }
- if (idx < point->tot_uw - 1 && point->uw[idx + 1].u < uw->u) {
- while (idx < point->tot_uw - 1 && point->uw[idx + 1].u < point->uw[idx].u) {
- SWAP(MaskSplinePointUW, point->uw[idx + 1], point->uw[idx]);
- idx++;
- }
- }
+ if (idx < point->tot_uw - 1 && point->uw[idx + 1].u < uw->u) {
+ while (idx < point->tot_uw - 1 && point->uw[idx + 1].u < point->uw[idx].u) {
+ SWAP(MaskSplinePointUW, point->uw[idx + 1], point->uw[idx]);
+ idx++;
+ }
+ }
- return &point->uw[idx];
- }
+ return &point->uw[idx];
+ }
- return uw;
+ return uw;
}
void BKE_mask_point_add_uw(MaskSplinePoint *point, float u, float w)
{
- if (!point->uw)
- point->uw = MEM_mallocN(sizeof(*point->uw), "mask point uw");
- else
- point->uw = MEM_reallocN(point->uw, (point->tot_uw + 1) * sizeof(*point->uw));
+ if (!point->uw)
+ point->uw = MEM_mallocN(sizeof(*point->uw), "mask point uw");
+ else
+ point->uw = MEM_reallocN(point->uw, (point->tot_uw + 1) * sizeof(*point->uw));
- point->uw[point->tot_uw].u = u;
- point->uw[point->tot_uw].w = w;
- point->uw[point->tot_uw].flag = 0;
+ point->uw[point->tot_uw].u = u;
+ point->uw[point->tot_uw].w = w;
+ point->uw[point->tot_uw].flag = 0;
- point->tot_uw++;
+ point->tot_uw++;
- BKE_mask_point_sort_uw(point, &point->uw[point->tot_uw - 1]);
+ BKE_mask_point_sort_uw(point, &point->uw[point->tot_uw - 1]);
}
void BKE_mask_point_select_set(MaskSplinePoint *point, const bool do_select)
{
- int i;
-
- if (do_select) {
- MASKPOINT_SEL_ALL(point);
- }
- else {
- MASKPOINT_DESEL_ALL(point);
- }
-
- for (i = 0; i < point->tot_uw; i++) {
- if (do_select) {
- point->uw[i].flag |= SELECT;
- }
- else {
- point->uw[i].flag &= ~SELECT;
- }
- }
-}
-
-void BKE_mask_point_select_set_handle(MaskSplinePoint *point, const eMaskWhichHandle which_handle, const bool do_select)
-{
- if (do_select) {
- if (ELEM(which_handle, MASK_WHICH_HANDLE_STICK, MASK_WHICH_HANDLE_BOTH)) {
- point->bezt.f1 |= SELECT;
- point->bezt.f3 |= SELECT;
- }
- else if (which_handle == MASK_WHICH_HANDLE_LEFT) {
- point->bezt.f1 |= SELECT;
- }
- else if (which_handle == MASK_WHICH_HANDLE_RIGHT) {
- point->bezt.f3 |= SELECT;
- }
- else {
- BLI_assert(!"Wrong which_handle passed to BKE_mask_point_select_set_handle");
- }
- }
- else {
- if (ELEM(which_handle, MASK_WHICH_HANDLE_STICK, MASK_WHICH_HANDLE_BOTH)) {
- point->bezt.f1 &= ~SELECT;
- point->bezt.f3 &= ~SELECT;
- }
- else if (which_handle == MASK_WHICH_HANDLE_LEFT) {
- point->bezt.f1 &= ~SELECT;
- }
- else if (which_handle == MASK_WHICH_HANDLE_RIGHT) {
- point->bezt.f3 &= ~SELECT;
- }
- else {
- BLI_assert(!"Wrong which_handle passed to BKE_mask_point_select_set_handle");
- }
- }
+ int i;
+
+ if (do_select) {
+ MASKPOINT_SEL_ALL(point);
+ }
+ else {
+ MASKPOINT_DESEL_ALL(point);
+ }
+
+ for (i = 0; i < point->tot_uw; i++) {
+ if (do_select) {
+ point->uw[i].flag |= SELECT;
+ }
+ else {
+ point->uw[i].flag &= ~SELECT;
+ }
+ }
+}
+
+void BKE_mask_point_select_set_handle(MaskSplinePoint *point,
+ const eMaskWhichHandle which_handle,
+ const bool do_select)
+{
+ if (do_select) {
+ if (ELEM(which_handle, MASK_WHICH_HANDLE_STICK, MASK_WHICH_HANDLE_BOTH)) {
+ point->bezt.f1 |= SELECT;
+ point->bezt.f3 |= SELECT;
+ }
+ else if (which_handle == MASK_WHICH_HANDLE_LEFT) {
+ point->bezt.f1 |= SELECT;
+ }
+ else if (which_handle == MASK_WHICH_HANDLE_RIGHT) {
+ point->bezt.f3 |= SELECT;
+ }
+ else {
+ BLI_assert(!"Wrong which_handle passed to BKE_mask_point_select_set_handle");
+ }
+ }
+ else {
+ if (ELEM(which_handle, MASK_WHICH_HANDLE_STICK, MASK_WHICH_HANDLE_BOTH)) {
+ point->bezt.f1 &= ~SELECT;
+ point->bezt.f3 &= ~SELECT;
+ }
+ else if (which_handle == MASK_WHICH_HANDLE_LEFT) {
+ point->bezt.f1 &= ~SELECT;
+ }
+ else if (which_handle == MASK_WHICH_HANDLE_RIGHT) {
+ point->bezt.f3 &= ~SELECT;
+ }
+ else {
+ BLI_assert(!"Wrong which_handle passed to BKE_mask_point_select_set_handle");
+ }
+ }
}
/* only mask block itself */
static Mask *mask_alloc(Main *bmain, const char *name)
{
- Mask *mask;
+ Mask *mask;
- mask = BKE_libblock_alloc(bmain, ID_MSK, name, 0);
+ mask = BKE_libblock_alloc(bmain, ID_MSK, name, 0);
- id_fake_user_set(&mask->id);
+ id_fake_user_set(&mask->id);
- return mask;
+ return mask;
}
Mask *BKE_mask_new(Main *bmain, const char *name)
{
- Mask *mask;
- char mask_name[MAX_ID_NAME - 2];
+ Mask *mask;
+ char mask_name[MAX_ID_NAME - 2];
- if (name && name[0])
- BLI_strncpy(mask_name, name, sizeof(mask_name));
- else
- strcpy(mask_name, "Mask");
+ if (name && name[0])
+ BLI_strncpy(mask_name, name, sizeof(mask_name));
+ else
+ strcpy(mask_name, "Mask");
- mask = mask_alloc(bmain, mask_name);
+ mask = mask_alloc(bmain, mask_name);
- /* arbitrary defaults */
- mask->sfra = 1;
- mask->efra = 100;
+ /* arbitrary defaults */
+ mask->sfra = 1;
+ mask->efra = 100;
- DEG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
- return mask;
+ return mask;
}
/* TODO(sergey): Use generic BKE_libblock_copy_nolib() instead. */
/* TODO(bastien): Use new super cool & generic BKE_id_copy_ex() instead! */
Mask *BKE_mask_copy_nolib(Mask *mask)
{
- Mask *mask_new;
+ Mask *mask_new;
- mask_new = MEM_dupallocN(mask);
+ mask_new = MEM_dupallocN(mask);
- /*take care here! - we may want to copy anim data */
- mask_new->adt = NULL;
+ /*take care here! - we may want to copy anim data */
+ mask_new->adt = NULL;
- BLI_listbase_clear(&mask_new->masklayers);
+ BLI_listbase_clear(&mask_new->masklayers);
- BKE_mask_layer_copy_list(&mask_new->masklayers, &mask->masklayers);
+ BKE_mask_layer_copy_list(&mask_new->masklayers, &mask->masklayers);
- /* enable fake user by default */
- id_fake_user_set(&mask->id);
+ /* enable fake user by default */
+ id_fake_user_set(&mask->id);
- return mask_new;
+ return mask_new;
}
/**
@@ -850,673 +861,697 @@ Mask *BKE_mask_copy_nolib(Mask *mask)
*
* \param flag: Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
*/
-void BKE_mask_copy_data(Main *UNUSED(bmain), Mask *mask_dst, const Mask *mask_src, const int UNUSED(flag))
+void BKE_mask_copy_data(Main *UNUSED(bmain),
+ Mask *mask_dst,
+ const Mask *mask_src,
+ const int UNUSED(flag))
{
- BLI_listbase_clear(&mask_dst->masklayers);
+ BLI_listbase_clear(&mask_dst->masklayers);
- BKE_mask_layer_copy_list(&mask_dst->masklayers, &mask_src->masklayers); /* TODO add unused flag to those as well. */
+ BKE_mask_layer_copy_list(&mask_dst->masklayers,
+ &mask_src->masklayers); /* TODO add unused flag to those as well. */
- /* enable fake user by default */
- id_fake_user_set(&mask_dst->id);
+ /* enable fake user by default */
+ id_fake_user_set(&mask_dst->id);
}
Mask *BKE_mask_copy(Main *bmain, const Mask *mask)
{
- Mask *mask_copy;
- BKE_id_copy(bmain, &mask->id, (ID **)&mask_copy);
- return mask_copy;
+ Mask *mask_copy;
+ BKE_id_copy(bmain, &mask->id, (ID **)&mask_copy);
+ return mask_copy;
}
void BKE_mask_make_local(Main *bmain, Mask *mask, const bool lib_local)
{
- BKE_id_make_local_generic(bmain, &mask->id, true, lib_local);
+ BKE_id_make_local_generic(bmain, &mask->id, true, lib_local);
}
void BKE_mask_point_free(MaskSplinePoint *point)
{
- if (point->uw)
- MEM_freeN(point->uw);
+ if (point->uw)
+ MEM_freeN(point->uw);
}
void BKE_mask_spline_free(MaskSpline *spline)
{
- int i = 0;
+ int i = 0;
- for (i = 0; i < spline->tot_point; i++) {
- MaskSplinePoint *point;
- point = &spline->points[i];
- BKE_mask_point_free(point);
+ for (i = 0; i < spline->tot_point; i++) {
+ MaskSplinePoint *point;
+ point = &spline->points[i];
+ BKE_mask_point_free(point);
- if (spline->points_deform) {
- point = &spline->points_deform[i];
- BKE_mask_point_free(point);
- }
- }
+ if (spline->points_deform) {
+ point = &spline->points_deform[i];
+ BKE_mask_point_free(point);
+ }
+ }
- MEM_freeN(spline->points);
+ MEM_freeN(spline->points);
- if (spline->points_deform) {
- MEM_freeN(spline->points_deform);
- }
+ if (spline->points_deform) {
+ MEM_freeN(spline->points_deform);
+ }
- MEM_freeN(spline);
+ MEM_freeN(spline);
}
void BKE_mask_spline_free_list(ListBase *splines)
{
- MaskSpline *spline = splines->first;
- while (spline) {
- MaskSpline *next_spline = spline->next;
+ MaskSpline *spline = splines->first;
+ while (spline) {
+ MaskSpline *next_spline = spline->next;
- BLI_remlink(splines, spline);
- BKE_mask_spline_free(spline);
+ BLI_remlink(splines, spline);
+ BKE_mask_spline_free(spline);
- spline = next_spline;
- }
+ spline = next_spline;
+ }
}
static MaskSplinePoint *mask_spline_points_copy(const MaskSplinePoint *points, int tot_point)
{
- MaskSplinePoint *npoints;
- int i;
+ MaskSplinePoint *npoints;
+ int i;
- npoints = MEM_dupallocN(points);
+ npoints = MEM_dupallocN(points);
- for (i = 0; i < tot_point; i++) {
- MaskSplinePoint *point = &npoints[i];
+ for (i = 0; i < tot_point; i++) {
+ MaskSplinePoint *point = &npoints[i];
- if (point->uw)
- point->uw = MEM_dupallocN(point->uw);
- }
+ if (point->uw)
+ point->uw = MEM_dupallocN(point->uw);
+ }
- return npoints;
+ return npoints;
}
MaskSpline *BKE_mask_spline_copy(const MaskSpline *spline)
{
- MaskSpline *nspline = MEM_callocN(sizeof(MaskSpline), "new spline");
+ MaskSpline *nspline = MEM_callocN(sizeof(MaskSpline), "new spline");
- *nspline = *spline;
+ *nspline = *spline;
- nspline->points_deform = NULL;
- nspline->points = mask_spline_points_copy(spline->points, spline->tot_point);
+ nspline->points_deform = NULL;
+ nspline->points = mask_spline_points_copy(spline->points, spline->tot_point);
- if (spline->points_deform) {
- nspline->points_deform = mask_spline_points_copy(spline->points_deform, spline->tot_point);
- }
+ if (spline->points_deform) {
+ nspline->points_deform = mask_spline_points_copy(spline->points_deform, spline->tot_point);
+ }
- return nspline;
+ return nspline;
}
/* note: does NOT add to the list */
MaskLayerShape *BKE_mask_layer_shape_alloc(MaskLayer *masklay, const int frame)
{
- MaskLayerShape *masklay_shape;
- int tot_vert = BKE_mask_layer_shape_totvert(masklay);
+ MaskLayerShape *masklay_shape;
+ int tot_vert = BKE_mask_layer_shape_totvert(masklay);
- masklay_shape = MEM_mallocN(sizeof(MaskLayerShape), __func__);
- masklay_shape->frame = frame;
- masklay_shape->tot_vert = tot_vert;
- masklay_shape->data = MEM_mallocN(tot_vert * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE, __func__);
+ masklay_shape = MEM_mallocN(sizeof(MaskLayerShape), __func__);
+ masklay_shape->frame = frame;
+ masklay_shape->tot_vert = tot_vert;
+ masklay_shape->data = MEM_mallocN(tot_vert * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE,
+ __func__);
- return masklay_shape;
+ return masklay_shape;
}
void BKE_mask_layer_shape_free(MaskLayerShape *masklay_shape)
{
- if (masklay_shape->data) {
- MEM_freeN(masklay_shape->data);
- }
+ if (masklay_shape->data) {
+ MEM_freeN(masklay_shape->data);
+ }
- MEM_freeN(masklay_shape);
+ MEM_freeN(masklay_shape);
}
/** \brief Free all animation keys for a mask layer
*/
void BKE_mask_layer_free_shapes(MaskLayer *masklay)
{
- MaskLayerShape *masklay_shape;
+ MaskLayerShape *masklay_shape;
- /* free animation data */
- masklay_shape = masklay->splines_shapes.first;
- while (masklay_shape) {
- MaskLayerShape *next_masklay_shape = masklay_shape->next;
+ /* free animation data */
+ masklay_shape = masklay->splines_shapes.first;
+ while (masklay_shape) {
+ MaskLayerShape *next_masklay_shape = masklay_shape->next;
- BLI_remlink(&masklay->splines_shapes, masklay_shape);
- BKE_mask_layer_shape_free(masklay_shape);
+ BLI_remlink(&masklay->splines_shapes, masklay_shape);
+ BKE_mask_layer_shape_free(masklay_shape);
- masklay_shape = next_masklay_shape;
- }
+ masklay_shape = next_masklay_shape;
+ }
}
void BKE_mask_layer_free(MaskLayer *masklay)
{
- /* free splines */
- BKE_mask_spline_free_list(&masklay->splines);
+ /* free splines */
+ BKE_mask_spline_free_list(&masklay->splines);
- /* free animation data */
- BKE_mask_layer_free_shapes(masklay);
+ /* free animation data */
+ BKE_mask_layer_free_shapes(masklay);
- MEM_freeN(masklay);
+ MEM_freeN(masklay);
}
void BKE_mask_layer_free_list(ListBase *masklayers)
{
- MaskLayer *masklay = masklayers->first;
+ MaskLayer *masklay = masklayers->first;
- while (masklay) {
- MaskLayer *masklay_next = masklay->next;
+ while (masklay) {
+ MaskLayer *masklay_next = masklay->next;
- BLI_remlink(masklayers, masklay);
- BKE_mask_layer_free(masklay);
+ BLI_remlink(masklayers, masklay);
+ BKE_mask_layer_free(masklay);
- masklay = masklay_next;
- }
+ masklay = masklay_next;
+ }
}
/** Free (or release) any data used by this mask (does not free the mask itself). */
void BKE_mask_free(Mask *mask)
{
- BKE_animdata_free((ID *)mask, false);
+ BKE_animdata_free((ID *)mask, false);
- /* free mask data */
- BKE_mask_layer_free_list(&mask->masklayers);
+ /* free mask data */
+ BKE_mask_layer_free_list(&mask->masklayers);
}
void BKE_mask_coord_from_frame(float r_co[2], const float co[2], const float frame_size[2])
{
- if (frame_size[0] == frame_size[1]) {
- r_co[0] = co[0];
- r_co[1] = co[1];
- }
- else if (frame_size[0] < frame_size[1]) {
- r_co[0] = ((co[0] - 0.5f) * (frame_size[0] / frame_size[1])) + 0.5f;
- r_co[1] = co[1];
- }
- else { /* (frame_size[0] > frame_size[1]) */
- r_co[0] = co[0];
- r_co[1] = ((co[1] - 0.5f) * (frame_size[1] / frame_size[0])) + 0.5f;
- }
+ if (frame_size[0] == frame_size[1]) {
+ r_co[0] = co[0];
+ r_co[1] = co[1];
+ }
+ else if (frame_size[0] < frame_size[1]) {
+ r_co[0] = ((co[0] - 0.5f) * (frame_size[0] / frame_size[1])) + 0.5f;
+ r_co[1] = co[1];
+ }
+ else { /* (frame_size[0] > frame_size[1]) */
+ r_co[0] = co[0];
+ r_co[1] = ((co[1] - 0.5f) * (frame_size[1] / frame_size[0])) + 0.5f;
+ }
}
-void BKE_mask_coord_from_movieclip(MovieClip *clip, MovieClipUser *user, float r_co[2], const float co[2])
+void BKE_mask_coord_from_movieclip(MovieClip *clip,
+ MovieClipUser *user,
+ float r_co[2],
+ const float co[2])
{
- float aspx, aspy;
- float frame_size[2];
+ float aspx, aspy;
+ float frame_size[2];
- /* scaling for the clip */
- BKE_movieclip_get_size_fl(clip, user, frame_size);
- BKE_movieclip_get_aspect(clip, &aspx, &aspy);
+ /* scaling for the clip */
+ BKE_movieclip_get_size_fl(clip, user, frame_size);
+ BKE_movieclip_get_aspect(clip, &aspx, &aspy);
- frame_size[1] *= (aspy / aspx);
+ frame_size[1] *= (aspy / aspx);
- BKE_mask_coord_from_frame(r_co, co, frame_size);
+ BKE_mask_coord_from_frame(r_co, co, frame_size);
}
void BKE_mask_coord_from_image(Image *image, ImageUser *iuser, float r_co[2], const float co[2])
{
- float aspx, aspy;
- float frame_size[2];
+ float aspx, aspy;
+ float frame_size[2];
- BKE_image_get_size_fl(image, iuser, frame_size);
- BKE_image_get_aspect(image, &aspx, &aspy);
+ BKE_image_get_size_fl(image, iuser, frame_size);
+ BKE_image_get_aspect(image, &aspx, &aspy);
- frame_size[1] *= (aspy / aspx);
+ frame_size[1] *= (aspy / aspx);
- BKE_mask_coord_from_frame(r_co, co, frame_size);
+ BKE_mask_coord_from_frame(r_co, co, frame_size);
}
/* as above but divide */
void BKE_mask_coord_to_frame(float r_co[2], const float co[2], const float frame_size[2])
{
- if (frame_size[0] == frame_size[1]) {
- r_co[0] = co[0];
- r_co[1] = co[1];
- }
- else if (frame_size[0] < frame_size[1]) {
- r_co[0] = ((co[0] - 0.5f) / (frame_size[0] / frame_size[1])) + 0.5f;
- r_co[1] = co[1];
- }
- else { /* (frame_size[0] > frame_size[1]) */
- r_co[0] = co[0];
- r_co[1] = ((co[1] - 0.5f) / (frame_size[1] / frame_size[0])) + 0.5f;
- }
+ if (frame_size[0] == frame_size[1]) {
+ r_co[0] = co[0];
+ r_co[1] = co[1];
+ }
+ else if (frame_size[0] < frame_size[1]) {
+ r_co[0] = ((co[0] - 0.5f) / (frame_size[0] / frame_size[1])) + 0.5f;
+ r_co[1] = co[1];
+ }
+ else { /* (frame_size[0] > frame_size[1]) */
+ r_co[0] = co[0];
+ r_co[1] = ((co[1] - 0.5f) / (frame_size[1] / frame_size[0])) + 0.5f;
+ }
}
-void BKE_mask_coord_to_movieclip(MovieClip *clip, MovieClipUser *user, float r_co[2], const float co[2])
+void BKE_mask_coord_to_movieclip(MovieClip *clip,
+ MovieClipUser *user,
+ float r_co[2],
+ const float co[2])
{
- float aspx, aspy;
- float frame_size[2];
+ float aspx, aspy;
+ float frame_size[2];
- /* scaling for the clip */
- BKE_movieclip_get_size_fl(clip, user, frame_size);
- BKE_movieclip_get_aspect(clip, &aspx, &aspy);
+ /* scaling for the clip */
+ BKE_movieclip_get_size_fl(clip, user, frame_size);
+ BKE_movieclip_get_aspect(clip, &aspx, &aspy);
- frame_size[1] *= (aspy / aspx);
+ frame_size[1] *= (aspy / aspx);
- BKE_mask_coord_to_frame(r_co, co, frame_size);
+ BKE_mask_coord_to_frame(r_co, co, frame_size);
}
void BKE_mask_coord_to_image(Image *image, ImageUser *iuser, float r_co[2], const float co[2])
{
- float aspx, aspy;
- float frame_size[2];
+ float aspx, aspy;
+ float frame_size[2];
- /* scaling for the clip */
- BKE_image_get_size_fl(image, iuser, frame_size);
- BKE_image_get_aspect(image, &aspx, &aspy);
+ /* scaling for the clip */
+ BKE_image_get_size_fl(image, iuser, frame_size);
+ BKE_image_get_aspect(image, &aspx, &aspy);
- frame_size[1] *= (aspy / aspx);
+ frame_size[1] *= (aspy / aspx);
- BKE_mask_coord_to_frame(r_co, co, frame_size);
+ BKE_mask_coord_to_frame(r_co, co, frame_size);
}
-void BKE_mask_point_parent_matrix_get(MaskSplinePoint *point, float ctime, float parent_matrix[3][3])
+void BKE_mask_point_parent_matrix_get(MaskSplinePoint *point,
+ float ctime,
+ float parent_matrix[3][3])
{
- MaskParent *parent = &point->parent;
+ MaskParent *parent = &point->parent;
- unit_m3(parent_matrix);
+ unit_m3(parent_matrix);
- if (!parent) {
- return;
- }
+ if (!parent) {
+ return;
+ }
- if (parent->id_type == ID_MC) {
- if (parent->id) {
- MovieClip *clip = (MovieClip *) parent->id;
- MovieTracking *tracking = (MovieTracking *) &clip->tracking;
- MovieTrackingObject *ob = BKE_tracking_object_get_named(tracking, parent->parent);
+ if (parent->id_type == ID_MC) {
+ if (parent->id) {
+ MovieClip *clip = (MovieClip *)parent->id;
+ MovieTracking *tracking = (MovieTracking *)&clip->tracking;
+ MovieTrackingObject *ob = BKE_tracking_object_get_named(tracking, parent->parent);
- if (ob) {
- MovieClipUser user = {0};
- float clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, ctime);
- BKE_movieclip_user_set_frame(&user, ctime);
+ if (ob) {
+ MovieClipUser user = {0};
+ float clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, ctime);
+ BKE_movieclip_user_set_frame(&user, ctime);
- if (parent->type == MASK_PARENT_POINT_TRACK) {
- MovieTrackingTrack *track = BKE_tracking_track_get_named(tracking, ob, parent->sub_parent);
+ if (parent->type == MASK_PARENT_POINT_TRACK) {
+ MovieTrackingTrack *track = BKE_tracking_track_get_named(
+ tracking, ob, parent->sub_parent);
- if (track) {
- float marker_position[2], parent_co[2];
- BKE_tracking_marker_get_subframe_position(track, clip_framenr, marker_position);
- BKE_mask_coord_from_movieclip(clip, &user, parent_co, marker_position);
- sub_v2_v2v2(parent_matrix[2], parent_co, parent->parent_orig);
- }
- }
- else /* if (parent->type == MASK_PARENT_PLANE_TRACK) */ {
- MovieTrackingPlaneTrack *plane_track = BKE_tracking_plane_track_get_named(tracking, ob, parent->sub_parent);
+ if (track) {
+ float marker_position[2], parent_co[2];
+ BKE_tracking_marker_get_subframe_position(track, clip_framenr, marker_position);
+ BKE_mask_coord_from_movieclip(clip, &user, parent_co, marker_position);
+ sub_v2_v2v2(parent_matrix[2], parent_co, parent->parent_orig);
+ }
+ }
+ else /* if (parent->type == MASK_PARENT_PLANE_TRACK) */ {
+ MovieTrackingPlaneTrack *plane_track = BKE_tracking_plane_track_get_named(
+ tracking, ob, parent->sub_parent);
- if (plane_track) {
- float corners[4][2];
- float aspx, aspy;
- float frame_size[2], H[3][3], mask_from_clip_matrix[3][3], mask_to_clip_matrix[3][3];
+ if (plane_track) {
+ float corners[4][2];
+ float aspx, aspy;
+ float frame_size[2], H[3][3], mask_from_clip_matrix[3][3], mask_to_clip_matrix[3][3];
- BKE_tracking_plane_marker_get_subframe_corners(plane_track, ctime, corners);
- BKE_tracking_homography_between_two_quads(parent->parent_corners_orig, corners, H);
+ BKE_tracking_plane_marker_get_subframe_corners(plane_track, ctime, corners);
+ BKE_tracking_homography_between_two_quads(parent->parent_corners_orig, corners, H);
- unit_m3(mask_from_clip_matrix);
+ unit_m3(mask_from_clip_matrix);
- BKE_movieclip_get_size_fl(clip, &user, frame_size);
- BKE_movieclip_get_aspect(clip, &aspx, &aspy);
+ BKE_movieclip_get_size_fl(clip, &user, frame_size);
+ BKE_movieclip_get_aspect(clip, &aspx, &aspy);
- frame_size[1] *= (aspy / aspx);
- if (frame_size[0] == frame_size[1]) {
- /* pass */
- }
- else if (frame_size[0] < frame_size[1]) {
- mask_from_clip_matrix[0][0] = frame_size[1] / frame_size[0];
- mask_from_clip_matrix[2][0] = -0.5f * (frame_size[1] / frame_size[0]) + 0.5f;
- }
- else { /* (frame_size[0] > frame_size[1]) */
- mask_from_clip_matrix[1][1] = frame_size[1] / frame_size[0];
- mask_from_clip_matrix[2][1] = -0.5f * (frame_size[1] / frame_size[0]) + 0.5f;
- }
+ frame_size[1] *= (aspy / aspx);
+ if (frame_size[0] == frame_size[1]) {
+ /* pass */
+ }
+ else if (frame_size[0] < frame_size[1]) {
+ mask_from_clip_matrix[0][0] = frame_size[1] / frame_size[0];
+ mask_from_clip_matrix[2][0] = -0.5f * (frame_size[1] / frame_size[0]) + 0.5f;
+ }
+ else { /* (frame_size[0] > frame_size[1]) */
+ mask_from_clip_matrix[1][1] = frame_size[1] / frame_size[0];
+ mask_from_clip_matrix[2][1] = -0.5f * (frame_size[1] / frame_size[0]) + 0.5f;
+ }
- invert_m3_m3(mask_to_clip_matrix, mask_from_clip_matrix);
- mul_m3_series(parent_matrix, mask_from_clip_matrix, H, mask_to_clip_matrix);
- }
- }
- }
- }
- }
+ invert_m3_m3(mask_to_clip_matrix, mask_from_clip_matrix);
+ mul_m3_series(parent_matrix, mask_from_clip_matrix, H, mask_to_clip_matrix);
+ }
+ }
+ }
+ }
+ }
}
-static void mask_calc_point_handle(MaskSplinePoint *point, MaskSplinePoint *point_prev, MaskSplinePoint *point_next)
+static void mask_calc_point_handle(MaskSplinePoint *point,
+ MaskSplinePoint *point_prev,
+ MaskSplinePoint *point_next)
{
- BezTriple *bezt = &point->bezt;
- BezTriple *bezt_prev = NULL, *bezt_next = NULL;
- //int handle_type = bezt->h1;
+ BezTriple *bezt = &point->bezt;
+ BezTriple *bezt_prev = NULL, *bezt_next = NULL;
+ //int handle_type = bezt->h1;
- if (point_prev)
- bezt_prev = &point_prev->bezt;
+ if (point_prev)
+ bezt_prev = &point_prev->bezt;
- if (point_next)
- bezt_next = &point_next->bezt;
+ if (point_next)
+ bezt_next = &point_next->bezt;
#if 1
- if (bezt_prev || bezt_next) {
- BKE_nurb_handle_calc(bezt, bezt_prev, bezt_next, 0, 0);
- }
+ if (bezt_prev || bezt_next) {
+ BKE_nurb_handle_calc(bezt, bezt_prev, bezt_next, 0, 0);
+ }
#else
- if (handle_type == HD_VECT) {
- BKE_nurb_handle_calc(bezt, bezt_prev, bezt_next, 0, 0);
- }
- else if (handle_type == HD_AUTO) {
- BKE_nurb_handle_calc(bezt, bezt_prev, bezt_next, 0, 0);
- }
- else if (handle_type == HD_ALIGN || handle_type == HD_ALIGN_DOUBLESIDE) {
- float v1[3], v2[3];
- float vec[3], h[3];
-
- sub_v3_v3v3(v1, bezt->vec[0], bezt->vec[1]);
- sub_v3_v3v3(v2, bezt->vec[2], bezt->vec[1]);
- add_v3_v3v3(vec, v1, v2);
-
- if (len_squared_v3(vec) > (1e-3f * 1e-3f)) {
- h[0] = vec[1];
- h[1] = -vec[0];
- h[2] = 0.0f;
- }
- else {
- copy_v3_v3(h, v1);
- }
-
- add_v3_v3v3(bezt->vec[0], bezt->vec[1], h);
- sub_v3_v3v3(bezt->vec[2], bezt->vec[1], h);
- }
+ if (handle_type == HD_VECT) {
+ BKE_nurb_handle_calc(bezt, bezt_prev, bezt_next, 0, 0);
+ }
+ else if (handle_type == HD_AUTO) {
+ BKE_nurb_handle_calc(bezt, bezt_prev, bezt_next, 0, 0);
+ }
+ else if (handle_type == HD_ALIGN || handle_type == HD_ALIGN_DOUBLESIDE) {
+ float v1[3], v2[3];
+ float vec[3], h[3];
+
+ sub_v3_v3v3(v1, bezt->vec[0], bezt->vec[1]);
+ sub_v3_v3v3(v2, bezt->vec[2], bezt->vec[1]);
+ add_v3_v3v3(vec, v1, v2);
+
+ if (len_squared_v3(vec) > (1e-3f * 1e-3f)) {
+ h[0] = vec[1];
+ h[1] = -vec[0];
+ h[2] = 0.0f;
+ }
+ else {
+ copy_v3_v3(h, v1);
+ }
+
+ add_v3_v3v3(bezt->vec[0], bezt->vec[1], h);
+ sub_v3_v3v3(bezt->vec[2], bezt->vec[1], h);
+ }
#endif
}
-void BKE_mask_get_handle_point_adjacent(MaskSpline *spline, MaskSplinePoint *point,
- MaskSplinePoint **r_point_prev, MaskSplinePoint **r_point_next)
+void BKE_mask_get_handle_point_adjacent(MaskSpline *spline,
+ MaskSplinePoint *point,
+ MaskSplinePoint **r_point_prev,
+ MaskSplinePoint **r_point_next)
{
- /* TODO, could avoid calling this at such low level */
- MaskSplinePoint *points_array = BKE_mask_spline_point_array_from_point(spline, point);
+ /* TODO, could avoid calling this at such low level */
+ MaskSplinePoint *points_array = BKE_mask_spline_point_array_from_point(spline, point);
- *r_point_prev = mask_spline_point_prev(spline, points_array, point);
- *r_point_next = mask_spline_point_next(spline, points_array, point);
+ *r_point_prev = mask_spline_point_prev(spline, points_array, point);
+ *r_point_next = mask_spline_point_next(spline, points_array, point);
}
/* calculates the tangent of a point by its previous and next
* (ignoring handles - as if its a poly line) */
void BKE_mask_calc_tangent_polyline(MaskSpline *spline, MaskSplinePoint *point, float t[2])
{
- float tvec_a[2], tvec_b[2];
+ float tvec_a[2], tvec_b[2];
- MaskSplinePoint *point_prev, *point_next;
+ MaskSplinePoint *point_prev, *point_next;
- BKE_mask_get_handle_point_adjacent(spline, point,
- &point_prev, &point_next);
+ BKE_mask_get_handle_point_adjacent(spline, point, &point_prev, &point_next);
- if (point_prev) {
- sub_v2_v2v2(tvec_a, point->bezt.vec[1], point_prev->bezt.vec[1]);
- normalize_v2(tvec_a);
- }
- else {
- zero_v2(tvec_a);
- }
+ if (point_prev) {
+ sub_v2_v2v2(tvec_a, point->bezt.vec[1], point_prev->bezt.vec[1]);
+ normalize_v2(tvec_a);
+ }
+ else {
+ zero_v2(tvec_a);
+ }
- if (point_next) {
- sub_v2_v2v2(tvec_b, point_next->bezt.vec[1], point->bezt.vec[1]);
- normalize_v2(tvec_b);
- }
- else {
- zero_v2(tvec_b);
- }
+ if (point_next) {
+ sub_v2_v2v2(tvec_b, point_next->bezt.vec[1], point->bezt.vec[1]);
+ normalize_v2(tvec_b);
+ }
+ else {
+ zero_v2(tvec_b);
+ }
- add_v2_v2v2(t, tvec_a, tvec_b);
- normalize_v2(t);
+ add_v2_v2v2(t, tvec_a, tvec_b);
+ normalize_v2(t);
}
void BKE_mask_calc_handle_point(MaskSpline *spline, MaskSplinePoint *point)
{
- MaskSplinePoint *point_prev, *point_next;
+ MaskSplinePoint *point_prev, *point_next;
- BKE_mask_get_handle_point_adjacent(spline, point,
- &point_prev, &point_next);
+ BKE_mask_get_handle_point_adjacent(spline, point, &point_prev, &point_next);
- mask_calc_point_handle(point, point_prev, point_next);
+ mask_calc_point_handle(point, point_prev, point_next);
}
-void BKE_mask_calc_handle_adjacent_interp(MaskSpline *spline, MaskSplinePoint *point, const float u)
+void BKE_mask_calc_handle_adjacent_interp(MaskSpline *spline,
+ MaskSplinePoint *point,
+ const float u)
{
- /* TODO! - make this interpolate between siblings - not always midpoint! */
- int length_tot = 0;
- float length_average = 0.0f;
- float weight_average = 0.0f;
-
+ /* TODO! - make this interpolate between siblings - not always midpoint! */
+ int length_tot = 0;
+ float length_average = 0.0f;
+ float weight_average = 0.0f;
- MaskSplinePoint *point_prev, *point_next;
+ MaskSplinePoint *point_prev, *point_next;
- BLI_assert(u >= 0.0f && u <= 1.0f);
+ BLI_assert(u >= 0.0f && u <= 1.0f);
- BKE_mask_get_handle_point_adjacent(spline, point,
- &point_prev, &point_next);
+ BKE_mask_get_handle_point_adjacent(spline, point, &point_prev, &point_next);
- if (point_prev && point_next) {
- length_average = ((len_v2v2(point_prev->bezt.vec[0], point_prev->bezt.vec[1]) * (1.0f - u)) +
- (len_v2v2(point_next->bezt.vec[2], point_next->bezt.vec[1]) * u));
+ if (point_prev && point_next) {
+ length_average = ((len_v2v2(point_prev->bezt.vec[0], point_prev->bezt.vec[1]) * (1.0f - u)) +
+ (len_v2v2(point_next->bezt.vec[2], point_next->bezt.vec[1]) * u));
- weight_average = (point_prev->bezt.weight * (1.0f - u) +
- point_next->bezt.weight * u);
- length_tot = 1;
- }
- else {
- if (point_prev) {
- length_average += len_v2v2(point_prev->bezt.vec[0], point_prev->bezt.vec[1]);
- weight_average += point_prev->bezt.weight;
- length_tot++;
- }
+ weight_average = (point_prev->bezt.weight * (1.0f - u) + point_next->bezt.weight * u);
+ length_tot = 1;
+ }
+ else {
+ if (point_prev) {
+ length_average += len_v2v2(point_prev->bezt.vec[0], point_prev->bezt.vec[1]);
+ weight_average += point_prev->bezt.weight;
+ length_tot++;
+ }
- if (point_next) {
- length_average += len_v2v2(point_next->bezt.vec[2], point_next->bezt.vec[1]);
- weight_average += point_next->bezt.weight;
- length_tot++;
- }
- }
+ if (point_next) {
+ length_average += len_v2v2(point_next->bezt.vec[2], point_next->bezt.vec[1]);
+ weight_average += point_next->bezt.weight;
+ length_tot++;
+ }
+ }
- if (length_tot) {
- length_average /= (float)length_tot;
- weight_average /= (float)length_tot;
+ if (length_tot) {
+ length_average /= (float)length_tot;
+ weight_average /= (float)length_tot;
- dist_ensure_v2_v2fl(point->bezt.vec[0], point->bezt.vec[1], length_average);
- dist_ensure_v2_v2fl(point->bezt.vec[2], point->bezt.vec[1], length_average);
- point->bezt.weight = weight_average;
- }
+ dist_ensure_v2_v2fl(point->bezt.vec[0], point->bezt.vec[1], length_average);
+ dist_ensure_v2_v2fl(point->bezt.vec[2], point->bezt.vec[1], length_average);
+ point->bezt.weight = weight_average;
+ }
}
-
/**
* \brief Resets auto handles even for non-auto bezier points
*
* Useful for giving sane defaults.
*/
-void BKE_mask_calc_handle_point_auto(MaskSpline *spline, MaskSplinePoint *point,
+void BKE_mask_calc_handle_point_auto(MaskSpline *spline,
+ MaskSplinePoint *point,
const bool do_recalc_length)
{
- MaskSplinePoint *point_prev, *point_next;
- const char h_back[2] = {point->bezt.h1, point->bezt.h2};
- const float length_average = (do_recalc_length) ? 0.0f /* dummy value */ :
- (len_v3v3(point->bezt.vec[0], point->bezt.vec[1]) +
- len_v3v3(point->bezt.vec[1], point->bezt.vec[2])) / 2.0f;
+ MaskSplinePoint *point_prev, *point_next;
+ const char h_back[2] = {point->bezt.h1, point->bezt.h2};
+ const float length_average = (do_recalc_length) ?
+ 0.0f /* dummy value */ :
+ (len_v3v3(point->bezt.vec[0], point->bezt.vec[1]) +
+ len_v3v3(point->bezt.vec[1], point->bezt.vec[2])) /
+ 2.0f;
- BKE_mask_get_handle_point_adjacent(spline, point,
- &point_prev, &point_next);
+ BKE_mask_get_handle_point_adjacent(spline, point, &point_prev, &point_next);
- point->bezt.h1 = HD_AUTO;
- point->bezt.h2 = HD_AUTO;
- mask_calc_point_handle(point, point_prev, point_next);
+ point->bezt.h1 = HD_AUTO;
+ point->bezt.h2 = HD_AUTO;
+ mask_calc_point_handle(point, point_prev, point_next);
- point->bezt.h1 = h_back[0];
- point->bezt.h2 = h_back[1];
+ point->bezt.h1 = h_back[0];
+ point->bezt.h2 = h_back[1];
- /* preserve length by applying it back */
- if (do_recalc_length == false) {
- dist_ensure_v2_v2fl(point->bezt.vec[0], point->bezt.vec[1], length_average);
- dist_ensure_v2_v2fl(point->bezt.vec[2], point->bezt.vec[1], length_average);
- }
+ /* preserve length by applying it back */
+ if (do_recalc_length == false) {
+ dist_ensure_v2_v2fl(point->bezt.vec[0], point->bezt.vec[1], length_average);
+ dist_ensure_v2_v2fl(point->bezt.vec[2], point->bezt.vec[1], length_average);
+ }
}
void BKE_mask_layer_calc_handles(MaskLayer *masklay)
{
- MaskSpline *spline;
- for (spline = masklay->splines.first; spline; spline = spline->next) {
- int i;
- for (i = 0; i < spline->tot_point; i++) {
- BKE_mask_calc_handle_point(spline, &spline->points[i]);
- }
- }
+ MaskSpline *spline;
+ for (spline = masklay->splines.first; spline; spline = spline->next) {
+ int i;
+ for (i = 0; i < spline->tot_point; i++) {
+ BKE_mask_calc_handle_point(spline, &spline->points[i]);
+ }
+ }
}
void BKE_mask_spline_ensure_deform(MaskSpline *spline)
{
- int allocated_points = (MEM_allocN_len(spline->points_deform) / sizeof(*spline->points_deform));
- // printf("SPLINE ALLOC %p %d\n", spline->points_deform, allocated_points);
+ int allocated_points = (MEM_allocN_len(spline->points_deform) / sizeof(*spline->points_deform));
+ // printf("SPLINE ALLOC %p %d\n", spline->points_deform, allocated_points);
- if (spline->points_deform == NULL || allocated_points != spline->tot_point) {
- // printf("alloc new deform spline\n");
+ if (spline->points_deform == NULL || allocated_points != spline->tot_point) {
+ // printf("alloc new deform spline\n");
- if (spline->points_deform) {
- int i;
+ if (spline->points_deform) {
+ int i;
- for (i = 0; i < allocated_points; i++) {
- MaskSplinePoint *point = &spline->points_deform[i];
- BKE_mask_point_free(point);
- }
+ for (i = 0; i < allocated_points; i++) {
+ MaskSplinePoint *point = &spline->points_deform[i];
+ BKE_mask_point_free(point);
+ }
- MEM_freeN(spline->points_deform);
- }
+ MEM_freeN(spline->points_deform);
+ }
- spline->points_deform = MEM_callocN(sizeof(*spline->points_deform) * spline->tot_point, __func__);
- }
- else {
- // printf("alloc spline done\n");
- }
+ spline->points_deform = MEM_callocN(sizeof(*spline->points_deform) * spline->tot_point,
+ __func__);
+ }
+ else {
+ // printf("alloc spline done\n");
+ }
}
void BKE_mask_layer_evaluate(MaskLayer *masklay, const float ctime, const bool do_newframe)
{
- /* Animation if available. */
- if (do_newframe) {
- BKE_mask_layer_evaluate_animation(masklay, ctime);
- }
- /* Update deform. */
- BKE_mask_layer_evaluate_deform(masklay, ctime);
+ /* Animation if available. */
+ if (do_newframe) {
+ BKE_mask_layer_evaluate_animation(masklay, ctime);
+ }
+ /* Update deform. */
+ BKE_mask_layer_evaluate_deform(masklay, ctime);
}
void BKE_mask_evaluate(Mask *mask, const float ctime, const bool do_newframe)
{
- MaskLayer *masklay;
+ MaskLayer *masklay;
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
- BKE_mask_layer_evaluate(masklay, ctime, do_newframe);
- }
+ for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
+ BKE_mask_layer_evaluate(masklay, ctime, do_newframe);
+ }
}
/* the purpose of this function is to ensure spline->points_deform is never out of date.
* for now re-evaluate all. eventually this might work differently */
void BKE_mask_update_display(Mask *mask, float ctime)
{
- BKE_mask_evaluate(mask, ctime, false);
+ BKE_mask_evaluate(mask, ctime, false);
}
void BKE_mask_evaluate_all_masks(Main *bmain, float ctime, const bool do_newframe)
{
- Mask *mask;
+ Mask *mask;
- for (mask = bmain->masks.first; mask; mask = mask->id.next) {
- BKE_mask_evaluate(mask, ctime, do_newframe);
- }
+ for (mask = bmain->masks.first; mask; mask = mask->id.next) {
+ BKE_mask_evaluate(mask, ctime, do_newframe);
+ }
}
void BKE_mask_parent_init(MaskParent *parent)
{
- parent->id_type = ID_MC;
+ parent->id_type = ID_MC;
}
-
/* *** own animation/shapekey implementation ***
* BKE_mask_layer_shape_XXX */
int BKE_mask_layer_shape_totvert(MaskLayer *masklay)
{
- int tot = 0;
- MaskSpline *spline;
+ int tot = 0;
+ MaskSpline *spline;
- for (spline = masklay->splines.first; spline; spline = spline->next) {
- tot += spline->tot_point;
- }
+ for (spline = masklay->splines.first; spline; spline = spline->next) {
+ tot += spline->tot_point;
+ }
- return tot;
+ return tot;
}
-static void mask_layer_shape_from_mask_point(BezTriple *bezt, float fp[MASK_OBJECT_SHAPE_ELEM_SIZE])
+static void mask_layer_shape_from_mask_point(BezTriple *bezt,
+ float fp[MASK_OBJECT_SHAPE_ELEM_SIZE])
{
- copy_v2_v2(&fp[0], bezt->vec[0]);
- copy_v2_v2(&fp[2], bezt->vec[1]);
- copy_v2_v2(&fp[4], bezt->vec[2]);
- fp[6] = bezt->weight;
- fp[7] = bezt->radius;
+ copy_v2_v2(&fp[0], bezt->vec[0]);
+ copy_v2_v2(&fp[2], bezt->vec[1]);
+ copy_v2_v2(&fp[4], bezt->vec[2]);
+ fp[6] = bezt->weight;
+ fp[7] = bezt->radius;
}
static void mask_layer_shape_to_mask_point(BezTriple *bezt, float fp[MASK_OBJECT_SHAPE_ELEM_SIZE])
{
- copy_v2_v2(bezt->vec[0], &fp[0]);
- copy_v2_v2(bezt->vec[1], &fp[2]);
- copy_v2_v2(bezt->vec[2], &fp[4]);
- bezt->weight = fp[6];
- bezt->radius = fp[7];
+ copy_v2_v2(bezt->vec[0], &fp[0]);
+ copy_v2_v2(bezt->vec[1], &fp[2]);
+ copy_v2_v2(bezt->vec[2], &fp[4]);
+ bezt->weight = fp[6];
+ bezt->radius = fp[7];
}
/* these functions match. copy is swapped */
void BKE_mask_layer_shape_from_mask(MaskLayer *masklay, MaskLayerShape *masklay_shape)
{
- int tot = BKE_mask_layer_shape_totvert(masklay);
-
- if (masklay_shape->tot_vert == tot) {
- float *fp = masklay_shape->data;
-
- MaskSpline *spline;
- for (spline = masklay->splines.first; spline; spline = spline->next) {
- int i;
- for (i = 0; i < spline->tot_point; i++) {
- mask_layer_shape_from_mask_point(&spline->points[i].bezt, fp);
- fp += MASK_OBJECT_SHAPE_ELEM_SIZE;
- }
- }
- }
- else {
- CLOG_ERROR(&LOG, "vert mismatch %d != %d (frame %d)",
- masklay_shape->tot_vert, tot, masklay_shape->frame);
- }
+ int tot = BKE_mask_layer_shape_totvert(masklay);
+
+ if (masklay_shape->tot_vert == tot) {
+ float *fp = masklay_shape->data;
+
+ MaskSpline *spline;
+ for (spline = masklay->splines.first; spline; spline = spline->next) {
+ int i;
+ for (i = 0; i < spline->tot_point; i++) {
+ mask_layer_shape_from_mask_point(&spline->points[i].bezt, fp);
+ fp += MASK_OBJECT_SHAPE_ELEM_SIZE;
+ }
+ }
+ }
+ else {
+ CLOG_ERROR(&LOG,
+ "vert mismatch %d != %d (frame %d)",
+ masklay_shape->tot_vert,
+ tot,
+ masklay_shape->frame);
+ }
}
void BKE_mask_layer_shape_to_mask(MaskLayer *masklay, MaskLayerShape *masklay_shape)
{
- int tot = BKE_mask_layer_shape_totvert(masklay);
+ int tot = BKE_mask_layer_shape_totvert(masklay);
- if (masklay_shape->tot_vert == tot) {
- float *fp = masklay_shape->data;
+ if (masklay_shape->tot_vert == tot) {
+ float *fp = masklay_shape->data;
- MaskSpline *spline;
- for (spline = masklay->splines.first; spline; spline = spline->next) {
- int i;
- for (i = 0; i < spline->tot_point; i++) {
- mask_layer_shape_to_mask_point(&spline->points[i].bezt, fp);
- fp += MASK_OBJECT_SHAPE_ELEM_SIZE;
- }
- }
- }
- else {
- CLOG_ERROR(&LOG, "vert mismatch %d != %d (frame %d)",
- masklay_shape->tot_vert, tot, masklay_shape->frame);
- }
+ MaskSpline *spline;
+ for (spline = masklay->splines.first; spline; spline = spline->next) {
+ int i;
+ for (i = 0; i < spline->tot_point; i++) {
+ mask_layer_shape_to_mask_point(&spline->points[i].bezt, fp);
+ fp += MASK_OBJECT_SHAPE_ELEM_SIZE;
+ }
+ }
+ }
+ else {
+ CLOG_ERROR(&LOG,
+ "vert mismatch %d != %d (frame %d)",
+ masklay_shape->tot_vert,
+ tot,
+ masklay_shape->frame);
+ }
}
-BLI_INLINE void interp_v2_v2v2_flfl(float target[2], const float a[2], const float b[2],
- const float t, const float s)
+BLI_INLINE void interp_v2_v2v2_flfl(
+ float target[2], const float a[2], const float b[2], const float t, const float s)
{
- target[0] = s * a[0] + t * b[0];
- target[1] = s * a[1] + t * b[1];
+ target[0] = s * a[0] + t * b[0];
+ target[1] = s * a[1] + t * b[1];
}
/* linear interpolation only */
@@ -1525,423 +1560,445 @@ void BKE_mask_layer_shape_to_mask_interp(MaskLayer *masklay,
MaskLayerShape *masklay_shape_b,
const float fac)
{
- int tot = BKE_mask_layer_shape_totvert(masklay);
- if (masklay_shape_a->tot_vert == tot && masklay_shape_b->tot_vert == tot) {
- const float *fp_a = masklay_shape_a->data;
- const float *fp_b = masklay_shape_b->data;
- const float ifac = 1.0f - fac;
-
- MaskSpline *spline;
- for (spline = masklay->splines.first; spline; spline = spline->next) {
- int i;
- for (i = 0; i < spline->tot_point; i++) {
- BezTriple *bezt = &spline->points[i].bezt;
- /* *** BKE_mask_layer_shape_from_mask - swapped *** */
- interp_v2_v2v2_flfl(bezt->vec[0], fp_a, fp_b, fac, ifac); fp_a += 2; fp_b += 2;
- interp_v2_v2v2_flfl(bezt->vec[1], fp_a, fp_b, fac, ifac); fp_a += 2; fp_b += 2;
- interp_v2_v2v2_flfl(bezt->vec[2], fp_a, fp_b, fac, ifac); fp_a += 2; fp_b += 2;
- bezt->weight = (fp_a[0] * ifac) + (fp_b[0] * fac);
- bezt->radius = (fp_a[1] * ifac) + (fp_b[1] * fac); fp_a += 2; fp_b += 2;
- }
- }
- }
- else {
- CLOG_ERROR(&LOG, "vert mismatch %d != %d != %d (frame %d - %d)",
- masklay_shape_a->tot_vert, masklay_shape_b->tot_vert, tot,
- masklay_shape_a->frame, masklay_shape_b->frame);
- }
+ int tot = BKE_mask_layer_shape_totvert(masklay);
+ if (masklay_shape_a->tot_vert == tot && masklay_shape_b->tot_vert == tot) {
+ const float *fp_a = masklay_shape_a->data;
+ const float *fp_b = masklay_shape_b->data;
+ const float ifac = 1.0f - fac;
+
+ MaskSpline *spline;
+ for (spline = masklay->splines.first; spline; spline = spline->next) {
+ int i;
+ for (i = 0; i < spline->tot_point; i++) {
+ BezTriple *bezt = &spline->points[i].bezt;
+ /* *** BKE_mask_layer_shape_from_mask - swapped *** */
+ interp_v2_v2v2_flfl(bezt->vec[0], fp_a, fp_b, fac, ifac);
+ fp_a += 2;
+ fp_b += 2;
+ interp_v2_v2v2_flfl(bezt->vec[1], fp_a, fp_b, fac, ifac);
+ fp_a += 2;
+ fp_b += 2;
+ interp_v2_v2v2_flfl(bezt->vec[2], fp_a, fp_b, fac, ifac);
+ fp_a += 2;
+ fp_b += 2;
+ bezt->weight = (fp_a[0] * ifac) + (fp_b[0] * fac);
+ bezt->radius = (fp_a[1] * ifac) + (fp_b[1] * fac);
+ fp_a += 2;
+ fp_b += 2;
+ }
+ }
+ }
+ else {
+ CLOG_ERROR(&LOG,
+ "vert mismatch %d != %d != %d (frame %d - %d)",
+ masklay_shape_a->tot_vert,
+ masklay_shape_b->tot_vert,
+ tot,
+ masklay_shape_a->frame,
+ masklay_shape_b->frame);
+ }
}
MaskLayerShape *BKE_mask_layer_shape_find_frame(MaskLayer *masklay, const int frame)
{
- MaskLayerShape *masklay_shape;
+ MaskLayerShape *masklay_shape;
- for (masklay_shape = masklay->splines_shapes.first;
- masklay_shape;
- masklay_shape = masklay_shape->next)
- {
- if (frame == masklay_shape->frame) {
- return masklay_shape;
- }
- else if (frame < masklay_shape->frame) {
- break;
- }
- }
+ for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
+ masklay_shape = masklay_shape->next) {
+ if (frame == masklay_shape->frame) {
+ return masklay_shape;
+ }
+ else if (frame < masklay_shape->frame) {
+ break;
+ }
+ }
- return NULL;
+ return NULL;
}
/* when returning 2 - the frame isnt found but before/after frames are */
-int BKE_mask_layer_shape_find_frame_range(MaskLayer *masklay, const float frame,
+int BKE_mask_layer_shape_find_frame_range(MaskLayer *masklay,
+ const float frame,
MaskLayerShape **r_masklay_shape_a,
MaskLayerShape **r_masklay_shape_b)
{
- MaskLayerShape *masklay_shape;
-
- for (masklay_shape = masklay->splines_shapes.first;
- masklay_shape;
- masklay_shape = masklay_shape->next)
- {
- if (frame == masklay_shape->frame) {
- *r_masklay_shape_a = masklay_shape;
- *r_masklay_shape_b = NULL;
- return 1;
- }
- else if (frame < masklay_shape->frame) {
- if (masklay_shape->prev) {
- *r_masklay_shape_a = masklay_shape->prev;
- *r_masklay_shape_b = masklay_shape;
- return 2;
- }
- else {
- *r_masklay_shape_a = masklay_shape;
- *r_masklay_shape_b = NULL;
- return 1;
- }
- }
- }
-
- if ((masklay_shape = masklay->splines_shapes.last)) {
- *r_masklay_shape_a = masklay_shape;
- *r_masklay_shape_b = NULL;
- return 1;
- }
- else {
- *r_masklay_shape_a = NULL;
- *r_masklay_shape_b = NULL;
-
- return 0;
- }
+ MaskLayerShape *masklay_shape;
+
+ for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
+ masklay_shape = masklay_shape->next) {
+ if (frame == masklay_shape->frame) {
+ *r_masklay_shape_a = masklay_shape;
+ *r_masklay_shape_b = NULL;
+ return 1;
+ }
+ else if (frame < masklay_shape->frame) {
+ if (masklay_shape->prev) {
+ *r_masklay_shape_a = masklay_shape->prev;
+ *r_masklay_shape_b = masklay_shape;
+ return 2;
+ }
+ else {
+ *r_masklay_shape_a = masklay_shape;
+ *r_masklay_shape_b = NULL;
+ return 1;
+ }
+ }
+ }
+
+ if ((masklay_shape = masklay->splines_shapes.last)) {
+ *r_masklay_shape_a = masklay_shape;
+ *r_masklay_shape_b = NULL;
+ return 1;
+ }
+ else {
+ *r_masklay_shape_a = NULL;
+ *r_masklay_shape_b = NULL;
+
+ return 0;
+ }
}
MaskLayerShape *BKE_mask_layer_shape_verify_frame(MaskLayer *masklay, const int frame)
{
- MaskLayerShape *masklay_shape;
+ MaskLayerShape *masklay_shape;
- masklay_shape = BKE_mask_layer_shape_find_frame(masklay, frame);
+ masklay_shape = BKE_mask_layer_shape_find_frame(masklay, frame);
- if (masklay_shape == NULL) {
- masklay_shape = BKE_mask_layer_shape_alloc(masklay, frame);
- BLI_addtail(&masklay->splines_shapes, masklay_shape);
- BKE_mask_layer_shape_sort(masklay);
- }
+ if (masklay_shape == NULL) {
+ masklay_shape = BKE_mask_layer_shape_alloc(masklay, frame);
+ BLI_addtail(&masklay->splines_shapes, masklay_shape);
+ BKE_mask_layer_shape_sort(masklay);
+ }
- return masklay_shape;
+ return masklay_shape;
}
MaskLayerShape *BKE_mask_layer_shape_duplicate(MaskLayerShape *masklay_shape)
{
- MaskLayerShape *masklay_shape_copy;
+ MaskLayerShape *masklay_shape_copy;
- masklay_shape_copy = MEM_dupallocN(masklay_shape);
+ masklay_shape_copy = MEM_dupallocN(masklay_shape);
- if (LIKELY(masklay_shape_copy->data)) {
- masklay_shape_copy->data = MEM_dupallocN(masklay_shape_copy->data);
- }
+ if (LIKELY(masklay_shape_copy->data)) {
+ masklay_shape_copy->data = MEM_dupallocN(masklay_shape_copy->data);
+ }
- return masklay_shape_copy;
+ return masklay_shape_copy;
}
void BKE_mask_layer_shape_unlink(MaskLayer *masklay, MaskLayerShape *masklay_shape)
{
- BLI_remlink(&masklay->splines_shapes, masklay_shape);
+ BLI_remlink(&masklay->splines_shapes, masklay_shape);
- BKE_mask_layer_shape_free(masklay_shape);
+ BKE_mask_layer_shape_free(masklay_shape);
}
-static int mask_layer_shape_sort_cb(const void *masklay_shape_a_ptr, const void *masklay_shape_b_ptr)
+static int mask_layer_shape_sort_cb(const void *masklay_shape_a_ptr,
+ const void *masklay_shape_b_ptr)
{
- const MaskLayerShape *masklay_shape_a = masklay_shape_a_ptr;
- const MaskLayerShape *masklay_shape_b = masklay_shape_b_ptr;
+ const MaskLayerShape *masklay_shape_a = masklay_shape_a_ptr;
+ const MaskLayerShape *masklay_shape_b = masklay_shape_b_ptr;
- if (masklay_shape_a->frame < masklay_shape_b->frame) return -1;
- else if (masklay_shape_a->frame > masklay_shape_b->frame) return 1;
- else return 0;
+ if (masklay_shape_a->frame < masklay_shape_b->frame)
+ return -1;
+ else if (masklay_shape_a->frame > masklay_shape_b->frame)
+ return 1;
+ else
+ return 0;
}
void BKE_mask_layer_shape_sort(MaskLayer *masklay)
{
- BLI_listbase_sort(&masklay->splines_shapes, mask_layer_shape_sort_cb);
+ BLI_listbase_sort(&masklay->splines_shapes, mask_layer_shape_sort_cb);
}
-bool BKE_mask_layer_shape_spline_from_index(MaskLayer *masklay, int index,
- MaskSpline **r_masklay_shape, int *r_index)
+bool BKE_mask_layer_shape_spline_from_index(MaskLayer *masklay,
+ int index,
+ MaskSpline **r_masklay_shape,
+ int *r_index)
{
- MaskSpline *spline;
+ MaskSpline *spline;
- for (spline = masklay->splines.first; spline; spline = spline->next) {
- if (index < spline->tot_point) {
- *r_masklay_shape = spline;
- *r_index = index;
- return true;
- }
- index -= spline->tot_point;
- }
+ for (spline = masklay->splines.first; spline; spline = spline->next) {
+ if (index < spline->tot_point) {
+ *r_masklay_shape = spline;
+ *r_index = index;
+ return true;
+ }
+ index -= spline->tot_point;
+ }
- return false;
+ return false;
}
int BKE_mask_layer_shape_spline_to_index(MaskLayer *masklay, MaskSpline *spline)
{
- MaskSpline *spline_iter;
- int i_abs = 0;
- for (spline_iter = masklay->splines.first;
- spline_iter && spline_iter != spline;
- i_abs += spline_iter->tot_point, spline_iter = spline_iter->next)
- {
- /* pass */
- }
+ MaskSpline *spline_iter;
+ int i_abs = 0;
+ for (spline_iter = masklay->splines.first; spline_iter && spline_iter != spline;
+ i_abs += spline_iter->tot_point, spline_iter = spline_iter->next) {
+ /* pass */
+ }
- return i_abs;
+ return i_abs;
}
/* basic 2D interpolation functions, could make more comprehensive later */
-static void interp_weights_uv_v2_calc(float r_uv[2], const float pt[2], const float pt_a[2], const float pt_b[2])
+static void interp_weights_uv_v2_calc(float r_uv[2],
+ const float pt[2],
+ const float pt_a[2],
+ const float pt_b[2])
{
- float pt_on_line[2];
- r_uv[0] = closest_to_line_v2(pt_on_line, pt, pt_a, pt_b);
- r_uv[1] = (len_v2v2(pt_on_line, pt) / len_v2v2(pt_a, pt_b)) *
- ((line_point_side_v2(pt_a, pt_b, pt) < 0.0f) ? -1.0f : 1.0f); /* this line only sets the sign */
+ float pt_on_line[2];
+ r_uv[0] = closest_to_line_v2(pt_on_line, pt, pt_a, pt_b);
+ r_uv[1] = (len_v2v2(pt_on_line, pt) / len_v2v2(pt_a, pt_b)) *
+ ((line_point_side_v2(pt_a, pt_b, pt) < 0.0f) ?
+ -1.0f :
+ 1.0f); /* this line only sets the sign */
}
-
-static void interp_weights_uv_v2_apply(const float uv[2], float r_pt[2], const float pt_a[2], const float pt_b[2])
+static void interp_weights_uv_v2_apply(const float uv[2],
+ float r_pt[2],
+ const float pt_a[2],
+ const float pt_b[2])
{
- const float dvec[2] = {pt_b[0] - pt_a[0],
- pt_b[1] - pt_a[1]};
+ const float dvec[2] = {pt_b[0] - pt_a[0], pt_b[1] - pt_a[1]};
- /* u */
- madd_v2_v2v2fl(r_pt, pt_a, dvec, uv[0]);
+ /* u */
+ madd_v2_v2v2fl(r_pt, pt_a, dvec, uv[0]);
- /* v */
- r_pt[0] += -dvec[1] * uv[1];
- r_pt[1] += dvec[0] * uv[1];
+ /* v */
+ r_pt[0] += -dvec[1] * uv[1];
+ r_pt[1] += dvec[0] * uv[1];
}
/* when a new points added - resize all shapekey array */
-void BKE_mask_layer_shape_changed_add(MaskLayer *masklay, int index,
- bool do_init, bool do_init_interpolate)
-{
- MaskLayerShape *masklay_shape;
-
- /* spline index from masklay */
- MaskSpline *spline;
- int spline_point_index;
-
- if (BKE_mask_layer_shape_spline_from_index(masklay, index,
- &spline, &spline_point_index))
- {
- /* sanity check */
- /* the point has already been removed in this array so subtract one when comparing with the shapes */
- int tot = BKE_mask_layer_shape_totvert(masklay) - 1;
-
- /* for interpolation */
- /* TODO - assumes closed curve for now */
- float uv[3][2]; /* 3x 2D handles */
- const int pi_curr = spline_point_index;
- const int pi_prev = ((spline_point_index - 1) + spline->tot_point) % spline->tot_point;
- const int pi_next = (spline_point_index + 1) % spline->tot_point;
-
- const int index_offset = index - spline_point_index;
- /* const int pi_curr_abs = index; */
- const int pi_prev_abs = pi_prev + index_offset;
- const int pi_next_abs = pi_next + index_offset;
-
- int i;
- if (do_init_interpolate) {
- for (i = 0; i < 3; i++) {
- interp_weights_uv_v2_calc(uv[i],
- spline->points[pi_curr].bezt.vec[i],
- spline->points[pi_prev].bezt.vec[i],
- spline->points[pi_next].bezt.vec[i]);
- }
- }
-
- for (masklay_shape = masklay->splines_shapes.first;
- masklay_shape;
- masklay_shape = masklay_shape->next)
- {
- if (tot == masklay_shape->tot_vert) {
- float *data_resized;
-
- masklay_shape->tot_vert++;
- data_resized = MEM_mallocN(masklay_shape->tot_vert * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE, __func__);
- if (index > 0) {
- memcpy(data_resized,
- masklay_shape->data,
- index * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE);
- }
-
- if (index != masklay_shape->tot_vert - 1) {
- memcpy(&data_resized[(index + 1) * MASK_OBJECT_SHAPE_ELEM_SIZE],
- masklay_shape->data + (index * MASK_OBJECT_SHAPE_ELEM_SIZE),
- (masklay_shape->tot_vert - (index + 1)) * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE);
- }
-
- if (do_init) {
- float *fp = &data_resized[index * MASK_OBJECT_SHAPE_ELEM_SIZE];
-
- mask_layer_shape_from_mask_point(&spline->points[spline_point_index].bezt, fp);
-
- if (do_init_interpolate && spline->tot_point > 2) {
- for (i = 0; i < 3; i++) {
- interp_weights_uv_v2_apply(uv[i],
- &fp[i * 2],
- &data_resized[(pi_prev_abs * MASK_OBJECT_SHAPE_ELEM_SIZE) + (i * 2)],
- &data_resized[(pi_next_abs * MASK_OBJECT_SHAPE_ELEM_SIZE) + (i * 2)]);
- }
- }
- }
- else {
- memset(&data_resized[index * MASK_OBJECT_SHAPE_ELEM_SIZE],
- 0,
- sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE);
- }
-
- MEM_freeN(masklay_shape->data);
- masklay_shape->data = data_resized;
- }
- else {
- CLOG_ERROR(&LOG, "vert mismatch %d != %d (frame %d)",
- masklay_shape->tot_vert, tot, masklay_shape->frame);
- }
- }
- }
+void BKE_mask_layer_shape_changed_add(MaskLayer *masklay,
+ int index,
+ bool do_init,
+ bool do_init_interpolate)
+{
+ MaskLayerShape *masklay_shape;
+
+ /* spline index from masklay */
+ MaskSpline *spline;
+ int spline_point_index;
+
+ if (BKE_mask_layer_shape_spline_from_index(masklay, index, &spline, &spline_point_index)) {
+ /* sanity check */
+ /* the point has already been removed in this array so subtract one when comparing with the shapes */
+ int tot = BKE_mask_layer_shape_totvert(masklay) - 1;
+
+ /* for interpolation */
+ /* TODO - assumes closed curve for now */
+ float uv[3][2]; /* 3x 2D handles */
+ const int pi_curr = spline_point_index;
+ const int pi_prev = ((spline_point_index - 1) + spline->tot_point) % spline->tot_point;
+ const int pi_next = (spline_point_index + 1) % spline->tot_point;
+
+ const int index_offset = index - spline_point_index;
+ /* const int pi_curr_abs = index; */
+ const int pi_prev_abs = pi_prev + index_offset;
+ const int pi_next_abs = pi_next + index_offset;
+
+ int i;
+ if (do_init_interpolate) {
+ for (i = 0; i < 3; i++) {
+ interp_weights_uv_v2_calc(uv[i],
+ spline->points[pi_curr].bezt.vec[i],
+ spline->points[pi_prev].bezt.vec[i],
+ spline->points[pi_next].bezt.vec[i]);
+ }
+ }
+
+ for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
+ masklay_shape = masklay_shape->next) {
+ if (tot == masklay_shape->tot_vert) {
+ float *data_resized;
+
+ masklay_shape->tot_vert++;
+ data_resized = MEM_mallocN(
+ masklay_shape->tot_vert * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE, __func__);
+ if (index > 0) {
+ memcpy(data_resized,
+ masklay_shape->data,
+ index * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE);
+ }
+
+ if (index != masklay_shape->tot_vert - 1) {
+ memcpy(&data_resized[(index + 1) * MASK_OBJECT_SHAPE_ELEM_SIZE],
+ masklay_shape->data + (index * MASK_OBJECT_SHAPE_ELEM_SIZE),
+ (masklay_shape->tot_vert - (index + 1)) * sizeof(float) *
+ MASK_OBJECT_SHAPE_ELEM_SIZE);
+ }
+
+ if (do_init) {
+ float *fp = &data_resized[index * MASK_OBJECT_SHAPE_ELEM_SIZE];
+
+ mask_layer_shape_from_mask_point(&spline->points[spline_point_index].bezt, fp);
+
+ if (do_init_interpolate && spline->tot_point > 2) {
+ for (i = 0; i < 3; i++) {
+ interp_weights_uv_v2_apply(
+ uv[i],
+ &fp[i * 2],
+ &data_resized[(pi_prev_abs * MASK_OBJECT_SHAPE_ELEM_SIZE) + (i * 2)],
+ &data_resized[(pi_next_abs * MASK_OBJECT_SHAPE_ELEM_SIZE) + (i * 2)]);
+ }
+ }
+ }
+ else {
+ memset(&data_resized[index * MASK_OBJECT_SHAPE_ELEM_SIZE],
+ 0,
+ sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE);
+ }
+
+ MEM_freeN(masklay_shape->data);
+ masklay_shape->data = data_resized;
+ }
+ else {
+ CLOG_ERROR(&LOG,
+ "vert mismatch %d != %d (frame %d)",
+ masklay_shape->tot_vert,
+ tot,
+ masklay_shape->frame);
+ }
+ }
+ }
}
-
/* move array to account for removed point */
void BKE_mask_layer_shape_changed_remove(MaskLayer *masklay, int index, int count)
{
- MaskLayerShape *masklay_shape;
-
- /* the point has already been removed in this array so add one when comparing with the shapes */
- int tot = BKE_mask_layer_shape_totvert(masklay);
-
- for (masklay_shape = masklay->splines_shapes.first;
- masklay_shape;
- masklay_shape = masklay_shape->next)
- {
- if (tot == masklay_shape->tot_vert - count) {
- float *data_resized;
-
- masklay_shape->tot_vert -= count;
- data_resized = MEM_mallocN(masklay_shape->tot_vert * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE, __func__);
- if (index > 0) {
- memcpy(data_resized,
- masklay_shape->data,
- index * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE);
- }
-
- if (index != masklay_shape->tot_vert) {
- memcpy(&data_resized[index * MASK_OBJECT_SHAPE_ELEM_SIZE],
- masklay_shape->data + ((index + count) * MASK_OBJECT_SHAPE_ELEM_SIZE),
- (masklay_shape->tot_vert - index) * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE);
- }
-
- MEM_freeN(masklay_shape->data);
- masklay_shape->data = data_resized;
- }
- else {
- CLOG_ERROR(&LOG, "vert mismatch %d != %d (frame %d)",
- masklay_shape->tot_vert - count, tot, masklay_shape->frame);
- }
- }
+ MaskLayerShape *masklay_shape;
+
+ /* the point has already been removed in this array so add one when comparing with the shapes */
+ int tot = BKE_mask_layer_shape_totvert(masklay);
+
+ for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
+ masklay_shape = masklay_shape->next) {
+ if (tot == masklay_shape->tot_vert - count) {
+ float *data_resized;
+
+ masklay_shape->tot_vert -= count;
+ data_resized = MEM_mallocN(
+ masklay_shape->tot_vert * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE, __func__);
+ if (index > 0) {
+ memcpy(data_resized,
+ masklay_shape->data,
+ index * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE);
+ }
+
+ if (index != masklay_shape->tot_vert) {
+ memcpy(&data_resized[index * MASK_OBJECT_SHAPE_ELEM_SIZE],
+ masklay_shape->data + ((index + count) * MASK_OBJECT_SHAPE_ELEM_SIZE),
+ (masklay_shape->tot_vert - index) * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE);
+ }
+
+ MEM_freeN(masklay_shape->data);
+ masklay_shape->data = data_resized;
+ }
+ else {
+ CLOG_ERROR(&LOG,
+ "vert mismatch %d != %d (frame %d)",
+ masklay_shape->tot_vert - count,
+ tot,
+ masklay_shape->frame);
+ }
+ }
}
int BKE_mask_get_duration(Mask *mask)
{
- return max_ii(1, mask->efra - mask->sfra);
+ return max_ii(1, mask->efra - mask->sfra);
}
/*********************** clipboard *************************/
static void mask_clipboard_free_ex(bool final_free)
{
- BKE_mask_spline_free_list(&mask_clipboard.splines);
- BLI_listbase_clear(&mask_clipboard.splines);
- if (mask_clipboard.id_hash) {
- if (final_free) {
- BLI_ghash_free(mask_clipboard.id_hash, NULL, MEM_freeN);
- }
- else {
- BLI_ghash_clear(mask_clipboard.id_hash, NULL, MEM_freeN);
- }
- }
+ BKE_mask_spline_free_list(&mask_clipboard.splines);
+ BLI_listbase_clear(&mask_clipboard.splines);
+ if (mask_clipboard.id_hash) {
+ if (final_free) {
+ BLI_ghash_free(mask_clipboard.id_hash, NULL, MEM_freeN);
+ }
+ else {
+ BLI_ghash_clear(mask_clipboard.id_hash, NULL, MEM_freeN);
+ }
+ }
}
/* Free the clipboard. */
void BKE_mask_clipboard_free(void)
{
- mask_clipboard_free_ex(true);
+ mask_clipboard_free_ex(true);
}
/* Copy selected visible splines from the given layer to clipboard. */
void BKE_mask_clipboard_copy_from_layer(MaskLayer *mask_layer)
{
- MaskSpline *spline;
-
- /* Nothing to do if selection if disabled for the given layer. */
- if (mask_layer->restrictflag & MASK_RESTRICT_SELECT) {
- return;
- }
-
- mask_clipboard_free_ex(false);
- if (mask_clipboard.id_hash == NULL) {
- mask_clipboard.id_hash = BLI_ghash_ptr_new("mask clipboard ID hash");
- }
-
- for (spline = mask_layer->splines.first; spline; spline = spline->next) {
- if (spline->flag & SELECT) {
- MaskSpline *spline_new = BKE_mask_spline_copy(spline);
- int i;
- for (i = 0; i < spline_new->tot_point; i++) {
- MaskSplinePoint *point = &spline_new->points[i];
- if (point->parent.id) {
- if (!BLI_ghash_lookup(mask_clipboard.id_hash, point->parent.id)) {
- int len = strlen(point->parent.id->name);
- char *name_copy = MEM_mallocN(len + 1, "mask clipboard ID name");
- strcpy(name_copy, point->parent.id->name);
- BLI_ghash_insert(mask_clipboard.id_hash,
- point->parent.id,
- name_copy);
- }
- }
- }
-
- BLI_addtail(&mask_clipboard.splines, spline_new);
- }
- }
+ MaskSpline *spline;
+
+ /* Nothing to do if selection if disabled for the given layer. */
+ if (mask_layer->restrictflag & MASK_RESTRICT_SELECT) {
+ return;
+ }
+
+ mask_clipboard_free_ex(false);
+ if (mask_clipboard.id_hash == NULL) {
+ mask_clipboard.id_hash = BLI_ghash_ptr_new("mask clipboard ID hash");
+ }
+
+ for (spline = mask_layer->splines.first; spline; spline = spline->next) {
+ if (spline->flag & SELECT) {
+ MaskSpline *spline_new = BKE_mask_spline_copy(spline);
+ int i;
+ for (i = 0; i < spline_new->tot_point; i++) {
+ MaskSplinePoint *point = &spline_new->points[i];
+ if (point->parent.id) {
+ if (!BLI_ghash_lookup(mask_clipboard.id_hash, point->parent.id)) {
+ int len = strlen(point->parent.id->name);
+ char *name_copy = MEM_mallocN(len + 1, "mask clipboard ID name");
+ strcpy(name_copy, point->parent.id->name);
+ BLI_ghash_insert(mask_clipboard.id_hash, point->parent.id, name_copy);
+ }
+ }
+ }
+
+ BLI_addtail(&mask_clipboard.splines, spline_new);
+ }
+ }
}
/* Check clipboard is empty. */
bool BKE_mask_clipboard_is_empty(void)
{
- return BLI_listbase_is_empty(&mask_clipboard.splines);
+ return BLI_listbase_is_empty(&mask_clipboard.splines);
}
/* Paste the contents of clipboard to given mask layer */
void BKE_mask_clipboard_paste_to_layer(Main *bmain, MaskLayer *mask_layer)
{
- MaskSpline *spline;
+ MaskSpline *spline;
- for (spline = mask_clipboard.splines.first; spline; spline = spline->next) {
- MaskSpline *spline_new = BKE_mask_spline_copy(spline);
- int i;
+ for (spline = mask_clipboard.splines.first; spline; spline = spline->next) {
+ MaskSpline *spline_new = BKE_mask_spline_copy(spline);
+ int i;
- for (i = 0; i < spline_new->tot_point; i++) {
- MaskSplinePoint *point = &spline_new->points[i];
- if (point->parent.id) {
- const char *id_name = BLI_ghash_lookup(mask_clipboard.id_hash, point->parent.id);
- ListBase *listbase;
+ for (i = 0; i < spline_new->tot_point; i++) {
+ MaskSplinePoint *point = &spline_new->points[i];
+ if (point->parent.id) {
+ const char *id_name = BLI_ghash_lookup(mask_clipboard.id_hash, point->parent.id);
+ ListBase *listbase;
- BLI_assert(id_name != NULL);
+ BLI_assert(id_name != NULL);
- listbase = which_libbase(bmain, GS(id_name));
- point->parent.id = BLI_findstring(listbase, id_name + 2, offsetof(ID, name) + 2);
- }
- }
+ listbase = which_libbase(bmain, GS(id_name));
+ point->parent.id = BLI_findstring(listbase, id_name + 2, offsetof(ID, name) + 2);
+ }
+ }
- BLI_addtail(&mask_layer->splines, spline_new);
- }
+ BLI_addtail(&mask_layer->splines, spline_new);
+ }
}
diff --git a/source/blender/blenkernel/intern/mask_evaluate.c b/source/blender/blenkernel/intern/mask_evaluate.c
index 4237943717e..2b84c1f32c1 100644
--- a/source/blender/blenkernel/intern/mask_evaluate.c
+++ b/source/blender/blenkernel/intern/mask_evaluate.c
@@ -42,874 +42,903 @@
unsigned int BKE_mask_spline_resolution(MaskSpline *spline, int width, int height)
{
- float max_segment = 0.01f;
- unsigned int i, resol = 1;
+ float max_segment = 0.01f;
+ unsigned int i, resol = 1;
- if (width != 0 && height != 0) {
- max_segment = 1.0f / (float)max_ii(width, height);
- }
+ if (width != 0 && height != 0) {
+ max_segment = 1.0f / (float)max_ii(width, height);
+ }
- for (i = 0; i < spline->tot_point; i++) {
- MaskSplinePoint *point = &spline->points[i];
- BezTriple *bezt_curr, *bezt_next;
- float a, b, c, len;
- unsigned int cur_resol;
+ for (i = 0; i < spline->tot_point; i++) {
+ MaskSplinePoint *point = &spline->points[i];
+ BezTriple *bezt_curr, *bezt_next;
+ float a, b, c, len;
+ unsigned int cur_resol;
- bezt_curr = &point->bezt;
- bezt_next = BKE_mask_spline_point_next_bezt(spline, spline->points, point);
+ bezt_curr = &point->bezt;
+ bezt_next = BKE_mask_spline_point_next_bezt(spline, spline->points, point);
- if (bezt_next == NULL) {
- break;
- }
+ if (bezt_next == NULL) {
+ break;
+ }
- a = len_v3v3(bezt_curr->vec[1], bezt_curr->vec[2]);
- b = len_v3v3(bezt_curr->vec[2], bezt_next->vec[0]);
- c = len_v3v3(bezt_next->vec[0], bezt_next->vec[1]);
+ a = len_v3v3(bezt_curr->vec[1], bezt_curr->vec[2]);
+ b = len_v3v3(bezt_curr->vec[2], bezt_next->vec[0]);
+ c = len_v3v3(bezt_next->vec[0], bezt_next->vec[1]);
- len = a + b + c;
- cur_resol = len / max_segment;
+ len = a + b + c;
+ cur_resol = len / max_segment;
- resol = MAX2(resol, cur_resol);
+ resol = MAX2(resol, cur_resol);
- if (resol >= MASK_RESOL_MAX) {
- break;
- }
- }
+ if (resol >= MASK_RESOL_MAX) {
+ break;
+ }
+ }
- return CLAMPIS(resol, 1, MASK_RESOL_MAX);
+ return CLAMPIS(resol, 1, MASK_RESOL_MAX);
}
unsigned int BKE_mask_spline_feather_resolution(MaskSpline *spline, int width, int height)
{
- const float max_segment = 0.005;
- unsigned int resol = BKE_mask_spline_resolution(spline, width, height);
- float max_jump = 0.0f;
- int i;
+ const float max_segment = 0.005;
+ unsigned int resol = BKE_mask_spline_resolution(spline, width, height);
+ float max_jump = 0.0f;
+ int i;
- /* avoid checking the featrher if we already hit the maximum value */
- if (resol >= MASK_RESOL_MAX) {
- return MASK_RESOL_MAX;
- }
+ /* avoid checking the featrher if we already hit the maximum value */
+ if (resol >= MASK_RESOL_MAX) {
+ return MASK_RESOL_MAX;
+ }
- for (i = 0; i < spline->tot_point; i++) {
- MaskSplinePoint *point = &spline->points[i];
- float prev_u, prev_w;
- int j;
+ for (i = 0; i < spline->tot_point; i++) {
+ MaskSplinePoint *point = &spline->points[i];
+ float prev_u, prev_w;
+ int j;
- prev_u = 0.0f;
- prev_w = point->bezt.weight;
+ prev_u = 0.0f;
+ prev_w = point->bezt.weight;
- for (j = 0; j < point->tot_uw; j++) {
- const float w_diff = (point->uw[j].w - prev_w);
- const float u_diff = (point->uw[j].u - prev_u);
+ for (j = 0; j < point->tot_uw; j++) {
+ const float w_diff = (point->uw[j].w - prev_w);
+ const float u_diff = (point->uw[j].u - prev_u);
- /* avoid divide by zero and very high values,
- * though these get clamped eventually */
- if (u_diff > FLT_EPSILON) {
- float jump = fabsf(w_diff / u_diff);
+ /* avoid divide by zero and very high values,
+ * though these get clamped eventually */
+ if (u_diff > FLT_EPSILON) {
+ float jump = fabsf(w_diff / u_diff);
- max_jump = max_ff(max_jump, jump);
- }
+ max_jump = max_ff(max_jump, jump);
+ }
- prev_u = point->uw[j].u;
- prev_w = point->uw[j].w;
- }
- }
+ prev_u = point->uw[j].u;
+ prev_w = point->uw[j].w;
+ }
+ }
- resol += max_jump / max_segment;
+ resol += max_jump / max_segment;
- return CLAMPIS(resol, 1, MASK_RESOL_MAX);
+ return CLAMPIS(resol, 1, MASK_RESOL_MAX);
}
int BKE_mask_spline_differentiate_calc_total(const MaskSpline *spline, const unsigned int resol)
{
- if (spline->flag & MASK_SPLINE_CYCLIC) {
- return spline->tot_point * resol;
- }
- else {
- return ((spline->tot_point - 1) * resol) + 1;
- }
+ if (spline->flag & MASK_SPLINE_CYCLIC) {
+ return spline->tot_point * resol;
+ }
+ else {
+ return ((spline->tot_point - 1) * resol) + 1;
+ }
}
float (*BKE_mask_spline_differentiate_with_resolution(MaskSpline *spline,
unsigned int *tot_diff_point,
- const unsigned int resol
- ))[2]
+ const unsigned int resol))[2]
{
- MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
-
- MaskSplinePoint *point_curr, *point_prev;
- float (*diff_points)[2], (*fp)[2];
- const int tot = BKE_mask_spline_differentiate_calc_total(spline, resol);
- int a;
-
- if (spline->tot_point <= 1) {
- /* nothing to differentiate */
- *tot_diff_point = 0;
- return NULL;
- }
-
- /* len+1 because of 'forward_diff_bezier' function */
- *tot_diff_point = tot;
- diff_points = fp = MEM_mallocN((tot + 1) * sizeof(*diff_points), "mask spline vets");
-
- a = spline->tot_point - 1;
- if (spline->flag & MASK_SPLINE_CYCLIC)
- a++;
-
- point_prev = points_array;
- point_curr = point_prev + 1;
-
- while (a--) {
- BezTriple *bezt_prev;
- BezTriple *bezt_curr;
- int j;
-
- if (a == 0 && (spline->flag & MASK_SPLINE_CYCLIC))
- point_curr = points_array;
-
- bezt_prev = &point_prev->bezt;
- bezt_curr = &point_curr->bezt;
-
- for (j = 0; j < 2; j++) {
- BKE_curve_forward_diff_bezier(bezt_prev->vec[1][j], bezt_prev->vec[2][j],
- bezt_curr->vec[0][j], bezt_curr->vec[1][j],
- &(*fp)[j], resol, 2 * sizeof(float));
- }
-
- fp += resol;
-
- if (a == 0 && (spline->flag & MASK_SPLINE_CYCLIC) == 0) {
- copy_v2_v2(*fp, bezt_curr->vec[1]);
- }
-
- point_prev = point_curr;
- point_curr++;
- }
-
- return diff_points;
+ MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
+
+ MaskSplinePoint *point_curr, *point_prev;
+ float(*diff_points)[2], (*fp)[2];
+ const int tot = BKE_mask_spline_differentiate_calc_total(spline, resol);
+ int a;
+
+ if (spline->tot_point <= 1) {
+ /* nothing to differentiate */
+ *tot_diff_point = 0;
+ return NULL;
+ }
+
+ /* len+1 because of 'forward_diff_bezier' function */
+ *tot_diff_point = tot;
+ diff_points = fp = MEM_mallocN((tot + 1) * sizeof(*diff_points), "mask spline vets");
+
+ a = spline->tot_point - 1;
+ if (spline->flag & MASK_SPLINE_CYCLIC)
+ a++;
+
+ point_prev = points_array;
+ point_curr = point_prev + 1;
+
+ while (a--) {
+ BezTriple *bezt_prev;
+ BezTriple *bezt_curr;
+ int j;
+
+ if (a == 0 && (spline->flag & MASK_SPLINE_CYCLIC))
+ point_curr = points_array;
+
+ bezt_prev = &point_prev->bezt;
+ bezt_curr = &point_curr->bezt;
+
+ for (j = 0; j < 2; j++) {
+ BKE_curve_forward_diff_bezier(bezt_prev->vec[1][j],
+ bezt_prev->vec[2][j],
+ bezt_curr->vec[0][j],
+ bezt_curr->vec[1][j],
+ &(*fp)[j],
+ resol,
+ 2 * sizeof(float));
+ }
+
+ fp += resol;
+
+ if (a == 0 && (spline->flag & MASK_SPLINE_CYCLIC) == 0) {
+ copy_v2_v2(*fp, bezt_curr->vec[1]);
+ }
+
+ point_prev = point_curr;
+ point_curr++;
+ }
+
+ return diff_points;
}
-float (*BKE_mask_spline_differentiate(MaskSpline *spline, int width, int height,
- unsigned int *tot_diff_point
- ))[2]
+float (*BKE_mask_spline_differentiate(
+ MaskSpline *spline, int width, int height, unsigned int *tot_diff_point))[2]
{
- int unsigned resol = BKE_mask_spline_resolution(spline, width, height);
+ int unsigned resol = BKE_mask_spline_resolution(spline, width, height);
- return BKE_mask_spline_differentiate_with_resolution(spline, tot_diff_point, resol);
+ return BKE_mask_spline_differentiate_with_resolution(spline, tot_diff_point, resol);
}
/* ** feather points self-intersection collapse routine ** */
typedef struct FeatherEdgesBucket {
- int tot_segment;
- int (*segments)[2];
- int alloc_segment;
+ int tot_segment;
+ int (*segments)[2];
+ int alloc_segment;
} FeatherEdgesBucket;
static void feather_bucket_add_edge(FeatherEdgesBucket *bucket, int start, int end)
{
- const int alloc_delta = 256;
+ const int alloc_delta = 256;
- if (bucket->tot_segment >= bucket->alloc_segment) {
- if (!bucket->segments) {
- bucket->segments = MEM_callocN(alloc_delta * sizeof(*bucket->segments), "feather bucket segments");
- }
- else {
- bucket->segments = MEM_reallocN(bucket->segments,
- (alloc_delta + bucket->tot_segment) * sizeof(*bucket->segments));
- }
+ if (bucket->tot_segment >= bucket->alloc_segment) {
+ if (!bucket->segments) {
+ bucket->segments = MEM_callocN(alloc_delta * sizeof(*bucket->segments),
+ "feather bucket segments");
+ }
+ else {
+ bucket->segments = MEM_reallocN(
+ bucket->segments, (alloc_delta + bucket->tot_segment) * sizeof(*bucket->segments));
+ }
- bucket->alloc_segment += alloc_delta;
- }
+ bucket->alloc_segment += alloc_delta;
+ }
- bucket->segments[bucket->tot_segment][0] = start;
- bucket->segments[bucket->tot_segment][1] = end;
+ bucket->segments[bucket->tot_segment][0] = start;
+ bucket->segments[bucket->tot_segment][1] = end;
- bucket->tot_segment++;
+ bucket->tot_segment++;
}
-static void feather_bucket_check_intersect(
- float (*feather_points)[2], int tot_feather_point, FeatherEdgesBucket *bucket,
- int cur_a, int cur_b)
+static void feather_bucket_check_intersect(float (*feather_points)[2],
+ int tot_feather_point,
+ FeatherEdgesBucket *bucket,
+ int cur_a,
+ int cur_b)
{
- int i;
-
- const float *v1 = (float *) feather_points[cur_a];
- const float *v2 = (float *) feather_points[cur_b];
-
- for (i = 0; i < bucket->tot_segment; i++) {
- int check_a = bucket->segments[i][0];
- int check_b = bucket->segments[i][1];
-
- const float *v3 = (float *) feather_points[check_a];
- const float *v4 = (float *) feather_points[check_b];
-
- if (check_a >= cur_a - 1 || cur_b == check_a)
- continue;
-
- if (isect_seg_seg_v2_simple(v1, v2, v3, v4)) {
- int k;
- float p[2];
- float min_a[2], max_a[2];
- float min_b[2], max_b[2];
-
- isect_seg_seg_v2_point(v1, v2, v3, v4, p);
-
- INIT_MINMAX2(min_a, max_a);
- INIT_MINMAX2(min_b, max_b);
-
- /* collapse loop with smaller AABB */
- for (k = 0; k < tot_feather_point; k++) {
- if (k >= check_b && k <= cur_a) {
- minmax_v2v2_v2(min_a, max_a, feather_points[k]);
- }
- else {
- minmax_v2v2_v2(min_b, max_b, feather_points[k]);
- }
- }
-
- if (max_a[0] - min_a[0] < max_b[0] - min_b[0] ||
- max_a[1] - min_a[1] < max_b[1] - min_b[1])
- {
- for (k = check_b; k <= cur_a; k++) {
- copy_v2_v2(feather_points[k], p);
- }
- }
- else {
- for (k = 0; k <= check_a; k++) {
- copy_v2_v2(feather_points[k], p);
- }
-
- if (cur_b != 0) {
- for (k = cur_b; k < tot_feather_point; k++) {
- copy_v2_v2(feather_points[k], p);
- }
- }
- }
- }
- }
+ int i;
+
+ const float *v1 = (float *)feather_points[cur_a];
+ const float *v2 = (float *)feather_points[cur_b];
+
+ for (i = 0; i < bucket->tot_segment; i++) {
+ int check_a = bucket->segments[i][0];
+ int check_b = bucket->segments[i][1];
+
+ const float *v3 = (float *)feather_points[check_a];
+ const float *v4 = (float *)feather_points[check_b];
+
+ if (check_a >= cur_a - 1 || cur_b == check_a)
+ continue;
+
+ if (isect_seg_seg_v2_simple(v1, v2, v3, v4)) {
+ int k;
+ float p[2];
+ float min_a[2], max_a[2];
+ float min_b[2], max_b[2];
+
+ isect_seg_seg_v2_point(v1, v2, v3, v4, p);
+
+ INIT_MINMAX2(min_a, max_a);
+ INIT_MINMAX2(min_b, max_b);
+
+ /* collapse loop with smaller AABB */
+ for (k = 0; k < tot_feather_point; k++) {
+ if (k >= check_b && k <= cur_a) {
+ minmax_v2v2_v2(min_a, max_a, feather_points[k]);
+ }
+ else {
+ minmax_v2v2_v2(min_b, max_b, feather_points[k]);
+ }
+ }
+
+ if (max_a[0] - min_a[0] < max_b[0] - min_b[0] || max_a[1] - min_a[1] < max_b[1] - min_b[1]) {
+ for (k = check_b; k <= cur_a; k++) {
+ copy_v2_v2(feather_points[k], p);
+ }
+ }
+ else {
+ for (k = 0; k <= check_a; k++) {
+ copy_v2_v2(feather_points[k], p);
+ }
+
+ if (cur_b != 0) {
+ for (k = cur_b; k < tot_feather_point; k++) {
+ copy_v2_v2(feather_points[k], p);
+ }
+ }
+ }
+ }
+ }
}
-static int feather_bucket_index_from_coord(
- const float co[2], const float min[2], const float bucket_scale[2],
- const int buckets_per_side)
+static int feather_bucket_index_from_coord(const float co[2],
+ const float min[2],
+ const float bucket_scale[2],
+ const int buckets_per_side)
{
- int x = (int) ((co[0] - min[0]) * bucket_scale[0]);
- int y = (int) ((co[1] - min[1]) * bucket_scale[1]);
+ int x = (int)((co[0] - min[0]) * bucket_scale[0]);
+ int y = (int)((co[1] - min[1]) * bucket_scale[1]);
- if (x == buckets_per_side)
- x--;
+ if (x == buckets_per_side)
+ x--;
- if (y == buckets_per_side)
- y--;
+ if (y == buckets_per_side)
+ y--;
- return y * buckets_per_side + x;
+ return y * buckets_per_side + x;
}
-static void feather_bucket_get_diagonal(
- FeatherEdgesBucket *buckets, int start_bucket_index, int end_bucket_index, int buckets_per_side,
- FeatherEdgesBucket **r_diagonal_bucket_a, FeatherEdgesBucket **r_diagonal_bucket_b)
+static void feather_bucket_get_diagonal(FeatherEdgesBucket *buckets,
+ int start_bucket_index,
+ int end_bucket_index,
+ int buckets_per_side,
+ FeatherEdgesBucket **r_diagonal_bucket_a,
+ FeatherEdgesBucket **r_diagonal_bucket_b)
{
- int start_bucket_x = start_bucket_index % buckets_per_side;
- int start_bucket_y = start_bucket_index / buckets_per_side;
+ int start_bucket_x = start_bucket_index % buckets_per_side;
+ int start_bucket_y = start_bucket_index / buckets_per_side;
- int end_bucket_x = end_bucket_index % buckets_per_side;
- int end_bucket_y = end_bucket_index / buckets_per_side;
+ int end_bucket_x = end_bucket_index % buckets_per_side;
+ int end_bucket_y = end_bucket_index / buckets_per_side;
- int diagonal_bucket_a_index = start_bucket_y * buckets_per_side + end_bucket_x;
- int diagonal_bucket_b_index = end_bucket_y * buckets_per_side + start_bucket_x;
+ int diagonal_bucket_a_index = start_bucket_y * buckets_per_side + end_bucket_x;
+ int diagonal_bucket_b_index = end_bucket_y * buckets_per_side + start_bucket_x;
- *r_diagonal_bucket_a = &buckets[diagonal_bucket_a_index];
- *r_diagonal_bucket_b = &buckets[diagonal_bucket_b_index];
+ *r_diagonal_bucket_a = &buckets[diagonal_bucket_a_index];
+ *r_diagonal_bucket_b = &buckets[diagonal_bucket_b_index];
}
-void BKE_mask_spline_feather_collapse_inner_loops(
- MaskSpline *spline, float (*feather_points)[2], const unsigned int tot_feather_point)
+void BKE_mask_spline_feather_collapse_inner_loops(MaskSpline *spline,
+ float (*feather_points)[2],
+ const unsigned int tot_feather_point)
{
-#define BUCKET_INDEX(co) \
- feather_bucket_index_from_coord(co, min, bucket_scale, buckets_per_side)
-
- int buckets_per_side, tot_bucket;
- float bucket_size, bucket_scale[2];
+#define BUCKET_INDEX(co) feather_bucket_index_from_coord(co, min, bucket_scale, buckets_per_side)
- FeatherEdgesBucket *buckets;
+ int buckets_per_side, tot_bucket;
+ float bucket_size, bucket_scale[2];
- unsigned int i;
- float min[2], max[2];
- float max_delta_x = -1.0f, max_delta_y = -1.0f, max_delta;
+ FeatherEdgesBucket *buckets;
- if (tot_feather_point < 4) {
- /* self-intersection works only for quads at least,
- * in other cases polygon can't be self-intersecting anyway
- */
+ unsigned int i;
+ float min[2], max[2];
+ float max_delta_x = -1.0f, max_delta_y = -1.0f, max_delta;
- return;
- }
+ if (tot_feather_point < 4) {
+ /* self-intersection works only for quads at least,
+ * in other cases polygon can't be self-intersecting anyway
+ */
- /* find min/max corners of mask to build buckets in that space */
- INIT_MINMAX2(min, max);
+ return;
+ }
- for (i = 0; i < tot_feather_point; i++) {
- unsigned int next = i + 1;
- float delta;
+ /* find min/max corners of mask to build buckets in that space */
+ INIT_MINMAX2(min, max);
- minmax_v2v2_v2(min, max, feather_points[i]);
+ for (i = 0; i < tot_feather_point; i++) {
+ unsigned int next = i + 1;
+ float delta;
- if (next == tot_feather_point) {
- if (spline->flag & MASK_SPLINE_CYCLIC)
- next = 0;
- else
- break;
- }
+ minmax_v2v2_v2(min, max, feather_points[i]);
- delta = fabsf(feather_points[i][0] - feather_points[next][0]);
- if (delta > max_delta_x)
- max_delta_x = delta;
+ if (next == tot_feather_point) {
+ if (spline->flag & MASK_SPLINE_CYCLIC)
+ next = 0;
+ else
+ break;
+ }
- delta = fabsf(feather_points[i][1] - feather_points[next][1]);
- if (delta > max_delta_y)
- max_delta_y = delta;
- }
+ delta = fabsf(feather_points[i][0] - feather_points[next][0]);
+ if (delta > max_delta_x)
+ max_delta_x = delta;
- /* prevent divisionsby zero by ensuring bounding box is not collapsed */
- if (max[0] - min[0] < FLT_EPSILON) {
- max[0] += 0.01f;
- min[0] -= 0.01f;
- }
+ delta = fabsf(feather_points[i][1] - feather_points[next][1]);
+ if (delta > max_delta_y)
+ max_delta_y = delta;
+ }
- if (max[1] - min[1] < FLT_EPSILON) {
- max[1] += 0.01f;
- min[1] -= 0.01f;
- }
+ /* prevent divisionsby zero by ensuring bounding box is not collapsed */
+ if (max[0] - min[0] < FLT_EPSILON) {
+ max[0] += 0.01f;
+ min[0] -= 0.01f;
+ }
- /* use dynamically calculated buckets per side, so we likely wouldn't
- * run into a situation when segment doesn't fit two buckets which is
- * pain collecting candidates for intersection
- */
+ if (max[1] - min[1] < FLT_EPSILON) {
+ max[1] += 0.01f;
+ min[1] -= 0.01f;
+ }
- max_delta_x /= max[0] - min[0];
- max_delta_y /= max[1] - min[1];
+ /* use dynamically calculated buckets per side, so we likely wouldn't
+ * run into a situation when segment doesn't fit two buckets which is
+ * pain collecting candidates for intersection
+ */
- max_delta = MAX2(max_delta_x, max_delta_y);
+ max_delta_x /= max[0] - min[0];
+ max_delta_y /= max[1] - min[1];
- buckets_per_side = min_ii(512, 0.9f / max_delta);
+ max_delta = MAX2(max_delta_x, max_delta_y);
- if (buckets_per_side == 0) {
- /* happens when some segment fills the whole bounding box across some of dimension */
+ buckets_per_side = min_ii(512, 0.9f / max_delta);
- buckets_per_side = 1;
- }
+ if (buckets_per_side == 0) {
+ /* happens when some segment fills the whole bounding box across some of dimension */
- tot_bucket = buckets_per_side * buckets_per_side;
- bucket_size = 1.0f / buckets_per_side;
+ buckets_per_side = 1;
+ }
- /* pre-compute multipliers, to save mathematical operations in loops */
- bucket_scale[0] = 1.0f / ((max[0] - min[0]) * bucket_size);
- bucket_scale[1] = 1.0f / ((max[1] - min[1]) * bucket_size);
+ tot_bucket = buckets_per_side * buckets_per_side;
+ bucket_size = 1.0f / buckets_per_side;
- /* fill in buckets' edges */
- buckets = MEM_callocN(sizeof(FeatherEdgesBucket) * tot_bucket, "feather buckets");
+ /* pre-compute multipliers, to save mathematical operations in loops */
+ bucket_scale[0] = 1.0f / ((max[0] - min[0]) * bucket_size);
+ bucket_scale[1] = 1.0f / ((max[1] - min[1]) * bucket_size);
- for (i = 0; i < tot_feather_point; i++) {
- int start = i, end = i + 1;
- int start_bucket_index, end_bucket_index;
+ /* fill in buckets' edges */
+ buckets = MEM_callocN(sizeof(FeatherEdgesBucket) * tot_bucket, "feather buckets");
- if (end == tot_feather_point) {
- if (spline->flag & MASK_SPLINE_CYCLIC)
- end = 0;
- else
- break;
- }
+ for (i = 0; i < tot_feather_point; i++) {
+ int start = i, end = i + 1;
+ int start_bucket_index, end_bucket_index;
- start_bucket_index = BUCKET_INDEX(feather_points[start]);
- end_bucket_index = BUCKET_INDEX(feather_points[end]);
+ if (end == tot_feather_point) {
+ if (spline->flag & MASK_SPLINE_CYCLIC)
+ end = 0;
+ else
+ break;
+ }
- feather_bucket_add_edge(&buckets[start_bucket_index], start, end);
+ start_bucket_index = BUCKET_INDEX(feather_points[start]);
+ end_bucket_index = BUCKET_INDEX(feather_points[end]);
- if (start_bucket_index != end_bucket_index) {
- FeatherEdgesBucket *end_bucket = &buckets[end_bucket_index];
- FeatherEdgesBucket *diagonal_bucket_a, *diagonal_bucket_b;
+ feather_bucket_add_edge(&buckets[start_bucket_index], start, end);
- feather_bucket_get_diagonal(buckets, start_bucket_index, end_bucket_index, buckets_per_side,
- &diagonal_bucket_a, &diagonal_bucket_b);
+ if (start_bucket_index != end_bucket_index) {
+ FeatherEdgesBucket *end_bucket = &buckets[end_bucket_index];
+ FeatherEdgesBucket *diagonal_bucket_a, *diagonal_bucket_b;
- feather_bucket_add_edge(end_bucket, start, end);
- feather_bucket_add_edge(diagonal_bucket_a, start, end);
- feather_bucket_add_edge(diagonal_bucket_a, start, end);
- }
- }
+ feather_bucket_get_diagonal(buckets,
+ start_bucket_index,
+ end_bucket_index,
+ buckets_per_side,
+ &diagonal_bucket_a,
+ &diagonal_bucket_b);
- /* check all edges for intersection with edges from their buckets */
- for (i = 0; i < tot_feather_point; i++) {
- int cur_a = i, cur_b = i + 1;
- int start_bucket_index, end_bucket_index;
+ feather_bucket_add_edge(end_bucket, start, end);
+ feather_bucket_add_edge(diagonal_bucket_a, start, end);
+ feather_bucket_add_edge(diagonal_bucket_a, start, end);
+ }
+ }
- FeatherEdgesBucket *start_bucket;
+ /* check all edges for intersection with edges from their buckets */
+ for (i = 0; i < tot_feather_point; i++) {
+ int cur_a = i, cur_b = i + 1;
+ int start_bucket_index, end_bucket_index;
- if (cur_b == tot_feather_point)
- cur_b = 0;
+ FeatherEdgesBucket *start_bucket;
- start_bucket_index = BUCKET_INDEX(feather_points[cur_a]);
- end_bucket_index = BUCKET_INDEX(feather_points[cur_b]);
+ if (cur_b == tot_feather_point)
+ cur_b = 0;
- start_bucket = &buckets[start_bucket_index];
+ start_bucket_index = BUCKET_INDEX(feather_points[cur_a]);
+ end_bucket_index = BUCKET_INDEX(feather_points[cur_b]);
+
+ start_bucket = &buckets[start_bucket_index];
- feather_bucket_check_intersect(feather_points, tot_feather_point, start_bucket, cur_a, cur_b);
+ feather_bucket_check_intersect(feather_points, tot_feather_point, start_bucket, cur_a, cur_b);
- if (start_bucket_index != end_bucket_index) {
- FeatherEdgesBucket *end_bucket = &buckets[end_bucket_index];
- FeatherEdgesBucket *diagonal_bucket_a, *diagonal_bucket_b;
+ if (start_bucket_index != end_bucket_index) {
+ FeatherEdgesBucket *end_bucket = &buckets[end_bucket_index];
+ FeatherEdgesBucket *diagonal_bucket_a, *diagonal_bucket_b;
- feather_bucket_get_diagonal(buckets, start_bucket_index, end_bucket_index, buckets_per_side,
- &diagonal_bucket_a, &diagonal_bucket_b);
+ feather_bucket_get_diagonal(buckets,
+ start_bucket_index,
+ end_bucket_index,
+ buckets_per_side,
+ &diagonal_bucket_a,
+ &diagonal_bucket_b);
- feather_bucket_check_intersect(feather_points, tot_feather_point, end_bucket, cur_a, cur_b);
- feather_bucket_check_intersect(feather_points, tot_feather_point, diagonal_bucket_a, cur_a, cur_b);
- feather_bucket_check_intersect(feather_points, tot_feather_point, diagonal_bucket_b, cur_a, cur_b);
- }
- }
+ feather_bucket_check_intersect(feather_points, tot_feather_point, end_bucket, cur_a, cur_b);
+ feather_bucket_check_intersect(
+ feather_points, tot_feather_point, diagonal_bucket_a, cur_a, cur_b);
+ feather_bucket_check_intersect(
+ feather_points, tot_feather_point, diagonal_bucket_b, cur_a, cur_b);
+ }
+ }
- /* free buckets */
- for (i = 0; i < tot_bucket; i++) {
- if (buckets[i].segments)
- MEM_freeN(buckets[i].segments);
- }
+ /* free buckets */
+ for (i = 0; i < tot_bucket; i++) {
+ if (buckets[i].segments)
+ MEM_freeN(buckets[i].segments);
+ }
- MEM_freeN(buckets);
+ MEM_freeN(buckets);
#undef BUCKET_INDEX
}
/** only called from #BKE_mask_spline_feather_differentiated_points_with_resolution() ! */
static float (*mask_spline_feather_differentiated_points_with_resolution__even(
- MaskSpline *spline, unsigned int *tot_feather_point,
- const unsigned int resol, const bool do_feather_isect))[2]
+ MaskSpline *spline,
+ unsigned int *tot_feather_point,
+ const unsigned int resol,
+ const bool do_feather_isect))[2]
{
- MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
- MaskSplinePoint *point_curr, *point_prev;
- float (*feather)[2], (*fp)[2];
-
- const int tot = BKE_mask_spline_differentiate_calc_total(spline, resol);
- int a;
+ MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
+ MaskSplinePoint *point_curr, *point_prev;
+ float(*feather)[2], (*fp)[2];
- /* tot+1 because of 'forward_diff_bezier' function */
- feather = fp = MEM_mallocN((tot + 1) * sizeof(*feather), "mask spline feather diff points");
+ const int tot = BKE_mask_spline_differentiate_calc_total(spline, resol);
+ int a;
- a = spline->tot_point - 1;
- if (spline->flag & MASK_SPLINE_CYCLIC)
- a++;
+ /* tot+1 because of 'forward_diff_bezier' function */
+ feather = fp = MEM_mallocN((tot + 1) * sizeof(*feather), "mask spline feather diff points");
- point_prev = points_array;
- point_curr = point_prev + 1;
+ a = spline->tot_point - 1;
+ if (spline->flag & MASK_SPLINE_CYCLIC)
+ a++;
- while (a--) {
- /* BezTriple *bezt_prev; */ /* UNUSED */
- /* BezTriple *bezt_curr; */ /* UNUSED */
- int j;
+ point_prev = points_array;
+ point_curr = point_prev + 1;
- if (a == 0 && (spline->flag & MASK_SPLINE_CYCLIC))
- point_curr = points_array;
+ while (a--) {
+ /* BezTriple *bezt_prev; */ /* UNUSED */
+ /* BezTriple *bezt_curr; */ /* UNUSED */
+ int j;
+ if (a == 0 && (spline->flag & MASK_SPLINE_CYCLIC))
+ point_curr = points_array;
- /* bezt_prev = &point_prev->bezt; */
- /* bezt_curr = &point_curr->bezt; */
+ /* bezt_prev = &point_prev->bezt; */
+ /* bezt_curr = &point_curr->bezt; */
- for (j = 0; j < resol; j++, fp++) {
- float u = (float) j / resol, weight;
- float co[2], n[2];
+ for (j = 0; j < resol; j++, fp++) {
+ float u = (float)j / resol, weight;
+ float co[2], n[2];
- /* TODO - these calls all calculate similar things
- * could be unified for some speed */
- BKE_mask_point_segment_co(spline, point_prev, u, co);
- BKE_mask_point_normal(spline, point_prev, u, n);
- weight = BKE_mask_point_weight(spline, point_prev, u);
+ /* TODO - these calls all calculate similar things
+ * could be unified for some speed */
+ BKE_mask_point_segment_co(spline, point_prev, u, co);
+ BKE_mask_point_normal(spline, point_prev, u, n);
+ weight = BKE_mask_point_weight(spline, point_prev, u);
- madd_v2_v2v2fl(*fp, co, n, weight);
- }
+ madd_v2_v2v2fl(*fp, co, n, weight);
+ }
- if (a == 0 && (spline->flag & MASK_SPLINE_CYCLIC) == 0) {
- float u = 1.0f, weight;
- float co[2], n[2];
+ if (a == 0 && (spline->flag & MASK_SPLINE_CYCLIC) == 0) {
+ float u = 1.0f, weight;
+ float co[2], n[2];
- BKE_mask_point_segment_co(spline, point_prev, u, co);
- BKE_mask_point_normal(spline, point_prev, u, n);
- weight = BKE_mask_point_weight(spline, point_prev, u);
+ BKE_mask_point_segment_co(spline, point_prev, u, co);
+ BKE_mask_point_normal(spline, point_prev, u, n);
+ weight = BKE_mask_point_weight(spline, point_prev, u);
- madd_v2_v2v2fl(*fp, co, n, weight);
- }
+ madd_v2_v2v2fl(*fp, co, n, weight);
+ }
- point_prev = point_curr;
- point_curr++;
- }
+ point_prev = point_curr;
+ point_curr++;
+ }
- *tot_feather_point = tot;
+ *tot_feather_point = tot;
- if ((spline->flag & MASK_SPLINE_NOINTERSECT) && do_feather_isect) {
- BKE_mask_spline_feather_collapse_inner_loops(spline, feather, tot);
- }
+ if ((spline->flag & MASK_SPLINE_NOINTERSECT) && do_feather_isect) {
+ BKE_mask_spline_feather_collapse_inner_loops(spline, feather, tot);
+ }
- return feather;
+ return feather;
}
/** only called from #BKE_mask_spline_feather_differentiated_points_with_resolution() ! */
static float (*mask_spline_feather_differentiated_points_with_resolution__double(
- MaskSpline *spline, unsigned int *tot_feather_point,
- const unsigned int resol, const bool do_feather_isect))[2]
+ MaskSpline *spline,
+ unsigned int *tot_feather_point,
+ const unsigned int resol,
+ const bool do_feather_isect))[2]
{
- MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
-
- MaskSplinePoint *point_curr, *point_prev;
- float (*feather)[2], (*fp)[2];
- const int tot = BKE_mask_spline_differentiate_calc_total(spline, resol);
- int a;
-
- if (spline->tot_point <= 1) {
- /* nothing to differentiate */
- *tot_feather_point = 0;
- return NULL;
- }
-
- /* len+1 because of 'forward_diff_bezier' function */
- *tot_feather_point = tot;
- feather = fp = MEM_mallocN((tot + 1) * sizeof(*feather), "mask spline vets");
-
- a = spline->tot_point - 1;
- if (spline->flag & MASK_SPLINE_CYCLIC)
- a++;
-
- point_prev = points_array;
- point_curr = point_prev + 1;
-
- while (a--) {
- BezTriple local_prevbezt;
- BezTriple local_bezt;
- float point_prev_n[2], point_curr_n[2], tvec[2];
- float weight_prev, weight_curr;
- float len_base, len_feather, len_scalar;
-
- BezTriple *bezt_prev;
- BezTriple *bezt_curr;
- int j;
-
- if (a == 0 && (spline->flag & MASK_SPLINE_CYCLIC))
- point_curr = points_array;
-
- bezt_prev = &point_prev->bezt;
- bezt_curr = &point_curr->bezt;
-
- /* modified copy for feather */
- local_prevbezt = *bezt_prev;
- local_bezt = *bezt_curr;
-
- bezt_prev = &local_prevbezt;
- bezt_curr = &local_bezt;
-
- /* calc the normals */
- sub_v2_v2v2(tvec, bezt_prev->vec[1], bezt_prev->vec[0]);
- normalize_v2(tvec);
- point_prev_n[0] = -tvec[1];
- point_prev_n[1] = tvec[0];
-
- sub_v2_v2v2(tvec, bezt_curr->vec[1], bezt_curr->vec[0]);
- normalize_v2(tvec);
- point_curr_n[0] = -tvec[1];
- point_curr_n[1] = tvec[0];
-
- weight_prev = bezt_prev->weight;
- weight_curr = bezt_curr->weight;
-
- mul_v2_fl(point_prev_n, weight_prev);
- mul_v2_fl(point_curr_n, weight_curr);
-
- /* before we transform verts */
- len_base = len_v2v2(bezt_prev->vec[1], bezt_curr->vec[1]);
-
- // add_v2_v2(bezt_prev->vec[0], point_prev_n); // not needed
- add_v2_v2(bezt_prev->vec[1], point_prev_n);
- add_v2_v2(bezt_prev->vec[2], point_prev_n);
-
- add_v2_v2(bezt_curr->vec[0], point_curr_n);
- add_v2_v2(bezt_curr->vec[1], point_curr_n);
- // add_v2_v2(bezt_curr->vec[2], point_curr_n); // not needed
-
- len_feather = len_v2v2(bezt_prev->vec[1], bezt_curr->vec[1]);
-
- /* scale by chane in length */
- len_scalar = len_feather / len_base;
- dist_ensure_v2_v2fl(bezt_prev->vec[2], bezt_prev->vec[1], len_scalar * len_v2v2(bezt_prev->vec[2], bezt_prev->vec[1]));
- dist_ensure_v2_v2fl(bezt_curr->vec[0], bezt_curr->vec[1], len_scalar * len_v2v2(bezt_curr->vec[0], bezt_curr->vec[1]));
-
-
- for (j = 0; j < 2; j++) {
- BKE_curve_forward_diff_bezier(bezt_prev->vec[1][j], bezt_prev->vec[2][j],
- bezt_curr->vec[0][j], bezt_curr->vec[1][j],
- &(*fp)[j], resol, 2 * sizeof(float));
- }
-
-
- /* scale by the uw's */
- if (point_prev->tot_uw) {
- for (j = 0; j < resol; j++, fp++) {
- float u = (float) j / resol;
- float weight_uw, weight_scalar;
- float co[2];
-
- /* TODO - these calls all calculate similar things
- * could be unified for some speed */
- BKE_mask_point_segment_co(spline, point_prev, u, co);
-
- weight_uw = BKE_mask_point_weight(spline, point_prev, u);
- weight_scalar = BKE_mask_point_weight_scalar(spline, point_prev, u);
-
- dist_ensure_v2_v2fl(*fp, co, len_v2v2(*fp, co) * (weight_uw / weight_scalar));
- }
- }
- else {
- fp += resol;
- }
-
- if (a == 0 && (spline->flag & MASK_SPLINE_CYCLIC) == 0) {
- copy_v2_v2(*fp, bezt_curr->vec[1]);
- }
-
- point_prev = point_curr;
- point_curr++;
- }
-
- if ((spline->flag & MASK_SPLINE_NOINTERSECT) && do_feather_isect) {
- BKE_mask_spline_feather_collapse_inner_loops(spline, feather, tot);
- }
-
- return feather;
+ MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
+
+ MaskSplinePoint *point_curr, *point_prev;
+ float(*feather)[2], (*fp)[2];
+ const int tot = BKE_mask_spline_differentiate_calc_total(spline, resol);
+ int a;
+
+ if (spline->tot_point <= 1) {
+ /* nothing to differentiate */
+ *tot_feather_point = 0;
+ return NULL;
+ }
+
+ /* len+1 because of 'forward_diff_bezier' function */
+ *tot_feather_point = tot;
+ feather = fp = MEM_mallocN((tot + 1) * sizeof(*feather), "mask spline vets");
+
+ a = spline->tot_point - 1;
+ if (spline->flag & MASK_SPLINE_CYCLIC)
+ a++;
+
+ point_prev = points_array;
+ point_curr = point_prev + 1;
+
+ while (a--) {
+ BezTriple local_prevbezt;
+ BezTriple local_bezt;
+ float point_prev_n[2], point_curr_n[2], tvec[2];
+ float weight_prev, weight_curr;
+ float len_base, len_feather, len_scalar;
+
+ BezTriple *bezt_prev;
+ BezTriple *bezt_curr;
+ int j;
+
+ if (a == 0 && (spline->flag & MASK_SPLINE_CYCLIC))
+ point_curr = points_array;
+
+ bezt_prev = &point_prev->bezt;
+ bezt_curr = &point_curr->bezt;
+
+ /* modified copy for feather */
+ local_prevbezt = *bezt_prev;
+ local_bezt = *bezt_curr;
+
+ bezt_prev = &local_prevbezt;
+ bezt_curr = &local_bezt;
+
+ /* calc the normals */
+ sub_v2_v2v2(tvec, bezt_prev->vec[1], bezt_prev->vec[0]);
+ normalize_v2(tvec);
+ point_prev_n[0] = -tvec[1];
+ point_prev_n[1] = tvec[0];
+
+ sub_v2_v2v2(tvec, bezt_curr->vec[1], bezt_curr->vec[0]);
+ normalize_v2(tvec);
+ point_curr_n[0] = -tvec[1];
+ point_curr_n[1] = tvec[0];
+
+ weight_prev = bezt_prev->weight;
+ weight_curr = bezt_curr->weight;
+
+ mul_v2_fl(point_prev_n, weight_prev);
+ mul_v2_fl(point_curr_n, weight_curr);
+
+ /* before we transform verts */
+ len_base = len_v2v2(bezt_prev->vec[1], bezt_curr->vec[1]);
+
+ // add_v2_v2(bezt_prev->vec[0], point_prev_n); // not needed
+ add_v2_v2(bezt_prev->vec[1], point_prev_n);
+ add_v2_v2(bezt_prev->vec[2], point_prev_n);
+
+ add_v2_v2(bezt_curr->vec[0], point_curr_n);
+ add_v2_v2(bezt_curr->vec[1], point_curr_n);
+ // add_v2_v2(bezt_curr->vec[2], point_curr_n); // not needed
+
+ len_feather = len_v2v2(bezt_prev->vec[1], bezt_curr->vec[1]);
+
+ /* scale by chane in length */
+ len_scalar = len_feather / len_base;
+ dist_ensure_v2_v2fl(bezt_prev->vec[2],
+ bezt_prev->vec[1],
+ len_scalar * len_v2v2(bezt_prev->vec[2], bezt_prev->vec[1]));
+ dist_ensure_v2_v2fl(bezt_curr->vec[0],
+ bezt_curr->vec[1],
+ len_scalar * len_v2v2(bezt_curr->vec[0], bezt_curr->vec[1]));
+
+ for (j = 0; j < 2; j++) {
+ BKE_curve_forward_diff_bezier(bezt_prev->vec[1][j],
+ bezt_prev->vec[2][j],
+ bezt_curr->vec[0][j],
+ bezt_curr->vec[1][j],
+ &(*fp)[j],
+ resol,
+ 2 * sizeof(float));
+ }
+
+ /* scale by the uw's */
+ if (point_prev->tot_uw) {
+ for (j = 0; j < resol; j++, fp++) {
+ float u = (float)j / resol;
+ float weight_uw, weight_scalar;
+ float co[2];
+
+ /* TODO - these calls all calculate similar things
+ * could be unified for some speed */
+ BKE_mask_point_segment_co(spline, point_prev, u, co);
+
+ weight_uw = BKE_mask_point_weight(spline, point_prev, u);
+ weight_scalar = BKE_mask_point_weight_scalar(spline, point_prev, u);
+
+ dist_ensure_v2_v2fl(*fp, co, len_v2v2(*fp, co) * (weight_uw / weight_scalar));
+ }
+ }
+ else {
+ fp += resol;
+ }
+
+ if (a == 0 && (spline->flag & MASK_SPLINE_CYCLIC) == 0) {
+ copy_v2_v2(*fp, bezt_curr->vec[1]);
+ }
+
+ point_prev = point_curr;
+ point_curr++;
+ }
+
+ if ((spline->flag & MASK_SPLINE_NOINTERSECT) && do_feather_isect) {
+ BKE_mask_spline_feather_collapse_inner_loops(spline, feather, tot);
+ }
+
+ return feather;
}
/**
* values align with #BKE_mask_spline_differentiate_with_resolution
* when \a resol arguments match.
*/
-float (*BKE_mask_spline_feather_differentiated_points_with_resolution(
- MaskSpline *spline, unsigned int *tot_feather_point,
- const unsigned int resol, const bool do_feather_isect))[2]
+float (
+ *BKE_mask_spline_feather_differentiated_points_with_resolution(MaskSpline *spline,
+ unsigned int *tot_feather_point,
+ const unsigned int resol,
+ const bool do_feather_isect))[2]
{
- switch (spline->offset_mode) {
- case MASK_SPLINE_OFFSET_EVEN:
- return mask_spline_feather_differentiated_points_with_resolution__even(spline, tot_feather_point, resol, do_feather_isect);
- case MASK_SPLINE_OFFSET_SMOOTH:
- default:
- return mask_spline_feather_differentiated_points_with_resolution__double(spline, tot_feather_point, resol, do_feather_isect);
- }
+ switch (spline->offset_mode) {
+ case MASK_SPLINE_OFFSET_EVEN:
+ return mask_spline_feather_differentiated_points_with_resolution__even(
+ spline, tot_feather_point, resol, do_feather_isect);
+ case MASK_SPLINE_OFFSET_SMOOTH:
+ default:
+ return mask_spline_feather_differentiated_points_with_resolution__double(
+ spline, tot_feather_point, resol, do_feather_isect);
+ }
}
float (*BKE_mask_spline_feather_points(MaskSpline *spline, int *tot_feather_point))[2]
{
- MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
+ MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
- int i, tot = 0;
- float (*feather)[2], (*fp)[2];
+ int i, tot = 0;
+ float(*feather)[2], (*fp)[2];
- /* count */
- for (i = 0; i < spline->tot_point; i++) {
- MaskSplinePoint *point = &points_array[i];
+ /* count */
+ for (i = 0; i < spline->tot_point; i++) {
+ MaskSplinePoint *point = &points_array[i];
- tot += point->tot_uw + 1;
- }
+ tot += point->tot_uw + 1;
+ }
- /* create data */
- feather = fp = MEM_mallocN(tot * sizeof(*feather), "mask spline feather points");
+ /* create data */
+ feather = fp = MEM_mallocN(tot * sizeof(*feather), "mask spline feather points");
- for (i = 0; i < spline->tot_point; i++) {
- MaskSplinePoint *point = &points_array[i];
- BezTriple *bezt = &point->bezt;
- float weight, n[2];
- int j;
+ for (i = 0; i < spline->tot_point; i++) {
+ MaskSplinePoint *point = &points_array[i];
+ BezTriple *bezt = &point->bezt;
+ float weight, n[2];
+ int j;
- BKE_mask_point_normal(spline, point, 0.0f, n);
- weight = BKE_mask_point_weight(spline, point, 0.0f);
+ BKE_mask_point_normal(spline, point, 0.0f, n);
+ weight = BKE_mask_point_weight(spline, point, 0.0f);
- madd_v2_v2v2fl(*fp, bezt->vec[1], n, weight);
- fp++;
+ madd_v2_v2v2fl(*fp, bezt->vec[1], n, weight);
+ fp++;
- for (j = 0; j < point->tot_uw; j++) {
- float u = point->uw[j].u;
- float co[2];
+ for (j = 0; j < point->tot_uw; j++) {
+ float u = point->uw[j].u;
+ float co[2];
- BKE_mask_point_segment_co(spline, point, u, co);
- BKE_mask_point_normal(spline, point, u, n);
- weight = BKE_mask_point_weight(spline, point, u);
+ BKE_mask_point_segment_co(spline, point, u, co);
+ BKE_mask_point_normal(spline, point, u, n);
+ weight = BKE_mask_point_weight(spline, point, u);
- madd_v2_v2v2fl(*fp, co, n, weight);
- fp++;
- }
- }
+ madd_v2_v2v2fl(*fp, co, n, weight);
+ fp++;
+ }
+ }
- *tot_feather_point = tot;
+ *tot_feather_point = tot;
- return feather;
+ return feather;
}
/* *** mask point functions which involve evaluation *** */
-float *BKE_mask_point_segment_feather_diff(MaskSpline *spline, MaskSplinePoint *point,
- int width, int height,
+float *BKE_mask_point_segment_feather_diff(MaskSpline *spline,
+ MaskSplinePoint *point,
+ int width,
+ int height,
unsigned int *tot_feather_point)
{
- float *feather, *fp;
- unsigned int resol = BKE_mask_spline_feather_resolution(spline, width, height);
- unsigned int i;
+ float *feather, *fp;
+ unsigned int resol = BKE_mask_spline_feather_resolution(spline, width, height);
+ unsigned int i;
- feather = fp = MEM_callocN(2 * resol * sizeof(float), "mask point spline feather diff points");
+ feather = fp = MEM_callocN(2 * resol * sizeof(float), "mask point spline feather diff points");
- for (i = 0; i < resol; i++, fp += 2) {
- float u = (float)(i % resol) / resol, weight;
- float co[2], n[2];
+ for (i = 0; i < resol; i++, fp += 2) {
+ float u = (float)(i % resol) / resol, weight;
+ float co[2], n[2];
- BKE_mask_point_segment_co(spline, point, u, co);
- BKE_mask_point_normal(spline, point, u, n);
- weight = BKE_mask_point_weight(spline, point, u);
+ BKE_mask_point_segment_co(spline, point, u, co);
+ BKE_mask_point_normal(spline, point, u, n);
+ weight = BKE_mask_point_weight(spline, point, u);
- fp[0] = co[0] + n[0] * weight;
- fp[1] = co[1] + n[1] * weight;
- }
+ fp[0] = co[0] + n[0] * weight;
+ fp[1] = co[1] + n[1] * weight;
+ }
- *tot_feather_point = resol;
+ *tot_feather_point = resol;
- return feather;
+ return feather;
}
-float *BKE_mask_point_segment_diff(MaskSpline *spline, MaskSplinePoint *point,
- int width, int height, unsigned int *tot_diff_point)
+float *BKE_mask_point_segment_diff(MaskSpline *spline,
+ MaskSplinePoint *point,
+ int width,
+ int height,
+ unsigned int *tot_diff_point)
{
- MaskSplinePoint *points_array = BKE_mask_spline_point_array_from_point(spline, point);
+ MaskSplinePoint *points_array = BKE_mask_spline_point_array_from_point(spline, point);
- BezTriple *bezt, *bezt_next;
- float *diff_points, *fp;
- int j, resol = BKE_mask_spline_resolution(spline, width, height);
+ BezTriple *bezt, *bezt_next;
+ float *diff_points, *fp;
+ int j, resol = BKE_mask_spline_resolution(spline, width, height);
- bezt = &point->bezt;
- bezt_next = BKE_mask_spline_point_next_bezt(spline, points_array, point);
+ bezt = &point->bezt;
+ bezt_next = BKE_mask_spline_point_next_bezt(spline, points_array, point);
- if (!bezt_next)
- return NULL;
+ if (!bezt_next)
+ return NULL;
- /* resol+1 because of 'forward_diff_bezier' function */
- *tot_diff_point = resol + 1;
- diff_points = fp = MEM_callocN((resol + 1) * 2 * sizeof(float), "mask segment vets");
+ /* resol+1 because of 'forward_diff_bezier' function */
+ *tot_diff_point = resol + 1;
+ diff_points = fp = MEM_callocN((resol + 1) * 2 * sizeof(float), "mask segment vets");
- for (j = 0; j < 2; j++) {
- BKE_curve_forward_diff_bezier(bezt->vec[1][j], bezt->vec[2][j],
- bezt_next->vec[0][j], bezt_next->vec[1][j],
- fp + j, resol, 2 * sizeof(float));
- }
+ for (j = 0; j < 2; j++) {
+ BKE_curve_forward_diff_bezier(bezt->vec[1][j],
+ bezt->vec[2][j],
+ bezt_next->vec[0][j],
+ bezt_next->vec[1][j],
+ fp + j,
+ resol,
+ 2 * sizeof(float));
+ }
- copy_v2_v2(fp + 2 * resol, bezt_next->vec[1]);
+ copy_v2_v2(fp + 2 * resol, bezt_next->vec[1]);
- return diff_points;
+ return diff_points;
}
static void mask_evaluate_apply_point_parent(MaskSplinePoint *point, float ctime)
{
- float parent_matrix[3][3];
- BKE_mask_point_parent_matrix_get(point, ctime, parent_matrix);
- mul_m3_v2(parent_matrix, point->bezt.vec[0]);
- mul_m3_v2(parent_matrix, point->bezt.vec[1]);
- mul_m3_v2(parent_matrix, point->bezt.vec[2]);
+ float parent_matrix[3][3];
+ BKE_mask_point_parent_matrix_get(point, ctime, parent_matrix);
+ mul_m3_v2(parent_matrix, point->bezt.vec[0]);
+ mul_m3_v2(parent_matrix, point->bezt.vec[1]);
+ mul_m3_v2(parent_matrix, point->bezt.vec[2]);
}
void BKE_mask_layer_evaluate_animation(MaskLayer *masklay, const float ctime)
{
- /* animation if available */
- MaskLayerShape *masklay_shape_a;
- MaskLayerShape *masklay_shape_b;
- int found;
- if ((found = BKE_mask_layer_shape_find_frame_range(
- masklay, ctime, &masklay_shape_a, &masklay_shape_b)))
- {
- if (found == 1) {
+ /* animation if available */
+ MaskLayerShape *masklay_shape_a;
+ MaskLayerShape *masklay_shape_b;
+ int found;
+ if ((found = BKE_mask_layer_shape_find_frame_range(
+ masklay, ctime, &masklay_shape_a, &masklay_shape_b))) {
+ if (found == 1) {
#if 0
- printf("%s: exact %d %d (%d)\n",
- __func__,
- (int)ctime,
- BLI_listbase_count(&masklay->splines_shapes),
- masklay_shape_a->frame);
+ printf("%s: exact %d %d (%d)\n",
+ __func__,
+ (int)ctime,
+ BLI_listbase_count(&masklay->splines_shapes),
+ masklay_shape_a->frame);
#endif
- BKE_mask_layer_shape_to_mask(masklay, masklay_shape_a);
- }
- else if (found == 2) {
- float w = masklay_shape_b->frame - masklay_shape_a->frame;
+ BKE_mask_layer_shape_to_mask(masklay, masklay_shape_a);
+ }
+ else if (found == 2) {
+ float w = masklay_shape_b->frame - masklay_shape_a->frame;
#if 0
- printf("%s: tween %d %d (%d %d)\n",
- __func__,
- (int)ctime,
- BLI_listbase_count(&masklay->splines_shapes),
- masklay_shape_a->frame, masklay_shape_b->frame);
+ printf("%s: tween %d %d (%d %d)\n",
+ __func__,
+ (int)ctime,
+ BLI_listbase_count(&masklay->splines_shapes),
+ masklay_shape_a->frame, masklay_shape_b->frame);
#endif
- BKE_mask_layer_shape_to_mask_interp(
- masklay,
- masklay_shape_a, masklay_shape_b,
- (ctime - masklay_shape_a->frame) / w);
- }
- else {
- /* always fail, should never happen */
- BLI_assert(found == 2);
- }
- }
+ BKE_mask_layer_shape_to_mask_interp(
+ masklay, masklay_shape_a, masklay_shape_b, (ctime - masklay_shape_a->frame) / w);
+ }
+ else {
+ /* always fail, should never happen */
+ BLI_assert(found == 2);
+ }
+ }
}
void BKE_mask_layer_evaluate_deform(MaskLayer *masklay, const float ctime)
{
- BKE_mask_layer_calc_handles(masklay);
- for (MaskSpline *spline = masklay->splines.first;
- spline != NULL;
- spline = spline->next)
- {
- bool need_handle_recalc = false;
- BKE_mask_spline_ensure_deform(spline);
- for (int i = 0; i < spline->tot_point; i++) {
- MaskSplinePoint *point = &spline->points[i];
- MaskSplinePoint *point_deform = &spline->points_deform[i];
- BKE_mask_point_free(point_deform);
- *point_deform = *point;
- point_deform->uw = point->uw ? MEM_dupallocN(point->uw) : NULL;
- mask_evaluate_apply_point_parent(point_deform, ctime);
- if (ELEM(point->bezt.h1, HD_AUTO, HD_VECT)) {
- need_handle_recalc = true;
- }
- }
- /* if the spline has auto or vector handles, these need to be
- * recalculated after deformation.
- */
- if (need_handle_recalc) {
- for (int i = 0; i < spline->tot_point; i++) {
- MaskSplinePoint *point_deform = &spline->points_deform[i];
- if (ELEM(point_deform->bezt.h1, HD_AUTO, HD_VECT)) {
- BKE_mask_calc_handle_point(spline, point_deform);
- }
- }
- }
- /* end extra calc handles loop */
- }
+ BKE_mask_layer_calc_handles(masklay);
+ for (MaskSpline *spline = masklay->splines.first; spline != NULL; spline = spline->next) {
+ bool need_handle_recalc = false;
+ BKE_mask_spline_ensure_deform(spline);
+ for (int i = 0; i < spline->tot_point; i++) {
+ MaskSplinePoint *point = &spline->points[i];
+ MaskSplinePoint *point_deform = &spline->points_deform[i];
+ BKE_mask_point_free(point_deform);
+ *point_deform = *point;
+ point_deform->uw = point->uw ? MEM_dupallocN(point->uw) : NULL;
+ mask_evaluate_apply_point_parent(point_deform, ctime);
+ if (ELEM(point->bezt.h1, HD_AUTO, HD_VECT)) {
+ need_handle_recalc = true;
+ }
+ }
+ /* if the spline has auto or vector handles, these need to be
+ * recalculated after deformation.
+ */
+ if (need_handle_recalc) {
+ for (int i = 0; i < spline->tot_point; i++) {
+ MaskSplinePoint *point_deform = &spline->points_deform[i];
+ if (ELEM(point_deform->bezt.h1, HD_AUTO, HD_VECT)) {
+ BKE_mask_calc_handle_point(spline, point_deform);
+ }
+ }
+ }
+ /* end extra calc handles loop */
+ }
}
void BKE_mask_eval_animation(struct Depsgraph *depsgraph, Mask *mask)
{
- float ctime = DEG_get_ctime(depsgraph);
- DEG_debug_print_eval(depsgraph, __func__, mask->id.name, mask);
- for (MaskLayer *mask_layer = mask->masklayers.first;
- mask_layer != NULL;
- mask_layer = mask_layer->next)
- {
- BKE_mask_layer_evaluate_animation(mask_layer, ctime);
- }
+ float ctime = DEG_get_ctime(depsgraph);
+ DEG_debug_print_eval(depsgraph, __func__, mask->id.name, mask);
+ for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer != NULL;
+ mask_layer = mask_layer->next) {
+ BKE_mask_layer_evaluate_animation(mask_layer, ctime);
+ }
}
void BKE_mask_eval_update(struct Depsgraph *depsgraph, Mask *mask)
{
- float ctime = DEG_get_ctime(depsgraph);
- DEG_debug_print_eval(depsgraph, __func__, mask->id.name, mask);
- for (MaskLayer *mask_layer = mask->masklayers.first;
- mask_layer != NULL;
- mask_layer = mask_layer->next)
- {
- BKE_mask_layer_evaluate_deform(mask_layer, ctime);
- }
+ float ctime = DEG_get_ctime(depsgraph);
+ DEG_debug_print_eval(depsgraph, __func__, mask->id.name, mask);
+ for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer != NULL;
+ mask_layer = mask_layer->next) {
+ BKE_mask_layer_evaluate_deform(mask_layer, ctime);
+ }
}
diff --git a/source/blender/blenkernel/intern/mask_rasterize.c b/source/blender/blenkernel/intern/mask_rasterize.c
index a1405f1243c..24137b680ba 100644
--- a/source/blender/blenkernel/intern/mask_rasterize.c
+++ b/source/blender/blenkernel/intern/mask_rasterize.c
@@ -91,51 +91,55 @@
#define BUCKET_PIXELS_PER_CELL 4
#define SF_EDGE_IS_BOUNDARY 0xff
-#define SF_KEYINDEX_TEMP_ID ((unsigned int) -1)
+#define SF_KEYINDEX_TEMP_ID ((unsigned int)-1)
-#define TRI_TERMINATOR_ID ((unsigned int) -1)
-#define TRI_VERT ((unsigned int) -1)
+#define TRI_TERMINATOR_ID ((unsigned int)-1)
+#define TRI_VERT ((unsigned int)-1)
/* for debugging add... */
#ifndef NDEBUG
/* printf("%u %u %u %u\n", _t[0], _t[1], _t[2], _t[3]); \ */
-# define FACE_ASSERT(face, vert_max) \
-{ \
- unsigned int *_t = face; \
- BLI_assert(_t[0] < vert_max); \
- BLI_assert(_t[1] < vert_max); \
- BLI_assert(_t[2] < vert_max); \
- BLI_assert(_t[3] < vert_max || _t[3] == TRI_VERT); \
-} (void)0
+# define FACE_ASSERT(face, vert_max) \
+ { \
+ unsigned int *_t = face; \
+ BLI_assert(_t[0] < vert_max); \
+ BLI_assert(_t[1] < vert_max); \
+ BLI_assert(_t[2] < vert_max); \
+ BLI_assert(_t[3] < vert_max || _t[3] == TRI_VERT); \
+ } \
+ (void)0
#else
- /* do nothing */
+/* do nothing */
# define FACE_ASSERT(face, vert_max)
#endif
static CLG_LogRef LOG = {"bke.mask_rasterize"};
-static void rotate_point_v2(float r_p[2], const float p[2], const float cent[2], const float angle, const float asp[2])
+static void rotate_point_v2(
+ float r_p[2], const float p[2], const float cent[2], const float angle, const float asp[2])
{
- const float s = sinf(angle);
- const float c = cosf(angle);
- float p_new[2];
+ const float s = sinf(angle);
+ const float c = cosf(angle);
+ float p_new[2];
- /* translate point back to origin */
- r_p[0] = (p[0] - cent[0]) / asp[0];
- r_p[1] = (p[1] - cent[1]) / asp[1];
+ /* translate point back to origin */
+ r_p[0] = (p[0] - cent[0]) / asp[0];
+ r_p[1] = (p[1] - cent[1]) / asp[1];
- /* rotate point */
- p_new[0] = ((r_p[0] * c) - (r_p[1] * s)) * asp[0];
- p_new[1] = ((r_p[0] * s) + (r_p[1] * c)) * asp[1];
+ /* rotate point */
+ p_new[0] = ((r_p[0] * c) - (r_p[1] * s)) * asp[0];
+ p_new[1] = ((r_p[0] * s) + (r_p[1] * c)) * asp[1];
- /* translate point back */
- r_p[0] = p_new[0] + cent[0];
- r_p[1] = p_new[1] + cent[1];
+ /* translate point back */
+ r_p[0] = p_new[0] + cent[0];
+ r_p[1] = p_new[1] + cent[1];
}
-BLI_INLINE unsigned int clampis_uint(const unsigned int v, const unsigned int min, const unsigned int max)
+BLI_INLINE unsigned int clampis_uint(const unsigned int v,
+ const unsigned int min,
+ const unsigned int max)
{
- return v < min ? min : (v > max ? max : v);
+ return v < min ? min : (v > max ? max : v);
}
/* --------------------------------------------------------------------- */
@@ -151,54 +155,51 @@ BLI_INLINE unsigned int clampis_uint(const unsigned int v, const unsigned int mi
/* internal use only */
typedef struct MaskRasterLayer {
- /* geometry */
- unsigned int face_tot;
- unsigned int (*face_array)[4]; /* access coords tri/quad */
- float (*face_coords)[3]; /* xy, z 0-1 (1.0 == filled) */
-
-
- /* 2d bounds (to quickly skip bucket lookup) */
- rctf bounds;
-
-
- /* buckets */
- unsigned int **buckets_face;
- /* cache divide and subtract */
- float buckets_xy_scalar[2]; /* (1.0 / (buckets_width + FLT_EPSILON)) * buckets_x */
- unsigned int buckets_x;
- unsigned int buckets_y;
-
-
- /* copied direct from #MaskLayer.--- */
- /* blending options */
- float alpha;
- char blend;
- char blend_flag;
- char falloff;
+ /* geometry */
+ unsigned int face_tot;
+ unsigned int (*face_array)[4]; /* access coords tri/quad */
+ float (*face_coords)[3]; /* xy, z 0-1 (1.0 == filled) */
+
+ /* 2d bounds (to quickly skip bucket lookup) */
+ rctf bounds;
+
+ /* buckets */
+ unsigned int **buckets_face;
+ /* cache divide and subtract */
+ float buckets_xy_scalar[2]; /* (1.0 / (buckets_width + FLT_EPSILON)) * buckets_x */
+ unsigned int buckets_x;
+ unsigned int buckets_y;
+
+ /* copied direct from #MaskLayer.--- */
+ /* blending options */
+ float alpha;
+ char blend;
+ char blend_flag;
+ char falloff;
} MaskRasterLayer;
typedef struct MaskRasterSplineInfo {
- /* body of the spline */
- unsigned int vertex_offset;
- unsigned int vertex_total;
+ /* body of the spline */
+ unsigned int vertex_offset;
+ unsigned int vertex_total;
- /* capping for non-filled, non cyclic splines */
- unsigned int vertex_total_cap_head;
- unsigned int vertex_total_cap_tail;
+ /* capping for non-filled, non cyclic splines */
+ unsigned int vertex_total_cap_head;
+ unsigned int vertex_total_cap_tail;
- bool is_cyclic;
+ bool is_cyclic;
} MaskRasterSplineInfo;
/**
* opaque local struct for mask pixel lookup, each MaskLayer needs one of these
*/
struct MaskRasterHandle {
- MaskRasterLayer *layers;
- unsigned int layers_tot;
+ MaskRasterLayer *layers;
+ unsigned int layers_tot;
- /* 2d bounds (to quickly skip bucket lookup) */
- rctf bounds;
+ /* 2d bounds (to quickly skip bucket lookup) */
+ rctf bounds;
};
/* --------------------------------------------------------------------- */
@@ -207,107 +208,107 @@ struct MaskRasterHandle {
MaskRasterHandle *BKE_maskrasterize_handle_new(void)
{
- MaskRasterHandle *mr_handle;
+ MaskRasterHandle *mr_handle;
- mr_handle = MEM_callocN(sizeof(MaskRasterHandle), "MaskRasterHandle");
+ mr_handle = MEM_callocN(sizeof(MaskRasterHandle), "MaskRasterHandle");
- return mr_handle;
+ return mr_handle;
}
void BKE_maskrasterize_handle_free(MaskRasterHandle *mr_handle)
{
- const unsigned int layers_tot = mr_handle->layers_tot;
- unsigned int i;
- MaskRasterLayer *layer = mr_handle->layers;
-
- for (i = 0; i < layers_tot; i++, layer++) {
-
- if (layer->face_array) {
- MEM_freeN(layer->face_array);
- }
-
- if (layer->face_coords) {
- MEM_freeN(layer->face_coords);
- }
-
- if (layer->buckets_face) {
- const unsigned int bucket_tot = layer->buckets_x * layer->buckets_y;
- unsigned int bucket_index;
- for (bucket_index = 0; bucket_index < bucket_tot; bucket_index++) {
- unsigned int *face_index = layer->buckets_face[bucket_index];
- if (face_index) {
- MEM_freeN(face_index);
- }
- }
-
- MEM_freeN(layer->buckets_face);
- }
- }
-
- MEM_freeN(mr_handle->layers);
- MEM_freeN(mr_handle);
+ const unsigned int layers_tot = mr_handle->layers_tot;
+ unsigned int i;
+ MaskRasterLayer *layer = mr_handle->layers;
+
+ for (i = 0; i < layers_tot; i++, layer++) {
+
+ if (layer->face_array) {
+ MEM_freeN(layer->face_array);
+ }
+
+ if (layer->face_coords) {
+ MEM_freeN(layer->face_coords);
+ }
+
+ if (layer->buckets_face) {
+ const unsigned int bucket_tot = layer->buckets_x * layer->buckets_y;
+ unsigned int bucket_index;
+ for (bucket_index = 0; bucket_index < bucket_tot; bucket_index++) {
+ unsigned int *face_index = layer->buckets_face[bucket_index];
+ if (face_index) {
+ MEM_freeN(face_index);
+ }
+ }
+
+ MEM_freeN(layer->buckets_face);
+ }
+ }
+
+ MEM_freeN(mr_handle->layers);
+ MEM_freeN(mr_handle);
}
-
-static void maskrasterize_spline_differentiate_point_outset(float (*diff_feather_points)[2], float (*diff_points)[2],
- const unsigned int tot_diff_point, const float ofs,
+static void maskrasterize_spline_differentiate_point_outset(float (*diff_feather_points)[2],
+ float (*diff_points)[2],
+ const unsigned int tot_diff_point,
+ const float ofs,
const bool do_test)
{
- unsigned int k_prev = tot_diff_point - 2;
- unsigned int k_curr = tot_diff_point - 1;
- unsigned int k_next = 0;
+ unsigned int k_prev = tot_diff_point - 2;
+ unsigned int k_curr = tot_diff_point - 1;
+ unsigned int k_next = 0;
- unsigned int k;
+ unsigned int k;
- float d_prev[2];
- float d_next[2];
- float d[2];
+ float d_prev[2];
+ float d_next[2];
+ float d[2];
- const float *co_prev;
- const float *co_curr;
- const float *co_next;
+ const float *co_prev;
+ const float *co_curr;
+ const float *co_next;
- const float ofs_squared = ofs * ofs;
+ const float ofs_squared = ofs * ofs;
- co_prev = diff_points[k_prev];
- co_curr = diff_points[k_curr];
- co_next = diff_points[k_next];
+ co_prev = diff_points[k_prev];
+ co_curr = diff_points[k_curr];
+ co_next = diff_points[k_next];
- /* precalc */
- sub_v2_v2v2(d_prev, co_prev, co_curr);
- normalize_v2(d_prev);
+ /* precalc */
+ sub_v2_v2v2(d_prev, co_prev, co_curr);
+ normalize_v2(d_prev);
- for (k = 0; k < tot_diff_point; k++) {
+ for (k = 0; k < tot_diff_point; k++) {
- /* co_prev = diff_points[k_prev]; */ /* precalc */
- co_curr = diff_points[k_curr];
- co_next = diff_points[k_next];
+ /* co_prev = diff_points[k_prev]; */ /* precalc */
+ co_curr = diff_points[k_curr];
+ co_next = diff_points[k_next];
- /* sub_v2_v2v2(d_prev, co_prev, co_curr); */ /* precalc */
- sub_v2_v2v2(d_next, co_curr, co_next);
+ /* sub_v2_v2v2(d_prev, co_prev, co_curr); */ /* precalc */
+ sub_v2_v2v2(d_next, co_curr, co_next);
- /* normalize_v2(d_prev); */ /* precalc */
- normalize_v2(d_next);
+ /* normalize_v2(d_prev); */ /* precalc */
+ normalize_v2(d_next);
- if ((do_test == false) ||
- (len_squared_v2v2(diff_feather_points[k], diff_points[k]) < ofs_squared))
- {
+ if ((do_test == false) ||
+ (len_squared_v2v2(diff_feather_points[k], diff_points[k]) < ofs_squared)) {
- add_v2_v2v2(d, d_prev, d_next);
+ add_v2_v2v2(d, d_prev, d_next);
- normalize_v2(d);
+ normalize_v2(d);
- diff_feather_points[k][0] = diff_points[k][0] + ( d[1] * ofs);
- diff_feather_points[k][1] = diff_points[k][1] + (-d[0] * ofs);
- }
+ diff_feather_points[k][0] = diff_points[k][0] + (d[1] * ofs);
+ diff_feather_points[k][1] = diff_points[k][1] + (-d[0] * ofs);
+ }
- /* use next iter */
- copy_v2_v2(d_prev, d_next);
+ /* use next iter */
+ copy_v2_v2(d_prev, d_next);
- /* k_prev = k_curr; */ /* precalc */
- k_curr = k_next;
- k_next++;
- }
+ /* k_prev = k_curr; */ /* precalc */
+ k_curr = k_next;
+ k_next++;
+ }
}
/* this function is not exact, sometimes it returns false positives,
@@ -319,876 +320,891 @@ static void maskrasterize_spline_differentiate_point_outset(float (*diff_feather
* - if not get the max radius to a corner of the bucket and see how close we
* are to any of the triangle edges.
*/
-static bool layer_bucket_isect_test(
- const MaskRasterLayer *layer, unsigned int face_index,
- const unsigned int bucket_x, const unsigned int bucket_y,
- const float bucket_size_x, const float bucket_size_y,
- const float bucket_max_rad_squared)
+static bool layer_bucket_isect_test(const MaskRasterLayer *layer,
+ unsigned int face_index,
+ const unsigned int bucket_x,
+ const unsigned int bucket_y,
+ const float bucket_size_x,
+ const float bucket_size_y,
+ const float bucket_max_rad_squared)
{
- unsigned int *face = layer->face_array[face_index];
- float (*cos)[3] = layer->face_coords;
-
- const float xmin = layer->bounds.xmin + (bucket_size_x * (float)bucket_x);
- const float ymin = layer->bounds.ymin + (bucket_size_y * (float)bucket_y);
- const float xmax = xmin + bucket_size_x;
- const float ymax = ymin + bucket_size_y;
-
- const float cent[2] = {(xmin + xmax) * 0.5f,
- (ymin + ymax) * 0.5f};
-
- if (face[3] == TRI_VERT) {
- const float *v1 = cos[face[0]];
- const float *v2 = cos[face[1]];
- const float *v3 = cos[face[2]];
-
- if (isect_point_tri_v2(cent, v1, v2, v3)) {
- return true;
- }
- else {
- if ((dist_squared_to_line_segment_v2(cent, v1, v2) < bucket_max_rad_squared) ||
- (dist_squared_to_line_segment_v2(cent, v2, v3) < bucket_max_rad_squared) ||
- (dist_squared_to_line_segment_v2(cent, v3, v1) < bucket_max_rad_squared))
- {
- return true;
- }
- else {
- // printf("skip tri\n");
- return false;
- }
- }
-
- }
- else {
- const float *v1 = cos[face[0]];
- const float *v2 = cos[face[1]];
- const float *v3 = cos[face[2]];
- const float *v4 = cos[face[3]];
-
- if (isect_point_tri_v2(cent, v1, v2, v3)) {
- return true;
- }
- else if (isect_point_tri_v2(cent, v1, v3, v4)) {
- return true;
- }
- else {
- if ((dist_squared_to_line_segment_v2(cent, v1, v2) < bucket_max_rad_squared) ||
- (dist_squared_to_line_segment_v2(cent, v2, v3) < bucket_max_rad_squared) ||
- (dist_squared_to_line_segment_v2(cent, v3, v4) < bucket_max_rad_squared) ||
- (dist_squared_to_line_segment_v2(cent, v4, v1) < bucket_max_rad_squared))
- {
- return true;
- }
- else {
- // printf("skip quad\n");
- return false;
- }
- }
- }
+ unsigned int *face = layer->face_array[face_index];
+ float(*cos)[3] = layer->face_coords;
+
+ const float xmin = layer->bounds.xmin + (bucket_size_x * (float)bucket_x);
+ const float ymin = layer->bounds.ymin + (bucket_size_y * (float)bucket_y);
+ const float xmax = xmin + bucket_size_x;
+ const float ymax = ymin + bucket_size_y;
+
+ const float cent[2] = {(xmin + xmax) * 0.5f, (ymin + ymax) * 0.5f};
+
+ if (face[3] == TRI_VERT) {
+ const float *v1 = cos[face[0]];
+ const float *v2 = cos[face[1]];
+ const float *v3 = cos[face[2]];
+
+ if (isect_point_tri_v2(cent, v1, v2, v3)) {
+ return true;
+ }
+ else {
+ if ((dist_squared_to_line_segment_v2(cent, v1, v2) < bucket_max_rad_squared) ||
+ (dist_squared_to_line_segment_v2(cent, v2, v3) < bucket_max_rad_squared) ||
+ (dist_squared_to_line_segment_v2(cent, v3, v1) < bucket_max_rad_squared)) {
+ return true;
+ }
+ else {
+ // printf("skip tri\n");
+ return false;
+ }
+ }
+ }
+ else {
+ const float *v1 = cos[face[0]];
+ const float *v2 = cos[face[1]];
+ const float *v3 = cos[face[2]];
+ const float *v4 = cos[face[3]];
+
+ if (isect_point_tri_v2(cent, v1, v2, v3)) {
+ return true;
+ }
+ else if (isect_point_tri_v2(cent, v1, v3, v4)) {
+ return true;
+ }
+ else {
+ if ((dist_squared_to_line_segment_v2(cent, v1, v2) < bucket_max_rad_squared) ||
+ (dist_squared_to_line_segment_v2(cent, v2, v3) < bucket_max_rad_squared) ||
+ (dist_squared_to_line_segment_v2(cent, v3, v4) < bucket_max_rad_squared) ||
+ (dist_squared_to_line_segment_v2(cent, v4, v1) < bucket_max_rad_squared)) {
+ return true;
+ }
+ else {
+ // printf("skip quad\n");
+ return false;
+ }
+ }
+ }
}
static void layer_bucket_init_dummy(MaskRasterLayer *layer)
{
- layer->face_tot = 0;
- layer->face_coords = NULL;
- layer->face_array = NULL;
+ layer->face_tot = 0;
+ layer->face_coords = NULL;
+ layer->face_array = NULL;
- layer->buckets_x = 0;
- layer->buckets_y = 0;
+ layer->buckets_x = 0;
+ layer->buckets_y = 0;
- layer->buckets_xy_scalar[0] = 0.0f;
- layer->buckets_xy_scalar[1] = 0.0f;
+ layer->buckets_xy_scalar[0] = 0.0f;
+ layer->buckets_xy_scalar[1] = 0.0f;
- layer->buckets_face = NULL;
+ layer->buckets_face = NULL;
- BLI_rctf_init(&layer->bounds, -1.0f, -1.0f, -1.0f, -1.0f);
+ BLI_rctf_init(&layer->bounds, -1.0f, -1.0f, -1.0f, -1.0f);
}
static void layer_bucket_init(MaskRasterLayer *layer, const float pixel_size)
{
- MemArena *arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), __func__);
-
- const float bucket_dim_x = BLI_rctf_size_x(&layer->bounds);
- const float bucket_dim_y = BLI_rctf_size_y(&layer->bounds);
-
- layer->buckets_x = (unsigned int)((bucket_dim_x / pixel_size) / (float)BUCKET_PIXELS_PER_CELL);
- layer->buckets_y = (unsigned int)((bucket_dim_y / pixel_size) / (float)BUCKET_PIXELS_PER_CELL);
-
-// printf("bucket size %ux%u\n", layer->buckets_x, layer->buckets_y);
-
- CLAMP(layer->buckets_x, 8, 512);
- CLAMP(layer->buckets_y, 8, 512);
-
- layer->buckets_xy_scalar[0] = (1.0f / (bucket_dim_x + FLT_EPSILON)) * (float)layer->buckets_x;
- layer->buckets_xy_scalar[1] = (1.0f / (bucket_dim_y + FLT_EPSILON)) * (float)layer->buckets_y;
-
- {
- /* width and height of each bucket */
- const float bucket_size_x = (bucket_dim_x + FLT_EPSILON) / (float)layer->buckets_x;
- const float bucket_size_y = (bucket_dim_y + FLT_EPSILON) / (float)layer->buckets_y;
- const float bucket_max_rad = (max_ff(bucket_size_x, bucket_size_y) * (float)M_SQRT2) + FLT_EPSILON;
- const float bucket_max_rad_squared = bucket_max_rad * bucket_max_rad;
-
- unsigned int *face = &layer->face_array[0][0];
- float (*cos)[3] = layer->face_coords;
-
- const unsigned int bucket_tot = layer->buckets_x * layer->buckets_y;
- LinkNode **bucketstore = MEM_callocN(bucket_tot * sizeof(LinkNode *), __func__);
- unsigned int *bucketstore_tot = MEM_callocN(bucket_tot * sizeof(unsigned int), __func__);
-
- unsigned int face_index;
-
- for (face_index = 0; face_index < layer->face_tot; face_index++, face += 4) {
- float xmin;
- float xmax;
- float ymin;
- float ymax;
-
- if (face[3] == TRI_VERT) {
- const float *v1 = cos[face[0]];
- const float *v2 = cos[face[1]];
- const float *v3 = cos[face[2]];
-
- xmin = min_ff(v1[0], min_ff(v2[0], v3[0]));
- xmax = max_ff(v1[0], max_ff(v2[0], v3[0]));
- ymin = min_ff(v1[1], min_ff(v2[1], v3[1]));
- ymax = max_ff(v1[1], max_ff(v2[1], v3[1]));
- }
- else {
- const float *v1 = cos[face[0]];
- const float *v2 = cos[face[1]];
- const float *v3 = cos[face[2]];
- const float *v4 = cos[face[3]];
-
- xmin = min_ff(v1[0], min_ff(v2[0], min_ff(v3[0], v4[0])));
- xmax = max_ff(v1[0], max_ff(v2[0], max_ff(v3[0], v4[0])));
- ymin = min_ff(v1[1], min_ff(v2[1], min_ff(v3[1], v4[1])));
- ymax = max_ff(v1[1], max_ff(v2[1], max_ff(v3[1], v4[1])));
- }
-
-
- /* not essential but may as will skip any faces outside the view */
- if (!((xmax < 0.0f) || (ymax < 0.0f) || (xmin > 1.0f) || (ymin > 1.0f))) {
-
- CLAMP(xmin, 0.0f, 1.0f);
- CLAMP(ymin, 0.0f, 1.0f);
- CLAMP(xmax, 0.0f, 1.0f);
- CLAMP(ymax, 0.0f, 1.0f);
-
- {
- unsigned int xi_min = (unsigned int) ((xmin - layer->bounds.xmin) * layer->buckets_xy_scalar[0]);
- unsigned int xi_max = (unsigned int) ((xmax - layer->bounds.xmin) * layer->buckets_xy_scalar[0]);
- unsigned int yi_min = (unsigned int) ((ymin - layer->bounds.ymin) * layer->buckets_xy_scalar[1]);
- unsigned int yi_max = (unsigned int) ((ymax - layer->bounds.ymin) * layer->buckets_xy_scalar[1]);
- void *face_index_void = POINTER_FROM_UINT(face_index);
-
- unsigned int xi, yi;
-
- /* this should _almost_ never happen but since it can in extreme cases,
- * we have to clamp the values or we overrun the buffer and crash */
- if (xi_min >= layer->buckets_x) xi_min = layer->buckets_x - 1;
- if (xi_max >= layer->buckets_x) xi_max = layer->buckets_x - 1;
- if (yi_min >= layer->buckets_y) yi_min = layer->buckets_y - 1;
- if (yi_max >= layer->buckets_y) yi_max = layer->buckets_y - 1;
-
- for (yi = yi_min; yi <= yi_max; yi++) {
- unsigned int bucket_index = (layer->buckets_x * yi) + xi_min;
- for (xi = xi_min; xi <= xi_max; xi++, bucket_index++) {
- // unsigned int bucket_index = (layer->buckets_x * yi) + xi; /* correct but do in outer loop */
-
- BLI_assert(xi < layer->buckets_x);
- BLI_assert(yi < layer->buckets_y);
- BLI_assert(bucket_index < bucket_tot);
-
- /* check if the bucket intersects with the face */
- /* note: there is a trade off here since checking box/tri intersections isn't
- * as optimal as it could be, but checking pixels against faces they will never intersect
- * with is likely the greater slowdown here - so check if the cell intersects the face */
- if (layer_bucket_isect_test(layer, face_index,
- xi, yi,
- bucket_size_x, bucket_size_y,
- bucket_max_rad_squared))
- {
- BLI_linklist_prepend_arena(&bucketstore[bucket_index], face_index_void, arena);
- bucketstore_tot[bucket_index]++;
- }
- }
- }
- }
- }
- }
-
- if (1) {
- /* now convert linknodes into arrays for faster per pixel access */
- unsigned int **buckets_face = MEM_mallocN(bucket_tot * sizeof(*buckets_face), __func__);
- unsigned int bucket_index;
-
- for (bucket_index = 0; bucket_index < bucket_tot; bucket_index++) {
- if (bucketstore_tot[bucket_index]) {
- unsigned int *bucket = MEM_mallocN((bucketstore_tot[bucket_index] + 1) * sizeof(unsigned int),
- __func__);
- LinkNode *bucket_node;
-
- buckets_face[bucket_index] = bucket;
-
- for (bucket_node = bucketstore[bucket_index]; bucket_node; bucket_node = bucket_node->next) {
- *bucket = POINTER_AS_UINT(bucket_node->link);
- bucket++;
- }
- *bucket = TRI_TERMINATOR_ID;
- }
- else {
- buckets_face[bucket_index] = NULL;
- }
- }
-
- layer->buckets_face = buckets_face;
- }
-
- MEM_freeN(bucketstore);
- MEM_freeN(bucketstore_tot);
- }
-
- BLI_memarena_free(arena);
+ MemArena *arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), __func__);
+
+ const float bucket_dim_x = BLI_rctf_size_x(&layer->bounds);
+ const float bucket_dim_y = BLI_rctf_size_y(&layer->bounds);
+
+ layer->buckets_x = (unsigned int)((bucket_dim_x / pixel_size) / (float)BUCKET_PIXELS_PER_CELL);
+ layer->buckets_y = (unsigned int)((bucket_dim_y / pixel_size) / (float)BUCKET_PIXELS_PER_CELL);
+
+ // printf("bucket size %ux%u\n", layer->buckets_x, layer->buckets_y);
+
+ CLAMP(layer->buckets_x, 8, 512);
+ CLAMP(layer->buckets_y, 8, 512);
+
+ layer->buckets_xy_scalar[0] = (1.0f / (bucket_dim_x + FLT_EPSILON)) * (float)layer->buckets_x;
+ layer->buckets_xy_scalar[1] = (1.0f / (bucket_dim_y + FLT_EPSILON)) * (float)layer->buckets_y;
+
+ {
+ /* width and height of each bucket */
+ const float bucket_size_x = (bucket_dim_x + FLT_EPSILON) / (float)layer->buckets_x;
+ const float bucket_size_y = (bucket_dim_y + FLT_EPSILON) / (float)layer->buckets_y;
+ const float bucket_max_rad = (max_ff(bucket_size_x, bucket_size_y) * (float)M_SQRT2) +
+ FLT_EPSILON;
+ const float bucket_max_rad_squared = bucket_max_rad * bucket_max_rad;
+
+ unsigned int *face = &layer->face_array[0][0];
+ float(*cos)[3] = layer->face_coords;
+
+ const unsigned int bucket_tot = layer->buckets_x * layer->buckets_y;
+ LinkNode **bucketstore = MEM_callocN(bucket_tot * sizeof(LinkNode *), __func__);
+ unsigned int *bucketstore_tot = MEM_callocN(bucket_tot * sizeof(unsigned int), __func__);
+
+ unsigned int face_index;
+
+ for (face_index = 0; face_index < layer->face_tot; face_index++, face += 4) {
+ float xmin;
+ float xmax;
+ float ymin;
+ float ymax;
+
+ if (face[3] == TRI_VERT) {
+ const float *v1 = cos[face[0]];
+ const float *v2 = cos[face[1]];
+ const float *v3 = cos[face[2]];
+
+ xmin = min_ff(v1[0], min_ff(v2[0], v3[0]));
+ xmax = max_ff(v1[0], max_ff(v2[0], v3[0]));
+ ymin = min_ff(v1[1], min_ff(v2[1], v3[1]));
+ ymax = max_ff(v1[1], max_ff(v2[1], v3[1]));
+ }
+ else {
+ const float *v1 = cos[face[0]];
+ const float *v2 = cos[face[1]];
+ const float *v3 = cos[face[2]];
+ const float *v4 = cos[face[3]];
+
+ xmin = min_ff(v1[0], min_ff(v2[0], min_ff(v3[0], v4[0])));
+ xmax = max_ff(v1[0], max_ff(v2[0], max_ff(v3[0], v4[0])));
+ ymin = min_ff(v1[1], min_ff(v2[1], min_ff(v3[1], v4[1])));
+ ymax = max_ff(v1[1], max_ff(v2[1], max_ff(v3[1], v4[1])));
+ }
+
+ /* not essential but may as will skip any faces outside the view */
+ if (!((xmax < 0.0f) || (ymax < 0.0f) || (xmin > 1.0f) || (ymin > 1.0f))) {
+
+ CLAMP(xmin, 0.0f, 1.0f);
+ CLAMP(ymin, 0.0f, 1.0f);
+ CLAMP(xmax, 0.0f, 1.0f);
+ CLAMP(ymax, 0.0f, 1.0f);
+
+ {
+ unsigned int xi_min = (unsigned int)((xmin - layer->bounds.xmin) *
+ layer->buckets_xy_scalar[0]);
+ unsigned int xi_max = (unsigned int)((xmax - layer->bounds.xmin) *
+ layer->buckets_xy_scalar[0]);
+ unsigned int yi_min = (unsigned int)((ymin - layer->bounds.ymin) *
+ layer->buckets_xy_scalar[1]);
+ unsigned int yi_max = (unsigned int)((ymax - layer->bounds.ymin) *
+ layer->buckets_xy_scalar[1]);
+ void *face_index_void = POINTER_FROM_UINT(face_index);
+
+ unsigned int xi, yi;
+
+ /* this should _almost_ never happen but since it can in extreme cases,
+ * we have to clamp the values or we overrun the buffer and crash */
+ if (xi_min >= layer->buckets_x)
+ xi_min = layer->buckets_x - 1;
+ if (xi_max >= layer->buckets_x)
+ xi_max = layer->buckets_x - 1;
+ if (yi_min >= layer->buckets_y)
+ yi_min = layer->buckets_y - 1;
+ if (yi_max >= layer->buckets_y)
+ yi_max = layer->buckets_y - 1;
+
+ for (yi = yi_min; yi <= yi_max; yi++) {
+ unsigned int bucket_index = (layer->buckets_x * yi) + xi_min;
+ for (xi = xi_min; xi <= xi_max; xi++, bucket_index++) {
+ // unsigned int bucket_index = (layer->buckets_x * yi) + xi; /* correct but do in outer loop */
+
+ BLI_assert(xi < layer->buckets_x);
+ BLI_assert(yi < layer->buckets_y);
+ BLI_assert(bucket_index < bucket_tot);
+
+ /* check if the bucket intersects with the face */
+ /* note: there is a trade off here since checking box/tri intersections isn't
+ * as optimal as it could be, but checking pixels against faces they will never intersect
+ * with is likely the greater slowdown here - so check if the cell intersects the face */
+ if (layer_bucket_isect_test(layer,
+ face_index,
+ xi,
+ yi,
+ bucket_size_x,
+ bucket_size_y,
+ bucket_max_rad_squared)) {
+ BLI_linklist_prepend_arena(&bucketstore[bucket_index], face_index_void, arena);
+ bucketstore_tot[bucket_index]++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (1) {
+ /* now convert linknodes into arrays for faster per pixel access */
+ unsigned int **buckets_face = MEM_mallocN(bucket_tot * sizeof(*buckets_face), __func__);
+ unsigned int bucket_index;
+
+ for (bucket_index = 0; bucket_index < bucket_tot; bucket_index++) {
+ if (bucketstore_tot[bucket_index]) {
+ unsigned int *bucket = MEM_mallocN(
+ (bucketstore_tot[bucket_index] + 1) * sizeof(unsigned int), __func__);
+ LinkNode *bucket_node;
+
+ buckets_face[bucket_index] = bucket;
+
+ for (bucket_node = bucketstore[bucket_index]; bucket_node;
+ bucket_node = bucket_node->next) {
+ *bucket = POINTER_AS_UINT(bucket_node->link);
+ bucket++;
+ }
+ *bucket = TRI_TERMINATOR_ID;
+ }
+ else {
+ buckets_face[bucket_index] = NULL;
+ }
+ }
+
+ layer->buckets_face = buckets_face;
+ }
+
+ MEM_freeN(bucketstore);
+ MEM_freeN(bucketstore_tot);
+ }
+
+ BLI_memarena_free(arena);
}
-void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle, struct Mask *mask,
- const int width, const int height,
- const bool do_aspect_correct, const bool do_mask_aa,
+void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle,
+ struct Mask *mask,
+ const int width,
+ const int height,
+ const bool do_aspect_correct,
+ const bool do_mask_aa,
const bool do_feather)
{
- const rctf default_bounds = {0.0f, 1.0f, 0.0f, 1.0f};
- const float pixel_size = 1.0f / (float)min_ii(width, height);
- const float asp_xy[2] = {(do_aspect_correct && width > height) ? (float)height / (float)width : 1.0f,
- (do_aspect_correct && width < height) ? (float)width / (float)height : 1.0f};
+ const rctf default_bounds = {0.0f, 1.0f, 0.0f, 1.0f};
+ const float pixel_size = 1.0f / (float)min_ii(width, height);
+ const float asp_xy[2] = {
+ (do_aspect_correct && width > height) ? (float)height / (float)width : 1.0f,
+ (do_aspect_correct && width < height) ? (float)width / (float)height : 1.0f};
- const float zvec[3] = {0.0f, 0.0f, 1.0f};
- MaskLayer *masklay;
- unsigned int masklay_index;
- MemArena *sf_arena;
+ const float zvec[3] = {0.0f, 0.0f, 1.0f};
+ MaskLayer *masklay;
+ unsigned int masklay_index;
+ MemArena *sf_arena;
- mr_handle->layers_tot = (unsigned int)BLI_listbase_count(&mask->masklayers);
- mr_handle->layers = MEM_mallocN(sizeof(MaskRasterLayer) * mr_handle->layers_tot, "MaskRasterLayer");
- BLI_rctf_init_minmax(&mr_handle->bounds);
+ mr_handle->layers_tot = (unsigned int)BLI_listbase_count(&mask->masklayers);
+ mr_handle->layers = MEM_mallocN(sizeof(MaskRasterLayer) * mr_handle->layers_tot,
+ "MaskRasterLayer");
+ BLI_rctf_init_minmax(&mr_handle->bounds);
- sf_arena = BLI_memarena_new(BLI_SCANFILL_ARENA_SIZE, __func__);
+ sf_arena = BLI_memarena_new(BLI_SCANFILL_ARENA_SIZE, __func__);
- for (masklay = mask->masklayers.first, masklay_index = 0; masklay; masklay = masklay->next, masklay_index++) {
+ for (masklay = mask->masklayers.first, masklay_index = 0; masklay;
+ masklay = masklay->next, masklay_index++) {
- /* we need to store vertex ranges for open splines for filling */
- unsigned int tot_splines;
- MaskRasterSplineInfo *open_spline_ranges;
- unsigned int open_spline_index = 0;
+ /* we need to store vertex ranges for open splines for filling */
+ unsigned int tot_splines;
+ MaskRasterSplineInfo *open_spline_ranges;
+ unsigned int open_spline_index = 0;
- MaskSpline *spline;
+ MaskSpline *spline;
- /* scanfill */
- ScanFillContext sf_ctx;
- ScanFillVert *sf_vert = NULL;
- ScanFillVert *sf_vert_next = NULL;
- ScanFillFace *sf_tri;
+ /* scanfill */
+ ScanFillContext sf_ctx;
+ ScanFillVert *sf_vert = NULL;
+ ScanFillVert *sf_vert_next = NULL;
+ ScanFillFace *sf_tri;
- unsigned int sf_vert_tot = 0;
- unsigned int tot_feather_quads = 0;
+ unsigned int sf_vert_tot = 0;
+ unsigned int tot_feather_quads = 0;
#ifdef USE_SCANFILL_EDGE_WORKAROUND
- unsigned int tot_boundary_used = 0;
- unsigned int tot_boundary_found = 0;
+ unsigned int tot_boundary_used = 0;
+ unsigned int tot_boundary_found = 0;
#endif
- if (masklay->restrictflag & MASK_RESTRICT_RENDER) {
- /* skip the layer */
- mr_handle->layers_tot--;
- masklay_index--;
- continue;
- }
-
- tot_splines = (unsigned int)BLI_listbase_count(&masklay->splines);
- open_spline_ranges = MEM_callocN(sizeof(*open_spline_ranges) * tot_splines, __func__);
-
- BLI_scanfill_begin_arena(&sf_ctx, sf_arena);
-
- for (spline = masklay->splines.first; spline; spline = spline->next) {
- const bool is_cyclic = (spline->flag & MASK_SPLINE_CYCLIC) != 0;
- const bool is_fill = (spline->flag & MASK_SPLINE_NOFILL) == 0;
-
- float (*diff_points)[2];
- unsigned int tot_diff_point;
-
- float (*diff_feather_points)[2];
- float (*diff_feather_points_flip)[2];
- unsigned int tot_diff_feather_points;
-
- const unsigned int resol_a = BKE_mask_spline_resolution(spline, width, height) / 4;
- const unsigned int resol_b = BKE_mask_spline_feather_resolution(spline, width, height) / 4;
- const unsigned int resol = CLAMPIS(MAX2(resol_a, resol_b), 4, 512);
-
- diff_points = BKE_mask_spline_differentiate_with_resolution(
- spline, &tot_diff_point, resol);
-
- if (do_feather) {
- diff_feather_points = BKE_mask_spline_feather_differentiated_points_with_resolution(
- spline, &tot_diff_feather_points, resol, false);
- BLI_assert(diff_feather_points);
- }
- else {
- tot_diff_feather_points = 0;
- diff_feather_points = NULL;
- }
-
- if (tot_diff_point > 3) {
- ScanFillVert *sf_vert_prev;
- unsigned int j;
-
- float co[3];
- co[2] = 0.0f;
-
- sf_ctx.poly_nr++;
-
- if (do_aspect_correct) {
- if (width != height) {
- float *fp;
- float *ffp;
- unsigned int i;
- float asp;
-
- if (width < height) {
- fp = &diff_points[0][0];
- ffp = tot_diff_feather_points ? &diff_feather_points[0][0] : NULL;
- asp = (float)width / (float)height;
- }
- else {
- fp = &diff_points[0][1];
- ffp = tot_diff_feather_points ? &diff_feather_points[0][1] : NULL;
- asp = (float)height / (float)width;
- }
-
- for (i = 0; i < tot_diff_point; i++, fp += 2) {
- (*fp) = (((*fp) - 0.5f) / asp) + 0.5f;
- }
-
- if (tot_diff_feather_points) {
- for (i = 0; i < tot_diff_feather_points; i++, ffp += 2) {
- (*ffp) = (((*ffp) - 0.5f) / asp) + 0.5f;
- }
- }
- }
- }
-
- /* fake aa, using small feather */
- if (do_mask_aa == true) {
- if (do_feather == false) {
- tot_diff_feather_points = tot_diff_point;
- diff_feather_points = MEM_mallocN(sizeof(*diff_feather_points) *
- (size_t)tot_diff_feather_points,
- __func__);
- /* add single pixel feather */
- maskrasterize_spline_differentiate_point_outset(diff_feather_points, diff_points,
- tot_diff_point, pixel_size, false);
- }
- else {
- /* ensure single pixel feather, on any zero feather areas */
- maskrasterize_spline_differentiate_point_outset(diff_feather_points, diff_points,
- tot_diff_point, pixel_size, true);
- }
- }
-
- if (is_fill) {
- /* applt intersections depending on fill settings */
- if (spline->flag & MASK_SPLINE_NOINTERSECT) {
- BKE_mask_spline_feather_collapse_inner_loops(spline, diff_feather_points, tot_diff_feather_points);
- }
-
- copy_v2_v2(co, diff_points[0]);
- sf_vert_prev = BLI_scanfill_vert_add(&sf_ctx, co);
- sf_vert_prev->tmp.u = sf_vert_tot;
- sf_vert_prev->keyindex = sf_vert_tot + tot_diff_point; /* absolute index of feather vert */
- sf_vert_tot++;
-
- /* TODO, an alternate functions so we can avoid double vector copy! */
- for (j = 1; j < tot_diff_point; j++) {
- copy_v2_v2(co, diff_points[j]);
- sf_vert = BLI_scanfill_vert_add(&sf_ctx, co);
- sf_vert->tmp.u = sf_vert_tot;
- sf_vert->keyindex = sf_vert_tot + tot_diff_point; /* absolute index of feather vert */
- sf_vert_tot++;
- }
-
- sf_vert = sf_vert_prev;
- sf_vert_prev = sf_ctx.fillvertbase.last;
-
- for (j = 0; j < tot_diff_point; j++) {
- ScanFillEdge *sf_edge = BLI_scanfill_edge_add(&sf_ctx, sf_vert_prev, sf_vert);
+ if (masklay->restrictflag & MASK_RESTRICT_RENDER) {
+ /* skip the layer */
+ mr_handle->layers_tot--;
+ masklay_index--;
+ continue;
+ }
+
+ tot_splines = (unsigned int)BLI_listbase_count(&masklay->splines);
+ open_spline_ranges = MEM_callocN(sizeof(*open_spline_ranges) * tot_splines, __func__);
+
+ BLI_scanfill_begin_arena(&sf_ctx, sf_arena);
+
+ for (spline = masklay->splines.first; spline; spline = spline->next) {
+ const bool is_cyclic = (spline->flag & MASK_SPLINE_CYCLIC) != 0;
+ const bool is_fill = (spline->flag & MASK_SPLINE_NOFILL) == 0;
+
+ float(*diff_points)[2];
+ unsigned int tot_diff_point;
+
+ float(*diff_feather_points)[2];
+ float(*diff_feather_points_flip)[2];
+ unsigned int tot_diff_feather_points;
+
+ const unsigned int resol_a = BKE_mask_spline_resolution(spline, width, height) / 4;
+ const unsigned int resol_b = BKE_mask_spline_feather_resolution(spline, width, height) / 4;
+ const unsigned int resol = CLAMPIS(MAX2(resol_a, resol_b), 4, 512);
+
+ diff_points = BKE_mask_spline_differentiate_with_resolution(spline, &tot_diff_point, resol);
+
+ if (do_feather) {
+ diff_feather_points = BKE_mask_spline_feather_differentiated_points_with_resolution(
+ spline, &tot_diff_feather_points, resol, false);
+ BLI_assert(diff_feather_points);
+ }
+ else {
+ tot_diff_feather_points = 0;
+ diff_feather_points = NULL;
+ }
+
+ if (tot_diff_point > 3) {
+ ScanFillVert *sf_vert_prev;
+ unsigned int j;
+
+ float co[3];
+ co[2] = 0.0f;
+
+ sf_ctx.poly_nr++;
+
+ if (do_aspect_correct) {
+ if (width != height) {
+ float *fp;
+ float *ffp;
+ unsigned int i;
+ float asp;
+
+ if (width < height) {
+ fp = &diff_points[0][0];
+ ffp = tot_diff_feather_points ? &diff_feather_points[0][0] : NULL;
+ asp = (float)width / (float)height;
+ }
+ else {
+ fp = &diff_points[0][1];
+ ffp = tot_diff_feather_points ? &diff_feather_points[0][1] : NULL;
+ asp = (float)height / (float)width;
+ }
+
+ for (i = 0; i < tot_diff_point; i++, fp += 2) {
+ (*fp) = (((*fp) - 0.5f) / asp) + 0.5f;
+ }
+
+ if (tot_diff_feather_points) {
+ for (i = 0; i < tot_diff_feather_points; i++, ffp += 2) {
+ (*ffp) = (((*ffp) - 0.5f) / asp) + 0.5f;
+ }
+ }
+ }
+ }
+
+ /* fake aa, using small feather */
+ if (do_mask_aa == true) {
+ if (do_feather == false) {
+ tot_diff_feather_points = tot_diff_point;
+ diff_feather_points = MEM_mallocN(
+ sizeof(*diff_feather_points) * (size_t)tot_diff_feather_points, __func__);
+ /* add single pixel feather */
+ maskrasterize_spline_differentiate_point_outset(
+ diff_feather_points, diff_points, tot_diff_point, pixel_size, false);
+ }
+ else {
+ /* ensure single pixel feather, on any zero feather areas */
+ maskrasterize_spline_differentiate_point_outset(
+ diff_feather_points, diff_points, tot_diff_point, pixel_size, true);
+ }
+ }
+
+ if (is_fill) {
+ /* applt intersections depending on fill settings */
+ if (spline->flag & MASK_SPLINE_NOINTERSECT) {
+ BKE_mask_spline_feather_collapse_inner_loops(
+ spline, diff_feather_points, tot_diff_feather_points);
+ }
+
+ copy_v2_v2(co, diff_points[0]);
+ sf_vert_prev = BLI_scanfill_vert_add(&sf_ctx, co);
+ sf_vert_prev->tmp.u = sf_vert_tot;
+ sf_vert_prev->keyindex = sf_vert_tot +
+ tot_diff_point; /* absolute index of feather vert */
+ sf_vert_tot++;
+
+ /* TODO, an alternate functions so we can avoid double vector copy! */
+ for (j = 1; j < tot_diff_point; j++) {
+ copy_v2_v2(co, diff_points[j]);
+ sf_vert = BLI_scanfill_vert_add(&sf_ctx, co);
+ sf_vert->tmp.u = sf_vert_tot;
+ sf_vert->keyindex = sf_vert_tot + tot_diff_point; /* absolute index of feather vert */
+ sf_vert_tot++;
+ }
+
+ sf_vert = sf_vert_prev;
+ sf_vert_prev = sf_ctx.fillvertbase.last;
+
+ for (j = 0; j < tot_diff_point; j++) {
+ ScanFillEdge *sf_edge = BLI_scanfill_edge_add(&sf_ctx, sf_vert_prev, sf_vert);
#ifdef USE_SCANFILL_EDGE_WORKAROUND
- if (diff_feather_points) {
- sf_edge->tmp.c = SF_EDGE_IS_BOUNDARY;
- tot_boundary_used++;
- }
+ if (diff_feather_points) {
+ sf_edge->tmp.c = SF_EDGE_IS_BOUNDARY;
+ tot_boundary_used++;
+ }
#else
- (void)sf_edge;
+ (void)sf_edge;
#endif
- sf_vert_prev = sf_vert;
- sf_vert = sf_vert->next;
- }
-
- if (diff_feather_points) {
- float co_feather[3];
- co_feather[2] = 1.0f;
-
- BLI_assert(tot_diff_feather_points == tot_diff_point);
-
- /* note: only added for convenience, we don't infact use these to scanfill,
- * only to create feather faces after scanfill */
- for (j = 0; j < tot_diff_feather_points; j++) {
- copy_v2_v2(co_feather, diff_feather_points[j]);
- sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);
- sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
- sf_vert_tot++;
- }
-
- tot_feather_quads += tot_diff_point;
- }
- }
- else {
- /* unfilled spline */
- if (diff_feather_points) {
-
- float co_diff[2];
-
- float co_feather[3];
- co_feather[2] = 1.0f;
-
- if (spline->flag & MASK_SPLINE_NOINTERSECT) {
- diff_feather_points_flip = MEM_mallocN(sizeof(float) * 2 * tot_diff_feather_points, "diff_feather_points_flip");
-
- for (j = 0; j < tot_diff_point; j++) {
- sub_v2_v2v2(co_diff, diff_points[j], diff_feather_points[j]);
- add_v2_v2v2(diff_feather_points_flip[j], diff_points[j], co_diff);
- }
-
- BKE_mask_spline_feather_collapse_inner_loops(spline, diff_feather_points, tot_diff_feather_points);
- BKE_mask_spline_feather_collapse_inner_loops(spline, diff_feather_points_flip, tot_diff_feather_points);
- }
- else {
- diff_feather_points_flip = NULL;
- }
-
-
- open_spline_ranges[open_spline_index].vertex_offset = sf_vert_tot;
- open_spline_ranges[open_spline_index].vertex_total = tot_diff_point;
-
- /* TODO, an alternate functions so we can avoid double vector copy! */
- for (j = 0; j < tot_diff_point; j++) {
-
- /* center vert */
- copy_v2_v2(co, diff_points[j]);
- sf_vert = BLI_scanfill_vert_add(&sf_ctx, co);
- sf_vert->tmp.u = sf_vert_tot;
- sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
- sf_vert_tot++;
-
-
- /* feather vert A */
- copy_v2_v2(co_feather, diff_feather_points[j]);
- sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);
- sf_vert->tmp.u = sf_vert_tot;
- sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
- sf_vert_tot++;
-
-
- /* feather vert B */
- if (diff_feather_points_flip) {
- copy_v2_v2(co_feather, diff_feather_points_flip[j]);
- }
- else {
- sub_v2_v2v2(co_diff, co, co_feather);
- add_v2_v2v2(co_feather, co, co_diff);
- }
-
- sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);
- sf_vert->tmp.u = sf_vert_tot;
- sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
- sf_vert_tot++;
-
- tot_feather_quads += 2;
- }
-
- if (!is_cyclic) {
- tot_feather_quads -= 2;
- }
-
- if (diff_feather_points_flip) {
- MEM_freeN(diff_feather_points_flip);
- diff_feather_points_flip = NULL;
- }
-
- /* cap ends */
-
- /* dummy init value */
- open_spline_ranges[open_spline_index].vertex_total_cap_head = 0;
- open_spline_ranges[open_spline_index].vertex_total_cap_tail = 0;
-
- if (!is_cyclic) {
- const float *fp_cent;
- const float *fp_turn;
-
- unsigned int k;
-
- fp_cent = diff_points[0];
- fp_turn = diff_feather_points[0];
-
-#define CALC_CAP_RESOL \
- clampis_uint((unsigned int )(len_v2v2(fp_cent, fp_turn) / \
- (pixel_size * SPLINE_RESOL_CAP_PER_PIXEL)), \
- SPLINE_RESOL_CAP_MIN, SPLINE_RESOL_CAP_MAX)
-
- {
- const unsigned int vertex_total_cap = CALC_CAP_RESOL;
-
- for (k = 1; k < vertex_total_cap; k++) {
- const float angle = (float)k * (1.0f / (float)vertex_total_cap) * (float)M_PI;
- rotate_point_v2(co_feather, fp_turn, fp_cent, angle, asp_xy);
-
- sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);
- sf_vert->tmp.u = sf_vert_tot;
- sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
- sf_vert_tot++;
- }
- tot_feather_quads += vertex_total_cap;
-
- open_spline_ranges[open_spline_index].vertex_total_cap_head = vertex_total_cap;
- }
-
- fp_cent = diff_points[tot_diff_point - 1];
- fp_turn = diff_feather_points[tot_diff_point - 1];
-
- {
- const unsigned int vertex_total_cap = CALC_CAP_RESOL;
-
- for (k = 1; k < vertex_total_cap; k++) {
- const float angle = (float)k * (1.0f / (float)vertex_total_cap) * (float)M_PI;
- rotate_point_v2(co_feather, fp_turn, fp_cent, -angle, asp_xy);
-
- sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);
- sf_vert->tmp.u = sf_vert_tot;
- sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
- sf_vert_tot++;
- }
- tot_feather_quads += vertex_total_cap;
-
- open_spline_ranges[open_spline_index].vertex_total_cap_tail = vertex_total_cap;
- }
- }
-
- open_spline_ranges[open_spline_index].is_cyclic = is_cyclic;
- open_spline_index++;
+ sf_vert_prev = sf_vert;
+ sf_vert = sf_vert->next;
+ }
+
+ if (diff_feather_points) {
+ float co_feather[3];
+ co_feather[2] = 1.0f;
+
+ BLI_assert(tot_diff_feather_points == tot_diff_point);
+
+ /* note: only added for convenience, we don't infact use these to scanfill,
+ * only to create feather faces after scanfill */
+ for (j = 0; j < tot_diff_feather_points; j++) {
+ copy_v2_v2(co_feather, diff_feather_points[j]);
+ sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);
+ sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
+ sf_vert_tot++;
+ }
+
+ tot_feather_quads += tot_diff_point;
+ }
+ }
+ else {
+ /* unfilled spline */
+ if (diff_feather_points) {
+
+ float co_diff[2];
+
+ float co_feather[3];
+ co_feather[2] = 1.0f;
+
+ if (spline->flag & MASK_SPLINE_NOINTERSECT) {
+ diff_feather_points_flip = MEM_mallocN(sizeof(float) * 2 * tot_diff_feather_points,
+ "diff_feather_points_flip");
+
+ for (j = 0; j < tot_diff_point; j++) {
+ sub_v2_v2v2(co_diff, diff_points[j], diff_feather_points[j]);
+ add_v2_v2v2(diff_feather_points_flip[j], diff_points[j], co_diff);
+ }
+
+ BKE_mask_spline_feather_collapse_inner_loops(
+ spline, diff_feather_points, tot_diff_feather_points);
+ BKE_mask_spline_feather_collapse_inner_loops(
+ spline, diff_feather_points_flip, tot_diff_feather_points);
+ }
+ else {
+ diff_feather_points_flip = NULL;
+ }
+
+ open_spline_ranges[open_spline_index].vertex_offset = sf_vert_tot;
+ open_spline_ranges[open_spline_index].vertex_total = tot_diff_point;
+
+ /* TODO, an alternate functions so we can avoid double vector copy! */
+ for (j = 0; j < tot_diff_point; j++) {
+
+ /* center vert */
+ copy_v2_v2(co, diff_points[j]);
+ sf_vert = BLI_scanfill_vert_add(&sf_ctx, co);
+ sf_vert->tmp.u = sf_vert_tot;
+ sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
+ sf_vert_tot++;
+
+ /* feather vert A */
+ copy_v2_v2(co_feather, diff_feather_points[j]);
+ sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);
+ sf_vert->tmp.u = sf_vert_tot;
+ sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
+ sf_vert_tot++;
+
+ /* feather vert B */
+ if (diff_feather_points_flip) {
+ copy_v2_v2(co_feather, diff_feather_points_flip[j]);
+ }
+ else {
+ sub_v2_v2v2(co_diff, co, co_feather);
+ add_v2_v2v2(co_feather, co, co_diff);
+ }
+
+ sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);
+ sf_vert->tmp.u = sf_vert_tot;
+ sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
+ sf_vert_tot++;
+
+ tot_feather_quads += 2;
+ }
+
+ if (!is_cyclic) {
+ tot_feather_quads -= 2;
+ }
+
+ if (diff_feather_points_flip) {
+ MEM_freeN(diff_feather_points_flip);
+ diff_feather_points_flip = NULL;
+ }
+
+ /* cap ends */
+
+ /* dummy init value */
+ open_spline_ranges[open_spline_index].vertex_total_cap_head = 0;
+ open_spline_ranges[open_spline_index].vertex_total_cap_tail = 0;
+
+ if (!is_cyclic) {
+ const float *fp_cent;
+ const float *fp_turn;
+
+ unsigned int k;
+
+ fp_cent = diff_points[0];
+ fp_turn = diff_feather_points[0];
+
+#define CALC_CAP_RESOL \
+ clampis_uint( \
+ (unsigned int)(len_v2v2(fp_cent, fp_turn) / (pixel_size * SPLINE_RESOL_CAP_PER_PIXEL)), \
+ SPLINE_RESOL_CAP_MIN, \
+ SPLINE_RESOL_CAP_MAX)
+
+ {
+ const unsigned int vertex_total_cap = CALC_CAP_RESOL;
+
+ for (k = 1; k < vertex_total_cap; k++) {
+ const float angle = (float)k * (1.0f / (float)vertex_total_cap) * (float)M_PI;
+ rotate_point_v2(co_feather, fp_turn, fp_cent, angle, asp_xy);
+
+ sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);
+ sf_vert->tmp.u = sf_vert_tot;
+ sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
+ sf_vert_tot++;
+ }
+ tot_feather_quads += vertex_total_cap;
+
+ open_spline_ranges[open_spline_index].vertex_total_cap_head = vertex_total_cap;
+ }
+
+ fp_cent = diff_points[tot_diff_point - 1];
+ fp_turn = diff_feather_points[tot_diff_point - 1];
+
+ {
+ const unsigned int vertex_total_cap = CALC_CAP_RESOL;
+
+ for (k = 1; k < vertex_total_cap; k++) {
+ const float angle = (float)k * (1.0f / (float)vertex_total_cap) * (float)M_PI;
+ rotate_point_v2(co_feather, fp_turn, fp_cent, -angle, asp_xy);
+
+ sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);
+ sf_vert->tmp.u = sf_vert_tot;
+ sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
+ sf_vert_tot++;
+ }
+ tot_feather_quads += vertex_total_cap;
+
+ open_spline_ranges[open_spline_index].vertex_total_cap_tail = vertex_total_cap;
+ }
+ }
+
+ open_spline_ranges[open_spline_index].is_cyclic = is_cyclic;
+ open_spline_index++;
#undef CALC_CAP_RESOL
- /* end capping */
-
- }
- }
- }
-
- if (diff_points) {
- MEM_freeN(diff_points);
- }
-
- if (diff_feather_points) {
- MEM_freeN(diff_feather_points);
- }
- }
-
- {
- unsigned int (*face_array)[4], *face; /* access coords */
- float (*face_coords)[3], *cos; /* xy, z 0-1 (1.0 == filled) */
- unsigned int sf_tri_tot;
- rctf bounds;
- unsigned int face_index;
- int scanfill_flag = 0;
-
- bool is_isect = false;
- ListBase isect_remvertbase = {NULL, NULL};
- ListBase isect_remedgebase = {NULL, NULL};
-
- /* now we have all the splines */
- face_coords = MEM_mallocN((sizeof(float) * 3) * sf_vert_tot, "maskrast_face_coords");
-
- /* init bounds */
- BLI_rctf_init_minmax(&bounds);
-
- /* coords */
- cos = (float *)face_coords;
- for (sf_vert = sf_ctx.fillvertbase.first; sf_vert; sf_vert = sf_vert_next) {
- sf_vert_next = sf_vert->next;
- copy_v3_v3(cos, sf_vert->co);
-
- /* remove so as not to interfere with fill (called after) */
- if (sf_vert->keyindex == SF_KEYINDEX_TEMP_ID) {
- BLI_remlink(&sf_ctx.fillvertbase, sf_vert);
- }
-
- /* bounds */
- BLI_rctf_do_minmax_v(&bounds, cos);
-
- cos += 3;
- }
-
-
- /* --- inefficient self-intersect case --- */
- /* if self intersections are found, its too trickty to attempt to map vertices
- * so just realloc and add entirely new vertices - the result of the self-intersect check
- */
- if ((masklay->flag & MASK_LAYERFLAG_FILL_OVERLAP) &&
- (is_isect = BLI_scanfill_calc_self_isect(&sf_ctx,
- &isect_remvertbase,
- &isect_remedgebase)))
- {
- unsigned int sf_vert_tot_isect = (unsigned int)BLI_listbase_count(&sf_ctx.fillvertbase);
- unsigned int i = sf_vert_tot;
-
- face_coords = MEM_reallocN(face_coords, sizeof(float[3]) * (sf_vert_tot + sf_vert_tot_isect));
-
- cos = (float *)&face_coords[sf_vert_tot][0];
-
- for (sf_vert = sf_ctx.fillvertbase.first; sf_vert; sf_vert = sf_vert->next) {
- copy_v3_v3(cos, sf_vert->co);
- sf_vert->tmp.u = i++;
- cos += 3;
- }
-
- sf_vert_tot += sf_vert_tot_isect;
-
- /* we need to calc polys after self intersect */
- scanfill_flag |= BLI_SCANFILL_CALC_POLYS;
- }
- /* --- end inefficient code --- */
-
-
- /* main scan-fill */
- if ((masklay->flag & MASK_LAYERFLAG_FILL_DISCRETE) == 0)
- scanfill_flag |= BLI_SCANFILL_CALC_HOLES;
-
- sf_tri_tot = (unsigned int)BLI_scanfill_calc_ex(&sf_ctx, scanfill_flag, zvec);
-
- if (is_isect) {
- /* add removed data back, we only need edges for feather,
- * but add verts back so they get freed along with others */
- BLI_movelisttolist(&sf_ctx.fillvertbase, &isect_remvertbase);
- BLI_movelisttolist(&sf_ctx.filledgebase, &isect_remedgebase);
- }
-
- face_array = MEM_mallocN(sizeof(*face_array) * ((size_t)sf_tri_tot + (size_t)tot_feather_quads), "maskrast_face_index");
- face_index = 0;
-
- /* faces */
- face = (unsigned int *)face_array;
- for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) {
- *(face++) = sf_tri->v3->tmp.u;
- *(face++) = sf_tri->v2->tmp.u;
- *(face++) = sf_tri->v1->tmp.u;
- *(face++) = TRI_VERT;
- face_index++;
- FACE_ASSERT(face - 4, sf_vert_tot);
- }
-
- /* start of feather faces... if we have this set,
- * 'face_index' is kept from loop above */
-
- BLI_assert(face_index == sf_tri_tot);
-
- if (tot_feather_quads) {
- ScanFillEdge *sf_edge;
-
- for (sf_edge = sf_ctx.filledgebase.first; sf_edge; sf_edge = sf_edge->next) {
- if (sf_edge->tmp.c == SF_EDGE_IS_BOUNDARY) {
- *(face++) = sf_edge->v1->tmp.u;
- *(face++) = sf_edge->v2->tmp.u;
- *(face++) = sf_edge->v2->keyindex;
- *(face++) = sf_edge->v1->keyindex;
- face_index++;
- FACE_ASSERT(face - 4, sf_vert_tot);
+ /* end capping */
+ }
+ }
+ }
+
+ if (diff_points) {
+ MEM_freeN(diff_points);
+ }
+
+ if (diff_feather_points) {
+ MEM_freeN(diff_feather_points);
+ }
+ }
+
+ {
+ unsigned int(*face_array)[4], *face; /* access coords */
+ float(*face_coords)[3], *cos; /* xy, z 0-1 (1.0 == filled) */
+ unsigned int sf_tri_tot;
+ rctf bounds;
+ unsigned int face_index;
+ int scanfill_flag = 0;
+
+ bool is_isect = false;
+ ListBase isect_remvertbase = {NULL, NULL};
+ ListBase isect_remedgebase = {NULL, NULL};
+
+ /* now we have all the splines */
+ face_coords = MEM_mallocN((sizeof(float) * 3) * sf_vert_tot, "maskrast_face_coords");
+
+ /* init bounds */
+ BLI_rctf_init_minmax(&bounds);
+
+ /* coords */
+ cos = (float *)face_coords;
+ for (sf_vert = sf_ctx.fillvertbase.first; sf_vert; sf_vert = sf_vert_next) {
+ sf_vert_next = sf_vert->next;
+ copy_v3_v3(cos, sf_vert->co);
+
+ /* remove so as not to interfere with fill (called after) */
+ if (sf_vert->keyindex == SF_KEYINDEX_TEMP_ID) {
+ BLI_remlink(&sf_ctx.fillvertbase, sf_vert);
+ }
+
+ /* bounds */
+ BLI_rctf_do_minmax_v(&bounds, cos);
+
+ cos += 3;
+ }
+
+ /* --- inefficient self-intersect case --- */
+ /* if self intersections are found, its too trickty to attempt to map vertices
+ * so just realloc and add entirely new vertices - the result of the self-intersect check
+ */
+ if ((masklay->flag & MASK_LAYERFLAG_FILL_OVERLAP) &&
+ (is_isect = BLI_scanfill_calc_self_isect(
+ &sf_ctx, &isect_remvertbase, &isect_remedgebase))) {
+ unsigned int sf_vert_tot_isect = (unsigned int)BLI_listbase_count(&sf_ctx.fillvertbase);
+ unsigned int i = sf_vert_tot;
+
+ face_coords = MEM_reallocN(face_coords,
+ sizeof(float[3]) * (sf_vert_tot + sf_vert_tot_isect));
+
+ cos = (float *)&face_coords[sf_vert_tot][0];
+
+ for (sf_vert = sf_ctx.fillvertbase.first; sf_vert; sf_vert = sf_vert->next) {
+ copy_v3_v3(cos, sf_vert->co);
+ sf_vert->tmp.u = i++;
+ cos += 3;
+ }
+
+ sf_vert_tot += sf_vert_tot_isect;
+
+ /* we need to calc polys after self intersect */
+ scanfill_flag |= BLI_SCANFILL_CALC_POLYS;
+ }
+ /* --- end inefficient code --- */
+
+ /* main scan-fill */
+ if ((masklay->flag & MASK_LAYERFLAG_FILL_DISCRETE) == 0)
+ scanfill_flag |= BLI_SCANFILL_CALC_HOLES;
+
+ sf_tri_tot = (unsigned int)BLI_scanfill_calc_ex(&sf_ctx, scanfill_flag, zvec);
+
+ if (is_isect) {
+ /* add removed data back, we only need edges for feather,
+ * but add verts back so they get freed along with others */
+ BLI_movelisttolist(&sf_ctx.fillvertbase, &isect_remvertbase);
+ BLI_movelisttolist(&sf_ctx.filledgebase, &isect_remedgebase);
+ }
+
+ face_array = MEM_mallocN(sizeof(*face_array) *
+ ((size_t)sf_tri_tot + (size_t)tot_feather_quads),
+ "maskrast_face_index");
+ face_index = 0;
+
+ /* faces */
+ face = (unsigned int *)face_array;
+ for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) {
+ *(face++) = sf_tri->v3->tmp.u;
+ *(face++) = sf_tri->v2->tmp.u;
+ *(face++) = sf_tri->v1->tmp.u;
+ *(face++) = TRI_VERT;
+ face_index++;
+ FACE_ASSERT(face - 4, sf_vert_tot);
+ }
+
+ /* start of feather faces... if we have this set,
+ * 'face_index' is kept from loop above */
+
+ BLI_assert(face_index == sf_tri_tot);
+
+ if (tot_feather_quads) {
+ ScanFillEdge *sf_edge;
+
+ for (sf_edge = sf_ctx.filledgebase.first; sf_edge; sf_edge = sf_edge->next) {
+ if (sf_edge->tmp.c == SF_EDGE_IS_BOUNDARY) {
+ *(face++) = sf_edge->v1->tmp.u;
+ *(face++) = sf_edge->v2->tmp.u;
+ *(face++) = sf_edge->v2->keyindex;
+ *(face++) = sf_edge->v1->keyindex;
+ face_index++;
+ FACE_ASSERT(face - 4, sf_vert_tot);
#ifdef USE_SCANFILL_EDGE_WORKAROUND
- tot_boundary_found++;
+ tot_boundary_found++;
#endif
- }
- }
- }
+ }
+ }
+ }
#ifdef USE_SCANFILL_EDGE_WORKAROUND
- if (tot_boundary_found != tot_boundary_used) {
- BLI_assert(tot_boundary_found < tot_boundary_used);
- }
+ if (tot_boundary_found != tot_boundary_used) {
+ BLI_assert(tot_boundary_found < tot_boundary_used);
+ }
#endif
- /* feather only splines */
- while (open_spline_index > 0) {
- const unsigned int vertex_offset = open_spline_ranges[--open_spline_index].vertex_offset;
- unsigned int vertex_total = open_spline_ranges[ open_spline_index].vertex_total;
- unsigned int vertex_total_cap_head = open_spline_ranges[ open_spline_index].vertex_total_cap_head;
- unsigned int vertex_total_cap_tail = open_spline_ranges[ open_spline_index].vertex_total_cap_tail;
- unsigned int k, j;
-
- j = vertex_offset;
-
- /* subtract one since we reference next vertex triple */
- for (k = 0; k < vertex_total - 1; k++, j += 3) {
-
- BLI_assert(j == vertex_offset + (k * 3));
-
- *(face++) = j + 3; /* next span */ /* z 1 */
- *(face++) = j + 0; /* z 1 */
- *(face++) = j + 1; /* z 0 */
- *(face++) = j + 4; /* next span */ /* z 0 */
- face_index++;
- FACE_ASSERT(face - 4, sf_vert_tot);
-
- *(face++) = j + 0; /* z 1 */
- *(face++) = j + 3; /* next span */ /* z 1 */
- *(face++) = j + 5; /* next span */ /* z 0 */
- *(face++) = j + 2; /* z 0 */
- face_index++;
- FACE_ASSERT(face - 4, sf_vert_tot);
- }
-
- if (open_spline_ranges[open_spline_index].is_cyclic) {
- *(face++) = vertex_offset + 0; /* next span */ /* z 1 */
- *(face++) = j + 0; /* z 1 */
- *(face++) = j + 1; /* z 0 */
- *(face++) = vertex_offset + 1; /* next span */ /* z 0 */
- face_index++;
- FACE_ASSERT(face - 4, sf_vert_tot);
-
- *(face++) = j + 0; /* z 1 */
- *(face++) = vertex_offset + 0; /* next span */ /* z 1 */
- *(face++) = vertex_offset + 2; /* next span */ /* z 0 */
- *(face++) = j + 2; /* z 0 */
- face_index++;
- FACE_ASSERT(face - 4, sf_vert_tot);
- }
- else {
- unsigned int midvidx = vertex_offset;
-
- /***************
- * cap end 'a' */
- j = midvidx + (vertex_total * 3);
-
- for (k = 0; k < vertex_total_cap_head - 2; k++, j++) {
- *(face++) = midvidx + 0; /* z 1 */
- *(face++) = midvidx + 0; /* z 1 */
- *(face++) = j + 0; /* z 0 */
- *(face++) = j + 1; /* z 0 */
- face_index++;
- FACE_ASSERT(face - 4, sf_vert_tot);
- }
-
- j = vertex_offset + (vertex_total * 3);
-
- /* 2 tris that join the original */
- *(face++) = midvidx + 0; /* z 1 */
- *(face++) = midvidx + 0; /* z 1 */
- *(face++) = midvidx + 1; /* z 0 */
- *(face++) = j + 0; /* z 0 */
- face_index++;
- FACE_ASSERT(face - 4, sf_vert_tot);
-
- *(face++) = midvidx + 0; /* z 1 */
- *(face++) = midvidx + 0; /* z 1 */
- *(face++) = j + vertex_total_cap_head - 2; /* z 0 */
- *(face++) = midvidx + 2; /* z 0 */
- face_index++;
- FACE_ASSERT(face - 4, sf_vert_tot);
-
-
- /***************
- * cap end 'b' */
- /* ... same as previous but v 2-3 flipped, and different initial offsets */
-
- j = vertex_offset + (vertex_total * 3) + (vertex_total_cap_head - 1);
-
- midvidx = vertex_offset + (vertex_total * 3) - 3;
-
- for (k = 0; k < vertex_total_cap_tail - 2; k++, j++) {
- *(face++) = midvidx; /* z 1 */
- *(face++) = midvidx; /* z 1 */
- *(face++) = j + 1; /* z 0 */
- *(face++) = j + 0; /* z 0 */
- face_index++;
- FACE_ASSERT(face - 4, sf_vert_tot);
- }
-
- j = vertex_offset + (vertex_total * 3) + (vertex_total_cap_head - 1);
-
- /* 2 tris that join the original */
- *(face++) = midvidx + 0; /* z 1 */
- *(face++) = midvidx + 0; /* z 1 */
- *(face++) = j + 0; /* z 0 */
- *(face++) = midvidx + 1; /* z 0 */
- face_index++;
- FACE_ASSERT(face - 4, sf_vert_tot);
-
- *(face++) = midvidx + 0; /* z 1 */
- *(face++) = midvidx + 0; /* z 1 */
- *(face++) = midvidx + 2; /* z 0 */
- *(face++) = j + vertex_total_cap_tail - 2; /* z 0 */
- face_index++;
- FACE_ASSERT(face - 4, sf_vert_tot);
-
- }
- }
-
- MEM_freeN(open_spline_ranges);
-
-// fprintf(stderr, "%u %u (%u %u), %u\n", face_index, sf_tri_tot + tot_feather_quads, sf_tri_tot, tot_feather_quads, tot_boundary_used - tot_boundary_found);
+ /* feather only splines */
+ while (open_spline_index > 0) {
+ const unsigned int vertex_offset = open_spline_ranges[--open_spline_index].vertex_offset;
+ unsigned int vertex_total = open_spline_ranges[open_spline_index].vertex_total;
+ unsigned int vertex_total_cap_head =
+ open_spline_ranges[open_spline_index].vertex_total_cap_head;
+ unsigned int vertex_total_cap_tail =
+ open_spline_ranges[open_spline_index].vertex_total_cap_tail;
+ unsigned int k, j;
+
+ j = vertex_offset;
+
+ /* subtract one since we reference next vertex triple */
+ for (k = 0; k < vertex_total - 1; k++, j += 3) {
+
+ BLI_assert(j == vertex_offset + (k * 3));
+
+ *(face++) = j + 3; /* next span */ /* z 1 */
+ *(face++) = j + 0; /* z 1 */
+ *(face++) = j + 1; /* z 0 */
+ *(face++) = j + 4; /* next span */ /* z 0 */
+ face_index++;
+ FACE_ASSERT(face - 4, sf_vert_tot);
+
+ *(face++) = j + 0; /* z 1 */
+ *(face++) = j + 3; /* next span */ /* z 1 */
+ *(face++) = j + 5; /* next span */ /* z 0 */
+ *(face++) = j + 2; /* z 0 */
+ face_index++;
+ FACE_ASSERT(face - 4, sf_vert_tot);
+ }
+
+ if (open_spline_ranges[open_spline_index].is_cyclic) {
+ *(face++) = vertex_offset + 0; /* next span */ /* z 1 */
+ *(face++) = j + 0; /* z 1 */
+ *(face++) = j + 1; /* z 0 */
+ *(face++) = vertex_offset + 1; /* next span */ /* z 0 */
+ face_index++;
+ FACE_ASSERT(face - 4, sf_vert_tot);
+
+ *(face++) = j + 0; /* z 1 */
+ *(face++) = vertex_offset + 0; /* next span */ /* z 1 */
+ *(face++) = vertex_offset + 2; /* next span */ /* z 0 */
+ *(face++) = j + 2; /* z 0 */
+ face_index++;
+ FACE_ASSERT(face - 4, sf_vert_tot);
+ }
+ else {
+ unsigned int midvidx = vertex_offset;
+
+ /***************
+ * cap end 'a' */
+ j = midvidx + (vertex_total * 3);
+
+ for (k = 0; k < vertex_total_cap_head - 2; k++, j++) {
+ *(face++) = midvidx + 0; /* z 1 */
+ *(face++) = midvidx + 0; /* z 1 */
+ *(face++) = j + 0; /* z 0 */
+ *(face++) = j + 1; /* z 0 */
+ face_index++;
+ FACE_ASSERT(face - 4, sf_vert_tot);
+ }
+
+ j = vertex_offset + (vertex_total * 3);
+
+ /* 2 tris that join the original */
+ *(face++) = midvidx + 0; /* z 1 */
+ *(face++) = midvidx + 0; /* z 1 */
+ *(face++) = midvidx + 1; /* z 0 */
+ *(face++) = j + 0; /* z 0 */
+ face_index++;
+ FACE_ASSERT(face - 4, sf_vert_tot);
+
+ *(face++) = midvidx + 0; /* z 1 */
+ *(face++) = midvidx + 0; /* z 1 */
+ *(face++) = j + vertex_total_cap_head - 2; /* z 0 */
+ *(face++) = midvidx + 2; /* z 0 */
+ face_index++;
+ FACE_ASSERT(face - 4, sf_vert_tot);
+
+ /***************
+ * cap end 'b' */
+ /* ... same as previous but v 2-3 flipped, and different initial offsets */
+
+ j = vertex_offset + (vertex_total * 3) + (vertex_total_cap_head - 1);
+
+ midvidx = vertex_offset + (vertex_total * 3) - 3;
+
+ for (k = 0; k < vertex_total_cap_tail - 2; k++, j++) {
+ *(face++) = midvidx; /* z 1 */
+ *(face++) = midvidx; /* z 1 */
+ *(face++) = j + 1; /* z 0 */
+ *(face++) = j + 0; /* z 0 */
+ face_index++;
+ FACE_ASSERT(face - 4, sf_vert_tot);
+ }
+
+ j = vertex_offset + (vertex_total * 3) + (vertex_total_cap_head - 1);
+
+ /* 2 tris that join the original */
+ *(face++) = midvidx + 0; /* z 1 */
+ *(face++) = midvidx + 0; /* z 1 */
+ *(face++) = j + 0; /* z 0 */
+ *(face++) = midvidx + 1; /* z 0 */
+ face_index++;
+ FACE_ASSERT(face - 4, sf_vert_tot);
+
+ *(face++) = midvidx + 0; /* z 1 */
+ *(face++) = midvidx + 0; /* z 1 */
+ *(face++) = midvidx + 2; /* z 0 */
+ *(face++) = j + vertex_total_cap_tail - 2; /* z 0 */
+ face_index++;
+ FACE_ASSERT(face - 4, sf_vert_tot);
+ }
+ }
+
+ MEM_freeN(open_spline_ranges);
+
+ // fprintf(stderr, "%u %u (%u %u), %u\n", face_index, sf_tri_tot + tot_feather_quads, sf_tri_tot, tot_feather_quads, tot_boundary_used - tot_boundary_found);
#ifdef USE_SCANFILL_EDGE_WORKAROUND
- BLI_assert(face_index + (tot_boundary_used - tot_boundary_found) == sf_tri_tot + tot_feather_quads);
+ BLI_assert(face_index + (tot_boundary_used - tot_boundary_found) ==
+ sf_tri_tot + tot_feather_quads);
#else
- BLI_assert(face_index == sf_tri_tot + tot_feather_quads);
+ BLI_assert(face_index == sf_tri_tot + tot_feather_quads);
#endif
- {
- MaskRasterLayer *layer = &mr_handle->layers[masklay_index];
+ {
+ MaskRasterLayer *layer = &mr_handle->layers[masklay_index];
- if (BLI_rctf_isect(&default_bounds, &bounds, &bounds)) {
+ if (BLI_rctf_isect(&default_bounds, &bounds, &bounds)) {
#ifdef USE_SCANFILL_EDGE_WORKAROUND
- layer->face_tot = (sf_tri_tot + tot_feather_quads) - (tot_boundary_used - tot_boundary_found);
+ layer->face_tot = (sf_tri_tot + tot_feather_quads) -
+ (tot_boundary_used - tot_boundary_found);
#else
- layer->face_tot = (sf_tri_tot + tot_feather_quads);
+ layer->face_tot = (sf_tri_tot + tot_feather_quads);
#endif
- layer->face_coords = face_coords;
- layer->face_array = face_array;
- layer->bounds = bounds;
+ layer->face_coords = face_coords;
+ layer->face_array = face_array;
+ layer->bounds = bounds;
- layer_bucket_init(layer, pixel_size);
+ layer_bucket_init(layer, pixel_size);
- BLI_rctf_union(&mr_handle->bounds, &bounds);
- }
- else {
- MEM_freeN(face_coords);
- MEM_freeN(face_array);
+ BLI_rctf_union(&mr_handle->bounds, &bounds);
+ }
+ else {
+ MEM_freeN(face_coords);
+ MEM_freeN(face_array);
- layer_bucket_init_dummy(layer);
- }
+ layer_bucket_init_dummy(layer);
+ }
- /* copy as-is */
- layer->alpha = masklay->alpha;
- layer->blend = masklay->blend;
- layer->blend_flag = masklay->blend_flag;
- layer->falloff = masklay->falloff;
- }
+ /* copy as-is */
+ layer->alpha = masklay->alpha;
+ layer->blend = masklay->blend;
+ layer->blend_flag = masklay->blend_flag;
+ layer->falloff = masklay->falloff;
+ }
- /* printf("tris %d, feather tris %d\n", sf_tri_tot, tot_feather_quads); */
- }
+ /* printf("tris %d, feather tris %d\n", sf_tri_tot, tot_feather_quads); */
+ }
- /* add trianges */
- BLI_scanfill_end_arena(&sf_ctx, sf_arena);
- }
+ /* add trianges */
+ BLI_scanfill_end_arena(&sf_ctx, sf_arena);
+ }
- BLI_memarena_free(sf_arena);
+ BLI_memarena_free(sf_arena);
}
-
/* --------------------------------------------------------------------- */
/* functions that run inside the sampling thread (keep fast!) */
/* --------------------------------------------------------------------- */
@@ -1198,274 +1214,273 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle, struct Mask *mas
static float maskrasterize_layer_z_depth_tri(const float pt[2],
const float v1[3], const float v2[3], const float v3[3])
{
- float w[3];
- barycentric_weights_v2(v1, v2, v3, pt, w);
- return (v1[2] * w[0]) + (v2[2] * w[1]) + (v3[2] * w[2]);
+ float w[3];
+ barycentric_weights_v2(v1, v2, v3, pt, w);
+ return (v1[2] * w[0]) + (v2[2] * w[1]) + (v3[2] * w[2]);
}
#endif
-static float maskrasterize_layer_z_depth_quad(const float pt[2],
- const float v1[3], const float v2[3], const float v3[3], const float v4[3])
+static float maskrasterize_layer_z_depth_quad(
+ const float pt[2], const float v1[3], const float v2[3], const float v3[3], const float v4[3])
{
- float w[4];
- barycentric_weights_v2_quad(v1, v2, v3, v4, pt, w);
- //return (v1[2] * w[0]) + (v2[2] * w[1]) + (v3[2] * w[2]) + (v4[2] * w[3]);
- return w[2] + w[3]; /* we can make this assumption for small speedup */
+ float w[4];
+ barycentric_weights_v2_quad(v1, v2, v3, v4, pt, w);
+ //return (v1[2] * w[0]) + (v2[2] * w[1]) + (v3[2] * w[2]) + (v4[2] * w[3]);
+ return w[2] + w[3]; /* we can make this assumption for small speedup */
}
-static float maskrasterize_layer_isect(unsigned int *face, float (*cos)[3], const float dist_orig, const float xy[2])
+static float maskrasterize_layer_isect(unsigned int *face,
+ float (*cos)[3],
+ const float dist_orig,
+ const float xy[2])
{
- /* we always cast from same place only need xy */
- if (face[3] == TRI_VERT) {
- /* --- tri --- */
+ /* we always cast from same place only need xy */
+ if (face[3] == TRI_VERT) {
+ /* --- tri --- */
#if 0
- /* not essential but avoids unneeded extra lookups */
- if ((cos[0][2] < dist_orig) ||
- (cos[1][2] < dist_orig) ||
- (cos[2][2] < dist_orig))
- {
- if (isect_point_tri_v2_cw(xy, cos[face[0]], cos[face[1]], cos[face[2]])) {
- /* we know all tris are close for now */
- return maskrasterize_layer_z_depth_tri(xy, cos[face[0]], cos[face[1]], cos[face[2]]);
- }
- }
+ /* not essential but avoids unneeded extra lookups */
+ if ((cos[0][2] < dist_orig) ||
+ (cos[1][2] < dist_orig) ||
+ (cos[2][2] < dist_orig))
+ {
+ if (isect_point_tri_v2_cw(xy, cos[face[0]], cos[face[1]], cos[face[2]])) {
+ /* we know all tris are close for now */
+ return maskrasterize_layer_z_depth_tri(xy, cos[face[0]], cos[face[1]], cos[face[2]]);
+ }
+ }
#else
- /* we know all tris are close for now */
- if (isect_point_tri_v2_cw(xy, cos[face[0]], cos[face[1]], cos[face[2]])) {
- return 0.0f;
- }
+ /* we know all tris are close for now */
+ if (isect_point_tri_v2_cw(xy, cos[face[0]], cos[face[1]], cos[face[2]])) {
+ return 0.0f;
+ }
#endif
- }
- else {
- /* --- quad --- */
-
- /* not essential but avoids unneeded extra lookups */
- if ((cos[0][2] < dist_orig) ||
- (cos[1][2] < dist_orig) ||
- (cos[2][2] < dist_orig) ||
- (cos[3][2] < dist_orig))
- {
-
- /* needs work */
+ }
+ else {
+ /* --- quad --- */
+
+ /* not essential but avoids unneeded extra lookups */
+ if ((cos[0][2] < dist_orig) || (cos[1][2] < dist_orig) || (cos[2][2] < dist_orig) ||
+ (cos[3][2] < dist_orig)) {
+
+ /* needs work */
#if 1
- /* quad check fails for bow-tie, so keep using 2 tri checks */
- //if (isect_point_quad_v2(xy, cos[face[0]], cos[face[1]], cos[face[2]], cos[face[3]]))
- if (isect_point_tri_v2(xy, cos[face[0]], cos[face[1]], cos[face[2]]) ||
- isect_point_tri_v2(xy, cos[face[0]], cos[face[2]], cos[face[3]]))
- {
- return maskrasterize_layer_z_depth_quad(xy, cos[face[0]], cos[face[1]], cos[face[2]], cos[face[3]]);
- }
+ /* quad check fails for bow-tie, so keep using 2 tri checks */
+ //if (isect_point_quad_v2(xy, cos[face[0]], cos[face[1]], cos[face[2]], cos[face[3]]))
+ if (isect_point_tri_v2(xy, cos[face[0]], cos[face[1]], cos[face[2]]) ||
+ isect_point_tri_v2(xy, cos[face[0]], cos[face[2]], cos[face[3]])) {
+ return maskrasterize_layer_z_depth_quad(
+ xy, cos[face[0]], cos[face[1]], cos[face[2]], cos[face[3]]);
+ }
#elif 1
- /* don't use isect_point_tri_v2_cw because we could have bow-tie quads */
-
- if (isect_point_tri_v2(xy, cos[face[0]], cos[face[1]], cos[face[2]])) {
- return maskrasterize_layer_z_depth_tri(xy, cos[face[0]], cos[face[1]], cos[face[2]]);
- }
- else if (isect_point_tri_v2(xy, cos[face[0]], cos[face[2]], cos[face[3]])) {
- return maskrasterize_layer_z_depth_tri(xy, cos[face[0]], cos[face[2]], cos[face[3]]);
- }
+ /* don't use isect_point_tri_v2_cw because we could have bow-tie quads */
+
+ if (isect_point_tri_v2(xy, cos[face[0]], cos[face[1]], cos[face[2]])) {
+ return maskrasterize_layer_z_depth_tri(xy, cos[face[0]], cos[face[1]], cos[face[2]]);
+ }
+ else if (isect_point_tri_v2(xy, cos[face[0]], cos[face[2]], cos[face[3]])) {
+ return maskrasterize_layer_z_depth_tri(xy, cos[face[0]], cos[face[2]], cos[face[3]]);
+ }
#else
- /* cheat - we know first 2 verts are z0.0f and second 2 are z 1.0f */
- /* ... worth looking into */
+ /* cheat - we know first 2 verts are z0.0f and second 2 are z 1.0f */
+ /* ... worth looking into */
#endif
- }
- }
+ }
+ }
- return 1.0f;
+ return 1.0f;
}
BLI_INLINE unsigned int layer_bucket_index_from_xy(MaskRasterLayer *layer, const float xy[2])
{
- BLI_assert(BLI_rctf_isect_pt_v(&layer->bounds, xy));
+ BLI_assert(BLI_rctf_isect_pt_v(&layer->bounds, xy));
- return ( (unsigned int)((xy[0] - layer->bounds.xmin) * layer->buckets_xy_scalar[0])) +
- (((unsigned int)((xy[1] - layer->bounds.ymin) * layer->buckets_xy_scalar[1])) * layer->buckets_x);
+ return ((unsigned int)((xy[0] - layer->bounds.xmin) * layer->buckets_xy_scalar[0])) +
+ (((unsigned int)((xy[1] - layer->bounds.ymin) * layer->buckets_xy_scalar[1])) *
+ layer->buckets_x);
}
static float layer_bucket_depth_from_xy(MaskRasterLayer *layer, const float xy[2])
{
- unsigned int index = layer_bucket_index_from_xy(layer, xy);
- unsigned int *face_index = layer->buckets_face[index];
-
- if (face_index) {
- unsigned int (*face_array)[4] = layer->face_array;
- float (*cos)[3] = layer->face_coords;
- float best_dist = 1.0f;
- while (*face_index != TRI_TERMINATOR_ID) {
- const float test_dist = maskrasterize_layer_isect(face_array[*face_index], cos, best_dist, xy);
- if (test_dist < best_dist) {
- best_dist = test_dist;
- /* comparing with 0.0f is OK here because triangles are always zero depth */
- if (best_dist == 0.0f) {
- /* bail early, we're as close as possible */
- return 0.0f;
- }
- }
- face_index++;
- }
- return best_dist;
- }
- else {
- return 1.0f;
- }
+ unsigned int index = layer_bucket_index_from_xy(layer, xy);
+ unsigned int *face_index = layer->buckets_face[index];
+
+ if (face_index) {
+ unsigned int(*face_array)[4] = layer->face_array;
+ float(*cos)[3] = layer->face_coords;
+ float best_dist = 1.0f;
+ while (*face_index != TRI_TERMINATOR_ID) {
+ const float test_dist = maskrasterize_layer_isect(
+ face_array[*face_index], cos, best_dist, xy);
+ if (test_dist < best_dist) {
+ best_dist = test_dist;
+ /* comparing with 0.0f is OK here because triangles are always zero depth */
+ if (best_dist == 0.0f) {
+ /* bail early, we're as close as possible */
+ return 0.0f;
+ }
+ }
+ face_index++;
+ }
+ return best_dist;
+ }
+ else {
+ return 1.0f;
+ }
}
float BKE_maskrasterize_handle_sample(MaskRasterHandle *mr_handle, const float xy[2])
{
- /* can't do this because some layers may invert */
- /* if (BLI_rctf_isect_pt_v(&mr_handle->bounds, xy)) */
-
- const unsigned int layers_tot = mr_handle->layers_tot;
- unsigned int i;
- MaskRasterLayer *layer = mr_handle->layers;
-
- /* return value */
- float value = 0.0f;
-
- for (i = 0; i < layers_tot; i++, layer++) {
- float value_layer;
-
- /* also used as signal for unused layer (when render is disabled) */
- if (layer->alpha != 0.0f && BLI_rctf_isect_pt_v(&layer->bounds, xy)) {
- value_layer = 1.0f - layer_bucket_depth_from_xy(layer, xy);
-
- switch (layer->falloff) {
- case PROP_SMOOTH:
- /* ease - gives less hard lines for dilate/erode feather */
- value_layer = (3.0f * value_layer * value_layer - 2.0f * value_layer * value_layer * value_layer);
- break;
- case PROP_SPHERE:
- value_layer = sqrtf(2.0f * value_layer - value_layer * value_layer);
- break;
- case PROP_ROOT:
- value_layer = sqrtf(value_layer);
- break;
- case PROP_SHARP:
- value_layer = value_layer * value_layer;
- break;
- case PROP_INVSQUARE:
- value_layer = value_layer * (2.0f - value_layer);
- break;
- case PROP_LIN:
- default:
- /* nothing */
- break;
- }
-
- if (layer->blend != MASK_BLEND_REPLACE) {
- value_layer *= layer->alpha;
- }
- }
- else {
- value_layer = 0.0f;
- }
-
- if (layer->blend_flag & MASK_BLENDFLAG_INVERT) {
- value_layer = 1.0f - value_layer;
- }
-
- switch (layer->blend) {
- case MASK_BLEND_MERGE_ADD:
- value += value_layer * (1.0f - value);
- break;
- case MASK_BLEND_MERGE_SUBTRACT:
- value -= value_layer * value;
- break;
- case MASK_BLEND_ADD:
- value += value_layer;
- break;
- case MASK_BLEND_SUBTRACT:
- value -= value_layer;
- break;
- case MASK_BLEND_LIGHTEN:
- value = max_ff(value, value_layer);
- break;
- case MASK_BLEND_DARKEN:
- value = min_ff(value, value_layer);
- break;
- case MASK_BLEND_MUL:
- value *= value_layer;
- break;
- case MASK_BLEND_REPLACE:
- value = (value * (1.0f - layer->alpha)) + (value_layer * layer->alpha);
- break;
- case MASK_BLEND_DIFFERENCE:
- value = fabsf(value - value_layer);
- break;
- default: /* same as add */
- CLOG_ERROR(&LOG, "unhandled blend type: %d", layer->blend);
- BLI_assert(0);
- value += value_layer;
- break;
- }
-
- /* clamp after applying each layer so we don't get
- * issues subtracting after accumulating over 1.0f */
- CLAMP(value, 0.0f, 1.0f);
- }
-
- return value;
+ /* can't do this because some layers may invert */
+ /* if (BLI_rctf_isect_pt_v(&mr_handle->bounds, xy)) */
+
+ const unsigned int layers_tot = mr_handle->layers_tot;
+ unsigned int i;
+ MaskRasterLayer *layer = mr_handle->layers;
+
+ /* return value */
+ float value = 0.0f;
+
+ for (i = 0; i < layers_tot; i++, layer++) {
+ float value_layer;
+
+ /* also used as signal for unused layer (when render is disabled) */
+ if (layer->alpha != 0.0f && BLI_rctf_isect_pt_v(&layer->bounds, xy)) {
+ value_layer = 1.0f - layer_bucket_depth_from_xy(layer, xy);
+
+ switch (layer->falloff) {
+ case PROP_SMOOTH:
+ /* ease - gives less hard lines for dilate/erode feather */
+ value_layer = (3.0f * value_layer * value_layer -
+ 2.0f * value_layer * value_layer * value_layer);
+ break;
+ case PROP_SPHERE:
+ value_layer = sqrtf(2.0f * value_layer - value_layer * value_layer);
+ break;
+ case PROP_ROOT:
+ value_layer = sqrtf(value_layer);
+ break;
+ case PROP_SHARP:
+ value_layer = value_layer * value_layer;
+ break;
+ case PROP_INVSQUARE:
+ value_layer = value_layer * (2.0f - value_layer);
+ break;
+ case PROP_LIN:
+ default:
+ /* nothing */
+ break;
+ }
+
+ if (layer->blend != MASK_BLEND_REPLACE) {
+ value_layer *= layer->alpha;
+ }
+ }
+ else {
+ value_layer = 0.0f;
+ }
+
+ if (layer->blend_flag & MASK_BLENDFLAG_INVERT) {
+ value_layer = 1.0f - value_layer;
+ }
+
+ switch (layer->blend) {
+ case MASK_BLEND_MERGE_ADD:
+ value += value_layer * (1.0f - value);
+ break;
+ case MASK_BLEND_MERGE_SUBTRACT:
+ value -= value_layer * value;
+ break;
+ case MASK_BLEND_ADD:
+ value += value_layer;
+ break;
+ case MASK_BLEND_SUBTRACT:
+ value -= value_layer;
+ break;
+ case MASK_BLEND_LIGHTEN:
+ value = max_ff(value, value_layer);
+ break;
+ case MASK_BLEND_DARKEN:
+ value = min_ff(value, value_layer);
+ break;
+ case MASK_BLEND_MUL:
+ value *= value_layer;
+ break;
+ case MASK_BLEND_REPLACE:
+ value = (value * (1.0f - layer->alpha)) + (value_layer * layer->alpha);
+ break;
+ case MASK_BLEND_DIFFERENCE:
+ value = fabsf(value - value_layer);
+ break;
+ default: /* same as add */
+ CLOG_ERROR(&LOG, "unhandled blend type: %d", layer->blend);
+ BLI_assert(0);
+ value += value_layer;
+ break;
+ }
+
+ /* clamp after applying each layer so we don't get
+ * issues subtracting after accumulating over 1.0f */
+ CLAMP(value, 0.0f, 1.0f);
+ }
+
+ return value;
}
-
typedef struct MaskRasterizeBufferData {
- MaskRasterHandle *mr_handle;
- float x_inv, y_inv;
- float x_px_ofs, y_px_ofs;
- uint width;
+ MaskRasterHandle *mr_handle;
+ float x_inv, y_inv;
+ float x_px_ofs, y_px_ofs;
+ uint width;
- float *buffer;
+ float *buffer;
} MaskRasterizeBufferData;
-static void maskrasterize_buffer_cb(
- void *__restrict userdata,
- const int y,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void maskrasterize_buffer_cb(void *__restrict userdata,
+ const int y,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- MaskRasterizeBufferData *data = userdata;
+ MaskRasterizeBufferData *data = userdata;
- MaskRasterHandle *mr_handle = data->mr_handle;
- float *buffer = data->buffer;
+ MaskRasterHandle *mr_handle = data->mr_handle;
+ float *buffer = data->buffer;
- const uint width = data->width;
- const float x_inv = data->x_inv;
- const float x_px_ofs = data->x_px_ofs;
+ const uint width = data->width;
+ const float x_inv = data->x_inv;
+ const float x_px_ofs = data->x_px_ofs;
- uint i = (uint)y * width;
- float xy[2];
- xy[1] = ((float)y * data->y_inv) + data->y_px_ofs;
- for (uint x = 0; x < width; x++, i++) {
- xy[0] = ((float)x * x_inv) + x_px_ofs;
+ uint i = (uint)y * width;
+ float xy[2];
+ xy[1] = ((float)y * data->y_inv) + data->y_px_ofs;
+ for (uint x = 0; x < width; x++, i++) {
+ xy[0] = ((float)x * x_inv) + x_px_ofs;
- buffer[i] = BKE_maskrasterize_handle_sample(mr_handle, xy);
- }
+ buffer[i] = BKE_maskrasterize_handle_sample(mr_handle, xy);
+ }
}
/**
* \brief Rasterize a buffer from a single mask (threaded execution).
*/
void BKE_maskrasterize_buffer(MaskRasterHandle *mr_handle,
- const unsigned int width, const unsigned int height,
+ const unsigned int width,
+ const unsigned int height,
float *buffer)
{
- const float x_inv = 1.0f / (float)width;
- const float y_inv = 1.0f / (float)height;
-
- MaskRasterizeBufferData data = {
- .mr_handle = mr_handle,
- .x_inv = x_inv,
- .y_inv = y_inv,
- .x_px_ofs = x_inv * 0.5f,
- .y_px_ofs = y_inv * 0.5f,
- .width = width,
- .buffer = buffer,
- };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((size_t)height * width > 10000);
- BLI_task_parallel_range(0, (int)height,
- &data,
- maskrasterize_buffer_cb,
- &settings);
+ const float x_inv = 1.0f / (float)width;
+ const float y_inv = 1.0f / (float)height;
+
+ MaskRasterizeBufferData data = {
+ .mr_handle = mr_handle,
+ .x_inv = x_inv,
+ .y_inv = y_inv,
+ .x_px_ofs = x_inv * 0.5f,
+ .y_px_ofs = y_inv * 0.5f,
+ .width = width,
+ .buffer = buffer,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((size_t)height * width > 10000);
+ BLI_task_parallel_range(0, (int)height, &data, maskrasterize_buffer_cb, &settings);
}
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 52e7c687694..a4da6663de8 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -21,7 +21,6 @@
* \ingroup bke
*/
-
#include <string.h>
#include <math.h>
#include <stddef.h>
@@ -78,98 +77,97 @@ static CLG_LogRef LOG = {"bke.material"};
/* called on startup, creator.c */
void init_def_material(void)
{
- BKE_material_init(&defmaterial);
+ BKE_material_init(&defmaterial);
}
/** Free (or release) any data used by this material (does not free the material itself). */
void BKE_material_free(Material *ma)
{
- BKE_animdata_free((ID *)ma, false);
+ BKE_animdata_free((ID *)ma, false);
- /* Free gpu material before the ntree */
- GPU_material_free(&ma->gpumaterial);
+ /* Free gpu material before the ntree */
+ GPU_material_free(&ma->gpumaterial);
- /* is no lib link block, but material extension */
- if (ma->nodetree) {
- ntreeFreeNestedTree(ma->nodetree);
- MEM_freeN(ma->nodetree);
- ma->nodetree = NULL;
- }
+ /* is no lib link block, but material extension */
+ if (ma->nodetree) {
+ ntreeFreeNestedTree(ma->nodetree);
+ MEM_freeN(ma->nodetree);
+ ma->nodetree = NULL;
+ }
- MEM_SAFE_FREE(ma->texpaintslot);
+ MEM_SAFE_FREE(ma->texpaintslot);
- MEM_SAFE_FREE(ma->gp_style);
+ MEM_SAFE_FREE(ma->gp_style);
- BKE_icon_id_delete((ID *)ma);
- BKE_previewimg_free(&ma->preview);
+ BKE_icon_id_delete((ID *)ma);
+ BKE_previewimg_free(&ma->preview);
}
void BKE_material_init_gpencil_settings(Material *ma)
{
- if ((ma) && (ma->gp_style == NULL)) {
- ma->gp_style = MEM_callocN(sizeof(MaterialGPencilStyle), "Grease Pencil Material Settings");
-
- MaterialGPencilStyle *gp_style = ma->gp_style;
- /* set basic settings */
- gp_style->stroke_rgba[3] = 1.0f;
- gp_style->fill_rgba[3] = 1.0f;
- gp_style->pattern_gridsize = 0.1f;
- gp_style->gradient_radius = 0.5f;
- ARRAY_SET_ITEMS(gp_style->mix_rgba, 1.0f, 1.0f, 1.0f, 0.2f);
- ARRAY_SET_ITEMS(gp_style->gradient_scale, 1.0f, 1.0f);
- ARRAY_SET_ITEMS(gp_style->texture_scale, 1.0f, 1.0f);
- gp_style->texture_opacity = 1.0f;
- gp_style->texture_pixsize = 100.0f;
-
- gp_style->flag |= GP_STYLE_STROKE_SHOW;
- }
+ if ((ma) && (ma->gp_style == NULL)) {
+ ma->gp_style = MEM_callocN(sizeof(MaterialGPencilStyle), "Grease Pencil Material Settings");
+
+ MaterialGPencilStyle *gp_style = ma->gp_style;
+ /* set basic settings */
+ gp_style->stroke_rgba[3] = 1.0f;
+ gp_style->fill_rgba[3] = 1.0f;
+ gp_style->pattern_gridsize = 0.1f;
+ gp_style->gradient_radius = 0.5f;
+ ARRAY_SET_ITEMS(gp_style->mix_rgba, 1.0f, 1.0f, 1.0f, 0.2f);
+ ARRAY_SET_ITEMS(gp_style->gradient_scale, 1.0f, 1.0f);
+ ARRAY_SET_ITEMS(gp_style->texture_scale, 1.0f, 1.0f);
+ gp_style->texture_opacity = 1.0f;
+ gp_style->texture_pixsize = 100.0f;
+
+ gp_style->flag |= GP_STYLE_STROKE_SHOW;
+ }
}
void BKE_material_init(Material *ma)
{
- BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(ma, id));
+ BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(ma, id));
- ma->r = ma->g = ma->b = 0.8;
- ma->specr = ma->specg = ma->specb = 1.0;
- ma->a = 1.0f;
- ma->spec = 0.5;
+ ma->r = ma->g = ma->b = 0.8;
+ ma->specr = ma->specg = ma->specb = 1.0;
+ ma->a = 1.0f;
+ ma->spec = 0.5;
- ma->roughness = 0.25f;
+ ma->roughness = 0.25f;
- ma->pr_type = MA_SPHERE;
+ ma->pr_type = MA_SPHERE;
- ma->preview = NULL;
+ ma->preview = NULL;
- ma->alpha_threshold = 0.5f;
+ ma->alpha_threshold = 0.5f;
- ma->blend_shadow = MA_BS_SOLID;
+ ma->blend_shadow = MA_BS_SOLID;
}
Material *BKE_material_add(Main *bmain, const char *name)
{
- Material *ma;
+ Material *ma;
- ma = BKE_libblock_alloc(bmain, ID_MA, name, 0);
+ ma = BKE_libblock_alloc(bmain, ID_MA, name, 0);
- BKE_material_init(ma);
+ BKE_material_init(ma);
- return ma;
+ return ma;
}
Material *BKE_material_add_gpencil(Main *bmain, const char *name)
{
- Material *ma;
+ Material *ma;
- ma = BKE_material_add(bmain, name);
+ ma = BKE_material_add(bmain, name);
- /* grease pencil settings */
- if (ma != NULL) {
- BKE_material_init_gpencil_settings(ma);
- }
- return ma;
+ /* grease pencil settings */
+ if (ma != NULL) {
+ BKE_material_init_gpencil_settings(ma);
+ }
+ return ma;
}
-
/**
* Only copy internal data of Material ID from source to already allocated/initialized destination.
* You probably never want to use that directly, use BKE_id_copy or BKE_id_copy_ex for typical needs.
@@ -180,633 +178,648 @@ Material *BKE_material_add_gpencil(Main *bmain, const char *name)
*/
void BKE_material_copy_data(Main *bmain, Material *ma_dst, const Material *ma_src, const int flag)
{
- if (ma_src->nodetree) {
- /* Note: nodetree is *not* in bmain, however this specific case is handled at lower level
- * (see BKE_libblock_copy_ex()). */
- BKE_id_copy_ex(bmain, (ID *)ma_src->nodetree, (ID **)&ma_dst->nodetree, flag);
- }
-
- if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
- BKE_previewimg_id_copy(&ma_dst->id, &ma_src->id);
- }
- else {
- ma_dst->preview = NULL;
- }
-
- if (ma_src->texpaintslot != NULL) {
- ma_dst->texpaintslot = MEM_dupallocN(ma_src->texpaintslot);
- }
-
- if (ma_src->gp_style != NULL) {
- ma_dst->gp_style = MEM_dupallocN(ma_src->gp_style);
- }
-
- BLI_listbase_clear(&ma_dst->gpumaterial);
-
- /* TODO Duplicate Engine Settings and set runtime to NULL */
+ if (ma_src->nodetree) {
+ /* Note: nodetree is *not* in bmain, however this specific case is handled at lower level
+ * (see BKE_libblock_copy_ex()). */
+ BKE_id_copy_ex(bmain, (ID *)ma_src->nodetree, (ID **)&ma_dst->nodetree, flag);
+ }
+
+ if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
+ BKE_previewimg_id_copy(&ma_dst->id, &ma_src->id);
+ }
+ else {
+ ma_dst->preview = NULL;
+ }
+
+ if (ma_src->texpaintslot != NULL) {
+ ma_dst->texpaintslot = MEM_dupallocN(ma_src->texpaintslot);
+ }
+
+ if (ma_src->gp_style != NULL) {
+ ma_dst->gp_style = MEM_dupallocN(ma_src->gp_style);
+ }
+
+ BLI_listbase_clear(&ma_dst->gpumaterial);
+
+ /* TODO Duplicate Engine Settings and set runtime to NULL */
}
Material *BKE_material_copy(Main *bmain, const Material *ma)
{
- Material *ma_copy;
- BKE_id_copy(bmain, &ma->id, (ID **)&ma_copy);
- return ma_copy;
+ Material *ma_copy;
+ BKE_id_copy(bmain, &ma->id, (ID **)&ma_copy);
+ return ma_copy;
}
/* XXX (see above) material copy without adding to main dbase */
Material *BKE_material_localize(Material *ma)
{
- /* TODO(bastien): Replace with something like:
- *
- * Material *ma_copy;
- * BKE_id_copy_ex(bmain, &ma->id, (ID **)&ma_copy,
- * LIB_ID_COPY_NO_MAIN | LIB_ID_COPY_NO_PREVIEW | LIB_ID_COPY_NO_USER_REFCOUNT,
- * false);
- * return ma_copy;
- *
- * NOTE: Only possible once nested node trees are fully converted to that too. */
+ /* TODO(bastien): Replace with something like:
+ *
+ * Material *ma_copy;
+ * BKE_id_copy_ex(bmain, &ma->id, (ID **)&ma_copy,
+ * LIB_ID_COPY_NO_MAIN | LIB_ID_COPY_NO_PREVIEW | LIB_ID_COPY_NO_USER_REFCOUNT,
+ * false);
+ * return ma_copy;
+ *
+ * NOTE: Only possible once nested node trees are fully converted to that too. */
- Material *man = BKE_libblock_copy_for_localize(&ma->id);
+ Material *man = BKE_libblock_copy_for_localize(&ma->id);
- man->texpaintslot = NULL;
- man->preview = NULL;
+ man->texpaintslot = NULL;
+ man->preview = NULL;
- if (ma->nodetree != NULL) {
- man->nodetree = ntreeLocalize(ma->nodetree);
- }
+ if (ma->nodetree != NULL) {
+ man->nodetree = ntreeLocalize(ma->nodetree);
+ }
- if (ma->gp_style != NULL) {
- man->gp_style = MEM_dupallocN(ma->gp_style);
- }
+ if (ma->gp_style != NULL) {
+ man->gp_style = MEM_dupallocN(ma->gp_style);
+ }
- BLI_listbase_clear(&man->gpumaterial);
+ BLI_listbase_clear(&man->gpumaterial);
- /* TODO Duplicate Engine Settings and set runtime to NULL */
+ /* TODO Duplicate Engine Settings and set runtime to NULL */
- man->id.tag |= LIB_TAG_LOCALIZED;
+ man->id.tag |= LIB_TAG_LOCALIZED;
- return man;
+ return man;
}
void BKE_material_make_local(Main *bmain, Material *ma, const bool lib_local)
{
- BKE_id_make_local_generic(bmain, &ma->id, true, lib_local);
+ BKE_id_make_local_generic(bmain, &ma->id, true, lib_local);
}
Material ***give_matarar(Object *ob)
{
- Mesh *me;
- Curve *cu;
- MetaBall *mb;
- bGPdata *gpd;
-
- if (ob->type == OB_MESH) {
- me = ob->data;
- return &(me->mat);
- }
- else if (ELEM(ob->type, OB_CURVE, OB_FONT, OB_SURF)) {
- cu = ob->data;
- return &(cu->mat);
- }
- else if (ob->type == OB_MBALL) {
- mb = ob->data;
- return &(mb->mat);
- }
- else if (ob->type == OB_GPENCIL) {
- gpd = ob->data;
- return &(gpd->mat);
- }
- return NULL;
+ Mesh *me;
+ Curve *cu;
+ MetaBall *mb;
+ bGPdata *gpd;
+
+ if (ob->type == OB_MESH) {
+ me = ob->data;
+ return &(me->mat);
+ }
+ else if (ELEM(ob->type, OB_CURVE, OB_FONT, OB_SURF)) {
+ cu = ob->data;
+ return &(cu->mat);
+ }
+ else if (ob->type == OB_MBALL) {
+ mb = ob->data;
+ return &(mb->mat);
+ }
+ else if (ob->type == OB_GPENCIL) {
+ gpd = ob->data;
+ return &(gpd->mat);
+ }
+ return NULL;
}
short *give_totcolp(Object *ob)
{
- Mesh *me;
- Curve *cu;
- MetaBall *mb;
- bGPdata *gpd;
-
- if (ob->type == OB_MESH) {
- me = ob->data;
- return &(me->totcol);
- }
- else if (ELEM(ob->type, OB_CURVE, OB_FONT, OB_SURF)) {
- cu = ob->data;
- return &(cu->totcol);
- }
- else if (ob->type == OB_MBALL) {
- mb = ob->data;
- return &(mb->totcol);
- }
- else if (ob->type == OB_GPENCIL) {
- gpd = ob->data;
- return &(gpd->totcol);
- }
- return NULL;
+ Mesh *me;
+ Curve *cu;
+ MetaBall *mb;
+ bGPdata *gpd;
+
+ if (ob->type == OB_MESH) {
+ me = ob->data;
+ return &(me->totcol);
+ }
+ else if (ELEM(ob->type, OB_CURVE, OB_FONT, OB_SURF)) {
+ cu = ob->data;
+ return &(cu->totcol);
+ }
+ else if (ob->type == OB_MBALL) {
+ mb = ob->data;
+ return &(mb->totcol);
+ }
+ else if (ob->type == OB_GPENCIL) {
+ gpd = ob->data;
+ return &(gpd->totcol);
+ }
+ return NULL;
}
/* same as above but for ID's */
Material ***give_matarar_id(ID *id)
{
- /* ensure we don't try get materials from non-obdata */
- BLI_assert(OB_DATA_SUPPORT_ID(GS(id->name)));
-
- switch (GS(id->name)) {
- case ID_ME:
- return &(((Mesh *)id)->mat);
- case ID_CU:
- return &(((Curve *)id)->mat);
- case ID_MB:
- return &(((MetaBall *)id)->mat);
- case ID_GD:
- return &(((bGPdata *)id)->mat);
- default:
- break;
- }
- return NULL;
+ /* ensure we don't try get materials from non-obdata */
+ BLI_assert(OB_DATA_SUPPORT_ID(GS(id->name)));
+
+ switch (GS(id->name)) {
+ case ID_ME:
+ return &(((Mesh *)id)->mat);
+ case ID_CU:
+ return &(((Curve *)id)->mat);
+ case ID_MB:
+ return &(((MetaBall *)id)->mat);
+ case ID_GD:
+ return &(((bGPdata *)id)->mat);
+ default:
+ break;
+ }
+ return NULL;
}
short *give_totcolp_id(ID *id)
{
- /* ensure we don't try get materials from non-obdata */
- BLI_assert(OB_DATA_SUPPORT_ID(GS(id->name)));
-
- switch (GS(id->name)) {
- case ID_ME:
- return &(((Mesh *)id)->totcol);
- case ID_CU:
- return &(((Curve *)id)->totcol);
- case ID_MB:
- return &(((MetaBall *)id)->totcol);
- case ID_GD:
- return &(((bGPdata *)id)->totcol);
- default:
- break;
- }
- return NULL;
+ /* ensure we don't try get materials from non-obdata */
+ BLI_assert(OB_DATA_SUPPORT_ID(GS(id->name)));
+
+ switch (GS(id->name)) {
+ case ID_ME:
+ return &(((Mesh *)id)->totcol);
+ case ID_CU:
+ return &(((Curve *)id)->totcol);
+ case ID_MB:
+ return &(((MetaBall *)id)->totcol);
+ case ID_GD:
+ return &(((bGPdata *)id)->totcol);
+ default:
+ break;
+ }
+ return NULL;
}
static void material_data_index_remove_id(ID *id, short index)
{
- /* ensure we don't try get materials from non-obdata */
- BLI_assert(OB_DATA_SUPPORT_ID(GS(id->name)));
-
- switch (GS(id->name)) {
- case ID_ME:
- BKE_mesh_material_index_remove((Mesh *)id, index);
- break;
- case ID_CU:
- BKE_curve_material_index_remove((Curve *)id, index);
- break;
- case ID_MB:
- /* meta-elems don't have materials atm */
- break;
- case ID_GD:
- BKE_gpencil_material_index_remove((bGPdata *)id, index);
- break;
- default:
- break;
- }
+ /* ensure we don't try get materials from non-obdata */
+ BLI_assert(OB_DATA_SUPPORT_ID(GS(id->name)));
+
+ switch (GS(id->name)) {
+ case ID_ME:
+ BKE_mesh_material_index_remove((Mesh *)id, index);
+ break;
+ case ID_CU:
+ BKE_curve_material_index_remove((Curve *)id, index);
+ break;
+ case ID_MB:
+ /* meta-elems don't have materials atm */
+ break;
+ case ID_GD:
+ BKE_gpencil_material_index_remove((bGPdata *)id, index);
+ break;
+ default:
+ break;
+ }
}
static void material_data_index_clear_id(ID *id)
{
- /* ensure we don't try get materials from non-obdata */
- BLI_assert(OB_DATA_SUPPORT_ID(GS(id->name)));
-
- switch (GS(id->name)) {
- case ID_ME:
- BKE_mesh_material_index_clear((Mesh *)id);
- break;
- case ID_CU:
- BKE_curve_material_index_clear((Curve *)id);
- break;
- case ID_MB:
- /* meta-elems don't have materials atm */
- break;
- default:
- break;
- }
+ /* ensure we don't try get materials from non-obdata */
+ BLI_assert(OB_DATA_SUPPORT_ID(GS(id->name)));
+
+ switch (GS(id->name)) {
+ case ID_ME:
+ BKE_mesh_material_index_clear((Mesh *)id);
+ break;
+ case ID_CU:
+ BKE_curve_material_index_clear((Curve *)id);
+ break;
+ case ID_MB:
+ /* meta-elems don't have materials atm */
+ break;
+ default:
+ break;
+ }
}
void BKE_material_resize_id(Main *bmain, ID *id, short totcol, bool do_id_user)
{
- Material ***matar = give_matarar_id(id);
- short *totcolp = give_totcolp_id(id);
-
- if (matar == NULL) {
- return;
- }
-
- if (do_id_user && totcol < (*totcolp)) {
- short i;
- for (i = totcol; i < (*totcolp); i++) {
- id_us_min((ID *)(*matar)[i]);
- }
- }
-
- if (totcol == 0) {
- if (*totcolp) {
- MEM_freeN(*matar);
- *matar = NULL;
- }
- }
- else {
- *matar = MEM_recallocN(*matar, sizeof(void *) * totcol);
- }
- *totcolp = totcol;
-
- DEG_id_tag_update(id, ID_RECALC_COPY_ON_WRITE);
- DEG_relations_tag_update(bmain);
+ Material ***matar = give_matarar_id(id);
+ short *totcolp = give_totcolp_id(id);
+
+ if (matar == NULL) {
+ return;
+ }
+
+ if (do_id_user && totcol < (*totcolp)) {
+ short i;
+ for (i = totcol; i < (*totcolp); i++) {
+ id_us_min((ID *)(*matar)[i]);
+ }
+ }
+
+ if (totcol == 0) {
+ if (*totcolp) {
+ MEM_freeN(*matar);
+ *matar = NULL;
+ }
+ }
+ else {
+ *matar = MEM_recallocN(*matar, sizeof(void *) * totcol);
+ }
+ *totcolp = totcol;
+
+ DEG_id_tag_update(id, ID_RECALC_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
}
void BKE_material_append_id(Main *bmain, ID *id, Material *ma)
{
- Material ***matar;
- if ((matar = give_matarar_id(id))) {
- short *totcol = give_totcolp_id(id);
- Material **mat = MEM_callocN(sizeof(void *) * ((*totcol) + 1), "newmatar");
- if (*totcol) memcpy(mat, *matar, sizeof(void *) * (*totcol));
- if (*matar) MEM_freeN(*matar);
-
- *matar = mat;
- (*matar)[(*totcol)++] = ma;
-
- id_us_plus((ID *)ma);
- test_all_objects_materials(bmain, id);
-
- DEG_id_tag_update(id, ID_RECALC_COPY_ON_WRITE);
- DEG_relations_tag_update(bmain);
- }
+ Material ***matar;
+ if ((matar = give_matarar_id(id))) {
+ short *totcol = give_totcolp_id(id);
+ Material **mat = MEM_callocN(sizeof(void *) * ((*totcol) + 1), "newmatar");
+ if (*totcol)
+ memcpy(mat, *matar, sizeof(void *) * (*totcol));
+ if (*matar)
+ MEM_freeN(*matar);
+
+ *matar = mat;
+ (*matar)[(*totcol)++] = ma;
+
+ id_us_plus((ID *)ma);
+ test_all_objects_materials(bmain, id);
+
+ DEG_id_tag_update(id, ID_RECALC_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
+ }
}
Material *BKE_material_pop_id(Main *bmain, ID *id, int index_i, bool update_data)
{
- short index = (short)index_i;
- Material *ret = NULL;
- Material ***matar;
- if ((matar = give_matarar_id(id))) {
- short *totcol = give_totcolp_id(id);
- if (index >= 0 && index < (*totcol)) {
- ret = (*matar)[index];
- id_us_min((ID *)ret);
-
- if (*totcol <= 1) {
- *totcol = 0;
- MEM_freeN(*matar);
- *matar = NULL;
- }
- else {
- if (index + 1 != (*totcol))
- memmove((*matar) + index, (*matar) + (index + 1), sizeof(void *) * ((*totcol) - (index + 1)));
-
- (*totcol)--;
- *matar = MEM_reallocN(*matar, sizeof(void *) * (*totcol));
- test_all_objects_materials(bmain, id);
- }
-
- if (update_data) {
- /* decrease mat_nr index */
- material_data_index_remove_id(id, index);
- }
-
- DEG_id_tag_update(id, ID_RECALC_COPY_ON_WRITE);
- DEG_relations_tag_update(bmain);
- }
- }
-
- return ret;
+ short index = (short)index_i;
+ Material *ret = NULL;
+ Material ***matar;
+ if ((matar = give_matarar_id(id))) {
+ short *totcol = give_totcolp_id(id);
+ if (index >= 0 && index < (*totcol)) {
+ ret = (*matar)[index];
+ id_us_min((ID *)ret);
+
+ if (*totcol <= 1) {
+ *totcol = 0;
+ MEM_freeN(*matar);
+ *matar = NULL;
+ }
+ else {
+ if (index + 1 != (*totcol))
+ memmove((*matar) + index,
+ (*matar) + (index + 1),
+ sizeof(void *) * ((*totcol) - (index + 1)));
+
+ (*totcol)--;
+ *matar = MEM_reallocN(*matar, sizeof(void *) * (*totcol));
+ test_all_objects_materials(bmain, id);
+ }
+
+ if (update_data) {
+ /* decrease mat_nr index */
+ material_data_index_remove_id(id, index);
+ }
+
+ DEG_id_tag_update(id, ID_RECALC_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
+ }
+ }
+
+ return ret;
}
void BKE_material_clear_id(Main *bmain, ID *id, bool update_data)
{
- Material ***matar;
- if ((matar = give_matarar_id(id))) {
- short *totcol = give_totcolp_id(id);
-
- while ((*totcol)--) {
- id_us_min((ID *)((*matar)[*totcol]));
- }
- *totcol = 0;
- if (*matar) {
- MEM_freeN(*matar);
- *matar = NULL;
- }
-
- if (update_data) {
- /* decrease mat_nr index */
- material_data_index_clear_id(id);
- }
-
- DEG_id_tag_update(id, ID_RECALC_COPY_ON_WRITE);
- DEG_relations_tag_update(bmain);
- }
+ Material ***matar;
+ if ((matar = give_matarar_id(id))) {
+ short *totcol = give_totcolp_id(id);
+
+ while ((*totcol)--) {
+ id_us_min((ID *)((*matar)[*totcol]));
+ }
+ *totcol = 0;
+ if (*matar) {
+ MEM_freeN(*matar);
+ *matar = NULL;
+ }
+
+ if (update_data) {
+ /* decrease mat_nr index */
+ material_data_index_clear_id(id);
+ }
+
+ DEG_id_tag_update(id, ID_RECALC_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
+ }
}
Material **give_current_material_p(Object *ob, short act)
{
- Material ***matarar, **ma_p;
- const short *totcolp;
-
- if (ob == NULL) return NULL;
-
- /* if object cannot have material, (totcolp == NULL) */
- totcolp = give_totcolp(ob);
- if (totcolp == NULL || ob->totcol == 0) return NULL;
-
- /* return NULL for invalid 'act', can happen for mesh face indices */
- if (act > ob->totcol)
- return NULL;
- else if (act <= 0) {
- if (act < 0) {
- CLOG_ERROR(&LOG, "Negative material index!");
- }
- return NULL;
- }
-
- if (ob->matbits && ob->matbits[act - 1]) { /* in object */
- ma_p = &ob->mat[act - 1];
- }
- else { /* in data */
-
- /* check for inconsistency */
- if (*totcolp < ob->totcol)
- ob->totcol = *totcolp;
- if (act > ob->totcol) act = ob->totcol;
-
- matarar = give_matarar(ob);
-
- if (matarar && *matarar) {
- ma_p = &(*matarar)[act - 1];
- }
- else {
- ma_p = NULL;
- }
- }
-
- return ma_p;
+ Material ***matarar, **ma_p;
+ const short *totcolp;
+
+ if (ob == NULL)
+ return NULL;
+
+ /* if object cannot have material, (totcolp == NULL) */
+ totcolp = give_totcolp(ob);
+ if (totcolp == NULL || ob->totcol == 0)
+ return NULL;
+
+ /* return NULL for invalid 'act', can happen for mesh face indices */
+ if (act > ob->totcol)
+ return NULL;
+ else if (act <= 0) {
+ if (act < 0) {
+ CLOG_ERROR(&LOG, "Negative material index!");
+ }
+ return NULL;
+ }
+
+ if (ob->matbits && ob->matbits[act - 1]) { /* in object */
+ ma_p = &ob->mat[act - 1];
+ }
+ else { /* in data */
+
+ /* check for inconsistency */
+ if (*totcolp < ob->totcol)
+ ob->totcol = *totcolp;
+ if (act > ob->totcol)
+ act = ob->totcol;
+
+ matarar = give_matarar(ob);
+
+ if (matarar && *matarar) {
+ ma_p = &(*matarar)[act - 1];
+ }
+ else {
+ ma_p = NULL;
+ }
+ }
+
+ return ma_p;
}
Material *give_current_material(Object *ob, short act)
{
- Material **ma_p = give_current_material_p(ob, act);
- return ma_p ? *ma_p : NULL;
+ Material **ma_p = give_current_material_p(ob, act);
+ return ma_p ? *ma_p : NULL;
}
MaterialGPencilStyle *BKE_material_gpencil_settings_get(Object *ob, short act)
{
- Material *ma = give_current_material(ob, act);
- if (ma != NULL) {
- if (ma->gp_style == NULL) {
- BKE_material_init_gpencil_settings(ma);
- }
-
- return ma->gp_style;
- }
- else {
- return NULL;
- }
+ Material *ma = give_current_material(ob, act);
+ if (ma != NULL) {
+ if (ma->gp_style == NULL) {
+ BKE_material_init_gpencil_settings(ma);
+ }
+
+ return ma->gp_style;
+ }
+ else {
+ return NULL;
+ }
}
Material *give_node_material(Material *ma)
{
- if (ma && ma->use_nodes && ma->nodetree) {
- bNode *node = nodeGetActiveID(ma->nodetree, ID_MA);
+ if (ma && ma->use_nodes && ma->nodetree) {
+ bNode *node = nodeGetActiveID(ma->nodetree, ID_MA);
- if (node)
- return (Material *)node->id;
- }
+ if (node)
+ return (Material *)node->id;
+ }
- return NULL;
+ return NULL;
}
void BKE_material_resize_object(Main *bmain, Object *ob, const short totcol, bool do_id_user)
{
- Material **newmatar;
- char *newmatbits;
-
- if (do_id_user && totcol < ob->totcol) {
- short i;
- for (i = totcol; i < ob->totcol; i++) {
- id_us_min((ID *)ob->mat[i]);
- }
- }
-
- if (totcol == 0) {
- if (ob->totcol) {
- MEM_freeN(ob->mat);
- MEM_freeN(ob->matbits);
- ob->mat = NULL;
- ob->matbits = NULL;
- }
- }
- else if (ob->totcol < totcol) {
- newmatar = MEM_callocN(sizeof(void *) * totcol, "newmatar");
- newmatbits = MEM_callocN(sizeof(char) * totcol, "newmatbits");
- if (ob->totcol) {
- memcpy(newmatar, ob->mat, sizeof(void *) * ob->totcol);
- memcpy(newmatbits, ob->matbits, sizeof(char) * ob->totcol);
- MEM_freeN(ob->mat);
- MEM_freeN(ob->matbits);
- }
- ob->mat = newmatar;
- ob->matbits = newmatbits;
- }
- /* XXX, why not realloc on shrink? - campbell */
-
- ob->totcol = totcol;
- if (ob->totcol && ob->actcol == 0) ob->actcol = 1;
- if (ob->actcol > ob->totcol) ob->actcol = ob->totcol;
-
- DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE | ID_RECALC_GEOMETRY);
- DEG_relations_tag_update(bmain);
+ Material **newmatar;
+ char *newmatbits;
+
+ if (do_id_user && totcol < ob->totcol) {
+ short i;
+ for (i = totcol; i < ob->totcol; i++) {
+ id_us_min((ID *)ob->mat[i]);
+ }
+ }
+
+ if (totcol == 0) {
+ if (ob->totcol) {
+ MEM_freeN(ob->mat);
+ MEM_freeN(ob->matbits);
+ ob->mat = NULL;
+ ob->matbits = NULL;
+ }
+ }
+ else if (ob->totcol < totcol) {
+ newmatar = MEM_callocN(sizeof(void *) * totcol, "newmatar");
+ newmatbits = MEM_callocN(sizeof(char) * totcol, "newmatbits");
+ if (ob->totcol) {
+ memcpy(newmatar, ob->mat, sizeof(void *) * ob->totcol);
+ memcpy(newmatbits, ob->matbits, sizeof(char) * ob->totcol);
+ MEM_freeN(ob->mat);
+ MEM_freeN(ob->matbits);
+ }
+ ob->mat = newmatar;
+ ob->matbits = newmatbits;
+ }
+ /* XXX, why not realloc on shrink? - campbell */
+
+ ob->totcol = totcol;
+ if (ob->totcol && ob->actcol == 0)
+ ob->actcol = 1;
+ if (ob->actcol > ob->totcol)
+ ob->actcol = ob->totcol;
+
+ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE | ID_RECALC_GEOMETRY);
+ DEG_relations_tag_update(bmain);
}
void test_object_materials(Main *bmain, Object *ob, ID *id)
{
- /* make the ob mat-array same size as 'ob->data' mat-array */
- const short *totcol;
+ /* make the ob mat-array same size as 'ob->data' mat-array */
+ const short *totcol;
- if (id == NULL || (totcol = give_totcolp_id(id)) == NULL) {
- return;
- }
+ if (id == NULL || (totcol = give_totcolp_id(id)) == NULL) {
+ return;
+ }
- BKE_material_resize_object(bmain, ob, *totcol, false);
+ BKE_material_resize_object(bmain, ob, *totcol, false);
}
void test_all_objects_materials(Main *bmain, ID *id)
{
- /* make the ob mat-array same size as 'ob->data' mat-array */
- Object *ob;
- const short *totcol;
-
- if (id == NULL || (totcol = give_totcolp_id(id)) == NULL) {
- return;
- }
-
- BKE_main_lock(bmain);
- for (ob = bmain->objects.first; ob; ob = ob->id.next) {
- if (ob->data == id) {
- BKE_material_resize_object(bmain, ob, *totcol, false);
- }
- }
- BKE_main_unlock(bmain);
+ /* make the ob mat-array same size as 'ob->data' mat-array */
+ Object *ob;
+ const short *totcol;
+
+ if (id == NULL || (totcol = give_totcolp_id(id)) == NULL) {
+ return;
+ }
+
+ BKE_main_lock(bmain);
+ for (ob = bmain->objects.first; ob; ob = ob->id.next) {
+ if (ob->data == id) {
+ BKE_material_resize_object(bmain, ob, *totcol, false);
+ }
+ }
+ BKE_main_unlock(bmain);
}
void assign_material_id(Main *bmain, ID *id, Material *ma, short act)
{
- Material *mao, **matar, ***matarar;
- short *totcolp;
+ Material *mao, **matar, ***matarar;
+ short *totcolp;
- if (act > MAXMAT) return;
- if (act < 1) act = 1;
+ if (act > MAXMAT)
+ return;
+ if (act < 1)
+ act = 1;
- /* test arraylens */
+ /* test arraylens */
- totcolp = give_totcolp_id(id);
- matarar = give_matarar_id(id);
+ totcolp = give_totcolp_id(id);
+ matarar = give_matarar_id(id);
- if (totcolp == NULL || matarar == NULL) return;
+ if (totcolp == NULL || matarar == NULL)
+ return;
- if (act > *totcolp) {
- matar = MEM_callocN(sizeof(void *) * act, "matarray1");
+ if (act > *totcolp) {
+ matar = MEM_callocN(sizeof(void *) * act, "matarray1");
- if (*totcolp) {
- memcpy(matar, *matarar, sizeof(void *) * (*totcolp));
- MEM_freeN(*matarar);
- }
+ if (*totcolp) {
+ memcpy(matar, *matarar, sizeof(void *) * (*totcolp));
+ MEM_freeN(*matarar);
+ }
- *matarar = matar;
- *totcolp = act;
- }
+ *matarar = matar;
+ *totcolp = act;
+ }
- /* in data */
- mao = (*matarar)[act - 1];
- if (mao)
- id_us_min(&mao->id);
- (*matarar)[act - 1] = ma;
+ /* in data */
+ mao = (*matarar)[act - 1];
+ if (mao)
+ id_us_min(&mao->id);
+ (*matarar)[act - 1] = ma;
- if (ma)
- id_us_plus(&ma->id);
+ if (ma)
+ id_us_plus(&ma->id);
- test_all_objects_materials(bmain, id);
+ test_all_objects_materials(bmain, id);
}
void assign_material(Main *bmain, Object *ob, Material *ma, short act, int assign_type)
{
- Material *mao, **matar, ***matarar;
- short *totcolp;
- char bit = 0;
-
- if (act > MAXMAT) return;
- if (act < 1) act = 1;
-
- /* prevent crashing when using accidentally */
- BLI_assert(!ID_IS_LINKED(ob));
- if (ID_IS_LINKED(ob)) return;
-
- /* test arraylens */
-
- totcolp = give_totcolp(ob);
- matarar = give_matarar(ob);
-
- if (totcolp == NULL || matarar == NULL) return;
-
- if (act > *totcolp) {
- matar = MEM_callocN(sizeof(void *) * act, "matarray1");
-
- if (*totcolp) {
- memcpy(matar, *matarar, sizeof(void *) * (*totcolp));
- MEM_freeN(*matarar);
- }
-
- *matarar = matar;
- *totcolp = act;
- }
-
- if (act > ob->totcol) {
- /* Need more space in the material arrays */
- ob->mat = MEM_recallocN_id(ob->mat, sizeof(void *) * act, "matarray2");
- ob->matbits = MEM_recallocN_id(ob->matbits, sizeof(char) * act, "matbits1");
- ob->totcol = act;
- }
-
- /* Determine the object/mesh linking */
- if (assign_type == BKE_MAT_ASSIGN_EXISTING) {
- /* keep existing option (avoid confusion in scripts),
- * intentionally ignore userpref (default to obdata). */
- bit = ob->matbits[act - 1];
- }
- else if (assign_type == BKE_MAT_ASSIGN_USERPREF && ob->totcol && ob->actcol) {
- /* copy from previous material */
- bit = ob->matbits[ob->actcol - 1];
- }
- else {
- switch (assign_type) {
- case BKE_MAT_ASSIGN_OBDATA:
- bit = 0;
- break;
- case BKE_MAT_ASSIGN_OBJECT:
- bit = 1;
- break;
- case BKE_MAT_ASSIGN_USERPREF:
- default:
- bit = (U.flag & USER_MAT_ON_OB) ? 1 : 0;
- break;
- }
- }
-
- /* do it */
-
- ob->matbits[act - 1] = bit;
- if (bit == 1) { /* in object */
- mao = ob->mat[act - 1];
- if (mao)
- id_us_min(&mao->id);
- ob->mat[act - 1] = ma;
- test_object_materials(bmain, ob, ob->data);
- }
- else { /* in data */
- mao = (*matarar)[act - 1];
- if (mao)
- id_us_min(&mao->id);
- (*matarar)[act - 1] = ma;
- test_all_objects_materials(bmain, ob->data); /* Data may be used by several objects... */
- }
-
- if (ma)
- id_us_plus(&ma->id);
+ Material *mao, **matar, ***matarar;
+ short *totcolp;
+ char bit = 0;
+
+ if (act > MAXMAT)
+ return;
+ if (act < 1)
+ act = 1;
+
+ /* prevent crashing when using accidentally */
+ BLI_assert(!ID_IS_LINKED(ob));
+ if (ID_IS_LINKED(ob))
+ return;
+
+ /* test arraylens */
+
+ totcolp = give_totcolp(ob);
+ matarar = give_matarar(ob);
+
+ if (totcolp == NULL || matarar == NULL)
+ return;
+
+ if (act > *totcolp) {
+ matar = MEM_callocN(sizeof(void *) * act, "matarray1");
+
+ if (*totcolp) {
+ memcpy(matar, *matarar, sizeof(void *) * (*totcolp));
+ MEM_freeN(*matarar);
+ }
+
+ *matarar = matar;
+ *totcolp = act;
+ }
+
+ if (act > ob->totcol) {
+ /* Need more space in the material arrays */
+ ob->mat = MEM_recallocN_id(ob->mat, sizeof(void *) * act, "matarray2");
+ ob->matbits = MEM_recallocN_id(ob->matbits, sizeof(char) * act, "matbits1");
+ ob->totcol = act;
+ }
+
+ /* Determine the object/mesh linking */
+ if (assign_type == BKE_MAT_ASSIGN_EXISTING) {
+ /* keep existing option (avoid confusion in scripts),
+ * intentionally ignore userpref (default to obdata). */
+ bit = ob->matbits[act - 1];
+ }
+ else if (assign_type == BKE_MAT_ASSIGN_USERPREF && ob->totcol && ob->actcol) {
+ /* copy from previous material */
+ bit = ob->matbits[ob->actcol - 1];
+ }
+ else {
+ switch (assign_type) {
+ case BKE_MAT_ASSIGN_OBDATA:
+ bit = 0;
+ break;
+ case BKE_MAT_ASSIGN_OBJECT:
+ bit = 1;
+ break;
+ case BKE_MAT_ASSIGN_USERPREF:
+ default:
+ bit = (U.flag & USER_MAT_ON_OB) ? 1 : 0;
+ break;
+ }
+ }
+
+ /* do it */
+
+ ob->matbits[act - 1] = bit;
+ if (bit == 1) { /* in object */
+ mao = ob->mat[act - 1];
+ if (mao)
+ id_us_min(&mao->id);
+ ob->mat[act - 1] = ma;
+ test_object_materials(bmain, ob, ob->data);
+ }
+ else { /* in data */
+ mao = (*matarar)[act - 1];
+ if (mao)
+ id_us_min(&mao->id);
+ (*matarar)[act - 1] = ma;
+ test_all_objects_materials(bmain, ob->data); /* Data may be used by several objects... */
+ }
+
+ if (ma)
+ id_us_plus(&ma->id);
}
-
void BKE_material_remap_object(Object *ob, const unsigned int *remap)
{
- Material ***matar = give_matarar(ob);
- const short *totcol_p = give_totcolp(ob);
-
- BLI_array_permute(ob->mat, ob->totcol, remap);
-
- if (ob->matbits) {
- BLI_array_permute(ob->matbits, ob->totcol, remap);
- }
-
- if (matar) {
- BLI_array_permute(*matar, *totcol_p, remap);
- }
-
- if (ob->type == OB_MESH) {
- BKE_mesh_material_remap(ob->data, remap, ob->totcol);
- }
- else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
- BKE_curve_material_remap(ob->data, remap, ob->totcol);
- }
- else if (ob->type == OB_GPENCIL) {
- BKE_gpencil_material_remap(ob->data, remap, ob->totcol);
- }
- else {
- /* add support for this object data! */
- BLI_assert(matar == NULL);
- }
+ Material ***matar = give_matarar(ob);
+ const short *totcol_p = give_totcolp(ob);
+
+ BLI_array_permute(ob->mat, ob->totcol, remap);
+
+ if (ob->matbits) {
+ BLI_array_permute(ob->matbits, ob->totcol, remap);
+ }
+
+ if (matar) {
+ BLI_array_permute(*matar, *totcol_p, remap);
+ }
+
+ if (ob->type == OB_MESH) {
+ BKE_mesh_material_remap(ob->data, remap, ob->totcol);
+ }
+ else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
+ BKE_curve_material_remap(ob->data, remap, ob->totcol);
+ }
+ else if (ob->type == OB_GPENCIL) {
+ BKE_gpencil_material_remap(ob->data, remap, ob->totcol);
+ }
+ else {
+ /* add support for this object data! */
+ BLI_assert(matar == NULL);
+ }
}
/**
@@ -815,550 +828,553 @@ void BKE_material_remap_object(Object *ob, const unsigned int *remap)
* \param remap_src_to_dst: An array the size of `ob_src->totcol`
* where index values are filled in which map to \a ob_dst materials.
*/
-void BKE_material_remap_object_calc(
- Object *ob_dst, Object *ob_src,
- short *remap_src_to_dst)
+void BKE_material_remap_object_calc(Object *ob_dst, Object *ob_src, short *remap_src_to_dst)
{
- if (ob_src->totcol == 0) {
- return;
- }
-
- GHash *gh_mat_map = BLI_ghash_ptr_new_ex(__func__, ob_src->totcol);
-
- for (int i = 0; i < ob_dst->totcol; i++) {
- Material *ma_src = give_current_material(ob_dst, i + 1);
- BLI_ghash_reinsert(gh_mat_map, ma_src, POINTER_FROM_INT(i), NULL, NULL);
- }
-
- /* setup default mapping (when materials don't match) */
- {
- int i = 0;
- if (ob_dst->totcol >= ob_src->totcol) {
- for (; i < ob_src->totcol; i++) {
- remap_src_to_dst[i] = i;
- }
- }
- else {
- for (; i < ob_dst->totcol; i++) {
- remap_src_to_dst[i] = i;
- }
- for (; i < ob_src->totcol; i++) {
- remap_src_to_dst[i] = 0;
- }
- }
- }
-
- for (int i = 0; i < ob_src->totcol; i++) {
- Material *ma_src = give_current_material(ob_src, i + 1);
-
- if ((i < ob_dst->totcol) && (ma_src == give_current_material(ob_dst, i + 1))) {
- /* when objects have exact matching materials - keep existing index */
- }
- else {
- void **index_src_p = BLI_ghash_lookup_p(gh_mat_map, ma_src);
- if (index_src_p) {
- remap_src_to_dst[i] = POINTER_AS_INT(*index_src_p);
- }
- }
- }
-
- BLI_ghash_free(gh_mat_map, NULL, NULL);
+ if (ob_src->totcol == 0) {
+ return;
+ }
+
+ GHash *gh_mat_map = BLI_ghash_ptr_new_ex(__func__, ob_src->totcol);
+
+ for (int i = 0; i < ob_dst->totcol; i++) {
+ Material *ma_src = give_current_material(ob_dst, i + 1);
+ BLI_ghash_reinsert(gh_mat_map, ma_src, POINTER_FROM_INT(i), NULL, NULL);
+ }
+
+ /* setup default mapping (when materials don't match) */
+ {
+ int i = 0;
+ if (ob_dst->totcol >= ob_src->totcol) {
+ for (; i < ob_src->totcol; i++) {
+ remap_src_to_dst[i] = i;
+ }
+ }
+ else {
+ for (; i < ob_dst->totcol; i++) {
+ remap_src_to_dst[i] = i;
+ }
+ for (; i < ob_src->totcol; i++) {
+ remap_src_to_dst[i] = 0;
+ }
+ }
+ }
+
+ for (int i = 0; i < ob_src->totcol; i++) {
+ Material *ma_src = give_current_material(ob_src, i + 1);
+
+ if ((i < ob_dst->totcol) && (ma_src == give_current_material(ob_dst, i + 1))) {
+ /* when objects have exact matching materials - keep existing index */
+ }
+ else {
+ void **index_src_p = BLI_ghash_lookup_p(gh_mat_map, ma_src);
+ if (index_src_p) {
+ remap_src_to_dst[i] = POINTER_AS_INT(*index_src_p);
+ }
+ }
+ }
+
+ BLI_ghash_free(gh_mat_map, NULL, NULL);
}
-
/* XXX - this calls many more update calls per object then are needed, could be optimized */
void assign_matarar(Main *bmain, struct Object *ob, struct Material ***matar, short totcol)
{
- int actcol_orig = ob->actcol;
- short i;
+ int actcol_orig = ob->actcol;
+ short i;
- while ((ob->totcol > totcol) &&
- BKE_object_material_slot_remove(bmain, ob))
- {
- /* pass */
- }
+ while ((ob->totcol > totcol) && BKE_object_material_slot_remove(bmain, ob)) {
+ /* pass */
+ }
- /* now we have the right number of slots */
- for (i = 0; i < totcol; i++)
- assign_material(bmain, ob, (*matar)[i], i + 1, BKE_MAT_ASSIGN_USERPREF);
+ /* now we have the right number of slots */
+ for (i = 0; i < totcol; i++)
+ assign_material(bmain, ob, (*matar)[i], i + 1, BKE_MAT_ASSIGN_USERPREF);
- if (actcol_orig > ob->totcol)
- actcol_orig = ob->totcol;
+ if (actcol_orig > ob->totcol)
+ actcol_orig = ob->totcol;
- ob->actcol = actcol_orig;
+ ob->actcol = actcol_orig;
}
-
short BKE_object_material_slot_find_index(Object *ob, Material *ma)
{
- Material ***matarar;
- short a, *totcolp;
+ Material ***matarar;
+ short a, *totcolp;
- if (ma == NULL) return 0;
+ if (ma == NULL)
+ return 0;
- totcolp = give_totcolp(ob);
- matarar = give_matarar(ob);
+ totcolp = give_totcolp(ob);
+ matarar = give_matarar(ob);
- if (totcolp == NULL || matarar == NULL) return 0;
+ if (totcolp == NULL || matarar == NULL)
+ return 0;
- for (a = 0; a < *totcolp; a++)
- if ((*matarar)[a] == ma)
- break;
- if (a < *totcolp)
- return a + 1;
- return 0;
+ for (a = 0; a < *totcolp; a++)
+ if ((*matarar)[a] == ma)
+ break;
+ if (a < *totcolp)
+ return a + 1;
+ return 0;
}
bool BKE_object_material_slot_add(Main *bmain, Object *ob)
{
- if (ob == NULL) return false;
- if (ob->totcol >= MAXMAT) return false;
-
- assign_material(bmain, ob, NULL, ob->totcol + 1, BKE_MAT_ASSIGN_USERPREF);
- ob->actcol = ob->totcol;
- return true;
+ if (ob == NULL)
+ return false;
+ if (ob->totcol >= MAXMAT)
+ return false;
+
+ assign_material(bmain, ob, NULL, ob->totcol + 1, BKE_MAT_ASSIGN_USERPREF);
+ ob->actcol = ob->totcol;
+ return true;
}
/* ****************** */
bool BKE_object_material_slot_remove(Main *bmain, Object *ob)
{
- Material *mao, ***matarar;
- short *totcolp;
- short a, actcol;
-
- if (ob == NULL || ob->totcol == 0) {
- return false;
- }
-
- /* this should never happen and used to crash */
- if (ob->actcol <= 0) {
- CLOG_ERROR(&LOG, "invalid material index %d, report a bug!", ob->actcol);
- BLI_assert(0);
- return false;
- }
-
- /* take a mesh/curve/mball as starting point, remove 1 index,
- * AND with all objects that share the ob->data
- *
- * after that check indices in mesh/curve/mball!!!
- */
-
- totcolp = give_totcolp(ob);
- matarar = give_matarar(ob);
-
- if (ELEM(NULL, matarar, *matarar)) {
- return false;
- }
-
- /* can happen on face selection in editmode */
- if (ob->actcol > ob->totcol) {
- ob->actcol = ob->totcol;
- }
-
- /* we delete the actcol */
- mao = (*matarar)[ob->actcol - 1];
- if (mao)
- id_us_min(&mao->id);
-
- for (a = ob->actcol; a < ob->totcol; a++)
- (*matarar)[a - 1] = (*matarar)[a];
- (*totcolp)--;
-
- if (*totcolp == 0) {
- MEM_freeN(*matarar);
- *matarar = NULL;
- }
-
- actcol = ob->actcol;
-
- for (Object *obt = bmain->objects.first; obt; obt = obt->id.next) {
- if (obt->data == ob->data) {
- /* Can happen when object material lists are used, see: T52953 */
- if (actcol > obt->totcol) {
- continue;
- }
- /* WATCH IT: do not use actcol from ob or from obt (can become zero) */
- mao = obt->mat[actcol - 1];
- if (mao)
- id_us_min(&mao->id);
-
- for (a = actcol; a < obt->totcol; a++) {
- obt->mat[a - 1] = obt->mat[a];
- obt->matbits[a - 1] = obt->matbits[a];
- }
- obt->totcol--;
- if (obt->actcol > obt->totcol) obt->actcol = obt->totcol;
-
- if (obt->totcol == 0) {
- MEM_freeN(obt->mat);
- MEM_freeN(obt->matbits);
- obt->mat = NULL;
- obt->matbits = NULL;
- }
- }
- }
-
- /* check indices from mesh */
- if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_GPENCIL)) {
- material_data_index_remove_id((ID *)ob->data, actcol - 1);
- if (ob->runtime.curve_cache) {
- BKE_displist_free(&ob->runtime.curve_cache->disp);
- }
- }
-
- return true;
+ Material *mao, ***matarar;
+ short *totcolp;
+ short a, actcol;
+
+ if (ob == NULL || ob->totcol == 0) {
+ return false;
+ }
+
+ /* this should never happen and used to crash */
+ if (ob->actcol <= 0) {
+ CLOG_ERROR(&LOG, "invalid material index %d, report a bug!", ob->actcol);
+ BLI_assert(0);
+ return false;
+ }
+
+ /* take a mesh/curve/mball as starting point, remove 1 index,
+ * AND with all objects that share the ob->data
+ *
+ * after that check indices in mesh/curve/mball!!!
+ */
+
+ totcolp = give_totcolp(ob);
+ matarar = give_matarar(ob);
+
+ if (ELEM(NULL, matarar, *matarar)) {
+ return false;
+ }
+
+ /* can happen on face selection in editmode */
+ if (ob->actcol > ob->totcol) {
+ ob->actcol = ob->totcol;
+ }
+
+ /* we delete the actcol */
+ mao = (*matarar)[ob->actcol - 1];
+ if (mao)
+ id_us_min(&mao->id);
+
+ for (a = ob->actcol; a < ob->totcol; a++)
+ (*matarar)[a - 1] = (*matarar)[a];
+ (*totcolp)--;
+
+ if (*totcolp == 0) {
+ MEM_freeN(*matarar);
+ *matarar = NULL;
+ }
+
+ actcol = ob->actcol;
+
+ for (Object *obt = bmain->objects.first; obt; obt = obt->id.next) {
+ if (obt->data == ob->data) {
+ /* Can happen when object material lists are used, see: T52953 */
+ if (actcol > obt->totcol) {
+ continue;
+ }
+ /* WATCH IT: do not use actcol from ob or from obt (can become zero) */
+ mao = obt->mat[actcol - 1];
+ if (mao)
+ id_us_min(&mao->id);
+
+ for (a = actcol; a < obt->totcol; a++) {
+ obt->mat[a - 1] = obt->mat[a];
+ obt->matbits[a - 1] = obt->matbits[a];
+ }
+ obt->totcol--;
+ if (obt->actcol > obt->totcol)
+ obt->actcol = obt->totcol;
+
+ if (obt->totcol == 0) {
+ MEM_freeN(obt->mat);
+ MEM_freeN(obt->matbits);
+ obt->mat = NULL;
+ obt->matbits = NULL;
+ }
+ }
+ }
+
+ /* check indices from mesh */
+ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_GPENCIL)) {
+ material_data_index_remove_id((ID *)ob->data, actcol - 1);
+ if (ob->runtime.curve_cache) {
+ BKE_displist_free(&ob->runtime.curve_cache->disp);
+ }
+ }
+
+ return true;
}
static bNode *nodetree_uv_node_recursive(bNode *node)
{
- bNode *inode;
- bNodeSocket *sock;
-
- for (sock = node->inputs.first; sock; sock = sock->next) {
- if (sock->link) {
- inode = sock->link->fromnode;
- if (inode->typeinfo->nclass == NODE_CLASS_INPUT && inode->typeinfo->type == SH_NODE_UVMAP) {
- return inode;
- }
- else {
- return nodetree_uv_node_recursive(inode);
- }
- }
- }
-
- return NULL;
+ bNode *inode;
+ bNodeSocket *sock;
+
+ for (sock = node->inputs.first; sock; sock = sock->next) {
+ if (sock->link) {
+ inode = sock->link->fromnode;
+ if (inode->typeinfo->nclass == NODE_CLASS_INPUT && inode->typeinfo->type == SH_NODE_UVMAP) {
+ return inode;
+ }
+ else {
+ return nodetree_uv_node_recursive(inode);
+ }
+ }
+ }
+
+ return NULL;
}
static int count_texture_nodes_recursive(bNodeTree *nodetree)
{
- int tex_nodes = 0;
-
- for (bNode *node = nodetree->nodes.first; node; node = node->next) {
- if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id) {
- tex_nodes++;
- }
- else if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id) {
- /* recurse into the node group and see if it contains any textures */
- tex_nodes += count_texture_nodes_recursive((bNodeTree *)node->id);
- }
- }
-
- return tex_nodes;
+ int tex_nodes = 0;
+
+ for (bNode *node = nodetree->nodes.first; node; node = node->next) {
+ if (node->typeinfo->nclass == NODE_CLASS_TEXTURE &&
+ node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id) {
+ tex_nodes++;
+ }
+ else if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id) {
+ /* recurse into the node group and see if it contains any textures */
+ tex_nodes += count_texture_nodes_recursive((bNodeTree *)node->id);
+ }
+ }
+
+ return tex_nodes;
}
-static void fill_texpaint_slots_recursive(bNodeTree *nodetree, bNode *active_node, Material *ma, int *index)
+static void fill_texpaint_slots_recursive(bNodeTree *nodetree,
+ bNode *active_node,
+ Material *ma,
+ int *index)
{
- for (bNode *node = nodetree->nodes.first; node; node = node->next) {
- if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id) {
- if (active_node == node) {
- ma->paint_active_slot = *index;
- }
-
- ma->texpaintslot[*index].ima = (Image *)node->id;
- ma->texpaintslot[*index].interp = ((NodeTexImage *)node->storage)->interpolation;
-
- /* for new renderer, we need to traverse the treeback in search of a UV node */
- bNode *uvnode = nodetree_uv_node_recursive(node);
-
- if (uvnode) {
- NodeShaderUVMap *storage = (NodeShaderUVMap *)uvnode->storage;
- ma->texpaintslot[*index].uvname = storage->uv_map;
- /* set a value to index so UI knows that we have a valid pointer for the mesh */
- ma->texpaintslot[*index].valid = true;
- }
- else {
- /* just invalidate the index here so UV map does not get displayed on the UI */
- ma->texpaintslot[*index].valid = false;
- }
- (*index)++;
- }
- else if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id) {
- /* recurse into the node group and see if it contains any textures */
- fill_texpaint_slots_recursive((bNodeTree *)node->id, active_node, ma, index);
- }
- }
+ for (bNode *node = nodetree->nodes.first; node; node = node->next) {
+ if (node->typeinfo->nclass == NODE_CLASS_TEXTURE &&
+ node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id) {
+ if (active_node == node) {
+ ma->paint_active_slot = *index;
+ }
+
+ ma->texpaintslot[*index].ima = (Image *)node->id;
+ ma->texpaintslot[*index].interp = ((NodeTexImage *)node->storage)->interpolation;
+
+ /* for new renderer, we need to traverse the treeback in search of a UV node */
+ bNode *uvnode = nodetree_uv_node_recursive(node);
+
+ if (uvnode) {
+ NodeShaderUVMap *storage = (NodeShaderUVMap *)uvnode->storage;
+ ma->texpaintslot[*index].uvname = storage->uv_map;
+ /* set a value to index so UI knows that we have a valid pointer for the mesh */
+ ma->texpaintslot[*index].valid = true;
+ }
+ else {
+ /* just invalidate the index here so UV map does not get displayed on the UI */
+ ma->texpaintslot[*index].valid = false;
+ }
+ (*index)++;
+ }
+ else if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id) {
+ /* recurse into the node group and see if it contains any textures */
+ fill_texpaint_slots_recursive((bNodeTree *)node->id, active_node, ma, index);
+ }
+ }
}
void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma)
{
- int count = 0;
- int index = 0;
+ int count = 0;
+ int index = 0;
- if (!ma)
- return;
+ if (!ma)
+ return;
- /* COW needed when adding texture slot on an object with no materials. */
- DEG_id_tag_update(&ma->id, ID_RECALC_SHADING | ID_RECALC_COPY_ON_WRITE);
+ /* COW needed when adding texture slot on an object with no materials. */
+ DEG_id_tag_update(&ma->id, ID_RECALC_SHADING | ID_RECALC_COPY_ON_WRITE);
- if (ma->texpaintslot) {
- MEM_freeN(ma->texpaintslot);
- ma->tot_slots = 0;
- ma->texpaintslot = NULL;
- }
+ if (ma->texpaintslot) {
+ MEM_freeN(ma->texpaintslot);
+ ma->tot_slots = 0;
+ ma->texpaintslot = NULL;
+ }
- if (scene->toolsettings->imapaint.mode == IMAGEPAINT_MODE_IMAGE) {
- ma->paint_active_slot = 0;
- ma->paint_clone_slot = 0;
- return;
- }
+ if (scene->toolsettings->imapaint.mode == IMAGEPAINT_MODE_IMAGE) {
+ ma->paint_active_slot = 0;
+ ma->paint_clone_slot = 0;
+ return;
+ }
- if (!(ma->nodetree)) {
- ma->paint_active_slot = 0;
- ma->paint_clone_slot = 0;
- return;
- }
+ if (!(ma->nodetree)) {
+ ma->paint_active_slot = 0;
+ ma->paint_clone_slot = 0;
+ return;
+ }
- count = count_texture_nodes_recursive(ma->nodetree);
+ count = count_texture_nodes_recursive(ma->nodetree);
- if (count == 0) {
- ma->paint_active_slot = 0;
- ma->paint_clone_slot = 0;
- return;
- }
+ if (count == 0) {
+ ma->paint_active_slot = 0;
+ ma->paint_clone_slot = 0;
+ return;
+ }
- ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots");
+ ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots");
- bNode *active_node = nodeGetActiveTexture(ma->nodetree);
+ bNode *active_node = nodeGetActiveTexture(ma->nodetree);
- fill_texpaint_slots_recursive(ma->nodetree, active_node, ma, &index);
+ fill_texpaint_slots_recursive(ma->nodetree, active_node, ma, &index);
- ma->tot_slots = count;
+ ma->tot_slots = count;
+ if (ma->paint_active_slot >= count) {
+ ma->paint_active_slot = count - 1;
+ }
- if (ma->paint_active_slot >= count) {
- ma->paint_active_slot = count - 1;
- }
+ if (ma->paint_clone_slot >= count) {
+ ma->paint_clone_slot = count - 1;
+ }
- if (ma->paint_clone_slot >= count) {
- ma->paint_clone_slot = count - 1;
- }
-
- return;
+ return;
}
void BKE_texpaint_slots_refresh_object(Scene *scene, struct Object *ob)
{
- int i;
+ int i;
- for (i = 1; i < ob->totcol + 1; i++) {
- Material *ma = give_current_material(ob, i);
- BKE_texpaint_slot_refresh_cache(scene, ma);
- }
+ for (i = 1; i < ob->totcol + 1; i++) {
+ Material *ma = give_current_material(ob, i);
+ BKE_texpaint_slot_refresh_cache(scene, ma);
+ }
}
-
/* r_col = current value, col = new value, (fac == 0) is no change */
void ramp_blend(int type, float r_col[3], const float fac, const float col[3])
{
- float tmp, facm = 1.0f - fac;
-
- switch (type) {
- case MA_RAMP_BLEND:
- r_col[0] = facm * (r_col[0]) + fac * col[0];
- r_col[1] = facm * (r_col[1]) + fac * col[1];
- r_col[2] = facm * (r_col[2]) + fac * col[2];
- break;
- case MA_RAMP_ADD:
- r_col[0] += fac * col[0];
- r_col[1] += fac * col[1];
- r_col[2] += fac * col[2];
- break;
- case MA_RAMP_MULT:
- r_col[0] *= (facm + fac * col[0]);
- r_col[1] *= (facm + fac * col[1]);
- r_col[2] *= (facm + fac * col[2]);
- break;
- case MA_RAMP_SCREEN:
- r_col[0] = 1.0f - (facm + fac * (1.0f - col[0])) * (1.0f - r_col[0]);
- r_col[1] = 1.0f - (facm + fac * (1.0f - col[1])) * (1.0f - r_col[1]);
- r_col[2] = 1.0f - (facm + fac * (1.0f - col[2])) * (1.0f - r_col[2]);
- break;
- case MA_RAMP_OVERLAY:
- if (r_col[0] < 0.5f)
- r_col[0] *= (facm + 2.0f * fac * col[0]);
- else
- r_col[0] = 1.0f - (facm + 2.0f * fac * (1.0f - col[0])) * (1.0f - r_col[0]);
- if (r_col[1] < 0.5f)
- r_col[1] *= (facm + 2.0f * fac * col[1]);
- else
- r_col[1] = 1.0f - (facm + 2.0f * fac * (1.0f - col[1])) * (1.0f - r_col[1]);
- if (r_col[2] < 0.5f)
- r_col[2] *= (facm + 2.0f * fac * col[2]);
- else
- r_col[2] = 1.0f - (facm + 2.0f * fac * (1.0f - col[2])) * (1.0f - r_col[2]);
- break;
- case MA_RAMP_SUB:
- r_col[0] -= fac * col[0];
- r_col[1] -= fac * col[1];
- r_col[2] -= fac * col[2];
- break;
- case MA_RAMP_DIV:
- if (col[0] != 0.0f)
- r_col[0] = facm * (r_col[0]) + fac * (r_col[0]) / col[0];
- if (col[1] != 0.0f)
- r_col[1] = facm * (r_col[1]) + fac * (r_col[1]) / col[1];
- if (col[2] != 0.0f)
- r_col[2] = facm * (r_col[2]) + fac * (r_col[2]) / col[2];
- break;
- case MA_RAMP_DIFF:
- r_col[0] = facm * (r_col[0]) + fac * fabsf(r_col[0] - col[0]);
- r_col[1] = facm * (r_col[1]) + fac * fabsf(r_col[1] - col[1]);
- r_col[2] = facm * (r_col[2]) + fac * fabsf(r_col[2] - col[2]);
- break;
- case MA_RAMP_DARK:
- r_col[0] = min_ff(r_col[0], col[0]) * fac + r_col[0] * facm;
- r_col[1] = min_ff(r_col[1], col[1]) * fac + r_col[1] * facm;
- r_col[2] = min_ff(r_col[2], col[2]) * fac + r_col[2] * facm;
- break;
- case MA_RAMP_LIGHT:
- tmp = fac * col[0];
- if (tmp > r_col[0]) r_col[0] = tmp;
- tmp = fac * col[1];
- if (tmp > r_col[1]) r_col[1] = tmp;
- tmp = fac * col[2];
- if (tmp > r_col[2]) r_col[2] = tmp;
- break;
- case MA_RAMP_DODGE:
- if (r_col[0] != 0.0f) {
- tmp = 1.0f - fac * col[0];
- if (tmp <= 0.0f)
- r_col[0] = 1.0f;
- else if ((tmp = (r_col[0]) / tmp) > 1.0f)
- r_col[0] = 1.0f;
- else
- r_col[0] = tmp;
- }
- if (r_col[1] != 0.0f) {
- tmp = 1.0f - fac * col[1];
- if (tmp <= 0.0f)
- r_col[1] = 1.0f;
- else if ((tmp = (r_col[1]) / tmp) > 1.0f)
- r_col[1] = 1.0f;
- else
- r_col[1] = tmp;
- }
- if (r_col[2] != 0.0f) {
- tmp = 1.0f - fac * col[2];
- if (tmp <= 0.0f)
- r_col[2] = 1.0f;
- else if ((tmp = (r_col[2]) / tmp) > 1.0f)
- r_col[2] = 1.0f;
- else
- r_col[2] = tmp;
- }
- break;
- case MA_RAMP_BURN:
- tmp = facm + fac * col[0];
-
- if (tmp <= 0.0f)
- r_col[0] = 0.0f;
- else if ((tmp = (1.0f - (1.0f - (r_col[0])) / tmp)) < 0.0f)
- r_col[0] = 0.0f;
- else if (tmp > 1.0f)
- r_col[0] = 1.0f;
- else
- r_col[0] = tmp;
-
- tmp = facm + fac * col[1];
- if (tmp <= 0.0f)
- r_col[1] = 0.0f;
- else if ((tmp = (1.0f - (1.0f - (r_col[1])) / tmp)) < 0.0f)
- r_col[1] = 0.0f;
- else if (tmp > 1.0f)
- r_col[1] = 1.0f;
- else
- r_col[1] = tmp;
-
- tmp = facm + fac * col[2];
- if (tmp <= 0.0f)
- r_col[2] = 0.0f;
- else if ((tmp = (1.0f - (1.0f - (r_col[2])) / tmp)) < 0.0f)
- r_col[2] = 0.0f;
- else if (tmp > 1.0f)
- r_col[2] = 1.0f;
- else
- r_col[2] = tmp;
- break;
- case MA_RAMP_HUE:
- {
- float rH, rS, rV;
- float colH, colS, colV;
- float tmpr, tmpg, tmpb;
- rgb_to_hsv(col[0], col[1], col[2], &colH, &colS, &colV);
- if (colS != 0) {
- rgb_to_hsv(r_col[0], r_col[1], r_col[2], &rH, &rS, &rV);
- hsv_to_rgb(colH, rS, rV, &tmpr, &tmpg, &tmpb);
- r_col[0] = facm * (r_col[0]) + fac * tmpr;
- r_col[1] = facm * (r_col[1]) + fac * tmpg;
- r_col[2] = facm * (r_col[2]) + fac * tmpb;
- }
- break;
- }
- case MA_RAMP_SAT:
- {
- float rH, rS, rV;
- float colH, colS, colV;
- rgb_to_hsv(r_col[0], r_col[1], r_col[2], &rH, &rS, &rV);
- if (rS != 0) {
- rgb_to_hsv(col[0], col[1], col[2], &colH, &colS, &colV);
- hsv_to_rgb(rH, (facm * rS + fac * colS), rV, r_col + 0, r_col + 1, r_col + 2);
- }
- break;
- }
- case MA_RAMP_VAL:
- {
- float rH, rS, rV;
- float colH, colS, colV;
- rgb_to_hsv(r_col[0], r_col[1], r_col[2], &rH, &rS, &rV);
- rgb_to_hsv(col[0], col[1], col[2], &colH, &colS, &colV);
- hsv_to_rgb(rH, rS, (facm * rV + fac * colV), r_col + 0, r_col + 1, r_col + 2);
- break;
- }
- case MA_RAMP_COLOR:
- {
- float rH, rS, rV;
- float colH, colS, colV;
- float tmpr, tmpg, tmpb;
- rgb_to_hsv(col[0], col[1], col[2], &colH, &colS, &colV);
- if (colS != 0) {
- rgb_to_hsv(r_col[0], r_col[1], r_col[2], &rH, &rS, &rV);
- hsv_to_rgb(colH, colS, rV, &tmpr, &tmpg, &tmpb);
- r_col[0] = facm * (r_col[0]) + fac * tmpr;
- r_col[1] = facm * (r_col[1]) + fac * tmpg;
- r_col[2] = facm * (r_col[2]) + fac * tmpb;
- }
- break;
- }
- case MA_RAMP_SOFT:
- {
- float scr, scg, scb;
-
- /* first calculate non-fac based Screen mix */
- scr = 1.0f - (1.0f - col[0]) * (1.0f - r_col[0]);
- scg = 1.0f - (1.0f - col[1]) * (1.0f - r_col[1]);
- scb = 1.0f - (1.0f - col[2]) * (1.0f - r_col[2]);
-
- r_col[0] = facm * (r_col[0]) + fac * (((1.0f - r_col[0]) * col[0] * (r_col[0])) + (r_col[0] * scr));
- r_col[1] = facm * (r_col[1]) + fac * (((1.0f - r_col[1]) * col[1] * (r_col[1])) + (r_col[1] * scg));
- r_col[2] = facm * (r_col[2]) + fac * (((1.0f - r_col[2]) * col[2] * (r_col[2])) + (r_col[2] * scb));
- break;
- }
- case MA_RAMP_LINEAR:
- if (col[0] > 0.5f)
- r_col[0] = r_col[0] + fac * (2.0f * (col[0] - 0.5f));
- else
- r_col[0] = r_col[0] + fac * (2.0f * (col[0]) - 1.0f);
- if (col[1] > 0.5f)
- r_col[1] = r_col[1] + fac * (2.0f * (col[1] - 0.5f));
- else
- r_col[1] = r_col[1] + fac * (2.0f * (col[1]) - 1.0f);
- if (col[2] > 0.5f)
- r_col[2] = r_col[2] + fac * (2.0f * (col[2] - 0.5f));
- else
- r_col[2] = r_col[2] + fac * (2.0f * (col[2]) - 1.0f);
- break;
- }
+ float tmp, facm = 1.0f - fac;
+
+ switch (type) {
+ case MA_RAMP_BLEND:
+ r_col[0] = facm * (r_col[0]) + fac * col[0];
+ r_col[1] = facm * (r_col[1]) + fac * col[1];
+ r_col[2] = facm * (r_col[2]) + fac * col[2];
+ break;
+ case MA_RAMP_ADD:
+ r_col[0] += fac * col[0];
+ r_col[1] += fac * col[1];
+ r_col[2] += fac * col[2];
+ break;
+ case MA_RAMP_MULT:
+ r_col[0] *= (facm + fac * col[0]);
+ r_col[1] *= (facm + fac * col[1]);
+ r_col[2] *= (facm + fac * col[2]);
+ break;
+ case MA_RAMP_SCREEN:
+ r_col[0] = 1.0f - (facm + fac * (1.0f - col[0])) * (1.0f - r_col[0]);
+ r_col[1] = 1.0f - (facm + fac * (1.0f - col[1])) * (1.0f - r_col[1]);
+ r_col[2] = 1.0f - (facm + fac * (1.0f - col[2])) * (1.0f - r_col[2]);
+ break;
+ case MA_RAMP_OVERLAY:
+ if (r_col[0] < 0.5f)
+ r_col[0] *= (facm + 2.0f * fac * col[0]);
+ else
+ r_col[0] = 1.0f - (facm + 2.0f * fac * (1.0f - col[0])) * (1.0f - r_col[0]);
+ if (r_col[1] < 0.5f)
+ r_col[1] *= (facm + 2.0f * fac * col[1]);
+ else
+ r_col[1] = 1.0f - (facm + 2.0f * fac * (1.0f - col[1])) * (1.0f - r_col[1]);
+ if (r_col[2] < 0.5f)
+ r_col[2] *= (facm + 2.0f * fac * col[2]);
+ else
+ r_col[2] = 1.0f - (facm + 2.0f * fac * (1.0f - col[2])) * (1.0f - r_col[2]);
+ break;
+ case MA_RAMP_SUB:
+ r_col[0] -= fac * col[0];
+ r_col[1] -= fac * col[1];
+ r_col[2] -= fac * col[2];
+ break;
+ case MA_RAMP_DIV:
+ if (col[0] != 0.0f)
+ r_col[0] = facm * (r_col[0]) + fac * (r_col[0]) / col[0];
+ if (col[1] != 0.0f)
+ r_col[1] = facm * (r_col[1]) + fac * (r_col[1]) / col[1];
+ if (col[2] != 0.0f)
+ r_col[2] = facm * (r_col[2]) + fac * (r_col[2]) / col[2];
+ break;
+ case MA_RAMP_DIFF:
+ r_col[0] = facm * (r_col[0]) + fac * fabsf(r_col[0] - col[0]);
+ r_col[1] = facm * (r_col[1]) + fac * fabsf(r_col[1] - col[1]);
+ r_col[2] = facm * (r_col[2]) + fac * fabsf(r_col[2] - col[2]);
+ break;
+ case MA_RAMP_DARK:
+ r_col[0] = min_ff(r_col[0], col[0]) * fac + r_col[0] * facm;
+ r_col[1] = min_ff(r_col[1], col[1]) * fac + r_col[1] * facm;
+ r_col[2] = min_ff(r_col[2], col[2]) * fac + r_col[2] * facm;
+ break;
+ case MA_RAMP_LIGHT:
+ tmp = fac * col[0];
+ if (tmp > r_col[0])
+ r_col[0] = tmp;
+ tmp = fac * col[1];
+ if (tmp > r_col[1])
+ r_col[1] = tmp;
+ tmp = fac * col[2];
+ if (tmp > r_col[2])
+ r_col[2] = tmp;
+ break;
+ case MA_RAMP_DODGE:
+ if (r_col[0] != 0.0f) {
+ tmp = 1.0f - fac * col[0];
+ if (tmp <= 0.0f)
+ r_col[0] = 1.0f;
+ else if ((tmp = (r_col[0]) / tmp) > 1.0f)
+ r_col[0] = 1.0f;
+ else
+ r_col[0] = tmp;
+ }
+ if (r_col[1] != 0.0f) {
+ tmp = 1.0f - fac * col[1];
+ if (tmp <= 0.0f)
+ r_col[1] = 1.0f;
+ else if ((tmp = (r_col[1]) / tmp) > 1.0f)
+ r_col[1] = 1.0f;
+ else
+ r_col[1] = tmp;
+ }
+ if (r_col[2] != 0.0f) {
+ tmp = 1.0f - fac * col[2];
+ if (tmp <= 0.0f)
+ r_col[2] = 1.0f;
+ else if ((tmp = (r_col[2]) / tmp) > 1.0f)
+ r_col[2] = 1.0f;
+ else
+ r_col[2] = tmp;
+ }
+ break;
+ case MA_RAMP_BURN:
+ tmp = facm + fac * col[0];
+
+ if (tmp <= 0.0f)
+ r_col[0] = 0.0f;
+ else if ((tmp = (1.0f - (1.0f - (r_col[0])) / tmp)) < 0.0f)
+ r_col[0] = 0.0f;
+ else if (tmp > 1.0f)
+ r_col[0] = 1.0f;
+ else
+ r_col[0] = tmp;
+
+ tmp = facm + fac * col[1];
+ if (tmp <= 0.0f)
+ r_col[1] = 0.0f;
+ else if ((tmp = (1.0f - (1.0f - (r_col[1])) / tmp)) < 0.0f)
+ r_col[1] = 0.0f;
+ else if (tmp > 1.0f)
+ r_col[1] = 1.0f;
+ else
+ r_col[1] = tmp;
+
+ tmp = facm + fac * col[2];
+ if (tmp <= 0.0f)
+ r_col[2] = 0.0f;
+ else if ((tmp = (1.0f - (1.0f - (r_col[2])) / tmp)) < 0.0f)
+ r_col[2] = 0.0f;
+ else if (tmp > 1.0f)
+ r_col[2] = 1.0f;
+ else
+ r_col[2] = tmp;
+ break;
+ case MA_RAMP_HUE: {
+ float rH, rS, rV;
+ float colH, colS, colV;
+ float tmpr, tmpg, tmpb;
+ rgb_to_hsv(col[0], col[1], col[2], &colH, &colS, &colV);
+ if (colS != 0) {
+ rgb_to_hsv(r_col[0], r_col[1], r_col[2], &rH, &rS, &rV);
+ hsv_to_rgb(colH, rS, rV, &tmpr, &tmpg, &tmpb);
+ r_col[0] = facm * (r_col[0]) + fac * tmpr;
+ r_col[1] = facm * (r_col[1]) + fac * tmpg;
+ r_col[2] = facm * (r_col[2]) + fac * tmpb;
+ }
+ break;
+ }
+ case MA_RAMP_SAT: {
+ float rH, rS, rV;
+ float colH, colS, colV;
+ rgb_to_hsv(r_col[0], r_col[1], r_col[2], &rH, &rS, &rV);
+ if (rS != 0) {
+ rgb_to_hsv(col[0], col[1], col[2], &colH, &colS, &colV);
+ hsv_to_rgb(rH, (facm * rS + fac * colS), rV, r_col + 0, r_col + 1, r_col + 2);
+ }
+ break;
+ }
+ case MA_RAMP_VAL: {
+ float rH, rS, rV;
+ float colH, colS, colV;
+ rgb_to_hsv(r_col[0], r_col[1], r_col[2], &rH, &rS, &rV);
+ rgb_to_hsv(col[0], col[1], col[2], &colH, &colS, &colV);
+ hsv_to_rgb(rH, rS, (facm * rV + fac * colV), r_col + 0, r_col + 1, r_col + 2);
+ break;
+ }
+ case MA_RAMP_COLOR: {
+ float rH, rS, rV;
+ float colH, colS, colV;
+ float tmpr, tmpg, tmpb;
+ rgb_to_hsv(col[0], col[1], col[2], &colH, &colS, &colV);
+ if (colS != 0) {
+ rgb_to_hsv(r_col[0], r_col[1], r_col[2], &rH, &rS, &rV);
+ hsv_to_rgb(colH, colS, rV, &tmpr, &tmpg, &tmpb);
+ r_col[0] = facm * (r_col[0]) + fac * tmpr;
+ r_col[1] = facm * (r_col[1]) + fac * tmpg;
+ r_col[2] = facm * (r_col[2]) + fac * tmpb;
+ }
+ break;
+ }
+ case MA_RAMP_SOFT: {
+ float scr, scg, scb;
+
+ /* first calculate non-fac based Screen mix */
+ scr = 1.0f - (1.0f - col[0]) * (1.0f - r_col[0]);
+ scg = 1.0f - (1.0f - col[1]) * (1.0f - r_col[1]);
+ scb = 1.0f - (1.0f - col[2]) * (1.0f - r_col[2]);
+
+ r_col[0] = facm * (r_col[0]) +
+ fac * (((1.0f - r_col[0]) * col[0] * (r_col[0])) + (r_col[0] * scr));
+ r_col[1] = facm * (r_col[1]) +
+ fac * (((1.0f - r_col[1]) * col[1] * (r_col[1])) + (r_col[1] * scg));
+ r_col[2] = facm * (r_col[2]) +
+ fac * (((1.0f - r_col[2]) * col[2] * (r_col[2])) + (r_col[2] * scb));
+ break;
+ }
+ case MA_RAMP_LINEAR:
+ if (col[0] > 0.5f)
+ r_col[0] = r_col[0] + fac * (2.0f * (col[0] - 0.5f));
+ else
+ r_col[0] = r_col[0] + fac * (2.0f * (col[0]) - 1.0f);
+ if (col[1] > 0.5f)
+ r_col[1] = r_col[1] + fac * (2.0f * (col[1] - 0.5f));
+ else
+ r_col[1] = r_col[1] + fac * (2.0f * (col[1]) - 1.0f);
+ if (col[2] > 0.5f)
+ r_col[2] = r_col[2] + fac * (2.0f * (col[2] - 0.5f));
+ else
+ r_col[2] = r_col[2] + fac * (2.0f * (col[2]) - 1.0f);
+ break;
+ }
}
/**
@@ -1371,64 +1387,64 @@ static short matcopied = 0;
void clear_matcopybuf(void)
{
- memset(&matcopybuf, 0, sizeof(Material));
- matcopied = 0;
+ memset(&matcopybuf, 0, sizeof(Material));
+ matcopied = 0;
}
void free_matcopybuf(void)
{
- if (matcopybuf.nodetree) {
- ntreeFreeLocalTree(matcopybuf.nodetree);
- MEM_freeN(matcopybuf.nodetree);
- matcopybuf.nodetree = NULL;
- }
+ if (matcopybuf.nodetree) {
+ ntreeFreeLocalTree(matcopybuf.nodetree);
+ MEM_freeN(matcopybuf.nodetree);
+ matcopybuf.nodetree = NULL;
+ }
- matcopied = 0;
+ matcopied = 0;
}
void copy_matcopybuf(Main *bmain, Material *ma)
{
- if (matcopied)
- free_matcopybuf();
+ if (matcopied)
+ free_matcopybuf();
- memcpy(&matcopybuf, ma, sizeof(Material));
+ memcpy(&matcopybuf, ma, sizeof(Material));
- if (ma->nodetree != NULL) {
- matcopybuf.nodetree = ntreeCopyTree_ex(ma->nodetree, bmain, false);
- }
+ if (ma->nodetree != NULL) {
+ matcopybuf.nodetree = ntreeCopyTree_ex(ma->nodetree, bmain, false);
+ }
- matcopybuf.preview = NULL;
- BLI_listbase_clear(&matcopybuf.gpumaterial);
- /* TODO Duplicate Engine Settings and set runtime to NULL */
- matcopied = 1;
+ matcopybuf.preview = NULL;
+ BLI_listbase_clear(&matcopybuf.gpumaterial);
+ /* TODO Duplicate Engine Settings and set runtime to NULL */
+ matcopied = 1;
}
void paste_matcopybuf(Main *bmain, Material *ma)
{
- ID id;
+ ID id;
- if (matcopied == 0)
- return;
+ if (matcopied == 0)
+ return;
- /* Free gpu material before the ntree */
- GPU_material_free(&ma->gpumaterial);
+ /* Free gpu material before the ntree */
+ GPU_material_free(&ma->gpumaterial);
- if (ma->nodetree) {
- ntreeFreeNestedTree(ma->nodetree);
- MEM_freeN(ma->nodetree);
- }
+ if (ma->nodetree) {
+ ntreeFreeNestedTree(ma->nodetree);
+ MEM_freeN(ma->nodetree);
+ }
- id = (ma->id);
- memcpy(ma, &matcopybuf, sizeof(Material));
- (ma->id) = id;
+ id = (ma->id);
+ memcpy(ma, &matcopybuf, sizeof(Material));
+ (ma->id) = id;
- if (matcopybuf.nodetree != NULL) {
- ma->nodetree = ntreeCopyTree_ex(matcopybuf.nodetree, bmain, false);
- }
+ if (matcopybuf.nodetree != NULL) {
+ ma->nodetree = ntreeCopyTree_ex(matcopybuf.nodetree, bmain, false);
+ }
}
void BKE_material_eval(struct Depsgraph *depsgraph, Material *material)
{
- DEG_debug_print_eval(depsgraph, __func__, material->id.name, material);
- GPU_material_free(&material->gpumaterial);
+ DEG_debug_print_eval(depsgraph, __func__, material->id.name, material);
+ GPU_material_free(&material->gpumaterial);
}
diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c
index 6a28c341fac..8ab042d5446 100644
--- a/source/blender/blenkernel/intern/mball.c
+++ b/source/blender/blenkernel/intern/mball.c
@@ -63,37 +63,38 @@
/** Free (or release) any data used by this mball (does not free the mball itself). */
void BKE_mball_free(MetaBall *mb)
{
- BKE_animdata_free((ID *)mb, false);
+ BKE_animdata_free((ID *)mb, false);
- BKE_mball_batch_cache_free(mb);
+ BKE_mball_batch_cache_free(mb);
- MEM_SAFE_FREE(mb->mat);
+ MEM_SAFE_FREE(mb->mat);
- BLI_freelistN(&mb->elems);
- if (mb->disp.first) BKE_displist_free(&mb->disp);
+ BLI_freelistN(&mb->elems);
+ if (mb->disp.first)
+ BKE_displist_free(&mb->disp);
}
void BKE_mball_init(MetaBall *mb)
{
- BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(mb, id));
+ BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(mb, id));
- mb->size[0] = mb->size[1] = mb->size[2] = 1.0;
- mb->texflag = MB_AUTOSPACE;
+ mb->size[0] = mb->size[1] = mb->size[2] = 1.0;
+ mb->texflag = MB_AUTOSPACE;
- mb->wiresize = 0.4f;
- mb->rendersize = 0.2f;
- mb->thresh = 0.6f;
+ mb->wiresize = 0.4f;
+ mb->rendersize = 0.2f;
+ mb->thresh = 0.6f;
}
MetaBall *BKE_mball_add(Main *bmain, const char *name)
{
- MetaBall *mb;
+ MetaBall *mb;
- mb = BKE_libblock_alloc(bmain, ID_MB, name, 0);
+ mb = BKE_libblock_alloc(bmain, ID_MB, name, 0);
- BKE_mball_init(mb);
+ BKE_mball_init(mb);
- return mb;
+ return mb;
}
/**
@@ -104,76 +105,79 @@ MetaBall *BKE_mball_add(Main *bmain, const char *name)
*
* \param flag: Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
*/
-void BKE_mball_copy_data(Main *UNUSED(bmain), MetaBall *mb_dst, const MetaBall *mb_src, const int UNUSED(flag))
+void BKE_mball_copy_data(Main *UNUSED(bmain),
+ MetaBall *mb_dst,
+ const MetaBall *mb_src,
+ const int UNUSED(flag))
{
- BLI_duplicatelist(&mb_dst->elems, &mb_src->elems);
+ BLI_duplicatelist(&mb_dst->elems, &mb_src->elems);
- mb_dst->mat = MEM_dupallocN(mb_src->mat);
+ mb_dst->mat = MEM_dupallocN(mb_src->mat);
- mb_dst->editelems = NULL;
- mb_dst->lastelem = NULL;
- mb_dst->batch_cache = NULL;
+ mb_dst->editelems = NULL;
+ mb_dst->lastelem = NULL;
+ mb_dst->batch_cache = NULL;
}
MetaBall *BKE_mball_copy(Main *bmain, const MetaBall *mb)
{
- MetaBall *mb_copy;
- BKE_id_copy(bmain, &mb->id, (ID **)&mb_copy);
- return mb_copy;
+ MetaBall *mb_copy;
+ BKE_id_copy(bmain, &mb->id, (ID **)&mb_copy);
+ return mb_copy;
}
void BKE_mball_make_local(Main *bmain, MetaBall *mb, const bool lib_local)
{
- BKE_id_make_local_generic(bmain, &mb->id, true, lib_local);
+ BKE_id_make_local_generic(bmain, &mb->id, true, lib_local);
}
/* most simple meta-element adding function
* don't do context manipulation here (rna uses) */
MetaElem *BKE_mball_element_add(MetaBall *mb, const int type)
{
- MetaElem *ml = MEM_callocN(sizeof(MetaElem), "metaelem");
+ MetaElem *ml = MEM_callocN(sizeof(MetaElem), "metaelem");
- unit_qt(ml->quat);
+ unit_qt(ml->quat);
- ml->rad = 2.0;
- ml->s = 2.0;
- ml->flag = MB_SCALE_RAD;
+ ml->rad = 2.0;
+ ml->s = 2.0;
+ ml->flag = MB_SCALE_RAD;
- switch (type) {
- case MB_BALL:
- ml->type = MB_BALL;
- ml->expx = ml->expy = ml->expz = 1.0;
+ switch (type) {
+ case MB_BALL:
+ ml->type = MB_BALL;
+ ml->expx = ml->expy = ml->expz = 1.0;
- break;
- case MB_TUBE:
- ml->type = MB_TUBE;
- ml->expx = ml->expy = ml->expz = 1.0;
+ break;
+ case MB_TUBE:
+ ml->type = MB_TUBE;
+ ml->expx = ml->expy = ml->expz = 1.0;
- break;
- case MB_PLANE:
- ml->type = MB_PLANE;
- ml->expx = ml->expy = ml->expz = 1.0;
+ break;
+ case MB_PLANE:
+ ml->type = MB_PLANE;
+ ml->expx = ml->expy = ml->expz = 1.0;
- break;
- case MB_ELIPSOID:
- ml->type = MB_ELIPSOID;
- ml->expx = 1.2f;
- ml->expy = 0.8f;
- ml->expz = 1.0;
+ break;
+ case MB_ELIPSOID:
+ ml->type = MB_ELIPSOID;
+ ml->expx = 1.2f;
+ ml->expy = 0.8f;
+ ml->expz = 1.0;
- break;
- case MB_CUBE:
- ml->type = MB_CUBE;
- ml->expx = ml->expy = ml->expz = 1.0;
+ break;
+ case MB_CUBE:
+ ml->type = MB_CUBE;
+ ml->expx = ml->expy = ml->expz = 1.0;
- break;
- default:
- break;
- }
+ break;
+ default:
+ break;
+ }
- BLI_addtail(&mb->elems, ml);
+ BLI_addtail(&mb->elems, ml);
- return ml;
+ return ml;
}
/** Compute bounding box of all MetaElems/MetaBalls.
*
@@ -183,95 +187,96 @@ MetaElem *BKE_mball_element_add(MetaBall *mb, const int type)
*/
void BKE_mball_texspace_calc(Object *ob)
{
- DispList *dl;
- BoundBox *bb;
- float *data, min[3], max[3] /*, loc[3], size[3] */;
- int tot;
- bool do_it = false;
-
- if (ob->runtime.bb == NULL) {
- ob->runtime.bb = MEM_callocN(sizeof(BoundBox), "mb boundbox");
- }
- bb = ob->runtime.bb;
-
- /* Weird one, this. */
-/* INIT_MINMAX(min, max); */
- (min)[0] = (min)[1] = (min)[2] = 1.0e30f;
- (max)[0] = (max)[1] = (max)[2] = -1.0e30f;
-
- dl = ob->runtime.curve_cache->disp.first;
- while (dl) {
- tot = dl->nr;
- if (tot) do_it = true;
- data = dl->verts;
- while (tot--) {
- /* Also weird... but longer. From utildefines. */
- minmax_v3v3_v3(min, max, data);
- data += 3;
- }
- dl = dl->next;
- }
-
- if (!do_it) {
- min[0] = min[1] = min[2] = -1.0f;
- max[0] = max[1] = max[2] = 1.0f;
- }
-
- BKE_boundbox_init_from_minmax(bb, min, max);
-
- bb->flag &= ~BOUNDBOX_DIRTY;
+ DispList *dl;
+ BoundBox *bb;
+ float *data, min[3], max[3] /*, loc[3], size[3] */;
+ int tot;
+ bool do_it = false;
+
+ if (ob->runtime.bb == NULL) {
+ ob->runtime.bb = MEM_callocN(sizeof(BoundBox), "mb boundbox");
+ }
+ bb = ob->runtime.bb;
+
+ /* Weird one, this. */
+ /* INIT_MINMAX(min, max); */
+ (min)[0] = (min)[1] = (min)[2] = 1.0e30f;
+ (max)[0] = (max)[1] = (max)[2] = -1.0e30f;
+
+ dl = ob->runtime.curve_cache->disp.first;
+ while (dl) {
+ tot = dl->nr;
+ if (tot)
+ do_it = true;
+ data = dl->verts;
+ while (tot--) {
+ /* Also weird... but longer. From utildefines. */
+ minmax_v3v3_v3(min, max, data);
+ data += 3;
+ }
+ dl = dl->next;
+ }
+
+ if (!do_it) {
+ min[0] = min[1] = min[2] = -1.0f;
+ max[0] = max[1] = max[2] = 1.0f;
+ }
+
+ BKE_boundbox_init_from_minmax(bb, min, max);
+
+ bb->flag &= ~BOUNDBOX_DIRTY;
}
/** Return or compute bbox for given metaball object. */
BoundBox *BKE_mball_boundbox_get(Object *ob)
{
- BLI_assert(ob->type == OB_MBALL);
+ BLI_assert(ob->type == OB_MBALL);
- if (ob->runtime.bb != NULL && (ob->runtime.bb->flag & BOUNDBOX_DIRTY) == 0) {
- return ob->runtime.bb;
- }
+ if (ob->runtime.bb != NULL && (ob->runtime.bb->flag & BOUNDBOX_DIRTY) == 0) {
+ return ob->runtime.bb;
+ }
- /* This should always only be called with evaluated objects, but currently RNA is a problem here... */
- if (ob->runtime.curve_cache != NULL) {
- BKE_mball_texspace_calc(ob);
- }
+ /* This should always only be called with evaluated objects, but currently RNA is a problem here... */
+ if (ob->runtime.curve_cache != NULL) {
+ BKE_mball_texspace_calc(ob);
+ }
- return ob->runtime.bb;
+ return ob->runtime.bb;
}
float *BKE_mball_make_orco(Object *ob, ListBase *dispbase)
{
- BoundBox *bb;
- DispList *dl;
- float *data, *orco, *orcodata;
- float loc[3], size[3];
- int a;
+ BoundBox *bb;
+ DispList *dl;
+ float *data, *orco, *orcodata;
+ float loc[3], size[3];
+ int a;
- /* restore size and loc */
- bb = ob->runtime.bb;
- loc[0] = (bb->vec[0][0] + bb->vec[4][0]) / 2.0f;
- size[0] = bb->vec[4][0] - loc[0];
- loc[1] = (bb->vec[0][1] + bb->vec[2][1]) / 2.0f;
- size[1] = bb->vec[2][1] - loc[1];
- loc[2] = (bb->vec[0][2] + bb->vec[1][2]) / 2.0f;
- size[2] = bb->vec[1][2] - loc[2];
+ /* restore size and loc */
+ bb = ob->runtime.bb;
+ loc[0] = (bb->vec[0][0] + bb->vec[4][0]) / 2.0f;
+ size[0] = bb->vec[4][0] - loc[0];
+ loc[1] = (bb->vec[0][1] + bb->vec[2][1]) / 2.0f;
+ size[1] = bb->vec[2][1] - loc[1];
+ loc[2] = (bb->vec[0][2] + bb->vec[1][2]) / 2.0f;
+ size[2] = bb->vec[1][2] - loc[2];
- dl = dispbase->first;
- orcodata = MEM_mallocN(sizeof(float) * 3 * dl->nr, "MballOrco");
+ dl = dispbase->first;
+ orcodata = MEM_mallocN(sizeof(float) * 3 * dl->nr, "MballOrco");
- data = dl->verts;
- orco = orcodata;
- a = dl->nr;
- while (a--) {
- orco[0] = (data[0] - loc[0]) / size[0];
- orco[1] = (data[1] - loc[1]) / size[1];
- orco[2] = (data[2] - loc[2]) / size[2];
+ data = dl->verts;
+ orco = orcodata;
+ a = dl->nr;
+ while (a--) {
+ orco[0] = (data[0] - loc[0]) / size[0];
+ orco[1] = (data[1] - loc[1]) / size[1];
+ orco[2] = (data[2] - loc[2]) / size[2];
- data += 3;
- orco += 3;
- }
+ data += 3;
+ orco += 3;
+ }
- return orcodata;
+ return orcodata;
}
/* Note on mball basis stuff 2.5x (this is a can of worms)
@@ -285,7 +290,6 @@ float *BKE_mball_make_orco(Object *ob, ListBase *dispbase)
* - Campbell
*/
-
/** \brief Test, if Object *ob is basic MetaBall.
*
* It test last character of Object ID name. If last character
@@ -293,64 +297,63 @@ float *BKE_mball_make_orco(Object *ob, ListBase *dispbase)
*/
bool BKE_mball_is_basis(Object *ob)
{
- /* just a quick test */
- const int len = strlen(ob->id.name);
- return (!isdigit(ob->id.name[len - 1]));
+ /* just a quick test */
+ const int len = strlen(ob->id.name);
+ return (!isdigit(ob->id.name[len - 1]));
}
/* return nonzero if ob1 is a basis mball for ob */
bool BKE_mball_is_basis_for(Object *ob1, Object *ob2)
{
- int basis1nr, basis2nr;
- char basis1name[MAX_ID_NAME], basis2name[MAX_ID_NAME];
+ int basis1nr, basis2nr;
+ char basis1name[MAX_ID_NAME], basis2name[MAX_ID_NAME];
- if (ob1->id.name[2] != ob2->id.name[2]) {
- /* Quick return in case first char of both ID's names is not the same... */
- return false;
- }
+ if (ob1->id.name[2] != ob2->id.name[2]) {
+ /* Quick return in case first char of both ID's names is not the same... */
+ return false;
+ }
- BLI_split_name_num(basis1name, &basis1nr, ob1->id.name + 2, '.');
- BLI_split_name_num(basis2name, &basis2nr, ob2->id.name + 2, '.');
+ BLI_split_name_num(basis1name, &basis1nr, ob1->id.name + 2, '.');
+ BLI_split_name_num(basis2name, &basis2nr, ob2->id.name + 2, '.');
- if (STREQ(basis1name, basis2name)) {
- return BKE_mball_is_basis(ob1);
- }
- else {
- return false;
- }
+ if (STREQ(basis1name, basis2name)) {
+ return BKE_mball_is_basis(ob1);
+ }
+ else {
+ return false;
+ }
}
bool BKE_mball_is_any_selected(const MetaBall *mb)
{
- for (const MetaElem *ml = mb->editelems->first; ml != NULL; ml = ml->next) {
- if (ml->flag & SELECT) {
- return true;
- }
- }
- return false;
+ for (const MetaElem *ml = mb->editelems->first; ml != NULL; ml = ml->next) {
+ if (ml->flag & SELECT) {
+ return true;
+ }
+ }
+ return false;
}
-
bool BKE_mball_is_any_selected_multi(Base **bases, int bases_len)
{
- for (uint base_index = 0; base_index < bases_len; base_index++) {
- Object *obedit = bases[base_index]->object;
- MetaBall *mb = (MetaBall *)obedit->data;
- if (BKE_mball_is_any_selected(mb)) {
- return true;
- }
- }
- return false;
+ for (uint base_index = 0; base_index < bases_len; base_index++) {
+ Object *obedit = bases[base_index]->object;
+ MetaBall *mb = (MetaBall *)obedit->data;
+ if (BKE_mball_is_any_selected(mb)) {
+ return true;
+ }
+ }
+ return false;
}
bool BKE_mball_is_any_unselected(const MetaBall *mb)
{
- for (const MetaElem *ml = mb->editelems->first; ml != NULL; ml = ml->next) {
- if ((ml->flag & SELECT) == 0) {
- return true;
- }
- }
- return false;
+ for (const MetaElem *ml = mb->editelems->first; ml != NULL; ml = ml->next) {
+ if ((ml->flag & SELECT) == 0) {
+ return true;
+ }
+ }
+ return false;
}
/* \brief copy some properties from object to other metaball object with same base name
@@ -361,40 +364,40 @@ bool BKE_mball_is_any_unselected(const MetaBall *mb)
* because this metaball influence polygonisation of metaballs. */
void BKE_mball_properties_copy(Scene *scene, Object *active_object)
{
- Scene *sce_iter = scene;
- Base *base;
- Object *ob;
- MetaBall *active_mball = (MetaBall *)active_object->data;
- int basisnr, obnr;
- char basisname[MAX_ID_NAME], obname[MAX_ID_NAME];
- SceneBaseIter iter;
-
- BLI_split_name_num(basisname, &basisnr, active_object->id.name + 2, '.');
-
- /* Pass depsgraph as NULL, which means we will not expand into
- * duplis unlike when we generate the mball. Expanding duplis
- * would not be compatible when editing multiple view layers. */
- BKE_scene_base_iter_next(NULL, &iter, &sce_iter, 0, NULL, NULL);
- while (BKE_scene_base_iter_next(NULL, &iter, &sce_iter, 1, &base, &ob)) {
- if (ob->type == OB_MBALL) {
- if (ob != active_object) {
- BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.');
-
- /* Object ob has to be in same "group" ... it means, that it has to have
- * same base of its name */
- if (STREQ(obname, basisname)) {
- MetaBall *mb = ob->data;
-
- /* Copy properties from selected/edited metaball */
- mb->wiresize = active_mball->wiresize;
- mb->rendersize = active_mball->rendersize;
- mb->thresh = active_mball->thresh;
- mb->flag = active_mball->flag;
- DEG_id_tag_update(&mb->id, 0);
- }
- }
- }
- }
+ Scene *sce_iter = scene;
+ Base *base;
+ Object *ob;
+ MetaBall *active_mball = (MetaBall *)active_object->data;
+ int basisnr, obnr;
+ char basisname[MAX_ID_NAME], obname[MAX_ID_NAME];
+ SceneBaseIter iter;
+
+ BLI_split_name_num(basisname, &basisnr, active_object->id.name + 2, '.');
+
+ /* Pass depsgraph as NULL, which means we will not expand into
+ * duplis unlike when we generate the mball. Expanding duplis
+ * would not be compatible when editing multiple view layers. */
+ BKE_scene_base_iter_next(NULL, &iter, &sce_iter, 0, NULL, NULL);
+ while (BKE_scene_base_iter_next(NULL, &iter, &sce_iter, 1, &base, &ob)) {
+ if (ob->type == OB_MBALL) {
+ if (ob != active_object) {
+ BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.');
+
+ /* Object ob has to be in same "group" ... it means, that it has to have
+ * same base of its name */
+ if (STREQ(obname, basisname)) {
+ MetaBall *mb = ob->data;
+
+ /* Copy properties from selected/edited metaball */
+ mb->wiresize = active_mball->wiresize;
+ mb->rendersize = active_mball->rendersize;
+ mb->thresh = active_mball->thresh;
+ mb->flag = active_mball->flag;
+ DEG_id_tag_update(&mb->id, 0);
+ }
+ }
+ }
+ }
}
/** \brief This function finds basic MetaBall.
@@ -408,234 +411,233 @@ void BKE_mball_properties_copy(Scene *scene, Object *active_object)
*/
Object *BKE_mball_basis_find(Scene *scene, Object *basis)
{
- Object *bob = basis;
- int basisnr, obnr;
- char basisname[MAX_ID_NAME], obname[MAX_ID_NAME];
+ Object *bob = basis;
+ int basisnr, obnr;
+ char basisname[MAX_ID_NAME], obname[MAX_ID_NAME];
- BLI_split_name_num(basisname, &basisnr, basis->id.name + 2, '.');
+ BLI_split_name_num(basisname, &basisnr, basis->id.name + 2, '.');
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
- Object *ob = base->object;
- if ((ob->type == OB_MBALL) && !(base->flag & BASE_FROM_DUPLI)) {
- if (ob != bob) {
- BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.');
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
+ view_layer = view_layer->next) {
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ Object *ob = base->object;
+ if ((ob->type == OB_MBALL) && !(base->flag & BASE_FROM_DUPLI)) {
+ if (ob != bob) {
+ BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.');
- /* object ob has to be in same "group" ... it means, that it has to have same base of its name */
- if (STREQ(obname, basisname)) {
- if (obnr < basisnr) {
- basis = ob;
- basisnr = obnr;
- }
- }
- }
- }
- }
- }
+ /* object ob has to be in same "group" ... it means, that it has to have same base of its name */
+ if (STREQ(obname, basisname)) {
+ if (obnr < basisnr) {
+ basis = ob;
+ basisnr = obnr;
+ }
+ }
+ }
+ }
+ }
+ }
- return basis;
+ return basis;
}
bool BKE_mball_minmax_ex(
- const MetaBall *mb, float min[3], float max[3],
- const float obmat[4][4], const short flag)
+ const MetaBall *mb, float min[3], float max[3], const float obmat[4][4], const short flag)
{
- const float scale = obmat ? mat4_to_scale(obmat) : 1.0f;
- bool changed = false;
- float centroid[3], vec[3];
+ const float scale = obmat ? mat4_to_scale(obmat) : 1.0f;
+ bool changed = false;
+ float centroid[3], vec[3];
- INIT_MINMAX(min, max);
+ INIT_MINMAX(min, max);
- for (const MetaElem *ml = mb->elems.first; ml; ml = ml->next) {
- if ((ml->flag & flag) == flag) {
- const float scale_mb = (ml->rad * 0.5f) * scale;
- int i;
+ for (const MetaElem *ml = mb->elems.first; ml; ml = ml->next) {
+ if ((ml->flag & flag) == flag) {
+ const float scale_mb = (ml->rad * 0.5f) * scale;
+ int i;
- if (obmat) {
- mul_v3_m4v3(centroid, obmat, &ml->x);
- }
- else {
- copy_v3_v3(centroid, &ml->x);
- }
+ if (obmat) {
+ mul_v3_m4v3(centroid, obmat, &ml->x);
+ }
+ else {
+ copy_v3_v3(centroid, &ml->x);
+ }
- /* TODO, non circle shapes cubes etc, probably nobody notices - campbell */
- for (i = -1; i != 3; i += 2) {
- copy_v3_v3(vec, centroid);
- add_v3_fl(vec, scale_mb * i);
- minmax_v3v3_v3(min, max, vec);
- }
- changed = true;
- }
- }
+ /* TODO, non circle shapes cubes etc, probably nobody notices - campbell */
+ for (i = -1; i != 3; i += 2) {
+ copy_v3_v3(vec, centroid);
+ add_v3_fl(vec, scale_mb * i);
+ minmax_v3v3_v3(min, max, vec);
+ }
+ changed = true;
+ }
+ }
- return changed;
+ return changed;
}
-
/* basic vertex data functions */
bool BKE_mball_minmax(const MetaBall *mb, float min[3], float max[3])
{
- INIT_MINMAX(min, max);
+ INIT_MINMAX(min, max);
- for (const MetaElem *ml = mb->elems.first; ml; ml = ml->next) {
- minmax_v3v3_v3(min, max, &ml->x);
- }
+ for (const MetaElem *ml = mb->elems.first; ml; ml = ml->next) {
+ minmax_v3v3_v3(min, max, &ml->x);
+ }
- return (BLI_listbase_is_empty(&mb->elems) == false);
+ return (BLI_listbase_is_empty(&mb->elems) == false);
}
bool BKE_mball_center_median(const MetaBall *mb, float r_cent[3])
{
- int total = 0;
+ int total = 0;
- zero_v3(r_cent);
+ zero_v3(r_cent);
- for (const MetaElem *ml = mb->elems.first; ml; ml = ml->next) {
- add_v3_v3(r_cent, &ml->x);
- total++;
- }
+ for (const MetaElem *ml = mb->elems.first; ml; ml = ml->next) {
+ add_v3_v3(r_cent, &ml->x);
+ total++;
+ }
- if (total) {
- mul_v3_fl(r_cent, 1.0f / (float)total);
- }
+ if (total) {
+ mul_v3_fl(r_cent, 1.0f / (float)total);
+ }
- return (total != 0);
+ return (total != 0);
}
bool BKE_mball_center_bounds(const MetaBall *mb, float r_cent[3])
{
- float min[3], max[3];
+ float min[3], max[3];
- if (BKE_mball_minmax(mb, min, max)) {
- mid_v3_v3v3(r_cent, min, max);
- return true;
- }
+ if (BKE_mball_minmax(mb, min, max)) {
+ mid_v3_v3v3(r_cent, min, max);
+ return true;
+ }
- return false;
+ return false;
}
void BKE_mball_transform(MetaBall *mb, float mat[4][4], const bool do_props)
{
- float quat[4];
- const float scale = mat4_to_scale(mat);
- const float scale_sqrt = sqrtf(scale);
+ float quat[4];
+ const float scale = mat4_to_scale(mat);
+ const float scale_sqrt = sqrtf(scale);
- mat4_to_quat(quat, mat);
+ mat4_to_quat(quat, mat);
- for (MetaElem *ml = mb->elems.first; ml; ml = ml->next) {
- mul_m4_v3(mat, &ml->x);
- mul_qt_qtqt(ml->quat, quat, ml->quat);
+ for (MetaElem *ml = mb->elems.first; ml; ml = ml->next) {
+ mul_m4_v3(mat, &ml->x);
+ mul_qt_qtqt(ml->quat, quat, ml->quat);
- if (do_props) {
- ml->rad *= scale;
- /* hrmf, probably elems shouldn't be
- * treating scale differently - campbell */
- if (!MB_TYPE_SIZE_SQUARED(ml->type)) {
- mul_v3_fl(&ml->expx, scale);
- }
- else {
- mul_v3_fl(&ml->expx, scale_sqrt);
- }
- }
- }
+ if (do_props) {
+ ml->rad *= scale;
+ /* hrmf, probably elems shouldn't be
+ * treating scale differently - campbell */
+ if (!MB_TYPE_SIZE_SQUARED(ml->type)) {
+ mul_v3_fl(&ml->expx, scale);
+ }
+ else {
+ mul_v3_fl(&ml->expx, scale_sqrt);
+ }
+ }
+ }
}
void BKE_mball_translate(MetaBall *mb, const float offset[3])
{
- for (MetaElem *ml = mb->elems.first; ml; ml = ml->next) {
- add_v3_v3(&ml->x, offset);
- }
+ for (MetaElem *ml = mb->elems.first; ml; ml = ml->next) {
+ add_v3_v3(&ml->x, offset);
+ }
}
/* *** select funcs *** */
int BKE_mball_select_count(const MetaBall *mb)
{
- int sel = 0;
- for (const MetaElem *ml = mb->editelems->first; ml; ml = ml->next) {
- if (ml->flag & SELECT) {
- sel++;
- }
- }
- return sel;
+ int sel = 0;
+ for (const MetaElem *ml = mb->editelems->first; ml; ml = ml->next) {
+ if (ml->flag & SELECT) {
+ sel++;
+ }
+ }
+ return sel;
}
int BKE_mball_select_count_multi(Base **bases, int bases_len)
{
- int sel = 0;
- for (uint ob_index = 0; ob_index < bases_len; ob_index++) {
- const Object *obedit = bases[ob_index]->object;
- const MetaBall *mb = (MetaBall *)obedit->data;
- sel += BKE_mball_select_count(mb);
- }
- return sel;
+ int sel = 0;
+ for (uint ob_index = 0; ob_index < bases_len; ob_index++) {
+ const Object *obedit = bases[ob_index]->object;
+ const MetaBall *mb = (MetaBall *)obedit->data;
+ sel += BKE_mball_select_count(mb);
+ }
+ return sel;
}
bool BKE_mball_select_all(MetaBall *mb)
{
- bool changed = false;
- for (MetaElem *ml = mb->editelems->first; ml; ml = ml->next) {
- if ((ml->flag & SELECT) == 0) {
- ml->flag |= SELECT;
- changed = true;
- }
- }
- return changed;
+ bool changed = false;
+ for (MetaElem *ml = mb->editelems->first; ml; ml = ml->next) {
+ if ((ml->flag & SELECT) == 0) {
+ ml->flag |= SELECT;
+ changed = true;
+ }
+ }
+ return changed;
}
bool BKE_mball_select_all_multi_ex(Base **bases, int bases_len)
{
- bool changed_multi = false;
- for (uint ob_index = 0; ob_index < bases_len; ob_index++) {
- Object *obedit = bases[ob_index]->object;
- MetaBall *mb = obedit->data;
- changed_multi |= BKE_mball_select_all(mb);
- }
- return changed_multi;
+ bool changed_multi = false;
+ for (uint ob_index = 0; ob_index < bases_len; ob_index++) {
+ Object *obedit = bases[ob_index]->object;
+ MetaBall *mb = obedit->data;
+ changed_multi |= BKE_mball_select_all(mb);
+ }
+ return changed_multi;
}
bool BKE_mball_deselect_all(MetaBall *mb)
{
- bool changed = false;
- for (MetaElem *ml = mb->editelems->first; ml; ml = ml->next) {
- if ((ml->flag & SELECT) != 0) {
- ml->flag &= ~SELECT;
- changed = true;
- }
- }
- return changed;
+ bool changed = false;
+ for (MetaElem *ml = mb->editelems->first; ml; ml = ml->next) {
+ if ((ml->flag & SELECT) != 0) {
+ ml->flag &= ~SELECT;
+ changed = true;
+ }
+ }
+ return changed;
}
bool BKE_mball_deselect_all_multi_ex(Base **bases, int bases_len)
{
- bool changed_multi = false;
- for (uint ob_index = 0; ob_index < bases_len; ob_index++) {
- Object *obedit = bases[ob_index]->object;
- MetaBall *mb = obedit->data;
- changed_multi |= BKE_mball_deselect_all(mb);
- DEG_id_tag_update(&mb->id, ID_RECALC_SELECT);
- }
- return changed_multi;
+ bool changed_multi = false;
+ for (uint ob_index = 0; ob_index < bases_len; ob_index++) {
+ Object *obedit = bases[ob_index]->object;
+ MetaBall *mb = obedit->data;
+ changed_multi |= BKE_mball_deselect_all(mb);
+ DEG_id_tag_update(&mb->id, ID_RECALC_SELECT);
+ }
+ return changed_multi;
}
bool BKE_mball_select_swap(MetaBall *mb)
{
- bool changed = false;
- for (MetaElem *ml = mb->editelems->first; ml; ml = ml->next) {
- ml->flag ^= SELECT;
- changed = true;
- }
- return changed;
+ bool changed = false;
+ for (MetaElem *ml = mb->editelems->first; ml; ml = ml->next) {
+ ml->flag ^= SELECT;
+ changed = true;
+ }
+ return changed;
}
bool BKE_mball_select_swap_multi_ex(Base **bases, int bases_len)
{
- bool changed_multi = false;
- for (uint ob_index = 0; ob_index < bases_len; ob_index++) {
- Object *obedit = bases[ob_index]->object;
- MetaBall *mb = (MetaBall *)obedit->data;
- changed_multi |= BKE_mball_select_swap(mb);
- }
- return changed_multi;
+ bool changed_multi = false;
+ for (uint ob_index = 0; ob_index < bases_len; ob_index++) {
+ Object *obedit = bases[ob_index]->object;
+ MetaBall *mb = (MetaBall *)obedit->data;
+ changed_multi |= BKE_mball_select_swap(mb);
+ }
+ return changed_multi;
}
/* **** Depsgraph evaluation **** */
@@ -647,13 +649,13 @@ void (*BKE_mball_batch_cache_free_cb)(MetaBall *mb) = NULL;
void BKE_mball_batch_cache_dirty_tag(MetaBall *mb, int mode)
{
- if (mb->batch_cache) {
- BKE_mball_batch_cache_dirty_tag_cb(mb, mode);
- }
+ if (mb->batch_cache) {
+ BKE_mball_batch_cache_dirty_tag_cb(mb, mode);
+ }
}
void BKE_mball_batch_cache_free(MetaBall *mb)
{
- if (mb->batch_cache) {
- BKE_mball_batch_cache_free_cb(mb);
- }
+ if (mb->batch_cache) {
+ BKE_mball_batch_cache_free_cb(mb);
+ }
}
diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c
index df62d8b1041..3ca46b7be61 100644
--- a/source/blender/blenkernel/intern/mball_tessellate.c
+++ b/source/blender/blenkernel/intern/mball_tessellate.c
@@ -43,7 +43,7 @@
#include "BKE_global.h"
#include "BKE_displist.h"
-#include "BKE_mball_tessellate.h" /* own include */
+#include "BKE_mball_tessellate.h" /* own include */
#include "BKE_scene.h"
#include "DEG_depsgraph.h"
@@ -56,82 +56,82 @@
/* Data types */
-typedef struct corner { /* corner of a cube */
- int i, j, k; /* (i, j, k) is index within lattice */
- float co[3], value; /* location and function value */
- struct corner *next;
+typedef struct corner { /* corner of a cube */
+ int i, j, k; /* (i, j, k) is index within lattice */
+ float co[3], value; /* location and function value */
+ struct corner *next;
} CORNER;
-typedef struct cube { /* partitioning cell (cube) */
- int i, j, k; /* lattice location of cube */
- CORNER *corners[8]; /* eight corners */
+typedef struct cube { /* partitioning cell (cube) */
+ int i, j, k; /* lattice location of cube */
+ CORNER *corners[8]; /* eight corners */
} CUBE;
-typedef struct cubes { /* linked list of cubes acting as stack */
- CUBE cube; /* a single cube */
- struct cubes *next; /* remaining elements */
+typedef struct cubes { /* linked list of cubes acting as stack */
+ CUBE cube; /* a single cube */
+ struct cubes *next; /* remaining elements */
} CUBES;
-typedef struct centerlist { /* list of cube locations */
- int i, j, k; /* cube location */
- struct centerlist *next; /* remaining elements */
+typedef struct centerlist { /* list of cube locations */
+ int i, j, k; /* cube location */
+ struct centerlist *next; /* remaining elements */
} CENTERLIST;
-typedef struct edgelist { /* list of edges */
- int i1, j1, k1, i2, j2, k2; /* edge corner ids */
- int vid; /* vertex id */
- struct edgelist *next; /* remaining elements */
+typedef struct edgelist { /* list of edges */
+ int i1, j1, k1, i2, j2, k2; /* edge corner ids */
+ int vid; /* vertex id */
+ struct edgelist *next; /* remaining elements */
} EDGELIST;
-typedef struct intlist { /* list of integers */
- int i; /* an integer */
- struct intlist *next; /* remaining elements */
+typedef struct intlist { /* list of integers */
+ int i; /* an integer */
+ struct intlist *next; /* remaining elements */
} INTLIST;
-typedef struct intlists { /* list of list of integers */
- INTLIST *list; /* a list of integers */
- struct intlists *next; /* remaining elements */
+typedef struct intlists { /* list of list of integers */
+ INTLIST *list; /* a list of integers */
+ struct intlists *next; /* remaining elements */
} INTLISTS;
-typedef struct Box { /* an AABB with pointer to metalelem */
- float min[3], max[3];
- const MetaElem *ml;
+typedef struct Box { /* an AABB with pointer to metalelem */
+ float min[3], max[3];
+ const MetaElem *ml;
} Box;
-typedef struct MetaballBVHNode { /* BVH node */
- Box bb[2]; /* AABB of children */
- struct MetaballBVHNode *child[2];
+typedef struct MetaballBVHNode { /* BVH node */
+ Box bb[2]; /* AABB of children */
+ struct MetaballBVHNode *child[2];
} MetaballBVHNode;
-typedef struct process { /* parameters, storage */
- float thresh, size; /* mball threshold, single cube size */
- float delta; /* small delta for calculating normals */
- unsigned int converge_res; /* converge procedure resolution (more = slower) */
+typedef struct process { /* parameters, storage */
+ float thresh, size; /* mball threshold, single cube size */
+ float delta; /* small delta for calculating normals */
+ unsigned int converge_res; /* converge procedure resolution (more = slower) */
- MetaElem **mainb; /* array of all metaelems */
- unsigned int totelem, mem; /* number of metaelems */
+ MetaElem **mainb; /* array of all metaelems */
+ unsigned int totelem, mem; /* number of metaelems */
- MetaballBVHNode metaball_bvh; /* The simplest bvh */
- Box allbb; /* Bounding box of all metaelems */
+ MetaballBVHNode metaball_bvh; /* The simplest bvh */
+ Box allbb; /* Bounding box of all metaelems */
- MetaballBVHNode **bvh_queue; /* Queue used during bvh traversal */
- unsigned int bvh_queue_size;
+ MetaballBVHNode **bvh_queue; /* Queue used during bvh traversal */
+ unsigned int bvh_queue_size;
- CUBES *cubes; /* stack of cubes waiting for polygonization */
- CENTERLIST **centers; /* cube center hash table */
- CORNER **corners; /* corner value hash table */
- EDGELIST **edges; /* edge and vertex id hash table */
+ CUBES *cubes; /* stack of cubes waiting for polygonization */
+ CENTERLIST **centers; /* cube center hash table */
+ CORNER **corners; /* corner value hash table */
+ EDGELIST **edges; /* edge and vertex id hash table */
- int (*indices)[4]; /* output indices */
- unsigned int totindex; /* size of memory allocated for indices */
- unsigned int curindex; /* number of currently added indices */
+ int (*indices)[4]; /* output indices */
+ unsigned int totindex; /* size of memory allocated for indices */
+ unsigned int curindex; /* number of currently added indices */
- float (*co)[3], (*no)[3]; /* surface vertices - positions and normals */
- unsigned int totvertex; /* memory size */
- unsigned int curvertex; /* currently added vertices */
+ float (*co)[3], (*no)[3]; /* surface vertices - positions and normals */
+ unsigned int totvertex; /* memory size */
+ unsigned int curvertex; /* currently added vertices */
- /* memory allocation from common pool */
- MemArena *pgn_elements;
+ /* memory allocation from common pool */
+ MemArena *pgn_elements;
} PROCESS;
/* Forward declarations */
@@ -144,20 +144,20 @@ static void converge(PROCESS *process, const CORNER *c1, const CORNER *c2, float
static void make_box_union(const BoundBox *a, const Box *b, Box *r_out)
{
- r_out->min[0] = min_ff(a->vec[0][0], b->min[0]);
- r_out->min[1] = min_ff(a->vec[0][1], b->min[1]);
- r_out->min[2] = min_ff(a->vec[0][2], b->min[2]);
+ r_out->min[0] = min_ff(a->vec[0][0], b->min[0]);
+ r_out->min[1] = min_ff(a->vec[0][1], b->min[1]);
+ r_out->min[2] = min_ff(a->vec[0][2], b->min[2]);
- r_out->max[0] = max_ff(a->vec[6][0], b->max[0]);
- r_out->max[1] = max_ff(a->vec[6][1], b->max[1]);
- r_out->max[2] = max_ff(a->vec[6][2], b->max[2]);
+ r_out->max[0] = max_ff(a->vec[6][0], b->max[0]);
+ r_out->max[1] = max_ff(a->vec[6][1], b->max[1]);
+ r_out->max[2] = max_ff(a->vec[6][2], b->max[2]);
}
static void make_box_from_metaelem(Box *r, const MetaElem *ml)
{
- copy_v3_v3(r->max, ml->bb->vec[6]);
- copy_v3_v3(r->min, ml->bb->vec[0]);
- r->ml = ml;
+ copy_v3_v3(r->max, ml->bb->vec[6]);
+ copy_v3_v3(r->min, ml->bb->vec[0]);
+ r->ml = ml;
}
/**
@@ -165,83 +165,90 @@ static void make_box_from_metaelem(Box *r, const MetaElem *ml)
* where centroids of elements in the [start, i) segment lie "on the right side" of div,
* and elements in the [i, end) segment lie "on the left"
*/
-static unsigned int partition_mainb(MetaElem **mainb, unsigned int start, unsigned int end, unsigned int s, float div)
+static unsigned int partition_mainb(
+ MetaElem **mainb, unsigned int start, unsigned int end, unsigned int s, float div)
{
- unsigned int i = start, j = end - 1;
- div *= 2.0f;
+ unsigned int i = start, j = end - 1;
+ div *= 2.0f;
- while (1) {
- while (i < j && div > (mainb[i]->bb->vec[6][s] + mainb[i]->bb->vec[0][s])) i++;
- while (j > i && div < (mainb[j]->bb->vec[6][s] + mainb[j]->bb->vec[0][s])) j--;
+ while (1) {
+ while (i < j && div > (mainb[i]->bb->vec[6][s] + mainb[i]->bb->vec[0][s]))
+ i++;
+ while (j > i && div < (mainb[j]->bb->vec[6][s] + mainb[j]->bb->vec[0][s]))
+ j--;
- if (i >= j)
- break;
+ if (i >= j)
+ break;
- SWAP(MetaElem *, mainb[i], mainb[j]);
- i++;
- j--;
- }
+ SWAP(MetaElem *, mainb[i], mainb[j]);
+ i++;
+ j--;
+ }
- if (i == start) {
- i++;
- }
+ if (i == start) {
+ i++;
+ }
- return i;
+ return i;
}
/**
* Recursively builds a BVH, dividing elements along the middle of the longest axis of allbox.
*/
-static void build_bvh_spatial(
- PROCESS *process, MetaballBVHNode *node,
- unsigned int start, unsigned int end, const Box *allbox)
+static void build_bvh_spatial(PROCESS *process,
+ MetaballBVHNode *node,
+ unsigned int start,
+ unsigned int end,
+ const Box *allbox)
{
- unsigned int part, j, s;
- float dim[3], div;
-
- /* Maximum bvh queue size is number of nodes which are made, equals calls to this function. */
- process->bvh_queue_size++;
-
- dim[0] = allbox->max[0] - allbox->min[0];
- dim[1] = allbox->max[1] - allbox->min[1];
- dim[2] = allbox->max[2] - allbox->min[2];
-
- s = 0;
- if (dim[1] > dim[0] && dim[1] > dim[2]) s = 1;
- else if (dim[2] > dim[1] && dim[2] > dim[0]) s = 2;
-
- div = allbox->min[s] + (dim[s] / 2.0f);
-
- part = partition_mainb(process->mainb, start, end, s, div);
-
- make_box_from_metaelem(&node->bb[0], process->mainb[start]);
- node->child[0] = NULL;
-
- if (part > start + 1) {
- for (j = start; j < part; j++) {
- make_box_union(process->mainb[j]->bb, &node->bb[0], &node->bb[0]);
- }
-
- node->child[0] = BLI_memarena_alloc(process->pgn_elements, sizeof(MetaballBVHNode));
- build_bvh_spatial(process, node->child[0], start, part, &node->bb[0]);
- }
-
- node->child[1] = NULL;
- if (part < end) {
- make_box_from_metaelem(&node->bb[1], process->mainb[part]);
-
- if (part < end - 1) {
- for (j = part; j < end; j++) {
- make_box_union(process->mainb[j]->bb, &node->bb[1], &node->bb[1]);
- }
-
- node->child[1] = BLI_memarena_alloc(process->pgn_elements, sizeof(MetaballBVHNode));
- build_bvh_spatial(process, node->child[1], part, end, &node->bb[1]);
- }
- }
- else {
- INIT_MINMAX(node->bb[1].min, node->bb[1].max);
- }
+ unsigned int part, j, s;
+ float dim[3], div;
+
+ /* Maximum bvh queue size is number of nodes which are made, equals calls to this function. */
+ process->bvh_queue_size++;
+
+ dim[0] = allbox->max[0] - allbox->min[0];
+ dim[1] = allbox->max[1] - allbox->min[1];
+ dim[2] = allbox->max[2] - allbox->min[2];
+
+ s = 0;
+ if (dim[1] > dim[0] && dim[1] > dim[2])
+ s = 1;
+ else if (dim[2] > dim[1] && dim[2] > dim[0])
+ s = 2;
+
+ div = allbox->min[s] + (dim[s] / 2.0f);
+
+ part = partition_mainb(process->mainb, start, end, s, div);
+
+ make_box_from_metaelem(&node->bb[0], process->mainb[start]);
+ node->child[0] = NULL;
+
+ if (part > start + 1) {
+ for (j = start; j < part; j++) {
+ make_box_union(process->mainb[j]->bb, &node->bb[0], &node->bb[0]);
+ }
+
+ node->child[0] = BLI_memarena_alloc(process->pgn_elements, sizeof(MetaballBVHNode));
+ build_bvh_spatial(process, node->child[0], start, part, &node->bb[0]);
+ }
+
+ node->child[1] = NULL;
+ if (part < end) {
+ make_box_from_metaelem(&node->bb[1], process->mainb[part]);
+
+ if (part < end - 1) {
+ for (j = part; j < end; j++) {
+ make_box_union(process->mainb[j]->bb, &node->bb[1], &node->bb[1]);
+ }
+
+ node->child[1] = BLI_memarena_alloc(process->pgn_elements, sizeof(MetaballBVHNode));
+ build_bvh_spatial(process, node->child[1], part, end, &node->bb[1]);
+ }
+ }
+ else {
+ INIT_MINMAX(node->bb[1].min, node->bb[1].max);
+ }
}
/* ******************** ARITH ************************* */
@@ -259,30 +266,30 @@ static void build_bvh_spatial(
* any and all purposes, provided that this notice appears in all copies.
*/
-#define L 0 /* left direction: -x, -i */
-#define R 1 /* right direction: +x, +i */
-#define B 2 /* bottom direction: -y, -j */
-#define T 3 /* top direction: +y, +j */
-#define N 4 /* near direction: -z, -k */
-#define F 5 /* far direction: +z, +k */
-#define LBN 0 /* left bottom near corner */
-#define LBF 1 /* left bottom far corner */
-#define LTN 2 /* left top near corner */
-#define LTF 3 /* left top far corner */
-#define RBN 4 /* right bottom near corner */
-#define RBF 5 /* right bottom far corner */
-#define RTN 6 /* right top near corner */
-#define RTF 7 /* right top far corner */
+#define L 0 /* left direction: -x, -i */
+#define R 1 /* right direction: +x, +i */
+#define B 2 /* bottom direction: -y, -j */
+#define T 3 /* top direction: +y, +j */
+#define N 4 /* near direction: -z, -k */
+#define F 5 /* far direction: +z, +k */
+#define LBN 0 /* left bottom near corner */
+#define LBF 1 /* left bottom far corner */
+#define LTN 2 /* left top near corner */
+#define LTF 3 /* left top far corner */
+#define RBN 4 /* right bottom near corner */
+#define RBF 5 /* right bottom far corner */
+#define RTN 6 /* right top near corner */
+#define RTF 7 /* right top far corner */
/**
* the LBN corner of cube (i, j, k), corresponds with location
* (i-0.5)*size, (j-0.5)*size, (k-0.5)*size)
*/
-#define HASHBIT (5)
-#define HASHSIZE (size_t)(1 << (3 * HASHBIT)) /*! < hash table size (32768) */
+#define HASHBIT (5)
+#define HASHSIZE (size_t)(1 << (3 * HASHBIT)) /*! < hash table size (32768) */
-#define HASH(i, j, k) ((((( (i) & 31) << 5) | ( (j) & 31)) << 5) | ( (k) & 31) )
+#define HASH(i, j, k) ((((((i)&31) << 5) | ((j)&31)) << 5) | ((k)&31))
#define MB_BIT(i, bit) (((i) >> (bit)) & 1)
// #define FLIP(i, bit) ((i) ^ 1 << (bit)) /* flip the given bit of i */
@@ -299,60 +306,78 @@ static void build_bvh_spatial(
*/
static float densfunc(const MetaElem *ball, float x, float y, float z)
{
- float dist2;
- float dvec[3] = {x, y, z};
-
- mul_m4_v3((float (*)[4])ball->imat, dvec);
-
- switch (ball->type) {
- case MB_BALL:
- /* do nothing */
- break;
- case MB_CUBE:
- if (dvec[2] > ball->expz) dvec[2] -= ball->expz;
- else if (dvec[2] < -ball->expz) dvec[2] += ball->expz;
- else dvec[2] = 0.0;
- ATTR_FALLTHROUGH;
- case MB_PLANE:
- if (dvec[1] > ball->expy) dvec[1] -= ball->expy;
- else if (dvec[1] < -ball->expy) dvec[1] += ball->expy;
- else dvec[1] = 0.0;
- ATTR_FALLTHROUGH;
- case MB_TUBE:
- if (dvec[0] > ball->expx) dvec[0] -= ball->expx;
- else if (dvec[0] < -ball->expx) dvec[0] += ball->expx;
- else dvec[0] = 0.0;
- break;
- case MB_ELIPSOID:
- dvec[0] /= ball->expx;
- dvec[1] /= ball->expy;
- dvec[2] /= ball->expz;
- break;
-
- /* *** deprecated, could be removed?, do-versioned at least *** */
- case MB_TUBEX:
- if (dvec[0] > ball->len) dvec[0] -= ball->len;
- else if (dvec[0] < -ball->len) dvec[0] += ball->len;
- else dvec[0] = 0.0;
- break;
- case MB_TUBEY:
- if (dvec[1] > ball->len) dvec[1] -= ball->len;
- else if (dvec[1] < -ball->len) dvec[1] += ball->len;
- else dvec[1] = 0.0;
- break;
- case MB_TUBEZ:
- if (dvec[2] > ball->len) dvec[2] -= ball->len;
- else if (dvec[2] < -ball->len) dvec[2] += ball->len;
- else dvec[2] = 0.0;
- break;
- /* *** end deprecated *** */
- }
-
- /* ball->rad2 is inverse of squared rad */
- dist2 = 1.0f - (len_squared_v3(dvec) * ball->rad2);
-
- /* ball->s is negative if metaball is negative */
- return (dist2 < 0.0f) ? 0.0f : (ball->s * dist2 * dist2 * dist2);
+ float dist2;
+ float dvec[3] = {x, y, z};
+
+ mul_m4_v3((float(*)[4])ball->imat, dvec);
+
+ switch (ball->type) {
+ case MB_BALL:
+ /* do nothing */
+ break;
+ case MB_CUBE:
+ if (dvec[2] > ball->expz)
+ dvec[2] -= ball->expz;
+ else if (dvec[2] < -ball->expz)
+ dvec[2] += ball->expz;
+ else
+ dvec[2] = 0.0;
+ ATTR_FALLTHROUGH;
+ case MB_PLANE:
+ if (dvec[1] > ball->expy)
+ dvec[1] -= ball->expy;
+ else if (dvec[1] < -ball->expy)
+ dvec[1] += ball->expy;
+ else
+ dvec[1] = 0.0;
+ ATTR_FALLTHROUGH;
+ case MB_TUBE:
+ if (dvec[0] > ball->expx)
+ dvec[0] -= ball->expx;
+ else if (dvec[0] < -ball->expx)
+ dvec[0] += ball->expx;
+ else
+ dvec[0] = 0.0;
+ break;
+ case MB_ELIPSOID:
+ dvec[0] /= ball->expx;
+ dvec[1] /= ball->expy;
+ dvec[2] /= ball->expz;
+ break;
+
+ /* *** deprecated, could be removed?, do-versioned at least *** */
+ case MB_TUBEX:
+ if (dvec[0] > ball->len)
+ dvec[0] -= ball->len;
+ else if (dvec[0] < -ball->len)
+ dvec[0] += ball->len;
+ else
+ dvec[0] = 0.0;
+ break;
+ case MB_TUBEY:
+ if (dvec[1] > ball->len)
+ dvec[1] -= ball->len;
+ else if (dvec[1] < -ball->len)
+ dvec[1] += ball->len;
+ else
+ dvec[1] = 0.0;
+ break;
+ case MB_TUBEZ:
+ if (dvec[2] > ball->len)
+ dvec[2] -= ball->len;
+ else if (dvec[2] < -ball->len)
+ dvec[2] += ball->len;
+ else
+ dvec[2] = 0.0;
+ break;
+ /* *** end deprecated *** */
+ }
+
+ /* ball->rad2 is inverse of squared rad */
+ dist2 = 1.0f - (len_squared_v3(dvec) * ball->rad2);
+
+ /* ball->s is negative if metaball is negative */
+ return (dist2 < 0.0f) ? 0.0f : (ball->s * dist2 * dist2 * dist2);
}
/**
@@ -361,28 +386,28 @@ static float densfunc(const MetaElem *ball, float x, float y, float z)
*/
static float metaball(PROCESS *process, float x, float y, float z)
{
- int i;
- float dens = 0.0f;
- unsigned int front = 0, back = 0;
- MetaballBVHNode *node;
-
- process->bvh_queue[front++] = &process->metaball_bvh;
-
- while (front != back) {
- node = process->bvh_queue[back++];
-
- for (i = 0; i < 2; i++) {
- if ((node->bb[i].min[0] <= x) && (node->bb[i].max[0] >= x) &&
- (node->bb[i].min[1] <= y) && (node->bb[i].max[1] >= y) &&
- (node->bb[i].min[2] <= z) && (node->bb[i].max[2] >= z))
- {
- if (node->child[i]) process->bvh_queue[front++] = node->child[i];
- else dens += densfunc(node->bb[i].ml, x, y, z);
- }
- }
- }
-
- return process->thresh - dens;
+ int i;
+ float dens = 0.0f;
+ unsigned int front = 0, back = 0;
+ MetaballBVHNode *node;
+
+ process->bvh_queue[front++] = &process->metaball_bvh;
+
+ while (front != back) {
+ node = process->bvh_queue[back++];
+
+ for (i = 0; i < 2; i++) {
+ if ((node->bb[i].min[0] <= x) && (node->bb[i].max[0] >= x) && (node->bb[i].min[1] <= y) &&
+ (node->bb[i].max[1] >= y) && (node->bb[i].min[2] <= z) && (node->bb[i].max[2] >= z)) {
+ if (node->child[i])
+ process->bvh_queue[front++] = node->child[i];
+ else
+ dens += densfunc(node->bb[i].ml, x, y, z);
+ }
+ }
+ }
+
+ return process->thresh - dens;
}
/**
@@ -390,87 +415,148 @@ static float metaball(PROCESS *process, float x, float y, float z)
*/
static void make_face(PROCESS *process, int i1, int i2, int i3, int i4)
{
- int *cur;
+ int *cur;
#ifdef USE_ACCUM_NORMAL
- float n[3];
+ float n[3];
#endif
- if (UNLIKELY(process->totindex == process->curindex)) {
- process->totindex += 4096;
- process->indices = MEM_reallocN(process->indices, sizeof(int[4]) * process->totindex);
- }
+ if (UNLIKELY(process->totindex == process->curindex)) {
+ process->totindex += 4096;
+ process->indices = MEM_reallocN(process->indices, sizeof(int[4]) * process->totindex);
+ }
- cur = process->indices[process->curindex++];
+ cur = process->indices[process->curindex++];
- /* displists now support array drawing, we treat tri's as fake quad */
+ /* displists now support array drawing, we treat tri's as fake quad */
- cur[0] = i1;
- cur[1] = i2;
- cur[2] = i3;
- cur[3] = i4;
+ cur[0] = i1;
+ cur[1] = i2;
+ cur[2] = i3;
+ cur[3] = i4;
#ifdef USE_ACCUM_NORMAL
- if (i4 == i3) {
- normal_tri_v3(n, process->co[i1], process->co[i2], process->co[i3]);
- accumulate_vertex_normals_v3(
- process->no[i1], process->no[i2], process->no[i3], NULL, n,
- process->co[i1], process->co[i2], process->co[i3], NULL);
- }
- else {
- normal_quad_v3(n, process->co[i1], process->co[i2], process->co[i3], process->co[i4]);
- accumulate_vertex_normals_v3(
- process->no[i1], process->no[i2], process->no[i3], process->no[i4], n,
- process->co[i1], process->co[i2], process->co[i3], process->co[i4]);
- }
+ if (i4 == i3) {
+ normal_tri_v3(n, process->co[i1], process->co[i2], process->co[i3]);
+ accumulate_vertex_normals_v3(process->no[i1],
+ process->no[i2],
+ process->no[i3],
+ NULL,
+ n,
+ process->co[i1],
+ process->co[i2],
+ process->co[i3],
+ NULL);
+ }
+ else {
+ normal_quad_v3(n, process->co[i1], process->co[i2], process->co[i3], process->co[i4]);
+ accumulate_vertex_normals_v3(process->no[i1],
+ process->no[i2],
+ process->no[i3],
+ process->no[i4],
+ n,
+ process->co[i1],
+ process->co[i2],
+ process->co[i3],
+ process->co[i4]);
+ }
#endif
-
}
/* Frees allocated memory */
static void freepolygonize(PROCESS *process)
{
- if (process->corners) MEM_freeN(process->corners);
- if (process->edges) MEM_freeN(process->edges);
- if (process->centers) MEM_freeN(process->centers);
- if (process->mainb) MEM_freeN(process->mainb);
- if (process->bvh_queue) MEM_freeN(process->bvh_queue);
- if (process->pgn_elements) BLI_memarena_free(process->pgn_elements);
+ if (process->corners)
+ MEM_freeN(process->corners);
+ if (process->edges)
+ MEM_freeN(process->edges);
+ if (process->centers)
+ MEM_freeN(process->centers);
+ if (process->mainb)
+ MEM_freeN(process->mainb);
+ if (process->bvh_queue)
+ MEM_freeN(process->bvh_queue);
+ if (process->pgn_elements)
+ BLI_memarena_free(process->pgn_elements);
}
/* **************** POLYGONIZATION ************************ */
/**** Cubical Polygonization (optional) ****/
-#define LB 0 /* left bottom edge */
-#define LT 1 /* left top edge */
-#define LN 2 /* left near edge */
-#define LF 3 /* left far edge */
-#define RB 4 /* right bottom edge */
-#define RT 5 /* right top edge */
-#define RN 6 /* right near edge */
-#define RF 7 /* right far edge */
-#define BN 8 /* bottom near edge */
-#define BF 9 /* bottom far edge */
-#define TN 10 /* top near edge */
-#define TF 11 /* top far edge */
+#define LB 0 /* left bottom edge */
+#define LT 1 /* left top edge */
+#define LN 2 /* left near edge */
+#define LF 3 /* left far edge */
+#define RB 4 /* right bottom edge */
+#define RT 5 /* right top edge */
+#define RN 6 /* right near edge */
+#define RF 7 /* right far edge */
+#define BN 8 /* bottom near edge */
+#define BF 9 /* bottom far edge */
+#define TN 10 /* top near edge */
+#define TF 11 /* top far edge */
static INTLISTS *cubetable[256];
static char faces[256];
/* edge: LB, LT, LN, LF, RB, RT, RN, RF, BN, BF, TN, TF */
static int corner1[12] = {
- LBN, LTN, LBN, LBF, RBN, RTN, RBN, RBF, LBN, LBF, LTN, LTF,
+ LBN,
+ LTN,
+ LBN,
+ LBF,
+ RBN,
+ RTN,
+ RBN,
+ RBF,
+ LBN,
+ LBF,
+ LTN,
+ LTF,
};
static int corner2[12] = {
- LBF, LTF, LTN, LTF, RBF, RTF, RTN, RTF, RBN, RBF, RTN, RTF,
+ LBF,
+ LTF,
+ LTN,
+ LTF,
+ RBF,
+ RTF,
+ RTN,
+ RTF,
+ RBN,
+ RBF,
+ RTN,
+ RTF,
};
static int leftface[12] = {
- B, L, L, F, R, T, N, R, N, B, T, F,
+ B,
+ L,
+ L,
+ F,
+ R,
+ T,
+ N,
+ R,
+ N,
+ B,
+ T,
+ F,
};
/* face on left when going corner1 to corner2 */
static int rightface[12] = {
- L, T, N, L, B, R, R, F, B, F, N, T,
+ L,
+ T,
+ N,
+ L,
+ B,
+ R,
+ R,
+ F,
+ B,
+ F,
+ N,
+ T,
};
/* face on right when going corner1 to corner2 */
@@ -479,64 +565,70 @@ static int rightface[12] = {
*/
static void docube(PROCESS *process, CUBE *cube)
{
- INTLISTS *polys;
- CORNER *c1, *c2;
- int i, index = 0, count, indexar[8];
-
- /* Determine which case cube falls into. */
- for (i = 0; i < 8; i++) {
- if (cube->corners[i]->value > 0.0f) {
- index += (1 << i);
- }
- }
-
- /* Using faces[] table, adds neighbouring cube if surface intersects face in this direction. */
- if (MB_BIT(faces[index], 0)) add_cube(process, cube->i - 1, cube->j, cube->k);
- if (MB_BIT(faces[index], 1)) add_cube(process, cube->i + 1, cube->j, cube->k);
- if (MB_BIT(faces[index], 2)) add_cube(process, cube->i, cube->j - 1, cube->k);
- if (MB_BIT(faces[index], 3)) add_cube(process, cube->i, cube->j + 1, cube->k);
- if (MB_BIT(faces[index], 4)) add_cube(process, cube->i, cube->j, cube->k - 1);
- if (MB_BIT(faces[index], 5)) add_cube(process, cube->i, cube->j, cube->k + 1);
-
- /* Using cubetable[], determines polygons for output. */
- for (polys = cubetable[index]; polys; polys = polys->next) {
- INTLIST *edges;
-
- count = 0;
- /* Sets needed vertex id's lying on the edges. */
- for (edges = polys->list; edges; edges = edges->next) {
- c1 = cube->corners[corner1[edges->i]];
- c2 = cube->corners[corner2[edges->i]];
-
- indexar[count] = vertid(process, c1, c2);
- count++;
- }
-
- /* Adds faces to output. */
- if (count > 2) {
- switch (count) {
- case 3:
- make_face(process, indexar[2], indexar[1], indexar[0], indexar[0]); /* triangle */
- break;
- case 4:
- make_face(process, indexar[3], indexar[2], indexar[1], indexar[0]);
- break;
- case 5:
- make_face(process, indexar[3], indexar[2], indexar[1], indexar[0]);
- make_face(process, indexar[4], indexar[3], indexar[0], indexar[0]); /* triangle */
- break;
- case 6:
- make_face(process, indexar[3], indexar[2], indexar[1], indexar[0]);
- make_face(process, indexar[5], indexar[4], indexar[3], indexar[0]);
- break;
- case 7:
- make_face(process, indexar[3], indexar[2], indexar[1], indexar[0]);
- make_face(process, indexar[5], indexar[4], indexar[3], indexar[0]);
- make_face(process, indexar[6], indexar[5], indexar[0], indexar[0]); /* triangle */
- break;
- }
- }
- }
+ INTLISTS *polys;
+ CORNER *c1, *c2;
+ int i, index = 0, count, indexar[8];
+
+ /* Determine which case cube falls into. */
+ for (i = 0; i < 8; i++) {
+ if (cube->corners[i]->value > 0.0f) {
+ index += (1 << i);
+ }
+ }
+
+ /* Using faces[] table, adds neighbouring cube if surface intersects face in this direction. */
+ if (MB_BIT(faces[index], 0))
+ add_cube(process, cube->i - 1, cube->j, cube->k);
+ if (MB_BIT(faces[index], 1))
+ add_cube(process, cube->i + 1, cube->j, cube->k);
+ if (MB_BIT(faces[index], 2))
+ add_cube(process, cube->i, cube->j - 1, cube->k);
+ if (MB_BIT(faces[index], 3))
+ add_cube(process, cube->i, cube->j + 1, cube->k);
+ if (MB_BIT(faces[index], 4))
+ add_cube(process, cube->i, cube->j, cube->k - 1);
+ if (MB_BIT(faces[index], 5))
+ add_cube(process, cube->i, cube->j, cube->k + 1);
+
+ /* Using cubetable[], determines polygons for output. */
+ for (polys = cubetable[index]; polys; polys = polys->next) {
+ INTLIST *edges;
+
+ count = 0;
+ /* Sets needed vertex id's lying on the edges. */
+ for (edges = polys->list; edges; edges = edges->next) {
+ c1 = cube->corners[corner1[edges->i]];
+ c2 = cube->corners[corner2[edges->i]];
+
+ indexar[count] = vertid(process, c1, c2);
+ count++;
+ }
+
+ /* Adds faces to output. */
+ if (count > 2) {
+ switch (count) {
+ case 3:
+ make_face(process, indexar[2], indexar[1], indexar[0], indexar[0]); /* triangle */
+ break;
+ case 4:
+ make_face(process, indexar[3], indexar[2], indexar[1], indexar[0]);
+ break;
+ case 5:
+ make_face(process, indexar[3], indexar[2], indexar[1], indexar[0]);
+ make_face(process, indexar[4], indexar[3], indexar[0], indexar[0]); /* triangle */
+ break;
+ case 6:
+ make_face(process, indexar[3], indexar[2], indexar[1], indexar[0]);
+ make_face(process, indexar[5], indexar[4], indexar[3], indexar[0]);
+ break;
+ case 7:
+ make_face(process, indexar[3], indexar[2], indexar[1], indexar[0]);
+ make_face(process, indexar[5], indexar[4], indexar[3], indexar[0]);
+ make_face(process, indexar[6], indexar[5], indexar[0], indexar[0]); /* triangle */
+ break;
+ }
+ }
+ }
}
/**
@@ -545,35 +637,35 @@ static void docube(PROCESS *process, CUBE *cube)
*/
static CORNER *setcorner(PROCESS *process, int i, int j, int k)
{
- /* for speed, do corner value caching here */
- CORNER *c;
- int index;
+ /* for speed, do corner value caching here */
+ CORNER *c;
+ int index;
- /* does corner exist? */
- index = HASH(i, j, k);
- c = process->corners[index];
+ /* does corner exist? */
+ index = HASH(i, j, k);
+ c = process->corners[index];
- for (; c != NULL; c = c->next) {
- if (c->i == i && c->j == j && c->k == k) {
- return c;
- }
- }
+ for (; c != NULL; c = c->next) {
+ if (c->i == i && c->j == j && c->k == k) {
+ return c;
+ }
+ }
- c = BLI_memarena_alloc(process->pgn_elements, sizeof(CORNER));
+ c = BLI_memarena_alloc(process->pgn_elements, sizeof(CORNER));
- c->i = i;
- c->co[0] = ((float)i - 0.5f) * process->size;
- c->j = j;
- c->co[1] = ((float)j - 0.5f) * process->size;
- c->k = k;
- c->co[2] = ((float)k - 0.5f) * process->size;
+ c->i = i;
+ c->co[0] = ((float)i - 0.5f) * process->size;
+ c->j = j;
+ c->co[1] = ((float)j - 0.5f) * process->size;
+ c->k = k;
+ c->co[2] = ((float)k - 0.5f) * process->size;
- c->value = metaball(process, c->co[0], c->co[1], c->co[2]);
+ c->value = metaball(process, c->co[0], c->co[1], c->co[2]);
- c->next = process->corners[index];
- process->corners[index] = c;
+ c->next = process->corners[index];
+ process->corners[index] = c;
- return c;
+ return c;
}
/**
@@ -581,33 +673,33 @@ static CORNER *setcorner(PROCESS *process, int i, int j, int k)
*/
static int nextcwedge(int edge, int face)
{
- switch (edge) {
- case LB:
- return (face == L) ? LF : BN;
- case LT:
- return (face == L) ? LN : TF;
- case LN:
- return (face == L) ? LB : TN;
- case LF:
- return (face == L) ? LT : BF;
- case RB:
- return (face == R) ? RN : BF;
- case RT:
- return (face == R) ? RF : TN;
- case RN:
- return (face == R) ? RT : BN;
- case RF:
- return (face == R) ? RB : TF;
- case BN:
- return (face == B) ? RB : LN;
- case BF:
- return (face == B) ? LB : RF;
- case TN:
- return (face == T) ? LT : RN;
- case TF:
- return (face == T) ? RT : LF;
- }
- return 0;
+ switch (edge) {
+ case LB:
+ return (face == L) ? LF : BN;
+ case LT:
+ return (face == L) ? LN : TF;
+ case LN:
+ return (face == L) ? LB : TN;
+ case LF:
+ return (face == L) ? LT : BF;
+ case RB:
+ return (face == R) ? RN : BF;
+ case RT:
+ return (face == R) ? RF : TN;
+ case RN:
+ return (face == R) ? RT : BN;
+ case RF:
+ return (face == R) ? RB : TF;
+ case BN:
+ return (face == B) ? RB : LN;
+ case BF:
+ return (face == B) ? LB : RF;
+ case TN:
+ return (face == T) ? LT : RN;
+ case TF:
+ return (face == T) ? RT : LF;
+ }
+ return 0;
}
/**
@@ -615,8 +707,8 @@ static int nextcwedge(int edge, int face)
*/
static int otherface(int edge, int face)
{
- int other = leftface[edge];
- return face == other ? rightface[edge] : other;
+ int other = leftface[edge];
+ return face == other ? rightface[edge] : other;
}
/**
@@ -624,86 +716,96 @@ static int otherface(int edge, int face)
*/
static void makecubetable(void)
{
- static bool is_done = false;
- int i, e, c, done[12], pos[8];
-
- if (is_done) return;
- is_done = true;
-
- for (i = 0; i < 256; i++) {
- for (e = 0; e < 12; e++) done[e] = 0;
- for (c = 0; c < 8; c++) pos[c] = MB_BIT(i, c);
- for (e = 0; e < 12; e++) {
- if (!done[e] && (pos[corner1[e]] != pos[corner2[e]])) {
- INTLIST *ints = NULL;
- INTLISTS *lists = MEM_callocN(sizeof(INTLISTS), "mball_intlist");
- int start = e, edge = e;
-
- /* get face that is to right of edge from pos to neg corner: */
- int face = pos[corner1[e]] ? rightface[e] : leftface[e];
-
- while (1) {
- edge = nextcwedge(edge, face);
- done[edge] = 1;
- if (pos[corner1[edge]] != pos[corner2[edge]]) {
- INTLIST *tmp = ints;
-
- ints = MEM_callocN(sizeof(INTLIST), "mball_intlist");
- ints->i = edge;
- ints->next = tmp; /* add edge to head of list */
-
- if (edge == start) break;
- face = otherface(edge, face);
- }
- }
- lists->list = ints; /* add ints to head of table entry */
- lists->next = cubetable[i];
- cubetable[i] = lists;
- }
- }
- }
-
- for (i = 0; i < 256; i++) {
- INTLISTS *polys;
- faces[i] = 0;
- for (polys = cubetable[i]; polys; polys = polys->next) {
- INTLIST *edges;
-
- for (edges = polys->list; edges; edges = edges->next) {
- if (edges->i == LB || edges->i == LT || edges->i == LN || edges->i == LF) faces[i] |= 1 << L;
- if (edges->i == RB || edges->i == RT || edges->i == RN || edges->i == RF) faces[i] |= 1 << R;
- if (edges->i == LB || edges->i == RB || edges->i == BN || edges->i == BF) faces[i] |= 1 << B;
- if (edges->i == LT || edges->i == RT || edges->i == TN || edges->i == TF) faces[i] |= 1 << T;
- if (edges->i == LN || edges->i == RN || edges->i == BN || edges->i == TN) faces[i] |= 1 << N;
- if (edges->i == LF || edges->i == RF || edges->i == BF || edges->i == TF) faces[i] |= 1 << F;
- }
- }
- }
+ static bool is_done = false;
+ int i, e, c, done[12], pos[8];
+
+ if (is_done)
+ return;
+ is_done = true;
+
+ for (i = 0; i < 256; i++) {
+ for (e = 0; e < 12; e++)
+ done[e] = 0;
+ for (c = 0; c < 8; c++)
+ pos[c] = MB_BIT(i, c);
+ for (e = 0; e < 12; e++) {
+ if (!done[e] && (pos[corner1[e]] != pos[corner2[e]])) {
+ INTLIST *ints = NULL;
+ INTLISTS *lists = MEM_callocN(sizeof(INTLISTS), "mball_intlist");
+ int start = e, edge = e;
+
+ /* get face that is to right of edge from pos to neg corner: */
+ int face = pos[corner1[e]] ? rightface[e] : leftface[e];
+
+ while (1) {
+ edge = nextcwedge(edge, face);
+ done[edge] = 1;
+ if (pos[corner1[edge]] != pos[corner2[edge]]) {
+ INTLIST *tmp = ints;
+
+ ints = MEM_callocN(sizeof(INTLIST), "mball_intlist");
+ ints->i = edge;
+ ints->next = tmp; /* add edge to head of list */
+
+ if (edge == start)
+ break;
+ face = otherface(edge, face);
+ }
+ }
+ lists->list = ints; /* add ints to head of table entry */
+ lists->next = cubetable[i];
+ cubetable[i] = lists;
+ }
+ }
+ }
+
+ for (i = 0; i < 256; i++) {
+ INTLISTS *polys;
+ faces[i] = 0;
+ for (polys = cubetable[i]; polys; polys = polys->next) {
+ INTLIST *edges;
+
+ for (edges = polys->list; edges; edges = edges->next) {
+ if (edges->i == LB || edges->i == LT || edges->i == LN || edges->i == LF)
+ faces[i] |= 1 << L;
+ if (edges->i == RB || edges->i == RT || edges->i == RN || edges->i == RF)
+ faces[i] |= 1 << R;
+ if (edges->i == LB || edges->i == RB || edges->i == BN || edges->i == BF)
+ faces[i] |= 1 << B;
+ if (edges->i == LT || edges->i == RT || edges->i == TN || edges->i == TF)
+ faces[i] |= 1 << T;
+ if (edges->i == LN || edges->i == RN || edges->i == BN || edges->i == TN)
+ faces[i] |= 1 << N;
+ if (edges->i == LF || edges->i == RF || edges->i == BF || edges->i == TF)
+ faces[i] |= 1 << F;
+ }
+ }
+ }
}
void BKE_mball_cubeTable_free(void)
{
- int i;
- INTLISTS *lists, *nlists;
- INTLIST *ints, *nints;
-
- for (i = 0; i < 256; i++) {
- lists = cubetable[i];
- while (lists) {
- nlists = lists->next;
-
- ints = lists->list;
- while (ints) {
- nints = ints->next;
- MEM_freeN(ints);
- ints = nints;
- }
-
- MEM_freeN(lists);
- lists = nlists;
- }
- cubetable[i] = NULL;
- }
+ int i;
+ INTLISTS *lists, *nlists;
+ INTLIST *ints, *nints;
+
+ for (i = 0; i < 256; i++) {
+ lists = cubetable[i];
+ while (lists) {
+ nlists = lists->next;
+
+ ints = lists->list;
+ while (ints) {
+ nints = ints->next;
+ MEM_freeN(ints);
+ ints = nints;
+ }
+
+ MEM_freeN(lists);
+ lists = nlists;
+ }
+ cubetable[i] = NULL;
+ }
}
/**** Storage ****/
@@ -713,92 +815,85 @@ void BKE_mball_cubeTable_free(void)
*/
static int setcenter(PROCESS *process, CENTERLIST *table[], const int i, const int j, const int k)
{
- int index;
- CENTERLIST *newc, *l, *q;
+ int index;
+ CENTERLIST *newc, *l, *q;
- index = HASH(i, j, k);
- q = table[index];
+ index = HASH(i, j, k);
+ q = table[index];
- for (l = q; l != NULL; l = l->next) {
- if (l->i == i && l->j == j && l->k == k) return 1;
- }
+ for (l = q; l != NULL; l = l->next) {
+ if (l->i == i && l->j == j && l->k == k)
+ return 1;
+ }
- newc = BLI_memarena_alloc(process->pgn_elements, sizeof(CENTERLIST));
- newc->i = i;
- newc->j = j;
- newc->k = k;
- newc->next = q;
- table[index] = newc;
+ newc = BLI_memarena_alloc(process->pgn_elements, sizeof(CENTERLIST));
+ newc->i = i;
+ newc->j = j;
+ newc->k = k;
+ newc->next = q;
+ table[index] = newc;
- return 0;
+ return 0;
}
/**
* Sets vid of vertex lying on given edge.
*/
-static void setedge(
- PROCESS *process,
- int i1, int j1, int k1,
- int i2, int j2, int k2,
- int vid)
+static void setedge(PROCESS *process, int i1, int j1, int k1, int i2, int j2, int k2, int vid)
{
- int index;
- EDGELIST *newe;
-
- if (i1 > i2 || (i1 == i2 && (j1 > j2 || (j1 == j2 && k1 > k2)))) {
- int t = i1;
- i1 = i2;
- i2 = t;
- t = j1;
- j1 = j2;
- j2 = t;
- t = k1;
- k1 = k2;
- k2 = t;
- }
- index = HASH(i1, j1, k1) + HASH(i2, j2, k2);
- newe = BLI_memarena_alloc(process->pgn_elements, sizeof(EDGELIST));
-
- newe->i1 = i1;
- newe->j1 = j1;
- newe->k1 = k1;
- newe->i2 = i2;
- newe->j2 = j2;
- newe->k2 = k2;
- newe->vid = vid;
- newe->next = process->edges[index];
- process->edges[index] = newe;
+ int index;
+ EDGELIST *newe;
+
+ if (i1 > i2 || (i1 == i2 && (j1 > j2 || (j1 == j2 && k1 > k2)))) {
+ int t = i1;
+ i1 = i2;
+ i2 = t;
+ t = j1;
+ j1 = j2;
+ j2 = t;
+ t = k1;
+ k1 = k2;
+ k2 = t;
+ }
+ index = HASH(i1, j1, k1) + HASH(i2, j2, k2);
+ newe = BLI_memarena_alloc(process->pgn_elements, sizeof(EDGELIST));
+
+ newe->i1 = i1;
+ newe->j1 = j1;
+ newe->k1 = k1;
+ newe->i2 = i2;
+ newe->j2 = j2;
+ newe->k2 = k2;
+ newe->vid = vid;
+ newe->next = process->edges[index];
+ process->edges[index] = newe;
}
/**
* \return vertex id for edge; return -1 if not set
*/
-static int getedge(EDGELIST *table[],
- int i1, int j1, int k1,
- int i2, int j2, int k2)
+static int getedge(EDGELIST *table[], int i1, int j1, int k1, int i2, int j2, int k2)
{
- EDGELIST *q;
-
- if (i1 > i2 || (i1 == i2 && (j1 > j2 || (j1 == j2 && k1 > k2)))) {
- int t = i1;
- i1 = i2;
- i2 = t;
- t = j1;
- j1 = j2;
- j2 = t;
- t = k1;
- k1 = k2;
- k2 = t;
- }
- q = table[HASH(i1, j1, k1) + HASH(i2, j2, k2)];
- for (; q != NULL; q = q->next) {
- if (q->i1 == i1 && q->j1 == j1 && q->k1 == k1 &&
- q->i2 == i2 && q->j2 == j2 && q->k2 == k2)
- {
- return q->vid;
- }
- }
- return -1;
+ EDGELIST *q;
+
+ if (i1 > i2 || (i1 == i2 && (j1 > j2 || (j1 == j2 && k1 > k2)))) {
+ int t = i1;
+ i1 = i2;
+ i2 = t;
+ t = j1;
+ j1 = j2;
+ j2 = t;
+ t = k1;
+ k1 = k2;
+ k2 = t;
+ }
+ q = table[HASH(i1, j1, k1) + HASH(i2, j2, k2)];
+ for (; q != NULL; q = q->next) {
+ if (q->i1 == i1 && q->j1 == j1 && q->k1 == k1 && q->i2 == i2 && q->j2 == j2 && q->k2 == k2) {
+ return q->vid;
+ }
+ }
+ return -1;
}
/**
@@ -806,16 +901,16 @@ static int getedge(EDGELIST *table[],
*/
static void addtovertices(PROCESS *process, const float v[3], const float no[3])
{
- if (process->curvertex == process->totvertex) {
- process->totvertex += 4096;
- process->co = MEM_reallocN(process->co, process->totvertex * sizeof(float[3]));
- process->no = MEM_reallocN(process->no, process->totvertex * sizeof(float[3]));
- }
+ if (process->curvertex == process->totvertex) {
+ process->totvertex += 4096;
+ process->co = MEM_reallocN(process->co, process->totvertex * sizeof(float[3]));
+ process->no = MEM_reallocN(process->no, process->totvertex * sizeof(float[3]));
+ }
- copy_v3_v3(process->co[process->curvertex], v);
- copy_v3_v3(process->no[process->curvertex], no);
+ copy_v3_v3(process->co[process->curvertex], v);
+ copy_v3_v3(process->no[process->curvertex], no);
- process->curvertex++;
+ process->curvertex++;
}
#ifndef USE_ACCUM_NORMAL
@@ -826,14 +921,14 @@ static void addtovertices(PROCESS *process, const float v[3], const float no[3])
*/
static void vnormal(PROCESS *process, const float point[3], float r_no[3])
{
- const float delta = process->delta;
- const float f = metaball(process, point[0], point[1], point[2]);
+ const float delta = process->delta;
+ const float f = metaball(process, point[0], point[1], point[2]);
- r_no[0] = metaball(process, point[0] + delta, point[1], point[2]) - f;
- r_no[1] = metaball(process, point[0], point[1] + delta, point[2]) - f;
- r_no[2] = metaball(process, point[0], point[1], point[2] + delta) - f;
+ r_no[0] = metaball(process, point[0] + delta, point[1], point[2]) - f;
+ r_no[1] = metaball(process, point[0], point[1] + delta, point[2]) - f;
+ r_no[2] = metaball(process, point[0], point[1], point[2] + delta) - f;
}
-#endif /* USE_ACCUM_NORMAL */
+#endif /* USE_ACCUM_NORMAL */
/**
* \return the id of vertex between two corners.
@@ -842,24 +937,25 @@ static void vnormal(PROCESS *process, const float point[3], float r_no[3])
*/
static int vertid(PROCESS *process, const CORNER *c1, const CORNER *c2)
{
- float v[3], no[3];
- int vid = getedge(process->edges, c1->i, c1->j, c1->k, c2->i, c2->j, c2->k);
+ float v[3], no[3];
+ int vid = getedge(process->edges, c1->i, c1->j, c1->k, c2->i, c2->j, c2->k);
- if (vid != -1) return vid; /* previously computed */
+ if (vid != -1)
+ return vid; /* previously computed */
- converge(process, c1, c2, v); /* position */
+ converge(process, c1, c2, v); /* position */
#ifdef USE_ACCUM_NORMAL
- zero_v3(no);
+ zero_v3(no);
#else
- vnormal(process, v, no);
+ vnormal(process, v, no);
#endif
- addtovertices(process, v, no); /* save vertex */
- vid = (int)process->curvertex - 1;
- setedge(process, c1->i, c1->j, c1->k, c2->i, c2->j, c2->k, vid);
+ addtovertices(process, v, no); /* save vertex */
+ vid = (int)process->curvertex - 1;
+ setedge(process, c1->i, c1->j, c1->k, c2->i, c2->j, c2->k, vid);
- return vid;
+ return vid;
}
/**
@@ -868,41 +964,40 @@ static int vertid(PROCESS *process, const CORNER *c1, const CORNER *c2)
*/
static void converge(PROCESS *process, const CORNER *c1, const CORNER *c2, float r_p[3])
{
- float tmp, dens;
- unsigned int i;
- float c1_value, c1_co[3];
- float c2_value, c2_co[3];
-
- if (c1->value < c2->value) {
- c1_value = c2->value;
- copy_v3_v3(c1_co, c2->co);
- c2_value = c1->value;
- copy_v3_v3(c2_co, c1->co);
- }
- else {
- c1_value = c1->value;
- copy_v3_v3(c1_co, c1->co);
- c2_value = c2->value;
- copy_v3_v3(c2_co, c2->co);
- }
-
-
- for (i = 0; i < process->converge_res; i++) {
- interp_v3_v3v3(r_p, c1_co, c2_co, 0.5f);
- dens = metaball(process, r_p[0], r_p[1], r_p[2]);
-
- if (dens > 0.0f) {
- c1_value = dens;
- copy_v3_v3(c1_co, r_p);
- }
- else {
- c2_value = dens;
- copy_v3_v3(c2_co, r_p);
- }
- }
-
- tmp = -c1_value / (c2_value - c1_value);
- interp_v3_v3v3(r_p, c1_co, c2_co, tmp);
+ float tmp, dens;
+ unsigned int i;
+ float c1_value, c1_co[3];
+ float c2_value, c2_co[3];
+
+ if (c1->value < c2->value) {
+ c1_value = c2->value;
+ copy_v3_v3(c1_co, c2->co);
+ c2_value = c1->value;
+ copy_v3_v3(c2_co, c1->co);
+ }
+ else {
+ c1_value = c1->value;
+ copy_v3_v3(c1_co, c1->co);
+ c2_value = c2->value;
+ copy_v3_v3(c2_co, c2->co);
+ }
+
+ for (i = 0; i < process->converge_res; i++) {
+ interp_v3_v3v3(r_p, c1_co, c2_co, 0.5f);
+ dens = metaball(process, r_p[0], r_p[1], r_p[2]);
+
+ if (dens > 0.0f) {
+ c1_value = dens;
+ copy_v3_v3(c1_co, r_p);
+ }
+ else {
+ c2_value = dens;
+ copy_v3_v3(c2_co, r_p);
+ }
+ }
+
+ tmp = -c1_value / (c2_value - c1_value);
+ interp_v3_v3v3(r_p, c1_co, c2_co, tmp);
}
/**
@@ -910,42 +1005,45 @@ static void converge(PROCESS *process, const CORNER *c1, const CORNER *c2, float
*/
static void add_cube(PROCESS *process, int i, int j, int k)
{
- CUBES *ncube;
- int n;
-
- /* test if cube has been found before */
- if (setcenter(process, process->centers, i, j, k) == 0) {
- /* push cube on stack: */
- ncube = BLI_memarena_alloc(process->pgn_elements, sizeof(CUBES));
- ncube->next = process->cubes;
- process->cubes = ncube;
-
- ncube->cube.i = i;
- ncube->cube.j = j;
- ncube->cube.k = k;
-
- /* set corners of initial cube: */
- for (n = 0; n < 8; n++)
- ncube->cube.corners[n] = setcorner(process, i + MB_BIT(n, 2), j + MB_BIT(n, 1), k + MB_BIT(n, 0));
- }
+ CUBES *ncube;
+ int n;
+
+ /* test if cube has been found before */
+ if (setcenter(process, process->centers, i, j, k) == 0) {
+ /* push cube on stack: */
+ ncube = BLI_memarena_alloc(process->pgn_elements, sizeof(CUBES));
+ ncube->next = process->cubes;
+ process->cubes = ncube;
+
+ ncube->cube.i = i;
+ ncube->cube.j = j;
+ ncube->cube.k = k;
+
+ /* set corners of initial cube: */
+ for (n = 0; n < 8; n++)
+ ncube->cube.corners[n] = setcorner(
+ process, i + MB_BIT(n, 2), j + MB_BIT(n, 1), k + MB_BIT(n, 0));
+ }
}
static void next_lattice(int r[3], const float pos[3], const float size)
{
- r[0] = (int)ceil((pos[0] / size) + 0.5f);
- r[1] = (int)ceil((pos[1] / size) + 0.5f);
- r[2] = (int)ceil((pos[2] / size) + 0.5f);
+ r[0] = (int)ceil((pos[0] / size) + 0.5f);
+ r[1] = (int)ceil((pos[1] / size) + 0.5f);
+ r[2] = (int)ceil((pos[2] / size) + 0.5f);
}
static void prev_lattice(int r[3], const float pos[3], const float size)
{
- next_lattice(r, pos, size);
- r[0]--; r[1]--; r[2]--;
+ next_lattice(r, pos, size);
+ r[0]--;
+ r[1]--;
+ r[2]--;
}
static void closest_latice(int r[3], const float pos[3], const float size)
{
- r[0] = (int)floorf(pos[0] / size + 1.0f);
- r[1] = (int)floorf(pos[1] / size + 1.0f);
- r[2] = (int)floorf(pos[2] / size + 1.0f);
+ r[0] = (int)floorf(pos[0] / size + 1.0f);
+ r[1] = (int)floorf(pos[1] / size + 1.0f);
+ r[2] = (int)floorf(pos[2] / size + 1.0f);
}
/**
@@ -953,47 +1051,47 @@ static void closest_latice(int r[3], const float pos[3], const float size)
*/
static void find_first_points(PROCESS *process, const unsigned int em)
{
- const MetaElem *ml;
- int center[3], lbn[3], rtf[3], it[3], dir[3], add[3];
- float tmp[3], a, b;
-
- ml = process->mainb[em];
-
- mid_v3_v3v3(tmp, ml->bb->vec[0], ml->bb->vec[6]);
- closest_latice(center, tmp, process->size);
- prev_lattice(lbn, ml->bb->vec[0], process->size);
- next_lattice(rtf, ml->bb->vec[6], process->size);
-
- for (dir[0] = -1; dir[0] <= 1; dir[0]++) {
- for (dir[1] = -1; dir[1] <= 1; dir[1]++) {
- for (dir[2] = -1; dir[2] <= 1; dir[2]++) {
- if (dir[0] == 0 && dir[1] == 0 && dir[2] == 0) {
- continue;
- }
-
- copy_v3_v3_int(it, center);
-
- b = setcorner(process, it[0], it[1], it[2])->value;
- do {
- it[0] += dir[0];
- it[1] += dir[1];
- it[2] += dir[2];
- a = b;
- b = setcorner(process, it[0], it[1], it[2])->value;
-
- if (a * b < 0.0f) {
- add[0] = it[0] - dir[0];
- add[1] = it[1] - dir[1];
- add[2] = it[2] - dir[2];
- DO_MIN(it, add);
- add_cube(process, add[0], add[1], add[2]);
- break;
- }
- } while ((it[0] > lbn[0]) && (it[1] > lbn[1]) && (it[2] > lbn[2]) &&
- (it[0] < rtf[0]) && (it[1] < rtf[1]) && (it[2] < rtf[2]));
- }
- }
- }
+ const MetaElem *ml;
+ int center[3], lbn[3], rtf[3], it[3], dir[3], add[3];
+ float tmp[3], a, b;
+
+ ml = process->mainb[em];
+
+ mid_v3_v3v3(tmp, ml->bb->vec[0], ml->bb->vec[6]);
+ closest_latice(center, tmp, process->size);
+ prev_lattice(lbn, ml->bb->vec[0], process->size);
+ next_lattice(rtf, ml->bb->vec[6], process->size);
+
+ for (dir[0] = -1; dir[0] <= 1; dir[0]++) {
+ for (dir[1] = -1; dir[1] <= 1; dir[1]++) {
+ for (dir[2] = -1; dir[2] <= 1; dir[2]++) {
+ if (dir[0] == 0 && dir[1] == 0 && dir[2] == 0) {
+ continue;
+ }
+
+ copy_v3_v3_int(it, center);
+
+ b = setcorner(process, it[0], it[1], it[2])->value;
+ do {
+ it[0] += dir[0];
+ it[1] += dir[1];
+ it[2] += dir[2];
+ a = b;
+ b = setcorner(process, it[0], it[1], it[2])->value;
+
+ if (a * b < 0.0f) {
+ add[0] = it[0] - dir[0];
+ add[1] = it[1] - dir[1];
+ add[2] = it[2] - dir[2];
+ DO_MIN(it, add);
+ add_cube(process, add[0], add[1], add[2]);
+ break;
+ }
+ } while ((it[0] > lbn[0]) && (it[1] > lbn[1]) && (it[2] > lbn[2]) && (it[0] < rtf[0]) &&
+ (it[1] < rtf[1]) && (it[2] < rtf[2]));
+ }
+ }
+ }
}
/**
@@ -1004,26 +1102,27 @@ static void find_first_points(PROCESS *process, const unsigned int em)
*/
static void polygonize(PROCESS *process)
{
- CUBE c;
- unsigned int i;
+ CUBE c;
+ unsigned int i;
- process->centers = MEM_callocN(HASHSIZE * sizeof(CENTERLIST *), "mbproc->centers");
- process->corners = MEM_callocN(HASHSIZE * sizeof(CORNER *), "mbproc->corners");
- process->edges = MEM_callocN(2 * HASHSIZE * sizeof(EDGELIST *), "mbproc->edges");
- process->bvh_queue = MEM_callocN(sizeof(MetaballBVHNode *) * process->bvh_queue_size, "Metaball BVH Queue");
+ process->centers = MEM_callocN(HASHSIZE * sizeof(CENTERLIST *), "mbproc->centers");
+ process->corners = MEM_callocN(HASHSIZE * sizeof(CORNER *), "mbproc->corners");
+ process->edges = MEM_callocN(2 * HASHSIZE * sizeof(EDGELIST *), "mbproc->edges");
+ process->bvh_queue = MEM_callocN(sizeof(MetaballBVHNode *) * process->bvh_queue_size,
+ "Metaball BVH Queue");
- makecubetable();
+ makecubetable();
- for (i = 0; i < process->totelem; i++) {
- find_first_points(process, i);
- }
+ for (i = 0; i < process->totelem; i++) {
+ find_first_points(process, i);
+ }
- while (process->cubes != NULL) {
- c = process->cubes->cube;
- process->cubes = process->cubes->next;
+ while (process->cubes != NULL) {
+ c = process->cubes->cube;
+ process->cubes = process->cubes->next;
- docube(process, &c);
- }
+ docube(process, &c);
+ }
}
/**
@@ -1032,248 +1131,260 @@ static void polygonize(PROCESS *process)
* Computes bounding boxes for building BVH. */
static void init_meta(Depsgraph *depsgraph, PROCESS *process, Scene *scene, Object *ob)
{
- Scene *sce_iter = scene;
- Base *base;
- Object *bob;
- MetaBall *mb;
- const MetaElem *ml;
- float obinv[4][4], obmat[4][4];
- unsigned int i;
- int obnr, zero_size = 0;
- char obname[MAX_ID_NAME];
- SceneBaseIter iter;
-
- copy_m4_m4(obmat, ob->obmat); /* to cope with duplicators from BKE_scene_base_iter_next */
- invert_m4_m4(obinv, ob->obmat);
-
- BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.');
-
- /* make main array */
- BKE_scene_base_iter_next(depsgraph, &iter, &sce_iter, 0, NULL, NULL);
- while (BKE_scene_base_iter_next(depsgraph, &iter, &sce_iter, 1, &base, &bob)) {
- if (bob->type == OB_MBALL) {
- zero_size = 0;
- ml = NULL;
-
- if (bob == ob && (base->flag_legacy & OB_FROMDUPLI) == 0) {
- mb = ob->data;
-
- if (mb->editelems) ml = mb->editelems->first;
- else ml = mb->elems.first;
- }
- else {
- char name[MAX_ID_NAME];
- int nr;
-
- BLI_split_name_num(name, &nr, bob->id.name + 2, '.');
- if (STREQ(obname, name)) {
- mb = bob->data;
-
- if (mb->editelems) ml = mb->editelems->first;
- else ml = mb->elems.first;
- }
- }
-
- /* when metaball object has zero scale, then MetaElem to this MetaBall
- * will not be put to mainb array */
- if (has_zero_axis_m4(bob->obmat)) {
- zero_size = 1;
- }
- else if (bob->parent) {
- struct Object *pob = bob->parent;
- while (pob) {
- if (has_zero_axis_m4(pob->obmat)) {
- zero_size = 1;
- break;
- }
- pob = pob->parent;
- }
- }
-
- if (zero_size) {
- while (ml) {
- ml = ml->next;
- }
- }
- else {
- while (ml) {
- if (!(ml->flag & MB_HIDE)) {
- float pos[4][4], rot[4][4];
- float expx, expy, expz;
- float tempmin[3], tempmax[3];
-
- MetaElem *new_ml;
-
- /* make a copy because of duplicates */
- new_ml = BLI_memarena_alloc(process->pgn_elements, sizeof(MetaElem));
- *(new_ml) = *ml;
- new_ml->bb = BLI_memarena_alloc(process->pgn_elements, sizeof(BoundBox));
- new_ml->mat = BLI_memarena_alloc(process->pgn_elements, 4 * 4 * sizeof(float));
- new_ml->imat = BLI_memarena_alloc(process->pgn_elements, 4 * 4 * sizeof(float));
-
- /* too big stiffness seems only ugly due to linear interpolation
- * no need to have possibility for too big stiffness */
- if (ml->s > 10.0f) new_ml->s = 10.0f;
- else new_ml->s = ml->s;
-
- /* if metaball is negative, set stiffness negative */
- if (new_ml->flag & MB_NEGATIVE) new_ml->s = -new_ml->s;
-
- /* Translation of MetaElem */
- unit_m4(pos);
- pos[3][0] = ml->x;
- pos[3][1] = ml->y;
- pos[3][2] = ml->z;
-
- /* Rotation of MetaElem is stored in quat */
- quat_to_mat4(rot, ml->quat);
-
- /* basis object space -> world -> ml object space -> position -> rotation -> ml local space */
- mul_m4_series((float(*)[4])new_ml->mat, obinv, bob->obmat, pos, rot);
- /* ml local space -> basis object space */
- invert_m4_m4((float(*)[4])new_ml->imat, (float(*)[4])new_ml->mat);
-
- /* rad2 is inverse of squared radius */
- new_ml->rad2 = 1 / (ml->rad * ml->rad);
-
- /* initial dimensions = radius */
- expx = ml->rad;
- expy = ml->rad;
- expz = ml->rad;
-
- switch (ml->type) {
- case MB_BALL:
- break;
- case MB_CUBE: /* cube is "expanded" by expz, expy and expx */
- expz += ml->expz;
- ATTR_FALLTHROUGH;
- case MB_PLANE: /* plane is "expanded" by expy and expx */
- expy += ml->expy;
- ATTR_FALLTHROUGH;
- case MB_TUBE: /* tube is "expanded" by expx */
- expx += ml->expx;
- break;
- case MB_ELIPSOID: /* ellipsoid is "stretched" by exp* */
- expx *= ml->expx;
- expy *= ml->expy;
- expz *= ml->expz;
- break;
- }
-
- /* untransformed Bounding Box of MetaElem */
- /* TODO, its possible the elem type has been changed and the exp* values can use a fallback */
- copy_v3_fl3(new_ml->bb->vec[0], -expx, -expy, -expz); /* 0 */
- copy_v3_fl3(new_ml->bb->vec[1], +expx, -expy, -expz); /* 1 */
- copy_v3_fl3(new_ml->bb->vec[2], +expx, +expy, -expz); /* 2 */
- copy_v3_fl3(new_ml->bb->vec[3], -expx, +expy, -expz); /* 3 */
- copy_v3_fl3(new_ml->bb->vec[4], -expx, -expy, +expz); /* 4 */
- copy_v3_fl3(new_ml->bb->vec[5], +expx, -expy, +expz); /* 5 */
- copy_v3_fl3(new_ml->bb->vec[6], +expx, +expy, +expz); /* 6 */
- copy_v3_fl3(new_ml->bb->vec[7], -expx, +expy, +expz); /* 7 */
-
- /* transformation of Metalem bb */
- for (i = 0; i < 8; i++)
- mul_m4_v3((float(*)[4])new_ml->mat, new_ml->bb->vec[i]);
-
- /* find max and min of transformed bb */
- INIT_MINMAX(tempmin, tempmax);
- for (i = 0; i < 8; i++) {
- DO_MINMAX(new_ml->bb->vec[i], tempmin, tempmax);
- }
-
- /* set only point 0 and 6 - AABB of Metaelem */
- copy_v3_v3(new_ml->bb->vec[0], tempmin);
- copy_v3_v3(new_ml->bb->vec[6], tempmax);
-
- /* add new_ml to mainb[] */
- if (UNLIKELY(process->totelem == process->mem)) {
- process->mem = process->mem * 2 + 10;
- process->mainb = MEM_reallocN(process->mainb, sizeof(MetaElem *) * process->mem);
- }
- process->mainb[process->totelem++] = new_ml;
- }
- ml = ml->next;
- }
- }
- }
- }
-
- /* compute AABB of all Metaelems */
- if (process->totelem > 0) {
- copy_v3_v3(process->allbb.min, process->mainb[0]->bb->vec[0]);
- copy_v3_v3(process->allbb.max, process->mainb[0]->bb->vec[6]);
- for (i = 1; i < process->totelem; i++)
- make_box_union(process->mainb[i]->bb, &process->allbb, &process->allbb);
- }
+ Scene *sce_iter = scene;
+ Base *base;
+ Object *bob;
+ MetaBall *mb;
+ const MetaElem *ml;
+ float obinv[4][4], obmat[4][4];
+ unsigned int i;
+ int obnr, zero_size = 0;
+ char obname[MAX_ID_NAME];
+ SceneBaseIter iter;
+
+ copy_m4_m4(obmat, ob->obmat); /* to cope with duplicators from BKE_scene_base_iter_next */
+ invert_m4_m4(obinv, ob->obmat);
+
+ BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.');
+
+ /* make main array */
+ BKE_scene_base_iter_next(depsgraph, &iter, &sce_iter, 0, NULL, NULL);
+ while (BKE_scene_base_iter_next(depsgraph, &iter, &sce_iter, 1, &base, &bob)) {
+ if (bob->type == OB_MBALL) {
+ zero_size = 0;
+ ml = NULL;
+
+ if (bob == ob && (base->flag_legacy & OB_FROMDUPLI) == 0) {
+ mb = ob->data;
+
+ if (mb->editelems)
+ ml = mb->editelems->first;
+ else
+ ml = mb->elems.first;
+ }
+ else {
+ char name[MAX_ID_NAME];
+ int nr;
+
+ BLI_split_name_num(name, &nr, bob->id.name + 2, '.');
+ if (STREQ(obname, name)) {
+ mb = bob->data;
+
+ if (mb->editelems)
+ ml = mb->editelems->first;
+ else
+ ml = mb->elems.first;
+ }
+ }
+
+ /* when metaball object has zero scale, then MetaElem to this MetaBall
+ * will not be put to mainb array */
+ if (has_zero_axis_m4(bob->obmat)) {
+ zero_size = 1;
+ }
+ else if (bob->parent) {
+ struct Object *pob = bob->parent;
+ while (pob) {
+ if (has_zero_axis_m4(pob->obmat)) {
+ zero_size = 1;
+ break;
+ }
+ pob = pob->parent;
+ }
+ }
+
+ if (zero_size) {
+ while (ml) {
+ ml = ml->next;
+ }
+ }
+ else {
+ while (ml) {
+ if (!(ml->flag & MB_HIDE)) {
+ float pos[4][4], rot[4][4];
+ float expx, expy, expz;
+ float tempmin[3], tempmax[3];
+
+ MetaElem *new_ml;
+
+ /* make a copy because of duplicates */
+ new_ml = BLI_memarena_alloc(process->pgn_elements, sizeof(MetaElem));
+ *(new_ml) = *ml;
+ new_ml->bb = BLI_memarena_alloc(process->pgn_elements, sizeof(BoundBox));
+ new_ml->mat = BLI_memarena_alloc(process->pgn_elements, 4 * 4 * sizeof(float));
+ new_ml->imat = BLI_memarena_alloc(process->pgn_elements, 4 * 4 * sizeof(float));
+
+ /* too big stiffness seems only ugly due to linear interpolation
+ * no need to have possibility for too big stiffness */
+ if (ml->s > 10.0f)
+ new_ml->s = 10.0f;
+ else
+ new_ml->s = ml->s;
+
+ /* if metaball is negative, set stiffness negative */
+ if (new_ml->flag & MB_NEGATIVE)
+ new_ml->s = -new_ml->s;
+
+ /* Translation of MetaElem */
+ unit_m4(pos);
+ pos[3][0] = ml->x;
+ pos[3][1] = ml->y;
+ pos[3][2] = ml->z;
+
+ /* Rotation of MetaElem is stored in quat */
+ quat_to_mat4(rot, ml->quat);
+
+ /* basis object space -> world -> ml object space -> position -> rotation -> ml local space */
+ mul_m4_series((float(*)[4])new_ml->mat, obinv, bob->obmat, pos, rot);
+ /* ml local space -> basis object space */
+ invert_m4_m4((float(*)[4])new_ml->imat, (float(*)[4])new_ml->mat);
+
+ /* rad2 is inverse of squared radius */
+ new_ml->rad2 = 1 / (ml->rad * ml->rad);
+
+ /* initial dimensions = radius */
+ expx = ml->rad;
+ expy = ml->rad;
+ expz = ml->rad;
+
+ switch (ml->type) {
+ case MB_BALL:
+ break;
+ case MB_CUBE: /* cube is "expanded" by expz, expy and expx */
+ expz += ml->expz;
+ ATTR_FALLTHROUGH;
+ case MB_PLANE: /* plane is "expanded" by expy and expx */
+ expy += ml->expy;
+ ATTR_FALLTHROUGH;
+ case MB_TUBE: /* tube is "expanded" by expx */
+ expx += ml->expx;
+ break;
+ case MB_ELIPSOID: /* ellipsoid is "stretched" by exp* */
+ expx *= ml->expx;
+ expy *= ml->expy;
+ expz *= ml->expz;
+ break;
+ }
+
+ /* untransformed Bounding Box of MetaElem */
+ /* TODO, its possible the elem type has been changed and the exp* values can use a fallback */
+ copy_v3_fl3(new_ml->bb->vec[0], -expx, -expy, -expz); /* 0 */
+ copy_v3_fl3(new_ml->bb->vec[1], +expx, -expy, -expz); /* 1 */
+ copy_v3_fl3(new_ml->bb->vec[2], +expx, +expy, -expz); /* 2 */
+ copy_v3_fl3(new_ml->bb->vec[3], -expx, +expy, -expz); /* 3 */
+ copy_v3_fl3(new_ml->bb->vec[4], -expx, -expy, +expz); /* 4 */
+ copy_v3_fl3(new_ml->bb->vec[5], +expx, -expy, +expz); /* 5 */
+ copy_v3_fl3(new_ml->bb->vec[6], +expx, +expy, +expz); /* 6 */
+ copy_v3_fl3(new_ml->bb->vec[7], -expx, +expy, +expz); /* 7 */
+
+ /* transformation of Metalem bb */
+ for (i = 0; i < 8; i++)
+ mul_m4_v3((float(*)[4])new_ml->mat, new_ml->bb->vec[i]);
+
+ /* find max and min of transformed bb */
+ INIT_MINMAX(tempmin, tempmax);
+ for (i = 0; i < 8; i++) {
+ DO_MINMAX(new_ml->bb->vec[i], tempmin, tempmax);
+ }
+
+ /* set only point 0 and 6 - AABB of Metaelem */
+ copy_v3_v3(new_ml->bb->vec[0], tempmin);
+ copy_v3_v3(new_ml->bb->vec[6], tempmax);
+
+ /* add new_ml to mainb[] */
+ if (UNLIKELY(process->totelem == process->mem)) {
+ process->mem = process->mem * 2 + 10;
+ process->mainb = MEM_reallocN(process->mainb, sizeof(MetaElem *) * process->mem);
+ }
+ process->mainb[process->totelem++] = new_ml;
+ }
+ ml = ml->next;
+ }
+ }
+ }
+ }
+
+ /* compute AABB of all Metaelems */
+ if (process->totelem > 0) {
+ copy_v3_v3(process->allbb.min, process->mainb[0]->bb->vec[0]);
+ copy_v3_v3(process->allbb.max, process->mainb[0]->bb->vec[6]);
+ for (i = 1; i < process->totelem; i++)
+ make_box_union(process->mainb[i]->bb, &process->allbb, &process->allbb);
+ }
}
void BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase)
{
- MetaBall *mb;
- DispList *dl;
- unsigned int a;
- PROCESS process = {0};
- bool is_render = DEG_get_mode(depsgraph) == DAG_EVAL_RENDER;
-
- mb = ob->data;
-
- process.thresh = mb->thresh;
-
- if (process.thresh < 0.001f) process.converge_res = 16;
- else if (process.thresh < 0.01f) process.converge_res = 8;
- else if (process.thresh < 0.1f) process.converge_res = 4;
- else process.converge_res = 2;
-
- if (is_render && (mb->flag == MB_UPDATE_NEVER)) return;
- if ((G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) && mb->flag == MB_UPDATE_FAST) return;
-
- if (is_render) {
- process.size = mb->rendersize;
- }
- else {
- process.size = mb->wiresize;
- if ((G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) && mb->flag == MB_UPDATE_HALFRES) {
- process.size *= 2.0f;
- }
- }
-
- process.delta = process.size * 0.001f;
-
- process.pgn_elements = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "Metaball memarena");
-
- /* initialize all mainb (MetaElems) */
- init_meta(depsgraph, &process, scene, ob);
-
- if (process.totelem > 0) {
- build_bvh_spatial(&process, &process.metaball_bvh, 0, process.totelem, &process.allbb);
-
- /* don't polygonize metaballs with too high resolution (base mball to small)
- * note: Eps was 0.0001f but this was giving problems for blood animation for durian, using 0.00001f */
- if (ob->scale[0] > 0.00001f * (process.allbb.max[0] - process.allbb.min[0]) ||
- ob->scale[1] > 0.00001f * (process.allbb.max[1] - process.allbb.min[1]) ||
- ob->scale[2] > 0.00001f * (process.allbb.max[2] - process.allbb.min[2]))
- {
- polygonize(&process);
-
- /* add resulting surface to displist */
- if (process.curindex) {
- dl = MEM_callocN(sizeof(DispList), "mballdisp");
- BLI_addtail(dispbase, dl);
- dl->type = DL_INDEX4;
- dl->nr = (int)process.curvertex;
- dl->parts = (int)process.curindex;
-
- dl->index = (int *)process.indices;
-
- for (a = 0; a < process.curvertex; a++) {
- normalize_v3(process.no[a]);
- }
-
- dl->verts = (float *)process.co;
- dl->nors = (float *)process.no;
- }
- }
- }
-
- freepolygonize(&process);
+ MetaBall *mb;
+ DispList *dl;
+ unsigned int a;
+ PROCESS process = {0};
+ bool is_render = DEG_get_mode(depsgraph) == DAG_EVAL_RENDER;
+
+ mb = ob->data;
+
+ process.thresh = mb->thresh;
+
+ if (process.thresh < 0.001f)
+ process.converge_res = 16;
+ else if (process.thresh < 0.01f)
+ process.converge_res = 8;
+ else if (process.thresh < 0.1f)
+ process.converge_res = 4;
+ else
+ process.converge_res = 2;
+
+ if (is_render && (mb->flag == MB_UPDATE_NEVER))
+ return;
+ if ((G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) && mb->flag == MB_UPDATE_FAST)
+ return;
+
+ if (is_render) {
+ process.size = mb->rendersize;
+ }
+ else {
+ process.size = mb->wiresize;
+ if ((G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) && mb->flag == MB_UPDATE_HALFRES) {
+ process.size *= 2.0f;
+ }
+ }
+
+ process.delta = process.size * 0.001f;
+
+ process.pgn_elements = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "Metaball memarena");
+
+ /* initialize all mainb (MetaElems) */
+ init_meta(depsgraph, &process, scene, ob);
+
+ if (process.totelem > 0) {
+ build_bvh_spatial(&process, &process.metaball_bvh, 0, process.totelem, &process.allbb);
+
+ /* don't polygonize metaballs with too high resolution (base mball to small)
+ * note: Eps was 0.0001f but this was giving problems for blood animation for durian, using 0.00001f */
+ if (ob->scale[0] > 0.00001f * (process.allbb.max[0] - process.allbb.min[0]) ||
+ ob->scale[1] > 0.00001f * (process.allbb.max[1] - process.allbb.min[1]) ||
+ ob->scale[2] > 0.00001f * (process.allbb.max[2] - process.allbb.min[2])) {
+ polygonize(&process);
+
+ /* add resulting surface to displist */
+ if (process.curindex) {
+ dl = MEM_callocN(sizeof(DispList), "mballdisp");
+ BLI_addtail(dispbase, dl);
+ dl->type = DL_INDEX4;
+ dl->nr = (int)process.curvertex;
+ dl->parts = (int)process.curindex;
+
+ dl->index = (int *)process.indices;
+
+ for (a = 0; a < process.curvertex; a++) {
+ normalize_v3(process.no[a]);
+ }
+
+ dl->verts = (float *)process.co;
+ dl->nors = (float *)process.no;
+ }
+ }
+ }
+
+ freepolygonize(&process);
}
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index 74fb31d0121..5df06e61744 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -52,205 +52,213 @@
#include "DEG_depsgraph.h"
enum {
- MESHCMP_DVERT_WEIGHTMISMATCH = 1,
- MESHCMP_DVERT_GROUPMISMATCH,
- MESHCMP_DVERT_TOTGROUPMISMATCH,
- MESHCMP_LOOPCOLMISMATCH,
- MESHCMP_LOOPUVMISMATCH,
- MESHCMP_LOOPMISMATCH,
- MESHCMP_POLYVERTMISMATCH,
- MESHCMP_POLYMISMATCH,
- MESHCMP_EDGEUNKNOWN,
- MESHCMP_VERTCOMISMATCH,
- MESHCMP_CDLAYERS_MISMATCH,
+ MESHCMP_DVERT_WEIGHTMISMATCH = 1,
+ MESHCMP_DVERT_GROUPMISMATCH,
+ MESHCMP_DVERT_TOTGROUPMISMATCH,
+ MESHCMP_LOOPCOLMISMATCH,
+ MESHCMP_LOOPUVMISMATCH,
+ MESHCMP_LOOPMISMATCH,
+ MESHCMP_POLYVERTMISMATCH,
+ MESHCMP_POLYMISMATCH,
+ MESHCMP_EDGEUNKNOWN,
+ MESHCMP_VERTCOMISMATCH,
+ MESHCMP_CDLAYERS_MISMATCH,
};
static const char *cmpcode_to_str(int code)
{
- switch (code) {
- case MESHCMP_DVERT_WEIGHTMISMATCH:
- return "Vertex Weight Mismatch";
- case MESHCMP_DVERT_GROUPMISMATCH:
- return "Vertex Group Mismatch";
- case MESHCMP_DVERT_TOTGROUPMISMATCH:
- return "Vertex Doesn't Belong To Same Number Of Groups";
- case MESHCMP_LOOPCOLMISMATCH:
- return "Vertex Color Mismatch";
- case MESHCMP_LOOPUVMISMATCH:
- return "UV Mismatch";
- case MESHCMP_LOOPMISMATCH:
- return "Loop Mismatch";
- case MESHCMP_POLYVERTMISMATCH:
- return "Loop Vert Mismatch In Poly Test";
- case MESHCMP_POLYMISMATCH:
- return "Loop Vert Mismatch";
- case MESHCMP_EDGEUNKNOWN:
- return "Edge Mismatch";
- case MESHCMP_VERTCOMISMATCH:
- return "Vertex Coordinate Mismatch";
- case MESHCMP_CDLAYERS_MISMATCH:
- return "CustomData Layer Count Mismatch";
- default:
- return "Mesh Comparison Code Unknown";
- }
+ switch (code) {
+ case MESHCMP_DVERT_WEIGHTMISMATCH:
+ return "Vertex Weight Mismatch";
+ case MESHCMP_DVERT_GROUPMISMATCH:
+ return "Vertex Group Mismatch";
+ case MESHCMP_DVERT_TOTGROUPMISMATCH:
+ return "Vertex Doesn't Belong To Same Number Of Groups";
+ case MESHCMP_LOOPCOLMISMATCH:
+ return "Vertex Color Mismatch";
+ case MESHCMP_LOOPUVMISMATCH:
+ return "UV Mismatch";
+ case MESHCMP_LOOPMISMATCH:
+ return "Loop Mismatch";
+ case MESHCMP_POLYVERTMISMATCH:
+ return "Loop Vert Mismatch In Poly Test";
+ case MESHCMP_POLYMISMATCH:
+ return "Loop Vert Mismatch";
+ case MESHCMP_EDGEUNKNOWN:
+ return "Edge Mismatch";
+ case MESHCMP_VERTCOMISMATCH:
+ return "Vertex Coordinate Mismatch";
+ case MESHCMP_CDLAYERS_MISMATCH:
+ return "CustomData Layer Count Mismatch";
+ default:
+ return "Mesh Comparison Code Unknown";
+ }
}
/* thresh is threshold for comparing vertices, uvs, vertex colors,
* weights, etc.*/
-static int customdata_compare(CustomData *c1, CustomData *c2, Mesh *m1, Mesh *m2, const float thresh)
-{
- const float thresh_sq = thresh * thresh;
- CustomDataLayer *l1, *l2;
- int i, i1 = 0, i2 = 0, tot, j;
-
- for (i = 0; i < c1->totlayer; i++) {
- if (ELEM(c1->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY,
- CD_MLOOPUV, CD_MLOOPCOL, CD_MDEFORMVERT))
- {
- i1++;
- }
- }
-
- for (i = 0; i < c2->totlayer; i++) {
- if (ELEM(c2->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY,
- CD_MLOOPUV, CD_MLOOPCOL, CD_MDEFORMVERT))
- {
- i2++;
- }
- }
-
- if (i1 != i2)
- return MESHCMP_CDLAYERS_MISMATCH;
-
- l1 = c1->layers; l2 = c2->layers;
- tot = i1;
- i1 = 0; i2 = 0;
- for (i = 0; i < tot; i++) {
- while (i1 < c1->totlayer && !ELEM(l1->type, CD_MVERT, CD_MEDGE, CD_MPOLY,
- CD_MLOOPUV, CD_MLOOPCOL, CD_MDEFORMVERT))
- {
- i1++;
- l1++;
- }
-
- while (i2 < c2->totlayer && !ELEM(l2->type, CD_MVERT, CD_MEDGE, CD_MPOLY,
- CD_MLOOPUV, CD_MLOOPCOL, CD_MDEFORMVERT))
- {
- i2++;
- l2++;
- }
-
- if (l1->type == CD_MVERT) {
- MVert *v1 = l1->data;
- MVert *v2 = l2->data;
- int vtot = m1->totvert;
-
- for (j = 0; j < vtot; j++, v1++, v2++) {
- if (len_squared_v3v3(v1->co, v2->co) > thresh_sq)
- return MESHCMP_VERTCOMISMATCH;
- /* I don't care about normals, let's just do coordinates */
- }
- }
-
- /*we're order-agnostic for edges here*/
- if (l1->type == CD_MEDGE) {
- MEdge *e1 = l1->data;
- MEdge *e2 = l2->data;
- int etot = m1->totedge;
- EdgeHash *eh = BLI_edgehash_new_ex(__func__, etot);
-
- for (j = 0; j < etot; j++, e1++) {
- BLI_edgehash_insert(eh, e1->v1, e1->v2, e1);
- }
-
- for (j = 0; j < etot; j++, e2++) {
- if (!BLI_edgehash_lookup(eh, e2->v1, e2->v2))
- return MESHCMP_EDGEUNKNOWN;
- }
- BLI_edgehash_free(eh, NULL);
- }
-
- if (l1->type == CD_MPOLY) {
- MPoly *p1 = l1->data;
- MPoly *p2 = l2->data;
- int ptot = m1->totpoly;
-
- for (j = 0; j < ptot; j++, p1++, p2++) {
- MLoop *lp1, *lp2;
- int k;
-
- if (p1->totloop != p2->totloop)
- return MESHCMP_POLYMISMATCH;
-
- lp1 = m1->mloop + p1->loopstart;
- lp2 = m2->mloop + p2->loopstart;
-
- for (k = 0; k < p1->totloop; k++, lp1++, lp2++) {
- if (lp1->v != lp2->v)
- return MESHCMP_POLYVERTMISMATCH;
- }
- }
- }
- if (l1->type == CD_MLOOP) {
- MLoop *lp1 = l1->data;
- MLoop *lp2 = l2->data;
- int ltot = m1->totloop;
-
- for (j = 0; j < ltot; j++, lp1++, lp2++) {
- if (lp1->v != lp2->v)
- return MESHCMP_LOOPMISMATCH;
- }
- }
- if (l1->type == CD_MLOOPUV) {
- MLoopUV *lp1 = l1->data;
- MLoopUV *lp2 = l2->data;
- int ltot = m1->totloop;
-
- for (j = 0; j < ltot; j++, lp1++, lp2++) {
- if (len_squared_v2v2(lp1->uv, lp2->uv) > thresh_sq)
- return MESHCMP_LOOPUVMISMATCH;
- }
- }
-
- if (l1->type == CD_MLOOPCOL) {
- MLoopCol *lp1 = l1->data;
- MLoopCol *lp2 = l2->data;
- int ltot = m1->totloop;
-
- for (j = 0; j < ltot; j++, lp1++, lp2++) {
- if (ABS(lp1->r - lp2->r) > thresh ||
- ABS(lp1->g - lp2->g) > thresh ||
- ABS(lp1->b - lp2->b) > thresh ||
- ABS(lp1->a - lp2->a) > thresh)
- {
- return MESHCMP_LOOPCOLMISMATCH;
- }
- }
- }
-
- if (l1->type == CD_MDEFORMVERT) {
- MDeformVert *dv1 = l1->data;
- MDeformVert *dv2 = l2->data;
- int dvtot = m1->totvert;
-
- for (j = 0; j < dvtot; j++, dv1++, dv2++) {
- int k;
- MDeformWeight *dw1 = dv1->dw, *dw2 = dv2->dw;
-
- if (dv1->totweight != dv2->totweight)
- return MESHCMP_DVERT_TOTGROUPMISMATCH;
-
- for (k = 0; k < dv1->totweight; k++, dw1++, dw2++) {
- if (dw1->def_nr != dw2->def_nr)
- return MESHCMP_DVERT_GROUPMISMATCH;
- if (fabsf(dw1->weight - dw2->weight) > thresh)
- return MESHCMP_DVERT_WEIGHTMISMATCH;
- }
- }
- }
- }
-
- return 0;
+static int customdata_compare(
+ CustomData *c1, CustomData *c2, Mesh *m1, Mesh *m2, const float thresh)
+{
+ const float thresh_sq = thresh * thresh;
+ CustomDataLayer *l1, *l2;
+ int i, i1 = 0, i2 = 0, tot, j;
+
+ for (i = 0; i < c1->totlayer; i++) {
+ if (ELEM(c1->layers[i].type,
+ CD_MVERT,
+ CD_MEDGE,
+ CD_MPOLY,
+ CD_MLOOPUV,
+ CD_MLOOPCOL,
+ CD_MDEFORMVERT)) {
+ i1++;
+ }
+ }
+
+ for (i = 0; i < c2->totlayer; i++) {
+ if (ELEM(c2->layers[i].type,
+ CD_MVERT,
+ CD_MEDGE,
+ CD_MPOLY,
+ CD_MLOOPUV,
+ CD_MLOOPCOL,
+ CD_MDEFORMVERT)) {
+ i2++;
+ }
+ }
+
+ if (i1 != i2)
+ return MESHCMP_CDLAYERS_MISMATCH;
+
+ l1 = c1->layers;
+ l2 = c2->layers;
+ tot = i1;
+ i1 = 0;
+ i2 = 0;
+ for (i = 0; i < tot; i++) {
+ while (
+ i1 < c1->totlayer &&
+ !ELEM(l1->type, CD_MVERT, CD_MEDGE, CD_MPOLY, CD_MLOOPUV, CD_MLOOPCOL, CD_MDEFORMVERT)) {
+ i1++;
+ l1++;
+ }
+
+ while (
+ i2 < c2->totlayer &&
+ !ELEM(l2->type, CD_MVERT, CD_MEDGE, CD_MPOLY, CD_MLOOPUV, CD_MLOOPCOL, CD_MDEFORMVERT)) {
+ i2++;
+ l2++;
+ }
+
+ if (l1->type == CD_MVERT) {
+ MVert *v1 = l1->data;
+ MVert *v2 = l2->data;
+ int vtot = m1->totvert;
+
+ for (j = 0; j < vtot; j++, v1++, v2++) {
+ if (len_squared_v3v3(v1->co, v2->co) > thresh_sq)
+ return MESHCMP_VERTCOMISMATCH;
+ /* I don't care about normals, let's just do coordinates */
+ }
+ }
+
+ /*we're order-agnostic for edges here*/
+ if (l1->type == CD_MEDGE) {
+ MEdge *e1 = l1->data;
+ MEdge *e2 = l2->data;
+ int etot = m1->totedge;
+ EdgeHash *eh = BLI_edgehash_new_ex(__func__, etot);
+
+ for (j = 0; j < etot; j++, e1++) {
+ BLI_edgehash_insert(eh, e1->v1, e1->v2, e1);
+ }
+
+ for (j = 0; j < etot; j++, e2++) {
+ if (!BLI_edgehash_lookup(eh, e2->v1, e2->v2))
+ return MESHCMP_EDGEUNKNOWN;
+ }
+ BLI_edgehash_free(eh, NULL);
+ }
+
+ if (l1->type == CD_MPOLY) {
+ MPoly *p1 = l1->data;
+ MPoly *p2 = l2->data;
+ int ptot = m1->totpoly;
+
+ for (j = 0; j < ptot; j++, p1++, p2++) {
+ MLoop *lp1, *lp2;
+ int k;
+
+ if (p1->totloop != p2->totloop)
+ return MESHCMP_POLYMISMATCH;
+
+ lp1 = m1->mloop + p1->loopstart;
+ lp2 = m2->mloop + p2->loopstart;
+
+ for (k = 0; k < p1->totloop; k++, lp1++, lp2++) {
+ if (lp1->v != lp2->v)
+ return MESHCMP_POLYVERTMISMATCH;
+ }
+ }
+ }
+ if (l1->type == CD_MLOOP) {
+ MLoop *lp1 = l1->data;
+ MLoop *lp2 = l2->data;
+ int ltot = m1->totloop;
+
+ for (j = 0; j < ltot; j++, lp1++, lp2++) {
+ if (lp1->v != lp2->v)
+ return MESHCMP_LOOPMISMATCH;
+ }
+ }
+ if (l1->type == CD_MLOOPUV) {
+ MLoopUV *lp1 = l1->data;
+ MLoopUV *lp2 = l2->data;
+ int ltot = m1->totloop;
+
+ for (j = 0; j < ltot; j++, lp1++, lp2++) {
+ if (len_squared_v2v2(lp1->uv, lp2->uv) > thresh_sq)
+ return MESHCMP_LOOPUVMISMATCH;
+ }
+ }
+
+ if (l1->type == CD_MLOOPCOL) {
+ MLoopCol *lp1 = l1->data;
+ MLoopCol *lp2 = l2->data;
+ int ltot = m1->totloop;
+
+ for (j = 0; j < ltot; j++, lp1++, lp2++) {
+ if (ABS(lp1->r - lp2->r) > thresh || ABS(lp1->g - lp2->g) > thresh ||
+ ABS(lp1->b - lp2->b) > thresh || ABS(lp1->a - lp2->a) > thresh) {
+ return MESHCMP_LOOPCOLMISMATCH;
+ }
+ }
+ }
+
+ if (l1->type == CD_MDEFORMVERT) {
+ MDeformVert *dv1 = l1->data;
+ MDeformVert *dv2 = l2->data;
+ int dvtot = m1->totvert;
+
+ for (j = 0; j < dvtot; j++, dv1++, dv2++) {
+ int k;
+ MDeformWeight *dw1 = dv1->dw, *dw2 = dv2->dw;
+
+ if (dv1->totweight != dv2->totweight)
+ return MESHCMP_DVERT_TOTGROUPMISMATCH;
+
+ for (k = 0; k < dv1->totweight; k++, dw1++, dw2++) {
+ if (dw1->def_nr != dw2->def_nr)
+ return MESHCMP_DVERT_GROUPMISMATCH;
+ if (fabsf(dw1->weight - dw2->weight) > thresh)
+ return MESHCMP_DVERT_WEIGHTMISMATCH;
+ }
+ }
+ }
+ }
+
+ return 0;
}
/**
@@ -261,154 +269,146 @@ static int customdata_compare(CustomData *c1, CustomData *c2, Mesh *m1, Mesh *m2
*/
const char *BKE_mesh_cmp(Mesh *me1, Mesh *me2, float thresh)
{
- int c;
+ int c;
- if (!me1 || !me2)
- return "Requires two input meshes";
+ if (!me1 || !me2)
+ return "Requires two input meshes";
- if (me1->totvert != me2->totvert)
- return "Number of verts don't match";
+ if (me1->totvert != me2->totvert)
+ return "Number of verts don't match";
- if (me1->totedge != me2->totedge)
- return "Number of edges don't match";
+ if (me1->totedge != me2->totedge)
+ return "Number of edges don't match";
- if (me1->totpoly != me2->totpoly)
- return "Number of faces don't match";
+ if (me1->totpoly != me2->totpoly)
+ return "Number of faces don't match";
- if (me1->totloop != me2->totloop)
- return "Number of loops don't match";
+ if (me1->totloop != me2->totloop)
+ return "Number of loops don't match";
- if ((c = customdata_compare(&me1->vdata, &me2->vdata, me1, me2, thresh)))
- return cmpcode_to_str(c);
+ if ((c = customdata_compare(&me1->vdata, &me2->vdata, me1, me2, thresh)))
+ return cmpcode_to_str(c);
- if ((c = customdata_compare(&me1->edata, &me2->edata, me1, me2, thresh)))
- return cmpcode_to_str(c);
+ if ((c = customdata_compare(&me1->edata, &me2->edata, me1, me2, thresh)))
+ return cmpcode_to_str(c);
- if ((c = customdata_compare(&me1->ldata, &me2->ldata, me1, me2, thresh)))
- return cmpcode_to_str(c);
+ if ((c = customdata_compare(&me1->ldata, &me2->ldata, me1, me2, thresh)))
+ return cmpcode_to_str(c);
- if ((c = customdata_compare(&me1->pdata, &me2->pdata, me1, me2, thresh)))
- return cmpcode_to_str(c);
+ if ((c = customdata_compare(&me1->pdata, &me2->pdata, me1, me2, thresh)))
+ return cmpcode_to_str(c);
- return NULL;
+ return NULL;
}
static void mesh_ensure_tessellation_customdata(Mesh *me)
{
- if (UNLIKELY((me->totface != 0) && (me->totpoly == 0))) {
- /* Pass, otherwise this function clears 'mface' before
- * versioning 'mface -> mpoly' code kicks in [#30583]
- *
- * Callers could also check but safer to do here - campbell */
- }
- else {
- const int tottex_original = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
- const int totcol_original = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
-
- const int tottex_tessface = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
- const int totcol_tessface = CustomData_number_of_layers(&me->fdata, CD_MCOL);
-
- if (tottex_tessface != tottex_original ||
- totcol_tessface != totcol_original)
- {
- BKE_mesh_tessface_clear(me);
-
- CustomData_from_bmeshpoly(&me->fdata, &me->ldata, me->totface);
-
- /* TODO - add some --debug-mesh option */
- if (G.debug & G_DEBUG) {
- /* note: this warning may be un-called for if we are initializing the mesh for the
- * first time from bmesh, rather then giving a warning about this we could be smarter
- * and check if there was any data to begin with, for now just print the warning with
- * some info to help troubleshoot what's going on - campbell */
- printf("%s: warning! Tessellation uvs or vcol data got out of sync, "
- "had to reset!\n CD_MTFACE: %d != CD_MLOOPUV: %d || CD_MCOL: %d != CD_MLOOPCOL: %d\n",
- __func__, tottex_tessface, tottex_original, totcol_tessface, totcol_original);
- }
- }
- }
+ if (UNLIKELY((me->totface != 0) && (me->totpoly == 0))) {
+ /* Pass, otherwise this function clears 'mface' before
+ * versioning 'mface -> mpoly' code kicks in [#30583]
+ *
+ * Callers could also check but safer to do here - campbell */
+ }
+ else {
+ const int tottex_original = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
+ const int totcol_original = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
+
+ const int tottex_tessface = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
+ const int totcol_tessface = CustomData_number_of_layers(&me->fdata, CD_MCOL);
+
+ if (tottex_tessface != tottex_original || totcol_tessface != totcol_original) {
+ BKE_mesh_tessface_clear(me);
+
+ CustomData_from_bmeshpoly(&me->fdata, &me->ldata, me->totface);
+
+ /* TODO - add some --debug-mesh option */
+ if (G.debug & G_DEBUG) {
+ /* note: this warning may be un-called for if we are initializing the mesh for the
+ * first time from bmesh, rather then giving a warning about this we could be smarter
+ * and check if there was any data to begin with, for now just print the warning with
+ * some info to help troubleshoot what's going on - campbell */
+ printf(
+ "%s: warning! Tessellation uvs or vcol data got out of sync, "
+ "had to reset!\n CD_MTFACE: %d != CD_MLOOPUV: %d || CD_MCOL: %d != CD_MLOOPCOL: "
+ "%d\n",
+ __func__,
+ tottex_tessface,
+ tottex_original,
+ totcol_tessface,
+ totcol_original);
+ }
+ }
+ }
}
void BKE_mesh_ensure_skin_customdata(Mesh *me)
{
- BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : NULL;
- MVertSkin *vs;
-
- if (bm) {
- if (!CustomData_has_layer(&bm->vdata, CD_MVERT_SKIN)) {
- BMVert *v;
- BMIter iter;
-
- BM_data_layer_add(bm, &bm->vdata, CD_MVERT_SKIN);
-
- /* Mark an arbitrary vertex as root */
- BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
- vs = CustomData_bmesh_get(
- &bm->vdata, v->head.data,
- CD_MVERT_SKIN);
- vs->flag |= MVERT_SKIN_ROOT;
- break;
- }
- }
- }
- else {
- if (!CustomData_has_layer(&me->vdata, CD_MVERT_SKIN)) {
- vs = CustomData_add_layer(
- &me->vdata,
- CD_MVERT_SKIN,
- CD_DEFAULT,
- NULL,
- me->totvert);
-
- /* Mark an arbitrary vertex as root */
- if (vs) {
- vs->flag |= MVERT_SKIN_ROOT;
- }
- }
- }
+ BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : NULL;
+ MVertSkin *vs;
+
+ if (bm) {
+ if (!CustomData_has_layer(&bm->vdata, CD_MVERT_SKIN)) {
+ BMVert *v;
+ BMIter iter;
+
+ BM_data_layer_add(bm, &bm->vdata, CD_MVERT_SKIN);
+
+ /* Mark an arbitrary vertex as root */
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ vs = CustomData_bmesh_get(&bm->vdata, v->head.data, CD_MVERT_SKIN);
+ vs->flag |= MVERT_SKIN_ROOT;
+ break;
+ }
+ }
+ }
+ else {
+ if (!CustomData_has_layer(&me->vdata, CD_MVERT_SKIN)) {
+ vs = CustomData_add_layer(&me->vdata, CD_MVERT_SKIN, CD_DEFAULT, NULL, me->totvert);
+
+ /* Mark an arbitrary vertex as root */
+ if (vs) {
+ vs->flag |= MVERT_SKIN_ROOT;
+ }
+ }
+ }
}
bool BKE_mesh_ensure_facemap_customdata(struct Mesh *me)
{
- BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : NULL;
- bool changed = false;
- if (bm) {
- if (!CustomData_has_layer(&bm->pdata, CD_FACEMAP)) {
- BM_data_layer_add(bm, &bm->pdata, CD_FACEMAP);
- changed = true;
- }
- }
- else {
- if (!CustomData_has_layer(&me->pdata, CD_FACEMAP)) {
- CustomData_add_layer(
- &me->pdata,
- CD_FACEMAP,
- CD_DEFAULT,
- NULL,
- me->totpoly);
- changed = true;
- }
- }
- return changed;
+ BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : NULL;
+ bool changed = false;
+ if (bm) {
+ if (!CustomData_has_layer(&bm->pdata, CD_FACEMAP)) {
+ BM_data_layer_add(bm, &bm->pdata, CD_FACEMAP);
+ changed = true;
+ }
+ }
+ else {
+ if (!CustomData_has_layer(&me->pdata, CD_FACEMAP)) {
+ CustomData_add_layer(&me->pdata, CD_FACEMAP, CD_DEFAULT, NULL, me->totpoly);
+ changed = true;
+ }
+ }
+ return changed;
}
bool BKE_mesh_clear_facemap_customdata(struct Mesh *me)
{
- BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : NULL;
- bool changed = false;
- if (bm) {
- if (CustomData_has_layer(&bm->pdata, CD_FACEMAP)) {
- BM_data_layer_free(bm, &bm->pdata, CD_FACEMAP);
- changed = true;
- }
- }
- else {
- if (CustomData_has_layer(&me->pdata, CD_FACEMAP)) {
- CustomData_free_layers(&me->pdata, CD_FACEMAP, me->totpoly);
- changed = true;
- }
- }
- return changed;
+ BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : NULL;
+ bool changed = false;
+ if (bm) {
+ if (CustomData_has_layer(&bm->pdata, CD_FACEMAP)) {
+ BM_data_layer_free(bm, &bm->pdata, CD_FACEMAP);
+ changed = true;
+ }
+ }
+ else {
+ if (CustomData_has_layer(&me->pdata, CD_FACEMAP)) {
+ CustomData_free_layers(&me->pdata, CD_FACEMAP, me->totpoly);
+ changed = true;
+ }
+ }
+ return changed;
}
/* this ensures grouped customdata (e.g. mtexpoly and mloopuv and mtface, or
@@ -419,101 +419,101 @@ bool BKE_mesh_clear_facemap_customdata(struct Mesh *me)
* versions of the mesh. - campbell*/
static void mesh_update_linked_customdata(Mesh *me, const bool do_ensure_tess_cd)
{
- if (do_ensure_tess_cd) {
- mesh_ensure_tessellation_customdata(me);
- }
+ if (do_ensure_tess_cd) {
+ mesh_ensure_tessellation_customdata(me);
+ }
- CustomData_bmesh_update_active_layers(&me->fdata, &me->ldata);
+ CustomData_bmesh_update_active_layers(&me->fdata, &me->ldata);
}
void BKE_mesh_update_customdata_pointers(Mesh *me, const bool do_ensure_tess_cd)
{
- mesh_update_linked_customdata(me, do_ensure_tess_cd);
+ mesh_update_linked_customdata(me, do_ensure_tess_cd);
- me->mvert = CustomData_get_layer(&me->vdata, CD_MVERT);
- me->dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT);
+ me->mvert = CustomData_get_layer(&me->vdata, CD_MVERT);
+ me->dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT);
- me->medge = CustomData_get_layer(&me->edata, CD_MEDGE);
+ me->medge = CustomData_get_layer(&me->edata, CD_MEDGE);
- me->mface = CustomData_get_layer(&me->fdata, CD_MFACE);
- me->mcol = CustomData_get_layer(&me->fdata, CD_MCOL);
- me->mtface = CustomData_get_layer(&me->fdata, CD_MTFACE);
+ me->mface = CustomData_get_layer(&me->fdata, CD_MFACE);
+ me->mcol = CustomData_get_layer(&me->fdata, CD_MCOL);
+ me->mtface = CustomData_get_layer(&me->fdata, CD_MTFACE);
- me->mpoly = CustomData_get_layer(&me->pdata, CD_MPOLY);
- me->mloop = CustomData_get_layer(&me->ldata, CD_MLOOP);
+ me->mpoly = CustomData_get_layer(&me->pdata, CD_MPOLY);
+ me->mloop = CustomData_get_layer(&me->ldata, CD_MLOOP);
- me->mloopcol = CustomData_get_layer(&me->ldata, CD_MLOOPCOL);
- me->mloopuv = CustomData_get_layer(&me->ldata, CD_MLOOPUV);
+ me->mloopcol = CustomData_get_layer(&me->ldata, CD_MLOOPCOL);
+ me->mloopuv = CustomData_get_layer(&me->ldata, CD_MLOOPUV);
}
bool BKE_mesh_has_custom_loop_normals(Mesh *me)
{
- if (me->edit_mesh) {
- return CustomData_has_layer(&me->edit_mesh->bm->ldata, CD_CUSTOMLOOPNORMAL);
- }
- else {
- return CustomData_has_layer(&me->ldata, CD_CUSTOMLOOPNORMAL);
- }
+ if (me->edit_mesh) {
+ return CustomData_has_layer(&me->edit_mesh->bm->ldata, CD_CUSTOMLOOPNORMAL);
+ }
+ else {
+ return CustomData_has_layer(&me->ldata, CD_CUSTOMLOOPNORMAL);
+ }
}
/** Free (or release) any data used by this mesh (does not free the mesh itself). */
void BKE_mesh_free(Mesh *me)
{
- BKE_animdata_free(&me->id, false);
+ BKE_animdata_free(&me->id, false);
- BKE_mesh_runtime_clear_cache(me);
+ BKE_mesh_runtime_clear_cache(me);
- CustomData_free(&me->vdata, me->totvert);
- CustomData_free(&me->edata, me->totedge);
- CustomData_free(&me->fdata, me->totface);
- CustomData_free(&me->ldata, me->totloop);
- CustomData_free(&me->pdata, me->totpoly);
+ CustomData_free(&me->vdata, me->totvert);
+ CustomData_free(&me->edata, me->totedge);
+ CustomData_free(&me->fdata, me->totface);
+ CustomData_free(&me->ldata, me->totloop);
+ CustomData_free(&me->pdata, me->totpoly);
- MEM_SAFE_FREE(me->mat);
- MEM_SAFE_FREE(me->bb);
- MEM_SAFE_FREE(me->mselect);
- MEM_SAFE_FREE(me->edit_mesh);
+ MEM_SAFE_FREE(me->mat);
+ MEM_SAFE_FREE(me->bb);
+ MEM_SAFE_FREE(me->mselect);
+ MEM_SAFE_FREE(me->edit_mesh);
}
static void mesh_tessface_clear_intern(Mesh *mesh, int free_customdata)
{
- if (free_customdata) {
- CustomData_free(&mesh->fdata, mesh->totface);
- }
- else {
- CustomData_reset(&mesh->fdata);
- }
+ if (free_customdata) {
+ CustomData_free(&mesh->fdata, mesh->totface);
+ }
+ else {
+ CustomData_reset(&mesh->fdata);
+ }
- mesh->mface = NULL;
- mesh->mtface = NULL;
- mesh->mcol = NULL;
- mesh->totface = 0;
+ mesh->mface = NULL;
+ mesh->mtface = NULL;
+ mesh->mcol = NULL;
+ mesh->totface = 0;
}
void BKE_mesh_init(Mesh *me)
{
- BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(me, id));
+ BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(me, id));
- me->size[0] = me->size[1] = me->size[2] = 1.0;
- me->smoothresh = DEG2RADF(30);
- me->texflag = ME_AUTOSPACE;
+ me->size[0] = me->size[1] = me->size[2] = 1.0;
+ me->smoothresh = DEG2RADF(30);
+ me->texflag = ME_AUTOSPACE;
- CustomData_reset(&me->vdata);
- CustomData_reset(&me->edata);
- CustomData_reset(&me->fdata);
- CustomData_reset(&me->pdata);
- CustomData_reset(&me->ldata);
+ CustomData_reset(&me->vdata);
+ CustomData_reset(&me->edata);
+ CustomData_reset(&me->fdata);
+ CustomData_reset(&me->pdata);
+ CustomData_reset(&me->ldata);
}
Mesh *BKE_mesh_add(Main *bmain, const char *name)
{
- Mesh *me;
+ Mesh *me;
- me = BKE_libblock_alloc(bmain, ID_ME, name, 0);
+ me = BKE_libblock_alloc(bmain, ID_ME, name, 0);
- BKE_mesh_init(me);
+ BKE_mesh_init(me);
- return me;
+ return me;
}
/**
@@ -526,659 +526,675 @@ Mesh *BKE_mesh_add(Main *bmain, const char *name)
*/
void BKE_mesh_copy_data(Main *bmain, Mesh *me_dst, const Mesh *me_src, const int flag)
{
- BKE_mesh_runtime_reset_on_copy(me_dst, flag);
- if ((me_src->id.tag & LIB_TAG_NO_MAIN) == 0) {
- /* This is a direct copy of a main mesh, so for now it has the same topology. */
- me_dst->runtime.deformed_only = true;
- }
- /* XXX WHAT? Why? Comment, please! And pretty sure this is not valid for regular Mesh copying? */
- me_dst->runtime.is_original = false;
+ BKE_mesh_runtime_reset_on_copy(me_dst, flag);
+ if ((me_src->id.tag & LIB_TAG_NO_MAIN) == 0) {
+ /* This is a direct copy of a main mesh, so for now it has the same topology. */
+ me_dst->runtime.deformed_only = true;
+ }
+ /* XXX WHAT? Why? Comment, please! And pretty sure this is not valid for regular Mesh copying? */
+ me_dst->runtime.is_original = false;
- const bool do_tessface = ((me_src->totface != 0) && (me_src->totpoly == 0)); /* only do tessface if we have no polys */
- CustomData_MeshMasks mask = CD_MASK_MESH;
+ const bool do_tessface = ((me_src->totface != 0) &&
+ (me_src->totpoly == 0)); /* only do tessface if we have no polys */
+ CustomData_MeshMasks mask = CD_MASK_MESH;
- if (me_src->id.tag & LIB_TAG_NO_MAIN) {
- /* For copies in depsgraph, keep data like origindex and orco. */
- CustomData_MeshMasks_update(&mask, &CD_MASK_DERIVEDMESH);
- }
+ if (me_src->id.tag & LIB_TAG_NO_MAIN) {
+ /* For copies in depsgraph, keep data like origindex and orco. */
+ CustomData_MeshMasks_update(&mask, &CD_MASK_DERIVEDMESH);
+ }
- me_dst->mat = MEM_dupallocN(me_src->mat);
+ me_dst->mat = MEM_dupallocN(me_src->mat);
- const eCDAllocType alloc_type = (flag & LIB_ID_COPY_CD_REFERENCE) ? CD_REFERENCE : CD_DUPLICATE;
- CustomData_copy(&me_src->vdata, &me_dst->vdata, mask.vmask, alloc_type, me_dst->totvert);
- CustomData_copy(&me_src->edata, &me_dst->edata, mask.emask, alloc_type, me_dst->totedge);
- CustomData_copy(&me_src->ldata, &me_dst->ldata, mask.lmask, alloc_type, me_dst->totloop);
- CustomData_copy(&me_src->pdata, &me_dst->pdata, mask.pmask, alloc_type, me_dst->totpoly);
- if (do_tessface) {
- CustomData_copy(&me_src->fdata, &me_dst->fdata, mask.fmask, alloc_type, me_dst->totface);
- }
- else {
- mesh_tessface_clear_intern(me_dst, false);
- }
+ const eCDAllocType alloc_type = (flag & LIB_ID_COPY_CD_REFERENCE) ? CD_REFERENCE : CD_DUPLICATE;
+ CustomData_copy(&me_src->vdata, &me_dst->vdata, mask.vmask, alloc_type, me_dst->totvert);
+ CustomData_copy(&me_src->edata, &me_dst->edata, mask.emask, alloc_type, me_dst->totedge);
+ CustomData_copy(&me_src->ldata, &me_dst->ldata, mask.lmask, alloc_type, me_dst->totloop);
+ CustomData_copy(&me_src->pdata, &me_dst->pdata, mask.pmask, alloc_type, me_dst->totpoly);
+ if (do_tessface) {
+ CustomData_copy(&me_src->fdata, &me_dst->fdata, mask.fmask, alloc_type, me_dst->totface);
+ }
+ else {
+ mesh_tessface_clear_intern(me_dst, false);
+ }
- BKE_mesh_update_customdata_pointers(me_dst, do_tessface);
+ BKE_mesh_update_customdata_pointers(me_dst, do_tessface);
- me_dst->edit_mesh = NULL;
+ me_dst->edit_mesh = NULL;
- me_dst->mselect = MEM_dupallocN(me_dst->mselect);
- me_dst->bb = MEM_dupallocN(me_dst->bb);
+ me_dst->mselect = MEM_dupallocN(me_dst->mselect);
+ me_dst->bb = MEM_dupallocN(me_dst->bb);
- /* TODO Do we want to add flag to prevent this? */
- if (me_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) {
- BKE_id_copy_ex(bmain, &me_src->key->id, (ID **)&me_dst->key, flag);
- }
+ /* TODO Do we want to add flag to prevent this? */
+ if (me_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) {
+ BKE_id_copy_ex(bmain, &me_src->key->id, (ID **)&me_dst->key, flag);
+ }
}
/* Custom data layer functions; those assume that totXXX are set correctly. */
static void mesh_ensure_cdlayers_primary(Mesh *mesh, bool do_tessface)
{
- if (!CustomData_get_layer(&mesh->vdata, CD_MVERT))
- CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, NULL, mesh->totvert);
- if (!CustomData_get_layer(&mesh->edata, CD_MEDGE))
- CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_CALLOC, NULL, mesh->totedge);
- if (!CustomData_get_layer(&mesh->ldata, CD_MLOOP))
- CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, NULL, mesh->totloop);
- if (!CustomData_get_layer(&mesh->pdata, CD_MPOLY))
- CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, NULL, mesh->totpoly);
+ if (!CustomData_get_layer(&mesh->vdata, CD_MVERT))
+ CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, NULL, mesh->totvert);
+ if (!CustomData_get_layer(&mesh->edata, CD_MEDGE))
+ CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_CALLOC, NULL, mesh->totedge);
+ if (!CustomData_get_layer(&mesh->ldata, CD_MLOOP))
+ CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, NULL, mesh->totloop);
+ if (!CustomData_get_layer(&mesh->pdata, CD_MPOLY))
+ CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, NULL, mesh->totpoly);
- if (do_tessface && !CustomData_get_layer(&mesh->fdata, CD_MFACE))
- CustomData_add_layer(&mesh->fdata, CD_MFACE, CD_CALLOC, NULL, mesh->totface);
+ if (do_tessface && !CustomData_get_layer(&mesh->fdata, CD_MFACE))
+ CustomData_add_layer(&mesh->fdata, CD_MFACE, CD_CALLOC, NULL, mesh->totface);
}
-Mesh *BKE_mesh_new_nomain(int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len)
+Mesh *BKE_mesh_new_nomain(
+ int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len)
{
- Mesh *mesh = BKE_libblock_alloc(
- NULL, ID_ME,
- BKE_idcode_to_name(ID_ME),
- LIB_ID_COPY_LOCALIZE);
- BKE_libblock_init_empty(&mesh->id);
+ Mesh *mesh = BKE_libblock_alloc(NULL, ID_ME, BKE_idcode_to_name(ID_ME), LIB_ID_COPY_LOCALIZE);
+ BKE_libblock_init_empty(&mesh->id);
- /* don't use CustomData_reset(...); because we dont want to touch customdata */
- copy_vn_i(mesh->vdata.typemap, CD_NUMTYPES, -1);
- copy_vn_i(mesh->edata.typemap, CD_NUMTYPES, -1);
- copy_vn_i(mesh->fdata.typemap, CD_NUMTYPES, -1);
- copy_vn_i(mesh->ldata.typemap, CD_NUMTYPES, -1);
- copy_vn_i(mesh->pdata.typemap, CD_NUMTYPES, -1);
+ /* don't use CustomData_reset(...); because we dont want to touch customdata */
+ copy_vn_i(mesh->vdata.typemap, CD_NUMTYPES, -1);
+ copy_vn_i(mesh->edata.typemap, CD_NUMTYPES, -1);
+ copy_vn_i(mesh->fdata.typemap, CD_NUMTYPES, -1);
+ copy_vn_i(mesh->ldata.typemap, CD_NUMTYPES, -1);
+ copy_vn_i(mesh->pdata.typemap, CD_NUMTYPES, -1);
- mesh->totvert = verts_len;
- mesh->totedge = edges_len;
- mesh->totface = tessface_len;
- mesh->totloop = loops_len;
- mesh->totpoly = polys_len;
+ mesh->totvert = verts_len;
+ mesh->totedge = edges_len;
+ mesh->totface = tessface_len;
+ mesh->totloop = loops_len;
+ mesh->totpoly = polys_len;
- mesh_ensure_cdlayers_primary(mesh, true);
- BKE_mesh_update_customdata_pointers(mesh, false);
+ mesh_ensure_cdlayers_primary(mesh, true);
+ BKE_mesh_update_customdata_pointers(mesh, false);
- return mesh;
+ return mesh;
}
-static Mesh *mesh_new_nomain_from_template_ex(
- const Mesh *me_src,
- int verts_len, int edges_len, int tessface_len,
- int loops_len, int polys_len,
- CustomData_MeshMasks mask)
+static Mesh *mesh_new_nomain_from_template_ex(const Mesh *me_src,
+ int verts_len,
+ int edges_len,
+ int tessface_len,
+ int loops_len,
+ int polys_len,
+ CustomData_MeshMasks mask)
{
- /* Only do tessface if we are creating tessfaces or copying from mesh with only tessfaces. */
- const bool do_tessface = (tessface_len ||
- ((me_src->totface != 0) && (me_src->totpoly == 0)));
+ /* Only do tessface if we are creating tessfaces or copying from mesh with only tessfaces. */
+ const bool do_tessface = (tessface_len || ((me_src->totface != 0) && (me_src->totpoly == 0)));
- Mesh *me_dst = BKE_id_new_nomain(ID_ME, NULL);
+ Mesh *me_dst = BKE_id_new_nomain(ID_ME, NULL);
- me_dst->mat = MEM_dupallocN(me_src->mat);
- me_dst->mselect = MEM_dupallocN(me_dst->mselect);
+ me_dst->mat = MEM_dupallocN(me_src->mat);
+ me_dst->mselect = MEM_dupallocN(me_dst->mselect);
- me_dst->totvert = verts_len;
- me_dst->totedge = edges_len;
- me_dst->totface = tessface_len;
- me_dst->totloop = loops_len;
- me_dst->totpoly = polys_len;
+ me_dst->totvert = verts_len;
+ me_dst->totedge = edges_len;
+ me_dst->totface = tessface_len;
+ me_dst->totloop = loops_len;
+ me_dst->totpoly = polys_len;
- me_dst->cd_flag = me_src->cd_flag;
- me_dst->editflag = me_src->editflag;
+ me_dst->cd_flag = me_src->cd_flag;
+ me_dst->editflag = me_src->editflag;
- CustomData_copy(&me_src->vdata, &me_dst->vdata, mask.vmask, CD_CALLOC, verts_len);
- CustomData_copy(&me_src->edata, &me_dst->edata, mask.emask, CD_CALLOC, edges_len);
- CustomData_copy(&me_src->ldata, &me_dst->ldata, mask.lmask, CD_CALLOC, loops_len);
- CustomData_copy(&me_src->pdata, &me_dst->pdata, mask.pmask, CD_CALLOC, polys_len);
- if (do_tessface) {
- CustomData_copy(&me_src->fdata, &me_dst->fdata, mask.fmask, CD_CALLOC, tessface_len);
- }
- else {
- mesh_tessface_clear_intern(me_dst, false);
- }
+ CustomData_copy(&me_src->vdata, &me_dst->vdata, mask.vmask, CD_CALLOC, verts_len);
+ CustomData_copy(&me_src->edata, &me_dst->edata, mask.emask, CD_CALLOC, edges_len);
+ CustomData_copy(&me_src->ldata, &me_dst->ldata, mask.lmask, CD_CALLOC, loops_len);
+ CustomData_copy(&me_src->pdata, &me_dst->pdata, mask.pmask, CD_CALLOC, polys_len);
+ if (do_tessface) {
+ CustomData_copy(&me_src->fdata, &me_dst->fdata, mask.fmask, CD_CALLOC, tessface_len);
+ }
+ else {
+ mesh_tessface_clear_intern(me_dst, false);
+ }
- /* The destination mesh should at least have valid primary CD layers,
- * even in cases where the source mesh does not. */
- mesh_ensure_cdlayers_primary(me_dst, do_tessface);
- BKE_mesh_update_customdata_pointers(me_dst, false);
+ /* The destination mesh should at least have valid primary CD layers,
+ * even in cases where the source mesh does not. */
+ mesh_ensure_cdlayers_primary(me_dst, do_tessface);
+ BKE_mesh_update_customdata_pointers(me_dst, false);
- return me_dst;
+ return me_dst;
}
-Mesh *BKE_mesh_new_nomain_from_template(
- const Mesh *me_src,
- int verts_len, int edges_len, int tessface_len,
- int loops_len, int polys_len)
+Mesh *BKE_mesh_new_nomain_from_template(const Mesh *me_src,
+ int verts_len,
+ int edges_len,
+ int tessface_len,
+ int loops_len,
+ int polys_len)
{
- return mesh_new_nomain_from_template_ex(
- me_src,
- verts_len, edges_len, tessface_len,
- loops_len, polys_len,
- CD_MASK_EVERYTHING);
+ return mesh_new_nomain_from_template_ex(
+ me_src, verts_len, edges_len, tessface_len, loops_len, polys_len, CD_MASK_EVERYTHING);
}
Mesh *BKE_mesh_copy_for_eval(struct Mesh *source, bool reference)
{
- int flags = LIB_ID_COPY_LOCALIZE;
+ int flags = LIB_ID_COPY_LOCALIZE;
- if (reference) {
- flags |= LIB_ID_COPY_CD_REFERENCE;
- }
+ if (reference) {
+ flags |= LIB_ID_COPY_CD_REFERENCE;
+ }
- Mesh *result;
- BKE_id_copy_ex(NULL, &source->id, (ID **)&result, flags);
- return result;
+ Mesh *result;
+ BKE_id_copy_ex(NULL, &source->id, (ID **)&result, flags);
+ return result;
}
Mesh *BKE_mesh_copy(Main *bmain, const Mesh *me)
{
- Mesh *me_copy;
- BKE_id_copy(bmain, &me->id, (ID **)&me_copy);
- return me_copy;
+ Mesh *me_copy;
+ BKE_id_copy(bmain, &me->id, (ID **)&me_copy);
+ return me_copy;
}
-BMesh *BKE_mesh_to_bmesh_ex(
- const Mesh *me,
- const struct BMeshCreateParams *create_params,
- const struct BMeshFromMeshParams *convert_params)
+BMesh *BKE_mesh_to_bmesh_ex(const Mesh *me,
+ const struct BMeshCreateParams *create_params,
+ const struct BMeshFromMeshParams *convert_params)
{
- BMesh *bm;
- const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(me);
+ BMesh *bm;
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(me);
- bm = BM_mesh_create(&allocsize, create_params);
- BM_mesh_bm_from_me(bm, me, convert_params);
+ bm = BM_mesh_create(&allocsize, create_params);
+ BM_mesh_bm_from_me(bm, me, convert_params);
- return bm;
+ return bm;
}
-BMesh *BKE_mesh_to_bmesh(
- Mesh *me, Object *ob,
- const bool add_key_index, const struct BMeshCreateParams *params)
+BMesh *BKE_mesh_to_bmesh(Mesh *me,
+ Object *ob,
+ const bool add_key_index,
+ const struct BMeshCreateParams *params)
{
- return BKE_mesh_to_bmesh_ex(
- me, params,
- &(struct BMeshFromMeshParams){
- .calc_face_normal = false,
- .add_key_index = add_key_index,
- .use_shapekey = true,
- .active_shapekey = ob->shapenr,
- });
+ return BKE_mesh_to_bmesh_ex(me,
+ params,
+ &(struct BMeshFromMeshParams){
+ .calc_face_normal = false,
+ .add_key_index = add_key_index,
+ .use_shapekey = true,
+ .active_shapekey = ob->shapenr,
+ });
}
Mesh *BKE_mesh_from_bmesh_nomain(BMesh *bm, const struct BMeshToMeshParams *params)
{
- BLI_assert(params->calc_object_remap == false);
- Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL);
- BM_mesh_bm_to_me(NULL, bm, mesh, params);
- return mesh;
+ BLI_assert(params->calc_object_remap == false);
+ Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL);
+ BM_mesh_bm_to_me(NULL, bm, mesh, params);
+ return mesh;
}
Mesh *BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm, const CustomData_MeshMasks *cd_mask_extra)
{
- Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL);
- BM_mesh_bm_to_me_for_eval(bm, mesh, cd_mask_extra);
- return mesh;
+ Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL);
+ BM_mesh_bm_to_me_for_eval(bm, mesh, cd_mask_extra);
+ return mesh;
}
/**
* TODO(campbell): support mesh with only an edit-mesh which is lazy initialized.
*/
-Mesh *BKE_mesh_from_editmesh_with_coords_thin_wrap(
- BMEditMesh *em, const CustomData_MeshMasks *data_mask, float (*vertexCos)[3])
-{
- Mesh *me = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, data_mask);
- /* Use editmesh directly where possible. */
- me->runtime.is_original = true;
- if (vertexCos) {
- /* We will own this array in the future. */
- BKE_mesh_apply_vert_coords(me, vertexCos);
- MEM_freeN(vertexCos);
- me->runtime.is_original = false;
- }
- return me;
+Mesh *BKE_mesh_from_editmesh_with_coords_thin_wrap(BMEditMesh *em,
+ const CustomData_MeshMasks *data_mask,
+ float (*vertexCos)[3])
+{
+ Mesh *me = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, data_mask);
+ /* Use editmesh directly where possible. */
+ me->runtime.is_original = true;
+ if (vertexCos) {
+ /* We will own this array in the future. */
+ BKE_mesh_apply_vert_coords(me, vertexCos);
+ MEM_freeN(vertexCos);
+ me->runtime.is_original = false;
+ }
+ return me;
}
void BKE_mesh_make_local(Main *bmain, Mesh *me, const bool lib_local)
{
- BKE_id_make_local_generic(bmain, &me->id, true, lib_local);
-}
-
-bool BKE_mesh_uv_cdlayer_rename_index(
- Mesh *me, const int loop_index, const int face_index,
- const char *new_name, const bool do_tessface)
-{
- CustomData *ldata, *fdata;
- CustomDataLayer *cdlu, *cdlf;
-
- if (me->edit_mesh) {
- ldata = &me->edit_mesh->bm->ldata;
- fdata = NULL; /* No tessellated data in BMesh! */
- }
- else {
- ldata = &me->ldata;
- fdata = &me->fdata;
- }
-
- cdlu = &ldata->layers[loop_index];
- cdlf = (face_index != -1) && fdata && do_tessface ? &fdata->layers[face_index] : NULL;
-
- if (cdlu->name != new_name) {
- /* Mesh validate passes a name from the CD layer as the new name,
- * Avoid memcpy from self to self in this case.
- */
- BLI_strncpy(cdlu->name, new_name, sizeof(cdlu->name));
- CustomData_set_layer_unique_name(ldata, loop_index);
- }
-
- if (cdlf == NULL) {
- return false;
- }
-
- BLI_strncpy(cdlf->name, cdlu->name, sizeof(cdlf->name));
- CustomData_set_layer_unique_name(fdata, face_index);
-
- return true;
-}
-
-bool BKE_mesh_uv_cdlayer_rename(Mesh *me, const char *old_name, const char *new_name, bool do_tessface)
-{
- CustomData *ldata, *fdata;
- if (me->edit_mesh) {
- ldata = &me->edit_mesh->bm->ldata;
- /* No tessellated data in BMesh! */
- fdata = NULL;
- do_tessface = false;
- }
- else {
- ldata = &me->ldata;
- fdata = &me->fdata;
- do_tessface = (do_tessface && fdata->totlayer);
- }
-
- {
- const int lidx_start = CustomData_get_layer_index(ldata, CD_MLOOPUV);
- const int fidx_start = do_tessface ? CustomData_get_layer_index(fdata, CD_MTFACE) : -1;
- int lidx = CustomData_get_named_layer(ldata, CD_MLOOPUV, old_name);
- int fidx = do_tessface ? CustomData_get_named_layer(fdata, CD_MTFACE, old_name) : -1;
-
- /* None of those cases should happen, in theory!
- * Note this assume we have the same number of mtexpoly, mloopuv and mtface layers!
- */
- if (lidx == -1) {
- if (fidx == -1) {
- /* No layer found with this name! */
- return false;
- }
- else {
- lidx = fidx;
- }
- }
-
- /* Go back to absolute indices! */
- lidx += lidx_start;
- if (fidx != -1)
- fidx += fidx_start;
-
- return BKE_mesh_uv_cdlayer_rename_index(me, lidx, fidx, new_name, do_tessface);
- }
+ BKE_id_make_local_generic(bmain, &me->id, true, lib_local);
+}
+
+bool BKE_mesh_uv_cdlayer_rename_index(Mesh *me,
+ const int loop_index,
+ const int face_index,
+ const char *new_name,
+ const bool do_tessface)
+{
+ CustomData *ldata, *fdata;
+ CustomDataLayer *cdlu, *cdlf;
+
+ if (me->edit_mesh) {
+ ldata = &me->edit_mesh->bm->ldata;
+ fdata = NULL; /* No tessellated data in BMesh! */
+ }
+ else {
+ ldata = &me->ldata;
+ fdata = &me->fdata;
+ }
+
+ cdlu = &ldata->layers[loop_index];
+ cdlf = (face_index != -1) && fdata && do_tessface ? &fdata->layers[face_index] : NULL;
+
+ if (cdlu->name != new_name) {
+ /* Mesh validate passes a name from the CD layer as the new name,
+ * Avoid memcpy from self to self in this case.
+ */
+ BLI_strncpy(cdlu->name, new_name, sizeof(cdlu->name));
+ CustomData_set_layer_unique_name(ldata, loop_index);
+ }
+
+ if (cdlf == NULL) {
+ return false;
+ }
+
+ BLI_strncpy(cdlf->name, cdlu->name, sizeof(cdlf->name));
+ CustomData_set_layer_unique_name(fdata, face_index);
+
+ return true;
+}
+
+bool BKE_mesh_uv_cdlayer_rename(Mesh *me,
+ const char *old_name,
+ const char *new_name,
+ bool do_tessface)
+{
+ CustomData *ldata, *fdata;
+ if (me->edit_mesh) {
+ ldata = &me->edit_mesh->bm->ldata;
+ /* No tessellated data in BMesh! */
+ fdata = NULL;
+ do_tessface = false;
+ }
+ else {
+ ldata = &me->ldata;
+ fdata = &me->fdata;
+ do_tessface = (do_tessface && fdata->totlayer);
+ }
+
+ {
+ const int lidx_start = CustomData_get_layer_index(ldata, CD_MLOOPUV);
+ const int fidx_start = do_tessface ? CustomData_get_layer_index(fdata, CD_MTFACE) : -1;
+ int lidx = CustomData_get_named_layer(ldata, CD_MLOOPUV, old_name);
+ int fidx = do_tessface ? CustomData_get_named_layer(fdata, CD_MTFACE, old_name) : -1;
+
+ /* None of those cases should happen, in theory!
+ * Note this assume we have the same number of mtexpoly, mloopuv and mtface layers!
+ */
+ if (lidx == -1) {
+ if (fidx == -1) {
+ /* No layer found with this name! */
+ return false;
+ }
+ else {
+ lidx = fidx;
+ }
+ }
+
+ /* Go back to absolute indices! */
+ lidx += lidx_start;
+ if (fidx != -1)
+ fidx += fidx_start;
+
+ return BKE_mesh_uv_cdlayer_rename_index(me, lidx, fidx, new_name, do_tessface);
+ }
}
void BKE_mesh_boundbox_calc(Mesh *me, float r_loc[3], float r_size[3])
{
- BoundBox *bb;
- float min[3], max[3];
- float mloc[3], msize[3];
+ BoundBox *bb;
+ float min[3], max[3];
+ float mloc[3], msize[3];
- if (me->bb == NULL) me->bb = MEM_callocN(sizeof(BoundBox), "boundbox");
- bb = me->bb;
+ if (me->bb == NULL)
+ me->bb = MEM_callocN(sizeof(BoundBox), "boundbox");
+ bb = me->bb;
- if (!r_loc) r_loc = mloc;
- if (!r_size) r_size = msize;
+ if (!r_loc)
+ r_loc = mloc;
+ if (!r_size)
+ r_size = msize;
- INIT_MINMAX(min, max);
- if (!BKE_mesh_minmax(me, min, max)) {
- min[0] = min[1] = min[2] = -1.0f;
- max[0] = max[1] = max[2] = 1.0f;
- }
+ INIT_MINMAX(min, max);
+ if (!BKE_mesh_minmax(me, min, max)) {
+ min[0] = min[1] = min[2] = -1.0f;
+ max[0] = max[1] = max[2] = 1.0f;
+ }
- mid_v3_v3v3(r_loc, min, max);
+ mid_v3_v3v3(r_loc, min, max);
- r_size[0] = (max[0] - min[0]) / 2.0f;
- r_size[1] = (max[1] - min[1]) / 2.0f;
- r_size[2] = (max[2] - min[2]) / 2.0f;
+ r_size[0] = (max[0] - min[0]) / 2.0f;
+ r_size[1] = (max[1] - min[1]) / 2.0f;
+ r_size[2] = (max[2] - min[2]) / 2.0f;
- BKE_boundbox_init_from_minmax(bb, min, max);
+ BKE_boundbox_init_from_minmax(bb, min, max);
- bb->flag &= ~BOUNDBOX_DIRTY;
+ bb->flag &= ~BOUNDBOX_DIRTY;
}
void BKE_mesh_texspace_calc(Mesh *me)
{
- float loc[3], size[3];
- int a;
+ float loc[3], size[3];
+ int a;
- BKE_mesh_boundbox_calc(me, loc, size);
+ BKE_mesh_boundbox_calc(me, loc, size);
- if (me->texflag & ME_AUTOSPACE) {
- for (a = 0; a < 3; a++) {
- if (size[a] == 0.0f) size[a] = 1.0f;
- else if (size[a] > 0.0f && size[a] < 0.00001f) size[a] = 0.00001f;
- else if (size[a] < 0.0f && size[a] > -0.00001f) size[a] = -0.00001f;
- }
+ if (me->texflag & ME_AUTOSPACE) {
+ for (a = 0; a < 3; a++) {
+ if (size[a] == 0.0f)
+ size[a] = 1.0f;
+ else if (size[a] > 0.0f && size[a] < 0.00001f)
+ size[a] = 0.00001f;
+ else if (size[a] < 0.0f && size[a] > -0.00001f)
+ size[a] = -0.00001f;
+ }
- copy_v3_v3(me->loc, loc);
- copy_v3_v3(me->size, size);
- zero_v3(me->rot);
- }
+ copy_v3_v3(me->loc, loc);
+ copy_v3_v3(me->size, size);
+ zero_v3(me->rot);
+ }
}
BoundBox *BKE_mesh_boundbox_get(Object *ob)
{
- /* This is Object-level data access, DO NOT touch to Mesh's bb, would be totally thread-unsafe. */
- if (ob->runtime.bb == NULL || ob->runtime.bb->flag & BOUNDBOX_DIRTY) {
- Mesh *me = ob->data;
- float min[3], max[3];
+ /* This is Object-level data access, DO NOT touch to Mesh's bb, would be totally thread-unsafe. */
+ if (ob->runtime.bb == NULL || ob->runtime.bb->flag & BOUNDBOX_DIRTY) {
+ Mesh *me = ob->data;
+ float min[3], max[3];
- INIT_MINMAX(min, max);
- if (!BKE_mesh_minmax(me, min, max)) {
- min[0] = min[1] = min[2] = -1.0f;
- max[0] = max[1] = max[2] = 1.0f;
- }
+ INIT_MINMAX(min, max);
+ if (!BKE_mesh_minmax(me, min, max)) {
+ min[0] = min[1] = min[2] = -1.0f;
+ max[0] = max[1] = max[2] = 1.0f;
+ }
- if (ob->runtime.bb == NULL) {
- ob->runtime.bb = MEM_mallocN(sizeof(*ob->runtime.bb), __func__);
- }
- BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
- ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
- }
+ if (ob->runtime.bb == NULL) {
+ ob->runtime.bb = MEM_mallocN(sizeof(*ob->runtime.bb), __func__);
+ }
+ BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
+ ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
+ }
- return ob->runtime.bb;
+ return ob->runtime.bb;
}
BoundBox *BKE_mesh_texspace_get(Mesh *me, float r_loc[3], float r_rot[3], float r_size[3])
{
- if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) {
- BKE_mesh_texspace_calc(me);
- }
+ if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) {
+ BKE_mesh_texspace_calc(me);
+ }
- if (r_loc) copy_v3_v3(r_loc, me->loc);
- if (r_rot) copy_v3_v3(r_rot, me->rot);
- if (r_size) copy_v3_v3(r_size, me->size);
+ if (r_loc)
+ copy_v3_v3(r_loc, me->loc);
+ if (r_rot)
+ copy_v3_v3(r_rot, me->rot);
+ if (r_size)
+ copy_v3_v3(r_size, me->size);
- return me->bb;
+ return me->bb;
}
-void BKE_mesh_texspace_get_reference(Mesh *me, short **r_texflag, float **r_loc, float **r_rot, float **r_size)
+void BKE_mesh_texspace_get_reference(
+ Mesh *me, short **r_texflag, float **r_loc, float **r_rot, float **r_size)
{
- if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) {
- BKE_mesh_texspace_calc(me);
- }
+ if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) {
+ BKE_mesh_texspace_calc(me);
+ }
- if (r_texflag != NULL) *r_texflag = &me->texflag;
- if (r_loc != NULL) *r_loc = me->loc;
- if (r_rot != NULL) *r_rot = me->rot;
- if (r_size != NULL) *r_size = me->size;
+ if (r_texflag != NULL)
+ *r_texflag = &me->texflag;
+ if (r_loc != NULL)
+ *r_loc = me->loc;
+ if (r_rot != NULL)
+ *r_rot = me->rot;
+ if (r_size != NULL)
+ *r_size = me->size;
}
void BKE_mesh_texspace_copy_from_object(Mesh *me, Object *ob)
{
- float *texloc, *texrot, *texsize;
- short *texflag;
+ float *texloc, *texrot, *texsize;
+ short *texflag;
- if (BKE_object_obdata_texspace_get(ob, &texflag, &texloc, &texsize, &texrot)) {
- me->texflag = *texflag;
- copy_v3_v3(me->loc, texloc);
- copy_v3_v3(me->size, texsize);
- copy_v3_v3(me->rot, texrot);
- }
+ if (BKE_object_obdata_texspace_get(ob, &texflag, &texloc, &texsize, &texrot)) {
+ me->texflag = *texflag;
+ copy_v3_v3(me->loc, texloc);
+ copy_v3_v3(me->size, texsize);
+ copy_v3_v3(me->rot, texrot);
+ }
}
float (*BKE_mesh_orco_verts_get(Object *ob))[3]
{
- Mesh *me = ob->data;
- MVert *mvert = NULL;
- Mesh *tme = me->texcomesh ? me->texcomesh : me;
- int a, totvert;
- float (*vcos)[3] = NULL;
+ Mesh *me = ob->data;
+ MVert *mvert = NULL;
+ Mesh *tme = me->texcomesh ? me->texcomesh : me;
+ int a, totvert;
+ float(*vcos)[3] = NULL;
- /* Get appropriate vertex coordinates */
- vcos = MEM_calloc_arrayN(me->totvert, sizeof(*vcos), "orco mesh");
- mvert = tme->mvert;
- totvert = min_ii(tme->totvert, me->totvert);
+ /* Get appropriate vertex coordinates */
+ vcos = MEM_calloc_arrayN(me->totvert, sizeof(*vcos), "orco mesh");
+ mvert = tme->mvert;
+ totvert = min_ii(tme->totvert, me->totvert);
- for (a = 0; a < totvert; a++, mvert++) {
- copy_v3_v3(vcos[a], mvert->co);
- }
+ for (a = 0; a < totvert; a++, mvert++) {
+ copy_v3_v3(vcos[a], mvert->co);
+ }
- return vcos;
+ return vcos;
}
void BKE_mesh_orco_verts_transform(Mesh *me, float (*orco)[3], int totvert, int invert)
{
- float loc[3], size[3];
- int a;
+ float loc[3], size[3];
+ int a;
- BKE_mesh_texspace_get(me->texcomesh ? me->texcomesh : me, loc, NULL, size);
+ BKE_mesh_texspace_get(me->texcomesh ? me->texcomesh : me, loc, NULL, size);
- if (invert) {
- for (a = 0; a < totvert; a++) {
- float *co = orco[a];
- madd_v3_v3v3v3(co, loc, co, size);
- }
- }
- else {
- for (a = 0; a < totvert; a++) {
- float *co = orco[a];
- co[0] = (co[0] - loc[0]) / size[0];
- co[1] = (co[1] - loc[1]) / size[1];
- co[2] = (co[2] - loc[2]) / size[2];
- }
- }
+ if (invert) {
+ for (a = 0; a < totvert; a++) {
+ float *co = orco[a];
+ madd_v3_v3v3v3(co, loc, co, size);
+ }
+ }
+ else {
+ for (a = 0; a < totvert; a++) {
+ float *co = orco[a];
+ co[0] = (co[0] - loc[0]) / size[0];
+ co[1] = (co[1] - loc[1]) / size[1];
+ co[2] = (co[2] - loc[2]) / size[2];
+ }
+ }
}
/* rotates the vertices of a face in case v[2] or v[3] (vertex index) is = 0.
* this is necessary to make the if (mface->v4) check for quads work */
int test_index_face(MFace *mface, CustomData *fdata, int mfindex, int nr)
{
- /* first test if the face is legal */
- if ((mface->v3 || nr == 4) && mface->v3 == mface->v4) {
- mface->v4 = 0;
- nr--;
- }
- if ((mface->v2 || mface->v4) && mface->v2 == mface->v3) {
- mface->v3 = mface->v4;
- mface->v4 = 0;
- nr--;
- }
- if (mface->v1 == mface->v2) {
- mface->v2 = mface->v3;
- mface->v3 = mface->v4;
- mface->v4 = 0;
- nr--;
- }
-
- /* check corrupt cases, bow-tie geometry, cant handle these because edge data wont exist so just return 0 */
- if (nr == 3) {
- if (
- /* real edges */
- mface->v1 == mface->v2 ||
- mface->v2 == mface->v3 ||
- mface->v3 == mface->v1)
- {
- return 0;
- }
- }
- else if (nr == 4) {
- if (
- /* real edges */
- mface->v1 == mface->v2 ||
- mface->v2 == mface->v3 ||
- mface->v3 == mface->v4 ||
- mface->v4 == mface->v1 ||
- /* across the face */
- mface->v1 == mface->v3 ||
- mface->v2 == mface->v4)
- {
- return 0;
- }
- }
-
- /* prevent a zero at wrong index location */
- if (nr == 3) {
- if (mface->v3 == 0) {
- static int corner_indices[4] = {1, 2, 0, 3};
-
- SWAP(unsigned int, mface->v1, mface->v2);
- SWAP(unsigned int, mface->v2, mface->v3);
-
- if (fdata)
- CustomData_swap_corners(fdata, mfindex, corner_indices);
- }
- }
- else if (nr == 4) {
- if (mface->v3 == 0 || mface->v4 == 0) {
- static int corner_indices[4] = {2, 3, 0, 1};
-
- SWAP(unsigned int, mface->v1, mface->v3);
- SWAP(unsigned int, mface->v2, mface->v4);
-
- if (fdata)
- CustomData_swap_corners(fdata, mfindex, corner_indices);
- }
- }
-
- return nr;
+ /* first test if the face is legal */
+ if ((mface->v3 || nr == 4) && mface->v3 == mface->v4) {
+ mface->v4 = 0;
+ nr--;
+ }
+ if ((mface->v2 || mface->v4) && mface->v2 == mface->v3) {
+ mface->v3 = mface->v4;
+ mface->v4 = 0;
+ nr--;
+ }
+ if (mface->v1 == mface->v2) {
+ mface->v2 = mface->v3;
+ mface->v3 = mface->v4;
+ mface->v4 = 0;
+ nr--;
+ }
+
+ /* check corrupt cases, bow-tie geometry, cant handle these because edge data wont exist so just return 0 */
+ if (nr == 3) {
+ if (
+ /* real edges */
+ mface->v1 == mface->v2 || mface->v2 == mface->v3 || mface->v3 == mface->v1) {
+ return 0;
+ }
+ }
+ else if (nr == 4) {
+ if (
+ /* real edges */
+ mface->v1 == mface->v2 || mface->v2 == mface->v3 || mface->v3 == mface->v4 ||
+ mface->v4 == mface->v1 ||
+ /* across the face */
+ mface->v1 == mface->v3 || mface->v2 == mface->v4) {
+ return 0;
+ }
+ }
+
+ /* prevent a zero at wrong index location */
+ if (nr == 3) {
+ if (mface->v3 == 0) {
+ static int corner_indices[4] = {1, 2, 0, 3};
+
+ SWAP(unsigned int, mface->v1, mface->v2);
+ SWAP(unsigned int, mface->v2, mface->v3);
+
+ if (fdata)
+ CustomData_swap_corners(fdata, mfindex, corner_indices);
+ }
+ }
+ else if (nr == 4) {
+ if (mface->v3 == 0 || mface->v4 == 0) {
+ static int corner_indices[4] = {2, 3, 0, 1};
+
+ SWAP(unsigned int, mface->v1, mface->v3);
+ SWAP(unsigned int, mface->v2, mface->v4);
+
+ if (fdata)
+ CustomData_swap_corners(fdata, mfindex, corner_indices);
+ }
+ }
+
+ return nr;
}
Mesh *BKE_mesh_from_object(Object *ob)
{
- if (ob == NULL) return NULL;
- if (ob->type == OB_MESH) return ob->data;
- else return NULL;
+ if (ob == NULL)
+ return NULL;
+ if (ob->type == OB_MESH)
+ return ob->data;
+ else
+ return NULL;
}
void BKE_mesh_assign_object(Main *bmain, Object *ob, Mesh *me)
{
- Mesh *old = NULL;
+ Mesh *old = NULL;
- multires_force_update(ob);
+ multires_force_update(ob);
- if (ob == NULL) return;
+ if (ob == NULL)
+ return;
- if (ob->type == OB_MESH) {
- old = ob->data;
- if (old)
- id_us_min(&old->id);
- ob->data = me;
- id_us_plus((ID *)me);
- }
+ if (ob->type == OB_MESH) {
+ old = ob->data;
+ if (old)
+ id_us_min(&old->id);
+ ob->data = me;
+ id_us_plus((ID *)me);
+ }
- test_object_materials(bmain, ob, (ID *)me);
+ test_object_materials(bmain, ob, (ID *)me);
- test_object_modifiers(ob);
+ test_object_modifiers(ob);
}
void BKE_mesh_material_index_remove(Mesh *me, short index)
{
- MPoly *mp;
- MFace *mf;
- int i;
+ MPoly *mp;
+ MFace *mf;
+ int i;
- for (mp = me->mpoly, i = 0; i < me->totpoly; i++, mp++) {
- if (mp->mat_nr && mp->mat_nr >= index) {
- mp->mat_nr--;
- }
- }
+ for (mp = me->mpoly, i = 0; i < me->totpoly; i++, mp++) {
+ if (mp->mat_nr && mp->mat_nr >= index) {
+ mp->mat_nr--;
+ }
+ }
- for (mf = me->mface, i = 0; i < me->totface; i++, mf++) {
- if (mf->mat_nr && mf->mat_nr >= index) {
- mf->mat_nr--;
- }
- }
+ for (mf = me->mface, i = 0; i < me->totface; i++, mf++) {
+ if (mf->mat_nr && mf->mat_nr >= index) {
+ mf->mat_nr--;
+ }
+ }
}
void BKE_mesh_material_index_clear(Mesh *me)
{
- MPoly *mp;
- MFace *mf;
- int i;
+ MPoly *mp;
+ MFace *mf;
+ int i;
- for (mp = me->mpoly, i = 0; i < me->totpoly; i++, mp++) {
- mp->mat_nr = 0;
- }
+ for (mp = me->mpoly, i = 0; i < me->totpoly; i++, mp++) {
+ mp->mat_nr = 0;
+ }
- for (mf = me->mface, i = 0; i < me->totface; i++, mf++) {
- mf->mat_nr = 0;
- }
+ for (mf = me->mface, i = 0; i < me->totface; i++, mf++) {
+ mf->mat_nr = 0;
+ }
}
void BKE_mesh_material_remap(Mesh *me, const unsigned int *remap, unsigned int remap_len)
{
- const short remap_len_short = (short)remap_len;
+ const short remap_len_short = (short)remap_len;
#define MAT_NR_REMAP(n) \
- if (n < remap_len_short) { \
- BLI_assert(n >= 0 && remap[n] < remap_len_short); \
- n = remap[n]; \
- } ((void)0)
-
- if (me->edit_mesh) {
- BMEditMesh *em = me->edit_mesh;
- BMIter iter;
- BMFace *efa;
-
- BM_ITER_MESH(efa, &iter, em->bm, BM_FACES_OF_MESH) {
- MAT_NR_REMAP(efa->mat_nr);
- }
- }
- else {
- int i;
- for (i = 0; i < me->totpoly; i++) {
- MAT_NR_REMAP(me->mpoly[i].mat_nr);
- }
- }
+ if (n < remap_len_short) { \
+ BLI_assert(n >= 0 && remap[n] < remap_len_short); \
+ n = remap[n]; \
+ } \
+ ((void)0)
+
+ if (me->edit_mesh) {
+ BMEditMesh *em = me->edit_mesh;
+ BMIter iter;
+ BMFace *efa;
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ MAT_NR_REMAP(efa->mat_nr);
+ }
+ }
+ else {
+ int i;
+ for (i = 0; i < me->totpoly; i++) {
+ MAT_NR_REMAP(me->mpoly[i].mat_nr);
+ }
+ }
#undef MAT_NR_REMAP
-
}
void BKE_mesh_smooth_flag_set(Object *meshOb, int enableSmooth)
{
- Mesh *me = meshOb->data;
- int i;
+ Mesh *me = meshOb->data;
+ int i;
- for (i = 0; i < me->totpoly; i++) {
- MPoly *mp = &me->mpoly[i];
+ for (i = 0; i < me->totpoly; i++) {
+ MPoly *mp = &me->mpoly[i];
- if (enableSmooth) {
- mp->flag |= ME_SMOOTH;
- }
- else {
- mp->flag &= ~ME_SMOOTH;
- }
- }
+ if (enableSmooth) {
+ mp->flag |= ME_SMOOTH;
+ }
+ else {
+ mp->flag &= ~ME_SMOOTH;
+ }
+ }
- for (i = 0; i < me->totface; i++) {
- MFace *mf = &me->mface[i];
+ for (i = 0; i < me->totface; i++) {
+ MFace *mf = &me->mface[i];
- if (enableSmooth) {
- mf->flag |= ME_SMOOTH;
- }
- else {
- mf->flag &= ~ME_SMOOTH;
- }
- }
+ if (enableSmooth) {
+ mf->flag |= ME_SMOOTH;
+ }
+ else {
+ mf->flag &= ~ME_SMOOTH;
+ }
+ }
}
/**
@@ -1187,31 +1203,30 @@ void BKE_mesh_smooth_flag_set(Object *meshOb, int enableSmooth)
*/
float (*BKE_mesh_vertexCos_get(const Mesh *me, int *r_verts_len))[3]
{
- int i, verts_len = me->totvert;
- float (*cos)[3] = MEM_malloc_arrayN(verts_len, sizeof(*cos), "vertexcos1");
+ int i, verts_len = me->totvert;
+ float(*cos)[3] = MEM_malloc_arrayN(verts_len, sizeof(*cos), "vertexcos1");
- if (r_verts_len) *r_verts_len = verts_len;
- for (i = 0; i < verts_len; i++)
- copy_v3_v3(cos[i], me->mvert[i].co);
+ if (r_verts_len)
+ *r_verts_len = verts_len;
+ for (i = 0; i < verts_len; i++)
+ copy_v3_v3(cos[i], me->mvert[i].co);
- return cos;
+ return cos;
}
/**
* Find the index of the loop in 'poly' which references vertex,
* returns -1 if not found
*/
-int poly_find_loop_from_vert(
- const MPoly *poly, const MLoop *loopstart,
- unsigned vert)
+int poly_find_loop_from_vert(const MPoly *poly, const MLoop *loopstart, unsigned vert)
{
- int j;
- for (j = 0; j < poly->totloop; j++, loopstart++) {
- if (loopstart->v == vert)
- return j;
- }
+ int j;
+ for (j = 0; j < poly->totloop; j++, loopstart++) {
+ if (loopstart->v == vert)
+ return j;
+ }
- return -1;
+ return -1;
}
/**
@@ -1219,23 +1234,20 @@ int poly_find_loop_from_vert(
* vertex. Returns the index of the loop matching vertex, or -1 if the
* vertex is not in \a poly
*/
-int poly_get_adj_loops_from_vert(
- const MPoly *poly,
- const MLoop *mloop, unsigned int vert,
- unsigned int r_adj[2])
+int poly_get_adj_loops_from_vert(const MPoly *poly,
+ const MLoop *mloop,
+ unsigned int vert,
+ unsigned int r_adj[2])
{
- int corner = poly_find_loop_from_vert(
- poly,
- &mloop[poly->loopstart],
- vert);
+ int corner = poly_find_loop_from_vert(poly, &mloop[poly->loopstart], vert);
- if (corner != -1) {
- /* vertex was found */
- r_adj[0] = ME_POLY_LOOP_PREV(mloop, poly, corner)->v;
- r_adj[1] = ME_POLY_LOOP_NEXT(mloop, poly, corner)->v;
- }
+ if (corner != -1) {
+ /* vertex was found */
+ r_adj[0] = ME_POLY_LOOP_PREV(mloop, poly, corner)->v;
+ r_adj[1] = ME_POLY_LOOP_NEXT(mloop, poly, corner)->v;
+ }
- return corner;
+ return corner;
}
/**
@@ -1244,12 +1256,12 @@ int poly_get_adj_loops_from_vert(
*/
int BKE_mesh_edge_other_vert(const MEdge *e, int v)
{
- if (e->v1 == v)
- return e->v2;
- else if (e->v2 == v)
- return e->v1;
- else
- return -1;
+ if (e->v1 == v)
+ return e->v2;
+ else if (e->v2 == v)
+ return e->v1;
+ else
+ return -1;
}
/**
@@ -1257,224 +1269,222 @@ int BKE_mesh_edge_other_vert(const MEdge *e, int v)
*/
void BKE_mesh_looptri_get_real_edges(const Mesh *mesh, const MLoopTri *looptri, int r_edges[3])
{
- for (int i = 2, i_next = 0; i_next < 3; i = i_next++) {
- const MLoop *l1 = &mesh->mloop[looptri->tri[i]], *l2 = &mesh->mloop[looptri->tri[i_next]];
- const MEdge *e = &mesh->medge[l1->e];
+ for (int i = 2, i_next = 0; i_next < 3; i = i_next++) {
+ const MLoop *l1 = &mesh->mloop[looptri->tri[i]], *l2 = &mesh->mloop[looptri->tri[i_next]];
+ const MEdge *e = &mesh->medge[l1->e];
- bool is_real = (l1->v == e->v1 && l2->v == e->v2) || (l1->v == e->v2 && l2->v == e->v1);
+ bool is_real = (l1->v == e->v1 && l2->v == e->v2) || (l1->v == e->v2 && l2->v == e->v1);
- r_edges[i] = is_real ? l1->e : -1;
- }
+ r_edges[i] = is_real ? l1->e : -1;
+ }
}
/* basic vertex data functions */
bool BKE_mesh_minmax(const Mesh *me, float r_min[3], float r_max[3])
{
- int i = me->totvert;
- MVert *mvert;
- for (mvert = me->mvert; i--; mvert++) {
- minmax_v3v3_v3(r_min, r_max, mvert->co);
- }
+ int i = me->totvert;
+ MVert *mvert;
+ for (mvert = me->mvert; i--; mvert++) {
+ minmax_v3v3_v3(r_min, r_max, mvert->co);
+ }
- return (me->totvert != 0);
+ return (me->totvert != 0);
}
void BKE_mesh_transform(Mesh *me, float mat[4][4], bool do_keys)
{
- int i;
- MVert *mvert = me->mvert;
- float (*lnors)[3] = CustomData_get_layer(&me->ldata, CD_NORMAL);
+ int i;
+ MVert *mvert = me->mvert;
+ float(*lnors)[3] = CustomData_get_layer(&me->ldata, CD_NORMAL);
- for (i = 0; i < me->totvert; i++, mvert++)
- mul_m4_v3(mat, mvert->co);
+ for (i = 0; i < me->totvert; i++, mvert++)
+ mul_m4_v3(mat, mvert->co);
- if (do_keys && me->key) {
- KeyBlock *kb;
- for (kb = me->key->block.first; kb; kb = kb->next) {
- float *fp = kb->data;
- for (i = kb->totelem; i--; fp += 3) {
- mul_m4_v3(mat, fp);
- }
- }
- }
+ if (do_keys && me->key) {
+ KeyBlock *kb;
+ for (kb = me->key->block.first; kb; kb = kb->next) {
+ float *fp = kb->data;
+ for (i = kb->totelem; i--; fp += 3) {
+ mul_m4_v3(mat, fp);
+ }
+ }
+ }
- /* don't update normals, caller can do this explicitly.
- * We do update loop normals though, those may not be auto-generated (see e.g. STL import script)! */
- if (lnors) {
- float m3[3][3];
+ /* don't update normals, caller can do this explicitly.
+ * We do update loop normals though, those may not be auto-generated (see e.g. STL import script)! */
+ if (lnors) {
+ float m3[3][3];
- copy_m3_m4(m3, mat);
- normalize_m3(m3);
- for (i = 0; i < me->totloop; i++, lnors++) {
- mul_m3_v3(m3, *lnors);
- }
- }
+ copy_m3_m4(m3, mat);
+ normalize_m3(m3);
+ for (i = 0; i < me->totloop; i++, lnors++) {
+ mul_m3_v3(m3, *lnors);
+ }
+ }
}
void BKE_mesh_translate(Mesh *me, const float offset[3], const bool do_keys)
{
- int i = me->totvert;
- MVert *mvert;
- for (mvert = me->mvert; i--; mvert++) {
- add_v3_v3(mvert->co, offset);
- }
+ int i = me->totvert;
+ MVert *mvert;
+ for (mvert = me->mvert; i--; mvert++) {
+ add_v3_v3(mvert->co, offset);
+ }
- if (do_keys && me->key) {
- KeyBlock *kb;
- for (kb = me->key->block.first; kb; kb = kb->next) {
- float *fp = kb->data;
- for (i = kb->totelem; i--; fp += 3) {
- add_v3_v3(fp, offset);
- }
- }
- }
+ if (do_keys && me->key) {
+ KeyBlock *kb;
+ for (kb = me->key->block.first; kb; kb = kb->next) {
+ float *fp = kb->data;
+ for (i = kb->totelem; i--; fp += 3) {
+ add_v3_v3(fp, offset);
+ }
+ }
+ }
}
void BKE_mesh_ensure_navmesh(Mesh *me)
{
- if (!CustomData_has_layer(&me->pdata, CD_RECAST)) {
- int i;
- int polys_len = me->totpoly;
- int *recastData;
- recastData = (int *)MEM_malloc_arrayN(polys_len, sizeof(int), __func__);
- for (i = 0; i < polys_len; i++) {
- recastData[i] = i + 1;
- }
- CustomData_add_layer_named(&me->pdata, CD_RECAST, CD_ASSIGN, recastData, polys_len, "recastData");
- }
+ if (!CustomData_has_layer(&me->pdata, CD_RECAST)) {
+ int i;
+ int polys_len = me->totpoly;
+ int *recastData;
+ recastData = (int *)MEM_malloc_arrayN(polys_len, sizeof(int), __func__);
+ for (i = 0; i < polys_len; i++) {
+ recastData[i] = i + 1;
+ }
+ CustomData_add_layer_named(
+ &me->pdata, CD_RECAST, CD_ASSIGN, recastData, polys_len, "recastData");
+ }
}
void BKE_mesh_tessface_calc(Mesh *mesh)
{
- mesh->totface = BKE_mesh_recalc_tessellation(
- &mesh->fdata, &mesh->ldata, &mesh->pdata,
- mesh->mvert,
- mesh->totface, mesh->totloop, mesh->totpoly,
- /* calc normals right after, don't copy from polys here */
- false);
+ mesh->totface = BKE_mesh_recalc_tessellation(
+ &mesh->fdata,
+ &mesh->ldata,
+ &mesh->pdata,
+ mesh->mvert,
+ mesh->totface,
+ mesh->totloop,
+ mesh->totpoly,
+ /* calc normals right after, don't copy from polys here */
+ false);
- BKE_mesh_update_customdata_pointers(mesh, true);
+ BKE_mesh_update_customdata_pointers(mesh, true);
}
void BKE_mesh_tessface_ensure(Mesh *mesh)
{
- if (mesh->totpoly && mesh->totface == 0) {
- BKE_mesh_tessface_calc(mesh);
- }
+ if (mesh->totpoly && mesh->totface == 0) {
+ BKE_mesh_tessface_calc(mesh);
+ }
}
void BKE_mesh_tessface_clear(Mesh *mesh)
{
- mesh_tessface_clear_intern(mesh, true);
+ mesh_tessface_clear_intern(mesh, true);
}
void BKE_mesh_do_versions_cd_flag_init(Mesh *mesh)
{
- if (UNLIKELY(mesh->cd_flag)) {
- return;
- }
- else {
- MVert *mv;
- MEdge *med;
- int i;
-
- for (mv = mesh->mvert, i = 0; i < mesh->totvert; mv++, i++) {
- if (mv->bweight != 0) {
- mesh->cd_flag |= ME_CDFLAG_VERT_BWEIGHT;
- break;
- }
- }
-
- for (med = mesh->medge, i = 0; i < mesh->totedge; med++, i++) {
- if (med->bweight != 0) {
- mesh->cd_flag |= ME_CDFLAG_EDGE_BWEIGHT;
- if (mesh->cd_flag & ME_CDFLAG_EDGE_CREASE) {
- break;
- }
- }
- if (med->crease != 0) {
- mesh->cd_flag |= ME_CDFLAG_EDGE_CREASE;
- if (mesh->cd_flag & ME_CDFLAG_EDGE_BWEIGHT) {
- break;
- }
- }
- }
-
- }
+ if (UNLIKELY(mesh->cd_flag)) {
+ return;
+ }
+ else {
+ MVert *mv;
+ MEdge *med;
+ int i;
+
+ for (mv = mesh->mvert, i = 0; i < mesh->totvert; mv++, i++) {
+ if (mv->bweight != 0) {
+ mesh->cd_flag |= ME_CDFLAG_VERT_BWEIGHT;
+ break;
+ }
+ }
+
+ for (med = mesh->medge, i = 0; i < mesh->totedge; med++, i++) {
+ if (med->bweight != 0) {
+ mesh->cd_flag |= ME_CDFLAG_EDGE_BWEIGHT;
+ if (mesh->cd_flag & ME_CDFLAG_EDGE_CREASE) {
+ break;
+ }
+ }
+ if (med->crease != 0) {
+ mesh->cd_flag |= ME_CDFLAG_EDGE_CREASE;
+ if (mesh->cd_flag & ME_CDFLAG_EDGE_BWEIGHT) {
+ break;
+ }
+ }
+ }
+ }
}
-
/* -------------------------------------------------------------------- */
/* MSelect functions (currently used in weight paint mode) */
void BKE_mesh_mselect_clear(Mesh *me)
{
- if (me->mselect) {
- MEM_freeN(me->mselect);
- me->mselect = NULL;
- }
- me->totselect = 0;
+ if (me->mselect) {
+ MEM_freeN(me->mselect);
+ me->mselect = NULL;
+ }
+ me->totselect = 0;
}
void BKE_mesh_mselect_validate(Mesh *me)
{
- MSelect *mselect_src, *mselect_dst;
- int i_src, i_dst;
-
- if (me->totselect == 0)
- return;
-
- mselect_src = me->mselect;
- mselect_dst = MEM_malloc_arrayN((me->totselect), sizeof(MSelect), "Mesh selection history");
-
- for (i_src = 0, i_dst = 0; i_src < me->totselect; i_src++) {
- int index = mselect_src[i_src].index;
- switch (mselect_src[i_src].type) {
- case ME_VSEL:
- {
- if (me->mvert[index].flag & SELECT) {
- mselect_dst[i_dst] = mselect_src[i_src];
- i_dst++;
- }
- break;
- }
- case ME_ESEL:
- {
- if (me->medge[index].flag & SELECT) {
- mselect_dst[i_dst] = mselect_src[i_src];
- i_dst++;
- }
- break;
- }
- case ME_FSEL:
- {
- if (me->mpoly[index].flag & SELECT) {
- mselect_dst[i_dst] = mselect_src[i_src];
- i_dst++;
- }
- break;
- }
- default:
- {
- BLI_assert(0);
- break;
- }
- }
- }
-
- MEM_freeN(mselect_src);
-
- if (i_dst == 0) {
- MEM_freeN(mselect_dst);
- mselect_dst = NULL;
- }
- else if (i_dst != me->totselect) {
- mselect_dst = MEM_reallocN(mselect_dst, sizeof(MSelect) * i_dst);
- }
-
- me->totselect = i_dst;
- me->mselect = mselect_dst;
-
+ MSelect *mselect_src, *mselect_dst;
+ int i_src, i_dst;
+
+ if (me->totselect == 0)
+ return;
+
+ mselect_src = me->mselect;
+ mselect_dst = MEM_malloc_arrayN((me->totselect), sizeof(MSelect), "Mesh selection history");
+
+ for (i_src = 0, i_dst = 0; i_src < me->totselect; i_src++) {
+ int index = mselect_src[i_src].index;
+ switch (mselect_src[i_src].type) {
+ case ME_VSEL: {
+ if (me->mvert[index].flag & SELECT) {
+ mselect_dst[i_dst] = mselect_src[i_src];
+ i_dst++;
+ }
+ break;
+ }
+ case ME_ESEL: {
+ if (me->medge[index].flag & SELECT) {
+ mselect_dst[i_dst] = mselect_src[i_src];
+ i_dst++;
+ }
+ break;
+ }
+ case ME_FSEL: {
+ if (me->mpoly[index].flag & SELECT) {
+ mselect_dst[i_dst] = mselect_src[i_src];
+ i_dst++;
+ }
+ break;
+ }
+ default: {
+ BLI_assert(0);
+ break;
+ }
+ }
+ }
+
+ MEM_freeN(mselect_src);
+
+ if (i_dst == 0) {
+ MEM_freeN(mselect_dst);
+ mselect_dst = NULL;
+ }
+ else if (i_dst != me->totselect) {
+ mselect_dst = MEM_reallocN(mselect_dst, sizeof(MSelect) * i_dst);
+ }
+
+ me->totselect = i_dst;
+ me->mselect = mselect_dst;
}
/**
@@ -1482,19 +1492,17 @@ void BKE_mesh_mselect_validate(Mesh *me)
*/
int BKE_mesh_mselect_find(Mesh *me, int index, int type)
{
- int i;
+ int i;
- BLI_assert(ELEM(type, ME_VSEL, ME_ESEL, ME_FSEL));
+ BLI_assert(ELEM(type, ME_VSEL, ME_ESEL, ME_FSEL));
- for (i = 0; i < me->totselect; i++) {
- if ((me->mselect[i].index == index) &&
- (me->mselect[i].type == type))
- {
- return i;
- }
- }
+ for (i = 0; i < me->totselect; i++) {
+ if ((me->mselect[i].index == index) && (me->mselect[i].type == type)) {
+ return i;
+ }
+ }
- return -1;
+ return -1;
}
/**
@@ -1502,77 +1510,76 @@ int BKE_mesh_mselect_find(Mesh *me, int index, int type)
*/
int BKE_mesh_mselect_active_get(Mesh *me, int type)
{
- BLI_assert(ELEM(type, ME_VSEL, ME_ESEL, ME_FSEL));
+ BLI_assert(ELEM(type, ME_VSEL, ME_ESEL, ME_FSEL));
- if (me->totselect) {
- if (me->mselect[me->totselect - 1].type == type) {
- return me->mselect[me->totselect - 1].index;
- }
- }
- return -1;
+ if (me->totselect) {
+ if (me->mselect[me->totselect - 1].type == type) {
+ return me->mselect[me->totselect - 1].index;
+ }
+ }
+ return -1;
}
void BKE_mesh_mselect_active_set(Mesh *me, int index, int type)
{
- const int msel_index = BKE_mesh_mselect_find(me, index, type);
+ const int msel_index = BKE_mesh_mselect_find(me, index, type);
- if (msel_index == -1) {
- /* add to the end */
- me->mselect = MEM_reallocN(me->mselect, sizeof(MSelect) * (me->totselect + 1));
- me->mselect[me->totselect].index = index;
- me->mselect[me->totselect].type = type;
- me->totselect++;
- }
- else if (msel_index != me->totselect - 1) {
- /* move to the end */
- SWAP(MSelect, me->mselect[msel_index], me->mselect[me->totselect - 1]);
- }
+ if (msel_index == -1) {
+ /* add to the end */
+ me->mselect = MEM_reallocN(me->mselect, sizeof(MSelect) * (me->totselect + 1));
+ me->mselect[me->totselect].index = index;
+ me->mselect[me->totselect].type = type;
+ me->totselect++;
+ }
+ else if (msel_index != me->totselect - 1) {
+ /* move to the end */
+ SWAP(MSelect, me->mselect[msel_index], me->mselect[me->totselect - 1]);
+ }
- BLI_assert((me->mselect[me->totselect - 1].index == index) &&
- (me->mselect[me->totselect - 1].type == type));
+ BLI_assert((me->mselect[me->totselect - 1].index == index) &&
+ (me->mselect[me->totselect - 1].type == type));
}
void BKE_mesh_count_selected_items(const Mesh *mesh, int r_count[3])
{
- r_count[0] = r_count[1] = r_count[2] = 0;
- if (mesh->edit_mesh) {
- BMesh *bm = mesh->edit_mesh->bm;
- r_count[0] = bm->totvertsel;
- r_count[1] = bm->totedgesel;
- r_count[2] = bm->totfacesel;
- }
- /* We could support faces in paint modes. */
-
+ r_count[0] = r_count[1] = r_count[2] = 0;
+ if (mesh->edit_mesh) {
+ BMesh *bm = mesh->edit_mesh->bm;
+ r_count[0] = bm->totvertsel;
+ r_count[1] = bm->totedgesel;
+ r_count[2] = bm->totfacesel;
+ }
+ /* We could support faces in paint modes. */
}
void BKE_mesh_apply_vert_coords(Mesh *mesh, float (*vertCoords)[3])
{
- MVert *vert;
- int i;
+ MVert *vert;
+ int i;
- /* this will just return the pointer if it wasn't a referenced layer */
- vert = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MVERT, mesh->totvert);
- mesh->mvert = vert;
+ /* this will just return the pointer if it wasn't a referenced layer */
+ vert = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MVERT, mesh->totvert);
+ mesh->mvert = vert;
- for (i = 0; i < mesh->totvert; ++i, ++vert)
- copy_v3_v3(vert->co, vertCoords[i]);
+ for (i = 0; i < mesh->totvert; ++i, ++vert)
+ copy_v3_v3(vert->co, vertCoords[i]);
- mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
}
void BKE_mesh_apply_vert_normals(Mesh *mesh, short (*vertNormals)[3])
{
- MVert *vert;
- int i;
+ MVert *vert;
+ int i;
- /* this will just return the pointer if it wasn't a referenced layer */
- vert = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MVERT, mesh->totvert);
- mesh->mvert = vert;
+ /* this will just return the pointer if it wasn't a referenced layer */
+ vert = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MVERT, mesh->totvert);
+ mesh->mvert = vert;
- for (i = 0; i < mesh->totvert; ++i, ++vert)
- copy_v3_v3_short(vert->no, vertNormals[i]);
+ for (i = 0; i < mesh->totvert; ++i, ++vert)
+ copy_v3_v3_short(vert->no, vertNormals[i]);
- mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
+ mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
}
/**
@@ -1583,246 +1590,268 @@ void BKE_mesh_apply_vert_normals(Mesh *mesh, short (*vertNormals)[3])
*/
void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spacearr)
{
- float (*r_loopnors)[3];
- float (*polynors)[3];
- short (*clnors)[2] = NULL;
- bool free_polynors = false;
-
- /* Note that we enforce computing clnors when the clnor space array is requested by caller here.
- * However, we obviously only use the autosmooth angle threshold only in case autosmooth is enabled. */
- const bool use_split_normals = (r_lnors_spacearr != NULL) || ((mesh->flag & ME_AUTOSMOOTH) != 0);
- const float split_angle = (mesh->flag & ME_AUTOSMOOTH) != 0 ? mesh->smoothresh : (float)M_PI;
-
- if (CustomData_has_layer(&mesh->ldata, CD_NORMAL)) {
- r_loopnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
- memset(r_loopnors, 0, sizeof(float[3]) * mesh->totloop);
- }
- else {
- r_loopnors = CustomData_add_layer(&mesh->ldata, CD_NORMAL, CD_CALLOC, NULL, mesh->totloop);
- CustomData_set_layer_flag(&mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY);
- }
-
- /* may be NULL */
- clnors = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL);
-
- if (CustomData_has_layer(&mesh->pdata, CD_NORMAL)) {
- /* This assume that layer is always up to date, not sure this is the case (esp. in Edit mode?)... */
- polynors = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
- free_polynors = false;
- }
- else {
- polynors = MEM_malloc_arrayN(mesh->totpoly, sizeof(float[3]), __func__);
- BKE_mesh_calc_normals_poly(
- mesh->mvert, NULL, mesh->totvert,
- mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, polynors, false);
- free_polynors = true;
- }
-
- BKE_mesh_normals_loop_split(
- mesh->mvert, mesh->totvert, mesh->medge, mesh->totedge,
- mesh->mloop, r_loopnors, mesh->totloop, mesh->mpoly, (const float (*)[3])polynors, mesh->totpoly,
- use_split_normals, split_angle, r_lnors_spacearr, clnors, NULL);
-
- if (free_polynors) {
- MEM_freeN(polynors);
- }
-
- mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
+ float(*r_loopnors)[3];
+ float(*polynors)[3];
+ short(*clnors)[2] = NULL;
+ bool free_polynors = false;
+
+ /* Note that we enforce computing clnors when the clnor space array is requested by caller here.
+ * However, we obviously only use the autosmooth angle threshold only in case autosmooth is enabled. */
+ const bool use_split_normals = (r_lnors_spacearr != NULL) || ((mesh->flag & ME_AUTOSMOOTH) != 0);
+ const float split_angle = (mesh->flag & ME_AUTOSMOOTH) != 0 ? mesh->smoothresh : (float)M_PI;
+
+ if (CustomData_has_layer(&mesh->ldata, CD_NORMAL)) {
+ r_loopnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
+ memset(r_loopnors, 0, sizeof(float[3]) * mesh->totloop);
+ }
+ else {
+ r_loopnors = CustomData_add_layer(&mesh->ldata, CD_NORMAL, CD_CALLOC, NULL, mesh->totloop);
+ CustomData_set_layer_flag(&mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY);
+ }
+
+ /* may be NULL */
+ clnors = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL);
+
+ if (CustomData_has_layer(&mesh->pdata, CD_NORMAL)) {
+ /* This assume that layer is always up to date, not sure this is the case (esp. in Edit mode?)... */
+ polynors = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
+ free_polynors = false;
+ }
+ else {
+ polynors = MEM_malloc_arrayN(mesh->totpoly, sizeof(float[3]), __func__);
+ BKE_mesh_calc_normals_poly(mesh->mvert,
+ NULL,
+ mesh->totvert,
+ mesh->mloop,
+ mesh->mpoly,
+ mesh->totloop,
+ mesh->totpoly,
+ polynors,
+ false);
+ free_polynors = true;
+ }
+
+ BKE_mesh_normals_loop_split(mesh->mvert,
+ mesh->totvert,
+ mesh->medge,
+ mesh->totedge,
+ mesh->mloop,
+ r_loopnors,
+ mesh->totloop,
+ mesh->mpoly,
+ (const float(*)[3])polynors,
+ mesh->totpoly,
+ use_split_normals,
+ split_angle,
+ r_lnors_spacearr,
+ clnors,
+ NULL);
+
+ if (free_polynors) {
+ MEM_freeN(polynors);
+ }
+
+ mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
}
void BKE_mesh_calc_normals_split(Mesh *mesh)
{
- BKE_mesh_calc_normals_split_ex(mesh, NULL);
+ BKE_mesh_calc_normals_split_ex(mesh, NULL);
}
/* Split faces helper functions. */
typedef struct SplitFaceNewVert {
- struct SplitFaceNewVert *next;
- int new_index;
- int orig_index;
- float *vnor;
+ struct SplitFaceNewVert *next;
+ int new_index;
+ int orig_index;
+ float *vnor;
} SplitFaceNewVert;
typedef struct SplitFaceNewEdge {
- struct SplitFaceNewEdge *next;
- int new_index;
- int orig_index;
- int v1;
- int v2;
+ struct SplitFaceNewEdge *next;
+ int new_index;
+ int orig_index;
+ int v1;
+ int v2;
} SplitFaceNewEdge;
/* Detect needed new vertices, and update accordingly loops' vertex indices.
* WARNING! Leaves mesh in invalid state. */
-static int split_faces_prepare_new_verts(
- const Mesh *mesh, MLoopNorSpaceArray *lnors_spacearr, SplitFaceNewVert **new_verts, MemArena *memarena)
-{
- /* This is now mandatory, trying to do the job in simple way without that data is doomed to fail, even when only
- * dealing with smooth/flat faces one can find cases that no simple algorithm can handle properly. */
- BLI_assert(lnors_spacearr != NULL);
-
- const int loops_len = mesh->totloop;
- int verts_len = mesh->totvert;
- MVert *mvert = mesh->mvert;
- MLoop *mloop = mesh->mloop;
-
- BLI_bitmap *verts_used = BLI_BITMAP_NEW(verts_len, __func__);
- BLI_bitmap *done_loops = BLI_BITMAP_NEW(loops_len, __func__);
-
- MLoop *ml = mloop;
- MLoopNorSpace **lnor_space = lnors_spacearr->lspacearr;
-
- BLI_assert(lnors_spacearr->data_type == MLNOR_SPACEARR_LOOP_INDEX);
-
- for (int loop_idx = 0; loop_idx < loops_len; loop_idx++, ml++, lnor_space++) {
- if (!BLI_BITMAP_TEST(done_loops, loop_idx)) {
- const int vert_idx = ml->v;
- const bool vert_used = BLI_BITMAP_TEST_BOOL(verts_used, vert_idx);
- /* If vert is already used by another smooth fan, we need a new vert for this one. */
- const int new_vert_idx = vert_used ? verts_len++ : vert_idx;
-
- BLI_assert(*lnor_space);
-
- if ((*lnor_space)->flags & MLNOR_SPACE_IS_SINGLE) {
- /* Single loop in this fan... */
- BLI_assert(POINTER_AS_INT((*lnor_space)->loops) == loop_idx);
- BLI_BITMAP_ENABLE(done_loops, loop_idx);
- if (vert_used) {
- ml->v = new_vert_idx;
- }
- }
- else {
- for (LinkNode *lnode = (*lnor_space)->loops; lnode; lnode = lnode->next) {
- const int ml_fan_idx = POINTER_AS_INT(lnode->link);
- BLI_BITMAP_ENABLE(done_loops, ml_fan_idx);
- if (vert_used) {
- mloop[ml_fan_idx].v = new_vert_idx;
- }
- }
- }
-
- if (!vert_used) {
- BLI_BITMAP_ENABLE(verts_used, vert_idx);
- /* We need to update that vertex's normal here, we won't go over it again. */
- /* This is important! *DO NOT* set vnor to final computed lnor, vnor should always be defined to
- * 'automatic normal' value computed from its polys, not some custom normal.
- * Fortunately, that's the loop normal space's 'lnor' reference vector. ;) */
- normal_float_to_short_v3(mvert[vert_idx].no, (*lnor_space)->vec_lnor);
- }
- else {
- /* Add new vert to list. */
- SplitFaceNewVert *new_vert = BLI_memarena_alloc(memarena, sizeof(*new_vert));
- new_vert->orig_index = vert_idx;
- new_vert->new_index = new_vert_idx;
- new_vert->vnor = (*lnor_space)->vec_lnor; /* See note above. */
- new_vert->next = *new_verts;
- *new_verts = new_vert;
- }
- }
- }
-
- MEM_freeN(done_loops);
- MEM_freeN(verts_used);
-
- return verts_len - mesh->totvert;
+static int split_faces_prepare_new_verts(const Mesh *mesh,
+ MLoopNorSpaceArray *lnors_spacearr,
+ SplitFaceNewVert **new_verts,
+ MemArena *memarena)
+{
+ /* This is now mandatory, trying to do the job in simple way without that data is doomed to fail, even when only
+ * dealing with smooth/flat faces one can find cases that no simple algorithm can handle properly. */
+ BLI_assert(lnors_spacearr != NULL);
+
+ const int loops_len = mesh->totloop;
+ int verts_len = mesh->totvert;
+ MVert *mvert = mesh->mvert;
+ MLoop *mloop = mesh->mloop;
+
+ BLI_bitmap *verts_used = BLI_BITMAP_NEW(verts_len, __func__);
+ BLI_bitmap *done_loops = BLI_BITMAP_NEW(loops_len, __func__);
+
+ MLoop *ml = mloop;
+ MLoopNorSpace **lnor_space = lnors_spacearr->lspacearr;
+
+ BLI_assert(lnors_spacearr->data_type == MLNOR_SPACEARR_LOOP_INDEX);
+
+ for (int loop_idx = 0; loop_idx < loops_len; loop_idx++, ml++, lnor_space++) {
+ if (!BLI_BITMAP_TEST(done_loops, loop_idx)) {
+ const int vert_idx = ml->v;
+ const bool vert_used = BLI_BITMAP_TEST_BOOL(verts_used, vert_idx);
+ /* If vert is already used by another smooth fan, we need a new vert for this one. */
+ const int new_vert_idx = vert_used ? verts_len++ : vert_idx;
+
+ BLI_assert(*lnor_space);
+
+ if ((*lnor_space)->flags & MLNOR_SPACE_IS_SINGLE) {
+ /* Single loop in this fan... */
+ BLI_assert(POINTER_AS_INT((*lnor_space)->loops) == loop_idx);
+ BLI_BITMAP_ENABLE(done_loops, loop_idx);
+ if (vert_used) {
+ ml->v = new_vert_idx;
+ }
+ }
+ else {
+ for (LinkNode *lnode = (*lnor_space)->loops; lnode; lnode = lnode->next) {
+ const int ml_fan_idx = POINTER_AS_INT(lnode->link);
+ BLI_BITMAP_ENABLE(done_loops, ml_fan_idx);
+ if (vert_used) {
+ mloop[ml_fan_idx].v = new_vert_idx;
+ }
+ }
+ }
+
+ if (!vert_used) {
+ BLI_BITMAP_ENABLE(verts_used, vert_idx);
+ /* We need to update that vertex's normal here, we won't go over it again. */
+ /* This is important! *DO NOT* set vnor to final computed lnor, vnor should always be defined to
+ * 'automatic normal' value computed from its polys, not some custom normal.
+ * Fortunately, that's the loop normal space's 'lnor' reference vector. ;) */
+ normal_float_to_short_v3(mvert[vert_idx].no, (*lnor_space)->vec_lnor);
+ }
+ else {
+ /* Add new vert to list. */
+ SplitFaceNewVert *new_vert = BLI_memarena_alloc(memarena, sizeof(*new_vert));
+ new_vert->orig_index = vert_idx;
+ new_vert->new_index = new_vert_idx;
+ new_vert->vnor = (*lnor_space)->vec_lnor; /* See note above. */
+ new_vert->next = *new_verts;
+ *new_verts = new_vert;
+ }
+ }
+ }
+
+ MEM_freeN(done_loops);
+ MEM_freeN(verts_used);
+
+ return verts_len - mesh->totvert;
}
/* Detect needed new edges, and update accordingly loops' edge indices.
* WARNING! Leaves mesh in invalid state. */
-static int split_faces_prepare_new_edges(
- const Mesh *mesh, SplitFaceNewEdge **new_edges, MemArena *memarena)
-{
- const int num_polys = mesh->totpoly;
- int num_edges = mesh->totedge;
- MEdge *medge = mesh->medge;
- MLoop *mloop = mesh->mloop;
- const MPoly *mpoly = mesh->mpoly;
-
- BLI_bitmap *edges_used = BLI_BITMAP_NEW(num_edges, __func__);
- EdgeHash *edges_hash = BLI_edgehash_new_ex(__func__, num_edges);
-
- const MPoly *mp = mpoly;
- for (int poly_idx = 0; poly_idx < num_polys; poly_idx++, mp++) {
- MLoop *ml_prev = &mloop[mp->loopstart + mp->totloop - 1];
- MLoop *ml = &mloop[mp->loopstart];
- for (int loop_idx = 0; loop_idx < mp->totloop; loop_idx++, ml++) {
- void **eval;
- if (!BLI_edgehash_ensure_p(edges_hash, ml_prev->v, ml->v, &eval)) {
- const int edge_idx = ml_prev->e;
-
- /* That edge has not been encountered yet, define it. */
- if (BLI_BITMAP_TEST(edges_used, edge_idx)) {
- /* Original edge has already been used, we need to define a new one. */
- const int new_edge_idx = num_edges++;
- *eval = POINTER_FROM_INT(new_edge_idx);
- ml_prev->e = new_edge_idx;
-
- SplitFaceNewEdge *new_edge = BLI_memarena_alloc(memarena, sizeof(*new_edge));
- new_edge->orig_index = edge_idx;
- new_edge->new_index = new_edge_idx;
- new_edge->v1 = ml_prev->v;
- new_edge->v2 = ml->v;
- new_edge->next = *new_edges;
- *new_edges = new_edge;
- }
- else {
- /* We can re-use original edge. */
- medge[edge_idx].v1 = ml_prev->v;
- medge[edge_idx].v2 = ml->v;
- *eval = POINTER_FROM_INT(edge_idx);
- BLI_BITMAP_ENABLE(edges_used, edge_idx);
- }
- }
- else {
- /* Edge already known, just update loop's edge index. */
- ml_prev->e = POINTER_AS_INT(*eval);
- }
-
- ml_prev = ml;
- }
- }
-
- MEM_freeN(edges_used);
- BLI_edgehash_free(edges_hash, NULL);
-
- return num_edges - mesh->totedge;
+static int split_faces_prepare_new_edges(const Mesh *mesh,
+ SplitFaceNewEdge **new_edges,
+ MemArena *memarena)
+{
+ const int num_polys = mesh->totpoly;
+ int num_edges = mesh->totedge;
+ MEdge *medge = mesh->medge;
+ MLoop *mloop = mesh->mloop;
+ const MPoly *mpoly = mesh->mpoly;
+
+ BLI_bitmap *edges_used = BLI_BITMAP_NEW(num_edges, __func__);
+ EdgeHash *edges_hash = BLI_edgehash_new_ex(__func__, num_edges);
+
+ const MPoly *mp = mpoly;
+ for (int poly_idx = 0; poly_idx < num_polys; poly_idx++, mp++) {
+ MLoop *ml_prev = &mloop[mp->loopstart + mp->totloop - 1];
+ MLoop *ml = &mloop[mp->loopstart];
+ for (int loop_idx = 0; loop_idx < mp->totloop; loop_idx++, ml++) {
+ void **eval;
+ if (!BLI_edgehash_ensure_p(edges_hash, ml_prev->v, ml->v, &eval)) {
+ const int edge_idx = ml_prev->e;
+
+ /* That edge has not been encountered yet, define it. */
+ if (BLI_BITMAP_TEST(edges_used, edge_idx)) {
+ /* Original edge has already been used, we need to define a new one. */
+ const int new_edge_idx = num_edges++;
+ *eval = POINTER_FROM_INT(new_edge_idx);
+ ml_prev->e = new_edge_idx;
+
+ SplitFaceNewEdge *new_edge = BLI_memarena_alloc(memarena, sizeof(*new_edge));
+ new_edge->orig_index = edge_idx;
+ new_edge->new_index = new_edge_idx;
+ new_edge->v1 = ml_prev->v;
+ new_edge->v2 = ml->v;
+ new_edge->next = *new_edges;
+ *new_edges = new_edge;
+ }
+ else {
+ /* We can re-use original edge. */
+ medge[edge_idx].v1 = ml_prev->v;
+ medge[edge_idx].v2 = ml->v;
+ *eval = POINTER_FROM_INT(edge_idx);
+ BLI_BITMAP_ENABLE(edges_used, edge_idx);
+ }
+ }
+ else {
+ /* Edge already known, just update loop's edge index. */
+ ml_prev->e = POINTER_AS_INT(*eval);
+ }
+
+ ml_prev = ml;
+ }
+ }
+
+ MEM_freeN(edges_used);
+ BLI_edgehash_free(edges_hash, NULL);
+
+ return num_edges - mesh->totedge;
}
/* Perform actual split of vertices. */
-static void split_faces_split_new_verts(
- Mesh *mesh, SplitFaceNewVert *new_verts, const int num_new_verts)
+static void split_faces_split_new_verts(Mesh *mesh,
+ SplitFaceNewVert *new_verts,
+ const int num_new_verts)
{
- const int verts_len = mesh->totvert - num_new_verts;
- MVert *mvert = mesh->mvert;
+ const int verts_len = mesh->totvert - num_new_verts;
+ MVert *mvert = mesh->mvert;
- /* Remember new_verts is a single linklist, so its items are in reversed order... */
- MVert *new_mv = &mvert[mesh->totvert - 1];
- for (int i = mesh->totvert - 1; i >= verts_len ; i--, new_mv--, new_verts = new_verts->next) {
- BLI_assert(new_verts->new_index == i);
- BLI_assert(new_verts->new_index != new_verts->orig_index);
- CustomData_copy_data(&mesh->vdata, &mesh->vdata, new_verts->orig_index, i, 1);
- if (new_verts->vnor) {
- normal_float_to_short_v3(new_mv->no, new_verts->vnor);
- }
- }
+ /* Remember new_verts is a single linklist, so its items are in reversed order... */
+ MVert *new_mv = &mvert[mesh->totvert - 1];
+ for (int i = mesh->totvert - 1; i >= verts_len; i--, new_mv--, new_verts = new_verts->next) {
+ BLI_assert(new_verts->new_index == i);
+ BLI_assert(new_verts->new_index != new_verts->orig_index);
+ CustomData_copy_data(&mesh->vdata, &mesh->vdata, new_verts->orig_index, i, 1);
+ if (new_verts->vnor) {
+ normal_float_to_short_v3(new_mv->no, new_verts->vnor);
+ }
+ }
}
/* Perform actual split of edges. */
-static void split_faces_split_new_edges(
- Mesh *mesh, SplitFaceNewEdge *new_edges, const int num_new_edges)
+static void split_faces_split_new_edges(Mesh *mesh,
+ SplitFaceNewEdge *new_edges,
+ const int num_new_edges)
{
- const int num_edges = mesh->totedge - num_new_edges;
- MEdge *medge = mesh->medge;
+ const int num_edges = mesh->totedge - num_new_edges;
+ MEdge *medge = mesh->medge;
- /* Remember new_edges is a single linklist, so its items are in reversed order... */
- MEdge *new_med = &medge[mesh->totedge - 1];
- for (int i = mesh->totedge - 1; i >= num_edges ; i--, new_med--, new_edges = new_edges->next) {
- BLI_assert(new_edges->new_index == i);
- BLI_assert(new_edges->new_index != new_edges->orig_index);
- CustomData_copy_data(&mesh->edata, &mesh->edata, new_edges->orig_index, i, 1);
- new_med->v1 = new_edges->v1;
- new_med->v2 = new_edges->v2;
- }
+ /* Remember new_edges is a single linklist, so its items are in reversed order... */
+ MEdge *new_med = &medge[mesh->totedge - 1];
+ for (int i = mesh->totedge - 1; i >= num_edges; i--, new_med--, new_edges = new_edges->next) {
+ BLI_assert(new_edges->new_index == i);
+ BLI_assert(new_edges->new_index != new_edges->orig_index);
+ CustomData_copy_data(&mesh->edata, &mesh->edata, new_edges->orig_index, i, 1);
+ new_med->v1 = new_edges->v1;
+ new_med->v2 = new_edges->v2;
+ }
}
/* Split faces based on the edge angle and loop normals.
@@ -1833,76 +1862,75 @@ static void split_faces_split_new_edges(
*/
void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals)
{
- const int num_polys = mesh->totpoly;
-
- if (num_polys == 0) {
- return;
- }
- BKE_mesh_tessface_clear(mesh);
-
- MLoopNorSpaceArray lnors_spacearr = {NULL};
- /* Compute loop normals and loop normal spaces (a.k.a. smooth fans of faces around vertices). */
- BKE_mesh_calc_normals_split_ex(mesh, &lnors_spacearr);
- /* Stealing memarena from loop normals space array. */
- MemArena *memarena = lnors_spacearr.mem;
-
- SplitFaceNewVert *new_verts = NULL;
- SplitFaceNewEdge *new_edges = NULL;
-
- /* Detect loop normal spaces (a.k.a. smooth fans) that will need a new vert. */
- const int num_new_verts = split_faces_prepare_new_verts(mesh, &lnors_spacearr, &new_verts, memarena);
-
- if (num_new_verts > 0) {
- /* Reminder: beyond this point, there is no way out, mesh is in invalid state (due to early-reassignment of
- * loops' vertex and edge indices to new, to-be-created split ones). */
-
- const int num_new_edges = split_faces_prepare_new_edges(mesh, &new_edges, memarena);
- /* We can have to split a vertex without having to add a single new edge... */
- const bool do_edges = (num_new_edges > 0);
-
- /* Reallocate all vert and edge related data. */
- mesh->totvert += num_new_verts;
- CustomData_realloc(&mesh->vdata, mesh->totvert);
- if (do_edges) {
- mesh->totedge += num_new_edges;
- CustomData_realloc(&mesh->edata, mesh->totedge);
- }
- /* Update pointers to a newly allocated memory. */
- BKE_mesh_update_customdata_pointers(mesh, false);
-
- /* Perform actual split of vertices and edges. */
- split_faces_split_new_verts(mesh, new_verts, num_new_verts);
- if (do_edges) {
- split_faces_split_new_edges(mesh, new_edges, num_new_edges);
- }
- }
-
- /* Note: after this point mesh is expected to be valid again. */
-
- /* CD_NORMAL is expected to be temporary only. */
- if (free_loop_normals) {
- CustomData_free_layers(&mesh->ldata, CD_NORMAL, mesh->totloop);
- }
-
- /* Also frees new_verts/edges temp data, since we used its memarena to allocate them. */
- BKE_lnor_spacearr_free(&lnors_spacearr);
+ const int num_polys = mesh->totpoly;
+
+ if (num_polys == 0) {
+ return;
+ }
+ BKE_mesh_tessface_clear(mesh);
+
+ MLoopNorSpaceArray lnors_spacearr = {NULL};
+ /* Compute loop normals and loop normal spaces (a.k.a. smooth fans of faces around vertices). */
+ BKE_mesh_calc_normals_split_ex(mesh, &lnors_spacearr);
+ /* Stealing memarena from loop normals space array. */
+ MemArena *memarena = lnors_spacearr.mem;
+
+ SplitFaceNewVert *new_verts = NULL;
+ SplitFaceNewEdge *new_edges = NULL;
+
+ /* Detect loop normal spaces (a.k.a. smooth fans) that will need a new vert. */
+ const int num_new_verts = split_faces_prepare_new_verts(
+ mesh, &lnors_spacearr, &new_verts, memarena);
+
+ if (num_new_verts > 0) {
+ /* Reminder: beyond this point, there is no way out, mesh is in invalid state (due to early-reassignment of
+ * loops' vertex and edge indices to new, to-be-created split ones). */
+
+ const int num_new_edges = split_faces_prepare_new_edges(mesh, &new_edges, memarena);
+ /* We can have to split a vertex without having to add a single new edge... */
+ const bool do_edges = (num_new_edges > 0);
+
+ /* Reallocate all vert and edge related data. */
+ mesh->totvert += num_new_verts;
+ CustomData_realloc(&mesh->vdata, mesh->totvert);
+ if (do_edges) {
+ mesh->totedge += num_new_edges;
+ CustomData_realloc(&mesh->edata, mesh->totedge);
+ }
+ /* Update pointers to a newly allocated memory. */
+ BKE_mesh_update_customdata_pointers(mesh, false);
+
+ /* Perform actual split of vertices and edges. */
+ split_faces_split_new_verts(mesh, new_verts, num_new_verts);
+ if (do_edges) {
+ split_faces_split_new_edges(mesh, new_edges, num_new_edges);
+ }
+ }
+
+ /* Note: after this point mesh is expected to be valid again. */
+
+ /* CD_NORMAL is expected to be temporary only. */
+ if (free_loop_normals) {
+ CustomData_free_layers(&mesh->ldata, CD_NORMAL, mesh->totloop);
+ }
+
+ /* Also frees new_verts/edges temp data, since we used its memarena to allocate them. */
+ BKE_lnor_spacearr_free(&lnors_spacearr);
#ifdef VALIDATE_MESH
- BKE_mesh_validate(mesh, true, true);
+ BKE_mesh_validate(mesh, true, true);
#endif
}
/* **** Depsgraph evaluation **** */
-void BKE_mesh_eval_geometry(
- Depsgraph *depsgraph,
- Mesh *mesh)
-{
- DEG_debug_print_eval(depsgraph, __func__, mesh->id.name, mesh);
- if (mesh->bb == NULL || (mesh->bb->flag & BOUNDBOX_DIRTY)) {
- BKE_mesh_texspace_calc(mesh);
- }
- /* Clear autospace flag in evaluated mesh, so that texspace does not get recomputed when bbox is
- * (e.g. after modifiers, etc.) */
- mesh->texflag &= ~ME_AUTOSPACE;
+void BKE_mesh_eval_geometry(Depsgraph *depsgraph, Mesh *mesh)
+{
+ DEG_debug_print_eval(depsgraph, __func__, mesh->id.name, mesh);
+ if (mesh->bb == NULL || (mesh->bb->flag & BOUNDBOX_DIRTY)) {
+ BKE_mesh_texspace_calc(mesh);
+ }
+ /* Clear autospace flag in evaluated mesh, so that texspace does not get recomputed when bbox is
+ * (e.g. after modifiers, etc.) */
+ mesh->texflag &= ~ME_AUTOSPACE;
}
diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c
index 5be4b8524b1..6f96267ff55 100644
--- a/source/blender/blenkernel/intern/mesh_convert.c
+++ b/source/blender/blenkernel/intern/mesh_convert.c
@@ -59,7 +59,8 @@
// #undef VALIDATE_MESH
#ifdef VALIDATE_MESH
-# define ASSERT_IS_VALID_MESH(mesh) (BLI_assert((mesh == NULL) || (BKE_mesh_is_valid(mesh) == true)))
+# define ASSERT_IS_VALID_MESH(mesh) \
+ (BLI_assert((mesh == NULL) || (BKE_mesh_is_valid(mesh) == true)))
#else
# define ASSERT_IS_VALID_MESH(mesh)
#endif
@@ -68,163 +69,168 @@ static CLG_LogRef LOG = {"bke.mesh_convert"};
void BKE_mesh_from_metaball(ListBase *lb, Mesh *me)
{
- DispList *dl;
- MVert *mvert;
- MLoop *mloop, *allloop;
- MPoly *mpoly;
- const float *nors, *verts;
- int a, *index;
-
- dl = lb->first;
- if (dl == NULL) return;
-
- if (dl->type == DL_INDEX4) {
- mvert = CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, dl->nr);
- allloop = mloop = CustomData_add_layer(&me->ldata, CD_MLOOP, CD_CALLOC, NULL, dl->parts * 4);
- mpoly = CustomData_add_layer(&me->pdata, CD_MPOLY, CD_CALLOC, NULL, dl->parts);
- me->mvert = mvert;
- me->mloop = mloop;
- me->mpoly = mpoly;
- me->totvert = dl->nr;
- me->totpoly = dl->parts;
-
- a = dl->nr;
- nors = dl->nors;
- verts = dl->verts;
- while (a--) {
- copy_v3_v3(mvert->co, verts);
- normal_float_to_short_v3(mvert->no, nors);
- mvert++;
- nors += 3;
- verts += 3;
- }
-
- a = dl->parts;
- index = dl->index;
- while (a--) {
- int count = index[2] != index[3] ? 4 : 3;
-
- mloop[0].v = index[0];
- mloop[1].v = index[1];
- mloop[2].v = index[2];
- if (count == 4)
- mloop[3].v = index[3];
-
- mpoly->totloop = count;
- mpoly->loopstart = (int)(mloop - allloop);
- mpoly->flag = ME_SMOOTH;
-
-
- mpoly++;
- mloop += count;
- me->totloop += count;
- index += 4;
- }
-
- BKE_mesh_update_customdata_pointers(me, true);
-
- BKE_mesh_calc_normals(me);
-
- BKE_mesh_calc_edges(me, true, false);
- }
+ DispList *dl;
+ MVert *mvert;
+ MLoop *mloop, *allloop;
+ MPoly *mpoly;
+ const float *nors, *verts;
+ int a, *index;
+
+ dl = lb->first;
+ if (dl == NULL)
+ return;
+
+ if (dl->type == DL_INDEX4) {
+ mvert = CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, dl->nr);
+ allloop = mloop = CustomData_add_layer(&me->ldata, CD_MLOOP, CD_CALLOC, NULL, dl->parts * 4);
+ mpoly = CustomData_add_layer(&me->pdata, CD_MPOLY, CD_CALLOC, NULL, dl->parts);
+ me->mvert = mvert;
+ me->mloop = mloop;
+ me->mpoly = mpoly;
+ me->totvert = dl->nr;
+ me->totpoly = dl->parts;
+
+ a = dl->nr;
+ nors = dl->nors;
+ verts = dl->verts;
+ while (a--) {
+ copy_v3_v3(mvert->co, verts);
+ normal_float_to_short_v3(mvert->no, nors);
+ mvert++;
+ nors += 3;
+ verts += 3;
+ }
+
+ a = dl->parts;
+ index = dl->index;
+ while (a--) {
+ int count = index[2] != index[3] ? 4 : 3;
+
+ mloop[0].v = index[0];
+ mloop[1].v = index[1];
+ mloop[2].v = index[2];
+ if (count == 4)
+ mloop[3].v = index[3];
+
+ mpoly->totloop = count;
+ mpoly->loopstart = (int)(mloop - allloop);
+ mpoly->flag = ME_SMOOTH;
+
+ mpoly++;
+ mloop += count;
+ me->totloop += count;
+ index += 4;
+ }
+
+ BKE_mesh_update_customdata_pointers(me, true);
+
+ BKE_mesh_calc_normals(me);
+
+ BKE_mesh_calc_edges(me, true, false);
+ }
}
/**
* Specialized function to use when we _know_ existing edges don't overlap with poly edges.
*/
static void make_edges_mdata_extend(
- MEdge **r_alledge, int *r_totedge,
- const MPoly *mpoly, MLoop *mloop,
- const int totpoly)
+ MEdge **r_alledge, int *r_totedge, const MPoly *mpoly, MLoop *mloop, const int totpoly)
{
- int totedge = *r_totedge;
- int totedge_new;
- EdgeHash *eh;
- unsigned int eh_reserve;
- const MPoly *mp;
- int i;
+ int totedge = *r_totedge;
+ int totedge_new;
+ EdgeHash *eh;
+ unsigned int eh_reserve;
+ const MPoly *mp;
+ int i;
- eh_reserve = max_ii(totedge, BLI_EDGEHASH_SIZE_GUESS_FROM_POLYS(totpoly));
- eh = BLI_edgehash_new_ex(__func__, eh_reserve);
+ eh_reserve = max_ii(totedge, BLI_EDGEHASH_SIZE_GUESS_FROM_POLYS(totpoly));
+ eh = BLI_edgehash_new_ex(__func__, eh_reserve);
- for (i = 0, mp = mpoly; i < totpoly; i++, mp++) {
- BKE_mesh_poly_edgehash_insert(eh, mp, mloop + mp->loopstart);
- }
+ for (i = 0, mp = mpoly; i < totpoly; i++, mp++) {
+ BKE_mesh_poly_edgehash_insert(eh, mp, mloop + mp->loopstart);
+ }
- totedge_new = BLI_edgehash_len(eh);
+ totedge_new = BLI_edgehash_len(eh);
#ifdef DEBUG
- /* ensure that there's no overlap! */
- if (totedge_new) {
- MEdge *medge = *r_alledge;
- for (i = 0; i < totedge; i++, medge++) {
- BLI_assert(BLI_edgehash_haskey(eh, medge->v1, medge->v2) == false);
- }
- }
+ /* ensure that there's no overlap! */
+ if (totedge_new) {
+ MEdge *medge = *r_alledge;
+ for (i = 0; i < totedge; i++, medge++) {
+ BLI_assert(BLI_edgehash_haskey(eh, medge->v1, medge->v2) == false);
+ }
+ }
#endif
- if (totedge_new) {
- EdgeHashIterator *ehi;
- MEdge *medge;
- unsigned int e_index = totedge;
-
- *r_alledge = medge = (*r_alledge ? MEM_reallocN(*r_alledge, sizeof(MEdge) * (totedge + totedge_new)) :
- MEM_calloc_arrayN(totedge_new, sizeof(MEdge), __func__));
- medge += totedge;
-
- totedge += totedge_new;
-
- /* --- */
- for (ehi = BLI_edgehashIterator_new(eh);
- BLI_edgehashIterator_isDone(ehi) == false;
- BLI_edgehashIterator_step(ehi), ++medge, e_index++)
- {
- BLI_edgehashIterator_getKey(ehi, &medge->v1, &medge->v2);
- BLI_edgehashIterator_setValue(ehi, POINTER_FROM_UINT(e_index));
-
- medge->crease = medge->bweight = 0;
- medge->flag = ME_EDGEDRAW | ME_EDGERENDER;
- }
- BLI_edgehashIterator_free(ehi);
-
- *r_totedge = totedge;
-
-
- for (i = 0, mp = mpoly; i < totpoly; i++, mp++) {
- MLoop *l = &mloop[mp->loopstart];
- MLoop *l_prev = (l + (mp->totloop - 1));
- int j;
- for (j = 0; j < mp->totloop; j++, l++) {
- /* lookup hashed edge index */
- l_prev->e = POINTER_AS_UINT(BLI_edgehash_lookup(eh, l_prev->v, l->v));
- l_prev = l;
- }
- }
- }
-
- BLI_edgehash_free(eh, NULL);
+ if (totedge_new) {
+ EdgeHashIterator *ehi;
+ MEdge *medge;
+ unsigned int e_index = totedge;
+
+ *r_alledge = medge = (*r_alledge ?
+ MEM_reallocN(*r_alledge, sizeof(MEdge) * (totedge + totedge_new)) :
+ MEM_calloc_arrayN(totedge_new, sizeof(MEdge), __func__));
+ medge += totedge;
+
+ totedge += totedge_new;
+
+ /* --- */
+ for (ehi = BLI_edgehashIterator_new(eh); BLI_edgehashIterator_isDone(ehi) == false;
+ BLI_edgehashIterator_step(ehi), ++medge, e_index++) {
+ BLI_edgehashIterator_getKey(ehi, &medge->v1, &medge->v2);
+ BLI_edgehashIterator_setValue(ehi, POINTER_FROM_UINT(e_index));
+
+ medge->crease = medge->bweight = 0;
+ medge->flag = ME_EDGEDRAW | ME_EDGERENDER;
+ }
+ BLI_edgehashIterator_free(ehi);
+
+ *r_totedge = totedge;
+
+ for (i = 0, mp = mpoly; i < totpoly; i++, mp++) {
+ MLoop *l = &mloop[mp->loopstart];
+ MLoop *l_prev = (l + (mp->totloop - 1));
+ int j;
+ for (j = 0; j < mp->totloop; j++, l++) {
+ /* lookup hashed edge index */
+ l_prev->e = POINTER_AS_UINT(BLI_edgehash_lookup(eh, l_prev->v, l->v));
+ l_prev = l;
+ }
+ }
+ }
+
+ BLI_edgehash_free(eh, NULL);
}
-
/* Initialize mverts, medges and, faces for converting nurbs to mesh and derived mesh */
/* return non-zero on error */
-int BKE_mesh_nurbs_to_mdata(
- Object *ob, MVert **r_allvert, int *r_totvert,
- MEdge **r_alledge, int *r_totedge, MLoop **r_allloop, MPoly **r_allpoly,
- int *r_totloop, int *r_totpoly)
+int BKE_mesh_nurbs_to_mdata(Object *ob,
+ MVert **r_allvert,
+ int *r_totvert,
+ MEdge **r_alledge,
+ int *r_totedge,
+ MLoop **r_allloop,
+ MPoly **r_allpoly,
+ int *r_totloop,
+ int *r_totpoly)
{
- ListBase disp = {NULL, NULL};
-
- if (ob->runtime.curve_cache) {
- disp = ob->runtime.curve_cache->disp;
- }
-
- return BKE_mesh_nurbs_displist_to_mdata(
- ob, &disp,
- r_allvert, r_totvert,
- r_alledge, r_totedge,
- r_allloop, r_allpoly, NULL,
- r_totloop, r_totpoly);
+ ListBase disp = {NULL, NULL};
+
+ if (ob->runtime.curve_cache) {
+ disp = ob->runtime.curve_cache->disp;
+ }
+
+ return BKE_mesh_nurbs_displist_to_mdata(ob,
+ &disp,
+ r_allvert,
+ r_totvert,
+ r_alledge,
+ r_totedge,
+ r_allloop,
+ r_allpoly,
+ NULL,
+ r_totloop,
+ r_totpoly);
}
/* BMESH: this doesn't calculate all edges from polygons,
@@ -232,609 +238,646 @@ int BKE_mesh_nurbs_to_mdata(
/* Initialize mverts, medges and, faces for converting nurbs to mesh and derived mesh */
/* use specified dispbase */
-int BKE_mesh_nurbs_displist_to_mdata(
- Object *ob, const ListBase *dispbase,
- MVert **r_allvert, int *r_totvert,
- MEdge **r_alledge, int *r_totedge,
- MLoop **r_allloop, MPoly **r_allpoly,
- MLoopUV **r_alluv,
- int *r_totloop, int *r_totpoly)
+int BKE_mesh_nurbs_displist_to_mdata(Object *ob,
+ const ListBase *dispbase,
+ MVert **r_allvert,
+ int *r_totvert,
+ MEdge **r_alledge,
+ int *r_totedge,
+ MLoop **r_allloop,
+ MPoly **r_allpoly,
+ MLoopUV **r_alluv,
+ int *r_totloop,
+ int *r_totpoly)
{
- Curve *cu = ob->data;
- DispList *dl;
- MVert *mvert;
- MPoly *mpoly;
- MLoop *mloop;
- MLoopUV *mloopuv = NULL;
- MEdge *medge;
- const float *data;
- int a, b, ofs, vertcount, startvert, totvert = 0, totedge = 0, totloop = 0, totpoly = 0;
- int p1, p2, p3, p4, *index;
- const bool conv_polys = ((CU_DO_2DFILL(cu) == false) || /* 2d polys are filled with DL_INDEX3 displists */
- (ob->type == OB_SURF)); /* surf polys are never filled */
-
- /* count */
- dl = dispbase->first;
- while (dl) {
- if (dl->type == DL_SEGM) {
- totvert += dl->parts * dl->nr;
- totedge += dl->parts * (dl->nr - 1);
- }
- else if (dl->type == DL_POLY) {
- if (conv_polys) {
- totvert += dl->parts * dl->nr;
- totedge += dl->parts * dl->nr;
- }
- }
- else if (dl->type == DL_SURF) {
- int tot;
- totvert += dl->parts * dl->nr;
- tot = (dl->parts - 1 + ((dl->flag & DL_CYCL_V) == 2)) * (dl->nr - 1 + (dl->flag & DL_CYCL_U));
- totpoly += tot;
- totloop += tot * 4;
- }
- else if (dl->type == DL_INDEX3) {
- int tot;
- totvert += dl->nr;
- tot = dl->parts;
- totpoly += tot;
- totloop += tot * 3;
- }
- dl = dl->next;
- }
-
- if (totvert == 0) {
- /* error("can't convert"); */
- /* Make Sure you check ob->data is a curve */
- return -1;
- }
-
- *r_allvert = mvert = MEM_calloc_arrayN(totvert, sizeof(MVert), "nurbs_init mvert");
- *r_alledge = medge = MEM_calloc_arrayN(totedge, sizeof(MEdge), "nurbs_init medge");
- *r_allloop = mloop = MEM_calloc_arrayN(totpoly, 4 * sizeof(MLoop), "nurbs_init mloop"); // totloop
- *r_allpoly = mpoly = MEM_calloc_arrayN(totpoly, sizeof(MPoly), "nurbs_init mloop");
-
- if (r_alluv)
- *r_alluv = mloopuv = MEM_calloc_arrayN(totpoly, 4 * sizeof(MLoopUV), "nurbs_init mloopuv");
-
- /* verts and faces */
- vertcount = 0;
-
- dl = dispbase->first;
- while (dl) {
- const bool is_smooth = (dl->rt & CU_SMOOTH) != 0;
-
- if (dl->type == DL_SEGM) {
- startvert = vertcount;
- a = dl->parts * dl->nr;
- data = dl->verts;
- while (a--) {
- copy_v3_v3(mvert->co, data);
- data += 3;
- vertcount++;
- mvert++;
- }
-
- for (a = 0; a < dl->parts; a++) {
- ofs = a * dl->nr;
- for (b = 1; b < dl->nr; b++) {
- medge->v1 = startvert + ofs + b - 1;
- medge->v2 = startvert + ofs + b;
- medge->flag = ME_LOOSEEDGE | ME_EDGERENDER | ME_EDGEDRAW;
-
- medge++;
- }
- }
-
- }
- else if (dl->type == DL_POLY) {
- if (conv_polys) {
- startvert = vertcount;
- a = dl->parts * dl->nr;
- data = dl->verts;
- while (a--) {
- copy_v3_v3(mvert->co, data);
- data += 3;
- vertcount++;
- mvert++;
- }
-
- for (a = 0; a < dl->parts; a++) {
- ofs = a * dl->nr;
- for (b = 0; b < dl->nr; b++) {
- medge->v1 = startvert + ofs + b;
- if (b == dl->nr - 1) medge->v2 = startvert + ofs;
- else medge->v2 = startvert + ofs + b + 1;
- medge->flag = ME_LOOSEEDGE | ME_EDGERENDER | ME_EDGEDRAW;
- medge++;
- }
- }
- }
- }
- else if (dl->type == DL_INDEX3) {
- startvert = vertcount;
- a = dl->nr;
- data = dl->verts;
- while (a--) {
- copy_v3_v3(mvert->co, data);
- data += 3;
- vertcount++;
- mvert++;
- }
-
- a = dl->parts;
- index = dl->index;
- while (a--) {
- mloop[0].v = startvert + index[0];
- mloop[1].v = startvert + index[2];
- mloop[2].v = startvert + index[1];
- mpoly->loopstart = (int)(mloop - (*r_allloop));
- mpoly->totloop = 3;
- mpoly->mat_nr = dl->col;
-
- if (mloopuv) {
- int i;
-
- for (i = 0; i < 3; i++, mloopuv++) {
- mloopuv->uv[0] = (mloop[i].v - startvert) / (float)(dl->nr - 1);
- mloopuv->uv[1] = 0.0f;
- }
- }
-
- if (is_smooth) mpoly->flag |= ME_SMOOTH;
- mpoly++;
- mloop += 3;
- index += 3;
- }
- }
- else if (dl->type == DL_SURF) {
- startvert = vertcount;
- a = dl->parts * dl->nr;
- data = dl->verts;
- while (a--) {
- copy_v3_v3(mvert->co, data);
- data += 3;
- vertcount++;
- mvert++;
- }
-
- for (a = 0; a < dl->parts; a++) {
-
- if ( (dl->flag & DL_CYCL_V) == 0 && a == dl->parts - 1) break;
-
- if (dl->flag & DL_CYCL_U) { /* p2 -> p1 -> */
- p1 = startvert + dl->nr * a; /* p4 -> p3 -> */
- p2 = p1 + dl->nr - 1; /* -----> next row */
- p3 = p1 + dl->nr;
- p4 = p2 + dl->nr;
- b = 0;
- }
- else {
- p2 = startvert + dl->nr * a;
- p1 = p2 + 1;
- p4 = p2 + dl->nr;
- p3 = p1 + dl->nr;
- b = 1;
- }
- if ( (dl->flag & DL_CYCL_V) && a == dl->parts - 1) {
- p3 -= dl->parts * dl->nr;
- p4 -= dl->parts * dl->nr;
- }
-
- for (; b < dl->nr; b++) {
- mloop[0].v = p1;
- mloop[1].v = p3;
- mloop[2].v = p4;
- mloop[3].v = p2;
- mpoly->loopstart = (int)(mloop - (*r_allloop));
- mpoly->totloop = 4;
- mpoly->mat_nr = dl->col;
-
- if (mloopuv) {
- int orco_sizeu = dl->nr - 1;
- int orco_sizev = dl->parts - 1;
- int i;
-
- /* exception as handled in convertblender.c too */
- if (dl->flag & DL_CYCL_U) {
- orco_sizeu++;
- if (dl->flag & DL_CYCL_V)
- orco_sizev++;
- }
- else if (dl->flag & DL_CYCL_V) {
- orco_sizev++;
- }
-
- for (i = 0; i < 4; i++, mloopuv++) {
- /* find uv based on vertex index into grid array */
- int v = mloop[i].v - startvert;
-
- mloopuv->uv[0] = (v / dl->nr) / (float)orco_sizev;
- mloopuv->uv[1] = (v % dl->nr) / (float)orco_sizeu;
-
- /* cyclic correction */
- if ((i == 1 || i == 2) && mloopuv->uv[0] == 0.0f)
- mloopuv->uv[0] = 1.0f;
- if ((i == 0 || i == 1) && mloopuv->uv[1] == 0.0f)
- mloopuv->uv[1] = 1.0f;
- }
- }
-
- if (is_smooth) mpoly->flag |= ME_SMOOTH;
- mpoly++;
- mloop += 4;
-
- p4 = p3;
- p3++;
- p2 = p1;
- p1++;
- }
- }
- }
-
- dl = dl->next;
- }
-
- if (totpoly) {
- make_edges_mdata_extend(
- r_alledge, &totedge,
- *r_allpoly, *r_allloop, totpoly);
- }
-
- *r_totpoly = totpoly;
- *r_totloop = totloop;
- *r_totedge = totedge;
- *r_totvert = totvert;
-
- return 0;
+ Curve *cu = ob->data;
+ DispList *dl;
+ MVert *mvert;
+ MPoly *mpoly;
+ MLoop *mloop;
+ MLoopUV *mloopuv = NULL;
+ MEdge *medge;
+ const float *data;
+ int a, b, ofs, vertcount, startvert, totvert = 0, totedge = 0, totloop = 0, totpoly = 0;
+ int p1, p2, p3, p4, *index;
+ const bool conv_polys = ((CU_DO_2DFILL(cu) ==
+ false) || /* 2d polys are filled with DL_INDEX3 displists */
+ (ob->type == OB_SURF)); /* surf polys are never filled */
+
+ /* count */
+ dl = dispbase->first;
+ while (dl) {
+ if (dl->type == DL_SEGM) {
+ totvert += dl->parts * dl->nr;
+ totedge += dl->parts * (dl->nr - 1);
+ }
+ else if (dl->type == DL_POLY) {
+ if (conv_polys) {
+ totvert += dl->parts * dl->nr;
+ totedge += dl->parts * dl->nr;
+ }
+ }
+ else if (dl->type == DL_SURF) {
+ int tot;
+ totvert += dl->parts * dl->nr;
+ tot = (dl->parts - 1 + ((dl->flag & DL_CYCL_V) == 2)) *
+ (dl->nr - 1 + (dl->flag & DL_CYCL_U));
+ totpoly += tot;
+ totloop += tot * 4;
+ }
+ else if (dl->type == DL_INDEX3) {
+ int tot;
+ totvert += dl->nr;
+ tot = dl->parts;
+ totpoly += tot;
+ totloop += tot * 3;
+ }
+ dl = dl->next;
+ }
+
+ if (totvert == 0) {
+ /* error("can't convert"); */
+ /* Make Sure you check ob->data is a curve */
+ return -1;
+ }
+
+ *r_allvert = mvert = MEM_calloc_arrayN(totvert, sizeof(MVert), "nurbs_init mvert");
+ *r_alledge = medge = MEM_calloc_arrayN(totedge, sizeof(MEdge), "nurbs_init medge");
+ *r_allloop = mloop = MEM_calloc_arrayN(
+ totpoly, 4 * sizeof(MLoop), "nurbs_init mloop"); // totloop
+ *r_allpoly = mpoly = MEM_calloc_arrayN(totpoly, sizeof(MPoly), "nurbs_init mloop");
+
+ if (r_alluv)
+ *r_alluv = mloopuv = MEM_calloc_arrayN(totpoly, 4 * sizeof(MLoopUV), "nurbs_init mloopuv");
+
+ /* verts and faces */
+ vertcount = 0;
+
+ dl = dispbase->first;
+ while (dl) {
+ const bool is_smooth = (dl->rt & CU_SMOOTH) != 0;
+
+ if (dl->type == DL_SEGM) {
+ startvert = vertcount;
+ a = dl->parts * dl->nr;
+ data = dl->verts;
+ while (a--) {
+ copy_v3_v3(mvert->co, data);
+ data += 3;
+ vertcount++;
+ mvert++;
+ }
+
+ for (a = 0; a < dl->parts; a++) {
+ ofs = a * dl->nr;
+ for (b = 1; b < dl->nr; b++) {
+ medge->v1 = startvert + ofs + b - 1;
+ medge->v2 = startvert + ofs + b;
+ medge->flag = ME_LOOSEEDGE | ME_EDGERENDER | ME_EDGEDRAW;
+
+ medge++;
+ }
+ }
+ }
+ else if (dl->type == DL_POLY) {
+ if (conv_polys) {
+ startvert = vertcount;
+ a = dl->parts * dl->nr;
+ data = dl->verts;
+ while (a--) {
+ copy_v3_v3(mvert->co, data);
+ data += 3;
+ vertcount++;
+ mvert++;
+ }
+
+ for (a = 0; a < dl->parts; a++) {
+ ofs = a * dl->nr;
+ for (b = 0; b < dl->nr; b++) {
+ medge->v1 = startvert + ofs + b;
+ if (b == dl->nr - 1)
+ medge->v2 = startvert + ofs;
+ else
+ medge->v2 = startvert + ofs + b + 1;
+ medge->flag = ME_LOOSEEDGE | ME_EDGERENDER | ME_EDGEDRAW;
+ medge++;
+ }
+ }
+ }
+ }
+ else if (dl->type == DL_INDEX3) {
+ startvert = vertcount;
+ a = dl->nr;
+ data = dl->verts;
+ while (a--) {
+ copy_v3_v3(mvert->co, data);
+ data += 3;
+ vertcount++;
+ mvert++;
+ }
+
+ a = dl->parts;
+ index = dl->index;
+ while (a--) {
+ mloop[0].v = startvert + index[0];
+ mloop[1].v = startvert + index[2];
+ mloop[2].v = startvert + index[1];
+ mpoly->loopstart = (int)(mloop - (*r_allloop));
+ mpoly->totloop = 3;
+ mpoly->mat_nr = dl->col;
+
+ if (mloopuv) {
+ int i;
+
+ for (i = 0; i < 3; i++, mloopuv++) {
+ mloopuv->uv[0] = (mloop[i].v - startvert) / (float)(dl->nr - 1);
+ mloopuv->uv[1] = 0.0f;
+ }
+ }
+
+ if (is_smooth)
+ mpoly->flag |= ME_SMOOTH;
+ mpoly++;
+ mloop += 3;
+ index += 3;
+ }
+ }
+ else if (dl->type == DL_SURF) {
+ startvert = vertcount;
+ a = dl->parts * dl->nr;
+ data = dl->verts;
+ while (a--) {
+ copy_v3_v3(mvert->co, data);
+ data += 3;
+ vertcount++;
+ mvert++;
+ }
+
+ for (a = 0; a < dl->parts; a++) {
+
+ if ((dl->flag & DL_CYCL_V) == 0 && a == dl->parts - 1)
+ break;
+
+ if (dl->flag & DL_CYCL_U) { /* p2 -> p1 -> */
+ p1 = startvert + dl->nr * a; /* p4 -> p3 -> */
+ p2 = p1 + dl->nr - 1; /* -----> next row */
+ p3 = p1 + dl->nr;
+ p4 = p2 + dl->nr;
+ b = 0;
+ }
+ else {
+ p2 = startvert + dl->nr * a;
+ p1 = p2 + 1;
+ p4 = p2 + dl->nr;
+ p3 = p1 + dl->nr;
+ b = 1;
+ }
+ if ((dl->flag & DL_CYCL_V) && a == dl->parts - 1) {
+ p3 -= dl->parts * dl->nr;
+ p4 -= dl->parts * dl->nr;
+ }
+
+ for (; b < dl->nr; b++) {
+ mloop[0].v = p1;
+ mloop[1].v = p3;
+ mloop[2].v = p4;
+ mloop[3].v = p2;
+ mpoly->loopstart = (int)(mloop - (*r_allloop));
+ mpoly->totloop = 4;
+ mpoly->mat_nr = dl->col;
+
+ if (mloopuv) {
+ int orco_sizeu = dl->nr - 1;
+ int orco_sizev = dl->parts - 1;
+ int i;
+
+ /* exception as handled in convertblender.c too */
+ if (dl->flag & DL_CYCL_U) {
+ orco_sizeu++;
+ if (dl->flag & DL_CYCL_V)
+ orco_sizev++;
+ }
+ else if (dl->flag & DL_CYCL_V) {
+ orco_sizev++;
+ }
+
+ for (i = 0; i < 4; i++, mloopuv++) {
+ /* find uv based on vertex index into grid array */
+ int v = mloop[i].v - startvert;
+
+ mloopuv->uv[0] = (v / dl->nr) / (float)orco_sizev;
+ mloopuv->uv[1] = (v % dl->nr) / (float)orco_sizeu;
+
+ /* cyclic correction */
+ if ((i == 1 || i == 2) && mloopuv->uv[0] == 0.0f)
+ mloopuv->uv[0] = 1.0f;
+ if ((i == 0 || i == 1) && mloopuv->uv[1] == 0.0f)
+ mloopuv->uv[1] = 1.0f;
+ }
+ }
+
+ if (is_smooth)
+ mpoly->flag |= ME_SMOOTH;
+ mpoly++;
+ mloop += 4;
+
+ p4 = p3;
+ p3++;
+ p2 = p1;
+ p1++;
+ }
+ }
+ }
+
+ dl = dl->next;
+ }
+
+ if (totpoly) {
+ make_edges_mdata_extend(r_alledge, &totedge, *r_allpoly, *r_allloop, totpoly);
+ }
+
+ *r_totpoly = totpoly;
+ *r_totloop = totloop;
+ *r_totedge = totedge;
+ *r_totvert = totvert;
+
+ return 0;
}
Mesh *BKE_mesh_new_nomain_from_curve_displist(Object *ob, ListBase *dispbase)
{
- Curve *cu = ob->data;
- Mesh *mesh;
- MVert *allvert;
- MEdge *alledge;
- MLoop *allloop;
- MPoly *allpoly;
- MLoopUV *alluv = NULL;
- int totvert, totedge, totloop, totpoly;
- bool use_orco_uv = (cu->flag & CU_UV_ORCO) != 0;
-
- if (BKE_mesh_nurbs_displist_to_mdata(
- ob, dispbase, &allvert, &totvert, &alledge,
- &totedge, &allloop, &allpoly, (use_orco_uv) ? &alluv : NULL,
- &totloop, &totpoly) != 0)
- {
- /* Error initializing mdata. This often happens when curve is empty */
- return BKE_mesh_new_nomain(0, 0, 0, 0, 0);
- }
-
- mesh = BKE_mesh_new_nomain(totvert, totedge, 0, totloop, totpoly);
- mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
-
- memcpy(mesh->mvert, allvert, totvert * sizeof(MVert));
- memcpy(mesh->medge, alledge, totedge * sizeof(MEdge));
- memcpy(mesh->mloop, allloop, totloop * sizeof(MLoop));
- memcpy(mesh->mpoly, allpoly, totpoly * sizeof(MPoly));
-
- if (alluv) {
- const char *uvname = "Orco";
- CustomData_add_layer_named(&mesh->ldata, CD_MLOOPUV, CD_ASSIGN, alluv, totloop, uvname);
- }
-
- MEM_freeN(allvert);
- MEM_freeN(alledge);
- MEM_freeN(allloop);
- MEM_freeN(allpoly);
-
- return mesh;
+ Curve *cu = ob->data;
+ Mesh *mesh;
+ MVert *allvert;
+ MEdge *alledge;
+ MLoop *allloop;
+ MPoly *allpoly;
+ MLoopUV *alluv = NULL;
+ int totvert, totedge, totloop, totpoly;
+ bool use_orco_uv = (cu->flag & CU_UV_ORCO) != 0;
+
+ if (BKE_mesh_nurbs_displist_to_mdata(ob,
+ dispbase,
+ &allvert,
+ &totvert,
+ &alledge,
+ &totedge,
+ &allloop,
+ &allpoly,
+ (use_orco_uv) ? &alluv : NULL,
+ &totloop,
+ &totpoly) != 0) {
+ /* Error initializing mdata. This often happens when curve is empty */
+ return BKE_mesh_new_nomain(0, 0, 0, 0, 0);
+ }
+
+ mesh = BKE_mesh_new_nomain(totvert, totedge, 0, totloop, totpoly);
+ mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+
+ memcpy(mesh->mvert, allvert, totvert * sizeof(MVert));
+ memcpy(mesh->medge, alledge, totedge * sizeof(MEdge));
+ memcpy(mesh->mloop, allloop, totloop * sizeof(MLoop));
+ memcpy(mesh->mpoly, allpoly, totpoly * sizeof(MPoly));
+
+ if (alluv) {
+ const char *uvname = "Orco";
+ CustomData_add_layer_named(&mesh->ldata, CD_MLOOPUV, CD_ASSIGN, alluv, totloop, uvname);
+ }
+
+ MEM_freeN(allvert);
+ MEM_freeN(alledge);
+ MEM_freeN(allloop);
+ MEM_freeN(allpoly);
+
+ return mesh;
}
Mesh *BKE_mesh_new_nomain_from_curve(Object *ob)
{
- ListBase disp = {NULL, NULL};
+ ListBase disp = {NULL, NULL};
- if (ob->runtime.curve_cache) {
- disp = ob->runtime.curve_cache->disp;
- }
+ if (ob->runtime.curve_cache) {
+ disp = ob->runtime.curve_cache->disp;
+ }
- return BKE_mesh_new_nomain_from_curve_displist(ob, &disp);
+ return BKE_mesh_new_nomain_from_curve_displist(ob, &disp);
}
/* this may fail replacing ob->data, be sure to check ob->type */
-void BKE_mesh_from_nurbs_displist(
- Main *bmain, Object *ob, ListBase *dispbase, const bool use_orco_uv, const char *obdata_name, bool temporary)
+void BKE_mesh_from_nurbs_displist(Main *bmain,
+ Object *ob,
+ ListBase *dispbase,
+ const bool use_orco_uv,
+ const char *obdata_name,
+ bool temporary)
{
- Object *ob1;
- Mesh *me_eval = ob->runtime.mesh_eval;
- Mesh *me;
- Curve *cu;
- MVert *allvert = NULL;
- MEdge *alledge = NULL;
- MLoop *allloop = NULL;
- MLoopUV *alluv = NULL;
- MPoly *allpoly = NULL;
- int totvert, totedge, totloop, totpoly;
-
- cu = ob->data;
-
- if (me_eval == NULL) {
- if (BKE_mesh_nurbs_displist_to_mdata(
- ob, dispbase, &allvert, &totvert,
- &alledge, &totedge, &allloop,
- &allpoly, (use_orco_uv) ? &alluv : NULL,
- &totloop, &totpoly) != 0)
- {
- /* Error initializing */
- return;
- }
-
- /* make mesh */
- me = BKE_mesh_add(bmain, obdata_name);
- me->totvert = totvert;
- me->totedge = totedge;
- me->totloop = totloop;
- me->totpoly = totpoly;
-
- me->mvert = CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, allvert, me->totvert);
- me->medge = CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, alledge, me->totedge);
- me->mloop = CustomData_add_layer(&me->ldata, CD_MLOOP, CD_ASSIGN, allloop, me->totloop);
- me->mpoly = CustomData_add_layer(&me->pdata, CD_MPOLY, CD_ASSIGN, allpoly, me->totpoly);
-
- if (alluv) {
- const char *uvname = "Orco";
- me->mloopuv = CustomData_add_layer_named(&me->ldata, CD_MLOOPUV, CD_ASSIGN, alluv, me->totloop, uvname);
- }
-
- BKE_mesh_calc_normals(me);
- }
- else {
- me = BKE_mesh_add(bmain, obdata_name);
- ob->runtime.mesh_eval = NULL;
- BKE_mesh_nomain_to_mesh(me_eval, me, ob, &CD_MASK_MESH, true);
- }
-
- me->totcol = cu->totcol;
- me->mat = cu->mat;
-
- /* Copy evaluated texture space from curve to mesh.
- *
- * Note that we disable auto texture space feature since that will cause
- * texture space to evaluate differently for curve and mesh, since curve
- * uses CV to calculate bounding box, and mesh uses what is coming from
- * tessellated curve.
- */
- me->texflag = cu->texflag & ~CU_AUTOSPACE;
- copy_v3_v3(me->loc, cu->loc);
- copy_v3_v3(me->size, cu->size);
- copy_v3_v3(me->rot, cu->rot);
- BKE_mesh_texspace_calc(me);
-
- cu->mat = NULL;
- cu->totcol = 0;
-
- /* Do not decrement ob->data usercount here, it's done at end of func with BKE_id_free_us() call. */
- ob->data = me;
- ob->type = OB_MESH;
-
- /* other users */
- ob1 = bmain->objects.first;
- while (ob1) {
- if (ob1->data == cu) {
- ob1->type = OB_MESH;
-
- id_us_min((ID *)ob1->data);
- ob1->data = ob->data;
- id_us_plus((ID *)ob1->data);
- }
- ob1 = ob1->id.next;
- }
-
- if (temporary) {
- /* For temporary objects in BKE_mesh_new_from_object don't remap
- * the entire scene with associated depsgraph updates, which are
- * problematic for renderers exporting data. */
- BKE_id_free(NULL, cu);
- }
- else {
- BKE_id_free_us(bmain, cu);
- }
+ Object *ob1;
+ Mesh *me_eval = ob->runtime.mesh_eval;
+ Mesh *me;
+ Curve *cu;
+ MVert *allvert = NULL;
+ MEdge *alledge = NULL;
+ MLoop *allloop = NULL;
+ MLoopUV *alluv = NULL;
+ MPoly *allpoly = NULL;
+ int totvert, totedge, totloop, totpoly;
+
+ cu = ob->data;
+
+ if (me_eval == NULL) {
+ if (BKE_mesh_nurbs_displist_to_mdata(ob,
+ dispbase,
+ &allvert,
+ &totvert,
+ &alledge,
+ &totedge,
+ &allloop,
+ &allpoly,
+ (use_orco_uv) ? &alluv : NULL,
+ &totloop,
+ &totpoly) != 0) {
+ /* Error initializing */
+ return;
+ }
+
+ /* make mesh */
+ me = BKE_mesh_add(bmain, obdata_name);
+ me->totvert = totvert;
+ me->totedge = totedge;
+ me->totloop = totloop;
+ me->totpoly = totpoly;
+
+ me->mvert = CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, allvert, me->totvert);
+ me->medge = CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, alledge, me->totedge);
+ me->mloop = CustomData_add_layer(&me->ldata, CD_MLOOP, CD_ASSIGN, allloop, me->totloop);
+ me->mpoly = CustomData_add_layer(&me->pdata, CD_MPOLY, CD_ASSIGN, allpoly, me->totpoly);
+
+ if (alluv) {
+ const char *uvname = "Orco";
+ me->mloopuv = CustomData_add_layer_named(
+ &me->ldata, CD_MLOOPUV, CD_ASSIGN, alluv, me->totloop, uvname);
+ }
+
+ BKE_mesh_calc_normals(me);
+ }
+ else {
+ me = BKE_mesh_add(bmain, obdata_name);
+ ob->runtime.mesh_eval = NULL;
+ BKE_mesh_nomain_to_mesh(me_eval, me, ob, &CD_MASK_MESH, true);
+ }
+
+ me->totcol = cu->totcol;
+ me->mat = cu->mat;
+
+ /* Copy evaluated texture space from curve to mesh.
+ *
+ * Note that we disable auto texture space feature since that will cause
+ * texture space to evaluate differently for curve and mesh, since curve
+ * uses CV to calculate bounding box, and mesh uses what is coming from
+ * tessellated curve.
+ */
+ me->texflag = cu->texflag & ~CU_AUTOSPACE;
+ copy_v3_v3(me->loc, cu->loc);
+ copy_v3_v3(me->size, cu->size);
+ copy_v3_v3(me->rot, cu->rot);
+ BKE_mesh_texspace_calc(me);
+
+ cu->mat = NULL;
+ cu->totcol = 0;
+
+ /* Do not decrement ob->data usercount here, it's done at end of func with BKE_id_free_us() call. */
+ ob->data = me;
+ ob->type = OB_MESH;
+
+ /* other users */
+ ob1 = bmain->objects.first;
+ while (ob1) {
+ if (ob1->data == cu) {
+ ob1->type = OB_MESH;
+
+ id_us_min((ID *)ob1->data);
+ ob1->data = ob->data;
+ id_us_plus((ID *)ob1->data);
+ }
+ ob1 = ob1->id.next;
+ }
+
+ if (temporary) {
+ /* For temporary objects in BKE_mesh_new_from_object don't remap
+ * the entire scene with associated depsgraph updates, which are
+ * problematic for renderers exporting data. */
+ BKE_id_free(NULL, cu);
+ }
+ else {
+ BKE_id_free_us(bmain, cu);
+ }
}
void BKE_mesh_from_nurbs(Main *bmain, Object *ob)
{
- Curve *cu = (Curve *) ob->data;
- bool use_orco_uv = (cu->flag & CU_UV_ORCO) != 0;
- ListBase disp = {NULL, NULL};
+ Curve *cu = (Curve *)ob->data;
+ bool use_orco_uv = (cu->flag & CU_UV_ORCO) != 0;
+ ListBase disp = {NULL, NULL};
- if (ob->runtime.curve_cache) {
- disp = ob->runtime.curve_cache->disp;
- }
+ if (ob->runtime.curve_cache) {
+ disp = ob->runtime.curve_cache->disp;
+ }
- BKE_mesh_from_nurbs_displist(bmain, ob, &disp, use_orco_uv, cu->id.name, false);
+ BKE_mesh_from_nurbs_displist(bmain, ob, &disp, use_orco_uv, cu->id.name, false);
}
typedef struct EdgeLink {
- struct EdgeLink *next, *prev;
- void *edge;
+ struct EdgeLink *next, *prev;
+ void *edge;
} EdgeLink;
typedef struct VertLink {
- Link *next, *prev;
- unsigned int index;
+ Link *next, *prev;
+ unsigned int index;
} VertLink;
static void prependPolyLineVert(ListBase *lb, unsigned int index)
{
- VertLink *vl = MEM_callocN(sizeof(VertLink), "VertLink");
- vl->index = index;
- BLI_addhead(lb, vl);
+ VertLink *vl = MEM_callocN(sizeof(VertLink), "VertLink");
+ vl->index = index;
+ BLI_addhead(lb, vl);
}
static void appendPolyLineVert(ListBase *lb, unsigned int index)
{
- VertLink *vl = MEM_callocN(sizeof(VertLink), "VertLink");
- vl->index = index;
- BLI_addtail(lb, vl);
+ VertLink *vl = MEM_callocN(sizeof(VertLink), "VertLink");
+ vl->index = index;
+ BLI_addtail(lb, vl);
}
void BKE_mesh_to_curve_nurblist(const Mesh *me, ListBase *nurblist, const int edge_users_test)
{
- MVert *mvert = me->mvert;
- MEdge *med, *medge = me->medge;
- MPoly *mp, *mpoly = me->mpoly;
- MLoop *mloop = me->mloop;
-
- int medge_len = me->totedge;
- int mpoly_len = me->totpoly;
- int totedges = 0;
- int i;
-
- /* only to detect edge polylines */
- int *edge_users;
-
- ListBase edges = {NULL, NULL};
-
- /* get boundary edges */
- edge_users = MEM_calloc_arrayN(medge_len, sizeof(int), __func__);
- for (i = 0, mp = mpoly; i < mpoly_len; i++, mp++) {
- MLoop *ml = &mloop[mp->loopstart];
- int j;
- for (j = 0; j < mp->totloop; j++, ml++) {
- edge_users[ml->e]++;
- }
- }
-
- /* create edges from all faces (so as to find edges not in any faces) */
- med = medge;
- for (i = 0; i < medge_len; i++, med++) {
- if (edge_users[i] == edge_users_test) {
- EdgeLink *edl = MEM_callocN(sizeof(EdgeLink), "EdgeLink");
- edl->edge = med;
-
- BLI_addtail(&edges, edl); totedges++;
- }
- }
- MEM_freeN(edge_users);
-
- if (edges.first) {
- while (edges.first) {
- /* each iteration find a polyline and add this as a nurbs poly spline */
-
- ListBase polyline = {NULL, NULL}; /* store a list of VertLink's */
- bool closed = false;
- int totpoly = 0;
- MEdge *med_current = ((EdgeLink *)edges.last)->edge;
- unsigned int startVert = med_current->v1;
- unsigned int endVert = med_current->v2;
- bool ok = true;
-
- appendPolyLineVert(&polyline, startVert); totpoly++;
- appendPolyLineVert(&polyline, endVert); totpoly++;
- BLI_freelinkN(&edges, edges.last); totedges--;
-
- while (ok) { /* while connected edges are found... */
- EdgeLink *edl = edges.last;
- ok = false;
- while (edl) {
- EdgeLink *edl_prev = edl->prev;
-
- med = edl->edge;
-
- if (med->v1 == endVert) {
- endVert = med->v2;
- appendPolyLineVert(&polyline, med->v2); totpoly++;
- BLI_freelinkN(&edges, edl); totedges--;
- ok = true;
- }
- else if (med->v2 == endVert) {
- endVert = med->v1;
- appendPolyLineVert(&polyline, endVert); totpoly++;
- BLI_freelinkN(&edges, edl); totedges--;
- ok = true;
- }
- else if (med->v1 == startVert) {
- startVert = med->v2;
- prependPolyLineVert(&polyline, startVert); totpoly++;
- BLI_freelinkN(&edges, edl); totedges--;
- ok = true;
- }
- else if (med->v2 == startVert) {
- startVert = med->v1;
- prependPolyLineVert(&polyline, startVert); totpoly++;
- BLI_freelinkN(&edges, edl); totedges--;
- ok = true;
- }
-
- edl = edl_prev;
- }
- }
-
- /* Now we have a polyline, make into a curve */
- if (startVert == endVert) {
- BLI_freelinkN(&polyline, polyline.last);
- totpoly--;
- closed = true;
- }
-
- /* --- nurbs --- */
- {
- Nurb *nu;
- BPoint *bp;
- VertLink *vl;
-
- /* create new 'nurb' within the curve */
- nu = (Nurb *)MEM_callocN(sizeof(Nurb), "MeshNurb");
-
- nu->pntsu = totpoly;
- nu->pntsv = 1;
- nu->orderu = 4;
- nu->flagu = CU_NURB_ENDPOINT | (closed ? CU_NURB_CYCLIC : 0); /* endpoint */
- nu->resolu = 12;
-
- nu->bp = (BPoint *)MEM_calloc_arrayN(totpoly, sizeof(BPoint), "bpoints");
-
- /* add points */
- vl = polyline.first;
- for (i = 0, bp = nu->bp; i < totpoly; i++, bp++, vl = (VertLink *)vl->next) {
- copy_v3_v3(bp->vec, mvert[vl->index].co);
- bp->f1 = SELECT;
- bp->radius = bp->weight = 1.0;
- }
- BLI_freelistN(&polyline);
-
- /* add nurb to curve */
- BLI_addtail(nurblist, nu);
- }
- /* --- done with nurbs --- */
- }
- }
+ MVert *mvert = me->mvert;
+ MEdge *med, *medge = me->medge;
+ MPoly *mp, *mpoly = me->mpoly;
+ MLoop *mloop = me->mloop;
+
+ int medge_len = me->totedge;
+ int mpoly_len = me->totpoly;
+ int totedges = 0;
+ int i;
+
+ /* only to detect edge polylines */
+ int *edge_users;
+
+ ListBase edges = {NULL, NULL};
+
+ /* get boundary edges */
+ edge_users = MEM_calloc_arrayN(medge_len, sizeof(int), __func__);
+ for (i = 0, mp = mpoly; i < mpoly_len; i++, mp++) {
+ MLoop *ml = &mloop[mp->loopstart];
+ int j;
+ for (j = 0; j < mp->totloop; j++, ml++) {
+ edge_users[ml->e]++;
+ }
+ }
+
+ /* create edges from all faces (so as to find edges not in any faces) */
+ med = medge;
+ for (i = 0; i < medge_len; i++, med++) {
+ if (edge_users[i] == edge_users_test) {
+ EdgeLink *edl = MEM_callocN(sizeof(EdgeLink), "EdgeLink");
+ edl->edge = med;
+
+ BLI_addtail(&edges, edl);
+ totedges++;
+ }
+ }
+ MEM_freeN(edge_users);
+
+ if (edges.first) {
+ while (edges.first) {
+ /* each iteration find a polyline and add this as a nurbs poly spline */
+
+ ListBase polyline = {NULL, NULL}; /* store a list of VertLink's */
+ bool closed = false;
+ int totpoly = 0;
+ MEdge *med_current = ((EdgeLink *)edges.last)->edge;
+ unsigned int startVert = med_current->v1;
+ unsigned int endVert = med_current->v2;
+ bool ok = true;
+
+ appendPolyLineVert(&polyline, startVert);
+ totpoly++;
+ appendPolyLineVert(&polyline, endVert);
+ totpoly++;
+ BLI_freelinkN(&edges, edges.last);
+ totedges--;
+
+ while (ok) { /* while connected edges are found... */
+ EdgeLink *edl = edges.last;
+ ok = false;
+ while (edl) {
+ EdgeLink *edl_prev = edl->prev;
+
+ med = edl->edge;
+
+ if (med->v1 == endVert) {
+ endVert = med->v2;
+ appendPolyLineVert(&polyline, med->v2);
+ totpoly++;
+ BLI_freelinkN(&edges, edl);
+ totedges--;
+ ok = true;
+ }
+ else if (med->v2 == endVert) {
+ endVert = med->v1;
+ appendPolyLineVert(&polyline, endVert);
+ totpoly++;
+ BLI_freelinkN(&edges, edl);
+ totedges--;
+ ok = true;
+ }
+ else if (med->v1 == startVert) {
+ startVert = med->v2;
+ prependPolyLineVert(&polyline, startVert);
+ totpoly++;
+ BLI_freelinkN(&edges, edl);
+ totedges--;
+ ok = true;
+ }
+ else if (med->v2 == startVert) {
+ startVert = med->v1;
+ prependPolyLineVert(&polyline, startVert);
+ totpoly++;
+ BLI_freelinkN(&edges, edl);
+ totedges--;
+ ok = true;
+ }
+
+ edl = edl_prev;
+ }
+ }
+
+ /* Now we have a polyline, make into a curve */
+ if (startVert == endVert) {
+ BLI_freelinkN(&polyline, polyline.last);
+ totpoly--;
+ closed = true;
+ }
+
+ /* --- nurbs --- */
+ {
+ Nurb *nu;
+ BPoint *bp;
+ VertLink *vl;
+
+ /* create new 'nurb' within the curve */
+ nu = (Nurb *)MEM_callocN(sizeof(Nurb), "MeshNurb");
+
+ nu->pntsu = totpoly;
+ nu->pntsv = 1;
+ nu->orderu = 4;
+ nu->flagu = CU_NURB_ENDPOINT | (closed ? CU_NURB_CYCLIC : 0); /* endpoint */
+ nu->resolu = 12;
+
+ nu->bp = (BPoint *)MEM_calloc_arrayN(totpoly, sizeof(BPoint), "bpoints");
+
+ /* add points */
+ vl = polyline.first;
+ for (i = 0, bp = nu->bp; i < totpoly; i++, bp++, vl = (VertLink *)vl->next) {
+ copy_v3_v3(bp->vec, mvert[vl->index].co);
+ bp->f1 = SELECT;
+ bp->radius = bp->weight = 1.0;
+ }
+ BLI_freelistN(&polyline);
+
+ /* add nurb to curve */
+ BLI_addtail(nurblist, nu);
+ }
+ /* --- done with nurbs --- */
+ }
+ }
}
void BKE_mesh_to_curve(Main *bmain, Depsgraph *depsgraph, Scene *UNUSED(scene), Object *ob)
{
- /* make new mesh data from the original copy */
- Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
- Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
- Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &CD_MASK_MESH);
- ListBase nurblist = {NULL, NULL};
+ /* make new mesh data from the original copy */
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &CD_MASK_MESH);
+ ListBase nurblist = {NULL, NULL};
- BKE_mesh_to_curve_nurblist(me_eval, &nurblist, 0);
- BKE_mesh_to_curve_nurblist(me_eval, &nurblist, 1);
+ BKE_mesh_to_curve_nurblist(me_eval, &nurblist, 0);
+ BKE_mesh_to_curve_nurblist(me_eval, &nurblist, 1);
- if (nurblist.first) {
- Curve *cu = BKE_curve_add(bmain, ob->id.name + 2, OB_CURVE);
- cu->flag |= CU_3D;
+ if (nurblist.first) {
+ Curve *cu = BKE_curve_add(bmain, ob->id.name + 2, OB_CURVE);
+ cu->flag |= CU_3D;
- cu->nurb = nurblist;
+ cu->nurb = nurblist;
- id_us_min(&((Mesh *)ob->data)->id);
- ob->data = cu;
- ob->type = OB_CURVE;
+ id_us_min(&((Mesh *)ob->data)->id);
+ ob->data = cu;
+ ob->type = OB_CURVE;
- BKE_object_free_derived_caches(ob);
- }
+ BKE_object_free_derived_caches(ob);
+ }
}
/* settings: 1 - preview, 2 - render
@@ -856,600 +899,620 @@ void BKE_mesh_to_curve(Main *bmain, Depsgraph *depsgraph, Scene *UNUSED(scene),
* The result mesh will point to an evaluated datablocks. For example,
* materials will be an evaluated IDs from the dependency graph.
*/
-Mesh *BKE_mesh_new_from_object(
- Depsgraph *depsgraph, Main *bmain, Scene *sce, Object *ob,
- const bool apply_modifiers, const bool calc_undeformed)
+Mesh *BKE_mesh_new_from_object(Depsgraph *depsgraph,
+ Main *bmain,
+ Scene *sce,
+ Object *ob,
+ const bool apply_modifiers,
+ const bool calc_undeformed)
{
- Mesh *tmpmesh;
- Curve *tmpcu = NULL, *copycu;
- int i;
- const bool render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
- bool effective_apply_modifiers = apply_modifiers;
- bool do_mat_id_data_us = true;
-
- Object *object_input = ob;
- Object *object_eval = DEG_get_evaluated_object(depsgraph, object_input);
- Object object_for_eval;
-
- if (object_eval == object_input) {
- /* Evaluated mesh contains all modifiers applied already.
- * The other types of object has them applied, but are stored in other
- * data structures than a mesh. So need to apply modifiers again on a
- * temporary copy before converting result to mesh. */
- if (object_input->type == OB_MESH) {
- effective_apply_modifiers = false;
- }
- else {
- effective_apply_modifiers = true;
- }
- object_for_eval = *object_eval;
- }
- else {
- if (apply_modifiers) {
- object_for_eval = *object_eval;
- if (object_for_eval.runtime.mesh_orig != NULL) {
- object_for_eval.data = object_for_eval.runtime.mesh_orig;
- }
- }
- else {
- object_for_eval = *object_input;
- }
- }
-
- const bool cage = !effective_apply_modifiers;
-
- /* perform the mesh extraction based on type */
- switch (object_for_eval.type) {
- case OB_FONT:
- case OB_CURVE:
- case OB_SURF:
- {
- ListBase dispbase = {NULL, NULL};
- Mesh *me_eval_final = NULL;
- int uv_from_orco;
-
- /* copies object and modifiers (but not the data) */
- Object *tmpobj;
- BKE_id_copy_ex(NULL, &object_for_eval.id, (ID **)&tmpobj, LIB_ID_COPY_LOCALIZE);
- tmpcu = (Curve *)tmpobj->data;
-
- /* Copy cached display list, it might be needed by the stack evaluation.
- * Ideally stack should be able to use render-time display list, but doing
- * so is quite tricky and not safe so close to the release.
- *
- * TODO(sergey): Look into more proper solution.
- */
- if (object_for_eval.runtime.curve_cache != NULL) {
- if (tmpobj->runtime.curve_cache == NULL) {
- tmpobj->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for curve types");
- }
- BKE_displist_copy(&tmpobj->runtime.curve_cache->disp, &object_for_eval.runtime.curve_cache->disp);
- }
-
- /* if getting the original caged mesh, delete object modifiers */
- if (cage)
- BKE_object_free_modifiers(tmpobj, LIB_ID_CREATE_NO_USER_REFCOUNT);
-
- /* copies the data, but *not* the shapekeys. */
- BKE_id_copy_ex(NULL, object_for_eval.data, (ID **)&copycu, LIB_ID_COPY_LOCALIZE);
- tmpobj->data = copycu;
-
- /* make sure texture space is calculated for a copy of curve,
- * it will be used for the final result.
- */
- BKE_curve_texspace_calc(copycu);
-
- /* temporarily set edit so we get updates from edit mode, but
- * also because for text datablocks copying it while in edit
- * mode gives invalid data structures */
- copycu->editfont = tmpcu->editfont;
- copycu->editnurb = tmpcu->editnurb;
-
- /* get updated display list, and convert to a mesh */
- BKE_displist_make_curveTypes_forRender(
- depsgraph, sce, tmpobj, &dispbase, &me_eval_final, false, render,
- NULL);
-
- copycu->editfont = NULL;
- copycu->editnurb = NULL;
-
- tmpobj->runtime.mesh_eval = me_eval_final;
-
- /* convert object type to mesh */
- uv_from_orco = (tmpcu->flag & CU_UV_ORCO) != 0;
- BKE_mesh_from_nurbs_displist(bmain, tmpobj, &dispbase, uv_from_orco, tmpcu->id.name + 2, true);
- /* Function above also frees copycu (aka tmpobj->data), make this obvious here. */
- copycu = NULL;
-
- tmpmesh = tmpobj->data;
- id_us_min(&tmpmesh->id); /* Gets one user from its creation in BKE_mesh_from_nurbs_displist(). */
-
- BKE_displist_free(&dispbase);
-
- /* BKE_mesh_from_nurbs changes the type to a mesh, check it worked.
- * if it didn't the curve did not have any segments or otherwise
- * would have generated an empty mesh */
- if (tmpobj->type != OB_MESH) {
- BKE_id_free(NULL, tmpobj);
- return NULL;
- }
-
- BKE_id_free(NULL, tmpobj);
-
- /* XXX The curve to mesh conversion is convoluted... But essentially, BKE_mesh_from_nurbs_displist()
- * already transfers the ownership of materials from the temp copy of the Curve ID to the new
- * Mesh ID, so we do not want to increase materials' usercount later. */
- do_mat_id_data_us = false;
-
- break;
- }
-
- case OB_MBALL:
- {
- /* metaballs don't have modifiers, so just convert to mesh */
- Object *basis_ob = BKE_mball_basis_find(sce, object_input);
- /* todo, re-generatre for render-res */
- /* metaball_polygonize(scene, ob) */
-
- if (basis_ob != object_input) {
- /* Only do basis metaball. */
- return NULL;
- }
-
- tmpmesh = BKE_mesh_add(bmain, ((ID *)object_for_eval.data)->name + 2);
- /* BKE_mesh_add gives us a user count we don't need */
- id_us_min(&tmpmesh->id);
-
- if (render) {
- ListBase disp = {NULL, NULL};
- BKE_displist_make_mball_forRender(depsgraph, sce, &object_for_eval, &disp);
- BKE_mesh_from_metaball(&disp, tmpmesh);
- BKE_displist_free(&disp);
- }
- else {
- ListBase disp = {NULL, NULL};
- if (object_for_eval.runtime.curve_cache) {
- disp = object_for_eval.runtime.curve_cache->disp;
- }
- BKE_mesh_from_metaball(&disp, tmpmesh);
- }
-
- BKE_mesh_texspace_copy_from_object(tmpmesh, &object_for_eval);
-
- break;
-
- }
- case OB_MESH:
- /* copies object and modifiers (but not the data) */
- if (cage) {
- /* copies the data (but *not* the shapekeys). */
- Mesh *mesh = object_for_eval.data;
- BKE_id_copy_ex(bmain, &mesh->id, (ID **)&tmpmesh, 0);
- /* XXX BKE_mesh_copy() already handles materials usercount. */
- do_mat_id_data_us = false;
- }
- /* if not getting the original caged mesh, get final derived mesh */
- else {
- /* Make a dummy mesh, saves copying */
- Mesh *me_eval;
- CustomData_MeshMasks mask = CD_MASK_MESH; /* this seems more suitable, exporter,
- * for example, needs CD_MASK_MDEFORMVERT */
-
- if (calc_undeformed) {
- mask.vmask |= CD_MASK_ORCO;
- }
-
- if (render) {
- me_eval = mesh_create_eval_final_render(depsgraph, sce, &object_for_eval, &mask);
- }
- else {
- me_eval = mesh_create_eval_final_view(depsgraph, sce, &object_for_eval, &mask);
- }
-
- tmpmesh = BKE_mesh_add(bmain, ((ID *)object_for_eval.data)->name + 2);
- BKE_mesh_nomain_to_mesh(me_eval, tmpmesh, &object_for_eval, &mask, true);
-
- /* Copy autosmooth settings from original mesh. */
- Mesh *me = (Mesh *)object_for_eval.data;
- tmpmesh->flag |= (me->flag & ME_AUTOSMOOTH);
- tmpmesh->smoothresh = me->smoothresh;
- }
-
- /* BKE_mesh_add/copy gives us a user count we don't need */
- id_us_min(&tmpmesh->id);
-
- break;
- default:
- /* "Object does not have geometry data") */
- return NULL;
- }
-
- /* Copy materials to new mesh */
- switch (object_for_eval.type) {
- case OB_SURF:
- case OB_FONT:
- case OB_CURVE:
- tmpmesh->totcol = tmpcu->totcol;
-
- /* free old material list (if it exists) and adjust user counts */
- if (tmpcu->mat) {
- for (i = tmpcu->totcol; i-- > 0; ) {
- /* are we an object material or data based? */
- tmpmesh->mat[i] = give_current_material(object_input, i + 1);
-
- if (((object_for_eval.matbits && object_for_eval.matbits[i]) || do_mat_id_data_us) && tmpmesh->mat[i]) {
- id_us_plus(&tmpmesh->mat[i]->id);
- }
- }
- }
- break;
-
- case OB_MBALL:
- {
- MetaBall *tmpmb = (MetaBall *)object_for_eval.data;
- tmpmesh->mat = MEM_dupallocN(tmpmb->mat);
- tmpmesh->totcol = tmpmb->totcol;
-
- /* free old material list (if it exists) and adjust user counts */
- if (tmpmb->mat) {
- for (i = tmpmb->totcol; i-- > 0; ) {
- /* are we an object material or data based? */
- tmpmesh->mat[i] = give_current_material(object_input, i + 1);
-
- if (((object_for_eval.matbits && object_for_eval.matbits[i]) || do_mat_id_data_us) && tmpmesh->mat[i]) {
- id_us_plus(&tmpmesh->mat[i]->id);
- }
- }
- }
- break;
- }
-
- case OB_MESH:
- if (!cage) {
- Mesh *origmesh = object_for_eval.data;
- tmpmesh->flag = origmesh->flag;
- tmpmesh->mat = MEM_dupallocN(origmesh->mat);
- tmpmesh->totcol = origmesh->totcol;
- tmpmesh->smoothresh = origmesh->smoothresh;
- if (origmesh->mat) {
- for (i = origmesh->totcol; i-- > 0; ) {
- /* are we an object material or data based? */
- tmpmesh->mat[i] = give_current_material(object_input, i + 1);
-
- if (((object_for_eval.matbits && object_for_eval.matbits[i]) || do_mat_id_data_us) && tmpmesh->mat[i]) {
- id_us_plus(&tmpmesh->mat[i]->id);
- }
- }
- }
- }
- break;
- } /* end copy materials */
-
- return tmpmesh;
+ Mesh *tmpmesh;
+ Curve *tmpcu = NULL, *copycu;
+ int i;
+ const bool render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
+ bool effective_apply_modifiers = apply_modifiers;
+ bool do_mat_id_data_us = true;
+
+ Object *object_input = ob;
+ Object *object_eval = DEG_get_evaluated_object(depsgraph, object_input);
+ Object object_for_eval;
+
+ if (object_eval == object_input) {
+ /* Evaluated mesh contains all modifiers applied already.
+ * The other types of object has them applied, but are stored in other
+ * data structures than a mesh. So need to apply modifiers again on a
+ * temporary copy before converting result to mesh. */
+ if (object_input->type == OB_MESH) {
+ effective_apply_modifiers = false;
+ }
+ else {
+ effective_apply_modifiers = true;
+ }
+ object_for_eval = *object_eval;
+ }
+ else {
+ if (apply_modifiers) {
+ object_for_eval = *object_eval;
+ if (object_for_eval.runtime.mesh_orig != NULL) {
+ object_for_eval.data = object_for_eval.runtime.mesh_orig;
+ }
+ }
+ else {
+ object_for_eval = *object_input;
+ }
+ }
+
+ const bool cage = !effective_apply_modifiers;
+
+ /* perform the mesh extraction based on type */
+ switch (object_for_eval.type) {
+ case OB_FONT:
+ case OB_CURVE:
+ case OB_SURF: {
+ ListBase dispbase = {NULL, NULL};
+ Mesh *me_eval_final = NULL;
+ int uv_from_orco;
+
+ /* copies object and modifiers (but not the data) */
+ Object *tmpobj;
+ BKE_id_copy_ex(NULL, &object_for_eval.id, (ID **)&tmpobj, LIB_ID_COPY_LOCALIZE);
+ tmpcu = (Curve *)tmpobj->data;
+
+ /* Copy cached display list, it might be needed by the stack evaluation.
+ * Ideally stack should be able to use render-time display list, but doing
+ * so is quite tricky and not safe so close to the release.
+ *
+ * TODO(sergey): Look into more proper solution.
+ */
+ if (object_for_eval.runtime.curve_cache != NULL) {
+ if (tmpobj->runtime.curve_cache == NULL) {
+ tmpobj->runtime.curve_cache = MEM_callocN(sizeof(CurveCache),
+ "CurveCache for curve types");
+ }
+ BKE_displist_copy(&tmpobj->runtime.curve_cache->disp,
+ &object_for_eval.runtime.curve_cache->disp);
+ }
+
+ /* if getting the original caged mesh, delete object modifiers */
+ if (cage)
+ BKE_object_free_modifiers(tmpobj, LIB_ID_CREATE_NO_USER_REFCOUNT);
+
+ /* copies the data, but *not* the shapekeys. */
+ BKE_id_copy_ex(NULL, object_for_eval.data, (ID **)&copycu, LIB_ID_COPY_LOCALIZE);
+ tmpobj->data = copycu;
+
+ /* make sure texture space is calculated for a copy of curve,
+ * it will be used for the final result.
+ */
+ BKE_curve_texspace_calc(copycu);
+
+ /* temporarily set edit so we get updates from edit mode, but
+ * also because for text datablocks copying it while in edit
+ * mode gives invalid data structures */
+ copycu->editfont = tmpcu->editfont;
+ copycu->editnurb = tmpcu->editnurb;
+
+ /* get updated display list, and convert to a mesh */
+ BKE_displist_make_curveTypes_forRender(
+ depsgraph, sce, tmpobj, &dispbase, &me_eval_final, false, render, NULL);
+
+ copycu->editfont = NULL;
+ copycu->editnurb = NULL;
+
+ tmpobj->runtime.mesh_eval = me_eval_final;
+
+ /* convert object type to mesh */
+ uv_from_orco = (tmpcu->flag & CU_UV_ORCO) != 0;
+ BKE_mesh_from_nurbs_displist(
+ bmain, tmpobj, &dispbase, uv_from_orco, tmpcu->id.name + 2, true);
+ /* Function above also frees copycu (aka tmpobj->data), make this obvious here. */
+ copycu = NULL;
+
+ tmpmesh = tmpobj->data;
+ id_us_min(
+ &tmpmesh->id); /* Gets one user from its creation in BKE_mesh_from_nurbs_displist(). */
+
+ BKE_displist_free(&dispbase);
+
+ /* BKE_mesh_from_nurbs changes the type to a mesh, check it worked.
+ * if it didn't the curve did not have any segments or otherwise
+ * would have generated an empty mesh */
+ if (tmpobj->type != OB_MESH) {
+ BKE_id_free(NULL, tmpobj);
+ return NULL;
+ }
+
+ BKE_id_free(NULL, tmpobj);
+
+ /* XXX The curve to mesh conversion is convoluted... But essentially, BKE_mesh_from_nurbs_displist()
+ * already transfers the ownership of materials from the temp copy of the Curve ID to the new
+ * Mesh ID, so we do not want to increase materials' usercount later. */
+ do_mat_id_data_us = false;
+
+ break;
+ }
+
+ case OB_MBALL: {
+ /* metaballs don't have modifiers, so just convert to mesh */
+ Object *basis_ob = BKE_mball_basis_find(sce, object_input);
+ /* todo, re-generatre for render-res */
+ /* metaball_polygonize(scene, ob) */
+
+ if (basis_ob != object_input) {
+ /* Only do basis metaball. */
+ return NULL;
+ }
+
+ tmpmesh = BKE_mesh_add(bmain, ((ID *)object_for_eval.data)->name + 2);
+ /* BKE_mesh_add gives us a user count we don't need */
+ id_us_min(&tmpmesh->id);
+
+ if (render) {
+ ListBase disp = {NULL, NULL};
+ BKE_displist_make_mball_forRender(depsgraph, sce, &object_for_eval, &disp);
+ BKE_mesh_from_metaball(&disp, tmpmesh);
+ BKE_displist_free(&disp);
+ }
+ else {
+ ListBase disp = {NULL, NULL};
+ if (object_for_eval.runtime.curve_cache) {
+ disp = object_for_eval.runtime.curve_cache->disp;
+ }
+ BKE_mesh_from_metaball(&disp, tmpmesh);
+ }
+
+ BKE_mesh_texspace_copy_from_object(tmpmesh, &object_for_eval);
+
+ break;
+ }
+ case OB_MESH:
+ /* copies object and modifiers (but not the data) */
+ if (cage) {
+ /* copies the data (but *not* the shapekeys). */
+ Mesh *mesh = object_for_eval.data;
+ BKE_id_copy_ex(bmain, &mesh->id, (ID **)&tmpmesh, 0);
+ /* XXX BKE_mesh_copy() already handles materials usercount. */
+ do_mat_id_data_us = false;
+ }
+ /* if not getting the original caged mesh, get final derived mesh */
+ else {
+ /* Make a dummy mesh, saves copying */
+ Mesh *me_eval;
+ CustomData_MeshMasks mask = CD_MASK_MESH; /* this seems more suitable, exporter,
+ * for example, needs CD_MASK_MDEFORMVERT */
+
+ if (calc_undeformed) {
+ mask.vmask |= CD_MASK_ORCO;
+ }
+
+ if (render) {
+ me_eval = mesh_create_eval_final_render(depsgraph, sce, &object_for_eval, &mask);
+ }
+ else {
+ me_eval = mesh_create_eval_final_view(depsgraph, sce, &object_for_eval, &mask);
+ }
+
+ tmpmesh = BKE_mesh_add(bmain, ((ID *)object_for_eval.data)->name + 2);
+ BKE_mesh_nomain_to_mesh(me_eval, tmpmesh, &object_for_eval, &mask, true);
+
+ /* Copy autosmooth settings from original mesh. */
+ Mesh *me = (Mesh *)object_for_eval.data;
+ tmpmesh->flag |= (me->flag & ME_AUTOSMOOTH);
+ tmpmesh->smoothresh = me->smoothresh;
+ }
+
+ /* BKE_mesh_add/copy gives us a user count we don't need */
+ id_us_min(&tmpmesh->id);
+
+ break;
+ default:
+ /* "Object does not have geometry data") */
+ return NULL;
+ }
+
+ /* Copy materials to new mesh */
+ switch (object_for_eval.type) {
+ case OB_SURF:
+ case OB_FONT:
+ case OB_CURVE:
+ tmpmesh->totcol = tmpcu->totcol;
+
+ /* free old material list (if it exists) and adjust user counts */
+ if (tmpcu->mat) {
+ for (i = tmpcu->totcol; i-- > 0;) {
+ /* are we an object material or data based? */
+ tmpmesh->mat[i] = give_current_material(object_input, i + 1);
+
+ if (((object_for_eval.matbits && object_for_eval.matbits[i]) || do_mat_id_data_us) &&
+ tmpmesh->mat[i]) {
+ id_us_plus(&tmpmesh->mat[i]->id);
+ }
+ }
+ }
+ break;
+
+ case OB_MBALL: {
+ MetaBall *tmpmb = (MetaBall *)object_for_eval.data;
+ tmpmesh->mat = MEM_dupallocN(tmpmb->mat);
+ tmpmesh->totcol = tmpmb->totcol;
+
+ /* free old material list (if it exists) and adjust user counts */
+ if (tmpmb->mat) {
+ for (i = tmpmb->totcol; i-- > 0;) {
+ /* are we an object material or data based? */
+ tmpmesh->mat[i] = give_current_material(object_input, i + 1);
+
+ if (((object_for_eval.matbits && object_for_eval.matbits[i]) || do_mat_id_data_us) &&
+ tmpmesh->mat[i]) {
+ id_us_plus(&tmpmesh->mat[i]->id);
+ }
+ }
+ }
+ break;
+ }
+
+ case OB_MESH:
+ if (!cage) {
+ Mesh *origmesh = object_for_eval.data;
+ tmpmesh->flag = origmesh->flag;
+ tmpmesh->mat = MEM_dupallocN(origmesh->mat);
+ tmpmesh->totcol = origmesh->totcol;
+ tmpmesh->smoothresh = origmesh->smoothresh;
+ if (origmesh->mat) {
+ for (i = origmesh->totcol; i-- > 0;) {
+ /* are we an object material or data based? */
+ tmpmesh->mat[i] = give_current_material(object_input, i + 1);
+
+ if (((object_for_eval.matbits && object_for_eval.matbits[i]) || do_mat_id_data_us) &&
+ tmpmesh->mat[i]) {
+ id_us_plus(&tmpmesh->mat[i]->id);
+ }
+ }
+ }
+ }
+ break;
+ } /* end copy materials */
+
+ return tmpmesh;
}
-
static void add_shapekey_layers(Mesh *mesh_dest, Mesh *mesh_src)
{
- KeyBlock *kb;
- Key *key = mesh_src->key;
- int i;
-
- if (!mesh_src->key)
- return;
-
- /* ensure we can use mesh vertex count for derived mesh custom data */
- if (mesh_src->totvert != mesh_dest->totvert) {
- CLOG_ERROR(&LOG, "vertex size mismatch (mesh/dm) '%s' (%d != %d)",
- mesh_src->id.name + 2, mesh_src->totvert, mesh_dest->totvert);
- return;
- }
-
- for (i = 0, kb = key->block.first; kb; kb = kb->next, i++) {
- int ci;
- float *array;
-
- if (mesh_src->totvert != kb->totelem) {
- CLOG_ERROR(&LOG, "vertex size mismatch (Mesh '%s':%d != KeyBlock '%s':%d)",
- mesh_src->id.name + 2, mesh_src->totvert, kb->name, kb->totelem);
- array = MEM_calloc_arrayN((size_t)mesh_src->totvert, 3 * sizeof(float), __func__);
- }
- else {
- array = MEM_malloc_arrayN((size_t)mesh_src->totvert, 3 * sizeof(float), __func__);
- memcpy(array, kb->data, (size_t)mesh_src->totvert * 3 * sizeof(float));
- }
-
- CustomData_add_layer_named(&mesh_dest->vdata, CD_SHAPEKEY, CD_ASSIGN, array, mesh_dest->totvert, kb->name);
- ci = CustomData_get_layer_index_n(&mesh_dest->vdata, CD_SHAPEKEY, i);
-
- mesh_dest->vdata.layers[ci].uid = kb->uid;
- }
+ KeyBlock *kb;
+ Key *key = mesh_src->key;
+ int i;
+
+ if (!mesh_src->key)
+ return;
+
+ /* ensure we can use mesh vertex count for derived mesh custom data */
+ if (mesh_src->totvert != mesh_dest->totvert) {
+ CLOG_ERROR(&LOG,
+ "vertex size mismatch (mesh/dm) '%s' (%d != %d)",
+ mesh_src->id.name + 2,
+ mesh_src->totvert,
+ mesh_dest->totvert);
+ return;
+ }
+
+ for (i = 0, kb = key->block.first; kb; kb = kb->next, i++) {
+ int ci;
+ float *array;
+
+ if (mesh_src->totvert != kb->totelem) {
+ CLOG_ERROR(&LOG,
+ "vertex size mismatch (Mesh '%s':%d != KeyBlock '%s':%d)",
+ mesh_src->id.name + 2,
+ mesh_src->totvert,
+ kb->name,
+ kb->totelem);
+ array = MEM_calloc_arrayN((size_t)mesh_src->totvert, 3 * sizeof(float), __func__);
+ }
+ else {
+ array = MEM_malloc_arrayN((size_t)mesh_src->totvert, 3 * sizeof(float), __func__);
+ memcpy(array, kb->data, (size_t)mesh_src->totvert * 3 * sizeof(float));
+ }
+
+ CustomData_add_layer_named(
+ &mesh_dest->vdata, CD_SHAPEKEY, CD_ASSIGN, array, mesh_dest->totvert, kb->name);
+ ci = CustomData_get_layer_index_n(&mesh_dest->vdata, CD_SHAPEKEY, i);
+
+ mesh_dest->vdata.layers[ci].uid = kb->uid;
+ }
}
-
-Mesh *BKE_mesh_create_derived_for_modifier(
- struct Depsgraph *depsgraph, Scene *scene, Object *ob,
- ModifierData *md, int build_shapekey_layers)
+Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ ModifierData *md,
+ int build_shapekey_layers)
{
- Mesh *me = ob->runtime.mesh_orig ? ob->runtime.mesh_orig : ob->data;
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- Mesh *result;
- KeyBlock *kb;
- ModifierEvalContext mectx = {depsgraph, ob, 0};
+ Mesh *me = ob->runtime.mesh_orig ? ob->runtime.mesh_orig : ob->data;
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ Mesh *result;
+ KeyBlock *kb;
+ ModifierEvalContext mectx = {depsgraph, ob, 0};
- if (!(md->mode & eModifierMode_Realtime)) {
- return NULL;
- }
+ if (!(md->mode & eModifierMode_Realtime)) {
+ return NULL;
+ }
- if (mti->isDisabled && mti->isDisabled(scene, md, 0)) {
- return NULL;
- }
+ if (mti->isDisabled && mti->isDisabled(scene, md, 0)) {
+ return NULL;
+ }
- if (build_shapekey_layers && me->key && (kb = BLI_findlink(&me->key->block, ob->shapenr - 1))) {
- BKE_keyblock_convert_to_mesh(kb, me);
- }
+ if (build_shapekey_layers && me->key && (kb = BLI_findlink(&me->key->block, ob->shapenr - 1))) {
+ BKE_keyblock_convert_to_mesh(kb, me);
+ }
- if (mti->type == eModifierTypeType_OnlyDeform) {
- int numVerts;
- float (*deformedVerts)[3] = BKE_mesh_vertexCos_get(me, &numVerts);
+ if (mti->type == eModifierTypeType_OnlyDeform) {
+ int numVerts;
+ float(*deformedVerts)[3] = BKE_mesh_vertexCos_get(me, &numVerts);
- mti->deformVerts(md, &mectx, NULL, deformedVerts, numVerts);
- BKE_id_copy_ex(NULL, &me->id, (ID **)&result, LIB_ID_COPY_LOCALIZE);
- BKE_mesh_apply_vert_coords(result, deformedVerts);
+ mti->deformVerts(md, &mectx, NULL, deformedVerts, numVerts);
+ BKE_id_copy_ex(NULL, &me->id, (ID **)&result, LIB_ID_COPY_LOCALIZE);
+ BKE_mesh_apply_vert_coords(result, deformedVerts);
- if (build_shapekey_layers)
- add_shapekey_layers(result, me);
+ if (build_shapekey_layers)
+ add_shapekey_layers(result, me);
- MEM_freeN(deformedVerts);
- }
- else {
- Mesh *mesh_temp;
- BKE_id_copy_ex(NULL, &me->id, (ID **)&mesh_temp, LIB_ID_COPY_LOCALIZE);
+ MEM_freeN(deformedVerts);
+ }
+ else {
+ Mesh *mesh_temp;
+ BKE_id_copy_ex(NULL, &me->id, (ID **)&mesh_temp, LIB_ID_COPY_LOCALIZE);
- if (build_shapekey_layers)
- add_shapekey_layers(mesh_temp, me);
+ if (build_shapekey_layers)
+ add_shapekey_layers(mesh_temp, me);
- result = mti->applyModifier(md, &mectx, mesh_temp);
- ASSERT_IS_VALID_MESH(result);
+ result = mti->applyModifier(md, &mectx, mesh_temp);
+ ASSERT_IS_VALID_MESH(result);
- if (mesh_temp != result) {
- BKE_id_free(NULL, mesh_temp);
- }
- }
+ if (mesh_temp != result) {
+ BKE_id_free(NULL, mesh_temp);
+ }
+ }
- return result;
+ return result;
}
/* This is a Mesh-based copy of the same function in DerivedMesh.c */
static void shapekey_layers_to_keyblocks(Mesh *mesh_src, Mesh *mesh_dst, int actshape_uid)
{
- KeyBlock *kb;
- int i, j, tot;
-
- if (!mesh_dst->key)
- return;
-
- tot = CustomData_number_of_layers(&mesh_src->vdata, CD_SHAPEKEY);
- for (i = 0; i < tot; i++) {
- CustomDataLayer *layer = &mesh_src->vdata.layers[CustomData_get_layer_index_n(&mesh_src->vdata, CD_SHAPEKEY, i)];
- float (*cos)[3], (*kbcos)[3];
-
- for (kb = mesh_dst->key->block.first; kb; kb = kb->next) {
- if (kb->uid == layer->uid)
- break;
- }
-
- if (!kb) {
- kb = BKE_keyblock_add(mesh_dst->key, layer->name);
- kb->uid = layer->uid;
- }
-
- if (kb->data)
- MEM_freeN(kb->data);
-
- cos = CustomData_get_layer_n(&mesh_src->vdata, CD_SHAPEKEY, i);
- kb->totelem = mesh_src->totvert;
-
- kb->data = kbcos = MEM_malloc_arrayN(kb->totelem, 3 * sizeof(float), __func__);
- if (kb->uid == actshape_uid) {
- MVert *mvert = mesh_src->mvert;
-
- for (j = 0; j < mesh_src->totvert; j++, kbcos++, mvert++) {
- copy_v3_v3(*kbcos, mvert->co);
- }
- }
- else {
- for (j = 0; j < kb->totelem; j++, cos++, kbcos++) {
- copy_v3_v3(*kbcos, *cos);
- }
- }
- }
-
- for (kb = mesh_dst->key->block.first; kb; kb = kb->next) {
- if (kb->totelem != mesh_src->totvert) {
- if (kb->data)
- MEM_freeN(kb->data);
-
- kb->totelem = mesh_src->totvert;
- kb->data = MEM_calloc_arrayN(kb->totelem, 3 * sizeof(float), __func__);
- CLOG_ERROR(&LOG, "lost a shapekey layer: '%s'! (bmesh internal error)", kb->name);
- }
- }
+ KeyBlock *kb;
+ int i, j, tot;
+
+ if (!mesh_dst->key)
+ return;
+
+ tot = CustomData_number_of_layers(&mesh_src->vdata, CD_SHAPEKEY);
+ for (i = 0; i < tot; i++) {
+ CustomDataLayer *layer =
+ &mesh_src->vdata.layers[CustomData_get_layer_index_n(&mesh_src->vdata, CD_SHAPEKEY, i)];
+ float(*cos)[3], (*kbcos)[3];
+
+ for (kb = mesh_dst->key->block.first; kb; kb = kb->next) {
+ if (kb->uid == layer->uid)
+ break;
+ }
+
+ if (!kb) {
+ kb = BKE_keyblock_add(mesh_dst->key, layer->name);
+ kb->uid = layer->uid;
+ }
+
+ if (kb->data)
+ MEM_freeN(kb->data);
+
+ cos = CustomData_get_layer_n(&mesh_src->vdata, CD_SHAPEKEY, i);
+ kb->totelem = mesh_src->totvert;
+
+ kb->data = kbcos = MEM_malloc_arrayN(kb->totelem, 3 * sizeof(float), __func__);
+ if (kb->uid == actshape_uid) {
+ MVert *mvert = mesh_src->mvert;
+
+ for (j = 0; j < mesh_src->totvert; j++, kbcos++, mvert++) {
+ copy_v3_v3(*kbcos, mvert->co);
+ }
+ }
+ else {
+ for (j = 0; j < kb->totelem; j++, cos++, kbcos++) {
+ copy_v3_v3(*kbcos, *cos);
+ }
+ }
+ }
+
+ for (kb = mesh_dst->key->block.first; kb; kb = kb->next) {
+ if (kb->totelem != mesh_src->totvert) {
+ if (kb->data)
+ MEM_freeN(kb->data);
+
+ kb->totelem = mesh_src->totvert;
+ kb->data = MEM_calloc_arrayN(kb->totelem, 3 * sizeof(float), __func__);
+ CLOG_ERROR(&LOG, "lost a shapekey layer: '%s'! (bmesh internal error)", kb->name);
+ }
+ }
}
-
/* This is a Mesh-based copy of DM_to_mesh() */
-void BKE_mesh_nomain_to_mesh(
- Mesh *mesh_src, Mesh *mesh_dst, Object *ob, const CustomData_MeshMasks *mask, bool take_ownership)
+void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
+ Mesh *mesh_dst,
+ Object *ob,
+ const CustomData_MeshMasks *mask,
+ bool take_ownership)
{
- /* mesh_src might depend on mesh_dst, so we need to do everything with a local copy */
- /* TODO(Sybren): the above claim came from DM_to_mesh(); check whether it is still true with Mesh */
- Mesh tmp = *mesh_dst;
- int totvert, totedge /*, totface */ /* UNUSED */, totloop, totpoly;
- int did_shapekeys = 0;
- eCDAllocType alloctype = CD_DUPLICATE;
-
- if (take_ownership /* && dm->type == DM_TYPE_CDDM && dm->needsFree */) {
- bool has_any_referenced_layers =
- CustomData_has_referenced(&mesh_src->vdata) ||
- CustomData_has_referenced(&mesh_src->edata) ||
- CustomData_has_referenced(&mesh_src->ldata) ||
- CustomData_has_referenced(&mesh_src->fdata) ||
- CustomData_has_referenced(&mesh_src->pdata);
- if (!has_any_referenced_layers) {
- alloctype = CD_ASSIGN;
- }
- }
- CustomData_reset(&tmp.vdata);
- CustomData_reset(&tmp.edata);
- CustomData_reset(&tmp.fdata);
- CustomData_reset(&tmp.ldata);
- CustomData_reset(&tmp.pdata);
-
- BKE_mesh_ensure_normals(mesh_src);
-
- totvert = tmp.totvert = mesh_src->totvert;
- totedge = tmp.totedge = mesh_src->totedge;
- totloop = tmp.totloop = mesh_src->totloop;
- totpoly = tmp.totpoly = mesh_src->totpoly;
- tmp.totface = 0;
-
- CustomData_copy(&mesh_src->vdata, &tmp.vdata, mask->vmask, alloctype, totvert);
- CustomData_copy(&mesh_src->edata, &tmp.edata, mask->emask, alloctype, totedge);
- CustomData_copy(&mesh_src->ldata, &tmp.ldata, mask->lmask, alloctype, totloop);
- CustomData_copy(&mesh_src->pdata, &tmp.pdata, mask->pmask, alloctype, totpoly);
- tmp.cd_flag = mesh_src->cd_flag;
- tmp.runtime.deformed_only = mesh_src->runtime.deformed_only;
-
- if (CustomData_has_layer(&mesh_src->vdata, CD_SHAPEKEY)) {
- KeyBlock *kb;
- int uid;
-
- if (ob) {
- kb = BLI_findlink(&mesh_dst->key->block, ob->shapenr - 1);
- if (kb) {
- uid = kb->uid;
- }
- else {
- CLOG_ERROR(&LOG, "could not find active shapekey %d!", ob->shapenr - 1);
-
- uid = INT_MAX;
- }
- }
- else {
- /* if no object, set to INT_MAX so we don't mess up any shapekey layers */
- uid = INT_MAX;
- }
-
- shapekey_layers_to_keyblocks(mesh_src, mesh_dst, uid);
- did_shapekeys = 1;
- }
-
- /* copy texture space */
- if (ob) {
- BKE_mesh_texspace_copy_from_object(&tmp, ob);
- }
-
- /* not all DerivedMeshes store their verts/edges/faces in CustomData, so
- * we set them here in case they are missing */
- /* TODO(Sybren): we could probably replace CD_ASSIGN with alloctype and always directly pass mesh_src->mxxx,
- * instead of using a ternary operator. */
- if (!CustomData_has_layer(&tmp.vdata, CD_MVERT)) {
- CustomData_add_layer(
- &tmp.vdata, CD_MVERT, CD_ASSIGN,
- (alloctype == CD_ASSIGN) ? mesh_src->mvert : MEM_dupallocN(mesh_src->mvert),
- totvert);
- }
- if (!CustomData_has_layer(&tmp.edata, CD_MEDGE)) {
- CustomData_add_layer(
- &tmp.edata, CD_MEDGE, CD_ASSIGN,
- (alloctype == CD_ASSIGN) ? mesh_src->medge : MEM_dupallocN(mesh_src->medge),
- totedge);
- }
- if (!CustomData_has_layer(&tmp.pdata, CD_MPOLY)) {
- /* TODO(Sybren): assignment to tmp.mxxx is probably not necessary due to the
- * BKE_mesh_update_customdata_pointers() call below. */
- tmp.mloop = (alloctype == CD_ASSIGN) ? mesh_src->mloop : MEM_dupallocN(mesh_src->mloop);
- tmp.mpoly = (alloctype == CD_ASSIGN) ? mesh_src->mpoly : MEM_dupallocN(mesh_src->mpoly);
-
- CustomData_add_layer(&tmp.ldata, CD_MLOOP, CD_ASSIGN, tmp.mloop, tmp.totloop);
- CustomData_add_layer(&tmp.pdata, CD_MPOLY, CD_ASSIGN, tmp.mpoly, tmp.totpoly);
- }
-
- /* object had got displacement layer, should copy this layer to save sculpted data */
- /* NOTE: maybe some other layers should be copied? nazgul */
- if (CustomData_has_layer(&mesh_dst->ldata, CD_MDISPS)) {
- if (totloop == mesh_dst->totloop) {
- MDisps *mdisps = CustomData_get_layer(&mesh_dst->ldata, CD_MDISPS);
- CustomData_add_layer(&tmp.ldata, CD_MDISPS, alloctype, mdisps, totloop);
- }
- }
-
- /* yes, must be before _and_ after tessellate */
- BKE_mesh_update_customdata_pointers(&tmp, false);
-
- /* since 2.65 caller must do! */
- // BKE_mesh_tessface_calc(&tmp);
-
- CustomData_free(&mesh_dst->vdata, mesh_dst->totvert);
- CustomData_free(&mesh_dst->edata, mesh_dst->totedge);
- CustomData_free(&mesh_dst->fdata, mesh_dst->totface);
- CustomData_free(&mesh_dst->ldata, mesh_dst->totloop);
- CustomData_free(&mesh_dst->pdata, mesh_dst->totpoly);
-
- /* ok, this should now use new CD shapekey data,
- * which should be fed through the modifier
- * stack */
- if (tmp.totvert != mesh_dst->totvert && !did_shapekeys && mesh_dst->key) {
- CLOG_ERROR(&LOG, "YEEK! this should be recoded! Shape key loss!: ID '%s'", tmp.id.name);
- if (tmp.key && !(tmp.id.tag & LIB_TAG_NO_MAIN)) {
- id_us_min(&tmp.key->id);
- }
- tmp.key = NULL;
- }
-
- /* Clear selection history */
- MEM_SAFE_FREE(tmp.mselect);
- tmp.totselect = 0;
- BLI_assert(ELEM(tmp.bb, NULL, mesh_dst->bb));
- if (mesh_dst->bb) {
- MEM_freeN(mesh_dst->bb);
- tmp.bb = NULL;
- }
-
- /* skip the listbase */
- MEMCPY_STRUCT_AFTER(mesh_dst, &tmp, id.prev);
-
- if (take_ownership) {
- if (alloctype == CD_ASSIGN) {
- CustomData_free_typemask(&mesh_src->vdata, mesh_src->totvert, ~mask->vmask);
- CustomData_free_typemask(&mesh_src->edata, mesh_src->totedge, ~mask->emask);
- CustomData_free_typemask(&mesh_src->ldata, mesh_src->totloop, ~mask->lmask);
- CustomData_free_typemask(&mesh_src->pdata, mesh_src->totpoly, ~mask->pmask);
- }
- BKE_id_free(NULL, mesh_src);
- }
+ /* mesh_src might depend on mesh_dst, so we need to do everything with a local copy */
+ /* TODO(Sybren): the above claim came from DM_to_mesh(); check whether it is still true with Mesh */
+ Mesh tmp = *mesh_dst;
+ int totvert, totedge /*, totface */ /* UNUSED */, totloop, totpoly;
+ int did_shapekeys = 0;
+ eCDAllocType alloctype = CD_DUPLICATE;
+
+ if (take_ownership /* && dm->type == DM_TYPE_CDDM && dm->needsFree */) {
+ bool has_any_referenced_layers = CustomData_has_referenced(&mesh_src->vdata) ||
+ CustomData_has_referenced(&mesh_src->edata) ||
+ CustomData_has_referenced(&mesh_src->ldata) ||
+ CustomData_has_referenced(&mesh_src->fdata) ||
+ CustomData_has_referenced(&mesh_src->pdata);
+ if (!has_any_referenced_layers) {
+ alloctype = CD_ASSIGN;
+ }
+ }
+ CustomData_reset(&tmp.vdata);
+ CustomData_reset(&tmp.edata);
+ CustomData_reset(&tmp.fdata);
+ CustomData_reset(&tmp.ldata);
+ CustomData_reset(&tmp.pdata);
+
+ BKE_mesh_ensure_normals(mesh_src);
+
+ totvert = tmp.totvert = mesh_src->totvert;
+ totedge = tmp.totedge = mesh_src->totedge;
+ totloop = tmp.totloop = mesh_src->totloop;
+ totpoly = tmp.totpoly = mesh_src->totpoly;
+ tmp.totface = 0;
+
+ CustomData_copy(&mesh_src->vdata, &tmp.vdata, mask->vmask, alloctype, totvert);
+ CustomData_copy(&mesh_src->edata, &tmp.edata, mask->emask, alloctype, totedge);
+ CustomData_copy(&mesh_src->ldata, &tmp.ldata, mask->lmask, alloctype, totloop);
+ CustomData_copy(&mesh_src->pdata, &tmp.pdata, mask->pmask, alloctype, totpoly);
+ tmp.cd_flag = mesh_src->cd_flag;
+ tmp.runtime.deformed_only = mesh_src->runtime.deformed_only;
+
+ if (CustomData_has_layer(&mesh_src->vdata, CD_SHAPEKEY)) {
+ KeyBlock *kb;
+ int uid;
+
+ if (ob) {
+ kb = BLI_findlink(&mesh_dst->key->block, ob->shapenr - 1);
+ if (kb) {
+ uid = kb->uid;
+ }
+ else {
+ CLOG_ERROR(&LOG, "could not find active shapekey %d!", ob->shapenr - 1);
+
+ uid = INT_MAX;
+ }
+ }
+ else {
+ /* if no object, set to INT_MAX so we don't mess up any shapekey layers */
+ uid = INT_MAX;
+ }
+
+ shapekey_layers_to_keyblocks(mesh_src, mesh_dst, uid);
+ did_shapekeys = 1;
+ }
+
+ /* copy texture space */
+ if (ob) {
+ BKE_mesh_texspace_copy_from_object(&tmp, ob);
+ }
+
+ /* not all DerivedMeshes store their verts/edges/faces in CustomData, so
+ * we set them here in case they are missing */
+ /* TODO(Sybren): we could probably replace CD_ASSIGN with alloctype and always directly pass mesh_src->mxxx,
+ * instead of using a ternary operator. */
+ if (!CustomData_has_layer(&tmp.vdata, CD_MVERT)) {
+ CustomData_add_layer(&tmp.vdata,
+ CD_MVERT,
+ CD_ASSIGN,
+ (alloctype == CD_ASSIGN) ? mesh_src->mvert :
+ MEM_dupallocN(mesh_src->mvert),
+ totvert);
+ }
+ if (!CustomData_has_layer(&tmp.edata, CD_MEDGE)) {
+ CustomData_add_layer(&tmp.edata,
+ CD_MEDGE,
+ CD_ASSIGN,
+ (alloctype == CD_ASSIGN) ? mesh_src->medge :
+ MEM_dupallocN(mesh_src->medge),
+ totedge);
+ }
+ if (!CustomData_has_layer(&tmp.pdata, CD_MPOLY)) {
+ /* TODO(Sybren): assignment to tmp.mxxx is probably not necessary due to the
+ * BKE_mesh_update_customdata_pointers() call below. */
+ tmp.mloop = (alloctype == CD_ASSIGN) ? mesh_src->mloop : MEM_dupallocN(mesh_src->mloop);
+ tmp.mpoly = (alloctype == CD_ASSIGN) ? mesh_src->mpoly : MEM_dupallocN(mesh_src->mpoly);
+
+ CustomData_add_layer(&tmp.ldata, CD_MLOOP, CD_ASSIGN, tmp.mloop, tmp.totloop);
+ CustomData_add_layer(&tmp.pdata, CD_MPOLY, CD_ASSIGN, tmp.mpoly, tmp.totpoly);
+ }
+
+ /* object had got displacement layer, should copy this layer to save sculpted data */
+ /* NOTE: maybe some other layers should be copied? nazgul */
+ if (CustomData_has_layer(&mesh_dst->ldata, CD_MDISPS)) {
+ if (totloop == mesh_dst->totloop) {
+ MDisps *mdisps = CustomData_get_layer(&mesh_dst->ldata, CD_MDISPS);
+ CustomData_add_layer(&tmp.ldata, CD_MDISPS, alloctype, mdisps, totloop);
+ }
+ }
+
+ /* yes, must be before _and_ after tessellate */
+ BKE_mesh_update_customdata_pointers(&tmp, false);
+
+ /* since 2.65 caller must do! */
+ // BKE_mesh_tessface_calc(&tmp);
+
+ CustomData_free(&mesh_dst->vdata, mesh_dst->totvert);
+ CustomData_free(&mesh_dst->edata, mesh_dst->totedge);
+ CustomData_free(&mesh_dst->fdata, mesh_dst->totface);
+ CustomData_free(&mesh_dst->ldata, mesh_dst->totloop);
+ CustomData_free(&mesh_dst->pdata, mesh_dst->totpoly);
+
+ /* ok, this should now use new CD shapekey data,
+ * which should be fed through the modifier
+ * stack */
+ if (tmp.totvert != mesh_dst->totvert && !did_shapekeys && mesh_dst->key) {
+ CLOG_ERROR(&LOG, "YEEK! this should be recoded! Shape key loss!: ID '%s'", tmp.id.name);
+ if (tmp.key && !(tmp.id.tag & LIB_TAG_NO_MAIN)) {
+ id_us_min(&tmp.key->id);
+ }
+ tmp.key = NULL;
+ }
+
+ /* Clear selection history */
+ MEM_SAFE_FREE(tmp.mselect);
+ tmp.totselect = 0;
+ BLI_assert(ELEM(tmp.bb, NULL, mesh_dst->bb));
+ if (mesh_dst->bb) {
+ MEM_freeN(mesh_dst->bb);
+ tmp.bb = NULL;
+ }
+
+ /* skip the listbase */
+ MEMCPY_STRUCT_AFTER(mesh_dst, &tmp, id.prev);
+
+ if (take_ownership) {
+ if (alloctype == CD_ASSIGN) {
+ CustomData_free_typemask(&mesh_src->vdata, mesh_src->totvert, ~mask->vmask);
+ CustomData_free_typemask(&mesh_src->edata, mesh_src->totedge, ~mask->emask);
+ CustomData_free_typemask(&mesh_src->ldata, mesh_src->totloop, ~mask->lmask);
+ CustomData_free_typemask(&mesh_src->pdata, mesh_src->totpoly, ~mask->pmask);
+ }
+ BKE_id_free(NULL, mesh_src);
+ }
}
/* This is a Mesh-based copy of DM_to_meshkey() */
void BKE_mesh_nomain_to_meshkey(Mesh *mesh_src, Mesh *mesh_dst, KeyBlock *kb)
{
- int a, totvert = mesh_src->totvert;
- float *fp;
- MVert *mvert;
+ int a, totvert = mesh_src->totvert;
+ float *fp;
+ MVert *mvert;
- if (totvert == 0 || mesh_dst->totvert == 0 || mesh_dst->totvert != totvert) {
- return;
- }
+ if (totvert == 0 || mesh_dst->totvert == 0 || mesh_dst->totvert != totvert) {
+ return;
+ }
- if (kb->data) MEM_freeN(kb->data);
- kb->data = MEM_malloc_arrayN(mesh_dst->key->elemsize, mesh_dst->totvert, "kb->data");
- kb->totelem = totvert;
+ if (kb->data)
+ MEM_freeN(kb->data);
+ kb->data = MEM_malloc_arrayN(mesh_dst->key->elemsize, mesh_dst->totvert, "kb->data");
+ kb->totelem = totvert;
- fp = kb->data;
- mvert = mesh_src->mvert;
+ fp = kb->data;
+ mvert = mesh_src->mvert;
- for (a = 0; a < kb->totelem; a++, fp += 3, mvert++) {
- copy_v3_v3(fp, mvert->co);
- }
+ for (a = 0; a < kb->totelem; a++, fp += 3, mvert++) {
+ copy_v3_v3(fp, mvert->co);
+ }
}
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index 1e4c9a6950a..2ef1a009321 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -74,14 +74,14 @@ static CLG_LogRef LOG = {"bke.mesh_evaluate"};
*/
static void mesh_calc_normals_vert_fallback(MVert *mverts, int numVerts)
{
- int i;
- for (i = 0; i < numVerts; i++) {
- MVert *mv = &mverts[i];
- float no[3];
+ int i;
+ for (i = 0; i < numVerts; i++) {
+ MVert *mv = &mverts[i];
+ float no[3];
- normalize_v3_v3(no, mv->co);
- normal_float_to_short_v3(mv->no, no);
- }
+ normalize_v3_v3(no, mv->co);
+ normal_float_to_short_v3(mv->no, no);
+ }
}
/* TODO(Sybren): we can probably rename this to BKE_mesh_calc_normals_mapping(),
@@ -89,265 +89,302 @@ static void mesh_calc_normals_vert_fallback(MVert *mverts, int numVerts)
* called anywhere. */
void BKE_mesh_calc_normals_mapping_simple(struct Mesh *mesh)
{
- const bool only_face_normals = CustomData_is_referenced_layer(&mesh->vdata, CD_MVERT);
+ const bool only_face_normals = CustomData_is_referenced_layer(&mesh->vdata, CD_MVERT);
- BKE_mesh_calc_normals_mapping_ex(
- mesh->mvert, mesh->totvert,
- mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, NULL,
- mesh->mface, mesh->totface, NULL, NULL,
- only_face_normals);
+ BKE_mesh_calc_normals_mapping_ex(mesh->mvert,
+ mesh->totvert,
+ mesh->mloop,
+ mesh->mpoly,
+ mesh->totloop,
+ mesh->totpoly,
+ NULL,
+ mesh->mface,
+ mesh->totface,
+ NULL,
+ NULL,
+ only_face_normals);
}
/* Calculate vertex and face normals, face normals are returned in *r_faceNors if non-NULL
* and vertex normals are stored in actual mverts.
*/
-void BKE_mesh_calc_normals_mapping(
- MVert *mverts, int numVerts,
- const MLoop *mloop, const MPoly *mpolys, int numLoops, int numPolys, float (*r_polyNors)[3],
- const MFace *mfaces, int numFaces, const int *origIndexFace, float (*r_faceNors)[3])
-{
- BKE_mesh_calc_normals_mapping_ex(
- mverts, numVerts, mloop, mpolys,
- numLoops, numPolys, r_polyNors, mfaces, numFaces,
- origIndexFace, r_faceNors, false);
+void BKE_mesh_calc_normals_mapping(MVert *mverts,
+ int numVerts,
+ const MLoop *mloop,
+ const MPoly *mpolys,
+ int numLoops,
+ int numPolys,
+ float (*r_polyNors)[3],
+ const MFace *mfaces,
+ int numFaces,
+ const int *origIndexFace,
+ float (*r_faceNors)[3])
+{
+ BKE_mesh_calc_normals_mapping_ex(mverts,
+ numVerts,
+ mloop,
+ mpolys,
+ numLoops,
+ numPolys,
+ r_polyNors,
+ mfaces,
+ numFaces,
+ origIndexFace,
+ r_faceNors,
+ false);
}
/* extended version of 'BKE_mesh_calc_normals_poly' with option not to calc vertex normals */
-void BKE_mesh_calc_normals_mapping_ex(
- MVert *mverts, int numVerts,
- const MLoop *mloop, const MPoly *mpolys,
- int numLoops, int numPolys, float (*r_polyNors)[3],
- const MFace *mfaces, int numFaces, const int *origIndexFace, float (*r_faceNors)[3],
- const bool only_face_normals)
-{
- float (*pnors)[3] = r_polyNors, (*fnors)[3] = r_faceNors;
- int i;
- const MFace *mf;
- const MPoly *mp;
-
- if (numPolys == 0) {
- if (only_face_normals == false) {
- mesh_calc_normals_vert_fallback(mverts, numVerts);
- }
- return;
- }
-
- /* if we are not calculating verts and no verts were passes then we have nothing to do */
- if ((only_face_normals == true) && (r_polyNors == NULL) && (r_faceNors == NULL)) {
- CLOG_WARN(&LOG, "called with nothing to do");
- return;
- }
-
- if (!pnors) pnors = MEM_calloc_arrayN((size_t)numPolys, sizeof(float[3]), __func__);
- /* if (!fnors) fnors = MEM_calloc_arrayN(numFaces, sizeof(float[3]), "face nors mesh.c"); */ /* NO NEED TO ALLOC YET */
-
-
- if (only_face_normals == false) {
- /* vertex normals are optional, they require some extra calculations,
- * so make them optional */
- BKE_mesh_calc_normals_poly(mverts, NULL, numVerts, mloop, mpolys, numLoops, numPolys, pnors, false);
- }
- else {
- /* only calc poly normals */
- mp = mpolys;
- for (i = 0; i < numPolys; i++, mp++) {
- BKE_mesh_calc_poly_normal(mp, mloop + mp->loopstart, mverts, pnors[i]);
- }
- }
-
- if (origIndexFace &&
- /* fnors == r_faceNors */ /* NO NEED TO ALLOC YET */
- fnors != NULL &&
- numFaces)
- {
- mf = mfaces;
- for (i = 0; i < numFaces; i++, mf++, origIndexFace++) {
- if (*origIndexFace < numPolys) {
- copy_v3_v3(fnors[i], pnors[*origIndexFace]);
- }
- else {
- /* eek, we're not corresponding to polys */
- CLOG_ERROR(&LOG, "tessellation face indices are incorrect. normals may look bad.");
- }
- }
- }
-
- if (pnors != r_polyNors) MEM_freeN(pnors);
- /* if (fnors != r_faceNors) MEM_freeN(fnors); */ /* NO NEED TO ALLOC YET */
-
- fnors = pnors = NULL;
-
+void BKE_mesh_calc_normals_mapping_ex(MVert *mverts,
+ int numVerts,
+ const MLoop *mloop,
+ const MPoly *mpolys,
+ int numLoops,
+ int numPolys,
+ float (*r_polyNors)[3],
+ const MFace *mfaces,
+ int numFaces,
+ const int *origIndexFace,
+ float (*r_faceNors)[3],
+ const bool only_face_normals)
+{
+ float(*pnors)[3] = r_polyNors, (*fnors)[3] = r_faceNors;
+ int i;
+ const MFace *mf;
+ const MPoly *mp;
+
+ if (numPolys == 0) {
+ if (only_face_normals == false) {
+ mesh_calc_normals_vert_fallback(mverts, numVerts);
+ }
+ return;
+ }
+
+ /* if we are not calculating verts and no verts were passes then we have nothing to do */
+ if ((only_face_normals == true) && (r_polyNors == NULL) && (r_faceNors == NULL)) {
+ CLOG_WARN(&LOG, "called with nothing to do");
+ return;
+ }
+
+ if (!pnors)
+ pnors = MEM_calloc_arrayN((size_t)numPolys, sizeof(float[3]), __func__);
+ /* if (!fnors) fnors = MEM_calloc_arrayN(numFaces, sizeof(float[3]), "face nors mesh.c"); */ /* NO NEED TO ALLOC YET */
+
+ if (only_face_normals == false) {
+ /* vertex normals are optional, they require some extra calculations,
+ * so make them optional */
+ BKE_mesh_calc_normals_poly(
+ mverts, NULL, numVerts, mloop, mpolys, numLoops, numPolys, pnors, false);
+ }
+ else {
+ /* only calc poly normals */
+ mp = mpolys;
+ for (i = 0; i < numPolys; i++, mp++) {
+ BKE_mesh_calc_poly_normal(mp, mloop + mp->loopstart, mverts, pnors[i]);
+ }
+ }
+
+ if (origIndexFace &&
+ /* fnors == r_faceNors */ /* NO NEED TO ALLOC YET */
+ fnors != NULL &&
+ numFaces) {
+ mf = mfaces;
+ for (i = 0; i < numFaces; i++, mf++, origIndexFace++) {
+ if (*origIndexFace < numPolys) {
+ copy_v3_v3(fnors[i], pnors[*origIndexFace]);
+ }
+ else {
+ /* eek, we're not corresponding to polys */
+ CLOG_ERROR(&LOG, "tessellation face indices are incorrect. normals may look bad.");
+ }
+ }
+ }
+
+ if (pnors != r_polyNors)
+ MEM_freeN(pnors);
+ /* if (fnors != r_faceNors) MEM_freeN(fnors); */ /* NO NEED TO ALLOC YET */
+
+ fnors = pnors = NULL;
}
typedef struct MeshCalcNormalsData {
- const MPoly *mpolys;
- const MLoop *mloop;
- MVert *mverts;
- float (*pnors)[3];
- float (*lnors_weighted)[3];
- float (*vnors)[3];
+ const MPoly *mpolys;
+ const MLoop *mloop;
+ MVert *mverts;
+ float (*pnors)[3];
+ float (*lnors_weighted)[3];
+ float (*vnors)[3];
} MeshCalcNormalsData;
-static void mesh_calc_normals_poly_cb(
- void *__restrict userdata,
- const int pidx,
- const ParallelRangeTLS *__restrict UNUSED(tls))
-{
- MeshCalcNormalsData *data = userdata;
- const MPoly *mp = &data->mpolys[pidx];
-
- BKE_mesh_calc_poly_normal(mp, data->mloop + mp->loopstart, data->mverts, data->pnors[pidx]);
-}
-
-static void mesh_calc_normals_poly_prepare_cb(
- void *__restrict userdata,
- const int pidx,
- const ParallelRangeTLS *__restrict UNUSED(tls))
-{
- MeshCalcNormalsData *data = userdata;
- const MPoly *mp = &data->mpolys[pidx];
- const MLoop *ml = &data->mloop[mp->loopstart];
- const MVert *mverts = data->mverts;
-
- float pnor_temp[3];
- float *pnor = data->pnors ? data->pnors[pidx] : pnor_temp;
- float (*lnors_weighted)[3] = data->lnors_weighted;
-
- const int nverts = mp->totloop;
- float (*edgevecbuf)[3] = BLI_array_alloca(edgevecbuf, (size_t)nverts);
- int i;
-
- /* Polygon Normal and edge-vector */
- /* inline version of #BKE_mesh_calc_poly_normal, also does edge-vectors */
- {
- int i_prev = nverts - 1;
- const float *v_prev = mverts[ml[i_prev].v].co;
- const float *v_curr;
-
- zero_v3(pnor);
- /* Newell's Method */
- for (i = 0; i < nverts; i++) {
- v_curr = mverts[ml[i].v].co;
- add_newell_cross_v3_v3v3(pnor, v_prev, v_curr);
-
- /* Unrelated to normalize, calculate edge-vector */
- sub_v3_v3v3(edgevecbuf[i_prev], v_prev, v_curr);
- normalize_v3(edgevecbuf[i_prev]);
- i_prev = i;
-
- v_prev = v_curr;
- }
- if (UNLIKELY(normalize_v3(pnor) == 0.0f)) {
- pnor[2] = 1.0f; /* other axes set to 0.0 */
- }
- }
-
- /* accumulate angle weighted face normal */
- /* inline version of #accumulate_vertex_normals_poly_v3,
- * split between this threaded callback and #mesh_calc_normals_poly_accum_cb. */
- {
- const float *prev_edge = edgevecbuf[nverts - 1];
-
- for (i = 0; i < nverts; i++) {
- const int lidx = mp->loopstart + i;
- const float *cur_edge = edgevecbuf[i];
-
- /* calculate angle between the two poly edges incident on
- * this vertex */
- const float fac = saacos(-dot_v3v3(cur_edge, prev_edge));
-
- /* Store for later accumulation */
- mul_v3_v3fl(lnors_weighted[lidx], pnor, fac);
-
- prev_edge = cur_edge;
- }
- }
-}
-
-static void mesh_calc_normals_poly_finalize_cb(
- void *__restrict userdata,
- const int vidx,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void mesh_calc_normals_poly_cb(void *__restrict userdata,
+ const int pidx,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- MeshCalcNormalsData *data = userdata;
-
- MVert *mv = &data->mverts[vidx];
- float *no = data->vnors[vidx];
-
- if (UNLIKELY(normalize_v3(no) == 0.0f)) {
- /* following Mesh convention; we use vertex coordinate itself for normal in this case */
- normalize_v3_v3(no, mv->co);
- }
+ MeshCalcNormalsData *data = userdata;
+ const MPoly *mp = &data->mpolys[pidx];
- normal_float_to_short_v3(mv->no, no);
+ BKE_mesh_calc_poly_normal(mp, data->mloop + mp->loopstart, data->mverts, data->pnors[pidx]);
}
-void BKE_mesh_calc_normals_poly(
- MVert *mverts, float (*r_vertnors)[3], int numVerts,
- const MLoop *mloop, const MPoly *mpolys,
- int numLoops, int numPolys, float (*r_polynors)[3],
- const bool only_face_normals)
+static void mesh_calc_normals_poly_prepare_cb(void *__restrict userdata,
+ const int pidx,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- float (*pnors)[3] = r_polynors;
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.min_iter_per_thread = 1024;
-
- if (only_face_normals) {
- BLI_assert((pnors != NULL) || (numPolys == 0));
- BLI_assert(r_vertnors == NULL);
+ MeshCalcNormalsData *data = userdata;
+ const MPoly *mp = &data->mpolys[pidx];
+ const MLoop *ml = &data->mloop[mp->loopstart];
+ const MVert *mverts = data->mverts;
- MeshCalcNormalsData data = {
- .mpolys = mpolys, .mloop = mloop, .mverts = mverts, .pnors = pnors,
- };
-
- BLI_task_parallel_range(0, numPolys, &data, mesh_calc_normals_poly_cb, &settings);
- return;
- }
-
- float (*vnors)[3] = r_vertnors;
- float (*lnors_weighted)[3] = MEM_malloc_arrayN((size_t)numLoops, sizeof(*lnors_weighted), __func__);
- bool free_vnors = false;
-
- /* first go through and calculate normals for all the polys */
- if (vnors == NULL) {
- vnors = MEM_calloc_arrayN((size_t)numVerts, sizeof(*vnors), __func__);
- free_vnors = true;
- }
- else {
- memset(vnors, 0, sizeof(*vnors) * (size_t)numVerts);
- }
-
- MeshCalcNormalsData data = {
- .mpolys = mpolys, .mloop = mloop, .mverts = mverts,
- .pnors = pnors, .lnors_weighted = lnors_weighted, .vnors = vnors,
- };
+ float pnor_temp[3];
+ float *pnor = data->pnors ? data->pnors[pidx] : pnor_temp;
+ float(*lnors_weighted)[3] = data->lnors_weighted;
- /* Compute poly normals, and prepare weighted loop normals. */
- BLI_task_parallel_range(0, numPolys, &data, mesh_calc_normals_poly_prepare_cb, &settings);
+ const int nverts = mp->totloop;
+ float(*edgevecbuf)[3] = BLI_array_alloca(edgevecbuf, (size_t)nverts);
+ int i;
- /* Actually accumulate weighted loop normals into vertex ones. */
- /* Unfortunately, not possible to thread that (not in a reasonable, totally lock- and barrier-free fashion),
- * since several loops will point to the same vertex... */
- for (int lidx = 0; lidx < numLoops; lidx++) {
- add_v3_v3(vnors[mloop[lidx].v], data.lnors_weighted[lidx]);
- }
+ /* Polygon Normal and edge-vector */
+ /* inline version of #BKE_mesh_calc_poly_normal, also does edge-vectors */
+ {
+ int i_prev = nverts - 1;
+ const float *v_prev = mverts[ml[i_prev].v].co;
+ const float *v_curr;
+
+ zero_v3(pnor);
+ /* Newell's Method */
+ for (i = 0; i < nverts; i++) {
+ v_curr = mverts[ml[i].v].co;
+ add_newell_cross_v3_v3v3(pnor, v_prev, v_curr);
+
+ /* Unrelated to normalize, calculate edge-vector */
+ sub_v3_v3v3(edgevecbuf[i_prev], v_prev, v_curr);
+ normalize_v3(edgevecbuf[i_prev]);
+ i_prev = i;
+
+ v_prev = v_curr;
+ }
+ if (UNLIKELY(normalize_v3(pnor) == 0.0f)) {
+ pnor[2] = 1.0f; /* other axes set to 0.0 */
+ }
+ }
+
+ /* accumulate angle weighted face normal */
+ /* inline version of #accumulate_vertex_normals_poly_v3,
+ * split between this threaded callback and #mesh_calc_normals_poly_accum_cb. */
+ {
+ const float *prev_edge = edgevecbuf[nverts - 1];
+
+ for (i = 0; i < nverts; i++) {
+ const int lidx = mp->loopstart + i;
+ const float *cur_edge = edgevecbuf[i];
+
+ /* calculate angle between the two poly edges incident on
+ * this vertex */
+ const float fac = saacos(-dot_v3v3(cur_edge, prev_edge));
+
+ /* Store for later accumulation */
+ mul_v3_v3fl(lnors_weighted[lidx], pnor, fac);
+
+ prev_edge = cur_edge;
+ }
+ }
+}
+
+static void mesh_calc_normals_poly_finalize_cb(void *__restrict userdata,
+ const int vidx,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ MeshCalcNormalsData *data = userdata;
+
+ MVert *mv = &data->mverts[vidx];
+ float *no = data->vnors[vidx];
+
+ if (UNLIKELY(normalize_v3(no) == 0.0f)) {
+ /* following Mesh convention; we use vertex coordinate itself for normal in this case */
+ normalize_v3_v3(no, mv->co);
+ }
+
+ normal_float_to_short_v3(mv->no, no);
+}
+
+void BKE_mesh_calc_normals_poly(MVert *mverts,
+ float (*r_vertnors)[3],
+ int numVerts,
+ const MLoop *mloop,
+ const MPoly *mpolys,
+ int numLoops,
+ int numPolys,
+ float (*r_polynors)[3],
+ const bool only_face_normals)
+{
+ float(*pnors)[3] = r_polynors;
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.min_iter_per_thread = 1024;
+
+ if (only_face_normals) {
+ BLI_assert((pnors != NULL) || (numPolys == 0));
+ BLI_assert(r_vertnors == NULL);
+
+ MeshCalcNormalsData data = {
+ .mpolys = mpolys,
+ .mloop = mloop,
+ .mverts = mverts,
+ .pnors = pnors,
+ };
+
+ BLI_task_parallel_range(0, numPolys, &data, mesh_calc_normals_poly_cb, &settings);
+ return;
+ }
+
+ float(*vnors)[3] = r_vertnors;
+ float(*lnors_weighted)[3] = MEM_malloc_arrayN(
+ (size_t)numLoops, sizeof(*lnors_weighted), __func__);
+ bool free_vnors = false;
+
+ /* first go through and calculate normals for all the polys */
+ if (vnors == NULL) {
+ vnors = MEM_calloc_arrayN((size_t)numVerts, sizeof(*vnors), __func__);
+ free_vnors = true;
+ }
+ else {
+ memset(vnors, 0, sizeof(*vnors) * (size_t)numVerts);
+ }
+
+ MeshCalcNormalsData data = {
+ .mpolys = mpolys,
+ .mloop = mloop,
+ .mverts = mverts,
+ .pnors = pnors,
+ .lnors_weighted = lnors_weighted,
+ .vnors = vnors,
+ };
+
+ /* Compute poly normals, and prepare weighted loop normals. */
+ BLI_task_parallel_range(0, numPolys, &data, mesh_calc_normals_poly_prepare_cb, &settings);
+
+ /* Actually accumulate weighted loop normals into vertex ones. */
+ /* Unfortunately, not possible to thread that (not in a reasonable, totally lock- and barrier-free fashion),
+ * since several loops will point to the same vertex... */
+ for (int lidx = 0; lidx < numLoops; lidx++) {
+ add_v3_v3(vnors[mloop[lidx].v], data.lnors_weighted[lidx]);
+ }
+
+ /* Normalize and validate computed vertex normals. */
+ BLI_task_parallel_range(0, numVerts, &data, mesh_calc_normals_poly_finalize_cb, &settings);
- /* Normalize and validate computed vertex normals. */
- BLI_task_parallel_range(0, numVerts, &data, mesh_calc_normals_poly_finalize_cb, &settings);
-
- if (free_vnors) {
- MEM_freeN(vnors);
- }
- MEM_freeN(lnors_weighted);
+ if (free_vnors) {
+ MEM_freeN(vnors);
+ }
+ MEM_freeN(lnors_weighted);
}
void BKE_mesh_ensure_normals(Mesh *mesh)
{
- if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) {
- BKE_mesh_calc_normals(mesh);
- }
- BLI_assert((mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) == 0);
+ if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) {
+ BKE_mesh_calc_normals(mesh);
+ }
+ BLI_assert((mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) == 0);
}
/**
@@ -355,185 +392,210 @@ void BKE_mesh_ensure_normals(Mesh *mesh)
*/
void BKE_mesh_ensure_normals_for_display(Mesh *mesh)
{
- float (*poly_nors)[3] = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
- const bool do_vert_normals = (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) != 0;
- const bool do_poly_normals = (mesh->runtime.cd_dirty_poly & CD_MASK_NORMAL || poly_nors == NULL);
+ float(*poly_nors)[3] = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
+ const bool do_vert_normals = (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) != 0;
+ const bool do_poly_normals = (mesh->runtime.cd_dirty_poly & CD_MASK_NORMAL || poly_nors == NULL);
- if (do_vert_normals || do_poly_normals) {
- const bool do_add_poly_nors_cddata = (poly_nors == NULL);
- if (do_add_poly_nors_cddata) {
- poly_nors = MEM_malloc_arrayN((size_t)mesh->totpoly, sizeof(*poly_nors), __func__);
- }
+ if (do_vert_normals || do_poly_normals) {
+ const bool do_add_poly_nors_cddata = (poly_nors == NULL);
+ if (do_add_poly_nors_cddata) {
+ poly_nors = MEM_malloc_arrayN((size_t)mesh->totpoly, sizeof(*poly_nors), __func__);
+ }
- /* calculate poly/vert normals */
- BKE_mesh_calc_normals_poly(
- mesh->mvert, NULL, mesh->totvert, mesh->mloop, mesh->mpoly,
- mesh->totloop, mesh->totpoly, poly_nors,
- !do_vert_normals);
+ /* calculate poly/vert normals */
+ BKE_mesh_calc_normals_poly(mesh->mvert,
+ NULL,
+ mesh->totvert,
+ mesh->mloop,
+ mesh->mpoly,
+ mesh->totloop,
+ mesh->totpoly,
+ poly_nors,
+ !do_vert_normals);
- if (do_add_poly_nors_cddata) {
- CustomData_add_layer(&mesh->pdata, CD_NORMAL, CD_ASSIGN, poly_nors, mesh->totpoly);
- }
+ if (do_add_poly_nors_cddata) {
+ CustomData_add_layer(&mesh->pdata, CD_NORMAL, CD_ASSIGN, poly_nors, mesh->totpoly);
+ }
- mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
- mesh->runtime.cd_dirty_poly &= ~CD_MASK_NORMAL;
- }
+ mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
+ mesh->runtime.cd_dirty_poly &= ~CD_MASK_NORMAL;
+ }
}
/* Note that this does not update the CD_NORMAL layer, but does update the normals in the CD_MVERT layer. */
void BKE_mesh_calc_normals(Mesh *mesh)
{
#ifdef DEBUG_TIME
- TIMEIT_START_AVERAGED(BKE_mesh_calc_normals);
+ TIMEIT_START_AVERAGED(BKE_mesh_calc_normals);
#endif
- BKE_mesh_calc_normals_poly(
- mesh->mvert, NULL, mesh->totvert,
- mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly,
- NULL, false);
+ BKE_mesh_calc_normals_poly(mesh->mvert,
+ NULL,
+ mesh->totvert,
+ mesh->mloop,
+ mesh->mpoly,
+ mesh->totloop,
+ mesh->totpoly,
+ NULL,
+ false);
#ifdef DEBUG_TIME
- TIMEIT_END_AVERAGED(BKE_mesh_calc_normals);
+ TIMEIT_END_AVERAGED(BKE_mesh_calc_normals);
#endif
- mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
+ mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
}
void BKE_mesh_calc_normals_tessface(
- MVert *mverts, int numVerts,
- const MFace *mfaces, int numFaces,
- float (*r_faceNors)[3])
-{
- float (*tnorms)[3] = MEM_calloc_arrayN((size_t)numVerts, sizeof(*tnorms), "tnorms");
- float (*fnors)[3] = (r_faceNors) ? r_faceNors : MEM_calloc_arrayN((size_t)numFaces, sizeof(*fnors), "meshnormals");
- int i;
-
- if (!tnorms || !fnors) {
- goto cleanup;
- }
-
- for (i = 0; i < numFaces; i++) {
- const MFace *mf = &mfaces[i];
- float *f_no = fnors[i];
- float *n4 = (mf->v4) ? tnorms[mf->v4] : NULL;
- const float *c4 = (mf->v4) ? mverts[mf->v4].co : NULL;
-
- if (mf->v4)
- normal_quad_v3(f_no, mverts[mf->v1].co, mverts[mf->v2].co, mverts[mf->v3].co, mverts[mf->v4].co);
- else
- normal_tri_v3(f_no, mverts[mf->v1].co, mverts[mf->v2].co, mverts[mf->v3].co);
-
- accumulate_vertex_normals_v3(
- tnorms[mf->v1], tnorms[mf->v2], tnorms[mf->v3], n4,
- f_no, mverts[mf->v1].co, mverts[mf->v2].co, mverts[mf->v3].co, c4);
- }
-
- /* following Mesh convention; we use vertex coordinate itself for normal in this case */
- for (i = 0; i < numVerts; i++) {
- MVert *mv = &mverts[i];
- float *no = tnorms[i];
-
- if (UNLIKELY(normalize_v3(no) == 0.0f)) {
- normalize_v3_v3(no, mv->co);
- }
-
- normal_float_to_short_v3(mv->no, no);
- }
+ MVert *mverts, int numVerts, const MFace *mfaces, int numFaces, float (*r_faceNors)[3])
+{
+ float(*tnorms)[3] = MEM_calloc_arrayN((size_t)numVerts, sizeof(*tnorms), "tnorms");
+ float(*fnors)[3] = (r_faceNors) ?
+ r_faceNors :
+ MEM_calloc_arrayN((size_t)numFaces, sizeof(*fnors), "meshnormals");
+ int i;
+
+ if (!tnorms || !fnors) {
+ goto cleanup;
+ }
+
+ for (i = 0; i < numFaces; i++) {
+ const MFace *mf = &mfaces[i];
+ float *f_no = fnors[i];
+ float *n4 = (mf->v4) ? tnorms[mf->v4] : NULL;
+ const float *c4 = (mf->v4) ? mverts[mf->v4].co : NULL;
+
+ if (mf->v4)
+ normal_quad_v3(
+ f_no, mverts[mf->v1].co, mverts[mf->v2].co, mverts[mf->v3].co, mverts[mf->v4].co);
+ else
+ normal_tri_v3(f_no, mverts[mf->v1].co, mverts[mf->v2].co, mverts[mf->v3].co);
+
+ accumulate_vertex_normals_v3(tnorms[mf->v1],
+ tnorms[mf->v2],
+ tnorms[mf->v3],
+ n4,
+ f_no,
+ mverts[mf->v1].co,
+ mverts[mf->v2].co,
+ mverts[mf->v3].co,
+ c4);
+ }
+
+ /* following Mesh convention; we use vertex coordinate itself for normal in this case */
+ for (i = 0; i < numVerts; i++) {
+ MVert *mv = &mverts[i];
+ float *no = tnorms[i];
+
+ if (UNLIKELY(normalize_v3(no) == 0.0f)) {
+ normalize_v3_v3(no, mv->co);
+ }
+
+ normal_float_to_short_v3(mv->no, no);
+ }
cleanup:
- MEM_freeN(tnorms);
-
- if (fnors != r_faceNors)
- MEM_freeN(fnors);
-}
-
-void BKE_mesh_calc_normals_looptri(
- MVert *mverts, int numVerts,
- const MLoop *mloop,
- const MLoopTri *looptri, int looptri_num,
- float (*r_tri_nors)[3])
-{
- float (*tnorms)[3] = MEM_calloc_arrayN((size_t)numVerts, sizeof(*tnorms), "tnorms");
- float (*fnors)[3] = (r_tri_nors) ? r_tri_nors : MEM_calloc_arrayN((size_t)looptri_num, sizeof(*fnors), "meshnormals");
- int i;
-
- if (!tnorms || !fnors) {
- goto cleanup;
- }
-
- for (i = 0; i < looptri_num; i++) {
- const MLoopTri *lt = &looptri[i];
- float *f_no = fnors[i];
- const unsigned int vtri[3] = {
- mloop[lt->tri[0]].v,
- mloop[lt->tri[1]].v,
- mloop[lt->tri[2]].v,
- };
-
- normal_tri_v3(
- f_no,
- mverts[vtri[0]].co, mverts[vtri[1]].co, mverts[vtri[2]].co);
-
- accumulate_vertex_normals_tri_v3(
- tnorms[vtri[0]], tnorms[vtri[1]], tnorms[vtri[2]],
- f_no, mverts[vtri[0]].co, mverts[vtri[1]].co, mverts[vtri[2]].co);
- }
-
- /* following Mesh convention; we use vertex coordinate itself for normal in this case */
- for (i = 0; i < numVerts; i++) {
- MVert *mv = &mverts[i];
- float *no = tnorms[i];
-
- if (UNLIKELY(normalize_v3(no) == 0.0f)) {
- normalize_v3_v3(no, mv->co);
- }
-
- normal_float_to_short_v3(mv->no, no);
- }
+ MEM_freeN(tnorms);
+
+ if (fnors != r_faceNors)
+ MEM_freeN(fnors);
+}
+
+void BKE_mesh_calc_normals_looptri(MVert *mverts,
+ int numVerts,
+ const MLoop *mloop,
+ const MLoopTri *looptri,
+ int looptri_num,
+ float (*r_tri_nors)[3])
+{
+ float(*tnorms)[3] = MEM_calloc_arrayN((size_t)numVerts, sizeof(*tnorms), "tnorms");
+ float(*fnors)[3] = (r_tri_nors) ?
+ r_tri_nors :
+ MEM_calloc_arrayN((size_t)looptri_num, sizeof(*fnors), "meshnormals");
+ int i;
+
+ if (!tnorms || !fnors) {
+ goto cleanup;
+ }
+
+ for (i = 0; i < looptri_num; i++) {
+ const MLoopTri *lt = &looptri[i];
+ float *f_no = fnors[i];
+ const unsigned int vtri[3] = {
+ mloop[lt->tri[0]].v,
+ mloop[lt->tri[1]].v,
+ mloop[lt->tri[2]].v,
+ };
+
+ normal_tri_v3(f_no, mverts[vtri[0]].co, mverts[vtri[1]].co, mverts[vtri[2]].co);
+
+ accumulate_vertex_normals_tri_v3(tnorms[vtri[0]],
+ tnorms[vtri[1]],
+ tnorms[vtri[2]],
+ f_no,
+ mverts[vtri[0]].co,
+ mverts[vtri[1]].co,
+ mverts[vtri[2]].co);
+ }
+
+ /* following Mesh convention; we use vertex coordinate itself for normal in this case */
+ for (i = 0; i < numVerts; i++) {
+ MVert *mv = &mverts[i];
+ float *no = tnorms[i];
+
+ if (UNLIKELY(normalize_v3(no) == 0.0f)) {
+ normalize_v3_v3(no, mv->co);
+ }
+
+ normal_float_to_short_v3(mv->no, no);
+ }
cleanup:
- MEM_freeN(tnorms);
+ MEM_freeN(tnorms);
- if (fnors != r_tri_nors)
- MEM_freeN(fnors);
+ if (fnors != r_tri_nors)
+ MEM_freeN(fnors);
}
-void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr, const int numLoops, const char data_type)
+void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr,
+ const int numLoops,
+ const char data_type)
{
- if (!(lnors_spacearr->lspacearr && lnors_spacearr->loops_pool)) {
- MemArena *mem;
+ if (!(lnors_spacearr->lspacearr && lnors_spacearr->loops_pool)) {
+ MemArena *mem;
- if (!lnors_spacearr->mem) {
- lnors_spacearr->mem = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
- }
- mem = lnors_spacearr->mem;
- lnors_spacearr->lspacearr = BLI_memarena_calloc(mem, sizeof(MLoopNorSpace *) * (size_t)numLoops);
- lnors_spacearr->loops_pool = BLI_memarena_alloc(mem, sizeof(LinkNode) * (size_t)numLoops);
+ if (!lnors_spacearr->mem) {
+ lnors_spacearr->mem = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+ }
+ mem = lnors_spacearr->mem;
+ lnors_spacearr->lspacearr = BLI_memarena_calloc(mem,
+ sizeof(MLoopNorSpace *) * (size_t)numLoops);
+ lnors_spacearr->loops_pool = BLI_memarena_alloc(mem, sizeof(LinkNode) * (size_t)numLoops);
- lnors_spacearr->num_spaces = 0;
- }
- BLI_assert(ELEM(data_type, MLNOR_SPACEARR_BMLOOP_PTR, MLNOR_SPACEARR_LOOP_INDEX));
- lnors_spacearr->data_type = data_type;
+ lnors_spacearr->num_spaces = 0;
+ }
+ BLI_assert(ELEM(data_type, MLNOR_SPACEARR_BMLOOP_PTR, MLNOR_SPACEARR_LOOP_INDEX));
+ lnors_spacearr->data_type = data_type;
}
void BKE_lnor_spacearr_clear(MLoopNorSpaceArray *lnors_spacearr)
{
- lnors_spacearr->num_spaces = 0;
- lnors_spacearr->lspacearr = NULL;
- lnors_spacearr->loops_pool = NULL;
- BLI_memarena_clear(lnors_spacearr->mem);
+ lnors_spacearr->num_spaces = 0;
+ lnors_spacearr->lspacearr = NULL;
+ lnors_spacearr->loops_pool = NULL;
+ BLI_memarena_clear(lnors_spacearr->mem);
}
void BKE_lnor_spacearr_free(MLoopNorSpaceArray *lnors_spacearr)
{
- lnors_spacearr->num_spaces = 0;
- lnors_spacearr->lspacearr = NULL;
- lnors_spacearr->loops_pool = NULL;
- BLI_memarena_free(lnors_spacearr->mem);
- lnors_spacearr->mem = NULL;
+ lnors_spacearr->num_spaces = 0;
+ lnors_spacearr->lspacearr = NULL;
+ lnors_spacearr->loops_pool = NULL;
+ BLI_memarena_free(lnors_spacearr->mem);
+ lnors_spacearr->mem = NULL;
}
MLoopNorSpace *BKE_lnor_space_create(MLoopNorSpaceArray *lnors_spacearr)
{
- lnors_spacearr->num_spaces++;
- return BLI_memarena_calloc(lnors_spacearr->mem, sizeof(MLoopNorSpace));
+ lnors_spacearr->num_spaces++;
+ return BLI_memarena_calloc(lnors_spacearr->mem, sizeof(MLoopNorSpace));
}
/* This threshold is a bit touchy (usual float precision issue), this value seems OK. */
@@ -543,69 +605,74 @@ MLoopNorSpace *BKE_lnor_space_create(MLoopNorSpaceArray *lnors_spacearr)
* Beware, this modifies ref_vec and other_vec in place!
* In case no valid space can be generated, ref_alpha and ref_beta are set to zero (which means 'use auto lnors').
*/
-void BKE_lnor_space_define(
- MLoopNorSpace *lnor_space, const float lnor[3],
- float vec_ref[3], float vec_other[3], BLI_Stack *edge_vectors)
-{
- const float pi2 = (float)M_PI * 2.0f;
- float tvec[3], dtp;
- const float dtp_ref = dot_v3v3(vec_ref, lnor);
- const float dtp_other = dot_v3v3(vec_other, lnor);
-
- if (UNLIKELY(fabsf(dtp_ref) >= LNOR_SPACE_TRIGO_THRESHOLD || fabsf(dtp_other) >= LNOR_SPACE_TRIGO_THRESHOLD)) {
- /* If vec_ref or vec_other are too much aligned with lnor, we can't build lnor space,
- * tag it as invalid and abort. */
- lnor_space->ref_alpha = lnor_space->ref_beta = 0.0f;
-
- if (edge_vectors) {
- BLI_stack_clear(edge_vectors);
- }
- return;
- }
-
- copy_v3_v3(lnor_space->vec_lnor, lnor);
-
- /* Compute ref alpha, average angle of all available edge vectors to lnor. */
- if (edge_vectors) {
- float alpha = 0.0f;
- int nbr = 0;
- while (!BLI_stack_is_empty(edge_vectors)) {
- const float *vec = BLI_stack_peek(edge_vectors);
- alpha += saacosf(dot_v3v3(vec, lnor));
- BLI_stack_discard(edge_vectors);
- nbr++;
- }
- /* Note: In theory, this could be 'nbr > 2', but there is one case where we only have two edges for
- * two loops: a smooth vertex with only two edges and two faces (our Monkey's nose has that, e.g.). */
- BLI_assert(nbr >= 2); /* This piece of code shall only be called for more than one loop... */
- lnor_space->ref_alpha = alpha / (float)nbr;
- }
- else {
- lnor_space->ref_alpha = (saacosf(dot_v3v3(vec_ref, lnor)) + saacosf(dot_v3v3(vec_other, lnor))) / 2.0f;
- }
-
- /* Project vec_ref on lnor's ortho plane. */
- mul_v3_v3fl(tvec, lnor, dtp_ref);
- sub_v3_v3(vec_ref, tvec);
- normalize_v3_v3(lnor_space->vec_ref, vec_ref);
-
- cross_v3_v3v3(tvec, lnor, lnor_space->vec_ref);
- normalize_v3_v3(lnor_space->vec_ortho, tvec);
-
- /* Project vec_other on lnor's ortho plane. */
- mul_v3_v3fl(tvec, lnor, dtp_other);
- sub_v3_v3(vec_other, tvec);
- normalize_v3(vec_other);
-
- /* Beta is angle between ref_vec and other_vec, around lnor. */
- dtp = dot_v3v3(lnor_space->vec_ref, vec_other);
- if (LIKELY(dtp < LNOR_SPACE_TRIGO_THRESHOLD)) {
- const float beta = saacos(dtp);
- lnor_space->ref_beta = (dot_v3v3(lnor_space->vec_ortho, vec_other) < 0.0f) ? pi2 - beta : beta;
- }
- else {
- lnor_space->ref_beta = pi2;
- }
+void BKE_lnor_space_define(MLoopNorSpace *lnor_space,
+ const float lnor[3],
+ float vec_ref[3],
+ float vec_other[3],
+ BLI_Stack *edge_vectors)
+{
+ const float pi2 = (float)M_PI * 2.0f;
+ float tvec[3], dtp;
+ const float dtp_ref = dot_v3v3(vec_ref, lnor);
+ const float dtp_other = dot_v3v3(vec_other, lnor);
+
+ if (UNLIKELY(fabsf(dtp_ref) >= LNOR_SPACE_TRIGO_THRESHOLD ||
+ fabsf(dtp_other) >= LNOR_SPACE_TRIGO_THRESHOLD)) {
+ /* If vec_ref or vec_other are too much aligned with lnor, we can't build lnor space,
+ * tag it as invalid and abort. */
+ lnor_space->ref_alpha = lnor_space->ref_beta = 0.0f;
+
+ if (edge_vectors) {
+ BLI_stack_clear(edge_vectors);
+ }
+ return;
+ }
+
+ copy_v3_v3(lnor_space->vec_lnor, lnor);
+
+ /* Compute ref alpha, average angle of all available edge vectors to lnor. */
+ if (edge_vectors) {
+ float alpha = 0.0f;
+ int nbr = 0;
+ while (!BLI_stack_is_empty(edge_vectors)) {
+ const float *vec = BLI_stack_peek(edge_vectors);
+ alpha += saacosf(dot_v3v3(vec, lnor));
+ BLI_stack_discard(edge_vectors);
+ nbr++;
+ }
+ /* Note: In theory, this could be 'nbr > 2', but there is one case where we only have two edges for
+ * two loops: a smooth vertex with only two edges and two faces (our Monkey's nose has that, e.g.). */
+ BLI_assert(nbr >= 2); /* This piece of code shall only be called for more than one loop... */
+ lnor_space->ref_alpha = alpha / (float)nbr;
+ }
+ else {
+ lnor_space->ref_alpha = (saacosf(dot_v3v3(vec_ref, lnor)) +
+ saacosf(dot_v3v3(vec_other, lnor))) /
+ 2.0f;
+ }
+
+ /* Project vec_ref on lnor's ortho plane. */
+ mul_v3_v3fl(tvec, lnor, dtp_ref);
+ sub_v3_v3(vec_ref, tvec);
+ normalize_v3_v3(lnor_space->vec_ref, vec_ref);
+
+ cross_v3_v3v3(tvec, lnor, lnor_space->vec_ref);
+ normalize_v3_v3(lnor_space->vec_ortho, tvec);
+
+ /* Project vec_other on lnor's ortho plane. */
+ mul_v3_v3fl(tvec, lnor, dtp_other);
+ sub_v3_v3(vec_other, tvec);
+ normalize_v3(vec_other);
+
+ /* Beta is angle between ref_vec and other_vec, around lnor. */
+ dtp = dot_v3v3(lnor_space->vec_ref, vec_other);
+ if (LIKELY(dtp < LNOR_SPACE_TRIGO_THRESHOLD)) {
+ const float beta = saacos(dtp);
+ lnor_space->ref_beta = (dot_v3v3(lnor_space->vec_ortho, vec_other) < 0.0f) ? pi2 - beta : beta;
+ }
+ else {
+ lnor_space->ref_beta = pi2;
+ }
}
/**
@@ -615,157 +682,166 @@ void BKE_lnor_space_define(
* If \a is_single is set, the BMLoop or loop index is directly stored in \a lnor_space->loops pointer (since there
* is only one loop in this fan), else it is added to the linked list of loops in the fan.
*/
-void BKE_lnor_space_add_loop(
- MLoopNorSpaceArray *lnors_spacearr, MLoopNorSpace *lnor_space,
- const int ml_index, void *bm_loop, const bool is_single)
-{
- BLI_assert((lnors_spacearr->data_type == MLNOR_SPACEARR_LOOP_INDEX && bm_loop == NULL) ||
- (lnors_spacearr->data_type == MLNOR_SPACEARR_BMLOOP_PTR && bm_loop != NULL));
-
- lnors_spacearr->lspacearr[ml_index] = lnor_space;
- if (bm_loop == NULL) {
- bm_loop = POINTER_FROM_INT(ml_index);
- }
- if (is_single) {
- BLI_assert(lnor_space->loops == NULL);
- lnor_space->flags |= MLNOR_SPACE_IS_SINGLE;
- lnor_space->loops = bm_loop;
- }
- else {
- BLI_assert((lnor_space->flags & MLNOR_SPACE_IS_SINGLE) == 0);
- BLI_linklist_prepend_nlink(&lnor_space->loops, bm_loop, &lnors_spacearr->loops_pool[ml_index]);
- }
+void BKE_lnor_space_add_loop(MLoopNorSpaceArray *lnors_spacearr,
+ MLoopNorSpace *lnor_space,
+ const int ml_index,
+ void *bm_loop,
+ const bool is_single)
+{
+ BLI_assert((lnors_spacearr->data_type == MLNOR_SPACEARR_LOOP_INDEX && bm_loop == NULL) ||
+ (lnors_spacearr->data_type == MLNOR_SPACEARR_BMLOOP_PTR && bm_loop != NULL));
+
+ lnors_spacearr->lspacearr[ml_index] = lnor_space;
+ if (bm_loop == NULL) {
+ bm_loop = POINTER_FROM_INT(ml_index);
+ }
+ if (is_single) {
+ BLI_assert(lnor_space->loops == NULL);
+ lnor_space->flags |= MLNOR_SPACE_IS_SINGLE;
+ lnor_space->loops = bm_loop;
+ }
+ else {
+ BLI_assert((lnor_space->flags & MLNOR_SPACE_IS_SINGLE) == 0);
+ BLI_linklist_prepend_nlink(&lnor_space->loops, bm_loop, &lnors_spacearr->loops_pool[ml_index]);
+ }
}
MINLINE float unit_short_to_float(const short val)
{
- return (float)val / (float)SHRT_MAX;
+ return (float)val / (float)SHRT_MAX;
}
MINLINE short unit_float_to_short(const float val)
{
- /* Rounding... */
- return (short)floorf(val * (float)SHRT_MAX + 0.5f);
-}
-
-void BKE_lnor_space_custom_data_to_normal(MLoopNorSpace *lnor_space, const short clnor_data[2], float r_custom_lnor[3])
-{
- /* NOP custom normal data or invalid lnor space, return. */
- if (clnor_data[0] == 0 || lnor_space->ref_alpha == 0.0f || lnor_space->ref_beta == 0.0f) {
- copy_v3_v3(r_custom_lnor, lnor_space->vec_lnor);
- return;
- }
-
- {
- /* TODO Check whether using sincosf() gives any noticeable benefit
- * (could not even get it working under linux though)! */
- const float pi2 = (float)(M_PI * 2.0);
- const float alphafac = unit_short_to_float(clnor_data[0]);
- const float alpha = (alphafac > 0.0f ? lnor_space->ref_alpha : pi2 - lnor_space->ref_alpha) * alphafac;
- const float betafac = unit_short_to_float(clnor_data[1]);
-
- mul_v3_v3fl(r_custom_lnor, lnor_space->vec_lnor, cosf(alpha));
-
- if (betafac == 0.0f) {
- madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ref, sinf(alpha));
- }
- else {
- const float sinalpha = sinf(alpha);
- const float beta = (betafac > 0.0f ? lnor_space->ref_beta : pi2 - lnor_space->ref_beta) * betafac;
- madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ref, sinalpha * cosf(beta));
- madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ortho, sinalpha * sinf(beta));
- }
- }
-}
-
-void BKE_lnor_space_custom_normal_to_data(MLoopNorSpace *lnor_space, const float custom_lnor[3], short r_clnor_data[2])
-{
- /* We use null vector as NOP custom normal (can be simpler than giving autocomputed lnor...). */
- if (is_zero_v3(custom_lnor) || compare_v3v3(lnor_space->vec_lnor, custom_lnor, 1e-4f)) {
- r_clnor_data[0] = r_clnor_data[1] = 0;
- return;
- }
-
- {
- const float pi2 = (float)(M_PI * 2.0);
- const float cos_alpha = dot_v3v3(lnor_space->vec_lnor, custom_lnor);
- float vec[3], cos_beta;
- float alpha;
-
- alpha = saacosf(cos_alpha);
- if (alpha > lnor_space->ref_alpha) {
- /* Note we could stick to [0, pi] range here, but makes decoding more complex, not worth it. */
- r_clnor_data[0] = unit_float_to_short(-(pi2 - alpha) / (pi2 - lnor_space->ref_alpha));
- }
- else {
- r_clnor_data[0] = unit_float_to_short(alpha / lnor_space->ref_alpha);
- }
-
- /* Project custom lnor on (vec_ref, vec_ortho) plane. */
- mul_v3_v3fl(vec, lnor_space->vec_lnor, -cos_alpha);
- add_v3_v3(vec, custom_lnor);
- normalize_v3(vec);
-
- cos_beta = dot_v3v3(lnor_space->vec_ref, vec);
-
- if (cos_beta < LNOR_SPACE_TRIGO_THRESHOLD) {
- float beta = saacosf(cos_beta);
- if (dot_v3v3(lnor_space->vec_ortho, vec) < 0.0f) {
- beta = pi2 - beta;
- }
-
- if (beta > lnor_space->ref_beta) {
- r_clnor_data[1] = unit_float_to_short(-(pi2 - beta) / (pi2 - lnor_space->ref_beta));
- }
- else {
- r_clnor_data[1] = unit_float_to_short(beta / lnor_space->ref_beta);
- }
- }
- else {
- r_clnor_data[1] = 0;
- }
- }
+ /* Rounding... */
+ return (short)floorf(val * (float)SHRT_MAX + 0.5f);
+}
+
+void BKE_lnor_space_custom_data_to_normal(MLoopNorSpace *lnor_space,
+ const short clnor_data[2],
+ float r_custom_lnor[3])
+{
+ /* NOP custom normal data or invalid lnor space, return. */
+ if (clnor_data[0] == 0 || lnor_space->ref_alpha == 0.0f || lnor_space->ref_beta == 0.0f) {
+ copy_v3_v3(r_custom_lnor, lnor_space->vec_lnor);
+ return;
+ }
+
+ {
+ /* TODO Check whether using sincosf() gives any noticeable benefit
+ * (could not even get it working under linux though)! */
+ const float pi2 = (float)(M_PI * 2.0);
+ const float alphafac = unit_short_to_float(clnor_data[0]);
+ const float alpha = (alphafac > 0.0f ? lnor_space->ref_alpha : pi2 - lnor_space->ref_alpha) *
+ alphafac;
+ const float betafac = unit_short_to_float(clnor_data[1]);
+
+ mul_v3_v3fl(r_custom_lnor, lnor_space->vec_lnor, cosf(alpha));
+
+ if (betafac == 0.0f) {
+ madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ref, sinf(alpha));
+ }
+ else {
+ const float sinalpha = sinf(alpha);
+ const float beta = (betafac > 0.0f ? lnor_space->ref_beta : pi2 - lnor_space->ref_beta) *
+ betafac;
+ madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ref, sinalpha * cosf(beta));
+ madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ortho, sinalpha * sinf(beta));
+ }
+ }
+}
+
+void BKE_lnor_space_custom_normal_to_data(MLoopNorSpace *lnor_space,
+ const float custom_lnor[3],
+ short r_clnor_data[2])
+{
+ /* We use null vector as NOP custom normal (can be simpler than giving autocomputed lnor...). */
+ if (is_zero_v3(custom_lnor) || compare_v3v3(lnor_space->vec_lnor, custom_lnor, 1e-4f)) {
+ r_clnor_data[0] = r_clnor_data[1] = 0;
+ return;
+ }
+
+ {
+ const float pi2 = (float)(M_PI * 2.0);
+ const float cos_alpha = dot_v3v3(lnor_space->vec_lnor, custom_lnor);
+ float vec[3], cos_beta;
+ float alpha;
+
+ alpha = saacosf(cos_alpha);
+ if (alpha > lnor_space->ref_alpha) {
+ /* Note we could stick to [0, pi] range here, but makes decoding more complex, not worth it. */
+ r_clnor_data[0] = unit_float_to_short(-(pi2 - alpha) / (pi2 - lnor_space->ref_alpha));
+ }
+ else {
+ r_clnor_data[0] = unit_float_to_short(alpha / lnor_space->ref_alpha);
+ }
+
+ /* Project custom lnor on (vec_ref, vec_ortho) plane. */
+ mul_v3_v3fl(vec, lnor_space->vec_lnor, -cos_alpha);
+ add_v3_v3(vec, custom_lnor);
+ normalize_v3(vec);
+
+ cos_beta = dot_v3v3(lnor_space->vec_ref, vec);
+
+ if (cos_beta < LNOR_SPACE_TRIGO_THRESHOLD) {
+ float beta = saacosf(cos_beta);
+ if (dot_v3v3(lnor_space->vec_ortho, vec) < 0.0f) {
+ beta = pi2 - beta;
+ }
+
+ if (beta > lnor_space->ref_beta) {
+ r_clnor_data[1] = unit_float_to_short(-(pi2 - beta) / (pi2 - lnor_space->ref_beta));
+ }
+ else {
+ r_clnor_data[1] = unit_float_to_short(beta / lnor_space->ref_beta);
+ }
+ }
+ else {
+ r_clnor_data[1] = 0;
+ }
+ }
}
#define LOOP_SPLIT_TASK_BLOCK_SIZE 1024
typedef struct LoopSplitTaskData {
- /* Specific to each instance (each task). */
- MLoopNorSpace *lnor_space; /* We have to create those outside of tasks, since afaik memarena is not threadsafe. */
- float (*lnor)[3];
- const MLoop *ml_curr;
- const MLoop *ml_prev;
- int ml_curr_index;
- int ml_prev_index;
- const int *e2l_prev; /* Also used a flag to switch between single or fan process! */
- int mp_index;
-
- /* This one is special, it's owned and managed by worker tasks, avoid to have to create it for each fan! */
- BLI_Stack *edge_vectors;
-
- char pad_c;
+ /* Specific to each instance (each task). */
+ MLoopNorSpace *
+ lnor_space; /* We have to create those outside of tasks, since afaik memarena is not threadsafe. */
+ float (*lnor)[3];
+ const MLoop *ml_curr;
+ const MLoop *ml_prev;
+ int ml_curr_index;
+ int ml_prev_index;
+ const int *e2l_prev; /* Also used a flag to switch between single or fan process! */
+ int mp_index;
+
+ /* This one is special, it's owned and managed by worker tasks, avoid to have to create it for each fan! */
+ BLI_Stack *edge_vectors;
+
+ char pad_c;
} LoopSplitTaskData;
typedef struct LoopSplitTaskDataCommon {
- /* Read/write.
- * Note we do not need to protect it, though, since two different tasks will *always* affect different
- * elements in the arrays. */
- MLoopNorSpaceArray *lnors_spacearr;
- float (*loopnors)[3];
- short (*clnors_data)[2];
-
- /* Read-only. */
- const MVert *mverts;
- const MEdge *medges;
- const MLoop *mloops;
- const MPoly *mpolys;
- int (*edge_to_loops)[2];
- int *loop_to_poly;
- const float (*polynors)[3];
-
- int numEdges;
- int numLoops;
- int numPolys;
+ /* Read/write.
+ * Note we do not need to protect it, though, since two different tasks will *always* affect different
+ * elements in the arrays. */
+ MLoopNorSpaceArray *lnors_spacearr;
+ float (*loopnors)[3];
+ short (*clnors_data)[2];
+
+ /* Read-only. */
+ const MVert *mverts;
+ const MEdge *medges;
+ const MLoop *mloops;
+ const MPoly *mpolys;
+ int (*edge_to_loops)[2];
+ int *loop_to_poly;
+ const float (*polynors)[3];
+
+ int numEdges;
+ int numLoops;
+ int numPolys;
} LoopSplitTaskDataCommon;
#define INDEX_UNSET INT_MIN
@@ -773,714 +849,753 @@ typedef struct LoopSplitTaskDataCommon {
/* See comment about edge_to_loops below. */
#define IS_EDGE_SHARP(_e2l) (ELEM((_e2l)[1], INDEX_UNSET, INDEX_INVALID))
-static void mesh_edges_sharp_tag(
- LoopSplitTaskDataCommon *data,
- const bool check_angle, const float split_angle, const bool do_sharp_edges_tag)
-{
- const MVert *mverts = data->mverts;
- const MEdge *medges = data->medges;
- const MLoop *mloops = data->mloops;
-
- const MPoly *mpolys = data->mpolys;
-
- const int numEdges = data->numEdges;
- const int numPolys = data->numPolys;
-
- float (*loopnors)[3] = data->loopnors; /* Note: loopnors may be NULL here. */
- const float (*polynors)[3] = data->polynors;
-
- int (*edge_to_loops)[2] = data->edge_to_loops;
- int *loop_to_poly = data->loop_to_poly;
-
- BLI_bitmap *sharp_edges = do_sharp_edges_tag ? BLI_BITMAP_NEW(numEdges, __func__) : NULL;
-
- const MPoly *mp;
- int mp_index;
-
- const float split_angle_cos = check_angle ? cosf(split_angle) : -1.0f;
-
- for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) {
- const MLoop *ml_curr;
- int *e2l;
- int ml_curr_index = mp->loopstart;
- const int ml_last_index = (ml_curr_index + mp->totloop) - 1;
-
- ml_curr = &mloops[ml_curr_index];
-
- for (; ml_curr_index <= ml_last_index; ml_curr++, ml_curr_index++) {
- e2l = edge_to_loops[ml_curr->e];
-
- loop_to_poly[ml_curr_index] = mp_index;
-
- /* Pre-populate all loop normals as if their verts were all-smooth, this way we don't have to compute
- * those later!
- */
- if (loopnors) {
- normal_short_to_float_v3(loopnors[ml_curr_index], mverts[ml_curr->v].no);
- }
-
- /* Check whether current edge might be smooth or sharp */
- if ((e2l[0] | e2l[1]) == 0) {
- /* 'Empty' edge until now, set e2l[0] (and e2l[1] to INDEX_UNSET to tag it as unset). */
- e2l[0] = ml_curr_index;
- /* We have to check this here too, else we might miss some flat faces!!! */
- e2l[1] = (mp->flag & ME_SMOOTH) ? INDEX_UNSET : INDEX_INVALID;
- }
- else if (e2l[1] == INDEX_UNSET) {
- const bool is_angle_sharp = (
- check_angle &&
- dot_v3v3(polynors[loop_to_poly[e2l[0]]], polynors[mp_index]) < split_angle_cos);
-
- /* Second loop using this edge, time to test its sharpness.
- * An edge is sharp if it is tagged as such, or its face is not smooth,
- * or both poly have opposed (flipped) normals, i.e. both loops on the same edge share the same vertex,
- * or angle between both its polys' normals is above split_angle value.
- */
- if (!(mp->flag & ME_SMOOTH) || (medges[ml_curr->e].flag & ME_SHARP) ||
- ml_curr->v == mloops[e2l[0]].v ||
- is_angle_sharp)
- {
- /* Note: we are sure that loop != 0 here ;) */
- e2l[1] = INDEX_INVALID;
-
- /* We want to avoid tagging edges as sharp when it is already defined as such by
- * other causes than angle threshold... */
- if (do_sharp_edges_tag && is_angle_sharp) {
- BLI_BITMAP_SET(sharp_edges, ml_curr->e, true);
- }
- }
- else {
- e2l[1] = ml_curr_index;
- }
- }
- else if (!IS_EDGE_SHARP(e2l)) {
- /* More than two loops using this edge, tag as sharp if not yet done. */
- e2l[1] = INDEX_INVALID;
-
- /* We want to avoid tagging edges as sharp when it is already defined as such by
- * other causes than angle threshold... */
- if (do_sharp_edges_tag) {
- BLI_BITMAP_SET(sharp_edges, ml_curr->e, false);
- }
- }
- /* Else, edge is already 'disqualified' (i.e. sharp)! */
- }
- }
-
- /* If requested, do actual tagging of edges as sharp in another loop. */
- if (do_sharp_edges_tag) {
- MEdge *me;
- int me_index;
- for (me = (MEdge *)medges, me_index = 0; me_index < numEdges; me++, me_index++) {
- if (BLI_BITMAP_TEST(sharp_edges, me_index)) {
- me->flag |= ME_SHARP;
- }
- }
-
- MEM_freeN(sharp_edges);
- }
+static void mesh_edges_sharp_tag(LoopSplitTaskDataCommon *data,
+ const bool check_angle,
+ const float split_angle,
+ const bool do_sharp_edges_tag)
+{
+ const MVert *mverts = data->mverts;
+ const MEdge *medges = data->medges;
+ const MLoop *mloops = data->mloops;
+
+ const MPoly *mpolys = data->mpolys;
+
+ const int numEdges = data->numEdges;
+ const int numPolys = data->numPolys;
+
+ float(*loopnors)[3] = data->loopnors; /* Note: loopnors may be NULL here. */
+ const float(*polynors)[3] = data->polynors;
+
+ int(*edge_to_loops)[2] = data->edge_to_loops;
+ int *loop_to_poly = data->loop_to_poly;
+
+ BLI_bitmap *sharp_edges = do_sharp_edges_tag ? BLI_BITMAP_NEW(numEdges, __func__) : NULL;
+
+ const MPoly *mp;
+ int mp_index;
+
+ const float split_angle_cos = check_angle ? cosf(split_angle) : -1.0f;
+
+ for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) {
+ const MLoop *ml_curr;
+ int *e2l;
+ int ml_curr_index = mp->loopstart;
+ const int ml_last_index = (ml_curr_index + mp->totloop) - 1;
+
+ ml_curr = &mloops[ml_curr_index];
+
+ for (; ml_curr_index <= ml_last_index; ml_curr++, ml_curr_index++) {
+ e2l = edge_to_loops[ml_curr->e];
+
+ loop_to_poly[ml_curr_index] = mp_index;
+
+ /* Pre-populate all loop normals as if their verts were all-smooth, this way we don't have to compute
+ * those later!
+ */
+ if (loopnors) {
+ normal_short_to_float_v3(loopnors[ml_curr_index], mverts[ml_curr->v].no);
+ }
+
+ /* Check whether current edge might be smooth or sharp */
+ if ((e2l[0] | e2l[1]) == 0) {
+ /* 'Empty' edge until now, set e2l[0] (and e2l[1] to INDEX_UNSET to tag it as unset). */
+ e2l[0] = ml_curr_index;
+ /* We have to check this here too, else we might miss some flat faces!!! */
+ e2l[1] = (mp->flag & ME_SMOOTH) ? INDEX_UNSET : INDEX_INVALID;
+ }
+ else if (e2l[1] == INDEX_UNSET) {
+ const bool is_angle_sharp = (check_angle &&
+ dot_v3v3(polynors[loop_to_poly[e2l[0]]], polynors[mp_index]) <
+ split_angle_cos);
+
+ /* Second loop using this edge, time to test its sharpness.
+ * An edge is sharp if it is tagged as such, or its face is not smooth,
+ * or both poly have opposed (flipped) normals, i.e. both loops on the same edge share the same vertex,
+ * or angle between both its polys' normals is above split_angle value.
+ */
+ if (!(mp->flag & ME_SMOOTH) || (medges[ml_curr->e].flag & ME_SHARP) ||
+ ml_curr->v == mloops[e2l[0]].v || is_angle_sharp) {
+ /* Note: we are sure that loop != 0 here ;) */
+ e2l[1] = INDEX_INVALID;
+
+ /* We want to avoid tagging edges as sharp when it is already defined as such by
+ * other causes than angle threshold... */
+ if (do_sharp_edges_tag && is_angle_sharp) {
+ BLI_BITMAP_SET(sharp_edges, ml_curr->e, true);
+ }
+ }
+ else {
+ e2l[1] = ml_curr_index;
+ }
+ }
+ else if (!IS_EDGE_SHARP(e2l)) {
+ /* More than two loops using this edge, tag as sharp if not yet done. */
+ e2l[1] = INDEX_INVALID;
+
+ /* We want to avoid tagging edges as sharp when it is already defined as such by
+ * other causes than angle threshold... */
+ if (do_sharp_edges_tag) {
+ BLI_BITMAP_SET(sharp_edges, ml_curr->e, false);
+ }
+ }
+ /* Else, edge is already 'disqualified' (i.e. sharp)! */
+ }
+ }
+
+ /* If requested, do actual tagging of edges as sharp in another loop. */
+ if (do_sharp_edges_tag) {
+ MEdge *me;
+ int me_index;
+ for (me = (MEdge *)medges, me_index = 0; me_index < numEdges; me++, me_index++) {
+ if (BLI_BITMAP_TEST(sharp_edges, me_index)) {
+ me->flag |= ME_SHARP;
+ }
+ }
+
+ MEM_freeN(sharp_edges);
+ }
}
/** Define sharp edges as needed to mimic 'autosmooth' from angle threshold.
*
* Used when defining an empty custom loop normals data layer, to keep same shading as with autosmooth!
*/
-void BKE_edges_sharp_from_angle_set(
- const struct MVert *mverts, const int UNUSED(numVerts),
- struct MEdge *medges, const int numEdges,
- struct MLoop *mloops, const int numLoops,
- struct MPoly *mpolys, const float (*polynors)[3], const int numPolys,
- const float split_angle)
-{
- if (split_angle >= (float)M_PI) {
- /* Nothing to do! */
- return;
- }
-
- /* Mapping edge -> loops. See BKE_mesh_normals_loop_split() for details. */
- int (*edge_to_loops)[2] = MEM_calloc_arrayN((size_t)numEdges, sizeof(*edge_to_loops), __func__);
-
- /* Simple mapping from a loop to its polygon index. */
- int *loop_to_poly = MEM_malloc_arrayN((size_t)numLoops, sizeof(*loop_to_poly), __func__);
-
- LoopSplitTaskDataCommon common_data = {
- .mverts = mverts,
- .medges = medges,
- .mloops = mloops,
- .mpolys = mpolys,
- .edge_to_loops = edge_to_loops,
- .loop_to_poly = loop_to_poly,
- .polynors = polynors,
- .numEdges = numEdges,
- .numPolys = numPolys,
- };
-
- mesh_edges_sharp_tag(&common_data, true, split_angle, true);
-
- MEM_freeN(edge_to_loops);
- MEM_freeN(loop_to_poly);
-}
-
-void BKE_mesh_loop_manifold_fan_around_vert_next(
- const MLoop *mloops, const MPoly *mpolys,
- const int *loop_to_poly, const int *e2lfan_curr, const uint mv_pivot_index,
- const MLoop **r_mlfan_curr, int *r_mlfan_curr_index, int *r_mlfan_vert_index, int *r_mpfan_curr_index)
-{
- const MLoop *mlfan_next;
- const MPoly *mpfan_next;
-
- /* Warning! This is rather complex!
- * We have to find our next edge around the vertex (fan mode).
- * First we find the next loop, which is either previous or next to mlfan_curr_index, depending
- * whether both loops using current edge are in the same direction or not, and whether
- * mlfan_curr_index actually uses the vertex we are fanning around!
- * mlfan_curr_index is the index of mlfan_next here, and mlfan_next is not the real next one
- * (i.e. not the future mlfan_curr)...
- */
- *r_mlfan_curr_index = (e2lfan_curr[0] == *r_mlfan_curr_index) ? e2lfan_curr[1] : e2lfan_curr[0];
- *r_mpfan_curr_index = loop_to_poly[*r_mlfan_curr_index];
-
- BLI_assert(*r_mlfan_curr_index >= 0);
- BLI_assert(*r_mpfan_curr_index >= 0);
-
- mlfan_next = &mloops[*r_mlfan_curr_index];
- mpfan_next = &mpolys[*r_mpfan_curr_index];
- if (((*r_mlfan_curr)->v == mlfan_next->v && (*r_mlfan_curr)->v == mv_pivot_index) ||
- ((*r_mlfan_curr)->v != mlfan_next->v && (*r_mlfan_curr)->v != mv_pivot_index))
- {
- /* We need the previous loop, but current one is our vertex's loop. */
- *r_mlfan_vert_index = *r_mlfan_curr_index;
- if (--(*r_mlfan_curr_index) < mpfan_next->loopstart) {
- *r_mlfan_curr_index = mpfan_next->loopstart + mpfan_next->totloop - 1;
- }
- }
- else {
- /* We need the next loop, which is also our vertex's loop. */
- if (++(*r_mlfan_curr_index) >= mpfan_next->loopstart + mpfan_next->totloop) {
- *r_mlfan_curr_index = mpfan_next->loopstart;
- }
- *r_mlfan_vert_index = *r_mlfan_curr_index;
- }
- *r_mlfan_curr = &mloops[*r_mlfan_curr_index];
- /* And now we are back in sync, mlfan_curr_index is the index of mlfan_curr! Pff! */
+void BKE_edges_sharp_from_angle_set(const struct MVert *mverts,
+ const int UNUSED(numVerts),
+ struct MEdge *medges,
+ const int numEdges,
+ struct MLoop *mloops,
+ const int numLoops,
+ struct MPoly *mpolys,
+ const float (*polynors)[3],
+ const int numPolys,
+ const float split_angle)
+{
+ if (split_angle >= (float)M_PI) {
+ /* Nothing to do! */
+ return;
+ }
+
+ /* Mapping edge -> loops. See BKE_mesh_normals_loop_split() for details. */
+ int(*edge_to_loops)[2] = MEM_calloc_arrayN((size_t)numEdges, sizeof(*edge_to_loops), __func__);
+
+ /* Simple mapping from a loop to its polygon index. */
+ int *loop_to_poly = MEM_malloc_arrayN((size_t)numLoops, sizeof(*loop_to_poly), __func__);
+
+ LoopSplitTaskDataCommon common_data = {
+ .mverts = mverts,
+ .medges = medges,
+ .mloops = mloops,
+ .mpolys = mpolys,
+ .edge_to_loops = edge_to_loops,
+ .loop_to_poly = loop_to_poly,
+ .polynors = polynors,
+ .numEdges = numEdges,
+ .numPolys = numPolys,
+ };
+
+ mesh_edges_sharp_tag(&common_data, true, split_angle, true);
+
+ MEM_freeN(edge_to_loops);
+ MEM_freeN(loop_to_poly);
+}
+
+void BKE_mesh_loop_manifold_fan_around_vert_next(const MLoop *mloops,
+ const MPoly *mpolys,
+ const int *loop_to_poly,
+ const int *e2lfan_curr,
+ const uint mv_pivot_index,
+ const MLoop **r_mlfan_curr,
+ int *r_mlfan_curr_index,
+ int *r_mlfan_vert_index,
+ int *r_mpfan_curr_index)
+{
+ const MLoop *mlfan_next;
+ const MPoly *mpfan_next;
+
+ /* Warning! This is rather complex!
+ * We have to find our next edge around the vertex (fan mode).
+ * First we find the next loop, which is either previous or next to mlfan_curr_index, depending
+ * whether both loops using current edge are in the same direction or not, and whether
+ * mlfan_curr_index actually uses the vertex we are fanning around!
+ * mlfan_curr_index is the index of mlfan_next here, and mlfan_next is not the real next one
+ * (i.e. not the future mlfan_curr)...
+ */
+ *r_mlfan_curr_index = (e2lfan_curr[0] == *r_mlfan_curr_index) ? e2lfan_curr[1] : e2lfan_curr[0];
+ *r_mpfan_curr_index = loop_to_poly[*r_mlfan_curr_index];
+
+ BLI_assert(*r_mlfan_curr_index >= 0);
+ BLI_assert(*r_mpfan_curr_index >= 0);
+
+ mlfan_next = &mloops[*r_mlfan_curr_index];
+ mpfan_next = &mpolys[*r_mpfan_curr_index];
+ if (((*r_mlfan_curr)->v == mlfan_next->v && (*r_mlfan_curr)->v == mv_pivot_index) ||
+ ((*r_mlfan_curr)->v != mlfan_next->v && (*r_mlfan_curr)->v != mv_pivot_index)) {
+ /* We need the previous loop, but current one is our vertex's loop. */
+ *r_mlfan_vert_index = *r_mlfan_curr_index;
+ if (--(*r_mlfan_curr_index) < mpfan_next->loopstart) {
+ *r_mlfan_curr_index = mpfan_next->loopstart + mpfan_next->totloop - 1;
+ }
+ }
+ else {
+ /* We need the next loop, which is also our vertex's loop. */
+ if (++(*r_mlfan_curr_index) >= mpfan_next->loopstart + mpfan_next->totloop) {
+ *r_mlfan_curr_index = mpfan_next->loopstart;
+ }
+ *r_mlfan_vert_index = *r_mlfan_curr_index;
+ }
+ *r_mlfan_curr = &mloops[*r_mlfan_curr_index];
+ /* And now we are back in sync, mlfan_curr_index is the index of mlfan_curr! Pff! */
}
static void split_loop_nor_single_do(LoopSplitTaskDataCommon *common_data, LoopSplitTaskData *data)
{
- MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr;
- short (*clnors_data)[2] = common_data->clnors_data;
-
- const MVert *mverts = common_data->mverts;
- const MEdge *medges = common_data->medges;
- const float (*polynors)[3] = common_data->polynors;
-
- MLoopNorSpace *lnor_space = data->lnor_space;
- float (*lnor)[3] = data->lnor;
- const MLoop *ml_curr = data->ml_curr;
- const MLoop *ml_prev = data->ml_prev;
- const int ml_curr_index = data->ml_curr_index;
-#if 0 /* Not needed for 'single' loop. */
- const int ml_prev_index = data->ml_prev_index;
- const int *e2l_prev = data->e2l_prev;
+ MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr;
+ short(*clnors_data)[2] = common_data->clnors_data;
+
+ const MVert *mverts = common_data->mverts;
+ const MEdge *medges = common_data->medges;
+ const float(*polynors)[3] = common_data->polynors;
+
+ MLoopNorSpace *lnor_space = data->lnor_space;
+ float(*lnor)[3] = data->lnor;
+ const MLoop *ml_curr = data->ml_curr;
+ const MLoop *ml_prev = data->ml_prev;
+ const int ml_curr_index = data->ml_curr_index;
+#if 0 /* Not needed for 'single' loop. */
+ const int ml_prev_index = data->ml_prev_index;
+ const int *e2l_prev = data->e2l_prev;
#endif
- const int mp_index = data->mp_index;
+ const int mp_index = data->mp_index;
- /* Simple case (both edges around that vertex are sharp in current polygon),
- * this loop just takes its poly normal.
- */
- copy_v3_v3(*lnor, polynors[mp_index]);
+ /* Simple case (both edges around that vertex are sharp in current polygon),
+ * this loop just takes its poly normal.
+ */
+ copy_v3_v3(*lnor, polynors[mp_index]);
-// printf("BASIC: handling loop %d / edge %d / vert %d / poly %d\n", ml_curr_index, ml_curr->e, ml_curr->v, mp_index);
+ // printf("BASIC: handling loop %d / edge %d / vert %d / poly %d\n", ml_curr_index, ml_curr->e, ml_curr->v, mp_index);
- /* If needed, generate this (simple!) lnor space. */
- if (lnors_spacearr) {
- float vec_curr[3], vec_prev[3];
+ /* If needed, generate this (simple!) lnor space. */
+ if (lnors_spacearr) {
+ float vec_curr[3], vec_prev[3];
- const unsigned int mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */
- const MVert *mv_pivot = &mverts[mv_pivot_index];
- const MEdge *me_curr = &medges[ml_curr->e];
- const MVert *mv_2 = (me_curr->v1 == mv_pivot_index) ? &mverts[me_curr->v2] : &mverts[me_curr->v1];
- const MEdge *me_prev = &medges[ml_prev->e];
- const MVert *mv_3 = (me_prev->v1 == mv_pivot_index) ? &mverts[me_prev->v2] : &mverts[me_prev->v1];
+ const unsigned int mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */
+ const MVert *mv_pivot = &mverts[mv_pivot_index];
+ const MEdge *me_curr = &medges[ml_curr->e];
+ const MVert *mv_2 = (me_curr->v1 == mv_pivot_index) ? &mverts[me_curr->v2] :
+ &mverts[me_curr->v1];
+ const MEdge *me_prev = &medges[ml_prev->e];
+ const MVert *mv_3 = (me_prev->v1 == mv_pivot_index) ? &mverts[me_prev->v2] :
+ &mverts[me_prev->v1];
- sub_v3_v3v3(vec_curr, mv_2->co, mv_pivot->co);
- normalize_v3(vec_curr);
- sub_v3_v3v3(vec_prev, mv_3->co, mv_pivot->co);
- normalize_v3(vec_prev);
+ sub_v3_v3v3(vec_curr, mv_2->co, mv_pivot->co);
+ normalize_v3(vec_curr);
+ sub_v3_v3v3(vec_prev, mv_3->co, mv_pivot->co);
+ normalize_v3(vec_prev);
- BKE_lnor_space_define(lnor_space, *lnor, vec_curr, vec_prev, NULL);
- /* We know there is only one loop in this space, no need to create a linklist in this case... */
- BKE_lnor_space_add_loop(lnors_spacearr, lnor_space, ml_curr_index, NULL, true);
+ BKE_lnor_space_define(lnor_space, *lnor, vec_curr, vec_prev, NULL);
+ /* We know there is only one loop in this space, no need to create a linklist in this case... */
+ BKE_lnor_space_add_loop(lnors_spacearr, lnor_space, ml_curr_index, NULL, true);
- if (clnors_data) {
- BKE_lnor_space_custom_data_to_normal(lnor_space, clnors_data[ml_curr_index], *lnor);
- }
- }
+ if (clnors_data) {
+ BKE_lnor_space_custom_data_to_normal(lnor_space, clnors_data[ml_curr_index], *lnor);
+ }
+ }
}
static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSplitTaskData *data)
{
- MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr;
- float (*loopnors)[3] = common_data->loopnors;
- short (*clnors_data)[2] = common_data->clnors_data;
-
- const MVert *mverts = common_data->mverts;
- const MEdge *medges = common_data->medges;
- const MLoop *mloops = common_data->mloops;
- const MPoly *mpolys = common_data->mpolys;
- const int (*edge_to_loops)[2] = common_data->edge_to_loops;
- const int *loop_to_poly = common_data->loop_to_poly;
- const float (*polynors)[3] = common_data->polynors;
-
- MLoopNorSpace *lnor_space = data->lnor_space;
-#if 0 /* Not needed for 'fan' loops. */
- float (*lnor)[3] = data->lnor;
+ MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr;
+ float(*loopnors)[3] = common_data->loopnors;
+ short(*clnors_data)[2] = common_data->clnors_data;
+
+ const MVert *mverts = common_data->mverts;
+ const MEdge *medges = common_data->medges;
+ const MLoop *mloops = common_data->mloops;
+ const MPoly *mpolys = common_data->mpolys;
+ const int(*edge_to_loops)[2] = common_data->edge_to_loops;
+ const int *loop_to_poly = common_data->loop_to_poly;
+ const float(*polynors)[3] = common_data->polynors;
+
+ MLoopNorSpace *lnor_space = data->lnor_space;
+#if 0 /* Not needed for 'fan' loops. */
+ float (*lnor)[3] = data->lnor;
#endif
- const MLoop *ml_curr = data->ml_curr;
- const MLoop *ml_prev = data->ml_prev;
- const int ml_curr_index = data->ml_curr_index;
- const int ml_prev_index = data->ml_prev_index;
- const int mp_index = data->mp_index;
- const int *e2l_prev = data->e2l_prev;
-
- BLI_Stack *edge_vectors = data->edge_vectors;
-
- /* Gah... We have to fan around current vertex, until we find the other non-smooth edge,
- * and accumulate face normals into the vertex!
- * Note in case this vertex has only one sharp edges, this is a waste because the normal is the same as
- * the vertex normal, but I do not see any easy way to detect that (would need to count number
- * of sharp edges per vertex, I doubt the additional memory usage would be worth it, especially as
- * it should not be a common case in real-life meshes anyway).
- */
- const unsigned int mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */
- const MVert *mv_pivot = &mverts[mv_pivot_index];
- const MEdge *me_org = &medges[ml_curr->e]; /* ml_curr would be mlfan_prev if we needed that one */
- const int *e2lfan_curr;
- float vec_curr[3], vec_prev[3], vec_org[3];
- const MLoop *mlfan_curr;
- float lnor[3] = {0.0f, 0.0f, 0.0f};
- /* mlfan_vert_index: the loop of our current edge might not be the loop of our current vertex! */
- int mlfan_curr_index, mlfan_vert_index, mpfan_curr_index;
-
- /* We validate clnors data on the fly - cheapest way to do! */
- int clnors_avg[2] = {0, 0};
- short (*clnor_ref)[2] = NULL;
- int clnors_nbr = 0;
- bool clnors_invalid = false;
-
- /* Temp loop normal stack. */
- BLI_SMALLSTACK_DECLARE(normal, float *);
- /* Temp clnors stack. */
- BLI_SMALLSTACK_DECLARE(clnors, short *);
-
- e2lfan_curr = e2l_prev;
- mlfan_curr = ml_prev;
- mlfan_curr_index = ml_prev_index;
- mlfan_vert_index = ml_curr_index;
- mpfan_curr_index = mp_index;
-
- BLI_assert(mlfan_curr_index >= 0);
- BLI_assert(mlfan_vert_index >= 0);
- BLI_assert(mpfan_curr_index >= 0);
-
- /* Only need to compute previous edge's vector once, then we can just reuse old current one! */
- {
- const MVert *mv_2 = (me_org->v1 == mv_pivot_index) ? &mverts[me_org->v2] : &mverts[me_org->v1];
-
- sub_v3_v3v3(vec_org, mv_2->co, mv_pivot->co);
- normalize_v3(vec_org);
- copy_v3_v3(vec_prev, vec_org);
-
- if (lnors_spacearr) {
- BLI_stack_push(edge_vectors, vec_org);
- }
- }
-
-// printf("FAN: vert %d, start edge %d\n", mv_pivot_index, ml_curr->e);
-
- while (true) {
- const MEdge *me_curr = &medges[mlfan_curr->e];
- /* Compute edge vectors.
- * NOTE: We could pre-compute those into an array, in the first iteration, instead of computing them
- * twice (or more) here. However, time gained is not worth memory and time lost,
- * given the fact that this code should not be called that much in real-life meshes...
- */
- {
- const MVert *mv_2 = (me_curr->v1 == mv_pivot_index) ? &mverts[me_curr->v2] : &mverts[me_curr->v1];
-
- sub_v3_v3v3(vec_curr, mv_2->co, mv_pivot->co);
- normalize_v3(vec_curr);
- }
-
-// printf("\thandling edge %d / loop %d\n", mlfan_curr->e, mlfan_curr_index);
-
- {
- /* Code similar to accumulate_vertex_normals_poly_v3. */
- /* Calculate angle between the two poly edges incident on this vertex. */
- const float fac = saacos(dot_v3v3(vec_curr, vec_prev));
- /* Accumulate */
- madd_v3_v3fl(lnor, polynors[mpfan_curr_index], fac);
-
- if (clnors_data) {
- /* Accumulate all clnors, if they are not all equal we have to fix that! */
- short (*clnor)[2] = &clnors_data[mlfan_vert_index];
- if (clnors_nbr) {
- clnors_invalid |= ((*clnor_ref)[0] != (*clnor)[0] || (*clnor_ref)[1] != (*clnor)[1]);
- }
- else {
- clnor_ref = clnor;
- }
- clnors_avg[0] += (*clnor)[0];
- clnors_avg[1] += (*clnor)[1];
- clnors_nbr++;
- /* We store here a pointer to all custom lnors processed. */
- BLI_SMALLSTACK_PUSH(clnors, (short *)*clnor);
- }
- }
-
- /* We store here a pointer to all loop-normals processed. */
- BLI_SMALLSTACK_PUSH(normal, (float *)(loopnors[mlfan_vert_index]));
-
- if (lnors_spacearr) {
- /* Assign current lnor space to current 'vertex' loop. */
- BKE_lnor_space_add_loop(lnors_spacearr, lnor_space, mlfan_vert_index, NULL, false);
- if (me_curr != me_org) {
- /* We store here all edges-normalized vectors processed. */
- BLI_stack_push(edge_vectors, vec_curr);
- }
- }
-
- if (IS_EDGE_SHARP(e2lfan_curr) || (me_curr == me_org)) {
- /* Current edge is sharp and we have finished with this fan of faces around this vert,
- * or this vert is smooth, and we have completed a full turn around it.
- */
-// printf("FAN: Finished!\n");
- break;
- }
-
- copy_v3_v3(vec_prev, vec_curr);
-
- /* Find next loop of the smooth fan. */
- BKE_mesh_loop_manifold_fan_around_vert_next(
- mloops, mpolys, loop_to_poly, e2lfan_curr, mv_pivot_index,
- &mlfan_curr, &mlfan_curr_index, &mlfan_vert_index, &mpfan_curr_index);
-
- e2lfan_curr = edge_to_loops[mlfan_curr->e];
- }
-
- {
- float lnor_len = normalize_v3(lnor);
-
- /* If we are generating lnor spacearr, we can now define the one for this fan,
- * and optionally compute final lnor from custom data too!
- */
- if (lnors_spacearr) {
- if (UNLIKELY(lnor_len == 0.0f)) {
- /* Use vertex normal as fallback! */
- copy_v3_v3(lnor, loopnors[mlfan_vert_index]);
- lnor_len = 1.0f;
- }
-
- BKE_lnor_space_define(lnor_space, lnor, vec_org, vec_curr, edge_vectors);
-
- if (clnors_data) {
- if (clnors_invalid) {
- short *clnor;
-
- clnors_avg[0] /= clnors_nbr;
- clnors_avg[1] /= clnors_nbr;
- /* Fix/update all clnors of this fan with computed average value. */
- if (G.debug & G_DEBUG) {
- printf("Invalid clnors in this fan!\n");
- }
- while ((clnor = BLI_SMALLSTACK_POP(clnors))) {
- //print_v2("org clnor", clnor);
- clnor[0] = (short)clnors_avg[0];
- clnor[1] = (short)clnors_avg[1];
- }
- //print_v2("new clnors", clnors_avg);
- }
- /* Extra bonus: since smallstack is local to this func, no more need to empty it at all cost! */
-
- BKE_lnor_space_custom_data_to_normal(lnor_space, *clnor_ref, lnor);
- }
- }
-
- /* In case we get a zero normal here, just use vertex normal already set! */
- if (LIKELY(lnor_len != 0.0f)) {
- /* Copy back the final computed normal into all related loop-normals. */
- float *nor;
-
- while ((nor = BLI_SMALLSTACK_POP(normal))) {
- copy_v3_v3(nor, lnor);
- }
- }
- /* Extra bonus: since smallstack is local to this func, no more need to empty it at all cost! */
- }
-}
-
-static void loop_split_worker_do(
- LoopSplitTaskDataCommon *common_data, LoopSplitTaskData *data, BLI_Stack *edge_vectors)
-{
- BLI_assert(data->ml_curr);
- if (data->e2l_prev) {
- BLI_assert((edge_vectors == NULL) || BLI_stack_is_empty(edge_vectors));
- data->edge_vectors = edge_vectors;
- split_loop_nor_fan_do(common_data, data);
- }
- else {
- /* No need for edge_vectors for 'single' case! */
- split_loop_nor_single_do(common_data, data);
- }
-}
-
-static void loop_split_worker(TaskPool * __restrict pool, void *taskdata, int UNUSED(threadid))
-{
- LoopSplitTaskDataCommon *common_data = BLI_task_pool_userdata(pool);
- LoopSplitTaskData *data = taskdata;
-
- /* Temp edge vectors stack, only used when computing lnor spacearr. */
- BLI_Stack *edge_vectors = common_data->lnors_spacearr ? BLI_stack_new(sizeof(float[3]), __func__) : NULL;
+ const MLoop *ml_curr = data->ml_curr;
+ const MLoop *ml_prev = data->ml_prev;
+ const int ml_curr_index = data->ml_curr_index;
+ const int ml_prev_index = data->ml_prev_index;
+ const int mp_index = data->mp_index;
+ const int *e2l_prev = data->e2l_prev;
+
+ BLI_Stack *edge_vectors = data->edge_vectors;
+
+ /* Gah... We have to fan around current vertex, until we find the other non-smooth edge,
+ * and accumulate face normals into the vertex!
+ * Note in case this vertex has only one sharp edges, this is a waste because the normal is the same as
+ * the vertex normal, but I do not see any easy way to detect that (would need to count number
+ * of sharp edges per vertex, I doubt the additional memory usage would be worth it, especially as
+ * it should not be a common case in real-life meshes anyway).
+ */
+ const unsigned int mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */
+ const MVert *mv_pivot = &mverts[mv_pivot_index];
+ const MEdge *me_org =
+ &medges[ml_curr->e]; /* ml_curr would be mlfan_prev if we needed that one */
+ const int *e2lfan_curr;
+ float vec_curr[3], vec_prev[3], vec_org[3];
+ const MLoop *mlfan_curr;
+ float lnor[3] = {0.0f, 0.0f, 0.0f};
+ /* mlfan_vert_index: the loop of our current edge might not be the loop of our current vertex! */
+ int mlfan_curr_index, mlfan_vert_index, mpfan_curr_index;
+
+ /* We validate clnors data on the fly - cheapest way to do! */
+ int clnors_avg[2] = {0, 0};
+ short(*clnor_ref)[2] = NULL;
+ int clnors_nbr = 0;
+ bool clnors_invalid = false;
+
+ /* Temp loop normal stack. */
+ BLI_SMALLSTACK_DECLARE(normal, float *);
+ /* Temp clnors stack. */
+ BLI_SMALLSTACK_DECLARE(clnors, short *);
+
+ e2lfan_curr = e2l_prev;
+ mlfan_curr = ml_prev;
+ mlfan_curr_index = ml_prev_index;
+ mlfan_vert_index = ml_curr_index;
+ mpfan_curr_index = mp_index;
+
+ BLI_assert(mlfan_curr_index >= 0);
+ BLI_assert(mlfan_vert_index >= 0);
+ BLI_assert(mpfan_curr_index >= 0);
+
+ /* Only need to compute previous edge's vector once, then we can just reuse old current one! */
+ {
+ const MVert *mv_2 = (me_org->v1 == mv_pivot_index) ? &mverts[me_org->v2] : &mverts[me_org->v1];
+
+ sub_v3_v3v3(vec_org, mv_2->co, mv_pivot->co);
+ normalize_v3(vec_org);
+ copy_v3_v3(vec_prev, vec_org);
+
+ if (lnors_spacearr) {
+ BLI_stack_push(edge_vectors, vec_org);
+ }
+ }
+
+ // printf("FAN: vert %d, start edge %d\n", mv_pivot_index, ml_curr->e);
+
+ while (true) {
+ const MEdge *me_curr = &medges[mlfan_curr->e];
+ /* Compute edge vectors.
+ * NOTE: We could pre-compute those into an array, in the first iteration, instead of computing them
+ * twice (or more) here. However, time gained is not worth memory and time lost,
+ * given the fact that this code should not be called that much in real-life meshes...
+ */
+ {
+ const MVert *mv_2 = (me_curr->v1 == mv_pivot_index) ? &mverts[me_curr->v2] :
+ &mverts[me_curr->v1];
+
+ sub_v3_v3v3(vec_curr, mv_2->co, mv_pivot->co);
+ normalize_v3(vec_curr);
+ }
+
+ // printf("\thandling edge %d / loop %d\n", mlfan_curr->e, mlfan_curr_index);
+
+ {
+ /* Code similar to accumulate_vertex_normals_poly_v3. */
+ /* Calculate angle between the two poly edges incident on this vertex. */
+ const float fac = saacos(dot_v3v3(vec_curr, vec_prev));
+ /* Accumulate */
+ madd_v3_v3fl(lnor, polynors[mpfan_curr_index], fac);
+
+ if (clnors_data) {
+ /* Accumulate all clnors, if they are not all equal we have to fix that! */
+ short(*clnor)[2] = &clnors_data[mlfan_vert_index];
+ if (clnors_nbr) {
+ clnors_invalid |= ((*clnor_ref)[0] != (*clnor)[0] || (*clnor_ref)[1] != (*clnor)[1]);
+ }
+ else {
+ clnor_ref = clnor;
+ }
+ clnors_avg[0] += (*clnor)[0];
+ clnors_avg[1] += (*clnor)[1];
+ clnors_nbr++;
+ /* We store here a pointer to all custom lnors processed. */
+ BLI_SMALLSTACK_PUSH(clnors, (short *)*clnor);
+ }
+ }
+
+ /* We store here a pointer to all loop-normals processed. */
+ BLI_SMALLSTACK_PUSH(normal, (float *)(loopnors[mlfan_vert_index]));
+
+ if (lnors_spacearr) {
+ /* Assign current lnor space to current 'vertex' loop. */
+ BKE_lnor_space_add_loop(lnors_spacearr, lnor_space, mlfan_vert_index, NULL, false);
+ if (me_curr != me_org) {
+ /* We store here all edges-normalized vectors processed. */
+ BLI_stack_push(edge_vectors, vec_curr);
+ }
+ }
+
+ if (IS_EDGE_SHARP(e2lfan_curr) || (me_curr == me_org)) {
+ /* Current edge is sharp and we have finished with this fan of faces around this vert,
+ * or this vert is smooth, and we have completed a full turn around it.
+ */
+ // printf("FAN: Finished!\n");
+ break;
+ }
+
+ copy_v3_v3(vec_prev, vec_curr);
+
+ /* Find next loop of the smooth fan. */
+ BKE_mesh_loop_manifold_fan_around_vert_next(mloops,
+ mpolys,
+ loop_to_poly,
+ e2lfan_curr,
+ mv_pivot_index,
+ &mlfan_curr,
+ &mlfan_curr_index,
+ &mlfan_vert_index,
+ &mpfan_curr_index);
+
+ e2lfan_curr = edge_to_loops[mlfan_curr->e];
+ }
+
+ {
+ float lnor_len = normalize_v3(lnor);
+
+ /* If we are generating lnor spacearr, we can now define the one for this fan,
+ * and optionally compute final lnor from custom data too!
+ */
+ if (lnors_spacearr) {
+ if (UNLIKELY(lnor_len == 0.0f)) {
+ /* Use vertex normal as fallback! */
+ copy_v3_v3(lnor, loopnors[mlfan_vert_index]);
+ lnor_len = 1.0f;
+ }
+
+ BKE_lnor_space_define(lnor_space, lnor, vec_org, vec_curr, edge_vectors);
+
+ if (clnors_data) {
+ if (clnors_invalid) {
+ short *clnor;
+
+ clnors_avg[0] /= clnors_nbr;
+ clnors_avg[1] /= clnors_nbr;
+ /* Fix/update all clnors of this fan with computed average value. */
+ if (G.debug & G_DEBUG) {
+ printf("Invalid clnors in this fan!\n");
+ }
+ while ((clnor = BLI_SMALLSTACK_POP(clnors))) {
+ //print_v2("org clnor", clnor);
+ clnor[0] = (short)clnors_avg[0];
+ clnor[1] = (short)clnors_avg[1];
+ }
+ //print_v2("new clnors", clnors_avg);
+ }
+ /* Extra bonus: since smallstack is local to this func, no more need to empty it at all cost! */
+
+ BKE_lnor_space_custom_data_to_normal(lnor_space, *clnor_ref, lnor);
+ }
+ }
+
+ /* In case we get a zero normal here, just use vertex normal already set! */
+ if (LIKELY(lnor_len != 0.0f)) {
+ /* Copy back the final computed normal into all related loop-normals. */
+ float *nor;
+
+ while ((nor = BLI_SMALLSTACK_POP(normal))) {
+ copy_v3_v3(nor, lnor);
+ }
+ }
+ /* Extra bonus: since smallstack is local to this func, no more need to empty it at all cost! */
+ }
+}
+
+static void loop_split_worker_do(LoopSplitTaskDataCommon *common_data,
+ LoopSplitTaskData *data,
+ BLI_Stack *edge_vectors)
+{
+ BLI_assert(data->ml_curr);
+ if (data->e2l_prev) {
+ BLI_assert((edge_vectors == NULL) || BLI_stack_is_empty(edge_vectors));
+ data->edge_vectors = edge_vectors;
+ split_loop_nor_fan_do(common_data, data);
+ }
+ else {
+ /* No need for edge_vectors for 'single' case! */
+ split_loop_nor_single_do(common_data, data);
+ }
+}
+
+static void loop_split_worker(TaskPool *__restrict pool, void *taskdata, int UNUSED(threadid))
+{
+ LoopSplitTaskDataCommon *common_data = BLI_task_pool_userdata(pool);
+ LoopSplitTaskData *data = taskdata;
+
+ /* Temp edge vectors stack, only used when computing lnor spacearr. */
+ BLI_Stack *edge_vectors = common_data->lnors_spacearr ?
+ BLI_stack_new(sizeof(float[3]), __func__) :
+ NULL;
#ifdef DEBUG_TIME
- TIMEIT_START_AVERAGED(loop_split_worker);
+ TIMEIT_START_AVERAGED(loop_split_worker);
#endif
- for (int i = 0; i < LOOP_SPLIT_TASK_BLOCK_SIZE; i++, data++) {
- /* A NULL ml_curr is used to tag ended data! */
- if (data->ml_curr == NULL) {
- break;
- }
+ for (int i = 0; i < LOOP_SPLIT_TASK_BLOCK_SIZE; i++, data++) {
+ /* A NULL ml_curr is used to tag ended data! */
+ if (data->ml_curr == NULL) {
+ break;
+ }
- loop_split_worker_do(common_data, data, edge_vectors);
- }
+ loop_split_worker_do(common_data, data, edge_vectors);
+ }
- if (edge_vectors) {
- BLI_stack_free(edge_vectors);
- }
+ if (edge_vectors) {
+ BLI_stack_free(edge_vectors);
+ }
#ifdef DEBUG_TIME
- TIMEIT_END_AVERAGED(loop_split_worker);
+ TIMEIT_END_AVERAGED(loop_split_worker);
#endif
}
/* Check whether gievn loop is part of an unknown-so-far cyclic smooth fan, or not.
* Needed because cyclic smooth fans have no obvious 'entry point', and yet we need to walk them once, and only once. */
-static bool loop_split_generator_check_cyclic_smooth_fan(
- const MLoop *mloops, const MPoly *mpolys,
- const int (*edge_to_loops)[2], const int *loop_to_poly, const int *e2l_prev, BLI_bitmap *skip_loops,
- const MLoop *ml_curr, const MLoop *ml_prev, const int ml_curr_index, const int ml_prev_index,
- const int mp_curr_index)
-{
- const unsigned int mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */
- const int *e2lfan_curr;
- const MLoop *mlfan_curr;
- /* mlfan_vert_index: the loop of our current edge might not be the loop of our current vertex! */
- int mlfan_curr_index, mlfan_vert_index, mpfan_curr_index;
-
- e2lfan_curr = e2l_prev;
- if (IS_EDGE_SHARP(e2lfan_curr)) {
- /* Sharp loop, so not a cyclic smooth fan... */
- return false;
- }
-
- mlfan_curr = ml_prev;
- mlfan_curr_index = ml_prev_index;
- mlfan_vert_index = ml_curr_index;
- mpfan_curr_index = mp_curr_index;
-
- BLI_assert(mlfan_curr_index >= 0);
- BLI_assert(mlfan_vert_index >= 0);
- BLI_assert(mpfan_curr_index >= 0);
-
- BLI_assert(!BLI_BITMAP_TEST(skip_loops, mlfan_vert_index));
- BLI_BITMAP_ENABLE(skip_loops, mlfan_vert_index);
-
- while (true) {
- /* Find next loop of the smooth fan. */
- BKE_mesh_loop_manifold_fan_around_vert_next(
- mloops, mpolys, loop_to_poly, e2lfan_curr, mv_pivot_index,
- &mlfan_curr, &mlfan_curr_index, &mlfan_vert_index, &mpfan_curr_index);
-
- e2lfan_curr = edge_to_loops[mlfan_curr->e];
-
- if (IS_EDGE_SHARP(e2lfan_curr)) {
- /* Sharp loop/edge, so not a cyclic smooth fan... */
- return false;
- }
- /* Smooth loop/edge... */
- else if (BLI_BITMAP_TEST(skip_loops, mlfan_vert_index)) {
- if (mlfan_vert_index == ml_curr_index) {
- /* We walked around a whole cyclic smooth fan without finding any already-processed loop, means we can
- * use initial ml_curr/ml_prev edge as start for this smooth fan. */
- return true;
- }
- /* ... already checked in some previous looping, we can abort. */
- return false;
- }
- else {
- /* ... we can skip it in future, and keep checking the smooth fan. */
- BLI_BITMAP_ENABLE(skip_loops, mlfan_vert_index);
- }
- }
+static bool loop_split_generator_check_cyclic_smooth_fan(const MLoop *mloops,
+ const MPoly *mpolys,
+ const int (*edge_to_loops)[2],
+ const int *loop_to_poly,
+ const int *e2l_prev,
+ BLI_bitmap *skip_loops,
+ const MLoop *ml_curr,
+ const MLoop *ml_prev,
+ const int ml_curr_index,
+ const int ml_prev_index,
+ const int mp_curr_index)
+{
+ const unsigned int mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */
+ const int *e2lfan_curr;
+ const MLoop *mlfan_curr;
+ /* mlfan_vert_index: the loop of our current edge might not be the loop of our current vertex! */
+ int mlfan_curr_index, mlfan_vert_index, mpfan_curr_index;
+
+ e2lfan_curr = e2l_prev;
+ if (IS_EDGE_SHARP(e2lfan_curr)) {
+ /* Sharp loop, so not a cyclic smooth fan... */
+ return false;
+ }
+
+ mlfan_curr = ml_prev;
+ mlfan_curr_index = ml_prev_index;
+ mlfan_vert_index = ml_curr_index;
+ mpfan_curr_index = mp_curr_index;
+
+ BLI_assert(mlfan_curr_index >= 0);
+ BLI_assert(mlfan_vert_index >= 0);
+ BLI_assert(mpfan_curr_index >= 0);
+
+ BLI_assert(!BLI_BITMAP_TEST(skip_loops, mlfan_vert_index));
+ BLI_BITMAP_ENABLE(skip_loops, mlfan_vert_index);
+
+ while (true) {
+ /* Find next loop of the smooth fan. */
+ BKE_mesh_loop_manifold_fan_around_vert_next(mloops,
+ mpolys,
+ loop_to_poly,
+ e2lfan_curr,
+ mv_pivot_index,
+ &mlfan_curr,
+ &mlfan_curr_index,
+ &mlfan_vert_index,
+ &mpfan_curr_index);
+
+ e2lfan_curr = edge_to_loops[mlfan_curr->e];
+
+ if (IS_EDGE_SHARP(e2lfan_curr)) {
+ /* Sharp loop/edge, so not a cyclic smooth fan... */
+ return false;
+ }
+ /* Smooth loop/edge... */
+ else if (BLI_BITMAP_TEST(skip_loops, mlfan_vert_index)) {
+ if (mlfan_vert_index == ml_curr_index) {
+ /* We walked around a whole cyclic smooth fan without finding any already-processed loop, means we can
+ * use initial ml_curr/ml_prev edge as start for this smooth fan. */
+ return true;
+ }
+ /* ... already checked in some previous looping, we can abort. */
+ return false;
+ }
+ else {
+ /* ... we can skip it in future, and keep checking the smooth fan. */
+ BLI_BITMAP_ENABLE(skip_loops, mlfan_vert_index);
+ }
+ }
}
static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common_data)
{
- MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr;
- float (*loopnors)[3] = common_data->loopnors;
+ MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr;
+ float(*loopnors)[3] = common_data->loopnors;
- const MLoop *mloops = common_data->mloops;
- const MPoly *mpolys = common_data->mpolys;
- const int *loop_to_poly = common_data->loop_to_poly;
- const int (*edge_to_loops)[2] = common_data->edge_to_loops;
- const int numLoops = common_data->numLoops;
- const int numPolys = common_data->numPolys;
+ const MLoop *mloops = common_data->mloops;
+ const MPoly *mpolys = common_data->mpolys;
+ const int *loop_to_poly = common_data->loop_to_poly;
+ const int(*edge_to_loops)[2] = common_data->edge_to_loops;
+ const int numLoops = common_data->numLoops;
+ const int numPolys = common_data->numPolys;
- const MPoly *mp;
- int mp_index;
+ const MPoly *mp;
+ int mp_index;
- const MLoop *ml_curr;
- const MLoop *ml_prev;
- int ml_curr_index;
- int ml_prev_index;
+ const MLoop *ml_curr;
+ const MLoop *ml_prev;
+ int ml_curr_index;
+ int ml_prev_index;
- BLI_bitmap *skip_loops = BLI_BITMAP_NEW(numLoops, __func__);
+ BLI_bitmap *skip_loops = BLI_BITMAP_NEW(numLoops, __func__);
- LoopSplitTaskData *data_buff = NULL;
- int data_idx = 0;
+ LoopSplitTaskData *data_buff = NULL;
+ int data_idx = 0;
- /* Temp edge vectors stack, only used when computing lnor spacearr (and we are not multi-threading). */
- BLI_Stack *edge_vectors = NULL;
+ /* Temp edge vectors stack, only used when computing lnor spacearr (and we are not multi-threading). */
+ BLI_Stack *edge_vectors = NULL;
#ifdef DEBUG_TIME
- TIMEIT_START_AVERAGED(loop_split_generator);
+ TIMEIT_START_AVERAGED(loop_split_generator);
#endif
- if (!pool) {
- if (lnors_spacearr) {
- edge_vectors = BLI_stack_new(sizeof(float[3]), __func__);
- }
- }
-
- /* We now know edges that can be smoothed (with their vector, and their two loops), and edges that will be hard!
- * Now, time to generate the normals.
- */
- for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) {
- float (*lnors)[3];
- const int ml_last_index = (mp->loopstart + mp->totloop) - 1;
- ml_curr_index = mp->loopstart;
- ml_prev_index = ml_last_index;
-
- ml_curr = &mloops[ml_curr_index];
- ml_prev = &mloops[ml_prev_index];
- lnors = &loopnors[ml_curr_index];
-
- for (; ml_curr_index <= ml_last_index; ml_curr++, ml_curr_index++, lnors++) {
- const int *e2l_curr = edge_to_loops[ml_curr->e];
- const int *e2l_prev = edge_to_loops[ml_prev->e];
-
-// printf("Checking loop %d / edge %u / vert %u (sharp edge: %d, skiploop: %d)...",
-// ml_curr_index, ml_curr->e, ml_curr->v, IS_EDGE_SHARP(e2l_curr), BLI_BITMAP_TEST_BOOL(skip_loops, ml_curr_index));
-
- /* A smooth edge, we have to check for cyclic smooth fan case.
- * If we find a new, never-processed cyclic smooth fan, we can do it now using that loop/edge as
- * 'entry point', otherwise we can skip it. */
- /* Note: In theory, we could make loop_split_generator_check_cyclic_smooth_fan() store
- * mlfan_vert_index'es and edge indexes in two stacks, to avoid having to fan again around the vert during
- * actual computation of clnor & clnorspace. However, this would complicate the code, add more memory usage,
- * and despite its logical complexity, loop_manifold_fan_around_vert_next() is quite cheap in term of
- * CPU cycles, so really think it's not worth it. */
- if (!IS_EDGE_SHARP(e2l_curr) &&
- (BLI_BITMAP_TEST(skip_loops, ml_curr_index) ||
- !loop_split_generator_check_cyclic_smooth_fan(
- mloops, mpolys, edge_to_loops, loop_to_poly, e2l_prev, skip_loops,
- ml_curr, ml_prev, ml_curr_index, ml_prev_index, mp_index)))
- {
-// printf("SKIPPING!\n");
- }
- else {
- LoopSplitTaskData *data, data_local;
-
-// printf("PROCESSING!\n");
-
- if (pool) {
- if (data_idx == 0) {
- data_buff = MEM_calloc_arrayN(LOOP_SPLIT_TASK_BLOCK_SIZE, sizeof(*data_buff), __func__);
- }
- data = &data_buff[data_idx];
- }
- else {
- data = &data_local;
- memset(data, 0, sizeof(*data));
- }
-
- if (IS_EDGE_SHARP(e2l_curr) && IS_EDGE_SHARP(e2l_prev)) {
- data->lnor = lnors;
- data->ml_curr = ml_curr;
- data->ml_prev = ml_prev;
- data->ml_curr_index = ml_curr_index;
-#if 0 /* Not needed for 'single' loop. */
- data->ml_prev_index = ml_prev_index;
- data->e2l_prev = NULL; /* Tag as 'single' task. */
+ if (!pool) {
+ if (lnors_spacearr) {
+ edge_vectors = BLI_stack_new(sizeof(float[3]), __func__);
+ }
+ }
+
+ /* We now know edges that can be smoothed (with their vector, and their two loops), and edges that will be hard!
+ * Now, time to generate the normals.
+ */
+ for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) {
+ float(*lnors)[3];
+ const int ml_last_index = (mp->loopstart + mp->totloop) - 1;
+ ml_curr_index = mp->loopstart;
+ ml_prev_index = ml_last_index;
+
+ ml_curr = &mloops[ml_curr_index];
+ ml_prev = &mloops[ml_prev_index];
+ lnors = &loopnors[ml_curr_index];
+
+ for (; ml_curr_index <= ml_last_index; ml_curr++, ml_curr_index++, lnors++) {
+ const int *e2l_curr = edge_to_loops[ml_curr->e];
+ const int *e2l_prev = edge_to_loops[ml_prev->e];
+
+ // printf("Checking loop %d / edge %u / vert %u (sharp edge: %d, skiploop: %d)...",
+ // ml_curr_index, ml_curr->e, ml_curr->v, IS_EDGE_SHARP(e2l_curr), BLI_BITMAP_TEST_BOOL(skip_loops, ml_curr_index));
+
+ /* A smooth edge, we have to check for cyclic smooth fan case.
+ * If we find a new, never-processed cyclic smooth fan, we can do it now using that loop/edge as
+ * 'entry point', otherwise we can skip it. */
+ /* Note: In theory, we could make loop_split_generator_check_cyclic_smooth_fan() store
+ * mlfan_vert_index'es and edge indexes in two stacks, to avoid having to fan again around the vert during
+ * actual computation of clnor & clnorspace. However, this would complicate the code, add more memory usage,
+ * and despite its logical complexity, loop_manifold_fan_around_vert_next() is quite cheap in term of
+ * CPU cycles, so really think it's not worth it. */
+ if (!IS_EDGE_SHARP(e2l_curr) && (BLI_BITMAP_TEST(skip_loops, ml_curr_index) ||
+ !loop_split_generator_check_cyclic_smooth_fan(mloops,
+ mpolys,
+ edge_to_loops,
+ loop_to_poly,
+ e2l_prev,
+ skip_loops,
+ ml_curr,
+ ml_prev,
+ ml_curr_index,
+ ml_prev_index,
+ mp_index))) {
+ // printf("SKIPPING!\n");
+ }
+ else {
+ LoopSplitTaskData *data, data_local;
+
+ // printf("PROCESSING!\n");
+
+ if (pool) {
+ if (data_idx == 0) {
+ data_buff = MEM_calloc_arrayN(
+ LOOP_SPLIT_TASK_BLOCK_SIZE, sizeof(*data_buff), __func__);
+ }
+ data = &data_buff[data_idx];
+ }
+ else {
+ data = &data_local;
+ memset(data, 0, sizeof(*data));
+ }
+
+ if (IS_EDGE_SHARP(e2l_curr) && IS_EDGE_SHARP(e2l_prev)) {
+ data->lnor = lnors;
+ data->ml_curr = ml_curr;
+ data->ml_prev = ml_prev;
+ data->ml_curr_index = ml_curr_index;
+#if 0 /* Not needed for 'single' loop. */
+ data->ml_prev_index = ml_prev_index;
+ data->e2l_prev = NULL; /* Tag as 'single' task. */
#endif
- data->mp_index = mp_index;
- if (lnors_spacearr) {
- data->lnor_space = BKE_lnor_space_create(lnors_spacearr);
- }
- }
- /* We *do not need* to check/tag loops as already computed!
- * Due to the fact a loop only links to one of its two edges, a same fan *will never be walked
- * more than once!*
- * Since we consider edges having neighbor polys with inverted (flipped) normals as sharp, we are sure
- * that no fan will be skipped, even only considering the case (sharp curr_edge, smooth prev_edge),
- * and not the alternative (smooth curr_edge, sharp prev_edge).
- * All this due/thanks to link between normals and loop ordering (i.e. winding).
- */
- else {
-#if 0 /* Not needed for 'fan' loops. */
- data->lnor = lnors;
+ data->mp_index = mp_index;
+ if (lnors_spacearr) {
+ data->lnor_space = BKE_lnor_space_create(lnors_spacearr);
+ }
+ }
+ /* We *do not need* to check/tag loops as already computed!
+ * Due to the fact a loop only links to one of its two edges, a same fan *will never be walked
+ * more than once!*
+ * Since we consider edges having neighbor polys with inverted (flipped) normals as sharp, we are sure
+ * that no fan will be skipped, even only considering the case (sharp curr_edge, smooth prev_edge),
+ * and not the alternative (smooth curr_edge, sharp prev_edge).
+ * All this due/thanks to link between normals and loop ordering (i.e. winding).
+ */
+ else {
+#if 0 /* Not needed for 'fan' loops. */
+ data->lnor = lnors;
#endif
- data->ml_curr = ml_curr;
- data->ml_prev = ml_prev;
- data->ml_curr_index = ml_curr_index;
- data->ml_prev_index = ml_prev_index;
- data->e2l_prev = e2l_prev; /* Also tag as 'fan' task. */
- data->mp_index = mp_index;
- if (lnors_spacearr) {
- data->lnor_space = BKE_lnor_space_create(lnors_spacearr);
- }
- }
-
- if (pool) {
- data_idx++;
- if (data_idx == LOOP_SPLIT_TASK_BLOCK_SIZE) {
- BLI_task_pool_push(pool, loop_split_worker, data_buff, true, TASK_PRIORITY_LOW);
- data_idx = 0;
- }
- }
- else {
- loop_split_worker_do(common_data, data, edge_vectors);
- }
- }
-
- ml_prev = ml_curr;
- ml_prev_index = ml_curr_index;
- }
- }
-
- /* Last block of data... Since it is calloc'ed and we use first NULL item as stopper, everything is fine. */
- if (pool && data_idx) {
- BLI_task_pool_push(pool, loop_split_worker, data_buff, true, TASK_PRIORITY_LOW);
- }
-
- if (edge_vectors) {
- BLI_stack_free(edge_vectors);
- }
- MEM_freeN(skip_loops);
+ data->ml_curr = ml_curr;
+ data->ml_prev = ml_prev;
+ data->ml_curr_index = ml_curr_index;
+ data->ml_prev_index = ml_prev_index;
+ data->e2l_prev = e2l_prev; /* Also tag as 'fan' task. */
+ data->mp_index = mp_index;
+ if (lnors_spacearr) {
+ data->lnor_space = BKE_lnor_space_create(lnors_spacearr);
+ }
+ }
+
+ if (pool) {
+ data_idx++;
+ if (data_idx == LOOP_SPLIT_TASK_BLOCK_SIZE) {
+ BLI_task_pool_push(pool, loop_split_worker, data_buff, true, TASK_PRIORITY_LOW);
+ data_idx = 0;
+ }
+ }
+ else {
+ loop_split_worker_do(common_data, data, edge_vectors);
+ }
+ }
+
+ ml_prev = ml_curr;
+ ml_prev_index = ml_curr_index;
+ }
+ }
+
+ /* Last block of data... Since it is calloc'ed and we use first NULL item as stopper, everything is fine. */
+ if (pool && data_idx) {
+ BLI_task_pool_push(pool, loop_split_worker, data_buff, true, TASK_PRIORITY_LOW);
+ }
+
+ if (edge_vectors) {
+ BLI_stack_free(edge_vectors);
+ }
+ MEM_freeN(skip_loops);
#ifdef DEBUG_TIME
- TIMEIT_END_AVERAGED(loop_split_generator);
+ TIMEIT_END_AVERAGED(loop_split_generator);
#endif
}
@@ -1488,127 +1603,138 @@ static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common
* Compute split normals, i.e. vertex normals associated with each poly (hence 'loop normals').
* Useful to materialize sharp edges (or non-smooth faces) without actually modifying the geometry (splitting edges).
*/
-void BKE_mesh_normals_loop_split(
- const MVert *mverts, const int UNUSED(numVerts), MEdge *medges, const int numEdges,
- MLoop *mloops, float (*r_loopnors)[3], const int numLoops,
- MPoly *mpolys, const float (*polynors)[3], const int numPolys,
- const bool use_split_normals, const float split_angle,
- MLoopNorSpaceArray *r_lnors_spacearr, short (*clnors_data)[2], int *r_loop_to_poly)
-{
- /* For now this is not supported. If we do not use split normals, we do not generate anything fancy! */
- BLI_assert(use_split_normals || !(r_lnors_spacearr));
-
- if (!use_split_normals) {
- /* In this case, we simply fill lnors with vnors (or fnors for flat faces), quite simple!
- * Note this is done here to keep some logic and consistency in this quite complex code,
- * since we may want to use lnors even when mesh's 'autosmooth' is disabled (see e.g. mesh mapping code).
- * As usual, we could handle that on case-by-case basis, but simpler to keep it well confined here.
- */
- int mp_index;
-
- for (mp_index = 0; mp_index < numPolys; mp_index++) {
- MPoly *mp = &mpolys[mp_index];
- int ml_index = mp->loopstart;
- const int ml_index_end = ml_index + mp->totloop;
- const bool is_poly_flat = ((mp->flag & ME_SMOOTH) == 0);
-
- for (; ml_index < ml_index_end; ml_index++) {
- if (r_loop_to_poly) {
- r_loop_to_poly[ml_index] = mp_index;
- }
- if (is_poly_flat) {
- copy_v3_v3(r_loopnors[ml_index], polynors[mp_index]);
- }
- else {
- normal_short_to_float_v3(r_loopnors[ml_index], mverts[mloops[ml_index].v].no);
- }
- }
- }
- return;
- }
-
- /* Mapping edge -> loops.
- * If that edge is used by more than two loops (polys), it is always sharp (and tagged as such, see below).
- * We also use the second loop index as a kind of flag: smooth edge: > 0,
- * sharp edge: < 0 (INDEX_INVALID || INDEX_UNSET),
- * unset: INDEX_UNSET
- * Note that currently we only have two values for second loop of sharp edges. However, if needed, we can
- * store the negated value of loop index instead of INDEX_INVALID to retrieve the real value later in code).
- * Note also that lose edges always have both values set to 0!
- */
- int (*edge_to_loops)[2] = MEM_calloc_arrayN((size_t)numEdges, sizeof(*edge_to_loops), __func__);
-
- /* Simple mapping from a loop to its polygon index. */
- int *loop_to_poly = r_loop_to_poly ? r_loop_to_poly : MEM_malloc_arrayN((size_t)numLoops, sizeof(*loop_to_poly), __func__);
-
- /* When using custom loop normals, disable the angle feature! */
- const bool check_angle = (split_angle < (float)M_PI) && (clnors_data == NULL);
-
- MLoopNorSpaceArray _lnors_spacearr = {NULL};
+void BKE_mesh_normals_loop_split(const MVert *mverts,
+ const int UNUSED(numVerts),
+ MEdge *medges,
+ const int numEdges,
+ MLoop *mloops,
+ float (*r_loopnors)[3],
+ const int numLoops,
+ MPoly *mpolys,
+ const float (*polynors)[3],
+ const int numPolys,
+ const bool use_split_normals,
+ const float split_angle,
+ MLoopNorSpaceArray *r_lnors_spacearr,
+ short (*clnors_data)[2],
+ int *r_loop_to_poly)
+{
+ /* For now this is not supported. If we do not use split normals, we do not generate anything fancy! */
+ BLI_assert(use_split_normals || !(r_lnors_spacearr));
+
+ if (!use_split_normals) {
+ /* In this case, we simply fill lnors with vnors (or fnors for flat faces), quite simple!
+ * Note this is done here to keep some logic and consistency in this quite complex code,
+ * since we may want to use lnors even when mesh's 'autosmooth' is disabled (see e.g. mesh mapping code).
+ * As usual, we could handle that on case-by-case basis, but simpler to keep it well confined here.
+ */
+ int mp_index;
+
+ for (mp_index = 0; mp_index < numPolys; mp_index++) {
+ MPoly *mp = &mpolys[mp_index];
+ int ml_index = mp->loopstart;
+ const int ml_index_end = ml_index + mp->totloop;
+ const bool is_poly_flat = ((mp->flag & ME_SMOOTH) == 0);
+
+ for (; ml_index < ml_index_end; ml_index++) {
+ if (r_loop_to_poly) {
+ r_loop_to_poly[ml_index] = mp_index;
+ }
+ if (is_poly_flat) {
+ copy_v3_v3(r_loopnors[ml_index], polynors[mp_index]);
+ }
+ else {
+ normal_short_to_float_v3(r_loopnors[ml_index], mverts[mloops[ml_index].v].no);
+ }
+ }
+ }
+ return;
+ }
+
+ /* Mapping edge -> loops.
+ * If that edge is used by more than two loops (polys), it is always sharp (and tagged as such, see below).
+ * We also use the second loop index as a kind of flag: smooth edge: > 0,
+ * sharp edge: < 0 (INDEX_INVALID || INDEX_UNSET),
+ * unset: INDEX_UNSET
+ * Note that currently we only have two values for second loop of sharp edges. However, if needed, we can
+ * store the negated value of loop index instead of INDEX_INVALID to retrieve the real value later in code).
+ * Note also that lose edges always have both values set to 0!
+ */
+ int(*edge_to_loops)[2] = MEM_calloc_arrayN((size_t)numEdges, sizeof(*edge_to_loops), __func__);
+
+ /* Simple mapping from a loop to its polygon index. */
+ int *loop_to_poly = r_loop_to_poly ?
+ r_loop_to_poly :
+ MEM_malloc_arrayN((size_t)numLoops, sizeof(*loop_to_poly), __func__);
+
+ /* When using custom loop normals, disable the angle feature! */
+ const bool check_angle = (split_angle < (float)M_PI) && (clnors_data == NULL);
+
+ MLoopNorSpaceArray _lnors_spacearr = {NULL};
#ifdef DEBUG_TIME
- TIMEIT_START_AVERAGED(BKE_mesh_normals_loop_split);
+ TIMEIT_START_AVERAGED(BKE_mesh_normals_loop_split);
#endif
- if (!r_lnors_spacearr && clnors_data) {
- /* We need to compute lnor spacearr if some custom lnor data are given to us! */
- r_lnors_spacearr = &_lnors_spacearr;
- }
- if (r_lnors_spacearr) {
- BKE_lnor_spacearr_init(r_lnors_spacearr, numLoops, MLNOR_SPACEARR_LOOP_INDEX);
- }
-
- /* Init data common to all tasks. */
- LoopSplitTaskDataCommon common_data = {
- .lnors_spacearr = r_lnors_spacearr,
- .loopnors = r_loopnors,
- .clnors_data = clnors_data,
- .mverts = mverts,
- .medges = medges,
- .mloops = mloops,
- .mpolys = mpolys,
- .edge_to_loops = edge_to_loops,
- .loop_to_poly = loop_to_poly,
- .polynors = polynors,
- .numEdges = numEdges,
- .numLoops = numLoops,
- .numPolys = numPolys,
- };
-
- /* This first loop check which edges are actually smooth, and compute edge vectors. */
- mesh_edges_sharp_tag(&common_data, check_angle, split_angle, false);
-
- if (numLoops < LOOP_SPLIT_TASK_BLOCK_SIZE * 8) {
- /* Not enough loops to be worth the whole threading overhead... */
- loop_split_generator(NULL, &common_data);
- }
- else {
- TaskScheduler *task_scheduler;
- TaskPool *task_pool;
-
- task_scheduler = BLI_task_scheduler_get();
- task_pool = BLI_task_pool_create(task_scheduler, &common_data);
-
- loop_split_generator(task_pool, &common_data);
-
- BLI_task_pool_work_and_wait(task_pool);
-
- BLI_task_pool_free(task_pool);
- }
-
- MEM_freeN(edge_to_loops);
- if (!r_loop_to_poly) {
- MEM_freeN(loop_to_poly);
- }
-
- if (r_lnors_spacearr) {
- if (r_lnors_spacearr == &_lnors_spacearr) {
- BKE_lnor_spacearr_free(r_lnors_spacearr);
- }
- }
+ if (!r_lnors_spacearr && clnors_data) {
+ /* We need to compute lnor spacearr if some custom lnor data are given to us! */
+ r_lnors_spacearr = &_lnors_spacearr;
+ }
+ if (r_lnors_spacearr) {
+ BKE_lnor_spacearr_init(r_lnors_spacearr, numLoops, MLNOR_SPACEARR_LOOP_INDEX);
+ }
+
+ /* Init data common to all tasks. */
+ LoopSplitTaskDataCommon common_data = {
+ .lnors_spacearr = r_lnors_spacearr,
+ .loopnors = r_loopnors,
+ .clnors_data = clnors_data,
+ .mverts = mverts,
+ .medges = medges,
+ .mloops = mloops,
+ .mpolys = mpolys,
+ .edge_to_loops = edge_to_loops,
+ .loop_to_poly = loop_to_poly,
+ .polynors = polynors,
+ .numEdges = numEdges,
+ .numLoops = numLoops,
+ .numPolys = numPolys,
+ };
+
+ /* This first loop check which edges are actually smooth, and compute edge vectors. */
+ mesh_edges_sharp_tag(&common_data, check_angle, split_angle, false);
+
+ if (numLoops < LOOP_SPLIT_TASK_BLOCK_SIZE * 8) {
+ /* Not enough loops to be worth the whole threading overhead... */
+ loop_split_generator(NULL, &common_data);
+ }
+ else {
+ TaskScheduler *task_scheduler;
+ TaskPool *task_pool;
+
+ task_scheduler = BLI_task_scheduler_get();
+ task_pool = BLI_task_pool_create(task_scheduler, &common_data);
+
+ loop_split_generator(task_pool, &common_data);
+
+ BLI_task_pool_work_and_wait(task_pool);
+
+ BLI_task_pool_free(task_pool);
+ }
+
+ MEM_freeN(edge_to_loops);
+ if (!r_loop_to_poly) {
+ MEM_freeN(loop_to_poly);
+ }
+
+ if (r_lnors_spacearr) {
+ if (r_lnors_spacearr == &_lnors_spacearr) {
+ BKE_lnor_spacearr_free(r_lnors_spacearr);
+ }
+ }
#ifdef DEBUG_TIME
- TIMEIT_END_AVERAGED(BKE_mesh_normals_loop_split);
+ TIMEIT_END_AVERAGED(BKE_mesh_normals_loop_split);
#endif
}
@@ -1625,262 +1751,338 @@ void BKE_mesh_normals_loop_split(
* r_custom_loopnors is expected to have normalized normals, or zero ones, in which case they will be replaced
* by default loop/vertex normal.
*/
-static void mesh_normals_loop_custom_set(
- const MVert *mverts, const int numVerts, MEdge *medges, const int numEdges,
- MLoop *mloops, float (*r_custom_loopnors)[3], const int numLoops,
- MPoly *mpolys, const float (*polynors)[3], const int numPolys,
- short (*r_clnors_data)[2], const bool use_vertices)
-{
- /* We *may* make that poor BKE_mesh_normals_loop_split() even more complex by making it handling that
- * feature too, would probably be more efficient in absolute.
- * However, this function *is not* performance-critical, since it is mostly expected to be called
- * by io addons when importing custom normals, and modifier (and perhaps from some editing tools later?).
- * So better to keep some simplicity here, and just call BKE_mesh_normals_loop_split() twice!
- */
- MLoopNorSpaceArray lnors_spacearr = {NULL};
- BLI_bitmap *done_loops = BLI_BITMAP_NEW((size_t)numLoops, __func__);
- float (*lnors)[3] = MEM_calloc_arrayN((size_t)numLoops, sizeof(*lnors), __func__);
- int *loop_to_poly = MEM_malloc_arrayN((size_t)numLoops, sizeof(int), __func__);
- /* In this case we always consider split nors as ON, and do not want to use angle to define smooth fans! */
- const bool use_split_normals = true;
- const float split_angle = (float)M_PI;
- int i;
-
- BLI_SMALLSTACK_DECLARE(clnors_data, short *);
-
- /* Compute current lnor spacearr. */
- BKE_mesh_normals_loop_split(
- mverts, numVerts, medges, numEdges, mloops, lnors, numLoops,
- mpolys, polynors, numPolys, use_split_normals, split_angle,
- &lnors_spacearr, NULL, loop_to_poly);
-
- /* Set all given zero vectors to their default value. */
- if (use_vertices) {
- for (i = 0; i < numVerts; i++) {
- if (is_zero_v3(r_custom_loopnors[i])) {
- normal_short_to_float_v3(r_custom_loopnors[i], mverts[i].no);
- }
- }
- }
- else {
- for (i = 0; i < numLoops; i++) {
- if (is_zero_v3(r_custom_loopnors[i])) {
- copy_v3_v3(r_custom_loopnors[i], lnors[i]);
- }
- }
- }
-
- BLI_assert(lnors_spacearr.data_type == MLNOR_SPACEARR_LOOP_INDEX);
-
- /* Now, check each current smooth fan (one lnor space per smooth fan!), and if all its matching custom lnors
- * are not (enough) equal, add sharp edges as needed.
- * This way, next time we run BKE_mesh_normals_loop_split(), we'll get lnor spacearr/smooth fans matching
- * given custom lnors.
- * Note this code *will never* unsharp edges!
- * And quite obviously, when we set custom normals per vertices, running this is absolutely useless.
- */
- if (!use_vertices) {
- for (i = 0; i < numLoops; i++) {
- if (!lnors_spacearr.lspacearr[i]) {
- /* This should not happen in theory, but in some rare case (probably ugly geometry)
- * we can get some NULL loopspacearr at this point. :/
- * Maybe we should set those loops' edges as sharp?
- */
- BLI_BITMAP_ENABLE(done_loops, i);
- if (G.debug & G_DEBUG) {
- printf("WARNING! Getting invalid NULL loop space for loop %d!\n", i);
- }
- continue;
- }
-
- if (!BLI_BITMAP_TEST(done_loops, i)) {
- /* Notes:
- * * In case of mono-loop smooth fan, we have nothing to do.
- * * Loops in this linklist are ordered (in reversed order compared to how they were discovered by
- * BKE_mesh_normals_loop_split(), but this is not a problem). Which means if we find a
- * mismatching clnor, we know all remaining loops will have to be in a new, different smooth fan/
- * lnor space.
- * * In smooth fan case, we compare each clnor against a ref one, to avoid small differences adding
- * up into a real big one in the end!
- */
- if (lnors_spacearr.lspacearr[i]->flags & MLNOR_SPACE_IS_SINGLE) {
- BLI_BITMAP_ENABLE(done_loops, i);
- continue;
- }
-
- LinkNode *loops = lnors_spacearr.lspacearr[i]->loops;
- MLoop *prev_ml = NULL;
- const float *org_nor = NULL;
-
- while (loops) {
- const int lidx = POINTER_AS_INT(loops->link);
- MLoop *ml = &mloops[lidx];
- const int nidx = lidx;
- float *nor = r_custom_loopnors[nidx];
-
- if (!org_nor) {
- org_nor = nor;
- }
- else if (dot_v3v3(org_nor, nor) < LNOR_SPACE_TRIGO_THRESHOLD) {
- /* Current normal differs too much from org one, we have to tag the edge between
- * previous loop's face and current's one as sharp.
- * We know those two loops do not point to the same edge, since we do not allow reversed winding
- * in a same smooth fan.
- */
- const MPoly *mp = &mpolys[loop_to_poly[lidx]];
- const MLoop *mlp = &mloops[(lidx == mp->loopstart) ? mp->loopstart + mp->totloop - 1 : lidx - 1];
- medges[(prev_ml->e == mlp->e) ? prev_ml->e : ml->e].flag |= ME_SHARP;
-
- org_nor = nor;
- }
-
- prev_ml = ml;
- loops = loops->next;
- BLI_BITMAP_ENABLE(done_loops, lidx);
- }
-
- /* We also have to check between last and first loops, otherwise we may miss some sharp edges here!
- * This is just a simplified version of above while loop.
- * See T45984. */
- loops = lnors_spacearr.lspacearr[i]->loops;
- if (loops && org_nor) {
- const int lidx = POINTER_AS_INT(loops->link);
- MLoop *ml = &mloops[lidx];
- const int nidx = lidx;
- float *nor = r_custom_loopnors[nidx];
-
- if (dot_v3v3(org_nor, nor) < LNOR_SPACE_TRIGO_THRESHOLD) {
- const MPoly *mp = &mpolys[loop_to_poly[lidx]];
- const MLoop *mlp = &mloops[(lidx == mp->loopstart) ? mp->loopstart + mp->totloop - 1 : lidx - 1];
- medges[(prev_ml->e == mlp->e) ? prev_ml->e : ml->e].flag |= ME_SHARP;
- }
- }
- }
- }
-
- /* And now, recompute our new auto lnors and lnor spacearr! */
- BKE_lnor_spacearr_clear(&lnors_spacearr);
- BKE_mesh_normals_loop_split(
- mverts, numVerts, medges, numEdges, mloops, lnors, numLoops,
- mpolys, polynors, numPolys, use_split_normals, split_angle,
- &lnors_spacearr, NULL, loop_to_poly);
- }
- else {
- BLI_bitmap_set_all(done_loops, true, (size_t)numLoops);
- }
-
- /* And we just have to convert plain object-space custom normals to our lnor space-encoded ones. */
- for (i = 0; i < numLoops; i++) {
- if (!lnors_spacearr.lspacearr[i]) {
- BLI_BITMAP_DISABLE(done_loops, i);
- if (G.debug & G_DEBUG) {
- printf("WARNING! Still getting invalid NULL loop space in second loop for loop %d!\n", i);
- }
- continue;
- }
-
- if (BLI_BITMAP_TEST_BOOL(done_loops, i)) {
- /* Note we accumulate and average all custom normals in current smooth fan, to avoid getting different
- * clnors data (tiny differences in plain custom normals can give rather huge differences in
- * computed 2D factors).
- */
- LinkNode *loops = lnors_spacearr.lspacearr[i]->loops;
- if (lnors_spacearr.lspacearr[i]->flags & MLNOR_SPACE_IS_SINGLE) {
- BLI_assert(POINTER_AS_INT(loops) == i);
- const int nidx = use_vertices ? (int)mloops[i].v : i;
- float *nor = r_custom_loopnors[nidx];
-
- BKE_lnor_space_custom_normal_to_data(lnors_spacearr.lspacearr[i], nor, r_clnors_data[i]);
- BLI_BITMAP_DISABLE(done_loops, i);
- }
- else {
- int nbr_nors = 0;
- float avg_nor[3];
- short clnor_data_tmp[2], *clnor_data;
-
- zero_v3(avg_nor);
- while (loops) {
- const int lidx = POINTER_AS_INT(loops->link);
- const int nidx = use_vertices ? (int)mloops[lidx].v : lidx;
- float *nor = r_custom_loopnors[nidx];
-
- nbr_nors++;
- add_v3_v3(avg_nor, nor);
- BLI_SMALLSTACK_PUSH(clnors_data, (short *)r_clnors_data[lidx]);
-
- loops = loops->next;
- BLI_BITMAP_DISABLE(done_loops, lidx);
- }
-
- mul_v3_fl(avg_nor, 1.0f / (float)nbr_nors);
- BKE_lnor_space_custom_normal_to_data(lnors_spacearr.lspacearr[i], avg_nor, clnor_data_tmp);
-
- while ((clnor_data = BLI_SMALLSTACK_POP(clnors_data))) {
- clnor_data[0] = clnor_data_tmp[0];
- clnor_data[1] = clnor_data_tmp[1];
- }
- }
- }
- }
-
- MEM_freeN(lnors);
- MEM_freeN(loop_to_poly);
- MEM_freeN(done_loops);
- BKE_lnor_spacearr_free(&lnors_spacearr);
-}
-
-void BKE_mesh_normals_loop_custom_set(
- const MVert *mverts, const int numVerts, MEdge *medges, const int numEdges,
- MLoop *mloops, float (*r_custom_loopnors)[3], const int numLoops,
- MPoly *mpolys, const float (*polynors)[3], const int numPolys,
- short (*r_clnors_data)[2])
-{
- mesh_normals_loop_custom_set(
- mverts, numVerts, medges, numEdges, mloops, r_custom_loopnors, numLoops,
- mpolys, polynors, numPolys, r_clnors_data, false);
-}
-
-void BKE_mesh_normals_loop_custom_from_vertices_set(
- const MVert *mverts, float (*r_custom_vertnors)[3], const int numVerts,
- MEdge *medges, const int numEdges, MLoop *mloops, const int numLoops,
- MPoly *mpolys, const float (*polynors)[3], const int numPolys,
- short (*r_clnors_data)[2])
-{
- mesh_normals_loop_custom_set(
- mverts, numVerts, medges, numEdges, mloops, r_custom_vertnors, numLoops,
- mpolys, polynors, numPolys, r_clnors_data, true);
+static void mesh_normals_loop_custom_set(const MVert *mverts,
+ const int numVerts,
+ MEdge *medges,
+ const int numEdges,
+ MLoop *mloops,
+ float (*r_custom_loopnors)[3],
+ const int numLoops,
+ MPoly *mpolys,
+ const float (*polynors)[3],
+ const int numPolys,
+ short (*r_clnors_data)[2],
+ const bool use_vertices)
+{
+ /* We *may* make that poor BKE_mesh_normals_loop_split() even more complex by making it handling that
+ * feature too, would probably be more efficient in absolute.
+ * However, this function *is not* performance-critical, since it is mostly expected to be called
+ * by io addons when importing custom normals, and modifier (and perhaps from some editing tools later?).
+ * So better to keep some simplicity here, and just call BKE_mesh_normals_loop_split() twice!
+ */
+ MLoopNorSpaceArray lnors_spacearr = {NULL};
+ BLI_bitmap *done_loops = BLI_BITMAP_NEW((size_t)numLoops, __func__);
+ float(*lnors)[3] = MEM_calloc_arrayN((size_t)numLoops, sizeof(*lnors), __func__);
+ int *loop_to_poly = MEM_malloc_arrayN((size_t)numLoops, sizeof(int), __func__);
+ /* In this case we always consider split nors as ON, and do not want to use angle to define smooth fans! */
+ const bool use_split_normals = true;
+ const float split_angle = (float)M_PI;
+ int i;
+
+ BLI_SMALLSTACK_DECLARE(clnors_data, short *);
+
+ /* Compute current lnor spacearr. */
+ BKE_mesh_normals_loop_split(mverts,
+ numVerts,
+ medges,
+ numEdges,
+ mloops,
+ lnors,
+ numLoops,
+ mpolys,
+ polynors,
+ numPolys,
+ use_split_normals,
+ split_angle,
+ &lnors_spacearr,
+ NULL,
+ loop_to_poly);
+
+ /* Set all given zero vectors to their default value. */
+ if (use_vertices) {
+ for (i = 0; i < numVerts; i++) {
+ if (is_zero_v3(r_custom_loopnors[i])) {
+ normal_short_to_float_v3(r_custom_loopnors[i], mverts[i].no);
+ }
+ }
+ }
+ else {
+ for (i = 0; i < numLoops; i++) {
+ if (is_zero_v3(r_custom_loopnors[i])) {
+ copy_v3_v3(r_custom_loopnors[i], lnors[i]);
+ }
+ }
+ }
+
+ BLI_assert(lnors_spacearr.data_type == MLNOR_SPACEARR_LOOP_INDEX);
+
+ /* Now, check each current smooth fan (one lnor space per smooth fan!), and if all its matching custom lnors
+ * are not (enough) equal, add sharp edges as needed.
+ * This way, next time we run BKE_mesh_normals_loop_split(), we'll get lnor spacearr/smooth fans matching
+ * given custom lnors.
+ * Note this code *will never* unsharp edges!
+ * And quite obviously, when we set custom normals per vertices, running this is absolutely useless.
+ */
+ if (!use_vertices) {
+ for (i = 0; i < numLoops; i++) {
+ if (!lnors_spacearr.lspacearr[i]) {
+ /* This should not happen in theory, but in some rare case (probably ugly geometry)
+ * we can get some NULL loopspacearr at this point. :/
+ * Maybe we should set those loops' edges as sharp?
+ */
+ BLI_BITMAP_ENABLE(done_loops, i);
+ if (G.debug & G_DEBUG) {
+ printf("WARNING! Getting invalid NULL loop space for loop %d!\n", i);
+ }
+ continue;
+ }
+
+ if (!BLI_BITMAP_TEST(done_loops, i)) {
+ /* Notes:
+ * * In case of mono-loop smooth fan, we have nothing to do.
+ * * Loops in this linklist are ordered (in reversed order compared to how they were discovered by
+ * BKE_mesh_normals_loop_split(), but this is not a problem). Which means if we find a
+ * mismatching clnor, we know all remaining loops will have to be in a new, different smooth fan/
+ * lnor space.
+ * * In smooth fan case, we compare each clnor against a ref one, to avoid small differences adding
+ * up into a real big one in the end!
+ */
+ if (lnors_spacearr.lspacearr[i]->flags & MLNOR_SPACE_IS_SINGLE) {
+ BLI_BITMAP_ENABLE(done_loops, i);
+ continue;
+ }
+
+ LinkNode *loops = lnors_spacearr.lspacearr[i]->loops;
+ MLoop *prev_ml = NULL;
+ const float *org_nor = NULL;
+
+ while (loops) {
+ const int lidx = POINTER_AS_INT(loops->link);
+ MLoop *ml = &mloops[lidx];
+ const int nidx = lidx;
+ float *nor = r_custom_loopnors[nidx];
+
+ if (!org_nor) {
+ org_nor = nor;
+ }
+ else if (dot_v3v3(org_nor, nor) < LNOR_SPACE_TRIGO_THRESHOLD) {
+ /* Current normal differs too much from org one, we have to tag the edge between
+ * previous loop's face and current's one as sharp.
+ * We know those two loops do not point to the same edge, since we do not allow reversed winding
+ * in a same smooth fan.
+ */
+ const MPoly *mp = &mpolys[loop_to_poly[lidx]];
+ const MLoop *mlp =
+ &mloops[(lidx == mp->loopstart) ? mp->loopstart + mp->totloop - 1 : lidx - 1];
+ medges[(prev_ml->e == mlp->e) ? prev_ml->e : ml->e].flag |= ME_SHARP;
+
+ org_nor = nor;
+ }
+
+ prev_ml = ml;
+ loops = loops->next;
+ BLI_BITMAP_ENABLE(done_loops, lidx);
+ }
+
+ /* We also have to check between last and first loops, otherwise we may miss some sharp edges here!
+ * This is just a simplified version of above while loop.
+ * See T45984. */
+ loops = lnors_spacearr.lspacearr[i]->loops;
+ if (loops && org_nor) {
+ const int lidx = POINTER_AS_INT(loops->link);
+ MLoop *ml = &mloops[lidx];
+ const int nidx = lidx;
+ float *nor = r_custom_loopnors[nidx];
+
+ if (dot_v3v3(org_nor, nor) < LNOR_SPACE_TRIGO_THRESHOLD) {
+ const MPoly *mp = &mpolys[loop_to_poly[lidx]];
+ const MLoop *mlp =
+ &mloops[(lidx == mp->loopstart) ? mp->loopstart + mp->totloop - 1 : lidx - 1];
+ medges[(prev_ml->e == mlp->e) ? prev_ml->e : ml->e].flag |= ME_SHARP;
+ }
+ }
+ }
+ }
+
+ /* And now, recompute our new auto lnors and lnor spacearr! */
+ BKE_lnor_spacearr_clear(&lnors_spacearr);
+ BKE_mesh_normals_loop_split(mverts,
+ numVerts,
+ medges,
+ numEdges,
+ mloops,
+ lnors,
+ numLoops,
+ mpolys,
+ polynors,
+ numPolys,
+ use_split_normals,
+ split_angle,
+ &lnors_spacearr,
+ NULL,
+ loop_to_poly);
+ }
+ else {
+ BLI_bitmap_set_all(done_loops, true, (size_t)numLoops);
+ }
+
+ /* And we just have to convert plain object-space custom normals to our lnor space-encoded ones. */
+ for (i = 0; i < numLoops; i++) {
+ if (!lnors_spacearr.lspacearr[i]) {
+ BLI_BITMAP_DISABLE(done_loops, i);
+ if (G.debug & G_DEBUG) {
+ printf("WARNING! Still getting invalid NULL loop space in second loop for loop %d!\n", i);
+ }
+ continue;
+ }
+
+ if (BLI_BITMAP_TEST_BOOL(done_loops, i)) {
+ /* Note we accumulate and average all custom normals in current smooth fan, to avoid getting different
+ * clnors data (tiny differences in plain custom normals can give rather huge differences in
+ * computed 2D factors).
+ */
+ LinkNode *loops = lnors_spacearr.lspacearr[i]->loops;
+ if (lnors_spacearr.lspacearr[i]->flags & MLNOR_SPACE_IS_SINGLE) {
+ BLI_assert(POINTER_AS_INT(loops) == i);
+ const int nidx = use_vertices ? (int)mloops[i].v : i;
+ float *nor = r_custom_loopnors[nidx];
+
+ BKE_lnor_space_custom_normal_to_data(lnors_spacearr.lspacearr[i], nor, r_clnors_data[i]);
+ BLI_BITMAP_DISABLE(done_loops, i);
+ }
+ else {
+ int nbr_nors = 0;
+ float avg_nor[3];
+ short clnor_data_tmp[2], *clnor_data;
+
+ zero_v3(avg_nor);
+ while (loops) {
+ const int lidx = POINTER_AS_INT(loops->link);
+ const int nidx = use_vertices ? (int)mloops[lidx].v : lidx;
+ float *nor = r_custom_loopnors[nidx];
+
+ nbr_nors++;
+ add_v3_v3(avg_nor, nor);
+ BLI_SMALLSTACK_PUSH(clnors_data, (short *)r_clnors_data[lidx]);
+
+ loops = loops->next;
+ BLI_BITMAP_DISABLE(done_loops, lidx);
+ }
+
+ mul_v3_fl(avg_nor, 1.0f / (float)nbr_nors);
+ BKE_lnor_space_custom_normal_to_data(lnors_spacearr.lspacearr[i], avg_nor, clnor_data_tmp);
+
+ while ((clnor_data = BLI_SMALLSTACK_POP(clnors_data))) {
+ clnor_data[0] = clnor_data_tmp[0];
+ clnor_data[1] = clnor_data_tmp[1];
+ }
+ }
+ }
+ }
+
+ MEM_freeN(lnors);
+ MEM_freeN(loop_to_poly);
+ MEM_freeN(done_loops);
+ BKE_lnor_spacearr_free(&lnors_spacearr);
+}
+
+void BKE_mesh_normals_loop_custom_set(const MVert *mverts,
+ const int numVerts,
+ MEdge *medges,
+ const int numEdges,
+ MLoop *mloops,
+ float (*r_custom_loopnors)[3],
+ const int numLoops,
+ MPoly *mpolys,
+ const float (*polynors)[3],
+ const int numPolys,
+ short (*r_clnors_data)[2])
+{
+ mesh_normals_loop_custom_set(mverts,
+ numVerts,
+ medges,
+ numEdges,
+ mloops,
+ r_custom_loopnors,
+ numLoops,
+ mpolys,
+ polynors,
+ numPolys,
+ r_clnors_data,
+ false);
+}
+
+void BKE_mesh_normals_loop_custom_from_vertices_set(const MVert *mverts,
+ float (*r_custom_vertnors)[3],
+ const int numVerts,
+ MEdge *medges,
+ const int numEdges,
+ MLoop *mloops,
+ const int numLoops,
+ MPoly *mpolys,
+ const float (*polynors)[3],
+ const int numPolys,
+ short (*r_clnors_data)[2])
+{
+ mesh_normals_loop_custom_set(mverts,
+ numVerts,
+ medges,
+ numEdges,
+ mloops,
+ r_custom_vertnors,
+ numLoops,
+ mpolys,
+ polynors,
+ numPolys,
+ r_clnors_data,
+ true);
}
static void mesh_set_custom_normals(Mesh *mesh, float (*r_custom_nors)[3], const bool use_vertices)
{
- short (*clnors)[2];
- const int numloops = mesh->totloop;
-
- clnors = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL);
- if (clnors != NULL) {
- memset(clnors, 0, sizeof(*clnors) * (size_t)numloops);
- }
- else {
- clnors = CustomData_add_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL, numloops);
- }
-
- float (*polynors)[3] = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
- bool free_polynors = false;
- if (polynors == NULL) {
- polynors = MEM_mallocN(sizeof(float[3]) * (size_t)mesh->totpoly, __func__);
- BKE_mesh_calc_normals_poly(
- mesh->mvert, NULL, mesh->totvert,
- mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, polynors, false);
- free_polynors = true;
- }
-
- mesh_normals_loop_custom_set(
- mesh->mvert, mesh->totvert, mesh->medge, mesh->totedge, mesh->mloop, r_custom_nors, mesh->totloop,
- mesh->mpoly, polynors, mesh->totpoly, clnors, use_vertices);
-
- if (free_polynors) {
- MEM_freeN(polynors);
- }
+ short(*clnors)[2];
+ const int numloops = mesh->totloop;
+
+ clnors = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL);
+ if (clnors != NULL) {
+ memset(clnors, 0, sizeof(*clnors) * (size_t)numloops);
+ }
+ else {
+ clnors = CustomData_add_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL, numloops);
+ }
+
+ float(*polynors)[3] = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
+ bool free_polynors = false;
+ if (polynors == NULL) {
+ polynors = MEM_mallocN(sizeof(float[3]) * (size_t)mesh->totpoly, __func__);
+ BKE_mesh_calc_normals_poly(mesh->mvert,
+ NULL,
+ mesh->totvert,
+ mesh->mloop,
+ mesh->mpoly,
+ mesh->totloop,
+ mesh->totpoly,
+ polynors,
+ false);
+ free_polynors = true;
+ }
+
+ mesh_normals_loop_custom_set(mesh->mvert,
+ mesh->totvert,
+ mesh->medge,
+ mesh->totedge,
+ mesh->mloop,
+ r_custom_nors,
+ mesh->totloop,
+ mesh->mpoly,
+ polynors,
+ mesh->totpoly,
+ clnors,
+ use_vertices);
+
+ if (free_polynors) {
+ MEM_freeN(polynors);
+ }
}
/**
@@ -1891,7 +2093,7 @@ static void mesh_set_custom_normals(Mesh *mesh, float (*r_custom_nors)[3], const
*/
void BKE_mesh_set_custom_normals(Mesh *mesh, float (*r_custom_loopnors)[3])
{
- mesh_set_custom_normals(mesh, r_custom_loopnors, false);
+ mesh_set_custom_normals(mesh, r_custom_loopnors, false);
}
/**
@@ -1902,47 +2104,46 @@ void BKE_mesh_set_custom_normals(Mesh *mesh, float (*r_custom_loopnors)[3])
*/
void BKE_mesh_set_custom_normals_from_vertices(Mesh *mesh, float (*r_custom_vertnors)[3])
{
- mesh_set_custom_normals(mesh, r_custom_vertnors, true);
+ mesh_set_custom_normals(mesh, r_custom_vertnors, true);
}
-
/**
* Computes average per-vertex normals from given custom loop normals.
*
* \param clnors: The computed custom loop normals.
* \param r_vert_clnors: The (already allocated) array where to store averaged per-vertex normals.
*/
-void BKE_mesh_normals_loop_to_vertex(
- const int numVerts, const MLoop *mloops, const int numLoops,
- const float (*clnors)[3], float (*r_vert_clnors)[3])
+void BKE_mesh_normals_loop_to_vertex(const int numVerts,
+ const MLoop *mloops,
+ const int numLoops,
+ const float (*clnors)[3],
+ float (*r_vert_clnors)[3])
{
- const MLoop *ml;
- int i;
+ const MLoop *ml;
+ int i;
- int *vert_loops_nbr = MEM_calloc_arrayN((size_t)numVerts, sizeof(*vert_loops_nbr), __func__);
+ int *vert_loops_nbr = MEM_calloc_arrayN((size_t)numVerts, sizeof(*vert_loops_nbr), __func__);
- copy_vn_fl((float *)r_vert_clnors, 3 * numVerts, 0.0f);
+ copy_vn_fl((float *)r_vert_clnors, 3 * numVerts, 0.0f);
- for (i = 0, ml = mloops; i < numLoops; i++, ml++) {
- const unsigned int v = ml->v;
+ for (i = 0, ml = mloops; i < numLoops; i++, ml++) {
+ const unsigned int v = ml->v;
- add_v3_v3(r_vert_clnors[v], clnors[i]);
- vert_loops_nbr[v]++;
- }
+ add_v3_v3(r_vert_clnors[v], clnors[i]);
+ vert_loops_nbr[v]++;
+ }
- for (i = 0; i < numVerts; i++) {
- mul_v3_fl(r_vert_clnors[i], 1.0f / (float)vert_loops_nbr[i]);
- }
+ for (i = 0; i < numVerts; i++) {
+ mul_v3_fl(r_vert_clnors[i], 1.0f / (float)vert_loops_nbr[i]);
+ }
- MEM_freeN(vert_loops_nbr);
+ MEM_freeN(vert_loops_nbr);
}
-
#undef LNOR_SPACE_TRIGO_THRESHOLD
/** \} */
-
/* -------------------------------------------------------------------- */
/** \name Polygon Calculations
* \{ */
@@ -1954,175 +2155,169 @@ void BKE_mesh_normals_loop_to_vertex(
* polygon See Graphics Gems for
* computing newell normal.
*/
-static void mesh_calc_ngon_normal(
- const MPoly *mpoly, const MLoop *loopstart,
- const MVert *mvert, float normal[3])
-{
- const int nverts = mpoly->totloop;
- const float *v_prev = mvert[loopstart[nverts - 1].v].co;
- const float *v_curr;
- int i;
-
- zero_v3(normal);
-
- /* Newell's Method */
- for (i = 0; i < nverts; i++) {
- v_curr = mvert[loopstart[i].v].co;
- add_newell_cross_v3_v3v3(normal, v_prev, v_curr);
- v_prev = v_curr;
- }
-
- if (UNLIKELY(normalize_v3(normal) == 0.0f)) {
- normal[2] = 1.0f; /* other axis set to 0.0 */
- }
-}
-
-void BKE_mesh_calc_poly_normal(
- const MPoly *mpoly, const MLoop *loopstart,
- const MVert *mvarray, float r_no[3])
-{
- if (mpoly->totloop > 4) {
- mesh_calc_ngon_normal(mpoly, loopstart, mvarray, r_no);
- }
- else if (mpoly->totloop == 3) {
- normal_tri_v3(
- r_no,
- mvarray[loopstart[0].v].co,
- mvarray[loopstart[1].v].co,
- mvarray[loopstart[2].v].co);
- }
- else if (mpoly->totloop == 4) {
- normal_quad_v3(
- r_no,
- mvarray[loopstart[0].v].co,
- mvarray[loopstart[1].v].co,
- mvarray[loopstart[2].v].co,
- mvarray[loopstart[3].v].co);
- }
- else { /* horrible, two sided face! */
- r_no[0] = 0.0;
- r_no[1] = 0.0;
- r_no[2] = 1.0;
- }
+static void mesh_calc_ngon_normal(const MPoly *mpoly,
+ const MLoop *loopstart,
+ const MVert *mvert,
+ float normal[3])
+{
+ const int nverts = mpoly->totloop;
+ const float *v_prev = mvert[loopstart[nverts - 1].v].co;
+ const float *v_curr;
+ int i;
+
+ zero_v3(normal);
+
+ /* Newell's Method */
+ for (i = 0; i < nverts; i++) {
+ v_curr = mvert[loopstart[i].v].co;
+ add_newell_cross_v3_v3v3(normal, v_prev, v_curr);
+ v_prev = v_curr;
+ }
+
+ if (UNLIKELY(normalize_v3(normal) == 0.0f)) {
+ normal[2] = 1.0f; /* other axis set to 0.0 */
+ }
+}
+
+void BKE_mesh_calc_poly_normal(const MPoly *mpoly,
+ const MLoop *loopstart,
+ const MVert *mvarray,
+ float r_no[3])
+{
+ if (mpoly->totloop > 4) {
+ mesh_calc_ngon_normal(mpoly, loopstart, mvarray, r_no);
+ }
+ else if (mpoly->totloop == 3) {
+ normal_tri_v3(
+ r_no, mvarray[loopstart[0].v].co, mvarray[loopstart[1].v].co, mvarray[loopstart[2].v].co);
+ }
+ else if (mpoly->totloop == 4) {
+ normal_quad_v3(r_no,
+ mvarray[loopstart[0].v].co,
+ mvarray[loopstart[1].v].co,
+ mvarray[loopstart[2].v].co,
+ mvarray[loopstart[3].v].co);
+ }
+ else { /* horrible, two sided face! */
+ r_no[0] = 0.0;
+ r_no[1] = 0.0;
+ r_no[2] = 1.0;
+ }
}
/* duplicate of function above _but_ takes coords rather then mverts */
-static void mesh_calc_ngon_normal_coords(
- const MPoly *mpoly, const MLoop *loopstart,
- const float (*vertex_coords)[3], float r_normal[3])
-{
- const int nverts = mpoly->totloop;
- const float *v_prev = vertex_coords[loopstart[nverts - 1].v];
- const float *v_curr;
- int i;
-
- zero_v3(r_normal);
-
- /* Newell's Method */
- for (i = 0; i < nverts; i++) {
- v_curr = vertex_coords[loopstart[i].v];
- add_newell_cross_v3_v3v3(r_normal, v_prev, v_curr);
- v_prev = v_curr;
- }
-
- if (UNLIKELY(normalize_v3(r_normal) == 0.0f)) {
- r_normal[2] = 1.0f; /* other axis set to 0.0 */
- }
-}
-
-void BKE_mesh_calc_poly_normal_coords(
- const MPoly *mpoly, const MLoop *loopstart,
- const float (*vertex_coords)[3], float r_no[3])
-{
- if (mpoly->totloop > 4) {
- mesh_calc_ngon_normal_coords(mpoly, loopstart, vertex_coords, r_no);
- }
- else if (mpoly->totloop == 3) {
- normal_tri_v3(
- r_no,
- vertex_coords[loopstart[0].v],
- vertex_coords[loopstart[1].v],
- vertex_coords[loopstart[2].v]);
- }
- else if (mpoly->totloop == 4) {
- normal_quad_v3(
- r_no,
- vertex_coords[loopstart[0].v],
- vertex_coords[loopstart[1].v],
- vertex_coords[loopstart[2].v],
- vertex_coords[loopstart[3].v]);
- }
- else { /* horrible, two sided face! */
- r_no[0] = 0.0;
- r_no[1] = 0.0;
- r_no[2] = 1.0;
- }
-}
-
-static void mesh_calc_ngon_center(
- const MPoly *mpoly, const MLoop *loopstart,
- const MVert *mvert, float cent[3])
-{
- const float w = 1.0f / (float)mpoly->totloop;
- int i;
-
- zero_v3(cent);
-
- for (i = 0; i < mpoly->totloop; i++) {
- madd_v3_v3fl(cent, mvert[(loopstart++)->v].co, w);
- }
-}
-
-void BKE_mesh_calc_poly_center(
- const MPoly *mpoly, const MLoop *loopstart,
- const MVert *mvarray, float r_cent[3])
-{
- if (mpoly->totloop == 3) {
- mid_v3_v3v3v3(
- r_cent,
- mvarray[loopstart[0].v].co,
- mvarray[loopstart[1].v].co,
- mvarray[loopstart[2].v].co);
- }
- else if (mpoly->totloop == 4) {
- mid_v3_v3v3v3v3(
- r_cent,
- mvarray[loopstart[0].v].co,
- mvarray[loopstart[1].v].co,
- mvarray[loopstart[2].v].co,
- mvarray[loopstart[3].v].co);
- }
- else {
- mesh_calc_ngon_center(mpoly, loopstart, mvarray, r_cent);
- }
+static void mesh_calc_ngon_normal_coords(const MPoly *mpoly,
+ const MLoop *loopstart,
+ const float (*vertex_coords)[3],
+ float r_normal[3])
+{
+ const int nverts = mpoly->totloop;
+ const float *v_prev = vertex_coords[loopstart[nverts - 1].v];
+ const float *v_curr;
+ int i;
+
+ zero_v3(r_normal);
+
+ /* Newell's Method */
+ for (i = 0; i < nverts; i++) {
+ v_curr = vertex_coords[loopstart[i].v];
+ add_newell_cross_v3_v3v3(r_normal, v_prev, v_curr);
+ v_prev = v_curr;
+ }
+
+ if (UNLIKELY(normalize_v3(r_normal) == 0.0f)) {
+ r_normal[2] = 1.0f; /* other axis set to 0.0 */
+ }
+}
+
+void BKE_mesh_calc_poly_normal_coords(const MPoly *mpoly,
+ const MLoop *loopstart,
+ const float (*vertex_coords)[3],
+ float r_no[3])
+{
+ if (mpoly->totloop > 4) {
+ mesh_calc_ngon_normal_coords(mpoly, loopstart, vertex_coords, r_no);
+ }
+ else if (mpoly->totloop == 3) {
+ normal_tri_v3(r_no,
+ vertex_coords[loopstart[0].v],
+ vertex_coords[loopstart[1].v],
+ vertex_coords[loopstart[2].v]);
+ }
+ else if (mpoly->totloop == 4) {
+ normal_quad_v3(r_no,
+ vertex_coords[loopstart[0].v],
+ vertex_coords[loopstart[1].v],
+ vertex_coords[loopstart[2].v],
+ vertex_coords[loopstart[3].v]);
+ }
+ else { /* horrible, two sided face! */
+ r_no[0] = 0.0;
+ r_no[1] = 0.0;
+ r_no[2] = 1.0;
+ }
+}
+
+static void mesh_calc_ngon_center(const MPoly *mpoly,
+ const MLoop *loopstart,
+ const MVert *mvert,
+ float cent[3])
+{
+ const float w = 1.0f / (float)mpoly->totloop;
+ int i;
+
+ zero_v3(cent);
+
+ for (i = 0; i < mpoly->totloop; i++) {
+ madd_v3_v3fl(cent, mvert[(loopstart++)->v].co, w);
+ }
+}
+
+void BKE_mesh_calc_poly_center(const MPoly *mpoly,
+ const MLoop *loopstart,
+ const MVert *mvarray,
+ float r_cent[3])
+{
+ if (mpoly->totloop == 3) {
+ mid_v3_v3v3v3(r_cent,
+ mvarray[loopstart[0].v].co,
+ mvarray[loopstart[1].v].co,
+ mvarray[loopstart[2].v].co);
+ }
+ else if (mpoly->totloop == 4) {
+ mid_v3_v3v3v3v3(r_cent,
+ mvarray[loopstart[0].v].co,
+ mvarray[loopstart[1].v].co,
+ mvarray[loopstart[2].v].co,
+ mvarray[loopstart[3].v].co);
+ }
+ else {
+ mesh_calc_ngon_center(mpoly, loopstart, mvarray, r_cent);
+ }
}
/* note, passing polynormal is only a speedup so we can skip calculating it */
-float BKE_mesh_calc_poly_area(
- const MPoly *mpoly, const MLoop *loopstart,
- const MVert *mvarray)
-{
- if (mpoly->totloop == 3) {
- return area_tri_v3(
- mvarray[loopstart[0].v].co,
- mvarray[loopstart[1].v].co,
- mvarray[loopstart[2].v].co);
- }
- else {
- int i;
- const MLoop *l_iter = loopstart;
- float area;
- float (*vertexcos)[3] = BLI_array_alloca(vertexcos, (size_t)mpoly->totloop);
-
- /* pack vertex cos into an array for area_poly_v3 */
- for (i = 0; i < mpoly->totloop; i++, l_iter++) {
- copy_v3_v3(vertexcos[i], mvarray[l_iter->v].co);
- }
-
- /* finally calculate the area */
- area = area_poly_v3((const float (*)[3])vertexcos, (unsigned int)mpoly->totloop);
-
- return area;
- }
+float BKE_mesh_calc_poly_area(const MPoly *mpoly, const MLoop *loopstart, const MVert *mvarray)
+{
+ if (mpoly->totloop == 3) {
+ return area_tri_v3(
+ mvarray[loopstart[0].v].co, mvarray[loopstart[1].v].co, mvarray[loopstart[2].v].co);
+ }
+ else {
+ int i;
+ const MLoop *l_iter = loopstart;
+ float area;
+ float(*vertexcos)[3] = BLI_array_alloca(vertexcos, (size_t)mpoly->totloop);
+
+ /* pack vertex cos into an array for area_poly_v3 */
+ for (i = 0; i < mpoly->totloop; i++, l_iter++) {
+ copy_v3_v3(vertexcos[i], mvarray[l_iter->v].co);
+ }
+
+ /* finally calculate the area */
+ area = area_poly_v3((const float(*)[3])vertexcos, (unsigned int)mpoly->totloop);
+
+ return area;
+ }
}
/**
@@ -2141,41 +2336,42 @@ float BKE_mesh_calc_poly_area(
* - The resulting volume will only be correct if the mesh is manifold and has consistent face winding
* (non-contiguous face normals or holes in the mesh surface).
*/
-static float mesh_calc_poly_volume_centroid(
- const MPoly *mpoly, const MLoop *loopstart, const MVert *mvarray,
- float r_cent[3])
+static float mesh_calc_poly_volume_centroid(const MPoly *mpoly,
+ const MLoop *loopstart,
+ const MVert *mvarray,
+ float r_cent[3])
{
- const float *v_pivot, *v_step1;
- float total_volume = 0.0f;
+ const float *v_pivot, *v_step1;
+ float total_volume = 0.0f;
- zero_v3(r_cent);
+ zero_v3(r_cent);
- v_pivot = mvarray[loopstart[0].v].co;
- v_step1 = mvarray[loopstart[1].v].co;
+ v_pivot = mvarray[loopstart[0].v].co;
+ v_step1 = mvarray[loopstart[1].v].co;
- for (int i = 2; i < mpoly->totloop; i++) {
- const float *v_step2 = mvarray[loopstart[i].v].co;
+ for (int i = 2; i < mpoly->totloop; i++) {
+ const float *v_step2 = mvarray[loopstart[i].v].co;
- /* Calculate the 6x volume of the tetrahedron formed by the 3 vertices
- * of the triangle and the origin as the fourth vertex */
- float v_cross[3];
- cross_v3_v3v3(v_cross, v_pivot, v_step1);
- const float tetra_volume = dot_v3v3 (v_cross, v_step2);
- total_volume += tetra_volume;
+ /* Calculate the 6x volume of the tetrahedron formed by the 3 vertices
+ * of the triangle and the origin as the fourth vertex */
+ float v_cross[3];
+ cross_v3_v3v3(v_cross, v_pivot, v_step1);
+ const float tetra_volume = dot_v3v3(v_cross, v_step2);
+ total_volume += tetra_volume;
- /* Calculate the centroid of the tetrahedron formed by the 3 vertices
- * of the triangle and the origin as the fourth vertex.
- * The centroid is simply the average of the 4 vertices.
- *
- * Note that the vector is 4x the actual centroid so the division can be done once at the end. */
- for (uint j = 0; j < 3; j++) {
- r_cent[j] += tetra_volume * (v_pivot[j] + v_step1[j] + v_step2[j]);
- }
+ /* Calculate the centroid of the tetrahedron formed by the 3 vertices
+ * of the triangle and the origin as the fourth vertex.
+ * The centroid is simply the average of the 4 vertices.
+ *
+ * Note that the vector is 4x the actual centroid so the division can be done once at the end. */
+ for (uint j = 0; j < 3; j++) {
+ r_cent[j] += tetra_volume * (v_pivot[j] + v_step1[j] + v_step2[j]);
+ }
- v_step1 = v_step2;
- }
+ v_step1 = v_step2;
+ }
- return total_volume;
+ return total_volume;
}
/**
@@ -2184,154 +2380,158 @@ static float mesh_calc_poly_volume_centroid(
* - This has the advantage over #mesh_calc_poly_volume_centroid
* that it doesn't depend on solid geometry, instead it weights the surface by volume.
*/
-static float mesh_calc_poly_area_centroid(
- const MPoly *mpoly, const MLoop *loopstart, const MVert *mvarray,
- float r_cent[3])
+static float mesh_calc_poly_area_centroid(const MPoly *mpoly,
+ const MLoop *loopstart,
+ const MVert *mvarray,
+ float r_cent[3])
{
- int i;
- float tri_area;
- float total_area = 0.0f;
- float v1[3], v2[3], v3[3], normal[3], tri_cent[3];
+ int i;
+ float tri_area;
+ float total_area = 0.0f;
+ float v1[3], v2[3], v3[3], normal[3], tri_cent[3];
- BKE_mesh_calc_poly_normal(mpoly, loopstart, mvarray, normal);
- copy_v3_v3(v1, mvarray[loopstart[0].v].co);
- copy_v3_v3(v2, mvarray[loopstart[1].v].co);
- zero_v3(r_cent);
+ BKE_mesh_calc_poly_normal(mpoly, loopstart, mvarray, normal);
+ copy_v3_v3(v1, mvarray[loopstart[0].v].co);
+ copy_v3_v3(v2, mvarray[loopstart[1].v].co);
+ zero_v3(r_cent);
- for (i = 2; i < mpoly->totloop; i++) {
- copy_v3_v3(v3, mvarray[loopstart[i].v].co);
+ for (i = 2; i < mpoly->totloop; i++) {
+ copy_v3_v3(v3, mvarray[loopstart[i].v].co);
- tri_area = area_tri_signed_v3(v1, v2, v3, normal);
- total_area += tri_area;
+ tri_area = area_tri_signed_v3(v1, v2, v3, normal);
+ total_area += tri_area;
- mid_v3_v3v3v3(tri_cent, v1, v2, v3);
- madd_v3_v3fl(r_cent, tri_cent, tri_area);
+ mid_v3_v3v3v3(tri_cent, v1, v2, v3);
+ madd_v3_v3fl(r_cent, tri_cent, tri_area);
- copy_v3_v3(v2, v3);
- }
+ copy_v3_v3(v2, v3);
+ }
- mul_v3_fl(r_cent, 1.0f / total_area);
+ mul_v3_fl(r_cent, 1.0f / total_area);
- return total_area;
+ return total_area;
}
-void BKE_mesh_calc_poly_angles(
- const MPoly *mpoly, const MLoop *loopstart,
- const MVert *mvarray, float angles[])
+void BKE_mesh_calc_poly_angles(const MPoly *mpoly,
+ const MLoop *loopstart,
+ const MVert *mvarray,
+ float angles[])
{
- float nor_prev[3];
- float nor_next[3];
+ float nor_prev[3];
+ float nor_next[3];
- int i_this = mpoly->totloop - 1;
- int i_next = 0;
+ int i_this = mpoly->totloop - 1;
+ int i_next = 0;
- sub_v3_v3v3(nor_prev, mvarray[loopstart[i_this - 1].v].co, mvarray[loopstart[i_this].v].co);
- normalize_v3(nor_prev);
+ sub_v3_v3v3(nor_prev, mvarray[loopstart[i_this - 1].v].co, mvarray[loopstart[i_this].v].co);
+ normalize_v3(nor_prev);
- while (i_next < mpoly->totloop) {
- sub_v3_v3v3(nor_next, mvarray[loopstart[i_this].v].co, mvarray[loopstart[i_next].v].co);
- normalize_v3(nor_next);
- angles[i_this] = angle_normalized_v3v3(nor_prev, nor_next);
+ while (i_next < mpoly->totloop) {
+ sub_v3_v3v3(nor_next, mvarray[loopstart[i_this].v].co, mvarray[loopstart[i_next].v].co);
+ normalize_v3(nor_next);
+ angles[i_this] = angle_normalized_v3v3(nor_prev, nor_next);
- /* step */
- copy_v3_v3(nor_prev, nor_next);
- i_this = i_next;
- i_next++;
- }
+ /* step */
+ copy_v3_v3(nor_prev, nor_next);
+ i_this = i_next;
+ i_next++;
+ }
}
void BKE_mesh_poly_edgehash_insert(EdgeHash *ehash, const MPoly *mp, const MLoop *mloop)
{
- const MLoop *ml, *ml_next;
- int i = mp->totloop;
+ const MLoop *ml, *ml_next;
+ int i = mp->totloop;
- ml_next = mloop; /* first loop */
- ml = &ml_next[i - 1]; /* last loop */
+ ml_next = mloop; /* first loop */
+ ml = &ml_next[i - 1]; /* last loop */
- while (i-- != 0) {
- BLI_edgehash_reinsert(ehash, ml->v, ml_next->v, NULL);
+ while (i-- != 0) {
+ BLI_edgehash_reinsert(ehash, ml->v, ml_next->v, NULL);
- ml = ml_next;
- ml_next++;
- }
+ ml = ml_next;
+ ml_next++;
+ }
}
-void BKE_mesh_poly_edgebitmap_insert(unsigned int *edge_bitmap, const MPoly *mp, const MLoop *mloop)
+void BKE_mesh_poly_edgebitmap_insert(unsigned int *edge_bitmap,
+ const MPoly *mp,
+ const MLoop *mloop)
{
- const MLoop *ml;
- int i = mp->totloop;
+ const MLoop *ml;
+ int i = mp->totloop;
- ml = mloop;
+ ml = mloop;
- while (i-- != 0) {
- BLI_BITMAP_ENABLE(edge_bitmap, ml->e);
- ml++;
- }
+ while (i-- != 0) {
+ BLI_BITMAP_ENABLE(edge_bitmap, ml->e);
+ ml++;
+ }
}
/** \} */
-
/* -------------------------------------------------------------------- */
/** \name Mesh Center Calculation
* \{ */
bool BKE_mesh_center_median(const Mesh *me, float r_cent[3])
{
- int i = me->totvert;
- const MVert *mvert;
- zero_v3(r_cent);
- for (mvert = me->mvert; i--; mvert++) {
- add_v3_v3(r_cent, mvert->co);
- }
- /* otherwise we get NAN for 0 verts */
- if (me->totvert) {
- mul_v3_fl(r_cent, 1.0f / (float)me->totvert);
- }
+ int i = me->totvert;
+ const MVert *mvert;
+ zero_v3(r_cent);
+ for (mvert = me->mvert; i--; mvert++) {
+ add_v3_v3(r_cent, mvert->co);
+ }
+ /* otherwise we get NAN for 0 verts */
+ if (me->totvert) {
+ mul_v3_fl(r_cent, 1.0f / (float)me->totvert);
+ }
- return (me->totvert != 0);
+ return (me->totvert != 0);
}
bool BKE_mesh_center_bounds(const Mesh *me, float r_cent[3])
{
- float min[3], max[3];
- INIT_MINMAX(min, max);
- if (BKE_mesh_minmax(me, min, max)) {
- mid_v3_v3v3(r_cent, min, max);
- return true;
- }
+ float min[3], max[3];
+ INIT_MINMAX(min, max);
+ if (BKE_mesh_minmax(me, min, max)) {
+ mid_v3_v3v3(r_cent, min, max);
+ return true;
+ }
- return false;
+ return false;
}
bool BKE_mesh_center_of_surface(const Mesh *me, float r_cent[3])
{
- int i = me->totpoly;
- MPoly *mpoly;
- float poly_area;
- float total_area = 0.0f;
- float poly_cent[3];
+ int i = me->totpoly;
+ MPoly *mpoly;
+ float poly_area;
+ float total_area = 0.0f;
+ float poly_cent[3];
- zero_v3(r_cent);
+ zero_v3(r_cent);
- /* calculate a weighted average of polygon centroids */
- for (mpoly = me->mpoly; i--; mpoly++) {
- poly_area = mesh_calc_poly_area_centroid(mpoly, me->mloop + mpoly->loopstart, me->mvert, poly_cent);
+ /* calculate a weighted average of polygon centroids */
+ for (mpoly = me->mpoly; i--; mpoly++) {
+ poly_area = mesh_calc_poly_area_centroid(
+ mpoly, me->mloop + mpoly->loopstart, me->mvert, poly_cent);
- madd_v3_v3fl(r_cent, poly_cent, poly_area);
- total_area += poly_area;
- }
- /* otherwise we get NAN for 0 polys */
- if (me->totpoly) {
- mul_v3_fl(r_cent, 1.0f / total_area);
- }
+ madd_v3_v3fl(r_cent, poly_cent, poly_area);
+ total_area += poly_area;
+ }
+ /* otherwise we get NAN for 0 polys */
+ if (me->totpoly) {
+ mul_v3_fl(r_cent, 1.0f / total_area);
+ }
- /* zero area faces cause this, fallback to median */
- if (UNLIKELY(!is_finite_v3(r_cent))) {
- return BKE_mesh_center_median(me, r_cent);
- }
+ /* zero area faces cause this, fallback to median */
+ if (UNLIKELY(!is_finite_v3(r_cent))) {
+ return BKE_mesh_center_median(me, r_cent);
+ }
- return (me->totpoly != 0);
+ return (me->totpoly != 0);
}
/**
@@ -2339,77 +2539,79 @@ bool BKE_mesh_center_of_surface(const Mesh *me, float r_cent[3])
*/
bool BKE_mesh_center_of_volume(const Mesh *me, float r_cent[3])
{
- int i = me->totpoly;
- MPoly *mpoly;
- float poly_volume;
- float total_volume = 0.0f;
- float poly_cent[3];
+ int i = me->totpoly;
+ MPoly *mpoly;
+ float poly_volume;
+ float total_volume = 0.0f;
+ float poly_cent[3];
- zero_v3(r_cent);
+ zero_v3(r_cent);
- /* calculate a weighted average of polyhedron centroids */
- for (mpoly = me->mpoly; i--; mpoly++) {
- poly_volume = mesh_calc_poly_volume_centroid(mpoly, me->mloop + mpoly->loopstart, me->mvert, poly_cent);
+ /* calculate a weighted average of polyhedron centroids */
+ for (mpoly = me->mpoly; i--; mpoly++) {
+ poly_volume = mesh_calc_poly_volume_centroid(
+ mpoly, me->mloop + mpoly->loopstart, me->mvert, poly_cent);
- /* poly_cent is already volume-weighted, so no need to multiply by the volume */
- add_v3_v3(r_cent, poly_cent);
- total_volume += poly_volume;
- }
- /* otherwise we get NAN for 0 polys */
- if (total_volume != 0.0f) {
- /* multiply by 0.25 to get the correct centroid */
- /* no need to divide volume by 6 as the centroid is weighted by 6x the volume, so it all cancels out */
- mul_v3_fl(r_cent, 0.25f / total_volume);
- }
+ /* poly_cent is already volume-weighted, so no need to multiply by the volume */
+ add_v3_v3(r_cent, poly_cent);
+ total_volume += poly_volume;
+ }
+ /* otherwise we get NAN for 0 polys */
+ if (total_volume != 0.0f) {
+ /* multiply by 0.25 to get the correct centroid */
+ /* no need to divide volume by 6 as the centroid is weighted by 6x the volume, so it all cancels out */
+ mul_v3_fl(r_cent, 0.25f / total_volume);
+ }
- /* this can happen for non-manifold objects, fallback to median */
- if (UNLIKELY(!is_finite_v3(r_cent))) {
- return BKE_mesh_center_median(me, r_cent);
- }
+ /* this can happen for non-manifold objects, fallback to median */
+ if (UNLIKELY(!is_finite_v3(r_cent))) {
+ return BKE_mesh_center_median(me, r_cent);
+ }
- return (me->totpoly != 0);
+ return (me->totpoly != 0);
}
/** \} */
-
/* -------------------------------------------------------------------- */
/** \name Mesh Volume Calculation
* \{ */
-static bool mesh_calc_center_centroid_ex(
- const MVert *mverts, int UNUSED(mverts_num),
- const MLoopTri *looptri, int looptri_num,
- const MLoop *mloop, float r_center[3])
+static bool mesh_calc_center_centroid_ex(const MVert *mverts,
+ int UNUSED(mverts_num),
+ const MLoopTri *looptri,
+ int looptri_num,
+ const MLoop *mloop,
+ float r_center[3])
{
- const MLoopTri *lt;
- float totweight;
- int i;
+ const MLoopTri *lt;
+ float totweight;
+ int i;
- zero_v3(r_center);
+ zero_v3(r_center);
- if (looptri_num == 0)
- return false;
+ if (looptri_num == 0)
+ return false;
- totweight = 0.0f;
- for (i = 0, lt = looptri; i < looptri_num; i++, lt++) {
- const MVert *v1 = &mverts[mloop[lt->tri[0]].v];
- const MVert *v2 = &mverts[mloop[lt->tri[1]].v];
- const MVert *v3 = &mverts[mloop[lt->tri[2]].v];
- float area;
+ totweight = 0.0f;
+ for (i = 0, lt = looptri; i < looptri_num; i++, lt++) {
+ const MVert *v1 = &mverts[mloop[lt->tri[0]].v];
+ const MVert *v2 = &mverts[mloop[lt->tri[1]].v];
+ const MVert *v3 = &mverts[mloop[lt->tri[2]].v];
+ float area;
- area = area_tri_v3(v1->co, v2->co, v3->co);
- madd_v3_v3fl(r_center, v1->co, area);
- madd_v3_v3fl(r_center, v2->co, area);
- madd_v3_v3fl(r_center, v3->co, area);
- totweight += area;
- }
- if (totweight == 0.0f)
- return false;
+ area = area_tri_v3(v1->co, v2->co, v3->co);
+ madd_v3_v3fl(r_center, v1->co, area);
+ madd_v3_v3fl(r_center, v2->co, area);
+ madd_v3_v3fl(r_center, v3->co, area);
+ totweight += area;
+ }
+ if (totweight == 0.0f)
+ return false;
- mul_v3_fl(r_center, 1.0f / (3.0f * totweight));
+ mul_v3_fl(r_center, 1.0f / (3.0f * totweight));
- return true;
+ return true;
}
/**
@@ -2418,62 +2620,64 @@ static bool mesh_calc_center_centroid_ex(
* \param r_volume: Volume (unsigned).
* \param r_center: Center of mass.
*/
-void BKE_mesh_calc_volume(
- const MVert *mverts, const int mverts_num,
- const MLoopTri *looptri, const int looptri_num,
- const MLoop *mloop,
- float *r_volume, float r_center[3])
-{
- const MLoopTri *lt;
- float center[3];
- float totvol;
- int i;
-
- if (r_volume)
- *r_volume = 0.0f;
- if (r_center)
- zero_v3(r_center);
-
- if (looptri_num == 0)
- return;
-
- if (!mesh_calc_center_centroid_ex(mverts, mverts_num, looptri, looptri_num, mloop, center))
- return;
-
- totvol = 0.0f;
-
- for (i = 0, lt = looptri; i < looptri_num; i++, lt++) {
- const MVert *v1 = &mverts[mloop[lt->tri[0]].v];
- const MVert *v2 = &mverts[mloop[lt->tri[1]].v];
- const MVert *v3 = &mverts[mloop[lt->tri[2]].v];
- float vol;
-
- vol = volume_tetrahedron_signed_v3(center, v1->co, v2->co, v3->co);
- if (r_volume) {
- totvol += vol;
- }
- if (r_center) {
- /* averaging factor 1/3 is applied in the end */
- madd_v3_v3fl(r_center, v1->co, vol);
- madd_v3_v3fl(r_center, v2->co, vol);
- madd_v3_v3fl(r_center, v3->co, vol);
- }
- }
-
- /* Note: Depending on arbitrary centroid position,
- * totvol can become negative even for a valid mesh.
- * The true value is always the positive value.
- */
- if (r_volume) {
- *r_volume = fabsf(totvol);
- }
- if (r_center) {
- /* Note: Factor 1/3 is applied once for all vertices here.
- * This also automatically negates the vector if totvol is negative.
- */
- if (totvol != 0.0f)
- mul_v3_fl(r_center, (1.0f / 3.0f) / totvol);
- }
+void BKE_mesh_calc_volume(const MVert *mverts,
+ const int mverts_num,
+ const MLoopTri *looptri,
+ const int looptri_num,
+ const MLoop *mloop,
+ float *r_volume,
+ float r_center[3])
+{
+ const MLoopTri *lt;
+ float center[3];
+ float totvol;
+ int i;
+
+ if (r_volume)
+ *r_volume = 0.0f;
+ if (r_center)
+ zero_v3(r_center);
+
+ if (looptri_num == 0)
+ return;
+
+ if (!mesh_calc_center_centroid_ex(mverts, mverts_num, looptri, looptri_num, mloop, center))
+ return;
+
+ totvol = 0.0f;
+
+ for (i = 0, lt = looptri; i < looptri_num; i++, lt++) {
+ const MVert *v1 = &mverts[mloop[lt->tri[0]].v];
+ const MVert *v2 = &mverts[mloop[lt->tri[1]].v];
+ const MVert *v3 = &mverts[mloop[lt->tri[2]].v];
+ float vol;
+
+ vol = volume_tetrahedron_signed_v3(center, v1->co, v2->co, v3->co);
+ if (r_volume) {
+ totvol += vol;
+ }
+ if (r_center) {
+ /* averaging factor 1/3 is applied in the end */
+ madd_v3_v3fl(r_center, v1->co, vol);
+ madd_v3_v3fl(r_center, v2->co, vol);
+ madd_v3_v3fl(r_center, v3->co, vol);
+ }
+ }
+
+ /* Note: Depending on arbitrary centroid position,
+ * totvol can become negative even for a valid mesh.
+ * The true value is always the positive value.
+ */
+ if (r_volume) {
+ *r_volume = fabsf(totvol);
+ }
+ if (r_center) {
+ /* Note: Factor 1/3 is applied once for all vertices here.
+ * This also automatically negates the vector if totvol is negative.
+ */
+ if (totvol != 0.0f)
+ mul_v3_fl(r_center, (1.0f / 3.0f) / totvol);
+ }
}
/** \} */
@@ -2486,69 +2690,72 @@ void BKE_mesh_calc_volume(
* Convert a triangle or quadrangle of loop/poly data to tessface data
*/
void BKE_mesh_loops_to_mface_corners(
- CustomData *fdata, CustomData *ldata,
- CustomData *UNUSED(pdata), unsigned int lindex[4], int findex,
- const int UNUSED(polyindex),
- const int mf_len, /* 3 or 4 */
-
- /* cache values to avoid lookups every time */
- const int numUV, /* CustomData_number_of_layers(ldata, CD_MLOOPUV) */
- const int numCol, /* CustomData_number_of_layers(ldata, CD_MLOOPCOL) */
- const bool hasPCol, /* CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL) */
- const bool hasOrigSpace, /* CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP) */
- const bool hasLNor /* CustomData_has_layer(ldata, CD_NORMAL) */
+ CustomData *fdata,
+ CustomData *ldata,
+ CustomData *UNUSED(pdata),
+ unsigned int lindex[4],
+ int findex,
+ const int UNUSED(polyindex),
+ const int mf_len, /* 3 or 4 */
+
+ /* cache values to avoid lookups every time */
+ const int numUV, /* CustomData_number_of_layers(ldata, CD_MLOOPUV) */
+ const int numCol, /* CustomData_number_of_layers(ldata, CD_MLOOPCOL) */
+ const bool hasPCol, /* CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL) */
+ const bool hasOrigSpace, /* CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP) */
+ const bool hasLNor /* CustomData_has_layer(ldata, CD_NORMAL) */
)
{
- MTFace *texface;
- MCol *mcol;
- MLoopCol *mloopcol;
- MLoopUV *mloopuv;
- int i, j;
+ MTFace *texface;
+ MCol *mcol;
+ MLoopCol *mloopcol;
+ MLoopUV *mloopuv;
+ int i, j;
- for (i = 0; i < numUV; i++) {
- texface = CustomData_get_n(fdata, CD_MTFACE, findex, i);
+ for (i = 0; i < numUV; i++) {
+ texface = CustomData_get_n(fdata, CD_MTFACE, findex, i);
- for (j = 0; j < mf_len; j++) {
- mloopuv = CustomData_get_n(ldata, CD_MLOOPUV, (int)lindex[j], i);
- copy_v2_v2(texface->uv[j], mloopuv->uv);
- }
- }
+ for (j = 0; j < mf_len; j++) {
+ mloopuv = CustomData_get_n(ldata, CD_MLOOPUV, (int)lindex[j], i);
+ copy_v2_v2(texface->uv[j], mloopuv->uv);
+ }
+ }
- for (i = 0; i < numCol; i++) {
- mcol = CustomData_get_n(fdata, CD_MCOL, findex, i);
+ for (i = 0; i < numCol; i++) {
+ mcol = CustomData_get_n(fdata, CD_MCOL, findex, i);
- for (j = 0; j < mf_len; j++) {
- mloopcol = CustomData_get_n(ldata, CD_MLOOPCOL, (int)lindex[j], i);
- MESH_MLOOPCOL_TO_MCOL(mloopcol, &mcol[j]);
- }
- }
+ for (j = 0; j < mf_len; j++) {
+ mloopcol = CustomData_get_n(ldata, CD_MLOOPCOL, (int)lindex[j], i);
+ MESH_MLOOPCOL_TO_MCOL(mloopcol, &mcol[j]);
+ }
+ }
- if (hasPCol) {
- mcol = CustomData_get(fdata, findex, CD_PREVIEW_MCOL);
+ if (hasPCol) {
+ mcol = CustomData_get(fdata, findex, CD_PREVIEW_MCOL);
- for (j = 0; j < mf_len; j++) {
- mloopcol = CustomData_get(ldata, (int)lindex[j], CD_PREVIEW_MLOOPCOL);
- MESH_MLOOPCOL_TO_MCOL(mloopcol, &mcol[j]);
- }
- }
+ for (j = 0; j < mf_len; j++) {
+ mloopcol = CustomData_get(ldata, (int)lindex[j], CD_PREVIEW_MLOOPCOL);
+ MESH_MLOOPCOL_TO_MCOL(mloopcol, &mcol[j]);
+ }
+ }
- if (hasOrigSpace) {
- OrigSpaceFace *of = CustomData_get(fdata, findex, CD_ORIGSPACE);
- OrigSpaceLoop *lof;
+ if (hasOrigSpace) {
+ OrigSpaceFace *of = CustomData_get(fdata, findex, CD_ORIGSPACE);
+ OrigSpaceLoop *lof;
- for (j = 0; j < mf_len; j++) {
- lof = CustomData_get(ldata, (int)lindex[j], CD_ORIGSPACE_MLOOP);
- copy_v2_v2(of->uv[j], lof->uv);
- }
- }
+ for (j = 0; j < mf_len; j++) {
+ lof = CustomData_get(ldata, (int)lindex[j], CD_ORIGSPACE_MLOOP);
+ copy_v2_v2(of->uv[j], lof->uv);
+ }
+ }
- if (hasLNor) {
- short (*tlnors)[3] = CustomData_get(fdata, findex, CD_TESSLOOPNORMAL);
+ if (hasLNor) {
+ short(*tlnors)[3] = CustomData_get(fdata, findex, CD_TESSLOOPNORMAL);
- for (j = 0; j < mf_len; j++) {
- normal_float_to_short_v3(tlnors[j], CustomData_get(ldata, (int)lindex[j], CD_NORMAL));
- }
- }
+ for (j = 0; j < mf_len; j++) {
+ normal_float_to_short_v3(tlnors[j], CustomData_get(ldata, (int)lindex[j], CD_NORMAL));
+ }
+ }
}
/**
@@ -2558,138 +2765,139 @@ void BKE_mesh_loops_to_mface_corners(
*
* \note when mface is not NULL, mface[face_index].v4 is used to test quads, else, loopindices[face_index][3] is used.
*/
-void BKE_mesh_loops_to_tessdata(
- CustomData *fdata, CustomData *ldata, MFace *mface,
- int *polyindices, unsigned int (*loopindices)[4], const int num_faces)
-{
- /* Note: performances are sub-optimal when we get a NULL mface, we could be ~25% quicker with dedicated code...
- * Issue is, unless having two different functions with nearly the same code, there's not much ways to solve
- * this. Better imho to live with it for now. :/ --mont29
- */
- const int numUV = CustomData_number_of_layers(ldata, CD_MLOOPUV);
- const int numCol = CustomData_number_of_layers(ldata, CD_MLOOPCOL);
- const bool hasPCol = CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL);
- const bool hasOrigSpace = CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP);
- const bool hasLoopNormal = CustomData_has_layer(ldata, CD_NORMAL);
- const bool hasLoopTangent = CustomData_has_layer(ldata, CD_TANGENT);
- int findex, i, j;
- const int *pidx;
- unsigned int (*lidx)[4];
-
- for (i = 0; i < numUV; i++) {
- MTFace *texface = CustomData_get_layer_n(fdata, CD_MTFACE, i);
- MLoopUV *mloopuv = CustomData_get_layer_n(ldata, CD_MLOOPUV, i);
-
- for (findex = 0, pidx = polyindices, lidx = loopindices;
- findex < num_faces;
- pidx++, lidx++, findex++, texface++)
- {
- for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
- copy_v2_v2(texface->uv[j], mloopuv[(*lidx)[j]].uv);
- }
- }
- }
-
- for (i = 0; i < numCol; i++) {
- MCol (*mcol)[4] = CustomData_get_layer_n(fdata, CD_MCOL, i);
- MLoopCol *mloopcol = CustomData_get_layer_n(ldata, CD_MLOOPCOL, i);
-
- for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, mcol++) {
- for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
- MESH_MLOOPCOL_TO_MCOL(&mloopcol[(*lidx)[j]], &(*mcol)[j]);
- }
- }
- }
-
- if (hasPCol) {
- MCol (*mcol)[4] = CustomData_get_layer(fdata, CD_PREVIEW_MCOL);
- MLoopCol *mloopcol = CustomData_get_layer(ldata, CD_PREVIEW_MLOOPCOL);
-
- for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, mcol++) {
- for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
- MESH_MLOOPCOL_TO_MCOL(&mloopcol[(*lidx)[j]], &(*mcol)[j]);
- }
- }
- }
-
- if (hasOrigSpace) {
- OrigSpaceFace *of = CustomData_get_layer(fdata, CD_ORIGSPACE);
- OrigSpaceLoop *lof = CustomData_get_layer(ldata, CD_ORIGSPACE_MLOOP);
-
- for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, of++) {
- for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
- copy_v2_v2(of->uv[j], lof[(*lidx)[j]].uv);
- }
- }
- }
-
- if (hasLoopNormal) {
- short (*fnors)[4][3] = CustomData_get_layer(fdata, CD_TESSLOOPNORMAL);
- float (*lnors)[3] = CustomData_get_layer(ldata, CD_NORMAL);
-
- for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, fnors++) {
- for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
- normal_float_to_short_v3((*fnors)[j], lnors[(*lidx)[j]]);
- }
- }
- }
-
- if (hasLoopTangent) {
- /* need to do for all uv maps at some point */
- float (*ftangents)[4] = CustomData_get_layer(fdata, CD_TANGENT);
- float (*ltangents)[4] = CustomData_get_layer(ldata, CD_TANGENT);
-
- for (findex = 0, pidx = polyindices, lidx = loopindices;
- findex < num_faces;
- pidx++, lidx++, findex++)
- {
- int nverts = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3;
- for (j = nverts; j--;) {
- copy_v4_v4(ftangents[findex * 4 + j], ltangents[(*lidx)[j]]);
- }
- }
- }
-}
-
-void BKE_mesh_tangent_loops_to_tessdata(
- CustomData *fdata, CustomData *ldata, MFace *mface,
- int *polyindices, unsigned int (*loopindices)[4], const int num_faces, const char *layer_name)
-{
- /* Note: performances are sub-optimal when we get a NULL mface, we could be ~25% quicker with dedicated code...
- * Issue is, unless having two different functions with nearly the same code, there's not much ways to solve
- * this. Better imho to live with it for now. :/ --mont29
- */
-
- float (*ftangents)[4] = NULL;
- float (*ltangents)[4] = NULL;
-
- int findex, j;
- const int *pidx;
- unsigned int (*lidx)[4];
-
- if (layer_name)
- ltangents = CustomData_get_layer_named(ldata, CD_TANGENT, layer_name);
- else
- ltangents = CustomData_get_layer(ldata, CD_TANGENT);
-
- if (ltangents) {
- /* need to do for all uv maps at some point */
- if (layer_name)
- ftangents = CustomData_get_layer_named(fdata, CD_TANGENT, layer_name);
- else
- ftangents = CustomData_get_layer(fdata, CD_TANGENT);
- if (ftangents) {
- for (findex = 0, pidx = polyindices, lidx = loopindices;
- findex < num_faces;
- pidx++, lidx++, findex++)
- {
- int nverts = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3;
- for (j = nverts; j--;) {
- copy_v4_v4(ftangents[findex * 4 + j], ltangents[(*lidx)[j]]);
- }
- }
- }
- }
+void BKE_mesh_loops_to_tessdata(CustomData *fdata,
+ CustomData *ldata,
+ MFace *mface,
+ int *polyindices,
+ unsigned int (*loopindices)[4],
+ const int num_faces)
+{
+ /* Note: performances are sub-optimal when we get a NULL mface, we could be ~25% quicker with dedicated code...
+ * Issue is, unless having two different functions with nearly the same code, there's not much ways to solve
+ * this. Better imho to live with it for now. :/ --mont29
+ */
+ const int numUV = CustomData_number_of_layers(ldata, CD_MLOOPUV);
+ const int numCol = CustomData_number_of_layers(ldata, CD_MLOOPCOL);
+ const bool hasPCol = CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL);
+ const bool hasOrigSpace = CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP);
+ const bool hasLoopNormal = CustomData_has_layer(ldata, CD_NORMAL);
+ const bool hasLoopTangent = CustomData_has_layer(ldata, CD_TANGENT);
+ int findex, i, j;
+ const int *pidx;
+ unsigned int(*lidx)[4];
+
+ for (i = 0; i < numUV; i++) {
+ MTFace *texface = CustomData_get_layer_n(fdata, CD_MTFACE, i);
+ MLoopUV *mloopuv = CustomData_get_layer_n(ldata, CD_MLOOPUV, i);
+
+ for (findex = 0, pidx = polyindices, lidx = loopindices; findex < num_faces;
+ pidx++, lidx++, findex++, texface++) {
+ for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
+ copy_v2_v2(texface->uv[j], mloopuv[(*lidx)[j]].uv);
+ }
+ }
+ }
+
+ for (i = 0; i < numCol; i++) {
+ MCol(*mcol)[4] = CustomData_get_layer_n(fdata, CD_MCOL, i);
+ MLoopCol *mloopcol = CustomData_get_layer_n(ldata, CD_MLOOPCOL, i);
+
+ for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, mcol++) {
+ for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
+ MESH_MLOOPCOL_TO_MCOL(&mloopcol[(*lidx)[j]], &(*mcol)[j]);
+ }
+ }
+ }
+
+ if (hasPCol) {
+ MCol(*mcol)[4] = CustomData_get_layer(fdata, CD_PREVIEW_MCOL);
+ MLoopCol *mloopcol = CustomData_get_layer(ldata, CD_PREVIEW_MLOOPCOL);
+
+ for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, mcol++) {
+ for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
+ MESH_MLOOPCOL_TO_MCOL(&mloopcol[(*lidx)[j]], &(*mcol)[j]);
+ }
+ }
+ }
+
+ if (hasOrigSpace) {
+ OrigSpaceFace *of = CustomData_get_layer(fdata, CD_ORIGSPACE);
+ OrigSpaceLoop *lof = CustomData_get_layer(ldata, CD_ORIGSPACE_MLOOP);
+
+ for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, of++) {
+ for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
+ copy_v2_v2(of->uv[j], lof[(*lidx)[j]].uv);
+ }
+ }
+ }
+
+ if (hasLoopNormal) {
+ short(*fnors)[4][3] = CustomData_get_layer(fdata, CD_TESSLOOPNORMAL);
+ float(*lnors)[3] = CustomData_get_layer(ldata, CD_NORMAL);
+
+ for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, fnors++) {
+ for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
+ normal_float_to_short_v3((*fnors)[j], lnors[(*lidx)[j]]);
+ }
+ }
+ }
+
+ if (hasLoopTangent) {
+ /* need to do for all uv maps at some point */
+ float(*ftangents)[4] = CustomData_get_layer(fdata, CD_TANGENT);
+ float(*ltangents)[4] = CustomData_get_layer(ldata, CD_TANGENT);
+
+ for (findex = 0, pidx = polyindices, lidx = loopindices; findex < num_faces;
+ pidx++, lidx++, findex++) {
+ int nverts = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3;
+ for (j = nverts; j--;) {
+ copy_v4_v4(ftangents[findex * 4 + j], ltangents[(*lidx)[j]]);
+ }
+ }
+ }
+}
+
+void BKE_mesh_tangent_loops_to_tessdata(CustomData *fdata,
+ CustomData *ldata,
+ MFace *mface,
+ int *polyindices,
+ unsigned int (*loopindices)[4],
+ const int num_faces,
+ const char *layer_name)
+{
+ /* Note: performances are sub-optimal when we get a NULL mface, we could be ~25% quicker with dedicated code...
+ * Issue is, unless having two different functions with nearly the same code, there's not much ways to solve
+ * this. Better imho to live with it for now. :/ --mont29
+ */
+
+ float(*ftangents)[4] = NULL;
+ float(*ltangents)[4] = NULL;
+
+ int findex, j;
+ const int *pidx;
+ unsigned int(*lidx)[4];
+
+ if (layer_name)
+ ltangents = CustomData_get_layer_named(ldata, CD_TANGENT, layer_name);
+ else
+ ltangents = CustomData_get_layer(ldata, CD_TANGENT);
+
+ if (ltangents) {
+ /* need to do for all uv maps at some point */
+ if (layer_name)
+ ftangents = CustomData_get_layer_named(fdata, CD_TANGENT, layer_name);
+ else
+ ftangents = CustomData_get_layer(fdata, CD_TANGENT);
+ if (ftangents) {
+ for (findex = 0, pidx = polyindices, lidx = loopindices; findex < num_faces;
+ pidx++, lidx++, findex++) {
+ int nverts = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3;
+ for (j = nverts; j--;) {
+ copy_v4_v4(ftangents[findex * 4 + j], ltangents[(*lidx)[j]]);
+ }
+ }
+ }
+ }
}
/**
@@ -2699,507 +2907,530 @@ void BKE_mesh_tangent_loops_to_tessdata(
*
* \return number of tessellation faces.
*/
-int BKE_mesh_recalc_tessellation(
- CustomData *fdata, CustomData *ldata, CustomData *pdata,
- MVert *mvert,
- int totface, int totloop, int totpoly,
- const bool do_face_nor_copy)
-{
- /* use this to avoid locking pthread for _every_ polygon
- * and calling the fill function */
+int BKE_mesh_recalc_tessellation(CustomData *fdata,
+ CustomData *ldata,
+ CustomData *pdata,
+ MVert *mvert,
+ int totface,
+ int totloop,
+ int totpoly,
+ const bool do_face_nor_copy)
+{
+ /* use this to avoid locking pthread for _every_ polygon
+ * and calling the fill function */
#define USE_TESSFACE_SPEEDUP
-#define USE_TESSFACE_QUADS /* NEEDS FURTHER TESTING */
+#define USE_TESSFACE_QUADS /* NEEDS FURTHER TESTING */
/* We abuse MFace->edcode to tag quad faces. See below for details. */
#define TESSFACE_IS_QUAD 1
- const int looptri_num = poly_to_tri_count(totpoly, totloop);
-
- MPoly *mp, *mpoly;
- MLoop *ml, *mloop;
- MFace *mface, *mf;
- MemArena *arena = NULL;
- int *mface_to_poly_map;
- unsigned int (*lindices)[4];
- int poly_index, mface_index;
- unsigned int j;
-
- mpoly = CustomData_get_layer(pdata, CD_MPOLY);
- mloop = CustomData_get_layer(ldata, CD_MLOOP);
-
- /* allocate the length of totfaces, avoid many small reallocs,
- * if all faces are tri's it will be correct, quads == 2x allocs */
- /* take care. we are _not_ calloc'ing so be sure to initialize each field */
- mface_to_poly_map = MEM_malloc_arrayN((size_t)looptri_num, sizeof(*mface_to_poly_map), __func__);
- mface = MEM_malloc_arrayN((size_t)looptri_num, sizeof(*mface), __func__);
- lindices = MEM_malloc_arrayN((size_t)looptri_num, sizeof(*lindices), __func__);
-
- mface_index = 0;
- mp = mpoly;
- for (poly_index = 0; poly_index < totpoly; poly_index++, mp++) {
- const unsigned int mp_loopstart = (unsigned int)mp->loopstart;
- const unsigned int mp_totloop = (unsigned int)mp->totloop;
- unsigned int l1, l2, l3, l4;
- unsigned int *lidx;
- if (mp_totloop < 3) {
- /* do nothing */
- }
+ const int looptri_num = poly_to_tri_count(totpoly, totloop);
+
+ MPoly *mp, *mpoly;
+ MLoop *ml, *mloop;
+ MFace *mface, *mf;
+ MemArena *arena = NULL;
+ int *mface_to_poly_map;
+ unsigned int(*lindices)[4];
+ int poly_index, mface_index;
+ unsigned int j;
+
+ mpoly = CustomData_get_layer(pdata, CD_MPOLY);
+ mloop = CustomData_get_layer(ldata, CD_MLOOP);
+
+ /* allocate the length of totfaces, avoid many small reallocs,
+ * if all faces are tri's it will be correct, quads == 2x allocs */
+ /* take care. we are _not_ calloc'ing so be sure to initialize each field */
+ mface_to_poly_map = MEM_malloc_arrayN((size_t)looptri_num, sizeof(*mface_to_poly_map), __func__);
+ mface = MEM_malloc_arrayN((size_t)looptri_num, sizeof(*mface), __func__);
+ lindices = MEM_malloc_arrayN((size_t)looptri_num, sizeof(*lindices), __func__);
+
+ mface_index = 0;
+ mp = mpoly;
+ for (poly_index = 0; poly_index < totpoly; poly_index++, mp++) {
+ const unsigned int mp_loopstart = (unsigned int)mp->loopstart;
+ const unsigned int mp_totloop = (unsigned int)mp->totloop;
+ unsigned int l1, l2, l3, l4;
+ unsigned int *lidx;
+ if (mp_totloop < 3) {
+ /* do nothing */
+ }
#ifdef USE_TESSFACE_SPEEDUP
-#define ML_TO_MF(i1, i2, i3) \
- mface_to_poly_map[mface_index] = poly_index; \
- mf = &mface[mface_index]; \
- lidx = lindices[mface_index]; \
- /* set loop indices, transformed to vert indices later */ \
- l1 = mp_loopstart + i1; \
- l2 = mp_loopstart + i2; \
- l3 = mp_loopstart + i3; \
- mf->v1 = mloop[l1].v; \
- mf->v2 = mloop[l2].v; \
- mf->v3 = mloop[l3].v; \
- mf->v4 = 0; \
- lidx[0] = l1; \
- lidx[1] = l2; \
- lidx[2] = l3; \
- lidx[3] = 0; \
- mf->mat_nr = mp->mat_nr; \
- mf->flag = mp->flag; \
- mf->edcode = 0; \
- (void)0
+# define ML_TO_MF(i1, i2, i3) \
+ mface_to_poly_map[mface_index] = poly_index; \
+ mf = &mface[mface_index]; \
+ lidx = lindices[mface_index]; \
+ /* set loop indices, transformed to vert indices later */ \
+ l1 = mp_loopstart + i1; \
+ l2 = mp_loopstart + i2; \
+ l3 = mp_loopstart + i3; \
+ mf->v1 = mloop[l1].v; \
+ mf->v2 = mloop[l2].v; \
+ mf->v3 = mloop[l3].v; \
+ mf->v4 = 0; \
+ lidx[0] = l1; \
+ lidx[1] = l2; \
+ lidx[2] = l3; \
+ lidx[3] = 0; \
+ mf->mat_nr = mp->mat_nr; \
+ mf->flag = mp->flag; \
+ mf->edcode = 0; \
+ (void)0
/* ALMOST IDENTICAL TO DEFINE ABOVE (see EXCEPTION) */
-#define ML_TO_MF_QUAD() \
- mface_to_poly_map[mface_index] = poly_index; \
- mf = &mface[mface_index]; \
- lidx = lindices[mface_index]; \
- /* set loop indices, transformed to vert indices later */ \
- l1 = mp_loopstart + 0; /* EXCEPTION */ \
- l2 = mp_loopstart + 1; /* EXCEPTION */ \
- l3 = mp_loopstart + 2; /* EXCEPTION */ \
- l4 = mp_loopstart + 3; /* EXCEPTION */ \
- mf->v1 = mloop[l1].v; \
- mf->v2 = mloop[l2].v; \
- mf->v3 = mloop[l3].v; \
- mf->v4 = mloop[l4].v; \
- lidx[0] = l1; \
- lidx[1] = l2; \
- lidx[2] = l3; \
- lidx[3] = l4; \
- mf->mat_nr = mp->mat_nr; \
- mf->flag = mp->flag; \
- mf->edcode = TESSFACE_IS_QUAD; \
- (void)0
-
-
- else if (mp_totloop == 3) {
- ML_TO_MF(0, 1, 2);
- mface_index++;
- }
- else if (mp_totloop == 4) {
-#ifdef USE_TESSFACE_QUADS
- ML_TO_MF_QUAD();
- mface_index++;
-#else
- ML_TO_MF(0, 1, 2);
- mface_index++;
- ML_TO_MF(0, 2, 3);
- mface_index++;
-#endif
- }
+# define ML_TO_MF_QUAD() \
+ mface_to_poly_map[mface_index] = poly_index; \
+ mf = &mface[mface_index]; \
+ lidx = lindices[mface_index]; \
+ /* set loop indices, transformed to vert indices later */ \
+ l1 = mp_loopstart + 0; /* EXCEPTION */ \
+ l2 = mp_loopstart + 1; /* EXCEPTION */ \
+ l3 = mp_loopstart + 2; /* EXCEPTION */ \
+ l4 = mp_loopstart + 3; /* EXCEPTION */ \
+ mf->v1 = mloop[l1].v; \
+ mf->v2 = mloop[l2].v; \
+ mf->v3 = mloop[l3].v; \
+ mf->v4 = mloop[l4].v; \
+ lidx[0] = l1; \
+ lidx[1] = l2; \
+ lidx[2] = l3; \
+ lidx[3] = l4; \
+ mf->mat_nr = mp->mat_nr; \
+ mf->flag = mp->flag; \
+ mf->edcode = TESSFACE_IS_QUAD; \
+ (void)0
+
+ else if (mp_totloop == 3) {
+ ML_TO_MF(0, 1, 2);
+ mface_index++;
+ }
+ else if (mp_totloop == 4) {
+# ifdef USE_TESSFACE_QUADS
+ ML_TO_MF_QUAD();
+ mface_index++;
+# else
+ ML_TO_MF(0, 1, 2);
+ mface_index++;
+ ML_TO_MF(0, 2, 3);
+ mface_index++;
+# endif
+ }
#endif /* USE_TESSFACE_SPEEDUP */
- else {
- const float *co_curr, *co_prev;
+ else {
+ const float *co_curr, *co_prev;
- float normal[3];
-
- float axis_mat[3][3];
- float (*projverts)[2];
- unsigned int (*tris)[3];
-
- const unsigned int totfilltri = mp_totloop - 2;
-
- if (UNLIKELY(arena == NULL)) {
- arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
- }
-
- tris = BLI_memarena_alloc(arena, sizeof(*tris) * (size_t)totfilltri);
- projverts = BLI_memarena_alloc(arena, sizeof(*projverts) * (size_t)mp_totloop);
-
- zero_v3(normal);
-
- /* calc normal, flipped: to get a positive 2d cross product */
- ml = mloop + mp_loopstart;
- co_prev = mvert[ml[mp_totloop - 1].v].co;
- for (j = 0; j < mp_totloop; j++, ml++) {
- co_curr = mvert[ml->v].co;
- add_newell_cross_v3_v3v3(normal, co_prev, co_curr);
- co_prev = co_curr;
- }
- if (UNLIKELY(normalize_v3(normal) == 0.0f)) {
- normal[2] = 1.0f;
- }
-
- /* project verts to 2d */
- axis_dominant_v3_to_m3_negate(axis_mat, normal);
-
- ml = mloop + mp_loopstart;
- for (j = 0; j < mp_totloop; j++, ml++) {
- mul_v2_m3v3(projverts[j], axis_mat, mvert[ml->v].co);
- }
-
- BLI_polyfill_calc_arena(projverts, mp_totloop, 1, tris, arena);
-
- /* apply fill */
- for (j = 0; j < totfilltri; j++) {
- unsigned int *tri = tris[j];
- lidx = lindices[mface_index];
-
- mface_to_poly_map[mface_index] = poly_index;
- mf = &mface[mface_index];
-
- /* set loop indices, transformed to vert indices later */
- l1 = mp_loopstart + tri[0];
- l2 = mp_loopstart + tri[1];
- l3 = mp_loopstart + tri[2];
-
- mf->v1 = mloop[l1].v;
- mf->v2 = mloop[l2].v;
- mf->v3 = mloop[l3].v;
- mf->v4 = 0;
-
- lidx[0] = l1;
- lidx[1] = l2;
- lidx[2] = l3;
- lidx[3] = 0;
-
- mf->mat_nr = mp->mat_nr;
- mf->flag = mp->flag;
- mf->edcode = 0;
-
- mface_index++;
- }
-
- BLI_memarena_clear(arena);
- }
- }
-
- if (arena) {
- BLI_memarena_free(arena);
- arena = NULL;
- }
-
- CustomData_free(fdata, totface);
- totface = mface_index;
-
- BLI_assert(totface <= looptri_num);
-
- /* not essential but without this we store over-alloc'd memory in the CustomData layers */
- if (LIKELY(looptri_num != totface)) {
- mface = MEM_reallocN(mface, sizeof(*mface) * (size_t)totface);
- mface_to_poly_map = MEM_reallocN(mface_to_poly_map, sizeof(*mface_to_poly_map) * (size_t)totface);
- }
-
- CustomData_add_layer(fdata, CD_MFACE, CD_ASSIGN, mface, totface);
-
- /* CD_ORIGINDEX will contain an array of indices from tessfaces to the polygons
- * they are directly tessellated from */
- CustomData_add_layer(fdata, CD_ORIGINDEX, CD_ASSIGN, mface_to_poly_map, totface);
- CustomData_from_bmeshpoly(fdata, ldata, totface);
-
- if (do_face_nor_copy) {
- /* If polys have a normals layer, copying that to faces can help
- * avoid the need to recalculate normals later */
- if (CustomData_has_layer(pdata, CD_NORMAL)) {
- float (*pnors)[3] = CustomData_get_layer(pdata, CD_NORMAL);
- float (*fnors)[3] = CustomData_add_layer(fdata, CD_NORMAL, CD_CALLOC, NULL, totface);
- for (mface_index = 0; mface_index < totface; mface_index++) {
- copy_v3_v3(fnors[mface_index], pnors[mface_to_poly_map[mface_index]]);
- }
- }
- }
-
- /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx:
- * Polygons take care of their loops ordering, hence not of their vertices ordering.
- * Currently, our tfaces' fourth vertex index might be 0 even for a quad. However, we know our fourth loop index is
- * never 0 for quads (because they are sorted for polygons, and our quads are still mere copies of their polygons).
- * So we pass NULL as MFace pointer, and BKE_mesh_loops_to_tessdata will use the fourth loop index as quad test.
- * ...
- */
- BKE_mesh_loops_to_tessdata(fdata, ldata, NULL, mface_to_poly_map, lindices, totface);
-
- /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx:
- * ...However, most TFace code uses 'MFace->v4 == 0' test to check whether it is a tri or quad.
- * test_index_face() will check this and rotate the tessellated face if needed.
- */
+ float normal[3];
+
+ float axis_mat[3][3];
+ float(*projverts)[2];
+ unsigned int(*tris)[3];
+
+ const unsigned int totfilltri = mp_totloop - 2;
+
+ if (UNLIKELY(arena == NULL)) {
+ arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+ }
+
+ tris = BLI_memarena_alloc(arena, sizeof(*tris) * (size_t)totfilltri);
+ projverts = BLI_memarena_alloc(arena, sizeof(*projverts) * (size_t)mp_totloop);
+
+ zero_v3(normal);
+
+ /* calc normal, flipped: to get a positive 2d cross product */
+ ml = mloop + mp_loopstart;
+ co_prev = mvert[ml[mp_totloop - 1].v].co;
+ for (j = 0; j < mp_totloop; j++, ml++) {
+ co_curr = mvert[ml->v].co;
+ add_newell_cross_v3_v3v3(normal, co_prev, co_curr);
+ co_prev = co_curr;
+ }
+ if (UNLIKELY(normalize_v3(normal) == 0.0f)) {
+ normal[2] = 1.0f;
+ }
+
+ /* project verts to 2d */
+ axis_dominant_v3_to_m3_negate(axis_mat, normal);
+
+ ml = mloop + mp_loopstart;
+ for (j = 0; j < mp_totloop; j++, ml++) {
+ mul_v2_m3v3(projverts[j], axis_mat, mvert[ml->v].co);
+ }
+
+ BLI_polyfill_calc_arena(projverts, mp_totloop, 1, tris, arena);
+
+ /* apply fill */
+ for (j = 0; j < totfilltri; j++) {
+ unsigned int *tri = tris[j];
+ lidx = lindices[mface_index];
+
+ mface_to_poly_map[mface_index] = poly_index;
+ mf = &mface[mface_index];
+
+ /* set loop indices, transformed to vert indices later */
+ l1 = mp_loopstart + tri[0];
+ l2 = mp_loopstart + tri[1];
+ l3 = mp_loopstart + tri[2];
+
+ mf->v1 = mloop[l1].v;
+ mf->v2 = mloop[l2].v;
+ mf->v3 = mloop[l3].v;
+ mf->v4 = 0;
+
+ lidx[0] = l1;
+ lidx[1] = l2;
+ lidx[2] = l3;
+ lidx[3] = 0;
+
+ mf->mat_nr = mp->mat_nr;
+ mf->flag = mp->flag;
+ mf->edcode = 0;
+
+ mface_index++;
+ }
+
+ BLI_memarena_clear(arena);
+ }
+ }
+
+ if (arena) {
+ BLI_memarena_free(arena);
+ arena = NULL;
+ }
+
+ CustomData_free(fdata, totface);
+ totface = mface_index;
+
+ BLI_assert(totface <= looptri_num);
+
+ /* not essential but without this we store over-alloc'd memory in the CustomData layers */
+ if (LIKELY(looptri_num != totface)) {
+ mface = MEM_reallocN(mface, sizeof(*mface) * (size_t)totface);
+ mface_to_poly_map = MEM_reallocN(mface_to_poly_map,
+ sizeof(*mface_to_poly_map) * (size_t)totface);
+ }
+
+ CustomData_add_layer(fdata, CD_MFACE, CD_ASSIGN, mface, totface);
+
+ /* CD_ORIGINDEX will contain an array of indices from tessfaces to the polygons
+ * they are directly tessellated from */
+ CustomData_add_layer(fdata, CD_ORIGINDEX, CD_ASSIGN, mface_to_poly_map, totface);
+ CustomData_from_bmeshpoly(fdata, ldata, totface);
+
+ if (do_face_nor_copy) {
+ /* If polys have a normals layer, copying that to faces can help
+ * avoid the need to recalculate normals later */
+ if (CustomData_has_layer(pdata, CD_NORMAL)) {
+ float(*pnors)[3] = CustomData_get_layer(pdata, CD_NORMAL);
+ float(*fnors)[3] = CustomData_add_layer(fdata, CD_NORMAL, CD_CALLOC, NULL, totface);
+ for (mface_index = 0; mface_index < totface; mface_index++) {
+ copy_v3_v3(fnors[mface_index], pnors[mface_to_poly_map[mface_index]]);
+ }
+ }
+ }
+
+ /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx:
+ * Polygons take care of their loops ordering, hence not of their vertices ordering.
+ * Currently, our tfaces' fourth vertex index might be 0 even for a quad. However, we know our fourth loop index is
+ * never 0 for quads (because they are sorted for polygons, and our quads are still mere copies of their polygons).
+ * So we pass NULL as MFace pointer, and BKE_mesh_loops_to_tessdata will use the fourth loop index as quad test.
+ * ...
+ */
+ BKE_mesh_loops_to_tessdata(fdata, ldata, NULL, mface_to_poly_map, lindices, totface);
+
+ /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx:
+ * ...However, most TFace code uses 'MFace->v4 == 0' test to check whether it is a tri or quad.
+ * test_index_face() will check this and rotate the tessellated face if needed.
+ */
#ifdef USE_TESSFACE_QUADS
- mf = mface;
- for (mface_index = 0; mface_index < totface; mface_index++, mf++) {
- if (mf->edcode == TESSFACE_IS_QUAD) {
- test_index_face(mf, fdata, mface_index, 4);
- mf->edcode = 0;
- }
- }
+ mf = mface;
+ for (mface_index = 0; mface_index < totface; mface_index++, mf++) {
+ if (mf->edcode == TESSFACE_IS_QUAD) {
+ test_index_face(mf, fdata, mface_index, 4);
+ mf->edcode = 0;
+ }
+ }
#endif
- MEM_freeN(lindices);
+ MEM_freeN(lindices);
- return totface;
+ return totface;
#undef USE_TESSFACE_SPEEDUP
#undef USE_TESSFACE_QUADS
#undef ML_TO_MF
#undef ML_TO_MF_QUAD
-
}
/**
* Calculate tessellation into #MLoopTri which exist only for this purpose.
*/
-void BKE_mesh_recalc_looptri(
- const MLoop *mloop, const MPoly *mpoly,
- const MVert *mvert,
- int totloop, int totpoly,
- MLoopTri *mlooptri)
+void BKE_mesh_recalc_looptri(const MLoop *mloop,
+ const MPoly *mpoly,
+ const MVert *mvert,
+ int totloop,
+ int totpoly,
+ MLoopTri *mlooptri)
{
- /* use this to avoid locking pthread for _every_ polygon
- * and calling the fill function */
+ /* use this to avoid locking pthread for _every_ polygon
+ * and calling the fill function */
#define USE_TESSFACE_SPEEDUP
- const MPoly *mp;
- const MLoop *ml;
- MLoopTri *mlt;
- MemArena *arena = NULL;
- int poly_index, mlooptri_index;
- unsigned int j;
-
- mlooptri_index = 0;
- mp = mpoly;
- for (poly_index = 0; poly_index < totpoly; poly_index++, mp++) {
- const unsigned int mp_loopstart = (unsigned int)mp->loopstart;
- const unsigned int mp_totloop = (unsigned int)mp->totloop;
- unsigned int l1, l2, l3;
- if (mp_totloop < 3) {
- /* do nothing */
- }
+ const MPoly *mp;
+ const MLoop *ml;
+ MLoopTri *mlt;
+ MemArena *arena = NULL;
+ int poly_index, mlooptri_index;
+ unsigned int j;
+
+ mlooptri_index = 0;
+ mp = mpoly;
+ for (poly_index = 0; poly_index < totpoly; poly_index++, mp++) {
+ const unsigned int mp_loopstart = (unsigned int)mp->loopstart;
+ const unsigned int mp_totloop = (unsigned int)mp->totloop;
+ unsigned int l1, l2, l3;
+ if (mp_totloop < 3) {
+ /* do nothing */
+ }
#ifdef USE_TESSFACE_SPEEDUP
-#define ML_TO_MLT(i1, i2, i3) { \
- mlt = &mlooptri[mlooptri_index]; \
- l1 = mp_loopstart + i1; \
- l2 = mp_loopstart + i2; \
- l3 = mp_loopstart + i3; \
- ARRAY_SET_ITEMS(mlt->tri, l1, l2, l3); \
- mlt->poly = (unsigned int)poly_index; \
- } ((void)0)
-
- else if (mp_totloop == 3) {
- ML_TO_MLT(0, 1, 2);
- mlooptri_index++;
- }
- else if (mp_totloop == 4) {
- ML_TO_MLT(0, 1, 2);
- MLoopTri *mlt_a = mlt;
- mlooptri_index++;
- ML_TO_MLT(0, 2, 3);
- MLoopTri *mlt_b = mlt;
- mlooptri_index++;
-
- if (UNLIKELY(is_quad_flip_v3_first_third_fast(
- mvert[mloop[mlt_a->tri[0]].v].co,
- mvert[mloop[mlt_a->tri[1]].v].co,
- mvert[mloop[mlt_a->tri[2]].v].co,
- mvert[mloop[mlt_b->tri[2]].v].co)))
- {
- /* flip out of degenerate 0-2 state. */
- mlt_a->tri[2] = mlt_b->tri[2];
- mlt_b->tri[0] = mlt_a->tri[1];
- }
- }
+# define ML_TO_MLT(i1, i2, i3) \
+ { \
+ mlt = &mlooptri[mlooptri_index]; \
+ l1 = mp_loopstart + i1; \
+ l2 = mp_loopstart + i2; \
+ l3 = mp_loopstart + i3; \
+ ARRAY_SET_ITEMS(mlt->tri, l1, l2, l3); \
+ mlt->poly = (unsigned int)poly_index; \
+ } \
+ ((void)0)
+
+ else if (mp_totloop == 3) {
+ ML_TO_MLT(0, 1, 2);
+ mlooptri_index++;
+ }
+ else if (mp_totloop == 4) {
+ ML_TO_MLT(0, 1, 2);
+ MLoopTri *mlt_a = mlt;
+ mlooptri_index++;
+ ML_TO_MLT(0, 2, 3);
+ MLoopTri *mlt_b = mlt;
+ mlooptri_index++;
+
+ if (UNLIKELY(is_quad_flip_v3_first_third_fast(mvert[mloop[mlt_a->tri[0]].v].co,
+ mvert[mloop[mlt_a->tri[1]].v].co,
+ mvert[mloop[mlt_a->tri[2]].v].co,
+ mvert[mloop[mlt_b->tri[2]].v].co))) {
+ /* flip out of degenerate 0-2 state. */
+ mlt_a->tri[2] = mlt_b->tri[2];
+ mlt_b->tri[0] = mlt_a->tri[1];
+ }
+ }
#endif /* USE_TESSFACE_SPEEDUP */
- else {
- const float *co_curr, *co_prev;
+ else {
+ const float *co_curr, *co_prev;
- float normal[3];
+ float normal[3];
- float axis_mat[3][3];
- float (*projverts)[2];
- unsigned int (*tris)[3];
+ float axis_mat[3][3];
+ float(*projverts)[2];
+ unsigned int(*tris)[3];
- const unsigned int totfilltri = mp_totloop - 2;
+ const unsigned int totfilltri = mp_totloop - 2;
- if (UNLIKELY(arena == NULL)) {
- arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
- }
+ if (UNLIKELY(arena == NULL)) {
+ arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+ }
- tris = BLI_memarena_alloc(arena, sizeof(*tris) * (size_t)totfilltri);
- projverts = BLI_memarena_alloc(arena, sizeof(*projverts) * (size_t)mp_totloop);
+ tris = BLI_memarena_alloc(arena, sizeof(*tris) * (size_t)totfilltri);
+ projverts = BLI_memarena_alloc(arena, sizeof(*projverts) * (size_t)mp_totloop);
- zero_v3(normal);
+ zero_v3(normal);
- /* calc normal, flipped: to get a positive 2d cross product */
- ml = mloop + mp_loopstart;
- co_prev = mvert[ml[mp_totloop - 1].v].co;
- for (j = 0; j < mp_totloop; j++, ml++) {
- co_curr = mvert[ml->v].co;
- add_newell_cross_v3_v3v3(normal, co_prev, co_curr);
- co_prev = co_curr;
- }
- if (UNLIKELY(normalize_v3(normal) == 0.0f)) {
- normal[2] = 1.0f;
- }
+ /* calc normal, flipped: to get a positive 2d cross product */
+ ml = mloop + mp_loopstart;
+ co_prev = mvert[ml[mp_totloop - 1].v].co;
+ for (j = 0; j < mp_totloop; j++, ml++) {
+ co_curr = mvert[ml->v].co;
+ add_newell_cross_v3_v3v3(normal, co_prev, co_curr);
+ co_prev = co_curr;
+ }
+ if (UNLIKELY(normalize_v3(normal) == 0.0f)) {
+ normal[2] = 1.0f;
+ }
- /* project verts to 2d */
- axis_dominant_v3_to_m3_negate(axis_mat, normal);
+ /* project verts to 2d */
+ axis_dominant_v3_to_m3_negate(axis_mat, normal);
- ml = mloop + mp_loopstart;
- for (j = 0; j < mp_totloop; j++, ml++) {
- mul_v2_m3v3(projverts[j], axis_mat, mvert[ml->v].co);
- }
+ ml = mloop + mp_loopstart;
+ for (j = 0; j < mp_totloop; j++, ml++) {
+ mul_v2_m3v3(projverts[j], axis_mat, mvert[ml->v].co);
+ }
- BLI_polyfill_calc_arena(projverts, mp_totloop, 1, tris, arena);
+ BLI_polyfill_calc_arena(projverts, mp_totloop, 1, tris, arena);
- /* apply fill */
- for (j = 0; j < totfilltri; j++) {
- unsigned int *tri = tris[j];
+ /* apply fill */
+ for (j = 0; j < totfilltri; j++) {
+ unsigned int *tri = tris[j];
- mlt = &mlooptri[mlooptri_index];
+ mlt = &mlooptri[mlooptri_index];
- /* set loop indices, transformed to vert indices later */
- l1 = mp_loopstart + tri[0];
- l2 = mp_loopstart + tri[1];
- l3 = mp_loopstart + tri[2];
+ /* set loop indices, transformed to vert indices later */
+ l1 = mp_loopstart + tri[0];
+ l2 = mp_loopstart + tri[1];
+ l3 = mp_loopstart + tri[2];
- ARRAY_SET_ITEMS(mlt->tri, l1, l2, l3);
- mlt->poly = (unsigned int)poly_index;
+ ARRAY_SET_ITEMS(mlt->tri, l1, l2, l3);
+ mlt->poly = (unsigned int)poly_index;
- mlooptri_index++;
- }
+ mlooptri_index++;
+ }
- BLI_memarena_clear(arena);
- }
- }
+ BLI_memarena_clear(arena);
+ }
+ }
- if (arena) {
- BLI_memarena_free(arena);
- arena = NULL;
- }
+ if (arena) {
+ BLI_memarena_free(arena);
+ arena = NULL;
+ }
- BLI_assert(mlooptri_index == poly_to_tri_count(totpoly, totloop));
- UNUSED_VARS_NDEBUG(totloop);
+ BLI_assert(mlooptri_index == poly_to_tri_count(totpoly, totloop));
+ UNUSED_VARS_NDEBUG(totloop);
#undef USE_TESSFACE_SPEEDUP
#undef ML_TO_MLT
}
-static void bm_corners_to_loops_ex(
- ID *id, CustomData *fdata, CustomData *ldata,
- MFace *mface, int totloop, int findex, int loopstart, int numTex, int numCol)
-{
- MTFace *texface;
- MCol *mcol;
- MLoopCol *mloopcol;
- MLoopUV *mloopuv;
- MFace *mf;
- int i;
-
- mf = mface + findex;
-
- for (i = 0; i < numTex; i++) {
- texface = CustomData_get_n(fdata, CD_MTFACE, findex, i);
-
- mloopuv = CustomData_get_n(ldata, CD_MLOOPUV, loopstart, i);
- copy_v2_v2(mloopuv->uv, texface->uv[0]); mloopuv++;
- copy_v2_v2(mloopuv->uv, texface->uv[1]); mloopuv++;
- copy_v2_v2(mloopuv->uv, texface->uv[2]); mloopuv++;
-
- if (mf->v4) {
- copy_v2_v2(mloopuv->uv, texface->uv[3]); mloopuv++;
- }
- }
-
- for (i = 0; i < numCol; i++) {
- mloopcol = CustomData_get_n(ldata, CD_MLOOPCOL, loopstart, i);
- mcol = CustomData_get_n(fdata, CD_MCOL, findex, i);
-
- MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[0]); mloopcol++;
- MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[1]); mloopcol++;
- MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[2]); mloopcol++;
- if (mf->v4) {
- MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[3]); mloopcol++;
- }
- }
-
- if (CustomData_has_layer(fdata, CD_TESSLOOPNORMAL)) {
- float (*lnors)[3] = CustomData_get(ldata, loopstart, CD_NORMAL);
- short (*tlnors)[3] = CustomData_get(fdata, findex, CD_TESSLOOPNORMAL);
- const int max = mf->v4 ? 4 : 3;
-
- for (i = 0; i < max; i++, lnors++, tlnors++) {
- normal_short_to_float_v3(*lnors, *tlnors);
- }
- }
-
- if (CustomData_has_layer(fdata, CD_MDISPS)) {
- MDisps *ld = CustomData_get(ldata, loopstart, CD_MDISPS);
- MDisps *fd = CustomData_get(fdata, findex, CD_MDISPS);
- float (*disps)[3] = fd->disps;
- int tot = mf->v4 ? 4 : 3;
- int corners;
-
- if (CustomData_external_test(fdata, CD_MDISPS)) {
- if (id && fdata->external) {
- CustomData_external_add(
- ldata, id, CD_MDISPS,
- totloop, fdata->external->filename);
- }
- }
-
- corners = multires_mdisp_corners(fd);
-
- if (corners == 0) {
- /* Empty MDisp layers appear in at least one of the sintel.blend files.
- * Not sure why this happens, but it seems fine to just ignore them here.
- * If (corners == 0) for a non-empty layer though, something went wrong. */
- BLI_assert(fd->totdisp == 0);
- }
- else {
- const int side = (int)sqrtf((float)(fd->totdisp / corners));
- const int side_sq = side * side;
-
- for (i = 0; i < tot; i++, disps += side_sq, ld++) {
- ld->totdisp = side_sq;
- ld->level = (int)(logf((float)side - 1.0f) / (float)M_LN2) + 1;
-
- if (ld->disps)
- MEM_freeN(ld->disps);
-
- ld->disps = MEM_malloc_arrayN((size_t)side_sq, sizeof(float[3]), "converted loop mdisps");
- if (fd->disps) {
- memcpy(ld->disps, disps, (size_t)side_sq * sizeof(float[3]));
- }
- else {
- memset(ld->disps, 0, (size_t)side_sq * sizeof(float[3]));
- }
- }
- }
- }
+static void bm_corners_to_loops_ex(ID *id,
+ CustomData *fdata,
+ CustomData *ldata,
+ MFace *mface,
+ int totloop,
+ int findex,
+ int loopstart,
+ int numTex,
+ int numCol)
+{
+ MTFace *texface;
+ MCol *mcol;
+ MLoopCol *mloopcol;
+ MLoopUV *mloopuv;
+ MFace *mf;
+ int i;
+
+ mf = mface + findex;
+
+ for (i = 0; i < numTex; i++) {
+ texface = CustomData_get_n(fdata, CD_MTFACE, findex, i);
+
+ mloopuv = CustomData_get_n(ldata, CD_MLOOPUV, loopstart, i);
+ copy_v2_v2(mloopuv->uv, texface->uv[0]);
+ mloopuv++;
+ copy_v2_v2(mloopuv->uv, texface->uv[1]);
+ mloopuv++;
+ copy_v2_v2(mloopuv->uv, texface->uv[2]);
+ mloopuv++;
+
+ if (mf->v4) {
+ copy_v2_v2(mloopuv->uv, texface->uv[3]);
+ mloopuv++;
+ }
+ }
+
+ for (i = 0; i < numCol; i++) {
+ mloopcol = CustomData_get_n(ldata, CD_MLOOPCOL, loopstart, i);
+ mcol = CustomData_get_n(fdata, CD_MCOL, findex, i);
+
+ MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[0]);
+ mloopcol++;
+ MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[1]);
+ mloopcol++;
+ MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[2]);
+ mloopcol++;
+ if (mf->v4) {
+ MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[3]);
+ mloopcol++;
+ }
+ }
+
+ if (CustomData_has_layer(fdata, CD_TESSLOOPNORMAL)) {
+ float(*lnors)[3] = CustomData_get(ldata, loopstart, CD_NORMAL);
+ short(*tlnors)[3] = CustomData_get(fdata, findex, CD_TESSLOOPNORMAL);
+ const int max = mf->v4 ? 4 : 3;
+
+ for (i = 0; i < max; i++, lnors++, tlnors++) {
+ normal_short_to_float_v3(*lnors, *tlnors);
+ }
+ }
+
+ if (CustomData_has_layer(fdata, CD_MDISPS)) {
+ MDisps *ld = CustomData_get(ldata, loopstart, CD_MDISPS);
+ MDisps *fd = CustomData_get(fdata, findex, CD_MDISPS);
+ float(*disps)[3] = fd->disps;
+ int tot = mf->v4 ? 4 : 3;
+ int corners;
+
+ if (CustomData_external_test(fdata, CD_MDISPS)) {
+ if (id && fdata->external) {
+ CustomData_external_add(ldata, id, CD_MDISPS, totloop, fdata->external->filename);
+ }
+ }
+
+ corners = multires_mdisp_corners(fd);
+
+ if (corners == 0) {
+ /* Empty MDisp layers appear in at least one of the sintel.blend files.
+ * Not sure why this happens, but it seems fine to just ignore them here.
+ * If (corners == 0) for a non-empty layer though, something went wrong. */
+ BLI_assert(fd->totdisp == 0);
+ }
+ else {
+ const int side = (int)sqrtf((float)(fd->totdisp / corners));
+ const int side_sq = side * side;
+
+ for (i = 0; i < tot; i++, disps += side_sq, ld++) {
+ ld->totdisp = side_sq;
+ ld->level = (int)(logf((float)side - 1.0f) / (float)M_LN2) + 1;
+
+ if (ld->disps)
+ MEM_freeN(ld->disps);
+
+ ld->disps = MEM_malloc_arrayN((size_t)side_sq, sizeof(float[3]), "converted loop mdisps");
+ if (fd->disps) {
+ memcpy(ld->disps, disps, (size_t)side_sq * sizeof(float[3]));
+ }
+ else {
+ memset(ld->disps, 0, (size_t)side_sq * sizeof(float[3]));
+ }
+ }
+ }
+ }
}
-
void BKE_mesh_convert_mfaces_to_mpolys(Mesh *mesh)
{
- BKE_mesh_convert_mfaces_to_mpolys_ex(
- &mesh->id, &mesh->fdata, &mesh->ldata, &mesh->pdata,
- mesh->totedge, mesh->totface, mesh->totloop, mesh->totpoly,
- mesh->medge, mesh->mface,
- &mesh->totloop, &mesh->totpoly, &mesh->mloop, &mesh->mpoly);
+ BKE_mesh_convert_mfaces_to_mpolys_ex(&mesh->id,
+ &mesh->fdata,
+ &mesh->ldata,
+ &mesh->pdata,
+ mesh->totedge,
+ mesh->totface,
+ mesh->totloop,
+ mesh->totpoly,
+ mesh->medge,
+ mesh->mface,
+ &mesh->totloop,
+ &mesh->totpoly,
+ &mesh->mloop,
+ &mesh->mpoly);
- BKE_mesh_update_customdata_pointers(mesh, true);
+ BKE_mesh_update_customdata_pointers(mesh, true);
}
/* the same as BKE_mesh_convert_mfaces_to_mpolys but oriented to be used in do_versions from readfile.c
@@ -3214,126 +3445,145 @@ void BKE_mesh_convert_mfaces_to_mpolys(Mesh *mesh)
*/
void BKE_mesh_do_versions_convert_mfaces_to_mpolys(Mesh *mesh)
{
- BKE_mesh_convert_mfaces_to_mpolys_ex(
- &mesh->id, &mesh->fdata, &mesh->ldata, &mesh->pdata,
- mesh->totedge, mesh->totface, mesh->totloop, mesh->totpoly,
- mesh->medge, mesh->mface,
- &mesh->totloop, &mesh->totpoly, &mesh->mloop, &mesh->mpoly);
-
- CustomData_bmesh_do_versions_update_active_layers(&mesh->fdata, &mesh->ldata);
-
- BKE_mesh_update_customdata_pointers(mesh, true);
-}
-
-void BKE_mesh_convert_mfaces_to_mpolys_ex(
- ID *id, CustomData *fdata, CustomData *ldata, CustomData *pdata,
- int totedge_i, int totface_i, int totloop_i, int totpoly_i,
- MEdge *medge, MFace *mface,
- int *r_totloop, int *r_totpoly,
- MLoop **r_mloop, MPoly **r_mpoly)
-{
- MFace *mf;
- MLoop *ml, *mloop;
- MPoly *mp, *mpoly;
- MEdge *me;
- EdgeHash *eh;
- int numTex, numCol;
- int i, j, totloop, totpoly, *polyindex;
-
- /* old flag, clear to allow for reuse */
+ BKE_mesh_convert_mfaces_to_mpolys_ex(&mesh->id,
+ &mesh->fdata,
+ &mesh->ldata,
+ &mesh->pdata,
+ mesh->totedge,
+ mesh->totface,
+ mesh->totloop,
+ mesh->totpoly,
+ mesh->medge,
+ mesh->mface,
+ &mesh->totloop,
+ &mesh->totpoly,
+ &mesh->mloop,
+ &mesh->mpoly);
+
+ CustomData_bmesh_do_versions_update_active_layers(&mesh->fdata, &mesh->ldata);
+
+ BKE_mesh_update_customdata_pointers(mesh, true);
+}
+
+void BKE_mesh_convert_mfaces_to_mpolys_ex(ID *id,
+ CustomData *fdata,
+ CustomData *ldata,
+ CustomData *pdata,
+ int totedge_i,
+ int totface_i,
+ int totloop_i,
+ int totpoly_i,
+ MEdge *medge,
+ MFace *mface,
+ int *r_totloop,
+ int *r_totpoly,
+ MLoop **r_mloop,
+ MPoly **r_mpoly)
+{
+ MFace *mf;
+ MLoop *ml, *mloop;
+ MPoly *mp, *mpoly;
+ MEdge *me;
+ EdgeHash *eh;
+ int numTex, numCol;
+ int i, j, totloop, totpoly, *polyindex;
+
+ /* old flag, clear to allow for reuse */
#define ME_FGON (1 << 3)
- /* just in case some of these layers are filled in (can happen with python created meshes) */
- CustomData_free(ldata, totloop_i);
- CustomData_free(pdata, totpoly_i);
+ /* just in case some of these layers are filled in (can happen with python created meshes) */
+ CustomData_free(ldata, totloop_i);
+ CustomData_free(pdata, totpoly_i);
- totpoly = totface_i;
- mpoly = MEM_calloc_arrayN((size_t)totpoly, sizeof(MPoly), "mpoly converted");
- CustomData_add_layer(pdata, CD_MPOLY, CD_ASSIGN, mpoly, totpoly);
+ totpoly = totface_i;
+ mpoly = MEM_calloc_arrayN((size_t)totpoly, sizeof(MPoly), "mpoly converted");
+ CustomData_add_layer(pdata, CD_MPOLY, CD_ASSIGN, mpoly, totpoly);
- numTex = CustomData_number_of_layers(fdata, CD_MTFACE);
- numCol = CustomData_number_of_layers(fdata, CD_MCOL);
+ numTex = CustomData_number_of_layers(fdata, CD_MTFACE);
+ numCol = CustomData_number_of_layers(fdata, CD_MCOL);
- totloop = 0;
- mf = mface;
- for (i = 0; i < totface_i; i++, mf++) {
- totloop += mf->v4 ? 4 : 3;
- }
+ totloop = 0;
+ mf = mface;
+ for (i = 0; i < totface_i; i++, mf++) {
+ totloop += mf->v4 ? 4 : 3;
+ }
- mloop = MEM_calloc_arrayN((size_t)totloop, sizeof(MLoop), "mloop converted");
+ mloop = MEM_calloc_arrayN((size_t)totloop, sizeof(MLoop), "mloop converted");
- CustomData_add_layer(ldata, CD_MLOOP, CD_ASSIGN, mloop, totloop);
+ CustomData_add_layer(ldata, CD_MLOOP, CD_ASSIGN, mloop, totloop);
- CustomData_to_bmeshpoly(fdata, ldata, totloop);
+ CustomData_to_bmeshpoly(fdata, ldata, totloop);
- if (id) {
- /* ensure external data is transferred */
- CustomData_external_read(fdata, id, CD_MASK_MDISPS, totface_i);
- }
+ if (id) {
+ /* ensure external data is transferred */
+ CustomData_external_read(fdata, id, CD_MASK_MDISPS, totface_i);
+ }
- eh = BLI_edgehash_new_ex(__func__, (unsigned int)totedge_i);
+ eh = BLI_edgehash_new_ex(__func__, (unsigned int)totedge_i);
- /* build edge hash */
- me = medge;
- for (i = 0; i < totedge_i; i++, me++) {
- BLI_edgehash_insert(eh, me->v1, me->v2, POINTER_FROM_UINT(i));
+ /* build edge hash */
+ me = medge;
+ for (i = 0; i < totedge_i; i++, me++) {
+ BLI_edgehash_insert(eh, me->v1, me->v2, POINTER_FROM_UINT(i));
- /* unrelated but avoid having the FGON flag enabled, so we can reuse it later for something else */
- me->flag &= ~ME_FGON;
- }
+ /* unrelated but avoid having the FGON flag enabled, so we can reuse it later for something else */
+ me->flag &= ~ME_FGON;
+ }
- polyindex = CustomData_get_layer(fdata, CD_ORIGINDEX);
+ polyindex = CustomData_get_layer(fdata, CD_ORIGINDEX);
- j = 0; /* current loop index */
- ml = mloop;
- mf = mface;
- mp = mpoly;
- for (i = 0; i < totface_i; i++, mf++, mp++) {
- mp->loopstart = j;
+ j = 0; /* current loop index */
+ ml = mloop;
+ mf = mface;
+ mp = mpoly;
+ for (i = 0; i < totface_i; i++, mf++, mp++) {
+ mp->loopstart = j;
- mp->totloop = mf->v4 ? 4 : 3;
+ mp->totloop = mf->v4 ? 4 : 3;
- mp->mat_nr = mf->mat_nr;
- mp->flag = mf->flag;
+ mp->mat_nr = mf->mat_nr;
+ mp->flag = mf->flag;
-# define ML(v1, v2) { \
- ml->v = mf->v1; \
- ml->e = POINTER_AS_UINT(BLI_edgehash_lookup(eh, mf->v1, mf->v2)); \
- ml++; j++; \
- } (void)0
+#define ML(v1, v2) \
+ { \
+ ml->v = mf->v1; \
+ ml->e = POINTER_AS_UINT(BLI_edgehash_lookup(eh, mf->v1, mf->v2)); \
+ ml++; \
+ j++; \
+ } \
+ (void)0
- ML(v1, v2);
- ML(v2, v3);
- if (mf->v4) {
- ML(v3, v4);
- ML(v4, v1);
- }
- else {
- ML(v3, v1);
- }
+ ML(v1, v2);
+ ML(v2, v3);
+ if (mf->v4) {
+ ML(v3, v4);
+ ML(v4, v1);
+ }
+ else {
+ ML(v3, v1);
+ }
-# undef ML
+#undef ML
- bm_corners_to_loops_ex(id, fdata, ldata, mface, totloop, i, mp->loopstart, numTex, numCol);
+ bm_corners_to_loops_ex(id, fdata, ldata, mface, totloop, i, mp->loopstart, numTex, numCol);
- if (polyindex) {
- *polyindex = i;
- polyindex++;
- }
- }
+ if (polyindex) {
+ *polyindex = i;
+ polyindex++;
+ }
+ }
- /* note, we don't convert NGons at all, these are not even real ngons,
- * they have their own UV's, colors etc - its more an editing feature. */
+ /* note, we don't convert NGons at all, these are not even real ngons,
+ * they have their own UV's, colors etc - its more an editing feature. */
- BLI_edgehash_free(eh, NULL);
+ BLI_edgehash_free(eh, NULL);
- *r_totpoly = totpoly;
- *r_totloop = totloop;
- *r_mpoly = mpoly;
- *r_mloop = mloop;
+ *r_totpoly = totpoly;
+ *r_totloop = totloop;
+ *r_mpoly = mpoly;
+ *r_mloop = mloop;
#undef ME_FGON
-
}
/** \} */
@@ -3343,38 +3593,38 @@ void BKE_mesh_convert_mfaces_to_mpolys_ex(
*/
void BKE_mesh_mdisp_flip(MDisps *md, const bool use_loop_mdisp_flip)
{
- if (UNLIKELY(!md->totdisp || !md->disps)) {
- return;
- }
+ if (UNLIKELY(!md->totdisp || !md->disps)) {
+ return;
+ }
- const int sides = (int)sqrt(md->totdisp);
- float (*co)[3] = md->disps;
+ const int sides = (int)sqrt(md->totdisp);
+ float(*co)[3] = md->disps;
- for (int x = 0; x < sides; x++) {
- float *co_a, *co_b;
+ for (int x = 0; x < sides; x++) {
+ float *co_a, *co_b;
- for (int y = 0; y < x; y++) {
- co_a = co[y * sides + x];
- co_b = co[x * sides + y];
+ for (int y = 0; y < x; y++) {
+ co_a = co[y * sides + x];
+ co_b = co[x * sides + y];
- swap_v3_v3(co_a, co_b);
- SWAP(float, co_a[0], co_a[1]);
- SWAP(float, co_b[0], co_b[1]);
+ swap_v3_v3(co_a, co_b);
+ SWAP(float, co_a[0], co_a[1]);
+ SWAP(float, co_b[0], co_b[1]);
- if (use_loop_mdisp_flip) {
- co_a[2] *= -1.0f;
- co_b[2] *= -1.0f;
- }
- }
+ if (use_loop_mdisp_flip) {
+ co_a[2] *= -1.0f;
+ co_b[2] *= -1.0f;
+ }
+ }
- co_a = co[x * sides + x];
+ co_a = co[x * sides + x];
- SWAP(float, co_a[0], co_a[1]);
+ SWAP(float, co_a[0], co_a[1]);
- if (use_loop_mdisp_flip) {
- co_a[2] *= -1.0f;
- }
- }
+ if (use_loop_mdisp_flip) {
+ co_a[2] *= -1.0f;
+ }
+ }
}
/**
@@ -3385,49 +3635,52 @@ void BKE_mesh_mdisp_flip(MDisps *md, const bool use_loop_mdisp_flip)
* \param mloop: the full loops array.
* \param ldata: the loops custom data.
*/
-void BKE_mesh_polygon_flip_ex(
- MPoly *mpoly, MLoop *mloop, CustomData *ldata,
- float (*lnors)[3], MDisps *mdisp, const bool use_loop_mdisp_flip)
-{
- int loopstart = mpoly->loopstart;
- int loopend = loopstart + mpoly->totloop - 1;
- const bool loops_in_ldata = (CustomData_get_layer(ldata, CD_MLOOP) == mloop);
-
- if (mdisp) {
- for (int i = loopstart; i <= loopend; i++) {
- BKE_mesh_mdisp_flip(&mdisp[i], use_loop_mdisp_flip);
- }
- }
-
- /* Note that we keep same start vertex for flipped face. */
-
- /* We also have to update loops edge
- * (they will get their original 'other edge', that is, the original edge of their original previous loop)... */
- unsigned int prev_edge_index = mloop[loopstart].e;
- mloop[loopstart].e = mloop[loopend].e;
-
- for (loopstart++; loopend > loopstart; loopstart++, loopend--) {
- mloop[loopend].e = mloop[loopend - 1].e;
- SWAP(unsigned int, mloop[loopstart].e, prev_edge_index);
-
- if (!loops_in_ldata) {
- SWAP(MLoop, mloop[loopstart], mloop[loopend]);
- }
- if (lnors) {
- swap_v3_v3(lnors[loopstart], lnors[loopend]);
- }
- CustomData_swap(ldata, loopstart, loopend);
- }
- /* Even if we did not swap the other 'pivot' loop, we need to set its swapped edge. */
- if (loopstart == loopend) {
- mloop[loopstart].e = prev_edge_index;
- }
+void BKE_mesh_polygon_flip_ex(MPoly *mpoly,
+ MLoop *mloop,
+ CustomData *ldata,
+ float (*lnors)[3],
+ MDisps *mdisp,
+ const bool use_loop_mdisp_flip)
+{
+ int loopstart = mpoly->loopstart;
+ int loopend = loopstart + mpoly->totloop - 1;
+ const bool loops_in_ldata = (CustomData_get_layer(ldata, CD_MLOOP) == mloop);
+
+ if (mdisp) {
+ for (int i = loopstart; i <= loopend; i++) {
+ BKE_mesh_mdisp_flip(&mdisp[i], use_loop_mdisp_flip);
+ }
+ }
+
+ /* Note that we keep same start vertex for flipped face. */
+
+ /* We also have to update loops edge
+ * (they will get their original 'other edge', that is, the original edge of their original previous loop)... */
+ unsigned int prev_edge_index = mloop[loopstart].e;
+ mloop[loopstart].e = mloop[loopend].e;
+
+ for (loopstart++; loopend > loopstart; loopstart++, loopend--) {
+ mloop[loopend].e = mloop[loopend - 1].e;
+ SWAP(unsigned int, mloop[loopstart].e, prev_edge_index);
+
+ if (!loops_in_ldata) {
+ SWAP(MLoop, mloop[loopstart], mloop[loopend]);
+ }
+ if (lnors) {
+ swap_v3_v3(lnors[loopstart], lnors[loopend]);
+ }
+ CustomData_swap(ldata, loopstart, loopend);
+ }
+ /* Even if we did not swap the other 'pivot' loop, we need to set its swapped edge. */
+ if (loopstart == loopend) {
+ mloop[loopstart].e = prev_edge_index;
+ }
}
void BKE_mesh_polygon_flip(MPoly *mpoly, MLoop *mloop, CustomData *ldata)
{
- MDisps *mdisp = CustomData_get_layer(ldata, CD_MDISPS);
- BKE_mesh_polygon_flip_ex(mpoly, mloop, ldata, NULL, mdisp, true);
+ MDisps *mdisp = CustomData_get_layer(ldata, CD_MDISPS);
+ BKE_mesh_polygon_flip_ex(mpoly, mloop, ldata, NULL, mdisp, true);
}
/**
@@ -3435,16 +3688,15 @@ void BKE_mesh_polygon_flip(MPoly *mpoly, MLoop *mloop, CustomData *ldata)
*
* \note Invalidates tessellation, caller must handle that.
*/
-void BKE_mesh_polygons_flip(
- MPoly *mpoly, MLoop *mloop, CustomData *ldata, int totpoly)
+void BKE_mesh_polygons_flip(MPoly *mpoly, MLoop *mloop, CustomData *ldata, int totpoly)
{
- MDisps *mdisp = CustomData_get_layer(ldata, CD_MDISPS);
- MPoly *mp;
- int i;
+ MDisps *mdisp = CustomData_get_layer(ldata, CD_MDISPS);
+ MPoly *mp;
+ int i;
- for (mp = mpoly, i = 0; i < totpoly; mp++, i++) {
- BKE_mesh_polygon_flip_ex(mp, mloop, ldata, NULL, mdisp, true);
- }
+ for (mp = mpoly, i = 0; i < totpoly; mp++, i++) {
+ BKE_mesh_polygon_flip_ex(mp, mloop, ldata, NULL, mdisp, true);
+ }
}
/* -------------------------------------------------------------------- */
@@ -3453,187 +3705,181 @@ void BKE_mesh_polygons_flip(
/* update the hide flag for edges and faces from the corresponding
* flag in verts */
-void BKE_mesh_flush_hidden_from_verts_ex(
- const MVert *mvert,
- const MLoop *mloop,
- MEdge *medge, const int totedge,
- MPoly *mpoly, const int totpoly)
-{
- int i, j;
-
- for (i = 0; i < totedge; i++) {
- MEdge *e = &medge[i];
- if (mvert[e->v1].flag & ME_HIDE ||
- mvert[e->v2].flag & ME_HIDE)
- {
- e->flag |= ME_HIDE;
- }
- else {
- e->flag &= ~ME_HIDE;
- }
- }
- for (i = 0; i < totpoly; i++) {
- MPoly *p = &mpoly[i];
- p->flag &= (char)~ME_HIDE;
- for (j = 0; j < p->totloop; j++) {
- if (mvert[mloop[p->loopstart + j].v].flag & ME_HIDE)
- p->flag |= ME_HIDE;
- }
- }
+void BKE_mesh_flush_hidden_from_verts_ex(const MVert *mvert,
+ const MLoop *mloop,
+ MEdge *medge,
+ const int totedge,
+ MPoly *mpoly,
+ const int totpoly)
+{
+ int i, j;
+
+ for (i = 0; i < totedge; i++) {
+ MEdge *e = &medge[i];
+ if (mvert[e->v1].flag & ME_HIDE || mvert[e->v2].flag & ME_HIDE) {
+ e->flag |= ME_HIDE;
+ }
+ else {
+ e->flag &= ~ME_HIDE;
+ }
+ }
+ for (i = 0; i < totpoly; i++) {
+ MPoly *p = &mpoly[i];
+ p->flag &= (char)~ME_HIDE;
+ for (j = 0; j < p->totloop; j++) {
+ if (mvert[mloop[p->loopstart + j].v].flag & ME_HIDE)
+ p->flag |= ME_HIDE;
+ }
+ }
}
void BKE_mesh_flush_hidden_from_verts(Mesh *me)
{
- BKE_mesh_flush_hidden_from_verts_ex(
- me->mvert, me->mloop,
- me->medge, me->totedge,
- me->mpoly, me->totpoly);
-}
-
-void BKE_mesh_flush_hidden_from_polys_ex(
- MVert *mvert,
- const MLoop *mloop,
- MEdge *medge, const int UNUSED(totedge),
- const MPoly *mpoly, const int totpoly)
-{
- const MPoly *mp;
- int i;
-
- i = totpoly;
- for (mp = mpoly; i--; mp++) {
- if (mp->flag & ME_HIDE) {
- const MLoop *ml;
- int j;
- j = mp->totloop;
- for (ml = &mloop[mp->loopstart]; j--; ml++) {
- mvert[ml->v].flag |= ME_HIDE;
- medge[ml->e].flag |= ME_HIDE;
- }
- }
- }
-
- i = totpoly;
- for (mp = mpoly; i--; mp++) {
- if ((mp->flag & ME_HIDE) == 0) {
- const MLoop *ml;
- int j;
- j = mp->totloop;
- for (ml = &mloop[mp->loopstart]; j--; ml++) {
- mvert[ml->v].flag &= (char)~ME_HIDE;
- medge[ml->e].flag &= (short)~ME_HIDE;
- }
- }
- }
+ BKE_mesh_flush_hidden_from_verts_ex(
+ me->mvert, me->mloop, me->medge, me->totedge, me->mpoly, me->totpoly);
+}
+
+void BKE_mesh_flush_hidden_from_polys_ex(MVert *mvert,
+ const MLoop *mloop,
+ MEdge *medge,
+ const int UNUSED(totedge),
+ const MPoly *mpoly,
+ const int totpoly)
+{
+ const MPoly *mp;
+ int i;
+
+ i = totpoly;
+ for (mp = mpoly; i--; mp++) {
+ if (mp->flag & ME_HIDE) {
+ const MLoop *ml;
+ int j;
+ j = mp->totloop;
+ for (ml = &mloop[mp->loopstart]; j--; ml++) {
+ mvert[ml->v].flag |= ME_HIDE;
+ medge[ml->e].flag |= ME_HIDE;
+ }
+ }
+ }
+
+ i = totpoly;
+ for (mp = mpoly; i--; mp++) {
+ if ((mp->flag & ME_HIDE) == 0) {
+ const MLoop *ml;
+ int j;
+ j = mp->totloop;
+ for (ml = &mloop[mp->loopstart]; j--; ml++) {
+ mvert[ml->v].flag &= (char)~ME_HIDE;
+ medge[ml->e].flag &= (short)~ME_HIDE;
+ }
+ }
+ }
}
void BKE_mesh_flush_hidden_from_polys(Mesh *me)
{
- BKE_mesh_flush_hidden_from_polys_ex(
- me->mvert, me->mloop,
- me->medge, me->totedge,
- me->mpoly, me->totpoly);
+ BKE_mesh_flush_hidden_from_polys_ex(
+ me->mvert, me->mloop, me->medge, me->totedge, me->mpoly, me->totpoly);
}
/**
* simple poly -> vert/edge selection.
*/
-void BKE_mesh_flush_select_from_polys_ex(
- MVert *mvert, const int totvert,
- const MLoop *mloop,
- MEdge *medge, const int totedge,
- const MPoly *mpoly, const int totpoly)
-{
- MVert *mv;
- MEdge *med;
- const MPoly *mp;
- int i;
-
- i = totvert;
- for (mv = mvert; i--; mv++) {
- mv->flag &= (char)~SELECT;
- }
-
- i = totedge;
- for (med = medge; i--; med++) {
- med->flag &= ~SELECT;
- }
-
- i = totpoly;
- for (mp = mpoly; i--; mp++) {
- /* assume if its selected its not hidden and none of its verts/edges are hidden
- * (a common assumption)*/
- if (mp->flag & ME_FACE_SEL) {
- const MLoop *ml;
- int j;
- j = mp->totloop;
- for (ml = &mloop[mp->loopstart]; j--; ml++) {
- mvert[ml->v].flag |= SELECT;
- medge[ml->e].flag |= SELECT;
- }
- }
- }
+void BKE_mesh_flush_select_from_polys_ex(MVert *mvert,
+ const int totvert,
+ const MLoop *mloop,
+ MEdge *medge,
+ const int totedge,
+ const MPoly *mpoly,
+ const int totpoly)
+{
+ MVert *mv;
+ MEdge *med;
+ const MPoly *mp;
+ int i;
+
+ i = totvert;
+ for (mv = mvert; i--; mv++) {
+ mv->flag &= (char)~SELECT;
+ }
+
+ i = totedge;
+ for (med = medge; i--; med++) {
+ med->flag &= ~SELECT;
+ }
+
+ i = totpoly;
+ for (mp = mpoly; i--; mp++) {
+ /* assume if its selected its not hidden and none of its verts/edges are hidden
+ * (a common assumption)*/
+ if (mp->flag & ME_FACE_SEL) {
+ const MLoop *ml;
+ int j;
+ j = mp->totloop;
+ for (ml = &mloop[mp->loopstart]; j--; ml++) {
+ mvert[ml->v].flag |= SELECT;
+ medge[ml->e].flag |= SELECT;
+ }
+ }
+ }
}
void BKE_mesh_flush_select_from_polys(Mesh *me)
{
- BKE_mesh_flush_select_from_polys_ex(
- me->mvert, me->totvert,
- me->mloop,
- me->medge, me->totedge,
- me->mpoly, me->totpoly);
-}
-
-void BKE_mesh_flush_select_from_verts_ex(
- const MVert *mvert, const int UNUSED(totvert),
- const MLoop *mloop,
- MEdge *medge, const int totedge,
- MPoly *mpoly, const int totpoly)
-{
- MEdge *med;
- MPoly *mp;
- int i;
-
- /* edges */
- i = totedge;
- for (med = medge; i--; med++) {
- if ((med->flag & ME_HIDE) == 0) {
- if ((mvert[med->v1].flag & SELECT) && (mvert[med->v2].flag & SELECT)) {
- med->flag |= SELECT;
- }
- else {
- med->flag &= ~SELECT;
- }
- }
- }
-
- /* polys */
- i = totpoly;
- for (mp = mpoly; i--; mp++) {
- if ((mp->flag & ME_HIDE) == 0) {
- bool ok = true;
- const MLoop *ml;
- int j;
- j = mp->totloop;
- for (ml = &mloop[mp->loopstart]; j--; ml++) {
- if ((mvert[ml->v].flag & SELECT) == 0) {
- ok = false;
- break;
- }
- }
-
- if (ok) {
- mp->flag |= ME_FACE_SEL;
- }
- else {
- mp->flag &= (char)~ME_FACE_SEL;
- }
- }
- }
+ BKE_mesh_flush_select_from_polys_ex(
+ me->mvert, me->totvert, me->mloop, me->medge, me->totedge, me->mpoly, me->totpoly);
+}
+
+void BKE_mesh_flush_select_from_verts_ex(const MVert *mvert,
+ const int UNUSED(totvert),
+ const MLoop *mloop,
+ MEdge *medge,
+ const int totedge,
+ MPoly *mpoly,
+ const int totpoly)
+{
+ MEdge *med;
+ MPoly *mp;
+ int i;
+
+ /* edges */
+ i = totedge;
+ for (med = medge; i--; med++) {
+ if ((med->flag & ME_HIDE) == 0) {
+ if ((mvert[med->v1].flag & SELECT) && (mvert[med->v2].flag & SELECT)) {
+ med->flag |= SELECT;
+ }
+ else {
+ med->flag &= ~SELECT;
+ }
+ }
+ }
+
+ /* polys */
+ i = totpoly;
+ for (mp = mpoly; i--; mp++) {
+ if ((mp->flag & ME_HIDE) == 0) {
+ bool ok = true;
+ const MLoop *ml;
+ int j;
+ j = mp->totloop;
+ for (ml = &mloop[mp->loopstart]; j--; ml++) {
+ if ((mvert[ml->v].flag & SELECT) == 0) {
+ ok = false;
+ break;
+ }
+ }
+
+ if (ok) {
+ mp->flag |= ME_FACE_SEL;
+ }
+ else {
+ mp->flag &= (char)~ME_FACE_SEL;
+ }
+ }
+ }
}
void BKE_mesh_flush_select_from_verts(Mesh *me)
{
- BKE_mesh_flush_select_from_verts_ex(
- me->mvert, me->totvert,
- me->mloop,
- me->medge, me->totedge,
- me->mpoly, me->totpoly);
+ BKE_mesh_flush_select_from_verts_ex(
+ me->mvert, me->totvert, me->mloop, me->medge, me->totedge, me->mpoly, me->totpoly);
}
/** \} */
@@ -3652,53 +3898,58 @@ void BKE_mesh_flush_select_from_verts(Mesh *me)
* \param vert_cos_org: reference for the output location.
* \param vert_cos_new: resulting coords.
*/
-void BKE_mesh_calc_relative_deform(
- const MPoly *mpoly, const int totpoly,
- const MLoop *mloop, const int totvert,
-
- const float (*vert_cos_src)[3],
- const float (*vert_cos_dst)[3],
-
- const float (*vert_cos_org)[3],
- float (*vert_cos_new)[3])
-{
- const MPoly *mp;
- int i;
-
- int *vert_accum = MEM_calloc_arrayN((size_t)totvert, sizeof(*vert_accum), __func__);
-
- memset(vert_cos_new, '\0', sizeof(*vert_cos_new) * (size_t)totvert);
-
- for (i = 0, mp = mpoly; i < totpoly; i++, mp++) {
- const MLoop *loopstart = mloop + mp->loopstart;
- int j;
-
- for (j = 0; j < mp->totloop; j++) {
- unsigned int v_prev = loopstart[(mp->totloop + (j - 1)) % mp->totloop].v;
- unsigned int v_curr = loopstart[j].v;
- unsigned int v_next = loopstart[(j + 1) % mp->totloop].v;
-
- float tvec[3];
-
- transform_point_by_tri_v3(
- tvec, vert_cos_dst[v_curr],
- vert_cos_org[v_prev], vert_cos_org[v_curr], vert_cos_org[v_next],
- vert_cos_src[v_prev], vert_cos_src[v_curr], vert_cos_src[v_next]);
-
- add_v3_v3(vert_cos_new[v_curr], tvec);
- vert_accum[v_curr] += 1;
- }
- }
-
- for (i = 0; i < totvert; i++) {
- if (vert_accum[i]) {
- mul_v3_fl(vert_cos_new[i], 1.0f / (float)vert_accum[i]);
- }
- else {
- copy_v3_v3(vert_cos_new[i], vert_cos_org[i]);
- }
- }
-
- MEM_freeN(vert_accum);
+void BKE_mesh_calc_relative_deform(const MPoly *mpoly,
+ const int totpoly,
+ const MLoop *mloop,
+ const int totvert,
+
+ const float (*vert_cos_src)[3],
+ const float (*vert_cos_dst)[3],
+
+ const float (*vert_cos_org)[3],
+ float (*vert_cos_new)[3])
+{
+ const MPoly *mp;
+ int i;
+
+ int *vert_accum = MEM_calloc_arrayN((size_t)totvert, sizeof(*vert_accum), __func__);
+
+ memset(vert_cos_new, '\0', sizeof(*vert_cos_new) * (size_t)totvert);
+
+ for (i = 0, mp = mpoly; i < totpoly; i++, mp++) {
+ const MLoop *loopstart = mloop + mp->loopstart;
+ int j;
+
+ for (j = 0; j < mp->totloop; j++) {
+ unsigned int v_prev = loopstart[(mp->totloop + (j - 1)) % mp->totloop].v;
+ unsigned int v_curr = loopstart[j].v;
+ unsigned int v_next = loopstart[(j + 1) % mp->totloop].v;
+
+ float tvec[3];
+
+ transform_point_by_tri_v3(tvec,
+ vert_cos_dst[v_curr],
+ vert_cos_org[v_prev],
+ vert_cos_org[v_curr],
+ vert_cos_org[v_next],
+ vert_cos_src[v_prev],
+ vert_cos_src[v_curr],
+ vert_cos_src[v_next]);
+
+ add_v3_v3(vert_cos_new[v_curr], tvec);
+ vert_accum[v_curr] += 1;
+ }
+ }
+
+ for (i = 0; i < totvert; i++) {
+ if (vert_accum[i]) {
+ mul_v3_fl(vert_cos_new[i], 1.0f / (float)vert_accum[i]);
+ }
+ else {
+ copy_v3_v3(vert_cos_new[i], vert_cos_org[i]);
+ }
+ }
+
+ MEM_freeN(vert_accum);
}
/** \} */
diff --git a/source/blender/blenkernel/intern/mesh_iterators.c b/source/blender/blenkernel/intern/mesh_iterators.c
index 053e45cfe84..1f8436408fb 100644
--- a/source/blender/blenkernel/intern/mesh_iterators.c
+++ b/source/blender/blenkernel/intern/mesh_iterators.c
@@ -33,173 +33,182 @@
#include "MEM_guardedalloc.h"
/* Copied from cdDM_foreachMappedVert */
-void BKE_mesh_foreach_mapped_vert(
- Mesh *mesh,
- void (*func)(void *userData, int index, const float co[3], const float no_f[3], const short no_s[3]),
- void *userData,
- MeshForeachFlag flag)
+void BKE_mesh_foreach_mapped_vert(Mesh *mesh,
+ void (*func)(void *userData,
+ int index,
+ const float co[3],
+ const float no_f[3],
+ const short no_s[3]),
+ void *userData,
+ MeshForeachFlag flag)
{
- const MVert *mv = mesh->mvert;
- const int *index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX);
-
- if (index) {
- for (int i = 0; i < mesh->totvert; i++, mv++) {
- const short *no = (flag & MESH_FOREACH_USE_NORMAL) ? mv->no : NULL;
- const int orig = *index++;
- if (orig == ORIGINDEX_NONE) {
- continue;
- }
- func(userData, orig, mv->co, NULL, no);
- }
- }
- else {
- for (int i = 0; i < mesh->totvert; i++, mv++) {
- const short *no = (flag & MESH_FOREACH_USE_NORMAL) ? mv->no : NULL;
- func(userData, i, mv->co, NULL, no);
- }
- }
+ const MVert *mv = mesh->mvert;
+ const int *index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX);
+
+ if (index) {
+ for (int i = 0; i < mesh->totvert; i++, mv++) {
+ const short *no = (flag & MESH_FOREACH_USE_NORMAL) ? mv->no : NULL;
+ const int orig = *index++;
+ if (orig == ORIGINDEX_NONE) {
+ continue;
+ }
+ func(userData, orig, mv->co, NULL, no);
+ }
+ }
+ else {
+ for (int i = 0; i < mesh->totvert; i++, mv++) {
+ const short *no = (flag & MESH_FOREACH_USE_NORMAL) ? mv->no : NULL;
+ func(userData, i, mv->co, NULL, no);
+ }
+ }
}
/* Copied from cdDM_foreachMappedEdge */
void BKE_mesh_foreach_mapped_edge(
- Mesh *mesh,
- void (*func)(void *userData, int index, const float v0co[3], const float v1co[3]),
- void *userData)
+ Mesh *mesh,
+ void (*func)(void *userData, int index, const float v0co[3], const float v1co[3]),
+ void *userData)
{
- const MVert *mv = mesh->mvert;
- const MEdge *med = mesh->medge;
- const int *index = CustomData_get_layer(&mesh->edata, CD_ORIGINDEX);
-
- if (index) {
- for (int i = 0; i < mesh->totedge; i++, med++) {
- const int orig = *index++;
- if (orig == ORIGINDEX_NONE) {
- continue;
- }
- func(userData, orig, mv[med->v1].co, mv[med->v2].co);
- }
- }
- else {
- for (int i = 0; i < mesh->totedge; i++, med++) {
- func(userData, i, mv[med->v1].co, mv[med->v2].co);
- }
- }
+ const MVert *mv = mesh->mvert;
+ const MEdge *med = mesh->medge;
+ const int *index = CustomData_get_layer(&mesh->edata, CD_ORIGINDEX);
+
+ if (index) {
+ for (int i = 0; i < mesh->totedge; i++, med++) {
+ const int orig = *index++;
+ if (orig == ORIGINDEX_NONE) {
+ continue;
+ }
+ func(userData, orig, mv[med->v1].co, mv[med->v2].co);
+ }
+ }
+ else {
+ for (int i = 0; i < mesh->totedge; i++, med++) {
+ func(userData, i, mv[med->v1].co, mv[med->v2].co);
+ }
+ }
}
/* Copied from cdDM_foreachMappedLoop */
-void BKE_mesh_foreach_mapped_loop(
- Mesh *mesh,
- void (*func)(void *userData, int vertex_index, int face_index, const float co[3], const float no[3]),
- void *userData,
- MeshForeachFlag flag)
+void BKE_mesh_foreach_mapped_loop(Mesh *mesh,
+ void (*func)(void *userData,
+ int vertex_index,
+ int face_index,
+ const float co[3],
+ const float no[3]),
+ void *userData,
+ MeshForeachFlag flag)
{
- /* We can't use dm->getLoopDataLayout(dm) here, we want to always access dm->loopData, EditDerivedBMesh would
- * return loop data from bmesh itself. */
- const float (*lnors)[3] = (flag & MESH_FOREACH_USE_NORMAL) ? CustomData_get_layer(&mesh->ldata, CD_NORMAL) : NULL;
-
- const MVert *mv = mesh->mvert;
- const MLoop *ml = mesh->mloop;
- const MPoly *mp = mesh->mpoly;
- const int *v_index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX);
- const int *f_index = CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX);
- int p_idx, i;
-
- if (v_index || f_index) {
- for (p_idx = 0; p_idx < mesh->totpoly; p_idx++, mp++) {
- for (i = 0; i < mp->totloop; i++, ml++) {
- const int v_idx = v_index ? v_index[ml->v] : ml->v;
- const int f_idx = f_index ? f_index[p_idx] : p_idx;
- const float *no = lnors ? *lnors++ : NULL;
- if (ELEM(ORIGINDEX_NONE, v_idx, f_idx)) {
- continue;
- }
- func(userData, v_idx, f_idx, mv[ml->v].co, no);
- }
- }
- }
- else {
- for (p_idx = 0; p_idx < mesh->totpoly; p_idx++, mp++) {
- for (i = 0; i < mp->totloop; i++, ml++) {
- const int v_idx = ml->v;
- const int f_idx = p_idx;
- const float *no = lnors ? *lnors++ : NULL;
- func(userData, v_idx, f_idx, mv[ml->v].co, no);
- }
- }
- }
+ /* We can't use dm->getLoopDataLayout(dm) here, we want to always access dm->loopData, EditDerivedBMesh would
+ * return loop data from bmesh itself. */
+ const float(*lnors)[3] = (flag & MESH_FOREACH_USE_NORMAL) ?
+ CustomData_get_layer(&mesh->ldata, CD_NORMAL) :
+ NULL;
+
+ const MVert *mv = mesh->mvert;
+ const MLoop *ml = mesh->mloop;
+ const MPoly *mp = mesh->mpoly;
+ const int *v_index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX);
+ const int *f_index = CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX);
+ int p_idx, i;
+
+ if (v_index || f_index) {
+ for (p_idx = 0; p_idx < mesh->totpoly; p_idx++, mp++) {
+ for (i = 0; i < mp->totloop; i++, ml++) {
+ const int v_idx = v_index ? v_index[ml->v] : ml->v;
+ const int f_idx = f_index ? f_index[p_idx] : p_idx;
+ const float *no = lnors ? *lnors++ : NULL;
+ if (ELEM(ORIGINDEX_NONE, v_idx, f_idx)) {
+ continue;
+ }
+ func(userData, v_idx, f_idx, mv[ml->v].co, no);
+ }
+ }
+ }
+ else {
+ for (p_idx = 0; p_idx < mesh->totpoly; p_idx++, mp++) {
+ for (i = 0; i < mp->totloop; i++, ml++) {
+ const int v_idx = ml->v;
+ const int f_idx = p_idx;
+ const float *no = lnors ? *lnors++ : NULL;
+ func(userData, v_idx, f_idx, mv[ml->v].co, no);
+ }
+ }
+ }
}
/* Copied from cdDM_foreachMappedFaceCenter */
void BKE_mesh_foreach_mapped_face_center(
- Mesh *mesh,
- void (*func)(void *userData, int index, const float cent[3], const float no[3]),
- void *userData,
- MeshForeachFlag flag)
+ Mesh *mesh,
+ void (*func)(void *userData, int index, const float cent[3], const float no[3]),
+ void *userData,
+ MeshForeachFlag flag)
{
- const MVert *mvert = mesh->mvert;
- const MPoly *mp = mesh->mpoly;
- const MLoop *ml;
- float _no_buf[3];
- float *no = (flag & MESH_FOREACH_USE_NORMAL) ? _no_buf : NULL;
- const int *index = CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX);
-
- if (index) {
- for (int i = 0; i < mesh->totpoly; i++, mp++) {
- const int orig = *index++;
- if (orig == ORIGINDEX_NONE) {
- continue;
- }
- float cent[3];
- ml = &mesh->mloop[mp->loopstart];
- BKE_mesh_calc_poly_center(mp, ml, mvert, cent);
- if (flag & MESH_FOREACH_USE_NORMAL) {
- BKE_mesh_calc_poly_normal(mp, ml, mvert, no);
- }
- func(userData, orig, cent, no);
- }
- }
- else {
- for (int i = 0; i < mesh->totpoly; i++, mp++) {
- float cent[3];
- ml = &mesh->mloop[mp->loopstart];
- BKE_mesh_calc_poly_center(mp, ml, mvert, cent);
- if (flag & MESH_FOREACH_USE_NORMAL) {
- BKE_mesh_calc_poly_normal(mp, ml, mvert, no);
- }
- func(userData, i, cent, no);
- }
- }
+ const MVert *mvert = mesh->mvert;
+ const MPoly *mp = mesh->mpoly;
+ const MLoop *ml;
+ float _no_buf[3];
+ float *no = (flag & MESH_FOREACH_USE_NORMAL) ? _no_buf : NULL;
+ const int *index = CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX);
+
+ if (index) {
+ for (int i = 0; i < mesh->totpoly; i++, mp++) {
+ const int orig = *index++;
+ if (orig == ORIGINDEX_NONE) {
+ continue;
+ }
+ float cent[3];
+ ml = &mesh->mloop[mp->loopstart];
+ BKE_mesh_calc_poly_center(mp, ml, mvert, cent);
+ if (flag & MESH_FOREACH_USE_NORMAL) {
+ BKE_mesh_calc_poly_normal(mp, ml, mvert, no);
+ }
+ func(userData, orig, cent, no);
+ }
+ }
+ else {
+ for (int i = 0; i < mesh->totpoly; i++, mp++) {
+ float cent[3];
+ ml = &mesh->mloop[mp->loopstart];
+ BKE_mesh_calc_poly_center(mp, ml, mvert, cent);
+ if (flag & MESH_FOREACH_USE_NORMAL) {
+ BKE_mesh_calc_poly_normal(mp, ml, mvert, no);
+ }
+ func(userData, i, cent, no);
+ }
+ }
}
-
/* Helpers based on above foreach loopers> */
typedef struct MappedVCosData {
- float (*vertexcos)[3];
- BLI_bitmap *vertex_visit;
+ float (*vertexcos)[3];
+ BLI_bitmap *vertex_visit;
} MappedVCosData;
-static void get_vertexcos__mapFunc(
- void *user_data, int index, const float co[3],
- const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
+static void get_vertexcos__mapFunc(void *user_data,
+ int index,
+ const float co[3],
+ const float UNUSED(no_f[3]),
+ const short UNUSED(no_s[3]))
{
- MappedVCosData *mapped_vcos_data = (MappedVCosData *)user_data;
-
- if (BLI_BITMAP_TEST(mapped_vcos_data->vertex_visit, index) == 0) {
- /* We need coord from prototype vertex, not from copies,
- * we assume they stored in the beginning of vertex array stored in evaluated mesh
- * (mirror modifier for eg does this). */
- copy_v3_v3(mapped_vcos_data->vertexcos[index], co);
- BLI_BITMAP_ENABLE(mapped_vcos_data->vertex_visit, index);
- }
+ MappedVCosData *mapped_vcos_data = (MappedVCosData *)user_data;
+
+ if (BLI_BITMAP_TEST(mapped_vcos_data->vertex_visit, index) == 0) {
+ /* We need coord from prototype vertex, not from copies,
+ * we assume they stored in the beginning of vertex array stored in evaluated mesh
+ * (mirror modifier for eg does this). */
+ copy_v3_v3(mapped_vcos_data->vertexcos[index], co);
+ BLI_BITMAP_ENABLE(mapped_vcos_data->vertex_visit, index);
+ }
}
void BKE_mesh_foreach_mapped_vert_coords_get(Mesh *me_eval, float (*r_cos)[3], const int totcos)
{
- MappedVCosData user_data;
- memset(r_cos, 0, sizeof(*r_cos) * totcos);
- user_data.vertexcos = r_cos;
- user_data.vertex_visit = BLI_BITMAP_NEW(totcos, __func__);
- BKE_mesh_foreach_mapped_vert(me_eval, get_vertexcos__mapFunc, &user_data, MESH_FOREACH_NOP);
- MEM_freeN(user_data.vertex_visit);
+ MappedVCosData user_data;
+ memset(r_cos, 0, sizeof(*r_cos) * totcos);
+ user_data.vertexcos = r_cos;
+ user_data.vertex_visit = BLI_BITMAP_NEW(totcos, __func__);
+ BKE_mesh_foreach_mapped_vert(me_eval, get_vertexcos__mapFunc, &user_data, MESH_FOREACH_NOP);
+ MEM_freeN(user_data.vertex_visit);
}
diff --git a/source/blender/blenkernel/intern/mesh_mapping.c b/source/blender/blenkernel/intern/mesh_mapping.c
index 312af598d98..811b78411a3 100644
--- a/source/blender/blenkernel/intern/mesh_mapping.c
+++ b/source/blender/blenkernel/intern/mesh_mapping.c
@@ -37,149 +37,153 @@
#include "BLI_strict_flags.h"
-
/* -------------------------------------------------------------------- */
/** \name Mesh Connectivity Mapping
* \{ */
-
/* ngon version wip, based on BM_uv_vert_map_create */
/* this replaces the non bmesh function (in trunk) which takes MTFace's, if we ever need it back we could
* but for now this replaces it because its unused. */
-UvVertMap *BKE_mesh_uv_vert_map_create(
- const MPoly *mpoly, const MLoop *mloop, const MLoopUV *mloopuv,
- unsigned int totpoly, unsigned int totvert,
- const float limit[2], const bool selected, const bool use_winding)
+UvVertMap *BKE_mesh_uv_vert_map_create(const MPoly *mpoly,
+ const MLoop *mloop,
+ const MLoopUV *mloopuv,
+ unsigned int totpoly,
+ unsigned int totvert,
+ const float limit[2],
+ const bool selected,
+ const bool use_winding)
{
- UvVertMap *vmap;
- UvMapVert *buf;
- const MPoly *mp;
- unsigned int a;
- int i, totuv, nverts;
-
- bool *winding = NULL;
- BLI_buffer_declare_static(vec2f, tf_uv_buf, BLI_BUFFER_NOP, 32);
-
- totuv = 0;
-
- /* generate UvMapVert array */
- mp = mpoly;
- for (a = 0; a < totpoly; a++, mp++)
- if (!selected || (!(mp->flag & ME_HIDE) && (mp->flag & ME_FACE_SEL)))
- totuv += mp->totloop;
-
- if (totuv == 0)
- return NULL;
-
- vmap = (UvVertMap *)MEM_callocN(sizeof(*vmap), "UvVertMap");
- buf = vmap->buf = (UvMapVert *)MEM_callocN(sizeof(*vmap->buf) * (size_t)totuv, "UvMapVert");
- vmap->vert = (UvMapVert **)MEM_callocN(sizeof(*vmap->vert) * totvert, "UvMapVert*");
- if (use_winding) {
- winding = MEM_callocN(sizeof(*winding) * totpoly, "winding");
- }
-
- if (!vmap->vert || !vmap->buf) {
- BKE_mesh_uv_vert_map_free(vmap);
- return NULL;
- }
-
- mp = mpoly;
- for (a = 0; a < totpoly; a++, mp++) {
- if (!selected || (!(mp->flag & ME_HIDE) && (mp->flag & ME_FACE_SEL))) {
- float (*tf_uv)[2] = NULL;
-
- if (use_winding) {
- tf_uv = (float (*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, (size_t)mp->totloop);
- }
-
- nverts = mp->totloop;
-
- for (i = 0; i < nverts; i++) {
- buf->loop_of_poly_index = (unsigned short)i;
- buf->poly_index = a;
- buf->separate = 0;
- buf->next = vmap->vert[mloop[mp->loopstart + i].v];
- vmap->vert[mloop[mp->loopstart + i].v] = buf;
-
- if (use_winding) {
- copy_v2_v2(tf_uv[i], mloopuv[mpoly[a].loopstart + i].uv);
- }
-
- buf++;
- }
-
- if (use_winding) {
- winding[a] = cross_poly_v2(tf_uv, (unsigned int)nverts) > 0;
- }
- }
- }
-
- /* sort individual uvs for each vert */
- for (a = 0; a < totvert; a++) {
- UvMapVert *newvlist = NULL, *vlist = vmap->vert[a];
- UvMapVert *iterv, *v, *lastv, *next;
- const float *uv, *uv2;
- float uvdiff[2];
-
- while (vlist) {
- v = vlist;
- vlist = vlist->next;
- v->next = newvlist;
- newvlist = v;
-
- uv = mloopuv[mpoly[v->poly_index].loopstart + v->loop_of_poly_index].uv;
- lastv = NULL;
- iterv = vlist;
-
- while (iterv) {
- next = iterv->next;
-
- uv2 = mloopuv[mpoly[iterv->poly_index].loopstart + iterv->loop_of_poly_index].uv;
- sub_v2_v2v2(uvdiff, uv2, uv);
-
-
- if (fabsf(uv[0] - uv2[0]) < limit[0] && fabsf(uv[1] - uv2[1]) < limit[1] &&
- (!use_winding || winding[iterv->poly_index] == winding[v->poly_index]))
- {
- if (lastv) lastv->next = next;
- else vlist = next;
- iterv->next = newvlist;
- newvlist = iterv;
- }
- else
- lastv = iterv;
-
- iterv = next;
- }
-
- newvlist->separate = 1;
- }
-
- vmap->vert[a] = newvlist;
- }
-
- if (use_winding) {
- MEM_freeN(winding);
- }
-
- BLI_buffer_free(&tf_uv_buf);
-
- return vmap;
+ UvVertMap *vmap;
+ UvMapVert *buf;
+ const MPoly *mp;
+ unsigned int a;
+ int i, totuv, nverts;
+
+ bool *winding = NULL;
+ BLI_buffer_declare_static(vec2f, tf_uv_buf, BLI_BUFFER_NOP, 32);
+
+ totuv = 0;
+
+ /* generate UvMapVert array */
+ mp = mpoly;
+ for (a = 0; a < totpoly; a++, mp++)
+ if (!selected || (!(mp->flag & ME_HIDE) && (mp->flag & ME_FACE_SEL)))
+ totuv += mp->totloop;
+
+ if (totuv == 0)
+ return NULL;
+
+ vmap = (UvVertMap *)MEM_callocN(sizeof(*vmap), "UvVertMap");
+ buf = vmap->buf = (UvMapVert *)MEM_callocN(sizeof(*vmap->buf) * (size_t)totuv, "UvMapVert");
+ vmap->vert = (UvMapVert **)MEM_callocN(sizeof(*vmap->vert) * totvert, "UvMapVert*");
+ if (use_winding) {
+ winding = MEM_callocN(sizeof(*winding) * totpoly, "winding");
+ }
+
+ if (!vmap->vert || !vmap->buf) {
+ BKE_mesh_uv_vert_map_free(vmap);
+ return NULL;
+ }
+
+ mp = mpoly;
+ for (a = 0; a < totpoly; a++, mp++) {
+ if (!selected || (!(mp->flag & ME_HIDE) && (mp->flag & ME_FACE_SEL))) {
+ float(*tf_uv)[2] = NULL;
+
+ if (use_winding) {
+ tf_uv = (float(*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, (size_t)mp->totloop);
+ }
+
+ nverts = mp->totloop;
+
+ for (i = 0; i < nverts; i++) {
+ buf->loop_of_poly_index = (unsigned short)i;
+ buf->poly_index = a;
+ buf->separate = 0;
+ buf->next = vmap->vert[mloop[mp->loopstart + i].v];
+ vmap->vert[mloop[mp->loopstart + i].v] = buf;
+
+ if (use_winding) {
+ copy_v2_v2(tf_uv[i], mloopuv[mpoly[a].loopstart + i].uv);
+ }
+
+ buf++;
+ }
+
+ if (use_winding) {
+ winding[a] = cross_poly_v2(tf_uv, (unsigned int)nverts) > 0;
+ }
+ }
+ }
+
+ /* sort individual uvs for each vert */
+ for (a = 0; a < totvert; a++) {
+ UvMapVert *newvlist = NULL, *vlist = vmap->vert[a];
+ UvMapVert *iterv, *v, *lastv, *next;
+ const float *uv, *uv2;
+ float uvdiff[2];
+
+ while (vlist) {
+ v = vlist;
+ vlist = vlist->next;
+ v->next = newvlist;
+ newvlist = v;
+
+ uv = mloopuv[mpoly[v->poly_index].loopstart + v->loop_of_poly_index].uv;
+ lastv = NULL;
+ iterv = vlist;
+
+ while (iterv) {
+ next = iterv->next;
+
+ uv2 = mloopuv[mpoly[iterv->poly_index].loopstart + iterv->loop_of_poly_index].uv;
+ sub_v2_v2v2(uvdiff, uv2, uv);
+
+ if (fabsf(uv[0] - uv2[0]) < limit[0] && fabsf(uv[1] - uv2[1]) < limit[1] &&
+ (!use_winding || winding[iterv->poly_index] == winding[v->poly_index])) {
+ if (lastv)
+ lastv->next = next;
+ else
+ vlist = next;
+ iterv->next = newvlist;
+ newvlist = iterv;
+ }
+ else
+ lastv = iterv;
+
+ iterv = next;
+ }
+
+ newvlist->separate = 1;
+ }
+
+ vmap->vert[a] = newvlist;
+ }
+
+ if (use_winding) {
+ MEM_freeN(winding);
+ }
+
+ BLI_buffer_free(&tf_uv_buf);
+
+ return vmap;
}
UvMapVert *BKE_mesh_uv_vert_map_get_vert(UvVertMap *vmap, unsigned int v)
{
- return vmap->vert[v];
+ return vmap->vert[v];
}
void BKE_mesh_uv_vert_map_free(UvVertMap *vmap)
{
- if (vmap) {
- if (vmap->vert) MEM_freeN(vmap->vert);
- if (vmap->buf) MEM_freeN(vmap->buf);
- MEM_freeN(vmap);
- }
+ if (vmap) {
+ if (vmap->vert)
+ MEM_freeN(vmap->vert);
+ if (vmap->buf)
+ MEM_freeN(vmap->buf);
+ MEM_freeN(vmap);
+ }
}
/**
@@ -189,117 +193,130 @@ void BKE_mesh_uv_vert_map_free(UvVertMap *vmap)
*
* Wrapped by #BKE_mesh_vert_poly_map_create & BKE_mesh_vert_loop_map_create
*/
-static void mesh_vert_poly_or_loop_map_create(
- MeshElemMap **r_map, int **r_mem,
- const MPoly *mpoly, const MLoop *mloop,
- int totvert, int totpoly, int totloop, const bool do_loops)
+static void mesh_vert_poly_or_loop_map_create(MeshElemMap **r_map,
+ int **r_mem,
+ const MPoly *mpoly,
+ const MLoop *mloop,
+ int totvert,
+ int totpoly,
+ int totloop,
+ const bool do_loops)
{
- MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totvert, __func__);
- int *indices, *index_iter;
- int i, j;
+ MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totvert, __func__);
+ int *indices, *index_iter;
+ int i, j;
- indices = index_iter = MEM_mallocN(sizeof(int) * (size_t)totloop, __func__);
+ indices = index_iter = MEM_mallocN(sizeof(int) * (size_t)totloop, __func__);
- /* Count number of polys for each vertex */
- for (i = 0; i < totpoly; i++) {
- const MPoly *p = &mpoly[i];
+ /* Count number of polys for each vertex */
+ for (i = 0; i < totpoly; i++) {
+ const MPoly *p = &mpoly[i];
- for (j = 0; j < p->totloop; j++)
- map[mloop[p->loopstart + j].v].count++;
- }
+ for (j = 0; j < p->totloop; j++)
+ map[mloop[p->loopstart + j].v].count++;
+ }
- /* Assign indices mem */
- for (i = 0; i < totvert; i++) {
- map[i].indices = index_iter;
- index_iter += map[i].count;
+ /* Assign indices mem */
+ for (i = 0; i < totvert; i++) {
+ map[i].indices = index_iter;
+ index_iter += map[i].count;
- /* Reset 'count' for use as index in last loop */
- map[i].count = 0;
- }
+ /* Reset 'count' for use as index in last loop */
+ map[i].count = 0;
+ }
- /* Find the users */
- for (i = 0; i < totpoly; i++) {
- const MPoly *p = &mpoly[i];
+ /* Find the users */
+ for (i = 0; i < totpoly; i++) {
+ const MPoly *p = &mpoly[i];
- for (j = 0; j < p->totloop; j++) {
- unsigned int v = mloop[p->loopstart + j].v;
+ for (j = 0; j < p->totloop; j++) {
+ unsigned int v = mloop[p->loopstart + j].v;
- map[v].indices[map[v].count] = do_loops ? p->loopstart + j : i;
- map[v].count++;
- }
- }
+ map[v].indices[map[v].count] = do_loops ? p->loopstart + j : i;
+ map[v].count++;
+ }
+ }
- *r_map = map;
- *r_mem = indices;
+ *r_map = map;
+ *r_mem = indices;
}
/**
* Generates a map where the key is the vertex and the value is a list of polys that use that vertex as a corner.
* The lists are allocated from one memory pool.
*/
-void BKE_mesh_vert_poly_map_create(
- MeshElemMap **r_map, int **r_mem,
- const MPoly *mpoly, const MLoop *mloop,
- int totvert, int totpoly, int totloop)
+void BKE_mesh_vert_poly_map_create(MeshElemMap **r_map,
+ int **r_mem,
+ const MPoly *mpoly,
+ const MLoop *mloop,
+ int totvert,
+ int totpoly,
+ int totloop)
{
- mesh_vert_poly_or_loop_map_create(r_map, r_mem, mpoly, mloop, totvert, totpoly, totloop, false);
+ mesh_vert_poly_or_loop_map_create(r_map, r_mem, mpoly, mloop, totvert, totpoly, totloop, false);
}
/**
* Generates a map where the key is the vertex and the value is a list of loops that use that vertex as a corner.
* The lists are allocated from one memory pool.
*/
-void BKE_mesh_vert_loop_map_create(
- MeshElemMap **r_map, int **r_mem,
- const MPoly *mpoly, const MLoop *mloop,
- int totvert, int totpoly, int totloop)
+void BKE_mesh_vert_loop_map_create(MeshElemMap **r_map,
+ int **r_mem,
+ const MPoly *mpoly,
+ const MLoop *mloop,
+ int totvert,
+ int totpoly,
+ int totloop)
{
- mesh_vert_poly_or_loop_map_create(r_map, r_mem, mpoly, mloop, totvert, totpoly, totloop, true);
+ mesh_vert_poly_or_loop_map_create(r_map, r_mem, mpoly, mloop, totvert, totpoly, totloop, true);
}
/**
* Generates a map where the key is the edge and the value is a list of looptris that use that edge.
* The lists are allocated from one memory pool.
*/
-void BKE_mesh_vert_looptri_map_create(
- MeshElemMap **r_map, int **r_mem,
- const MVert *UNUSED(mvert), const int totvert,
- const MLoopTri *mlooptri, const int totlooptri,
- const MLoop *mloop, const int UNUSED(totloop))
+void BKE_mesh_vert_looptri_map_create(MeshElemMap **r_map,
+ int **r_mem,
+ const MVert *UNUSED(mvert),
+ const int totvert,
+ const MLoopTri *mlooptri,
+ const int totlooptri,
+ const MLoop *mloop,
+ const int UNUSED(totloop))
{
- MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totvert, __func__);
- int *indices = MEM_mallocN(sizeof(int) * (size_t)totlooptri * 3, __func__);
- int *index_step;
- const MLoopTri *mlt;
- int i;
-
- /* count face users */
- for (i = 0, mlt = mlooptri; i < totlooptri; mlt++, i++) {
- for (int j = 3; j--;) {
- map[mloop[mlt->tri[j]].v].count++;
- }
- }
-
- /* create offsets */
- index_step = indices;
- for (i = 0; i < totvert; i++) {
- map[i].indices = index_step;
- index_step += map[i].count;
-
- /* re-count, using this as an index below */
- map[i].count = 0;
- }
-
- /* assign looptri-edge users */
- for (i = 0, mlt = mlooptri; i < totlooptri; mlt++, i++) {
- for (int j = 3; j--;) {
- MeshElemMap *map_ele = &map[mloop[mlt->tri[j]].v];
- map_ele->indices[map_ele->count++] = i;
- }
- }
-
- *r_map = map;
- *r_mem = indices;
+ MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totvert, __func__);
+ int *indices = MEM_mallocN(sizeof(int) * (size_t)totlooptri * 3, __func__);
+ int *index_step;
+ const MLoopTri *mlt;
+ int i;
+
+ /* count face users */
+ for (i = 0, mlt = mlooptri; i < totlooptri; mlt++, i++) {
+ for (int j = 3; j--;) {
+ map[mloop[mlt->tri[j]].v].count++;
+ }
+ }
+
+ /* create offsets */
+ index_step = indices;
+ for (i = 0; i < totvert; i++) {
+ map[i].indices = index_step;
+ index_step += map[i].count;
+
+ /* re-count, using this as an index below */
+ map[i].count = 0;
+ }
+
+ /* assign looptri-edge users */
+ for (i = 0, mlt = mlooptri; i < totlooptri; mlt++, i++) {
+ for (int j = 3; j--;) {
+ MeshElemMap *map_ele = &map[mloop[mlt->tri[j]].v];
+ map_ele->indices[map_ele->count++] = i;
+ }
+ }
+
+ *r_map = map;
+ *r_mem = indices;
}
/**
@@ -307,86 +324,84 @@ void BKE_mesh_vert_looptri_map_create(
* The lists are allocated from one memory pool.
*/
void BKE_mesh_vert_edge_map_create(
- MeshElemMap **r_map, int **r_mem,
- const MEdge *medge, int totvert, int totedge)
+ MeshElemMap **r_map, int **r_mem, const MEdge *medge, int totvert, int totedge)
{
- MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totvert, "vert-edge map");
- int *indices = MEM_mallocN(sizeof(int[2]) * (size_t)totedge, "vert-edge map mem");
- int *i_pt = indices;
+ MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totvert, "vert-edge map");
+ int *indices = MEM_mallocN(sizeof(int[2]) * (size_t)totedge, "vert-edge map mem");
+ int *i_pt = indices;
- int i;
+ int i;
- /* Count number of edges for each vertex */
- for (i = 0; i < totedge; i++) {
- map[medge[i].v1].count++;
- map[medge[i].v2].count++;
- }
+ /* Count number of edges for each vertex */
+ for (i = 0; i < totedge; i++) {
+ map[medge[i].v1].count++;
+ map[medge[i].v2].count++;
+ }
- /* Assign indices mem */
- for (i = 0; i < totvert; i++) {
- map[i].indices = i_pt;
- i_pt += map[i].count;
+ /* Assign indices mem */
+ for (i = 0; i < totvert; i++) {
+ map[i].indices = i_pt;
+ i_pt += map[i].count;
- /* Reset 'count' for use as index in last loop */
- map[i].count = 0;
- }
+ /* Reset 'count' for use as index in last loop */
+ map[i].count = 0;
+ }
- /* Find the users */
- for (i = 0; i < totedge; i++) {
- const unsigned int v[2] = {medge[i].v1, medge[i].v2};
+ /* Find the users */
+ for (i = 0; i < totedge; i++) {
+ const unsigned int v[2] = {medge[i].v1, medge[i].v2};
- map[v[0]].indices[map[v[0]].count] = i;
- map[v[1]].indices[map[v[1]].count] = i;
+ map[v[0]].indices[map[v[0]].count] = i;
+ map[v[1]].indices[map[v[1]].count] = i;
- map[v[0]].count++;
- map[v[1]].count++;
- }
+ map[v[0]].count++;
+ map[v[1]].count++;
+ }
- *r_map = map;
- *r_mem = indices;
+ *r_map = map;
+ *r_mem = indices;
}
/**
* A version of #BKE_mesh_vert_edge_map_create that references connected vertices directly (not their edges).
*/
void BKE_mesh_vert_edge_vert_map_create(
- MeshElemMap **r_map, int **r_mem,
- const MEdge *medge, int totvert, int totedge)
+ MeshElemMap **r_map, int **r_mem, const MEdge *medge, int totvert, int totedge)
{
- MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totvert, "vert-edge map");
- int *indices = MEM_mallocN(sizeof(int[2]) * (size_t)totedge, "vert-edge map mem");
- int *i_pt = indices;
+ MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totvert, "vert-edge map");
+ int *indices = MEM_mallocN(sizeof(int[2]) * (size_t)totedge, "vert-edge map mem");
+ int *i_pt = indices;
- int i;
+ int i;
- /* Count number of edges for each vertex */
- for (i = 0; i < totedge; i++) {
- map[medge[i].v1].count++;
- map[medge[i].v2].count++;
- }
+ /* Count number of edges for each vertex */
+ for (i = 0; i < totedge; i++) {
+ map[medge[i].v1].count++;
+ map[medge[i].v2].count++;
+ }
- /* Assign indices mem */
- for (i = 0; i < totvert; i++) {
- map[i].indices = i_pt;
- i_pt += map[i].count;
+ /* Assign indices mem */
+ for (i = 0; i < totvert; i++) {
+ map[i].indices = i_pt;
+ i_pt += map[i].count;
- /* Reset 'count' for use as index in last loop */
- map[i].count = 0;
- }
+ /* Reset 'count' for use as index in last loop */
+ map[i].count = 0;
+ }
- /* Find the users */
- for (i = 0; i < totedge; i++) {
- const unsigned int v[2] = {medge[i].v1, medge[i].v2};
+ /* Find the users */
+ for (i = 0; i < totedge; i++) {
+ const unsigned int v[2] = {medge[i].v1, medge[i].v2};
- map[v[0]].indices[map[v[0]].count] = (int)v[1];
- map[v[1]].indices[map[v[1]].count] = (int)v[0];
+ map[v[0]].indices[map[v[0]].count] = (int)v[1];
+ map[v[1]].indices[map[v[1]].count] = (int)v[0];
- map[v[0]].count++;
- map[v[1]].count++;
- }
+ map[v[0]].count++;
+ map[v[1]].count++;
+ }
- *r_map = map;
- *r_mem = indices;
+ *r_map = map;
+ *r_mem = indices;
}
/**
@@ -394,104 +409,109 @@ void BKE_mesh_vert_edge_vert_map_create(
* Loops indices of a same poly are contiguous and in winding order.
* The lists are allocated from one memory pool.
*/
-void BKE_mesh_edge_loop_map_create(
- MeshElemMap **r_map, int **r_mem,
- const MEdge *UNUSED(medge), const int totedge,
- const MPoly *mpoly, const int totpoly,
- const MLoop *mloop, const int totloop)
+void BKE_mesh_edge_loop_map_create(MeshElemMap **r_map,
+ int **r_mem,
+ const MEdge *UNUSED(medge),
+ const int totedge,
+ const MPoly *mpoly,
+ const int totpoly,
+ const MLoop *mloop,
+ const int totloop)
{
- MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totedge, "edge-poly map");
- int *indices = MEM_mallocN(sizeof(int) * (size_t)totloop * 2, "edge-poly map mem");
- int *index_step;
- const MPoly *mp;
- int i;
-
- /* count face users */
- for (i = 0, mp = mpoly; i < totpoly; mp++, i++) {
- const MLoop *ml;
- int j = mp->totloop;
- for (ml = &mloop[mp->loopstart]; j--; ml++) {
- map[ml->e].count += 2;
- }
- }
-
- /* create offsets */
- index_step = indices;
- for (i = 0; i < totedge; i++) {
- map[i].indices = index_step;
- index_step += map[i].count;
-
- /* re-count, using this as an index below */
- map[i].count = 0;
- }
-
- /* assign loop-edge users */
- for (i = 0, mp = mpoly; i < totpoly; mp++, i++) {
- const MLoop *ml;
- MeshElemMap *map_ele;
- const int max_loop = mp->loopstart + mp->totloop;
- int j = mp->loopstart;
- for (ml = &mloop[j]; j < max_loop; j++, ml++) {
- map_ele = &map[ml->e];
- map_ele->indices[map_ele->count++] = j;
- map_ele->indices[map_ele->count++] = j + 1;
- }
- /* last edge/loop of poly, must point back to first loop! */
- map_ele->indices[map_ele->count - 1] = mp->loopstart;
- }
-
- *r_map = map;
- *r_mem = indices;
+ MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totedge, "edge-poly map");
+ int *indices = MEM_mallocN(sizeof(int) * (size_t)totloop * 2, "edge-poly map mem");
+ int *index_step;
+ const MPoly *mp;
+ int i;
+
+ /* count face users */
+ for (i = 0, mp = mpoly; i < totpoly; mp++, i++) {
+ const MLoop *ml;
+ int j = mp->totloop;
+ for (ml = &mloop[mp->loopstart]; j--; ml++) {
+ map[ml->e].count += 2;
+ }
+ }
+
+ /* create offsets */
+ index_step = indices;
+ for (i = 0; i < totedge; i++) {
+ map[i].indices = index_step;
+ index_step += map[i].count;
+
+ /* re-count, using this as an index below */
+ map[i].count = 0;
+ }
+
+ /* assign loop-edge users */
+ for (i = 0, mp = mpoly; i < totpoly; mp++, i++) {
+ const MLoop *ml;
+ MeshElemMap *map_ele;
+ const int max_loop = mp->loopstart + mp->totloop;
+ int j = mp->loopstart;
+ for (ml = &mloop[j]; j < max_loop; j++, ml++) {
+ map_ele = &map[ml->e];
+ map_ele->indices[map_ele->count++] = j;
+ map_ele->indices[map_ele->count++] = j + 1;
+ }
+ /* last edge/loop of poly, must point back to first loop! */
+ map_ele->indices[map_ele->count - 1] = mp->loopstart;
+ }
+
+ *r_map = map;
+ *r_mem = indices;
}
/**
* Generates a map where the key is the edge and the value is a list of polygons that use that edge.
* The lists are allocated from one memory pool.
*/
-void BKE_mesh_edge_poly_map_create(
- MeshElemMap **r_map, int **r_mem,
- const MEdge *UNUSED(medge), const int totedge,
- const MPoly *mpoly, const int totpoly,
- const MLoop *mloop, const int totloop)
+void BKE_mesh_edge_poly_map_create(MeshElemMap **r_map,
+ int **r_mem,
+ const MEdge *UNUSED(medge),
+ const int totedge,
+ const MPoly *mpoly,
+ const int totpoly,
+ const MLoop *mloop,
+ const int totloop)
{
- MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totedge, "edge-poly map");
- int *indices = MEM_mallocN(sizeof(int) * (size_t)totloop, "edge-poly map mem");
- int *index_step;
- const MPoly *mp;
- int i;
-
- /* count face users */
- for (i = 0, mp = mpoly; i < totpoly; mp++, i++) {
- const MLoop *ml;
- int j = mp->totloop;
- for (ml = &mloop[mp->loopstart]; j--; ml++) {
- map[ml->e].count++;
- }
- }
-
- /* create offsets */
- index_step = indices;
- for (i = 0; i < totedge; i++) {
- map[i].indices = index_step;
- index_step += map[i].count;
-
- /* re-count, using this as an index below */
- map[i].count = 0;
-
- }
-
- /* assign poly-edge users */
- for (i = 0, mp = mpoly; i < totpoly; mp++, i++) {
- const MLoop *ml;
- int j = mp->totloop;
- for (ml = &mloop[mp->loopstart]; j--; ml++) {
- MeshElemMap *map_ele = &map[ml->e];
- map_ele->indices[map_ele->count++] = i;
- }
- }
-
- *r_map = map;
- *r_mem = indices;
+ MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totedge, "edge-poly map");
+ int *indices = MEM_mallocN(sizeof(int) * (size_t)totloop, "edge-poly map mem");
+ int *index_step;
+ const MPoly *mp;
+ int i;
+
+ /* count face users */
+ for (i = 0, mp = mpoly; i < totpoly; mp++, i++) {
+ const MLoop *ml;
+ int j = mp->totloop;
+ for (ml = &mloop[mp->loopstart]; j--; ml++) {
+ map[ml->e].count++;
+ }
+ }
+
+ /* create offsets */
+ index_step = indices;
+ for (i = 0; i < totedge; i++) {
+ map[i].indices = index_step;
+ index_step += map[i].count;
+
+ /* re-count, using this as an index below */
+ map[i].count = 0;
+ }
+
+ /* assign poly-edge users */
+ for (i = 0, mp = mpoly; i < totpoly; mp++, i++) {
+ const MLoop *ml;
+ int j = mp->totloop;
+ for (ml = &mloop[mp->loopstart]; j--; ml++) {
+ MeshElemMap *map_ele = &map[ml->e];
+ map_ele->indices[map_ele->count++] = i;
+ }
+ }
+
+ *r_map = map;
+ *r_mem = indices;
}
/**
@@ -508,80 +528,82 @@ void BKE_mesh_edge_poly_map_create(
* ``totfinal`` could be ``tottessface`` and ``final_origindex`` its ORIGINDEX customdata.
* This would allow an MPoly to loop over its tessfaces.
*/
-void BKE_mesh_origindex_map_create(
- MeshElemMap **r_map, int **r_mem,
- const int totsource,
- const int *final_origindex, const int totfinal)
+void BKE_mesh_origindex_map_create(MeshElemMap **r_map,
+ int **r_mem,
+ const int totsource,
+ const int *final_origindex,
+ const int totfinal)
{
- MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totsource, "poly-tessface map");
- int *indices = MEM_mallocN(sizeof(int) * (size_t)totfinal, "poly-tessface map mem");
- int *index_step;
- int i;
-
- /* count face users */
- for (i = 0; i < totfinal; i++) {
- if (final_origindex[i] != ORIGINDEX_NONE) {
- BLI_assert(final_origindex[i] < totsource);
- map[final_origindex[i]].count++;
- }
- }
-
- /* create offsets */
- index_step = indices;
- for (i = 0; i < totsource; i++) {
- map[i].indices = index_step;
- index_step += map[i].count;
-
- /* re-count, using this as an index below */
- map[i].count = 0;
- }
-
- /* assign poly-tessface users */
- for (i = 0; i < totfinal; i++) {
- if (final_origindex[i] != ORIGINDEX_NONE) {
- MeshElemMap *map_ele = &map[final_origindex[i]];
- map_ele->indices[map_ele->count++] = i;
- }
- }
-
- *r_map = map;
- *r_mem = indices;
+ MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totsource, "poly-tessface map");
+ int *indices = MEM_mallocN(sizeof(int) * (size_t)totfinal, "poly-tessface map mem");
+ int *index_step;
+ int i;
+
+ /* count face users */
+ for (i = 0; i < totfinal; i++) {
+ if (final_origindex[i] != ORIGINDEX_NONE) {
+ BLI_assert(final_origindex[i] < totsource);
+ map[final_origindex[i]].count++;
+ }
+ }
+
+ /* create offsets */
+ index_step = indices;
+ for (i = 0; i < totsource; i++) {
+ map[i].indices = index_step;
+ index_step += map[i].count;
+
+ /* re-count, using this as an index below */
+ map[i].count = 0;
+ }
+
+ /* assign poly-tessface users */
+ for (i = 0; i < totfinal; i++) {
+ if (final_origindex[i] != ORIGINDEX_NONE) {
+ MeshElemMap *map_ele = &map[final_origindex[i]];
+ map_ele->indices[map_ele->count++] = i;
+ }
+ }
+
+ *r_map = map;
+ *r_mem = indices;
}
/**
* A version of #BKE_mesh_origindex_map_create that takes a looptri array.
* Making a poly -> looptri map.
*/
-void BKE_mesh_origindex_map_create_looptri(
- MeshElemMap **r_map, int **r_mem,
- const MPoly *mpoly, const int mpoly_num,
- const MLoopTri *looptri, const int looptri_num)
+void BKE_mesh_origindex_map_create_looptri(MeshElemMap **r_map,
+ int **r_mem,
+ const MPoly *mpoly,
+ const int mpoly_num,
+ const MLoopTri *looptri,
+ const int looptri_num)
{
- MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)mpoly_num, "poly-tessface map");
- int *indices = MEM_mallocN(sizeof(int) * (size_t)looptri_num, "poly-tessface map mem");
- int *index_step;
- int i;
-
- /* create offsets */
- index_step = indices;
- for (i = 0; i < mpoly_num; i++) {
- map[i].indices = index_step;
- index_step += ME_POLY_TRI_TOT(&mpoly[i]);
- }
-
- /* assign poly-tessface users */
- for (i = 0; i < looptri_num; i++) {
- MeshElemMap *map_ele = &map[looptri[i].poly];
- map_ele->indices[map_ele->count++] = i;
- }
-
- *r_map = map;
- *r_mem = indices;
+ MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)mpoly_num, "poly-tessface map");
+ int *indices = MEM_mallocN(sizeof(int) * (size_t)looptri_num, "poly-tessface map mem");
+ int *index_step;
+ int i;
+
+ /* create offsets */
+ index_step = indices;
+ for (i = 0; i < mpoly_num; i++) {
+ map[i].indices = index_step;
+ index_step += ME_POLY_TRI_TOT(&mpoly[i]);
+ }
+
+ /* assign poly-tessface users */
+ for (i = 0; i < looptri_num; i++) {
+ MeshElemMap *map_ele = &map[looptri[i].poly];
+ map_ele->indices[map_ele->count++] = i;
+ }
+
+ *r_map = map;
+ *r_mem = indices;
}
/** \} */
-
/* -------------------------------------------------------------------- */
/** \name Mesh loops/poly islands.
* Used currently for UVs and 'smooth groups'.
@@ -590,192 +612,208 @@ void BKE_mesh_origindex_map_create_looptri(
/**
* Callback deciding whether the given poly/loop/edge define an island boundary or not.
*/
-typedef bool (*MeshRemap_CheckIslandBoundary)(
- const struct MPoly *mpoly, const struct MLoop *mloop, const struct MEdge *medge,
- const int nbr_egde_users, void *user_data);
-
-static void poly_edge_loop_islands_calc(
- const MEdge *medge, const int totedge, const MPoly *mpoly, const int totpoly,
- const MLoop *mloop, const int totloop, MeshElemMap *edge_poly_map,
- const bool use_bitflags, MeshRemap_CheckIslandBoundary edge_boundary_check, void *edge_boundary_check_data,
- int **r_poly_groups, int *r_totgroup, BLI_bitmap **r_edge_borders, int *r_totedgeborder)
+typedef bool (*MeshRemap_CheckIslandBoundary)(const struct MPoly *mpoly,
+ const struct MLoop *mloop,
+ const struct MEdge *medge,
+ const int nbr_egde_users,
+ void *user_data);
+
+static void poly_edge_loop_islands_calc(const MEdge *medge,
+ const int totedge,
+ const MPoly *mpoly,
+ const int totpoly,
+ const MLoop *mloop,
+ const int totloop,
+ MeshElemMap *edge_poly_map,
+ const bool use_bitflags,
+ MeshRemap_CheckIslandBoundary edge_boundary_check,
+ void *edge_boundary_check_data,
+ int **r_poly_groups,
+ int *r_totgroup,
+ BLI_bitmap **r_edge_borders,
+ int *r_totedgeborder)
{
- int *poly_groups;
- int *poly_stack;
-
- BLI_bitmap *edge_borders = NULL;
- int num_edgeborders = 0;
-
- int poly_prev = 0;
- const int temp_poly_group_id = 3; /* Placeholder value. */
- const int poly_group_id_overflowed = 5; /* Group we could not find any available bit, will be reset to 0 at end */
- int tot_group = 0;
- bool group_id_overflow = false;
-
- /* map vars */
- int *edge_poly_mem = NULL;
-
- if (totpoly == 0) {
- *r_totgroup = 0;
- *r_poly_groups = NULL;
- if (r_edge_borders) {
- *r_edge_borders = NULL;
- *r_totedgeborder = 0;
- }
- return;
- }
-
- if (r_edge_borders) {
- edge_borders = BLI_BITMAP_NEW(totedge, __func__);
- *r_totedgeborder = 0;
- }
-
- if (!edge_poly_map) {
- BKE_mesh_edge_poly_map_create(
- &edge_poly_map, &edge_poly_mem,
- medge, totedge, mpoly, totpoly, mloop, totloop);
- }
-
- poly_groups = MEM_callocN(sizeof(int) * (size_t)totpoly, __func__);
- poly_stack = MEM_mallocN(sizeof(int) * (size_t)totpoly, __func__);
-
- while (true) {
- int poly;
- int bit_poly_group_mask = 0;
- int poly_group_id;
- int ps_curr_idx = 0, ps_end_idx = 0; /* stack indices */
-
- for (poly = poly_prev; poly < totpoly; poly++) {
- if (poly_groups[poly] == 0) {
- break;
- }
- }
-
- if (poly == totpoly) {
- /* all done */
- break;
- }
-
- poly_group_id = use_bitflags ? temp_poly_group_id : ++tot_group;
-
- /* start searching from here next time */
- poly_prev = poly + 1;
-
- poly_groups[poly] = poly_group_id;
- poly_stack[ps_end_idx++] = poly;
-
- while (ps_curr_idx != ps_end_idx) {
- const MPoly *mp;
- const MLoop *ml;
- int j;
-
- poly = poly_stack[ps_curr_idx++];
- BLI_assert(poly_groups[poly] == poly_group_id);
-
- mp = &mpoly[poly];
- for (ml = &mloop[mp->loopstart], j = mp->totloop; j--; ml++) {
- /* loop over poly users */
- const int me_idx = (int)ml->e;
- const MEdge *me = &medge[me_idx];
- const MeshElemMap *map_ele = &edge_poly_map[me_idx];
- const int *p = map_ele->indices;
- int i = map_ele->count;
- if (!edge_boundary_check(mp, ml, me, i, edge_boundary_check_data)) {
- for (; i--; p++) {
- /* if we meet other non initialized its a bug */
- BLI_assert(ELEM(poly_groups[*p], 0, poly_group_id));
-
- if (poly_groups[*p] == 0) {
- poly_groups[*p] = poly_group_id;
- poly_stack[ps_end_idx++] = *p;
- }
- }
- }
- else {
- if (edge_borders && !BLI_BITMAP_TEST(edge_borders, me_idx)) {
- BLI_BITMAP_ENABLE(edge_borders, me_idx);
- num_edgeborders++;
- }
- if (use_bitflags) {
- /* Find contiguous smooth groups already assigned, these are the values we can't reuse! */
- for (; i--; p++) {
- int bit = poly_groups[*p];
- if (!ELEM(bit, 0, poly_group_id, poly_group_id_overflowed) &&
- !(bit_poly_group_mask & bit))
- {
- bit_poly_group_mask |= bit;
- }
- }
- }
- }
- }
- }
- /* And now, we have all our poly from current group in poly_stack (from 0 to (ps_end_idx - 1)), as well as
- * all smoothgroups bits we can't use in bit_poly_group_mask.
- */
- if (use_bitflags) {
- int i, *p, gid_bit = 0;
- poly_group_id = 1;
-
- /* Find first bit available! */
- for (; (poly_group_id & bit_poly_group_mask) && (gid_bit < 32); gid_bit++) {
- poly_group_id <<= 1; /* will 'overflow' on last possible iteration. */
- }
- if (UNLIKELY(gid_bit > 31)) {
- /* All bits used in contiguous smooth groups, we can't do much!
- * Note: this is *very* unlikely - theoretically, four groups are enough, I don't think we can reach
- * this goal with such a simple algo, but I don't think either we'll never need all 32 groups!
- */
- printf("Warning, could not find an available id for current smooth group, faces will me marked "
- "as out of any smooth group...\n");
- poly_group_id = poly_group_id_overflowed; /* Can't use 0, will have to set them to this value later. */
- group_id_overflow = true;
- }
- if (gid_bit > tot_group) {
- tot_group = gid_bit;
- }
- /* And assign the final smooth group id to that poly group! */
- for (i = ps_end_idx, p = poly_stack; i--; p++) {
- poly_groups[*p] = poly_group_id;
- }
- }
- }
-
- if (use_bitflags) {
- /* used bits are zero-based. */
- tot_group++;
- }
-
- if (UNLIKELY(group_id_overflow)) {
- int i = totpoly, *gid = poly_groups;
- for (; i--; gid++) {
- if (*gid == poly_group_id_overflowed) {
- *gid = 0;
- }
- }
- /* Using 0 as group id adds one more group! */
- tot_group++;
- }
-
- if (edge_poly_mem) {
- MEM_freeN(edge_poly_map);
- MEM_freeN(edge_poly_mem);
- }
- MEM_freeN(poly_stack);
-
- *r_totgroup = tot_group;
- *r_poly_groups = poly_groups;
- if (r_edge_borders) {
- *r_edge_borders = edge_borders;
- *r_totedgeborder = num_edgeborders;
- }
+ int *poly_groups;
+ int *poly_stack;
+
+ BLI_bitmap *edge_borders = NULL;
+ int num_edgeborders = 0;
+
+ int poly_prev = 0;
+ const int temp_poly_group_id = 3; /* Placeholder value. */
+ const int poly_group_id_overflowed =
+ 5; /* Group we could not find any available bit, will be reset to 0 at end */
+ int tot_group = 0;
+ bool group_id_overflow = false;
+
+ /* map vars */
+ int *edge_poly_mem = NULL;
+
+ if (totpoly == 0) {
+ *r_totgroup = 0;
+ *r_poly_groups = NULL;
+ if (r_edge_borders) {
+ *r_edge_borders = NULL;
+ *r_totedgeborder = 0;
+ }
+ return;
+ }
+
+ if (r_edge_borders) {
+ edge_borders = BLI_BITMAP_NEW(totedge, __func__);
+ *r_totedgeborder = 0;
+ }
+
+ if (!edge_poly_map) {
+ BKE_mesh_edge_poly_map_create(
+ &edge_poly_map, &edge_poly_mem, medge, totedge, mpoly, totpoly, mloop, totloop);
+ }
+
+ poly_groups = MEM_callocN(sizeof(int) * (size_t)totpoly, __func__);
+ poly_stack = MEM_mallocN(sizeof(int) * (size_t)totpoly, __func__);
+
+ while (true) {
+ int poly;
+ int bit_poly_group_mask = 0;
+ int poly_group_id;
+ int ps_curr_idx = 0, ps_end_idx = 0; /* stack indices */
+
+ for (poly = poly_prev; poly < totpoly; poly++) {
+ if (poly_groups[poly] == 0) {
+ break;
+ }
+ }
+
+ if (poly == totpoly) {
+ /* all done */
+ break;
+ }
+
+ poly_group_id = use_bitflags ? temp_poly_group_id : ++tot_group;
+
+ /* start searching from here next time */
+ poly_prev = poly + 1;
+
+ poly_groups[poly] = poly_group_id;
+ poly_stack[ps_end_idx++] = poly;
+
+ while (ps_curr_idx != ps_end_idx) {
+ const MPoly *mp;
+ const MLoop *ml;
+ int j;
+
+ poly = poly_stack[ps_curr_idx++];
+ BLI_assert(poly_groups[poly] == poly_group_id);
+
+ mp = &mpoly[poly];
+ for (ml = &mloop[mp->loopstart], j = mp->totloop; j--; ml++) {
+ /* loop over poly users */
+ const int me_idx = (int)ml->e;
+ const MEdge *me = &medge[me_idx];
+ const MeshElemMap *map_ele = &edge_poly_map[me_idx];
+ const int *p = map_ele->indices;
+ int i = map_ele->count;
+ if (!edge_boundary_check(mp, ml, me, i, edge_boundary_check_data)) {
+ for (; i--; p++) {
+ /* if we meet other non initialized its a bug */
+ BLI_assert(ELEM(poly_groups[*p], 0, poly_group_id));
+
+ if (poly_groups[*p] == 0) {
+ poly_groups[*p] = poly_group_id;
+ poly_stack[ps_end_idx++] = *p;
+ }
+ }
+ }
+ else {
+ if (edge_borders && !BLI_BITMAP_TEST(edge_borders, me_idx)) {
+ BLI_BITMAP_ENABLE(edge_borders, me_idx);
+ num_edgeborders++;
+ }
+ if (use_bitflags) {
+ /* Find contiguous smooth groups already assigned, these are the values we can't reuse! */
+ for (; i--; p++) {
+ int bit = poly_groups[*p];
+ if (!ELEM(bit, 0, poly_group_id, poly_group_id_overflowed) &&
+ !(bit_poly_group_mask & bit)) {
+ bit_poly_group_mask |= bit;
+ }
+ }
+ }
+ }
+ }
+ }
+ /* And now, we have all our poly from current group in poly_stack (from 0 to (ps_end_idx - 1)), as well as
+ * all smoothgroups bits we can't use in bit_poly_group_mask.
+ */
+ if (use_bitflags) {
+ int i, *p, gid_bit = 0;
+ poly_group_id = 1;
+
+ /* Find first bit available! */
+ for (; (poly_group_id & bit_poly_group_mask) && (gid_bit < 32); gid_bit++) {
+ poly_group_id <<= 1; /* will 'overflow' on last possible iteration. */
+ }
+ if (UNLIKELY(gid_bit > 31)) {
+ /* All bits used in contiguous smooth groups, we can't do much!
+ * Note: this is *very* unlikely - theoretically, four groups are enough, I don't think we can reach
+ * this goal with such a simple algo, but I don't think either we'll never need all 32 groups!
+ */
+ printf(
+ "Warning, could not find an available id for current smooth group, faces will me "
+ "marked "
+ "as out of any smooth group...\n");
+ poly_group_id =
+ poly_group_id_overflowed; /* Can't use 0, will have to set them to this value later. */
+ group_id_overflow = true;
+ }
+ if (gid_bit > tot_group) {
+ tot_group = gid_bit;
+ }
+ /* And assign the final smooth group id to that poly group! */
+ for (i = ps_end_idx, p = poly_stack; i--; p++) {
+ poly_groups[*p] = poly_group_id;
+ }
+ }
+ }
+
+ if (use_bitflags) {
+ /* used bits are zero-based. */
+ tot_group++;
+ }
+
+ if (UNLIKELY(group_id_overflow)) {
+ int i = totpoly, *gid = poly_groups;
+ for (; i--; gid++) {
+ if (*gid == poly_group_id_overflowed) {
+ *gid = 0;
+ }
+ }
+ /* Using 0 as group id adds one more group! */
+ tot_group++;
+ }
+
+ if (edge_poly_mem) {
+ MEM_freeN(edge_poly_map);
+ MEM_freeN(edge_poly_mem);
+ }
+ MEM_freeN(poly_stack);
+
+ *r_totgroup = tot_group;
+ *r_poly_groups = poly_groups;
+ if (r_edge_borders) {
+ *r_edge_borders = edge_borders;
+ *r_totedgeborder = num_edgeborders;
+ }
}
-static bool poly_is_island_boundary_smooth_cb(
- const MPoly *mp, const MLoop *UNUSED(ml), const MEdge *me, const int nbr_egde_users, void *UNUSED(user_data))
+static bool poly_is_island_boundary_smooth_cb(const MPoly *mp,
+ const MLoop *UNUSED(ml),
+ const MEdge *me,
+ const int nbr_egde_users,
+ void *UNUSED(user_data))
{
- /* Edge is sharp if its poly is sharp, or edge itself is sharp, or edge is not used by exactly two polygons. */
- return (!(mp->flag & ME_SMOOTH) || (me->flag & ME_SHARP) || (nbr_egde_users != 2));
+ /* Edge is sharp if its poly is sharp, or edge itself is sharp, or edge is not used by exactly two polygons. */
+ return (!(mp->flag & ME_SMOOTH) || (me->flag & ME_SHARP) || (nbr_egde_users != 2));
}
/**
@@ -786,116 +824,143 @@ static bool poly_is_island_boundary_smooth_cb(
* (0 being used as 'invalid' flag).
* Note it's callers's responsibility to MEM_freeN returned array.
*/
-int *BKE_mesh_calc_smoothgroups(
- const MEdge *medge, const int totedge,
- const MPoly *mpoly, const int totpoly,
- const MLoop *mloop, const int totloop,
- int *r_totgroup, const bool use_bitflags)
+int *BKE_mesh_calc_smoothgroups(const MEdge *medge,
+ const int totedge,
+ const MPoly *mpoly,
+ const int totpoly,
+ const MLoop *mloop,
+ const int totloop,
+ int *r_totgroup,
+ const bool use_bitflags)
{
- int *poly_groups = NULL;
-
- poly_edge_loop_islands_calc(
- medge, totedge, mpoly, totpoly, mloop, totloop, NULL, use_bitflags,
- poly_is_island_boundary_smooth_cb, NULL, &poly_groups, r_totgroup, NULL, NULL);
-
- return poly_groups;
+ int *poly_groups = NULL;
+
+ poly_edge_loop_islands_calc(medge,
+ totedge,
+ mpoly,
+ totpoly,
+ mloop,
+ totloop,
+ NULL,
+ use_bitflags,
+ poly_is_island_boundary_smooth_cb,
+ NULL,
+ &poly_groups,
+ r_totgroup,
+ NULL,
+ NULL);
+
+ return poly_groups;
}
#define MISLAND_DEFAULT_BUFSIZE 64
-void BKE_mesh_loop_islands_init(
- MeshIslandStore *island_store,
- const short item_type, const int items_num, const short island_type, const short innercut_type)
+void BKE_mesh_loop_islands_init(MeshIslandStore *island_store,
+ const short item_type,
+ const int items_num,
+ const short island_type,
+ const short innercut_type)
{
- MemArena *mem = island_store->mem;
-
- if (mem == NULL) {
- mem = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
- island_store->mem = mem;
- }
- /* else memarena should be cleared */
-
- BLI_assert(ELEM(item_type, MISLAND_TYPE_VERT, MISLAND_TYPE_EDGE, MISLAND_TYPE_POLY, MISLAND_TYPE_LOOP));
- BLI_assert(ELEM(island_type, MISLAND_TYPE_VERT, MISLAND_TYPE_EDGE, MISLAND_TYPE_POLY, MISLAND_TYPE_LOOP));
-
- island_store->item_type = item_type;
- island_store->items_to_islands_num = items_num;
- island_store->items_to_islands = BLI_memarena_alloc(mem, sizeof(*island_store->items_to_islands) * (size_t)items_num);
-
- island_store->island_type = island_type;
- island_store->islands_num_alloc = MISLAND_DEFAULT_BUFSIZE;
- island_store->islands = BLI_memarena_alloc(mem, sizeof(*island_store->islands) * island_store->islands_num_alloc);
-
- island_store->innercut_type = innercut_type;
- island_store->innercuts = BLI_memarena_alloc(mem, sizeof(*island_store->innercuts) * island_store->islands_num_alloc);
+ MemArena *mem = island_store->mem;
+
+ if (mem == NULL) {
+ mem = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+ island_store->mem = mem;
+ }
+ /* else memarena should be cleared */
+
+ BLI_assert(
+ ELEM(item_type, MISLAND_TYPE_VERT, MISLAND_TYPE_EDGE, MISLAND_TYPE_POLY, MISLAND_TYPE_LOOP));
+ BLI_assert(ELEM(
+ island_type, MISLAND_TYPE_VERT, MISLAND_TYPE_EDGE, MISLAND_TYPE_POLY, MISLAND_TYPE_LOOP));
+
+ island_store->item_type = item_type;
+ island_store->items_to_islands_num = items_num;
+ island_store->items_to_islands = BLI_memarena_alloc(
+ mem, sizeof(*island_store->items_to_islands) * (size_t)items_num);
+
+ island_store->island_type = island_type;
+ island_store->islands_num_alloc = MISLAND_DEFAULT_BUFSIZE;
+ island_store->islands = BLI_memarena_alloc(
+ mem, sizeof(*island_store->islands) * island_store->islands_num_alloc);
+
+ island_store->innercut_type = innercut_type;
+ island_store->innercuts = BLI_memarena_alloc(
+ mem, sizeof(*island_store->innercuts) * island_store->islands_num_alloc);
}
void BKE_mesh_loop_islands_clear(MeshIslandStore *island_store)
{
- island_store->item_type = MISLAND_TYPE_NONE;
- island_store->items_to_islands_num = 0;
- island_store->items_to_islands = NULL;
+ island_store->item_type = MISLAND_TYPE_NONE;
+ island_store->items_to_islands_num = 0;
+ island_store->items_to_islands = NULL;
- island_store->island_type = MISLAND_TYPE_NONE;
- island_store->islands_num = 0;
- island_store->islands = NULL;
+ island_store->island_type = MISLAND_TYPE_NONE;
+ island_store->islands_num = 0;
+ island_store->islands = NULL;
- island_store->innercut_type = MISLAND_TYPE_NONE;
- island_store->innercuts = NULL;
+ island_store->innercut_type = MISLAND_TYPE_NONE;
+ island_store->innercuts = NULL;
- if (island_store->mem) {
- BLI_memarena_clear(island_store->mem);
- }
+ if (island_store->mem) {
+ BLI_memarena_clear(island_store->mem);
+ }
- island_store->islands_num_alloc = 0;
+ island_store->islands_num_alloc = 0;
}
void BKE_mesh_loop_islands_free(MeshIslandStore *island_store)
{
- if (island_store->mem) {
- BLI_memarena_free(island_store->mem);
- island_store->mem = NULL;
- }
+ if (island_store->mem) {
+ BLI_memarena_free(island_store->mem);
+ island_store->mem = NULL;
+ }
}
-void BKE_mesh_loop_islands_add(
- MeshIslandStore *island_store, const int item_num, int *items_indices,
- const int num_island_items, int *island_item_indices,
- const int num_innercut_items, int *innercut_item_indices)
+void BKE_mesh_loop_islands_add(MeshIslandStore *island_store,
+ const int item_num,
+ int *items_indices,
+ const int num_island_items,
+ int *island_item_indices,
+ const int num_innercut_items,
+ int *innercut_item_indices)
{
- MemArena *mem = island_store->mem;
-
- MeshElemMap *isld, *innrcut;
- const int curr_island_idx = island_store->islands_num++;
- const size_t curr_num_islands = (size_t)island_store->islands_num;
- int i = item_num;
-
- while (i--) {
- island_store->items_to_islands[items_indices[i]] = curr_island_idx;
- }
-
- if (UNLIKELY(curr_num_islands > island_store->islands_num_alloc)) {
- MeshElemMap **islds, **innrcuts;
-
- island_store->islands_num_alloc *= 2;
- islds = BLI_memarena_alloc(mem, sizeof(*islds) * island_store->islands_num_alloc);
- memcpy(islds, island_store->islands, sizeof(*islds) * (curr_num_islands - 1));
- island_store->islands = islds;
-
- innrcuts = BLI_memarena_alloc(mem, sizeof(*innrcuts) * island_store->islands_num_alloc);
- memcpy(innrcuts, island_store->innercuts, sizeof(*innrcuts) * (curr_num_islands - 1));
- island_store->innercuts = innrcuts;
- }
-
- island_store->islands[curr_island_idx] = isld = BLI_memarena_alloc(mem, sizeof(*isld));
- isld->count = num_island_items;
- isld->indices = BLI_memarena_alloc(mem, sizeof(*isld->indices) * (size_t)num_island_items);
- memcpy(isld->indices, island_item_indices, sizeof(*isld->indices) * (size_t)num_island_items);
-
- island_store->innercuts[curr_island_idx] = innrcut = BLI_memarena_alloc(mem, sizeof(*innrcut));
- innrcut->count = num_innercut_items;
- innrcut->indices = BLI_memarena_alloc(mem, sizeof(*innrcut->indices) * (size_t)num_innercut_items);
- memcpy(innrcut->indices, innercut_item_indices, sizeof(*innrcut->indices) * (size_t)num_innercut_items);
+ MemArena *mem = island_store->mem;
+
+ MeshElemMap *isld, *innrcut;
+ const int curr_island_idx = island_store->islands_num++;
+ const size_t curr_num_islands = (size_t)island_store->islands_num;
+ int i = item_num;
+
+ while (i--) {
+ island_store->items_to_islands[items_indices[i]] = curr_island_idx;
+ }
+
+ if (UNLIKELY(curr_num_islands > island_store->islands_num_alloc)) {
+ MeshElemMap **islds, **innrcuts;
+
+ island_store->islands_num_alloc *= 2;
+ islds = BLI_memarena_alloc(mem, sizeof(*islds) * island_store->islands_num_alloc);
+ memcpy(islds, island_store->islands, sizeof(*islds) * (curr_num_islands - 1));
+ island_store->islands = islds;
+
+ innrcuts = BLI_memarena_alloc(mem, sizeof(*innrcuts) * island_store->islands_num_alloc);
+ memcpy(innrcuts, island_store->innercuts, sizeof(*innrcuts) * (curr_num_islands - 1));
+ island_store->innercuts = innrcuts;
+ }
+
+ island_store->islands[curr_island_idx] = isld = BLI_memarena_alloc(mem, sizeof(*isld));
+ isld->count = num_island_items;
+ isld->indices = BLI_memarena_alloc(mem, sizeof(*isld->indices) * (size_t)num_island_items);
+ memcpy(isld->indices, island_item_indices, sizeof(*isld->indices) * (size_t)num_island_items);
+
+ island_store->innercuts[curr_island_idx] = innrcut = BLI_memarena_alloc(mem, sizeof(*innrcut));
+ innrcut->count = num_innercut_items;
+ innrcut->indices = BLI_memarena_alloc(mem,
+ sizeof(*innrcut->indices) * (size_t)num_innercut_items);
+ memcpy(innrcut->indices,
+ innercut_item_indices,
+ sizeof(*innrcut->indices) * (size_t)num_innercut_items);
}
/* TODO: I'm not sure edge seam flag is enough to define UV islands? Maybe we should also consider UVmaps values
@@ -904,196 +969,217 @@ void BKE_mesh_loop_islands_add(
* not sure we want that at all!
*/
typedef struct MeshCheckIslandBoundaryUv {
- const MLoop *loops;
- const MLoopUV *luvs;
- const MeshElemMap *edge_loop_map;
+ const MLoop *loops;
+ const MLoopUV *luvs;
+ const MeshElemMap *edge_loop_map;
} MeshCheckIslandBoundaryUv;
-static bool mesh_check_island_boundary_uv(
- const MPoly *UNUSED(mp), const MLoop *ml, const MEdge *me,
- const int UNUSED(nbr_egde_users), void *user_data)
+static bool mesh_check_island_boundary_uv(const MPoly *UNUSED(mp),
+ const MLoop *ml,
+ const MEdge *me,
+ const int UNUSED(nbr_egde_users),
+ void *user_data)
{
- if (user_data) {
- const MeshCheckIslandBoundaryUv *data = user_data;
- const MLoop *loops = data->loops;
- const MLoopUV *luvs = data->luvs;
- const MeshElemMap *edge_to_loops = &data->edge_loop_map[ml->e];
-
- BLI_assert(edge_to_loops->count >= 2 && (edge_to_loops->count % 2) == 0);
-
- const unsigned int v1 = loops[edge_to_loops->indices[0]].v;
- const unsigned int v2 = loops[edge_to_loops->indices[1]].v;
- const float *uvco_v1 = luvs[edge_to_loops->indices[0]].uv;
- const float *uvco_v2 = luvs[edge_to_loops->indices[1]].uv;
- for (int i = 2; i < edge_to_loops->count; i += 2) {
- if (loops[edge_to_loops->indices[i]].v == v1) {
- if (!equals_v2v2(uvco_v1, luvs[edge_to_loops->indices[i]].uv) ||
- !equals_v2v2(uvco_v2, luvs[edge_to_loops->indices[i + 1]].uv))
- {
- return true;
- }
- }
- else {
- BLI_assert(loops[edge_to_loops->indices[i]].v == v2);
- UNUSED_VARS_NDEBUG(v2);
- if (!equals_v2v2(uvco_v2, luvs[edge_to_loops->indices[i]].uv) ||
- !equals_v2v2(uvco_v1, luvs[edge_to_loops->indices[i + 1]].uv))
- {
- return true;
- }
- }
- }
- return false;
- }
- else {
- /* Edge is UV boundary if tagged as seam. */
- return (me->flag & ME_SEAM) != 0;
- }
+ if (user_data) {
+ const MeshCheckIslandBoundaryUv *data = user_data;
+ const MLoop *loops = data->loops;
+ const MLoopUV *luvs = data->luvs;
+ const MeshElemMap *edge_to_loops = &data->edge_loop_map[ml->e];
+
+ BLI_assert(edge_to_loops->count >= 2 && (edge_to_loops->count % 2) == 0);
+
+ const unsigned int v1 = loops[edge_to_loops->indices[0]].v;
+ const unsigned int v2 = loops[edge_to_loops->indices[1]].v;
+ const float *uvco_v1 = luvs[edge_to_loops->indices[0]].uv;
+ const float *uvco_v2 = luvs[edge_to_loops->indices[1]].uv;
+ for (int i = 2; i < edge_to_loops->count; i += 2) {
+ if (loops[edge_to_loops->indices[i]].v == v1) {
+ if (!equals_v2v2(uvco_v1, luvs[edge_to_loops->indices[i]].uv) ||
+ !equals_v2v2(uvco_v2, luvs[edge_to_loops->indices[i + 1]].uv)) {
+ return true;
+ }
+ }
+ else {
+ BLI_assert(loops[edge_to_loops->indices[i]].v == v2);
+ UNUSED_VARS_NDEBUG(v2);
+ if (!equals_v2v2(uvco_v2, luvs[edge_to_loops->indices[i]].uv) ||
+ !equals_v2v2(uvco_v1, luvs[edge_to_loops->indices[i + 1]].uv)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ else {
+ /* Edge is UV boundary if tagged as seam. */
+ return (me->flag & ME_SEAM) != 0;
+ }
}
-static bool mesh_calc_islands_loop_poly_uv(
- MVert *UNUSED(verts), const int UNUSED(totvert),
- MEdge *edges, const int totedge,
- MPoly *polys, const int totpoly,
- MLoop *loops, const int totloop,
- const MLoopUV *luvs,
- MeshIslandStore *r_island_store)
+static bool mesh_calc_islands_loop_poly_uv(MVert *UNUSED(verts),
+ const int UNUSED(totvert),
+ MEdge *edges,
+ const int totedge,
+ MPoly *polys,
+ const int totpoly,
+ MLoop *loops,
+ const int totloop,
+ const MLoopUV *luvs,
+ MeshIslandStore *r_island_store)
{
- int *poly_groups = NULL;
- int num_poly_groups;
-
- /* map vars */
- MeshElemMap *edge_poly_map;
- int *edge_poly_mem;
-
- MeshElemMap *edge_loop_map;
- int *edge_loop_mem;
-
- MeshCheckIslandBoundaryUv edge_boundary_check_data;
-
- int *poly_indices;
- int *loop_indices;
- int num_pidx, num_lidx;
-
- /* Those are used to detect 'inner cuts', i.e. edges that are borders, and yet have two or more polys of
- * a same group using them (typical case: seam used to unwrap properly a cylinder). */
- BLI_bitmap *edge_borders = NULL;
- int num_edge_borders = 0;
- char *edge_border_count = NULL;
- int *edge_innercut_indices = NULL;
- int num_einnercuts = 0;
-
- int grp_idx, p_idx, pl_idx, l_idx;
-
- BKE_mesh_loop_islands_clear(r_island_store);
- BKE_mesh_loop_islands_init(r_island_store, MISLAND_TYPE_LOOP, totloop, MISLAND_TYPE_POLY, MISLAND_TYPE_EDGE);
-
- BKE_mesh_edge_poly_map_create(
- &edge_poly_map, &edge_poly_mem,
- edges, totedge, polys, totpoly, loops, totloop);
-
- if (luvs) {
- BKE_mesh_edge_loop_map_create(
- &edge_loop_map, &edge_loop_mem,
- edges, totedge, polys, totpoly, loops, totloop);
- edge_boundary_check_data.loops = loops;
- edge_boundary_check_data.luvs = luvs;
- edge_boundary_check_data.edge_loop_map = edge_loop_map;
- }
-
- poly_edge_loop_islands_calc(
- edges, totedge, polys, totpoly, loops, totloop, edge_poly_map, false,
- mesh_check_island_boundary_uv, luvs ? &edge_boundary_check_data : NULL,
- &poly_groups, &num_poly_groups, &edge_borders, &num_edge_borders);
-
- if (!num_poly_groups) {
- /* Should never happen... */
- MEM_freeN(edge_poly_map);
- MEM_freeN(edge_poly_mem);
-
- if (edge_borders) {
- MEM_freeN(edge_borders);
- }
- return false;
- }
-
- if (num_edge_borders) {
- edge_border_count = MEM_mallocN(sizeof(*edge_border_count) * (size_t)totedge, __func__);
- edge_innercut_indices = MEM_mallocN(sizeof(*edge_innercut_indices) * (size_t)num_edge_borders, __func__);
- }
-
- poly_indices = MEM_mallocN(sizeof(*poly_indices) * (size_t)totpoly, __func__);
- loop_indices = MEM_mallocN(sizeof(*loop_indices) * (size_t)totloop, __func__);
-
- /* Note: here we ignore '0' invalid group - this should *never* happen in this case anyway? */
- for (grp_idx = 1; grp_idx <= num_poly_groups; grp_idx++) {
- num_pidx = num_lidx = 0;
- if (num_edge_borders) {
- num_einnercuts = 0;
- memset(edge_border_count, 0, sizeof(*edge_border_count) * (size_t)totedge);
- }
-
- for (p_idx = 0; p_idx < totpoly; p_idx++) {
- MPoly *mp;
-
- if (poly_groups[p_idx] != grp_idx) {
- continue;
- }
-
- mp = &polys[p_idx];
- poly_indices[num_pidx++] = p_idx;
- for (l_idx = mp->loopstart, pl_idx = 0; pl_idx < mp->totloop; l_idx++, pl_idx++) {
- MLoop *ml = &loops[l_idx];
- loop_indices[num_lidx++] = l_idx;
- if (num_edge_borders && BLI_BITMAP_TEST(edge_borders, ml->e) && (edge_border_count[ml->e] < 2)) {
- edge_border_count[ml->e]++;
- if (edge_border_count[ml->e] == 2) {
- edge_innercut_indices[num_einnercuts++] = (int)ml->e;
- }
- }
- }
- }
-
- BKE_mesh_loop_islands_add(
- r_island_store, num_lidx, loop_indices, num_pidx, poly_indices,
- num_einnercuts, edge_innercut_indices);
- }
-
- MEM_freeN(edge_poly_map);
- MEM_freeN(edge_poly_mem);
-
- if (luvs) {
- MEM_freeN(edge_loop_map);
- MEM_freeN(edge_loop_mem);
- }
-
- MEM_freeN(poly_indices);
- MEM_freeN(loop_indices);
- MEM_freeN(poly_groups);
-
- if (edge_borders) {
- MEM_freeN(edge_borders);
- }
-
- if (num_edge_borders) {
- MEM_freeN(edge_border_count);
- MEM_freeN(edge_innercut_indices);
- }
- return true;
+ int *poly_groups = NULL;
+ int num_poly_groups;
+
+ /* map vars */
+ MeshElemMap *edge_poly_map;
+ int *edge_poly_mem;
+
+ MeshElemMap *edge_loop_map;
+ int *edge_loop_mem;
+
+ MeshCheckIslandBoundaryUv edge_boundary_check_data;
+
+ int *poly_indices;
+ int *loop_indices;
+ int num_pidx, num_lidx;
+
+ /* Those are used to detect 'inner cuts', i.e. edges that are borders, and yet have two or more polys of
+ * a same group using them (typical case: seam used to unwrap properly a cylinder). */
+ BLI_bitmap *edge_borders = NULL;
+ int num_edge_borders = 0;
+ char *edge_border_count = NULL;
+ int *edge_innercut_indices = NULL;
+ int num_einnercuts = 0;
+
+ int grp_idx, p_idx, pl_idx, l_idx;
+
+ BKE_mesh_loop_islands_clear(r_island_store);
+ BKE_mesh_loop_islands_init(
+ r_island_store, MISLAND_TYPE_LOOP, totloop, MISLAND_TYPE_POLY, MISLAND_TYPE_EDGE);
+
+ BKE_mesh_edge_poly_map_create(
+ &edge_poly_map, &edge_poly_mem, edges, totedge, polys, totpoly, loops, totloop);
+
+ if (luvs) {
+ BKE_mesh_edge_loop_map_create(
+ &edge_loop_map, &edge_loop_mem, edges, totedge, polys, totpoly, loops, totloop);
+ edge_boundary_check_data.loops = loops;
+ edge_boundary_check_data.luvs = luvs;
+ edge_boundary_check_data.edge_loop_map = edge_loop_map;
+ }
+
+ poly_edge_loop_islands_calc(edges,
+ totedge,
+ polys,
+ totpoly,
+ loops,
+ totloop,
+ edge_poly_map,
+ false,
+ mesh_check_island_boundary_uv,
+ luvs ? &edge_boundary_check_data : NULL,
+ &poly_groups,
+ &num_poly_groups,
+ &edge_borders,
+ &num_edge_borders);
+
+ if (!num_poly_groups) {
+ /* Should never happen... */
+ MEM_freeN(edge_poly_map);
+ MEM_freeN(edge_poly_mem);
+
+ if (edge_borders) {
+ MEM_freeN(edge_borders);
+ }
+ return false;
+ }
+
+ if (num_edge_borders) {
+ edge_border_count = MEM_mallocN(sizeof(*edge_border_count) * (size_t)totedge, __func__);
+ edge_innercut_indices = MEM_mallocN(sizeof(*edge_innercut_indices) * (size_t)num_edge_borders,
+ __func__);
+ }
+
+ poly_indices = MEM_mallocN(sizeof(*poly_indices) * (size_t)totpoly, __func__);
+ loop_indices = MEM_mallocN(sizeof(*loop_indices) * (size_t)totloop, __func__);
+
+ /* Note: here we ignore '0' invalid group - this should *never* happen in this case anyway? */
+ for (grp_idx = 1; grp_idx <= num_poly_groups; grp_idx++) {
+ num_pidx = num_lidx = 0;
+ if (num_edge_borders) {
+ num_einnercuts = 0;
+ memset(edge_border_count, 0, sizeof(*edge_border_count) * (size_t)totedge);
+ }
+
+ for (p_idx = 0; p_idx < totpoly; p_idx++) {
+ MPoly *mp;
+
+ if (poly_groups[p_idx] != grp_idx) {
+ continue;
+ }
+
+ mp = &polys[p_idx];
+ poly_indices[num_pidx++] = p_idx;
+ for (l_idx = mp->loopstart, pl_idx = 0; pl_idx < mp->totloop; l_idx++, pl_idx++) {
+ MLoop *ml = &loops[l_idx];
+ loop_indices[num_lidx++] = l_idx;
+ if (num_edge_borders && BLI_BITMAP_TEST(edge_borders, ml->e) &&
+ (edge_border_count[ml->e] < 2)) {
+ edge_border_count[ml->e]++;
+ if (edge_border_count[ml->e] == 2) {
+ edge_innercut_indices[num_einnercuts++] = (int)ml->e;
+ }
+ }
+ }
+ }
+
+ BKE_mesh_loop_islands_add(r_island_store,
+ num_lidx,
+ loop_indices,
+ num_pidx,
+ poly_indices,
+ num_einnercuts,
+ edge_innercut_indices);
+ }
+
+ MEM_freeN(edge_poly_map);
+ MEM_freeN(edge_poly_mem);
+
+ if (luvs) {
+ MEM_freeN(edge_loop_map);
+ MEM_freeN(edge_loop_mem);
+ }
+
+ MEM_freeN(poly_indices);
+ MEM_freeN(loop_indices);
+ MEM_freeN(poly_groups);
+
+ if (edge_borders) {
+ MEM_freeN(edge_borders);
+ }
+
+ if (num_edge_borders) {
+ MEM_freeN(edge_border_count);
+ MEM_freeN(edge_innercut_indices);
+ }
+ return true;
}
/**
* Calculate 'generic' UV islands, i.e. based only on actual geometry data (edge seams), not some UV layers coordinates.
*/
-bool BKE_mesh_calc_islands_loop_poly_edgeseam(
- MVert *verts, const int totvert,
- MEdge *edges, const int totedge,
- MPoly *polys, const int totpoly,
- MLoop *loops, const int totloop,
- MeshIslandStore *r_island_store)
+bool BKE_mesh_calc_islands_loop_poly_edgeseam(MVert *verts,
+ const int totvert,
+ MEdge *edges,
+ const int totedge,
+ MPoly *polys,
+ const int totpoly,
+ MLoop *loops,
+ const int totloop,
+ MeshIslandStore *r_island_store)
{
- return mesh_calc_islands_loop_poly_uv(
- verts, totvert, edges, totedge, polys, totpoly, loops, totloop, NULL, r_island_store);
+ return mesh_calc_islands_loop_poly_uv(
+ verts, totvert, edges, totedge, polys, totpoly, loops, totloop, NULL, r_island_store);
}
/**
@@ -1107,17 +1193,20 @@ bool BKE_mesh_calc_islands_loop_poly_edgeseam(
* \note All this could be optimized...
* Not sure it would be worth the more complex code, though, those loops are supposed to be really quick to do...
*/
-bool BKE_mesh_calc_islands_loop_poly_uvmap(
- MVert *verts, const int totvert,
- MEdge *edges, const int totedge,
- MPoly *polys, const int totpoly,
- MLoop *loops, const int totloop,
- const MLoopUV *luvs,
- MeshIslandStore *r_island_store)
+bool BKE_mesh_calc_islands_loop_poly_uvmap(MVert *verts,
+ const int totvert,
+ MEdge *edges,
+ const int totedge,
+ MPoly *polys,
+ const int totpoly,
+ MLoop *loops,
+ const int totloop,
+ const MLoopUV *luvs,
+ MeshIslandStore *r_island_store)
{
- BLI_assert(luvs != NULL);
- return mesh_calc_islands_loop_poly_uv(
- verts, totvert, edges, totedge, polys, totpoly, loops, totloop, luvs, r_island_store);
+ BLI_assert(luvs != NULL);
+ return mesh_calc_islands_loop_poly_uv(
+ verts, totvert, edges, totedge, polys, totpoly, loops, totloop, luvs, r_island_store);
}
/** \} */
diff --git a/source/blender/blenkernel/intern/mesh_merge.c b/source/blender/blenkernel/intern/mesh_merge.c
index 0866b52779e..1d534f72842 100644
--- a/source/blender/blenkernel/intern/mesh_merge.c
+++ b/source/blender/blenkernel/intern/mesh_merge.c
@@ -20,7 +20,7 @@
/** \file
* \ingroup bke
*/
-#include <string.h> // for memcpy
+#include <string.h> // for memcpy
#include "MEM_guardedalloc.h"
@@ -37,7 +37,6 @@
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
-
/**
* Poly compare with vtargetmap
* Function used by #BKE_mesh_merge_verts.
@@ -48,164 +47,162 @@
* and may be called again with direct_reverse=-1 for reverse order.
* \return 1 if polys are identical, 0 if polys are different.
*/
-static int cddm_poly_compare(
- MLoop *mloop_array,
- MPoly *mpoly_source, MPoly *mpoly_target,
- const int *vtargetmap, const int direct_reverse)
+static int cddm_poly_compare(MLoop *mloop_array,
+ MPoly *mpoly_source,
+ MPoly *mpoly_target,
+ const int *vtargetmap,
+ const int direct_reverse)
{
- int vert_source, first_vert_source, vert_target;
- int i_loop_source;
- int i_loop_target, i_loop_target_start, i_loop_target_offset, i_loop_target_adjusted;
- bool compare_completed = false;
- bool same_loops = false;
-
- MLoop *mloop_source, *mloop_target;
-
- BLI_assert(direct_reverse == 1 || direct_reverse == -1);
-
- i_loop_source = 0;
- mloop_source = mloop_array + mpoly_source->loopstart;
- vert_source = mloop_source->v;
-
- if (vtargetmap[vert_source] != -1) {
- vert_source = vtargetmap[vert_source];
- }
- else {
- /* All source loop vertices should be mapped */
- BLI_assert(false);
- }
-
- /* Find same vertex within mpoly_target's loops */
- mloop_target = mloop_array + mpoly_target->loopstart;
- for (i_loop_target = 0; i_loop_target < mpoly_target->totloop; i_loop_target++, mloop_target++) {
- if (mloop_target->v == vert_source) {
- break;
- }
- }
-
- /* If same vertex not found, then polys cannot be equal */
- if (i_loop_target >= mpoly_target->totloop) {
- return false;
- }
-
- /* Now mloop_source and m_loop_target have one identical vertex */
- /* mloop_source is at position 0, while m_loop_target has advanced to find identical vertex */
- /* Go around the loop and check that all vertices match in same order */
- /* Skipping source loops when consecutive source vertices are mapped to same target vertex */
-
- i_loop_target_start = i_loop_target;
- i_loop_target_offset = 0;
- first_vert_source = vert_source;
-
- compare_completed = false;
- same_loops = false;
-
- while (!compare_completed) {
-
- vert_target = mloop_target->v;
-
- /* First advance i_loop_source, until it points to different vertex, after mapping applied */
- do {
- i_loop_source++;
-
- if (i_loop_source == mpoly_source->totloop) {
- /* End of loops for source, must match end of loop for target. */
- if (i_loop_target_offset == mpoly_target->totloop - 1) {
- compare_completed = true;
- same_loops = true;
- break; /* Polys are identical */
- }
- else {
- compare_completed = true;
- same_loops = false;
- break; /* Polys are different */
- }
- }
-
- mloop_source++;
- vert_source = mloop_source->v;
-
- if (vtargetmap[vert_source] != -1) {
- vert_source = vtargetmap[vert_source];
- }
- else {
- /* All source loop vertices should be mapped */
- BLI_assert(false);
- }
-
- } while (vert_source == vert_target);
-
- if (compare_completed) {
- break;
- }
-
- /* Now advance i_loop_target as well */
- i_loop_target_offset++;
-
- if (i_loop_target_offset == mpoly_target->totloop) {
- /* End of loops for target only, that means no match */
- /* except if all remaining source vertices are mapped to first target */
- for (; i_loop_source < mpoly_source->totloop; i_loop_source++, mloop_source++) {
- vert_source = vtargetmap[mloop_source->v];
- if (vert_source != first_vert_source) {
- compare_completed = true;
- same_loops = false;
- break;
- }
- }
- if (!compare_completed) {
- same_loops = true;
- }
- break;
- }
-
- /* Adjust i_loop_target for cycling around and for direct/reverse order defined by delta = +1 or -1 */
- i_loop_target_adjusted = (i_loop_target_start + direct_reverse * i_loop_target_offset) % mpoly_target->totloop;
- if (i_loop_target_adjusted < 0) {
- i_loop_target_adjusted += mpoly_target->totloop;
- }
- mloop_target = mloop_array + mpoly_target->loopstart + i_loop_target_adjusted;
- vert_target = mloop_target->v;
-
- if (vert_target != vert_source) {
- same_loops = false; /* Polys are different */
- break;
- }
- }
- return same_loops;
+ int vert_source, first_vert_source, vert_target;
+ int i_loop_source;
+ int i_loop_target, i_loop_target_start, i_loop_target_offset, i_loop_target_adjusted;
+ bool compare_completed = false;
+ bool same_loops = false;
+
+ MLoop *mloop_source, *mloop_target;
+
+ BLI_assert(direct_reverse == 1 || direct_reverse == -1);
+
+ i_loop_source = 0;
+ mloop_source = mloop_array + mpoly_source->loopstart;
+ vert_source = mloop_source->v;
+
+ if (vtargetmap[vert_source] != -1) {
+ vert_source = vtargetmap[vert_source];
+ }
+ else {
+ /* All source loop vertices should be mapped */
+ BLI_assert(false);
+ }
+
+ /* Find same vertex within mpoly_target's loops */
+ mloop_target = mloop_array + mpoly_target->loopstart;
+ for (i_loop_target = 0; i_loop_target < mpoly_target->totloop; i_loop_target++, mloop_target++) {
+ if (mloop_target->v == vert_source) {
+ break;
+ }
+ }
+
+ /* If same vertex not found, then polys cannot be equal */
+ if (i_loop_target >= mpoly_target->totloop) {
+ return false;
+ }
+
+ /* Now mloop_source and m_loop_target have one identical vertex */
+ /* mloop_source is at position 0, while m_loop_target has advanced to find identical vertex */
+ /* Go around the loop and check that all vertices match in same order */
+ /* Skipping source loops when consecutive source vertices are mapped to same target vertex */
+
+ i_loop_target_start = i_loop_target;
+ i_loop_target_offset = 0;
+ first_vert_source = vert_source;
+
+ compare_completed = false;
+ same_loops = false;
+
+ while (!compare_completed) {
+
+ vert_target = mloop_target->v;
+
+ /* First advance i_loop_source, until it points to different vertex, after mapping applied */
+ do {
+ i_loop_source++;
+
+ if (i_loop_source == mpoly_source->totloop) {
+ /* End of loops for source, must match end of loop for target. */
+ if (i_loop_target_offset == mpoly_target->totloop - 1) {
+ compare_completed = true;
+ same_loops = true;
+ break; /* Polys are identical */
+ }
+ else {
+ compare_completed = true;
+ same_loops = false;
+ break; /* Polys are different */
+ }
+ }
+
+ mloop_source++;
+ vert_source = mloop_source->v;
+
+ if (vtargetmap[vert_source] != -1) {
+ vert_source = vtargetmap[vert_source];
+ }
+ else {
+ /* All source loop vertices should be mapped */
+ BLI_assert(false);
+ }
+
+ } while (vert_source == vert_target);
+
+ if (compare_completed) {
+ break;
+ }
+
+ /* Now advance i_loop_target as well */
+ i_loop_target_offset++;
+
+ if (i_loop_target_offset == mpoly_target->totloop) {
+ /* End of loops for target only, that means no match */
+ /* except if all remaining source vertices are mapped to first target */
+ for (; i_loop_source < mpoly_source->totloop; i_loop_source++, mloop_source++) {
+ vert_source = vtargetmap[mloop_source->v];
+ if (vert_source != first_vert_source) {
+ compare_completed = true;
+ same_loops = false;
+ break;
+ }
+ }
+ if (!compare_completed) {
+ same_loops = true;
+ }
+ break;
+ }
+
+ /* Adjust i_loop_target for cycling around and for direct/reverse order defined by delta = +1 or -1 */
+ i_loop_target_adjusted = (i_loop_target_start + direct_reverse * i_loop_target_offset) %
+ mpoly_target->totloop;
+ if (i_loop_target_adjusted < 0) {
+ i_loop_target_adjusted += mpoly_target->totloop;
+ }
+ mloop_target = mloop_array + mpoly_target->loopstart + i_loop_target_adjusted;
+ vert_target = mloop_target->v;
+
+ if (vert_target != vert_source) {
+ same_loops = false; /* Polys are different */
+ break;
+ }
+ }
+ return same_loops;
}
-
/* Utility stuff for using GHash with polys, used by vertex merging. */
typedef struct PolyKey {
- int poly_index; /* index of the MPoly within the derived mesh */
- int totloops; /* number of loops in the poly */
- unsigned int hash_sum; /* Sum of all vertices indices */
- unsigned int hash_xor; /* Xor of all vertices indices */
+ int poly_index; /* index of the MPoly within the derived mesh */
+ int totloops; /* number of loops in the poly */
+ unsigned int hash_sum; /* Sum of all vertices indices */
+ unsigned int hash_xor; /* Xor of all vertices indices */
} PolyKey;
-
static unsigned int poly_gset_hash_fn(const void *key)
{
- const PolyKey *pk = key;
- return pk->hash_sum;
+ const PolyKey *pk = key;
+ return pk->hash_sum;
}
static bool poly_gset_compare_fn(const void *k1, const void *k2)
{
- const PolyKey *pk1 = k1;
- const PolyKey *pk2 = k2;
- if ((pk1->hash_sum == pk2->hash_sum) &&
- (pk1->hash_xor == pk2->hash_xor) &&
- (pk1->totloops == pk2->totloops))
- {
- /* Equality - note that this does not mean equality of polys */
- return false;
- }
- else {
- return true;
- }
+ const PolyKey *pk1 = k1;
+ const PolyKey *pk2 = k2;
+ if ((pk1->hash_sum == pk2->hash_sum) && (pk1->hash_xor == pk2->hash_xor) &&
+ (pk1->totloops == pk2->totloops)) {
+ /* Equality - note that this does not mean equality of polys */
+ return false;
+ }
+ else {
+ return true;
+ }
}
/**
@@ -238,442 +235,441 @@ static bool poly_gset_compare_fn(const void *k1, const void *k2)
*
* \note #BKE_mesh_recalc_tessellation has to run on the returned DM if you want to access tessfaces.
*/
-Mesh *BKE_mesh_merge_verts(Mesh *mesh, const int *vtargetmap, const int tot_vtargetmap, const int merge_mode)
+Mesh *BKE_mesh_merge_verts(Mesh *mesh,
+ const int *vtargetmap,
+ const int tot_vtargetmap,
+ const int merge_mode)
{
- /* This was commented out back in 2013, see commit f45d8827bafe6b9eaf9de42f4054e9d84a21955d. */
-// #define USE_LOOPS
-
- Mesh *result = NULL;
-
- const int totvert = mesh->totvert;
- const int totedge = mesh->totedge;
- const int totloop = mesh->totloop;
- const int totpoly = mesh->totpoly;
-
- const int totvert_final = totvert - tot_vtargetmap;
-
- MVert *mv, *mvert = MEM_malloc_arrayN(totvert_final, sizeof(*mvert), __func__);
- int *oldv = MEM_malloc_arrayN(totvert_final, sizeof(*oldv), __func__);
- int *newv = MEM_malloc_arrayN(totvert, sizeof(*newv), __func__);
- STACK_DECLARE(mvert);
- STACK_DECLARE(oldv);
-
- /* Note: create (totedge + totloop) elements because partially invalid polys due to merge may require
- * generating new edges, and while in 99% cases we'll still end with less final edges than totedge,
- * cases can be forged that would end requiring more... */
- MEdge *med, *medge = MEM_malloc_arrayN((totedge + totloop), sizeof(*medge), __func__);
- int *olde = MEM_malloc_arrayN((totedge + totloop), sizeof(*olde), __func__);
- int *newe = MEM_malloc_arrayN((totedge + totloop), sizeof(*newe), __func__);
- STACK_DECLARE(medge);
- STACK_DECLARE(olde);
-
- MLoop *ml, *mloop = MEM_malloc_arrayN(totloop, sizeof(*mloop), __func__);
- int *oldl = MEM_malloc_arrayN(totloop, sizeof(*oldl), __func__);
+ /* This was commented out back in 2013, see commit f45d8827bafe6b9eaf9de42f4054e9d84a21955d. */
+ // #define USE_LOOPS
+
+ Mesh *result = NULL;
+
+ const int totvert = mesh->totvert;
+ const int totedge = mesh->totedge;
+ const int totloop = mesh->totloop;
+ const int totpoly = mesh->totpoly;
+
+ const int totvert_final = totvert - tot_vtargetmap;
+
+ MVert *mv, *mvert = MEM_malloc_arrayN(totvert_final, sizeof(*mvert), __func__);
+ int *oldv = MEM_malloc_arrayN(totvert_final, sizeof(*oldv), __func__);
+ int *newv = MEM_malloc_arrayN(totvert, sizeof(*newv), __func__);
+ STACK_DECLARE(mvert);
+ STACK_DECLARE(oldv);
+
+ /* Note: create (totedge + totloop) elements because partially invalid polys due to merge may require
+ * generating new edges, and while in 99% cases we'll still end with less final edges than totedge,
+ * cases can be forged that would end requiring more... */
+ MEdge *med, *medge = MEM_malloc_arrayN((totedge + totloop), sizeof(*medge), __func__);
+ int *olde = MEM_malloc_arrayN((totedge + totloop), sizeof(*olde), __func__);
+ int *newe = MEM_malloc_arrayN((totedge + totloop), sizeof(*newe), __func__);
+ STACK_DECLARE(medge);
+ STACK_DECLARE(olde);
+
+ MLoop *ml, *mloop = MEM_malloc_arrayN(totloop, sizeof(*mloop), __func__);
+ int *oldl = MEM_malloc_arrayN(totloop, sizeof(*oldl), __func__);
#ifdef USE_LOOPS
- int *newl = MEM_malloc_arrayN(totloop, sizeof(*newl), __func__);
+ int *newl = MEM_malloc_arrayN(totloop, sizeof(*newl), __func__);
#endif
- STACK_DECLARE(mloop);
- STACK_DECLARE(oldl);
-
- MPoly *mp, *mpoly = MEM_malloc_arrayN(totpoly, sizeof(*medge), __func__);
- int *oldp = MEM_malloc_arrayN(totpoly, sizeof(*oldp), __func__);
- STACK_DECLARE(mpoly);
- STACK_DECLARE(oldp);
-
- EdgeHash *ehash = BLI_edgehash_new_ex(__func__, totedge);
-
- int i, j, c;
-
- PolyKey *poly_keys;
- GSet *poly_gset = NULL;
- MeshElemMap *poly_map = NULL;
- int *poly_map_mem = NULL;
-
- STACK_INIT(oldv, totvert_final);
- STACK_INIT(olde, totedge);
- STACK_INIT(oldl, totloop);
- STACK_INIT(oldp, totpoly);
-
- STACK_INIT(mvert, totvert_final);
- STACK_INIT(medge, totedge);
- STACK_INIT(mloop, totloop);
- STACK_INIT(mpoly, totpoly);
-
- /* fill newv with destination vertex indices */
- mv = mesh->mvert;
- c = 0;
- for (i = 0; i < totvert; i++, mv++) {
- if (vtargetmap[i] == -1) {
- STACK_PUSH(oldv, i);
- STACK_PUSH(mvert, *mv);
- newv[i] = c++;
- }
- else {
- /* dummy value */
- newv[i] = 0;
- }
- }
-
- /* now link target vertices to destination indices */
- for (i = 0; i < totvert; i++) {
- if (vtargetmap[i] != -1) {
- newv[i] = newv[vtargetmap[i]];
- }
- }
-
- /* Don't remap vertices in cddm->mloop, because we need to know the original
- * indices in order to skip faces with all vertices merged.
- * The "update loop indices..." section further down remaps vertices in mloop.
- */
-
- /* now go through and fix edges and faces */
- med = mesh->medge;
- c = 0;
- for (i = 0; i < totedge; i++, med++) {
- const unsigned int v1 = (vtargetmap[med->v1] != -1) ? vtargetmap[med->v1] : med->v1;
- const unsigned int v2 = (vtargetmap[med->v2] != -1) ? vtargetmap[med->v2] : med->v2;
- if (LIKELY(v1 != v2)) {
- void **val_p;
-
- if (BLI_edgehash_ensure_p(ehash, v1, v2, &val_p)) {
- newe[i] = POINTER_AS_INT(*val_p);
- }
- else {
- STACK_PUSH(olde, i);
- STACK_PUSH(medge, *med);
- newe[i] = c;
- *val_p = POINTER_FROM_INT(c);
- c++;
- }
- }
- else {
- newe[i] = -1;
- }
- }
-
- if (merge_mode == MESH_MERGE_VERTS_DUMP_IF_EQUAL) {
- /* In this mode, we need to determine, whenever a poly' vertices are all mapped */
- /* if the targets already make up a poly, in which case the new poly is dropped */
- /* This poly equality check is rather complex. We use a BLI_ghash to speed it up with a first level check */
- PolyKey *mpgh;
- poly_keys = MEM_malloc_arrayN(totpoly, sizeof(PolyKey), __func__);
- poly_gset = BLI_gset_new_ex(poly_gset_hash_fn, poly_gset_compare_fn, __func__, totpoly);
- /* Duplicates allowed because our compare function is not pure equality */
- BLI_gset_flag_set(poly_gset, GHASH_FLAG_ALLOW_DUPES);
-
- mp = mesh->mpoly;
- mpgh = poly_keys;
- for (i = 0; i < totpoly; i++, mp++, mpgh++) {
- mpgh->poly_index = i;
- mpgh->totloops = mp->totloop;
- ml = mesh->mloop + mp->loopstart;
- mpgh->hash_sum = mpgh->hash_xor = 0;
- for (j = 0; j < mp->totloop; j++, ml++) {
- mpgh->hash_sum += ml->v;
- mpgh->hash_xor ^= ml->v;
- }
- BLI_gset_insert(poly_gset, mpgh);
- }
-
- /* Can we optimise by reusing an old pmap ? How do we know an old pmap is stale ? */
- /* When called by MOD_array.c, the cddm has just been created, so it has no valid pmap. */
- BKE_mesh_vert_poly_map_create(
- &poly_map, &poly_map_mem,
- mesh->mpoly, mesh->mloop,
- totvert, totpoly, totloop);
- } /* done preparing for fast poly compare */
-
-
- mp = mesh->mpoly;
- mv = mesh->mvert;
- for (i = 0; i < totpoly; i++, mp++) {
- MPoly *mp_new;
-
- ml = mesh->mloop + mp->loopstart;
-
- /* check faces with all vertices merged */
- bool all_vertices_merged = true;
-
- for (j = 0; j < mp->totloop; j++, ml++) {
- if (vtargetmap[ml->v] == -1) {
- all_vertices_merged = false;
- /* This will be used to check for poly using several time the same vert. */
- mv[ml->v].flag &= ~ME_VERT_TMP_TAG;
- }
- else {
- /* This will be used to check for poly using several time the same vert. */
- mv[vtargetmap[ml->v]].flag &= ~ME_VERT_TMP_TAG;
- }
- }
-
- if (UNLIKELY(all_vertices_merged)) {
- if (merge_mode == MESH_MERGE_VERTS_DUMP_IF_MAPPED) {
- /* In this mode, all vertices merged is enough to dump face */
- continue;
- }
- else if (merge_mode == MESH_MERGE_VERTS_DUMP_IF_EQUAL) {
- /* Additional condition for face dump: target vertices must make up an identical face */
- /* The test has 2 steps: (1) first step is fast ghash lookup, but not failproof */
- /* (2) second step is thorough but more costly poly compare */
- int i_poly, v_target;
- bool found = false;
- PolyKey pkey;
-
- /* Use poly_gset for fast (although not 100% certain) identification of same poly */
- /* First, make up a poly_summary structure */
- ml = mesh->mloop + mp->loopstart;
- pkey.hash_sum = pkey.hash_xor = 0;
- pkey.totloops = 0;
- for (j = 0; j < mp->totloop; j++, ml++) {
- v_target = vtargetmap[ml->v]; /* Cannot be -1, they are all mapped */
- pkey.hash_sum += v_target;
- pkey.hash_xor ^= v_target;
- pkey.totloops++;
- }
- if (BLI_gset_haskey(poly_gset, &pkey)) {
-
- /* There might be a poly that matches this one.
- * We could just leave it there and say there is, and do a "continue".
- * ... but we are checking whether there is an exact poly match.
- * It's not so costly in terms of CPU since it's very rare, just a lot of complex code.
- */
-
- /* Consider current loop again */
- ml = mesh->mloop + mp->loopstart;
- /* Consider the target of the loop's first vert */
- v_target = vtargetmap[ml->v];
- /* Now see if v_target belongs to a poly that shares all vertices with source poly,
- * in same order, or reverse order */
-
- for (i_poly = 0; i_poly < poly_map[v_target].count; i_poly++) {
- MPoly *target_poly = mesh->mpoly + *(poly_map[v_target].indices + i_poly);
-
- if (cddm_poly_compare(mesh->mloop, mp, target_poly, vtargetmap, +1) ||
- cddm_poly_compare(mesh->mloop, mp, target_poly, vtargetmap, -1))
- {
- found = true;
- break;
- }
- }
- if (found) {
- /* Current poly's vertices are mapped to a poly that is strictly identical */
- /* Current poly is dumped */
- continue;
- }
- }
- }
- }
-
-
- /* Here either the poly's vertices were not all merged
- * or they were all merged, but targets do not make up an identical poly,
- * the poly is retained.
- */
- ml = mesh->mloop + mp->loopstart;
-
- c = 0;
- MLoop *last_valid_ml = NULL;
- MLoop *first_valid_ml = NULL;
- bool need_edge_from_last_valid_ml = false;
- bool need_edge_to_first_valid_ml = false;
- int created_edges = 0;
- for (j = 0; j < mp->totloop; j++, ml++) {
- const uint mlv = (vtargetmap[ml->v] != -1) ? vtargetmap[ml->v] : ml->v;
+ STACK_DECLARE(mloop);
+ STACK_DECLARE(oldl);
+
+ MPoly *mp, *mpoly = MEM_malloc_arrayN(totpoly, sizeof(*medge), __func__);
+ int *oldp = MEM_malloc_arrayN(totpoly, sizeof(*oldp), __func__);
+ STACK_DECLARE(mpoly);
+ STACK_DECLARE(oldp);
+
+ EdgeHash *ehash = BLI_edgehash_new_ex(__func__, totedge);
+
+ int i, j, c;
+
+ PolyKey *poly_keys;
+ GSet *poly_gset = NULL;
+ MeshElemMap *poly_map = NULL;
+ int *poly_map_mem = NULL;
+
+ STACK_INIT(oldv, totvert_final);
+ STACK_INIT(olde, totedge);
+ STACK_INIT(oldl, totloop);
+ STACK_INIT(oldp, totpoly);
+
+ STACK_INIT(mvert, totvert_final);
+ STACK_INIT(medge, totedge);
+ STACK_INIT(mloop, totloop);
+ STACK_INIT(mpoly, totpoly);
+
+ /* fill newv with destination vertex indices */
+ mv = mesh->mvert;
+ c = 0;
+ for (i = 0; i < totvert; i++, mv++) {
+ if (vtargetmap[i] == -1) {
+ STACK_PUSH(oldv, i);
+ STACK_PUSH(mvert, *mv);
+ newv[i] = c++;
+ }
+ else {
+ /* dummy value */
+ newv[i] = 0;
+ }
+ }
+
+ /* now link target vertices to destination indices */
+ for (i = 0; i < totvert; i++) {
+ if (vtargetmap[i] != -1) {
+ newv[i] = newv[vtargetmap[i]];
+ }
+ }
+
+ /* Don't remap vertices in cddm->mloop, because we need to know the original
+ * indices in order to skip faces with all vertices merged.
+ * The "update loop indices..." section further down remaps vertices in mloop.
+ */
+
+ /* now go through and fix edges and faces */
+ med = mesh->medge;
+ c = 0;
+ for (i = 0; i < totedge; i++, med++) {
+ const unsigned int v1 = (vtargetmap[med->v1] != -1) ? vtargetmap[med->v1] : med->v1;
+ const unsigned int v2 = (vtargetmap[med->v2] != -1) ? vtargetmap[med->v2] : med->v2;
+ if (LIKELY(v1 != v2)) {
+ void **val_p;
+
+ if (BLI_edgehash_ensure_p(ehash, v1, v2, &val_p)) {
+ newe[i] = POINTER_AS_INT(*val_p);
+ }
+ else {
+ STACK_PUSH(olde, i);
+ STACK_PUSH(medge, *med);
+ newe[i] = c;
+ *val_p = POINTER_FROM_INT(c);
+ c++;
+ }
+ }
+ else {
+ newe[i] = -1;
+ }
+ }
+
+ if (merge_mode == MESH_MERGE_VERTS_DUMP_IF_EQUAL) {
+ /* In this mode, we need to determine, whenever a poly' vertices are all mapped */
+ /* if the targets already make up a poly, in which case the new poly is dropped */
+ /* This poly equality check is rather complex. We use a BLI_ghash to speed it up with a first level check */
+ PolyKey *mpgh;
+ poly_keys = MEM_malloc_arrayN(totpoly, sizeof(PolyKey), __func__);
+ poly_gset = BLI_gset_new_ex(poly_gset_hash_fn, poly_gset_compare_fn, __func__, totpoly);
+ /* Duplicates allowed because our compare function is not pure equality */
+ BLI_gset_flag_set(poly_gset, GHASH_FLAG_ALLOW_DUPES);
+
+ mp = mesh->mpoly;
+ mpgh = poly_keys;
+ for (i = 0; i < totpoly; i++, mp++, mpgh++) {
+ mpgh->poly_index = i;
+ mpgh->totloops = mp->totloop;
+ ml = mesh->mloop + mp->loopstart;
+ mpgh->hash_sum = mpgh->hash_xor = 0;
+ for (j = 0; j < mp->totloop; j++, ml++) {
+ mpgh->hash_sum += ml->v;
+ mpgh->hash_xor ^= ml->v;
+ }
+ BLI_gset_insert(poly_gset, mpgh);
+ }
+
+ /* Can we optimise by reusing an old pmap ? How do we know an old pmap is stale ? */
+ /* When called by MOD_array.c, the cddm has just been created, so it has no valid pmap. */
+ BKE_mesh_vert_poly_map_create(
+ &poly_map, &poly_map_mem, mesh->mpoly, mesh->mloop, totvert, totpoly, totloop);
+ } /* done preparing for fast poly compare */
+
+ mp = mesh->mpoly;
+ mv = mesh->mvert;
+ for (i = 0; i < totpoly; i++, mp++) {
+ MPoly *mp_new;
+
+ ml = mesh->mloop + mp->loopstart;
+
+ /* check faces with all vertices merged */
+ bool all_vertices_merged = true;
+
+ for (j = 0; j < mp->totloop; j++, ml++) {
+ if (vtargetmap[ml->v] == -1) {
+ all_vertices_merged = false;
+ /* This will be used to check for poly using several time the same vert. */
+ mv[ml->v].flag &= ~ME_VERT_TMP_TAG;
+ }
+ else {
+ /* This will be used to check for poly using several time the same vert. */
+ mv[vtargetmap[ml->v]].flag &= ~ME_VERT_TMP_TAG;
+ }
+ }
+
+ if (UNLIKELY(all_vertices_merged)) {
+ if (merge_mode == MESH_MERGE_VERTS_DUMP_IF_MAPPED) {
+ /* In this mode, all vertices merged is enough to dump face */
+ continue;
+ }
+ else if (merge_mode == MESH_MERGE_VERTS_DUMP_IF_EQUAL) {
+ /* Additional condition for face dump: target vertices must make up an identical face */
+ /* The test has 2 steps: (1) first step is fast ghash lookup, but not failproof */
+ /* (2) second step is thorough but more costly poly compare */
+ int i_poly, v_target;
+ bool found = false;
+ PolyKey pkey;
+
+ /* Use poly_gset for fast (although not 100% certain) identification of same poly */
+ /* First, make up a poly_summary structure */
+ ml = mesh->mloop + mp->loopstart;
+ pkey.hash_sum = pkey.hash_xor = 0;
+ pkey.totloops = 0;
+ for (j = 0; j < mp->totloop; j++, ml++) {
+ v_target = vtargetmap[ml->v]; /* Cannot be -1, they are all mapped */
+ pkey.hash_sum += v_target;
+ pkey.hash_xor ^= v_target;
+ pkey.totloops++;
+ }
+ if (BLI_gset_haskey(poly_gset, &pkey)) {
+
+ /* There might be a poly that matches this one.
+ * We could just leave it there and say there is, and do a "continue".
+ * ... but we are checking whether there is an exact poly match.
+ * It's not so costly in terms of CPU since it's very rare, just a lot of complex code.
+ */
+
+ /* Consider current loop again */
+ ml = mesh->mloop + mp->loopstart;
+ /* Consider the target of the loop's first vert */
+ v_target = vtargetmap[ml->v];
+ /* Now see if v_target belongs to a poly that shares all vertices with source poly,
+ * in same order, or reverse order */
+
+ for (i_poly = 0; i_poly < poly_map[v_target].count; i_poly++) {
+ MPoly *target_poly = mesh->mpoly + *(poly_map[v_target].indices + i_poly);
+
+ if (cddm_poly_compare(mesh->mloop, mp, target_poly, vtargetmap, +1) ||
+ cddm_poly_compare(mesh->mloop, mp, target_poly, vtargetmap, -1)) {
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ /* Current poly's vertices are mapped to a poly that is strictly identical */
+ /* Current poly is dumped */
+ continue;
+ }
+ }
+ }
+ }
+
+ /* Here either the poly's vertices were not all merged
+ * or they were all merged, but targets do not make up an identical poly,
+ * the poly is retained.
+ */
+ ml = mesh->mloop + mp->loopstart;
+
+ c = 0;
+ MLoop *last_valid_ml = NULL;
+ MLoop *first_valid_ml = NULL;
+ bool need_edge_from_last_valid_ml = false;
+ bool need_edge_to_first_valid_ml = false;
+ int created_edges = 0;
+ for (j = 0; j < mp->totloop; j++, ml++) {
+ const uint mlv = (vtargetmap[ml->v] != -1) ? vtargetmap[ml->v] : ml->v;
#ifndef NDEBUG
- {
- MLoop *next_ml = mesh->mloop + mp->loopstart + ((j + 1) % mp->totloop);
- uint next_mlv = (vtargetmap[next_ml->v] != -1) ? vtargetmap[next_ml->v] : next_ml->v;
- med = mesh->medge + ml->e;
- uint v1 = (vtargetmap[med->v1] != -1) ? vtargetmap[med->v1] : med->v1;
- uint v2 = (vtargetmap[med->v2] != -1) ? vtargetmap[med->v2] : med->v2;
- BLI_assert((mlv == v1 && next_mlv == v2) || (mlv == v2 && next_mlv == v1));
- }
+ {
+ MLoop *next_ml = mesh->mloop + mp->loopstart + ((j + 1) % mp->totloop);
+ uint next_mlv = (vtargetmap[next_ml->v] != -1) ? vtargetmap[next_ml->v] : next_ml->v;
+ med = mesh->medge + ml->e;
+ uint v1 = (vtargetmap[med->v1] != -1) ? vtargetmap[med->v1] : med->v1;
+ uint v2 = (vtargetmap[med->v2] != -1) ? vtargetmap[med->v2] : med->v2;
+ BLI_assert((mlv == v1 && next_mlv == v2) || (mlv == v2 && next_mlv == v1));
+ }
#endif
- /* A loop is only valid if its matching edge is, and it's not reusing a vertex already used by this poly. */
- if (LIKELY((newe[ml->e] != -1) && ((mv[mlv].flag & ME_VERT_TMP_TAG) == 0))) {
- mv[mlv].flag |= ME_VERT_TMP_TAG;
-
- if (UNLIKELY(last_valid_ml != NULL && need_edge_from_last_valid_ml)) {
- /* We need to create a new edge between last valid loop and this one! */
- void **val_p;
-
- uint v1 = (vtargetmap[last_valid_ml->v] != -1) ? vtargetmap[last_valid_ml->v] : last_valid_ml->v;
- uint v2 = mlv;
- BLI_assert(v1 != v2);
- if (BLI_edgehash_ensure_p(ehash, v1, v2, &val_p)) {
- last_valid_ml->e = POINTER_AS_INT(*val_p);
- }
- else {
- const int new_eidx = STACK_SIZE(medge);
- STACK_PUSH(olde, olde[last_valid_ml->e]);
- STACK_PUSH(medge, mesh->medge[last_valid_ml->e]);
- medge[new_eidx].v1 = last_valid_ml->v;
- medge[new_eidx].v2 = ml->v;
- /* DO NOT change newe mapping, could break actual values due to some deleted original edges. */
- *val_p = POINTER_FROM_INT(new_eidx);
- created_edges++;
-
- last_valid_ml->e = new_eidx;
- }
- need_edge_from_last_valid_ml = false;
- }
+ /* A loop is only valid if its matching edge is, and it's not reusing a vertex already used by this poly. */
+ if (LIKELY((newe[ml->e] != -1) && ((mv[mlv].flag & ME_VERT_TMP_TAG) == 0))) {
+ mv[mlv].flag |= ME_VERT_TMP_TAG;
+
+ if (UNLIKELY(last_valid_ml != NULL && need_edge_from_last_valid_ml)) {
+ /* We need to create a new edge between last valid loop and this one! */
+ void **val_p;
+
+ uint v1 = (vtargetmap[last_valid_ml->v] != -1) ? vtargetmap[last_valid_ml->v] :
+ last_valid_ml->v;
+ uint v2 = mlv;
+ BLI_assert(v1 != v2);
+ if (BLI_edgehash_ensure_p(ehash, v1, v2, &val_p)) {
+ last_valid_ml->e = POINTER_AS_INT(*val_p);
+ }
+ else {
+ const int new_eidx = STACK_SIZE(medge);
+ STACK_PUSH(olde, olde[last_valid_ml->e]);
+ STACK_PUSH(medge, mesh->medge[last_valid_ml->e]);
+ medge[new_eidx].v1 = last_valid_ml->v;
+ medge[new_eidx].v2 = ml->v;
+ /* DO NOT change newe mapping, could break actual values due to some deleted original edges. */
+ *val_p = POINTER_FROM_INT(new_eidx);
+ created_edges++;
+
+ last_valid_ml->e = new_eidx;
+ }
+ need_edge_from_last_valid_ml = false;
+ }
#ifdef USE_LOOPS
- newl[j + mp->loopstart] = STACK_SIZE(mloop);
+ newl[j + mp->loopstart] = STACK_SIZE(mloop);
#endif
- STACK_PUSH(oldl, j + mp->loopstart);
- last_valid_ml = STACK_PUSH_RET_PTR(mloop);
- *last_valid_ml = *ml;
- if (first_valid_ml == NULL) {
- first_valid_ml = last_valid_ml;
- }
- c++;
-
- /* We absolutely HAVE to handle edge index remapping here, otherwise potential newly created edges
- * in that part of code make remapping later totally unreliable. */
- BLI_assert(newe[ml->e] != -1);
- last_valid_ml->e = newe[ml->e];
- }
- else {
- if (last_valid_ml != NULL) {
- need_edge_from_last_valid_ml = true;
- }
- else {
- need_edge_to_first_valid_ml = true;
- }
- }
- }
- if (UNLIKELY(last_valid_ml != NULL && !ELEM(first_valid_ml, NULL, last_valid_ml) &&
- (need_edge_to_first_valid_ml || need_edge_from_last_valid_ml)))
- {
- /* We need to create a new edge between last valid loop and first valid one! */
- void **val_p;
-
- uint v1 = (vtargetmap[last_valid_ml->v] != -1) ? vtargetmap[last_valid_ml->v] : last_valid_ml->v;
- uint v2 = (vtargetmap[first_valid_ml->v] != -1) ? vtargetmap[first_valid_ml->v] : first_valid_ml->v;
- BLI_assert(v1 != v2);
- if (BLI_edgehash_ensure_p(ehash, v1, v2, &val_p)) {
- last_valid_ml->e = POINTER_AS_INT(*val_p);
- }
- else {
- const int new_eidx = STACK_SIZE(medge);
- STACK_PUSH(olde, olde[last_valid_ml->e]);
- STACK_PUSH(medge, mesh->medge[last_valid_ml->e]);
- medge[new_eidx].v1 = last_valid_ml->v;
- medge[new_eidx].v2 = first_valid_ml->v;
- /* DO NOT change newe mapping, could break actual values due to some deleted original edges. */
- *val_p = POINTER_FROM_INT(new_eidx);
- created_edges++;
-
- last_valid_ml->e = new_eidx;
- }
- need_edge_to_first_valid_ml = need_edge_from_last_valid_ml = false;
- }
-
- if (UNLIKELY(c == 0)) {
- BLI_assert(created_edges == 0);
- continue;
- }
- else if (UNLIKELY(c < 3)) {
- STACK_DISCARD(oldl, c);
- STACK_DISCARD(mloop, c);
- if (created_edges > 0) {
- for (j = STACK_SIZE(medge) - created_edges; j < STACK_SIZE(medge); j++) {
- BLI_edgehash_remove(ehash, medge[j].v1, medge[j].v2, NULL);
- }
- STACK_DISCARD(olde, created_edges);
- STACK_DISCARD(medge, created_edges);
- }
- continue;
- }
-
- mp_new = STACK_PUSH_RET_PTR(mpoly);
- *mp_new = *mp;
- mp_new->totloop = c;
- BLI_assert(mp_new->totloop >= 3);
- mp_new->loopstart = STACK_SIZE(mloop) - c;
-
- STACK_PUSH(oldp, i);
- } /* end of the loop that tests polys */
-
-
- if (poly_gset) {
- // printf("hash quality %.6f\n", BLI_gset_calc_quality(poly_gset));
-
- BLI_gset_free(poly_gset, NULL);
- MEM_freeN(poly_keys);
- }
-
- /*create new cddm*/
- result = BKE_mesh_new_nomain_from_template(
- mesh, STACK_SIZE(mvert), STACK_SIZE(medge), 0, STACK_SIZE(mloop), STACK_SIZE(mpoly));
-
- /*update edge indices and copy customdata*/
- med = medge;
- for (i = 0; i < result->totedge; i++, med++) {
- BLI_assert(newv[med->v1] != -1);
- med->v1 = newv[med->v1];
- BLI_assert(newv[med->v2] != -1);
- med->v2 = newv[med->v2];
-
- /* Can happen in case vtargetmap contains some double chains, we do not support that. */
- BLI_assert(med->v1 != med->v2);
-
- CustomData_copy_data(&mesh->edata, &result->edata, olde[i], i, 1);
- }
-
- /*update loop indices and copy customdata*/
- ml = mloop;
- for (i = 0; i < result->totloop; i++, ml++) {
- /* Edge remapping has already be done in main loop handling part above. */
- BLI_assert(newv[ml->v] != -1);
- ml->v = newv[ml->v];
-
- CustomData_copy_data(&mesh->ldata, &result->ldata, oldl[i], i, 1);
- }
-
- /*copy vertex customdata*/
- mv = mvert;
- for (i = 0; i < result->totvert; i++, mv++) {
- CustomData_copy_data(&mesh->vdata, &result->vdata, oldv[i], i, 1);
- }
-
- /*copy poly customdata*/
- mp = mpoly;
- for (i = 0; i < result->totpoly; i++, mp++) {
- CustomData_copy_data(&mesh->pdata, &result->pdata, oldp[i], i, 1);
- }
-
- /*copy over data. CustomData_add_layer can do this, need to look it up.*/
- memcpy(result->mvert, mvert, sizeof(MVert) * STACK_SIZE(mvert));
- memcpy(result->medge, medge, sizeof(MEdge) * STACK_SIZE(medge));
- memcpy(result->mloop, mloop, sizeof(MLoop) * STACK_SIZE(mloop));
- memcpy(result->mpoly, mpoly, sizeof(MPoly) * STACK_SIZE(mpoly));
-
- MEM_freeN(mvert);
- MEM_freeN(medge);
- MEM_freeN(mloop);
- MEM_freeN(mpoly);
-
- MEM_freeN(newv);
- MEM_freeN(newe);
+ STACK_PUSH(oldl, j + mp->loopstart);
+ last_valid_ml = STACK_PUSH_RET_PTR(mloop);
+ *last_valid_ml = *ml;
+ if (first_valid_ml == NULL) {
+ first_valid_ml = last_valid_ml;
+ }
+ c++;
+
+ /* We absolutely HAVE to handle edge index remapping here, otherwise potential newly created edges
+ * in that part of code make remapping later totally unreliable. */
+ BLI_assert(newe[ml->e] != -1);
+ last_valid_ml->e = newe[ml->e];
+ }
+ else {
+ if (last_valid_ml != NULL) {
+ need_edge_from_last_valid_ml = true;
+ }
+ else {
+ need_edge_to_first_valid_ml = true;
+ }
+ }
+ }
+ if (UNLIKELY(last_valid_ml != NULL && !ELEM(first_valid_ml, NULL, last_valid_ml) &&
+ (need_edge_to_first_valid_ml || need_edge_from_last_valid_ml))) {
+ /* We need to create a new edge between last valid loop and first valid one! */
+ void **val_p;
+
+ uint v1 = (vtargetmap[last_valid_ml->v] != -1) ? vtargetmap[last_valid_ml->v] :
+ last_valid_ml->v;
+ uint v2 = (vtargetmap[first_valid_ml->v] != -1) ? vtargetmap[first_valid_ml->v] :
+ first_valid_ml->v;
+ BLI_assert(v1 != v2);
+ if (BLI_edgehash_ensure_p(ehash, v1, v2, &val_p)) {
+ last_valid_ml->e = POINTER_AS_INT(*val_p);
+ }
+ else {
+ const int new_eidx = STACK_SIZE(medge);
+ STACK_PUSH(olde, olde[last_valid_ml->e]);
+ STACK_PUSH(medge, mesh->medge[last_valid_ml->e]);
+ medge[new_eidx].v1 = last_valid_ml->v;
+ medge[new_eidx].v2 = first_valid_ml->v;
+ /* DO NOT change newe mapping, could break actual values due to some deleted original edges. */
+ *val_p = POINTER_FROM_INT(new_eidx);
+ created_edges++;
+
+ last_valid_ml->e = new_eidx;
+ }
+ need_edge_to_first_valid_ml = need_edge_from_last_valid_ml = false;
+ }
+
+ if (UNLIKELY(c == 0)) {
+ BLI_assert(created_edges == 0);
+ continue;
+ }
+ else if (UNLIKELY(c < 3)) {
+ STACK_DISCARD(oldl, c);
+ STACK_DISCARD(mloop, c);
+ if (created_edges > 0) {
+ for (j = STACK_SIZE(medge) - created_edges; j < STACK_SIZE(medge); j++) {
+ BLI_edgehash_remove(ehash, medge[j].v1, medge[j].v2, NULL);
+ }
+ STACK_DISCARD(olde, created_edges);
+ STACK_DISCARD(medge, created_edges);
+ }
+ continue;
+ }
+
+ mp_new = STACK_PUSH_RET_PTR(mpoly);
+ *mp_new = *mp;
+ mp_new->totloop = c;
+ BLI_assert(mp_new->totloop >= 3);
+ mp_new->loopstart = STACK_SIZE(mloop) - c;
+
+ STACK_PUSH(oldp, i);
+ } /* end of the loop that tests polys */
+
+ if (poly_gset) {
+ // printf("hash quality %.6f\n", BLI_gset_calc_quality(poly_gset));
+
+ BLI_gset_free(poly_gset, NULL);
+ MEM_freeN(poly_keys);
+ }
+
+ /*create new cddm*/
+ result = BKE_mesh_new_nomain_from_template(
+ mesh, STACK_SIZE(mvert), STACK_SIZE(medge), 0, STACK_SIZE(mloop), STACK_SIZE(mpoly));
+
+ /*update edge indices and copy customdata*/
+ med = medge;
+ for (i = 0; i < result->totedge; i++, med++) {
+ BLI_assert(newv[med->v1] != -1);
+ med->v1 = newv[med->v1];
+ BLI_assert(newv[med->v2] != -1);
+ med->v2 = newv[med->v2];
+
+ /* Can happen in case vtargetmap contains some double chains, we do not support that. */
+ BLI_assert(med->v1 != med->v2);
+
+ CustomData_copy_data(&mesh->edata, &result->edata, olde[i], i, 1);
+ }
+
+ /*update loop indices and copy customdata*/
+ ml = mloop;
+ for (i = 0; i < result->totloop; i++, ml++) {
+ /* Edge remapping has already be done in main loop handling part above. */
+ BLI_assert(newv[ml->v] != -1);
+ ml->v = newv[ml->v];
+
+ CustomData_copy_data(&mesh->ldata, &result->ldata, oldl[i], i, 1);
+ }
+
+ /*copy vertex customdata*/
+ mv = mvert;
+ for (i = 0; i < result->totvert; i++, mv++) {
+ CustomData_copy_data(&mesh->vdata, &result->vdata, oldv[i], i, 1);
+ }
+
+ /*copy poly customdata*/
+ mp = mpoly;
+ for (i = 0; i < result->totpoly; i++, mp++) {
+ CustomData_copy_data(&mesh->pdata, &result->pdata, oldp[i], i, 1);
+ }
+
+ /*copy over data. CustomData_add_layer can do this, need to look it up.*/
+ memcpy(result->mvert, mvert, sizeof(MVert) * STACK_SIZE(mvert));
+ memcpy(result->medge, medge, sizeof(MEdge) * STACK_SIZE(medge));
+ memcpy(result->mloop, mloop, sizeof(MLoop) * STACK_SIZE(mloop));
+ memcpy(result->mpoly, mpoly, sizeof(MPoly) * STACK_SIZE(mpoly));
+
+ MEM_freeN(mvert);
+ MEM_freeN(medge);
+ MEM_freeN(mloop);
+ MEM_freeN(mpoly);
+
+ MEM_freeN(newv);
+ MEM_freeN(newe);
#ifdef USE_LOOPS
- MEM_freeN(newl);
+ MEM_freeN(newl);
#endif
- MEM_freeN(oldv);
- MEM_freeN(olde);
- MEM_freeN(oldl);
- MEM_freeN(oldp);
+ MEM_freeN(oldv);
+ MEM_freeN(olde);
+ MEM_freeN(oldl);
+ MEM_freeN(oldp);
- BLI_edgehash_free(ehash, NULL);
+ BLI_edgehash_free(ehash, NULL);
- if (poly_map != NULL)
- MEM_freeN(poly_map);
- if (poly_map_mem != NULL)
- MEM_freeN(poly_map_mem);
+ if (poly_map != NULL)
+ MEM_freeN(poly_map);
+ if (poly_map_mem != NULL)
+ MEM_freeN(poly_map_mem);
- BKE_id_free(NULL, mesh);
+ BKE_id_free(NULL, mesh);
- return result;
+ return result;
}
diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c
index 7219332774a..b43339bf73f 100644
--- a/source/blender/blenkernel/intern/mesh_remap.c
+++ b/source/blender/blenkernel/intern/mesh_remap.c
@@ -42,7 +42,7 @@
#include "BKE_customdata.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
-#include "BKE_mesh_remap.h" /* own include */
+#include "BKE_mesh_remap.h" /* own include */
#include "BKE_mesh_runtime.h"
#include "BLI_strict_flags.h"
@@ -53,55 +53,63 @@ static CLG_LogRef LOG = {"bke.mesh"};
/** \name Some generic helpers.
* \{ */
-static bool mesh_remap_bvhtree_query_nearest(
- BVHTreeFromMesh *treedata, BVHTreeNearest *nearest,
- const float co[3], const float max_dist_sq, float *r_hit_dist)
+static bool mesh_remap_bvhtree_query_nearest(BVHTreeFromMesh *treedata,
+ BVHTreeNearest *nearest,
+ const float co[3],
+ const float max_dist_sq,
+ float *r_hit_dist)
{
- /* Use local proximity heuristics (to reduce the nearest search). */
- if (nearest->index != -1) {
- nearest->dist_sq = min_ff(len_squared_v3v3(co, nearest->co), max_dist_sq);
- }
- else {
- nearest->dist_sq = max_dist_sq;
- }
- /* Compute and store result. If invalid (-1 index), keep FLT_MAX dist. */
- BLI_bvhtree_find_nearest(treedata->tree, co, nearest, treedata->nearest_callback, treedata);
-
- if ((nearest->index != -1) && (nearest->dist_sq <= max_dist_sq)) {
- *r_hit_dist = sqrtf(nearest->dist_sq);
- return true;
- }
- else {
- return false;
- }
+ /* Use local proximity heuristics (to reduce the nearest search). */
+ if (nearest->index != -1) {
+ nearest->dist_sq = min_ff(len_squared_v3v3(co, nearest->co), max_dist_sq);
+ }
+ else {
+ nearest->dist_sq = max_dist_sq;
+ }
+ /* Compute and store result. If invalid (-1 index), keep FLT_MAX dist. */
+ BLI_bvhtree_find_nearest(treedata->tree, co, nearest, treedata->nearest_callback, treedata);
+
+ if ((nearest->index != -1) && (nearest->dist_sq <= max_dist_sq)) {
+ *r_hit_dist = sqrtf(nearest->dist_sq);
+ return true;
+ }
+ else {
+ return false;
+ }
}
-static bool mesh_remap_bvhtree_query_raycast(
- BVHTreeFromMesh *treedata, BVHTreeRayHit *rayhit,
- const float co[3], const float no[3], const float radius, const float max_dist, float *r_hit_dist)
+static bool mesh_remap_bvhtree_query_raycast(BVHTreeFromMesh *treedata,
+ BVHTreeRayHit *rayhit,
+ const float co[3],
+ const float no[3],
+ const float radius,
+ const float max_dist,
+ float *r_hit_dist)
{
- BVHTreeRayHit rayhit_tmp;
- float inv_no[3];
-
- rayhit->index = -1;
- rayhit->dist = max_dist;
- BLI_bvhtree_ray_cast(treedata->tree, co, no, radius, rayhit, treedata->raycast_callback, treedata);
-
- /* Also cast in the other direction! */
- rayhit_tmp = *rayhit;
- negate_v3_v3(inv_no, no);
- BLI_bvhtree_ray_cast(treedata->tree, co, inv_no, radius, &rayhit_tmp, treedata->raycast_callback, treedata);
- if (rayhit_tmp.dist < rayhit->dist) {
- *rayhit = rayhit_tmp;
- }
-
- if ((rayhit->index != -1) && (rayhit->dist <= max_dist)) {
- *r_hit_dist = rayhit->dist;
- return true;
- }
- else {
- return false;
- }
+ BVHTreeRayHit rayhit_tmp;
+ float inv_no[3];
+
+ rayhit->index = -1;
+ rayhit->dist = max_dist;
+ BLI_bvhtree_ray_cast(
+ treedata->tree, co, no, radius, rayhit, treedata->raycast_callback, treedata);
+
+ /* Also cast in the other direction! */
+ rayhit_tmp = *rayhit;
+ negate_v3_v3(inv_no, no);
+ BLI_bvhtree_ray_cast(
+ treedata->tree, co, inv_no, radius, &rayhit_tmp, treedata->raycast_callback, treedata);
+ if (rayhit_tmp.dist < rayhit->dist) {
+ *rayhit = rayhit_tmp;
+ }
+
+ if ((rayhit->index != -1) && (rayhit->dist <= max_dist)) {
+ *r_hit_dist = rayhit->dist;
+ return true;
+ }
+ else {
+ return false;
+ }
}
/** \} */
@@ -120,43 +128,45 @@ static bool mesh_remap_bvhtree_query_raycast(
* In other words, beyond a certain (relatively small) distance, all differences have more or less the same weight
* in final result, which allows to reduce influence of a few high differences, in favor of a global good matching.
*/
-float BKE_mesh_remap_calc_difference_from_mesh(
- const SpaceTransform *space_transform, const MVert *verts_dst, const int numverts_dst, Mesh *me_src)
+float BKE_mesh_remap_calc_difference_from_mesh(const SpaceTransform *space_transform,
+ const MVert *verts_dst,
+ const int numverts_dst,
+ Mesh *me_src)
{
- BVHTreeFromMesh treedata = {NULL};
- BVHTreeNearest nearest = {0};
- float hit_dist;
+ BVHTreeFromMesh treedata = {NULL};
+ BVHTreeNearest nearest = {0};
+ float hit_dist;
- float result = 0.0f;
- int i;
+ float result = 0.0f;
+ int i;
- BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_VERTS, 2);
- nearest.index = -1;
+ BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_VERTS, 2);
+ nearest.index = -1;
- for (i = 0; i < numverts_dst; i++) {
- float tmp_co[3];
+ for (i = 0; i < numverts_dst; i++) {
+ float tmp_co[3];
- copy_v3_v3(tmp_co, verts_dst[i].co);
+ copy_v3_v3(tmp_co, verts_dst[i].co);
- /* Convert the vertex to tree coordinates, if needed. */
- if (space_transform) {
- BLI_space_transform_apply(space_transform, tmp_co);
- }
+ /* Convert the vertex to tree coordinates, if needed. */
+ if (space_transform) {
+ BLI_space_transform_apply(space_transform, tmp_co);
+ }
- if (mesh_remap_bvhtree_query_nearest(&treedata, &nearest, tmp_co, FLT_MAX, &hit_dist)) {
- result += 1.0f / (hit_dist + 1.0f);
- }
- else {
- /* No source for this dest vertex! */
- result += 1e-18f;
- }
- }
+ if (mesh_remap_bvhtree_query_nearest(&treedata, &nearest, tmp_co, FLT_MAX, &hit_dist)) {
+ result += 1.0f / (hit_dist + 1.0f);
+ }
+ else {
+ /* No source for this dest vertex! */
+ result += 1e-18f;
+ }
+ }
- result = ((float)numverts_dst / result) - 1.0f;
+ result = ((float)numverts_dst / result) - 1.0f;
-// printf("%s: Computed difference between meshes (the lower the better): %f\n", __func__, result);
+ // printf("%s: Computed difference between meshes (the lower the better): %f\n", __func__, result);
- return result;
+ return result;
}
/* This helper computes the eigen values & vectors for covariance matrix of all given vertices coordinates.
@@ -169,133 +179,139 @@ float BKE_mesh_remap_calc_difference_from_mesh(
* three identical ones, etc.), since you cannot really define all axes in those cases. We default to dummy
* generated orthogonal vectors in this case, instead of using eigen vectors.
*/
-static void mesh_calc_eigen_matrix(
- const MVert *verts, const float (*vcos)[3], const int numverts, float r_mat[4][4])
+static void mesh_calc_eigen_matrix(const MVert *verts,
+ const float (*vcos)[3],
+ const int numverts,
+ float r_mat[4][4])
{
- float center[3], covmat[3][3];
- float eigen_val[3], eigen_vec[3][3];
- float (*cos)[3] = NULL;
-
- bool eigen_success;
- int i;
-
- if (verts) {
- const MVert *mv;
- float (*co)[3];
-
- cos = MEM_mallocN(sizeof(*cos) * (size_t)numverts, __func__);
- for (i = 0, co = cos, mv = verts; i < numverts; i++, co++, mv++) {
- copy_v3_v3(*co, mv->co);
- }
- /* TODO(sergey): For until we officially drop all compilers which
- * doesn't handle casting correct we use workaround to avoid explicit
- * cast here.
- */
- vcos = (void *)cos;
- }
- unit_m4(r_mat);
-
- /* Note: here we apply sample correction to covariance matrix, since we consider the vertices as a sample
- * of the whole 'surface' population of our mesh... */
- BLI_covariance_m3_v3n(vcos, numverts, true, covmat, center);
-
- if (cos) {
- MEM_freeN(cos);
- }
-
- eigen_success = BLI_eigen_solve_selfadjoint_m3((const float (*)[3])covmat, eigen_val, eigen_vec);
- BLI_assert(eigen_success);
- UNUSED_VARS_NDEBUG(eigen_success);
-
- /* Special handling of cases where some eigen values are (nearly) identical. */
- if (compare_ff_relative(eigen_val[0], eigen_val[1], FLT_EPSILON, 64)) {
- if (compare_ff_relative(eigen_val[0], eigen_val[2], FLT_EPSILON, 64)) {
- /* No preferred direction, that set of vertices has a spherical average,
- * so we simply returned scaled/translated identity matrix (with no rotation). */
- unit_m3(eigen_vec);
- }
- else {
- /* Ellipsoid defined by eigen values/vectors has a spherical section,
- * we can only define one axis from eigen_vec[2] (two others computed eigen vecs
- * are not so nice for us here, they tend to 'randomly' rotate around valid one).
- * Note that eigen vectors as returned by BLI_eigen_solve_selfadjoint_m3() are normalized. */
- ortho_basis_v3v3_v3(eigen_vec[0], eigen_vec[1], eigen_vec[2]);
- }
- }
- else if (compare_ff_relative(eigen_val[0], eigen_val[2], FLT_EPSILON, 64)) {
- /* Same as above, but with eigen_vec[1] as valid axis. */
- ortho_basis_v3v3_v3(eigen_vec[2], eigen_vec[0], eigen_vec[1]);
- }
- else if (compare_ff_relative(eigen_val[1], eigen_val[2], FLT_EPSILON, 64)) {
- /* Same as above, but with eigen_vec[0] as valid axis. */
- ortho_basis_v3v3_v3(eigen_vec[1], eigen_vec[2], eigen_vec[0]);
- }
-
- for (i = 0; i < 3; i++) {
- float evi = eigen_val[i];
-
- /* Protect against 1D/2D degenerated cases! */
- /* Note: not sure why we need square root of eigen values here (which are equivalent to singular values,
- * as far as I have understood), but it seems to heavily reduce (if not completely nullify)
- * the error due to non-uniform scalings... */
- evi = (evi < 1e-6f && evi > -1e-6f) ? ((evi < 0.0f) ? -1e-3f : 1e-3f) : sqrtf_signed(evi);
- mul_v3_fl(eigen_vec[i], evi);
- }
-
- copy_m4_m3(r_mat, eigen_vec);
- copy_v3_v3(r_mat[3], center);
+ float center[3], covmat[3][3];
+ float eigen_val[3], eigen_vec[3][3];
+ float(*cos)[3] = NULL;
+
+ bool eigen_success;
+ int i;
+
+ if (verts) {
+ const MVert *mv;
+ float(*co)[3];
+
+ cos = MEM_mallocN(sizeof(*cos) * (size_t)numverts, __func__);
+ for (i = 0, co = cos, mv = verts; i < numverts; i++, co++, mv++) {
+ copy_v3_v3(*co, mv->co);
+ }
+ /* TODO(sergey): For until we officially drop all compilers which
+ * doesn't handle casting correct we use workaround to avoid explicit
+ * cast here.
+ */
+ vcos = (void *)cos;
+ }
+ unit_m4(r_mat);
+
+ /* Note: here we apply sample correction to covariance matrix, since we consider the vertices as a sample
+ * of the whole 'surface' population of our mesh... */
+ BLI_covariance_m3_v3n(vcos, numverts, true, covmat, center);
+
+ if (cos) {
+ MEM_freeN(cos);
+ }
+
+ eigen_success = BLI_eigen_solve_selfadjoint_m3((const float(*)[3])covmat, eigen_val, eigen_vec);
+ BLI_assert(eigen_success);
+ UNUSED_VARS_NDEBUG(eigen_success);
+
+ /* Special handling of cases where some eigen values are (nearly) identical. */
+ if (compare_ff_relative(eigen_val[0], eigen_val[1], FLT_EPSILON, 64)) {
+ if (compare_ff_relative(eigen_val[0], eigen_val[2], FLT_EPSILON, 64)) {
+ /* No preferred direction, that set of vertices has a spherical average,
+ * so we simply returned scaled/translated identity matrix (with no rotation). */
+ unit_m3(eigen_vec);
+ }
+ else {
+ /* Ellipsoid defined by eigen values/vectors has a spherical section,
+ * we can only define one axis from eigen_vec[2] (two others computed eigen vecs
+ * are not so nice for us here, they tend to 'randomly' rotate around valid one).
+ * Note that eigen vectors as returned by BLI_eigen_solve_selfadjoint_m3() are normalized. */
+ ortho_basis_v3v3_v3(eigen_vec[0], eigen_vec[1], eigen_vec[2]);
+ }
+ }
+ else if (compare_ff_relative(eigen_val[0], eigen_val[2], FLT_EPSILON, 64)) {
+ /* Same as above, but with eigen_vec[1] as valid axis. */
+ ortho_basis_v3v3_v3(eigen_vec[2], eigen_vec[0], eigen_vec[1]);
+ }
+ else if (compare_ff_relative(eigen_val[1], eigen_val[2], FLT_EPSILON, 64)) {
+ /* Same as above, but with eigen_vec[0] as valid axis. */
+ ortho_basis_v3v3_v3(eigen_vec[1], eigen_vec[2], eigen_vec[0]);
+ }
+
+ for (i = 0; i < 3; i++) {
+ float evi = eigen_val[i];
+
+ /* Protect against 1D/2D degenerated cases! */
+ /* Note: not sure why we need square root of eigen values here (which are equivalent to singular values,
+ * as far as I have understood), but it seems to heavily reduce (if not completely nullify)
+ * the error due to non-uniform scalings... */
+ evi = (evi < 1e-6f && evi > -1e-6f) ? ((evi < 0.0f) ? -1e-3f : 1e-3f) : sqrtf_signed(evi);
+ mul_v3_fl(eigen_vec[i], evi);
+ }
+
+ copy_m4_m3(r_mat, eigen_vec);
+ copy_v3_v3(r_mat[3], center);
}
/**
* Set r_space_transform so that best bbox of dst matches best bbox of src.
*/
-void BKE_mesh_remap_find_best_match_from_mesh(
- const MVert *verts_dst, const int numverts_dst, Mesh *me_src, SpaceTransform *r_space_transform)
+void BKE_mesh_remap_find_best_match_from_mesh(const MVert *verts_dst,
+ const int numverts_dst,
+ Mesh *me_src,
+ SpaceTransform *r_space_transform)
{
- /* Note that those are done so that we successively get actual mirror matrix (by multiplication of columns)... */
- const float mirrors[][3] = {
- {-1.0f, 1.0f, 1.0f}, /* -> -1, 1, 1 */
- { 1.0f, -1.0f, 1.0f}, /* -> -1, -1, 1 */
- { 1.0f, 1.0f, -1.0f}, /* -> -1, -1, -1 */
- { 1.0f, -1.0f, 1.0f}, /* -> -1, 1, -1 */
- {-1.0f, 1.0f, 1.0f}, /* -> 1, 1, -1 */
- { 1.0f, -1.0f, 1.0f}, /* -> 1, -1, -1 */
- { 1.0f, 1.0f, -1.0f}, /* -> 1, -1, 1 */
- {0.0f, 0.0f, 0.0f},
- };
- const float (*mirr)[3];
-
- float mat_src[4][4], mat_dst[4][4], best_mat_dst[4][4];
- float best_match = FLT_MAX, match;
-
- const int numverts_src = me_src->totvert;
- float (*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL);
-
- mesh_calc_eigen_matrix(NULL, (const float (*)[3])vcos_src, numverts_src, mat_src);
- mesh_calc_eigen_matrix(verts_dst, NULL, numverts_dst, mat_dst);
-
- BLI_space_transform_global_from_matrices(r_space_transform, mat_dst, mat_src);
- match = BKE_mesh_remap_calc_difference_from_mesh(r_space_transform, verts_dst, numverts_dst, me_src);
- best_match = match;
- copy_m4_m4(best_mat_dst, mat_dst);
-
- /* And now, we have to check the other sixth possible mirrored versions... */
- for (mirr = mirrors; (*mirr)[0]; mirr++) {
- mul_v3_fl(mat_dst[0], (*mirr)[0]);
- mul_v3_fl(mat_dst[1], (*mirr)[1]);
- mul_v3_fl(mat_dst[2], (*mirr)[2]);
-
- BLI_space_transform_global_from_matrices(r_space_transform, mat_dst, mat_src);
- match = BKE_mesh_remap_calc_difference_from_mesh(r_space_transform, verts_dst, numverts_dst, me_src);
- if (match < best_match) {
- best_match = match;
- copy_m4_m4(best_mat_dst, mat_dst);
- }
- }
-
- BLI_space_transform_global_from_matrices(r_space_transform, best_mat_dst, mat_src);
-
- MEM_freeN(vcos_src);
+ /* Note that those are done so that we successively get actual mirror matrix (by multiplication of columns)... */
+ const float mirrors[][3] = {
+ {-1.0f, 1.0f, 1.0f}, /* -> -1, 1, 1 */
+ {1.0f, -1.0f, 1.0f}, /* -> -1, -1, 1 */
+ {1.0f, 1.0f, -1.0f}, /* -> -1, -1, -1 */
+ {1.0f, -1.0f, 1.0f}, /* -> -1, 1, -1 */
+ {-1.0f, 1.0f, 1.0f}, /* -> 1, 1, -1 */
+ {1.0f, -1.0f, 1.0f}, /* -> 1, -1, -1 */
+ {1.0f, 1.0f, -1.0f}, /* -> 1, -1, 1 */
+ {0.0f, 0.0f, 0.0f},
+ };
+ const float(*mirr)[3];
+
+ float mat_src[4][4], mat_dst[4][4], best_mat_dst[4][4];
+ float best_match = FLT_MAX, match;
+
+ const int numverts_src = me_src->totvert;
+ float(*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL);
+
+ mesh_calc_eigen_matrix(NULL, (const float(*)[3])vcos_src, numverts_src, mat_src);
+ mesh_calc_eigen_matrix(verts_dst, NULL, numverts_dst, mat_dst);
+
+ BLI_space_transform_global_from_matrices(r_space_transform, mat_dst, mat_src);
+ match = BKE_mesh_remap_calc_difference_from_mesh(
+ r_space_transform, verts_dst, numverts_dst, me_src);
+ best_match = match;
+ copy_m4_m4(best_mat_dst, mat_dst);
+
+ /* And now, we have to check the other sixth possible mirrored versions... */
+ for (mirr = mirrors; (*mirr)[0]; mirr++) {
+ mul_v3_fl(mat_dst[0], (*mirr)[0]);
+ mul_v3_fl(mat_dst[1], (*mirr)[1]);
+ mul_v3_fl(mat_dst[2], (*mirr)[2]);
+
+ BLI_space_transform_global_from_matrices(r_space_transform, mat_dst, mat_src);
+ match = BKE_mesh_remap_calc_difference_from_mesh(
+ r_space_transform, verts_dst, numverts_dst, me_src);
+ if (match < best_match) {
+ best_match = match;
+ copy_m4_m4(best_mat_dst, mat_dst);
+ }
+ }
+
+ BLI_space_transform_global_from_matrices(r_space_transform, best_mat_dst, mat_src);
+
+ MEM_freeN(vcos_src);
}
/** \} */
@@ -303,121 +319,139 @@ void BKE_mesh_remap_find_best_match_from_mesh(
/** \name Mesh to mesh mapping
* \{ */
-void BKE_mesh_remap_calc_source_cddata_masks_from_map_modes(
- const int UNUSED(vert_mode), const int UNUSED(edge_mode), const int loop_mode, const int UNUSED(poly_mode),
- CustomData_MeshMasks *cddata_mask)
+void BKE_mesh_remap_calc_source_cddata_masks_from_map_modes(const int UNUSED(vert_mode),
+ const int UNUSED(edge_mode),
+ const int loop_mode,
+ const int UNUSED(poly_mode),
+ CustomData_MeshMasks *cddata_mask)
{
- /* vert, edge and poly mapping modes never need extra cddata from source object. */
- const bool need_lnors_src = (loop_mode & MREMAP_USE_LOOP) && (loop_mode & MREMAP_USE_NORMAL);
- const bool need_pnors_src = need_lnors_src || ((loop_mode & MREMAP_USE_POLY) && (loop_mode & MREMAP_USE_NORMAL));
-
- if (need_lnors_src) {
- cddata_mask->lmask |= CD_MASK_NORMAL;
- }
- if (need_pnors_src) {
- cddata_mask->pmask |= CD_MASK_NORMAL;
- }
+ /* vert, edge and poly mapping modes never need extra cddata from source object. */
+ const bool need_lnors_src = (loop_mode & MREMAP_USE_LOOP) && (loop_mode & MREMAP_USE_NORMAL);
+ const bool need_pnors_src = need_lnors_src ||
+ ((loop_mode & MREMAP_USE_POLY) && (loop_mode & MREMAP_USE_NORMAL));
+
+ if (need_lnors_src) {
+ cddata_mask->lmask |= CD_MASK_NORMAL;
+ }
+ if (need_pnors_src) {
+ cddata_mask->pmask |= CD_MASK_NORMAL;
+ }
}
void BKE_mesh_remap_init(MeshPairRemap *map, const int items_num)
{
- MemArena *mem = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+ MemArena *mem = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
- BKE_mesh_remap_free(map);
+ BKE_mesh_remap_free(map);
- map->items = BLI_memarena_alloc(mem, sizeof(*map->items) * (size_t)items_num);
- map->items_num = items_num;
+ map->items = BLI_memarena_alloc(mem, sizeof(*map->items) * (size_t)items_num);
+ map->items_num = items_num;
- map->mem = mem;
+ map->mem = mem;
}
void BKE_mesh_remap_free(MeshPairRemap *map)
{
- if (map->mem) {
- BLI_memarena_free((MemArena *)map->mem);
- }
+ if (map->mem) {
+ BLI_memarena_free((MemArena *)map->mem);
+ }
- map->items_num = 0;
- map->items = NULL;
- map->mem = NULL;
+ map->items_num = 0;
+ map->items = NULL;
+ map->mem = NULL;
}
-static void mesh_remap_item_define(
- MeshPairRemap *map, const int index, const float UNUSED(hit_dist), const int island,
- const int sources_num, const int *indices_src, const float *weights_src)
+static void mesh_remap_item_define(MeshPairRemap *map,
+ const int index,
+ const float UNUSED(hit_dist),
+ const int island,
+ const int sources_num,
+ const int *indices_src,
+ const float *weights_src)
{
- MeshPairRemapItem *mapit = &map->items[index];
- MemArena *mem = map->mem;
-
- if (sources_num) {
- mapit->sources_num = sources_num;
- mapit->indices_src = BLI_memarena_alloc(mem, sizeof(*mapit->indices_src) * (size_t)sources_num);
- memcpy(mapit->indices_src, indices_src, sizeof(*mapit->indices_src) * (size_t)sources_num);
- mapit->weights_src = BLI_memarena_alloc(mem, sizeof(*mapit->weights_src) * (size_t)sources_num);
- memcpy(mapit->weights_src, weights_src, sizeof(*mapit->weights_src) * (size_t)sources_num);
- }
- else {
- mapit->sources_num = 0;
- mapit->indices_src = NULL;
- mapit->weights_src = NULL;
- }
- /* UNUSED */
- // mapit->hit_dist = hit_dist;
- mapit->island = island;
+ MeshPairRemapItem *mapit = &map->items[index];
+ MemArena *mem = map->mem;
+
+ if (sources_num) {
+ mapit->sources_num = sources_num;
+ mapit->indices_src = BLI_memarena_alloc(mem,
+ sizeof(*mapit->indices_src) * (size_t)sources_num);
+ memcpy(mapit->indices_src, indices_src, sizeof(*mapit->indices_src) * (size_t)sources_num);
+ mapit->weights_src = BLI_memarena_alloc(mem,
+ sizeof(*mapit->weights_src) * (size_t)sources_num);
+ memcpy(mapit->weights_src, weights_src, sizeof(*mapit->weights_src) * (size_t)sources_num);
+ }
+ else {
+ mapit->sources_num = 0;
+ mapit->indices_src = NULL;
+ mapit->weights_src = NULL;
+ }
+ /* UNUSED */
+ // mapit->hit_dist = hit_dist;
+ mapit->island = island;
}
void BKE_mesh_remap_item_define_invalid(MeshPairRemap *map, const int index)
{
- mesh_remap_item_define(map, index, FLT_MAX, 0, 0, NULL, NULL);
+ mesh_remap_item_define(map, index, FLT_MAX, 0, 0, NULL, NULL);
}
-static int mesh_remap_interp_poly_data_get(
- const MPoly *mp, MLoop *mloops, const float (*vcos_src)[3], const float point[3],
- size_t *buff_size, float (**vcos)[3], const bool use_loops, int **indices, float **weights,
- const bool do_weights, int *r_closest_index)
+static int mesh_remap_interp_poly_data_get(const MPoly *mp,
+ MLoop *mloops,
+ const float (*vcos_src)[3],
+ const float point[3],
+ size_t *buff_size,
+ float (**vcos)[3],
+ const bool use_loops,
+ int **indices,
+ float **weights,
+ const bool do_weights,
+ int *r_closest_index)
{
- MLoop *ml;
- float (*vco)[3];
- float ref_dist_sq = FLT_MAX;
- int *index;
- const int sources_num = mp->totloop;
- int i;
-
- if ((size_t)sources_num > *buff_size) {
- *buff_size = (size_t)sources_num;
- *vcos = MEM_reallocN(*vcos, sizeof(**vcos) * *buff_size);
- *indices = MEM_reallocN(*indices, sizeof(**indices) * *buff_size);
- if (do_weights) {
- *weights = MEM_reallocN(*weights, sizeof(**weights) * *buff_size);
- }
- }
-
- for (i = 0, ml = &mloops[mp->loopstart], vco = *vcos, index = *indices; i < sources_num; i++, ml++, vco++, index++) {
- *index = use_loops ? (int)mp->loopstart + i : (int)ml->v;
- copy_v3_v3(*vco, vcos_src[ml->v]);
- if (r_closest_index) {
- /* Find closest vert/loop in this case. */
- const float dist_sq = len_squared_v3v3(point, *vco);
- if (dist_sq < ref_dist_sq) {
- ref_dist_sq = dist_sq;
- *r_closest_index = *index;
- }
- }
- }
-
- if (do_weights) {
- interp_weights_poly_v3(*weights, *vcos, sources_num, point);
- }
-
- return sources_num;
+ MLoop *ml;
+ float(*vco)[3];
+ float ref_dist_sq = FLT_MAX;
+ int *index;
+ const int sources_num = mp->totloop;
+ int i;
+
+ if ((size_t)sources_num > *buff_size) {
+ *buff_size = (size_t)sources_num;
+ *vcos = MEM_reallocN(*vcos, sizeof(**vcos) * *buff_size);
+ *indices = MEM_reallocN(*indices, sizeof(**indices) * *buff_size);
+ if (do_weights) {
+ *weights = MEM_reallocN(*weights, sizeof(**weights) * *buff_size);
+ }
+ }
+
+ for (i = 0, ml = &mloops[mp->loopstart], vco = *vcos, index = *indices; i < sources_num;
+ i++, ml++, vco++, index++) {
+ *index = use_loops ? (int)mp->loopstart + i : (int)ml->v;
+ copy_v3_v3(*vco, vcos_src[ml->v]);
+ if (r_closest_index) {
+ /* Find closest vert/loop in this case. */
+ const float dist_sq = len_squared_v3v3(point, *vco);
+ if (dist_sq < ref_dist_sq) {
+ ref_dist_sq = dist_sq;
+ *r_closest_index = *index;
+ }
+ }
+ }
+
+ if (do_weights) {
+ interp_weights_poly_v3(*weights, *vcos, sources_num, point);
+ }
+
+ return sources_num;
}
/* Little helper when dealing with source islands */
typedef struct IslandResult {
- float factor; /* A factor, based on which best island for a given set of elements will be selected. */
- int index_src; /* Index of the source. */
- float hit_dist; /* The actual hit distance. */
- float hit_point[3]; /* The hit point, if relevant. */
+ float
+ factor; /* A factor, based on which best island for a given set of elements will be selected. */
+ int index_src; /* Index of the source. */
+ float hit_dist; /* The actual hit distance. */
+ float hit_point[3]; /* The hit point, if relevant. */
} IslandResult;
/* Note about all bvh/raycasting stuff below:
@@ -444,644 +478,722 @@ typedef struct IslandResult {
/* Will be enough in 99% of cases. */
#define MREMAP_DEFAULT_BUFSIZE 32
-void BKE_mesh_remap_calc_verts_from_mesh(
- const int mode, const SpaceTransform *space_transform, const float max_dist, const float ray_radius,
- const MVert *verts_dst, const int numverts_dst, const bool UNUSED(dirty_nors_dst), Mesh *me_src,
- MeshPairRemap *r_map)
+void BKE_mesh_remap_calc_verts_from_mesh(const int mode,
+ const SpaceTransform *space_transform,
+ const float max_dist,
+ const float ray_radius,
+ const MVert *verts_dst,
+ const int numverts_dst,
+ const bool UNUSED(dirty_nors_dst),
+ Mesh *me_src,
+ MeshPairRemap *r_map)
{
- const float full_weight = 1.0f;
- const float max_dist_sq = max_dist * max_dist;
- int i;
-
- BLI_assert(mode & MREMAP_MODE_VERT);
-
- BKE_mesh_remap_init(r_map, numverts_dst);
-
- if (mode == MREMAP_MODE_TOPOLOGY) {
- BLI_assert(numverts_dst == me_src->totvert);
- for (i = 0; i < numverts_dst; i++) {
- mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight);
- }
- }
- else {
- BVHTreeFromMesh treedata = {NULL};
- BVHTreeNearest nearest = {0};
- BVHTreeRayHit rayhit = {0};
- float hit_dist;
- float tmp_co[3], tmp_no[3];
-
- if (mode == MREMAP_MODE_VERT_NEAREST) {
- BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_VERTS, 2);
- nearest.index = -1;
-
- for (i = 0; i < numverts_dst; i++) {
- copy_v3_v3(tmp_co, verts_dst[i].co);
-
- /* Convert the vertex to tree coordinates, if needed. */
- if (space_transform) {
- BLI_space_transform_apply(space_transform, tmp_co);
- }
-
- if (mesh_remap_bvhtree_query_nearest(&treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
- mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &nearest.index, &full_weight);
- }
- else {
- /* No source for this dest vertex! */
- BKE_mesh_remap_item_define_invalid(r_map, i);
- }
- }
- }
- else if (ELEM(mode, MREMAP_MODE_VERT_EDGE_NEAREST, MREMAP_MODE_VERT_EDGEINTERP_NEAREST)) {
- MEdge *edges_src = me_src->medge;
- float (*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL);
-
- BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_EDGES, 2);
- nearest.index = -1;
-
- for (i = 0; i < numverts_dst; i++) {
- copy_v3_v3(tmp_co, verts_dst[i].co);
-
- /* Convert the vertex to tree coordinates, if needed. */
- if (space_transform) {
- BLI_space_transform_apply(space_transform, tmp_co);
- }
-
- if (mesh_remap_bvhtree_query_nearest(&treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
- MEdge *me = &edges_src[nearest.index];
- const float *v1cos = vcos_src[me->v1];
- const float *v2cos = vcos_src[me->v2];
-
- if (mode == MREMAP_MODE_VERT_EDGE_NEAREST) {
- const float dist_v1 = len_squared_v3v3(tmp_co, v1cos);
- const float dist_v2 = len_squared_v3v3(tmp_co, v2cos);
- const int index = (int)((dist_v1 > dist_v2) ? me->v2 : me->v1);
- mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &index, &full_weight);
- }
- else if (mode == MREMAP_MODE_VERT_EDGEINTERP_NEAREST) {
- int indices[2];
- float weights[2];
-
- indices[0] = (int)me->v1;
- indices[1] = (int)me->v2;
-
- /* Weight is inverse of point factor here... */
- weights[0] = line_point_factor_v3(tmp_co, v2cos, v1cos);
- CLAMP(weights[0], 0.0f, 1.0f);
- weights[1] = 1.0f - weights[0];
-
- mesh_remap_item_define(r_map, i, hit_dist, 0, 2, indices, weights);
- }
- }
- else {
- /* No source for this dest vertex! */
- BKE_mesh_remap_item_define_invalid(r_map, i);
- }
- }
-
- MEM_freeN(vcos_src);
- }
- else if (ELEM(mode, MREMAP_MODE_VERT_POLY_NEAREST, MREMAP_MODE_VERT_POLYINTERP_NEAREST,
- MREMAP_MODE_VERT_POLYINTERP_VNORPROJ))
- {
- MPoly *polys_src = me_src->mpoly;
- MLoop *loops_src = me_src->mloop;
- float (*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL);
-
- size_t tmp_buff_size = MREMAP_DEFAULT_BUFSIZE;
- float (*vcos)[3] = MEM_mallocN(sizeof(*vcos) * tmp_buff_size, __func__);
- int *indices = MEM_mallocN(sizeof(*indices) * tmp_buff_size, __func__);
- float *weights = MEM_mallocN(sizeof(*weights) * tmp_buff_size, __func__);
-
- BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_LOOPTRI, 2);
-
- if (mode == MREMAP_MODE_VERT_POLYINTERP_VNORPROJ) {
- for (i = 0; i < numverts_dst; i++) {
- copy_v3_v3(tmp_co, verts_dst[i].co);
- normal_short_to_float_v3(tmp_no, verts_dst[i].no);
-
- /* Convert the vertex to tree coordinates, if needed. */
- if (space_transform) {
- BLI_space_transform_apply(space_transform, tmp_co);
- BLI_space_transform_apply_normal(space_transform, tmp_no);
- }
-
- if (mesh_remap_bvhtree_query_raycast(
- &treedata, &rayhit, tmp_co, tmp_no, ray_radius, max_dist, &hit_dist))
- {
- const MLoopTri *lt = &treedata.looptri[rayhit.index];
- MPoly *mp_src = &polys_src[lt->poly];
- const int sources_num = mesh_remap_interp_poly_data_get(
- mp_src, loops_src, (const float (*)[3])vcos_src, rayhit.co,
- &tmp_buff_size, &vcos, false, &indices, &weights, true, NULL);
-
- mesh_remap_item_define(r_map, i, hit_dist, 0, sources_num, indices, weights);
- }
- else {
- /* No source for this dest vertex! */
- BKE_mesh_remap_item_define_invalid(r_map, i);
- }
- }
- }
- else {
- nearest.index = -1;
-
- for (i = 0; i < numverts_dst; i++) {
- copy_v3_v3(tmp_co, verts_dst[i].co);
-
- /* Convert the vertex to tree coordinates, if needed. */
- if (space_transform) {
- BLI_space_transform_apply(space_transform, tmp_co);
- }
-
- if (mesh_remap_bvhtree_query_nearest(&treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
- const MLoopTri *lt = &treedata.looptri[nearest.index];
- MPoly *mp = &polys_src[lt->poly];
-
- if (mode == MREMAP_MODE_VERT_POLY_NEAREST) {
- int index;
- mesh_remap_interp_poly_data_get(
- mp, loops_src, (const float (*)[3])vcos_src, nearest.co,
- &tmp_buff_size, &vcos, false, &indices, &weights, false,
- &index);
-
- mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &index, &full_weight);
- }
- else if (mode == MREMAP_MODE_VERT_POLYINTERP_NEAREST) {
- const int sources_num = mesh_remap_interp_poly_data_get(
- mp, loops_src, (const float (*)[3])vcos_src, nearest.co,
- &tmp_buff_size, &vcos, false, &indices, &weights, true,
- NULL);
-
- mesh_remap_item_define(r_map, i, hit_dist, 0, sources_num, indices, weights);
- }
- }
- else {
- /* No source for this dest vertex! */
- BKE_mesh_remap_item_define_invalid(r_map, i);
- }
- }
- }
-
- MEM_freeN(vcos_src);
- MEM_freeN(vcos);
- MEM_freeN(indices);
- MEM_freeN(weights);
- }
- else {
- CLOG_WARN(&LOG, "Unsupported mesh-to-mesh vertex mapping mode (%d)!", mode);
- memset(r_map->items, 0, sizeof(*r_map->items) * (size_t)numverts_dst);
- }
-
- free_bvhtree_from_mesh(&treedata);
- }
+ const float full_weight = 1.0f;
+ const float max_dist_sq = max_dist * max_dist;
+ int i;
+
+ BLI_assert(mode & MREMAP_MODE_VERT);
+
+ BKE_mesh_remap_init(r_map, numverts_dst);
+
+ if (mode == MREMAP_MODE_TOPOLOGY) {
+ BLI_assert(numverts_dst == me_src->totvert);
+ for (i = 0; i < numverts_dst; i++) {
+ mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight);
+ }
+ }
+ else {
+ BVHTreeFromMesh treedata = {NULL};
+ BVHTreeNearest nearest = {0};
+ BVHTreeRayHit rayhit = {0};
+ float hit_dist;
+ float tmp_co[3], tmp_no[3];
+
+ if (mode == MREMAP_MODE_VERT_NEAREST) {
+ BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_VERTS, 2);
+ nearest.index = -1;
+
+ for (i = 0; i < numverts_dst; i++) {
+ copy_v3_v3(tmp_co, verts_dst[i].co);
+
+ /* Convert the vertex to tree coordinates, if needed. */
+ if (space_transform) {
+ BLI_space_transform_apply(space_transform, tmp_co);
+ }
+
+ if (mesh_remap_bvhtree_query_nearest(
+ &treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
+ mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &nearest.index, &full_weight);
+ }
+ else {
+ /* No source for this dest vertex! */
+ BKE_mesh_remap_item_define_invalid(r_map, i);
+ }
+ }
+ }
+ else if (ELEM(mode, MREMAP_MODE_VERT_EDGE_NEAREST, MREMAP_MODE_VERT_EDGEINTERP_NEAREST)) {
+ MEdge *edges_src = me_src->medge;
+ float(*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL);
+
+ BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_EDGES, 2);
+ nearest.index = -1;
+
+ for (i = 0; i < numverts_dst; i++) {
+ copy_v3_v3(tmp_co, verts_dst[i].co);
+
+ /* Convert the vertex to tree coordinates, if needed. */
+ if (space_transform) {
+ BLI_space_transform_apply(space_transform, tmp_co);
+ }
+
+ if (mesh_remap_bvhtree_query_nearest(
+ &treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
+ MEdge *me = &edges_src[nearest.index];
+ const float *v1cos = vcos_src[me->v1];
+ const float *v2cos = vcos_src[me->v2];
+
+ if (mode == MREMAP_MODE_VERT_EDGE_NEAREST) {
+ const float dist_v1 = len_squared_v3v3(tmp_co, v1cos);
+ const float dist_v2 = len_squared_v3v3(tmp_co, v2cos);
+ const int index = (int)((dist_v1 > dist_v2) ? me->v2 : me->v1);
+ mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &index, &full_weight);
+ }
+ else if (mode == MREMAP_MODE_VERT_EDGEINTERP_NEAREST) {
+ int indices[2];
+ float weights[2];
+
+ indices[0] = (int)me->v1;
+ indices[1] = (int)me->v2;
+
+ /* Weight is inverse of point factor here... */
+ weights[0] = line_point_factor_v3(tmp_co, v2cos, v1cos);
+ CLAMP(weights[0], 0.0f, 1.0f);
+ weights[1] = 1.0f - weights[0];
+
+ mesh_remap_item_define(r_map, i, hit_dist, 0, 2, indices, weights);
+ }
+ }
+ else {
+ /* No source for this dest vertex! */
+ BKE_mesh_remap_item_define_invalid(r_map, i);
+ }
+ }
+
+ MEM_freeN(vcos_src);
+ }
+ else if (ELEM(mode,
+ MREMAP_MODE_VERT_POLY_NEAREST,
+ MREMAP_MODE_VERT_POLYINTERP_NEAREST,
+ MREMAP_MODE_VERT_POLYINTERP_VNORPROJ)) {
+ MPoly *polys_src = me_src->mpoly;
+ MLoop *loops_src = me_src->mloop;
+ float(*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL);
+
+ size_t tmp_buff_size = MREMAP_DEFAULT_BUFSIZE;
+ float(*vcos)[3] = MEM_mallocN(sizeof(*vcos) * tmp_buff_size, __func__);
+ int *indices = MEM_mallocN(sizeof(*indices) * tmp_buff_size, __func__);
+ float *weights = MEM_mallocN(sizeof(*weights) * tmp_buff_size, __func__);
+
+ BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_LOOPTRI, 2);
+
+ if (mode == MREMAP_MODE_VERT_POLYINTERP_VNORPROJ) {
+ for (i = 0; i < numverts_dst; i++) {
+ copy_v3_v3(tmp_co, verts_dst[i].co);
+ normal_short_to_float_v3(tmp_no, verts_dst[i].no);
+
+ /* Convert the vertex to tree coordinates, if needed. */
+ if (space_transform) {
+ BLI_space_transform_apply(space_transform, tmp_co);
+ BLI_space_transform_apply_normal(space_transform, tmp_no);
+ }
+
+ if (mesh_remap_bvhtree_query_raycast(
+ &treedata, &rayhit, tmp_co, tmp_no, ray_radius, max_dist, &hit_dist)) {
+ const MLoopTri *lt = &treedata.looptri[rayhit.index];
+ MPoly *mp_src = &polys_src[lt->poly];
+ const int sources_num = mesh_remap_interp_poly_data_get(mp_src,
+ loops_src,
+ (const float(*)[3])vcos_src,
+ rayhit.co,
+ &tmp_buff_size,
+ &vcos,
+ false,
+ &indices,
+ &weights,
+ true,
+ NULL);
+
+ mesh_remap_item_define(r_map, i, hit_dist, 0, sources_num, indices, weights);
+ }
+ else {
+ /* No source for this dest vertex! */
+ BKE_mesh_remap_item_define_invalid(r_map, i);
+ }
+ }
+ }
+ else {
+ nearest.index = -1;
+
+ for (i = 0; i < numverts_dst; i++) {
+ copy_v3_v3(tmp_co, verts_dst[i].co);
+
+ /* Convert the vertex to tree coordinates, if needed. */
+ if (space_transform) {
+ BLI_space_transform_apply(space_transform, tmp_co);
+ }
+
+ if (mesh_remap_bvhtree_query_nearest(
+ &treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
+ const MLoopTri *lt = &treedata.looptri[nearest.index];
+ MPoly *mp = &polys_src[lt->poly];
+
+ if (mode == MREMAP_MODE_VERT_POLY_NEAREST) {
+ int index;
+ mesh_remap_interp_poly_data_get(mp,
+ loops_src,
+ (const float(*)[3])vcos_src,
+ nearest.co,
+ &tmp_buff_size,
+ &vcos,
+ false,
+ &indices,
+ &weights,
+ false,
+ &index);
+
+ mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &index, &full_weight);
+ }
+ else if (mode == MREMAP_MODE_VERT_POLYINTERP_NEAREST) {
+ const int sources_num = mesh_remap_interp_poly_data_get(mp,
+ loops_src,
+ (const float(*)[3])vcos_src,
+ nearest.co,
+ &tmp_buff_size,
+ &vcos,
+ false,
+ &indices,
+ &weights,
+ true,
+ NULL);
+
+ mesh_remap_item_define(r_map, i, hit_dist, 0, sources_num, indices, weights);
+ }
+ }
+ else {
+ /* No source for this dest vertex! */
+ BKE_mesh_remap_item_define_invalid(r_map, i);
+ }
+ }
+ }
+
+ MEM_freeN(vcos_src);
+ MEM_freeN(vcos);
+ MEM_freeN(indices);
+ MEM_freeN(weights);
+ }
+ else {
+ CLOG_WARN(&LOG, "Unsupported mesh-to-mesh vertex mapping mode (%d)!", mode);
+ memset(r_map->items, 0, sizeof(*r_map->items) * (size_t)numverts_dst);
+ }
+
+ free_bvhtree_from_mesh(&treedata);
+ }
}
-void BKE_mesh_remap_calc_edges_from_mesh(
- const int mode, const SpaceTransform *space_transform, const float max_dist, const float ray_radius,
- const MVert *verts_dst, const int numverts_dst, const MEdge *edges_dst, const int numedges_dst,
- const bool UNUSED(dirty_nors_dst), Mesh *me_src, MeshPairRemap *r_map)
+void BKE_mesh_remap_calc_edges_from_mesh(const int mode,
+ const SpaceTransform *space_transform,
+ const float max_dist,
+ const float ray_radius,
+ const MVert *verts_dst,
+ const int numverts_dst,
+ const MEdge *edges_dst,
+ const int numedges_dst,
+ const bool UNUSED(dirty_nors_dst),
+ Mesh *me_src,
+ MeshPairRemap *r_map)
{
- const float full_weight = 1.0f;
- const float max_dist_sq = max_dist * max_dist;
- int i;
-
- BLI_assert(mode & MREMAP_MODE_EDGE);
-
- BKE_mesh_remap_init(r_map, numedges_dst);
-
- if (mode == MREMAP_MODE_TOPOLOGY) {
- BLI_assert(numedges_dst == me_src->totedge);
- for (i = 0; i < numedges_dst; i++) {
- mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight);
- }
- }
- else {
- BVHTreeFromMesh treedata = {NULL};
- BVHTreeNearest nearest = {0};
- BVHTreeRayHit rayhit = {0};
- float hit_dist;
- float tmp_co[3], tmp_no[3];
-
- if (mode == MREMAP_MODE_EDGE_VERT_NEAREST) {
- const int num_verts_src = me_src->totvert;
- const int num_edges_src = me_src->totedge;
- MEdge *edges_src = me_src->medge;
- float (*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL);
-
- MeshElemMap *vert_to_edge_src_map;
- int *vert_to_edge_src_map_mem;
-
- struct {
- float hit_dist;
- int index;
- } *v_dst_to_src_map = MEM_mallocN(sizeof(*v_dst_to_src_map) * (size_t)numverts_dst, __func__);
-
- for (i = 0; i < numverts_dst; i++) {
- v_dst_to_src_map[i].hit_dist = -1.0f;
- }
-
- BKE_mesh_vert_edge_map_create(
- &vert_to_edge_src_map, &vert_to_edge_src_map_mem,
- edges_src, num_verts_src, num_edges_src);
-
- BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_VERTS, 2);
- nearest.index = -1;
-
- for (i = 0; i < numedges_dst; i++) {
- const MEdge *e_dst = &edges_dst[i];
- float best_totdist = FLT_MAX;
- int best_eidx_src = -1;
- int j = 2;
-
- while (j--) {
- const unsigned int vidx_dst = j ? e_dst->v1 : e_dst->v2;
-
- /* Compute closest verts only once! */
- if (v_dst_to_src_map[vidx_dst].hit_dist == -1.0f) {
- copy_v3_v3(tmp_co, verts_dst[vidx_dst].co);
-
- /* Convert the vertex to tree coordinates, if needed. */
- if (space_transform) {
- BLI_space_transform_apply(space_transform, tmp_co);
- }
-
- if (mesh_remap_bvhtree_query_nearest(&treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
- v_dst_to_src_map[vidx_dst].hit_dist = hit_dist;
- v_dst_to_src_map[vidx_dst].index = nearest.index;
- }
- else {
- /* No source for this dest vert! */
- v_dst_to_src_map[vidx_dst].hit_dist = FLT_MAX;
- }
- }
- }
-
- /* Now, check all source edges of closest sources vertices, and select the one giving the smallest
- * total verts-to-verts distance. */
- for (j = 2; j--;) {
- const unsigned int vidx_dst = j ? e_dst->v1 : e_dst->v2;
- const float first_dist = v_dst_to_src_map[vidx_dst].hit_dist;
- const int vidx_src = v_dst_to_src_map[vidx_dst].index;
- int *eidx_src, k;
-
- if (vidx_src < 0) {
- continue;
- }
-
- eidx_src = vert_to_edge_src_map[vidx_src].indices;
- k = vert_to_edge_src_map[vidx_src].count;
-
- for (; k--; eidx_src++) {
- MEdge *e_src = &edges_src[*eidx_src];
- const float *other_co_src = vcos_src[BKE_mesh_edge_other_vert(e_src, vidx_src)];
- const float *other_co_dst = verts_dst[BKE_mesh_edge_other_vert(e_dst, (int)vidx_dst)].co;
- const float totdist = first_dist + len_v3v3(other_co_src, other_co_dst);
-
- if (totdist < best_totdist) {
- best_totdist = totdist;
- best_eidx_src = *eidx_src;
- }
- }
- }
-
- if (best_eidx_src >= 0) {
- const float *co1_src = vcos_src[edges_src[best_eidx_src].v1];
- const float *co2_src = vcos_src[edges_src[best_eidx_src].v2];
- const float *co1_dst = verts_dst[e_dst->v1].co;
- const float *co2_dst = verts_dst[e_dst->v2].co;
- float co_src[3], co_dst[3];
-
- /* TODO: would need an isect_seg_seg_v3(), actually! */
- const int isect_type = isect_line_line_v3(co1_src, co2_src, co1_dst, co2_dst, co_src, co_dst);
- if (isect_type != 0) {
- const float fac_src = line_point_factor_v3(co_src, co1_src, co2_src);
- const float fac_dst = line_point_factor_v3(co_dst, co1_dst, co2_dst);
- if (fac_src < 0.0f) {
- copy_v3_v3(co_src, co1_src);
- }
- else if (fac_src > 1.0f) {
- copy_v3_v3(co_src, co2_src);
- }
- if (fac_dst < 0.0f) {
- copy_v3_v3(co_dst, co1_dst);
- }
- else if (fac_dst > 1.0f) {
- copy_v3_v3(co_dst, co2_dst);
- }
- }
- hit_dist = len_v3v3(co_dst, co_src);
- mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &best_eidx_src, &full_weight);
- }
- else {
- /* No source for this dest edge! */
- BKE_mesh_remap_item_define_invalid(r_map, i);
- }
- }
-
- MEM_freeN(vcos_src);
- MEM_freeN(v_dst_to_src_map);
- MEM_freeN(vert_to_edge_src_map);
- MEM_freeN(vert_to_edge_src_map_mem);
- }
- else if (mode == MREMAP_MODE_EDGE_NEAREST) {
- BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_EDGES, 2);
- nearest.index = -1;
-
- for (i = 0; i < numedges_dst; i++) {
- interp_v3_v3v3(tmp_co, verts_dst[edges_dst[i].v1].co, verts_dst[edges_dst[i].v2].co, 0.5f);
-
- /* Convert the vertex to tree coordinates, if needed. */
- if (space_transform) {
- BLI_space_transform_apply(space_transform, tmp_co);
- }
-
- if (mesh_remap_bvhtree_query_nearest(&treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
- mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &nearest.index, &full_weight);
- }
- else {
- /* No source for this dest edge! */
- BKE_mesh_remap_item_define_invalid(r_map, i);
- }
- }
- }
- else if (mode == MREMAP_MODE_EDGE_POLY_NEAREST) {
- MEdge *edges_src = me_src->medge;
- MPoly *polys_src = me_src->mpoly;
- MLoop *loops_src = me_src->mloop;
- float (*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL);
-
- BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_LOOPTRI, 2);
-
- for (i = 0; i < numedges_dst; i++) {
- interp_v3_v3v3(tmp_co, verts_dst[edges_dst[i].v1].co, verts_dst[edges_dst[i].v2].co, 0.5f);
-
- /* Convert the vertex to tree coordinates, if needed. */
- if (space_transform) {
- BLI_space_transform_apply(space_transform, tmp_co);
- }
-
- if (mesh_remap_bvhtree_query_nearest(&treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
- const MLoopTri *lt = &treedata.looptri[nearest.index];
- MPoly *mp_src = &polys_src[lt->poly];
- MLoop *ml_src = &loops_src[mp_src->loopstart];
- int nloops = mp_src->totloop;
- float best_dist_sq = FLT_MAX;
- int best_eidx_src = -1;
-
- for (; nloops--; ml_src++) {
- MEdge *med_src = &edges_src[ml_src->e];
- float *co1_src = vcos_src[med_src->v1];
- float *co2_src = vcos_src[med_src->v2];
- float co_src[3];
- float dist_sq;
-
- interp_v3_v3v3(co_src, co1_src, co2_src, 0.5f);
- dist_sq = len_squared_v3v3(tmp_co, co_src);
- if (dist_sq < best_dist_sq) {
- best_dist_sq = dist_sq;
- best_eidx_src = (int)ml_src->e;
- }
- }
- if (best_eidx_src >= 0) {
- mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &best_eidx_src, &full_weight);
- }
- }
- else {
- /* No source for this dest edge! */
- BKE_mesh_remap_item_define_invalid(r_map, i);
- }
- }
-
- MEM_freeN(vcos_src);
- }
- else if (mode == MREMAP_MODE_EDGE_EDGEINTERP_VNORPROJ) {
- const int num_rays_min = 5, num_rays_max = 100;
- const int numedges_src = me_src->totedge;
-
- /* Subtleness - this one we can allocate only max number of cast rays per edges! */
- int *indices = MEM_mallocN(sizeof(*indices) * (size_t)min_ii(numedges_src, num_rays_max), __func__);
- /* Here it's simpler to just allocate for all edges :/ */
- float *weights = MEM_mallocN(sizeof(*weights) * (size_t)numedges_src, __func__);
-
- BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_EDGES, 2);
-
- for (i = 0; i < numedges_dst; i++) {
- /* For each dst edge, we sample some rays from it (interpolated from its vertices)
- * and use their hits to interpolate from source edges. */
- const MEdge *me = &edges_dst[i];
- float v1_co[3], v2_co[3];
- float v1_no[3], v2_no[3];
-
- int grid_size;
- float edge_dst_len;
- float grid_step;
-
- float totweights = 0.0f;
- float hit_dist_accum = 0.0f;
- int sources_num = 0;
- int j;
-
- copy_v3_v3(v1_co, verts_dst[me->v1].co);
- copy_v3_v3(v2_co, verts_dst[me->v2].co);
-
- normal_short_to_float_v3(v1_no, verts_dst[me->v1].no);
- normal_short_to_float_v3(v2_no, verts_dst[me->v2].no);
-
- /* We do our transform here, allows to interpolate from normals already in src space. */
- if (space_transform) {
- BLI_space_transform_apply(space_transform, v1_co);
- BLI_space_transform_apply(space_transform, v2_co);
- BLI_space_transform_apply_normal(space_transform, v1_no);
- BLI_space_transform_apply_normal(space_transform, v2_no);
- }
-
- copy_vn_fl(weights, (int)numedges_src, 0.0f);
-
- /* We adjust our ray-casting grid to ray_radius (the smaller, the more rays are cast),
- * with lower/upper bounds. */
- edge_dst_len = len_v3v3(v1_co, v2_co);
-
- grid_size = (int)((edge_dst_len / ray_radius) + 0.5f);
- CLAMP(grid_size, num_rays_min, num_rays_max); /* min 5 rays/edge, max 100. */
-
- grid_step = 1.0f / (float)grid_size; /* Not actual distance here, rather an interp fac... */
-
- /* And now we can cast all our rays, and see what we get! */
- for (j = 0; j < grid_size; j++) {
- const float fac = grid_step * (float)j;
-
- int n = (ray_radius > 0.0f) ? MREMAP_RAYCAST_APPROXIMATE_NR : 1;
- float w = 1.0f;
-
- interp_v3_v3v3(tmp_co, v1_co, v2_co, fac);
- interp_v3_v3v3_slerp_safe(tmp_no, v1_no, v2_no, fac);
-
- while (n--) {
- if (mesh_remap_bvhtree_query_raycast(
- &treedata, &rayhit, tmp_co, tmp_no, ray_radius / w, max_dist, &hit_dist))
- {
- weights[rayhit.index] += w;
- totweights += w;
- hit_dist_accum += hit_dist;
- break;
- }
- /* Next iteration will get bigger radius but smaller weight! */
- w /= MREMAP_RAYCAST_APPROXIMATE_FAC;
- }
- }
- /* A sampling is valid (as in, its result can be considered as valid sources) only if at least
- * half of the rays found a source! */
- if (totweights > ((float)grid_size / 2.0f)) {
- for (j = 0; j < (int)numedges_src; j++) {
- if (!weights[j]) {
- continue;
- }
- /* Note: sources_num is always <= j! */
- weights[sources_num] = weights[j] / totweights;
- indices[sources_num] = j;
- sources_num++;
- }
- mesh_remap_item_define(
- r_map, i, hit_dist_accum / totweights, 0,
- sources_num, indices, weights);
- }
- else {
- /* No source for this dest edge! */
- BKE_mesh_remap_item_define_invalid(r_map, i);
- }
- }
-
- MEM_freeN(indices);
- MEM_freeN(weights);
- }
- else {
- CLOG_WARN(&LOG, "Unsupported mesh-to-mesh edge mapping mode (%d)!", mode);
- memset(r_map->items, 0, sizeof(*r_map->items) * (size_t)numedges_dst);
- }
-
- free_bvhtree_from_mesh(&treedata);
- }
+ const float full_weight = 1.0f;
+ const float max_dist_sq = max_dist * max_dist;
+ int i;
+
+ BLI_assert(mode & MREMAP_MODE_EDGE);
+
+ BKE_mesh_remap_init(r_map, numedges_dst);
+
+ if (mode == MREMAP_MODE_TOPOLOGY) {
+ BLI_assert(numedges_dst == me_src->totedge);
+ for (i = 0; i < numedges_dst; i++) {
+ mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight);
+ }
+ }
+ else {
+ BVHTreeFromMesh treedata = {NULL};
+ BVHTreeNearest nearest = {0};
+ BVHTreeRayHit rayhit = {0};
+ float hit_dist;
+ float tmp_co[3], tmp_no[3];
+
+ if (mode == MREMAP_MODE_EDGE_VERT_NEAREST) {
+ const int num_verts_src = me_src->totvert;
+ const int num_edges_src = me_src->totedge;
+ MEdge *edges_src = me_src->medge;
+ float(*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL);
+
+ MeshElemMap *vert_to_edge_src_map;
+ int *vert_to_edge_src_map_mem;
+
+ struct {
+ float hit_dist;
+ int index;
+ } *v_dst_to_src_map = MEM_mallocN(sizeof(*v_dst_to_src_map) * (size_t)numverts_dst,
+ __func__);
+
+ for (i = 0; i < numverts_dst; i++) {
+ v_dst_to_src_map[i].hit_dist = -1.0f;
+ }
+
+ BKE_mesh_vert_edge_map_create(&vert_to_edge_src_map,
+ &vert_to_edge_src_map_mem,
+ edges_src,
+ num_verts_src,
+ num_edges_src);
+
+ BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_VERTS, 2);
+ nearest.index = -1;
+
+ for (i = 0; i < numedges_dst; i++) {
+ const MEdge *e_dst = &edges_dst[i];
+ float best_totdist = FLT_MAX;
+ int best_eidx_src = -1;
+ int j = 2;
+
+ while (j--) {
+ const unsigned int vidx_dst = j ? e_dst->v1 : e_dst->v2;
+
+ /* Compute closest verts only once! */
+ if (v_dst_to_src_map[vidx_dst].hit_dist == -1.0f) {
+ copy_v3_v3(tmp_co, verts_dst[vidx_dst].co);
+
+ /* Convert the vertex to tree coordinates, if needed. */
+ if (space_transform) {
+ BLI_space_transform_apply(space_transform, tmp_co);
+ }
+
+ if (mesh_remap_bvhtree_query_nearest(
+ &treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
+ v_dst_to_src_map[vidx_dst].hit_dist = hit_dist;
+ v_dst_to_src_map[vidx_dst].index = nearest.index;
+ }
+ else {
+ /* No source for this dest vert! */
+ v_dst_to_src_map[vidx_dst].hit_dist = FLT_MAX;
+ }
+ }
+ }
+
+ /* Now, check all source edges of closest sources vertices, and select the one giving the smallest
+ * total verts-to-verts distance. */
+ for (j = 2; j--;) {
+ const unsigned int vidx_dst = j ? e_dst->v1 : e_dst->v2;
+ const float first_dist = v_dst_to_src_map[vidx_dst].hit_dist;
+ const int vidx_src = v_dst_to_src_map[vidx_dst].index;
+ int *eidx_src, k;
+
+ if (vidx_src < 0) {
+ continue;
+ }
+
+ eidx_src = vert_to_edge_src_map[vidx_src].indices;
+ k = vert_to_edge_src_map[vidx_src].count;
+
+ for (; k--; eidx_src++) {
+ MEdge *e_src = &edges_src[*eidx_src];
+ const float *other_co_src = vcos_src[BKE_mesh_edge_other_vert(e_src, vidx_src)];
+ const float *other_co_dst =
+ verts_dst[BKE_mesh_edge_other_vert(e_dst, (int)vidx_dst)].co;
+ const float totdist = first_dist + len_v3v3(other_co_src, other_co_dst);
+
+ if (totdist < best_totdist) {
+ best_totdist = totdist;
+ best_eidx_src = *eidx_src;
+ }
+ }
+ }
+
+ if (best_eidx_src >= 0) {
+ const float *co1_src = vcos_src[edges_src[best_eidx_src].v1];
+ const float *co2_src = vcos_src[edges_src[best_eidx_src].v2];
+ const float *co1_dst = verts_dst[e_dst->v1].co;
+ const float *co2_dst = verts_dst[e_dst->v2].co;
+ float co_src[3], co_dst[3];
+
+ /* TODO: would need an isect_seg_seg_v3(), actually! */
+ const int isect_type = isect_line_line_v3(
+ co1_src, co2_src, co1_dst, co2_dst, co_src, co_dst);
+ if (isect_type != 0) {
+ const float fac_src = line_point_factor_v3(co_src, co1_src, co2_src);
+ const float fac_dst = line_point_factor_v3(co_dst, co1_dst, co2_dst);
+ if (fac_src < 0.0f) {
+ copy_v3_v3(co_src, co1_src);
+ }
+ else if (fac_src > 1.0f) {
+ copy_v3_v3(co_src, co2_src);
+ }
+ if (fac_dst < 0.0f) {
+ copy_v3_v3(co_dst, co1_dst);
+ }
+ else if (fac_dst > 1.0f) {
+ copy_v3_v3(co_dst, co2_dst);
+ }
+ }
+ hit_dist = len_v3v3(co_dst, co_src);
+ mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &best_eidx_src, &full_weight);
+ }
+ else {
+ /* No source for this dest edge! */
+ BKE_mesh_remap_item_define_invalid(r_map, i);
+ }
+ }
+
+ MEM_freeN(vcos_src);
+ MEM_freeN(v_dst_to_src_map);
+ MEM_freeN(vert_to_edge_src_map);
+ MEM_freeN(vert_to_edge_src_map_mem);
+ }
+ else if (mode == MREMAP_MODE_EDGE_NEAREST) {
+ BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_EDGES, 2);
+ nearest.index = -1;
+
+ for (i = 0; i < numedges_dst; i++) {
+ interp_v3_v3v3(tmp_co, verts_dst[edges_dst[i].v1].co, verts_dst[edges_dst[i].v2].co, 0.5f);
+
+ /* Convert the vertex to tree coordinates, if needed. */
+ if (space_transform) {
+ BLI_space_transform_apply(space_transform, tmp_co);
+ }
+
+ if (mesh_remap_bvhtree_query_nearest(
+ &treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
+ mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &nearest.index, &full_weight);
+ }
+ else {
+ /* No source for this dest edge! */
+ BKE_mesh_remap_item_define_invalid(r_map, i);
+ }
+ }
+ }
+ else if (mode == MREMAP_MODE_EDGE_POLY_NEAREST) {
+ MEdge *edges_src = me_src->medge;
+ MPoly *polys_src = me_src->mpoly;
+ MLoop *loops_src = me_src->mloop;
+ float(*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL);
+
+ BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_LOOPTRI, 2);
+
+ for (i = 0; i < numedges_dst; i++) {
+ interp_v3_v3v3(tmp_co, verts_dst[edges_dst[i].v1].co, verts_dst[edges_dst[i].v2].co, 0.5f);
+
+ /* Convert the vertex to tree coordinates, if needed. */
+ if (space_transform) {
+ BLI_space_transform_apply(space_transform, tmp_co);
+ }
+
+ if (mesh_remap_bvhtree_query_nearest(
+ &treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
+ const MLoopTri *lt = &treedata.looptri[nearest.index];
+ MPoly *mp_src = &polys_src[lt->poly];
+ MLoop *ml_src = &loops_src[mp_src->loopstart];
+ int nloops = mp_src->totloop;
+ float best_dist_sq = FLT_MAX;
+ int best_eidx_src = -1;
+
+ for (; nloops--; ml_src++) {
+ MEdge *med_src = &edges_src[ml_src->e];
+ float *co1_src = vcos_src[med_src->v1];
+ float *co2_src = vcos_src[med_src->v2];
+ float co_src[3];
+ float dist_sq;
+
+ interp_v3_v3v3(co_src, co1_src, co2_src, 0.5f);
+ dist_sq = len_squared_v3v3(tmp_co, co_src);
+ if (dist_sq < best_dist_sq) {
+ best_dist_sq = dist_sq;
+ best_eidx_src = (int)ml_src->e;
+ }
+ }
+ if (best_eidx_src >= 0) {
+ mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &best_eidx_src, &full_weight);
+ }
+ }
+ else {
+ /* No source for this dest edge! */
+ BKE_mesh_remap_item_define_invalid(r_map, i);
+ }
+ }
+
+ MEM_freeN(vcos_src);
+ }
+ else if (mode == MREMAP_MODE_EDGE_EDGEINTERP_VNORPROJ) {
+ const int num_rays_min = 5, num_rays_max = 100;
+ const int numedges_src = me_src->totedge;
+
+ /* Subtleness - this one we can allocate only max number of cast rays per edges! */
+ int *indices = MEM_mallocN(sizeof(*indices) * (size_t)min_ii(numedges_src, num_rays_max),
+ __func__);
+ /* Here it's simpler to just allocate for all edges :/ */
+ float *weights = MEM_mallocN(sizeof(*weights) * (size_t)numedges_src, __func__);
+
+ BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_EDGES, 2);
+
+ for (i = 0; i < numedges_dst; i++) {
+ /* For each dst edge, we sample some rays from it (interpolated from its vertices)
+ * and use their hits to interpolate from source edges. */
+ const MEdge *me = &edges_dst[i];
+ float v1_co[3], v2_co[3];
+ float v1_no[3], v2_no[3];
+
+ int grid_size;
+ float edge_dst_len;
+ float grid_step;
+
+ float totweights = 0.0f;
+ float hit_dist_accum = 0.0f;
+ int sources_num = 0;
+ int j;
+
+ copy_v3_v3(v1_co, verts_dst[me->v1].co);
+ copy_v3_v3(v2_co, verts_dst[me->v2].co);
+
+ normal_short_to_float_v3(v1_no, verts_dst[me->v1].no);
+ normal_short_to_float_v3(v2_no, verts_dst[me->v2].no);
+
+ /* We do our transform here, allows to interpolate from normals already in src space. */
+ if (space_transform) {
+ BLI_space_transform_apply(space_transform, v1_co);
+ BLI_space_transform_apply(space_transform, v2_co);
+ BLI_space_transform_apply_normal(space_transform, v1_no);
+ BLI_space_transform_apply_normal(space_transform, v2_no);
+ }
+
+ copy_vn_fl(weights, (int)numedges_src, 0.0f);
+
+ /* We adjust our ray-casting grid to ray_radius (the smaller, the more rays are cast),
+ * with lower/upper bounds. */
+ edge_dst_len = len_v3v3(v1_co, v2_co);
+
+ grid_size = (int)((edge_dst_len / ray_radius) + 0.5f);
+ CLAMP(grid_size, num_rays_min, num_rays_max); /* min 5 rays/edge, max 100. */
+
+ grid_step = 1.0f /
+ (float)grid_size; /* Not actual distance here, rather an interp fac... */
+
+ /* And now we can cast all our rays, and see what we get! */
+ for (j = 0; j < grid_size; j++) {
+ const float fac = grid_step * (float)j;
+
+ int n = (ray_radius > 0.0f) ? MREMAP_RAYCAST_APPROXIMATE_NR : 1;
+ float w = 1.0f;
+
+ interp_v3_v3v3(tmp_co, v1_co, v2_co, fac);
+ interp_v3_v3v3_slerp_safe(tmp_no, v1_no, v2_no, fac);
+
+ while (n--) {
+ if (mesh_remap_bvhtree_query_raycast(
+ &treedata, &rayhit, tmp_co, tmp_no, ray_radius / w, max_dist, &hit_dist)) {
+ weights[rayhit.index] += w;
+ totweights += w;
+ hit_dist_accum += hit_dist;
+ break;
+ }
+ /* Next iteration will get bigger radius but smaller weight! */
+ w /= MREMAP_RAYCAST_APPROXIMATE_FAC;
+ }
+ }
+ /* A sampling is valid (as in, its result can be considered as valid sources) only if at least
+ * half of the rays found a source! */
+ if (totweights > ((float)grid_size / 2.0f)) {
+ for (j = 0; j < (int)numedges_src; j++) {
+ if (!weights[j]) {
+ continue;
+ }
+ /* Note: sources_num is always <= j! */
+ weights[sources_num] = weights[j] / totweights;
+ indices[sources_num] = j;
+ sources_num++;
+ }
+ mesh_remap_item_define(
+ r_map, i, hit_dist_accum / totweights, 0, sources_num, indices, weights);
+ }
+ else {
+ /* No source for this dest edge! */
+ BKE_mesh_remap_item_define_invalid(r_map, i);
+ }
+ }
+
+ MEM_freeN(indices);
+ MEM_freeN(weights);
+ }
+ else {
+ CLOG_WARN(&LOG, "Unsupported mesh-to-mesh edge mapping mode (%d)!", mode);
+ memset(r_map->items, 0, sizeof(*r_map->items) * (size_t)numedges_dst);
+ }
+
+ free_bvhtree_from_mesh(&treedata);
+ }
}
-#define POLY_UNSET 0
+#define POLY_UNSET 0
#define POLY_CENTER_INIT 1
-#define POLY_COMPLETE 2
-
-static void mesh_island_to_astar_graph_edge_process(
- MeshIslandStore *islands, const int island_index, BLI_AStarGraph *as_graph,
- MVert *verts, MPoly *polys, MLoop *loops,
- const int edge_idx, BLI_bitmap *done_edges, MeshElemMap *edge_to_poly_map, const bool is_edge_innercut,
- int *poly_island_index_map, float (*poly_centers)[3], unsigned char *poly_status)
+#define POLY_COMPLETE 2
+
+static void mesh_island_to_astar_graph_edge_process(MeshIslandStore *islands,
+ const int island_index,
+ BLI_AStarGraph *as_graph,
+ MVert *verts,
+ MPoly *polys,
+ MLoop *loops,
+ const int edge_idx,
+ BLI_bitmap *done_edges,
+ MeshElemMap *edge_to_poly_map,
+ const bool is_edge_innercut,
+ int *poly_island_index_map,
+ float (*poly_centers)[3],
+ unsigned char *poly_status)
{
- int *poly_island_indices = BLI_array_alloca(poly_island_indices, (size_t)edge_to_poly_map[edge_idx].count);
- int i, j;
-
- for (i = 0; i < edge_to_poly_map[edge_idx].count; i++) {
- const int pidx = edge_to_poly_map[edge_idx].indices[i];
- MPoly *mp = &polys[pidx];
- const int pidx_isld = islands ? poly_island_index_map[pidx] : pidx;
- void *custom_data = is_edge_innercut ? POINTER_FROM_INT(edge_idx) : POINTER_FROM_INT(-1);
-
- if (UNLIKELY(islands && (islands->items_to_islands[mp->loopstart] != island_index))) {
- /* poly not in current island, happens with border edges... */
- poly_island_indices[i] = -1;
- continue;
- }
-
- if (poly_status[pidx_isld] == POLY_COMPLETE) {
- poly_island_indices[i] = pidx_isld;
- continue;
- }
-
- if (poly_status[pidx_isld] == POLY_UNSET) {
- BKE_mesh_calc_poly_center(mp, &loops[mp->loopstart], verts, poly_centers[pidx_isld]);
- BLI_astar_node_init(as_graph, pidx_isld, poly_centers[pidx_isld]);
- poly_status[pidx_isld] = POLY_CENTER_INIT;
- }
-
- for (j = i; j--;) {
- float dist_cost;
- const int pidx_isld_other = poly_island_indices[j];
-
- if (pidx_isld_other == -1 || poly_status[pidx_isld_other] == POLY_COMPLETE) {
- /* If the other poly is complete, that link has already been added! */
- continue;
- }
- dist_cost = len_v3v3(poly_centers[pidx_isld_other], poly_centers[pidx_isld]);
- BLI_astar_node_link_add(as_graph, pidx_isld_other, pidx_isld, dist_cost, custom_data);
- }
-
- poly_island_indices[i] = pidx_isld;
- }
-
- BLI_BITMAP_ENABLE(done_edges, edge_idx);
+ int *poly_island_indices = BLI_array_alloca(poly_island_indices,
+ (size_t)edge_to_poly_map[edge_idx].count);
+ int i, j;
+
+ for (i = 0; i < edge_to_poly_map[edge_idx].count; i++) {
+ const int pidx = edge_to_poly_map[edge_idx].indices[i];
+ MPoly *mp = &polys[pidx];
+ const int pidx_isld = islands ? poly_island_index_map[pidx] : pidx;
+ void *custom_data = is_edge_innercut ? POINTER_FROM_INT(edge_idx) : POINTER_FROM_INT(-1);
+
+ if (UNLIKELY(islands && (islands->items_to_islands[mp->loopstart] != island_index))) {
+ /* poly not in current island, happens with border edges... */
+ poly_island_indices[i] = -1;
+ continue;
+ }
+
+ if (poly_status[pidx_isld] == POLY_COMPLETE) {
+ poly_island_indices[i] = pidx_isld;
+ continue;
+ }
+
+ if (poly_status[pidx_isld] == POLY_UNSET) {
+ BKE_mesh_calc_poly_center(mp, &loops[mp->loopstart], verts, poly_centers[pidx_isld]);
+ BLI_astar_node_init(as_graph, pidx_isld, poly_centers[pidx_isld]);
+ poly_status[pidx_isld] = POLY_CENTER_INIT;
+ }
+
+ for (j = i; j--;) {
+ float dist_cost;
+ const int pidx_isld_other = poly_island_indices[j];
+
+ if (pidx_isld_other == -1 || poly_status[pidx_isld_other] == POLY_COMPLETE) {
+ /* If the other poly is complete, that link has already been added! */
+ continue;
+ }
+ dist_cost = len_v3v3(poly_centers[pidx_isld_other], poly_centers[pidx_isld]);
+ BLI_astar_node_link_add(as_graph, pidx_isld_other, pidx_isld, dist_cost, custom_data);
+ }
+
+ poly_island_indices[i] = pidx_isld;
+ }
+
+ BLI_BITMAP_ENABLE(done_edges, edge_idx);
}
-static void mesh_island_to_astar_graph(
- MeshIslandStore *islands, const int island_index,
- MVert *verts, MeshElemMap *edge_to_poly_map, const int numedges, MLoop *loops, MPoly *polys, const int numpolys,
- BLI_AStarGraph *r_as_graph)
+static void mesh_island_to_astar_graph(MeshIslandStore *islands,
+ const int island_index,
+ MVert *verts,
+ MeshElemMap *edge_to_poly_map,
+ const int numedges,
+ MLoop *loops,
+ MPoly *polys,
+ const int numpolys,
+ BLI_AStarGraph *r_as_graph)
{
- MeshElemMap *island_poly_map = islands ? islands->islands[island_index] : NULL;
- MeshElemMap *island_einnercut_map = islands ? islands->innercuts[island_index] : NULL;
-
- int *poly_island_index_map = NULL;
- BLI_bitmap *done_edges = BLI_BITMAP_NEW(numedges, __func__);
-
- const int node_num = islands ? island_poly_map->count : numpolys;
- unsigned char *poly_status = MEM_callocN(sizeof(*poly_status) * (size_t)node_num, __func__);
- float (*poly_centers)[3];
-
- int pidx_isld;
- int i;
-
- BLI_astar_graph_init(r_as_graph, node_num, NULL);
- /* poly_centers is owned by graph memarena. */
- poly_centers = BLI_memarena_calloc(r_as_graph->mem, sizeof(*poly_centers) * (size_t)node_num);
-
- if (islands) {
- /* poly_island_index_map is owned by graph memarena. */
- poly_island_index_map = BLI_memarena_calloc(r_as_graph->mem, sizeof(*poly_island_index_map) * (size_t)numpolys);
- for (i = island_poly_map->count; i--;) {
- poly_island_index_map[island_poly_map->indices[i]] = i;
- }
-
- r_as_graph->custom_data = poly_island_index_map;
-
- for (i = island_einnercut_map->count; i--;) {
- mesh_island_to_astar_graph_edge_process(
- islands, island_index, r_as_graph, verts, polys, loops,
- island_einnercut_map->indices[i], done_edges, edge_to_poly_map, true,
- poly_island_index_map, poly_centers, poly_status);
- }
- }
-
- for (pidx_isld = node_num; pidx_isld--;) {
- const int pidx = islands ? island_poly_map->indices[pidx_isld] : pidx_isld;
- MPoly *mp = &polys[pidx];
- int pl_idx, l_idx;
-
- if (poly_status[pidx_isld] == POLY_COMPLETE) {
- continue;
- }
-
- for (pl_idx = 0, l_idx = mp->loopstart; pl_idx < mp->totloop; pl_idx++, l_idx++) {
- MLoop *ml = &loops[l_idx];
-
- if (BLI_BITMAP_TEST(done_edges, ml->e)) {
- continue;
- }
-
- mesh_island_to_astar_graph_edge_process(
- islands, island_index, r_as_graph, verts, polys, loops,
- (int)ml->e, done_edges, edge_to_poly_map, false,
- poly_island_index_map, poly_centers, poly_status);
- }
- poly_status[pidx_isld] = POLY_COMPLETE;
- }
-
- MEM_freeN(done_edges);
- MEM_freeN(poly_status);
+ MeshElemMap *island_poly_map = islands ? islands->islands[island_index] : NULL;
+ MeshElemMap *island_einnercut_map = islands ? islands->innercuts[island_index] : NULL;
+
+ int *poly_island_index_map = NULL;
+ BLI_bitmap *done_edges = BLI_BITMAP_NEW(numedges, __func__);
+
+ const int node_num = islands ? island_poly_map->count : numpolys;
+ unsigned char *poly_status = MEM_callocN(sizeof(*poly_status) * (size_t)node_num, __func__);
+ float(*poly_centers)[3];
+
+ int pidx_isld;
+ int i;
+
+ BLI_astar_graph_init(r_as_graph, node_num, NULL);
+ /* poly_centers is owned by graph memarena. */
+ poly_centers = BLI_memarena_calloc(r_as_graph->mem, sizeof(*poly_centers) * (size_t)node_num);
+
+ if (islands) {
+ /* poly_island_index_map is owned by graph memarena. */
+ poly_island_index_map = BLI_memarena_calloc(r_as_graph->mem,
+ sizeof(*poly_island_index_map) * (size_t)numpolys);
+ for (i = island_poly_map->count; i--;) {
+ poly_island_index_map[island_poly_map->indices[i]] = i;
+ }
+
+ r_as_graph->custom_data = poly_island_index_map;
+
+ for (i = island_einnercut_map->count; i--;) {
+ mesh_island_to_astar_graph_edge_process(islands,
+ island_index,
+ r_as_graph,
+ verts,
+ polys,
+ loops,
+ island_einnercut_map->indices[i],
+ done_edges,
+ edge_to_poly_map,
+ true,
+ poly_island_index_map,
+ poly_centers,
+ poly_status);
+ }
+ }
+
+ for (pidx_isld = node_num; pidx_isld--;) {
+ const int pidx = islands ? island_poly_map->indices[pidx_isld] : pidx_isld;
+ MPoly *mp = &polys[pidx];
+ int pl_idx, l_idx;
+
+ if (poly_status[pidx_isld] == POLY_COMPLETE) {
+ continue;
+ }
+
+ for (pl_idx = 0, l_idx = mp->loopstart; pl_idx < mp->totloop; pl_idx++, l_idx++) {
+ MLoop *ml = &loops[l_idx];
+
+ if (BLI_BITMAP_TEST(done_edges, ml->e)) {
+ continue;
+ }
+
+ mesh_island_to_astar_graph_edge_process(islands,
+ island_index,
+ r_as_graph,
+ verts,
+ polys,
+ loops,
+ (int)ml->e,
+ done_edges,
+ edge_to_poly_map,
+ false,
+ poly_island_index_map,
+ poly_centers,
+ poly_status);
+ }
+ poly_status[pidx_isld] = POLY_COMPLETE;
+ }
+
+ MEM_freeN(done_edges);
+ MEM_freeN(poly_status);
}
#undef POLY_UNSET
@@ -1090,1145 +1202,1265 @@ static void mesh_island_to_astar_graph(
/* Our 'f_cost' callback func, to find shortest poly-path between two remapped-loops.
* Note we do not want to make innercuts 'walls' here, just detect when the shortest path goes by those. */
-static float mesh_remap_calc_loops_astar_f_cost(
- BLI_AStarGraph *as_graph, BLI_AStarSolution *as_solution, BLI_AStarGNLink *link,
- const int node_idx_curr, const int node_idx_next, const int node_idx_dst)
+static float mesh_remap_calc_loops_astar_f_cost(BLI_AStarGraph *as_graph,
+ BLI_AStarSolution *as_solution,
+ BLI_AStarGNLink *link,
+ const int node_idx_curr,
+ const int node_idx_next,
+ const int node_idx_dst)
{
- float *co_next, *co_dest;
-
- if (link && (POINTER_AS_INT(link->custom_data) != -1)) {
- /* An innercut edge... We tag our solution as potentially crossing innercuts.
- * Note it might not be the case in the end (AStar will explore around optimal path), but helps
- * trimming off some processing later... */
- if (!POINTER_AS_INT(as_solution->custom_data)) {
- as_solution->custom_data = POINTER_FROM_INT(true);
- }
- }
-
- /* Our heuristic part of current f_cost is distance from next node to destination one.
- * It is guaranteed to be less than (or equal to) actual shortest poly-path between next node and destination one.
- */
- co_next = (float *)as_graph->nodes[node_idx_next].custom_data;
- co_dest = (float *)as_graph->nodes[node_idx_dst].custom_data;
- return (link ? (as_solution->g_costs[node_idx_curr] + link->cost) : 0.0f) + len_v3v3(co_next, co_dest);
+ float *co_next, *co_dest;
+
+ if (link && (POINTER_AS_INT(link->custom_data) != -1)) {
+ /* An innercut edge... We tag our solution as potentially crossing innercuts.
+ * Note it might not be the case in the end (AStar will explore around optimal path), but helps
+ * trimming off some processing later... */
+ if (!POINTER_AS_INT(as_solution->custom_data)) {
+ as_solution->custom_data = POINTER_FROM_INT(true);
+ }
+ }
+
+ /* Our heuristic part of current f_cost is distance from next node to destination one.
+ * It is guaranteed to be less than (or equal to) actual shortest poly-path between next node and destination one.
+ */
+ co_next = (float *)as_graph->nodes[node_idx_next].custom_data;
+ co_dest = (float *)as_graph->nodes[node_idx_dst].custom_data;
+ return (link ? (as_solution->g_costs[node_idx_curr] + link->cost) : 0.0f) +
+ len_v3v3(co_next, co_dest);
}
#define ASTAR_STEPS_MAX 64
-
-void BKE_mesh_remap_calc_loops_from_mesh(
- const int mode, const SpaceTransform *space_transform, const float max_dist, const float ray_radius,
- MVert *verts_dst, const int numverts_dst, MEdge *edges_dst, const int numedges_dst,
- MLoop *loops_dst, const int numloops_dst, MPoly *polys_dst, const int numpolys_dst,
- CustomData *ldata_dst, CustomData *pdata_dst,
- const bool use_split_nors_dst, const float split_angle_dst, const bool dirty_nors_dst,
- Mesh *me_src,
- MeshRemapIslandsCalc gen_islands_src, const float islands_precision_src, MeshPairRemap *r_map)
+void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
+ const SpaceTransform *space_transform,
+ const float max_dist,
+ const float ray_radius,
+ MVert *verts_dst,
+ const int numverts_dst,
+ MEdge *edges_dst,
+ const int numedges_dst,
+ MLoop *loops_dst,
+ const int numloops_dst,
+ MPoly *polys_dst,
+ const int numpolys_dst,
+ CustomData *ldata_dst,
+ CustomData *pdata_dst,
+ const bool use_split_nors_dst,
+ const float split_angle_dst,
+ const bool dirty_nors_dst,
+ Mesh *me_src,
+ MeshRemapIslandsCalc gen_islands_src,
+ const float islands_precision_src,
+ MeshPairRemap *r_map)
{
- const float full_weight = 1.0f;
- const float max_dist_sq = max_dist * max_dist;
-
- int i;
-
- BLI_assert(mode & MREMAP_MODE_LOOP);
- BLI_assert((islands_precision_src >= 0.0f) && (islands_precision_src <= 1.0f));
-
- BKE_mesh_remap_init(r_map, numloops_dst);
-
- if (mode == MREMAP_MODE_TOPOLOGY) {
- /* In topology mapping, we assume meshes are identical, islands included! */
- BLI_assert(numloops_dst == me_src->totloop);
- for (i = 0; i < numloops_dst; i++) {
- mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight);
- }
- }
- else {
- BVHTreeFromMesh *treedata = NULL;
- BVHTreeNearest nearest = {0};
- BVHTreeRayHit rayhit = {0};
- int num_trees = 0;
- float hit_dist;
- float tmp_co[3], tmp_no[3];
-
- const bool use_from_vert = (mode & MREMAP_USE_VERT);
-
- MeshIslandStore island_store = {0};
- bool use_islands = false;
-
- BLI_AStarGraph *as_graphdata = NULL;
- BLI_AStarSolution as_solution = {0};
- const int isld_steps_src = (
- islands_precision_src ?
- max_ii((int)(ASTAR_STEPS_MAX * islands_precision_src + 0.499f), 1) : 0);
-
- float (*poly_nors_src)[3] = NULL;
- float (*loop_nors_src)[3] = NULL;
- float (*poly_nors_dst)[3] = NULL;
- float (*loop_nors_dst)[3] = NULL;
-
- float (*poly_cents_src)[3] = NULL;
-
- MeshElemMap *vert_to_loop_map_src = NULL;
- int *vert_to_loop_map_src_buff = NULL;
- MeshElemMap *vert_to_poly_map_src = NULL;
- int *vert_to_poly_map_src_buff = NULL;
- MeshElemMap *edge_to_poly_map_src = NULL;
- int *edge_to_poly_map_src_buff = NULL;
- MeshElemMap *poly_to_looptri_map_src = NULL;
- int *poly_to_looptri_map_src_buff = NULL;
-
- /* Unlike above, those are one-to-one mappings, simpler! */
- int *loop_to_poly_map_src = NULL;
-
- MVert *verts_src = me_src->mvert;
- const int num_verts_src = me_src->totvert;
- float (*vcos_src)[3] = NULL;
- MEdge *edges_src = me_src->medge;
- const int num_edges_src = me_src->totedge;
- MLoop *loops_src = me_src->mloop;
- const int num_loops_src = me_src->totloop;
- MPoly *polys_src = me_src->mpoly;
- const int num_polys_src = me_src->totpoly;
- const MLoopTri *looptri_src = NULL;
- int num_looptri_src = 0;
-
- size_t buff_size_interp = MREMAP_DEFAULT_BUFSIZE;
- float (*vcos_interp)[3] = NULL;
- int *indices_interp = NULL;
- float *weights_interp = NULL;
-
- MLoop *ml_src, *ml_dst;
- MPoly *mp_src, *mp_dst;
- int tindex, pidx_dst, lidx_dst, plidx_dst, pidx_src, lidx_src, plidx_src;
-
- IslandResult **islands_res;
- size_t islands_res_buff_size = MREMAP_DEFAULT_BUFSIZE;
-
- if (!use_from_vert) {
- vcos_src = BKE_mesh_vertexCos_get(me_src, NULL);
-
- vcos_interp = MEM_mallocN(sizeof(*vcos_interp) * buff_size_interp, __func__);
- indices_interp = MEM_mallocN(sizeof(*indices_interp) * buff_size_interp, __func__);
- weights_interp = MEM_mallocN(sizeof(*weights_interp) * buff_size_interp, __func__);
- }
-
- {
- const bool need_lnors_src = (mode & MREMAP_USE_LOOP) && (mode & MREMAP_USE_NORMAL);
- const bool need_lnors_dst = need_lnors_src || (mode & MREMAP_USE_NORPROJ);
- const bool need_pnors_src = need_lnors_src || ((mode & MREMAP_USE_POLY) && (mode & MREMAP_USE_NORMAL));
- const bool need_pnors_dst = need_lnors_dst || need_pnors_src;
-
- if (need_pnors_dst) {
- /* Cache poly nors into a temp CDLayer. */
- poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL);
- const bool do_poly_nors_dst = (poly_nors_dst == NULL);
- if (!poly_nors_dst) {
- poly_nors_dst = CustomData_add_layer(pdata_dst, CD_NORMAL, CD_CALLOC, NULL, numpolys_dst);
- CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
- }
- if (dirty_nors_dst || do_poly_nors_dst) {
- BKE_mesh_calc_normals_poly(
- verts_dst, NULL, numverts_dst, loops_dst, polys_dst,
- numloops_dst, numpolys_dst, poly_nors_dst, true);
- }
- }
- if (need_lnors_dst) {
- short (*custom_nors_dst)[2] = CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL);
-
- /* Cache poly nors into a temp CDLayer. */
- loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL);
- const bool do_loop_nors_dst = (loop_nors_dst == NULL);
- if (!loop_nors_dst) {
- loop_nors_dst = CustomData_add_layer(ldata_dst, CD_NORMAL, CD_CALLOC, NULL, numloops_dst);
- CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
- }
- if (dirty_nors_dst || do_loop_nors_dst) {
- BKE_mesh_normals_loop_split(
- verts_dst, numverts_dst, edges_dst, numedges_dst,
- loops_dst, loop_nors_dst, numloops_dst,
- polys_dst, (const float (*)[3])poly_nors_dst, numpolys_dst,
- use_split_nors_dst, split_angle_dst, NULL, custom_nors_dst, NULL);
- }
- }
- if (need_pnors_src || need_lnors_src) {
- if (need_pnors_src) {
- poly_nors_src = CustomData_get_layer(&me_src->pdata, CD_NORMAL);
- BLI_assert(poly_nors_src != NULL);
- }
- if (need_lnors_src) {
- loop_nors_src = CustomData_get_layer(&me_src->ldata, CD_NORMAL);
- BLI_assert(loop_nors_src != NULL);
- }
- }
- }
-
- if (use_from_vert) {
- BKE_mesh_vert_loop_map_create(
- &vert_to_loop_map_src, &vert_to_loop_map_src_buff,
- polys_src, loops_src, num_verts_src, num_polys_src, num_loops_src);
- if (mode & MREMAP_USE_POLY) {
- BKE_mesh_vert_poly_map_create(
- &vert_to_poly_map_src, &vert_to_poly_map_src_buff,
- polys_src, loops_src, num_verts_src, num_polys_src, num_loops_src);
- }
- }
-
- /* Needed for islands (or plain mesh) to AStar graph conversion. */
- BKE_mesh_edge_poly_map_create(
- &edge_to_poly_map_src, &edge_to_poly_map_src_buff,
- edges_src, num_edges_src, polys_src, num_polys_src, loops_src, num_loops_src);
- if (use_from_vert) {
- loop_to_poly_map_src = MEM_mallocN(sizeof(*loop_to_poly_map_src) * (size_t)num_loops_src, __func__);
- poly_cents_src = MEM_mallocN(sizeof(*poly_cents_src) * (size_t)num_polys_src, __func__);
- for (pidx_src = 0, mp_src = polys_src; pidx_src < num_polys_src; pidx_src++, mp_src++) {
- ml_src = &loops_src[mp_src->loopstart];
- for (plidx_src = 0, lidx_src = mp_src->loopstart; plidx_src < mp_src->totloop; plidx_src++, lidx_src++) {
- loop_to_poly_map_src[lidx_src] = pidx_src;
- }
- BKE_mesh_calc_poly_center(mp_src, ml_src, verts_src, poly_cents_src[pidx_src]);
- }
- }
-
- /* Island makes things slightly more complex here.
- * Basically, we:
- * * Make one treedata for each island's elements.
- * * Check all loops of a same dest poly against all treedata.
- * * Choose the island's elements giving the best results.
- */
-
- /* First, generate the islands, if possible. */
- if (gen_islands_src) {
- use_islands = gen_islands_src(
- verts_src, num_verts_src,
- edges_src, num_edges_src,
- polys_src, num_polys_src,
- loops_src, num_loops_src,
- &island_store);
-
- num_trees = use_islands ? island_store.islands_num : 1;
- treedata = MEM_callocN(sizeof(*treedata) * (size_t)num_trees, __func__);
- if (isld_steps_src) {
- as_graphdata = MEM_callocN(sizeof(*as_graphdata) * (size_t)num_trees, __func__);
- }
-
- if (use_islands) {
- /* We expect our islands to contain poly indices, with edge indices of 'inner cuts',
- * and a mapping loops -> islands indices.
- * This implies all loops of a same poly are in the same island. */
- BLI_assert((island_store.item_type == MISLAND_TYPE_LOOP) &&
- (island_store.island_type == MISLAND_TYPE_POLY) &&
- (island_store.innercut_type == MISLAND_TYPE_EDGE));
- }
- }
- else {
- num_trees = 1;
- treedata = MEM_callocN(sizeof(*treedata), __func__);
- if (isld_steps_src) {
- as_graphdata = MEM_callocN(sizeof(*as_graphdata), __func__);
- }
- }
-
- /* Build our AStar graphs. */
- if (isld_steps_src) {
- for (tindex = 0; tindex < num_trees; tindex++) {
- mesh_island_to_astar_graph(
- use_islands ? &island_store : NULL, tindex, verts_src, edge_to_poly_map_src, num_edges_src,
- loops_src, polys_src, num_polys_src, &as_graphdata[tindex]);
- }
- }
-
- /* Build our BVHtrees, either from verts or tessfaces. */
- if (use_from_vert) {
- if (use_islands) {
- BLI_bitmap *verts_active = BLI_BITMAP_NEW((size_t)num_verts_src, __func__);
-
- for (tindex = 0; tindex < num_trees; tindex++) {
- MeshElemMap *isld = island_store.islands[tindex];
- int num_verts_active = 0;
- BLI_bitmap_set_all(verts_active, false, (size_t)num_verts_src);
- for (i = 0; i < isld->count; i++) {
- mp_src = &polys_src[isld->indices[i]];
- for (lidx_src = mp_src->loopstart; lidx_src < mp_src->loopstart + mp_src->totloop; lidx_src++) {
- const unsigned int vidx_src = loops_src[lidx_src].v;
- if (!BLI_BITMAP_TEST(verts_active, vidx_src)) {
- BLI_BITMAP_ENABLE(verts_active, loops_src[lidx_src].v);
- num_verts_active++;
- }
- }
- }
- bvhtree_from_mesh_verts_ex(
- &treedata[tindex], verts_src, num_verts_src, false,
- verts_active, num_verts_active, 0.0, 2, 6);
- }
-
- MEM_freeN(verts_active);
- }
- else {
- BLI_assert(num_trees == 1);
- BKE_bvhtree_from_mesh_get(&treedata[0], me_src, BVHTREE_FROM_VERTS, 2);
- }
- }
- else { /* We use polygons. */
- if (use_islands) {
- /* bvhtree here uses looptri faces... */
- BLI_bitmap *looptri_active;
-
- looptri_src = BKE_mesh_runtime_looptri_ensure(me_src);
- num_looptri_src = me_src->runtime.looptris.len;
- looptri_active = BLI_BITMAP_NEW((size_t)num_looptri_src, __func__);
-
- for (tindex = 0; tindex < num_trees; tindex++) {
- int num_looptri_active = 0;
- BLI_bitmap_set_all(looptri_active, false, (size_t)num_looptri_src);
- for (i = 0; i < num_looptri_src; i++) {
- mp_src = &polys_src[looptri_src[i].poly];
- if (island_store.items_to_islands[mp_src->loopstart] == tindex) {
- BLI_BITMAP_ENABLE(looptri_active, i);
- num_looptri_active++;
- }
- }
- bvhtree_from_mesh_looptri_ex(
- &treedata[tindex],
- verts_src, false,
- loops_src, false,
- looptri_src, num_looptri_src, false,
- looptri_active, num_looptri_active, 0.0, 2, 6);
- }
-
- MEM_freeN(looptri_active);
- }
- else {
- BLI_assert(num_trees == 1);
- BKE_bvhtree_from_mesh_get(&treedata[0], me_src, BVHTREE_FROM_LOOPTRI, 2);
- }
- }
-
- /* And check each dest poly! */
- islands_res = MEM_mallocN(sizeof(*islands_res) * (size_t)num_trees, __func__);
- for (tindex = 0; tindex < num_trees; tindex++) {
- islands_res[tindex] = MEM_mallocN(sizeof(**islands_res) * islands_res_buff_size, __func__);
- }
-
- for (pidx_dst = 0, mp_dst = polys_dst; pidx_dst < numpolys_dst; pidx_dst++, mp_dst++) {
- float pnor_dst[3];
-
- /* Only in use_from_vert case, we may need polys' centers as fallback in case we cannot decide which
- * corner to use from normals only. */
- float pcent_dst[3];
- bool pcent_dst_valid = false;
-
- if (mode == MREMAP_MODE_LOOP_NEAREST_POLYNOR) {
- copy_v3_v3(pnor_dst, poly_nors_dst[pidx_dst]);
- if (space_transform) {
- BLI_space_transform_apply_normal(space_transform, pnor_dst);
- }
- }
-
- if ((size_t)mp_dst->totloop > islands_res_buff_size) {
- islands_res_buff_size = (size_t)mp_dst->totloop + MREMAP_DEFAULT_BUFSIZE;
- for (tindex = 0; tindex < num_trees; tindex++) {
- islands_res[tindex] = MEM_reallocN(islands_res[tindex], sizeof(**islands_res) * islands_res_buff_size);
- }
- }
-
- for (tindex = 0; tindex < num_trees; tindex++) {
- BVHTreeFromMesh *tdata = &treedata[tindex];
-
- ml_dst = &loops_dst[mp_dst->loopstart];
- for (plidx_dst = 0; plidx_dst < mp_dst->totloop; plidx_dst++, ml_dst++) {
- if (use_from_vert) {
- MeshElemMap *vert_to_refelem_map_src = NULL;
-
- copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co);
- nearest.index = -1;
-
- /* Convert the vertex to tree coordinates, if needed. */
- if (space_transform) {
- BLI_space_transform_apply(space_transform, tmp_co);
- }
-
- if (mesh_remap_bvhtree_query_nearest(tdata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
- float (*nor_dst)[3];
- float (*nors_src)[3];
- float best_nor_dot = -2.0f;
- float best_sqdist_fallback = FLT_MAX;
- int best_index_src = -1;
-
- if (mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) {
- copy_v3_v3(tmp_no, loop_nors_dst[plidx_dst + mp_dst->loopstart]);
- if (space_transform) {
- BLI_space_transform_apply_normal(space_transform, tmp_no);
- }
- nor_dst = &tmp_no;
- nors_src = loop_nors_src;
- vert_to_refelem_map_src = vert_to_loop_map_src;
- }
- else { /* if (mode == MREMAP_MODE_LOOP_NEAREST_POLYNOR) { */
- nor_dst = &pnor_dst;
- nors_src = poly_nors_src;
- vert_to_refelem_map_src = vert_to_poly_map_src;
- }
-
- for (i = vert_to_refelem_map_src[nearest.index].count; i--;) {
- const int index_src = vert_to_refelem_map_src[nearest.index].indices[i];
- BLI_assert(index_src != -1);
- const float dot = dot_v3v3(nors_src[index_src], *nor_dst);
-
- pidx_src = (
- (mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) ?
- loop_to_poly_map_src[index_src] : index_src);
- /* WARNING! This is not the *real* lidx_src in case of POLYNOR, we only use it
- * to check we stay on current island (all loops from a given poly are
- * on same island!). */
- lidx_src = (
- (mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) ?
- index_src : polys_src[pidx_src].loopstart);
-
- /* A same vert may be at the boundary of several islands! Hence, we have to ensure
- * poly/loop we are currently considering *belongs* to current island! */
- if (use_islands && island_store.items_to_islands[lidx_src] != tindex) {
- continue;
- }
-
- if (dot > best_nor_dot - 1e-6f) {
- /* We need something as fallback decision in case dest normal matches several
- * source normals (see T44522), using distance between polys' centers here. */
- float *pcent_src;
- float sqdist;
-
- mp_src = &polys_src[pidx_src];
- ml_src = &loops_src[mp_src->loopstart];
-
- if (!pcent_dst_valid) {
- BKE_mesh_calc_poly_center(
- mp_dst, &loops_dst[mp_dst->loopstart], verts_dst, pcent_dst);
- pcent_dst_valid = true;
- }
- pcent_src = poly_cents_src[pidx_src];
- sqdist = len_squared_v3v3(pcent_dst, pcent_src);
-
- if ((dot > best_nor_dot + 1e-6f) || (sqdist < best_sqdist_fallback)) {
- best_nor_dot = dot;
- best_sqdist_fallback = sqdist;
- best_index_src = index_src;
- }
- }
- }
- if (best_index_src == -1) {
- /* We found no item to map back from closest vertex... */
- best_nor_dot = -1.0f;
- hit_dist = FLT_MAX;
- }
- else if (mode == MREMAP_MODE_LOOP_NEAREST_POLYNOR) {
- /* Our best_index_src is a poly one for now!
- * Have to find its loop matching our closest vertex. */
- mp_src = &polys_src[best_index_src];
- ml_src = &loops_src[mp_src->loopstart];
- for (plidx_src = 0; plidx_src < mp_src->totloop; plidx_src++, ml_src++) {
- if ((int)ml_src->v == nearest.index) {
- best_index_src = plidx_src + mp_src->loopstart;
- break;
- }
- }
- }
- best_nor_dot = (best_nor_dot + 1.0f) * 0.5f;
- islands_res[tindex][plidx_dst].factor = hit_dist ? (best_nor_dot / hit_dist) : 1e18f;
- islands_res[tindex][plidx_dst].hit_dist = hit_dist;
- islands_res[tindex][plidx_dst].index_src = best_index_src;
- }
- else {
- /* No source for this dest loop! */
- islands_res[tindex][plidx_dst].factor = 0.0f;
- islands_res[tindex][plidx_dst].hit_dist = FLT_MAX;
- islands_res[tindex][plidx_dst].index_src = -1;
- }
- }
- else if (mode & MREMAP_USE_NORPROJ) {
- int n = (ray_radius > 0.0f) ? MREMAP_RAYCAST_APPROXIMATE_NR : 1;
- float w = 1.0f;
-
- copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co);
- copy_v3_v3(tmp_no, loop_nors_dst[plidx_dst + mp_dst->loopstart]);
-
- /* We do our transform here, since we may do several raycast/nearest queries. */
- if (space_transform) {
- BLI_space_transform_apply(space_transform, tmp_co);
- BLI_space_transform_apply_normal(space_transform, tmp_no);
- }
-
- while (n--) {
- if (mesh_remap_bvhtree_query_raycast(
- tdata, &rayhit, tmp_co, tmp_no, ray_radius / w, max_dist, &hit_dist))
- {
- islands_res[tindex][plidx_dst].factor = (hit_dist ? (1.0f / hit_dist) : 1e18f) * w;
- islands_res[tindex][plidx_dst].hit_dist = hit_dist;
- islands_res[tindex][plidx_dst].index_src = (int)tdata->looptri[rayhit.index].poly;
- copy_v3_v3(islands_res[tindex][plidx_dst].hit_point, rayhit.co);
- break;
- }
- /* Next iteration will get bigger radius but smaller weight! */
- w /= MREMAP_RAYCAST_APPROXIMATE_FAC;
- }
- if (n == -1) {
- /* Fallback to 'nearest' hit here, loops usually comes in 'face group', not good to
- * have only part of one dest face's loops to map to source.
- * Note that since we give this a null weight, if whole weight for a given face
- * is null, it means none of its loop mapped to this source island, hence we can skip it
- * later.
- */
- copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co);
- nearest.index = -1;
-
- /* Convert the vertex to tree coordinates, if needed. */
- if (space_transform) {
- BLI_space_transform_apply(space_transform, tmp_co);
- }
-
- /* In any case, this fallback nearest hit should have no weight at all
- * in 'best island' decision! */
- islands_res[tindex][plidx_dst].factor = 0.0f;
-
- if (mesh_remap_bvhtree_query_nearest(tdata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
- islands_res[tindex][plidx_dst].hit_dist = hit_dist;
- islands_res[tindex][plidx_dst].index_src = (int)tdata->looptri[nearest.index].poly;
- copy_v3_v3(islands_res[tindex][plidx_dst].hit_point, nearest.co);
- }
- else {
- /* No source for this dest loop! */
- islands_res[tindex][plidx_dst].hit_dist = FLT_MAX;
- islands_res[tindex][plidx_dst].index_src = -1;
- }
- }
- }
- else { /* Nearest poly either to use all its loops/verts or just closest one. */
- copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co);
- nearest.index = -1;
-
- /* Convert the vertex to tree coordinates, if needed. */
- if (space_transform) {
- BLI_space_transform_apply(space_transform, tmp_co);
- }
-
- if (mesh_remap_bvhtree_query_nearest(tdata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
- islands_res[tindex][plidx_dst].factor = hit_dist ? (1.0f / hit_dist) : 1e18f;
- islands_res[tindex][plidx_dst].hit_dist = hit_dist;
- islands_res[tindex][plidx_dst].index_src = (int)tdata->looptri[nearest.index].poly;
- copy_v3_v3(islands_res[tindex][plidx_dst].hit_point, nearest.co);
- }
- else {
- /* No source for this dest loop! */
- islands_res[tindex][plidx_dst].factor = 0.0f;
- islands_res[tindex][plidx_dst].hit_dist = FLT_MAX;
- islands_res[tindex][plidx_dst].index_src = -1;
- }
- }
- }
- }
-
- /* And now, find best island to use! */
- /* We have to first select the 'best source island' for given dst poly and its loops.
- * Then, we have to check that poly does not 'spread' across some island's limits
- * (like inner seams for UVs, etc.).
- * Note we only still partially support that kind of situation here, i.e. polys spreading over actual cracks
- * (like a narrow space without faces on src, splitting a 'tube-like' geometry). That kind of situation
- * should be relatively rare, though.
- */
- /* XXX This block in itself is big and complex enough to be a separate function but... it uses a bunch
- * of locale vars. Not worth sending all that through parameters (for now at least). */
- {
- BLI_AStarGraph *as_graph = NULL;
- int *poly_island_index_map = NULL;
- int pidx_src_prev = -1;
-
- MeshElemMap *best_island = NULL;
- float best_island_fac = 0.0f;
- int best_island_index = -1;
-
- for (tindex = 0; tindex < num_trees; tindex++) {
- float island_fac = 0.0f;
-
- for (plidx_dst = 0; plidx_dst < mp_dst->totloop; plidx_dst++) {
- island_fac += islands_res[tindex][plidx_dst].factor;
- }
- island_fac /= (float)mp_dst->totloop;
-
- if (island_fac > best_island_fac) {
- best_island_fac = island_fac;
- best_island_index = tindex;
- }
- }
-
- if (best_island_index != -1 && isld_steps_src) {
- best_island = use_islands ? island_store.islands[best_island_index] : NULL;
- as_graph = &as_graphdata[best_island_index];
- poly_island_index_map = (int *)as_graph->custom_data;
- BLI_astar_solution_init(as_graph, &as_solution, NULL);
- }
-
- for (plidx_dst = 0; plidx_dst < mp_dst->totloop; plidx_dst++) {
- IslandResult *isld_res;
- lidx_dst = plidx_dst + mp_dst->loopstart;
-
- if (best_island_index == -1) {
- /* No source for any loops of our dest poly in any source islands. */
- BKE_mesh_remap_item_define_invalid(r_map, lidx_dst);
- continue;
- }
-
- as_solution.custom_data = POINTER_FROM_INT(false);
-
- isld_res = &islands_res[best_island_index][plidx_dst];
- if (use_from_vert) {
- /* Indices stored in islands_res are those of loops, one per dest loop. */
- lidx_src = isld_res->index_src;
- if (lidx_src >= 0) {
- pidx_src = loop_to_poly_map_src[lidx_src];
- /* If prev and curr poly are the same, no need to do anything more!!! */
- if (!ELEM(pidx_src_prev, -1, pidx_src) && isld_steps_src) {
- int pidx_isld_src, pidx_isld_src_prev;
- if (poly_island_index_map) {
- pidx_isld_src = poly_island_index_map[pidx_src];
- pidx_isld_src_prev = poly_island_index_map[pidx_src_prev];
- }
- else {
- pidx_isld_src = pidx_src;
- pidx_isld_src_prev = pidx_src_prev;
- }
-
- BLI_astar_graph_solve(
- as_graph, pidx_isld_src_prev, pidx_isld_src,
- mesh_remap_calc_loops_astar_f_cost, &as_solution, isld_steps_src);
- if (POINTER_AS_INT(as_solution.custom_data) && (as_solution.steps > 0)) {
- /* Find first 'cutting edge' on path, and bring back lidx_src on poly just
- * before that edge.
- * Note we could try to be much smarter (like e.g. storing a whole poly's indices,
- * and making decision (on which side of cutting edge(s!) to be) on the end,
- * but this is one more level of complexity, better to first see if
- * simple solution works!
- */
- int last_valid_pidx_isld_src = -1;
- /* Note we go backward here, from dest to src poly. */
- for (i = as_solution.steps - 1; i--;) {
- BLI_AStarGNLink *as_link = as_solution.prev_links[pidx_isld_src];
- const int eidx = POINTER_AS_INT(as_link->custom_data);
- pidx_isld_src = as_solution.prev_nodes[pidx_isld_src];
- BLI_assert(pidx_isld_src != -1);
- if (eidx != -1) {
- /* we are 'crossing' a cutting edge. */
- last_valid_pidx_isld_src = pidx_isld_src;
- }
- }
- if (last_valid_pidx_isld_src != -1) {
- /* Find a new valid loop in that new poly (nearest one for now).
- * Note we could be much more subtle here, again that's for later... */
- int j;
- float best_dist_sq = FLT_MAX;
-
- ml_dst = &loops_dst[lidx_dst];
- copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co);
-
- /* We do our transform here, since we may do several raycast/nearest queries. */
- if (space_transform) {
- BLI_space_transform_apply(space_transform, tmp_co);
- }
-
- pidx_src = (
- use_islands ? best_island->indices[last_valid_pidx_isld_src] :
- last_valid_pidx_isld_src);
- mp_src = &polys_src[pidx_src];
- ml_src = &loops_src[mp_src->loopstart];
- for (j = 0; j < mp_src->totloop; j++, ml_src++) {
- const float dist_sq = len_squared_v3v3(verts_src[ml_src->v].co, tmp_co);
- if (dist_sq < best_dist_sq) {
- best_dist_sq = dist_sq;
- lidx_src = mp_src->loopstart + j;
- }
- }
- }
- }
- }
- mesh_remap_item_define(
- r_map, lidx_dst, isld_res->hit_dist,
- best_island_index, 1, &lidx_src, &full_weight);
- pidx_src_prev = pidx_src;
- }
- else {
- /* No source for this loop in this island. */
- /* TODO: would probably be better to get a source at all cost in best island anyway? */
- mesh_remap_item_define(
- r_map, lidx_dst, FLT_MAX,
- best_island_index, 0, NULL, NULL);
- }
- }
- else {
- /* Else, we use source poly, indices stored in islands_res are those of polygons. */
- pidx_src = isld_res->index_src;
- if (pidx_src >= 0) {
- float *hit_co = isld_res->hit_point;
- int best_loop_index_src;
-
- mp_src = &polys_src[pidx_src];
- /* If prev and curr poly are the same, no need to do anything more!!! */
- if (!ELEM(pidx_src_prev, -1, pidx_src) && isld_steps_src) {
- int pidx_isld_src, pidx_isld_src_prev;
- if (poly_island_index_map) {
- pidx_isld_src = poly_island_index_map[pidx_src];
- pidx_isld_src_prev = poly_island_index_map[pidx_src_prev];
- }
- else {
- pidx_isld_src = pidx_src;
- pidx_isld_src_prev = pidx_src_prev;
- }
-
- BLI_astar_graph_solve(
- as_graph, pidx_isld_src_prev, pidx_isld_src,
- mesh_remap_calc_loops_astar_f_cost, &as_solution, isld_steps_src);
- if (POINTER_AS_INT(as_solution.custom_data) && (as_solution.steps > 0)) {
- /* Find first 'cutting edge' on path, and bring back lidx_src on poly just
- * before that edge.
- * Note we could try to be much smarter (like e.g. storing a whole poly's indices,
- * and making decision (one which side of cutting edge(s!) to be on the end,
- * but this is one more level of complexity, better to first see if
- * simple solution works!
- */
- int last_valid_pidx_isld_src = -1;
- /* Note we go backward here, from dest to src poly. */
- for (i = as_solution.steps - 1; i--;) {
- BLI_AStarGNLink *as_link = as_solution.prev_links[pidx_isld_src];
- int eidx = POINTER_AS_INT(as_link->custom_data);
-
- pidx_isld_src = as_solution.prev_nodes[pidx_isld_src];
- BLI_assert(pidx_isld_src != -1);
- if (eidx != -1) {
- /* we are 'crossing' a cutting edge. */
- last_valid_pidx_isld_src = pidx_isld_src;
- }
- }
- if (last_valid_pidx_isld_src != -1) {
- /* Find a new valid loop in that new poly (nearest point on poly for now).
- * Note we could be much more subtle here, again that's for later... */
- float best_dist_sq = FLT_MAX;
- int j;
-
- ml_dst = &loops_dst[lidx_dst];
- copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co);
-
- /* We do our transform here, since we may do several raycast/nearest queries. */
- if (space_transform) {
- BLI_space_transform_apply(space_transform, tmp_co);
- }
-
- pidx_src = (
- use_islands ? best_island->indices[last_valid_pidx_isld_src] :
- last_valid_pidx_isld_src);
- mp_src = &polys_src[pidx_src];
-
- /* Create that one on demand. */
- if (poly_to_looptri_map_src == NULL) {
- BKE_mesh_origindex_map_create_looptri(
- &poly_to_looptri_map_src, &poly_to_looptri_map_src_buff,
- polys_src, num_polys_src,
- looptri_src, num_looptri_src);
- }
-
- for (j = poly_to_looptri_map_src[pidx_src].count; j--;) {
- float h[3];
- const MLoopTri *lt = &looptri_src[poly_to_looptri_map_src[pidx_src].indices[j]];
- float dist_sq;
-
- closest_on_tri_to_point_v3(
- h, tmp_co,
- vcos_src[loops_src[lt->tri[0]].v],
- vcos_src[loops_src[lt->tri[1]].v],
- vcos_src[loops_src[lt->tri[2]].v]);
- dist_sq = len_squared_v3v3(tmp_co, h);
- if (dist_sq < best_dist_sq) {
- copy_v3_v3(hit_co, h);
- best_dist_sq = dist_sq;
- }
- }
- }
- }
- }
-
- if (mode == MREMAP_MODE_LOOP_POLY_NEAREST) {
- mesh_remap_interp_poly_data_get(
- mp_src, loops_src, (const float (*)[3])vcos_src, hit_co,
- &buff_size_interp, &vcos_interp, true, &indices_interp,
- &weights_interp, false, &best_loop_index_src);
-
- mesh_remap_item_define(
- r_map, lidx_dst, isld_res->hit_dist,
- best_island_index, 1, &best_loop_index_src, &full_weight);
- }
- else {
- const int sources_num = mesh_remap_interp_poly_data_get(
- mp_src, loops_src, (const float (*)[3])vcos_src, hit_co,
- &buff_size_interp, &vcos_interp, true, &indices_interp,
- &weights_interp, true, NULL);
-
- mesh_remap_item_define(
- r_map, lidx_dst,
- isld_res->hit_dist, best_island_index,
- sources_num, indices_interp, weights_interp);
- }
-
- pidx_src_prev = pidx_src;
- }
- else {
- /* No source for this loop in this island. */
- /* TODO: would probably be better to get a source at all cost in best island anyway? */
- mesh_remap_item_define(r_map, lidx_dst, FLT_MAX, best_island_index, 0, NULL, NULL);
- }
- }
- }
-
- BLI_astar_solution_clear(&as_solution);
- }
- }
-
- for (tindex = 0; tindex < num_trees; tindex++) {
- MEM_freeN(islands_res[tindex]);
- free_bvhtree_from_mesh(&treedata[tindex]);
- if (isld_steps_src) {
- BLI_astar_graph_free(&as_graphdata[tindex]);
- }
- }
- MEM_freeN(islands_res);
- BKE_mesh_loop_islands_free(&island_store);
- MEM_freeN(treedata);
- if (isld_steps_src) {
- MEM_freeN(as_graphdata);
- BLI_astar_solution_free(&as_solution);
- }
-
- if (vcos_src) {
- MEM_freeN(vcos_src);
- }
- if (vert_to_loop_map_src) {
- MEM_freeN(vert_to_loop_map_src);
- }
- if (vert_to_loop_map_src_buff) {
- MEM_freeN(vert_to_loop_map_src_buff);
- }
- if (vert_to_poly_map_src) {
- MEM_freeN(vert_to_poly_map_src);
- }
- if (vert_to_poly_map_src_buff) {
- MEM_freeN(vert_to_poly_map_src_buff);
- }
- if (edge_to_poly_map_src) {
- MEM_freeN(edge_to_poly_map_src);
- }
- if (edge_to_poly_map_src_buff) {
- MEM_freeN(edge_to_poly_map_src_buff);
- }
- if (poly_to_looptri_map_src) {
- MEM_freeN(poly_to_looptri_map_src);
- }
- if (poly_to_looptri_map_src_buff) {
- MEM_freeN(poly_to_looptri_map_src_buff);
- }
- if (loop_to_poly_map_src) {
- MEM_freeN(loop_to_poly_map_src);
- }
- if (poly_cents_src) {
- MEM_freeN(poly_cents_src);
- }
- if (vcos_interp) {
- MEM_freeN(vcos_interp);
- }
- if (indices_interp) {
- MEM_freeN(indices_interp);
- }
- if (weights_interp) {
- MEM_freeN(weights_interp);
- }
- }
+ const float full_weight = 1.0f;
+ const float max_dist_sq = max_dist * max_dist;
+
+ int i;
+
+ BLI_assert(mode & MREMAP_MODE_LOOP);
+ BLI_assert((islands_precision_src >= 0.0f) && (islands_precision_src <= 1.0f));
+
+ BKE_mesh_remap_init(r_map, numloops_dst);
+
+ if (mode == MREMAP_MODE_TOPOLOGY) {
+ /* In topology mapping, we assume meshes are identical, islands included! */
+ BLI_assert(numloops_dst == me_src->totloop);
+ for (i = 0; i < numloops_dst; i++) {
+ mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight);
+ }
+ }
+ else {
+ BVHTreeFromMesh *treedata = NULL;
+ BVHTreeNearest nearest = {0};
+ BVHTreeRayHit rayhit = {0};
+ int num_trees = 0;
+ float hit_dist;
+ float tmp_co[3], tmp_no[3];
+
+ const bool use_from_vert = (mode & MREMAP_USE_VERT);
+
+ MeshIslandStore island_store = {0};
+ bool use_islands = false;
+
+ BLI_AStarGraph *as_graphdata = NULL;
+ BLI_AStarSolution as_solution = {0};
+ const int isld_steps_src = (islands_precision_src ?
+ max_ii((int)(ASTAR_STEPS_MAX * islands_precision_src + 0.499f),
+ 1) :
+ 0);
+
+ float(*poly_nors_src)[3] = NULL;
+ float(*loop_nors_src)[3] = NULL;
+ float(*poly_nors_dst)[3] = NULL;
+ float(*loop_nors_dst)[3] = NULL;
+
+ float(*poly_cents_src)[3] = NULL;
+
+ MeshElemMap *vert_to_loop_map_src = NULL;
+ int *vert_to_loop_map_src_buff = NULL;
+ MeshElemMap *vert_to_poly_map_src = NULL;
+ int *vert_to_poly_map_src_buff = NULL;
+ MeshElemMap *edge_to_poly_map_src = NULL;
+ int *edge_to_poly_map_src_buff = NULL;
+ MeshElemMap *poly_to_looptri_map_src = NULL;
+ int *poly_to_looptri_map_src_buff = NULL;
+
+ /* Unlike above, those are one-to-one mappings, simpler! */
+ int *loop_to_poly_map_src = NULL;
+
+ MVert *verts_src = me_src->mvert;
+ const int num_verts_src = me_src->totvert;
+ float(*vcos_src)[3] = NULL;
+ MEdge *edges_src = me_src->medge;
+ const int num_edges_src = me_src->totedge;
+ MLoop *loops_src = me_src->mloop;
+ const int num_loops_src = me_src->totloop;
+ MPoly *polys_src = me_src->mpoly;
+ const int num_polys_src = me_src->totpoly;
+ const MLoopTri *looptri_src = NULL;
+ int num_looptri_src = 0;
+
+ size_t buff_size_interp = MREMAP_DEFAULT_BUFSIZE;
+ float(*vcos_interp)[3] = NULL;
+ int *indices_interp = NULL;
+ float *weights_interp = NULL;
+
+ MLoop *ml_src, *ml_dst;
+ MPoly *mp_src, *mp_dst;
+ int tindex, pidx_dst, lidx_dst, plidx_dst, pidx_src, lidx_src, plidx_src;
+
+ IslandResult **islands_res;
+ size_t islands_res_buff_size = MREMAP_DEFAULT_BUFSIZE;
+
+ if (!use_from_vert) {
+ vcos_src = BKE_mesh_vertexCos_get(me_src, NULL);
+
+ vcos_interp = MEM_mallocN(sizeof(*vcos_interp) * buff_size_interp, __func__);
+ indices_interp = MEM_mallocN(sizeof(*indices_interp) * buff_size_interp, __func__);
+ weights_interp = MEM_mallocN(sizeof(*weights_interp) * buff_size_interp, __func__);
+ }
+
+ {
+ const bool need_lnors_src = (mode & MREMAP_USE_LOOP) && (mode & MREMAP_USE_NORMAL);
+ const bool need_lnors_dst = need_lnors_src || (mode & MREMAP_USE_NORPROJ);
+ const bool need_pnors_src = need_lnors_src ||
+ ((mode & MREMAP_USE_POLY) && (mode & MREMAP_USE_NORMAL));
+ const bool need_pnors_dst = need_lnors_dst || need_pnors_src;
+
+ if (need_pnors_dst) {
+ /* Cache poly nors into a temp CDLayer. */
+ poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL);
+ const bool do_poly_nors_dst = (poly_nors_dst == NULL);
+ if (!poly_nors_dst) {
+ poly_nors_dst = CustomData_add_layer(
+ pdata_dst, CD_NORMAL, CD_CALLOC, NULL, numpolys_dst);
+ CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
+ }
+ if (dirty_nors_dst || do_poly_nors_dst) {
+ BKE_mesh_calc_normals_poly(verts_dst,
+ NULL,
+ numverts_dst,
+ loops_dst,
+ polys_dst,
+ numloops_dst,
+ numpolys_dst,
+ poly_nors_dst,
+ true);
+ }
+ }
+ if (need_lnors_dst) {
+ short(*custom_nors_dst)[2] = CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL);
+
+ /* Cache poly nors into a temp CDLayer. */
+ loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL);
+ const bool do_loop_nors_dst = (loop_nors_dst == NULL);
+ if (!loop_nors_dst) {
+ loop_nors_dst = CustomData_add_layer(
+ ldata_dst, CD_NORMAL, CD_CALLOC, NULL, numloops_dst);
+ CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
+ }
+ if (dirty_nors_dst || do_loop_nors_dst) {
+ BKE_mesh_normals_loop_split(verts_dst,
+ numverts_dst,
+ edges_dst,
+ numedges_dst,
+ loops_dst,
+ loop_nors_dst,
+ numloops_dst,
+ polys_dst,
+ (const float(*)[3])poly_nors_dst,
+ numpolys_dst,
+ use_split_nors_dst,
+ split_angle_dst,
+ NULL,
+ custom_nors_dst,
+ NULL);
+ }
+ }
+ if (need_pnors_src || need_lnors_src) {
+ if (need_pnors_src) {
+ poly_nors_src = CustomData_get_layer(&me_src->pdata, CD_NORMAL);
+ BLI_assert(poly_nors_src != NULL);
+ }
+ if (need_lnors_src) {
+ loop_nors_src = CustomData_get_layer(&me_src->ldata, CD_NORMAL);
+ BLI_assert(loop_nors_src != NULL);
+ }
+ }
+ }
+
+ if (use_from_vert) {
+ BKE_mesh_vert_loop_map_create(&vert_to_loop_map_src,
+ &vert_to_loop_map_src_buff,
+ polys_src,
+ loops_src,
+ num_verts_src,
+ num_polys_src,
+ num_loops_src);
+ if (mode & MREMAP_USE_POLY) {
+ BKE_mesh_vert_poly_map_create(&vert_to_poly_map_src,
+ &vert_to_poly_map_src_buff,
+ polys_src,
+ loops_src,
+ num_verts_src,
+ num_polys_src,
+ num_loops_src);
+ }
+ }
+
+ /* Needed for islands (or plain mesh) to AStar graph conversion. */
+ BKE_mesh_edge_poly_map_create(&edge_to_poly_map_src,
+ &edge_to_poly_map_src_buff,
+ edges_src,
+ num_edges_src,
+ polys_src,
+ num_polys_src,
+ loops_src,
+ num_loops_src);
+ if (use_from_vert) {
+ loop_to_poly_map_src = MEM_mallocN(sizeof(*loop_to_poly_map_src) * (size_t)num_loops_src,
+ __func__);
+ poly_cents_src = MEM_mallocN(sizeof(*poly_cents_src) * (size_t)num_polys_src, __func__);
+ for (pidx_src = 0, mp_src = polys_src; pidx_src < num_polys_src; pidx_src++, mp_src++) {
+ ml_src = &loops_src[mp_src->loopstart];
+ for (plidx_src = 0, lidx_src = mp_src->loopstart; plidx_src < mp_src->totloop;
+ plidx_src++, lidx_src++) {
+ loop_to_poly_map_src[lidx_src] = pidx_src;
+ }
+ BKE_mesh_calc_poly_center(mp_src, ml_src, verts_src, poly_cents_src[pidx_src]);
+ }
+ }
+
+ /* Island makes things slightly more complex here.
+ * Basically, we:
+ * * Make one treedata for each island's elements.
+ * * Check all loops of a same dest poly against all treedata.
+ * * Choose the island's elements giving the best results.
+ */
+
+ /* First, generate the islands, if possible. */
+ if (gen_islands_src) {
+ use_islands = gen_islands_src(verts_src,
+ num_verts_src,
+ edges_src,
+ num_edges_src,
+ polys_src,
+ num_polys_src,
+ loops_src,
+ num_loops_src,
+ &island_store);
+
+ num_trees = use_islands ? island_store.islands_num : 1;
+ treedata = MEM_callocN(sizeof(*treedata) * (size_t)num_trees, __func__);
+ if (isld_steps_src) {
+ as_graphdata = MEM_callocN(sizeof(*as_graphdata) * (size_t)num_trees, __func__);
+ }
+
+ if (use_islands) {
+ /* We expect our islands to contain poly indices, with edge indices of 'inner cuts',
+ * and a mapping loops -> islands indices.
+ * This implies all loops of a same poly are in the same island. */
+ BLI_assert((island_store.item_type == MISLAND_TYPE_LOOP) &&
+ (island_store.island_type == MISLAND_TYPE_POLY) &&
+ (island_store.innercut_type == MISLAND_TYPE_EDGE));
+ }
+ }
+ else {
+ num_trees = 1;
+ treedata = MEM_callocN(sizeof(*treedata), __func__);
+ if (isld_steps_src) {
+ as_graphdata = MEM_callocN(sizeof(*as_graphdata), __func__);
+ }
+ }
+
+ /* Build our AStar graphs. */
+ if (isld_steps_src) {
+ for (tindex = 0; tindex < num_trees; tindex++) {
+ mesh_island_to_astar_graph(use_islands ? &island_store : NULL,
+ tindex,
+ verts_src,
+ edge_to_poly_map_src,
+ num_edges_src,
+ loops_src,
+ polys_src,
+ num_polys_src,
+ &as_graphdata[tindex]);
+ }
+ }
+
+ /* Build our BVHtrees, either from verts or tessfaces. */
+ if (use_from_vert) {
+ if (use_islands) {
+ BLI_bitmap *verts_active = BLI_BITMAP_NEW((size_t)num_verts_src, __func__);
+
+ for (tindex = 0; tindex < num_trees; tindex++) {
+ MeshElemMap *isld = island_store.islands[tindex];
+ int num_verts_active = 0;
+ BLI_bitmap_set_all(verts_active, false, (size_t)num_verts_src);
+ for (i = 0; i < isld->count; i++) {
+ mp_src = &polys_src[isld->indices[i]];
+ for (lidx_src = mp_src->loopstart; lidx_src < mp_src->loopstart + mp_src->totloop;
+ lidx_src++) {
+ const unsigned int vidx_src = loops_src[lidx_src].v;
+ if (!BLI_BITMAP_TEST(verts_active, vidx_src)) {
+ BLI_BITMAP_ENABLE(verts_active, loops_src[lidx_src].v);
+ num_verts_active++;
+ }
+ }
+ }
+ bvhtree_from_mesh_verts_ex(&treedata[tindex],
+ verts_src,
+ num_verts_src,
+ false,
+ verts_active,
+ num_verts_active,
+ 0.0,
+ 2,
+ 6);
+ }
+
+ MEM_freeN(verts_active);
+ }
+ else {
+ BLI_assert(num_trees == 1);
+ BKE_bvhtree_from_mesh_get(&treedata[0], me_src, BVHTREE_FROM_VERTS, 2);
+ }
+ }
+ else { /* We use polygons. */
+ if (use_islands) {
+ /* bvhtree here uses looptri faces... */
+ BLI_bitmap *looptri_active;
+
+ looptri_src = BKE_mesh_runtime_looptri_ensure(me_src);
+ num_looptri_src = me_src->runtime.looptris.len;
+ looptri_active = BLI_BITMAP_NEW((size_t)num_looptri_src, __func__);
+
+ for (tindex = 0; tindex < num_trees; tindex++) {
+ int num_looptri_active = 0;
+ BLI_bitmap_set_all(looptri_active, false, (size_t)num_looptri_src);
+ for (i = 0; i < num_looptri_src; i++) {
+ mp_src = &polys_src[looptri_src[i].poly];
+ if (island_store.items_to_islands[mp_src->loopstart] == tindex) {
+ BLI_BITMAP_ENABLE(looptri_active, i);
+ num_looptri_active++;
+ }
+ }
+ bvhtree_from_mesh_looptri_ex(&treedata[tindex],
+ verts_src,
+ false,
+ loops_src,
+ false,
+ looptri_src,
+ num_looptri_src,
+ false,
+ looptri_active,
+ num_looptri_active,
+ 0.0,
+ 2,
+ 6);
+ }
+
+ MEM_freeN(looptri_active);
+ }
+ else {
+ BLI_assert(num_trees == 1);
+ BKE_bvhtree_from_mesh_get(&treedata[0], me_src, BVHTREE_FROM_LOOPTRI, 2);
+ }
+ }
+
+ /* And check each dest poly! */
+ islands_res = MEM_mallocN(sizeof(*islands_res) * (size_t)num_trees, __func__);
+ for (tindex = 0; tindex < num_trees; tindex++) {
+ islands_res[tindex] = MEM_mallocN(sizeof(**islands_res) * islands_res_buff_size, __func__);
+ }
+
+ for (pidx_dst = 0, mp_dst = polys_dst; pidx_dst < numpolys_dst; pidx_dst++, mp_dst++) {
+ float pnor_dst[3];
+
+ /* Only in use_from_vert case, we may need polys' centers as fallback in case we cannot decide which
+ * corner to use from normals only. */
+ float pcent_dst[3];
+ bool pcent_dst_valid = false;
+
+ if (mode == MREMAP_MODE_LOOP_NEAREST_POLYNOR) {
+ copy_v3_v3(pnor_dst, poly_nors_dst[pidx_dst]);
+ if (space_transform) {
+ BLI_space_transform_apply_normal(space_transform, pnor_dst);
+ }
+ }
+
+ if ((size_t)mp_dst->totloop > islands_res_buff_size) {
+ islands_res_buff_size = (size_t)mp_dst->totloop + MREMAP_DEFAULT_BUFSIZE;
+ for (tindex = 0; tindex < num_trees; tindex++) {
+ islands_res[tindex] = MEM_reallocN(islands_res[tindex],
+ sizeof(**islands_res) * islands_res_buff_size);
+ }
+ }
+
+ for (tindex = 0; tindex < num_trees; tindex++) {
+ BVHTreeFromMesh *tdata = &treedata[tindex];
+
+ ml_dst = &loops_dst[mp_dst->loopstart];
+ for (plidx_dst = 0; plidx_dst < mp_dst->totloop; plidx_dst++, ml_dst++) {
+ if (use_from_vert) {
+ MeshElemMap *vert_to_refelem_map_src = NULL;
+
+ copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co);
+ nearest.index = -1;
+
+ /* Convert the vertex to tree coordinates, if needed. */
+ if (space_transform) {
+ BLI_space_transform_apply(space_transform, tmp_co);
+ }
+
+ if (mesh_remap_bvhtree_query_nearest(
+ tdata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
+ float(*nor_dst)[3];
+ float(*nors_src)[3];
+ float best_nor_dot = -2.0f;
+ float best_sqdist_fallback = FLT_MAX;
+ int best_index_src = -1;
+
+ if (mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) {
+ copy_v3_v3(tmp_no, loop_nors_dst[plidx_dst + mp_dst->loopstart]);
+ if (space_transform) {
+ BLI_space_transform_apply_normal(space_transform, tmp_no);
+ }
+ nor_dst = &tmp_no;
+ nors_src = loop_nors_src;
+ vert_to_refelem_map_src = vert_to_loop_map_src;
+ }
+ else { /* if (mode == MREMAP_MODE_LOOP_NEAREST_POLYNOR) { */
+ nor_dst = &pnor_dst;
+ nors_src = poly_nors_src;
+ vert_to_refelem_map_src = vert_to_poly_map_src;
+ }
+
+ for (i = vert_to_refelem_map_src[nearest.index].count; i--;) {
+ const int index_src = vert_to_refelem_map_src[nearest.index].indices[i];
+ BLI_assert(index_src != -1);
+ const float dot = dot_v3v3(nors_src[index_src], *nor_dst);
+
+ pidx_src = ((mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) ?
+ loop_to_poly_map_src[index_src] :
+ index_src);
+ /* WARNING! This is not the *real* lidx_src in case of POLYNOR, we only use it
+ * to check we stay on current island (all loops from a given poly are
+ * on same island!). */
+ lidx_src = ((mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) ?
+ index_src :
+ polys_src[pidx_src].loopstart);
+
+ /* A same vert may be at the boundary of several islands! Hence, we have to ensure
+ * poly/loop we are currently considering *belongs* to current island! */
+ if (use_islands && island_store.items_to_islands[lidx_src] != tindex) {
+ continue;
+ }
+
+ if (dot > best_nor_dot - 1e-6f) {
+ /* We need something as fallback decision in case dest normal matches several
+ * source normals (see T44522), using distance between polys' centers here. */
+ float *pcent_src;
+ float sqdist;
+
+ mp_src = &polys_src[pidx_src];
+ ml_src = &loops_src[mp_src->loopstart];
+
+ if (!pcent_dst_valid) {
+ BKE_mesh_calc_poly_center(
+ mp_dst, &loops_dst[mp_dst->loopstart], verts_dst, pcent_dst);
+ pcent_dst_valid = true;
+ }
+ pcent_src = poly_cents_src[pidx_src];
+ sqdist = len_squared_v3v3(pcent_dst, pcent_src);
+
+ if ((dot > best_nor_dot + 1e-6f) || (sqdist < best_sqdist_fallback)) {
+ best_nor_dot = dot;
+ best_sqdist_fallback = sqdist;
+ best_index_src = index_src;
+ }
+ }
+ }
+ if (best_index_src == -1) {
+ /* We found no item to map back from closest vertex... */
+ best_nor_dot = -1.0f;
+ hit_dist = FLT_MAX;
+ }
+ else if (mode == MREMAP_MODE_LOOP_NEAREST_POLYNOR) {
+ /* Our best_index_src is a poly one for now!
+ * Have to find its loop matching our closest vertex. */
+ mp_src = &polys_src[best_index_src];
+ ml_src = &loops_src[mp_src->loopstart];
+ for (plidx_src = 0; plidx_src < mp_src->totloop; plidx_src++, ml_src++) {
+ if ((int)ml_src->v == nearest.index) {
+ best_index_src = plidx_src + mp_src->loopstart;
+ break;
+ }
+ }
+ }
+ best_nor_dot = (best_nor_dot + 1.0f) * 0.5f;
+ islands_res[tindex][plidx_dst].factor = hit_dist ? (best_nor_dot / hit_dist) : 1e18f;
+ islands_res[tindex][plidx_dst].hit_dist = hit_dist;
+ islands_res[tindex][plidx_dst].index_src = best_index_src;
+ }
+ else {
+ /* No source for this dest loop! */
+ islands_res[tindex][plidx_dst].factor = 0.0f;
+ islands_res[tindex][plidx_dst].hit_dist = FLT_MAX;
+ islands_res[tindex][plidx_dst].index_src = -1;
+ }
+ }
+ else if (mode & MREMAP_USE_NORPROJ) {
+ int n = (ray_radius > 0.0f) ? MREMAP_RAYCAST_APPROXIMATE_NR : 1;
+ float w = 1.0f;
+
+ copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co);
+ copy_v3_v3(tmp_no, loop_nors_dst[plidx_dst + mp_dst->loopstart]);
+
+ /* We do our transform here, since we may do several raycast/nearest queries. */
+ if (space_transform) {
+ BLI_space_transform_apply(space_transform, tmp_co);
+ BLI_space_transform_apply_normal(space_transform, tmp_no);
+ }
+
+ while (n--) {
+ if (mesh_remap_bvhtree_query_raycast(
+ tdata, &rayhit, tmp_co, tmp_no, ray_radius / w, max_dist, &hit_dist)) {
+ islands_res[tindex][plidx_dst].factor = (hit_dist ? (1.0f / hit_dist) : 1e18f) * w;
+ islands_res[tindex][plidx_dst].hit_dist = hit_dist;
+ islands_res[tindex][plidx_dst].index_src = (int)tdata->looptri[rayhit.index].poly;
+ copy_v3_v3(islands_res[tindex][plidx_dst].hit_point, rayhit.co);
+ break;
+ }
+ /* Next iteration will get bigger radius but smaller weight! */
+ w /= MREMAP_RAYCAST_APPROXIMATE_FAC;
+ }
+ if (n == -1) {
+ /* Fallback to 'nearest' hit here, loops usually comes in 'face group', not good to
+ * have only part of one dest face's loops to map to source.
+ * Note that since we give this a null weight, if whole weight for a given face
+ * is null, it means none of its loop mapped to this source island, hence we can skip it
+ * later.
+ */
+ copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co);
+ nearest.index = -1;
+
+ /* Convert the vertex to tree coordinates, if needed. */
+ if (space_transform) {
+ BLI_space_transform_apply(space_transform, tmp_co);
+ }
+
+ /* In any case, this fallback nearest hit should have no weight at all
+ * in 'best island' decision! */
+ islands_res[tindex][plidx_dst].factor = 0.0f;
+
+ if (mesh_remap_bvhtree_query_nearest(
+ tdata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
+ islands_res[tindex][plidx_dst].hit_dist = hit_dist;
+ islands_res[tindex][plidx_dst].index_src = (int)tdata->looptri[nearest.index].poly;
+ copy_v3_v3(islands_res[tindex][plidx_dst].hit_point, nearest.co);
+ }
+ else {
+ /* No source for this dest loop! */
+ islands_res[tindex][plidx_dst].hit_dist = FLT_MAX;
+ islands_res[tindex][plidx_dst].index_src = -1;
+ }
+ }
+ }
+ else { /* Nearest poly either to use all its loops/verts or just closest one. */
+ copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co);
+ nearest.index = -1;
+
+ /* Convert the vertex to tree coordinates, if needed. */
+ if (space_transform) {
+ BLI_space_transform_apply(space_transform, tmp_co);
+ }
+
+ if (mesh_remap_bvhtree_query_nearest(
+ tdata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
+ islands_res[tindex][plidx_dst].factor = hit_dist ? (1.0f / hit_dist) : 1e18f;
+ islands_res[tindex][plidx_dst].hit_dist = hit_dist;
+ islands_res[tindex][plidx_dst].index_src = (int)tdata->looptri[nearest.index].poly;
+ copy_v3_v3(islands_res[tindex][plidx_dst].hit_point, nearest.co);
+ }
+ else {
+ /* No source for this dest loop! */
+ islands_res[tindex][plidx_dst].factor = 0.0f;
+ islands_res[tindex][plidx_dst].hit_dist = FLT_MAX;
+ islands_res[tindex][plidx_dst].index_src = -1;
+ }
+ }
+ }
+ }
+
+ /* And now, find best island to use! */
+ /* We have to first select the 'best source island' for given dst poly and its loops.
+ * Then, we have to check that poly does not 'spread' across some island's limits
+ * (like inner seams for UVs, etc.).
+ * Note we only still partially support that kind of situation here, i.e. polys spreading over actual cracks
+ * (like a narrow space without faces on src, splitting a 'tube-like' geometry). That kind of situation
+ * should be relatively rare, though.
+ */
+ /* XXX This block in itself is big and complex enough to be a separate function but... it uses a bunch
+ * of locale vars. Not worth sending all that through parameters (for now at least). */
+ {
+ BLI_AStarGraph *as_graph = NULL;
+ int *poly_island_index_map = NULL;
+ int pidx_src_prev = -1;
+
+ MeshElemMap *best_island = NULL;
+ float best_island_fac = 0.0f;
+ int best_island_index = -1;
+
+ for (tindex = 0; tindex < num_trees; tindex++) {
+ float island_fac = 0.0f;
+
+ for (plidx_dst = 0; plidx_dst < mp_dst->totloop; plidx_dst++) {
+ island_fac += islands_res[tindex][plidx_dst].factor;
+ }
+ island_fac /= (float)mp_dst->totloop;
+
+ if (island_fac > best_island_fac) {
+ best_island_fac = island_fac;
+ best_island_index = tindex;
+ }
+ }
+
+ if (best_island_index != -1 && isld_steps_src) {
+ best_island = use_islands ? island_store.islands[best_island_index] : NULL;
+ as_graph = &as_graphdata[best_island_index];
+ poly_island_index_map = (int *)as_graph->custom_data;
+ BLI_astar_solution_init(as_graph, &as_solution, NULL);
+ }
+
+ for (plidx_dst = 0; plidx_dst < mp_dst->totloop; plidx_dst++) {
+ IslandResult *isld_res;
+ lidx_dst = plidx_dst + mp_dst->loopstart;
+
+ if (best_island_index == -1) {
+ /* No source for any loops of our dest poly in any source islands. */
+ BKE_mesh_remap_item_define_invalid(r_map, lidx_dst);
+ continue;
+ }
+
+ as_solution.custom_data = POINTER_FROM_INT(false);
+
+ isld_res = &islands_res[best_island_index][plidx_dst];
+ if (use_from_vert) {
+ /* Indices stored in islands_res are those of loops, one per dest loop. */
+ lidx_src = isld_res->index_src;
+ if (lidx_src >= 0) {
+ pidx_src = loop_to_poly_map_src[lidx_src];
+ /* If prev and curr poly are the same, no need to do anything more!!! */
+ if (!ELEM(pidx_src_prev, -1, pidx_src) && isld_steps_src) {
+ int pidx_isld_src, pidx_isld_src_prev;
+ if (poly_island_index_map) {
+ pidx_isld_src = poly_island_index_map[pidx_src];
+ pidx_isld_src_prev = poly_island_index_map[pidx_src_prev];
+ }
+ else {
+ pidx_isld_src = pidx_src;
+ pidx_isld_src_prev = pidx_src_prev;
+ }
+
+ BLI_astar_graph_solve(as_graph,
+ pidx_isld_src_prev,
+ pidx_isld_src,
+ mesh_remap_calc_loops_astar_f_cost,
+ &as_solution,
+ isld_steps_src);
+ if (POINTER_AS_INT(as_solution.custom_data) && (as_solution.steps > 0)) {
+ /* Find first 'cutting edge' on path, and bring back lidx_src on poly just
+ * before that edge.
+ * Note we could try to be much smarter (like e.g. storing a whole poly's indices,
+ * and making decision (on which side of cutting edge(s!) to be) on the end,
+ * but this is one more level of complexity, better to first see if
+ * simple solution works!
+ */
+ int last_valid_pidx_isld_src = -1;
+ /* Note we go backward here, from dest to src poly. */
+ for (i = as_solution.steps - 1; i--;) {
+ BLI_AStarGNLink *as_link = as_solution.prev_links[pidx_isld_src];
+ const int eidx = POINTER_AS_INT(as_link->custom_data);
+ pidx_isld_src = as_solution.prev_nodes[pidx_isld_src];
+ BLI_assert(pidx_isld_src != -1);
+ if (eidx != -1) {
+ /* we are 'crossing' a cutting edge. */
+ last_valid_pidx_isld_src = pidx_isld_src;
+ }
+ }
+ if (last_valid_pidx_isld_src != -1) {
+ /* Find a new valid loop in that new poly (nearest one for now).
+ * Note we could be much more subtle here, again that's for later... */
+ int j;
+ float best_dist_sq = FLT_MAX;
+
+ ml_dst = &loops_dst[lidx_dst];
+ copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co);
+
+ /* We do our transform here, since we may do several raycast/nearest queries. */
+ if (space_transform) {
+ BLI_space_transform_apply(space_transform, tmp_co);
+ }
+
+ pidx_src = (use_islands ? best_island->indices[last_valid_pidx_isld_src] :
+ last_valid_pidx_isld_src);
+ mp_src = &polys_src[pidx_src];
+ ml_src = &loops_src[mp_src->loopstart];
+ for (j = 0; j < mp_src->totloop; j++, ml_src++) {
+ const float dist_sq = len_squared_v3v3(verts_src[ml_src->v].co, tmp_co);
+ if (dist_sq < best_dist_sq) {
+ best_dist_sq = dist_sq;
+ lidx_src = mp_src->loopstart + j;
+ }
+ }
+ }
+ }
+ }
+ mesh_remap_item_define(r_map,
+ lidx_dst,
+ isld_res->hit_dist,
+ best_island_index,
+ 1,
+ &lidx_src,
+ &full_weight);
+ pidx_src_prev = pidx_src;
+ }
+ else {
+ /* No source for this loop in this island. */
+ /* TODO: would probably be better to get a source at all cost in best island anyway? */
+ mesh_remap_item_define(r_map, lidx_dst, FLT_MAX, best_island_index, 0, NULL, NULL);
+ }
+ }
+ else {
+ /* Else, we use source poly, indices stored in islands_res are those of polygons. */
+ pidx_src = isld_res->index_src;
+ if (pidx_src >= 0) {
+ float *hit_co = isld_res->hit_point;
+ int best_loop_index_src;
+
+ mp_src = &polys_src[pidx_src];
+ /* If prev and curr poly are the same, no need to do anything more!!! */
+ if (!ELEM(pidx_src_prev, -1, pidx_src) && isld_steps_src) {
+ int pidx_isld_src, pidx_isld_src_prev;
+ if (poly_island_index_map) {
+ pidx_isld_src = poly_island_index_map[pidx_src];
+ pidx_isld_src_prev = poly_island_index_map[pidx_src_prev];
+ }
+ else {
+ pidx_isld_src = pidx_src;
+ pidx_isld_src_prev = pidx_src_prev;
+ }
+
+ BLI_astar_graph_solve(as_graph,
+ pidx_isld_src_prev,
+ pidx_isld_src,
+ mesh_remap_calc_loops_astar_f_cost,
+ &as_solution,
+ isld_steps_src);
+ if (POINTER_AS_INT(as_solution.custom_data) && (as_solution.steps > 0)) {
+ /* Find first 'cutting edge' on path, and bring back lidx_src on poly just
+ * before that edge.
+ * Note we could try to be much smarter (like e.g. storing a whole poly's indices,
+ * and making decision (one which side of cutting edge(s!) to be on the end,
+ * but this is one more level of complexity, better to first see if
+ * simple solution works!
+ */
+ int last_valid_pidx_isld_src = -1;
+ /* Note we go backward here, from dest to src poly. */
+ for (i = as_solution.steps - 1; i--;) {
+ BLI_AStarGNLink *as_link = as_solution.prev_links[pidx_isld_src];
+ int eidx = POINTER_AS_INT(as_link->custom_data);
+
+ pidx_isld_src = as_solution.prev_nodes[pidx_isld_src];
+ BLI_assert(pidx_isld_src != -1);
+ if (eidx != -1) {
+ /* we are 'crossing' a cutting edge. */
+ last_valid_pidx_isld_src = pidx_isld_src;
+ }
+ }
+ if (last_valid_pidx_isld_src != -1) {
+ /* Find a new valid loop in that new poly (nearest point on poly for now).
+ * Note we could be much more subtle here, again that's for later... */
+ float best_dist_sq = FLT_MAX;
+ int j;
+
+ ml_dst = &loops_dst[lidx_dst];
+ copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co);
+
+ /* We do our transform here, since we may do several raycast/nearest queries. */
+ if (space_transform) {
+ BLI_space_transform_apply(space_transform, tmp_co);
+ }
+
+ pidx_src = (use_islands ? best_island->indices[last_valid_pidx_isld_src] :
+ last_valid_pidx_isld_src);
+ mp_src = &polys_src[pidx_src];
+
+ /* Create that one on demand. */
+ if (poly_to_looptri_map_src == NULL) {
+ BKE_mesh_origindex_map_create_looptri(&poly_to_looptri_map_src,
+ &poly_to_looptri_map_src_buff,
+ polys_src,
+ num_polys_src,
+ looptri_src,
+ num_looptri_src);
+ }
+
+ for (j = poly_to_looptri_map_src[pidx_src].count; j--;) {
+ float h[3];
+ const MLoopTri *lt =
+ &looptri_src[poly_to_looptri_map_src[pidx_src].indices[j]];
+ float dist_sq;
+
+ closest_on_tri_to_point_v3(h,
+ tmp_co,
+ vcos_src[loops_src[lt->tri[0]].v],
+ vcos_src[loops_src[lt->tri[1]].v],
+ vcos_src[loops_src[lt->tri[2]].v]);
+ dist_sq = len_squared_v3v3(tmp_co, h);
+ if (dist_sq < best_dist_sq) {
+ copy_v3_v3(hit_co, h);
+ best_dist_sq = dist_sq;
+ }
+ }
+ }
+ }
+ }
+
+ if (mode == MREMAP_MODE_LOOP_POLY_NEAREST) {
+ mesh_remap_interp_poly_data_get(mp_src,
+ loops_src,
+ (const float(*)[3])vcos_src,
+ hit_co,
+ &buff_size_interp,
+ &vcos_interp,
+ true,
+ &indices_interp,
+ &weights_interp,
+ false,
+ &best_loop_index_src);
+
+ mesh_remap_item_define(r_map,
+ lidx_dst,
+ isld_res->hit_dist,
+ best_island_index,
+ 1,
+ &best_loop_index_src,
+ &full_weight);
+ }
+ else {
+ const int sources_num = mesh_remap_interp_poly_data_get(
+ mp_src,
+ loops_src,
+ (const float(*)[3])vcos_src,
+ hit_co,
+ &buff_size_interp,
+ &vcos_interp,
+ true,
+ &indices_interp,
+ &weights_interp,
+ true,
+ NULL);
+
+ mesh_remap_item_define(r_map,
+ lidx_dst,
+ isld_res->hit_dist,
+ best_island_index,
+ sources_num,
+ indices_interp,
+ weights_interp);
+ }
+
+ pidx_src_prev = pidx_src;
+ }
+ else {
+ /* No source for this loop in this island. */
+ /* TODO: would probably be better to get a source at all cost in best island anyway? */
+ mesh_remap_item_define(r_map, lidx_dst, FLT_MAX, best_island_index, 0, NULL, NULL);
+ }
+ }
+ }
+
+ BLI_astar_solution_clear(&as_solution);
+ }
+ }
+
+ for (tindex = 0; tindex < num_trees; tindex++) {
+ MEM_freeN(islands_res[tindex]);
+ free_bvhtree_from_mesh(&treedata[tindex]);
+ if (isld_steps_src) {
+ BLI_astar_graph_free(&as_graphdata[tindex]);
+ }
+ }
+ MEM_freeN(islands_res);
+ BKE_mesh_loop_islands_free(&island_store);
+ MEM_freeN(treedata);
+ if (isld_steps_src) {
+ MEM_freeN(as_graphdata);
+ BLI_astar_solution_free(&as_solution);
+ }
+
+ if (vcos_src) {
+ MEM_freeN(vcos_src);
+ }
+ if (vert_to_loop_map_src) {
+ MEM_freeN(vert_to_loop_map_src);
+ }
+ if (vert_to_loop_map_src_buff) {
+ MEM_freeN(vert_to_loop_map_src_buff);
+ }
+ if (vert_to_poly_map_src) {
+ MEM_freeN(vert_to_poly_map_src);
+ }
+ if (vert_to_poly_map_src_buff) {
+ MEM_freeN(vert_to_poly_map_src_buff);
+ }
+ if (edge_to_poly_map_src) {
+ MEM_freeN(edge_to_poly_map_src);
+ }
+ if (edge_to_poly_map_src_buff) {
+ MEM_freeN(edge_to_poly_map_src_buff);
+ }
+ if (poly_to_looptri_map_src) {
+ MEM_freeN(poly_to_looptri_map_src);
+ }
+ if (poly_to_looptri_map_src_buff) {
+ MEM_freeN(poly_to_looptri_map_src_buff);
+ }
+ if (loop_to_poly_map_src) {
+ MEM_freeN(loop_to_poly_map_src);
+ }
+ if (poly_cents_src) {
+ MEM_freeN(poly_cents_src);
+ }
+ if (vcos_interp) {
+ MEM_freeN(vcos_interp);
+ }
+ if (indices_interp) {
+ MEM_freeN(indices_interp);
+ }
+ if (weights_interp) {
+ MEM_freeN(weights_interp);
+ }
+ }
}
-void BKE_mesh_remap_calc_polys_from_mesh(
- const int mode, const SpaceTransform *space_transform, const float max_dist, const float ray_radius,
- MVert *verts_dst, const int numverts_dst, MLoop *loops_dst, const int numloops_dst,
- MPoly *polys_dst, const int numpolys_dst, CustomData *pdata_dst, const bool dirty_nors_dst,
- Mesh *me_src, MeshPairRemap *r_map)
+void BKE_mesh_remap_calc_polys_from_mesh(const int mode,
+ const SpaceTransform *space_transform,
+ const float max_dist,
+ const float ray_radius,
+ MVert *verts_dst,
+ const int numverts_dst,
+ MLoop *loops_dst,
+ const int numloops_dst,
+ MPoly *polys_dst,
+ const int numpolys_dst,
+ CustomData *pdata_dst,
+ const bool dirty_nors_dst,
+ Mesh *me_src,
+ MeshPairRemap *r_map)
{
- const float full_weight = 1.0f;
- const float max_dist_sq = max_dist * max_dist;
- float (*poly_nors_dst)[3] = NULL;
- float tmp_co[3], tmp_no[3];
- int i;
-
- BLI_assert(mode & MREMAP_MODE_POLY);
-
- if (mode & (MREMAP_USE_NORMAL | MREMAP_USE_NORPROJ)) {
- /* Cache poly nors into a temp CDLayer. */
- poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL);
- if (!poly_nors_dst) {
- poly_nors_dst = CustomData_add_layer(pdata_dst, CD_NORMAL, CD_CALLOC, NULL, numpolys_dst);
- CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
- }
- if (dirty_nors_dst) {
- BKE_mesh_calc_normals_poly(
- verts_dst, NULL, numverts_dst, loops_dst, polys_dst, numloops_dst, numpolys_dst,
- poly_nors_dst, true);
- }
- }
-
- BKE_mesh_remap_init(r_map, numpolys_dst);
-
- if (mode == MREMAP_MODE_TOPOLOGY) {
- BLI_assert(numpolys_dst == me_src->totpoly);
- for (i = 0; i < numpolys_dst; i++) {
- mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight);
- }
- }
- else {
- BVHTreeFromMesh treedata = {NULL};
- BVHTreeNearest nearest = {0};
- BVHTreeRayHit rayhit = {0};
- float hit_dist;
-
- BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_LOOPTRI, 2);
-
- if (mode == MREMAP_MODE_POLY_NEAREST) {
- nearest.index = -1;
-
- for (i = 0; i < numpolys_dst; i++) {
- MPoly *mp = &polys_dst[i];
-
- BKE_mesh_calc_poly_center(mp, &loops_dst[mp->loopstart], verts_dst, tmp_co);
-
- /* Convert the vertex to tree coordinates, if needed. */
- if (space_transform) {
- BLI_space_transform_apply(space_transform, tmp_co);
- }
-
- if (mesh_remap_bvhtree_query_nearest(&treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
- const MLoopTri *lt = &treedata.looptri[nearest.index];
- const int poly_index = (int)lt->poly;
- mesh_remap_item_define(
- r_map, i, hit_dist, 0,
- 1, &poly_index, &full_weight);
- }
- else {
- /* No source for this dest poly! */
- BKE_mesh_remap_item_define_invalid(r_map, i);
- }
- }
- }
- else if (mode == MREMAP_MODE_POLY_NOR) {
- BLI_assert(poly_nors_dst);
-
- for (i = 0; i < numpolys_dst; i++) {
- MPoly *mp = &polys_dst[i];
-
- BKE_mesh_calc_poly_center(mp, &loops_dst[mp->loopstart], verts_dst, tmp_co);
- copy_v3_v3(tmp_no, poly_nors_dst[i]);
-
- /* Convert the vertex to tree coordinates, if needed. */
- if (space_transform) {
- BLI_space_transform_apply(space_transform, tmp_co);
- BLI_space_transform_apply_normal(space_transform, tmp_no);
- }
-
- if (mesh_remap_bvhtree_query_raycast(
- &treedata, &rayhit, tmp_co, tmp_no, ray_radius, max_dist, &hit_dist))
- {
- const MLoopTri *lt = &treedata.looptri[rayhit.index];
- const int poly_index = (int)lt->poly;
-
- mesh_remap_item_define(
- r_map, i, hit_dist, 0,
- 1, &poly_index, &full_weight);
- }
- else {
- /* No source for this dest poly! */
- BKE_mesh_remap_item_define_invalid(r_map, i);
- }
- }
- }
- else if (mode == MREMAP_MODE_POLY_POLYINTERP_PNORPROJ) {
- /* We cast our rays randomly, with a pseudo-even distribution (since we spread across tessellated tris,
- * with additional weighting based on each tri's relative area).
- */
- RNG *rng = BLI_rng_new(0);
-
- const size_t numpolys_src = (size_t)me_src->totpoly;
-
- /* Here it's simpler to just allocate for all polys :/ */
- int *indices = MEM_mallocN(sizeof(*indices) * numpolys_src, __func__);
- float *weights = MEM_mallocN(sizeof(*weights) * numpolys_src, __func__);
-
- size_t tmp_poly_size = MREMAP_DEFAULT_BUFSIZE;
- float (*poly_vcos_2d)[2] = MEM_mallocN(sizeof(*poly_vcos_2d) * tmp_poly_size, __func__);
- /* Tessellated 2D poly, always (num_loops - 2) triangles. */
- int (*tri_vidx_2d)[3] = MEM_mallocN(sizeof(*tri_vidx_2d) * (tmp_poly_size - 2), __func__);
-
- for (i = 0; i < numpolys_dst; i++) {
- /* For each dst poly, we sample some rays from it (2D grid in pnor space)
- * and use their hits to interpolate from source polys. */
- /* Note: dst poly is early-converted into src space! */
- MPoly *mp = &polys_dst[i];
-
- int tot_rays, done_rays = 0;
- float poly_area_2d_inv, done_area = 0.0f;
-
- float pcent_dst[3];
- float to_pnor_2d_mat[3][3], from_pnor_2d_mat[3][3];
- float poly_dst_2d_min[2], poly_dst_2d_max[2], poly_dst_2d_z;
- float poly_dst_2d_size[2];
-
- float totweights = 0.0f;
- float hit_dist_accum = 0.0f;
- int sources_num = 0;
- const int tris_num = mp->totloop - 2;
- int j;
-
- BKE_mesh_calc_poly_center(mp, &loops_dst[mp->loopstart], verts_dst, pcent_dst);
- copy_v3_v3(tmp_no, poly_nors_dst[i]);
-
- /* We do our transform here, else it'd be redone by raycast helper for each ray, ugh! */
- if (space_transform) {
- BLI_space_transform_apply(space_transform, pcent_dst);
- BLI_space_transform_apply_normal(space_transform, tmp_no);
- }
-
- copy_vn_fl(weights, (int)numpolys_src, 0.0f);
-
- if (UNLIKELY((size_t)mp->totloop > tmp_poly_size)) {
- tmp_poly_size = (size_t)mp->totloop;
- poly_vcos_2d = MEM_reallocN(poly_vcos_2d, sizeof(*poly_vcos_2d) * tmp_poly_size);
- tri_vidx_2d = MEM_reallocN(tri_vidx_2d, sizeof(*tri_vidx_2d) * (tmp_poly_size - 2));
- }
-
- axis_dominant_v3_to_m3(to_pnor_2d_mat, tmp_no);
- invert_m3_m3(from_pnor_2d_mat, to_pnor_2d_mat);
-
- mul_m3_v3(to_pnor_2d_mat, pcent_dst);
- poly_dst_2d_z = pcent_dst[2];
-
- /* Get (2D) bounding square of our poly. */
- INIT_MINMAX2(poly_dst_2d_min, poly_dst_2d_max);
-
- for (j = 0; j < mp->totloop; j++) {
- MLoop *ml = &loops_dst[j + mp->loopstart];
- copy_v3_v3(tmp_co, verts_dst[ml->v].co);
- if (space_transform) {
- BLI_space_transform_apply(space_transform, tmp_co);
- }
- mul_v2_m3v3(poly_vcos_2d[j], to_pnor_2d_mat, tmp_co);
- minmax_v2v2_v2(poly_dst_2d_min, poly_dst_2d_max, poly_vcos_2d[j]);
- }
-
- /* We adjust our ray-casting grid to ray_radius (the smaller, the more rays are cast),
- * with lower/upper bounds. */
- sub_v2_v2v2(poly_dst_2d_size, poly_dst_2d_max, poly_dst_2d_min);
-
- if (ray_radius) {
- tot_rays = (int)((max_ff(poly_dst_2d_size[0], poly_dst_2d_size[1]) / ray_radius) + 0.5f);
- CLAMP(tot_rays, MREMAP_RAYCAST_TRI_SAMPLES_MIN, MREMAP_RAYCAST_TRI_SAMPLES_MAX);
- }
- else {
- /* If no radius (pure rays), give max number of rays! */
- tot_rays = MREMAP_RAYCAST_TRI_SAMPLES_MIN;
- }
- tot_rays *= tot_rays;
-
- poly_area_2d_inv = area_poly_v2((const float(*)[2])poly_vcos_2d, (unsigned int)mp->totloop);
- /* In case we have a null-area degenerated poly... */
- poly_area_2d_inv = 1.0f / max_ff(poly_area_2d_inv, 1e-9f);
-
- /* Tessellate our poly. */
- if (mp->totloop == 3) {
- tri_vidx_2d[0][0] = 0;
- tri_vidx_2d[0][1] = 1;
- tri_vidx_2d[0][2] = 2;
- }
- if (mp->totloop == 4) {
- tri_vidx_2d[0][0] = 0;
- tri_vidx_2d[0][1] = 1;
- tri_vidx_2d[0][2] = 2;
- tri_vidx_2d[1][0] = 0;
- tri_vidx_2d[1][1] = 2;
- tri_vidx_2d[1][2] = 3;
- }
- else {
- BLI_polyfill_calc(
- poly_vcos_2d, (unsigned int)mp->totloop, -1,
- (unsigned int (*)[3])tri_vidx_2d);
- }
-
- for (j = 0; j < tris_num; j++) {
- float *v1 = poly_vcos_2d[tri_vidx_2d[j][0]];
- float *v2 = poly_vcos_2d[tri_vidx_2d[j][1]];
- float *v3 = poly_vcos_2d[tri_vidx_2d[j][2]];
- int rays_num;
-
- /* All this allows us to get 'absolute' number of rays for each tri, avoiding accumulating
- * errors over iterations, and helping better even distribution. */
- done_area += area_tri_v2(v1, v2, v3);
- rays_num = max_ii((int)((float)tot_rays * done_area * poly_area_2d_inv + 0.5f) - done_rays, 0);
- done_rays += rays_num;
-
- while (rays_num--) {
- int n = (ray_radius > 0.0f) ? MREMAP_RAYCAST_APPROXIMATE_NR : 1;
- float w = 1.0f;
-
- BLI_rng_get_tri_sample_float_v2(rng, v1, v2, v3, tmp_co);
-
- tmp_co[2] = poly_dst_2d_z;
- mul_m3_v3(from_pnor_2d_mat, tmp_co);
-
- /* At this point, tmp_co is a point on our poly surface, in mesh_src space! */
- while (n--) {
- if (mesh_remap_bvhtree_query_raycast(
- &treedata, &rayhit, tmp_co, tmp_no, ray_radius / w, max_dist, &hit_dist))
- {
- const MLoopTri *lt = &treedata.looptri[rayhit.index];
-
- weights[lt->poly] += w;
- totweights += w;
- hit_dist_accum += hit_dist;
- break;
- }
- /* Next iteration will get bigger radius but smaller weight! */
- w /= MREMAP_RAYCAST_APPROXIMATE_FAC;
- }
- }
- }
-
- if (totweights > 0.0f) {
- for (j = 0; j < (int)numpolys_src; j++) {
- if (!weights[j]) {
- continue;
- }
- /* Note: sources_num is always <= j! */
- weights[sources_num] = weights[j] / totweights;
- indices[sources_num] = j;
- sources_num++;
- }
- mesh_remap_item_define(r_map, i, hit_dist_accum / totweights, 0, sources_num, indices, weights);
- }
- else {
- /* No source for this dest poly! */
- BKE_mesh_remap_item_define_invalid(r_map, i);
- }
- }
-
- MEM_freeN(tri_vidx_2d);
- MEM_freeN(poly_vcos_2d);
- MEM_freeN(indices);
- MEM_freeN(weights);
- BLI_rng_free(rng);
- }
- else {
- CLOG_WARN(&LOG, "Unsupported mesh-to-mesh poly mapping mode (%d)!", mode);
- memset(r_map->items, 0, sizeof(*r_map->items) * (size_t)numpolys_dst);
- }
-
- free_bvhtree_from_mesh(&treedata);
- }
+ const float full_weight = 1.0f;
+ const float max_dist_sq = max_dist * max_dist;
+ float(*poly_nors_dst)[3] = NULL;
+ float tmp_co[3], tmp_no[3];
+ int i;
+
+ BLI_assert(mode & MREMAP_MODE_POLY);
+
+ if (mode & (MREMAP_USE_NORMAL | MREMAP_USE_NORPROJ)) {
+ /* Cache poly nors into a temp CDLayer. */
+ poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL);
+ if (!poly_nors_dst) {
+ poly_nors_dst = CustomData_add_layer(pdata_dst, CD_NORMAL, CD_CALLOC, NULL, numpolys_dst);
+ CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
+ }
+ if (dirty_nors_dst) {
+ BKE_mesh_calc_normals_poly(verts_dst,
+ NULL,
+ numverts_dst,
+ loops_dst,
+ polys_dst,
+ numloops_dst,
+ numpolys_dst,
+ poly_nors_dst,
+ true);
+ }
+ }
+
+ BKE_mesh_remap_init(r_map, numpolys_dst);
+
+ if (mode == MREMAP_MODE_TOPOLOGY) {
+ BLI_assert(numpolys_dst == me_src->totpoly);
+ for (i = 0; i < numpolys_dst; i++) {
+ mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight);
+ }
+ }
+ else {
+ BVHTreeFromMesh treedata = {NULL};
+ BVHTreeNearest nearest = {0};
+ BVHTreeRayHit rayhit = {0};
+ float hit_dist;
+
+ BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_LOOPTRI, 2);
+
+ if (mode == MREMAP_MODE_POLY_NEAREST) {
+ nearest.index = -1;
+
+ for (i = 0; i < numpolys_dst; i++) {
+ MPoly *mp = &polys_dst[i];
+
+ BKE_mesh_calc_poly_center(mp, &loops_dst[mp->loopstart], verts_dst, tmp_co);
+
+ /* Convert the vertex to tree coordinates, if needed. */
+ if (space_transform) {
+ BLI_space_transform_apply(space_transform, tmp_co);
+ }
+
+ if (mesh_remap_bvhtree_query_nearest(
+ &treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
+ const MLoopTri *lt = &treedata.looptri[nearest.index];
+ const int poly_index = (int)lt->poly;
+ mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &poly_index, &full_weight);
+ }
+ else {
+ /* No source for this dest poly! */
+ BKE_mesh_remap_item_define_invalid(r_map, i);
+ }
+ }
+ }
+ else if (mode == MREMAP_MODE_POLY_NOR) {
+ BLI_assert(poly_nors_dst);
+
+ for (i = 0; i < numpolys_dst; i++) {
+ MPoly *mp = &polys_dst[i];
+
+ BKE_mesh_calc_poly_center(mp, &loops_dst[mp->loopstart], verts_dst, tmp_co);
+ copy_v3_v3(tmp_no, poly_nors_dst[i]);
+
+ /* Convert the vertex to tree coordinates, if needed. */
+ if (space_transform) {
+ BLI_space_transform_apply(space_transform, tmp_co);
+ BLI_space_transform_apply_normal(space_transform, tmp_no);
+ }
+
+ if (mesh_remap_bvhtree_query_raycast(
+ &treedata, &rayhit, tmp_co, tmp_no, ray_radius, max_dist, &hit_dist)) {
+ const MLoopTri *lt = &treedata.looptri[rayhit.index];
+ const int poly_index = (int)lt->poly;
+
+ mesh_remap_item_define(r_map, i, hit_dist, 0, 1, &poly_index, &full_weight);
+ }
+ else {
+ /* No source for this dest poly! */
+ BKE_mesh_remap_item_define_invalid(r_map, i);
+ }
+ }
+ }
+ else if (mode == MREMAP_MODE_POLY_POLYINTERP_PNORPROJ) {
+ /* We cast our rays randomly, with a pseudo-even distribution (since we spread across tessellated tris,
+ * with additional weighting based on each tri's relative area).
+ */
+ RNG *rng = BLI_rng_new(0);
+
+ const size_t numpolys_src = (size_t)me_src->totpoly;
+
+ /* Here it's simpler to just allocate for all polys :/ */
+ int *indices = MEM_mallocN(sizeof(*indices) * numpolys_src, __func__);
+ float *weights = MEM_mallocN(sizeof(*weights) * numpolys_src, __func__);
+
+ size_t tmp_poly_size = MREMAP_DEFAULT_BUFSIZE;
+ float(*poly_vcos_2d)[2] = MEM_mallocN(sizeof(*poly_vcos_2d) * tmp_poly_size, __func__);
+ /* Tessellated 2D poly, always (num_loops - 2) triangles. */
+ int(*tri_vidx_2d)[3] = MEM_mallocN(sizeof(*tri_vidx_2d) * (tmp_poly_size - 2), __func__);
+
+ for (i = 0; i < numpolys_dst; i++) {
+ /* For each dst poly, we sample some rays from it (2D grid in pnor space)
+ * and use their hits to interpolate from source polys. */
+ /* Note: dst poly is early-converted into src space! */
+ MPoly *mp = &polys_dst[i];
+
+ int tot_rays, done_rays = 0;
+ float poly_area_2d_inv, done_area = 0.0f;
+
+ float pcent_dst[3];
+ float to_pnor_2d_mat[3][3], from_pnor_2d_mat[3][3];
+ float poly_dst_2d_min[2], poly_dst_2d_max[2], poly_dst_2d_z;
+ float poly_dst_2d_size[2];
+
+ float totweights = 0.0f;
+ float hit_dist_accum = 0.0f;
+ int sources_num = 0;
+ const int tris_num = mp->totloop - 2;
+ int j;
+
+ BKE_mesh_calc_poly_center(mp, &loops_dst[mp->loopstart], verts_dst, pcent_dst);
+ copy_v3_v3(tmp_no, poly_nors_dst[i]);
+
+ /* We do our transform here, else it'd be redone by raycast helper for each ray, ugh! */
+ if (space_transform) {
+ BLI_space_transform_apply(space_transform, pcent_dst);
+ BLI_space_transform_apply_normal(space_transform, tmp_no);
+ }
+
+ copy_vn_fl(weights, (int)numpolys_src, 0.0f);
+
+ if (UNLIKELY((size_t)mp->totloop > tmp_poly_size)) {
+ tmp_poly_size = (size_t)mp->totloop;
+ poly_vcos_2d = MEM_reallocN(poly_vcos_2d, sizeof(*poly_vcos_2d) * tmp_poly_size);
+ tri_vidx_2d = MEM_reallocN(tri_vidx_2d, sizeof(*tri_vidx_2d) * (tmp_poly_size - 2));
+ }
+
+ axis_dominant_v3_to_m3(to_pnor_2d_mat, tmp_no);
+ invert_m3_m3(from_pnor_2d_mat, to_pnor_2d_mat);
+
+ mul_m3_v3(to_pnor_2d_mat, pcent_dst);
+ poly_dst_2d_z = pcent_dst[2];
+
+ /* Get (2D) bounding square of our poly. */
+ INIT_MINMAX2(poly_dst_2d_min, poly_dst_2d_max);
+
+ for (j = 0; j < mp->totloop; j++) {
+ MLoop *ml = &loops_dst[j + mp->loopstart];
+ copy_v3_v3(tmp_co, verts_dst[ml->v].co);
+ if (space_transform) {
+ BLI_space_transform_apply(space_transform, tmp_co);
+ }
+ mul_v2_m3v3(poly_vcos_2d[j], to_pnor_2d_mat, tmp_co);
+ minmax_v2v2_v2(poly_dst_2d_min, poly_dst_2d_max, poly_vcos_2d[j]);
+ }
+
+ /* We adjust our ray-casting grid to ray_radius (the smaller, the more rays are cast),
+ * with lower/upper bounds. */
+ sub_v2_v2v2(poly_dst_2d_size, poly_dst_2d_max, poly_dst_2d_min);
+
+ if (ray_radius) {
+ tot_rays = (int)((max_ff(poly_dst_2d_size[0], poly_dst_2d_size[1]) / ray_radius) + 0.5f);
+ CLAMP(tot_rays, MREMAP_RAYCAST_TRI_SAMPLES_MIN, MREMAP_RAYCAST_TRI_SAMPLES_MAX);
+ }
+ else {
+ /* If no radius (pure rays), give max number of rays! */
+ tot_rays = MREMAP_RAYCAST_TRI_SAMPLES_MIN;
+ }
+ tot_rays *= tot_rays;
+
+ poly_area_2d_inv = area_poly_v2((const float(*)[2])poly_vcos_2d,
+ (unsigned int)mp->totloop);
+ /* In case we have a null-area degenerated poly... */
+ poly_area_2d_inv = 1.0f / max_ff(poly_area_2d_inv, 1e-9f);
+
+ /* Tessellate our poly. */
+ if (mp->totloop == 3) {
+ tri_vidx_2d[0][0] = 0;
+ tri_vidx_2d[0][1] = 1;
+ tri_vidx_2d[0][2] = 2;
+ }
+ if (mp->totloop == 4) {
+ tri_vidx_2d[0][0] = 0;
+ tri_vidx_2d[0][1] = 1;
+ tri_vidx_2d[0][2] = 2;
+ tri_vidx_2d[1][0] = 0;
+ tri_vidx_2d[1][1] = 2;
+ tri_vidx_2d[1][2] = 3;
+ }
+ else {
+ BLI_polyfill_calc(
+ poly_vcos_2d, (unsigned int)mp->totloop, -1, (unsigned int(*)[3])tri_vidx_2d);
+ }
+
+ for (j = 0; j < tris_num; j++) {
+ float *v1 = poly_vcos_2d[tri_vidx_2d[j][0]];
+ float *v2 = poly_vcos_2d[tri_vidx_2d[j][1]];
+ float *v3 = poly_vcos_2d[tri_vidx_2d[j][2]];
+ int rays_num;
+
+ /* All this allows us to get 'absolute' number of rays for each tri, avoiding accumulating
+ * errors over iterations, and helping better even distribution. */
+ done_area += area_tri_v2(v1, v2, v3);
+ rays_num = max_ii(
+ (int)((float)tot_rays * done_area * poly_area_2d_inv + 0.5f) - done_rays, 0);
+ done_rays += rays_num;
+
+ while (rays_num--) {
+ int n = (ray_radius > 0.0f) ? MREMAP_RAYCAST_APPROXIMATE_NR : 1;
+ float w = 1.0f;
+
+ BLI_rng_get_tri_sample_float_v2(rng, v1, v2, v3, tmp_co);
+
+ tmp_co[2] = poly_dst_2d_z;
+ mul_m3_v3(from_pnor_2d_mat, tmp_co);
+
+ /* At this point, tmp_co is a point on our poly surface, in mesh_src space! */
+ while (n--) {
+ if (mesh_remap_bvhtree_query_raycast(
+ &treedata, &rayhit, tmp_co, tmp_no, ray_radius / w, max_dist, &hit_dist)) {
+ const MLoopTri *lt = &treedata.looptri[rayhit.index];
+
+ weights[lt->poly] += w;
+ totweights += w;
+ hit_dist_accum += hit_dist;
+ break;
+ }
+ /* Next iteration will get bigger radius but smaller weight! */
+ w /= MREMAP_RAYCAST_APPROXIMATE_FAC;
+ }
+ }
+ }
+
+ if (totweights > 0.0f) {
+ for (j = 0; j < (int)numpolys_src; j++) {
+ if (!weights[j]) {
+ continue;
+ }
+ /* Note: sources_num is always <= j! */
+ weights[sources_num] = weights[j] / totweights;
+ indices[sources_num] = j;
+ sources_num++;
+ }
+ mesh_remap_item_define(
+ r_map, i, hit_dist_accum / totweights, 0, sources_num, indices, weights);
+ }
+ else {
+ /* No source for this dest poly! */
+ BKE_mesh_remap_item_define_invalid(r_map, i);
+ }
+ }
+
+ MEM_freeN(tri_vidx_2d);
+ MEM_freeN(poly_vcos_2d);
+ MEM_freeN(indices);
+ MEM_freeN(weights);
+ BLI_rng_free(rng);
+ }
+ else {
+ CLOG_WARN(&LOG, "Unsupported mesh-to-mesh poly mapping mode (%d)!", mode);
+ memset(r_map->items, 0, sizeof(*r_map->items) * (size_t)numpolys_dst);
+ }
+
+ free_bvhtree_from_mesh(&treedata);
+ }
}
#undef MREMAP_RAYCAST_APPROXIMATE_NR
diff --git a/source/blender/blenkernel/intern/mesh_runtime.c b/source/blender/blenkernel/intern/mesh_runtime.c
index f7c16b763fe..dea64e64377 100644
--- a/source/blender/blenkernel/intern/mesh_runtime.c
+++ b/source/blender/blenkernel/intern/mesh_runtime.c
@@ -49,7 +49,7 @@ static ThreadRWMutex loops_cache_lock = PTHREAD_RWLOCK_INITIALIZER;
*/
void BKE_mesh_runtime_reset(Mesh *mesh)
{
- memset(&mesh->runtime, 0, sizeof(mesh->runtime));
+ memset(&mesh->runtime, 0, sizeof(mesh->runtime));
}
/* Clear all pointers which we don't want to be shared on copying the datablock.
@@ -57,21 +57,21 @@ void BKE_mesh_runtime_reset(Mesh *mesh)
* it's deformed only, or that its custom data layers are out of date.) */
void BKE_mesh_runtime_reset_on_copy(Mesh *mesh, const int UNUSED(flag))
{
- Mesh_Runtime *runtime = &mesh->runtime;
-
- runtime->edit_data = NULL;
- runtime->batch_cache = NULL;
- runtime->subdiv_ccg = NULL;
- memset(&runtime->looptris, 0, sizeof(runtime->looptris));
- runtime->bvh_cache = NULL;
- runtime->shrinkwrap_data = NULL;
+ Mesh_Runtime *runtime = &mesh->runtime;
+
+ runtime->edit_data = NULL;
+ runtime->batch_cache = NULL;
+ runtime->subdiv_ccg = NULL;
+ memset(&runtime->looptris, 0, sizeof(runtime->looptris));
+ runtime->bvh_cache = NULL;
+ runtime->shrinkwrap_data = NULL;
}
void BKE_mesh_runtime_clear_cache(Mesh *mesh)
{
- BKE_mesh_runtime_clear_geometry(mesh);
- BKE_mesh_batch_cache_free(mesh);
- BKE_mesh_runtime_clear_edit_data(mesh);
+ BKE_mesh_runtime_clear_geometry(mesh);
+ BKE_mesh_batch_cache_free(mesh);
+ BKE_mesh_runtime_clear_edit_data(mesh);
}
/* This is a ported copy of DM_ensure_looptri_data(dm) */
@@ -82,135 +82,137 @@ void BKE_mesh_runtime_clear_cache(Mesh *mesh)
*/
static void mesh_ensure_looptri_data(Mesh *mesh)
{
- const unsigned int totpoly = mesh->totpoly;
- const int looptris_len = poly_to_tri_count(totpoly, mesh->totloop);
-
- BLI_assert(mesh->runtime.looptris.array_wip == NULL);
-
- SWAP(MLoopTri *, mesh->runtime.looptris.array, mesh->runtime.looptris.array_wip);
-
- if ((looptris_len > mesh->runtime.looptris.len_alloc) ||
- (looptris_len < mesh->runtime.looptris.len_alloc * 2) ||
- (totpoly == 0))
- {
- MEM_SAFE_FREE(mesh->runtime.looptris.array_wip);
- mesh->runtime.looptris.len_alloc = 0;
- mesh->runtime.looptris.len = 0;
- }
-
- if (totpoly) {
- if (mesh->runtime.looptris.array_wip == NULL) {
- mesh->runtime.looptris.array_wip = MEM_malloc_arrayN(looptris_len, sizeof(*mesh->runtime.looptris.array_wip), __func__);
- mesh->runtime.looptris.len_alloc = looptris_len;
- }
-
- mesh->runtime.looptris.len = looptris_len;
- }
+ const unsigned int totpoly = mesh->totpoly;
+ const int looptris_len = poly_to_tri_count(totpoly, mesh->totloop);
+
+ BLI_assert(mesh->runtime.looptris.array_wip == NULL);
+
+ SWAP(MLoopTri *, mesh->runtime.looptris.array, mesh->runtime.looptris.array_wip);
+
+ if ((looptris_len > mesh->runtime.looptris.len_alloc) ||
+ (looptris_len < mesh->runtime.looptris.len_alloc * 2) || (totpoly == 0)) {
+ MEM_SAFE_FREE(mesh->runtime.looptris.array_wip);
+ mesh->runtime.looptris.len_alloc = 0;
+ mesh->runtime.looptris.len = 0;
+ }
+
+ if (totpoly) {
+ if (mesh->runtime.looptris.array_wip == NULL) {
+ mesh->runtime.looptris.array_wip = MEM_malloc_arrayN(
+ looptris_len, sizeof(*mesh->runtime.looptris.array_wip), __func__);
+ mesh->runtime.looptris.len_alloc = looptris_len;
+ }
+
+ mesh->runtime.looptris.len = looptris_len;
+ }
}
/* This is a ported copy of CDDM_recalc_looptri(dm). */
void BKE_mesh_runtime_looptri_recalc(Mesh *mesh)
{
- mesh_ensure_looptri_data(mesh);
- BLI_assert(mesh->totpoly == 0 || mesh->runtime.looptris.array_wip != NULL);
-
- BKE_mesh_recalc_looptri(
- mesh->mloop, mesh->mpoly,
- mesh->mvert,
- mesh->totloop, mesh->totpoly,
- mesh->runtime.looptris.array_wip);
-
- BLI_assert(mesh->runtime.looptris.array == NULL);
- atomic_cas_ptr((void **)&mesh->runtime.looptris.array, mesh->runtime.looptris.array, mesh->runtime.looptris.array_wip);
- mesh->runtime.looptris.array_wip = NULL;
+ mesh_ensure_looptri_data(mesh);
+ BLI_assert(mesh->totpoly == 0 || mesh->runtime.looptris.array_wip != NULL);
+
+ BKE_mesh_recalc_looptri(mesh->mloop,
+ mesh->mpoly,
+ mesh->mvert,
+ mesh->totloop,
+ mesh->totpoly,
+ mesh->runtime.looptris.array_wip);
+
+ BLI_assert(mesh->runtime.looptris.array == NULL);
+ atomic_cas_ptr((void **)&mesh->runtime.looptris.array,
+ mesh->runtime.looptris.array,
+ mesh->runtime.looptris.array_wip);
+ mesh->runtime.looptris.array_wip = NULL;
}
/* This is a ported copy of dm_getNumLoopTri(dm). */
int BKE_mesh_runtime_looptri_len(const Mesh *mesh)
{
- const int looptri_len = poly_to_tri_count(mesh->totpoly, mesh->totloop);
- BLI_assert(ELEM(mesh->runtime.looptris.len, 0, looptri_len));
- return looptri_len;
+ const int looptri_len = poly_to_tri_count(mesh->totpoly, mesh->totloop);
+ BLI_assert(ELEM(mesh->runtime.looptris.len, 0, looptri_len));
+ return looptri_len;
}
/* This is a ported copy of dm_getLoopTriArray(dm). */
const MLoopTri *BKE_mesh_runtime_looptri_ensure(Mesh *mesh)
{
- MLoopTri *looptri;
-
- BLI_rw_mutex_lock(&loops_cache_lock, THREAD_LOCK_READ);
- looptri = mesh->runtime.looptris.array;
- BLI_rw_mutex_unlock(&loops_cache_lock);
-
- if (looptri != NULL) {
- BLI_assert(BKE_mesh_runtime_looptri_len(mesh) == mesh->runtime.looptris.len);
- }
- else {
- BLI_rw_mutex_lock(&loops_cache_lock, THREAD_LOCK_WRITE);
- /* We need to ensure array is still NULL inside mutex-protected code, some other thread might have already
- * recomputed those looptris. */
- if (mesh->runtime.looptris.array == NULL) {
- BKE_mesh_runtime_looptri_recalc(mesh);
- }
- looptri = mesh->runtime.looptris.array;
- BLI_rw_mutex_unlock(&loops_cache_lock);
- }
- return looptri;
+ MLoopTri *looptri;
+
+ BLI_rw_mutex_lock(&loops_cache_lock, THREAD_LOCK_READ);
+ looptri = mesh->runtime.looptris.array;
+ BLI_rw_mutex_unlock(&loops_cache_lock);
+
+ if (looptri != NULL) {
+ BLI_assert(BKE_mesh_runtime_looptri_len(mesh) == mesh->runtime.looptris.len);
+ }
+ else {
+ BLI_rw_mutex_lock(&loops_cache_lock, THREAD_LOCK_WRITE);
+ /* We need to ensure array is still NULL inside mutex-protected code, some other thread might have already
+ * recomputed those looptris. */
+ if (mesh->runtime.looptris.array == NULL) {
+ BKE_mesh_runtime_looptri_recalc(mesh);
+ }
+ looptri = mesh->runtime.looptris.array;
+ BLI_rw_mutex_unlock(&loops_cache_lock);
+ }
+ return looptri;
}
/* This is a copy of DM_verttri_from_looptri(). */
-void BKE_mesh_runtime_verttri_from_looptri(
- MVertTri *r_verttri, const MLoop *mloop,
- const MLoopTri *looptri, int looptri_num)
+void BKE_mesh_runtime_verttri_from_looptri(MVertTri *r_verttri,
+ const MLoop *mloop,
+ const MLoopTri *looptri,
+ int looptri_num)
{
- int i;
- for (i = 0; i < looptri_num; i++) {
- r_verttri[i].tri[0] = mloop[looptri[i].tri[0]].v;
- r_verttri[i].tri[1] = mloop[looptri[i].tri[1]].v;
- r_verttri[i].tri[2] = mloop[looptri[i].tri[2]].v;
- }
+ int i;
+ for (i = 0; i < looptri_num; i++) {
+ r_verttri[i].tri[0] = mloop[looptri[i].tri[0]].v;
+ r_verttri[i].tri[1] = mloop[looptri[i].tri[1]].v;
+ r_verttri[i].tri[2] = mloop[looptri[i].tri[2]].v;
+ }
}
-
bool BKE_mesh_runtime_ensure_edit_data(struct Mesh *mesh)
{
- if (mesh->runtime.edit_data != NULL) {
- return false;
- }
+ if (mesh->runtime.edit_data != NULL) {
+ return false;
+ }
- mesh->runtime.edit_data = MEM_callocN(sizeof(EditMeshData), "EditMeshData");
- return true;
+ mesh->runtime.edit_data = MEM_callocN(sizeof(EditMeshData), "EditMeshData");
+ return true;
}
bool BKE_mesh_runtime_clear_edit_data(Mesh *mesh)
{
- if (mesh->runtime.edit_data == NULL) {
- return false;
- }
-
- if (mesh->runtime.edit_data->polyCos != NULL)
- MEM_freeN((void *)mesh->runtime.edit_data->polyCos);
- if (mesh->runtime.edit_data->polyNos != NULL)
- MEM_freeN((void *)mesh->runtime.edit_data->polyNos);
- if (mesh->runtime.edit_data->vertexCos != NULL)
- MEM_freeN((void *)mesh->runtime.edit_data->vertexCos);
- if (mesh->runtime.edit_data->vertexNos != NULL)
- MEM_freeN((void *)mesh->runtime.edit_data->vertexNos);
-
- MEM_SAFE_FREE(mesh->runtime.edit_data);
- return true;
+ if (mesh->runtime.edit_data == NULL) {
+ return false;
+ }
+
+ if (mesh->runtime.edit_data->polyCos != NULL)
+ MEM_freeN((void *)mesh->runtime.edit_data->polyCos);
+ if (mesh->runtime.edit_data->polyNos != NULL)
+ MEM_freeN((void *)mesh->runtime.edit_data->polyNos);
+ if (mesh->runtime.edit_data->vertexCos != NULL)
+ MEM_freeN((void *)mesh->runtime.edit_data->vertexCos);
+ if (mesh->runtime.edit_data->vertexNos != NULL)
+ MEM_freeN((void *)mesh->runtime.edit_data->vertexNos);
+
+ MEM_SAFE_FREE(mesh->runtime.edit_data);
+ return true;
}
void BKE_mesh_runtime_clear_geometry(Mesh *mesh)
{
- bvhcache_free(&mesh->runtime.bvh_cache);
- MEM_SAFE_FREE(mesh->runtime.looptris.array);
- /* TODO(sergey): Does this really belong here? */
- if (mesh->runtime.subdiv_ccg != NULL) {
- BKE_subdiv_ccg_destroy(mesh->runtime.subdiv_ccg);
- mesh->runtime.subdiv_ccg = NULL;
- }
- BKE_shrinkwrap_discard_boundary_data(mesh);
+ bvhcache_free(&mesh->runtime.bvh_cache);
+ MEM_SAFE_FREE(mesh->runtime.looptris.array);
+ /* TODO(sergey): Does this really belong here? */
+ if (mesh->runtime.subdiv_ccg != NULL) {
+ BKE_subdiv_ccg_destroy(mesh->runtime.subdiv_ccg);
+ mesh->runtime.subdiv_ccg = NULL;
+ }
+ BKE_shrinkwrap_discard_boundary_data(mesh);
}
/** \} */
@@ -225,15 +227,15 @@ void (*BKE_mesh_batch_cache_free_cb)(Mesh *me) = NULL;
void BKE_mesh_batch_cache_dirty_tag(Mesh *me, int mode)
{
- if (me->runtime.batch_cache) {
- BKE_mesh_batch_cache_dirty_tag_cb(me, mode);
- }
+ if (me->runtime.batch_cache) {
+ BKE_mesh_batch_cache_dirty_tag_cb(me, mode);
+ }
}
void BKE_mesh_batch_cache_free(Mesh *me)
{
- if (me->runtime.batch_cache) {
- BKE_mesh_batch_cache_free_cb(me);
- }
+ if (me->runtime.batch_cache) {
+ BKE_mesh_batch_cache_free_cb(me);
+ }
}
/** \} */
@@ -244,147 +246,166 @@ void BKE_mesh_batch_cache_free(Mesh *me)
* to help track down differences output */
#ifndef NDEBUG
-#include "BLI_dynstr.h"
+# include "BLI_dynstr.h"
-static void mesh_runtime_debug_info_layers(
- DynStr *dynstr, CustomData *cd)
+static void mesh_runtime_debug_info_layers(DynStr *dynstr, CustomData *cd)
{
- int type;
-
- for (type = 0; type < CD_NUMTYPES; type++) {
- if (CustomData_has_layer(cd, type)) {
- /* note: doesn't account for multiple layers */
- const char *name = CustomData_layertype_name(type);
- const int size = CustomData_sizeof(type);
- const void *pt = CustomData_get_layer(cd, type);
- const int pt_size = pt ? (int)(MEM_allocN_len(pt) / size) : 0;
- const char *structname;
- int structnum;
- CustomData_file_write_info(type, &structname, &structnum);
- BLI_dynstr_appendf(
- dynstr,
- " dict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n",
- name, structname, type, (const void *)pt, size, pt_size);
- }
- }
+ int type;
+
+ for (type = 0; type < CD_NUMTYPES; type++) {
+ if (CustomData_has_layer(cd, type)) {
+ /* note: doesn't account for multiple layers */
+ const char *name = CustomData_layertype_name(type);
+ const int size = CustomData_sizeof(type);
+ const void *pt = CustomData_get_layer(cd, type);
+ const int pt_size = pt ? (int)(MEM_allocN_len(pt) / size) : 0;
+ const char *structname;
+ int structnum;
+ CustomData_file_write_info(type, &structname, &structnum);
+ BLI_dynstr_appendf(
+ dynstr,
+ " dict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n",
+ name,
+ structname,
+ type,
+ (const void *)pt,
+ size,
+ pt_size);
+ }
+ }
}
char *BKE_mesh_runtime_debug_info(Mesh *me_eval)
{
- DynStr *dynstr = BLI_dynstr_new();
- char *ret;
-
- BLI_dynstr_append(dynstr, "{\n");
- BLI_dynstr_appendf(dynstr, " 'ptr': '%p',\n", (void *)me_eval);
-#if 0
- const char *tstr;
- switch (me_eval->type) {
- case DM_TYPE_CDDM: tstr = "DM_TYPE_CDDM"; break;
- case DM_TYPE_CCGDM: tstr = "DM_TYPE_CCGDM"; break;
- default: tstr = "UNKNOWN"; break;
- }
- BLI_dynstr_appendf(dynstr, " 'type': '%s',\n", tstr);
-#endif
- BLI_dynstr_appendf(dynstr, " 'totvert': %d,\n", me_eval->totvert);
- BLI_dynstr_appendf(dynstr, " 'totedge': %d,\n", me_eval->totedge);
- BLI_dynstr_appendf(dynstr, " 'totface': %d,\n", me_eval->totface);
- BLI_dynstr_appendf(dynstr, " 'totpoly': %d,\n", me_eval->totpoly);
- BLI_dynstr_appendf(dynstr, " 'deformed_only': %d,\n", me_eval->runtime.deformed_only);
-
- BLI_dynstr_append(dynstr, " 'vertexLayers': (\n");
- mesh_runtime_debug_info_layers(dynstr, &me_eval->vdata);
- BLI_dynstr_append(dynstr, " ),\n");
-
- BLI_dynstr_append(dynstr, " 'edgeLayers': (\n");
- mesh_runtime_debug_info_layers(dynstr, &me_eval->edata);
- BLI_dynstr_append(dynstr, " ),\n");
-
- BLI_dynstr_append(dynstr, " 'loopLayers': (\n");
- mesh_runtime_debug_info_layers(dynstr, &me_eval->ldata);
- BLI_dynstr_append(dynstr, " ),\n");
-
- BLI_dynstr_append(dynstr, " 'polyLayers': (\n");
- mesh_runtime_debug_info_layers(dynstr, &me_eval->pdata);
- BLI_dynstr_append(dynstr, " ),\n");
-
- BLI_dynstr_append(dynstr, " 'tessFaceLayers': (\n");
- mesh_runtime_debug_info_layers(dynstr, &me_eval->fdata);
- BLI_dynstr_append(dynstr, " ),\n");
-
- BLI_dynstr_append(dynstr, "}\n");
-
- ret = BLI_dynstr_get_cstring(dynstr);
- BLI_dynstr_free(dynstr);
- return ret;
+ DynStr *dynstr = BLI_dynstr_new();
+ char *ret;
+
+ BLI_dynstr_append(dynstr, "{\n");
+ BLI_dynstr_appendf(dynstr, " 'ptr': '%p',\n", (void *)me_eval);
+# if 0
+ const char *tstr;
+ switch (me_eval->type) {
+ case DM_TYPE_CDDM: tstr = "DM_TYPE_CDDM"; break;
+ case DM_TYPE_CCGDM: tstr = "DM_TYPE_CCGDM"; break;
+ default: tstr = "UNKNOWN"; break;
+ }
+ BLI_dynstr_appendf(dynstr, " 'type': '%s',\n", tstr);
+# endif
+ BLI_dynstr_appendf(dynstr, " 'totvert': %d,\n", me_eval->totvert);
+ BLI_dynstr_appendf(dynstr, " 'totedge': %d,\n", me_eval->totedge);
+ BLI_dynstr_appendf(dynstr, " 'totface': %d,\n", me_eval->totface);
+ BLI_dynstr_appendf(dynstr, " 'totpoly': %d,\n", me_eval->totpoly);
+ BLI_dynstr_appendf(dynstr, " 'deformed_only': %d,\n", me_eval->runtime.deformed_only);
+
+ BLI_dynstr_append(dynstr, " 'vertexLayers': (\n");
+ mesh_runtime_debug_info_layers(dynstr, &me_eval->vdata);
+ BLI_dynstr_append(dynstr, " ),\n");
+
+ BLI_dynstr_append(dynstr, " 'edgeLayers': (\n");
+ mesh_runtime_debug_info_layers(dynstr, &me_eval->edata);
+ BLI_dynstr_append(dynstr, " ),\n");
+
+ BLI_dynstr_append(dynstr, " 'loopLayers': (\n");
+ mesh_runtime_debug_info_layers(dynstr, &me_eval->ldata);
+ BLI_dynstr_append(dynstr, " ),\n");
+
+ BLI_dynstr_append(dynstr, " 'polyLayers': (\n");
+ mesh_runtime_debug_info_layers(dynstr, &me_eval->pdata);
+ BLI_dynstr_append(dynstr, " ),\n");
+
+ BLI_dynstr_append(dynstr, " 'tessFaceLayers': (\n");
+ mesh_runtime_debug_info_layers(dynstr, &me_eval->fdata);
+ BLI_dynstr_append(dynstr, " ),\n");
+
+ BLI_dynstr_append(dynstr, "}\n");
+
+ ret = BLI_dynstr_get_cstring(dynstr);
+ BLI_dynstr_free(dynstr);
+ return ret;
}
void BKE_mesh_runtime_debug_print(Mesh *me_eval)
{
- char *str = BKE_mesh_runtime_debug_info(me_eval);
- puts(str);
- fflush(stdout);
- MEM_freeN(str);
+ char *str = BKE_mesh_runtime_debug_info(me_eval);
+ puts(str);
+ fflush(stdout);
+ MEM_freeN(str);
}
/* XXX Should go in customdata file? */
void BKE_mesh_runtime_debug_print_cdlayers(CustomData *data)
{
- int i;
- const CustomDataLayer *layer;
-
- printf("{\n");
-
- for (i = 0, layer = data->layers; i < data->totlayer; i++, layer++) {
-
- const char *name = CustomData_layertype_name(layer->type);
- const int size = CustomData_sizeof(layer->type);
- const char *structname;
- int structnum;
- CustomData_file_write_info(layer->type, &structname, &structnum);
- printf(" dict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n",
- name, structname, layer->type, (const void *)layer->data, size, (int)(MEM_allocN_len(layer->data) / size));
- }
-
- printf("}\n");
+ int i;
+ const CustomDataLayer *layer;
+
+ printf("{\n");
+
+ for (i = 0, layer = data->layers; i < data->totlayer; i++, layer++) {
+
+ const char *name = CustomData_layertype_name(layer->type);
+ const int size = CustomData_sizeof(layer->type);
+ const char *structname;
+ int structnum;
+ CustomData_file_write_info(layer->type, &structname, &structnum);
+ printf(" dict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n",
+ name,
+ structname,
+ layer->type,
+ (const void *)layer->data,
+ size,
+ (int)(MEM_allocN_len(layer->data) / size));
+ }
+
+ printf("}\n");
}
bool BKE_mesh_runtime_is_valid(Mesh *me_eval)
{
- const bool do_verbose = true;
- const bool do_fixes = false;
-
- bool is_valid = true;
- bool changed = true;
-
- if (do_verbose) {
- printf("MESH: %s\n", me_eval->id.name + 2);
- }
-
- is_valid &= BKE_mesh_validate_all_customdata(
- &me_eval->vdata, me_eval->totvert,
- &me_eval->edata, me_eval->totedge,
- &me_eval->ldata, me_eval->totloop,
- &me_eval->pdata, me_eval->totpoly,
- false, /* setting mask here isn't useful, gives false positives */
- do_verbose, do_fixes,
- &changed);
-
- is_valid &= BKE_mesh_validate_arrays(
- me_eval,
- me_eval->mvert, me_eval->totvert,
- me_eval->medge, me_eval->totedge,
- me_eval->mface, me_eval->totface,
- me_eval->mloop, me_eval->totloop,
- me_eval->mpoly, me_eval->totpoly,
- me_eval->dvert,
- do_verbose, do_fixes,
- &changed);
-
- BLI_assert(changed == false);
-
- return is_valid;
+ const bool do_verbose = true;
+ const bool do_fixes = false;
+
+ bool is_valid = true;
+ bool changed = true;
+
+ if (do_verbose) {
+ printf("MESH: %s\n", me_eval->id.name + 2);
+ }
+
+ is_valid &= BKE_mesh_validate_all_customdata(
+ &me_eval->vdata,
+ me_eval->totvert,
+ &me_eval->edata,
+ me_eval->totedge,
+ &me_eval->ldata,
+ me_eval->totloop,
+ &me_eval->pdata,
+ me_eval->totpoly,
+ false, /* setting mask here isn't useful, gives false positives */
+ do_verbose,
+ do_fixes,
+ &changed);
+
+ is_valid &= BKE_mesh_validate_arrays(me_eval,
+ me_eval->mvert,
+ me_eval->totvert,
+ me_eval->medge,
+ me_eval->totedge,
+ me_eval->mface,
+ me_eval->totface,
+ me_eval->mloop,
+ me_eval->totloop,
+ me_eval->mpoly,
+ me_eval->totpoly,
+ me_eval->dvert,
+ do_verbose,
+ do_fixes,
+ &changed);
+
+ BLI_assert(changed == false);
+
+ return is_valid;
}
-#endif /* NDEBUG */
+#endif /* NDEBUG */
/** \} */
diff --git a/source/blender/blenkernel/intern/mesh_tangent.c b/source/blender/blenkernel/intern/mesh_tangent.c
index 0bb399630b8..e6c4e9ff4be 100644
--- a/source/blender/blenkernel/intern/mesh_tangent.c
+++ b/source/blender/blenkernel/intern/mesh_tangent.c
@@ -45,7 +45,6 @@
#include "atomic_ops.h"
#include "mikktspace.h"
-
/* -------------------------------------------------------------------- */
/** \name Mesh Tangent Calculations (Single Layer)
* \{ */
@@ -54,57 +53,66 @@
/* User data. */
typedef struct {
- const MPoly *mpolys; /* faces */
- const MLoop *mloops; /* faces's vertices */
- const MVert *mverts; /* vertices */
- const MLoopUV *luvs; /* texture coordinates */
- float (*lnors)[3]; /* loops' normals */
- float (*tangents)[4]; /* output tangents */
- int num_polys; /* number of polygons */
+ const MPoly *mpolys; /* faces */
+ const MLoop *mloops; /* faces's vertices */
+ const MVert *mverts; /* vertices */
+ const MLoopUV *luvs; /* texture coordinates */
+ float (*lnors)[3]; /* loops' normals */
+ float (*tangents)[4]; /* output tangents */
+ int num_polys; /* number of polygons */
} BKEMeshToTangent;
/* Mikktspace's API */
static int get_num_faces(const SMikkTSpaceContext *pContext)
{
- BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
- return p_mesh->num_polys;
+ BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
+ return p_mesh->num_polys;
}
static int get_num_verts_of_face(const SMikkTSpaceContext *pContext, const int face_idx)
{
- BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
- return p_mesh->mpolys[face_idx].totloop;
+ BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
+ return p_mesh->mpolys[face_idx].totloop;
}
-static void get_position(const SMikkTSpaceContext *pContext, float r_co[3], const int face_idx, const int vert_idx)
+static void get_position(const SMikkTSpaceContext *pContext,
+ float r_co[3],
+ const int face_idx,
+ const int vert_idx)
{
- BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
- const int loop_idx = p_mesh->mpolys[face_idx].loopstart + vert_idx;
- copy_v3_v3(r_co, p_mesh->mverts[p_mesh->mloops[loop_idx].v].co);
+ BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
+ const int loop_idx = p_mesh->mpolys[face_idx].loopstart + vert_idx;
+ copy_v3_v3(r_co, p_mesh->mverts[p_mesh->mloops[loop_idx].v].co);
}
-static void get_texture_coordinate(
- const SMikkTSpaceContext *pContext, float r_uv[2], const int face_idx,
- const int vert_idx)
+static void get_texture_coordinate(const SMikkTSpaceContext *pContext,
+ float r_uv[2],
+ const int face_idx,
+ const int vert_idx)
{
- BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
- copy_v2_v2(r_uv, p_mesh->luvs[p_mesh->mpolys[face_idx].loopstart + vert_idx].uv);
+ BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
+ copy_v2_v2(r_uv, p_mesh->luvs[p_mesh->mpolys[face_idx].loopstart + vert_idx].uv);
}
-static void get_normal(const SMikkTSpaceContext *pContext, float r_no[3], const int face_idx, const int vert_idx)
+static void get_normal(const SMikkTSpaceContext *pContext,
+ float r_no[3],
+ const int face_idx,
+ const int vert_idx)
{
- BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
- copy_v3_v3(r_no, p_mesh->lnors[p_mesh->mpolys[face_idx].loopstart + vert_idx]);
+ BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
+ copy_v3_v3(r_no, p_mesh->lnors[p_mesh->mpolys[face_idx].loopstart + vert_idx]);
}
-static void set_tspace(
- const SMikkTSpaceContext *pContext, const float fv_tangent[3], const float face_sign,
- const int face_idx, const int vert_idx)
+static void set_tspace(const SMikkTSpaceContext *pContext,
+ const float fv_tangent[3],
+ const float face_sign,
+ const int face_idx,
+ const int vert_idx)
{
- BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
- float *p_res = p_mesh->tangents[p_mesh->mpolys[face_idx].loopstart + vert_idx];
- copy_v3_v3(p_res, fv_tangent);
- p_res[3] = face_sign;
+ BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
+ float *p_res = p_mesh->tangents[p_mesh->mpolys[face_idx].loopstart + vert_idx];
+ copy_v3_v3(p_res, fv_tangent);
+ p_res[3] = face_sign;
}
/**
@@ -112,49 +120,55 @@ static void set_tspace(
* split normals can be used to recreate the full tangent space.
* Note: * The mesh should be made of only tris and quads!
*/
-void BKE_mesh_calc_loop_tangent_single_ex(
- const MVert *mverts, const int UNUSED(numVerts), const MLoop *mloops,
- float (*r_looptangent)[4], float (*loopnors)[3], const MLoopUV *loopuvs,
- const int UNUSED(numLoops), const MPoly *mpolys, const int numPolys,
- ReportList *reports)
+void BKE_mesh_calc_loop_tangent_single_ex(const MVert *mverts,
+ const int UNUSED(numVerts),
+ const MLoop *mloops,
+ float (*r_looptangent)[4],
+ float (*loopnors)[3],
+ const MLoopUV *loopuvs,
+ const int UNUSED(numLoops),
+ const MPoly *mpolys,
+ const int numPolys,
+ ReportList *reports)
{
- BKEMeshToTangent mesh_to_tangent = {NULL};
- SMikkTSpaceContext s_context = {NULL};
- SMikkTSpaceInterface s_interface = {NULL};
-
- const MPoly *mp;
- int mp_index;
-
- /* First check we do have a tris/quads only mesh. */
- for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) {
- if (mp->totloop > 4) {
- BKE_report(reports, RPT_ERROR, "Tangent space can only be computed for tris/quads, aborting");
- return;
- }
- }
-
- /* Compute Mikktspace's tangent normals. */
- mesh_to_tangent.mpolys = mpolys;
- mesh_to_tangent.mloops = mloops;
- mesh_to_tangent.mverts = mverts;
- mesh_to_tangent.luvs = loopuvs;
- mesh_to_tangent.lnors = loopnors;
- mesh_to_tangent.tangents = r_looptangent;
- mesh_to_tangent.num_polys = numPolys;
-
- s_context.m_pUserData = &mesh_to_tangent;
- s_context.m_pInterface = &s_interface;
- s_interface.m_getNumFaces = get_num_faces;
- s_interface.m_getNumVerticesOfFace = get_num_verts_of_face;
- s_interface.m_getPosition = get_position;
- s_interface.m_getTexCoord = get_texture_coordinate;
- s_interface.m_getNormal = get_normal;
- s_interface.m_setTSpaceBasic = set_tspace;
-
- /* 0 if failed */
- if (genTangSpaceDefault(&s_context) == false) {
- BKE_report(reports, RPT_ERROR, "Mikktspace failed to generate tangents for this mesh!");
- }
+ BKEMeshToTangent mesh_to_tangent = {NULL};
+ SMikkTSpaceContext s_context = {NULL};
+ SMikkTSpaceInterface s_interface = {NULL};
+
+ const MPoly *mp;
+ int mp_index;
+
+ /* First check we do have a tris/quads only mesh. */
+ for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) {
+ if (mp->totloop > 4) {
+ BKE_report(
+ reports, RPT_ERROR, "Tangent space can only be computed for tris/quads, aborting");
+ return;
+ }
+ }
+
+ /* Compute Mikktspace's tangent normals. */
+ mesh_to_tangent.mpolys = mpolys;
+ mesh_to_tangent.mloops = mloops;
+ mesh_to_tangent.mverts = mverts;
+ mesh_to_tangent.luvs = loopuvs;
+ mesh_to_tangent.lnors = loopnors;
+ mesh_to_tangent.tangents = r_looptangent;
+ mesh_to_tangent.num_polys = numPolys;
+
+ s_context.m_pUserData = &mesh_to_tangent;
+ s_context.m_pInterface = &s_interface;
+ s_interface.m_getNumFaces = get_num_faces;
+ s_interface.m_getNumVerticesOfFace = get_num_verts_of_face;
+ s_interface.m_getPosition = get_position;
+ s_interface.m_getTexCoord = get_texture_coordinate;
+ s_interface.m_getNormal = get_normal;
+ s_interface.m_setTSpaceBasic = set_tspace;
+
+ /* 0 if failed */
+ if (genTangSpaceDefault(&s_context) == false) {
+ BKE_report(reports, RPT_ERROR, "Mikktspace failed to generate tangents for this mesh!");
+ }
}
/**
@@ -163,62 +177,74 @@ void BKE_mesh_calc_loop_tangent_single_ex(
* - There must be a valid loop's CD_NORMALS available.
* - The mesh should be made of only tris and quads!
*/
-void BKE_mesh_calc_loop_tangent_single(Mesh *mesh, const char *uvmap, float (*r_looptangents)[4], ReportList *reports)
+void BKE_mesh_calc_loop_tangent_single(Mesh *mesh,
+ const char *uvmap,
+ float (*r_looptangents)[4],
+ ReportList *reports)
{
- MLoopUV *loopuvs;
- float (*loopnors)[3];
-
- /* Check we have valid texture coordinates first! */
- if (uvmap) {
- loopuvs = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvmap);
- }
- else {
- loopuvs = CustomData_get_layer(&mesh->ldata, CD_MLOOPUV);
- }
- if (!loopuvs) {
- BKE_reportf(reports, RPT_ERROR, "Tangent space computation needs an UVMap, \"%s\" not found, aborting", uvmap);
- return;
- }
-
- loopnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
- if (!loopnors) {
- BKE_report(reports, RPT_ERROR, "Tangent space computation needs loop normals, none found, aborting");
- return;
- }
-
- BKE_mesh_calc_loop_tangent_single_ex(
- mesh->mvert, mesh->totvert, mesh->mloop, r_looptangents,
- loopnors, loopuvs, mesh->totloop, mesh->mpoly, mesh->totpoly, reports);
+ MLoopUV *loopuvs;
+ float(*loopnors)[3];
+
+ /* Check we have valid texture coordinates first! */
+ if (uvmap) {
+ loopuvs = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvmap);
+ }
+ else {
+ loopuvs = CustomData_get_layer(&mesh->ldata, CD_MLOOPUV);
+ }
+ if (!loopuvs) {
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "Tangent space computation needs an UVMap, \"%s\" not found, aborting",
+ uvmap);
+ return;
+ }
+
+ loopnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
+ if (!loopnors) {
+ BKE_report(
+ reports, RPT_ERROR, "Tangent space computation needs loop normals, none found, aborting");
+ return;
+ }
+
+ BKE_mesh_calc_loop_tangent_single_ex(mesh->mvert,
+ mesh->totvert,
+ mesh->mloop,
+ r_looptangents,
+ loopnors,
+ loopuvs,
+ mesh->totloop,
+ mesh->mpoly,
+ mesh->totpoly,
+ reports);
}
/** \} */
-
/* -------------------------------------------------------------------- */
/** \name Mesh Tangent Calculations (All Layers)
* \{ */
-
/* Necessary complexity to handle looptri's as quads for correct tangents */
#define USE_LOOPTRI_DETECT_QUADS
typedef struct {
- const float (*precomputedFaceNormals)[3];
- const float (*precomputedLoopNormals)[3];
- const MLoopTri *looptri;
- MLoopUV *mloopuv; /* texture coordinates */
- const MPoly *mpoly; /* indices */
- const MLoop *mloop; /* indices */
- const MVert *mvert; /* vertices & normals */
- const float (*orco)[3];
- float (*tangent)[4]; /* destination */
- int numTessFaces;
+ const float (*precomputedFaceNormals)[3];
+ const float (*precomputedLoopNormals)[3];
+ const MLoopTri *looptri;
+ MLoopUV *mloopuv; /* texture coordinates */
+ const MPoly *mpoly; /* indices */
+ const MLoop *mloop; /* indices */
+ const MVert *mvert; /* vertices & normals */
+ const float (*orco)[3];
+ float (*tangent)[4]; /* destination */
+ int numTessFaces;
#ifdef USE_LOOPTRI_DETECT_QUADS
- /* map from 'fake' face index to looptri,
- * quads will point to the first looptri of the quad */
- const int *face_as_quad_map;
- int num_face_as_quad_map;
+ /* map from 'fake' face index to looptri,
+ * quads will point to the first looptri of the quad */
+ const int *face_as_quad_map;
+ int num_face_as_quad_map;
#endif
} SGLSLMeshToTangent;
@@ -226,235 +252,238 @@ typedef struct {
/* interface */
static int dm_ts_GetNumFaces(const SMikkTSpaceContext *pContext)
{
- SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
+ SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
#ifdef USE_LOOPTRI_DETECT_QUADS
- return pMesh->num_face_as_quad_map;
+ return pMesh->num_face_as_quad_map;
#else
- return pMesh->numTessFaces;
+ return pMesh->numTessFaces;
#endif
}
static int dm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num)
{
#ifdef USE_LOOPTRI_DETECT_QUADS
- SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
- if (pMesh->face_as_quad_map) {
- const MLoopTri *lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
- const MPoly *mp = &pMesh->mpoly[lt->poly];
- if (mp->totloop == 4) {
- return 4;
- }
- }
- return 3;
+ SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
+ if (pMesh->face_as_quad_map) {
+ const MLoopTri *lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
+ const MPoly *mp = &pMesh->mpoly[lt->poly];
+ if (mp->totloop == 4) {
+ return 4;
+ }
+ }
+ return 3;
#else
- UNUSED_VARS(pContext, face_num);
- return 3;
+ UNUSED_VARS(pContext, face_num);
+ return 3;
#endif
}
-static void dm_ts_GetPosition(
- const SMikkTSpaceContext *pContext, float r_co[3],
- const int face_num, const int vert_index)
+static void dm_ts_GetPosition(const SMikkTSpaceContext *pContext,
+ float r_co[3],
+ const int face_num,
+ const int vert_index)
{
- //assert(vert_index >= 0 && vert_index < 4);
- SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
- const MLoopTri *lt;
- uint loop_index;
- const float *co;
+ //assert(vert_index >= 0 && vert_index < 4);
+ SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
+ const MLoopTri *lt;
+ uint loop_index;
+ const float *co;
#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
- const MPoly *mp = &pMesh->mpoly[lt->poly];
- if (mp->totloop == 4) {
- loop_index = (uint)(mp->loopstart + vert_index);
- goto finally;
- }
- /* fall through to regular triangle */
- }
- else {
- lt = &pMesh->looptri[face_num];
- }
+ if (pMesh->face_as_quad_map) {
+ lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
+ const MPoly *mp = &pMesh->mpoly[lt->poly];
+ if (mp->totloop == 4) {
+ loop_index = (uint)(mp->loopstart + vert_index);
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = &pMesh->looptri[face_num];
+ }
#else
- lt = &pMesh->looptri[face_num];
+ lt = &pMesh->looptri[face_num];
#endif
- loop_index = lt->tri[vert_index];
+ loop_index = lt->tri[vert_index];
finally:
- co = pMesh->mvert[pMesh->mloop[loop_index].v].co;
- copy_v3_v3(r_co, co);
+ co = pMesh->mvert[pMesh->mloop[loop_index].v].co;
+ copy_v3_v3(r_co, co);
}
-static void dm_ts_GetTextureCoordinate(
- const SMikkTSpaceContext *pContext, float r_uv[2],
- const int face_num, const int vert_index)
+static void dm_ts_GetTextureCoordinate(const SMikkTSpaceContext *pContext,
+ float r_uv[2],
+ const int face_num,
+ const int vert_index)
{
- //assert(vert_index >= 0 && vert_index < 4);
- SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
- const MLoopTri *lt;
- uint loop_index;
+ //assert(vert_index >= 0 && vert_index < 4);
+ SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
+ const MLoopTri *lt;
+ uint loop_index;
#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
- const MPoly *mp = &pMesh->mpoly[lt->poly];
- if (mp->totloop == 4) {
- loop_index = (uint)(mp->loopstart + vert_index);
- goto finally;
- }
- /* fall through to regular triangle */
- }
- else {
- lt = &pMesh->looptri[face_num];
- }
+ if (pMesh->face_as_quad_map) {
+ lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
+ const MPoly *mp = &pMesh->mpoly[lt->poly];
+ if (mp->totloop == 4) {
+ loop_index = (uint)(mp->loopstart + vert_index);
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = &pMesh->looptri[face_num];
+ }
#else
- lt = &pMesh->looptri[face_num];
+ lt = &pMesh->looptri[face_num];
#endif
- loop_index = lt->tri[vert_index];
+ loop_index = lt->tri[vert_index];
finally:
- if (pMesh->mloopuv != NULL) {
- const float *uv = pMesh->mloopuv[loop_index].uv;
- copy_v2_v2(r_uv, uv);
- }
- else {
- const float *orco = pMesh->orco[pMesh->mloop[loop_index].v];
- map_to_sphere(&r_uv[0], &r_uv[1], orco[0], orco[1], orco[2]);
- }
+ if (pMesh->mloopuv != NULL) {
+ const float *uv = pMesh->mloopuv[loop_index].uv;
+ copy_v2_v2(r_uv, uv);
+ }
+ else {
+ const float *orco = pMesh->orco[pMesh->mloop[loop_index].v];
+ map_to_sphere(&r_uv[0], &r_uv[1], orco[0], orco[1], orco[2]);
+ }
}
-static void dm_ts_GetNormal(
- const SMikkTSpaceContext *pContext, float r_no[3],
- const int face_num, const int vert_index)
+static void dm_ts_GetNormal(const SMikkTSpaceContext *pContext,
+ float r_no[3],
+ const int face_num,
+ const int vert_index)
{
- //assert(vert_index >= 0 && vert_index < 4);
- SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData;
- const MLoopTri *lt;
- uint loop_index;
+ //assert(vert_index >= 0 && vert_index < 4);
+ SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *)pContext->m_pUserData;
+ const MLoopTri *lt;
+ uint loop_index;
#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
- const MPoly *mp = &pMesh->mpoly[lt->poly];
- if (mp->totloop == 4) {
- loop_index = (uint)(mp->loopstart + vert_index);
- goto finally;
- }
- /* fall through to regular triangle */
- }
- else {
- lt = &pMesh->looptri[face_num];
- }
+ if (pMesh->face_as_quad_map) {
+ lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
+ const MPoly *mp = &pMesh->mpoly[lt->poly];
+ if (mp->totloop == 4) {
+ loop_index = (uint)(mp->loopstart + vert_index);
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = &pMesh->looptri[face_num];
+ }
#else
- lt = &pMesh->looptri[face_num];
+ lt = &pMesh->looptri[face_num];
#endif
- loop_index = lt->tri[vert_index];
+ loop_index = lt->tri[vert_index];
finally:
- if (pMesh->precomputedLoopNormals) {
- copy_v3_v3(r_no, pMesh->precomputedLoopNormals[loop_index]);
- }
- else if ((pMesh->mpoly[lt->poly].flag & ME_SMOOTH) == 0) { /* flat */
- if (pMesh->precomputedFaceNormals) {
- copy_v3_v3(r_no, pMesh->precomputedFaceNormals[lt->poly]);
- }
- else {
+ if (pMesh->precomputedLoopNormals) {
+ copy_v3_v3(r_no, pMesh->precomputedLoopNormals[loop_index]);
+ }
+ else if ((pMesh->mpoly[lt->poly].flag & ME_SMOOTH) == 0) { /* flat */
+ if (pMesh->precomputedFaceNormals) {
+ copy_v3_v3(r_no, pMesh->precomputedFaceNormals[lt->poly]);
+ }
+ else {
#ifdef USE_LOOPTRI_DETECT_QUADS
- const MPoly *mp = &pMesh->mpoly[lt->poly];
- if (mp->totloop == 4) {
- normal_quad_v3(
- r_no,
- pMesh->mvert[pMesh->mloop[mp->loopstart + 0].v].co,
- pMesh->mvert[pMesh->mloop[mp->loopstart + 1].v].co,
- pMesh->mvert[pMesh->mloop[mp->loopstart + 2].v].co,
- pMesh->mvert[pMesh->mloop[mp->loopstart + 3].v].co);
- }
- else
+ const MPoly *mp = &pMesh->mpoly[lt->poly];
+ if (mp->totloop == 4) {
+ normal_quad_v3(r_no,
+ pMesh->mvert[pMesh->mloop[mp->loopstart + 0].v].co,
+ pMesh->mvert[pMesh->mloop[mp->loopstart + 1].v].co,
+ pMesh->mvert[pMesh->mloop[mp->loopstart + 2].v].co,
+ pMesh->mvert[pMesh->mloop[mp->loopstart + 3].v].co);
+ }
+ else
#endif
- {
- normal_tri_v3(
- r_no,
- pMesh->mvert[pMesh->mloop[lt->tri[0]].v].co,
- pMesh->mvert[pMesh->mloop[lt->tri[1]].v].co,
- pMesh->mvert[pMesh->mloop[lt->tri[2]].v].co);
- }
- }
- }
- else {
- const short *no = pMesh->mvert[pMesh->mloop[loop_index].v].no;
- normal_short_to_float_v3(r_no, no);
- }
+ {
+ normal_tri_v3(r_no,
+ pMesh->mvert[pMesh->mloop[lt->tri[0]].v].co,
+ pMesh->mvert[pMesh->mloop[lt->tri[1]].v].co,
+ pMesh->mvert[pMesh->mloop[lt->tri[2]].v].co);
+ }
+ }
+ }
+ else {
+ const short *no = pMesh->mvert[pMesh->mloop[loop_index].v].no;
+ normal_short_to_float_v3(r_no, no);
+ }
}
-static void dm_ts_SetTSpace(
- const SMikkTSpaceContext *pContext, const float fvTangent[3], const float fSign,
- const int face_num, const int vert_index)
+static void dm_ts_SetTSpace(const SMikkTSpaceContext *pContext,
+ const float fvTangent[3],
+ const float fSign,
+ const int face_num,
+ const int vert_index)
{
- //assert(vert_index >= 0 && vert_index < 4);
- SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData;
- const MLoopTri *lt;
- uint loop_index;
+ //assert(vert_index >= 0 && vert_index < 4);
+ SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *)pContext->m_pUserData;
+ const MLoopTri *lt;
+ uint loop_index;
#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
- const MPoly *mp = &pMesh->mpoly[lt->poly];
- if (mp->totloop == 4) {
- loop_index = (uint)(mp->loopstart + vert_index);
- goto finally;
- }
- /* fall through to regular triangle */
- }
- else {
- lt = &pMesh->looptri[face_num];
- }
+ if (pMesh->face_as_quad_map) {
+ lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
+ const MPoly *mp = &pMesh->mpoly[lt->poly];
+ if (mp->totloop == 4) {
+ loop_index = (uint)(mp->loopstart + vert_index);
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = &pMesh->looptri[face_num];
+ }
#else
- lt = &pMesh->looptri[face_num];
+ lt = &pMesh->looptri[face_num];
#endif
- loop_index = lt->tri[vert_index];
+ loop_index = lt->tri[vert_index];
- float *pRes;
+ float *pRes;
finally:
- pRes = pMesh->tangent[loop_index];
- copy_v3_v3(pRes, fvTangent);
- pRes[3] = fSign;
+ pRes = pMesh->tangent[loop_index];
+ copy_v3_v3(pRes, fvTangent);
+ pRes[3] = fSign;
}
-static void DM_calc_loop_tangents_thread(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
+static void DM_calc_loop_tangents_thread(TaskPool *__restrict UNUSED(pool),
+ void *taskdata,
+ int UNUSED(threadid))
{
- struct SGLSLMeshToTangent *mesh2tangent = taskdata;
- /* new computation method */
- {
- SMikkTSpaceContext sContext = {NULL};
- SMikkTSpaceInterface sInterface = {NULL};
-
- sContext.m_pUserData = mesh2tangent;
- sContext.m_pInterface = &sInterface;
- sInterface.m_getNumFaces = dm_ts_GetNumFaces;
- sInterface.m_getNumVerticesOfFace = dm_ts_GetNumVertsOfFace;
- sInterface.m_getPosition = dm_ts_GetPosition;
- sInterface.m_getTexCoord = dm_ts_GetTextureCoordinate;
- sInterface.m_getNormal = dm_ts_GetNormal;
- sInterface.m_setTSpaceBasic = dm_ts_SetTSpace;
-
- /* 0 if failed */
- genTangSpaceDefault(&sContext);
- }
+ struct SGLSLMeshToTangent *mesh2tangent = taskdata;
+ /* new computation method */
+ {
+ SMikkTSpaceContext sContext = {NULL};
+ SMikkTSpaceInterface sInterface = {NULL};
+
+ sContext.m_pUserData = mesh2tangent;
+ sContext.m_pInterface = &sInterface;
+ sInterface.m_getNumFaces = dm_ts_GetNumFaces;
+ sInterface.m_getNumVerticesOfFace = dm_ts_GetNumVertsOfFace;
+ sInterface.m_getPosition = dm_ts_GetPosition;
+ sInterface.m_getTexCoord = dm_ts_GetTextureCoordinate;
+ sInterface.m_getNormal = dm_ts_GetNormal;
+ sInterface.m_setTSpaceBasic = dm_ts_SetTSpace;
+
+ /* 0 if failed */
+ genTangSpaceDefault(&sContext);
+ }
}
-void BKE_mesh_add_loop_tangent_named_layer_for_uv(
- CustomData *uv_data, CustomData *tan_data, int numLoopData,
- const char *layer_name)
+void BKE_mesh_add_loop_tangent_named_layer_for_uv(CustomData *uv_data,
+ CustomData *tan_data,
+ int numLoopData,
+ const char *layer_name)
{
- if (CustomData_get_named_layer_index(tan_data, CD_TANGENT, layer_name) == -1 &&
- CustomData_get_named_layer_index(uv_data, CD_MLOOPUV, layer_name) != -1)
- {
- CustomData_add_layer_named(
- tan_data, CD_TANGENT, CD_CALLOC, NULL,
- numLoopData, layer_name);
- }
+ if (CustomData_get_named_layer_index(tan_data, CD_TANGENT, layer_name) == -1 &&
+ CustomData_get_named_layer_index(uv_data, CD_MLOOPUV, layer_name) != -1) {
+ CustomData_add_layer_named(tan_data, CD_TANGENT, CD_CALLOC, NULL, numLoopData, layer_name);
+ }
}
/**
@@ -462,248 +491,276 @@ void BKE_mesh_add_loop_tangent_named_layer_for_uv(
* Also, we calculate tangent_mask that works as a descriptor of tangents state.
* If tangent_mask has changed, then recalculate tangents.
*/
-void BKE_mesh_calc_loop_tangent_step_0(
- const CustomData *loopData, bool calc_active_tangent,
- const char (*tangent_names)[MAX_NAME], int tangent_names_count,
- bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n,
- char *ract_uv_name, char *rren_uv_name, short *rtangent_mask)
+void BKE_mesh_calc_loop_tangent_step_0(const CustomData *loopData,
+ bool calc_active_tangent,
+ const char (*tangent_names)[MAX_NAME],
+ int tangent_names_count,
+ bool *rcalc_act,
+ bool *rcalc_ren,
+ int *ract_uv_n,
+ int *rren_uv_n,
+ char *ract_uv_name,
+ char *rren_uv_name,
+ short *rtangent_mask)
{
- /* Active uv in viewport */
- int layer_index = CustomData_get_layer_index(loopData, CD_MLOOPUV);
- *ract_uv_n = CustomData_get_active_layer(loopData, CD_MLOOPUV);
- ract_uv_name[0] = 0;
- if (*ract_uv_n != -1) {
- strcpy(ract_uv_name, loopData->layers[*ract_uv_n + layer_index].name);
- }
-
- /* Active tangent in render */
- *rren_uv_n = CustomData_get_render_layer(loopData, CD_MLOOPUV);
- rren_uv_name[0] = 0;
- if (*rren_uv_n != -1) {
- strcpy(rren_uv_name, loopData->layers[*rren_uv_n + layer_index].name);
- }
-
- /* If active tangent not in tangent_names we take it into account */
- *rcalc_act = false;
- *rcalc_ren = false;
- for (int i = 0; i < tangent_names_count; i++) {
- if (tangent_names[i][0] == 0) {
- calc_active_tangent = true;
- }
- }
- if (calc_active_tangent) {
- *rcalc_act = true;
- *rcalc_ren = true;
- for (int i = 0; i < tangent_names_count; i++) {
- if (STREQ(ract_uv_name, tangent_names[i]))
- *rcalc_act = false;
- if (STREQ(rren_uv_name, tangent_names[i]))
- *rcalc_ren = false;
- }
- }
- *rtangent_mask = 0;
-
- const int uv_layer_num = CustomData_number_of_layers(loopData, CD_MLOOPUV);
- for (int n = 0; n < uv_layer_num; n++) {
- const char *name = CustomData_get_layer_name(loopData, CD_MLOOPUV, n);
- bool add = false;
- for (int i = 0; i < tangent_names_count; i++) {
- if (tangent_names[i][0] && STREQ(tangent_names[i], name)) {
- add = true;
- break;
- }
- }
- if (!add && ((*rcalc_act && ract_uv_name[0] && STREQ(ract_uv_name, name)) ||
- (*rcalc_ren && rren_uv_name[0] && STREQ(rren_uv_name, name))))
- {
- add = true;
- }
- if (add)
- *rtangent_mask |= (short)(1 << n);
- }
-
- if (uv_layer_num == 0)
- *rtangent_mask |= DM_TANGENT_MASK_ORCO;
+ /* Active uv in viewport */
+ int layer_index = CustomData_get_layer_index(loopData, CD_MLOOPUV);
+ *ract_uv_n = CustomData_get_active_layer(loopData, CD_MLOOPUV);
+ ract_uv_name[0] = 0;
+ if (*ract_uv_n != -1) {
+ strcpy(ract_uv_name, loopData->layers[*ract_uv_n + layer_index].name);
+ }
+
+ /* Active tangent in render */
+ *rren_uv_n = CustomData_get_render_layer(loopData, CD_MLOOPUV);
+ rren_uv_name[0] = 0;
+ if (*rren_uv_n != -1) {
+ strcpy(rren_uv_name, loopData->layers[*rren_uv_n + layer_index].name);
+ }
+
+ /* If active tangent not in tangent_names we take it into account */
+ *rcalc_act = false;
+ *rcalc_ren = false;
+ for (int i = 0; i < tangent_names_count; i++) {
+ if (tangent_names[i][0] == 0) {
+ calc_active_tangent = true;
+ }
+ }
+ if (calc_active_tangent) {
+ *rcalc_act = true;
+ *rcalc_ren = true;
+ for (int i = 0; i < tangent_names_count; i++) {
+ if (STREQ(ract_uv_name, tangent_names[i]))
+ *rcalc_act = false;
+ if (STREQ(rren_uv_name, tangent_names[i]))
+ *rcalc_ren = false;
+ }
+ }
+ *rtangent_mask = 0;
+
+ const int uv_layer_num = CustomData_number_of_layers(loopData, CD_MLOOPUV);
+ for (int n = 0; n < uv_layer_num; n++) {
+ const char *name = CustomData_get_layer_name(loopData, CD_MLOOPUV, n);
+ bool add = false;
+ for (int i = 0; i < tangent_names_count; i++) {
+ if (tangent_names[i][0] && STREQ(tangent_names[i], name)) {
+ add = true;
+ break;
+ }
+ }
+ if (!add && ((*rcalc_act && ract_uv_name[0] && STREQ(ract_uv_name, name)) ||
+ (*rcalc_ren && rren_uv_name[0] && STREQ(rren_uv_name, name)))) {
+ add = true;
+ }
+ if (add)
+ *rtangent_mask |= (short)(1 << n);
+ }
+
+ if (uv_layer_num == 0)
+ *rtangent_mask |= DM_TANGENT_MASK_ORCO;
}
/**
* See: #BKE_editmesh_loop_tangent_calc (matching logic).
*/
-void BKE_mesh_calc_loop_tangent_ex(
- const MVert *mvert,
- const MPoly *mpoly, const uint mpoly_len,
- const MLoop *mloop,
- const MLoopTri *looptri,
- const uint looptri_len,
-
- CustomData *loopdata,
- bool calc_active_tangent,
- const char (*tangent_names)[MAX_NAME], int tangent_names_len,
- const float (*poly_normals)[3],
- const float (*loop_normals)[3],
- const float (*vert_orco)[3],
- /* result */
- CustomData *loopdata_out,
- const uint loopdata_out_len,
- short *tangent_mask_curr_p)
+void BKE_mesh_calc_loop_tangent_ex(const MVert *mvert,
+ const MPoly *mpoly,
+ const uint mpoly_len,
+ const MLoop *mloop,
+ const MLoopTri *looptri,
+ const uint looptri_len,
+
+ CustomData *loopdata,
+ bool calc_active_tangent,
+ const char (*tangent_names)[MAX_NAME],
+ int tangent_names_len,
+ const float (*poly_normals)[3],
+ const float (*loop_normals)[3],
+ const float (*vert_orco)[3],
+ /* result */
+ CustomData *loopdata_out,
+ const uint loopdata_out_len,
+ short *tangent_mask_curr_p)
{
- int act_uv_n = -1;
- int ren_uv_n = -1;
- bool calc_act = false;
- bool calc_ren = false;
- char act_uv_name[MAX_NAME];
- char ren_uv_name[MAX_NAME];
- short tangent_mask = 0;
- short tangent_mask_curr = *tangent_mask_curr_p;
-
- BKE_mesh_calc_loop_tangent_step_0(
- loopdata, calc_active_tangent, tangent_names, tangent_names_len,
- &calc_act, &calc_ren, &act_uv_n, &ren_uv_n, act_uv_name, ren_uv_name, &tangent_mask);
- if ((tangent_mask_curr | tangent_mask) != tangent_mask_curr) {
- /* Check we have all the needed layers */
- /* Allocate needed tangent layers */
- for (int i = 0; i < tangent_names_len; i++)
- if (tangent_names[i][0])
- BKE_mesh_add_loop_tangent_named_layer_for_uv(loopdata, loopdata_out, (int)loopdata_out_len, tangent_names[i]);
- if ((tangent_mask & DM_TANGENT_MASK_ORCO) && CustomData_get_named_layer_index(loopdata, CD_TANGENT, "") == -1)
- CustomData_add_layer_named(loopdata_out, CD_TANGENT, CD_CALLOC, NULL, (int)loopdata_out_len, "");
- if (calc_act && act_uv_name[0])
- BKE_mesh_add_loop_tangent_named_layer_for_uv(loopdata, loopdata_out, (int)loopdata_out_len, act_uv_name);
- if (calc_ren && ren_uv_name[0])
- BKE_mesh_add_loop_tangent_named_layer_for_uv(loopdata, loopdata_out, (int)loopdata_out_len, ren_uv_name);
+ int act_uv_n = -1;
+ int ren_uv_n = -1;
+ bool calc_act = false;
+ bool calc_ren = false;
+ char act_uv_name[MAX_NAME];
+ char ren_uv_name[MAX_NAME];
+ short tangent_mask = 0;
+ short tangent_mask_curr = *tangent_mask_curr_p;
+
+ BKE_mesh_calc_loop_tangent_step_0(loopdata,
+ calc_active_tangent,
+ tangent_names,
+ tangent_names_len,
+ &calc_act,
+ &calc_ren,
+ &act_uv_n,
+ &ren_uv_n,
+ act_uv_name,
+ ren_uv_name,
+ &tangent_mask);
+ if ((tangent_mask_curr | tangent_mask) != tangent_mask_curr) {
+ /* Check we have all the needed layers */
+ /* Allocate needed tangent layers */
+ for (int i = 0; i < tangent_names_len; i++)
+ if (tangent_names[i][0])
+ BKE_mesh_add_loop_tangent_named_layer_for_uv(
+ loopdata, loopdata_out, (int)loopdata_out_len, tangent_names[i]);
+ if ((tangent_mask & DM_TANGENT_MASK_ORCO) &&
+ CustomData_get_named_layer_index(loopdata, CD_TANGENT, "") == -1)
+ CustomData_add_layer_named(
+ loopdata_out, CD_TANGENT, CD_CALLOC, NULL, (int)loopdata_out_len, "");
+ if (calc_act && act_uv_name[0])
+ BKE_mesh_add_loop_tangent_named_layer_for_uv(
+ loopdata, loopdata_out, (int)loopdata_out_len, act_uv_name);
+ if (calc_ren && ren_uv_name[0])
+ BKE_mesh_add_loop_tangent_named_layer_for_uv(
+ loopdata, loopdata_out, (int)loopdata_out_len, ren_uv_name);
#ifdef USE_LOOPTRI_DETECT_QUADS
- int num_face_as_quad_map;
- int *face_as_quad_map = NULL;
-
- /* map faces to quads */
- if (looptri_len != mpoly_len) {
- /* over alloc, since we dont know how many ngon or quads we have */
-
- /* map fake face index to looptri */
- face_as_quad_map = MEM_mallocN(sizeof(int) * looptri_len, __func__);
- int k, j;
- for (k = 0, j = 0; j < (int)looptri_len; k++, j++) {
- face_as_quad_map[k] = j;
- /* step over all quads */
- if (mpoly[looptri[j].poly].totloop == 4) {
- j++; /* skips the nest looptri */
- }
- }
- num_face_as_quad_map = k;
- }
- else {
- num_face_as_quad_map = (int)looptri_len;
- }
+ int num_face_as_quad_map;
+ int *face_as_quad_map = NULL;
+
+ /* map faces to quads */
+ if (looptri_len != mpoly_len) {
+ /* over alloc, since we dont know how many ngon or quads we have */
+
+ /* map fake face index to looptri */
+ face_as_quad_map = MEM_mallocN(sizeof(int) * looptri_len, __func__);
+ int k, j;
+ for (k = 0, j = 0; j < (int)looptri_len; k++, j++) {
+ face_as_quad_map[k] = j;
+ /* step over all quads */
+ if (mpoly[looptri[j].poly].totloop == 4) {
+ j++; /* skips the nest looptri */
+ }
+ }
+ num_face_as_quad_map = k;
+ }
+ else {
+ num_face_as_quad_map = (int)looptri_len;
+ }
#endif
- /* Calculation */
- if (looptri_len != 0) {
- TaskScheduler *scheduler = BLI_task_scheduler_get();
- TaskPool *task_pool;
- task_pool = BLI_task_pool_create(scheduler, NULL);
-
- tangent_mask_curr = 0;
- /* Calculate tangent layers */
- SGLSLMeshToTangent data_array[MAX_MTFACE];
- const int tangent_layer_num = CustomData_number_of_layers(loopdata_out, CD_TANGENT);
- for (int n = 0; n < tangent_layer_num; n++) {
- int index = CustomData_get_layer_index_n(loopdata_out, CD_TANGENT, n);
- BLI_assert(n < MAX_MTFACE);
- SGLSLMeshToTangent *mesh2tangent = &data_array[n];
- mesh2tangent->numTessFaces = (int)looptri_len;
+ /* Calculation */
+ if (looptri_len != 0) {
+ TaskScheduler *scheduler = BLI_task_scheduler_get();
+ TaskPool *task_pool;
+ task_pool = BLI_task_pool_create(scheduler, NULL);
+
+ tangent_mask_curr = 0;
+ /* Calculate tangent layers */
+ SGLSLMeshToTangent data_array[MAX_MTFACE];
+ const int tangent_layer_num = CustomData_number_of_layers(loopdata_out, CD_TANGENT);
+ for (int n = 0; n < tangent_layer_num; n++) {
+ int index = CustomData_get_layer_index_n(loopdata_out, CD_TANGENT, n);
+ BLI_assert(n < MAX_MTFACE);
+ SGLSLMeshToTangent *mesh2tangent = &data_array[n];
+ mesh2tangent->numTessFaces = (int)looptri_len;
#ifdef USE_LOOPTRI_DETECT_QUADS
- mesh2tangent->face_as_quad_map = face_as_quad_map;
- mesh2tangent->num_face_as_quad_map = num_face_as_quad_map;
+ mesh2tangent->face_as_quad_map = face_as_quad_map;
+ mesh2tangent->num_face_as_quad_map = num_face_as_quad_map;
#endif
- mesh2tangent->mvert = mvert;
- mesh2tangent->mpoly = mpoly;
- mesh2tangent->mloop = mloop;
- mesh2tangent->looptri = looptri;
- /* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled),
- * have to check this is valid...
- */
- mesh2tangent->precomputedLoopNormals = loop_normals;
- mesh2tangent->precomputedFaceNormals = poly_normals;
-
- mesh2tangent->orco = NULL;
- mesh2tangent->mloopuv = CustomData_get_layer_named(loopdata, CD_MLOOPUV, loopdata_out->layers[index].name);
-
- /* Fill the resulting tangent_mask */
- if (!mesh2tangent->mloopuv) {
- mesh2tangent->orco = vert_orco;
- if (!mesh2tangent->orco)
- continue;
-
- tangent_mask_curr |= DM_TANGENT_MASK_ORCO;
- }
- else {
- int uv_ind = CustomData_get_named_layer_index(loopdata, CD_MLOOPUV, loopdata_out->layers[index].name);
- int uv_start = CustomData_get_layer_index(loopdata, CD_MLOOPUV);
- BLI_assert(uv_ind != -1 && uv_start != -1);
- BLI_assert(uv_ind - uv_start < MAX_MTFACE);
- tangent_mask_curr |= (short)(1 << (uv_ind - uv_start));
- }
-
- mesh2tangent->tangent = loopdata_out->layers[index].data;
- BLI_task_pool_push(task_pool, DM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW);
- }
-
- BLI_assert(tangent_mask_curr == tangent_mask);
- BLI_task_pool_work_and_wait(task_pool);
- BLI_task_pool_free(task_pool);
- }
- else {
- tangent_mask_curr = tangent_mask;
- }
+ mesh2tangent->mvert = mvert;
+ mesh2tangent->mpoly = mpoly;
+ mesh2tangent->mloop = mloop;
+ mesh2tangent->looptri = looptri;
+ /* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled),
+ * have to check this is valid...
+ */
+ mesh2tangent->precomputedLoopNormals = loop_normals;
+ mesh2tangent->precomputedFaceNormals = poly_normals;
+
+ mesh2tangent->orco = NULL;
+ mesh2tangent->mloopuv = CustomData_get_layer_named(
+ loopdata, CD_MLOOPUV, loopdata_out->layers[index].name);
+
+ /* Fill the resulting tangent_mask */
+ if (!mesh2tangent->mloopuv) {
+ mesh2tangent->orco = vert_orco;
+ if (!mesh2tangent->orco)
+ continue;
+
+ tangent_mask_curr |= DM_TANGENT_MASK_ORCO;
+ }
+ else {
+ int uv_ind = CustomData_get_named_layer_index(
+ loopdata, CD_MLOOPUV, loopdata_out->layers[index].name);
+ int uv_start = CustomData_get_layer_index(loopdata, CD_MLOOPUV);
+ BLI_assert(uv_ind != -1 && uv_start != -1);
+ BLI_assert(uv_ind - uv_start < MAX_MTFACE);
+ tangent_mask_curr |= (short)(1 << (uv_ind - uv_start));
+ }
+
+ mesh2tangent->tangent = loopdata_out->layers[index].data;
+ BLI_task_pool_push(
+ task_pool, DM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW);
+ }
+
+ BLI_assert(tangent_mask_curr == tangent_mask);
+ BLI_task_pool_work_and_wait(task_pool);
+ BLI_task_pool_free(task_pool);
+ }
+ else {
+ tangent_mask_curr = tangent_mask;
+ }
#ifdef USE_LOOPTRI_DETECT_QUADS
- if (face_as_quad_map) {
- MEM_freeN(face_as_quad_map);
- }
-#undef USE_LOOPTRI_DETECT_QUADS
+ if (face_as_quad_map) {
+ MEM_freeN(face_as_quad_map);
+ }
+# undef USE_LOOPTRI_DETECT_QUADS
#endif
- *tangent_mask_curr_p = tangent_mask_curr;
-
- /* Update active layer index */
- int act_uv_index = CustomData_get_layer_index_n(loopdata, CD_MLOOPUV, act_uv_n);
- if (act_uv_index != -1) {
- int tan_index = CustomData_get_named_layer_index(loopdata, CD_TANGENT, loopdata->layers[act_uv_index].name);
- CustomData_set_layer_active_index(loopdata, CD_TANGENT, tan_index);
- }/* else tangent has been built from orco */
-
- /* Update render layer index */
- int ren_uv_index = CustomData_get_layer_index_n(loopdata, CD_MLOOPUV, ren_uv_n);
- if (ren_uv_index != -1) {
- int tan_index = CustomData_get_named_layer_index(loopdata, CD_TANGENT, loopdata->layers[ren_uv_index].name);
- CustomData_set_layer_render_index(loopdata, CD_TANGENT, tan_index);
- }/* else tangent has been built from orco */
- }
+ *tangent_mask_curr_p = tangent_mask_curr;
+
+ /* Update active layer index */
+ int act_uv_index = CustomData_get_layer_index_n(loopdata, CD_MLOOPUV, act_uv_n);
+ if (act_uv_index != -1) {
+ int tan_index = CustomData_get_named_layer_index(
+ loopdata, CD_TANGENT, loopdata->layers[act_uv_index].name);
+ CustomData_set_layer_active_index(loopdata, CD_TANGENT, tan_index);
+ } /* else tangent has been built from orco */
+
+ /* Update render layer index */
+ int ren_uv_index = CustomData_get_layer_index_n(loopdata, CD_MLOOPUV, ren_uv_n);
+ if (ren_uv_index != -1) {
+ int tan_index = CustomData_get_named_layer_index(
+ loopdata, CD_TANGENT, loopdata->layers[ren_uv_index].name);
+ CustomData_set_layer_render_index(loopdata, CD_TANGENT, tan_index);
+ } /* else tangent has been built from orco */
+ }
}
-void BKE_mesh_calc_loop_tangents(
- Mesh *me_eval, bool calc_active_tangent,
- const char (*tangent_names)[MAX_NAME], int tangent_names_len)
+void BKE_mesh_calc_loop_tangents(Mesh *me_eval,
+ bool calc_active_tangent,
+ const char (*tangent_names)[MAX_NAME],
+ int tangent_names_len)
{
- BKE_mesh_runtime_looptri_ensure(me_eval);
-
- /* TODO(campbell): store in Mesh.runtime to avoid recalculation. */
- short tangent_mask = 0;
- BKE_mesh_calc_loop_tangent_ex(
- me_eval->mvert,
- me_eval->mpoly, (uint)me_eval->totpoly,
- me_eval->mloop,
- me_eval->runtime.looptris.array, (uint)me_eval->runtime.looptris.len,
- &me_eval->ldata,
- calc_active_tangent,
- tangent_names, tangent_names_len,
- CustomData_get_layer(&me_eval->pdata, CD_NORMAL),
- CustomData_get_layer(&me_eval->ldata, CD_NORMAL),
- CustomData_get_layer(&me_eval->vdata, CD_ORCO), /* may be NULL */
- /* result */
- &me_eval->ldata, (uint)me_eval->totloop,
- &tangent_mask);
+ BKE_mesh_runtime_looptri_ensure(me_eval);
+
+ /* TODO(campbell): store in Mesh.runtime to avoid recalculation. */
+ short tangent_mask = 0;
+ BKE_mesh_calc_loop_tangent_ex(me_eval->mvert,
+ me_eval->mpoly,
+ (uint)me_eval->totpoly,
+ me_eval->mloop,
+ me_eval->runtime.looptris.array,
+ (uint)me_eval->runtime.looptris.len,
+ &me_eval->ldata,
+ calc_active_tangent,
+ tangent_names,
+ tangent_names_len,
+ CustomData_get_layer(&me_eval->pdata, CD_NORMAL),
+ CustomData_get_layer(&me_eval->ldata, CD_NORMAL),
+ CustomData_get_layer(&me_eval->vdata, CD_ORCO), /* may be NULL */
+ /* result */
+ &me_eval->ldata,
+ (uint)me_eval->totloop,
+ &tangent_mask);
}
/** \} */
diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c
index 295b65190a8..d54796a66c4 100644
--- a/source/blender/blenkernel/intern/mesh_validate.c
+++ b/source/blender/blenkernel/intern/mesh_validate.c
@@ -21,7 +21,6 @@
* \ingroup bke
*/
-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -57,872 +56,958 @@ static CLG_LogRef LOG = {"bke.mesh"};
* \{ */
typedef union {
- uint32_t verts[2];
- int64_t edval;
+ uint32_t verts[2];
+ int64_t edval;
} EdgeUUID;
typedef struct SortFace {
- EdgeUUID es[4];
- unsigned int index;
+ EdgeUUID es[4];
+ unsigned int index;
} SortFace;
/* Used to detect polys (faces) using exactly the same vertices. */
/* Used to detect loops used by no (disjoint) or more than one (intersect) polys. */
typedef struct SortPoly {
- int *verts;
- int numverts;
- int loopstart;
- unsigned int index;
- bool invalid; /* Poly index. */
+ int *verts;
+ int numverts;
+ int loopstart;
+ unsigned int index;
+ bool invalid; /* Poly index. */
} SortPoly;
-static void edge_store_assign(uint32_t verts[2], const uint32_t v1, const uint32_t v2)
+static void edge_store_assign(uint32_t verts[2], const uint32_t v1, const uint32_t v2)
{
- if (v1 < v2) {
- verts[0] = v1;
- verts[1] = v2;
- }
- else {
- verts[0] = v2;
- verts[1] = v1;
- }
+ if (v1 < v2) {
+ verts[0] = v1;
+ verts[1] = v2;
+ }
+ else {
+ verts[0] = v2;
+ verts[1] = v1;
+ }
}
static void edge_store_from_mface_quad(EdgeUUID es[4], MFace *mf)
{
- edge_store_assign(es[0].verts, mf->v1, mf->v2);
- edge_store_assign(es[1].verts, mf->v2, mf->v3);
- edge_store_assign(es[2].verts, mf->v3, mf->v4);
- edge_store_assign(es[3].verts, mf->v4, mf->v1);
+ edge_store_assign(es[0].verts, mf->v1, mf->v2);
+ edge_store_assign(es[1].verts, mf->v2, mf->v3);
+ edge_store_assign(es[2].verts, mf->v3, mf->v4);
+ edge_store_assign(es[3].verts, mf->v4, mf->v1);
}
static void edge_store_from_mface_tri(EdgeUUID es[4], MFace *mf)
{
- edge_store_assign(es[0].verts, mf->v1, mf->v2);
- edge_store_assign(es[1].verts, mf->v2, mf->v3);
- edge_store_assign(es[2].verts, mf->v3, mf->v1);
- es[3].verts[0] = es[3].verts[1] = UINT_MAX;
+ edge_store_assign(es[0].verts, mf->v1, mf->v2);
+ edge_store_assign(es[1].verts, mf->v2, mf->v3);
+ edge_store_assign(es[2].verts, mf->v3, mf->v1);
+ es[3].verts[0] = es[3].verts[1] = UINT_MAX;
}
static int int64_cmp(const void *v1, const void *v2)
{
- const int64_t x1 = *(const int64_t *)v1;
- const int64_t x2 = *(const int64_t *)v2;
+ const int64_t x1 = *(const int64_t *)v1;
+ const int64_t x2 = *(const int64_t *)v2;
- if (x1 > x2) {
- return 1;
- }
- else if (x1 < x2) {
- return -1;
- }
+ if (x1 > x2) {
+ return 1;
+ }
+ else if (x1 < x2) {
+ return -1;
+ }
- return 0;
+ return 0;
}
static int search_face_cmp(const void *v1, const void *v2)
{
- const SortFace *sfa = v1, *sfb = v2;
-
- if (sfa->es[0].edval > sfb->es[0].edval) {
- return 1;
- }
- else if (sfa->es[0].edval < sfb->es[0].edval) {
- return -1;
- }
-
- else if (sfa->es[1].edval > sfb->es[1].edval) {
- return 1;
- }
- else if (sfa->es[1].edval < sfb->es[1].edval) {
- return -1;
- }
-
- else if (sfa->es[2].edval > sfb->es[2].edval) {
- return 1;
- }
- else if (sfa->es[2].edval < sfb->es[2].edval) {
- return -1;
- }
-
- else if (sfa->es[3].edval > sfb->es[3].edval) {
- return 1;
- }
- else if (sfa->es[3].edval < sfb->es[3].edval) {
- return -1;
- }
-
- return 0;
+ const SortFace *sfa = v1, *sfb = v2;
+
+ if (sfa->es[0].edval > sfb->es[0].edval) {
+ return 1;
+ }
+ else if (sfa->es[0].edval < sfb->es[0].edval) {
+ return -1;
+ }
+
+ else if (sfa->es[1].edval > sfb->es[1].edval) {
+ return 1;
+ }
+ else if (sfa->es[1].edval < sfb->es[1].edval) {
+ return -1;
+ }
+
+ else if (sfa->es[2].edval > sfb->es[2].edval) {
+ return 1;
+ }
+ else if (sfa->es[2].edval < sfb->es[2].edval) {
+ return -1;
+ }
+
+ else if (sfa->es[3].edval > sfb->es[3].edval) {
+ return 1;
+ }
+ else if (sfa->es[3].edval < sfb->es[3].edval) {
+ return -1;
+ }
+
+ return 0;
}
/* TODO check there is not some standard define of this somewhere! */
static int int_cmp(const void *v1, const void *v2)
{
- return *(int *)v1 > *(int *)v2 ? 1 : *(int *)v1 < *(int *)v2 ? -1 : 0;
+ return *(int *)v1 > *(int *)v2 ? 1 : *(int *)v1 < *(int *)v2 ? -1 : 0;
}
static int search_poly_cmp(const void *v1, const void *v2)
{
- const SortPoly *sp1 = v1, *sp2 = v2;
- const int max_idx = sp1->numverts > sp2->numverts ? sp2->numverts : sp1->numverts;
- int idx;
-
- /* Reject all invalid polys at end of list! */
- if (sp1->invalid || sp2->invalid)
- return sp1->invalid ? (sp2->invalid ? 0 : 1) : -1;
- /* Else, sort on first non-equal verts (remember verts of valid polys are sorted). */
- for (idx = 0; idx < max_idx; idx++) {
- const int v1_i = sp1->verts[idx];
- const int v2_i = sp2->verts[idx];
- if (v1_i != v2_i) {
- return (v1_i > v2_i) ? 1 : -1;
- }
- }
- return sp1->numverts > sp2->numverts ? 1 : sp1->numverts < sp2->numverts ? -1 : 0;
+ const SortPoly *sp1 = v1, *sp2 = v2;
+ const int max_idx = sp1->numverts > sp2->numverts ? sp2->numverts : sp1->numverts;
+ int idx;
+
+ /* Reject all invalid polys at end of list! */
+ if (sp1->invalid || sp2->invalid)
+ return sp1->invalid ? (sp2->invalid ? 0 : 1) : -1;
+ /* Else, sort on first non-equal verts (remember verts of valid polys are sorted). */
+ for (idx = 0; idx < max_idx; idx++) {
+ const int v1_i = sp1->verts[idx];
+ const int v2_i = sp2->verts[idx];
+ if (v1_i != v2_i) {
+ return (v1_i > v2_i) ? 1 : -1;
+ }
+ }
+ return sp1->numverts > sp2->numverts ? 1 : sp1->numverts < sp2->numverts ? -1 : 0;
}
static int search_polyloop_cmp(const void *v1, const void *v2)
{
- const SortPoly *sp1 = v1, *sp2 = v2;
+ const SortPoly *sp1 = v1, *sp2 = v2;
- /* Reject all invalid polys at end of list! */
- if (sp1->invalid || sp2->invalid)
- return sp1->invalid && sp2->invalid ? 0 : sp1->invalid ? 1 : -1;
- /* Else, sort on loopstart. */
- return sp1->loopstart > sp2->loopstart ? 1 : sp1->loopstart < sp2->loopstart ? -1 : 0;
+ /* Reject all invalid polys at end of list! */
+ if (sp1->invalid || sp2->invalid)
+ return sp1->invalid && sp2->invalid ? 0 : sp1->invalid ? 1 : -1;
+ /* Else, sort on loopstart. */
+ return sp1->loopstart > sp2->loopstart ? 1 : sp1->loopstart < sp2->loopstart ? -1 : 0;
}
/** \} */
-
-
/* -------------------------------------------------------------------- */
/** \name Mesh Validation
* \{ */
-#define PRINT_MSG(...) if(do_verbose) CLOG_INFO(&LOG, 1, __VA_ARGS__)
+#define PRINT_MSG(...) \
+ if (do_verbose) \
+ CLOG_INFO(&LOG, 1, __VA_ARGS__)
-#define PRINT_ERR(...) do { \
- is_valid = false; \
- if (do_verbose) { CLOG_ERROR(&LOG, __VA_ARGS__); } \
- } while(0)
+#define PRINT_ERR(...) \
+ do { \
+ is_valid = false; \
+ if (do_verbose) { \
+ CLOG_ERROR(&LOG, __VA_ARGS__); \
+ } \
+ } while (0)
/**
* Validate the mesh, \a do_fixes requires \a mesh to be non-null.
*
* \return false if no changes needed to be made.
*/
-bool BKE_mesh_validate_arrays(
- Mesh *mesh,
- MVert *mverts, unsigned int totvert,
- MEdge *medges, unsigned int totedge,
- MFace *mfaces, unsigned int totface,
- MLoop *mloops, unsigned int totloop,
- MPoly *mpolys, unsigned int totpoly,
- MDeformVert *dverts, /* assume totvert length */
- const bool do_verbose, const bool do_fixes,
- bool *r_changed)
+bool BKE_mesh_validate_arrays(Mesh *mesh,
+ MVert *mverts,
+ unsigned int totvert,
+ MEdge *medges,
+ unsigned int totedge,
+ MFace *mfaces,
+ unsigned int totface,
+ MLoop *mloops,
+ unsigned int totloop,
+ MPoly *mpolys,
+ unsigned int totpoly,
+ MDeformVert *dverts, /* assume totvert length */
+ const bool do_verbose,
+ const bool do_fixes,
+ bool *r_changed)
{
-#define REMOVE_EDGE_TAG(_me) { _me->v2 = _me->v1; free_flag.edges = do_fixes; } (void)0
+#define REMOVE_EDGE_TAG(_me) \
+ { \
+ _me->v2 = _me->v1; \
+ free_flag.edges = do_fixes; \
+ } \
+ (void)0
#define IS_REMOVED_EDGE(_me) (_me->v2 == _me->v1)
-#define REMOVE_LOOP_TAG(_ml) { _ml->e = INVALID_LOOP_EDGE_MARKER; free_flag.polyloops = do_fixes; } (void)0
-#define REMOVE_POLY_TAG(_mp) { _mp->totloop *= -1; free_flag.polyloops = do_fixes; } (void)0
-
- MVert *mv = mverts;
- MEdge *me;
- MLoop *ml;
- MPoly *mp;
- unsigned int i, j;
- int *v;
-
- bool is_valid = true;
-
- union {
- struct {
- int verts : 1;
- int verts_weight : 1;
- int loops_edge : 1;
- };
- int as_flag;
- } fix_flag;
-
- union {
- struct {
- int edges : 1;
- int faces : 1;
- /* This regroups loops and polys! */
- int polyloops : 1;
- int mselect : 1;
- };
- int as_flag;
- } free_flag;
-
- union {
- struct {
- int edges : 1;
- };
- int as_flag;
- } recalc_flag;
-
- EdgeHash *edge_hash = BLI_edgehash_new_ex(__func__, totedge);
-
- BLI_assert(!(do_fixes && mesh == NULL));
-
- fix_flag.as_flag = 0;
- free_flag.as_flag = 0;
- recalc_flag.as_flag = 0;
-
- PRINT_MSG("verts(%u), edges(%u), loops(%u), polygons(%u)",
- totvert, totedge, totloop, totpoly);
-
- if (totedge == 0 && totpoly != 0) {
- PRINT_ERR("\tLogical error, %u polygons and 0 edges", totpoly);
- recalc_flag.edges = do_fixes;
- }
-
- for (i = 0; i < totvert; i++, mv++) {
- bool fix_normal = true;
-
- for (j = 0; j < 3; j++) {
- if (!isfinite(mv->co[j])) {
- PRINT_ERR("\tVertex %u: has invalid coordinate", i);
-
- if (do_fixes) {
- zero_v3(mv->co);
-
- fix_flag.verts = true;
- }
- }
-
- if (mv->no[j] != 0)
- fix_normal = false;
- }
-
- if (fix_normal) {
- PRINT_ERR("\tVertex %u: has zero normal, assuming Z-up normal", i);
- if (do_fixes) {
- mv->no[2] = SHRT_MAX;
- fix_flag.verts = true;
- }
- }
- }
-
- for (i = 0, me = medges; i < totedge; i++, me++) {
- bool remove = false;
-
- if (me->v1 == me->v2) {
- PRINT_ERR("\tEdge %u: has matching verts, both %u", i, me->v1);
- remove = do_fixes;
- }
- if (me->v1 >= totvert) {
- PRINT_ERR("\tEdge %u: v1 index out of range, %u", i, me->v1);
- remove = do_fixes;
- }
- if (me->v2 >= totvert) {
- PRINT_ERR("\tEdge %u: v2 index out of range, %u", i, me->v2);
- remove = do_fixes;
- }
-
- if ((me->v1 != me->v2) && BLI_edgehash_haskey(edge_hash, me->v1, me->v2)) {
- PRINT_ERR("\tEdge %u: is a duplicate of %d", i,
- POINTER_AS_INT(BLI_edgehash_lookup(edge_hash, me->v1, me->v2)));
- remove = do_fixes;
- }
-
- if (remove == false) {
- if (me->v1 != me->v2) {
- BLI_edgehash_insert(edge_hash, me->v1, me->v2, POINTER_FROM_INT(i));
- }
- }
- else {
- REMOVE_EDGE_TAG(me);
- }
- }
-
- if (mfaces && !mpolys) {
-# define REMOVE_FACE_TAG(_mf) { _mf->v3 = 0; free_flag.faces = do_fixes; } (void)0
-# define CHECK_FACE_VERT_INDEX(a, b) \
- if (mf->a == mf->b) { \
- PRINT_ERR(" face %u: verts invalid, " STRINGIFY(a) "/" STRINGIFY(b) " both %u", i, mf->a); \
- remove = do_fixes; \
- } (void)0
-# define CHECK_FACE_EDGE(a, b) \
- if (!BLI_edgehash_haskey(edge_hash, mf->a, mf->b)) { \
- PRINT_ERR(" face %u: edge " STRINGIFY(a) "/" STRINGIFY(b) \
- " (%u,%u) is missing edge data", i, mf->a, mf->b); \
- recalc_flag.edges = do_fixes; \
- } (void)0
-
- MFace *mf;
- MFace *mf_prev;
-
- SortFace *sort_faces = MEM_callocN(sizeof(SortFace) * totface, "search faces");
- SortFace *sf;
- SortFace *sf_prev;
- unsigned int totsortface = 0;
-
- PRINT_ERR("No Polys, only tessellated Faces");
-
- for (i = 0, mf = mfaces, sf = sort_faces; i < totface; i++, mf++) {
- bool remove = false;
- int fidx;
- unsigned int fv[4];
-
- fidx = mf->v4 ? 3 : 2;
- do {
- fv[fidx] = *(&(mf->v1) + fidx);
- if (fv[fidx] >= totvert) {
- PRINT_ERR("\tFace %u: 'v%d' index out of range, %u", i, fidx + 1, fv[fidx]);
- remove = do_fixes;
- }
- } while (fidx--);
-
- if (remove == false) {
- if (mf->v4) {
- CHECK_FACE_VERT_INDEX(v1, v2);
- CHECK_FACE_VERT_INDEX(v1, v3);
- CHECK_FACE_VERT_INDEX(v1, v4);
-
- CHECK_FACE_VERT_INDEX(v2, v3);
- CHECK_FACE_VERT_INDEX(v2, v4);
-
- CHECK_FACE_VERT_INDEX(v3, v4);
- }
- else {
- CHECK_FACE_VERT_INDEX(v1, v2);
- CHECK_FACE_VERT_INDEX(v1, v3);
-
- CHECK_FACE_VERT_INDEX(v2, v3);
- }
-
- if (remove == false) {
- if (totedge) {
- if (mf->v4) {
- CHECK_FACE_EDGE(v1, v2);
- CHECK_FACE_EDGE(v2, v3);
- CHECK_FACE_EDGE(v3, v4);
- CHECK_FACE_EDGE(v4, v1);
- }
- else {
- CHECK_FACE_EDGE(v1, v2);
- CHECK_FACE_EDGE(v2, v3);
- CHECK_FACE_EDGE(v3, v1);
- }
- }
-
- sf->index = i;
-
- if (mf->v4) {
- edge_store_from_mface_quad(sf->es, mf);
-
- qsort(sf->es, 4, sizeof(int64_t), int64_cmp);
- }
- else {
- edge_store_from_mface_tri(sf->es, mf);
- qsort(sf->es, 3, sizeof(int64_t), int64_cmp);
- }
-
- totsortface++;
- sf++;
- }
- }
-
- if (remove) {
- REMOVE_FACE_TAG(mf);
- }
- }
-
- qsort(sort_faces, totsortface, sizeof(SortFace), search_face_cmp);
-
- sf = sort_faces;
- sf_prev = sf;
- sf++;
-
- for (i = 1; i < totsortface; i++, sf++) {
- bool remove = false;
-
- /* on a valid mesh, code below will never run */
- if (memcmp(sf->es, sf_prev->es, sizeof(sf_prev->es)) == 0) {
- mf = mfaces + sf->index;
-
- if (do_verbose) {
- mf_prev = mfaces + sf_prev->index;
-
- if (mf->v4) {
- PRINT_ERR("\tFace %u & %u: are duplicates (%u,%u,%u,%u) (%u,%u,%u,%u)",
- sf->index, sf_prev->index, mf->v1, mf->v2, mf->v3, mf->v4,
- mf_prev->v1, mf_prev->v2, mf_prev->v3, mf_prev->v4);
- }
- else {
- PRINT_ERR("\tFace %u & %u: are duplicates (%u,%u,%u) (%u,%u,%u)",
- sf->index, sf_prev->index, mf->v1, mf->v2, mf->v3,
- mf_prev->v1, mf_prev->v2, mf_prev->v3);
- }
- }
-
- remove = do_fixes;
- }
- else {
- sf_prev = sf;
- }
-
- if (remove) {
- REMOVE_FACE_TAG(mf);
- }
- }
-
- MEM_freeN(sort_faces);
-
-# undef REMOVE_FACE_TAG
-# undef CHECK_FACE_VERT_INDEX
-# undef CHECK_FACE_EDGE
- }
-
- /* Checking loops and polys is a bit tricky, as they are quite intricate...
- *
- * Polys must have:
- * - a valid loopstart value.
- * - a valid totloop value (>= 3 and loopstart+totloop < me.totloop).
- *
- * Loops must have:
- * - a valid v value.
- * - a valid e value (corresponding to the edge it defines with the next loop in poly).
- *
- * Also, loops not used by polys can be discarded.
- * And "intersecting" loops (i.e. loops used by more than one poly) are invalid,
- * so be sure to leave at most one poly per loop!
- */
- {
- SortPoly *sort_polys = MEM_callocN(sizeof(SortPoly) * totpoly, "mesh validate's sort_polys");
- SortPoly *prev_sp, *sp = sort_polys;
- int prev_end;
-
- for (i = 0, mp = mpolys; i < totpoly; i++, mp++, sp++) {
- sp->index = i;
-
- if (mp->loopstart < 0 || mp->totloop < 3) {
- /* Invalid loop data. */
- PRINT_ERR("\tPoly %u is invalid (loopstart: %d, totloop: %d)",
- sp->index, mp->loopstart, mp->totloop);
- sp->invalid = true;
- }
- else if (mp->loopstart + mp->totloop > totloop) {
- /* Invalid loop data. */
- PRINT_ERR("\tPoly %u uses loops out of range (loopstart: %d, loopend: %d, max nbr of loops: %u)",
- sp->index, mp->loopstart, mp->loopstart + mp->totloop - 1, totloop - 1);
- sp->invalid = true;
- }
- else {
- /* Poly itself is valid, for now. */
- int v1, v2; /* v1 is prev loop vert idx, v2 is current loop one. */
- sp->invalid = false;
- sp->verts = v = MEM_mallocN(sizeof(int) * mp->totloop, "Vert idx of SortPoly");
- sp->numverts = mp->totloop;
- sp->loopstart = mp->loopstart;
-
- /* Ideally we would only have to do that once on all vertices before we start checking each poly, but
- * several polys can use same vert, so we have to ensure here all verts of current poly are cleared. */
- for (j = 0, ml = &mloops[sp->loopstart]; j < mp->totloop; j++, ml++) {
- if (ml->v < totvert) {
- mverts[ml->v].flag &= ~ME_VERT_TMP_TAG;
- }
- }
-
- /* Test all poly's loops' vert idx. */
- for (j = 0, ml = &mloops[sp->loopstart]; j < mp->totloop; j++, ml++, v++) {
- if (ml->v >= totvert) {
- /* Invalid vert idx. */
- PRINT_ERR("\tLoop %u has invalid vert reference (%u)", sp->loopstart + j, ml->v);
- sp->invalid = true;
- }
- else if (mverts[ml->v].flag & ME_VERT_TMP_TAG) {
- PRINT_ERR("\tPoly %u has duplicated vert reference at corner (%u)", i, j);
- sp->invalid = true;
- }
- else {
- mverts[ml->v].flag |= ME_VERT_TMP_TAG;
- }
- *v = ml->v;
- }
-
- if (sp->invalid)
- continue;
-
- /* Test all poly's loops. */
- for (j = 0, ml = &mloops[sp->loopstart]; j < mp->totloop; j++, ml++) {
- v1 = ml->v;
- v2 = mloops[sp->loopstart + (j + 1) % mp->totloop].v;
- if (!BLI_edgehash_haskey(edge_hash, v1, v2)) {
- /* Edge not existing. */
- PRINT_ERR("\tPoly %u needs missing edge (%d, %d)", sp->index, v1, v2);
- if (do_fixes)
- recalc_flag.edges = true;
- else
- sp->invalid = true;
- }
- else if (ml->e >= totedge) {
- /* Invalid edge idx.
- * We already know from previous text that a valid edge exists, use it (if allowed)! */
- if (do_fixes) {
- int prev_e = ml->e;
- ml->e = POINTER_AS_INT(BLI_edgehash_lookup(edge_hash, v1, v2));
- fix_flag.loops_edge = true;
- PRINT_ERR("\tLoop %u has invalid edge reference (%d), fixed using edge %u",
- sp->loopstart + j, prev_e, ml->e);
- }
- else {
- PRINT_ERR("\tLoop %u has invalid edge reference (%u)", sp->loopstart + j, ml->e);
- sp->invalid = true;
- }
- }
- else {
- me = &medges[ml->e];
- if (IS_REMOVED_EDGE(me) || !((me->v1 == v1 && me->v2 == v2) || (me->v1 == v2 && me->v2 == v1))) {
- /* The pointed edge is invalid (tagged as removed, or vert idx mismatch),
- * and we already know from previous test that a valid one exists, use it (if allowed)! */
- if (do_fixes) {
- int prev_e = ml->e;
- ml->e = POINTER_AS_INT(BLI_edgehash_lookup(edge_hash, v1, v2));
- fix_flag.loops_edge = true;
- PRINT_ERR("\tPoly %u has invalid edge reference (%d, is_removed: %d), fixed using edge %u",
- sp->index, prev_e, IS_REMOVED_EDGE(me), ml->e);
- }
- else {
- PRINT_ERR("\tPoly %u has invalid edge reference (%u)", sp->index, ml->e);
- sp->invalid = true;
- }
- }
- }
- }
-
- if (!sp->invalid) {
- /* Needed for checking polys using same verts below. */
- qsort(sp->verts, sp->numverts, sizeof(int), int_cmp);
- }
- }
- }
-
- /* Second check pass, testing polys using the same verts. */
- qsort(sort_polys, totpoly, sizeof(SortPoly), search_poly_cmp);
- sp = prev_sp = sort_polys;
- sp++;
-
- for (i = 1; i < totpoly; i++, sp++) {
- int p1_nv = sp->numverts, p2_nv = prev_sp->numverts;
- const int *p1_v = sp->verts, *p2_v = prev_sp->verts;
-
- if (sp->invalid) {
- /* break, because all known invalid polys have been put at the end by qsort with search_poly_cmp. */
- break;
- }
-
- /* Test same polys. */
- if ((p1_nv == p2_nv) && (memcmp(p1_v, p2_v, p1_nv * sizeof(*p1_v)) == 0)) {
- if (do_verbose) {
- // TODO: convert list to string
- PRINT_ERR("\tPolys %u and %u use same vertices (%d",
- prev_sp->index, sp->index, *p1_v);
- for (j = 1; j < p1_nv; j++)
- PRINT_ERR(", %d", p1_v[j]);
- PRINT_ERR("), considering poly %u as invalid.", sp->index);
- }
- else {
- is_valid = false;
- }
- sp->invalid = true;
- }
- else {
- prev_sp = sp;
- }
- }
-
- /* Third check pass, testing loops used by none or more than one poly. */
- qsort(sort_polys, totpoly, sizeof(SortPoly), search_polyloop_cmp);
- sp = sort_polys;
- prev_sp = NULL;
- prev_end = 0;
- for (i = 0; i < totpoly; i++, sp++) {
- /* Free this now, we don't need it anymore, and avoid us another loop! */
- if (sp->verts)
- MEM_freeN(sp->verts);
-
- /* Note above prev_sp: in following code, we make sure it is always valid poly (or NULL). */
- if (sp->invalid) {
- if (do_fixes) {
- REMOVE_POLY_TAG((&mpolys[sp->index]));
- /* DO NOT REMOVE ITS LOOPS!!!
- * As already invalid polys are at the end of the SortPoly list, the loops they
- * were the only users have already been tagged as "to remove" during previous
- * iterations, and we don't want to remove some loops that may be used by
- * another valid poly! */
- }
- }
- /* Test loops users. */
- else {
- /* Unused loops. */
- if (prev_end < sp->loopstart) {
- for (j = prev_end, ml = &mloops[prev_end]; j < sp->loopstart; j++, ml++) {
- PRINT_ERR("\tLoop %u is unused.", j);
- if (do_fixes)
- REMOVE_LOOP_TAG(ml);
- }
- prev_end = sp->loopstart + sp->numverts;
- prev_sp = sp;
- }
- /* Multi-used loops. */
- else if (prev_end > sp->loopstart) {
- PRINT_ERR("\tPolys %u and %u share loops from %d to %d, considering poly %u as invalid.",
- prev_sp->index, sp->index, sp->loopstart, prev_end, sp->index);
- if (do_fixes) {
- REMOVE_POLY_TAG((&mpolys[sp->index]));
- /* DO NOT REMOVE ITS LOOPS!!!
- * They might be used by some next, valid poly!
- * Just not updating prev_end/prev_sp vars is enough to ensure the loops
- * effectively no more needed will be marked as "to be removed"! */
- }
- }
- else {
- prev_end = sp->loopstart + sp->numverts;
- prev_sp = sp;
- }
- }
- }
- /* We may have some remaining unused loops to get rid of! */
- if (prev_end < totloop) {
- for (j = prev_end, ml = &mloops[prev_end]; j < totloop; j++, ml++) {
- PRINT_ERR("\tLoop %u is unused.", j);
- if (do_fixes)
- REMOVE_LOOP_TAG(ml);
- }
- }
-
- MEM_freeN(sort_polys);
- }
-
- BLI_edgehash_free(edge_hash, NULL);
-
- /* fix deform verts */
- if (dverts) {
- MDeformVert *dv;
- for (i = 0, dv = dverts; i < totvert; i++, dv++) {
- MDeformWeight *dw;
-
- for (j = 0, dw = dv->dw; j < dv->totweight; j++, dw++) {
- /* note, greater than max defgroups is accounted for in our code, but not < 0 */
- if (!isfinite(dw->weight)) {
- PRINT_ERR("\tVertex deform %u, group %d has weight: %f", i, dw->def_nr, dw->weight);
- if (do_fixes) {
- dw->weight = 0.0f;
- fix_flag.verts_weight = true;
- }
- }
- else if (dw->weight < 0.0f || dw->weight > 1.0f) {
- PRINT_ERR("\tVertex deform %u, group %d has weight: %f", i, dw->def_nr, dw->weight);
- if (do_fixes) {
- CLAMP(dw->weight, 0.0f, 1.0f);
- fix_flag.verts_weight = true;
- }
- }
-
- if (dw->def_nr < 0) {
- PRINT_ERR("\tVertex deform %u, has invalid group %d", i, dw->def_nr);
- if (do_fixes) {
- defvert_remove_group(dv, dw);
- fix_flag.verts_weight = true;
-
- if (dv->dw) {
- /* re-allocated, the new values compensate for stepping
- * within the for loop and may not be valid */
- j--;
- dw = dv->dw + j;
-
- }
- else { /* all freed */
- break;
- }
- }
- }
- }
- }
- }
-
-# undef REMOVE_EDGE_TAG
-# undef IS_REMOVED_EDGE
-# undef REMOVE_LOOP_TAG
-# undef REMOVE_POLY_TAG
-
- if (mesh) {
- if (free_flag.faces) {
- BKE_mesh_strip_loose_faces(mesh);
- }
-
- if (free_flag.polyloops) {
- BKE_mesh_strip_loose_polysloops(mesh);
- }
-
- if (free_flag.edges) {
- BKE_mesh_strip_loose_edges(mesh);
- }
-
- if (recalc_flag.edges) {
- BKE_mesh_calc_edges(mesh, true, false);
- }
- }
-
- if (mesh && mesh->mselect) {
- MSelect *msel;
-
- for (i = 0, msel = mesh->mselect; i < mesh->totselect; i++, msel++) {
- int tot_elem = 0;
-
- if (msel->index < 0) {
- PRINT_ERR("\tMesh select element %u type %d index is negative, "
- "resetting selection stack.\n", i, msel->type);
- free_flag.mselect = do_fixes;
- break;
- }
-
- switch (msel->type) {
- case ME_VSEL:
- tot_elem = mesh->totvert;
- break;
- case ME_ESEL:
- tot_elem = mesh->totedge;
- break;
- case ME_FSEL:
- tot_elem = mesh->totface;
- break;
- }
-
- if (msel->index > tot_elem) {
- PRINT_ERR("\tMesh select element %u type %d index %d is larger than data array size %d, "
- "resetting selection stack.\n", i, msel->type, msel->index, tot_elem);
-
- free_flag.mselect = do_fixes;
- break;
- }
- }
-
- if (free_flag.mselect) {
- MEM_freeN(mesh->mselect);
- mesh->mselect = NULL;
- mesh->totselect = 0;
- }
- }
-
- PRINT_MSG("%s: finished\n\n", __func__);
-
- *r_changed = (fix_flag.as_flag || free_flag.as_flag || recalc_flag.as_flag);
-
- BLI_assert((*r_changed == false) || (do_fixes == true));
-
- return is_valid;
+#define REMOVE_LOOP_TAG(_ml) \
+ { \
+ _ml->e = INVALID_LOOP_EDGE_MARKER; \
+ free_flag.polyloops = do_fixes; \
+ } \
+ (void)0
+#define REMOVE_POLY_TAG(_mp) \
+ { \
+ _mp->totloop *= -1; \
+ free_flag.polyloops = do_fixes; \
+ } \
+ (void)0
+
+ MVert *mv = mverts;
+ MEdge *me;
+ MLoop *ml;
+ MPoly *mp;
+ unsigned int i, j;
+ int *v;
+
+ bool is_valid = true;
+
+ union {
+ struct {
+ int verts : 1;
+ int verts_weight : 1;
+ int loops_edge : 1;
+ };
+ int as_flag;
+ } fix_flag;
+
+ union {
+ struct {
+ int edges : 1;
+ int faces : 1;
+ /* This regroups loops and polys! */
+ int polyloops : 1;
+ int mselect : 1;
+ };
+ int as_flag;
+ } free_flag;
+
+ union {
+ struct {
+ int edges : 1;
+ };
+ int as_flag;
+ } recalc_flag;
+
+ EdgeHash *edge_hash = BLI_edgehash_new_ex(__func__, totedge);
+
+ BLI_assert(!(do_fixes && mesh == NULL));
+
+ fix_flag.as_flag = 0;
+ free_flag.as_flag = 0;
+ recalc_flag.as_flag = 0;
+
+ PRINT_MSG("verts(%u), edges(%u), loops(%u), polygons(%u)", totvert, totedge, totloop, totpoly);
+
+ if (totedge == 0 && totpoly != 0) {
+ PRINT_ERR("\tLogical error, %u polygons and 0 edges", totpoly);
+ recalc_flag.edges = do_fixes;
+ }
+
+ for (i = 0; i < totvert; i++, mv++) {
+ bool fix_normal = true;
+
+ for (j = 0; j < 3; j++) {
+ if (!isfinite(mv->co[j])) {
+ PRINT_ERR("\tVertex %u: has invalid coordinate", i);
+
+ if (do_fixes) {
+ zero_v3(mv->co);
+
+ fix_flag.verts = true;
+ }
+ }
+
+ if (mv->no[j] != 0)
+ fix_normal = false;
+ }
+
+ if (fix_normal) {
+ PRINT_ERR("\tVertex %u: has zero normal, assuming Z-up normal", i);
+ if (do_fixes) {
+ mv->no[2] = SHRT_MAX;
+ fix_flag.verts = true;
+ }
+ }
+ }
+
+ for (i = 0, me = medges; i < totedge; i++, me++) {
+ bool remove = false;
+
+ if (me->v1 == me->v2) {
+ PRINT_ERR("\tEdge %u: has matching verts, both %u", i, me->v1);
+ remove = do_fixes;
+ }
+ if (me->v1 >= totvert) {
+ PRINT_ERR("\tEdge %u: v1 index out of range, %u", i, me->v1);
+ remove = do_fixes;
+ }
+ if (me->v2 >= totvert) {
+ PRINT_ERR("\tEdge %u: v2 index out of range, %u", i, me->v2);
+ remove = do_fixes;
+ }
+
+ if ((me->v1 != me->v2) && BLI_edgehash_haskey(edge_hash, me->v1, me->v2)) {
+ PRINT_ERR("\tEdge %u: is a duplicate of %d",
+ i,
+ POINTER_AS_INT(BLI_edgehash_lookup(edge_hash, me->v1, me->v2)));
+ remove = do_fixes;
+ }
+
+ if (remove == false) {
+ if (me->v1 != me->v2) {
+ BLI_edgehash_insert(edge_hash, me->v1, me->v2, POINTER_FROM_INT(i));
+ }
+ }
+ else {
+ REMOVE_EDGE_TAG(me);
+ }
+ }
+
+ if (mfaces && !mpolys) {
+#define REMOVE_FACE_TAG(_mf) \
+ { \
+ _mf->v3 = 0; \
+ free_flag.faces = do_fixes; \
+ } \
+ (void)0
+#define CHECK_FACE_VERT_INDEX(a, b) \
+ if (mf->a == mf->b) { \
+ PRINT_ERR(" face %u: verts invalid, " STRINGIFY(a) "/" STRINGIFY(b) " both %u", i, mf->a); \
+ remove = do_fixes; \
+ } \
+ (void)0
+#define CHECK_FACE_EDGE(a, b) \
+ if (!BLI_edgehash_haskey(edge_hash, mf->a, mf->b)) { \
+ PRINT_ERR(" face %u: edge " STRINGIFY(a) "/" STRINGIFY(b) " (%u,%u) is missing edge data", \
+ i, \
+ mf->a, \
+ mf->b); \
+ recalc_flag.edges = do_fixes; \
+ } \
+ (void)0
+
+ MFace *mf;
+ MFace *mf_prev;
+
+ SortFace *sort_faces = MEM_callocN(sizeof(SortFace) * totface, "search faces");
+ SortFace *sf;
+ SortFace *sf_prev;
+ unsigned int totsortface = 0;
+
+ PRINT_ERR("No Polys, only tessellated Faces");
+
+ for (i = 0, mf = mfaces, sf = sort_faces; i < totface; i++, mf++) {
+ bool remove = false;
+ int fidx;
+ unsigned int fv[4];
+
+ fidx = mf->v4 ? 3 : 2;
+ do {
+ fv[fidx] = *(&(mf->v1) + fidx);
+ if (fv[fidx] >= totvert) {
+ PRINT_ERR("\tFace %u: 'v%d' index out of range, %u", i, fidx + 1, fv[fidx]);
+ remove = do_fixes;
+ }
+ } while (fidx--);
+
+ if (remove == false) {
+ if (mf->v4) {
+ CHECK_FACE_VERT_INDEX(v1, v2);
+ CHECK_FACE_VERT_INDEX(v1, v3);
+ CHECK_FACE_VERT_INDEX(v1, v4);
+
+ CHECK_FACE_VERT_INDEX(v2, v3);
+ CHECK_FACE_VERT_INDEX(v2, v4);
+
+ CHECK_FACE_VERT_INDEX(v3, v4);
+ }
+ else {
+ CHECK_FACE_VERT_INDEX(v1, v2);
+ CHECK_FACE_VERT_INDEX(v1, v3);
+
+ CHECK_FACE_VERT_INDEX(v2, v3);
+ }
+
+ if (remove == false) {
+ if (totedge) {
+ if (mf->v4) {
+ CHECK_FACE_EDGE(v1, v2);
+ CHECK_FACE_EDGE(v2, v3);
+ CHECK_FACE_EDGE(v3, v4);
+ CHECK_FACE_EDGE(v4, v1);
+ }
+ else {
+ CHECK_FACE_EDGE(v1, v2);
+ CHECK_FACE_EDGE(v2, v3);
+ CHECK_FACE_EDGE(v3, v1);
+ }
+ }
+
+ sf->index = i;
+
+ if (mf->v4) {
+ edge_store_from_mface_quad(sf->es, mf);
+
+ qsort(sf->es, 4, sizeof(int64_t), int64_cmp);
+ }
+ else {
+ edge_store_from_mface_tri(sf->es, mf);
+ qsort(sf->es, 3, sizeof(int64_t), int64_cmp);
+ }
+
+ totsortface++;
+ sf++;
+ }
+ }
+
+ if (remove) {
+ REMOVE_FACE_TAG(mf);
+ }
+ }
+
+ qsort(sort_faces, totsortface, sizeof(SortFace), search_face_cmp);
+
+ sf = sort_faces;
+ sf_prev = sf;
+ sf++;
+
+ for (i = 1; i < totsortface; i++, sf++) {
+ bool remove = false;
+
+ /* on a valid mesh, code below will never run */
+ if (memcmp(sf->es, sf_prev->es, sizeof(sf_prev->es)) == 0) {
+ mf = mfaces + sf->index;
+
+ if (do_verbose) {
+ mf_prev = mfaces + sf_prev->index;
+
+ if (mf->v4) {
+ PRINT_ERR("\tFace %u & %u: are duplicates (%u,%u,%u,%u) (%u,%u,%u,%u)",
+ sf->index,
+ sf_prev->index,
+ mf->v1,
+ mf->v2,
+ mf->v3,
+ mf->v4,
+ mf_prev->v1,
+ mf_prev->v2,
+ mf_prev->v3,
+ mf_prev->v4);
+ }
+ else {
+ PRINT_ERR("\tFace %u & %u: are duplicates (%u,%u,%u) (%u,%u,%u)",
+ sf->index,
+ sf_prev->index,
+ mf->v1,
+ mf->v2,
+ mf->v3,
+ mf_prev->v1,
+ mf_prev->v2,
+ mf_prev->v3);
+ }
+ }
+
+ remove = do_fixes;
+ }
+ else {
+ sf_prev = sf;
+ }
+
+ if (remove) {
+ REMOVE_FACE_TAG(mf);
+ }
+ }
+
+ MEM_freeN(sort_faces);
+
+#undef REMOVE_FACE_TAG
+#undef CHECK_FACE_VERT_INDEX
+#undef CHECK_FACE_EDGE
+ }
+
+ /* Checking loops and polys is a bit tricky, as they are quite intricate...
+ *
+ * Polys must have:
+ * - a valid loopstart value.
+ * - a valid totloop value (>= 3 and loopstart+totloop < me.totloop).
+ *
+ * Loops must have:
+ * - a valid v value.
+ * - a valid e value (corresponding to the edge it defines with the next loop in poly).
+ *
+ * Also, loops not used by polys can be discarded.
+ * And "intersecting" loops (i.e. loops used by more than one poly) are invalid,
+ * so be sure to leave at most one poly per loop!
+ */
+ {
+ SortPoly *sort_polys = MEM_callocN(sizeof(SortPoly) * totpoly, "mesh validate's sort_polys");
+ SortPoly *prev_sp, *sp = sort_polys;
+ int prev_end;
+
+ for (i = 0, mp = mpolys; i < totpoly; i++, mp++, sp++) {
+ sp->index = i;
+
+ if (mp->loopstart < 0 || mp->totloop < 3) {
+ /* Invalid loop data. */
+ PRINT_ERR("\tPoly %u is invalid (loopstart: %d, totloop: %d)",
+ sp->index,
+ mp->loopstart,
+ mp->totloop);
+ sp->invalid = true;
+ }
+ else if (mp->loopstart + mp->totloop > totloop) {
+ /* Invalid loop data. */
+ PRINT_ERR(
+ "\tPoly %u uses loops out of range (loopstart: %d, loopend: %d, max nbr of loops: %u)",
+ sp->index,
+ mp->loopstart,
+ mp->loopstart + mp->totloop - 1,
+ totloop - 1);
+ sp->invalid = true;
+ }
+ else {
+ /* Poly itself is valid, for now. */
+ int v1, v2; /* v1 is prev loop vert idx, v2 is current loop one. */
+ sp->invalid = false;
+ sp->verts = v = MEM_mallocN(sizeof(int) * mp->totloop, "Vert idx of SortPoly");
+ sp->numverts = mp->totloop;
+ sp->loopstart = mp->loopstart;
+
+ /* Ideally we would only have to do that once on all vertices before we start checking each poly, but
+ * several polys can use same vert, so we have to ensure here all verts of current poly are cleared. */
+ for (j = 0, ml = &mloops[sp->loopstart]; j < mp->totloop; j++, ml++) {
+ if (ml->v < totvert) {
+ mverts[ml->v].flag &= ~ME_VERT_TMP_TAG;
+ }
+ }
+
+ /* Test all poly's loops' vert idx. */
+ for (j = 0, ml = &mloops[sp->loopstart]; j < mp->totloop; j++, ml++, v++) {
+ if (ml->v >= totvert) {
+ /* Invalid vert idx. */
+ PRINT_ERR("\tLoop %u has invalid vert reference (%u)", sp->loopstart + j, ml->v);
+ sp->invalid = true;
+ }
+ else if (mverts[ml->v].flag & ME_VERT_TMP_TAG) {
+ PRINT_ERR("\tPoly %u has duplicated vert reference at corner (%u)", i, j);
+ sp->invalid = true;
+ }
+ else {
+ mverts[ml->v].flag |= ME_VERT_TMP_TAG;
+ }
+ *v = ml->v;
+ }
+
+ if (sp->invalid)
+ continue;
+
+ /* Test all poly's loops. */
+ for (j = 0, ml = &mloops[sp->loopstart]; j < mp->totloop; j++, ml++) {
+ v1 = ml->v;
+ v2 = mloops[sp->loopstart + (j + 1) % mp->totloop].v;
+ if (!BLI_edgehash_haskey(edge_hash, v1, v2)) {
+ /* Edge not existing. */
+ PRINT_ERR("\tPoly %u needs missing edge (%d, %d)", sp->index, v1, v2);
+ if (do_fixes)
+ recalc_flag.edges = true;
+ else
+ sp->invalid = true;
+ }
+ else if (ml->e >= totedge) {
+ /* Invalid edge idx.
+ * We already know from previous text that a valid edge exists, use it (if allowed)! */
+ if (do_fixes) {
+ int prev_e = ml->e;
+ ml->e = POINTER_AS_INT(BLI_edgehash_lookup(edge_hash, v1, v2));
+ fix_flag.loops_edge = true;
+ PRINT_ERR("\tLoop %u has invalid edge reference (%d), fixed using edge %u",
+ sp->loopstart + j,
+ prev_e,
+ ml->e);
+ }
+ else {
+ PRINT_ERR("\tLoop %u has invalid edge reference (%u)", sp->loopstart + j, ml->e);
+ sp->invalid = true;
+ }
+ }
+ else {
+ me = &medges[ml->e];
+ if (IS_REMOVED_EDGE(me) ||
+ !((me->v1 == v1 && me->v2 == v2) || (me->v1 == v2 && me->v2 == v1))) {
+ /* The pointed edge is invalid (tagged as removed, or vert idx mismatch),
+ * and we already know from previous test that a valid one exists, use it (if allowed)! */
+ if (do_fixes) {
+ int prev_e = ml->e;
+ ml->e = POINTER_AS_INT(BLI_edgehash_lookup(edge_hash, v1, v2));
+ fix_flag.loops_edge = true;
+ PRINT_ERR(
+ "\tPoly %u has invalid edge reference (%d, is_removed: %d), fixed using edge "
+ "%u",
+ sp->index,
+ prev_e,
+ IS_REMOVED_EDGE(me),
+ ml->e);
+ }
+ else {
+ PRINT_ERR("\tPoly %u has invalid edge reference (%u)", sp->index, ml->e);
+ sp->invalid = true;
+ }
+ }
+ }
+ }
+
+ if (!sp->invalid) {
+ /* Needed for checking polys using same verts below. */
+ qsort(sp->verts, sp->numverts, sizeof(int), int_cmp);
+ }
+ }
+ }
+
+ /* Second check pass, testing polys using the same verts. */
+ qsort(sort_polys, totpoly, sizeof(SortPoly), search_poly_cmp);
+ sp = prev_sp = sort_polys;
+ sp++;
+
+ for (i = 1; i < totpoly; i++, sp++) {
+ int p1_nv = sp->numverts, p2_nv = prev_sp->numverts;
+ const int *p1_v = sp->verts, *p2_v = prev_sp->verts;
+
+ if (sp->invalid) {
+ /* break, because all known invalid polys have been put at the end by qsort with search_poly_cmp. */
+ break;
+ }
+
+ /* Test same polys. */
+ if ((p1_nv == p2_nv) && (memcmp(p1_v, p2_v, p1_nv * sizeof(*p1_v)) == 0)) {
+ if (do_verbose) {
+ // TODO: convert list to string
+ PRINT_ERR("\tPolys %u and %u use same vertices (%d", prev_sp->index, sp->index, *p1_v);
+ for (j = 1; j < p1_nv; j++)
+ PRINT_ERR(", %d", p1_v[j]);
+ PRINT_ERR("), considering poly %u as invalid.", sp->index);
+ }
+ else {
+ is_valid = false;
+ }
+ sp->invalid = true;
+ }
+ else {
+ prev_sp = sp;
+ }
+ }
+
+ /* Third check pass, testing loops used by none or more than one poly. */
+ qsort(sort_polys, totpoly, sizeof(SortPoly), search_polyloop_cmp);
+ sp = sort_polys;
+ prev_sp = NULL;
+ prev_end = 0;
+ for (i = 0; i < totpoly; i++, sp++) {
+ /* Free this now, we don't need it anymore, and avoid us another loop! */
+ if (sp->verts)
+ MEM_freeN(sp->verts);
+
+ /* Note above prev_sp: in following code, we make sure it is always valid poly (or NULL). */
+ if (sp->invalid) {
+ if (do_fixes) {
+ REMOVE_POLY_TAG((&mpolys[sp->index]));
+ /* DO NOT REMOVE ITS LOOPS!!!
+ * As already invalid polys are at the end of the SortPoly list, the loops they
+ * were the only users have already been tagged as "to remove" during previous
+ * iterations, and we don't want to remove some loops that may be used by
+ * another valid poly! */
+ }
+ }
+ /* Test loops users. */
+ else {
+ /* Unused loops. */
+ if (prev_end < sp->loopstart) {
+ for (j = prev_end, ml = &mloops[prev_end]; j < sp->loopstart; j++, ml++) {
+ PRINT_ERR("\tLoop %u is unused.", j);
+ if (do_fixes)
+ REMOVE_LOOP_TAG(ml);
+ }
+ prev_end = sp->loopstart + sp->numverts;
+ prev_sp = sp;
+ }
+ /* Multi-used loops. */
+ else if (prev_end > sp->loopstart) {
+ PRINT_ERR("\tPolys %u and %u share loops from %d to %d, considering poly %u as invalid.",
+ prev_sp->index,
+ sp->index,
+ sp->loopstart,
+ prev_end,
+ sp->index);
+ if (do_fixes) {
+ REMOVE_POLY_TAG((&mpolys[sp->index]));
+ /* DO NOT REMOVE ITS LOOPS!!!
+ * They might be used by some next, valid poly!
+ * Just not updating prev_end/prev_sp vars is enough to ensure the loops
+ * effectively no more needed will be marked as "to be removed"! */
+ }
+ }
+ else {
+ prev_end = sp->loopstart + sp->numverts;
+ prev_sp = sp;
+ }
+ }
+ }
+ /* We may have some remaining unused loops to get rid of! */
+ if (prev_end < totloop) {
+ for (j = prev_end, ml = &mloops[prev_end]; j < totloop; j++, ml++) {
+ PRINT_ERR("\tLoop %u is unused.", j);
+ if (do_fixes)
+ REMOVE_LOOP_TAG(ml);
+ }
+ }
+
+ MEM_freeN(sort_polys);
+ }
+
+ BLI_edgehash_free(edge_hash, NULL);
+
+ /* fix deform verts */
+ if (dverts) {
+ MDeformVert *dv;
+ for (i = 0, dv = dverts; i < totvert; i++, dv++) {
+ MDeformWeight *dw;
+
+ for (j = 0, dw = dv->dw; j < dv->totweight; j++, dw++) {
+ /* note, greater than max defgroups is accounted for in our code, but not < 0 */
+ if (!isfinite(dw->weight)) {
+ PRINT_ERR("\tVertex deform %u, group %d has weight: %f", i, dw->def_nr, dw->weight);
+ if (do_fixes) {
+ dw->weight = 0.0f;
+ fix_flag.verts_weight = true;
+ }
+ }
+ else if (dw->weight < 0.0f || dw->weight > 1.0f) {
+ PRINT_ERR("\tVertex deform %u, group %d has weight: %f", i, dw->def_nr, dw->weight);
+ if (do_fixes) {
+ CLAMP(dw->weight, 0.0f, 1.0f);
+ fix_flag.verts_weight = true;
+ }
+ }
+
+ if (dw->def_nr < 0) {
+ PRINT_ERR("\tVertex deform %u, has invalid group %d", i, dw->def_nr);
+ if (do_fixes) {
+ defvert_remove_group(dv, dw);
+ fix_flag.verts_weight = true;
+
+ if (dv->dw) {
+ /* re-allocated, the new values compensate for stepping
+ * within the for loop and may not be valid */
+ j--;
+ dw = dv->dw + j;
+ }
+ else { /* all freed */
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+#undef REMOVE_EDGE_TAG
+#undef IS_REMOVED_EDGE
+#undef REMOVE_LOOP_TAG
+#undef REMOVE_POLY_TAG
+
+ if (mesh) {
+ if (free_flag.faces) {
+ BKE_mesh_strip_loose_faces(mesh);
+ }
+
+ if (free_flag.polyloops) {
+ BKE_mesh_strip_loose_polysloops(mesh);
+ }
+
+ if (free_flag.edges) {
+ BKE_mesh_strip_loose_edges(mesh);
+ }
+
+ if (recalc_flag.edges) {
+ BKE_mesh_calc_edges(mesh, true, false);
+ }
+ }
+
+ if (mesh && mesh->mselect) {
+ MSelect *msel;
+
+ for (i = 0, msel = mesh->mselect; i < mesh->totselect; i++, msel++) {
+ int tot_elem = 0;
+
+ if (msel->index < 0) {
+ PRINT_ERR(
+ "\tMesh select element %u type %d index is negative, "
+ "resetting selection stack.\n",
+ i,
+ msel->type);
+ free_flag.mselect = do_fixes;
+ break;
+ }
+
+ switch (msel->type) {
+ case ME_VSEL:
+ tot_elem = mesh->totvert;
+ break;
+ case ME_ESEL:
+ tot_elem = mesh->totedge;
+ break;
+ case ME_FSEL:
+ tot_elem = mesh->totface;
+ break;
+ }
+
+ if (msel->index > tot_elem) {
+ PRINT_ERR(
+ "\tMesh select element %u type %d index %d is larger than data array size %d, "
+ "resetting selection stack.\n",
+ i,
+ msel->type,
+ msel->index,
+ tot_elem);
+
+ free_flag.mselect = do_fixes;
+ break;
+ }
+ }
+
+ if (free_flag.mselect) {
+ MEM_freeN(mesh->mselect);
+ mesh->mselect = NULL;
+ mesh->totselect = 0;
+ }
+ }
+
+ PRINT_MSG("%s: finished\n\n", __func__);
+
+ *r_changed = (fix_flag.as_flag || free_flag.as_flag || recalc_flag.as_flag);
+
+ BLI_assert((*r_changed == false) || (do_fixes == true));
+
+ return is_valid;
}
-static bool mesh_validate_customdata(
- CustomData *data, CustomDataMask mask, const uint totitems,
- const bool do_verbose, const bool do_fixes,
- bool *r_change)
+static bool mesh_validate_customdata(CustomData *data,
+ CustomDataMask mask,
+ const uint totitems,
+ const bool do_verbose,
+ const bool do_fixes,
+ bool *r_change)
{
- bool is_valid = true;
- bool has_fixes = false;
- int i = 0;
-
- PRINT_MSG("%s: Checking %d CD layers...\n", __func__, data->totlayer);
-
- while (i < data->totlayer) {
- CustomDataLayer *layer = &data->layers[i];
- bool ok = true;
-
- if (CustomData_layertype_is_singleton(layer->type)) {
- const int layer_tot = CustomData_number_of_layers(data, layer->type);
- if (layer_tot > 1) {
- PRINT_ERR("\tCustomDataLayer type %d is a singleton, found %d in Mesh structure\n",
- layer->type, layer_tot);
- ok = false;
- }
- }
-
- if (mask != 0) {
- CustomDataMask layer_typemask = CD_TYPE_AS_MASK(layer->type);
- if ((layer_typemask & mask) == 0) {
- PRINT_ERR("\tCustomDataLayer type %d which isn't in the mask\n",
- layer->type);
- ok = false;
- }
- }
-
- if (ok == false) {
- if (do_fixes) {
- CustomData_free_layer(data, layer->type, 0, i);
- has_fixes = true;
- }
- }
-
- if (ok) {
- if (CustomData_layer_validate(layer, totitems, do_fixes)) {
- PRINT_ERR("\tCustomDataLayer type %d has some invalid data\n", layer->type);
- has_fixes = do_fixes;
- }
- i++;
- }
- }
-
- PRINT_MSG("%s: Finished (is_valid=%d)\n\n", __func__, (int)!has_fixes);
-
- *r_change = has_fixes;
-
- return is_valid;
+ bool is_valid = true;
+ bool has_fixes = false;
+ int i = 0;
+
+ PRINT_MSG("%s: Checking %d CD layers...\n", __func__, data->totlayer);
+
+ while (i < data->totlayer) {
+ CustomDataLayer *layer = &data->layers[i];
+ bool ok = true;
+
+ if (CustomData_layertype_is_singleton(layer->type)) {
+ const int layer_tot = CustomData_number_of_layers(data, layer->type);
+ if (layer_tot > 1) {
+ PRINT_ERR("\tCustomDataLayer type %d is a singleton, found %d in Mesh structure\n",
+ layer->type,
+ layer_tot);
+ ok = false;
+ }
+ }
+
+ if (mask != 0) {
+ CustomDataMask layer_typemask = CD_TYPE_AS_MASK(layer->type);
+ if ((layer_typemask & mask) == 0) {
+ PRINT_ERR("\tCustomDataLayer type %d which isn't in the mask\n", layer->type);
+ ok = false;
+ }
+ }
+
+ if (ok == false) {
+ if (do_fixes) {
+ CustomData_free_layer(data, layer->type, 0, i);
+ has_fixes = true;
+ }
+ }
+
+ if (ok) {
+ if (CustomData_layer_validate(layer, totitems, do_fixes)) {
+ PRINT_ERR("\tCustomDataLayer type %d has some invalid data\n", layer->type);
+ has_fixes = do_fixes;
+ }
+ i++;
+ }
+ }
+
+ PRINT_MSG("%s: Finished (is_valid=%d)\n\n", __func__, (int)!has_fixes);
+
+ *r_change = has_fixes;
+
+ return is_valid;
}
/**
* \returns is_valid.
*/
-bool BKE_mesh_validate_all_customdata(
- CustomData *vdata, const uint totvert,
- CustomData *edata, const uint totedge,
- CustomData *ldata, const uint totloop,
- CustomData *pdata, const uint totpoly,
- const bool check_meshmask,
- const bool do_verbose, const bool do_fixes,
- bool *r_change)
+bool BKE_mesh_validate_all_customdata(CustomData *vdata,
+ const uint totvert,
+ CustomData *edata,
+ const uint totedge,
+ CustomData *ldata,
+ const uint totloop,
+ CustomData *pdata,
+ const uint totpoly,
+ const bool check_meshmask,
+ const bool do_verbose,
+ const bool do_fixes,
+ bool *r_change)
{
- bool is_valid = true;
- bool is_change_v, is_change_e, is_change_l, is_change_p;
- int tot_uvloop, tot_vcolloop;
- CustomData_MeshMasks mask = {0};
- if (check_meshmask) {
- mask = CD_MASK_MESH;
- }
-
- is_valid &= mesh_validate_customdata(vdata, mask.vmask, totvert, do_verbose, do_fixes, &is_change_v);
- is_valid &= mesh_validate_customdata(edata, mask.emask, totedge, do_verbose, do_fixes, &is_change_e);
- is_valid &= mesh_validate_customdata(ldata, mask.lmask, totloop, do_verbose, do_fixes, &is_change_l);
- is_valid &= mesh_validate_customdata(pdata, mask.pmask, totpoly, do_verbose, do_fixes, &is_change_p);
-
- tot_uvloop = CustomData_number_of_layers(ldata, CD_MLOOPUV);
- tot_vcolloop = CustomData_number_of_layers(ldata, CD_MLOOPCOL);
- if (tot_uvloop > MAX_MTFACE) {
- PRINT_ERR("\tMore UV layers than %d allowed, %d last ones won't be available for render, shaders, etc.\n",
- MAX_MTFACE, tot_uvloop - MAX_MTFACE);
- }
- if (tot_vcolloop > MAX_MCOL) {
- PRINT_ERR("\tMore VCol layers than %d allowed, %d last ones won't be available for render, shaders, etc.\n",
- MAX_MCOL, tot_vcolloop - MAX_MCOL);
- }
-
- /* check indices of clone/stencil */
- if (do_fixes && CustomData_get_clone_layer(ldata, CD_MLOOPUV) >= tot_uvloop) {
- CustomData_set_layer_clone(ldata, CD_MLOOPUV, 0);
- is_change_l = true;
- }
- if (do_fixes && CustomData_get_stencil_layer(ldata, CD_MLOOPUV) >= tot_uvloop) {
- CustomData_set_layer_stencil(ldata, CD_MLOOPUV, 0);
- is_change_l = true;
- }
-
- *r_change = (is_change_v || is_change_e || is_change_l || is_change_p);
-
- return is_valid;
+ bool is_valid = true;
+ bool is_change_v, is_change_e, is_change_l, is_change_p;
+ int tot_uvloop, tot_vcolloop;
+ CustomData_MeshMasks mask = {0};
+ if (check_meshmask) {
+ mask = CD_MASK_MESH;
+ }
+
+ is_valid &= mesh_validate_customdata(
+ vdata, mask.vmask, totvert, do_verbose, do_fixes, &is_change_v);
+ is_valid &= mesh_validate_customdata(
+ edata, mask.emask, totedge, do_verbose, do_fixes, &is_change_e);
+ is_valid &= mesh_validate_customdata(
+ ldata, mask.lmask, totloop, do_verbose, do_fixes, &is_change_l);
+ is_valid &= mesh_validate_customdata(
+ pdata, mask.pmask, totpoly, do_verbose, do_fixes, &is_change_p);
+
+ tot_uvloop = CustomData_number_of_layers(ldata, CD_MLOOPUV);
+ tot_vcolloop = CustomData_number_of_layers(ldata, CD_MLOOPCOL);
+ if (tot_uvloop > MAX_MTFACE) {
+ PRINT_ERR(
+ "\tMore UV layers than %d allowed, %d last ones won't be available for render, shaders, "
+ "etc.\n",
+ MAX_MTFACE,
+ tot_uvloop - MAX_MTFACE);
+ }
+ if (tot_vcolloop > MAX_MCOL) {
+ PRINT_ERR(
+ "\tMore VCol layers than %d allowed, %d last ones won't be available for render, shaders, "
+ "etc.\n",
+ MAX_MCOL,
+ tot_vcolloop - MAX_MCOL);
+ }
+
+ /* check indices of clone/stencil */
+ if (do_fixes && CustomData_get_clone_layer(ldata, CD_MLOOPUV) >= tot_uvloop) {
+ CustomData_set_layer_clone(ldata, CD_MLOOPUV, 0);
+ is_change_l = true;
+ }
+ if (do_fixes && CustomData_get_stencil_layer(ldata, CD_MLOOPUV) >= tot_uvloop) {
+ CustomData_set_layer_stencil(ldata, CD_MLOOPUV, 0);
+ is_change_l = true;
+ }
+
+ *r_change = (is_change_v || is_change_e || is_change_l || is_change_p);
+
+ return is_valid;
}
/**
@@ -932,40 +1017,49 @@ bool BKE_mesh_validate_all_customdata(
*/
bool BKE_mesh_validate(Mesh *me, const bool do_verbose, const bool cddata_check_mask)
{
- bool is_valid = true;
- bool changed;
-
- if (do_verbose) {
- CLOG_INFO(&LOG, 0, "MESH: %s", me->id.name + 2);
- }
-
- is_valid &= BKE_mesh_validate_all_customdata(
- &me->vdata, me->totvert,
- &me->edata, me->totedge,
- &me->ldata, me->totloop,
- &me->pdata, me->totpoly,
- cddata_check_mask,
- do_verbose, true,
- &changed);
-
- is_valid &= BKE_mesh_validate_arrays(
- me,
- me->mvert, me->totvert,
- me->medge, me->totedge,
- me->mface, me->totface,
- me->mloop, me->totloop,
- me->mpoly, me->totpoly,
- me->dvert,
- do_verbose, true,
- &changed);
-
- if (changed) {
- DEG_id_tag_update(&me->id, ID_RECALC_GEOMETRY);
- return true;
- }
- else {
- return false;
- }
+ bool is_valid = true;
+ bool changed;
+
+ if (do_verbose) {
+ CLOG_INFO(&LOG, 0, "MESH: %s", me->id.name + 2);
+ }
+
+ is_valid &= BKE_mesh_validate_all_customdata(&me->vdata,
+ me->totvert,
+ &me->edata,
+ me->totedge,
+ &me->ldata,
+ me->totloop,
+ &me->pdata,
+ me->totpoly,
+ cddata_check_mask,
+ do_verbose,
+ true,
+ &changed);
+
+ is_valid &= BKE_mesh_validate_arrays(me,
+ me->mvert,
+ me->totvert,
+ me->medge,
+ me->totedge,
+ me->mface,
+ me->totface,
+ me->mloop,
+ me->totloop,
+ me->mpoly,
+ me->totpoly,
+ me->dvert,
+ do_verbose,
+ true,
+ &changed);
+
+ if (changed) {
+ DEG_id_tag_update(&me->id, ID_RECALC_GEOMETRY);
+ return true;
+ }
+ else {
+ return false;
+ }
}
/**
@@ -977,34 +1071,45 @@ bool BKE_mesh_validate(Mesh *me, const bool do_verbose, const bool cddata_check_
*/
bool BKE_mesh_is_valid(Mesh *me)
{
- const bool do_verbose = true;
- const bool do_fixes = false;
-
- bool is_valid = true;
- bool changed = true;
-
- is_valid &= BKE_mesh_validate_all_customdata(
- &me->vdata, me->totvert,
- &me->edata, me->totedge,
- &me->ldata, me->totloop,
- &me->pdata, me->totpoly,
- false, /* setting mask here isn't useful, gives false positives */
- do_verbose, do_fixes, &changed);
-
- is_valid &= BKE_mesh_validate_arrays(
- me,
- me->mvert, me->totvert,
- me->medge, me->totedge,
- me->mface, me->totface,
- me->mloop, me->totloop,
- me->mpoly, me->totpoly,
- me->dvert,
- do_verbose, do_fixes,
- &changed);
-
- BLI_assert(changed == false);
-
- return is_valid;
+ const bool do_verbose = true;
+ const bool do_fixes = false;
+
+ bool is_valid = true;
+ bool changed = true;
+
+ is_valid &= BKE_mesh_validate_all_customdata(
+ &me->vdata,
+ me->totvert,
+ &me->edata,
+ me->totedge,
+ &me->ldata,
+ me->totloop,
+ &me->pdata,
+ me->totpoly,
+ false, /* setting mask here isn't useful, gives false positives */
+ do_verbose,
+ do_fixes,
+ &changed);
+
+ is_valid &= BKE_mesh_validate_arrays(me,
+ me->mvert,
+ me->totvert,
+ me->medge,
+ me->totedge,
+ me->mface,
+ me->totface,
+ me->mloop,
+ me->totloop,
+ me->mpoly,
+ me->totpoly,
+ me->dvert,
+ do_verbose,
+ do_fixes,
+ &changed);
+
+ BLI_assert(changed == false);
+
+ return is_valid;
}
/**
@@ -1013,31 +1118,30 @@ bool BKE_mesh_is_valid(Mesh *me)
*/
bool BKE_mesh_validate_material_indices(Mesh *me)
{
- MPoly *mp;
- const int max_idx = max_ii(0, me->totcol - 1);
- const int totpoly = me->totpoly;
- int i;
- bool is_valid = true;
-
- for (mp = me->mpoly, i = 0; i < totpoly; i++, mp++) {
- if (mp->mat_nr > max_idx) {
- mp->mat_nr = 0;
- is_valid = false;
- }
- }
-
- if (!is_valid) {
- DEG_id_tag_update(&me->id, ID_RECALC_GEOMETRY);
- return true;
- }
- else {
- return false;
- }
+ MPoly *mp;
+ const int max_idx = max_ii(0, me->totcol - 1);
+ const int totpoly = me->totpoly;
+ int i;
+ bool is_valid = true;
+
+ for (mp = me->mpoly, i = 0; i < totpoly; i++, mp++) {
+ if (mp->mat_nr > max_idx) {
+ mp->mat_nr = 0;
+ is_valid = false;
+ }
+ }
+
+ if (!is_valid) {
+ DEG_id_tag_update(&me->id, ID_RECALC_GEOMETRY);
+ return true;
+ }
+ else {
+ return false;
+ }
}
/** \} */
-
/* -------------------------------------------------------------------- */
/** \name Mesh Stripping (removing invalid data)
* \{ */
@@ -1045,22 +1149,22 @@ bool BKE_mesh_validate_material_indices(Mesh *me)
/* We need to keep this for edge creation (for now?), and some old readfile code... */
void BKE_mesh_strip_loose_faces(Mesh *me)
{
- MFace *f;
- int a, b;
-
- for (a = b = 0, f = me->mface; a < me->totface; a++, f++) {
- if (f->v3) {
- if (a != b) {
- memcpy(&me->mface[b], f, sizeof(me->mface[b]));
- CustomData_copy_data(&me->fdata, &me->fdata, a, b, 1);
- }
- b++;
- }
- }
- if (a != b) {
- CustomData_free_elem(&me->fdata, b, a - b);
- me->totface = b;
- }
+ MFace *f;
+ int a, b;
+
+ for (a = b = 0, f = me->mface; a < me->totface; a++, f++) {
+ if (f->v3) {
+ if (a != b) {
+ memcpy(&me->mface[b], f, sizeof(me->mface[b]));
+ CustomData_copy_data(&me->fdata, &me->fdata, a, b, 1);
+ }
+ b++;
+ }
+ }
+ if (a != b) {
+ CustomData_free_elem(&me->fdata, b, a - b);
+ me->totface = b;
+ }
}
/**
@@ -1072,113 +1176,111 @@ void BKE_mesh_strip_loose_faces(Mesh *me)
*/
void BKE_mesh_strip_loose_polysloops(Mesh *me)
{
- MPoly *p;
- MLoop *l;
- int a, b;
- /* New loops idx! */
- int *new_idx = MEM_mallocN(sizeof(int) * me->totloop, __func__);
-
- for (a = b = 0, p = me->mpoly; a < me->totpoly; a++, p++) {
- bool invalid = false;
- int i = p->loopstart;
- int stop = i + p->totloop;
-
- if (stop > me->totloop || stop < i) {
- invalid = true;
- }
- else {
- l = &me->mloop[i];
- i = stop - i;
- /* If one of the poly's loops is invalid, the whole poly is invalid! */
- for (; i--; l++) {
- if (l->e == INVALID_LOOP_EDGE_MARKER) {
- invalid = true;
- break;
- }
- }
- }
-
- if (p->totloop >= 3 && !invalid) {
- if (a != b) {
- memcpy(&me->mpoly[b], p, sizeof(me->mpoly[b]));
- CustomData_copy_data(&me->pdata, &me->pdata, a, b, 1);
- }
- b++;
- }
- }
- if (a != b) {
- CustomData_free_elem(&me->pdata, b, a - b);
- me->totpoly = b;
- }
-
- /* And now, get rid of invalid loops. */
- for (a = b = 0, l = me->mloop; a < me->totloop; a++, l++) {
- if (l->e != INVALID_LOOP_EDGE_MARKER) {
- if (a != b) {
- memcpy(&me->mloop[b], l, sizeof(me->mloop[b]));
- CustomData_copy_data(&me->ldata, &me->ldata, a, b, 1);
- }
- new_idx[a] = b;
- b++;
- }
- else {
- /* XXX Theoretically, we should be able to not do this, as no remaining poly
- * should use any stripped loop. But for security's sake... */
- new_idx[a] = -a;
- }
- }
- if (a != b) {
- CustomData_free_elem(&me->ldata, b, a - b);
- me->totloop = b;
- }
-
- /* And now, update polys' start loop index. */
- /* Note: At this point, there should never be any poly using a striped loop! */
- for (a = 0, p = me->mpoly; a < me->totpoly; a++, p++) {
- p->loopstart = new_idx[p->loopstart];
- }
-
- MEM_freeN(new_idx);
+ MPoly *p;
+ MLoop *l;
+ int a, b;
+ /* New loops idx! */
+ int *new_idx = MEM_mallocN(sizeof(int) * me->totloop, __func__);
+
+ for (a = b = 0, p = me->mpoly; a < me->totpoly; a++, p++) {
+ bool invalid = false;
+ int i = p->loopstart;
+ int stop = i + p->totloop;
+
+ if (stop > me->totloop || stop < i) {
+ invalid = true;
+ }
+ else {
+ l = &me->mloop[i];
+ i = stop - i;
+ /* If one of the poly's loops is invalid, the whole poly is invalid! */
+ for (; i--; l++) {
+ if (l->e == INVALID_LOOP_EDGE_MARKER) {
+ invalid = true;
+ break;
+ }
+ }
+ }
+
+ if (p->totloop >= 3 && !invalid) {
+ if (a != b) {
+ memcpy(&me->mpoly[b], p, sizeof(me->mpoly[b]));
+ CustomData_copy_data(&me->pdata, &me->pdata, a, b, 1);
+ }
+ b++;
+ }
+ }
+ if (a != b) {
+ CustomData_free_elem(&me->pdata, b, a - b);
+ me->totpoly = b;
+ }
+
+ /* And now, get rid of invalid loops. */
+ for (a = b = 0, l = me->mloop; a < me->totloop; a++, l++) {
+ if (l->e != INVALID_LOOP_EDGE_MARKER) {
+ if (a != b) {
+ memcpy(&me->mloop[b], l, sizeof(me->mloop[b]));
+ CustomData_copy_data(&me->ldata, &me->ldata, a, b, 1);
+ }
+ new_idx[a] = b;
+ b++;
+ }
+ else {
+ /* XXX Theoretically, we should be able to not do this, as no remaining poly
+ * should use any stripped loop. But for security's sake... */
+ new_idx[a] = -a;
+ }
+ }
+ if (a != b) {
+ CustomData_free_elem(&me->ldata, b, a - b);
+ me->totloop = b;
+ }
+
+ /* And now, update polys' start loop index. */
+ /* Note: At this point, there should never be any poly using a striped loop! */
+ for (a = 0, p = me->mpoly; a < me->totpoly; a++, p++) {
+ p->loopstart = new_idx[p->loopstart];
+ }
+
+ MEM_freeN(new_idx);
}
void BKE_mesh_strip_loose_edges(Mesh *me)
{
- MEdge *e;
- MLoop *l;
- int a, b;
- unsigned int *new_idx = MEM_mallocN(sizeof(int) * me->totedge, __func__);
-
- for (a = b = 0, e = me->medge; a < me->totedge; a++, e++) {
- if (e->v1 != e->v2) {
- if (a != b) {
- memcpy(&me->medge[b], e, sizeof(me->medge[b]));
- CustomData_copy_data(&me->edata, &me->edata, a, b, 1);
- }
- new_idx[a] = b;
- b++;
- }
- else {
- new_idx[a] = INVALID_LOOP_EDGE_MARKER;
- }
- }
- if (a != b) {
- CustomData_free_elem(&me->edata, b, a - b);
- me->totedge = b;
- }
-
- /* And now, update loops' edge indices. */
- /* XXX We hope no loop was pointing to a striped edge!
- * Else, its e will be set to INVALID_LOOP_EDGE_MARKER :/ */
- for (a = 0, l = me->mloop; a < me->totloop; a++, l++) {
- l->e = new_idx[l->e];
- }
-
- MEM_freeN(new_idx);
+ MEdge *e;
+ MLoop *l;
+ int a, b;
+ unsigned int *new_idx = MEM_mallocN(sizeof(int) * me->totedge, __func__);
+
+ for (a = b = 0, e = me->medge; a < me->totedge; a++, e++) {
+ if (e->v1 != e->v2) {
+ if (a != b) {
+ memcpy(&me->medge[b], e, sizeof(me->medge[b]));
+ CustomData_copy_data(&me->edata, &me->edata, a, b, 1);
+ }
+ new_idx[a] = b;
+ b++;
+ }
+ else {
+ new_idx[a] = INVALID_LOOP_EDGE_MARKER;
+ }
+ }
+ if (a != b) {
+ CustomData_free_elem(&me->edata, b, a - b);
+ me->totedge = b;
+ }
+
+ /* And now, update loops' edge indices. */
+ /* XXX We hope no loop was pointing to a striped edge!
+ * Else, its e will be set to INVALID_LOOP_EDGE_MARKER :/ */
+ for (a = 0, l = me->mloop; a < me->totloop; a++, l++) {
+ l->e = new_idx[l->e];
+ }
+
+ MEM_freeN(new_idx);
}
/** \} */
-
-
/* -------------------------------------------------------------------- */
/** \name Mesh Edge Calculation
* \{ */
@@ -1186,152 +1288,168 @@ void BKE_mesh_strip_loose_edges(Mesh *me)
/* make edges in a Mesh, for outside of editmode */
struct EdgeSort {
- unsigned int v1, v2;
- char is_loose, is_draw;
+ unsigned int v1, v2;
+ char is_loose, is_draw;
};
/* edges have to be added with lowest index first for sorting */
static void to_edgesort(
- struct EdgeSort *ed,
- unsigned int v1, unsigned int v2,
- char is_loose, short is_draw)
+ struct EdgeSort *ed, unsigned int v1, unsigned int v2, char is_loose, short is_draw)
{
- if (v1 < v2) {
- ed->v1 = v1; ed->v2 = v2;
- }
- else {
- ed->v1 = v2; ed->v2 = v1;
- }
- ed->is_loose = is_loose;
- ed->is_draw = is_draw;
+ if (v1 < v2) {
+ ed->v1 = v1;
+ ed->v2 = v2;
+ }
+ else {
+ ed->v1 = v2;
+ ed->v2 = v1;
+ }
+ ed->is_loose = is_loose;
+ ed->is_draw = is_draw;
}
static int vergedgesort(const void *v1, const void *v2)
{
- const struct EdgeSort *x1 = v1, *x2 = v2;
-
- if (x1->v1 > x2->v1) return 1;
- else if (x1->v1 < x2->v1) return -1;
- else if (x1->v2 > x2->v2) return 1;
- else if (x1->v2 < x2->v2) return -1;
-
- return 0;
+ const struct EdgeSort *x1 = v1, *x2 = v2;
+
+ if (x1->v1 > x2->v1)
+ return 1;
+ else if (x1->v1 < x2->v1)
+ return -1;
+ else if (x1->v2 > x2->v2)
+ return 1;
+ else if (x1->v2 < x2->v2)
+ return -1;
+
+ return 0;
}
-
/* Create edges based on known verts and faces,
* this function is only used when loading very old blend files */
-static void mesh_calc_edges_mdata(
- MVert *UNUSED(allvert), MFace *allface, MLoop *allloop,
- MPoly *allpoly, int UNUSED(totvert), int totface, int UNUSED(totloop), int totpoly,
- const bool use_old,
- MEdge **r_medge, int *r_totedge)
+static void mesh_calc_edges_mdata(MVert *UNUSED(allvert),
+ MFace *allface,
+ MLoop *allloop,
+ MPoly *allpoly,
+ int UNUSED(totvert),
+ int totface,
+ int UNUSED(totloop),
+ int totpoly,
+ const bool use_old,
+ MEdge **r_medge,
+ int *r_totedge)
{
- MPoly *mpoly;
- MFace *mface;
- MEdge *medge, *med;
- EdgeHash *hash;
- struct EdgeSort *edsort, *ed;
- int a, totedge = 0;
- unsigned int totedge_final = 0;
- unsigned int edge_index;
-
- /* we put all edges in array, sort them, and detect doubles that way */
-
- for (a = totface, mface = allface; a > 0; a--, mface++) {
- if (mface->v4) totedge += 4;
- else if (mface->v3) totedge += 3;
- else totedge += 1;
- }
-
- if (totedge == 0) {
- /* flag that mesh has edges */
- (*r_medge) = MEM_callocN(0, __func__);
- (*r_totedge) = 0;
- return;
- }
-
- ed = edsort = MEM_mallocN(totedge * sizeof(struct EdgeSort), "EdgeSort");
-
- for (a = totface, mface = allface; a > 0; a--, mface++) {
- to_edgesort(ed++, mface->v1, mface->v2, !mface->v3, mface->edcode & ME_V1V2);
- if (mface->v4) {
- to_edgesort(ed++, mface->v2, mface->v3, 0, mface->edcode & ME_V2V3);
- to_edgesort(ed++, mface->v3, mface->v4, 0, mface->edcode & ME_V3V4);
- to_edgesort(ed++, mface->v4, mface->v1, 0, mface->edcode & ME_V4V1);
- }
- else if (mface->v3) {
- to_edgesort(ed++, mface->v2, mface->v3, 0, mface->edcode & ME_V2V3);
- to_edgesort(ed++, mface->v3, mface->v1, 0, mface->edcode & ME_V3V1);
- }
- }
-
- qsort(edsort, totedge, sizeof(struct EdgeSort), vergedgesort);
-
- /* count final amount */
- for (a = totedge, ed = edsort; a > 1; a--, ed++) {
- /* edge is unique when it differs from next edge, or is last */
- if (ed->v1 != (ed + 1)->v1 || ed->v2 != (ed + 1)->v2) totedge_final++;
- }
- totedge_final++;
-
- medge = MEM_callocN(sizeof(MEdge) * totedge_final, __func__);
-
- for (a = totedge, med = medge, ed = edsort; a > 1; a--, ed++) {
- /* edge is unique when it differs from next edge, or is last */
- if (ed->v1 != (ed + 1)->v1 || ed->v2 != (ed + 1)->v2) {
- med->v1 = ed->v1;
- med->v2 = ed->v2;
- if (use_old == false || ed->is_draw) med->flag = ME_EDGEDRAW | ME_EDGERENDER;
- if (ed->is_loose) med->flag |= ME_LOOSEEDGE;
-
- /* order is swapped so extruding this edge as a surface wont flip face normals
- * with cyclic curves */
- if (ed->v1 + 1 != ed->v2) {
- SWAP(unsigned int, med->v1, med->v2);
- }
- med++;
- }
- else {
- /* equal edge, we merge the drawflag */
- (ed + 1)->is_draw |= ed->is_draw;
- }
- }
- /* last edge */
- med->v1 = ed->v1;
- med->v2 = ed->v2;
- med->flag = ME_EDGEDRAW;
- if (ed->is_loose) med->flag |= ME_LOOSEEDGE;
- med->flag |= ME_EDGERENDER;
-
- MEM_freeN(edsort);
-
- /* set edge members of mloops */
- hash = BLI_edgehash_new_ex(__func__, totedge_final);
- for (edge_index = 0, med = medge; edge_index < totedge_final; edge_index++, med++) {
- BLI_edgehash_insert(hash, med->v1, med->v2, POINTER_FROM_UINT(edge_index));
- }
-
- mpoly = allpoly;
- for (a = 0; a < totpoly; a++, mpoly++) {
- MLoop *ml, *ml_next;
- int i = mpoly->totloop;
-
- ml_next = allloop + mpoly->loopstart; /* first loop */
- ml = &ml_next[i - 1]; /* last loop */
-
- while (i-- != 0) {
- ml->e = POINTER_AS_UINT(BLI_edgehash_lookup(hash, ml->v, ml_next->v));
- ml = ml_next;
- ml_next++;
- }
- }
-
- BLI_edgehash_free(hash, NULL);
-
- *r_medge = medge;
- *r_totedge = totedge_final;
+ MPoly *mpoly;
+ MFace *mface;
+ MEdge *medge, *med;
+ EdgeHash *hash;
+ struct EdgeSort *edsort, *ed;
+ int a, totedge = 0;
+ unsigned int totedge_final = 0;
+ unsigned int edge_index;
+
+ /* we put all edges in array, sort them, and detect doubles that way */
+
+ for (a = totface, mface = allface; a > 0; a--, mface++) {
+ if (mface->v4)
+ totedge += 4;
+ else if (mface->v3)
+ totedge += 3;
+ else
+ totedge += 1;
+ }
+
+ if (totedge == 0) {
+ /* flag that mesh has edges */
+ (*r_medge) = MEM_callocN(0, __func__);
+ (*r_totedge) = 0;
+ return;
+ }
+
+ ed = edsort = MEM_mallocN(totedge * sizeof(struct EdgeSort), "EdgeSort");
+
+ for (a = totface, mface = allface; a > 0; a--, mface++) {
+ to_edgesort(ed++, mface->v1, mface->v2, !mface->v3, mface->edcode & ME_V1V2);
+ if (mface->v4) {
+ to_edgesort(ed++, mface->v2, mface->v3, 0, mface->edcode & ME_V2V3);
+ to_edgesort(ed++, mface->v3, mface->v4, 0, mface->edcode & ME_V3V4);
+ to_edgesort(ed++, mface->v4, mface->v1, 0, mface->edcode & ME_V4V1);
+ }
+ else if (mface->v3) {
+ to_edgesort(ed++, mface->v2, mface->v3, 0, mface->edcode & ME_V2V3);
+ to_edgesort(ed++, mface->v3, mface->v1, 0, mface->edcode & ME_V3V1);
+ }
+ }
+
+ qsort(edsort, totedge, sizeof(struct EdgeSort), vergedgesort);
+
+ /* count final amount */
+ for (a = totedge, ed = edsort; a > 1; a--, ed++) {
+ /* edge is unique when it differs from next edge, or is last */
+ if (ed->v1 != (ed + 1)->v1 || ed->v2 != (ed + 1)->v2)
+ totedge_final++;
+ }
+ totedge_final++;
+
+ medge = MEM_callocN(sizeof(MEdge) * totedge_final, __func__);
+
+ for (a = totedge, med = medge, ed = edsort; a > 1; a--, ed++) {
+ /* edge is unique when it differs from next edge, or is last */
+ if (ed->v1 != (ed + 1)->v1 || ed->v2 != (ed + 1)->v2) {
+ med->v1 = ed->v1;
+ med->v2 = ed->v2;
+ if (use_old == false || ed->is_draw)
+ med->flag = ME_EDGEDRAW | ME_EDGERENDER;
+ if (ed->is_loose)
+ med->flag |= ME_LOOSEEDGE;
+
+ /* order is swapped so extruding this edge as a surface wont flip face normals
+ * with cyclic curves */
+ if (ed->v1 + 1 != ed->v2) {
+ SWAP(unsigned int, med->v1, med->v2);
+ }
+ med++;
+ }
+ else {
+ /* equal edge, we merge the drawflag */
+ (ed + 1)->is_draw |= ed->is_draw;
+ }
+ }
+ /* last edge */
+ med->v1 = ed->v1;
+ med->v2 = ed->v2;
+ med->flag = ME_EDGEDRAW;
+ if (ed->is_loose)
+ med->flag |= ME_LOOSEEDGE;
+ med->flag |= ME_EDGERENDER;
+
+ MEM_freeN(edsort);
+
+ /* set edge members of mloops */
+ hash = BLI_edgehash_new_ex(__func__, totedge_final);
+ for (edge_index = 0, med = medge; edge_index < totedge_final; edge_index++, med++) {
+ BLI_edgehash_insert(hash, med->v1, med->v2, POINTER_FROM_UINT(edge_index));
+ }
+
+ mpoly = allpoly;
+ for (a = 0; a < totpoly; a++, mpoly++) {
+ MLoop *ml, *ml_next;
+ int i = mpoly->totloop;
+
+ ml_next = allloop + mpoly->loopstart; /* first loop */
+ ml = &ml_next[i - 1]; /* last loop */
+
+ while (i-- != 0) {
+ ml->e = POINTER_AS_UINT(BLI_edgehash_lookup(hash, ml->v, ml_next->v));
+ ml = ml_next;
+ ml_next++;
+ }
+ }
+
+ BLI_edgehash_free(hash, NULL);
+
+ *r_medge = medge;
+ *r_totedge = totedge_final;
}
/**
@@ -1340,29 +1458,35 @@ static void mesh_calc_edges_mdata(
*/
void BKE_mesh_calc_edges_legacy(Mesh *me, const bool use_old)
{
- MEdge *medge;
- int totedge = 0;
-
- mesh_calc_edges_mdata(
- me->mvert, me->mface, me->mloop, me->mpoly,
- me->totvert, me->totface, me->totloop, me->totpoly,
- use_old, &medge, &totedge);
-
- if (totedge == 0) {
- /* flag that mesh has edges */
- me->medge = medge;
- me->totedge = 0;
- return;
- }
-
- medge = CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, medge, totedge);
- me->medge = medge;
- me->totedge = totedge;
-
- BKE_mesh_strip_loose_faces(me);
+ MEdge *medge;
+ int totedge = 0;
+
+ mesh_calc_edges_mdata(me->mvert,
+ me->mface,
+ me->mloop,
+ me->mpoly,
+ me->totvert,
+ me->totface,
+ me->totloop,
+ me->totpoly,
+ use_old,
+ &medge,
+ &totedge);
+
+ if (totedge == 0) {
+ /* flag that mesh has edges */
+ me->medge = medge;
+ me->totedge = 0;
+ return;
+ }
+
+ medge = CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, medge, totedge);
+ me->medge = medge;
+ me->totedge = totedge;
+
+ BKE_mesh_strip_loose_faces(me);
}
-
/**
* Calculate edges from polygons
*
@@ -1371,106 +1495,104 @@ void BKE_mesh_calc_edges_legacy(Mesh *me, const bool use_old)
*/
void BKE_mesh_calc_edges(Mesh *mesh, bool update, const bool select)
{
- CustomData edata;
- EdgeHashIterator *ehi;
- MPoly *mp;
- MEdge *med, *med_orig;
- EdgeHash *eh;
- unsigned int eh_reserve;
- int i, totedge, totpoly = mesh->totpoly;
- int med_index;
- /* select for newly created meshes which are selected [#25595] */
- const short ed_flag = (ME_EDGEDRAW | ME_EDGERENDER) | (select ? SELECT : 0);
-
- if (mesh->totedge == 0)
- update = false;
-
- eh_reserve = max_ii(update ? mesh->totedge : 0, BLI_EDGEHASH_SIZE_GUESS_FROM_POLYS(totpoly));
- eh = BLI_edgehash_new_ex(__func__, eh_reserve);
-
- if (update) {
- /* assume existing edges are valid
- * useful when adding more faces and generating edges from them */
- med = mesh->medge;
- for (i = 0; i < mesh->totedge; i++, med++)
- BLI_edgehash_insert(eh, med->v1, med->v2, med);
- }
-
- /* mesh loops (bmesh only) */
- for (mp = mesh->mpoly, i = 0; i < totpoly; mp++, i++) {
- MLoop *l = &mesh->mloop[mp->loopstart];
- int j, v_prev = (l + (mp->totloop - 1))->v;
- for (j = 0; j < mp->totloop; j++, l++) {
- if (v_prev != l->v) {
- void **val_p;
- if (!BLI_edgehash_ensure_p(eh, v_prev, l->v, &val_p)) {
- *val_p = NULL;
- }
- }
- v_prev = l->v;
- }
- }
-
- totedge = BLI_edgehash_len(eh);
-
- /* write new edges into a temporary CustomData */
- CustomData_reset(&edata);
- CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge);
-
- med = CustomData_get_layer(&edata, CD_MEDGE);
- for (ehi = BLI_edgehashIterator_new(eh), i = 0;
- BLI_edgehashIterator_isDone(ehi) == false;
- BLI_edgehashIterator_step(ehi), ++i, ++med)
- {
- if (update && (med_orig = BLI_edgehashIterator_getValue(ehi))) {
- *med = *med_orig; /* copy from the original */
- }
- else {
- BLI_edgehashIterator_getKey(ehi, &med->v1, &med->v2);
- med->flag = ed_flag;
- }
-
- /* store the new edge index in the hash value */
- BLI_edgehashIterator_setValue(ehi, POINTER_FROM_INT(i));
- }
- BLI_edgehashIterator_free(ehi);
-
- if (mesh->totpoly) {
- /* second pass, iterate through all loops again and assign
- * the newly created edges to them. */
- for (mp = mesh->mpoly, i = 0; i < mesh->totpoly; mp++, i++) {
- MLoop *l = &mesh->mloop[mp->loopstart];
- MLoop *l_prev = (l + (mp->totloop - 1));
- int j;
- for (j = 0; j < mp->totloop; j++, l++) {
- /* lookup hashed edge index */
- med_index = POINTER_AS_INT(BLI_edgehash_lookup(eh, l_prev->v, l->v));
- l_prev->e = med_index;
- l_prev = l;
- }
- }
- }
-
- /* free old CustomData and assign new one */
- CustomData_free(&mesh->edata, mesh->totedge);
- mesh->edata = edata;
- mesh->totedge = totedge;
-
- mesh->medge = CustomData_get_layer(&mesh->edata, CD_MEDGE);
-
- BLI_edgehash_free(eh, NULL);
+ CustomData edata;
+ EdgeHashIterator *ehi;
+ MPoly *mp;
+ MEdge *med, *med_orig;
+ EdgeHash *eh;
+ unsigned int eh_reserve;
+ int i, totedge, totpoly = mesh->totpoly;
+ int med_index;
+ /* select for newly created meshes which are selected [#25595] */
+ const short ed_flag = (ME_EDGEDRAW | ME_EDGERENDER) | (select ? SELECT : 0);
+
+ if (mesh->totedge == 0)
+ update = false;
+
+ eh_reserve = max_ii(update ? mesh->totedge : 0, BLI_EDGEHASH_SIZE_GUESS_FROM_POLYS(totpoly));
+ eh = BLI_edgehash_new_ex(__func__, eh_reserve);
+
+ if (update) {
+ /* assume existing edges are valid
+ * useful when adding more faces and generating edges from them */
+ med = mesh->medge;
+ for (i = 0; i < mesh->totedge; i++, med++)
+ BLI_edgehash_insert(eh, med->v1, med->v2, med);
+ }
+
+ /* mesh loops (bmesh only) */
+ for (mp = mesh->mpoly, i = 0; i < totpoly; mp++, i++) {
+ MLoop *l = &mesh->mloop[mp->loopstart];
+ int j, v_prev = (l + (mp->totloop - 1))->v;
+ for (j = 0; j < mp->totloop; j++, l++) {
+ if (v_prev != l->v) {
+ void **val_p;
+ if (!BLI_edgehash_ensure_p(eh, v_prev, l->v, &val_p)) {
+ *val_p = NULL;
+ }
+ }
+ v_prev = l->v;
+ }
+ }
+
+ totedge = BLI_edgehash_len(eh);
+
+ /* write new edges into a temporary CustomData */
+ CustomData_reset(&edata);
+ CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge);
+
+ med = CustomData_get_layer(&edata, CD_MEDGE);
+ for (ehi = BLI_edgehashIterator_new(eh), i = 0; BLI_edgehashIterator_isDone(ehi) == false;
+ BLI_edgehashIterator_step(ehi), ++i, ++med) {
+ if (update && (med_orig = BLI_edgehashIterator_getValue(ehi))) {
+ *med = *med_orig; /* copy from the original */
+ }
+ else {
+ BLI_edgehashIterator_getKey(ehi, &med->v1, &med->v2);
+ med->flag = ed_flag;
+ }
+
+ /* store the new edge index in the hash value */
+ BLI_edgehashIterator_setValue(ehi, POINTER_FROM_INT(i));
+ }
+ BLI_edgehashIterator_free(ehi);
+
+ if (mesh->totpoly) {
+ /* second pass, iterate through all loops again and assign
+ * the newly created edges to them. */
+ for (mp = mesh->mpoly, i = 0; i < mesh->totpoly; mp++, i++) {
+ MLoop *l = &mesh->mloop[mp->loopstart];
+ MLoop *l_prev = (l + (mp->totloop - 1));
+ int j;
+ for (j = 0; j < mp->totloop; j++, l++) {
+ /* lookup hashed edge index */
+ med_index = POINTER_AS_INT(BLI_edgehash_lookup(eh, l_prev->v, l->v));
+ l_prev->e = med_index;
+ l_prev = l;
+ }
+ }
+ }
+
+ /* free old CustomData and assign new one */
+ CustomData_free(&mesh->edata, mesh->totedge);
+ mesh->edata = edata;
+ mesh->totedge = totedge;
+
+ mesh->medge = CustomData_get_layer(&mesh->edata, CD_MEDGE);
+
+ BLI_edgehash_free(eh, NULL);
}
void BKE_mesh_calc_edges_loose(Mesh *mesh)
{
- MEdge *med = mesh->medge;
- for (int i = 0; i < mesh->totedge; i++, med++) {
- med->flag |= ME_LOOSEEDGE;
- }
- MLoop *ml = mesh->mloop;
- for (int i = 0; i < mesh->totloop; i++, ml++) {
- mesh->medge[ml->e].flag &= ~ME_LOOSEEDGE;
- }
+ MEdge *med = mesh->medge;
+ for (int i = 0; i < mesh->totedge; i++, med++) {
+ med->flag |= ME_LOOSEEDGE;
+ }
+ MLoop *ml = mesh->mloop;
+ for (int i = 0; i < mesh->totloop; i++, ml++) {
+ mesh->medge[ml->e].flag &= ~ME_LOOSEEDGE;
+ }
}
/**
@@ -1481,57 +1603,55 @@ void BKE_mesh_calc_edges_loose(Mesh *mesh)
void BKE_mesh_calc_edges_tessface(Mesh *mesh)
{
- CustomData edgeData;
- EdgeSetIterator *ehi;
- MFace *mf = mesh->mface;
- MEdge *med;
- EdgeSet *eh;
- int i, *index, numEdges, numFaces = mesh->totface;
-
- eh = BLI_edgeset_new_ex(__func__, BLI_EDGEHASH_SIZE_GUESS_FROM_POLYS(numFaces));
-
- for (i = 0; i < numFaces; i++, mf++) {
- BLI_edgeset_add(eh, mf->v1, mf->v2);
- BLI_edgeset_add(eh, mf->v2, mf->v3);
-
- if (mf->v4) {
- BLI_edgeset_add(eh, mf->v3, mf->v4);
- BLI_edgeset_add(eh, mf->v4, mf->v1);
- }
- else {
- BLI_edgeset_add(eh, mf->v3, mf->v1);
- }
- }
-
- numEdges = BLI_edgeset_len(eh);
-
- /* write new edges into a temporary CustomData */
- CustomData_reset(&edgeData);
- CustomData_add_layer(&edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges);
- CustomData_add_layer(&edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, numEdges);
-
- med = CustomData_get_layer(&edgeData, CD_MEDGE);
- index = CustomData_get_layer(&edgeData, CD_ORIGINDEX);
-
- for (ehi = BLI_edgesetIterator_new(eh), i = 0;
- BLI_edgesetIterator_isDone(ehi) == false;
- BLI_edgesetIterator_step(ehi), i++, med++, index++)
- {
- BLI_edgesetIterator_getKey(ehi, &med->v1, &med->v2);
-
- med->flag = ME_EDGEDRAW | ME_EDGERENDER;
- *index = ORIGINDEX_NONE;
- }
- BLI_edgesetIterator_free(ehi);
-
- /* free old CustomData and assign new one */
- CustomData_free(&mesh->edata, mesh->totedge);
- mesh->edata = edgeData;
- mesh->totedge = numEdges;
-
- mesh->medge = CustomData_get_layer(&mesh->edata, CD_MEDGE);
-
- BLI_edgeset_free(eh);
+ CustomData edgeData;
+ EdgeSetIterator *ehi;
+ MFace *mf = mesh->mface;
+ MEdge *med;
+ EdgeSet *eh;
+ int i, *index, numEdges, numFaces = mesh->totface;
+
+ eh = BLI_edgeset_new_ex(__func__, BLI_EDGEHASH_SIZE_GUESS_FROM_POLYS(numFaces));
+
+ for (i = 0; i < numFaces; i++, mf++) {
+ BLI_edgeset_add(eh, mf->v1, mf->v2);
+ BLI_edgeset_add(eh, mf->v2, mf->v3);
+
+ if (mf->v4) {
+ BLI_edgeset_add(eh, mf->v3, mf->v4);
+ BLI_edgeset_add(eh, mf->v4, mf->v1);
+ }
+ else {
+ BLI_edgeset_add(eh, mf->v3, mf->v1);
+ }
+ }
+
+ numEdges = BLI_edgeset_len(eh);
+
+ /* write new edges into a temporary CustomData */
+ CustomData_reset(&edgeData);
+ CustomData_add_layer(&edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges);
+ CustomData_add_layer(&edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, numEdges);
+
+ med = CustomData_get_layer(&edgeData, CD_MEDGE);
+ index = CustomData_get_layer(&edgeData, CD_ORIGINDEX);
+
+ for (ehi = BLI_edgesetIterator_new(eh), i = 0; BLI_edgesetIterator_isDone(ehi) == false;
+ BLI_edgesetIterator_step(ehi), i++, med++, index++) {
+ BLI_edgesetIterator_getKey(ehi, &med->v1, &med->v2);
+
+ med->flag = ME_EDGEDRAW | ME_EDGERENDER;
+ *index = ORIGINDEX_NONE;
+ }
+ BLI_edgesetIterator_free(ehi);
+
+ /* free old CustomData and assign new one */
+ CustomData_free(&mesh->edata, mesh->totedge);
+ mesh->edata = edgeData;
+ mesh->totedge = numEdges;
+
+ mesh->medge = CustomData_get_layer(&mesh->edata, CD_MEDGE);
+
+ BLI_edgeset_free(eh);
}
/** \} */
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index 7600c74b777..7d4fc15ca56 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -76,317 +76,327 @@ static VirtualModifierData virtualModifierCommonData;
void BKE_modifier_init(void)
{
- ModifierData *md;
+ ModifierData *md;
- /* Initialize modifier types */
- modifier_type_init(modifier_types); /* MOD_utils.c */
+ /* Initialize modifier types */
+ modifier_type_init(modifier_types); /* MOD_utils.c */
- /* Initialize global cmmon storage used for virtual modifier list */
- md = modifier_new(eModifierType_Armature);
- virtualModifierCommonData.amd = *((ArmatureModifierData *) md);
- modifier_free(md);
+ /* Initialize global cmmon storage used for virtual modifier list */
+ md = modifier_new(eModifierType_Armature);
+ virtualModifierCommonData.amd = *((ArmatureModifierData *)md);
+ modifier_free(md);
- md = modifier_new(eModifierType_Curve);
- virtualModifierCommonData.cmd = *((CurveModifierData *) md);
- modifier_free(md);
+ md = modifier_new(eModifierType_Curve);
+ virtualModifierCommonData.cmd = *((CurveModifierData *)md);
+ modifier_free(md);
- md = modifier_new(eModifierType_Lattice);
- virtualModifierCommonData.lmd = *((LatticeModifierData *) md);
- modifier_free(md);
+ md = modifier_new(eModifierType_Lattice);
+ virtualModifierCommonData.lmd = *((LatticeModifierData *)md);
+ modifier_free(md);
- md = modifier_new(eModifierType_ShapeKey);
- virtualModifierCommonData.smd = *((ShapeKeyModifierData *) md);
- modifier_free(md);
+ md = modifier_new(eModifierType_ShapeKey);
+ virtualModifierCommonData.smd = *((ShapeKeyModifierData *)md);
+ modifier_free(md);
- virtualModifierCommonData.amd.modifier.mode |= eModifierMode_Virtual;
- virtualModifierCommonData.cmd.modifier.mode |= eModifierMode_Virtual;
- virtualModifierCommonData.lmd.modifier.mode |= eModifierMode_Virtual;
- virtualModifierCommonData.smd.modifier.mode |= eModifierMode_Virtual;
+ virtualModifierCommonData.amd.modifier.mode |= eModifierMode_Virtual;
+ virtualModifierCommonData.cmd.modifier.mode |= eModifierMode_Virtual;
+ virtualModifierCommonData.lmd.modifier.mode |= eModifierMode_Virtual;
+ virtualModifierCommonData.smd.modifier.mode |= eModifierMode_Virtual;
}
const ModifierTypeInfo *modifierType_getInfo(ModifierType type)
{
- /* type unsigned, no need to check < 0 */
- if (type < NUM_MODIFIER_TYPES && modifier_types[type]->name[0] != '\0') {
- return modifier_types[type];
- }
- else {
- return NULL;
- }
+ /* type unsigned, no need to check < 0 */
+ if (type < NUM_MODIFIER_TYPES && modifier_types[type]->name[0] != '\0') {
+ return modifier_types[type];
+ }
+ else {
+ return NULL;
+ }
}
/***/
ModifierData *modifier_new(int type)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(type);
- ModifierData *md = MEM_callocN(mti->structSize, mti->structName);
+ const ModifierTypeInfo *mti = modifierType_getInfo(type);
+ ModifierData *md = MEM_callocN(mti->structSize, mti->structName);
- /* note, this name must be made unique later */
- BLI_strncpy(md->name, DATA_(mti->name), sizeof(md->name));
+ /* note, this name must be made unique later */
+ BLI_strncpy(md->name, DATA_(mti->name), sizeof(md->name));
- md->type = type;
- md->mode = eModifierMode_Realtime | eModifierMode_Render | eModifierMode_Expanded;
- md->flag = eModifierFlag_StaticOverride_Local;
+ md->type = type;
+ md->mode = eModifierMode_Realtime | eModifierMode_Render | eModifierMode_Expanded;
+ md->flag = eModifierFlag_StaticOverride_Local;
- if (mti->flags & eModifierTypeFlag_EnableInEditmode)
- md->mode |= eModifierMode_Editmode;
+ if (mti->flags & eModifierTypeFlag_EnableInEditmode)
+ md->mode |= eModifierMode_Editmode;
- if (mti->initData) mti->initData(md);
+ if (mti->initData)
+ mti->initData(md);
- return md;
+ return md;
}
-static void modifier_free_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag)
+static void modifier_free_data_id_us_cb(void *UNUSED(userData),
+ Object *UNUSED(ob),
+ ID **idpoin,
+ int cb_flag)
{
- ID *id = *idpoin;
- if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
- id_us_min(id);
- }
+ ID *id = *idpoin;
+ if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
+ id_us_min(id);
+ }
}
void modifier_free_ex(ModifierData *md, const int flag)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- if (mti->foreachIDLink) {
- mti->foreachIDLink(md, NULL, modifier_free_data_id_us_cb, NULL);
- }
- else if (mti->foreachObjectLink) {
- mti->foreachObjectLink(md, NULL, (ObjectWalkFunc)modifier_free_data_id_us_cb, NULL);
- }
- }
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ if (mti->foreachIDLink) {
+ mti->foreachIDLink(md, NULL, modifier_free_data_id_us_cb, NULL);
+ }
+ else if (mti->foreachObjectLink) {
+ mti->foreachObjectLink(md, NULL, (ObjectWalkFunc)modifier_free_data_id_us_cb, NULL);
+ }
+ }
- if (mti->freeData) mti->freeData(md);
- if (md->error) MEM_freeN(md->error);
+ if (mti->freeData)
+ mti->freeData(md);
+ if (md->error)
+ MEM_freeN(md->error);
- MEM_freeN(md);
+ MEM_freeN(md);
}
void modifier_free(ModifierData *md)
{
- modifier_free_ex(md, 0);
+ modifier_free_ex(md, 0);
}
bool modifier_unique_name(ListBase *modifiers, ModifierData *md)
{
- if (modifiers && md) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ if (modifiers && md) {
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- return BLI_uniquename(modifiers, md, DATA_(mti->name), '.', offsetof(ModifierData, name), sizeof(md->name));
- }
- return false;
+ return BLI_uniquename(
+ modifiers, md, DATA_(mti->name), '.', offsetof(ModifierData, name), sizeof(md->name));
+ }
+ return false;
}
bool modifier_dependsOnTime(ModifierData *md)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- return mti->dependsOnTime && mti->dependsOnTime(md);
+ return mti->dependsOnTime && mti->dependsOnTime(md);
}
bool modifier_supportsMapping(ModifierData *md)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- return (mti->type == eModifierTypeType_OnlyDeform ||
- (mti->flags & eModifierTypeFlag_SupportsMapping));
+ return (mti->type == eModifierTypeType_OnlyDeform ||
+ (mti->flags & eModifierTypeFlag_SupportsMapping));
}
bool modifier_isPreview(ModifierData *md)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- /* Constructive modifiers are highly likely to also modify data like vgroups or vcol! */
- if (!((mti->flags & eModifierTypeFlag_UsesPreview) || (mti->type == eModifierTypeType_Constructive))) {
- return false;
- }
+ /* Constructive modifiers are highly likely to also modify data like vgroups or vcol! */
+ if (!((mti->flags & eModifierTypeFlag_UsesPreview) ||
+ (mti->type == eModifierTypeType_Constructive))) {
+ return false;
+ }
- if (md->mode & eModifierMode_Realtime) {
- return true;
- }
+ if (md->mode & eModifierMode_Realtime) {
+ return true;
+ }
- return false;
+ return false;
}
ModifierData *modifiers_findByType(Object *ob, ModifierType type)
{
- ModifierData *md = ob->modifiers.first;
+ ModifierData *md = ob->modifiers.first;
- for (; md; md = md->next)
- if (md->type == type)
- break;
+ for (; md; md = md->next)
+ if (md->type == type)
+ break;
- return md;
+ return md;
}
ModifierData *modifiers_findByName(Object *ob, const char *name)
{
- return BLI_findstring(&(ob->modifiers), name, offsetof(ModifierData, name));
+ return BLI_findstring(&(ob->modifiers), name, offsetof(ModifierData, name));
}
void modifiers_clearErrors(Object *ob)
{
- ModifierData *md = ob->modifiers.first;
- /* int qRedraw = 0; */
+ ModifierData *md = ob->modifiers.first;
+ /* int qRedraw = 0; */
- for (; md; md = md->next) {
- if (md->error) {
- MEM_freeN(md->error);
- md->error = NULL;
+ for (; md; md = md->next) {
+ if (md->error) {
+ MEM_freeN(md->error);
+ md->error = NULL;
- /* qRedraw = 1; */
- }
- }
+ /* qRedraw = 1; */
+ }
+ }
}
void modifiers_foreachObjectLink(Object *ob, ObjectWalkFunc walk, void *userData)
{
- ModifierData *md = ob->modifiers.first;
+ ModifierData *md = ob->modifiers.first;
- for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ for (; md; md = md->next) {
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- if (mti->foreachObjectLink)
- mti->foreachObjectLink(md, ob, walk, userData);
- }
+ if (mti->foreachObjectLink)
+ mti->foreachObjectLink(md, ob, walk, userData);
+ }
}
void modifiers_foreachIDLink(Object *ob, IDWalkFunc walk, void *userData)
{
- ModifierData *md = ob->modifiers.first;
+ ModifierData *md = ob->modifiers.first;
- for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ for (; md; md = md->next) {
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- if (mti->foreachIDLink) mti->foreachIDLink(md, ob, walk, userData);
- else if (mti->foreachObjectLink) {
- /* each Object can masquerade as an ID, so this should be OK */
- ObjectWalkFunc fp = (ObjectWalkFunc)walk;
- mti->foreachObjectLink(md, ob, fp, userData);
- }
- }
+ if (mti->foreachIDLink)
+ mti->foreachIDLink(md, ob, walk, userData);
+ else if (mti->foreachObjectLink) {
+ /* each Object can masquerade as an ID, so this should be OK */
+ ObjectWalkFunc fp = (ObjectWalkFunc)walk;
+ mti->foreachObjectLink(md, ob, fp, userData);
+ }
+ }
}
void modifiers_foreachTexLink(Object *ob, TexWalkFunc walk, void *userData)
{
- ModifierData *md = ob->modifiers.first;
+ ModifierData *md = ob->modifiers.first;
- for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ for (; md; md = md->next) {
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- if (mti->foreachTexLink)
- mti->foreachTexLink(md, ob, walk, userData);
- }
+ if (mti->foreachTexLink)
+ mti->foreachTexLink(md, ob, walk, userData);
+ }
}
/* callback's can use this
* to avoid copying every member.
*/
-void modifier_copyData_generic(const ModifierData *md_src, ModifierData *md_dst, const int UNUSED(flag))
+void modifier_copyData_generic(const ModifierData *md_src,
+ ModifierData *md_dst,
+ const int UNUSED(flag))
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md_src->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md_src->type);
- /* md_dst may have already be fully initialized with some extra allocated data,
- * we need to free it now to avoid memleak. */
- if (mti->freeData) {
- mti->freeData(md_dst);
- }
+ /* md_dst may have already be fully initialized with some extra allocated data,
+ * we need to free it now to avoid memleak. */
+ if (mti->freeData) {
+ mti->freeData(md_dst);
+ }
- const size_t data_size = sizeof(ModifierData);
- const char *md_src_data = ((const char *)md_src) + data_size;
- char *md_dst_data = ((char *)md_dst) + data_size;
- BLI_assert(data_size <= (size_t)mti->structSize);
- memcpy(md_dst_data, md_src_data, (size_t)mti->structSize - data_size);
+ const size_t data_size = sizeof(ModifierData);
+ const char *md_src_data = ((const char *)md_src) + data_size;
+ char *md_dst_data = ((char *)md_dst) + data_size;
+ BLI_assert(data_size <= (size_t)mti->structSize);
+ memcpy(md_dst_data, md_src_data, (size_t)mti->structSize - data_size);
- /* Runtime fields are never to be preserved. */
- md_dst->runtime = NULL;
+ /* Runtime fields are never to be preserved. */
+ md_dst->runtime = NULL;
}
-static void modifier_copy_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag)
+static void modifier_copy_data_id_us_cb(void *UNUSED(userData),
+ Object *UNUSED(ob),
+ ID **idpoin,
+ int cb_flag)
{
- ID *id = *idpoin;
- if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
- id_us_plus(id);
- }
+ ID *id = *idpoin;
+ if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
+ id_us_plus(id);
+ }
}
void modifier_copyData_ex(ModifierData *md, ModifierData *target, const int flag)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- target->mode = md->mode;
- target->flag = md->flag;
+ target->mode = md->mode;
+ target->flag = md->flag;
- if (mti->copyData) {
- mti->copyData(md, target, flag);
- }
+ if (mti->copyData) {
+ mti->copyData(md, target, flag);
+ }
- if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- if (mti->foreachIDLink) {
- mti->foreachIDLink(target, NULL, modifier_copy_data_id_us_cb, NULL);
- }
- else if (mti->foreachObjectLink) {
- mti->foreachObjectLink(target, NULL, (ObjectWalkFunc)modifier_copy_data_id_us_cb, NULL);
- }
- }
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ if (mti->foreachIDLink) {
+ mti->foreachIDLink(target, NULL, modifier_copy_data_id_us_cb, NULL);
+ }
+ else if (mti->foreachObjectLink) {
+ mti->foreachObjectLink(target, NULL, (ObjectWalkFunc)modifier_copy_data_id_us_cb, NULL);
+ }
+ }
}
void modifier_copyData(ModifierData *md, ModifierData *target)
{
- modifier_copyData_ex(md, target, 0);
+ modifier_copyData_ex(md, target, 0);
}
-
bool modifier_supportsCage(struct Scene *scene, ModifierData *md)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- return ((!mti->isDisabled || !mti->isDisabled(scene, md, 0)) &&
- (mti->flags & eModifierTypeFlag_SupportsEditmode) &&
- modifier_supportsMapping(md));
+ return ((!mti->isDisabled || !mti->isDisabled(scene, md, 0)) &&
+ (mti->flags & eModifierTypeFlag_SupportsEditmode) && modifier_supportsMapping(md));
}
bool modifier_couldBeCage(struct Scene *scene, ModifierData *md)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- return ((md->mode & eModifierMode_Realtime) &&
- (md->mode & eModifierMode_Editmode) &&
- (!mti->isDisabled || !mti->isDisabled(scene, md, 0)) &&
- modifier_supportsMapping(md));
+ return ((md->mode & eModifierMode_Realtime) && (md->mode & eModifierMode_Editmode) &&
+ (!mti->isDisabled || !mti->isDisabled(scene, md, 0)) && modifier_supportsMapping(md));
}
bool modifier_isSameTopology(ModifierData *md)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- return ELEM(mti->type, eModifierTypeType_OnlyDeform, eModifierTypeType_NonGeometrical);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ return ELEM(mti->type, eModifierTypeType_OnlyDeform, eModifierTypeType_NonGeometrical);
}
bool modifier_isNonGeometrical(ModifierData *md)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- return (mti->type == eModifierTypeType_NonGeometrical);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ return (mti->type == eModifierTypeType_NonGeometrical);
}
void modifier_setError(ModifierData *md, const char *_format, ...)
{
- char buffer[512];
- va_list ap;
- const char *format = TIP_(_format);
+ char buffer[512];
+ va_list ap;
+ const char *format = TIP_(_format);
- va_start(ap, _format);
- vsnprintf(buffer, sizeof(buffer), format, ap);
- va_end(ap);
- buffer[sizeof(buffer) - 1] = '\0';
+ va_start(ap, _format);
+ vsnprintf(buffer, sizeof(buffer), format, ap);
+ va_end(ap);
+ buffer[sizeof(buffer) - 1] = '\0';
- if (md->error)
- MEM_freeN(md->error);
+ if (md->error)
+ MEM_freeN(md->error);
- md->error = BLI_strdup(buffer);
+ md->error = BLI_strdup(buffer);
- CLOG_STR_ERROR(&LOG, md->error);
+ CLOG_STR_ERROR(&LOG, md->error);
}
/* used for buttons, to find out if the 'draw deformed in editmode' option is
@@ -396,71 +406,79 @@ void modifier_setError(ModifierData *md, const char *_format, ...)
* then is NULL)
* also used for some mesh tools to give warnings
*/
-int modifiers_getCageIndex(struct Scene *scene, Object *ob, int *r_lastPossibleCageIndex, bool is_virtual)
+int modifiers_getCageIndex(struct Scene *scene,
+ Object *ob,
+ int *r_lastPossibleCageIndex,
+ bool is_virtual)
{
- VirtualModifierData virtualModifierData;
- ModifierData *md = (is_virtual) ? modifiers_getVirtualModifierList(ob, &virtualModifierData) : ob->modifiers.first;
- int i, cageIndex = -1;
+ VirtualModifierData virtualModifierData;
+ ModifierData *md = (is_virtual) ? modifiers_getVirtualModifierList(ob, &virtualModifierData) :
+ ob->modifiers.first;
+ int i, cageIndex = -1;
- if (r_lastPossibleCageIndex) {
- /* ensure the value is initialized */
- *r_lastPossibleCageIndex = -1;
- }
+ if (r_lastPossibleCageIndex) {
+ /* ensure the value is initialized */
+ *r_lastPossibleCageIndex = -1;
+ }
- /* Find the last modifier acting on the cage. */
- for (i = 0; md; i++, md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- bool supports_mapping;
+ /* Find the last modifier acting on the cage. */
+ for (i = 0; md; i++, md = md->next) {
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ bool supports_mapping;
- if (mti->isDisabled && mti->isDisabled(scene, md, 0)) continue;
- if (!(mti->flags & eModifierTypeFlag_SupportsEditmode)) continue;
- if (md->mode & eModifierMode_DisableTemporary) continue;
+ if (mti->isDisabled && mti->isDisabled(scene, md, 0))
+ continue;
+ if (!(mti->flags & eModifierTypeFlag_SupportsEditmode))
+ continue;
+ if (md->mode & eModifierMode_DisableTemporary)
+ continue;
- supports_mapping = modifier_supportsMapping(md);
- if (r_lastPossibleCageIndex && supports_mapping) {
- *r_lastPossibleCageIndex = i;
- }
+ supports_mapping = modifier_supportsMapping(md);
+ if (r_lastPossibleCageIndex && supports_mapping) {
+ *r_lastPossibleCageIndex = i;
+ }
- if (!(md->mode & eModifierMode_Realtime)) continue;
- if (!(md->mode & eModifierMode_Editmode)) continue;
+ if (!(md->mode & eModifierMode_Realtime))
+ continue;
+ if (!(md->mode & eModifierMode_Editmode))
+ continue;
- if (!supports_mapping)
- break;
+ if (!supports_mapping)
+ break;
- if (md->mode & eModifierMode_OnCage)
- cageIndex = i;
- }
+ if (md->mode & eModifierMode_OnCage)
+ cageIndex = i;
+ }
- return cageIndex;
+ return cageIndex;
}
-
bool modifiers_isSoftbodyEnabled(Object *ob)
{
- ModifierData *md = modifiers_findByType(ob, eModifierType_Softbody);
+ ModifierData *md = modifiers_findByType(ob, eModifierType_Softbody);
- return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render));
+ return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render));
}
bool modifiers_isClothEnabled(Object *ob)
{
- ModifierData *md = modifiers_findByType(ob, eModifierType_Cloth);
+ ModifierData *md = modifiers_findByType(ob, eModifierType_Cloth);
- return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render));
+ return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render));
}
bool modifiers_isModifierEnabled(Object *ob, int modifierType)
{
- ModifierData *md = modifiers_findByType(ob, modifierType);
+ ModifierData *md = modifiers_findByType(ob, modifierType);
- return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render));
+ return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render));
}
bool modifiers_isParticleEnabled(Object *ob)
{
- ModifierData *md = modifiers_findByType(ob, eModifierType_ParticleSystem);
+ ModifierData *md = modifiers_findByType(ob, eModifierType_ParticleSystem);
- return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render));
+ return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render));
}
/**
@@ -470,122 +488,133 @@ bool modifiers_isParticleEnabled(Object *ob)
*/
bool modifier_isEnabled(const struct Scene *scene, ModifierData *md, int required_mode)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
-
- if ((md->mode & required_mode) != required_mode) return false;
- if (scene != NULL && mti->isDisabled && mti->isDisabled(scene, md, required_mode == eModifierMode_Render)) return false;
- if (md->mode & eModifierMode_DisableTemporary) return false;
- if ((required_mode & eModifierMode_Editmode) && !(mti->flags & eModifierTypeFlag_SupportsEditmode)) return false;
-
- return true;
-}
-
-CDMaskLink *modifiers_calcDataMasks(struct Scene *scene, Object *ob, ModifierData *md,
- const CustomData_MeshMasks *dataMask, int required_mode,
- ModifierData *previewmd, const CustomData_MeshMasks *previewmask)
-{
- CDMaskLink *dataMasks = NULL;
- CDMaskLink *curr, *prev;
-
- /* build a list of modifier data requirements in reverse order */
- for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
-
- curr = MEM_callocN(sizeof(CDMaskLink), "CDMaskLink");
-
- if (modifier_isEnabled(scene, md, required_mode)) {
- if (mti->requiredDataMask)
- mti->requiredDataMask(ob, md, &curr->mask);
-
- if (previewmd == md && previewmask != NULL) {
- CustomData_MeshMasks_update(&curr->mask, previewmask);
- }
- }
-
- /* prepend new datamask */
- curr->next = dataMasks;
- dataMasks = curr;
- }
-
- /* build the list of required data masks - each mask in the list must
- * include all elements of the masks that follow it
- *
- * note the list is currently in reverse order, so "masks that follow it"
- * actually means "masks that precede it" at the moment
- */
- for (curr = dataMasks, prev = NULL; curr; prev = curr, curr = curr->next) {
- if (prev) {
- CustomData_MeshMasks_update(&curr->mask, &prev->mask);
- }
- else {
- CustomData_MeshMasks_update(&curr->mask, dataMask);
- }
- }
-
- /* reverse the list so it's in the correct order */
- BLI_linklist_reverse((LinkNode **)&dataMasks);
-
- return dataMasks;
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if ((md->mode & required_mode) != required_mode)
+ return false;
+ if (scene != NULL && mti->isDisabled &&
+ mti->isDisabled(scene, md, required_mode == eModifierMode_Render))
+ return false;
+ if (md->mode & eModifierMode_DisableTemporary)
+ return false;
+ if ((required_mode & eModifierMode_Editmode) &&
+ !(mti->flags & eModifierTypeFlag_SupportsEditmode))
+ return false;
+
+ return true;
+}
+
+CDMaskLink *modifiers_calcDataMasks(struct Scene *scene,
+ Object *ob,
+ ModifierData *md,
+ const CustomData_MeshMasks *dataMask,
+ int required_mode,
+ ModifierData *previewmd,
+ const CustomData_MeshMasks *previewmask)
+{
+ CDMaskLink *dataMasks = NULL;
+ CDMaskLink *curr, *prev;
+
+ /* build a list of modifier data requirements in reverse order */
+ for (; md; md = md->next) {
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ curr = MEM_callocN(sizeof(CDMaskLink), "CDMaskLink");
+
+ if (modifier_isEnabled(scene, md, required_mode)) {
+ if (mti->requiredDataMask)
+ mti->requiredDataMask(ob, md, &curr->mask);
+
+ if (previewmd == md && previewmask != NULL) {
+ CustomData_MeshMasks_update(&curr->mask, previewmask);
+ }
+ }
+
+ /* prepend new datamask */
+ curr->next = dataMasks;
+ dataMasks = curr;
+ }
+
+ /* build the list of required data masks - each mask in the list must
+ * include all elements of the masks that follow it
+ *
+ * note the list is currently in reverse order, so "masks that follow it"
+ * actually means "masks that precede it" at the moment
+ */
+ for (curr = dataMasks, prev = NULL; curr; prev = curr, curr = curr->next) {
+ if (prev) {
+ CustomData_MeshMasks_update(&curr->mask, &prev->mask);
+ }
+ else {
+ CustomData_MeshMasks_update(&curr->mask, dataMask);
+ }
+ }
+
+ /* reverse the list so it's in the correct order */
+ BLI_linklist_reverse((LinkNode **)&dataMasks);
+
+ return dataMasks;
}
ModifierData *modifiers_getLastPreview(struct Scene *scene, ModifierData *md, int required_mode)
{
- ModifierData *tmp_md = NULL;
+ ModifierData *tmp_md = NULL;
- if ((required_mode & ~eModifierMode_Editmode) != eModifierMode_Realtime)
- return tmp_md;
+ if ((required_mode & ~eModifierMode_Editmode) != eModifierMode_Realtime)
+ return tmp_md;
- /* Find the latest modifier in stack generating preview. */
- for (; md; md = md->next) {
- if (modifier_isEnabled(scene, md, required_mode) && modifier_isPreview(md))
- tmp_md = md;
- }
- return tmp_md;
+ /* Find the latest modifier in stack generating preview. */
+ for (; md; md = md->next) {
+ if (modifier_isEnabled(scene, md, required_mode) && modifier_isPreview(md))
+ tmp_md = md;
+ }
+ return tmp_md;
}
/* NOTE: This is to support old files from before Blender supported modifiers,
* in some cases versioning code updates these so for new files this will
* return an empty list. */
-ModifierData *modifiers_getVirtualModifierList(Object *ob, VirtualModifierData *virtualModifierData)
-{
- ModifierData *md;
-
- md = ob->modifiers.first;
-
- *virtualModifierData = virtualModifierCommonData;
-
- if (ob->parent) {
- if (ob->parent->type == OB_ARMATURE && ob->partype == PARSKEL) {
- virtualModifierData->amd.object = ob->parent;
- virtualModifierData->amd.modifier.next = md;
- virtualModifierData->amd.deformflag = ((bArmature *)(ob->parent->data))->deformflag;
- md = &virtualModifierData->amd.modifier;
- }
- else if (ob->parent->type == OB_CURVE && ob->partype == PARSKEL) {
- virtualModifierData->cmd.object = ob->parent;
- virtualModifierData->cmd.defaxis = ob->trackflag + 1;
- virtualModifierData->cmd.modifier.next = md;
- md = &virtualModifierData->cmd.modifier;
- }
- else if (ob->parent->type == OB_LATTICE && ob->partype == PARSKEL) {
- virtualModifierData->lmd.object = ob->parent;
- virtualModifierData->lmd.modifier.next = md;
- md = &virtualModifierData->lmd.modifier;
- }
- }
-
- /* shape key modifier, not yet for curves */
- if (ELEM(ob->type, OB_MESH, OB_LATTICE) && BKE_key_from_object(ob)) {
- if (ob->type == OB_MESH && (ob->shapeflag & OB_SHAPE_EDIT_MODE))
- virtualModifierData->smd.modifier.mode |= eModifierMode_Editmode | eModifierMode_OnCage;
- else
- virtualModifierData->smd.modifier.mode &= ~eModifierMode_Editmode | eModifierMode_OnCage;
-
- virtualModifierData->smd.modifier.next = md;
- md = &virtualModifierData->smd.modifier;
- }
-
- return md;
+ModifierData *modifiers_getVirtualModifierList(Object *ob,
+ VirtualModifierData *virtualModifierData)
+{
+ ModifierData *md;
+
+ md = ob->modifiers.first;
+
+ *virtualModifierData = virtualModifierCommonData;
+
+ if (ob->parent) {
+ if (ob->parent->type == OB_ARMATURE && ob->partype == PARSKEL) {
+ virtualModifierData->amd.object = ob->parent;
+ virtualModifierData->amd.modifier.next = md;
+ virtualModifierData->amd.deformflag = ((bArmature *)(ob->parent->data))->deformflag;
+ md = &virtualModifierData->amd.modifier;
+ }
+ else if (ob->parent->type == OB_CURVE && ob->partype == PARSKEL) {
+ virtualModifierData->cmd.object = ob->parent;
+ virtualModifierData->cmd.defaxis = ob->trackflag + 1;
+ virtualModifierData->cmd.modifier.next = md;
+ md = &virtualModifierData->cmd.modifier;
+ }
+ else if (ob->parent->type == OB_LATTICE && ob->partype == PARSKEL) {
+ virtualModifierData->lmd.object = ob->parent;
+ virtualModifierData->lmd.modifier.next = md;
+ md = &virtualModifierData->lmd.modifier;
+ }
+ }
+
+ /* shape key modifier, not yet for curves */
+ if (ELEM(ob->type, OB_MESH, OB_LATTICE) && BKE_key_from_object(ob)) {
+ if (ob->type == OB_MESH && (ob->shapeflag & OB_SHAPE_EDIT_MODE))
+ virtualModifierData->smd.modifier.mode |= eModifierMode_Editmode | eModifierMode_OnCage;
+ else
+ virtualModifierData->smd.modifier.mode &= ~eModifierMode_Editmode | eModifierMode_OnCage;
+
+ virtualModifierData->smd.modifier.next = md;
+ md = &virtualModifierData->smd.modifier;
+ }
+
+ return md;
}
/* Takes an object and returns its first selected armature, else just its armature
@@ -593,44 +622,44 @@ ModifierData *modifiers_getVirtualModifierList(Object *ob, VirtualModifierData *
*/
Object *modifiers_isDeformedByArmature(Object *ob)
{
- VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
- ArmatureModifierData *amd = NULL;
+ VirtualModifierData virtualModifierData;
+ ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ ArmatureModifierData *amd = NULL;
- /* return the first selected armature, this lets us use multiple armatures */
- for (; md; md = md->next) {
- if (md->type == eModifierType_Armature) {
- amd = (ArmatureModifierData *) md;
- if (amd->object && (amd->object->flag & SELECT))
- return amd->object;
- }
- }
+ /* return the first selected armature, this lets us use multiple armatures */
+ for (; md; md = md->next) {
+ if (md->type == eModifierType_Armature) {
+ amd = (ArmatureModifierData *)md;
+ if (amd->object && (amd->object->flag & SELECT))
+ return amd->object;
+ }
+ }
- if (amd) /* if were still here then return the last armature */
- return amd->object;
+ if (amd) /* if were still here then return the last armature */
+ return amd->object;
- return NULL;
+ return NULL;
}
Object *modifiers_isDeformedByMeshDeform(Object *ob)
{
- VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
- MeshDeformModifierData *mdmd = NULL;
+ VirtualModifierData virtualModifierData;
+ ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ MeshDeformModifierData *mdmd = NULL;
- /* return the first selected armature, this lets us use multiple armatures */
- for (; md; md = md->next) {
- if (md->type == eModifierType_MeshDeform) {
- mdmd = (MeshDeformModifierData *) md;
- if (mdmd->object && (mdmd->object->flag & SELECT))
- return mdmd->object;
- }
- }
+ /* return the first selected armature, this lets us use multiple armatures */
+ for (; md; md = md->next) {
+ if (md->type == eModifierType_MeshDeform) {
+ mdmd = (MeshDeformModifierData *)md;
+ if (mdmd->object && (mdmd->object->flag & SELECT))
+ return mdmd->object;
+ }
+ }
- if (mdmd) /* if were still here then return the last armature */
- return mdmd->object;
+ if (mdmd) /* if were still here then return the last armature */
+ return mdmd->object;
- return NULL;
+ return NULL;
}
/* Takes an object and returns its first selected lattice, else just its lattice
@@ -638,23 +667,23 @@ Object *modifiers_isDeformedByMeshDeform(Object *ob)
*/
Object *modifiers_isDeformedByLattice(Object *ob)
{
- VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
- LatticeModifierData *lmd = NULL;
+ VirtualModifierData virtualModifierData;
+ ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ LatticeModifierData *lmd = NULL;
- /* return the first selected lattice, this lets us use multiple lattices */
- for (; md; md = md->next) {
- if (md->type == eModifierType_Lattice) {
- lmd = (LatticeModifierData *) md;
- if (lmd->object && (lmd->object->flag & SELECT))
- return lmd->object;
- }
- }
+ /* return the first selected lattice, this lets us use multiple lattices */
+ for (; md; md = md->next) {
+ if (md->type == eModifierType_Lattice) {
+ lmd = (LatticeModifierData *)md;
+ if (lmd->object && (lmd->object->flag & SELECT))
+ return lmd->object;
+ }
+ }
- if (lmd) /* if were still here then return the last lattice */
- return lmd->object;
+ if (lmd) /* if were still here then return the last lattice */
+ return lmd->object;
- return NULL;
+ return NULL;
}
/* Takes an object and returns its first selected curve, else just its curve
@@ -662,110 +691,111 @@ Object *modifiers_isDeformedByLattice(Object *ob)
*/
Object *modifiers_isDeformedByCurve(Object *ob)
{
- VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
- CurveModifierData *cmd = NULL;
+ VirtualModifierData virtualModifierData;
+ ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ CurveModifierData *cmd = NULL;
- /* return the first selected curve, this lets us use multiple curves */
- for (; md; md = md->next) {
- if (md->type == eModifierType_Curve) {
- cmd = (CurveModifierData *) md;
- if (cmd->object && (cmd->object->flag & SELECT))
- return cmd->object;
- }
- }
+ /* return the first selected curve, this lets us use multiple curves */
+ for (; md; md = md->next) {
+ if (md->type == eModifierType_Curve) {
+ cmd = (CurveModifierData *)md;
+ if (cmd->object && (cmd->object->flag & SELECT))
+ return cmd->object;
+ }
+ }
- if (cmd) /* if were still here then return the last curve */
- return cmd->object;
+ if (cmd) /* if were still here then return the last curve */
+ return cmd->object;
- return NULL;
+ return NULL;
}
bool modifiers_usesArmature(Object *ob, bArmature *arm)
{
- VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ VirtualModifierData virtualModifierData;
+ ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
- for (; md; md = md->next) {
- if (md->type == eModifierType_Armature) {
- ArmatureModifierData *amd = (ArmatureModifierData *) md;
- if (amd->object && amd->object->data == arm)
- return true;
- }
- }
+ for (; md; md = md->next) {
+ if (md->type == eModifierType_Armature) {
+ ArmatureModifierData *amd = (ArmatureModifierData *)md;
+ if (amd->object && amd->object->data == arm)
+ return true;
+ }
+ }
- return false;
+ return false;
}
bool modifier_isCorrectableDeformed(ModifierData *md)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- return mti->deformMatricesEM != NULL;
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ return mti->deformMatricesEM != NULL;
}
bool modifiers_isCorrectableDeformed(struct Scene *scene, Object *ob)
{
- VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
- int required_mode = eModifierMode_Realtime;
+ VirtualModifierData virtualModifierData;
+ ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ int required_mode = eModifierMode_Realtime;
- if (ob->mode == OB_MODE_EDIT) {
- required_mode |= eModifierMode_Editmode;
- }
- for (; md; md = md->next) {
- if (!modifier_isEnabled(scene, md, required_mode)) {
- /* pass */
- }
- else if (modifier_isCorrectableDeformed(md)) {
- return true;
- }
- }
- return false;
+ if (ob->mode == OB_MODE_EDIT) {
+ required_mode |= eModifierMode_Editmode;
+ }
+ for (; md; md = md->next) {
+ if (!modifier_isEnabled(scene, md, required_mode)) {
+ /* pass */
+ }
+ else if (modifier_isCorrectableDeformed(md)) {
+ return true;
+ }
+ }
+ return false;
}
/* Check whether the given object has a modifier in its stack that uses WEIGHT_MCOL CD layer
* to preview something... Used by DynamicPaint and WeightVG currently. */
bool modifiers_isPreview(Object *ob)
{
- ModifierData *md = ob->modifiers.first;
+ ModifierData *md = ob->modifiers.first;
- for (; md; md = md->next) {
- if (modifier_isPreview(md))
- return true;
- }
+ for (; md; md = md->next) {
+ if (modifier_isPreview(md))
+ return true;
+ }
- return false;
+ return false;
}
void modifier_freeTemporaryData(ModifierData *md)
{
- if (md->type == eModifierType_Armature) {
- ArmatureModifierData *amd = (ArmatureModifierData *)md;
+ if (md->type == eModifierType_Armature) {
+ ArmatureModifierData *amd = (ArmatureModifierData *)md;
- if (amd->prevCos) {
- MEM_freeN(amd->prevCos);
- amd->prevCos = NULL;
- }
- }
+ if (amd->prevCos) {
+ MEM_freeN(amd->prevCos);
+ amd->prevCos = NULL;
+ }
+ }
}
/* ensure modifier correctness when changing ob->data */
void test_object_modifiers(Object *ob)
{
- ModifierData *md;
+ ModifierData *md;
- /* just multires checked for now, since only multires
- * modifies mesh data */
+ /* just multires checked for now, since only multires
+ * modifies mesh data */
- if (ob->type != OB_MESH) return;
+ if (ob->type != OB_MESH)
+ return;
- for (md = ob->modifiers.first; md; md = md->next) {
- if (md->type == eModifierType_Multires) {
- MultiresModifierData *mmd = (MultiresModifierData *)md;
+ for (md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_Multires) {
+ MultiresModifierData *mmd = (MultiresModifierData *)md;
- multiresModifier_set_levels_from_disps(mmd, ob);
- }
- }
+ multiresModifier_set_levels_from_disps(mmd, ob);
+ }
+ }
}
/* where should this go?, it doesn't fit well anywhere :S - campbell */
@@ -781,84 +811,84 @@ void test_object_modifiers(Object *ob)
*/
const char *modifier_path_relbase(Main *bmain, Object *ob)
{
- if (G.relbase_valid || ID_IS_LINKED(ob)) {
- return ID_BLEND_PATH(bmain, &ob->id);
- }
- else {
- /* last resort, better then using "" which resolves to the current
- * working directory */
- return BKE_tempdir_session();
- }
+ if (G.relbase_valid || ID_IS_LINKED(ob)) {
+ return ID_BLEND_PATH(bmain, &ob->id);
+ }
+ else {
+ /* last resort, better then using "" which resolves to the current
+ * working directory */
+ return BKE_tempdir_session();
+ }
}
const char *modifier_path_relbase_from_global(Object *ob)
{
- if (G.relbase_valid || ID_IS_LINKED(ob)) {
- return ID_BLEND_PATH_FROM_GLOBAL(&ob->id);
- }
- else {
- /* last resort, better then using "" which resolves to the current
- * working directory */
- return BKE_tempdir_session();
- }
+ if (G.relbase_valid || ID_IS_LINKED(ob)) {
+ return ID_BLEND_PATH_FROM_GLOBAL(&ob->id);
+ }
+ else {
+ /* last resort, better then using "" which resolves to the current
+ * working directory */
+ return BKE_tempdir_session();
+ }
}
/* initializes the path with either */
void modifier_path_init(char *path, int path_maxlen, const char *name)
{
- /* elubie: changed this to default to the same dir as the render output
- * to prevent saving to C:\ on Windows */
- BLI_join_dirfile(path, path_maxlen,
- G.relbase_valid ? "//" : BKE_tempdir_session(),
- name);
+ /* elubie: changed this to default to the same dir as the render output
+ * to prevent saving to C:\ on Windows */
+ BLI_join_dirfile(path, path_maxlen, G.relbase_valid ? "//" : BKE_tempdir_session(), name);
}
-
/* wrapper around ModifierTypeInfo.applyModifier that ensures valid normals */
-struct Mesh *modwrap_applyModifier(
- ModifierData *md, const ModifierEvalContext *ctx,
- struct Mesh *me)
+struct Mesh *modwrap_applyModifier(ModifierData *md,
+ const ModifierEvalContext *ctx,
+ struct Mesh *me)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- BLI_assert(CustomData_has_layer(&me->pdata, CD_NORMAL) == false);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ BLI_assert(CustomData_has_layer(&me->pdata, CD_NORMAL) == false);
- if (mti->dependsOnNormals && mti->dependsOnNormals(md)) {
- BKE_mesh_calc_normals(me);
- }
- return mti->applyModifier(md, ctx, me);
+ if (mti->dependsOnNormals && mti->dependsOnNormals(md)) {
+ BKE_mesh_calc_normals(me);
+ }
+ return mti->applyModifier(md, ctx, me);
}
-void modwrap_deformVerts(
- ModifierData *md, const ModifierEvalContext *ctx,
- Mesh *me, float (*vertexCos)[3], int numVerts)
+void modwrap_deformVerts(ModifierData *md,
+ const ModifierEvalContext *ctx,
+ Mesh *me,
+ float (*vertexCos)[3],
+ int numVerts)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- BLI_assert(!me || CustomData_has_layer(&me->pdata, CD_NORMAL) == false);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ BLI_assert(!me || CustomData_has_layer(&me->pdata, CD_NORMAL) == false);
- if (me && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
- BKE_mesh_calc_normals(me);
- }
- mti->deformVerts(md, ctx, me, vertexCos, numVerts);
+ if (me && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
+ BKE_mesh_calc_normals(me);
+ }
+ mti->deformVerts(md, ctx, me, vertexCos, numVerts);
}
-void modwrap_deformVertsEM(
- ModifierData *md, const ModifierEvalContext *ctx,
- struct BMEditMesh *em, Mesh *me,
- float (*vertexCos)[3], int numVerts)
+void modwrap_deformVertsEM(ModifierData *md,
+ const ModifierEvalContext *ctx,
+ struct BMEditMesh *em,
+ Mesh *me,
+ float (*vertexCos)[3],
+ int numVerts)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- BLI_assert(!me || CustomData_has_layer(&me->pdata, CD_NORMAL) == false);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ BLI_assert(!me || CustomData_has_layer(&me->pdata, CD_NORMAL) == false);
- if (me && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
- BKE_mesh_calc_normals(me);
- }
- mti->deformVertsEM(md, ctx, em, me, vertexCos, numVerts);
+ if (me && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
+ BKE_mesh_calc_normals(me);
+ }
+ mti->deformVertsEM(md, ctx, em, me, vertexCos, numVerts);
}
/* end modifier callback wrappers */
-
/**
* Get evaluated mesh for other evaluated object, which is used as an operand for the modifier,
* e.g. second operand for boolean modifier.
@@ -867,41 +897,42 @@ void modwrap_deformVertsEM(
* \param get_cage_mesh Return evaluated mesh with only deforming modifiers applied
* (i.e. mesh topology remains the same as original one, a.k.a. 'cage' mesh).
*/
-Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object(Object *ob_eval, const bool get_cage_mesh)
+Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object(Object *ob_eval,
+ const bool get_cage_mesh)
{
- Mesh *me = NULL;
+ Mesh *me = NULL;
- if ((ob_eval->type == OB_MESH) && (ob_eval->mode & OB_MODE_EDIT)) {
- /* In EditMode, evaluated mesh is stored in BMEditMesh, not the object... */
- BMEditMesh *em = BKE_editmesh_from_object(ob_eval);
- if (em != NULL) { /* em might not exist yet in some cases, just after loading a .blend file, see T57878. */
- me = (get_cage_mesh && em->mesh_eval_cage != NULL) ? em->mesh_eval_cage : em->mesh_eval_final;
- }
- }
- if (me == NULL) {
- me = (get_cage_mesh && ob_eval->runtime.mesh_deform_eval != NULL) ? ob_eval->runtime.mesh_deform_eval :
- ob_eval->runtime.mesh_eval;
- }
+ if ((ob_eval->type == OB_MESH) && (ob_eval->mode & OB_MODE_EDIT)) {
+ /* In EditMode, evaluated mesh is stored in BMEditMesh, not the object... */
+ BMEditMesh *em = BKE_editmesh_from_object(ob_eval);
+ if (em !=
+ NULL) { /* em might not exist yet in some cases, just after loading a .blend file, see T57878. */
+ me = (get_cage_mesh && em->mesh_eval_cage != NULL) ? em->mesh_eval_cage :
+ em->mesh_eval_final;
+ }
+ }
+ if (me == NULL) {
+ me = (get_cage_mesh && ob_eval->runtime.mesh_deform_eval != NULL) ?
+ ob_eval->runtime.mesh_deform_eval :
+ ob_eval->runtime.mesh_eval;
+ }
- return me;
+ return me;
}
ModifierData *modifier_get_original(ModifierData *md)
{
- if (md->orig_modifier_data == NULL) {
- return md;
- }
- return md->orig_modifier_data;
+ if (md->orig_modifier_data == NULL) {
+ return md;
+ }
+ return md->orig_modifier_data;
}
-struct ModifierData *modifier_get_evaluated(
- Depsgraph *depsgraph,
- Object *object,
- ModifierData *md)
+struct ModifierData *modifier_get_evaluated(Depsgraph *depsgraph, Object *object, ModifierData *md)
{
- Object *object_eval = DEG_get_evaluated_object(depsgraph, object);
- if (object_eval == object) {
- return md;
- }
- return modifiers_findByName(object_eval, md->name);
+ Object *object_eval = DEG_get_evaluated_object(depsgraph, object);
+ if (object_eval == object) {
+ return md;
+ }
+ return modifiers_findByName(object_eval, md->name);
}
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index 1c056c9b652..51f7fd2208c 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -21,7 +21,6 @@
* \ingroup bke
*/
-
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
@@ -58,7 +57,7 @@
#include "BKE_main.h"
#include "BKE_movieclip.h"
#include "BKE_node.h"
-#include "BKE_image.h" /* openanim */
+#include "BKE_image.h" /* openanim */
#include "BKE_tracking.h"
#include "IMB_imbuf_types.h"
@@ -76,181 +75,167 @@
static int sequence_guess_offset(const char *full_name, int head_len, unsigned short numlen)
{
- char num[FILE_MAX] = {0};
+ char num[FILE_MAX] = {0};
- BLI_strncpy(num, full_name + head_len, numlen + 1);
+ BLI_strncpy(num, full_name + head_len, numlen + 1);
- return atoi(num);
+ return atoi(num);
}
static int rendersize_to_proxy(const MovieClipUser *user, int flag)
{
- if ((flag & MCLIP_USE_PROXY) == 0)
- return IMB_PROXY_NONE;
+ if ((flag & MCLIP_USE_PROXY) == 0)
+ return IMB_PROXY_NONE;
- switch (user->render_size) {
- case MCLIP_PROXY_RENDER_SIZE_25:
- return IMB_PROXY_25;
+ switch (user->render_size) {
+ case MCLIP_PROXY_RENDER_SIZE_25:
+ return IMB_PROXY_25;
- case MCLIP_PROXY_RENDER_SIZE_50:
- return IMB_PROXY_50;
+ case MCLIP_PROXY_RENDER_SIZE_50:
+ return IMB_PROXY_50;
- case MCLIP_PROXY_RENDER_SIZE_75:
- return IMB_PROXY_75;
+ case MCLIP_PROXY_RENDER_SIZE_75:
+ return IMB_PROXY_75;
- case MCLIP_PROXY_RENDER_SIZE_100:
- return IMB_PROXY_100;
+ case MCLIP_PROXY_RENDER_SIZE_100:
+ return IMB_PROXY_100;
- case MCLIP_PROXY_RENDER_SIZE_FULL:
- return IMB_PROXY_NONE;
- }
+ case MCLIP_PROXY_RENDER_SIZE_FULL:
+ return IMB_PROXY_NONE;
+ }
- return IMB_PROXY_NONE;
+ return IMB_PROXY_NONE;
}
static int rendersize_to_number(int render_size)
{
- switch (render_size) {
- case MCLIP_PROXY_RENDER_SIZE_25:
- return 25;
+ switch (render_size) {
+ case MCLIP_PROXY_RENDER_SIZE_25:
+ return 25;
- case MCLIP_PROXY_RENDER_SIZE_50:
- return 50;
+ case MCLIP_PROXY_RENDER_SIZE_50:
+ return 50;
- case MCLIP_PROXY_RENDER_SIZE_75:
- return 75;
+ case MCLIP_PROXY_RENDER_SIZE_75:
+ return 75;
- case MCLIP_PROXY_RENDER_SIZE_100:
- return 100;
+ case MCLIP_PROXY_RENDER_SIZE_100:
+ return 100;
- case MCLIP_PROXY_RENDER_SIZE_FULL:
- return 100;
- }
+ case MCLIP_PROXY_RENDER_SIZE_FULL:
+ return 100;
+ }
- return 100;
+ return 100;
}
static int get_timecode(MovieClip *clip, int flag)
{
- if ((flag & MCLIP_USE_PROXY) == 0)
- return IMB_TC_NONE;
+ if ((flag & MCLIP_USE_PROXY) == 0)
+ return IMB_TC_NONE;
- return clip->proxy.tc;
+ return clip->proxy.tc;
}
-static void get_sequence_fname(const MovieClip *clip,
- const int framenr,
- char *name)
+static void get_sequence_fname(const MovieClip *clip, const int framenr, char *name)
{
- unsigned short numlen;
- char head[FILE_MAX], tail[FILE_MAX];
- int offset;
+ unsigned short numlen;
+ char head[FILE_MAX], tail[FILE_MAX];
+ int offset;
- BLI_strncpy(name, clip->name, sizeof(clip->name));
- BLI_stringdec(name, head, tail, &numlen);
+ BLI_strncpy(name, clip->name, sizeof(clip->name));
+ BLI_stringdec(name, head, tail, &numlen);
- /* movieclips always points to first image from sequence,
- * autoguess offset for now. could be something smarter in the future
- */
- offset = sequence_guess_offset(clip->name, strlen(head), numlen);
+ /* movieclips always points to first image from sequence,
+ * autoguess offset for now. could be something smarter in the future
+ */
+ offset = sequence_guess_offset(clip->name, strlen(head), numlen);
- if (numlen) {
- BLI_stringenc(name,
- head, tail,
- numlen,
- offset + framenr - clip->start_frame + clip->frame_offset);
- }
- else {
- BLI_strncpy(name, clip->name, sizeof(clip->name));
- }
+ if (numlen) {
+ BLI_stringenc(
+ name, head, tail, numlen, offset + framenr - clip->start_frame + clip->frame_offset);
+ }
+ else {
+ BLI_strncpy(name, clip->name, sizeof(clip->name));
+ }
- BLI_path_abs(name, ID_BLEND_PATH_FROM_GLOBAL(&clip->id));
+ BLI_path_abs(name, ID_BLEND_PATH_FROM_GLOBAL(&clip->id));
}
/* supposed to work with sequences only */
-static void get_proxy_fname(const MovieClip *clip,
- int proxy_render_size,
- bool undistorted,
- int framenr,
- char *name)
+static void get_proxy_fname(
+ const MovieClip *clip, int proxy_render_size, bool undistorted, int framenr, char *name)
{
- int size = rendersize_to_number(proxy_render_size);
- char dir[FILE_MAX], clipdir[FILE_MAX], clipfile[FILE_MAX];
- int proxynr = framenr - clip->start_frame + 1 + clip->frame_offset;
+ int size = rendersize_to_number(proxy_render_size);
+ char dir[FILE_MAX], clipdir[FILE_MAX], clipfile[FILE_MAX];
+ int proxynr = framenr - clip->start_frame + 1 + clip->frame_offset;
- BLI_split_dirfile(clip->name, clipdir, clipfile, FILE_MAX, FILE_MAX);
+ BLI_split_dirfile(clip->name, clipdir, clipfile, FILE_MAX, FILE_MAX);
- if (clip->flag & MCLIP_USE_PROXY_CUSTOM_DIR) {
- BLI_strncpy(dir, clip->proxy.dir, sizeof(dir));
- }
- else {
- BLI_snprintf(dir, FILE_MAX, "%s/BL_proxy", clipdir);
- }
+ if (clip->flag & MCLIP_USE_PROXY_CUSTOM_DIR) {
+ BLI_strncpy(dir, clip->proxy.dir, sizeof(dir));
+ }
+ else {
+ BLI_snprintf(dir, FILE_MAX, "%s/BL_proxy", clipdir);
+ }
- if (undistorted)
- BLI_snprintf(name, FILE_MAX, "%s/%s/proxy_%d_undistorted/%08d", dir, clipfile, size, proxynr);
- else
- BLI_snprintf(name, FILE_MAX, "%s/%s/proxy_%d/%08d", dir, clipfile, size, proxynr);
+ if (undistorted)
+ BLI_snprintf(name, FILE_MAX, "%s/%s/proxy_%d_undistorted/%08d", dir, clipfile, size, proxynr);
+ else
+ BLI_snprintf(name, FILE_MAX, "%s/%s/proxy_%d/%08d", dir, clipfile, size, proxynr);
- BLI_path_abs(name, BKE_main_blendfile_path_from_global());
- BLI_path_frame(name, 1, 0);
+ BLI_path_abs(name, BKE_main_blendfile_path_from_global());
+ BLI_path_frame(name, 1, 0);
- strcat(name, ".jpg");
+ strcat(name, ".jpg");
}
#ifdef WITH_OPENEXR
typedef struct MultilayerConvertContext {
- float *combined_pass;
- int num_combined_channels;
+ float *combined_pass;
+ int num_combined_channels;
} MultilayerConvertContext;
-static void *movieclip_convert_multilayer_add_view(
- void *UNUSED(ctx_v),
- const char *UNUSED(view_name))
-{
- return NULL;
-}
-
-static void *movieclip_convert_multilayer_add_layer(
- void *ctx_v,
- const char *UNUSED(layer_name))
-{
- /* Return dummy non-NULL value, we don't use layer handle but need to return
- * something, so render API invokes the add_pass() callbacks. */
- return ctx_v;
-}
-
-static void movieclip_convert_multilayer_add_pass(
- void *UNUSED(layer),
- void *ctx_v,
- const char *pass_name,
- float *rect,
- int num_channels,
- const char *chan_id,
- const char *UNUSED(view_name))
-{
- /* NOTE: This function must free pass pixels data if it is not used, this
- * is how IMB_exr_multilayer_convert() is working. */
- MultilayerConvertContext *ctx = ctx_v;
- /* If we've found a first combined pass, skip all the rest ones. */
- if (ctx->combined_pass != NULL) {
- MEM_freeN(rect);
- return;
- }
- if (STREQ(pass_name, RE_PASSNAME_COMBINED) ||
- STREQ(chan_id, "RGBA") ||
- STREQ(chan_id, "RGB"))
- {
- ctx->combined_pass = rect;
- ctx->num_combined_channels = num_channels;
- }
- else {
- MEM_freeN(rect);
- }
-}
-
-#endif /* WITH_OPENEXR */
+static void *movieclip_convert_multilayer_add_view(void *UNUSED(ctx_v),
+ const char *UNUSED(view_name))
+{
+ return NULL;
+}
+
+static void *movieclip_convert_multilayer_add_layer(void *ctx_v, const char *UNUSED(layer_name))
+{
+ /* Return dummy non-NULL value, we don't use layer handle but need to return
+ * something, so render API invokes the add_pass() callbacks. */
+ return ctx_v;
+}
+
+static void movieclip_convert_multilayer_add_pass(void *UNUSED(layer),
+ void *ctx_v,
+ const char *pass_name,
+ float *rect,
+ int num_channels,
+ const char *chan_id,
+ const char *UNUSED(view_name))
+{
+ /* NOTE: This function must free pass pixels data if it is not used, this
+ * is how IMB_exr_multilayer_convert() is working. */
+ MultilayerConvertContext *ctx = ctx_v;
+ /* If we've found a first combined pass, skip all the rest ones. */
+ if (ctx->combined_pass != NULL) {
+ MEM_freeN(rect);
+ return;
+ }
+ if (STREQ(pass_name, RE_PASSNAME_COMBINED) || STREQ(chan_id, "RGBA") || STREQ(chan_id, "RGB")) {
+ ctx->combined_pass = rect;
+ ctx->num_combined_channels = num_channels;
+ }
+ else {
+ MEM_freeN(rect);
+ }
+}
+
+#endif /* WITH_OPENEXR */
/* Will try to make image buffer usable when originating from the multi-layer
* source.
@@ -258,31 +243,30 @@ static void movieclip_convert_multilayer_add_pass(
* but is better than a complete empty buffer. */
void BKE_movieclip_convert_multilayer_ibuf(struct ImBuf *ibuf)
{
- if (ibuf == NULL) {
- return;
- }
+ if (ibuf == NULL) {
+ return;
+ }
#ifdef WITH_OPENEXR
- if (ibuf->ftype != IMB_FTYPE_OPENEXR || ibuf->userdata == NULL) {
- return;
- }
- MultilayerConvertContext ctx;
- ctx.combined_pass = NULL;
- ctx.num_combined_channels = 0;
- IMB_exr_multilayer_convert(
- ibuf->userdata,
- &ctx,
- movieclip_convert_multilayer_add_view,
- movieclip_convert_multilayer_add_layer,
- movieclip_convert_multilayer_add_pass);
- if (ctx.combined_pass != NULL) {
- BLI_assert(ibuf->rect_float == NULL);
- ibuf->rect_float = ctx.combined_pass;
- ibuf->channels = ctx.num_combined_channels;
- ibuf->flags |= IB_rectfloat;
- ibuf->mall |= IB_rectfloat;
- }
- IMB_exr_close(ibuf->userdata);
- ibuf->userdata = NULL;
+ if (ibuf->ftype != IMB_FTYPE_OPENEXR || ibuf->userdata == NULL) {
+ return;
+ }
+ MultilayerConvertContext ctx;
+ ctx.combined_pass = NULL;
+ ctx.num_combined_channels = 0;
+ IMB_exr_multilayer_convert(ibuf->userdata,
+ &ctx,
+ movieclip_convert_multilayer_add_view,
+ movieclip_convert_multilayer_add_layer,
+ movieclip_convert_multilayer_add_pass);
+ if (ctx.combined_pass != NULL) {
+ BLI_assert(ibuf->rect_float == NULL);
+ ibuf->rect_float = ctx.combined_pass;
+ ibuf->channels = ctx.num_combined_channels;
+ ibuf->flags |= IB_rectfloat;
+ ibuf->mall |= IB_rectfloat;
+ }
+ IMB_exr_close(ibuf->userdata);
+ ibuf->userdata = NULL;
#endif
}
@@ -291,63 +275,63 @@ static ImBuf *movieclip_load_sequence_file(MovieClip *clip,
int framenr,
int flag)
{
- struct ImBuf *ibuf;
- char name[FILE_MAX];
- int loadflag;
- bool use_proxy = false;
- char *colorspace;
-
- use_proxy = (flag & MCLIP_USE_PROXY) && user->render_size != MCLIP_PROXY_RENDER_SIZE_FULL;
- if (use_proxy) {
- int undistort = user->render_flag & MCLIP_PROXY_RENDER_UNDISTORT;
- get_proxy_fname(clip, user->render_size, undistort, framenr, name);
-
- /* Well, this is a bit weird, but proxies for movie sources
- * are built in the same exact color space as the input,
- *
- * But image sequences are built in the display space.
- */
- if (clip->source == MCLIP_SRC_MOVIE) {
- colorspace = clip->colorspace_settings.name;
- }
- else {
- colorspace = NULL;
- }
- }
- else {
- get_sequence_fname(clip, framenr, name);
- colorspace = clip->colorspace_settings.name;
- }
-
- loadflag = IB_rect | IB_multilayer | IB_alphamode_detect | IB_metadata;
-
- /* read ibuf */
- ibuf = IMB_loadiffname(name, loadflag, colorspace);
- BKE_movieclip_convert_multilayer_ibuf(ibuf);
-
- return ibuf;
+ struct ImBuf *ibuf;
+ char name[FILE_MAX];
+ int loadflag;
+ bool use_proxy = false;
+ char *colorspace;
+
+ use_proxy = (flag & MCLIP_USE_PROXY) && user->render_size != MCLIP_PROXY_RENDER_SIZE_FULL;
+ if (use_proxy) {
+ int undistort = user->render_flag & MCLIP_PROXY_RENDER_UNDISTORT;
+ get_proxy_fname(clip, user->render_size, undistort, framenr, name);
+
+ /* Well, this is a bit weird, but proxies for movie sources
+ * are built in the same exact color space as the input,
+ *
+ * But image sequences are built in the display space.
+ */
+ if (clip->source == MCLIP_SRC_MOVIE) {
+ colorspace = clip->colorspace_settings.name;
+ }
+ else {
+ colorspace = NULL;
+ }
+ }
+ else {
+ get_sequence_fname(clip, framenr, name);
+ colorspace = clip->colorspace_settings.name;
+ }
+
+ loadflag = IB_rect | IB_multilayer | IB_alphamode_detect | IB_metadata;
+
+ /* read ibuf */
+ ibuf = IMB_loadiffname(name, loadflag, colorspace);
+ BKE_movieclip_convert_multilayer_ibuf(ibuf);
+
+ return ibuf;
}
static void movieclip_open_anim_file(MovieClip *clip)
{
- char str[FILE_MAX];
+ char str[FILE_MAX];
- if (!clip->anim) {
- BLI_strncpy(str, clip->name, FILE_MAX);
- BLI_path_abs(str, ID_BLEND_PATH_FROM_GLOBAL(&clip->id));
+ if (!clip->anim) {
+ BLI_strncpy(str, clip->name, FILE_MAX);
+ BLI_path_abs(str, ID_BLEND_PATH_FROM_GLOBAL(&clip->id));
- /* FIXME: make several stream accessible in image editor, too */
- clip->anim = openanim(str, IB_rect, 0, clip->colorspace_settings.name);
+ /* FIXME: make several stream accessible in image editor, too */
+ clip->anim = openanim(str, IB_rect, 0, clip->colorspace_settings.name);
- if (clip->anim) {
- if (clip->flag & MCLIP_USE_PROXY_CUSTOM_DIR) {
- char dir[FILE_MAX];
- BLI_strncpy(dir, clip->proxy.dir, sizeof(dir));
- BLI_path_abs(dir, BKE_main_blendfile_path_from_global());
- IMB_anim_set_index_dir(clip->anim, dir);
- }
- }
- }
+ if (clip->anim) {
+ if (clip->flag & MCLIP_USE_PROXY_CUSTOM_DIR) {
+ char dir[FILE_MAX];
+ BLI_strncpy(dir, clip->proxy.dir, sizeof(dir));
+ BLI_path_abs(dir, BKE_main_blendfile_path_from_global());
+ IMB_anim_set_index_dir(clip->anim, dir);
+ }
+ }
+ }
}
static ImBuf *movieclip_load_movie_file(MovieClip *clip,
@@ -355,305 +339,293 @@ static ImBuf *movieclip_load_movie_file(MovieClip *clip,
int framenr,
int flag)
{
- ImBuf *ibuf = NULL;
- int tc = get_timecode(clip, flag);
- int proxy = rendersize_to_proxy(user, flag);
+ ImBuf *ibuf = NULL;
+ int tc = get_timecode(clip, flag);
+ int proxy = rendersize_to_proxy(user, flag);
- movieclip_open_anim_file(clip);
+ movieclip_open_anim_file(clip);
- if (clip->anim) {
- int fra = framenr - clip->start_frame + clip->frame_offset;
+ if (clip->anim) {
+ int fra = framenr - clip->start_frame + clip->frame_offset;
- ibuf = IMB_anim_absolute(clip->anim, fra, tc, proxy);
- }
+ ibuf = IMB_anim_absolute(clip->anim, fra, tc, proxy);
+ }
- return ibuf;
+ return ibuf;
}
static void movieclip_calc_length(MovieClip *clip)
{
- if (clip->source == MCLIP_SRC_MOVIE) {
- movieclip_open_anim_file(clip);
-
- if (clip->anim) {
- clip->len = IMB_anim_get_duration(clip->anim, clip->proxy.tc);
- }
- }
- else if (clip->source == MCLIP_SRC_SEQUENCE) {
- unsigned short numlen;
- char name[FILE_MAX], head[FILE_MAX], tail[FILE_MAX];
-
- BLI_stringdec(clip->name, head, tail, &numlen);
-
- if (numlen == 0) {
- /* there's no number group in file name, assume it's single framed sequence */
- clip->len = 1;
- }
- else {
- clip->len = 0;
- for (;;) {
- get_sequence_fname(clip,
- clip->len + clip->start_frame,
- name);
-
- if (BLI_exists(name))
- clip->len++;
- else
- break;
- }
- }
- }
+ if (clip->source == MCLIP_SRC_MOVIE) {
+ movieclip_open_anim_file(clip);
+
+ if (clip->anim) {
+ clip->len = IMB_anim_get_duration(clip->anim, clip->proxy.tc);
+ }
+ }
+ else if (clip->source == MCLIP_SRC_SEQUENCE) {
+ unsigned short numlen;
+ char name[FILE_MAX], head[FILE_MAX], tail[FILE_MAX];
+
+ BLI_stringdec(clip->name, head, tail, &numlen);
+
+ if (numlen == 0) {
+ /* there's no number group in file name, assume it's single framed sequence */
+ clip->len = 1;
+ }
+ else {
+ clip->len = 0;
+ for (;;) {
+ get_sequence_fname(clip, clip->len + clip->start_frame, name);
+
+ if (BLI_exists(name))
+ clip->len++;
+ else
+ break;
+ }
+ }
+ }
}
/*********************** image buffer cache *************************/
typedef struct MovieClipCache {
- /* regular movie cache */
- struct MovieCache *moviecache;
-
- /* cached postprocessed shot */
- struct {
- ImBuf *ibuf;
- int framenr;
- int flag;
-
- /* cache for undistorted shot */
- float principal[2];
- float polynomial_k1, polynomial_k2, polynomial_k3;
- float division_k1, division_k2;
- short distortion_model;
- bool undistortion_used;
-
- int proxy;
- short render_flag;
- } postprocessed;
-
- /* cache for stable shot */
- struct {
- ImBuf *reference_ibuf;
-
- ImBuf *ibuf;
- int framenr;
- int postprocess_flag;
-
- float loc[2], scale, angle, aspect;
- int proxy, filter;
- short render_flag;
- } stabilized;
-
- int sequence_offset;
-
- bool is_still_sequence;
+ /* regular movie cache */
+ struct MovieCache *moviecache;
+
+ /* cached postprocessed shot */
+ struct {
+ ImBuf *ibuf;
+ int framenr;
+ int flag;
+
+ /* cache for undistorted shot */
+ float principal[2];
+ float polynomial_k1, polynomial_k2, polynomial_k3;
+ float division_k1, division_k2;
+ short distortion_model;
+ bool undistortion_used;
+
+ int proxy;
+ short render_flag;
+ } postprocessed;
+
+ /* cache for stable shot */
+ struct {
+ ImBuf *reference_ibuf;
+
+ ImBuf *ibuf;
+ int framenr;
+ int postprocess_flag;
+
+ float loc[2], scale, angle, aspect;
+ int proxy, filter;
+ short render_flag;
+ } stabilized;
+
+ int sequence_offset;
+
+ bool is_still_sequence;
} MovieClipCache;
typedef struct MovieClipImBufCacheKey {
- int framenr;
- int proxy;
- short render_flag;
+ int framenr;
+ int proxy;
+ short render_flag;
} MovieClipImBufCacheKey;
typedef struct MovieClipCachePriorityData {
- int framenr;
+ int framenr;
} MovieClipCachePriorityData;
static int user_frame_to_cache_frame(MovieClip *clip, int framenr)
{
- int index;
+ int index;
- index = framenr - clip->start_frame + clip->frame_offset;
+ index = framenr - clip->start_frame + clip->frame_offset;
- if (clip->source == MCLIP_SRC_SEQUENCE) {
- if (clip->cache->sequence_offset == -1) {
- unsigned short numlen;
- char head[FILE_MAX], tail[FILE_MAX];
+ if (clip->source == MCLIP_SRC_SEQUENCE) {
+ if (clip->cache->sequence_offset == -1) {
+ unsigned short numlen;
+ char head[FILE_MAX], tail[FILE_MAX];
- BLI_stringdec(clip->name, head, tail, &numlen);
+ BLI_stringdec(clip->name, head, tail, &numlen);
- /* see comment in get_sequence_fname */
- clip->cache->sequence_offset = sequence_guess_offset(clip->name, strlen(head), numlen);
- }
+ /* see comment in get_sequence_fname */
+ clip->cache->sequence_offset = sequence_guess_offset(clip->name, strlen(head), numlen);
+ }
- index += clip->cache->sequence_offset;
- }
+ index += clip->cache->sequence_offset;
+ }
- if (index < 0)
- return framenr - index;
+ if (index < 0)
+ return framenr - index;
- return framenr;
+ return framenr;
}
static void moviecache_keydata(void *userkey, int *framenr, int *proxy, int *render_flags)
{
- const MovieClipImBufCacheKey *key = userkey;
+ const MovieClipImBufCacheKey *key = userkey;
- *framenr = key->framenr;
- *proxy = key->proxy;
- *render_flags = key->render_flag;
+ *framenr = key->framenr;
+ *proxy = key->proxy;
+ *render_flags = key->render_flag;
}
static unsigned int moviecache_hashhash(const void *keyv)
{
- const MovieClipImBufCacheKey *key = keyv;
- int rval = key->framenr;
+ const MovieClipImBufCacheKey *key = keyv;
+ int rval = key->framenr;
- return rval;
+ return rval;
}
static bool moviecache_hashcmp(const void *av, const void *bv)
{
- const MovieClipImBufCacheKey *a = av;
- const MovieClipImBufCacheKey *b = bv;
+ const MovieClipImBufCacheKey *a = av;
+ const MovieClipImBufCacheKey *b = bv;
- return ((a->framenr != b->framenr) ||
- (a->proxy != b->proxy) ||
- (a->render_flag != b->render_flag));
+ return ((a->framenr != b->framenr) || (a->proxy != b->proxy) ||
+ (a->render_flag != b->render_flag));
}
static void *moviecache_getprioritydata(void *key_v)
{
- MovieClipImBufCacheKey *key = (MovieClipImBufCacheKey *) key_v;
- MovieClipCachePriorityData *priority_data;
+ MovieClipImBufCacheKey *key = (MovieClipImBufCacheKey *)key_v;
+ MovieClipCachePriorityData *priority_data;
- priority_data = MEM_callocN(sizeof(*priority_data), "movie cache clip priority data");
- priority_data->framenr = key->framenr;
+ priority_data = MEM_callocN(sizeof(*priority_data), "movie cache clip priority data");
+ priority_data->framenr = key->framenr;
- return priority_data;
+ return priority_data;
}
static int moviecache_getitempriority(void *last_userkey_v, void *priority_data_v)
{
- MovieClipImBufCacheKey *last_userkey = (MovieClipImBufCacheKey *) last_userkey_v;
- MovieClipCachePriorityData *priority_data = (MovieClipCachePriorityData *) priority_data_v;
+ MovieClipImBufCacheKey *last_userkey = (MovieClipImBufCacheKey *)last_userkey_v;
+ MovieClipCachePriorityData *priority_data = (MovieClipCachePriorityData *)priority_data_v;
- return -abs(last_userkey->framenr - priority_data->framenr);
+ return -abs(last_userkey->framenr - priority_data->framenr);
}
static void moviecache_prioritydeleter(void *priority_data_v)
{
- MovieClipCachePriorityData *priority_data = (MovieClipCachePriorityData *) priority_data_v;
+ MovieClipCachePriorityData *priority_data = (MovieClipCachePriorityData *)priority_data_v;
- MEM_freeN(priority_data);
+ MEM_freeN(priority_data);
}
-static ImBuf *get_imbuf_cache(MovieClip *clip,
- const MovieClipUser *user,
- int flag)
+static ImBuf *get_imbuf_cache(MovieClip *clip, const MovieClipUser *user, int flag)
{
- if (clip->cache) {
- MovieClipImBufCacheKey key;
+ if (clip->cache) {
+ MovieClipImBufCacheKey key;
- if (!clip->cache->is_still_sequence) {
- key.framenr = user_frame_to_cache_frame(clip, user->framenr);
- }
- else {
- key.framenr = 1;
- }
+ if (!clip->cache->is_still_sequence) {
+ key.framenr = user_frame_to_cache_frame(clip, user->framenr);
+ }
+ else {
+ key.framenr = 1;
+ }
- if (flag & MCLIP_USE_PROXY) {
- key.proxy = rendersize_to_proxy(user, flag);
- key.render_flag = user->render_flag;
- }
- else {
- key.proxy = IMB_PROXY_NONE;
- key.render_flag = 0;
- }
+ if (flag & MCLIP_USE_PROXY) {
+ key.proxy = rendersize_to_proxy(user, flag);
+ key.render_flag = user->render_flag;
+ }
+ else {
+ key.proxy = IMB_PROXY_NONE;
+ key.render_flag = 0;
+ }
- return IMB_moviecache_get(clip->cache->moviecache, &key);
- }
+ return IMB_moviecache_get(clip->cache->moviecache, &key);
+ }
- return NULL;
+ return NULL;
}
static bool has_imbuf_cache(MovieClip *clip, MovieClipUser *user, int flag)
{
- if (clip->cache) {
- MovieClipImBufCacheKey key;
+ if (clip->cache) {
+ MovieClipImBufCacheKey key;
- key.framenr = user_frame_to_cache_frame(clip, user->framenr);
+ key.framenr = user_frame_to_cache_frame(clip, user->framenr);
- if (flag & MCLIP_USE_PROXY) {
- key.proxy = rendersize_to_proxy(user, flag);
- key.render_flag = user->render_flag;
- }
- else {
- key.proxy = IMB_PROXY_NONE;
- key.render_flag = 0;
- }
+ if (flag & MCLIP_USE_PROXY) {
+ key.proxy = rendersize_to_proxy(user, flag);
+ key.render_flag = user->render_flag;
+ }
+ else {
+ key.proxy = IMB_PROXY_NONE;
+ key.render_flag = 0;
+ }
- return IMB_moviecache_has_frame(clip->cache->moviecache, &key);
- }
+ return IMB_moviecache_has_frame(clip->cache->moviecache, &key);
+ }
- return false;
+ return false;
}
-static bool put_imbuf_cache(MovieClip *clip,
- const MovieClipUser *user,
- ImBuf *ibuf,
- int flag,
- bool destructive)
+static bool put_imbuf_cache(
+ MovieClip *clip, const MovieClipUser *user, ImBuf *ibuf, int flag, bool destructive)
{
- MovieClipImBufCacheKey key;
+ MovieClipImBufCacheKey key;
- if (clip->cache == NULL) {
- struct MovieCache *moviecache;
+ if (clip->cache == NULL) {
+ struct MovieCache *moviecache;
- // char cache_name[64];
- // BLI_snprintf(cache_name, sizeof(cache_name), "movie %s", clip->id.name);
+ // char cache_name[64];
+ // BLI_snprintf(cache_name, sizeof(cache_name), "movie %s", clip->id.name);
- clip->cache = MEM_callocN(sizeof(MovieClipCache), "movieClipCache");
+ clip->cache = MEM_callocN(sizeof(MovieClipCache), "movieClipCache");
- moviecache = IMB_moviecache_create("movieclip",
- sizeof(MovieClipImBufCacheKey),
- moviecache_hashhash,
- moviecache_hashcmp);
+ moviecache = IMB_moviecache_create(
+ "movieclip", sizeof(MovieClipImBufCacheKey), moviecache_hashhash, moviecache_hashcmp);
- IMB_moviecache_set_getdata_callback(moviecache, moviecache_keydata);
- IMB_moviecache_set_priority_callback(moviecache,
- moviecache_getprioritydata,
- moviecache_getitempriority,
- moviecache_prioritydeleter);
+ IMB_moviecache_set_getdata_callback(moviecache, moviecache_keydata);
+ IMB_moviecache_set_priority_callback(moviecache,
+ moviecache_getprioritydata,
+ moviecache_getitempriority,
+ moviecache_prioritydeleter);
- clip->cache->moviecache = moviecache;
- clip->cache->sequence_offset = -1;
- if (clip->source == MCLIP_SRC_SEQUENCE) {
- unsigned short numlen;
- BLI_stringdec(clip->name, NULL, NULL, &numlen);
- clip->cache->is_still_sequence = (numlen == 0);
- }
- }
+ clip->cache->moviecache = moviecache;
+ clip->cache->sequence_offset = -1;
+ if (clip->source == MCLIP_SRC_SEQUENCE) {
+ unsigned short numlen;
+ BLI_stringdec(clip->name, NULL, NULL, &numlen);
+ clip->cache->is_still_sequence = (numlen == 0);
+ }
+ }
- if (!clip->cache->is_still_sequence) {
- key.framenr = user_frame_to_cache_frame(clip, user->framenr);
- }
- else {
- key.framenr = 1;
- }
+ if (!clip->cache->is_still_sequence) {
+ key.framenr = user_frame_to_cache_frame(clip, user->framenr);
+ }
+ else {
+ key.framenr = 1;
+ }
- if (flag & MCLIP_USE_PROXY) {
- key.proxy = rendersize_to_proxy(user, flag);
- key.render_flag = user->render_flag;
- }
- else {
- key.proxy = IMB_PROXY_NONE;
- key.render_flag = 0;
- }
+ if (flag & MCLIP_USE_PROXY) {
+ key.proxy = rendersize_to_proxy(user, flag);
+ key.render_flag = user->render_flag;
+ }
+ else {
+ key.proxy = IMB_PROXY_NONE;
+ key.render_flag = 0;
+ }
- if (destructive) {
- IMB_moviecache_put(clip->cache->moviecache, &key, ibuf);
- return true;
- }
- else {
- return IMB_moviecache_put_if_possible(clip->cache->moviecache, &key, ibuf);
- }
+ if (destructive) {
+ IMB_moviecache_put(clip->cache->moviecache, &key, ibuf);
+ return true;
+ }
+ else {
+ return IMB_moviecache_put_if_possible(clip->cache->moviecache, &key, ibuf);
+ }
}
-static bool moviecache_check_free_proxy(ImBuf *UNUSED(ibuf),
- void *userkey,
- void *UNUSED(userdata))
+static bool moviecache_check_free_proxy(ImBuf *UNUSED(ibuf), void *userkey, void *UNUSED(userdata))
{
- MovieClipImBufCacheKey *key = (MovieClipImBufCacheKey *)userkey;
+ MovieClipImBufCacheKey *key = (MovieClipImBufCacheKey *)userkey;
- return !(key->proxy == IMB_PROXY_NONE && key->render_flag == 0);
+ return !(key->proxy == IMB_PROXY_NONE && key->render_flag == 0);
}
/*********************** common functions *************************/
@@ -661,61 +633,59 @@ static bool moviecache_check_free_proxy(ImBuf *UNUSED(ibuf),
/* only image block itself */
static MovieClip *movieclip_alloc(Main *bmain, const char *name)
{
- MovieClip *clip;
+ MovieClip *clip;
- clip = BKE_libblock_alloc(bmain, ID_MC, name, 0);
+ clip = BKE_libblock_alloc(bmain, ID_MC, name, 0);
- clip->aspx = clip->aspy = 1.0f;
+ clip->aspx = clip->aspy = 1.0f;
- BKE_tracking_settings_init(&clip->tracking);
- BKE_color_managed_colorspace_settings_init(&clip->colorspace_settings);
+ BKE_tracking_settings_init(&clip->tracking);
+ BKE_color_managed_colorspace_settings_init(&clip->colorspace_settings);
- clip->proxy.build_size_flag = IMB_PROXY_25;
- clip->proxy.build_tc_flag = IMB_TC_RECORD_RUN |
- IMB_TC_FREE_RUN |
- IMB_TC_INTERPOLATED_REC_DATE_FREE_RUN |
- IMB_TC_RECORD_RUN_NO_GAPS;
- clip->proxy.quality = 90;
+ clip->proxy.build_size_flag = IMB_PROXY_25;
+ clip->proxy.build_tc_flag = IMB_TC_RECORD_RUN | IMB_TC_FREE_RUN |
+ IMB_TC_INTERPOLATED_REC_DATE_FREE_RUN | IMB_TC_RECORD_RUN_NO_GAPS;
+ clip->proxy.quality = 90;
- clip->start_frame = 1;
- clip->frame_offset = 0;
+ clip->start_frame = 1;
+ clip->frame_offset = 0;
- return clip;
+ return clip;
}
static void movieclip_load_get_size(MovieClip *clip)
{
- int width, height;
- MovieClipUser user = {0};
+ int width, height;
+ MovieClipUser user = {0};
- user.framenr = 1;
- BKE_movieclip_get_size(clip, &user, &width, &height);
+ user.framenr = 1;
+ BKE_movieclip_get_size(clip, &user, &width, &height);
- if (width && height) {
- clip->tracking.camera.principal[0] = ((float)width) / 2.0f;
- clip->tracking.camera.principal[1] = ((float)height) / 2.0f;
- }
- else {
- clip->lastsize[0] = clip->lastsize[1] = IMG_SIZE_FALLBACK;
- }
+ if (width && height) {
+ clip->tracking.camera.principal[0] = ((float)width) / 2.0f;
+ clip->tracking.camera.principal[1] = ((float)height) / 2.0f;
+ }
+ else {
+ clip->lastsize[0] = clip->lastsize[1] = IMG_SIZE_FALLBACK;
+ }
}
static void detect_clip_source(Main *bmain, MovieClip *clip)
{
- ImBuf *ibuf;
- char name[FILE_MAX];
+ ImBuf *ibuf;
+ char name[FILE_MAX];
- BLI_strncpy(name, clip->name, sizeof(name));
- BLI_path_abs(name, BKE_main_blendfile_path(bmain));
+ BLI_strncpy(name, clip->name, sizeof(name));
+ BLI_path_abs(name, BKE_main_blendfile_path(bmain));
- ibuf = IMB_testiffname(name, IB_rect | IB_multilayer);
- if (ibuf) {
- clip->source = MCLIP_SRC_SEQUENCE;
- IMB_freeImBuf(ibuf);
- }
- else {
- clip->source = MCLIP_SRC_MOVIE;
- }
+ ibuf = IMB_testiffname(name, IB_rect | IB_multilayer);
+ if (ibuf) {
+ clip->source = MCLIP_SRC_SEQUENCE;
+ IMB_freeImBuf(ibuf);
+ }
+ else {
+ clip->source = MCLIP_SRC_MOVIE;
+ }
}
/* checks if image was already loaded, then returns same image
@@ -724,158 +694,155 @@ static void detect_clip_source(Main *bmain, MovieClip *clip)
* pass on optional frame for #name images */
MovieClip *BKE_movieclip_file_add(Main *bmain, const char *name)
{
- MovieClip *clip;
- int file;
- char str[FILE_MAX];
+ MovieClip *clip;
+ int file;
+ char str[FILE_MAX];
- BLI_strncpy(str, name, sizeof(str));
- BLI_path_abs(str, BKE_main_blendfile_path(bmain));
+ BLI_strncpy(str, name, sizeof(str));
+ BLI_path_abs(str, BKE_main_blendfile_path(bmain));
- /* exists? */
- file = BLI_open(str, O_BINARY | O_RDONLY, 0);
- if (file == -1)
- return NULL;
- close(file);
+ /* exists? */
+ file = BLI_open(str, O_BINARY | O_RDONLY, 0);
+ if (file == -1)
+ return NULL;
+ close(file);
- /* ** add new movieclip ** */
+ /* ** add new movieclip ** */
- /* create a short library name */
- clip = movieclip_alloc(bmain, BLI_path_basename(name));
- BLI_strncpy(clip->name, name, sizeof(clip->name));
+ /* create a short library name */
+ clip = movieclip_alloc(bmain, BLI_path_basename(name));
+ BLI_strncpy(clip->name, name, sizeof(clip->name));
- detect_clip_source(bmain, clip);
+ detect_clip_source(bmain, clip);
- movieclip_load_get_size(clip);
- if (clip->lastsize[0]) {
- int width = clip->lastsize[0];
+ movieclip_load_get_size(clip);
+ if (clip->lastsize[0]) {
+ int width = clip->lastsize[0];
- clip->tracking.camera.focal = 24.0f * width / clip->tracking.camera.sensor_width;
- }
+ clip->tracking.camera.focal = 24.0f * width / clip->tracking.camera.sensor_width;
+ }
- movieclip_calc_length(clip);
+ movieclip_calc_length(clip);
- return clip;
+ return clip;
}
MovieClip *BKE_movieclip_file_add_exists_ex(Main *bmain, const char *filepath, bool *r_exists)
{
- MovieClip *clip;
- char str[FILE_MAX], strtest[FILE_MAX];
+ MovieClip *clip;
+ char str[FILE_MAX], strtest[FILE_MAX];
- BLI_strncpy(str, filepath, sizeof(str));
- BLI_path_abs(str, BKE_main_blendfile_path(bmain));
+ BLI_strncpy(str, filepath, sizeof(str));
+ BLI_path_abs(str, BKE_main_blendfile_path(bmain));
- /* first search an identical filepath */
- for (clip = bmain->movieclips.first; clip; clip = clip->id.next) {
- BLI_strncpy(strtest, clip->name, sizeof(clip->name));
- BLI_path_abs(strtest, ID_BLEND_PATH(bmain, &clip->id));
+ /* first search an identical filepath */
+ for (clip = bmain->movieclips.first; clip; clip = clip->id.next) {
+ BLI_strncpy(strtest, clip->name, sizeof(clip->name));
+ BLI_path_abs(strtest, ID_BLEND_PATH(bmain, &clip->id));
- if (BLI_path_cmp(strtest, str) == 0) {
- id_us_plus(&clip->id); /* officially should not, it doesn't link here! */
- if (r_exists)
- *r_exists = true;
- return clip;
- }
- }
+ if (BLI_path_cmp(strtest, str) == 0) {
+ id_us_plus(&clip->id); /* officially should not, it doesn't link here! */
+ if (r_exists)
+ *r_exists = true;
+ return clip;
+ }
+ }
- if (r_exists)
- *r_exists = false;
- return BKE_movieclip_file_add(bmain, filepath);
+ if (r_exists)
+ *r_exists = false;
+ return BKE_movieclip_file_add(bmain, filepath);
}
MovieClip *BKE_movieclip_file_add_exists(Main *bmain, const char *filepath)
{
- return BKE_movieclip_file_add_exists_ex(bmain, filepath, NULL);
+ return BKE_movieclip_file_add_exists_ex(bmain, filepath, NULL);
}
-static void real_ibuf_size(const MovieClip *clip,
- const MovieClipUser *user,
- const ImBuf *ibuf,
- int *width, int *height)
+static void real_ibuf_size(
+ const MovieClip *clip, const MovieClipUser *user, const ImBuf *ibuf, int *width, int *height)
{
- *width = ibuf->x;
- *height = ibuf->y;
+ *width = ibuf->x;
+ *height = ibuf->y;
- if (clip->flag & MCLIP_USE_PROXY) {
- switch (user->render_size) {
- case MCLIP_PROXY_RENDER_SIZE_25:
- (*width) *= 4;
- (*height) *= 4;
- break;
+ if (clip->flag & MCLIP_USE_PROXY) {
+ switch (user->render_size) {
+ case MCLIP_PROXY_RENDER_SIZE_25:
+ (*width) *= 4;
+ (*height) *= 4;
+ break;
- case MCLIP_PROXY_RENDER_SIZE_50:
- (*width) *= 2.0f;
- (*height) *= 2.0f;
- break;
+ case MCLIP_PROXY_RENDER_SIZE_50:
+ (*width) *= 2.0f;
+ (*height) *= 2.0f;
+ break;
- case MCLIP_PROXY_RENDER_SIZE_75:
- *width = ((float)*width) * 4.0f / 3.0f;
- *height = ((float)*height) * 4.0f / 3.0f;
- break;
- }
- }
+ case MCLIP_PROXY_RENDER_SIZE_75:
+ *width = ((float)*width) * 4.0f / 3.0f;
+ *height = ((float)*height) * 4.0f / 3.0f;
+ break;
+ }
+ }
}
static ImBuf *get_undistorted_ibuf(MovieClip *clip,
struct MovieDistortion *distortion,
ImBuf *ibuf)
{
- ImBuf *undistibuf;
+ ImBuf *undistibuf;
- if (distortion)
- undistibuf = BKE_tracking_distortion_exec(distortion, &clip->tracking, ibuf, ibuf->x, ibuf->y, 0.0f, 1);
- else
- undistibuf = BKE_tracking_undistort_frame(&clip->tracking, ibuf, ibuf->x, ibuf->y, 0.0f);
+ if (distortion)
+ undistibuf = BKE_tracking_distortion_exec(
+ distortion, &clip->tracking, ibuf, ibuf->x, ibuf->y, 0.0f, 1);
+ else
+ undistibuf = BKE_tracking_undistort_frame(&clip->tracking, ibuf, ibuf->x, ibuf->y, 0.0f);
- IMB_scaleImBuf(undistibuf, ibuf->x, ibuf->y);
+ IMB_scaleImBuf(undistibuf, ibuf->x, ibuf->y);
- return undistibuf;
+ return undistibuf;
}
static bool need_undistortion_postprocess(const MovieClipUser *user, int clip_flag)
{
- bool result = 0;
- const bool uses_full_frame =
- ((clip_flag & MCLIP_USE_PROXY) == 0) ||
- (user->render_size == MCLIP_PROXY_RENDER_SIZE_FULL);
- /* Only full undistorted render can be used as on-fly undistorting image. */
- result |= uses_full_frame &&
- (user->render_flag & MCLIP_PROXY_RENDER_UNDISTORT) != 0;
- return result;
+ bool result = 0;
+ const bool uses_full_frame = ((clip_flag & MCLIP_USE_PROXY) == 0) ||
+ (user->render_size == MCLIP_PROXY_RENDER_SIZE_FULL);
+ /* Only full undistorted render can be used as on-fly undistorting image. */
+ result |= uses_full_frame && (user->render_flag & MCLIP_PROXY_RENDER_UNDISTORT) != 0;
+ return result;
}
static bool need_postprocessed_frame(const MovieClipUser *user,
int clip_flag,
int postprocess_flag)
{
- bool result = (postprocess_flag != 0);
- result |= need_undistortion_postprocess(user, clip_flag);
- return result;
+ bool result = (postprocess_flag != 0);
+ result |= need_undistortion_postprocess(user, clip_flag);
+ return result;
}
static bool check_undistortion_cache_flags(const MovieClip *clip)
{
- const MovieClipCache *cache = clip->cache;
- const MovieTrackingCamera *camera = &clip->tracking.camera;
+ const MovieClipCache *cache = clip->cache;
+ const MovieTrackingCamera *camera = &clip->tracking.camera;
- /* check for distortion model changes */
- if (!equals_v2v2(camera->principal, cache->postprocessed.principal)) {
- return false;
- }
+ /* check for distortion model changes */
+ if (!equals_v2v2(camera->principal, cache->postprocessed.principal)) {
+ return false;
+ }
- if (camera->distortion_model != cache->postprocessed.distortion_model) {
- return false;
- }
+ if (camera->distortion_model != cache->postprocessed.distortion_model) {
+ return false;
+ }
- if (!equals_v3v3(&camera->k1, &cache->postprocessed.polynomial_k1)) {
- return false;
- }
+ if (!equals_v3v3(&camera->k1, &cache->postprocessed.polynomial_k1)) {
+ return false;
+ }
- if (!equals_v2v2(&camera->division_k1, &cache->postprocessed.division_k1)) {
- return false;
- }
+ if (!equals_v2v2(&camera->division_k1, &cache->postprocessed.division_k1)) {
+ return false;
+ }
- return true;
+ return true;
}
static ImBuf *get_postprocessed_cached_frame(const MovieClip *clip,
@@ -883,711 +850,719 @@ static ImBuf *get_postprocessed_cached_frame(const MovieClip *clip,
int flag,
int postprocess_flag)
{
- const MovieClipCache *cache = clip->cache;
- int framenr = user->framenr;
- short proxy = IMB_PROXY_NONE;
- int render_flag = 0;
+ const MovieClipCache *cache = clip->cache;
+ int framenr = user->framenr;
+ short proxy = IMB_PROXY_NONE;
+ int render_flag = 0;
- if (flag & MCLIP_USE_PROXY) {
- proxy = rendersize_to_proxy(user, flag);
- render_flag = user->render_flag;
- }
+ if (flag & MCLIP_USE_PROXY) {
+ proxy = rendersize_to_proxy(user, flag);
+ render_flag = user->render_flag;
+ }
- /* no cache or no cached postprocessed image */
- if (!clip->cache || !clip->cache->postprocessed.ibuf)
- return NULL;
+ /* no cache or no cached postprocessed image */
+ if (!clip->cache || !clip->cache->postprocessed.ibuf)
+ return NULL;
- /* postprocessing happened for other frame */
- if (cache->postprocessed.framenr != framenr)
- return NULL;
+ /* postprocessing happened for other frame */
+ if (cache->postprocessed.framenr != framenr)
+ return NULL;
- /* cached ibuf used different proxy settings */
- if (cache->postprocessed.render_flag != render_flag || cache->postprocessed.proxy != proxy)
- return NULL;
+ /* cached ibuf used different proxy settings */
+ if (cache->postprocessed.render_flag != render_flag || cache->postprocessed.proxy != proxy)
+ return NULL;
- if (cache->postprocessed.flag != postprocess_flag)
- return NULL;
+ if (cache->postprocessed.flag != postprocess_flag)
+ return NULL;
- if (need_undistortion_postprocess(user, flag)) {
- if (!check_undistortion_cache_flags(clip))
- return NULL;
- }
- else if (cache->postprocessed.undistortion_used)
- return NULL;
+ if (need_undistortion_postprocess(user, flag)) {
+ if (!check_undistortion_cache_flags(clip))
+ return NULL;
+ }
+ else if (cache->postprocessed.undistortion_used)
+ return NULL;
- IMB_refImBuf(cache->postprocessed.ibuf);
+ IMB_refImBuf(cache->postprocessed.ibuf);
- return cache->postprocessed.ibuf;
+ return cache->postprocessed.ibuf;
}
-static ImBuf *postprocess_frame(MovieClip *clip,
- const MovieClipUser *user,
- ImBuf *ibuf,
- int flag,
- int postprocess_flag)
+static ImBuf *postprocess_frame(
+ MovieClip *clip, const MovieClipUser *user, ImBuf *ibuf, int flag, int postprocess_flag)
{
- ImBuf *postproc_ibuf = NULL;
+ ImBuf *postproc_ibuf = NULL;
- if (need_undistortion_postprocess(user, flag)) {
- postproc_ibuf = get_undistorted_ibuf(clip, NULL, ibuf);
- }
- else {
- postproc_ibuf = IMB_dupImBuf(ibuf);
- }
+ if (need_undistortion_postprocess(user, flag)) {
+ postproc_ibuf = get_undistorted_ibuf(clip, NULL, ibuf);
+ }
+ else {
+ postproc_ibuf = IMB_dupImBuf(ibuf);
+ }
- if (postprocess_flag) {
- bool disable_red = (postprocess_flag & MOVIECLIP_DISABLE_RED) != 0;
- bool disable_green = (postprocess_flag & MOVIECLIP_DISABLE_GREEN) != 0;
- bool disable_blue = (postprocess_flag & MOVIECLIP_DISABLE_BLUE) != 0;
- bool grayscale = (postprocess_flag & MOVIECLIP_PREVIEW_GRAYSCALE) != 0;
+ if (postprocess_flag) {
+ bool disable_red = (postprocess_flag & MOVIECLIP_DISABLE_RED) != 0;
+ bool disable_green = (postprocess_flag & MOVIECLIP_DISABLE_GREEN) != 0;
+ bool disable_blue = (postprocess_flag & MOVIECLIP_DISABLE_BLUE) != 0;
+ bool grayscale = (postprocess_flag & MOVIECLIP_PREVIEW_GRAYSCALE) != 0;
- if (disable_red || disable_green || disable_blue || grayscale)
- BKE_tracking_disable_channels(postproc_ibuf, disable_red, disable_green, disable_blue, 1);
- }
+ if (disable_red || disable_green || disable_blue || grayscale)
+ BKE_tracking_disable_channels(postproc_ibuf, disable_red, disable_green, disable_blue, 1);
+ }
- return postproc_ibuf;
+ return postproc_ibuf;
}
-static void put_postprocessed_frame_to_cache(MovieClip *clip,
- const MovieClipUser *user,
- ImBuf *ibuf,
- int flag,
- int postprocess_flag)
+static void put_postprocessed_frame_to_cache(
+ MovieClip *clip, const MovieClipUser *user, ImBuf *ibuf, int flag, int postprocess_flag)
+{
+ MovieClipCache *cache = clip->cache;
+ MovieTrackingCamera *camera = &clip->tracking.camera;
+
+ cache->postprocessed.framenr = user->framenr;
+ cache->postprocessed.flag = postprocess_flag;
+
+ if (flag & MCLIP_USE_PROXY) {
+ cache->postprocessed.proxy = rendersize_to_proxy(user, flag);
+ cache->postprocessed.render_flag = user->render_flag;
+ }
+ else {
+ cache->postprocessed.proxy = IMB_PROXY_NONE;
+ cache->postprocessed.render_flag = 0;
+ }
+
+ if (need_undistortion_postprocess(user, flag)) {
+ cache->postprocessed.distortion_model = camera->distortion_model;
+ copy_v2_v2(cache->postprocessed.principal, camera->principal);
+ copy_v3_v3(&cache->postprocessed.polynomial_k1, &camera->k1);
+ copy_v2_v2(&cache->postprocessed.division_k1, &camera->division_k1);
+ cache->postprocessed.undistortion_used = true;
+ }
+ else {
+ cache->postprocessed.undistortion_used = false;
+ }
+
+ IMB_refImBuf(ibuf);
+
+ if (cache->postprocessed.ibuf)
+ IMB_freeImBuf(cache->postprocessed.ibuf);
+
+ cache->postprocessed.ibuf = ibuf;
+}
+
+static ImBuf *movieclip_get_postprocessed_ibuf(
+ MovieClip *clip, const MovieClipUser *user, int flag, int postprocess_flag, int cache_flag)
{
- MovieClipCache *cache = clip->cache;
- MovieTrackingCamera *camera = &clip->tracking.camera;
-
- cache->postprocessed.framenr = user->framenr;
- cache->postprocessed.flag = postprocess_flag;
-
- if (flag & MCLIP_USE_PROXY) {
- cache->postprocessed.proxy = rendersize_to_proxy(user, flag);
- cache->postprocessed.render_flag = user->render_flag;
- }
- else {
- cache->postprocessed.proxy = IMB_PROXY_NONE;
- cache->postprocessed.render_flag = 0;
- }
-
- if (need_undistortion_postprocess(user, flag)) {
- cache->postprocessed.distortion_model = camera->distortion_model;
- copy_v2_v2(cache->postprocessed.principal, camera->principal);
- copy_v3_v3(&cache->postprocessed.polynomial_k1, &camera->k1);
- copy_v2_v2(&cache->postprocessed.division_k1, &camera->division_k1);
- cache->postprocessed.undistortion_used = true;
- }
- else {
- cache->postprocessed.undistortion_used = false;
- }
-
- IMB_refImBuf(ibuf);
-
- if (cache->postprocessed.ibuf)
- IMB_freeImBuf(cache->postprocessed.ibuf);
-
- cache->postprocessed.ibuf = ibuf;
-}
-
-static ImBuf *movieclip_get_postprocessed_ibuf(MovieClip *clip,
- const MovieClipUser *user,
- int flag,
- int postprocess_flag,
- int cache_flag)
-{
- ImBuf *ibuf = NULL;
- int framenr = user->framenr;
- bool need_postprocess = false;
-
- /* cache isn't threadsafe itself and also loading of movies
- * can't happen from concurrent threads that's why we use lock here */
- BLI_thread_lock(LOCK_MOVIECLIP);
-
- /* try to obtain cached postprocessed frame first */
- if (need_postprocessed_frame(user, flag, postprocess_flag)) {
- ibuf = get_postprocessed_cached_frame(clip, user, flag, postprocess_flag);
-
- if (!ibuf)
- need_postprocess = true;
- }
-
- if (!ibuf)
- ibuf = get_imbuf_cache(clip, user, flag);
-
- if (!ibuf) {
- bool use_sequence = false;
-
- /* undistorted proxies for movies should be read as image sequence */
- use_sequence = (user->render_flag & MCLIP_PROXY_RENDER_UNDISTORT) &&
- (user->render_size != MCLIP_PROXY_RENDER_SIZE_FULL);
-
- if (clip->source == MCLIP_SRC_SEQUENCE || use_sequence) {
- ibuf = movieclip_load_sequence_file(clip, user, framenr, flag);
- }
- else {
- ibuf = movieclip_load_movie_file(clip, user, framenr, flag);
- }
-
- if (ibuf && (cache_flag & MOVIECLIP_CACHE_SKIP) == 0) {
- put_imbuf_cache(clip, user, ibuf, flag, true);
- }
- }
-
- if (ibuf) {
- clip->lastframe = framenr;
- real_ibuf_size(clip, user, ibuf, &clip->lastsize[0], &clip->lastsize[1]);
-
- /* postprocess frame and put to cache if needed*/
- if (need_postprocess) {
- ImBuf *tmpibuf = ibuf;
- ibuf = postprocess_frame(clip, user, tmpibuf, flag, postprocess_flag);
- IMB_freeImBuf(tmpibuf);
- if (ibuf && (cache_flag & MOVIECLIP_CACHE_SKIP) == 0) {
- put_postprocessed_frame_to_cache(clip, user, ibuf, flag, postprocess_flag);
- }
- }
- }
-
- BLI_thread_unlock(LOCK_MOVIECLIP);
-
- /* Fallback render in case proxies are not enabled or built */
- if (!ibuf &&
- user->render_flag & MCLIP_PROXY_RENDER_USE_FALLBACK_RENDER &&
- user->render_size != MCLIP_PROXY_RENDER_SIZE_FULL)
- {
- MovieClipUser user_fallback = *user;
- user_fallback.render_size = MCLIP_PROXY_RENDER_SIZE_FULL;
-
- ibuf = movieclip_get_postprocessed_ibuf(clip, &user_fallback, flag, postprocess_flag, cache_flag);
- }
-
- return ibuf;
+ ImBuf *ibuf = NULL;
+ int framenr = user->framenr;
+ bool need_postprocess = false;
+
+ /* cache isn't threadsafe itself and also loading of movies
+ * can't happen from concurrent threads that's why we use lock here */
+ BLI_thread_lock(LOCK_MOVIECLIP);
+
+ /* try to obtain cached postprocessed frame first */
+ if (need_postprocessed_frame(user, flag, postprocess_flag)) {
+ ibuf = get_postprocessed_cached_frame(clip, user, flag, postprocess_flag);
+
+ if (!ibuf)
+ need_postprocess = true;
+ }
+
+ if (!ibuf)
+ ibuf = get_imbuf_cache(clip, user, flag);
+
+ if (!ibuf) {
+ bool use_sequence = false;
+
+ /* undistorted proxies for movies should be read as image sequence */
+ use_sequence = (user->render_flag & MCLIP_PROXY_RENDER_UNDISTORT) &&
+ (user->render_size != MCLIP_PROXY_RENDER_SIZE_FULL);
+
+ if (clip->source == MCLIP_SRC_SEQUENCE || use_sequence) {
+ ibuf = movieclip_load_sequence_file(clip, user, framenr, flag);
+ }
+ else {
+ ibuf = movieclip_load_movie_file(clip, user, framenr, flag);
+ }
+
+ if (ibuf && (cache_flag & MOVIECLIP_CACHE_SKIP) == 0) {
+ put_imbuf_cache(clip, user, ibuf, flag, true);
+ }
+ }
+
+ if (ibuf) {
+ clip->lastframe = framenr;
+ real_ibuf_size(clip, user, ibuf, &clip->lastsize[0], &clip->lastsize[1]);
+
+ /* postprocess frame and put to cache if needed*/
+ if (need_postprocess) {
+ ImBuf *tmpibuf = ibuf;
+ ibuf = postprocess_frame(clip, user, tmpibuf, flag, postprocess_flag);
+ IMB_freeImBuf(tmpibuf);
+ if (ibuf && (cache_flag & MOVIECLIP_CACHE_SKIP) == 0) {
+ put_postprocessed_frame_to_cache(clip, user, ibuf, flag, postprocess_flag);
+ }
+ }
+ }
+
+ BLI_thread_unlock(LOCK_MOVIECLIP);
+
+ /* Fallback render in case proxies are not enabled or built */
+ if (!ibuf && user->render_flag & MCLIP_PROXY_RENDER_USE_FALLBACK_RENDER &&
+ user->render_size != MCLIP_PROXY_RENDER_SIZE_FULL) {
+ MovieClipUser user_fallback = *user;
+ user_fallback.render_size = MCLIP_PROXY_RENDER_SIZE_FULL;
+
+ ibuf = movieclip_get_postprocessed_ibuf(
+ clip, &user_fallback, flag, postprocess_flag, cache_flag);
+ }
+
+ return ibuf;
}
ImBuf *BKE_movieclip_get_ibuf(MovieClip *clip, MovieClipUser *user)
{
- return BKE_movieclip_get_ibuf_flag(clip, user, clip->flag, 0);
+ return BKE_movieclip_get_ibuf_flag(clip, user, clip->flag, 0);
}
ImBuf *BKE_movieclip_get_ibuf_flag(MovieClip *clip, MovieClipUser *user, int flag, int cache_flag)
{
- return movieclip_get_postprocessed_ibuf(clip, user, flag, 0, cache_flag);
+ return movieclip_get_postprocessed_ibuf(clip, user, flag, 0, cache_flag);
}
-ImBuf *BKE_movieclip_get_postprocessed_ibuf(MovieClip *clip, MovieClipUser *user, int postprocess_flag)
+ImBuf *BKE_movieclip_get_postprocessed_ibuf(MovieClip *clip,
+ MovieClipUser *user,
+ int postprocess_flag)
{
- return movieclip_get_postprocessed_ibuf(clip, user, clip->flag, postprocess_flag, 0);
+ return movieclip_get_postprocessed_ibuf(clip, user, clip->flag, postprocess_flag, 0);
}
-static ImBuf *get_stable_cached_frame(MovieClip *clip, MovieClipUser *user, ImBuf *reference_ibuf,
- int framenr, int postprocess_flag)
+static ImBuf *get_stable_cached_frame(
+ MovieClip *clip, MovieClipUser *user, ImBuf *reference_ibuf, int framenr, int postprocess_flag)
{
- MovieClipCache *cache = clip->cache;
- MovieTracking *tracking = &clip->tracking;
- ImBuf *stableibuf;
- float tloc[2], tscale, tangle;
- short proxy = IMB_PROXY_NONE;
- int render_flag = 0;
- int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, framenr);
+ MovieClipCache *cache = clip->cache;
+ MovieTracking *tracking = &clip->tracking;
+ ImBuf *stableibuf;
+ float tloc[2], tscale, tangle;
+ short proxy = IMB_PROXY_NONE;
+ int render_flag = 0;
+ int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, framenr);
- if (clip->flag & MCLIP_USE_PROXY) {
- proxy = rendersize_to_proxy(user, clip->flag);
- render_flag = user->render_flag;
- }
+ if (clip->flag & MCLIP_USE_PROXY) {
+ proxy = rendersize_to_proxy(user, clip->flag);
+ render_flag = user->render_flag;
+ }
- /* there's no cached frame or it was calculated for another frame */
- if (!cache->stabilized.ibuf || cache->stabilized.framenr != framenr)
- return NULL;
+ /* there's no cached frame or it was calculated for another frame */
+ if (!cache->stabilized.ibuf || cache->stabilized.framenr != framenr)
+ return NULL;
- if (cache->stabilized.reference_ibuf != reference_ibuf)
- return NULL;
+ if (cache->stabilized.reference_ibuf != reference_ibuf)
+ return NULL;
- /* cached ibuf used different proxy settings */
- if (cache->stabilized.render_flag != render_flag || cache->stabilized.proxy != proxy)
- return NULL;
+ /* cached ibuf used different proxy settings */
+ if (cache->stabilized.render_flag != render_flag || cache->stabilized.proxy != proxy)
+ return NULL;
- if (cache->stabilized.postprocess_flag != postprocess_flag)
- return NULL;
+ if (cache->stabilized.postprocess_flag != postprocess_flag)
+ return NULL;
- /* stabilization also depends on pixel aspect ratio */
- if (cache->stabilized.aspect != tracking->camera.pixel_aspect)
- return NULL;
+ /* stabilization also depends on pixel aspect ratio */
+ if (cache->stabilized.aspect != tracking->camera.pixel_aspect)
+ return NULL;
- if (cache->stabilized.filter != tracking->stabilization.filter)
- return NULL;
+ if (cache->stabilized.filter != tracking->stabilization.filter)
+ return NULL;
- stableibuf = cache->stabilized.ibuf;
+ stableibuf = cache->stabilized.ibuf;
- BKE_tracking_stabilization_data_get(clip, clip_framenr, stableibuf->x, stableibuf->y, tloc, &tscale, &tangle);
+ BKE_tracking_stabilization_data_get(
+ clip, clip_framenr, stableibuf->x, stableibuf->y, tloc, &tscale, &tangle);
- /* check for stabilization parameters */
- if (tscale != cache->stabilized.scale ||
- tangle != cache->stabilized.angle ||
- !equals_v2v2(tloc, cache->stabilized.loc))
- {
- return NULL;
- }
+ /* check for stabilization parameters */
+ if (tscale != cache->stabilized.scale || tangle != cache->stabilized.angle ||
+ !equals_v2v2(tloc, cache->stabilized.loc)) {
+ return NULL;
+ }
- IMB_refImBuf(stableibuf);
+ IMB_refImBuf(stableibuf);
- return stableibuf;
+ return stableibuf;
}
-static ImBuf *put_stabilized_frame_to_cache(MovieClip *clip, MovieClipUser *user, ImBuf *ibuf,
- int framenr, int postprocess_flag)
+static ImBuf *put_stabilized_frame_to_cache(
+ MovieClip *clip, MovieClipUser *user, ImBuf *ibuf, int framenr, int postprocess_flag)
{
- MovieClipCache *cache = clip->cache;
- MovieTracking *tracking = &clip->tracking;
- ImBuf *stableibuf;
- float tloc[2], tscale, tangle;
- int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, framenr);
+ MovieClipCache *cache = clip->cache;
+ MovieTracking *tracking = &clip->tracking;
+ ImBuf *stableibuf;
+ float tloc[2], tscale, tangle;
+ int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, framenr);
- stableibuf = BKE_tracking_stabilize_frame(clip, clip_framenr, ibuf, tloc, &tscale, &tangle);
+ stableibuf = BKE_tracking_stabilize_frame(clip, clip_framenr, ibuf, tloc, &tscale, &tangle);
- copy_v2_v2(cache->stabilized.loc, tloc);
+ copy_v2_v2(cache->stabilized.loc, tloc);
- cache->stabilized.reference_ibuf = ibuf;
- cache->stabilized.scale = tscale;
- cache->stabilized.angle = tangle;
- cache->stabilized.framenr = framenr;
- cache->stabilized.aspect = tracking->camera.pixel_aspect;
- cache->stabilized.filter = tracking->stabilization.filter;
+ cache->stabilized.reference_ibuf = ibuf;
+ cache->stabilized.scale = tscale;
+ cache->stabilized.angle = tangle;
+ cache->stabilized.framenr = framenr;
+ cache->stabilized.aspect = tracking->camera.pixel_aspect;
+ cache->stabilized.filter = tracking->stabilization.filter;
- if (clip->flag & MCLIP_USE_PROXY) {
- cache->stabilized.proxy = rendersize_to_proxy(user, clip->flag);
- cache->stabilized.render_flag = user->render_flag;
- }
- else {
- cache->stabilized.proxy = IMB_PROXY_NONE;
- cache->stabilized.render_flag = 0;
- }
+ if (clip->flag & MCLIP_USE_PROXY) {
+ cache->stabilized.proxy = rendersize_to_proxy(user, clip->flag);
+ cache->stabilized.render_flag = user->render_flag;
+ }
+ else {
+ cache->stabilized.proxy = IMB_PROXY_NONE;
+ cache->stabilized.render_flag = 0;
+ }
- cache->stabilized.postprocess_flag = postprocess_flag;
+ cache->stabilized.postprocess_flag = postprocess_flag;
- if (cache->stabilized.ibuf)
- IMB_freeImBuf(cache->stabilized.ibuf);
+ if (cache->stabilized.ibuf)
+ IMB_freeImBuf(cache->stabilized.ibuf);
- cache->stabilized.ibuf = stableibuf;
+ cache->stabilized.ibuf = stableibuf;
- IMB_refImBuf(stableibuf);
+ IMB_refImBuf(stableibuf);
- return stableibuf;
+ return stableibuf;
}
-ImBuf *BKE_movieclip_get_stable_ibuf(MovieClip *clip, MovieClipUser *user, float loc[2], float *scale, float *angle,
+ImBuf *BKE_movieclip_get_stable_ibuf(MovieClip *clip,
+ MovieClipUser *user,
+ float loc[2],
+ float *scale,
+ float *angle,
int postprocess_flag)
{
- ImBuf *ibuf, *stableibuf = NULL;
- int framenr = user->framenr;
+ ImBuf *ibuf, *stableibuf = NULL;
+ int framenr = user->framenr;
- ibuf = BKE_movieclip_get_postprocessed_ibuf(clip, user, postprocess_flag);
+ ibuf = BKE_movieclip_get_postprocessed_ibuf(clip, user, postprocess_flag);
- if (!ibuf)
- return NULL;
+ if (!ibuf)
+ return NULL;
- if (clip->tracking.stabilization.flag & TRACKING_2D_STABILIZATION) {
- MovieClipCache *cache = clip->cache;
+ if (clip->tracking.stabilization.flag & TRACKING_2D_STABILIZATION) {
+ MovieClipCache *cache = clip->cache;
- stableibuf = get_stable_cached_frame(clip, user, ibuf, framenr, postprocess_flag);
+ stableibuf = get_stable_cached_frame(clip, user, ibuf, framenr, postprocess_flag);
- if (!stableibuf)
- stableibuf = put_stabilized_frame_to_cache(clip, user, ibuf, framenr, postprocess_flag);
+ if (!stableibuf)
+ stableibuf = put_stabilized_frame_to_cache(clip, user, ibuf, framenr, postprocess_flag);
- if (loc)
- copy_v2_v2(loc, cache->stabilized.loc);
+ if (loc)
+ copy_v2_v2(loc, cache->stabilized.loc);
- if (scale)
- *scale = cache->stabilized.scale;
+ if (scale)
+ *scale = cache->stabilized.scale;
- if (angle)
- *angle = cache->stabilized.angle;
- }
- else {
- if (loc)
- zero_v2(loc);
+ if (angle)
+ *angle = cache->stabilized.angle;
+ }
+ else {
+ if (loc)
+ zero_v2(loc);
- if (scale)
- *scale = 1.0f;
+ if (scale)
+ *scale = 1.0f;
- if (angle)
- *angle = 0.0f;
+ if (angle)
+ *angle = 0.0f;
- stableibuf = ibuf;
- }
+ stableibuf = ibuf;
+ }
- if (stableibuf != ibuf) {
- IMB_freeImBuf(ibuf);
- ibuf = stableibuf;
- }
-
- return ibuf;
+ if (stableibuf != ibuf) {
+ IMB_freeImBuf(ibuf);
+ ibuf = stableibuf;
+ }
+ return ibuf;
}
bool BKE_movieclip_has_frame(MovieClip *clip, MovieClipUser *user)
{
- ImBuf *ibuf = BKE_movieclip_get_ibuf(clip, user);
+ ImBuf *ibuf = BKE_movieclip_get_ibuf(clip, user);
- if (ibuf) {
- IMB_freeImBuf(ibuf);
- return true;
- }
+ if (ibuf) {
+ IMB_freeImBuf(ibuf);
+ return true;
+ }
- return false;
+ return false;
}
void BKE_movieclip_get_size(MovieClip *clip, MovieClipUser *user, int *width, int *height)
{
#if 0
- /* originally was needed to support image sequences with different image dimensions,
- * which might be useful for such things as reconstruction of unordered image sequence,
- * or painting/rotoscoping of non-equal-sized images, but this ended up in unneeded
- * cache lookups and even unwanted non-proxied files loading when doing mask parenting,
- * so let's disable this for now and assume image sequence consists of images with
- * equal sizes (sergey)
- * TODO(sergey): Support reading sequences of different resolution.
- */
- if (user->framenr == clip->lastframe) {
+ /* originally was needed to support image sequences with different image dimensions,
+ * which might be useful for such things as reconstruction of unordered image sequence,
+ * or painting/rotoscoping of non-equal-sized images, but this ended up in unneeded
+ * cache lookups and even unwanted non-proxied files loading when doing mask parenting,
+ * so let's disable this for now and assume image sequence consists of images with
+ * equal sizes (sergey)
+ * TODO(sergey): Support reading sequences of different resolution.
+ */
+ if (user->framenr == clip->lastframe) {
#endif
- if (clip->lastsize[0] != 0 && clip->lastsize[1] != 0) {
- *width = clip->lastsize[0];
- *height = clip->lastsize[1];
- }
- else {
- ImBuf *ibuf = BKE_movieclip_get_ibuf(clip, user);
-
- if (ibuf && ibuf->x && ibuf->y) {
- real_ibuf_size(clip, user, ibuf, width, height);
- }
- else {
- *width = clip->lastsize[0];
- *height = clip->lastsize[1];
- }
-
- if (ibuf)
- IMB_freeImBuf(ibuf);
- }
+ if (clip->lastsize[0] != 0 && clip->lastsize[1] != 0) {
+ *width = clip->lastsize[0];
+ *height = clip->lastsize[1];
+ }
+ else {
+ ImBuf *ibuf = BKE_movieclip_get_ibuf(clip, user);
+
+ if (ibuf && ibuf->x && ibuf->y) {
+ real_ibuf_size(clip, user, ibuf, width, height);
+ }
+ else {
+ *width = clip->lastsize[0];
+ *height = clip->lastsize[1];
+ }
+
+ if (ibuf)
+ IMB_freeImBuf(ibuf);
+ }
}
void BKE_movieclip_get_size_fl(MovieClip *clip, MovieClipUser *user, float size[2])
{
- int width, height;
- BKE_movieclip_get_size(clip, user, &width, &height);
+ int width, height;
+ BKE_movieclip_get_size(clip, user, &width, &height);
- size[0] = (float)width;
- size[1] = (float)height;
+ size[0] = (float)width;
+ size[1] = (float)height;
}
int BKE_movieclip_get_duration(MovieClip *clip)
{
- if (!clip->len) {
- movieclip_calc_length(clip);
- }
+ if (!clip->len) {
+ movieclip_calc_length(clip);
+ }
- return clip->len;
+ return clip->len;
}
float BKE_movieclip_get_fps(MovieClip *clip)
{
- if (clip->source != MCLIP_SRC_MOVIE) {
- return 0.0f;
- }
- movieclip_open_anim_file(clip);
- if (clip->anim == NULL) {
- return 0.0f;
- }
- short frs_sec;
- float frs_sec_base;
- if (IMB_anim_get_fps(clip->anim, &frs_sec, &frs_sec_base, true)) {
- return (float)frs_sec / frs_sec_base;
- }
- return 0.0f;
+ if (clip->source != MCLIP_SRC_MOVIE) {
+ return 0.0f;
+ }
+ movieclip_open_anim_file(clip);
+ if (clip->anim == NULL) {
+ return 0.0f;
+ }
+ short frs_sec;
+ float frs_sec_base;
+ if (IMB_anim_get_fps(clip->anim, &frs_sec, &frs_sec_base, true)) {
+ return (float)frs_sec / frs_sec_base;
+ }
+ return 0.0f;
}
void BKE_movieclip_get_aspect(MovieClip *clip, float *aspx, float *aspy)
{
- *aspx = 1.0;
+ *aspx = 1.0;
- /* x is always 1 */
- *aspy = clip->aspy / clip->aspx / clip->tracking.camera.pixel_aspect;
+ /* x is always 1 */
+ *aspy = clip->aspy / clip->aspx / clip->tracking.camera.pixel_aspect;
}
/* get segments of cached frames. useful for debugging cache policies */
-void BKE_movieclip_get_cache_segments(MovieClip *clip, MovieClipUser *user, int *r_totseg, int **r_points)
+void BKE_movieclip_get_cache_segments(MovieClip *clip,
+ MovieClipUser *user,
+ int *r_totseg,
+ int **r_points)
{
- *r_totseg = 0;
- *r_points = NULL;
+ *r_totseg = 0;
+ *r_points = NULL;
- if (clip->cache) {
- int proxy = rendersize_to_proxy(user, clip->flag);
+ if (clip->cache) {
+ int proxy = rendersize_to_proxy(user, clip->flag);
- IMB_moviecache_get_cache_segments(clip->cache->moviecache, proxy, user->render_flag, r_totseg, r_points);
- }
+ IMB_moviecache_get_cache_segments(
+ clip->cache->moviecache, proxy, user->render_flag, r_totseg, r_points);
+ }
}
void BKE_movieclip_user_set_frame(MovieClipUser *iuser, int framenr)
{
- /* TODO: clamp framenr here? */
+ /* TODO: clamp framenr here? */
- iuser->framenr = framenr;
+ iuser->framenr = framenr;
}
static void free_buffers(MovieClip *clip)
{
- if (clip->cache) {
- IMB_moviecache_free(clip->cache->moviecache);
+ if (clip->cache) {
+ IMB_moviecache_free(clip->cache->moviecache);
- if (clip->cache->postprocessed.ibuf)
- IMB_freeImBuf(clip->cache->postprocessed.ibuf);
+ if (clip->cache->postprocessed.ibuf)
+ IMB_freeImBuf(clip->cache->postprocessed.ibuf);
- if (clip->cache->stabilized.ibuf)
- IMB_freeImBuf(clip->cache->stabilized.ibuf);
+ if (clip->cache->stabilized.ibuf)
+ IMB_freeImBuf(clip->cache->stabilized.ibuf);
- MEM_freeN(clip->cache);
- clip->cache = NULL;
- }
+ MEM_freeN(clip->cache);
+ clip->cache = NULL;
+ }
- if (clip->anim) {
- IMB_free_anim(clip->anim);
- clip->anim = NULL;
- }
+ if (clip->anim) {
+ IMB_free_anim(clip->anim);
+ clip->anim = NULL;
+ }
}
void BKE_movieclip_clear_cache(MovieClip *clip)
{
- free_buffers(clip);
+ free_buffers(clip);
}
void BKE_movieclip_clear_proxy_cache(MovieClip *clip)
{
- if (clip->cache && clip->cache->moviecache) {
- IMB_moviecache_cleanup(clip->cache->moviecache,
- moviecache_check_free_proxy,
- NULL);
- }
+ if (clip->cache && clip->cache->moviecache) {
+ IMB_moviecache_cleanup(clip->cache->moviecache, moviecache_check_free_proxy, NULL);
+ }
}
void BKE_movieclip_reload(Main *bmain, MovieClip *clip)
{
- /* clear cache */
- free_buffers(clip);
+ /* clear cache */
+ free_buffers(clip);
- /* update clip source */
- detect_clip_source(bmain, clip);
+ /* update clip source */
+ detect_clip_source(bmain, clip);
- clip->lastsize[0] = clip->lastsize[1] = 0;
- movieclip_load_get_size(clip);
+ clip->lastsize[0] = clip->lastsize[1] = 0;
+ movieclip_load_get_size(clip);
- movieclip_calc_length(clip);
+ movieclip_calc_length(clip);
- /* same as for image update -- don't use notifiers because they are not 100% sure to succeeded
- * (node trees which are not currently visible wouldn't be refreshed)
- */
- {
- Scene *scene;
- for (scene = bmain->scenes.first; scene; scene = scene->id.next) {
- if (scene->nodetree) {
- nodeUpdateID(scene->nodetree, &clip->id);
- }
- }
- }
+ /* same as for image update -- don't use notifiers because they are not 100% sure to succeeded
+ * (node trees which are not currently visible wouldn't be refreshed)
+ */
+ {
+ Scene *scene;
+ for (scene = bmain->scenes.first; scene; scene = scene->id.next) {
+ if (scene->nodetree) {
+ nodeUpdateID(scene->nodetree, &clip->id);
+ }
+ }
+ }
}
void BKE_movieclip_update_scopes(MovieClip *clip, MovieClipUser *user, MovieClipScopes *scopes)
{
- if (scopes->ok)
- return;
+ if (scopes->ok)
+ return;
- if (scopes->track_preview) {
- IMB_freeImBuf(scopes->track_preview);
- scopes->track_preview = NULL;
- }
+ if (scopes->track_preview) {
+ IMB_freeImBuf(scopes->track_preview);
+ scopes->track_preview = NULL;
+ }
- if (scopes->track_search) {
- IMB_freeImBuf(scopes->track_search);
- scopes->track_search = NULL;
- }
+ if (scopes->track_search) {
+ IMB_freeImBuf(scopes->track_search);
+ scopes->track_search = NULL;
+ }
- scopes->marker = NULL;
- scopes->track = NULL;
- scopes->track_locked = true;
+ scopes->marker = NULL;
+ scopes->track = NULL;
+ scopes->track_locked = true;
- if (clip) {
- MovieTrackingTrack *act_track = BKE_tracking_track_get_active(&clip->tracking);
+ if (clip) {
+ MovieTrackingTrack *act_track = BKE_tracking_track_get_active(&clip->tracking);
- if (act_track) {
- MovieTrackingTrack *track = act_track;
- int framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, user->framenr);
- MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
+ if (act_track) {
+ MovieTrackingTrack *track = act_track;
+ int framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, user->framenr);
+ MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
- scopes->marker = marker;
- scopes->track = track;
+ scopes->marker = marker;
+ scopes->track = track;
- if (marker->flag & MARKER_DISABLED) {
- scopes->track_disabled = true;
- }
- else {
- ImBuf *ibuf = BKE_movieclip_get_ibuf(clip, user);
+ if (marker->flag & MARKER_DISABLED) {
+ scopes->track_disabled = true;
+ }
+ else {
+ ImBuf *ibuf = BKE_movieclip_get_ibuf(clip, user);
- scopes->track_disabled = false;
+ scopes->track_disabled = false;
- if (ibuf && (ibuf->rect || ibuf->rect_float)) {
- MovieTrackingMarker undist_marker = *marker;
+ if (ibuf && (ibuf->rect || ibuf->rect_float)) {
+ MovieTrackingMarker undist_marker = *marker;
- if (user->render_flag & MCLIP_PROXY_RENDER_UNDISTORT) {
- int width, height;
- float aspy = 1.0f / clip->tracking.camera.pixel_aspect;
+ if (user->render_flag & MCLIP_PROXY_RENDER_UNDISTORT) {
+ int width, height;
+ float aspy = 1.0f / clip->tracking.camera.pixel_aspect;
- BKE_movieclip_get_size(clip, user, &width, &height);
+ BKE_movieclip_get_size(clip, user, &width, &height);
- undist_marker.pos[0] *= width;
- undist_marker.pos[1] *= height * aspy;
+ undist_marker.pos[0] *= width;
+ undist_marker.pos[1] *= height * aspy;
- BKE_tracking_undistort_v2(&clip->tracking, undist_marker.pos, undist_marker.pos);
+ BKE_tracking_undistort_v2(&clip->tracking, undist_marker.pos, undist_marker.pos);
- undist_marker.pos[0] /= width;
- undist_marker.pos[1] /= height * aspy;
- }
+ undist_marker.pos[0] /= width;
+ undist_marker.pos[1] /= height * aspy;
+ }
- scopes->track_search = BKE_tracking_get_search_imbuf(ibuf, track, &undist_marker, true, true);
+ scopes->track_search = BKE_tracking_get_search_imbuf(
+ ibuf, track, &undist_marker, true, true);
- scopes->undist_marker = undist_marker;
+ scopes->undist_marker = undist_marker;
- scopes->frame_width = ibuf->x;
- scopes->frame_height = ibuf->y;
+ scopes->frame_width = ibuf->x;
+ scopes->frame_height = ibuf->y;
- scopes->use_track_mask = (track->flag & TRACK_PREVIEW_ALPHA) != 0;
- }
+ scopes->use_track_mask = (track->flag & TRACK_PREVIEW_ALPHA) != 0;
+ }
- IMB_freeImBuf(ibuf);
- }
+ IMB_freeImBuf(ibuf);
+ }
- if ((track->flag & TRACK_LOCKED) == 0) {
- float pat_min[2], pat_max[2];
+ if ((track->flag & TRACK_LOCKED) == 0) {
+ float pat_min[2], pat_max[2];
- scopes->track_locked = false;
+ scopes->track_locked = false;
- /* XXX: would work fine with non-transformed patterns, but would likely fail
- * with transformed patterns, but that would be easier to debug when
- * we'll have real pattern sampling (at least to test) */
- BKE_tracking_marker_pattern_minmax(marker, pat_min, pat_max);
+ /* XXX: would work fine with non-transformed patterns, but would likely fail
+ * with transformed patterns, but that would be easier to debug when
+ * we'll have real pattern sampling (at least to test) */
+ BKE_tracking_marker_pattern_minmax(marker, pat_min, pat_max);
- scopes->slide_scale[0] = pat_max[0] - pat_min[0];
- scopes->slide_scale[1] = pat_max[1] - pat_min[1];
- }
- }
- }
+ scopes->slide_scale[0] = pat_max[0] - pat_min[0];
+ scopes->slide_scale[1] = pat_max[1] - pat_min[1];
+ }
+ }
+ }
- scopes->framenr = user->framenr;
- scopes->ok = true;
+ scopes->framenr = user->framenr;
+ scopes->ok = true;
}
-static void movieclip_build_proxy_ibuf(MovieClip *clip, ImBuf *ibuf, int cfra, int proxy_render_size, bool undistorted, bool threaded)
+static void movieclip_build_proxy_ibuf(
+ MovieClip *clip, ImBuf *ibuf, int cfra, int proxy_render_size, bool undistorted, bool threaded)
{
- char name[FILE_MAX];
- int quality, rectx, recty;
- int size = rendersize_to_number(proxy_render_size);
- ImBuf *scaleibuf;
+ char name[FILE_MAX];
+ int quality, rectx, recty;
+ int size = rendersize_to_number(proxy_render_size);
+ ImBuf *scaleibuf;
- get_proxy_fname(clip, proxy_render_size, undistorted, cfra, name);
+ get_proxy_fname(clip, proxy_render_size, undistorted, cfra, name);
- rectx = ibuf->x * size / 100.0f;
- recty = ibuf->y * size / 100.0f;
+ rectx = ibuf->x * size / 100.0f;
+ recty = ibuf->y * size / 100.0f;
- scaleibuf = IMB_dupImBuf(ibuf);
+ scaleibuf = IMB_dupImBuf(ibuf);
- if (threaded)
- IMB_scaleImBuf_threaded(scaleibuf, (short)rectx, (short)recty);
- else
- IMB_scaleImBuf(scaleibuf, (short)rectx, (short)recty);
+ if (threaded)
+ IMB_scaleImBuf_threaded(scaleibuf, (short)rectx, (short)recty);
+ else
+ IMB_scaleImBuf(scaleibuf, (short)rectx, (short)recty);
- quality = clip->proxy.quality;
- scaleibuf->ftype = IMB_FTYPE_JPG;
- scaleibuf->foptions.quality = quality;
- /* unsupported feature only confuses other s/w */
- if (scaleibuf->planes == 32)
- scaleibuf->planes = 24;
+ quality = clip->proxy.quality;
+ scaleibuf->ftype = IMB_FTYPE_JPG;
+ scaleibuf->foptions.quality = quality;
+ /* unsupported feature only confuses other s/w */
+ if (scaleibuf->planes == 32)
+ scaleibuf->planes = 24;
- /* TODO: currently the most weak part of multithreaded proxies,
- * could be solved in a way that thread only prepares memory
- * buffer and write to disk happens separately
- */
- BLI_thread_lock(LOCK_MOVIECLIP);
+ /* TODO: currently the most weak part of multithreaded proxies,
+ * could be solved in a way that thread only prepares memory
+ * buffer and write to disk happens separately
+ */
+ BLI_thread_lock(LOCK_MOVIECLIP);
- BLI_make_existing_file(name);
- if (IMB_saveiff(scaleibuf, name, IB_rect) == 0)
- perror(name);
+ BLI_make_existing_file(name);
+ if (IMB_saveiff(scaleibuf, name, IB_rect) == 0)
+ perror(name);
- BLI_thread_unlock(LOCK_MOVIECLIP);
+ BLI_thread_unlock(LOCK_MOVIECLIP);
- IMB_freeImBuf(scaleibuf);
+ IMB_freeImBuf(scaleibuf);
}
/* note: currently used by proxy job for movies, threading happens within single frame
* (meaning scaling shall be threaded)
*/
-void BKE_movieclip_build_proxy_frame(MovieClip *clip, int clip_flag, struct MovieDistortion *distortion,
- int cfra, int *build_sizes, int build_count, bool undistorted)
+void BKE_movieclip_build_proxy_frame(MovieClip *clip,
+ int clip_flag,
+ struct MovieDistortion *distortion,
+ int cfra,
+ int *build_sizes,
+ int build_count,
+ bool undistorted)
{
- ImBuf *ibuf;
- MovieClipUser user;
+ ImBuf *ibuf;
+ MovieClipUser user;
- if (!build_count)
- return;
+ if (!build_count)
+ return;
- user.framenr = cfra;
- user.render_flag = 0;
- user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL;
+ user.framenr = cfra;
+ user.render_flag = 0;
+ user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL;
- ibuf = BKE_movieclip_get_ibuf_flag(clip, &user, clip_flag, MOVIECLIP_CACHE_SKIP);
+ ibuf = BKE_movieclip_get_ibuf_flag(clip, &user, clip_flag, MOVIECLIP_CACHE_SKIP);
- if (ibuf) {
- ImBuf *tmpibuf = ibuf;
- int i;
+ if (ibuf) {
+ ImBuf *tmpibuf = ibuf;
+ int i;
- if (undistorted)
- tmpibuf = get_undistorted_ibuf(clip, distortion, ibuf);
+ if (undistorted)
+ tmpibuf = get_undistorted_ibuf(clip, distortion, ibuf);
- for (i = 0; i < build_count; i++)
- movieclip_build_proxy_ibuf(clip, tmpibuf, cfra, build_sizes[i], undistorted, true);
+ for (i = 0; i < build_count; i++)
+ movieclip_build_proxy_ibuf(clip, tmpibuf, cfra, build_sizes[i], undistorted, true);
- IMB_freeImBuf(ibuf);
+ IMB_freeImBuf(ibuf);
- if (tmpibuf != ibuf)
- IMB_freeImBuf(tmpibuf);
- }
+ if (tmpibuf != ibuf)
+ IMB_freeImBuf(tmpibuf);
+ }
}
/* note: currently used by proxy job for sequences, threading happens within sequence
* (different threads handles different frames, no threading within frame is needed)
*/
-void BKE_movieclip_build_proxy_frame_for_ibuf(MovieClip *clip, ImBuf *ibuf, struct MovieDistortion *distortion,
- int cfra, int *build_sizes, int build_count, bool undistorted)
+void BKE_movieclip_build_proxy_frame_for_ibuf(MovieClip *clip,
+ ImBuf *ibuf,
+ struct MovieDistortion *distortion,
+ int cfra,
+ int *build_sizes,
+ int build_count,
+ bool undistorted)
{
- if (!build_count)
- return;
+ if (!build_count)
+ return;
- if (ibuf) {
- ImBuf *tmpibuf = ibuf;
- int i;
+ if (ibuf) {
+ ImBuf *tmpibuf = ibuf;
+ int i;
- if (undistorted)
- tmpibuf = get_undistorted_ibuf(clip, distortion, ibuf);
+ if (undistorted)
+ tmpibuf = get_undistorted_ibuf(clip, distortion, ibuf);
- for (i = 0; i < build_count; i++)
- movieclip_build_proxy_ibuf(clip, tmpibuf, cfra, build_sizes[i], undistorted, false);
+ for (i = 0; i < build_count; i++)
+ movieclip_build_proxy_ibuf(clip, tmpibuf, cfra, build_sizes[i], undistorted, false);
- if (tmpibuf != ibuf)
- IMB_freeImBuf(tmpibuf);
- }
+ if (tmpibuf != ibuf)
+ IMB_freeImBuf(tmpibuf);
+ }
}
/** Free (or release) any data used by this movie clip (does not free the clip itself). */
void BKE_movieclip_free(MovieClip *clip)
{
- /* Also frees animdata. */
- free_buffers(clip);
+ /* Also frees animdata. */
+ free_buffers(clip);
- BKE_tracking_free(&clip->tracking);
- BKE_animdata_free((ID *) clip, false);
+ BKE_tracking_free(&clip->tracking);
+ BKE_animdata_free((ID *)clip, false);
}
/**
@@ -1598,149 +1573,150 @@ void BKE_movieclip_free(MovieClip *clip)
*
* \param flag: Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
*/
-void BKE_movieclip_copy_data(Main *UNUSED(bmain), MovieClip *clip_dst, const MovieClip *clip_src, const int flag)
+void BKE_movieclip_copy_data(Main *UNUSED(bmain),
+ MovieClip *clip_dst,
+ const MovieClip *clip_src,
+ const int flag)
{
- /* We never handle usercount here for own data. */
- const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
+ /* We never handle usercount here for own data. */
+ const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
- clip_dst->anim = NULL;
- clip_dst->cache = NULL;
+ clip_dst->anim = NULL;
+ clip_dst->cache = NULL;
- BKE_tracking_copy(&clip_dst->tracking, &clip_src->tracking, flag_subdata);
- clip_dst->tracking_context = NULL;
+ BKE_tracking_copy(&clip_dst->tracking, &clip_src->tracking, flag_subdata);
+ clip_dst->tracking_context = NULL;
- BKE_color_managed_colorspace_settings_copy(&clip_dst->colorspace_settings, &clip_src->colorspace_settings);
+ BKE_color_managed_colorspace_settings_copy(&clip_dst->colorspace_settings,
+ &clip_src->colorspace_settings);
}
MovieClip *BKE_movieclip_copy(Main *bmain, const MovieClip *clip)
{
- MovieClip *clip_copy;
- BKE_id_copy(bmain, &clip->id, (ID **)&clip_copy);
- return clip_copy;
+ MovieClip *clip_copy;
+ BKE_id_copy(bmain, &clip->id, (ID **)&clip_copy);
+ return clip_copy;
}
void BKE_movieclip_make_local(Main *bmain, MovieClip *clip, const bool lib_local)
{
- BKE_id_make_local_generic(bmain, &clip->id, true, lib_local);
+ BKE_id_make_local_generic(bmain, &clip->id, true, lib_local);
}
float BKE_movieclip_remap_scene_to_clip_frame(const MovieClip *clip, float framenr)
{
- return framenr - (float) clip->start_frame + 1.0f;
+ return framenr - (float)clip->start_frame + 1.0f;
}
float BKE_movieclip_remap_clip_to_scene_frame(const MovieClip *clip, float framenr)
{
- return framenr + (float) clip->start_frame - 1.0f;
+ return framenr + (float)clip->start_frame - 1.0f;
}
void BKE_movieclip_filename_for_frame(MovieClip *clip, MovieClipUser *user, char *name)
{
- if (clip->source == MCLIP_SRC_SEQUENCE) {
- int use_proxy;
+ if (clip->source == MCLIP_SRC_SEQUENCE) {
+ int use_proxy;
- use_proxy = (clip->flag & MCLIP_USE_PROXY) && user->render_size != MCLIP_PROXY_RENDER_SIZE_FULL;
+ use_proxy = (clip->flag & MCLIP_USE_PROXY) &&
+ user->render_size != MCLIP_PROXY_RENDER_SIZE_FULL;
- if (use_proxy) {
- int undistort = user->render_flag & MCLIP_PROXY_RENDER_UNDISTORT;
- get_proxy_fname(clip, user->render_size, undistort, user->framenr, name);
- }
- else {
- get_sequence_fname(clip, user->framenr, name);
- }
- }
- else {
- BLI_strncpy(name, clip->name, FILE_MAX);
- BLI_path_abs(name, ID_BLEND_PATH_FROM_GLOBAL(&clip->id));
- }
+ if (use_proxy) {
+ int undistort = user->render_flag & MCLIP_PROXY_RENDER_UNDISTORT;
+ get_proxy_fname(clip, user->render_size, undistort, user->framenr, name);
+ }
+ else {
+ get_sequence_fname(clip, user->framenr, name);
+ }
+ }
+ else {
+ BLI_strncpy(name, clip->name, FILE_MAX);
+ BLI_path_abs(name, ID_BLEND_PATH_FROM_GLOBAL(&clip->id));
+ }
}
ImBuf *BKE_movieclip_anim_ibuf_for_frame(MovieClip *clip, MovieClipUser *user)
{
- ImBuf *ibuf = NULL;
+ ImBuf *ibuf = NULL;
- if (clip->source == MCLIP_SRC_MOVIE) {
- BLI_thread_lock(LOCK_MOVIECLIP);
- ibuf = movieclip_load_movie_file(clip, user, user->framenr, clip->flag);
- BLI_thread_unlock(LOCK_MOVIECLIP);
- }
+ if (clip->source == MCLIP_SRC_MOVIE) {
+ BLI_thread_lock(LOCK_MOVIECLIP);
+ ibuf = movieclip_load_movie_file(clip, user, user->framenr, clip->flag);
+ BLI_thread_unlock(LOCK_MOVIECLIP);
+ }
- return ibuf;
+ return ibuf;
}
bool BKE_movieclip_has_cached_frame(MovieClip *clip, MovieClipUser *user)
{
- bool has_frame = false;
+ bool has_frame = false;
- BLI_thread_lock(LOCK_MOVIECLIP);
- has_frame = has_imbuf_cache(clip, user, clip->flag);
- BLI_thread_unlock(LOCK_MOVIECLIP);
+ BLI_thread_lock(LOCK_MOVIECLIP);
+ has_frame = has_imbuf_cache(clip, user, clip->flag);
+ BLI_thread_unlock(LOCK_MOVIECLIP);
- return has_frame;
+ return has_frame;
}
-bool BKE_movieclip_put_frame_if_possible(MovieClip *clip,
- MovieClipUser *user,
- ImBuf *ibuf)
+bool BKE_movieclip_put_frame_if_possible(MovieClip *clip, MovieClipUser *user, ImBuf *ibuf)
{
- bool result;
+ bool result;
- BLI_thread_lock(LOCK_MOVIECLIP);
- result = put_imbuf_cache(clip, user, ibuf, clip->flag, false);
- BLI_thread_unlock(LOCK_MOVIECLIP);
+ BLI_thread_lock(LOCK_MOVIECLIP);
+ result = put_imbuf_cache(clip, user, ibuf, clip->flag, false);
+ BLI_thread_unlock(LOCK_MOVIECLIP);
- return result;
+ return result;
}
static void movieclip_selection_synchronize(MovieClip *clip_dst, const MovieClip *clip_src)
{
- BLI_assert(clip_dst != clip_src);
- MovieTracking *tracking_dst = &clip_dst->tracking, tracking_src = clip_src->tracking;
- /* Syncs the active object, track and plane track. */
- tracking_dst->objectnr = tracking_src.objectnr;
- const int active_track_index = BLI_findindex(&tracking_src.tracks, tracking_src.act_track);
- const int active_plane_track_index = BLI_findindex(&tracking_src.plane_tracks, tracking_src.act_plane_track);
- tracking_dst->act_track = BLI_findlink(&tracking_dst->tracks, active_track_index);
- tracking_dst->act_plane_track = BLI_findlink(&tracking_dst->plane_tracks, active_plane_track_index);
-
- /* Syncs the tracking selection flag. */
- MovieTrackingObject *tracking_object_dst, *tracking_object_src;
- tracking_object_src = tracking_src.objects.first;
-
- for (tracking_object_dst = tracking_dst->objects.first;
- tracking_object_dst != NULL;
- tracking_object_dst = tracking_object_dst->next,
- tracking_object_src = tracking_object_src->next)
- {
- ListBase *tracksbase_dst, *tracksbase_src;
- tracksbase_dst = BKE_tracking_object_get_tracks(tracking_dst, tracking_object_dst);
- tracksbase_src = BKE_tracking_object_get_tracks(&tracking_src, tracking_object_src);
-
- MovieTrackingTrack *track_dst, *track_src;
- track_src = tracksbase_src->first;
- for (track_dst = tracksbase_dst->first;
- track_dst != NULL;
- track_dst = track_dst->next, track_src = track_src->next)
- {
- track_dst->flag = track_src->flag;
- track_dst->pat_flag = track_src->pat_flag;
- track_dst->search_flag = track_src->search_flag;
- }
- }
+ BLI_assert(clip_dst != clip_src);
+ MovieTracking *tracking_dst = &clip_dst->tracking, tracking_src = clip_src->tracking;
+ /* Syncs the active object, track and plane track. */
+ tracking_dst->objectnr = tracking_src.objectnr;
+ const int active_track_index = BLI_findindex(&tracking_src.tracks, tracking_src.act_track);
+ const int active_plane_track_index = BLI_findindex(&tracking_src.plane_tracks,
+ tracking_src.act_plane_track);
+ tracking_dst->act_track = BLI_findlink(&tracking_dst->tracks, active_track_index);
+ tracking_dst->act_plane_track = BLI_findlink(&tracking_dst->plane_tracks,
+ active_plane_track_index);
+
+ /* Syncs the tracking selection flag. */
+ MovieTrackingObject *tracking_object_dst, *tracking_object_src;
+ tracking_object_src = tracking_src.objects.first;
+
+ for (tracking_object_dst = tracking_dst->objects.first; tracking_object_dst != NULL;
+ tracking_object_dst = tracking_object_dst->next,
+ tracking_object_src = tracking_object_src->next) {
+ ListBase *tracksbase_dst, *tracksbase_src;
+ tracksbase_dst = BKE_tracking_object_get_tracks(tracking_dst, tracking_object_dst);
+ tracksbase_src = BKE_tracking_object_get_tracks(&tracking_src, tracking_object_src);
+
+ MovieTrackingTrack *track_dst, *track_src;
+ track_src = tracksbase_src->first;
+ for (track_dst = tracksbase_dst->first; track_dst != NULL;
+ track_dst = track_dst->next, track_src = track_src->next) {
+ track_dst->flag = track_src->flag;
+ track_dst->pat_flag = track_src->pat_flag;
+ track_dst->search_flag = track_src->search_flag;
+ }
+ }
}
void BKE_movieclip_eval_update(struct Depsgraph *depsgraph, MovieClip *clip)
{
- DEG_debug_print_eval(depsgraph, __func__, clip->id.name, clip);
- BKE_tracking_dopesheet_tag_update(&clip->tracking);
- if (DEG_is_active(depsgraph)) {
- MovieClip *clip_orig = (MovieClip *)DEG_get_original_id(&clip->id);
- BKE_tracking_dopesheet_tag_update(&clip_orig->tracking);
- }
+ DEG_debug_print_eval(depsgraph, __func__, clip->id.name, clip);
+ BKE_tracking_dopesheet_tag_update(&clip->tracking);
+ if (DEG_is_active(depsgraph)) {
+ MovieClip *clip_orig = (MovieClip *)DEG_get_original_id(&clip->id);
+ BKE_tracking_dopesheet_tag_update(&clip_orig->tracking);
+ }
}
void BKE_movieclip_eval_selection_update(struct Depsgraph *depsgraph, MovieClip *clip)
{
- DEG_debug_print_eval(depsgraph, __func__, clip->id.name, clip);
- movieclip_selection_synchronize(clip, (MovieClip *)clip->id.orig_id);
+ DEG_debug_print_eval(depsgraph, __func__, clip->id.name, clip);
+ movieclip_selection_synchronize(clip, (MovieClip *)clip->id.orig_id);
}
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c
index e546119b86d..5e404f7e264 100644
--- a/source/blender/blenkernel/intern/multires.c
+++ b/source/blender/blenkernel/intern/multires.c
@@ -21,7 +21,6 @@
* \ingroup bke
*/
-
#include "MEM_guardedalloc.h"
/* for reading old multires */
@@ -63,251 +62,241 @@
/* MULTIRES MODIFIER */
static const int multires_max_levels = 13;
-static const int multires_grid_tot[] = {0, 4, 9, 25, 81, 289, 1089, 4225, 16641, 66049, 263169, 1050625, 4198401, 16785409};
-static const int multires_side_tot[] = {0, 2, 3, 5, 9, 17, 33, 65, 129, 257, 513, 1025, 2049, 4097};
+static const int multires_grid_tot[] = {
+ 0, 4, 9, 25, 81, 289, 1089, 4225, 16641, 66049, 263169, 1050625, 4198401, 16785409};
+static const int multires_side_tot[] = {
+ 0, 2, 3, 5, 9, 17, 33, 65, 129, 257, 513, 1025, 2049, 4097};
/* See multiresModifier_disp_run for description of each operation */
typedef enum {
- APPLY_DISPLACEMENTS,
- CALC_DISPLACEMENTS,
- ADD_DISPLACEMENTS,
+ APPLY_DISPLACEMENTS,
+ CALC_DISPLACEMENTS,
+ ADD_DISPLACEMENTS,
} DispOp;
static void multires_mvert_to_ss(DerivedMesh *dm, MVert *mvert);
-static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, DerivedMesh *dm2, DispOp op, CCGElem **oldGridData, int totlvl);
+static void multiresModifier_disp_run(
+ DerivedMesh *dm, Mesh *me, DerivedMesh *dm2, DispOp op, CCGElem **oldGridData, int totlvl);
/** Customdata */
void multires_customdata_delete(Mesh *me)
{
- if (me->edit_mesh) {
- BMEditMesh *em = me->edit_mesh;
- /* CustomData_external_remove is used here only to mark layer
- * as non-external for further free-ing, so zero element count
- * looks safer than em->totface */
- CustomData_external_remove(&em->bm->ldata, &me->id,
- CD_MDISPS, 0);
- BM_data_layer_free(em->bm, &em->bm->ldata, CD_MDISPS);
+ if (me->edit_mesh) {
+ BMEditMesh *em = me->edit_mesh;
+ /* CustomData_external_remove is used here only to mark layer
+ * as non-external for further free-ing, so zero element count
+ * looks safer than em->totface */
+ CustomData_external_remove(&em->bm->ldata, &me->id, CD_MDISPS, 0);
+ BM_data_layer_free(em->bm, &em->bm->ldata, CD_MDISPS);
- BM_data_layer_free(em->bm, &em->bm->ldata, CD_GRID_PAINT_MASK);
- }
- else {
- CustomData_external_remove(&me->ldata, &me->id,
- CD_MDISPS, me->totloop);
- CustomData_free_layer_active(&me->ldata, CD_MDISPS,
- me->totloop);
+ BM_data_layer_free(em->bm, &em->bm->ldata, CD_GRID_PAINT_MASK);
+ }
+ else {
+ CustomData_external_remove(&me->ldata, &me->id, CD_MDISPS, me->totloop);
+ CustomData_free_layer_active(&me->ldata, CD_MDISPS, me->totloop);
- CustomData_free_layer_active(&me->ldata, CD_GRID_PAINT_MASK,
- me->totloop);
- }
+ CustomData_free_layer_active(&me->ldata, CD_GRID_PAINT_MASK, me->totloop);
+ }
}
/** Grid hiding */
-static BLI_bitmap *multires_mdisps_upsample_hidden(
- BLI_bitmap *lo_hidden,
- int lo_level, int hi_level,
-
- /* assumed to be at hi_level (or null) */
- const BLI_bitmap *prev_hidden)
-{
- BLI_bitmap *subd;
- int hi_gridsize = BKE_ccg_gridsize(hi_level);
- int lo_gridsize = BKE_ccg_gridsize(lo_level);
- int yh, xh, xl, yl, xo, yo, hi_ndx;
- int offset, factor;
-
- BLI_assert(lo_level <= hi_level);
-
- /* fast case */
- if (lo_level == hi_level)
- return MEM_dupallocN(lo_hidden);
-
- subd = BLI_BITMAP_NEW(SQUARE(hi_gridsize), "MDisps.hidden upsample");
-
- factor = BKE_ccg_factor(lo_level, hi_level);
- offset = 1 << (hi_level - lo_level - 1);
-
- /* low-res blocks */
- for (yl = 0; yl < lo_gridsize; yl++) {
- for (xl = 0; xl < lo_gridsize; xl++) {
- int lo_val = BLI_BITMAP_TEST(lo_hidden, yl * lo_gridsize + xl);
-
- /* high-res blocks */
- for (yo = -offset; yo <= offset; yo++) {
- yh = yl * factor + yo;
- if (yh < 0 || yh >= hi_gridsize)
- continue;
-
- for (xo = -offset; xo <= offset; xo++) {
- xh = xl * factor + xo;
- if (xh < 0 || xh >= hi_gridsize)
- continue;
-
- hi_ndx = yh * hi_gridsize + xh;
-
- if (prev_hidden) {
- /* If prev_hidden is available, copy it to
- * subd, except when the equivalent element in
- * lo_hidden is different */
- if (lo_val != prev_hidden[hi_ndx]) {
- BLI_BITMAP_SET(subd, hi_ndx, lo_val);
- }
- else {
- BLI_BITMAP_SET(subd, hi_ndx, prev_hidden[hi_ndx]);
- }
- }
- else {
- BLI_BITMAP_SET(subd, hi_ndx, lo_val);
- }
- }
- }
- }
- }
-
- return subd;
+static BLI_bitmap *multires_mdisps_upsample_hidden(BLI_bitmap *lo_hidden,
+ int lo_level,
+ int hi_level,
+
+ /* assumed to be at hi_level (or null) */
+ const BLI_bitmap *prev_hidden)
+{
+ BLI_bitmap *subd;
+ int hi_gridsize = BKE_ccg_gridsize(hi_level);
+ int lo_gridsize = BKE_ccg_gridsize(lo_level);
+ int yh, xh, xl, yl, xo, yo, hi_ndx;
+ int offset, factor;
+
+ BLI_assert(lo_level <= hi_level);
+
+ /* fast case */
+ if (lo_level == hi_level)
+ return MEM_dupallocN(lo_hidden);
+
+ subd = BLI_BITMAP_NEW(SQUARE(hi_gridsize), "MDisps.hidden upsample");
+
+ factor = BKE_ccg_factor(lo_level, hi_level);
+ offset = 1 << (hi_level - lo_level - 1);
+
+ /* low-res blocks */
+ for (yl = 0; yl < lo_gridsize; yl++) {
+ for (xl = 0; xl < lo_gridsize; xl++) {
+ int lo_val = BLI_BITMAP_TEST(lo_hidden, yl * lo_gridsize + xl);
+
+ /* high-res blocks */
+ for (yo = -offset; yo <= offset; yo++) {
+ yh = yl * factor + yo;
+ if (yh < 0 || yh >= hi_gridsize)
+ continue;
+
+ for (xo = -offset; xo <= offset; xo++) {
+ xh = xl * factor + xo;
+ if (xh < 0 || xh >= hi_gridsize)
+ continue;
+
+ hi_ndx = yh * hi_gridsize + xh;
+
+ if (prev_hidden) {
+ /* If prev_hidden is available, copy it to
+ * subd, except when the equivalent element in
+ * lo_hidden is different */
+ if (lo_val != prev_hidden[hi_ndx]) {
+ BLI_BITMAP_SET(subd, hi_ndx, lo_val);
+ }
+ else {
+ BLI_BITMAP_SET(subd, hi_ndx, prev_hidden[hi_ndx]);
+ }
+ }
+ else {
+ BLI_BITMAP_SET(subd, hi_ndx, lo_val);
+ }
+ }
+ }
+ }
+ }
+
+ return subd;
}
static BLI_bitmap *multires_mdisps_downsample_hidden(BLI_bitmap *old_hidden,
int old_level,
int new_level)
{
- BLI_bitmap *new_hidden;
- int new_gridsize = BKE_ccg_gridsize(new_level);
- int old_gridsize = BKE_ccg_gridsize(old_level);
- int x, y, factor, old_value;
-
- BLI_assert(new_level <= old_level);
- factor = BKE_ccg_factor(new_level, old_level);
- new_hidden = BLI_BITMAP_NEW(SQUARE(new_gridsize), "downsample hidden");
+ BLI_bitmap *new_hidden;
+ int new_gridsize = BKE_ccg_gridsize(new_level);
+ int old_gridsize = BKE_ccg_gridsize(old_level);
+ int x, y, factor, old_value;
+ BLI_assert(new_level <= old_level);
+ factor = BKE_ccg_factor(new_level, old_level);
+ new_hidden = BLI_BITMAP_NEW(SQUARE(new_gridsize), "downsample hidden");
- for (y = 0; y < new_gridsize; y++) {
- for (x = 0; x < new_gridsize; x++) {
- old_value = BLI_BITMAP_TEST(old_hidden,
- factor * y * old_gridsize + x * factor);
+ for (y = 0; y < new_gridsize; y++) {
+ for (x = 0; x < new_gridsize; x++) {
+ old_value = BLI_BITMAP_TEST(old_hidden, factor * y * old_gridsize + x * factor);
- BLI_BITMAP_SET(new_hidden, y * new_gridsize + x, old_value);
- }
- }
+ BLI_BITMAP_SET(new_hidden, y * new_gridsize + x, old_value);
+ }
+ }
- return new_hidden;
+ return new_hidden;
}
-static void multires_output_hidden_to_ccgdm(CCGDerivedMesh *ccgdm,
- Mesh *me, int level)
+static void multires_output_hidden_to_ccgdm(CCGDerivedMesh *ccgdm, Mesh *me, int level)
{
- const MDisps *mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
- BLI_bitmap **grid_hidden = ccgdm->gridHidden;
- int *gridOffset;
- int i, j;
+ const MDisps *mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
+ BLI_bitmap **grid_hidden = ccgdm->gridHidden;
+ int *gridOffset;
+ int i, j;
- gridOffset = ccgdm->dm.getGridOffset(&ccgdm->dm);
+ gridOffset = ccgdm->dm.getGridOffset(&ccgdm->dm);
- for (i = 0; i < me->totpoly; i++) {
- for (j = 0; j < me->mpoly[i].totloop; j++) {
- int g = gridOffset[i] + j;
- const MDisps *md = &mdisps[g];
- BLI_bitmap *gh = md->hidden;
+ for (i = 0; i < me->totpoly; i++) {
+ for (j = 0; j < me->mpoly[i].totloop; j++) {
+ int g = gridOffset[i] + j;
+ const MDisps *md = &mdisps[g];
+ BLI_bitmap *gh = md->hidden;
- if (gh) {
- grid_hidden[g] =
- multires_mdisps_downsample_hidden(gh, md->level, level);
- }
- }
- }
+ if (gh) {
+ grid_hidden[g] = multires_mdisps_downsample_hidden(gh, md->level, level);
+ }
+ }
+ }
}
/* subdivide mdisps.hidden if needed (assumes that md.level reflects
* the current level of md.hidden) */
static void multires_mdisps_subdivide_hidden(MDisps *md, int new_level)
{
- BLI_bitmap *subd;
+ BLI_bitmap *subd;
- BLI_assert(md->hidden);
+ BLI_assert(md->hidden);
- /* nothing to do if already subdivided enough */
- if (md->level >= new_level)
- return;
+ /* nothing to do if already subdivided enough */
+ if (md->level >= new_level)
+ return;
- subd = multires_mdisps_upsample_hidden(md->hidden,
- md->level,
- new_level,
- NULL);
+ subd = multires_mdisps_upsample_hidden(md->hidden, md->level, new_level, NULL);
- /* swap in the subdivided data */
- MEM_freeN(md->hidden);
- md->hidden = subd;
+ /* swap in the subdivided data */
+ MEM_freeN(md->hidden);
+ md->hidden = subd;
}
static MDisps *multires_mdisps_initialize_hidden(Mesh *me, int level)
{
- MDisps *mdisps = CustomData_add_layer(&me->ldata, CD_MDISPS,
- CD_CALLOC, NULL, me->totloop);
- int gridsize = BKE_ccg_gridsize(level);
- int gridarea = SQUARE(gridsize);
- int i, j;
+ MDisps *mdisps = CustomData_add_layer(&me->ldata, CD_MDISPS, CD_CALLOC, NULL, me->totloop);
+ int gridsize = BKE_ccg_gridsize(level);
+ int gridarea = SQUARE(gridsize);
+ int i, j;
- for (i = 0; i < me->totpoly; i++) {
- bool hide = false;
+ for (i = 0; i < me->totpoly; i++) {
+ bool hide = false;
- for (j = 0; j < me->mpoly[i].totloop; j++) {
- if (me->mvert[me->mloop[me->mpoly[i].loopstart + j].v].flag & ME_HIDE) {
- hide = true;
- break;
- }
- }
+ for (j = 0; j < me->mpoly[i].totloop; j++) {
+ if (me->mvert[me->mloop[me->mpoly[i].loopstart + j].v].flag & ME_HIDE) {
+ hide = true;
+ break;
+ }
+ }
- if (!hide)
- continue;
+ if (!hide)
+ continue;
- for (j = 0; j < me->mpoly[i].totloop; j++) {
- MDisps *md = &mdisps[me->mpoly[i].loopstart + j];
+ for (j = 0; j < me->mpoly[i].totloop; j++) {
+ MDisps *md = &mdisps[me->mpoly[i].loopstart + j];
- BLI_assert(!md->hidden);
+ BLI_assert(!md->hidden);
- md->hidden = BLI_BITMAP_NEW(gridarea, "MDisps.hidden initialize");
- BLI_bitmap_set_all(md->hidden, true, gridarea);
- }
- }
+ md->hidden = BLI_BITMAP_NEW(gridarea, "MDisps.hidden initialize");
+ BLI_bitmap_set_all(md->hidden, true, gridarea);
+ }
+ }
- return mdisps;
+ return mdisps;
}
-Mesh *BKE_multires_create_mesh(
- struct Depsgraph *depsgraph,
- Scene *scene,
- MultiresModifierData *mmd,
- Object *ob)
+Mesh *BKE_multires_create_mesh(struct Depsgraph *depsgraph,
+ Scene *scene,
+ MultiresModifierData *mmd,
+ Object *ob)
{
- Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
- Mesh *deformed_mesh = mesh_get_eval_deform(depsgraph, scene, ob_eval, &CD_MASK_BAREMESH);
- ModifierEvalContext modifier_ctx = {
- .depsgraph = depsgraph,
- .object = ob_eval,
- .flag = MOD_APPLY_USECACHE | MOD_APPLY_IGNORE_SIMPLIFY,
- };
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ Mesh *deformed_mesh = mesh_get_eval_deform(depsgraph, scene, ob_eval, &CD_MASK_BAREMESH);
+ ModifierEvalContext modifier_ctx = {
+ .depsgraph = depsgraph,
+ .object = ob_eval,
+ .flag = MOD_APPLY_USECACHE | MOD_APPLY_IGNORE_SIMPLIFY,
+ };
- const ModifierTypeInfo *mti = modifierType_getInfo(mmd->modifier.type);
- Mesh *result = mti->applyModifier(&mmd->modifier, &modifier_ctx, deformed_mesh);
+ const ModifierTypeInfo *mti = modifierType_getInfo(mmd->modifier.type);
+ Mesh *result = mti->applyModifier(&mmd->modifier, &modifier_ctx, deformed_mesh);
- if (result == deformed_mesh) {
- result = BKE_mesh_copy_for_eval(deformed_mesh, true);
- }
- return result;
+ if (result == deformed_mesh) {
+ result = BKE_mesh_copy_for_eval(deformed_mesh, true);
+ }
+ return result;
}
MultiresModifierData *find_multires_modifier_before(Scene *scene, ModifierData *lastmd)
{
- ModifierData *md;
+ ModifierData *md;
- for (md = lastmd; md; md = md->prev) {
- if (md->type == eModifierType_Multires) {
- if (modifier_isEnabled(scene, md, eModifierMode_Realtime))
- return (MultiresModifierData *)md;
- }
- }
+ for (md = lastmd; md; md = md->prev) {
+ if (md->type == eModifierType_Multires) {
+ if (modifier_isEnabled(scene, md, eModifierMode_Realtime))
+ return (MultiresModifierData *)md;
+ }
+ }
- return NULL;
+ return NULL;
}
/* used for applying scale on mdisps layer and syncing subdivide levels when joining objects
@@ -315,1113 +304,1158 @@ MultiresModifierData *find_multires_modifier_before(Scene *scene, ModifierData *
*/
MultiresModifierData *get_multires_modifier(Scene *scene, Object *ob, bool use_first)
{
- ModifierData *md;
- MultiresModifierData *mmd = NULL, *firstmmd = NULL;
+ ModifierData *md;
+ MultiresModifierData *mmd = NULL, *firstmmd = NULL;
- /* find first active multires modifier */
- for (md = ob->modifiers.first; md; md = md->next) {
- if (md->type == eModifierType_Multires) {
- if (!firstmmd)
- firstmmd = (MultiresModifierData *)md;
+ /* find first active multires modifier */
+ for (md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_Multires) {
+ if (!firstmmd)
+ firstmmd = (MultiresModifierData *)md;
- if (modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
- mmd = (MultiresModifierData *)md;
- break;
- }
- }
- }
+ if (modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
+ mmd = (MultiresModifierData *)md;
+ break;
+ }
+ }
+ }
- if (!mmd && use_first) {
- /* active multires have not been found
- * try to use first one */
- return firstmmd;
- }
+ if (!mmd && use_first) {
+ /* active multires have not been found
+ * try to use first one */
+ return firstmmd;
+ }
- return mmd;
+ return mmd;
}
-int multires_get_level(const Scene *scene, const Object *ob, const MultiresModifierData *mmd,
- bool render, bool ignore_simplify)
+int multires_get_level(const Scene *scene,
+ const Object *ob,
+ const MultiresModifierData *mmd,
+ bool render,
+ bool ignore_simplify)
{
- if (render)
- return (scene != NULL) ? get_render_subsurf_level(&scene->r, mmd->renderlvl, true) : mmd->renderlvl;
- else if (ob->mode == OB_MODE_SCULPT)
- return mmd->sculptlvl;
- else if (ignore_simplify)
- return mmd->lvl;
- else
- return (scene != NULL) ? get_render_subsurf_level(&scene->r, mmd->lvl, false) : mmd->lvl;
+ if (render)
+ return (scene != NULL) ? get_render_subsurf_level(&scene->r, mmd->renderlvl, true) :
+ mmd->renderlvl;
+ else if (ob->mode == OB_MODE_SCULPT)
+ return mmd->sculptlvl;
+ else if (ignore_simplify)
+ return mmd->lvl;
+ else
+ return (scene != NULL) ? get_render_subsurf_level(&scene->r, mmd->lvl, false) : mmd->lvl;
}
void multires_set_tot_level(Object *ob, MultiresModifierData *mmd, int lvl)
{
- mmd->totlvl = lvl;
+ mmd->totlvl = lvl;
- if (ob->mode != OB_MODE_SCULPT)
- mmd->lvl = CLAMPIS(MAX2(mmd->lvl, lvl), 0, mmd->totlvl);
+ if (ob->mode != OB_MODE_SCULPT)
+ mmd->lvl = CLAMPIS(MAX2(mmd->lvl, lvl), 0, mmd->totlvl);
- mmd->sculptlvl = CLAMPIS(MAX2(mmd->sculptlvl, lvl), 0, mmd->totlvl);
- mmd->renderlvl = CLAMPIS(MAX2(mmd->renderlvl, lvl), 0, mmd->totlvl);
+ mmd->sculptlvl = CLAMPIS(MAX2(mmd->sculptlvl, lvl), 0, mmd->totlvl);
+ mmd->renderlvl = CLAMPIS(MAX2(mmd->renderlvl, lvl), 0, mmd->totlvl);
}
static void multires_dm_mark_as_modified(DerivedMesh *dm, MultiresModifiedFlags flags)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
- ccgdm->multires.modified_flags |= flags;
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ ccgdm->multires.modified_flags |= flags;
}
-static void multires_ccg_mark_as_modified(SubdivCCG *subdiv_ccg,
- MultiresModifiedFlags flags)
+static void multires_ccg_mark_as_modified(SubdivCCG *subdiv_ccg, MultiresModifiedFlags flags)
{
- if (flags & MULTIRES_COORDS_MODIFIED) {
- subdiv_ccg->dirty.coords = true;
- }
- if (flags & MULTIRES_HIDDEN_MODIFIED) {
- subdiv_ccg->dirty.hidden = true;
- }
+ if (flags & MULTIRES_COORDS_MODIFIED) {
+ subdiv_ccg->dirty.coords = true;
+ }
+ if (flags & MULTIRES_HIDDEN_MODIFIED) {
+ subdiv_ccg->dirty.hidden = true;
+ }
}
void multires_mark_as_modified(Object *ob, MultiresModifiedFlags flags)
{
- if (ob == NULL) {
- return;
- }
- Mesh *mesh = ob->data;
- SubdivCCG *subdiv_ccg = mesh->runtime.subdiv_ccg;
- if (subdiv_ccg == NULL) {
- return;
- }
- multires_ccg_mark_as_modified(subdiv_ccg, flags);
+ if (ob == NULL) {
+ return;
+ }
+ Mesh *mesh = ob->data;
+ SubdivCCG *subdiv_ccg = mesh->runtime.subdiv_ccg;
+ if (subdiv_ccg == NULL) {
+ return;
+ }
+ multires_ccg_mark_as_modified(subdiv_ccg, flags);
}
void multires_force_update(Object *ob)
{
- if (ob == NULL) {
- return;
- }
- SculptSession *sculpt_session = ob->sculpt;
- if (sculpt_session != NULL && sculpt_session->pbvh != NULL) {
- PBVH *pbvh = sculpt_session->pbvh;
- if (BKE_pbvh_type(pbvh) == PBVH_GRIDS) {
- Mesh *mesh = ob->data;
- multiresModifier_reshapeFromCCG(
- sculpt_session->multires->totlvl, mesh, sculpt_session->subdiv_ccg);
- }
- else {
- /* NOTE: Disabled for until OpenSubdiv is enabled by default. */
- // BLI_assert(!"multires_force_update is used on non-grids PBVH");
- }
- BKE_pbvh_free(pbvh);
- ob->sculpt->pbvh = NULL;
- }
+ if (ob == NULL) {
+ return;
+ }
+ SculptSession *sculpt_session = ob->sculpt;
+ if (sculpt_session != NULL && sculpt_session->pbvh != NULL) {
+ PBVH *pbvh = sculpt_session->pbvh;
+ if (BKE_pbvh_type(pbvh) == PBVH_GRIDS) {
+ Mesh *mesh = ob->data;
+ multiresModifier_reshapeFromCCG(
+ sculpt_session->multires->totlvl, mesh, sculpt_session->subdiv_ccg);
+ }
+ else {
+ /* NOTE: Disabled for until OpenSubdiv is enabled by default. */
+ // BLI_assert(!"multires_force_update is used on non-grids PBVH");
+ }
+ BKE_pbvh_free(pbvh);
+ ob->sculpt->pbvh = NULL;
+ }
}
void multires_force_external_reload(Object *ob)
{
- Mesh *me = BKE_mesh_from_object(ob);
+ Mesh *me = BKE_mesh_from_object(ob);
- CustomData_external_reload(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop);
- multires_force_update(ob);
+ CustomData_external_reload(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop);
+ multires_force_update(ob);
}
void multires_force_render_update(Object *ob)
{
- if (ob && (ob->mode & OB_MODE_SCULPT) && modifiers_findByType(ob, eModifierType_Multires))
- multires_force_update(ob);
+ if (ob && (ob->mode & OB_MODE_SCULPT) && modifiers_findByType(ob, eModifierType_Multires))
+ multires_force_update(ob);
}
/* reset the multires levels to match the number of mdisps */
static int get_levels_from_disps(Object *ob)
{
- Mesh *me = ob->data;
- MDisps *mdisp, *md;
- int i, j, totlvl = 0;
-
- mdisp = CustomData_get_layer(&me->ldata, CD_MDISPS);
+ Mesh *me = ob->data;
+ MDisps *mdisp, *md;
+ int i, j, totlvl = 0;
- for (i = 0; i < me->totpoly; ++i) {
- md = mdisp + me->mpoly[i].loopstart;
+ mdisp = CustomData_get_layer(&me->ldata, CD_MDISPS);
- for (j = 0; j < me->mpoly[i].totloop; j++, md++) {
- if (md->totdisp == 0) continue;
+ for (i = 0; i < me->totpoly; ++i) {
+ md = mdisp + me->mpoly[i].loopstart;
- while (1) {
- int side = (1 << (totlvl - 1)) + 1;
- int lvl_totdisp = side * side;
- if (md->totdisp == lvl_totdisp)
- break;
- else if (md->totdisp < lvl_totdisp)
- totlvl--;
- else
- totlvl++;
+ for (j = 0; j < me->mpoly[i].totloop; j++, md++) {
+ if (md->totdisp == 0)
+ continue;
- }
+ while (1) {
+ int side = (1 << (totlvl - 1)) + 1;
+ int lvl_totdisp = side * side;
+ if (md->totdisp == lvl_totdisp)
+ break;
+ else if (md->totdisp < lvl_totdisp)
+ totlvl--;
+ else
+ totlvl++;
+ }
- break;
- }
- }
+ break;
+ }
+ }
- return totlvl;
+ return totlvl;
}
/* reset the multires levels to match the number of mdisps */
void multiresModifier_set_levels_from_disps(MultiresModifierData *mmd, Object *ob)
{
- Mesh *me = ob->data;
- MDisps *mdisp;
+ Mesh *me = ob->data;
+ MDisps *mdisp;
- if (me->edit_mesh)
- mdisp = CustomData_get_layer(&me->edit_mesh->bm->ldata, CD_MDISPS);
- else
- mdisp = CustomData_get_layer(&me->ldata, CD_MDISPS);
+ if (me->edit_mesh)
+ mdisp = CustomData_get_layer(&me->edit_mesh->bm->ldata, CD_MDISPS);
+ else
+ mdisp = CustomData_get_layer(&me->ldata, CD_MDISPS);
- if (mdisp) {
- mmd->totlvl = get_levels_from_disps(ob);
- mmd->lvl = MIN2(mmd->sculptlvl, mmd->totlvl);
- mmd->sculptlvl = MIN2(mmd->sculptlvl, mmd->totlvl);
- mmd->renderlvl = MIN2(mmd->renderlvl, mmd->totlvl);
- }
+ if (mdisp) {
+ mmd->totlvl = get_levels_from_disps(ob);
+ mmd->lvl = MIN2(mmd->sculptlvl, mmd->totlvl);
+ mmd->sculptlvl = MIN2(mmd->sculptlvl, mmd->totlvl);
+ mmd->renderlvl = MIN2(mmd->renderlvl, mmd->totlvl);
+ }
}
static void multires_set_tot_mdisps(Mesh *me, int lvl)
{
- MDisps *mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
- int i;
+ MDisps *mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
+ int i;
- if (mdisps) {
- for (i = 0; i < me->totloop; i++, mdisps++) {
- mdisps->totdisp = multires_grid_tot[lvl];
- mdisps->level = lvl;
- }
- }
+ if (mdisps) {
+ for (i = 0; i < me->totloop; i++, mdisps++) {
+ mdisps->totdisp = multires_grid_tot[lvl];
+ mdisps->level = lvl;
+ }
+ }
}
static void multires_reallocate_mdisps(int totloop, MDisps *mdisps, int lvl)
{
- int i;
+ int i;
- /* reallocate displacements to be filled in */
- for (i = 0; i < totloop; ++i) {
- int totdisp = multires_grid_tot[lvl];
- float (*disps)[3] = MEM_calloc_arrayN(totdisp, 3 * sizeof(float), "multires disps");
+ /* reallocate displacements to be filled in */
+ for (i = 0; i < totloop; ++i) {
+ int totdisp = multires_grid_tot[lvl];
+ float(*disps)[3] = MEM_calloc_arrayN(totdisp, 3 * sizeof(float), "multires disps");
- if (mdisps[i].disps)
- MEM_freeN(mdisps[i].disps);
+ if (mdisps[i].disps)
+ MEM_freeN(mdisps[i].disps);
- if (mdisps[i].level && mdisps[i].hidden)
- multires_mdisps_subdivide_hidden(&mdisps[i], lvl);
+ if (mdisps[i].level && mdisps[i].hidden)
+ multires_mdisps_subdivide_hidden(&mdisps[i], lvl);
- mdisps[i].disps = disps;
- mdisps[i].totdisp = totdisp;
- mdisps[i].level = lvl;
- }
+ mdisps[i].disps = disps;
+ mdisps[i].totdisp = totdisp;
+ mdisps[i].level = lvl;
+ }
}
static void multires_copy_grid(float (*gridA)[3], float (*gridB)[3], int sizeA, int sizeB)
{
- int x, y, j, skip;
+ int x, y, j, skip;
- if (sizeA > sizeB) {
- skip = (sizeA - 1) / (sizeB - 1);
+ if (sizeA > sizeB) {
+ skip = (sizeA - 1) / (sizeB - 1);
- for (j = 0, y = 0; y < sizeB; y++)
- for (x = 0; x < sizeB; x++, j++)
- copy_v3_v3(gridA[y * skip * sizeA + x * skip], gridB[j]);
- }
- else {
- skip = (sizeB - 1) / (sizeA - 1);
+ for (j = 0, y = 0; y < sizeB; y++)
+ for (x = 0; x < sizeB; x++, j++)
+ copy_v3_v3(gridA[y * skip * sizeA + x * skip], gridB[j]);
+ }
+ else {
+ skip = (sizeB - 1) / (sizeA - 1);
- for (j = 0, y = 0; y < sizeA; y++)
- for (x = 0; x < sizeA; x++, j++)
- copy_v3_v3(gridA[j], gridB[y * skip * sizeB + x * skip]);
- }
+ for (j = 0, y = 0; y < sizeA; y++)
+ for (x = 0; x < sizeA; x++, j++)
+ copy_v3_v3(gridA[j], gridB[y * skip * sizeB + x * skip]);
+ }
}
static void multires_copy_dm_grid(CCGElem *gridA, CCGElem *gridB, CCGKey *keyA, CCGKey *keyB)
{
- int x, y, j, skip;
+ int x, y, j, skip;
- if (keyA->grid_size > keyB->grid_size) {
- skip = (keyA->grid_size - 1) / (keyB->grid_size - 1);
+ if (keyA->grid_size > keyB->grid_size) {
+ skip = (keyA->grid_size - 1) / (keyB->grid_size - 1);
- for (j = 0, y = 0; y < keyB->grid_size; y++)
- for (x = 0; x < keyB->grid_size; x++, j++)
- memcpy(CCG_elem_offset_co(keyA, gridA, y * skip * keyA->grid_size + x * skip),
- CCG_elem_offset_co(keyB, gridB, j),
- keyA->elem_size);
- }
- else {
- skip = (keyB->grid_size - 1) / (keyA->grid_size - 1);
+ for (j = 0, y = 0; y < keyB->grid_size; y++)
+ for (x = 0; x < keyB->grid_size; x++, j++)
+ memcpy(CCG_elem_offset_co(keyA, gridA, y * skip * keyA->grid_size + x * skip),
+ CCG_elem_offset_co(keyB, gridB, j),
+ keyA->elem_size);
+ }
+ else {
+ skip = (keyB->grid_size - 1) / (keyA->grid_size - 1);
- for (j = 0, y = 0; y < keyA->grid_size; y++)
- for (x = 0; x < keyA->grid_size; x++, j++)
- memcpy(CCG_elem_offset_co(keyA, gridA, j),
- CCG_elem_offset_co(keyB, gridB, y * skip * keyB->grid_size + x * skip),
- keyA->elem_size);
- }
+ for (j = 0, y = 0; y < keyA->grid_size; y++)
+ for (x = 0; x < keyA->grid_size; x++, j++)
+ memcpy(CCG_elem_offset_co(keyA, gridA, j),
+ CCG_elem_offset_co(keyB, gridB, y * skip * keyB->grid_size + x * skip),
+ keyA->elem_size);
+ }
}
/* Reallocate gpm->data at a lower resolution and copy values over
* from the original high-resolution data */
static void multires_grid_paint_mask_downsample(GridPaintMask *gpm, int level)
{
- if (level < gpm->level) {
- int gridsize = BKE_ccg_gridsize(level);
- float *data = MEM_calloc_arrayN(SQUARE(gridsize), sizeof(float),
- "multires_grid_paint_mask_downsample");
- int x, y;
+ if (level < gpm->level) {
+ int gridsize = BKE_ccg_gridsize(level);
+ float *data = MEM_calloc_arrayN(
+ SQUARE(gridsize), sizeof(float), "multires_grid_paint_mask_downsample");
+ int x, y;
- for (y = 0; y < gridsize; y++) {
- for (x = 0; x < gridsize; x++) {
- data[y * gridsize + x] =
- paint_grid_paint_mask(gpm, level, x, y);
- }
- }
+ for (y = 0; y < gridsize; y++) {
+ for (x = 0; x < gridsize; x++) {
+ data[y * gridsize + x] = paint_grid_paint_mask(gpm, level, x, y);
+ }
+ }
- MEM_freeN(gpm->data);
- gpm->data = data;
- gpm->level = level;
- }
+ MEM_freeN(gpm->data);
+ gpm->data = data;
+ gpm->level = level;
+ }
}
static void multires_del_higher(MultiresModifierData *mmd, Object *ob, int lvl)
{
- Mesh *me = (Mesh *)ob->data;
- int levels = mmd->totlvl - lvl;
- MDisps *mdisps;
- GridPaintMask *gpm;
-
- multires_set_tot_mdisps(me, mmd->totlvl);
- CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop);
- mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
- gpm = CustomData_get_layer(&me->ldata, CD_GRID_PAINT_MASK);
-
- multires_force_update(ob);
-
- if (mdisps && levels > 0) {
- if (lvl > 0) {
- /* MLoop *ml = me->mloop; */ /*UNUSED*/
- int nsize = multires_side_tot[lvl];
- int hsize = multires_side_tot[mmd->totlvl];
- int i, j;
-
- for (i = 0; i < me->totpoly; ++i) {
- for (j = 0; j < me->mpoly[i].totloop; j++) {
- int g = me->mpoly[i].loopstart + j;
- MDisps *mdisp = &mdisps[g];
- float (*disps)[3], (*ndisps)[3], (*hdisps)[3];
- int totdisp = multires_grid_tot[lvl];
-
- disps = MEM_calloc_arrayN(totdisp, 3 * sizeof(float), "multires disps");
-
- ndisps = disps;
- hdisps = mdisp->disps;
-
- multires_copy_grid(ndisps, hdisps, nsize, hsize);
- if (mdisp->hidden) {
- BLI_bitmap *gh =
- multires_mdisps_downsample_hidden(mdisp->hidden,
- mdisp->level,
- lvl);
- MEM_freeN(mdisp->hidden);
- mdisp->hidden = gh;
- }
-
- ndisps += nsize * nsize;
- hdisps += hsize * hsize;
-
- MEM_freeN(mdisp->disps);
- mdisp->disps = disps;
- mdisp->totdisp = totdisp;
- mdisp->level = lvl;
-
- if (gpm) {
- multires_grid_paint_mask_downsample(&gpm[g], lvl);
- }
- }
- }
- }
- else {
- multires_customdata_delete(me);
- }
- }
-
- multires_set_tot_level(ob, mmd, lvl);
+ Mesh *me = (Mesh *)ob->data;
+ int levels = mmd->totlvl - lvl;
+ MDisps *mdisps;
+ GridPaintMask *gpm;
+
+ multires_set_tot_mdisps(me, mmd->totlvl);
+ CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop);
+ mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
+ gpm = CustomData_get_layer(&me->ldata, CD_GRID_PAINT_MASK);
+
+ multires_force_update(ob);
+
+ if (mdisps && levels > 0) {
+ if (lvl > 0) {
+ /* MLoop *ml = me->mloop; */ /*UNUSED*/
+ int nsize = multires_side_tot[lvl];
+ int hsize = multires_side_tot[mmd->totlvl];
+ int i, j;
+
+ for (i = 0; i < me->totpoly; ++i) {
+ for (j = 0; j < me->mpoly[i].totloop; j++) {
+ int g = me->mpoly[i].loopstart + j;
+ MDisps *mdisp = &mdisps[g];
+ float(*disps)[3], (*ndisps)[3], (*hdisps)[3];
+ int totdisp = multires_grid_tot[lvl];
+
+ disps = MEM_calloc_arrayN(totdisp, 3 * sizeof(float), "multires disps");
+
+ ndisps = disps;
+ hdisps = mdisp->disps;
+
+ multires_copy_grid(ndisps, hdisps, nsize, hsize);
+ if (mdisp->hidden) {
+ BLI_bitmap *gh = multires_mdisps_downsample_hidden(mdisp->hidden, mdisp->level, lvl);
+ MEM_freeN(mdisp->hidden);
+ mdisp->hidden = gh;
+ }
+
+ ndisps += nsize * nsize;
+ hdisps += hsize * hsize;
+
+ MEM_freeN(mdisp->disps);
+ mdisp->disps = disps;
+ mdisp->totdisp = totdisp;
+ mdisp->level = lvl;
+
+ if (gpm) {
+ multires_grid_paint_mask_downsample(&gpm[g], lvl);
+ }
+ }
+ }
+ }
+ else {
+ multires_customdata_delete(me);
+ }
+ }
+
+ multires_set_tot_level(ob, mmd, lvl);
}
/* (direction = 1) for delete higher, (direction = 0) for lower (not implemented yet) */
-void multiresModifier_del_levels(MultiresModifierData *mmd, Scene *scene, Object *ob, int direction)
-{
- Mesh *me = BKE_mesh_from_object(ob);
- int lvl = multires_get_level(scene, ob, mmd, false, true);
- int levels = mmd->totlvl - lvl;
- MDisps *mdisps;
-
- multires_set_tot_mdisps(me, mmd->totlvl);
- CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop);
- mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
-
- multires_force_update(ob);
-
- if (mdisps && levels > 0 && direction == 1) {
- multires_del_higher(mmd, ob, lvl);
- }
-
- multires_set_tot_level(ob, mmd, lvl);
-}
-
-static DerivedMesh *multires_dm_create_local(
- Scene *scene, Object *ob, DerivedMesh *dm,
- int lvl, int totlvl, int simple, bool alloc_paint_mask,
- int flags)
-{
- MultiresModifierData mmd = {{NULL}};
-
- mmd.lvl = lvl;
- mmd.sculptlvl = lvl;
- mmd.renderlvl = lvl;
- mmd.totlvl = totlvl;
- mmd.simple = simple;
-
- flags |= MULTIRES_USE_LOCAL_MMD;
- if (alloc_paint_mask)
- flags |= MULTIRES_ALLOC_PAINT_MASK;
-
- return multires_make_derived_from_derived(dm, &mmd, scene, ob, flags);
-}
-
-static DerivedMesh *subsurf_dm_create_local(
- Scene *scene, Object *ob, DerivedMesh *dm,
- int lvl,
- bool is_simple, bool is_optimal, bool is_plain_uv, bool alloc_paint_mask,
- bool for_render,
- SubsurfFlags flags)
-{
- SubsurfModifierData smd = {{NULL}};
-
- smd.levels = smd.renderLevels = lvl;
- smd.quality = 3;
- if (!is_plain_uv) {
- smd.uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS;
- }
- else {
- smd.uv_smooth = SUBSURF_UV_SMOOTH_NONE;
- }
- if (is_simple) {
- smd.subdivType = ME_SIMPLE_SUBSURF;
- }
- if (is_optimal) {
- smd.flags |= eSubsurfModifierFlag_ControlEdges;
- }
-
- if (ob->mode & OB_MODE_EDIT) {
- flags |= SUBSURF_IN_EDIT_MODE;
- }
- if (alloc_paint_mask) {
- flags |= SUBSURF_ALLOC_PAINT_MASK;
- }
- if (for_render) {
- flags |= SUBSURF_USE_RENDER_PARAMS;
- }
-
- return subsurf_make_derived_from_derived(dm, &smd, scene, NULL, flags);
+void multiresModifier_del_levels(MultiresModifierData *mmd,
+ Scene *scene,
+ Object *ob,
+ int direction)
+{
+ Mesh *me = BKE_mesh_from_object(ob);
+ int lvl = multires_get_level(scene, ob, mmd, false, true);
+ int levels = mmd->totlvl - lvl;
+ MDisps *mdisps;
+
+ multires_set_tot_mdisps(me, mmd->totlvl);
+ CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop);
+ mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
+
+ multires_force_update(ob);
+
+ if (mdisps && levels > 0 && direction == 1) {
+ multires_del_higher(mmd, ob, lvl);
+ }
+
+ multires_set_tot_level(ob, mmd, lvl);
+}
+
+static DerivedMesh *multires_dm_create_local(Scene *scene,
+ Object *ob,
+ DerivedMesh *dm,
+ int lvl,
+ int totlvl,
+ int simple,
+ bool alloc_paint_mask,
+ int flags)
+{
+ MultiresModifierData mmd = {{NULL}};
+
+ mmd.lvl = lvl;
+ mmd.sculptlvl = lvl;
+ mmd.renderlvl = lvl;
+ mmd.totlvl = totlvl;
+ mmd.simple = simple;
+
+ flags |= MULTIRES_USE_LOCAL_MMD;
+ if (alloc_paint_mask)
+ flags |= MULTIRES_ALLOC_PAINT_MASK;
+
+ return multires_make_derived_from_derived(dm, &mmd, scene, ob, flags);
+}
+
+static DerivedMesh *subsurf_dm_create_local(Scene *scene,
+ Object *ob,
+ DerivedMesh *dm,
+ int lvl,
+ bool is_simple,
+ bool is_optimal,
+ bool is_plain_uv,
+ bool alloc_paint_mask,
+ bool for_render,
+ SubsurfFlags flags)
+{
+ SubsurfModifierData smd = {{NULL}};
+
+ smd.levels = smd.renderLevels = lvl;
+ smd.quality = 3;
+ if (!is_plain_uv) {
+ smd.uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS;
+ }
+ else {
+ smd.uv_smooth = SUBSURF_UV_SMOOTH_NONE;
+ }
+ if (is_simple) {
+ smd.subdivType = ME_SIMPLE_SUBSURF;
+ }
+ if (is_optimal) {
+ smd.flags |= eSubsurfModifierFlag_ControlEdges;
+ }
+
+ if (ob->mode & OB_MODE_EDIT) {
+ flags |= SUBSURF_IN_EDIT_MODE;
+ }
+ if (alloc_paint_mask) {
+ flags |= SUBSURF_ALLOC_PAINT_MASK;
+ }
+ if (for_render) {
+ flags |= SUBSURF_USE_RENDER_PARAMS;
+ }
+
+ return subsurf_make_derived_from_derived(dm, &smd, scene, NULL, flags);
}
-
-
/* assumes no is normalized; return value's sign is negative if v is on
* the other side of the plane */
static float v3_dist_from_plane(float v[3], float center[3], float no[3])
{
- float s[3];
- sub_v3_v3v3(s, v, center);
- return dot_v3v3(s, no);
+ float s[3];
+ sub_v3_v3v3(s, v, center);
+ return dot_v3v3(s, no);
}
void multiresModifier_base_apply(MultiresModifierData *mmd, Scene *scene, Object *ob)
{
- DerivedMesh *cddm, *dispdm, *origdm;
- Mesh *me;
- const MeshElemMap *pmap;
- float (*origco)[3];
- int i, j, k, offset, totlvl;
-
- multires_force_update(ob);
-
- me = BKE_mesh_from_object(ob);
- totlvl = mmd->totlvl;
-
- /* nothing to do */
- if (!totlvl)
- return;
-
- /* XXX - probably not necessary to regenerate the cddm so much? */
-
- /* generate highest level with displacements */
- cddm = CDDM_from_mesh(me);
- DM_set_only_copy(cddm, &CD_MASK_BAREMESH);
- dispdm = multires_dm_create_local(scene, ob, cddm, totlvl, totlvl, 0, 0, MULTIRES_IGNORE_SIMPLIFY);
- cddm->release(cddm);
-
- /* copy the new locations of the base verts into the mesh */
- offset = dispdm->getNumVerts(dispdm) - me->totvert;
- for (i = 0; i < me->totvert; ++i) {
- dispdm->getVertCo(dispdm, offset + i, me->mvert[i].co);
- }
-
- /* heuristic to produce a better-fitting base mesh */
-
- cddm = CDDM_from_mesh(me);
- pmap = cddm->getPolyMap(ob, cddm);
- origco = MEM_calloc_arrayN(me->totvert, 3 * sizeof(float), "multires apply base origco");
- for (i = 0; i < me->totvert; ++i)
- copy_v3_v3(origco[i], me->mvert[i].co);
-
- for (i = 0; i < me->totvert; ++i) {
- float avg_no[3] = {0, 0, 0}, center[3] = {0, 0, 0}, push[3];
- float dist;
- int tot = 0;
-
- /* don't adjust verts not used by at least one poly */
- if (!pmap[i].count)
- continue;
-
- /* find center */
- for (j = 0; j < pmap[i].count; j++) {
- const MPoly *p = &me->mpoly[pmap[i].indices[j]];
-
- /* this double counts, not sure if that's bad or good */
- for (k = 0; k < p->totloop; ++k) {
- int vndx = me->mloop[p->loopstart + k].v;
- if (vndx != i) {
- add_v3_v3(center, origco[vndx]);
- tot++;
- }
- }
- }
- mul_v3_fl(center, 1.0f / tot);
-
- /* find normal */
- for (j = 0; j < pmap[i].count; j++) {
- const MPoly *p = &me->mpoly[pmap[i].indices[j]];
- MPoly fake_poly;
- MLoop *fake_loops;
- float (*fake_co)[3];
- float no[3];
-
- /* set up poly, loops, and coords in order to call
- * BKE_mesh_calc_poly_normal_coords() */
- fake_poly.totloop = p->totloop;
- fake_poly.loopstart = 0;
- fake_loops = MEM_malloc_arrayN(p->totloop, sizeof(MLoop), "fake_loops");
- fake_co = MEM_malloc_arrayN(p->totloop, 3 * sizeof(float), "fake_co");
-
- for (k = 0; k < p->totloop; ++k) {
- int vndx = me->mloop[p->loopstart + k].v;
-
- fake_loops[k].v = k;
-
- if (vndx == i)
- copy_v3_v3(fake_co[k], center);
- else
- copy_v3_v3(fake_co[k], origco[vndx]);
- }
-
- BKE_mesh_calc_poly_normal_coords(&fake_poly, fake_loops,
- (const float(*)[3])fake_co, no);
- MEM_freeN(fake_loops);
- MEM_freeN(fake_co);
-
- add_v3_v3(avg_no, no);
- }
- normalize_v3(avg_no);
-
- /* push vertex away from the plane */
- dist = v3_dist_from_plane(me->mvert[i].co, center, avg_no);
- copy_v3_v3(push, avg_no);
- mul_v3_fl(push, dist);
- add_v3_v3(me->mvert[i].co, push);
-
- }
-
- MEM_freeN(origco);
- cddm->release(cddm);
-
- /* Vertices were moved around, need to update normals after all the vertices are updated
- * Probably this is possible to do in the loop above, but this is rather tricky because
- * we don't know all needed vertices' coordinates there yet.
- */
- BKE_mesh_calc_normals(me);
-
- /* subdivide the mesh to highest level without displacements */
- cddm = CDDM_from_mesh(me);
- DM_set_only_copy(cddm, &CD_MASK_BAREMESH);
- origdm = subsurf_dm_create_local(
- scene, ob, cddm, totlvl, 0, 0, mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE,
- 0, false, SUBSURF_IGNORE_SIMPLIFY);
- cddm->release(cddm);
-
- /* calc disps */
- multiresModifier_disp_run(dispdm, me, NULL, CALC_DISPLACEMENTS, origdm->getGridData(origdm), totlvl);
-
- origdm->release(origdm);
- dispdm->release(dispdm);
+ DerivedMesh *cddm, *dispdm, *origdm;
+ Mesh *me;
+ const MeshElemMap *pmap;
+ float(*origco)[3];
+ int i, j, k, offset, totlvl;
+
+ multires_force_update(ob);
+
+ me = BKE_mesh_from_object(ob);
+ totlvl = mmd->totlvl;
+
+ /* nothing to do */
+ if (!totlvl)
+ return;
+
+ /* XXX - probably not necessary to regenerate the cddm so much? */
+
+ /* generate highest level with displacements */
+ cddm = CDDM_from_mesh(me);
+ DM_set_only_copy(cddm, &CD_MASK_BAREMESH);
+ dispdm = multires_dm_create_local(
+ scene, ob, cddm, totlvl, totlvl, 0, 0, MULTIRES_IGNORE_SIMPLIFY);
+ cddm->release(cddm);
+
+ /* copy the new locations of the base verts into the mesh */
+ offset = dispdm->getNumVerts(dispdm) - me->totvert;
+ for (i = 0; i < me->totvert; ++i) {
+ dispdm->getVertCo(dispdm, offset + i, me->mvert[i].co);
+ }
+
+ /* heuristic to produce a better-fitting base mesh */
+
+ cddm = CDDM_from_mesh(me);
+ pmap = cddm->getPolyMap(ob, cddm);
+ origco = MEM_calloc_arrayN(me->totvert, 3 * sizeof(float), "multires apply base origco");
+ for (i = 0; i < me->totvert; ++i)
+ copy_v3_v3(origco[i], me->mvert[i].co);
+
+ for (i = 0; i < me->totvert; ++i) {
+ float avg_no[3] = {0, 0, 0}, center[3] = {0, 0, 0}, push[3];
+ float dist;
+ int tot = 0;
+
+ /* don't adjust verts not used by at least one poly */
+ if (!pmap[i].count)
+ continue;
+
+ /* find center */
+ for (j = 0; j < pmap[i].count; j++) {
+ const MPoly *p = &me->mpoly[pmap[i].indices[j]];
+
+ /* this double counts, not sure if that's bad or good */
+ for (k = 0; k < p->totloop; ++k) {
+ int vndx = me->mloop[p->loopstart + k].v;
+ if (vndx != i) {
+ add_v3_v3(center, origco[vndx]);
+ tot++;
+ }
+ }
+ }
+ mul_v3_fl(center, 1.0f / tot);
+
+ /* find normal */
+ for (j = 0; j < pmap[i].count; j++) {
+ const MPoly *p = &me->mpoly[pmap[i].indices[j]];
+ MPoly fake_poly;
+ MLoop *fake_loops;
+ float(*fake_co)[3];
+ float no[3];
+
+ /* set up poly, loops, and coords in order to call
+ * BKE_mesh_calc_poly_normal_coords() */
+ fake_poly.totloop = p->totloop;
+ fake_poly.loopstart = 0;
+ fake_loops = MEM_malloc_arrayN(p->totloop, sizeof(MLoop), "fake_loops");
+ fake_co = MEM_malloc_arrayN(p->totloop, 3 * sizeof(float), "fake_co");
+
+ for (k = 0; k < p->totloop; ++k) {
+ int vndx = me->mloop[p->loopstart + k].v;
+
+ fake_loops[k].v = k;
+
+ if (vndx == i)
+ copy_v3_v3(fake_co[k], center);
+ else
+ copy_v3_v3(fake_co[k], origco[vndx]);
+ }
+
+ BKE_mesh_calc_poly_normal_coords(&fake_poly, fake_loops, (const float(*)[3])fake_co, no);
+ MEM_freeN(fake_loops);
+ MEM_freeN(fake_co);
+
+ add_v3_v3(avg_no, no);
+ }
+ normalize_v3(avg_no);
+
+ /* push vertex away from the plane */
+ dist = v3_dist_from_plane(me->mvert[i].co, center, avg_no);
+ copy_v3_v3(push, avg_no);
+ mul_v3_fl(push, dist);
+ add_v3_v3(me->mvert[i].co, push);
+ }
+
+ MEM_freeN(origco);
+ cddm->release(cddm);
+
+ /* Vertices were moved around, need to update normals after all the vertices are updated
+ * Probably this is possible to do in the loop above, but this is rather tricky because
+ * we don't know all needed vertices' coordinates there yet.
+ */
+ BKE_mesh_calc_normals(me);
+
+ /* subdivide the mesh to highest level without displacements */
+ cddm = CDDM_from_mesh(me);
+ DM_set_only_copy(cddm, &CD_MASK_BAREMESH);
+ origdm = subsurf_dm_create_local(scene,
+ ob,
+ cddm,
+ totlvl,
+ 0,
+ 0,
+ mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE,
+ 0,
+ false,
+ SUBSURF_IGNORE_SIMPLIFY);
+ cddm->release(cddm);
+
+ /* calc disps */
+ multiresModifier_disp_run(
+ dispdm, me, NULL, CALC_DISPLACEMENTS, origdm->getGridData(origdm), totlvl);
+
+ origdm->release(origdm);
+ dispdm->release(dispdm);
}
static void multires_subdivide(
- MultiresModifierData *mmd, Scene *scene, Object *ob,
- int totlvl, int updateblock, int simple)
-{
- Mesh *me = ob->data;
- MDisps *mdisps;
- const int lvl = mmd->totlvl;
-
- if ((totlvl > multires_max_levels) || (me->totpoly == 0))
- return;
-
- BLI_assert(totlvl > lvl);
-
- multires_force_update(ob);
-
- mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
- if (!mdisps)
- mdisps = multires_mdisps_initialize_hidden(me, totlvl);
-
- if (mdisps->disps && !updateblock && lvl != 0) {
- /* upsample */
- DerivedMesh *lowdm, *cddm, *highdm;
- CCGElem **highGridData, **lowGridData, **subGridData;
- CCGKey highGridKey, lowGridKey;
- CCGSubSurf *ss;
- int i, numGrids, highGridSize;
- const bool has_mask = CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK);
-
- /* create subsurf DM from original mesh at high level */
- cddm = CDDM_from_mesh(me);
- DM_set_only_copy(cddm, &CD_MASK_BAREMESH);
- highdm = subsurf_dm_create_local(
- NULL, ob, cddm, totlvl, simple, 0, mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE,
- has_mask, false, SUBSURF_IGNORE_SIMPLIFY);
- ss = ((CCGDerivedMesh *)highdm)->ss;
-
- /* create multires DM from original mesh at low level */
- lowdm = multires_dm_create_local(scene, ob, cddm, lvl, lvl, simple, has_mask, MULTIRES_IGNORE_SIMPLIFY);
- BLI_assert(lowdm != cddm);
- cddm->release(cddm);
-
- /* copy subsurf grids and replace them with low displaced grids */
- numGrids = highdm->getNumGrids(highdm);
- highGridSize = highdm->getGridSize(highdm);
- highGridData = highdm->getGridData(highdm);
- highdm->getGridKey(highdm, &highGridKey);
- lowGridData = lowdm->getGridData(lowdm);
- lowdm->getGridKey(lowdm, &lowGridKey);
-
- subGridData = MEM_calloc_arrayN(numGrids, sizeof(float *), "subGridData*");
-
- for (i = 0; i < numGrids; ++i) {
- /* backup subsurf grids */
- subGridData[i] = MEM_calloc_arrayN(highGridKey.elem_size, highGridSize * highGridSize, "subGridData");
- memcpy(subGridData[i], highGridData[i], highGridKey.elem_size * highGridSize * highGridSize);
-
- /* overwrite with current displaced grids */
- multires_copy_dm_grid(highGridData[i], lowGridData[i], &highGridKey, &lowGridKey);
- }
-
- /* low lower level dm no longer needed at this point */
- lowdm->release(lowdm);
-
- /* subsurf higher levels again with displaced data */
- ccgSubSurf_updateFromFaces(ss, lvl, NULL, 0);
- ccgSubSurf_updateLevels(ss, lvl, NULL, 0);
-
- /* reallocate displacements */
- multires_reallocate_mdisps(me->totloop, mdisps, totlvl);
-
- /* compute displacements */
- multiresModifier_disp_run(highdm, me, NULL, CALC_DISPLACEMENTS, subGridData, totlvl);
-
- /* free */
- highdm->release(highdm);
- for (i = 0; i < numGrids; ++i)
- MEM_freeN(subGridData[i]);
- MEM_freeN(subGridData);
- }
- else {
- /* only reallocate, nothing to upsample */
- multires_reallocate_mdisps(me->totloop, mdisps, totlvl);
- }
-
- multires_set_tot_level(ob, mmd, totlvl);
-}
-
-void multiresModifier_subdivide(MultiresModifierData *mmd, Scene *scene, Object *ob, int updateblock, int simple)
-{
- multires_subdivide(mmd, scene, ob, mmd->totlvl + 1, updateblock, simple);
+ MultiresModifierData *mmd, Scene *scene, Object *ob, int totlvl, int updateblock, int simple)
+{
+ Mesh *me = ob->data;
+ MDisps *mdisps;
+ const int lvl = mmd->totlvl;
+
+ if ((totlvl > multires_max_levels) || (me->totpoly == 0))
+ return;
+
+ BLI_assert(totlvl > lvl);
+
+ multires_force_update(ob);
+
+ mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
+ if (!mdisps)
+ mdisps = multires_mdisps_initialize_hidden(me, totlvl);
+
+ if (mdisps->disps && !updateblock && lvl != 0) {
+ /* upsample */
+ DerivedMesh *lowdm, *cddm, *highdm;
+ CCGElem **highGridData, **lowGridData, **subGridData;
+ CCGKey highGridKey, lowGridKey;
+ CCGSubSurf *ss;
+ int i, numGrids, highGridSize;
+ const bool has_mask = CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK);
+
+ /* create subsurf DM from original mesh at high level */
+ cddm = CDDM_from_mesh(me);
+ DM_set_only_copy(cddm, &CD_MASK_BAREMESH);
+ highdm = subsurf_dm_create_local(NULL,
+ ob,
+ cddm,
+ totlvl,
+ simple,
+ 0,
+ mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE,
+ has_mask,
+ false,
+ SUBSURF_IGNORE_SIMPLIFY);
+ ss = ((CCGDerivedMesh *)highdm)->ss;
+
+ /* create multires DM from original mesh at low level */
+ lowdm = multires_dm_create_local(
+ scene, ob, cddm, lvl, lvl, simple, has_mask, MULTIRES_IGNORE_SIMPLIFY);
+ BLI_assert(lowdm != cddm);
+ cddm->release(cddm);
+
+ /* copy subsurf grids and replace them with low displaced grids */
+ numGrids = highdm->getNumGrids(highdm);
+ highGridSize = highdm->getGridSize(highdm);
+ highGridData = highdm->getGridData(highdm);
+ highdm->getGridKey(highdm, &highGridKey);
+ lowGridData = lowdm->getGridData(lowdm);
+ lowdm->getGridKey(lowdm, &lowGridKey);
+
+ subGridData = MEM_calloc_arrayN(numGrids, sizeof(float *), "subGridData*");
+
+ for (i = 0; i < numGrids; ++i) {
+ /* backup subsurf grids */
+ subGridData[i] = MEM_calloc_arrayN(
+ highGridKey.elem_size, highGridSize * highGridSize, "subGridData");
+ memcpy(subGridData[i], highGridData[i], highGridKey.elem_size * highGridSize * highGridSize);
+
+ /* overwrite with current displaced grids */
+ multires_copy_dm_grid(highGridData[i], lowGridData[i], &highGridKey, &lowGridKey);
+ }
+
+ /* low lower level dm no longer needed at this point */
+ lowdm->release(lowdm);
+
+ /* subsurf higher levels again with displaced data */
+ ccgSubSurf_updateFromFaces(ss, lvl, NULL, 0);
+ ccgSubSurf_updateLevels(ss, lvl, NULL, 0);
+
+ /* reallocate displacements */
+ multires_reallocate_mdisps(me->totloop, mdisps, totlvl);
+
+ /* compute displacements */
+ multiresModifier_disp_run(highdm, me, NULL, CALC_DISPLACEMENTS, subGridData, totlvl);
+
+ /* free */
+ highdm->release(highdm);
+ for (i = 0; i < numGrids; ++i)
+ MEM_freeN(subGridData[i]);
+ MEM_freeN(subGridData);
+ }
+ else {
+ /* only reallocate, nothing to upsample */
+ multires_reallocate_mdisps(me->totloop, mdisps, totlvl);
+ }
+
+ multires_set_tot_level(ob, mmd, totlvl);
+}
+
+void multiresModifier_subdivide(
+ MultiresModifierData *mmd, Scene *scene, Object *ob, int updateblock, int simple)
+{
+ multires_subdivide(mmd, scene, ob, mmd->totlvl + 1, updateblock, simple);
}
static void grid_tangent(const CCGKey *key, int x, int y, int axis, CCGElem *grid, float t[3])
{
- if (axis == 0) {
- if (x == key->grid_size - 1) {
- if (y == key->grid_size - 1)
- sub_v3_v3v3(t, CCG_grid_elem_co(key, grid, x, y - 1), CCG_grid_elem_co(key, grid, x - 1, y - 1));
- else
- sub_v3_v3v3(t, CCG_grid_elem_co(key, grid, x, y), CCG_grid_elem_co(key, grid, x - 1, y));
- }
- else
- sub_v3_v3v3(t, CCG_grid_elem_co(key, grid, x + 1, y), CCG_grid_elem_co(key, grid, x, y));
- }
- else if (axis == 1) {
- if (y == key->grid_size - 1) {
- if (x == key->grid_size - 1)
- sub_v3_v3v3(t, CCG_grid_elem_co(key, grid, x - 1, y), CCG_grid_elem_co(key, grid, x - 1, (y - 1)));
- else
- sub_v3_v3v3(t, CCG_grid_elem_co(key, grid, x, y), CCG_grid_elem_co(key, grid, x, (y - 1)));
- }
- else
- sub_v3_v3v3(t, CCG_grid_elem_co(key, grid, x, (y + 1)), CCG_grid_elem_co(key, grid, x, y));
- }
+ if (axis == 0) {
+ if (x == key->grid_size - 1) {
+ if (y == key->grid_size - 1)
+ sub_v3_v3v3(
+ t, CCG_grid_elem_co(key, grid, x, y - 1), CCG_grid_elem_co(key, grid, x - 1, y - 1));
+ else
+ sub_v3_v3v3(t, CCG_grid_elem_co(key, grid, x, y), CCG_grid_elem_co(key, grid, x - 1, y));
+ }
+ else
+ sub_v3_v3v3(t, CCG_grid_elem_co(key, grid, x + 1, y), CCG_grid_elem_co(key, grid, x, y));
+ }
+ else if (axis == 1) {
+ if (y == key->grid_size - 1) {
+ if (x == key->grid_size - 1)
+ sub_v3_v3v3(
+ t, CCG_grid_elem_co(key, grid, x - 1, y), CCG_grid_elem_co(key, grid, x - 1, (y - 1)));
+ else
+ sub_v3_v3v3(t, CCG_grid_elem_co(key, grid, x, y), CCG_grid_elem_co(key, grid, x, (y - 1)));
+ }
+ else
+ sub_v3_v3v3(t, CCG_grid_elem_co(key, grid, x, (y + 1)), CCG_grid_elem_co(key, grid, x, y));
+ }
}
/* Construct 3x3 tangent-space matrix in 'mat' */
-static void grid_tangent_matrix(float mat[3][3], const CCGKey *key,
- int x, int y, CCGElem *grid)
+static void grid_tangent_matrix(float mat[3][3], const CCGKey *key, int x, int y, CCGElem *grid)
{
- grid_tangent(key, x, y, 0, grid, mat[0]);
- normalize_v3(mat[0]);
+ grid_tangent(key, x, y, 0, grid, mat[0]);
+ normalize_v3(mat[0]);
- grid_tangent(key, x, y, 1, grid, mat[1]);
- normalize_v3(mat[1]);
+ grid_tangent(key, x, y, 1, grid, mat[1]);
+ normalize_v3(mat[1]);
- copy_v3_v3(mat[2], CCG_grid_elem_no(key, grid, x, y));
+ copy_v3_v3(mat[2], CCG_grid_elem_no(key, grid, x, y));
}
-
typedef struct MultiresThreadedData {
- DispOp op;
- CCGElem **gridData, **subGridData;
- CCGKey *key;
- CCGKey *sub_key;
- MPoly *mpoly;
- MDisps *mdisps;
- GridPaintMask *grid_paint_mask;
- int *gridOffset;
- int gridSize, dGridSize, dSkip;
- float (*smat)[3];
+ DispOp op;
+ CCGElem **gridData, **subGridData;
+ CCGKey *key;
+ CCGKey *sub_key;
+ MPoly *mpoly;
+ MDisps *mdisps;
+ GridPaintMask *grid_paint_mask;
+ int *gridOffset;
+ int gridSize, dGridSize, dSkip;
+ float (*smat)[3];
} MultiresThreadedData;
-static void multires_disp_run_cb(
- void *__restrict userdata,
- const int pidx,
- const ParallelRangeTLS *__restrict UNUSED(tls))
-{
- MultiresThreadedData *tdata = userdata;
-
- DispOp op = tdata->op;
- CCGElem **gridData = tdata->gridData;
- CCGElem **subGridData = tdata->subGridData;
- CCGKey *key = tdata->key;
- MPoly *mpoly = tdata->mpoly;
- MDisps *mdisps = tdata->mdisps;
- GridPaintMask *grid_paint_mask = tdata->grid_paint_mask;
- int *gridOffset = tdata->gridOffset;
- int gridSize = tdata->gridSize;
- int dGridSize = tdata->dGridSize;
- int dSkip = tdata->dSkip;
-
- const int numVerts = mpoly[pidx].totloop;
- int S, x, y, gIndex = gridOffset[pidx];
-
- for (S = 0; S < numVerts; ++S, ++gIndex) {
- GridPaintMask *gpm = grid_paint_mask ? &grid_paint_mask[gIndex] : NULL;
- MDisps *mdisp = &mdisps[mpoly[pidx].loopstart + S];
- CCGElem *grid = gridData[gIndex];
- CCGElem *subgrid = subGridData[gIndex];
- float (*dispgrid)[3] = NULL;
-
- dispgrid = mdisp->disps;
-
- /* if needed, reallocate multires paint mask */
- if (gpm && gpm->level < key->level) {
- gpm->level = key->level;
- if (gpm->data) {
- MEM_freeN(gpm->data);
- }
- gpm->data = MEM_calloc_arrayN(key->grid_area, sizeof(float), "gpm.data");
- }
-
- for (y = 0; y < gridSize; y++) {
- for (x = 0; x < gridSize; x++) {
- float *co = CCG_grid_elem_co(key, grid, x, y);
- float *sco = CCG_grid_elem_co(key, subgrid, x, y);
- float *data = dispgrid[dGridSize * y * dSkip + x * dSkip];
- float mat[3][3], disp[3], d[3], mask;
-
- /* construct tangent space matrix */
- grid_tangent_matrix(mat, key, x, y, subgrid);
-
- switch (op) {
- case APPLY_DISPLACEMENTS:
- /* Convert displacement to object space
- * and add to grid points */
- mul_v3_m3v3(disp, mat, data);
- add_v3_v3v3(co, sco, disp);
- break;
- case CALC_DISPLACEMENTS:
- /* Calculate displacement between new and old
- * grid points and convert to tangent space */
- sub_v3_v3v3(disp, co, sco);
- invert_m3(mat);
- mul_v3_m3v3(data, mat, disp);
- break;
- case ADD_DISPLACEMENTS:
- /* Convert subdivided displacements to tangent
- * space and add to the original displacements */
- invert_m3(mat);
- mul_v3_m3v3(d, mat, co);
- add_v3_v3(data, d);
- break;
- }
-
- if (gpm) {
- switch (op) {
- case APPLY_DISPLACEMENTS:
- /* Copy mask from gpm to DM */
- *CCG_grid_elem_mask(key, grid, x, y) =
- paint_grid_paint_mask(gpm, key->level, x, y);
- break;
- case CALC_DISPLACEMENTS:
- /* Copy mask from DM to gpm */
- mask = *CCG_grid_elem_mask(key, grid, x, y);
- gpm->data[y * gridSize + x] = CLAMPIS(mask, 0, 1);
- break;
- case ADD_DISPLACEMENTS:
- /* Add mask displacement to gpm */
- gpm->data[y * gridSize + x] +=
- *CCG_grid_elem_mask(key, grid, x, y);
- break;
- }
- }
- }
- }
- }
+static void multires_disp_run_cb(void *__restrict userdata,
+ const int pidx,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ MultiresThreadedData *tdata = userdata;
+
+ DispOp op = tdata->op;
+ CCGElem **gridData = tdata->gridData;
+ CCGElem **subGridData = tdata->subGridData;
+ CCGKey *key = tdata->key;
+ MPoly *mpoly = tdata->mpoly;
+ MDisps *mdisps = tdata->mdisps;
+ GridPaintMask *grid_paint_mask = tdata->grid_paint_mask;
+ int *gridOffset = tdata->gridOffset;
+ int gridSize = tdata->gridSize;
+ int dGridSize = tdata->dGridSize;
+ int dSkip = tdata->dSkip;
+
+ const int numVerts = mpoly[pidx].totloop;
+ int S, x, y, gIndex = gridOffset[pidx];
+
+ for (S = 0; S < numVerts; ++S, ++gIndex) {
+ GridPaintMask *gpm = grid_paint_mask ? &grid_paint_mask[gIndex] : NULL;
+ MDisps *mdisp = &mdisps[mpoly[pidx].loopstart + S];
+ CCGElem *grid = gridData[gIndex];
+ CCGElem *subgrid = subGridData[gIndex];
+ float(*dispgrid)[3] = NULL;
+
+ dispgrid = mdisp->disps;
+
+ /* if needed, reallocate multires paint mask */
+ if (gpm && gpm->level < key->level) {
+ gpm->level = key->level;
+ if (gpm->data) {
+ MEM_freeN(gpm->data);
+ }
+ gpm->data = MEM_calloc_arrayN(key->grid_area, sizeof(float), "gpm.data");
+ }
+
+ for (y = 0; y < gridSize; y++) {
+ for (x = 0; x < gridSize; x++) {
+ float *co = CCG_grid_elem_co(key, grid, x, y);
+ float *sco = CCG_grid_elem_co(key, subgrid, x, y);
+ float *data = dispgrid[dGridSize * y * dSkip + x * dSkip];
+ float mat[3][3], disp[3], d[3], mask;
+
+ /* construct tangent space matrix */
+ grid_tangent_matrix(mat, key, x, y, subgrid);
+
+ switch (op) {
+ case APPLY_DISPLACEMENTS:
+ /* Convert displacement to object space
+ * and add to grid points */
+ mul_v3_m3v3(disp, mat, data);
+ add_v3_v3v3(co, sco, disp);
+ break;
+ case CALC_DISPLACEMENTS:
+ /* Calculate displacement between new and old
+ * grid points and convert to tangent space */
+ sub_v3_v3v3(disp, co, sco);
+ invert_m3(mat);
+ mul_v3_m3v3(data, mat, disp);
+ break;
+ case ADD_DISPLACEMENTS:
+ /* Convert subdivided displacements to tangent
+ * space and add to the original displacements */
+ invert_m3(mat);
+ mul_v3_m3v3(d, mat, co);
+ add_v3_v3(data, d);
+ break;
+ }
+
+ if (gpm) {
+ switch (op) {
+ case APPLY_DISPLACEMENTS:
+ /* Copy mask from gpm to DM */
+ *CCG_grid_elem_mask(key, grid, x, y) = paint_grid_paint_mask(gpm, key->level, x, y);
+ break;
+ case CALC_DISPLACEMENTS:
+ /* Copy mask from DM to gpm */
+ mask = *CCG_grid_elem_mask(key, grid, x, y);
+ gpm->data[y * gridSize + x] = CLAMPIS(mask, 0, 1);
+ break;
+ case ADD_DISPLACEMENTS:
+ /* Add mask displacement to gpm */
+ gpm->data[y * gridSize + x] += *CCG_grid_elem_mask(key, grid, x, y);
+ break;
+ }
+ }
+ }
+ }
+ }
}
/* XXX WARNING: subsurf elements from dm and oldGridData *must* be of the same format (size),
* because this code uses CCGKey's info from dm to access oldGridData's normals
* (through the call to grid_tangent_matrix())! */
-static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, DerivedMesh *dm2, DispOp op, CCGElem **oldGridData, int totlvl)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
- CCGElem **gridData, **subGridData;
- CCGKey key;
- MPoly *mpoly = me->mpoly;
- MDisps *mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
- GridPaintMask *grid_paint_mask = NULL;
- int *gridOffset;
- int i, gridSize, dGridSize, dSkip;
- int totloop, totpoly;
-
- /* this happens in the dm made by bmesh_mdisps_space_set */
- if (dm2 && CustomData_has_layer(&dm2->loopData, CD_MDISPS)) {
- mpoly = CustomData_get_layer(&dm2->polyData, CD_MPOLY);
- mdisps = CustomData_get_layer(&dm2->loopData, CD_MDISPS);
- totloop = dm2->numLoopData;
- totpoly = dm2->numPolyData;
- }
- else {
- totloop = me->totloop;
- totpoly = me->totpoly;
- }
-
- if (!mdisps) {
- if (op == CALC_DISPLACEMENTS)
- mdisps = CustomData_add_layer(&me->ldata, CD_MDISPS, CD_DEFAULT, NULL, me->totloop);
- else
- return;
- }
-
- /*numGrids = dm->getNumGrids(dm);*/ /*UNUSED*/
- gridSize = dm->getGridSize(dm);
- gridData = dm->getGridData(dm);
- gridOffset = dm->getGridOffset(dm);
- dm->getGridKey(dm, &key);
- subGridData = (oldGridData) ? oldGridData : gridData;
-
- dGridSize = multires_side_tot[totlvl];
- dSkip = (dGridSize - 1) / (gridSize - 1);
-
- /* multires paint masks */
- if (key.has_mask)
- grid_paint_mask = CustomData_get_layer(&me->ldata, CD_GRID_PAINT_MASK);
-
- /* when adding new faces in edit mode, need to allocate disps */
- for (i = 0; i < totloop; ++i) {
- if (mdisps[i].disps == NULL) {
- multires_reallocate_mdisps(totloop, mdisps, totlvl);
- break;
- }
- }
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.min_iter_per_thread = CCG_TASK_LIMIT;
-
- MultiresThreadedData data = {
- .op = op,
- .gridData = gridData,
- .subGridData = subGridData,
- .key = &key,
- .mpoly = mpoly,
- .mdisps = mdisps,
- .grid_paint_mask = grid_paint_mask,
- .gridOffset = gridOffset,
- .gridSize = gridSize,
- .dGridSize = dGridSize,
- .dSkip = dSkip,
- };
-
- BLI_task_parallel_range(0, totpoly, &data, multires_disp_run_cb, &settings);
-
- if (op == APPLY_DISPLACEMENTS) {
- ccgSubSurf_stitchFaces(ccgdm->ss, 0, NULL, 0);
- ccgSubSurf_updateNormals(ccgdm->ss, NULL, 0);
- }
+static void multiresModifier_disp_run(
+ DerivedMesh *dm, Mesh *me, DerivedMesh *dm2, DispOp op, CCGElem **oldGridData, int totlvl)
+{
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ CCGElem **gridData, **subGridData;
+ CCGKey key;
+ MPoly *mpoly = me->mpoly;
+ MDisps *mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
+ GridPaintMask *grid_paint_mask = NULL;
+ int *gridOffset;
+ int i, gridSize, dGridSize, dSkip;
+ int totloop, totpoly;
+
+ /* this happens in the dm made by bmesh_mdisps_space_set */
+ if (dm2 && CustomData_has_layer(&dm2->loopData, CD_MDISPS)) {
+ mpoly = CustomData_get_layer(&dm2->polyData, CD_MPOLY);
+ mdisps = CustomData_get_layer(&dm2->loopData, CD_MDISPS);
+ totloop = dm2->numLoopData;
+ totpoly = dm2->numPolyData;
+ }
+ else {
+ totloop = me->totloop;
+ totpoly = me->totpoly;
+ }
+
+ if (!mdisps) {
+ if (op == CALC_DISPLACEMENTS)
+ mdisps = CustomData_add_layer(&me->ldata, CD_MDISPS, CD_DEFAULT, NULL, me->totloop);
+ else
+ return;
+ }
+
+ /*numGrids = dm->getNumGrids(dm);*/ /*UNUSED*/
+ gridSize = dm->getGridSize(dm);
+ gridData = dm->getGridData(dm);
+ gridOffset = dm->getGridOffset(dm);
+ dm->getGridKey(dm, &key);
+ subGridData = (oldGridData) ? oldGridData : gridData;
+
+ dGridSize = multires_side_tot[totlvl];
+ dSkip = (dGridSize - 1) / (gridSize - 1);
+
+ /* multires paint masks */
+ if (key.has_mask)
+ grid_paint_mask = CustomData_get_layer(&me->ldata, CD_GRID_PAINT_MASK);
+
+ /* when adding new faces in edit mode, need to allocate disps */
+ for (i = 0; i < totloop; ++i) {
+ if (mdisps[i].disps == NULL) {
+ multires_reallocate_mdisps(totloop, mdisps, totlvl);
+ break;
+ }
+ }
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.min_iter_per_thread = CCG_TASK_LIMIT;
+
+ MultiresThreadedData data = {
+ .op = op,
+ .gridData = gridData,
+ .subGridData = subGridData,
+ .key = &key,
+ .mpoly = mpoly,
+ .mdisps = mdisps,
+ .grid_paint_mask = grid_paint_mask,
+ .gridOffset = gridOffset,
+ .gridSize = gridSize,
+ .dGridSize = dGridSize,
+ .dSkip = dSkip,
+ };
+
+ BLI_task_parallel_range(0, totpoly, &data, multires_disp_run_cb, &settings);
+
+ if (op == APPLY_DISPLACEMENTS) {
+ ccgSubSurf_stitchFaces(ccgdm->ss, 0, NULL, 0);
+ ccgSubSurf_updateNormals(ccgdm->ss, NULL, 0);
+ }
}
void multires_modifier_update_mdisps(struct DerivedMesh *dm, Scene *scene)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
- Object *ob;
- Mesh *me;
- MDisps *mdisps;
- MultiresModifierData *mmd;
-
- ob = ccgdm->multires.ob;
- me = ccgdm->multires.ob->data;
- mmd = ccgdm->multires.mmd;
- multires_set_tot_mdisps(me, mmd->totlvl);
- CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop);
- mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
-
- if (mdisps) {
- int lvl = ccgdm->multires.lvl;
- int totlvl = ccgdm->multires.totlvl;
-
- if (lvl < totlvl) {
- DerivedMesh *lowdm, *cddm, *highdm;
- CCGElem **highGridData, **lowGridData, **subGridData, **gridData, *diffGrid;
- CCGKey highGridKey, lowGridKey;
- CCGSubSurf *ss;
- int i, j, numGrids, highGridSize, lowGridSize;
- const bool has_mask = CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK);
-
- /* create subsurf DM from original mesh at high level */
- if (ob->derivedDeform) cddm = CDDM_copy(ob->derivedDeform);
- else cddm = CDDM_from_mesh(me);
- DM_set_only_copy(cddm, &CD_MASK_BAREMESH);
-
- highdm = subsurf_dm_create_local(
- scene, ob, cddm, totlvl, mmd->simple, 0, mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE,
- has_mask, false, SUBSURF_IGNORE_SIMPLIFY);
- ss = ((CCGDerivedMesh *)highdm)->ss;
-
- /* create multires DM from original mesh and displacements */
- lowdm = multires_dm_create_local(scene, ob, cddm, lvl, totlvl, mmd->simple, has_mask, MULTIRES_IGNORE_SIMPLIFY);
- cddm->release(cddm);
-
- /* gather grid data */
- numGrids = highdm->getNumGrids(highdm);
- highGridSize = highdm->getGridSize(highdm);
- highGridData = highdm->getGridData(highdm);
- highdm->getGridKey(highdm, &highGridKey);
- lowGridSize = lowdm->getGridSize(lowdm);
- lowGridData = lowdm->getGridData(lowdm);
- lowdm->getGridKey(lowdm, &lowGridKey);
- gridData = dm->getGridData(dm);
-
- BLI_assert(highGridKey.elem_size == lowGridKey.elem_size);
-
- subGridData = MEM_calloc_arrayN(numGrids, sizeof(CCGElem *), "subGridData*");
- diffGrid = MEM_calloc_arrayN(lowGridKey.elem_size, lowGridSize * lowGridSize, "diff");
-
- for (i = 0; i < numGrids; ++i) {
- /* backup subsurf grids */
- subGridData[i] = MEM_calloc_arrayN(highGridKey.elem_size, highGridSize * highGridSize, "subGridData");
- memcpy(subGridData[i], highGridData[i], highGridKey.elem_size * highGridSize * highGridSize);
-
- /* write difference of subsurf and displaced low level into high subsurf */
- for (j = 0; j < lowGridSize * lowGridSize; ++j) {
- sub_v4_v4v4(CCG_elem_offset_co(&lowGridKey, diffGrid, j),
- CCG_elem_offset_co(&lowGridKey, gridData[i], j),
- CCG_elem_offset_co(&lowGridKey, lowGridData[i], j));
- }
-
- multires_copy_dm_grid(highGridData[i], diffGrid, &highGridKey, &lowGridKey);
- }
-
- /* lower level dm no longer needed at this point */
- MEM_freeN(diffGrid);
- lowdm->release(lowdm);
-
- /* subsurf higher levels again with difference of coordinates */
- ccgSubSurf_updateFromFaces(ss, lvl, NULL, 0);
- ccgSubSurf_updateLevels(ss, lvl, NULL, 0);
-
- /* add to displacements */
- multiresModifier_disp_run(highdm, me, NULL, ADD_DISPLACEMENTS, subGridData, mmd->totlvl);
-
- /* free */
- highdm->release(highdm);
- for (i = 0; i < numGrids; ++i)
- MEM_freeN(subGridData[i]);
- MEM_freeN(subGridData);
- }
- else {
- DerivedMesh *cddm, *subdm;
- const bool has_mask = CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK);
-
- if (ob->derivedDeform) cddm = CDDM_copy(ob->derivedDeform);
- else cddm = CDDM_from_mesh(me);
- DM_set_only_copy(cddm, &CD_MASK_BAREMESH);
-
- subdm = subsurf_dm_create_local(
- scene, ob, cddm, mmd->totlvl, mmd->simple, 0, mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE,
- has_mask, false, SUBSURF_IGNORE_SIMPLIFY);
- cddm->release(cddm);
-
- multiresModifier_disp_run(dm, me, NULL, CALC_DISPLACEMENTS, subdm->getGridData(subdm), mmd->totlvl);
-
- subdm->release(subdm);
- }
- }
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ Object *ob;
+ Mesh *me;
+ MDisps *mdisps;
+ MultiresModifierData *mmd;
+
+ ob = ccgdm->multires.ob;
+ me = ccgdm->multires.ob->data;
+ mmd = ccgdm->multires.mmd;
+ multires_set_tot_mdisps(me, mmd->totlvl);
+ CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop);
+ mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
+
+ if (mdisps) {
+ int lvl = ccgdm->multires.lvl;
+ int totlvl = ccgdm->multires.totlvl;
+
+ if (lvl < totlvl) {
+ DerivedMesh *lowdm, *cddm, *highdm;
+ CCGElem **highGridData, **lowGridData, **subGridData, **gridData, *diffGrid;
+ CCGKey highGridKey, lowGridKey;
+ CCGSubSurf *ss;
+ int i, j, numGrids, highGridSize, lowGridSize;
+ const bool has_mask = CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK);
+
+ /* create subsurf DM from original mesh at high level */
+ if (ob->derivedDeform)
+ cddm = CDDM_copy(ob->derivedDeform);
+ else
+ cddm = CDDM_from_mesh(me);
+ DM_set_only_copy(cddm, &CD_MASK_BAREMESH);
+
+ highdm = subsurf_dm_create_local(scene,
+ ob,
+ cddm,
+ totlvl,
+ mmd->simple,
+ 0,
+ mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE,
+ has_mask,
+ false,
+ SUBSURF_IGNORE_SIMPLIFY);
+ ss = ((CCGDerivedMesh *)highdm)->ss;
+
+ /* create multires DM from original mesh and displacements */
+ lowdm = multires_dm_create_local(
+ scene, ob, cddm, lvl, totlvl, mmd->simple, has_mask, MULTIRES_IGNORE_SIMPLIFY);
+ cddm->release(cddm);
+
+ /* gather grid data */
+ numGrids = highdm->getNumGrids(highdm);
+ highGridSize = highdm->getGridSize(highdm);
+ highGridData = highdm->getGridData(highdm);
+ highdm->getGridKey(highdm, &highGridKey);
+ lowGridSize = lowdm->getGridSize(lowdm);
+ lowGridData = lowdm->getGridData(lowdm);
+ lowdm->getGridKey(lowdm, &lowGridKey);
+ gridData = dm->getGridData(dm);
+
+ BLI_assert(highGridKey.elem_size == lowGridKey.elem_size);
+
+ subGridData = MEM_calloc_arrayN(numGrids, sizeof(CCGElem *), "subGridData*");
+ diffGrid = MEM_calloc_arrayN(lowGridKey.elem_size, lowGridSize * lowGridSize, "diff");
+
+ for (i = 0; i < numGrids; ++i) {
+ /* backup subsurf grids */
+ subGridData[i] = MEM_calloc_arrayN(
+ highGridKey.elem_size, highGridSize * highGridSize, "subGridData");
+ memcpy(
+ subGridData[i], highGridData[i], highGridKey.elem_size * highGridSize * highGridSize);
+
+ /* write difference of subsurf and displaced low level into high subsurf */
+ for (j = 0; j < lowGridSize * lowGridSize; ++j) {
+ sub_v4_v4v4(CCG_elem_offset_co(&lowGridKey, diffGrid, j),
+ CCG_elem_offset_co(&lowGridKey, gridData[i], j),
+ CCG_elem_offset_co(&lowGridKey, lowGridData[i], j));
+ }
+
+ multires_copy_dm_grid(highGridData[i], diffGrid, &highGridKey, &lowGridKey);
+ }
+
+ /* lower level dm no longer needed at this point */
+ MEM_freeN(diffGrid);
+ lowdm->release(lowdm);
+
+ /* subsurf higher levels again with difference of coordinates */
+ ccgSubSurf_updateFromFaces(ss, lvl, NULL, 0);
+ ccgSubSurf_updateLevels(ss, lvl, NULL, 0);
+
+ /* add to displacements */
+ multiresModifier_disp_run(highdm, me, NULL, ADD_DISPLACEMENTS, subGridData, mmd->totlvl);
+
+ /* free */
+ highdm->release(highdm);
+ for (i = 0; i < numGrids; ++i)
+ MEM_freeN(subGridData[i]);
+ MEM_freeN(subGridData);
+ }
+ else {
+ DerivedMesh *cddm, *subdm;
+ const bool has_mask = CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK);
+
+ if (ob->derivedDeform)
+ cddm = CDDM_copy(ob->derivedDeform);
+ else
+ cddm = CDDM_from_mesh(me);
+ DM_set_only_copy(cddm, &CD_MASK_BAREMESH);
+
+ subdm = subsurf_dm_create_local(scene,
+ ob,
+ cddm,
+ mmd->totlvl,
+ mmd->simple,
+ 0,
+ mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE,
+ has_mask,
+ false,
+ SUBSURF_IGNORE_SIMPLIFY);
+ cddm->release(cddm);
+
+ multiresModifier_disp_run(
+ dm, me, NULL, CALC_DISPLACEMENTS, subdm->getGridData(subdm), mmd->totlvl);
+
+ subdm->release(subdm);
+ }
+ }
}
void multires_modifier_update_hidden(DerivedMesh *dm)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
- BLI_bitmap **grid_hidden = ccgdm->gridHidden;
- Mesh *me = ccgdm->multires.ob->data;
- MDisps *mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
- int totlvl = ccgdm->multires.totlvl;
- int lvl = ccgdm->multires.lvl;
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ BLI_bitmap **grid_hidden = ccgdm->gridHidden;
+ Mesh *me = ccgdm->multires.ob->data;
+ MDisps *mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
+ int totlvl = ccgdm->multires.totlvl;
+ int lvl = ccgdm->multires.lvl;
- if (mdisps) {
- int i;
+ if (mdisps) {
+ int i;
- for (i = 0; i < me->totloop; i++) {
- MDisps *md = &mdisps[i];
- BLI_bitmap *gh = grid_hidden[i];
+ for (i = 0; i < me->totloop; i++) {
+ MDisps *md = &mdisps[i];
+ BLI_bitmap *gh = grid_hidden[i];
- if (!gh && md->hidden) {
- MEM_freeN(md->hidden);
- md->hidden = NULL;
- }
- else if (gh) {
- gh = multires_mdisps_upsample_hidden(gh, lvl, totlvl,
- md->hidden);
- if (md->hidden)
- MEM_freeN(md->hidden);
+ if (!gh && md->hidden) {
+ MEM_freeN(md->hidden);
+ md->hidden = NULL;
+ }
+ else if (gh) {
+ gh = multires_mdisps_upsample_hidden(gh, lvl, totlvl, md->hidden);
+ if (md->hidden)
+ MEM_freeN(md->hidden);
- md->hidden = gh;
- }
- }
- }
+ md->hidden = gh;
+ }
+ }
+ }
}
void multires_stitch_grids(Object *ob)
{
- if (ob == NULL) {
- return;
- }
- SculptSession *sculpt_session = ob->sculpt;
- if (sculpt_session == NULL) {
- return;
- }
- PBVH *pbvh = sculpt_session->pbvh;
- SubdivCCG *subdiv_ccg = sculpt_session->subdiv_ccg;
- if (pbvh == NULL || subdiv_ccg == NULL) {
- return;
- }
- BLI_assert(BKE_pbvh_type(pbvh) == PBVH_GRIDS);
- /* NOTE: Currently CCG does not keep track of faces, making it impossible
- * to use BKE_pbvh_get_grid_updates().
- */
- CCGFace **faces;
- int num_faces;
- BKE_pbvh_get_grid_updates(pbvh, false, (void ***)&faces, &num_faces);
- if (num_faces) {
- BKE_subdiv_ccg_average_stitch_faces(subdiv_ccg, faces, num_faces);
- MEM_freeN(faces);
- }
-}
-
-DerivedMesh *multires_make_derived_from_derived(DerivedMesh *dm,
- MultiresModifierData *mmd,
- Scene *scene,
- Object *ob,
- MultiresFlags flags)
-{
- Mesh *me = ob->data;
- DerivedMesh *result;
- CCGDerivedMesh *ccgdm = NULL;
- CCGElem **gridData, **subGridData;
- CCGKey key;
- const bool render = (flags & MULTIRES_USE_RENDER_PARAMS) != 0;
- const bool ignore_simplify = (flags & MULTIRES_IGNORE_SIMPLIFY) != 0;
- int lvl = multires_get_level(scene, ob, mmd, render, ignore_simplify);
- int i, gridSize, numGrids;
-
- if (lvl == 0)
- return dm;
-
- const int subsurf_flags = ignore_simplify ? SUBSURF_IGNORE_SIMPLIFY : 0;
-
- result = subsurf_dm_create_local(scene, ob, dm, lvl,
- mmd->simple, mmd->flags & eMultiresModifierFlag_ControlEdges,
- mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE,
- flags & MULTIRES_ALLOC_PAINT_MASK,
- render, subsurf_flags);
-
- if (!(flags & MULTIRES_USE_LOCAL_MMD)) {
- ccgdm = (CCGDerivedMesh *)result;
-
- ccgdm->multires.ob = ob;
- ccgdm->multires.mmd = mmd;
- ccgdm->multires.local_mmd = 0;
- ccgdm->multires.lvl = lvl;
- ccgdm->multires.totlvl = mmd->totlvl;
- ccgdm->multires.modified_flags = 0;
- }
-
- numGrids = result->getNumGrids(result);
- gridSize = result->getGridSize(result);
- gridData = result->getGridData(result);
- result->getGridKey(result, &key);
-
- subGridData = MEM_malloc_arrayN(numGrids, sizeof(CCGElem *), "subGridData*");
-
- for (i = 0; i < numGrids; i++) {
- subGridData[i] = MEM_malloc_arrayN(key.elem_size, gridSize * gridSize, "subGridData");
- memcpy(subGridData[i], gridData[i], key.elem_size * gridSize * gridSize);
- }
-
- multires_set_tot_mdisps(me, mmd->totlvl);
- CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop);
-
- /*run displacement*/
- multiresModifier_disp_run(result, ob->data, dm, APPLY_DISPLACEMENTS, subGridData, mmd->totlvl);
-
- /* copy hidden elements for this level */
- if (ccgdm)
- multires_output_hidden_to_ccgdm(ccgdm, me, lvl);
-
- for (i = 0; i < numGrids; i++)
- MEM_freeN(subGridData[i]);
- MEM_freeN(subGridData);
-
- return result;
+ if (ob == NULL) {
+ return;
+ }
+ SculptSession *sculpt_session = ob->sculpt;
+ if (sculpt_session == NULL) {
+ return;
+ }
+ PBVH *pbvh = sculpt_session->pbvh;
+ SubdivCCG *subdiv_ccg = sculpt_session->subdiv_ccg;
+ if (pbvh == NULL || subdiv_ccg == NULL) {
+ return;
+ }
+ BLI_assert(BKE_pbvh_type(pbvh) == PBVH_GRIDS);
+ /* NOTE: Currently CCG does not keep track of faces, making it impossible
+ * to use BKE_pbvh_get_grid_updates().
+ */
+ CCGFace **faces;
+ int num_faces;
+ BKE_pbvh_get_grid_updates(pbvh, false, (void ***)&faces, &num_faces);
+ if (num_faces) {
+ BKE_subdiv_ccg_average_stitch_faces(subdiv_ccg, faces, num_faces);
+ MEM_freeN(faces);
+ }
+}
+
+DerivedMesh *multires_make_derived_from_derived(
+ DerivedMesh *dm, MultiresModifierData *mmd, Scene *scene, Object *ob, MultiresFlags flags)
+{
+ Mesh *me = ob->data;
+ DerivedMesh *result;
+ CCGDerivedMesh *ccgdm = NULL;
+ CCGElem **gridData, **subGridData;
+ CCGKey key;
+ const bool render = (flags & MULTIRES_USE_RENDER_PARAMS) != 0;
+ const bool ignore_simplify = (flags & MULTIRES_IGNORE_SIMPLIFY) != 0;
+ int lvl = multires_get_level(scene, ob, mmd, render, ignore_simplify);
+ int i, gridSize, numGrids;
+
+ if (lvl == 0)
+ return dm;
+
+ const int subsurf_flags = ignore_simplify ? SUBSURF_IGNORE_SIMPLIFY : 0;
+
+ result = subsurf_dm_create_local(scene,
+ ob,
+ dm,
+ lvl,
+ mmd->simple,
+ mmd->flags & eMultiresModifierFlag_ControlEdges,
+ mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE,
+ flags & MULTIRES_ALLOC_PAINT_MASK,
+ render,
+ subsurf_flags);
+
+ if (!(flags & MULTIRES_USE_LOCAL_MMD)) {
+ ccgdm = (CCGDerivedMesh *)result;
+
+ ccgdm->multires.ob = ob;
+ ccgdm->multires.mmd = mmd;
+ ccgdm->multires.local_mmd = 0;
+ ccgdm->multires.lvl = lvl;
+ ccgdm->multires.totlvl = mmd->totlvl;
+ ccgdm->multires.modified_flags = 0;
+ }
+
+ numGrids = result->getNumGrids(result);
+ gridSize = result->getGridSize(result);
+ gridData = result->getGridData(result);
+ result->getGridKey(result, &key);
+
+ subGridData = MEM_malloc_arrayN(numGrids, sizeof(CCGElem *), "subGridData*");
+
+ for (i = 0; i < numGrids; i++) {
+ subGridData[i] = MEM_malloc_arrayN(key.elem_size, gridSize * gridSize, "subGridData");
+ memcpy(subGridData[i], gridData[i], key.elem_size * gridSize * gridSize);
+ }
+
+ multires_set_tot_mdisps(me, mmd->totlvl);
+ CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop);
+
+ /*run displacement*/
+ multiresModifier_disp_run(result, ob->data, dm, APPLY_DISPLACEMENTS, subGridData, mmd->totlvl);
+
+ /* copy hidden elements for this level */
+ if (ccgdm)
+ multires_output_hidden_to_ccgdm(ccgdm, me, lvl);
+
+ for (i = 0; i < numGrids; i++)
+ MEM_freeN(subGridData[i]);
+ MEM_freeN(subGridData);
+
+ return result;
}
/**** Old Multires code ****
@@ -1430,874 +1464,988 @@ DerivedMesh *multires_make_derived_from_derived(DerivedMesh *dm,
/* Adapted from sculptmode.c */
void old_mdisps_bilinear(float out[3], float (*disps)[3], const int st, float u, float v)
{
- int x, y, x2, y2;
- const int st_max = st - 1;
- float urat, vrat, uopp;
- float d[4][3], d2[2][3];
-
- if (!disps || isnan(u) || isnan(v))
- return;
-
- if (u < 0)
- u = 0;
- else if (u >= st)
- u = st_max;
- if (v < 0)
- v = 0;
- else if (v >= st)
- v = st_max;
-
- x = floor(u);
- y = floor(v);
- x2 = x + 1;
- y2 = y + 1;
-
- if (x2 >= st) x2 = st_max;
- if (y2 >= st) y2 = st_max;
-
- urat = u - x;
- vrat = v - y;
- uopp = 1 - urat;
-
- mul_v3_v3fl(d[0], disps[y * st + x], uopp);
- mul_v3_v3fl(d[1], disps[y * st + x2], urat);
- mul_v3_v3fl(d[2], disps[y2 * st + x], uopp);
- mul_v3_v3fl(d[3], disps[y2 * st + x2], urat);
-
- add_v3_v3v3(d2[0], d[0], d[1]);
- add_v3_v3v3(d2[1], d[2], d[3]);
- mul_v3_fl(d2[0], 1 - vrat);
- mul_v3_fl(d2[1], vrat);
-
- add_v3_v3v3(out, d2[0], d2[1]);
-}
-
-static void old_mdisps_rotate(int S, int UNUSED(newside), int oldside, int x, int y, float *u, float *v)
-{
- float offset = oldside * 0.5f - 0.5f;
-
- if (S == 1) { *u = offset + x; *v = offset - y; }
- if (S == 2) { *u = offset + y; *v = offset + x; }
- if (S == 3) { *u = offset - x; *v = offset + y; }
- if (S == 0) { *u = offset - y; *v = offset - x; }
+ int x, y, x2, y2;
+ const int st_max = st - 1;
+ float urat, vrat, uopp;
+ float d[4][3], d2[2][3];
+
+ if (!disps || isnan(u) || isnan(v))
+ return;
+
+ if (u < 0)
+ u = 0;
+ else if (u >= st)
+ u = st_max;
+ if (v < 0)
+ v = 0;
+ else if (v >= st)
+ v = st_max;
+
+ x = floor(u);
+ y = floor(v);
+ x2 = x + 1;
+ y2 = y + 1;
+
+ if (x2 >= st)
+ x2 = st_max;
+ if (y2 >= st)
+ y2 = st_max;
+
+ urat = u - x;
+ vrat = v - y;
+ uopp = 1 - urat;
+
+ mul_v3_v3fl(d[0], disps[y * st + x], uopp);
+ mul_v3_v3fl(d[1], disps[y * st + x2], urat);
+ mul_v3_v3fl(d[2], disps[y2 * st + x], uopp);
+ mul_v3_v3fl(d[3], disps[y2 * st + x2], urat);
+
+ add_v3_v3v3(d2[0], d[0], d[1]);
+ add_v3_v3v3(d2[1], d[2], d[3]);
+ mul_v3_fl(d2[0], 1 - vrat);
+ mul_v3_fl(d2[1], vrat);
+
+ add_v3_v3v3(out, d2[0], d2[1]);
+}
+
+static void old_mdisps_rotate(
+ int S, int UNUSED(newside), int oldside, int x, int y, float *u, float *v)
+{
+ float offset = oldside * 0.5f - 0.5f;
+
+ if (S == 1) {
+ *u = offset + x;
+ *v = offset - y;
+ }
+ if (S == 2) {
+ *u = offset + y;
+ *v = offset + x;
+ }
+ if (S == 3) {
+ *u = offset - x;
+ *v = offset + y;
+ }
+ if (S == 0) {
+ *u = offset - y;
+ *v = offset - x;
+ }
}
static void old_mdisps_convert(MFace *mface, MDisps *mdisp)
{
- int newlvl = log(sqrt(mdisp->totdisp) - 1) / M_LN2;
- int oldlvl = newlvl + 1;
- int oldside = multires_side_tot[oldlvl];
- int newside = multires_side_tot[newlvl];
- int nvert = (mface->v4) ? 4 : 3;
- int newtotdisp = multires_grid_tot[newlvl] * nvert;
- int x, y, S;
- float (*disps)[3], (*out)[3], u = 0.0f, v = 0.0f; /* Quite gcc barking. */
-
- disps = MEM_calloc_arrayN(newtotdisp, 3 * sizeof(float), "multires disps");
-
- out = disps;
- for (S = 0; S < nvert; S++) {
- for (y = 0; y < newside; ++y) {
- for (x = 0; x < newside; ++x, ++out) {
- old_mdisps_rotate(S, newside, oldside, x, y, &u, &v);
- old_mdisps_bilinear(*out, mdisp->disps, oldside, u, v);
-
- if (S == 1) { (*out)[1] = -(*out)[1]; }
- else if (S == 2) { SWAP(float, (*out)[0], (*out)[1]); }
- else if (S == 3) { (*out)[0] = -(*out)[0]; }
- else if (S == 0) { SWAP(float, (*out)[0], (*out)[1]); (*out)[0] = -(*out)[0]; (*out)[1] = -(*out)[1]; }
- }
- }
- }
-
- MEM_freeN(mdisp->disps);
-
- mdisp->totdisp = newtotdisp;
- mdisp->level = newlvl;
- mdisp->disps = disps;
+ int newlvl = log(sqrt(mdisp->totdisp) - 1) / M_LN2;
+ int oldlvl = newlvl + 1;
+ int oldside = multires_side_tot[oldlvl];
+ int newside = multires_side_tot[newlvl];
+ int nvert = (mface->v4) ? 4 : 3;
+ int newtotdisp = multires_grid_tot[newlvl] * nvert;
+ int x, y, S;
+ float(*disps)[3], (*out)[3], u = 0.0f, v = 0.0f; /* Quite gcc barking. */
+
+ disps = MEM_calloc_arrayN(newtotdisp, 3 * sizeof(float), "multires disps");
+
+ out = disps;
+ for (S = 0; S < nvert; S++) {
+ for (y = 0; y < newside; ++y) {
+ for (x = 0; x < newside; ++x, ++out) {
+ old_mdisps_rotate(S, newside, oldside, x, y, &u, &v);
+ old_mdisps_bilinear(*out, mdisp->disps, oldside, u, v);
+
+ if (S == 1) {
+ (*out)[1] = -(*out)[1];
+ }
+ else if (S == 2) {
+ SWAP(float, (*out)[0], (*out)[1]);
+ }
+ else if (S == 3) {
+ (*out)[0] = -(*out)[0];
+ }
+ else if (S == 0) {
+ SWAP(float, (*out)[0], (*out)[1]);
+ (*out)[0] = -(*out)[0];
+ (*out)[1] = -(*out)[1];
+ }
+ }
+ }
+ }
+
+ MEM_freeN(mdisp->disps);
+
+ mdisp->totdisp = newtotdisp;
+ mdisp->level = newlvl;
+ mdisp->disps = disps;
}
void multires_load_old_250(Mesh *me)
{
- MDisps *mdisps, *mdisps2;
- MFace *mf;
- int i, j, k;
-
- mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS);
+ MDisps *mdisps, *mdisps2;
+ MFace *mf;
+ int i, j, k;
- if (mdisps) {
- for (i = 0; i < me->totface; i++)
- if (mdisps[i].totdisp)
- old_mdisps_convert(&me->mface[i], &mdisps[i]);
+ mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS);
- CustomData_add_layer(&me->ldata, CD_MDISPS, CD_CALLOC, NULL, me->totloop);
- mdisps2 = CustomData_get_layer(&me->ldata, CD_MDISPS);
+ if (mdisps) {
+ for (i = 0; i < me->totface; i++)
+ if (mdisps[i].totdisp)
+ old_mdisps_convert(&me->mface[i], &mdisps[i]);
- k = 0;
- mf = me->mface;
- for (i = 0; i < me->totface; i++, mf++) {
- int nvert = mf->v4 ? 4 : 3;
- int totdisp = mdisps[i].totdisp / nvert;
+ CustomData_add_layer(&me->ldata, CD_MDISPS, CD_CALLOC, NULL, me->totloop);
+ mdisps2 = CustomData_get_layer(&me->ldata, CD_MDISPS);
- for (j = 0; j < nvert; j++, k++) {
- mdisps2[k].disps = MEM_calloc_arrayN(totdisp, 3 * sizeof(float), "multires disp in conversion");
- mdisps2[k].totdisp = totdisp;
- mdisps2[k].level = mdisps[i].level;
- memcpy(mdisps2[k].disps, mdisps[i].disps + totdisp * j, totdisp);
- }
+ k = 0;
+ mf = me->mface;
+ for (i = 0; i < me->totface; i++, mf++) {
+ int nvert = mf->v4 ? 4 : 3;
+ int totdisp = mdisps[i].totdisp / nvert;
- }
- }
+ for (j = 0; j < nvert; j++, k++) {
+ mdisps2[k].disps = MEM_calloc_arrayN(
+ totdisp, 3 * sizeof(float), "multires disp in conversion");
+ mdisps2[k].totdisp = totdisp;
+ mdisps2[k].level = mdisps[i].level;
+ memcpy(mdisps2[k].disps, mdisps[i].disps + totdisp * j, totdisp);
+ }
+ }
+ }
}
/* Does not actually free lvl itself */
static void multires_free_level(MultiresLevel *lvl)
{
- if (lvl) {
- if (lvl->faces) MEM_freeN(lvl->faces);
- if (lvl->edges) MEM_freeN(lvl->edges);
- if (lvl->colfaces) MEM_freeN(lvl->colfaces);
- }
+ if (lvl) {
+ if (lvl->faces)
+ MEM_freeN(lvl->faces);
+ if (lvl->edges)
+ MEM_freeN(lvl->edges);
+ if (lvl->colfaces)
+ MEM_freeN(lvl->colfaces);
+ }
}
void multires_free(Multires *mr)
{
- if (mr) {
- MultiresLevel *lvl = mr->levels.first;
+ if (mr) {
+ MultiresLevel *lvl = mr->levels.first;
- /* Free the first-level data */
- if (lvl) {
- CustomData_free(&mr->vdata, lvl->totvert);
- CustomData_free(&mr->fdata, lvl->totface);
- if (mr->edge_flags)
- MEM_freeN(mr->edge_flags);
- if (mr->edge_creases)
- MEM_freeN(mr->edge_creases);
- }
+ /* Free the first-level data */
+ if (lvl) {
+ CustomData_free(&mr->vdata, lvl->totvert);
+ CustomData_free(&mr->fdata, lvl->totface);
+ if (mr->edge_flags)
+ MEM_freeN(mr->edge_flags);
+ if (mr->edge_creases)
+ MEM_freeN(mr->edge_creases);
+ }
- while (lvl) {
- multires_free_level(lvl);
- lvl = lvl->next;
- }
+ while (lvl) {
+ multires_free_level(lvl);
+ lvl = lvl->next;
+ }
- /* mr->verts may be NULL when loading old files, see direct_link_mesh() in readfile.c, and T43560. */
- MEM_SAFE_FREE(mr->verts);
+ /* mr->verts may be NULL when loading old files, see direct_link_mesh() in readfile.c, and T43560. */
+ MEM_SAFE_FREE(mr->verts);
- BLI_freelistN(&mr->levels);
+ BLI_freelistN(&mr->levels);
- MEM_freeN(mr);
- }
+ MEM_freeN(mr);
+ }
}
typedef struct IndexNode {
- struct IndexNode *next, *prev;
- int index;
+ struct IndexNode *next, *prev;
+ int index;
} IndexNode;
-static void create_old_vert_face_map(ListBase **map, IndexNode **mem, const MultiresFace *mface,
- const int totvert, const int totface)
+static void create_old_vert_face_map(ListBase **map,
+ IndexNode **mem,
+ const MultiresFace *mface,
+ const int totvert,
+ const int totface)
{
- int i, j;
- IndexNode *node = NULL;
+ int i, j;
+ IndexNode *node = NULL;
- (*map) = MEM_calloc_arrayN(totvert, sizeof(ListBase), "vert face map");
- (*mem) = MEM_calloc_arrayN(totface, 4 * sizeof(IndexNode), "vert face map mem");
- node = *mem;
+ (*map) = MEM_calloc_arrayN(totvert, sizeof(ListBase), "vert face map");
+ (*mem) = MEM_calloc_arrayN(totface, 4 * sizeof(IndexNode), "vert face map mem");
+ node = *mem;
- /* Find the users */
- for (i = 0; i < totface; ++i) {
- for (j = 0; j < (mface[i].v[3] ? 4 : 3); ++j, ++node) {
- node->index = i;
- BLI_addtail(&(*map)[mface[i].v[j]], node);
- }
- }
+ /* Find the users */
+ for (i = 0; i < totface; ++i) {
+ for (j = 0; j < (mface[i].v[3] ? 4 : 3); ++j, ++node) {
+ node->index = i;
+ BLI_addtail(&(*map)[mface[i].v[j]], node);
+ }
+ }
}
-static void create_old_vert_edge_map(ListBase **map, IndexNode **mem, const MultiresEdge *medge,
- const int totvert, const int totedge)
+static void create_old_vert_edge_map(ListBase **map,
+ IndexNode **mem,
+ const MultiresEdge *medge,
+ const int totvert,
+ const int totedge)
{
- int i, j;
- IndexNode *node = NULL;
+ int i, j;
+ IndexNode *node = NULL;
- (*map) = MEM_calloc_arrayN(totvert, sizeof(ListBase), "vert edge map");
- (*mem) = MEM_calloc_arrayN(totedge, 2 * sizeof(IndexNode), "vert edge map mem");
- node = *mem;
+ (*map) = MEM_calloc_arrayN(totvert, sizeof(ListBase), "vert edge map");
+ (*mem) = MEM_calloc_arrayN(totedge, 2 * sizeof(IndexNode), "vert edge map mem");
+ node = *mem;
- /* Find the users */
- for (i = 0; i < totedge; ++i) {
- for (j = 0; j < 2; ++j, ++node) {
- node->index = i;
- BLI_addtail(&(*map)[medge[i].v[j]], node);
- }
- }
+ /* Find the users */
+ for (i = 0; i < totedge; ++i) {
+ for (j = 0; j < 2; ++j, ++node) {
+ node->index = i;
+ BLI_addtail(&(*map)[medge[i].v[j]], node);
+ }
+ }
}
-static MultiresFace *find_old_face(ListBase *map, MultiresFace *faces, int v1, int v2, int v3, int v4)
+static MultiresFace *find_old_face(
+ ListBase *map, MultiresFace *faces, int v1, int v2, int v3, int v4)
{
- IndexNode *n1;
- int v[4], i, j;
+ IndexNode *n1;
+ int v[4], i, j;
- v[0] = v1;
- v[1] = v2;
- v[2] = v3;
- v[3] = v4;
+ v[0] = v1;
+ v[1] = v2;
+ v[2] = v3;
+ v[3] = v4;
- for (n1 = map[v1].first; n1; n1 = n1->next) {
- int fnd[4] = {0, 0, 0, 0};
+ for (n1 = map[v1].first; n1; n1 = n1->next) {
+ int fnd[4] = {0, 0, 0, 0};
- for (i = 0; i < 4; ++i) {
- for (j = 0; j < 4; ++j) {
- if (v[i] == faces[n1->index].v[j])
- fnd[i] = 1;
- }
- }
+ for (i = 0; i < 4; ++i) {
+ for (j = 0; j < 4; ++j) {
+ if (v[i] == faces[n1->index].v[j])
+ fnd[i] = 1;
+ }
+ }
- if (fnd[0] && fnd[1] && fnd[2] && fnd[3])
- return &faces[n1->index];
- }
+ if (fnd[0] && fnd[1] && fnd[2] && fnd[3])
+ return &faces[n1->index];
+ }
- return NULL;
+ return NULL;
}
static MultiresEdge *find_old_edge(ListBase *map, MultiresEdge *edges, int v1, int v2)
{
- IndexNode *n1, *n2;
-
- for (n1 = map[v1].first; n1; n1 = n1->next) {
- for (n2 = map[v2].first; n2; n2 = n2->next) {
- if (n1->index == n2->index)
- return &edges[n1->index];
- }
- }
-
- return NULL;
-}
-
-static void multires_load_old_edges(ListBase **emap, MultiresLevel *lvl, int *vvmap, int dst, int v1, int v2, int mov)
-{
- int emid = find_old_edge(emap[2], lvl->edges, v1, v2)->mid;
- vvmap[dst + mov] = emid;
-
- if (lvl->next->next) {
- multires_load_old_edges(emap + 1, lvl->next, vvmap, dst + mov, v1, emid, mov / 2);
- multires_load_old_edges(emap + 1, lvl->next, vvmap, dst + mov, v2, emid, -mov / 2);
- }
-}
-
-static void multires_load_old_faces(ListBase **fmap, ListBase **emap, MultiresLevel *lvl, int *vvmap, int dst,
- int v1, int v2, int v3, int v4, int st2, int st3)
-{
- int fmid;
- int emid13, emid14, emid23, emid24;
-
- if (lvl && lvl->next) {
- fmid = find_old_face(fmap[1], lvl->faces, v1, v2, v3, v4)->mid;
- vvmap[dst] = fmid;
-
- emid13 = find_old_edge(emap[1], lvl->edges, v1, v3)->mid;
- emid14 = find_old_edge(emap[1], lvl->edges, v1, v4)->mid;
- emid23 = find_old_edge(emap[1], lvl->edges, v2, v3)->mid;
- emid24 = find_old_edge(emap[1], lvl->edges, v2, v4)->mid;
-
-
- multires_load_old_faces(fmap + 1, emap + 1, lvl->next, vvmap, dst + st2 * st3 + st3,
- fmid, v2, emid23, emid24, st2, st3 / 2);
-
- multires_load_old_faces(fmap + 1, emap + 1, lvl->next, vvmap, dst - st2 * st3 + st3,
- emid14, emid24, fmid, v4, st2, st3 / 2);
-
- multires_load_old_faces(fmap + 1, emap + 1, lvl->next, vvmap, dst + st2 * st3 - st3,
- emid13, emid23, v3, fmid, st2, st3 / 2);
-
- multires_load_old_faces(fmap + 1, emap + 1, lvl->next, vvmap, dst - st2 * st3 - st3,
- v1, fmid, emid13, emid14, st2, st3 / 2);
-
- if (lvl->next->next) {
- multires_load_old_edges(emap, lvl->next, vvmap, dst, emid24, fmid, st3);
- multires_load_old_edges(emap, lvl->next, vvmap, dst, emid13, fmid, -st3);
- multires_load_old_edges(emap, lvl->next, vvmap, dst, emid14, fmid, -st2 * st3);
- multires_load_old_edges(emap, lvl->next, vvmap, dst, emid23, fmid, st2 * st3);
- }
- }
+ IndexNode *n1, *n2;
+
+ for (n1 = map[v1].first; n1; n1 = n1->next) {
+ for (n2 = map[v2].first; n2; n2 = n2->next) {
+ if (n1->index == n2->index)
+ return &edges[n1->index];
+ }
+ }
+
+ return NULL;
+}
+
+static void multires_load_old_edges(
+ ListBase **emap, MultiresLevel *lvl, int *vvmap, int dst, int v1, int v2, int mov)
+{
+ int emid = find_old_edge(emap[2], lvl->edges, v1, v2)->mid;
+ vvmap[dst + mov] = emid;
+
+ if (lvl->next->next) {
+ multires_load_old_edges(emap + 1, lvl->next, vvmap, dst + mov, v1, emid, mov / 2);
+ multires_load_old_edges(emap + 1, lvl->next, vvmap, dst + mov, v2, emid, -mov / 2);
+ }
+}
+
+static void multires_load_old_faces(ListBase **fmap,
+ ListBase **emap,
+ MultiresLevel *lvl,
+ int *vvmap,
+ int dst,
+ int v1,
+ int v2,
+ int v3,
+ int v4,
+ int st2,
+ int st3)
+{
+ int fmid;
+ int emid13, emid14, emid23, emid24;
+
+ if (lvl && lvl->next) {
+ fmid = find_old_face(fmap[1], lvl->faces, v1, v2, v3, v4)->mid;
+ vvmap[dst] = fmid;
+
+ emid13 = find_old_edge(emap[1], lvl->edges, v1, v3)->mid;
+ emid14 = find_old_edge(emap[1], lvl->edges, v1, v4)->mid;
+ emid23 = find_old_edge(emap[1], lvl->edges, v2, v3)->mid;
+ emid24 = find_old_edge(emap[1], lvl->edges, v2, v4)->mid;
+
+ multires_load_old_faces(fmap + 1,
+ emap + 1,
+ lvl->next,
+ vvmap,
+ dst + st2 * st3 + st3,
+ fmid,
+ v2,
+ emid23,
+ emid24,
+ st2,
+ st3 / 2);
+
+ multires_load_old_faces(fmap + 1,
+ emap + 1,
+ lvl->next,
+ vvmap,
+ dst - st2 * st3 + st3,
+ emid14,
+ emid24,
+ fmid,
+ v4,
+ st2,
+ st3 / 2);
+
+ multires_load_old_faces(fmap + 1,
+ emap + 1,
+ lvl->next,
+ vvmap,
+ dst + st2 * st3 - st3,
+ emid13,
+ emid23,
+ v3,
+ fmid,
+ st2,
+ st3 / 2);
+
+ multires_load_old_faces(fmap + 1,
+ emap + 1,
+ lvl->next,
+ vvmap,
+ dst - st2 * st3 - st3,
+ v1,
+ fmid,
+ emid13,
+ emid14,
+ st2,
+ st3 / 2);
+
+ if (lvl->next->next) {
+ multires_load_old_edges(emap, lvl->next, vvmap, dst, emid24, fmid, st3);
+ multires_load_old_edges(emap, lvl->next, vvmap, dst, emid13, fmid, -st3);
+ multires_load_old_edges(emap, lvl->next, vvmap, dst, emid14, fmid, -st2 * st3);
+ multires_load_old_edges(emap, lvl->next, vvmap, dst, emid23, fmid, st2 * st3);
+ }
+ }
}
static void multires_mvert_to_ss(DerivedMesh *dm, MVert *mvert)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGElem *vd;
- CCGKey key;
- int index;
- int totvert, totedge, totface;
- int gridSize = ccgSubSurf_getGridSize(ss);
- int edgeSize = ccgSubSurf_getEdgeSize(ss);
- int i = 0;
-
- dm->getGridKey(dm, &key);
-
- totface = ccgSubSurf_getNumFaces(ss);
- for (index = 0; index < totface; index++) {
- CCGFace *f = ccgdm->faceMap[index].face;
- int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
-
- vd = ccgSubSurf_getFaceCenterData(f);
- copy_v3_v3(CCG_elem_co(&key, vd), mvert[i].co);
- i++;
-
- for (S = 0; S < numVerts; S++) {
- for (x = 1; x < gridSize - 1; x++, i++) {
- vd = ccgSubSurf_getFaceGridEdgeData(ss, f, S, x);
- copy_v3_v3(CCG_elem_co(&key, vd), mvert[i].co);
- }
- }
-
- for (S = 0; S < numVerts; S++) {
- for (y = 1; y < gridSize - 1; y++) {
- for (x = 1; x < gridSize - 1; x++, i++) {
- vd = ccgSubSurf_getFaceGridData(ss, f, S, x, y);
- copy_v3_v3(CCG_elem_co(&key, vd), mvert[i].co);
- }
- }
- }
- }
-
- totedge = ccgSubSurf_getNumEdges(ss);
- for (index = 0; index < totedge; index++) {
- CCGEdge *e = ccgdm->edgeMap[index].edge;
- int x;
-
- for (x = 1; x < edgeSize - 1; x++, i++) {
- vd = ccgSubSurf_getEdgeData(ss, e, x);
- copy_v3_v3(CCG_elem_co(&key, vd), mvert[i].co);
- }
- }
-
- totvert = ccgSubSurf_getNumVerts(ss);
- for (index = 0; index < totvert; index++) {
- CCGVert *v = ccgdm->vertMap[index].vert;
-
- vd = ccgSubSurf_getVertData(ss, v);
- copy_v3_v3(CCG_elem_co(&key, vd), mvert[i].co);
- i++;
- }
-
- ccgSubSurf_updateToFaces(ss, 0, NULL, 0);
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ CCGElem *vd;
+ CCGKey key;
+ int index;
+ int totvert, totedge, totface;
+ int gridSize = ccgSubSurf_getGridSize(ss);
+ int edgeSize = ccgSubSurf_getEdgeSize(ss);
+ int i = 0;
+
+ dm->getGridKey(dm, &key);
+
+ totface = ccgSubSurf_getNumFaces(ss);
+ for (index = 0; index < totface; index++) {
+ CCGFace *f = ccgdm->faceMap[index].face;
+ int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
+
+ vd = ccgSubSurf_getFaceCenterData(f);
+ copy_v3_v3(CCG_elem_co(&key, vd), mvert[i].co);
+ i++;
+
+ for (S = 0; S < numVerts; S++) {
+ for (x = 1; x < gridSize - 1; x++, i++) {
+ vd = ccgSubSurf_getFaceGridEdgeData(ss, f, S, x);
+ copy_v3_v3(CCG_elem_co(&key, vd), mvert[i].co);
+ }
+ }
+
+ for (S = 0; S < numVerts; S++) {
+ for (y = 1; y < gridSize - 1; y++) {
+ for (x = 1; x < gridSize - 1; x++, i++) {
+ vd = ccgSubSurf_getFaceGridData(ss, f, S, x, y);
+ copy_v3_v3(CCG_elem_co(&key, vd), mvert[i].co);
+ }
+ }
+ }
+ }
+
+ totedge = ccgSubSurf_getNumEdges(ss);
+ for (index = 0; index < totedge; index++) {
+ CCGEdge *e = ccgdm->edgeMap[index].edge;
+ int x;
+
+ for (x = 1; x < edgeSize - 1; x++, i++) {
+ vd = ccgSubSurf_getEdgeData(ss, e, x);
+ copy_v3_v3(CCG_elem_co(&key, vd), mvert[i].co);
+ }
+ }
+
+ totvert = ccgSubSurf_getNumVerts(ss);
+ for (index = 0; index < totvert; index++) {
+ CCGVert *v = ccgdm->vertMap[index].vert;
+
+ vd = ccgSubSurf_getVertData(ss, v);
+ copy_v3_v3(CCG_elem_co(&key, vd), mvert[i].co);
+ i++;
+ }
+
+ ccgSubSurf_updateToFaces(ss, 0, NULL, 0);
}
/* Loads a multires object stored in the old Multires struct into the new format */
static void multires_load_old_dm(DerivedMesh *dm, Mesh *me, int totlvl)
{
- MultiresLevel *lvl, *lvl1;
- Multires *mr = me->mr;
- MVert *vsrc, *vdst;
- unsigned int src, dst;
- int st_last = multires_side_tot[totlvl - 1] - 1;
- int extedgelen = multires_side_tot[totlvl] - 2;
- int *vvmap; // inorder for dst, map to src
- int crossedgelen;
- int s, x, tottri, totquad;
- unsigned int i, j, totvert;
-
- src = 0;
- vsrc = mr->verts;
- vdst = dm->getVertArray(dm);
- totvert = (unsigned int)dm->getNumVerts(dm);
- vvmap = MEM_calloc_arrayN(totvert, sizeof(int), "multires vvmap");
-
- if (!vvmap) {
- return;
- }
-
- lvl1 = mr->levels.first;
- /* Load base verts */
- for (i = 0; i < lvl1->totvert; ++i) {
- vvmap[totvert - lvl1->totvert + i] = src;
- src++;
- }
-
- /* Original edges */
- dst = totvert - lvl1->totvert - extedgelen * lvl1->totedge;
- for (i = 0; i < lvl1->totedge; ++i) {
- int ldst = dst + extedgelen * i;
- int lsrc = src;
- lvl = lvl1->next;
-
- for (j = 2; j <= mr->level_count; ++j) {
- int base = multires_side_tot[totlvl - j + 1] - 2;
- int skip = multires_side_tot[totlvl - j + 2] - 1;
- int st = multires_side_tot[j - 1] - 1;
-
- for (x = 0; x < st; ++x)
- vvmap[ldst + base + x * skip] = lsrc + st * i + x;
-
- lsrc += lvl->totvert - lvl->prev->totvert;
- lvl = lvl->next;
- }
- }
-
- /* Center points */
- dst = 0;
- for (i = 0; i < lvl1->totface; ++i) {
- int sides = lvl1->faces[i].v[3] ? 4 : 3;
-
- vvmap[dst] = src + lvl1->totedge + i;
- dst += 1 + sides * (st_last - 1) * st_last;
- }
-
-
- /* The rest is only for level 3 and up */
- if (lvl1->next && lvl1->next->next) {
- ListBase **fmap, **emap;
- IndexNode **fmem, **emem;
-
- /* Face edge cross */
- tottri = totquad = 0;
- crossedgelen = multires_side_tot[totlvl - 1] - 2;
- dst = 0;
- for (i = 0; i < lvl1->totface; ++i) {
- int sides = lvl1->faces[i].v[3] ? 4 : 3;
-
- lvl = lvl1->next->next;
- dst++;
-
- for (j = 3; j <= mr->level_count; ++j) {
- int base = multires_side_tot[totlvl - j + 1] - 2;
- int skip = multires_side_tot[totlvl - j + 2] - 1;
- int st = pow(2, j - 2);
- int st2 = pow(2, j - 3);
- int lsrc = lvl->prev->totvert;
-
- /* Skip exterior edge verts */
- lsrc += lvl1->totedge * st;
-
- /* Skip earlier face edge crosses */
- lsrc += st2 * (tottri * 3 + totquad * 4);
-
- for (s = 0; s < sides; ++s) {
- for (x = 0; x < st2; ++x) {
- vvmap[dst + crossedgelen * (s + 1) - base - x * skip - 1] = lsrc;
- lsrc++;
- }
- }
-
- lvl = lvl->next;
- }
-
- dst += sides * (st_last - 1) * st_last;
-
- if (sides == 4) ++totquad;
- else ++tottri;
-
- }
-
- /* calculate vert to edge/face maps for each level (except the last) */
- fmap = MEM_calloc_arrayN((mr->level_count - 1), sizeof(ListBase *), "multires fmap");
- emap = MEM_calloc_arrayN((mr->level_count - 1), sizeof(ListBase *), "multires emap");
- fmem = MEM_calloc_arrayN((mr->level_count - 1), sizeof(IndexNode *), "multires fmem");
- emem = MEM_calloc_arrayN((mr->level_count - 1), sizeof(IndexNode *), "multires emem");
- lvl = lvl1;
- for (i = 0; i < (unsigned int)mr->level_count - 1; ++i) {
- create_old_vert_face_map(fmap + i, fmem + i, lvl->faces, lvl->totvert, lvl->totface);
- create_old_vert_edge_map(emap + i, emem + i, lvl->edges, lvl->totvert, lvl->totedge);
- lvl = lvl->next;
- }
-
- /* Interior face verts */
- /* lvl = lvl1->next->next; */ /* UNUSED */
- dst = 0;
- for (j = 0; j < lvl1->totface; ++j) {
- int sides = lvl1->faces[j].v[3] ? 4 : 3;
- int ldst = dst + 1 + sides * (st_last - 1);
-
- for (s = 0; s < sides; ++s) {
- int st2 = multires_side_tot[totlvl - 1] - 2;
- int st3 = multires_side_tot[totlvl - 2] - 2;
- int st4 = st3 == 0 ? 1 : (st3 + 1) / 2;
- int mid = ldst + st2 * st3 + st3;
- int cv = lvl1->faces[j].v[s];
- int nv = lvl1->faces[j].v[s == sides - 1 ? 0 : s + 1];
- int pv = lvl1->faces[j].v[s == 0 ? sides - 1 : s - 1];
-
- multires_load_old_faces(fmap, emap, lvl1->next, vvmap, mid,
- vvmap[dst], cv,
- find_old_edge(emap[0], lvl1->edges, pv, cv)->mid,
- find_old_edge(emap[0], lvl1->edges, cv, nv)->mid,
- st2, st4);
-
- ldst += (st_last - 1) * (st_last - 1);
- }
-
-
- dst = ldst;
- }
-
- /*lvl = lvl->next;*/ /*UNUSED*/
-
- for (i = 0; i < (unsigned int)(mr->level_count - 1); ++i) {
- MEM_freeN(fmap[i]);
- MEM_freeN(fmem[i]);
- MEM_freeN(emap[i]);
- MEM_freeN(emem[i]);
- }
-
- MEM_freeN(fmap);
- MEM_freeN(emap);
- MEM_freeN(fmem);
- MEM_freeN(emem);
- }
-
- /* Transfer verts */
- for (i = 0; i < totvert; ++i)
- copy_v3_v3(vdst[i].co, vsrc[vvmap[i]].co);
-
- MEM_freeN(vvmap);
-
- multires_mvert_to_ss(dm, vdst);
+ MultiresLevel *lvl, *lvl1;
+ Multires *mr = me->mr;
+ MVert *vsrc, *vdst;
+ unsigned int src, dst;
+ int st_last = multires_side_tot[totlvl - 1] - 1;
+ int extedgelen = multires_side_tot[totlvl] - 2;
+ int *vvmap; // inorder for dst, map to src
+ int crossedgelen;
+ int s, x, tottri, totquad;
+ unsigned int i, j, totvert;
+
+ src = 0;
+ vsrc = mr->verts;
+ vdst = dm->getVertArray(dm);
+ totvert = (unsigned int)dm->getNumVerts(dm);
+ vvmap = MEM_calloc_arrayN(totvert, sizeof(int), "multires vvmap");
+
+ if (!vvmap) {
+ return;
+ }
+
+ lvl1 = mr->levels.first;
+ /* Load base verts */
+ for (i = 0; i < lvl1->totvert; ++i) {
+ vvmap[totvert - lvl1->totvert + i] = src;
+ src++;
+ }
+
+ /* Original edges */
+ dst = totvert - lvl1->totvert - extedgelen * lvl1->totedge;
+ for (i = 0; i < lvl1->totedge; ++i) {
+ int ldst = dst + extedgelen * i;
+ int lsrc = src;
+ lvl = lvl1->next;
+
+ for (j = 2; j <= mr->level_count; ++j) {
+ int base = multires_side_tot[totlvl - j + 1] - 2;
+ int skip = multires_side_tot[totlvl - j + 2] - 1;
+ int st = multires_side_tot[j - 1] - 1;
+
+ for (x = 0; x < st; ++x)
+ vvmap[ldst + base + x * skip] = lsrc + st * i + x;
+
+ lsrc += lvl->totvert - lvl->prev->totvert;
+ lvl = lvl->next;
+ }
+ }
+
+ /* Center points */
+ dst = 0;
+ for (i = 0; i < lvl1->totface; ++i) {
+ int sides = lvl1->faces[i].v[3] ? 4 : 3;
+
+ vvmap[dst] = src + lvl1->totedge + i;
+ dst += 1 + sides * (st_last - 1) * st_last;
+ }
+
+ /* The rest is only for level 3 and up */
+ if (lvl1->next && lvl1->next->next) {
+ ListBase **fmap, **emap;
+ IndexNode **fmem, **emem;
+
+ /* Face edge cross */
+ tottri = totquad = 0;
+ crossedgelen = multires_side_tot[totlvl - 1] - 2;
+ dst = 0;
+ for (i = 0; i < lvl1->totface; ++i) {
+ int sides = lvl1->faces[i].v[3] ? 4 : 3;
+
+ lvl = lvl1->next->next;
+ dst++;
+
+ for (j = 3; j <= mr->level_count; ++j) {
+ int base = multires_side_tot[totlvl - j + 1] - 2;
+ int skip = multires_side_tot[totlvl - j + 2] - 1;
+ int st = pow(2, j - 2);
+ int st2 = pow(2, j - 3);
+ int lsrc = lvl->prev->totvert;
+
+ /* Skip exterior edge verts */
+ lsrc += lvl1->totedge * st;
+
+ /* Skip earlier face edge crosses */
+ lsrc += st2 * (tottri * 3 + totquad * 4);
+
+ for (s = 0; s < sides; ++s) {
+ for (x = 0; x < st2; ++x) {
+ vvmap[dst + crossedgelen * (s + 1) - base - x * skip - 1] = lsrc;
+ lsrc++;
+ }
+ }
+
+ lvl = lvl->next;
+ }
+
+ dst += sides * (st_last - 1) * st_last;
+
+ if (sides == 4)
+ ++totquad;
+ else
+ ++tottri;
+ }
+
+ /* calculate vert to edge/face maps for each level (except the last) */
+ fmap = MEM_calloc_arrayN((mr->level_count - 1), sizeof(ListBase *), "multires fmap");
+ emap = MEM_calloc_arrayN((mr->level_count - 1), sizeof(ListBase *), "multires emap");
+ fmem = MEM_calloc_arrayN((mr->level_count - 1), sizeof(IndexNode *), "multires fmem");
+ emem = MEM_calloc_arrayN((mr->level_count - 1), sizeof(IndexNode *), "multires emem");
+ lvl = lvl1;
+ for (i = 0; i < (unsigned int)mr->level_count - 1; ++i) {
+ create_old_vert_face_map(fmap + i, fmem + i, lvl->faces, lvl->totvert, lvl->totface);
+ create_old_vert_edge_map(emap + i, emem + i, lvl->edges, lvl->totvert, lvl->totedge);
+ lvl = lvl->next;
+ }
+
+ /* Interior face verts */
+ /* lvl = lvl1->next->next; */ /* UNUSED */
+ dst = 0;
+ for (j = 0; j < lvl1->totface; ++j) {
+ int sides = lvl1->faces[j].v[3] ? 4 : 3;
+ int ldst = dst + 1 + sides * (st_last - 1);
+
+ for (s = 0; s < sides; ++s) {
+ int st2 = multires_side_tot[totlvl - 1] - 2;
+ int st3 = multires_side_tot[totlvl - 2] - 2;
+ int st4 = st3 == 0 ? 1 : (st3 + 1) / 2;
+ int mid = ldst + st2 * st3 + st3;
+ int cv = lvl1->faces[j].v[s];
+ int nv = lvl1->faces[j].v[s == sides - 1 ? 0 : s + 1];
+ int pv = lvl1->faces[j].v[s == 0 ? sides - 1 : s - 1];
+
+ multires_load_old_faces(fmap,
+ emap,
+ lvl1->next,
+ vvmap,
+ mid,
+ vvmap[dst],
+ cv,
+ find_old_edge(emap[0], lvl1->edges, pv, cv)->mid,
+ find_old_edge(emap[0], lvl1->edges, cv, nv)->mid,
+ st2,
+ st4);
+
+ ldst += (st_last - 1) * (st_last - 1);
+ }
+
+ dst = ldst;
+ }
+
+ /*lvl = lvl->next;*/ /*UNUSED*/
+
+ for (i = 0; i < (unsigned int)(mr->level_count - 1); ++i) {
+ MEM_freeN(fmap[i]);
+ MEM_freeN(fmem[i]);
+ MEM_freeN(emap[i]);
+ MEM_freeN(emem[i]);
+ }
+
+ MEM_freeN(fmap);
+ MEM_freeN(emap);
+ MEM_freeN(fmem);
+ MEM_freeN(emem);
+ }
+
+ /* Transfer verts */
+ for (i = 0; i < totvert; ++i)
+ copy_v3_v3(vdst[i].co, vsrc[vvmap[i]].co);
+
+ MEM_freeN(vvmap);
+
+ multires_mvert_to_ss(dm, vdst);
}
/* Copy the first-level vcol data to the mesh, if it exists */
/* Warning: higher-level vcol data will be lost */
static void multires_load_old_vcols(Mesh *me)
{
- MultiresLevel *lvl;
- MultiresColFace *colface;
- MCol *mcol;
- int i, j;
+ MultiresLevel *lvl;
+ MultiresColFace *colface;
+ MCol *mcol;
+ int i, j;
- if (!(lvl = me->mr->levels.first))
- return;
+ if (!(lvl = me->mr->levels.first))
+ return;
- if (!(colface = lvl->colfaces))
- return;
+ if (!(colface = lvl->colfaces))
+ return;
- /* older multires format never supported multiple vcol layers,
- * so we can assume the active vcol layer is the correct one */
- if (!(mcol = CustomData_get_layer(&me->fdata, CD_MCOL)))
- return;
+ /* older multires format never supported multiple vcol layers,
+ * so we can assume the active vcol layer is the correct one */
+ if (!(mcol = CustomData_get_layer(&me->fdata, CD_MCOL)))
+ return;
- for (i = 0; i < me->totface; ++i) {
- for (j = 0; j < 4; ++j) {
- mcol[i * 4 + j].a = colface[i].col[j].a;
- mcol[i * 4 + j].r = colface[i].col[j].r;
- mcol[i * 4 + j].g = colface[i].col[j].g;
- mcol[i * 4 + j].b = colface[i].col[j].b;
- }
- }
+ for (i = 0; i < me->totface; ++i) {
+ for (j = 0; j < 4; ++j) {
+ mcol[i * 4 + j].a = colface[i].col[j].a;
+ mcol[i * 4 + j].r = colface[i].col[j].r;
+ mcol[i * 4 + j].g = colface[i].col[j].g;
+ mcol[i * 4 + j].b = colface[i].col[j].b;
+ }
+ }
}
/* Copy the first-level face-flag data to the mesh */
static void multires_load_old_face_flags(Mesh *me)
{
- MultiresLevel *lvl;
- MultiresFace *faces;
- int i;
+ MultiresLevel *lvl;
+ MultiresFace *faces;
+ int i;
- if (!(lvl = me->mr->levels.first))
- return;
+ if (!(lvl = me->mr->levels.first))
+ return;
- if (!(faces = lvl->faces))
- return;
+ if (!(faces = lvl->faces))
+ return;
- for (i = 0; i < me->totface; ++i)
- me->mface[i].flag = faces[i].flag;
+ for (i = 0; i < me->totface; ++i)
+ me->mface[i].flag = faces[i].flag;
}
void multires_load_old(Object *ob, Mesh *me)
{
- MultiresLevel *lvl;
- ModifierData *md;
- MultiresModifierData *mmd;
- DerivedMesh *dm, *orig;
- CustomDataLayer *l;
- int i;
-
- /* Load original level into the mesh */
- lvl = me->mr->levels.first;
- CustomData_free_layers(&me->vdata, CD_MVERT, lvl->totvert);
- CustomData_free_layers(&me->edata, CD_MEDGE, lvl->totedge);
- CustomData_free_layers(&me->fdata, CD_MFACE, lvl->totface);
- me->totvert = lvl->totvert;
- me->totedge = lvl->totedge;
- me->totface = lvl->totface;
- me->mvert = CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, me->totvert);
- me->medge = CustomData_add_layer(&me->edata, CD_MEDGE, CD_CALLOC, NULL, me->totedge);
- me->mface = CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, NULL, me->totface);
- memcpy(me->mvert, me->mr->verts, sizeof(MVert) * me->totvert);
- for (i = 0; i < me->totedge; ++i) {
- me->medge[i].v1 = lvl->edges[i].v[0];
- me->medge[i].v2 = lvl->edges[i].v[1];
- }
- for (i = 0; i < me->totface; ++i) {
- me->mface[i].v1 = lvl->faces[i].v[0];
- me->mface[i].v2 = lvl->faces[i].v[1];
- me->mface[i].v3 = lvl->faces[i].v[2];
- me->mface[i].v4 = lvl->faces[i].v[3];
- me->mface[i].mat_nr = lvl->faces[i].mat_nr;
- }
-
- /* Copy the first-level data to the mesh */
- /* XXX We must do this before converting tessfaces to polys/lopps! */
- for (i = 0, l = me->mr->vdata.layers; i < me->mr->vdata.totlayer; ++i, ++l)
- CustomData_add_layer(&me->vdata, l->type, CD_REFERENCE, l->data, me->totvert);
- for (i = 0, l = me->mr->fdata.layers; i < me->mr->fdata.totlayer; ++i, ++l)
- CustomData_add_layer(&me->fdata, l->type, CD_REFERENCE, l->data, me->totface);
- CustomData_reset(&me->mr->vdata);
- CustomData_reset(&me->mr->fdata);
-
- multires_load_old_vcols(me);
- multires_load_old_face_flags(me);
-
- /* multiresModifier_subdivide (actually, multires_subdivide) expects polys, not tessfaces! */
- BKE_mesh_convert_mfaces_to_mpolys(me);
-
- /* Add a multires modifier to the object */
- md = ob->modifiers.first;
- while (md && modifierType_getInfo(md->type)->type == eModifierTypeType_OnlyDeform)
- md = md->next;
- mmd = (MultiresModifierData *)modifier_new(eModifierType_Multires);
- BLI_insertlinkbefore(&ob->modifiers, md, mmd);
-
- for (i = 0; i < me->mr->level_count - 1; ++i)
- multiresModifier_subdivide(mmd, NULL, ob, 1, 0);
-
- mmd->lvl = mmd->totlvl;
- orig = CDDM_from_mesh(me);
- /* XXX We *must* alloc paint mask here, else we have some kind of mismatch in
- * multires_modifier_update_mdisps() (called by dm->release(dm)), which always creates the
- * reference subsurfed dm with this option, before calling multiresModifier_disp_run(),
- * which implicitly expects both subsurfs from its first dm and oldGridData parameters to
- * be of the same "format"! */
- dm = multires_make_derived_from_derived(orig, mmd, NULL, ob, 0);
-
- multires_load_old_dm(dm, me, mmd->totlvl + 1);
-
- multires_dm_mark_as_modified(dm, MULTIRES_COORDS_MODIFIED);
- dm->release(dm);
- orig->release(orig);
-
- /* Remove the old multires */
- multires_free(me->mr);
- me->mr = NULL;
+ MultiresLevel *lvl;
+ ModifierData *md;
+ MultiresModifierData *mmd;
+ DerivedMesh *dm, *orig;
+ CustomDataLayer *l;
+ int i;
+
+ /* Load original level into the mesh */
+ lvl = me->mr->levels.first;
+ CustomData_free_layers(&me->vdata, CD_MVERT, lvl->totvert);
+ CustomData_free_layers(&me->edata, CD_MEDGE, lvl->totedge);
+ CustomData_free_layers(&me->fdata, CD_MFACE, lvl->totface);
+ me->totvert = lvl->totvert;
+ me->totedge = lvl->totedge;
+ me->totface = lvl->totface;
+ me->mvert = CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, me->totvert);
+ me->medge = CustomData_add_layer(&me->edata, CD_MEDGE, CD_CALLOC, NULL, me->totedge);
+ me->mface = CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, NULL, me->totface);
+ memcpy(me->mvert, me->mr->verts, sizeof(MVert) * me->totvert);
+ for (i = 0; i < me->totedge; ++i) {
+ me->medge[i].v1 = lvl->edges[i].v[0];
+ me->medge[i].v2 = lvl->edges[i].v[1];
+ }
+ for (i = 0; i < me->totface; ++i) {
+ me->mface[i].v1 = lvl->faces[i].v[0];
+ me->mface[i].v2 = lvl->faces[i].v[1];
+ me->mface[i].v3 = lvl->faces[i].v[2];
+ me->mface[i].v4 = lvl->faces[i].v[3];
+ me->mface[i].mat_nr = lvl->faces[i].mat_nr;
+ }
+
+ /* Copy the first-level data to the mesh */
+ /* XXX We must do this before converting tessfaces to polys/lopps! */
+ for (i = 0, l = me->mr->vdata.layers; i < me->mr->vdata.totlayer; ++i, ++l)
+ CustomData_add_layer(&me->vdata, l->type, CD_REFERENCE, l->data, me->totvert);
+ for (i = 0, l = me->mr->fdata.layers; i < me->mr->fdata.totlayer; ++i, ++l)
+ CustomData_add_layer(&me->fdata, l->type, CD_REFERENCE, l->data, me->totface);
+ CustomData_reset(&me->mr->vdata);
+ CustomData_reset(&me->mr->fdata);
+
+ multires_load_old_vcols(me);
+ multires_load_old_face_flags(me);
+
+ /* multiresModifier_subdivide (actually, multires_subdivide) expects polys, not tessfaces! */
+ BKE_mesh_convert_mfaces_to_mpolys(me);
+
+ /* Add a multires modifier to the object */
+ md = ob->modifiers.first;
+ while (md && modifierType_getInfo(md->type)->type == eModifierTypeType_OnlyDeform)
+ md = md->next;
+ mmd = (MultiresModifierData *)modifier_new(eModifierType_Multires);
+ BLI_insertlinkbefore(&ob->modifiers, md, mmd);
+
+ for (i = 0; i < me->mr->level_count - 1; ++i)
+ multiresModifier_subdivide(mmd, NULL, ob, 1, 0);
+
+ mmd->lvl = mmd->totlvl;
+ orig = CDDM_from_mesh(me);
+ /* XXX We *must* alloc paint mask here, else we have some kind of mismatch in
+ * multires_modifier_update_mdisps() (called by dm->release(dm)), which always creates the
+ * reference subsurfed dm with this option, before calling multiresModifier_disp_run(),
+ * which implicitly expects both subsurfs from its first dm and oldGridData parameters to
+ * be of the same "format"! */
+ dm = multires_make_derived_from_derived(orig, mmd, NULL, ob, 0);
+
+ multires_load_old_dm(dm, me, mmd->totlvl + 1);
+
+ multires_dm_mark_as_modified(dm, MULTIRES_COORDS_MODIFIED);
+ dm->release(dm);
+ orig->release(orig);
+
+ /* Remove the old multires */
+ multires_free(me->mr);
+ me->mr = NULL;
}
/* If 'ob_src' and 'ob_dst' both have multires modifiers, synchronize them
* such that 'ob_dst' has the same total number of levels as 'ob_src'. */
-void multiresModifier_sync_levels_ex(Scene *scene, Object *ob_dst, MultiresModifierData *mmd_src, MultiresModifierData *mmd_dst)
+void multiresModifier_sync_levels_ex(Scene *scene,
+ Object *ob_dst,
+ MultiresModifierData *mmd_src,
+ MultiresModifierData *mmd_dst)
{
- if (mmd_src->totlvl == mmd_dst->totlvl) {
- return;
- }
+ if (mmd_src->totlvl == mmd_dst->totlvl) {
+ return;
+ }
- if (mmd_src->totlvl > mmd_dst->totlvl) {
- multires_subdivide(mmd_dst, scene, ob_dst, mmd_src->totlvl, false, mmd_dst->simple);
- }
- else {
- multires_del_higher(mmd_dst, ob_dst, mmd_src->totlvl);
- }
+ if (mmd_src->totlvl > mmd_dst->totlvl) {
+ multires_subdivide(mmd_dst, scene, ob_dst, mmd_src->totlvl, false, mmd_dst->simple);
+ }
+ else {
+ multires_del_higher(mmd_dst, ob_dst, mmd_src->totlvl);
+ }
}
static void multires_sync_levels(Scene *scene, Object *ob_src, Object *ob_dst)
{
- MultiresModifierData *mmd_src = get_multires_modifier(scene, ob_src, true);
- MultiresModifierData *mmd_dst = get_multires_modifier(scene, ob_dst, true);
+ MultiresModifierData *mmd_src = get_multires_modifier(scene, ob_src, true);
+ MultiresModifierData *mmd_dst = get_multires_modifier(scene, ob_dst, true);
- if (!mmd_src) {
- /* object could have MDISP even when there is no multires modifier
- * this could lead to troubles due to i've got no idea how mdisp could be
- * upsampled correct without modifier data.
- * just remove mdisps if no multires present (nazgul) */
+ if (!mmd_src) {
+ /* object could have MDISP even when there is no multires modifier
+ * this could lead to troubles due to i've got no idea how mdisp could be
+ * upsampled correct without modifier data.
+ * just remove mdisps if no multires present (nazgul) */
- multires_customdata_delete(ob_src->data);
- }
+ multires_customdata_delete(ob_src->data);
+ }
- if (mmd_src && mmd_dst) {
- multiresModifier_sync_levels_ex(scene, ob_dst, mmd_src, mmd_dst);
- }
+ if (mmd_src && mmd_dst) {
+ multiresModifier_sync_levels_ex(scene, ob_dst, mmd_src, mmd_dst);
+ }
}
static void multires_apply_uniform_scale(Object *object, const float scale)
{
- Mesh *mesh = (Mesh *)object->data;
- MDisps *mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS);
- for (int i = 0; i < mesh->totloop; ++i) {
- MDisps *grid = &mdisps[i];
- for (int j = 0; j < grid->totdisp; ++j) {
- mul_v3_fl(grid->disps[j], scale);
- }
- }
-}
-
-static void multires_apply_smat(
- struct Depsgraph *UNUSED(depsgraph),
- Scene *scene,
- Object *object,
- float smat[3][3])
-{
- const MultiresModifierData *mmd = get_multires_modifier(scene, object, true);
- if (mmd == NULL || mmd->totlvl == 0) {
- return;
- }
- /* Make sure layer present. */
- Mesh *mesh = (Mesh *)object->data;
- CustomData_external_read(
- &mesh->ldata, &mesh->id, CD_MASK_MDISPS, mesh->totloop);
- if (!CustomData_get_layer(&mesh->ldata, CD_MDISPS)) {
- return;
- }
- if (is_uniform_scaled_m3(smat)) {
- const float scale = mat3_to_scale(smat);
- multires_apply_uniform_scale(object, scale);
- }
- else {
- /* TODO(sergey): This branch of code actually requires more work to
- * preserve all the details.
- */
- const float scale = mat3_to_scale(smat);
- multires_apply_uniform_scale(object, scale);
- }
+ Mesh *mesh = (Mesh *)object->data;
+ MDisps *mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS);
+ for (int i = 0; i < mesh->totloop; ++i) {
+ MDisps *grid = &mdisps[i];
+ for (int j = 0; j < grid->totdisp; ++j) {
+ mul_v3_fl(grid->disps[j], scale);
+ }
+ }
+}
+
+static void multires_apply_smat(struct Depsgraph *UNUSED(depsgraph),
+ Scene *scene,
+ Object *object,
+ float smat[3][3])
+{
+ const MultiresModifierData *mmd = get_multires_modifier(scene, object, true);
+ if (mmd == NULL || mmd->totlvl == 0) {
+ return;
+ }
+ /* Make sure layer present. */
+ Mesh *mesh = (Mesh *)object->data;
+ CustomData_external_read(&mesh->ldata, &mesh->id, CD_MASK_MDISPS, mesh->totloop);
+ if (!CustomData_get_layer(&mesh->ldata, CD_MDISPS)) {
+ return;
+ }
+ if (is_uniform_scaled_m3(smat)) {
+ const float scale = mat3_to_scale(smat);
+ multires_apply_uniform_scale(object, scale);
+ }
+ else {
+ /* TODO(sergey): This branch of code actually requires more work to
+ * preserve all the details.
+ */
+ const float scale = mat3_to_scale(smat);
+ multires_apply_uniform_scale(object, scale);
+ }
}
int multires_mdisp_corners(MDisps *s)
{
- int lvl = 13;
+ int lvl = 13;
- while (lvl > 0) {
- int side = (1 << (lvl - 1)) + 1;
- if ((s->totdisp % (side * side)) == 0) return s->totdisp / (side * side);
- lvl--;
- }
+ while (lvl > 0) {
+ int side = (1 << (lvl - 1)) + 1;
+ if ((s->totdisp % (side * side)) == 0)
+ return s->totdisp / (side * side);
+ lvl--;
+ }
- return 0;
+ return 0;
}
void multiresModifier_scale_disp(struct Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- float smat[3][3];
+ float smat[3][3];
- /* object's scale matrix */
- BKE_object_scale_to_mat3(ob, smat);
+ /* object's scale matrix */
+ BKE_object_scale_to_mat3(ob, smat);
- multires_apply_smat(depsgraph, scene, ob, smat);
+ multires_apply_smat(depsgraph, scene, ob, smat);
}
-void multiresModifier_prepare_join(struct Depsgraph *depsgraph, Scene *scene, Object *ob, Object *to_ob)
+void multiresModifier_prepare_join(struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ Object *to_ob)
{
- float smat[3][3], tmat[3][3], mat[3][3];
- multires_sync_levels(scene, to_ob, ob);
+ float smat[3][3], tmat[3][3], mat[3][3];
+ multires_sync_levels(scene, to_ob, ob);
- /* construct scale matrix for displacement */
- BKE_object_scale_to_mat3(to_ob, tmat);
- invert_m3(tmat);
- BKE_object_scale_to_mat3(ob, smat);
- mul_m3_m3m3(mat, smat, tmat);
+ /* construct scale matrix for displacement */
+ BKE_object_scale_to_mat3(to_ob, tmat);
+ invert_m3(tmat);
+ BKE_object_scale_to_mat3(ob, smat);
+ mul_m3_m3m3(mat, smat, tmat);
- multires_apply_smat(depsgraph, scene, ob, mat);
+ multires_apply_smat(depsgraph, scene, ob, mat);
}
/* update multires data after topology changing */
void multires_topology_changed(Mesh *me)
{
- MDisps *mdisp = NULL, *cur = NULL;
- int i, grid = 0;
+ MDisps *mdisp = NULL, *cur = NULL;
+ int i, grid = 0;
- CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop);
- mdisp = CustomData_get_layer(&me->ldata, CD_MDISPS);
+ CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop);
+ mdisp = CustomData_get_layer(&me->ldata, CD_MDISPS);
- if (!mdisp)
- return;
+ if (!mdisp)
+ return;
- cur = mdisp;
- for (i = 0; i < me->totloop; i++, cur++) {
- if (cur->totdisp) {
- grid = mdisp->totdisp;
+ cur = mdisp;
+ for (i = 0; i < me->totloop; i++, cur++) {
+ if (cur->totdisp) {
+ grid = mdisp->totdisp;
- break;
- }
- }
+ break;
+ }
+ }
- for (i = 0; i < me->totloop; i++, mdisp++) {
- /* allocate memory for mdisp, the whole disp layer would be erased otherwise */
- if (!mdisp->totdisp || !mdisp->disps) {
- if (grid) {
- mdisp->totdisp = grid;
- mdisp->disps = MEM_calloc_arrayN(3 * sizeof(float), mdisp->totdisp, "mdisp topology");
- }
+ for (i = 0; i < me->totloop; i++, mdisp++) {
+ /* allocate memory for mdisp, the whole disp layer would be erased otherwise */
+ if (!mdisp->totdisp || !mdisp->disps) {
+ if (grid) {
+ mdisp->totdisp = grid;
+ mdisp->disps = MEM_calloc_arrayN(3 * sizeof(float), mdisp->totdisp, "mdisp topology");
+ }
- continue;
- }
- }
+ continue;
+ }
+ }
}
/***************** Multires interpolation stuff *****************/
/* Find per-corner coordinate with given per-face UV coord */
-int mdisp_rot_face_to_crn(struct MVert *UNUSED(mvert), struct MPoly *mpoly, struct MLoop *UNUSED(mloop), const struct MLoopTri *UNUSED(lt), const int face_side, const float u, const float v, float *x, float *y)
-{
- const float offset = face_side * 0.5f - 0.5f;
- int S = 0;
-
- if (mpoly->totloop == 4) {
- if (u <= offset && v <= offset) S = 0;
- else if (u > offset && v <= offset) S = 1;
- else if (u > offset && v > offset) S = 2;
- else if (u <= offset && v >= offset) S = 3;
-
- if (S == 0) {
- *y = offset - u;
- *x = offset - v;
- }
- else if (S == 1) {
- *x = u - offset;
- *y = offset - v;
- }
- else if (S == 2) {
- *y = u - offset;
- *x = v - offset;
- }
- else if (S == 3) {
- *x = offset - u;
- *y = v - offset;
- }
- }
- else if (mpoly->totloop == 3) {
- int grid_size = offset;
- float w = (face_side - 1) - u - v;
- float W1, W2;
-
- if (u >= v && u >= w) {S = 0; W1 = w; W2 = v; }
- else if (v >= u && v >= w) {S = 1; W1 = u; W2 = w; }
- else {S = 2; W1 = v; W2 = u; }
-
- W1 /= (face_side - 1);
- W2 /= (face_side - 1);
-
- *x = (1 - (2 * W1) / (1 - W2)) * grid_size;
- *y = (1 - (2 * W2) / (1 - W1)) * grid_size;
- }
- else {
- /* the complicated ngon case: find the actual coordinate from
- * the barycentric coordinates and finally find the closest vertex
- * should work reliably for convex cases only but better than nothing */
+int mdisp_rot_face_to_crn(struct MVert *UNUSED(mvert),
+ struct MPoly *mpoly,
+ struct MLoop *UNUSED(mloop),
+ const struct MLoopTri *UNUSED(lt),
+ const int face_side,
+ const float u,
+ const float v,
+ float *x,
+ float *y)
+{
+ const float offset = face_side * 0.5f - 0.5f;
+ int S = 0;
+
+ if (mpoly->totloop == 4) {
+ if (u <= offset && v <= offset)
+ S = 0;
+ else if (u > offset && v <= offset)
+ S = 1;
+ else if (u > offset && v > offset)
+ S = 2;
+ else if (u <= offset && v >= offset)
+ S = 3;
+
+ if (S == 0) {
+ *y = offset - u;
+ *x = offset - v;
+ }
+ else if (S == 1) {
+ *x = u - offset;
+ *y = offset - v;
+ }
+ else if (S == 2) {
+ *y = u - offset;
+ *x = v - offset;
+ }
+ else if (S == 3) {
+ *x = offset - u;
+ *y = v - offset;
+ }
+ }
+ else if (mpoly->totloop == 3) {
+ int grid_size = offset;
+ float w = (face_side - 1) - u - v;
+ float W1, W2;
+
+ if (u >= v && u >= w) {
+ S = 0;
+ W1 = w;
+ W2 = v;
+ }
+ else if (v >= u && v >= w) {
+ S = 1;
+ W1 = u;
+ W2 = w;
+ }
+ else {
+ S = 2;
+ W1 = v;
+ W2 = u;
+ }
+
+ W1 /= (face_side - 1);
+ W2 /= (face_side - 1);
+
+ *x = (1 - (2 * W1) / (1 - W2)) * grid_size;
+ *y = (1 - (2 * W2) / (1 - W1)) * grid_size;
+ }
+ else {
+ /* the complicated ngon case: find the actual coordinate from
+ * the barycentric coordinates and finally find the closest vertex
+ * should work reliably for convex cases only but better than nothing */
#if 0
- int minS, i;
- float mindist = FLT_MAX;
-
- for (i = 0; i < mpoly->totloop; i++) {
- float len = len_v3v3(NULL, mvert[mloop[mpoly->loopstart + i].v].co);
- if (len < mindist) {
- mindist = len;
- minS = i;
- }
- }
- S = minS;
+ int minS, i;
+ float mindist = FLT_MAX;
+
+ for (i = 0; i < mpoly->totloop; i++) {
+ float len = len_v3v3(NULL, mvert[mloop[mpoly->loopstart + i].v].co);
+ if (len < mindist) {
+ mindist = len;
+ minS = i;
+ }
+ }
+ S = minS;
#endif
- /* temp not implemented yet and also not working properly in current master.
- * (was worked around by subdividing once) */
- S = 0;
- *x = 0;
- *y = 0;
- }
-
- return S;
+ /* temp not implemented yet and also not working properly in current master.
+ * (was worked around by subdividing once) */
+ S = 0;
+ *x = 0;
+ *y = 0;
+ }
+
+ return S;
}
diff --git a/source/blender/blenkernel/intern/multires_inline.h b/source/blender/blenkernel/intern/multires_inline.h
index a8d43cc71d5..3d00101ec29 100644
--- a/source/blender/blenkernel/intern/multires_inline.h
+++ b/source/blender/blenkernel/intern/multires_inline.h
@@ -27,36 +27,35 @@
#include "BKE_multires.h"
#include "BLI_math_vector.h"
-BLI_INLINE void BKE_multires_construct_tangent_matrix(
- float tangent_matrix[3][3],
- const float dPdu[3],
- const float dPdv[3],
- const int corner)
+BLI_INLINE void BKE_multires_construct_tangent_matrix(float tangent_matrix[3][3],
+ const float dPdu[3],
+ const float dPdv[3],
+ const int corner)
{
- if (corner == 0) {
- copy_v3_v3(tangent_matrix[0], dPdv);
- copy_v3_v3(tangent_matrix[1], dPdu);
- mul_v3_fl(tangent_matrix[0], -1.0f);
- mul_v3_fl(tangent_matrix[1], -1.0f);
- }
- else if (corner == 1) {
- copy_v3_v3(tangent_matrix[0], dPdu);
- copy_v3_v3(tangent_matrix[1], dPdv);
- mul_v3_fl(tangent_matrix[1], -1.0f);
- }
- else if (corner == 2) {
- copy_v3_v3(tangent_matrix[0], dPdv);
- copy_v3_v3(tangent_matrix[1], dPdu);
- }
- else if (corner == 3) {
- copy_v3_v3(tangent_matrix[0], dPdu);
- copy_v3_v3(tangent_matrix[1], dPdv);
- mul_v3_fl(tangent_matrix[0], -1.0f);
- }
- cross_v3_v3v3(tangent_matrix[2], dPdu, dPdv);
- normalize_v3(tangent_matrix[0]);
- normalize_v3(tangent_matrix[1]);
- normalize_v3(tangent_matrix[2]);
+ if (corner == 0) {
+ copy_v3_v3(tangent_matrix[0], dPdv);
+ copy_v3_v3(tangent_matrix[1], dPdu);
+ mul_v3_fl(tangent_matrix[0], -1.0f);
+ mul_v3_fl(tangent_matrix[1], -1.0f);
+ }
+ else if (corner == 1) {
+ copy_v3_v3(tangent_matrix[0], dPdu);
+ copy_v3_v3(tangent_matrix[1], dPdv);
+ mul_v3_fl(tangent_matrix[1], -1.0f);
+ }
+ else if (corner == 2) {
+ copy_v3_v3(tangent_matrix[0], dPdv);
+ copy_v3_v3(tangent_matrix[1], dPdu);
+ }
+ else if (corner == 3) {
+ copy_v3_v3(tangent_matrix[0], dPdu);
+ copy_v3_v3(tangent_matrix[1], dPdv);
+ mul_v3_fl(tangent_matrix[0], -1.0f);
+ }
+ cross_v3_v3v3(tangent_matrix[2], dPdu, dPdv);
+ normalize_v3(tangent_matrix[0]);
+ normalize_v3(tangent_matrix[1]);
+ normalize_v3(tangent_matrix[2]);
}
-#endif /* __MULTIRES_INLINE_H__ */
+#endif /* __MULTIRES_INLINE_H__ */
diff --git a/source/blender/blenkernel/intern/multires_reshape.c b/source/blender/blenkernel/intern/multires_reshape.c
index 019757cc75a..2af55b1b0bc 100644
--- a/source/blender/blenkernel/intern/multires_reshape.c
+++ b/source/blender/blenkernel/intern/multires_reshape.c
@@ -45,19 +45,17 @@
#include "DEG_depsgraph_query.h"
-static void multires_reshape_init_mmd(
- MultiresModifierData *reshape_mmd,
- const MultiresModifierData *mmd)
+static void multires_reshape_init_mmd(MultiresModifierData *reshape_mmd,
+ const MultiresModifierData *mmd)
{
- *reshape_mmd = *mmd;
+ *reshape_mmd = *mmd;
}
-static void multires_reshape_init_mmd_top_level(
- MultiresModifierData *reshape_mmd,
- const MultiresModifierData *mmd)
+static void multires_reshape_init_mmd_top_level(MultiresModifierData *reshape_mmd,
+ const MultiresModifierData *mmd)
{
- *reshape_mmd = *mmd;
- reshape_mmd->lvl = reshape_mmd->totlvl;
+ *reshape_mmd = *mmd;
+ reshape_mmd->lvl = reshape_mmd->totlvl;
}
/* =============================================================================
@@ -65,187 +63,173 @@ static void multires_reshape_init_mmd_top_level(
*/
typedef struct MultiresReshapeContext {
- Subdiv *subdiv;
- const Mesh *coarse_mesh;
- MDisps *mdisps;
- GridPaintMask *grid_paint_mask;
- int top_grid_size;
- int top_level;
- /* Indexed by coarse face index, returns first ptex face index corresponding
- * to that coarse face. */
- int *face_ptex_offset;
+ Subdiv *subdiv;
+ const Mesh *coarse_mesh;
+ MDisps *mdisps;
+ GridPaintMask *grid_paint_mask;
+ int top_grid_size;
+ int top_level;
+ /* Indexed by coarse face index, returns first ptex face index corresponding
+ * to that coarse face. */
+ int *face_ptex_offset;
} MultiresReshapeContext;
-static void multires_reshape_allocate_displacement_grid(
- MDisps *displacement_grid, const int level)
+static void multires_reshape_allocate_displacement_grid(MDisps *displacement_grid, const int level)
{
- const int grid_size = BKE_subdiv_grid_size_from_level(level);
- const int grid_area = grid_size * grid_size;
- float (*disps)[3] = MEM_calloc_arrayN(
- grid_area, 3 * sizeof(float), "multires disps");
- if (displacement_grid->disps != NULL) {
- MEM_freeN(displacement_grid->disps);
- }
- displacement_grid->disps = disps;
- displacement_grid->totdisp = grid_area;
- displacement_grid->level = level;
+ const int grid_size = BKE_subdiv_grid_size_from_level(level);
+ const int grid_area = grid_size * grid_size;
+ float(*disps)[3] = MEM_calloc_arrayN(grid_area, 3 * sizeof(float), "multires disps");
+ if (displacement_grid->disps != NULL) {
+ MEM_freeN(displacement_grid->disps);
+ }
+ displacement_grid->disps = disps;
+ displacement_grid->totdisp = grid_area;
+ displacement_grid->level = level;
}
-static void multires_reshape_ensure_displacement_grid(
- MDisps *displacement_grid, const int level)
+static void multires_reshape_ensure_displacement_grid(MDisps *displacement_grid, const int level)
{
- if (displacement_grid->disps != NULL && displacement_grid->level == level) {
- return;
- }
- multires_reshape_allocate_displacement_grid(
- displacement_grid, level);
+ if (displacement_grid->disps != NULL && displacement_grid->level == level) {
+ return;
+ }
+ multires_reshape_allocate_displacement_grid(displacement_grid, level);
}
-static void multires_reshape_ensure_displacement_grids(
- Mesh *mesh,
- const int grid_level)
+static void multires_reshape_ensure_displacement_grids(Mesh *mesh, const int grid_level)
{
- const int num_grids = mesh->totloop;
- MDisps *mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS);
- for (int grid_index = 0; grid_index < num_grids; grid_index++) {
- multires_reshape_ensure_displacement_grid(
- &mdisps[grid_index], grid_level);
- }
+ const int num_grids = mesh->totloop;
+ MDisps *mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS);
+ for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+ multires_reshape_ensure_displacement_grid(&mdisps[grid_index], grid_level);
+ }
}
static void multires_reshape_ensure_mask_grids(Mesh *mesh, const int grid_level)
{
- GridPaintMask *grid_paint_masks =
- CustomData_get_layer(&mesh->ldata, CD_GRID_PAINT_MASK);
- if (grid_paint_masks == NULL) {
- return;
- }
- const int num_grids = mesh->totloop;
- const int grid_size = BKE_subdiv_grid_size_from_level(grid_level);
- const int grid_area = grid_size * grid_size;
- for (int grid_index = 0; grid_index < num_grids; grid_index++) {
- GridPaintMask *grid_paint_mask = &grid_paint_masks[grid_index];
- if (grid_paint_mask->level == grid_level) {
- continue;
- }
- grid_paint_mask->level = grid_level;
- if (grid_paint_mask->data) {
- MEM_freeN(grid_paint_mask->data);
- }
- grid_paint_mask->data = MEM_calloc_arrayN(
- grid_area, sizeof(float), "gpm.data");
- }
+ GridPaintMask *grid_paint_masks = CustomData_get_layer(&mesh->ldata, CD_GRID_PAINT_MASK);
+ if (grid_paint_masks == NULL) {
+ return;
+ }
+ const int num_grids = mesh->totloop;
+ const int grid_size = BKE_subdiv_grid_size_from_level(grid_level);
+ const int grid_area = grid_size * grid_size;
+ for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+ GridPaintMask *grid_paint_mask = &grid_paint_masks[grid_index];
+ if (grid_paint_mask->level == grid_level) {
+ continue;
+ }
+ grid_paint_mask->level = grid_level;
+ if (grid_paint_mask->data) {
+ MEM_freeN(grid_paint_mask->data);
+ }
+ grid_paint_mask->data = MEM_calloc_arrayN(grid_area, sizeof(float), "gpm.data");
+ }
}
static void multires_reshape_ensure_grids(Mesh *mesh, const int grid_level)
{
- multires_reshape_ensure_displacement_grids(mesh, grid_level);
- multires_reshape_ensure_mask_grids(mesh, grid_level);
+ multires_reshape_ensure_displacement_grids(mesh, grid_level);
+ multires_reshape_ensure_mask_grids(mesh, grid_level);
}
/* Convert normalized coordinate within a grid to a normalized coordinate within
* a ptex face. */
-static void multires_reshape_corner_coord_to_ptex(
- const MPoly *coarse_poly,
- const int corner, const float corner_u, const float corner_v,
- float *r_ptex_face_u, float *r_ptex_face_v)
+static void multires_reshape_corner_coord_to_ptex(const MPoly *coarse_poly,
+ const int corner,
+ const float corner_u,
+ const float corner_v,
+ float *r_ptex_face_u,
+ float *r_ptex_face_v)
{
- if (coarse_poly->totloop == 4) {
- float grid_u, grid_v;
- BKE_subdiv_ptex_face_uv_to_grid_uv(
- corner_u, corner_v, &grid_u, &grid_v);
- BKE_subdiv_rotate_grid_to_quad(corner, grid_u, grid_v,
- r_ptex_face_u, r_ptex_face_v);
- }
- else {
- *r_ptex_face_u = corner_u;
- *r_ptex_face_v = corner_v;
- }
+ if (coarse_poly->totloop == 4) {
+ float grid_u, grid_v;
+ BKE_subdiv_ptex_face_uv_to_grid_uv(corner_u, corner_v, &grid_u, &grid_v);
+ BKE_subdiv_rotate_grid_to_quad(corner, grid_u, grid_v, r_ptex_face_u, r_ptex_face_v);
+ }
+ else {
+ *r_ptex_face_u = corner_u;
+ *r_ptex_face_v = corner_v;
+ }
}
/* NOTE: The tangent vectors are measured in ptex face normalized coordinates,
* which is different from grid tangent. */
-static void multires_reshape_sample_surface(
- Subdiv *subdiv,
- const MPoly *coarse_poly,
- const int corner, const float corner_u, const float corner_v,
- const int ptex_face_index,
- float r_P[3], float r_dPdu[3], float r_dPdv[3])
+static void multires_reshape_sample_surface(Subdiv *subdiv,
+ const MPoly *coarse_poly,
+ const int corner,
+ const float corner_u,
+ const float corner_v,
+ const int ptex_face_index,
+ float r_P[3],
+ float r_dPdu[3],
+ float r_dPdv[3])
{
- float ptex_face_u, ptex_face_v;
- multires_reshape_corner_coord_to_ptex(
- coarse_poly, corner, corner_u, corner_v,
- &ptex_face_u, &ptex_face_v);
- BKE_subdiv_eval_limit_point_and_derivatives(
- subdiv,
- ptex_face_index, ptex_face_u, ptex_face_v,
- r_P, r_dPdu, r_dPdv);
+ float ptex_face_u, ptex_face_v;
+ multires_reshape_corner_coord_to_ptex(
+ coarse_poly, corner, corner_u, corner_v, &ptex_face_u, &ptex_face_v);
+ BKE_subdiv_eval_limit_point_and_derivatives(
+ subdiv, ptex_face_index, ptex_face_u, ptex_face_v, r_P, r_dPdu, r_dPdv);
}
-static void multires_reshape_tangent_matrix_for_corner(
- const MPoly *coarse_poly,
- const int coarse_corner,
- const float dPdu[3], const float dPdv[3],
- float r_tangent_matrix[3][3])
+static void multires_reshape_tangent_matrix_for_corner(const MPoly *coarse_poly,
+ const int coarse_corner,
+ const float dPdu[3],
+ const float dPdv[3],
+ float r_tangent_matrix[3][3])
{
- /* For a quad faces we would need to flip the tangent, since they will use
- * use different coordinates within displacement grid comparent to ptex
- * face. */
- const bool is_quad = (coarse_poly->totloop == 4);
- const int tangent_corner = is_quad ? coarse_corner : 0;
- BKE_multires_construct_tangent_matrix(
- r_tangent_matrix, dPdu, dPdv, tangent_corner);
+ /* For a quad faces we would need to flip the tangent, since they will use
+ * use different coordinates within displacement grid comparent to ptex
+ * face. */
+ const bool is_quad = (coarse_poly->totloop == 4);
+ const int tangent_corner = is_quad ? coarse_corner : 0;
+ BKE_multires_construct_tangent_matrix(r_tangent_matrix, dPdu, dPdv, tangent_corner);
}
-static void multires_reshape_vertex_from_final_data(
- MultiresReshapeContext *ctx,
- const int ptex_face_index,
- const float corner_u, const float corner_v,
- const int coarse_poly_index,
- const int coarse_corner,
- const float final_P[3], const float final_mask)
+static void multires_reshape_vertex_from_final_data(MultiresReshapeContext *ctx,
+ const int ptex_face_index,
+ const float corner_u,
+ const float corner_v,
+ const int coarse_poly_index,
+ const int coarse_corner,
+ const float final_P[3],
+ const float final_mask)
{
- Subdiv *subdiv = ctx->subdiv;
- const int grid_size = ctx->top_grid_size;
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MPoly *coarse_mpoly = coarse_mesh->mpoly;
- const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index];
- const int loop_index = coarse_poly->loopstart + coarse_corner;
- /* Evaluate limit surface. */
- float P[3], dPdu[3], dPdv[3];
- multires_reshape_sample_surface(
- subdiv,
- coarse_poly,
- coarse_corner, corner_u, corner_v,
- ptex_face_index,
- P, dPdu, dPdv);
- /* Construct tangent matrix which matches orientation of the current
- * displacement grid. */
- float tangent_matrix[3][3], inv_tangent_matrix[3][3];
- multires_reshape_tangent_matrix_for_corner(coarse_poly, coarse_corner,
- dPdu, dPdv,
- tangent_matrix);
- invert_m3_m3(inv_tangent_matrix, tangent_matrix);
- /* Convert object coordinate to a tangent space of displacement grid. */
- float D[3];
- sub_v3_v3v3(D, final_P, P);
- float tangent_D[3];
- mul_v3_m3v3(tangent_D, inv_tangent_matrix, D);
- /* Calculate index of element within the grid. */
- float grid_u, grid_v;
- BKE_subdiv_ptex_face_uv_to_grid_uv(corner_u, corner_v, &grid_u, &grid_v);
- const int grid_x = (grid_u * (grid_size - 1) + 0.5f);
- const int grid_y = (grid_v * (grid_size - 1) + 0.5f);
- const int index = grid_y * grid_size + grid_x;
- /* Write tangent displacement. */
- MDisps *displacement_grid = &ctx->mdisps[loop_index];
- copy_v3_v3(displacement_grid->disps[index], tangent_D);
- /* Write mask grid. */
- if (ctx->grid_paint_mask != NULL) {
- GridPaintMask *grid_paint_mask = &ctx->grid_paint_mask[loop_index];
- BLI_assert(grid_paint_mask->level == displacement_grid->level);
- grid_paint_mask->data[index] = final_mask;
- }
+ Subdiv *subdiv = ctx->subdiv;
+ const int grid_size = ctx->top_grid_size;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index];
+ const int loop_index = coarse_poly->loopstart + coarse_corner;
+ /* Evaluate limit surface. */
+ float P[3], dPdu[3], dPdv[3];
+ multires_reshape_sample_surface(
+ subdiv, coarse_poly, coarse_corner, corner_u, corner_v, ptex_face_index, P, dPdu, dPdv);
+ /* Construct tangent matrix which matches orientation of the current
+ * displacement grid. */
+ float tangent_matrix[3][3], inv_tangent_matrix[3][3];
+ multires_reshape_tangent_matrix_for_corner(
+ coarse_poly, coarse_corner, dPdu, dPdv, tangent_matrix);
+ invert_m3_m3(inv_tangent_matrix, tangent_matrix);
+ /* Convert object coordinate to a tangent space of displacement grid. */
+ float D[3];
+ sub_v3_v3v3(D, final_P, P);
+ float tangent_D[3];
+ mul_v3_m3v3(tangent_D, inv_tangent_matrix, D);
+ /* Calculate index of element within the grid. */
+ float grid_u, grid_v;
+ BKE_subdiv_ptex_face_uv_to_grid_uv(corner_u, corner_v, &grid_u, &grid_v);
+ const int grid_x = (grid_u * (grid_size - 1) + 0.5f);
+ const int grid_y = (grid_v * (grid_size - 1) + 0.5f);
+ const int index = grid_y * grid_size + grid_x;
+ /* Write tangent displacement. */
+ MDisps *displacement_grid = &ctx->mdisps[loop_index];
+ copy_v3_v3(displacement_grid->disps[index], tangent_D);
+ /* Write mask grid. */
+ if (ctx->grid_paint_mask != NULL) {
+ GridPaintMask *grid_paint_mask = &ctx->grid_paint_mask[loop_index];
+ BLI_assert(grid_paint_mask->level == displacement_grid->level);
+ grid_paint_mask->data[index] = final_mask;
+ }
}
/* =============================================================================
@@ -253,211 +237,192 @@ static void multires_reshape_vertex_from_final_data(
*/
typedef struct MultiresPropagateData {
- /* Number of displacement grids. */
- int num_grids;
- /* Resolution level up to which displacement is known. */
- int reshape_level;
- /* Resolution up to which propagation is happening, affecting all the
- * levels in [reshape_level + 1, top_level]. */
- int top_level;
- /* Grid sizes at the corresponding levels. */
- int reshape_grid_size;
- int top_grid_size;
- /* Keys to access CCG at different levels. */
- CCGKey reshape_level_key;
- CCGKey top_level_key;
- /* Original grid data, before any updates for reshape.
- * Contains data at the reshape_level resolution level. */
- CCGElem **orig_grids_data;
- /* Custom data layers from a coarse mesh. */
- MDisps *mdisps;
- GridPaintMask *grid_paint_mask;
+ /* Number of displacement grids. */
+ int num_grids;
+ /* Resolution level up to which displacement is known. */
+ int reshape_level;
+ /* Resolution up to which propagation is happening, affecting all the
+ * levels in [reshape_level + 1, top_level]. */
+ int top_level;
+ /* Grid sizes at the corresponding levels. */
+ int reshape_grid_size;
+ int top_grid_size;
+ /* Keys to access CCG at different levels. */
+ CCGKey reshape_level_key;
+ CCGKey top_level_key;
+ /* Original grid data, before any updates for reshape.
+ * Contains data at the reshape_level resolution level. */
+ CCGElem **orig_grids_data;
+ /* Custom data layers from a coarse mesh. */
+ MDisps *mdisps;
+ GridPaintMask *grid_paint_mask;
} MultiresPropagateData;
static CCGElem **allocate_grids(CCGKey *key, int num_grids)
{
- CCGElem **grids = MEM_calloc_arrayN(
- num_grids, sizeof(CCGElem *), "reshape grids*");
- for (int grid_index = 0; grid_index < num_grids; grid_index++) {
- grids[grid_index] = MEM_calloc_arrayN(
- key->elem_size,
- key->grid_area,
- "reshape orig_grids_data elems");
- }
- return grids;
+ CCGElem **grids = MEM_calloc_arrayN(num_grids, sizeof(CCGElem *), "reshape grids*");
+ for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+ grids[grid_index] = MEM_calloc_arrayN(
+ key->elem_size, key->grid_area, "reshape orig_grids_data elems");
+ }
+ return grids;
}
static void free_grids(CCGElem **grids, int num_grids)
{
- if (grids == NULL) {
- return;
- }
- for (int grid_index = 0; grid_index < num_grids; grid_index++) {
- MEM_freeN(grids[grid_index]);
- }
- MEM_freeN(grids);
+ if (grids == NULL) {
+ return;
+ }
+ for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+ MEM_freeN(grids[grid_index]);
+ }
+ MEM_freeN(grids);
}
/* Initialize element sizes and offsets. */
-static void multires_reshape_init_key_layers(
- CCGKey *key,
- const MultiresPropagateData *data)
+static void multires_reshape_init_key_layers(CCGKey *key, const MultiresPropagateData *data)
{
- key->elem_size = 3 * sizeof(float);
- if (data->grid_paint_mask != NULL) {
- key->mask_offset = 3 * sizeof(float);
- key->elem_size += sizeof(float);
- key->has_mask = true;
- }
- else {
- key->mask_offset = -1;
- key->has_mask = false;
- }
- /* We never have normals in original grids. */
- key->normal_offset = -1;
- key->has_normals = false;
+ key->elem_size = 3 * sizeof(float);
+ if (data->grid_paint_mask != NULL) {
+ key->mask_offset = 3 * sizeof(float);
+ key->elem_size += sizeof(float);
+ key->has_mask = true;
+ }
+ else {
+ key->mask_offset = -1;
+ key->has_mask = false;
+ }
+ /* We never have normals in original grids. */
+ key->normal_offset = -1;
+ key->has_normals = false;
}
/* Initialize key used to access reshape grids at given level. */
-static void multires_reshape_init_level_key(
- CCGKey *key,
- const MultiresPropagateData *data,
- const int level)
+static void multires_reshape_init_level_key(CCGKey *key,
+ const MultiresPropagateData *data,
+ const int level)
{
- key->level = level;
- /* Init layers. */
- multires_reshape_init_key_layers(key, data);
- /* By default, only 3 floats for coordinate, */
- key->grid_size = BKE_subdiv_grid_size_from_level(key->level);
- key->grid_area = key->grid_size * key->grid_size;
- key->grid_bytes = key->elem_size * key->grid_area;
+ key->level = level;
+ /* Init layers. */
+ multires_reshape_init_key_layers(key, data);
+ /* By default, only 3 floats for coordinate, */
+ key->grid_size = BKE_subdiv_grid_size_from_level(key->level);
+ key->grid_area = key->grid_size * key->grid_size;
+ key->grid_bytes = key->elem_size * key->grid_area;
}
-static void multires_reshape_store_original_grids(
- MultiresPropagateData *data)
+static void multires_reshape_store_original_grids(MultiresPropagateData *data)
{
- const int num_grids = data->num_grids;
- /* Original data to be backed up. */
- const MDisps *mdisps = data->mdisps;
- const GridPaintMask *grid_paint_mask = data->grid_paint_mask;
- /* Allocate grids for backup. */
- CCGKey *orig_key = &data->reshape_level_key;
- CCGElem **orig_grids_data = allocate_grids(orig_key, num_grids);
- /* Fill in grids. */
- const int orig_grid_size = data->reshape_grid_size;
- const int top_grid_size = data->top_grid_size;
- const int skip = (top_grid_size - 1) / (orig_grid_size - 1);
- for (int grid_index = 0; grid_index < num_grids; grid_index++) {
- CCGElem *orig_grid = orig_grids_data[grid_index];
- for (int y = 0; y < orig_grid_size; y++) {
- const int top_y = y * skip;
- for (int x = 0; x < orig_grid_size; x++) {
- const int top_x = x * skip;
- const int top_index = top_y * top_grid_size + top_x;
- memcpy(CCG_grid_elem_co(orig_key, orig_grid, x, y),
- mdisps[grid_index].disps[top_index],
- sizeof(float) * 3);
- if (orig_key->has_mask) {
- *CCG_grid_elem_mask(orig_key, orig_grid, x, y) =
- grid_paint_mask[grid_index].data[top_index];
- }
- }
- }
- }
- /* Store in the context. */
- data->orig_grids_data = orig_grids_data;
+ const int num_grids = data->num_grids;
+ /* Original data to be backed up. */
+ const MDisps *mdisps = data->mdisps;
+ const GridPaintMask *grid_paint_mask = data->grid_paint_mask;
+ /* Allocate grids for backup. */
+ CCGKey *orig_key = &data->reshape_level_key;
+ CCGElem **orig_grids_data = allocate_grids(orig_key, num_grids);
+ /* Fill in grids. */
+ const int orig_grid_size = data->reshape_grid_size;
+ const int top_grid_size = data->top_grid_size;
+ const int skip = (top_grid_size - 1) / (orig_grid_size - 1);
+ for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+ CCGElem *orig_grid = orig_grids_data[grid_index];
+ for (int y = 0; y < orig_grid_size; y++) {
+ const int top_y = y * skip;
+ for (int x = 0; x < orig_grid_size; x++) {
+ const int top_x = x * skip;
+ const int top_index = top_y * top_grid_size + top_x;
+ memcpy(CCG_grid_elem_co(orig_key, orig_grid, x, y),
+ mdisps[grid_index].disps[top_index],
+ sizeof(float) * 3);
+ if (orig_key->has_mask) {
+ *CCG_grid_elem_mask(
+ orig_key, orig_grid, x, y) = grid_paint_mask[grid_index].data[top_index];
+ }
+ }
+ }
+ }
+ /* Store in the context. */
+ data->orig_grids_data = orig_grids_data;
}
-static void multires_reshape_propagate_prepare(
- MultiresPropagateData *data,
- Mesh *coarse_mesh,
- const int reshape_level,
- const int top_level)
+static void multires_reshape_propagate_prepare(MultiresPropagateData *data,
+ Mesh *coarse_mesh,
+ const int reshape_level,
+ const int top_level)
{
- BLI_assert(reshape_level <= top_level);
- memset(data, 0, sizeof(*data));
- data->num_grids = coarse_mesh->totloop;
- data->reshape_level = reshape_level;
- data->top_level = top_level;
- if (reshape_level == top_level) {
- /* Nothing to do, reshape will happen on the whole grid content. */
- return;
- }
- data->mdisps = CustomData_get_layer(&coarse_mesh->ldata, CD_MDISPS);
- data->grid_paint_mask =
- CustomData_get_layer(&coarse_mesh->ldata, CD_GRID_PAINT_MASK);
- data->top_grid_size = BKE_subdiv_grid_size_from_level(top_level);
- data->reshape_grid_size = BKE_subdiv_grid_size_from_level(reshape_level);
- /* Initialize keys to access CCG at different levels. */
- multires_reshape_init_level_key(
- &data->reshape_level_key, data, data->reshape_level);
- multires_reshape_init_level_key(
- &data->top_level_key, data, data->top_level);
- /* Make a copy of grids before reshaping, so we can calculate deltas
- * later on. */
- multires_reshape_store_original_grids(data);
+ BLI_assert(reshape_level <= top_level);
+ memset(data, 0, sizeof(*data));
+ data->num_grids = coarse_mesh->totloop;
+ data->reshape_level = reshape_level;
+ data->top_level = top_level;
+ if (reshape_level == top_level) {
+ /* Nothing to do, reshape will happen on the whole grid content. */
+ return;
+ }
+ data->mdisps = CustomData_get_layer(&coarse_mesh->ldata, CD_MDISPS);
+ data->grid_paint_mask = CustomData_get_layer(&coarse_mesh->ldata, CD_GRID_PAINT_MASK);
+ data->top_grid_size = BKE_subdiv_grid_size_from_level(top_level);
+ data->reshape_grid_size = BKE_subdiv_grid_size_from_level(reshape_level);
+ /* Initialize keys to access CCG at different levels. */
+ multires_reshape_init_level_key(&data->reshape_level_key, data, data->reshape_level);
+ multires_reshape_init_level_key(&data->top_level_key, data, data->top_level);
+ /* Make a copy of grids before reshaping, so we can calculate deltas
+ * later on. */
+ multires_reshape_store_original_grids(data);
}
-static void multires_reshape_propagate_prepare_from_mmd(
- MultiresPropagateData *data,
- struct Depsgraph *depsgraph,
- Object *object,
- const MultiresModifierData *mmd,
- const int top_level,
- const bool use_render_params)
+static void multires_reshape_propagate_prepare_from_mmd(MultiresPropagateData *data,
+ struct Depsgraph *depsgraph,
+ Object *object,
+ const MultiresModifierData *mmd,
+ const int top_level,
+ const bool use_render_params)
{
- /* TODO(sergey): Find mode reliable way of getting current level. */
- Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
- Mesh *mesh = object->data;
- const int level = multires_get_level(
- scene_eval, object, mmd, use_render_params, true);
- multires_reshape_propagate_prepare(data, mesh, level, top_level);
+ /* TODO(sergey): Find mode reliable way of getting current level. */
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ Mesh *mesh = object->data;
+ const int level = multires_get_level(scene_eval, object, mmd, use_render_params, true);
+ multires_reshape_propagate_prepare(data, mesh, level, top_level);
}
/* Calculate delta of changed reshape level data layers. Delta goes to a
* grids at top level (meaning, the result grids are only partially filled
* in). */
-static void multires_reshape_calculate_delta(
- MultiresPropagateData *data,
- CCGElem **delta_grids_data)
+static void multires_reshape_calculate_delta(MultiresPropagateData *data,
+ CCGElem **delta_grids_data)
{
- const int num_grids = data->num_grids;
- /* At this point those custom data layers has updated data for the
- * level we are propagating from. */
- const MDisps *mdisps = data->mdisps;
- const GridPaintMask *grid_paint_mask = data->grid_paint_mask;
- CCGKey *reshape_key = &data->reshape_level_key;
- CCGKey *delta_level_key = &data->top_level_key;
- /* Calculate delta. */
- const int top_grid_size = data->top_grid_size;
- const int reshape_grid_size = data->reshape_grid_size;
- const int delta_grid_size = data->top_grid_size;
- const int skip = (top_grid_size - 1) / (reshape_grid_size - 1);
- for (int grid_index = 0; grid_index < num_grids; grid_index++) {
- /*const*/ CCGElem *orig_grid = data->orig_grids_data[grid_index];
- CCGElem *delta_grid = delta_grids_data[grid_index];
- for (int y = 0; y < reshape_grid_size; y++) {
- const int top_y = y * skip;
- for (int x = 0; x < reshape_grid_size; x++) {
- const int top_x = x * skip;
- const int top_index = top_y * delta_grid_size + top_x;
- sub_v3_v3v3(
- CCG_grid_elem_co(
- delta_level_key, delta_grid, top_x, top_y),
- mdisps[grid_index].disps[top_index],
- CCG_grid_elem_co(reshape_key, orig_grid, x, y));
- if (delta_level_key->has_mask) {
- const float old_mask_value = *CCG_grid_elem_mask(
- reshape_key, orig_grid, x, y);
- const float new_mask_value =
- grid_paint_mask[grid_index].data[top_index];
- *CCG_grid_elem_mask(
- delta_level_key, delta_grid, top_x, top_y) =
- new_mask_value - old_mask_value;
- }
- }
- }
- }
+ const int num_grids = data->num_grids;
+ /* At this point those custom data layers has updated data for the
+ * level we are propagating from. */
+ const MDisps *mdisps = data->mdisps;
+ const GridPaintMask *grid_paint_mask = data->grid_paint_mask;
+ CCGKey *reshape_key = &data->reshape_level_key;
+ CCGKey *delta_level_key = &data->top_level_key;
+ /* Calculate delta. */
+ const int top_grid_size = data->top_grid_size;
+ const int reshape_grid_size = data->reshape_grid_size;
+ const int delta_grid_size = data->top_grid_size;
+ const int skip = (top_grid_size - 1) / (reshape_grid_size - 1);
+ for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+ /*const*/ CCGElem *orig_grid = data->orig_grids_data[grid_index];
+ CCGElem *delta_grid = delta_grids_data[grid_index];
+ for (int y = 0; y < reshape_grid_size; y++) {
+ const int top_y = y * skip;
+ for (int x = 0; x < reshape_grid_size; x++) {
+ const int top_x = x * skip;
+ const int top_index = top_y * delta_grid_size + top_x;
+ sub_v3_v3v3(CCG_grid_elem_co(delta_level_key, delta_grid, top_x, top_y),
+ mdisps[grid_index].disps[top_index],
+ CCG_grid_elem_co(reshape_key, orig_grid, x, y));
+ if (delta_level_key->has_mask) {
+ const float old_mask_value = *CCG_grid_elem_mask(reshape_key, orig_grid, x, y);
+ const float new_mask_value = grid_paint_mask[grid_index].data[top_index];
+ *CCG_grid_elem_mask(delta_level_key, delta_grid, top_x, top_y) = new_mask_value -
+ old_mask_value;
+ }
+ }
+ }
+ }
}
/* Makes it so delta is propagated onto all the higher levels, but is also
@@ -465,207 +430,182 @@ static void multires_reshape_calculate_delta(
* boundaries. */
typedef struct MultiresPropagateCornerData {
- float coord_delta[3];
- float mask_delta;
+ float coord_delta[3];
+ float mask_delta;
} MultiresPropagateCornerData;
BLI_INLINE void multires_reshape_propagate_init_patch_corners(
- MultiresPropagateData *data,
- CCGElem *delta_grid,
- const int patch_x, const int patch_y,
- MultiresPropagateCornerData r_corners[4])
+ MultiresPropagateData *data,
+ CCGElem *delta_grid,
+ const int patch_x,
+ const int patch_y,
+ MultiresPropagateCornerData r_corners[4])
{
- CCGKey *delta_level_key = &data->top_level_key;
- const int orig_grid_size = data->reshape_grid_size;
- const int top_grid_size = data->top_grid_size;
- const int skip = (top_grid_size - 1) / (orig_grid_size - 1);
- const int x = patch_x * skip;
- const int y = patch_y * skip;
- /* Store coordinate deltas. */
- copy_v3_v3(r_corners[0].coord_delta,
- CCG_grid_elem_co(delta_level_key, delta_grid, x, y));
- copy_v3_v3(r_corners[1].coord_delta,
- CCG_grid_elem_co(delta_level_key, delta_grid, x + skip, y));
- copy_v3_v3(r_corners[2].coord_delta,
- CCG_grid_elem_co(delta_level_key, delta_grid, x, y + skip));
- copy_v3_v3(r_corners[3].coord_delta,
- CCG_grid_elem_co(delta_level_key, delta_grid,
- x + skip, y + skip));
- if (delta_level_key->has_mask) {
- r_corners[0].mask_delta =
- *CCG_grid_elem_mask(delta_level_key, delta_grid, x, y);
- r_corners[1].mask_delta =
- *CCG_grid_elem_mask(delta_level_key, delta_grid,
- x + skip, y);
- r_corners[2].mask_delta =
- *CCG_grid_elem_mask(delta_level_key, delta_grid,
- x, y + skip);
- r_corners[3].mask_delta =
- *CCG_grid_elem_mask(delta_level_key, delta_grid,
- x + skip, y + skip);
- }
+ CCGKey *delta_level_key = &data->top_level_key;
+ const int orig_grid_size = data->reshape_grid_size;
+ const int top_grid_size = data->top_grid_size;
+ const int skip = (top_grid_size - 1) / (orig_grid_size - 1);
+ const int x = patch_x * skip;
+ const int y = patch_y * skip;
+ /* Store coordinate deltas. */
+ copy_v3_v3(r_corners[0].coord_delta, CCG_grid_elem_co(delta_level_key, delta_grid, x, y));
+ copy_v3_v3(r_corners[1].coord_delta, CCG_grid_elem_co(delta_level_key, delta_grid, x + skip, y));
+ copy_v3_v3(r_corners[2].coord_delta, CCG_grid_elem_co(delta_level_key, delta_grid, x, y + skip));
+ copy_v3_v3(r_corners[3].coord_delta,
+ CCG_grid_elem_co(delta_level_key, delta_grid, x + skip, y + skip));
+ if (delta_level_key->has_mask) {
+ r_corners[0].mask_delta = *CCG_grid_elem_mask(delta_level_key, delta_grid, x, y);
+ r_corners[1].mask_delta = *CCG_grid_elem_mask(delta_level_key, delta_grid, x + skip, y);
+ r_corners[2].mask_delta = *CCG_grid_elem_mask(delta_level_key, delta_grid, x, y + skip);
+ r_corners[3].mask_delta = *CCG_grid_elem_mask(delta_level_key, delta_grid, x + skip, y + skip);
+ }
}
BLI_INLINE void multires_reshape_propagate_interpolate_coord(
- float delta[3],
- const MultiresPropagateCornerData corners[4],
- const float weights[4])
+ float delta[3], const MultiresPropagateCornerData corners[4], const float weights[4])
{
- interp_v3_v3v3v3v3(
- delta,
- corners[0].coord_delta, corners[1].coord_delta,
- corners[2].coord_delta, corners[3].coord_delta,
- weights);
+ interp_v3_v3v3v3v3(delta,
+ corners[0].coord_delta,
+ corners[1].coord_delta,
+ corners[2].coord_delta,
+ corners[3].coord_delta,
+ weights);
}
BLI_INLINE float multires_reshape_propagate_interpolate_mask(
- const MultiresPropagateCornerData corners[4],
- const float weights[4])
+ const MultiresPropagateCornerData corners[4], const float weights[4])
{
- return corners[0].mask_delta * weights[0] +
- corners[1].mask_delta * weights[1] +
- corners[2].mask_delta * weights[2] +
- corners[3].mask_delta * weights[3];
+ return corners[0].mask_delta * weights[0] + corners[1].mask_delta * weights[1] +
+ corners[2].mask_delta * weights[2] + corners[3].mask_delta * weights[3];
}
-BLI_INLINE void multires_reshape_propagate_and_smooth_delta_grid_patch(
- MultiresPropagateData *data,
- CCGElem *delta_grid,
- const int patch_x, const int patch_y)
+BLI_INLINE void multires_reshape_propagate_and_smooth_delta_grid_patch(MultiresPropagateData *data,
+ CCGElem *delta_grid,
+ const int patch_x,
+ const int patch_y)
{
- CCGKey *delta_level_key = &data->top_level_key;
- const int orig_grid_size = data->reshape_grid_size;
- const int top_grid_size = data->top_grid_size;
- const int skip = (top_grid_size - 1) / (orig_grid_size - 1);
- const float skip_inv = 1.0f / (float)skip;
- MultiresPropagateCornerData corners[4];
- multires_reshape_propagate_init_patch_corners(
- data, delta_grid, patch_x, patch_y, corners);
- const int start_x = patch_x * skip;
- const int start_y = patch_y * skip;
- for (int y = 0; y <= skip; y++) {
- const float v = (float)y * skip_inv;
- const int final_y = start_y + y;
- for (int x = 0; x <= skip; x++) {
- const float u = (float)x * skip_inv;
- const int final_x = start_x + x;
- const float linear_weights[4] = {(1.0f - u) * (1.0f - v),
- u * (1.0f - v),
- (1.0f - u) * v,
- u * v};
- multires_reshape_propagate_interpolate_coord(
- CCG_grid_elem_co(delta_level_key, delta_grid,
- final_x, final_y),
- corners,
- linear_weights);
- if (delta_level_key->has_mask) {
- float *mask = CCG_grid_elem_mask(delta_level_key, delta_grid,
- final_x, final_y);
- *mask = multires_reshape_propagate_interpolate_mask(
- corners, linear_weights);
- }
- }
- }
+ CCGKey *delta_level_key = &data->top_level_key;
+ const int orig_grid_size = data->reshape_grid_size;
+ const int top_grid_size = data->top_grid_size;
+ const int skip = (top_grid_size - 1) / (orig_grid_size - 1);
+ const float skip_inv = 1.0f / (float)skip;
+ MultiresPropagateCornerData corners[4];
+ multires_reshape_propagate_init_patch_corners(data, delta_grid, patch_x, patch_y, corners);
+ const int start_x = patch_x * skip;
+ const int start_y = patch_y * skip;
+ for (int y = 0; y <= skip; y++) {
+ const float v = (float)y * skip_inv;
+ const int final_y = start_y + y;
+ for (int x = 0; x <= skip; x++) {
+ const float u = (float)x * skip_inv;
+ const int final_x = start_x + x;
+ const float linear_weights[4] = {
+ (1.0f - u) * (1.0f - v), u * (1.0f - v), (1.0f - u) * v, u * v};
+ multires_reshape_propagate_interpolate_coord(
+ CCG_grid_elem_co(delta_level_key, delta_grid, final_x, final_y),
+ corners,
+ linear_weights);
+ if (delta_level_key->has_mask) {
+ float *mask = CCG_grid_elem_mask(delta_level_key, delta_grid, final_x, final_y);
+ *mask = multires_reshape_propagate_interpolate_mask(corners, linear_weights);
+ }
+ }
+ }
}
-BLI_INLINE void multires_reshape_propagate_and_smooth_delta_grid(
- MultiresPropagateData *data,
- CCGElem *delta_grid)
+BLI_INLINE void multires_reshape_propagate_and_smooth_delta_grid(MultiresPropagateData *data,
+ CCGElem *delta_grid)
{
- const int orig_grid_size = data->reshape_grid_size;
- for (int patch_y = 0; patch_y < orig_grid_size - 1; patch_y++) {
- for (int patch_x = 0; patch_x < orig_grid_size - 1; patch_x++) {
- multires_reshape_propagate_and_smooth_delta_grid_patch(
- data, delta_grid, patch_x, patch_y);
- }
- }
+ const int orig_grid_size = data->reshape_grid_size;
+ for (int patch_y = 0; patch_y < orig_grid_size - 1; patch_y++) {
+ for (int patch_x = 0; patch_x < orig_grid_size - 1; patch_x++) {
+ multires_reshape_propagate_and_smooth_delta_grid_patch(data, delta_grid, patch_x, patch_y);
+ }
+ }
}
/* Entry point to propagate+smooth. */
-static void multires_reshape_propagate_and_smooth_delta(
- MultiresPropagateData *data,
- CCGElem **delta_grids_data)
+static void multires_reshape_propagate_and_smooth_delta(MultiresPropagateData *data,
+ CCGElem **delta_grids_data)
{
- const int num_grids = data->num_grids;
- for (int grid_index = 0; grid_index < num_grids; grid_index++) {
- CCGElem *delta_grid = delta_grids_data[grid_index];
- multires_reshape_propagate_and_smooth_delta_grid(data, delta_grid);
- }
+ const int num_grids = data->num_grids;
+ for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+ CCGElem *delta_grid = delta_grids_data[grid_index];
+ multires_reshape_propagate_and_smooth_delta_grid(data, delta_grid);
+ }
}
/* Apply smoothed deltas on the actual data layers. */
-static void multires_reshape_propagate_apply_delta(
- MultiresPropagateData *data,
- CCGElem **delta_grids_data)
+static void multires_reshape_propagate_apply_delta(MultiresPropagateData *data,
+ CCGElem **delta_grids_data)
{
- const int num_grids = data->num_grids;
- /* At this point those custom data layers has updated data for the
- * level we are propagating from. */
- MDisps *mdisps = data->mdisps;
- GridPaintMask *grid_paint_mask = data->grid_paint_mask;
- CCGKey *orig_key = &data->reshape_level_key;
- CCGKey *delta_level_key = &data->top_level_key;
- CCGElem **orig_grids_data = data->orig_grids_data;
- const int orig_grid_size = data->reshape_grid_size;
- const int top_grid_size = data->top_grid_size;
- const int skip = (top_grid_size - 1) / (orig_grid_size - 1);
- /* Restore grid values at the reshape level. Those values are to be changed
- * to the accommodate for the smooth delta. */
- for (int grid_index = 0; grid_index < num_grids; grid_index++) {
- CCGElem *orig_grid = orig_grids_data[grid_index];
- for (int y = 0; y < orig_grid_size; y++) {
- const int top_y = y * skip;
- for (int x = 0; x < orig_grid_size; x++) {
- const int top_x = x * skip;
- const int top_index = top_y * top_grid_size + top_x;
- copy_v3_v3(mdisps[grid_index].disps[top_index],
- CCG_grid_elem_co(orig_key, orig_grid, x, y));
- if (grid_paint_mask != NULL) {
- grid_paint_mask[grid_index].data[top_index] =
- *CCG_grid_elem_mask(orig_key, orig_grid, x, y);
- }
- }
- }
- }
- /* Add smoothed delta to all the levels. */
- for (int grid_index = 0; grid_index < num_grids; grid_index++) {
- CCGElem *delta_grid = delta_grids_data[grid_index];
- for (int y = 0; y < top_grid_size; y++) {
- for (int x = 0; x < top_grid_size; x++) {
- const int top_index = y * top_grid_size + x;
- add_v3_v3(mdisps[grid_index].disps[top_index],
- CCG_grid_elem_co(delta_level_key, delta_grid, x, y));
- if (delta_level_key->has_mask) {
- grid_paint_mask[grid_index].data[top_index] +=
- *CCG_grid_elem_mask(
- delta_level_key, delta_grid, x, y);
- }
- }
- }
- }
+ const int num_grids = data->num_grids;
+ /* At this point those custom data layers has updated data for the
+ * level we are propagating from. */
+ MDisps *mdisps = data->mdisps;
+ GridPaintMask *grid_paint_mask = data->grid_paint_mask;
+ CCGKey *orig_key = &data->reshape_level_key;
+ CCGKey *delta_level_key = &data->top_level_key;
+ CCGElem **orig_grids_data = data->orig_grids_data;
+ const int orig_grid_size = data->reshape_grid_size;
+ const int top_grid_size = data->top_grid_size;
+ const int skip = (top_grid_size - 1) / (orig_grid_size - 1);
+ /* Restore grid values at the reshape level. Those values are to be changed
+ * to the accommodate for the smooth delta. */
+ for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+ CCGElem *orig_grid = orig_grids_data[grid_index];
+ for (int y = 0; y < orig_grid_size; y++) {
+ const int top_y = y * skip;
+ for (int x = 0; x < orig_grid_size; x++) {
+ const int top_x = x * skip;
+ const int top_index = top_y * top_grid_size + top_x;
+ copy_v3_v3(mdisps[grid_index].disps[top_index],
+ CCG_grid_elem_co(orig_key, orig_grid, x, y));
+ if (grid_paint_mask != NULL) {
+ grid_paint_mask[grid_index].data[top_index] = *CCG_grid_elem_mask(
+ orig_key, orig_grid, x, y);
+ }
+ }
+ }
+ }
+ /* Add smoothed delta to all the levels. */
+ for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+ CCGElem *delta_grid = delta_grids_data[grid_index];
+ for (int y = 0; y < top_grid_size; y++) {
+ for (int x = 0; x < top_grid_size; x++) {
+ const int top_index = y * top_grid_size + x;
+ add_v3_v3(mdisps[grid_index].disps[top_index],
+ CCG_grid_elem_co(delta_level_key, delta_grid, x, y));
+ if (delta_level_key->has_mask) {
+ grid_paint_mask[grid_index].data[top_index] += *CCG_grid_elem_mask(
+ delta_level_key, delta_grid, x, y);
+ }
+ }
+ }
+ }
}
static void multires_reshape_propagate(MultiresPropagateData *data)
{
- if (data->reshape_level == data->top_level) {
- return;
- }
- const int num_grids = data->num_grids;
- /* Calculate delta made at the reshape level. */
- CCGKey *delta_level_key = &data->top_level_key;
- CCGElem **delta_grids_data = allocate_grids(delta_level_key, num_grids);
- multires_reshape_calculate_delta(data, delta_grids_data);
- /* Propagate deltas to the higher levels. */
- multires_reshape_propagate_and_smooth_delta(data, delta_grids_data);
- /* Finally, apply smoothed deltas. */
- multires_reshape_propagate_apply_delta(data, delta_grids_data);
- /* Cleanup. */
- free_grids(delta_grids_data, num_grids);
+ if (data->reshape_level == data->top_level) {
+ return;
+ }
+ const int num_grids = data->num_grids;
+ /* Calculate delta made at the reshape level. */
+ CCGKey *delta_level_key = &data->top_level_key;
+ CCGElem **delta_grids_data = allocate_grids(delta_level_key, num_grids);
+ multires_reshape_calculate_delta(data, delta_grids_data);
+ /* Propagate deltas to the higher levels. */
+ multires_reshape_propagate_and_smooth_delta(data, delta_grids_data);
+ /* Finally, apply smoothed deltas. */
+ multires_reshape_propagate_apply_delta(data, delta_grids_data);
+ /* Cleanup. */
+ free_grids(delta_grids_data, num_grids);
}
static void multires_reshape_propagate_free(MultiresPropagateData *data)
{
- free_grids(data->orig_grids_data, data->num_grids);
+ free_grids(data->orig_grids_data, data->num_grids);
}
/* =============================================================================
@@ -673,270 +613,256 @@ static void multires_reshape_propagate_free(MultiresPropagateData *data)
*/
typedef struct MultiresReshapeFromDeformedVertsContext {
- MultiresReshapeContext reshape_ctx;
- const float (*deformed_verts)[3];
- int num_deformed_verts;
+ MultiresReshapeContext reshape_ctx;
+ const float (*deformed_verts)[3];
+ int num_deformed_verts;
} MultiresReshapeFromDeformedVertsContext;
-static bool multires_reshape_topology_info(
- const SubdivForeachContext *foreach_context,
- const int num_vertices,
- const int UNUSED(num_edges),
- const int UNUSED(num_loops),
- const int UNUSED(num_polygons))
+static bool multires_reshape_topology_info(const SubdivForeachContext *foreach_context,
+ const int num_vertices,
+ const int UNUSED(num_edges),
+ const int UNUSED(num_loops),
+ const int UNUSED(num_polygons))
{
- MultiresReshapeFromDeformedVertsContext *ctx = foreach_context->user_data;
- if (num_vertices != ctx->num_deformed_verts) {
- return false;
- }
- return true;
+ MultiresReshapeFromDeformedVertsContext *ctx = foreach_context->user_data;
+ if (num_vertices != ctx->num_deformed_verts) {
+ return false;
+ }
+ return true;
}
/* Will run reshaping for all grid elements which are adjacent to the given
* one. This is the way to ensure continuity of displacement stored in the
* grids across the inner boundaries of the grids. */
-static void multires_reshape_neighour_boundary_vertices(
- MultiresReshapeContext *ctx,
- const int UNUSED(ptex_face_index),
- const float corner_u, const float corner_v,
- const int coarse_poly_index,
- const int coarse_corner,
- const float final_P[3], const float final_mask)
+static void multires_reshape_neighour_boundary_vertices(MultiresReshapeContext *ctx,
+ const int UNUSED(ptex_face_index),
+ const float corner_u,
+ const float corner_v,
+ const int coarse_poly_index,
+ const int coarse_corner,
+ const float final_P[3],
+ const float final_mask)
{
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MPoly *coarse_mpoly = coarse_mesh->mpoly;
- const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index];
- const int num_corners = coarse_poly->totloop;
- const int start_ptex_face_index = ctx->face_ptex_offset[coarse_poly_index];
- const bool is_quad = (coarse_poly->totloop == 4);
- if (corner_u == 1.0f && corner_v == 1.0f) {
- for (int current_corner = 0;
- current_corner < num_corners;
- ++current_corner)
- {
- if (current_corner == coarse_corner) {
- continue;
- }
- const int current_ptex_face_index =
- is_quad ? start_ptex_face_index
- : start_ptex_face_index + current_corner;
- multires_reshape_vertex_from_final_data(
- ctx,
- current_ptex_face_index, 1.0f, 1.0f,
- coarse_poly_index,
- current_corner,
- final_P, final_mask);
- }
- }
- else if (corner_u == 1.0f) {
- const float next_corner_index = (coarse_corner + 1) % num_corners;
- const float next_corner_u = corner_v;
- const float next_corner_v = 1.0f;
- const int next_ptex_face_index =
- is_quad ? start_ptex_face_index
- : start_ptex_face_index + next_corner_index;
- multires_reshape_vertex_from_final_data(
- ctx,
- next_ptex_face_index, next_corner_u, next_corner_v,
- coarse_poly_index,
- next_corner_index,
- final_P, final_mask);
- }
- else if (corner_v == 1.0f) {
- const float prev_corner_index =
- (coarse_corner + num_corners - 1) % num_corners;
- const float prev_corner_u = 1.0f;
- const float prev_corner_v = corner_u;
- const int prev_ptex_face_index =
- is_quad ? start_ptex_face_index
- : start_ptex_face_index + prev_corner_index;
- multires_reshape_vertex_from_final_data(
- ctx,
- prev_ptex_face_index, prev_corner_u, prev_corner_v,
- coarse_poly_index,
- prev_corner_index,
- final_P, final_mask);
- }
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index];
+ const int num_corners = coarse_poly->totloop;
+ const int start_ptex_face_index = ctx->face_ptex_offset[coarse_poly_index];
+ const bool is_quad = (coarse_poly->totloop == 4);
+ if (corner_u == 1.0f && corner_v == 1.0f) {
+ for (int current_corner = 0; current_corner < num_corners; ++current_corner) {
+ if (current_corner == coarse_corner) {
+ continue;
+ }
+ const int current_ptex_face_index = is_quad ? start_ptex_face_index :
+ start_ptex_face_index + current_corner;
+ multires_reshape_vertex_from_final_data(ctx,
+ current_ptex_face_index,
+ 1.0f,
+ 1.0f,
+ coarse_poly_index,
+ current_corner,
+ final_P,
+ final_mask);
+ }
+ }
+ else if (corner_u == 1.0f) {
+ const float next_corner_index = (coarse_corner + 1) % num_corners;
+ const float next_corner_u = corner_v;
+ const float next_corner_v = 1.0f;
+ const int next_ptex_face_index = is_quad ? start_ptex_face_index :
+ start_ptex_face_index + next_corner_index;
+ multires_reshape_vertex_from_final_data(ctx,
+ next_ptex_face_index,
+ next_corner_u,
+ next_corner_v,
+ coarse_poly_index,
+ next_corner_index,
+ final_P,
+ final_mask);
+ }
+ else if (corner_v == 1.0f) {
+ const float prev_corner_index = (coarse_corner + num_corners - 1) % num_corners;
+ const float prev_corner_u = 1.0f;
+ const float prev_corner_v = corner_u;
+ const int prev_ptex_face_index = is_quad ? start_ptex_face_index :
+ start_ptex_face_index + prev_corner_index;
+ multires_reshape_vertex_from_final_data(ctx,
+ prev_ptex_face_index,
+ prev_corner_u,
+ prev_corner_v,
+ coarse_poly_index,
+ prev_corner_index,
+ final_P,
+ final_mask);
+ }
}
-static void multires_reshape_vertex(
- MultiresReshapeFromDeformedVertsContext *ctx,
- const int ptex_face_index,
- const float u, const float v,
- const int coarse_poly_index,
- const int coarse_corner,
- const int subdiv_vertex_index)
+static void multires_reshape_vertex(MultiresReshapeFromDeformedVertsContext *ctx,
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ const int coarse_poly_index,
+ const int coarse_corner,
+ const int subdiv_vertex_index)
{
- const float *final_P = ctx->deformed_verts[subdiv_vertex_index];
- const Mesh *coarse_mesh = ctx->reshape_ctx.coarse_mesh;
- const MPoly *coarse_mpoly = coarse_mesh->mpoly;
- const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index];
- const bool is_quad = (coarse_poly->totloop == 4);
- float corner_u, corner_v;
- int actual_coarse_corner;
- if (is_quad) {
- actual_coarse_corner = BKE_subdiv_rotate_quad_to_corner(
- u, v, &corner_u, &corner_v);
- }
- else {
- actual_coarse_corner = coarse_corner;
- corner_u = u;
- corner_v = v;
- }
- multires_reshape_vertex_from_final_data(
- &ctx->reshape_ctx,
- ptex_face_index, corner_u, corner_v,
- coarse_poly_index,
- actual_coarse_corner,
- final_P, 0.0f);
- multires_reshape_neighour_boundary_vertices(
- &ctx->reshape_ctx,
- ptex_face_index, corner_u, corner_v,
- coarse_poly_index,
- actual_coarse_corner,
- final_P, 0.0f);
+ const float *final_P = ctx->deformed_verts[subdiv_vertex_index];
+ const Mesh *coarse_mesh = ctx->reshape_ctx.coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index];
+ const bool is_quad = (coarse_poly->totloop == 4);
+ float corner_u, corner_v;
+ int actual_coarse_corner;
+ if (is_quad) {
+ actual_coarse_corner = BKE_subdiv_rotate_quad_to_corner(u, v, &corner_u, &corner_v);
+ }
+ else {
+ actual_coarse_corner = coarse_corner;
+ corner_u = u;
+ corner_v = v;
+ }
+ multires_reshape_vertex_from_final_data(&ctx->reshape_ctx,
+ ptex_face_index,
+ corner_u,
+ corner_v,
+ coarse_poly_index,
+ actual_coarse_corner,
+ final_P,
+ 0.0f);
+ multires_reshape_neighour_boundary_vertices(&ctx->reshape_ctx,
+ ptex_face_index,
+ corner_u,
+ corner_v,
+ coarse_poly_index,
+ actual_coarse_corner,
+ final_P,
+ 0.0f);
}
-static void multires_reshape_vertex_inner(
- const SubdivForeachContext *foreach_context,
- void *UNUSED(tls_v),
- const int ptex_face_index,
- const float u, const float v,
- const int coarse_poly_index,
- const int coarse_corner,
- const int subdiv_vertex_index)
+static void multires_reshape_vertex_inner(const SubdivForeachContext *foreach_context,
+ void *UNUSED(tls_v),
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ const int coarse_poly_index,
+ const int coarse_corner,
+ const int subdiv_vertex_index)
{
- MultiresReshapeFromDeformedVertsContext *ctx = foreach_context->user_data;
- multires_reshape_vertex(
- ctx,
- ptex_face_index, u, v,
- coarse_poly_index,
- coarse_corner,
- subdiv_vertex_index);
+ MultiresReshapeFromDeformedVertsContext *ctx = foreach_context->user_data;
+ multires_reshape_vertex(
+ ctx, ptex_face_index, u, v, coarse_poly_index, coarse_corner, subdiv_vertex_index);
}
static void multires_reshape_vertex_every_corner(
- const struct SubdivForeachContext *foreach_context,
- void *UNUSED(tls_v),
- const int ptex_face_index,
- const float u, const float v,
- const int UNUSED(coarse_vertex_index),
- const int coarse_poly_index,
- const int coarse_corner,
- const int subdiv_vertex_index)
+ const struct SubdivForeachContext *foreach_context,
+ void *UNUSED(tls_v),
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ const int UNUSED(coarse_vertex_index),
+ const int coarse_poly_index,
+ const int coarse_corner,
+ const int subdiv_vertex_index)
{
- MultiresReshapeFromDeformedVertsContext *ctx = foreach_context->user_data;
- multires_reshape_vertex(
- ctx,
- ptex_face_index, u, v,
- coarse_poly_index,
- coarse_corner,
- subdiv_vertex_index);
+ MultiresReshapeFromDeformedVertsContext *ctx = foreach_context->user_data;
+ multires_reshape_vertex(
+ ctx, ptex_face_index, u, v, coarse_poly_index, coarse_corner, subdiv_vertex_index);
}
-static void multires_reshape_vertex_every_edge(
- const struct SubdivForeachContext *foreach_context,
- void *UNUSED(tls_v),
- const int ptex_face_index,
- const float u, const float v,
- const int UNUSED(coarse_edge_index),
- const int coarse_poly_index,
- const int coarse_corner,
- const int subdiv_vertex_index)
+static void multires_reshape_vertex_every_edge(const struct SubdivForeachContext *foreach_context,
+ void *UNUSED(tls_v),
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ const int UNUSED(coarse_edge_index),
+ const int coarse_poly_index,
+ const int coarse_corner,
+ const int subdiv_vertex_index)
{
- MultiresReshapeFromDeformedVertsContext *ctx = foreach_context->user_data;
- multires_reshape_vertex(
- ctx,
- ptex_face_index, u, v,
- coarse_poly_index,
- coarse_corner,
- subdiv_vertex_index);
+ MultiresReshapeFromDeformedVertsContext *ctx = foreach_context->user_data;
+ multires_reshape_vertex(
+ ctx, ptex_face_index, u, v, coarse_poly_index, coarse_corner, subdiv_vertex_index);
}
-static Subdiv *multires_create_subdiv_for_reshape(
- struct Depsgraph *depsgraph,
- /*const*/ Object *object,
- const MultiresModifierData *mmd)
+static Subdiv *multires_create_subdiv_for_reshape(struct Depsgraph *depsgraph,
+ /*const*/ Object *object,
+ const MultiresModifierData *mmd)
{
- Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
- Object *object_eval = DEG_get_evaluated_object(depsgraph, object);
- Mesh *deformed_mesh = mesh_get_eval_deform(
- depsgraph, scene_eval, object_eval, &CD_MASK_BAREMESH);
- SubdivSettings subdiv_settings;
- BKE_multires_subdiv_settings_init(&subdiv_settings, mmd);
- Subdiv *subdiv = BKE_subdiv_new_from_mesh(&subdiv_settings, deformed_mesh);
- if (!BKE_subdiv_eval_update_from_mesh(subdiv, deformed_mesh)) {
- BKE_subdiv_free(subdiv);
- return NULL;
- }
- return subdiv;
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ Object *object_eval = DEG_get_evaluated_object(depsgraph, object);
+ Mesh *deformed_mesh = mesh_get_eval_deform(
+ depsgraph, scene_eval, object_eval, &CD_MASK_BAREMESH);
+ SubdivSettings subdiv_settings;
+ BKE_multires_subdiv_settings_init(&subdiv_settings, mmd);
+ Subdiv *subdiv = BKE_subdiv_new_from_mesh(&subdiv_settings, deformed_mesh);
+ if (!BKE_subdiv_eval_update_from_mesh(subdiv, deformed_mesh)) {
+ BKE_subdiv_free(subdiv);
+ return NULL;
+ }
+ return subdiv;
}
-static bool multires_reshape_from_vertcos(
- struct Depsgraph *depsgraph,
- Object *object,
- const MultiresModifierData *mmd,
- const float (*deformed_verts)[3],
- const int num_deformed_verts,
- const bool use_render_params)
+static bool multires_reshape_from_vertcos(struct Depsgraph *depsgraph,
+ Object *object,
+ const MultiresModifierData *mmd,
+ const float (*deformed_verts)[3],
+ const int num_deformed_verts,
+ const bool use_render_params)
{
- Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
- Mesh *coarse_mesh = object->data;
- MDisps *mdisps = CustomData_get_layer(&coarse_mesh->ldata, CD_MDISPS);
- /* Pick maximum between multires level and dispalcement level.
- * This is because mesh can be used by objects with multires at different
- * levels.
- *
- * TODO(sergey): At this point it should be possible to always use
- * mdisps->level. */
- const int top_level = max_ii(mmd->totlvl, mdisps->level);
- /* Make sure displacement grids are ready. */
- multires_reshape_ensure_grids(coarse_mesh, top_level);
- /* Initialize subdivision surface. */
- Subdiv *subdiv = multires_create_subdiv_for_reshape(depsgraph, object, mmd);
- if (subdiv == NULL) {
- return false;
- }
- /* Construct context. */
- MultiresReshapeFromDeformedVertsContext reshape_deformed_verts_ctx = {
- .reshape_ctx = {
- .subdiv = subdiv,
- .coarse_mesh = coarse_mesh,
- .mdisps = mdisps,
- .grid_paint_mask = NULL,
- .top_grid_size = BKE_subdiv_grid_size_from_level(top_level),
- .top_level = top_level,
- .face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv),
- },
- .deformed_verts = deformed_verts,
- .num_deformed_verts = num_deformed_verts,
- };
- SubdivForeachContext foreach_context = {
- .topology_info = multires_reshape_topology_info,
- .vertex_inner = multires_reshape_vertex_inner,
- .vertex_every_edge = multires_reshape_vertex_every_edge,
- .vertex_every_corner = multires_reshape_vertex_every_corner,
- .user_data = &reshape_deformed_verts_ctx,
- };
- /* Initialize mesh rasterization settings. */
- SubdivToMeshSettings mesh_settings;
- BKE_multires_subdiv_mesh_settings_init(
- &mesh_settings, scene_eval, object, mmd, use_render_params, true);
- /* Initialize propagation to higher levels. */
- MultiresPropagateData propagate_data;
- multires_reshape_propagate_prepare_from_mmd(
- &propagate_data, depsgraph, object, mmd, top_level, use_render_params);
- /* Run all the callbacks. */
- BKE_subdiv_foreach_subdiv_geometry(
- subdiv,
- &foreach_context,
- &mesh_settings,
- coarse_mesh);
- BKE_subdiv_free(subdiv);
- /* Update higher levels if needed. */
- multires_reshape_propagate(&propagate_data);
- multires_reshape_propagate_free(&propagate_data);
- return true;
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ Mesh *coarse_mesh = object->data;
+ MDisps *mdisps = CustomData_get_layer(&coarse_mesh->ldata, CD_MDISPS);
+ /* Pick maximum between multires level and dispalcement level.
+ * This is because mesh can be used by objects with multires at different
+ * levels.
+ *
+ * TODO(sergey): At this point it should be possible to always use
+ * mdisps->level. */
+ const int top_level = max_ii(mmd->totlvl, mdisps->level);
+ /* Make sure displacement grids are ready. */
+ multires_reshape_ensure_grids(coarse_mesh, top_level);
+ /* Initialize subdivision surface. */
+ Subdiv *subdiv = multires_create_subdiv_for_reshape(depsgraph, object, mmd);
+ if (subdiv == NULL) {
+ return false;
+ }
+ /* Construct context. */
+ MultiresReshapeFromDeformedVertsContext reshape_deformed_verts_ctx = {
+ .reshape_ctx =
+ {
+ .subdiv = subdiv,
+ .coarse_mesh = coarse_mesh,
+ .mdisps = mdisps,
+ .grid_paint_mask = NULL,
+ .top_grid_size = BKE_subdiv_grid_size_from_level(top_level),
+ .top_level = top_level,
+ .face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv),
+ },
+ .deformed_verts = deformed_verts,
+ .num_deformed_verts = num_deformed_verts,
+ };
+ SubdivForeachContext foreach_context = {
+ .topology_info = multires_reshape_topology_info,
+ .vertex_inner = multires_reshape_vertex_inner,
+ .vertex_every_edge = multires_reshape_vertex_every_edge,
+ .vertex_every_corner = multires_reshape_vertex_every_corner,
+ .user_data = &reshape_deformed_verts_ctx,
+ };
+ /* Initialize mesh rasterization settings. */
+ SubdivToMeshSettings mesh_settings;
+ BKE_multires_subdiv_mesh_settings_init(
+ &mesh_settings, scene_eval, object, mmd, use_render_params, true);
+ /* Initialize propagation to higher levels. */
+ MultiresPropagateData propagate_data;
+ multires_reshape_propagate_prepare_from_mmd(
+ &propagate_data, depsgraph, object, mmd, top_level, use_render_params);
+ /* Run all the callbacks. */
+ BKE_subdiv_foreach_subdiv_geometry(subdiv, &foreach_context, &mesh_settings, coarse_mesh);
+ BKE_subdiv_free(subdiv);
+ /* Update higher levels if needed. */
+ multires_reshape_propagate(&propagate_data);
+ multires_reshape_propagate_free(&propagate_data);
+ return true;
}
/* =============================================================================
@@ -947,94 +873,74 @@ static bool multires_reshape_from_vertcos(
*
* This function might fail in cases like source and destination not having
* matched amount of vertices. */
-bool multiresModifier_reshapeFromObject(
- struct Depsgraph *depsgraph,
- MultiresModifierData *mmd,
- Object *dst,
- Object *src)
+bool multiresModifier_reshapeFromObject(struct Depsgraph *depsgraph,
+ MultiresModifierData *mmd,
+ Object *dst,
+ Object *src)
{
- /* Would be cool to support this eventually, but it is very tricky to match
- * vertices order even for meshes, when mixing meshes and other objects it's
- * even more tricky. */
- if (src->type != OB_MESH) {
- return false;
- }
- MultiresModifierData reshape_mmd;
- multires_reshape_init_mmd(&reshape_mmd, mmd);
- /* Get evaluated vertices locations to reshape to. */
- Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
- Object *src_eval = DEG_get_evaluated_object(depsgraph, src);
- Mesh *src_mesh_eval = mesh_get_eval_final(
- depsgraph, scene_eval, src_eval, &CD_MASK_BAREMESH);
- int num_deformed_verts;
- float (*deformed_verts)[3] = BKE_mesh_vertexCos_get(
- src_mesh_eval, &num_deformed_verts);
- bool result = multires_reshape_from_vertcos(
- depsgraph,
- dst,
- &reshape_mmd,
- deformed_verts,
- num_deformed_verts,
- false);
- MEM_freeN(deformed_verts);
- return result;
+ /* Would be cool to support this eventually, but it is very tricky to match
+ * vertices order even for meshes, when mixing meshes and other objects it's
+ * even more tricky. */
+ if (src->type != OB_MESH) {
+ return false;
+ }
+ MultiresModifierData reshape_mmd;
+ multires_reshape_init_mmd(&reshape_mmd, mmd);
+ /* Get evaluated vertices locations to reshape to. */
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ Object *src_eval = DEG_get_evaluated_object(depsgraph, src);
+ Mesh *src_mesh_eval = mesh_get_eval_final(depsgraph, scene_eval, src_eval, &CD_MASK_BAREMESH);
+ int num_deformed_verts;
+ float(*deformed_verts)[3] = BKE_mesh_vertexCos_get(src_mesh_eval, &num_deformed_verts);
+ bool result = multires_reshape_from_vertcos(
+ depsgraph, dst, &reshape_mmd, deformed_verts, num_deformed_verts, false);
+ MEM_freeN(deformed_verts);
+ return result;
}
/* =============================================================================
* Reshape from modifier.
*/
-bool multiresModifier_reshapeFromDeformModifier(
- struct Depsgraph *depsgraph,
- MultiresModifierData *mmd,
- Object *object,
- ModifierData *md)
+bool multiresModifier_reshapeFromDeformModifier(struct Depsgraph *depsgraph,
+ MultiresModifierData *mmd,
+ Object *object,
+ ModifierData *md)
{
- MultiresModifierData highest_mmd;
- /* It is possible that the current subdivision level of multires is lower
- * that it's maximum possible one (i.e., viewport is set to a lower level
- * for the performance purposes). But even then, we want all the multires
- * levels to be reshaped. Most accurate way to do so is to ignore all
- * simplifications and calculate deformation modifier for the highest
- * possible multires level.
- * Alternative would be propagate displacement from current level to a
- * higher ones, but that is likely to cause artifacts. */
- multires_reshape_init_mmd_top_level(&highest_mmd, mmd);
- Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
- /* Perform sanity checks and early output. */
- if (multires_get_level(
- scene_eval, object, &highest_mmd, false, true) == 0)
- {
- return false;
- }
- /* Create mesh for the multires, ignoring any further modifiers (leading
- * deformation modifiers will be applied though). */
- Mesh *multires_mesh = BKE_multires_create_mesh(
- depsgraph, scene_eval, &highest_mmd, object);
- int num_deformed_verts;
- float (*deformed_verts)[3] = BKE_mesh_vertexCos_get(
- multires_mesh, &num_deformed_verts);
- /* Apply deformation modifier on the multires, */
- const ModifierEvalContext modifier_ctx = {
- .depsgraph = depsgraph,
- .object = object,
- .flag = MOD_APPLY_USECACHE | MOD_APPLY_IGNORE_SIMPLIFY,
- };
- modwrap_deformVerts(
- md, &modifier_ctx, multires_mesh, deformed_verts,
- multires_mesh->totvert);
- BKE_id_free(NULL, multires_mesh);
- /* Reshaping */
- bool result = multires_reshape_from_vertcos(
- depsgraph,
- object,
- &highest_mmd,
- deformed_verts,
- num_deformed_verts,
- false);
- /* Cleanup */
- MEM_freeN(deformed_verts);
- return result;
+ MultiresModifierData highest_mmd;
+ /* It is possible that the current subdivision level of multires is lower
+ * that it's maximum possible one (i.e., viewport is set to a lower level
+ * for the performance purposes). But even then, we want all the multires
+ * levels to be reshaped. Most accurate way to do so is to ignore all
+ * simplifications and calculate deformation modifier for the highest
+ * possible multires level.
+ * Alternative would be propagate displacement from current level to a
+ * higher ones, but that is likely to cause artifacts. */
+ multires_reshape_init_mmd_top_level(&highest_mmd, mmd);
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ /* Perform sanity checks and early output. */
+ if (multires_get_level(scene_eval, object, &highest_mmd, false, true) == 0) {
+ return false;
+ }
+ /* Create mesh for the multires, ignoring any further modifiers (leading
+ * deformation modifiers will be applied though). */
+ Mesh *multires_mesh = BKE_multires_create_mesh(depsgraph, scene_eval, &highest_mmd, object);
+ int num_deformed_verts;
+ float(*deformed_verts)[3] = BKE_mesh_vertexCos_get(multires_mesh, &num_deformed_verts);
+ /* Apply deformation modifier on the multires, */
+ const ModifierEvalContext modifier_ctx = {
+ .depsgraph = depsgraph,
+ .object = object,
+ .flag = MOD_APPLY_USECACHE | MOD_APPLY_IGNORE_SIMPLIFY,
+ };
+ modwrap_deformVerts(md, &modifier_ctx, multires_mesh, deformed_verts, multires_mesh->totvert);
+ BKE_id_free(NULL, multires_mesh);
+ /* Reshaping */
+ bool result = multires_reshape_from_vertcos(
+ depsgraph, object, &highest_mmd, deformed_verts, num_deformed_verts, false);
+ /* Cleanup */
+ MEM_freeN(deformed_verts);
+ return result;
}
/* =============================================================================
@@ -1042,122 +948,109 @@ bool multiresModifier_reshapeFromDeformModifier(
*/
typedef struct ReshapeFromCCGTaskData {
- MultiresReshapeContext reshape_ctx;
- const CCGKey *key;
- /*const*/ CCGElem **grids;
+ MultiresReshapeContext reshape_ctx;
+ const CCGKey *key;
+ /*const*/ CCGElem **grids;
} ReshapeFromCCGTaskData;
-static void reshape_from_ccg_task(
- void *__restrict userdata,
- const int coarse_poly_index,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void reshape_from_ccg_task(void *__restrict userdata,
+ const int coarse_poly_index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- ReshapeFromCCGTaskData *data = userdata;
- const CCGKey *key = data->key;
- /*const*/ CCGElem **grids = data->grids;
- const Mesh *coarse_mesh = data->reshape_ctx.coarse_mesh;
- const MPoly *coarse_mpoly = coarse_mesh->mpoly;
- const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index];
- const int key_grid_size = key->grid_size;
- const int key_grid_size_1 = key_grid_size - 1;
- const int resolution = key_grid_size;
- const float resolution_1_inv = 1.0f / (float)(resolution - 1);
- const int start_ptex_face_index =
- data->reshape_ctx.face_ptex_offset[coarse_poly_index];
- const bool is_quad = (coarse_poly->totloop == 4);
- for (int corner = 0; corner < coarse_poly->totloop; corner++) {
- for (int y = 0; y < resolution; y++) {
- const float corner_v = y * resolution_1_inv;
- for (int x = 0; x < resolution; x++) {
- const float corner_u = x * resolution_1_inv;
- /* Quad faces consists of a single ptex face. */
- const int ptex_face_index =
- is_quad ? start_ptex_face_index
- : start_ptex_face_index + corner;
- float grid_u, grid_v;
- BKE_subdiv_ptex_face_uv_to_grid_uv(
- corner_u, corner_v, &grid_u, &grid_v);
- /*const*/ CCGElem *grid =
- grids[coarse_poly->loopstart + corner];
- /*const*/ CCGElem *grid_element = CCG_grid_elem(
- key,
- grid,
- key_grid_size_1 * grid_u,
- key_grid_size_1 * grid_v);
- const float *final_P = CCG_elem_co(key, grid_element);
- float final_mask = 0.0f;
- if (key->has_mask) {
- final_mask = *CCG_elem_mask(key, grid_element);
- }
- multires_reshape_vertex_from_final_data(
- &data->reshape_ctx,
- ptex_face_index,
- corner_u, corner_v,
- coarse_poly_index,
- corner,
- final_P, final_mask);
- }
- }
- }
+ ReshapeFromCCGTaskData *data = userdata;
+ const CCGKey *key = data->key;
+ /*const*/ CCGElem **grids = data->grids;
+ const Mesh *coarse_mesh = data->reshape_ctx.coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index];
+ const int key_grid_size = key->grid_size;
+ const int key_grid_size_1 = key_grid_size - 1;
+ const int resolution = key_grid_size;
+ const float resolution_1_inv = 1.0f / (float)(resolution - 1);
+ const int start_ptex_face_index = data->reshape_ctx.face_ptex_offset[coarse_poly_index];
+ const bool is_quad = (coarse_poly->totloop == 4);
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ for (int y = 0; y < resolution; y++) {
+ const float corner_v = y * resolution_1_inv;
+ for (int x = 0; x < resolution; x++) {
+ const float corner_u = x * resolution_1_inv;
+ /* Quad faces consists of a single ptex face. */
+ const int ptex_face_index = is_quad ? start_ptex_face_index :
+ start_ptex_face_index + corner;
+ float grid_u, grid_v;
+ BKE_subdiv_ptex_face_uv_to_grid_uv(corner_u, corner_v, &grid_u, &grid_v);
+ /*const*/ CCGElem *grid = grids[coarse_poly->loopstart + corner];
+ /*const*/ CCGElem *grid_element = CCG_grid_elem(
+ key, grid, key_grid_size_1 * grid_u, key_grid_size_1 * grid_v);
+ const float *final_P = CCG_elem_co(key, grid_element);
+ float final_mask = 0.0f;
+ if (key->has_mask) {
+ final_mask = *CCG_elem_mask(key, grid_element);
+ }
+ multires_reshape_vertex_from_final_data(&data->reshape_ctx,
+ ptex_face_index,
+ corner_u,
+ corner_v,
+ coarse_poly_index,
+ corner,
+ final_P,
+ final_mask);
+ }
+ }
+ }
}
-bool multiresModifier_reshapeFromCCG(
- const int tot_level,
- Mesh *coarse_mesh,
- SubdivCCG *subdiv_ccg)
+bool multiresModifier_reshapeFromCCG(const int tot_level, Mesh *coarse_mesh, SubdivCCG *subdiv_ccg)
{
- CCGKey key;
- BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
- /* Sanity checks. */
- if (coarse_mesh->totloop != subdiv_ccg->num_grids) {
- /* Grids are supposed to eb created for each face-cornder (aka loop). */
- return false;
- }
- MDisps *mdisps = CustomData_get_layer(&coarse_mesh->ldata, CD_MDISPS);
- if (mdisps == NULL) {
- /* Multires displacement has been removed before current changes were
- * applies to all the levels. */
- return false;
- }
- GridPaintMask *grid_paint_mask =
- CustomData_get_layer(&coarse_mesh->ldata, CD_GRID_PAINT_MASK);
- Subdiv *subdiv = subdiv_ccg->subdiv;
- /* Pick maximum between multires level and dispalcement level.
- * This is because mesh can be used by objects with multires at different
- * levels.
- *
- * TODO(sergey): At this point it should be possible to always use
- * mdisps->level. */
- const int top_level = max_ii(tot_level, mdisps->level);
- /* Make sure displacement grids are ready. */
- multires_reshape_ensure_grids(coarse_mesh, top_level);
- /* Construct context. */
- ReshapeFromCCGTaskData data = {
- .reshape_ctx = {
- .subdiv = subdiv,
- .coarse_mesh = coarse_mesh,
- .mdisps = mdisps,
- .grid_paint_mask = grid_paint_mask,
- .top_grid_size = BKE_subdiv_grid_size_from_level(top_level),
- .top_level = top_level,
- .face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv),
- },
- .key = &key,
- .grids = subdiv_ccg->grids,
- };
- /* Initialize propagation to higher levels. */
- MultiresPropagateData propagate_data;
- multires_reshape_propagate_prepare(
- &propagate_data, coarse_mesh, key.level, top_level);
- /* Threaded grids iteration. */
- ParallelRangeSettings parallel_range_settings;
- BLI_parallel_range_settings_defaults(&parallel_range_settings);
- BLI_task_parallel_range(0, coarse_mesh->totpoly,
- &data,
- reshape_from_ccg_task,
- &parallel_range_settings);
- /* Update higher levels if needed. */
- multires_reshape_propagate(&propagate_data);
- multires_reshape_propagate_free(&propagate_data);
- return true;
+ CCGKey key;
+ BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
+ /* Sanity checks. */
+ if (coarse_mesh->totloop != subdiv_ccg->num_grids) {
+ /* Grids are supposed to eb created for each face-cornder (aka loop). */
+ return false;
+ }
+ MDisps *mdisps = CustomData_get_layer(&coarse_mesh->ldata, CD_MDISPS);
+ if (mdisps == NULL) {
+ /* Multires displacement has been removed before current changes were
+ * applies to all the levels. */
+ return false;
+ }
+ GridPaintMask *grid_paint_mask = CustomData_get_layer(&coarse_mesh->ldata, CD_GRID_PAINT_MASK);
+ Subdiv *subdiv = subdiv_ccg->subdiv;
+ /* Pick maximum between multires level and dispalcement level.
+ * This is because mesh can be used by objects with multires at different
+ * levels.
+ *
+ * TODO(sergey): At this point it should be possible to always use
+ * mdisps->level. */
+ const int top_level = max_ii(tot_level, mdisps->level);
+ /* Make sure displacement grids are ready. */
+ multires_reshape_ensure_grids(coarse_mesh, top_level);
+ /* Construct context. */
+ ReshapeFromCCGTaskData data = {
+ .reshape_ctx =
+ {
+ .subdiv = subdiv,
+ .coarse_mesh = coarse_mesh,
+ .mdisps = mdisps,
+ .grid_paint_mask = grid_paint_mask,
+ .top_grid_size = BKE_subdiv_grid_size_from_level(top_level),
+ .top_level = top_level,
+ .face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv),
+ },
+ .key = &key,
+ .grids = subdiv_ccg->grids,
+ };
+ /* Initialize propagation to higher levels. */
+ MultiresPropagateData propagate_data;
+ multires_reshape_propagate_prepare(&propagate_data, coarse_mesh, key.level, top_level);
+ /* Threaded grids iteration. */
+ ParallelRangeSettings parallel_range_settings;
+ BLI_parallel_range_settings_defaults(&parallel_range_settings);
+ BLI_task_parallel_range(
+ 0, coarse_mesh->totpoly, &data, reshape_from_ccg_task, &parallel_range_settings);
+ /* Update higher levels if needed. */
+ multires_reshape_propagate(&propagate_data);
+ multires_reshape_propagate_free(&propagate_data);
+ return true;
}
diff --git a/source/blender/blenkernel/intern/multires_subdiv.c b/source/blender/blenkernel/intern/multires_subdiv.c
index 59229f28751..2ea02ab6974 100644
--- a/source/blender/blenkernel/intern/multires_subdiv.c
+++ b/source/blender/blenkernel/intern/multires_subdiv.c
@@ -34,30 +34,25 @@
#include "BKE_subdiv.h"
#include "BKE_subdiv_mesh.h"
-void BKE_multires_subdiv_settings_init(
- SubdivSettings *settings,
- const MultiresModifierData *mmd)
+void BKE_multires_subdiv_settings_init(SubdivSettings *settings, const MultiresModifierData *mmd)
{
- settings->is_simple = (mmd->simple != 0);
- settings->is_adaptive = true;
- settings->level = settings->is_simple ? 1 : mmd->quality;
- settings->use_creases = (mmd->flags & eMultiresModifierFlag_UseCrease);
- settings->vtx_boundary_interpolation = SUBDIV_VTX_BOUNDARY_EDGE_ONLY;
- settings->fvar_linear_interpolation =
- BKE_subdiv_fvar_interpolation_from_uv_smooth(mmd->uv_smooth);
+ settings->is_simple = (mmd->simple != 0);
+ settings->is_adaptive = true;
+ settings->level = settings->is_simple ? 1 : mmd->quality;
+ settings->use_creases = (mmd->flags & eMultiresModifierFlag_UseCrease);
+ settings->vtx_boundary_interpolation = SUBDIV_VTX_BOUNDARY_EDGE_ONLY;
+ settings->fvar_linear_interpolation = BKE_subdiv_fvar_interpolation_from_uv_smooth(
+ mmd->uv_smooth);
}
-void BKE_multires_subdiv_mesh_settings_init(
- SubdivToMeshSettings *mesh_settings,
- const Scene *scene,
- const Object *object,
- const MultiresModifierData *mmd,
- const bool use_render_params,
- const bool ignore_simplify)
+void BKE_multires_subdiv_mesh_settings_init(SubdivToMeshSettings *mesh_settings,
+ const Scene *scene,
+ const Object *object,
+ const MultiresModifierData *mmd,
+ const bool use_render_params,
+ const bool ignore_simplify)
{
- const int level = multires_get_level(
- scene, object, mmd, use_render_params, ignore_simplify);
- mesh_settings->resolution = (1 << level) + 1;
- mesh_settings->use_optimal_display =
- (mmd->flags & eMultiresModifierFlag_ControlEdges);
+ const int level = multires_get_level(scene, object, mmd, use_render_params, ignore_simplify);
+ mesh_settings->resolution = (1 << level) + 1;
+ mesh_settings->use_optimal_display = (mmd->flags & eMultiresModifierFlag_ControlEdges);
}
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index a2631840f41..3b33af62073 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -21,7 +21,6 @@
* \ingroup bke
*/
-
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
@@ -72,38 +71,38 @@ static CLG_LogRef LOG = {"bke.nla"};
*/
void BKE_nlastrip_free(ListBase *strips, NlaStrip *strip, bool do_id_user)
{
- NlaStrip *cs, *csn;
-
- /* sanity checks */
- if (strip == NULL)
- return;
-
- /* free child-strips */
- for (cs = strip->strips.first; cs; cs = csn) {
- csn = cs->next;
- BKE_nlastrip_free(&strip->strips, cs, do_id_user);
- }
-
- /* remove reference to action */
- if (strip->act != NULL && do_id_user) {
- id_us_min(&strip->act->id);
- }
-
- /* free remapping info */
- //if (strip->remap)
- // BKE_animremap_free();
-
- /* free own F-Curves */
- free_fcurves(&strip->fcurves);
-
- /* free own F-Modifiers */
- free_fmodifiers(&strip->modifiers);
-
- /* free the strip itself */
- if (strips)
- BLI_freelinkN(strips, strip);
- else
- MEM_freeN(strip);
+ NlaStrip *cs, *csn;
+
+ /* sanity checks */
+ if (strip == NULL)
+ return;
+
+ /* free child-strips */
+ for (cs = strip->strips.first; cs; cs = csn) {
+ csn = cs->next;
+ BKE_nlastrip_free(&strip->strips, cs, do_id_user);
+ }
+
+ /* remove reference to action */
+ if (strip->act != NULL && do_id_user) {
+ id_us_min(&strip->act->id);
+ }
+
+ /* free remapping info */
+ //if (strip->remap)
+ // BKE_animremap_free();
+
+ /* free own F-Curves */
+ free_fcurves(&strip->fcurves);
+
+ /* free own F-Modifiers */
+ free_fmodifiers(&strip->modifiers);
+
+ /* free the strip itself */
+ if (strips)
+ BLI_freelinkN(strips, strip);
+ else
+ MEM_freeN(strip);
}
/* Remove the given NLA track from the set of NLA tracks, free the track's data,
@@ -111,23 +110,23 @@ void BKE_nlastrip_free(ListBase *strips, NlaStrip *strip, bool do_id_user)
*/
void BKE_nlatrack_free(ListBase *tracks, NlaTrack *nlt, bool do_id_user)
{
- NlaStrip *strip, *stripn;
-
- /* sanity checks */
- if (nlt == NULL)
- return;
-
- /* free strips */
- for (strip = nlt->strips.first; strip; strip = stripn) {
- stripn = strip->next;
- BKE_nlastrip_free(&nlt->strips, strip, do_id_user);
- }
-
- /* free NLA track itself now */
- if (tracks)
- BLI_freelinkN(tracks, nlt);
- else
- MEM_freeN(nlt);
+ NlaStrip *strip, *stripn;
+
+ /* sanity checks */
+ if (nlt == NULL)
+ return;
+
+ /* free strips */
+ for (strip = nlt->strips.first; strip; strip = stripn) {
+ stripn = strip->next;
+ BKE_nlastrip_free(&nlt->strips, strip, do_id_user);
+ }
+
+ /* free NLA track itself now */
+ if (tracks)
+ BLI_freelinkN(tracks, nlt);
+ else
+ MEM_freeN(nlt);
}
/* Free the elements of type NLA Tracks provided in the given list, but do not free
@@ -135,20 +134,20 @@ void BKE_nlatrack_free(ListBase *tracks, NlaTrack *nlt, bool do_id_user)
*/
void BKE_nla_tracks_free(ListBase *tracks, bool do_id_user)
{
- NlaTrack *nlt, *nltn;
+ NlaTrack *nlt, *nltn;
- /* sanity checks */
- if (ELEM(NULL, tracks, tracks->first))
- return;
+ /* sanity checks */
+ if (ELEM(NULL, tracks, tracks->first))
+ return;
- /* free tracks one by one */
- for (nlt = tracks->first; nlt; nlt = nltn) {
- nltn = nlt->next;
- BKE_nlatrack_free(tracks, nlt, do_id_user);
- }
+ /* free tracks one by one */
+ for (nlt = tracks->first; nlt; nlt = nltn) {
+ nltn = nlt->next;
+ BKE_nlatrack_free(tracks, nlt, do_id_user);
+ }
- /* clear the list's pointers to be safe */
- BLI_listbase_clear(tracks);
+ /* clear the list's pointers to be safe */
+ BLI_listbase_clear(tracks);
}
/* Copying ------------------------------------------- */
@@ -159,78 +158,84 @@ void BKE_nla_tracks_free(ListBase *tracks, bool do_id_user)
* \param use_same_action: When true, the existing action is used (instead of being duplicated)
* \param flag: Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_library.h
*/
-NlaStrip *BKE_nlastrip_copy(Main *bmain, NlaStrip *strip, const bool use_same_action, const int flag)
+NlaStrip *BKE_nlastrip_copy(Main *bmain,
+ NlaStrip *strip,
+ const bool use_same_action,
+ const int flag)
{
- NlaStrip *strip_d;
- NlaStrip *cs, *cs_d;
-
- const bool do_id_user = (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0;
-
- /* sanity check */
- if (strip == NULL)
- return NULL;
-
- /* make a copy */
- strip_d = MEM_dupallocN(strip);
- strip_d->next = strip_d->prev = NULL;
-
- /* handle action */
- if (strip_d->act) {
- if (use_same_action) {
- if (do_id_user) {
- /* increase user-count of action */
- id_us_plus(&strip_d->act->id);
- }
- }
- else {
- /* use a copy of the action instead (user count shouldn't have changed yet) */
- BKE_id_copy_ex(bmain, &strip_d->act->id, (ID **)&strip_d->act, flag);
- }
- }
-
- /* copy F-Curves and modifiers */
- copy_fcurves(&strip_d->fcurves, &strip->fcurves);
- copy_fmodifiers(&strip_d->modifiers, &strip->modifiers);
-
- /* make a copy of all the child-strips, one at a time */
- BLI_listbase_clear(&strip_d->strips);
-
- for (cs = strip->strips.first; cs; cs = cs->next) {
- cs_d = BKE_nlastrip_copy(bmain, cs, use_same_action, flag);
- BLI_addtail(&strip_d->strips, cs_d);
- }
-
- /* return the strip */
- return strip_d;
+ NlaStrip *strip_d;
+ NlaStrip *cs, *cs_d;
+
+ const bool do_id_user = (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0;
+
+ /* sanity check */
+ if (strip == NULL)
+ return NULL;
+
+ /* make a copy */
+ strip_d = MEM_dupallocN(strip);
+ strip_d->next = strip_d->prev = NULL;
+
+ /* handle action */
+ if (strip_d->act) {
+ if (use_same_action) {
+ if (do_id_user) {
+ /* increase user-count of action */
+ id_us_plus(&strip_d->act->id);
+ }
+ }
+ else {
+ /* use a copy of the action instead (user count shouldn't have changed yet) */
+ BKE_id_copy_ex(bmain, &strip_d->act->id, (ID **)&strip_d->act, flag);
+ }
+ }
+
+ /* copy F-Curves and modifiers */
+ copy_fcurves(&strip_d->fcurves, &strip->fcurves);
+ copy_fmodifiers(&strip_d->modifiers, &strip->modifiers);
+
+ /* make a copy of all the child-strips, one at a time */
+ BLI_listbase_clear(&strip_d->strips);
+
+ for (cs = strip->strips.first; cs; cs = cs->next) {
+ cs_d = BKE_nlastrip_copy(bmain, cs, use_same_action, flag);
+ BLI_addtail(&strip_d->strips, cs_d);
+ }
+
+ /* return the strip */
+ return strip_d;
}
/**
* Copy a single NLA Track.
* \param flag: Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_library.h
*/
-NlaTrack *BKE_nlatrack_copy(Main *bmain, NlaTrack *nlt, const bool use_same_actions, const int flag)
+NlaTrack *BKE_nlatrack_copy(Main *bmain,
+ NlaTrack *nlt,
+ const bool use_same_actions,
+ const int flag)
{
- NlaStrip *strip, *strip_d;
- NlaTrack *nlt_d;
+ NlaStrip *strip, *strip_d;
+ NlaTrack *nlt_d;
- /* sanity check */
- if (nlt == NULL)
- return NULL;
+ /* sanity check */
+ if (nlt == NULL)
+ return NULL;
- /* make a copy */
- nlt_d = MEM_dupallocN(nlt);
- nlt_d->next = nlt_d->prev = NULL;
+ /* make a copy */
+ nlt_d = MEM_dupallocN(nlt);
+ nlt_d->next = nlt_d->prev = NULL;
- /* make a copy of all the strips, one at a time */
- BLI_listbase_clear(&nlt_d->strips);
+ /* make a copy of all the strips, one at a time */
+ BLI_listbase_clear(&nlt_d->strips);
- for (strip = nlt->strips.first; strip; strip = strip->next) {
- strip_d = BKE_nlastrip_copy(bmain, strip, use_same_actions, flag);
- BLI_addtail(&nlt_d->strips, strip_d);
- }
+ for (strip = nlt->strips.first; strip; strip = strip->next) {
+ strip_d = BKE_nlastrip_copy(bmain, strip, use_same_actions, flag);
+ BLI_addtail(&nlt_d->strips, strip_d);
+ }
- /* return the copy */
- return nlt_d;
+ /* return the copy */
+ return nlt_d;
}
/**
@@ -239,22 +244,22 @@ NlaTrack *BKE_nlatrack_copy(Main *bmain, NlaTrack *nlt, const bool use_same_acti
*/
void BKE_nla_tracks_copy(Main *bmain, ListBase *dst, ListBase *src, const int flag)
{
- NlaTrack *nlt, *nlt_d;
-
- /* sanity checks */
- if (ELEM(NULL, dst, src))
- return;
-
- /* clear out the destination list first for precautions... */
- BLI_listbase_clear(dst);
-
- /* copy each NLA-track, one at a time */
- for (nlt = src->first; nlt; nlt = nlt->next) {
- /* make a copy, and add the copy to the destination list */
- // XXX: we need to fix this sometime
- nlt_d = BKE_nlatrack_copy(bmain, nlt, true, flag);
- BLI_addtail(dst, nlt_d);
- }
+ NlaTrack *nlt, *nlt_d;
+
+ /* sanity checks */
+ if (ELEM(NULL, dst, src))
+ return;
+
+ /* clear out the destination list first for precautions... */
+ BLI_listbase_clear(dst);
+
+ /* copy each NLA-track, one at a time */
+ for (nlt = src->first; nlt; nlt = nlt->next) {
+ /* make a copy, and add the copy to the destination list */
+ // XXX: we need to fix this sometime
+ nlt_d = BKE_nlatrack_copy(bmain, nlt, true, flag);
+ BLI_addtail(dst, nlt_d);
+ }
}
/* Adding ------------------------------------------- */
@@ -264,141 +269,143 @@ void BKE_nla_tracks_copy(Main *bmain, ListBase *dst, ListBase *src, const int fl
*/
NlaTrack *BKE_nlatrack_add(AnimData *adt, NlaTrack *prev)
{
- NlaTrack *nlt;
+ NlaTrack *nlt;
- /* sanity checks */
- if (adt == NULL)
- return NULL;
+ /* sanity checks */
+ if (adt == NULL)
+ return NULL;
- /* allocate new track */
- nlt = MEM_callocN(sizeof(NlaTrack), "NlaTrack");
+ /* allocate new track */
+ nlt = MEM_callocN(sizeof(NlaTrack), "NlaTrack");
- /* set settings requiring the track to not be part of the stack yet */
- nlt->flag = NLATRACK_SELECTED;
- nlt->index = BLI_listbase_count(&adt->nla_tracks);
+ /* set settings requiring the track to not be part of the stack yet */
+ nlt->flag = NLATRACK_SELECTED;
+ nlt->index = BLI_listbase_count(&adt->nla_tracks);
- /* add track to stack, and make it the active one */
- if (prev)
- BLI_insertlinkafter(&adt->nla_tracks, prev, nlt);
- else
- BLI_addtail(&adt->nla_tracks, nlt);
- BKE_nlatrack_set_active(&adt->nla_tracks, nlt);
+ /* add track to stack, and make it the active one */
+ if (prev)
+ BLI_insertlinkafter(&adt->nla_tracks, prev, nlt);
+ else
+ BLI_addtail(&adt->nla_tracks, nlt);
+ BKE_nlatrack_set_active(&adt->nla_tracks, nlt);
- /* must have unique name, but we need to seed this */
- strcpy(nlt->name, "NlaTrack");
- BLI_uniquename(&adt->nla_tracks, nlt, DATA_("NlaTrack"), '.', offsetof(NlaTrack, name), sizeof(nlt->name));
+ /* must have unique name, but we need to seed this */
+ strcpy(nlt->name, "NlaTrack");
+ BLI_uniquename(
+ &adt->nla_tracks, nlt, DATA_("NlaTrack"), '.', offsetof(NlaTrack, name), sizeof(nlt->name));
- /* return the new track */
- return nlt;
+ /* return the new track */
+ return nlt;
}
/* Create a NLA Strip referencing the given Action */
NlaStrip *BKE_nlastrip_new(bAction *act)
{
- NlaStrip *strip;
-
- /* sanity checks */
- if (act == NULL)
- return NULL;
-
- /* allocate new strip */
- strip = MEM_callocN(sizeof(NlaStrip), "NlaStrip");
-
- /* generic settings
- * - selected flag to highlight this to the user
- * - (XXX) disabled Auto-Blends, as this was often causing some unwanted effects
- * - (XXX) synchronization of strip-length in accordance with changes to action-length
- * is not done though, since this should only really happens in editmode for strips now
- * though this decision is still subject to further review...
- */
- strip->flag = NLASTRIP_FLAG_SELECT;
-
- /* assign the action reference */
- strip->act = act;
- id_us_plus(&act->id);
-
- /* determine initial range
- * - strip length cannot be 0... ever...
- */
- calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
-
- strip->start = strip->actstart;
- strip->end = (IS_EQF(strip->actstart, strip->actend)) ? (strip->actstart + 1.0f) : (strip->actend);
-
- /* strip should be referenced as-is */
- strip->scale = 1.0f;
- strip->repeat = 1.0f;
-
- /* return the new strip */
- return strip;
+ NlaStrip *strip;
+
+ /* sanity checks */
+ if (act == NULL)
+ return NULL;
+
+ /* allocate new strip */
+ strip = MEM_callocN(sizeof(NlaStrip), "NlaStrip");
+
+ /* generic settings
+ * - selected flag to highlight this to the user
+ * - (XXX) disabled Auto-Blends, as this was often causing some unwanted effects
+ * - (XXX) synchronization of strip-length in accordance with changes to action-length
+ * is not done though, since this should only really happens in editmode for strips now
+ * though this decision is still subject to further review...
+ */
+ strip->flag = NLASTRIP_FLAG_SELECT;
+
+ /* assign the action reference */
+ strip->act = act;
+ id_us_plus(&act->id);
+
+ /* determine initial range
+ * - strip length cannot be 0... ever...
+ */
+ calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
+
+ strip->start = strip->actstart;
+ strip->end = (IS_EQF(strip->actstart, strip->actend)) ? (strip->actstart + 1.0f) :
+ (strip->actend);
+
+ /* strip should be referenced as-is */
+ strip->scale = 1.0f;
+ strip->repeat = 1.0f;
+
+ /* return the new strip */
+ return strip;
}
/* Add new NLA-strip to the top of the NLA stack - i.e. into the last track if space, or a new one otherwise */
NlaStrip *BKE_nlastack_add_strip(AnimData *adt, bAction *act)
{
- NlaStrip *strip;
- NlaTrack *nlt;
-
- /* sanity checks */
- if (ELEM(NULL, adt, act))
- return NULL;
-
- /* create a new NLA strip */
- strip = BKE_nlastrip_new(act);
- if (strip == NULL)
- return NULL;
-
- /* firstly try adding strip to last track, but if that fails, add to a new track */
- if (BKE_nlatrack_add_strip(adt->nla_tracks.last, strip) == 0) {
- /* trying to add to the last track failed (no track or no space),
- * so add a new track to the stack, and add to that...
- */
- nlt = BKE_nlatrack_add(adt, NULL);
- BKE_nlatrack_add_strip(nlt, strip);
- }
-
- /* automatically name it too */
- BKE_nlastrip_validate_name(adt, strip);
-
- /* returns the strip added */
- return strip;
+ NlaStrip *strip;
+ NlaTrack *nlt;
+
+ /* sanity checks */
+ if (ELEM(NULL, adt, act))
+ return NULL;
+
+ /* create a new NLA strip */
+ strip = BKE_nlastrip_new(act);
+ if (strip == NULL)
+ return NULL;
+
+ /* firstly try adding strip to last track, but if that fails, add to a new track */
+ if (BKE_nlatrack_add_strip(adt->nla_tracks.last, strip) == 0) {
+ /* trying to add to the last track failed (no track or no space),
+ * so add a new track to the stack, and add to that...
+ */
+ nlt = BKE_nlatrack_add(adt, NULL);
+ BKE_nlatrack_add_strip(nlt, strip);
+ }
+
+ /* automatically name it too */
+ BKE_nlastrip_validate_name(adt, strip);
+
+ /* returns the strip added */
+ return strip;
}
/* Add a NLA Strip referencing the given speaker's sound */
NlaStrip *BKE_nla_add_soundstrip(Scene *scene, Speaker *speaker)
{
- NlaStrip *strip = MEM_callocN(sizeof(NlaStrip), "NlaSoundStrip");
+ NlaStrip *strip = MEM_callocN(sizeof(NlaStrip), "NlaSoundStrip");
- /* if speaker has a sound, set the strip length to the length of the sound,
- * otherwise default to length of 10 frames
- */
+ /* if speaker has a sound, set the strip length to the length of the sound,
+ * otherwise default to length of 10 frames
+ */
#ifdef WITH_AUDASPACE
- if (speaker->sound) {
- AUD_SoundInfo info = AUD_getInfo(speaker->sound->playback_handle);
+ if (speaker->sound) {
+ AUD_SoundInfo info = AUD_getInfo(speaker->sound->playback_handle);
- strip->end = (float)ceil((double)info.length * FPS);
- }
- else
+ strip->end = (float)ceil((double)info.length * FPS);
+ }
+ else
#endif
- {
- strip->end = 10.0f;
- /* quiet compiler warnings */
- (void)scene;
- (void)speaker;
- }
+ {
+ strip->end = 10.0f;
+ /* quiet compiler warnings */
+ (void)scene;
+ (void)speaker;
+ }
- /* general settings */
- strip->type = NLASTRIP_TYPE_SOUND;
+ /* general settings */
+ strip->type = NLASTRIP_TYPE_SOUND;
- strip->flag = NLASTRIP_FLAG_SELECT;
- strip->extendmode = NLASTRIP_EXTEND_NOTHING; /* nothing to extend... */
+ strip->flag = NLASTRIP_FLAG_SELECT;
+ strip->extendmode = NLASTRIP_EXTEND_NOTHING; /* nothing to extend... */
- /* strip should be referenced as-is */
- strip->scale = 1.0f;
- strip->repeat = 1.0f;
+ /* strip should be referenced as-is */
+ strip->scale = 1.0f;
+ strip->repeat = 1.0f;
- /* return this strip */
- return strip;
+ /* return this strip */
+ return strip;
}
/* *************************************************** */
@@ -411,69 +418,73 @@ NlaStrip *BKE_nla_add_soundstrip(Scene *scene, Speaker *speaker)
*/
static float nlastrip_get_frame_actionclip(NlaStrip *strip, float cframe, short mode)
{
- float actlength, scale;
- // float repeat; // UNUSED
-
- /* get number of repeats */
- if (IS_EQF(strip->repeat, 0.0f)) strip->repeat = 1.0f;
- // repeat = strip->repeat; // UNUSED
-
- /* scaling */
- if (IS_EQF(strip->scale, 0.0f)) strip->scale = 1.0f;
- scale = fabsf(strip->scale); /* scale must be positive - we've got a special flag for reversing */
-
- /* length of referenced action */
- actlength = strip->actend - strip->actstart;
- if (IS_EQF(actlength, 0.0f)) actlength = 1.0f;
-
- /* reversed = play strip backwards */
- if (strip->flag & NLASTRIP_FLAG_REVERSE) {
- /* FIXME: this won't work right with Graph Editor? */
- if (mode == NLATIME_CONVERT_MAP) {
- return strip->end - scale * (cframe - strip->actstart);
- }
- else if (mode == NLATIME_CONVERT_UNMAP) {
- return (strip->end + (strip->actstart * scale - cframe)) / scale;
- }
- else { /* if (mode == NLATIME_CONVERT_EVAL) */
- if (IS_EQF((float)cframe, strip->end) && IS_EQF(strip->repeat, floorf(strip->repeat))) {
- /* this case prevents the motion snapping back to the first frame at the end of the strip
- * by catching the case where repeats is a whole number, which means that the end of the strip
- * could also be interpreted as the end of the start of a repeat
- */
- return strip->actstart;
- }
- else {
- /* - the 'fmod(..., actlength * scale)' is needed to get the repeats working
- * - the '/ scale' is needed to ensure that scaling influences the timing within the repeat
- */
- return strip->actend - fmodf(cframe - strip->start, actlength * scale) / scale;
- }
- }
- }
- else {
- if (mode == NLATIME_CONVERT_MAP) {
- return strip->start + scale * (cframe - strip->actstart);
- }
- else if (mode == NLATIME_CONVERT_UNMAP) {
- return strip->actstart + (cframe - strip->start) / scale;
- }
- else { /* if (mode == NLATIME_CONVERT_EVAL) */
- if (IS_EQF(cframe, strip->end) && IS_EQF(strip->repeat, floorf(strip->repeat))) {
- /* this case prevents the motion snapping back to the first frame at the end of the strip
- * by catching the case where repeats is a whole number, which means that the end of the strip
- * could also be interpreted as the end of the start of a repeat
- */
- return strip->actend;
- }
- else {
- /* - the 'fmod(..., actlength * scale)' is needed to get the repeats working
- * - the '/ scale' is needed to ensure that scaling influences the timing within the repeat
- */
- return strip->actstart + fmodf(cframe - strip->start, actlength * scale) / scale;
- }
- }
- }
+ float actlength, scale;
+ // float repeat; // UNUSED
+
+ /* get number of repeats */
+ if (IS_EQF(strip->repeat, 0.0f))
+ strip->repeat = 1.0f;
+ // repeat = strip->repeat; // UNUSED
+
+ /* scaling */
+ if (IS_EQF(strip->scale, 0.0f))
+ strip->scale = 1.0f;
+ scale = fabsf(
+ strip->scale); /* scale must be positive - we've got a special flag for reversing */
+
+ /* length of referenced action */
+ actlength = strip->actend - strip->actstart;
+ if (IS_EQF(actlength, 0.0f))
+ actlength = 1.0f;
+
+ /* reversed = play strip backwards */
+ if (strip->flag & NLASTRIP_FLAG_REVERSE) {
+ /* FIXME: this won't work right with Graph Editor? */
+ if (mode == NLATIME_CONVERT_MAP) {
+ return strip->end - scale * (cframe - strip->actstart);
+ }
+ else if (mode == NLATIME_CONVERT_UNMAP) {
+ return (strip->end + (strip->actstart * scale - cframe)) / scale;
+ }
+ else { /* if (mode == NLATIME_CONVERT_EVAL) */
+ if (IS_EQF((float)cframe, strip->end) && IS_EQF(strip->repeat, floorf(strip->repeat))) {
+ /* this case prevents the motion snapping back to the first frame at the end of the strip
+ * by catching the case where repeats is a whole number, which means that the end of the strip
+ * could also be interpreted as the end of the start of a repeat
+ */
+ return strip->actstart;
+ }
+ else {
+ /* - the 'fmod(..., actlength * scale)' is needed to get the repeats working
+ * - the '/ scale' is needed to ensure that scaling influences the timing within the repeat
+ */
+ return strip->actend - fmodf(cframe - strip->start, actlength * scale) / scale;
+ }
+ }
+ }
+ else {
+ if (mode == NLATIME_CONVERT_MAP) {
+ return strip->start + scale * (cframe - strip->actstart);
+ }
+ else if (mode == NLATIME_CONVERT_UNMAP) {
+ return strip->actstart + (cframe - strip->start) / scale;
+ }
+ else { /* if (mode == NLATIME_CONVERT_EVAL) */
+ if (IS_EQF(cframe, strip->end) && IS_EQF(strip->repeat, floorf(strip->repeat))) {
+ /* this case prevents the motion snapping back to the first frame at the end of the strip
+ * by catching the case where repeats is a whole number, which means that the end of the strip
+ * could also be interpreted as the end of the start of a repeat
+ */
+ return strip->actend;
+ }
+ else {
+ /* - the 'fmod(..., actlength * scale)' is needed to get the repeats working
+ * - the '/ scale' is needed to ensure that scaling influences the timing within the repeat
+ */
+ return strip->actstart + fmodf(cframe - strip->start, actlength * scale) / scale;
+ }
+ }
+ }
}
/* non clipped mapping for strip-time <-> global time (for Transitions)
@@ -481,24 +492,24 @@ static float nlastrip_get_frame_actionclip(NlaStrip *strip, float cframe, short
*/
static float nlastrip_get_frame_transition(NlaStrip *strip, float cframe, short mode)
{
- float length;
-
- /* length of strip */
- length = strip->end - strip->start;
-
- /* reversed = play strip backwards */
- if (strip->flag & NLASTRIP_FLAG_REVERSE) {
- if (mode == NLATIME_CONVERT_MAP)
- return strip->end - (length * cframe);
- else
- return (strip->end - cframe) / length;
- }
- else {
- if (mode == NLATIME_CONVERT_MAP)
- return (length * cframe) + strip->start;
- else
- return (cframe - strip->start) / length;
- }
+ float length;
+
+ /* length of strip */
+ length = strip->end - strip->start;
+
+ /* reversed = play strip backwards */
+ if (strip->flag & NLASTRIP_FLAG_REVERSE) {
+ if (mode == NLATIME_CONVERT_MAP)
+ return strip->end - (length * cframe);
+ else
+ return (strip->end - cframe) / length;
+ }
+ else {
+ if (mode == NLATIME_CONVERT_MAP)
+ return (length * cframe) + strip->start;
+ else
+ return (cframe - strip->start) / length;
+ }
}
/* non clipped mapping for strip-time <-> global time
@@ -509,18 +520,17 @@ static float nlastrip_get_frame_transition(NlaStrip *strip, float cframe, short
*/
float nlastrip_get_frame(NlaStrip *strip, float cframe, short mode)
{
- switch (strip->type) {
- case NLASTRIP_TYPE_META: /* meta - for now, does the same as transition (is really just an empty container) */
- case NLASTRIP_TYPE_TRANSITION: /* transition */
- return nlastrip_get_frame_transition(strip, cframe, mode);
-
- case NLASTRIP_TYPE_CLIP: /* action-clip (default) */
- default:
- return nlastrip_get_frame_actionclip(strip, cframe, mode);
- }
+ switch (strip->type) {
+ case NLASTRIP_TYPE_META: /* meta - for now, does the same as transition (is really just an empty container) */
+ case NLASTRIP_TYPE_TRANSITION: /* transition */
+ return nlastrip_get_frame_transition(strip, cframe, mode);
+
+ case NLASTRIP_TYPE_CLIP: /* action-clip (default) */
+ default:
+ return nlastrip_get_frame_actionclip(strip, cframe, mode);
+ }
}
-
/* Non clipped mapping for strip-time <-> global time
* mode = eNlaTime_ConvertModes -> NLATIME_CONVERT_*
*
@@ -529,40 +539,40 @@ float nlastrip_get_frame(NlaStrip *strip, float cframe, short mode)
*/
float BKE_nla_tweakedit_remap(AnimData *adt, float cframe, short mode)
{
- NlaStrip *strip;
-
- /* sanity checks
- * - obviously we've got to have some starting data
- * - when not in tweakmode, the active Action does not have any scaling applied :)
- * - when in tweakmode, if the no-mapping flag is set, do not map
- */
- if ((adt == NULL) || (adt->flag & ADT_NLA_EDIT_ON) == 0 || (adt->flag & ADT_NLA_EDIT_NOMAP))
- return cframe;
-
- /* if the active-strip info has been stored already, access this, otherwise look this up
- * and store for (very probable) future usage
- */
- if (adt->act_track == NULL) {
- if (adt->actstrip)
- adt->act_track = BKE_nlatrack_find_tweaked(adt);
- else
- adt->act_track = BKE_nlatrack_find_active(&adt->nla_tracks);
- }
- if (adt->actstrip == NULL) {
- adt->actstrip = BKE_nlastrip_find_active(adt->act_track);
- }
- strip = adt->actstrip;
-
- /* sanity checks
- * - in rare cases, we may not be able to find this strip for some reason (internal error)
- * - for now, if the user has defined a curve to control the time, this correction cannot be performed
- * reliably...
- */
- if ((strip == NULL) || (strip->flag & NLASTRIP_FLAG_USR_TIME))
- return cframe;
-
- /* perform the correction now... */
- return nlastrip_get_frame(strip, cframe, mode);
+ NlaStrip *strip;
+
+ /* sanity checks
+ * - obviously we've got to have some starting data
+ * - when not in tweakmode, the active Action does not have any scaling applied :)
+ * - when in tweakmode, if the no-mapping flag is set, do not map
+ */
+ if ((adt == NULL) || (adt->flag & ADT_NLA_EDIT_ON) == 0 || (adt->flag & ADT_NLA_EDIT_NOMAP))
+ return cframe;
+
+ /* if the active-strip info has been stored already, access this, otherwise look this up
+ * and store for (very probable) future usage
+ */
+ if (adt->act_track == NULL) {
+ if (adt->actstrip)
+ adt->act_track = BKE_nlatrack_find_tweaked(adt);
+ else
+ adt->act_track = BKE_nlatrack_find_active(&adt->nla_tracks);
+ }
+ if (adt->actstrip == NULL) {
+ adt->actstrip = BKE_nlastrip_find_active(adt->act_track);
+ }
+ strip = adt->actstrip;
+
+ /* sanity checks
+ * - in rare cases, we may not be able to find this strip for some reason (internal error)
+ * - for now, if the user has defined a curve to control the time, this correction cannot be performed
+ * reliably...
+ */
+ if ((strip == NULL) || (strip->flag & NLASTRIP_FLAG_USR_TIME))
+ return cframe;
+
+ /* perform the correction now... */
+ return nlastrip_get_frame(strip, cframe, mode);
}
/* *************************************************** */
@@ -574,33 +584,33 @@ float BKE_nla_tweakedit_remap(AnimData *adt, float cframe, short mode)
/* Check if there is any space in the given list to add the given strip */
bool BKE_nlastrips_has_space(ListBase *strips, float start, float end)
{
- NlaStrip *strip;
-
- /* sanity checks */
- if ((strips == NULL) || IS_EQF(start, end))
- return false;
- if (start > end) {
- puts("BKE_nlastrips_has_space() error... start and end arguments swapped");
- SWAP(float, start, end);
- }
-
- /* loop over NLA strips checking for any overlaps with this area... */
- for (strip = strips->first; strip; strip = strip->next) {
- /* if start frame of strip is past the target end-frame, that means that
- * we've gone past the window we need to check for, so things are fine
- */
- if (strip->start >= end)
- return true;
-
- /* if the end of the strip is greater than either of the boundaries, the range
- * must fall within the extents of the strip
- */
- if ((strip->end > start) || (strip->end > end))
- return false;
- }
-
- /* if we are still here, we haven't encountered any overlapping strips */
- return true;
+ NlaStrip *strip;
+
+ /* sanity checks */
+ if ((strips == NULL) || IS_EQF(start, end))
+ return false;
+ if (start > end) {
+ puts("BKE_nlastrips_has_space() error... start and end arguments swapped");
+ SWAP(float, start, end);
+ }
+
+ /* loop over NLA strips checking for any overlaps with this area... */
+ for (strip = strips->first; strip; strip = strip->next) {
+ /* if start frame of strip is past the target end-frame, that means that
+ * we've gone past the window we need to check for, so things are fine
+ */
+ if (strip->start >= end)
+ return true;
+
+ /* if the end of the strip is greater than either of the boundaries, the range
+ * must fall within the extents of the strip
+ */
+ if ((strip->end > start) || (strip->end > end))
+ return false;
+ }
+
+ /* if we are still here, we haven't encountered any overlapping strips */
+ return true;
}
/* Rearrange the strips in the track so that they are always in order
@@ -608,43 +618,43 @@ bool BKE_nlastrips_has_space(ListBase *strips, float start, float end)
*/
void BKE_nlastrips_sort_strips(ListBase *strips)
{
- ListBase tmp = {NULL, NULL};
- NlaStrip *strip, *sstrip, *stripn;
-
- /* sanity checks */
- if (ELEM(NULL, strips, strips->first))
- return;
-
- /* we simply perform insertion sort on this list, since it is assumed that per track,
- * there are only likely to be at most 5-10 strips
- */
- for (strip = strips->first; strip; strip = stripn) {
- short not_added = 1;
-
- stripn = strip->next;
-
- /* remove this strip from the list, and add it to the new list, searching from the end of
- * the list, assuming that the lists are in order
- */
- BLI_remlink(strips, strip);
-
- for (sstrip = tmp.last; sstrip; sstrip = sstrip->prev) {
- /* check if add after */
- if (sstrip->end <= strip->start) {
- BLI_insertlinkafter(&tmp, sstrip, strip);
- not_added = 0;
- break;
- }
- }
-
- /* add before first? */
- if (not_added)
- BLI_addhead(&tmp, strip);
- }
-
- /* reassign the start and end points of the strips */
- strips->first = tmp.first;
- strips->last = tmp.last;
+ ListBase tmp = {NULL, NULL};
+ NlaStrip *strip, *sstrip, *stripn;
+
+ /* sanity checks */
+ if (ELEM(NULL, strips, strips->first))
+ return;
+
+ /* we simply perform insertion sort on this list, since it is assumed that per track,
+ * there are only likely to be at most 5-10 strips
+ */
+ for (strip = strips->first; strip; strip = stripn) {
+ short not_added = 1;
+
+ stripn = strip->next;
+
+ /* remove this strip from the list, and add it to the new list, searching from the end of
+ * the list, assuming that the lists are in order
+ */
+ BLI_remlink(strips, strip);
+
+ for (sstrip = tmp.last; sstrip; sstrip = sstrip->prev) {
+ /* check if add after */
+ if (sstrip->end <= strip->start) {
+ BLI_insertlinkafter(&tmp, sstrip, strip);
+ not_added = 0;
+ break;
+ }
+ }
+
+ /* add before first? */
+ if (not_added)
+ BLI_addhead(&tmp, strip);
+ }
+
+ /* reassign the start and end points of the strips */
+ strips->first = tmp.first;
+ strips->last = tmp.last;
}
/* Add the given NLA-Strip to the given list of strips, assuming that it
@@ -652,36 +662,35 @@ void BKE_nlastrips_sort_strips(ListBase *strips)
*/
bool BKE_nlastrips_add_strip(ListBase *strips, NlaStrip *strip)
{
- NlaStrip *ns;
- bool not_added = true;
-
- /* sanity checks */
- if (ELEM(NULL, strips, strip))
- return false;
-
- /* check if any space to add */
- if (BKE_nlastrips_has_space(strips, strip->start, strip->end) == 0)
- return false;
-
- /* find the right place to add the strip to the nominated track */
- for (ns = strips->first; ns; ns = ns->next) {
- /* if current strip occurs after the new strip, add it before */
- if (ns->start >= strip->end) {
- BLI_insertlinkbefore(strips, ns, strip);
- not_added = 0;
- break;
- }
- }
- if (not_added) {
- /* just add to the end of the list of the strips then... */
- BLI_addtail(strips, strip);
- }
-
- /* added... */
- return true;
+ NlaStrip *ns;
+ bool not_added = true;
+
+ /* sanity checks */
+ if (ELEM(NULL, strips, strip))
+ return false;
+
+ /* check if any space to add */
+ if (BKE_nlastrips_has_space(strips, strip->start, strip->end) == 0)
+ return false;
+
+ /* find the right place to add the strip to the nominated track */
+ for (ns = strips->first; ns; ns = ns->next) {
+ /* if current strip occurs after the new strip, add it before */
+ if (ns->start >= strip->end) {
+ BLI_insertlinkbefore(strips, ns, strip);
+ not_added = 0;
+ break;
+ }
+ }
+ if (not_added) {
+ /* just add to the end of the list of the strips then... */
+ BLI_addtail(strips, strip);
+ }
+
+ /* added... */
+ return true;
}
-
/* Meta-Strips ------------------------------------ */
/* Convert 'islands' (i.e. continuous string of) selected strips to be
@@ -690,75 +699,75 @@ bool BKE_nlastrips_add_strip(ListBase *strips, NlaStrip *strip)
*/
void BKE_nlastrips_make_metas(ListBase *strips, bool is_temp)
{
- NlaStrip *mstrip = NULL;
- NlaStrip *strip, *stripn;
-
- /* sanity checks */
- if (ELEM(NULL, strips, strips->first))
- return;
-
- /* group all continuous chains of selected strips into meta-strips */
- for (strip = strips->first; strip; strip = stripn) {
- stripn = strip->next;
-
- if (strip->flag & NLASTRIP_FLAG_SELECT) {
- /* if there is an existing meta-strip, add this strip to it, otherwise, create a new one */
- if (mstrip == NULL) {
- /* add a new meta-strip, and add it before the current strip that it will replace... */
- mstrip = MEM_callocN(sizeof(NlaStrip), "Meta-NlaStrip");
- mstrip->type = NLASTRIP_TYPE_META;
- BLI_insertlinkbefore(strips, strip, mstrip);
-
- /* set flags */
- mstrip->flag = NLASTRIP_FLAG_SELECT;
-
- /* set temp flag if appropriate (i.e. for transform-type editing) */
- if (is_temp)
- mstrip->flag |= NLASTRIP_FLAG_TEMP_META;
-
- /* set default repeat/scale values to prevent warnings */
- mstrip->repeat = mstrip->scale = 1.0f;
-
- /* make its start frame be set to the start frame of the current strip */
- mstrip->start = strip->start;
- }
-
- /* remove the selected strips from the track, and add to the meta */
- BLI_remlink(strips, strip);
- BLI_addtail(&mstrip->strips, strip);
-
- /* expand the meta's dimensions to include the newly added strip- i.e. its last frame */
- mstrip->end = strip->end;
- }
- else {
- /* current strip wasn't selected, so the end of 'island' of selected strips has been reached,
- * so stop adding strips to the current meta
- */
- mstrip = NULL;
- }
- }
+ NlaStrip *mstrip = NULL;
+ NlaStrip *strip, *stripn;
+
+ /* sanity checks */
+ if (ELEM(NULL, strips, strips->first))
+ return;
+
+ /* group all continuous chains of selected strips into meta-strips */
+ for (strip = strips->first; strip; strip = stripn) {
+ stripn = strip->next;
+
+ if (strip->flag & NLASTRIP_FLAG_SELECT) {
+ /* if there is an existing meta-strip, add this strip to it, otherwise, create a new one */
+ if (mstrip == NULL) {
+ /* add a new meta-strip, and add it before the current strip that it will replace... */
+ mstrip = MEM_callocN(sizeof(NlaStrip), "Meta-NlaStrip");
+ mstrip->type = NLASTRIP_TYPE_META;
+ BLI_insertlinkbefore(strips, strip, mstrip);
+
+ /* set flags */
+ mstrip->flag = NLASTRIP_FLAG_SELECT;
+
+ /* set temp flag if appropriate (i.e. for transform-type editing) */
+ if (is_temp)
+ mstrip->flag |= NLASTRIP_FLAG_TEMP_META;
+
+ /* set default repeat/scale values to prevent warnings */
+ mstrip->repeat = mstrip->scale = 1.0f;
+
+ /* make its start frame be set to the start frame of the current strip */
+ mstrip->start = strip->start;
+ }
+
+ /* remove the selected strips from the track, and add to the meta */
+ BLI_remlink(strips, strip);
+ BLI_addtail(&mstrip->strips, strip);
+
+ /* expand the meta's dimensions to include the newly added strip- i.e. its last frame */
+ mstrip->end = strip->end;
+ }
+ else {
+ /* current strip wasn't selected, so the end of 'island' of selected strips has been reached,
+ * so stop adding strips to the current meta
+ */
+ mstrip = NULL;
+ }
+ }
}
/* Split a meta-strip into a set of normal strips */
void BKE_nlastrips_clear_metastrip(ListBase *strips, NlaStrip *strip)
{
- NlaStrip *cs, *csn;
-
- /* sanity check */
- if (ELEM(NULL, strips, strip))
- return;
-
- /* move each one of the meta-strip's children before the meta-strip
- * in the list of strips after unlinking them from the meta-strip
- */
- for (cs = strip->strips.first; cs; cs = csn) {
- csn = cs->next;
- BLI_remlink(&strip->strips, cs);
- BLI_insertlinkbefore(strips, strip, cs);
- }
-
- /* free the meta-strip now */
- BKE_nlastrip_free(strips, strip, true);
+ NlaStrip *cs, *csn;
+
+ /* sanity check */
+ if (ELEM(NULL, strips, strip))
+ return;
+
+ /* move each one of the meta-strip's children before the meta-strip
+ * in the list of strips after unlinking them from the meta-strip
+ */
+ for (cs = strip->strips.first; cs; cs = csn) {
+ csn = cs->next;
+ BLI_remlink(&strip->strips, cs);
+ BLI_insertlinkbefore(strips, strip, cs);
+ }
+
+ /* free the meta-strip now */
+ BKE_nlastrip_free(strips, strip, true);
}
/* Remove meta-strips (i.e. flatten the list of strips) from the top-level of the list of strips
@@ -767,26 +776,26 @@ void BKE_nlastrips_clear_metastrip(ListBase *strips, NlaStrip *strip)
*/
void BKE_nlastrips_clear_metas(ListBase *strips, bool only_sel, bool only_temp)
{
- NlaStrip *strip, *stripn;
-
- /* sanity checks */
- if (ELEM(NULL, strips, strips->first))
- return;
-
- /* remove meta-strips fitting the criteria of the arguments */
- for (strip = strips->first; strip; strip = stripn) {
- stripn = strip->next;
-
- /* check if strip is a meta-strip */
- if (strip->type == NLASTRIP_TYPE_META) {
- /* if check if selection and 'temporary-only' considerations are met */
- if ((!only_sel) || (strip->flag & NLASTRIP_FLAG_SELECT)) {
- if ((!only_temp) || (strip->flag & NLASTRIP_FLAG_TEMP_META)) {
- BKE_nlastrips_clear_metastrip(strips, strip);
- }
- }
- }
- }
+ NlaStrip *strip, *stripn;
+
+ /* sanity checks */
+ if (ELEM(NULL, strips, strips->first))
+ return;
+
+ /* remove meta-strips fitting the criteria of the arguments */
+ for (strip = strips->first; strip; strip = stripn) {
+ stripn = strip->next;
+
+ /* check if strip is a meta-strip */
+ if (strip->type == NLASTRIP_TYPE_META) {
+ /* if check if selection and 'temporary-only' considerations are met */
+ if ((!only_sel) || (strip->flag & NLASTRIP_FLAG_SELECT)) {
+ if ((!only_temp) || (strip->flag & NLASTRIP_FLAG_TEMP_META)) {
+ BKE_nlastrips_clear_metastrip(strips, strip);
+ }
+ }
+ }
+ }
}
/* Add the given NLA-Strip to the given Meta-Strip, assuming that the
@@ -794,49 +803,49 @@ void BKE_nlastrips_clear_metas(ListBase *strips, bool only_sel, bool only_temp)
*/
bool BKE_nlameta_add_strip(NlaStrip *mstrip, NlaStrip *strip)
{
- /* sanity checks */
- if (ELEM(NULL, mstrip, strip))
- return false;
-
- /* firstly, check if the meta-strip has space for this */
- if (BKE_nlastrips_has_space(&mstrip->strips, strip->start, strip->end) == 0)
- return false;
-
- /* check if this would need to be added to the ends of the meta,
- * and subsequently, if the neighboring strips allow us enough room
- */
- if (strip->start < mstrip->start) {
- /* check if strip to the left (if it exists) ends before the
- * start of the strip we're trying to add
- */
- if ((mstrip->prev == NULL) || (mstrip->prev->end <= strip->start)) {
- /* add strip to start of meta's list, and expand dimensions */
- BLI_addhead(&mstrip->strips, strip);
- mstrip->start = strip->start;
-
- return true;
- }
- else /* failed... no room before */
- return false;
- }
- else if (strip->end > mstrip->end) {
- /* check if strip to the right (if it exists) starts before the
- * end of the strip we're trying to add
- */
- if ((mstrip->next == NULL) || (mstrip->next->start >= strip->end)) {
- /* add strip to end of meta's list, and expand dimensions */
- BLI_addtail(&mstrip->strips, strip);
- mstrip->end = strip->end;
-
- return true;
- }
- else /* failed... no room after */
- return false;
- }
- else {
- /* just try to add to the meta-strip (no dimension changes needed) */
- return BKE_nlastrips_add_strip(&mstrip->strips, strip);
- }
+ /* sanity checks */
+ if (ELEM(NULL, mstrip, strip))
+ return false;
+
+ /* firstly, check if the meta-strip has space for this */
+ if (BKE_nlastrips_has_space(&mstrip->strips, strip->start, strip->end) == 0)
+ return false;
+
+ /* check if this would need to be added to the ends of the meta,
+ * and subsequently, if the neighboring strips allow us enough room
+ */
+ if (strip->start < mstrip->start) {
+ /* check if strip to the left (if it exists) ends before the
+ * start of the strip we're trying to add
+ */
+ if ((mstrip->prev == NULL) || (mstrip->prev->end <= strip->start)) {
+ /* add strip to start of meta's list, and expand dimensions */
+ BLI_addhead(&mstrip->strips, strip);
+ mstrip->start = strip->start;
+
+ return true;
+ }
+ else /* failed... no room before */
+ return false;
+ }
+ else if (strip->end > mstrip->end) {
+ /* check if strip to the right (if it exists) starts before the
+ * end of the strip we're trying to add
+ */
+ if ((mstrip->next == NULL) || (mstrip->next->start >= strip->end)) {
+ /* add strip to end of meta's list, and expand dimensions */
+ BLI_addtail(&mstrip->strips, strip);
+ mstrip->end = strip->end;
+
+ return true;
+ }
+ else /* failed... no room after */
+ return false;
+ }
+ else {
+ /* just try to add to the meta-strip (no dimension changes needed) */
+ return BKE_nlastrips_add_strip(&mstrip->strips, strip);
+ }
}
/* Adjust the settings of NLA-Strips contained within a Meta-Strip (recursively),
@@ -844,77 +853,77 @@ bool BKE_nlameta_add_strip(NlaStrip *mstrip, NlaStrip *strip)
*/
void BKE_nlameta_flush_transforms(NlaStrip *mstrip)
{
- NlaStrip *strip;
- float oStart, oEnd, offset;
- float oLen, nLen;
- short scaleChanged = 0;
-
- /* sanity checks
- * - strip must exist
- * - strip must be a meta-strip with some contents
- */
- if (ELEM(NULL, mstrip, mstrip->strips.first))
- return;
- if (mstrip->type != NLASTRIP_TYPE_META)
- return;
-
- /* get the original start/end points, and calculate the start-frame offset
- * - these are simply the start/end frames of the child strips,
- * since we assume they weren't transformed yet
- */
- oStart = ((NlaStrip *)mstrip->strips.first)->start;
- oEnd = ((NlaStrip *)mstrip->strips.last)->end;
- offset = mstrip->start - oStart;
-
- /* optimization:
- * don't flush if nothing changed yet
- * TODO: maybe we need a flag to say always flush?
- */
- if (IS_EQF(oStart, mstrip->start) && IS_EQF(oEnd, mstrip->end))
- return;
-
- /* check if scale changed */
- oLen = oEnd - oStart;
- nLen = mstrip->end - mstrip->start;
- if (IS_EQF(nLen, oLen) == 0)
- scaleChanged = 1;
-
- /* for each child-strip, calculate new start/end points based on this new info */
- for (strip = mstrip->strips.first; strip; strip = strip->next) {
- if (scaleChanged) {
- float p1, p2;
-
- /* compute positions of endpoints relative to old extents of strip */
- p1 = (strip->start - oStart) / oLen;
- p2 = (strip->end - oStart) / oLen;
-
- /* apply new strip endpoints using the proportions, then wait for second pass to flush scale properly */
- strip->start = (p1 * nLen) + mstrip->start;
- strip->end = (p2 * nLen) + mstrip->start;
- }
- else {
- /* just apply the changes in offset to both ends of the strip */
- strip->start += offset;
- strip->end += offset;
- }
- }
-
- /* apply a second pass over child strips, to finish up unfinished business */
- for (strip = mstrip->strips.first; strip; strip = strip->next) {
- /* only if scale changed, need to perform RNA updates */
- if (scaleChanged) {
- PointerRNA ptr;
-
- /* use RNA updates to compute scale properly */
- RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &ptr);
-
- RNA_float_set(&ptr, "frame_start", strip->start);
- RNA_float_set(&ptr, "frame_end", strip->end);
- }
-
- /* finally, make sure the strip's children (if it is a meta-itself), get updated */
- BKE_nlameta_flush_transforms(strip);
- }
+ NlaStrip *strip;
+ float oStart, oEnd, offset;
+ float oLen, nLen;
+ short scaleChanged = 0;
+
+ /* sanity checks
+ * - strip must exist
+ * - strip must be a meta-strip with some contents
+ */
+ if (ELEM(NULL, mstrip, mstrip->strips.first))
+ return;
+ if (mstrip->type != NLASTRIP_TYPE_META)
+ return;
+
+ /* get the original start/end points, and calculate the start-frame offset
+ * - these are simply the start/end frames of the child strips,
+ * since we assume they weren't transformed yet
+ */
+ oStart = ((NlaStrip *)mstrip->strips.first)->start;
+ oEnd = ((NlaStrip *)mstrip->strips.last)->end;
+ offset = mstrip->start - oStart;
+
+ /* optimization:
+ * don't flush if nothing changed yet
+ * TODO: maybe we need a flag to say always flush?
+ */
+ if (IS_EQF(oStart, mstrip->start) && IS_EQF(oEnd, mstrip->end))
+ return;
+
+ /* check if scale changed */
+ oLen = oEnd - oStart;
+ nLen = mstrip->end - mstrip->start;
+ if (IS_EQF(nLen, oLen) == 0)
+ scaleChanged = 1;
+
+ /* for each child-strip, calculate new start/end points based on this new info */
+ for (strip = mstrip->strips.first; strip; strip = strip->next) {
+ if (scaleChanged) {
+ float p1, p2;
+
+ /* compute positions of endpoints relative to old extents of strip */
+ p1 = (strip->start - oStart) / oLen;
+ p2 = (strip->end - oStart) / oLen;
+
+ /* apply new strip endpoints using the proportions, then wait for second pass to flush scale properly */
+ strip->start = (p1 * nLen) + mstrip->start;
+ strip->end = (p2 * nLen) + mstrip->start;
+ }
+ else {
+ /* just apply the changes in offset to both ends of the strip */
+ strip->start += offset;
+ strip->end += offset;
+ }
+ }
+
+ /* apply a second pass over child strips, to finish up unfinished business */
+ for (strip = mstrip->strips.first; strip; strip = strip->next) {
+ /* only if scale changed, need to perform RNA updates */
+ if (scaleChanged) {
+ PointerRNA ptr;
+
+ /* use RNA updates to compute scale properly */
+ RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &ptr);
+
+ RNA_float_set(&ptr, "frame_start", strip->start);
+ RNA_float_set(&ptr, "frame_end", strip->end);
+ }
+
+ /* finally, make sure the strip's children (if it is a meta-itself), get updated */
+ BKE_nlameta_flush_transforms(strip);
+ }
}
/* NLA-Tracks ---------------------------------------- */
@@ -922,20 +931,20 @@ void BKE_nlameta_flush_transforms(NlaStrip *mstrip)
/* Find the active NLA-track for the given stack */
NlaTrack *BKE_nlatrack_find_active(ListBase *tracks)
{
- NlaTrack *nlt;
+ NlaTrack *nlt;
- /* sanity check */
- if (ELEM(NULL, tracks, tracks->first))
- return NULL;
+ /* sanity check */
+ if (ELEM(NULL, tracks, tracks->first))
+ return NULL;
- /* try to find the first active track */
- for (nlt = tracks->first; nlt; nlt = nlt->next) {
- if (nlt->flag & NLATRACK_ACTIVE)
- return nlt;
- }
+ /* try to find the first active track */
+ for (nlt = tracks->first; nlt; nlt = nlt->next) {
+ if (nlt->flag & NLATRACK_ACTIVE)
+ return nlt;
+ }
- /* none found */
- return NULL;
+ /* none found */
+ return NULL;
}
/* Get the NLA Track that the active action/action strip comes from,
@@ -945,30 +954,32 @@ NlaTrack *BKE_nlatrack_find_active(ListBase *tracks)
*/
NlaTrack *BKE_nlatrack_find_tweaked(AnimData *adt)
{
- NlaTrack *nlt;
-
- /* sanity check */
- if (adt == NULL)
- return NULL;
-
- /* Since the track itself gets disabled, we want the first disabled... */
- for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
- if (nlt->flag & (NLATRACK_ACTIVE | NLATRACK_DISABLED)) {
- /* For good measure, make sure that strip actually exists there */
- if (BLI_findindex(&nlt->strips, adt->actstrip) != -1) {
- return nlt;
- }
- else if (G.debug & G_DEBUG) {
- printf("%s: Active strip (%p, %s) not in NLA track found (%p, %s)\n",
- __func__,
- adt->actstrip, (adt->actstrip) ? adt->actstrip->name : "<None>",
- nlt, nlt->name);
- }
- }
- }
-
- /* Not found! */
- return NULL;
+ NlaTrack *nlt;
+
+ /* sanity check */
+ if (adt == NULL)
+ return NULL;
+
+ /* Since the track itself gets disabled, we want the first disabled... */
+ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ if (nlt->flag & (NLATRACK_ACTIVE | NLATRACK_DISABLED)) {
+ /* For good measure, make sure that strip actually exists there */
+ if (BLI_findindex(&nlt->strips, adt->actstrip) != -1) {
+ return nlt;
+ }
+ else if (G.debug & G_DEBUG) {
+ printf("%s: Active strip (%p, %s) not in NLA track found (%p, %s)\n",
+ __func__,
+ adt->actstrip,
+ (adt->actstrip) ? adt->actstrip->name : "<None>",
+ nlt,
+ nlt->name);
+ }
+ }
+ }
+
+ /* Not found! */
+ return NULL;
}
/* Toggle the 'solo' setting for the given NLA-track, making sure that it is the only one
@@ -976,31 +987,31 @@ NlaTrack *BKE_nlatrack_find_tweaked(AnimData *adt)
*/
void BKE_nlatrack_solo_toggle(AnimData *adt, NlaTrack *nlt)
{
- NlaTrack *nt;
-
- /* sanity check */
- if (ELEM(NULL, adt, adt->nla_tracks.first))
- return;
-
- /* firstly, make sure 'solo' flag for all tracks is disabled */
- for (nt = adt->nla_tracks.first; nt; nt = nt->next) {
- if (nt != nlt)
- nt->flag &= ~NLATRACK_SOLO;
- }
-
- /* now, enable 'solo' for the given track if appropriate */
- if (nlt) {
- /* toggle solo status */
- nlt->flag ^= NLATRACK_SOLO;
-
- /* set or clear solo-status on AnimData */
- if (nlt->flag & NLATRACK_SOLO)
- adt->flag |= ADT_NLA_SOLO_TRACK;
- else
- adt->flag &= ~ADT_NLA_SOLO_TRACK;
- }
- else
- adt->flag &= ~ADT_NLA_SOLO_TRACK;
+ NlaTrack *nt;
+
+ /* sanity check */
+ if (ELEM(NULL, adt, adt->nla_tracks.first))
+ return;
+
+ /* firstly, make sure 'solo' flag for all tracks is disabled */
+ for (nt = adt->nla_tracks.first; nt; nt = nt->next) {
+ if (nt != nlt)
+ nt->flag &= ~NLATRACK_SOLO;
+ }
+
+ /* now, enable 'solo' for the given track if appropriate */
+ if (nlt) {
+ /* toggle solo status */
+ nlt->flag ^= NLATRACK_SOLO;
+
+ /* set or clear solo-status on AnimData */
+ if (nlt->flag & NLATRACK_SOLO)
+ adt->flag |= ADT_NLA_SOLO_TRACK;
+ else
+ adt->flag &= ~ADT_NLA_SOLO_TRACK;
+ }
+ else
+ adt->flag &= ~ADT_NLA_SOLO_TRACK;
}
/* Make the given NLA-track the active one for the given stack. If no track is provided,
@@ -1008,39 +1019,39 @@ void BKE_nlatrack_solo_toggle(AnimData *adt, NlaTrack *nlt)
*/
void BKE_nlatrack_set_active(ListBase *tracks, NlaTrack *nlt_a)
{
- NlaTrack *nlt;
+ NlaTrack *nlt;
- /* sanity check */
- if (ELEM(NULL, tracks, tracks->first))
- return;
+ /* sanity check */
+ if (ELEM(NULL, tracks, tracks->first))
+ return;
- /* deactivate all the rest */
- for (nlt = tracks->first; nlt; nlt = nlt->next)
- nlt->flag &= ~NLATRACK_ACTIVE;
+ /* deactivate all the rest */
+ for (nlt = tracks->first; nlt; nlt = nlt->next)
+ nlt->flag &= ~NLATRACK_ACTIVE;
- /* set the given one as the active one */
- if (nlt_a)
- nlt_a->flag |= NLATRACK_ACTIVE;
+ /* set the given one as the active one */
+ if (nlt_a)
+ nlt_a->flag |= NLATRACK_ACTIVE;
}
/* Check if there is any space in the given track to add a strip of the given length */
bool BKE_nlatrack_has_space(NlaTrack *nlt, float start, float end)
{
- /* sanity checks
- * - track must exist
- * - track must be editable
- * - bounds cannot be equal (0-length is nasty)
- */
- if ((nlt == NULL) || (nlt->flag & NLATRACK_PROTECTED) || IS_EQF(start, end))
- return false;
-
- if (start > end) {
- puts("BKE_nlatrack_has_space() error... start and end arguments swapped");
- SWAP(float, start, end);
- }
-
- /* check if there's any space left in the track for a strip of the given length */
- return BKE_nlastrips_has_space(&nlt->strips, start, end);
+ /* sanity checks
+ * - track must exist
+ * - track must be editable
+ * - bounds cannot be equal (0-length is nasty)
+ */
+ if ((nlt == NULL) || (nlt->flag & NLATRACK_PROTECTED) || IS_EQF(start, end))
+ return false;
+
+ if (start > end) {
+ puts("BKE_nlatrack_has_space() error... start and end arguments swapped");
+ SWAP(float, start, end);
+ }
+
+ /* check if there's any space left in the track for a strip of the given length */
+ return BKE_nlastrips_has_space(&nlt->strips, start, end);
}
/* Rearrange the strips in the track so that they are always in order
@@ -1048,12 +1059,12 @@ bool BKE_nlatrack_has_space(NlaTrack *nlt, float start, float end)
*/
void BKE_nlatrack_sort_strips(NlaTrack *nlt)
{
- /* sanity checks */
- if (ELEM(NULL, nlt, nlt->strips.first))
- return;
+ /* sanity checks */
+ if (ELEM(NULL, nlt, nlt->strips.first))
+ return;
- /* sort the strips with a more generic function */
- BKE_nlastrips_sort_strips(&nlt->strips);
+ /* sort the strips with a more generic function */
+ BKE_nlastrips_sort_strips(&nlt->strips);
}
/* Add the given NLA-Strip to the given NLA-Track, assuming that it
@@ -1061,16 +1072,16 @@ void BKE_nlatrack_sort_strips(NlaTrack *nlt)
*/
bool BKE_nlatrack_add_strip(NlaTrack *nlt, NlaStrip *strip)
{
- /* sanity checks */
- if (ELEM(NULL, nlt, strip))
- return false;
+ /* sanity checks */
+ if (ELEM(NULL, nlt, strip))
+ return false;
- /* do not allow adding strips if this track is locked */
- if (nlt->flag & NLATRACK_PROTECTED)
- return false;
+ /* do not allow adding strips if this track is locked */
+ if (nlt->flag & NLATRACK_PROTECTED)
+ return false;
- /* try to add the strip to the track using a more generic function */
- return BKE_nlastrips_add_strip(&nlt->strips, strip);
+ /* try to add the strip to the track using a more generic function */
+ return BKE_nlastrips_add_strip(&nlt->strips, strip);
}
/* Get the extents of the given NLA-Track including gaps between strips,
@@ -1078,28 +1089,28 @@ bool BKE_nlatrack_add_strip(NlaTrack *nlt, NlaStrip *strip)
*/
bool BKE_nlatrack_get_bounds(NlaTrack *nlt, float bounds[2])
{
- NlaStrip *strip;
+ NlaStrip *strip;
- /* initialize bounds */
- if (bounds)
- bounds[0] = bounds[1] = 0.0f;
- else
- return false;
+ /* initialize bounds */
+ if (bounds)
+ bounds[0] = bounds[1] = 0.0f;
+ else
+ return false;
- /* sanity checks */
- if (ELEM(NULL, nlt, nlt->strips.first))
- return false;
+ /* sanity checks */
+ if (ELEM(NULL, nlt, nlt->strips.first))
+ return false;
- /* lower bound is first strip's start frame */
- strip = nlt->strips.first;
- bounds[0] = strip->start;
+ /* lower bound is first strip's start frame */
+ strip = nlt->strips.first;
+ bounds[0] = strip->start;
- /* upper bound is last strip's end frame */
- strip = nlt->strips.last;
- bounds[1] = strip->end;
+ /* upper bound is last strip's end frame */
+ strip = nlt->strips.last;
+ bounds[1] = strip->end;
- /* done */
- return true;
+ /* done */
+ return true;
}
/* NLA Strips -------------------------------------- */
@@ -1107,171 +1118,169 @@ bool BKE_nlatrack_get_bounds(NlaTrack *nlt, float bounds[2])
/* Find the active NLA-strip within the given track */
NlaStrip *BKE_nlastrip_find_active(NlaTrack *nlt)
{
- NlaStrip *strip;
+ NlaStrip *strip;
- /* sanity check */
- if (ELEM(NULL, nlt, nlt->strips.first))
- return NULL;
+ /* sanity check */
+ if (ELEM(NULL, nlt, nlt->strips.first))
+ return NULL;
- /* try to find the first active strip */
- for (strip = nlt->strips.first; strip; strip = strip->next) {
- if (strip->flag & NLASTRIP_FLAG_ACTIVE)
- return strip;
- }
+ /* try to find the first active strip */
+ for (strip = nlt->strips.first; strip; strip = strip->next) {
+ if (strip->flag & NLASTRIP_FLAG_ACTIVE)
+ return strip;
+ }
- /* none found */
- return NULL;
+ /* none found */
+ return NULL;
}
/* Make the given NLA-Strip the active one within the given block */
void BKE_nlastrip_set_active(AnimData *adt, NlaStrip *strip)
{
- NlaTrack *nlt;
- NlaStrip *nls;
-
- /* sanity checks */
- if (adt == NULL)
- return;
-
- /* loop over tracks, deactivating*/
- for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
- for (nls = nlt->strips.first; nls; nls = nls->next) {
- if (nls != strip)
- nls->flag &= ~NLASTRIP_FLAG_ACTIVE;
- else
- nls->flag |= NLASTRIP_FLAG_ACTIVE;
- }
- }
+ NlaTrack *nlt;
+ NlaStrip *nls;
+
+ /* sanity checks */
+ if (adt == NULL)
+ return;
+
+ /* loop over tracks, deactivating*/
+ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ for (nls = nlt->strips.first; nls; nls = nls->next) {
+ if (nls != strip)
+ nls->flag &= ~NLASTRIP_FLAG_ACTIVE;
+ else
+ nls->flag |= NLASTRIP_FLAG_ACTIVE;
+ }
+ }
}
-
/* Does the given NLA-strip fall within the given bounds (times)? */
bool BKE_nlastrip_within_bounds(NlaStrip *strip, float min, float max)
{
- const float stripLen = (strip) ? strip->end - strip->start : 0.0f;
- const float boundsLen = fabsf(max - min);
-
- /* sanity checks */
- if ((strip == NULL) || IS_EQF(stripLen, 0.0f) || IS_EQF(boundsLen, 0.0f))
- return false;
-
- /* only ok if at least part of the strip is within the bounding window
- * - first 2 cases cover when the strip length is less than the bounding area
- * - second 2 cases cover when the strip length is greater than the bounding area
- */
- if ((stripLen < boundsLen) &&
- !(IN_RANGE(strip->start, min, max) ||
- IN_RANGE(strip->end, min, max)))
- {
- return false;
- }
- if ((stripLen > boundsLen) &&
- !(IN_RANGE(min, strip->start, strip->end) ||
- IN_RANGE(max, strip->start, strip->end)) )
- {
- return false;
- }
-
- /* should be ok! */
- return true;
+ const float stripLen = (strip) ? strip->end - strip->start : 0.0f;
+ const float boundsLen = fabsf(max - min);
+
+ /* sanity checks */
+ if ((strip == NULL) || IS_EQF(stripLen, 0.0f) || IS_EQF(boundsLen, 0.0f))
+ return false;
+
+ /* only ok if at least part of the strip is within the bounding window
+ * - first 2 cases cover when the strip length is less than the bounding area
+ * - second 2 cases cover when the strip length is greater than the bounding area
+ */
+ if ((stripLen < boundsLen) &&
+ !(IN_RANGE(strip->start, min, max) || IN_RANGE(strip->end, min, max))) {
+ return false;
+ }
+ if ((stripLen > boundsLen) &&
+ !(IN_RANGE(min, strip->start, strip->end) || IN_RANGE(max, strip->start, strip->end))) {
+ return false;
+ }
+
+ /* should be ok! */
+ return true;
}
-
/* Ensure that strip doesn't overlap those around it after resizing by offsetting those which follow */
static void nlastrip_fix_resize_overlaps(NlaStrip *strip)
{
- /* next strips - do this first, since we're often just getting longer */
- if (strip->next) {
- NlaStrip *nls = strip->next;
- float offset = 0.0f;
-
- if (nls->type == NLASTRIP_TYPE_TRANSITION) {
- /* transition strips should grow/shrink to accommodate the resized strip,
- * but if the strip's bounds now exceed the transition, we're forced to
- * offset everything to maintain the balance
- */
- if (strip->end <= nls->start) {
- /* grow the transition to fill the void */
- nls->start = strip->end;
- }
- else if (strip->end < nls->end) {
- /* shrink the transition to give the strip room */
- nls->start = strip->end;
- }
- else {
- /* shrink transition down to 1 frame long (so that it can still be found),
- * then offset everything else by the remaining defict to give the strip room
- */
- nls->start = nls->end - 1.0f;
- offset = ceilf(strip->end - nls->start); /* XXX: review whether preventing fractionals is good here... */
-
- /* apply necessary offset to ensure that the strip has enough space */
- for (; nls; nls = nls->next) {
- nls->start += offset;
- nls->end += offset;
- }
- }
- }
- else if (strip->end > nls->start) {
- /* NOTE: need to ensure we don't have a fractional frame offset, even if that leaves a gap,
- * otherwise it will be very hard to get rid of later
- */
- offset = ceilf(strip->end - nls->start);
-
- /* apply to times of all strips in this direction */
- for (; nls; nls = nls->next) {
- nls->start += offset;
- nls->end += offset;
- }
- }
- }
-
- /* previous strips - same routine as before */
- /* NOTE: when strip bounds are recalculated, this is not considered! */
- if (strip->prev) {
- NlaStrip *nls = strip->prev;
- float offset = 0.0f;
-
- if (nls->type == NLASTRIP_TYPE_TRANSITION) {
- /* transition strips should grow/shrink to accommodate the resized strip,
- * but if the strip's bounds now exceed the transition, we're forced to
- * offset everything to maintain the balance
- */
- if (strip->start >= nls->end) {
- /* grow the transition to fill the void */
- nls->end = strip->start;
- }
- else if (strip->start > nls->start) {
- /* shrink the transition to give the strip room */
- nls->end = strip->start;
- }
- else {
- /* shrink transition down to 1 frame long (so that it can still be found),
- * then offset everything else by the remaining defict to give the strip room
- */
- nls->end = nls->start + 1.0f;
- offset = ceilf(nls->end - strip->start); /* XXX: review whether preventing fractionals is good here... */
-
- /* apply necessary offset to ensure that the strip has enough space */
- for (; nls; nls = nls->next) {
- nls->start -= offset;
- nls->end -= offset;
- }
- }
- }
- else if (strip->start < nls->end) {
- /* NOTE: need to ensure we don't have a fractional frame offset, even if that leaves a gap,
- * otherwise it will be very hard to get rid of later
- */
- offset = ceilf(nls->end - strip->start);
-
- /* apply to times of all strips in this direction */
- for (; nls; nls = nls->prev) {
- nls->start -= offset;
- nls->end -= offset;
- }
- }
- }
+ /* next strips - do this first, since we're often just getting longer */
+ if (strip->next) {
+ NlaStrip *nls = strip->next;
+ float offset = 0.0f;
+
+ if (nls->type == NLASTRIP_TYPE_TRANSITION) {
+ /* transition strips should grow/shrink to accommodate the resized strip,
+ * but if the strip's bounds now exceed the transition, we're forced to
+ * offset everything to maintain the balance
+ */
+ if (strip->end <= nls->start) {
+ /* grow the transition to fill the void */
+ nls->start = strip->end;
+ }
+ else if (strip->end < nls->end) {
+ /* shrink the transition to give the strip room */
+ nls->start = strip->end;
+ }
+ else {
+ /* shrink transition down to 1 frame long (so that it can still be found),
+ * then offset everything else by the remaining defict to give the strip room
+ */
+ nls->start = nls->end - 1.0f;
+ offset = ceilf(
+ strip->end -
+ nls->start); /* XXX: review whether preventing fractionals is good here... */
+
+ /* apply necessary offset to ensure that the strip has enough space */
+ for (; nls; nls = nls->next) {
+ nls->start += offset;
+ nls->end += offset;
+ }
+ }
+ }
+ else if (strip->end > nls->start) {
+ /* NOTE: need to ensure we don't have a fractional frame offset, even if that leaves a gap,
+ * otherwise it will be very hard to get rid of later
+ */
+ offset = ceilf(strip->end - nls->start);
+
+ /* apply to times of all strips in this direction */
+ for (; nls; nls = nls->next) {
+ nls->start += offset;
+ nls->end += offset;
+ }
+ }
+ }
+
+ /* previous strips - same routine as before */
+ /* NOTE: when strip bounds are recalculated, this is not considered! */
+ if (strip->prev) {
+ NlaStrip *nls = strip->prev;
+ float offset = 0.0f;
+
+ if (nls->type == NLASTRIP_TYPE_TRANSITION) {
+ /* transition strips should grow/shrink to accommodate the resized strip,
+ * but if the strip's bounds now exceed the transition, we're forced to
+ * offset everything to maintain the balance
+ */
+ if (strip->start >= nls->end) {
+ /* grow the transition to fill the void */
+ nls->end = strip->start;
+ }
+ else if (strip->start > nls->start) {
+ /* shrink the transition to give the strip room */
+ nls->end = strip->start;
+ }
+ else {
+ /* shrink transition down to 1 frame long (so that it can still be found),
+ * then offset everything else by the remaining defict to give the strip room
+ */
+ nls->end = nls->start + 1.0f;
+ offset = ceilf(
+ nls->end -
+ strip->start); /* XXX: review whether preventing fractionals is good here... */
+
+ /* apply necessary offset to ensure that the strip has enough space */
+ for (; nls; nls = nls->next) {
+ nls->start -= offset;
+ nls->end -= offset;
+ }
+ }
+ }
+ else if (strip->start < nls->end) {
+ /* NOTE: need to ensure we don't have a fractional frame offset, even if that leaves a gap,
+ * otherwise it will be very hard to get rid of later
+ */
+ offset = ceilf(nls->end - strip->start);
+
+ /* apply to times of all strips in this direction */
+ for (; nls; nls = nls->prev) {
+ nls->start -= offset;
+ nls->end -= offset;
+ }
+ }
+ }
}
/* Recalculate the start and end frames for the current strip, after changing
@@ -1279,57 +1288,58 @@ static void nlastrip_fix_resize_overlaps(NlaStrip *strip)
*/
void BKE_nlastrip_recalculate_bounds(NlaStrip *strip)
{
- float actlen, mapping;
+ float actlen, mapping;
- /* sanity checks
- * - must have a strip
- * - can only be done for action clips
- */
- if ((strip == NULL) || (strip->type != NLASTRIP_TYPE_CLIP))
- return;
+ /* sanity checks
+ * - must have a strip
+ * - can only be done for action clips
+ */
+ if ((strip == NULL) || (strip->type != NLASTRIP_TYPE_CLIP))
+ return;
- /* calculate new length factors */
- actlen = strip->actend - strip->actstart;
- if (IS_EQF(actlen, 0.0f)) actlen = 1.0f;
+ /* calculate new length factors */
+ actlen = strip->actend - strip->actstart;
+ if (IS_EQF(actlen, 0.0f))
+ actlen = 1.0f;
- mapping = strip->scale * strip->repeat;
+ mapping = strip->scale * strip->repeat;
- /* adjust endpoint of strip in response to this */
- if (IS_EQF(mapping, 0.0f) == 0)
- strip->end = (actlen * mapping) + strip->start;
+ /* adjust endpoint of strip in response to this */
+ if (IS_EQF(mapping, 0.0f) == 0)
+ strip->end = (actlen * mapping) + strip->start;
- /* make sure we don't overlap our neighbors */
- nlastrip_fix_resize_overlaps(strip);
+ /* make sure we don't overlap our neighbors */
+ nlastrip_fix_resize_overlaps(strip);
}
/* Is the given NLA-strip the first one to occur for the given AnimData block */
// TODO: make this an api method if necessary, but need to add prefix first
static bool nlastrip_is_first(AnimData *adt, NlaStrip *strip)
{
- NlaTrack *nlt;
- NlaStrip *ns;
-
- /* sanity checks */
- if (ELEM(NULL, adt, strip))
- return false;
-
- /* check if strip has any strips before it */
- if (strip->prev)
- return false;
-
- /* check other tracks to see if they have a strip that's earlier */
- /* TODO: or should we check that the strip's track is also the first? */
- for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
- /* only check the first strip, assuming that they're all in order */
- ns = nlt->strips.first;
- if (ns) {
- if (ns->start < strip->start)
- return false;
- }
- }
-
- /* should be first now */
- return true;
+ NlaTrack *nlt;
+ NlaStrip *ns;
+
+ /* sanity checks */
+ if (ELEM(NULL, adt, strip))
+ return false;
+
+ /* check if strip has any strips before it */
+ if (strip->prev)
+ return false;
+
+ /* check other tracks to see if they have a strip that's earlier */
+ /* TODO: or should we check that the strip's track is also the first? */
+ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ /* only check the first strip, assuming that they're all in order */
+ ns = nlt->strips.first;
+ if (ns) {
+ if (ns->start < strip->start)
+ return false;
+ }
+ }
+
+ /* should be first now */
+ return true;
}
/* Animated Strips ------------------------------------------- */
@@ -1337,98 +1347,98 @@ static bool nlastrip_is_first(AnimData *adt, NlaStrip *strip)
/* Check if the given NLA-Track has any strips with own F-Curves */
bool BKE_nlatrack_has_animated_strips(NlaTrack *nlt)
{
- NlaStrip *strip;
+ NlaStrip *strip;
- /* sanity checks */
- if (ELEM(NULL, nlt, nlt->strips.first))
- return false;
+ /* sanity checks */
+ if (ELEM(NULL, nlt, nlt->strips.first))
+ return false;
- /* check each strip for F-Curves only (don't care about whether the flags are set) */
- for (strip = nlt->strips.first; strip; strip = strip->next) {
- if (strip->fcurves.first)
- return true;
- }
+ /* check each strip for F-Curves only (don't care about whether the flags are set) */
+ for (strip = nlt->strips.first; strip; strip = strip->next) {
+ if (strip->fcurves.first)
+ return true;
+ }
- /* none found */
- return false;
+ /* none found */
+ return false;
}
/* Check if given NLA-Tracks have any strips with own F-Curves */
bool BKE_nlatracks_have_animated_strips(ListBase *tracks)
{
- NlaTrack *nlt;
+ NlaTrack *nlt;
- /* sanity checks */
- if (ELEM(NULL, tracks, tracks->first))
- return false;
+ /* sanity checks */
+ if (ELEM(NULL, tracks, tracks->first))
+ return false;
- /* check each track, stopping on the first hit */
- for (nlt = tracks->first; nlt; nlt = nlt->next) {
- if (BKE_nlatrack_has_animated_strips(nlt))
- return true;
- }
+ /* check each track, stopping on the first hit */
+ for (nlt = tracks->first; nlt; nlt = nlt->next) {
+ if (BKE_nlatrack_has_animated_strips(nlt))
+ return true;
+ }
- /* none found */
- return false;
+ /* none found */
+ return false;
}
/* Validate the NLA-Strips 'control' F-Curves based on the flags set*/
void BKE_nlastrip_validate_fcurves(NlaStrip *strip)
{
- FCurve *fcu;
-
- /* sanity checks */
- if (strip == NULL)
- return;
-
- /* if controlling influence... */
- if (strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) {
- /* try to get F-Curve */
- fcu = list_find_fcurve(&strip->fcurves, "influence", 0);
-
- /* add one if not found */
- if (fcu == NULL) {
- /* make new F-Curve */
- fcu = MEM_callocN(sizeof(FCurve), "NlaStrip FCurve");
- BLI_addtail(&strip->fcurves, fcu);
-
- /* set default flags */
- fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED);
- fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL;
-
- /* store path - make copy, and store that */
- fcu->rna_path = BLI_strdupn("influence", 9);
-
- /* insert keyframe to ensure current value stays on first refresh */
- fcu->bezt = MEM_callocN(sizeof(BezTriple), "nlastrip influence bezt");
- fcu->totvert = 1;
-
- fcu->bezt->vec[1][0] = strip->start;
- fcu->bezt->vec[1][1] = strip->influence;
- }
- }
-
- /* if controlling time... */
- if (strip->flag & NLASTRIP_FLAG_USR_TIME) {
- /* try to get F-Curve */
- fcu = list_find_fcurve(&strip->fcurves, "strip_time", 0);
-
- /* add one if not found */
- if (fcu == NULL) {
- /* make new F-Curve */
- fcu = MEM_callocN(sizeof(FCurve), "NlaStrip FCurve");
- BLI_addtail(&strip->fcurves, fcu);
-
- /* set default flags */
- fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED);
- fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL;
-
- /* store path - make copy, and store that */
- fcu->rna_path = BLI_strdupn("strip_time", 10);
-
- /* TODO: insert a few keyframes to ensure default behavior? */
- }
- }
+ FCurve *fcu;
+
+ /* sanity checks */
+ if (strip == NULL)
+ return;
+
+ /* if controlling influence... */
+ if (strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) {
+ /* try to get F-Curve */
+ fcu = list_find_fcurve(&strip->fcurves, "influence", 0);
+
+ /* add one if not found */
+ if (fcu == NULL) {
+ /* make new F-Curve */
+ fcu = MEM_callocN(sizeof(FCurve), "NlaStrip FCurve");
+ BLI_addtail(&strip->fcurves, fcu);
+
+ /* set default flags */
+ fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED);
+ fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL;
+
+ /* store path - make copy, and store that */
+ fcu->rna_path = BLI_strdupn("influence", 9);
+
+ /* insert keyframe to ensure current value stays on first refresh */
+ fcu->bezt = MEM_callocN(sizeof(BezTriple), "nlastrip influence bezt");
+ fcu->totvert = 1;
+
+ fcu->bezt->vec[1][0] = strip->start;
+ fcu->bezt->vec[1][1] = strip->influence;
+ }
+ }
+
+ /* if controlling time... */
+ if (strip->flag & NLASTRIP_FLAG_USR_TIME) {
+ /* try to get F-Curve */
+ fcu = list_find_fcurve(&strip->fcurves, "strip_time", 0);
+
+ /* add one if not found */
+ if (fcu == NULL) {
+ /* make new F-Curve */
+ fcu = MEM_callocN(sizeof(FCurve), "NlaStrip FCurve");
+ BLI_addtail(&strip->fcurves, fcu);
+
+ /* set default flags */
+ fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED);
+ fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL;
+
+ /* store path - make copy, and store that */
+ fcu->rna_path = BLI_strdupn("strip_time", 10);
+
+ /* TODO: insert a few keyframes to ensure default behavior? */
+ }
+ }
}
/* Check if the given RNA pointer + property combo should be handled by
@@ -1436,40 +1446,40 @@ void BKE_nlastrip_validate_fcurves(NlaStrip *strip)
*/
bool BKE_nlastrip_has_curves_for_property(const PointerRNA *ptr, const PropertyRNA *prop)
{
- /* sanity checks */
- if (ELEM(NULL, ptr, prop))
- return false;
-
- /* 1) Must be NLA strip */
- if (ptr->type == &RNA_NlaStrip) {
- /* 2) Must be one of the predefined properties */
- static PropertyRNA *prop_influence = NULL;
- static PropertyRNA *prop_time = NULL;
- static bool needs_init = true;
-
- /* Init the properties on first use */
- if (needs_init) {
- prop_influence = RNA_struct_type_find_property(&RNA_NlaStrip, "influence");
- prop_time = RNA_struct_type_find_property(&RNA_NlaStrip, "strip_time");
-
- needs_init = false;
- }
-
- /* Check if match */
- if (ELEM(prop, prop_influence, prop_time)) {
- return true;
- }
- }
-
- /* No criteria met */
- return false;
+ /* sanity checks */
+ if (ELEM(NULL, ptr, prop))
+ return false;
+
+ /* 1) Must be NLA strip */
+ if (ptr->type == &RNA_NlaStrip) {
+ /* 2) Must be one of the predefined properties */
+ static PropertyRNA *prop_influence = NULL;
+ static PropertyRNA *prop_time = NULL;
+ static bool needs_init = true;
+
+ /* Init the properties on first use */
+ if (needs_init) {
+ prop_influence = RNA_struct_type_find_property(&RNA_NlaStrip, "influence");
+ prop_time = RNA_struct_type_find_property(&RNA_NlaStrip, "strip_time");
+
+ needs_init = false;
+ }
+
+ /* Check if match */
+ if (ELEM(prop, prop_influence, prop_time)) {
+ return true;
+ }
+ }
+
+ /* No criteria met */
+ return false;
}
/* Sanity Validation ------------------------------------ */
static bool nla_editbone_name_check(void *arg, const char *name)
{
- return BLI_ghash_haskey((GHash *)arg, (const void *)name);
+ return BLI_ghash_haskey((GHash *)arg, (const void *)name);
}
/* Find (and set) a unique name for a strip from the whole AnimData block
@@ -1479,56 +1489,63 @@ static bool nla_editbone_name_check(void *arg, const char *name)
*/
void BKE_nlastrip_validate_name(AnimData *adt, NlaStrip *strip)
{
- GHash *gh;
- NlaStrip *tstrip;
- NlaTrack *nlt;
-
- /* sanity checks */
- if (ELEM(NULL, adt, strip))
- return;
-
- /* give strip a default name if none already */
- if (strip->name[0] == 0) {
- switch (strip->type) {
- case NLASTRIP_TYPE_CLIP: /* act-clip */
- BLI_strncpy(strip->name, (strip->act) ? (strip->act->id.name + 2) : ("<No Action>"), sizeof(strip->name));
- break;
- case NLASTRIP_TYPE_TRANSITION: /* transition */
- BLI_strncpy(strip->name, "Transition", sizeof(strip->name));
- break;
- case NLASTRIP_TYPE_META: /* meta */
- BLI_strncpy(strip->name, "Meta", sizeof(strip->name));
- break;
- default:
- BLI_strncpy(strip->name, "NLA Strip", sizeof(strip->name));
- break;
- }
- }
-
- /* build a hash-table of all the strips in the tracks
- * - this is easier than iterating over all the tracks+strips hierarchy every time
- * (and probably faster)
- */
- gh = BLI_ghash_str_new("nlastrip_validate_name gh");
-
- for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
- for (tstrip = nlt->strips.first; tstrip; tstrip = tstrip->next) {
- /* don't add the strip of interest */
- if (tstrip == strip)
- continue;
-
- /* use the name of the strip as the key, and the strip as the value, since we're mostly interested in the keys */
- BLI_ghash_insert(gh, tstrip->name, tstrip);
- }
- }
-
- /* if the hash-table has a match for this name, try other names...
- * - in an extreme case, it might not be able to find a name, but then everything else in Blender would fail too :)
- */
- BLI_uniquename_cb(nla_editbone_name_check, (void *)gh, DATA_("NlaStrip"), '.', strip->name, sizeof(strip->name));
-
- /* free the hash... */
- BLI_ghash_free(gh, NULL, NULL);
+ GHash *gh;
+ NlaStrip *tstrip;
+ NlaTrack *nlt;
+
+ /* sanity checks */
+ if (ELEM(NULL, adt, strip))
+ return;
+
+ /* give strip a default name if none already */
+ if (strip->name[0] == 0) {
+ switch (strip->type) {
+ case NLASTRIP_TYPE_CLIP: /* act-clip */
+ BLI_strncpy(strip->name,
+ (strip->act) ? (strip->act->id.name + 2) : ("<No Action>"),
+ sizeof(strip->name));
+ break;
+ case NLASTRIP_TYPE_TRANSITION: /* transition */
+ BLI_strncpy(strip->name, "Transition", sizeof(strip->name));
+ break;
+ case NLASTRIP_TYPE_META: /* meta */
+ BLI_strncpy(strip->name, "Meta", sizeof(strip->name));
+ break;
+ default:
+ BLI_strncpy(strip->name, "NLA Strip", sizeof(strip->name));
+ break;
+ }
+ }
+
+ /* build a hash-table of all the strips in the tracks
+ * - this is easier than iterating over all the tracks+strips hierarchy every time
+ * (and probably faster)
+ */
+ gh = BLI_ghash_str_new("nlastrip_validate_name gh");
+
+ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ for (tstrip = nlt->strips.first; tstrip; tstrip = tstrip->next) {
+ /* don't add the strip of interest */
+ if (tstrip == strip)
+ continue;
+
+ /* use the name of the strip as the key, and the strip as the value, since we're mostly interested in the keys */
+ BLI_ghash_insert(gh, tstrip->name, tstrip);
+ }
+ }
+
+ /* if the hash-table has a match for this name, try other names...
+ * - in an extreme case, it might not be able to find a name, but then everything else in Blender would fail too :)
+ */
+ BLI_uniquename_cb(nla_editbone_name_check,
+ (void *)gh,
+ DATA_("NlaStrip"),
+ '.',
+ strip->name,
+ sizeof(strip->name));
+
+ /* free the hash... */
+ BLI_ghash_free(gh, NULL, NULL);
}
/* ---- */
@@ -1538,139 +1555,142 @@ void BKE_nlastrip_validate_name(AnimData *adt, NlaStrip *strip)
* - track: nla-track that the overlapping strips should be found from
* - start, end: frames for the offending endpoints
*/
-static void nlastrip_get_endpoint_overlaps(NlaStrip *strip, NlaTrack *track, float **start, float **end)
+static void nlastrip_get_endpoint_overlaps(NlaStrip *strip,
+ NlaTrack *track,
+ float **start,
+ float **end)
{
- NlaStrip *nls;
-
- /* find strips that overlap over the start/end of the given strip,
- * but which don't cover the entire length
- */
- /* TODO: this scheme could get quite slow for doing this on many strips... */
- for (nls = track->strips.first; nls; nls = nls->next) {
- /* check if strip overlaps (extends over or exactly on) the entire range of the strip we're validating */
- if ((nls->start <= strip->start) && (nls->end >= strip->end)) {
- *start = NULL;
- *end = NULL;
- return;
- }
-
- /* check if strip doesn't even occur anywhere near... */
- if (nls->end < strip->start)
- continue; /* skip checking this strip... not worthy of mention */
- if (nls->start > strip->end)
- return; /* the range we're after has already passed */
-
- /* if this strip is not part of an island of continuous strips, it can be used
- * - this check needs to be done for each end of the strip we try and use...
- */
- if ((nls->next == NULL) || IS_EQF(nls->next->start, nls->end) == 0) {
- if ((nls->end > strip->start) && (nls->end < strip->end))
- *start = &nls->end;
- }
- if ((nls->prev == NULL) || IS_EQF(nls->prev->end, nls->start) == 0) {
- if ((nls->start < strip->end) && (nls->start > strip->start))
- *end = &nls->start;
- }
- }
+ NlaStrip *nls;
+
+ /* find strips that overlap over the start/end of the given strip,
+ * but which don't cover the entire length
+ */
+ /* TODO: this scheme could get quite slow for doing this on many strips... */
+ for (nls = track->strips.first; nls; nls = nls->next) {
+ /* check if strip overlaps (extends over or exactly on) the entire range of the strip we're validating */
+ if ((nls->start <= strip->start) && (nls->end >= strip->end)) {
+ *start = NULL;
+ *end = NULL;
+ return;
+ }
+
+ /* check if strip doesn't even occur anywhere near... */
+ if (nls->end < strip->start)
+ continue; /* skip checking this strip... not worthy of mention */
+ if (nls->start > strip->end)
+ return; /* the range we're after has already passed */
+
+ /* if this strip is not part of an island of continuous strips, it can be used
+ * - this check needs to be done for each end of the strip we try and use...
+ */
+ if ((nls->next == NULL) || IS_EQF(nls->next->start, nls->end) == 0) {
+ if ((nls->end > strip->start) && (nls->end < strip->end))
+ *start = &nls->end;
+ }
+ if ((nls->prev == NULL) || IS_EQF(nls->prev->end, nls->start) == 0) {
+ if ((nls->start < strip->end) && (nls->start > strip->start))
+ *end = &nls->start;
+ }
+ }
}
/* Determine auto-blending for the given strip */
static void BKE_nlastrip_validate_autoblends(NlaTrack *nlt, NlaStrip *nls)
{
- float *ps = NULL, *pe = NULL;
- float *ns = NULL, *ne = NULL;
-
- /* sanity checks */
- if (ELEM(NULL, nls, nlt))
- return;
- if ((nlt->prev == NULL) && (nlt->next == NULL))
- return;
- if ((nls->flag & NLASTRIP_FLAG_AUTO_BLENDS) == 0)
- return;
-
- /* get test ranges */
- if (nlt->prev)
- nlastrip_get_endpoint_overlaps(nls, nlt->prev, &ps, &pe);
- if (nlt->next)
- nlastrip_get_endpoint_overlaps(nls, nlt->next, &ns, &ne);
-
- /* set overlaps for this strip
- * - don't use the values obtained though if the end in question
- * is directly followed/preceded by another strip, forming an
- * 'island' of continuous strips
- */
- if ((ps || ns) && ((nls->prev == NULL) || IS_EQF(nls->prev->end, nls->start) == 0)) {
- /* start overlaps - pick the largest overlap */
- if ( ((ps && ns) && (*ps > *ns)) || (ps) )
- nls->blendin = *ps - nls->start;
- else
- nls->blendin = *ns - nls->start;
- }
- else /* no overlap allowed/needed */
- nls->blendin = 0.0f;
-
- if ((pe || ne) && ((nls->next == NULL) || IS_EQF(nls->next->start, nls->end) == 0)) {
- /* end overlaps - pick the largest overlap */
- if ( ((pe && ne) && (*pe > *ne)) || (pe) )
- nls->blendout = nls->end - *pe;
- else
- nls->blendout = nls->end - *ne;
- }
- else /* no overlap allowed/needed */
- nls->blendout = 0.0f;
+ float *ps = NULL, *pe = NULL;
+ float *ns = NULL, *ne = NULL;
+
+ /* sanity checks */
+ if (ELEM(NULL, nls, nlt))
+ return;
+ if ((nlt->prev == NULL) && (nlt->next == NULL))
+ return;
+ if ((nls->flag & NLASTRIP_FLAG_AUTO_BLENDS) == 0)
+ return;
+
+ /* get test ranges */
+ if (nlt->prev)
+ nlastrip_get_endpoint_overlaps(nls, nlt->prev, &ps, &pe);
+ if (nlt->next)
+ nlastrip_get_endpoint_overlaps(nls, nlt->next, &ns, &ne);
+
+ /* set overlaps for this strip
+ * - don't use the values obtained though if the end in question
+ * is directly followed/preceded by another strip, forming an
+ * 'island' of continuous strips
+ */
+ if ((ps || ns) && ((nls->prev == NULL) || IS_EQF(nls->prev->end, nls->start) == 0)) {
+ /* start overlaps - pick the largest overlap */
+ if (((ps && ns) && (*ps > *ns)) || (ps))
+ nls->blendin = *ps - nls->start;
+ else
+ nls->blendin = *ns - nls->start;
+ }
+ else /* no overlap allowed/needed */
+ nls->blendin = 0.0f;
+
+ if ((pe || ne) && ((nls->next == NULL) || IS_EQF(nls->next->start, nls->end) == 0)) {
+ /* end overlaps - pick the largest overlap */
+ if (((pe && ne) && (*pe > *ne)) || (pe))
+ nls->blendout = nls->end - *pe;
+ else
+ nls->blendout = nls->end - *ne;
+ }
+ else /* no overlap allowed/needed */
+ nls->blendout = 0.0f;
}
/* Ensure that auto-blending and other settings are set correctly */
void BKE_nla_validate_state(AnimData *adt)
{
- NlaStrip *strip, *fstrip = NULL;
- NlaTrack *nlt;
-
- /* sanity checks */
- if (ELEM(NULL, adt, adt->nla_tracks.first))
- return;
-
- /* adjust blending values for auto-blending, and also do an initial pass to find the earliest strip */
- for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
- for (strip = nlt->strips.first; strip; strip = strip->next) {
- /* auto-blending first */
- BKE_nlastrip_validate_autoblends(nlt, strip);
-
- /* extend mode - find first strip */
- if ((fstrip == NULL) || (strip->start < fstrip->start))
- fstrip = strip;
- }
- }
-
- /* second pass over the strips to adjust the extend-mode to fix any problems */
- for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
- for (strip = nlt->strips.first; strip; strip = strip->next) {
- /* apart from 'nothing' option which user has to explicitly choose, we don't really know if
- * we should be overwriting the extend setting (but assume that's what the user wanted)
- */
- /* TODO: 1 solution is to tie this in with auto-blending... */
- if (strip->extendmode != NLASTRIP_EXTEND_NOTHING) {
- /* 1) First strip must be set to extend hold, otherwise, stuff before acts dodgy
- * 2) Only overwrite extend mode if *not* changing it will most probably result in
- * occlusion problems, which will occur if...
- * - blendmode = REPLACE
- * - all channels the same (this is fiddly to test, so is currently assumed)
- *
- * Should fix problems such as [#29869]
- */
- if (strip == fstrip)
- strip->extendmode = NLASTRIP_EXTEND_HOLD;
- else if (strip->blendmode == NLASTRIP_MODE_REPLACE)
- strip->extendmode = NLASTRIP_EXTEND_HOLD_FORWARD;
- }
- }
- }
+ NlaStrip *strip, *fstrip = NULL;
+ NlaTrack *nlt;
+
+ /* sanity checks */
+ if (ELEM(NULL, adt, adt->nla_tracks.first))
+ return;
+
+ /* adjust blending values for auto-blending, and also do an initial pass to find the earliest strip */
+ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ for (strip = nlt->strips.first; strip; strip = strip->next) {
+ /* auto-blending first */
+ BKE_nlastrip_validate_autoblends(nlt, strip);
+
+ /* extend mode - find first strip */
+ if ((fstrip == NULL) || (strip->start < fstrip->start))
+ fstrip = strip;
+ }
+ }
+
+ /* second pass over the strips to adjust the extend-mode to fix any problems */
+ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ for (strip = nlt->strips.first; strip; strip = strip->next) {
+ /* apart from 'nothing' option which user has to explicitly choose, we don't really know if
+ * we should be overwriting the extend setting (but assume that's what the user wanted)
+ */
+ /* TODO: 1 solution is to tie this in with auto-blending... */
+ if (strip->extendmode != NLASTRIP_EXTEND_NOTHING) {
+ /* 1) First strip must be set to extend hold, otherwise, stuff before acts dodgy
+ * 2) Only overwrite extend mode if *not* changing it will most probably result in
+ * occlusion problems, which will occur if...
+ * - blendmode = REPLACE
+ * - all channels the same (this is fiddly to test, so is currently assumed)
+ *
+ * Should fix problems such as [#29869]
+ */
+ if (strip == fstrip)
+ strip->extendmode = NLASTRIP_EXTEND_HOLD;
+ else if (strip->blendmode == NLASTRIP_MODE_REPLACE)
+ strip->extendmode = NLASTRIP_EXTEND_HOLD_FORWARD;
+ }
+ }
+ }
}
/* Action Stashing -------------------------------------- */
/* name of stashed tracks - the translation stuff is included here to save extra work */
-#define STASH_TRACK_NAME DATA_("[Action Stash]")
+#define STASH_TRACK_NAME DATA_("[Action Stash]")
/* Check if an action is "stashed" in the NLA already
*
@@ -1680,19 +1700,19 @@ void BKE_nla_validate_state(AnimData *adt)
*/
bool BKE_nla_action_is_stashed(AnimData *adt, bAction *act)
{
- NlaTrack *nlt;
- NlaStrip *strip;
-
- for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
- if (strstr(nlt->name, STASH_TRACK_NAME)) {
- for (strip = nlt->strips.first; strip; strip = strip->next) {
- if (strip->act == act)
- return true;
- }
- }
- }
-
- return false;
+ NlaTrack *nlt;
+ NlaStrip *strip;
+
+ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ if (strstr(nlt->name, STASH_TRACK_NAME)) {
+ for (strip = nlt->strips.first; strip; strip = strip->next) {
+ if (strip->act == act)
+ return true;
+ }
+ }
+ }
+
+ return false;
}
/* "Stash" an action (i.e. store it as a track/layer in the NLA, but non-contributing)
@@ -1700,65 +1720,66 @@ bool BKE_nla_action_is_stashed(AnimData *adt, bAction *act)
*/
bool BKE_nla_action_stash(AnimData *adt)
{
- NlaTrack *prev_track = NULL;
- NlaTrack *nlt;
- NlaStrip *strip;
-
- /* sanity check */
- if (ELEM(NULL, adt, adt->action)) {
- CLOG_ERROR(&LOG, "Invalid argument - %p %p", adt, adt->action);
- return false;
- }
-
- /* do not add if it is already stashed */
- if (BKE_nla_action_is_stashed(adt, adt->action))
- return false;
-
- /* create a new track, and add this immediately above the previous stashing track */
- for (prev_track = adt->nla_tracks.last; prev_track; prev_track = prev_track->prev) {
- if (strstr(prev_track->name, STASH_TRACK_NAME)) {
- break;
- }
- }
-
- nlt = BKE_nlatrack_add(adt, prev_track);
- BLI_assert(nlt != NULL);
-
- /* we need to ensure that if there wasn't any previous instance, it must go to tbe bottom of the stack */
- if (prev_track == NULL) {
- BLI_remlink(&adt->nla_tracks, nlt);
- BLI_addhead(&adt->nla_tracks, nlt);
- }
-
- BLI_strncpy(nlt->name, STASH_TRACK_NAME, sizeof(nlt->name));
- BLI_uniquename(&adt->nla_tracks, nlt, STASH_TRACK_NAME, '.', offsetof(NlaTrack, name), sizeof(nlt->name));
-
- /* add the action as a strip in this new track
- * NOTE: a new user is created here
- */
- strip = BKE_nlastrip_new(adt->action);
- BLI_assert(strip != NULL);
-
- BKE_nlatrack_add_strip(nlt, strip);
- BKE_nlastrip_validate_name(adt, strip);
-
- /* mark the stash track and strip so that they doesn't disturb the stack animation,
- * and are unlikely to draw attention to itself (or be accidentally bumped around)
- *
- * NOTE: this must be done *after* adding the strip to the track, or else
- * the strip locking will prevent the strip from getting added
- */
- nlt->flag = (NLATRACK_MUTED | NLATRACK_PROTECTED);
- strip->flag &= ~(NLASTRIP_FLAG_SELECT | NLASTRIP_FLAG_ACTIVE);
-
- /* also mark the strip for auto syncing the length, so that the strips accurately
- * reflect the length of the action
- * XXX: we could do with some extra flags here to prevent repeats/scaling options from working!
- */
- strip->flag |= NLASTRIP_FLAG_SYNC_LENGTH;
-
- /* succeeded */
- return true;
+ NlaTrack *prev_track = NULL;
+ NlaTrack *nlt;
+ NlaStrip *strip;
+
+ /* sanity check */
+ if (ELEM(NULL, adt, adt->action)) {
+ CLOG_ERROR(&LOG, "Invalid argument - %p %p", adt, adt->action);
+ return false;
+ }
+
+ /* do not add if it is already stashed */
+ if (BKE_nla_action_is_stashed(adt, adt->action))
+ return false;
+
+ /* create a new track, and add this immediately above the previous stashing track */
+ for (prev_track = adt->nla_tracks.last; prev_track; prev_track = prev_track->prev) {
+ if (strstr(prev_track->name, STASH_TRACK_NAME)) {
+ break;
+ }
+ }
+
+ nlt = BKE_nlatrack_add(adt, prev_track);
+ BLI_assert(nlt != NULL);
+
+ /* we need to ensure that if there wasn't any previous instance, it must go to tbe bottom of the stack */
+ if (prev_track == NULL) {
+ BLI_remlink(&adt->nla_tracks, nlt);
+ BLI_addhead(&adt->nla_tracks, nlt);
+ }
+
+ BLI_strncpy(nlt->name, STASH_TRACK_NAME, sizeof(nlt->name));
+ BLI_uniquename(
+ &adt->nla_tracks, nlt, STASH_TRACK_NAME, '.', offsetof(NlaTrack, name), sizeof(nlt->name));
+
+ /* add the action as a strip in this new track
+ * NOTE: a new user is created here
+ */
+ strip = BKE_nlastrip_new(adt->action);
+ BLI_assert(strip != NULL);
+
+ BKE_nlatrack_add_strip(nlt, strip);
+ BKE_nlastrip_validate_name(adt, strip);
+
+ /* mark the stash track and strip so that they doesn't disturb the stack animation,
+ * and are unlikely to draw attention to itself (or be accidentally bumped around)
+ *
+ * NOTE: this must be done *after* adding the strip to the track, or else
+ * the strip locking will prevent the strip from getting added
+ */
+ nlt->flag = (NLATRACK_MUTED | NLATRACK_PROTECTED);
+ strip->flag &= ~(NLASTRIP_FLAG_SELECT | NLASTRIP_FLAG_ACTIVE);
+
+ /* also mark the strip for auto syncing the length, so that the strips accurately
+ * reflect the length of the action
+ * XXX: we could do with some extra flags here to prevent repeats/scaling options from working!
+ */
+ strip->flag |= NLASTRIP_FLAG_SYNC_LENGTH;
+
+ /* succeeded */
+ return true;
}
/* Core Tools ------------------------------------------- */
@@ -1771,74 +1792,74 @@ bool BKE_nla_action_stash(AnimData *adt)
/* TODO: maybe we should have checks for this too... */
void BKE_nla_action_pushdown(AnimData *adt)
{
- NlaStrip *strip;
- const bool is_first = (adt) && (adt->nla_tracks.first == NULL);
-
- /* sanity checks */
- /* TODO: need to report the error for this */
- if (ELEM(NULL, adt, adt->action))
- return;
-
- /* if the action is empty, we also shouldn't try to add to stack,
- * as that will cause us grief down the track
- */
- /* TODO: what about modifiers? */
- if (action_has_motion(adt->action) == 0) {
- CLOG_ERROR(&LOG, "action has no data");
- return;
- }
-
- /* add a new NLA strip to the track, which references the active action */
- strip = BKE_nlastack_add_strip(adt, adt->action);
-
- /* do other necessary work on strip */
- if (strip) {
- /* clear reference to action now that we've pushed it onto the stack */
- id_us_min(&adt->action->id);
- adt->action = NULL;
-
- /* copy current "action blending" settings from adt to the strip,
- * as it was keyframed with these settings, so omitting them will
- * change the effect [T54233]
- *
- * NOTE: We only do this when there are no tracks
- */
- if (is_first == false) {
- strip->blendmode = adt->act_blendmode;
- strip->influence = adt->act_influence;
- strip->extendmode = adt->act_extendmode;
-
- if (adt->act_influence < 1.0f) {
- /* enable "user-controlled" influence (which will insert a default keyframe)
- * so that the influence doesn't get lost on the new update
- *
- * NOTE: An alternative way would have been to instead hack the influence
- * to not get always get reset to full strength if NLASTRIP_FLAG_USR_INFLUENCE
- * is disabled but auto-blending isn't being used. However, that approach
- * is a bit hacky/hard to discover, and may cause backwards compatibility issues,
- * so it's better to just do it this way.
- */
- strip->flag |= NLASTRIP_FLAG_USR_INFLUENCE;
- BKE_nlastrip_validate_fcurves(strip);
- }
- }
-
- /* if the strip is the first one in the track it lives in, check if there
- * are strips in any other tracks that may be before this, and set the extend
- * mode accordingly
- */
- if (nlastrip_is_first(adt, strip) == 0) {
- /* not first, so extend mode can only be NLASTRIP_EXTEND_HOLD_FORWARD not NLASTRIP_EXTEND_HOLD,
- * so that it doesn't override strips in previous tracks
- */
- /* FIXME: this needs to be more automated, since user can rearrange strips */
- if (strip->extendmode == NLASTRIP_EXTEND_HOLD)
- strip->extendmode = NLASTRIP_EXTEND_HOLD_FORWARD;
- }
-
- /* make strip the active one... */
- BKE_nlastrip_set_active(adt, strip);
- }
+ NlaStrip *strip;
+ const bool is_first = (adt) && (adt->nla_tracks.first == NULL);
+
+ /* sanity checks */
+ /* TODO: need to report the error for this */
+ if (ELEM(NULL, adt, adt->action))
+ return;
+
+ /* if the action is empty, we also shouldn't try to add to stack,
+ * as that will cause us grief down the track
+ */
+ /* TODO: what about modifiers? */
+ if (action_has_motion(adt->action) == 0) {
+ CLOG_ERROR(&LOG, "action has no data");
+ return;
+ }
+
+ /* add a new NLA strip to the track, which references the active action */
+ strip = BKE_nlastack_add_strip(adt, adt->action);
+
+ /* do other necessary work on strip */
+ if (strip) {
+ /* clear reference to action now that we've pushed it onto the stack */
+ id_us_min(&adt->action->id);
+ adt->action = NULL;
+
+ /* copy current "action blending" settings from adt to the strip,
+ * as it was keyframed with these settings, so omitting them will
+ * change the effect [T54233]
+ *
+ * NOTE: We only do this when there are no tracks
+ */
+ if (is_first == false) {
+ strip->blendmode = adt->act_blendmode;
+ strip->influence = adt->act_influence;
+ strip->extendmode = adt->act_extendmode;
+
+ if (adt->act_influence < 1.0f) {
+ /* enable "user-controlled" influence (which will insert a default keyframe)
+ * so that the influence doesn't get lost on the new update
+ *
+ * NOTE: An alternative way would have been to instead hack the influence
+ * to not get always get reset to full strength if NLASTRIP_FLAG_USR_INFLUENCE
+ * is disabled but auto-blending isn't being used. However, that approach
+ * is a bit hacky/hard to discover, and may cause backwards compatibility issues,
+ * so it's better to just do it this way.
+ */
+ strip->flag |= NLASTRIP_FLAG_USR_INFLUENCE;
+ BKE_nlastrip_validate_fcurves(strip);
+ }
+ }
+
+ /* if the strip is the first one in the track it lives in, check if there
+ * are strips in any other tracks that may be before this, and set the extend
+ * mode accordingly
+ */
+ if (nlastrip_is_first(adt, strip) == 0) {
+ /* not first, so extend mode can only be NLASTRIP_EXTEND_HOLD_FORWARD not NLASTRIP_EXTEND_HOLD,
+ * so that it doesn't override strips in previous tracks
+ */
+ /* FIXME: this needs to be more automated, since user can rearrange strips */
+ if (strip->extendmode == NLASTRIP_EXTEND_HOLD)
+ strip->extendmode = NLASTRIP_EXTEND_HOLD_FORWARD;
+ }
+
+ /* make strip the active one... */
+ BKE_nlastrip_set_active(adt, strip);
+ }
}
/* Find the active strip + track combo, and set them up as the tweaking track,
@@ -1846,176 +1867,177 @@ void BKE_nla_action_pushdown(AnimData *adt)
*/
bool BKE_nla_tweakmode_enter(AnimData *adt)
{
- NlaTrack *nlt, *activeTrack = NULL;
- NlaStrip *strip, *activeStrip = NULL;
-
- /* verify that data is valid */
- if (ELEM(NULL, adt, adt->nla_tracks.first))
- return false;
-
- /* if block is already in tweakmode, just leave, but we should report
- * that this block is in tweakmode (as our returncode)
- */
- if (adt->flag & ADT_NLA_EDIT_ON)
- return true;
-
- /* go over the tracks, finding the active one, and its active strip
- * - if we cannot find both, then there's nothing to do
- */
- for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
- /* check if active */
- if (nlt->flag & NLATRACK_ACTIVE) {
- /* store reference to this active track */
- activeTrack = nlt;
-
- /* now try to find active strip */
- activeStrip = BKE_nlastrip_find_active(nlt);
- break;
- }
- }
-
- /* There are situations where we may have multiple strips selected and we want to enter tweakmode on all
- * of those at once. Usually in those cases, it will usually just be a single strip per AnimData.
- * In such cases, compromise and take the last selected track and/or last selected strip [#28468]
- */
- if (activeTrack == NULL) {
- /* try last selected track for active strip */
- for (nlt = adt->nla_tracks.last; nlt; nlt = nlt->prev) {
- if (nlt->flag & NLATRACK_SELECTED) {
- /* assume this is the active track */
- activeTrack = nlt;
-
- /* try to find active strip */
- activeStrip = BKE_nlastrip_find_active(nlt);
- break;
- }
- }
- }
- if ((activeTrack) && (activeStrip == NULL)) {
- /* no active strip in active or last selected track; compromise for first selected (assuming only single)... */
- for (strip = activeTrack->strips.first; strip; strip = strip->next) {
- if (strip->flag & (NLASTRIP_FLAG_SELECT | NLASTRIP_FLAG_ACTIVE)) {
- activeStrip = strip;
- break;
- }
- }
- }
-
- if (ELEM(NULL, activeTrack, activeStrip, activeStrip->act)) {
- if (G.debug & G_DEBUG) {
- printf("NLA tweakmode enter - neither active requirement found\n");
- printf("\tactiveTrack = %p, activeStrip = %p\n", (void *)activeTrack, (void *)activeStrip);
- }
- return false;
- }
-
- /* go over all the tracks up to the active one, tagging each strip that uses the same
- * action as the active strip, but leaving everything else alone
- */
- for (nlt = activeTrack->prev; nlt; nlt = nlt->prev) {
- for (strip = nlt->strips.first; strip; strip = strip->next) {
- if (strip->act == activeStrip->act)
- strip->flag |= NLASTRIP_FLAG_TWEAKUSER;
- else
- strip->flag &= ~NLASTRIP_FLAG_TWEAKUSER;
- }
- }
-
- /* tag all other strips in active track that uses the same action as the active strip */
- for (strip = activeTrack->strips.first; strip; strip = strip->next) {
- if ((strip->act == activeStrip->act) && (strip != activeStrip))
- strip->flag |= NLASTRIP_FLAG_TWEAKUSER;
- else
- strip->flag &= ~NLASTRIP_FLAG_TWEAKUSER;
- }
-
- /* go over all the tracks after AND INCLUDING the active one, tagging them as being disabled
- * - the active track needs to also be tagged, otherwise, it'll overlap with the tweaks going on
- */
- for (nlt = activeTrack; nlt; nlt = nlt->next)
- nlt->flag |= NLATRACK_DISABLED;
-
- /* handle AnimData level changes:
- * - 'real' active action to temp storage (no need to change user-counts)
- * - action of active strip set to be the 'active action', and have its usercount incremented
- * - editing-flag for this AnimData block should also get turned on (for more efficient restoring)
- * - take note of the active strip for mapping-correction of keyframes in the action being edited
- */
- adt->tmpact = adt->action;
- adt->action = activeStrip->act;
- adt->act_track = activeTrack;
- adt->actstrip = activeStrip;
- id_us_plus(&activeStrip->act->id);
- adt->flag |= ADT_NLA_EDIT_ON;
-
- /* done! */
- return true;
+ NlaTrack *nlt, *activeTrack = NULL;
+ NlaStrip *strip, *activeStrip = NULL;
+
+ /* verify that data is valid */
+ if (ELEM(NULL, adt, adt->nla_tracks.first))
+ return false;
+
+ /* if block is already in tweakmode, just leave, but we should report
+ * that this block is in tweakmode (as our returncode)
+ */
+ if (adt->flag & ADT_NLA_EDIT_ON)
+ return true;
+
+ /* go over the tracks, finding the active one, and its active strip
+ * - if we cannot find both, then there's nothing to do
+ */
+ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ /* check if active */
+ if (nlt->flag & NLATRACK_ACTIVE) {
+ /* store reference to this active track */
+ activeTrack = nlt;
+
+ /* now try to find active strip */
+ activeStrip = BKE_nlastrip_find_active(nlt);
+ break;
+ }
+ }
+
+ /* There are situations where we may have multiple strips selected and we want to enter tweakmode on all
+ * of those at once. Usually in those cases, it will usually just be a single strip per AnimData.
+ * In such cases, compromise and take the last selected track and/or last selected strip [#28468]
+ */
+ if (activeTrack == NULL) {
+ /* try last selected track for active strip */
+ for (nlt = adt->nla_tracks.last; nlt; nlt = nlt->prev) {
+ if (nlt->flag & NLATRACK_SELECTED) {
+ /* assume this is the active track */
+ activeTrack = nlt;
+
+ /* try to find active strip */
+ activeStrip = BKE_nlastrip_find_active(nlt);
+ break;
+ }
+ }
+ }
+ if ((activeTrack) && (activeStrip == NULL)) {
+ /* no active strip in active or last selected track; compromise for first selected (assuming only single)... */
+ for (strip = activeTrack->strips.first; strip; strip = strip->next) {
+ if (strip->flag & (NLASTRIP_FLAG_SELECT | NLASTRIP_FLAG_ACTIVE)) {
+ activeStrip = strip;
+ break;
+ }
+ }
+ }
+
+ if (ELEM(NULL, activeTrack, activeStrip, activeStrip->act)) {
+ if (G.debug & G_DEBUG) {
+ printf("NLA tweakmode enter - neither active requirement found\n");
+ printf("\tactiveTrack = %p, activeStrip = %p\n", (void *)activeTrack, (void *)activeStrip);
+ }
+ return false;
+ }
+
+ /* go over all the tracks up to the active one, tagging each strip that uses the same
+ * action as the active strip, but leaving everything else alone
+ */
+ for (nlt = activeTrack->prev; nlt; nlt = nlt->prev) {
+ for (strip = nlt->strips.first; strip; strip = strip->next) {
+ if (strip->act == activeStrip->act)
+ strip->flag |= NLASTRIP_FLAG_TWEAKUSER;
+ else
+ strip->flag &= ~NLASTRIP_FLAG_TWEAKUSER;
+ }
+ }
+
+ /* tag all other strips in active track that uses the same action as the active strip */
+ for (strip = activeTrack->strips.first; strip; strip = strip->next) {
+ if ((strip->act == activeStrip->act) && (strip != activeStrip))
+ strip->flag |= NLASTRIP_FLAG_TWEAKUSER;
+ else
+ strip->flag &= ~NLASTRIP_FLAG_TWEAKUSER;
+ }
+
+ /* go over all the tracks after AND INCLUDING the active one, tagging them as being disabled
+ * - the active track needs to also be tagged, otherwise, it'll overlap with the tweaks going on
+ */
+ for (nlt = activeTrack; nlt; nlt = nlt->next)
+ nlt->flag |= NLATRACK_DISABLED;
+
+ /* handle AnimData level changes:
+ * - 'real' active action to temp storage (no need to change user-counts)
+ * - action of active strip set to be the 'active action', and have its usercount incremented
+ * - editing-flag for this AnimData block should also get turned on (for more efficient restoring)
+ * - take note of the active strip for mapping-correction of keyframes in the action being edited
+ */
+ adt->tmpact = adt->action;
+ adt->action = activeStrip->act;
+ adt->act_track = activeTrack;
+ adt->actstrip = activeStrip;
+ id_us_plus(&activeStrip->act->id);
+ adt->flag |= ADT_NLA_EDIT_ON;
+
+ /* done! */
+ return true;
}
/* Exit tweakmode for this AnimData block */
void BKE_nla_tweakmode_exit(AnimData *adt)
{
- NlaStrip *strip;
- NlaTrack *nlt;
-
- /* verify that data is valid */
- if (ELEM(NULL, adt, adt->nla_tracks.first))
- return;
-
- /* hopefully the flag is correct - skip if not on */
- if ((adt->flag & ADT_NLA_EDIT_ON) == 0)
- return;
-
- /* sync the length of the user-strip with the new state of the action
- * but only if the user has explicitly asked for this to happen
- * (see [#34645] for things to be careful about)
- */
- if ((adt->actstrip) && (adt->actstrip->flag & NLASTRIP_FLAG_SYNC_LENGTH)) {
- strip = adt->actstrip;
-
- /* must be action-clip only (transitions don't have scale) */
- if ((strip->type == NLASTRIP_TYPE_CLIP) && (strip->act)) {
- /* recalculate the length of the action */
- calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
-
- /* adjust the strip extents in response to this */
- BKE_nlastrip_recalculate_bounds(strip);
- }
- }
-
- /* for all Tracks, clear the 'disabled' flag
- * for all Strips, clear the 'tweak-user' flag
- */
- for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
- nlt->flag &= ~NLATRACK_DISABLED;
-
- for (strip = nlt->strips.first; strip; strip = strip->next) {
- /* sync strip extents if this strip uses the same action */
- if ((adt->actstrip) && (adt->actstrip->act == strip->act) && (strip->flag & NLASTRIP_FLAG_SYNC_LENGTH)) {
- /* recalculate the length of the action */
- calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
-
- /* adjust the strip extents in response to this */
- BKE_nlastrip_recalculate_bounds(strip);
- }
-
- /* clear tweakuser flag */
- strip->flag &= ~NLASTRIP_FLAG_TWEAKUSER;
- }
- }
-
- /* handle AnimData level changes:
- * - 'temporary' active action needs its usercount decreased, since we're removing this reference
- * - 'real' active action is restored from storage
- * - storage pointer gets cleared (to avoid having bad notes hanging around)
- * - editing-flag for this AnimData block should also get turned off
- * - clear pointer to active strip
- */
- if (adt->action)
- id_us_min(&adt->action->id);
- adt->action = adt->tmpact;
- adt->tmpact = NULL;
- adt->act_track = NULL;
- adt->actstrip = NULL;
- adt->flag &= ~ADT_NLA_EDIT_ON;
+ NlaStrip *strip;
+ NlaTrack *nlt;
+
+ /* verify that data is valid */
+ if (ELEM(NULL, adt, adt->nla_tracks.first))
+ return;
+
+ /* hopefully the flag is correct - skip if not on */
+ if ((adt->flag & ADT_NLA_EDIT_ON) == 0)
+ return;
+
+ /* sync the length of the user-strip with the new state of the action
+ * but only if the user has explicitly asked for this to happen
+ * (see [#34645] for things to be careful about)
+ */
+ if ((adt->actstrip) && (adt->actstrip->flag & NLASTRIP_FLAG_SYNC_LENGTH)) {
+ strip = adt->actstrip;
+
+ /* must be action-clip only (transitions don't have scale) */
+ if ((strip->type == NLASTRIP_TYPE_CLIP) && (strip->act)) {
+ /* recalculate the length of the action */
+ calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
+
+ /* adjust the strip extents in response to this */
+ BKE_nlastrip_recalculate_bounds(strip);
+ }
+ }
+
+ /* for all Tracks, clear the 'disabled' flag
+ * for all Strips, clear the 'tweak-user' flag
+ */
+ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ nlt->flag &= ~NLATRACK_DISABLED;
+
+ for (strip = nlt->strips.first; strip; strip = strip->next) {
+ /* sync strip extents if this strip uses the same action */
+ if ((adt->actstrip) && (adt->actstrip->act == strip->act) &&
+ (strip->flag & NLASTRIP_FLAG_SYNC_LENGTH)) {
+ /* recalculate the length of the action */
+ calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
+
+ /* adjust the strip extents in response to this */
+ BKE_nlastrip_recalculate_bounds(strip);
+ }
+
+ /* clear tweakuser flag */
+ strip->flag &= ~NLASTRIP_FLAG_TWEAKUSER;
+ }
+ }
+
+ /* handle AnimData level changes:
+ * - 'temporary' active action needs its usercount decreased, since we're removing this reference
+ * - 'real' active action is restored from storage
+ * - storage pointer gets cleared (to avoid having bad notes hanging around)
+ * - editing-flag for this AnimData block should also get turned off
+ * - clear pointer to active strip
+ */
+ if (adt->action)
+ id_us_min(&adt->action->id);
+ adt->action = adt->tmpact;
+ adt->tmpact = NULL;
+ adt->act_track = NULL;
+ adt->actstrip = NULL;
+ adt->flag &= ~ADT_NLA_EDIT_ON;
}
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index aabd32d9cb6..ee6faeaee3d 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -81,25 +81,25 @@ static CLG_LogRef LOG = {"bke.node"};
static void node_add_sockets_from_type(bNodeTree *ntree, bNode *node, bNodeType *ntype)
{
- bNodeSocketTemplate *sockdef;
- /* bNodeSocket *sock; */ /* UNUSED */
+ bNodeSocketTemplate *sockdef;
+ /* bNodeSocket *sock; */ /* UNUSED */
- if (ntype->inputs) {
- sockdef = ntype->inputs;
- while (sockdef->type != -1) {
- /* sock = */ node_add_socket_from_template(ntree, node, sockdef, SOCK_IN);
+ if (ntype->inputs) {
+ sockdef = ntype->inputs;
+ while (sockdef->type != -1) {
+ /* sock = */ node_add_socket_from_template(ntree, node, sockdef, SOCK_IN);
- sockdef++;
- }
- }
- if (ntype->outputs) {
- sockdef = ntype->outputs;
- while (sockdef->type != -1) {
- /* sock = */ node_add_socket_from_template(ntree, node, sockdef, SOCK_OUT);
+ sockdef++;
+ }
+ }
+ if (ntype->outputs) {
+ sockdef = ntype->outputs;
+ while (sockdef->type != -1) {
+ /* sock = */ node_add_socket_from_template(ntree, node, sockdef, SOCK_OUT);
- sockdef++;
- }
- }
+ sockdef++;
+ }
+ }
}
/* Note: This function is called to initialize node data based on the type.
@@ -108,152 +108,162 @@ static void node_add_sockets_from_type(bNodeTree *ntree, bNode *node, bNodeType
*/
static void node_init(const struct bContext *C, bNodeTree *ntree, bNode *node)
{
- bNodeType *ntype = node->typeinfo;
- if (ntype == &NodeTypeUndefined)
- return;
+ bNodeType *ntype = node->typeinfo;
+ if (ntype == &NodeTypeUndefined)
+ return;
- /* only do this once */
- if (node->flag & NODE_INIT)
- return;
+ /* only do this once */
+ if (node->flag & NODE_INIT)
+ return;
- node->flag = NODE_SELECT | NODE_OPTIONS | ntype->flag;
- node->width = ntype->width;
- node->miniwidth = 42.0f;
- node->height = ntype->height;
- node->color[0] = node->color[1] = node->color[2] = 0.608; /* default theme color */
- /* initialize the node name with the node label.
- * note: do this after the initfunc so nodes get their data set which may be used in naming
- * (node groups for example) */
- /* XXX Do not use nodeLabel() here, it returns translated content for UI, which should *only* be used
- * in UI, *never* in data... Data have their own translation option!
- * This solution may be a bit rougher than nodeLabel()'s returned string, but it's simpler
- * than adding "do_translate" flags to this func (and labelfunc() as well). */
- BLI_strncpy(node->name, DATA_(ntype->ui_name), NODE_MAXSTR);
- nodeUniqueName(ntree, node);
+ node->flag = NODE_SELECT | NODE_OPTIONS | ntype->flag;
+ node->width = ntype->width;
+ node->miniwidth = 42.0f;
+ node->height = ntype->height;
+ node->color[0] = node->color[1] = node->color[2] = 0.608; /* default theme color */
+ /* initialize the node name with the node label.
+ * note: do this after the initfunc so nodes get their data set which may be used in naming
+ * (node groups for example) */
+ /* XXX Do not use nodeLabel() here, it returns translated content for UI, which should *only* be used
+ * in UI, *never* in data... Data have their own translation option!
+ * This solution may be a bit rougher than nodeLabel()'s returned string, but it's simpler
+ * than adding "do_translate" flags to this func (and labelfunc() as well). */
+ BLI_strncpy(node->name, DATA_(ntype->ui_name), NODE_MAXSTR);
+ nodeUniqueName(ntree, node);
- node_add_sockets_from_type(ntree, node, ntype);
+ node_add_sockets_from_type(ntree, node, ntype);
- if (ntype->initfunc != NULL)
- ntype->initfunc(ntree, node);
+ if (ntype->initfunc != NULL)
+ ntype->initfunc(ntree, node);
- if (ntree->typeinfo->node_add_init != NULL)
- ntree->typeinfo->node_add_init(ntree, node);
+ if (ntree->typeinfo->node_add_init != NULL)
+ ntree->typeinfo->node_add_init(ntree, node);
- if (node->id)
- id_us_plus(node->id);
+ if (node->id)
+ id_us_plus(node->id);
- /* extra init callback */
- if (ntype->initfunc_api) {
- PointerRNA ptr;
- RNA_pointer_create((ID *)ntree, &RNA_Node, node, &ptr);
+ /* extra init callback */
+ if (ntype->initfunc_api) {
+ PointerRNA ptr;
+ RNA_pointer_create((ID *)ntree, &RNA_Node, node, &ptr);
- /* XXX Warning: context can be NULL in case nodes are added in do_versions.
- * Delayed init is not supported for nodes with context-based initfunc_api atm.
- */
- BLI_assert(C != NULL);
- ntype->initfunc_api(C, &ptr);
- }
+ /* XXX Warning: context can be NULL in case nodes are added in do_versions.
+ * Delayed init is not supported for nodes with context-based initfunc_api atm.
+ */
+ BLI_assert(C != NULL);
+ ntype->initfunc_api(C, &ptr);
+ }
- node->flag |= NODE_INIT;
+ node->flag |= NODE_INIT;
}
static void ntree_set_typeinfo(bNodeTree *ntree, bNodeTreeType *typeinfo)
{
- if (typeinfo) {
- ntree->typeinfo = typeinfo;
+ if (typeinfo) {
+ ntree->typeinfo = typeinfo;
- /* deprecated integer type */
- ntree->type = typeinfo->type;
- }
- else {
- ntree->typeinfo = &NodeTreeTypeUndefined;
+ /* deprecated integer type */
+ ntree->type = typeinfo->type;
+ }
+ else {
+ ntree->typeinfo = &NodeTreeTypeUndefined;
- ntree->init &= ~NTREE_TYPE_INIT;
- }
+ ntree->init &= ~NTREE_TYPE_INIT;
+ }
}
-static void node_set_typeinfo(const struct bContext *C, bNodeTree *ntree, bNode *node, bNodeType *typeinfo)
+static void node_set_typeinfo(const struct bContext *C,
+ bNodeTree *ntree,
+ bNode *node,
+ bNodeType *typeinfo)
{
- /* for nodes saved in older versions storage can get lost, make undefined then */
- if (node->flag & NODE_INIT) {
- if (typeinfo && typeinfo->storagename[0] && !node->storage)
- typeinfo = NULL;
- }
+ /* for nodes saved in older versions storage can get lost, make undefined then */
+ if (node->flag & NODE_INIT) {
+ if (typeinfo && typeinfo->storagename[0] && !node->storage)
+ typeinfo = NULL;
+ }
- if (typeinfo) {
- node->typeinfo = typeinfo;
+ if (typeinfo) {
+ node->typeinfo = typeinfo;
- /* deprecated integer type */
- node->type = typeinfo->type;
+ /* deprecated integer type */
+ node->type = typeinfo->type;
- /* initialize the node if necessary */
- node_init(C, ntree, node);
- }
- else {
- node->typeinfo = &NodeTypeUndefined;
+ /* initialize the node if necessary */
+ node_init(C, ntree, node);
+ }
+ else {
+ node->typeinfo = &NodeTypeUndefined;
- ntree->init &= ~NTREE_TYPE_INIT;
- }
+ ntree->init &= ~NTREE_TYPE_INIT;
+ }
}
-static void node_socket_set_typeinfo(bNodeTree *ntree, bNodeSocket *sock, bNodeSocketType *typeinfo)
+static void node_socket_set_typeinfo(bNodeTree *ntree,
+ bNodeSocket *sock,
+ bNodeSocketType *typeinfo)
{
- if (typeinfo) {
- sock->typeinfo = typeinfo;
+ if (typeinfo) {
+ sock->typeinfo = typeinfo;
- /* deprecated integer type */
- sock->type = typeinfo->type;
+ /* deprecated integer type */
+ sock->type = typeinfo->type;
- if (sock->default_value == NULL) {
- /* initialize the default_value pointer used by standard socket types */
- node_socket_init_default_value(sock);
- }
- }
- else {
- sock->typeinfo = &NodeSocketTypeUndefined;
+ if (sock->default_value == NULL) {
+ /* initialize the default_value pointer used by standard socket types */
+ node_socket_init_default_value(sock);
+ }
+ }
+ else {
+ sock->typeinfo = &NodeSocketTypeUndefined;
- ntree->init &= ~NTREE_TYPE_INIT;
- }
+ ntree->init &= ~NTREE_TYPE_INIT;
+ }
}
/* Set specific typeinfo pointers in all node trees on register/unregister */
-static void update_typeinfo(Main *bmain, const struct bContext *C, bNodeTreeType *treetype, bNodeType *nodetype, bNodeSocketType *socktype, bool unregister)
-{
- if (!bmain)
- return;
-
- FOREACH_NODETREE_BEGIN(bmain, ntree, id) {
- bNode *node;
- bNodeSocket *sock;
-
- ntree->init |= NTREE_TYPE_INIT;
-
- if (treetype && STREQ(ntree->idname, treetype->idname))
- ntree_set_typeinfo(ntree, unregister ? NULL : treetype);
-
- /* initialize nodes */
- for (node = ntree->nodes.first; node; node = node->next) {
- if (nodetype && STREQ(node->idname, nodetype->idname))
- node_set_typeinfo(C, ntree, node, unregister ? NULL : nodetype);
-
- /* initialize node sockets */
- for (sock = node->inputs.first; sock; sock = sock->next)
- if (socktype && STREQ(sock->idname, socktype->idname))
- node_socket_set_typeinfo(ntree, sock, unregister ? NULL : socktype);
- for (sock = node->outputs.first; sock; sock = sock->next)
- if (socktype && STREQ(sock->idname, socktype->idname))
- node_socket_set_typeinfo(ntree, sock, unregister ? NULL : socktype);
- }
-
- /* initialize tree sockets */
- for (sock = ntree->inputs.first; sock; sock = sock->next)
- if (socktype && STREQ(sock->idname, socktype->idname))
- node_socket_set_typeinfo(ntree, sock, unregister ? NULL : socktype);
- for (sock = ntree->outputs.first; sock; sock = sock->next)
- if (socktype && STREQ(sock->idname, socktype->idname))
- node_socket_set_typeinfo(ntree, sock, unregister ? NULL : socktype);
- }
- FOREACH_NODETREE_END;
+static void update_typeinfo(Main *bmain,
+ const struct bContext *C,
+ bNodeTreeType *treetype,
+ bNodeType *nodetype,
+ bNodeSocketType *socktype,
+ bool unregister)
+{
+ if (!bmain)
+ return;
+
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ bNode *node;
+ bNodeSocket *sock;
+
+ ntree->init |= NTREE_TYPE_INIT;
+
+ if (treetype && STREQ(ntree->idname, treetype->idname))
+ ntree_set_typeinfo(ntree, unregister ? NULL : treetype);
+
+ /* initialize nodes */
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (nodetype && STREQ(node->idname, nodetype->idname))
+ node_set_typeinfo(C, ntree, node, unregister ? NULL : nodetype);
+
+ /* initialize node sockets */
+ for (sock = node->inputs.first; sock; sock = sock->next)
+ if (socktype && STREQ(sock->idname, socktype->idname))
+ node_socket_set_typeinfo(ntree, sock, unregister ? NULL : socktype);
+ for (sock = node->outputs.first; sock; sock = sock->next)
+ if (socktype && STREQ(sock->idname, socktype->idname))
+ node_socket_set_typeinfo(ntree, sock, unregister ? NULL : socktype);
+ }
+
+ /* initialize tree sockets */
+ for (sock = ntree->inputs.first; sock; sock = sock->next)
+ if (socktype && STREQ(sock->idname, socktype->idname))
+ node_socket_set_typeinfo(ntree, sock, unregister ? NULL : socktype);
+ for (sock = ntree->outputs.first; sock; sock = sock->next)
+ if (socktype && STREQ(sock->idname, socktype->idname))
+ node_socket_set_typeinfo(ntree, sock, unregister ? NULL : socktype);
+ }
+ FOREACH_NODETREE_END;
}
/* Try to initialize all typeinfo in a node tree.
@@ -263,29 +273,28 @@ static void update_typeinfo(Main *bmain, const struct bContext *C, bNodeTreeType
*/
void ntreeSetTypes(const struct bContext *C, bNodeTree *ntree)
{
- bNode *node;
- bNodeSocket *sock;
+ bNode *node;
+ bNodeSocket *sock;
- ntree->init |= NTREE_TYPE_INIT;
+ ntree->init |= NTREE_TYPE_INIT;
- ntree_set_typeinfo(ntree, ntreeTypeFind(ntree->idname));
+ ntree_set_typeinfo(ntree, ntreeTypeFind(ntree->idname));
- for (node = ntree->nodes.first; node; node = node->next) {
- node_set_typeinfo(C, ntree, node, nodeTypeFind(node->idname));
+ for (node = ntree->nodes.first; node; node = node->next) {
+ node_set_typeinfo(C, ntree, node, nodeTypeFind(node->idname));
- for (sock = node->inputs.first; sock; sock = sock->next)
- node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(sock->idname));
- for (sock = node->outputs.first; sock; sock = sock->next)
- node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(sock->idname));
- }
+ for (sock = node->inputs.first; sock; sock = sock->next)
+ node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(sock->idname));
+ for (sock = node->outputs.first; sock; sock = sock->next)
+ node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(sock->idname));
+ }
- for (sock = ntree->inputs.first; sock; sock = sock->next)
- node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(sock->idname));
- for (sock = ntree->outputs.first; sock; sock = sock->next)
- node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(sock->idname));
+ for (sock = ntree->inputs.first; sock; sock = sock->next)
+ node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(sock->idname));
+ for (sock = ntree->outputs.first; sock; sock = sock->next)
+ node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(sock->idname));
}
-
static GHash *nodetreetypes_hash = NULL;
static GHash *nodetypes_hash = NULL;
static GHash *nodesockettypes_hash = NULL;
@@ -293,522 +302,552 @@ static SpinLock spin;
bNodeTreeType *ntreeTypeFind(const char *idname)
{
- bNodeTreeType *nt;
+ bNodeTreeType *nt;
- if (idname[0]) {
- nt = BLI_ghash_lookup(nodetreetypes_hash, idname);
- if (nt)
- return nt;
- }
+ if (idname[0]) {
+ nt = BLI_ghash_lookup(nodetreetypes_hash, idname);
+ if (nt)
+ return nt;
+ }
- return NULL;
+ return NULL;
}
void ntreeTypeAdd(bNodeTreeType *nt)
{
- BLI_ghash_insert(nodetreetypes_hash, nt->idname, nt);
- /* XXX pass Main to register function? */
- /* Probably not. It is pretty much expected we want to update G_MAIN her I think - or we'd want to update *all*
- * active Mains, which we cannot do anyway currently. */
- update_typeinfo(G_MAIN, NULL, nt, NULL, NULL, false);
+ BLI_ghash_insert(nodetreetypes_hash, nt->idname, nt);
+ /* XXX pass Main to register function? */
+ /* Probably not. It is pretty much expected we want to update G_MAIN her I think - or we'd want to update *all*
+ * active Mains, which we cannot do anyway currently. */
+ update_typeinfo(G_MAIN, NULL, nt, NULL, NULL, false);
}
/* callback for hash value free function */
static void ntree_free_type(void *treetype_v)
{
- bNodeTreeType *treetype = treetype_v;
- /* XXX pass Main to unregister function? */
- /* Probably not. It is pretty much expected we want to update G_MAIN her I think - or we'd want to update *all*
- * active Mains, which we cannot do anyway currently. */
- update_typeinfo(G_MAIN, NULL, treetype, NULL, NULL, true);
- MEM_freeN(treetype);
+ bNodeTreeType *treetype = treetype_v;
+ /* XXX pass Main to unregister function? */
+ /* Probably not. It is pretty much expected we want to update G_MAIN her I think - or we'd want to update *all*
+ * active Mains, which we cannot do anyway currently. */
+ update_typeinfo(G_MAIN, NULL, treetype, NULL, NULL, true);
+ MEM_freeN(treetype);
}
void ntreeTypeFreeLink(const bNodeTreeType *nt)
{
- BLI_ghash_remove(nodetreetypes_hash, nt->idname, NULL, ntree_free_type);
+ BLI_ghash_remove(nodetreetypes_hash, nt->idname, NULL, ntree_free_type);
}
bool ntreeIsRegistered(bNodeTree *ntree)
{
- return (ntree->typeinfo != &NodeTreeTypeUndefined);
+ return (ntree->typeinfo != &NodeTreeTypeUndefined);
}
GHashIterator *ntreeTypeGetIterator(void)
{
- return BLI_ghashIterator_new(nodetreetypes_hash);
+ return BLI_ghashIterator_new(nodetreetypes_hash);
}
bNodeType *nodeTypeFind(const char *idname)
{
- bNodeType *nt;
+ bNodeType *nt;
- if (idname[0]) {
- nt = BLI_ghash_lookup(nodetypes_hash, idname);
- if (nt)
- return nt;
- }
+ if (idname[0]) {
+ nt = BLI_ghash_lookup(nodetypes_hash, idname);
+ if (nt)
+ return nt;
+ }
- return NULL;
+ return NULL;
}
static void free_dynamic_typeinfo(bNodeType *ntype)
{
- if (ntype->type == NODE_DYNAMIC) {
- if (ntype->inputs) {
- MEM_freeN(ntype->inputs);
- }
- if (ntype->outputs) {
- MEM_freeN(ntype->outputs);
- }
- }
+ if (ntype->type == NODE_DYNAMIC) {
+ if (ntype->inputs) {
+ MEM_freeN(ntype->inputs);
+ }
+ if (ntype->outputs) {
+ MEM_freeN(ntype->outputs);
+ }
+ }
}
/* callback for hash value free function */
static void node_free_type(void *nodetype_v)
{
- bNodeType *nodetype = nodetype_v;
- /* XXX pass Main to unregister function? */
- /* Probably not. It is pretty much expected we want to update G_MAIN her I think - or we'd want to update *all*
- * active Mains, which we cannot do anyway currently. */
- update_typeinfo(G_MAIN, NULL, NULL, nodetype, NULL, true);
+ bNodeType *nodetype = nodetype_v;
+ /* XXX pass Main to unregister function? */
+ /* Probably not. It is pretty much expected we want to update G_MAIN her I think - or we'd want to update *all*
+ * active Mains, which we cannot do anyway currently. */
+ update_typeinfo(G_MAIN, NULL, NULL, nodetype, NULL, true);
- /* XXX deprecated */
- if (nodetype->type == NODE_DYNAMIC)
- free_dynamic_typeinfo(nodetype);
+ /* XXX deprecated */
+ if (nodetype->type == NODE_DYNAMIC)
+ free_dynamic_typeinfo(nodetype);
- if (nodetype->needs_free)
- MEM_freeN(nodetype);
+ if (nodetype->needs_free)
+ MEM_freeN(nodetype);
}
void nodeRegisterType(bNodeType *nt)
{
- /* debug only: basic verification of registered types */
- BLI_assert(nt->idname[0] != '\0');
- BLI_assert(nt->poll != NULL);
+ /* debug only: basic verification of registered types */
+ BLI_assert(nt->idname[0] != '\0');
+ BLI_assert(nt->poll != NULL);
- BLI_ghash_insert(nodetypes_hash, nt->idname, nt);
- /* XXX pass Main to register function? */
- /* Probably not. It is pretty much expected we want to update G_MAIN her I think - or we'd want to update *all*
- * active Mains, which we cannot do anyway currently. */
- update_typeinfo(G_MAIN, NULL, NULL, nt, NULL, false);
+ BLI_ghash_insert(nodetypes_hash, nt->idname, nt);
+ /* XXX pass Main to register function? */
+ /* Probably not. It is pretty much expected we want to update G_MAIN her I think - or we'd want to update *all*
+ * active Mains, which we cannot do anyway currently. */
+ update_typeinfo(G_MAIN, NULL, NULL, nt, NULL, false);
}
void nodeUnregisterType(bNodeType *nt)
{
- BLI_ghash_remove(nodetypes_hash, nt->idname, NULL, node_free_type);
+ BLI_ghash_remove(nodetypes_hash, nt->idname, NULL, node_free_type);
}
bool nodeIsRegistered(bNode *node)
{
- return (node->typeinfo != &NodeTypeUndefined);
+ return (node->typeinfo != &NodeTypeUndefined);
}
GHashIterator *nodeTypeGetIterator(void)
{
- return BLI_ghashIterator_new(nodetypes_hash);
+ return BLI_ghashIterator_new(nodetypes_hash);
}
bNodeSocketType *nodeSocketTypeFind(const char *idname)
{
- bNodeSocketType *st;
+ bNodeSocketType *st;
- if (idname[0]) {
- st = BLI_ghash_lookup(nodesockettypes_hash, idname);
- if (st)
- return st;
- }
+ if (idname[0]) {
+ st = BLI_ghash_lookup(nodesockettypes_hash, idname);
+ if (st)
+ return st;
+ }
- return NULL;
+ return NULL;
}
/* callback for hash value free function */
static void node_free_socket_type(void *socktype_v)
{
- bNodeSocketType *socktype = socktype_v;
- /* XXX pass Main to unregister function? */
- /* Probably not. It is pretty much expected we want to update G_MAIN her I think - or we'd want to update *all*
- * active Mains, which we cannot do anyway currently. */
- update_typeinfo(G_MAIN, NULL, NULL, NULL, socktype, true);
+ bNodeSocketType *socktype = socktype_v;
+ /* XXX pass Main to unregister function? */
+ /* Probably not. It is pretty much expected we want to update G_MAIN her I think - or we'd want to update *all*
+ * active Mains, which we cannot do anyway currently. */
+ update_typeinfo(G_MAIN, NULL, NULL, NULL, socktype, true);
- MEM_freeN(socktype);
+ MEM_freeN(socktype);
}
void nodeRegisterSocketType(bNodeSocketType *st)
{
- BLI_ghash_insert(nodesockettypes_hash, (void *)st->idname, st);
- /* XXX pass Main to register function? */
- /* Probably not. It is pretty much expected we want to update G_MAIN her I think - or we'd want to update *all*
- * active Mains, which we cannot do anyway currently. */
- update_typeinfo(G_MAIN, NULL, NULL, NULL, st, false);
+ BLI_ghash_insert(nodesockettypes_hash, (void *)st->idname, st);
+ /* XXX pass Main to register function? */
+ /* Probably not. It is pretty much expected we want to update G_MAIN her I think - or we'd want to update *all*
+ * active Mains, which we cannot do anyway currently. */
+ update_typeinfo(G_MAIN, NULL, NULL, NULL, st, false);
}
void nodeUnregisterSocketType(bNodeSocketType *st)
{
- BLI_ghash_remove(nodesockettypes_hash, st->idname, NULL, node_free_socket_type);
+ BLI_ghash_remove(nodesockettypes_hash, st->idname, NULL, node_free_socket_type);
}
bool nodeSocketIsRegistered(bNodeSocket *sock)
{
- return (sock->typeinfo != &NodeSocketTypeUndefined);
+ return (sock->typeinfo != &NodeSocketTypeUndefined);
}
GHashIterator *nodeSocketTypeGetIterator(void)
{
- return BLI_ghashIterator_new(nodesockettypes_hash);
+ return BLI_ghashIterator_new(nodesockettypes_hash);
}
struct bNodeSocket *nodeFindSocket(bNode *node, int in_out, const char *identifier)
{
- bNodeSocket *sock = (in_out == SOCK_IN ? node->inputs.first : node->outputs.first);
- for (; sock; sock = sock->next) {
- if (STREQ(sock->identifier, identifier))
- return sock;
- }
- return NULL;
+ bNodeSocket *sock = (in_out == SOCK_IN ? node->inputs.first : node->outputs.first);
+ for (; sock; sock = sock->next) {
+ if (STREQ(sock->identifier, identifier))
+ return sock;
+ }
+ return NULL;
}
/* find unique socket identifier */
static bool unique_identifier_check(void *arg, const char *identifier)
{
- struct ListBase *lb = arg;
- bNodeSocket *sock;
- for (sock = lb->first; sock; sock = sock->next) {
- if (STREQ(sock->identifier, identifier))
- return true;
- }
- return false;
+ struct ListBase *lb = arg;
+ bNodeSocket *sock;
+ for (sock = lb->first; sock; sock = sock->next) {
+ if (STREQ(sock->identifier, identifier))
+ return true;
+ }
+ return false;
}
-static bNodeSocket *make_socket(bNodeTree *ntree, bNode *UNUSED(node), int in_out, ListBase *lb,
- const char *idname, const char *identifier, const char *name)
+static bNodeSocket *make_socket(bNodeTree *ntree,
+ bNode *UNUSED(node),
+ int in_out,
+ ListBase *lb,
+ const char *idname,
+ const char *identifier,
+ const char *name)
{
- bNodeSocket *sock;
- char auto_identifier[MAX_NAME];
+ bNodeSocket *sock;
+ char auto_identifier[MAX_NAME];
- if (identifier && identifier[0] != '\0') {
- /* use explicit identifier */
- BLI_strncpy(auto_identifier, identifier, sizeof(auto_identifier));
- }
- else {
- /* if no explicit identifier is given, assign a unique identifier based on the name */
- BLI_strncpy(auto_identifier, name, sizeof(auto_identifier));
- }
- /* make the identifier unique */
- BLI_uniquename_cb(unique_identifier_check, lb, "socket", '.', auto_identifier, sizeof(auto_identifier));
+ if (identifier && identifier[0] != '\0') {
+ /* use explicit identifier */
+ BLI_strncpy(auto_identifier, identifier, sizeof(auto_identifier));
+ }
+ else {
+ /* if no explicit identifier is given, assign a unique identifier based on the name */
+ BLI_strncpy(auto_identifier, name, sizeof(auto_identifier));
+ }
+ /* make the identifier unique */
+ BLI_uniquename_cb(
+ unique_identifier_check, lb, "socket", '.', auto_identifier, sizeof(auto_identifier));
- sock = MEM_callocN(sizeof(bNodeSocket), "sock");
- sock->in_out = in_out;
+ sock = MEM_callocN(sizeof(bNodeSocket), "sock");
+ sock->in_out = in_out;
- BLI_strncpy(sock->identifier, auto_identifier, NODE_MAXSTR);
- sock->limit = (in_out == SOCK_IN ? 1 : 0xFFF);
+ BLI_strncpy(sock->identifier, auto_identifier, NODE_MAXSTR);
+ sock->limit = (in_out == SOCK_IN ? 1 : 0xFFF);
- BLI_strncpy(sock->name, name, NODE_MAXSTR);
- sock->storage = NULL;
- sock->flag |= SOCK_COLLAPSED;
- sock->type = SOCK_CUSTOM; /* int type undefined by default */
+ BLI_strncpy(sock->name, name, NODE_MAXSTR);
+ sock->storage = NULL;
+ sock->flag |= SOCK_COLLAPSED;
+ sock->type = SOCK_CUSTOM; /* int type undefined by default */
- BLI_strncpy(sock->idname, idname, sizeof(sock->idname));
- node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(idname));
+ BLI_strncpy(sock->idname, idname, sizeof(sock->idname));
+ node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(idname));
- return sock;
+ return sock;
}
-void nodeModifySocketType(bNodeTree *ntree, bNode *UNUSED(node), bNodeSocket *sock,
- int type, int subtype)
+void nodeModifySocketType(
+ bNodeTree *ntree, bNode *UNUSED(node), bNodeSocket *sock, int type, int subtype)
{
- const char *idname = nodeStaticSocketType(type, subtype);
+ const char *idname = nodeStaticSocketType(type, subtype);
- if (!idname) {
- CLOG_ERROR(&LOG, "static node socket type %d undefined", type);
- return;
- }
+ if (!idname) {
+ CLOG_ERROR(&LOG, "static node socket type %d undefined", type);
+ return;
+ }
- if (sock->default_value) {
- MEM_freeN(sock->default_value);
- sock->default_value = NULL;
- }
+ if (sock->default_value) {
+ MEM_freeN(sock->default_value);
+ sock->default_value = NULL;
+ }
- sock->type = type;
- BLI_strncpy(sock->idname, idname, sizeof(sock->idname));
- node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(idname));
+ sock->type = type;
+ BLI_strncpy(sock->idname, idname, sizeof(sock->idname));
+ node_socket_set_typeinfo(ntree, sock, nodeSocketTypeFind(idname));
}
-bNodeSocket *nodeAddSocket(bNodeTree *ntree, bNode *node, int in_out, const char *idname,
- const char *identifier, const char *name)
+bNodeSocket *nodeAddSocket(bNodeTree *ntree,
+ bNode *node,
+ int in_out,
+ const char *idname,
+ const char *identifier,
+ const char *name)
{
- ListBase *lb = (in_out == SOCK_IN ? &node->inputs : &node->outputs);
- bNodeSocket *sock = make_socket(ntree, node, in_out, lb, idname, identifier, name);
+ ListBase *lb = (in_out == SOCK_IN ? &node->inputs : &node->outputs);
+ bNodeSocket *sock = make_socket(ntree, node, in_out, lb, idname, identifier, name);
- BLI_remlink(lb, sock); /* does nothing for new socket */
- BLI_addtail(lb, sock);
+ BLI_remlink(lb, sock); /* does nothing for new socket */
+ BLI_addtail(lb, sock);
- node->update |= NODE_UPDATE;
+ node->update |= NODE_UPDATE;
- return sock;
+ return sock;
}
-bNodeSocket *nodeInsertSocket(bNodeTree *ntree, bNode *node, int in_out, const char *idname,
- bNodeSocket *next_sock, const char *identifier, const char *name)
+bNodeSocket *nodeInsertSocket(bNodeTree *ntree,
+ bNode *node,
+ int in_out,
+ const char *idname,
+ bNodeSocket *next_sock,
+ const char *identifier,
+ const char *name)
{
- ListBase *lb = (in_out == SOCK_IN ? &node->inputs : &node->outputs);
- bNodeSocket *sock = make_socket(ntree, node, in_out, lb, idname, identifier, name);
+ ListBase *lb = (in_out == SOCK_IN ? &node->inputs : &node->outputs);
+ bNodeSocket *sock = make_socket(ntree, node, in_out, lb, idname, identifier, name);
- BLI_remlink(lb, sock); /* does nothing for new socket */
- BLI_insertlinkbefore(lb, next_sock, sock);
+ BLI_remlink(lb, sock); /* does nothing for new socket */
+ BLI_insertlinkbefore(lb, next_sock, sock);
- node->update |= NODE_UPDATE;
+ node->update |= NODE_UPDATE;
- return sock;
+ return sock;
}
const char *nodeStaticSocketType(int type, int subtype)
{
- switch (type) {
- case SOCK_FLOAT:
- switch (subtype) {
- case PROP_UNSIGNED:
- return "NodeSocketFloatUnsigned";
- case PROP_PERCENTAGE:
- return "NodeSocketFloatPercentage";
- case PROP_FACTOR:
- return "NodeSocketFloatFactor";
- case PROP_ANGLE:
- return "NodeSocketFloatAngle";
- case PROP_TIME:
- return "NodeSocketFloatTime";
- case PROP_NONE:
- default:
- return "NodeSocketFloat";
- }
- case SOCK_INT:
- switch (subtype) {
- case PROP_UNSIGNED:
- return "NodeSocketIntUnsigned";
- case PROP_PERCENTAGE:
- return "NodeSocketIntPercentage";
- case PROP_FACTOR:
- return "NodeSocketIntFactor";
- case PROP_NONE:
- default:
- return "NodeSocketInt";
- }
- case SOCK_BOOLEAN:
- return "NodeSocketBool";
- case SOCK_VECTOR:
- switch (subtype) {
- case PROP_TRANSLATION:
- return "NodeSocketVectorTranslation";
- case PROP_DIRECTION:
- return "NodeSocketVectorDirection";
- case PROP_VELOCITY:
- return "NodeSocketVectorVelocity";
- case PROP_ACCELERATION:
- return "NodeSocketVectorAcceleration";
- case PROP_EULER:
- return "NodeSocketVectorEuler";
- case PROP_XYZ:
- return "NodeSocketVectorXYZ";
- case PROP_NONE:
- default:
- return "NodeSocketVector";
- }
- case SOCK_RGBA:
- return "NodeSocketColor";
- case SOCK_STRING:
- return "NodeSocketString";
- case SOCK_SHADER:
- return "NodeSocketShader";
- }
- return NULL;
+ switch (type) {
+ case SOCK_FLOAT:
+ switch (subtype) {
+ case PROP_UNSIGNED:
+ return "NodeSocketFloatUnsigned";
+ case PROP_PERCENTAGE:
+ return "NodeSocketFloatPercentage";
+ case PROP_FACTOR:
+ return "NodeSocketFloatFactor";
+ case PROP_ANGLE:
+ return "NodeSocketFloatAngle";
+ case PROP_TIME:
+ return "NodeSocketFloatTime";
+ case PROP_NONE:
+ default:
+ return "NodeSocketFloat";
+ }
+ case SOCK_INT:
+ switch (subtype) {
+ case PROP_UNSIGNED:
+ return "NodeSocketIntUnsigned";
+ case PROP_PERCENTAGE:
+ return "NodeSocketIntPercentage";
+ case PROP_FACTOR:
+ return "NodeSocketIntFactor";
+ case PROP_NONE:
+ default:
+ return "NodeSocketInt";
+ }
+ case SOCK_BOOLEAN:
+ return "NodeSocketBool";
+ case SOCK_VECTOR:
+ switch (subtype) {
+ case PROP_TRANSLATION:
+ return "NodeSocketVectorTranslation";
+ case PROP_DIRECTION:
+ return "NodeSocketVectorDirection";
+ case PROP_VELOCITY:
+ return "NodeSocketVectorVelocity";
+ case PROP_ACCELERATION:
+ return "NodeSocketVectorAcceleration";
+ case PROP_EULER:
+ return "NodeSocketVectorEuler";
+ case PROP_XYZ:
+ return "NodeSocketVectorXYZ";
+ case PROP_NONE:
+ default:
+ return "NodeSocketVector";
+ }
+ case SOCK_RGBA:
+ return "NodeSocketColor";
+ case SOCK_STRING:
+ return "NodeSocketString";
+ case SOCK_SHADER:
+ return "NodeSocketShader";
+ }
+ return NULL;
}
const char *nodeStaticSocketInterfaceType(int type, int subtype)
{
- switch (type) {
- case SOCK_FLOAT:
- switch (subtype) {
- case PROP_UNSIGNED:
- return "NodeSocketInterfaceFloatUnsigned";
- case PROP_PERCENTAGE:
- return "NodeSocketInterfaceFloatPercentage";
- case PROP_FACTOR:
- return "NodeSocketInterfaceFloatFactor";
- case PROP_ANGLE:
- return "NodeSocketInterfaceFloatAngle";
- case PROP_TIME:
- return "NodeSocketInterfaceFloatTime";
- case PROP_NONE:
- default:
- return "NodeSocketInterfaceFloat";
- }
- case SOCK_INT:
- switch (subtype) {
- case PROP_UNSIGNED:
- return "NodeSocketInterfaceIntUnsigned";
- case PROP_PERCENTAGE:
- return "NodeSocketInterfaceIntPercentage";
- case PROP_FACTOR:
- return "NodeSocketInterfaceIntFactor";
- case PROP_NONE:
- default:
- return "NodeSocketInterfaceInt";
- }
- case SOCK_BOOLEAN:
- return "NodeSocketInterfaceBool";
- case SOCK_VECTOR:
- switch (subtype) {
- case PROP_TRANSLATION:
- return "NodeSocketInterfaceVectorTranslation";
- case PROP_DIRECTION:
- return "NodeSocketInterfaceVectorDirection";
- case PROP_VELOCITY:
- return "NodeSocketInterfaceVectorVelocity";
- case PROP_ACCELERATION:
- return "NodeSocketInterfaceVectorAcceleration";
- case PROP_EULER:
- return "NodeSocketInterfaceVectorEuler";
- case PROP_XYZ:
- return "NodeSocketInterfaceVectorXYZ";
- case PROP_NONE:
- default:
- return "NodeSocketInterfaceVector";
- }
- case SOCK_RGBA:
- return "NodeSocketInterfaceColor";
- case SOCK_STRING:
- return "NodeSocketInterfaceString";
- case SOCK_SHADER:
- return "NodeSocketInterfaceShader";
- }
- return NULL;
-}
-
-bNodeSocket *nodeAddStaticSocket(bNodeTree *ntree, bNode *node, int in_out, int type, int subtype,
- const char *identifier, const char *name)
-{
- const char *idname = nodeStaticSocketType(type, subtype);
- bNodeSocket *sock;
-
- if (!idname) {
- CLOG_ERROR(&LOG, "static node socket type %d undefined", type);
- return NULL;
- }
-
- sock = nodeAddSocket(ntree, node, in_out, idname, identifier, name);
- sock->type = type;
- return sock;
-}
-
-bNodeSocket *nodeInsertStaticSocket(bNodeTree *ntree, bNode *node, int in_out, int type, int subtype,
- bNodeSocket *next_sock, const char *identifier, const char *name)
-{
- const char *idname = nodeStaticSocketType(type, subtype);
- bNodeSocket *sock;
-
- if (!idname) {
- CLOG_ERROR(&LOG, "static node socket type %d undefined", type);
- return NULL;
- }
-
- sock = nodeInsertSocket(ntree, node, in_out, idname, next_sock, identifier, name);
- sock->type = type;
- return sock;
-}
-
-static void node_socket_free(bNodeTree *UNUSED(ntree), bNodeSocket *sock, bNode *UNUSED(node), const bool do_id_user)
-{
- if (sock->prop) {
- IDP_FreeProperty_ex(sock->prop, do_id_user);
- MEM_freeN(sock->prop);
- }
-
- if (sock->default_value)
- MEM_freeN(sock->default_value);
+ switch (type) {
+ case SOCK_FLOAT:
+ switch (subtype) {
+ case PROP_UNSIGNED:
+ return "NodeSocketInterfaceFloatUnsigned";
+ case PROP_PERCENTAGE:
+ return "NodeSocketInterfaceFloatPercentage";
+ case PROP_FACTOR:
+ return "NodeSocketInterfaceFloatFactor";
+ case PROP_ANGLE:
+ return "NodeSocketInterfaceFloatAngle";
+ case PROP_TIME:
+ return "NodeSocketInterfaceFloatTime";
+ case PROP_NONE:
+ default:
+ return "NodeSocketInterfaceFloat";
+ }
+ case SOCK_INT:
+ switch (subtype) {
+ case PROP_UNSIGNED:
+ return "NodeSocketInterfaceIntUnsigned";
+ case PROP_PERCENTAGE:
+ return "NodeSocketInterfaceIntPercentage";
+ case PROP_FACTOR:
+ return "NodeSocketInterfaceIntFactor";
+ case PROP_NONE:
+ default:
+ return "NodeSocketInterfaceInt";
+ }
+ case SOCK_BOOLEAN:
+ return "NodeSocketInterfaceBool";
+ case SOCK_VECTOR:
+ switch (subtype) {
+ case PROP_TRANSLATION:
+ return "NodeSocketInterfaceVectorTranslation";
+ case PROP_DIRECTION:
+ return "NodeSocketInterfaceVectorDirection";
+ case PROP_VELOCITY:
+ return "NodeSocketInterfaceVectorVelocity";
+ case PROP_ACCELERATION:
+ return "NodeSocketInterfaceVectorAcceleration";
+ case PROP_EULER:
+ return "NodeSocketInterfaceVectorEuler";
+ case PROP_XYZ:
+ return "NodeSocketInterfaceVectorXYZ";
+ case PROP_NONE:
+ default:
+ return "NodeSocketInterfaceVector";
+ }
+ case SOCK_RGBA:
+ return "NodeSocketInterfaceColor";
+ case SOCK_STRING:
+ return "NodeSocketInterfaceString";
+ case SOCK_SHADER:
+ return "NodeSocketInterfaceShader";
+ }
+ return NULL;
+}
+
+bNodeSocket *nodeAddStaticSocket(bNodeTree *ntree,
+ bNode *node,
+ int in_out,
+ int type,
+ int subtype,
+ const char *identifier,
+ const char *name)
+{
+ const char *idname = nodeStaticSocketType(type, subtype);
+ bNodeSocket *sock;
+
+ if (!idname) {
+ CLOG_ERROR(&LOG, "static node socket type %d undefined", type);
+ return NULL;
+ }
+
+ sock = nodeAddSocket(ntree, node, in_out, idname, identifier, name);
+ sock->type = type;
+ return sock;
+}
+
+bNodeSocket *nodeInsertStaticSocket(bNodeTree *ntree,
+ bNode *node,
+ int in_out,
+ int type,
+ int subtype,
+ bNodeSocket *next_sock,
+ const char *identifier,
+ const char *name)
+{
+ const char *idname = nodeStaticSocketType(type, subtype);
+ bNodeSocket *sock;
+
+ if (!idname) {
+ CLOG_ERROR(&LOG, "static node socket type %d undefined", type);
+ return NULL;
+ }
+
+ sock = nodeInsertSocket(ntree, node, in_out, idname, next_sock, identifier, name);
+ sock->type = type;
+ return sock;
+}
+
+static void node_socket_free(bNodeTree *UNUSED(ntree),
+ bNodeSocket *sock,
+ bNode *UNUSED(node),
+ const bool do_id_user)
+{
+ if (sock->prop) {
+ IDP_FreeProperty_ex(sock->prop, do_id_user);
+ MEM_freeN(sock->prop);
+ }
+
+ if (sock->default_value)
+ MEM_freeN(sock->default_value);
}
void nodeRemoveSocket(bNodeTree *ntree, bNode *node, bNodeSocket *sock)
{
- bNodeLink *link, *next;
+ bNodeLink *link, *next;
- for (link = ntree->links.first; link; link = next) {
- next = link->next;
- if (link->fromsock == sock || link->tosock == sock) {
- nodeRemLink(ntree, link);
- }
- }
+ for (link = ntree->links.first; link; link = next) {
+ next = link->next;
+ if (link->fromsock == sock || link->tosock == sock) {
+ nodeRemLink(ntree, link);
+ }
+ }
- /* this is fast, this way we don't need an in_out argument */
- BLI_remlink(&node->inputs, sock);
- BLI_remlink(&node->outputs, sock);
+ /* this is fast, this way we don't need an in_out argument */
+ BLI_remlink(&node->inputs, sock);
+ BLI_remlink(&node->outputs, sock);
- node_socket_free(ntree, sock, node, true);
- MEM_freeN(sock);
+ node_socket_free(ntree, sock, node, true);
+ MEM_freeN(sock);
- node->update |= NODE_UPDATE;
+ node->update |= NODE_UPDATE;
}
void nodeRemoveAllSockets(bNodeTree *ntree, bNode *node)
{
- bNodeSocket *sock, *sock_next;
- bNodeLink *link, *next;
+ bNodeSocket *sock, *sock_next;
+ bNodeLink *link, *next;
- for (link = ntree->links.first; link; link = next) {
- next = link->next;
- if (link->fromnode == node || link->tonode == node) {
- nodeRemLink(ntree, link);
- }
- }
+ for (link = ntree->links.first; link; link = next) {
+ next = link->next;
+ if (link->fromnode == node || link->tonode == node) {
+ nodeRemLink(ntree, link);
+ }
+ }
- for (sock = node->inputs.first; sock; sock = sock_next) {
- sock_next = sock->next;
- node_socket_free(ntree, sock, node, true);
- MEM_freeN(sock);
- }
- BLI_listbase_clear(&node->inputs);
+ for (sock = node->inputs.first; sock; sock = sock_next) {
+ sock_next = sock->next;
+ node_socket_free(ntree, sock, node, true);
+ MEM_freeN(sock);
+ }
+ BLI_listbase_clear(&node->inputs);
- for (sock = node->outputs.first; sock; sock = sock_next) {
- sock_next = sock->next;
- node_socket_free(ntree, sock, node, true);
- MEM_freeN(sock);
- }
- BLI_listbase_clear(&node->outputs);
+ for (sock = node->outputs.first; sock; sock = sock_next) {
+ sock_next = sock->next;
+ node_socket_free(ntree, sock, node, true);
+ MEM_freeN(sock);
+ }
+ BLI_listbase_clear(&node->outputs);
- node->update |= NODE_UPDATE;
+ node->update |= NODE_UPDATE;
}
/* finds a node based on its name */
bNode *nodeFindNodebyName(bNodeTree *ntree, const char *name)
{
- return BLI_findstring(&ntree->nodes, name, offsetof(bNode, name));
+ return BLI_findstring(&ntree->nodes, name, offsetof(bNode, name));
}
/* finds a node based on given socket */
int nodeFindNode(bNodeTree *ntree, bNodeSocket *sock, bNode **nodep, int *sockindex)
{
- int in_out = sock->in_out;
- bNode *node;
- bNodeSocket *tsock;
- int index = 0;
+ int in_out = sock->in_out;
+ bNode *node;
+ bNodeSocket *tsock;
+ int index = 0;
- for (node = ntree->nodes.first; node; node = node->next) {
- tsock = (in_out == SOCK_IN ? node->inputs.first : node->outputs.first);
- for (index = 0; tsock; tsock = tsock->next, index++) {
- if (tsock == sock)
- break;
- }
- if (tsock)
- break;
- }
+ for (node = ntree->nodes.first; node; node = node->next) {
+ tsock = (in_out == SOCK_IN ? node->inputs.first : node->outputs.first);
+ for (index = 0; tsock; tsock = tsock->next, index++) {
+ if (tsock == sock)
+ break;
+ }
+ if (tsock)
+ break;
+ }
- if (node) {
- *nodep = node;
- if (sockindex) *sockindex = index;
- return 1;
- }
+ if (node) {
+ *nodep = node;
+ if (sockindex)
+ *sockindex = index;
+ return 1;
+ }
- *nodep = NULL;
- return 0;
+ *nodep = NULL;
+ return 0;
}
/**
@@ -816,12 +855,12 @@ int nodeFindNode(bNodeTree *ntree, bNodeSocket *sock, bNode **nodep, int *sockin
*/
bNode *nodeFindRootParent(bNode *node)
{
- if (node->parent) {
- return nodeFindRootParent(node->parent);
- }
- else {
- return node->type == NODE_FRAME ? node : NULL;
- }
+ if (node->parent) {
+ return nodeFindRootParent(node->parent);
+ }
+ else {
+ return node->type == NODE_FRAME ? node : NULL;
+ }
}
/**
@@ -830,13 +869,13 @@ bNode *nodeFindRootParent(bNode *node)
*/
bool nodeIsChildOf(const bNode *parent, const bNode *child)
{
- if (parent == child) {
- return true;
- }
- else if (child->parent) {
- return nodeIsChildOf(parent, child->parent);
- }
- return false;
+ if (parent == child) {
+ return true;
+ }
+ else if (child->parent) {
+ return nodeIsChildOf(parent, child->parent);
+ }
+ return false;
}
/**
@@ -846,30 +885,31 @@ bool nodeIsChildOf(const bNode *parent, const bNode *child)
* \param reversed: for backwards iteration
* \note Recursive
*/
-void nodeChainIter(
- const bNodeTree *ntree, const bNode *node_start,
- bool (*callback)(bNode *, bNode *, void *, const bool), void *userdata,
- const bool reversed)
-{
- bNodeLink *link;
-
- for (link = ntree->links.first; link; link = link->next) {
- if ((link->flag & NODE_LINK_VALID) == 0) {
- /* Skip links marked as cyclic. */
- continue;
- }
- if (link->tonode && link->fromnode) {
- /* is the link part of the chain meaning node_start == fromnode (or tonode for reversed case)? */
- if ((reversed && (link->tonode == node_start)) ||
- (!reversed && link->fromnode == node_start))
- {
- if (!callback(link->fromnode, link->tonode, userdata, reversed)) {
- return;
- }
- nodeChainIter(ntree, reversed ? link->fromnode : link->tonode, callback, userdata, reversed);
- }
- }
- }
+void nodeChainIter(const bNodeTree *ntree,
+ const bNode *node_start,
+ bool (*callback)(bNode *, bNode *, void *, const bool),
+ void *userdata,
+ const bool reversed)
+{
+ bNodeLink *link;
+
+ for (link = ntree->links.first; link; link = link->next) {
+ if ((link->flag & NODE_LINK_VALID) == 0) {
+ /* Skip links marked as cyclic. */
+ continue;
+ }
+ if (link->tonode && link->fromnode) {
+ /* is the link part of the chain meaning node_start == fromnode (or tonode for reversed case)? */
+ if ((reversed && (link->tonode == node_start)) ||
+ (!reversed && link->fromnode == node_start)) {
+ if (!callback(link->fromnode, link->tonode, userdata, reversed)) {
+ return;
+ }
+ nodeChainIter(
+ ntree, reversed ? link->fromnode : link->tonode, callback, userdata, reversed);
+ }
+ }
+ }
}
/**
@@ -879,12 +919,12 @@ void nodeChainIter(
*/
void nodeParentsIter(bNode *node, bool (*callback)(bNode *, void *), void *userdata)
{
- if (node->parent) {
- if (!callback(node->parent, userdata)) {
- return;
- }
- nodeParentsIter(node->parent, callback, userdata);
- }
+ if (node->parent) {
+ if (!callback(node->parent, userdata)) {
+ return;
+ }
+ nodeParentsIter(node->parent, callback, userdata);
+ }
}
/* ************** Add stuff ********** */
@@ -892,397 +932,398 @@ void nodeParentsIter(bNode *node, bool (*callback)(bNode *, void *), void *userd
/* Find the first available, non-duplicate name for a given node */
void nodeUniqueName(bNodeTree *ntree, bNode *node)
{
- BLI_uniquename(&ntree->nodes, node, DATA_("Node"), '.', offsetof(bNode, name), sizeof(node->name));
+ BLI_uniquename(
+ &ntree->nodes, node, DATA_("Node"), '.', offsetof(bNode, name), sizeof(node->name));
}
bNode *nodeAddNode(const struct bContext *C, bNodeTree *ntree, const char *idname)
{
- bNode *node;
+ bNode *node;
- node = MEM_callocN(sizeof(bNode), "new node");
- BLI_addtail(&ntree->nodes, node);
+ node = MEM_callocN(sizeof(bNode), "new node");
+ BLI_addtail(&ntree->nodes, node);
- BLI_strncpy(node->idname, idname, sizeof(node->idname));
- node_set_typeinfo(C, ntree, node, nodeTypeFind(idname));
+ BLI_strncpy(node->idname, idname, sizeof(node->idname));
+ node_set_typeinfo(C, ntree, node, nodeTypeFind(idname));
- ntree->update |= NTREE_UPDATE_NODES;
+ ntree->update |= NTREE_UPDATE_NODES;
- return node;
+ return node;
}
bNode *nodeAddStaticNode(const struct bContext *C, bNodeTree *ntree, int type)
{
- const char *idname = NULL;
-
- NODE_TYPES_BEGIN(ntype) {
- /* do an extra poll here, because some int types are used
- * for multiple node types, this helps find the desired type
- */
- if (ntype->type == type && (!ntype->poll || ntype->poll(ntype, ntree))) {
- idname = ntype->idname;
- break;
- }
- } NODE_TYPES_END;
- if (!idname) {
- CLOG_ERROR(&LOG, "static node type %d undefined", type);
- return NULL;
- }
- return nodeAddNode(C, ntree, idname);
+ const char *idname = NULL;
+
+ NODE_TYPES_BEGIN (ntype) {
+ /* do an extra poll here, because some int types are used
+ * for multiple node types, this helps find the desired type
+ */
+ if (ntype->type == type && (!ntype->poll || ntype->poll(ntype, ntree))) {
+ idname = ntype->idname;
+ break;
+ }
+ }
+ NODE_TYPES_END;
+ if (!idname) {
+ CLOG_ERROR(&LOG, "static node type %d undefined", type);
+ return NULL;
+ }
+ return nodeAddNode(C, ntree, idname);
}
static void node_socket_copy(bNodeSocket *sock_dst, bNodeSocket *sock_src, const int flag)
{
- sock_src->new_sock = sock_dst;
+ sock_src->new_sock = sock_dst;
- if (sock_src->prop) {
- sock_dst->prop = IDP_CopyProperty_ex(sock_src->prop, flag);
- }
+ if (sock_src->prop) {
+ sock_dst->prop = IDP_CopyProperty_ex(sock_src->prop, flag);
+ }
- if (sock_src->default_value) {
- sock_dst->default_value = MEM_dupallocN(sock_src->default_value);
- }
+ if (sock_src->default_value) {
+ sock_dst->default_value = MEM_dupallocN(sock_src->default_value);
+ }
- sock_dst->stack_index = 0;
- /* XXX some compositor node (e.g. image, render layers) still store
- * some persistent buffer data here, need to clear this to avoid dangling pointers.
- */
- sock_dst->cache = NULL;
+ sock_dst->stack_index = 0;
+ /* XXX some compositor node (e.g. image, render layers) still store
+ * some persistent buffer data here, need to clear this to avoid dangling pointers.
+ */
+ sock_dst->cache = NULL;
}
/* keep socket listorder identical, for copying links */
/* ntree is the target tree */
bNode *BKE_node_copy_ex(bNodeTree *ntree, bNode *node_src, const int flag)
{
- bNode *node_dst = MEM_callocN(sizeof(bNode), "dupli node");
- bNodeSocket *sock_dst, *sock_src;
- bNodeLink *link_dst, *link_src;
-
- *node_dst = *node_src;
- /* can be called for nodes outside a node tree (e.g. clipboard) */
- if (ntree) {
- nodeUniqueName(ntree, node_dst);
-
- BLI_addtail(&ntree->nodes, node_dst);
- }
-
- BLI_duplicatelist(&node_dst->inputs, &node_src->inputs);
- for (sock_dst = node_dst->inputs.first, sock_src = node_src->inputs.first;
- sock_dst != NULL;
- sock_dst = sock_dst->next, sock_src = sock_src->next)
- {
- node_socket_copy(sock_dst, sock_src, flag);
- }
-
- BLI_duplicatelist(&node_dst->outputs, &node_src->outputs);
- for (sock_dst = node_dst->outputs.first, sock_src = node_src->outputs.first;
- sock_dst != NULL;
- sock_dst = sock_dst->next, sock_src = sock_src->next)
- {
- node_socket_copy(sock_dst, sock_src, flag);
- }
-
- if (node_src->prop) {
- node_dst->prop = IDP_CopyProperty_ex(node_src->prop, flag);
- }
-
- BLI_duplicatelist(&node_dst->internal_links, &node_src->internal_links);
- for (link_dst = node_dst->internal_links.first, link_src = node_src->internal_links.first;
- link_dst != NULL;
- link_dst = link_dst->next, link_src = link_src->next)
- {
- link_dst->fromnode = node_dst;
- link_dst->tonode = node_dst;
- link_dst->fromsock = link_dst->fromsock->new_sock;
- link_dst->tosock = link_dst->tosock->new_sock;
- }
-
- if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- id_us_plus(node_dst->id);
- }
-
- if (node_src->typeinfo->copyfunc) {
- node_src->typeinfo->copyfunc(ntree, node_dst, node_src);
- }
-
- node_src->new_node = node_dst;
- node_dst->new_node = NULL;
-
- bool do_copy_api = !((flag & LIB_ID_CREATE_NO_MAIN) || (flag & LIB_ID_COPY_LOCALIZE));
- if (node_dst->typeinfo->copyfunc_api && do_copy_api) {
- PointerRNA ptr;
- RNA_pointer_create((ID *)ntree, &RNA_Node, node_dst, &ptr);
-
- node_dst->typeinfo->copyfunc_api(&ptr, node_src);
- }
-
- if (ntree) {
- ntree->update |= NTREE_UPDATE_NODES;
- }
-
- return node_dst;
+ bNode *node_dst = MEM_callocN(sizeof(bNode), "dupli node");
+ bNodeSocket *sock_dst, *sock_src;
+ bNodeLink *link_dst, *link_src;
+
+ *node_dst = *node_src;
+ /* can be called for nodes outside a node tree (e.g. clipboard) */
+ if (ntree) {
+ nodeUniqueName(ntree, node_dst);
+
+ BLI_addtail(&ntree->nodes, node_dst);
+ }
+
+ BLI_duplicatelist(&node_dst->inputs, &node_src->inputs);
+ for (sock_dst = node_dst->inputs.first, sock_src = node_src->inputs.first; sock_dst != NULL;
+ sock_dst = sock_dst->next, sock_src = sock_src->next) {
+ node_socket_copy(sock_dst, sock_src, flag);
+ }
+
+ BLI_duplicatelist(&node_dst->outputs, &node_src->outputs);
+ for (sock_dst = node_dst->outputs.first, sock_src = node_src->outputs.first; sock_dst != NULL;
+ sock_dst = sock_dst->next, sock_src = sock_src->next) {
+ node_socket_copy(sock_dst, sock_src, flag);
+ }
+
+ if (node_src->prop) {
+ node_dst->prop = IDP_CopyProperty_ex(node_src->prop, flag);
+ }
+
+ BLI_duplicatelist(&node_dst->internal_links, &node_src->internal_links);
+ for (link_dst = node_dst->internal_links.first, link_src = node_src->internal_links.first;
+ link_dst != NULL;
+ link_dst = link_dst->next, link_src = link_src->next) {
+ link_dst->fromnode = node_dst;
+ link_dst->tonode = node_dst;
+ link_dst->fromsock = link_dst->fromsock->new_sock;
+ link_dst->tosock = link_dst->tosock->new_sock;
+ }
+
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id_us_plus(node_dst->id);
+ }
+
+ if (node_src->typeinfo->copyfunc) {
+ node_src->typeinfo->copyfunc(ntree, node_dst, node_src);
+ }
+
+ node_src->new_node = node_dst;
+ node_dst->new_node = NULL;
+
+ bool do_copy_api = !((flag & LIB_ID_CREATE_NO_MAIN) || (flag & LIB_ID_COPY_LOCALIZE));
+ if (node_dst->typeinfo->copyfunc_api && do_copy_api) {
+ PointerRNA ptr;
+ RNA_pointer_create((ID *)ntree, &RNA_Node, node_dst, &ptr);
+
+ node_dst->typeinfo->copyfunc_api(&ptr, node_src);
+ }
+
+ if (ntree) {
+ ntree->update |= NTREE_UPDATE_NODES;
+ }
+
+ return node_dst;
}
/* also used via rna api, so we check for proper input output direction */
-bNodeLink *nodeAddLink(bNodeTree *ntree, bNode *fromnode, bNodeSocket *fromsock, bNode *tonode, bNodeSocket *tosock)
-{
- bNodeLink *link = NULL;
-
- /* test valid input */
- BLI_assert(fromnode);
- BLI_assert(tonode);
-
- if (fromsock->in_out == SOCK_OUT && tosock->in_out == SOCK_IN) {
- link = MEM_callocN(sizeof(bNodeLink), "link");
- if (ntree)
- BLI_addtail(&ntree->links, link);
- link->fromnode = fromnode;
- link->fromsock = fromsock;
- link->tonode = tonode;
- link->tosock = tosock;
- }
- else if (fromsock->in_out == SOCK_IN && tosock->in_out == SOCK_OUT) {
- /* OK but flip */
- link = MEM_callocN(sizeof(bNodeLink), "link");
- if (ntree)
- BLI_addtail(&ntree->links, link);
- link->fromnode = tonode;
- link->fromsock = tosock;
- link->tonode = fromnode;
- link->tosock = fromsock;
- }
-
- if (ntree)
- ntree->update |= NTREE_UPDATE_LINKS;
-
- return link;
+bNodeLink *nodeAddLink(
+ bNodeTree *ntree, bNode *fromnode, bNodeSocket *fromsock, bNode *tonode, bNodeSocket *tosock)
+{
+ bNodeLink *link = NULL;
+
+ /* test valid input */
+ BLI_assert(fromnode);
+ BLI_assert(tonode);
+
+ if (fromsock->in_out == SOCK_OUT && tosock->in_out == SOCK_IN) {
+ link = MEM_callocN(sizeof(bNodeLink), "link");
+ if (ntree)
+ BLI_addtail(&ntree->links, link);
+ link->fromnode = fromnode;
+ link->fromsock = fromsock;
+ link->tonode = tonode;
+ link->tosock = tosock;
+ }
+ else if (fromsock->in_out == SOCK_IN && tosock->in_out == SOCK_OUT) {
+ /* OK but flip */
+ link = MEM_callocN(sizeof(bNodeLink), "link");
+ if (ntree)
+ BLI_addtail(&ntree->links, link);
+ link->fromnode = tonode;
+ link->fromsock = tosock;
+ link->tonode = fromnode;
+ link->tosock = fromsock;
+ }
+
+ if (ntree)
+ ntree->update |= NTREE_UPDATE_LINKS;
+
+ return link;
}
void nodeRemLink(bNodeTree *ntree, bNodeLink *link)
{
- /* can be called for links outside a node tree (e.g. clipboard) */
- if (ntree)
- BLI_remlink(&ntree->links, link);
+ /* can be called for links outside a node tree (e.g. clipboard) */
+ if (ntree)
+ BLI_remlink(&ntree->links, link);
- if (link->tosock)
- link->tosock->link = NULL;
- MEM_freeN(link);
+ if (link->tosock)
+ link->tosock->link = NULL;
+ MEM_freeN(link);
- if (ntree)
- ntree->update |= NTREE_UPDATE_LINKS;
+ if (ntree)
+ ntree->update |= NTREE_UPDATE_LINKS;
}
void nodeRemSocketLinks(bNodeTree *ntree, bNodeSocket *sock)
{
- bNodeLink *link, *next;
+ bNodeLink *link, *next;
- for (link = ntree->links.first; link; link = next) {
- next = link->next;
- if (link->fromsock == sock || link->tosock == sock) {
- nodeRemLink(ntree, link);
- }
- }
+ for (link = ntree->links.first; link; link = next) {
+ next = link->next;
+ if (link->fromsock == sock || link->tosock == sock) {
+ nodeRemLink(ntree, link);
+ }
+ }
- ntree->update |= NTREE_UPDATE_LINKS;
+ ntree->update |= NTREE_UPDATE_LINKS;
}
bool nodeLinkIsHidden(bNodeLink *link)
{
- return nodeSocketIsHidden(link->fromsock) || nodeSocketIsHidden(link->tosock);
+ return nodeSocketIsHidden(link->fromsock) || nodeSocketIsHidden(link->tosock);
}
void nodeInternalRelink(bNodeTree *ntree, bNode *node)
{
- bNodeLink *link, *link_next;
-
- /* store link pointers in output sockets, for efficient lookup */
- for (link = node->internal_links.first; link; link = link->next)
- link->tosock->link = link;
-
- /* redirect downstream links */
- for (link = ntree->links.first; link; link = link_next) {
- link_next = link->next;
-
- /* do we have internal link? */
- if (link->fromnode == node) {
- if (link->fromsock->link) {
- /* get the upstream input link */
- bNodeLink *fromlink = link->fromsock->link->fromsock->link;
- /* skip the node */
- if (fromlink) {
- link->fromnode = fromlink->fromnode;
- link->fromsock = fromlink->fromsock;
-
- /* if the up- or downstream link is invalid,
- * the replacement link will be invalid too.
- */
- if (!(fromlink->flag & NODE_LINK_VALID))
- link->flag &= ~NODE_LINK_VALID;
-
- ntree->update |= NTREE_UPDATE_LINKS;
- }
- else
- nodeRemLink(ntree, link);
- }
- else
- nodeRemLink(ntree, link);
- }
- }
-
- /* remove remaining upstream links */
- for (link = ntree->links.first; link; link = link_next) {
- link_next = link->next;
-
- if (link->tonode == node)
- nodeRemLink(ntree, link);
- }
+ bNodeLink *link, *link_next;
+
+ /* store link pointers in output sockets, for efficient lookup */
+ for (link = node->internal_links.first; link; link = link->next)
+ link->tosock->link = link;
+
+ /* redirect downstream links */
+ for (link = ntree->links.first; link; link = link_next) {
+ link_next = link->next;
+
+ /* do we have internal link? */
+ if (link->fromnode == node) {
+ if (link->fromsock->link) {
+ /* get the upstream input link */
+ bNodeLink *fromlink = link->fromsock->link->fromsock->link;
+ /* skip the node */
+ if (fromlink) {
+ link->fromnode = fromlink->fromnode;
+ link->fromsock = fromlink->fromsock;
+
+ /* if the up- or downstream link is invalid,
+ * the replacement link will be invalid too.
+ */
+ if (!(fromlink->flag & NODE_LINK_VALID))
+ link->flag &= ~NODE_LINK_VALID;
+
+ ntree->update |= NTREE_UPDATE_LINKS;
+ }
+ else
+ nodeRemLink(ntree, link);
+ }
+ else
+ nodeRemLink(ntree, link);
+ }
+ }
+
+ /* remove remaining upstream links */
+ for (link = ntree->links.first; link; link = link_next) {
+ link_next = link->next;
+
+ if (link->tonode == node)
+ nodeRemLink(ntree, link);
+ }
}
void nodeToView(bNode *node, float x, float y, float *rx, float *ry)
{
- if (node->parent) {
- nodeToView(node->parent, x + node->locx, y + node->locy, rx, ry);
- }
- else {
- *rx = x + node->locx;
- *ry = y + node->locy;
- }
+ if (node->parent) {
+ nodeToView(node->parent, x + node->locx, y + node->locy, rx, ry);
+ }
+ else {
+ *rx = x + node->locx;
+ *ry = y + node->locy;
+ }
}
void nodeFromView(bNode *node, float x, float y, float *rx, float *ry)
{
- if (node->parent) {
- nodeFromView(node->parent, x, y, rx, ry);
- *rx -= node->locx;
- *ry -= node->locy;
- }
- else {
- *rx = x - node->locx;
- *ry = y - node->locy;
- }
+ if (node->parent) {
+ nodeFromView(node->parent, x, y, rx, ry);
+ *rx -= node->locx;
+ *ry -= node->locy;
+ }
+ else {
+ *rx = x - node->locx;
+ *ry = y - node->locy;
+ }
}
bool nodeAttachNodeCheck(bNode *node, bNode *parent)
{
- bNode *parent_recurse;
- for (parent_recurse = node; parent_recurse; parent_recurse = parent_recurse->parent) {
- if (parent_recurse == parent) {
- return true;
- }
- }
+ bNode *parent_recurse;
+ for (parent_recurse = node; parent_recurse; parent_recurse = parent_recurse->parent) {
+ if (parent_recurse == parent) {
+ return true;
+ }
+ }
- return false;
+ return false;
}
void nodeAttachNode(bNode *node, bNode *parent)
{
- float locx, locy;
+ float locx, locy;
- BLI_assert(parent->type == NODE_FRAME);
- BLI_assert(nodeAttachNodeCheck(parent, node) == false);
+ BLI_assert(parent->type == NODE_FRAME);
+ BLI_assert(nodeAttachNodeCheck(parent, node) == false);
- nodeToView(node, 0.0f, 0.0f, &locx, &locy);
+ nodeToView(node, 0.0f, 0.0f, &locx, &locy);
- node->parent = parent;
- /* transform to parent space */
- nodeFromView(parent, locx, locy, &node->locx, &node->locy);
+ node->parent = parent;
+ /* transform to parent space */
+ nodeFromView(parent, locx, locy, &node->locx, &node->locy);
}
void nodeDetachNode(struct bNode *node)
{
- float locx, locy;
+ float locx, locy;
- if (node->parent) {
+ if (node->parent) {
- BLI_assert(node->parent->type == NODE_FRAME);
+ BLI_assert(node->parent->type == NODE_FRAME);
- /* transform to view space */
- nodeToView(node, 0.0f, 0.0f, &locx, &locy);
- node->locx = locx;
- node->locy = locy;
- node->parent = NULL;
- }
+ /* transform to view space */
+ nodeToView(node, 0.0f, 0.0f, &locx, &locy);
+ node->locx = locx;
+ node->locy = locy;
+ node->parent = NULL;
+ }
}
-void nodePositionRelative(bNode *from_node, bNode *to_node, bNodeSocket *from_sock, bNodeSocket *to_sock)
+void nodePositionRelative(bNode *from_node,
+ bNode *to_node,
+ bNodeSocket *from_sock,
+ bNodeSocket *to_sock)
{
- float offset_x;
- int tot_sock_idx;
+ float offset_x;
+ int tot_sock_idx;
- /* Socket to plug into. */
- if (SOCK_IN == to_sock->in_out) {
- offset_x = - (from_node->typeinfo->width + 50);
- tot_sock_idx = BLI_listbase_count(&to_node->outputs);
- tot_sock_idx += BLI_findindex(&to_node->inputs, to_sock);
- }
- else {
- offset_x = to_node->typeinfo->width + 50;
- tot_sock_idx = BLI_findindex(&to_node->outputs, to_sock);
- }
+ /* Socket to plug into. */
+ if (SOCK_IN == to_sock->in_out) {
+ offset_x = -(from_node->typeinfo->width + 50);
+ tot_sock_idx = BLI_listbase_count(&to_node->outputs);
+ tot_sock_idx += BLI_findindex(&to_node->inputs, to_sock);
+ }
+ else {
+ offset_x = to_node->typeinfo->width + 50;
+ tot_sock_idx = BLI_findindex(&to_node->outputs, to_sock);
+ }
- BLI_assert(tot_sock_idx != -1);
+ BLI_assert(tot_sock_idx != -1);
- float offset_y = U.widget_unit * tot_sock_idx;
+ float offset_y = U.widget_unit * tot_sock_idx;
- /* Output socket. */
- if (from_sock) {
- if (SOCK_IN == from_sock->in_out) {
- tot_sock_idx = BLI_listbase_count(&from_node->outputs);
- tot_sock_idx += BLI_findindex(&from_node->inputs, from_sock);
- }
- else {
- tot_sock_idx = BLI_findindex(&from_node->outputs, from_sock);
- }
- }
+ /* Output socket. */
+ if (from_sock) {
+ if (SOCK_IN == from_sock->in_out) {
+ tot_sock_idx = BLI_listbase_count(&from_node->outputs);
+ tot_sock_idx += BLI_findindex(&from_node->inputs, from_sock);
+ }
+ else {
+ tot_sock_idx = BLI_findindex(&from_node->outputs, from_sock);
+ }
+ }
- BLI_assert(tot_sock_idx != -1);
+ BLI_assert(tot_sock_idx != -1);
- offset_y -= U.widget_unit * tot_sock_idx;
+ offset_y -= U.widget_unit * tot_sock_idx;
- from_node->locx = to_node->locx + offset_x;
- from_node->locy = to_node->locy - offset_y;
+ from_node->locx = to_node->locx + offset_x;
+ from_node->locy = to_node->locy - offset_y;
}
void nodePositionPropagate(bNode *node)
{
- for (bNodeSocket *nsock = node->inputs.first; nsock; nsock = nsock->next) {
- if (nsock->link != NULL) {
- bNodeLink *link = nsock->link;
- nodePositionRelative(link->fromnode, link->tonode, link->fromsock, link->tosock);
- nodePositionPropagate(link->fromnode);
- }
- }
+ for (bNodeSocket *nsock = node->inputs.first; nsock; nsock = nsock->next) {
+ if (nsock->link != NULL) {
+ bNodeLink *link = nsock->link;
+ nodePositionRelative(link->fromnode, link->tonode, link->fromsock, link->tosock);
+ nodePositionPropagate(link->fromnode);
+ }
+ }
}
void ntreeInitDefault(bNodeTree *ntree)
{
- ntree_set_typeinfo(ntree, NULL);
+ ntree_set_typeinfo(ntree, NULL);
}
bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname)
{
- bNodeTree *ntree;
+ bNodeTree *ntree;
- /* trees are created as local trees for compositor, material or texture nodes,
- * node groups and other tree types are created as library data.
- */
- if (bmain) {
- ntree = BKE_libblock_alloc(bmain, ID_NT, name, 0);
- }
- else {
- ntree = MEM_callocN(sizeof(bNodeTree), "new node tree");
- *( (short *)ntree->id.name ) = ID_NT;
- BLI_strncpy(ntree->id.name + 2, name, sizeof(ntree->id.name));
- }
+ /* trees are created as local trees for compositor, material or texture nodes,
+ * node groups and other tree types are created as library data.
+ */
+ if (bmain) {
+ ntree = BKE_libblock_alloc(bmain, ID_NT, name, 0);
+ }
+ else {
+ ntree = MEM_callocN(sizeof(bNodeTree), "new node tree");
+ *((short *)ntree->id.name) = ID_NT;
+ BLI_strncpy(ntree->id.name + 2, name, sizeof(ntree->id.name));
+ }
- /* Types are fully initialized at this point,
- * if an undefined node is added later this will be reset.
- */
- ntree->init |= NTREE_TYPE_INIT;
+ /* Types are fully initialized at this point,
+ * if an undefined node is added later this will be reset.
+ */
+ ntree->init |= NTREE_TYPE_INIT;
- BLI_strncpy(ntree->idname, idname, sizeof(ntree->idname));
- ntree_set_typeinfo(ntree, ntreeTypeFind(idname));
+ BLI_strncpy(ntree->idname, idname, sizeof(ntree->idname));
+ ntree_set_typeinfo(ntree, ntreeTypeFind(idname));
- return ntree;
+ return ntree;
}
/**
@@ -1293,108 +1334,109 @@ bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname)
*
* \param flag: Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
*/
-void BKE_node_tree_copy_data(Main *UNUSED(bmain), bNodeTree *ntree_dst, const bNodeTree *ntree_src, const int flag)
-{
- bNodeSocket *sock_dst, *sock_src;
- bNodeLink *link_dst;
-
- /* We never handle usercount here for own data. */
- const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
-
- /* in case a running nodetree is copied */
- ntree_dst->execdata = NULL;
-
- ntree_dst->duplilock = NULL;
-
- BLI_listbase_clear(&ntree_dst->nodes);
- BLI_listbase_clear(&ntree_dst->links);
-
- for (bNode *node_src = ntree_src->nodes.first; node_src; node_src = node_src->next) {
- BKE_node_copy_ex(ntree_dst, node_src, flag_subdata);
- }
-
- /* copy links */
- BLI_duplicatelist(&ntree_dst->links, &ntree_src->links);
- for (link_dst = ntree_dst->links.first; link_dst; link_dst = link_dst->next) {
- link_dst->fromnode = (link_dst->fromnode ? link_dst->fromnode->new_node : NULL);
- link_dst->fromsock = (link_dst->fromsock ? link_dst->fromsock->new_sock : NULL);
- link_dst->tonode = (link_dst->tonode ? link_dst->tonode->new_node : NULL);
- link_dst->tosock = (link_dst->tosock ? link_dst->tosock->new_sock : NULL);
- /* update the link socket's pointer */
- if (link_dst->tosock) {
- link_dst->tosock->link = link_dst;
- }
- }
-
- /* copy interface sockets */
- BLI_duplicatelist(&ntree_dst->inputs, &ntree_src->inputs);
- for (sock_dst = ntree_dst->inputs.first, sock_src = ntree_src->inputs.first;
- sock_dst != NULL;
- sock_dst = sock_dst->next, sock_src = sock_src->next)
- {
- node_socket_copy(sock_dst, sock_src, flag_subdata);
- }
-
- BLI_duplicatelist(&ntree_dst->outputs, &ntree_src->outputs);
- for (sock_dst = ntree_dst->outputs.first, sock_src = ntree_src->outputs.first;
- sock_dst != NULL;
- sock_dst = sock_dst->next, sock_src = sock_src->next)
- {
- node_socket_copy(sock_dst, sock_src, flag_subdata);
- }
-
- /* copy preview hash */
- if (ntree_src->previews && (flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
- bNodeInstanceHashIterator iter;
-
- ntree_dst->previews = BKE_node_instance_hash_new("node previews");
-
- NODE_INSTANCE_HASH_ITER(iter, ntree_src->previews) {
- bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter);
- bNodePreview *preview = BKE_node_instance_hash_iterator_get_value(&iter);
- BKE_node_instance_hash_insert(ntree_dst->previews, key, BKE_node_preview_copy(preview));
- }
- }
- else {
- ntree_dst->previews = NULL;
- }
-
- /* update node->parent pointers */
- for (bNode *node_dst = ntree_dst->nodes.first, *node_src = ntree_src->nodes.first; node_dst; node_dst = node_dst->next, node_src = node_src->next) {
- if (node_dst->parent) {
- node_dst->parent = node_dst->parent->new_node;
- }
- }
-
- /* node tree will generate its own interface type */
- ntree_dst->interface_type = NULL;
+void BKE_node_tree_copy_data(Main *UNUSED(bmain),
+ bNodeTree *ntree_dst,
+ const bNodeTree *ntree_src,
+ const int flag)
+{
+ bNodeSocket *sock_dst, *sock_src;
+ bNodeLink *link_dst;
+
+ /* We never handle usercount here for own data. */
+ const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
+
+ /* in case a running nodetree is copied */
+ ntree_dst->execdata = NULL;
+
+ ntree_dst->duplilock = NULL;
+
+ BLI_listbase_clear(&ntree_dst->nodes);
+ BLI_listbase_clear(&ntree_dst->links);
+
+ for (bNode *node_src = ntree_src->nodes.first; node_src; node_src = node_src->next) {
+ BKE_node_copy_ex(ntree_dst, node_src, flag_subdata);
+ }
+
+ /* copy links */
+ BLI_duplicatelist(&ntree_dst->links, &ntree_src->links);
+ for (link_dst = ntree_dst->links.first; link_dst; link_dst = link_dst->next) {
+ link_dst->fromnode = (link_dst->fromnode ? link_dst->fromnode->new_node : NULL);
+ link_dst->fromsock = (link_dst->fromsock ? link_dst->fromsock->new_sock : NULL);
+ link_dst->tonode = (link_dst->tonode ? link_dst->tonode->new_node : NULL);
+ link_dst->tosock = (link_dst->tosock ? link_dst->tosock->new_sock : NULL);
+ /* update the link socket's pointer */
+ if (link_dst->tosock) {
+ link_dst->tosock->link = link_dst;
+ }
+ }
+
+ /* copy interface sockets */
+ BLI_duplicatelist(&ntree_dst->inputs, &ntree_src->inputs);
+ for (sock_dst = ntree_dst->inputs.first, sock_src = ntree_src->inputs.first; sock_dst != NULL;
+ sock_dst = sock_dst->next, sock_src = sock_src->next) {
+ node_socket_copy(sock_dst, sock_src, flag_subdata);
+ }
+
+ BLI_duplicatelist(&ntree_dst->outputs, &ntree_src->outputs);
+ for (sock_dst = ntree_dst->outputs.first, sock_src = ntree_src->outputs.first; sock_dst != NULL;
+ sock_dst = sock_dst->next, sock_src = sock_src->next) {
+ node_socket_copy(sock_dst, sock_src, flag_subdata);
+ }
+
+ /* copy preview hash */
+ if (ntree_src->previews && (flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
+ bNodeInstanceHashIterator iter;
+
+ ntree_dst->previews = BKE_node_instance_hash_new("node previews");
+
+ NODE_INSTANCE_HASH_ITER(iter, ntree_src->previews)
+ {
+ bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter);
+ bNodePreview *preview = BKE_node_instance_hash_iterator_get_value(&iter);
+ BKE_node_instance_hash_insert(ntree_dst->previews, key, BKE_node_preview_copy(preview));
+ }
+ }
+ else {
+ ntree_dst->previews = NULL;
+ }
+
+ /* update node->parent pointers */
+ for (bNode *node_dst = ntree_dst->nodes.first, *node_src = ntree_src->nodes.first; node_dst;
+ node_dst = node_dst->next, node_src = node_src->next) {
+ if (node_dst->parent) {
+ node_dst->parent = node_dst->parent->new_node;
+ }
+ }
+
+ /* node tree will generate its own interface type */
+ ntree_dst->interface_type = NULL;
}
bNodeTree *ntreeCopyTree_ex(const bNodeTree *ntree, Main *bmain, const bool do_id_user)
{
- bNodeTree *ntree_copy;
- const int flag = do_id_user ? LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_CREATE_NO_MAIN : 0;
- BKE_id_copy_ex(bmain, (ID *)ntree, (ID **)&ntree_copy, flag);
- return ntree_copy;
+ bNodeTree *ntree_copy;
+ const int flag = do_id_user ? LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_CREATE_NO_MAIN : 0;
+ BKE_id_copy_ex(bmain, (ID *)ntree, (ID **)&ntree_copy, flag);
+ return ntree_copy;
}
bNodeTree *ntreeCopyTree(Main *bmain, const bNodeTree *ntree)
{
- return ntreeCopyTree_ex(ntree, bmain, true);
+ return ntreeCopyTree_ex(ntree, bmain, true);
}
void ntreeUserIncrefID(bNodeTree *ntree)
{
- bNode *node;
- for (node = ntree->nodes.first; node; node = node->next) {
- id_us_plus(node->id);
- }
+ bNode *node;
+ for (node = ntree->nodes.first; node; node = node->next) {
+ id_us_plus(node->id);
+ }
}
void ntreeUserDecrefID(bNodeTree *ntree)
{
- bNode *node;
- for (node = ntree->nodes.first; node; node = node->next) {
- id_us_min(node->id);
- }
+ bNode *node;
+ for (node = ntree->nodes.first; node; node = node->next) {
+ id_us_min(node->id);
+ }
}
/* *************** Node Preview *********** */
@@ -1406,233 +1448,248 @@ void ntreeUserDecrefID(bNodeTree *ntree)
*/
int BKE_node_preview_used(bNode *node)
{
- /* XXX check for closed nodes? */
- return (node->typeinfo->flag & NODE_PREVIEW) != 0;
+ /* XXX check for closed nodes? */
+ return (node->typeinfo->flag & NODE_PREVIEW) != 0;
}
-bNodePreview *BKE_node_preview_verify(bNodeInstanceHash *previews, bNodeInstanceKey key, int xsize, int ysize, bool create)
+bNodePreview *BKE_node_preview_verify(
+ bNodeInstanceHash *previews, bNodeInstanceKey key, int xsize, int ysize, bool create)
{
- bNodePreview *preview;
+ bNodePreview *preview;
- preview = BKE_node_instance_hash_lookup(previews, key);
- if (!preview) {
- if (create) {
- preview = MEM_callocN(sizeof(bNodePreview), "node preview");
- BKE_node_instance_hash_insert(previews, key, preview);
- }
- else
- return NULL;
- }
+ preview = BKE_node_instance_hash_lookup(previews, key);
+ if (!preview) {
+ if (create) {
+ preview = MEM_callocN(sizeof(bNodePreview), "node preview");
+ BKE_node_instance_hash_insert(previews, key, preview);
+ }
+ else
+ return NULL;
+ }
- /* node previews can get added with variable size this way */
- if (xsize == 0 || ysize == 0)
- return preview;
+ /* node previews can get added with variable size this way */
+ if (xsize == 0 || ysize == 0)
+ return preview;
- /* sanity checks & initialize */
- if (preview->rect) {
- if (preview->xsize != xsize || preview->ysize != ysize) {
- MEM_freeN(preview->rect);
- preview->rect = NULL;
- }
- }
+ /* sanity checks & initialize */
+ if (preview->rect) {
+ if (preview->xsize != xsize || preview->ysize != ysize) {
+ MEM_freeN(preview->rect);
+ preview->rect = NULL;
+ }
+ }
- if (preview->rect == NULL) {
- preview->rect = MEM_callocN(4 * xsize + xsize * ysize * sizeof(char) * 4, "node preview rect");
- preview->xsize = xsize;
- preview->ysize = ysize;
- }
- /* no clear, makes nicer previews */
+ if (preview->rect == NULL) {
+ preview->rect = MEM_callocN(4 * xsize + xsize * ysize * sizeof(char) * 4, "node preview rect");
+ preview->xsize = xsize;
+ preview->ysize = ysize;
+ }
+ /* no clear, makes nicer previews */
- return preview;
+ return preview;
}
bNodePreview *BKE_node_preview_copy(bNodePreview *preview)
{
- bNodePreview *new_preview = MEM_dupallocN(preview);
- if (preview->rect)
- new_preview->rect = MEM_dupallocN(preview->rect);
- return new_preview;
+ bNodePreview *new_preview = MEM_dupallocN(preview);
+ if (preview->rect)
+ new_preview->rect = MEM_dupallocN(preview->rect);
+ return new_preview;
}
void BKE_node_preview_free(bNodePreview *preview)
{
- if (preview->rect)
- MEM_freeN(preview->rect);
- MEM_freeN(preview);
+ if (preview->rect)
+ MEM_freeN(preview->rect);
+ MEM_freeN(preview);
}
-static void node_preview_init_tree_recursive(bNodeInstanceHash *previews, bNodeTree *ntree, bNodeInstanceKey parent_key, int xsize, int ysize, int create)
+static void node_preview_init_tree_recursive(bNodeInstanceHash *previews,
+ bNodeTree *ntree,
+ bNodeInstanceKey parent_key,
+ int xsize,
+ int ysize,
+ int create)
{
- bNode *node;
- for (node = ntree->nodes.first; node; node = node->next) {
- bNodeInstanceKey key = BKE_node_instance_key(parent_key, ntree, node);
+ bNode *node;
+ for (node = ntree->nodes.first; node; node = node->next) {
+ bNodeInstanceKey key = BKE_node_instance_key(parent_key, ntree, node);
- if (BKE_node_preview_used(node)) {
- node->preview_xsize = xsize;
- node->preview_ysize = ysize;
+ if (BKE_node_preview_used(node)) {
+ node->preview_xsize = xsize;
+ node->preview_ysize = ysize;
- BKE_node_preview_verify(previews, key, xsize, ysize, create);
- }
+ BKE_node_preview_verify(previews, key, xsize, ysize, create);
+ }
- if (node->type == NODE_GROUP && node->id)
- node_preview_init_tree_recursive(previews, (bNodeTree *)node->id, key, xsize, ysize, create);
- }
+ if (node->type == NODE_GROUP && node->id)
+ node_preview_init_tree_recursive(previews, (bNodeTree *)node->id, key, xsize, ysize, create);
+ }
}
void BKE_node_preview_init_tree(bNodeTree *ntree, int xsize, int ysize, int create_previews)
{
- if (!ntree)
- return;
+ if (!ntree)
+ return;
- if (!ntree->previews)
- ntree->previews = BKE_node_instance_hash_new("node previews");
+ if (!ntree->previews)
+ ntree->previews = BKE_node_instance_hash_new("node previews");
- node_preview_init_tree_recursive(ntree->previews, ntree, NODE_INSTANCE_KEY_BASE, xsize, ysize, create_previews);
+ node_preview_init_tree_recursive(
+ ntree->previews, ntree, NODE_INSTANCE_KEY_BASE, xsize, ysize, create_previews);
}
-static void node_preview_tag_used_recursive(bNodeInstanceHash *previews, bNodeTree *ntree, bNodeInstanceKey parent_key)
+static void node_preview_tag_used_recursive(bNodeInstanceHash *previews,
+ bNodeTree *ntree,
+ bNodeInstanceKey parent_key)
{
- bNode *node;
- for (node = ntree->nodes.first; node; node = node->next) {
- bNodeInstanceKey key = BKE_node_instance_key(parent_key, ntree, node);
+ bNode *node;
+ for (node = ntree->nodes.first; node; node = node->next) {
+ bNodeInstanceKey key = BKE_node_instance_key(parent_key, ntree, node);
- if (BKE_node_preview_used(node))
- BKE_node_instance_hash_tag_key(previews, key);
+ if (BKE_node_preview_used(node))
+ BKE_node_instance_hash_tag_key(previews, key);
- if (node->type == NODE_GROUP && node->id)
- node_preview_tag_used_recursive(previews, (bNodeTree *)node->id, key);
- }
+ if (node->type == NODE_GROUP && node->id)
+ node_preview_tag_used_recursive(previews, (bNodeTree *)node->id, key);
+ }
}
void BKE_node_preview_remove_unused(bNodeTree *ntree)
{
- if (!ntree || !ntree->previews)
- return;
+ if (!ntree || !ntree->previews)
+ return;
- /* use the instance hash functions for tagging and removing unused previews */
- BKE_node_instance_hash_clear_tags(ntree->previews);
- node_preview_tag_used_recursive(ntree->previews, ntree, NODE_INSTANCE_KEY_BASE);
+ /* use the instance hash functions for tagging and removing unused previews */
+ BKE_node_instance_hash_clear_tags(ntree->previews);
+ node_preview_tag_used_recursive(ntree->previews, ntree, NODE_INSTANCE_KEY_BASE);
- BKE_node_instance_hash_remove_untagged(ntree->previews, (bNodeInstanceValueFP)BKE_node_preview_free);
+ BKE_node_instance_hash_remove_untagged(ntree->previews,
+ (bNodeInstanceValueFP)BKE_node_preview_free);
}
void BKE_node_preview_free_tree(bNodeTree *ntree)
{
- if (!ntree)
- return;
+ if (!ntree)
+ return;
- if (ntree->previews) {
- BKE_node_instance_hash_free(ntree->previews, (bNodeInstanceValueFP)BKE_node_preview_free);
- ntree->previews = NULL;
- }
+ if (ntree->previews) {
+ BKE_node_instance_hash_free(ntree->previews, (bNodeInstanceValueFP)BKE_node_preview_free);
+ ntree->previews = NULL;
+ }
}
void BKE_node_preview_clear(bNodePreview *preview)
{
- if (preview && preview->rect)
- memset(preview->rect, 0, MEM_allocN_len(preview->rect));
+ if (preview && preview->rect)
+ memset(preview->rect, 0, MEM_allocN_len(preview->rect));
}
void BKE_node_preview_clear_tree(bNodeTree *ntree)
{
- bNodeInstanceHashIterator iter;
+ bNodeInstanceHashIterator iter;
- if (!ntree || !ntree->previews)
- return;
+ if (!ntree || !ntree->previews)
+ return;
- NODE_INSTANCE_HASH_ITER(iter, ntree->previews) {
- bNodePreview *preview = BKE_node_instance_hash_iterator_get_value(&iter);
- BKE_node_preview_clear(preview);
- }
+ NODE_INSTANCE_HASH_ITER(iter, ntree->previews)
+ {
+ bNodePreview *preview = BKE_node_instance_hash_iterator_get_value(&iter);
+ BKE_node_preview_clear(preview);
+ }
}
static void node_preview_sync(bNodePreview *to, bNodePreview *from)
{
- /* sizes should have been initialized by BKE_node_preview_init_tree */
- BLI_assert(to->xsize == from->xsize && to->ysize == from->ysize);
+ /* sizes should have been initialized by BKE_node_preview_init_tree */
+ BLI_assert(to->xsize == from->xsize && to->ysize == from->ysize);
- /* copy over contents of previews */
- if (to->rect && from->rect) {
- int xsize = to->xsize;
- int ysize = to->ysize;
- memcpy(to->rect, from->rect, xsize * ysize * sizeof(char) * 4);
- }
+ /* copy over contents of previews */
+ if (to->rect && from->rect) {
+ int xsize = to->xsize;
+ int ysize = to->ysize;
+ memcpy(to->rect, from->rect, xsize * ysize * sizeof(char) * 4);
+ }
}
void BKE_node_preview_sync_tree(bNodeTree *to_ntree, bNodeTree *from_ntree)
{
- bNodeInstanceHash *from_previews = from_ntree->previews;
- bNodeInstanceHash *to_previews = to_ntree->previews;
- bNodeInstanceHashIterator iter;
+ bNodeInstanceHash *from_previews = from_ntree->previews;
+ bNodeInstanceHash *to_previews = to_ntree->previews;
+ bNodeInstanceHashIterator iter;
- if (!from_previews || !to_previews)
- return;
+ if (!from_previews || !to_previews)
+ return;
- NODE_INSTANCE_HASH_ITER(iter, from_previews) {
- bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter);
- bNodePreview *from = BKE_node_instance_hash_iterator_get_value(&iter);
- bNodePreview *to = BKE_node_instance_hash_lookup(to_previews, key);
+ NODE_INSTANCE_HASH_ITER(iter, from_previews)
+ {
+ bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter);
+ bNodePreview *from = BKE_node_instance_hash_iterator_get_value(&iter);
+ bNodePreview *to = BKE_node_instance_hash_lookup(to_previews, key);
- if (from && to)
- node_preview_sync(to, from);
- }
+ if (from && to)
+ node_preview_sync(to, from);
+ }
}
void BKE_node_preview_merge_tree(bNodeTree *to_ntree, bNodeTree *from_ntree, bool remove_old)
{
- if (remove_old || !to_ntree->previews) {
- /* free old previews */
- if (to_ntree->previews)
- BKE_node_instance_hash_free(to_ntree->previews, (bNodeInstanceValueFP)BKE_node_preview_free);
+ if (remove_old || !to_ntree->previews) {
+ /* free old previews */
+ if (to_ntree->previews)
+ BKE_node_instance_hash_free(to_ntree->previews, (bNodeInstanceValueFP)BKE_node_preview_free);
- /* transfer previews */
- to_ntree->previews = from_ntree->previews;
- from_ntree->previews = NULL;
+ /* transfer previews */
+ to_ntree->previews = from_ntree->previews;
+ from_ntree->previews = NULL;
- /* clean up, in case any to_ntree nodes have been removed */
- BKE_node_preview_remove_unused(to_ntree);
- }
- else {
- bNodeInstanceHashIterator iter;
+ /* clean up, in case any to_ntree nodes have been removed */
+ BKE_node_preview_remove_unused(to_ntree);
+ }
+ else {
+ bNodeInstanceHashIterator iter;
- if (from_ntree->previews) {
- NODE_INSTANCE_HASH_ITER(iter, from_ntree->previews) {
- bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter);
- bNodePreview *preview = BKE_node_instance_hash_iterator_get_value(&iter);
+ if (from_ntree->previews) {
+ NODE_INSTANCE_HASH_ITER(iter, from_ntree->previews)
+ {
+ bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter);
+ bNodePreview *preview = BKE_node_instance_hash_iterator_get_value(&iter);
- /* replace existing previews */
- BKE_node_instance_hash_remove(to_ntree->previews, key, (bNodeInstanceValueFP)BKE_node_preview_free);
- BKE_node_instance_hash_insert(to_ntree->previews, key, preview);
- }
+ /* replace existing previews */
+ BKE_node_instance_hash_remove(
+ to_ntree->previews, key, (bNodeInstanceValueFP)BKE_node_preview_free);
+ BKE_node_instance_hash_insert(to_ntree->previews, key, preview);
+ }
- /* Note: NULL free function here, because pointers have already been moved over to to_ntree->previews! */
- BKE_node_instance_hash_free(from_ntree->previews, NULL);
- from_ntree->previews = NULL;
- }
- }
+ /* Note: NULL free function here, because pointers have already been moved over to to_ntree->previews! */
+ BKE_node_instance_hash_free(from_ntree->previews, NULL);
+ from_ntree->previews = NULL;
+ }
+ }
}
/* hack warning! this function is only used for shader previews, and
* since it gets called multiple times per pixel for Ztransp we only
* add the color once. Preview gets cleared before it starts render though */
-void BKE_node_preview_set_pixel(bNodePreview *preview, const float col[4], int x, int y, bool do_manage)
-{
- if (preview) {
- if (x >= 0 && y >= 0) {
- if (x < preview->xsize && y < preview->ysize) {
- unsigned char *tar = preview->rect + 4 * ((preview->xsize * y) + x);
-
- if (do_manage) {
- linearrgb_to_srgb_uchar4(tar, col);
- }
- else {
- rgba_float_to_uchar(tar, col);
- }
- }
- //else printf("prv out bound x y %d %d\n", x, y);
- }
- //else printf("prv out bound x y %d %d\n", x, y);
- }
+void BKE_node_preview_set_pixel(
+ bNodePreview *preview, const float col[4], int x, int y, bool do_manage)
+{
+ if (preview) {
+ if (x >= 0 && y >= 0) {
+ if (x < preview->xsize && y < preview->ysize) {
+ unsigned char *tar = preview->rect + 4 * ((preview->xsize * y) + x);
+
+ if (do_manage) {
+ linearrgb_to_srgb_uchar4(tar, col);
+ }
+ else {
+ rgba_float_to_uchar(tar, col);
+ }
+ }
+ //else printf("prv out bound x y %d %d\n", x, y);
+ }
+ //else printf("prv out bound x y %d %d\n", x, y);
+ }
}
/* ************** Free stuff ********** */
@@ -1640,436 +1697,441 @@ void BKE_node_preview_set_pixel(bNodePreview *preview, const float col[4], int x
/* goes over entire tree */
void nodeUnlinkNode(bNodeTree *ntree, bNode *node)
{
- bNodeLink *link, *next;
- bNodeSocket *sock;
- ListBase *lb;
-
- for (link = ntree->links.first; link; link = next) {
- next = link->next;
-
- if (link->fromnode == node) {
- lb = &node->outputs;
- if (link->tonode)
- link->tonode->update |= NODE_UPDATE;
- }
- else if (link->tonode == node)
- lb = &node->inputs;
- else
- lb = NULL;
-
- if (lb) {
- for (sock = lb->first; sock; sock = sock->next) {
- if (link->fromsock == sock || link->tosock == sock)
- break;
- }
- if (sock) {
- nodeRemLink(ntree, link);
- }
- }
- }
+ bNodeLink *link, *next;
+ bNodeSocket *sock;
+ ListBase *lb;
+
+ for (link = ntree->links.first; link; link = next) {
+ next = link->next;
+
+ if (link->fromnode == node) {
+ lb = &node->outputs;
+ if (link->tonode)
+ link->tonode->update |= NODE_UPDATE;
+ }
+ else if (link->tonode == node)
+ lb = &node->inputs;
+ else
+ lb = NULL;
+
+ if (lb) {
+ for (sock = lb->first; sock; sock = sock->next) {
+ if (link->fromsock == sock || link->tosock == sock)
+ break;
+ }
+ if (sock) {
+ nodeRemLink(ntree, link);
+ }
+ }
+ }
}
static void node_unlink_attached(bNodeTree *ntree, bNode *parent)
{
- bNode *node;
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->parent == parent)
- nodeDetachNode(node);
- }
+ bNode *node;
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (node->parent == parent)
+ nodeDetachNode(node);
+ }
}
/* Free the node itself. ID user refcounting is up the caller,
* that does not happen here. */
static void node_free_node(bNodeTree *ntree, bNode *node)
{
- bNodeSocket *sock, *nextsock;
+ bNodeSocket *sock, *nextsock;
- /* since it is called while free database, node->id is undefined */
+ /* since it is called while free database, node->id is undefined */
- /* can be called for nodes outside a node tree (e.g. clipboard) */
- if (ntree) {
- /* remove all references to this node */
- nodeUnlinkNode(ntree, node);
- node_unlink_attached(ntree, node);
+ /* can be called for nodes outside a node tree (e.g. clipboard) */
+ if (ntree) {
+ /* remove all references to this node */
+ nodeUnlinkNode(ntree, node);
+ node_unlink_attached(ntree, node);
- BLI_remlink(&ntree->nodes, node);
+ BLI_remlink(&ntree->nodes, node);
- if (ntree->typeinfo->free_node_cache)
- ntree->typeinfo->free_node_cache(ntree, node);
+ if (ntree->typeinfo->free_node_cache)
+ ntree->typeinfo->free_node_cache(ntree, node);
- /* texture node has bad habit of keeping exec data around */
- if (ntree->type == NTREE_TEXTURE && ntree->execdata) {
- ntreeTexEndExecTree(ntree->execdata);
- ntree->execdata = NULL;
- }
- }
+ /* texture node has bad habit of keeping exec data around */
+ if (ntree->type == NTREE_TEXTURE && ntree->execdata) {
+ ntreeTexEndExecTree(ntree->execdata);
+ ntree->execdata = NULL;
+ }
+ }
- if (node->typeinfo->freefunc) {
- node->typeinfo->freefunc(node);
- }
+ if (node->typeinfo->freefunc) {
+ node->typeinfo->freefunc(node);
+ }
- for (sock = node->inputs.first; sock; sock = nextsock) {
- nextsock = sock->next;
- /* Remember, no ID user refcount management here! */
- node_socket_free(ntree, sock, node, false);
- MEM_freeN(sock);
- }
- for (sock = node->outputs.first; sock; sock = nextsock) {
- nextsock = sock->next;
- /* Remember, no ID user refcount management here! */
- node_socket_free(ntree, sock, node, false);
- MEM_freeN(sock);
- }
+ for (sock = node->inputs.first; sock; sock = nextsock) {
+ nextsock = sock->next;
+ /* Remember, no ID user refcount management here! */
+ node_socket_free(ntree, sock, node, false);
+ MEM_freeN(sock);
+ }
+ for (sock = node->outputs.first; sock; sock = nextsock) {
+ nextsock = sock->next;
+ /* Remember, no ID user refcount management here! */
+ node_socket_free(ntree, sock, node, false);
+ MEM_freeN(sock);
+ }
- BLI_freelistN(&node->internal_links);
+ BLI_freelistN(&node->internal_links);
- if (node->prop) {
- /* Remember, no ID user refcount management here! */
- IDP_FreeProperty_ex(node->prop, false);
- MEM_freeN(node->prop);
- }
+ if (node->prop) {
+ /* Remember, no ID user refcount management here! */
+ IDP_FreeProperty_ex(node->prop, false);
+ MEM_freeN(node->prop);
+ }
- MEM_freeN(node);
+ MEM_freeN(node);
- if (ntree)
- ntree->update |= NTREE_UPDATE_NODES;
+ if (ntree)
+ ntree->update |= NTREE_UPDATE_NODES;
}
void ntreeFreeLocalNode(bNodeTree *ntree, bNode *node)
{
- /* For removing nodes while editing localized node trees. */
- BLI_assert((ntree->id.tag & LIB_TAG_LOCALIZED) != 0);
- node_free_node(ntree, node);
+ /* For removing nodes while editing localized node trees. */
+ BLI_assert((ntree->id.tag & LIB_TAG_LOCALIZED) != 0);
+ node_free_node(ntree, node);
}
void nodeRemoveNode(Main *bmain, bNodeTree *ntree, bNode *node, bool do_id_user)
{
- /* This function is not for localized node trees, we do not want
- * do to ID user refcounting and removal of animdation data then. */
- BLI_assert((ntree->id.tag & LIB_TAG_LOCALIZED) == 0);
+ /* This function is not for localized node trees, we do not want
+ * do to ID user refcounting and removal of animdation data then. */
+ BLI_assert((ntree->id.tag & LIB_TAG_LOCALIZED) == 0);
- if (do_id_user) {
- /* Free callback for NodeCustomGroup. */
- if (node->typeinfo->freefunc_api) {
- PointerRNA ptr;
- RNA_pointer_create((ID *)ntree, &RNA_Node, node, &ptr);
+ if (do_id_user) {
+ /* Free callback for NodeCustomGroup. */
+ if (node->typeinfo->freefunc_api) {
+ PointerRNA ptr;
+ RNA_pointer_create((ID *)ntree, &RNA_Node, node, &ptr);
- node->typeinfo->freefunc_api(&ptr);
- }
+ node->typeinfo->freefunc_api(&ptr);
+ }
- /* Do user counting. */
- if (node->id) {
- id_us_min(node->id);
- }
- }
+ /* Do user counting. */
+ if (node->id) {
+ id_us_min(node->id);
+ }
+ }
- /* Remove animation data. */
- char propname_esc[MAX_IDPROP_NAME * 2];
- char prefix[MAX_IDPROP_NAME * 2];
+ /* Remove animation data. */
+ char propname_esc[MAX_IDPROP_NAME * 2];
+ char prefix[MAX_IDPROP_NAME * 2];
- BLI_strescape(propname_esc, node->name, sizeof(propname_esc));
- BLI_snprintf(prefix, sizeof(prefix), "nodes[\"%s\"]", propname_esc);
+ BLI_strescape(propname_esc, node->name, sizeof(propname_esc));
+ BLI_snprintf(prefix, sizeof(prefix), "nodes[\"%s\"]", propname_esc);
- if (BKE_animdata_fix_paths_remove((ID *)ntree, prefix)) {
- if (bmain != NULL) {
- DEG_relations_tag_update(bmain);
- }
- }
+ if (BKE_animdata_fix_paths_remove((ID *)ntree, prefix)) {
+ if (bmain != NULL) {
+ DEG_relations_tag_update(bmain);
+ }
+ }
- /* Free node itself. */
- node_free_node(ntree, node);
+ /* Free node itself. */
+ node_free_node(ntree, node);
}
static void node_socket_interface_free(bNodeTree *UNUSED(ntree), bNodeSocket *sock)
{
- if (sock->prop) {
- IDP_FreeProperty(sock->prop);
- MEM_freeN(sock->prop);
- }
+ if (sock->prop) {
+ IDP_FreeProperty(sock->prop);
+ MEM_freeN(sock->prop);
+ }
- if (sock->default_value)
- MEM_freeN(sock->default_value);
+ if (sock->default_value)
+ MEM_freeN(sock->default_value);
}
static void free_localized_node_groups(bNodeTree *ntree)
{
- bNode *node;
+ bNode *node;
- /* Only localized node trees store a copy for each node group tree.
- * Each node group tree in a localized node tree can be freed,
- * since it is a localized copy itself (no risk of accessing free'd
- * data in main, see [#37939]).
- */
- if (!(ntree->id.tag & LIB_TAG_LOCALIZED))
- return;
+ /* Only localized node trees store a copy for each node group tree.
+ * Each node group tree in a localized node tree can be freed,
+ * since it is a localized copy itself (no risk of accessing free'd
+ * data in main, see [#37939]).
+ */
+ if (!(ntree->id.tag & LIB_TAG_LOCALIZED))
+ return;
- for (node = ntree->nodes.first; node; node = node->next) {
- if ((ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) && node->id) {
- bNodeTree *ngroup = (bNodeTree *)node->id;
- ntreeFreeTree(ngroup);
- MEM_freeN(ngroup);
- }
- }
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if ((ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) && node->id) {
+ bNodeTree *ngroup = (bNodeTree *)node->id;
+ ntreeFreeTree(ngroup);
+ MEM_freeN(ngroup);
+ }
+ }
}
/* Free (or release) any data used by this nodetree. Does not free the
* nodetree itself and does no ID user counting. */
void ntreeFreeTree(bNodeTree *ntree)
{
- bNode *node, *next;
- bNodeSocket *sock, *nextsock;
-
- BKE_animdata_free((ID *)ntree, false);
-
- /* XXX hack! node trees should not store execution graphs at all.
- * This should be removed when old tree types no longer require it.
- * Currently the execution data for texture nodes remains in the tree
- * after execution, until the node tree is updated or freed.
- */
- if (ntree->execdata) {
- switch (ntree->type) {
- case NTREE_SHADER:
- ntreeShaderEndExecTree(ntree->execdata);
- break;
- case NTREE_TEXTURE:
- ntreeTexEndExecTree(ntree->execdata);
- ntree->execdata = NULL;
- break;
- }
- }
-
- /* XXX not nice, but needed to free localized node groups properly */
- free_localized_node_groups(ntree);
-
- /* unregister associated RNA types */
- ntreeInterfaceTypeFree(ntree);
-
- BLI_freelistN(&ntree->links); /* do first, then unlink_node goes fast */
-
- for (node = ntree->nodes.first; node; node = next) {
- next = node->next;
- node_free_node(ntree, node);
- }
-
- /* free interface sockets */
- for (sock = ntree->inputs.first; sock; sock = nextsock) {
- nextsock = sock->next;
- node_socket_interface_free(ntree, sock);
- MEM_freeN(sock);
- }
- for (sock = ntree->outputs.first; sock; sock = nextsock) {
- nextsock = sock->next;
- node_socket_interface_free(ntree, sock);
- MEM_freeN(sock);
- }
-
- /* free preview hash */
- if (ntree->previews) {
- BKE_node_instance_hash_free(ntree->previews, (bNodeInstanceValueFP)BKE_node_preview_free);
- }
-
- if (ntree->duplilock)
- BLI_mutex_free(ntree->duplilock);
-
- if (ntree->id.tag & LIB_TAG_LOCALIZED) {
- BKE_libblock_free_data(&ntree->id, true);
- }
+ bNode *node, *next;
+ bNodeSocket *sock, *nextsock;
+
+ BKE_animdata_free((ID *)ntree, false);
+
+ /* XXX hack! node trees should not store execution graphs at all.
+ * This should be removed when old tree types no longer require it.
+ * Currently the execution data for texture nodes remains in the tree
+ * after execution, until the node tree is updated or freed.
+ */
+ if (ntree->execdata) {
+ switch (ntree->type) {
+ case NTREE_SHADER:
+ ntreeShaderEndExecTree(ntree->execdata);
+ break;
+ case NTREE_TEXTURE:
+ ntreeTexEndExecTree(ntree->execdata);
+ ntree->execdata = NULL;
+ break;
+ }
+ }
+
+ /* XXX not nice, but needed to free localized node groups properly */
+ free_localized_node_groups(ntree);
+
+ /* unregister associated RNA types */
+ ntreeInterfaceTypeFree(ntree);
+
+ BLI_freelistN(&ntree->links); /* do first, then unlink_node goes fast */
+
+ for (node = ntree->nodes.first; node; node = next) {
+ next = node->next;
+ node_free_node(ntree, node);
+ }
+
+ /* free interface sockets */
+ for (sock = ntree->inputs.first; sock; sock = nextsock) {
+ nextsock = sock->next;
+ node_socket_interface_free(ntree, sock);
+ MEM_freeN(sock);
+ }
+ for (sock = ntree->outputs.first; sock; sock = nextsock) {
+ nextsock = sock->next;
+ node_socket_interface_free(ntree, sock);
+ MEM_freeN(sock);
+ }
+
+ /* free preview hash */
+ if (ntree->previews) {
+ BKE_node_instance_hash_free(ntree->previews, (bNodeInstanceValueFP)BKE_node_preview_free);
+ }
+
+ if (ntree->duplilock)
+ BLI_mutex_free(ntree->duplilock);
+
+ if (ntree->id.tag & LIB_TAG_LOCALIZED) {
+ BKE_libblock_free_data(&ntree->id, true);
+ }
}
void ntreeFreeNestedTree(bNodeTree *ntree)
{
- ntreeFreeTree(ntree);
- BKE_libblock_free_data(&ntree->id, true);
+ ntreeFreeTree(ntree);
+ BKE_libblock_free_data(&ntree->id, true);
}
void ntreeFreeLocalTree(bNodeTree *ntree)
{
- if (ntree->id.tag & LIB_TAG_LOCALIZED) {
- ntreeFreeTree(ntree);
- }
- else {
- ntreeFreeTree(ntree);
- BKE_libblock_free_data(&ntree->id, true);
- }
+ if (ntree->id.tag & LIB_TAG_LOCALIZED) {
+ ntreeFreeTree(ntree);
+ }
+ else {
+ ntreeFreeTree(ntree);
+ BKE_libblock_free_data(&ntree->id, true);
+ }
}
void ntreeFreeCache(bNodeTree *ntree)
{
- if (ntree == NULL) return;
+ if (ntree == NULL)
+ return;
- if (ntree->typeinfo->free_cache)
- ntree->typeinfo->free_cache(ntree);
+ if (ntree->typeinfo->free_cache)
+ ntree->typeinfo->free_cache(ntree);
}
void ntreeSetOutput(bNodeTree *ntree)
{
- bNode *node;
-
- /* find the active outputs, might become tree type dependent handler */
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->typeinfo->nclass == NODE_CLASS_OUTPUT) {
- bNode *tnode;
- int output = 0;
-
- /* we need a check for which output node should be tagged like this, below an exception */
- if (node->type == CMP_NODE_OUTPUT_FILE)
- continue;
-
- /* there is more types having output class, each one is checked */
- for (tnode = ntree->nodes.first; tnode; tnode = tnode->next) {
- if (tnode->typeinfo->nclass == NODE_CLASS_OUTPUT) {
-
- if (ntree->type == NTREE_COMPOSIT) {
-
- /* same type, exception for viewer */
- if (tnode->type == node->type ||
- (ELEM(tnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER) &&
- ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)))
- {
- if (tnode->flag & NODE_DO_OUTPUT) {
- output++;
- if (output > 1)
- tnode->flag &= ~NODE_DO_OUTPUT;
- }
- }
- }
- else {
- /* same type */
- if (tnode->type == node->type) {
- if (tnode->flag & NODE_DO_OUTPUT) {
- output++;
- if (output > 1)
- tnode->flag &= ~NODE_DO_OUTPUT;
- }
- }
- }
- }
- }
- if (output == 0)
- node->flag |= NODE_DO_OUTPUT;
- }
-
- /* group node outputs use this flag too */
- if (node->type == NODE_GROUP_OUTPUT) {
- bNode *tnode;
- int output = 0;
-
- for (tnode = ntree->nodes.first; tnode; tnode = tnode->next) {
- if (tnode->type == NODE_GROUP_OUTPUT) {
- if (tnode->flag & NODE_DO_OUTPUT) {
- output++;
- if (output > 1)
- tnode->flag &= ~NODE_DO_OUTPUT;
- }
- }
- }
- if (output == 0)
- node->flag |= NODE_DO_OUTPUT;
- }
- }
-
- /* here we could recursively set which nodes have to be done,
- * might be different for editor or for "real" use... */
+ bNode *node;
+
+ /* find the active outputs, might become tree type dependent handler */
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (node->typeinfo->nclass == NODE_CLASS_OUTPUT) {
+ bNode *tnode;
+ int output = 0;
+
+ /* we need a check for which output node should be tagged like this, below an exception */
+ if (node->type == CMP_NODE_OUTPUT_FILE)
+ continue;
+
+ /* there is more types having output class, each one is checked */
+ for (tnode = ntree->nodes.first; tnode; tnode = tnode->next) {
+ if (tnode->typeinfo->nclass == NODE_CLASS_OUTPUT) {
+
+ if (ntree->type == NTREE_COMPOSIT) {
+
+ /* same type, exception for viewer */
+ if (tnode->type == node->type ||
+ (ELEM(tnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER) &&
+ ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))) {
+ if (tnode->flag & NODE_DO_OUTPUT) {
+ output++;
+ if (output > 1)
+ tnode->flag &= ~NODE_DO_OUTPUT;
+ }
+ }
+ }
+ else {
+ /* same type */
+ if (tnode->type == node->type) {
+ if (tnode->flag & NODE_DO_OUTPUT) {
+ output++;
+ if (output > 1)
+ tnode->flag &= ~NODE_DO_OUTPUT;
+ }
+ }
+ }
+ }
+ }
+ if (output == 0)
+ node->flag |= NODE_DO_OUTPUT;
+ }
+
+ /* group node outputs use this flag too */
+ if (node->type == NODE_GROUP_OUTPUT) {
+ bNode *tnode;
+ int output = 0;
+
+ for (tnode = ntree->nodes.first; tnode; tnode = tnode->next) {
+ if (tnode->type == NODE_GROUP_OUTPUT) {
+ if (tnode->flag & NODE_DO_OUTPUT) {
+ output++;
+ if (output > 1)
+ tnode->flag &= ~NODE_DO_OUTPUT;
+ }
+ }
+ }
+ if (output == 0)
+ node->flag |= NODE_DO_OUTPUT;
+ }
+ }
+
+ /* here we could recursively set which nodes have to be done,
+ * might be different for editor or for "real" use... */
}
bNodeTree *ntreeFromID(const ID *id)
{
- switch (GS(id->name)) {
- case ID_MA: return ((const Material *)id)->nodetree;
- case ID_LA: return ((const Light *)id)->nodetree;
- case ID_WO: return ((const World *)id)->nodetree;
- case ID_TE: return ((const Tex *)id)->nodetree;
- case ID_SCE: return ((const Scene *)id)->nodetree;
- case ID_LS: return ((const FreestyleLineStyle *)id)->nodetree;
- default: return NULL;
- }
+ switch (GS(id->name)) {
+ case ID_MA:
+ return ((const Material *)id)->nodetree;
+ case ID_LA:
+ return ((const Light *)id)->nodetree;
+ case ID_WO:
+ return ((const World *)id)->nodetree;
+ case ID_TE:
+ return ((const Tex *)id)->nodetree;
+ case ID_SCE:
+ return ((const Scene *)id)->nodetree;
+ case ID_LS:
+ return ((const FreestyleLineStyle *)id)->nodetree;
+ default:
+ return NULL;
+ }
}
void ntreeMakeLocal(Main *bmain, bNodeTree *ntree, bool id_in_mainlist, const bool lib_local)
{
- BKE_id_make_local_generic(bmain, &ntree->id, id_in_mainlist, lib_local);
+ BKE_id_make_local_generic(bmain, &ntree->id, id_in_mainlist, lib_local);
}
int ntreeNodeExists(bNodeTree *ntree, bNode *testnode)
{
- bNode *node = ntree->nodes.first;
- for (; node; node = node->next)
- if (node == testnode)
- return 1;
- return 0;
+ bNode *node = ntree->nodes.first;
+ for (; node; node = node->next)
+ if (node == testnode)
+ return 1;
+ return 0;
}
int ntreeOutputExists(bNode *node, bNodeSocket *testsock)
{
- bNodeSocket *sock = node->outputs.first;
- for (; sock; sock = sock->next)
- if (sock == testsock)
- return 1;
- return 0;
+ bNodeSocket *sock = node->outputs.first;
+ for (; sock; sock = sock->next)
+ if (sock == testsock)
+ return 1;
+ return 0;
}
void ntreeNodeFlagSet(const bNodeTree *ntree, const int flag, const bool enable)
{
- bNode *node = ntree->nodes.first;
+ bNode *node = ntree->nodes.first;
- for (; node; node = node->next) {
- if (enable) {
- node->flag |= flag;
- }
- else {
- node->flag &= ~flag;
- }
- }
+ for (; node; node = node->next) {
+ if (enable) {
+ node->flag |= flag;
+ }
+ else {
+ node->flag &= ~flag;
+ }
+ }
}
/* returns localized tree for execution in threads */
bNodeTree *ntreeLocalize(bNodeTree *ntree)
{
- if (ntree) {
- bNodeTree *ltree;
- bNode *node;
+ if (ntree) {
+ bNodeTree *ltree;
+ bNode *node;
- BLI_spin_lock(&spin);
- if (!ntree->duplilock) {
- ntree->duplilock = BLI_mutex_alloc();
- }
- BLI_spin_unlock(&spin);
+ BLI_spin_lock(&spin);
+ if (!ntree->duplilock) {
+ ntree->duplilock = BLI_mutex_alloc();
+ }
+ BLI_spin_unlock(&spin);
- BLI_mutex_lock(ntree->duplilock);
+ BLI_mutex_lock(ntree->duplilock);
- /* Make full copy outside of Main database.
- * Note: previews are not copied here.
- */
- BKE_id_copy_ex(
- NULL, &ntree->id, (ID **)&ltree,
- (LIB_ID_COPY_LOCALIZE |
- LIB_ID_COPY_NO_ANIMDATA));
+ /* Make full copy outside of Main database.
+ * Note: previews are not copied here.
+ */
+ BKE_id_copy_ex(
+ NULL, &ntree->id, (ID **)&ltree, (LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_NO_ANIMDATA));
- ltree->id.tag |= LIB_TAG_LOCALIZED;
+ ltree->id.tag |= LIB_TAG_LOCALIZED;
- for (node = ltree->nodes.first; node; node = node->next) {
- if ((ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) && node->id) {
- node->id = (ID *)ntreeLocalize((bNodeTree *)node->id);
- }
- }
+ for (node = ltree->nodes.first; node; node = node->next) {
+ if ((ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) && node->id) {
+ node->id = (ID *)ntreeLocalize((bNodeTree *)node->id);
+ }
+ }
- /* ensures only a single output node is enabled */
- ntreeSetOutput(ntree);
+ /* ensures only a single output node is enabled */
+ ntreeSetOutput(ntree);
- for (node = ntree->nodes.first; node; node = node->next) {
- /* store new_node pointer to original */
- node->new_node->original = node;
- }
+ for (node = ntree->nodes.first; node; node = node->next) {
+ /* store new_node pointer to original */
+ node->new_node->original = node;
+ }
- if (ntree->typeinfo->localize)
- ntree->typeinfo->localize(ltree, ntree);
+ if (ntree->typeinfo->localize)
+ ntree->typeinfo->localize(ltree, ntree);
- BLI_mutex_unlock(ntree->duplilock);
+ BLI_mutex_unlock(ntree->duplilock);
- return ltree;
- }
- else
- return NULL;
+ return ltree;
+ }
+ else
+ return NULL;
}
/* sync local composite with real tree */
@@ -2077,478 +2139,502 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree)
/* is called by jobs manager, outside threads, so it doesn't happen during draw */
void ntreeLocalSync(bNodeTree *localtree, bNodeTree *ntree)
{
- if (localtree && ntree) {
- if (ntree->typeinfo->local_sync)
- ntree->typeinfo->local_sync(localtree, ntree);
- }
+ if (localtree && ntree) {
+ if (ntree->typeinfo->local_sync)
+ ntree->typeinfo->local_sync(localtree, ntree);
+ }
}
/* merge local tree results back, and free local tree */
/* we have to assume the editor already changed completely */
void ntreeLocalMerge(Main *bmain, bNodeTree *localtree, bNodeTree *ntree)
{
- if (ntree && localtree) {
- if (ntree->typeinfo->local_merge)
- ntree->typeinfo->local_merge(bmain, localtree, ntree);
+ if (ntree && localtree) {
+ if (ntree->typeinfo->local_merge)
+ ntree->typeinfo->local_merge(bmain, localtree, ntree);
- ntreeFreeTree(localtree);
- MEM_freeN(localtree);
- }
+ ntreeFreeTree(localtree);
+ MEM_freeN(localtree);
+ }
}
-
/* ************ NODE TREE INTERFACE *************** */
-static bNodeSocket *make_socket_interface(bNodeTree *ntree, int in_out,
- const char *idname, const char *name)
-{
- bNodeSocketType *stype = nodeSocketTypeFind(idname);
- bNodeSocket *sock;
- int own_index = ntree->cur_index++;
-
- if (stype == NULL) {
- return NULL;
- }
-
- sock = MEM_callocN(sizeof(bNodeSocket), "socket template");
- BLI_strncpy(sock->idname, stype->idname, sizeof(sock->idname));
- node_socket_set_typeinfo(ntree, sock, stype);
- sock->in_out = in_out;
- sock->type = SOCK_CUSTOM; /* int type undefined by default */
-
- /* assign new unique index */
- own_index = ntree->cur_index++;
- /* use the own_index as socket identifier */
- if (in_out == SOCK_IN)
- BLI_snprintf(sock->identifier, MAX_NAME, "Input_%d", own_index);
- else
- BLI_snprintf(sock->identifier, MAX_NAME, "Output_%d", own_index);
+static bNodeSocket *make_socket_interface(bNodeTree *ntree,
+ int in_out,
+ const char *idname,
+ const char *name)
+{
+ bNodeSocketType *stype = nodeSocketTypeFind(idname);
+ bNodeSocket *sock;
+ int own_index = ntree->cur_index++;
+
+ if (stype == NULL) {
+ return NULL;
+ }
+
+ sock = MEM_callocN(sizeof(bNodeSocket), "socket template");
+ BLI_strncpy(sock->idname, stype->idname, sizeof(sock->idname));
+ node_socket_set_typeinfo(ntree, sock, stype);
+ sock->in_out = in_out;
+ sock->type = SOCK_CUSTOM; /* int type undefined by default */
+
+ /* assign new unique index */
+ own_index = ntree->cur_index++;
+ /* use the own_index as socket identifier */
+ if (in_out == SOCK_IN)
+ BLI_snprintf(sock->identifier, MAX_NAME, "Input_%d", own_index);
+ else
+ BLI_snprintf(sock->identifier, MAX_NAME, "Output_%d", own_index);
#ifdef USE_NODE_COMPAT_CUSTOMNODES
- /* XXX forward compatibility:
- * own_index is deprecated, but needs to be set here.
- * Node sockets generally use the identifier string instead now,
- * but reconstructing own_index in writefile.c would require parsing the identifier string.
- */
-
-#if (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 406)) || defined(__clang__)
-# pragma GCC diagnostic push
-# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#endif
+ /* XXX forward compatibility:
+ * own_index is deprecated, but needs to be set here.
+ * Node sockets generally use the identifier string instead now,
+ * but reconstructing own_index in writefile.c would require parsing the identifier string.
+ */
- sock->own_index = own_index;
+# if (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 406)) || defined(__clang__)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+# endif
-#if (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 406)) || defined(__clang__)
-# pragma GCC diagnostic pop
-#endif
+ sock->own_index = own_index;
+
+# if (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 406)) || defined(__clang__)
+# pragma GCC diagnostic pop
+# endif
-#endif /* USE_NODE_COMPAT_CUSTOMNODES */
+#endif /* USE_NODE_COMPAT_CUSTOMNODES */
- sock->limit = (in_out == SOCK_IN ? 1 : 0xFFF);
+ sock->limit = (in_out == SOCK_IN ? 1 : 0xFFF);
- BLI_strncpy(sock->name, name, NODE_MAXSTR);
- sock->storage = NULL;
- sock->flag |= SOCK_COLLAPSED;
+ BLI_strncpy(sock->name, name, NODE_MAXSTR);
+ sock->storage = NULL;
+ sock->flag |= SOCK_COLLAPSED;
- return sock;
+ return sock;
}
bNodeSocket *ntreeFindSocketInterface(bNodeTree *ntree, int in_out, const char *identifier)
{
- bNodeSocket *iosock = (in_out == SOCK_IN ? ntree->inputs.first : ntree->outputs.first);
- for (; iosock; iosock = iosock->next)
- if (STREQ(iosock->identifier, identifier))
- return iosock;
- return NULL;
+ bNodeSocket *iosock = (in_out == SOCK_IN ? ntree->inputs.first : ntree->outputs.first);
+ for (; iosock; iosock = iosock->next)
+ if (STREQ(iosock->identifier, identifier))
+ return iosock;
+ return NULL;
}
-bNodeSocket *ntreeAddSocketInterface(bNodeTree *ntree, int in_out, const char *idname, const char *name)
+bNodeSocket *ntreeAddSocketInterface(bNodeTree *ntree,
+ int in_out,
+ const char *idname,
+ const char *name)
{
- bNodeSocket *iosock;
+ bNodeSocket *iosock;
- iosock = make_socket_interface(ntree, in_out, idname, name);
- if (in_out == SOCK_IN) {
- BLI_addtail(&ntree->inputs, iosock);
- ntree->update |= NTREE_UPDATE_GROUP_IN;
- }
- else if (in_out == SOCK_OUT) {
- BLI_addtail(&ntree->outputs, iosock);
- ntree->update |= NTREE_UPDATE_GROUP_OUT;
- }
+ iosock = make_socket_interface(ntree, in_out, idname, name);
+ if (in_out == SOCK_IN) {
+ BLI_addtail(&ntree->inputs, iosock);
+ ntree->update |= NTREE_UPDATE_GROUP_IN;
+ }
+ else if (in_out == SOCK_OUT) {
+ BLI_addtail(&ntree->outputs, iosock);
+ ntree->update |= NTREE_UPDATE_GROUP_OUT;
+ }
- return iosock;
+ return iosock;
}
-bNodeSocket *ntreeInsertSocketInterface(bNodeTree *ntree, int in_out, const char *idname,
- bNodeSocket *next_sock, const char *name)
+bNodeSocket *ntreeInsertSocketInterface(
+ bNodeTree *ntree, int in_out, const char *idname, bNodeSocket *next_sock, const char *name)
{
- bNodeSocket *iosock;
+ bNodeSocket *iosock;
- iosock = make_socket_interface(ntree, in_out, idname, name);
- if (in_out == SOCK_IN) {
- BLI_insertlinkbefore(&ntree->inputs, next_sock, iosock);
- ntree->update |= NTREE_UPDATE_GROUP_IN;
- }
- else if (in_out == SOCK_OUT) {
- BLI_insertlinkbefore(&ntree->outputs, next_sock, iosock);
- ntree->update |= NTREE_UPDATE_GROUP_OUT;
- }
+ iosock = make_socket_interface(ntree, in_out, idname, name);
+ if (in_out == SOCK_IN) {
+ BLI_insertlinkbefore(&ntree->inputs, next_sock, iosock);
+ ntree->update |= NTREE_UPDATE_GROUP_IN;
+ }
+ else if (in_out == SOCK_OUT) {
+ BLI_insertlinkbefore(&ntree->outputs, next_sock, iosock);
+ ntree->update |= NTREE_UPDATE_GROUP_OUT;
+ }
- return iosock;
+ return iosock;
}
-struct bNodeSocket *ntreeAddSocketInterfaceFromSocket(bNodeTree *ntree, bNode *from_node, bNodeSocket *from_sock)
+struct bNodeSocket *ntreeAddSocketInterfaceFromSocket(bNodeTree *ntree,
+ bNode *from_node,
+ bNodeSocket *from_sock)
{
- bNodeSocket *iosock = ntreeAddSocketInterface(ntree, from_sock->in_out, from_sock->idname, from_sock->name);
- if (iosock) {
- if (iosock->typeinfo->interface_from_socket)
- iosock->typeinfo->interface_from_socket(ntree, iosock, from_node, from_sock);
- }
- return iosock;
+ bNodeSocket *iosock = ntreeAddSocketInterface(
+ ntree, from_sock->in_out, from_sock->idname, from_sock->name);
+ if (iosock) {
+ if (iosock->typeinfo->interface_from_socket)
+ iosock->typeinfo->interface_from_socket(ntree, iosock, from_node, from_sock);
+ }
+ return iosock;
}
-struct bNodeSocket *ntreeInsertSocketInterfaceFromSocket(bNodeTree *ntree, bNodeSocket *next_sock, bNode *from_node, bNodeSocket *from_sock)
+struct bNodeSocket *ntreeInsertSocketInterfaceFromSocket(bNodeTree *ntree,
+ bNodeSocket *next_sock,
+ bNode *from_node,
+ bNodeSocket *from_sock)
{
- bNodeSocket *iosock = ntreeInsertSocketInterface(ntree, from_sock->in_out, from_sock->idname, next_sock, from_sock->name);
- if (iosock) {
- if (iosock->typeinfo->interface_from_socket)
- iosock->typeinfo->interface_from_socket(ntree, iosock, from_node, from_sock);
- }
- return iosock;
+ bNodeSocket *iosock = ntreeInsertSocketInterface(
+ ntree, from_sock->in_out, from_sock->idname, next_sock, from_sock->name);
+ if (iosock) {
+ if (iosock->typeinfo->interface_from_socket)
+ iosock->typeinfo->interface_from_socket(ntree, iosock, from_node, from_sock);
+ }
+ return iosock;
}
void ntreeRemoveSocketInterface(bNodeTree *ntree, bNodeSocket *sock)
{
- /* this is fast, this way we don't need an in_out argument */
- BLI_remlink(&ntree->inputs, sock);
- BLI_remlink(&ntree->outputs, sock);
+ /* this is fast, this way we don't need an in_out argument */
+ BLI_remlink(&ntree->inputs, sock);
+ BLI_remlink(&ntree->outputs, sock);
- node_socket_interface_free(ntree, sock);
- MEM_freeN(sock);
+ node_socket_interface_free(ntree, sock);
+ MEM_freeN(sock);
- ntree->update |= NTREE_UPDATE_GROUP;
+ ntree->update |= NTREE_UPDATE_GROUP;
}
/* generates a valid RNA identifier from the node tree name */
static void ntree_interface_identifier_base(bNodeTree *ntree, char *base)
{
- /* generate a valid RNA identifier */
- sprintf(base, "NodeTreeInterface_%s", ntree->id.name + 2);
- RNA_identifier_sanitize(base, false);
+ /* generate a valid RNA identifier */
+ sprintf(base, "NodeTreeInterface_%s", ntree->id.name + 2);
+ RNA_identifier_sanitize(base, false);
}
/* check if the identifier is already in use */
static bool ntree_interface_unique_identifier_check(void *UNUSED(data), const char *identifier)
{
- return (RNA_struct_find(identifier) != NULL);
+ return (RNA_struct_find(identifier) != NULL);
}
/* generates the actual unique identifier and ui name and description */
-static void ntree_interface_identifier(bNodeTree *ntree, const char *base, char *identifier, int maxlen, char *name, char *description)
+static void ntree_interface_identifier(bNodeTree *ntree,
+ const char *base,
+ char *identifier,
+ int maxlen,
+ char *name,
+ char *description)
{
- /* There is a possibility that different node tree names get mapped to the same identifier
- * after sanitization (e.g. "SomeGroup_A", "SomeGroup.A" both get sanitized to "SomeGroup_A").
- * On top of the sanitized id string add a number suffix if necessary to avoid duplicates.
- */
- identifier[0] = '\0';
- BLI_uniquename_cb(ntree_interface_unique_identifier_check, NULL, base, '_', identifier, maxlen);
+ /* There is a possibility that different node tree names get mapped to the same identifier
+ * after sanitization (e.g. "SomeGroup_A", "SomeGroup.A" both get sanitized to "SomeGroup_A").
+ * On top of the sanitized id string add a number suffix if necessary to avoid duplicates.
+ */
+ identifier[0] = '\0';
+ BLI_uniquename_cb(ntree_interface_unique_identifier_check, NULL, base, '_', identifier, maxlen);
- sprintf(name, "Node Tree %s Interface", ntree->id.name + 2);
- sprintf(description, "Interface properties of node group %s", ntree->id.name + 2);
+ sprintf(name, "Node Tree %s Interface", ntree->id.name + 2);
+ sprintf(description, "Interface properties of node group %s", ntree->id.name + 2);
}
static void ntree_interface_type_create(bNodeTree *ntree)
{
- StructRNA *srna;
- bNodeSocket *sock;
- /* strings are generated from base string + ID name, sizes are sufficient */
- char base[MAX_ID_NAME + 64], identifier[MAX_ID_NAME + 64], name[MAX_ID_NAME + 64], description[MAX_ID_NAME + 64];
-
- /* generate a valid RNA identifier */
- ntree_interface_identifier_base(ntree, base);
- ntree_interface_identifier(ntree, base, identifier, sizeof(identifier), name, description);
-
- /* register a subtype of PropertyGroup */
- srna = RNA_def_struct_ptr(&BLENDER_RNA, identifier, &RNA_PropertyGroup);
- RNA_def_struct_ui_text(srna, name, description);
- RNA_def_struct_duplicate_pointers(&BLENDER_RNA, srna);
-
- /* associate the RNA type with the node tree */
- ntree->interface_type = srna;
- RNA_struct_blender_type_set(srna, ntree);
-
- /* add socket properties */
- for (sock = ntree->inputs.first; sock; sock = sock->next) {
- bNodeSocketType *stype = sock->typeinfo;
- if (stype && stype->interface_register_properties)
- stype->interface_register_properties(ntree, sock, srna);
- }
- for (sock = ntree->outputs.first; sock; sock = sock->next) {
- bNodeSocketType *stype = sock->typeinfo;
- if (stype && stype->interface_register_properties)
- stype->interface_register_properties(ntree, sock, srna);
- }
+ StructRNA *srna;
+ bNodeSocket *sock;
+ /* strings are generated from base string + ID name, sizes are sufficient */
+ char base[MAX_ID_NAME + 64], identifier[MAX_ID_NAME + 64], name[MAX_ID_NAME + 64],
+ description[MAX_ID_NAME + 64];
+
+ /* generate a valid RNA identifier */
+ ntree_interface_identifier_base(ntree, base);
+ ntree_interface_identifier(ntree, base, identifier, sizeof(identifier), name, description);
+
+ /* register a subtype of PropertyGroup */
+ srna = RNA_def_struct_ptr(&BLENDER_RNA, identifier, &RNA_PropertyGroup);
+ RNA_def_struct_ui_text(srna, name, description);
+ RNA_def_struct_duplicate_pointers(&BLENDER_RNA, srna);
+
+ /* associate the RNA type with the node tree */
+ ntree->interface_type = srna;
+ RNA_struct_blender_type_set(srna, ntree);
+
+ /* add socket properties */
+ for (sock = ntree->inputs.first; sock; sock = sock->next) {
+ bNodeSocketType *stype = sock->typeinfo;
+ if (stype && stype->interface_register_properties)
+ stype->interface_register_properties(ntree, sock, srna);
+ }
+ for (sock = ntree->outputs.first; sock; sock = sock->next) {
+ bNodeSocketType *stype = sock->typeinfo;
+ if (stype && stype->interface_register_properties)
+ stype->interface_register_properties(ntree, sock, srna);
+ }
}
StructRNA *ntreeInterfaceTypeGet(bNodeTree *ntree, int create)
{
- if (ntree->interface_type) {
- /* strings are generated from base string + ID name, sizes are sufficient */
- char base[MAX_ID_NAME + 64], identifier[MAX_ID_NAME + 64], name[MAX_ID_NAME + 64], description[MAX_ID_NAME + 64];
+ if (ntree->interface_type) {
+ /* strings are generated from base string + ID name, sizes are sufficient */
+ char base[MAX_ID_NAME + 64], identifier[MAX_ID_NAME + 64], name[MAX_ID_NAME + 64],
+ description[MAX_ID_NAME + 64];
- /* A bit of a hack: when changing the ID name, update the RNA type identifier too,
- * so that the names match. This is not strictly necessary to keep it working,
- * but better for identifying associated NodeTree blocks and RNA types.
- */
- StructRNA *srna = ntree->interface_type;
+ /* A bit of a hack: when changing the ID name, update the RNA type identifier too,
+ * so that the names match. This is not strictly necessary to keep it working,
+ * but better for identifying associated NodeTree blocks and RNA types.
+ */
+ StructRNA *srna = ntree->interface_type;
- ntree_interface_identifier_base(ntree, base);
+ ntree_interface_identifier_base(ntree, base);
- /* RNA identifier may have a number suffix, but should start with the idbase string */
- if (!STREQLEN(RNA_struct_identifier(srna), base, sizeof(base))) {
- /* generate new unique RNA identifier from the ID name */
- ntree_interface_identifier(ntree, base, identifier, sizeof(identifier), name, description);
+ /* RNA identifier may have a number suffix, but should start with the idbase string */
+ if (!STREQLEN(RNA_struct_identifier(srna), base, sizeof(base))) {
+ /* generate new unique RNA identifier from the ID name */
+ ntree_interface_identifier(ntree, base, identifier, sizeof(identifier), name, description);
- /* rename the RNA type */
- RNA_def_struct_free_pointers(&BLENDER_RNA, srna);
- RNA_def_struct_identifier(&BLENDER_RNA, srna, identifier);
- RNA_def_struct_ui_text(srna, name, description);
- RNA_def_struct_duplicate_pointers(&BLENDER_RNA, srna);
- }
- }
- else if (create) {
- ntree_interface_type_create(ntree);
- }
+ /* rename the RNA type */
+ RNA_def_struct_free_pointers(&BLENDER_RNA, srna);
+ RNA_def_struct_identifier(&BLENDER_RNA, srna, identifier);
+ RNA_def_struct_ui_text(srna, name, description);
+ RNA_def_struct_duplicate_pointers(&BLENDER_RNA, srna);
+ }
+ }
+ else if (create) {
+ ntree_interface_type_create(ntree);
+ }
- return ntree->interface_type;
+ return ntree->interface_type;
}
void ntreeInterfaceTypeFree(bNodeTree *ntree)
{
- if (ntree->interface_type) {
- RNA_struct_free(&BLENDER_RNA, ntree->interface_type);
- ntree->interface_type = NULL;
- }
+ if (ntree->interface_type) {
+ RNA_struct_free(&BLENDER_RNA, ntree->interface_type);
+ ntree->interface_type = NULL;
+ }
}
void ntreeInterfaceTypeUpdate(bNodeTree *ntree)
{
- /* XXX it would be sufficient to just recreate all properties
- * instead of re-registering the whole struct type,
- * but there is currently no good way to do this in the RNA functions.
- * Overhead should be negligible.
- */
- ntreeInterfaceTypeFree(ntree);
- ntree_interface_type_create(ntree);
+ /* XXX it would be sufficient to just recreate all properties
+ * instead of re-registering the whole struct type,
+ * but there is currently no good way to do this in the RNA functions.
+ * Overhead should be negligible.
+ */
+ ntreeInterfaceTypeFree(ntree);
+ ntree_interface_type_create(ntree);
}
-
/* ************ find stuff *************** */
bNode *ntreeFindType(const bNodeTree *ntree, int type)
{
- if (ntree) {
- for (bNode * node = ntree->nodes.first; node; node = node->next) {
- if (node->type == type) {
- return node;
- }
- }
- }
- return NULL;
+ if (ntree) {
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == type) {
+ return node;
+ }
+ }
+ }
+ return NULL;
}
bool ntreeHasType(const bNodeTree *ntree, int type)
{
- return ntreeFindType(ntree, type) != NULL;
+ return ntreeFindType(ntree, type) != NULL;
}
bool ntreeHasTree(const bNodeTree *ntree, const bNodeTree *lookup)
{
- bNode *node;
+ bNode *node;
- if (ntree == lookup)
- return true;
+ if (ntree == lookup)
+ return true;
- for (node = ntree->nodes.first; node; node = node->next)
- if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id)
- if (ntreeHasTree((bNodeTree *)node->id, lookup))
- return true;
+ for (node = ntree->nodes.first; node; node = node->next)
+ if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id)
+ if (ntreeHasTree((bNodeTree *)node->id, lookup))
+ return true;
- return false;
+ return false;
}
bNodeLink *nodeFindLink(bNodeTree *ntree, bNodeSocket *from, bNodeSocket *to)
{
- bNodeLink *link;
+ bNodeLink *link;
- for (link = ntree->links.first; link; link = link->next) {
- if (link->fromsock == from && link->tosock == to)
- return link;
- if (link->fromsock == to && link->tosock == from) /* hrms? */
- return link;
- }
- return NULL;
+ for (link = ntree->links.first; link; link = link->next) {
+ if (link->fromsock == from && link->tosock == to)
+ return link;
+ if (link->fromsock == to && link->tosock == from) /* hrms? */
+ return link;
+ }
+ return NULL;
}
int nodeCountSocketLinks(bNodeTree *ntree, bNodeSocket *sock)
{
- bNodeLink *link;
- int tot = 0;
+ bNodeLink *link;
+ int tot = 0;
- for (link = ntree->links.first; link; link = link->next) {
- if (link->fromsock == sock || link->tosock == sock)
- tot++;
- }
- return tot;
+ for (link = ntree->links.first; link; link = link->next) {
+ if (link->fromsock == sock || link->tosock == sock)
+ tot++;
+ }
+ return tot;
}
bNode *nodeGetActive(bNodeTree *ntree)
{
- bNode *node;
-
- if (ntree == NULL) return NULL;
-
- for (node = ntree->nodes.first; node; node = node->next)
- if (node->flag & NODE_ACTIVE)
- break;
- return node;
-}
-
-static bNode *node_get_active_id_recursive(bNodeInstanceKey active_key, bNodeInstanceKey parent_key, bNodeTree *ntree, short idtype)
-{
- if (parent_key.value == active_key.value || active_key.value == 0) {
- bNode *node;
- for (node = ntree->nodes.first; node; node = node->next)
- if (node->id && GS(node->id->name) == idtype)
- if (node->flag & NODE_ACTIVE_ID)
- return node;
- }
- else {
- bNode *node, *tnode;
- /* no node with active ID in this tree, look inside groups */
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == NODE_GROUP) {
- bNodeTree *group = (bNodeTree *)node->id;
- if (group) {
- bNodeInstanceKey group_key = BKE_node_instance_key(parent_key, ntree, node);
- tnode = node_get_active_id_recursive(active_key, group_key, group, idtype);
- if (tnode)
- return tnode;
- }
- }
- }
- }
-
- return NULL;
+ bNode *node;
+
+ if (ntree == NULL)
+ return NULL;
+
+ for (node = ntree->nodes.first; node; node = node->next)
+ if (node->flag & NODE_ACTIVE)
+ break;
+ return node;
+}
+
+static bNode *node_get_active_id_recursive(bNodeInstanceKey active_key,
+ bNodeInstanceKey parent_key,
+ bNodeTree *ntree,
+ short idtype)
+{
+ if (parent_key.value == active_key.value || active_key.value == 0) {
+ bNode *node;
+ for (node = ntree->nodes.first; node; node = node->next)
+ if (node->id && GS(node->id->name) == idtype)
+ if (node->flag & NODE_ACTIVE_ID)
+ return node;
+ }
+ else {
+ bNode *node, *tnode;
+ /* no node with active ID in this tree, look inside groups */
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == NODE_GROUP) {
+ bNodeTree *group = (bNodeTree *)node->id;
+ if (group) {
+ bNodeInstanceKey group_key = BKE_node_instance_key(parent_key, ntree, node);
+ tnode = node_get_active_id_recursive(active_key, group_key, group, idtype);
+ if (tnode)
+ return tnode;
+ }
+ }
+ }
+ }
+
+ return NULL;
}
/* two active flags, ID nodes have special flag for buttons display */
bNode *nodeGetActiveID(bNodeTree *ntree, short idtype)
{
- if (ntree)
- return node_get_active_id_recursive(ntree->active_viewer_key, NODE_INSTANCE_KEY_BASE, ntree, idtype);
- else
- return NULL;
+ if (ntree)
+ return node_get_active_id_recursive(
+ ntree->active_viewer_key, NODE_INSTANCE_KEY_BASE, ntree, idtype);
+ else
+ return NULL;
}
bool nodeSetActiveID(bNodeTree *ntree, short idtype, ID *id)
{
- bNode *node;
- bool ok = false;
+ bNode *node;
+ bool ok = false;
- if (ntree == NULL) return ok;
+ if (ntree == NULL)
+ return ok;
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->id && GS(node->id->name) == idtype) {
- if (id && ok == false && node->id == id) {
- node->flag |= NODE_ACTIVE_ID;
- ok = true;
- }
- else {
- node->flag &= ~NODE_ACTIVE_ID;
- }
- }
- }
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (node->id && GS(node->id->name) == idtype) {
+ if (id && ok == false && node->id == id) {
+ node->flag |= NODE_ACTIVE_ID;
+ ok = true;
+ }
+ else {
+ node->flag &= ~NODE_ACTIVE_ID;
+ }
+ }
+ }
- /* update all groups linked from here
- * if active ID node has been found already,
- * just pass NULL so other matching nodes are deactivated.
- */
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == NODE_GROUP)
- ok |= nodeSetActiveID((bNodeTree *)node->id, idtype, (ok == false ? id : NULL));
- }
+ /* update all groups linked from here
+ * if active ID node has been found already,
+ * just pass NULL so other matching nodes are deactivated.
+ */
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == NODE_GROUP)
+ ok |= nodeSetActiveID((bNodeTree *)node->id, idtype, (ok == false ? id : NULL));
+ }
- return ok;
+ return ok;
}
-
/* two active flags, ID nodes have special flag for buttons display */
void nodeClearActiveID(bNodeTree *ntree, short idtype)
{
- bNode *node;
+ bNode *node;
- if (ntree == NULL) return;
+ if (ntree == NULL)
+ return;
- for (node = ntree->nodes.first; node; node = node->next)
- if (node->id && GS(node->id->name) == idtype)
- node->flag &= ~NODE_ACTIVE_ID;
+ for (node = ntree->nodes.first; node; node = node->next)
+ if (node->id && GS(node->id->name) == idtype)
+ node->flag &= ~NODE_ACTIVE_ID;
}
void nodeSetSelected(bNode *node, bool select)
{
- if (select) {
- node->flag |= NODE_SELECT;
- }
- else {
- bNodeSocket *sock;
+ if (select) {
+ node->flag |= NODE_SELECT;
+ }
+ else {
+ bNodeSocket *sock;
- node->flag &= ~NODE_SELECT;
+ node->flag &= ~NODE_SELECT;
- /* deselect sockets too */
- for (sock = node->inputs.first; sock; sock = sock->next)
- sock->flag &= ~NODE_SELECT;
- for (sock = node->outputs.first; sock; sock = sock->next)
- sock->flag &= ~NODE_SELECT;
- }
+ /* deselect sockets too */
+ for (sock = node->inputs.first; sock; sock = sock->next)
+ sock->flag &= ~NODE_SELECT;
+ for (sock = node->outputs.first; sock; sock = sock->next)
+ sock->flag &= ~NODE_SELECT;
+ }
}
void nodeClearActive(bNodeTree *ntree)
{
- bNode *node;
+ bNode *node;
- if (ntree == NULL) return;
+ if (ntree == NULL)
+ return;
- for (node = ntree->nodes.first; node; node = node->next)
- node->flag &= ~(NODE_ACTIVE | NODE_ACTIVE_ID);
+ for (node = ntree->nodes.first; node; node = node->next)
+ node->flag &= ~(NODE_ACTIVE | NODE_ACTIVE_ID);
}
/* two active flags, ID nodes have special flag for buttons display */
void nodeSetActive(bNodeTree *ntree, bNode *node)
{
- bNode *tnode;
+ bNode *tnode;
- /* make sure only one node is active, and only one per ID type */
- for (tnode = ntree->nodes.first; tnode; tnode = tnode->next) {
- tnode->flag &= ~NODE_ACTIVE;
+ /* make sure only one node is active, and only one per ID type */
+ for (tnode = ntree->nodes.first; tnode; tnode = tnode->next) {
+ tnode->flag &= ~NODE_ACTIVE;
- if (node->id && tnode->id) {
- if (GS(node->id->name) == GS(tnode->id->name))
- tnode->flag &= ~NODE_ACTIVE_ID;
- }
- if (node->typeinfo->nclass == NODE_CLASS_TEXTURE)
- tnode->flag &= ~NODE_ACTIVE_TEXTURE;
- }
+ if (node->id && tnode->id) {
+ if (GS(node->id->name) == GS(tnode->id->name))
+ tnode->flag &= ~NODE_ACTIVE_ID;
+ }
+ if (node->typeinfo->nclass == NODE_CLASS_TEXTURE)
+ tnode->flag &= ~NODE_ACTIVE_TEXTURE;
+ }
- node->flag |= NODE_ACTIVE;
- if (node->id)
- node->flag |= NODE_ACTIVE_ID;
- if (node->typeinfo->nclass == NODE_CLASS_TEXTURE)
- node->flag |= NODE_ACTIVE_TEXTURE;
+ node->flag |= NODE_ACTIVE;
+ if (node->id)
+ node->flag |= NODE_ACTIVE_ID;
+ if (node->typeinfo->nclass == NODE_CLASS_TEXTURE)
+ node->flag |= NODE_ACTIVE_TEXTURE;
}
int nodeSocketIsHidden(bNodeSocket *sock)
{
- return ((sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) != 0);
+ return ((sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) != 0);
}
/* ************** Node Clipboard *********** */
@@ -2564,152 +2650,149 @@ int nodeSocketIsHidden(bNodeSocket *sock)
* reference other pointers which need validation.
*/
typedef struct bNodeClipboardExtraInfo {
- struct bNodeClipboardExtraInfo *next, *prev;
- ID *id;
- char id_name[MAX_ID_NAME];
- char library_name[FILE_MAX];
+ struct bNodeClipboardExtraInfo *next, *prev;
+ ID *id;
+ char id_name[MAX_ID_NAME];
+ char library_name[FILE_MAX];
} bNodeClipboardExtraInfo;
-#endif /* USE_NODE_CB_VALIDATE */
-
+#endif /* USE_NODE_CB_VALIDATE */
typedef struct bNodeClipboard {
- ListBase nodes;
+ ListBase nodes;
#ifdef USE_NODE_CB_VALIDATE
- ListBase nodes_extra_info;
+ ListBase nodes_extra_info;
#endif
- ListBase links;
- int type;
+ ListBase links;
+ int type;
} bNodeClipboard;
static bNodeClipboard node_clipboard = {{NULL}};
void BKE_node_clipboard_init(struct bNodeTree *ntree)
{
- node_clipboard.type = ntree->type;
+ node_clipboard.type = ntree->type;
}
void BKE_node_clipboard_clear(void)
{
- bNode *node, *node_next;
- bNodeLink *link, *link_next;
+ bNode *node, *node_next;
+ bNodeLink *link, *link_next;
- for (link = node_clipboard.links.first; link; link = link_next) {
- link_next = link->next;
- nodeRemLink(NULL, link);
- }
- BLI_listbase_clear(&node_clipboard.links);
+ for (link = node_clipboard.links.first; link; link = link_next) {
+ link_next = link->next;
+ nodeRemLink(NULL, link);
+ }
+ BLI_listbase_clear(&node_clipboard.links);
- for (node = node_clipboard.nodes.first; node; node = node_next) {
- node_next = node->next;
- node_free_node(NULL, node);
- }
- BLI_listbase_clear(&node_clipboard.nodes);
+ for (node = node_clipboard.nodes.first; node; node = node_next) {
+ node_next = node->next;
+ node_free_node(NULL, node);
+ }
+ BLI_listbase_clear(&node_clipboard.nodes);
#ifdef USE_NODE_CB_VALIDATE
- BLI_freelistN(&node_clipboard.nodes_extra_info);
+ BLI_freelistN(&node_clipboard.nodes_extra_info);
#endif
}
/* return false when one or more ID's are lost */
bool BKE_node_clipboard_validate(void)
{
- bool ok = true;
+ bool ok = true;
#ifdef USE_NODE_CB_VALIDATE
- bNodeClipboardExtraInfo *node_info;
- bNode *node;
-
+ bNodeClipboardExtraInfo *node_info;
+ bNode *node;
- /* lists must be aligned */
- BLI_assert(BLI_listbase_count(&node_clipboard.nodes) ==
- BLI_listbase_count(&node_clipboard.nodes_extra_info));
+ /* lists must be aligned */
+ BLI_assert(BLI_listbase_count(&node_clipboard.nodes) ==
+ BLI_listbase_count(&node_clipboard.nodes_extra_info));
- for (node = node_clipboard.nodes.first, node_info = node_clipboard.nodes_extra_info.first;
- node;
- node = node->next, node_info = node_info->next)
- {
- /* validate the node against the stored node info */
+ for (node = node_clipboard.nodes.first, node_info = node_clipboard.nodes_extra_info.first; node;
+ node = node->next, node_info = node_info->next) {
+ /* validate the node against the stored node info */
- /* re-assign each loop since we may clear,
- * open a new file where the ID is valid, and paste again */
- node->id = node_info->id;
+ /* re-assign each loop since we may clear,
+ * open a new file where the ID is valid, and paste again */
+ node->id = node_info->id;
- /* currently only validate the ID */
- if (node->id) {
- /* We want to search into current blend file, so using G_MAIN is valid here too. */
- ListBase *lb = which_libbase(G_MAIN, GS(node_info->id_name));
- BLI_assert(lb != NULL);
+ /* currently only validate the ID */
+ if (node->id) {
+ /* We want to search into current blend file, so using G_MAIN is valid here too. */
+ ListBase *lb = which_libbase(G_MAIN, GS(node_info->id_name));
+ BLI_assert(lb != NULL);
- if (BLI_findindex(lb, node_info->id) == -1) {
- /* may assign NULL */
- node->id = BLI_findstring(lb, node_info->id_name + 2, offsetof(ID, name) + 2);
+ if (BLI_findindex(lb, node_info->id) == -1) {
+ /* may assign NULL */
+ node->id = BLI_findstring(lb, node_info->id_name + 2, offsetof(ID, name) + 2);
- if (node->id == NULL) {
- ok = false;
- }
- }
- }
- }
-#endif /* USE_NODE_CB_VALIDATE */
+ if (node->id == NULL) {
+ ok = false;
+ }
+ }
+ }
+ }
+#endif /* USE_NODE_CB_VALIDATE */
- return ok;
+ return ok;
}
void BKE_node_clipboard_add_node(bNode *node)
{
#ifdef USE_NODE_CB_VALIDATE
- /* add extra info */
- bNodeClipboardExtraInfo *node_info = MEM_mallocN(sizeof(bNodeClipboardExtraInfo), "bNodeClipboardExtraInfo");
-
- node_info->id = node->id;
- if (node->id) {
- BLI_strncpy(node_info->id_name, node->id->name, sizeof(node_info->id_name));
- if (ID_IS_LINKED(node->id)) {
- BLI_strncpy(node_info->library_name, node->id->lib->filepath, sizeof(node_info->library_name));
- }
- else {
- node_info->library_name[0] = '\0';
- }
- }
- else {
- node_info->id_name[0] = '\0';
- node_info->library_name[0] = '\0';
- }
- BLI_addtail(&node_clipboard.nodes_extra_info, node_info);
- /* end extra info */
-#endif /* USE_NODE_CB_VALIDATE */
-
- /* add node */
- BLI_addtail(&node_clipboard.nodes, node);
-
+ /* add extra info */
+ bNodeClipboardExtraInfo *node_info = MEM_mallocN(sizeof(bNodeClipboardExtraInfo),
+ "bNodeClipboardExtraInfo");
+
+ node_info->id = node->id;
+ if (node->id) {
+ BLI_strncpy(node_info->id_name, node->id->name, sizeof(node_info->id_name));
+ if (ID_IS_LINKED(node->id)) {
+ BLI_strncpy(
+ node_info->library_name, node->id->lib->filepath, sizeof(node_info->library_name));
+ }
+ else {
+ node_info->library_name[0] = '\0';
+ }
+ }
+ else {
+ node_info->id_name[0] = '\0';
+ node_info->library_name[0] = '\0';
+ }
+ BLI_addtail(&node_clipboard.nodes_extra_info, node_info);
+ /* end extra info */
+#endif /* USE_NODE_CB_VALIDATE */
+
+ /* add node */
+ BLI_addtail(&node_clipboard.nodes, node);
}
void BKE_node_clipboard_add_link(bNodeLink *link)
{
- BLI_addtail(&node_clipboard.links, link);
+ BLI_addtail(&node_clipboard.links, link);
}
const ListBase *BKE_node_clipboard_get_nodes(void)
{
- return &node_clipboard.nodes;
+ return &node_clipboard.nodes;
}
const ListBase *BKE_node_clipboard_get_links(void)
{
- return &node_clipboard.links;
+ return &node_clipboard.links;
}
int BKE_node_clipboard_get_type(void)
{
- return node_clipboard.type;
+ return node_clipboard.type;
}
void BKE_node_clipboard_free(void)
{
- BKE_node_clipboard_validate();
- BKE_node_clipboard_clear();
+ BKE_node_clipboard_validate();
+ BKE_node_clipboard_clear();
}
/* Node Instance Hash */
@@ -2724,598 +2807,623 @@ const bNodeInstanceKey NODE_INSTANCE_KEY_NONE = {0};
*/
static bNodeInstanceKey node_hash_int_str(bNodeInstanceKey hash, const char *str)
{
- char c;
+ char c;
- while ((c = *str++))
- hash.value = ((hash.value << 5) + hash.value) ^ c; /* (hash * 33) ^ c */
+ while ((c = *str++))
+ hash.value = ((hash.value << 5) + hash.value) ^ c; /* (hash * 33) ^ c */
- /* separator '\0' character, to avoid ambiguity from concatenated strings */
- hash.value = (hash.value << 5) + hash.value; /* hash * 33 */
+ /* separator '\0' character, to avoid ambiguity from concatenated strings */
+ hash.value = (hash.value << 5) + hash.value; /* hash * 33 */
- return hash;
+ return hash;
}
bNodeInstanceKey BKE_node_instance_key(bNodeInstanceKey parent_key, bNodeTree *ntree, bNode *node)
{
- bNodeInstanceKey key;
+ bNodeInstanceKey key;
- key = node_hash_int_str(parent_key, ntree->id.name + 2);
+ key = node_hash_int_str(parent_key, ntree->id.name + 2);
- if (node)
- key = node_hash_int_str(key, node->name);
+ if (node)
+ key = node_hash_int_str(key, node->name);
- return key;
+ return key;
}
static unsigned int node_instance_hash_key(const void *key)
{
- return ((const bNodeInstanceKey *)key)->value;
+ return ((const bNodeInstanceKey *)key)->value;
}
static bool node_instance_hash_key_cmp(const void *a, const void *b)
{
- unsigned int value_a = ((const bNodeInstanceKey *)a)->value;
- unsigned int value_b = ((const bNodeInstanceKey *)b)->value;
+ unsigned int value_a = ((const bNodeInstanceKey *)a)->value;
+ unsigned int value_b = ((const bNodeInstanceKey *)b)->value;
- return (value_a != value_b);
+ return (value_a != value_b);
}
bNodeInstanceHash *BKE_node_instance_hash_new(const char *info)
{
- bNodeInstanceHash *hash = MEM_mallocN(sizeof(bNodeInstanceHash), info);
- hash->ghash = BLI_ghash_new(node_instance_hash_key, node_instance_hash_key_cmp, "node instance hash ghash");
- return hash;
+ bNodeInstanceHash *hash = MEM_mallocN(sizeof(bNodeInstanceHash), info);
+ hash->ghash = BLI_ghash_new(
+ node_instance_hash_key, node_instance_hash_key_cmp, "node instance hash ghash");
+ return hash;
}
void BKE_node_instance_hash_free(bNodeInstanceHash *hash, bNodeInstanceValueFP valfreefp)
{
- BLI_ghash_free(hash->ghash, NULL, (GHashValFreeFP)valfreefp);
- MEM_freeN(hash);
+ BLI_ghash_free(hash->ghash, NULL, (GHashValFreeFP)valfreefp);
+ MEM_freeN(hash);
}
void BKE_node_instance_hash_insert(bNodeInstanceHash *hash, bNodeInstanceKey key, void *value)
{
- bNodeInstanceHashEntry *entry = value;
- entry->key = key;
- entry->tag = 0;
- BLI_ghash_insert(hash->ghash, &entry->key, value);
+ bNodeInstanceHashEntry *entry = value;
+ entry->key = key;
+ entry->tag = 0;
+ BLI_ghash_insert(hash->ghash, &entry->key, value);
}
void *BKE_node_instance_hash_lookup(bNodeInstanceHash *hash, bNodeInstanceKey key)
{
- return BLI_ghash_lookup(hash->ghash, &key);
+ return BLI_ghash_lookup(hash->ghash, &key);
}
-int BKE_node_instance_hash_remove(bNodeInstanceHash *hash, bNodeInstanceKey key, bNodeInstanceValueFP valfreefp)
+int BKE_node_instance_hash_remove(bNodeInstanceHash *hash,
+ bNodeInstanceKey key,
+ bNodeInstanceValueFP valfreefp)
{
- return BLI_ghash_remove(hash->ghash, &key, NULL, (GHashValFreeFP)valfreefp);
+ return BLI_ghash_remove(hash->ghash, &key, NULL, (GHashValFreeFP)valfreefp);
}
void BKE_node_instance_hash_clear(bNodeInstanceHash *hash, bNodeInstanceValueFP valfreefp)
{
- BLI_ghash_clear(hash->ghash, NULL, (GHashValFreeFP)valfreefp);
+ BLI_ghash_clear(hash->ghash, NULL, (GHashValFreeFP)valfreefp);
}
void *BKE_node_instance_hash_pop(bNodeInstanceHash *hash, bNodeInstanceKey key)
{
- return BLI_ghash_popkey(hash->ghash, &key, NULL);
+ return BLI_ghash_popkey(hash->ghash, &key, NULL);
}
int BKE_node_instance_hash_haskey(bNodeInstanceHash *hash, bNodeInstanceKey key)
{
- return BLI_ghash_haskey(hash->ghash, &key);
+ return BLI_ghash_haskey(hash->ghash, &key);
}
int BKE_node_instance_hash_size(bNodeInstanceHash *hash)
{
- return BLI_ghash_len(hash->ghash);
+ return BLI_ghash_len(hash->ghash);
}
void BKE_node_instance_hash_clear_tags(bNodeInstanceHash *hash)
{
- bNodeInstanceHashIterator iter;
+ bNodeInstanceHashIterator iter;
- NODE_INSTANCE_HASH_ITER(iter, hash) {
- bNodeInstanceHashEntry *value = BKE_node_instance_hash_iterator_get_value(&iter);
+ NODE_INSTANCE_HASH_ITER(iter, hash)
+ {
+ bNodeInstanceHashEntry *value = BKE_node_instance_hash_iterator_get_value(&iter);
- value->tag = 0;
- }
+ value->tag = 0;
+ }
}
void BKE_node_instance_hash_tag(bNodeInstanceHash *UNUSED(hash), void *value)
{
- bNodeInstanceHashEntry *entry = value;
- entry->tag = 1;
+ bNodeInstanceHashEntry *entry = value;
+ entry->tag = 1;
}
bool BKE_node_instance_hash_tag_key(bNodeInstanceHash *hash, bNodeInstanceKey key)
{
- bNodeInstanceHashEntry *entry = BKE_node_instance_hash_lookup(hash, key);
+ bNodeInstanceHashEntry *entry = BKE_node_instance_hash_lookup(hash, key);
- if (entry) {
- entry->tag = 1;
- return true;
- }
- else
- return false;
+ if (entry) {
+ entry->tag = 1;
+ return true;
+ }
+ else
+ return false;
}
-void BKE_node_instance_hash_remove_untagged(bNodeInstanceHash *hash, bNodeInstanceValueFP valfreefp)
+void BKE_node_instance_hash_remove_untagged(bNodeInstanceHash *hash,
+ bNodeInstanceValueFP valfreefp)
{
- /* NOTE: Hash must not be mutated during iterating!
- * Store tagged entries in a separate list and remove items afterward.
- */
- bNodeInstanceKey *untagged = MEM_mallocN(sizeof(bNodeInstanceKey) * BKE_node_instance_hash_size(hash), "temporary node instance key list");
- bNodeInstanceHashIterator iter;
- int num_untagged, i;
+ /* NOTE: Hash must not be mutated during iterating!
+ * Store tagged entries in a separate list and remove items afterward.
+ */
+ bNodeInstanceKey *untagged = MEM_mallocN(sizeof(bNodeInstanceKey) *
+ BKE_node_instance_hash_size(hash),
+ "temporary node instance key list");
+ bNodeInstanceHashIterator iter;
+ int num_untagged, i;
- num_untagged = 0;
- NODE_INSTANCE_HASH_ITER(iter, hash) {
- bNodeInstanceHashEntry *value = BKE_node_instance_hash_iterator_get_value(&iter);
+ num_untagged = 0;
+ NODE_INSTANCE_HASH_ITER(iter, hash)
+ {
+ bNodeInstanceHashEntry *value = BKE_node_instance_hash_iterator_get_value(&iter);
- if (!value->tag)
- untagged[num_untagged++] = BKE_node_instance_hash_iterator_get_key(&iter);
- }
+ if (!value->tag)
+ untagged[num_untagged++] = BKE_node_instance_hash_iterator_get_key(&iter);
+ }
- for (i = 0; i < num_untagged; ++i) {
- BKE_node_instance_hash_remove(hash, untagged[i], valfreefp);
- }
+ for (i = 0; i < num_untagged; ++i) {
+ BKE_node_instance_hash_remove(hash, untagged[i], valfreefp);
+ }
- MEM_freeN(untagged);
+ MEM_freeN(untagged);
}
-
/* ************** dependency stuff *********** */
/* node is guaranteed to be not checked before */
static int node_get_deplist_recurs(bNodeTree *ntree, bNode *node, bNode ***nsort)
{
- bNode *fromnode;
- bNodeLink *link;
- int level = 0xFFF;
+ bNode *fromnode;
+ bNodeLink *link;
+ int level = 0xFFF;
- node->done = true;
+ node->done = true;
- /* check linked nodes */
- for (link = ntree->links.first; link; link = link->next) {
- if (link->tonode == node) {
- fromnode = link->fromnode;
- if (fromnode->done == 0)
- fromnode->level = node_get_deplist_recurs(ntree, fromnode, nsort);
- if (fromnode->level <= level)
- level = fromnode->level - 1;
- }
- }
+ /* check linked nodes */
+ for (link = ntree->links.first; link; link = link->next) {
+ if (link->tonode == node) {
+ fromnode = link->fromnode;
+ if (fromnode->done == 0)
+ fromnode->level = node_get_deplist_recurs(ntree, fromnode, nsort);
+ if (fromnode->level <= level)
+ level = fromnode->level - 1;
+ }
+ }
- /* check parent node */
- if (node->parent) {
- if (node->parent->done == 0)
- node->parent->level = node_get_deplist_recurs(ntree, node->parent, nsort);
- if (node->parent->level <= level)
- level = node->parent->level - 1;
- }
+ /* check parent node */
+ if (node->parent) {
+ if (node->parent->done == 0)
+ node->parent->level = node_get_deplist_recurs(ntree, node->parent, nsort);
+ if (node->parent->level <= level)
+ level = node->parent->level - 1;
+ }
- if (nsort) {
- **nsort = node;
- (*nsort)++;
- }
+ if (nsort) {
+ **nsort = node;
+ (*nsort)++;
+ }
- return level;
+ return level;
}
void ntreeGetDependencyList(struct bNodeTree *ntree, struct bNode ***deplist, int *totnodes)
{
- bNode *node, **nsort;
+ bNode *node, **nsort;
- *totnodes = 0;
+ *totnodes = 0;
- /* first clear data */
- for (node = ntree->nodes.first; node; node = node->next) {
- node->done = false;
- (*totnodes)++;
- }
- if (*totnodes == 0) {
- *deplist = NULL;
- return;
- }
+ /* first clear data */
+ for (node = ntree->nodes.first; node; node = node->next) {
+ node->done = false;
+ (*totnodes)++;
+ }
+ if (*totnodes == 0) {
+ *deplist = NULL;
+ return;
+ }
- nsort = *deplist = MEM_callocN((*totnodes) * sizeof(bNode *), "sorted node array");
+ nsort = *deplist = MEM_callocN((*totnodes) * sizeof(bNode *), "sorted node array");
- /* recursive check */
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->done == 0) {
- node->level = node_get_deplist_recurs(ntree, node, &nsort);
- }
- }
+ /* recursive check */
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (node->done == 0) {
+ node->level = node_get_deplist_recurs(ntree, node, &nsort);
+ }
+ }
}
/* only updates node->level for detecting cycles links */
static void ntree_update_node_level(bNodeTree *ntree)
{
- bNode *node;
+ bNode *node;
- /* first clear tag */
- for (node = ntree->nodes.first; node; node = node->next) {
- node->done = false;
- }
+ /* first clear tag */
+ for (node = ntree->nodes.first; node; node = node->next) {
+ node->done = false;
+ }
- /* recursive check */
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->done == 0) {
- node->level = node_get_deplist_recurs(ntree, node, NULL);
- }
- }
+ /* recursive check */
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (node->done == 0) {
+ node->level = node_get_deplist_recurs(ntree, node, NULL);
+ }
+ }
}
void ntreeTagUsedSockets(bNodeTree *ntree)
{
- bNode *node;
- bNodeSocket *sock;
- bNodeLink *link;
+ bNode *node;
+ bNodeSocket *sock;
+ bNodeLink *link;
- /* first clear data */
- for (node = ntree->nodes.first; node; node = node->next) {
- for (sock = node->inputs.first; sock; sock = sock->next) {
- sock->flag &= ~SOCK_IN_USE;
- }
- for (sock = node->outputs.first; sock; sock = sock->next) {
- sock->flag &= ~SOCK_IN_USE;
- }
- }
+ /* first clear data */
+ for (node = ntree->nodes.first; node; node = node->next) {
+ for (sock = node->inputs.first; sock; sock = sock->next) {
+ sock->flag &= ~SOCK_IN_USE;
+ }
+ for (sock = node->outputs.first; sock; sock = sock->next) {
+ sock->flag &= ~SOCK_IN_USE;
+ }
+ }
- for (link = ntree->links.first; link; link = link->next) {
- /* link is unused if either side is disabled */
- if ((link->fromsock->flag & SOCK_UNAVAIL) || (link->tosock->flag & SOCK_UNAVAIL))
- continue;
+ for (link = ntree->links.first; link; link = link->next) {
+ /* link is unused if either side is disabled */
+ if ((link->fromsock->flag & SOCK_UNAVAIL) || (link->tosock->flag & SOCK_UNAVAIL))
+ continue;
- link->fromsock->flag |= SOCK_IN_USE;
- link->tosock->flag |= SOCK_IN_USE;
- }
+ link->fromsock->flag |= SOCK_IN_USE;
+ link->tosock->flag |= SOCK_IN_USE;
+ }
}
static void ntree_update_link_pointers(bNodeTree *ntree)
{
- bNode *node;
- bNodeSocket *sock;
- bNodeLink *link;
+ bNode *node;
+ bNodeSocket *sock;
+ bNodeLink *link;
- /* first clear data */
- for (node = ntree->nodes.first; node; node = node->next) {
- for (sock = node->inputs.first; sock; sock = sock->next) {
- sock->link = NULL;
- }
- }
+ /* first clear data */
+ for (node = ntree->nodes.first; node; node = node->next) {
+ for (sock = node->inputs.first; sock; sock = sock->next) {
+ sock->link = NULL;
+ }
+ }
- for (link = ntree->links.first; link; link = link->next) {
- link->tosock->link = link;
- }
+ for (link = ntree->links.first; link; link = link->next) {
+ link->tosock->link = link;
+ }
- ntreeTagUsedSockets(ntree);
+ ntreeTagUsedSockets(ntree);
}
static void ntree_validate_links(bNodeTree *ntree)
{
- bNodeLink *link;
+ bNodeLink *link;
- for (link = ntree->links.first; link; link = link->next) {
- link->flag |= NODE_LINK_VALID;
- if (link->fromnode && link->tonode && link->fromnode->level <= link->tonode->level)
- link->flag &= ~NODE_LINK_VALID;
- else if (ntree->typeinfo->validate_link) {
- if (!ntree->typeinfo->validate_link(ntree, link))
- link->flag &= ~NODE_LINK_VALID;
- }
- }
+ for (link = ntree->links.first; link; link = link->next) {
+ link->flag |= NODE_LINK_VALID;
+ if (link->fromnode && link->tonode && link->fromnode->level <= link->tonode->level)
+ link->flag &= ~NODE_LINK_VALID;
+ else if (ntree->typeinfo->validate_link) {
+ if (!ntree->typeinfo->validate_link(ntree, link))
+ link->flag &= ~NODE_LINK_VALID;
+ }
+ }
}
void ntreeVerifyNodes(struct Main *main, struct ID *id)
{
- FOREACH_NODETREE_BEGIN(main, ntree, owner_id) {
- bNode *node;
+ FOREACH_NODETREE_BEGIN (main, ntree, owner_id) {
+ bNode *node;
- for (node = ntree->nodes.first; node; node = node->next)
- if (node->typeinfo->verifyfunc)
- node->typeinfo->verifyfunc(ntree, node, id);
- } FOREACH_NODETREE_END;
+ for (node = ntree->nodes.first; node; node = node->next)
+ if (node->typeinfo->verifyfunc)
+ node->typeinfo->verifyfunc(ntree, node, id);
+ }
+ FOREACH_NODETREE_END;
}
void ntreeUpdateTree(Main *bmain, bNodeTree *ntree)
{
- bNode *node;
+ bNode *node;
- if (!ntree)
- return;
+ if (!ntree)
+ return;
- /* avoid reentrant updates, can be caused by RNA update callbacks */
- if (ntree->is_updating)
- return;
- ntree->is_updating = true;
+ /* avoid reentrant updates, can be caused by RNA update callbacks */
+ if (ntree->is_updating)
+ return;
+ ntree->is_updating = true;
- if (ntree->update & (NTREE_UPDATE_LINKS | NTREE_UPDATE_NODES)) {
- /* set the bNodeSocket->link pointers */
- ntree_update_link_pointers(ntree);
- }
+ if (ntree->update & (NTREE_UPDATE_LINKS | NTREE_UPDATE_NODES)) {
+ /* set the bNodeSocket->link pointers */
+ ntree_update_link_pointers(ntree);
+ }
- /* update individual nodes */
- for (node = ntree->nodes.first; node; node = node->next) {
- /* node tree update tags override individual node update flags */
- if ((node->update & NODE_UPDATE) || (ntree->update & NTREE_UPDATE)) {
- if (node->typeinfo->updatefunc)
- node->typeinfo->updatefunc(ntree, node);
+ /* update individual nodes */
+ for (node = ntree->nodes.first; node; node = node->next) {
+ /* node tree update tags override individual node update flags */
+ if ((node->update & NODE_UPDATE) || (ntree->update & NTREE_UPDATE)) {
+ if (node->typeinfo->updatefunc)
+ node->typeinfo->updatefunc(ntree, node);
- nodeUpdateInternalLinks(ntree, node);
- }
- }
+ nodeUpdateInternalLinks(ntree, node);
+ }
+ }
- /* generic tree update callback */
- if (ntree->typeinfo->update)
- ntree->typeinfo->update(ntree);
- /* XXX this should be moved into the tree type update callback for tree supporting node groups.
- * Currently the node tree interface is still a generic feature of the base NodeTree type.
- */
- if (ntree->update & NTREE_UPDATE_GROUP)
- ntreeInterfaceTypeUpdate(ntree);
+ /* generic tree update callback */
+ if (ntree->typeinfo->update)
+ ntree->typeinfo->update(ntree);
+ /* XXX this should be moved into the tree type update callback for tree supporting node groups.
+ * Currently the node tree interface is still a generic feature of the base NodeTree type.
+ */
+ if (ntree->update & NTREE_UPDATE_GROUP)
+ ntreeInterfaceTypeUpdate(ntree);
- /* XXX hack, should be done by depsgraph!! */
- if (bmain)
- ntreeVerifyNodes(bmain, &ntree->id);
+ /* XXX hack, should be done by depsgraph!! */
+ if (bmain)
+ ntreeVerifyNodes(bmain, &ntree->id);
- if (ntree->update & (NTREE_UPDATE_LINKS | NTREE_UPDATE_NODES)) {
- /* node updates can change sockets or links, repeat link pointer update afterward */
- ntree_update_link_pointers(ntree);
+ if (ntree->update & (NTREE_UPDATE_LINKS | NTREE_UPDATE_NODES)) {
+ /* node updates can change sockets or links, repeat link pointer update afterward */
+ ntree_update_link_pointers(ntree);
- /* update the node level from link dependencies */
- ntree_update_node_level(ntree);
+ /* update the node level from link dependencies */
+ ntree_update_node_level(ntree);
- /* check link validity */
- ntree_validate_links(ntree);
- }
+ /* check link validity */
+ ntree_validate_links(ntree);
+ }
- /* clear update flags */
- for (node = ntree->nodes.first; node; node = node->next) {
- node->update = 0;
- }
- ntree->update = 0;
+ /* clear update flags */
+ for (node = ntree->nodes.first; node; node = node->next) {
+ node->update = 0;
+ }
+ ntree->update = 0;
- ntree->is_updating = false;
+ ntree->is_updating = false;
}
void nodeUpdate(bNodeTree *ntree, bNode *node)
{
- /* avoid reentrant updates, can be caused by RNA update callbacks */
- if (ntree->is_updating)
- return;
- ntree->is_updating = true;
+ /* avoid reentrant updates, can be caused by RNA update callbacks */
+ if (ntree->is_updating)
+ return;
+ ntree->is_updating = true;
- if (node->typeinfo->updatefunc)
- node->typeinfo->updatefunc(ntree, node);
+ if (node->typeinfo->updatefunc)
+ node->typeinfo->updatefunc(ntree, node);
- nodeUpdateInternalLinks(ntree, node);
+ nodeUpdateInternalLinks(ntree, node);
- /* clear update flag */
- node->update = 0;
+ /* clear update flag */
+ node->update = 0;
- ntree->is_updating = false;
+ ntree->is_updating = false;
}
bool nodeUpdateID(bNodeTree *ntree, ID *id)
{
- bNode *node;
- bool changed = false;
+ bNode *node;
+ bool changed = false;
- if (ELEM(NULL, id, ntree))
- return changed;
+ if (ELEM(NULL, id, ntree))
+ return changed;
- /* avoid reentrant updates, can be caused by RNA update callbacks */
- if (ntree->is_updating)
- return changed;
- ntree->is_updating = true;
+ /* avoid reentrant updates, can be caused by RNA update callbacks */
+ if (ntree->is_updating)
+ return changed;
+ ntree->is_updating = true;
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->id == id) {
- changed = true;
- node->update |= NODE_UPDATE_ID;
- if (node->typeinfo->updatefunc)
- node->typeinfo->updatefunc(ntree, node);
- /* clear update flag */
- node->update = 0;
- }
- }
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (node->id == id) {
+ changed = true;
+ node->update |= NODE_UPDATE_ID;
+ if (node->typeinfo->updatefunc)
+ node->typeinfo->updatefunc(ntree, node);
+ /* clear update flag */
+ node->update = 0;
+ }
+ }
- for (node = ntree->nodes.first; node; node = node->next) {
- nodeUpdateInternalLinks(ntree, node);
- }
+ for (node = ntree->nodes.first; node; node = node->next) {
+ nodeUpdateInternalLinks(ntree, node);
+ }
- ntree->is_updating = false;
- return changed;
+ ntree->is_updating = false;
+ return changed;
}
void nodeUpdateInternalLinks(bNodeTree *ntree, bNode *node)
{
- BLI_freelistN(&node->internal_links);
+ BLI_freelistN(&node->internal_links);
- if (node->typeinfo && node->typeinfo->update_internal_links)
- node->typeinfo->update_internal_links(ntree, node);
+ if (node->typeinfo && node->typeinfo->update_internal_links)
+ node->typeinfo->update_internal_links(ntree, node);
}
-
/* ************* node type access ********** */
void nodeLabel(bNodeTree *ntree, bNode *node, char *label, int maxlen)
{
- label[0] = '\0';
+ label[0] = '\0';
- if (node->label[0] != '\0') {
- BLI_strncpy(label, node->label, maxlen);
- }
- else if (node->typeinfo->labelfunc) {
- node->typeinfo->labelfunc(ntree, node, label, maxlen);
- }
+ if (node->label[0] != '\0') {
+ BLI_strncpy(label, node->label, maxlen);
+ }
+ else if (node->typeinfo->labelfunc) {
+ node->typeinfo->labelfunc(ntree, node, label, maxlen);
+ }
- /* The previous methods (labelfunc) could not provide an adequate label for the node. */
- if (label[0] == '\0') {
- /* Kind of hacky and weak... Ideally would be better to use RNA here. :| */
- const char *tmp = CTX_IFACE_(BLT_I18NCONTEXT_ID_NODETREE, node->typeinfo->ui_name);
- if (tmp == node->typeinfo->ui_name) {
- tmp = IFACE_(node->typeinfo->ui_name);
- }
- BLI_strncpy(label, tmp, maxlen);
- }
+ /* The previous methods (labelfunc) could not provide an adequate label for the node. */
+ if (label[0] == '\0') {
+ /* Kind of hacky and weak... Ideally would be better to use RNA here. :| */
+ const char *tmp = CTX_IFACE_(BLT_I18NCONTEXT_ID_NODETREE, node->typeinfo->ui_name);
+ if (tmp == node->typeinfo->ui_name) {
+ tmp = IFACE_(node->typeinfo->ui_name);
+ }
+ BLI_strncpy(label, tmp, maxlen);
+ }
}
static void node_type_base_defaults(bNodeType *ntype)
{
- /* default size values */
- node_type_size_preset(ntype, NODE_SIZE_DEFAULT);
- ntype->height = 100;
- ntype->minheight = 30;
- ntype->maxheight = FLT_MAX;
+ /* default size values */
+ node_type_size_preset(ntype, NODE_SIZE_DEFAULT);
+ ntype->height = 100;
+ ntype->minheight = 30;
+ ntype->maxheight = FLT_MAX;
}
/* allow this node for any tree type */
static bool node_poll_default(bNodeType *UNUSED(ntype), bNodeTree *UNUSED(ntree))
{
- return true;
+ return true;
}
/* use the basic poll function */
static bool node_poll_instance_default(bNode *node, bNodeTree *ntree)
{
- return node->typeinfo->poll(node->typeinfo, ntree);
+ return node->typeinfo->poll(node->typeinfo, ntree);
}
void node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
{
- /* Use static type info header to map static int type to identifier string and RNA struct type.
- * Associate the RNA struct type with the bNodeType.
- * Dynamically registered nodes will create an RNA type at runtime
- * and call RNA_struct_blender_type_set, so this only needs to be done for old RNA types
- * created in makesrna, which can not be associated to a bNodeType immediately,
- * since bNodeTypes are registered afterward ...
- */
+ /* Use static type info header to map static int type to identifier string and RNA struct type.
+ * Associate the RNA struct type with the bNodeType.
+ * Dynamically registered nodes will create an RNA type at runtime
+ * and call RNA_struct_blender_type_set, so this only needs to be done for old RNA types
+ * created in makesrna, which can not be associated to a bNodeType immediately,
+ * since bNodeTypes are registered afterward ...
+ */
#define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \
- case ID: \
- BLI_strncpy(ntype->idname, #Category #StructName, sizeof(ntype->idname)); \
- ntype->ext.srna = RNA_struct_find(#Category #StructName); \
- BLI_assert(ntype->ext.srna != NULL); \
- RNA_struct_blender_type_set(ntype->ext.srna, ntype); \
- break;
-
- switch (type) {
+ case ID: \
+ BLI_strncpy(ntype->idname, #Category #StructName, sizeof(ntype->idname)); \
+ ntype->ext.srna = RNA_struct_find(#Category #StructName); \
+ BLI_assert(ntype->ext.srna != NULL); \
+ RNA_struct_blender_type_set(ntype->ext.srna, ntype); \
+ break;
+
+ switch (type) {
#include "NOD_static_types.h"
- }
+ }
- /* make sure we have a valid type (everything registered) */
- BLI_assert(ntype->idname[0] != '\0');
+ /* make sure we have a valid type (everything registered) */
+ BLI_assert(ntype->idname[0] != '\0');
- ntype->type = type;
- BLI_strncpy(ntype->ui_name, name, sizeof(ntype->ui_name));
- ntype->nclass = nclass;
- ntype->flag = flag;
+ ntype->type = type;
+ BLI_strncpy(ntype->ui_name, name, sizeof(ntype->ui_name));
+ ntype->nclass = nclass;
+ ntype->flag = flag;
- node_type_base_defaults(ntype);
+ node_type_base_defaults(ntype);
- ntype->poll = node_poll_default;
- ntype->poll_instance = node_poll_instance_default;
+ ntype->poll = node_poll_default;
+ ntype->poll_instance = node_poll_instance_default;
}
-void node_type_base_custom(bNodeType *ntype, const char *idname, const char *name, short nclass, short flag)
+void node_type_base_custom(
+ bNodeType *ntype, const char *idname, const char *name, short nclass, short flag)
{
- BLI_strncpy(ntype->idname, idname, sizeof(ntype->idname));
- ntype->type = NODE_CUSTOM;
- BLI_strncpy(ntype->ui_name, name, sizeof(ntype->ui_name));
- ntype->nclass = nclass;
- ntype->flag = flag;
+ BLI_strncpy(ntype->idname, idname, sizeof(ntype->idname));
+ ntype->type = NODE_CUSTOM;
+ BLI_strncpy(ntype->ui_name, name, sizeof(ntype->ui_name));
+ ntype->nclass = nclass;
+ ntype->flag = flag;
- node_type_base_defaults(ntype);
+ node_type_base_defaults(ntype);
}
static bool unique_socket_template_identifier_check(void *arg, const char *name)
{
- bNodeSocketTemplate *ntemp;
- struct {bNodeSocketTemplate *list; bNodeSocketTemplate *ntemp;} *data = arg;
+ bNodeSocketTemplate *ntemp;
+ struct {
+ bNodeSocketTemplate *list;
+ bNodeSocketTemplate *ntemp;
+ } *data = arg;
- for (ntemp = data->list; ntemp->type >= 0; ++ntemp) {
- if (ntemp != data->ntemp) {
- if (STREQ(ntemp->identifier, name)) {
- return true;
- }
- }
- }
+ for (ntemp = data->list; ntemp->type >= 0; ++ntemp) {
+ if (ntemp != data->ntemp) {
+ if (STREQ(ntemp->identifier, name)) {
+ return true;
+ }
+ }
+ }
- return false;
+ return false;
}
-static void unique_socket_template_identifier(bNodeSocketTemplate *list, bNodeSocketTemplate *ntemp, const char defname[], char delim)
+static void unique_socket_template_identifier(bNodeSocketTemplate *list,
+ bNodeSocketTemplate *ntemp,
+ const char defname[],
+ char delim)
{
- struct {bNodeSocketTemplate *list; bNodeSocketTemplate *ntemp;} data;
- data.list = list;
- data.ntemp = ntemp;
+ struct {
+ bNodeSocketTemplate *list;
+ bNodeSocketTemplate *ntemp;
+ } data;
+ data.list = list;
+ data.ntemp = ntemp;
- BLI_uniquename_cb(unique_socket_template_identifier_check, &data, defname, delim, ntemp->identifier, sizeof(ntemp->identifier));
+ BLI_uniquename_cb(unique_socket_template_identifier_check,
+ &data,
+ defname,
+ delim,
+ ntemp->identifier,
+ sizeof(ntemp->identifier));
}
-void node_type_socket_templates(struct bNodeType *ntype, struct bNodeSocketTemplate *inputs, struct bNodeSocketTemplate *outputs)
+void node_type_socket_templates(struct bNodeType *ntype,
+ struct bNodeSocketTemplate *inputs,
+ struct bNodeSocketTemplate *outputs)
{
- bNodeSocketTemplate *ntemp;
+ bNodeSocketTemplate *ntemp;
- ntype->inputs = inputs;
- ntype->outputs = outputs;
+ ntype->inputs = inputs;
+ ntype->outputs = outputs;
- /* automatically generate unique identifiers */
- if (inputs) {
- /* clear identifier strings (uninitialized memory) */
- for (ntemp = inputs; ntemp->type >= 0; ++ntemp)
- ntemp->identifier[0] = '\0';
+ /* automatically generate unique identifiers */
+ if (inputs) {
+ /* clear identifier strings (uninitialized memory) */
+ for (ntemp = inputs; ntemp->type >= 0; ++ntemp)
+ ntemp->identifier[0] = '\0';
- for (ntemp = inputs; ntemp->type >= 0; ++ntemp) {
- BLI_strncpy(ntemp->identifier, ntemp->name, sizeof(ntemp->identifier));
- unique_socket_template_identifier(inputs, ntemp, ntemp->identifier, '_');
- }
- }
- if (outputs) {
- /* clear identifier strings (uninitialized memory) */
- for (ntemp = outputs; ntemp->type >= 0; ++ntemp)
- ntemp->identifier[0] = '\0';
+ for (ntemp = inputs; ntemp->type >= 0; ++ntemp) {
+ BLI_strncpy(ntemp->identifier, ntemp->name, sizeof(ntemp->identifier));
+ unique_socket_template_identifier(inputs, ntemp, ntemp->identifier, '_');
+ }
+ }
+ if (outputs) {
+ /* clear identifier strings (uninitialized memory) */
+ for (ntemp = outputs; ntemp->type >= 0; ++ntemp)
+ ntemp->identifier[0] = '\0';
- for (ntemp = outputs; ntemp->type >= 0; ++ntemp) {
- BLI_strncpy(ntemp->identifier, ntemp->name, sizeof(ntemp->identifier));
- unique_socket_template_identifier(outputs, ntemp, ntemp->identifier, '_');
- }
- }
+ for (ntemp = outputs; ntemp->type >= 0; ++ntemp) {
+ BLI_strncpy(ntemp->identifier, ntemp->name, sizeof(ntemp->identifier));
+ unique_socket_template_identifier(outputs, ntemp, ntemp->identifier, '_');
+ }
+ }
}
-void node_type_init(struct bNodeType *ntype, void (*initfunc)(struct bNodeTree *ntree, struct bNode *node))
+void node_type_init(struct bNodeType *ntype,
+ void (*initfunc)(struct bNodeTree *ntree, struct bNode *node))
{
- ntype->initfunc = initfunc;
+ ntype->initfunc = initfunc;
}
void node_type_size(struct bNodeType *ntype, int width, int minwidth, int maxwidth)
{
- ntype->width = width;
- ntype->minwidth = minwidth;
- if (maxwidth <= minwidth)
- ntype->maxwidth = FLT_MAX;
- else
- ntype->maxwidth = maxwidth;
+ ntype->width = width;
+ ntype->minwidth = minwidth;
+ if (maxwidth <= minwidth)
+ ntype->maxwidth = FLT_MAX;
+ else
+ ntype->maxwidth = maxwidth;
}
void node_type_size_preset(struct bNodeType *ntype, eNodeSizePreset size)
{
- switch (size) {
- case NODE_SIZE_DEFAULT:
- node_type_size(ntype, 140, 100, NODE_DEFAULT_MAX_WIDTH);
- break;
- case NODE_SIZE_SMALL:
- node_type_size(ntype, 100, 80, NODE_DEFAULT_MAX_WIDTH);
- break;
- case NODE_SIZE_MIDDLE:
- node_type_size(ntype, 150, 120, NODE_DEFAULT_MAX_WIDTH);
- break;
- case NODE_SIZE_LARGE:
- node_type_size(ntype, 240, 140, NODE_DEFAULT_MAX_WIDTH);
- break;
- }
+ switch (size) {
+ case NODE_SIZE_DEFAULT:
+ node_type_size(ntype, 140, 100, NODE_DEFAULT_MAX_WIDTH);
+ break;
+ case NODE_SIZE_SMALL:
+ node_type_size(ntype, 100, 80, NODE_DEFAULT_MAX_WIDTH);
+ break;
+ case NODE_SIZE_MIDDLE:
+ node_type_size(ntype, 150, 120, NODE_DEFAULT_MAX_WIDTH);
+ break;
+ case NODE_SIZE_LARGE:
+ node_type_size(ntype, 240, 140, NODE_DEFAULT_MAX_WIDTH);
+ break;
+ }
}
/**
@@ -3323,440 +3431,452 @@ void node_type_size_preset(struct bNodeType *ntype, eNodeSizePreset size)
* Otherwise nodes will reload as undefined (T46619).
*/
void node_type_storage(bNodeType *ntype,
- const char *storagename,
- void (*freefunc)(struct bNode *node),
- void (*copyfunc)(struct bNodeTree *dest_ntree, struct bNode *dest_node, struct bNode *src_node))
+ const char *storagename,
+ void (*freefunc)(struct bNode *node),
+ void (*copyfunc)(struct bNodeTree *dest_ntree,
+ struct bNode *dest_node,
+ struct bNode *src_node))
{
- if (storagename)
- BLI_strncpy(ntype->storagename, storagename, sizeof(ntype->storagename));
- else
- ntype->storagename[0] = '\0';
- ntype->copyfunc = copyfunc;
- ntype->freefunc = freefunc;
+ if (storagename)
+ BLI_strncpy(ntype->storagename, storagename, sizeof(ntype->storagename));
+ else
+ ntype->storagename[0] = '\0';
+ ntype->copyfunc = copyfunc;
+ ntype->freefunc = freefunc;
}
-void node_type_label(struct bNodeType *ntype, void (*labelfunc)(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen))
+void node_type_label(
+ struct bNodeType *ntype,
+ void (*labelfunc)(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen))
{
- ntype->labelfunc = labelfunc;
+ ntype->labelfunc = labelfunc;
}
void node_type_update(struct bNodeType *ntype,
void (*updatefunc)(struct bNodeTree *ntree, struct bNode *node),
- void (*verifyfunc)(struct bNodeTree *ntree, struct bNode *node, struct ID *id))
+ void (*verifyfunc)(struct bNodeTree *ntree,
+ struct bNode *node,
+ struct ID *id))
{
- ntype->updatefunc = updatefunc;
- ntype->verifyfunc = verifyfunc;
+ ntype->updatefunc = updatefunc;
+ ntype->verifyfunc = verifyfunc;
}
-void node_type_exec(struct bNodeType *ntype, NodeInitExecFunction initexecfunc, NodeFreeExecFunction freeexecfunc, NodeExecFunction execfunc)
+void node_type_exec(struct bNodeType *ntype,
+ NodeInitExecFunction initexecfunc,
+ NodeFreeExecFunction freeexecfunc,
+ NodeExecFunction execfunc)
{
- ntype->initexecfunc = initexecfunc;
- ntype->freeexecfunc = freeexecfunc;
- ntype->execfunc = execfunc;
+ ntype->initexecfunc = initexecfunc;
+ ntype->freeexecfunc = freeexecfunc;
+ ntype->execfunc = execfunc;
}
void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpufunc)
{
- ntype->gpufunc = gpufunc;
+ ntype->gpufunc = gpufunc;
}
-void node_type_internal_links(bNodeType *ntype, void (*update_internal_links)(bNodeTree *, bNode *))
+void node_type_internal_links(bNodeType *ntype,
+ void (*update_internal_links)(bNodeTree *, bNode *))
{
- ntype->update_internal_links = update_internal_links;
+ ntype->update_internal_links = update_internal_links;
}
/* callbacks for undefined types */
static bool node_undefined_poll(bNodeType *UNUSED(ntype), bNodeTree *UNUSED(nodetree))
{
- /* this type can not be added deliberately, it's just a placeholder */
- return false;
+ /* this type can not be added deliberately, it's just a placeholder */
+ return false;
}
/* register fallback types used for undefined tree, nodes, sockets */
static void register_undefined_types(void)
{
- /* Note: these types are not registered in the type hashes,
- * they are just used as placeholders in case the actual types are not registered.
- */
+ /* Note: these types are not registered in the type hashes,
+ * they are just used as placeholders in case the actual types are not registered.
+ */
- strcpy(NodeTreeTypeUndefined.idname, "NodeTreeUndefined");
- strcpy(NodeTreeTypeUndefined.ui_name, N_("Undefined"));
- strcpy(NodeTreeTypeUndefined.ui_description, N_("Undefined Node Tree Type"));
+ strcpy(NodeTreeTypeUndefined.idname, "NodeTreeUndefined");
+ strcpy(NodeTreeTypeUndefined.ui_name, N_("Undefined"));
+ strcpy(NodeTreeTypeUndefined.ui_description, N_("Undefined Node Tree Type"));
- node_type_base_custom(&NodeTypeUndefined, "NodeUndefined", "Undefined", 0, 0);
- NodeTypeUndefined.poll = node_undefined_poll;
+ node_type_base_custom(&NodeTypeUndefined, "NodeUndefined", "Undefined", 0, 0);
+ NodeTypeUndefined.poll = node_undefined_poll;
- BLI_strncpy(NodeSocketTypeUndefined.idname, "NodeSocketUndefined", sizeof(NodeSocketTypeUndefined.idname));
- /* extra type info for standard socket types */
- NodeSocketTypeUndefined.type = SOCK_CUSTOM;
- NodeSocketTypeUndefined.subtype = PROP_NONE;
+ BLI_strncpy(NodeSocketTypeUndefined.idname,
+ "NodeSocketUndefined",
+ sizeof(NodeSocketTypeUndefined.idname));
+ /* extra type info for standard socket types */
+ NodeSocketTypeUndefined.type = SOCK_CUSTOM;
+ NodeSocketTypeUndefined.subtype = PROP_NONE;
}
static void registerCompositNodes(void)
{
- register_node_type_cmp_group();
-
- register_node_type_cmp_rlayers();
- register_node_type_cmp_image();
- register_node_type_cmp_texture();
- register_node_type_cmp_value();
- register_node_type_cmp_rgb();
- register_node_type_cmp_curve_time();
- register_node_type_cmp_movieclip();
-
- register_node_type_cmp_composite();
- register_node_type_cmp_viewer();
- register_node_type_cmp_splitviewer();
- register_node_type_cmp_output_file();
- register_node_type_cmp_view_levels();
-
- register_node_type_cmp_curve_rgb();
- register_node_type_cmp_mix_rgb();
- register_node_type_cmp_hue_sat();
- register_node_type_cmp_brightcontrast();
- register_node_type_cmp_gamma();
- register_node_type_cmp_invert();
- register_node_type_cmp_alphaover();
- register_node_type_cmp_zcombine();
- register_node_type_cmp_colorbalance();
- register_node_type_cmp_huecorrect();
-
- register_node_type_cmp_normal();
- register_node_type_cmp_curve_vec();
- register_node_type_cmp_map_value();
- register_node_type_cmp_map_range();
- register_node_type_cmp_normalize();
-
- register_node_type_cmp_filter();
- register_node_type_cmp_blur();
- register_node_type_cmp_dblur();
- register_node_type_cmp_bilateralblur();
- register_node_type_cmp_vecblur();
- register_node_type_cmp_dilateerode();
- register_node_type_cmp_inpaint();
- register_node_type_cmp_despeckle();
- register_node_type_cmp_defocus();
- register_node_type_cmp_sunbeams();
-
- register_node_type_cmp_valtorgb();
- register_node_type_cmp_rgbtobw();
- register_node_type_cmp_setalpha();
- register_node_type_cmp_idmask();
- register_node_type_cmp_math();
- register_node_type_cmp_seprgba();
- register_node_type_cmp_combrgba();
- register_node_type_cmp_sephsva();
- register_node_type_cmp_combhsva();
- register_node_type_cmp_sepyuva();
- register_node_type_cmp_combyuva();
- register_node_type_cmp_sepycca();
- register_node_type_cmp_combycca();
- register_node_type_cmp_premulkey();
-
- register_node_type_cmp_diff_matte();
- register_node_type_cmp_distance_matte();
- register_node_type_cmp_chroma_matte();
- register_node_type_cmp_color_matte();
- register_node_type_cmp_channel_matte();
- register_node_type_cmp_color_spill();
- register_node_type_cmp_luma_matte();
- register_node_type_cmp_doubleedgemask();
- register_node_type_cmp_keyingscreen();
- register_node_type_cmp_keying();
- register_node_type_cmp_cryptomatte();
-
- register_node_type_cmp_translate();
- register_node_type_cmp_rotate();
- register_node_type_cmp_scale();
- register_node_type_cmp_flip();
- register_node_type_cmp_crop();
- register_node_type_cmp_displace();
- register_node_type_cmp_mapuv();
- register_node_type_cmp_glare();
- register_node_type_cmp_tonemap();
- register_node_type_cmp_lensdist();
- register_node_type_cmp_transform();
- register_node_type_cmp_stabilize2d();
- register_node_type_cmp_moviedistortion();
-
- register_node_type_cmp_colorcorrection();
- register_node_type_cmp_boxmask();
- register_node_type_cmp_ellipsemask();
- register_node_type_cmp_bokehimage();
- register_node_type_cmp_bokehblur();
- register_node_type_cmp_switch();
- register_node_type_cmp_switch_view();
- register_node_type_cmp_pixelate();
-
- register_node_type_cmp_mask();
- register_node_type_cmp_trackpos();
- register_node_type_cmp_planetrackdeform();
- register_node_type_cmp_cornerpin();
+ register_node_type_cmp_group();
+
+ register_node_type_cmp_rlayers();
+ register_node_type_cmp_image();
+ register_node_type_cmp_texture();
+ register_node_type_cmp_value();
+ register_node_type_cmp_rgb();
+ register_node_type_cmp_curve_time();
+ register_node_type_cmp_movieclip();
+
+ register_node_type_cmp_composite();
+ register_node_type_cmp_viewer();
+ register_node_type_cmp_splitviewer();
+ register_node_type_cmp_output_file();
+ register_node_type_cmp_view_levels();
+
+ register_node_type_cmp_curve_rgb();
+ register_node_type_cmp_mix_rgb();
+ register_node_type_cmp_hue_sat();
+ register_node_type_cmp_brightcontrast();
+ register_node_type_cmp_gamma();
+ register_node_type_cmp_invert();
+ register_node_type_cmp_alphaover();
+ register_node_type_cmp_zcombine();
+ register_node_type_cmp_colorbalance();
+ register_node_type_cmp_huecorrect();
+
+ register_node_type_cmp_normal();
+ register_node_type_cmp_curve_vec();
+ register_node_type_cmp_map_value();
+ register_node_type_cmp_map_range();
+ register_node_type_cmp_normalize();
+
+ register_node_type_cmp_filter();
+ register_node_type_cmp_blur();
+ register_node_type_cmp_dblur();
+ register_node_type_cmp_bilateralblur();
+ register_node_type_cmp_vecblur();
+ register_node_type_cmp_dilateerode();
+ register_node_type_cmp_inpaint();
+ register_node_type_cmp_despeckle();
+ register_node_type_cmp_defocus();
+ register_node_type_cmp_sunbeams();
+
+ register_node_type_cmp_valtorgb();
+ register_node_type_cmp_rgbtobw();
+ register_node_type_cmp_setalpha();
+ register_node_type_cmp_idmask();
+ register_node_type_cmp_math();
+ register_node_type_cmp_seprgba();
+ register_node_type_cmp_combrgba();
+ register_node_type_cmp_sephsva();
+ register_node_type_cmp_combhsva();
+ register_node_type_cmp_sepyuva();
+ register_node_type_cmp_combyuva();
+ register_node_type_cmp_sepycca();
+ register_node_type_cmp_combycca();
+ register_node_type_cmp_premulkey();
+
+ register_node_type_cmp_diff_matte();
+ register_node_type_cmp_distance_matte();
+ register_node_type_cmp_chroma_matte();
+ register_node_type_cmp_color_matte();
+ register_node_type_cmp_channel_matte();
+ register_node_type_cmp_color_spill();
+ register_node_type_cmp_luma_matte();
+ register_node_type_cmp_doubleedgemask();
+ register_node_type_cmp_keyingscreen();
+ register_node_type_cmp_keying();
+ register_node_type_cmp_cryptomatte();
+
+ register_node_type_cmp_translate();
+ register_node_type_cmp_rotate();
+ register_node_type_cmp_scale();
+ register_node_type_cmp_flip();
+ register_node_type_cmp_crop();
+ register_node_type_cmp_displace();
+ register_node_type_cmp_mapuv();
+ register_node_type_cmp_glare();
+ register_node_type_cmp_tonemap();
+ register_node_type_cmp_lensdist();
+ register_node_type_cmp_transform();
+ register_node_type_cmp_stabilize2d();
+ register_node_type_cmp_moviedistortion();
+
+ register_node_type_cmp_colorcorrection();
+ register_node_type_cmp_boxmask();
+ register_node_type_cmp_ellipsemask();
+ register_node_type_cmp_bokehimage();
+ register_node_type_cmp_bokehblur();
+ register_node_type_cmp_switch();
+ register_node_type_cmp_switch_view();
+ register_node_type_cmp_pixelate();
+
+ register_node_type_cmp_mask();
+ register_node_type_cmp_trackpos();
+ register_node_type_cmp_planetrackdeform();
+ register_node_type_cmp_cornerpin();
}
static void registerShaderNodes(void)
{
- register_node_type_sh_group();
-
- register_node_type_sh_camera();
- register_node_type_sh_gamma();
- register_node_type_sh_brightcontrast();
- register_node_type_sh_value();
- register_node_type_sh_rgb();
- register_node_type_sh_wireframe();
- register_node_type_sh_wavelength();
- register_node_type_sh_blackbody();
- register_node_type_sh_mix_rgb();
- register_node_type_sh_valtorgb();
- register_node_type_sh_rgbtobw();
- register_node_type_sh_shadertorgb();
- register_node_type_sh_normal();
- register_node_type_sh_mapping();
- register_node_type_sh_curve_vec();
- register_node_type_sh_curve_rgb();
- register_node_type_sh_math();
- register_node_type_sh_vect_math();
- register_node_type_sh_vect_transform();
- register_node_type_sh_squeeze();
- register_node_type_sh_invert();
- register_node_type_sh_seprgb();
- register_node_type_sh_combrgb();
- register_node_type_sh_sephsv();
- register_node_type_sh_combhsv();
- register_node_type_sh_sepxyz();
- register_node_type_sh_combxyz();
- register_node_type_sh_hue_sat();
-
- register_node_type_sh_attribute();
- register_node_type_sh_bevel();
- register_node_type_sh_displacement();
- register_node_type_sh_vector_displacement();
- register_node_type_sh_geometry();
- register_node_type_sh_light_path();
- register_node_type_sh_light_falloff();
- register_node_type_sh_object_info();
- register_node_type_sh_fresnel();
- register_node_type_sh_layer_weight();
- register_node_type_sh_tex_coord();
- register_node_type_sh_particle_info();
- register_node_type_sh_bump();
-
- register_node_type_sh_background();
- register_node_type_sh_bsdf_anisotropic();
- register_node_type_sh_bsdf_diffuse();
- register_node_type_sh_bsdf_principled();
- register_node_type_sh_bsdf_glossy();
- register_node_type_sh_bsdf_glass();
- register_node_type_sh_bsdf_translucent();
- register_node_type_sh_bsdf_transparent();
- register_node_type_sh_bsdf_velvet();
- register_node_type_sh_bsdf_toon();
- register_node_type_sh_bsdf_hair();
- register_node_type_sh_bsdf_hair_principled();
- register_node_type_sh_emission();
- register_node_type_sh_holdout();
- register_node_type_sh_volume_absorption();
- register_node_type_sh_volume_scatter();
- register_node_type_sh_volume_principled();
- register_node_type_sh_subsurface_scattering();
- register_node_type_sh_mix_shader();
- register_node_type_sh_add_shader();
- register_node_type_sh_uvmap();
- register_node_type_sh_uvalongstroke();
- register_node_type_sh_eevee_specular();
-
- register_node_type_sh_output_light();
- register_node_type_sh_output_material();
- register_node_type_sh_output_world();
- register_node_type_sh_output_linestyle();
-
- register_node_type_sh_tex_image();
- register_node_type_sh_tex_environment();
- register_node_type_sh_tex_sky();
- register_node_type_sh_tex_noise();
- register_node_type_sh_tex_wave();
- register_node_type_sh_tex_voronoi();
- register_node_type_sh_tex_musgrave();
- register_node_type_sh_tex_gradient();
- register_node_type_sh_tex_magic();
- register_node_type_sh_tex_checker();
- register_node_type_sh_tex_brick();
- register_node_type_sh_tex_pointdensity();
- register_node_type_sh_tex_ies();
+ register_node_type_sh_group();
+
+ register_node_type_sh_camera();
+ register_node_type_sh_gamma();
+ register_node_type_sh_brightcontrast();
+ register_node_type_sh_value();
+ register_node_type_sh_rgb();
+ register_node_type_sh_wireframe();
+ register_node_type_sh_wavelength();
+ register_node_type_sh_blackbody();
+ register_node_type_sh_mix_rgb();
+ register_node_type_sh_valtorgb();
+ register_node_type_sh_rgbtobw();
+ register_node_type_sh_shadertorgb();
+ register_node_type_sh_normal();
+ register_node_type_sh_mapping();
+ register_node_type_sh_curve_vec();
+ register_node_type_sh_curve_rgb();
+ register_node_type_sh_math();
+ register_node_type_sh_vect_math();
+ register_node_type_sh_vect_transform();
+ register_node_type_sh_squeeze();
+ register_node_type_sh_invert();
+ register_node_type_sh_seprgb();
+ register_node_type_sh_combrgb();
+ register_node_type_sh_sephsv();
+ register_node_type_sh_combhsv();
+ register_node_type_sh_sepxyz();
+ register_node_type_sh_combxyz();
+ register_node_type_sh_hue_sat();
+
+ register_node_type_sh_attribute();
+ register_node_type_sh_bevel();
+ register_node_type_sh_displacement();
+ register_node_type_sh_vector_displacement();
+ register_node_type_sh_geometry();
+ register_node_type_sh_light_path();
+ register_node_type_sh_light_falloff();
+ register_node_type_sh_object_info();
+ register_node_type_sh_fresnel();
+ register_node_type_sh_layer_weight();
+ register_node_type_sh_tex_coord();
+ register_node_type_sh_particle_info();
+ register_node_type_sh_bump();
+
+ register_node_type_sh_background();
+ register_node_type_sh_bsdf_anisotropic();
+ register_node_type_sh_bsdf_diffuse();
+ register_node_type_sh_bsdf_principled();
+ register_node_type_sh_bsdf_glossy();
+ register_node_type_sh_bsdf_glass();
+ register_node_type_sh_bsdf_translucent();
+ register_node_type_sh_bsdf_transparent();
+ register_node_type_sh_bsdf_velvet();
+ register_node_type_sh_bsdf_toon();
+ register_node_type_sh_bsdf_hair();
+ register_node_type_sh_bsdf_hair_principled();
+ register_node_type_sh_emission();
+ register_node_type_sh_holdout();
+ register_node_type_sh_volume_absorption();
+ register_node_type_sh_volume_scatter();
+ register_node_type_sh_volume_principled();
+ register_node_type_sh_subsurface_scattering();
+ register_node_type_sh_mix_shader();
+ register_node_type_sh_add_shader();
+ register_node_type_sh_uvmap();
+ register_node_type_sh_uvalongstroke();
+ register_node_type_sh_eevee_specular();
+
+ register_node_type_sh_output_light();
+ register_node_type_sh_output_material();
+ register_node_type_sh_output_world();
+ register_node_type_sh_output_linestyle();
+
+ register_node_type_sh_tex_image();
+ register_node_type_sh_tex_environment();
+ register_node_type_sh_tex_sky();
+ register_node_type_sh_tex_noise();
+ register_node_type_sh_tex_wave();
+ register_node_type_sh_tex_voronoi();
+ register_node_type_sh_tex_musgrave();
+ register_node_type_sh_tex_gradient();
+ register_node_type_sh_tex_magic();
+ register_node_type_sh_tex_checker();
+ register_node_type_sh_tex_brick();
+ register_node_type_sh_tex_pointdensity();
+ register_node_type_sh_tex_ies();
}
static void registerTextureNodes(void)
{
- register_node_type_tex_group();
-
-
- register_node_type_tex_math();
- register_node_type_tex_mix_rgb();
- register_node_type_tex_valtorgb();
- register_node_type_tex_rgbtobw();
- register_node_type_tex_valtonor();
- register_node_type_tex_curve_rgb();
- register_node_type_tex_curve_time();
- register_node_type_tex_invert();
- register_node_type_tex_hue_sat();
- register_node_type_tex_coord();
- register_node_type_tex_distance();
- register_node_type_tex_compose();
- register_node_type_tex_decompose();
-
- register_node_type_tex_output();
- register_node_type_tex_viewer();
- register_node_type_sh_script();
- register_node_type_sh_tangent();
- register_node_type_sh_normal_map();
- register_node_type_sh_hair_info();
-
- register_node_type_tex_checker();
- register_node_type_tex_texture();
- register_node_type_tex_bricks();
- register_node_type_tex_image();
- register_node_type_sh_bsdf_refraction();
- register_node_type_sh_ambient_occlusion();
-
- register_node_type_tex_rotate();
- register_node_type_tex_translate();
- register_node_type_tex_scale();
- register_node_type_tex_at();
-
- register_node_type_tex_proc_voronoi();
- register_node_type_tex_proc_blend();
- register_node_type_tex_proc_magic();
- register_node_type_tex_proc_marble();
- register_node_type_tex_proc_clouds();
- register_node_type_tex_proc_wood();
- register_node_type_tex_proc_musgrave();
- register_node_type_tex_proc_noise();
- register_node_type_tex_proc_stucci();
- register_node_type_tex_proc_distnoise();
+ register_node_type_tex_group();
+
+ register_node_type_tex_math();
+ register_node_type_tex_mix_rgb();
+ register_node_type_tex_valtorgb();
+ register_node_type_tex_rgbtobw();
+ register_node_type_tex_valtonor();
+ register_node_type_tex_curve_rgb();
+ register_node_type_tex_curve_time();
+ register_node_type_tex_invert();
+ register_node_type_tex_hue_sat();
+ register_node_type_tex_coord();
+ register_node_type_tex_distance();
+ register_node_type_tex_compose();
+ register_node_type_tex_decompose();
+
+ register_node_type_tex_output();
+ register_node_type_tex_viewer();
+ register_node_type_sh_script();
+ register_node_type_sh_tangent();
+ register_node_type_sh_normal_map();
+ register_node_type_sh_hair_info();
+
+ register_node_type_tex_checker();
+ register_node_type_tex_texture();
+ register_node_type_tex_bricks();
+ register_node_type_tex_image();
+ register_node_type_sh_bsdf_refraction();
+ register_node_type_sh_ambient_occlusion();
+
+ register_node_type_tex_rotate();
+ register_node_type_tex_translate();
+ register_node_type_tex_scale();
+ register_node_type_tex_at();
+
+ register_node_type_tex_proc_voronoi();
+ register_node_type_tex_proc_blend();
+ register_node_type_tex_proc_magic();
+ register_node_type_tex_proc_marble();
+ register_node_type_tex_proc_clouds();
+ register_node_type_tex_proc_wood();
+ register_node_type_tex_proc_musgrave();
+ register_node_type_tex_proc_noise();
+ register_node_type_tex_proc_stucci();
+ register_node_type_tex_proc_distnoise();
}
void init_nodesystem(void)
{
- nodetreetypes_hash = BLI_ghash_str_new("nodetreetypes_hash gh");
- nodetypes_hash = BLI_ghash_str_new("nodetypes_hash gh");
- nodesockettypes_hash = BLI_ghash_str_new("nodesockettypes_hash gh");
- BLI_spin_init(&spin);
+ nodetreetypes_hash = BLI_ghash_str_new("nodetreetypes_hash gh");
+ nodetypes_hash = BLI_ghash_str_new("nodetypes_hash gh");
+ nodesockettypes_hash = BLI_ghash_str_new("nodesockettypes_hash gh");
+ BLI_spin_init(&spin);
- register_undefined_types();
+ register_undefined_types();
- register_standard_node_socket_types();
+ register_standard_node_socket_types();
- register_node_tree_type_cmp();
- register_node_tree_type_sh();
- register_node_tree_type_tex();
+ register_node_tree_type_cmp();
+ register_node_tree_type_sh();
+ register_node_tree_type_tex();
- register_node_type_frame();
- register_node_type_reroute();
- register_node_type_group_input();
- register_node_type_group_output();
+ register_node_type_frame();
+ register_node_type_reroute();
+ register_node_type_group_input();
+ register_node_type_group_output();
- registerCompositNodes();
- registerShaderNodes();
- registerTextureNodes();
+ registerCompositNodes();
+ registerShaderNodes();
+ registerTextureNodes();
}
void free_nodesystem(void)
{
- if (nodetypes_hash) {
- NODE_TYPES_BEGIN(nt) {
- if (nt->ext.free) {
- nt->ext.free(nt->ext.data);
- }
- } NODE_TYPES_END;
-
- BLI_ghash_free(nodetypes_hash, NULL, node_free_type);
- nodetypes_hash = NULL;
- }
-
- if (nodesockettypes_hash) {
- NODE_SOCKET_TYPES_BEGIN(st) {
- if (st->ext_socket.free)
- st->ext_socket.free(st->ext_socket.data);
- if (st->ext_interface.free)
- st->ext_interface.free(st->ext_interface.data);
- } NODE_SOCKET_TYPES_END;
-
- BLI_ghash_free(nodesockettypes_hash, NULL, node_free_socket_type);
- nodesockettypes_hash = NULL;
- }
-
- if (nodetreetypes_hash) {
- NODE_TREE_TYPES_BEGIN (nt)
- {
- if (nt->ext.free) {
- nt->ext.free(nt->ext.data);
- }
- }
- NODE_TREE_TYPES_END;
-
- BLI_ghash_free(nodetreetypes_hash, NULL, ntree_free_type);
- nodetreetypes_hash = NULL;
- }
+ if (nodetypes_hash) {
+ NODE_TYPES_BEGIN (nt) {
+ if (nt->ext.free) {
+ nt->ext.free(nt->ext.data);
+ }
+ }
+ NODE_TYPES_END;
+
+ BLI_ghash_free(nodetypes_hash, NULL, node_free_type);
+ nodetypes_hash = NULL;
+ }
+
+ if (nodesockettypes_hash) {
+ NODE_SOCKET_TYPES_BEGIN (st) {
+ if (st->ext_socket.free)
+ st->ext_socket.free(st->ext_socket.data);
+ if (st->ext_interface.free)
+ st->ext_interface.free(st->ext_interface.data);
+ }
+ NODE_SOCKET_TYPES_END;
+
+ BLI_ghash_free(nodesockettypes_hash, NULL, node_free_socket_type);
+ nodesockettypes_hash = NULL;
+ }
+
+ if (nodetreetypes_hash) {
+ NODE_TREE_TYPES_BEGIN (nt) {
+ if (nt->ext.free) {
+ nt->ext.free(nt->ext.data);
+ }
+ }
+ NODE_TREE_TYPES_END;
+
+ BLI_ghash_free(nodetreetypes_hash, NULL, ntree_free_type);
+ nodetreetypes_hash = NULL;
+ }
}
-
/* -------------------------------------------------------------------- */
/* NodeTree Iterator Helpers (FOREACH_NODETREE_BEGIN) */
void BKE_node_tree_iter_init(struct NodeTreeIterStore *ntreeiter, struct Main *bmain)
{
- ntreeiter->ngroup = bmain->nodetrees.first;
- ntreeiter->scene = bmain->scenes.first;
- ntreeiter->mat = bmain->materials.first;
- ntreeiter->tex = bmain->textures.first;
- ntreeiter->light = bmain->lights.first;
- ntreeiter->world = bmain->worlds.first;
- ntreeiter->linestyle = bmain->linestyles.first;
+ ntreeiter->ngroup = bmain->nodetrees.first;
+ ntreeiter->scene = bmain->scenes.first;
+ ntreeiter->mat = bmain->materials.first;
+ ntreeiter->tex = bmain->textures.first;
+ ntreeiter->light = bmain->lights.first;
+ ntreeiter->world = bmain->worlds.first;
+ ntreeiter->linestyle = bmain->linestyles.first;
}
bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter,
- bNodeTree **r_nodetree, struct ID **r_id)
-{
- if (ntreeiter->ngroup) {
- *r_nodetree = ntreeiter->ngroup;
- *r_id = (ID *)ntreeiter->ngroup;
- ntreeiter->ngroup = ntreeiter->ngroup->id.next;
- }
- else if (ntreeiter->scene) {
- *r_nodetree = ntreeiter->scene->nodetree;
- *r_id = (ID *)ntreeiter->scene;
- ntreeiter->scene = ntreeiter->scene->id.next;
- }
- else if (ntreeiter->mat) {
- *r_nodetree = ntreeiter->mat->nodetree;
- *r_id = (ID *)ntreeiter->mat;
- ntreeiter->mat = ntreeiter->mat->id.next;
- }
- else if (ntreeiter->tex) {
- *r_nodetree = ntreeiter->tex->nodetree;
- *r_id = (ID *)ntreeiter->tex;
- ntreeiter->tex = ntreeiter->tex->id.next;
- }
- else if (ntreeiter->light) {
- *r_nodetree = ntreeiter->light->nodetree;
- *r_id = (ID *)ntreeiter->light;
- ntreeiter->light = ntreeiter->light->id.next;
- }
- else if (ntreeiter->world) {
- *r_nodetree = ntreeiter->world->nodetree;
- *r_id = (ID *)ntreeiter->world;
- ntreeiter->world = ntreeiter->world->id.next;
- }
- else if (ntreeiter->linestyle) {
- *r_nodetree = ntreeiter->linestyle->nodetree;
- *r_id = (ID *)ntreeiter->linestyle;
- ntreeiter->linestyle = ntreeiter->linestyle->id.next;
- }
- else {
- return false;
- }
-
- return true;
+ bNodeTree **r_nodetree,
+ struct ID **r_id)
+{
+ if (ntreeiter->ngroup) {
+ *r_nodetree = ntreeiter->ngroup;
+ *r_id = (ID *)ntreeiter->ngroup;
+ ntreeiter->ngroup = ntreeiter->ngroup->id.next;
+ }
+ else if (ntreeiter->scene) {
+ *r_nodetree = ntreeiter->scene->nodetree;
+ *r_id = (ID *)ntreeiter->scene;
+ ntreeiter->scene = ntreeiter->scene->id.next;
+ }
+ else if (ntreeiter->mat) {
+ *r_nodetree = ntreeiter->mat->nodetree;
+ *r_id = (ID *)ntreeiter->mat;
+ ntreeiter->mat = ntreeiter->mat->id.next;
+ }
+ else if (ntreeiter->tex) {
+ *r_nodetree = ntreeiter->tex->nodetree;
+ *r_id = (ID *)ntreeiter->tex;
+ ntreeiter->tex = ntreeiter->tex->id.next;
+ }
+ else if (ntreeiter->light) {
+ *r_nodetree = ntreeiter->light->nodetree;
+ *r_id = (ID *)ntreeiter->light;
+ ntreeiter->light = ntreeiter->light->id.next;
+ }
+ else if (ntreeiter->world) {
+ *r_nodetree = ntreeiter->world->nodetree;
+ *r_id = (ID *)ntreeiter->world;
+ ntreeiter->world = ntreeiter->world->id.next;
+ }
+ else if (ntreeiter->linestyle) {
+ *r_nodetree = ntreeiter->linestyle->nodetree;
+ *r_id = (ID *)ntreeiter->linestyle;
+ ntreeiter->linestyle = ntreeiter->linestyle->id.next;
+ }
+ else {
+ return false;
+ }
+
+ return true;
}
/* -------------------------------------------------------------------- */
@@ -3764,22 +3884,22 @@ bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter,
void BKE_nodetree_remove_layer_n(bNodeTree *ntree, Scene *scene, const int layer_index)
{
- BLI_assert(layer_index != -1);
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
- if (node->type == CMP_NODE_R_LAYERS && (Scene *)node->id == scene) {
- if (node->custom1 == layer_index) {
- node->custom1 = 0;
- }
- else if (node->custom1 > layer_index) {
- node->custom1--;
- }
- }
- }
+ BLI_assert(layer_index != -1);
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == CMP_NODE_R_LAYERS && (Scene *)node->id == scene) {
+ if (node->custom1 == layer_index) {
+ node->custom1 = 0;
+ }
+ else if (node->custom1 > layer_index) {
+ node->custom1--;
+ }
+ }
+ }
}
void BKE_nodetree_shading_params_eval(struct Depsgraph *depsgraph,
bNodeTree *ntree_dst,
const bNodeTree *ntree_src)
{
- DEG_debug_print_eval(depsgraph, __func__, ntree_src->id.name, ntree_dst);
+ DEG_debug_print_eval(depsgraph, __func__, ntree_src->id.name, ntree_dst);
}
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 6e9c8ecb480..303d63d6a8b 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -21,7 +21,6 @@
* \ingroup bke
*/
-
#include <string.h>
#include <math.h>
#include <stdio.h>
@@ -123,11 +122,11 @@
#include "DRW_engine.h"
#ifdef WITH_MOD_FLUID
-#include "LBM_fluidsim.h"
+# include "LBM_fluidsim.h"
#endif
#ifdef WITH_PYTHON
-#include "BPY_extern.h"
+# include "BPY_extern.h"
#endif
#include "CCGSubSurf.h"
@@ -149,561 +148,543 @@ static ThreadMutex vparent_lock = BLI_MUTEX_INITIALIZER;
void BKE_object_workob_clear(Object *workob)
{
- memset(workob, 0, sizeof(Object));
+ memset(workob, 0, sizeof(Object));
- workob->scale[0] = workob->scale[1] = workob->scale[2] = 1.0f;
- workob->dscale[0] = workob->dscale[1] = workob->dscale[2] = 1.0f;
- workob->rotmode = ROT_MODE_EUL;
+ workob->scale[0] = workob->scale[1] = workob->scale[2] = 1.0f;
+ workob->dscale[0] = workob->dscale[1] = workob->dscale[2] = 1.0f;
+ workob->rotmode = ROT_MODE_EUL;
}
void BKE_object_free_particlesystems(Object *ob)
{
- ParticleSystem *psys;
+ ParticleSystem *psys;
- while ((psys = BLI_pophead(&ob->particlesystem))) {
- psys_free(ob, psys);
- }
+ while ((psys = BLI_pophead(&ob->particlesystem))) {
+ psys_free(ob, psys);
+ }
}
void BKE_object_free_softbody(Object *ob)
{
- sbFree(ob);
+ sbFree(ob);
}
void BKE_object_free_curve_cache(Object *ob)
{
- if (ob->runtime.curve_cache) {
- BKE_displist_free(&ob->runtime.curve_cache->disp);
- BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev);
- if (ob->runtime.curve_cache->path) {
- free_path(ob->runtime.curve_cache->path);
- }
- BKE_nurbList_free(&ob->runtime.curve_cache->deformed_nurbs);
- MEM_freeN(ob->runtime.curve_cache);
- ob->runtime.curve_cache = NULL;
- }
+ if (ob->runtime.curve_cache) {
+ BKE_displist_free(&ob->runtime.curve_cache->disp);
+ BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev);
+ if (ob->runtime.curve_cache->path) {
+ free_path(ob->runtime.curve_cache->path);
+ }
+ BKE_nurbList_free(&ob->runtime.curve_cache->deformed_nurbs);
+ MEM_freeN(ob->runtime.curve_cache);
+ ob->runtime.curve_cache = NULL;
+ }
}
void BKE_object_free_modifiers(Object *ob, const int flag)
{
- ModifierData *md;
- GpencilModifierData *gp_md;
+ ModifierData *md;
+ GpencilModifierData *gp_md;
- while ((md = BLI_pophead(&ob->modifiers))) {
- modifier_free_ex(md, flag);
- }
+ while ((md = BLI_pophead(&ob->modifiers))) {
+ modifier_free_ex(md, flag);
+ }
- while ((gp_md = BLI_pophead(&ob->greasepencil_modifiers))) {
- BKE_gpencil_modifier_free_ex(gp_md, flag);
- }
- /* particle modifiers were freed, so free the particlesystems as well */
- BKE_object_free_particlesystems(ob);
+ while ((gp_md = BLI_pophead(&ob->greasepencil_modifiers))) {
+ BKE_gpencil_modifier_free_ex(gp_md, flag);
+ }
+ /* particle modifiers were freed, so free the particlesystems as well */
+ BKE_object_free_particlesystems(ob);
- /* same for softbody */
- BKE_object_free_softbody(ob);
+ /* same for softbody */
+ BKE_object_free_softbody(ob);
- /* modifiers may have stored data in the DM cache */
- BKE_object_free_derived_caches(ob);
+ /* modifiers may have stored data in the DM cache */
+ BKE_object_free_derived_caches(ob);
}
void BKE_object_free_shaderfx(Object *ob, const int flag)
{
- ShaderFxData *fx;
+ ShaderFxData *fx;
- while ((fx = BLI_pophead(&ob->shader_fx))) {
- BKE_shaderfx_free_ex(fx, flag);
- }
+ while ((fx = BLI_pophead(&ob->shader_fx))) {
+ BKE_shaderfx_free_ex(fx, flag);
+ }
}
void BKE_object_modifier_hook_reset(Object *ob, HookModifierData *hmd)
{
- /* reset functionality */
- if (hmd->object) {
- bPoseChannel *pchan = BKE_pose_channel_find_name(hmd->object->pose, hmd->subtarget);
+ /* reset functionality */
+ if (hmd->object) {
+ bPoseChannel *pchan = BKE_pose_channel_find_name(hmd->object->pose, hmd->subtarget);
- if (hmd->subtarget[0] && pchan) {
- float imat[4][4], mat[4][4];
+ if (hmd->subtarget[0] && pchan) {
+ float imat[4][4], mat[4][4];
- /* calculate the world-space matrix for the pose-channel target first, then carry on as usual */
- mul_m4_m4m4(mat, hmd->object->obmat, pchan->pose_mat);
+ /* calculate the world-space matrix for the pose-channel target first, then carry on as usual */
+ mul_m4_m4m4(mat, hmd->object->obmat, pchan->pose_mat);
- invert_m4_m4(imat, mat);
- mul_m4_m4m4(hmd->parentinv, imat, ob->obmat);
- }
- else {
- invert_m4_m4(hmd->object->imat, hmd->object->obmat);
- mul_m4_m4m4(hmd->parentinv, hmd->object->imat, ob->obmat);
- }
- }
+ invert_m4_m4(imat, mat);
+ mul_m4_m4m4(hmd->parentinv, imat, ob->obmat);
+ }
+ else {
+ invert_m4_m4(hmd->object->imat, hmd->object->obmat);
+ mul_m4_m4m4(hmd->parentinv, hmd->object->imat, ob->obmat);
+ }
+ }
}
void BKE_object_modifier_gpencil_hook_reset(Object *ob, HookGpencilModifierData *hmd)
{
- if (hmd->object == NULL) {
- return;
- }
- /* reset functionality */
- bPoseChannel *pchan = BKE_pose_channel_find_name(hmd->object->pose, hmd->subtarget);
+ if (hmd->object == NULL) {
+ return;
+ }
+ /* reset functionality */
+ bPoseChannel *pchan = BKE_pose_channel_find_name(hmd->object->pose, hmd->subtarget);
- if (hmd->subtarget[0] && pchan) {
- float imat[4][4], mat[4][4];
+ if (hmd->subtarget[0] && pchan) {
+ float imat[4][4], mat[4][4];
- /* calculate the world-space matrix for the pose-channel target first, then carry on as usual */
- mul_m4_m4m4(mat, hmd->object->obmat, pchan->pose_mat);
+ /* calculate the world-space matrix for the pose-channel target first, then carry on as usual */
+ mul_m4_m4m4(mat, hmd->object->obmat, pchan->pose_mat);
- invert_m4_m4(imat, mat);
- mul_m4_m4m4(hmd->parentinv, imat, ob->obmat);
- }
- else {
- invert_m4_m4(hmd->object->imat, hmd->object->obmat);
- mul_m4_m4m4(hmd->parentinv, hmd->object->imat, ob->obmat);
- }
+ invert_m4_m4(imat, mat);
+ mul_m4_m4m4(hmd->parentinv, imat, ob->obmat);
+ }
+ else {
+ invert_m4_m4(hmd->object->imat, hmd->object->obmat);
+ mul_m4_m4m4(hmd->parentinv, hmd->object->imat, ob->obmat);
+ }
}
bool BKE_object_support_modifier_type_check(const Object *ob, int modifier_type)
{
- const ModifierTypeInfo *mti;
+ const ModifierTypeInfo *mti;
- mti = modifierType_getInfo(modifier_type);
+ mti = modifierType_getInfo(modifier_type);
- /* only geometry objects should be able to get modifiers [#25291] */
- if (!ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
- return false;
- }
+ /* only geometry objects should be able to get modifiers [#25291] */
+ if (!ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
+ return false;
+ }
- if (ob->type == OB_LATTICE && (mti->flags & eModifierTypeFlag_AcceptsLattice) == 0) {
- return false;
- }
+ if (ob->type == OB_LATTICE && (mti->flags & eModifierTypeFlag_AcceptsLattice) == 0) {
+ return false;
+ }
- if (!((mti->flags & eModifierTypeFlag_AcceptsCVs) ||
- (ob->type == OB_MESH && (mti->flags & eModifierTypeFlag_AcceptsMesh))))
- {
- return false;
- }
+ if (!((mti->flags & eModifierTypeFlag_AcceptsCVs) ||
+ (ob->type == OB_MESH && (mti->flags & eModifierTypeFlag_AcceptsMesh)))) {
+ return false;
+ }
- return true;
+ return true;
}
void BKE_object_link_modifiers(Scene *scene, struct Object *ob_dst, const struct Object *ob_src)
{
- ModifierData *md;
- BKE_object_free_modifiers(ob_dst, 0);
+ ModifierData *md;
+ BKE_object_free_modifiers(ob_dst, 0);
- if (!ELEM(ob_dst->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
- /* only objects listed above can have modifiers and linking them to objects
- * which doesn't have modifiers stack is quite silly */
- return;
- }
+ if (!ELEM(ob_dst->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
+ /* only objects listed above can have modifiers and linking them to objects
+ * which doesn't have modifiers stack is quite silly */
+ return;
+ }
- for (md = ob_src->modifiers.first; md; md = md->next) {
- ModifierData *nmd = NULL;
+ for (md = ob_src->modifiers.first; md; md = md->next) {
+ ModifierData *nmd = NULL;
- if (ELEM(md->type,
- eModifierType_Hook,
- eModifierType_Collision))
- {
- continue;
- }
+ if (ELEM(md->type, eModifierType_Hook, eModifierType_Collision)) {
+ continue;
+ }
- if (!BKE_object_support_modifier_type_check(ob_dst, md->type))
- continue;
+ if (!BKE_object_support_modifier_type_check(ob_dst, md->type))
+ continue;
- switch (md->type) {
- case eModifierType_Softbody:
- BKE_object_copy_softbody(ob_dst, ob_src, 0);
- break;
- case eModifierType_Skin:
- /* ensure skin-node customdata exists */
- BKE_mesh_ensure_skin_customdata(ob_dst->data);
- break;
- }
+ switch (md->type) {
+ case eModifierType_Softbody:
+ BKE_object_copy_softbody(ob_dst, ob_src, 0);
+ break;
+ case eModifierType_Skin:
+ /* ensure skin-node customdata exists */
+ BKE_mesh_ensure_skin_customdata(ob_dst->data);
+ break;
+ }
- nmd = modifier_new(md->type);
- BLI_strncpy(nmd->name, md->name, sizeof(nmd->name));
+ nmd = modifier_new(md->type);
+ BLI_strncpy(nmd->name, md->name, sizeof(nmd->name));
- if (md->type == eModifierType_Multires) {
- /* Has to be done after mod creation, but *before* we actually copy its settings! */
- multiresModifier_sync_levels_ex(scene, ob_dst, (MultiresModifierData *)md, (MultiresModifierData *)nmd);
- }
+ if (md->type == eModifierType_Multires) {
+ /* Has to be done after mod creation, but *before* we actually copy its settings! */
+ multiresModifier_sync_levels_ex(
+ scene, ob_dst, (MultiresModifierData *)md, (MultiresModifierData *)nmd);
+ }
- modifier_copyData(md, nmd);
- BLI_addtail(&ob_dst->modifiers, nmd);
- modifier_unique_name(&ob_dst->modifiers, nmd);
- }
+ modifier_copyData(md, nmd);
+ BLI_addtail(&ob_dst->modifiers, nmd);
+ modifier_unique_name(&ob_dst->modifiers, nmd);
+ }
- BKE_object_copy_particlesystems(ob_dst, ob_src, 0);
+ BKE_object_copy_particlesystems(ob_dst, ob_src, 0);
- /* TODO: smoke?, cloth? */
+ /* TODO: smoke?, cloth? */
}
/* Copy CCG related data. Used to sync copy of mesh with reshaped original
* mesh.
*/
-static void copy_ccg_data(Mesh *mesh_destination,
- Mesh *mesh_source,
- int layer_type)
-{
- BLI_assert(mesh_destination->totloop == mesh_source->totloop);
- CustomData *data_destination = &mesh_destination->ldata;
- CustomData *data_source = &mesh_source->ldata;
- const int num_elements = mesh_source->totloop;
- if (!CustomData_has_layer(data_source, layer_type)) {
- return;
- }
- const int layer_index = CustomData_get_layer_index(
- data_destination, layer_type);
- CustomData_free_layer(
- data_destination, layer_type, num_elements, layer_index);
- BLI_assert(!CustomData_has_layer(data_destination, layer_type));
- CustomData_add_layer(
- data_destination, layer_type, CD_CALLOC, NULL, num_elements);
- BLI_assert(CustomData_has_layer(data_destination, layer_type));
- CustomData_copy_layer_type_data(data_source, data_destination,
- layer_type, 0, 0, num_elements);
+static void copy_ccg_data(Mesh *mesh_destination, Mesh *mesh_source, int layer_type)
+{
+ BLI_assert(mesh_destination->totloop == mesh_source->totloop);
+ CustomData *data_destination = &mesh_destination->ldata;
+ CustomData *data_source = &mesh_source->ldata;
+ const int num_elements = mesh_source->totloop;
+ if (!CustomData_has_layer(data_source, layer_type)) {
+ return;
+ }
+ const int layer_index = CustomData_get_layer_index(data_destination, layer_type);
+ CustomData_free_layer(data_destination, layer_type, num_elements, layer_index);
+ BLI_assert(!CustomData_has_layer(data_destination, layer_type));
+ CustomData_add_layer(data_destination, layer_type, CD_CALLOC, NULL, num_elements);
+ BLI_assert(CustomData_has_layer(data_destination, layer_type));
+ CustomData_copy_layer_type_data(data_source, data_destination, layer_type, 0, 0, num_elements);
}
static void object_update_from_subsurf_ccg(Object *object)
{
- /* Currently CCG is only created for Mesh objects. */
- if (object->type != OB_MESH) {
- return;
- }
- /* Object was never evaluated, so can not have CCG subdivision surface. */
- Mesh *mesh_eval = object->runtime.mesh_eval;
- if (mesh_eval == NULL) {
- return;
- }
- SubdivCCG *subdiv_ccg = mesh_eval->runtime.subdiv_ccg;
- if (subdiv_ccg == NULL) {
- return;
- }
- /* Check whether there is anything to be reshaped. */
- if (!subdiv_ccg->dirty.coords && !subdiv_ccg->dirty.hidden) {
- return;
- }
- const int tot_level = mesh_eval->runtime.subdiv_ccg_tot_level;
- Object *object_orig = DEG_get_original_object(object);
- Mesh *mesh_orig = (Mesh *)object_orig->data;
- multiresModifier_reshapeFromCCG(tot_level, mesh_orig, subdiv_ccg);
- /* NOTE: we need to reshape into an original mesh from main database,
- * allowing:
- *
- * - Update copies of that mesh at any moment.
- * - Save the file without doing extra reshape.
- * - All the users of the mesh have updated displacement.
- *
- * However, the tricky part here is that we only know about sculpted
- * state of a mesh on an object level, and object is being updated after
- * mesh datablock is updated. This forces us to:
- *
- * - Update mesh datablock from object evaluation, which is technically
- * forbidden, but there is no other place for this yet.
- * - Reshape to the original mesh from main database, and then copy updated
- * layer to copy of that mesh (since copy of the mesh has decoupled
- * custom data layers).
- *
- * All this is defeating all the designs we need to follow to allow safe
- * threaded evaluation, but this is as good as we can make it within the
- * current sculpt//evaluated mesh design. This is also how we've survived
- * with old DerivedMesh based solutions. So, while this is all wrong and
- * needs reconsideration, doesn't seem to be a big stopper for real
- * production artists.
- */
- /* TODO(sergey): Solve this somehow, to be fully stable for threaded
- * evaluation environment.
- */
- /* NOTE: runtime.mesh_orig is what was before assigning mesh_eval,
- * it is orig as in what was in object_eval->data before evaluating
- * modifier stack.
- *
- * mesh_cow is a copy-on-written version od object_orig->data.
- */
- Mesh *mesh_cow = object->runtime.mesh_orig;
- copy_ccg_data(mesh_cow, mesh_orig, CD_MDISPS);
- copy_ccg_data(mesh_cow, mesh_orig, CD_GRID_PAINT_MASK);
- /* Everything is now up-to-date. */
- subdiv_ccg->dirty.coords = false;
- subdiv_ccg->dirty.hidden = false;
+ /* Currently CCG is only created for Mesh objects. */
+ if (object->type != OB_MESH) {
+ return;
+ }
+ /* Object was never evaluated, so can not have CCG subdivision surface. */
+ Mesh *mesh_eval = object->runtime.mesh_eval;
+ if (mesh_eval == NULL) {
+ return;
+ }
+ SubdivCCG *subdiv_ccg = mesh_eval->runtime.subdiv_ccg;
+ if (subdiv_ccg == NULL) {
+ return;
+ }
+ /* Check whether there is anything to be reshaped. */
+ if (!subdiv_ccg->dirty.coords && !subdiv_ccg->dirty.hidden) {
+ return;
+ }
+ const int tot_level = mesh_eval->runtime.subdiv_ccg_tot_level;
+ Object *object_orig = DEG_get_original_object(object);
+ Mesh *mesh_orig = (Mesh *)object_orig->data;
+ multiresModifier_reshapeFromCCG(tot_level, mesh_orig, subdiv_ccg);
+ /* NOTE: we need to reshape into an original mesh from main database,
+ * allowing:
+ *
+ * - Update copies of that mesh at any moment.
+ * - Save the file without doing extra reshape.
+ * - All the users of the mesh have updated displacement.
+ *
+ * However, the tricky part here is that we only know about sculpted
+ * state of a mesh on an object level, and object is being updated after
+ * mesh datablock is updated. This forces us to:
+ *
+ * - Update mesh datablock from object evaluation, which is technically
+ * forbidden, but there is no other place for this yet.
+ * - Reshape to the original mesh from main database, and then copy updated
+ * layer to copy of that mesh (since copy of the mesh has decoupled
+ * custom data layers).
+ *
+ * All this is defeating all the designs we need to follow to allow safe
+ * threaded evaluation, but this is as good as we can make it within the
+ * current sculpt//evaluated mesh design. This is also how we've survived
+ * with old DerivedMesh based solutions. So, while this is all wrong and
+ * needs reconsideration, doesn't seem to be a big stopper for real
+ * production artists.
+ */
+ /* TODO(sergey): Solve this somehow, to be fully stable for threaded
+ * evaluation environment.
+ */
+ /* NOTE: runtime.mesh_orig is what was before assigning mesh_eval,
+ * it is orig as in what was in object_eval->data before evaluating
+ * modifier stack.
+ *
+ * mesh_cow is a copy-on-written version od object_orig->data.
+ */
+ Mesh *mesh_cow = object->runtime.mesh_orig;
+ copy_ccg_data(mesh_cow, mesh_orig, CD_MDISPS);
+ copy_ccg_data(mesh_cow, mesh_orig, CD_GRID_PAINT_MASK);
+ /* Everything is now up-to-date. */
+ subdiv_ccg->dirty.coords = false;
+ subdiv_ccg->dirty.hidden = false;
}
/* free data derived from mesh, called when mesh changes or is freed */
void BKE_object_free_derived_caches(Object *ob)
{
- /* Also serves as signal to remake texspace.
- *
- * NOTE: This function can be called from threads on different objects
- * sharing same data datablock. So we need to ensure atomic nature of
- * data modification here.
- */
- if (ob->type == OB_MESH) {
- Mesh *me = ob->data;
-
- if (me && me->bb) {
- atomic_fetch_and_or_int32(&me->bb->flag, BOUNDBOX_DIRTY);
- }
- }
- else if (ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT)) {
- Curve *cu = ob->data;
-
- if (cu && cu->bb) {
- atomic_fetch_and_or_int32(&cu->bb->flag, BOUNDBOX_DIRTY);
- }
- }
-
- MEM_SAFE_FREE(ob->runtime.bb);
-
- object_update_from_subsurf_ccg(ob);
- BKE_object_free_derived_mesh_caches(ob);
- BKE_armature_cached_bbone_deformation_free(ob);
-
- if (ob->runtime.mesh_eval != NULL) {
- Mesh *mesh_eval = ob->runtime.mesh_eval;
- /* Restore initial pointer. */
- if (ob->data == mesh_eval) {
- ob->data = ob->runtime.mesh_orig;
- }
- /* Evaluated mesh points to edit mesh, but does not own it. */
- mesh_eval->edit_mesh = NULL;
- BKE_mesh_free(mesh_eval);
- BKE_libblock_free_data(&mesh_eval->id, false);
- MEM_freeN(mesh_eval);
- ob->runtime.mesh_eval = NULL;
- }
- if (ob->runtime.mesh_deform_eval != NULL) {
- Mesh *mesh_deform_eval = ob->runtime.mesh_deform_eval;
- BKE_mesh_free(mesh_deform_eval);
- BKE_libblock_free_data(&mesh_deform_eval->id, false);
- MEM_freeN(mesh_deform_eval);
- ob->runtime.mesh_deform_eval = NULL;
- }
-
- BKE_object_free_curve_cache(ob);
-
- /* clear grease pencil data */
- DRW_gpencil_freecache(ob);
+ /* Also serves as signal to remake texspace.
+ *
+ * NOTE: This function can be called from threads on different objects
+ * sharing same data datablock. So we need to ensure atomic nature of
+ * data modification here.
+ */
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+
+ if (me && me->bb) {
+ atomic_fetch_and_or_int32(&me->bb->flag, BOUNDBOX_DIRTY);
+ }
+ }
+ else if (ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT)) {
+ Curve *cu = ob->data;
+
+ if (cu && cu->bb) {
+ atomic_fetch_and_or_int32(&cu->bb->flag, BOUNDBOX_DIRTY);
+ }
+ }
+
+ MEM_SAFE_FREE(ob->runtime.bb);
+
+ object_update_from_subsurf_ccg(ob);
+ BKE_object_free_derived_mesh_caches(ob);
+ BKE_armature_cached_bbone_deformation_free(ob);
+
+ if (ob->runtime.mesh_eval != NULL) {
+ Mesh *mesh_eval = ob->runtime.mesh_eval;
+ /* Restore initial pointer. */
+ if (ob->data == mesh_eval) {
+ ob->data = ob->runtime.mesh_orig;
+ }
+ /* Evaluated mesh points to edit mesh, but does not own it. */
+ mesh_eval->edit_mesh = NULL;
+ BKE_mesh_free(mesh_eval);
+ BKE_libblock_free_data(&mesh_eval->id, false);
+ MEM_freeN(mesh_eval);
+ ob->runtime.mesh_eval = NULL;
+ }
+ if (ob->runtime.mesh_deform_eval != NULL) {
+ Mesh *mesh_deform_eval = ob->runtime.mesh_deform_eval;
+ BKE_mesh_free(mesh_deform_eval);
+ BKE_libblock_free_data(&mesh_deform_eval->id, false);
+ MEM_freeN(mesh_deform_eval);
+ ob->runtime.mesh_deform_eval = NULL;
+ }
+
+ BKE_object_free_curve_cache(ob);
+
+ /* clear grease pencil data */
+ DRW_gpencil_freecache(ob);
}
void BKE_object_free_derived_mesh_caches(struct Object *ob)
{
- if (ob->derivedFinal) {
- ob->derivedFinal->needsFree = 1;
- ob->derivedFinal->release(ob->derivedFinal);
- ob->derivedFinal = NULL;
- }
- if (ob->derivedDeform) {
- ob->derivedDeform->needsFree = 1;
- ob->derivedDeform->release(ob->derivedDeform);
- ob->derivedDeform = NULL;
- }
+ if (ob->derivedFinal) {
+ ob->derivedFinal->needsFree = 1;
+ ob->derivedFinal->release(ob->derivedFinal);
+ ob->derivedFinal = NULL;
+ }
+ if (ob->derivedDeform) {
+ ob->derivedDeform->needsFree = 1;
+ ob->derivedDeform->release(ob->derivedDeform);
+ ob->derivedDeform = NULL;
+ }
}
void BKE_object_free_caches(Object *object)
{
- ModifierData *md;
- short update_flag = 0;
-
- /* Free particle system caches holding paths. */
- if (object->particlesystem.first) {
- ParticleSystem *psys;
- for (psys = object->particlesystem.first;
- psys != NULL;
- psys = psys->next)
- {
- psys_free_path_cache(psys, psys->edit);
- update_flag |= ID_RECALC_PSYS_REDO;
- }
- }
-
- /* Free memory used by cached derived meshes in the particle system modifiers. */
- for (md = object->modifiers.first; md != NULL; md = md->next) {
- if (md->type == eModifierType_ParticleSystem) {
- ParticleSystemModifierData *psmd = (ParticleSystemModifierData *) md;
- if (psmd->mesh_final) {
- BKE_id_free(NULL, psmd->mesh_final);
- psmd->mesh_final = NULL;
- if (psmd->mesh_original) {
- BKE_id_free(NULL, psmd->mesh_original);
- psmd->mesh_original = NULL;
- }
- psmd->flag |= eParticleSystemFlag_file_loaded;
- update_flag |= ID_RECALC_GEOMETRY;
- }
- }
- }
-
- /* NOTE: If object is coming from a duplicator, it might be a temporary
- * object created by dependency graph, which shares pointers with original
- * object. In this case we can not free anything.
- */
- if ((object->base_flag & BASE_FROM_DUPLI) == 0) {
- BKE_object_free_derived_caches(object);
- update_flag |= ID_RECALC_GEOMETRY;
- }
-
- /* Tag object for update, so once memory critical operation is over and
- * scene update routines are back to it's business the object will be
- * guaranteed to be in a known state.
- */
- if (update_flag != 0) {
- DEG_id_tag_update(&object->id, update_flag);
- }
+ ModifierData *md;
+ short update_flag = 0;
+
+ /* Free particle system caches holding paths. */
+ if (object->particlesystem.first) {
+ ParticleSystem *psys;
+ for (psys = object->particlesystem.first; psys != NULL; psys = psys->next) {
+ psys_free_path_cache(psys, psys->edit);
+ update_flag |= ID_RECALC_PSYS_REDO;
+ }
+ }
+
+ /* Free memory used by cached derived meshes in the particle system modifiers. */
+ for (md = object->modifiers.first; md != NULL; md = md->next) {
+ if (md->type == eModifierType_ParticleSystem) {
+ ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;
+ if (psmd->mesh_final) {
+ BKE_id_free(NULL, psmd->mesh_final);
+ psmd->mesh_final = NULL;
+ if (psmd->mesh_original) {
+ BKE_id_free(NULL, psmd->mesh_original);
+ psmd->mesh_original = NULL;
+ }
+ psmd->flag |= eParticleSystemFlag_file_loaded;
+ update_flag |= ID_RECALC_GEOMETRY;
+ }
+ }
+ }
+
+ /* NOTE: If object is coming from a duplicator, it might be a temporary
+ * object created by dependency graph, which shares pointers with original
+ * object. In this case we can not free anything.
+ */
+ if ((object->base_flag & BASE_FROM_DUPLI) == 0) {
+ BKE_object_free_derived_caches(object);
+ update_flag |= ID_RECALC_GEOMETRY;
+ }
+
+ /* Tag object for update, so once memory critical operation is over and
+ * scene update routines are back to it's business the object will be
+ * guaranteed to be in a known state.
+ */
+ if (update_flag != 0) {
+ DEG_id_tag_update(&object->id, update_flag);
+ }
}
/** Free (or release) any data used by this object (does not free the object itself). */
void BKE_object_free(Object *ob)
{
- BKE_animdata_free((ID *)ob, false);
+ BKE_animdata_free((ID *)ob, false);
- DRW_drawdata_free((ID *)ob);
+ DRW_drawdata_free((ID *)ob);
- /* BKE_<id>_free shall never touch to ID->us. Never ever. */
- BKE_object_free_modifiers(ob, LIB_ID_CREATE_NO_USER_REFCOUNT);
- BKE_object_free_shaderfx(ob, LIB_ID_CREATE_NO_USER_REFCOUNT);
+ /* BKE_<id>_free shall never touch to ID->us. Never ever. */
+ BKE_object_free_modifiers(ob, LIB_ID_CREATE_NO_USER_REFCOUNT);
+ BKE_object_free_shaderfx(ob, LIB_ID_CREATE_NO_USER_REFCOUNT);
- MEM_SAFE_FREE(ob->mat);
- MEM_SAFE_FREE(ob->matbits);
- MEM_SAFE_FREE(ob->iuser);
- MEM_SAFE_FREE(ob->runtime.bb);
+ MEM_SAFE_FREE(ob->mat);
+ MEM_SAFE_FREE(ob->matbits);
+ MEM_SAFE_FREE(ob->iuser);
+ MEM_SAFE_FREE(ob->runtime.bb);
- BLI_freelistN(&ob->defbase);
- BLI_freelistN(&ob->fmaps);
- if (ob->pose) {
- BKE_pose_free_ex(ob->pose, false);
- ob->pose = NULL;
- }
- if (ob->mpath) {
- animviz_free_motionpath(ob->mpath);
- ob->mpath = NULL;
- }
+ BLI_freelistN(&ob->defbase);
+ BLI_freelistN(&ob->fmaps);
+ if (ob->pose) {
+ BKE_pose_free_ex(ob->pose, false);
+ ob->pose = NULL;
+ }
+ if (ob->mpath) {
+ animviz_free_motionpath(ob->mpath);
+ ob->mpath = NULL;
+ }
- BKE_constraints_free_ex(&ob->constraints, false);
+ BKE_constraints_free_ex(&ob->constraints, false);
- BKE_partdeflect_free(ob->pd);
- BKE_rigidbody_free_object(ob, NULL);
- BKE_rigidbody_free_constraint(ob);
+ BKE_partdeflect_free(ob->pd);
+ BKE_rigidbody_free_object(ob, NULL);
+ BKE_rigidbody_free_constraint(ob);
- sbFree(ob);
+ sbFree(ob);
- BKE_sculptsession_free(ob);
+ BKE_sculptsession_free(ob);
- BLI_freelistN(&ob->pc_ids);
+ BLI_freelistN(&ob->pc_ids);
- BLI_freelistN(&ob->lodlevels);
+ BLI_freelistN(&ob->lodlevels);
- /* Free runtime curves data. */
- if (ob->runtime.curve_cache) {
- BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev);
- if (ob->runtime.curve_cache->path)
- free_path(ob->runtime.curve_cache->path);
- MEM_freeN(ob->runtime.curve_cache);
- ob->runtime.curve_cache = NULL;
- }
+ /* Free runtime curves data. */
+ if (ob->runtime.curve_cache) {
+ BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev);
+ if (ob->runtime.curve_cache->path)
+ free_path(ob->runtime.curve_cache->path);
+ MEM_freeN(ob->runtime.curve_cache);
+ ob->runtime.curve_cache = NULL;
+ }
- BKE_previewimg_free(&ob->preview);
+ BKE_previewimg_free(&ob->preview);
}
/* actual check for internal data, not context or flags */
bool BKE_object_is_in_editmode(const Object *ob)
{
- if (ob->data == NULL) {
- return false;
- }
-
- switch (ob->type) {
- case OB_MESH:
- return ((Mesh *)ob->data)->edit_mesh != NULL;
- case OB_ARMATURE:
- return ((bArmature *)ob->data)->edbo != NULL;
- case OB_FONT:
- return ((Curve *)ob->data)->editfont != NULL;
- case OB_MBALL:
- return ((MetaBall *)ob->data)->editelems != NULL;
- case OB_LATTICE:
- return ((Lattice *)ob->data)->editlatt != NULL;
- case OB_SURF:
- case OB_CURVE:
- return ((Curve *)ob->data)->editnurb != NULL;
- default:
- return false;
- }
+ if (ob->data == NULL) {
+ return false;
+ }
+
+ switch (ob->type) {
+ case OB_MESH:
+ return ((Mesh *)ob->data)->edit_mesh != NULL;
+ case OB_ARMATURE:
+ return ((bArmature *)ob->data)->edbo != NULL;
+ case OB_FONT:
+ return ((Curve *)ob->data)->editfont != NULL;
+ case OB_MBALL:
+ return ((MetaBall *)ob->data)->editelems != NULL;
+ case OB_LATTICE:
+ return ((Lattice *)ob->data)->editlatt != NULL;
+ case OB_SURF:
+ case OB_CURVE:
+ return ((Curve *)ob->data)->editnurb != NULL;
+ default:
+ return false;
+ }
}
bool BKE_object_is_in_editmode_vgroup(const Object *ob)
{
- return (OB_TYPE_SUPPORT_VGROUP(ob->type) &&
- BKE_object_is_in_editmode(ob));
+ return (OB_TYPE_SUPPORT_VGROUP(ob->type) && BKE_object_is_in_editmode(ob));
}
bool BKE_object_data_is_in_editmode(const ID *id)
{
- const short type = GS(id->name);
- BLI_assert(OB_DATA_SUPPORT_EDITMODE(type));
- switch (type) {
- case ID_ME:
- return ((const Mesh *)id)->edit_mesh != NULL;
- case ID_CU:
- return (
- (((const Curve *)id)->editnurb != NULL) ||
- (((const Curve *)id)->editfont != NULL)
- );
- case ID_MB:
- return ((const MetaBall *)id)->editelems != NULL;
- case ID_LT:
- return ((const Lattice *)id)->editlatt != NULL;
- case ID_AR:
- return ((const bArmature *)id)->edbo != NULL;
- default:
- BLI_assert(0);
- return false;
- }
+ const short type = GS(id->name);
+ BLI_assert(OB_DATA_SUPPORT_EDITMODE(type));
+ switch (type) {
+ case ID_ME:
+ return ((const Mesh *)id)->edit_mesh != NULL;
+ case ID_CU:
+ return ((((const Curve *)id)->editnurb != NULL) || (((const Curve *)id)->editfont != NULL));
+ case ID_MB:
+ return ((const MetaBall *)id)->editelems != NULL;
+ case ID_LT:
+ return ((const Lattice *)id)->editlatt != NULL;
+ case ID_AR:
+ return ((const bArmature *)id)->edbo != NULL;
+ default:
+ BLI_assert(0);
+ return false;
+ }
}
bool BKE_object_is_in_wpaint_select_vert(const Object *ob)
{
- if (ob->type == OB_MESH) {
- Mesh *me = ob->data;
- return ((ob->mode & OB_MODE_WEIGHT_PAINT) &&
- (me->edit_mesh == NULL) &&
- (ME_EDIT_PAINT_SEL_MODE(me) == SCE_SELECT_VERTEX));
- }
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+ return ((ob->mode & OB_MODE_WEIGHT_PAINT) && (me->edit_mesh == NULL) &&
+ (ME_EDIT_PAINT_SEL_MODE(me) == SCE_SELECT_VERTEX));
+ }
- return false;
+ return false;
}
bool BKE_object_has_mode_data(const struct Object *ob, eObjectMode object_mode)
{
- if (object_mode & OB_MODE_EDIT) {
- if (BKE_object_is_in_editmode(ob)) {
- return true;
- }
- }
- else if (object_mode & OB_MODE_VERTEX_PAINT) {
- if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_VERTEX_PAINT)) {
- return true;
- }
- }
- else if (object_mode & OB_MODE_WEIGHT_PAINT) {
- if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_WEIGHT_PAINT)) {
- return true;
- }
- }
- else if (object_mode & OB_MODE_SCULPT) {
- if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_SCULPT)) {
- return true;
- }
- }
- else if (object_mode & OB_MODE_POSE) {
- if (ob->pose != NULL) {
- return true;
- }
- }
- return false;
+ if (object_mode & OB_MODE_EDIT) {
+ if (BKE_object_is_in_editmode(ob)) {
+ return true;
+ }
+ }
+ else if (object_mode & OB_MODE_VERTEX_PAINT) {
+ if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_VERTEX_PAINT)) {
+ return true;
+ }
+ }
+ else if (object_mode & OB_MODE_WEIGHT_PAINT) {
+ if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_WEIGHT_PAINT)) {
+ return true;
+ }
+ }
+ else if (object_mode & OB_MODE_SCULPT) {
+ if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_SCULPT)) {
+ return true;
+ }
+ }
+ else if (object_mode & OB_MODE_POSE) {
+ if (ob->pose != NULL) {
+ return true;
+ }
+ }
+ return false;
}
bool BKE_object_is_mode_compat(const struct Object *ob, eObjectMode object_mode)
{
- return ((ob->mode == object_mode) ||
- (ob->mode & object_mode) != 0);
+ return ((ob->mode == object_mode) || (ob->mode & object_mode) != 0);
}
/**
@@ -711,192 +692,219 @@ bool BKE_object_is_mode_compat(const struct Object *ob, eObjectMode object_mode)
*/
int BKE_object_visibility(const Object *ob, const int dag_eval_mode)
{
- if ((ob->base_flag & BASE_VISIBLE) == 0) {
- return 0;
- }
-
- /* Test which components the object has. */
- int visibility = OB_VISIBLE_SELF;
- if (ob->particlesystem.first) {
- visibility |= OB_VISIBLE_INSTANCES | OB_VISIBLE_PARTICLES;
- }
- else if (ob->transflag & OB_DUPLI) {
- visibility |= OB_VISIBLE_INSTANCES;
- }
-
- /* Optional hiding of self if there are particles or instancers. */
- if (visibility & (OB_VISIBLE_PARTICLES | OB_VISIBLE_INSTANCES)) {
- switch ((eEvaluationMode)dag_eval_mode) {
- case DAG_EVAL_VIEWPORT:
- if (!(ob->duplicator_visibility_flag & OB_DUPLI_FLAG_VIEWPORT)) {
- visibility &= ~OB_VISIBLE_SELF;
- }
- break;
- case DAG_EVAL_RENDER:
- if (!(ob->duplicator_visibility_flag & OB_DUPLI_FLAG_RENDER)) {
- visibility &= ~OB_VISIBLE_SELF;
- }
- break;
- }
- }
-
- return visibility;
+ if ((ob->base_flag & BASE_VISIBLE) == 0) {
+ return 0;
+ }
+
+ /* Test which components the object has. */
+ int visibility = OB_VISIBLE_SELF;
+ if (ob->particlesystem.first) {
+ visibility |= OB_VISIBLE_INSTANCES | OB_VISIBLE_PARTICLES;
+ }
+ else if (ob->transflag & OB_DUPLI) {
+ visibility |= OB_VISIBLE_INSTANCES;
+ }
+
+ /* Optional hiding of self if there are particles or instancers. */
+ if (visibility & (OB_VISIBLE_PARTICLES | OB_VISIBLE_INSTANCES)) {
+ switch ((eEvaluationMode)dag_eval_mode) {
+ case DAG_EVAL_VIEWPORT:
+ if (!(ob->duplicator_visibility_flag & OB_DUPLI_FLAG_VIEWPORT)) {
+ visibility &= ~OB_VISIBLE_SELF;
+ }
+ break;
+ case DAG_EVAL_RENDER:
+ if (!(ob->duplicator_visibility_flag & OB_DUPLI_FLAG_RENDER)) {
+ visibility &= ~OB_VISIBLE_SELF;
+ }
+ break;
+ }
+ }
+
+ return visibility;
}
bool BKE_object_exists_check(Main *bmain, const Object *obtest)
{
- Object *ob;
+ Object *ob;
- if (obtest == NULL) return false;
+ if (obtest == NULL)
+ return false;
- ob = bmain->objects.first;
- while (ob) {
- if (ob == obtest) return true;
- ob = ob->id.next;
- }
- return false;
+ ob = bmain->objects.first;
+ while (ob) {
+ if (ob == obtest)
+ return true;
+ ob = ob->id.next;
+ }
+ return false;
}
/* *************************************************** */
static const char *get_obdata_defname(int type)
{
- switch (type) {
- case OB_MESH: return DATA_("Mesh");
- case OB_CURVE: return DATA_("Curve");
- case OB_SURF: return DATA_("Surf");
- case OB_FONT: return DATA_("Text");
- case OB_MBALL: return DATA_("Mball");
- case OB_CAMERA: return DATA_("Camera");
- case OB_LAMP: return CTX_DATA_(BLT_I18NCONTEXT_ID_LIGHT, "Light");
- case OB_LATTICE: return DATA_("Lattice");
- case OB_ARMATURE: return DATA_("Armature");
- case OB_SPEAKER: return DATA_("Speaker");
- case OB_EMPTY: return DATA_("Empty");
- case OB_GPENCIL: return DATA_("GPencil");
- default:
- CLOG_ERROR(&LOG, "Internal error, bad type: %d", type);
- return DATA_("Empty");
- }
+ switch (type) {
+ case OB_MESH:
+ return DATA_("Mesh");
+ case OB_CURVE:
+ return DATA_("Curve");
+ case OB_SURF:
+ return DATA_("Surf");
+ case OB_FONT:
+ return DATA_("Text");
+ case OB_MBALL:
+ return DATA_("Mball");
+ case OB_CAMERA:
+ return DATA_("Camera");
+ case OB_LAMP:
+ return CTX_DATA_(BLT_I18NCONTEXT_ID_LIGHT, "Light");
+ case OB_LATTICE:
+ return DATA_("Lattice");
+ case OB_ARMATURE:
+ return DATA_("Armature");
+ case OB_SPEAKER:
+ return DATA_("Speaker");
+ case OB_EMPTY:
+ return DATA_("Empty");
+ case OB_GPENCIL:
+ return DATA_("GPencil");
+ default:
+ CLOG_ERROR(&LOG, "Internal error, bad type: %d", type);
+ return DATA_("Empty");
+ }
}
void *BKE_object_obdata_add_from_type(Main *bmain, int type, const char *name)
{
- if (name == NULL) {
- name = get_obdata_defname(type);
- }
-
- switch (type) {
- case OB_MESH: return BKE_mesh_add(bmain, name);
- case OB_CURVE: return BKE_curve_add(bmain, name, OB_CURVE);
- case OB_SURF: return BKE_curve_add(bmain, name, OB_SURF);
- case OB_FONT: return BKE_curve_add(bmain, name, OB_FONT);
- case OB_MBALL: return BKE_mball_add(bmain, name);
- case OB_CAMERA: return BKE_camera_add(bmain, name);
- case OB_LAMP: return BKE_light_add(bmain, name);
- case OB_LATTICE: return BKE_lattice_add(bmain, name);
- case OB_ARMATURE: return BKE_armature_add(bmain, name);
- case OB_SPEAKER: return BKE_speaker_add(bmain, name);
- case OB_LIGHTPROBE:return BKE_lightprobe_add(bmain, name);
- case OB_GPENCIL: return BKE_gpencil_data_addnew(bmain, name);
- case OB_EMPTY: return NULL;
- default:
- CLOG_ERROR(&LOG, "Internal error, bad type: %d", type);
- return NULL;
- }
+ if (name == NULL) {
+ name = get_obdata_defname(type);
+ }
+
+ switch (type) {
+ case OB_MESH:
+ return BKE_mesh_add(bmain, name);
+ case OB_CURVE:
+ return BKE_curve_add(bmain, name, OB_CURVE);
+ case OB_SURF:
+ return BKE_curve_add(bmain, name, OB_SURF);
+ case OB_FONT:
+ return BKE_curve_add(bmain, name, OB_FONT);
+ case OB_MBALL:
+ return BKE_mball_add(bmain, name);
+ case OB_CAMERA:
+ return BKE_camera_add(bmain, name);
+ case OB_LAMP:
+ return BKE_light_add(bmain, name);
+ case OB_LATTICE:
+ return BKE_lattice_add(bmain, name);
+ case OB_ARMATURE:
+ return BKE_armature_add(bmain, name);
+ case OB_SPEAKER:
+ return BKE_speaker_add(bmain, name);
+ case OB_LIGHTPROBE:
+ return BKE_lightprobe_add(bmain, name);
+ case OB_GPENCIL:
+ return BKE_gpencil_data_addnew(bmain, name);
+ case OB_EMPTY:
+ return NULL;
+ default:
+ CLOG_ERROR(&LOG, "Internal error, bad type: %d", type);
+ return NULL;
+ }
}
void BKE_object_init(Object *ob)
{
- /* BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(ob, id)); */ /* ob->type is already initialized... */
+ /* BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(ob, id)); */ /* ob->type is already initialized... */
- copy_v4_fl(ob->color, 1.0f);
+ copy_v4_fl(ob->color, 1.0f);
- ob->scale[0] = ob->scale[1] = ob->scale[2] = 1.0;
- ob->dscale[0] = ob->dscale[1] = ob->dscale[2] = 1.0;
+ ob->scale[0] = ob->scale[1] = ob->scale[2] = 1.0;
+ ob->dscale[0] = ob->dscale[1] = ob->dscale[2] = 1.0;
- /* objects should default to having Euler XYZ rotations,
- * but rotations default to quaternions
- */
- ob->rotmode = ROT_MODE_EUL;
+ /* objects should default to having Euler XYZ rotations,
+ * but rotations default to quaternions
+ */
+ ob->rotmode = ROT_MODE_EUL;
- unit_axis_angle(ob->rotAxis, &ob->rotAngle);
- unit_axis_angle(ob->drotAxis, &ob->drotAngle);
+ unit_axis_angle(ob->rotAxis, &ob->rotAngle);
+ unit_axis_angle(ob->drotAxis, &ob->drotAngle);
- unit_qt(ob->quat);
- unit_qt(ob->dquat);
+ unit_qt(ob->quat);
+ unit_qt(ob->dquat);
- /* rotation locks should be 4D for 4 component rotations by default... */
- ob->protectflag = OB_LOCK_ROT4D;
+ /* rotation locks should be 4D for 4 component rotations by default... */
+ ob->protectflag = OB_LOCK_ROT4D;
- unit_m4(ob->constinv);
- unit_m4(ob->parentinv);
- unit_m4(ob->obmat);
- ob->dt = OB_TEXTURE;
- ob->empty_drawtype = OB_PLAINAXES;
- ob->empty_drawsize = 1.0;
- ob->empty_image_depth = OB_EMPTY_IMAGE_DEPTH_DEFAULT;
- if (ob->type == OB_EMPTY) {
- copy_v2_fl(ob->ima_ofs, -0.5f);
- }
+ unit_m4(ob->constinv);
+ unit_m4(ob->parentinv);
+ unit_m4(ob->obmat);
+ ob->dt = OB_TEXTURE;
+ ob->empty_drawtype = OB_PLAINAXES;
+ ob->empty_drawsize = 1.0;
+ ob->empty_image_depth = OB_EMPTY_IMAGE_DEPTH_DEFAULT;
+ if (ob->type == OB_EMPTY) {
+ copy_v2_fl(ob->ima_ofs, -0.5f);
+ }
- if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) {
- ob->trackflag = OB_NEGZ;
- ob->upflag = OB_POSY;
- }
- else {
- ob->trackflag = OB_POSY;
- ob->upflag = OB_POSZ;
- }
+ if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) {
+ ob->trackflag = OB_NEGZ;
+ ob->upflag = OB_POSY;
+ }
+ else {
+ ob->trackflag = OB_POSY;
+ ob->upflag = OB_POSZ;
+ }
- ob->instance_faces_scale = 1.0;
+ ob->instance_faces_scale = 1.0;
- ob->col_group = 0x01;
- ob->col_mask = 0xffff;
- ob->preview = NULL;
- ob->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT | OB_DUPLI_FLAG_RENDER;
+ ob->col_group = 0x01;
+ ob->col_mask = 0xffff;
+ ob->preview = NULL;
+ ob->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT | OB_DUPLI_FLAG_RENDER;
- /* NT fluid sim defaults */
- ob->fluidsimSettings = NULL;
+ /* NT fluid sim defaults */
+ ob->fluidsimSettings = NULL;
- BLI_listbase_clear(&ob->pc_ids);
+ BLI_listbase_clear(&ob->pc_ids);
- /* Animation Visualization defaults */
- animviz_settings_init(&ob->avs);
+ /* Animation Visualization defaults */
+ animviz_settings_init(&ob->avs);
}
/* more general add: creates minimum required data, but without vertices etc. */
Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
{
- Object *ob;
+ Object *ob;
- if (!name)
- name = get_obdata_defname(type);
+ if (!name)
+ name = get_obdata_defname(type);
- ob = BKE_libblock_alloc(bmain, ID_OB, name, 0);
+ ob = BKE_libblock_alloc(bmain, ID_OB, name, 0);
- /* We increase object user count when linking to Collections. */
- id_us_min(&ob->id);
+ /* We increase object user count when linking to Collections. */
+ id_us_min(&ob->id);
- /* default object vars */
- ob->type = type;
+ /* default object vars */
+ ob->type = type;
- BKE_object_init(ob);
+ BKE_object_init(ob);
- return ob;
+ return ob;
}
-
static Object *object_add_common(Main *bmain, ViewLayer *view_layer, int type, const char *name)
{
- Object *ob;
+ Object *ob;
- ob = BKE_object_add_only_object(bmain, type, name);
- ob->data = BKE_object_obdata_add_from_type(bmain, type, name);
- BKE_view_layer_base_deselect_all(view_layer);
+ ob = BKE_object_add_only_object(bmain, type, name);
+ ob->data = BKE_object_obdata_add_from_type(bmain, type, name);
+ BKE_view_layer_base_deselect_all(view_layer);
- DEG_id_tag_update_ex(bmain, &ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
- return ob;
+ DEG_id_tag_update_ex(
+ bmain, &ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
+ return ob;
}
/**
@@ -907,22 +915,21 @@ static Object *object_add_common(Main *bmain, ViewLayer *view_layer, int type, c
*/
/* creates minimum required data, but without vertices etc. */
Object *BKE_object_add(
- Main *bmain, Scene *UNUSED(scene), ViewLayer *view_layer,
- int type, const char *name)
+ Main *bmain, Scene *UNUSED(scene), ViewLayer *view_layer, int type, const char *name)
{
- Object *ob;
- Base *base;
- LayerCollection *layer_collection;
+ Object *ob;
+ Base *base;
+ LayerCollection *layer_collection;
- ob = object_add_common(bmain, view_layer, type, name);
+ ob = object_add_common(bmain, view_layer, type, name);
- layer_collection = BKE_layer_collection_get_active(view_layer);
- BKE_collection_object_add(bmain, layer_collection->collection, ob);
+ layer_collection = BKE_layer_collection_get_active(view_layer);
+ BKE_collection_object_add(bmain, layer_collection->collection, ob);
- base = BKE_view_layer_base_find(view_layer, ob);
- BKE_view_layer_base_select_and_set_active(view_layer, base);
+ base = BKE_view_layer_base_find(view_layer, ob);
+ BKE_view_layer_base_select_and_set_active(view_layer, base);
- return ob;
+ return ob;
}
/**
@@ -931,19 +938,18 @@ Object *BKE_object_add(
* \param ob_src: object to use to determine the collections of the new object.
*/
Object *BKE_object_add_from(
- Main *bmain, Scene *scene, ViewLayer *view_layer,
- int type, const char *name, Object *ob_src)
+ Main *bmain, Scene *scene, ViewLayer *view_layer, int type, const char *name, Object *ob_src)
{
- Object *ob;
- Base *base;
+ Object *ob;
+ Base *base;
- ob = object_add_common(bmain, view_layer, type, name);
- BKE_collection_object_add_from(bmain, scene, ob_src, ob);
+ ob = object_add_common(bmain, view_layer, type, name);
+ BKE_collection_object_add_from(bmain, scene, ob_src, ob);
- base = BKE_view_layer_base_find(view_layer, ob);
- BKE_view_layer_base_select_and_set_active(view_layer, base);
+ base = BKE_view_layer_base_find(view_layer, ob);
+ BKE_view_layer_base_select_and_set_active(view_layer, base);
- return ob;
+ return ob;
}
/**
@@ -956,353 +962,360 @@ Object *BKE_object_add_from(
* assigning it to the object.
*/
Object *BKE_object_add_for_data(
- Main *bmain, ViewLayer *view_layer,
- int type, const char *name, ID *data, bool do_id_user)
+ Main *bmain, ViewLayer *view_layer, int type, const char *name, ID *data, bool do_id_user)
{
- Object *ob;
- Base *base;
- LayerCollection *layer_collection;
+ Object *ob;
+ Base *base;
+ LayerCollection *layer_collection;
- /* same as object_add_common, except we don't create new ob->data */
- ob = BKE_object_add_only_object(bmain, type, name);
- ob->data = data;
- if (do_id_user) id_us_plus(data);
+ /* same as object_add_common, except we don't create new ob->data */
+ ob = BKE_object_add_only_object(bmain, type, name);
+ ob->data = data;
+ if (do_id_user)
+ id_us_plus(data);
- BKE_view_layer_base_deselect_all(view_layer);
- DEG_id_tag_update_ex(bmain, &ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
+ BKE_view_layer_base_deselect_all(view_layer);
+ DEG_id_tag_update_ex(
+ bmain, &ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
- layer_collection = BKE_layer_collection_get_active(view_layer);
- BKE_collection_object_add(bmain, layer_collection->collection, ob);
+ layer_collection = BKE_layer_collection_get_active(view_layer);
+ BKE_collection_object_add(bmain, layer_collection->collection, ob);
- base = BKE_view_layer_base_find(view_layer, ob);
- BKE_view_layer_base_select_and_set_active(view_layer, base);
+ base = BKE_view_layer_base_find(view_layer, ob);
+ BKE_view_layer_base_select_and_set_active(view_layer, base);
- return ob;
+ return ob;
}
-
void BKE_object_copy_softbody(struct Object *ob_dst, const struct Object *ob_src, const int flag)
{
- SoftBody *sb = ob_src->soft;
- SoftBody *sbn;
- bool tagged_no_main = ob_dst->id.tag & LIB_TAG_NO_MAIN;
+ SoftBody *sb = ob_src->soft;
+ SoftBody *sbn;
+ bool tagged_no_main = ob_dst->id.tag & LIB_TAG_NO_MAIN;
- ob_dst->softflag = ob_src->softflag;
- if (sb == NULL) {
- ob_dst->soft = NULL;
- return;
- }
+ ob_dst->softflag = ob_src->softflag;
+ if (sb == NULL) {
+ ob_dst->soft = NULL;
+ return;
+ }
- sbn = MEM_dupallocN(sb);
+ sbn = MEM_dupallocN(sb);
- if ((flag & LIB_ID_COPY_CACHES) == 0) {
- sbn->totspring = sbn->totpoint = 0;
- sbn->bpoint = NULL;
- sbn->bspring = NULL;
- }
- else {
- sbn->totspring = sb->totspring;
- sbn->totpoint = sb->totpoint;
+ if ((flag & LIB_ID_COPY_CACHES) == 0) {
+ sbn->totspring = sbn->totpoint = 0;
+ sbn->bpoint = NULL;
+ sbn->bspring = NULL;
+ }
+ else {
+ sbn->totspring = sb->totspring;
+ sbn->totpoint = sb->totpoint;
- if (sbn->bpoint) {
- int i;
+ if (sbn->bpoint) {
+ int i;
- sbn->bpoint = MEM_dupallocN(sbn->bpoint);
+ sbn->bpoint = MEM_dupallocN(sbn->bpoint);
- for (i = 0; i < sbn->totpoint; i++) {
- if (sbn->bpoint[i].springs)
- sbn->bpoint[i].springs = MEM_dupallocN(sbn->bpoint[i].springs);
- }
- }
+ for (i = 0; i < sbn->totpoint; i++) {
+ if (sbn->bpoint[i].springs)
+ sbn->bpoint[i].springs = MEM_dupallocN(sbn->bpoint[i].springs);
+ }
+ }
- if (sb->bspring)
- sbn->bspring = MEM_dupallocN(sb->bspring);
- }
+ if (sb->bspring)
+ sbn->bspring = MEM_dupallocN(sb->bspring);
+ }
- sbn->keys = NULL;
- sbn->totkey = sbn->totpointkey = 0;
+ sbn->keys = NULL;
+ sbn->totkey = sbn->totpointkey = 0;
- sbn->scratch = NULL;
+ sbn->scratch = NULL;
- if (tagged_no_main == 0) {
- sbn->shared = MEM_dupallocN(sb->shared);
- sbn->shared->pointcache = BKE_ptcache_copy_list(&sbn->shared->ptcaches, &sb->shared->ptcaches, flag);
- }
+ if (tagged_no_main == 0) {
+ sbn->shared = MEM_dupallocN(sb->shared);
+ sbn->shared->pointcache = BKE_ptcache_copy_list(
+ &sbn->shared->ptcaches, &sb->shared->ptcaches, flag);
+ }
- if (sb->effector_weights)
- sbn->effector_weights = MEM_dupallocN(sb->effector_weights);
+ if (sb->effector_weights)
+ sbn->effector_weights = MEM_dupallocN(sb->effector_weights);
- ob_dst->soft = sbn;
+ ob_dst->soft = sbn;
}
ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys, const int flag)
{
- ParticleSystem *psysn = MEM_dupallocN(psys);
+ ParticleSystem *psysn = MEM_dupallocN(psys);
- psys_copy_particles(psysn, psys);
+ psys_copy_particles(psysn, psys);
- if (psys->clmd) {
- psysn->clmd = (ClothModifierData *)modifier_new(eModifierType_Cloth);
- modifier_copyData_ex((ModifierData *)psys->clmd, (ModifierData *)psysn->clmd, flag);
- psys->hair_in_mesh = psys->hair_out_mesh = NULL;
- }
+ if (psys->clmd) {
+ psysn->clmd = (ClothModifierData *)modifier_new(eModifierType_Cloth);
+ modifier_copyData_ex((ModifierData *)psys->clmd, (ModifierData *)psysn->clmd, flag);
+ psys->hair_in_mesh = psys->hair_out_mesh = NULL;
+ }
- BLI_duplicatelist(&psysn->targets, &psys->targets);
+ BLI_duplicatelist(&psysn->targets, &psys->targets);
- psysn->pathcache = NULL;
- psysn->childcache = NULL;
- psysn->edit = NULL;
- psysn->pdd = NULL;
- psysn->effectors = NULL;
- psysn->tree = NULL;
- psysn->bvhtree = NULL;
- psysn->batch_cache = NULL;
+ psysn->pathcache = NULL;
+ psysn->childcache = NULL;
+ psysn->edit = NULL;
+ psysn->pdd = NULL;
+ psysn->effectors = NULL;
+ psysn->tree = NULL;
+ psysn->bvhtree = NULL;
+ psysn->batch_cache = NULL;
- BLI_listbase_clear(&psysn->pathcachebufs);
- BLI_listbase_clear(&psysn->childcachebufs);
+ BLI_listbase_clear(&psysn->pathcachebufs);
+ BLI_listbase_clear(&psysn->childcachebufs);
- if (flag & LIB_ID_CREATE_NO_MAIN) {
- BLI_assert((psys->flag & PSYS_SHARED_CACHES) == 0);
- psysn->flag |= PSYS_SHARED_CACHES;
- BLI_assert(psysn->pointcache != NULL);
- }
- else {
- psysn->pointcache = BKE_ptcache_copy_list(&psysn->ptcaches, &psys->ptcaches, flag);
- }
+ if (flag & LIB_ID_CREATE_NO_MAIN) {
+ BLI_assert((psys->flag & PSYS_SHARED_CACHES) == 0);
+ psysn->flag |= PSYS_SHARED_CACHES;
+ BLI_assert(psysn->pointcache != NULL);
+ }
+ else {
+ psysn->pointcache = BKE_ptcache_copy_list(&psysn->ptcaches, &psys->ptcaches, flag);
+ }
- /* XXX - from reading existing code this seems correct but intended usage of
- * pointcache should /w cloth should be added in 'ParticleSystem' - campbell */
- if (psysn->clmd) {
- psysn->clmd->point_cache = psysn->pointcache;
- }
+ /* XXX - from reading existing code this seems correct but intended usage of
+ * pointcache should /w cloth should be added in 'ParticleSystem' - campbell */
+ if (psysn->clmd) {
+ psysn->clmd->point_cache = psysn->pointcache;
+ }
- if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- id_us_plus((ID *)psysn->part);
- }
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id_us_plus((ID *)psysn->part);
+ }
- return psysn;
+ return psysn;
}
void BKE_object_copy_particlesystems(Object *ob_dst, const Object *ob_src, const int flag)
{
- ParticleSystem *psys, *npsys;
- ModifierData *md;
-
- if (ob_dst->type != OB_MESH) {
- /* currently only mesh objects can have soft body */
- return;
- }
-
- BLI_listbase_clear(&ob_dst->particlesystem);
- for (psys = ob_src->particlesystem.first; psys; psys = psys->next) {
- npsys = BKE_object_copy_particlesystem(psys, flag);
-
- BLI_addtail(&ob_dst->particlesystem, npsys);
-
- /* need to update particle modifiers too */
- for (md = ob_dst->modifiers.first; md; md = md->next) {
- if (md->type == eModifierType_ParticleSystem) {
- ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;
- if (psmd->psys == psys)
- psmd->psys = npsys;
- }
- else if (md->type == eModifierType_DynamicPaint) {
- DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
- if (pmd->brush) {
- if (pmd->brush->psys == psys) {
- pmd->brush->psys = npsys;
- }
- }
- }
- else if (md->type == eModifierType_Smoke) {
- SmokeModifierData *smd = (SmokeModifierData *) md;
-
- if (smd->type == MOD_SMOKE_TYPE_FLOW) {
- if (smd->flow) {
- if (smd->flow->psys == psys)
- smd->flow->psys = npsys;
- }
- }
- }
- }
- }
+ ParticleSystem *psys, *npsys;
+ ModifierData *md;
+
+ if (ob_dst->type != OB_MESH) {
+ /* currently only mesh objects can have soft body */
+ return;
+ }
+
+ BLI_listbase_clear(&ob_dst->particlesystem);
+ for (psys = ob_src->particlesystem.first; psys; psys = psys->next) {
+ npsys = BKE_object_copy_particlesystem(psys, flag);
+
+ BLI_addtail(&ob_dst->particlesystem, npsys);
+
+ /* need to update particle modifiers too */
+ for (md = ob_dst->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_ParticleSystem) {
+ ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;
+ if (psmd->psys == psys)
+ psmd->psys = npsys;
+ }
+ else if (md->type == eModifierType_DynamicPaint) {
+ DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
+ if (pmd->brush) {
+ if (pmd->brush->psys == psys) {
+ pmd->brush->psys = npsys;
+ }
+ }
+ }
+ else if (md->type == eModifierType_Smoke) {
+ SmokeModifierData *smd = (SmokeModifierData *)md;
+
+ if (smd->type == MOD_SMOKE_TYPE_FLOW) {
+ if (smd->flow) {
+ if (smd->flow->psys == psys)
+ smd->flow->psys = npsys;
+ }
+ }
+ }
+ }
+ }
}
static void copy_object_pose(Object *obn, const Object *ob, const int flag)
{
- bPoseChannel *chan;
+ bPoseChannel *chan;
- /* note: need to clear obn->pose pointer first,
- * so that BKE_pose_copy_data works (otherwise there's a crash) */
- obn->pose = NULL;
- BKE_pose_copy_data_ex(&obn->pose, ob->pose, flag, true); /* true = copy constraints */
+ /* note: need to clear obn->pose pointer first,
+ * so that BKE_pose_copy_data works (otherwise there's a crash) */
+ obn->pose = NULL;
+ BKE_pose_copy_data_ex(&obn->pose, ob->pose, flag, true); /* true = copy constraints */
- for (chan = obn->pose->chanbase.first; chan; chan = chan->next) {
- bConstraint *con;
+ for (chan = obn->pose->chanbase.first; chan; chan = chan->next) {
+ bConstraint *con;
- chan->flag &= ~(POSE_LOC | POSE_ROT | POSE_SIZE);
+ chan->flag &= ~(POSE_LOC | POSE_ROT | POSE_SIZE);
- /* XXX Remapping object pointing onto itself should be handled by generic BKE_library_remap stuff, but...
- * the flush_constraint_targets callback am not sure about, so will delay that for now. */
- for (con = chan->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
+ /* XXX Remapping object pointing onto itself should be handled by generic BKE_library_remap stuff, but...
+ * the flush_constraint_targets callback am not sure about, so will delay that for now. */
+ for (con = chan->constraints.first; con; con = con->next) {
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
- for (ct = targets.first; ct; ct = ct->next) {
- if (ct->tar == ob)
- ct->tar = obn;
- }
+ for (ct = targets.first; ct; ct = ct->next) {
+ if (ct->tar == ob)
+ ct->tar = obn;
+ }
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 0);
- }
- }
- }
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 0);
+ }
+ }
+ }
}
static void copy_object_lod(Object *obn, const Object *ob, const int UNUSED(flag))
{
- BLI_duplicatelist(&obn->lodlevels, &ob->lodlevels);
+ BLI_duplicatelist(&obn->lodlevels, &ob->lodlevels);
- obn->currentlod = (LodLevel *)obn->lodlevels.first;
+ obn->currentlod = (LodLevel *)obn->lodlevels.first;
}
bool BKE_object_pose_context_check(const Object *ob)
{
- if ((ob) &&
- (ob->type == OB_ARMATURE) &&
- (ob->pose) &&
- (ob->mode & OB_MODE_POSE))
- {
- return true;
- }
- else {
- return false;
- }
+ if ((ob) && (ob->type == OB_ARMATURE) && (ob->pose) && (ob->mode & OB_MODE_POSE)) {
+ return true;
+ }
+ else {
+ return false;
+ }
}
Object *BKE_object_pose_armature_get(Object *ob)
{
- if (ob == NULL)
- return NULL;
+ if (ob == NULL)
+ return NULL;
- if (BKE_object_pose_context_check(ob))
- return ob;
+ if (BKE_object_pose_context_check(ob))
+ return ob;
- ob = modifiers_isDeformedByArmature(ob);
+ ob = modifiers_isDeformedByArmature(ob);
- /* Only use selected check when non-active. */
- if (BKE_object_pose_context_check(ob))
- return ob;
+ /* Only use selected check when non-active. */
+ if (BKE_object_pose_context_check(ob))
+ return ob;
- return NULL;
+ return NULL;
}
Object *BKE_object_pose_armature_get_visible(Object *ob, ViewLayer *view_layer, View3D *v3d)
{
- Object *ob_armature = BKE_object_pose_armature_get(ob);
- if (ob_armature) {
- Base *base = BKE_view_layer_base_find(view_layer, ob_armature);
- if (base) {
- if (BASE_VISIBLE(v3d, base)) {
- return ob_armature;
- }
- }
- }
- return NULL;
+ Object *ob_armature = BKE_object_pose_armature_get(ob);
+ if (ob_armature) {
+ Base *base = BKE_view_layer_base_find(view_layer, ob_armature);
+ if (base) {
+ if (BASE_VISIBLE(v3d, base)) {
+ return ob_armature;
+ }
+ }
+ }
+ return NULL;
}
/**
* Access pose array with special check to get pose object when in weight paint mode.
*/
-Object **BKE_object_pose_array_get_ex(ViewLayer *view_layer, View3D *v3d, uint *r_objects_len, bool unique)
-{
- Object *ob_active = OBACT(view_layer);
- Object *ob_pose = BKE_object_pose_armature_get(ob_active);
- Object **objects = NULL;
- if (ob_pose == ob_active) {
- objects = BKE_view_layer_array_from_objects_in_mode(
- view_layer, v3d, r_objects_len, {
- .object_mode = OB_MODE_POSE,
- .no_dup_data = unique,
- });
- }
- else if (ob_pose != NULL) {
- *r_objects_len = 1;
- objects = MEM_mallocN(sizeof(*objects), __func__);
- objects[0] = ob_pose;
- }
- else {
- *r_objects_len = 0;
- objects = MEM_mallocN(0, __func__);
- }
- return objects;
+Object **BKE_object_pose_array_get_ex(ViewLayer *view_layer,
+ View3D *v3d,
+ uint *r_objects_len,
+ bool unique)
+{
+ Object *ob_active = OBACT(view_layer);
+ Object *ob_pose = BKE_object_pose_armature_get(ob_active);
+ Object **objects = NULL;
+ if (ob_pose == ob_active) {
+ objects = BKE_view_layer_array_from_objects_in_mode(view_layer,
+ v3d,
+ r_objects_len,
+ {
+ .object_mode = OB_MODE_POSE,
+ .no_dup_data = unique,
+ });
+ }
+ else if (ob_pose != NULL) {
+ *r_objects_len = 1;
+ objects = MEM_mallocN(sizeof(*objects), __func__);
+ objects[0] = ob_pose;
+ }
+ else {
+ *r_objects_len = 0;
+ objects = MEM_mallocN(0, __func__);
+ }
+ return objects;
}
Object **BKE_object_pose_array_get_unique(ViewLayer *view_layer, View3D *v3d, uint *r_objects_len)
{
- return BKE_object_pose_array_get_ex(view_layer, v3d, r_objects_len, true);
+ return BKE_object_pose_array_get_ex(view_layer, v3d, r_objects_len, true);
}
Object **BKE_object_pose_array_get(ViewLayer *view_layer, View3D *v3d, uint *r_objects_len)
{
- return BKE_object_pose_array_get_ex(view_layer, v3d, r_objects_len, false);
-}
-
-Base **BKE_object_pose_base_array_get_ex(ViewLayer *view_layer, View3D *v3d, uint *r_bases_len, bool unique)
-{
- Base *base_active = BASACT(view_layer);
- Object *ob_pose = base_active ? BKE_object_pose_armature_get(base_active->object) : NULL;
- Base *base_pose = NULL;
- Base **bases = NULL;
-
- if (base_active) {
- if (ob_pose == base_active->object) {
- base_pose = base_active;
- }
- else {
- base_pose = BKE_view_layer_base_find(view_layer, ob_pose);
- }
- }
-
- if (base_active && (base_pose == base_active)) {
- bases = BKE_view_layer_array_from_bases_in_mode(
- view_layer, v3d, r_bases_len, {
- .object_mode = OB_MODE_POSE,
- .no_dup_data = unique,
- });
- }
- else if (base_pose != NULL) {
- *r_bases_len = 1;
- bases = MEM_mallocN(sizeof(*bases), __func__);
- bases[0] = base_pose;
- }
- else {
- *r_bases_len = 0;
- bases = MEM_mallocN(0, __func__);
- }
- return bases;
+ return BKE_object_pose_array_get_ex(view_layer, v3d, r_objects_len, false);
+}
+
+Base **BKE_object_pose_base_array_get_ex(ViewLayer *view_layer,
+ View3D *v3d,
+ uint *r_bases_len,
+ bool unique)
+{
+ Base *base_active = BASACT(view_layer);
+ Object *ob_pose = base_active ? BKE_object_pose_armature_get(base_active->object) : NULL;
+ Base *base_pose = NULL;
+ Base **bases = NULL;
+
+ if (base_active) {
+ if (ob_pose == base_active->object) {
+ base_pose = base_active;
+ }
+ else {
+ base_pose = BKE_view_layer_base_find(view_layer, ob_pose);
+ }
+ }
+
+ if (base_active && (base_pose == base_active)) {
+ bases = BKE_view_layer_array_from_bases_in_mode(view_layer,
+ v3d,
+ r_bases_len,
+ {
+ .object_mode = OB_MODE_POSE,
+ .no_dup_data = unique,
+ });
+ }
+ else if (base_pose != NULL) {
+ *r_bases_len = 1;
+ bases = MEM_mallocN(sizeof(*bases), __func__);
+ bases[0] = base_pose;
+ }
+ else {
+ *r_bases_len = 0;
+ bases = MEM_mallocN(0, __func__);
+ }
+ return bases;
}
Base **BKE_object_pose_base_array_get_unique(ViewLayer *view_layer, View3D *v3d, uint *r_bases_len)
{
- return BKE_object_pose_base_array_get_ex(view_layer, v3d, r_bases_len, true);
+ return BKE_object_pose_base_array_get_ex(view_layer, v3d, r_bases_len, true);
}
Base **BKE_object_pose_base_array_get(ViewLayer *view_layer, View3D *v3d, uint *r_bases_len)
{
- return BKE_object_pose_base_array_get_ex(view_layer, v3d, r_bases_len, false);
+ return BKE_object_pose_base_array_get_ex(view_layer, v3d, r_bases_len, false);
}
void BKE_object_transform_copy(Object *ob_tar, const Object *ob_src)
{
- copy_v3_v3(ob_tar->loc, ob_src->loc);
- copy_v3_v3(ob_tar->rot, ob_src->rot);
- copy_v3_v3(ob_tar->quat, ob_src->quat);
- copy_v3_v3(ob_tar->rotAxis, ob_src->rotAxis);
- ob_tar->rotAngle = ob_src->rotAngle;
- ob_tar->rotmode = ob_src->rotmode;
- copy_v3_v3(ob_tar->scale, ob_src->scale);
+ copy_v3_v3(ob_tar->loc, ob_src->loc);
+ copy_v3_v3(ob_tar->rot, ob_src->rot);
+ copy_v3_v3(ob_tar->quat, ob_src->quat);
+ copy_v3_v3(ob_tar->rotAxis, ob_src->rotAxis);
+ ob_tar->rotAngle = ob_src->rotAngle;
+ ob_tar->rotmode = ob_src->rotmode;
+ copy_v3_v3(ob_tar->scale, ob_src->scale);
}
/**
@@ -1315,116 +1328,118 @@ void BKE_object_transform_copy(Object *ob_tar, const Object *ob_src)
*/
void BKE_object_copy_data(Main *bmain, Object *ob_dst, const Object *ob_src, const int flag)
{
- ModifierData *md;
- GpencilModifierData *gmd;
- ShaderFxData *fx;
-
- /* Do not copy runtime data. */
- BKE_object_runtime_reset_on_copy(ob_dst, flag);
-
- /* We never handle usercount here for own data. */
- const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
-
- if (ob_src->totcol) {
- ob_dst->mat = MEM_dupallocN(ob_src->mat);
- ob_dst->matbits = MEM_dupallocN(ob_src->matbits);
- ob_dst->totcol = ob_src->totcol;
- }
- else if (ob_dst->mat != NULL || ob_dst->matbits != NULL) {
- /* This shall not be needed, but better be safe than sorry. */
- BLI_assert(!"Object copy: non-NULL material pointers with zero counter, should not happen.");
- ob_dst->mat = NULL;
- ob_dst->matbits = NULL;
- }
-
- if (ob_src->iuser) ob_dst->iuser = MEM_dupallocN(ob_src->iuser);
-
- if (ob_src->runtime.bb) ob_dst->runtime.bb = MEM_dupallocN(ob_src->runtime.bb);
-
- BLI_listbase_clear(&ob_dst->modifiers);
-
- for (md = ob_src->modifiers.first; md; md = md->next) {
- ModifierData *nmd = modifier_new(md->type);
- BLI_strncpy(nmd->name, md->name, sizeof(nmd->name));
- modifier_copyData_ex(md, nmd, flag_subdata);
- BLI_addtail(&ob_dst->modifiers, nmd);
- }
-
- BLI_listbase_clear(&ob_dst->greasepencil_modifiers);
-
- for (gmd = ob_src->greasepencil_modifiers.first; gmd; gmd = gmd->next) {
- GpencilModifierData *nmd = BKE_gpencil_modifier_new(gmd->type);
- BLI_strncpy(nmd->name, gmd->name, sizeof(nmd->name));
- BKE_gpencil_modifier_copyData_ex(gmd, nmd, flag_subdata);
- BLI_addtail(&ob_dst->greasepencil_modifiers, nmd);
- }
-
- BLI_listbase_clear(&ob_dst->shader_fx);
-
- for (fx = ob_src->shader_fx.first; fx; fx = fx->next) {
- ShaderFxData *nfx = BKE_shaderfx_new(fx->type);
- BLI_strncpy(nfx->name, fx->name, sizeof(nfx->name));
- BKE_shaderfx_copyData_ex(fx, nfx, flag_subdata);
- BLI_addtail(&ob_dst->shader_fx, nfx);
- }
-
- if (ob_src->pose) {
- copy_object_pose(ob_dst, ob_src, flag_subdata);
- /* backwards compat... non-armatures can get poses in older files? */
- if (ob_src->type == OB_ARMATURE) {
- const bool do_pose_id_user = (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0;
- BKE_pose_rebuild(bmain, ob_dst, ob_dst->data, do_pose_id_user);
- }
- }
- defgroup_copy_list(&ob_dst->defbase, &ob_src->defbase);
- BKE_object_facemap_copy_list(&ob_dst->fmaps, &ob_src->fmaps);
- BKE_constraints_copy_ex(&ob_dst->constraints, &ob_src->constraints, flag_subdata, true);
-
- ob_dst->mode = ob_dst->type != OB_GPENCIL ? OB_MODE_OBJECT : ob_dst->mode;
- ob_dst->sculpt = NULL;
-
- if (ob_src->pd) {
- ob_dst->pd = MEM_dupallocN(ob_src->pd);
- if (ob_dst->pd->rng) {
- ob_dst->pd->rng = MEM_dupallocN(ob_src->pd->rng);
- }
- }
- BKE_object_copy_softbody(ob_dst, ob_src, flag_subdata);
- ob_dst->rigidbody_object = BKE_rigidbody_copy_object(ob_src, flag_subdata);
- ob_dst->rigidbody_constraint = BKE_rigidbody_copy_constraint(ob_src, flag_subdata);
-
- BKE_object_copy_particlesystems(ob_dst, ob_src, flag_subdata);
-
- ob_dst->derivedDeform = NULL;
- ob_dst->derivedFinal = NULL;
-
- BLI_listbase_clear((ListBase *)&ob_dst->drawdata);
- BLI_listbase_clear(&ob_dst->pc_ids);
-
- ob_dst->avs = ob_src->avs;
- ob_dst->mpath = animviz_copy_motionpath(ob_src->mpath);
-
- copy_object_lod(ob_dst, ob_src, flag_subdata);
-
- /* Do not copy object's preview (mostly due to the fact renderers create temp copy of objects). */
- if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) { /* XXX TODO temp hack */
- BKE_previewimg_id_copy(&ob_dst->id, &ob_src->id);
- }
- else {
- ob_dst->preview = NULL;
- }
+ ModifierData *md;
+ GpencilModifierData *gmd;
+ ShaderFxData *fx;
+
+ /* Do not copy runtime data. */
+ BKE_object_runtime_reset_on_copy(ob_dst, flag);
+
+ /* We never handle usercount here for own data. */
+ const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
+
+ if (ob_src->totcol) {
+ ob_dst->mat = MEM_dupallocN(ob_src->mat);
+ ob_dst->matbits = MEM_dupallocN(ob_src->matbits);
+ ob_dst->totcol = ob_src->totcol;
+ }
+ else if (ob_dst->mat != NULL || ob_dst->matbits != NULL) {
+ /* This shall not be needed, but better be safe than sorry. */
+ BLI_assert(!"Object copy: non-NULL material pointers with zero counter, should not happen.");
+ ob_dst->mat = NULL;
+ ob_dst->matbits = NULL;
+ }
+
+ if (ob_src->iuser)
+ ob_dst->iuser = MEM_dupallocN(ob_src->iuser);
+
+ if (ob_src->runtime.bb)
+ ob_dst->runtime.bb = MEM_dupallocN(ob_src->runtime.bb);
+
+ BLI_listbase_clear(&ob_dst->modifiers);
+
+ for (md = ob_src->modifiers.first; md; md = md->next) {
+ ModifierData *nmd = modifier_new(md->type);
+ BLI_strncpy(nmd->name, md->name, sizeof(nmd->name));
+ modifier_copyData_ex(md, nmd, flag_subdata);
+ BLI_addtail(&ob_dst->modifiers, nmd);
+ }
+
+ BLI_listbase_clear(&ob_dst->greasepencil_modifiers);
+
+ for (gmd = ob_src->greasepencil_modifiers.first; gmd; gmd = gmd->next) {
+ GpencilModifierData *nmd = BKE_gpencil_modifier_new(gmd->type);
+ BLI_strncpy(nmd->name, gmd->name, sizeof(nmd->name));
+ BKE_gpencil_modifier_copyData_ex(gmd, nmd, flag_subdata);
+ BLI_addtail(&ob_dst->greasepencil_modifiers, nmd);
+ }
+
+ BLI_listbase_clear(&ob_dst->shader_fx);
+
+ for (fx = ob_src->shader_fx.first; fx; fx = fx->next) {
+ ShaderFxData *nfx = BKE_shaderfx_new(fx->type);
+ BLI_strncpy(nfx->name, fx->name, sizeof(nfx->name));
+ BKE_shaderfx_copyData_ex(fx, nfx, flag_subdata);
+ BLI_addtail(&ob_dst->shader_fx, nfx);
+ }
+
+ if (ob_src->pose) {
+ copy_object_pose(ob_dst, ob_src, flag_subdata);
+ /* backwards compat... non-armatures can get poses in older files? */
+ if (ob_src->type == OB_ARMATURE) {
+ const bool do_pose_id_user = (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0;
+ BKE_pose_rebuild(bmain, ob_dst, ob_dst->data, do_pose_id_user);
+ }
+ }
+ defgroup_copy_list(&ob_dst->defbase, &ob_src->defbase);
+ BKE_object_facemap_copy_list(&ob_dst->fmaps, &ob_src->fmaps);
+ BKE_constraints_copy_ex(&ob_dst->constraints, &ob_src->constraints, flag_subdata, true);
+
+ ob_dst->mode = ob_dst->type != OB_GPENCIL ? OB_MODE_OBJECT : ob_dst->mode;
+ ob_dst->sculpt = NULL;
+
+ if (ob_src->pd) {
+ ob_dst->pd = MEM_dupallocN(ob_src->pd);
+ if (ob_dst->pd->rng) {
+ ob_dst->pd->rng = MEM_dupallocN(ob_src->pd->rng);
+ }
+ }
+ BKE_object_copy_softbody(ob_dst, ob_src, flag_subdata);
+ ob_dst->rigidbody_object = BKE_rigidbody_copy_object(ob_src, flag_subdata);
+ ob_dst->rigidbody_constraint = BKE_rigidbody_copy_constraint(ob_src, flag_subdata);
+
+ BKE_object_copy_particlesystems(ob_dst, ob_src, flag_subdata);
+
+ ob_dst->derivedDeform = NULL;
+ ob_dst->derivedFinal = NULL;
+
+ BLI_listbase_clear((ListBase *)&ob_dst->drawdata);
+ BLI_listbase_clear(&ob_dst->pc_ids);
+
+ ob_dst->avs = ob_src->avs;
+ ob_dst->mpath = animviz_copy_motionpath(ob_src->mpath);
+
+ copy_object_lod(ob_dst, ob_src, flag_subdata);
+
+ /* Do not copy object's preview (mostly due to the fact renderers create temp copy of objects). */
+ if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) { /* XXX TODO temp hack */
+ BKE_previewimg_id_copy(&ob_dst->id, &ob_src->id);
+ }
+ else {
+ ob_dst->preview = NULL;
+ }
}
/* copy objects, will re-initialize cached simulation data */
Object *BKE_object_copy(Main *bmain, const Object *ob)
{
- Object *ob_copy;
- BKE_id_copy(bmain, &ob->id, (ID **)&ob_copy);
+ Object *ob_copy;
+ BKE_id_copy(bmain, &ob->id, (ID **)&ob_copy);
- /* We increase object user count when linking to Collections. */
- id_us_min(&ob_copy->id);
+ /* We increase object user count when linking to Collections. */
+ id_us_min(&ob_copy->id);
- return ob_copy;
+ return ob_copy;
}
/** Perform deep-copy of object and its 'children' data-blocks (obdata, materials, actions, etc.).
@@ -1437,295 +1452,321 @@ Object *BKE_object_copy(Main *bmain, const Object *ob)
*/
Object *BKE_object_duplicate(Main *bmain, const Object *ob, const int dupflag)
{
- Material ***matarar;
- ID *id;
- int a, didit;
- Object *obn = BKE_object_copy(bmain, ob);
-
- /* 0 == full linked. */
- if (dupflag == 0) {
- return obn;
- }
-
-#define ID_NEW_REMAP_US(a) if ( (a)->id.newid) { (a) = (void *)(a)->id.newid; (a)->id.us++; }
-#define ID_NEW_REMAP_US2(a) if (((ID *)a)->newid) { (a) = ((ID *)a)->newid; ((ID *)a)->us++; }
-
- /* duplicates using userflags */
- if (dupflag & USER_DUP_ACT) {
- BKE_animdata_copy_id_action(bmain, &obn->id, true);
- }
-
- if (dupflag & USER_DUP_MAT) {
- for (a = 0; a < obn->totcol; a++) {
- id = (ID *)obn->mat[a];
- if (id) {
- ID_NEW_REMAP_US(obn->mat[a])
- else {
- obn->mat[a] = ID_NEW_SET(obn->mat[a], BKE_material_copy(bmain, obn->mat[a]));
- }
- id_us_min(id);
-
- if (dupflag & USER_DUP_ACT) {
- BKE_animdata_copy_id_action(bmain, &obn->mat[a]->id, true);
- }
- }
- }
- }
- if (dupflag & USER_DUP_PSYS) {
- ParticleSystem *psys;
- for (psys = obn->particlesystem.first; psys; psys = psys->next) {
- id = (ID *) psys->part;
- if (id) {
- ID_NEW_REMAP_US(psys->part)
- else {
- psys->part = ID_NEW_SET(psys->part, BKE_particlesettings_copy(bmain, psys->part));
- }
-
- if (dupflag & USER_DUP_ACT) {
- BKE_animdata_copy_id_action(bmain, &psys->part->id, true);
- }
-
- id_us_min(id);
- }
- }
- }
-
- id = obn->data;
- didit = 0;
-
- switch (obn->type) {
- case OB_MESH:
- if (dupflag & USER_DUP_MESH) {
- ID_NEW_REMAP_US2(obn->data)
- else {
- obn->data = ID_NEW_SET(obn->data, BKE_mesh_copy(bmain, obn->data));
- didit = 1;
- }
- id_us_min(id);
- }
- break;
- case OB_CURVE:
- if (dupflag & USER_DUP_CURVE) {
- ID_NEW_REMAP_US2(obn->data)
- else {
- obn->data = ID_NEW_SET(obn->data, BKE_curve_copy(bmain, obn->data));
- didit = 1;
- }
- id_us_min(id);
- }
- break;
- case OB_SURF:
- if (dupflag & USER_DUP_SURF) {
- ID_NEW_REMAP_US2(obn->data)
- else {
- obn->data = ID_NEW_SET(obn->data, BKE_curve_copy(bmain, obn->data));
- didit = 1;
- }
- id_us_min(id);
- }
- break;
- case OB_FONT:
- if (dupflag & USER_DUP_FONT) {
- ID_NEW_REMAP_US2(obn->data)
- else {
- obn->data = ID_NEW_SET(obn->data, BKE_curve_copy(bmain, obn->data));
- didit = 1;
- }
- id_us_min(id);
- }
- break;
- case OB_MBALL:
- if (dupflag & USER_DUP_MBALL) {
- ID_NEW_REMAP_US2(obn->data)
- else {
- obn->data = ID_NEW_SET(obn->data, BKE_mball_copy(bmain, obn->data));
- didit = 1;
- }
- id_us_min(id);
- }
- break;
- case OB_LAMP:
- if (dupflag & USER_DUP_LAMP) {
- ID_NEW_REMAP_US2(obn->data)
- else {
- obn->data = ID_NEW_SET(obn->data, BKE_light_copy(bmain, obn->data));
- didit = 1;
- }
- id_us_min(id);
- }
- break;
- case OB_ARMATURE:
- if (dupflag != 0) {
- DEG_id_tag_update(&obn->id, ID_RECALC_GEOMETRY);
- if (obn->pose)
- BKE_pose_tag_recalc(bmain, obn->pose);
- if (dupflag & USER_DUP_ARM) {
- ID_NEW_REMAP_US2(obn->data)
- else {
- obn->data = ID_NEW_SET(obn->data, BKE_armature_copy(bmain, obn->data));
- BKE_pose_rebuild(bmain, obn, obn->data, true);
- didit = 1;
- }
- id_us_min(id);
- }
- }
- break;
- case OB_LATTICE:
- if (dupflag != 0) {
- ID_NEW_REMAP_US2(obn->data)
- else {
- obn->data = ID_NEW_SET(obn->data, BKE_lattice_copy(bmain, obn->data));
- didit = 1;
- }
- id_us_min(id);
- }
- break;
- case OB_CAMERA:
- if (dupflag != 0) {
- ID_NEW_REMAP_US2(obn->data)
- else {
- obn->data = ID_NEW_SET(obn->data, BKE_camera_copy(bmain, obn->data));
- didit = 1;
- }
- id_us_min(id);
- }
- break;
- case OB_LIGHTPROBE:
- if (dupflag != 0) {
- ID_NEW_REMAP_US2(obn->data)
- else {
- obn->data = ID_NEW_SET(obn->data, BKE_lightprobe_copy(bmain, obn->data));
- didit = 1;
- }
- id_us_min(id);
- }
- break;
- case OB_SPEAKER:
- if (dupflag != 0) {
- ID_NEW_REMAP_US2(obn->data)
- else {
- obn->data = ID_NEW_SET(obn->data, BKE_speaker_copy(bmain, obn->data));
- didit = 1;
- }
- id_us_min(id);
- }
- break;
- case OB_GPENCIL:
- if (dupflag != 0) {
- ID_NEW_REMAP_US2(obn->data)
- else {
- obn->data = ID_NEW_SET(obn->data, BKE_gpencil_copy(bmain, obn->data));
- didit = 1;
- }
- id_us_min(id);
- }
- break;
- }
-
- /* Check if obdata is copied. */
- if (didit) {
- Key *key = BKE_key_from_object(obn);
-
- Key *oldkey = BKE_key_from_object(ob);
- if (oldkey != NULL) {
- ID_NEW_SET(oldkey, key);
- }
-
- if (dupflag & USER_DUP_ACT) {
- BKE_animdata_copy_id_action(bmain, (ID *)obn->data, true);
- if (key) {
- BKE_animdata_copy_id_action(bmain, (ID *)key, true);
- }
- }
-
- if (dupflag & USER_DUP_MAT) {
- matarar = give_matarar(obn);
- if (matarar) {
- for (a = 0; a < obn->totcol; a++) {
- id = (ID *)(*matarar)[a];
- if (id) {
- ID_NEW_REMAP_US((*matarar)[a])
- else {
- (*matarar)[a] = ID_NEW_SET((*matarar)[a], BKE_material_copy(bmain, (*matarar)[a]));
- }
- id_us_min(id);
- }
- }
- }
- }
- }
+ Material ***matarar;
+ ID *id;
+ int a, didit;
+ Object *obn = BKE_object_copy(bmain, ob);
+
+ /* 0 == full linked. */
+ if (dupflag == 0) {
+ return obn;
+ }
+
+#define ID_NEW_REMAP_US(a) \
+ if ((a)->id.newid) { \
+ (a) = (void *)(a)->id.newid; \
+ (a)->id.us++; \
+ }
+#define ID_NEW_REMAP_US2(a) \
+ if (((ID *)a)->newid) { \
+ (a) = ((ID *)a)->newid; \
+ ((ID *)a)->us++; \
+ }
+
+ /* duplicates using userflags */
+ if (dupflag & USER_DUP_ACT) {
+ BKE_animdata_copy_id_action(bmain, &obn->id, true);
+ }
+
+ if (dupflag & USER_DUP_MAT) {
+ for (a = 0; a < obn->totcol; a++) {
+ id = (ID *)obn->mat[a];
+ if (id) {
+ ID_NEW_REMAP_US(obn->mat[a])
+ else
+ {
+ obn->mat[a] = ID_NEW_SET(obn->mat[a], BKE_material_copy(bmain, obn->mat[a]));
+ }
+ id_us_min(id);
+
+ if (dupflag & USER_DUP_ACT) {
+ BKE_animdata_copy_id_action(bmain, &obn->mat[a]->id, true);
+ }
+ }
+ }
+ }
+ if (dupflag & USER_DUP_PSYS) {
+ ParticleSystem *psys;
+ for (psys = obn->particlesystem.first; psys; psys = psys->next) {
+ id = (ID *)psys->part;
+ if (id) {
+ ID_NEW_REMAP_US(psys->part)
+ else
+ {
+ psys->part = ID_NEW_SET(psys->part, BKE_particlesettings_copy(bmain, psys->part));
+ }
+
+ if (dupflag & USER_DUP_ACT) {
+ BKE_animdata_copy_id_action(bmain, &psys->part->id, true);
+ }
+
+ id_us_min(id);
+ }
+ }
+ }
+
+ id = obn->data;
+ didit = 0;
+
+ switch (obn->type) {
+ case OB_MESH:
+ if (dupflag & USER_DUP_MESH) {
+ ID_NEW_REMAP_US2(obn->data)
+ else
+ {
+ obn->data = ID_NEW_SET(obn->data, BKE_mesh_copy(bmain, obn->data));
+ didit = 1;
+ }
+ id_us_min(id);
+ }
+ break;
+ case OB_CURVE:
+ if (dupflag & USER_DUP_CURVE) {
+ ID_NEW_REMAP_US2(obn->data)
+ else
+ {
+ obn->data = ID_NEW_SET(obn->data, BKE_curve_copy(bmain, obn->data));
+ didit = 1;
+ }
+ id_us_min(id);
+ }
+ break;
+ case OB_SURF:
+ if (dupflag & USER_DUP_SURF) {
+ ID_NEW_REMAP_US2(obn->data)
+ else
+ {
+ obn->data = ID_NEW_SET(obn->data, BKE_curve_copy(bmain, obn->data));
+ didit = 1;
+ }
+ id_us_min(id);
+ }
+ break;
+ case OB_FONT:
+ if (dupflag & USER_DUP_FONT) {
+ ID_NEW_REMAP_US2(obn->data)
+ else
+ {
+ obn->data = ID_NEW_SET(obn->data, BKE_curve_copy(bmain, obn->data));
+ didit = 1;
+ }
+ id_us_min(id);
+ }
+ break;
+ case OB_MBALL:
+ if (dupflag & USER_DUP_MBALL) {
+ ID_NEW_REMAP_US2(obn->data)
+ else
+ {
+ obn->data = ID_NEW_SET(obn->data, BKE_mball_copy(bmain, obn->data));
+ didit = 1;
+ }
+ id_us_min(id);
+ }
+ break;
+ case OB_LAMP:
+ if (dupflag & USER_DUP_LAMP) {
+ ID_NEW_REMAP_US2(obn->data)
+ else
+ {
+ obn->data = ID_NEW_SET(obn->data, BKE_light_copy(bmain, obn->data));
+ didit = 1;
+ }
+ id_us_min(id);
+ }
+ break;
+ case OB_ARMATURE:
+ if (dupflag != 0) {
+ DEG_id_tag_update(&obn->id, ID_RECALC_GEOMETRY);
+ if (obn->pose)
+ BKE_pose_tag_recalc(bmain, obn->pose);
+ if (dupflag & USER_DUP_ARM) {
+ ID_NEW_REMAP_US2(obn->data)
+ else
+ {
+ obn->data = ID_NEW_SET(obn->data, BKE_armature_copy(bmain, obn->data));
+ BKE_pose_rebuild(bmain, obn, obn->data, true);
+ didit = 1;
+ }
+ id_us_min(id);
+ }
+ }
+ break;
+ case OB_LATTICE:
+ if (dupflag != 0) {
+ ID_NEW_REMAP_US2(obn->data)
+ else
+ {
+ obn->data = ID_NEW_SET(obn->data, BKE_lattice_copy(bmain, obn->data));
+ didit = 1;
+ }
+ id_us_min(id);
+ }
+ break;
+ case OB_CAMERA:
+ if (dupflag != 0) {
+ ID_NEW_REMAP_US2(obn->data)
+ else
+ {
+ obn->data = ID_NEW_SET(obn->data, BKE_camera_copy(bmain, obn->data));
+ didit = 1;
+ }
+ id_us_min(id);
+ }
+ break;
+ case OB_LIGHTPROBE:
+ if (dupflag != 0) {
+ ID_NEW_REMAP_US2(obn->data)
+ else
+ {
+ obn->data = ID_NEW_SET(obn->data, BKE_lightprobe_copy(bmain, obn->data));
+ didit = 1;
+ }
+ id_us_min(id);
+ }
+ break;
+ case OB_SPEAKER:
+ if (dupflag != 0) {
+ ID_NEW_REMAP_US2(obn->data)
+ else
+ {
+ obn->data = ID_NEW_SET(obn->data, BKE_speaker_copy(bmain, obn->data));
+ didit = 1;
+ }
+ id_us_min(id);
+ }
+ break;
+ case OB_GPENCIL:
+ if (dupflag != 0) {
+ ID_NEW_REMAP_US2(obn->data)
+ else
+ {
+ obn->data = ID_NEW_SET(obn->data, BKE_gpencil_copy(bmain, obn->data));
+ didit = 1;
+ }
+ id_us_min(id);
+ }
+ break;
+ }
+
+ /* Check if obdata is copied. */
+ if (didit) {
+ Key *key = BKE_key_from_object(obn);
+
+ Key *oldkey = BKE_key_from_object(ob);
+ if (oldkey != NULL) {
+ ID_NEW_SET(oldkey, key);
+ }
+
+ if (dupflag & USER_DUP_ACT) {
+ BKE_animdata_copy_id_action(bmain, (ID *)obn->data, true);
+ if (key) {
+ BKE_animdata_copy_id_action(bmain, (ID *)key, true);
+ }
+ }
+
+ if (dupflag & USER_DUP_MAT) {
+ matarar = give_matarar(obn);
+ if (matarar) {
+ for (a = 0; a < obn->totcol; a++) {
+ id = (ID *)(*matarar)[a];
+ if (id) {
+ ID_NEW_REMAP_US((*matarar)[a])
+ else
+ {
+ (*matarar)[a] = ID_NEW_SET((*matarar)[a], BKE_material_copy(bmain, (*matarar)[a]));
+ }
+ id_us_min(id);
+ }
+ }
+ }
+ }
+ }
#undef ID_NEW_REMAP_US
#undef ID_NEW_REMAP_US2
- if (ob->data != NULL) {
- DEG_id_tag_update_ex(bmain, (ID *)obn->data, ID_RECALC_EDITORS);
- }
+ if (ob->data != NULL) {
+ DEG_id_tag_update_ex(bmain, (ID *)obn->data, ID_RECALC_EDITORS);
+ }
- return obn;
+ return obn;
}
-void BKE_object_make_local_ex(Main *bmain, Object *ob, const bool lib_local, const bool clear_proxy)
+void BKE_object_make_local_ex(Main *bmain,
+ Object *ob,
+ const bool lib_local,
+ const bool clear_proxy)
{
- bool is_local = false, is_lib = false;
+ bool is_local = false, is_lib = false;
- /* - only lib users: do nothing (unless force_local is set)
- * - only local users: set flag
- * - mixed: make copy
- * In case we make a whole lib's content local, we always want to localize, and we skip remapping (done later).
- */
+ /* - only lib users: do nothing (unless force_local is set)
+ * - only local users: set flag
+ * - mixed: make copy
+ * In case we make a whole lib's content local, we always want to localize, and we skip remapping (done later).
+ */
- if (!ID_IS_LINKED(ob)) {
- return;
- }
+ if (!ID_IS_LINKED(ob)) {
+ return;
+ }
- BKE_library_ID_test_usages(bmain, ob, &is_local, &is_lib);
+ BKE_library_ID_test_usages(bmain, ob, &is_local, &is_lib);
- if (lib_local || is_local) {
- if (!is_lib) {
- id_clear_lib_data(bmain, &ob->id);
- BKE_id_expand_local(bmain, &ob->id);
- if (clear_proxy) {
- if (ob->proxy_from != NULL) {
- ob->proxy_from->proxy = NULL;
- ob->proxy_from->proxy_group = NULL;
- }
- ob->proxy = ob->proxy_from = ob->proxy_group = NULL;
- }
- }
- else {
- Object *ob_new = BKE_object_copy(bmain, ob);
+ if (lib_local || is_local) {
+ if (!is_lib) {
+ id_clear_lib_data(bmain, &ob->id);
+ BKE_id_expand_local(bmain, &ob->id);
+ if (clear_proxy) {
+ if (ob->proxy_from != NULL) {
+ ob->proxy_from->proxy = NULL;
+ ob->proxy_from->proxy_group = NULL;
+ }
+ ob->proxy = ob->proxy_from = ob->proxy_group = NULL;
+ }
+ }
+ else {
+ Object *ob_new = BKE_object_copy(bmain, ob);
- ob_new->id.us = 0;
- ob_new->proxy = ob_new->proxy_from = ob_new->proxy_group = NULL;
+ ob_new->id.us = 0;
+ ob_new->proxy = ob_new->proxy_from = ob_new->proxy_group = NULL;
- /* setting newid is mandatory for complex make_lib_local logic... */
- ID_NEW_SET(ob, ob_new);
+ /* setting newid is mandatory for complex make_lib_local logic... */
+ ID_NEW_SET(ob, ob_new);
- if (!lib_local) {
- BKE_libblock_remap(bmain, ob, ob_new, ID_REMAP_SKIP_INDIRECT_USAGE);
- }
- }
- }
+ if (!lib_local) {
+ BKE_libblock_remap(bmain, ob, ob_new, ID_REMAP_SKIP_INDIRECT_USAGE);
+ }
+ }
+ }
}
void BKE_object_make_local(Main *bmain, Object *ob, const bool lib_local)
{
- BKE_object_make_local_ex(bmain, ob, lib_local, true);
+ BKE_object_make_local_ex(bmain, ob, lib_local, true);
}
/* Returns true if the Object is from an external blend file (libdata) */
bool BKE_object_is_libdata(const Object *ob)
{
- return (ob && ID_IS_LINKED(ob));
+ return (ob && ID_IS_LINKED(ob));
}
/* Returns true if the Object data is from an external blend file (libdata) */
bool BKE_object_obdata_is_libdata(const Object *ob)
{
- /* Linked objects with local obdata are forbidden! */
- BLI_assert(!ob || !ob->data || (ID_IS_LINKED(ob) ? ID_IS_LINKED(ob->data) : true));
- return (ob && ob->data && ID_IS_LINKED(ob->data));
+ /* Linked objects with local obdata are forbidden! */
+ BLI_assert(!ob || !ob->data || (ID_IS_LINKED(ob) ? ID_IS_LINKED(ob->data) : true));
+ return (ob && ob->data && ID_IS_LINKED(ob->data));
}
/* *************** PROXY **************** */
@@ -1733,54 +1774,52 @@ bool BKE_object_obdata_is_libdata(const Object *ob)
/* when you make proxy, ensure the exposed layers are extern */
static void armature_set_id_extern(Object *ob)
{
- bArmature *arm = ob->data;
- bPoseChannel *pchan;
- unsigned int lay = arm->layer_protected;
-
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (!(pchan->bone->layer & lay))
- id_lib_extern((ID *)pchan->custom);
- }
+ bArmature *arm = ob->data;
+ bPoseChannel *pchan;
+ unsigned int lay = arm->layer_protected;
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (!(pchan->bone->layer & lay))
+ id_lib_extern((ID *)pchan->custom);
+ }
}
void BKE_object_copy_proxy_drivers(Object *ob, Object *target)
{
- if ((target->adt) && (target->adt->drivers.first)) {
- FCurve *fcu;
-
- /* add new animdata block */
- if (!ob->adt)
- ob->adt = BKE_animdata_add_id(&ob->id);
-
- /* make a copy of all the drivers (for now), then correct any links that need fixing */
- free_fcurves(&ob->adt->drivers);
- copy_fcurves(&ob->adt->drivers, &target->adt->drivers);
-
- for (fcu = ob->adt->drivers.first; fcu; fcu = fcu->next) {
- ChannelDriver *driver = fcu->driver;
- DriverVar *dvar;
-
- for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
- /* all drivers */
- DRIVER_TARGETS_LOOPER_BEGIN(dvar)
- {
- if (dtar->id) {
- if ((Object *)dtar->id == target)
- dtar->id = (ID *)ob;
- else {
- /* only on local objects because this causes indirect links
- * 'a -> b -> c', blend to point directly to a.blend
- * when a.blend has a proxy thats linked into c.blend */
- if (!ID_IS_LINKED(ob))
- id_lib_extern((ID *)dtar->id);
- }
- }
- }
- DRIVER_TARGETS_LOOPER_END;
- }
- }
- }
+ if ((target->adt) && (target->adt->drivers.first)) {
+ FCurve *fcu;
+
+ /* add new animdata block */
+ if (!ob->adt)
+ ob->adt = BKE_animdata_add_id(&ob->id);
+
+ /* make a copy of all the drivers (for now), then correct any links that need fixing */
+ free_fcurves(&ob->adt->drivers);
+ copy_fcurves(&ob->adt->drivers, &target->adt->drivers);
+
+ for (fcu = ob->adt->drivers.first; fcu; fcu = fcu->next) {
+ ChannelDriver *driver = fcu->driver;
+ DriverVar *dvar;
+
+ for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
+ /* all drivers */
+ DRIVER_TARGETS_LOOPER_BEGIN (dvar) {
+ if (dtar->id) {
+ if ((Object *)dtar->id == target)
+ dtar->id = (ID *)ob;
+ else {
+ /* only on local objects because this causes indirect links
+ * 'a -> b -> c', blend to point directly to a.blend
+ * when a.blend has a proxy thats linked into c.blend */
+ if (!ID_IS_LINKED(ob))
+ id_lib_extern((ID *)dtar->id);
+ }
+ }
+ }
+ DRIVER_TARGETS_LOOPER_END;
+ }
+ }
+ }
}
/* proxy rule: lib_object->proxy_from == the one we borrow from, set temporally while object_update */
@@ -1789,101 +1828,103 @@ void BKE_object_copy_proxy_drivers(Object *ob, Object *target)
void BKE_object_make_proxy(Main *bmain, Object *ob, Object *target, Object *cob)
{
- /* paranoia checks */
- if (ID_IS_LINKED(ob) || !ID_IS_LINKED(target)) {
- CLOG_ERROR(&LOG, "cannot make proxy");
- return;
- }
-
- ob->proxy = target;
- ob->proxy_group = cob;
- id_lib_extern(&target->id);
-
- DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
- DEG_id_tag_update(&target->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
-
- /* copy transform
- * - cob means this proxy comes from a collection, just apply the matrix
- * so the object wont move from its dupli-transform.
- *
- * - no cob means this is being made from a linked object,
- * this is closer to making a copy of the object - in-place. */
- if (cob) {
- ob->rotmode = target->rotmode;
- mul_m4_m4m4(ob->obmat, cob->obmat, target->obmat);
- if (cob->instance_collection) { /* should always be true */
- float tvec[3];
- mul_v3_mat3_m4v3(tvec, ob->obmat, cob->instance_collection->instance_offset);
- sub_v3_v3(ob->obmat[3], tvec);
- }
- BKE_object_apply_mat4(ob, ob->obmat, false, true);
- }
- else {
- BKE_object_transform_copy(ob, target);
- ob->parent = target->parent; /* libdata */
- copy_m4_m4(ob->parentinv, target->parentinv);
- }
-
- /* copy animdata stuff - drivers only for now... */
- BKE_object_copy_proxy_drivers(ob, target);
-
- /* skip constraints? */
- /* FIXME: this is considered by many as a bug */
-
- /* set object type and link to data */
- ob->type = target->type;
- ob->data = target->data;
- id_us_plus((ID *)ob->data); /* ensures lib data becomes LIB_TAG_EXTERN */
-
- /* copy vertex groups */
- defgroup_copy_list(&ob->defbase, &target->defbase);
-
- /* copy material and index information */
- ob->actcol = ob->totcol = 0;
- if (ob->mat) MEM_freeN(ob->mat);
- if (ob->matbits) MEM_freeN(ob->matbits);
- ob->mat = NULL;
- ob->matbits = NULL;
- if ((target->totcol) && (target->mat) && OB_TYPE_SUPPORT_MATERIAL(ob->type)) {
- int i;
-
- ob->actcol = target->actcol;
- ob->totcol = target->totcol;
-
- ob->mat = MEM_dupallocN(target->mat);
- ob->matbits = MEM_dupallocN(target->matbits);
- for (i = 0; i < target->totcol; i++) {
- /* don't need to run test_object_materials
- * since we know this object is new and not used elsewhere */
- id_us_plus((ID *)ob->mat[i]);
- }
- }
-
- /* type conversions */
- if (target->type == OB_ARMATURE) {
- copy_object_pose(ob, target, 0); /* data copy, object pointers in constraints */
- BKE_pose_rest(ob->pose); /* clear all transforms in channels */
- BKE_pose_rebuild(bmain, ob, ob->data, true); /* set all internal links */
-
- armature_set_id_extern(ob);
- }
- else if (target->type == OB_EMPTY) {
- ob->empty_drawtype = target->empty_drawtype;
- ob->empty_drawsize = target->empty_drawsize;
- }
-
- /* copy IDProperties */
- if (ob->id.properties) {
- IDP_FreeProperty(ob->id.properties);
- MEM_freeN(ob->id.properties);
- ob->id.properties = NULL;
- }
- if (target->id.properties) {
- ob->id.properties = IDP_CopyProperty(target->id.properties);
- }
-
- /* copy drawtype info */
- ob->dt = target->dt;
+ /* paranoia checks */
+ if (ID_IS_LINKED(ob) || !ID_IS_LINKED(target)) {
+ CLOG_ERROR(&LOG, "cannot make proxy");
+ return;
+ }
+
+ ob->proxy = target;
+ ob->proxy_group = cob;
+ id_lib_extern(&target->id);
+
+ DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
+ DEG_id_tag_update(&target->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
+
+ /* copy transform
+ * - cob means this proxy comes from a collection, just apply the matrix
+ * so the object wont move from its dupli-transform.
+ *
+ * - no cob means this is being made from a linked object,
+ * this is closer to making a copy of the object - in-place. */
+ if (cob) {
+ ob->rotmode = target->rotmode;
+ mul_m4_m4m4(ob->obmat, cob->obmat, target->obmat);
+ if (cob->instance_collection) { /* should always be true */
+ float tvec[3];
+ mul_v3_mat3_m4v3(tvec, ob->obmat, cob->instance_collection->instance_offset);
+ sub_v3_v3(ob->obmat[3], tvec);
+ }
+ BKE_object_apply_mat4(ob, ob->obmat, false, true);
+ }
+ else {
+ BKE_object_transform_copy(ob, target);
+ ob->parent = target->parent; /* libdata */
+ copy_m4_m4(ob->parentinv, target->parentinv);
+ }
+
+ /* copy animdata stuff - drivers only for now... */
+ BKE_object_copy_proxy_drivers(ob, target);
+
+ /* skip constraints? */
+ /* FIXME: this is considered by many as a bug */
+
+ /* set object type and link to data */
+ ob->type = target->type;
+ ob->data = target->data;
+ id_us_plus((ID *)ob->data); /* ensures lib data becomes LIB_TAG_EXTERN */
+
+ /* copy vertex groups */
+ defgroup_copy_list(&ob->defbase, &target->defbase);
+
+ /* copy material and index information */
+ ob->actcol = ob->totcol = 0;
+ if (ob->mat)
+ MEM_freeN(ob->mat);
+ if (ob->matbits)
+ MEM_freeN(ob->matbits);
+ ob->mat = NULL;
+ ob->matbits = NULL;
+ if ((target->totcol) && (target->mat) && OB_TYPE_SUPPORT_MATERIAL(ob->type)) {
+ int i;
+
+ ob->actcol = target->actcol;
+ ob->totcol = target->totcol;
+
+ ob->mat = MEM_dupallocN(target->mat);
+ ob->matbits = MEM_dupallocN(target->matbits);
+ for (i = 0; i < target->totcol; i++) {
+ /* don't need to run test_object_materials
+ * since we know this object is new and not used elsewhere */
+ id_us_plus((ID *)ob->mat[i]);
+ }
+ }
+
+ /* type conversions */
+ if (target->type == OB_ARMATURE) {
+ copy_object_pose(ob, target, 0); /* data copy, object pointers in constraints */
+ BKE_pose_rest(ob->pose); /* clear all transforms in channels */
+ BKE_pose_rebuild(bmain, ob, ob->data, true); /* set all internal links */
+
+ armature_set_id_extern(ob);
+ }
+ else if (target->type == OB_EMPTY) {
+ ob->empty_drawtype = target->empty_drawtype;
+ ob->empty_drawsize = target->empty_drawsize;
+ }
+
+ /* copy IDProperties */
+ if (ob->id.properties) {
+ IDP_FreeProperty(ob->id.properties);
+ MEM_freeN(ob->id.properties);
+ ob->id.properties = NULL;
+ }
+ if (target->id.properties) {
+ ob->id.properties = IDP_CopyProperty(target->id.properties);
+ }
+
+ /* copy drawtype info */
+ ob->dt = target->dt;
}
/**
@@ -1892,205 +1933,198 @@ void BKE_object_make_proxy(Main *bmain, Object *ob, Object *target, Object *cob)
*/
void BKE_object_obdata_size_init(struct Object *ob, const float size)
{
- /* apply radius as a scale to types that support it */
- switch (ob->type) {
- case OB_EMPTY:
- {
- ob->empty_drawsize *= size;
- break;
- }
- case OB_FONT:
- {
- Curve *cu = ob->data;
- cu->fsize *= size;
- break;
- }
- case OB_CAMERA:
- {
- Camera *cam = ob->data;
- cam->drawsize *= size;
- break;
- }
- case OB_LAMP:
- {
- Light *lamp = ob->data;
- lamp->dist *= size;
- lamp->area_size *= size;
- lamp->area_sizey *= size;
- lamp->area_sizez *= size;
- break;
- }
- /* Only lattice (not mesh, curve, mball...),
- * because its got data when newly added */
- case OB_LATTICE:
- {
- struct Lattice *lt = ob->data;
- float mat[4][4];
-
- unit_m4(mat);
- scale_m4_fl(mat, size);
-
- BKE_lattice_transform(lt, (float (*)[4])mat, false);
- break;
- }
- }
+ /* apply radius as a scale to types that support it */
+ switch (ob->type) {
+ case OB_EMPTY: {
+ ob->empty_drawsize *= size;
+ break;
+ }
+ case OB_FONT: {
+ Curve *cu = ob->data;
+ cu->fsize *= size;
+ break;
+ }
+ case OB_CAMERA: {
+ Camera *cam = ob->data;
+ cam->drawsize *= size;
+ break;
+ }
+ case OB_LAMP: {
+ Light *lamp = ob->data;
+ lamp->dist *= size;
+ lamp->area_size *= size;
+ lamp->area_sizey *= size;
+ lamp->area_sizez *= size;
+ break;
+ }
+ /* Only lattice (not mesh, curve, mball...),
+ * because its got data when newly added */
+ case OB_LATTICE: {
+ struct Lattice *lt = ob->data;
+ float mat[4][4];
+
+ unit_m4(mat);
+ scale_m4_fl(mat, size);
+
+ BKE_lattice_transform(lt, (float(*)[4])mat, false);
+ break;
+ }
+ }
}
/* *************** CALC ****************** */
void BKE_object_scale_to_mat3(Object *ob, float mat[3][3])
{
- float vec[3];
- mul_v3_v3v3(vec, ob->scale, ob->dscale);
- size_to_mat3(mat, vec);
+ float vec[3];
+ mul_v3_v3v3(vec, ob->scale, ob->dscale);
+ size_to_mat3(mat, vec);
}
void BKE_object_rot_to_mat3(Object *ob, float mat[3][3], bool use_drot)
{
- float rmat[3][3], dmat[3][3];
-
- /* 'dmat' is the delta-rotation matrix, which will get (pre)multiplied
- * with the rotation matrix to yield the appropriate rotation
- */
-
- /* rotations may either be quats, eulers (with various rotation orders), or axis-angle */
- if (ob->rotmode > 0) {
- /* euler rotations (will cause gimble lock, but this can be alleviated a bit with rotation orders) */
- eulO_to_mat3(rmat, ob->rot, ob->rotmode);
- eulO_to_mat3(dmat, ob->drot, ob->rotmode);
- }
- else if (ob->rotmode == ROT_MODE_AXISANGLE) {
- /* axis-angle - not really that great for 3D-changing orientations */
- axis_angle_to_mat3(rmat, ob->rotAxis, ob->rotAngle);
- axis_angle_to_mat3(dmat, ob->drotAxis, ob->drotAngle);
- }
- else {
- /* quats are normalized before use to eliminate scaling issues */
- float tquat[4];
-
- normalize_qt_qt(tquat, ob->quat);
- quat_to_mat3(rmat, tquat);
-
- normalize_qt_qt(tquat, ob->dquat);
- quat_to_mat3(dmat, tquat);
- }
-
- /* combine these rotations */
- if (use_drot)
- mul_m3_m3m3(mat, dmat, rmat);
- else
- copy_m3_m3(mat, rmat);
+ float rmat[3][3], dmat[3][3];
+
+ /* 'dmat' is the delta-rotation matrix, which will get (pre)multiplied
+ * with the rotation matrix to yield the appropriate rotation
+ */
+
+ /* rotations may either be quats, eulers (with various rotation orders), or axis-angle */
+ if (ob->rotmode > 0) {
+ /* euler rotations (will cause gimble lock, but this can be alleviated a bit with rotation orders) */
+ eulO_to_mat3(rmat, ob->rot, ob->rotmode);
+ eulO_to_mat3(dmat, ob->drot, ob->rotmode);
+ }
+ else if (ob->rotmode == ROT_MODE_AXISANGLE) {
+ /* axis-angle - not really that great for 3D-changing orientations */
+ axis_angle_to_mat3(rmat, ob->rotAxis, ob->rotAngle);
+ axis_angle_to_mat3(dmat, ob->drotAxis, ob->drotAngle);
+ }
+ else {
+ /* quats are normalized before use to eliminate scaling issues */
+ float tquat[4];
+
+ normalize_qt_qt(tquat, ob->quat);
+ quat_to_mat3(rmat, tquat);
+
+ normalize_qt_qt(tquat, ob->dquat);
+ quat_to_mat3(dmat, tquat);
+ }
+
+ /* combine these rotations */
+ if (use_drot)
+ mul_m3_m3m3(mat, dmat, rmat);
+ else
+ copy_m3_m3(mat, rmat);
}
void BKE_object_mat3_to_rot(Object *ob, float mat[3][3], bool use_compat)
{
- BLI_ASSERT_UNIT_M3(mat);
-
- switch (ob->rotmode) {
- case ROT_MODE_QUAT:
- {
- float dquat[4];
- mat3_normalized_to_quat(ob->quat, mat);
- normalize_qt_qt(dquat, ob->dquat);
- invert_qt_normalized(dquat);
- mul_qt_qtqt(ob->quat, dquat, ob->quat);
- break;
- }
- case ROT_MODE_AXISANGLE:
- {
- float quat[4];
- float dquat[4];
-
- /* without drot we could apply 'mat' directly */
- mat3_normalized_to_quat(quat, mat);
- axis_angle_to_quat(dquat, ob->drotAxis, ob->drotAngle);
- invert_qt_normalized(dquat);
- mul_qt_qtqt(quat, dquat, quat);
- quat_to_axis_angle(ob->rotAxis, &ob->rotAngle, quat);
- break;
- }
- default: /* euler */
- {
- float quat[4];
- float dquat[4];
-
- /* without drot we could apply 'mat' directly */
- mat3_normalized_to_quat(quat, mat);
- eulO_to_quat(dquat, ob->drot, ob->rotmode);
- invert_qt_normalized(dquat);
- mul_qt_qtqt(quat, dquat, quat);
- /* end drot correction */
-
- if (use_compat) quat_to_compatible_eulO(ob->rot, ob->rot, ob->rotmode, quat);
- else quat_to_eulO(ob->rot, ob->rotmode, quat);
- break;
- }
- }
-}
-
-void BKE_object_tfm_protected_backup(const Object *ob,
- ObjectTfmProtectedChannels *obtfm)
+ BLI_ASSERT_UNIT_M3(mat);
+
+ switch (ob->rotmode) {
+ case ROT_MODE_QUAT: {
+ float dquat[4];
+ mat3_normalized_to_quat(ob->quat, mat);
+ normalize_qt_qt(dquat, ob->dquat);
+ invert_qt_normalized(dquat);
+ mul_qt_qtqt(ob->quat, dquat, ob->quat);
+ break;
+ }
+ case ROT_MODE_AXISANGLE: {
+ float quat[4];
+ float dquat[4];
+
+ /* without drot we could apply 'mat' directly */
+ mat3_normalized_to_quat(quat, mat);
+ axis_angle_to_quat(dquat, ob->drotAxis, ob->drotAngle);
+ invert_qt_normalized(dquat);
+ mul_qt_qtqt(quat, dquat, quat);
+ quat_to_axis_angle(ob->rotAxis, &ob->rotAngle, quat);
+ break;
+ }
+ default: /* euler */
+ {
+ float quat[4];
+ float dquat[4];
+
+ /* without drot we could apply 'mat' directly */
+ mat3_normalized_to_quat(quat, mat);
+ eulO_to_quat(dquat, ob->drot, ob->rotmode);
+ invert_qt_normalized(dquat);
+ mul_qt_qtqt(quat, dquat, quat);
+ /* end drot correction */
+
+ if (use_compat)
+ quat_to_compatible_eulO(ob->rot, ob->rot, ob->rotmode, quat);
+ else
+ quat_to_eulO(ob->rot, ob->rotmode, quat);
+ break;
+ }
+ }
+}
+
+void BKE_object_tfm_protected_backup(const Object *ob, ObjectTfmProtectedChannels *obtfm)
{
#define TFMCPY(_v) (obtfm->_v = ob->_v)
#define TFMCPY3D(_v) copy_v3_v3(obtfm->_v, ob->_v)
#define TFMCPY4D(_v) copy_v4_v4(obtfm->_v, ob->_v)
- TFMCPY3D(loc);
- TFMCPY3D(dloc);
- TFMCPY3D(scale);
- TFMCPY3D(dscale);
- TFMCPY3D(rot);
- TFMCPY3D(drot);
- TFMCPY4D(quat);
- TFMCPY4D(dquat);
- TFMCPY3D(rotAxis);
- TFMCPY3D(drotAxis);
- TFMCPY(rotAngle);
- TFMCPY(drotAngle);
+ TFMCPY3D(loc);
+ TFMCPY3D(dloc);
+ TFMCPY3D(scale);
+ TFMCPY3D(dscale);
+ TFMCPY3D(rot);
+ TFMCPY3D(drot);
+ TFMCPY4D(quat);
+ TFMCPY4D(dquat);
+ TFMCPY3D(rotAxis);
+ TFMCPY3D(drotAxis);
+ TFMCPY(rotAngle);
+ TFMCPY(drotAngle);
#undef TFMCPY
#undef TFMCPY3D
#undef TFMCPY4D
-
}
void BKE_object_tfm_protected_restore(Object *ob,
const ObjectTfmProtectedChannels *obtfm,
const short protectflag)
{
- unsigned int i;
+ unsigned int i;
- for (i = 0; i < 3; i++) {
- if (protectflag & (OB_LOCK_LOCX << i)) {
- ob->loc[i] = obtfm->loc[i];
- ob->dloc[i] = obtfm->dloc[i];
- }
+ for (i = 0; i < 3; i++) {
+ if (protectflag & (OB_LOCK_LOCX << i)) {
+ ob->loc[i] = obtfm->loc[i];
+ ob->dloc[i] = obtfm->dloc[i];
+ }
- if (protectflag & (OB_LOCK_SCALEX << i)) {
- ob->scale[i] = obtfm->scale[i];
- ob->dscale[i] = obtfm->dscale[i];
- }
+ if (protectflag & (OB_LOCK_SCALEX << i)) {
+ ob->scale[i] = obtfm->scale[i];
+ ob->dscale[i] = obtfm->dscale[i];
+ }
- if (protectflag & (OB_LOCK_ROTX << i)) {
- ob->rot[i] = obtfm->rot[i];
- ob->drot[i] = obtfm->drot[i];
+ if (protectflag & (OB_LOCK_ROTX << i)) {
+ ob->rot[i] = obtfm->rot[i];
+ ob->drot[i] = obtfm->drot[i];
- ob->quat[i + 1] = obtfm->quat[i + 1];
- ob->dquat[i + 1] = obtfm->dquat[i + 1];
+ ob->quat[i + 1] = obtfm->quat[i + 1];
+ ob->dquat[i + 1] = obtfm->dquat[i + 1];
- ob->rotAxis[i] = obtfm->rotAxis[i];
- ob->drotAxis[i] = obtfm->drotAxis[i];
- }
- }
+ ob->rotAxis[i] = obtfm->rotAxis[i];
+ ob->drotAxis[i] = obtfm->drotAxis[i];
+ }
+ }
- if ((protectflag & OB_LOCK_ROT4D) && (protectflag & OB_LOCK_ROTW)) {
- ob->quat[0] = obtfm->quat[0];
- ob->dquat[0] = obtfm->dquat[0];
+ if ((protectflag & OB_LOCK_ROT4D) && (protectflag & OB_LOCK_ROTW)) {
+ ob->quat[0] = obtfm->quat[0];
+ ob->dquat[0] = obtfm->dquat[0];
- ob->rotAngle = obtfm->rotAngle;
- ob->drotAngle = obtfm->drotAngle;
- }
+ ob->rotAngle = obtfm->rotAngle;
+ ob->drotAngle = obtfm->drotAngle;
+ }
}
void BKE_object_tfm_copy(Object *object_dst, const Object *object_src)
@@ -2099,18 +2133,18 @@ void BKE_object_tfm_copy(Object *object_dst, const Object *object_src)
#define TFMCPY3D(_v) copy_v3_v3(object_dst->_v, object_src->_v)
#define TFMCPY4D(_v) copy_v4_v4(object_dst->_v, object_src->_v)
- TFMCPY3D(loc);
- TFMCPY3D(dloc);
- TFMCPY3D(scale);
- TFMCPY3D(dscale);
- TFMCPY3D(rot);
- TFMCPY3D(drot);
- TFMCPY4D(quat);
- TFMCPY4D(dquat);
- TFMCPY3D(rotAxis);
- TFMCPY3D(drotAxis);
- TFMCPY(rotAngle);
- TFMCPY(drotAngle);
+ TFMCPY3D(loc);
+ TFMCPY3D(dloc);
+ TFMCPY3D(scale);
+ TFMCPY3D(dscale);
+ TFMCPY3D(rot);
+ TFMCPY3D(drot);
+ TFMCPY4D(quat);
+ TFMCPY4D(dquat);
+ TFMCPY3D(rotAxis);
+ TFMCPY3D(drotAxis);
+ TFMCPY(rotAngle);
+ TFMCPY(drotAngle);
#undef TFMCPY
#undef TFMCPY3D
@@ -2119,41 +2153,41 @@ void BKE_object_tfm_copy(Object *object_dst, const Object *object_src)
void BKE_object_to_mat3(Object *ob, float mat[3][3]) /* no parent */
{
- float smat[3][3];
- float rmat[3][3];
- /*float q1[4];*/
+ float smat[3][3];
+ float rmat[3][3];
+ /*float q1[4];*/
- /* scale */
- BKE_object_scale_to_mat3(ob, smat);
+ /* scale */
+ BKE_object_scale_to_mat3(ob, smat);
- /* rot */
- BKE_object_rot_to_mat3(ob, rmat, true);
- mul_m3_m3m3(mat, rmat, smat);
+ /* rot */
+ BKE_object_rot_to_mat3(ob, rmat, true);
+ mul_m3_m3m3(mat, rmat, smat);
}
void BKE_object_to_mat4(Object *ob, float mat[4][4])
{
- float tmat[3][3];
+ float tmat[3][3];
- BKE_object_to_mat3(ob, tmat);
+ BKE_object_to_mat3(ob, tmat);
- copy_m4_m3(mat, tmat);
+ copy_m4_m3(mat, tmat);
- add_v3_v3v3(mat[3], ob->loc, ob->dloc);
+ add_v3_v3v3(mat[3], ob->loc, ob->dloc);
}
void BKE_object_matrix_local_get(struct Object *ob, float mat[4][4])
{
- if (ob->parent) {
- float par_imat[4][4];
+ if (ob->parent) {
+ float par_imat[4][4];
- BKE_object_get_parent_matrix(ob, ob->parent, par_imat);
- invert_m4(par_imat);
- mul_m4_m4m4(mat, par_imat, ob->obmat);
- }
- else {
- copy_m4_m4(mat, ob->obmat);
- }
+ BKE_object_get_parent_matrix(ob, ob->parent, par_imat);
+ invert_m4(par_imat);
+ mul_m4_m4m4(mat, par_imat, ob->obmat);
+ }
+ else {
+ copy_m4_m4(mat, ob->obmat);
+ }
}
/**
@@ -2162,337 +2196,346 @@ void BKE_object_matrix_local_get(struct Object *ob, float mat[4][4])
*/
static bool ob_parcurve(Object *ob, Object *par, float mat[4][4])
{
- Curve *cu = par->data;
- float vec[4], dir[3], quat[4], radius, ctime;
-
- /* NOTE: Curve cache is supposed to be evaluated here already, however there
- * are cases where we can not guarantee that. This includes, for example,
- * dependency cycles. We can't correct anything from here, since that would
- * cause a threading conflicts.
- *
- * TODO(sergey): Somce of the legit looking cases like T56619 need to be
- * looked into, and maybe curve cache (and other dependencies) are to be
- * evaluated prior to conversion. */
- if (par->runtime.curve_cache == NULL) {
- return false;
- }
- if (par->runtime.curve_cache->path == NULL) {
- return false;
- }
-
- /* ctime is now a proper var setting of Curve which gets set by Animato like any other var that's animated,
- * but this will only work if it actually is animated...
- *
- * we divide the curvetime calculated in the previous step by the length of the path, to get a time
- * factor, which then gets clamped to lie within 0.0 - 1.0 range
- */
- if (cu->pathlen) {
- ctime = cu->ctime / cu->pathlen;
- }
- else {
- ctime = cu->ctime;
- }
- CLAMP(ctime, 0.0f, 1.0f);
-
- unit_m4(mat);
-
- /* vec: 4 items! */
- if (where_on_path(par, ctime, vec, dir, (cu->flag & CU_FOLLOW) ? quat : NULL, &radius, NULL)) {
- if (cu->flag & CU_FOLLOW) {
- quat_apply_track(quat, ob->trackflag, ob->upflag);
- normalize_qt(quat);
- quat_to_mat4(mat, quat);
- }
- if (cu->flag & CU_PATH_RADIUS) {
- float tmat[4][4], rmat[4][4];
- scale_m4_fl(tmat, radius);
- mul_m4_m4m4(rmat, tmat, mat);
- copy_m4_m4(mat, rmat);
- }
- copy_v3_v3(mat[3], vec);
- }
-
- return true;
+ Curve *cu = par->data;
+ float vec[4], dir[3], quat[4], radius, ctime;
+
+ /* NOTE: Curve cache is supposed to be evaluated here already, however there
+ * are cases where we can not guarantee that. This includes, for example,
+ * dependency cycles. We can't correct anything from here, since that would
+ * cause a threading conflicts.
+ *
+ * TODO(sergey): Somce of the legit looking cases like T56619 need to be
+ * looked into, and maybe curve cache (and other dependencies) are to be
+ * evaluated prior to conversion. */
+ if (par->runtime.curve_cache == NULL) {
+ return false;
+ }
+ if (par->runtime.curve_cache->path == NULL) {
+ return false;
+ }
+
+ /* ctime is now a proper var setting of Curve which gets set by Animato like any other var that's animated,
+ * but this will only work if it actually is animated...
+ *
+ * we divide the curvetime calculated in the previous step by the length of the path, to get a time
+ * factor, which then gets clamped to lie within 0.0 - 1.0 range
+ */
+ if (cu->pathlen) {
+ ctime = cu->ctime / cu->pathlen;
+ }
+ else {
+ ctime = cu->ctime;
+ }
+ CLAMP(ctime, 0.0f, 1.0f);
+
+ unit_m4(mat);
+
+ /* vec: 4 items! */
+ if (where_on_path(par, ctime, vec, dir, (cu->flag & CU_FOLLOW) ? quat : NULL, &radius, NULL)) {
+ if (cu->flag & CU_FOLLOW) {
+ quat_apply_track(quat, ob->trackflag, ob->upflag);
+ normalize_qt(quat);
+ quat_to_mat4(mat, quat);
+ }
+ if (cu->flag & CU_PATH_RADIUS) {
+ float tmat[4][4], rmat[4][4];
+ scale_m4_fl(tmat, radius);
+ mul_m4_m4m4(rmat, tmat, mat);
+ copy_m4_m4(mat, rmat);
+ }
+ copy_v3_v3(mat[3], vec);
+ }
+
+ return true;
}
static void ob_parbone(Object *ob, Object *par, float mat[4][4])
{
- bPoseChannel *pchan;
- float vec[3];
-
- if (par->type != OB_ARMATURE) {
- unit_m4(mat);
- return;
- }
-
- /* Make sure the bone is still valid */
- pchan = BKE_pose_channel_find_name(par->pose, ob->parsubstr);
- if (!pchan || !pchan->bone) {
- CLOG_ERROR(&LOG, "Object %s with Bone parent: bone %s doesn't exist", ob->id.name + 2, ob->parsubstr);
- unit_m4(mat);
- return;
- }
-
- /* get bone transform */
- if (pchan->bone->flag & BONE_RELATIVE_PARENTING) {
- /* the new option uses the root - expected behavior, but differs from old... */
- /* XXX check on version patching? */
- copy_m4_m4(mat, pchan->chan_mat);
- }
- else {
- copy_m4_m4(mat, pchan->pose_mat);
-
- /* but for backwards compatibility, the child has to move to the tail */
- copy_v3_v3(vec, mat[1]);
- mul_v3_fl(vec, pchan->bone->length);
- add_v3_v3(mat[3], vec);
- }
+ bPoseChannel *pchan;
+ float vec[3];
+
+ if (par->type != OB_ARMATURE) {
+ unit_m4(mat);
+ return;
+ }
+
+ /* Make sure the bone is still valid */
+ pchan = BKE_pose_channel_find_name(par->pose, ob->parsubstr);
+ if (!pchan || !pchan->bone) {
+ CLOG_ERROR(
+ &LOG, "Object %s with Bone parent: bone %s doesn't exist", ob->id.name + 2, ob->parsubstr);
+ unit_m4(mat);
+ return;
+ }
+
+ /* get bone transform */
+ if (pchan->bone->flag & BONE_RELATIVE_PARENTING) {
+ /* the new option uses the root - expected behavior, but differs from old... */
+ /* XXX check on version patching? */
+ copy_m4_m4(mat, pchan->chan_mat);
+ }
+ else {
+ copy_m4_m4(mat, pchan->pose_mat);
+
+ /* but for backwards compatibility, the child has to move to the tail */
+ copy_v3_v3(vec, mat[1]);
+ mul_v3_fl(vec, pchan->bone->length);
+ add_v3_v3(mat[3], vec);
+ }
}
static void give_parvert(Object *par, int nr, float vec[3])
{
- zero_v3(vec);
+ zero_v3(vec);
- if (par->type == OB_MESH) {
- Mesh *me = par->data;
- BMEditMesh *em = me->edit_mesh;
- Mesh *me_eval = (em) ? em->mesh_eval_final : par->runtime.mesh_eval;
+ if (par->type == OB_MESH) {
+ Mesh *me = par->data;
+ BMEditMesh *em = me->edit_mesh;
+ Mesh *me_eval = (em) ? em->mesh_eval_final : par->runtime.mesh_eval;
- if (me_eval) {
- int count = 0;
- const int numVerts = me_eval->totvert;
+ if (me_eval) {
+ int count = 0;
+ const int numVerts = me_eval->totvert;
- if (nr < numVerts) {
- if (em && me_eval->runtime.is_original) {
- if (em->bm->elem_table_dirty & BM_VERT) {
+ if (nr < numVerts) {
+ if (em && me_eval->runtime.is_original) {
+ if (em->bm->elem_table_dirty & BM_VERT) {
#ifdef VPARENT_THREADING_HACK
- BLI_mutex_lock(&vparent_lock);
- if (em->bm->elem_table_dirty & BM_VERT) {
- BM_mesh_elem_table_ensure(em->bm, BM_VERT);
- }
- BLI_mutex_unlock(&vparent_lock);
+ BLI_mutex_lock(&vparent_lock);
+ if (em->bm->elem_table_dirty & BM_VERT) {
+ BM_mesh_elem_table_ensure(em->bm, BM_VERT);
+ }
+ BLI_mutex_unlock(&vparent_lock);
#else
- BLI_assert(!"Not safe for threading");
- BM_mesh_elem_table_ensure(em->bm, BM_VERT);
+ BLI_assert(!"Not safe for threading");
+ BM_mesh_elem_table_ensure(em->bm, BM_VERT);
#endif
- }
- }
-
- if (CustomData_has_layer(&me_eval->vdata, CD_ORIGINDEX) &&
- !(em && me_eval->runtime.is_original))
- {
- const int *index = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX);
- /* Get the average of all verts with (original index == nr). */
- for (int i = 0; i < numVerts; i++) {
- if (index[i] == nr) {
- add_v3_v3(vec, me_eval->mvert[i].co);
- count++;
- }
- }
- }
- else {
- if (nr < numVerts) {
- add_v3_v3(vec, me_eval->mvert[nr].co);
- count++;
- }
- }
- }
-
- if (count == 0) {
- /* keep as 0, 0, 0 */
- }
- else if (count > 0) {
- mul_v3_fl(vec, 1.0f / count);
- }
- else {
- /* use first index if its out of range */
- if (me_eval->totvert) {
- copy_v3_v3(vec, me_eval->mvert[0].co);
- }
- }
- }
- else {
- CLOG_ERROR(&LOG, "Evaluated mesh is needed to solve parenting, "
- "object position can be wrong now");
- }
- }
- else if (ELEM(par->type, OB_CURVE, OB_SURF)) {
- ListBase *nurb;
-
- /* Unless there's some weird depsgraph failure the cache should exist. */
- BLI_assert(par->runtime.curve_cache != NULL);
-
- if (par->runtime.curve_cache->deformed_nurbs.first != NULL) {
- nurb = &par->runtime.curve_cache->deformed_nurbs;
- }
- else {
- Curve *cu = par->data;
- nurb = BKE_curve_nurbs_get(cu);
- }
-
- BKE_nurbList_index_get_co(nurb, nr, vec);
- }
- else if (par->type == OB_LATTICE) {
- Lattice *latt = par->data;
- DispList *dl = par->runtime.curve_cache ? BKE_displist_find(&par->runtime.curve_cache->disp, DL_VERTS) : NULL;
- float (*co)[3] = dl ? (float (*)[3])dl->verts : NULL;
- int tot;
-
- if (latt->editlatt) latt = latt->editlatt->latt;
-
- tot = latt->pntsu * latt->pntsv * latt->pntsw;
-
- /* ensure dl is correct size */
- BLI_assert(dl == NULL || dl->nr == tot);
-
- if (nr < tot) {
- if (co) {
- copy_v3_v3(vec, co[nr]);
- }
- else {
- copy_v3_v3(vec, latt->def[nr].vec);
- }
- }
- }
+ }
+ }
+
+ if (CustomData_has_layer(&me_eval->vdata, CD_ORIGINDEX) &&
+ !(em && me_eval->runtime.is_original)) {
+ const int *index = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX);
+ /* Get the average of all verts with (original index == nr). */
+ for (int i = 0; i < numVerts; i++) {
+ if (index[i] == nr) {
+ add_v3_v3(vec, me_eval->mvert[i].co);
+ count++;
+ }
+ }
+ }
+ else {
+ if (nr < numVerts) {
+ add_v3_v3(vec, me_eval->mvert[nr].co);
+ count++;
+ }
+ }
+ }
+
+ if (count == 0) {
+ /* keep as 0, 0, 0 */
+ }
+ else if (count > 0) {
+ mul_v3_fl(vec, 1.0f / count);
+ }
+ else {
+ /* use first index if its out of range */
+ if (me_eval->totvert) {
+ copy_v3_v3(vec, me_eval->mvert[0].co);
+ }
+ }
+ }
+ else {
+ CLOG_ERROR(&LOG,
+ "Evaluated mesh is needed to solve parenting, "
+ "object position can be wrong now");
+ }
+ }
+ else if (ELEM(par->type, OB_CURVE, OB_SURF)) {
+ ListBase *nurb;
+
+ /* Unless there's some weird depsgraph failure the cache should exist. */
+ BLI_assert(par->runtime.curve_cache != NULL);
+
+ if (par->runtime.curve_cache->deformed_nurbs.first != NULL) {
+ nurb = &par->runtime.curve_cache->deformed_nurbs;
+ }
+ else {
+ Curve *cu = par->data;
+ nurb = BKE_curve_nurbs_get(cu);
+ }
+
+ BKE_nurbList_index_get_co(nurb, nr, vec);
+ }
+ else if (par->type == OB_LATTICE) {
+ Lattice *latt = par->data;
+ DispList *dl = par->runtime.curve_cache ?
+ BKE_displist_find(&par->runtime.curve_cache->disp, DL_VERTS) :
+ NULL;
+ float(*co)[3] = dl ? (float(*)[3])dl->verts : NULL;
+ int tot;
+
+ if (latt->editlatt)
+ latt = latt->editlatt->latt;
+
+ tot = latt->pntsu * latt->pntsv * latt->pntsw;
+
+ /* ensure dl is correct size */
+ BLI_assert(dl == NULL || dl->nr == tot);
+
+ if (nr < tot) {
+ if (co) {
+ copy_v3_v3(vec, co[nr]);
+ }
+ else {
+ copy_v3_v3(vec, latt->def[nr].vec);
+ }
+ }
+ }
}
static void ob_parvert3(Object *ob, Object *par, float mat[4][4])
{
- /* in local ob space */
- if (OB_TYPE_SUPPORT_PARVERT(par->type)) {
- float cmat[3][3], v1[3], v2[3], v3[3], q[4];
+ /* in local ob space */
+ if (OB_TYPE_SUPPORT_PARVERT(par->type)) {
+ float cmat[3][3], v1[3], v2[3], v3[3], q[4];
- give_parvert(par, ob->par1, v1);
- give_parvert(par, ob->par2, v2);
- give_parvert(par, ob->par3, v3);
+ give_parvert(par, ob->par1, v1);
+ give_parvert(par, ob->par2, v2);
+ give_parvert(par, ob->par3, v3);
- tri_to_quat(q, v1, v2, v3);
- quat_to_mat3(cmat, q);
- copy_m4_m3(mat, cmat);
+ tri_to_quat(q, v1, v2, v3);
+ quat_to_mat3(cmat, q);
+ copy_m4_m3(mat, cmat);
- mid_v3_v3v3v3(mat[3], v1, v2, v3);
- }
- else {
- unit_m4(mat);
- }
+ mid_v3_v3v3v3(mat[3], v1, v2, v3);
+ }
+ else {
+ unit_m4(mat);
+ }
}
void BKE_object_get_parent_matrix(Object *ob, Object *par, float parentmat[4][4])
{
- float tmat[4][4];
- float vec[3];
- bool ok;
-
- switch (ob->partype & PARTYPE) {
- case PAROBJECT:
- ok = 0;
- if (par->type == OB_CURVE) {
- if ((((Curve *)par->data)->flag & CU_PATH) &&
- (ob_parcurve(ob, par, tmat)))
- {
- ok = 1;
- }
- }
-
- if (ok) mul_m4_m4m4(parentmat, par->obmat, tmat);
- else copy_m4_m4(parentmat, par->obmat);
-
- break;
- case PARBONE:
- ob_parbone(ob, par, tmat);
- mul_m4_m4m4(parentmat, par->obmat, tmat);
- break;
-
- case PARVERT1:
- unit_m4(parentmat);
- give_parvert(par, ob->par1, vec);
- mul_v3_m4v3(parentmat[3], par->obmat, vec);
- break;
- case PARVERT3:
- ob_parvert3(ob, par, tmat);
-
- mul_m4_m4m4(parentmat, par->obmat, tmat);
- break;
-
- case PARSKEL:
- copy_m4_m4(parentmat, par->obmat);
- break;
- }
+ float tmat[4][4];
+ float vec[3];
+ bool ok;
+
+ switch (ob->partype & PARTYPE) {
+ case PAROBJECT:
+ ok = 0;
+ if (par->type == OB_CURVE) {
+ if ((((Curve *)par->data)->flag & CU_PATH) && (ob_parcurve(ob, par, tmat))) {
+ ok = 1;
+ }
+ }
+
+ if (ok)
+ mul_m4_m4m4(parentmat, par->obmat, tmat);
+ else
+ copy_m4_m4(parentmat, par->obmat);
+
+ break;
+ case PARBONE:
+ ob_parbone(ob, par, tmat);
+ mul_m4_m4m4(parentmat, par->obmat, tmat);
+ break;
+
+ case PARVERT1:
+ unit_m4(parentmat);
+ give_parvert(par, ob->par1, vec);
+ mul_v3_m4v3(parentmat[3], par->obmat, vec);
+ break;
+ case PARVERT3:
+ ob_parvert3(ob, par, tmat);
+
+ mul_m4_m4m4(parentmat, par->obmat, tmat);
+ break;
+
+ case PARSKEL:
+ copy_m4_m4(parentmat, par->obmat);
+ break;
+ }
}
/**
* \param r_originmat: Optional matrix that stores the space the object is in (without its own matrix applied)
*/
-static void solve_parenting(Object *ob, Object *par, float obmat[4][4],
- float r_originmat[3][3], const bool set_origin)
+static void solve_parenting(
+ Object *ob, Object *par, float obmat[4][4], float r_originmat[3][3], const bool set_origin)
{
- float totmat[4][4];
- float tmat[4][4];
- float locmat[4][4];
+ float totmat[4][4];
+ float tmat[4][4];
+ float locmat[4][4];
- BKE_object_to_mat4(ob, locmat);
+ BKE_object_to_mat4(ob, locmat);
- BKE_object_get_parent_matrix(ob, par, totmat);
+ BKE_object_get_parent_matrix(ob, par, totmat);
- /* total */
- mul_m4_m4m4(tmat, totmat, ob->parentinv);
- mul_m4_m4m4(obmat, tmat, locmat);
+ /* total */
+ mul_m4_m4m4(tmat, totmat, ob->parentinv);
+ mul_m4_m4m4(obmat, tmat, locmat);
- if (r_originmat) {
- /* usable originmat */
- copy_m3_m4(r_originmat, tmat);
- }
+ if (r_originmat) {
+ /* usable originmat */
+ copy_m3_m4(r_originmat, tmat);
+ }
- /* origin, for help line */
- if (set_origin) {
- if ((ob->partype & PARTYPE) == PARSKEL) {
- copy_v3_v3(ob->runtime.parent_display_origin, par->obmat[3]);
- }
- else {
- copy_v3_v3(ob->runtime.parent_display_origin, totmat[3]);
- }
- }
+ /* origin, for help line */
+ if (set_origin) {
+ if ((ob->partype & PARTYPE) == PARSKEL) {
+ copy_v3_v3(ob->runtime.parent_display_origin, par->obmat[3]);
+ }
+ else {
+ copy_v3_v3(ob->runtime.parent_display_origin, totmat[3]);
+ }
+ }
}
/* note, scene is the active scene while actual_scene is the scene the object resides in */
-static void object_where_is_calc_ex(
- Depsgraph *depsgraph, Scene *scene, Object *ob, float ctime,
- RigidBodyWorld *rbw, float r_originmat[3][3])
-{
- if (ob->parent) {
- Object *par = ob->parent;
-
- /* calculate parent matrix */
- solve_parenting(ob, par, ob->obmat, r_originmat, true);
- }
- else {
- BKE_object_to_mat4(ob, ob->obmat);
- }
-
- /* try to fall back to the scene rigid body world if none given */
- rbw = rbw ? rbw : scene->rigidbody_world;
- /* read values pushed into RBO from sim/cache... */
- BKE_rigidbody_sync_transforms(rbw, ob, ctime);
-
- /* solve constraints */
- if (ob->constraints.first && !(ob->transflag & OB_NO_CONSTRAINTS)) {
- bConstraintOb *cob;
- cob = BKE_constraints_make_evalob(depsgraph, scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
- BKE_constraints_solve(depsgraph, &ob->constraints, cob, ctime);
- BKE_constraints_clear_evalob(cob);
- }
-
- /* set negative scale flag in object */
- if (is_negative_m4(ob->obmat)) ob->transflag |= OB_NEG_SCALE;
- else ob->transflag &= ~OB_NEG_SCALE;
+static void object_where_is_calc_ex(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ float ctime,
+ RigidBodyWorld *rbw,
+ float r_originmat[3][3])
+{
+ if (ob->parent) {
+ Object *par = ob->parent;
+
+ /* calculate parent matrix */
+ solve_parenting(ob, par, ob->obmat, r_originmat, true);
+ }
+ else {
+ BKE_object_to_mat4(ob, ob->obmat);
+ }
+
+ /* try to fall back to the scene rigid body world if none given */
+ rbw = rbw ? rbw : scene->rigidbody_world;
+ /* read values pushed into RBO from sim/cache... */
+ BKE_rigidbody_sync_transforms(rbw, ob, ctime);
+
+ /* solve constraints */
+ if (ob->constraints.first && !(ob->transflag & OB_NO_CONSTRAINTS)) {
+ bConstraintOb *cob;
+ cob = BKE_constraints_make_evalob(depsgraph, scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
+ BKE_constraints_solve(depsgraph, &ob->constraints, cob, ctime);
+ BKE_constraints_clear_evalob(cob);
+ }
+
+ /* set negative scale flag in object */
+ if (is_negative_m4(ob->obmat))
+ ob->transflag |= OB_NEG_SCALE;
+ else
+ ob->transflag &= ~OB_NEG_SCALE;
}
void BKE_object_where_is_calc_time(Depsgraph *depsgraph, Scene *scene, Object *ob, float ctime)
{
- /* Execute drivers and animation. */
- BKE_animsys_evaluate_animdata(depsgraph, scene, &ob->id, ob->adt, ctime, ADT_RECALC_ALL);
- object_where_is_calc_ex(depsgraph, scene, ob, ctime, NULL, NULL);
+ /* Execute drivers and animation. */
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &ob->id, ob->adt, ctime, ADT_RECALC_ALL);
+ object_where_is_calc_ex(depsgraph, scene, ob, ctime, NULL, NULL);
}
/* get object transformation matrix without recalculating dependencies and
@@ -2501,24 +2544,25 @@ void BKE_object_where_is_calc_time(Depsgraph *depsgraph, Scene *scene, Object *o
* used for bundles orientation in 3d space relative to parented blender camera */
void BKE_object_where_is_calc_mat4(Object *ob, float obmat[4][4])
{
- if (ob->parent) {
- Object *par = ob->parent;
- solve_parenting(ob, par, obmat, NULL, false);
- }
- else {
- BKE_object_to_mat4(ob, obmat);
- }
+ if (ob->parent) {
+ Object *par = ob->parent;
+ solve_parenting(ob, par, obmat, NULL, false);
+ }
+ else {
+ BKE_object_to_mat4(ob, obmat);
+ }
}
-void BKE_object_where_is_calc_ex(Depsgraph *depsgraph, Scene *scene, RigidBodyWorld *rbw, Object *ob, float r_originmat[3][3])
+void BKE_object_where_is_calc_ex(
+ Depsgraph *depsgraph, Scene *scene, RigidBodyWorld *rbw, Object *ob, float r_originmat[3][3])
{
- float ctime = DEG_get_ctime(depsgraph);
- object_where_is_calc_ex(depsgraph, scene, ob, ctime, rbw, r_originmat);
+ float ctime = DEG_get_ctime(depsgraph);
+ object_where_is_calc_ex(depsgraph, scene, ob, ctime, rbw, r_originmat);
}
void BKE_object_where_is_calc(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- float ctime = DEG_get_ctime(depsgraph);
- object_where_is_calc_ex(depsgraph, scene, ob, ctime, NULL, NULL);
+ float ctime = DEG_get_ctime(depsgraph);
+ object_where_is_calc_ex(depsgraph, scene, ob, ctime, NULL, NULL);
}
/**
@@ -2531,28 +2575,28 @@ void BKE_object_where_is_calc(Depsgraph *depsgraph, Scene *scene, Object *ob)
*/
void BKE_object_workob_calc_parent(Depsgraph *depsgraph, Scene *scene, Object *ob, Object *workob)
{
- BKE_object_workob_clear(workob);
+ BKE_object_workob_clear(workob);
- unit_m4(workob->obmat);
- unit_m4(workob->parentinv);
- unit_m4(workob->constinv);
+ unit_m4(workob->obmat);
+ unit_m4(workob->parentinv);
+ unit_m4(workob->constinv);
- /* Since this is used while calculating parenting, at this moment ob_eval->parent is still NULL. */
- workob->parent = DEG_get_evaluated_object(depsgraph, ob->parent);
+ /* Since this is used while calculating parenting, at this moment ob_eval->parent is still NULL. */
+ workob->parent = DEG_get_evaluated_object(depsgraph, ob->parent);
- workob->trackflag = ob->trackflag;
- workob->upflag = ob->upflag;
+ workob->trackflag = ob->trackflag;
+ workob->upflag = ob->upflag;
- workob->partype = ob->partype;
- workob->par1 = ob->par1;
- workob->par2 = ob->par2;
- workob->par3 = ob->par3;
+ workob->partype = ob->partype;
+ workob->par1 = ob->par1;
+ workob->par2 = ob->par2;
+ workob->par3 = ob->par3;
- workob->constraints = ob->constraints;
+ workob->constraints = ob->constraints;
- BLI_strncpy(workob->parsubstr, ob->parsubstr, sizeof(workob->parsubstr));
+ BLI_strncpy(workob->parsubstr, ob->parsubstr, sizeof(workob->parsubstr));
- BKE_object_where_is_calc(depsgraph, scene, workob);
+ BKE_object_where_is_calc(depsgraph, scene, workob);
}
/**
@@ -2562,504 +2606,513 @@ void BKE_object_workob_calc_parent(Depsgraph *depsgraph, Scene *scene, Object *o
* \param parent: the parent space in which this object will be set relative to (should probably always be parent_eval).
* \param use_compat: true to ensure that rotations are set using the min difference between the old and new orientation.
*/
-void BKE_object_apply_mat4_ex(Object *ob, float mat[4][4], Object *parent, float parentinv[4][4], const bool use_compat)
+void BKE_object_apply_mat4_ex(
+ Object *ob, float mat[4][4], Object *parent, float parentinv[4][4], const bool use_compat)
{
- /* see BKE_pchan_apply_mat4() for the equivalent 'pchan' function */
+ /* see BKE_pchan_apply_mat4() for the equivalent 'pchan' function */
- float rot[3][3];
+ float rot[3][3];
- if (parent != NULL) {
- float rmat[4][4], diff_mat[4][4], imat[4][4], parent_mat[4][4];
+ if (parent != NULL) {
+ float rmat[4][4], diff_mat[4][4], imat[4][4], parent_mat[4][4];
- BKE_object_get_parent_matrix(ob, parent, parent_mat);
+ BKE_object_get_parent_matrix(ob, parent, parent_mat);
- mul_m4_m4m4(diff_mat, parent_mat, parentinv);
- invert_m4_m4(imat, diff_mat);
- mul_m4_m4m4(rmat, imat, mat); /* get the parent relative matrix */
+ mul_m4_m4m4(diff_mat, parent_mat, parentinv);
+ invert_m4_m4(imat, diff_mat);
+ mul_m4_m4m4(rmat, imat, mat); /* get the parent relative matrix */
- /* same as below, use rmat rather than mat */
- mat4_to_loc_rot_size(ob->loc, rot, ob->scale, rmat);
- }
- else {
- mat4_to_loc_rot_size(ob->loc, rot, ob->scale, mat);
- }
+ /* same as below, use rmat rather than mat */
+ mat4_to_loc_rot_size(ob->loc, rot, ob->scale, rmat);
+ }
+ else {
+ mat4_to_loc_rot_size(ob->loc, rot, ob->scale, mat);
+ }
- BKE_object_mat3_to_rot(ob, rot, use_compat);
+ BKE_object_mat3_to_rot(ob, rot, use_compat);
- sub_v3_v3(ob->loc, ob->dloc);
+ sub_v3_v3(ob->loc, ob->dloc);
- if (ob->dscale[0] != 0.0f) ob->scale[0] /= ob->dscale[0];
- if (ob->dscale[1] != 0.0f) ob->scale[1] /= ob->dscale[1];
- if (ob->dscale[2] != 0.0f) ob->scale[2] /= ob->dscale[2];
+ if (ob->dscale[0] != 0.0f)
+ ob->scale[0] /= ob->dscale[0];
+ if (ob->dscale[1] != 0.0f)
+ ob->scale[1] /= ob->dscale[1];
+ if (ob->dscale[2] != 0.0f)
+ ob->scale[2] /= ob->dscale[2];
- /* BKE_object_mat3_to_rot handles delta rotations */
+ /* BKE_object_mat3_to_rot handles delta rotations */
}
/* XXX: should be removed after COW operators port to use BKE_object_apply_mat4_ex directly */
-void BKE_object_apply_mat4(Object *ob, float mat[4][4], const bool use_compat, const bool use_parent)
+void BKE_object_apply_mat4(Object *ob,
+ float mat[4][4],
+ const bool use_compat,
+ const bool use_parent)
{
- BKE_object_apply_mat4_ex(ob, mat, use_parent ? ob->parent : NULL, ob->parentinv, use_compat);
+ BKE_object_apply_mat4_ex(ob, mat, use_parent ? ob->parent : NULL, ob->parentinv, use_compat);
}
BoundBox *BKE_boundbox_alloc_unit(void)
{
- BoundBox *bb;
- const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {1.0f, 1.0f, 1.0f};
+ BoundBox *bb;
+ const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {1.0f, 1.0f, 1.0f};
- bb = MEM_callocN(sizeof(BoundBox), "OB-BoundBox");
- BKE_boundbox_init_from_minmax(bb, min, max);
+ bb = MEM_callocN(sizeof(BoundBox), "OB-BoundBox");
+ BKE_boundbox_init_from_minmax(bb, min, max);
- return bb;
+ return bb;
}
void BKE_boundbox_init_from_minmax(BoundBox *bb, const float min[3], const float max[3])
{
- bb->vec[0][0] = bb->vec[1][0] = bb->vec[2][0] = bb->vec[3][0] = min[0];
- bb->vec[4][0] = bb->vec[5][0] = bb->vec[6][0] = bb->vec[7][0] = max[0];
+ bb->vec[0][0] = bb->vec[1][0] = bb->vec[2][0] = bb->vec[3][0] = min[0];
+ bb->vec[4][0] = bb->vec[5][0] = bb->vec[6][0] = bb->vec[7][0] = max[0];
- bb->vec[0][1] = bb->vec[1][1] = bb->vec[4][1] = bb->vec[5][1] = min[1];
- bb->vec[2][1] = bb->vec[3][1] = bb->vec[6][1] = bb->vec[7][1] = max[1];
+ bb->vec[0][1] = bb->vec[1][1] = bb->vec[4][1] = bb->vec[5][1] = min[1];
+ bb->vec[2][1] = bb->vec[3][1] = bb->vec[6][1] = bb->vec[7][1] = max[1];
- bb->vec[0][2] = bb->vec[3][2] = bb->vec[4][2] = bb->vec[7][2] = min[2];
- bb->vec[1][2] = bb->vec[2][2] = bb->vec[5][2] = bb->vec[6][2] = max[2];
+ bb->vec[0][2] = bb->vec[3][2] = bb->vec[4][2] = bb->vec[7][2] = min[2];
+ bb->vec[1][2] = bb->vec[2][2] = bb->vec[5][2] = bb->vec[6][2] = max[2];
}
void BKE_boundbox_calc_center_aabb(const BoundBox *bb, float r_cent[3])
{
- r_cent[0] = 0.5f * (bb->vec[0][0] + bb->vec[4][0]);
- r_cent[1] = 0.5f * (bb->vec[0][1] + bb->vec[2][1]);
- r_cent[2] = 0.5f * (bb->vec[0][2] + bb->vec[1][2]);
+ r_cent[0] = 0.5f * (bb->vec[0][0] + bb->vec[4][0]);
+ r_cent[1] = 0.5f * (bb->vec[0][1] + bb->vec[2][1]);
+ r_cent[2] = 0.5f * (bb->vec[0][2] + bb->vec[1][2]);
}
void BKE_boundbox_calc_size_aabb(const BoundBox *bb, float r_size[3])
{
- r_size[0] = 0.5f * fabsf(bb->vec[0][0] - bb->vec[4][0]);
- r_size[1] = 0.5f * fabsf(bb->vec[0][1] - bb->vec[2][1]);
- r_size[2] = 0.5f * fabsf(bb->vec[0][2] - bb->vec[1][2]);
+ r_size[0] = 0.5f * fabsf(bb->vec[0][0] - bb->vec[4][0]);
+ r_size[1] = 0.5f * fabsf(bb->vec[0][1] - bb->vec[2][1]);
+ r_size[2] = 0.5f * fabsf(bb->vec[0][2] - bb->vec[1][2]);
}
void BKE_boundbox_minmax(const BoundBox *bb, float obmat[4][4], float r_min[3], float r_max[3])
{
- int i;
- for (i = 0; i < 8; i++) {
- float vec[3];
- mul_v3_m4v3(vec, obmat, bb->vec[i]);
- minmax_v3v3_v3(r_min, r_max, vec);
- }
+ int i;
+ for (i = 0; i < 8; i++) {
+ float vec[3];
+ mul_v3_m4v3(vec, obmat, bb->vec[i]);
+ minmax_v3v3_v3(r_min, r_max, vec);
+ }
}
BoundBox *BKE_object_boundbox_get(Object *ob)
{
- BoundBox *bb = NULL;
-
- switch (ob->type) {
- case OB_MESH:
- bb = BKE_mesh_boundbox_get(ob);
- break;
- case OB_CURVE:
- case OB_SURF:
- case OB_FONT:
- bb = BKE_curve_boundbox_get(ob);
- break;
- case OB_MBALL:
- bb = BKE_mball_boundbox_get(ob);
- break;
- case OB_LATTICE:
- bb = BKE_lattice_boundbox_get(ob);
- break;
- case OB_ARMATURE:
- bb = BKE_armature_boundbox_get(ob);
- break;
- case OB_GPENCIL:
- bb = BKE_gpencil_boundbox_get(ob);
- break;
- default:
- break;
- }
- return bb;
+ BoundBox *bb = NULL;
+
+ switch (ob->type) {
+ case OB_MESH:
+ bb = BKE_mesh_boundbox_get(ob);
+ break;
+ case OB_CURVE:
+ case OB_SURF:
+ case OB_FONT:
+ bb = BKE_curve_boundbox_get(ob);
+ break;
+ case OB_MBALL:
+ bb = BKE_mball_boundbox_get(ob);
+ break;
+ case OB_LATTICE:
+ bb = BKE_lattice_boundbox_get(ob);
+ break;
+ case OB_ARMATURE:
+ bb = BKE_armature_boundbox_get(ob);
+ break;
+ case OB_GPENCIL:
+ bb = BKE_gpencil_boundbox_get(ob);
+ break;
+ default:
+ break;
+ }
+ return bb;
}
/* used to temporally disable/enable boundbox */
void BKE_object_boundbox_flag(Object *ob, int flag, const bool set)
{
- BoundBox *bb = BKE_object_boundbox_get(ob);
- if (bb) {
- if (set) bb->flag |= flag;
- else bb->flag &= ~flag;
- }
+ BoundBox *bb = BKE_object_boundbox_get(ob);
+ if (bb) {
+ if (set)
+ bb->flag |= flag;
+ else
+ bb->flag &= ~flag;
+ }
}
void BKE_object_boundbox_calc_from_mesh(struct Object *ob, struct Mesh *me_eval)
{
- float min[3], max[3];
+ float min[3], max[3];
- INIT_MINMAX(min, max);
+ INIT_MINMAX(min, max);
- if (!BKE_mesh_minmax(me_eval, min, max)) {
- zero_v3(min);
- zero_v3(max);
- }
+ if (!BKE_mesh_minmax(me_eval, min, max)) {
+ zero_v3(min);
+ zero_v3(max);
+ }
- if (ob->runtime.bb == NULL) {
- ob->runtime.bb = MEM_callocN(sizeof(BoundBox), "DM-BoundBox");
- }
+ if (ob->runtime.bb == NULL) {
+ ob->runtime.bb = MEM_callocN(sizeof(BoundBox), "DM-BoundBox");
+ }
- BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
+ BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
- ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
+ ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
}
void BKE_object_dimensions_get(Object *ob, float vec[3])
{
- BoundBox *bb = NULL;
+ BoundBox *bb = NULL;
- bb = BKE_object_boundbox_get(ob);
- if (bb) {
- float scale[3];
+ bb = BKE_object_boundbox_get(ob);
+ if (bb) {
+ float scale[3];
- mat4_to_size(scale, ob->obmat);
+ mat4_to_size(scale, ob->obmat);
- vec[0] = fabsf(scale[0]) * (bb->vec[4][0] - bb->vec[0][0]);
- vec[1] = fabsf(scale[1]) * (bb->vec[2][1] - bb->vec[0][1]);
- vec[2] = fabsf(scale[2]) * (bb->vec[1][2] - bb->vec[0][2]);
- }
- else {
- zero_v3(vec);
- }
+ vec[0] = fabsf(scale[0]) * (bb->vec[4][0] - bb->vec[0][0]);
+ vec[1] = fabsf(scale[1]) * (bb->vec[2][1] - bb->vec[0][1]);
+ vec[2] = fabsf(scale[2]) * (bb->vec[1][2] - bb->vec[0][2]);
+ }
+ else {
+ zero_v3(vec);
+ }
}
void BKE_object_dimensions_set(Object *ob, const float value[3], int axis_mask)
{
- BoundBox *bb = NULL;
+ BoundBox *bb = NULL;
- bb = BKE_object_boundbox_get(ob);
- if (bb) {
- float len[3];
+ bb = BKE_object_boundbox_get(ob);
+ if (bb) {
+ float len[3];
- len[0] = bb->vec[4][0] - bb->vec[0][0];
- len[1] = bb->vec[2][1] - bb->vec[0][1];
- len[2] = bb->vec[1][2] - bb->vec[0][2];
+ len[0] = bb->vec[4][0] - bb->vec[0][0];
+ len[1] = bb->vec[2][1] - bb->vec[0][1];
+ len[2] = bb->vec[1][2] - bb->vec[0][2];
- for (int i = 0; i < 3; i++) {
- if (((1 << i) & axis_mask) == 0) {
- if (len[i] > 0.0f) {
- ob->scale[i] = copysignf(value[i] / len[i], ob->scale[i]);
- }
- }
- }
- }
+ for (int i = 0; i < 3; i++) {
+ if (((1 << i) & axis_mask) == 0) {
+ if (len[i] > 0.0f) {
+ ob->scale[i] = copysignf(value[i] / len[i], ob->scale[i]);
+ }
+ }
+ }
+ }
}
void BKE_object_minmax(Object *ob, float min_r[3], float max_r[3], const bool use_hidden)
{
- BoundBox bb;
- float vec[3];
- bool changed = false;
-
- switch (ob->type) {
- case OB_CURVE:
- case OB_FONT:
- case OB_SURF:
- {
- bb = *BKE_curve_boundbox_get(ob);
- BKE_boundbox_minmax(&bb, ob->obmat, min_r, max_r);
- changed = true;
- break;
- }
- case OB_MESH:
- {
- bb = *BKE_mesh_boundbox_get(ob);
- BKE_boundbox_minmax(&bb, ob->obmat, min_r, max_r);
- changed = true;
- break;
- }
- case OB_GPENCIL:
- {
- bb = *BKE_gpencil_boundbox_get(ob);
- BKE_boundbox_minmax(&bb, ob->obmat, min_r, max_r);
- changed = true;
- break;
- }
- case OB_LATTICE:
- {
- Lattice *lt = ob->data;
- BPoint *bp = lt->def;
- int u, v, w;
-
- for (w = 0; w < lt->pntsw; w++) {
- for (v = 0; v < lt->pntsv; v++) {
- for (u = 0; u < lt->pntsu; u++, bp++) {
- mul_v3_m4v3(vec, ob->obmat, bp->vec);
- minmax_v3v3_v3(min_r, max_r, vec);
- }
- }
- }
- changed = true;
- break;
- }
- case OB_ARMATURE:
- {
- changed = BKE_pose_minmax(ob, min_r, max_r, use_hidden, false);
- break;
- }
- case OB_MBALL:
- {
- float ob_min[3], ob_max[3];
-
- changed = BKE_mball_minmax_ex(ob->data, ob_min, ob_max, ob->obmat, 0);
- if (changed) {
- minmax_v3v3_v3(min_r, max_r, ob_min);
- minmax_v3v3_v3(min_r, max_r, ob_max);
- }
- break;
- }
- }
-
- if (changed == false) {
- float size[3];
-
- copy_v3_v3(size, ob->scale);
- if (ob->type == OB_EMPTY) {
- mul_v3_fl(size, ob->empty_drawsize);
- }
-
- minmax_v3v3_v3(min_r, max_r, ob->obmat[3]);
-
- copy_v3_v3(vec, ob->obmat[3]);
- add_v3_v3(vec, size);
- minmax_v3v3_v3(min_r, max_r, vec);
-
- copy_v3_v3(vec, ob->obmat[3]);
- sub_v3_v3(vec, size);
- minmax_v3v3_v3(min_r, max_r, vec);
- }
+ BoundBox bb;
+ float vec[3];
+ bool changed = false;
+
+ switch (ob->type) {
+ case OB_CURVE:
+ case OB_FONT:
+ case OB_SURF: {
+ bb = *BKE_curve_boundbox_get(ob);
+ BKE_boundbox_minmax(&bb, ob->obmat, min_r, max_r);
+ changed = true;
+ break;
+ }
+ case OB_MESH: {
+ bb = *BKE_mesh_boundbox_get(ob);
+ BKE_boundbox_minmax(&bb, ob->obmat, min_r, max_r);
+ changed = true;
+ break;
+ }
+ case OB_GPENCIL: {
+ bb = *BKE_gpencil_boundbox_get(ob);
+ BKE_boundbox_minmax(&bb, ob->obmat, min_r, max_r);
+ changed = true;
+ break;
+ }
+ case OB_LATTICE: {
+ Lattice *lt = ob->data;
+ BPoint *bp = lt->def;
+ int u, v, w;
+
+ for (w = 0; w < lt->pntsw; w++) {
+ for (v = 0; v < lt->pntsv; v++) {
+ for (u = 0; u < lt->pntsu; u++, bp++) {
+ mul_v3_m4v3(vec, ob->obmat, bp->vec);
+ minmax_v3v3_v3(min_r, max_r, vec);
+ }
+ }
+ }
+ changed = true;
+ break;
+ }
+ case OB_ARMATURE: {
+ changed = BKE_pose_minmax(ob, min_r, max_r, use_hidden, false);
+ break;
+ }
+ case OB_MBALL: {
+ float ob_min[3], ob_max[3];
+
+ changed = BKE_mball_minmax_ex(ob->data, ob_min, ob_max, ob->obmat, 0);
+ if (changed) {
+ minmax_v3v3_v3(min_r, max_r, ob_min);
+ minmax_v3v3_v3(min_r, max_r, ob_max);
+ }
+ break;
+ }
+ }
+
+ if (changed == false) {
+ float size[3];
+
+ copy_v3_v3(size, ob->scale);
+ if (ob->type == OB_EMPTY) {
+ mul_v3_fl(size, ob->empty_drawsize);
+ }
+
+ minmax_v3v3_v3(min_r, max_r, ob->obmat[3]);
+
+ copy_v3_v3(vec, ob->obmat[3]);
+ add_v3_v3(vec, size);
+ minmax_v3v3_v3(min_r, max_r, vec);
+
+ copy_v3_v3(vec, ob->obmat[3]);
+ sub_v3_v3(vec, size);
+ minmax_v3v3_v3(min_r, max_r, vec);
+ }
}
void BKE_object_empty_draw_type_set(Object *ob, const int value)
{
- ob->empty_drawtype = value;
-
- if (ob->type == OB_EMPTY && ob->empty_drawtype == OB_EMPTY_IMAGE) {
- if (!ob->iuser) {
- ob->iuser = MEM_callocN(sizeof(ImageUser), "image user");
- ob->iuser->ok = 1;
- ob->iuser->flag |= IMA_ANIM_ALWAYS;
- ob->iuser->frames = 100;
- ob->iuser->sfra = 1;
- }
- }
- else {
- if (ob->iuser) {
- MEM_freeN(ob->iuser);
- ob->iuser = NULL;
- }
- }
+ ob->empty_drawtype = value;
+
+ if (ob->type == OB_EMPTY && ob->empty_drawtype == OB_EMPTY_IMAGE) {
+ if (!ob->iuser) {
+ ob->iuser = MEM_callocN(sizeof(ImageUser), "image user");
+ ob->iuser->ok = 1;
+ ob->iuser->flag |= IMA_ANIM_ALWAYS;
+ ob->iuser->frames = 100;
+ ob->iuser->sfra = 1;
+ }
+ }
+ else {
+ if (ob->iuser) {
+ MEM_freeN(ob->iuser);
+ ob->iuser = NULL;
+ }
+ }
}
bool BKE_object_empty_image_frame_is_visible_in_view3d(const Object *ob, const RegionView3D *rv3d)
{
- const char visibility_flag = ob->empty_image_visibility_flag;
- if (rv3d->is_persp) {
- return (visibility_flag & OB_EMPTY_IMAGE_HIDE_PERSPECTIVE) == 0;
- }
- else {
- return (visibility_flag & OB_EMPTY_IMAGE_HIDE_ORTHOGRAPHIC) == 0;
- }
+ const char visibility_flag = ob->empty_image_visibility_flag;
+ if (rv3d->is_persp) {
+ return (visibility_flag & OB_EMPTY_IMAGE_HIDE_PERSPECTIVE) == 0;
+ }
+ else {
+ return (visibility_flag & OB_EMPTY_IMAGE_HIDE_ORTHOGRAPHIC) == 0;
+ }
}
bool BKE_object_empty_image_data_is_visible_in_view3d(const Object *ob, const RegionView3D *rv3d)
{
- /* Caller is expected to check this. */
- BLI_assert(BKE_object_empty_image_frame_is_visible_in_view3d(ob, rv3d));
-
- const char visibility_flag = ob->empty_image_visibility_flag;
-
- if ((visibility_flag & (OB_EMPTY_IMAGE_HIDE_BACK | OB_EMPTY_IMAGE_HIDE_FRONT)) != 0) {
- float eps, dot;
- if (rv3d->is_persp) {
- /* Note, we could normalize the 'view_dir' then use 'eps'
- * however the issue with empty objects being visible when viewed from the side
- * is only noticeable in orthographic views. */
- float view_dir[3];
- sub_v3_v3v3(view_dir, rv3d->viewinv[3], ob->obmat[3]);
- dot = dot_v3v3(ob->obmat[2], view_dir);
- eps = 0.0f;
- }
- else {
- dot = dot_v3v3(ob->obmat[2], rv3d->viewinv[2]);
- eps = 1e-5f;
- }
- if (visibility_flag & OB_EMPTY_IMAGE_HIDE_BACK) {
- if (dot < eps) {
- return false;
- }
- }
- if (visibility_flag & OB_EMPTY_IMAGE_HIDE_FRONT) {
- if (dot > -eps) {
- return false;
- }
- }
- }
-
- return true;
-}
-
-bool BKE_object_minmax_dupli(Depsgraph *depsgraph, Scene *scene, Object *ob, float r_min[3], float r_max[3], const bool use_hidden)
-{
- bool ok = false;
- if ((ob->transflag & OB_DUPLI) == 0) {
- return ok;
- }
- else {
- ListBase *lb;
- DupliObject *dob;
- lb = object_duplilist(depsgraph, scene, ob);
- for (dob = lb->first; dob; dob = dob->next) {
- if ((use_hidden == false) && (dob->no_draw != 0)) {
- /* pass */
- }
- else {
- BoundBox *bb = BKE_object_boundbox_get(dob->ob);
-
- if (bb) {
- int i;
- for (i = 0; i < 8; i++) {
- float vec[3];
- mul_v3_m4v3(vec, dob->mat, bb->vec[i]);
- minmax_v3v3_v3(r_min, r_max, vec);
- }
-
- ok = true;
- }
- }
- }
- free_object_duplilist(lb); /* does restore */
- }
-
- return ok;
-}
-
-void BKE_object_foreach_display_point(
- Object *ob, float obmat[4][4],
- void (*func_cb)(const float[3], void *), void *user_data)
-{
- float co[3];
-
- if (ob->runtime.mesh_eval) {
- const Mesh *me = ob->runtime.mesh_eval;
- const MVert *mv = me->mvert;
- const int totvert = me->totvert;
- for (int i = 0; i < totvert; i++, mv++) {
- mul_v3_m4v3(co, obmat, mv->co);
- func_cb(co, user_data);
- }
- }
- else if (ob->runtime.curve_cache && ob->runtime.curve_cache->disp.first) {
- DispList *dl;
-
- for (dl = ob->runtime.curve_cache->disp.first; dl; dl = dl->next) {
- const float *v3 = dl->verts;
- int totvert = dl->nr;
- int i;
-
- for (i = 0; i < totvert; i++, v3 += 3) {
- mul_v3_m4v3(co, obmat, v3);
- func_cb(co, user_data);
- }
- }
- }
-}
-
-void BKE_scene_foreach_display_point(
- Depsgraph *depsgraph,
- void (*func_cb)(const float[3], void *), void *user_data)
-{
- DEG_OBJECT_ITER_BEGIN(
- depsgraph, ob,
- DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
- DEG_ITER_OBJECT_FLAG_VISIBLE |
- DEG_ITER_OBJECT_FLAG_DUPLI)
- {
- if ((ob->base_flag & BASE_SELECTED) != 0) {
- BKE_object_foreach_display_point(ob, ob->obmat, func_cb, user_data);
- }
- }
- DEG_OBJECT_ITER_END;
+ /* Caller is expected to check this. */
+ BLI_assert(BKE_object_empty_image_frame_is_visible_in_view3d(ob, rv3d));
+
+ const char visibility_flag = ob->empty_image_visibility_flag;
+
+ if ((visibility_flag & (OB_EMPTY_IMAGE_HIDE_BACK | OB_EMPTY_IMAGE_HIDE_FRONT)) != 0) {
+ float eps, dot;
+ if (rv3d->is_persp) {
+ /* Note, we could normalize the 'view_dir' then use 'eps'
+ * however the issue with empty objects being visible when viewed from the side
+ * is only noticeable in orthographic views. */
+ float view_dir[3];
+ sub_v3_v3v3(view_dir, rv3d->viewinv[3], ob->obmat[3]);
+ dot = dot_v3v3(ob->obmat[2], view_dir);
+ eps = 0.0f;
+ }
+ else {
+ dot = dot_v3v3(ob->obmat[2], rv3d->viewinv[2]);
+ eps = 1e-5f;
+ }
+ if (visibility_flag & OB_EMPTY_IMAGE_HIDE_BACK) {
+ if (dot < eps) {
+ return false;
+ }
+ }
+ if (visibility_flag & OB_EMPTY_IMAGE_HIDE_FRONT) {
+ if (dot > -eps) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool BKE_object_minmax_dupli(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ float r_min[3],
+ float r_max[3],
+ const bool use_hidden)
+{
+ bool ok = false;
+ if ((ob->transflag & OB_DUPLI) == 0) {
+ return ok;
+ }
+ else {
+ ListBase *lb;
+ DupliObject *dob;
+ lb = object_duplilist(depsgraph, scene, ob);
+ for (dob = lb->first; dob; dob = dob->next) {
+ if ((use_hidden == false) && (dob->no_draw != 0)) {
+ /* pass */
+ }
+ else {
+ BoundBox *bb = BKE_object_boundbox_get(dob->ob);
+
+ if (bb) {
+ int i;
+ for (i = 0; i < 8; i++) {
+ float vec[3];
+ mul_v3_m4v3(vec, dob->mat, bb->vec[i]);
+ minmax_v3v3_v3(r_min, r_max, vec);
+ }
+
+ ok = true;
+ }
+ }
+ }
+ free_object_duplilist(lb); /* does restore */
+ }
+
+ return ok;
+}
+
+void BKE_object_foreach_display_point(Object *ob,
+ float obmat[4][4],
+ void (*func_cb)(const float[3], void *),
+ void *user_data)
+{
+ float co[3];
+
+ if (ob->runtime.mesh_eval) {
+ const Mesh *me = ob->runtime.mesh_eval;
+ const MVert *mv = me->mvert;
+ const int totvert = me->totvert;
+ for (int i = 0; i < totvert; i++, mv++) {
+ mul_v3_m4v3(co, obmat, mv->co);
+ func_cb(co, user_data);
+ }
+ }
+ else if (ob->runtime.curve_cache && ob->runtime.curve_cache->disp.first) {
+ DispList *dl;
+
+ for (dl = ob->runtime.curve_cache->disp.first; dl; dl = dl->next) {
+ const float *v3 = dl->verts;
+ int totvert = dl->nr;
+ int i;
+
+ for (i = 0; i < totvert; i++, v3 += 3) {
+ mul_v3_m4v3(co, obmat, v3);
+ func_cb(co, user_data);
+ }
+ }
+ }
+}
+
+void BKE_scene_foreach_display_point(Depsgraph *depsgraph,
+ void (*func_cb)(const float[3], void *),
+ void *user_data)
+{
+ DEG_OBJECT_ITER_BEGIN (depsgraph,
+ ob,
+ DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | DEG_ITER_OBJECT_FLAG_VISIBLE |
+ DEG_ITER_OBJECT_FLAG_DUPLI) {
+ if ((ob->base_flag & BASE_SELECTED) != 0) {
+ BKE_object_foreach_display_point(ob, ob->obmat, func_cb, user_data);
+ }
+ }
+ DEG_OBJECT_ITER_END;
}
/* copied from DNA_object_types.h */
typedef struct ObTfmBack {
- float loc[3], dloc[3];
- /** scale and delta scale. */
- float scale[3], dscale[3];
- /** euler rotation. */
- float rot[3], drot[3];
- /** quaternion rotation. */
- float quat[4], dquat[4];
- /** axis angle rotation - axis part. */
- float rotAxis[3], drotAxis[3];
- /** axis angle rotation - angle part. */
- float rotAngle, drotAngle;
- /** final worldspace matrix with constraints & animsys applied. */
- float obmat[4][4];
- /** inverse result of parent, so that object doesn't 'stick' to parent. */
- float parentinv[4][4];
- /** inverse result of constraints. doesn't include effect of parent or object local transform. */
- float constinv[4][4];
- /** inverse matrix of 'obmat' for during render, temporally: ipokeys of transform. */
- float imat[4][4];
+ float loc[3], dloc[3];
+ /** scale and delta scale. */
+ float scale[3], dscale[3];
+ /** euler rotation. */
+ float rot[3], drot[3];
+ /** quaternion rotation. */
+ float quat[4], dquat[4];
+ /** axis angle rotation - axis part. */
+ float rotAxis[3], drotAxis[3];
+ /** axis angle rotation - angle part. */
+ float rotAngle, drotAngle;
+ /** final worldspace matrix with constraints & animsys applied. */
+ float obmat[4][4];
+ /** inverse result of parent, so that object doesn't 'stick' to parent. */
+ float parentinv[4][4];
+ /** inverse result of constraints. doesn't include effect of parent or object local transform. */
+ float constinv[4][4];
+ /** inverse matrix of 'obmat' for during render, temporally: ipokeys of transform. */
+ float imat[4][4];
} ObTfmBack;
void *BKE_object_tfm_backup(Object *ob)
{
- ObTfmBack *obtfm = MEM_mallocN(sizeof(ObTfmBack), "ObTfmBack");
- copy_v3_v3(obtfm->loc, ob->loc);
- copy_v3_v3(obtfm->dloc, ob->dloc);
- copy_v3_v3(obtfm->scale, ob->scale);
- copy_v3_v3(obtfm->dscale, ob->dscale);
- copy_v3_v3(obtfm->rot, ob->rot);
- copy_v3_v3(obtfm->drot, ob->drot);
- copy_qt_qt(obtfm->quat, ob->quat);
- copy_qt_qt(obtfm->dquat, ob->dquat);
- copy_v3_v3(obtfm->rotAxis, ob->rotAxis);
- copy_v3_v3(obtfm->drotAxis, ob->drotAxis);
- obtfm->rotAngle = ob->rotAngle;
- obtfm->drotAngle = ob->drotAngle;
- copy_m4_m4(obtfm->obmat, ob->obmat);
- copy_m4_m4(obtfm->parentinv, ob->parentinv);
- copy_m4_m4(obtfm->constinv, ob->constinv);
- copy_m4_m4(obtfm->imat, ob->imat);
-
- return (void *)obtfm;
+ ObTfmBack *obtfm = MEM_mallocN(sizeof(ObTfmBack), "ObTfmBack");
+ copy_v3_v3(obtfm->loc, ob->loc);
+ copy_v3_v3(obtfm->dloc, ob->dloc);
+ copy_v3_v3(obtfm->scale, ob->scale);
+ copy_v3_v3(obtfm->dscale, ob->dscale);
+ copy_v3_v3(obtfm->rot, ob->rot);
+ copy_v3_v3(obtfm->drot, ob->drot);
+ copy_qt_qt(obtfm->quat, ob->quat);
+ copy_qt_qt(obtfm->dquat, ob->dquat);
+ copy_v3_v3(obtfm->rotAxis, ob->rotAxis);
+ copy_v3_v3(obtfm->drotAxis, ob->drotAxis);
+ obtfm->rotAngle = ob->rotAngle;
+ obtfm->drotAngle = ob->drotAngle;
+ copy_m4_m4(obtfm->obmat, ob->obmat);
+ copy_m4_m4(obtfm->parentinv, ob->parentinv);
+ copy_m4_m4(obtfm->constinv, ob->constinv);
+ copy_m4_m4(obtfm->imat, ob->imat);
+
+ return (void *)obtfm;
}
void BKE_object_tfm_restore(Object *ob, void *obtfm_pt)
{
- ObTfmBack *obtfm = (ObTfmBack *)obtfm_pt;
- copy_v3_v3(ob->loc, obtfm->loc);
- copy_v3_v3(ob->dloc, obtfm->dloc);
- copy_v3_v3(ob->scale, obtfm->scale);
- copy_v3_v3(ob->dscale, obtfm->dscale);
- copy_v3_v3(ob->rot, obtfm->rot);
- copy_v3_v3(ob->drot, obtfm->drot);
- copy_qt_qt(ob->quat, obtfm->quat);
- copy_qt_qt(ob->dquat, obtfm->dquat);
- copy_v3_v3(ob->rotAxis, obtfm->rotAxis);
- copy_v3_v3(ob->drotAxis, obtfm->drotAxis);
- ob->rotAngle = obtfm->rotAngle;
- ob->drotAngle = obtfm->drotAngle;
- copy_m4_m4(ob->obmat, obtfm->obmat);
- copy_m4_m4(ob->parentinv, obtfm->parentinv);
- copy_m4_m4(ob->constinv, obtfm->constinv);
- copy_m4_m4(ob->imat, obtfm->imat);
+ ObTfmBack *obtfm = (ObTfmBack *)obtfm_pt;
+ copy_v3_v3(ob->loc, obtfm->loc);
+ copy_v3_v3(ob->dloc, obtfm->dloc);
+ copy_v3_v3(ob->scale, obtfm->scale);
+ copy_v3_v3(ob->dscale, obtfm->dscale);
+ copy_v3_v3(ob->rot, obtfm->rot);
+ copy_v3_v3(ob->drot, obtfm->drot);
+ copy_qt_qt(ob->quat, obtfm->quat);
+ copy_qt_qt(ob->dquat, obtfm->dquat);
+ copy_v3_v3(ob->rotAxis, obtfm->rotAxis);
+ copy_v3_v3(ob->drotAxis, obtfm->drotAxis);
+ ob->rotAngle = obtfm->rotAngle;
+ ob->drotAngle = obtfm->drotAngle;
+ copy_m4_m4(ob->obmat, obtfm->obmat);
+ copy_m4_m4(ob->parentinv, obtfm->parentinv);
+ copy_m4_m4(ob->constinv, obtfm->constinv);
+ copy_m4_m4(ob->imat, obtfm->imat);
}
bool BKE_object_parent_loop_check(const Object *par, const Object *ob)
{
- /* test if 'ob' is a parent somewhere in par's parents */
- if (par == NULL) return false;
- if (ob == par) return true;
- return BKE_object_parent_loop_check(par->parent, ob);
+ /* test if 'ob' is a parent somewhere in par's parents */
+ if (par == NULL)
+ return false;
+ if (ob == par)
+ return true;
+ return BKE_object_parent_loop_check(par->parent, ob);
}
static void object_handle_update_proxy(Depsgraph *depsgraph,
@@ -3067,21 +3120,21 @@ static void object_handle_update_proxy(Depsgraph *depsgraph,
Object *object,
const bool do_proxy_update)
{
- /* The case when this is a collection proxy, object_update is called in collection.c */
- if (object->proxy == NULL) {
- return;
- }
- /* set pointer in library proxy target, for copying, but restore it */
- object->proxy->proxy_from = object;
- // printf("set proxy pointer for later collection stuff %s\n", ob->id.name);
+ /* The case when this is a collection proxy, object_update is called in collection.c */
+ if (object->proxy == NULL) {
+ return;
+ }
+ /* set pointer in library proxy target, for copying, but restore it */
+ object->proxy->proxy_from = object;
+ // printf("set proxy pointer for later collection stuff %s\n", ob->id.name);
- /* the no-group proxy case, we call update */
- if (object->proxy_group == NULL) {
- if (do_proxy_update) {
- // printf("call update, lib ob %s proxy %s\n", ob->proxy->id.name, ob->id.name);
- BKE_object_handle_update(depsgraph, scene, object->proxy);
- }
- }
+ /* the no-group proxy case, we call update */
+ if (object->proxy_group == NULL) {
+ if (do_proxy_update) {
+ // printf("call update, lib ob %s proxy %s\n", ob->proxy->id.name, ob->id.name);
+ BKE_object_handle_update(depsgraph, scene, object->proxy);
+ }
+ }
}
/* proxy rule: lib_object->proxy_from == the one we borrow from, only set temporal and cleared here */
@@ -3093,58 +3146,58 @@ static void object_handle_update_proxy(Depsgraph *depsgraph,
/* requires flags to be set! */
/* Ideally we shouldn't have to pass the rigid body world, but need bigger restructuring to avoid id */
void BKE_object_handle_update_ex(Depsgraph *depsgraph,
- Scene *scene, Object *ob,
+ Scene *scene,
+ Object *ob,
RigidBodyWorld *rbw,
const bool do_proxy_update)
{
- const ID *object_data = ob->data;
- const bool recalc_object = (ob->id.recalc & ID_RECALC_ALL) != 0;
- const bool recalc_data =
- (object_data != NULL) ? ((object_data->recalc & ID_RECALC_ALL) != 0)
- : 0;
- if (!recalc_object && ! recalc_data) {
- object_handle_update_proxy(depsgraph, scene, ob, do_proxy_update);
- return;
- }
- /* Speed optimization for animation lookups. */
- if (ob->pose != NULL) {
- BKE_pose_channels_hash_make(ob->pose);
- if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
- BKE_pose_update_constraint_flags(ob->pose);
- }
- }
- if (recalc_data) {
- if (ob->type == OB_ARMATURE) {
- /* this happens for reading old files and to match library armatures
- * with poses we do it ahead of BKE_object_where_is_calc to ensure animation
- * is evaluated on the rebuilt pose, otherwise we get incorrect poses
- * on file load */
- if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) {
- /* No need to pass bmain here, we assume we do not need to rebuild DEG from here... */
- BKE_pose_rebuild(NULL, ob, ob->data, true);
- }
- }
- }
- /* XXX new animsys warning: depsgraph tag ID_RECALC_GEOMETRY should not skip drivers,
- * which is only in BKE_object_where_is_calc now */
- /* XXX: should this case be ID_RECALC_TRANSFORM instead? */
- if (recalc_object || recalc_data) {
- if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) {
- printf("recalcob %s\n", ob->id.name + 2);
- }
- /* Handle proxy copy for target. */
- if (!BKE_object_eval_proxy_copy(depsgraph, ob)) {
- BKE_object_where_is_calc_ex(depsgraph, scene, rbw, ob, NULL);
- }
- }
-
- if (recalc_data) {
- BKE_object_handle_data_update(depsgraph, scene, ob);
- }
-
- ob->id.recalc &= ID_RECALC_ALL;
-
- object_handle_update_proxy(depsgraph, scene, ob, do_proxy_update);
+ const ID *object_data = ob->data;
+ const bool recalc_object = (ob->id.recalc & ID_RECALC_ALL) != 0;
+ const bool recalc_data = (object_data != NULL) ? ((object_data->recalc & ID_RECALC_ALL) != 0) :
+ 0;
+ if (!recalc_object && !recalc_data) {
+ object_handle_update_proxy(depsgraph, scene, ob, do_proxy_update);
+ return;
+ }
+ /* Speed optimization for animation lookups. */
+ if (ob->pose != NULL) {
+ BKE_pose_channels_hash_make(ob->pose);
+ if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
+ BKE_pose_update_constraint_flags(ob->pose);
+ }
+ }
+ if (recalc_data) {
+ if (ob->type == OB_ARMATURE) {
+ /* this happens for reading old files and to match library armatures
+ * with poses we do it ahead of BKE_object_where_is_calc to ensure animation
+ * is evaluated on the rebuilt pose, otherwise we get incorrect poses
+ * on file load */
+ if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) {
+ /* No need to pass bmain here, we assume we do not need to rebuild DEG from here... */
+ BKE_pose_rebuild(NULL, ob, ob->data, true);
+ }
+ }
+ }
+ /* XXX new animsys warning: depsgraph tag ID_RECALC_GEOMETRY should not skip drivers,
+ * which is only in BKE_object_where_is_calc now */
+ /* XXX: should this case be ID_RECALC_TRANSFORM instead? */
+ if (recalc_object || recalc_data) {
+ if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) {
+ printf("recalcob %s\n", ob->id.name + 2);
+ }
+ /* Handle proxy copy for target. */
+ if (!BKE_object_eval_proxy_copy(depsgraph, ob)) {
+ BKE_object_where_is_calc_ex(depsgraph, scene, rbw, ob, NULL);
+ }
+ }
+
+ if (recalc_data) {
+ BKE_object_handle_data_update(depsgraph, scene, ob);
+ }
+
+ ob->id.recalc &= ID_RECALC_ALL;
+
+ object_handle_update_proxy(depsgraph, scene, ob, do_proxy_update);
}
/**
@@ -3156,106 +3209,112 @@ void BKE_object_handle_update_ex(Depsgraph *depsgraph,
*/
void BKE_object_handle_update(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- BKE_object_handle_update_ex(depsgraph, scene, ob, NULL, true);
+ BKE_object_handle_update_ex(depsgraph, scene, ob, NULL, true);
}
void BKE_object_sculpt_data_create(Object *ob)
{
- BLI_assert((ob->sculpt == NULL) && (ob->mode & OB_MODE_ALL_SCULPT));
- ob->sculpt = MEM_callocN(sizeof(SculptSession), __func__);
- ob->sculpt->mode_type = ob->mode;
+ BLI_assert((ob->sculpt == NULL) && (ob->mode & OB_MODE_ALL_SCULPT));
+ ob->sculpt = MEM_callocN(sizeof(SculptSession), __func__);
+ ob->sculpt->mode_type = ob->mode;
}
void BKE_object_sculpt_modifiers_changed(Object *ob)
{
- SculptSession *ss = ob->sculpt;
-
- if (ss && ss->building_vp_handle == false) {
- if (!ss->cache) {
- /* we free pbvh on changes, except during sculpt since it can't deal with
- * changing PVBH node organization, we hope topology does not change in
- * the meantime .. weak */
- if (ss->pbvh) {
- BKE_pbvh_free(ss->pbvh);
- ss->pbvh = NULL;
- }
-
- BKE_sculptsession_free_deformMats(ob->sculpt);
-
- /* In vertex/weight paint, force maps to be rebuilt. */
- BKE_sculptsession_free_vwpaint_data(ob->sculpt);
- }
- else {
- PBVHNode **nodes;
- int n, totnode;
-
- BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
-
- for (n = 0; n < totnode; n++)
- BKE_pbvh_node_mark_update(nodes[n]);
-
- MEM_freeN(nodes);
- }
- }
-}
-
-int BKE_object_obdata_texspace_get(Object *ob, short **r_texflag, float **r_loc, float **r_size, float **r_rot)
-{
-
- if (ob->data == NULL)
- return 0;
-
- switch (GS(((ID *)ob->data)->name)) {
- case ID_ME:
- {
- BKE_mesh_texspace_get_reference((Mesh *)ob->data, r_texflag, r_loc, r_rot, r_size);
- break;
- }
- case ID_CU:
- {
- Curve *cu = ob->data;
- if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) {
- BKE_curve_texspace_calc(cu);
- }
- if (r_texflag) *r_texflag = &cu->texflag;
- if (r_loc) *r_loc = cu->loc;
- if (r_size) *r_size = cu->size;
- if (r_rot) *r_rot = cu->rot;
- break;
- }
- case ID_MB:
- {
- MetaBall *mb = ob->data;
- if (r_texflag) *r_texflag = &mb->texflag;
- if (r_loc) *r_loc = mb->loc;
- if (r_size) *r_size = mb->size;
- if (r_rot) *r_rot = mb->rot;
- break;
- }
- default:
- return 0;
- }
- return 1;
+ SculptSession *ss = ob->sculpt;
+
+ if (ss && ss->building_vp_handle == false) {
+ if (!ss->cache) {
+ /* we free pbvh on changes, except during sculpt since it can't deal with
+ * changing PVBH node organization, we hope topology does not change in
+ * the meantime .. weak */
+ if (ss->pbvh) {
+ BKE_pbvh_free(ss->pbvh);
+ ss->pbvh = NULL;
+ }
+
+ BKE_sculptsession_free_deformMats(ob->sculpt);
+
+ /* In vertex/weight paint, force maps to be rebuilt. */
+ BKE_sculptsession_free_vwpaint_data(ob->sculpt);
+ }
+ else {
+ PBVHNode **nodes;
+ int n, totnode;
+
+ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+
+ for (n = 0; n < totnode; n++)
+ BKE_pbvh_node_mark_update(nodes[n]);
+
+ MEM_freeN(nodes);
+ }
+ }
+}
+
+int BKE_object_obdata_texspace_get(
+ Object *ob, short **r_texflag, float **r_loc, float **r_size, float **r_rot)
+{
+
+ if (ob->data == NULL)
+ return 0;
+
+ switch (GS(((ID *)ob->data)->name)) {
+ case ID_ME: {
+ BKE_mesh_texspace_get_reference((Mesh *)ob->data, r_texflag, r_loc, r_rot, r_size);
+ break;
+ }
+ case ID_CU: {
+ Curve *cu = ob->data;
+ if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) {
+ BKE_curve_texspace_calc(cu);
+ }
+ if (r_texflag)
+ *r_texflag = &cu->texflag;
+ if (r_loc)
+ *r_loc = cu->loc;
+ if (r_size)
+ *r_size = cu->size;
+ if (r_rot)
+ *r_rot = cu->rot;
+ break;
+ }
+ case ID_MB: {
+ MetaBall *mb = ob->data;
+ if (r_texflag)
+ *r_texflag = &mb->texflag;
+ if (r_loc)
+ *r_loc = mb->loc;
+ if (r_size)
+ *r_size = mb->size;
+ if (r_rot)
+ *r_rot = mb->rot;
+ break;
+ }
+ default:
+ return 0;
+ }
+ return 1;
}
/** Get evaluated mesh for given (main, original) object and depsgraph. */
Mesh *BKE_object_get_evaluated_mesh(const Depsgraph *depsgraph, Object *ob)
{
- Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
- return ob_eval->runtime.mesh_eval;
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ return ob_eval->runtime.mesh_eval;
}
/* Get object's mesh with all modifiers applied. */
Mesh *BKE_object_get_final_mesh(Object *object)
{
- if (object->runtime.mesh_eval != NULL) {
- BLI_assert((object->id.tag & LIB_TAG_COPIED_ON_WRITE) != 0);
- BLI_assert(object->runtime.mesh_eval == object->data);
- BLI_assert((object->runtime.mesh_eval->id.tag & LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT) != 0);
- return object->runtime.mesh_eval;
- }
- /* Wasn't evaluated yet. */
- return object->data;
+ if (object->runtime.mesh_eval != NULL) {
+ BLI_assert((object->id.tag & LIB_TAG_COPIED_ON_WRITE) != 0);
+ BLI_assert(object->runtime.mesh_eval == object->data);
+ BLI_assert((object->runtime.mesh_eval->id.tag & LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT) != 0);
+ return object->runtime.mesh_eval;
+ }
+ /* Wasn't evaluated yet. */
+ return object->data;
}
/* Get mesh which is not affected by modifiers:
@@ -3266,17 +3325,17 @@ Mesh *BKE_object_get_final_mesh(Object *object)
*/
Mesh *BKE_object_get_pre_modified_mesh(Object *object)
{
- if (object->runtime.mesh_orig != NULL) {
- BLI_assert(object->id.tag & LIB_TAG_COPIED_ON_WRITE);
- BLI_assert(object->id.orig_id != NULL);
- BLI_assert(object->runtime.mesh_orig->id.orig_id == ((Object *)object->id.orig_id)->data);
- Mesh *result = object->runtime.mesh_orig;
- BLI_assert((result->id.tag & LIB_TAG_COPIED_ON_WRITE) != 0);
- BLI_assert((result->id.tag & LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT) == 0);
- return result;
- }
- BLI_assert((object->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0);
- return object->data;
+ if (object->runtime.mesh_orig != NULL) {
+ BLI_assert(object->id.tag & LIB_TAG_COPIED_ON_WRITE);
+ BLI_assert(object->id.orig_id != NULL);
+ BLI_assert(object->runtime.mesh_orig->id.orig_id == ((Object *)object->id.orig_id)->data);
+ Mesh *result = object->runtime.mesh_orig;
+ BLI_assert((result->id.tag & LIB_TAG_COPIED_ON_WRITE) != 0);
+ BLI_assert((result->id.tag & LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT) == 0);
+ return result;
+ }
+ BLI_assert((object->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0);
+ return object->data;
}
/* Get a mesh which corresponds to very very original mesh from bmain.
@@ -3286,73 +3345,76 @@ Mesh *BKE_object_get_pre_modified_mesh(Object *object)
*/
Mesh *BKE_object_get_original_mesh(Object *object)
{
- Mesh *result = NULL;
- if (object->id.orig_id == NULL) {
- BLI_assert((object->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0);
- result = object->data;
- }
- else {
- BLI_assert((object->id.tag & LIB_TAG_COPIED_ON_WRITE) != 0);
- result = ((Object *)object->id.orig_id)->data;
- }
- BLI_assert(result != NULL);
- BLI_assert((result->id.tag & (LIB_TAG_COPIED_ON_WRITE | LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT)) == 0);
- return result;
+ Mesh *result = NULL;
+ if (object->id.orig_id == NULL) {
+ BLI_assert((object->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0);
+ result = object->data;
+ }
+ else {
+ BLI_assert((object->id.tag & LIB_TAG_COPIED_ON_WRITE) != 0);
+ result = ((Object *)object->id.orig_id)->data;
+ }
+ BLI_assert(result != NULL);
+ BLI_assert((result->id.tag & (LIB_TAG_COPIED_ON_WRITE | LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT)) ==
+ 0);
+ return result;
}
static int pc_cmp(const void *a, const void *b)
{
- const LinkData *ad = a, *bd = b;
- if (POINTER_AS_INT(ad->data) > POINTER_AS_INT(bd->data))
- return 1;
- else return 0;
+ const LinkData *ad = a, *bd = b;
+ if (POINTER_AS_INT(ad->data) > POINTER_AS_INT(bd->data))
+ return 1;
+ else
+ return 0;
}
int BKE_object_insert_ptcache(Object *ob)
{
- LinkData *link = NULL;
- int i = 0;
+ LinkData *link = NULL;
+ int i = 0;
- BLI_listbase_sort(&ob->pc_ids, pc_cmp);
+ BLI_listbase_sort(&ob->pc_ids, pc_cmp);
- for (link = ob->pc_ids.first, i = 0; link; link = link->next, i++) {
- int index = POINTER_AS_INT(link->data);
+ for (link = ob->pc_ids.first, i = 0; link; link = link->next, i++) {
+ int index = POINTER_AS_INT(link->data);
- if (i < index)
- break;
- }
+ if (i < index)
+ break;
+ }
- link = MEM_callocN(sizeof(LinkData), "PCLink");
- link->data = POINTER_FROM_INT(i);
- BLI_addtail(&ob->pc_ids, link);
+ link = MEM_callocN(sizeof(LinkData), "PCLink");
+ link->data = POINTER_FROM_INT(i);
+ BLI_addtail(&ob->pc_ids, link);
- return i;
+ return i;
}
static int pc_findindex(ListBase *listbase, int index)
{
- LinkData *link = NULL;
- int number = 0;
+ LinkData *link = NULL;
+ int number = 0;
- if (listbase == NULL) return -1;
+ if (listbase == NULL)
+ return -1;
- link = listbase->first;
- while (link) {
- if (POINTER_AS_INT(link->data) == index)
- return number;
+ link = listbase->first;
+ while (link) {
+ if (POINTER_AS_INT(link->data) == index)
+ return number;
- number++;
- link = link->next;
- }
+ number++;
+ link = link->next;
+ }
- return -1;
+ return -1;
}
void BKE_object_delete_ptcache(Object *ob, int index)
{
- int list_index = pc_findindex(&ob->pc_ids, index);
- LinkData *link = BLI_findlink(&ob->pc_ids, list_index);
- BLI_freelinkN(&ob->pc_ids, link);
+ int list_index = pc_findindex(&ob->pc_ids, index);
+ LinkData *link = BLI_findlink(&ob->pc_ids, list_index);
+ BLI_freelinkN(&ob->pc_ids, link);
}
/* shape key utility function */
@@ -3360,258 +3422,261 @@ void BKE_object_delete_ptcache(Object *ob, int index)
/************************* Mesh ************************/
static KeyBlock *insert_meshkey(Main *bmain, Object *ob, const char *name, const bool from_mix)
{
- Mesh *me = ob->data;
- Key *key = me->key;
- KeyBlock *kb;
- int newkey = 0;
-
- if (key == NULL) {
- key = me->key = BKE_key_add(bmain, (ID *)me);
- key->type = KEY_RELATIVE;
- newkey = 1;
- }
-
- if (newkey || from_mix == false) {
- /* create from mesh */
- kb = BKE_keyblock_add_ctime(key, name, false);
- BKE_keyblock_convert_from_mesh(me, key, kb);
- }
- else {
- /* copy from current values */
- int totelem;
- float *data = BKE_key_evaluate_object(ob, &totelem);
-
- /* create new block with prepared data */
- kb = BKE_keyblock_add_ctime(key, name, false);
- kb->data = data;
- kb->totelem = totelem;
- }
-
- return kb;
+ Mesh *me = ob->data;
+ Key *key = me->key;
+ KeyBlock *kb;
+ int newkey = 0;
+
+ if (key == NULL) {
+ key = me->key = BKE_key_add(bmain, (ID *)me);
+ key->type = KEY_RELATIVE;
+ newkey = 1;
+ }
+
+ if (newkey || from_mix == false) {
+ /* create from mesh */
+ kb = BKE_keyblock_add_ctime(key, name, false);
+ BKE_keyblock_convert_from_mesh(me, key, kb);
+ }
+ else {
+ /* copy from current values */
+ int totelem;
+ float *data = BKE_key_evaluate_object(ob, &totelem);
+
+ /* create new block with prepared data */
+ kb = BKE_keyblock_add_ctime(key, name, false);
+ kb->data = data;
+ kb->totelem = totelem;
+ }
+
+ return kb;
}
/************************* Lattice ************************/
static KeyBlock *insert_lattkey(Main *bmain, Object *ob, const char *name, const bool from_mix)
{
- Lattice *lt = ob->data;
- Key *key = lt->key;
- KeyBlock *kb;
- int newkey = 0;
-
- if (key == NULL) {
- key = lt->key = BKE_key_add(bmain, (ID *)lt);
- key->type = KEY_RELATIVE;
- newkey = 1;
- }
-
- if (newkey || from_mix == false) {
- kb = BKE_keyblock_add_ctime(key, name, false);
- if (!newkey) {
- KeyBlock *basekb = (KeyBlock *)key->block.first;
- kb->data = MEM_dupallocN(basekb->data);
- kb->totelem = basekb->totelem;
- }
- else {
- BKE_keyblock_convert_from_lattice(lt, kb);
- }
- }
- else {
- /* copy from current values */
- int totelem;
- float *data = BKE_key_evaluate_object(ob, &totelem);
-
- /* create new block with prepared data */
- kb = BKE_keyblock_add_ctime(key, name, false);
- kb->totelem = totelem;
- kb->data = data;
- }
-
- return kb;
+ Lattice *lt = ob->data;
+ Key *key = lt->key;
+ KeyBlock *kb;
+ int newkey = 0;
+
+ if (key == NULL) {
+ key = lt->key = BKE_key_add(bmain, (ID *)lt);
+ key->type = KEY_RELATIVE;
+ newkey = 1;
+ }
+
+ if (newkey || from_mix == false) {
+ kb = BKE_keyblock_add_ctime(key, name, false);
+ if (!newkey) {
+ KeyBlock *basekb = (KeyBlock *)key->block.first;
+ kb->data = MEM_dupallocN(basekb->data);
+ kb->totelem = basekb->totelem;
+ }
+ else {
+ BKE_keyblock_convert_from_lattice(lt, kb);
+ }
+ }
+ else {
+ /* copy from current values */
+ int totelem;
+ float *data = BKE_key_evaluate_object(ob, &totelem);
+
+ /* create new block with prepared data */
+ kb = BKE_keyblock_add_ctime(key, name, false);
+ kb->totelem = totelem;
+ kb->data = data;
+ }
+
+ return kb;
}
/************************* Curve ************************/
static KeyBlock *insert_curvekey(Main *bmain, Object *ob, const char *name, const bool from_mix)
{
- Curve *cu = ob->data;
- Key *key = cu->key;
- KeyBlock *kb;
- ListBase *lb = BKE_curve_nurbs_get(cu);
- int newkey = 0;
-
- if (key == NULL) {
- key = cu->key = BKE_key_add(bmain, (ID *)cu);
- key->type = KEY_RELATIVE;
- newkey = 1;
- }
-
- if (newkey || from_mix == false) {
- /* create from curve */
- kb = BKE_keyblock_add_ctime(key, name, false);
- if (!newkey) {
- KeyBlock *basekb = (KeyBlock *)key->block.first;
- kb->data = MEM_dupallocN(basekb->data);
- kb->totelem = basekb->totelem;
- }
- else {
- BKE_keyblock_convert_from_curve(cu, kb, lb);
- }
- }
- else {
- /* copy from current values */
- int totelem;
- float *data = BKE_key_evaluate_object(ob, &totelem);
-
- /* create new block with prepared data */
- kb = BKE_keyblock_add_ctime(key, name, false);
- kb->totelem = totelem;
- kb->data = data;
- }
-
- return kb;
-}
-
-KeyBlock *BKE_object_shapekey_insert(Main *bmain, Object *ob, const char *name, const bool from_mix)
-{
- switch (ob->type) {
- case OB_MESH:
- return insert_meshkey(bmain, ob, name, from_mix);
- case OB_CURVE:
- case OB_SURF:
- return insert_curvekey(bmain, ob, name, from_mix);
- case OB_LATTICE:
- return insert_lattkey(bmain, ob, name, from_mix);
- default:
- return NULL;
- }
-
+ Curve *cu = ob->data;
+ Key *key = cu->key;
+ KeyBlock *kb;
+ ListBase *lb = BKE_curve_nurbs_get(cu);
+ int newkey = 0;
+
+ if (key == NULL) {
+ key = cu->key = BKE_key_add(bmain, (ID *)cu);
+ key->type = KEY_RELATIVE;
+ newkey = 1;
+ }
+
+ if (newkey || from_mix == false) {
+ /* create from curve */
+ kb = BKE_keyblock_add_ctime(key, name, false);
+ if (!newkey) {
+ KeyBlock *basekb = (KeyBlock *)key->block.first;
+ kb->data = MEM_dupallocN(basekb->data);
+ kb->totelem = basekb->totelem;
+ }
+ else {
+ BKE_keyblock_convert_from_curve(cu, kb, lb);
+ }
+ }
+ else {
+ /* copy from current values */
+ int totelem;
+ float *data = BKE_key_evaluate_object(ob, &totelem);
+
+ /* create new block with prepared data */
+ kb = BKE_keyblock_add_ctime(key, name, false);
+ kb->totelem = totelem;
+ kb->data = data;
+ }
+
+ return kb;
+}
+
+KeyBlock *BKE_object_shapekey_insert(Main *bmain,
+ Object *ob,
+ const char *name,
+ const bool from_mix)
+{
+ switch (ob->type) {
+ case OB_MESH:
+ return insert_meshkey(bmain, ob, name, from_mix);
+ case OB_CURVE:
+ case OB_SURF:
+ return insert_curvekey(bmain, ob, name, from_mix);
+ case OB_LATTICE:
+ return insert_lattkey(bmain, ob, name, from_mix);
+ default:
+ return NULL;
+ }
}
bool BKE_object_shapekey_free(Main *bmain, Object *ob)
{
- Key **key_p, *key;
+ Key **key_p, *key;
- key_p = BKE_key_from_object_p(ob);
- if (ELEM(NULL, key_p, *key_p)) {
- return false;
- }
+ key_p = BKE_key_from_object_p(ob);
+ if (ELEM(NULL, key_p, *key_p)) {
+ return false;
+ }
- key = *key_p;
- *key_p = NULL;
+ key = *key_p;
+ *key_p = NULL;
- BKE_id_free_us(bmain, key);
+ BKE_id_free_us(bmain, key);
- return false;
+ return false;
}
bool BKE_object_shapekey_remove(Main *bmain, Object *ob, KeyBlock *kb)
{
- KeyBlock *rkb;
- Key *key = BKE_key_from_object(ob);
- short kb_index;
-
- if (key == NULL) {
- return false;
- }
-
- kb_index = BLI_findindex(&key->block, kb);
- BLI_assert(kb_index != -1);
-
- for (rkb = key->block.first; rkb; rkb = rkb->next) {
- if (rkb->relative == kb_index) {
- /* remap to the 'Basis' */
- rkb->relative = 0;
- }
- else if (rkb->relative >= kb_index) {
- /* Fix positional shift of the keys when kb is deleted from the list */
- rkb->relative -= 1;
- }
- }
-
- BLI_remlink(&key->block, kb);
- key->totkey--;
- if (key->refkey == kb) {
- key->refkey = key->block.first;
-
- if (key->refkey) {
- /* apply new basis key on original data */
- switch (ob->type) {
- case OB_MESH:
- BKE_keyblock_convert_to_mesh(key->refkey, ob->data);
- break;
- case OB_CURVE:
- case OB_SURF:
- BKE_keyblock_convert_to_curve(key->refkey, ob->data, BKE_curve_nurbs_get(ob->data));
- break;
- case OB_LATTICE:
- BKE_keyblock_convert_to_lattice(key->refkey, ob->data);
- break;
- }
- }
- }
-
- if (kb->data) {
- MEM_freeN(kb->data);
- }
- MEM_freeN(kb);
-
- if (ob->shapenr > 1) {
- ob->shapenr--;
- }
-
- if (key->totkey == 0) {
- BKE_object_shapekey_free(bmain, ob);
- }
-
- return true;
+ KeyBlock *rkb;
+ Key *key = BKE_key_from_object(ob);
+ short kb_index;
+
+ if (key == NULL) {
+ return false;
+ }
+
+ kb_index = BLI_findindex(&key->block, kb);
+ BLI_assert(kb_index != -1);
+
+ for (rkb = key->block.first; rkb; rkb = rkb->next) {
+ if (rkb->relative == kb_index) {
+ /* remap to the 'Basis' */
+ rkb->relative = 0;
+ }
+ else if (rkb->relative >= kb_index) {
+ /* Fix positional shift of the keys when kb is deleted from the list */
+ rkb->relative -= 1;
+ }
+ }
+
+ BLI_remlink(&key->block, kb);
+ key->totkey--;
+ if (key->refkey == kb) {
+ key->refkey = key->block.first;
+
+ if (key->refkey) {
+ /* apply new basis key on original data */
+ switch (ob->type) {
+ case OB_MESH:
+ BKE_keyblock_convert_to_mesh(key->refkey, ob->data);
+ break;
+ case OB_CURVE:
+ case OB_SURF:
+ BKE_keyblock_convert_to_curve(key->refkey, ob->data, BKE_curve_nurbs_get(ob->data));
+ break;
+ case OB_LATTICE:
+ BKE_keyblock_convert_to_lattice(key->refkey, ob->data);
+ break;
+ }
+ }
+ }
+
+ if (kb->data) {
+ MEM_freeN(kb->data);
+ }
+ MEM_freeN(kb);
+
+ if (ob->shapenr > 1) {
+ ob->shapenr--;
+ }
+
+ if (key->totkey == 0) {
+ BKE_object_shapekey_free(bmain, ob);
+ }
+
+ return true;
}
bool BKE_object_flag_test_recursive(const Object *ob, short flag)
{
- if (ob->flag & flag) {
- return true;
- }
- else if (ob->parent) {
- return BKE_object_flag_test_recursive(ob->parent, flag);
- }
- else {
- return false;
- }
+ if (ob->flag & flag) {
+ return true;
+ }
+ else if (ob->parent) {
+ return BKE_object_flag_test_recursive(ob->parent, flag);
+ }
+ else {
+ return false;
+ }
}
bool BKE_object_is_child_recursive(const Object *ob_parent, const Object *ob_child)
{
- for (ob_child = ob_child->parent; ob_child; ob_child = ob_child->parent) {
- if (ob_child == ob_parent) {
- return true;
- }
- }
- return false;
+ for (ob_child = ob_child->parent; ob_child; ob_child = ob_child->parent) {
+ if (ob_child == ob_parent) {
+ return true;
+ }
+ }
+ return false;
}
/* most important if this is modified it should _always_ return True, in certain
* cases false positives are hard to avoid (shape keys for example) */
int BKE_object_is_modified(Scene *scene, Object *ob)
{
- int flag = 0;
+ int flag = 0;
- if (BKE_key_from_object(ob)) {
- flag |= eModifierMode_Render | eModifierMode_Realtime;
- }
- else {
- ModifierData *md;
- VirtualModifierData virtualModifierData;
- /* cloth */
- for (md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
- md && (flag != (eModifierMode_Render | eModifierMode_Realtime));
- md = md->next)
- {
- if ((flag & eModifierMode_Render) == 0 && modifier_isEnabled(scene, md, eModifierMode_Render))
- flag |= eModifierMode_Render;
+ if (BKE_key_from_object(ob)) {
+ flag |= eModifierMode_Render | eModifierMode_Realtime;
+ }
+ else {
+ ModifierData *md;
+ VirtualModifierData virtualModifierData;
+ /* cloth */
+ for (md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ md && (flag != (eModifierMode_Render | eModifierMode_Realtime));
+ md = md->next) {
+ if ((flag & eModifierMode_Render) == 0 &&
+ modifier_isEnabled(scene, md, eModifierMode_Render))
+ flag |= eModifierMode_Render;
- if ((flag & eModifierMode_Realtime) == 0 && modifier_isEnabled(scene, md, eModifierMode_Realtime))
- flag |= eModifierMode_Realtime;
- }
- }
+ if ((flag & eModifierMode_Realtime) == 0 &&
+ modifier_isEnabled(scene, md, eModifierMode_Realtime))
+ flag |= eModifierMode_Realtime;
+ }
+ }
- return flag;
+ return flag;
}
/* Check of objects moves in time. */
@@ -3626,93 +3691,90 @@ int BKE_object_is_modified(Scene *scene, Object *ob)
*/
static bool object_moves_in_time(Object *object)
{
- AnimData *adt = object->adt;
- if (adt != NULL) {
- /* If object has any sort of animation data assume it is moving. */
- if (adt->action != NULL ||
- !BLI_listbase_is_empty(&adt->nla_tracks) ||
- !BLI_listbase_is_empty(&adt->drivers) ||
- !BLI_listbase_is_empty(&adt->overrides))
- {
- return true;
- }
- }
- if (!BLI_listbase_is_empty(&object->constraints)) {
- return true;
- }
- if (object->parent != NULL) {
- /* TODO(sergey): Do recursive check here? */
- return true;
- }
- return false;
+ AnimData *adt = object->adt;
+ if (adt != NULL) {
+ /* If object has any sort of animation data assume it is moving. */
+ if (adt->action != NULL || !BLI_listbase_is_empty(&adt->nla_tracks) ||
+ !BLI_listbase_is_empty(&adt->drivers) || !BLI_listbase_is_empty(&adt->overrides)) {
+ return true;
+ }
+ }
+ if (!BLI_listbase_is_empty(&object->constraints)) {
+ return true;
+ }
+ if (object->parent != NULL) {
+ /* TODO(sergey): Do recursive check here? */
+ return true;
+ }
+ return false;
}
static bool object_deforms_in_time(Object *object)
{
- if (BKE_key_from_object(object) != NULL) {
- return true;
- }
- if (!BLI_listbase_is_empty(&object->modifiers)) {
- return true;
- }
- return object_moves_in_time(object);
+ if (BKE_key_from_object(object) != NULL) {
+ return true;
+ }
+ if (!BLI_listbase_is_empty(&object->modifiers)) {
+ return true;
+ }
+ return object_moves_in_time(object);
}
static bool constructive_modifier_is_deform_modified(ModifierData *md)
{
- /* TODO(sergey): Consider generalizing this a bit so all modifier logic
- * is concentrated in MOD_{modifier}.c file,
- */
- if (md->type == eModifierType_Array) {
- ArrayModifierData *amd = (ArrayModifierData *)md;
- /* TODO(sergey): Check if curve is deformed. */
- return (amd->start_cap != NULL && object_moves_in_time(amd->start_cap)) ||
- (amd->end_cap != NULL && object_moves_in_time(amd->end_cap)) ||
- (amd->curve_ob != NULL && object_moves_in_time(amd->curve_ob)) ||
- (amd->offset_ob != NULL && object_moves_in_time(amd->offset_ob));
- }
- else if (md->type == eModifierType_Mirror) {
- MirrorModifierData *mmd = (MirrorModifierData *)md;
- return mmd->mirror_ob != NULL && object_moves_in_time(mmd->mirror_ob);
- }
- else if (md->type == eModifierType_Screw) {
- ScrewModifierData *smd = (ScrewModifierData *)md;
- return smd->ob_axis != NULL && object_moves_in_time(smd->ob_axis);
- }
- else if (md->type == eModifierType_MeshSequenceCache) {
- /* NOTE: Not ideal because it's unknown whether topology changes or not.
- * This will be detected later, so by assuming it's only deformation
- * going on here we allow to bake deform-only mesh to Alembic and have
- * proper motion blur after that.
- */
- return true;
- }
- return false;
+ /* TODO(sergey): Consider generalizing this a bit so all modifier logic
+ * is concentrated in MOD_{modifier}.c file,
+ */
+ if (md->type == eModifierType_Array) {
+ ArrayModifierData *amd = (ArrayModifierData *)md;
+ /* TODO(sergey): Check if curve is deformed. */
+ return (amd->start_cap != NULL && object_moves_in_time(amd->start_cap)) ||
+ (amd->end_cap != NULL && object_moves_in_time(amd->end_cap)) ||
+ (amd->curve_ob != NULL && object_moves_in_time(amd->curve_ob)) ||
+ (amd->offset_ob != NULL && object_moves_in_time(amd->offset_ob));
+ }
+ else if (md->type == eModifierType_Mirror) {
+ MirrorModifierData *mmd = (MirrorModifierData *)md;
+ return mmd->mirror_ob != NULL && object_moves_in_time(mmd->mirror_ob);
+ }
+ else if (md->type == eModifierType_Screw) {
+ ScrewModifierData *smd = (ScrewModifierData *)md;
+ return smd->ob_axis != NULL && object_moves_in_time(smd->ob_axis);
+ }
+ else if (md->type == eModifierType_MeshSequenceCache) {
+ /* NOTE: Not ideal because it's unknown whether topology changes or not.
+ * This will be detected later, so by assuming it's only deformation
+ * going on here we allow to bake deform-only mesh to Alembic and have
+ * proper motion blur after that.
+ */
+ return true;
+ }
+ return false;
}
static bool modifiers_has_animation_check(Object *ob)
{
- /* TODO(sergey): This is a bit code duplication with depsgraph, but
- * would be nicer to solve this as a part of new dependency graph
- * work, so we avoid conflicts and so.
- */
- if (ob->adt != NULL) {
- AnimData *adt = ob->adt;
- FCurve *fcu;
- if (adt->action != NULL) {
- for (fcu = adt->action->curves.first; fcu; fcu = fcu->next) {
- if (fcu->rna_path && strstr(fcu->rna_path, "modifiers[")) {
- return true;
- }
- }
- }
- for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
- if (fcu->rna_path && strstr(fcu->rna_path, "modifiers[")) {
- return true;
- }
- }
- }
- return false;
+ /* TODO(sergey): This is a bit code duplication with depsgraph, but
+ * would be nicer to solve this as a part of new dependency graph
+ * work, so we avoid conflicts and so.
+ */
+ if (ob->adt != NULL) {
+ AnimData *adt = ob->adt;
+ FCurve *fcu;
+ if (adt->action != NULL) {
+ for (fcu = adt->action->curves.first; fcu; fcu = fcu->next) {
+ if (fcu->rna_path && strstr(fcu->rna_path, "modifiers[")) {
+ return true;
+ }
+ }
+ }
+ for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
+ if (fcu->rna_path && strstr(fcu->rna_path, "modifiers[")) {
+ return true;
+ }
+ }
+ }
+ return false;
}
/* test if object is affected by deforming modifiers (for motion blur). again
@@ -3720,114 +3782,111 @@ static bool modifiers_has_animation_check(Object *ob)
* and we can still if there was actual deformation afterwards */
int BKE_object_is_deform_modified(Scene *scene, Object *ob)
{
- ModifierData *md;
- VirtualModifierData virtualModifierData;
- int flag = 0;
- const bool is_modifier_animated = modifiers_has_animation_check(ob);
+ ModifierData *md;
+ VirtualModifierData virtualModifierData;
+ int flag = 0;
+ const bool is_modifier_animated = modifiers_has_animation_check(ob);
- if (BKE_key_from_object(ob)) {
- flag |= eModifierMode_Realtime | eModifierMode_Render;
- }
+ if (BKE_key_from_object(ob)) {
+ flag |= eModifierMode_Realtime | eModifierMode_Render;
+ }
- if (ob->type == OB_CURVE) {
- Curve *cu = (Curve *)ob->data;
- if (cu->taperobj != NULL && object_deforms_in_time(cu->taperobj)) {
- flag |= eModifierMode_Realtime | eModifierMode_Render;
- }
- }
+ if (ob->type == OB_CURVE) {
+ Curve *cu = (Curve *)ob->data;
+ if (cu->taperobj != NULL && object_deforms_in_time(cu->taperobj)) {
+ flag |= eModifierMode_Realtime | eModifierMode_Render;
+ }
+ }
- /* cloth */
- for (md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
- md && (flag != (eModifierMode_Render | eModifierMode_Realtime));
- md = md->next)
- {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- bool can_deform = mti->type == eModifierTypeType_OnlyDeform ||
- is_modifier_animated;
+ /* cloth */
+ for (md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ md && (flag != (eModifierMode_Render | eModifierMode_Realtime));
+ md = md->next) {
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ bool can_deform = mti->type == eModifierTypeType_OnlyDeform || is_modifier_animated;
- if (!can_deform) {
- can_deform = constructive_modifier_is_deform_modified(md);
- }
+ if (!can_deform) {
+ can_deform = constructive_modifier_is_deform_modified(md);
+ }
- if (can_deform) {
- if (!(flag & eModifierMode_Render) && modifier_isEnabled(scene, md, eModifierMode_Render))
- flag |= eModifierMode_Render;
+ if (can_deform) {
+ if (!(flag & eModifierMode_Render) && modifier_isEnabled(scene, md, eModifierMode_Render))
+ flag |= eModifierMode_Render;
- if (!(flag & eModifierMode_Realtime) && modifier_isEnabled(scene, md, eModifierMode_Realtime))
- flag |= eModifierMode_Realtime;
- }
- }
+ if (!(flag & eModifierMode_Realtime) &&
+ modifier_isEnabled(scene, md, eModifierMode_Realtime))
+ flag |= eModifierMode_Realtime;
+ }
+ }
- return flag;
+ return flag;
}
/* See if an object is using an animated modifier */
bool BKE_object_is_animated(Scene *scene, Object *ob)
{
- ModifierData *md;
- VirtualModifierData virtualModifierData;
+ ModifierData *md;
+ VirtualModifierData virtualModifierData;
- for (md = modifiers_getVirtualModifierList(ob, &virtualModifierData); md; md = md->next)
- if (modifier_dependsOnTime(md) &&
- (modifier_isEnabled(scene, md, eModifierMode_Realtime) ||
- modifier_isEnabled(scene, md, eModifierMode_Render)))
- {
- return true;
- }
- return false;
+ for (md = modifiers_getVirtualModifierList(ob, &virtualModifierData); md; md = md->next)
+ if (modifier_dependsOnTime(md) && (modifier_isEnabled(scene, md, eModifierMode_Realtime) ||
+ modifier_isEnabled(scene, md, eModifierMode_Render))) {
+ return true;
+ }
+ return false;
}
/** Return the number of scenes using (instantiating) that object in their collections. */
int BKE_object_scenes_users_get(Main *bmain, Object *ob)
{
- int num_scenes = 0;
- for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
- if (BKE_collection_has_object_recursive(BKE_collection_master(scene), ob)) {
- num_scenes++;
- }
- }
- return num_scenes;
+ int num_scenes = 0;
+ for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
+ if (BKE_collection_has_object_recursive(BKE_collection_master(scene), ob)) {
+ num_scenes++;
+ }
+ }
+ return num_scenes;
}
MovieClip *BKE_object_movieclip_get(Scene *scene, Object *ob, bool use_default)
{
- MovieClip *clip = use_default ? scene->clip : NULL;
- bConstraint *con = ob->constraints.first, *scon = NULL;
+ MovieClip *clip = use_default ? scene->clip : NULL;
+ bConstraint *con = ob->constraints.first, *scon = NULL;
- while (con) {
- if (con->type == CONSTRAINT_TYPE_CAMERASOLVER) {
- if (scon == NULL || (scon->flag & CONSTRAINT_OFF))
- scon = con;
- }
+ while (con) {
+ if (con->type == CONSTRAINT_TYPE_CAMERASOLVER) {
+ if (scon == NULL || (scon->flag & CONSTRAINT_OFF))
+ scon = con;
+ }
- con = con->next;
- }
+ con = con->next;
+ }
- if (scon) {
- bCameraSolverConstraint *solver = scon->data;
- if ((solver->flag & CAMERASOLVER_ACTIVECLIP) == 0)
- clip = solver->clip;
- else
- clip = scene->clip;
- }
+ if (scon) {
+ bCameraSolverConstraint *solver = scon->data;
+ if ((solver->flag & CAMERASOLVER_ACTIVECLIP) == 0)
+ clip = solver->clip;
+ else
+ clip = scene->clip;
+ }
- return clip;
+ return clip;
}
void BKE_object_runtime_reset(Object *object)
{
- memset(&object->runtime, 0, sizeof(object->runtime));
+ memset(&object->runtime, 0, sizeof(object->runtime));
}
/* Reset all pointers which we don't want to be shared when copying the object. */
void BKE_object_runtime_reset_on_copy(Object *object, const int UNUSED(flag))
{
- Object_Runtime *runtime = &object->runtime;
- runtime->mesh_eval = NULL;
- runtime->mesh_deform_eval = NULL;
- runtime->curve_cache = NULL;
- runtime->gpencil_cache = NULL;
- runtime->cached_bbone_deformation = NULL;
+ Object_Runtime *runtime = &object->runtime;
+ runtime->mesh_eval = NULL;
+ runtime->mesh_deform_eval = NULL;
+ runtime->curve_cache = NULL;
+ runtime->gpencil_cache = NULL;
+ runtime->cached_bbone_deformation = NULL;
}
/*
@@ -3835,32 +3894,32 @@ void BKE_object_runtime_reset_on_copy(Object *object, const int UNUSED(flag))
*/
static Object *obrel_armature_find(Object *ob)
{
- Object *ob_arm = NULL;
+ Object *ob_arm = NULL;
- if (ob->parent && ob->partype == PARSKEL && ob->parent->type == OB_ARMATURE) {
- ob_arm = ob->parent;
- }
- else {
- ModifierData *mod;
- for (mod = (ModifierData *)ob->modifiers.first; mod; mod = mod->next) {
- if (mod->type == eModifierType_Armature) {
- ob_arm = ((ArmatureModifierData *)mod)->object;
- }
- }
- }
+ if (ob->parent && ob->partype == PARSKEL && ob->parent->type == OB_ARMATURE) {
+ ob_arm = ob->parent;
+ }
+ else {
+ ModifierData *mod;
+ for (mod = (ModifierData *)ob->modifiers.first; mod; mod = mod->next) {
+ if (mod->type == eModifierType_Armature) {
+ ob_arm = ((ArmatureModifierData *)mod)->object;
+ }
+ }
+ }
- return ob_arm;
+ return ob_arm;
}
static bool obrel_list_test(Object *ob)
{
- return ob && !(ob->id.tag & LIB_TAG_DOIT);
+ return ob && !(ob->id.tag & LIB_TAG_DOIT);
}
static void obrel_list_add(LinkNode **links, Object *ob)
{
- BLI_linklist_prepend(links, ob);
- ob->id.tag |= LIB_TAG_DOIT;
+ BLI_linklist_prepend(links, ob);
+ ob->id.tag |= LIB_TAG_DOIT;
}
/*
@@ -3870,84 +3929,84 @@ static void obrel_list_add(LinkNode **links, Object *ob)
* If OB_SET_VISIBLE or OB_SET_SELECTED are collected,
* then also add related objects according to the given includeFilters.
*/
-LinkNode *BKE_object_relational_superset(struct ViewLayer *view_layer, eObjectSet objectSet, eObRelationTypes includeFilter)
-{
- LinkNode *links = NULL;
-
- Base *base;
-
- /* Remove markers from all objects */
- for (base = view_layer->object_bases.first; base; base = base->next) {
- base->object->id.tag &= ~LIB_TAG_DOIT;
- }
-
- /* iterate over all selected and visible objects */
- for (base = view_layer->object_bases.first; base; base = base->next) {
- if (objectSet == OB_SET_ALL) {
- /* as we get all anyways just add it */
- Object *ob = base->object;
- obrel_list_add(&links, ob);
- }
- else {
- if ((objectSet == OB_SET_SELECTED && BASE_SELECTED_EDITABLE(((View3D *)NULL), base)) ||
- (objectSet == OB_SET_VISIBLE && BASE_EDITABLE(((View3D *)NULL), base)))
- {
- Object *ob = base->object;
-
- if (obrel_list_test(ob))
- obrel_list_add(&links, ob);
-
- /* parent relationship */
- if (includeFilter & (OB_REL_PARENT | OB_REL_PARENT_RECURSIVE)) {
- Object *parent = ob->parent;
- if (obrel_list_test(parent)) {
-
- obrel_list_add(&links, parent);
-
- /* recursive parent relationship */
- if (includeFilter & OB_REL_PARENT_RECURSIVE) {
- parent = parent->parent;
- while (obrel_list_test(parent)) {
-
- obrel_list_add(&links, parent);
- parent = parent->parent;
- }
- }
- }
- }
-
- /* child relationship */
- if (includeFilter & (OB_REL_CHILDREN | OB_REL_CHILDREN_RECURSIVE)) {
- Base *local_base;
- for (local_base = view_layer->object_bases.first; local_base; local_base = local_base->next) {
- if (BASE_EDITABLE(((View3D *)NULL), local_base)) {
-
- Object *child = local_base->object;
- if (obrel_list_test(child)) {
- if ((includeFilter & OB_REL_CHILDREN_RECURSIVE && BKE_object_is_child_recursive(ob, child)) ||
- (includeFilter & OB_REL_CHILDREN && child->parent && child->parent == ob))
- {
- obrel_list_add(&links, child);
- }
- }
- }
- }
- }
-
-
- /* include related armatures */
- if (includeFilter & OB_REL_MOD_ARMATURE) {
- Object *arm = obrel_armature_find(ob);
- if (obrel_list_test(arm)) {
- obrel_list_add(&links, arm);
- }
- }
-
- }
- }
- }
-
- return links;
+LinkNode *BKE_object_relational_superset(struct ViewLayer *view_layer,
+ eObjectSet objectSet,
+ eObRelationTypes includeFilter)
+{
+ LinkNode *links = NULL;
+
+ Base *base;
+
+ /* Remove markers from all objects */
+ for (base = view_layer->object_bases.first; base; base = base->next) {
+ base->object->id.tag &= ~LIB_TAG_DOIT;
+ }
+
+ /* iterate over all selected and visible objects */
+ for (base = view_layer->object_bases.first; base; base = base->next) {
+ if (objectSet == OB_SET_ALL) {
+ /* as we get all anyways just add it */
+ Object *ob = base->object;
+ obrel_list_add(&links, ob);
+ }
+ else {
+ if ((objectSet == OB_SET_SELECTED && BASE_SELECTED_EDITABLE(((View3D *)NULL), base)) ||
+ (objectSet == OB_SET_VISIBLE && BASE_EDITABLE(((View3D *)NULL), base))) {
+ Object *ob = base->object;
+
+ if (obrel_list_test(ob))
+ obrel_list_add(&links, ob);
+
+ /* parent relationship */
+ if (includeFilter & (OB_REL_PARENT | OB_REL_PARENT_RECURSIVE)) {
+ Object *parent = ob->parent;
+ if (obrel_list_test(parent)) {
+
+ obrel_list_add(&links, parent);
+
+ /* recursive parent relationship */
+ if (includeFilter & OB_REL_PARENT_RECURSIVE) {
+ parent = parent->parent;
+ while (obrel_list_test(parent)) {
+
+ obrel_list_add(&links, parent);
+ parent = parent->parent;
+ }
+ }
+ }
+ }
+
+ /* child relationship */
+ if (includeFilter & (OB_REL_CHILDREN | OB_REL_CHILDREN_RECURSIVE)) {
+ Base *local_base;
+ for (local_base = view_layer->object_bases.first; local_base;
+ local_base = local_base->next) {
+ if (BASE_EDITABLE(((View3D *)NULL), local_base)) {
+
+ Object *child = local_base->object;
+ if (obrel_list_test(child)) {
+ if ((includeFilter & OB_REL_CHILDREN_RECURSIVE &&
+ BKE_object_is_child_recursive(ob, child)) ||
+ (includeFilter & OB_REL_CHILDREN && child->parent && child->parent == ob)) {
+ obrel_list_add(&links, child);
+ }
+ }
+ }
+ }
+ }
+
+ /* include related armatures */
+ if (includeFilter & OB_REL_MOD_ARMATURE) {
+ Object *arm = obrel_armature_find(ob);
+ if (obrel_list_test(arm)) {
+ obrel_list_add(&links, arm);
+ }
+ }
+ }
+ }
+ }
+
+ return links;
}
/**
@@ -3955,22 +4014,22 @@ LinkNode *BKE_object_relational_superset(struct ViewLayer *view_layer, eObjectSe
*/
struct LinkNode *BKE_object_groups(Main *bmain, Scene *scene, Object *ob)
{
- LinkNode *collection_linknode = NULL;
- Collection *collection = NULL;
- while ((collection = BKE_collection_object_find(bmain, scene, collection, ob))) {
- BLI_linklist_prepend(&collection_linknode, collection);
- }
+ LinkNode *collection_linknode = NULL;
+ Collection *collection = NULL;
+ while ((collection = BKE_collection_object_find(bmain, scene, collection, ob))) {
+ BLI_linklist_prepend(&collection_linknode, collection);
+ }
- return collection_linknode;
+ return collection_linknode;
}
void BKE_object_groups_clear(Main *bmain, Scene *scene, Object *ob)
{
- Collection *collection = NULL;
- while ((collection = BKE_collection_object_find(bmain, scene, collection, ob))) {
- BKE_collection_object_remove(bmain, collection, ob, false);
- DEG_id_tag_update(&collection->id, ID_RECALC_COPY_ON_WRITE);
- }
+ Collection *collection = NULL;
+ while ((collection = BKE_collection_object_find(bmain, scene, collection, ob))) {
+ BKE_collection_object_remove(bmain, collection, ob, false);
+ DEG_id_tag_update(&collection->id, ID_RECALC_COPY_ON_WRITE);
+ }
}
/**
@@ -3984,349 +4043,350 @@ void BKE_object_groups_clear(Main *bmain, Scene *scene, Object *ob)
*/
KDTree_3d *BKE_object_as_kdtree(Object *ob, int *r_tot)
{
- KDTree_3d *tree = NULL;
- unsigned int tot = 0;
-
- switch (ob->type) {
- case OB_MESH:
- {
- Mesh *me = ob->data;
- unsigned int i;
-
- Mesh *me_eval = ob->runtime.mesh_deform_eval ? ob->runtime.mesh_deform_eval : ob->runtime.mesh_deform_eval;
- const int *index;
-
- if (me_eval && (index = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX))) {
- MVert *mvert = me_eval->mvert;
- uint totvert = me_eval->totvert;
-
- /* tree over-allocs in case where some verts have ORIGINDEX_NONE */
- tot = 0;
- tree = BLI_kdtree_3d_new(totvert);
-
- /* we don't how how many verts from the DM we can use */
- for (i = 0; i < totvert; i++) {
- if (index[i] != ORIGINDEX_NONE) {
- float co[3];
- mul_v3_m4v3(co, ob->obmat, mvert[i].co);
- BLI_kdtree_3d_insert(tree, index[i], co);
- tot++;
- }
- }
- }
- else {
- MVert *mvert = me->mvert;
-
- tot = me->totvert;
- tree = BLI_kdtree_3d_new(tot);
-
- for (i = 0; i < tot; i++) {
- float co[3];
- mul_v3_m4v3(co, ob->obmat, mvert[i].co);
- BLI_kdtree_3d_insert(tree, i, co);
- }
- }
-
- BLI_kdtree_3d_balance(tree);
- break;
- }
- case OB_CURVE:
- case OB_SURF:
- {
- /* TODO: take deformation into account */
- Curve *cu = ob->data;
- unsigned int i, a;
-
- Nurb *nu;
-
- tot = BKE_nurbList_verts_count_without_handles(&cu->nurb);
- tree = BLI_kdtree_3d_new(tot);
- i = 0;
-
- nu = cu->nurb.first;
- while (nu) {
- if (nu->bezt) {
- BezTriple *bezt;
-
- bezt = nu->bezt;
- a = nu->pntsu;
- while (a--) {
- float co[3];
- mul_v3_m4v3(co, ob->obmat, bezt->vec[1]);
- BLI_kdtree_3d_insert(tree, i++, co);
- bezt++;
- }
- }
- else {
- BPoint *bp;
-
- bp = nu->bp;
- a = nu->pntsu * nu->pntsv;
- while (a--) {
- float co[3];
- mul_v3_m4v3(co, ob->obmat, bp->vec);
- BLI_kdtree_3d_insert(tree, i++, co);
- bp++;
- }
- }
- nu = nu->next;
- }
-
- BLI_kdtree_3d_balance(tree);
- break;
- }
- case OB_LATTICE:
- {
- /* TODO: take deformation into account */
- Lattice *lt = ob->data;
- BPoint *bp;
- unsigned int i;
-
- tot = lt->pntsu * lt->pntsv * lt->pntsw;
- tree = BLI_kdtree_3d_new(tot);
- i = 0;
-
- for (bp = lt->def; i < tot; bp++) {
- float co[3];
- mul_v3_m4v3(co, ob->obmat, bp->vec);
- BLI_kdtree_3d_insert(tree, i++, co);
- }
-
- BLI_kdtree_3d_balance(tree);
- break;
- }
- }
-
- *r_tot = tot;
- return tree;
+ KDTree_3d *tree = NULL;
+ unsigned int tot = 0;
+
+ switch (ob->type) {
+ case OB_MESH: {
+ Mesh *me = ob->data;
+ unsigned int i;
+
+ Mesh *me_eval = ob->runtime.mesh_deform_eval ? ob->runtime.mesh_deform_eval :
+ ob->runtime.mesh_deform_eval;
+ const int *index;
+
+ if (me_eval && (index = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX))) {
+ MVert *mvert = me_eval->mvert;
+ uint totvert = me_eval->totvert;
+
+ /* tree over-allocs in case where some verts have ORIGINDEX_NONE */
+ tot = 0;
+ tree = BLI_kdtree_3d_new(totvert);
+
+ /* we don't how how many verts from the DM we can use */
+ for (i = 0; i < totvert; i++) {
+ if (index[i] != ORIGINDEX_NONE) {
+ float co[3];
+ mul_v3_m4v3(co, ob->obmat, mvert[i].co);
+ BLI_kdtree_3d_insert(tree, index[i], co);
+ tot++;
+ }
+ }
+ }
+ else {
+ MVert *mvert = me->mvert;
+
+ tot = me->totvert;
+ tree = BLI_kdtree_3d_new(tot);
+
+ for (i = 0; i < tot; i++) {
+ float co[3];
+ mul_v3_m4v3(co, ob->obmat, mvert[i].co);
+ BLI_kdtree_3d_insert(tree, i, co);
+ }
+ }
+
+ BLI_kdtree_3d_balance(tree);
+ break;
+ }
+ case OB_CURVE:
+ case OB_SURF: {
+ /* TODO: take deformation into account */
+ Curve *cu = ob->data;
+ unsigned int i, a;
+
+ Nurb *nu;
+
+ tot = BKE_nurbList_verts_count_without_handles(&cu->nurb);
+ tree = BLI_kdtree_3d_new(tot);
+ i = 0;
+
+ nu = cu->nurb.first;
+ while (nu) {
+ if (nu->bezt) {
+ BezTriple *bezt;
+
+ bezt = nu->bezt;
+ a = nu->pntsu;
+ while (a--) {
+ float co[3];
+ mul_v3_m4v3(co, ob->obmat, bezt->vec[1]);
+ BLI_kdtree_3d_insert(tree, i++, co);
+ bezt++;
+ }
+ }
+ else {
+ BPoint *bp;
+
+ bp = nu->bp;
+ a = nu->pntsu * nu->pntsv;
+ while (a--) {
+ float co[3];
+ mul_v3_m4v3(co, ob->obmat, bp->vec);
+ BLI_kdtree_3d_insert(tree, i++, co);
+ bp++;
+ }
+ }
+ nu = nu->next;
+ }
+
+ BLI_kdtree_3d_balance(tree);
+ break;
+ }
+ case OB_LATTICE: {
+ /* TODO: take deformation into account */
+ Lattice *lt = ob->data;
+ BPoint *bp;
+ unsigned int i;
+
+ tot = lt->pntsu * lt->pntsv * lt->pntsw;
+ tree = BLI_kdtree_3d_new(tot);
+ i = 0;
+
+ for (bp = lt->def; i < tot; bp++) {
+ float co[3];
+ mul_v3_m4v3(co, ob->obmat, bp->vec);
+ BLI_kdtree_3d_insert(tree, i++, co);
+ }
+
+ BLI_kdtree_3d_balance(tree);
+ break;
+ }
+ }
+
+ *r_tot = tot;
+ return tree;
}
bool BKE_object_modifier_use_time(Object *ob, ModifierData *md)
{
- if (modifier_dependsOnTime(md)) {
- return true;
- }
-
- /* Check whether modifier is animated. */
- /* TODO: this should be handled as part of build_animdata() -- Aligorith */
- if (ob->adt) {
- AnimData *adt = ob->adt;
- FCurve *fcu;
-
- char pattern[MAX_NAME + 16];
- BLI_snprintf(pattern, sizeof(pattern), "modifiers[\"%s\"]", md->name);
-
- /* action - check for F-Curves with paths containing 'modifiers[' */
- if (adt->action) {
- for (fcu = (FCurve *)adt->action->curves.first;
- fcu != NULL;
- fcu = (FCurve *)fcu->next)
- {
- if (fcu->rna_path && strstr(fcu->rna_path, pattern))
- return true;
- }
- }
-
- /* This here allows modifier properties to get driven and still update properly
- *
- * Workaround to get [#26764] (e.g. subsurf levels not updating when animated/driven)
- * working, without the updating problems ([#28525] [#28690] [#28774] [#28777]) caused
- * by the RNA updates cache introduced in r.38649
- */
- for (fcu = (FCurve *)adt->drivers.first;
- fcu != NULL;
- fcu = (FCurve *)fcu->next)
- {
- if (fcu->rna_path && strstr(fcu->rna_path, pattern))
- return true;
- }
-
- /* XXX: also, should check NLA strips, though for now assume that nobody uses
- * that and we can omit that for performance reasons... */
- }
-
- return false;
+ if (modifier_dependsOnTime(md)) {
+ return true;
+ }
+
+ /* Check whether modifier is animated. */
+ /* TODO: this should be handled as part of build_animdata() -- Aligorith */
+ if (ob->adt) {
+ AnimData *adt = ob->adt;
+ FCurve *fcu;
+
+ char pattern[MAX_NAME + 16];
+ BLI_snprintf(pattern, sizeof(pattern), "modifiers[\"%s\"]", md->name);
+
+ /* action - check for F-Curves with paths containing 'modifiers[' */
+ if (adt->action) {
+ for (fcu = (FCurve *)adt->action->curves.first; fcu != NULL; fcu = (FCurve *)fcu->next) {
+ if (fcu->rna_path && strstr(fcu->rna_path, pattern))
+ return true;
+ }
+ }
+
+ /* This here allows modifier properties to get driven and still update properly
+ *
+ * Workaround to get [#26764] (e.g. subsurf levels not updating when animated/driven)
+ * working, without the updating problems ([#28525] [#28690] [#28774] [#28777]) caused
+ * by the RNA updates cache introduced in r.38649
+ */
+ for (fcu = (FCurve *)adt->drivers.first; fcu != NULL; fcu = (FCurve *)fcu->next) {
+ if (fcu->rna_path && strstr(fcu->rna_path, pattern))
+ return true;
+ }
+
+ /* XXX: also, should check NLA strips, though for now assume that nobody uses
+ * that and we can omit that for performance reasons... */
+ }
+
+ return false;
}
bool BKE_object_modifier_gpencil_use_time(Object *ob, GpencilModifierData *md)
{
- if (BKE_gpencil_modifier_dependsOnTime(md)) {
- return true;
- }
+ if (BKE_gpencil_modifier_dependsOnTime(md)) {
+ return true;
+ }
- /* Check whether modifier is animated. */
- /* TODO (Aligorith): this should be handled as part of build_animdata() */
- if (ob->adt) {
- AnimData *adt = ob->adt;
- FCurve *fcu;
+ /* Check whether modifier is animated. */
+ /* TODO (Aligorith): this should be handled as part of build_animdata() */
+ if (ob->adt) {
+ AnimData *adt = ob->adt;
+ FCurve *fcu;
- char pattern[MAX_NAME + 32];
- BLI_snprintf(pattern, sizeof(pattern), "grease_pencil_modifiers[\"%s\"]", md->name);
+ char pattern[MAX_NAME + 32];
+ BLI_snprintf(pattern, sizeof(pattern), "grease_pencil_modifiers[\"%s\"]", md->name);
- /* action - check for F-Curves with paths containing 'grease_pencil_modifiers[' */
- if (adt->action) {
- for (fcu = adt->action->curves.first; fcu != NULL; fcu = fcu->next) {
- if (fcu->rna_path && strstr(fcu->rna_path, pattern)) {
- return true;
- }
- }
- }
+ /* action - check for F-Curves with paths containing 'grease_pencil_modifiers[' */
+ if (adt->action) {
+ for (fcu = adt->action->curves.first; fcu != NULL; fcu = fcu->next) {
+ if (fcu->rna_path && strstr(fcu->rna_path, pattern)) {
+ return true;
+ }
+ }
+ }
- /* This here allows modifier properties to get driven and still update properly */
- for (fcu = adt->drivers.first; fcu != NULL; fcu = fcu->next) {
- if (fcu->rna_path && strstr(fcu->rna_path, pattern)) {
- return true;
- }
- }
- }
+ /* This here allows modifier properties to get driven and still update properly */
+ for (fcu = adt->drivers.first; fcu != NULL; fcu = fcu->next) {
+ if (fcu->rna_path && strstr(fcu->rna_path, pattern)) {
+ return true;
+ }
+ }
+ }
- return false;
+ return false;
}
bool BKE_object_shaderfx_use_time(Object *ob, ShaderFxData *fx)
{
- if (BKE_shaderfx_dependsOnTime(fx)) {
- return true;
- }
+ if (BKE_shaderfx_dependsOnTime(fx)) {
+ return true;
+ }
- /* Check whether effect is animated. */
- /* TODO (Aligorith): this should be handled as part of build_animdata() */
- if (ob->adt) {
- AnimData *adt = ob->adt;
- FCurve *fcu;
+ /* Check whether effect is animated. */
+ /* TODO (Aligorith): this should be handled as part of build_animdata() */
+ if (ob->adt) {
+ AnimData *adt = ob->adt;
+ FCurve *fcu;
- char pattern[MAX_NAME + 32];
- BLI_snprintf(pattern, sizeof(pattern), "shader_effects[\"%s\"]", fx->name);
+ char pattern[MAX_NAME + 32];
+ BLI_snprintf(pattern, sizeof(pattern), "shader_effects[\"%s\"]", fx->name);
- /* action - check for F-Curves with paths containing string[' */
- if (adt->action) {
- for (fcu = adt->action->curves.first; fcu != NULL; fcu = fcu->next) {
- if (fcu->rna_path && strstr(fcu->rna_path, pattern))
- return true;
- }
- }
+ /* action - check for F-Curves with paths containing string[' */
+ if (adt->action) {
+ for (fcu = adt->action->curves.first; fcu != NULL; fcu = fcu->next) {
+ if (fcu->rna_path && strstr(fcu->rna_path, pattern))
+ return true;
+ }
+ }
- /* This here allows properties to get driven and still update properly */
- for (fcu = adt->drivers.first; fcu != NULL; fcu = fcu->next) {
- if (fcu->rna_path && strstr(fcu->rna_path, pattern))
- return true;
- }
- }
+ /* This here allows properties to get driven and still update properly */
+ for (fcu = adt->drivers.first; fcu != NULL; fcu = fcu->next) {
+ if (fcu->rna_path && strstr(fcu->rna_path, pattern))
+ return true;
+ }
+ }
- return false;
+ return false;
}
/* set "ignore cache" flag for all caches on this object */
static void object_cacheIgnoreClear(Object *ob, int state)
{
- ListBase pidlist;
- PTCacheID *pid;
- BKE_ptcache_ids_from_object(&pidlist, ob, NULL, 0);
+ ListBase pidlist;
+ PTCacheID *pid;
+ BKE_ptcache_ids_from_object(&pidlist, ob, NULL, 0);
- for (pid = pidlist.first; pid; pid = pid->next) {
- if (pid->cache) {
- if (state)
- pid->cache->flag |= PTCACHE_IGNORE_CLEAR;
- else
- pid->cache->flag &= ~PTCACHE_IGNORE_CLEAR;
- }
- }
+ for (pid = pidlist.first; pid; pid = pid->next) {
+ if (pid->cache) {
+ if (state)
+ pid->cache->flag |= PTCACHE_IGNORE_CLEAR;
+ else
+ pid->cache->flag &= ~PTCACHE_IGNORE_CLEAR;
+ }
+ }
- BLI_freelistN(&pidlist);
+ BLI_freelistN(&pidlist);
}
/* Note: this function should eventually be replaced by depsgraph functionality.
* Avoid calling this in new code unless there is a very good reason for it!
*/
-bool BKE_object_modifier_update_subframe(
- Depsgraph *depsgraph, Scene *scene, Object *ob, bool update_mesh,
- int parent_recursion, float frame, int type)
-{
- ModifierData *md = modifiers_findByType(ob, (ModifierType)type);
- bConstraint *con;
-
- if (type == eModifierType_DynamicPaint) {
- DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
-
- /* if other is dynamic paint canvas, don't update */
- if (pmd && pmd->canvas)
- return true;
- }
- else if (type == eModifierType_Smoke) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
-
- if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) != 0)
- return true;
- }
-
- /* if object has parents, update them too */
- if (parent_recursion) {
- int recursion = parent_recursion - 1;
- bool no_update = false;
- if (ob->parent) no_update |= BKE_object_modifier_update_subframe(depsgraph, scene, ob->parent, 0, recursion, frame, type);
- if (ob->track) no_update |= BKE_object_modifier_update_subframe(depsgraph, scene, ob->track, 0, recursion, frame, type);
-
- /* skip subframe if object is parented
- * to vertex of a dynamic paint canvas */
- if (no_update && (ob->partype == PARVERT1 || ob->partype == PARVERT3))
- return false;
-
- /* also update constraint targets */
- for (con = ob->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- ListBase targets = {NULL, NULL};
-
- if (cti && cti->get_constraint_targets) {
- bConstraintTarget *ct;
- cti->get_constraint_targets(con, &targets);
- for (ct = targets.first; ct; ct = ct->next) {
- if (ct->tar)
- BKE_object_modifier_update_subframe(depsgraph, scene, ct->tar, 0, recursion, frame, type);
- }
- /* free temp targets */
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 0);
- }
- }
- }
-
- /* was originally ID_RECALC_ALL - TODO - which flags are really needed??? */
- /* TODO(sergey): What about animation? */
- ob->id.recalc |= ID_RECALC_ALL;
- if (update_mesh) {
- BKE_animsys_evaluate_animdata(depsgraph, scene, &ob->id, ob->adt, frame, ADT_RECALC_ANIM);
- /* ignore cache clear during subframe updates
- * to not mess up cache validity */
- object_cacheIgnoreClear(ob, 1);
- BKE_object_handle_update(depsgraph, scene, ob);
- object_cacheIgnoreClear(ob, 0);
- }
- else {
- BKE_object_where_is_calc_time(depsgraph, scene, ob, frame);
- }
-
- /* for curve following objects, parented curve has to be updated too */
- if (ob->type == OB_CURVE) {
- Curve *cu = ob->data;
- BKE_animsys_evaluate_animdata(depsgraph, scene, &cu->id, cu->adt, frame, ADT_RECALC_ANIM);
- }
- /* and armatures... */
- if (ob->type == OB_ARMATURE) {
- bArmature *arm = ob->data;
- BKE_animsys_evaluate_animdata(depsgraph, scene, &arm->id, arm->adt, frame, ADT_RECALC_ANIM);
- BKE_pose_where_is(depsgraph, scene, ob);
- }
-
- return false;
+bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ bool update_mesh,
+ int parent_recursion,
+ float frame,
+ int type)
+{
+ ModifierData *md = modifiers_findByType(ob, (ModifierType)type);
+ bConstraint *con;
+
+ if (type == eModifierType_DynamicPaint) {
+ DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
+
+ /* if other is dynamic paint canvas, don't update */
+ if (pmd && pmd->canvas)
+ return true;
+ }
+ else if (type == eModifierType_Smoke) {
+ SmokeModifierData *smd = (SmokeModifierData *)md;
+
+ if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) != 0)
+ return true;
+ }
+
+ /* if object has parents, update them too */
+ if (parent_recursion) {
+ int recursion = parent_recursion - 1;
+ bool no_update = false;
+ if (ob->parent)
+ no_update |= BKE_object_modifier_update_subframe(
+ depsgraph, scene, ob->parent, 0, recursion, frame, type);
+ if (ob->track)
+ no_update |= BKE_object_modifier_update_subframe(
+ depsgraph, scene, ob->track, 0, recursion, frame, type);
+
+ /* skip subframe if object is parented
+ * to vertex of a dynamic paint canvas */
+ if (no_update && (ob->partype == PARVERT1 || ob->partype == PARVERT3))
+ return false;
+
+ /* also update constraint targets */
+ for (con = ob->constraints.first; con; con = con->next) {
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ ListBase targets = {NULL, NULL};
+
+ if (cti && cti->get_constraint_targets) {
+ bConstraintTarget *ct;
+ cti->get_constraint_targets(con, &targets);
+ for (ct = targets.first; ct; ct = ct->next) {
+ if (ct->tar)
+ BKE_object_modifier_update_subframe(
+ depsgraph, scene, ct->tar, 0, recursion, frame, type);
+ }
+ /* free temp targets */
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 0);
+ }
+ }
+ }
+
+ /* was originally ID_RECALC_ALL - TODO - which flags are really needed??? */
+ /* TODO(sergey): What about animation? */
+ ob->id.recalc |= ID_RECALC_ALL;
+ if (update_mesh) {
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &ob->id, ob->adt, frame, ADT_RECALC_ANIM);
+ /* ignore cache clear during subframe updates
+ * to not mess up cache validity */
+ object_cacheIgnoreClear(ob, 1);
+ BKE_object_handle_update(depsgraph, scene, ob);
+ object_cacheIgnoreClear(ob, 0);
+ }
+ else {
+ BKE_object_where_is_calc_time(depsgraph, scene, ob, frame);
+ }
+
+ /* for curve following objects, parented curve has to be updated too */
+ if (ob->type == OB_CURVE) {
+ Curve *cu = ob->data;
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &cu->id, cu->adt, frame, ADT_RECALC_ANIM);
+ }
+ /* and armatures... */
+ if (ob->type == OB_ARMATURE) {
+ bArmature *arm = ob->data;
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &arm->id, arm->adt, frame, ADT_RECALC_ANIM);
+ BKE_pose_where_is(depsgraph, scene, ob);
+ }
+
+ return false;
}
void BKE_object_type_set_empty_for_versioning(Object *ob)
{
- ob->type = OB_EMPTY;
- ob->data = NULL;
- if (ob->pose) {
- BKE_pose_free_ex(ob->pose, false);
- ob->pose = NULL;
- }
- ob->mode = OB_MODE_OBJECT;
+ ob->type = OB_EMPTY;
+ ob->data = NULL;
+ if (ob->pose) {
+ BKE_pose_free_ex(ob->pose, false);
+ ob->pose = NULL;
+ }
+ ob->mode = OB_MODE_OBJECT;
}
diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c
index e0be162024d..be3dbbb1c71 100644
--- a/source/blender/blenkernel/intern/object_deform.c
+++ b/source/blender/blenkernel/intern/object_deform.c
@@ -45,7 +45,7 @@
#include "BKE_action.h"
#include "BKE_deform.h"
#include "BKE_editmesh.h"
-#include "BKE_object_deform.h" /* own include */
+#include "BKE_object_deform.h" /* own include */
#include "BKE_object.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
@@ -56,9 +56,9 @@
static Lattice *object_defgroup_lattice_get(ID *id)
{
- Lattice *lt = (Lattice *)id;
- BLI_assert(GS(id->name) == ID_LT);
- return (lt->editlatt) ? lt->editlatt->latt : lt;
+ Lattice *lt = (Lattice *)id;
+ BLI_assert(GS(id->name) == ID_LT);
+ return (lt->editlatt) ? lt->editlatt->latt : lt;
}
/**
@@ -70,43 +70,42 @@ static Lattice *object_defgroup_lattice_get(ID *id)
*/
void BKE_object_defgroup_remap_update_users(Object *ob, int *map)
{
- ModifierData *md;
- ParticleSystem *psys;
- int a;
-
- /* these cases don't use names to refer to vertex groups, so when
- * they get removed the numbers get out of sync, this corrects that */
-
- if (ob->soft) {
- ob->soft->vertgroup = map[ob->soft->vertgroup];
- }
-
- for (md = ob->modifiers.first; md; md = md->next) {
- if (md->type == eModifierType_Explode) {
- ExplodeModifierData *emd = (ExplodeModifierData *)md;
- emd->vgroup = map[emd->vgroup];
- }
- else if (md->type == eModifierType_Cloth) {
- ClothModifierData *clmd = (ClothModifierData *)md;
- ClothSimSettings *clsim = clmd->sim_parms;
-
- if (clsim) {
- clsim->vgroup_mass = map[clsim->vgroup_mass];
- clsim->vgroup_bend = map[clsim->vgroup_bend];
- clsim->vgroup_struct = map[clsim->vgroup_struct];
- }
- }
- }
-
- for (psys = ob->particlesystem.first; psys; psys = psys->next) {
- for (a = 0; a < PSYS_TOT_VG; a++) {
- psys->vgroup[a] = map[psys->vgroup[a]];
- }
- }
+ ModifierData *md;
+ ParticleSystem *psys;
+ int a;
+
+ /* these cases don't use names to refer to vertex groups, so when
+ * they get removed the numbers get out of sync, this corrects that */
+
+ if (ob->soft) {
+ ob->soft->vertgroup = map[ob->soft->vertgroup];
+ }
+
+ for (md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_Explode) {
+ ExplodeModifierData *emd = (ExplodeModifierData *)md;
+ emd->vgroup = map[emd->vgroup];
+ }
+ else if (md->type == eModifierType_Cloth) {
+ ClothModifierData *clmd = (ClothModifierData *)md;
+ ClothSimSettings *clsim = clmd->sim_parms;
+
+ if (clsim) {
+ clsim->vgroup_mass = map[clsim->vgroup_mass];
+ clsim->vgroup_bend = map[clsim->vgroup_bend];
+ clsim->vgroup_struct = map[clsim->vgroup_struct];
+ }
+ }
+ }
+
+ for (psys = ob->particlesystem.first; psys; psys = psys->next) {
+ for (a = 0; a < PSYS_TOT_VG; a++) {
+ psys->vgroup[a] = map[psys->vgroup[a]];
+ }
+ }
}
/** \} */
-
/** \name Group creation
* \{ */
@@ -115,16 +114,16 @@ void BKE_object_defgroup_remap_update_users(Object *ob, int *map)
*/
bDeformGroup *BKE_object_defgroup_add_name(Object *ob, const char *name)
{
- bDeformGroup *defgroup;
+ bDeformGroup *defgroup;
- if (!ob || !OB_TYPE_SUPPORT_VGROUP(ob->type))
- return NULL;
+ if (!ob || !OB_TYPE_SUPPORT_VGROUP(ob->type))
+ return NULL;
- defgroup = BKE_defgroup_new(ob, name);
+ defgroup = BKE_defgroup_new(ob, name);
- ob->actdef = BLI_listbase_count(&ob->defbase);
+ ob->actdef = BLI_listbase_count(&ob->defbase);
- return defgroup;
+ return defgroup;
}
/**
@@ -132,7 +131,7 @@ bDeformGroup *BKE_object_defgroup_add_name(Object *ob, const char *name)
*/
bDeformGroup *BKE_object_defgroup_add(Object *ob)
{
- return BKE_object_defgroup_add_name(ob, DATA_("Group"));
+ return BKE_object_defgroup_add_name(ob, DATA_("Group"));
}
/**
@@ -140,22 +139,22 @@ bDeformGroup *BKE_object_defgroup_add(Object *ob)
*/
MDeformVert *BKE_object_defgroup_data_create(ID *id)
{
- if (GS(id->name) == ID_ME) {
- Mesh *me = (Mesh *)id;
- me->dvert = CustomData_add_layer(&me->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, me->totvert);
- return me->dvert;
- }
- else if (GS(id->name) == ID_LT) {
- Lattice *lt = (Lattice *)id;
- lt->dvert = MEM_callocN(sizeof(MDeformVert) * lt->pntsu * lt->pntsv * lt->pntsw, "lattice deformVert");
- return lt->dvert;
- }
-
- return NULL;
+ if (GS(id->name) == ID_ME) {
+ Mesh *me = (Mesh *)id;
+ me->dvert = CustomData_add_layer(&me->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, me->totvert);
+ return me->dvert;
+ }
+ else if (GS(id->name) == ID_LT) {
+ Lattice *lt = (Lattice *)id;
+ lt->dvert = MEM_callocN(sizeof(MDeformVert) * lt->pntsu * lt->pntsv * lt->pntsw,
+ "lattice deformVert");
+ return lt->dvert;
+ }
+
+ return NULL;
}
/** \} */
-
/** \name Group clearing
* \{ */
@@ -167,72 +166,72 @@ MDeformVert *BKE_object_defgroup_data_create(ID *id)
*/
bool BKE_object_defgroup_clear(Object *ob, bDeformGroup *dg, const bool use_selection)
{
- MDeformVert *dv;
- const int def_nr = BLI_findindex(&ob->defbase, dg);
- bool changed = false;
-
- if (ob->type == OB_MESH) {
- Mesh *me = ob->data;
-
- if (me->edit_mesh) {
- BMEditMesh *em = me->edit_mesh;
- const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
-
- if (cd_dvert_offset != -1) {
- BMVert *eve;
- BMIter iter;
-
- BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
- dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
-
- if (dv && dv->dw && (!use_selection || BM_elem_flag_test(eve, BM_ELEM_SELECT))) {
- MDeformWeight *dw = defvert_find_index(dv, def_nr);
- defvert_remove_group(dv, dw); /* dw can be NULL */
- changed = true;
- }
- }
- }
- }
- else {
- if (me->dvert) {
- MVert *mv;
- int i;
-
- mv = me->mvert;
- dv = me->dvert;
-
- for (i = 0; i < me->totvert; i++, mv++, dv++) {
- if (dv->dw && (!use_selection || (mv->flag & SELECT))) {
- MDeformWeight *dw = defvert_find_index(dv, def_nr);
- defvert_remove_group(dv, dw); /* dw can be NULL */
- changed = true;
- }
- }
- }
- }
- }
- else if (ob->type == OB_LATTICE) {
- Lattice *lt = object_defgroup_lattice_get((ID *)(ob->data));
-
- if (lt->dvert) {
- BPoint *bp;
- int i, tot = lt->pntsu * lt->pntsv * lt->pntsw;
-
- for (i = 0, bp = lt->def; i < tot; i++, bp++) {
- if (!use_selection || (bp->f1 & SELECT)) {
- MDeformWeight *dw;
-
- dv = &lt->dvert[i];
-
- dw = defvert_find_index(dv, def_nr);
- defvert_remove_group(dv, dw); /* dw can be NULL */
- changed = true;
- }
- }
- }
- }
-
- return changed;
+ MDeformVert *dv;
+ const int def_nr = BLI_findindex(&ob->defbase, dg);
+ bool changed = false;
+
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+
+ if (me->edit_mesh) {
+ BMEditMesh *em = me->edit_mesh;
+ const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
+
+ if (cd_dvert_offset != -1) {
+ BMVert *eve;
+ BMIter iter;
+
+ BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
+ dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
+
+ if (dv && dv->dw && (!use_selection || BM_elem_flag_test(eve, BM_ELEM_SELECT))) {
+ MDeformWeight *dw = defvert_find_index(dv, def_nr);
+ defvert_remove_group(dv, dw); /* dw can be NULL */
+ changed = true;
+ }
+ }
+ }
+ }
+ else {
+ if (me->dvert) {
+ MVert *mv;
+ int i;
+
+ mv = me->mvert;
+ dv = me->dvert;
+
+ for (i = 0; i < me->totvert; i++, mv++, dv++) {
+ if (dv->dw && (!use_selection || (mv->flag & SELECT))) {
+ MDeformWeight *dw = defvert_find_index(dv, def_nr);
+ defvert_remove_group(dv, dw); /* dw can be NULL */
+ changed = true;
+ }
+ }
+ }
+ }
+ }
+ else if (ob->type == OB_LATTICE) {
+ Lattice *lt = object_defgroup_lattice_get((ID *)(ob->data));
+
+ if (lt->dvert) {
+ BPoint *bp;
+ int i, tot = lt->pntsu * lt->pntsv * lt->pntsw;
+
+ for (i = 0, bp = lt->def; i < tot; i++, bp++) {
+ if (!use_selection || (bp->f1 & SELECT)) {
+ MDeformWeight *dw;
+
+ dv = &lt->dvert[i];
+
+ dw = defvert_find_index(dv, def_nr);
+ defvert_remove_group(dv, dw); /* dw can be NULL */
+ changed = true;
+ }
+ }
+ }
+ }
+
+ return changed;
}
/**
@@ -243,155 +242,154 @@ bool BKE_object_defgroup_clear(Object *ob, bDeformGroup *dg, const bool use_sele
*/
bool BKE_object_defgroup_clear_all(Object *ob, const bool use_selection)
{
- bDeformGroup *dg;
- bool changed = false;
+ bDeformGroup *dg;
+ bool changed = false;
- for (dg = ob->defbase.first; dg; dg = dg->next) {
- if (BKE_object_defgroup_clear(ob, dg, use_selection)) {
- changed = true;
- }
- }
+ for (dg = ob->defbase.first; dg; dg = dg->next) {
+ if (BKE_object_defgroup_clear(ob, dg, use_selection)) {
+ changed = true;
+ }
+ }
- return changed;
+ return changed;
}
/** \} */
-
/** \name Group removal
* \{ */
static void object_defgroup_remove_update_users(Object *ob, const int idx)
{
- int i, defbase_tot = BLI_listbase_count(&ob->defbase) + 1;
- int *map = MEM_mallocN(sizeof(int) * defbase_tot, "vgroup del");
-
- map[idx] = map[0] = 0;
- for (i = 1; i < idx; i++) {
- map[i] = i;
- }
- for (i = idx + 1; i < defbase_tot; i++) {
- map[i] = i - 1;
- }
-
- BKE_object_defgroup_remap_update_users(ob, map);
- MEM_freeN(map);
+ int i, defbase_tot = BLI_listbase_count(&ob->defbase) + 1;
+ int *map = MEM_mallocN(sizeof(int) * defbase_tot, "vgroup del");
+
+ map[idx] = map[0] = 0;
+ for (i = 1; i < idx; i++) {
+ map[i] = i;
+ }
+ for (i = idx + 1; i < defbase_tot; i++) {
+ map[i] = i - 1;
+ }
+
+ BKE_object_defgroup_remap_update_users(ob, map);
+ MEM_freeN(map);
}
static void object_defgroup_remove_common(Object *ob, bDeformGroup *dg, const int def_nr)
{
- object_defgroup_remove_update_users(ob, def_nr + 1);
-
- /* Remove the group */
- BLI_freelinkN(&ob->defbase, dg);
-
- /* Update the active deform index if necessary */
- if (ob->actdef > def_nr)
- ob->actdef--;
-
- /* remove all dverts */
- if (BLI_listbase_is_empty(&ob->defbase)) {
- if (ob->type == OB_MESH) {
- Mesh *me = ob->data;
- CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert);
- me->dvert = NULL;
- }
- else if (ob->type == OB_LATTICE) {
- Lattice *lt = object_defgroup_lattice_get((ID *)(ob->data));
- if (lt->dvert) {
- MEM_freeN(lt->dvert);
- lt->dvert = NULL;
- }
- }
- }
- else if (ob->actdef < 1) { /* Keep a valid active index if we still have some vgroups. */
- ob->actdef = 1;
- }
+ object_defgroup_remove_update_users(ob, def_nr + 1);
+
+ /* Remove the group */
+ BLI_freelinkN(&ob->defbase, dg);
+
+ /* Update the active deform index if necessary */
+ if (ob->actdef > def_nr)
+ ob->actdef--;
+
+ /* remove all dverts */
+ if (BLI_listbase_is_empty(&ob->defbase)) {
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+ CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert);
+ me->dvert = NULL;
+ }
+ else if (ob->type == OB_LATTICE) {
+ Lattice *lt = object_defgroup_lattice_get((ID *)(ob->data));
+ if (lt->dvert) {
+ MEM_freeN(lt->dvert);
+ lt->dvert = NULL;
+ }
+ }
+ }
+ else if (ob->actdef < 1) { /* Keep a valid active index if we still have some vgroups. */
+ ob->actdef = 1;
+ }
}
static void object_defgroup_remove_object_mode(Object *ob, bDeformGroup *dg)
{
- MDeformVert *dvert_array = NULL;
- int dvert_tot = 0;
- const int def_nr = BLI_findindex(&ob->defbase, dg);
-
- BLI_assert(def_nr != -1);
-
- BKE_object_defgroup_array_get(ob->data, &dvert_array, &dvert_tot);
-
- if (dvert_array) {
- int i, j;
- MDeformVert *dv;
- for (i = 0, dv = dvert_array; i < dvert_tot; i++, dv++) {
- MDeformWeight *dw;
-
- dw = defvert_find_index(dv, def_nr);
- defvert_remove_group(dv, dw); /* dw can be NULL */
-
- /* inline, make into a function if anything else needs to do this */
- for (j = 0; j < dv->totweight; j++) {
- if (dv->dw[j].def_nr > def_nr) {
- dv->dw[j].def_nr--;
- }
- }
- /* done */
- }
- }
-
- object_defgroup_remove_common(ob, dg, def_nr);
+ MDeformVert *dvert_array = NULL;
+ int dvert_tot = 0;
+ const int def_nr = BLI_findindex(&ob->defbase, dg);
+
+ BLI_assert(def_nr != -1);
+
+ BKE_object_defgroup_array_get(ob->data, &dvert_array, &dvert_tot);
+
+ if (dvert_array) {
+ int i, j;
+ MDeformVert *dv;
+ for (i = 0, dv = dvert_array; i < dvert_tot; i++, dv++) {
+ MDeformWeight *dw;
+
+ dw = defvert_find_index(dv, def_nr);
+ defvert_remove_group(dv, dw); /* dw can be NULL */
+
+ /* inline, make into a function if anything else needs to do this */
+ for (j = 0; j < dv->totweight; j++) {
+ if (dv->dw[j].def_nr > def_nr) {
+ dv->dw[j].def_nr--;
+ }
+ }
+ /* done */
+ }
+ }
+
+ object_defgroup_remove_common(ob, dg, def_nr);
}
static void object_defgroup_remove_edit_mode(Object *ob, bDeformGroup *dg)
{
- int i;
- const int def_nr = BLI_findindex(&ob->defbase, dg);
-
- BLI_assert(def_nr != -1);
-
- /* Make sure that no verts are using this group - if none were removed, we can skip next per-vert update. */
- if (!BKE_object_defgroup_clear(ob, dg, false)) {
- /* Nothing to do. */
- }
- /* Else, make sure that any groups with higher indices are adjusted accordingly */
- else if (ob->type == OB_MESH) {
- Mesh *me = ob->data;
- BMEditMesh *em = me->edit_mesh;
- const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
-
- BMIter iter;
- BMVert *eve;
- MDeformVert *dvert;
-
- BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
- dvert = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
-
- if (dvert) {
- for (i = 0; i < dvert->totweight; i++) {
- if (dvert->dw[i].def_nr > def_nr) {
- dvert->dw[i].def_nr--;
- }
- }
- }
- }
- }
- else if (ob->type == OB_LATTICE) {
- Lattice *lt = ((Lattice *)(ob->data))->editlatt->latt;
- BPoint *bp;
- MDeformVert *dvert = lt->dvert;
- int a, tot;
-
- if (dvert) {
- tot = lt->pntsu * lt->pntsv * lt->pntsw;
- for (a = 0, bp = lt->def; a < tot; a++, bp++, dvert++) {
- for (i = 0; i < dvert->totweight; i++) {
- if (dvert->dw[i].def_nr > def_nr) {
- dvert->dw[i].def_nr--;
- }
- }
- }
- }
- }
-
- object_defgroup_remove_common(ob, dg, def_nr);
+ int i;
+ const int def_nr = BLI_findindex(&ob->defbase, dg);
+
+ BLI_assert(def_nr != -1);
+
+ /* Make sure that no verts are using this group - if none were removed, we can skip next per-vert update. */
+ if (!BKE_object_defgroup_clear(ob, dg, false)) {
+ /* Nothing to do. */
+ }
+ /* Else, make sure that any groups with higher indices are adjusted accordingly */
+ else if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+ BMEditMesh *em = me->edit_mesh;
+ const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
+
+ BMIter iter;
+ BMVert *eve;
+ MDeformVert *dvert;
+
+ BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
+ dvert = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
+
+ if (dvert) {
+ for (i = 0; i < dvert->totweight; i++) {
+ if (dvert->dw[i].def_nr > def_nr) {
+ dvert->dw[i].def_nr--;
+ }
+ }
+ }
+ }
+ }
+ else if (ob->type == OB_LATTICE) {
+ Lattice *lt = ((Lattice *)(ob->data))->editlatt->latt;
+ BPoint *bp;
+ MDeformVert *dvert = lt->dvert;
+ int a, tot;
+
+ if (dvert) {
+ tot = lt->pntsu * lt->pntsv * lt->pntsw;
+ for (a = 0, bp = lt->def; a < tot; a++, bp++, dvert++) {
+ for (i = 0; i < dvert->totweight; i++) {
+ if (dvert->dw[i].def_nr > def_nr) {
+ dvert->dw[i].def_nr--;
+ }
+ }
+ }
+ }
+ }
+
+ object_defgroup_remove_common(ob, dg, def_nr);
}
/**
@@ -399,17 +397,17 @@ static void object_defgroup_remove_edit_mode(Object *ob, bDeformGroup *dg)
*/
void BKE_object_defgroup_remove(Object *ob, bDeformGroup *defgroup)
{
- if (ob->type == OB_GPENCIL) {
- BKE_gpencil_vgroup_remove(ob, defgroup);
- }
- else {
- if (BKE_object_is_in_editmode_vgroup(ob))
- object_defgroup_remove_edit_mode(ob, defgroup);
- else
- object_defgroup_remove_object_mode(ob, defgroup);
-
- BKE_object_batch_cache_dirty_tag(ob);
- }
+ if (ob->type == OB_GPENCIL) {
+ BKE_gpencil_vgroup_remove(ob, defgroup);
+ }
+ else {
+ if (BKE_object_is_in_editmode_vgroup(ob))
+ object_defgroup_remove_edit_mode(ob, defgroup);
+ else
+ object_defgroup_remove_object_mode(ob, defgroup);
+
+ BKE_object_batch_cache_dirty_tag(ob);
+ }
}
/**
@@ -418,40 +416,40 @@ void BKE_object_defgroup_remove(Object *ob, bDeformGroup *defgroup)
*/
void BKE_object_defgroup_remove_all_ex(struct Object *ob, bool only_unlocked)
{
- bDeformGroup *dg = (bDeformGroup *)ob->defbase.first;
- const bool edit_mode = BKE_object_is_in_editmode_vgroup(ob);
-
- if (dg) {
- while (dg) {
- bDeformGroup *next_dg = dg->next;
-
- if (!only_unlocked || (dg->flag & DG_LOCK_WEIGHT) == 0) {
- if (edit_mode)
- object_defgroup_remove_edit_mode(ob, dg);
- else
- object_defgroup_remove_object_mode(ob, dg);
- }
-
- dg = next_dg;
- }
- }
- else { /* ob->defbase is empty... */
- /* remove all dverts */
- if (ob->type == OB_MESH) {
- Mesh *me = ob->data;
- CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert);
- me->dvert = NULL;
- }
- else if (ob->type == OB_LATTICE) {
- Lattice *lt = object_defgroup_lattice_get((ID *)(ob->data));
- if (lt->dvert) {
- MEM_freeN(lt->dvert);
- lt->dvert = NULL;
- }
- }
- /* Fix counters/indices */
- ob->actdef = 0;
- }
+ bDeformGroup *dg = (bDeformGroup *)ob->defbase.first;
+ const bool edit_mode = BKE_object_is_in_editmode_vgroup(ob);
+
+ if (dg) {
+ while (dg) {
+ bDeformGroup *next_dg = dg->next;
+
+ if (!only_unlocked || (dg->flag & DG_LOCK_WEIGHT) == 0) {
+ if (edit_mode)
+ object_defgroup_remove_edit_mode(ob, dg);
+ else
+ object_defgroup_remove_object_mode(ob, dg);
+ }
+
+ dg = next_dg;
+ }
+ }
+ else { /* ob->defbase is empty... */
+ /* remove all dverts */
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+ CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert);
+ me->dvert = NULL;
+ }
+ else if (ob->type == OB_LATTICE) {
+ Lattice *lt = object_defgroup_lattice_get((ID *)(ob->data));
+ if (lt->dvert) {
+ MEM_freeN(lt->dvert);
+ lt->dvert = NULL;
+ }
+ }
+ /* Fix counters/indices */
+ ob->actdef = 0;
+ }
}
/**
@@ -459,7 +457,7 @@ void BKE_object_defgroup_remove_all_ex(struct Object *ob, bool only_unlocked)
*/
void BKE_object_defgroup_remove_all(struct Object *ob)
{
- BKE_object_defgroup_remove_all_ex(ob, false);
+ BKE_object_defgroup_remove_all_ex(ob, false);
}
/**
@@ -469,62 +467,66 @@ void BKE_object_defgroup_remove_all(struct Object *ob)
*/
int *BKE_object_defgroup_index_map_create(Object *ob_src, Object *ob_dst, int *r_map_len)
{
- /* Build src to merged mapping of vgroup indices. */
- if (BLI_listbase_is_empty(&ob_src->defbase) || BLI_listbase_is_empty(&ob_dst->defbase)) {
- *r_map_len = 0;
- return NULL;
- }
-
- bDeformGroup *dg_src;
- *r_map_len = BLI_listbase_count(&ob_src->defbase);
- int *vgroup_index_map = MEM_malloc_arrayN(*r_map_len, sizeof(*vgroup_index_map), "defgroup index map create");
- bool is_vgroup_remap_needed = false;
- int i;
-
- for (dg_src = ob_src->defbase.first, i = 0; dg_src; dg_src = dg_src->next, i++) {
- vgroup_index_map[i] = defgroup_name_index(ob_dst, dg_src->name);
- is_vgroup_remap_needed = is_vgroup_remap_needed || (vgroup_index_map[i] != i);
- }
-
- if (!is_vgroup_remap_needed) {
- MEM_freeN(vgroup_index_map);
- vgroup_index_map = NULL;
- *r_map_len = 0;
- }
-
- return vgroup_index_map;
+ /* Build src to merged mapping of vgroup indices. */
+ if (BLI_listbase_is_empty(&ob_src->defbase) || BLI_listbase_is_empty(&ob_dst->defbase)) {
+ *r_map_len = 0;
+ return NULL;
+ }
+
+ bDeformGroup *dg_src;
+ *r_map_len = BLI_listbase_count(&ob_src->defbase);
+ int *vgroup_index_map = MEM_malloc_arrayN(
+ *r_map_len, sizeof(*vgroup_index_map), "defgroup index map create");
+ bool is_vgroup_remap_needed = false;
+ int i;
+
+ for (dg_src = ob_src->defbase.first, i = 0; dg_src; dg_src = dg_src->next, i++) {
+ vgroup_index_map[i] = defgroup_name_index(ob_dst, dg_src->name);
+ is_vgroup_remap_needed = is_vgroup_remap_needed || (vgroup_index_map[i] != i);
+ }
+
+ if (!is_vgroup_remap_needed) {
+ MEM_freeN(vgroup_index_map);
+ vgroup_index_map = NULL;
+ *r_map_len = 0;
+ }
+
+ return vgroup_index_map;
}
-void BKE_object_defgroup_index_map_apply(MDeformVert *dvert, int dvert_len, const int *map, int map_len)
+void BKE_object_defgroup_index_map_apply(MDeformVert *dvert,
+ int dvert_len,
+ const int *map,
+ int map_len)
{
- if (map == NULL || map_len == 0) {
- return;
- }
-
- MDeformVert *dv = dvert;
- for (int i = 0; i < dvert_len; i++, dv++) {
- int totweight = dv->totweight;
- for (int j = 0; j < totweight; j++) {
- int def_nr = dv->dw[j].def_nr;
- if ((uint)def_nr < (uint)map_len && map[def_nr] != -1) {
- dv->dw[j].def_nr = map[def_nr];
- }
- else {
- totweight--;
- dv->dw[j] = dv->dw[totweight];
- j--;
- }
- }
- if (totweight != dv->totweight) {
- if (totweight) {
- dv->dw = MEM_reallocN(dv->dw, sizeof(*dv->dw) * totweight);
- }
- else {
- MEM_SAFE_FREE(dv->dw);
- }
- dv->totweight = totweight;
- }
- }
+ if (map == NULL || map_len == 0) {
+ return;
+ }
+
+ MDeformVert *dv = dvert;
+ for (int i = 0; i < dvert_len; i++, dv++) {
+ int totweight = dv->totweight;
+ for (int j = 0; j < totweight; j++) {
+ int def_nr = dv->dw[j].def_nr;
+ if ((uint)def_nr < (uint)map_len && map[def_nr] != -1) {
+ dv->dw[j].def_nr = map[def_nr];
+ }
+ else {
+ totweight--;
+ dv->dw[j] = dv->dw[totweight];
+ j--;
+ }
+ }
+ if (totweight != dv->totweight) {
+ if (totweight) {
+ dv->dw = MEM_reallocN(dv->dw, sizeof(*dv->dw) * totweight);
+ }
+ else {
+ MEM_SAFE_FREE(dv->dw);
+ }
+ dv->totweight = totweight;
+ }
+ }
}
/**
@@ -534,30 +536,28 @@ void BKE_object_defgroup_index_map_apply(MDeformVert *dvert, int dvert_len, cons
*/
bool BKE_object_defgroup_array_get(ID *id, MDeformVert **dvert_arr, int *dvert_tot)
{
- if (id) {
- switch (GS(id->name)) {
- case ID_ME:
- {
- Mesh *me = (Mesh *)id;
- *dvert_arr = me->dvert;
- *dvert_tot = me->totvert;
- return true;
- }
- case ID_LT:
- {
- Lattice *lt = object_defgroup_lattice_get(id);
- *dvert_arr = lt->dvert;
- *dvert_tot = lt->pntsu * lt->pntsv * lt->pntsw;
- return true;
- }
- default:
- break;
- }
- }
-
- *dvert_arr = NULL;
- *dvert_tot = 0;
- return false;
+ if (id) {
+ switch (GS(id->name)) {
+ case ID_ME: {
+ Mesh *me = (Mesh *)id;
+ *dvert_arr = me->dvert;
+ *dvert_tot = me->totvert;
+ return true;
+ }
+ case ID_LT: {
+ Lattice *lt = object_defgroup_lattice_get(id);
+ *dvert_arr = lt->dvert;
+ *dvert_tot = lt->pntsu * lt->pntsv * lt->pntsw;
+ return true;
+ }
+ default:
+ break;
+ }
+ }
+
+ *dvert_arr = NULL;
+ *dvert_tot = 0;
+ return false;
}
/** \} */
@@ -569,220 +569,225 @@ bool BKE_object_defgroup_array_get(ID *id, MDeformVert **dvert_arr, int *dvert_t
*/
bool *BKE_object_defgroup_lock_flags_get(Object *ob, const int defbase_tot)
{
- bool is_locked = false;
- int i;
- //int defbase_tot = BLI_listbase_count(&ob->defbase);
- bool *lock_flags = MEM_mallocN(defbase_tot * sizeof(bool), "defflags");
- bDeformGroup *defgroup;
-
- for (i = 0, defgroup = ob->defbase.first; i < defbase_tot && defgroup; defgroup = defgroup->next, i++) {
- lock_flags[i] = ((defgroup->flag & DG_LOCK_WEIGHT) != 0);
- is_locked |= lock_flags[i];
- }
- if (is_locked) {
- return lock_flags;
- }
-
- MEM_freeN(lock_flags);
- return NULL;
+ bool is_locked = false;
+ int i;
+ //int defbase_tot = BLI_listbase_count(&ob->defbase);
+ bool *lock_flags = MEM_mallocN(defbase_tot * sizeof(bool), "defflags");
+ bDeformGroup *defgroup;
+
+ for (i = 0, defgroup = ob->defbase.first; i < defbase_tot && defgroup;
+ defgroup = defgroup->next, i++) {
+ lock_flags[i] = ((defgroup->flag & DG_LOCK_WEIGHT) != 0);
+ is_locked |= lock_flags[i];
+ }
+ if (is_locked) {
+ return lock_flags;
+ }
+
+ MEM_freeN(lock_flags);
+ return NULL;
}
bool *BKE_object_defgroup_validmap_get(Object *ob, const int defbase_tot)
{
- bDeformGroup *dg;
- ModifierData *md;
- bool *defgroup_validmap;
- GHash *gh;
- int i, step1 = 1;
- //int defbase_tot = BLI_listbase_count(&ob->defbase);
- VirtualModifierData virtualModifierData;
-
- if (BLI_listbase_is_empty(&ob->defbase)) {
- return NULL;
- }
-
- gh = BLI_ghash_str_new_ex(__func__, defbase_tot);
-
- /* add all names to a hash table */
- for (dg = ob->defbase.first; dg; dg = dg->next) {
- BLI_ghash_insert(gh, dg->name, NULL);
- }
-
- BLI_assert(BLI_ghash_len(gh) == defbase_tot);
-
- /* now loop through the armature modifiers and identify deform bones */
- for (md = ob->modifiers.first; md; md = !md->next && step1 ? (step1 = 0), modifiers_getVirtualModifierList(ob, &virtualModifierData) : md->next) {
- if (!(md->mode & (eModifierMode_Realtime | eModifierMode_Virtual)))
- continue;
-
- if (md->type == eModifierType_Armature) {
- ArmatureModifierData *amd = (ArmatureModifierData *) md;
-
- if (amd->object && amd->object->pose) {
- bPose *pose = amd->object->pose;
- bPoseChannel *chan;
-
- for (chan = pose->chanbase.first; chan; chan = chan->next) {
- void **val_p;
- if (chan->bone->flag & BONE_NO_DEFORM)
- continue;
-
- val_p = BLI_ghash_lookup_p(gh, chan->name);
- if (val_p) {
- *val_p = POINTER_FROM_INT(1);
- }
- }
- }
- }
- }
-
- defgroup_validmap = MEM_mallocN(sizeof(*defgroup_validmap) * defbase_tot, "wpaint valid map");
-
- /* add all names to a hash table */
- for (dg = ob->defbase.first, i = 0; dg; dg = dg->next, i++) {
- defgroup_validmap[i] = (BLI_ghash_lookup(gh, dg->name) != NULL);
- }
-
- BLI_assert(i == BLI_ghash_len(gh));
-
- BLI_ghash_free(gh, NULL, NULL);
-
- return defgroup_validmap;
+ bDeformGroup *dg;
+ ModifierData *md;
+ bool *defgroup_validmap;
+ GHash *gh;
+ int i, step1 = 1;
+ //int defbase_tot = BLI_listbase_count(&ob->defbase);
+ VirtualModifierData virtualModifierData;
+
+ if (BLI_listbase_is_empty(&ob->defbase)) {
+ return NULL;
+ }
+
+ gh = BLI_ghash_str_new_ex(__func__, defbase_tot);
+
+ /* add all names to a hash table */
+ for (dg = ob->defbase.first; dg; dg = dg->next) {
+ BLI_ghash_insert(gh, dg->name, NULL);
+ }
+
+ BLI_assert(BLI_ghash_len(gh) == defbase_tot);
+
+ /* now loop through the armature modifiers and identify deform bones */
+ for (md = ob->modifiers.first; md; md = !md->next && step1 ? (step1 = 0),
+ modifiers_getVirtualModifierList(ob, &virtualModifierData) :
+ md->next) {
+ if (!(md->mode & (eModifierMode_Realtime | eModifierMode_Virtual)))
+ continue;
+
+ if (md->type == eModifierType_Armature) {
+ ArmatureModifierData *amd = (ArmatureModifierData *)md;
+
+ if (amd->object && amd->object->pose) {
+ bPose *pose = amd->object->pose;
+ bPoseChannel *chan;
+
+ for (chan = pose->chanbase.first; chan; chan = chan->next) {
+ void **val_p;
+ if (chan->bone->flag & BONE_NO_DEFORM)
+ continue;
+
+ val_p = BLI_ghash_lookup_p(gh, chan->name);
+ if (val_p) {
+ *val_p = POINTER_FROM_INT(1);
+ }
+ }
+ }
+ }
+ }
+
+ defgroup_validmap = MEM_mallocN(sizeof(*defgroup_validmap) * defbase_tot, "wpaint valid map");
+
+ /* add all names to a hash table */
+ for (dg = ob->defbase.first, i = 0; dg; dg = dg->next, i++) {
+ defgroup_validmap[i] = (BLI_ghash_lookup(gh, dg->name) != NULL);
+ }
+
+ BLI_assert(i == BLI_ghash_len(gh));
+
+ BLI_ghash_free(gh, NULL, NULL);
+
+ return defgroup_validmap;
}
/* Returns total selected vgroups,
* wpi.defbase_sel is assumed malloc'd, all values are set */
bool *BKE_object_defgroup_selected_get(Object *ob, int defbase_tot, int *r_dg_flags_sel_tot)
{
- bool *dg_selection = MEM_mallocN(defbase_tot * sizeof(bool), __func__);
- bDeformGroup *defgroup;
- unsigned int i;
- Object *armob = BKE_object_pose_armature_get(ob);
- (*r_dg_flags_sel_tot) = 0;
-
- if (armob) {
- bPose *pose = armob->pose;
- for (i = 0, defgroup = ob->defbase.first; i < defbase_tot && defgroup; defgroup = defgroup->next, i++) {
- bPoseChannel *pchan = BKE_pose_channel_find_name(pose, defgroup->name);
- if (pchan && (pchan->bone->flag & BONE_SELECTED)) {
- dg_selection[i] = true;
- (*r_dg_flags_sel_tot) += 1;
- }
- else {
- dg_selection[i] = false;
- }
- }
- }
- else {
- memset(dg_selection, false, sizeof(*dg_selection) * defbase_tot);
- }
-
- return dg_selection;
+ bool *dg_selection = MEM_mallocN(defbase_tot * sizeof(bool), __func__);
+ bDeformGroup *defgroup;
+ unsigned int i;
+ Object *armob = BKE_object_pose_armature_get(ob);
+ (*r_dg_flags_sel_tot) = 0;
+
+ if (armob) {
+ bPose *pose = armob->pose;
+ for (i = 0, defgroup = ob->defbase.first; i < defbase_tot && defgroup;
+ defgroup = defgroup->next, i++) {
+ bPoseChannel *pchan = BKE_pose_channel_find_name(pose, defgroup->name);
+ if (pchan && (pchan->bone->flag & BONE_SELECTED)) {
+ dg_selection[i] = true;
+ (*r_dg_flags_sel_tot) += 1;
+ }
+ else {
+ dg_selection[i] = false;
+ }
+ }
+ }
+ else {
+ memset(dg_selection, false, sizeof(*dg_selection) * defbase_tot);
+ }
+
+ return dg_selection;
}
/* Marks mirror vgroups in output and counts them. Output and counter assumed to be already initialized.
* Designed to be usable after BKE_object_defgroup_selected_get to extend selection to mirror.
*/
-void BKE_object_defgroup_mirror_selection(
- struct Object *ob, int defbase_tot, const bool *dg_selection,
- bool *dg_flags_sel, int *r_dg_flags_sel_tot)
+void BKE_object_defgroup_mirror_selection(struct Object *ob,
+ int defbase_tot,
+ const bool *dg_selection,
+ bool *dg_flags_sel,
+ int *r_dg_flags_sel_tot)
{
- bDeformGroup *defgroup;
- unsigned int i;
- int i_mirr;
-
- for (i = 0, defgroup = ob->defbase.first; i < defbase_tot && defgroup; defgroup = defgroup->next, i++) {
- if (dg_selection[i]) {
- char name_flip[MAXBONENAME];
-
- BLI_string_flip_side_name(name_flip, defgroup->name, false, sizeof(name_flip));
- i_mirr = STREQ(name_flip, defgroup->name) ? i : defgroup_name_index(ob, name_flip);
-
- if ((i_mirr >= 0 && i_mirr < defbase_tot) && (dg_flags_sel[i_mirr] == false)) {
- dg_flags_sel[i_mirr] = true;
- (*r_dg_flags_sel_tot) += 1;
- }
- }
- }
+ bDeformGroup *defgroup;
+ unsigned int i;
+ int i_mirr;
+
+ for (i = 0, defgroup = ob->defbase.first; i < defbase_tot && defgroup;
+ defgroup = defgroup->next, i++) {
+ if (dg_selection[i]) {
+ char name_flip[MAXBONENAME];
+
+ BLI_string_flip_side_name(name_flip, defgroup->name, false, sizeof(name_flip));
+ i_mirr = STREQ(name_flip, defgroup->name) ? i : defgroup_name_index(ob, name_flip);
+
+ if ((i_mirr >= 0 && i_mirr < defbase_tot) && (dg_flags_sel[i_mirr] == false)) {
+ dg_flags_sel[i_mirr] = true;
+ (*r_dg_flags_sel_tot) += 1;
+ }
+ }
+ }
}
/**
* Return the subset type of the Vertex Group Selection
*/
-bool *BKE_object_defgroup_subset_from_select_type(
- Object *ob, eVGroupSelect subset_type, int *r_defgroup_tot, int *r_subset_count)
+bool *BKE_object_defgroup_subset_from_select_type(Object *ob,
+ eVGroupSelect subset_type,
+ int *r_defgroup_tot,
+ int *r_subset_count)
{
- bool *defgroup_validmap = NULL;
- *r_defgroup_tot = BLI_listbase_count(&ob->defbase);
-
- switch (subset_type) {
- case WT_VGROUP_ACTIVE:
- {
- const int def_nr_active = ob->actdef - 1;
- defgroup_validmap = MEM_mallocN(*r_defgroup_tot * sizeof(*defgroup_validmap), __func__);
- memset(defgroup_validmap, false, *r_defgroup_tot * sizeof(*defgroup_validmap));
- if ((def_nr_active >= 0) && (def_nr_active < *r_defgroup_tot)) {
- *r_subset_count = 1;
- defgroup_validmap[def_nr_active] = true;
- }
- else {
- *r_subset_count = 0;
- }
- break;
- }
- case WT_VGROUP_BONE_SELECT:
- {
- defgroup_validmap = BKE_object_defgroup_selected_get(ob, *r_defgroup_tot, r_subset_count);
- break;
- }
- case WT_VGROUP_BONE_DEFORM:
- {
- int i;
- defgroup_validmap = BKE_object_defgroup_validmap_get(ob, *r_defgroup_tot);
- *r_subset_count = 0;
- for (i = 0; i < *r_defgroup_tot; i++) {
- if (defgroup_validmap[i] == true) {
- *r_subset_count += 1;
- }
- }
- break;
- }
- case WT_VGROUP_BONE_DEFORM_OFF:
- {
- int i;
- defgroup_validmap = BKE_object_defgroup_validmap_get(ob, *r_defgroup_tot);
- *r_subset_count = 0;
- for (i = 0; i < *r_defgroup_tot; i++) {
- defgroup_validmap[i] = !defgroup_validmap[i];
- if (defgroup_validmap[i] == true) {
- *r_subset_count += 1;
- }
- }
- break;
- }
- case WT_VGROUP_ALL:
- default:
- {
- defgroup_validmap = MEM_mallocN(*r_defgroup_tot * sizeof(*defgroup_validmap), __func__);
- memset(defgroup_validmap, true, *r_defgroup_tot * sizeof(*defgroup_validmap));
- *r_subset_count = *r_defgroup_tot;
- break;
- }
- }
-
- return defgroup_validmap;
+ bool *defgroup_validmap = NULL;
+ *r_defgroup_tot = BLI_listbase_count(&ob->defbase);
+
+ switch (subset_type) {
+ case WT_VGROUP_ACTIVE: {
+ const int def_nr_active = ob->actdef - 1;
+ defgroup_validmap = MEM_mallocN(*r_defgroup_tot * sizeof(*defgroup_validmap), __func__);
+ memset(defgroup_validmap, false, *r_defgroup_tot * sizeof(*defgroup_validmap));
+ if ((def_nr_active >= 0) && (def_nr_active < *r_defgroup_tot)) {
+ *r_subset_count = 1;
+ defgroup_validmap[def_nr_active] = true;
+ }
+ else {
+ *r_subset_count = 0;
+ }
+ break;
+ }
+ case WT_VGROUP_BONE_SELECT: {
+ defgroup_validmap = BKE_object_defgroup_selected_get(ob, *r_defgroup_tot, r_subset_count);
+ break;
+ }
+ case WT_VGROUP_BONE_DEFORM: {
+ int i;
+ defgroup_validmap = BKE_object_defgroup_validmap_get(ob, *r_defgroup_tot);
+ *r_subset_count = 0;
+ for (i = 0; i < *r_defgroup_tot; i++) {
+ if (defgroup_validmap[i] == true) {
+ *r_subset_count += 1;
+ }
+ }
+ break;
+ }
+ case WT_VGROUP_BONE_DEFORM_OFF: {
+ int i;
+ defgroup_validmap = BKE_object_defgroup_validmap_get(ob, *r_defgroup_tot);
+ *r_subset_count = 0;
+ for (i = 0; i < *r_defgroup_tot; i++) {
+ defgroup_validmap[i] = !defgroup_validmap[i];
+ if (defgroup_validmap[i] == true) {
+ *r_subset_count += 1;
+ }
+ }
+ break;
+ }
+ case WT_VGROUP_ALL:
+ default: {
+ defgroup_validmap = MEM_mallocN(*r_defgroup_tot * sizeof(*defgroup_validmap), __func__);
+ memset(defgroup_validmap, true, *r_defgroup_tot * sizeof(*defgroup_validmap));
+ *r_subset_count = *r_defgroup_tot;
+ break;
+ }
+ }
+
+ return defgroup_validmap;
}
/**
* store indices from the defgroup_validmap (faster lookups in some cases)
*/
-void BKE_object_defgroup_subset_to_index_array(
- const bool *defgroup_validmap, const int defgroup_tot, int *r_defgroup_subset_map)
+void BKE_object_defgroup_subset_to_index_array(const bool *defgroup_validmap,
+ const int defgroup_tot,
+ int *r_defgroup_subset_map)
{
- int i, j = 0;
- for (i = 0; i < defgroup_tot; i++) {
- if (defgroup_validmap[i]) {
- r_defgroup_subset_map[j++] = i;
- }
- }
+ int i, j = 0;
+ for (i = 0; i < defgroup_tot; i++) {
+ if (defgroup_validmap[i]) {
+ r_defgroup_subset_map[j++] = i;
+ }
+ }
}
diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c
index 41fb78761b8..2544bb6a8f0 100644
--- a/source/blender/blenkernel/intern/object_dupli.c
+++ b/source/blender/blenkernel/intern/object_dupli.c
@@ -65,144 +65,147 @@
/* Dupli-Geometry */
typedef struct DupliContext {
- Depsgraph *depsgraph;
- Collection *collection; /* XXX child objects are selected from this group if set, could be nicer */
- Object *obedit; /* Only to check if the object is in edit-mode. */
+ Depsgraph *depsgraph;
+ Collection
+ *collection; /* XXX child objects are selected from this group if set, could be nicer */
+ Object *obedit; /* Only to check if the object is in edit-mode. */
- Scene *scene;
- ViewLayer *view_layer;
- Object *object;
- float space_mat[4][4];
+ Scene *scene;
+ ViewLayer *view_layer;
+ Object *object;
+ float space_mat[4][4];
- int persistent_id[MAX_DUPLI_RECUR];
- int level;
+ int persistent_id[MAX_DUPLI_RECUR];
+ int level;
- const struct DupliGenerator *gen;
+ const struct DupliGenerator *gen;
- /* result containers */
- ListBase *duplilist; /* legacy doubly-linked list */
+ /* result containers */
+ ListBase *duplilist; /* legacy doubly-linked list */
} DupliContext;
typedef struct DupliGenerator {
- short type; /* dupli type */
- void (*make_duplis)(const DupliContext *ctx);
+ short type; /* dupli type */
+ void (*make_duplis)(const DupliContext *ctx);
} DupliGenerator;
static const DupliGenerator *get_dupli_generator(const DupliContext *ctx);
/* create initial context for root object */
static void init_context(
- DupliContext *r_ctx, Depsgraph *depsgraph,
- Scene *scene, Object *ob, float space_mat[4][4])
+ DupliContext *r_ctx, Depsgraph *depsgraph, Scene *scene, Object *ob, float space_mat[4][4])
{
- r_ctx->depsgraph = depsgraph;
- r_ctx->scene = scene;
- r_ctx->view_layer = DEG_get_evaluated_view_layer(depsgraph);
- r_ctx->collection = NULL;
-
- r_ctx->object = ob;
- r_ctx->obedit = OBEDIT_FROM_OBACT(ob);
- if (space_mat)
- copy_m4_m4(r_ctx->space_mat, space_mat);
- else
- unit_m4(r_ctx->space_mat);
- r_ctx->level = 0;
-
- r_ctx->gen = get_dupli_generator(r_ctx);
-
- r_ctx->duplilist = NULL;
+ r_ctx->depsgraph = depsgraph;
+ r_ctx->scene = scene;
+ r_ctx->view_layer = DEG_get_evaluated_view_layer(depsgraph);
+ r_ctx->collection = NULL;
+
+ r_ctx->object = ob;
+ r_ctx->obedit = OBEDIT_FROM_OBACT(ob);
+ if (space_mat)
+ copy_m4_m4(r_ctx->space_mat, space_mat);
+ else
+ unit_m4(r_ctx->space_mat);
+ r_ctx->level = 0;
+
+ r_ctx->gen = get_dupli_generator(r_ctx);
+
+ r_ctx->duplilist = NULL;
}
/* create sub-context for recursive duplis */
-static void copy_dupli_context(DupliContext *r_ctx, const DupliContext *ctx, Object *ob, float mat[4][4], int index)
+static void copy_dupli_context(
+ DupliContext *r_ctx, const DupliContext *ctx, Object *ob, float mat[4][4], int index)
{
- *r_ctx = *ctx;
+ *r_ctx = *ctx;
- /* XXX annoying, previously was done by passing an ID* argument, this at least is more explicit */
- if (ctx->gen->type == OB_DUPLICOLLECTION)
- r_ctx->collection = ctx->object->instance_collection;
+ /* XXX annoying, previously was done by passing an ID* argument, this at least is more explicit */
+ if (ctx->gen->type == OB_DUPLICOLLECTION)
+ r_ctx->collection = ctx->object->instance_collection;
- r_ctx->object = ob;
- if (mat)
- mul_m4_m4m4(r_ctx->space_mat, (float (*)[4])ctx->space_mat, mat);
- r_ctx->persistent_id[r_ctx->level] = index;
- ++r_ctx->level;
+ r_ctx->object = ob;
+ if (mat)
+ mul_m4_m4m4(r_ctx->space_mat, (float(*)[4])ctx->space_mat, mat);
+ r_ctx->persistent_id[r_ctx->level] = index;
+ ++r_ctx->level;
- r_ctx->gen = get_dupli_generator(r_ctx);
+ r_ctx->gen = get_dupli_generator(r_ctx);
}
/* generate a dupli instance
* mat is transform of the object relative to current context (including object obmat)
*/
-static DupliObject *make_dupli(const DupliContext *ctx,
- Object *ob, float mat[4][4], int index)
+static DupliObject *make_dupli(const DupliContext *ctx, Object *ob, float mat[4][4], int index)
{
- DupliObject *dob;
- int i;
-
- /* add a DupliObject instance to the result container */
- if (ctx->duplilist) {
- dob = MEM_callocN(sizeof(DupliObject), "dupli object");
- BLI_addtail(ctx->duplilist, dob);
- }
- else {
- return NULL;
- }
-
- dob->ob = ob;
- mul_m4_m4m4(dob->mat, (float (*)[4])ctx->space_mat, mat);
- dob->type = ctx->gen->type;
-
- /* set persistent id, which is an array with a persistent index for each level
- * (particle number, vertex number, ..). by comparing this we can find the same
- * dupli object between frames, which is needed for motion blur. last level
- * goes first in the array. */
- dob->persistent_id[0] = index;
- for (i = 1; i < ctx->level + 1; i++)
- dob->persistent_id[i] = ctx->persistent_id[ctx->level - i];
- /* fill rest of values with INT_MAX which index will never have as value */
- for (; i < MAX_DUPLI_RECUR; i++)
- dob->persistent_id[i] = INT_MAX;
-
- /* metaballs never draw in duplis, they are instead merged into one by the basis
- * mball outside of the group. this does mean that if that mball is not in the
- * scene, they will not show up at all, limitation that should be solved once. */
- if (ob->type == OB_MBALL)
- dob->no_draw = true;
-
- /* random number */
- /* the logic here is designed to match Cycles */
- dob->random_id = BLI_hash_string(dob->ob->id.name + 2);
-
- if (dob->persistent_id[0] != INT_MAX) {
- for (i = 0; i < MAX_DUPLI_RECUR * 2; i++) {
- dob->random_id = BLI_hash_int_2d(dob->random_id, (unsigned int)dob->persistent_id[i]);
- }
- }
- else {
- dob->random_id = BLI_hash_int_2d(dob->random_id, 0);
- }
-
- if (ctx->object != ob) {
- dob->random_id ^= BLI_hash_int(BLI_hash_string(ctx->object->id.name + 2));
- }
-
- return dob;
+ DupliObject *dob;
+ int i;
+
+ /* add a DupliObject instance to the result container */
+ if (ctx->duplilist) {
+ dob = MEM_callocN(sizeof(DupliObject), "dupli object");
+ BLI_addtail(ctx->duplilist, dob);
+ }
+ else {
+ return NULL;
+ }
+
+ dob->ob = ob;
+ mul_m4_m4m4(dob->mat, (float(*)[4])ctx->space_mat, mat);
+ dob->type = ctx->gen->type;
+
+ /* set persistent id, which is an array with a persistent index for each level
+ * (particle number, vertex number, ..). by comparing this we can find the same
+ * dupli object between frames, which is needed for motion blur. last level
+ * goes first in the array. */
+ dob->persistent_id[0] = index;
+ for (i = 1; i < ctx->level + 1; i++)
+ dob->persistent_id[i] = ctx->persistent_id[ctx->level - i];
+ /* fill rest of values with INT_MAX which index will never have as value */
+ for (; i < MAX_DUPLI_RECUR; i++)
+ dob->persistent_id[i] = INT_MAX;
+
+ /* metaballs never draw in duplis, they are instead merged into one by the basis
+ * mball outside of the group. this does mean that if that mball is not in the
+ * scene, they will not show up at all, limitation that should be solved once. */
+ if (ob->type == OB_MBALL)
+ dob->no_draw = true;
+
+ /* random number */
+ /* the logic here is designed to match Cycles */
+ dob->random_id = BLI_hash_string(dob->ob->id.name + 2);
+
+ if (dob->persistent_id[0] != INT_MAX) {
+ for (i = 0; i < MAX_DUPLI_RECUR * 2; i++) {
+ dob->random_id = BLI_hash_int_2d(dob->random_id, (unsigned int)dob->persistent_id[i]);
+ }
+ }
+ else {
+ dob->random_id = BLI_hash_int_2d(dob->random_id, 0);
+ }
+
+ if (ctx->object != ob) {
+ dob->random_id ^= BLI_hash_int(BLI_hash_string(ctx->object->id.name + 2));
+ }
+
+ return dob;
}
/* recursive dupli objects
* space_mat is the local dupli space (excluding dupli object obmat!)
*/
-static void make_recursive_duplis(const DupliContext *ctx, Object *ob, float space_mat[4][4], int index)
+static void make_recursive_duplis(const DupliContext *ctx,
+ Object *ob,
+ float space_mat[4][4],
+ int index)
{
- /* simple preventing of too deep nested collections with MAX_DUPLI_RECUR */
- if (ctx->level < MAX_DUPLI_RECUR) {
- DupliContext rctx;
- copy_dupli_context(&rctx, ctx, ob, space_mat, index);
- if (rctx.gen) {
- rctx.gen->make_duplis(&rctx);
- }
- }
+ /* simple preventing of too deep nested collections with MAX_DUPLI_RECUR */
+ if (ctx->level < MAX_DUPLI_RECUR) {
+ DupliContext rctx;
+ copy_dupli_context(&rctx, ctx, ob, space_mat, index);
+ if (rctx.gen) {
+ rctx.gen->make_duplis(&rctx);
+ }
+ }
}
/* ---- Child Duplis ---- */
@@ -211,810 +214,821 @@ typedef void (*MakeChildDuplisFunc)(const DupliContext *ctx, void *userdata, Obj
static bool is_child(const Object *ob, const Object *parent)
{
- const Object *ob_parent = ob->parent;
- while (ob_parent) {
- if (ob_parent == parent)
- return true;
- ob_parent = ob_parent->parent;
- }
- return false;
+ const Object *ob_parent = ob->parent;
+ while (ob_parent) {
+ if (ob_parent == parent)
+ return true;
+ ob_parent = ob_parent->parent;
+ }
+ return false;
}
/* create duplis from every child in scene or collection */
-static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChildDuplisFunc make_child_duplis_cb)
+static void make_child_duplis(const DupliContext *ctx,
+ void *userdata,
+ MakeChildDuplisFunc make_child_duplis_cb)
{
- Object *parent = ctx->object;
-
- if (ctx->collection) {
- eEvaluationMode mode = DEG_get_mode(ctx->depsgraph);
- FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(ctx->collection, ob, mode)
- {
- if ((ob != ctx->obedit) && is_child(ob, parent)) {
- DupliContext pctx;
- copy_dupli_context(&pctx, ctx, ctx->object, NULL, _base_id);
-
- /* metaballs have a different dupli handling */
- if (ob->type != OB_MBALL) {
- ob->flag |= OB_DONE; /* doesn't render */
- }
- make_child_duplis_cb(&pctx, userdata, ob);
- }
- }
- FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
- }
- else {
- int baseid = 0;
- ViewLayer *view_layer = ctx->view_layer;
- for (Base *base = view_layer->object_bases.first; base; base = base->next, baseid++) {
- Object *ob = base->object;
- if ((ob != ctx->obedit) && is_child(ob, parent)) {
- DupliContext pctx;
- copy_dupli_context(&pctx, ctx, ctx->object, NULL, baseid);
-
- /* metaballs have a different dupli handling */
- if (ob->type != OB_MBALL)
- ob->flag |= OB_DONE; /* doesn't render */
-
- make_child_duplis_cb(&pctx, userdata, ob);
- }
- }
- }
+ Object *parent = ctx->object;
+
+ if (ctx->collection) {
+ eEvaluationMode mode = DEG_get_mode(ctx->depsgraph);
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (ctx->collection, ob, mode) {
+ if ((ob != ctx->obedit) && is_child(ob, parent)) {
+ DupliContext pctx;
+ copy_dupli_context(&pctx, ctx, ctx->object, NULL, _base_id);
+
+ /* metaballs have a different dupli handling */
+ if (ob->type != OB_MBALL) {
+ ob->flag |= OB_DONE; /* doesn't render */
+ }
+ make_child_duplis_cb(&pctx, userdata, ob);
+ }
+ }
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
+ }
+ else {
+ int baseid = 0;
+ ViewLayer *view_layer = ctx->view_layer;
+ for (Base *base = view_layer->object_bases.first; base; base = base->next, baseid++) {
+ Object *ob = base->object;
+ if ((ob != ctx->obedit) && is_child(ob, parent)) {
+ DupliContext pctx;
+ copy_dupli_context(&pctx, ctx, ctx->object, NULL, baseid);
+
+ /* metaballs have a different dupli handling */
+ if (ob->type != OB_MBALL)
+ ob->flag |= OB_DONE; /* doesn't render */
+
+ make_child_duplis_cb(&pctx, userdata, ob);
+ }
+ }
+ }
}
-
/*---- Implementations ----*/
/* OB_DUPLICOLLECTION */
static void make_duplis_collection(const DupliContext *ctx)
{
- Object *ob = ctx->object;
- Collection *collection;
- float collection_mat[4][4];
-
- if (ob->instance_collection == NULL) return;
- collection = ob->instance_collection;
-
- /* combine collection offset and obmat */
- unit_m4(collection_mat);
- sub_v3_v3(collection_mat[3], collection->instance_offset);
- mul_m4_m4m4(collection_mat, ob->obmat, collection_mat);
- /* don't access 'ob->obmat' from now on. */
-
- eEvaluationMode mode = DEG_get_mode(ctx->depsgraph);
- FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(collection, cob, mode)
- {
- if (cob != ob) {
- float mat[4][4];
-
- /* collection dupli offset, should apply after everything else */
- mul_m4_m4m4(mat, collection_mat, cob->obmat);
-
- make_dupli(ctx, cob, mat, _base_id);
-
- /* recursion */
- make_recursive_duplis(ctx, cob, collection_mat, _base_id);
- }
- }
- FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
+ Object *ob = ctx->object;
+ Collection *collection;
+ float collection_mat[4][4];
+
+ if (ob->instance_collection == NULL)
+ return;
+ collection = ob->instance_collection;
+
+ /* combine collection offset and obmat */
+ unit_m4(collection_mat);
+ sub_v3_v3(collection_mat[3], collection->instance_offset);
+ mul_m4_m4m4(collection_mat, ob->obmat, collection_mat);
+ /* don't access 'ob->obmat' from now on. */
+
+ eEvaluationMode mode = DEG_get_mode(ctx->depsgraph);
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (collection, cob, mode) {
+ if (cob != ob) {
+ float mat[4][4];
+
+ /* collection dupli offset, should apply after everything else */
+ mul_m4_m4m4(mat, collection_mat, cob->obmat);
+
+ make_dupli(ctx, cob, mat, _base_id);
+
+ /* recursion */
+ make_recursive_duplis(ctx, cob, collection_mat, _base_id);
+ }
+ }
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
}
static const DupliGenerator gen_dupli_collection = {
- OB_DUPLICOLLECTION, /* type */
- make_duplis_collection /* make_duplis */
+ OB_DUPLICOLLECTION, /* type */
+ make_duplis_collection /* make_duplis */
};
/* OB_DUPLIVERTS */
typedef struct VertexDupliData {
- Mesh *me_eval;
- BMEditMesh *edit_mesh;
- int totvert;
- float (*orco)[3];
- bool use_rotation;
-
- const DupliContext *ctx;
- Object *inst_ob; /* object to instantiate (argument for vertex map callback) */
- float child_imat[4][4];
+ Mesh *me_eval;
+ BMEditMesh *edit_mesh;
+ int totvert;
+ float (*orco)[3];
+ bool use_rotation;
+
+ const DupliContext *ctx;
+ Object *inst_ob; /* object to instantiate (argument for vertex map callback) */
+ float child_imat[4][4];
} VertexDupliData;
-static void get_duplivert_transform(const float co[3], const short no[3],
- bool use_rotation, short axis, short upflag, float mat[4][4])
+static void get_duplivert_transform(const float co[3],
+ const short no[3],
+ bool use_rotation,
+ short axis,
+ short upflag,
+ float mat[4][4])
{
- float quat[4];
- const float size[3] = {1.0f, 1.0f, 1.0f};
-
- if (use_rotation) {
- /* construct rotation matrix from normals */
- float nor_f[3];
- nor_f[0] = (float)-no[0];
- nor_f[1] = (float)-no[1];
- nor_f[2] = (float)-no[2];
- vec_to_quat(quat, nor_f, axis, upflag);
- }
- else
- unit_qt(quat);
-
- loc_quat_size_to_mat4(mat, co, quat, size);
+ float quat[4];
+ const float size[3] = {1.0f, 1.0f, 1.0f};
+
+ if (use_rotation) {
+ /* construct rotation matrix from normals */
+ float nor_f[3];
+ nor_f[0] = (float)-no[0];
+ nor_f[1] = (float)-no[1];
+ nor_f[2] = (float)-no[2];
+ vec_to_quat(quat, nor_f, axis, upflag);
+ }
+ else
+ unit_qt(quat);
+
+ loc_quat_size_to_mat4(mat, co, quat, size);
}
-static void vertex_dupli(const VertexDupliData *vdd, int index, const float co[3], const short no[3])
+static void vertex_dupli(const VertexDupliData *vdd,
+ int index,
+ const float co[3],
+ const short no[3])
{
- Object *inst_ob = vdd->inst_ob;
- DupliObject *dob;
- float obmat[4][4], space_mat[4][4];
+ Object *inst_ob = vdd->inst_ob;
+ DupliObject *dob;
+ float obmat[4][4], space_mat[4][4];
- /* obmat is transform to vertex */
- get_duplivert_transform(co, no, vdd->use_rotation, inst_ob->trackflag, inst_ob->upflag, obmat);
- /* make offset relative to inst_ob using relative child transform */
- mul_mat3_m4_v3((float (*)[4])vdd->child_imat, obmat[3]);
- /* apply obmat _after_ the local vertex transform */
- mul_m4_m4m4(obmat, inst_ob->obmat, obmat);
+ /* obmat is transform to vertex */
+ get_duplivert_transform(co, no, vdd->use_rotation, inst_ob->trackflag, inst_ob->upflag, obmat);
+ /* make offset relative to inst_ob using relative child transform */
+ mul_mat3_m4_v3((float(*)[4])vdd->child_imat, obmat[3]);
+ /* apply obmat _after_ the local vertex transform */
+ mul_m4_m4m4(obmat, inst_ob->obmat, obmat);
- /* space matrix is constructed by removing obmat transform,
- * this yields the worldspace transform for recursive duplis
- */
- mul_m4_m4m4(space_mat, obmat, inst_ob->imat);
+ /* space matrix is constructed by removing obmat transform,
+ * this yields the worldspace transform for recursive duplis
+ */
+ mul_m4_m4m4(space_mat, obmat, inst_ob->imat);
- dob = make_dupli(vdd->ctx, vdd->inst_ob, obmat, index);
+ dob = make_dupli(vdd->ctx, vdd->inst_ob, obmat, index);
- if (vdd->orco)
- copy_v3_v3(dob->orco, vdd->orco[index]);
+ if (vdd->orco)
+ copy_v3_v3(dob->orco, vdd->orco[index]);
- /* recursion */
- make_recursive_duplis(vdd->ctx, vdd->inst_ob, space_mat, index);
+ /* recursion */
+ make_recursive_duplis(vdd->ctx, vdd->inst_ob, space_mat, index);
}
static void make_child_duplis_verts(const DupliContext *ctx, void *userdata, Object *child)
{
- VertexDupliData *vdd = userdata;
- Mesh *me_eval = vdd->me_eval;
-
- vdd->inst_ob = child;
- invert_m4_m4(child->imat, child->obmat);
- /* relative transform from parent to child space */
- mul_m4_m4m4(vdd->child_imat, child->imat, ctx->object->obmat);
-
- const MVert *mvert = me_eval->mvert;
- const int *origindex = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX);
-
- for (int i = 0, j = 0; i < me_eval->totvert; i++) {
- if (origindex == NULL || origindex[i] != ORIGINDEX_NONE) {
- vertex_dupli(vdd, j++, mvert[i].co, mvert[i].no);
- }
- }
+ VertexDupliData *vdd = userdata;
+ Mesh *me_eval = vdd->me_eval;
+
+ vdd->inst_ob = child;
+ invert_m4_m4(child->imat, child->obmat);
+ /* relative transform from parent to child space */
+ mul_m4_m4m4(vdd->child_imat, child->imat, ctx->object->obmat);
+
+ const MVert *mvert = me_eval->mvert;
+ const int *origindex = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX);
+
+ for (int i = 0, j = 0; i < me_eval->totvert; i++) {
+ if (origindex == NULL || origindex[i] != ORIGINDEX_NONE) {
+ vertex_dupli(vdd, j++, mvert[i].co, mvert[i].no);
+ }
+ }
}
static void make_duplis_verts(const DupliContext *ctx)
{
- Object *parent = ctx->object;
- VertexDupliData vdd;
-
- vdd.ctx = ctx;
- vdd.use_rotation = parent->transflag & OB_DUPLIROT;
-
- /* gather mesh info */
- {
- vdd.edit_mesh = BKE_editmesh_from_object(parent);
-
- /* We do not need any render-specific handling anymore, depsgraph takes care of that. */
- /* NOTE: Do direct access to the evaluated mesh: this function is used
- * during meta balls evaluation. But even without those all the objects
- * which are needed for correct instancing are already evaluated. */
- if (vdd.edit_mesh != NULL) {
- vdd.me_eval = vdd.edit_mesh->mesh_eval_cage;
- }
- else {
- vdd.me_eval = parent->runtime.mesh_eval;
- }
-
- if (vdd.me_eval == NULL) {
- return;
- }
-
- vdd.orco = CustomData_get_layer(&vdd.me_eval->vdata, CD_ORCO);
- vdd.totvert = vdd.me_eval->totvert;
- }
-
- make_child_duplis(ctx, &vdd, make_child_duplis_verts);
-
- vdd.me_eval = NULL;
+ Object *parent = ctx->object;
+ VertexDupliData vdd;
+
+ vdd.ctx = ctx;
+ vdd.use_rotation = parent->transflag & OB_DUPLIROT;
+
+ /* gather mesh info */
+ {
+ vdd.edit_mesh = BKE_editmesh_from_object(parent);
+
+ /* We do not need any render-specific handling anymore, depsgraph takes care of that. */
+ /* NOTE: Do direct access to the evaluated mesh: this function is used
+ * during meta balls evaluation. But even without those all the objects
+ * which are needed for correct instancing are already evaluated. */
+ if (vdd.edit_mesh != NULL) {
+ vdd.me_eval = vdd.edit_mesh->mesh_eval_cage;
+ }
+ else {
+ vdd.me_eval = parent->runtime.mesh_eval;
+ }
+
+ if (vdd.me_eval == NULL) {
+ return;
+ }
+
+ vdd.orco = CustomData_get_layer(&vdd.me_eval->vdata, CD_ORCO);
+ vdd.totvert = vdd.me_eval->totvert;
+ }
+
+ make_child_duplis(ctx, &vdd, make_child_duplis_verts);
+
+ vdd.me_eval = NULL;
}
static const DupliGenerator gen_dupli_verts = {
- OB_DUPLIVERTS, /* type */
- make_duplis_verts /* make_duplis */
+ OB_DUPLIVERTS, /* type */
+ make_duplis_verts /* make_duplis */
};
/* OB_DUPLIVERTS - FONT */
-static Object *find_family_object(Main *bmain, const char *family, size_t family_len, unsigned int ch, GHash *family_gh)
+static Object *find_family_object(
+ Main *bmain, const char *family, size_t family_len, unsigned int ch, GHash *family_gh)
{
- Object **ob_pt;
- Object *ob;
- void *ch_key = POINTER_FROM_UINT(ch);
-
- if ((ob_pt = (Object **)BLI_ghash_lookup_p(family_gh, ch_key))) {
- ob = *ob_pt;
- }
- else {
- char ch_utf8[7];
- size_t ch_utf8_len;
-
- ch_utf8_len = BLI_str_utf8_from_unicode(ch, ch_utf8);
- ch_utf8[ch_utf8_len] = '\0';
- ch_utf8_len += 1; /* compare with null terminator */
-
- for (ob = bmain->objects.first; ob; ob = ob->id.next) {
- if (STREQLEN(ob->id.name + 2 + family_len, ch_utf8, ch_utf8_len)) {
- if (STREQLEN(ob->id.name + 2, family, family_len)) {
- break;
- }
- }
- }
-
- /* inserted value can be NULL, just to save searches in future */
- BLI_ghash_insert(family_gh, ch_key, ob);
- }
-
- return ob;
+ Object **ob_pt;
+ Object *ob;
+ void *ch_key = POINTER_FROM_UINT(ch);
+
+ if ((ob_pt = (Object **)BLI_ghash_lookup_p(family_gh, ch_key))) {
+ ob = *ob_pt;
+ }
+ else {
+ char ch_utf8[7];
+ size_t ch_utf8_len;
+
+ ch_utf8_len = BLI_str_utf8_from_unicode(ch, ch_utf8);
+ ch_utf8[ch_utf8_len] = '\0';
+ ch_utf8_len += 1; /* compare with null terminator */
+
+ for (ob = bmain->objects.first; ob; ob = ob->id.next) {
+ if (STREQLEN(ob->id.name + 2 + family_len, ch_utf8, ch_utf8_len)) {
+ if (STREQLEN(ob->id.name + 2, family, family_len)) {
+ break;
+ }
+ }
+ }
+
+ /* inserted value can be NULL, just to save searches in future */
+ BLI_ghash_insert(family_gh, ch_key, ob);
+ }
+
+ return ob;
}
static void make_duplis_font(const DupliContext *ctx)
{
- Object *par = ctx->object;
- GHash *family_gh;
- Object *ob;
- Curve *cu;
- struct CharTrans *ct, *chartransdata = NULL;
- float vec[3], obmat[4][4], pmat[4][4], fsize, xof, yof;
- int text_len, a;
- size_t family_len;
- const wchar_t *text = NULL;
- bool text_free = false;
+ Object *par = ctx->object;
+ GHash *family_gh;
+ Object *ob;
+ Curve *cu;
+ struct CharTrans *ct, *chartransdata = NULL;
+ float vec[3], obmat[4][4], pmat[4][4], fsize, xof, yof;
+ int text_len, a;
+ size_t family_len;
+ const wchar_t *text = NULL;
+ bool text_free = false;
- /* font dupliverts not supported inside collections */
- if (ctx->collection)
- return;
+ /* font dupliverts not supported inside collections */
+ if (ctx->collection)
+ return;
- copy_m4_m4(pmat, par->obmat);
+ copy_m4_m4(pmat, par->obmat);
- /* in par the family name is stored, use this to find the other objects */
+ /* in par the family name is stored, use this to find the other objects */
- BKE_vfont_to_curve_ex(par, par->data, FO_DUPLI, NULL,
- &text, &text_len, &text_free, &chartransdata);
+ BKE_vfont_to_curve_ex(
+ par, par->data, FO_DUPLI, NULL, &text, &text_len, &text_free, &chartransdata);
- if (text == NULL || chartransdata == NULL) {
- return;
- }
+ if (text == NULL || chartransdata == NULL) {
+ return;
+ }
- cu = par->data;
- fsize = cu->fsize;
- xof = cu->xof;
- yof = cu->yof;
+ cu = par->data;
+ fsize = cu->fsize;
+ xof = cu->xof;
+ yof = cu->yof;
- ct = chartransdata;
+ ct = chartransdata;
- /* cache result */
- family_len = strlen(cu->family);
- family_gh = BLI_ghash_int_new_ex(__func__, 256);
+ /* cache result */
+ family_len = strlen(cu->family);
+ family_gh = BLI_ghash_int_new_ex(__func__, 256);
- /* advance matching BLI_strncpy_wchar_from_utf8 */
- for (a = 0; a < text_len; a++, ct++) {
+ /* advance matching BLI_strncpy_wchar_from_utf8 */
+ for (a = 0; a < text_len; a++, ct++) {
- /* XXX That G.main is *really* ugly, but not sure what to do here...
- * Definitively don't think it would be safe to put back Main *bmain pointer in DupliContext as done in 2.7x? */
- ob = find_family_object(G.main, cu->family, family_len, (unsigned int)text[a], family_gh);
- if (ob) {
- vec[0] = fsize * (ct->xof - xof);
- vec[1] = fsize * (ct->yof - yof);
- vec[2] = 0.0;
+ /* XXX That G.main is *really* ugly, but not sure what to do here...
+ * Definitively don't think it would be safe to put back Main *bmain pointer in DupliContext as done in 2.7x? */
+ ob = find_family_object(G.main, cu->family, family_len, (unsigned int)text[a], family_gh);
+ if (ob) {
+ vec[0] = fsize * (ct->xof - xof);
+ vec[1] = fsize * (ct->yof - yof);
+ vec[2] = 0.0;
- mul_m4_v3(pmat, vec);
+ mul_m4_v3(pmat, vec);
- copy_m4_m4(obmat, par->obmat);
+ copy_m4_m4(obmat, par->obmat);
- if (UNLIKELY(ct->rot != 0.0f)) {
- float rmat[4][4];
+ if (UNLIKELY(ct->rot != 0.0f)) {
+ float rmat[4][4];
- zero_v3(obmat[3]);
- axis_angle_to_mat4_single(rmat, 'Z', -ct->rot);
- mul_m4_m4m4(obmat, obmat, rmat);
- }
+ zero_v3(obmat[3]);
+ axis_angle_to_mat4_single(rmat, 'Z', -ct->rot);
+ mul_m4_m4m4(obmat, obmat, rmat);
+ }
- copy_v3_v3(obmat[3], vec);
+ copy_v3_v3(obmat[3], vec);
- make_dupli(ctx, ob, obmat, a);
- }
- }
+ make_dupli(ctx, ob, obmat, a);
+ }
+ }
- if (text_free) {
- MEM_freeN((void *)text);
- }
+ if (text_free) {
+ MEM_freeN((void *)text);
+ }
- BLI_ghash_free(family_gh, NULL, NULL);
+ BLI_ghash_free(family_gh, NULL, NULL);
- MEM_freeN(chartransdata);
+ MEM_freeN(chartransdata);
}
static const DupliGenerator gen_dupli_verts_font = {
- OB_DUPLIVERTS, /* type */
- make_duplis_font /* make_duplis */
+ OB_DUPLIVERTS, /* type */
+ make_duplis_font /* make_duplis */
};
/* OB_DUPLIFACES */
typedef struct FaceDupliData {
- Mesh *me_eval;
- int totface;
- MPoly *mpoly;
- MLoop *mloop;
- MVert *mvert;
- float (*orco)[3];
- MLoopUV *mloopuv;
- bool use_scale;
+ Mesh *me_eval;
+ int totface;
+ MPoly *mpoly;
+ MLoop *mloop;
+ MVert *mvert;
+ float (*orco)[3];
+ MLoopUV *mloopuv;
+ bool use_scale;
} FaceDupliData;
-static void get_dupliface_transform(MPoly *mpoly, MLoop *mloop, MVert *mvert,
- bool use_scale, float scale_fac, float mat[4][4])
+static void get_dupliface_transform(
+ MPoly *mpoly, MLoop *mloop, MVert *mvert, bool use_scale, float scale_fac, float mat[4][4])
{
- float loc[3], quat[4], scale, size[3];
- float f_no[3];
-
- /* location */
- BKE_mesh_calc_poly_center(mpoly, mloop, mvert, loc);
- /* rotation */
- {
- const float *v1, *v2, *v3;
- BKE_mesh_calc_poly_normal(mpoly, mloop, mvert, f_no);
- v1 = mvert[mloop[0].v].co;
- v2 = mvert[mloop[1].v].co;
- v3 = mvert[mloop[2].v].co;
- tri_to_quat_ex(quat, v1, v2, v3, f_no);
- }
- /* scale */
- if (use_scale) {
- float area = BKE_mesh_calc_poly_area(mpoly, mloop, mvert);
- scale = sqrtf(area) * scale_fac;
- }
- else
- scale = 1.0f;
- size[0] = size[1] = size[2] = scale;
-
- loc_quat_size_to_mat4(mat, loc, quat, size);
+ float loc[3], quat[4], scale, size[3];
+ float f_no[3];
+
+ /* location */
+ BKE_mesh_calc_poly_center(mpoly, mloop, mvert, loc);
+ /* rotation */
+ {
+ const float *v1, *v2, *v3;
+ BKE_mesh_calc_poly_normal(mpoly, mloop, mvert, f_no);
+ v1 = mvert[mloop[0].v].co;
+ v2 = mvert[mloop[1].v].co;
+ v3 = mvert[mloop[2].v].co;
+ tri_to_quat_ex(quat, v1, v2, v3, f_no);
+ }
+ /* scale */
+ if (use_scale) {
+ float area = BKE_mesh_calc_poly_area(mpoly, mloop, mvert);
+ scale = sqrtf(area) * scale_fac;
+ }
+ else
+ scale = 1.0f;
+ size[0] = size[1] = size[2] = scale;
+
+ loc_quat_size_to_mat4(mat, loc, quat, size);
}
static void make_child_duplis_faces(const DupliContext *ctx, void *userdata, Object *inst_ob)
{
- FaceDupliData *fdd = userdata;
- MPoly *mpoly = fdd->mpoly, *mp;
- MLoop *mloop = fdd->mloop;
- MVert *mvert = fdd->mvert;
- float (*orco)[3] = fdd->orco;
- MLoopUV *mloopuv = fdd->mloopuv;
- int a, totface = fdd->totface;
- float child_imat[4][4];
- DupliObject *dob;
-
- invert_m4_m4(inst_ob->imat, inst_ob->obmat);
- /* relative transform from parent to child space */
- mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->obmat);
-
- for (a = 0, mp = mpoly; a < totface; a++, mp++) {
- MLoop *loopstart = mloop + mp->loopstart;
- float space_mat[4][4], obmat[4][4];
-
- if (UNLIKELY(mp->totloop < 3))
- continue;
-
- /* obmat is transform to face */
- get_dupliface_transform(mp, loopstart, mvert, fdd->use_scale, ctx->object->instance_faces_scale, obmat);
- /* make offset relative to inst_ob using relative child transform */
- mul_mat3_m4_v3(child_imat, obmat[3]);
-
- /* XXX ugly hack to ensure same behavior as in master
- * this should not be needed, parentinv is not consistent
- * outside of parenting.
- */
- {
- float imat[3][3];
- copy_m3_m4(imat, inst_ob->parentinv);
- mul_m4_m3m4(obmat, imat, obmat);
- }
-
- /* apply obmat _after_ the local face transform */
- mul_m4_m4m4(obmat, inst_ob->obmat, obmat);
-
- /* space matrix is constructed by removing obmat transform,
- * this yields the worldspace transform for recursive duplis
- */
- mul_m4_m4m4(space_mat, obmat, inst_ob->imat);
-
- dob = make_dupli(ctx, inst_ob, obmat, a);
-
- const float w = 1.0f / (float)mp->totloop;
- if (orco) {
- for (int j = 0; j < mp->totloop; j++) {
- madd_v3_v3fl(dob->orco, orco[loopstart[j].v], w);
- }
- }
- if (mloopuv) {
- for (int j = 0; j < mp->totloop; j++) {
- madd_v2_v2fl(dob->uv, mloopuv[mp->loopstart + j].uv, w);
- }
- }
-
- /* recursion */
- make_recursive_duplis(ctx, inst_ob, space_mat, a);
- }
+ FaceDupliData *fdd = userdata;
+ MPoly *mpoly = fdd->mpoly, *mp;
+ MLoop *mloop = fdd->mloop;
+ MVert *mvert = fdd->mvert;
+ float(*orco)[3] = fdd->orco;
+ MLoopUV *mloopuv = fdd->mloopuv;
+ int a, totface = fdd->totface;
+ float child_imat[4][4];
+ DupliObject *dob;
+
+ invert_m4_m4(inst_ob->imat, inst_ob->obmat);
+ /* relative transform from parent to child space */
+ mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->obmat);
+
+ for (a = 0, mp = mpoly; a < totface; a++, mp++) {
+ MLoop *loopstart = mloop + mp->loopstart;
+ float space_mat[4][4], obmat[4][4];
+
+ if (UNLIKELY(mp->totloop < 3))
+ continue;
+
+ /* obmat is transform to face */
+ get_dupliface_transform(
+ mp, loopstart, mvert, fdd->use_scale, ctx->object->instance_faces_scale, obmat);
+ /* make offset relative to inst_ob using relative child transform */
+ mul_mat3_m4_v3(child_imat, obmat[3]);
+
+ /* XXX ugly hack to ensure same behavior as in master
+ * this should not be needed, parentinv is not consistent
+ * outside of parenting.
+ */
+ {
+ float imat[3][3];
+ copy_m3_m4(imat, inst_ob->parentinv);
+ mul_m4_m3m4(obmat, imat, obmat);
+ }
+
+ /* apply obmat _after_ the local face transform */
+ mul_m4_m4m4(obmat, inst_ob->obmat, obmat);
+
+ /* space matrix is constructed by removing obmat transform,
+ * this yields the worldspace transform for recursive duplis
+ */
+ mul_m4_m4m4(space_mat, obmat, inst_ob->imat);
+
+ dob = make_dupli(ctx, inst_ob, obmat, a);
+
+ const float w = 1.0f / (float)mp->totloop;
+ if (orco) {
+ for (int j = 0; j < mp->totloop; j++) {
+ madd_v3_v3fl(dob->orco, orco[loopstart[j].v], w);
+ }
+ }
+ if (mloopuv) {
+ for (int j = 0; j < mp->totloop; j++) {
+ madd_v2_v2fl(dob->uv, mloopuv[mp->loopstart + j].uv, w);
+ }
+ }
+
+ /* recursion */
+ make_recursive_duplis(ctx, inst_ob, space_mat, a);
+ }
}
static void make_duplis_faces(const DupliContext *ctx)
{
- Object *parent = ctx->object;
- FaceDupliData fdd;
-
- fdd.use_scale = ((parent->transflag & OB_DUPLIFACES_SCALE) != 0);
-
- /* gather mesh info */
- {
- BMEditMesh *em = BKE_editmesh_from_object(parent);
-
- /* We do not need any render-smecific handling anymore, depsgraph takes care of that. */
- /* NOTE: Do direct access to the evaluated mesh: this function is used
- * during meta balls evaluation. But even without those all the objects
- * which are needed for correct instancing are already evaluated. */
- if (em != NULL) {
- fdd.me_eval = em->mesh_eval_cage;
- }
- else {
- fdd.me_eval = parent->runtime.mesh_eval;
- }
-
- if (fdd.me_eval == NULL) {
- return;
- }
-
- fdd.orco = CustomData_get_layer(&fdd.me_eval->vdata, CD_ORCO);
- const int uv_idx = CustomData_get_render_layer(&fdd.me_eval->ldata, CD_MLOOPUV);
- fdd.mloopuv = CustomData_get_layer_n(&fdd.me_eval->ldata, CD_MLOOPUV, uv_idx);
-
- fdd.totface = fdd.me_eval->totpoly;
- fdd.mpoly = fdd.me_eval->mpoly;
- fdd.mloop = fdd.me_eval->mloop;
- fdd.mvert = fdd.me_eval->mvert;
- }
-
- make_child_duplis(ctx, &fdd, make_child_duplis_faces);
-
- fdd.me_eval = NULL;
+ Object *parent = ctx->object;
+ FaceDupliData fdd;
+
+ fdd.use_scale = ((parent->transflag & OB_DUPLIFACES_SCALE) != 0);
+
+ /* gather mesh info */
+ {
+ BMEditMesh *em = BKE_editmesh_from_object(parent);
+
+ /* We do not need any render-smecific handling anymore, depsgraph takes care of that. */
+ /* NOTE: Do direct access to the evaluated mesh: this function is used
+ * during meta balls evaluation. But even without those all the objects
+ * which are needed for correct instancing are already evaluated. */
+ if (em != NULL) {
+ fdd.me_eval = em->mesh_eval_cage;
+ }
+ else {
+ fdd.me_eval = parent->runtime.mesh_eval;
+ }
+
+ if (fdd.me_eval == NULL) {
+ return;
+ }
+
+ fdd.orco = CustomData_get_layer(&fdd.me_eval->vdata, CD_ORCO);
+ const int uv_idx = CustomData_get_render_layer(&fdd.me_eval->ldata, CD_MLOOPUV);
+ fdd.mloopuv = CustomData_get_layer_n(&fdd.me_eval->ldata, CD_MLOOPUV, uv_idx);
+
+ fdd.totface = fdd.me_eval->totpoly;
+ fdd.mpoly = fdd.me_eval->mpoly;
+ fdd.mloop = fdd.me_eval->mloop;
+ fdd.mvert = fdd.me_eval->mvert;
+ }
+
+ make_child_duplis(ctx, &fdd, make_child_duplis_faces);
+
+ fdd.me_eval = NULL;
}
static const DupliGenerator gen_dupli_faces = {
- OB_DUPLIFACES, /* type */
- make_duplis_faces /* make_duplis */
+ OB_DUPLIFACES, /* type */
+ make_duplis_faces /* make_duplis */
};
/* OB_DUPLIPARTS */
static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem *psys)
{
- Scene *scene = ctx->scene;
- Object *par = ctx->object;
- eEvaluationMode mode = DEG_get_mode(ctx->depsgraph);
- bool for_render = mode == DAG_EVAL_RENDER;
-
- Object *ob = NULL, **oblist = NULL;
- DupliObject *dob;
- ParticleDupliWeight *dw;
- ParticleSettings *part;
- ParticleData *pa;
- ChildParticle *cpa = NULL;
- ParticleKey state;
- ParticleCacheKey *cache;
- float ctime, scale = 1.0f;
- float tmat[4][4], mat[4][4], pamat[4][4], size = 0.0;
- int a, b, hair = 0;
- int totpart, totchild;
-
- int no_draw_flag = PARS_UNEXIST;
-
- if (psys == NULL) return;
-
- part = psys->part;
-
- if (part == NULL)
- return;
-
- if (!psys_check_enabled(par, psys, for_render))
- return;
-
- if (!for_render)
- no_draw_flag |= PARS_NO_DISP;
-
- ctime = DEG_get_ctime(ctx->depsgraph); /* NOTE: in old animsys, used parent object's timeoffset... */
-
- totpart = psys->totpart;
- totchild = psys->totchild;
-
- if ((for_render || part->draw_as == PART_DRAW_REND) && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) {
- ParticleSimulationData sim = {NULL};
- sim.depsgraph = ctx->depsgraph;
- sim.scene = scene;
- sim.ob = par;
- sim.psys = psys;
- sim.psmd = psys_get_modifier(par, psys);
- /* make sure emitter imat is in global coordinates instead of render view coordinates */
- invert_m4_m4(par->imat, par->obmat);
-
- /* first check for loops (particle system object used as dupli object) */
- if (part->ren_as == PART_DRAW_OB) {
- if (ELEM(part->instance_object, NULL, par))
- return;
- }
- else { /*PART_DRAW_GR */
- if (part->instance_collection == NULL)
- return;
-
- const ListBase dup_collection_objects = BKE_collection_object_cache_get(part->instance_collection);
- if (BLI_listbase_is_empty(&dup_collection_objects))
- return;
-
- if (BLI_findptr(&dup_collection_objects, par, offsetof(Base, object))) {
- return;
- }
- }
-
- /* if we have a hair particle system, use the path cache */
- if (part->type == PART_HAIR) {
- if (psys->flag & PSYS_HAIR_DONE)
- hair = (totchild == 0 || psys->childcache) && psys->pathcache;
- if (!hair)
- return;
-
- /* we use cache, update totchild according to cached data */
- totchild = psys->totchildcache;
- totpart = psys->totcached;
- }
-
- RNG *rng = BLI_rng_new_srandom(31415926u + (unsigned int)psys->seed);
-
- psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
-
- /* gather list of objects or single object */
- int totcollection = 0;
-
- if (part->ren_as == PART_DRAW_GR) {
- if (part->draw & PART_DRAW_COUNT_GR) {
- psys_find_group_weights(part);
-
- for (dw = part->instance_weights.first; dw; dw = dw->next) {
- FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(part->instance_collection, object, mode)
- {
- if (dw->ob == object) {
- totcollection += dw->count;
- break;
- }
- }
- FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
- }
- }
- else {
- FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(part->instance_collection, object, mode)
- {
- (void) object;
- totcollection++;
- }
- FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
- }
-
- oblist = MEM_callocN((size_t)totcollection * sizeof(Object *), "dupcollection object list");
-
- if (part->draw & PART_DRAW_COUNT_GR) {
- a = 0;
- for (dw = part->instance_weights.first; dw; dw = dw->next) {
- FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(part->instance_collection, object, mode)
- {
- if (dw->ob == object) {
- for (b = 0; b < dw->count; b++, a++) {
- oblist[a] = dw->ob;
- }
- break;
- }
- }
- FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
- }
- }
- else {
- a = 0;
- FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(part->instance_collection, object, mode)
- {
- oblist[a] = object;
- a++;
- }
- FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
- }
- }
- else {
- ob = part->instance_object;
- }
-
- if (totchild == 0 || part->draw & PART_DRAW_PARENT)
- a = 0;
- else
- a = totpart;
-
- for (pa = psys->particles; a < totpart + totchild; a++, pa++) {
- if (a < totpart) {
- /* handle parent particle */
- if (pa->flag & no_draw_flag)
- continue;
-
- /* pa_num = pa->num; */ /* UNUSED */
- size = pa->size;
- }
- else {
- /* handle child particle */
- cpa = &psys->child[a - totpart];
-
- /* pa_num = a; */ /* UNUSED */
- size = psys_get_child_size(psys, cpa, ctime, NULL);
- }
-
- /* some hair paths might be non-existent so they can't be used for duplication */
- if (hair && psys->pathcache &&
- ((a < totpart && psys->pathcache[a]->segments < 0) ||
- (a >= totpart && psys->childcache[a - totpart]->segments < 0)))
- {
- continue;
- }
-
- if (part->ren_as == PART_DRAW_GR) {
- /* prevent divide by zero below [#28336] */
- if (totcollection == 0)
- continue;
-
- /* for collections, pick the object based on settings */
- if (part->draw & PART_DRAW_RAND_GR)
- b = BLI_rng_get_int(rng) % totcollection;
- else
- b = a % totcollection;
-
- ob = oblist[b];
- }
-
- if (hair) {
- /* hair we handle separate and compute transform based on hair keys */
- if (a < totpart) {
- cache = psys->pathcache[a];
- psys_get_dupli_path_transform(&sim, pa, NULL, cache, pamat, &scale);
- }
- else {
- cache = psys->childcache[a - totpart];
- psys_get_dupli_path_transform(&sim, NULL, cpa, cache, pamat, &scale);
- }
-
- copy_v3_v3(pamat[3], cache->co);
- pamat[3][3] = 1.0f;
-
- }
- else {
- /* first key */
- state.time = ctime;
- if (psys_get_particle_state(&sim, a, &state, 0) == 0) {
- continue;
- }
- else {
- float tquat[4];
- normalize_qt_qt(tquat, state.rot);
- quat_to_mat4(pamat, tquat);
- copy_v3_v3(pamat[3], state.co);
- pamat[3][3] = 1.0f;
- }
- }
-
- if (part->ren_as == PART_DRAW_GR && psys->part->draw & PART_DRAW_WHOLE_GR) {
- b = 0;
- FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(part->instance_collection, object, mode)
- {
- copy_m4_m4(tmat, oblist[b]->obmat);
-
- /* apply particle scale */
- mul_mat3_m4_fl(tmat, size * scale);
- mul_v3_fl(tmat[3], size * scale);
-
- /* collection dupli offset, should apply after everything else */
- if (!is_zero_v3(part->instance_collection->instance_offset)) {
- sub_v3_v3(tmat[3], part->instance_collection->instance_offset);
- }
-
- /* individual particle transform */
- mul_m4_m4m4(mat, pamat, tmat);
-
- dob = make_dupli(ctx, object, mat, a);
- dob->particle_system = psys;
-
- psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco);
-
- b++;
- }
- FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
- }
- else {
- float obmat[4][4];
- copy_m4_m4(obmat, ob->obmat);
-
- float vec[3];
- copy_v3_v3(vec, obmat[3]);
- zero_v3(obmat[3]);
-
- /* particle rotation uses x-axis as the aligned axis, so pre-rotate the object accordingly */
- if ((part->draw & PART_DRAW_ROTATE_OB) == 0) {
- float xvec[3], q[4], size_mat[4][4], original_size[3];
-
- mat4_to_size(original_size, obmat);
- size_to_mat4(size_mat, original_size);
-
- xvec[0] = -1.f;
- xvec[1] = xvec[2] = 0;
- vec_to_quat(q, xvec, ob->trackflag, ob->upflag);
- quat_to_mat4(obmat, q);
- obmat[3][3] = 1.0f;
-
- /* add scaling if requested */
- if ((part->draw & PART_DRAW_NO_SCALE_OB) == 0)
- mul_m4_m4m4(obmat, obmat, size_mat);
- }
- else if (part->draw & PART_DRAW_NO_SCALE_OB) {
- /* remove scaling */
- float size_mat[4][4], original_size[3];
-
- mat4_to_size(original_size, obmat);
- size_to_mat4(size_mat, original_size);
- invert_m4(size_mat);
-
- mul_m4_m4m4(obmat, obmat, size_mat);
- }
-
- mul_m4_m4m4(tmat, pamat, obmat);
- mul_mat3_m4_fl(tmat, size * scale);
-
- copy_m4_m4(mat, tmat);
-
- if (part->draw & PART_DRAW_GLOBAL_OB)
- add_v3_v3v3(mat[3], mat[3], vec);
-
- dob = make_dupli(ctx, ob, mat, a);
- dob->particle_system = psys;
- psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco);
- }
- }
-
- BLI_rng_free(rng);
- }
-
- /* clean up */
- if (oblist)
- MEM_freeN(oblist);
-
- if (psys->lattice_deform_data) {
- end_latt_deform(psys->lattice_deform_data);
- psys->lattice_deform_data = NULL;
- }
+ Scene *scene = ctx->scene;
+ Object *par = ctx->object;
+ eEvaluationMode mode = DEG_get_mode(ctx->depsgraph);
+ bool for_render = mode == DAG_EVAL_RENDER;
+
+ Object *ob = NULL, **oblist = NULL;
+ DupliObject *dob;
+ ParticleDupliWeight *dw;
+ ParticleSettings *part;
+ ParticleData *pa;
+ ChildParticle *cpa = NULL;
+ ParticleKey state;
+ ParticleCacheKey *cache;
+ float ctime, scale = 1.0f;
+ float tmat[4][4], mat[4][4], pamat[4][4], size = 0.0;
+ int a, b, hair = 0;
+ int totpart, totchild;
+
+ int no_draw_flag = PARS_UNEXIST;
+
+ if (psys == NULL)
+ return;
+
+ part = psys->part;
+
+ if (part == NULL)
+ return;
+
+ if (!psys_check_enabled(par, psys, for_render))
+ return;
+
+ if (!for_render)
+ no_draw_flag |= PARS_NO_DISP;
+
+ ctime = DEG_get_ctime(
+ ctx->depsgraph); /* NOTE: in old animsys, used parent object's timeoffset... */
+
+ totpart = psys->totpart;
+ totchild = psys->totchild;
+
+ if ((for_render || part->draw_as == PART_DRAW_REND) &&
+ ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) {
+ ParticleSimulationData sim = {NULL};
+ sim.depsgraph = ctx->depsgraph;
+ sim.scene = scene;
+ sim.ob = par;
+ sim.psys = psys;
+ sim.psmd = psys_get_modifier(par, psys);
+ /* make sure emitter imat is in global coordinates instead of render view coordinates */
+ invert_m4_m4(par->imat, par->obmat);
+
+ /* first check for loops (particle system object used as dupli object) */
+ if (part->ren_as == PART_DRAW_OB) {
+ if (ELEM(part->instance_object, NULL, par))
+ return;
+ }
+ else { /*PART_DRAW_GR */
+ if (part->instance_collection == NULL)
+ return;
+
+ const ListBase dup_collection_objects = BKE_collection_object_cache_get(
+ part->instance_collection);
+ if (BLI_listbase_is_empty(&dup_collection_objects))
+ return;
+
+ if (BLI_findptr(&dup_collection_objects, par, offsetof(Base, object))) {
+ return;
+ }
+ }
+
+ /* if we have a hair particle system, use the path cache */
+ if (part->type == PART_HAIR) {
+ if (psys->flag & PSYS_HAIR_DONE)
+ hair = (totchild == 0 || psys->childcache) && psys->pathcache;
+ if (!hair)
+ return;
+
+ /* we use cache, update totchild according to cached data */
+ totchild = psys->totchildcache;
+ totpart = psys->totcached;
+ }
+
+ RNG *rng = BLI_rng_new_srandom(31415926u + (unsigned int)psys->seed);
+
+ psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
+
+ /* gather list of objects or single object */
+ int totcollection = 0;
+
+ if (part->ren_as == PART_DRAW_GR) {
+ if (part->draw & PART_DRAW_COUNT_GR) {
+ psys_find_group_weights(part);
+
+ for (dw = part->instance_weights.first; dw; dw = dw->next) {
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (
+ part->instance_collection, object, mode) {
+ if (dw->ob == object) {
+ totcollection += dw->count;
+ break;
+ }
+ }
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
+ }
+ }
+ else {
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (
+ part->instance_collection, object, mode) {
+ (void)object;
+ totcollection++;
+ }
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
+ }
+
+ oblist = MEM_callocN((size_t)totcollection * sizeof(Object *), "dupcollection object list");
+
+ if (part->draw & PART_DRAW_COUNT_GR) {
+ a = 0;
+ for (dw = part->instance_weights.first; dw; dw = dw->next) {
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (
+ part->instance_collection, object, mode) {
+ if (dw->ob == object) {
+ for (b = 0; b < dw->count; b++, a++) {
+ oblist[a] = dw->ob;
+ }
+ break;
+ }
+ }
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
+ }
+ }
+ else {
+ a = 0;
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (
+ part->instance_collection, object, mode) {
+ oblist[a] = object;
+ a++;
+ }
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
+ }
+ }
+ else {
+ ob = part->instance_object;
+ }
+
+ if (totchild == 0 || part->draw & PART_DRAW_PARENT)
+ a = 0;
+ else
+ a = totpart;
+
+ for (pa = psys->particles; a < totpart + totchild; a++, pa++) {
+ if (a < totpart) {
+ /* handle parent particle */
+ if (pa->flag & no_draw_flag)
+ continue;
+
+ /* pa_num = pa->num; */ /* UNUSED */
+ size = pa->size;
+ }
+ else {
+ /* handle child particle */
+ cpa = &psys->child[a - totpart];
+
+ /* pa_num = a; */ /* UNUSED */
+ size = psys_get_child_size(psys, cpa, ctime, NULL);
+ }
+
+ /* some hair paths might be non-existent so they can't be used for duplication */
+ if (hair && psys->pathcache &&
+ ((a < totpart && psys->pathcache[a]->segments < 0) ||
+ (a >= totpart && psys->childcache[a - totpart]->segments < 0))) {
+ continue;
+ }
+
+ if (part->ren_as == PART_DRAW_GR) {
+ /* prevent divide by zero below [#28336] */
+ if (totcollection == 0)
+ continue;
+
+ /* for collections, pick the object based on settings */
+ if (part->draw & PART_DRAW_RAND_GR)
+ b = BLI_rng_get_int(rng) % totcollection;
+ else
+ b = a % totcollection;
+
+ ob = oblist[b];
+ }
+
+ if (hair) {
+ /* hair we handle separate and compute transform based on hair keys */
+ if (a < totpart) {
+ cache = psys->pathcache[a];
+ psys_get_dupli_path_transform(&sim, pa, NULL, cache, pamat, &scale);
+ }
+ else {
+ cache = psys->childcache[a - totpart];
+ psys_get_dupli_path_transform(&sim, NULL, cpa, cache, pamat, &scale);
+ }
+
+ copy_v3_v3(pamat[3], cache->co);
+ pamat[3][3] = 1.0f;
+ }
+ else {
+ /* first key */
+ state.time = ctime;
+ if (psys_get_particle_state(&sim, a, &state, 0) == 0) {
+ continue;
+ }
+ else {
+ float tquat[4];
+ normalize_qt_qt(tquat, state.rot);
+ quat_to_mat4(pamat, tquat);
+ copy_v3_v3(pamat[3], state.co);
+ pamat[3][3] = 1.0f;
+ }
+ }
+
+ if (part->ren_as == PART_DRAW_GR && psys->part->draw & PART_DRAW_WHOLE_GR) {
+ b = 0;
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (
+ part->instance_collection, object, mode) {
+ copy_m4_m4(tmat, oblist[b]->obmat);
+
+ /* apply particle scale */
+ mul_mat3_m4_fl(tmat, size * scale);
+ mul_v3_fl(tmat[3], size * scale);
+
+ /* collection dupli offset, should apply after everything else */
+ if (!is_zero_v3(part->instance_collection->instance_offset)) {
+ sub_v3_v3(tmat[3], part->instance_collection->instance_offset);
+ }
+
+ /* individual particle transform */
+ mul_m4_m4m4(mat, pamat, tmat);
+
+ dob = make_dupli(ctx, object, mat, a);
+ dob->particle_system = psys;
+
+ psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco);
+
+ b++;
+ }
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
+ }
+ else {
+ float obmat[4][4];
+ copy_m4_m4(obmat, ob->obmat);
+
+ float vec[3];
+ copy_v3_v3(vec, obmat[3]);
+ zero_v3(obmat[3]);
+
+ /* particle rotation uses x-axis as the aligned axis, so pre-rotate the object accordingly */
+ if ((part->draw & PART_DRAW_ROTATE_OB) == 0) {
+ float xvec[3], q[4], size_mat[4][4], original_size[3];
+
+ mat4_to_size(original_size, obmat);
+ size_to_mat4(size_mat, original_size);
+
+ xvec[0] = -1.f;
+ xvec[1] = xvec[2] = 0;
+ vec_to_quat(q, xvec, ob->trackflag, ob->upflag);
+ quat_to_mat4(obmat, q);
+ obmat[3][3] = 1.0f;
+
+ /* add scaling if requested */
+ if ((part->draw & PART_DRAW_NO_SCALE_OB) == 0)
+ mul_m4_m4m4(obmat, obmat, size_mat);
+ }
+ else if (part->draw & PART_DRAW_NO_SCALE_OB) {
+ /* remove scaling */
+ float size_mat[4][4], original_size[3];
+
+ mat4_to_size(original_size, obmat);
+ size_to_mat4(size_mat, original_size);
+ invert_m4(size_mat);
+
+ mul_m4_m4m4(obmat, obmat, size_mat);
+ }
+
+ mul_m4_m4m4(tmat, pamat, obmat);
+ mul_mat3_m4_fl(tmat, size * scale);
+
+ copy_m4_m4(mat, tmat);
+
+ if (part->draw & PART_DRAW_GLOBAL_OB)
+ add_v3_v3v3(mat[3], mat[3], vec);
+
+ dob = make_dupli(ctx, ob, mat, a);
+ dob->particle_system = psys;
+ psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco);
+ }
+ }
+
+ BLI_rng_free(rng);
+ }
+
+ /* clean up */
+ if (oblist)
+ MEM_freeN(oblist);
+
+ if (psys->lattice_deform_data) {
+ end_latt_deform(psys->lattice_deform_data);
+ psys->lattice_deform_data = NULL;
+ }
}
static void make_duplis_particles(const DupliContext *ctx)
{
- ParticleSystem *psys;
- int psysid;
-
- /* particle system take up one level in id, the particles another */
- for (psys = ctx->object->particlesystem.first, psysid = 0; psys; psys = psys->next, psysid++) {
- /* particles create one more level for persistent psys index */
- DupliContext pctx;
- copy_dupli_context(&pctx, ctx, ctx->object, NULL, psysid);
- make_duplis_particle_system(&pctx, psys);
- }
+ ParticleSystem *psys;
+ int psysid;
+
+ /* particle system take up one level in id, the particles another */
+ for (psys = ctx->object->particlesystem.first, psysid = 0; psys; psys = psys->next, psysid++) {
+ /* particles create one more level for persistent psys index */
+ DupliContext pctx;
+ copy_dupli_context(&pctx, ctx, ctx->object, NULL, psysid);
+ make_duplis_particle_system(&pctx, psys);
+ }
}
static const DupliGenerator gen_dupli_particles = {
- OB_DUPLIPARTS, /* type */
- make_duplis_particles /* make_duplis */
+ OB_DUPLIPARTS, /* type */
+ make_duplis_particles /* make_duplis */
};
/* ------------- */
@@ -1022,57 +1036,57 @@ static const DupliGenerator gen_dupli_particles = {
/* select dupli generator from given context */
static const DupliGenerator *get_dupli_generator(const DupliContext *ctx)
{
- int transflag = ctx->object->transflag;
- int restrictflag = ctx->object->restrictflag;
-
- if ((transflag & OB_DUPLI) == 0)
- return NULL;
-
- /* Should the dupli's be generated for this object? - Respect restrict flags */
- if (DEG_get_mode(ctx->depsgraph) == DAG_EVAL_RENDER ? (restrictflag & OB_RESTRICT_RENDER) : (restrictflag & OB_RESTRICT_VIEW))
- return NULL;
-
- if (transflag & OB_DUPLIPARTS) {
- return &gen_dupli_particles;
- }
- else if (transflag & OB_DUPLIVERTS) {
- if (ctx->object->type == OB_MESH) {
- return &gen_dupli_verts;
- }
- else if (ctx->object->type == OB_FONT) {
- return &gen_dupli_verts_font;
- }
- }
- else if (transflag & OB_DUPLIFACES) {
- if (ctx->object->type == OB_MESH)
- return &gen_dupli_faces;
- }
- else if (transflag & OB_DUPLICOLLECTION) {
- return &gen_dupli_collection;
- }
-
- return NULL;
+ int transflag = ctx->object->transflag;
+ int restrictflag = ctx->object->restrictflag;
+
+ if ((transflag & OB_DUPLI) == 0)
+ return NULL;
+
+ /* Should the dupli's be generated for this object? - Respect restrict flags */
+ if (DEG_get_mode(ctx->depsgraph) == DAG_EVAL_RENDER ? (restrictflag & OB_RESTRICT_RENDER) :
+ (restrictflag & OB_RESTRICT_VIEW))
+ return NULL;
+
+ if (transflag & OB_DUPLIPARTS) {
+ return &gen_dupli_particles;
+ }
+ else if (transflag & OB_DUPLIVERTS) {
+ if (ctx->object->type == OB_MESH) {
+ return &gen_dupli_verts;
+ }
+ else if (ctx->object->type == OB_FONT) {
+ return &gen_dupli_verts_font;
+ }
+ }
+ else if (transflag & OB_DUPLIFACES) {
+ if (ctx->object->type == OB_MESH)
+ return &gen_dupli_faces;
+ }
+ else if (transflag & OB_DUPLICOLLECTION) {
+ return &gen_dupli_collection;
+ }
+
+ return NULL;
}
-
/* ---- ListBase dupli container implementation ---- */
/* Returns a list of DupliObject */
ListBase *object_duplilist(Depsgraph *depsgraph, Scene *sce, Object *ob)
{
- ListBase *duplilist = MEM_callocN(sizeof(ListBase), "duplilist");
- DupliContext ctx;
- init_context(&ctx, depsgraph, sce, ob, NULL);
- if (ctx.gen) {
- ctx.duplilist = duplilist;
- ctx.gen->make_duplis(&ctx);
- }
-
- return duplilist;
+ ListBase *duplilist = MEM_callocN(sizeof(ListBase), "duplilist");
+ DupliContext ctx;
+ init_context(&ctx, depsgraph, sce, ob, NULL);
+ if (ctx.gen) {
+ ctx.duplilist = duplilist;
+ ctx.gen->make_duplis(&ctx);
+ }
+
+ return duplilist;
}
void free_object_duplilist(ListBase *lb)
{
- BLI_freelistN(lb);
- MEM_freeN(lb);
+ BLI_freelistN(lb);
+ MEM_freeN(lb);
}
diff --git a/source/blender/blenkernel/intern/object_facemap.c b/source/blender/blenkernel/intern/object_facemap.c
index 19f0b77342a..4548a6d6bd1 100644
--- a/source/blender/blenkernel/intern/object_facemap.c
+++ b/source/blender/blenkernel/intern/object_facemap.c
@@ -34,7 +34,7 @@
#include "BKE_customdata.h"
#include "BKE_editmesh.h"
#include "BKE_object.h"
-#include "BKE_object_facemap.h" /* own include */
+#include "BKE_object_facemap.h" /* own include */
#include "BKE_object_deform.h"
#include "BLT_translation.h"
@@ -46,202 +46,208 @@
static bool fmap_unique_check(void *arg, const char *name)
{
- struct {Object *ob; void *fm; } *data = arg;
-
- bFaceMap *fmap;
-
- for (fmap = data->ob->fmaps.first; fmap; fmap = fmap->next) {
- if (data->fm != fmap) {
- if (!strcmp(fmap->name, name)) {
- return true;
- }
- }
- }
-
- return false;
+ struct {
+ Object *ob;
+ void *fm;
+ } *data = arg;
+
+ bFaceMap *fmap;
+
+ for (fmap = data->ob->fmaps.first; fmap; fmap = fmap->next) {
+ if (data->fm != fmap) {
+ if (!strcmp(fmap->name, name)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
}
static bFaceMap *fmap_duplicate(bFaceMap *infmap)
{
- bFaceMap *outfmap;
+ bFaceMap *outfmap;
- if (!infmap)
- return NULL;
+ if (!infmap)
+ return NULL;
- outfmap = MEM_callocN(sizeof(bFaceMap), "copy facemap");
+ outfmap = MEM_callocN(sizeof(bFaceMap), "copy facemap");
- /* For now, just copy everything over. */
- memcpy(outfmap, infmap, sizeof(bFaceMap));
+ /* For now, just copy everything over. */
+ memcpy(outfmap, infmap, sizeof(bFaceMap));
- outfmap->next = outfmap->prev = NULL;
+ outfmap->next = outfmap->prev = NULL;
- return outfmap;
+ return outfmap;
}
void BKE_object_facemap_copy_list(ListBase *outbase, const ListBase *inbase)
{
- bFaceMap *fmap, *fmapn;
+ bFaceMap *fmap, *fmapn;
- BLI_listbase_clear(outbase);
+ BLI_listbase_clear(outbase);
- for (fmap = inbase->first; fmap; fmap = fmap->next) {
- fmapn = fmap_duplicate(fmap);
- BLI_addtail(outbase, fmapn);
- }
+ for (fmap = inbase->first; fmap; fmap = fmap->next) {
+ fmapn = fmap_duplicate(fmap);
+ BLI_addtail(outbase, fmapn);
+ }
}
void BKE_object_facemap_unique_name(Object *ob, bFaceMap *fmap)
{
- struct {Object *ob; void *fmap; } data;
- data.ob = ob;
- data.fmap = fmap;
-
- BLI_uniquename_cb(fmap_unique_check, &data, DATA_("Group"), '.', fmap->name, sizeof(fmap->name));
+ struct {
+ Object *ob;
+ void *fmap;
+ } data;
+ data.ob = ob;
+ data.fmap = fmap;
+
+ BLI_uniquename_cb(fmap_unique_check, &data, DATA_("Group"), '.', fmap->name, sizeof(fmap->name));
}
bFaceMap *BKE_object_facemap_add_name(Object *ob, const char *name)
{
- bFaceMap *fmap;
+ bFaceMap *fmap;
- if (!ob || ob->type != OB_MESH)
- return NULL;
+ if (!ob || ob->type != OB_MESH)
+ return NULL;
- fmap = MEM_callocN(sizeof(bFaceMap), __func__);
+ fmap = MEM_callocN(sizeof(bFaceMap), __func__);
- BLI_strncpy(fmap->name, name, sizeof(fmap->name));
+ BLI_strncpy(fmap->name, name, sizeof(fmap->name));
- BLI_addtail(&ob->fmaps, fmap);
+ BLI_addtail(&ob->fmaps, fmap);
- ob->actfmap = BLI_listbase_count(&ob->fmaps);
+ ob->actfmap = BLI_listbase_count(&ob->fmaps);
- BKE_object_facemap_unique_name(ob, fmap);
+ BKE_object_facemap_unique_name(ob, fmap);
- return fmap;
+ return fmap;
}
bFaceMap *BKE_object_facemap_add(Object *ob)
{
- return BKE_object_facemap_add_name(ob, DATA_("FaceMap"));
+ return BKE_object_facemap_add_name(ob, DATA_("FaceMap"));
}
-
static void object_fmap_remove_edit_mode(Object *ob, bFaceMap *fmap, bool do_selected, bool purge)
{
- const int fmap_nr = BLI_findindex(&ob->fmaps, fmap);
-
- if (ob->type == OB_MESH) {
- Mesh *me = ob->data;
-
- if (me->edit_mesh) {
- BMEditMesh *em = me->edit_mesh;
- const int cd_fmap_offset = CustomData_get_offset(&em->bm->pdata, CD_FACEMAP);
-
- if (cd_fmap_offset != -1) {
- BMFace *efa;
- BMIter iter;
- int *map;
-
- if (purge) {
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset);
-
- if (map) {
- if (*map == fmap_nr)
- *map = -1;
- else if (*map > fmap_nr)
- *map -= 1;
- }
- }
- }
- else {
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset);
-
- if (map && *map == fmap_nr && (!do_selected || BM_elem_flag_test(efa, BM_ELEM_SELECT))) {
- *map = -1;
- }
- }
- }
- }
-
- if (ob->actfmap == BLI_listbase_count(&ob->fmaps))
- ob->actfmap--;
-
- BLI_remlink(&ob->fmaps, fmap);
- MEM_freeN(fmap);
- }
- }
+ const int fmap_nr = BLI_findindex(&ob->fmaps, fmap);
+
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+
+ if (me->edit_mesh) {
+ BMEditMesh *em = me->edit_mesh;
+ const int cd_fmap_offset = CustomData_get_offset(&em->bm->pdata, CD_FACEMAP);
+
+ if (cd_fmap_offset != -1) {
+ BMFace *efa;
+ BMIter iter;
+ int *map;
+
+ if (purge) {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset);
+
+ if (map) {
+ if (*map == fmap_nr)
+ *map = -1;
+ else if (*map > fmap_nr)
+ *map -= 1;
+ }
+ }
+ }
+ else {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset);
+
+ if (map && *map == fmap_nr &&
+ (!do_selected || BM_elem_flag_test(efa, BM_ELEM_SELECT))) {
+ *map = -1;
+ }
+ }
+ }
+ }
+
+ if (ob->actfmap == BLI_listbase_count(&ob->fmaps))
+ ob->actfmap--;
+
+ BLI_remlink(&ob->fmaps, fmap);
+ MEM_freeN(fmap);
+ }
+ }
}
static void object_fmap_remove_object_mode(Object *ob, bFaceMap *fmap, bool purge)
{
- const int fmap_nr = BLI_findindex(&ob->fmaps, fmap);
-
- if (ob->type == OB_MESH) {
- Mesh *me = ob->data;
-
- if (CustomData_has_layer(&me->pdata, CD_FACEMAP)) {
- int *map = CustomData_get_layer(&me->pdata, CD_FACEMAP);
- int i;
-
- if (map) {
- for (i = 0; i < me->totpoly; i++) {
- if (map[i] == fmap_nr)
- map[i] = -1;
- else if (purge && map[i] > fmap_nr)
- map[i]--;
- }
- }
- }
-
- if (ob->actfmap == BLI_listbase_count(&ob->fmaps))
- ob->actfmap--;
-
- BLI_remlink(&ob->fmaps, fmap);
- MEM_freeN(fmap);
- }
+ const int fmap_nr = BLI_findindex(&ob->fmaps, fmap);
+
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+
+ if (CustomData_has_layer(&me->pdata, CD_FACEMAP)) {
+ int *map = CustomData_get_layer(&me->pdata, CD_FACEMAP);
+ int i;
+
+ if (map) {
+ for (i = 0; i < me->totpoly; i++) {
+ if (map[i] == fmap_nr)
+ map[i] = -1;
+ else if (purge && map[i] > fmap_nr)
+ map[i]--;
+ }
+ }
+ }
+
+ if (ob->actfmap == BLI_listbase_count(&ob->fmaps))
+ ob->actfmap--;
+
+ BLI_remlink(&ob->fmaps, fmap);
+ MEM_freeN(fmap);
+ }
}
static void fmap_remove_exec(Object *ob, bFaceMap *fmap, const bool is_edit_mode, const bool purge)
{
- if (is_edit_mode)
- object_fmap_remove_edit_mode(ob, fmap, false, purge);
- else
- object_fmap_remove_object_mode(ob, fmap, purge);
+ if (is_edit_mode)
+ object_fmap_remove_edit_mode(ob, fmap, false, purge);
+ else
+ object_fmap_remove_object_mode(ob, fmap, purge);
}
void BKE_object_facemap_remove(Object *ob, bFaceMap *fmap)
{
- fmap_remove_exec(ob, fmap, BKE_object_is_in_editmode(ob), true);
+ fmap_remove_exec(ob, fmap, BKE_object_is_in_editmode(ob), true);
}
void BKE_object_facemap_clear(Object *ob)
{
- bFaceMap *fmap = (bFaceMap *)ob->fmaps.first;
-
- if (fmap) {
- const bool edit_mode = BKE_object_is_in_editmode_vgroup(ob);
-
- while (fmap) {
- bFaceMap *next_fmap = fmap->next;
- fmap_remove_exec(ob, fmap, edit_mode, false);
- fmap = next_fmap;
- }
- }
- /* remove all face-maps */
- if (ob->type == OB_MESH) {
- Mesh *me = ob->data;
- CustomData_free_layer(&me->pdata, CD_FACEMAP, me->totpoly, 0);
- }
- ob->actfmap = 0;
+ bFaceMap *fmap = (bFaceMap *)ob->fmaps.first;
+
+ if (fmap) {
+ const bool edit_mode = BKE_object_is_in_editmode_vgroup(ob);
+
+ while (fmap) {
+ bFaceMap *next_fmap = fmap->next;
+ fmap_remove_exec(ob, fmap, edit_mode, false);
+ fmap = next_fmap;
+ }
+ }
+ /* remove all face-maps */
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+ CustomData_free_layer(&me->pdata, CD_FACEMAP, me->totpoly, 0);
+ }
+ ob->actfmap = 0;
}
int BKE_object_facemap_name_index(Object *ob, const char *name)
{
- return (name) ? BLI_findstringindex(&ob->fmaps, name, offsetof(bFaceMap, name)) : -1;
+ return (name) ? BLI_findstringindex(&ob->fmaps, name, offsetof(bFaceMap, name)) : -1;
}
bFaceMap *BKE_object_facemap_find_name(Object *ob, const char *name)
{
- return BLI_findstring(&ob->fmaps, name, offsetof(bFaceMap, name));
+ return BLI_findstring(&ob->fmaps, name, offsetof(bFaceMap, name));
}
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index bcca39cff24..75c0b0b3dc0 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -71,177 +71,173 @@
*/
void BKE_object_eval_reset(Object *ob_eval)
{
- BKE_object_free_derived_caches(ob_eval);
+ BKE_object_free_derived_caches(ob_eval);
}
void BKE_object_eval_local_transform(Depsgraph *depsgraph, Object *ob)
{
- DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
+ DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
- /* calculate local matrix */
- BKE_object_to_mat4(ob, ob->obmat);
+ /* calculate local matrix */
+ BKE_object_to_mat4(ob, ob->obmat);
}
/* Evaluate parent */
/* NOTE: based on solve_parenting(), but with the cruft stripped out */
void BKE_object_eval_parent(Depsgraph *depsgraph, Object *ob)
{
- Object *par = ob->parent;
+ Object *par = ob->parent;
- float totmat[4][4];
- float tmat[4][4];
- float locmat[4][4];
+ float totmat[4][4];
+ float tmat[4][4];
+ float locmat[4][4];
- DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
+ DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
- /* get local matrix (but don't calculate it, as that was done already!) */
- // XXX: redundant?
- copy_m4_m4(locmat, ob->obmat);
+ /* get local matrix (but don't calculate it, as that was done already!) */
+ // XXX: redundant?
+ copy_m4_m4(locmat, ob->obmat);
- /* get parent effect matrix */
- BKE_object_get_parent_matrix(ob, par, totmat);
+ /* get parent effect matrix */
+ BKE_object_get_parent_matrix(ob, par, totmat);
- /* total */
- mul_m4_m4m4(tmat, totmat, ob->parentinv);
- mul_m4_m4m4(ob->obmat, tmat, locmat);
+ /* total */
+ mul_m4_m4m4(tmat, totmat, ob->parentinv);
+ mul_m4_m4m4(ob->obmat, tmat, locmat);
- /* origin, for help line */
- if ((ob->partype & PARTYPE) == PARSKEL) {
- copy_v3_v3(ob->runtime.parent_display_origin, par->obmat[3]);
- }
- else {
- copy_v3_v3(ob->runtime.parent_display_origin, totmat[3]);
- }
+ /* origin, for help line */
+ if ((ob->partype & PARTYPE) == PARSKEL) {
+ copy_v3_v3(ob->runtime.parent_display_origin, par->obmat[3]);
+ }
+ else {
+ copy_v3_v3(ob->runtime.parent_display_origin, totmat[3]);
+ }
}
-void BKE_object_eval_constraints(Depsgraph *depsgraph,
- Scene *scene,
- Object *ob)
+void BKE_object_eval_constraints(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- bConstraintOb *cob;
- float ctime = BKE_scene_frame_get(scene);
-
- DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
-
- /* evaluate constraints stack */
- /* TODO: split this into:
- * - pre (i.e. BKE_constraints_make_evalob, per-constraint (i.e.
- * - inner body of BKE_constraints_solve),
- * - post (i.e. BKE_constraints_clear_evalob)
- *
- * Not sure why, this is from Joshua - sergey
- *
- */
- cob = BKE_constraints_make_evalob(depsgraph, scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
- BKE_constraints_solve(depsgraph, &ob->constraints, cob, ctime);
- BKE_constraints_clear_evalob(cob);
+ bConstraintOb *cob;
+ float ctime = BKE_scene_frame_get(scene);
+
+ DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
+
+ /* evaluate constraints stack */
+ /* TODO: split this into:
+ * - pre (i.e. BKE_constraints_make_evalob, per-constraint (i.e.
+ * - inner body of BKE_constraints_solve),
+ * - post (i.e. BKE_constraints_clear_evalob)
+ *
+ * Not sure why, this is from Joshua - sergey
+ *
+ */
+ cob = BKE_constraints_make_evalob(depsgraph, scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
+ BKE_constraints_solve(depsgraph, &ob->constraints, cob, ctime);
+ BKE_constraints_clear_evalob(cob);
}
void BKE_object_eval_transform_final(Depsgraph *depsgraph, Object *ob)
{
- DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
- /* Make sure inverse matrix is always up to date. This way users of it
- * do not need to worry about relcalculating it. */
- invert_m4_m4(ob->imat, ob->obmat);
- /* Set negative scale flag in object. */
- if (is_negative_m4(ob->obmat)) ob->transflag |= OB_NEG_SCALE;
- else ob->transflag &= ~OB_NEG_SCALE;
+ DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
+ /* Make sure inverse matrix is always up to date. This way users of it
+ * do not need to worry about relcalculating it. */
+ invert_m4_m4(ob->imat, ob->obmat);
+ /* Set negative scale flag in object. */
+ if (is_negative_m4(ob->obmat))
+ ob->transflag |= OB_NEG_SCALE;
+ else
+ ob->transflag &= ~OB_NEG_SCALE;
}
-void BKE_object_handle_data_update(
- Depsgraph *depsgraph,
- Scene *scene,
- Object *ob)
+void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
+ DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
- /* includes all keys and modifiers */
- switch (ob->type) {
- case OB_MESH:
- {
+ /* includes all keys and modifiers */
+ switch (ob->type) {
+ case OB_MESH: {
#if 0
- BMEditMesh *em = (ob->mode & OB_MODE_EDIT) ? BKE_editmesh_from_object(ob) : NULL;
+ BMEditMesh *em = (ob->mode & OB_MODE_EDIT) ? BKE_editmesh_from_object(ob) : NULL;
#else
- BMEditMesh *em = (ob->mode & OB_MODE_EDIT) ? ((Mesh *)ob->data)->edit_mesh : NULL;
- if (em && em->ob != ob) {
- em = NULL;
- }
+ BMEditMesh *em = (ob->mode & OB_MODE_EDIT) ? ((Mesh *)ob->data)->edit_mesh : NULL;
+ if (em && em->ob != ob) {
+ em = NULL;
+ }
#endif
- CustomData_MeshMasks cddata_masks = scene->customdata_mask;
- CustomData_MeshMasks_update(&cddata_masks, &CD_MASK_BAREMESH);
+ CustomData_MeshMasks cddata_masks = scene->customdata_mask;
+ CustomData_MeshMasks_update(&cddata_masks, &CD_MASK_BAREMESH);
#ifdef WITH_FREESTYLE
- /* make sure Freestyle edge/face marks appear in DM for render (see T40315) */
- if (DEG_get_mode(depsgraph) != DAG_EVAL_VIEWPORT) {
- cddata_masks.emask |= CD_MASK_FREESTYLE_EDGE;
- cddata_masks.pmask |= CD_MASK_FREESTYLE_FACE;
- }
+ /* make sure Freestyle edge/face marks appear in DM for render (see T40315) */
+ if (DEG_get_mode(depsgraph) != DAG_EVAL_VIEWPORT) {
+ cddata_masks.emask |= CD_MASK_FREESTYLE_EDGE;
+ cddata_masks.pmask |= CD_MASK_FREESTYLE_FACE;
+ }
#endif
- if (em) {
- makeDerivedMesh(depsgraph, scene, ob, em, &cddata_masks); /* was CD_MASK_BAREMESH */
- }
- else {
- makeDerivedMesh(depsgraph, scene, ob, NULL, &cddata_masks);
- }
- break;
- }
- case OB_ARMATURE:
- if (ID_IS_LINKED(ob) && ob->proxy_from) {
- if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) {
- printf("Proxy copy error, lib Object: %s proxy Object: %s\n",
- ob->id.name + 2, ob->proxy_from->id.name + 2);
- }
- }
- else {
- BKE_pose_where_is(depsgraph, scene, ob);
- }
- break;
-
- case OB_MBALL:
- BKE_displist_make_mball(depsgraph, scene, ob);
- break;
-
- case OB_CURVE:
- case OB_SURF:
- case OB_FONT:
- BKE_displist_make_curveTypes(depsgraph, scene, ob, false, false, NULL);
- break;
-
- case OB_LATTICE:
- BKE_lattice_modifiers_calc(depsgraph, scene, ob);
- break;
- }
-
- /* particles */
- if (!(ob->mode & OB_MODE_EDIT) && ob->particlesystem.first) {
- const bool use_render_params = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
- ParticleSystem *tpsys, *psys;
- ob->transflag &= ~OB_DUPLIPARTS;
- psys = ob->particlesystem.first;
- while (psys) {
- if (psys_check_enabled(ob, psys, use_render_params)) {
- /* check use of dupli objects here */
- if (psys->part && (psys->part->draw_as == PART_DRAW_REND || use_render_params) &&
- ((psys->part->ren_as == PART_DRAW_OB && psys->part->instance_object) ||
- (psys->part->ren_as == PART_DRAW_GR && psys->part->instance_collection)))
- {
- ob->transflag |= OB_DUPLIPARTS;
- }
-
- particle_system_update(depsgraph, scene, ob, psys, use_render_params);
- psys = psys->next;
- }
- else if (psys->flag & PSYS_DELETE) {
- tpsys = psys->next;
- BLI_remlink(&ob->particlesystem, psys);
- psys_free(ob, psys);
- psys = tpsys;
- }
- else
- psys = psys->next;
- }
- }
- BKE_object_eval_boundbox(depsgraph, ob);
+ if (em) {
+ makeDerivedMesh(depsgraph, scene, ob, em, &cddata_masks); /* was CD_MASK_BAREMESH */
+ }
+ else {
+ makeDerivedMesh(depsgraph, scene, ob, NULL, &cddata_masks);
+ }
+ break;
+ }
+ case OB_ARMATURE:
+ if (ID_IS_LINKED(ob) && ob->proxy_from) {
+ if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) {
+ printf("Proxy copy error, lib Object: %s proxy Object: %s\n",
+ ob->id.name + 2,
+ ob->proxy_from->id.name + 2);
+ }
+ }
+ else {
+ BKE_pose_where_is(depsgraph, scene, ob);
+ }
+ break;
+
+ case OB_MBALL:
+ BKE_displist_make_mball(depsgraph, scene, ob);
+ break;
+
+ case OB_CURVE:
+ case OB_SURF:
+ case OB_FONT:
+ BKE_displist_make_curveTypes(depsgraph, scene, ob, false, false, NULL);
+ break;
+
+ case OB_LATTICE:
+ BKE_lattice_modifiers_calc(depsgraph, scene, ob);
+ break;
+ }
+
+ /* particles */
+ if (!(ob->mode & OB_MODE_EDIT) && ob->particlesystem.first) {
+ const bool use_render_params = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
+ ParticleSystem *tpsys, *psys;
+ ob->transflag &= ~OB_DUPLIPARTS;
+ psys = ob->particlesystem.first;
+ while (psys) {
+ if (psys_check_enabled(ob, psys, use_render_params)) {
+ /* check use of dupli objects here */
+ if (psys->part && (psys->part->draw_as == PART_DRAW_REND || use_render_params) &&
+ ((psys->part->ren_as == PART_DRAW_OB && psys->part->instance_object) ||
+ (psys->part->ren_as == PART_DRAW_GR && psys->part->instance_collection))) {
+ ob->transflag |= OB_DUPLIPARTS;
+ }
+
+ particle_system_update(depsgraph, scene, ob, psys, use_render_params);
+ psys = psys->next;
+ }
+ else if (psys->flag & PSYS_DELETE) {
+ tpsys = psys->next;
+ BLI_remlink(&ob->particlesystem, psys);
+ psys_free(ob, psys);
+ psys = tpsys;
+ }
+ else
+ psys = psys->next;
+ }
+ }
+ BKE_object_eval_boundbox(depsgraph, ob);
}
/**
@@ -250,219 +246,205 @@ void BKE_object_handle_data_update(
*/
void BKE_object_eval_boundbox(Depsgraph *depsgraph, Object *object)
{
- if (!DEG_is_active(depsgraph)) {
- return;
- }
- Object *ob_orig = DEG_get_original_object(object);
- BoundBox *bb = BKE_object_boundbox_get(object);
- if (bb != NULL) {
- if (ob_orig->runtime.bb == NULL) {
- ob_orig->runtime.bb = MEM_mallocN(sizeof(*ob_orig->runtime.bb), __func__);
- }
- *ob_orig->runtime.bb = *bb;
- }
+ if (!DEG_is_active(depsgraph)) {
+ return;
+ }
+ Object *ob_orig = DEG_get_original_object(object);
+ BoundBox *bb = BKE_object_boundbox_get(object);
+ if (bb != NULL) {
+ if (ob_orig->runtime.bb == NULL) {
+ ob_orig->runtime.bb = MEM_mallocN(sizeof(*ob_orig->runtime.bb), __func__);
+ }
+ *ob_orig->runtime.bb = *bb;
+ }
}
void BKE_object_synchronize_to_original(Depsgraph *depsgraph, Object *object)
{
- if (!DEG_is_active(depsgraph)) {
- return;
- }
- Object *object_orig = DEG_get_original_object(object);
- /* Base flags. */
- object_orig->base_flag = object->base_flag;
- /* Transformation flags. */
- copy_m4_m4(object_orig->obmat, object->obmat);
- copy_m4_m4(object_orig->imat, object->imat);
- copy_m4_m4(object_orig->constinv, object->constinv);
- object_orig->transflag = object->transflag;
- object_orig->flag = object->flag;
-
- /* Copy back error messages from modifiers. */
- for (ModifierData *md = object->modifiers.first, *md_orig = object_orig->modifiers.first;
- md != NULL && md_orig != NULL;
- md = md->next, md_orig = md_orig->next)
- {
- BLI_assert(md->type == md_orig->type && STREQ(md->name, md_orig->name));
- MEM_SAFE_FREE(md_orig->error);
- if (md->error != NULL) {
- md_orig->error = BLI_strdup(md->error);
- }
- }
+ if (!DEG_is_active(depsgraph)) {
+ return;
+ }
+ Object *object_orig = DEG_get_original_object(object);
+ /* Base flags. */
+ object_orig->base_flag = object->base_flag;
+ /* Transformation flags. */
+ copy_m4_m4(object_orig->obmat, object->obmat);
+ copy_m4_m4(object_orig->imat, object->imat);
+ copy_m4_m4(object_orig->constinv, object->constinv);
+ object_orig->transflag = object->transflag;
+ object_orig->flag = object->flag;
+
+ /* Copy back error messages from modifiers. */
+ for (ModifierData *md = object->modifiers.first, *md_orig = object_orig->modifiers.first;
+ md != NULL && md_orig != NULL;
+ md = md->next, md_orig = md_orig->next) {
+ BLI_assert(md->type == md_orig->type && STREQ(md->name, md_orig->name));
+ MEM_SAFE_FREE(md_orig->error);
+ if (md->error != NULL) {
+ md_orig->error = BLI_strdup(md->error);
+ }
+ }
}
-bool BKE_object_eval_proxy_copy(Depsgraph *depsgraph,
- Object *object)
+bool BKE_object_eval_proxy_copy(Depsgraph *depsgraph, Object *object)
{
- /* Handle proxy copy for target, */
- if (ID_IS_LINKED(object) && object->proxy_from) {
- DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
- if (object->proxy_from->proxy_group) {
- /* Transform proxy into group space. */
- Object *obg = object->proxy_from->proxy_group;
- float imat[4][4];
- invert_m4_m4(imat, obg->obmat);
- mul_m4_m4m4(object->obmat, imat, object->proxy_from->obmat);
- /* Should always be true. */
- if (obg->instance_collection) {
- add_v3_v3(object->obmat[3], obg->instance_collection->instance_offset);
- }
- }
- else {
- copy_m4_m4(object->obmat, object->proxy_from->obmat);
- }
- return true;
- }
- return false;
+ /* Handle proxy copy for target, */
+ if (ID_IS_LINKED(object) && object->proxy_from) {
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
+ if (object->proxy_from->proxy_group) {
+ /* Transform proxy into group space. */
+ Object *obg = object->proxy_from->proxy_group;
+ float imat[4][4];
+ invert_m4_m4(imat, obg->obmat);
+ mul_m4_m4m4(object->obmat, imat, object->proxy_from->obmat);
+ /* Should always be true. */
+ if (obg->instance_collection) {
+ add_v3_v3(object->obmat[3], obg->instance_collection->instance_offset);
+ }
+ }
+ else {
+ copy_m4_m4(object->obmat, object->proxy_from->obmat);
+ }
+ return true;
+ }
+ return false;
}
void BKE_object_eval_uber_transform(Depsgraph *depsgraph, Object *object)
{
- BKE_object_eval_proxy_copy(depsgraph, object);
+ BKE_object_eval_proxy_copy(depsgraph, object);
}
void BKE_object_batch_cache_dirty_tag(Object *ob)
{
- switch (ob->type) {
- case OB_MESH:
- BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
- break;
- case OB_LATTICE:
- BKE_lattice_batch_cache_dirty_tag(ob->data, BKE_LATTICE_BATCH_DIRTY_ALL);
- break;
- case OB_CURVE:
- case OB_FONT:
- case OB_SURF:
- BKE_curve_batch_cache_dirty_tag(ob->data, BKE_CURVE_BATCH_DIRTY_ALL);
- break;
- case OB_MBALL:
- BKE_mball_batch_cache_dirty_tag(ob->data, BKE_MBALL_BATCH_DIRTY_ALL);
- break;
- case OB_GPENCIL:
- BKE_gpencil_batch_cache_dirty_tag(ob->data);
- break;
- }
+ switch (ob->type) {
+ case OB_MESH:
+ BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
+ break;
+ case OB_LATTICE:
+ BKE_lattice_batch_cache_dirty_tag(ob->data, BKE_LATTICE_BATCH_DIRTY_ALL);
+ break;
+ case OB_CURVE:
+ case OB_FONT:
+ case OB_SURF:
+ BKE_curve_batch_cache_dirty_tag(ob->data, BKE_CURVE_BATCH_DIRTY_ALL);
+ break;
+ case OB_MBALL:
+ BKE_mball_batch_cache_dirty_tag(ob->data, BKE_MBALL_BATCH_DIRTY_ALL);
+ break;
+ case OB_GPENCIL:
+ BKE_gpencil_batch_cache_dirty_tag(ob->data);
+ break;
+ }
}
-void BKE_object_eval_uber_data(Depsgraph *depsgraph,
- Scene *scene,
- Object *ob)
+void BKE_object_eval_uber_data(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
- BLI_assert(ob->type != OB_ARMATURE);
- BKE_object_handle_data_update(depsgraph, scene, ob);
- BKE_object_batch_cache_dirty_tag(ob);
+ DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
+ BLI_assert(ob->type != OB_ARMATURE);
+ BKE_object_handle_data_update(depsgraph, scene, ob);
+ BKE_object_batch_cache_dirty_tag(ob);
}
-void BKE_object_eval_ptcache_reset(Depsgraph *depsgraph,
- Scene *scene,
- Object *object)
+void BKE_object_eval_ptcache_reset(Depsgraph *depsgraph, Scene *scene, Object *object)
{
- DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
- BKE_ptcache_object_reset(scene, object, PTCACHE_RESET_DEPSGRAPH);
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
+ BKE_ptcache_object_reset(scene, object, PTCACHE_RESET_DEPSGRAPH);
}
-void BKE_object_eval_transform_all(Depsgraph *depsgraph,
- Scene *scene,
- Object *object)
+void BKE_object_eval_transform_all(Depsgraph *depsgraph, Scene *scene, Object *object)
{
- /* This mimics full transform update chain from new depsgraph. */
- BKE_object_eval_local_transform(depsgraph, object);
- if (object->parent != NULL) {
- BKE_object_eval_parent(depsgraph, object);
- }
- if (!BLI_listbase_is_empty(&object->constraints)) {
- BKE_object_eval_constraints(depsgraph, scene, object);
- }
- BKE_object_eval_uber_transform(depsgraph, object);
- BKE_object_eval_transform_final(depsgraph, object);
+ /* This mimics full transform update chain from new depsgraph. */
+ BKE_object_eval_local_transform(depsgraph, object);
+ if (object->parent != NULL) {
+ BKE_object_eval_parent(depsgraph, object);
+ }
+ if (!BLI_listbase_is_empty(&object->constraints)) {
+ BKE_object_eval_constraints(depsgraph, scene, object);
+ }
+ BKE_object_eval_uber_transform(depsgraph, object);
+ BKE_object_eval_transform_final(depsgraph, object);
}
void BKE_object_eval_update_shading(Depsgraph *depsgraph, Object *object)
{
- DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
- if (object->type == OB_MESH) {
- BKE_mesh_batch_cache_dirty_tag(object->data, BKE_MESH_BATCH_DIRTY_SHADING);
- }
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
+ if (object->type == OB_MESH) {
+ BKE_mesh_batch_cache_dirty_tag(object->data, BKE_MESH_BATCH_DIRTY_SHADING);
+ }
}
void BKE_object_data_select_update(Depsgraph *depsgraph, ID *object_data)
{
- DEG_debug_print_eval(depsgraph, __func__, object_data->name, object_data);
- switch (GS(object_data->name)) {
- case ID_ME:
- BKE_mesh_batch_cache_dirty_tag(
- (Mesh *)object_data,
- BKE_MESH_BATCH_DIRTY_SELECT);
- break;
- case ID_CU:
- BKE_curve_batch_cache_dirty_tag(
- (Curve *)object_data,
- BKE_CURVE_BATCH_DIRTY_SELECT);
- break;
- case ID_LT:
- BKE_lattice_batch_cache_dirty_tag(
- (struct Lattice *)object_data,
- BKE_LATTICE_BATCH_DIRTY_SELECT);
- break;
- default:
- break;
- }
+ DEG_debug_print_eval(depsgraph, __func__, object_data->name, object_data);
+ switch (GS(object_data->name)) {
+ case ID_ME:
+ BKE_mesh_batch_cache_dirty_tag((Mesh *)object_data, BKE_MESH_BATCH_DIRTY_SELECT);
+ break;
+ case ID_CU:
+ BKE_curve_batch_cache_dirty_tag((Curve *)object_data, BKE_CURVE_BATCH_DIRTY_SELECT);
+ break;
+ case ID_LT:
+ BKE_lattice_batch_cache_dirty_tag((struct Lattice *)object_data,
+ BKE_LATTICE_BATCH_DIRTY_SELECT);
+ break;
+ default:
+ break;
+ }
}
void BKE_object_eval_eval_base_flags(Depsgraph *depsgraph,
- Scene *scene, const int view_layer_index,
- Object *object, int base_index,
+ Scene *scene,
+ const int view_layer_index,
+ Object *object,
+ int base_index,
const bool is_from_set)
{
- /* TODO(sergey): Avoid list lookup. */
- BLI_assert(view_layer_index >= 0);
- ViewLayer *view_layer = BLI_findlink(&scene->view_layers, view_layer_index);
- BLI_assert(view_layer != NULL);
- BLI_assert(view_layer->object_bases_array != NULL);
- BLI_assert(base_index >= 0);
- BLI_assert(base_index < MEM_allocN_len(view_layer->object_bases_array) / sizeof(Base *));
- Base *base = view_layer->object_bases_array[base_index];
- BLI_assert(base->object == object);
-
- DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
-
- /* Set base flags based on collection and object restriction. */
- BKE_base_eval_flags(base);
-
- /* For render, compute base visibility again since BKE_base_eval_flags
- * assumed viewport visibility. Selectability does not matter here. */
- if (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER) {
- if (base->flag & BASE_ENABLED_RENDER) {
- base->flag |= BASE_VISIBLE;
- }
- else {
- base->flag &= ~BASE_VISIBLE;
- }
- }
-
- /* Copy flags and settings from base. */
- object->base_flag = base->flag;
- if (is_from_set) {
- object->base_flag |= BASE_FROM_SET;
- object->base_flag &= ~(BASE_SELECTED | BASE_SELECTABLE);
- }
- object->base_local_view_bits = base->local_view_bits;
-
- if (object->mode == OB_MODE_PARTICLE_EDIT) {
- for (ParticleSystem *psys = object->particlesystem.first;
- psys != NULL;
- psys = psys->next)
- {
- BKE_particle_batch_cache_dirty_tag(psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
- }
- }
-
- /* Copy base flag back to the original view layer for editing. */
- if (DEG_is_active(depsgraph) && (view_layer == DEG_get_evaluated_view_layer(depsgraph))) {
- Base *base_orig = base->base_orig;
- BLI_assert(base_orig != NULL);
- BLI_assert(base_orig->object != NULL);
- base_orig->flag = base->flag;
- }
+ /* TODO(sergey): Avoid list lookup. */
+ BLI_assert(view_layer_index >= 0);
+ ViewLayer *view_layer = BLI_findlink(&scene->view_layers, view_layer_index);
+ BLI_assert(view_layer != NULL);
+ BLI_assert(view_layer->object_bases_array != NULL);
+ BLI_assert(base_index >= 0);
+ BLI_assert(base_index < MEM_allocN_len(view_layer->object_bases_array) / sizeof(Base *));
+ Base *base = view_layer->object_bases_array[base_index];
+ BLI_assert(base->object == object);
+
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
+
+ /* Set base flags based on collection and object restriction. */
+ BKE_base_eval_flags(base);
+
+ /* For render, compute base visibility again since BKE_base_eval_flags
+ * assumed viewport visibility. Selectability does not matter here. */
+ if (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER) {
+ if (base->flag & BASE_ENABLED_RENDER) {
+ base->flag |= BASE_VISIBLE;
+ }
+ else {
+ base->flag &= ~BASE_VISIBLE;
+ }
+ }
+
+ /* Copy flags and settings from base. */
+ object->base_flag = base->flag;
+ if (is_from_set) {
+ object->base_flag |= BASE_FROM_SET;
+ object->base_flag &= ~(BASE_SELECTED | BASE_SELECTABLE);
+ }
+ object->base_local_view_bits = base->local_view_bits;
+
+ if (object->mode == OB_MODE_PARTICLE_EDIT) {
+ for (ParticleSystem *psys = object->particlesystem.first; psys != NULL; psys = psys->next) {
+ BKE_particle_batch_cache_dirty_tag(psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
+ }
+ }
+
+ /* Copy base flag back to the original view layer for editing. */
+ if (DEG_is_active(depsgraph) && (view_layer == DEG_get_evaluated_view_layer(depsgraph))) {
+ Base *base_orig = base->base_orig;
+ BLI_assert(base_orig != NULL);
+ BLI_assert(base_orig->object != NULL);
+ base_orig->flag = base->flag;
+ }
}
diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c
index 9d5488bb8d3..f84048b502f 100644
--- a/source/blender/blenkernel/intern/ocean.c
+++ b/source/blender/blenkernel/intern/ocean.c
@@ -52,118 +52,116 @@
#ifdef WITH_OCEANSIM
/* Ocean code */
-#include "fftw3.h"
+# include "fftw3.h"
-#define GRAVITY 9.81f
+# define GRAVITY 9.81f
typedef struct Ocean {
- /* ********* input parameters to the sim ********* */
- float _V;
- float _l;
- float _w;
- float _A;
- float _damp_reflections;
- float _wind_alignment;
- float _depth;
-
- float _wx;
- float _wz;
-
- float _L;
-
- /* dimensions of computational grid */
- int _M;
- int _N;
-
- /* spatial size of computational grid */
- float _Lx;
- float _Lz;
-
- float normalize_factor; /* init w */
- float time;
-
- short _do_disp_y;
- short _do_normals;
- short _do_chop;
- short _do_jacobian;
-
- /* mutex for threaded texture access */
- ThreadRWMutex oceanmutex;
-
- /* ********* sim data arrays ********* */
-
- /* two dimensional arrays of complex */
- fftw_complex *_fft_in; /* init w sim w */
- fftw_complex *_fft_in_x; /* init w sim w */
- fftw_complex *_fft_in_z; /* init w sim w */
- fftw_complex *_fft_in_jxx; /* init w sim w */
- fftw_complex *_fft_in_jzz; /* init w sim w */
- fftw_complex *_fft_in_jxz; /* init w sim w */
- fftw_complex *_fft_in_nx; /* init w sim w */
- fftw_complex *_fft_in_nz; /* init w sim w */
- fftw_complex *_htilda; /* init w sim w (only once) */
-
- /* fftw "plans" */
- fftw_plan _disp_y_plan; /* init w sim r */
- fftw_plan _disp_x_plan; /* init w sim r */
- fftw_plan _disp_z_plan; /* init w sim r */
- fftw_plan _N_x_plan; /* init w sim r */
- fftw_plan _N_z_plan; /* init w sim r */
- fftw_plan _Jxx_plan; /* init w sim r */
- fftw_plan _Jxz_plan; /* init w sim r */
- fftw_plan _Jzz_plan; /* init w sim r */
-
- /* two dimensional arrays of float */
- double *_disp_y; /* init w sim w via plan? */
- double *_N_x; /* init w sim w via plan? */
- /* all member of this array has same values, so convert this array to a float to reduce memory usage (MEM01)*/
- /*float * _N_y; */
- double _N_y; /* sim w ********* can be rearranged? */
- double *_N_z; /* init w sim w via plan? */
- double *_disp_x; /* init w sim w via plan? */
- double *_disp_z; /* init w sim w via plan? */
-
- /* two dimensional arrays of float */
- /* Jacobian and minimum eigenvalue */
- double *_Jxx; /* init w sim w */
- double *_Jzz; /* init w sim w */
- double *_Jxz; /* init w sim w */
-
- /* one dimensional float array */
- float *_kx; /* init w sim r */
- float *_kz; /* init w sim r */
-
- /* two dimensional complex array */
- fftw_complex *_h0; /* init w sim r */
- fftw_complex *_h0_minus; /* init w sim r */
-
- /* two dimensional float array */
- float *_k; /* init w sim r */
+ /* ********* input parameters to the sim ********* */
+ float _V;
+ float _l;
+ float _w;
+ float _A;
+ float _damp_reflections;
+ float _wind_alignment;
+ float _depth;
+
+ float _wx;
+ float _wz;
+
+ float _L;
+
+ /* dimensions of computational grid */
+ int _M;
+ int _N;
+
+ /* spatial size of computational grid */
+ float _Lx;
+ float _Lz;
+
+ float normalize_factor; /* init w */
+ float time;
+
+ short _do_disp_y;
+ short _do_normals;
+ short _do_chop;
+ short _do_jacobian;
+
+ /* mutex for threaded texture access */
+ ThreadRWMutex oceanmutex;
+
+ /* ********* sim data arrays ********* */
+
+ /* two dimensional arrays of complex */
+ fftw_complex *_fft_in; /* init w sim w */
+ fftw_complex *_fft_in_x; /* init w sim w */
+ fftw_complex *_fft_in_z; /* init w sim w */
+ fftw_complex *_fft_in_jxx; /* init w sim w */
+ fftw_complex *_fft_in_jzz; /* init w sim w */
+ fftw_complex *_fft_in_jxz; /* init w sim w */
+ fftw_complex *_fft_in_nx; /* init w sim w */
+ fftw_complex *_fft_in_nz; /* init w sim w */
+ fftw_complex *_htilda; /* init w sim w (only once) */
+
+ /* fftw "plans" */
+ fftw_plan _disp_y_plan; /* init w sim r */
+ fftw_plan _disp_x_plan; /* init w sim r */
+ fftw_plan _disp_z_plan; /* init w sim r */
+ fftw_plan _N_x_plan; /* init w sim r */
+ fftw_plan _N_z_plan; /* init w sim r */
+ fftw_plan _Jxx_plan; /* init w sim r */
+ fftw_plan _Jxz_plan; /* init w sim r */
+ fftw_plan _Jzz_plan; /* init w sim r */
+
+ /* two dimensional arrays of float */
+ double *_disp_y; /* init w sim w via plan? */
+ double *_N_x; /* init w sim w via plan? */
+ /* all member of this array has same values, so convert this array to a float to reduce memory usage (MEM01)*/
+ /*float * _N_y; */
+ double _N_y; /* sim w ********* can be rearranged? */
+ double *_N_z; /* init w sim w via plan? */
+ double *_disp_x; /* init w sim w via plan? */
+ double *_disp_z; /* init w sim w via plan? */
+
+ /* two dimensional arrays of float */
+ /* Jacobian and minimum eigenvalue */
+ double *_Jxx; /* init w sim w */
+ double *_Jzz; /* init w sim w */
+ double *_Jxz; /* init w sim w */
+
+ /* one dimensional float array */
+ float *_kx; /* init w sim r */
+ float *_kz; /* init w sim r */
+
+ /* two dimensional complex array */
+ fftw_complex *_h0; /* init w sim r */
+ fftw_complex *_h0_minus; /* init w sim r */
+
+ /* two dimensional float array */
+ float *_k; /* init w sim r */
} Ocean;
-
-
static float nextfr(RNG *rng, float min, float max)
{
- return BLI_rng_get_float(rng) * (min - max) + max;
+ return BLI_rng_get_float(rng) * (min - max) + max;
}
static float gaussRand(RNG *rng)
{
- /* Note: to avoid numerical problems with very small numbers, we make these variables singe-precision floats,
- * but later we call the double-precision log() and sqrt() functions instead of logf() and sqrtf().
- */
- float x;
- float y;
- float length2;
+ /* Note: to avoid numerical problems with very small numbers, we make these variables singe-precision floats,
+ * but later we call the double-precision log() and sqrt() functions instead of logf() and sqrtf().
+ */
+ float x;
+ float y;
+ float length2;
- do {
- x = (float) (nextfr(rng, -1, 1));
- y = (float)(nextfr(rng, -1, 1));
- length2 = x * x + y * y;
- } while (length2 >= 1 || length2 == 0);
+ do {
+ x = (float)(nextfr(rng, -1, 1));
+ y = (float)(nextfr(rng, -1, 1));
+ length2 = x * x + y * y;
+ } while (length2 >= 1 || length2 == 0);
- return x * sqrtf(-2.0f * logf(length2) / length2);
+ return x * sqrtf(-2.0f * logf(length2) / length2);
}
/**
@@ -171,59 +169,57 @@ static float gaussRand(RNG *rng)
*/
MINLINE float catrom(float p0, float p1, float p2, float p3, float f)
{
- return 0.5f * ((2.0f * p1) +
- (-p0 + p2) * f +
- (2.0f * p0 - 5.0f * p1 + 4.0f * p2 - p3) * f * f +
- (-p0 + 3.0f * p1 - 3.0f * p2 + p3) * f * f * f);
+ return 0.5f * ((2.0f * p1) + (-p0 + p2) * f + (2.0f * p0 - 5.0f * p1 + 4.0f * p2 - p3) * f * f +
+ (-p0 + 3.0f * p1 - 3.0f * p2 + p3) * f * f * f);
}
MINLINE float omega(float k, float depth)
{
- return sqrtf(GRAVITY * k * tanhf(k * depth));
+ return sqrtf(GRAVITY * k * tanhf(k * depth));
}
/* modified Phillips spectrum */
static float Ph(struct Ocean *o, float kx, float kz)
{
- float tmp;
- float k2 = kx * kx + kz * kz;
+ float tmp;
+ float k2 = kx * kx + kz * kz;
- if (k2 == 0.0f) {
- return 0.0f; /* no DC component */
- }
+ if (k2 == 0.0f) {
+ return 0.0f; /* no DC component */
+ }
- /* damp out the waves going in the direction opposite the wind */
- tmp = (o->_wx * kx + o->_wz * kz) / sqrtf(k2);
- if (tmp < 0) {
- tmp *= o->_damp_reflections;
- }
+ /* damp out the waves going in the direction opposite the wind */
+ tmp = (o->_wx * kx + o->_wz * kz) / sqrtf(k2);
+ if (tmp < 0) {
+ tmp *= o->_damp_reflections;
+ }
- return o->_A * expf(-1.0f / (k2 * (o->_L * o->_L))) * expf(-k2 * (o->_l * o->_l)) *
- powf(fabsf(tmp), o->_wind_alignment) / (k2 * k2);
+ return o->_A * expf(-1.0f / (k2 * (o->_L * o->_L))) * expf(-k2 * (o->_l * o->_l)) *
+ powf(fabsf(tmp), o->_wind_alignment) / (k2 * k2);
}
static void compute_eigenstuff(struct OceanResult *ocr, float jxx, float jzz, float jxz)
{
- float a, b, qplus, qminus;
- a = jxx + jzz;
- b = sqrt((jxx - jzz) * (jxx - jzz) + 4 * jxz * jxz);
+ float a, b, qplus, qminus;
+ a = jxx + jzz;
+ b = sqrt((jxx - jzz) * (jxx - jzz) + 4 * jxz * jxz);
- ocr->Jminus = 0.5f * (a - b);
- ocr->Jplus = 0.5f * (a + b);
+ ocr->Jminus = 0.5f * (a - b);
+ ocr->Jplus = 0.5f * (a + b);
- qplus = (ocr->Jplus - jxx) / jxz;
- qminus = (ocr->Jminus - jxx) / jxz;
+ qplus = (ocr->Jplus - jxx) / jxz;
+ qminus = (ocr->Jminus - jxx) / jxz;
- a = sqrt(1 + qplus * qplus);
- b = sqrt(1 + qminus * qminus);
+ a = sqrt(1 + qplus * qplus);
+ b = sqrt(1 + qminus * qminus);
- ocr->Eplus[0] = 1.0f / a;
- ocr->Eplus[1] = 0.0f;
- ocr->Eplus[2] = qplus / a;
+ ocr->Eplus[0] = 1.0f / a;
+ ocr->Eplus[1] = 0.0f;
+ ocr->Eplus[2] = qplus / a;
- ocr->Eminus[0] = 1.0f / b;
- ocr->Eminus[1] = 0.0f;
- ocr->Eminus[2] = qminus / b;
+ ocr->Eminus[0] = 1.0f / b;
+ ocr->Eminus[1] = 0.0f;
+ ocr->Eminus[2] = qminus / b;
}
/*
@@ -233,218 +229,235 @@ static void compute_eigenstuff(struct OceanResult *ocr, float jxx, float jzz, fl
* */
static void init_complex(fftw_complex cmpl, float real, float image)
{
- cmpl[0] = real;
- cmpl[1] = image;
+ cmpl[0] = real;
+ cmpl[1] = image;
}
static void add_comlex_c(fftw_complex res, fftw_complex cmpl1, fftw_complex cmpl2)
{
- res[0] = cmpl1[0] + cmpl2[0];
- res[1] = cmpl1[1] + cmpl2[1];
+ res[0] = cmpl1[0] + cmpl2[0];
+ res[1] = cmpl1[1] + cmpl2[1];
}
static void mul_complex_f(fftw_complex res, fftw_complex cmpl, float f)
{
- res[0] = cmpl[0] * (double)f;
- res[1] = cmpl[1] * (double)f;
+ res[0] = cmpl[0] * (double)f;
+ res[1] = cmpl[1] * (double)f;
}
static void mul_complex_c(fftw_complex res, fftw_complex cmpl1, fftw_complex cmpl2)
{
- fftwf_complex temp;
- temp[0] = cmpl1[0] * cmpl2[0] - cmpl1[1] * cmpl2[1];
- temp[1] = cmpl1[0] * cmpl2[1] + cmpl1[1] * cmpl2[0];
- res[0] = temp[0];
- res[1] = temp[1];
+ fftwf_complex temp;
+ temp[0] = cmpl1[0] * cmpl2[0] - cmpl1[1] * cmpl2[1];
+ temp[1] = cmpl1[0] * cmpl2[1] + cmpl1[1] * cmpl2[0];
+ res[0] = temp[0];
+ res[1] = temp[1];
}
static float real_c(fftw_complex cmpl)
{
- return cmpl[0];
+ return cmpl[0];
}
static float image_c(fftw_complex cmpl)
{
- return cmpl[1];
+ return cmpl[1];
}
static void conj_complex(fftw_complex res, fftw_complex cmpl1)
{
- res[0] = cmpl1[0];
- res[1] = -cmpl1[1];
+ res[0] = cmpl1[0];
+ res[1] = -cmpl1[1];
}
static void exp_complex(fftw_complex res, fftw_complex cmpl)
{
- float r = expf(cmpl[0]);
+ float r = expf(cmpl[0]);
- res[0] = cosf(cmpl[1]) * r;
- res[1] = sinf(cmpl[1]) * r;
+ res[0] = cosf(cmpl[1]) * r;
+ res[1] = sinf(cmpl[1]) * r;
}
float BKE_ocean_jminus_to_foam(float jminus, float coverage)
{
- float foam = jminus * -0.005f + coverage;
- CLAMP(foam, 0.0f, 1.0f);
- return foam * foam;
+ float foam = jminus * -0.005f + coverage;
+ CLAMP(foam, 0.0f, 1.0f);
+ return foam * foam;
}
void BKE_ocean_eval_uv(struct Ocean *oc, struct OceanResult *ocr, float u, float v)
{
- int i0, i1, j0, j1;
- float frac_x, frac_z;
- float uu, vv;
+ int i0, i1, j0, j1;
+ float frac_x, frac_z;
+ float uu, vv;
- /* first wrap the texture so 0 <= (u, v) < 1 */
- u = fmodf(u, 1.0f);
- v = fmodf(v, 1.0f);
+ /* first wrap the texture so 0 <= (u, v) < 1 */
+ u = fmodf(u, 1.0f);
+ v = fmodf(v, 1.0f);
- if (u < 0) u += 1.0f;
- if (v < 0) v += 1.0f;
+ if (u < 0)
+ u += 1.0f;
+ if (v < 0)
+ v += 1.0f;
- BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_READ);
+ BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_READ);
- uu = u * oc->_M;
- vv = v * oc->_N;
+ uu = u * oc->_M;
+ vv = v * oc->_N;
- i0 = (int)floor(uu);
- j0 = (int)floor(vv);
+ i0 = (int)floor(uu);
+ j0 = (int)floor(vv);
- i1 = (i0 + 1);
- j1 = (j0 + 1);
+ i1 = (i0 + 1);
+ j1 = (j0 + 1);
- frac_x = uu - i0;
- frac_z = vv - j0;
+ frac_x = uu - i0;
+ frac_z = vv - j0;
- i0 = i0 % oc->_M;
- j0 = j0 % oc->_N;
+ i0 = i0 % oc->_M;
+ j0 = j0 % oc->_N;
- i1 = i1 % oc->_M;
- j1 = j1 % oc->_N;
+ i1 = i1 % oc->_M;
+ j1 = j1 % oc->_N;
-#define BILERP(m) (interpf(interpf(m[i1 * oc->_N + j1], m[i0 * oc->_N + j1], frac_x), \
- interpf(m[i1 * oc->_N + j0], m[i0 * oc->_N + j0], frac_x), \
- frac_z))
+# define BILERP(m) \
+ (interpf(interpf(m[i1 * oc->_N + j1], m[i0 * oc->_N + j1], frac_x), \
+ interpf(m[i1 * oc->_N + j0], m[i0 * oc->_N + j0], frac_x), \
+ frac_z))
- {
- if (oc->_do_disp_y) {
- ocr->disp[1] = BILERP(oc->_disp_y);
- }
+ {
+ if (oc->_do_disp_y) {
+ ocr->disp[1] = BILERP(oc->_disp_y);
+ }
- if (oc->_do_normals) {
- ocr->normal[0] = BILERP(oc->_N_x);
- ocr->normal[1] = oc->_N_y /*BILERP(oc->_N_y) (MEM01)*/;
- ocr->normal[2] = BILERP(oc->_N_z);
- }
+ if (oc->_do_normals) {
+ ocr->normal[0] = BILERP(oc->_N_x);
+ ocr->normal[1] = oc->_N_y /*BILERP(oc->_N_y) (MEM01)*/;
+ ocr->normal[2] = BILERP(oc->_N_z);
+ }
- if (oc->_do_chop) {
- ocr->disp[0] = BILERP(oc->_disp_x);
- ocr->disp[2] = BILERP(oc->_disp_z);
- }
- else {
- ocr->disp[0] = 0.0;
- ocr->disp[2] = 0.0;
- }
+ if (oc->_do_chop) {
+ ocr->disp[0] = BILERP(oc->_disp_x);
+ ocr->disp[2] = BILERP(oc->_disp_z);
+ }
+ else {
+ ocr->disp[0] = 0.0;
+ ocr->disp[2] = 0.0;
+ }
- if (oc->_do_jacobian) {
- compute_eigenstuff(ocr, BILERP(oc->_Jxx), BILERP(oc->_Jzz), BILERP(oc->_Jxz));
- }
- }
-#undef BILERP
+ if (oc->_do_jacobian) {
+ compute_eigenstuff(ocr, BILERP(oc->_Jxx), BILERP(oc->_Jzz), BILERP(oc->_Jxz));
+ }
+ }
+# undef BILERP
- BLI_rw_mutex_unlock(&oc->oceanmutex);
+ BLI_rw_mutex_unlock(&oc->oceanmutex);
}
/* use catmullrom interpolation rather than linear */
void BKE_ocean_eval_uv_catrom(struct Ocean *oc, struct OceanResult *ocr, float u, float v)
{
- int i0, i1, i2, i3, j0, j1, j2, j3;
- float frac_x, frac_z;
- float uu, vv;
-
- /* first wrap the texture so 0 <= (u, v) < 1 */
- u = fmod(u, 1.0f);
- v = fmod(v, 1.0f);
-
- if (u < 0) u += 1.0f;
- if (v < 0) v += 1.0f;
-
- BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_READ);
-
- uu = u * oc->_M;
- vv = v * oc->_N;
-
- i1 = (int)floor(uu);
- j1 = (int)floor(vv);
-
- i2 = (i1 + 1);
- j2 = (j1 + 1);
-
- frac_x = uu - i1;
- frac_z = vv - j1;
-
- i1 = i1 % oc->_M;
- j1 = j1 % oc->_N;
-
- i2 = i2 % oc->_M;
- j2 = j2 % oc->_N;
-
- i0 = (i1 - 1);
- i3 = (i2 + 1);
- i0 = i0 < 0 ? i0 + oc->_M : i0;
- i3 = i3 >= oc->_M ? i3 - oc->_M : i3;
-
- j0 = (j1 - 1);
- j3 = (j2 + 1);
- j0 = j0 < 0 ? j0 + oc->_N : j0;
- j3 = j3 >= oc->_N ? j3 - oc->_N : j3;
-
-#define INTERP(m) catrom(catrom(m[i0 * oc->_N + j0], m[i1 * oc->_N + j0], \
- m[i2 * oc->_N + j0], m[i3 * oc->_N + j0], frac_x), \
- catrom(m[i0 * oc->_N + j1], m[i1 * oc->_N + j1], \
- m[i2 * oc->_N + j1], m[i3 * oc->_N + j1], frac_x), \
- catrom(m[i0 * oc->_N + j2], m[i1 * oc->_N + j2], \
- m[i2 * oc->_N + j2], m[i3 * oc->_N + j2], frac_x), \
- catrom(m[i0 * oc->_N + j3], m[i1 * oc->_N + j3], \
- m[i2 * oc->_N + j3], m[i3 * oc->_N + j3], frac_x), \
- frac_z)
-
- {
- if (oc->_do_disp_y) {
- ocr->disp[1] = INTERP(oc->_disp_y);
- }
- if (oc->_do_normals) {
- ocr->normal[0] = INTERP(oc->_N_x);
- ocr->normal[1] = oc->_N_y /*INTERP(oc->_N_y) (MEM01)*/;
- ocr->normal[2] = INTERP(oc->_N_z);
- }
- if (oc->_do_chop) {
- ocr->disp[0] = INTERP(oc->_disp_x);
- ocr->disp[2] = INTERP(oc->_disp_z);
- }
- else {
- ocr->disp[0] = 0.0;
- ocr->disp[2] = 0.0;
- }
-
- if (oc->_do_jacobian) {
- compute_eigenstuff(ocr, INTERP(oc->_Jxx), INTERP(oc->_Jzz), INTERP(oc->_Jxz));
- }
- }
-#undef INTERP
-
- BLI_rw_mutex_unlock(&oc->oceanmutex);
-
+ int i0, i1, i2, i3, j0, j1, j2, j3;
+ float frac_x, frac_z;
+ float uu, vv;
+
+ /* first wrap the texture so 0 <= (u, v) < 1 */
+ u = fmod(u, 1.0f);
+ v = fmod(v, 1.0f);
+
+ if (u < 0)
+ u += 1.0f;
+ if (v < 0)
+ v += 1.0f;
+
+ BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_READ);
+
+ uu = u * oc->_M;
+ vv = v * oc->_N;
+
+ i1 = (int)floor(uu);
+ j1 = (int)floor(vv);
+
+ i2 = (i1 + 1);
+ j2 = (j1 + 1);
+
+ frac_x = uu - i1;
+ frac_z = vv - j1;
+
+ i1 = i1 % oc->_M;
+ j1 = j1 % oc->_N;
+
+ i2 = i2 % oc->_M;
+ j2 = j2 % oc->_N;
+
+ i0 = (i1 - 1);
+ i3 = (i2 + 1);
+ i0 = i0 < 0 ? i0 + oc->_M : i0;
+ i3 = i3 >= oc->_M ? i3 - oc->_M : i3;
+
+ j0 = (j1 - 1);
+ j3 = (j2 + 1);
+ j0 = j0 < 0 ? j0 + oc->_N : j0;
+ j3 = j3 >= oc->_N ? j3 - oc->_N : j3;
+
+# define INTERP(m) \
+ catrom(catrom(m[i0 * oc->_N + j0], \
+ m[i1 * oc->_N + j0], \
+ m[i2 * oc->_N + j0], \
+ m[i3 * oc->_N + j0], \
+ frac_x), \
+ catrom(m[i0 * oc->_N + j1], \
+ m[i1 * oc->_N + j1], \
+ m[i2 * oc->_N + j1], \
+ m[i3 * oc->_N + j1], \
+ frac_x), \
+ catrom(m[i0 * oc->_N + j2], \
+ m[i1 * oc->_N + j2], \
+ m[i2 * oc->_N + j2], \
+ m[i3 * oc->_N + j2], \
+ frac_x), \
+ catrom(m[i0 * oc->_N + j3], \
+ m[i1 * oc->_N + j3], \
+ m[i2 * oc->_N + j3], \
+ m[i3 * oc->_N + j3], \
+ frac_x), \
+ frac_z)
+
+ {
+ if (oc->_do_disp_y) {
+ ocr->disp[1] = INTERP(oc->_disp_y);
+ }
+ if (oc->_do_normals) {
+ ocr->normal[0] = INTERP(oc->_N_x);
+ ocr->normal[1] = oc->_N_y /*INTERP(oc->_N_y) (MEM01)*/;
+ ocr->normal[2] = INTERP(oc->_N_z);
+ }
+ if (oc->_do_chop) {
+ ocr->disp[0] = INTERP(oc->_disp_x);
+ ocr->disp[2] = INTERP(oc->_disp_z);
+ }
+ else {
+ ocr->disp[0] = 0.0;
+ ocr->disp[2] = 0.0;
+ }
+
+ if (oc->_do_jacobian) {
+ compute_eigenstuff(ocr, INTERP(oc->_Jxx), INTERP(oc->_Jzz), INTERP(oc->_Jxz));
+ }
+ }
+# undef INTERP
+
+ BLI_rw_mutex_unlock(&oc->oceanmutex);
}
void BKE_ocean_eval_xz(struct Ocean *oc, struct OceanResult *ocr, float x, float z)
{
- BKE_ocean_eval_uv(oc, ocr, x / oc->_Lx, z / oc->_Lz);
+ BKE_ocean_eval_uv(oc, ocr, x / oc->_Lx, z / oc->_Lz);
}
void BKE_ocean_eval_xz_catrom(struct Ocean *oc, struct OceanResult *ocr, float x, float z)
{
- BKE_ocean_eval_uv_catrom(oc, ocr, x / oc->_Lx, z / oc->_Lz);
+ BKE_ocean_eval_uv_catrom(oc, ocr, x / oc->_Lx, z / oc->_Lz);
}
/* note that this doesn't wrap properly for i, j < 0, but its not really meant for that being just a way to get
@@ -452,986 +465,1095 @@ void BKE_ocean_eval_xz_catrom(struct Ocean *oc, struct OceanResult *ocr, float x
*/
void BKE_ocean_eval_ij(struct Ocean *oc, struct OceanResult *ocr, int i, int j)
{
- BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_READ);
+ BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_READ);
- i = abs(i) % oc->_M;
- j = abs(j) % oc->_N;
+ i = abs(i) % oc->_M;
+ j = abs(j) % oc->_N;
- ocr->disp[1] = oc->_do_disp_y ? (float)oc->_disp_y[i * oc->_N + j] : 0.0f;
+ ocr->disp[1] = oc->_do_disp_y ? (float)oc->_disp_y[i * oc->_N + j] : 0.0f;
- if (oc->_do_chop) {
- ocr->disp[0] = oc->_disp_x[i * oc->_N + j];
- ocr->disp[2] = oc->_disp_z[i * oc->_N + j];
- }
- else {
- ocr->disp[0] = 0.0f;
- ocr->disp[2] = 0.0f;
- }
+ if (oc->_do_chop) {
+ ocr->disp[0] = oc->_disp_x[i * oc->_N + j];
+ ocr->disp[2] = oc->_disp_z[i * oc->_N + j];
+ }
+ else {
+ ocr->disp[0] = 0.0f;
+ ocr->disp[2] = 0.0f;
+ }
- if (oc->_do_normals) {
- ocr->normal[0] = oc->_N_x[i * oc->_N + j];
- ocr->normal[1] = oc->_N_y /* oc->_N_y[i * oc->_N + j] (MEM01) */;
- ocr->normal[2] = oc->_N_z[i * oc->_N + j];
+ if (oc->_do_normals) {
+ ocr->normal[0] = oc->_N_x[i * oc->_N + j];
+ ocr->normal[1] = oc->_N_y /* oc->_N_y[i * oc->_N + j] (MEM01) */;
+ ocr->normal[2] = oc->_N_z[i * oc->_N + j];
- normalize_v3(ocr->normal);
- }
+ normalize_v3(ocr->normal);
+ }
- if (oc->_do_jacobian) {
- compute_eigenstuff(ocr, oc->_Jxx[i * oc->_N + j], oc->_Jzz[i * oc->_N + j], oc->_Jxz[i * oc->_N + j]);
- }
+ if (oc->_do_jacobian) {
+ compute_eigenstuff(
+ ocr, oc->_Jxx[i * oc->_N + j], oc->_Jzz[i * oc->_N + j], oc->_Jxz[i * oc->_N + j]);
+ }
- BLI_rw_mutex_unlock(&oc->oceanmutex);
+ BLI_rw_mutex_unlock(&oc->oceanmutex);
}
typedef struct OceanSimulateData {
- Ocean *o;
- float t;
- float scale;
- float chop_amount;
+ Ocean *o;
+ float t;
+ float scale;
+ float chop_amount;
} OceanSimulateData;
-static void ocean_compute_htilda(
- void *__restrict userdata,
- const int i,
- const ParallelRangeTLS *__restrict UNUSED(tls))
-{
- OceanSimulateData *osd = userdata;
- const Ocean *o = osd->o;
- const float scale = osd->scale;
- const float t = osd->t;
-
- int j;
-
- /* note the <= _N/2 here, see the fftw doco about the mechanics of the complex->real fft storage */
- for (j = 0; j <= o->_N / 2; ++j) {
- fftw_complex exp_param1;
- fftw_complex exp_param2;
- fftw_complex conj_param;
-
- init_complex(exp_param1, 0.0, omega(o->_k[i * (1 + o->_N / 2) + j], o->_depth) * t);
- init_complex(exp_param2, 0.0, -omega(o->_k[i * (1 + o->_N / 2) + j], o->_depth) * t);
- exp_complex(exp_param1, exp_param1);
- exp_complex(exp_param2, exp_param2);
- conj_complex(conj_param, o->_h0_minus[i * o->_N + j]);
-
- mul_complex_c(exp_param1, o->_h0[i * o->_N + j], exp_param1);
- mul_complex_c(exp_param2, conj_param, exp_param2);
-
- add_comlex_c(o->_htilda[i * (1 + o->_N / 2) + j], exp_param1, exp_param2);
- mul_complex_f(o->_fft_in[i * (1 + o->_N / 2) + j], o->_htilda[i * (1 + o->_N / 2) + j], scale);
- }
-}
-
-static void ocean_compute_displacement_y(TaskPool * __restrict pool, void *UNUSED(taskdata), int UNUSED(threadid))
-{
- OceanSimulateData *osd = BLI_task_pool_userdata(pool);
- const Ocean *o = osd->o;
-
- fftw_execute(o->_disp_y_plan);
-}
-
-static void ocean_compute_displacement_x(TaskPool * __restrict pool, void *UNUSED(taskdata), int UNUSED(threadid))
-{
- OceanSimulateData *osd = BLI_task_pool_userdata(pool);
- const Ocean *o = osd->o;
- const float scale = osd->scale;
- const float chop_amount = osd->chop_amount;
- int i, j;
-
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j <= o->_N / 2; ++j) {
- fftw_complex mul_param;
- fftw_complex minus_i;
-
- init_complex(minus_i, 0.0, -1.0);
- init_complex(mul_param, -scale, 0);
- mul_complex_f(mul_param, mul_param, chop_amount);
- mul_complex_c(mul_param, mul_param, minus_i);
- mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]);
- mul_complex_f(mul_param, mul_param,
- ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ?
- 0.0f :
- o->_kx[i] / o->_k[i * (1 + o->_N / 2) + j]));
- init_complex(o->_fft_in_x[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param));
- }
- }
- fftw_execute(o->_disp_x_plan);
-}
-
-static void ocean_compute_displacement_z(TaskPool * __restrict pool, void *UNUSED(taskdata), int UNUSED(threadid))
-{
- OceanSimulateData *osd = BLI_task_pool_userdata(pool);
- const Ocean *o = osd->o;
- const float scale = osd->scale;
- const float chop_amount = osd->chop_amount;
- int i, j;
-
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j <= o->_N / 2; ++j) {
- fftw_complex mul_param;
- fftw_complex minus_i;
-
- init_complex(minus_i, 0.0, -1.0);
- init_complex(mul_param, -scale, 0);
- mul_complex_f(mul_param, mul_param, chop_amount);
- mul_complex_c(mul_param, mul_param, minus_i);
- mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]);
- mul_complex_f(mul_param, mul_param,
- ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ?
- 0.0f :
- o->_kz[j] / o->_k[i * (1 + o->_N / 2) + j]));
- init_complex(o->_fft_in_z[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param));
- }
- }
- fftw_execute(o->_disp_z_plan);
-}
-
-static void ocean_compute_jacobian_jxx(TaskPool * __restrict pool, void *UNUSED(taskdata), int UNUSED(threadid))
-{
- OceanSimulateData *osd = BLI_task_pool_userdata(pool);
- const Ocean *o = osd->o;
- const float chop_amount = osd->chop_amount;
- int i, j;
-
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j <= o->_N / 2; ++j) {
- fftw_complex mul_param;
-
- /* init_complex(mul_param, -scale, 0); */
- init_complex(mul_param, -1, 0);
-
- mul_complex_f(mul_param, mul_param, chop_amount);
- mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]);
- mul_complex_f(mul_param, mul_param,
- ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ?
- 0.0f :
- o->_kx[i] * o->_kx[i] / o->_k[i * (1 + o->_N / 2) + j]));
- init_complex(o->_fft_in_jxx[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param));
- }
- }
- fftw_execute(o->_Jxx_plan);
-
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j < o->_N; ++j) {
- o->_Jxx[i * o->_N + j] += 1.0;
- }
- }
-}
-
-static void ocean_compute_jacobian_jzz(TaskPool * __restrict pool, void *UNUSED(taskdata), int UNUSED(threadid))
-{
- OceanSimulateData *osd = BLI_task_pool_userdata(pool);
- const Ocean *o = osd->o;
- const float chop_amount = osd->chop_amount;
- int i, j;
-
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j <= o->_N / 2; ++j) {
- fftw_complex mul_param;
-
- /* init_complex(mul_param, -scale, 0); */
- init_complex(mul_param, -1, 0);
-
- mul_complex_f(mul_param, mul_param, chop_amount);
- mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]);
- mul_complex_f(mul_param, mul_param,
- ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ?
- 0.0f :
- o->_kz[j] * o->_kz[j] / o->_k[i * (1 + o->_N / 2) + j]));
- init_complex(o->_fft_in_jzz[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param));
- }
- }
- fftw_execute(o->_Jzz_plan);
-
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j < o->_N; ++j) {
- o->_Jzz[i * o->_N + j] += 1.0;
- }
- }
-}
-
-static void ocean_compute_jacobian_jxz(TaskPool * __restrict pool, void *UNUSED(taskdata), int UNUSED(threadid))
-{
- OceanSimulateData *osd = BLI_task_pool_userdata(pool);
- const Ocean *o = osd->o;
- const float chop_amount = osd->chop_amount;
- int i, j;
-
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j <= o->_N / 2; ++j) {
- fftw_complex mul_param;
-
- /* init_complex(mul_param, -scale, 0); */
- init_complex(mul_param, -1, 0);
-
- mul_complex_f(mul_param, mul_param, chop_amount);
- mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]);
- mul_complex_f(mul_param, mul_param,
- ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ?
- 0.0f :
- o->_kx[i] * o->_kz[j] / o->_k[i * (1 + o->_N / 2) + j]));
- init_complex(o->_fft_in_jxz[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param));
- }
- }
- fftw_execute(o->_Jxz_plan);
-}
-
-static void ocean_compute_normal_x(TaskPool * __restrict pool, void *UNUSED(taskdata), int UNUSED(threadid))
-{
- OceanSimulateData *osd = BLI_task_pool_userdata(pool);
- const Ocean *o = osd->o;
- int i, j;
-
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j <= o->_N / 2; ++j) {
- fftw_complex mul_param;
-
- init_complex(mul_param, 0.0, -1.0);
- mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]);
- mul_complex_f(mul_param, mul_param, o->_kx[i]);
- init_complex(o->_fft_in_nx[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param));
- }
- }
- fftw_execute(o->_N_x_plan);
-}
-
-static void ocean_compute_normal_z(TaskPool * __restrict pool, void *UNUSED(taskdata), int UNUSED(threadid))
-{
- OceanSimulateData *osd = BLI_task_pool_userdata(pool);
- const Ocean *o = osd->o;
- int i, j;
-
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j <= o->_N / 2; ++j) {
- fftw_complex mul_param;
-
- init_complex(mul_param, 0.0, -1.0);
- mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]);
- mul_complex_f(mul_param, mul_param, o->_kz[i]);
- init_complex(o->_fft_in_nz[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param));
- }
- }
- fftw_execute(o->_N_z_plan);
+static void ocean_compute_htilda(void *__restrict userdata,
+ const int i,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ OceanSimulateData *osd = userdata;
+ const Ocean *o = osd->o;
+ const float scale = osd->scale;
+ const float t = osd->t;
+
+ int j;
+
+ /* note the <= _N/2 here, see the fftw doco about the mechanics of the complex->real fft storage */
+ for (j = 0; j <= o->_N / 2; ++j) {
+ fftw_complex exp_param1;
+ fftw_complex exp_param2;
+ fftw_complex conj_param;
+
+ init_complex(exp_param1, 0.0, omega(o->_k[i * (1 + o->_N / 2) + j], o->_depth) * t);
+ init_complex(exp_param2, 0.0, -omega(o->_k[i * (1 + o->_N / 2) + j], o->_depth) * t);
+ exp_complex(exp_param1, exp_param1);
+ exp_complex(exp_param2, exp_param2);
+ conj_complex(conj_param, o->_h0_minus[i * o->_N + j]);
+
+ mul_complex_c(exp_param1, o->_h0[i * o->_N + j], exp_param1);
+ mul_complex_c(exp_param2, conj_param, exp_param2);
+
+ add_comlex_c(o->_htilda[i * (1 + o->_N / 2) + j], exp_param1, exp_param2);
+ mul_complex_f(o->_fft_in[i * (1 + o->_N / 2) + j], o->_htilda[i * (1 + o->_N / 2) + j], scale);
+ }
+}
+
+static void ocean_compute_displacement_y(TaskPool *__restrict pool,
+ void *UNUSED(taskdata),
+ int UNUSED(threadid))
+{
+ OceanSimulateData *osd = BLI_task_pool_userdata(pool);
+ const Ocean *o = osd->o;
+
+ fftw_execute(o->_disp_y_plan);
+}
+
+static void ocean_compute_displacement_x(TaskPool *__restrict pool,
+ void *UNUSED(taskdata),
+ int UNUSED(threadid))
+{
+ OceanSimulateData *osd = BLI_task_pool_userdata(pool);
+ const Ocean *o = osd->o;
+ const float scale = osd->scale;
+ const float chop_amount = osd->chop_amount;
+ int i, j;
+
+ for (i = 0; i < o->_M; ++i) {
+ for (j = 0; j <= o->_N / 2; ++j) {
+ fftw_complex mul_param;
+ fftw_complex minus_i;
+
+ init_complex(minus_i, 0.0, -1.0);
+ init_complex(mul_param, -scale, 0);
+ mul_complex_f(mul_param, mul_param, chop_amount);
+ mul_complex_c(mul_param, mul_param, minus_i);
+ mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]);
+ mul_complex_f(mul_param,
+ mul_param,
+ ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ?
+ 0.0f :
+ o->_kx[i] / o->_k[i * (1 + o->_N / 2) + j]));
+ init_complex(o->_fft_in_x[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param));
+ }
+ }
+ fftw_execute(o->_disp_x_plan);
+}
+
+static void ocean_compute_displacement_z(TaskPool *__restrict pool,
+ void *UNUSED(taskdata),
+ int UNUSED(threadid))
+{
+ OceanSimulateData *osd = BLI_task_pool_userdata(pool);
+ const Ocean *o = osd->o;
+ const float scale = osd->scale;
+ const float chop_amount = osd->chop_amount;
+ int i, j;
+
+ for (i = 0; i < o->_M; ++i) {
+ for (j = 0; j <= o->_N / 2; ++j) {
+ fftw_complex mul_param;
+ fftw_complex minus_i;
+
+ init_complex(minus_i, 0.0, -1.0);
+ init_complex(mul_param, -scale, 0);
+ mul_complex_f(mul_param, mul_param, chop_amount);
+ mul_complex_c(mul_param, mul_param, minus_i);
+ mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]);
+ mul_complex_f(mul_param,
+ mul_param,
+ ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ?
+ 0.0f :
+ o->_kz[j] / o->_k[i * (1 + o->_N / 2) + j]));
+ init_complex(o->_fft_in_z[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param));
+ }
+ }
+ fftw_execute(o->_disp_z_plan);
+}
+
+static void ocean_compute_jacobian_jxx(TaskPool *__restrict pool,
+ void *UNUSED(taskdata),
+ int UNUSED(threadid))
+{
+ OceanSimulateData *osd = BLI_task_pool_userdata(pool);
+ const Ocean *o = osd->o;
+ const float chop_amount = osd->chop_amount;
+ int i, j;
+
+ for (i = 0; i < o->_M; ++i) {
+ for (j = 0; j <= o->_N / 2; ++j) {
+ fftw_complex mul_param;
+
+ /* init_complex(mul_param, -scale, 0); */
+ init_complex(mul_param, -1, 0);
+
+ mul_complex_f(mul_param, mul_param, chop_amount);
+ mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]);
+ mul_complex_f(mul_param,
+ mul_param,
+ ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ?
+ 0.0f :
+ o->_kx[i] * o->_kx[i] / o->_k[i * (1 + o->_N / 2) + j]));
+ init_complex(o->_fft_in_jxx[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param));
+ }
+ }
+ fftw_execute(o->_Jxx_plan);
+
+ for (i = 0; i < o->_M; ++i) {
+ for (j = 0; j < o->_N; ++j) {
+ o->_Jxx[i * o->_N + j] += 1.0;
+ }
+ }
+}
+
+static void ocean_compute_jacobian_jzz(TaskPool *__restrict pool,
+ void *UNUSED(taskdata),
+ int UNUSED(threadid))
+{
+ OceanSimulateData *osd = BLI_task_pool_userdata(pool);
+ const Ocean *o = osd->o;
+ const float chop_amount = osd->chop_amount;
+ int i, j;
+
+ for (i = 0; i < o->_M; ++i) {
+ for (j = 0; j <= o->_N / 2; ++j) {
+ fftw_complex mul_param;
+
+ /* init_complex(mul_param, -scale, 0); */
+ init_complex(mul_param, -1, 0);
+
+ mul_complex_f(mul_param, mul_param, chop_amount);
+ mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]);
+ mul_complex_f(mul_param,
+ mul_param,
+ ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ?
+ 0.0f :
+ o->_kz[j] * o->_kz[j] / o->_k[i * (1 + o->_N / 2) + j]));
+ init_complex(o->_fft_in_jzz[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param));
+ }
+ }
+ fftw_execute(o->_Jzz_plan);
+
+ for (i = 0; i < o->_M; ++i) {
+ for (j = 0; j < o->_N; ++j) {
+ o->_Jzz[i * o->_N + j] += 1.0;
+ }
+ }
+}
+
+static void ocean_compute_jacobian_jxz(TaskPool *__restrict pool,
+ void *UNUSED(taskdata),
+ int UNUSED(threadid))
+{
+ OceanSimulateData *osd = BLI_task_pool_userdata(pool);
+ const Ocean *o = osd->o;
+ const float chop_amount = osd->chop_amount;
+ int i, j;
+
+ for (i = 0; i < o->_M; ++i) {
+ for (j = 0; j <= o->_N / 2; ++j) {
+ fftw_complex mul_param;
+
+ /* init_complex(mul_param, -scale, 0); */
+ init_complex(mul_param, -1, 0);
+
+ mul_complex_f(mul_param, mul_param, chop_amount);
+ mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]);
+ mul_complex_f(mul_param,
+ mul_param,
+ ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ?
+ 0.0f :
+ o->_kx[i] * o->_kz[j] / o->_k[i * (1 + o->_N / 2) + j]));
+ init_complex(o->_fft_in_jxz[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param));
+ }
+ }
+ fftw_execute(o->_Jxz_plan);
+}
+
+static void ocean_compute_normal_x(TaskPool *__restrict pool,
+ void *UNUSED(taskdata),
+ int UNUSED(threadid))
+{
+ OceanSimulateData *osd = BLI_task_pool_userdata(pool);
+ const Ocean *o = osd->o;
+ int i, j;
+
+ for (i = 0; i < o->_M; ++i) {
+ for (j = 0; j <= o->_N / 2; ++j) {
+ fftw_complex mul_param;
+
+ init_complex(mul_param, 0.0, -1.0);
+ mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]);
+ mul_complex_f(mul_param, mul_param, o->_kx[i]);
+ init_complex(o->_fft_in_nx[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param));
+ }
+ }
+ fftw_execute(o->_N_x_plan);
+}
+
+static void ocean_compute_normal_z(TaskPool *__restrict pool,
+ void *UNUSED(taskdata),
+ int UNUSED(threadid))
+{
+ OceanSimulateData *osd = BLI_task_pool_userdata(pool);
+ const Ocean *o = osd->o;
+ int i, j;
+
+ for (i = 0; i < o->_M; ++i) {
+ for (j = 0; j <= o->_N / 2; ++j) {
+ fftw_complex mul_param;
+
+ init_complex(mul_param, 0.0, -1.0);
+ mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]);
+ mul_complex_f(mul_param, mul_param, o->_kz[i]);
+ init_complex(o->_fft_in_nz[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param));
+ }
+ }
+ fftw_execute(o->_N_z_plan);
}
void BKE_ocean_simulate(struct Ocean *o, float t, float scale, float chop_amount)
{
- TaskScheduler *scheduler = BLI_task_scheduler_get();
- TaskPool *pool;
+ TaskScheduler *scheduler = BLI_task_scheduler_get();
+ TaskPool *pool;
- OceanSimulateData osd;
+ OceanSimulateData osd;
- scale *= o->normalize_factor;
+ scale *= o->normalize_factor;
- osd.o = o;
- osd.t = t;
- osd.scale = scale;
- osd.chop_amount = chop_amount;
+ osd.o = o;
+ osd.t = t;
+ osd.scale = scale;
+ osd.chop_amount = chop_amount;
- pool = BLI_task_pool_create(scheduler, &osd);
+ pool = BLI_task_pool_create(scheduler, &osd);
- BLI_rw_mutex_lock(&o->oceanmutex, THREAD_LOCK_WRITE);
+ BLI_rw_mutex_lock(&o->oceanmutex, THREAD_LOCK_WRITE);
- /* Note about multi-threading here: we have to run a first set of computations (htilda one) before we can run
- * all others, since they all depend on it.
- * So we make a first parallelized forloop run for htilda, and then pack all other computations into
- * a set of parallel tasks.
- * This is not optimal in all cases, but remains reasonably simple and should be OK most of the time. */
+ /* Note about multi-threading here: we have to run a first set of computations (htilda one) before we can run
+ * all others, since they all depend on it.
+ * So we make a first parallelized forloop run for htilda, and then pack all other computations into
+ * a set of parallel tasks.
+ * This is not optimal in all cases, but remains reasonably simple and should be OK most of the time. */
- /* compute a new htilda */
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (o->_M > 16);
- BLI_task_parallel_range(0, o->_M, &osd, ocean_compute_htilda, &settings);
+ /* compute a new htilda */
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (o->_M > 16);
+ BLI_task_parallel_range(0, o->_M, &osd, ocean_compute_htilda, &settings);
- if (o->_do_disp_y) {
- BLI_task_pool_push(pool, ocean_compute_displacement_y, NULL, false, TASK_PRIORITY_HIGH);
- }
+ if (o->_do_disp_y) {
+ BLI_task_pool_push(pool, ocean_compute_displacement_y, NULL, false, TASK_PRIORITY_HIGH);
+ }
- if (o->_do_chop) {
- BLI_task_pool_push(pool, ocean_compute_displacement_x, NULL, false, TASK_PRIORITY_HIGH);
- BLI_task_pool_push(pool, ocean_compute_displacement_z, NULL, false, TASK_PRIORITY_HIGH);
- }
+ if (o->_do_chop) {
+ BLI_task_pool_push(pool, ocean_compute_displacement_x, NULL, false, TASK_PRIORITY_HIGH);
+ BLI_task_pool_push(pool, ocean_compute_displacement_z, NULL, false, TASK_PRIORITY_HIGH);
+ }
- if (o->_do_jacobian) {
- BLI_task_pool_push(pool, ocean_compute_jacobian_jxx, NULL, false, TASK_PRIORITY_HIGH);
- BLI_task_pool_push(pool, ocean_compute_jacobian_jzz, NULL, false, TASK_PRIORITY_HIGH);
- BLI_task_pool_push(pool, ocean_compute_jacobian_jxz, NULL, false, TASK_PRIORITY_HIGH);
- }
+ if (o->_do_jacobian) {
+ BLI_task_pool_push(pool, ocean_compute_jacobian_jxx, NULL, false, TASK_PRIORITY_HIGH);
+ BLI_task_pool_push(pool, ocean_compute_jacobian_jzz, NULL, false, TASK_PRIORITY_HIGH);
+ BLI_task_pool_push(pool, ocean_compute_jacobian_jxz, NULL, false, TASK_PRIORITY_HIGH);
+ }
- if (o->_do_normals) {
- BLI_task_pool_push(pool, ocean_compute_normal_x, NULL, false, TASK_PRIORITY_HIGH);
- BLI_task_pool_push(pool, ocean_compute_normal_z, NULL, false, TASK_PRIORITY_HIGH);
- o->_N_y = 1.0f / scale;
- }
+ if (o->_do_normals) {
+ BLI_task_pool_push(pool, ocean_compute_normal_x, NULL, false, TASK_PRIORITY_HIGH);
+ BLI_task_pool_push(pool, ocean_compute_normal_z, NULL, false, TASK_PRIORITY_HIGH);
+ o->_N_y = 1.0f / scale;
+ }
- BLI_task_pool_work_and_wait(pool);
+ BLI_task_pool_work_and_wait(pool);
- BLI_rw_mutex_unlock(&o->oceanmutex);
+ BLI_rw_mutex_unlock(&o->oceanmutex);
- BLI_task_pool_free(pool);
+ BLI_task_pool_free(pool);
}
static void set_height_normalize_factor(struct Ocean *oc)
{
- float res = 1.0;
- float max_h = 0.0;
+ float res = 1.0;
+ float max_h = 0.0;
- int i, j;
+ int i, j;
- if (!oc->_do_disp_y) return;
+ if (!oc->_do_disp_y)
+ return;
- oc->normalize_factor = 1.0;
+ oc->normalize_factor = 1.0;
- BKE_ocean_simulate(oc, 0.0, 1.0, 0);
+ BKE_ocean_simulate(oc, 0.0, 1.0, 0);
- BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_READ);
+ BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_READ);
- for (i = 0; i < oc->_M; ++i) {
- for (j = 0; j < oc->_N; ++j) {
- if (max_h < fabs(oc->_disp_y[i * oc->_N + j])) {
- max_h = fabs(oc->_disp_y[i * oc->_N + j]);
- }
- }
- }
+ for (i = 0; i < oc->_M; ++i) {
+ for (j = 0; j < oc->_N; ++j) {
+ if (max_h < fabs(oc->_disp_y[i * oc->_N + j])) {
+ max_h = fabs(oc->_disp_y[i * oc->_N + j]);
+ }
+ }
+ }
- BLI_rw_mutex_unlock(&oc->oceanmutex);
+ BLI_rw_mutex_unlock(&oc->oceanmutex);
- if (max_h == 0.0f)
- max_h = 0.00001f; /* just in case ... */
+ if (max_h == 0.0f)
+ max_h = 0.00001f; /* just in case ... */
- res = 1.0f / (max_h);
+ res = 1.0f / (max_h);
- oc->normalize_factor = res;
+ oc->normalize_factor = res;
}
struct Ocean *BKE_ocean_add(void)
{
- Ocean *oc = MEM_callocN(sizeof(Ocean), "ocean sim data");
+ Ocean *oc = MEM_callocN(sizeof(Ocean), "ocean sim data");
- BLI_rw_mutex_init(&oc->oceanmutex);
+ BLI_rw_mutex_init(&oc->oceanmutex);
- return oc;
+ return oc;
}
bool BKE_ocean_ensure(struct OceanModifierData *omd)
{
- if (omd->ocean) {
- return false;
- }
+ if (omd->ocean) {
+ return false;
+ }
- omd->ocean = BKE_ocean_add();
- BKE_ocean_init_from_modifier(omd->ocean, omd);
- return true;
+ omd->ocean = BKE_ocean_add();
+ BKE_ocean_init_from_modifier(omd->ocean, omd);
+ return true;
}
void BKE_ocean_init_from_modifier(struct Ocean *ocean, struct OceanModifierData const *omd)
{
- short do_heightfield, do_chop, do_normals, do_jacobian;
-
- do_heightfield = true;
- do_chop = (omd->chop_amount > 0);
- do_normals = (omd->flag & MOD_OCEAN_GENERATE_NORMALS);
- do_jacobian = (omd->flag & MOD_OCEAN_GENERATE_FOAM);
-
- BKE_ocean_free_data(ocean);
- BKE_ocean_init(ocean, omd->resolution * omd->resolution, omd->resolution * omd->resolution,
- omd->spatial_size, omd->spatial_size,
- omd->wind_velocity, omd->smallest_wave, 1.0, omd->wave_direction, omd->damp, omd->wave_alignment,
- omd->depth, omd->time,
- do_heightfield, do_chop, do_normals, do_jacobian,
- omd->seed);
-}
-
-void BKE_ocean_init(struct Ocean *o, int M, int N, float Lx, float Lz, float V, float l, float A, float w, float damp,
- float alignment, float depth, float time, short do_height_field, short do_chop, short do_normals,
- short do_jacobian, int seed)
-{
- RNG *rng;
- int i, j, ii;
-
- BLI_rw_mutex_lock(&o->oceanmutex, THREAD_LOCK_WRITE);
-
- o->_M = M;
- o->_N = N;
- o->_V = V;
- o->_l = l;
- o->_A = A;
- o->_w = w;
- o->_damp_reflections = 1.0f - damp;
- o->_wind_alignment = alignment;
- o->_depth = depth;
- o->_Lx = Lx;
- o->_Lz = Lz;
- o->_wx = cos(w);
- o->_wz = -sin(w); /* wave direction */
- o->_L = V * V / GRAVITY; /* largest wave for a given velocity V */
- o->time = time;
-
- o->_do_disp_y = do_height_field;
- o->_do_normals = do_normals;
- o->_do_chop = do_chop;
- o->_do_jacobian = do_jacobian;
-
- o->_k = (float *) MEM_mallocN(M * (1 + N / 2) * sizeof(float), "ocean_k");
- o->_h0 = (fftw_complex *) MEM_mallocN(M * N * sizeof(fftw_complex), "ocean_h0");
- o->_h0_minus = (fftw_complex *) MEM_mallocN(M * N * sizeof(fftw_complex), "ocean_h0_minus");
- o->_kx = (float *) MEM_mallocN(o->_M * sizeof(float), "ocean_kx");
- o->_kz = (float *) MEM_mallocN(o->_N * sizeof(float), "ocean_kz");
-
- /* make this robust in the face of erroneous usage */
- if (o->_Lx == 0.0f)
- o->_Lx = 0.001f;
-
- if (o->_Lz == 0.0f)
- o->_Lz = 0.001f;
-
- /* the +ve components and DC */
- for (i = 0; i <= o->_M / 2; ++i)
- o->_kx[i] = 2.0f * (float)M_PI * i / o->_Lx;
-
- /* the -ve components */
- for (i = o->_M - 1, ii = 0; i > o->_M / 2; --i, ++ii)
- o->_kx[i] = -2.0f * (float)M_PI * ii / o->_Lx;
-
- /* the +ve components and DC */
- for (i = 0; i <= o->_N / 2; ++i)
- o->_kz[i] = 2.0f * (float)M_PI * i / o->_Lz;
-
- /* the -ve components */
- for (i = o->_N - 1, ii = 0; i > o->_N / 2; --i, ++ii)
- o->_kz[i] = -2.0f * (float)M_PI * ii / o->_Lz;
-
- /* pre-calculate the k matrix */
- for (i = 0; i < o->_M; ++i)
- for (j = 0; j <= o->_N / 2; ++j)
- o->_k[i * (1 + o->_N / 2) + j] = sqrt(o->_kx[i] * o->_kx[i] + o->_kz[j] * o->_kz[j]);
-
- /*srand(seed);*/
- rng = BLI_rng_new(seed);
-
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j < o->_N; ++j) {
- float r1 = gaussRand(rng);
- float r2 = gaussRand(rng);
-
- fftw_complex r1r2;
- init_complex(r1r2, r1, r2);
- mul_complex_f(o->_h0[i * o->_N + j], r1r2, (float)(sqrt(Ph(o, o->_kx[i], o->_kz[j]) / 2.0f)));
- mul_complex_f(o->_h0_minus[i * o->_N + j], r1r2, (float)(sqrt(Ph(o, -o->_kx[i], -o->_kz[j]) / 2.0f)));
- }
- }
-
- o->_fft_in = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_fft_in");
- o->_htilda = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_htilda");
-
- BLI_thread_lock(LOCK_FFTW);
-
- if (o->_do_disp_y) {
- o->_disp_y = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_disp_y");
- o->_disp_y_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in, o->_disp_y, FFTW_ESTIMATE);
- }
-
- if (o->_do_normals) {
- o->_fft_in_nx = (fftw_complex *) MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_fft_in_nx");
- o->_fft_in_nz = (fftw_complex *) MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_fft_in_nz");
-
- o->_N_x = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_N_x");
- /* o->_N_y = (float *) fftwf_malloc(o->_M * o->_N * sizeof(float)); (MEM01) */
- o->_N_z = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_N_z");
-
- o->_N_x_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_nx, o->_N_x, FFTW_ESTIMATE);
- o->_N_z_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_nz, o->_N_z, FFTW_ESTIMATE);
- }
-
- if (o->_do_chop) {
- o->_fft_in_x = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_fft_in_x");
- o->_fft_in_z = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_fft_in_z");
-
- o->_disp_x = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_disp_x");
- o->_disp_z = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_disp_z");
-
- o->_disp_x_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_x, o->_disp_x, FFTW_ESTIMATE);
- o->_disp_z_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_z, o->_disp_z, FFTW_ESTIMATE);
- }
- if (o->_do_jacobian) {
- o->_fft_in_jxx = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex),
- "ocean_fft_in_jxx");
- o->_fft_in_jzz = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex),
- "ocean_fft_in_jzz");
- o->_fft_in_jxz = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex),
- "ocean_fft_in_jxz");
-
- o->_Jxx = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_Jxx");
- o->_Jzz = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_Jzz");
- o->_Jxz = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_Jxz");
-
- o->_Jxx_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_jxx, o->_Jxx, FFTW_ESTIMATE);
- o->_Jzz_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_jzz, o->_Jzz, FFTW_ESTIMATE);
- o->_Jxz_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_jxz, o->_Jxz, FFTW_ESTIMATE);
- }
-
- BLI_thread_unlock(LOCK_FFTW);
+ short do_heightfield, do_chop, do_normals, do_jacobian;
+
+ do_heightfield = true;
+ do_chop = (omd->chop_amount > 0);
+ do_normals = (omd->flag & MOD_OCEAN_GENERATE_NORMALS);
+ do_jacobian = (omd->flag & MOD_OCEAN_GENERATE_FOAM);
+
+ BKE_ocean_free_data(ocean);
+ BKE_ocean_init(ocean,
+ omd->resolution * omd->resolution,
+ omd->resolution * omd->resolution,
+ omd->spatial_size,
+ omd->spatial_size,
+ omd->wind_velocity,
+ omd->smallest_wave,
+ 1.0,
+ omd->wave_direction,
+ omd->damp,
+ omd->wave_alignment,
+ omd->depth,
+ omd->time,
+ do_heightfield,
+ do_chop,
+ do_normals,
+ do_jacobian,
+ omd->seed);
+}
+
+void BKE_ocean_init(struct Ocean *o,
+ int M,
+ int N,
+ float Lx,
+ float Lz,
+ float V,
+ float l,
+ float A,
+ float w,
+ float damp,
+ float alignment,
+ float depth,
+ float time,
+ short do_height_field,
+ short do_chop,
+ short do_normals,
+ short do_jacobian,
+ int seed)
+{
+ RNG *rng;
+ int i, j, ii;
+
+ BLI_rw_mutex_lock(&o->oceanmutex, THREAD_LOCK_WRITE);
+
+ o->_M = M;
+ o->_N = N;
+ o->_V = V;
+ o->_l = l;
+ o->_A = A;
+ o->_w = w;
+ o->_damp_reflections = 1.0f - damp;
+ o->_wind_alignment = alignment;
+ o->_depth = depth;
+ o->_Lx = Lx;
+ o->_Lz = Lz;
+ o->_wx = cos(w);
+ o->_wz = -sin(w); /* wave direction */
+ o->_L = V * V / GRAVITY; /* largest wave for a given velocity V */
+ o->time = time;
+
+ o->_do_disp_y = do_height_field;
+ o->_do_normals = do_normals;
+ o->_do_chop = do_chop;
+ o->_do_jacobian = do_jacobian;
+
+ o->_k = (float *)MEM_mallocN(M * (1 + N / 2) * sizeof(float), "ocean_k");
+ o->_h0 = (fftw_complex *)MEM_mallocN(M * N * sizeof(fftw_complex), "ocean_h0");
+ o->_h0_minus = (fftw_complex *)MEM_mallocN(M * N * sizeof(fftw_complex), "ocean_h0_minus");
+ o->_kx = (float *)MEM_mallocN(o->_M * sizeof(float), "ocean_kx");
+ o->_kz = (float *)MEM_mallocN(o->_N * sizeof(float), "ocean_kz");
+
+ /* make this robust in the face of erroneous usage */
+ if (o->_Lx == 0.0f)
+ o->_Lx = 0.001f;
+
+ if (o->_Lz == 0.0f)
+ o->_Lz = 0.001f;
+
+ /* the +ve components and DC */
+ for (i = 0; i <= o->_M / 2; ++i)
+ o->_kx[i] = 2.0f * (float)M_PI * i / o->_Lx;
+
+ /* the -ve components */
+ for (i = o->_M - 1, ii = 0; i > o->_M / 2; --i, ++ii)
+ o->_kx[i] = -2.0f * (float)M_PI * ii / o->_Lx;
+
+ /* the +ve components and DC */
+ for (i = 0; i <= o->_N / 2; ++i)
+ o->_kz[i] = 2.0f * (float)M_PI * i / o->_Lz;
+
+ /* the -ve components */
+ for (i = o->_N - 1, ii = 0; i > o->_N / 2; --i, ++ii)
+ o->_kz[i] = -2.0f * (float)M_PI * ii / o->_Lz;
+
+ /* pre-calculate the k matrix */
+ for (i = 0; i < o->_M; ++i)
+ for (j = 0; j <= o->_N / 2; ++j)
+ o->_k[i * (1 + o->_N / 2) + j] = sqrt(o->_kx[i] * o->_kx[i] + o->_kz[j] * o->_kz[j]);
+
+ /*srand(seed);*/
+ rng = BLI_rng_new(seed);
+
+ for (i = 0; i < o->_M; ++i) {
+ for (j = 0; j < o->_N; ++j) {
+ float r1 = gaussRand(rng);
+ float r2 = gaussRand(rng);
+
+ fftw_complex r1r2;
+ init_complex(r1r2, r1, r2);
+ mul_complex_f(
+ o->_h0[i * o->_N + j], r1r2, (float)(sqrt(Ph(o, o->_kx[i], o->_kz[j]) / 2.0f)));
+ mul_complex_f(
+ o->_h0_minus[i * o->_N + j], r1r2, (float)(sqrt(Ph(o, -o->_kx[i], -o->_kz[j]) / 2.0f)));
+ }
+ }
+
+ o->_fft_in = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex),
+ "ocean_fft_in");
+ o->_htilda = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex),
+ "ocean_htilda");
+
+ BLI_thread_lock(LOCK_FFTW);
+
+ if (o->_do_disp_y) {
+ o->_disp_y = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_disp_y");
+ o->_disp_y_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in, o->_disp_y, FFTW_ESTIMATE);
+ }
+
+ if (o->_do_normals) {
+ o->_fft_in_nx = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex),
+ "ocean_fft_in_nx");
+ o->_fft_in_nz = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex),
+ "ocean_fft_in_nz");
+
+ o->_N_x = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_N_x");
+ /* o->_N_y = (float *) fftwf_malloc(o->_M * o->_N * sizeof(float)); (MEM01) */
+ o->_N_z = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_N_z");
+
+ o->_N_x_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_nx, o->_N_x, FFTW_ESTIMATE);
+ o->_N_z_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_nz, o->_N_z, FFTW_ESTIMATE);
+ }
+
+ if (o->_do_chop) {
+ o->_fft_in_x = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex),
+ "ocean_fft_in_x");
+ o->_fft_in_z = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex),
+ "ocean_fft_in_z");
+
+ o->_disp_x = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_disp_x");
+ o->_disp_z = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_disp_z");
+
+ o->_disp_x_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_x, o->_disp_x, FFTW_ESTIMATE);
+ o->_disp_z_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_z, o->_disp_z, FFTW_ESTIMATE);
+ }
+ if (o->_do_jacobian) {
+ o->_fft_in_jxx = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex),
+ "ocean_fft_in_jxx");
+ o->_fft_in_jzz = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex),
+ "ocean_fft_in_jzz");
+ o->_fft_in_jxz = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex),
+ "ocean_fft_in_jxz");
+
+ o->_Jxx = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_Jxx");
+ o->_Jzz = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_Jzz");
+ o->_Jxz = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_Jxz");
+
+ o->_Jxx_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_jxx, o->_Jxx, FFTW_ESTIMATE);
+ o->_Jzz_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_jzz, o->_Jzz, FFTW_ESTIMATE);
+ o->_Jxz_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_jxz, o->_Jxz, FFTW_ESTIMATE);
+ }
- BLI_rw_mutex_unlock(&o->oceanmutex);
+ BLI_thread_unlock(LOCK_FFTW);
+
+ BLI_rw_mutex_unlock(&o->oceanmutex);
- set_height_normalize_factor(o);
-
- BLI_rng_free(rng);
+ set_height_normalize_factor(o);
+
+ BLI_rng_free(rng);
}
void BKE_ocean_free_data(struct Ocean *oc)
{
- if (!oc) return;
-
- BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_WRITE);
-
- BLI_thread_lock(LOCK_FFTW);
-
- if (oc->_do_disp_y) {
- fftw_destroy_plan(oc->_disp_y_plan);
- MEM_freeN(oc->_disp_y);
- }
-
- if (oc->_do_normals) {
- MEM_freeN(oc->_fft_in_nx);
- MEM_freeN(oc->_fft_in_nz);
- fftw_destroy_plan(oc->_N_x_plan);
- fftw_destroy_plan(oc->_N_z_plan);
- MEM_freeN(oc->_N_x);
- /*fftwf_free(oc->_N_y); (MEM01)*/
- MEM_freeN(oc->_N_z);
- }
-
- if (oc->_do_chop) {
- MEM_freeN(oc->_fft_in_x);
- MEM_freeN(oc->_fft_in_z);
- fftw_destroy_plan(oc->_disp_x_plan);
- fftw_destroy_plan(oc->_disp_z_plan);
- MEM_freeN(oc->_disp_x);
- MEM_freeN(oc->_disp_z);
- }
-
- if (oc->_do_jacobian) {
- MEM_freeN(oc->_fft_in_jxx);
- MEM_freeN(oc->_fft_in_jzz);
- MEM_freeN(oc->_fft_in_jxz);
- fftw_destroy_plan(oc->_Jxx_plan);
- fftw_destroy_plan(oc->_Jzz_plan);
- fftw_destroy_plan(oc->_Jxz_plan);
- MEM_freeN(oc->_Jxx);
- MEM_freeN(oc->_Jzz);
- MEM_freeN(oc->_Jxz);
- }
-
- BLI_thread_unlock(LOCK_FFTW);
-
- if (oc->_fft_in)
- MEM_freeN(oc->_fft_in);
-
- /* check that ocean data has been initialized */
- if (oc->_htilda) {
- MEM_freeN(oc->_htilda);
- MEM_freeN(oc->_k);
- MEM_freeN(oc->_h0);
- MEM_freeN(oc->_h0_minus);
- MEM_freeN(oc->_kx);
- MEM_freeN(oc->_kz);
- }
-
- BLI_rw_mutex_unlock(&oc->oceanmutex);
+ if (!oc)
+ return;
+
+ BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_WRITE);
+
+ BLI_thread_lock(LOCK_FFTW);
+
+ if (oc->_do_disp_y) {
+ fftw_destroy_plan(oc->_disp_y_plan);
+ MEM_freeN(oc->_disp_y);
+ }
+
+ if (oc->_do_normals) {
+ MEM_freeN(oc->_fft_in_nx);
+ MEM_freeN(oc->_fft_in_nz);
+ fftw_destroy_plan(oc->_N_x_plan);
+ fftw_destroy_plan(oc->_N_z_plan);
+ MEM_freeN(oc->_N_x);
+ /*fftwf_free(oc->_N_y); (MEM01)*/
+ MEM_freeN(oc->_N_z);
+ }
+
+ if (oc->_do_chop) {
+ MEM_freeN(oc->_fft_in_x);
+ MEM_freeN(oc->_fft_in_z);
+ fftw_destroy_plan(oc->_disp_x_plan);
+ fftw_destroy_plan(oc->_disp_z_plan);
+ MEM_freeN(oc->_disp_x);
+ MEM_freeN(oc->_disp_z);
+ }
+
+ if (oc->_do_jacobian) {
+ MEM_freeN(oc->_fft_in_jxx);
+ MEM_freeN(oc->_fft_in_jzz);
+ MEM_freeN(oc->_fft_in_jxz);
+ fftw_destroy_plan(oc->_Jxx_plan);
+ fftw_destroy_plan(oc->_Jzz_plan);
+ fftw_destroy_plan(oc->_Jxz_plan);
+ MEM_freeN(oc->_Jxx);
+ MEM_freeN(oc->_Jzz);
+ MEM_freeN(oc->_Jxz);
+ }
+
+ BLI_thread_unlock(LOCK_FFTW);
+
+ if (oc->_fft_in)
+ MEM_freeN(oc->_fft_in);
+
+ /* check that ocean data has been initialized */
+ if (oc->_htilda) {
+ MEM_freeN(oc->_htilda);
+ MEM_freeN(oc->_k);
+ MEM_freeN(oc->_h0);
+ MEM_freeN(oc->_h0_minus);
+ MEM_freeN(oc->_kx);
+ MEM_freeN(oc->_kz);
+ }
+
+ BLI_rw_mutex_unlock(&oc->oceanmutex);
}
void BKE_ocean_free(struct Ocean *oc)
{
- if (!oc) return;
+ if (!oc)
+ return;
- BKE_ocean_free_data(oc);
- BLI_rw_mutex_end(&oc->oceanmutex);
+ BKE_ocean_free_data(oc);
+ BLI_rw_mutex_end(&oc->oceanmutex);
- MEM_freeN(oc);
+ MEM_freeN(oc);
}
-#undef GRAVITY
-
+# undef GRAVITY
/* ********* Baking/Caching ********* */
+# define CACHE_TYPE_DISPLACE 1
+# define CACHE_TYPE_FOAM 2
+# define CACHE_TYPE_NORMAL 3
-#define CACHE_TYPE_DISPLACE 1
-#define CACHE_TYPE_FOAM 2
-#define CACHE_TYPE_NORMAL 3
-
-static void cache_filename(char *string, const char *path, const char *relbase, int frame, int type)
+static void cache_filename(
+ char *string, const char *path, const char *relbase, int frame, int type)
{
- char cachepath[FILE_MAX];
- const char *fname;
+ char cachepath[FILE_MAX];
+ const char *fname;
- switch (type) {
- case CACHE_TYPE_FOAM:
- fname = "foam_";
- break;
- case CACHE_TYPE_NORMAL:
- fname = "normal_";
- break;
- case CACHE_TYPE_DISPLACE:
- default:
- fname = "disp_";
- break;
- }
+ switch (type) {
+ case CACHE_TYPE_FOAM:
+ fname = "foam_";
+ break;
+ case CACHE_TYPE_NORMAL:
+ fname = "normal_";
+ break;
+ case CACHE_TYPE_DISPLACE:
+ default:
+ fname = "disp_";
+ break;
+ }
- BLI_join_dirfile(cachepath, sizeof(cachepath), path, fname);
+ BLI_join_dirfile(cachepath, sizeof(cachepath), path, fname);
- BKE_image_path_from_imtype(string, cachepath, relbase, frame, R_IMF_IMTYPE_OPENEXR, true, true, "");
+ BKE_image_path_from_imtype(
+ string, cachepath, relbase, frame, R_IMF_IMTYPE_OPENEXR, true, true, "");
}
/* silly functions but useful to inline when the args do a lot of indirections */
MINLINE void rgb_to_rgba_unit_alpha(float r_rgba[4], const float rgb[3])
{
- r_rgba[0] = rgb[0];
- r_rgba[1] = rgb[1];
- r_rgba[2] = rgb[2];
- r_rgba[3] = 1.0f;
+ r_rgba[0] = rgb[0];
+ r_rgba[1] = rgb[1];
+ r_rgba[2] = rgb[2];
+ r_rgba[3] = 1.0f;
}
MINLINE void value_to_rgba_unit_alpha(float r_rgba[4], const float value)
{
- r_rgba[0] = value;
- r_rgba[1] = value;
- r_rgba[2] = value;
- r_rgba[3] = 1.0f;
+ r_rgba[0] = value;
+ r_rgba[1] = value;
+ r_rgba[2] = value;
+ r_rgba[3] = 1.0f;
}
void BKE_ocean_free_cache(struct OceanCache *och)
{
- int i, f = 0;
-
- if (!och) return;
-
- if (och->ibufs_disp) {
- for (i = och->start, f = 0; i <= och->end; i++, f++) {
- if (och->ibufs_disp[f]) {
- IMB_freeImBuf(och->ibufs_disp[f]);
- }
- }
- MEM_freeN(och->ibufs_disp);
- }
-
- if (och->ibufs_foam) {
- for (i = och->start, f = 0; i <= och->end; i++, f++) {
- if (och->ibufs_foam[f]) {
- IMB_freeImBuf(och->ibufs_foam[f]);
- }
- }
- MEM_freeN(och->ibufs_foam);
- }
-
- if (och->ibufs_norm) {
- for (i = och->start, f = 0; i <= och->end; i++, f++) {
- if (och->ibufs_norm[f]) {
- IMB_freeImBuf(och->ibufs_norm[f]);
- }
- }
- MEM_freeN(och->ibufs_norm);
- }
-
- if (och->time)
- MEM_freeN(och->time);
- MEM_freeN(och);
-}
-
-void BKE_ocean_cache_eval_uv(struct OceanCache *och, struct OceanResult *ocr, int f, float u, float v)
-{
- int res_x = och->resolution_x;
- int res_y = och->resolution_y;
- float result[4];
-
- u = fmod(u, 1.0);
- v = fmod(v, 1.0);
-
- if (u < 0) u += 1.0f;
- if (v < 0) v += 1.0f;
-
- if (och->ibufs_disp[f]) {
- ibuf_sample(och->ibufs_disp[f], u, v, (1.0f / (float)res_x), (1.0f / (float)res_y), result);
- copy_v3_v3(ocr->disp, result);
- }
-
- if (och->ibufs_foam[f]) {
- ibuf_sample(och->ibufs_foam[f], u, v, (1.0f / (float)res_x), (1.0f / (float)res_y), result);
- ocr->foam = result[0];
- }
-
- if (och->ibufs_norm[f]) {
- ibuf_sample(och->ibufs_norm[f], u, v, (1.0f / (float)res_x), (1.0f / (float)res_y), result);
- copy_v3_v3(ocr->normal, result);
- }
+ int i, f = 0;
+
+ if (!och)
+ return;
+
+ if (och->ibufs_disp) {
+ for (i = och->start, f = 0; i <= och->end; i++, f++) {
+ if (och->ibufs_disp[f]) {
+ IMB_freeImBuf(och->ibufs_disp[f]);
+ }
+ }
+ MEM_freeN(och->ibufs_disp);
+ }
+
+ if (och->ibufs_foam) {
+ for (i = och->start, f = 0; i <= och->end; i++, f++) {
+ if (och->ibufs_foam[f]) {
+ IMB_freeImBuf(och->ibufs_foam[f]);
+ }
+ }
+ MEM_freeN(och->ibufs_foam);
+ }
+
+ if (och->ibufs_norm) {
+ for (i = och->start, f = 0; i <= och->end; i++, f++) {
+ if (och->ibufs_norm[f]) {
+ IMB_freeImBuf(och->ibufs_norm[f]);
+ }
+ }
+ MEM_freeN(och->ibufs_norm);
+ }
+
+ if (och->time)
+ MEM_freeN(och->time);
+ MEM_freeN(och);
+}
+
+void BKE_ocean_cache_eval_uv(
+ struct OceanCache *och, struct OceanResult *ocr, int f, float u, float v)
+{
+ int res_x = och->resolution_x;
+ int res_y = och->resolution_y;
+ float result[4];
+
+ u = fmod(u, 1.0);
+ v = fmod(v, 1.0);
+
+ if (u < 0)
+ u += 1.0f;
+ if (v < 0)
+ v += 1.0f;
+
+ if (och->ibufs_disp[f]) {
+ ibuf_sample(och->ibufs_disp[f], u, v, (1.0f / (float)res_x), (1.0f / (float)res_y), result);
+ copy_v3_v3(ocr->disp, result);
+ }
+
+ if (och->ibufs_foam[f]) {
+ ibuf_sample(och->ibufs_foam[f], u, v, (1.0f / (float)res_x), (1.0f / (float)res_y), result);
+ ocr->foam = result[0];
+ }
+
+ if (och->ibufs_norm[f]) {
+ ibuf_sample(och->ibufs_norm[f], u, v, (1.0f / (float)res_x), (1.0f / (float)res_y), result);
+ copy_v3_v3(ocr->normal, result);
+ }
}
void BKE_ocean_cache_eval_ij(struct OceanCache *och, struct OceanResult *ocr, int f, int i, int j)
{
- const int res_x = och->resolution_x;
- const int res_y = och->resolution_y;
+ const int res_x = och->resolution_x;
+ const int res_y = och->resolution_y;
- if (i < 0) i = -i;
- if (j < 0) j = -j;
+ if (i < 0)
+ i = -i;
+ if (j < 0)
+ j = -j;
- i = i % res_x;
- j = j % res_y;
+ i = i % res_x;
+ j = j % res_y;
- if (och->ibufs_disp[f]) {
- copy_v3_v3(ocr->disp, &och->ibufs_disp[f]->rect_float[4 * (res_x * j + i)]);
- }
+ if (och->ibufs_disp[f]) {
+ copy_v3_v3(ocr->disp, &och->ibufs_disp[f]->rect_float[4 * (res_x * j + i)]);
+ }
- if (och->ibufs_foam[f]) {
- ocr->foam = och->ibufs_foam[f]->rect_float[4 * (res_x * j + i)];
- }
+ if (och->ibufs_foam[f]) {
+ ocr->foam = och->ibufs_foam[f]->rect_float[4 * (res_x * j + i)];
+ }
- if (och->ibufs_norm[f]) {
- copy_v3_v3(ocr->normal, &och->ibufs_norm[f]->rect_float[4 * (res_x * j + i)]);
- }
+ if (och->ibufs_norm[f]) {
+ copy_v3_v3(ocr->normal, &och->ibufs_norm[f]->rect_float[4 * (res_x * j + i)]);
+ }
}
-struct OceanCache *BKE_ocean_init_cache(const char *bakepath, const char *relbase, int start, int end, float wave_scale,
- float chop_amount, float foam_coverage, float foam_fade, int resolution)
+struct OceanCache *BKE_ocean_init_cache(const char *bakepath,
+ const char *relbase,
+ int start,
+ int end,
+ float wave_scale,
+ float chop_amount,
+ float foam_coverage,
+ float foam_fade,
+ int resolution)
{
- OceanCache *och = MEM_callocN(sizeof(OceanCache), "ocean cache data");
+ OceanCache *och = MEM_callocN(sizeof(OceanCache), "ocean cache data");
- och->bakepath = bakepath;
- och->relbase = relbase;
+ och->bakepath = bakepath;
+ och->relbase = relbase;
- och->start = start;
- och->end = end;
- och->duration = (end - start) + 1;
- och->wave_scale = wave_scale;
- och->chop_amount = chop_amount;
- och->foam_coverage = foam_coverage;
- och->foam_fade = foam_fade;
- och->resolution_x = resolution * resolution;
- och->resolution_y = resolution * resolution;
+ och->start = start;
+ och->end = end;
+ och->duration = (end - start) + 1;
+ och->wave_scale = wave_scale;
+ och->chop_amount = chop_amount;
+ och->foam_coverage = foam_coverage;
+ och->foam_fade = foam_fade;
+ och->resolution_x = resolution * resolution;
+ och->resolution_y = resolution * resolution;
- och->ibufs_disp = MEM_callocN(sizeof(ImBuf *) * och->duration, "displacement imbuf pointer array");
- och->ibufs_foam = MEM_callocN(sizeof(ImBuf *) * och->duration, "foam imbuf pointer array");
- och->ibufs_norm = MEM_callocN(sizeof(ImBuf *) * och->duration, "normal imbuf pointer array");
+ och->ibufs_disp = MEM_callocN(sizeof(ImBuf *) * och->duration,
+ "displacement imbuf pointer array");
+ och->ibufs_foam = MEM_callocN(sizeof(ImBuf *) * och->duration, "foam imbuf pointer array");
+ och->ibufs_norm = MEM_callocN(sizeof(ImBuf *) * och->duration, "normal imbuf pointer array");
- och->time = NULL;
+ och->time = NULL;
- return och;
+ return och;
}
void BKE_ocean_simulate_cache(struct OceanCache *och, int frame)
{
- char string[FILE_MAX];
- int f = frame;
+ char string[FILE_MAX];
+ int f = frame;
- /* ibufs array is zero based, but filenames are based on frame numbers */
- /* still need to clamp frame numbers to valid range of images on disk though */
- CLAMP(frame, och->start, och->end);
- f = frame - och->start; /* shift to 0 based */
+ /* ibufs array is zero based, but filenames are based on frame numbers */
+ /* still need to clamp frame numbers to valid range of images on disk though */
+ CLAMP(frame, och->start, och->end);
+ f = frame - och->start; /* shift to 0 based */
- /* if image is already loaded in mem, return */
- if (och->ibufs_disp[f] != NULL) return;
+ /* if image is already loaded in mem, return */
+ if (och->ibufs_disp[f] != NULL)
+ return;
- /* use default color spaces since we know for sure cache files were saved with default settings too */
+ /* use default color spaces since we know for sure cache files were saved with default settings too */
- cache_filename(string, och->bakepath, och->relbase, frame, CACHE_TYPE_DISPLACE);
- och->ibufs_disp[f] = IMB_loadiffname(string, 0, NULL);
+ cache_filename(string, och->bakepath, och->relbase, frame, CACHE_TYPE_DISPLACE);
+ och->ibufs_disp[f] = IMB_loadiffname(string, 0, NULL);
- cache_filename(string, och->bakepath, och->relbase, frame, CACHE_TYPE_FOAM);
- och->ibufs_foam[f] = IMB_loadiffname(string, 0, NULL);
+ cache_filename(string, och->bakepath, och->relbase, frame, CACHE_TYPE_FOAM);
+ och->ibufs_foam[f] = IMB_loadiffname(string, 0, NULL);
- cache_filename(string, och->bakepath, och->relbase, frame, CACHE_TYPE_NORMAL);
- och->ibufs_norm[f] = IMB_loadiffname(string, 0, NULL);
+ cache_filename(string, och->bakepath, och->relbase, frame, CACHE_TYPE_NORMAL);
+ och->ibufs_norm[f] = IMB_loadiffname(string, 0, NULL);
}
-
-void BKE_ocean_bake(struct Ocean *o, struct OceanCache *och, void (*update_cb)(void *, float progress, int *cancel),
+void BKE_ocean_bake(struct Ocean *o,
+ struct OceanCache *och,
+ void (*update_cb)(void *, float progress, int *cancel),
void *update_cb_data)
{
- /* note: some of these values remain uninitialized unless certain options
- * are enabled, take care that BKE_ocean_eval_ij() initializes a member
- * before use - campbell */
- OceanResult ocr;
+ /* note: some of these values remain uninitialized unless certain options
+ * are enabled, take care that BKE_ocean_eval_ij() initializes a member
+ * before use - campbell */
+ OceanResult ocr;
- ImageFormatData imf = {0};
+ ImageFormatData imf = {0};
- int f, i = 0, x, y, cancel = 0;
- float progress;
+ int f, i = 0, x, y, cancel = 0;
+ float progress;
- ImBuf *ibuf_foam, *ibuf_disp, *ibuf_normal;
- float *prev_foam;
- int res_x = och->resolution_x;
- int res_y = och->resolution_y;
- char string[FILE_MAX];
- //RNG *rng;
+ ImBuf *ibuf_foam, *ibuf_disp, *ibuf_normal;
+ float *prev_foam;
+ int res_x = och->resolution_x;
+ int res_y = och->resolution_y;
+ char string[FILE_MAX];
+ //RNG *rng;
- if (!o) return;
+ if (!o)
+ return;
- if (o->_do_jacobian) prev_foam = MEM_callocN(res_x * res_y * sizeof(float), "previous frame foam bake data");
- else prev_foam = NULL;
+ if (o->_do_jacobian)
+ prev_foam = MEM_callocN(res_x * res_y * sizeof(float), "previous frame foam bake data");
+ else
+ prev_foam = NULL;
- //rng = BLI_rng_new(0);
+ //rng = BLI_rng_new(0);
- /* setup image format */
- imf.imtype = R_IMF_IMTYPE_OPENEXR;
- imf.depth = R_IMF_CHAN_DEPTH_16;
- imf.exr_codec = R_IMF_EXR_CODEC_ZIP;
+ /* setup image format */
+ imf.imtype = R_IMF_IMTYPE_OPENEXR;
+ imf.depth = R_IMF_CHAN_DEPTH_16;
+ imf.exr_codec = R_IMF_EXR_CODEC_ZIP;
- for (f = och->start, i = 0; f <= och->end; f++, i++) {
+ for (f = och->start, i = 0; f <= och->end; f++, i++) {
- /* create a new imbuf to store image for this frame */
- ibuf_foam = IMB_allocImBuf(res_x, res_y, 32, IB_rectfloat);
- ibuf_disp = IMB_allocImBuf(res_x, res_y, 32, IB_rectfloat);
- ibuf_normal = IMB_allocImBuf(res_x, res_y, 32, IB_rectfloat);
+ /* create a new imbuf to store image for this frame */
+ ibuf_foam = IMB_allocImBuf(res_x, res_y, 32, IB_rectfloat);
+ ibuf_disp = IMB_allocImBuf(res_x, res_y, 32, IB_rectfloat);
+ ibuf_normal = IMB_allocImBuf(res_x, res_y, 32, IB_rectfloat);
- BKE_ocean_simulate(o, och->time[i], och->wave_scale, och->chop_amount);
+ BKE_ocean_simulate(o, och->time[i], och->wave_scale, och->chop_amount);
- /* add new foam */
- for (y = 0; y < res_y; y++) {
- for (x = 0; x < res_x; x++) {
+ /* add new foam */
+ for (y = 0; y < res_y; y++) {
+ for (x = 0; x < res_x; x++) {
- BKE_ocean_eval_ij(o, &ocr, x, y);
+ BKE_ocean_eval_ij(o, &ocr, x, y);
- /* add to the image */
- rgb_to_rgba_unit_alpha(&ibuf_disp->rect_float[4 * (res_x * y + x)], ocr.disp);
+ /* add to the image */
+ rgb_to_rgba_unit_alpha(&ibuf_disp->rect_float[4 * (res_x * y + x)], ocr.disp);
- if (o->_do_jacobian) {
- /* TODO, cleanup unused code - campbell */
+ if (o->_do_jacobian) {
+ /* TODO, cleanup unused code - campbell */
- float /*r, */ /* UNUSED */ pr = 0.0f, foam_result;
- float neg_disp, neg_eplus;
+ float /*r, */ /* UNUSED */ pr = 0.0f, foam_result;
+ float neg_disp, neg_eplus;
- ocr.foam = BKE_ocean_jminus_to_foam(ocr.Jminus, och->foam_coverage);
+ ocr.foam = BKE_ocean_jminus_to_foam(ocr.Jminus, och->foam_coverage);
- /* accumulate previous value for this cell */
- if (i > 0) {
- pr = prev_foam[res_x * y + x];
- }
+ /* accumulate previous value for this cell */
+ if (i > 0) {
+ pr = prev_foam[res_x * y + x];
+ }
- /* r = BLI_rng_get_float(rng); */ /* UNUSED */ /* randomly reduce foam */
+ /* r = BLI_rng_get_float(rng); */ /* UNUSED */ /* randomly reduce foam */
- /* pr = pr * och->foam_fade; */ /* overall fade */
+ /* pr = pr * och->foam_fade; */ /* overall fade */
- /* remember ocean coord sys is Y up!
- * break up the foam where height (Y) is low (wave valley), and X and Z displacement is greatest
- */
+ /* remember ocean coord sys is Y up!
+ * break up the foam where height (Y) is low (wave valley), and X and Z displacement is greatest
+ */
- neg_disp = ocr.disp[1] < 0.0f ? 1.0f + ocr.disp[1] : 1.0f;
- neg_disp = neg_disp < 0.0f ? 0.0f : neg_disp;
+ neg_disp = ocr.disp[1] < 0.0f ? 1.0f + ocr.disp[1] : 1.0f;
+ neg_disp = neg_disp < 0.0f ? 0.0f : neg_disp;
- /* foam, 'ocr.Eplus' only initialized with do_jacobian */
- neg_eplus = ocr.Eplus[2] < 0.0f ? 1.0f + ocr.Eplus[2] : 1.0f;
- neg_eplus = neg_eplus < 0.0f ? 0.0f : neg_eplus;
+ /* foam, 'ocr.Eplus' only initialized with do_jacobian */
+ neg_eplus = ocr.Eplus[2] < 0.0f ? 1.0f + ocr.Eplus[2] : 1.0f;
+ neg_eplus = neg_eplus < 0.0f ? 0.0f : neg_eplus;
- if (pr < 1.0f)
- pr *= pr;
+ if (pr < 1.0f)
+ pr *= pr;
- pr *= och->foam_fade * (0.75f + neg_eplus * 0.25f);
+ pr *= och->foam_fade * (0.75f + neg_eplus * 0.25f);
- /* A full clamping should not be needed! */
- foam_result = min_ff(pr + ocr.foam, 1.0f);
+ /* A full clamping should not be needed! */
+ foam_result = min_ff(pr + ocr.foam, 1.0f);
- prev_foam[res_x * y + x] = foam_result;
+ prev_foam[res_x * y + x] = foam_result;
- /*foam_result = min_ff(foam_result, 1.0f); */
+ /*foam_result = min_ff(foam_result, 1.0f); */
- value_to_rgba_unit_alpha(&ibuf_foam->rect_float[4 * (res_x * y + x)], foam_result);
- }
+ value_to_rgba_unit_alpha(&ibuf_foam->rect_float[4 * (res_x * y + x)], foam_result);
+ }
- if (o->_do_normals) {
- rgb_to_rgba_unit_alpha(&ibuf_normal->rect_float[4 * (res_x * y + x)], ocr.normal);
- }
- }
- }
+ if (o->_do_normals) {
+ rgb_to_rgba_unit_alpha(&ibuf_normal->rect_float[4 * (res_x * y + x)], ocr.normal);
+ }
+ }
+ }
- /* write the images */
- cache_filename(string, och->bakepath, och->relbase, f, CACHE_TYPE_DISPLACE);
- if (0 == BKE_imbuf_write(ibuf_disp, string, &imf))
- printf("Cannot save Displacement File Output to %s\n", string);
+ /* write the images */
+ cache_filename(string, och->bakepath, och->relbase, f, CACHE_TYPE_DISPLACE);
+ if (0 == BKE_imbuf_write(ibuf_disp, string, &imf))
+ printf("Cannot save Displacement File Output to %s\n", string);
- if (o->_do_jacobian) {
- cache_filename(string, och->bakepath, och->relbase, f, CACHE_TYPE_FOAM);
- if (0 == BKE_imbuf_write(ibuf_foam, string, &imf))
- printf("Cannot save Foam File Output to %s\n", string);
- }
+ if (o->_do_jacobian) {
+ cache_filename(string, och->bakepath, och->relbase, f, CACHE_TYPE_FOAM);
+ if (0 == BKE_imbuf_write(ibuf_foam, string, &imf))
+ printf("Cannot save Foam File Output to %s\n", string);
+ }
- if (o->_do_normals) {
- cache_filename(string, och->bakepath, och->relbase, f, CACHE_TYPE_NORMAL);
- if (0 == BKE_imbuf_write(ibuf_normal, string, &imf))
- printf("Cannot save Normal File Output to %s\n", string);
- }
+ if (o->_do_normals) {
+ cache_filename(string, och->bakepath, och->relbase, f, CACHE_TYPE_NORMAL);
+ if (0 == BKE_imbuf_write(ibuf_normal, string, &imf))
+ printf("Cannot save Normal File Output to %s\n", string);
+ }
- IMB_freeImBuf(ibuf_disp);
- IMB_freeImBuf(ibuf_foam);
- IMB_freeImBuf(ibuf_normal);
+ IMB_freeImBuf(ibuf_disp);
+ IMB_freeImBuf(ibuf_foam);
+ IMB_freeImBuf(ibuf_normal);
- progress = (f - och->start) / (float)och->duration;
+ progress = (f - och->start) / (float)och->duration;
- update_cb(update_cb_data, progress, &cancel);
+ update_cb(update_cb_data, progress, &cancel);
- if (cancel) {
- if (prev_foam) MEM_freeN(prev_foam);
- //BLI_rng_free(rng);
- return;
- }
- }
+ if (cancel) {
+ if (prev_foam)
+ MEM_freeN(prev_foam);
+ //BLI_rng_free(rng);
+ return;
+ }
+ }
- //BLI_rng_free(rng);
- if (prev_foam) MEM_freeN(prev_foam);
- och->baked = 1;
+ //BLI_rng_free(rng);
+ if (prev_foam)
+ MEM_freeN(prev_foam);
+ och->baked = 1;
}
#else /* WITH_OCEANSIM */
/* stub */
typedef struct Ocean {
- /* need some data here, C does not allow empty struct */
- int stub;
+ /* need some data here, C does not allow empty struct */
+ int stub;
} Ocean;
-
float BKE_ocean_jminus_to_foam(float UNUSED(jminus), float UNUSED(coverage))
{
- return 0.0f;
+ return 0.0f;
}
-void BKE_ocean_eval_uv(struct Ocean *UNUSED(oc), struct OceanResult *UNUSED(ocr), float UNUSED(u), float UNUSED(v))
+void BKE_ocean_eval_uv(struct Ocean *UNUSED(oc),
+ struct OceanResult *UNUSED(ocr),
+ float UNUSED(u),
+ float UNUSED(v))
{
}
/* use catmullrom interpolation rather than linear */
-void BKE_ocean_eval_uv_catrom(struct Ocean *UNUSED(oc), struct OceanResult *UNUSED(ocr), float UNUSED(u),
+void BKE_ocean_eval_uv_catrom(struct Ocean *UNUSED(oc),
+ struct OceanResult *UNUSED(ocr),
+ float UNUSED(u),
float UNUSED(v))
{
}
-void BKE_ocean_eval_xz(struct Ocean *UNUSED(oc), struct OceanResult *UNUSED(ocr), float UNUSED(x), float UNUSED(z))
+void BKE_ocean_eval_xz(struct Ocean *UNUSED(oc),
+ struct OceanResult *UNUSED(ocr),
+ float UNUSED(x),
+ float UNUSED(z))
{
}
-void BKE_ocean_eval_xz_catrom(struct Ocean *UNUSED(oc), struct OceanResult *UNUSED(ocr), float UNUSED(x),
+void BKE_ocean_eval_xz_catrom(struct Ocean *UNUSED(oc),
+ struct OceanResult *UNUSED(ocr),
+ float UNUSED(x),
float UNUSED(z))
{
}
-void BKE_ocean_eval_ij(struct Ocean *UNUSED(oc), struct OceanResult *UNUSED(ocr), int UNUSED(i), int UNUSED(j))
+void BKE_ocean_eval_ij(struct Ocean *UNUSED(oc),
+ struct OceanResult *UNUSED(ocr),
+ int UNUSED(i),
+ int UNUSED(j))
{
}
-void BKE_ocean_simulate(struct Ocean *UNUSED(o), float UNUSED(t), float UNUSED(scale), float UNUSED(chop_amount))
+void BKE_ocean_simulate(struct Ocean *UNUSED(o),
+ float UNUSED(t),
+ float UNUSED(scale),
+ float UNUSED(chop_amount))
{
}
struct Ocean *BKE_ocean_add(void)
{
- Ocean *oc = MEM_callocN(sizeof(Ocean), "ocean sim data");
+ Ocean *oc = MEM_callocN(sizeof(Ocean), "ocean sim data");
- return oc;
+ return oc;
}
-void BKE_ocean_init(struct Ocean *UNUSED(o), int UNUSED(M), int UNUSED(N), float UNUSED(Lx), float UNUSED(Lz),
- float UNUSED(V), float UNUSED(l), float UNUSED(A), float UNUSED(w), float UNUSED(damp),
- float UNUSED(alignment), float UNUSED(depth), float UNUSED(time), short UNUSED(do_height_field),
- short UNUSED(do_chop), short UNUSED(do_normals), short UNUSED(do_jacobian), int UNUSED(seed))
+void BKE_ocean_init(struct Ocean *UNUSED(o),
+ int UNUSED(M),
+ int UNUSED(N),
+ float UNUSED(Lx),
+ float UNUSED(Lz),
+ float UNUSED(V),
+ float UNUSED(l),
+ float UNUSED(A),
+ float UNUSED(w),
+ float UNUSED(damp),
+ float UNUSED(alignment),
+ float UNUSED(depth),
+ float UNUSED(time),
+ short UNUSED(do_height_field),
+ short UNUSED(do_chop),
+ short UNUSED(do_normals),
+ short UNUSED(do_jacobian),
+ int UNUSED(seed))
{
}
@@ -1441,52 +1563,67 @@ void BKE_ocean_free_data(struct Ocean *UNUSED(oc))
void BKE_ocean_free(struct Ocean *oc)
{
- if (!oc) return;
- MEM_freeN(oc);
+ if (!oc)
+ return;
+ MEM_freeN(oc);
}
-
/* ********* Baking/Caching ********* */
-
void BKE_ocean_free_cache(struct OceanCache *och)
{
- if (!och) return;
+ if (!och)
+ return;
- MEM_freeN(och);
+ MEM_freeN(och);
}
-void BKE_ocean_cache_eval_uv(struct OceanCache *UNUSED(och), struct OceanResult *UNUSED(ocr), int UNUSED(f),
- float UNUSED(u), float UNUSED(v))
+void BKE_ocean_cache_eval_uv(struct OceanCache *UNUSED(och),
+ struct OceanResult *UNUSED(ocr),
+ int UNUSED(f),
+ float UNUSED(u),
+ float UNUSED(v))
{
}
-void BKE_ocean_cache_eval_ij(struct OceanCache *UNUSED(och), struct OceanResult *UNUSED(ocr), int UNUSED(f),
- int UNUSED(i), int UNUSED(j))
+void BKE_ocean_cache_eval_ij(struct OceanCache *UNUSED(och),
+ struct OceanResult *UNUSED(ocr),
+ int UNUSED(f),
+ int UNUSED(i),
+ int UNUSED(j))
{
}
-OceanCache *BKE_ocean_init_cache(const char *UNUSED(bakepath), const char *UNUSED(relbase), int UNUSED(start),
- int UNUSED(end), float UNUSED(wave_scale), float UNUSED(chop_amount),
- float UNUSED(foam_coverage), float UNUSED(foam_fade), int UNUSED(resolution))
+OceanCache *BKE_ocean_init_cache(const char *UNUSED(bakepath),
+ const char *UNUSED(relbase),
+ int UNUSED(start),
+ int UNUSED(end),
+ float UNUSED(wave_scale),
+ float UNUSED(chop_amount),
+ float UNUSED(foam_coverage),
+ float UNUSED(foam_fade),
+ int UNUSED(resolution))
{
- OceanCache *och = MEM_callocN(sizeof(OceanCache), "ocean cache data");
+ OceanCache *och = MEM_callocN(sizeof(OceanCache), "ocean cache data");
- return och;
+ return och;
}
void BKE_ocean_simulate_cache(struct OceanCache *UNUSED(och), int UNUSED(frame))
{
}
-void BKE_ocean_bake(struct Ocean *UNUSED(o), struct OceanCache *UNUSED(och),
- void (*update_cb)(void *, float progress, int *cancel), void *UNUSED(update_cb_data))
+void BKE_ocean_bake(struct Ocean *UNUSED(o),
+ struct OceanCache *UNUSED(och),
+ void (*update_cb)(void *, float progress, int *cancel),
+ void *UNUSED(update_cb_data))
{
- /* unused */
- (void)update_cb;
+ /* unused */
+ (void)update_cb;
}
-void BKE_ocean_init_from_modifier(struct Ocean *UNUSED(ocean), struct OceanModifierData const *UNUSED(omd))
+void BKE_ocean_init_from_modifier(struct Ocean *UNUSED(ocean),
+ struct OceanModifierData const *UNUSED(omd))
{
}
@@ -1494,7 +1631,7 @@ void BKE_ocean_init_from_modifier(struct Ocean *UNUSED(ocean), struct OceanModif
void BKE_ocean_free_modifier_cache(struct OceanModifierData *omd)
{
- BKE_ocean_free_cache(omd->oceancache);
- omd->oceancache = NULL;
- omd->cached = false;
+ BKE_ocean_free_cache(omd->oceancache);
+ omd->oceancache = NULL;
+ omd->cached = false;
}
diff --git a/source/blender/blenkernel/intern/outliner_treehash.c b/source/blender/blenkernel/intern/outliner_treehash.c
index e524cd0b642..a58dfb59dd8 100644
--- a/source/blender/blenkernel/intern/outliner_treehash.c
+++ b/source/blender/blenkernel/intern/outliner_treehash.c
@@ -34,10 +34,10 @@
#include "MEM_guardedalloc.h"
typedef struct TseGroup {
- TreeStoreElem **elems;
- int lastused;
- int size;
- int allocated;
+ TreeStoreElem **elems;
+ int lastused;
+ int size;
+ int allocated;
} TseGroup;
/* Allocate structure for TreeStoreElements;
@@ -45,198 +45,208 @@ typedef struct TseGroup {
* so there is no need to preallocate memory for more than one pointer */
static TseGroup *tse_group_create(void)
{
- TseGroup *tse_group = MEM_mallocN(sizeof(TseGroup), "TseGroup");
- tse_group->elems = MEM_mallocN(sizeof(TreeStoreElem *), "TseGroupElems");
- tse_group->size = 0;
- tse_group->allocated = 1;
- tse_group->lastused = 0;
- return tse_group;
+ TseGroup *tse_group = MEM_mallocN(sizeof(TseGroup), "TseGroup");
+ tse_group->elems = MEM_mallocN(sizeof(TreeStoreElem *), "TseGroupElems");
+ tse_group->size = 0;
+ tse_group->allocated = 1;
+ tse_group->lastused = 0;
+ return tse_group;
}
static void tse_group_add_element(TseGroup *tse_group, TreeStoreElem *elem)
{
- if (UNLIKELY(tse_group->size == tse_group->allocated)) {
- tse_group->allocated *= 2;
- tse_group->elems = MEM_reallocN(tse_group->elems, sizeof(TreeStoreElem *) * tse_group->allocated);
- }
- tse_group->elems[tse_group->size] = elem;
- tse_group->size++;
+ if (UNLIKELY(tse_group->size == tse_group->allocated)) {
+ tse_group->allocated *= 2;
+ tse_group->elems = MEM_reallocN(tse_group->elems,
+ sizeof(TreeStoreElem *) * tse_group->allocated);
+ }
+ tse_group->elems[tse_group->size] = elem;
+ tse_group->size++;
}
static void tse_group_remove_element(TseGroup *tse_group, TreeStoreElem *elem)
{
- int min_allocated = MAX2(1, tse_group->allocated / 2);
- BLI_assert(tse_group->allocated == 1 || (tse_group->allocated % 2) == 0);
+ int min_allocated = MAX2(1, tse_group->allocated / 2);
+ BLI_assert(tse_group->allocated == 1 || (tse_group->allocated % 2) == 0);
- tse_group->size--;
- BLI_assert(tse_group->size >= 0);
- for (int i = 0; i < tse_group->size; i++) {
- if (tse_group->elems[i] == elem) {
- memcpy(tse_group->elems[i], tse_group->elems[i + 1], (tse_group->size - (i + 1)) * sizeof(TreeStoreElem *));
- break;
- }
- }
+ tse_group->size--;
+ BLI_assert(tse_group->size >= 0);
+ for (int i = 0; i < tse_group->size; i++) {
+ if (tse_group->elems[i] == elem) {
+ memcpy(tse_group->elems[i],
+ tse_group->elems[i + 1],
+ (tse_group->size - (i + 1)) * sizeof(TreeStoreElem *));
+ break;
+ }
+ }
- if (UNLIKELY(tse_group->size > 0 && tse_group->size <= min_allocated)) {
- tse_group->allocated = min_allocated;
- tse_group->elems = MEM_reallocN(tse_group->elems, sizeof(TreeStoreElem *) * tse_group->allocated);
- }
+ if (UNLIKELY(tse_group->size > 0 && tse_group->size <= min_allocated)) {
+ tse_group->allocated = min_allocated;
+ tse_group->elems = MEM_reallocN(tse_group->elems,
+ sizeof(TreeStoreElem *) * tse_group->allocated);
+ }
}
static void tse_group_free(TseGroup *tse_group)
{
- MEM_freeN(tse_group->elems);
- MEM_freeN(tse_group);
+ MEM_freeN(tse_group->elems);
+ MEM_freeN(tse_group);
}
static unsigned int tse_hash(const void *ptr)
{
- const TreeStoreElem *tse = ptr;
- union {
- short h_pair[2];
- unsigned int u_int;
- } hash;
+ const TreeStoreElem *tse = ptr;
+ union {
+ short h_pair[2];
+ unsigned int u_int;
+ } hash;
- BLI_assert(tse->type || !tse->nr);
+ BLI_assert(tse->type || !tse->nr);
- hash.h_pair[0] = tse->type;
- hash.h_pair[1] = tse->nr;
+ hash.h_pair[0] = tse->type;
+ hash.h_pair[1] = tse->nr;
- hash.u_int ^= BLI_ghashutil_ptrhash(tse->id);
+ hash.u_int ^= BLI_ghashutil_ptrhash(tse->id);
- return hash.u_int;
+ return hash.u_int;
}
static bool tse_cmp(const void *a, const void *b)
{
- const TreeStoreElem *tse_a = a;
- const TreeStoreElem *tse_b = b;
- return tse_a->type != tse_b->type || tse_a->nr != tse_b->nr || tse_a->id != tse_b->id;
+ const TreeStoreElem *tse_a = a;
+ const TreeStoreElem *tse_b = b;
+ return tse_a->type != tse_b->type || tse_a->nr != tse_b->nr || tse_a->id != tse_b->id;
}
static void fill_treehash(void *treehash, BLI_mempool *treestore)
{
- TreeStoreElem *tselem;
- BLI_mempool_iter iter;
- BLI_mempool_iternew(treestore, &iter);
+ TreeStoreElem *tselem;
+ BLI_mempool_iter iter;
+ BLI_mempool_iternew(treestore, &iter);
- BLI_assert(treehash);
+ BLI_assert(treehash);
- while ((tselem = BLI_mempool_iterstep(&iter))) {
- BKE_outliner_treehash_add_element(treehash, tselem);
- }
+ while ((tselem = BLI_mempool_iterstep(&iter))) {
+ BKE_outliner_treehash_add_element(treehash, tselem);
+ }
}
void *BKE_outliner_treehash_create_from_treestore(BLI_mempool *treestore)
{
- GHash *treehash = BLI_ghash_new_ex(tse_hash, tse_cmp, "treehash", BLI_mempool_len(treestore));
- fill_treehash(treehash, treestore);
- return treehash;
+ GHash *treehash = BLI_ghash_new_ex(tse_hash, tse_cmp, "treehash", BLI_mempool_len(treestore));
+ fill_treehash(treehash, treestore);
+ return treehash;
}
static void free_treehash_group(void *key)
{
- tse_group_free(key);
+ tse_group_free(key);
}
void BKE_outliner_treehash_clear_used(void *treehash)
{
- GHashIterator gh_iter;
+ GHashIterator gh_iter;
- GHASH_ITER(gh_iter, treehash) {
- TseGroup *group = BLI_ghashIterator_getValue(&gh_iter);
- group->lastused = 0;
- }
+ GHASH_ITER (gh_iter, treehash) {
+ TseGroup *group = BLI_ghashIterator_getValue(&gh_iter);
+ group->lastused = 0;
+ }
}
void *BKE_outliner_treehash_rebuild_from_treestore(void *treehash, BLI_mempool *treestore)
{
- BLI_assert(treehash);
+ BLI_assert(treehash);
- BLI_ghash_clear_ex(treehash, NULL, free_treehash_group, BLI_mempool_len(treestore));
- fill_treehash(treehash, treestore);
- return treehash;
+ BLI_ghash_clear_ex(treehash, NULL, free_treehash_group, BLI_mempool_len(treestore));
+ fill_treehash(treehash, treestore);
+ return treehash;
}
void BKE_outliner_treehash_add_element(void *treehash, TreeStoreElem *elem)
{
- TseGroup *group;
- void **val_p;
+ TseGroup *group;
+ void **val_p;
- if (!BLI_ghash_ensure_p(treehash, elem, &val_p)) {
- *val_p = tse_group_create();
- }
- group = *val_p;
- group->lastused = 0;
- tse_group_add_element(group, elem);
+ if (!BLI_ghash_ensure_p(treehash, elem, &val_p)) {
+ *val_p = tse_group_create();
+ }
+ group = *val_p;
+ group->lastused = 0;
+ tse_group_add_element(group, elem);
}
void BKE_outliner_treehash_remove_element(void *treehash, TreeStoreElem *elem)
{
- TseGroup *group = BLI_ghash_lookup(treehash, elem);
+ TseGroup *group = BLI_ghash_lookup(treehash, elem);
- BLI_assert(group != NULL);
- if (group->size <= 1) {
- /* one element -> remove group completely */
- BLI_ghash_remove(treehash, elem, NULL, free_treehash_group);
- }
- else {
- tse_group_remove_element(group, elem);
- }
+ BLI_assert(group != NULL);
+ if (group->size <= 1) {
+ /* one element -> remove group completely */
+ BLI_ghash_remove(treehash, elem, NULL, free_treehash_group);
+ }
+ else {
+ tse_group_remove_element(group, elem);
+ }
}
static TseGroup *BKE_outliner_treehash_lookup_group(GHash *th, short type, short nr, struct ID *id)
{
- TreeStoreElem tse_template;
- tse_template.type = type;
- tse_template.nr = type ? nr : 0; // we're picky! :)
- tse_template.id = id;
+ TreeStoreElem tse_template;
+ tse_template.type = type;
+ tse_template.nr = type ? nr : 0; // we're picky! :)
+ tse_template.id = id;
- BLI_assert(th);
+ BLI_assert(th);
- return BLI_ghash_lookup(th, &tse_template);
+ return BLI_ghash_lookup(th, &tse_template);
}
-TreeStoreElem *BKE_outliner_treehash_lookup_unused(void *treehash, short type, short nr, struct ID *id)
+TreeStoreElem *BKE_outliner_treehash_lookup_unused(void *treehash,
+ short type,
+ short nr,
+ struct ID *id)
{
- TseGroup *group;
+ TseGroup *group;
- BLI_assert(treehash);
+ BLI_assert(treehash);
- group = BKE_outliner_treehash_lookup_group(treehash, type, nr, id);
- if (group) {
- /* Find unused element, with optimization to start from previously
- * found element assuming we do repeated lookups. */
- int size = group->size;
- int offset = group->lastused;
+ group = BKE_outliner_treehash_lookup_group(treehash, type, nr, id);
+ if (group) {
+ /* Find unused element, with optimization to start from previously
+ * found element assuming we do repeated lookups. */
+ int size = group->size;
+ int offset = group->lastused;
- for (int i = 0; i < size; i++, offset++) {
- if (offset >= size) {
- offset = 0;
- }
+ for (int i = 0; i < size; i++, offset++) {
+ if (offset >= size) {
+ offset = 0;
+ }
- if (!group->elems[offset]->used) {
- group->lastused = offset;
- return group->elems[offset];
- }
- }
- }
- return NULL;
+ if (!group->elems[offset]->used) {
+ group->lastused = offset;
+ return group->elems[offset];
+ }
+ }
+ }
+ return NULL;
}
-TreeStoreElem *BKE_outliner_treehash_lookup_any(void *treehash, short type, short nr, struct ID *id)
+TreeStoreElem *BKE_outliner_treehash_lookup_any(void *treehash,
+ short type,
+ short nr,
+ struct ID *id)
{
- TseGroup *group;
+ TseGroup *group;
- BLI_assert(treehash);
+ BLI_assert(treehash);
- group = BKE_outliner_treehash_lookup_group(treehash, type, nr, id);
- return group ? group->elems[0] : NULL;
+ group = BKE_outliner_treehash_lookup_group(treehash, type, nr, id);
+ return group ? group->elems[0] : NULL;
}
void BKE_outliner_treehash_free(void *treehash)
{
- BLI_assert(treehash);
+ BLI_assert(treehash);
- BLI_ghash_free(treehash, NULL, free_treehash_group);
+ BLI_ghash_free(treehash, NULL, free_treehash_group);
}
diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c
index a039e0544d5..a1b315be19a 100644
--- a/source/blender/blenkernel/intern/packedFile.c
+++ b/source/blender/blenkernel/intern/packedFile.c
@@ -21,15 +21,14 @@
* \ingroup bke
*/
-
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#ifndef WIN32
-#include <unistd.h>
+# include <unistd.h>
#else
-#include <io.h>
+# include <io.h>
#endif
#include <string.h>
#include "MEM_guardedalloc.h"
@@ -52,272 +51,284 @@
int seekPackedFile(PackedFile *pf, int offset, int whence)
{
- int oldseek = -1, seek = 0;
-
- if (pf) {
- oldseek = pf->seek;
- switch (whence) {
- case SEEK_CUR:
- seek = oldseek + offset;
- break;
- case SEEK_END:
- seek = pf->size + offset;
- break;
- case SEEK_SET:
- seek = offset;
- break;
- default:
- oldseek = -1;
- break;
- }
- if (seek < 0) {
- seek = 0;
- }
- else if (seek > pf->size) {
- seek = pf->size;
- }
- pf->seek = seek;
- }
-
- return(oldseek);
+ int oldseek = -1, seek = 0;
+
+ if (pf) {
+ oldseek = pf->seek;
+ switch (whence) {
+ case SEEK_CUR:
+ seek = oldseek + offset;
+ break;
+ case SEEK_END:
+ seek = pf->size + offset;
+ break;
+ case SEEK_SET:
+ seek = offset;
+ break;
+ default:
+ oldseek = -1;
+ break;
+ }
+ if (seek < 0) {
+ seek = 0;
+ }
+ else if (seek > pf->size) {
+ seek = pf->size;
+ }
+ pf->seek = seek;
+ }
+
+ return (oldseek);
}
void rewindPackedFile(PackedFile *pf)
{
- seekPackedFile(pf, 0, SEEK_SET);
+ seekPackedFile(pf, 0, SEEK_SET);
}
int readPackedFile(PackedFile *pf, void *data, int size)
{
- if ((pf != NULL) && (size >= 0) && (data != NULL)) {
- if (size + pf->seek > pf->size) {
- size = pf->size - pf->seek;
- }
-
- if (size > 0) {
- memcpy(data, ((char *) pf->data) + pf->seek, size);
- }
- else {
- size = 0;
- }
-
- pf->seek += size;
- }
- else {
- size = -1;
- }
-
- return(size);
+ if ((pf != NULL) && (size >= 0) && (data != NULL)) {
+ if (size + pf->seek > pf->size) {
+ size = pf->size - pf->seek;
+ }
+
+ if (size > 0) {
+ memcpy(data, ((char *)pf->data) + pf->seek, size);
+ }
+ else {
+ size = 0;
+ }
+
+ pf->seek += size;
+ }
+ else {
+ size = -1;
+ }
+
+ return (size);
}
int countPackedFiles(Main *bmain)
{
- Image *ima;
- VFont *vf;
- bSound *sound;
- int count = 0;
+ Image *ima;
+ VFont *vf;
+ bSound *sound;
+ int count = 0;
- /* let's check if there are packed files... */
- for (ima = bmain->images.first; ima; ima = ima->id.next)
- if (BKE_image_has_packedfile(ima))
- count ++;
+ /* let's check if there are packed files... */
+ for (ima = bmain->images.first; ima; ima = ima->id.next)
+ if (BKE_image_has_packedfile(ima))
+ count++;
- for (vf = bmain->fonts.first; vf; vf = vf->id.next)
- if (vf->packedfile)
- count++;
+ for (vf = bmain->fonts.first; vf; vf = vf->id.next)
+ if (vf->packedfile)
+ count++;
- for (sound = bmain->sounds.first; sound; sound = sound->id.next)
- if (sound->packedfile)
- count++;
+ for (sound = bmain->sounds.first; sound; sound = sound->id.next)
+ if (sound->packedfile)
+ count++;
- return count;
+ return count;
}
void freePackedFile(PackedFile *pf)
{
- if (pf) {
- MEM_freeN(pf->data);
- MEM_freeN(pf);
- }
- else
- printf("freePackedFile: Trying to free a NULL pointer\n");
+ if (pf) {
+ MEM_freeN(pf->data);
+ MEM_freeN(pf);
+ }
+ else
+ printf("freePackedFile: Trying to free a NULL pointer\n");
}
PackedFile *dupPackedFile(const PackedFile *pf_src)
{
- PackedFile *pf_dst;
+ PackedFile *pf_dst;
- pf_dst = MEM_dupallocN(pf_src);
- pf_dst->data = MEM_dupallocN(pf_src->data);
+ pf_dst = MEM_dupallocN(pf_src);
+ pf_dst->data = MEM_dupallocN(pf_src->data);
- return pf_dst;
+ return pf_dst;
}
PackedFile *newPackedFileMemory(void *mem, int memlen)
{
- PackedFile *pf = MEM_callocN(sizeof(*pf), "PackedFile");
- pf->data = mem;
- pf->size = memlen;
+ PackedFile *pf = MEM_callocN(sizeof(*pf), "PackedFile");
+ pf->data = mem;
+ pf->size = memlen;
- return pf;
+ return pf;
}
PackedFile *newPackedFile(ReportList *reports, const char *filename, const char *basepath)
{
- PackedFile *pf = NULL;
- int file, filelen;
- char name[FILE_MAX];
- void *data;
-
- /* render result has no filename and can be ignored
- * any other files with no name can be ignored too */
- if (filename[0] == '\0')
- return NULL;
-
- //XXX waitcursor(1);
-
- /* convert relative filenames to absolute filenames */
-
- BLI_strncpy(name, filename, sizeof(name));
- BLI_path_abs(name, basepath);
-
- /* open the file
- * and create a PackedFile structure */
-
- file = BLI_open(name, O_BINARY | O_RDONLY, 0);
- if (file == -1) {
- BKE_reportf(reports, RPT_ERROR, "Unable to pack file, source path '%s' not found", name);
- }
- else {
- filelen = BLI_file_descriptor_size(file);
-
- if (filelen == 0) {
- /* MEM_mallocN complains about MEM_mallocN(0, "bla");
- * we don't care.... */
- data = MEM_mallocN(1, "packFile");
- }
- else {
- data = MEM_mallocN(filelen, "packFile");
- }
- if (read(file, data, filelen) == filelen) {
- pf = newPackedFileMemory(data, filelen);
- }
- else {
- MEM_freeN(data);
- }
-
- close(file);
- }
-
- //XXX waitcursor(0);
-
- return (pf);
+ PackedFile *pf = NULL;
+ int file, filelen;
+ char name[FILE_MAX];
+ void *data;
+
+ /* render result has no filename and can be ignored
+ * any other files with no name can be ignored too */
+ if (filename[0] == '\0')
+ return NULL;
+
+ //XXX waitcursor(1);
+
+ /* convert relative filenames to absolute filenames */
+
+ BLI_strncpy(name, filename, sizeof(name));
+ BLI_path_abs(name, basepath);
+
+ /* open the file
+ * and create a PackedFile structure */
+
+ file = BLI_open(name, O_BINARY | O_RDONLY, 0);
+ if (file == -1) {
+ BKE_reportf(reports, RPT_ERROR, "Unable to pack file, source path '%s' not found", name);
+ }
+ else {
+ filelen = BLI_file_descriptor_size(file);
+
+ if (filelen == 0) {
+ /* MEM_mallocN complains about MEM_mallocN(0, "bla");
+ * we don't care.... */
+ data = MEM_mallocN(1, "packFile");
+ }
+ else {
+ data = MEM_mallocN(filelen, "packFile");
+ }
+ if (read(file, data, filelen) == filelen) {
+ pf = newPackedFileMemory(data, filelen);
+ }
+ else {
+ MEM_freeN(data);
+ }
+
+ close(file);
+ }
+
+ //XXX waitcursor(0);
+
+ return (pf);
}
/* no libraries for now */
void packAll(Main *bmain, ReportList *reports, bool verbose)
{
- Image *ima;
- VFont *vfont;
- bSound *sound;
- int tot = 0;
-
- for (ima = bmain->images.first; ima; ima = ima->id.next) {
- if (BKE_image_has_packedfile(ima) == false && !ID_IS_LINKED(ima)) {
- if (ima->source == IMA_SRC_FILE) {
- BKE_image_packfiles(reports, ima, ID_BLEND_PATH(bmain, &ima->id));
- tot ++;
- }
- else if (BKE_image_is_animated(ima) && verbose) {
- BKE_reportf(reports, RPT_WARNING, "Image '%s' skipped, movies and image sequences not supported",
- ima->id.name + 2);
- }
- }
- }
-
- for (vfont = bmain->fonts.first; vfont; vfont = vfont->id.next) {
- if (vfont->packedfile == NULL && !ID_IS_LINKED(vfont) && BKE_vfont_is_builtin(vfont) == false) {
- vfont->packedfile = newPackedFile(reports, vfont->name, BKE_main_blendfile_path(bmain));
- tot ++;
- }
- }
-
- for (sound = bmain->sounds.first; sound; sound = sound->id.next) {
- if (sound->packedfile == NULL && !ID_IS_LINKED(sound)) {
- sound->packedfile = newPackedFile(reports, sound->name, BKE_main_blendfile_path(bmain));
- tot++;
- }
- }
-
- if (tot > 0)
- BKE_reportf(reports, RPT_INFO, "Packed %d files", tot);
- else if (verbose)
- BKE_report(reports, RPT_INFO, "No new files have been packed");
+ Image *ima;
+ VFont *vfont;
+ bSound *sound;
+ int tot = 0;
+
+ for (ima = bmain->images.first; ima; ima = ima->id.next) {
+ if (BKE_image_has_packedfile(ima) == false && !ID_IS_LINKED(ima)) {
+ if (ima->source == IMA_SRC_FILE) {
+ BKE_image_packfiles(reports, ima, ID_BLEND_PATH(bmain, &ima->id));
+ tot++;
+ }
+ else if (BKE_image_is_animated(ima) && verbose) {
+ BKE_reportf(reports,
+ RPT_WARNING,
+ "Image '%s' skipped, movies and image sequences not supported",
+ ima->id.name + 2);
+ }
+ }
+ }
+
+ for (vfont = bmain->fonts.first; vfont; vfont = vfont->id.next) {
+ if (vfont->packedfile == NULL && !ID_IS_LINKED(vfont) &&
+ BKE_vfont_is_builtin(vfont) == false) {
+ vfont->packedfile = newPackedFile(reports, vfont->name, BKE_main_blendfile_path(bmain));
+ tot++;
+ }
+ }
+
+ for (sound = bmain->sounds.first; sound; sound = sound->id.next) {
+ if (sound->packedfile == NULL && !ID_IS_LINKED(sound)) {
+ sound->packedfile = newPackedFile(reports, sound->name, BKE_main_blendfile_path(bmain));
+ tot++;
+ }
+ }
+
+ if (tot > 0)
+ BKE_reportf(reports, RPT_INFO, "Packed %d files", tot);
+ else if (verbose)
+ BKE_report(reports, RPT_INFO, "No new files have been packed");
}
-int writePackedFile(
- ReportList *reports, const char *ref_file_name, const char *filename, PackedFile *pf, const bool guimode)
+int writePackedFile(ReportList *reports,
+ const char *ref_file_name,
+ const char *filename,
+ PackedFile *pf,
+ const bool guimode)
{
- int file, number;
- int ret_value = RET_OK;
- bool remove_tmp = false;
- char name[FILE_MAX];
- char tempname[FILE_MAX];
-/* void *data; */
-
- if (guimode) {} //XXX waitcursor(1);
-
- BLI_strncpy(name, filename, sizeof(name));
- BLI_path_abs(name, ref_file_name);
-
- if (BLI_exists(name)) {
- for (number = 1; number <= 999; number++) {
- BLI_snprintf(tempname, sizeof(tempname), "%s.%03d_", name, number);
- if (!BLI_exists(tempname)) {
- if (BLI_copy(name, tempname) == RET_OK) {
- remove_tmp = true;
- }
- break;
- }
- }
- }
-
- /* make sure the path to the file exists... */
- BLI_make_existing_file(name);
-
- file = BLI_open(name, O_BINARY + O_WRONLY + O_CREAT + O_TRUNC, 0666);
- if (file == -1) {
- BKE_reportf(reports, RPT_ERROR, "Error creating file '%s'", name);
- ret_value = RET_ERROR;
- }
- else {
- if (write(file, pf->data, pf->size) != pf->size) {
- BKE_reportf(reports, RPT_ERROR, "Error writing file '%s'", name);
- ret_value = RET_ERROR;
- }
- else {
- BKE_reportf(reports, RPT_INFO, "Saved packed file to: %s", name);
- }
-
- close(file);
- }
-
- if (remove_tmp) {
- if (ret_value == RET_ERROR) {
- if (BLI_rename(tempname, name) != 0) {
- BKE_reportf(reports, RPT_ERROR, "Error restoring temp file (check files '%s' '%s')", tempname, name);
- }
- }
- else {
- if (BLI_delete(tempname, false, false) != 0) {
- BKE_reportf(reports, RPT_ERROR, "Error deleting '%s' (ignored)", tempname);
- }
- }
- }
-
- if (guimode) {} //XXX waitcursor(0);
-
- return (ret_value);
+ int file, number;
+ int ret_value = RET_OK;
+ bool remove_tmp = false;
+ char name[FILE_MAX];
+ char tempname[FILE_MAX];
+ /* void *data; */
+
+ if (guimode) {
+ } //XXX waitcursor(1);
+
+ BLI_strncpy(name, filename, sizeof(name));
+ BLI_path_abs(name, ref_file_name);
+
+ if (BLI_exists(name)) {
+ for (number = 1; number <= 999; number++) {
+ BLI_snprintf(tempname, sizeof(tempname), "%s.%03d_", name, number);
+ if (!BLI_exists(tempname)) {
+ if (BLI_copy(name, tempname) == RET_OK) {
+ remove_tmp = true;
+ }
+ break;
+ }
+ }
+ }
+
+ /* make sure the path to the file exists... */
+ BLI_make_existing_file(name);
+
+ file = BLI_open(name, O_BINARY + O_WRONLY + O_CREAT + O_TRUNC, 0666);
+ if (file == -1) {
+ BKE_reportf(reports, RPT_ERROR, "Error creating file '%s'", name);
+ ret_value = RET_ERROR;
+ }
+ else {
+ if (write(file, pf->data, pf->size) != pf->size) {
+ BKE_reportf(reports, RPT_ERROR, "Error writing file '%s'", name);
+ ret_value = RET_ERROR;
+ }
+ else {
+ BKE_reportf(reports, RPT_INFO, "Saved packed file to: %s", name);
+ }
+
+ close(file);
+ }
+
+ if (remove_tmp) {
+ if (ret_value == RET_ERROR) {
+ if (BLI_rename(tempname, name) != 0) {
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "Error restoring temp file (check files '%s' '%s')",
+ tempname,
+ name);
+ }
+ }
+ else {
+ if (BLI_delete(tempname, false, false) != 0) {
+ BKE_reportf(reports, RPT_ERROR, "Error deleting '%s' (ignored)", tempname);
+ }
+ }
+ }
+
+ if (guimode) {
+ } //XXX waitcursor(0);
+
+ return (ret_value);
}
/**
@@ -330,54 +341,54 @@ int writePackedFile(
*/
int checkPackedFile(const char *ref_file_name, const char *filename, PackedFile *pf)
{
- BLI_stat_t st;
- int ret_val, i, len, file;
- char buf[4096];
- char name[FILE_MAX];
-
- BLI_strncpy(name, filename, sizeof(name));
- BLI_path_abs(name, ref_file_name);
-
- if (BLI_stat(name, &st) == -1) {
- ret_val = PF_NOFILE;
- }
- else if (st.st_size != pf->size) {
- ret_val = PF_DIFFERS;
- }
- else {
- /* we'll have to compare the two... */
-
- file = BLI_open(name, O_BINARY | O_RDONLY, 0);
- if (file == -1) {
- ret_val = PF_NOFILE;
- }
- else {
- ret_val = PF_EQUAL;
-
- for (i = 0; i < pf->size; i += sizeof(buf)) {
- len = pf->size - i;
- if (len > sizeof(buf)) {
- len = sizeof(buf);
- }
-
- if (read(file, buf, len) != len) {
- /* read error ... */
- ret_val = PF_DIFFERS;
- break;
- }
- else {
- if (memcmp(buf, ((char *)pf->data) + i, len)) {
- ret_val = PF_DIFFERS;
- break;
- }
- }
- }
-
- close(file);
- }
- }
-
- return(ret_val);
+ BLI_stat_t st;
+ int ret_val, i, len, file;
+ char buf[4096];
+ char name[FILE_MAX];
+
+ BLI_strncpy(name, filename, sizeof(name));
+ BLI_path_abs(name, ref_file_name);
+
+ if (BLI_stat(name, &st) == -1) {
+ ret_val = PF_NOFILE;
+ }
+ else if (st.st_size != pf->size) {
+ ret_val = PF_DIFFERS;
+ }
+ else {
+ /* we'll have to compare the two... */
+
+ file = BLI_open(name, O_BINARY | O_RDONLY, 0);
+ if (file == -1) {
+ ret_val = PF_NOFILE;
+ }
+ else {
+ ret_val = PF_EQUAL;
+
+ for (i = 0; i < pf->size; i += sizeof(buf)) {
+ len = pf->size - i;
+ if (len > sizeof(buf)) {
+ len = sizeof(buf);
+ }
+
+ if (read(file, buf, len) != len) {
+ /* read error ... */
+ ret_val = PF_DIFFERS;
+ break;
+ }
+ else {
+ if (memcmp(buf, ((char *)pf->data) + i, len)) {
+ ret_val = PF_DIFFERS;
+ break;
+ }
+ }
+ }
+
+ close(file);
+ }
+ }
+
+ return (ret_val);
}
/**
@@ -388,339 +399,347 @@ int checkPackedFile(const char *ref_file_name, const char *filename, PackedFile
*
* \warning 'abs_name' may be relative still! (use a "//" prefix) be sure to run #BLI_path_abs on it first.
*/
-char *unpackFile(
- ReportList *reports, const char *ref_file_name,
- const char *abs_name, const char *local_name, PackedFile *pf, int how)
+char *unpackFile(ReportList *reports,
+ const char *ref_file_name,
+ const char *abs_name,
+ const char *local_name,
+ PackedFile *pf,
+ int how)
{
- char *newname = NULL;
- const char *temp = NULL;
-
- if (pf != NULL) {
- switch (how) {
- case -1:
- case PF_KEEP:
- break;
- case PF_REMOVE:
- temp = abs_name;
- break;
- case PF_USE_LOCAL:
- {
- char temp_abs[FILE_MAX];
-
- BLI_strncpy(temp_abs, local_name, sizeof(temp_abs));
- BLI_path_abs(temp_abs, ref_file_name);
-
- /* if file exists use it */
- if (BLI_exists(temp_abs)) {
- temp = local_name;
- break;
- }
- /* else create it */
- ATTR_FALLTHROUGH;
- }
- case PF_WRITE_LOCAL:
- if (writePackedFile(reports, ref_file_name, local_name, pf, 1) == RET_OK) {
- temp = local_name;
- }
- break;
- case PF_USE_ORIGINAL:
- {
- char temp_abs[FILE_MAX];
-
- BLI_strncpy(temp_abs, abs_name, sizeof(temp_abs));
- BLI_path_abs(temp_abs, ref_file_name);
-
- /* if file exists use it */
- if (BLI_exists(temp_abs)) {
- BKE_reportf(reports, RPT_INFO, "Use existing file (instead of packed): %s", abs_name);
- temp = abs_name;
- break;
- }
- /* else create it */
- ATTR_FALLTHROUGH;
- }
- case PF_WRITE_ORIGINAL:
- if (writePackedFile(reports, ref_file_name, abs_name, pf, 1) == RET_OK) {
- temp = abs_name;
- }
- break;
- default:
- printf("unpackFile: unknown return_value %d\n", how);
- break;
- }
-
- if (temp) {
- newname = BLI_strdup(temp);
- }
- }
-
- return newname;
+ char *newname = NULL;
+ const char *temp = NULL;
+
+ if (pf != NULL) {
+ switch (how) {
+ case -1:
+ case PF_KEEP:
+ break;
+ case PF_REMOVE:
+ temp = abs_name;
+ break;
+ case PF_USE_LOCAL: {
+ char temp_abs[FILE_MAX];
+
+ BLI_strncpy(temp_abs, local_name, sizeof(temp_abs));
+ BLI_path_abs(temp_abs, ref_file_name);
+
+ /* if file exists use it */
+ if (BLI_exists(temp_abs)) {
+ temp = local_name;
+ break;
+ }
+ /* else create it */
+ ATTR_FALLTHROUGH;
+ }
+ case PF_WRITE_LOCAL:
+ if (writePackedFile(reports, ref_file_name, local_name, pf, 1) == RET_OK) {
+ temp = local_name;
+ }
+ break;
+ case PF_USE_ORIGINAL: {
+ char temp_abs[FILE_MAX];
+
+ BLI_strncpy(temp_abs, abs_name, sizeof(temp_abs));
+ BLI_path_abs(temp_abs, ref_file_name);
+
+ /* if file exists use it */
+ if (BLI_exists(temp_abs)) {
+ BKE_reportf(reports, RPT_INFO, "Use existing file (instead of packed): %s", abs_name);
+ temp = abs_name;
+ break;
+ }
+ /* else create it */
+ ATTR_FALLTHROUGH;
+ }
+ case PF_WRITE_ORIGINAL:
+ if (writePackedFile(reports, ref_file_name, abs_name, pf, 1) == RET_OK) {
+ temp = abs_name;
+ }
+ break;
+ default:
+ printf("unpackFile: unknown return_value %d\n", how);
+ break;
+ }
+
+ if (temp) {
+ newname = BLI_strdup(temp);
+ }
+ }
+
+ return newname;
}
-static void unpack_generate_paths(
- const char *name, ID *id, char *r_abspath, char *r_relpath, size_t abspathlen, size_t relpathlen)
+static void unpack_generate_paths(const char *name,
+ ID *id,
+ char *r_abspath,
+ char *r_relpath,
+ size_t abspathlen,
+ size_t relpathlen)
{
- char tempname[FILE_MAX];
- char tempdir[FILE_MAXDIR];
-
- BLI_split_dirfile(name, tempdir, tempname, sizeof(tempdir), sizeof(tempname));
-
- if (tempname[0] == '\0') {
- /* Note: we do not have any real way to re-create extension out of data... */
- BLI_strncpy(tempname, id->name + 2, sizeof(tempname));
- printf("%s\n", tempname);
- BLI_filename_make_safe(tempname);
- printf("%s\n", tempname);
- }
-
- if (tempdir[0] == '\0') {
- /* Fallback to relative dir. */
- BLI_strncpy(tempdir, "//", sizeof(tempdir));
- }
-
- switch (GS(id->name)) {
- case ID_VF:
- BLI_snprintf(r_relpath, relpathlen, "//fonts/%s", tempname);
- break;
- case ID_SO:
- BLI_snprintf(r_relpath, relpathlen, "//sounds/%s", tempname);
- break;
- case ID_IM:
- BLI_snprintf(r_relpath, relpathlen, "//textures/%s", tempname);
- break;
- default:
- break;
- }
-
- {
- size_t len = BLI_strncpy_rlen(r_abspath, tempdir, abspathlen);
- BLI_strncpy(r_abspath + len, tempname, abspathlen - len);
- }
+ char tempname[FILE_MAX];
+ char tempdir[FILE_MAXDIR];
+
+ BLI_split_dirfile(name, tempdir, tempname, sizeof(tempdir), sizeof(tempname));
+
+ if (tempname[0] == '\0') {
+ /* Note: we do not have any real way to re-create extension out of data... */
+ BLI_strncpy(tempname, id->name + 2, sizeof(tempname));
+ printf("%s\n", tempname);
+ BLI_filename_make_safe(tempname);
+ printf("%s\n", tempname);
+ }
+
+ if (tempdir[0] == '\0') {
+ /* Fallback to relative dir. */
+ BLI_strncpy(tempdir, "//", sizeof(tempdir));
+ }
+
+ switch (GS(id->name)) {
+ case ID_VF:
+ BLI_snprintf(r_relpath, relpathlen, "//fonts/%s", tempname);
+ break;
+ case ID_SO:
+ BLI_snprintf(r_relpath, relpathlen, "//sounds/%s", tempname);
+ break;
+ case ID_IM:
+ BLI_snprintf(r_relpath, relpathlen, "//textures/%s", tempname);
+ break;
+ default:
+ break;
+ }
+
+ {
+ size_t len = BLI_strncpy_rlen(r_abspath, tempdir, abspathlen);
+ BLI_strncpy(r_abspath + len, tempname, abspathlen - len);
+ }
}
int unpackVFont(Main *bmain, ReportList *reports, VFont *vfont, int how)
{
- char localname[FILE_MAX], absname[FILE_MAX];
- char *newname;
- int ret_value = RET_ERROR;
-
- if (vfont != NULL) {
- unpack_generate_paths(vfont->name, (ID *)vfont, absname, localname, sizeof(absname), sizeof(localname));
- newname = unpackFile(reports, BKE_main_blendfile_path(bmain), absname, localname, vfont->packedfile, how);
- if (newname != NULL) {
- ret_value = RET_OK;
- freePackedFile(vfont->packedfile);
- vfont->packedfile = NULL;
- BLI_strncpy(vfont->name, newname, sizeof(vfont->name));
- MEM_freeN(newname);
- }
- }
-
- return (ret_value);
+ char localname[FILE_MAX], absname[FILE_MAX];
+ char *newname;
+ int ret_value = RET_ERROR;
+
+ if (vfont != NULL) {
+ unpack_generate_paths(
+ vfont->name, (ID *)vfont, absname, localname, sizeof(absname), sizeof(localname));
+ newname = unpackFile(
+ reports, BKE_main_blendfile_path(bmain), absname, localname, vfont->packedfile, how);
+ if (newname != NULL) {
+ ret_value = RET_OK;
+ freePackedFile(vfont->packedfile);
+ vfont->packedfile = NULL;
+ BLI_strncpy(vfont->name, newname, sizeof(vfont->name));
+ MEM_freeN(newname);
+ }
+ }
+
+ return (ret_value);
}
int unpackSound(Main *bmain, ReportList *reports, bSound *sound, int how)
{
- char localname[FILE_MAX], absname[FILE_MAX];
- char *newname;
- int ret_value = RET_ERROR;
+ char localname[FILE_MAX], absname[FILE_MAX];
+ char *newname;
+ int ret_value = RET_ERROR;
- if (sound != NULL) {
- unpack_generate_paths(sound->name, (ID *)sound, absname, localname, sizeof(absname), sizeof(localname));
- newname = unpackFile(reports, BKE_main_blendfile_path(bmain), absname, localname, sound->packedfile, how);
- if (newname != NULL) {
- BLI_strncpy(sound->name, newname, sizeof(sound->name));
- MEM_freeN(newname);
+ if (sound != NULL) {
+ unpack_generate_paths(
+ sound->name, (ID *)sound, absname, localname, sizeof(absname), sizeof(localname));
+ newname = unpackFile(
+ reports, BKE_main_blendfile_path(bmain), absname, localname, sound->packedfile, how);
+ if (newname != NULL) {
+ BLI_strncpy(sound->name, newname, sizeof(sound->name));
+ MEM_freeN(newname);
- freePackedFile(sound->packedfile);
- sound->packedfile = NULL;
+ freePackedFile(sound->packedfile);
+ sound->packedfile = NULL;
- BKE_sound_load(bmain, sound);
+ BKE_sound_load(bmain, sound);
- ret_value = RET_OK;
- }
- }
+ ret_value = RET_OK;
+ }
+ }
- return(ret_value);
+ return (ret_value);
}
int unpackImage(Main *bmain, ReportList *reports, Image *ima, int how)
{
- int ret_value = RET_ERROR;
-
- if (ima != NULL) {
- while (ima->packedfiles.last) {
- char localname[FILE_MAX], absname[FILE_MAX];
- char *newname;
- ImagePackedFile *imapf = ima->packedfiles.last;
-
- unpack_generate_paths(imapf->filepath, (ID *)ima, absname, localname, sizeof(absname), sizeof(localname));
- newname = unpackFile(reports, BKE_main_blendfile_path(bmain), absname, localname, imapf->packedfile, how);
-
- if (newname != NULL) {
- ImageView *iv;
-
- ret_value = ret_value == RET_ERROR ? RET_ERROR : RET_OK;
- freePackedFile(imapf->packedfile);
- imapf->packedfile = NULL;
-
- /* update the new corresponding view filepath */
- iv = BLI_findstring(&ima->views, imapf->filepath, offsetof(ImageView, filepath));
- if (iv) {
- BLI_strncpy(iv->filepath, newname, sizeof(imapf->filepath));
- }
-
- /* keep the new name in the image for non-pack specific reasons */
- if (how != PF_REMOVE) {
- BLI_strncpy(ima->name, newname, sizeof(imapf->filepath));
- }
- MEM_freeN(newname);
- }
- else {
- ret_value = RET_ERROR;
- }
-
- BLI_remlink(&ima->packedfiles, imapf);
- MEM_freeN(imapf);
- }
- }
-
- if (ret_value == RET_OK) {
- BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_RELOAD);
- }
-
- return(ret_value);
+ int ret_value = RET_ERROR;
+
+ if (ima != NULL) {
+ while (ima->packedfiles.last) {
+ char localname[FILE_MAX], absname[FILE_MAX];
+ char *newname;
+ ImagePackedFile *imapf = ima->packedfiles.last;
+
+ unpack_generate_paths(
+ imapf->filepath, (ID *)ima, absname, localname, sizeof(absname), sizeof(localname));
+ newname = unpackFile(
+ reports, BKE_main_blendfile_path(bmain), absname, localname, imapf->packedfile, how);
+
+ if (newname != NULL) {
+ ImageView *iv;
+
+ ret_value = ret_value == RET_ERROR ? RET_ERROR : RET_OK;
+ freePackedFile(imapf->packedfile);
+ imapf->packedfile = NULL;
+
+ /* update the new corresponding view filepath */
+ iv = BLI_findstring(&ima->views, imapf->filepath, offsetof(ImageView, filepath));
+ if (iv) {
+ BLI_strncpy(iv->filepath, newname, sizeof(imapf->filepath));
+ }
+
+ /* keep the new name in the image for non-pack specific reasons */
+ if (how != PF_REMOVE) {
+ BLI_strncpy(ima->name, newname, sizeof(imapf->filepath));
+ }
+ MEM_freeN(newname);
+ }
+ else {
+ ret_value = RET_ERROR;
+ }
+
+ BLI_remlink(&ima->packedfiles, imapf);
+ MEM_freeN(imapf);
+ }
+ }
+
+ if (ret_value == RET_OK) {
+ BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_RELOAD);
+ }
+
+ return (ret_value);
}
int unpackLibraries(Main *bmain, ReportList *reports)
{
- Library *lib;
- char *newname;
- int ret_value = RET_ERROR;
+ Library *lib;
+ char *newname;
+ int ret_value = RET_ERROR;
- for (lib = bmain->libraries.first; lib; lib = lib->id.next) {
- if (lib->packedfile && lib->name[0]) {
+ for (lib = bmain->libraries.first; lib; lib = lib->id.next) {
+ if (lib->packedfile && lib->name[0]) {
- newname = unpackFile(reports, BKE_main_blendfile_path(bmain), lib->filepath, lib->filepath, lib->packedfile, PF_WRITE_ORIGINAL);
- if (newname != NULL) {
- ret_value = RET_OK;
+ newname = unpackFile(reports,
+ BKE_main_blendfile_path(bmain),
+ lib->filepath,
+ lib->filepath,
+ lib->packedfile,
+ PF_WRITE_ORIGINAL);
+ if (newname != NULL) {
+ ret_value = RET_OK;
- printf("Unpacked .blend library: %s\n", newname);
+ printf("Unpacked .blend library: %s\n", newname);
- freePackedFile(lib->packedfile);
- lib->packedfile = NULL;
+ freePackedFile(lib->packedfile);
+ lib->packedfile = NULL;
- MEM_freeN(newname);
- }
- }
- }
+ MEM_freeN(newname);
+ }
+ }
+ }
- return(ret_value);
+ return (ret_value);
}
void packLibraries(Main *bmain, ReportList *reports)
{
- Library *lib;
+ Library *lib;
- /* test for relativenss */
- for (lib = bmain->libraries.first; lib; lib = lib->id.next)
- if (!BLI_path_is_rel(lib->name))
- break;
+ /* test for relativenss */
+ for (lib = bmain->libraries.first; lib; lib = lib->id.next)
+ if (!BLI_path_is_rel(lib->name))
+ break;
- if (lib) {
- BKE_reportf(reports, RPT_ERROR, "Cannot pack absolute file: '%s'", lib->name);
- return;
- }
+ if (lib) {
+ BKE_reportf(reports, RPT_ERROR, "Cannot pack absolute file: '%s'", lib->name);
+ return;
+ }
- for (lib = bmain->libraries.first; lib; lib = lib->id.next)
- if (lib->packedfile == NULL)
- lib->packedfile = newPackedFile(reports, lib->name, BKE_main_blendfile_path(bmain));
+ for (lib = bmain->libraries.first; lib; lib = lib->id.next)
+ if (lib->packedfile == NULL)
+ lib->packedfile = newPackedFile(reports, lib->name, BKE_main_blendfile_path(bmain));
}
void unpackAll(Main *bmain, ReportList *reports, int how)
{
- Image *ima;
- VFont *vf;
- bSound *sound;
+ Image *ima;
+ VFont *vf;
+ bSound *sound;
- for (ima = bmain->images.first; ima; ima = ima->id.next)
- if (BKE_image_has_packedfile(ima))
- unpackImage(bmain, reports, ima, how);
+ for (ima = bmain->images.first; ima; ima = ima->id.next)
+ if (BKE_image_has_packedfile(ima))
+ unpackImage(bmain, reports, ima, how);
- for (vf = bmain->fonts.first; vf; vf = vf->id.next)
- if (vf->packedfile)
- unpackVFont(bmain, reports, vf, how);
+ for (vf = bmain->fonts.first; vf; vf = vf->id.next)
+ if (vf->packedfile)
+ unpackVFont(bmain, reports, vf, how);
- for (sound = bmain->sounds.first; sound; sound = sound->id.next)
- if (sound->packedfile)
- unpackSound(bmain, reports, sound, how);
+ for (sound = bmain->sounds.first; sound; sound = sound->id.next)
+ if (sound->packedfile)
+ unpackSound(bmain, reports, sound, how);
}
/* ID should be not NULL, return 1 if there's a packed file */
bool BKE_pack_check(ID *id)
{
- switch (GS(id->name)) {
- case ID_IM:
- {
- Image *ima = (Image *)id;
- return BKE_image_has_packedfile(ima);
- }
- case ID_VF:
- {
- VFont *vf = (VFont *)id;
- return vf->packedfile != NULL;
- }
- case ID_SO:
- {
- bSound *snd = (bSound *)id;
- return snd->packedfile != NULL;
- }
- case ID_LI:
- {
- Library *li = (Library *)id;
- return li->packedfile != NULL;
- }
- default:
- break;
- }
- return false;
+ switch (GS(id->name)) {
+ case ID_IM: {
+ Image *ima = (Image *)id;
+ return BKE_image_has_packedfile(ima);
+ }
+ case ID_VF: {
+ VFont *vf = (VFont *)id;
+ return vf->packedfile != NULL;
+ }
+ case ID_SO: {
+ bSound *snd = (bSound *)id;
+ return snd->packedfile != NULL;
+ }
+ case ID_LI: {
+ Library *li = (Library *)id;
+ return li->packedfile != NULL;
+ }
+ default:
+ break;
+ }
+ return false;
}
/* ID should be not NULL */
void BKE_unpack_id(Main *bmain, ID *id, ReportList *reports, int how)
{
- switch (GS(id->name)) {
- case ID_IM:
- {
- Image *ima = (Image *)id;
- if (BKE_image_has_packedfile(ima)) {
- unpackImage(bmain, reports, ima, how);
- }
- break;
- }
- case ID_VF:
- {
- VFont *vf = (VFont *)id;
- if (vf->packedfile) {
- unpackVFont(bmain, reports, vf, how);
- }
- break;
- }
- case ID_SO:
- {
- bSound *snd = (bSound *)id;
- if (snd->packedfile) {
- unpackSound(bmain, reports, snd, how);
- }
- break;
- }
- case ID_LI:
- {
- Library *li = (Library *)id;
- BKE_reportf(reports, RPT_ERROR, "Cannot unpack individual Library file, '%s'", li->name);
- break;
- }
- default:
- break;
- }
+ switch (GS(id->name)) {
+ case ID_IM: {
+ Image *ima = (Image *)id;
+ if (BKE_image_has_packedfile(ima)) {
+ unpackImage(bmain, reports, ima, how);
+ }
+ break;
+ }
+ case ID_VF: {
+ VFont *vf = (VFont *)id;
+ if (vf->packedfile) {
+ unpackVFont(bmain, reports, vf, how);
+ }
+ break;
+ }
+ case ID_SO: {
+ bSound *snd = (bSound *)id;
+ if (snd->packedfile) {
+ unpackSound(bmain, reports, snd, how);
+ }
+ break;
+ }
+ case ID_LI: {
+ Library *li = (Library *)id;
+ BKE_reportf(reports, RPT_ERROR, "Cannot unpack individual Library file, '%s'", li->name);
+ break;
+ }
+ default:
+ break;
+ }
}
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index be0d176dddc..22586c674db 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -81,350 +81,354 @@ static eOverlayControlFlags overlay_flags = 0;
void BKE_paint_invalidate_overlay_tex(Scene *scene, ViewLayer *view_layer, const Tex *tex)
{
- Paint *p = BKE_paint_get_active(scene, view_layer);
- Brush *br = p->brush;
+ Paint *p = BKE_paint_get_active(scene, view_layer);
+ Brush *br = p->brush;
- if (!br)
- return;
+ if (!br)
+ return;
- if (br->mtex.tex == tex)
- overlay_flags |= PAINT_OVERLAY_INVALID_TEXTURE_PRIMARY;
- if (br->mask_mtex.tex == tex)
- overlay_flags |= PAINT_OVERLAY_INVALID_TEXTURE_SECONDARY;
+ if (br->mtex.tex == tex)
+ overlay_flags |= PAINT_OVERLAY_INVALID_TEXTURE_PRIMARY;
+ if (br->mask_mtex.tex == tex)
+ overlay_flags |= PAINT_OVERLAY_INVALID_TEXTURE_SECONDARY;
}
void BKE_paint_invalidate_cursor_overlay(Scene *scene, ViewLayer *view_layer, CurveMapping *curve)
{
- Paint *p = BKE_paint_get_active(scene, view_layer);
- Brush *br = p->brush;
+ Paint *p = BKE_paint_get_active(scene, view_layer);
+ Brush *br = p->brush;
- if (br && br->curve == curve)
- overlay_flags |= PAINT_OVERLAY_INVALID_CURVE;
+ if (br && br->curve == curve)
+ overlay_flags |= PAINT_OVERLAY_INVALID_CURVE;
}
void BKE_paint_invalidate_overlay_all(void)
{
- overlay_flags |= (PAINT_OVERLAY_INVALID_TEXTURE_SECONDARY |
- PAINT_OVERLAY_INVALID_TEXTURE_PRIMARY |
- PAINT_OVERLAY_INVALID_CURVE);
+ overlay_flags |= (PAINT_OVERLAY_INVALID_TEXTURE_SECONDARY |
+ PAINT_OVERLAY_INVALID_TEXTURE_PRIMARY | PAINT_OVERLAY_INVALID_CURVE);
}
eOverlayControlFlags BKE_paint_get_overlay_flags(void)
{
- return overlay_flags;
+ return overlay_flags;
}
void BKE_paint_set_overlay_override(eOverlayFlags flags)
{
- if (flags & BRUSH_OVERLAY_OVERRIDE_MASK) {
- if (flags & BRUSH_OVERLAY_CURSOR_OVERRIDE_ON_STROKE)
- overlay_flags |= PAINT_OVERLAY_OVERRIDE_CURSOR;
- if (flags & BRUSH_OVERLAY_PRIMARY_OVERRIDE_ON_STROKE)
- overlay_flags |= PAINT_OVERLAY_OVERRIDE_PRIMARY;
- if (flags & BRUSH_OVERLAY_SECONDARY_OVERRIDE_ON_STROKE)
- overlay_flags |= PAINT_OVERLAY_OVERRIDE_SECONDARY;
- }
- else {
- overlay_flags &= ~(PAINT_OVERRIDE_MASK);
- }
+ if (flags & BRUSH_OVERLAY_OVERRIDE_MASK) {
+ if (flags & BRUSH_OVERLAY_CURSOR_OVERRIDE_ON_STROKE)
+ overlay_flags |= PAINT_OVERLAY_OVERRIDE_CURSOR;
+ if (flags & BRUSH_OVERLAY_PRIMARY_OVERRIDE_ON_STROKE)
+ overlay_flags |= PAINT_OVERLAY_OVERRIDE_PRIMARY;
+ if (flags & BRUSH_OVERLAY_SECONDARY_OVERRIDE_ON_STROKE)
+ overlay_flags |= PAINT_OVERLAY_OVERRIDE_SECONDARY;
+ }
+ else {
+ overlay_flags &= ~(PAINT_OVERRIDE_MASK);
+ }
}
void BKE_paint_reset_overlay_invalid(eOverlayControlFlags flag)
{
- overlay_flags &= ~(flag);
+ overlay_flags &= ~(flag);
}
Paint *BKE_paint_get_active_from_paintmode(Scene *sce, ePaintMode mode)
{
- if (sce) {
- ToolSettings *ts = sce->toolsettings;
-
- switch (mode) {
- case PAINT_MODE_SCULPT:
- return &ts->sculpt->paint;
- case PAINT_MODE_VERTEX:
- return &ts->vpaint->paint;
- case PAINT_MODE_WEIGHT:
- return &ts->wpaint->paint;
- case PAINT_MODE_TEXTURE_2D:
- case PAINT_MODE_TEXTURE_3D:
- return &ts->imapaint.paint;
- case PAINT_MODE_SCULPT_UV:
- return &ts->uvsculpt->paint;
- case PAINT_MODE_GPENCIL:
- return &ts->gp_paint->paint;
- case PAINT_MODE_INVALID:
- return NULL;
- default:
- return &ts->imapaint.paint;
- }
- }
-
- return NULL;
+ if (sce) {
+ ToolSettings *ts = sce->toolsettings;
+
+ switch (mode) {
+ case PAINT_MODE_SCULPT:
+ return &ts->sculpt->paint;
+ case PAINT_MODE_VERTEX:
+ return &ts->vpaint->paint;
+ case PAINT_MODE_WEIGHT:
+ return &ts->wpaint->paint;
+ case PAINT_MODE_TEXTURE_2D:
+ case PAINT_MODE_TEXTURE_3D:
+ return &ts->imapaint.paint;
+ case PAINT_MODE_SCULPT_UV:
+ return &ts->uvsculpt->paint;
+ case PAINT_MODE_GPENCIL:
+ return &ts->gp_paint->paint;
+ case PAINT_MODE_INVALID:
+ return NULL;
+ default:
+ return &ts->imapaint.paint;
+ }
+ }
+
+ return NULL;
}
const EnumPropertyItem *BKE_paint_get_tool_enum_from_paintmode(ePaintMode mode)
{
- switch (mode) {
- case PAINT_MODE_SCULPT:
- return rna_enum_brush_sculpt_tool_items;
- case PAINT_MODE_VERTEX:
- return rna_enum_brush_vertex_tool_items;
- case PAINT_MODE_WEIGHT:
- return rna_enum_brush_weight_tool_items;
- case PAINT_MODE_TEXTURE_2D:
- case PAINT_MODE_TEXTURE_3D:
- return rna_enum_brush_image_tool_items;
- case PAINT_MODE_SCULPT_UV:
- return NULL;
- case PAINT_MODE_GPENCIL:
- return rna_enum_brush_gpencil_types_items;
- case PAINT_MODE_INVALID:
- break;
- }
- return NULL;
+ switch (mode) {
+ case PAINT_MODE_SCULPT:
+ return rna_enum_brush_sculpt_tool_items;
+ case PAINT_MODE_VERTEX:
+ return rna_enum_brush_vertex_tool_items;
+ case PAINT_MODE_WEIGHT:
+ return rna_enum_brush_weight_tool_items;
+ case PAINT_MODE_TEXTURE_2D:
+ case PAINT_MODE_TEXTURE_3D:
+ return rna_enum_brush_image_tool_items;
+ case PAINT_MODE_SCULPT_UV:
+ return NULL;
+ case PAINT_MODE_GPENCIL:
+ return rna_enum_brush_gpencil_types_items;
+ case PAINT_MODE_INVALID:
+ break;
+ }
+ return NULL;
}
const char *BKE_paint_get_tool_prop_id_from_paintmode(ePaintMode mode)
{
- switch (mode) {
- case PAINT_MODE_SCULPT: return "sculpt_tool";
- case PAINT_MODE_VERTEX: return "vertex_tool";
- case PAINT_MODE_WEIGHT: return "weight_tool";
- case PAINT_MODE_TEXTURE_2D:
- case PAINT_MODE_TEXTURE_3D: return "image_tool";
- case PAINT_MODE_GPENCIL: return "gpencil_tool";
- default:
- /* invalid paint mode */
- return NULL;
- }
+ switch (mode) {
+ case PAINT_MODE_SCULPT:
+ return "sculpt_tool";
+ case PAINT_MODE_VERTEX:
+ return "vertex_tool";
+ case PAINT_MODE_WEIGHT:
+ return "weight_tool";
+ case PAINT_MODE_TEXTURE_2D:
+ case PAINT_MODE_TEXTURE_3D:
+ return "image_tool";
+ case PAINT_MODE_GPENCIL:
+ return "gpencil_tool";
+ default:
+ /* invalid paint mode */
+ return NULL;
+ }
}
Paint *BKE_paint_get_active(Scene *sce, ViewLayer *view_layer)
{
- if (sce && view_layer) {
- ToolSettings *ts = sce->toolsettings;
-
- if (view_layer->basact && view_layer->basact->object) {
- switch (view_layer->basact->object->mode) {
- case OB_MODE_SCULPT:
- return &ts->sculpt->paint;
- case OB_MODE_VERTEX_PAINT:
- return &ts->vpaint->paint;
- case OB_MODE_WEIGHT_PAINT:
- return &ts->wpaint->paint;
- case OB_MODE_TEXTURE_PAINT:
- return &ts->imapaint.paint;
- case OB_MODE_PAINT_GPENCIL:
- return &ts->gp_paint->paint;
- case OB_MODE_EDIT:
- if (ts->use_uv_sculpt)
- return &ts->uvsculpt->paint;
- return &ts->imapaint.paint;
- default:
- break;
- }
- }
-
- /* default to image paint */
- return &ts->imapaint.paint;
- }
-
- return NULL;
+ if (sce && view_layer) {
+ ToolSettings *ts = sce->toolsettings;
+
+ if (view_layer->basact && view_layer->basact->object) {
+ switch (view_layer->basact->object->mode) {
+ case OB_MODE_SCULPT:
+ return &ts->sculpt->paint;
+ case OB_MODE_VERTEX_PAINT:
+ return &ts->vpaint->paint;
+ case OB_MODE_WEIGHT_PAINT:
+ return &ts->wpaint->paint;
+ case OB_MODE_TEXTURE_PAINT:
+ return &ts->imapaint.paint;
+ case OB_MODE_PAINT_GPENCIL:
+ return &ts->gp_paint->paint;
+ case OB_MODE_EDIT:
+ if (ts->use_uv_sculpt)
+ return &ts->uvsculpt->paint;
+ return &ts->imapaint.paint;
+ default:
+ break;
+ }
+ }
+
+ /* default to image paint */
+ return &ts->imapaint.paint;
+ }
+
+ return NULL;
}
Paint *BKE_paint_get_active_from_context(const bContext *C)
{
- Scene *sce = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- SpaceImage *sima;
+ Scene *sce = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ SpaceImage *sima;
- if (sce && view_layer) {
- ToolSettings *ts = sce->toolsettings;
- Object *obact = NULL;
+ if (sce && view_layer) {
+ ToolSettings *ts = sce->toolsettings;
+ Object *obact = NULL;
- if (view_layer->basact && view_layer->basact->object)
- obact = view_layer->basact->object;
+ if (view_layer->basact && view_layer->basact->object)
+ obact = view_layer->basact->object;
- if ((sima = CTX_wm_space_image(C)) != NULL) {
- if (obact && obact->mode == OB_MODE_EDIT) {
- if (sima->mode == SI_MODE_PAINT)
- return &ts->imapaint.paint;
- else if (ts->use_uv_sculpt)
- return &ts->uvsculpt->paint;
- }
- else {
- return &ts->imapaint.paint;
- }
- }
- else {
- return BKE_paint_get_active(sce, view_layer);
- }
- }
+ if ((sima = CTX_wm_space_image(C)) != NULL) {
+ if (obact && obact->mode == OB_MODE_EDIT) {
+ if (sima->mode == SI_MODE_PAINT)
+ return &ts->imapaint.paint;
+ else if (ts->use_uv_sculpt)
+ return &ts->uvsculpt->paint;
+ }
+ else {
+ return &ts->imapaint.paint;
+ }
+ }
+ else {
+ return BKE_paint_get_active(sce, view_layer);
+ }
+ }
- return NULL;
+ return NULL;
}
ePaintMode BKE_paintmode_get_active_from_context(const bContext *C)
{
- Scene *sce = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- SpaceImage *sima;
-
- if (sce && view_layer) {
- ToolSettings *ts = sce->toolsettings;
- Object *obact = NULL;
-
- if (view_layer->basact && view_layer->basact->object)
- obact = view_layer->basact->object;
-
- if ((sima = CTX_wm_space_image(C)) != NULL) {
- if (obact && obact->mode == OB_MODE_EDIT) {
- if (sima->mode == SI_MODE_PAINT)
- return PAINT_MODE_TEXTURE_2D;
- else if (ts->use_uv_sculpt)
- return PAINT_MODE_SCULPT_UV;
- }
- else {
- return PAINT_MODE_TEXTURE_2D;
- }
- }
- else if (obact) {
- switch (obact->mode) {
- case OB_MODE_SCULPT:
- return PAINT_MODE_SCULPT;
- case OB_MODE_VERTEX_PAINT:
- return PAINT_MODE_VERTEX;
- case OB_MODE_WEIGHT_PAINT:
- return PAINT_MODE_WEIGHT;
- case OB_MODE_TEXTURE_PAINT:
- return PAINT_MODE_TEXTURE_3D;
- case OB_MODE_EDIT:
- if (ts->use_uv_sculpt)
- return PAINT_MODE_SCULPT_UV;
- return PAINT_MODE_TEXTURE_2D;
- default:
- return PAINT_MODE_TEXTURE_2D;
- }
- }
- else {
- /* default to image paint */
- return PAINT_MODE_TEXTURE_2D;
- }
- }
-
- return PAINT_MODE_INVALID;
+ Scene *sce = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ SpaceImage *sima;
+
+ if (sce && view_layer) {
+ ToolSettings *ts = sce->toolsettings;
+ Object *obact = NULL;
+
+ if (view_layer->basact && view_layer->basact->object)
+ obact = view_layer->basact->object;
+
+ if ((sima = CTX_wm_space_image(C)) != NULL) {
+ if (obact && obact->mode == OB_MODE_EDIT) {
+ if (sima->mode == SI_MODE_PAINT)
+ return PAINT_MODE_TEXTURE_2D;
+ else if (ts->use_uv_sculpt)
+ return PAINT_MODE_SCULPT_UV;
+ }
+ else {
+ return PAINT_MODE_TEXTURE_2D;
+ }
+ }
+ else if (obact) {
+ switch (obact->mode) {
+ case OB_MODE_SCULPT:
+ return PAINT_MODE_SCULPT;
+ case OB_MODE_VERTEX_PAINT:
+ return PAINT_MODE_VERTEX;
+ case OB_MODE_WEIGHT_PAINT:
+ return PAINT_MODE_WEIGHT;
+ case OB_MODE_TEXTURE_PAINT:
+ return PAINT_MODE_TEXTURE_3D;
+ case OB_MODE_EDIT:
+ if (ts->use_uv_sculpt)
+ return PAINT_MODE_SCULPT_UV;
+ return PAINT_MODE_TEXTURE_2D;
+ default:
+ return PAINT_MODE_TEXTURE_2D;
+ }
+ }
+ else {
+ /* default to image paint */
+ return PAINT_MODE_TEXTURE_2D;
+ }
+ }
+
+ return PAINT_MODE_INVALID;
}
ePaintMode BKE_paintmode_get_from_tool(const struct bToolRef *tref)
{
- if (tref->space_type == SPACE_VIEW3D) {
- switch (tref->mode) {
- case CTX_MODE_SCULPT:
- return PAINT_MODE_SCULPT;
- case CTX_MODE_PAINT_VERTEX:
- return PAINT_MODE_VERTEX;
- case CTX_MODE_PAINT_WEIGHT:
- return PAINT_MODE_WEIGHT;
- case CTX_MODE_PAINT_GPENCIL:
- return PAINT_MODE_GPENCIL;
- case CTX_MODE_PAINT_TEXTURE:
- return PAINT_MODE_TEXTURE_3D;
- }
- }
- else if (tref->space_type == SPACE_IMAGE) {
- switch (tref->mode) {
- case SI_MODE_PAINT:
- return PAINT_MODE_TEXTURE_2D;
- }
- }
-
- return PAINT_MODE_INVALID;
+ if (tref->space_type == SPACE_VIEW3D) {
+ switch (tref->mode) {
+ case CTX_MODE_SCULPT:
+ return PAINT_MODE_SCULPT;
+ case CTX_MODE_PAINT_VERTEX:
+ return PAINT_MODE_VERTEX;
+ case CTX_MODE_PAINT_WEIGHT:
+ return PAINT_MODE_WEIGHT;
+ case CTX_MODE_PAINT_GPENCIL:
+ return PAINT_MODE_GPENCIL;
+ case CTX_MODE_PAINT_TEXTURE:
+ return PAINT_MODE_TEXTURE_3D;
+ }
+ }
+ else if (tref->space_type == SPACE_IMAGE) {
+ switch (tref->mode) {
+ case SI_MODE_PAINT:
+ return PAINT_MODE_TEXTURE_2D;
+ }
+ }
+
+ return PAINT_MODE_INVALID;
}
Brush *BKE_paint_brush(Paint *p)
{
- return p ? p->brush : NULL;
+ return p ? p->brush : NULL;
}
void BKE_paint_brush_set(Paint *p, Brush *br)
{
- if (p) {
- id_us_min((ID *)p->brush);
- id_us_plus((ID *)br);
- p->brush = br;
+ if (p) {
+ id_us_min((ID *)p->brush);
+ id_us_plus((ID *)br);
+ p->brush = br;
- BKE_paint_toolslots_brush_update(p);
- }
+ BKE_paint_toolslots_brush_update(p);
+ }
}
void BKE_paint_runtime_init(const ToolSettings *ts, Paint *paint)
{
- if (paint == &ts->imapaint.paint) {
- paint->runtime.tool_offset = offsetof(Brush, imagepaint_tool);
- paint->runtime.ob_mode = OB_MODE_TEXTURE_PAINT;
- }
- else if (paint == &ts->sculpt->paint) {
- paint->runtime.tool_offset = offsetof(Brush, sculpt_tool);
- paint->runtime.ob_mode = OB_MODE_SCULPT;
- }
- else if (paint == &ts->vpaint->paint) {
- paint->runtime.tool_offset = offsetof(Brush, vertexpaint_tool);
- paint->runtime.ob_mode = OB_MODE_VERTEX_PAINT;
- }
- else if (paint == &ts->wpaint->paint) {
- paint->runtime.tool_offset = offsetof(Brush, weightpaint_tool);
- paint->runtime.ob_mode = OB_MODE_WEIGHT_PAINT;
- }
- else if (paint == &ts->gp_paint->paint) {
- paint->runtime.tool_offset = offsetof(Brush, gpencil_tool);
- paint->runtime.ob_mode = OB_MODE_PAINT_GPENCIL;
- }
- else if (paint == &ts->uvsculpt->paint) {
- /* We don't use these yet. */
- paint->runtime.tool_offset = 0;
- paint->runtime.ob_mode = 0;
- }
- else {
- BLI_assert(0);
- }
+ if (paint == &ts->imapaint.paint) {
+ paint->runtime.tool_offset = offsetof(Brush, imagepaint_tool);
+ paint->runtime.ob_mode = OB_MODE_TEXTURE_PAINT;
+ }
+ else if (paint == &ts->sculpt->paint) {
+ paint->runtime.tool_offset = offsetof(Brush, sculpt_tool);
+ paint->runtime.ob_mode = OB_MODE_SCULPT;
+ }
+ else if (paint == &ts->vpaint->paint) {
+ paint->runtime.tool_offset = offsetof(Brush, vertexpaint_tool);
+ paint->runtime.ob_mode = OB_MODE_VERTEX_PAINT;
+ }
+ else if (paint == &ts->wpaint->paint) {
+ paint->runtime.tool_offset = offsetof(Brush, weightpaint_tool);
+ paint->runtime.ob_mode = OB_MODE_WEIGHT_PAINT;
+ }
+ else if (paint == &ts->gp_paint->paint) {
+ paint->runtime.tool_offset = offsetof(Brush, gpencil_tool);
+ paint->runtime.ob_mode = OB_MODE_PAINT_GPENCIL;
+ }
+ else if (paint == &ts->uvsculpt->paint) {
+ /* We don't use these yet. */
+ paint->runtime.tool_offset = 0;
+ paint->runtime.ob_mode = 0;
+ }
+ else {
+ BLI_assert(0);
+ }
}
uint BKE_paint_get_brush_tool_offset_from_paintmode(const ePaintMode mode)
{
- switch (mode) {
- case PAINT_MODE_TEXTURE_2D:
- case PAINT_MODE_TEXTURE_3D:
- return offsetof(Brush, imagepaint_tool);
- case PAINT_MODE_SCULPT:
- return offsetof(Brush, sculpt_tool);
- case PAINT_MODE_VERTEX:
- return offsetof(Brush, vertexpaint_tool);
- case PAINT_MODE_WEIGHT:
- return offsetof(Brush, weightpaint_tool);
- case PAINT_MODE_GPENCIL:
- return offsetof(Brush, gpencil_tool);
- case PAINT_MODE_SCULPT_UV:
- case PAINT_MODE_INVALID:
- break; /* We don't use these yet. */
- }
- return 0;
+ switch (mode) {
+ case PAINT_MODE_TEXTURE_2D:
+ case PAINT_MODE_TEXTURE_3D:
+ return offsetof(Brush, imagepaint_tool);
+ case PAINT_MODE_SCULPT:
+ return offsetof(Brush, sculpt_tool);
+ case PAINT_MODE_VERTEX:
+ return offsetof(Brush, vertexpaint_tool);
+ case PAINT_MODE_WEIGHT:
+ return offsetof(Brush, weightpaint_tool);
+ case PAINT_MODE_GPENCIL:
+ return offsetof(Brush, gpencil_tool);
+ case PAINT_MODE_SCULPT_UV:
+ case PAINT_MODE_INVALID:
+ break; /* We don't use these yet. */
+ }
+ return 0;
}
/** Free (or release) any data used by this paint curve (does not free the pcurve itself). */
void BKE_paint_curve_free(PaintCurve *pc)
{
- MEM_SAFE_FREE(pc->points);
- pc->tot_points = 0;
+ MEM_SAFE_FREE(pc->points);
+ pc->tot_points = 0;
}
PaintCurve *BKE_paint_curve_add(Main *bmain, const char *name)
{
- PaintCurve *pc;
+ PaintCurve *pc;
- pc = BKE_libblock_alloc(bmain, ID_PC, name, 0);
+ pc = BKE_libblock_alloc(bmain, ID_PC, name, 0);
- return pc;
+ return pc;
}
/**
@@ -435,79 +439,83 @@ PaintCurve *BKE_paint_curve_add(Main *bmain, const char *name)
*
* \param flag: Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
*/
-void BKE_paint_curve_copy_data(Main *UNUSED(bmain), PaintCurve *pc_dst, const PaintCurve *pc_src, const int UNUSED(flag))
+void BKE_paint_curve_copy_data(Main *UNUSED(bmain),
+ PaintCurve *pc_dst,
+ const PaintCurve *pc_src,
+ const int UNUSED(flag))
{
- if (pc_src->tot_points != 0) {
- pc_dst->points = MEM_dupallocN(pc_src->points);
- }
+ if (pc_src->tot_points != 0) {
+ pc_dst->points = MEM_dupallocN(pc_src->points);
+ }
}
PaintCurve *BKE_paint_curve_copy(Main *bmain, const PaintCurve *pc)
{
- PaintCurve *pc_copy;
- BKE_id_copy(bmain, &pc->id, (ID **)&pc_copy);
- return pc_copy;
+ PaintCurve *pc_copy;
+ BKE_id_copy(bmain, &pc->id, (ID **)&pc_copy);
+ return pc_copy;
}
void BKE_paint_curve_make_local(Main *bmain, PaintCurve *pc, const bool lib_local)
{
- BKE_id_make_local_generic(bmain, &pc->id, true, lib_local);
+ BKE_id_make_local_generic(bmain, &pc->id, true, lib_local);
}
Palette *BKE_paint_palette(Paint *p)
{
- return p ? p->palette : NULL;
+ return p ? p->palette : NULL;
}
void BKE_paint_palette_set(Paint *p, Palette *palette)
{
- if (p) {
- id_us_min((ID *)p->palette);
- p->palette = palette;
- id_us_plus((ID *)p->palette);
- }
+ if (p) {
+ id_us_min((ID *)p->palette);
+ p->palette = palette;
+ id_us_plus((ID *)p->palette);
+ }
}
void BKE_paint_curve_set(Brush *br, PaintCurve *pc)
{
- if (br) {
- id_us_min((ID *)br->paint_curve);
- br->paint_curve = pc;
- id_us_plus((ID *)br->paint_curve);
- }
+ if (br) {
+ id_us_min((ID *)br->paint_curve);
+ br->paint_curve = pc;
+ id_us_plus((ID *)br->paint_curve);
+ }
}
void BKE_paint_curve_clamp_endpoint_add_index(PaintCurve *pc, const int add_index)
{
- pc->add_index = (add_index || pc->tot_points == 1) ? (add_index + 1) : 0;
+ pc->add_index = (add_index || pc->tot_points == 1) ? (add_index + 1) : 0;
}
/* remove colour from palette. Must be certain color is inside the palette! */
void BKE_palette_color_remove(Palette *palette, PaletteColor *color)
{
- if (BLI_listbase_count_at_most(&palette->colors, palette->active_color) == palette->active_color) {
- palette->active_color--;
- }
+ if (BLI_listbase_count_at_most(&palette->colors, palette->active_color) ==
+ palette->active_color) {
+ palette->active_color--;
+ }
- BLI_remlink(&palette->colors, color);
+ BLI_remlink(&palette->colors, color);
- if (palette->active_color < 0 && !BLI_listbase_is_empty(&palette->colors)) {
- palette->active_color = 0;
- }
+ if (palette->active_color < 0 && !BLI_listbase_is_empty(&palette->colors)) {
+ palette->active_color = 0;
+ }
- MEM_freeN(color);
+ MEM_freeN(color);
}
void BKE_palette_clear(Palette *palette)
{
- BLI_freelistN(&palette->colors);
- palette->active_color = 0;
+ BLI_freelistN(&palette->colors);
+ palette->active_color = 0;
}
Palette *BKE_palette_add(Main *bmain, const char *name)
{
- Palette *palette = BKE_id_new(bmain, ID_PAL, name);
- return palette;
+ Palette *palette = BKE_id_new(bmain, ID_PAL, name);
+ return palette;
}
/**
@@ -518,67 +526,64 @@ Palette *BKE_palette_add(Main *bmain, const char *name)
*
* \param flag: Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
*/
-void BKE_palette_copy_data(Main *UNUSED(bmain), Palette *palette_dst, const Palette *palette_src, const int UNUSED(flag))
+void BKE_palette_copy_data(Main *UNUSED(bmain),
+ Palette *palette_dst,
+ const Palette *palette_src,
+ const int UNUSED(flag))
{
- BLI_duplicatelist(&palette_dst->colors, &palette_src->colors);
+ BLI_duplicatelist(&palette_dst->colors, &palette_src->colors);
}
Palette *BKE_palette_copy(Main *bmain, const Palette *palette)
{
- Palette *palette_copy;
- BKE_id_copy(bmain, &palette->id, (ID **)&palette_copy);
- return palette_copy;
+ Palette *palette_copy;
+ BKE_id_copy(bmain, &palette->id, (ID **)&palette_copy);
+ return palette_copy;
}
void BKE_palette_make_local(Main *bmain, Palette *palette, const bool lib_local)
{
- BKE_id_make_local_generic(bmain, &palette->id, true, lib_local);
+ BKE_id_make_local_generic(bmain, &palette->id, true, lib_local);
}
void BKE_palette_init(Palette *palette)
{
- /* Enable fake user by default. */
- id_fake_user_set(&palette->id);
+ /* Enable fake user by default. */
+ id_fake_user_set(&palette->id);
}
/** Free (or release) any data used by this palette (does not free the palette itself). */
void BKE_palette_free(Palette *palette)
{
- BLI_freelistN(&palette->colors);
+ BLI_freelistN(&palette->colors);
}
PaletteColor *BKE_palette_color_add(Palette *palette)
{
- PaletteColor *color = MEM_callocN(sizeof(*color), "Palette Color");
- BLI_addtail(&palette->colors, color);
- return color;
+ PaletteColor *color = MEM_callocN(sizeof(*color), "Palette Color");
+ BLI_addtail(&palette->colors, color);
+ return color;
}
bool BKE_palette_is_empty(const struct Palette *palette)
{
- return BLI_listbase_is_empty(&palette->colors);
+ return BLI_listbase_is_empty(&palette->colors);
}
/* are we in vertex paint or weight paint face select mode? */
bool BKE_paint_select_face_test(Object *ob)
{
- return ( (ob != NULL) &&
- (ob->type == OB_MESH) &&
- (ob->data != NULL) &&
- (((Mesh *)ob->data)->editflag & ME_EDIT_PAINT_FACE_SEL) &&
- (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT))
- );
+ return ((ob != NULL) && (ob->type == OB_MESH) && (ob->data != NULL) &&
+ (((Mesh *)ob->data)->editflag & ME_EDIT_PAINT_FACE_SEL) &&
+ (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT)));
}
/* are we in weight paint vertex select mode? */
bool BKE_paint_select_vert_test(Object *ob)
{
- return ( (ob != NULL) &&
- (ob->type == OB_MESH) &&
- (ob->data != NULL) &&
- (((Mesh *)ob->data)->editflag & ME_EDIT_PAINT_VERT_SEL) &&
- (ob->mode & OB_MODE_WEIGHT_PAINT || ob->mode & OB_MODE_VERTEX_PAINT)
- );
+ return ((ob != NULL) && (ob->type == OB_MESH) && (ob->data != NULL) &&
+ (((Mesh *)ob->data)->editflag & ME_EDIT_PAINT_VERT_SEL) &&
+ (ob->mode & OB_MODE_WEIGHT_PAINT || ob->mode & OB_MODE_VERTEX_PAINT));
}
/**
@@ -587,43 +592,42 @@ bool BKE_paint_select_vert_test(Object *ob)
*/
bool BKE_paint_select_elem_test(Object *ob)
{
- return (BKE_paint_select_vert_test(ob) ||
- BKE_paint_select_face_test(ob));
+ return (BKE_paint_select_vert_test(ob) || BKE_paint_select_face_test(ob));
}
void BKE_paint_cavity_curve_preset(Paint *p, int preset)
{
- CurveMap *cm = NULL;
+ CurveMap *cm = NULL;
- if (!p->cavity_curve)
- p->cavity_curve = curvemapping_add(1, 0, 0, 1, 1);
+ if (!p->cavity_curve)
+ p->cavity_curve = curvemapping_add(1, 0, 0, 1, 1);
- cm = p->cavity_curve->cm;
- cm->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
+ cm = p->cavity_curve->cm;
+ cm->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
- p->cavity_curve->preset = preset;
- curvemap_reset(cm, &p->cavity_curve->clipr, p->cavity_curve->preset, CURVEMAP_SLOPE_POSITIVE);
- curvemapping_changed(p->cavity_curve, false);
+ p->cavity_curve->preset = preset;
+ curvemap_reset(cm, &p->cavity_curve->clipr, p->cavity_curve->preset, CURVEMAP_SLOPE_POSITIVE);
+ curvemapping_changed(p->cavity_curve, false);
}
eObjectMode BKE_paint_object_mode_from_paintmode(ePaintMode mode)
{
- switch (mode) {
- case PAINT_MODE_SCULPT:
- return OB_MODE_SCULPT;
- case PAINT_MODE_VERTEX:
- return OB_MODE_VERTEX_PAINT;
- case PAINT_MODE_WEIGHT:
- return OB_MODE_WEIGHT_PAINT;
- case PAINT_MODE_TEXTURE_2D:
- case PAINT_MODE_TEXTURE_3D:
- return OB_MODE_TEXTURE_PAINT;
- case PAINT_MODE_SCULPT_UV:
- return OB_MODE_EDIT;
- case PAINT_MODE_INVALID:
- default:
- return 0;
- }
+ switch (mode) {
+ case PAINT_MODE_SCULPT:
+ return OB_MODE_SCULPT;
+ case PAINT_MODE_VERTEX:
+ return OB_MODE_VERTEX_PAINT;
+ case PAINT_MODE_WEIGHT:
+ return OB_MODE_WEIGHT_PAINT;
+ case PAINT_MODE_TEXTURE_2D:
+ case PAINT_MODE_TEXTURE_3D:
+ return OB_MODE_TEXTURE_PAINT;
+ case PAINT_MODE_SCULPT_UV:
+ return OB_MODE_EDIT;
+ case PAINT_MODE_INVALID:
+ default:
+ return 0;
+ }
}
/**
@@ -631,94 +635,91 @@ eObjectMode BKE_paint_object_mode_from_paintmode(ePaintMode mode)
*/
bool BKE_paint_ensure(const ToolSettings *ts, struct Paint **r_paint)
{
- Paint *paint = NULL;
- if (*r_paint) {
- /* Note: 'ts->imapaint' is ignored, it's not allocated. */
- BLI_assert(
- ELEM(*r_paint,
- &ts->gp_paint->paint,
- &ts->sculpt->paint,
- &ts->vpaint->paint,
- &ts->wpaint->paint,
- &ts->uvsculpt->paint));
+ Paint *paint = NULL;
+ if (*r_paint) {
+ /* Note: 'ts->imapaint' is ignored, it's not allocated. */
+ BLI_assert(ELEM(*r_paint,
+ &ts->gp_paint->paint,
+ &ts->sculpt->paint,
+ &ts->vpaint->paint,
+ &ts->wpaint->paint,
+ &ts->uvsculpt->paint));
#ifdef DEBUG
- struct Paint paint_test = **r_paint;
- BKE_paint_runtime_init(ts, *r_paint);
- /* Swap so debug doesn't hide errors when release fails. */
- SWAP(Paint, **r_paint, paint_test);
- BLI_assert(paint_test.runtime.ob_mode == (*r_paint)->runtime.ob_mode);
- BLI_assert(paint_test.runtime.tool_offset == (*r_paint)->runtime.tool_offset);
+ struct Paint paint_test = **r_paint;
+ BKE_paint_runtime_init(ts, *r_paint);
+ /* Swap so debug doesn't hide errors when release fails. */
+ SWAP(Paint, **r_paint, paint_test);
+ BLI_assert(paint_test.runtime.ob_mode == (*r_paint)->runtime.ob_mode);
+ BLI_assert(paint_test.runtime.tool_offset == (*r_paint)->runtime.tool_offset);
#endif
- return true;
- }
+ return true;
+ }
- if (((VPaint **)r_paint == &ts->vpaint) ||
- ((VPaint **)r_paint == &ts->wpaint))
- {
- VPaint *data = MEM_callocN(sizeof(*data), __func__);
- paint = &data->paint;
- }
- else if ((Sculpt **)r_paint == &ts->sculpt) {
- Sculpt *data = MEM_callocN(sizeof(*data), __func__);
- paint = &data->paint;
+ if (((VPaint **)r_paint == &ts->vpaint) || ((VPaint **)r_paint == &ts->wpaint)) {
+ VPaint *data = MEM_callocN(sizeof(*data), __func__);
+ paint = &data->paint;
+ }
+ else if ((Sculpt **)r_paint == &ts->sculpt) {
+ Sculpt *data = MEM_callocN(sizeof(*data), __func__);
+ paint = &data->paint;
- /* Turn on X plane mirror symmetry by default */
- paint->symmetry_flags |= PAINT_SYMM_X;
+ /* Turn on X plane mirror symmetry by default */
+ paint->symmetry_flags |= PAINT_SYMM_X;
- /* Make sure at least dyntopo subdivision is enabled */
- data->flags |= SCULPT_DYNTOPO_SUBDIVIDE | SCULPT_DYNTOPO_COLLAPSE;
- }
- else if ((GpPaint **)r_paint == &ts->gp_paint) {
- GpPaint *data = MEM_callocN(sizeof(*data), __func__);
- paint = &data->paint;
- }
- else if ((UvSculpt **)r_paint == &ts->uvsculpt) {
- UvSculpt *data = MEM_callocN(sizeof(*data), __func__);
- paint = &data->paint;
- }
+ /* Make sure at least dyntopo subdivision is enabled */
+ data->flags |= SCULPT_DYNTOPO_SUBDIVIDE | SCULPT_DYNTOPO_COLLAPSE;
+ }
+ else if ((GpPaint **)r_paint == &ts->gp_paint) {
+ GpPaint *data = MEM_callocN(sizeof(*data), __func__);
+ paint = &data->paint;
+ }
+ else if ((UvSculpt **)r_paint == &ts->uvsculpt) {
+ UvSculpt *data = MEM_callocN(sizeof(*data), __func__);
+ paint = &data->paint;
+ }
- paint->flags |= PAINT_SHOW_BRUSH;
+ paint->flags |= PAINT_SHOW_BRUSH;
- *r_paint = paint;
+ *r_paint = paint;
- BKE_paint_runtime_init(ts, paint);
+ BKE_paint_runtime_init(ts, paint);
- return false;
+ return false;
}
void BKE_paint_init(Main *bmain, Scene *sce, ePaintMode mode, const char col[3])
{
- UnifiedPaintSettings *ups = &sce->toolsettings->unified_paint_settings;
- Paint *paint = BKE_paint_get_active_from_paintmode(sce, mode);
-
- /* If there's no brush, create one */
- if (PAINT_MODE_HAS_BRUSH(mode)) {
- Brush *brush = BKE_paint_brush(paint);
- if (brush == NULL) {
- eObjectMode ob_mode = BKE_paint_object_mode_from_paintmode(mode);
- brush = BKE_brush_first_search(bmain, ob_mode);
- if (!brush) {
- brush = BKE_brush_add(bmain, "Brush", ob_mode);
- id_us_min(&brush->id); /* fake user only */
- }
- BKE_paint_brush_set(paint, brush);
- }
- }
-
- memcpy(paint->paint_cursor_col, col, 3);
- paint->paint_cursor_col[3] = 128;
- ups->last_stroke_valid = false;
- zero_v3(ups->average_stroke_accum);
- ups->average_stroke_counter = 0;
- if (!paint->cavity_curve)
- BKE_paint_cavity_curve_preset(paint, CURVE_PRESET_LINE);
+ UnifiedPaintSettings *ups = &sce->toolsettings->unified_paint_settings;
+ Paint *paint = BKE_paint_get_active_from_paintmode(sce, mode);
+
+ /* If there's no brush, create one */
+ if (PAINT_MODE_HAS_BRUSH(mode)) {
+ Brush *brush = BKE_paint_brush(paint);
+ if (brush == NULL) {
+ eObjectMode ob_mode = BKE_paint_object_mode_from_paintmode(mode);
+ brush = BKE_brush_first_search(bmain, ob_mode);
+ if (!brush) {
+ brush = BKE_brush_add(bmain, "Brush", ob_mode);
+ id_us_min(&brush->id); /* fake user only */
+ }
+ BKE_paint_brush_set(paint, brush);
+ }
+ }
+
+ memcpy(paint->paint_cursor_col, col, 3);
+ paint->paint_cursor_col[3] = 128;
+ ups->last_stroke_valid = false;
+ zero_v3(ups->average_stroke_accum);
+ ups->average_stroke_counter = 0;
+ if (!paint->cavity_curve)
+ BKE_paint_cavity_curve_preset(paint, CURVE_PRESET_LINE);
}
void BKE_paint_free(Paint *paint)
{
- curvemapping_free(paint->cavity_curve);
- MEM_SAFE_FREE(paint->tool_slots);
+ curvemapping_free(paint->cavity_curve);
+ MEM_SAFE_FREE(paint->tool_slots);
}
/* called when copying scene settings, so even if 'src' and 'tar' are the same
@@ -727,78 +728,76 @@ void BKE_paint_free(Paint *paint)
* with paint_brush_set() */
void BKE_paint_copy(Paint *src, Paint *tar, const int flag)
{
- tar->brush = src->brush;
- tar->cavity_curve = curvemapping_copy(src->cavity_curve);
- tar->tool_slots = MEM_dupallocN(src->tool_slots);
+ tar->brush = src->brush;
+ tar->cavity_curve = curvemapping_copy(src->cavity_curve);
+ tar->tool_slots = MEM_dupallocN(src->tool_slots);
- if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- id_us_plus((ID *)tar->brush);
- id_us_plus((ID *)tar->palette);
- if (src->tool_slots != NULL) {
- for (int i = 0; i < tar->tool_slots_len; i++) {
- id_us_plus((ID *)tar->tool_slots[i].brush);
- }
- }
- }
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id_us_plus((ID *)tar->brush);
+ id_us_plus((ID *)tar->palette);
+ if (src->tool_slots != NULL) {
+ for (int i = 0; i < tar->tool_slots_len; i++) {
+ id_us_plus((ID *)tar->tool_slots[i].brush);
+ }
+ }
+ }
}
void BKE_paint_stroke_get_average(Scene *scene, Object *ob, float stroke[3])
{
- UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
- if (ups->last_stroke_valid && ups->average_stroke_counter > 0) {
- float fac = 1.0f / ups->average_stroke_counter;
- mul_v3_v3fl(stroke, ups->average_stroke_accum, fac);
- }
- else {
- copy_v3_v3(stroke, ob->obmat[3]);
- }
+ UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+ if (ups->last_stroke_valid && ups->average_stroke_counter > 0) {
+ float fac = 1.0f / ups->average_stroke_counter;
+ mul_v3_v3fl(stroke, ups->average_stroke_accum, fac);
+ }
+ else {
+ copy_v3_v3(stroke, ob->obmat[3]);
+ }
}
/* returns non-zero if any of the face's vertices
* are hidden, zero otherwise */
bool paint_is_face_hidden(const MLoopTri *lt, const MVert *mvert, const MLoop *mloop)
{
- return ((mvert[mloop[lt->tri[0]].v].flag & ME_HIDE) ||
- (mvert[mloop[lt->tri[1]].v].flag & ME_HIDE) ||
- (mvert[mloop[lt->tri[2]].v].flag & ME_HIDE));
+ return ((mvert[mloop[lt->tri[0]].v].flag & ME_HIDE) ||
+ (mvert[mloop[lt->tri[1]].v].flag & ME_HIDE) ||
+ (mvert[mloop[lt->tri[2]].v].flag & ME_HIDE));
}
/* returns non-zero if any of the corners of the grid
* face whose inner corner is at (x, y) are hidden,
* zero otherwise */
-bool paint_is_grid_face_hidden(const unsigned int *grid_hidden,
- int gridsize, int x, int y)
+bool paint_is_grid_face_hidden(const unsigned int *grid_hidden, int gridsize, int x, int y)
{
- /* skip face if any of its corners are hidden */
- return (BLI_BITMAP_TEST(grid_hidden, y * gridsize + x) ||
- BLI_BITMAP_TEST(grid_hidden, y * gridsize + x + 1) ||
- BLI_BITMAP_TEST(grid_hidden, (y + 1) * gridsize + x + 1) ||
- BLI_BITMAP_TEST(grid_hidden, (y + 1) * gridsize + x));
+ /* skip face if any of its corners are hidden */
+ return (BLI_BITMAP_TEST(grid_hidden, y * gridsize + x) ||
+ BLI_BITMAP_TEST(grid_hidden, y * gridsize + x + 1) ||
+ BLI_BITMAP_TEST(grid_hidden, (y + 1) * gridsize + x + 1) ||
+ BLI_BITMAP_TEST(grid_hidden, (y + 1) * gridsize + x));
}
/* Return true if all vertices in the face are visible, false otherwise */
bool paint_is_bmesh_face_hidden(BMFace *f)
{
- BMLoop *l_iter;
- BMLoop *l_first;
+ BMLoop *l_iter;
+ BMLoop *l_first;
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- if (BM_elem_flag_test(l_iter->v, BM_ELEM_HIDDEN)) {
- return true;
- }
- } while ((l_iter = l_iter->next) != l_first);
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if (BM_elem_flag_test(l_iter->v, BM_ELEM_HIDDEN)) {
+ return true;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
- return false;
+ return false;
}
-float paint_grid_paint_mask(const GridPaintMask *gpm, unsigned level,
- unsigned x, unsigned y)
+float paint_grid_paint_mask(const GridPaintMask *gpm, unsigned level, unsigned x, unsigned y)
{
- int factor = BKE_ccg_factor(level, gpm->level);
- int gridsize = BKE_ccg_gridsize(gpm->level);
+ int factor = BKE_ccg_factor(level, gpm->level);
+ int gridsize = BKE_ccg_gridsize(gpm->level);
- return gpm->data[(y * factor) * gridsize + (x * factor)];
+ return gpm->data[(y * factor) * gridsize + (x * factor)];
}
/* threshold to move before updating the brush rotation */
@@ -806,617 +805,621 @@ float paint_grid_paint_mask(const GridPaintMask *gpm, unsigned level,
void paint_update_brush_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, float rotation)
{
- if (brush->mtex.brush_angle_mode & MTEX_ANGLE_RAKE)
- ups->brush_rotation = rotation;
- else
- ups->brush_rotation = 0.0f;
+ if (brush->mtex.brush_angle_mode & MTEX_ANGLE_RAKE)
+ ups->brush_rotation = rotation;
+ else
+ ups->brush_rotation = 0.0f;
- if (brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE)
- ups->brush_rotation_sec = rotation;
- else
- ups->brush_rotation_sec = 0.0f;
+ if (brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE)
+ ups->brush_rotation_sec = rotation;
+ else
+ ups->brush_rotation_sec = 0.0f;
}
-bool paint_calculate_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, const float mouse_pos[2])
+bool paint_calculate_rake_rotation(UnifiedPaintSettings *ups,
+ Brush *brush,
+ const float mouse_pos[2])
{
- bool ok = false;
- if ((brush->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) || (brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) {
- const float r = RAKE_THRESHHOLD;
- float rotation;
+ bool ok = false;
+ if ((brush->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) ||
+ (brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) {
+ const float r = RAKE_THRESHHOLD;
+ float rotation;
- float dpos[2];
- sub_v2_v2v2(dpos, ups->last_rake, mouse_pos);
+ float dpos[2];
+ sub_v2_v2v2(dpos, ups->last_rake, mouse_pos);
- if (len_squared_v2(dpos) >= r * r) {
- rotation = atan2f(dpos[0], dpos[1]);
+ if (len_squared_v2(dpos) >= r * r) {
+ rotation = atan2f(dpos[0], dpos[1]);
- copy_v2_v2(ups->last_rake, mouse_pos);
+ copy_v2_v2(ups->last_rake, mouse_pos);
- ups->last_rake_angle = rotation;
+ ups->last_rake_angle = rotation;
- paint_update_brush_rake_rotation(ups, brush, rotation);
- ok = true;
- }
- /* make sure we reset here to the last rotation to avoid accumulating
- * values in case a random rotation is also added */
- else {
- paint_update_brush_rake_rotation(ups, brush, ups->last_rake_angle);
- ok = false;
- }
- }
- else {
- ups->brush_rotation = ups->brush_rotation_sec = 0.0f;
- ok = true;
- }
- return ok;
+ paint_update_brush_rake_rotation(ups, brush, rotation);
+ ok = true;
+ }
+ /* make sure we reset here to the last rotation to avoid accumulating
+ * values in case a random rotation is also added */
+ else {
+ paint_update_brush_rake_rotation(ups, brush, ups->last_rake_angle);
+ ok = false;
+ }
+ }
+ else {
+ ups->brush_rotation = ups->brush_rotation_sec = 0.0f;
+ ok = true;
+ }
+ return ok;
}
void BKE_sculptsession_free_deformMats(SculptSession *ss)
{
- MEM_SAFE_FREE(ss->orig_cos);
- MEM_SAFE_FREE(ss->deform_cos);
- MEM_SAFE_FREE(ss->deform_imats);
+ MEM_SAFE_FREE(ss->orig_cos);
+ MEM_SAFE_FREE(ss->deform_cos);
+ MEM_SAFE_FREE(ss->deform_imats);
}
void BKE_sculptsession_free_vwpaint_data(struct SculptSession *ss)
{
- struct SculptVertexPaintGeomMap *gmap = NULL;
- if (ss->mode_type == OB_MODE_VERTEX_PAINT) {
- gmap = &ss->mode.vpaint.gmap;
-
- MEM_SAFE_FREE(ss->mode.vpaint.previous_color);
- }
- else if (ss->mode_type == OB_MODE_WEIGHT_PAINT) {
- gmap = &ss->mode.wpaint.gmap;
-
- MEM_SAFE_FREE(ss->mode.wpaint.alpha_weight);
- if (ss->mode.wpaint.dvert_prev) {
- BKE_defvert_array_free_elems(ss->mode.wpaint.dvert_prev, ss->totvert);
- MEM_freeN(ss->mode.wpaint.dvert_prev);
- ss->mode.wpaint.dvert_prev = NULL;
- }
- }
- else {
- return;
- }
- MEM_SAFE_FREE(gmap->vert_to_loop);
- MEM_SAFE_FREE(gmap->vert_map_mem);
- MEM_SAFE_FREE(gmap->vert_to_poly);
- MEM_SAFE_FREE(gmap->poly_map_mem);
+ struct SculptVertexPaintGeomMap *gmap = NULL;
+ if (ss->mode_type == OB_MODE_VERTEX_PAINT) {
+ gmap = &ss->mode.vpaint.gmap;
+
+ MEM_SAFE_FREE(ss->mode.vpaint.previous_color);
+ }
+ else if (ss->mode_type == OB_MODE_WEIGHT_PAINT) {
+ gmap = &ss->mode.wpaint.gmap;
+
+ MEM_SAFE_FREE(ss->mode.wpaint.alpha_weight);
+ if (ss->mode.wpaint.dvert_prev) {
+ BKE_defvert_array_free_elems(ss->mode.wpaint.dvert_prev, ss->totvert);
+ MEM_freeN(ss->mode.wpaint.dvert_prev);
+ ss->mode.wpaint.dvert_prev = NULL;
+ }
+ }
+ else {
+ return;
+ }
+ MEM_SAFE_FREE(gmap->vert_to_loop);
+ MEM_SAFE_FREE(gmap->vert_map_mem);
+ MEM_SAFE_FREE(gmap->vert_to_poly);
+ MEM_SAFE_FREE(gmap->poly_map_mem);
}
/* Write out the sculpt dynamic-topology BMesh to the Mesh */
static void sculptsession_bm_to_me_update_data_only(Object *ob, bool reorder)
{
- SculptSession *ss = ob->sculpt;
-
- if (ss->bm) {
- if (ob->data) {
- BMIter iter;
- BMFace *efa;
- BM_ITER_MESH (efa, &iter, ss->bm, BM_FACES_OF_MESH) {
- BM_elem_flag_set(efa, BM_ELEM_SMOOTH, ss->bm_smooth_shading);
- }
- if (reorder)
- BM_log_mesh_elems_reorder(ss->bm, ss->bm_log);
- BM_mesh_bm_to_me(NULL, ss->bm, ob->data, (&(struct BMeshToMeshParams){.calc_object_remap = false,}));
- }
- }
+ SculptSession *ss = ob->sculpt;
+
+ if (ss->bm) {
+ if (ob->data) {
+ BMIter iter;
+ BMFace *efa;
+ BM_ITER_MESH (efa, &iter, ss->bm, BM_FACES_OF_MESH) {
+ BM_elem_flag_set(efa, BM_ELEM_SMOOTH, ss->bm_smooth_shading);
+ }
+ if (reorder)
+ BM_log_mesh_elems_reorder(ss->bm, ss->bm_log);
+ BM_mesh_bm_to_me(NULL,
+ ss->bm,
+ ob->data,
+ (&(struct BMeshToMeshParams){
+ .calc_object_remap = false,
+ }));
+ }
+ }
}
void BKE_sculptsession_bm_to_me(Object *ob, bool reorder)
{
- if (ob && ob->sculpt) {
- sculptsession_bm_to_me_update_data_only(ob, reorder);
+ if (ob && ob->sculpt) {
+ sculptsession_bm_to_me_update_data_only(ob, reorder);
- /* ensure the objects evaluated mesh doesn't hold onto arrays now realloc'd in the mesh [#34473] */
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- }
+ /* ensure the objects evaluated mesh doesn't hold onto arrays now realloc'd in the mesh [#34473] */
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
}
void BKE_sculptsession_bm_to_me_for_render(Object *object)
{
- if (object && object->sculpt) {
- if (object->sculpt->bm) {
- /* Ensure no points to old arrays are stored in DM
- *
- * Apparently, we could not use DEG_id_tag_update
- * here because this will lead to the while object
- * surface to disappear, so we'll release DM in place.
- */
- BKE_object_free_derived_caches(object);
+ if (object && object->sculpt) {
+ if (object->sculpt->bm) {
+ /* Ensure no points to old arrays are stored in DM
+ *
+ * Apparently, we could not use DEG_id_tag_update
+ * here because this will lead to the while object
+ * surface to disappear, so we'll release DM in place.
+ */
+ BKE_object_free_derived_caches(object);
- if (object->sculpt->pbvh) {
- BKE_pbvh_free(object->sculpt->pbvh);
- object->sculpt->pbvh = NULL;
- }
+ if (object->sculpt->pbvh) {
+ BKE_pbvh_free(object->sculpt->pbvh);
+ object->sculpt->pbvh = NULL;
+ }
- sculptsession_bm_to_me_update_data_only(object, false);
+ sculptsession_bm_to_me_update_data_only(object, false);
- /* In contrast with sculptsession_bm_to_me no need in
- * DAG tag update here - derived mesh was freed and
- * old pointers are nowhere stored.
- */
- }
- }
+ /* In contrast with sculptsession_bm_to_me no need in
+ * DAG tag update here - derived mesh was freed and
+ * old pointers are nowhere stored.
+ */
+ }
+ }
}
void BKE_sculptsession_free(Object *ob)
{
- if (ob && ob->sculpt) {
- SculptSession *ss = ob->sculpt;
+ if (ob && ob->sculpt) {
+ SculptSession *ss = ob->sculpt;
- if (ss->bm) {
- BKE_sculptsession_bm_to_me(ob, true);
- BM_mesh_free(ss->bm);
- }
+ if (ss->bm) {
+ BKE_sculptsession_bm_to_me(ob, true);
+ BM_mesh_free(ss->bm);
+ }
- if (ss->pbvh)
- BKE_pbvh_free(ss->pbvh);
- MEM_SAFE_FREE(ss->pmap);
- MEM_SAFE_FREE(ss->pmap_mem);
- if (ss->bm_log)
- BM_log_free(ss->bm_log);
+ if (ss->pbvh)
+ BKE_pbvh_free(ss->pbvh);
+ MEM_SAFE_FREE(ss->pmap);
+ MEM_SAFE_FREE(ss->pmap_mem);
+ if (ss->bm_log)
+ BM_log_free(ss->bm_log);
- if (ss->texcache)
- MEM_freeN(ss->texcache);
+ if (ss->texcache)
+ MEM_freeN(ss->texcache);
- if (ss->tex_pool)
- BKE_image_pool_free(ss->tex_pool);
+ if (ss->tex_pool)
+ BKE_image_pool_free(ss->tex_pool);
- if (ss->layer_co)
- MEM_freeN(ss->layer_co);
+ if (ss->layer_co)
+ MEM_freeN(ss->layer_co);
- if (ss->orig_cos)
- MEM_freeN(ss->orig_cos);
- if (ss->deform_cos)
- MEM_freeN(ss->deform_cos);
- if (ss->deform_imats)
- MEM_freeN(ss->deform_imats);
+ if (ss->orig_cos)
+ MEM_freeN(ss->orig_cos);
+ if (ss->deform_cos)
+ MEM_freeN(ss->deform_cos);
+ if (ss->deform_imats)
+ MEM_freeN(ss->deform_imats);
- BKE_sculptsession_free_vwpaint_data(ob->sculpt);
+ BKE_sculptsession_free_vwpaint_data(ob->sculpt);
- MEM_freeN(ss);
+ MEM_freeN(ss);
- ob->sculpt = NULL;
- }
+ ob->sculpt = NULL;
+ }
}
/* Sculpt mode handles multires differently from regular meshes, but only if
* it's the last modifier on the stack and it is not on the first level */
MultiresModifierData *BKE_sculpt_multires_active(Scene *scene, Object *ob)
{
- Mesh *me = (Mesh *)ob->data;
- ModifierData *md;
- VirtualModifierData virtualModifierData;
+ Mesh *me = (Mesh *)ob->data;
+ ModifierData *md;
+ VirtualModifierData virtualModifierData;
- if (ob->sculpt && ob->sculpt->bm) {
- /* can't combine multires and dynamic topology */
- return NULL;
- }
+ if (ob->sculpt && ob->sculpt->bm) {
+ /* can't combine multires and dynamic topology */
+ return NULL;
+ }
- if (!CustomData_get_layer(&me->ldata, CD_MDISPS)) {
- /* multires can't work without displacement layer */
- return NULL;
- }
+ if (!CustomData_get_layer(&me->ldata, CD_MDISPS)) {
+ /* multires can't work without displacement layer */
+ return NULL;
+ }
- for (md = modifiers_getVirtualModifierList(ob, &virtualModifierData); md; md = md->next) {
- if (md->type == eModifierType_Multires) {
- MultiresModifierData *mmd = (MultiresModifierData *)md;
+ for (md = modifiers_getVirtualModifierList(ob, &virtualModifierData); md; md = md->next) {
+ if (md->type == eModifierType_Multires) {
+ MultiresModifierData *mmd = (MultiresModifierData *)md;
- if (!modifier_isEnabled(scene, md, eModifierMode_Realtime))
- continue;
+ if (!modifier_isEnabled(scene, md, eModifierMode_Realtime))
+ continue;
- if (mmd->sculptlvl > 0) return mmd;
- else return NULL;
- }
- }
+ if (mmd->sculptlvl > 0)
+ return mmd;
+ else
+ return NULL;
+ }
+ }
- return NULL;
+ return NULL;
}
-
/* Checks if there are any supported deformation modifiers active */
static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob)
{
- ModifierData *md;
- Mesh *me = (Mesh *)ob->data;
- MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
- VirtualModifierData virtualModifierData;
+ ModifierData *md;
+ Mesh *me = (Mesh *)ob->data;
+ MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
+ VirtualModifierData virtualModifierData;
- if (mmd || ob->sculpt->bm)
- return false;
+ if (mmd || ob->sculpt->bm)
+ return false;
- /* non-locked shape keys could be handled in the same way as deformed mesh */
- if ((ob->shapeflag & OB_SHAPE_LOCK) == 0 && me->key && ob->shapenr)
- return true;
+ /* non-locked shape keys could be handled in the same way as deformed mesh */
+ if ((ob->shapeflag & OB_SHAPE_LOCK) == 0 && me->key && ob->shapenr)
+ return true;
- md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
- /* exception for shape keys because we can edit those */
- for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue;
- if (ELEM(md->type, eModifierType_ShapeKey, eModifierType_Multires)) continue;
+ /* exception for shape keys because we can edit those */
+ for (; md; md = md->next) {
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ if (!modifier_isEnabled(scene, md, eModifierMode_Realtime))
+ continue;
+ if (ELEM(md->type, eModifierType_ShapeKey, eModifierType_Multires))
+ continue;
- if (mti->type == eModifierTypeType_OnlyDeform) return true;
- else if ((sd->flags & SCULPT_ONLY_DEFORM) == 0) return true;
- }
+ if (mti->type == eModifierTypeType_OnlyDeform)
+ return true;
+ else if ((sd->flags & SCULPT_ONLY_DEFORM) == 0)
+ return true;
+ }
- return false;
+ return false;
}
/**
* \param need_mask: So that the evaluated mesh that is returned has mask data.
*/
void BKE_sculpt_update_mesh_elements(
- Depsgraph *depsgraph, Scene *scene, Sculpt *sd, Object *ob,
- bool need_pmap, bool need_mask)
-{
- /* TODO(sergey): Make sure ob points to an original object. This is what it
- * is supposed to be pointing to. The issue is, currently draw code takes
- * care of PBVH creation, even though this is something up to dependency
- * graph.
- * Probably, we need to being back logic which was checking for sculpt mode
- * and (re)create PBVH if needed in that case, similar to how DerivedMesh
- * was handling this.
- */
- ob = DEG_get_original_object(ob);
- Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
-
- SculptSession *ss = ob->sculpt;
- Mesh *me = BKE_object_get_original_mesh(ob);
- MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
-
- ss->modifiers_active = sculpt_modifiers_active(scene, sd, ob);
- ss->show_diffuse_color = (sd->flags & SCULPT_SHOW_DIFFUSE) != 0;
- ss->show_mask = (sd->flags & SCULPT_HIDE_MASK) == 0;
-
- ss->building_vp_handle = false;
-
- if (need_mask) {
- if (mmd == NULL) {
- if (!CustomData_has_layer(&me->vdata, CD_PAINT_MASK)) {
- BKE_sculpt_mask_layers_ensure(ob, NULL);
- }
- }
- else {
- if (!CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK)) {
+ Depsgraph *depsgraph, Scene *scene, Sculpt *sd, Object *ob, bool need_pmap, bool need_mask)
+{
+ /* TODO(sergey): Make sure ob points to an original object. This is what it
+ * is supposed to be pointing to. The issue is, currently draw code takes
+ * care of PBVH creation, even though this is something up to dependency
+ * graph.
+ * Probably, we need to being back logic which was checking for sculpt mode
+ * and (re)create PBVH if needed in that case, similar to how DerivedMesh
+ * was handling this.
+ */
+ ob = DEG_get_original_object(ob);
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+
+ SculptSession *ss = ob->sculpt;
+ Mesh *me = BKE_object_get_original_mesh(ob);
+ MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
+
+ ss->modifiers_active = sculpt_modifiers_active(scene, sd, ob);
+ ss->show_diffuse_color = (sd->flags & SCULPT_SHOW_DIFFUSE) != 0;
+ ss->show_mask = (sd->flags & SCULPT_HIDE_MASK) == 0;
+
+ ss->building_vp_handle = false;
+
+ if (need_mask) {
+ if (mmd == NULL) {
+ if (!CustomData_has_layer(&me->vdata, CD_PAINT_MASK)) {
+ BKE_sculpt_mask_layers_ensure(ob, NULL);
+ }
+ }
+ else {
+ if (!CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK)) {
#if 1
- BKE_sculpt_mask_layers_ensure(ob, mmd);
-#else /* if we wanted to support adding mask data while multi-res painting, we would need to do this */
- if ((ED_sculpt_mask_layers_ensure(ob, mmd) & ED_SCULPT_MASK_LAYER_CALC_LOOP)) {
- /* remake the derived mesh */
- ob->recalc |= ID_RECALC_GEOMETRY;
- BKE_object_handle_update(scene, ob);
- }
+ BKE_sculpt_mask_layers_ensure(ob, mmd);
+#else /* if we wanted to support adding mask data while multi-res painting, we would need to do this */
+ if ((ED_sculpt_mask_layers_ensure(ob, mmd) & ED_SCULPT_MASK_LAYER_CALC_LOOP)) {
+ /* remake the derived mesh */
+ ob->recalc |= ID_RECALC_GEOMETRY;
+ BKE_object_handle_update(scene, ob);
+ }
#endif
- }
- }
- }
-
- /* tessfaces aren't used and will become invalid */
- BKE_mesh_tessface_clear(me);
-
- ss->kb = (mmd == NULL) ? BKE_keyblock_from_object(ob) : NULL;
-
- Mesh *me_eval = mesh_get_eval_final(depsgraph, scene, ob_eval, &CD_MASK_BAREMESH);
-
- /* VWPaint require mesh info for loop lookup, so require sculpt mode here */
- if (mmd && ob->mode & OB_MODE_SCULPT) {
- ss->multires = mmd;
- ss->totvert = me_eval->totvert;
- ss->totpoly = me_eval->totpoly;
- ss->mvert = NULL;
- ss->mpoly = NULL;
- ss->mloop = NULL;
- }
- else {
- ss->totvert = me->totvert;
- ss->totpoly = me->totpoly;
- ss->mvert = me->mvert;
- ss->mpoly = me->mpoly;
- ss->mloop = me->mloop;
- ss->multires = NULL;
- ss->vmask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK);
- }
-
- ss->subdiv_ccg = me_eval->runtime.subdiv_ccg;
-
- PBVH *pbvh = BKE_sculpt_object_pbvh_ensure(depsgraph, ob);
- BLI_assert(pbvh == ss->pbvh);
- UNUSED_VARS_NDEBUG(pbvh);
- MEM_SAFE_FREE(ss->pmap);
- MEM_SAFE_FREE(ss->pmap_mem);
- if (need_pmap && ob->type == OB_MESH) {
- BKE_mesh_vert_poly_map_create(
- &ss->pmap, &ss->pmap_mem,
- me->mpoly, me->mloop,
- me->totvert, me->totpoly, me->totloop);
- }
-
- pbvh_show_diffuse_color_set(ss->pbvh, ss->show_diffuse_color);
- pbvh_show_mask_set(ss->pbvh, ss->show_mask);
-
- if (ss->modifiers_active) {
- if (!ss->orig_cos) {
- Object *object_orig = DEG_get_original_object(ob);
- int a;
-
- BKE_sculptsession_free_deformMats(ss);
-
- ss->orig_cos = (ss->kb) ? BKE_keyblock_convert_to_vertcos(ob, ss->kb) : BKE_mesh_vertexCos_get(me, NULL);
-
- BKE_crazyspace_build_sculpt(depsgraph, scene, object_orig, &ss->deform_imats, &ss->deform_cos);
- BKE_pbvh_apply_vertCos(ss->pbvh, ss->deform_cos, me->totvert);
-
- for (a = 0; a < me->totvert; ++a) {
- invert_m3(ss->deform_imats[a]);
- }
- }
- }
- else {
- BKE_sculptsession_free_deformMats(ss);
- }
-
- if (ss->kb != NULL && ss->deform_cos == NULL) {
- ss->deform_cos = BKE_keyblock_convert_to_vertcos(ob, ss->kb);
- }
-
- /* if pbvh is deformed, key block is already applied to it */
- if (ss->kb) {
- bool pbvh_deformed = BKE_pbvh_isDeformed(ss->pbvh);
- if (!pbvh_deformed || ss->deform_cos == NULL) {
- float (*vertCos)[3] = BKE_keyblock_convert_to_vertcos(ob, ss->kb);
-
- if (vertCos) {
- if (!pbvh_deformed) {
- /* apply shape keys coordinates to PBVH */
- BKE_pbvh_apply_vertCos(ss->pbvh, vertCos, me->totvert);
- }
- if (ss->deform_cos == NULL) {
- ss->deform_cos = vertCos;
- }
- if (vertCos != ss->deform_cos) {
- MEM_freeN(vertCos);
- }
- }
- }
- }
-
- /* 2.8x - avoid full mesh update! */
- BKE_mesh_batch_cache_dirty_tag(me, BKE_MESH_BATCH_DIRTY_SCULPT_COORDS);
+ }
+ }
+ }
+
+ /* tessfaces aren't used and will become invalid */
+ BKE_mesh_tessface_clear(me);
+
+ ss->kb = (mmd == NULL) ? BKE_keyblock_from_object(ob) : NULL;
+
+ Mesh *me_eval = mesh_get_eval_final(depsgraph, scene, ob_eval, &CD_MASK_BAREMESH);
+
+ /* VWPaint require mesh info for loop lookup, so require sculpt mode here */
+ if (mmd && ob->mode & OB_MODE_SCULPT) {
+ ss->multires = mmd;
+ ss->totvert = me_eval->totvert;
+ ss->totpoly = me_eval->totpoly;
+ ss->mvert = NULL;
+ ss->mpoly = NULL;
+ ss->mloop = NULL;
+ }
+ else {
+ ss->totvert = me->totvert;
+ ss->totpoly = me->totpoly;
+ ss->mvert = me->mvert;
+ ss->mpoly = me->mpoly;
+ ss->mloop = me->mloop;
+ ss->multires = NULL;
+ ss->vmask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK);
+ }
+
+ ss->subdiv_ccg = me_eval->runtime.subdiv_ccg;
+
+ PBVH *pbvh = BKE_sculpt_object_pbvh_ensure(depsgraph, ob);
+ BLI_assert(pbvh == ss->pbvh);
+ UNUSED_VARS_NDEBUG(pbvh);
+ MEM_SAFE_FREE(ss->pmap);
+ MEM_SAFE_FREE(ss->pmap_mem);
+ if (need_pmap && ob->type == OB_MESH) {
+ BKE_mesh_vert_poly_map_create(
+ &ss->pmap, &ss->pmap_mem, me->mpoly, me->mloop, me->totvert, me->totpoly, me->totloop);
+ }
+
+ pbvh_show_diffuse_color_set(ss->pbvh, ss->show_diffuse_color);
+ pbvh_show_mask_set(ss->pbvh, ss->show_mask);
+
+ if (ss->modifiers_active) {
+ if (!ss->orig_cos) {
+ Object *object_orig = DEG_get_original_object(ob);
+ int a;
+
+ BKE_sculptsession_free_deformMats(ss);
+
+ ss->orig_cos = (ss->kb) ? BKE_keyblock_convert_to_vertcos(ob, ss->kb) :
+ BKE_mesh_vertexCos_get(me, NULL);
+
+ BKE_crazyspace_build_sculpt(
+ depsgraph, scene, object_orig, &ss->deform_imats, &ss->deform_cos);
+ BKE_pbvh_apply_vertCos(ss->pbvh, ss->deform_cos, me->totvert);
+
+ for (a = 0; a < me->totvert; ++a) {
+ invert_m3(ss->deform_imats[a]);
+ }
+ }
+ }
+ else {
+ BKE_sculptsession_free_deformMats(ss);
+ }
+
+ if (ss->kb != NULL && ss->deform_cos == NULL) {
+ ss->deform_cos = BKE_keyblock_convert_to_vertcos(ob, ss->kb);
+ }
+
+ /* if pbvh is deformed, key block is already applied to it */
+ if (ss->kb) {
+ bool pbvh_deformed = BKE_pbvh_isDeformed(ss->pbvh);
+ if (!pbvh_deformed || ss->deform_cos == NULL) {
+ float(*vertCos)[3] = BKE_keyblock_convert_to_vertcos(ob, ss->kb);
+
+ if (vertCos) {
+ if (!pbvh_deformed) {
+ /* apply shape keys coordinates to PBVH */
+ BKE_pbvh_apply_vertCos(ss->pbvh, vertCos, me->totvert);
+ }
+ if (ss->deform_cos == NULL) {
+ ss->deform_cos = vertCos;
+ }
+ if (vertCos != ss->deform_cos) {
+ MEM_freeN(vertCos);
+ }
+ }
+ }
+ }
+
+ /* 2.8x - avoid full mesh update! */
+ BKE_mesh_batch_cache_dirty_tag(me, BKE_MESH_BATCH_DIRTY_SCULPT_COORDS);
}
int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd)
{
- const float *paint_mask;
- Mesh *me = ob->data;
- int ret = 0;
-
- paint_mask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK);
-
- /* if multires is active, create a grid paint mask layer if there
- * isn't one already */
- if (mmd && !CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK)) {
- GridPaintMask *gmask;
- int level = max_ii(1, mmd->sculptlvl);
- int gridsize = BKE_ccg_gridsize(level);
- int gridarea = gridsize * gridsize;
- int i, j;
-
- gmask = CustomData_add_layer(&me->ldata, CD_GRID_PAINT_MASK,
- CD_CALLOC, NULL, me->totloop);
-
- for (i = 0; i < me->totloop; i++) {
- GridPaintMask *gpm = &gmask[i];
-
- gpm->level = level;
- gpm->data = MEM_callocN(sizeof(float) * gridarea,
- "GridPaintMask.data");
- }
-
- /* if vertices already have mask, copy into multires data */
- if (paint_mask) {
- for (i = 0; i < me->totpoly; i++) {
- const MPoly *p = &me->mpoly[i];
- float avg = 0;
-
- /* mask center */
- for (j = 0; j < p->totloop; j++) {
- const MLoop *l = &me->mloop[p->loopstart + j];
- avg += paint_mask[l->v];
- }
- avg /= (float)p->totloop;
-
- /* fill in multires mask corner */
- for (j = 0; j < p->totloop; j++) {
- GridPaintMask *gpm = &gmask[p->loopstart + j];
- const MLoop *l = &me->mloop[p->loopstart + j];
- const MLoop *prev = ME_POLY_LOOP_PREV(me->mloop, p, j);
- const MLoop *next = ME_POLY_LOOP_NEXT(me->mloop, p, j);
-
- gpm->data[0] = avg;
- gpm->data[1] = (paint_mask[l->v] +
- paint_mask[next->v]) * 0.5f;
- gpm->data[2] = (paint_mask[l->v] +
- paint_mask[prev->v]) * 0.5f;
- gpm->data[3] = paint_mask[l->v];
- }
- }
- }
-
- ret |= SCULPT_MASK_LAYER_CALC_LOOP;
- }
-
- /* create vertex paint mask layer if there isn't one already */
- if (!paint_mask) {
- CustomData_add_layer(&me->vdata, CD_PAINT_MASK,
- CD_CALLOC, NULL, me->totvert);
- ret |= SCULPT_MASK_LAYER_CALC_VERT;
- }
-
- return ret;
+ const float *paint_mask;
+ Mesh *me = ob->data;
+ int ret = 0;
+
+ paint_mask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK);
+
+ /* if multires is active, create a grid paint mask layer if there
+ * isn't one already */
+ if (mmd && !CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK)) {
+ GridPaintMask *gmask;
+ int level = max_ii(1, mmd->sculptlvl);
+ int gridsize = BKE_ccg_gridsize(level);
+ int gridarea = gridsize * gridsize;
+ int i, j;
+
+ gmask = CustomData_add_layer(&me->ldata, CD_GRID_PAINT_MASK, CD_CALLOC, NULL, me->totloop);
+
+ for (i = 0; i < me->totloop; i++) {
+ GridPaintMask *gpm = &gmask[i];
+
+ gpm->level = level;
+ gpm->data = MEM_callocN(sizeof(float) * gridarea, "GridPaintMask.data");
+ }
+
+ /* if vertices already have mask, copy into multires data */
+ if (paint_mask) {
+ for (i = 0; i < me->totpoly; i++) {
+ const MPoly *p = &me->mpoly[i];
+ float avg = 0;
+
+ /* mask center */
+ for (j = 0; j < p->totloop; j++) {
+ const MLoop *l = &me->mloop[p->loopstart + j];
+ avg += paint_mask[l->v];
+ }
+ avg /= (float)p->totloop;
+
+ /* fill in multires mask corner */
+ for (j = 0; j < p->totloop; j++) {
+ GridPaintMask *gpm = &gmask[p->loopstart + j];
+ const MLoop *l = &me->mloop[p->loopstart + j];
+ const MLoop *prev = ME_POLY_LOOP_PREV(me->mloop, p, j);
+ const MLoop *next = ME_POLY_LOOP_NEXT(me->mloop, p, j);
+
+ gpm->data[0] = avg;
+ gpm->data[1] = (paint_mask[l->v] + paint_mask[next->v]) * 0.5f;
+ gpm->data[2] = (paint_mask[l->v] + paint_mask[prev->v]) * 0.5f;
+ gpm->data[3] = paint_mask[l->v];
+ }
+ }
+ }
+
+ ret |= SCULPT_MASK_LAYER_CALC_LOOP;
+ }
+
+ /* create vertex paint mask layer if there isn't one already */
+ if (!paint_mask) {
+ CustomData_add_layer(&me->vdata, CD_PAINT_MASK, CD_CALLOC, NULL, me->totvert);
+ ret |= SCULPT_MASK_LAYER_CALC_VERT;
+ }
+
+ return ret;
}
void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene)
{
- BKE_paint_ensure(scene->toolsettings, (Paint **)&scene->toolsettings->sculpt);
-
- Sculpt *sd = scene->toolsettings->sculpt;
- if (!sd->detail_size) {
- sd->detail_size = 12;
- }
- if (!sd->detail_percent) {
- sd->detail_percent = 25;
- }
- if (sd->constant_detail == 0.0f) {
- sd->constant_detail = 3.0f;
- }
-
- /* Set sane default tiling offsets */
- if (!sd->paint.tile_offset[0]) {
- sd->paint.tile_offset[0] = 1.0f;
- }
- if (!sd->paint.tile_offset[1]) {
- sd->paint.tile_offset[1] = 1.0f;
- }
- if (!sd->paint.tile_offset[2]) {
- sd->paint.tile_offset[2] = 1.0f;
- }
+ BKE_paint_ensure(scene->toolsettings, (Paint **)&scene->toolsettings->sculpt);
+
+ Sculpt *sd = scene->toolsettings->sculpt;
+ if (!sd->detail_size) {
+ sd->detail_size = 12;
+ }
+ if (!sd->detail_percent) {
+ sd->detail_percent = 25;
+ }
+ if (sd->constant_detail == 0.0f) {
+ sd->constant_detail = 3.0f;
+ }
+
+ /* Set sane default tiling offsets */
+ if (!sd->paint.tile_offset[0]) {
+ sd->paint.tile_offset[0] = 1.0f;
+ }
+ if (!sd->paint.tile_offset[1]) {
+ sd->paint.tile_offset[1] = 1.0f;
+ }
+ if (!sd->paint.tile_offset[2]) {
+ sd->paint.tile_offset[2] = 1.0f;
+ }
}
static bool check_sculpt_object_deformed(Object *object, const bool for_construction)
{
- bool deformed = false;
+ bool deformed = false;
- /* Active modifiers means extra deformation, which can't be handled correct
- * on birth of PBVH and sculpt "layer" levels, so use PBVH only for internal brush
- * stuff and show final evaluated mesh so user would see actual object shape.
- */
- deformed |= object->sculpt->modifiers_active;
+ /* Active modifiers means extra deformation, which can't be handled correct
+ * on birth of PBVH and sculpt "layer" levels, so use PBVH only for internal brush
+ * stuff and show final evaluated mesh so user would see actual object shape.
+ */
+ deformed |= object->sculpt->modifiers_active;
- if (for_construction) {
- deformed |= object->sculpt->kb != NULL;
- }
- else {
- /* As in case with modifiers, we can't synchronize deformation made against
- * PBVH and non-locked keyblock, so also use PBVH only for brushes and
- * final DM to give final result to user.
- */
- deformed |= object->sculpt->kb && (object->shapeflag & OB_SHAPE_LOCK) == 0;
- }
+ if (for_construction) {
+ deformed |= object->sculpt->kb != NULL;
+ }
+ else {
+ /* As in case with modifiers, we can't synchronize deformation made against
+ * PBVH and non-locked keyblock, so also use PBVH only for brushes and
+ * final DM to give final result to user.
+ */
+ deformed |= object->sculpt->kb && (object->shapeflag & OB_SHAPE_LOCK) == 0;
+ }
- return deformed;
+ return deformed;
}
static PBVH *build_pbvh_for_dynamic_topology(Object *ob)
{
- PBVH *pbvh = BKE_pbvh_new();
- BKE_pbvh_build_bmesh(pbvh, ob->sculpt->bm,
- ob->sculpt->bm_smooth_shading,
- ob->sculpt->bm_log, ob->sculpt->cd_vert_node_offset,
- ob->sculpt->cd_face_node_offset);
- pbvh_show_diffuse_color_set(pbvh, ob->sculpt->show_diffuse_color);
- pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
- return pbvh;
+ PBVH *pbvh = BKE_pbvh_new();
+ BKE_pbvh_build_bmesh(pbvh,
+ ob->sculpt->bm,
+ ob->sculpt->bm_smooth_shading,
+ ob->sculpt->bm_log,
+ ob->sculpt->cd_vert_node_offset,
+ ob->sculpt->cd_face_node_offset);
+ pbvh_show_diffuse_color_set(pbvh, ob->sculpt->show_diffuse_color);
+ pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
+ return pbvh;
}
static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform)
{
- Mesh *me = BKE_object_get_original_mesh(ob);
- const int looptris_num = poly_to_tri_count(me->totpoly, me->totloop);
- PBVH *pbvh = BKE_pbvh_new();
+ Mesh *me = BKE_object_get_original_mesh(ob);
+ const int looptris_num = poly_to_tri_count(me->totpoly, me->totloop);
+ PBVH *pbvh = BKE_pbvh_new();
- MLoopTri *looptri = MEM_malloc_arrayN(
- looptris_num, sizeof(*looptri), __func__);
+ MLoopTri *looptri = MEM_malloc_arrayN(looptris_num, sizeof(*looptri), __func__);
- BKE_mesh_recalc_looptri(
- me->mloop, me->mpoly,
- me->mvert,
- me->totloop, me->totpoly,
- looptri);
+ BKE_mesh_recalc_looptri(me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, looptri);
- BKE_pbvh_build_mesh(
- pbvh,
- me->mpoly, me->mloop,
- me->mvert, me->totvert, &me->vdata,
- looptri, looptris_num);
+ BKE_pbvh_build_mesh(
+ pbvh, me->mpoly, me->mloop, me->mvert, me->totvert, &me->vdata, looptri, looptris_num);
- pbvh_show_diffuse_color_set(pbvh, ob->sculpt->show_diffuse_color);
- pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
+ pbvh_show_diffuse_color_set(pbvh, ob->sculpt->show_diffuse_color);
+ pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
- const bool is_deformed = check_sculpt_object_deformed(ob, true);
- if (is_deformed && me_eval_deform != NULL) {
- int totvert;
- float (*v_cos)[3] = BKE_mesh_vertexCos_get(me_eval_deform, &totvert);
- BKE_pbvh_apply_vertCos(pbvh, v_cos, totvert);
- MEM_freeN(v_cos);
- }
+ const bool is_deformed = check_sculpt_object_deformed(ob, true);
+ if (is_deformed && me_eval_deform != NULL) {
+ int totvert;
+ float(*v_cos)[3] = BKE_mesh_vertexCos_get(me_eval_deform, &totvert);
+ BKE_pbvh_apply_vertCos(pbvh, v_cos, totvert);
+ MEM_freeN(v_cos);
+ }
- return pbvh;
+ return pbvh;
}
static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg)
{
- CCGKey key;
- BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
- PBVH *pbvh = BKE_pbvh_new();
- BKE_pbvh_build_grids(
- pbvh,
- subdiv_ccg->grids, subdiv_ccg->num_grids,
- &key,
- (void **)subdiv_ccg->grid_faces,
- subdiv_ccg->grid_flag_mats,
- subdiv_ccg->grid_hidden);
- pbvh_show_diffuse_color_set(pbvh, ob->sculpt->show_diffuse_color);
- pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
- return pbvh;
+ CCGKey key;
+ BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
+ PBVH *pbvh = BKE_pbvh_new();
+ BKE_pbvh_build_grids(pbvh,
+ subdiv_ccg->grids,
+ subdiv_ccg->num_grids,
+ &key,
+ (void **)subdiv_ccg->grid_faces,
+ subdiv_ccg->grid_flag_mats,
+ subdiv_ccg->grid_hidden);
+ pbvh_show_diffuse_color_set(pbvh, ob->sculpt->show_diffuse_color);
+ pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
+ return pbvh;
}
PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
{
- if (ob == NULL || ob->sculpt == NULL) {
- return NULL;
- }
- PBVH *pbvh = ob->sculpt->pbvh;
- if (pbvh != NULL) {
- /* NOTE: It is possible that grids were re-allocated due to modifier
- * stack. Need to update those pointers. */
- if (BKE_pbvh_type(pbvh) == PBVH_GRIDS) {
- Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
- Mesh *mesh_eval = object_eval->data;
- SubdivCCG *subdiv_ccg = mesh_eval->runtime.subdiv_ccg;
- if (subdiv_ccg != NULL) {
- BKE_sculpt_bvh_update_from_ccg(pbvh, subdiv_ccg);
- }
- }
- return pbvh;
- }
-
- if (ob->sculpt->bm != NULL) {
- /* Sculpting on a BMesh (dynamic-topology) gets a special PBVH. */
- pbvh = build_pbvh_for_dynamic_topology(ob);
- }
- else {
- Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
- Mesh *mesh_eval = object_eval->data;
- if (mesh_eval->runtime.subdiv_ccg != NULL) {
- pbvh = build_pbvh_from_ccg(ob, mesh_eval->runtime.subdiv_ccg);
- }
- else if (ob->type == OB_MESH) {
- Mesh *me_eval_deform = mesh_get_eval_deform(
- depsgraph, DEG_get_evaluated_scene(depsgraph), object_eval, &CD_MASK_BAREMESH);
- pbvh = build_pbvh_from_regular_mesh(ob, me_eval_deform);
- }
- }
-
- ob->sculpt->pbvh = pbvh;
- return pbvh;
+ if (ob == NULL || ob->sculpt == NULL) {
+ return NULL;
+ }
+ PBVH *pbvh = ob->sculpt->pbvh;
+ if (pbvh != NULL) {
+ /* NOTE: It is possible that grids were re-allocated due to modifier
+ * stack. Need to update those pointers. */
+ if (BKE_pbvh_type(pbvh) == PBVH_GRIDS) {
+ Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
+ Mesh *mesh_eval = object_eval->data;
+ SubdivCCG *subdiv_ccg = mesh_eval->runtime.subdiv_ccg;
+ if (subdiv_ccg != NULL) {
+ BKE_sculpt_bvh_update_from_ccg(pbvh, subdiv_ccg);
+ }
+ }
+ return pbvh;
+ }
+
+ if (ob->sculpt->bm != NULL) {
+ /* Sculpting on a BMesh (dynamic-topology) gets a special PBVH. */
+ pbvh = build_pbvh_for_dynamic_topology(ob);
+ }
+ else {
+ Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
+ Mesh *mesh_eval = object_eval->data;
+ if (mesh_eval->runtime.subdiv_ccg != NULL) {
+ pbvh = build_pbvh_from_ccg(ob, mesh_eval->runtime.subdiv_ccg);
+ }
+ else if (ob->type == OB_MESH) {
+ Mesh *me_eval_deform = mesh_get_eval_deform(
+ depsgraph, DEG_get_evaluated_scene(depsgraph), object_eval, &CD_MASK_BAREMESH);
+ pbvh = build_pbvh_from_regular_mesh(ob, me_eval_deform);
+ }
+ }
+
+ ob->sculpt->pbvh = pbvh;
+ return pbvh;
}
void BKE_sculpt_bvh_update_from_ccg(PBVH *pbvh, SubdivCCG *subdiv_ccg)
{
- BKE_pbvh_grids_update(pbvh, subdiv_ccg->grids, (void **)subdiv_ccg->grid_faces,
- subdiv_ccg->grid_flag_mats, subdiv_ccg->grid_hidden);
+ BKE_pbvh_grids_update(pbvh,
+ subdiv_ccg->grids,
+ (void **)subdiv_ccg->grid_faces,
+ subdiv_ccg->grid_flag_mats,
+ subdiv_ccg->grid_hidden);
}
diff --git a/source/blender/blenkernel/intern/paint_toolslots.c b/source/blender/blenkernel/intern/paint_toolslots.c
index 24b801ce67f..942d5e758f3 100644
--- a/source/blender/blenkernel/intern/paint_toolslots.c
+++ b/source/blender/blenkernel/intern/paint_toolslots.c
@@ -35,65 +35,64 @@
void BKE_paint_toolslots_len_ensure(Paint *paint, int len)
{
- /* Tool slots are 'uchar'. */
- BLI_assert(len <= UCHAR_MAX);
- if (paint->tool_slots_len < len) {
- paint->tool_slots = MEM_recallocN(paint->tool_slots, sizeof(*paint->tool_slots) * len);
- paint->tool_slots_len = len;
- }
+ /* Tool slots are 'uchar'. */
+ BLI_assert(len <= UCHAR_MAX);
+ if (paint->tool_slots_len < len) {
+ paint->tool_slots = MEM_recallocN(paint->tool_slots, sizeof(*paint->tool_slots) * len);
+ paint->tool_slots_len = len;
+ }
}
static void paint_toolslots_init(Main *bmain, Paint *paint)
{
- if (paint == NULL) {
- return;
- }
- const eObjectMode ob_mode = paint->runtime.ob_mode;
- BLI_assert(paint->runtime.tool_offset && ob_mode);
- for (Brush *brush = bmain->brushes.first; brush; brush = brush->id.next) {
- if (brush->ob_mode & ob_mode) {
- const int slot_index = BKE_brush_tool_get(brush, paint);
- BKE_paint_toolslots_len_ensure(paint, slot_index + 1);
- if (paint->tool_slots[slot_index].brush == NULL) {
- paint->tool_slots[slot_index].brush = brush;
- id_us_plus(&brush->id);
- }
- }
- }
+ if (paint == NULL) {
+ return;
+ }
+ const eObjectMode ob_mode = paint->runtime.ob_mode;
+ BLI_assert(paint->runtime.tool_offset && ob_mode);
+ for (Brush *brush = bmain->brushes.first; brush; brush = brush->id.next) {
+ if (brush->ob_mode & ob_mode) {
+ const int slot_index = BKE_brush_tool_get(brush, paint);
+ BKE_paint_toolslots_len_ensure(paint, slot_index + 1);
+ if (paint->tool_slots[slot_index].brush == NULL) {
+ paint->tool_slots[slot_index].brush = brush;
+ id_us_plus(&brush->id);
+ }
+ }
+ }
}
void BKE_paint_toolslots_init_from_main(struct Main *bmain)
{
- for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
- ToolSettings *ts = scene->toolsettings;
- paint_toolslots_init(bmain, &ts->imapaint.paint);
- paint_toolslots_init(bmain, &ts->sculpt->paint);
- paint_toolslots_init(bmain, &ts->vpaint->paint);
- paint_toolslots_init(bmain, &ts->wpaint->paint);
- paint_toolslots_init(bmain, &ts->gp_paint->paint);
- }
+ for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
+ ToolSettings *ts = scene->toolsettings;
+ paint_toolslots_init(bmain, &ts->imapaint.paint);
+ paint_toolslots_init(bmain, &ts->sculpt->paint);
+ paint_toolslots_init(bmain, &ts->vpaint->paint);
+ paint_toolslots_init(bmain, &ts->wpaint->paint);
+ paint_toolslots_init(bmain, &ts->gp_paint->paint);
+ }
}
-
void BKE_paint_toolslots_brush_update_ex(Paint *paint, Brush *brush)
{
- const uint tool_offset = paint->runtime.tool_offset;
- UNUSED_VARS_NDEBUG(tool_offset);
- BLI_assert(tool_offset != 0);
- const int slot_index = BKE_brush_tool_get(brush, paint);
- BKE_paint_toolslots_len_ensure(paint, slot_index + 1);
- PaintToolSlot *tslot = &paint->tool_slots[slot_index];
- id_us_plus(&brush->id);
- id_us_min(&tslot->brush->id);
- tslot->brush = brush;
+ const uint tool_offset = paint->runtime.tool_offset;
+ UNUSED_VARS_NDEBUG(tool_offset);
+ BLI_assert(tool_offset != 0);
+ const int slot_index = BKE_brush_tool_get(brush, paint);
+ BKE_paint_toolslots_len_ensure(paint, slot_index + 1);
+ PaintToolSlot *tslot = &paint->tool_slots[slot_index];
+ id_us_plus(&brush->id);
+ id_us_min(&tslot->brush->id);
+ tslot->brush = brush;
}
void BKE_paint_toolslots_brush_update(Paint *paint)
{
- if (paint->brush == NULL) {
- return;
- }
- BKE_paint_toolslots_brush_update_ex(paint, paint->brush);
+ if (paint->brush == NULL) {
+ return;
+ }
+ BKE_paint_toolslots_brush_update_ex(paint, paint->brush);
}
/**
@@ -102,35 +101,34 @@ void BKE_paint_toolslots_brush_update(Paint *paint)
*/
void BKE_paint_toolslots_brush_validate(Main *bmain, Paint *paint)
{
- /* Clear slots with invalid slots or mode (unlikely but possible). */
- const uint tool_offset = paint->runtime.tool_offset;
- UNUSED_VARS_NDEBUG(tool_offset);
- const eObjectMode ob_mode = paint->runtime.ob_mode;
- BLI_assert(tool_offset && ob_mode);
- for (int i = 0; i < paint->tool_slots_len; i++) {
- PaintToolSlot *tslot = &paint->tool_slots[i];
- if (tslot->brush) {
- if ((i != BKE_brush_tool_get(tslot->brush, paint)) ||
- (tslot->brush->ob_mode & ob_mode) == 0)
- {
- id_us_min(&tslot->brush->id);
- tslot->brush = NULL;
- }
- }
- }
-
- /* Unlikely but possible the active brush is not currently using a slot. */
- BKE_paint_toolslots_brush_update(paint);
-
- /* Fill slots from brushes. */
- paint_toolslots_init(bmain, paint);
+ /* Clear slots with invalid slots or mode (unlikely but possible). */
+ const uint tool_offset = paint->runtime.tool_offset;
+ UNUSED_VARS_NDEBUG(tool_offset);
+ const eObjectMode ob_mode = paint->runtime.ob_mode;
+ BLI_assert(tool_offset && ob_mode);
+ for (int i = 0; i < paint->tool_slots_len; i++) {
+ PaintToolSlot *tslot = &paint->tool_slots[i];
+ if (tslot->brush) {
+ if ((i != BKE_brush_tool_get(tslot->brush, paint)) ||
+ (tslot->brush->ob_mode & ob_mode) == 0) {
+ id_us_min(&tslot->brush->id);
+ tslot->brush = NULL;
+ }
+ }
+ }
+
+ /* Unlikely but possible the active brush is not currently using a slot. */
+ BKE_paint_toolslots_brush_update(paint);
+
+ /* Fill slots from brushes. */
+ paint_toolslots_init(bmain, paint);
}
Brush *BKE_paint_toolslots_brush_get(Paint *paint, int slot_index)
{
- if (slot_index < paint->tool_slots_len) {
- PaintToolSlot *tslot = &paint->tool_slots[slot_index];
- return tslot->brush;
- }
- return NULL;
+ if (slot_index < paint->tool_slots_len) {
+ PaintToolSlot *tslot = &paint->tool_slots[slot_index];
+ return tslot->brush;
+ }
+ return NULL;
}
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 35869c44b87..9e121d279ba 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -21,7 +21,6 @@
* \ingroup bke
*/
-
#include <stdlib.h>
#include <math.h>
#include <string.h>
@@ -69,7 +68,7 @@
#include "BKE_library.h"
#include "BKE_modifier.h"
#include "BKE_mesh.h"
-#include "BKE_cdderivedmesh.h" /* for weight_to_rgb() */
+#include "BKE_cdderivedmesh.h" /* for weight_to_rgb() */
#include "BKE_pointcache.h"
#include "BKE_scene.h"
#include "BKE_deform.h"
@@ -88,46 +87,69 @@ float PSYS_FRAND_BASE[PSYS_FRAND_COUNT];
void psys_init_rng(void)
{
- RNG *rng = BLI_rng_new_srandom(5831); /* arbitrary */
- for (int i = 0; i < PSYS_FRAND_COUNT; ++i) {
- PSYS_FRAND_BASE[i] = BLI_rng_get_float(rng);
- PSYS_FRAND_SEED_OFFSET[i] = (unsigned int)BLI_rng_get_int(rng);
- PSYS_FRAND_SEED_MULTIPLIER[i] = (unsigned int)BLI_rng_get_int(rng);
- }
- BLI_rng_free(rng);
+ RNG *rng = BLI_rng_new_srandom(5831); /* arbitrary */
+ for (int i = 0; i < PSYS_FRAND_COUNT; ++i) {
+ PSYS_FRAND_BASE[i] = BLI_rng_get_float(rng);
+ PSYS_FRAND_SEED_OFFSET[i] = (unsigned int)BLI_rng_get_int(rng);
+ PSYS_FRAND_SEED_MULTIPLIER[i] = (unsigned int)BLI_rng_get_int(rng);
+ }
+ BLI_rng_free(rng);
}
-static void get_child_modifier_parameters(ParticleSettings *part, ParticleThreadContext *ctx,
- ChildParticle *cpa, short cpa_from, int cpa_num, float *cpa_fuv, float *orco, ParticleTexture *ptex);
-static void get_cpa_texture(Mesh *mesh, ParticleSystem *psys, ParticleSettings *part, ParticleData *par,
- int child_index, int face_index, const float fw[4], float *orco, ParticleTexture *ptex, int event, float cfra);
+static void get_child_modifier_parameters(ParticleSettings *part,
+ ParticleThreadContext *ctx,
+ ChildParticle *cpa,
+ short cpa_from,
+ int cpa_num,
+ float *cpa_fuv,
+ float *orco,
+ ParticleTexture *ptex);
+static void get_cpa_texture(Mesh *mesh,
+ ParticleSystem *psys,
+ ParticleSettings *part,
+ ParticleData *par,
+ int child_index,
+ int face_index,
+ const float fw[4],
+ float *orco,
+ ParticleTexture *ptex,
+ int event,
+ float cfra);
/* few helpers for countall etc. */
int count_particles(ParticleSystem *psys)
{
- ParticleSettings *part = psys->part;
- PARTICLE_P;
- int tot = 0;
-
- LOOP_SHOWN_PARTICLES {
- if (pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN) == 0) {}
- else if (pa->alive == PARS_DEAD && (part->flag & PART_DIED) == 0) {}
- else tot++;
- }
- return tot;
+ ParticleSettings *part = psys->part;
+ PARTICLE_P;
+ int tot = 0;
+
+ LOOP_SHOWN_PARTICLES
+ {
+ if (pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN) == 0) {
+ }
+ else if (pa->alive == PARS_DEAD && (part->flag & PART_DIED) == 0) {
+ }
+ else
+ tot++;
+ }
+ return tot;
}
int count_particles_mod(ParticleSystem *psys, int totgr, int cur)
{
- ParticleSettings *part = psys->part;
- PARTICLE_P;
- int tot = 0;
-
- LOOP_SHOWN_PARTICLES {
- if (pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN) == 0) {}
- else if (pa->alive == PARS_DEAD && (part->flag & PART_DIED) == 0) {}
- else if (p % totgr == cur) tot++;
- }
- return tot;
+ ParticleSettings *part = psys->part;
+ PARTICLE_P;
+ int tot = 0;
+
+ LOOP_SHOWN_PARTICLES
+ {
+ if (pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN) == 0) {
+ }
+ else if (pa->alive == PARS_DEAD && (part->flag & PART_DIED) == 0) {
+ }
+ else if (p % totgr == cur)
+ tot++;
+ }
+ return tot;
}
/* we allocate path cache memory in chunks instead of a big contiguous
* chunk, windows' memory allocater fails to find big blocks of memory often */
@@ -136,1192 +158,1241 @@ int count_particles_mod(ParticleSystem *psys, int totgr, int cur)
static ParticleCacheKey *pcache_key_segment_endpoint_safe(ParticleCacheKey *key)
{
- return (key->segments > 0) ? (key + (key->segments - 1)) : key;
+ return (key->segments > 0) ? (key + (key->segments - 1)) : key;
}
static ParticleCacheKey **psys_alloc_path_cache_buffers(ListBase *bufs, int tot, int totkeys)
{
- LinkData *buf;
- ParticleCacheKey **cache;
- int i, totkey, totbufkey;
+ LinkData *buf;
+ ParticleCacheKey **cache;
+ int i, totkey, totbufkey;
- tot = MAX2(tot, 1);
- totkey = 0;
- cache = MEM_callocN(tot * sizeof(void *), "PathCacheArray");
+ tot = MAX2(tot, 1);
+ totkey = 0;
+ cache = MEM_callocN(tot * sizeof(void *), "PathCacheArray");
- while (totkey < tot) {
- totbufkey = MIN2(tot - totkey, PATH_CACHE_BUF_SIZE);
- buf = MEM_callocN(sizeof(LinkData), "PathCacheLinkData");
- buf->data = MEM_callocN(sizeof(ParticleCacheKey) * totbufkey * totkeys, "ParticleCacheKey");
+ while (totkey < tot) {
+ totbufkey = MIN2(tot - totkey, PATH_CACHE_BUF_SIZE);
+ buf = MEM_callocN(sizeof(LinkData), "PathCacheLinkData");
+ buf->data = MEM_callocN(sizeof(ParticleCacheKey) * totbufkey * totkeys, "ParticleCacheKey");
- for (i = 0; i < totbufkey; i++)
- cache[totkey + i] = ((ParticleCacheKey *)buf->data) + i * totkeys;
+ for (i = 0; i < totbufkey; i++)
+ cache[totkey + i] = ((ParticleCacheKey *)buf->data) + i * totkeys;
- totkey += totbufkey;
- BLI_addtail(bufs, buf);
- }
+ totkey += totbufkey;
+ BLI_addtail(bufs, buf);
+ }
- return cache;
+ return cache;
}
static void psys_free_path_cache_buffers(ParticleCacheKey **cache, ListBase *bufs)
{
- LinkData *buf;
+ LinkData *buf;
- if (cache)
- MEM_freeN(cache);
+ if (cache)
+ MEM_freeN(cache);
- for (buf = bufs->first; buf; buf = buf->next)
- MEM_freeN(buf->data);
- BLI_freelistN(bufs);
+ for (buf = bufs->first; buf; buf = buf->next)
+ MEM_freeN(buf->data);
+ BLI_freelistN(bufs);
}
/************************************************/
-/* Getting stuff */
+/* Getting stuff */
/************************************************/
/* get object's active particle system safely */
ParticleSystem *psys_get_current(Object *ob)
{
- ParticleSystem *psys;
- if (ob == NULL) return NULL;
+ ParticleSystem *psys;
+ if (ob == NULL)
+ return NULL;
- for (psys = ob->particlesystem.first; psys; psys = psys->next) {
- if (psys->flag & PSYS_CURRENT)
- return psys;
- }
+ for (psys = ob->particlesystem.first; psys; psys = psys->next) {
+ if (psys->flag & PSYS_CURRENT)
+ return psys;
+ }
- return NULL;
+ return NULL;
}
short psys_get_current_num(Object *ob)
{
- ParticleSystem *psys;
- short i;
+ ParticleSystem *psys;
+ short i;
- if (ob == NULL) return 0;
+ if (ob == NULL)
+ return 0;
- for (psys = ob->particlesystem.first, i = 0; psys; psys = psys->next, i++)
- if (psys->flag & PSYS_CURRENT)
- return i;
+ for (psys = ob->particlesystem.first, i = 0; psys; psys = psys->next, i++)
+ if (psys->flag & PSYS_CURRENT)
+ return i;
- return i;
+ return i;
}
void psys_set_current_num(Object *ob, int index)
{
- ParticleSystem *psys;
- short i;
-
- if (ob == NULL) return;
-
- for (psys = ob->particlesystem.first, i = 0; psys; psys = psys->next, i++) {
- if (i == index)
- psys->flag |= PSYS_CURRENT;
- else
- psys->flag &= ~PSYS_CURRENT;
- }
+ ParticleSystem *psys;
+ short i;
+
+ if (ob == NULL)
+ return;
+
+ for (psys = ob->particlesystem.first, i = 0; psys; psys = psys->next, i++) {
+ if (i == index)
+ psys->flag |= PSYS_CURRENT;
+ else
+ psys->flag &= ~PSYS_CURRENT;
+ }
}
struct LatticeDeformData *psys_create_lattice_deform_data(ParticleSimulationData *sim)
{
- struct LatticeDeformData *lattice_deform_data = NULL;
-
- if (psys_in_edit_mode(sim->depsgraph, sim->psys) == 0) {
- Object *lattice = NULL;
- ModifierData *md = (ModifierData *)psys_get_modifier(sim->ob, sim->psys);
- bool for_render = DEG_get_mode(sim->depsgraph) == DAG_EVAL_RENDER;
- int mode = for_render ? eModifierMode_Render : eModifierMode_Realtime;
-
- for (; md; md = md->next) {
- if (md->type == eModifierType_Lattice) {
- if (md->mode & mode) {
- LatticeModifierData *lmd = (LatticeModifierData *)md;
- lattice = lmd->object;
- sim->psys->lattice_strength = lmd->strength;
- }
-
- break;
- }
- }
- if (lattice)
- lattice_deform_data = init_latt_deform(lattice, NULL);
- }
-
- return lattice_deform_data;
+ struct LatticeDeformData *lattice_deform_data = NULL;
+
+ if (psys_in_edit_mode(sim->depsgraph, sim->psys) == 0) {
+ Object *lattice = NULL;
+ ModifierData *md = (ModifierData *)psys_get_modifier(sim->ob, sim->psys);
+ bool for_render = DEG_get_mode(sim->depsgraph) == DAG_EVAL_RENDER;
+ int mode = for_render ? eModifierMode_Render : eModifierMode_Realtime;
+
+ for (; md; md = md->next) {
+ if (md->type == eModifierType_Lattice) {
+ if (md->mode & mode) {
+ LatticeModifierData *lmd = (LatticeModifierData *)md;
+ lattice = lmd->object;
+ sim->psys->lattice_strength = lmd->strength;
+ }
+
+ break;
+ }
+ }
+ if (lattice)
+ lattice_deform_data = init_latt_deform(lattice, NULL);
+ }
+
+ return lattice_deform_data;
}
void psys_disable_all(Object *ob)
{
- ParticleSystem *psys = ob->particlesystem.first;
+ ParticleSystem *psys = ob->particlesystem.first;
- for (; psys; psys = psys->next)
- psys->flag |= PSYS_DISABLED;
+ for (; psys; psys = psys->next)
+ psys->flag |= PSYS_DISABLED;
}
void psys_enable_all(Object *ob)
{
- ParticleSystem *psys = ob->particlesystem.first;
+ ParticleSystem *psys = ob->particlesystem.first;
- for (; psys; psys = psys->next)
- psys->flag &= ~PSYS_DISABLED;
+ for (; psys; psys = psys->next)
+ psys->flag &= ~PSYS_DISABLED;
}
ParticleSystem *psys_orig_get(ParticleSystem *psys)
{
- if (psys->orig_psys == NULL) {
- return psys;
- }
- return psys->orig_psys;
+ if (psys->orig_psys == NULL) {
+ return psys;
+ }
+ return psys->orig_psys;
}
-struct ParticleSystem *psys_eval_get(Depsgraph *depsgraph,
- Object *object,
- ParticleSystem *psys)
+struct ParticleSystem *psys_eval_get(Depsgraph *depsgraph, Object *object, ParticleSystem *psys)
{
- Object *object_eval = DEG_get_evaluated_object(depsgraph, object);
- if (object_eval == object) {
- return psys;
- }
- ParticleSystem *psys_eval = object_eval->particlesystem.first;
- while (psys_eval != NULL) {
- if (psys_eval->orig_psys == psys) {
- return psys_eval;
- }
- psys_eval = psys_eval->next;
- }
- return psys_eval;
+ Object *object_eval = DEG_get_evaluated_object(depsgraph, object);
+ if (object_eval == object) {
+ return psys;
+ }
+ ParticleSystem *psys_eval = object_eval->particlesystem.first;
+ while (psys_eval != NULL) {
+ if (psys_eval->orig_psys == psys) {
+ return psys_eval;
+ }
+ psys_eval = psys_eval->next;
+ }
+ return psys_eval;
}
static PTCacheEdit *psys_orig_edit_get(ParticleSystem *psys)
{
- if (psys->orig_psys == NULL) {
- return psys->edit;
- }
- return psys->orig_psys->edit;
+ if (psys->orig_psys == NULL) {
+ return psys->edit;
+ }
+ return psys->orig_psys->edit;
}
bool psys_in_edit_mode(Depsgraph *depsgraph, const ParticleSystem *psys)
{
- const ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
- if (view_layer->basact == NULL) {
- /* TODO(sergey): Needs double-check with multi-object edit. */
- return false;
- }
- const bool use_render_params = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
- const Object *object = view_layer->basact->object;
- if (object->mode != OB_MODE_PARTICLE_EDIT) {
- return false;
- }
- const ParticleSystem *psys_orig = psys_orig_get((ParticleSystem *)psys);
- return (psys_orig->edit || psys->pointcache->edit) &&
- (use_render_params == false);
+ const ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
+ if (view_layer->basact == NULL) {
+ /* TODO(sergey): Needs double-check with multi-object edit. */
+ return false;
+ }
+ const bool use_render_params = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
+ const Object *object = view_layer->basact->object;
+ if (object->mode != OB_MODE_PARTICLE_EDIT) {
+ return false;
+ }
+ const ParticleSystem *psys_orig = psys_orig_get((ParticleSystem *)psys);
+ return (psys_orig->edit || psys->pointcache->edit) && (use_render_params == false);
}
bool psys_check_enabled(Object *ob, ParticleSystem *psys, const bool use_render_params)
{
- ParticleSystemModifierData *psmd;
+ ParticleSystemModifierData *psmd;
- if (psys->flag & PSYS_DISABLED || psys->flag & PSYS_DELETE || !psys->part)
- return 0;
+ if (psys->flag & PSYS_DISABLED || psys->flag & PSYS_DELETE || !psys->part)
+ return 0;
- psmd = psys_get_modifier(ob, psys);
- if (use_render_params) {
- if (!(psmd->modifier.mode & eModifierMode_Render))
- return 0;
- }
- else if (!(psmd->modifier.mode & eModifierMode_Realtime))
- return 0;
+ psmd = psys_get_modifier(ob, psys);
+ if (use_render_params) {
+ if (!(psmd->modifier.mode & eModifierMode_Render))
+ return 0;
+ }
+ else if (!(psmd->modifier.mode & eModifierMode_Realtime))
+ return 0;
- return 1;
+ return 1;
}
bool psys_check_edited(ParticleSystem *psys)
{
- if (psys->part && psys->part->type == PART_HAIR)
- return (psys->flag & PSYS_EDITED || (psys->edit && psys->edit->edited));
- else
- return (psys->pointcache->edit && psys->pointcache->edit->edited);
+ if (psys->part && psys->part->type == PART_HAIR)
+ return (psys->flag & PSYS_EDITED || (psys->edit && psys->edit->edited));
+ else
+ return (psys->pointcache->edit && psys->pointcache->edit->edited);
}
void psys_find_group_weights(ParticleSettings *part)
{
- /* Find object pointers based on index. If the collection is linked from
- * another library linking may not have the object pointers available on
- * file load, so we have to retrieve them later. See T49273. */
- const ListBase instance_collection_objects = BKE_collection_object_cache_get(part->instance_collection);
-
- for (ParticleDupliWeight *dw = part->instance_weights.first; dw; dw = dw->next) {
- if (dw->ob == NULL) {
- Base *base = BLI_findlink(&instance_collection_objects, dw->index);
- if (base != NULL) {
- dw->ob = base->object;
- }
- }
- }
+ /* Find object pointers based on index. If the collection is linked from
+ * another library linking may not have the object pointers available on
+ * file load, so we have to retrieve them later. See T49273. */
+ const ListBase instance_collection_objects = BKE_collection_object_cache_get(
+ part->instance_collection);
+
+ for (ParticleDupliWeight *dw = part->instance_weights.first; dw; dw = dw->next) {
+ if (dw->ob == NULL) {
+ Base *base = BLI_findlink(&instance_collection_objects, dw->index);
+ if (base != NULL) {
+ dw->ob = base->object;
+ }
+ }
+ }
}
void psys_check_group_weights(ParticleSettings *part)
{
- ParticleDupliWeight *dw, *tdw;
-
- if (part->ren_as != PART_DRAW_GR || !part->instance_collection) {
- BLI_freelistN(&part->instance_weights);
- return;
- }
-
- /* Find object pointers. */
- psys_find_group_weights(part);
-
- /* Remove NULL objects, that were removed from the collection. */
- dw = part->instance_weights.first;
- while (dw) {
- if (dw->ob == NULL || !BKE_collection_has_object_recursive(part->instance_collection, dw->ob)) {
- tdw = dw->next;
- BLI_freelinkN(&part->instance_weights, dw);
- dw = tdw;
- }
- else {
- dw = dw->next;
- }
- }
-
- /* Add new objects in the collection. */
- int index = 0;
- FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(part->instance_collection, object)
- {
- dw = part->instance_weights.first;
- while (dw && dw->ob != object) {
- dw = dw->next;
- }
-
- if (!dw) {
- dw = MEM_callocN(sizeof(ParticleDupliWeight), "ParticleDupliWeight");
- dw->ob = object;
- dw->count = 1;
- BLI_addtail(&part->instance_weights, dw);
- }
-
- dw->index = index++;
- }
- FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
-
- /* Ensure there is an element marked as current. */
- int current = 0;
- for (dw = part->instance_weights.first; dw; dw = dw->next) {
- if (dw->flag & PART_DUPLIW_CURRENT) {
- current = 1;
- break;
- }
- }
-
- if (!current) {
- dw = part->instance_weights.first;
- if (dw)
- dw->flag |= PART_DUPLIW_CURRENT;
- }
+ ParticleDupliWeight *dw, *tdw;
+
+ if (part->ren_as != PART_DRAW_GR || !part->instance_collection) {
+ BLI_freelistN(&part->instance_weights);
+ return;
+ }
+
+ /* Find object pointers. */
+ psys_find_group_weights(part);
+
+ /* Remove NULL objects, that were removed from the collection. */
+ dw = part->instance_weights.first;
+ while (dw) {
+ if (dw->ob == NULL ||
+ !BKE_collection_has_object_recursive(part->instance_collection, dw->ob)) {
+ tdw = dw->next;
+ BLI_freelinkN(&part->instance_weights, dw);
+ dw = tdw;
+ }
+ else {
+ dw = dw->next;
+ }
+ }
+
+ /* Add new objects in the collection. */
+ int index = 0;
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (part->instance_collection, object) {
+ dw = part->instance_weights.first;
+ while (dw && dw->ob != object) {
+ dw = dw->next;
+ }
+
+ if (!dw) {
+ dw = MEM_callocN(sizeof(ParticleDupliWeight), "ParticleDupliWeight");
+ dw->ob = object;
+ dw->count = 1;
+ BLI_addtail(&part->instance_weights, dw);
+ }
+
+ dw->index = index++;
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+
+ /* Ensure there is an element marked as current. */
+ int current = 0;
+ for (dw = part->instance_weights.first; dw; dw = dw->next) {
+ if (dw->flag & PART_DUPLIW_CURRENT) {
+ current = 1;
+ break;
+ }
+ }
+
+ if (!current) {
+ dw = part->instance_weights.first;
+ if (dw)
+ dw->flag |= PART_DUPLIW_CURRENT;
+ }
}
int psys_uses_gravity(ParticleSimulationData *sim)
{
- return sim->scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY && sim->psys->part && sim->psys->part->effector_weights->global_gravity != 0.0f;
+ return sim->scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY && sim->psys->part &&
+ sim->psys->part->effector_weights->global_gravity != 0.0f;
}
/************************************************/
-/* Freeing stuff */
+/* Freeing stuff */
/************************************************/
static void fluid_free_settings(SPHFluidSettings *fluid)
{
- if (fluid)
- MEM_freeN(fluid);
+ if (fluid)
+ MEM_freeN(fluid);
}
/** Free (or release) any data used by this particle settings (does not free the partsett itself). */
void BKE_particlesettings_free(ParticleSettings *part)
{
- int a;
+ int a;
- BKE_animdata_free((ID *)part, false);
+ BKE_animdata_free((ID *)part, false);
- for (a = 0; a < MAX_MTEX; a++) {
- MEM_SAFE_FREE(part->mtex[a]);
- }
+ for (a = 0; a < MAX_MTEX; a++) {
+ MEM_SAFE_FREE(part->mtex[a]);
+ }
- if (part->clumpcurve)
- curvemapping_free(part->clumpcurve);
- if (part->roughcurve)
- curvemapping_free(part->roughcurve);
- if (part->twistcurve)
- curvemapping_free(part->twistcurve);
+ if (part->clumpcurve)
+ curvemapping_free(part->clumpcurve);
+ if (part->roughcurve)
+ curvemapping_free(part->roughcurve);
+ if (part->twistcurve)
+ curvemapping_free(part->twistcurve);
- BKE_partdeflect_free(part->pd);
- BKE_partdeflect_free(part->pd2);
+ BKE_partdeflect_free(part->pd);
+ BKE_partdeflect_free(part->pd2);
- MEM_SAFE_FREE(part->effector_weights);
+ MEM_SAFE_FREE(part->effector_weights);
- BLI_freelistN(&part->instance_weights);
+ BLI_freelistN(&part->instance_weights);
- boid_free_settings(part->boids);
- fluid_free_settings(part->fluid);
+ boid_free_settings(part->boids);
+ fluid_free_settings(part->fluid);
}
void free_hair(Object *object, ParticleSystem *psys, int dynamics)
{
- PARTICLE_P;
-
- LOOP_PARTICLES {
- if (pa->hair)
- MEM_freeN(pa->hair);
- pa->hair = NULL;
- pa->totkey = 0;
- }
-
- psys->flag &= ~PSYS_HAIR_DONE;
-
- if (psys->clmd) {
- if (dynamics) {
- modifier_free((ModifierData *)psys->clmd);
- psys->clmd = NULL;
- PTCacheID pid;
- BKE_ptcache_id_from_particles(&pid, object, psys);
- BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_ALL, 0);
- }
- else {
- cloth_free_modifier(psys->clmd);
- }
- }
-
- if (psys->hair_in_mesh)
- BKE_id_free(NULL, psys->hair_in_mesh);
- psys->hair_in_mesh = NULL;
-
- if (psys->hair_out_mesh)
- BKE_id_free(NULL, psys->hair_out_mesh);
- psys->hair_out_mesh = NULL;
+ PARTICLE_P;
+
+ LOOP_PARTICLES
+ {
+ if (pa->hair)
+ MEM_freeN(pa->hair);
+ pa->hair = NULL;
+ pa->totkey = 0;
+ }
+
+ psys->flag &= ~PSYS_HAIR_DONE;
+
+ if (psys->clmd) {
+ if (dynamics) {
+ modifier_free((ModifierData *)psys->clmd);
+ psys->clmd = NULL;
+ PTCacheID pid;
+ BKE_ptcache_id_from_particles(&pid, object, psys);
+ BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_ALL, 0);
+ }
+ else {
+ cloth_free_modifier(psys->clmd);
+ }
+ }
+
+ if (psys->hair_in_mesh)
+ BKE_id_free(NULL, psys->hair_in_mesh);
+ psys->hair_in_mesh = NULL;
+
+ if (psys->hair_out_mesh)
+ BKE_id_free(NULL, psys->hair_out_mesh);
+ psys->hair_out_mesh = NULL;
}
void free_keyed_keys(ParticleSystem *psys)
{
- PARTICLE_P;
-
- if (psys->part->type == PART_HAIR)
- return;
-
- if (psys->particles && psys->particles->keys) {
- MEM_freeN(psys->particles->keys);
-
- LOOP_PARTICLES {
- if (pa->keys) {
- pa->keys = NULL;
- pa->totkey = 0;
- }
- }
- }
+ PARTICLE_P;
+
+ if (psys->part->type == PART_HAIR)
+ return;
+
+ if (psys->particles && psys->particles->keys) {
+ MEM_freeN(psys->particles->keys);
+
+ LOOP_PARTICLES
+ {
+ if (pa->keys) {
+ pa->keys = NULL;
+ pa->totkey = 0;
+ }
+ }
+ }
}
static void free_child_path_cache(ParticleSystem *psys)
{
- psys_free_path_cache_buffers(psys->childcache, &psys->childcachebufs);
- psys->childcache = NULL;
- psys->totchildcache = 0;
+ psys_free_path_cache_buffers(psys->childcache, &psys->childcachebufs);
+ psys->childcache = NULL;
+ psys->totchildcache = 0;
}
void psys_free_path_cache(ParticleSystem *psys, PTCacheEdit *edit)
{
- if (edit) {
- psys_free_path_cache_buffers(edit->pathcache, &edit->pathcachebufs);
- edit->pathcache = NULL;
- edit->totcached = 0;
- }
- if (psys) {
- psys_free_path_cache_buffers(psys->pathcache, &psys->pathcachebufs);
- psys->pathcache = NULL;
- psys->totcached = 0;
-
- free_child_path_cache(psys);
- }
+ if (edit) {
+ psys_free_path_cache_buffers(edit->pathcache, &edit->pathcachebufs);
+ edit->pathcache = NULL;
+ edit->totcached = 0;
+ }
+ if (psys) {
+ psys_free_path_cache_buffers(psys->pathcache, &psys->pathcachebufs);
+ psys->pathcache = NULL;
+ psys->totcached = 0;
+
+ free_child_path_cache(psys);
+ }
}
void psys_free_children(ParticleSystem *psys)
{
- if (psys->child) {
- MEM_freeN(psys->child);
- psys->child = NULL;
- psys->totchild = 0;
- }
+ if (psys->child) {
+ MEM_freeN(psys->child);
+ psys->child = NULL;
+ psys->totchild = 0;
+ }
- free_child_path_cache(psys);
+ free_child_path_cache(psys);
}
void psys_free_particles(ParticleSystem *psys)
{
- PARTICLE_P;
-
- if (psys->particles) {
- /* Even though psys->part should never be NULL, this can happen as an exception during deletion.
- * See ID_REMAP_SKIP/FORCE/FLAG_NEVER_NULL_USAGE in BKE_library_remap. */
- if (psys->part && psys->part->type == PART_HAIR) {
- LOOP_PARTICLES {
- if (pa->hair)
- MEM_freeN(pa->hair);
- }
- }
-
- if (psys->particles->keys)
- MEM_freeN(psys->particles->keys);
-
- if (psys->particles->boid)
- MEM_freeN(psys->particles->boid);
-
- MEM_freeN(psys->particles);
- psys->particles = NULL;
- psys->totpart = 0;
- }
+ PARTICLE_P;
+
+ if (psys->particles) {
+ /* Even though psys->part should never be NULL, this can happen as an exception during deletion.
+ * See ID_REMAP_SKIP/FORCE/FLAG_NEVER_NULL_USAGE in BKE_library_remap. */
+ if (psys->part && psys->part->type == PART_HAIR) {
+ LOOP_PARTICLES
+ {
+ if (pa->hair)
+ MEM_freeN(pa->hair);
+ }
+ }
+
+ if (psys->particles->keys)
+ MEM_freeN(psys->particles->keys);
+
+ if (psys->particles->boid)
+ MEM_freeN(psys->particles->boid);
+
+ MEM_freeN(psys->particles);
+ psys->particles = NULL;
+ psys->totpart = 0;
+ }
}
void psys_free_pdd(ParticleSystem *psys)
{
- if (psys->pdd) {
- if (psys->pdd->cdata)
- MEM_freeN(psys->pdd->cdata);
- psys->pdd->cdata = NULL;
-
- if (psys->pdd->vdata)
- MEM_freeN(psys->pdd->vdata);
- psys->pdd->vdata = NULL;
-
- if (psys->pdd->ndata)
- MEM_freeN(psys->pdd->ndata);
- psys->pdd->ndata = NULL;
-
- if (psys->pdd->vedata)
- MEM_freeN(psys->pdd->vedata);
- psys->pdd->vedata = NULL;
-
- psys->pdd->totpoint = 0;
- psys->pdd->totpart = 0;
- psys->pdd->partsize = 0;
- }
+ if (psys->pdd) {
+ if (psys->pdd->cdata)
+ MEM_freeN(psys->pdd->cdata);
+ psys->pdd->cdata = NULL;
+
+ if (psys->pdd->vdata)
+ MEM_freeN(psys->pdd->vdata);
+ psys->pdd->vdata = NULL;
+
+ if (psys->pdd->ndata)
+ MEM_freeN(psys->pdd->ndata);
+ psys->pdd->ndata = NULL;
+
+ if (psys->pdd->vedata)
+ MEM_freeN(psys->pdd->vedata);
+ psys->pdd->vedata = NULL;
+
+ psys->pdd->totpoint = 0;
+ psys->pdd->totpart = 0;
+ psys->pdd->partsize = 0;
+ }
}
/* free everything */
void psys_free(Object *ob, ParticleSystem *psys)
{
- if (psys) {
- int nr = 0;
- ParticleSystem *tpsys;
-
- psys_free_path_cache(psys, NULL);
-
- /* NOTE: We pass dynamics=0 to free_hair() to prevent it from doing an
- * unneeded clear of the cache. But for historical reason that code path
- * was only clearing cloth part of modifier data.
- *
- * Part of the story there is that particle evaluation is trying to not
- * re-allocate thew ModifierData itself, and limits all allocations to
- * the cloth part of it.
- *
- * Why evaluation is relying on hair_free() and in some specific code
- * paths there is beyond me.
- */
- free_hair(ob, psys, 0);
- if (psys->clmd != NULL) {
- modifier_free((ModifierData *)psys->clmd);
- }
-
- psys_free_particles(psys);
-
- if (psys->edit && psys->free_edit)
- psys->free_edit(psys->edit);
-
- if (psys->child) {
- MEM_freeN(psys->child);
- psys->child = NULL;
- psys->totchild = 0;
- }
-
- /* check if we are last non-visible particle system */
- for (tpsys = ob->particlesystem.first; tpsys; tpsys = tpsys->next) {
- if (tpsys->part) {
- if (ELEM(tpsys->part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) {
- nr++;
- break;
- }
- }
- }
- /* clear do-not-draw-flag */
- if (!nr)
- ob->transflag &= ~OB_DUPLIPARTS;
-
- psys->part = NULL;
-
- if ((psys->flag & PSYS_SHARED_CACHES) == 0) {
- BKE_ptcache_free_list(&psys->ptcaches);
- }
- psys->pointcache = NULL;
-
- BLI_freelistN(&psys->targets);
-
- BLI_bvhtree_free(psys->bvhtree);
- BLI_kdtree_3d_free(psys->tree);
-
- if (psys->fluid_springs)
- MEM_freeN(psys->fluid_springs);
-
- BKE_effectors_free(psys->effectors);
-
- if (psys->pdd) {
- psys_free_pdd(psys);
- MEM_freeN(psys->pdd);
- }
-
- BKE_particle_batch_cache_free(psys);
-
- MEM_freeN(psys);
- }
+ if (psys) {
+ int nr = 0;
+ ParticleSystem *tpsys;
+
+ psys_free_path_cache(psys, NULL);
+
+ /* NOTE: We pass dynamics=0 to free_hair() to prevent it from doing an
+ * unneeded clear of the cache. But for historical reason that code path
+ * was only clearing cloth part of modifier data.
+ *
+ * Part of the story there is that particle evaluation is trying to not
+ * re-allocate thew ModifierData itself, and limits all allocations to
+ * the cloth part of it.
+ *
+ * Why evaluation is relying on hair_free() and in some specific code
+ * paths there is beyond me.
+ */
+ free_hair(ob, psys, 0);
+ if (psys->clmd != NULL) {
+ modifier_free((ModifierData *)psys->clmd);
+ }
+
+ psys_free_particles(psys);
+
+ if (psys->edit && psys->free_edit)
+ psys->free_edit(psys->edit);
+
+ if (psys->child) {
+ MEM_freeN(psys->child);
+ psys->child = NULL;
+ psys->totchild = 0;
+ }
+
+ /* check if we are last non-visible particle system */
+ for (tpsys = ob->particlesystem.first; tpsys; tpsys = tpsys->next) {
+ if (tpsys->part) {
+ if (ELEM(tpsys->part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) {
+ nr++;
+ break;
+ }
+ }
+ }
+ /* clear do-not-draw-flag */
+ if (!nr)
+ ob->transflag &= ~OB_DUPLIPARTS;
+
+ psys->part = NULL;
+
+ if ((psys->flag & PSYS_SHARED_CACHES) == 0) {
+ BKE_ptcache_free_list(&psys->ptcaches);
+ }
+ psys->pointcache = NULL;
+
+ BLI_freelistN(&psys->targets);
+
+ BLI_bvhtree_free(psys->bvhtree);
+ BLI_kdtree_3d_free(psys->tree);
+
+ if (psys->fluid_springs)
+ MEM_freeN(psys->fluid_springs);
+
+ BKE_effectors_free(psys->effectors);
+
+ if (psys->pdd) {
+ psys_free_pdd(psys);
+ MEM_freeN(psys->pdd);
+ }
+
+ BKE_particle_batch_cache_free(psys);
+
+ MEM_freeN(psys);
+ }
}
void psys_copy_particles(ParticleSystem *psys_dst, ParticleSystem *psys_src)
{
- /* Free existing particles. */
- if (psys_dst->particles != psys_src->particles) {
- psys_free_particles(psys_dst);
- }
- if (psys_dst->child != psys_src->child) {
- psys_free_children(psys_dst);
- }
- /* Restore counters. */
- psys_dst->totpart = psys_src->totpart;
- psys_dst->totchild = psys_src->totchild;
- /* Copy particles and children. */
- psys_dst->particles = MEM_dupallocN(psys_src->particles);
- psys_dst->child = MEM_dupallocN(psys_src->child);
- if (psys_dst->part->type == PART_HAIR) {
- ParticleData *pa;
- int p;
- for (p = 0, pa = psys_dst->particles; p < psys_dst->totpart; p++, pa++) {
- pa->hair = MEM_dupallocN(pa->hair);
- }
- }
- if (psys_dst->particles && (psys_dst->particles->keys || psys_dst->particles->boid)) {
- ParticleKey *key = psys_dst->particles->keys;
- BoidParticle *boid = psys_dst->particles->boid;
- ParticleData *pa;
- int p;
- if (key != NULL) {
- key = MEM_dupallocN(key);
- }
- if (boid != NULL) {
- boid = MEM_dupallocN(boid);
- }
- for (p = 0, pa = psys_dst->particles; p < psys_dst->totpart; p++, pa++) {
- if (boid != NULL) {
- pa->boid = boid++;
- }
- if (key != NULL) {
- pa->keys = key;
- key += pa->totkey;
- }
- }
- }
+ /* Free existing particles. */
+ if (psys_dst->particles != psys_src->particles) {
+ psys_free_particles(psys_dst);
+ }
+ if (psys_dst->child != psys_src->child) {
+ psys_free_children(psys_dst);
+ }
+ /* Restore counters. */
+ psys_dst->totpart = psys_src->totpart;
+ psys_dst->totchild = psys_src->totchild;
+ /* Copy particles and children. */
+ psys_dst->particles = MEM_dupallocN(psys_src->particles);
+ psys_dst->child = MEM_dupallocN(psys_src->child);
+ if (psys_dst->part->type == PART_HAIR) {
+ ParticleData *pa;
+ int p;
+ for (p = 0, pa = psys_dst->particles; p < psys_dst->totpart; p++, pa++) {
+ pa->hair = MEM_dupallocN(pa->hair);
+ }
+ }
+ if (psys_dst->particles && (psys_dst->particles->keys || psys_dst->particles->boid)) {
+ ParticleKey *key = psys_dst->particles->keys;
+ BoidParticle *boid = psys_dst->particles->boid;
+ ParticleData *pa;
+ int p;
+ if (key != NULL) {
+ key = MEM_dupallocN(key);
+ }
+ if (boid != NULL) {
+ boid = MEM_dupallocN(boid);
+ }
+ for (p = 0, pa = psys_dst->particles; p < psys_dst->totpart; p++, pa++) {
+ if (boid != NULL) {
+ pa->boid = boid++;
+ }
+ if (key != NULL) {
+ pa->keys = key;
+ key += pa->totkey;
+ }
+ }
+ }
}
/************************************************/
-/* Interpolation */
+/* Interpolation */
/************************************************/
-static float interpolate_particle_value(float v1, float v2, float v3, float v4, const float w[4], int four)
+static float interpolate_particle_value(
+ float v1, float v2, float v3, float v4, const float w[4], int four)
{
- float value;
+ float value;
- value = w[0] * v1 + w[1] * v2 + w[2] * v3;
- if (four)
- value += w[3] * v4;
+ value = w[0] * v1 + w[1] * v2 + w[2] * v3;
+ if (four)
+ value += w[3] * v4;
- CLAMP(value, 0.f, 1.f);
+ CLAMP(value, 0.f, 1.f);
- return value;
+ return value;
}
-void psys_interpolate_particle(short type, ParticleKey keys[4], float dt, ParticleKey *result, bool velocity)
+void psys_interpolate_particle(
+ short type, ParticleKey keys[4], float dt, ParticleKey *result, bool velocity)
{
- float t[4];
-
- if (type < 0) {
- interp_cubic_v3(result->co, result->vel, keys[1].co, keys[1].vel, keys[2].co, keys[2].vel, dt);
- }
- else {
- key_curve_position_weights(dt, t, type);
-
- interp_v3_v3v3v3v3(result->co, keys[0].co, keys[1].co, keys[2].co, keys[3].co, t);
-
- if (velocity) {
- float temp[3];
-
- if (dt > 0.999f) {
- key_curve_position_weights(dt - 0.001f, t, type);
- interp_v3_v3v3v3v3(temp, keys[0].co, keys[1].co, keys[2].co, keys[3].co, t);
- sub_v3_v3v3(result->vel, result->co, temp);
- }
- else {
- key_curve_position_weights(dt + 0.001f, t, type);
- interp_v3_v3v3v3v3(temp, keys[0].co, keys[1].co, keys[2].co, keys[3].co, t);
- sub_v3_v3v3(result->vel, temp, result->co);
- }
- }
- }
+ float t[4];
+
+ if (type < 0) {
+ interp_cubic_v3(result->co, result->vel, keys[1].co, keys[1].vel, keys[2].co, keys[2].vel, dt);
+ }
+ else {
+ key_curve_position_weights(dt, t, type);
+
+ interp_v3_v3v3v3v3(result->co, keys[0].co, keys[1].co, keys[2].co, keys[3].co, t);
+
+ if (velocity) {
+ float temp[3];
+
+ if (dt > 0.999f) {
+ key_curve_position_weights(dt - 0.001f, t, type);
+ interp_v3_v3v3v3v3(temp, keys[0].co, keys[1].co, keys[2].co, keys[3].co, t);
+ sub_v3_v3v3(result->vel, result->co, temp);
+ }
+ else {
+ key_curve_position_weights(dt + 0.001f, t, type);
+ interp_v3_v3v3v3v3(temp, keys[0].co, keys[1].co, keys[2].co, keys[3].co, t);
+ sub_v3_v3v3(result->vel, temp, result->co);
+ }
+ }
+ }
}
-
typedef struct ParticleInterpolationData {
- HairKey *hkey[2];
+ HairKey *hkey[2];
- Mesh *mesh;
- MVert *mvert[2];
+ Mesh *mesh;
+ MVert *mvert[2];
- int keyed;
- ParticleKey *kkey[2];
+ int keyed;
+ ParticleKey *kkey[2];
- PointCache *cache;
- PTCacheMem *pm;
+ PointCache *cache;
+ PTCacheMem *pm;
- PTCacheEditPoint *epoint;
- PTCacheEditKey *ekey[2];
+ PTCacheEditPoint *epoint;
+ PTCacheEditKey *ekey[2];
- float birthtime, dietime;
- int bspline;
+ float birthtime, dietime;
+ int bspline;
} ParticleInterpolationData;
/* Assumes pointcache->mem_cache exists, so for disk cached particles call psys_make_temp_pointcache() before use */
/* It uses ParticleInterpolationData->pm to store the current memory cache frame so it's thread safe. */
-static void get_pointcache_keys_for_time(Object *UNUSED(ob), PointCache *cache, PTCacheMem **cur, int index, float t, ParticleKey *key1, ParticleKey *key2)
+static void get_pointcache_keys_for_time(Object *UNUSED(ob),
+ PointCache *cache,
+ PTCacheMem **cur,
+ int index,
+ float t,
+ ParticleKey *key1,
+ ParticleKey *key2)
{
- static PTCacheMem *pm = NULL;
- int index1, index2;
-
- if (index < 0) { /* initialize */
- *cur = cache->mem_cache.first;
-
- if (*cur)
- *cur = (*cur)->next;
- }
- else {
- if (*cur) {
- while (*cur && (*cur)->next && (float)(*cur)->frame < t)
- *cur = (*cur)->next;
-
- pm = *cur;
-
- index2 = BKE_ptcache_mem_index_find(pm, index);
- index1 = BKE_ptcache_mem_index_find(pm->prev, index);
- if (index2 < 0) {
- return;
- }
-
- BKE_ptcache_make_particle_key(key2, index2, pm->data, (float)pm->frame);
- if (index1 < 0)
- copy_particle_key(key1, key2, 1);
- else
- BKE_ptcache_make_particle_key(key1, index1, pm->prev->data, (float)pm->prev->frame);
- }
- else if (cache->mem_cache.first) {
- pm = cache->mem_cache.first;
- index2 = BKE_ptcache_mem_index_find(pm, index);
- if (index2 < 0) {
- return;
- }
- BKE_ptcache_make_particle_key(key2, index2, pm->data, (float)pm->frame);
- copy_particle_key(key1, key2, 1);
- }
- }
+ static PTCacheMem *pm = NULL;
+ int index1, index2;
+
+ if (index < 0) { /* initialize */
+ *cur = cache->mem_cache.first;
+
+ if (*cur)
+ *cur = (*cur)->next;
+ }
+ else {
+ if (*cur) {
+ while (*cur && (*cur)->next && (float)(*cur)->frame < t)
+ *cur = (*cur)->next;
+
+ pm = *cur;
+
+ index2 = BKE_ptcache_mem_index_find(pm, index);
+ index1 = BKE_ptcache_mem_index_find(pm->prev, index);
+ if (index2 < 0) {
+ return;
+ }
+
+ BKE_ptcache_make_particle_key(key2, index2, pm->data, (float)pm->frame);
+ if (index1 < 0)
+ copy_particle_key(key1, key2, 1);
+ else
+ BKE_ptcache_make_particle_key(key1, index1, pm->prev->data, (float)pm->prev->frame);
+ }
+ else if (cache->mem_cache.first) {
+ pm = cache->mem_cache.first;
+ index2 = BKE_ptcache_mem_index_find(pm, index);
+ if (index2 < 0) {
+ return;
+ }
+ BKE_ptcache_make_particle_key(key2, index2, pm->data, (float)pm->frame);
+ copy_particle_key(key1, key2, 1);
+ }
+ }
}
-static int get_pointcache_times_for_particle(PointCache *cache, int index, float *start, float *end)
+static int get_pointcache_times_for_particle(PointCache *cache,
+ int index,
+ float *start,
+ float *end)
{
- PTCacheMem *pm;
- int ret = 0;
-
- for (pm = cache->mem_cache.first; pm; pm = pm->next) {
- if (BKE_ptcache_mem_index_find(pm, index) >= 0) {
- *start = pm->frame;
- ret++;
- break;
- }
- }
-
- for (pm = cache->mem_cache.last; pm; pm = pm->prev) {
- if (BKE_ptcache_mem_index_find(pm, index) >= 0) {
- *end = pm->frame;
- ret++;
- break;
- }
- }
-
- return ret == 2;
+ PTCacheMem *pm;
+ int ret = 0;
+
+ for (pm = cache->mem_cache.first; pm; pm = pm->next) {
+ if (BKE_ptcache_mem_index_find(pm, index) >= 0) {
+ *start = pm->frame;
+ ret++;
+ break;
+ }
+ }
+
+ for (pm = cache->mem_cache.last; pm; pm = pm->prev) {
+ if (BKE_ptcache_mem_index_find(pm, index) >= 0) {
+ *end = pm->frame;
+ ret++;
+ break;
+ }
+ }
+
+ return ret == 2;
}
float psys_get_dietime_from_cache(PointCache *cache, int index)
{
- PTCacheMem *pm;
- int dietime = 10000000; /* some max value so that we can default to pa->time+lifetime */
+ PTCacheMem *pm;
+ int dietime = 10000000; /* some max value so that we can default to pa->time+lifetime */
- for (pm = cache->mem_cache.last; pm; pm = pm->prev) {
- if (BKE_ptcache_mem_index_find(pm, index) >= 0)
- return (float)pm->frame;
- }
+ for (pm = cache->mem_cache.last; pm; pm = pm->prev) {
+ if (BKE_ptcache_mem_index_find(pm, index) >= 0)
+ return (float)pm->frame;
+ }
- return (float)dietime;
+ return (float)dietime;
}
-static void init_particle_interpolation(Object *ob, ParticleSystem *psys, ParticleData *pa, ParticleInterpolationData *pind)
+static void init_particle_interpolation(Object *ob,
+ ParticleSystem *psys,
+ ParticleData *pa,
+ ParticleInterpolationData *pind)
{
- if (pind->epoint) {
- PTCacheEditPoint *point = pind->epoint;
-
- pind->ekey[0] = point->keys;
- pind->ekey[1] = point->totkey > 1 ? point->keys + 1 : NULL;
-
- pind->birthtime = *(point->keys->time);
- pind->dietime = *((point->keys + point->totkey - 1)->time);
- }
- else if (pind->keyed) {
- ParticleKey *key = pa->keys;
- pind->kkey[0] = key;
- pind->kkey[1] = pa->totkey > 1 ? key + 1 : NULL;
-
- pind->birthtime = key->time;
- pind->dietime = (key + pa->totkey - 1)->time;
- }
- else if (pind->cache) {
- float start = 0.0f, end = 0.0f;
- get_pointcache_keys_for_time(ob, pind->cache, &pind->pm, -1, 0.0f, NULL, NULL);
- pind->birthtime = pa ? pa->time : pind->cache->startframe;
- pind->dietime = pa ? pa->dietime : pind->cache->endframe;
-
- if (get_pointcache_times_for_particle(pind->cache, pa - psys->particles, &start, &end)) {
- pind->birthtime = MAX2(pind->birthtime, start);
- pind->dietime = MIN2(pind->dietime, end);
- }
- }
- else {
- HairKey *key = pa->hair;
- pind->hkey[0] = key;
- pind->hkey[1] = key + 1;
-
- pind->birthtime = key->time;
- pind->dietime = (key + pa->totkey - 1)->time;
-
- if (pind->mesh) {
- pind->mvert[0] = &pind->mesh->mvert[pa->hair_index];
- pind->mvert[1] = pind->mvert[0] + 1;
- }
- }
+ if (pind->epoint) {
+ PTCacheEditPoint *point = pind->epoint;
+
+ pind->ekey[0] = point->keys;
+ pind->ekey[1] = point->totkey > 1 ? point->keys + 1 : NULL;
+
+ pind->birthtime = *(point->keys->time);
+ pind->dietime = *((point->keys + point->totkey - 1)->time);
+ }
+ else if (pind->keyed) {
+ ParticleKey *key = pa->keys;
+ pind->kkey[0] = key;
+ pind->kkey[1] = pa->totkey > 1 ? key + 1 : NULL;
+
+ pind->birthtime = key->time;
+ pind->dietime = (key + pa->totkey - 1)->time;
+ }
+ else if (pind->cache) {
+ float start = 0.0f, end = 0.0f;
+ get_pointcache_keys_for_time(ob, pind->cache, &pind->pm, -1, 0.0f, NULL, NULL);
+ pind->birthtime = pa ? pa->time : pind->cache->startframe;
+ pind->dietime = pa ? pa->dietime : pind->cache->endframe;
+
+ if (get_pointcache_times_for_particle(pind->cache, pa - psys->particles, &start, &end)) {
+ pind->birthtime = MAX2(pind->birthtime, start);
+ pind->dietime = MIN2(pind->dietime, end);
+ }
+ }
+ else {
+ HairKey *key = pa->hair;
+ pind->hkey[0] = key;
+ pind->hkey[1] = key + 1;
+
+ pind->birthtime = key->time;
+ pind->dietime = (key + pa->totkey - 1)->time;
+
+ if (pind->mesh) {
+ pind->mvert[0] = &pind->mesh->mvert[pa->hair_index];
+ pind->mvert[1] = pind->mvert[0] + 1;
+ }
+ }
}
static void edit_to_particle(ParticleKey *key, PTCacheEditKey *ekey)
{
- copy_v3_v3(key->co, ekey->co);
- if (ekey->vel) {
- copy_v3_v3(key->vel, ekey->vel);
- }
- key->time = *(ekey->time);
+ copy_v3_v3(key->co, ekey->co);
+ if (ekey->vel) {
+ copy_v3_v3(key->vel, ekey->vel);
+ }
+ key->time = *(ekey->time);
}
static void hair_to_particle(ParticleKey *key, HairKey *hkey)
{
- copy_v3_v3(key->co, hkey->co);
- key->time = hkey->time;
+ copy_v3_v3(key->co, hkey->co);
+ key->time = hkey->time;
}
static void mvert_to_particle(ParticleKey *key, MVert *mvert, HairKey *hkey)
{
- copy_v3_v3(key->co, mvert->co);
- key->time = hkey->time;
+ copy_v3_v3(key->co, mvert->co);
+ key->time = hkey->time;
}
-static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData *pa, float t, ParticleInterpolationData *pind, ParticleKey *result)
+static void do_particle_interpolation(ParticleSystem *psys,
+ int p,
+ ParticleData *pa,
+ float t,
+ ParticleInterpolationData *pind,
+ ParticleKey *result)
{
- PTCacheEditPoint *point = pind->epoint;
- ParticleKey keys[4];
- int point_vel = (point && point->keys->vel);
- float real_t, dfra, keytime, invdt = 1.f;
-
- /* billboards wont fill in all of these, so start cleared */
- memset(keys, 0, sizeof(keys));
-
- /* interpret timing and find keys */
- if (point) {
- if (result->time < 0.0f)
- real_t = -result->time;
- else
- real_t = *(pind->ekey[0]->time) + t * (*(pind->ekey[0][point->totkey - 1].time) - *(pind->ekey[0]->time));
-
- while (*(pind->ekey[1]->time) < real_t)
- pind->ekey[1]++;
-
- pind->ekey[0] = pind->ekey[1] - 1;
- }
- else if (pind->keyed) {
- /* we have only one key, so let's use that */
- if (pind->kkey[1] == NULL) {
- copy_particle_key(result, pind->kkey[0], 1);
- return;
- }
-
- if (result->time < 0.0f)
- real_t = -result->time;
- else
- real_t = pind->kkey[0]->time + t * (pind->kkey[0][pa->totkey - 1].time - pind->kkey[0]->time);
-
- if (psys->part->phystype == PART_PHYS_KEYED && psys->flag & PSYS_KEYED_TIMING) {
- ParticleTarget *pt = psys->targets.first;
-
- pt = pt->next;
-
- while (pt && pa->time + pt->time < real_t)
- pt = pt->next;
-
- if (pt) {
- pt = pt->prev;
-
- if (pa->time + pt->time + pt->duration > real_t)
- real_t = pa->time + pt->time;
- }
- else
- real_t = pa->time + ((ParticleTarget *)psys->targets.last)->time;
- }
-
- CLAMP(real_t, pa->time, pa->dietime);
-
- while (pind->kkey[1]->time < real_t)
- pind->kkey[1]++;
-
- pind->kkey[0] = pind->kkey[1] - 1;
- }
- else if (pind->cache) {
- if (result->time < 0.0f) /* flag for time in frames */
- real_t = -result->time;
- else
- real_t = pa->time + t * (pa->dietime - pa->time);
- }
- else {
- if (result->time < 0.0f)
- real_t = -result->time;
- else
- real_t = pind->hkey[0]->time + t * (pind->hkey[0][pa->totkey - 1].time - pind->hkey[0]->time);
-
- while (pind->hkey[1]->time < real_t) {
- pind->hkey[1]++;
- pind->mvert[1]++;
- }
-
- pind->hkey[0] = pind->hkey[1] - 1;
- }
-
- /* set actual interpolation keys */
- if (point) {
- edit_to_particle(keys + 1, pind->ekey[0]);
- edit_to_particle(keys + 2, pind->ekey[1]);
- }
- else if (pind->mesh) {
- pind->mvert[0] = pind->mvert[1] - 1;
- mvert_to_particle(keys + 1, pind->mvert[0], pind->hkey[0]);
- mvert_to_particle(keys + 2, pind->mvert[1], pind->hkey[1]);
- }
- else if (pind->keyed) {
- memcpy(keys + 1, pind->kkey[0], sizeof(ParticleKey));
- memcpy(keys + 2, pind->kkey[1], sizeof(ParticleKey));
- }
- else if (pind->cache) {
- get_pointcache_keys_for_time(NULL, pind->cache, &pind->pm, p, real_t, keys + 1, keys + 2);
- }
- else {
- hair_to_particle(keys + 1, pind->hkey[0]);
- hair_to_particle(keys + 2, pind->hkey[1]);
- }
-
- /* set secondary interpolation keys for hair */
- if (!pind->keyed && !pind->cache && !point_vel) {
- if (point) {
- if (pind->ekey[0] != point->keys)
- edit_to_particle(keys, pind->ekey[0] - 1);
- else
- edit_to_particle(keys, pind->ekey[0]);
- }
- else if (pind->mesh) {
- if (pind->hkey[0] != pa->hair)
- mvert_to_particle(keys, pind->mvert[0] - 1, pind->hkey[0] - 1);
- else
- mvert_to_particle(keys, pind->mvert[0], pind->hkey[0]);
- }
- else {
- if (pind->hkey[0] != pa->hair)
- hair_to_particle(keys, pind->hkey[0] - 1);
- else
- hair_to_particle(keys, pind->hkey[0]);
- }
-
- if (point) {
- if (pind->ekey[1] != point->keys + point->totkey - 1)
- edit_to_particle(keys + 3, pind->ekey[1] + 1);
- else
- edit_to_particle(keys + 3, pind->ekey[1]);
- }
- else if (pind->mesh) {
- if (pind->hkey[1] != pa->hair + pa->totkey - 1)
- mvert_to_particle(keys + 3, pind->mvert[1] + 1, pind->hkey[1] + 1);
- else
- mvert_to_particle(keys + 3, pind->mvert[1], pind->hkey[1]);
- }
- else {
- if (pind->hkey[1] != pa->hair + pa->totkey - 1)
- hair_to_particle(keys + 3, pind->hkey[1] + 1);
- else
- hair_to_particle(keys + 3, pind->hkey[1]);
- }
- }
-
- dfra = keys[2].time - keys[1].time;
- keytime = (real_t - keys[1].time) / dfra;
-
- /* convert velocity to timestep size */
- if (pind->keyed || pind->cache || point_vel) {
- invdt = dfra * 0.04f * (psys ? psys->part->timetweak : 1.f);
- mul_v3_fl(keys[1].vel, invdt);
- mul_v3_fl(keys[2].vel, invdt);
- interp_qt_qtqt(result->rot, keys[1].rot, keys[2].rot, keytime);
- }
-
- /* now we should have in chronologiacl order k1<=k2<=t<=k3<=k4 with keytime between [0, 1]->[k2, k3] (k1 & k4 used for cardinal & bspline interpolation)*/
- psys_interpolate_particle((pind->keyed || pind->cache || point_vel) ? -1 /* signal for cubic interpolation */
- : (pind->bspline ? KEY_BSPLINE : KEY_CARDINAL),
- keys, keytime, result, 1);
-
- /* the velocity needs to be converted back from cubic interpolation */
- if (pind->keyed || pind->cache || point_vel)
- mul_v3_fl(result->vel, 1.f / invdt);
+ PTCacheEditPoint *point = pind->epoint;
+ ParticleKey keys[4];
+ int point_vel = (point && point->keys->vel);
+ float real_t, dfra, keytime, invdt = 1.f;
+
+ /* billboards wont fill in all of these, so start cleared */
+ memset(keys, 0, sizeof(keys));
+
+ /* interpret timing and find keys */
+ if (point) {
+ if (result->time < 0.0f)
+ real_t = -result->time;
+ else
+ real_t = *(pind->ekey[0]->time) +
+ t * (*(pind->ekey[0][point->totkey - 1].time) - *(pind->ekey[0]->time));
+
+ while (*(pind->ekey[1]->time) < real_t)
+ pind->ekey[1]++;
+
+ pind->ekey[0] = pind->ekey[1] - 1;
+ }
+ else if (pind->keyed) {
+ /* we have only one key, so let's use that */
+ if (pind->kkey[1] == NULL) {
+ copy_particle_key(result, pind->kkey[0], 1);
+ return;
+ }
+
+ if (result->time < 0.0f)
+ real_t = -result->time;
+ else
+ real_t = pind->kkey[0]->time +
+ t * (pind->kkey[0][pa->totkey - 1].time - pind->kkey[0]->time);
+
+ if (psys->part->phystype == PART_PHYS_KEYED && psys->flag & PSYS_KEYED_TIMING) {
+ ParticleTarget *pt = psys->targets.first;
+
+ pt = pt->next;
+
+ while (pt && pa->time + pt->time < real_t)
+ pt = pt->next;
+
+ if (pt) {
+ pt = pt->prev;
+
+ if (pa->time + pt->time + pt->duration > real_t)
+ real_t = pa->time + pt->time;
+ }
+ else
+ real_t = pa->time + ((ParticleTarget *)psys->targets.last)->time;
+ }
+
+ CLAMP(real_t, pa->time, pa->dietime);
+
+ while (pind->kkey[1]->time < real_t)
+ pind->kkey[1]++;
+
+ pind->kkey[0] = pind->kkey[1] - 1;
+ }
+ else if (pind->cache) {
+ if (result->time < 0.0f) /* flag for time in frames */
+ real_t = -result->time;
+ else
+ real_t = pa->time + t * (pa->dietime - pa->time);
+ }
+ else {
+ if (result->time < 0.0f)
+ real_t = -result->time;
+ else
+ real_t = pind->hkey[0]->time +
+ t * (pind->hkey[0][pa->totkey - 1].time - pind->hkey[0]->time);
+
+ while (pind->hkey[1]->time < real_t) {
+ pind->hkey[1]++;
+ pind->mvert[1]++;
+ }
+
+ pind->hkey[0] = pind->hkey[1] - 1;
+ }
+
+ /* set actual interpolation keys */
+ if (point) {
+ edit_to_particle(keys + 1, pind->ekey[0]);
+ edit_to_particle(keys + 2, pind->ekey[1]);
+ }
+ else if (pind->mesh) {
+ pind->mvert[0] = pind->mvert[1] - 1;
+ mvert_to_particle(keys + 1, pind->mvert[0], pind->hkey[0]);
+ mvert_to_particle(keys + 2, pind->mvert[1], pind->hkey[1]);
+ }
+ else if (pind->keyed) {
+ memcpy(keys + 1, pind->kkey[0], sizeof(ParticleKey));
+ memcpy(keys + 2, pind->kkey[1], sizeof(ParticleKey));
+ }
+ else if (pind->cache) {
+ get_pointcache_keys_for_time(NULL, pind->cache, &pind->pm, p, real_t, keys + 1, keys + 2);
+ }
+ else {
+ hair_to_particle(keys + 1, pind->hkey[0]);
+ hair_to_particle(keys + 2, pind->hkey[1]);
+ }
+
+ /* set secondary interpolation keys for hair */
+ if (!pind->keyed && !pind->cache && !point_vel) {
+ if (point) {
+ if (pind->ekey[0] != point->keys)
+ edit_to_particle(keys, pind->ekey[0] - 1);
+ else
+ edit_to_particle(keys, pind->ekey[0]);
+ }
+ else if (pind->mesh) {
+ if (pind->hkey[0] != pa->hair)
+ mvert_to_particle(keys, pind->mvert[0] - 1, pind->hkey[0] - 1);
+ else
+ mvert_to_particle(keys, pind->mvert[0], pind->hkey[0]);
+ }
+ else {
+ if (pind->hkey[0] != pa->hair)
+ hair_to_particle(keys, pind->hkey[0] - 1);
+ else
+ hair_to_particle(keys, pind->hkey[0]);
+ }
+
+ if (point) {
+ if (pind->ekey[1] != point->keys + point->totkey - 1)
+ edit_to_particle(keys + 3, pind->ekey[1] + 1);
+ else
+ edit_to_particle(keys + 3, pind->ekey[1]);
+ }
+ else if (pind->mesh) {
+ if (pind->hkey[1] != pa->hair + pa->totkey - 1)
+ mvert_to_particle(keys + 3, pind->mvert[1] + 1, pind->hkey[1] + 1);
+ else
+ mvert_to_particle(keys + 3, pind->mvert[1], pind->hkey[1]);
+ }
+ else {
+ if (pind->hkey[1] != pa->hair + pa->totkey - 1)
+ hair_to_particle(keys + 3, pind->hkey[1] + 1);
+ else
+ hair_to_particle(keys + 3, pind->hkey[1]);
+ }
+ }
+
+ dfra = keys[2].time - keys[1].time;
+ keytime = (real_t - keys[1].time) / dfra;
+
+ /* convert velocity to timestep size */
+ if (pind->keyed || pind->cache || point_vel) {
+ invdt = dfra * 0.04f * (psys ? psys->part->timetweak : 1.f);
+ mul_v3_fl(keys[1].vel, invdt);
+ mul_v3_fl(keys[2].vel, invdt);
+ interp_qt_qtqt(result->rot, keys[1].rot, keys[2].rot, keytime);
+ }
+
+ /* now we should have in chronologiacl order k1<=k2<=t<=k3<=k4 with keytime between [0, 1]->[k2, k3] (k1 & k4 used for cardinal & bspline interpolation)*/
+ psys_interpolate_particle((pind->keyed || pind->cache || point_vel) ?
+ -1 /* signal for cubic interpolation */
+ :
+ (pind->bspline ? KEY_BSPLINE : KEY_CARDINAL),
+ keys,
+ keytime,
+ result,
+ 1);
+
+ /* the velocity needs to be converted back from cubic interpolation */
+ if (pind->keyed || pind->cache || point_vel)
+ mul_v3_fl(result->vel, 1.f / invdt);
}
static void interpolate_pathcache(ParticleCacheKey *first, float t, ParticleCacheKey *result)
{
- int i = 0;
- ParticleCacheKey *cur = first;
-
- /* scale the requested time to fit the entire path even if the path is cut early */
- t *= (first + first->segments)->time;
-
- while (i < first->segments && cur->time < t)
- cur++;
-
- if (cur->time == t)
- *result = *cur;
- else {
- float dt = (t - (cur - 1)->time) / (cur->time - (cur - 1)->time);
- interp_v3_v3v3(result->co, (cur - 1)->co, cur->co, dt);
- interp_v3_v3v3(result->vel, (cur - 1)->vel, cur->vel, dt);
- interp_qt_qtqt(result->rot, (cur - 1)->rot, cur->rot, dt);
- result->time = t;
- }
-
- /* first is actual base rotation, others are incremental from first */
- if (cur == first || cur - 1 == first)
- copy_qt_qt(result->rot, first->rot);
- else
- mul_qt_qtqt(result->rot, first->rot, result->rot);
+ int i = 0;
+ ParticleCacheKey *cur = first;
+
+ /* scale the requested time to fit the entire path even if the path is cut early */
+ t *= (first + first->segments)->time;
+
+ while (i < first->segments && cur->time < t)
+ cur++;
+
+ if (cur->time == t)
+ *result = *cur;
+ else {
+ float dt = (t - (cur - 1)->time) / (cur->time - (cur - 1)->time);
+ interp_v3_v3v3(result->co, (cur - 1)->co, cur->co, dt);
+ interp_v3_v3v3(result->vel, (cur - 1)->vel, cur->vel, dt);
+ interp_qt_qtqt(result->rot, (cur - 1)->rot, cur->rot, dt);
+ result->time = t;
+ }
+
+ /* first is actual base rotation, others are incremental from first */
+ if (cur == first || cur - 1 == first)
+ copy_qt_qt(result->rot, first->rot);
+ else
+ mul_qt_qtqt(result->rot, first->rot, result->rot);
}
/************************************************/
-/* Particles on a dm */
+/* Particles on a dm */
/************************************************/
/* interpolate a location on a face based on face coordinates */
-void psys_interpolate_face(MVert *mvert, MFace *mface, MTFace *tface, float (*orcodata)[3],
- float w[4], float vec[3], float nor[3], float utan[3], float vtan[3],
+void psys_interpolate_face(MVert *mvert,
+ MFace *mface,
+ MTFace *tface,
+ float (*orcodata)[3],
+ float w[4],
+ float vec[3],
+ float nor[3],
+ float utan[3],
+ float vtan[3],
float orco[3])
{
- float *v1 = 0, *v2 = 0, *v3 = 0, *v4 = 0;
- float e1[3], e2[3], s1, s2, t1, t2;
- float *uv1, *uv2, *uv3, *uv4;
- float n1[3], n2[3], n3[3], n4[3];
- float tuv[4][2];
- float *o1, *o2, *o3, *o4;
-
- v1 = mvert[mface->v1].co;
- v2 = mvert[mface->v2].co;
- v3 = mvert[mface->v3].co;
-
- normal_short_to_float_v3(n1, mvert[mface->v1].no);
- normal_short_to_float_v3(n2, mvert[mface->v2].no);
- normal_short_to_float_v3(n3, mvert[mface->v3].no);
-
- if (mface->v4) {
- v4 = mvert[mface->v4].co;
- normal_short_to_float_v3(n4, mvert[mface->v4].no);
-
- interp_v3_v3v3v3v3(vec, v1, v2, v3, v4, w);
-
- if (nor) {
- if (mface->flag & ME_SMOOTH)
- interp_v3_v3v3v3v3(nor, n1, n2, n3, n4, w);
- else
- normal_quad_v3(nor, v1, v2, v3, v4);
- }
- }
- else {
- interp_v3_v3v3v3(vec, v1, v2, v3, w);
-
- if (nor) {
- if (mface->flag & ME_SMOOTH)
- interp_v3_v3v3v3(nor, n1, n2, n3, w);
- else
- normal_tri_v3(nor, v1, v2, v3);
- }
- }
-
- /* calculate tangent vectors */
- if (utan && vtan) {
- if (tface) {
- uv1 = tface->uv[0];
- uv2 = tface->uv[1];
- uv3 = tface->uv[2];
- uv4 = tface->uv[3];
- }
- else {
- uv1 = tuv[0]; uv2 = tuv[1]; uv3 = tuv[2]; uv4 = tuv[3];
- map_to_sphere(uv1, uv1 + 1, v1[0], v1[1], v1[2]);
- map_to_sphere(uv2, uv2 + 1, v2[0], v2[1], v2[2]);
- map_to_sphere(uv3, uv3 + 1, v3[0], v3[1], v3[2]);
- if (v4)
- map_to_sphere(uv4, uv4 + 1, v4[0], v4[1], v4[2]);
- }
-
- if (v4) {
- s1 = uv3[0] - uv1[0];
- s2 = uv4[0] - uv1[0];
-
- t1 = uv3[1] - uv1[1];
- t2 = uv4[1] - uv1[1];
-
- sub_v3_v3v3(e1, v3, v1);
- sub_v3_v3v3(e2, v4, v1);
- }
- else {
- s1 = uv2[0] - uv1[0];
- s2 = uv3[0] - uv1[0];
-
- t1 = uv2[1] - uv1[1];
- t2 = uv3[1] - uv1[1];
-
- sub_v3_v3v3(e1, v2, v1);
- sub_v3_v3v3(e2, v3, v1);
- }
-
- vtan[0] = (s1 * e2[0] - s2 * e1[0]);
- vtan[1] = (s1 * e2[1] - s2 * e1[1]);
- vtan[2] = (s1 * e2[2] - s2 * e1[2]);
-
- utan[0] = (t1 * e2[0] - t2 * e1[0]);
- utan[1] = (t1 * e2[1] - t2 * e1[1]);
- utan[2] = (t1 * e2[2] - t2 * e1[2]);
- }
-
- if (orco) {
- if (orcodata) {
- o1 = orcodata[mface->v1];
- o2 = orcodata[mface->v2];
- o3 = orcodata[mface->v3];
-
- if (mface->v4) {
- o4 = orcodata[mface->v4];
-
- interp_v3_v3v3v3v3(orco, o1, o2, o3, o4, w);
- }
- else {
- interp_v3_v3v3v3(orco, o1, o2, o3, w);
- }
- }
- else {
- copy_v3_v3(orco, vec);
- }
- }
+ float *v1 = 0, *v2 = 0, *v3 = 0, *v4 = 0;
+ float e1[3], e2[3], s1, s2, t1, t2;
+ float *uv1, *uv2, *uv3, *uv4;
+ float n1[3], n2[3], n3[3], n4[3];
+ float tuv[4][2];
+ float *o1, *o2, *o3, *o4;
+
+ v1 = mvert[mface->v1].co;
+ v2 = mvert[mface->v2].co;
+ v3 = mvert[mface->v3].co;
+
+ normal_short_to_float_v3(n1, mvert[mface->v1].no);
+ normal_short_to_float_v3(n2, mvert[mface->v2].no);
+ normal_short_to_float_v3(n3, mvert[mface->v3].no);
+
+ if (mface->v4) {
+ v4 = mvert[mface->v4].co;
+ normal_short_to_float_v3(n4, mvert[mface->v4].no);
+
+ interp_v3_v3v3v3v3(vec, v1, v2, v3, v4, w);
+
+ if (nor) {
+ if (mface->flag & ME_SMOOTH)
+ interp_v3_v3v3v3v3(nor, n1, n2, n3, n4, w);
+ else
+ normal_quad_v3(nor, v1, v2, v3, v4);
+ }
+ }
+ else {
+ interp_v3_v3v3v3(vec, v1, v2, v3, w);
+
+ if (nor) {
+ if (mface->flag & ME_SMOOTH)
+ interp_v3_v3v3v3(nor, n1, n2, n3, w);
+ else
+ normal_tri_v3(nor, v1, v2, v3);
+ }
+ }
+
+ /* calculate tangent vectors */
+ if (utan && vtan) {
+ if (tface) {
+ uv1 = tface->uv[0];
+ uv2 = tface->uv[1];
+ uv3 = tface->uv[2];
+ uv4 = tface->uv[3];
+ }
+ else {
+ uv1 = tuv[0];
+ uv2 = tuv[1];
+ uv3 = tuv[2];
+ uv4 = tuv[3];
+ map_to_sphere(uv1, uv1 + 1, v1[0], v1[1], v1[2]);
+ map_to_sphere(uv2, uv2 + 1, v2[0], v2[1], v2[2]);
+ map_to_sphere(uv3, uv3 + 1, v3[0], v3[1], v3[2]);
+ if (v4)
+ map_to_sphere(uv4, uv4 + 1, v4[0], v4[1], v4[2]);
+ }
+
+ if (v4) {
+ s1 = uv3[0] - uv1[0];
+ s2 = uv4[0] - uv1[0];
+
+ t1 = uv3[1] - uv1[1];
+ t2 = uv4[1] - uv1[1];
+
+ sub_v3_v3v3(e1, v3, v1);
+ sub_v3_v3v3(e2, v4, v1);
+ }
+ else {
+ s1 = uv2[0] - uv1[0];
+ s2 = uv3[0] - uv1[0];
+
+ t1 = uv2[1] - uv1[1];
+ t2 = uv3[1] - uv1[1];
+
+ sub_v3_v3v3(e1, v2, v1);
+ sub_v3_v3v3(e2, v3, v1);
+ }
+
+ vtan[0] = (s1 * e2[0] - s2 * e1[0]);
+ vtan[1] = (s1 * e2[1] - s2 * e1[1]);
+ vtan[2] = (s1 * e2[2] - s2 * e1[2]);
+
+ utan[0] = (t1 * e2[0] - t2 * e1[0]);
+ utan[1] = (t1 * e2[1] - t2 * e1[1]);
+ utan[2] = (t1 * e2[2] - t2 * e1[2]);
+ }
+
+ if (orco) {
+ if (orcodata) {
+ o1 = orcodata[mface->v1];
+ o2 = orcodata[mface->v2];
+ o3 = orcodata[mface->v3];
+
+ if (mface->v4) {
+ o4 = orcodata[mface->v4];
+
+ interp_v3_v3v3v3v3(orco, o1, o2, o3, o4, w);
+ }
+ else {
+ interp_v3_v3v3v3(orco, o1, o2, o3, w);
+ }
+ }
+ else {
+ copy_v3_v3(orco, vec);
+ }
+ }
}
void psys_interpolate_uvs(const MTFace *tface, int quad, const float w[4], float uvco[2])
{
- float v10 = tface->uv[0][0];
- float v11 = tface->uv[0][1];
- float v20 = tface->uv[1][0];
- float v21 = tface->uv[1][1];
- float v30 = tface->uv[2][0];
- float v31 = tface->uv[2][1];
- float v40, v41;
-
- if (quad) {
- v40 = tface->uv[3][0];
- v41 = tface->uv[3][1];
-
- uvco[0] = w[0] * v10 + w[1] * v20 + w[2] * v30 + w[3] * v40;
- uvco[1] = w[0] * v11 + w[1] * v21 + w[2] * v31 + w[3] * v41;
- }
- else {
- uvco[0] = w[0] * v10 + w[1] * v20 + w[2] * v30;
- uvco[1] = w[0] * v11 + w[1] * v21 + w[2] * v31;
- }
+ float v10 = tface->uv[0][0];
+ float v11 = tface->uv[0][1];
+ float v20 = tface->uv[1][0];
+ float v21 = tface->uv[1][1];
+ float v30 = tface->uv[2][0];
+ float v31 = tface->uv[2][1];
+ float v40, v41;
+
+ if (quad) {
+ v40 = tface->uv[3][0];
+ v41 = tface->uv[3][1];
+
+ uvco[0] = w[0] * v10 + w[1] * v20 + w[2] * v30 + w[3] * v40;
+ uvco[1] = w[0] * v11 + w[1] * v21 + w[2] * v31 + w[3] * v41;
+ }
+ else {
+ uvco[0] = w[0] * v10 + w[1] * v20 + w[2] * v30;
+ uvco[1] = w[0] * v11 + w[1] * v21 + w[2] * v31;
+ }
}
void psys_interpolate_mcol(const MCol *mcol, int quad, const float w[4], MCol *mc)
{
- const char *cp1, *cp2, *cp3, *cp4;
- char *cp;
-
- cp = (char *)mc;
- cp1 = (const char *)&mcol[0];
- cp2 = (const char *)&mcol[1];
- cp3 = (const char *)&mcol[2];
-
- if (quad) {
- cp4 = (char *)&mcol[3];
-
- cp[0] = (int)(w[0] * cp1[0] + w[1] * cp2[0] + w[2] * cp3[0] + w[3] * cp4[0]);
- cp[1] = (int)(w[0] * cp1[1] + w[1] * cp2[1] + w[2] * cp3[1] + w[3] * cp4[1]);
- cp[2] = (int)(w[0] * cp1[2] + w[1] * cp2[2] + w[2] * cp3[2] + w[3] * cp4[2]);
- cp[3] = (int)(w[0] * cp1[3] + w[1] * cp2[3] + w[2] * cp3[3] + w[3] * cp4[3]);
- }
- else {
- cp[0] = (int)(w[0] * cp1[0] + w[1] * cp2[0] + w[2] * cp3[0]);
- cp[1] = (int)(w[0] * cp1[1] + w[1] * cp2[1] + w[2] * cp3[1]);
- cp[2] = (int)(w[0] * cp1[2] + w[1] * cp2[2] + w[2] * cp3[2]);
- cp[3] = (int)(w[0] * cp1[3] + w[1] * cp2[3] + w[2] * cp3[3]);
- }
+ const char *cp1, *cp2, *cp3, *cp4;
+ char *cp;
+
+ cp = (char *)mc;
+ cp1 = (const char *)&mcol[0];
+ cp2 = (const char *)&mcol[1];
+ cp3 = (const char *)&mcol[2];
+
+ if (quad) {
+ cp4 = (char *)&mcol[3];
+
+ cp[0] = (int)(w[0] * cp1[0] + w[1] * cp2[0] + w[2] * cp3[0] + w[3] * cp4[0]);
+ cp[1] = (int)(w[0] * cp1[1] + w[1] * cp2[1] + w[2] * cp3[1] + w[3] * cp4[1]);
+ cp[2] = (int)(w[0] * cp1[2] + w[1] * cp2[2] + w[2] * cp3[2] + w[3] * cp4[2]);
+ cp[3] = (int)(w[0] * cp1[3] + w[1] * cp2[3] + w[2] * cp3[3] + w[3] * cp4[3]);
+ }
+ else {
+ cp[0] = (int)(w[0] * cp1[0] + w[1] * cp2[0] + w[2] * cp3[0]);
+ cp[1] = (int)(w[0] * cp1[1] + w[1] * cp2[1] + w[2] * cp3[1]);
+ cp[2] = (int)(w[0] * cp1[2] + w[1] * cp2[2] + w[2] * cp3[2]);
+ cp[3] = (int)(w[0] * cp1[3] + w[1] * cp2[3] + w[2] * cp3[3]);
+ }
}
-static float psys_interpolate_value_from_verts(Mesh *mesh, short from, int index, const float fw[4], const float *values)
+static float psys_interpolate_value_from_verts(
+ Mesh *mesh, short from, int index, const float fw[4], const float *values)
{
- if (values == 0 || index == -1)
- return 0.0;
-
- switch (from) {
- case PART_FROM_VERT:
- return values[index];
- case PART_FROM_FACE:
- case PART_FROM_VOLUME:
- {
- MFace *mf = &mesh->mface[index];
- return interpolate_particle_value(values[mf->v1], values[mf->v2], values[mf->v3], values[mf->v4], fw, mf->v4);
- }
-
- }
- return 0.0f;
+ if (values == 0 || index == -1)
+ return 0.0;
+
+ switch (from) {
+ case PART_FROM_VERT:
+ return values[index];
+ case PART_FROM_FACE:
+ case PART_FROM_VOLUME: {
+ MFace *mf = &mesh->mface[index];
+ return interpolate_particle_value(
+ values[mf->v1], values[mf->v2], values[mf->v3], values[mf->v4], fw, mf->v4);
+ }
+ }
+ return 0.0f;
}
/* conversion of pa->fw to origspace layer coordinates */
static void psys_w_to_origspace(const float w[4], float uv[2])
{
- uv[0] = w[1] + w[2];
- uv[1] = w[2] + w[3];
+ uv[0] = w[1] + w[2];
+ uv[1] = w[2] + w[3];
}
/* conversion of pa->fw to weights in face from origspace */
static void psys_origspace_to_w(OrigSpaceFace *osface, int quad, const float w[4], float neww[4])
{
- float v[4][3], co[3];
-
- v[0][0] = osface->uv[0][0]; v[0][1] = osface->uv[0][1]; v[0][2] = 0.0f;
- v[1][0] = osface->uv[1][0]; v[1][1] = osface->uv[1][1]; v[1][2] = 0.0f;
- v[2][0] = osface->uv[2][0]; v[2][1] = osface->uv[2][1]; v[2][2] = 0.0f;
-
- psys_w_to_origspace(w, co);
- co[2] = 0.0f;
-
- if (quad) {
- v[3][0] = osface->uv[3][0]; v[3][1] = osface->uv[3][1]; v[3][2] = 0.0f;
- interp_weights_poly_v3(neww, v, 4, co);
- }
- else {
- interp_weights_poly_v3(neww, v, 3, co);
- neww[3] = 0.0f;
- }
+ float v[4][3], co[3];
+
+ v[0][0] = osface->uv[0][0];
+ v[0][1] = osface->uv[0][1];
+ v[0][2] = 0.0f;
+ v[1][0] = osface->uv[1][0];
+ v[1][1] = osface->uv[1][1];
+ v[1][2] = 0.0f;
+ v[2][0] = osface->uv[2][0];
+ v[2][1] = osface->uv[2][1];
+ v[2][2] = 0.0f;
+
+ psys_w_to_origspace(w, co);
+ co[2] = 0.0f;
+
+ if (quad) {
+ v[3][0] = osface->uv[3][0];
+ v[3][1] = osface->uv[3][1];
+ v[3][2] = 0.0f;
+ interp_weights_poly_v3(neww, v, 4, co);
+ }
+ else {
+ interp_weights_poly_v3(neww, v, 3, co);
+ neww[3] = 0.0f;
+ }
}
/**
@@ -1336,1119 +1407,1302 @@ static void psys_origspace_to_w(OrigSpaceFace *osface, int quad, const float w[4
* one for each final \a mesh_final polygon, containing all its tessfaces indices.
* \return The \a mesh_final tessface index.
*/
-int psys_particle_dm_face_lookup(
- Mesh *mesh_final, Mesh *mesh_original,
- int findex_orig, const float fw[4], struct LinkNode **poly_nodes)
+int psys_particle_dm_face_lookup(Mesh *mesh_final,
+ Mesh *mesh_original,
+ int findex_orig,
+ const float fw[4],
+ struct LinkNode **poly_nodes)
{
- MFace *mtessface_final;
- OrigSpaceFace *osface_final;
- int pindex_orig;
- float uv[2], (*faceuv)[2];
-
- const int *index_mf_to_mpoly_deformed = NULL;
- const int *index_mf_to_mpoly = NULL;
- const int *index_mp_to_orig = NULL;
-
- const int totface_final = mesh_final->totface;
- const int totface_deformed = mesh_original ? mesh_original->totface : totface_final;
-
- if (ELEM(0, totface_final, totface_deformed)) {
- return DMCACHE_NOTFOUND;
- }
-
- index_mf_to_mpoly = CustomData_get_layer(&mesh_final->fdata, CD_ORIGINDEX);
- index_mp_to_orig = CustomData_get_layer(&mesh_final->pdata, CD_ORIGINDEX);
- BLI_assert(index_mf_to_mpoly);
-
- if (mesh_original) {
- index_mf_to_mpoly_deformed = CustomData_get_layer(&mesh_original->fdata, CD_ORIGINDEX);
- }
- else {
- BLI_assert(mesh_final->runtime.deformed_only);
- index_mf_to_mpoly_deformed = index_mf_to_mpoly;
- }
- BLI_assert(index_mf_to_mpoly_deformed);
-
- pindex_orig = index_mf_to_mpoly_deformed[findex_orig];
-
- if (mesh_original == NULL) {
- mesh_original = mesh_final;
- }
-
- index_mf_to_mpoly_deformed = NULL;
-
- mtessface_final = mesh_final->mface;
- osface_final = CustomData_get_layer(&mesh_final->fdata, CD_ORIGSPACE);
-
- if (osface_final == NULL) {
- /* Assume we don't need osface_final data, and we get a direct 1-1 mapping... */
- if (findex_orig < totface_final) {
- //printf("\tNO CD_ORIGSPACE, assuming not needed\n");
- return findex_orig;
- }
- else {
- printf("\tNO CD_ORIGSPACE, error out of range\n");
- return DMCACHE_NOTFOUND;
- }
- }
- else if (findex_orig >= mesh_original->totface) {
- return DMCACHE_NOTFOUND; /* index not in the original mesh */
- }
-
- psys_w_to_origspace(fw, uv);
-
- if (poly_nodes) {
- /* we can have a restricted linked list of faces to check, faster! */
- LinkNode *tessface_node = poly_nodes[pindex_orig];
-
- for (; tessface_node; tessface_node = tessface_node->next) {
- int findex_dst = POINTER_AS_INT(tessface_node->link);
- faceuv = osface_final[findex_dst].uv;
-
- /* check that this intersects - Its possible this misses :/ -
- * could also check its not between */
- if (mtessface_final[findex_dst].v4) {
- if (isect_point_quad_v2(uv, faceuv[0], faceuv[1], faceuv[2], faceuv[3])) {
- return findex_dst;
- }
- }
- else if (isect_point_tri_v2(uv, faceuv[0], faceuv[1], faceuv[2])) {
- return findex_dst;
- }
- }
- }
- else { /* if we have no node, try every face */
- for (int findex_dst = 0; findex_dst < totface_final; findex_dst++) {
- /* If current tessface from 'final' DM and orig tessface (given by index) map to the same orig poly... */
- if (BKE_mesh_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, findex_dst) == pindex_orig) {
- faceuv = osface_final[findex_dst].uv;
-
- /* check that this intersects - Its possible this misses :/ -
- * could also check its not between */
- if (mtessface_final[findex_dst].v4) {
- if (isect_point_quad_v2(uv, faceuv[0], faceuv[1], faceuv[2], faceuv[3])) {
- return findex_dst;
- }
- }
- else if (isect_point_tri_v2(uv, faceuv[0], faceuv[1], faceuv[2])) {
- return findex_dst;
- }
- }
- }
- }
-
- return DMCACHE_NOTFOUND;
+ MFace *mtessface_final;
+ OrigSpaceFace *osface_final;
+ int pindex_orig;
+ float uv[2], (*faceuv)[2];
+
+ const int *index_mf_to_mpoly_deformed = NULL;
+ const int *index_mf_to_mpoly = NULL;
+ const int *index_mp_to_orig = NULL;
+
+ const int totface_final = mesh_final->totface;
+ const int totface_deformed = mesh_original ? mesh_original->totface : totface_final;
+
+ if (ELEM(0, totface_final, totface_deformed)) {
+ return DMCACHE_NOTFOUND;
+ }
+
+ index_mf_to_mpoly = CustomData_get_layer(&mesh_final->fdata, CD_ORIGINDEX);
+ index_mp_to_orig = CustomData_get_layer(&mesh_final->pdata, CD_ORIGINDEX);
+ BLI_assert(index_mf_to_mpoly);
+
+ if (mesh_original) {
+ index_mf_to_mpoly_deformed = CustomData_get_layer(&mesh_original->fdata, CD_ORIGINDEX);
+ }
+ else {
+ BLI_assert(mesh_final->runtime.deformed_only);
+ index_mf_to_mpoly_deformed = index_mf_to_mpoly;
+ }
+ BLI_assert(index_mf_to_mpoly_deformed);
+
+ pindex_orig = index_mf_to_mpoly_deformed[findex_orig];
+
+ if (mesh_original == NULL) {
+ mesh_original = mesh_final;
+ }
+
+ index_mf_to_mpoly_deformed = NULL;
+
+ mtessface_final = mesh_final->mface;
+ osface_final = CustomData_get_layer(&mesh_final->fdata, CD_ORIGSPACE);
+
+ if (osface_final == NULL) {
+ /* Assume we don't need osface_final data, and we get a direct 1-1 mapping... */
+ if (findex_orig < totface_final) {
+ //printf("\tNO CD_ORIGSPACE, assuming not needed\n");
+ return findex_orig;
+ }
+ else {
+ printf("\tNO CD_ORIGSPACE, error out of range\n");
+ return DMCACHE_NOTFOUND;
+ }
+ }
+ else if (findex_orig >= mesh_original->totface) {
+ return DMCACHE_NOTFOUND; /* index not in the original mesh */
+ }
+
+ psys_w_to_origspace(fw, uv);
+
+ if (poly_nodes) {
+ /* we can have a restricted linked list of faces to check, faster! */
+ LinkNode *tessface_node = poly_nodes[pindex_orig];
+
+ for (; tessface_node; tessface_node = tessface_node->next) {
+ int findex_dst = POINTER_AS_INT(tessface_node->link);
+ faceuv = osface_final[findex_dst].uv;
+
+ /* check that this intersects - Its possible this misses :/ -
+ * could also check its not between */
+ if (mtessface_final[findex_dst].v4) {
+ if (isect_point_quad_v2(uv, faceuv[0], faceuv[1], faceuv[2], faceuv[3])) {
+ return findex_dst;
+ }
+ }
+ else if (isect_point_tri_v2(uv, faceuv[0], faceuv[1], faceuv[2])) {
+ return findex_dst;
+ }
+ }
+ }
+ else { /* if we have no node, try every face */
+ for (int findex_dst = 0; findex_dst < totface_final; findex_dst++) {
+ /* If current tessface from 'final' DM and orig tessface (given by index) map to the same orig poly... */
+ if (BKE_mesh_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, findex_dst) ==
+ pindex_orig) {
+ faceuv = osface_final[findex_dst].uv;
+
+ /* check that this intersects - Its possible this misses :/ -
+ * could also check its not between */
+ if (mtessface_final[findex_dst].v4) {
+ if (isect_point_quad_v2(uv, faceuv[0], faceuv[1], faceuv[2], faceuv[3])) {
+ return findex_dst;
+ }
+ }
+ else if (isect_point_tri_v2(uv, faceuv[0], faceuv[1], faceuv[2])) {
+ return findex_dst;
+ }
+ }
+ }
+ }
+
+ return DMCACHE_NOTFOUND;
}
-static int psys_map_index_on_dm(Mesh *mesh, int from, int index, int index_dmcache, const float fw[4], float UNUSED(foffset), int *mapindex, float mapfw[4])
+static int psys_map_index_on_dm(Mesh *mesh,
+ int from,
+ int index,
+ int index_dmcache,
+ const float fw[4],
+ float UNUSED(foffset),
+ int *mapindex,
+ float mapfw[4])
{
- if (index < 0)
- return 0;
-
- if (mesh->runtime.deformed_only || index_dmcache == DMCACHE_ISCHILD) {
- /* for meshes that are either only deformed or for child particles, the
- * index and fw do not require any mapping, so we can directly use it */
- if (from == PART_FROM_VERT) {
- if (index >= mesh->totvert)
- return 0;
-
- *mapindex = index;
- }
- else { /* FROM_FACE/FROM_VOLUME */
- if (index >= mesh->totface)
- return 0;
-
- *mapindex = index;
- copy_v4_v4(mapfw, fw);
- }
- }
- else {
- /* for other meshes that have been modified, we try to map the particle
- * to their new location, which means a different index, and for faces
- * also a new face interpolation weights */
- if (from == PART_FROM_VERT) {
- if (index_dmcache == DMCACHE_NOTFOUND || index_dmcache > mesh->totvert)
- return 0;
-
- *mapindex = index_dmcache;
- }
- else { /* FROM_FACE/FROM_VOLUME */
- /* find a face on the derived mesh that uses this face */
- MFace *mface;
- OrigSpaceFace *osface;
- int i;
-
- i = index_dmcache;
-
- if (i == DMCACHE_NOTFOUND || i >= mesh->totface)
- return 0;
-
- *mapindex = i;
-
- /* modify the original weights to become
- * weights for the derived mesh face */
- osface = CustomData_get_layer(&mesh->fdata, CD_ORIGSPACE);
- mface = &mesh->mface[i];
-
- if (osface == NULL)
- mapfw[0] = mapfw[1] = mapfw[2] = mapfw[3] = 0.0f;
- else
- psys_origspace_to_w(&osface[i], mface->v4, fw, mapfw);
- }
- }
-
- return 1;
+ if (index < 0)
+ return 0;
+
+ if (mesh->runtime.deformed_only || index_dmcache == DMCACHE_ISCHILD) {
+ /* for meshes that are either only deformed or for child particles, the
+ * index and fw do not require any mapping, so we can directly use it */
+ if (from == PART_FROM_VERT) {
+ if (index >= mesh->totvert)
+ return 0;
+
+ *mapindex = index;
+ }
+ else { /* FROM_FACE/FROM_VOLUME */
+ if (index >= mesh->totface)
+ return 0;
+
+ *mapindex = index;
+ copy_v4_v4(mapfw, fw);
+ }
+ }
+ else {
+ /* for other meshes that have been modified, we try to map the particle
+ * to their new location, which means a different index, and for faces
+ * also a new face interpolation weights */
+ if (from == PART_FROM_VERT) {
+ if (index_dmcache == DMCACHE_NOTFOUND || index_dmcache > mesh->totvert)
+ return 0;
+
+ *mapindex = index_dmcache;
+ }
+ else { /* FROM_FACE/FROM_VOLUME */
+ /* find a face on the derived mesh that uses this face */
+ MFace *mface;
+ OrigSpaceFace *osface;
+ int i;
+
+ i = index_dmcache;
+
+ if (i == DMCACHE_NOTFOUND || i >= mesh->totface)
+ return 0;
+
+ *mapindex = i;
+
+ /* modify the original weights to become
+ * weights for the derived mesh face */
+ osface = CustomData_get_layer(&mesh->fdata, CD_ORIGSPACE);
+ mface = &mesh->mface[i];
+
+ if (osface == NULL)
+ mapfw[0] = mapfw[1] = mapfw[2] = mapfw[3] = 0.0f;
+ else
+ psys_origspace_to_w(&osface[i], mface->v4, fw, mapfw);
+ }
+ }
+
+ return 1;
}
/* interprets particle data to get a point on a mesh in object space */
-void psys_particle_on_dm(Mesh *mesh_final, int from, int index, int index_dmcache,
- const float fw[4], float foffset, float vec[3], float nor[3], float utan[3], float vtan[3],
+void psys_particle_on_dm(Mesh *mesh_final,
+ int from,
+ int index,
+ int index_dmcache,
+ const float fw[4],
+ float foffset,
+ float vec[3],
+ float nor[3],
+ float utan[3],
+ float vtan[3],
float orco[3])
{
- float tmpnor[3], mapfw[4];
- float (*orcodata)[3];
- int mapindex;
-
- if (!psys_map_index_on_dm(mesh_final, from, index, index_dmcache, fw, foffset, &mapindex, mapfw)) {
- if (vec) { vec[0] = vec[1] = vec[2] = 0.0; }
- if (nor) { nor[0] = nor[1] = 0.0; nor[2] = 1.0; }
- if (orco) { orco[0] = orco[1] = orco[2] = 0.0; }
- if (utan) { utan[0] = utan[1] = utan[2] = 0.0; }
- if (vtan) { vtan[0] = vtan[1] = vtan[2] = 0.0; }
-
- return;
- }
-
- orcodata = CustomData_get_layer(&mesh_final->vdata, CD_ORCO);
-
- if (from == PART_FROM_VERT) {
- copy_v3_v3(vec, mesh_final->mvert[mapindex].co);
-
- if (nor) {
- normal_short_to_float_v3(nor, mesh_final->mvert[mapindex].no);
- normalize_v3(nor);
- }
-
- if (orco) {
- if (orcodata) {
- copy_v3_v3(orco, orcodata[mapindex]);
- }
- else {
- copy_v3_v3(orco, vec);
- }
- }
-
- if (utan && vtan) {
- utan[0] = utan[1] = utan[2] = 0.0f;
- vtan[0] = vtan[1] = vtan[2] = 0.0f;
- }
- }
- else { /* PART_FROM_FACE / PART_FROM_VOLUME */
- MFace *mface;
- MTFace *mtface;
- MVert *mvert;
-
- mface = &mesh_final->mface[mapindex];
- mvert = mesh_final->mvert;
- mtface = mesh_final->mtface;
-
- if (mtface)
- mtface += mapindex;
-
- if (from == PART_FROM_VOLUME) {
- psys_interpolate_face(mvert, mface, mtface, orcodata, mapfw, vec, tmpnor, utan, vtan, orco);
- if (nor)
- copy_v3_v3(nor, tmpnor);
-
- normalize_v3(tmpnor); /* XXX Why not normalize tmpnor before copying it into nor??? -- mont29 */
- mul_v3_fl(tmpnor, -foffset);
- add_v3_v3(vec, tmpnor);
- }
- else
- psys_interpolate_face(mvert, mface, mtface, orcodata, mapfw, vec, nor, utan, vtan, orco);
- }
+ float tmpnor[3], mapfw[4];
+ float(*orcodata)[3];
+ int mapindex;
+
+ if (!psys_map_index_on_dm(
+ mesh_final, from, index, index_dmcache, fw, foffset, &mapindex, mapfw)) {
+ if (vec) {
+ vec[0] = vec[1] = vec[2] = 0.0;
+ }
+ if (nor) {
+ nor[0] = nor[1] = 0.0;
+ nor[2] = 1.0;
+ }
+ if (orco) {
+ orco[0] = orco[1] = orco[2] = 0.0;
+ }
+ if (utan) {
+ utan[0] = utan[1] = utan[2] = 0.0;
+ }
+ if (vtan) {
+ vtan[0] = vtan[1] = vtan[2] = 0.0;
+ }
+
+ return;
+ }
+
+ orcodata = CustomData_get_layer(&mesh_final->vdata, CD_ORCO);
+
+ if (from == PART_FROM_VERT) {
+ copy_v3_v3(vec, mesh_final->mvert[mapindex].co);
+
+ if (nor) {
+ normal_short_to_float_v3(nor, mesh_final->mvert[mapindex].no);
+ normalize_v3(nor);
+ }
+
+ if (orco) {
+ if (orcodata) {
+ copy_v3_v3(orco, orcodata[mapindex]);
+ }
+ else {
+ copy_v3_v3(orco, vec);
+ }
+ }
+
+ if (utan && vtan) {
+ utan[0] = utan[1] = utan[2] = 0.0f;
+ vtan[0] = vtan[1] = vtan[2] = 0.0f;
+ }
+ }
+ else { /* PART_FROM_FACE / PART_FROM_VOLUME */
+ MFace *mface;
+ MTFace *mtface;
+ MVert *mvert;
+
+ mface = &mesh_final->mface[mapindex];
+ mvert = mesh_final->mvert;
+ mtface = mesh_final->mtface;
+
+ if (mtface)
+ mtface += mapindex;
+
+ if (from == PART_FROM_VOLUME) {
+ psys_interpolate_face(mvert, mface, mtface, orcodata, mapfw, vec, tmpnor, utan, vtan, orco);
+ if (nor)
+ copy_v3_v3(nor, tmpnor);
+
+ normalize_v3(
+ tmpnor); /* XXX Why not normalize tmpnor before copying it into nor??? -- mont29 */
+ mul_v3_fl(tmpnor, -foffset);
+ add_v3_v3(vec, tmpnor);
+ }
+ else
+ psys_interpolate_face(mvert, mface, mtface, orcodata, mapfw, vec, nor, utan, vtan, orco);
+ }
}
float psys_particle_value_from_verts(Mesh *mesh, short from, ParticleData *pa, float *values)
{
- float mapfw[4];
- int mapindex;
+ float mapfw[4];
+ int mapindex;
- if (!psys_map_index_on_dm(mesh, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, &mapindex, mapfw))
- return 0.0f;
+ if (!psys_map_index_on_dm(
+ mesh, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, &mapindex, mapfw))
+ return 0.0f;
- return psys_interpolate_value_from_verts(mesh, from, mapindex, mapfw, values);
+ return psys_interpolate_value_from_verts(mesh, from, mapindex, mapfw, values);
}
ParticleSystemModifierData *psys_get_modifier(Object *ob, ParticleSystem *psys)
{
- ModifierData *md;
- ParticleSystemModifierData *psmd;
-
- for (md = ob->modifiers.first; md; md = md->next) {
- if (md->type == eModifierType_ParticleSystem) {
- psmd = (ParticleSystemModifierData *) md;
- if (psmd->psys == psys) {
- return psmd;
- }
- }
- }
- return NULL;
+ ModifierData *md;
+ ParticleSystemModifierData *psmd;
+
+ for (md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_ParticleSystem) {
+ psmd = (ParticleSystemModifierData *)md;
+ if (psmd->psys == psys) {
+ return psmd;
+ }
+ }
+ }
+ return NULL;
}
/************************************************/
-/* Particles on a shape */
+/* Particles on a shape */
/************************************************/
/* ready for future use */
-static void psys_particle_on_shape(int UNUSED(distr), int UNUSED(index),
- float *UNUSED(fuv), float vec[3], float nor[3], float utan[3], float vtan[3],
+static void psys_particle_on_shape(int UNUSED(distr),
+ int UNUSED(index),
+ float *UNUSED(fuv),
+ float vec[3],
+ float nor[3],
+ float utan[3],
+ float vtan[3],
float orco[3])
{
- /* TODO */
- float zerovec[3] = {0.0f, 0.0f, 0.0f};
- if (vec) {
- copy_v3_v3(vec, zerovec);
- }
- if (nor) {
- copy_v3_v3(nor, zerovec);
- }
- if (utan) {
- copy_v3_v3(utan, zerovec);
- }
- if (vtan) {
- copy_v3_v3(vtan, zerovec);
- }
- if (orco) {
- copy_v3_v3(orco, zerovec);
- }
+ /* TODO */
+ float zerovec[3] = {0.0f, 0.0f, 0.0f};
+ if (vec) {
+ copy_v3_v3(vec, zerovec);
+ }
+ if (nor) {
+ copy_v3_v3(nor, zerovec);
+ }
+ if (utan) {
+ copy_v3_v3(utan, zerovec);
+ }
+ if (vtan) {
+ copy_v3_v3(vtan, zerovec);
+ }
+ if (orco) {
+ copy_v3_v3(orco, zerovec);
+ }
}
/************************************************/
-/* Particles on emitter */
+/* Particles on emitter */
/************************************************/
void psys_emitter_customdata_mask(ParticleSystem *psys, CustomData_MeshMasks *r_cddata_masks)
{
- MTex *mtex;
- int i;
-
- if (!psys->part)
- return;
-
- for (i = 0; i < MAX_MTEX; i++) {
- mtex = psys->part->mtex[i];
- if (mtex && mtex->mapto && (mtex->texco & TEXCO_UV))
- r_cddata_masks->fmask |= CD_MASK_MTFACE;
- }
-
- if (psys->part->tanfac != 0.0f)
- r_cddata_masks->fmask |= CD_MASK_MTFACE;
-
- /* ask for vertexgroups if we need them */
- for (i = 0; i < PSYS_TOT_VG; i++) {
- if (psys->vgroup[i]) {
- r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
- break;
- }
- }
-
- /* particles only need this if they are after a non deform modifier, and
- * the modifier stack will only create them in that case. */
- r_cddata_masks->lmask |= CD_MASK_ORIGSPACE_MLOOP;
- /* XXX Check we do need all those? */
- r_cddata_masks->vmask |= CD_MASK_ORIGINDEX;
- r_cddata_masks->emask |= CD_MASK_ORIGINDEX;
- r_cddata_masks->pmask |= CD_MASK_ORIGINDEX;
-
- r_cddata_masks->vmask |= CD_MASK_ORCO;
+ MTex *mtex;
+ int i;
+
+ if (!psys->part)
+ return;
+
+ for (i = 0; i < MAX_MTEX; i++) {
+ mtex = psys->part->mtex[i];
+ if (mtex && mtex->mapto && (mtex->texco & TEXCO_UV))
+ r_cddata_masks->fmask |= CD_MASK_MTFACE;
+ }
+
+ if (psys->part->tanfac != 0.0f)
+ r_cddata_masks->fmask |= CD_MASK_MTFACE;
+
+ /* ask for vertexgroups if we need them */
+ for (i = 0; i < PSYS_TOT_VG; i++) {
+ if (psys->vgroup[i]) {
+ r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
+ break;
+ }
+ }
+
+ /* particles only need this if they are after a non deform modifier, and
+ * the modifier stack will only create them in that case. */
+ r_cddata_masks->lmask |= CD_MASK_ORIGSPACE_MLOOP;
+ /* XXX Check we do need all those? */
+ r_cddata_masks->vmask |= CD_MASK_ORIGINDEX;
+ r_cddata_masks->emask |= CD_MASK_ORIGINDEX;
+ r_cddata_masks->pmask |= CD_MASK_ORIGINDEX;
+
+ r_cddata_masks->vmask |= CD_MASK_ORCO;
}
-void psys_particle_on_emitter(ParticleSystemModifierData *psmd, int from, int index, int index_dmcache,
- float fuv[4], float foffset, float vec[3], float nor[3], float utan[3], float vtan[3],
+void psys_particle_on_emitter(ParticleSystemModifierData *psmd,
+ int from,
+ int index,
+ int index_dmcache,
+ float fuv[4],
+ float foffset,
+ float vec[3],
+ float nor[3],
+ float utan[3],
+ float vtan[3],
float orco[3])
{
- if (psmd && psmd->mesh_final) {
- if (psmd->psys->part->distr == PART_DISTR_GRID && psmd->psys->part->from != PART_FROM_VERT) {
- if (vec)
- copy_v3_v3(vec, fuv);
-
- if (orco)
- copy_v3_v3(orco, fuv);
- return;
- }
- /* we cant use the num_dmcache */
- psys_particle_on_dm(psmd->mesh_final, from, index, index_dmcache, fuv, foffset, vec, nor, utan, vtan, orco);
- }
- else
- psys_particle_on_shape(from, index, fuv, vec, nor, utan, vtan, orco);
-
+ if (psmd && psmd->mesh_final) {
+ if (psmd->psys->part->distr == PART_DISTR_GRID && psmd->psys->part->from != PART_FROM_VERT) {
+ if (vec)
+ copy_v3_v3(vec, fuv);
+
+ if (orco)
+ copy_v3_v3(orco, fuv);
+ return;
+ }
+ /* we cant use the num_dmcache */
+ psys_particle_on_dm(
+ psmd->mesh_final, from, index, index_dmcache, fuv, foffset, vec, nor, utan, vtan, orco);
+ }
+ else
+ psys_particle_on_shape(from, index, fuv, vec, nor, utan, vtan, orco);
}
/************************************************/
-/* Path Cache */
+/* Path Cache */
/************************************************/
void precalc_guides(ParticleSimulationData *sim, ListBase *effectors)
{
- EffectedPoint point;
- ParticleKey state;
- EffectorData efd;
- EffectorCache *eff;
- ParticleSystem *psys = sim->psys;
- EffectorWeights *weights = sim->psys->part->effector_weights;
- GuideEffectorData *data;
- PARTICLE_P;
-
- if (!effectors)
- return;
-
- LOOP_PARTICLES {
- psys_particle_on_emitter(sim->psmd, sim->psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, state.co, 0, 0, 0, 0);
-
- mul_m4_v3(sim->ob->obmat, state.co);
- mul_mat3_m4_v3(sim->ob->obmat, state.vel);
-
- pd_point_from_particle(sim, pa, &state, &point);
-
- for (eff = effectors->first; eff; eff = eff->next) {
- if (eff->pd->forcefield != PFIELD_GUIDE)
- continue;
-
- if (!eff->guide_data)
- eff->guide_data = MEM_callocN(sizeof(GuideEffectorData) * psys->totpart, "GuideEffectorData");
-
- data = eff->guide_data + p;
-
- sub_v3_v3v3(efd.vec_to_point, state.co, eff->guide_loc);
- copy_v3_v3(efd.nor, eff->guide_dir);
- efd.distance = len_v3(efd.vec_to_point);
-
- copy_v3_v3(data->vec_to_point, efd.vec_to_point);
- data->strength = effector_falloff(eff, &efd, &point, weights);
- }
- }
+ EffectedPoint point;
+ ParticleKey state;
+ EffectorData efd;
+ EffectorCache *eff;
+ ParticleSystem *psys = sim->psys;
+ EffectorWeights *weights = sim->psys->part->effector_weights;
+ GuideEffectorData *data;
+ PARTICLE_P;
+
+ if (!effectors)
+ return;
+
+ LOOP_PARTICLES
+ {
+ psys_particle_on_emitter(sim->psmd,
+ sim->psys->part->from,
+ pa->num,
+ pa->num_dmcache,
+ pa->fuv,
+ pa->foffset,
+ state.co,
+ 0,
+ 0,
+ 0,
+ 0);
+
+ mul_m4_v3(sim->ob->obmat, state.co);
+ mul_mat3_m4_v3(sim->ob->obmat, state.vel);
+
+ pd_point_from_particle(sim, pa, &state, &point);
+
+ for (eff = effectors->first; eff; eff = eff->next) {
+ if (eff->pd->forcefield != PFIELD_GUIDE)
+ continue;
+
+ if (!eff->guide_data)
+ eff->guide_data = MEM_callocN(sizeof(GuideEffectorData) * psys->totpart,
+ "GuideEffectorData");
+
+ data = eff->guide_data + p;
+
+ sub_v3_v3v3(efd.vec_to_point, state.co, eff->guide_loc);
+ copy_v3_v3(efd.nor, eff->guide_dir);
+ efd.distance = len_v3(efd.vec_to_point);
+
+ copy_v3_v3(data->vec_to_point, efd.vec_to_point);
+ data->strength = effector_falloff(eff, &efd, &point, weights);
+ }
+ }
}
-int do_guides(Depsgraph *depsgraph, ParticleSettings *part, ListBase *effectors, ParticleKey *state, int index, float time)
+int do_guides(Depsgraph *depsgraph,
+ ParticleSettings *part,
+ ListBase *effectors,
+ ParticleKey *state,
+ int index,
+ float time)
{
- CurveMapping *clumpcurve = (part->child_flag & PART_CHILD_USE_CLUMP_CURVE) ? part->clumpcurve : NULL;
- CurveMapping *roughcurve = (part->child_flag & PART_CHILD_USE_ROUGH_CURVE) ? part->roughcurve : NULL;
- EffectorCache *eff;
- PartDeflect *pd;
- Curve *cu;
- GuideEffectorData *data;
-
- float effect[3] = {0.0f, 0.0f, 0.0f}, veffect[3] = {0.0f, 0.0f, 0.0f};
- float guidevec[4], guidedir[3], rot2[4], temp[3];
- float guidetime, radius, weight, angle, totstrength = 0.0f;
- float vec_to_point[3];
-
- if (effectors) for (eff = effectors->first; eff; eff = eff->next) {
- pd = eff->pd;
-
- if (pd->forcefield != PFIELD_GUIDE)
- continue;
-
- data = eff->guide_data + index;
-
- if (data->strength <= 0.0f)
- continue;
-
- guidetime = time / (1.0f - pd->free_end);
-
- if (guidetime > 1.0f)
- continue;
-
- cu = (Curve *)eff->ob->data;
-
- if (pd->flag & PFIELD_GUIDE_PATH_ADD) {
- if (where_on_path(eff->ob, data->strength * guidetime, guidevec, guidedir, NULL, &radius, &weight) == 0)
- return 0;
- }
- else {
- if (where_on_path(eff->ob, guidetime, guidevec, guidedir, NULL, &radius, &weight) == 0)
- return 0;
- }
-
- mul_m4_v3(eff->ob->obmat, guidevec);
- mul_mat3_m4_v3(eff->ob->obmat, guidedir);
-
- normalize_v3(guidedir);
-
- copy_v3_v3(vec_to_point, data->vec_to_point);
-
- if (guidetime != 0.0f) {
- /* curve direction */
- cross_v3_v3v3(temp, eff->guide_dir, guidedir);
- angle = dot_v3v3(eff->guide_dir, guidedir) / (len_v3(eff->guide_dir));
- angle = saacos(angle);
- axis_angle_to_quat(rot2, temp, angle);
- mul_qt_v3(rot2, vec_to_point);
-
- /* curve tilt */
- axis_angle_to_quat(rot2, guidedir, guidevec[3] - eff->guide_loc[3]);
- mul_qt_v3(rot2, vec_to_point);
- }
-
- /* curve taper */
- if (cu->taperobj)
- mul_v3_fl(vec_to_point, BKE_displist_calc_taper(depsgraph, eff->scene, cu->taperobj, (int)(data->strength * guidetime * 100.0f), 100));
-
- else { /* curve size*/
- if (cu->flag & CU_PATH_RADIUS) {
- mul_v3_fl(vec_to_point, radius);
- }
- }
-
- if (clumpcurve)
- curvemapping_changed_all(clumpcurve);
- if (roughcurve)
- curvemapping_changed_all(roughcurve);
-
- {
- ParticleKey key;
- float par_co[3] = {0.0f, 0.0f, 0.0f};
- float par_vel[3] = {0.0f, 0.0f, 0.0f};
- float par_rot[4] = {1.0f, 0.0f, 0.0f, 0.0f};
- float orco_offset[3] = {0.0f, 0.0f, 0.0f};
-
- copy_v3_v3(key.co, vec_to_point);
- do_kink(&key, par_co, par_vel, par_rot, guidetime, pd->kink_freq, pd->kink_shape, pd->kink_amp, 0.f, pd->kink, pd->kink_axis, 0, 0);
- do_clump(&key, par_co, guidetime, orco_offset, pd->clump_fac, pd->clump_pow, 1.0f,
- part->child_flag & PART_CHILD_USE_CLUMP_NOISE, part->clump_noise_size, clumpcurve);
- copy_v3_v3(vec_to_point, key.co);
- }
-
- add_v3_v3(vec_to_point, guidevec);
-
- //sub_v3_v3v3(pa_loc, pa_loc, pa_zero);
- madd_v3_v3fl(effect, vec_to_point, data->strength);
- madd_v3_v3fl(veffect, guidedir, data->strength);
- totstrength += data->strength;
-
- if (pd->flag & PFIELD_GUIDE_PATH_WEIGHT)
- totstrength *= weight;
- }
-
- if (totstrength != 0.0f) {
- if (totstrength > 1.0f)
- mul_v3_fl(effect, 1.0f / totstrength);
- CLAMP(totstrength, 0.0f, 1.0f);
- //add_v3_v3(effect, pa_zero);
- interp_v3_v3v3(state->co, state->co, effect, totstrength);
-
- normalize_v3(veffect);
- mul_v3_fl(veffect, len_v3(state->vel));
- copy_v3_v3(state->vel, veffect);
- return 1;
- }
- return 0;
+ CurveMapping *clumpcurve = (part->child_flag & PART_CHILD_USE_CLUMP_CURVE) ? part->clumpcurve :
+ NULL;
+ CurveMapping *roughcurve = (part->child_flag & PART_CHILD_USE_ROUGH_CURVE) ? part->roughcurve :
+ NULL;
+ EffectorCache *eff;
+ PartDeflect *pd;
+ Curve *cu;
+ GuideEffectorData *data;
+
+ float effect[3] = {0.0f, 0.0f, 0.0f}, veffect[3] = {0.0f, 0.0f, 0.0f};
+ float guidevec[4], guidedir[3], rot2[4], temp[3];
+ float guidetime, radius, weight, angle, totstrength = 0.0f;
+ float vec_to_point[3];
+
+ if (effectors)
+ for (eff = effectors->first; eff; eff = eff->next) {
+ pd = eff->pd;
+
+ if (pd->forcefield != PFIELD_GUIDE)
+ continue;
+
+ data = eff->guide_data + index;
+
+ if (data->strength <= 0.0f)
+ continue;
+
+ guidetime = time / (1.0f - pd->free_end);
+
+ if (guidetime > 1.0f)
+ continue;
+
+ cu = (Curve *)eff->ob->data;
+
+ if (pd->flag & PFIELD_GUIDE_PATH_ADD) {
+ if (where_on_path(
+ eff->ob, data->strength * guidetime, guidevec, guidedir, NULL, &radius, &weight) ==
+ 0)
+ return 0;
+ }
+ else {
+ if (where_on_path(eff->ob, guidetime, guidevec, guidedir, NULL, &radius, &weight) == 0)
+ return 0;
+ }
+
+ mul_m4_v3(eff->ob->obmat, guidevec);
+ mul_mat3_m4_v3(eff->ob->obmat, guidedir);
+
+ normalize_v3(guidedir);
+
+ copy_v3_v3(vec_to_point, data->vec_to_point);
+
+ if (guidetime != 0.0f) {
+ /* curve direction */
+ cross_v3_v3v3(temp, eff->guide_dir, guidedir);
+ angle = dot_v3v3(eff->guide_dir, guidedir) / (len_v3(eff->guide_dir));
+ angle = saacos(angle);
+ axis_angle_to_quat(rot2, temp, angle);
+ mul_qt_v3(rot2, vec_to_point);
+
+ /* curve tilt */
+ axis_angle_to_quat(rot2, guidedir, guidevec[3] - eff->guide_loc[3]);
+ mul_qt_v3(rot2, vec_to_point);
+ }
+
+ /* curve taper */
+ if (cu->taperobj)
+ mul_v3_fl(vec_to_point,
+ BKE_displist_calc_taper(depsgraph,
+ eff->scene,
+ cu->taperobj,
+ (int)(data->strength * guidetime * 100.0f),
+ 100));
+
+ else { /* curve size*/
+ if (cu->flag & CU_PATH_RADIUS) {
+ mul_v3_fl(vec_to_point, radius);
+ }
+ }
+
+ if (clumpcurve)
+ curvemapping_changed_all(clumpcurve);
+ if (roughcurve)
+ curvemapping_changed_all(roughcurve);
+
+ {
+ ParticleKey key;
+ float par_co[3] = {0.0f, 0.0f, 0.0f};
+ float par_vel[3] = {0.0f, 0.0f, 0.0f};
+ float par_rot[4] = {1.0f, 0.0f, 0.0f, 0.0f};
+ float orco_offset[3] = {0.0f, 0.0f, 0.0f};
+
+ copy_v3_v3(key.co, vec_to_point);
+ do_kink(&key,
+ par_co,
+ par_vel,
+ par_rot,
+ guidetime,
+ pd->kink_freq,
+ pd->kink_shape,
+ pd->kink_amp,
+ 0.f,
+ pd->kink,
+ pd->kink_axis,
+ 0,
+ 0);
+ do_clump(&key,
+ par_co,
+ guidetime,
+ orco_offset,
+ pd->clump_fac,
+ pd->clump_pow,
+ 1.0f,
+ part->child_flag & PART_CHILD_USE_CLUMP_NOISE,
+ part->clump_noise_size,
+ clumpcurve);
+ copy_v3_v3(vec_to_point, key.co);
+ }
+
+ add_v3_v3(vec_to_point, guidevec);
+
+ //sub_v3_v3v3(pa_loc, pa_loc, pa_zero);
+ madd_v3_v3fl(effect, vec_to_point, data->strength);
+ madd_v3_v3fl(veffect, guidedir, data->strength);
+ totstrength += data->strength;
+
+ if (pd->flag & PFIELD_GUIDE_PATH_WEIGHT)
+ totstrength *= weight;
+ }
+
+ if (totstrength != 0.0f) {
+ if (totstrength > 1.0f)
+ mul_v3_fl(effect, 1.0f / totstrength);
+ CLAMP(totstrength, 0.0f, 1.0f);
+ //add_v3_v3(effect, pa_zero);
+ interp_v3_v3v3(state->co, state->co, effect, totstrength);
+
+ normalize_v3(veffect);
+ mul_v3_fl(veffect, len_v3(state->vel));
+ copy_v3_v3(state->vel, veffect);
+ return 1;
+ }
+ return 0;
}
-static void do_path_effectors(ParticleSimulationData *sim, int i, ParticleCacheKey *ca, int k, int steps, float *UNUSED(rootco), float effector, float UNUSED(dfra), float UNUSED(cfra), float *length, float *vec)
+static void do_path_effectors(ParticleSimulationData *sim,
+ int i,
+ ParticleCacheKey *ca,
+ int k,
+ int steps,
+ float *UNUSED(rootco),
+ float effector,
+ float UNUSED(dfra),
+ float UNUSED(cfra),
+ float *length,
+ float *vec)
{
- float force[3] = {0.0f, 0.0f, 0.0f};
- ParticleKey eff_key;
- EffectedPoint epoint;
+ float force[3] = {0.0f, 0.0f, 0.0f};
+ ParticleKey eff_key;
+ EffectedPoint epoint;
- /* Don't apply effectors for dynamic hair, otherwise the effectors don't get applied twice. */
- if (sim->psys->flag & PSYS_HAIR_DYNAMICS)
- return;
+ /* Don't apply effectors for dynamic hair, otherwise the effectors don't get applied twice. */
+ if (sim->psys->flag & PSYS_HAIR_DYNAMICS)
+ return;
- copy_v3_v3(eff_key.co, (ca - 1)->co);
- copy_v3_v3(eff_key.vel, (ca - 1)->vel);
- copy_qt_qt(eff_key.rot, (ca - 1)->rot);
+ copy_v3_v3(eff_key.co, (ca - 1)->co);
+ copy_v3_v3(eff_key.vel, (ca - 1)->vel);
+ copy_qt_qt(eff_key.rot, (ca - 1)->rot);
- pd_point_from_particle(sim, sim->psys->particles + i, &eff_key, &epoint);
- BKE_effectors_apply(sim->psys->effectors, sim->colliders, sim->psys->part->effector_weights, &epoint, force, NULL);
+ pd_point_from_particle(sim, sim->psys->particles + i, &eff_key, &epoint);
+ BKE_effectors_apply(sim->psys->effectors,
+ sim->colliders,
+ sim->psys->part->effector_weights,
+ &epoint,
+ force,
+ NULL);
- mul_v3_fl(force, effector * powf((float)k / (float)steps, 100.0f * sim->psys->part->eff_hair) / (float)steps);
+ mul_v3_fl(force,
+ effector * powf((float)k / (float)steps, 100.0f * sim->psys->part->eff_hair) /
+ (float)steps);
- add_v3_v3(force, vec);
+ add_v3_v3(force, vec);
- normalize_v3(force);
+ normalize_v3(force);
- if (k < steps)
- sub_v3_v3v3(vec, (ca + 1)->co, ca->co);
+ if (k < steps)
+ sub_v3_v3v3(vec, (ca + 1)->co, ca->co);
- madd_v3_v3v3fl(ca->co, (ca - 1)->co, force, *length);
+ madd_v3_v3v3fl(ca->co, (ca - 1)->co, force, *length);
- if (k < steps)
- *length = len_v3(vec);
+ if (k < steps)
+ *length = len_v3(vec);
}
-static void offset_child(ChildParticle *cpa, ParticleKey *par, float *par_rot, ParticleKey *child, float flat, float radius)
+static void offset_child(ChildParticle *cpa,
+ ParticleKey *par,
+ float *par_rot,
+ ParticleKey *child,
+ float flat,
+ float radius)
{
- copy_v3_v3(child->co, cpa->fuv);
- mul_v3_fl(child->co, radius);
+ copy_v3_v3(child->co, cpa->fuv);
+ mul_v3_fl(child->co, radius);
- child->co[0] *= flat;
+ child->co[0] *= flat;
- copy_v3_v3(child->vel, par->vel);
+ copy_v3_v3(child->vel, par->vel);
- if (par_rot) {
- mul_qt_v3(par_rot, child->co);
- copy_qt_qt(child->rot, par_rot);
- }
- else
- unit_qt(child->rot);
+ if (par_rot) {
+ mul_qt_v3(par_rot, child->co);
+ copy_qt_qt(child->rot, par_rot);
+ }
+ else
+ unit_qt(child->rot);
- add_v3_v3(child->co, par->co);
+ add_v3_v3(child->co, par->co);
}
float *psys_cache_vgroup(Mesh *mesh, ParticleSystem *psys, int vgroup)
{
- float *vg = 0;
-
- if (vgroup < 0) {
- /* hair dynamics pinning vgroup */
-
- }
- else if (psys->vgroup[vgroup]) {
- MDeformVert *dvert = mesh->dvert;
- if (dvert) {
- int totvert = mesh->totvert, i;
- vg = MEM_callocN(sizeof(float) * totvert, "vg_cache");
- if (psys->vg_neg & (1 << vgroup)) {
- for (i = 0; i < totvert; i++)
- vg[i] = 1.0f - defvert_find_weight(&dvert[i], psys->vgroup[vgroup] - 1);
- }
- else {
- for (i = 0; i < totvert; i++)
- vg[i] = defvert_find_weight(&dvert[i], psys->vgroup[vgroup] - 1);
- }
- }
- }
- return vg;
+ float *vg = 0;
+
+ if (vgroup < 0) {
+ /* hair dynamics pinning vgroup */
+ }
+ else if (psys->vgroup[vgroup]) {
+ MDeformVert *dvert = mesh->dvert;
+ if (dvert) {
+ int totvert = mesh->totvert, i;
+ vg = MEM_callocN(sizeof(float) * totvert, "vg_cache");
+ if (psys->vg_neg & (1 << vgroup)) {
+ for (i = 0; i < totvert; i++)
+ vg[i] = 1.0f - defvert_find_weight(&dvert[i], psys->vgroup[vgroup] - 1);
+ }
+ else {
+ for (i = 0; i < totvert; i++)
+ vg[i] = defvert_find_weight(&dvert[i], psys->vgroup[vgroup] - 1);
+ }
+ }
+ }
+ return vg;
}
void psys_find_parents(ParticleSimulationData *sim, const bool use_render_params)
{
- ParticleSystem *psys = sim->psys;
- ParticleSettings *part = sim->psys->part;
- KDTree_3d *tree;
- ChildParticle *cpa;
- ParticleTexture ptex;
- int p, totparent, totchild = sim->psys->totchild;
- float co[3], orco[3];
- int from = PART_FROM_FACE;
- totparent = (int)(totchild * part->parents * 0.3f);
-
- if (use_render_params && part->child_nbr && part->ren_child_nbr)
- totparent *= (float)part->child_nbr / (float)part->ren_child_nbr;
-
- /* hard limit, workaround for it being ignored above */
- if (sim->psys->totpart < totparent) {
- totparent = sim->psys->totpart;
- }
-
- tree = BLI_kdtree_3d_new(totparent);
-
- for (p = 0, cpa = sim->psys->child; p < totparent; p++, cpa++) {
- psys_particle_on_emitter(sim->psmd, from, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, co, 0, 0, 0, orco);
-
- /* Check if particle doesn't exist because of texture influence. Insert only existing particles into kdtree. */
- get_cpa_texture(sim->psmd->mesh_final, psys, part, psys->particles + cpa->pa[0], p, cpa->num, cpa->fuv, orco, &ptex, PAMAP_DENS | PAMAP_CHILD, psys->cfra);
-
- if (ptex.exist >= psys_frand(psys, p + 24)) {
- BLI_kdtree_3d_insert(tree, p, orco);
- }
- }
-
- BLI_kdtree_3d_balance(tree);
-
- for (; p < totchild; p++, cpa++) {
- psys_particle_on_emitter(sim->psmd, from, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, co, 0, 0, 0, orco);
- cpa->parent = BLI_kdtree_3d_find_nearest(tree, orco, NULL);
- }
-
- BLI_kdtree_3d_free(tree);
+ ParticleSystem *psys = sim->psys;
+ ParticleSettings *part = sim->psys->part;
+ KDTree_3d *tree;
+ ChildParticle *cpa;
+ ParticleTexture ptex;
+ int p, totparent, totchild = sim->psys->totchild;
+ float co[3], orco[3];
+ int from = PART_FROM_FACE;
+ totparent = (int)(totchild * part->parents * 0.3f);
+
+ if (use_render_params && part->child_nbr && part->ren_child_nbr)
+ totparent *= (float)part->child_nbr / (float)part->ren_child_nbr;
+
+ /* hard limit, workaround for it being ignored above */
+ if (sim->psys->totpart < totparent) {
+ totparent = sim->psys->totpart;
+ }
+
+ tree = BLI_kdtree_3d_new(totparent);
+
+ for (p = 0, cpa = sim->psys->child; p < totparent; p++, cpa++) {
+ psys_particle_on_emitter(
+ sim->psmd, from, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, co, 0, 0, 0, orco);
+
+ /* Check if particle doesn't exist because of texture influence. Insert only existing particles into kdtree. */
+ get_cpa_texture(sim->psmd->mesh_final,
+ psys,
+ part,
+ psys->particles + cpa->pa[0],
+ p,
+ cpa->num,
+ cpa->fuv,
+ orco,
+ &ptex,
+ PAMAP_DENS | PAMAP_CHILD,
+ psys->cfra);
+
+ if (ptex.exist >= psys_frand(psys, p + 24)) {
+ BLI_kdtree_3d_insert(tree, p, orco);
+ }
+ }
+
+ BLI_kdtree_3d_balance(tree);
+
+ for (; p < totchild; p++, cpa++) {
+ psys_particle_on_emitter(
+ sim->psmd, from, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, co, 0, 0, 0, orco);
+ cpa->parent = BLI_kdtree_3d_find_nearest(tree, orco, NULL);
+ }
+
+ BLI_kdtree_3d_free(tree);
}
-static bool psys_thread_context_init_path(
- ParticleThreadContext *ctx, ParticleSimulationData *sim, Scene *scene,
- float cfra, const bool editupdate, const bool use_render_params)
+static bool psys_thread_context_init_path(ParticleThreadContext *ctx,
+ ParticleSimulationData *sim,
+ Scene *scene,
+ float cfra,
+ const bool editupdate,
+ const bool use_render_params)
{
- ParticleSystem *psys = sim->psys;
- ParticleSettings *part = psys->part;
- int totparent = 0, between = 0;
- int segments = 1 << part->draw_step;
- int totchild = psys->totchild;
-
- psys_thread_context_init(ctx, sim);
-
- /*---start figuring out what is actually wanted---*/
- if (psys_in_edit_mode(sim->depsgraph, psys)) {
- ParticleEditSettings *pset = &scene->toolsettings->particle;
-
- if ((use_render_params == 0) && (psys_orig_edit_get(psys) == NULL || pset->flag & PE_DRAW_PART) == 0)
- totchild = 0;
-
- segments = 1 << pset->draw_step;
- }
-
- if (totchild && part->childtype == PART_CHILD_FACES) {
- totparent = (int)(totchild * part->parents * 0.3f);
-
- if (use_render_params && part->child_nbr && part->ren_child_nbr)
- totparent *= (float)part->child_nbr / (float)part->ren_child_nbr;
-
- /* part->parents could still be 0 so we can't test with totparent */
- between = 1;
- }
-
- if (use_render_params)
- segments = 1 << part->ren_step;
- else {
- totchild = (int)((float)totchild * (float)part->disp / 100.0f);
- totparent = MIN2(totparent, totchild);
- }
-
- if (totchild == 0)
- return false;
-
- /* fill context values */
- ctx->between = between;
- ctx->segments = segments;
- if (ELEM(part->kink, PART_KINK_SPIRAL))
- ctx->extra_segments = max_ii(part->kink_extra_steps, 1);
- else
- ctx->extra_segments = 0;
- ctx->totchild = totchild;
- ctx->totparent = totparent;
- ctx->parent_pass = 0;
- ctx->cfra = cfra;
- ctx->editupdate = editupdate;
-
- psys->lattice_deform_data = psys_create_lattice_deform_data(&ctx->sim);
-
- /* cache all relevant vertex groups if they exist */
- ctx->vg_length = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_LENGTH);
- ctx->vg_clump = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_CLUMP);
- ctx->vg_kink = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_KINK);
- ctx->vg_rough1 = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_ROUGH1);
- ctx->vg_rough2 = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_ROUGH2);
- ctx->vg_roughe = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_ROUGHE);
- ctx->vg_twist = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_TWIST);
- if (psys->part->flag & PART_CHILD_EFFECT)
- ctx->vg_effector = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_EFFECTOR);
-
- /* prepare curvemapping tables */
- if ((part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && part->clumpcurve) {
- ctx->clumpcurve = curvemapping_copy(part->clumpcurve);
- curvemapping_changed_all(ctx->clumpcurve);
- }
- else {
- ctx->clumpcurve = NULL;
- }
- if ((part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && part->roughcurve) {
- ctx->roughcurve = curvemapping_copy(part->roughcurve);
- curvemapping_changed_all(ctx->roughcurve);
- }
- else {
- ctx->roughcurve = NULL;
- }
- if ((part->child_flag & PART_CHILD_USE_TWIST_CURVE) && part->twistcurve) {
- ctx->twistcurve = curvemapping_copy(part->twistcurve);
- curvemapping_changed_all(ctx->twistcurve);
- }
- else {
- ctx->twistcurve = NULL;
- }
-
- return true;
+ ParticleSystem *psys = sim->psys;
+ ParticleSettings *part = psys->part;
+ int totparent = 0, between = 0;
+ int segments = 1 << part->draw_step;
+ int totchild = psys->totchild;
+
+ psys_thread_context_init(ctx, sim);
+
+ /*---start figuring out what is actually wanted---*/
+ if (psys_in_edit_mode(sim->depsgraph, psys)) {
+ ParticleEditSettings *pset = &scene->toolsettings->particle;
+
+ if ((use_render_params == 0) &&
+ (psys_orig_edit_get(psys) == NULL || pset->flag & PE_DRAW_PART) == 0)
+ totchild = 0;
+
+ segments = 1 << pset->draw_step;
+ }
+
+ if (totchild && part->childtype == PART_CHILD_FACES) {
+ totparent = (int)(totchild * part->parents * 0.3f);
+
+ if (use_render_params && part->child_nbr && part->ren_child_nbr)
+ totparent *= (float)part->child_nbr / (float)part->ren_child_nbr;
+
+ /* part->parents could still be 0 so we can't test with totparent */
+ between = 1;
+ }
+
+ if (use_render_params)
+ segments = 1 << part->ren_step;
+ else {
+ totchild = (int)((float)totchild * (float)part->disp / 100.0f);
+ totparent = MIN2(totparent, totchild);
+ }
+
+ if (totchild == 0)
+ return false;
+
+ /* fill context values */
+ ctx->between = between;
+ ctx->segments = segments;
+ if (ELEM(part->kink, PART_KINK_SPIRAL))
+ ctx->extra_segments = max_ii(part->kink_extra_steps, 1);
+ else
+ ctx->extra_segments = 0;
+ ctx->totchild = totchild;
+ ctx->totparent = totparent;
+ ctx->parent_pass = 0;
+ ctx->cfra = cfra;
+ ctx->editupdate = editupdate;
+
+ psys->lattice_deform_data = psys_create_lattice_deform_data(&ctx->sim);
+
+ /* cache all relevant vertex groups if they exist */
+ ctx->vg_length = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_LENGTH);
+ ctx->vg_clump = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_CLUMP);
+ ctx->vg_kink = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_KINK);
+ ctx->vg_rough1 = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_ROUGH1);
+ ctx->vg_rough2 = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_ROUGH2);
+ ctx->vg_roughe = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_ROUGHE);
+ ctx->vg_twist = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_TWIST);
+ if (psys->part->flag & PART_CHILD_EFFECT)
+ ctx->vg_effector = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_EFFECTOR);
+
+ /* prepare curvemapping tables */
+ if ((part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && part->clumpcurve) {
+ ctx->clumpcurve = curvemapping_copy(part->clumpcurve);
+ curvemapping_changed_all(ctx->clumpcurve);
+ }
+ else {
+ ctx->clumpcurve = NULL;
+ }
+ if ((part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && part->roughcurve) {
+ ctx->roughcurve = curvemapping_copy(part->roughcurve);
+ curvemapping_changed_all(ctx->roughcurve);
+ }
+ else {
+ ctx->roughcurve = NULL;
+ }
+ if ((part->child_flag & PART_CHILD_USE_TWIST_CURVE) && part->twistcurve) {
+ ctx->twistcurve = curvemapping_copy(part->twistcurve);
+ curvemapping_changed_all(ctx->twistcurve);
+ }
+ else {
+ ctx->twistcurve = NULL;
+ }
+
+ return true;
}
static void psys_task_init_path(ParticleTask *task, ParticleSimulationData *sim)
{
- /* init random number generator */
- int seed = 31415926 + sim->psys->seed;
+ /* init random number generator */
+ int seed = 31415926 + sim->psys->seed;
- task->rng_path = BLI_rng_new(seed);
+ task->rng_path = BLI_rng_new(seed);
}
/* note: this function must be thread safe, except for branching! */
-static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cpa, ParticleCacheKey *child_keys, int i)
+static void psys_thread_create_path(ParticleTask *task,
+ struct ChildParticle *cpa,
+ ParticleCacheKey *child_keys,
+ int i)
{
- ParticleThreadContext *ctx = task->ctx;
- Object *ob = ctx->sim.ob;
- ParticleSystem *psys = ctx->sim.psys;
- ParticleSettings *part = psys->part;
- ParticleCacheKey **cache = psys->childcache;
- PTCacheEdit *edit = psys_orig_edit_get(psys);
- ParticleCacheKey **pcache = psys_in_edit_mode(ctx->sim.depsgraph, psys) && edit ? edit->pathcache : psys->pathcache;
- ParticleCacheKey *child, *key[4];
- ParticleTexture ptex;
- float *cpa_fuv = 0, *par_rot = 0, rot[4];
- float orco[3], hairmat[4][4], dvec[3], off1[4][3], off2[4][3];
- float eff_length, eff_vec[3], weight[4];
- int k, cpa_num;
- short cpa_from;
-
- if (!pcache)
- return;
-
- if (ctx->between) {
- ParticleData *pa = psys->particles + cpa->pa[0];
- int w, needupdate;
- float foffset, wsum = 0.f;
- float co[3];
- float p_min = part->parting_min;
- float p_max = part->parting_max;
- /* Virtual parents don't work nicely with parting. */
- float p_fac = part->parents > 0.f ? 0.f : part->parting_fac;
-
- if (ctx->editupdate) {
- needupdate = 0;
- w = 0;
- while (w < 4 && cpa->pa[w] >= 0) {
- if (edit->points[cpa->pa[w]].flag & PEP_EDIT_RECALC) {
- needupdate = 1;
- break;
- }
- w++;
- }
-
- if (!needupdate)
- return;
- else
- memset(child_keys, 0, sizeof(*child_keys) * (ctx->segments + 1));
- }
-
- /* get parent paths */
- for (w = 0; w < 4; w++) {
- if (cpa->pa[w] >= 0) {
- key[w] = pcache[cpa->pa[w]];
- weight[w] = cpa->w[w];
- }
- else {
- key[w] = pcache[0];
- weight[w] = 0.f;
- }
- }
-
- /* modify weights to create parting */
- if (p_fac > 0.f) {
- const ParticleCacheKey *key_0_last = pcache_key_segment_endpoint_safe(key[0]);
- for (w = 0; w < 4; w++) {
- if (w && (weight[w] > 0.f)) {
- const ParticleCacheKey *key_w_last = pcache_key_segment_endpoint_safe(key[w]);
- float d;
- if (part->flag & PART_CHILD_LONG_HAIR) {
- /* For long hair use tip distance/root distance as parting factor instead of root to tip angle. */
- float d1 = len_v3v3(key[0]->co, key[w]->co);
- float d2 = len_v3v3(key_0_last->co, key_w_last->co);
-
- d = d1 > 0.f ? d2 / d1 - 1.f : 10000.f;
- }
- else {
- float v1[3], v2[3];
- sub_v3_v3v3(v1, key_0_last->co, key[0]->co);
- sub_v3_v3v3(v2, key_w_last->co, key[w]->co);
- normalize_v3(v1);
- normalize_v3(v2);
-
- d = RAD2DEGF(saacos(dot_v3v3(v1, v2)));
- }
-
- if (p_max > p_min)
- d = (d - p_min) / (p_max - p_min);
- else
- d = (d - p_min) <= 0.f ? 0.f : 1.f;
-
- CLAMP(d, 0.f, 1.f);
-
- if (d > 0.f)
- weight[w] *= (1.f - d);
- }
- wsum += weight[w];
- }
- for (w = 0; w < 4; w++)
- weight[w] /= wsum;
-
- interp_v4_v4v4(weight, cpa->w, weight, p_fac);
- }
-
- /* get the original coordinates (orco) for texture usage */
- cpa_num = cpa->num;
-
- foffset = cpa->foffset;
- cpa_fuv = cpa->fuv;
- cpa_from = PART_FROM_FACE;
-
- psys_particle_on_emitter(ctx->sim.psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa->fuv, foffset, co, 0, 0, 0, orco);
-
- mul_m4_v3(ob->obmat, co);
-
- for (w = 0; w < 4; w++)
- sub_v3_v3v3(off1[w], co, key[w]->co);
-
- psys_mat_hair_to_global(ob, ctx->sim.psmd->mesh_final, psys->part->from, pa, hairmat);
- }
- else {
- ParticleData *pa = psys->particles + cpa->parent;
- float co[3];
- if (ctx->editupdate) {
- if (!(edit->points[cpa->parent].flag & PEP_EDIT_RECALC))
- return;
-
- memset(child_keys, 0, sizeof(*child_keys) * (ctx->segments + 1));
- }
-
- /* get the parent path */
- key[0] = pcache[cpa->parent];
-
- /* get the original coordinates (orco) for texture usage */
- cpa_from = part->from;
-
- /*
- * NOTE: Should in theory be the same as:
- * cpa_num = psys_particle_dm_face_lookup(
- * ctx->sim.psmd->dm_final,
- * ctx->sim.psmd->dm_deformed,
- * pa->num, pa->fuv,
- * NULL);
- */
- cpa_num = (ELEM(pa->num_dmcache, DMCACHE_ISCHILD, DMCACHE_NOTFOUND))
- ? pa->num
- : pa->num_dmcache;
-
- /* XXX hack to avoid messed up particle num and subsequent crash (#40733) */
- if (cpa_num > ctx->sim.psmd->mesh_final->totface)
- cpa_num = 0;
- cpa_fuv = pa->fuv;
-
- psys_particle_on_emitter(ctx->sim.psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa_fuv, pa->foffset, co, 0, 0, 0, orco);
-
- psys_mat_hair_to_global(ob, ctx->sim.psmd->mesh_final, psys->part->from, pa, hairmat);
- }
-
- child_keys->segments = ctx->segments;
-
- /* get different child parameters from textures & vgroups */
- get_child_modifier_parameters(part, ctx, cpa, cpa_from, cpa_num, cpa_fuv, orco, &ptex);
-
- if (ptex.exist < psys_frand(psys, i + 24)) {
- child_keys->segments = -1;
- return;
- }
-
- /* create the child path */
- for (k = 0, child = child_keys; k <= ctx->segments; k++, child++) {
- if (ctx->between) {
- int w = 0;
-
- zero_v3(child->co);
- zero_v3(child->vel);
- unit_qt(child->rot);
-
- for (w = 0; w < 4; w++) {
- copy_v3_v3(off2[w], off1[w]);
-
- if (part->flag & PART_CHILD_LONG_HAIR) {
- /* Use parent rotation (in addition to emission location) to determine child offset. */
- if (k)
- mul_qt_v3((key[w] + k)->rot, off2[w]);
-
- /* Fade the effect of rotation for even lengths in the end */
- project_v3_v3v3(dvec, off2[w], (key[w] + k)->vel);
- madd_v3_v3fl(off2[w], dvec, -(float)k / (float)ctx->segments);
- }
-
- add_v3_v3(off2[w], (key[w] + k)->co);
- }
-
- /* child position is the weighted sum of parent positions */
- interp_v3_v3v3v3v3(child->co, off2[0], off2[1], off2[2], off2[3], weight);
- interp_v3_v3v3v3v3(child->vel, (key[0] + k)->vel, (key[1] + k)->vel, (key[2] + k)->vel, (key[3] + k)->vel, weight);
-
- copy_qt_qt(child->rot, (key[0] + k)->rot);
- }
- else {
- if (k) {
- mul_qt_qtqt(rot, (key[0] + k)->rot, key[0]->rot);
- par_rot = rot;
- }
- else {
- par_rot = key[0]->rot;
- }
- /* offset the child from the parent position */
- offset_child(cpa, (ParticleKey *)(key[0] + k), par_rot, (ParticleKey *)child, part->childflat, part->childrad);
- }
-
- child->time = (float)k / (float)ctx->segments;
- }
-
- /* apply effectors */
- if (part->flag & PART_CHILD_EFFECT) {
- for (k = 0, child = child_keys; k <= ctx->segments; k++, child++) {
- if (k) {
- do_path_effectors(&ctx->sim, cpa->pa[0], child, k, ctx->segments, child_keys->co, ptex.effector, 0.0f, ctx->cfra, &eff_length, eff_vec);
- }
- else {
- sub_v3_v3v3(eff_vec, (child + 1)->co, child->co);
- eff_length = len_v3(eff_vec);
- }
- }
- }
-
- {
- ParticleData *pa = NULL;
- ParticleCacheKey *par = NULL;
- float par_co[3];
- float par_orco[3];
-
- if (ctx->totparent) {
- if (i >= ctx->totparent) {
- pa = &psys->particles[cpa->parent];
- /* this is now threadsafe, virtual parents are calculated before rest of children */
- BLI_assert(cpa->parent < psys->totchildcache);
- par = cache[cpa->parent];
- }
- }
- else if (cpa->parent >= 0) {
- pa = &psys->particles[cpa->parent];
- par = pcache[cpa->parent];
-
- /* If particle is unexisting, try to pick a viable parent from particles used for interpolation. */
- for (k = 0; k < 4 && pa && (pa->flag & PARS_UNEXIST); k++) {
- if (cpa->pa[k] >= 0) {
- pa = &psys->particles[cpa->pa[k]];
- par = pcache[cpa->pa[k]];
- }
- }
-
- if (pa->flag & PARS_UNEXIST) pa = NULL;
- }
-
- if (pa) {
- ListBase modifiers;
- BLI_listbase_clear(&modifiers);
-
- psys_particle_on_emitter(ctx->sim.psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset,
- par_co, NULL, NULL, NULL, par_orco);
-
- psys_apply_child_modifiers(ctx, &modifiers, cpa, &ptex, orco, hairmat, child_keys, par, par_orco);
- }
- else
- zero_v3(par_orco);
- }
-
- /* Hide virtual parents */
- if (i < ctx->totparent)
- child_keys->segments = -1;
+ ParticleThreadContext *ctx = task->ctx;
+ Object *ob = ctx->sim.ob;
+ ParticleSystem *psys = ctx->sim.psys;
+ ParticleSettings *part = psys->part;
+ ParticleCacheKey **cache = psys->childcache;
+ PTCacheEdit *edit = psys_orig_edit_get(psys);
+ ParticleCacheKey **pcache = psys_in_edit_mode(ctx->sim.depsgraph, psys) && edit ?
+ edit->pathcache :
+ psys->pathcache;
+ ParticleCacheKey *child, *key[4];
+ ParticleTexture ptex;
+ float *cpa_fuv = 0, *par_rot = 0, rot[4];
+ float orco[3], hairmat[4][4], dvec[3], off1[4][3], off2[4][3];
+ float eff_length, eff_vec[3], weight[4];
+ int k, cpa_num;
+ short cpa_from;
+
+ if (!pcache)
+ return;
+
+ if (ctx->between) {
+ ParticleData *pa = psys->particles + cpa->pa[0];
+ int w, needupdate;
+ float foffset, wsum = 0.f;
+ float co[3];
+ float p_min = part->parting_min;
+ float p_max = part->parting_max;
+ /* Virtual parents don't work nicely with parting. */
+ float p_fac = part->parents > 0.f ? 0.f : part->parting_fac;
+
+ if (ctx->editupdate) {
+ needupdate = 0;
+ w = 0;
+ while (w < 4 && cpa->pa[w] >= 0) {
+ if (edit->points[cpa->pa[w]].flag & PEP_EDIT_RECALC) {
+ needupdate = 1;
+ break;
+ }
+ w++;
+ }
+
+ if (!needupdate)
+ return;
+ else
+ memset(child_keys, 0, sizeof(*child_keys) * (ctx->segments + 1));
+ }
+
+ /* get parent paths */
+ for (w = 0; w < 4; w++) {
+ if (cpa->pa[w] >= 0) {
+ key[w] = pcache[cpa->pa[w]];
+ weight[w] = cpa->w[w];
+ }
+ else {
+ key[w] = pcache[0];
+ weight[w] = 0.f;
+ }
+ }
+
+ /* modify weights to create parting */
+ if (p_fac > 0.f) {
+ const ParticleCacheKey *key_0_last = pcache_key_segment_endpoint_safe(key[0]);
+ for (w = 0; w < 4; w++) {
+ if (w && (weight[w] > 0.f)) {
+ const ParticleCacheKey *key_w_last = pcache_key_segment_endpoint_safe(key[w]);
+ float d;
+ if (part->flag & PART_CHILD_LONG_HAIR) {
+ /* For long hair use tip distance/root distance as parting factor instead of root to tip angle. */
+ float d1 = len_v3v3(key[0]->co, key[w]->co);
+ float d2 = len_v3v3(key_0_last->co, key_w_last->co);
+
+ d = d1 > 0.f ? d2 / d1 - 1.f : 10000.f;
+ }
+ else {
+ float v1[3], v2[3];
+ sub_v3_v3v3(v1, key_0_last->co, key[0]->co);
+ sub_v3_v3v3(v2, key_w_last->co, key[w]->co);
+ normalize_v3(v1);
+ normalize_v3(v2);
+
+ d = RAD2DEGF(saacos(dot_v3v3(v1, v2)));
+ }
+
+ if (p_max > p_min)
+ d = (d - p_min) / (p_max - p_min);
+ else
+ d = (d - p_min) <= 0.f ? 0.f : 1.f;
+
+ CLAMP(d, 0.f, 1.f);
+
+ if (d > 0.f)
+ weight[w] *= (1.f - d);
+ }
+ wsum += weight[w];
+ }
+ for (w = 0; w < 4; w++)
+ weight[w] /= wsum;
+
+ interp_v4_v4v4(weight, cpa->w, weight, p_fac);
+ }
+
+ /* get the original coordinates (orco) for texture usage */
+ cpa_num = cpa->num;
+
+ foffset = cpa->foffset;
+ cpa_fuv = cpa->fuv;
+ cpa_from = PART_FROM_FACE;
+
+ psys_particle_on_emitter(
+ ctx->sim.psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa->fuv, foffset, co, 0, 0, 0, orco);
+
+ mul_m4_v3(ob->obmat, co);
+
+ for (w = 0; w < 4; w++)
+ sub_v3_v3v3(off1[w], co, key[w]->co);
+
+ psys_mat_hair_to_global(ob, ctx->sim.psmd->mesh_final, psys->part->from, pa, hairmat);
+ }
+ else {
+ ParticleData *pa = psys->particles + cpa->parent;
+ float co[3];
+ if (ctx->editupdate) {
+ if (!(edit->points[cpa->parent].flag & PEP_EDIT_RECALC))
+ return;
+
+ memset(child_keys, 0, sizeof(*child_keys) * (ctx->segments + 1));
+ }
+
+ /* get the parent path */
+ key[0] = pcache[cpa->parent];
+
+ /* get the original coordinates (orco) for texture usage */
+ cpa_from = part->from;
+
+ /*
+ * NOTE: Should in theory be the same as:
+ * cpa_num = psys_particle_dm_face_lookup(
+ * ctx->sim.psmd->dm_final,
+ * ctx->sim.psmd->dm_deformed,
+ * pa->num, pa->fuv,
+ * NULL);
+ */
+ cpa_num = (ELEM(pa->num_dmcache, DMCACHE_ISCHILD, DMCACHE_NOTFOUND)) ? pa->num :
+ pa->num_dmcache;
+
+ /* XXX hack to avoid messed up particle num and subsequent crash (#40733) */
+ if (cpa_num > ctx->sim.psmd->mesh_final->totface)
+ cpa_num = 0;
+ cpa_fuv = pa->fuv;
+
+ psys_particle_on_emitter(ctx->sim.psmd,
+ cpa_from,
+ cpa_num,
+ DMCACHE_ISCHILD,
+ cpa_fuv,
+ pa->foffset,
+ co,
+ 0,
+ 0,
+ 0,
+ orco);
+
+ psys_mat_hair_to_global(ob, ctx->sim.psmd->mesh_final, psys->part->from, pa, hairmat);
+ }
+
+ child_keys->segments = ctx->segments;
+
+ /* get different child parameters from textures & vgroups */
+ get_child_modifier_parameters(part, ctx, cpa, cpa_from, cpa_num, cpa_fuv, orco, &ptex);
+
+ if (ptex.exist < psys_frand(psys, i + 24)) {
+ child_keys->segments = -1;
+ return;
+ }
+
+ /* create the child path */
+ for (k = 0, child = child_keys; k <= ctx->segments; k++, child++) {
+ if (ctx->between) {
+ int w = 0;
+
+ zero_v3(child->co);
+ zero_v3(child->vel);
+ unit_qt(child->rot);
+
+ for (w = 0; w < 4; w++) {
+ copy_v3_v3(off2[w], off1[w]);
+
+ if (part->flag & PART_CHILD_LONG_HAIR) {
+ /* Use parent rotation (in addition to emission location) to determine child offset. */
+ if (k)
+ mul_qt_v3((key[w] + k)->rot, off2[w]);
+
+ /* Fade the effect of rotation for even lengths in the end */
+ project_v3_v3v3(dvec, off2[w], (key[w] + k)->vel);
+ madd_v3_v3fl(off2[w], dvec, -(float)k / (float)ctx->segments);
+ }
+
+ add_v3_v3(off2[w], (key[w] + k)->co);
+ }
+
+ /* child position is the weighted sum of parent positions */
+ interp_v3_v3v3v3v3(child->co, off2[0], off2[1], off2[2], off2[3], weight);
+ interp_v3_v3v3v3v3(child->vel,
+ (key[0] + k)->vel,
+ (key[1] + k)->vel,
+ (key[2] + k)->vel,
+ (key[3] + k)->vel,
+ weight);
+
+ copy_qt_qt(child->rot, (key[0] + k)->rot);
+ }
+ else {
+ if (k) {
+ mul_qt_qtqt(rot, (key[0] + k)->rot, key[0]->rot);
+ par_rot = rot;
+ }
+ else {
+ par_rot = key[0]->rot;
+ }
+ /* offset the child from the parent position */
+ offset_child(cpa,
+ (ParticleKey *)(key[0] + k),
+ par_rot,
+ (ParticleKey *)child,
+ part->childflat,
+ part->childrad);
+ }
+
+ child->time = (float)k / (float)ctx->segments;
+ }
+
+ /* apply effectors */
+ if (part->flag & PART_CHILD_EFFECT) {
+ for (k = 0, child = child_keys; k <= ctx->segments; k++, child++) {
+ if (k) {
+ do_path_effectors(&ctx->sim,
+ cpa->pa[0],
+ child,
+ k,
+ ctx->segments,
+ child_keys->co,
+ ptex.effector,
+ 0.0f,
+ ctx->cfra,
+ &eff_length,
+ eff_vec);
+ }
+ else {
+ sub_v3_v3v3(eff_vec, (child + 1)->co, child->co);
+ eff_length = len_v3(eff_vec);
+ }
+ }
+ }
+
+ {
+ ParticleData *pa = NULL;
+ ParticleCacheKey *par = NULL;
+ float par_co[3];
+ float par_orco[3];
+
+ if (ctx->totparent) {
+ if (i >= ctx->totparent) {
+ pa = &psys->particles[cpa->parent];
+ /* this is now threadsafe, virtual parents are calculated before rest of children */
+ BLI_assert(cpa->parent < psys->totchildcache);
+ par = cache[cpa->parent];
+ }
+ }
+ else if (cpa->parent >= 0) {
+ pa = &psys->particles[cpa->parent];
+ par = pcache[cpa->parent];
+
+ /* If particle is unexisting, try to pick a viable parent from particles used for interpolation. */
+ for (k = 0; k < 4 && pa && (pa->flag & PARS_UNEXIST); k++) {
+ if (cpa->pa[k] >= 0) {
+ pa = &psys->particles[cpa->pa[k]];
+ par = pcache[cpa->pa[k]];
+ }
+ }
+
+ if (pa->flag & PARS_UNEXIST)
+ pa = NULL;
+ }
+
+ if (pa) {
+ ListBase modifiers;
+ BLI_listbase_clear(&modifiers);
+
+ psys_particle_on_emitter(ctx->sim.psmd,
+ part->from,
+ pa->num,
+ pa->num_dmcache,
+ pa->fuv,
+ pa->foffset,
+ par_co,
+ NULL,
+ NULL,
+ NULL,
+ par_orco);
+
+ psys_apply_child_modifiers(
+ ctx, &modifiers, cpa, &ptex, orco, hairmat, child_keys, par, par_orco);
+ }
+ else
+ zero_v3(par_orco);
+ }
+
+ /* Hide virtual parents */
+ if (i < ctx->totparent)
+ child_keys->segments = -1;
}
-static void exec_child_path_cache(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
+static void exec_child_path_cache(TaskPool *__restrict UNUSED(pool),
+ void *taskdata,
+ int UNUSED(threadid))
{
- ParticleTask *task = taskdata;
- ParticleThreadContext *ctx = task->ctx;
- ParticleSystem *psys = ctx->sim.psys;
- ParticleCacheKey **cache = psys->childcache;
- ChildParticle *cpa;
- int i;
-
- cpa = psys->child + task->begin;
- for (i = task->begin; i < task->end; ++i, ++cpa) {
- BLI_assert(i < psys->totchildcache);
- psys_thread_create_path(task, cpa, cache[i], i);
- }
+ ParticleTask *task = taskdata;
+ ParticleThreadContext *ctx = task->ctx;
+ ParticleSystem *psys = ctx->sim.psys;
+ ParticleCacheKey **cache = psys->childcache;
+ ChildParticle *cpa;
+ int i;
+
+ cpa = psys->child + task->begin;
+ for (i = task->begin; i < task->end; ++i, ++cpa) {
+ BLI_assert(i < psys->totchildcache);
+ psys_thread_create_path(task, cpa, cache[i], i);
+ }
}
-void psys_cache_child_paths(
- ParticleSimulationData *sim, float cfra,
- const bool editupdate, const bool use_render_params)
+void psys_cache_child_paths(ParticleSimulationData *sim,
+ float cfra,
+ const bool editupdate,
+ const bool use_render_params)
{
- TaskScheduler *task_scheduler;
- TaskPool *task_pool;
- ParticleThreadContext ctx;
- ParticleTask *tasks_parent, *tasks_child;
- int numtasks_parent, numtasks_child;
- int i, totchild, totparent;
-
- if (sim->psys->flag & PSYS_GLOBAL_HAIR)
- return;
-
- /* create a task pool for child path tasks */
- if (!psys_thread_context_init_path(&ctx, sim, sim->scene, cfra, editupdate, use_render_params))
- return;
-
- task_scheduler = BLI_task_scheduler_get();
- task_pool = BLI_task_pool_create(task_scheduler, &ctx);
- totchild = ctx.totchild;
- totparent = ctx.totparent;
-
- if (editupdate && sim->psys->childcache && totchild == sim->psys->totchildcache) {
- /* just overwrite the existing cache */
- }
- else {
- /* clear out old and create new empty path cache */
- free_child_path_cache(sim->psys);
-
- sim->psys->childcache = psys_alloc_path_cache_buffers(&sim->psys->childcachebufs, totchild, ctx.segments + ctx.extra_segments + 1);
- sim->psys->totchildcache = totchild;
- }
-
- /* cache parent paths */
- ctx.parent_pass = 1;
- psys_tasks_create(&ctx, 0, totparent, &tasks_parent, &numtasks_parent);
- for (i = 0; i < numtasks_parent; ++i) {
- ParticleTask *task = &tasks_parent[i];
-
- psys_task_init_path(task, sim);
- BLI_task_pool_push(task_pool, exec_child_path_cache, task, false, TASK_PRIORITY_LOW);
- }
- BLI_task_pool_work_and_wait(task_pool);
-
- /* cache child paths */
- ctx.parent_pass = 0;
- psys_tasks_create(&ctx, totparent, totchild, &tasks_child, &numtasks_child);
- for (i = 0; i < numtasks_child; ++i) {
- ParticleTask *task = &tasks_child[i];
-
- psys_task_init_path(task, sim);
- BLI_task_pool_push(task_pool, exec_child_path_cache, task, false, TASK_PRIORITY_LOW);
- }
- BLI_task_pool_work_and_wait(task_pool);
-
- BLI_task_pool_free(task_pool);
-
- psys_tasks_free(tasks_parent, numtasks_parent);
- psys_tasks_free(tasks_child, numtasks_child);
-
- psys_thread_context_free(&ctx);
+ TaskScheduler *task_scheduler;
+ TaskPool *task_pool;
+ ParticleThreadContext ctx;
+ ParticleTask *tasks_parent, *tasks_child;
+ int numtasks_parent, numtasks_child;
+ int i, totchild, totparent;
+
+ if (sim->psys->flag & PSYS_GLOBAL_HAIR)
+ return;
+
+ /* create a task pool for child path tasks */
+ if (!psys_thread_context_init_path(&ctx, sim, sim->scene, cfra, editupdate, use_render_params))
+ return;
+
+ task_scheduler = BLI_task_scheduler_get();
+ task_pool = BLI_task_pool_create(task_scheduler, &ctx);
+ totchild = ctx.totchild;
+ totparent = ctx.totparent;
+
+ if (editupdate && sim->psys->childcache && totchild == sim->psys->totchildcache) {
+ /* just overwrite the existing cache */
+ }
+ else {
+ /* clear out old and create new empty path cache */
+ free_child_path_cache(sim->psys);
+
+ sim->psys->childcache = psys_alloc_path_cache_buffers(
+ &sim->psys->childcachebufs, totchild, ctx.segments + ctx.extra_segments + 1);
+ sim->psys->totchildcache = totchild;
+ }
+
+ /* cache parent paths */
+ ctx.parent_pass = 1;
+ psys_tasks_create(&ctx, 0, totparent, &tasks_parent, &numtasks_parent);
+ for (i = 0; i < numtasks_parent; ++i) {
+ ParticleTask *task = &tasks_parent[i];
+
+ psys_task_init_path(task, sim);
+ BLI_task_pool_push(task_pool, exec_child_path_cache, task, false, TASK_PRIORITY_LOW);
+ }
+ BLI_task_pool_work_and_wait(task_pool);
+
+ /* cache child paths */
+ ctx.parent_pass = 0;
+ psys_tasks_create(&ctx, totparent, totchild, &tasks_child, &numtasks_child);
+ for (i = 0; i < numtasks_child; ++i) {
+ ParticleTask *task = &tasks_child[i];
+
+ psys_task_init_path(task, sim);
+ BLI_task_pool_push(task_pool, exec_child_path_cache, task, false, TASK_PRIORITY_LOW);
+ }
+ BLI_task_pool_work_and_wait(task_pool);
+
+ BLI_task_pool_free(task_pool);
+
+ psys_tasks_free(tasks_parent, numtasks_parent);
+ psys_tasks_free(tasks_child, numtasks_child);
+
+ psys_thread_context_free(&ctx);
}
/* figure out incremental rotations along path starting from unit quat */
-static void cache_key_incremental_rotation(ParticleCacheKey *key0, ParticleCacheKey *key1, ParticleCacheKey *key2, float *prev_tangent, int i)
+static void cache_key_incremental_rotation(ParticleCacheKey *key0,
+ ParticleCacheKey *key1,
+ ParticleCacheKey *key2,
+ float *prev_tangent,
+ int i)
{
- float cosangle, angle, tangent[3], normal[3], q[4];
-
- switch (i) {
- case 0:
- /* start from second key */
- break;
- case 1:
- /* calculate initial tangent for incremental rotations */
- sub_v3_v3v3(prev_tangent, key0->co, key1->co);
- normalize_v3(prev_tangent);
- unit_qt(key1->rot);
- break;
- default:
- sub_v3_v3v3(tangent, key0->co, key1->co);
- normalize_v3(tangent);
-
- cosangle = dot_v3v3(tangent, prev_tangent);
-
- /* note we do the comparison on cosangle instead of
- * angle, since floating point accuracy makes it give
- * different results across platforms */
- if (cosangle > 0.999999f) {
- copy_v4_v4(key1->rot, key2->rot);
- }
- else {
- angle = saacos(cosangle);
- cross_v3_v3v3(normal, prev_tangent, tangent);
- axis_angle_to_quat(q, normal, angle);
- mul_qt_qtqt(key1->rot, q, key2->rot);
- }
-
- copy_v3_v3(prev_tangent, tangent);
- }
+ float cosangle, angle, tangent[3], normal[3], q[4];
+
+ switch (i) {
+ case 0:
+ /* start from second key */
+ break;
+ case 1:
+ /* calculate initial tangent for incremental rotations */
+ sub_v3_v3v3(prev_tangent, key0->co, key1->co);
+ normalize_v3(prev_tangent);
+ unit_qt(key1->rot);
+ break;
+ default:
+ sub_v3_v3v3(tangent, key0->co, key1->co);
+ normalize_v3(tangent);
+
+ cosangle = dot_v3v3(tangent, prev_tangent);
+
+ /* note we do the comparison on cosangle instead of
+ * angle, since floating point accuracy makes it give
+ * different results across platforms */
+ if (cosangle > 0.999999f) {
+ copy_v4_v4(key1->rot, key2->rot);
+ }
+ else {
+ angle = saacos(cosangle);
+ cross_v3_v3v3(normal, prev_tangent, tangent);
+ axis_angle_to_quat(q, normal, angle);
+ mul_qt_qtqt(key1->rot, q, key2->rot);
+ }
+
+ copy_v3_v3(prev_tangent, tangent);
+ }
}
/**
@@ -2458,827 +2712,854 @@ static void cache_key_incremental_rotation(ParticleCacheKey *key0, ParticleCache
* - Cached path data is also used to determine cut position for the editmode tool. */
void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_render_params)
{
- PARTICLE_PSMD;
- ParticleEditSettings *pset = &sim->scene->toolsettings->particle;
- ParticleSystem *psys = sim->psys;
- ParticleSettings *part = psys->part;
- ParticleCacheKey *ca, **cache;
-
- Mesh *hair_mesh = (psys->part->type == PART_HAIR && psys->flag & PSYS_HAIR_DYNAMICS) ? psys->hair_out_mesh : NULL;
-
- ParticleKey result;
-
- Material *ma;
- ParticleInterpolationData pind;
- ParticleTexture ptex;
-
- PARTICLE_P;
-
- float birthtime = 0.0, dietime = 0.0;
- float t, time = 0.0, dfra = 1.0 /* , frs_sec = sim->scene->r.frs_sec*/ /*UNUSED*/;
- float col[4] = {0.5f, 0.5f, 0.5f, 1.0f};
- float prev_tangent[3] = {0.0f, 0.0f, 0.0f}, hairmat[4][4];
- float rotmat[3][3];
- int k;
- int segments = (int)pow(2.0, (double)((use_render_params) ? part->ren_step : part->draw_step));
- int totpart = psys->totpart;
- float length, vec[3];
- float *vg_effector = NULL;
- float *vg_length = NULL, pa_length = 1.0f;
- int keyed, baked;
-
- /* we don't have anything valid to create paths from so let's quit here */
- if ((psys->flag & PSYS_HAIR_DONE || psys->flag & PSYS_KEYED || psys->pointcache) == 0)
- return;
-
- if (psys_in_edit_mode(sim->depsgraph, psys))
- if ((psys->edit == NULL || pset->flag & PE_DRAW_PART) == 0)
- return;
-
- keyed = psys->flag & PSYS_KEYED;
- baked = psys->pointcache->mem_cache.first && psys->part->type != PART_HAIR;
-
- /* clear out old and create new empty path cache */
- psys_free_path_cache(psys, psys->edit);
- cache = psys->pathcache = psys_alloc_path_cache_buffers(&psys->pathcachebufs, totpart, segments + 1);
-
- psys->lattice_deform_data = psys_create_lattice_deform_data(sim);
- ma = give_current_material(sim->ob, psys->part->omat);
- if (ma && (psys->part->draw_col == PART_DRAW_COL_MAT))
- copy_v3_v3(col, &ma->r);
-
- if ((psys->flag & PSYS_GLOBAL_HAIR) == 0) {
- if ((psys->part->flag & PART_CHILD_EFFECT) == 0)
- vg_effector = psys_cache_vgroup(psmd->mesh_final, psys, PSYS_VG_EFFECTOR);
-
- if (!psys->totchild)
- vg_length = psys_cache_vgroup(psmd->mesh_final, psys, PSYS_VG_LENGTH);
- }
-
- /* ensure we have tessfaces to be used for mapping */
- if (part->from != PART_FROM_VERT) {
- BKE_mesh_tessface_ensure(psmd->mesh_final);
- }
-
- /*---first main loop: create all actual particles' paths---*/
- LOOP_PARTICLES {
- if (!psys->totchild) {
- psys_get_texture(sim, pa, &ptex, PAMAP_LENGTH, 0.f);
- pa_length = ptex.length * (1.0f - part->randlength * psys_frand(psys, psys->seed + p));
- if (vg_length)
- pa_length *= psys_particle_value_from_verts(psmd->mesh_final, part->from, pa, vg_length);
- }
-
- pind.keyed = keyed;
- pind.cache = baked ? psys->pointcache : NULL;
- pind.epoint = NULL;
- pind.bspline = (psys->part->flag & PART_HAIR_BSPLINE);
- pind.mesh = hair_mesh;
-
- memset(cache[p], 0, sizeof(*cache[p]) * (segments + 1));
-
- cache[p]->segments = segments;
-
- /*--get the first data points--*/
- init_particle_interpolation(sim->ob, sim->psys, pa, &pind);
-
- /* hairmat is needed for for non-hair particle too so we get proper rotations */
- psys_mat_hair_to_global(sim->ob, psmd->mesh_final, psys->part->from, pa, hairmat);
- copy_v3_v3(rotmat[0], hairmat[2]);
- copy_v3_v3(rotmat[1], hairmat[1]);
- copy_v3_v3(rotmat[2], hairmat[0]);
-
- if (part->draw & PART_ABS_PATH_TIME) {
- birthtime = MAX2(pind.birthtime, part->path_start);
- dietime = MIN2(pind.dietime, part->path_end);
- }
- else {
- float tb = pind.birthtime;
- birthtime = tb + part->path_start * (pind.dietime - tb);
- dietime = tb + part->path_end * (pind.dietime - tb);
- }
-
- if (birthtime >= dietime) {
- cache[p]->segments = -1;
- continue;
- }
-
- dietime = birthtime + pa_length * (dietime - birthtime);
-
- /*--interpolate actual path from data points--*/
- for (k = 0, ca = cache[p]; k <= segments; k++, ca++) {
- time = (float)k / (float)segments;
- t = birthtime + time * (dietime - birthtime);
- result.time = -t;
- do_particle_interpolation(psys, p, pa, t, &pind, &result);
- copy_v3_v3(ca->co, result.co);
-
- /* dynamic hair is in object space */
- /* keyed and baked are already in global space */
- if (hair_mesh)
- mul_m4_v3(sim->ob->obmat, ca->co);
- else if (!keyed && !baked && !(psys->flag & PSYS_GLOBAL_HAIR))
- mul_m4_v3(hairmat, ca->co);
-
- copy_v3_v3(ca->col, col);
- }
-
- if (part->type == PART_HAIR) {
- HairKey *hkey;
-
- for (k = 0, hkey = pa->hair; k < pa->totkey; ++k, ++hkey) {
- mul_v3_m4v3(hkey->world_co, hairmat, hkey->co);
- }
- }
-
- /*--modify paths and calculate rotation & velocity--*/
-
- if (!(psys->flag & PSYS_GLOBAL_HAIR)) {
- /* apply effectors */
- if ((psys->part->flag & PART_CHILD_EFFECT) == 0) {
- float effector = 1.0f;
- if (vg_effector)
- effector *= psys_particle_value_from_verts(psmd->mesh_final, psys->part->from, pa, vg_effector);
-
- sub_v3_v3v3(vec, (cache[p] + 1)->co, cache[p]->co);
- length = len_v3(vec);
-
- for (k = 1, ca = cache[p] + 1; k <= segments; k++, ca++)
- do_path_effectors(sim, p, ca, k, segments, cache[p]->co, effector, dfra, cfra, &length, vec);
- }
-
- /* apply guide curves to path data */
- if (sim->psys->effectors && (psys->part->flag & PART_CHILD_EFFECT) == 0) {
- for (k = 0, ca = cache[p]; k <= segments; k++, ca++)
- /* ca is safe to cast, since only co and vel are used */
- do_guides(sim->depsgraph, sim->psys->part, sim->psys->effectors, (ParticleKey *)ca, p, (float)k / (float)segments);
- }
-
- /* lattices have to be calculated separately to avoid mixups between effector calculations */
- if (psys->lattice_deform_data) {
- for (k = 0, ca = cache[p]; k <= segments; k++, ca++)
- calc_latt_deform(psys->lattice_deform_data, ca->co, psys->lattice_strength);
- }
- }
-
- /* finally do rotation & velocity */
- for (k = 1, ca = cache[p] + 1; k <= segments; k++, ca++) {
- cache_key_incremental_rotation(ca, ca - 1, ca - 2, prev_tangent, k);
-
- if (k == segments)
- copy_qt_qt(ca->rot, (ca - 1)->rot);
-
- /* set velocity */
- sub_v3_v3v3(ca->vel, ca->co, (ca - 1)->co);
-
- if (k == 1)
- copy_v3_v3((ca - 1)->vel, ca->vel);
-
- ca->time = (float)k / (float)segments;
- }
- /* First rotation is based on emitting face orientation.
- * This is way better than having flipping rotations resulting
- * from using a global axis as a rotation pole (vec_to_quat()).
- * It's not an ideal solution though since it disregards the
- * initial tangent, but taking that in to account will allow
- * the possibility of flipping again. -jahka
- */
- mat3_to_quat_is_ok(cache[p]->rot, rotmat);
- }
-
- psys->totcached = totpart;
-
- if (psys->lattice_deform_data) {
- end_latt_deform(psys->lattice_deform_data);
- psys->lattice_deform_data = NULL;
- }
-
- if (vg_effector)
- MEM_freeN(vg_effector);
-
- if (vg_length)
- MEM_freeN(vg_length);
+ PARTICLE_PSMD;
+ ParticleEditSettings *pset = &sim->scene->toolsettings->particle;
+ ParticleSystem *psys = sim->psys;
+ ParticleSettings *part = psys->part;
+ ParticleCacheKey *ca, **cache;
+
+ Mesh *hair_mesh = (psys->part->type == PART_HAIR && psys->flag & PSYS_HAIR_DYNAMICS) ?
+ psys->hair_out_mesh :
+ NULL;
+
+ ParticleKey result;
+
+ Material *ma;
+ ParticleInterpolationData pind;
+ ParticleTexture ptex;
+
+ PARTICLE_P;
+
+ float birthtime = 0.0, dietime = 0.0;
+ float t, time = 0.0, dfra = 1.0 /* , frs_sec = sim->scene->r.frs_sec*/ /*UNUSED*/;
+ float col[4] = {0.5f, 0.5f, 0.5f, 1.0f};
+ float prev_tangent[3] = {0.0f, 0.0f, 0.0f}, hairmat[4][4];
+ float rotmat[3][3];
+ int k;
+ int segments = (int)pow(2.0, (double)((use_render_params) ? part->ren_step : part->draw_step));
+ int totpart = psys->totpart;
+ float length, vec[3];
+ float *vg_effector = NULL;
+ float *vg_length = NULL, pa_length = 1.0f;
+ int keyed, baked;
+
+ /* we don't have anything valid to create paths from so let's quit here */
+ if ((psys->flag & PSYS_HAIR_DONE || psys->flag & PSYS_KEYED || psys->pointcache) == 0)
+ return;
+
+ if (psys_in_edit_mode(sim->depsgraph, psys))
+ if ((psys->edit == NULL || pset->flag & PE_DRAW_PART) == 0)
+ return;
+
+ keyed = psys->flag & PSYS_KEYED;
+ baked = psys->pointcache->mem_cache.first && psys->part->type != PART_HAIR;
+
+ /* clear out old and create new empty path cache */
+ psys_free_path_cache(psys, psys->edit);
+ cache = psys->pathcache = psys_alloc_path_cache_buffers(
+ &psys->pathcachebufs, totpart, segments + 1);
+
+ psys->lattice_deform_data = psys_create_lattice_deform_data(sim);
+ ma = give_current_material(sim->ob, psys->part->omat);
+ if (ma && (psys->part->draw_col == PART_DRAW_COL_MAT))
+ copy_v3_v3(col, &ma->r);
+
+ if ((psys->flag & PSYS_GLOBAL_HAIR) == 0) {
+ if ((psys->part->flag & PART_CHILD_EFFECT) == 0)
+ vg_effector = psys_cache_vgroup(psmd->mesh_final, psys, PSYS_VG_EFFECTOR);
+
+ if (!psys->totchild)
+ vg_length = psys_cache_vgroup(psmd->mesh_final, psys, PSYS_VG_LENGTH);
+ }
+
+ /* ensure we have tessfaces to be used for mapping */
+ if (part->from != PART_FROM_VERT) {
+ BKE_mesh_tessface_ensure(psmd->mesh_final);
+ }
+
+ /*---first main loop: create all actual particles' paths---*/
+ LOOP_PARTICLES
+ {
+ if (!psys->totchild) {
+ psys_get_texture(sim, pa, &ptex, PAMAP_LENGTH, 0.f);
+ pa_length = ptex.length * (1.0f - part->randlength * psys_frand(psys, psys->seed + p));
+ if (vg_length)
+ pa_length *= psys_particle_value_from_verts(psmd->mesh_final, part->from, pa, vg_length);
+ }
+
+ pind.keyed = keyed;
+ pind.cache = baked ? psys->pointcache : NULL;
+ pind.epoint = NULL;
+ pind.bspline = (psys->part->flag & PART_HAIR_BSPLINE);
+ pind.mesh = hair_mesh;
+
+ memset(cache[p], 0, sizeof(*cache[p]) * (segments + 1));
+
+ cache[p]->segments = segments;
+
+ /*--get the first data points--*/
+ init_particle_interpolation(sim->ob, sim->psys, pa, &pind);
+
+ /* hairmat is needed for for non-hair particle too so we get proper rotations */
+ psys_mat_hair_to_global(sim->ob, psmd->mesh_final, psys->part->from, pa, hairmat);
+ copy_v3_v3(rotmat[0], hairmat[2]);
+ copy_v3_v3(rotmat[1], hairmat[1]);
+ copy_v3_v3(rotmat[2], hairmat[0]);
+
+ if (part->draw & PART_ABS_PATH_TIME) {
+ birthtime = MAX2(pind.birthtime, part->path_start);
+ dietime = MIN2(pind.dietime, part->path_end);
+ }
+ else {
+ float tb = pind.birthtime;
+ birthtime = tb + part->path_start * (pind.dietime - tb);
+ dietime = tb + part->path_end * (pind.dietime - tb);
+ }
+
+ if (birthtime >= dietime) {
+ cache[p]->segments = -1;
+ continue;
+ }
+
+ dietime = birthtime + pa_length * (dietime - birthtime);
+
+ /*--interpolate actual path from data points--*/
+ for (k = 0, ca = cache[p]; k <= segments; k++, ca++) {
+ time = (float)k / (float)segments;
+ t = birthtime + time * (dietime - birthtime);
+ result.time = -t;
+ do_particle_interpolation(psys, p, pa, t, &pind, &result);
+ copy_v3_v3(ca->co, result.co);
+
+ /* dynamic hair is in object space */
+ /* keyed and baked are already in global space */
+ if (hair_mesh)
+ mul_m4_v3(sim->ob->obmat, ca->co);
+ else if (!keyed && !baked && !(psys->flag & PSYS_GLOBAL_HAIR))
+ mul_m4_v3(hairmat, ca->co);
+
+ copy_v3_v3(ca->col, col);
+ }
+
+ if (part->type == PART_HAIR) {
+ HairKey *hkey;
+
+ for (k = 0, hkey = pa->hair; k < pa->totkey; ++k, ++hkey) {
+ mul_v3_m4v3(hkey->world_co, hairmat, hkey->co);
+ }
+ }
+
+ /*--modify paths and calculate rotation & velocity--*/
+
+ if (!(psys->flag & PSYS_GLOBAL_HAIR)) {
+ /* apply effectors */
+ if ((psys->part->flag & PART_CHILD_EFFECT) == 0) {
+ float effector = 1.0f;
+ if (vg_effector)
+ effector *= psys_particle_value_from_verts(
+ psmd->mesh_final, psys->part->from, pa, vg_effector);
+
+ sub_v3_v3v3(vec, (cache[p] + 1)->co, cache[p]->co);
+ length = len_v3(vec);
+
+ for (k = 1, ca = cache[p] + 1; k <= segments; k++, ca++)
+ do_path_effectors(
+ sim, p, ca, k, segments, cache[p]->co, effector, dfra, cfra, &length, vec);
+ }
+
+ /* apply guide curves to path data */
+ if (sim->psys->effectors && (psys->part->flag & PART_CHILD_EFFECT) == 0) {
+ for (k = 0, ca = cache[p]; k <= segments; k++, ca++)
+ /* ca is safe to cast, since only co and vel are used */
+ do_guides(sim->depsgraph,
+ sim->psys->part,
+ sim->psys->effectors,
+ (ParticleKey *)ca,
+ p,
+ (float)k / (float)segments);
+ }
+
+ /* lattices have to be calculated separately to avoid mixups between effector calculations */
+ if (psys->lattice_deform_data) {
+ for (k = 0, ca = cache[p]; k <= segments; k++, ca++)
+ calc_latt_deform(psys->lattice_deform_data, ca->co, psys->lattice_strength);
+ }
+ }
+
+ /* finally do rotation & velocity */
+ for (k = 1, ca = cache[p] + 1; k <= segments; k++, ca++) {
+ cache_key_incremental_rotation(ca, ca - 1, ca - 2, prev_tangent, k);
+
+ if (k == segments)
+ copy_qt_qt(ca->rot, (ca - 1)->rot);
+
+ /* set velocity */
+ sub_v3_v3v3(ca->vel, ca->co, (ca - 1)->co);
+
+ if (k == 1)
+ copy_v3_v3((ca - 1)->vel, ca->vel);
+
+ ca->time = (float)k / (float)segments;
+ }
+ /* First rotation is based on emitting face orientation.
+ * This is way better than having flipping rotations resulting
+ * from using a global axis as a rotation pole (vec_to_quat()).
+ * It's not an ideal solution though since it disregards the
+ * initial tangent, but taking that in to account will allow
+ * the possibility of flipping again. -jahka
+ */
+ mat3_to_quat_is_ok(cache[p]->rot, rotmat);
+ }
+
+ psys->totcached = totpart;
+
+ if (psys->lattice_deform_data) {
+ end_latt_deform(psys->lattice_deform_data);
+ psys->lattice_deform_data = NULL;
+ }
+
+ if (vg_effector)
+ MEM_freeN(vg_effector);
+
+ if (vg_length)
+ MEM_freeN(vg_length);
}
typedef struct CacheEditrPathsIterData {
- Object *object;
- PTCacheEdit *edit;
- ParticleSystemModifierData *psmd;
- ParticleData *pa;
- int segments;
- bool use_weight;
- float sel_col[3];
- float nosel_col[3];
+ Object *object;
+ PTCacheEdit *edit;
+ ParticleSystemModifierData *psmd;
+ ParticleData *pa;
+ int segments;
+ bool use_weight;
+ float sel_col[3];
+ float nosel_col[3];
} CacheEditrPathsIterData;
-static void psys_cache_edit_paths_iter(
- void *__restrict iter_data_v,
- const int iter,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void psys_cache_edit_paths_iter(void *__restrict iter_data_v,
+ const int iter,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- CacheEditrPathsIterData *iter_data = (CacheEditrPathsIterData *)iter_data_v;
- PTCacheEdit *edit = iter_data->edit;
- PTCacheEditPoint *point = &edit->points[iter];
- if (edit->totcached && !(point->flag & PEP_EDIT_RECALC)) {
- return;
- }
- if (point->totkey == 0) {
- return;
- }
- Object *ob = iter_data->object;
- ParticleSystem *psys = edit->psys;
- ParticleCacheKey **cache = edit->pathcache;
- ParticleSystemModifierData *psmd = iter_data->psmd;
- ParticleData *pa = iter_data->pa ? iter_data->pa + iter : NULL;
- PTCacheEditKey *ekey = point->keys;
- const int segments = iter_data->segments;
- const bool use_weight = iter_data->use_weight;
-
- float birthtime = 0.0f, dietime = 0.0f;
- float hairmat[4][4], rotmat[3][3], prev_tangent[3] = {0.0f, 0.0f, 0.0f};
-
- ParticleInterpolationData pind;
- pind.keyed = 0;
- pind.cache = NULL;
- pind.epoint = point;
- pind.bspline = psys ? (psys->part->flag & PART_HAIR_BSPLINE) : 0;
- pind.mesh = NULL;
-
- /* should init_particle_interpolation set this ? */
- if (use_weight) {
- pind.hkey[0] = NULL;
- /* pa != NULL since the weight brush is only available for hair */
- pind.hkey[0] = pa->hair;
- pind.hkey[1] = pa->hair + 1;
- }
-
- memset(cache[iter], 0, sizeof(*cache[iter]) * (segments + 1));
-
- cache[iter]->segments = segments;
-
- /*--get the first data points--*/
- init_particle_interpolation(ob, psys, pa, &pind);
-
- if (psys) {
- psys_mat_hair_to_global(ob, psmd->mesh_final, psys->part->from, pa, hairmat);
- copy_v3_v3(rotmat[0], hairmat[2]);
- copy_v3_v3(rotmat[1], hairmat[1]);
- copy_v3_v3(rotmat[2], hairmat[0]);
- }
-
- birthtime = pind.birthtime;
- dietime = pind.dietime;
-
- if (birthtime >= dietime) {
- cache[iter]->segments = -1;
- return;
- }
-
- /*--interpolate actual path from data points--*/
- ParticleCacheKey *ca;
- int k;
- float t, time = 0.0f, keytime = 0.0f;
- for (k = 0, ca = cache[iter]; k <= segments; k++, ca++) {
- time = (float)k / (float)segments;
- t = birthtime + time * (dietime - birthtime);
- ParticleKey result;
- result.time = -t;
- do_particle_interpolation(psys, iter, pa, t, &pind, &result);
- copy_v3_v3(ca->co, result.co);
-
- /* non-hair points are already in global space */
- if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
- mul_m4_v3(hairmat, ca->co);
-
- if (k) {
- cache_key_incremental_rotation(ca, ca - 1, ca - 2, prev_tangent, k);
-
- if (k == segments)
- copy_qt_qt(ca->rot, (ca - 1)->rot);
-
- /* set velocity */
- sub_v3_v3v3(ca->vel, ca->co, (ca - 1)->co);
-
- if (k == 1)
- copy_v3_v3((ca - 1)->vel, ca->vel);
- }
- }
- else {
- ca->vel[0] = ca->vel[1] = 0.0f;
- ca->vel[2] = 1.0f;
- }
-
- /* selection coloring in edit mode */
- if (use_weight) {
- if (k == 0) {
- BKE_defvert_weight_to_rgb(ca->col, pind.hkey[1]->weight);
- }
- else {
- /* warning: copied from 'do_particle_interpolation' (without 'mvert' array stepping) */
- float real_t;
- if (result.time < 0.0f) {
- real_t = -result.time;
- }
- else {
- real_t = pind.hkey[0]->time + t * (pind.hkey[0][pa->totkey - 1].time - pind.hkey[0]->time);
- }
-
- while (pind.hkey[1]->time < real_t) {
- pind.hkey[1]++;
- }
- pind.hkey[0] = pind.hkey[1] - 1;
- /* end copy */
-
-
- float w1[3], w2[3];
- keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time));
-
- BKE_defvert_weight_to_rgb(w1, pind.hkey[0]->weight);
- BKE_defvert_weight_to_rgb(w2, pind.hkey[1]->weight);
-
- interp_v3_v3v3(ca->col, w1, w2, keytime);
- }
- }
- else {
- if ((ekey + (pind.ekey[0] - point->keys))->flag & PEK_SELECT) {
- if ((ekey + (pind.ekey[1] - point->keys))->flag & PEK_SELECT) {
- copy_v3_v3(ca->col, iter_data->sel_col);
- }
- else {
- keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time));
- interp_v3_v3v3(ca->col, iter_data->sel_col, iter_data->nosel_col, keytime);
- }
- }
- else {
- if ((ekey + (pind.ekey[1] - point->keys))->flag & PEK_SELECT) {
- keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time));
- interp_v3_v3v3(ca->col, iter_data->nosel_col, iter_data->sel_col, keytime);
- }
- else {
- copy_v3_v3(ca->col, iter_data->nosel_col);
- }
- }
- }
-
- ca->time = t;
- }
- if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
- /* First rotation is based on emitting face orientation.
- * This is way better than having flipping rotations resulting
- * from using a global axis as a rotation pole (vec_to_quat()).
- * It's not an ideal solution though since it disregards the
- * initial tangent, but taking that in to account will allow
- * the possibility of flipping again. -jahka
- */
- mat3_to_quat_is_ok(cache[iter]->rot, rotmat);
- }
+ CacheEditrPathsIterData *iter_data = (CacheEditrPathsIterData *)iter_data_v;
+ PTCacheEdit *edit = iter_data->edit;
+ PTCacheEditPoint *point = &edit->points[iter];
+ if (edit->totcached && !(point->flag & PEP_EDIT_RECALC)) {
+ return;
+ }
+ if (point->totkey == 0) {
+ return;
+ }
+ Object *ob = iter_data->object;
+ ParticleSystem *psys = edit->psys;
+ ParticleCacheKey **cache = edit->pathcache;
+ ParticleSystemModifierData *psmd = iter_data->psmd;
+ ParticleData *pa = iter_data->pa ? iter_data->pa + iter : NULL;
+ PTCacheEditKey *ekey = point->keys;
+ const int segments = iter_data->segments;
+ const bool use_weight = iter_data->use_weight;
+
+ float birthtime = 0.0f, dietime = 0.0f;
+ float hairmat[4][4], rotmat[3][3], prev_tangent[3] = {0.0f, 0.0f, 0.0f};
+
+ ParticleInterpolationData pind;
+ pind.keyed = 0;
+ pind.cache = NULL;
+ pind.epoint = point;
+ pind.bspline = psys ? (psys->part->flag & PART_HAIR_BSPLINE) : 0;
+ pind.mesh = NULL;
+
+ /* should init_particle_interpolation set this ? */
+ if (use_weight) {
+ pind.hkey[0] = NULL;
+ /* pa != NULL since the weight brush is only available for hair */
+ pind.hkey[0] = pa->hair;
+ pind.hkey[1] = pa->hair + 1;
+ }
+
+ memset(cache[iter], 0, sizeof(*cache[iter]) * (segments + 1));
+
+ cache[iter]->segments = segments;
+
+ /*--get the first data points--*/
+ init_particle_interpolation(ob, psys, pa, &pind);
+
+ if (psys) {
+ psys_mat_hair_to_global(ob, psmd->mesh_final, psys->part->from, pa, hairmat);
+ copy_v3_v3(rotmat[0], hairmat[2]);
+ copy_v3_v3(rotmat[1], hairmat[1]);
+ copy_v3_v3(rotmat[2], hairmat[0]);
+ }
+
+ birthtime = pind.birthtime;
+ dietime = pind.dietime;
+
+ if (birthtime >= dietime) {
+ cache[iter]->segments = -1;
+ return;
+ }
+
+ /*--interpolate actual path from data points--*/
+ ParticleCacheKey *ca;
+ int k;
+ float t, time = 0.0f, keytime = 0.0f;
+ for (k = 0, ca = cache[iter]; k <= segments; k++, ca++) {
+ time = (float)k / (float)segments;
+ t = birthtime + time * (dietime - birthtime);
+ ParticleKey result;
+ result.time = -t;
+ do_particle_interpolation(psys, iter, pa, t, &pind, &result);
+ copy_v3_v3(ca->co, result.co);
+
+ /* non-hair points are already in global space */
+ if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
+ mul_m4_v3(hairmat, ca->co);
+
+ if (k) {
+ cache_key_incremental_rotation(ca, ca - 1, ca - 2, prev_tangent, k);
+
+ if (k == segments)
+ copy_qt_qt(ca->rot, (ca - 1)->rot);
+
+ /* set velocity */
+ sub_v3_v3v3(ca->vel, ca->co, (ca - 1)->co);
+
+ if (k == 1)
+ copy_v3_v3((ca - 1)->vel, ca->vel);
+ }
+ }
+ else {
+ ca->vel[0] = ca->vel[1] = 0.0f;
+ ca->vel[2] = 1.0f;
+ }
+
+ /* selection coloring in edit mode */
+ if (use_weight) {
+ if (k == 0) {
+ BKE_defvert_weight_to_rgb(ca->col, pind.hkey[1]->weight);
+ }
+ else {
+ /* warning: copied from 'do_particle_interpolation' (without 'mvert' array stepping) */
+ float real_t;
+ if (result.time < 0.0f) {
+ real_t = -result.time;
+ }
+ else {
+ real_t = pind.hkey[0]->time +
+ t * (pind.hkey[0][pa->totkey - 1].time - pind.hkey[0]->time);
+ }
+
+ while (pind.hkey[1]->time < real_t) {
+ pind.hkey[1]++;
+ }
+ pind.hkey[0] = pind.hkey[1] - 1;
+ /* end copy */
+
+ float w1[3], w2[3];
+ keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time));
+
+ BKE_defvert_weight_to_rgb(w1, pind.hkey[0]->weight);
+ BKE_defvert_weight_to_rgb(w2, pind.hkey[1]->weight);
+
+ interp_v3_v3v3(ca->col, w1, w2, keytime);
+ }
+ }
+ else {
+ if ((ekey + (pind.ekey[0] - point->keys))->flag & PEK_SELECT) {
+ if ((ekey + (pind.ekey[1] - point->keys))->flag & PEK_SELECT) {
+ copy_v3_v3(ca->col, iter_data->sel_col);
+ }
+ else {
+ keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time));
+ interp_v3_v3v3(ca->col, iter_data->sel_col, iter_data->nosel_col, keytime);
+ }
+ }
+ else {
+ if ((ekey + (pind.ekey[1] - point->keys))->flag & PEK_SELECT) {
+ keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time));
+ interp_v3_v3v3(ca->col, iter_data->nosel_col, iter_data->sel_col, keytime);
+ }
+ else {
+ copy_v3_v3(ca->col, iter_data->nosel_col);
+ }
+ }
+ }
+
+ ca->time = t;
+ }
+ if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
+ /* First rotation is based on emitting face orientation.
+ * This is way better than having flipping rotations resulting
+ * from using a global axis as a rotation pole (vec_to_quat()).
+ * It's not an ideal solution though since it disregards the
+ * initial tangent, but taking that in to account will allow
+ * the possibility of flipping again. -jahka
+ */
+ mat3_to_quat_is_ok(cache[iter]->rot, rotmat);
+ }
}
-void psys_cache_edit_paths(Depsgraph *depsgraph, Scene *scene, Object *ob, PTCacheEdit *edit, float cfra, const bool use_render_params)
+void psys_cache_edit_paths(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ PTCacheEdit *edit,
+ float cfra,
+ const bool use_render_params)
{
- ParticleCacheKey **cache = edit->pathcache;
- ParticleEditSettings *pset = &scene->toolsettings->particle;
-
- ParticleSystem *psys = edit->psys;
-
- ParticleData *pa = psys ? psys->particles : NULL;
-
- int segments = 1 << pset->draw_step;
- int totpart = edit->totpoint, recalc_set = 0;
-
- segments = MAX2(segments, 4);
-
- if (!cache || edit->totpoint != edit->totcached) {
- /* Clear out old and create new empty path cache. */
- psys_free_path_cache(edit->psys, edit);
- cache = edit->pathcache = psys_alloc_path_cache_buffers(&edit->pathcachebufs, totpart, segments + 1);
- /* Set flag for update (child particles check this too). */
- int i;
- PTCacheEditPoint *point;
- for (i = 0, point = edit->points; i < totpart; i++, point++) {
- point->flag |= PEP_EDIT_RECALC;
- }
- recalc_set = 1;
- }
-
- const bool use_weight = (pset->brushtype == PE_BRUSH_WEIGHT) && (psys != NULL) && (psys->particles != NULL);
-
- CacheEditrPathsIterData iter_data;
- iter_data.object = ob;
- iter_data.edit = edit;
- iter_data.psmd = edit->psmd_eval;
- iter_data.pa = pa;
- iter_data.segments = segments;
- iter_data.use_weight = use_weight;
-
- if (use_weight) {
- ; /* use weight painting colors now... */
- }
- else {
- iter_data.sel_col[0] = (float)edit->sel_col[0] / 255.0f;
- iter_data.sel_col[1] = (float)edit->sel_col[1] / 255.0f;
- iter_data.sel_col[2] = (float)edit->sel_col[2] / 255.0f;
- iter_data.nosel_col[0] = (float)edit->nosel_col[0] / 255.0f;
- iter_data.nosel_col[1] = (float)edit->nosel_col[1] / 255.0f;
- iter_data.nosel_col[2] = (float)edit->nosel_col[2] / 255.0f;
- }
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
- BLI_task_parallel_range(0, edit->totpoint, &iter_data, psys_cache_edit_paths_iter, &settings);
-
- edit->totcached = totpart;
-
- if (psys) {
- ParticleSimulationData sim = {0};
- sim.depsgraph = depsgraph;
- sim.scene = scene;
- sim.ob = ob;
- sim.psys = psys;
- sim.psmd = edit->psmd_eval;
-
- psys_cache_child_paths(&sim, cfra, true, use_render_params);
- }
-
- /* clear recalc flag if set here */
- if (recalc_set) {
- PTCacheEditPoint *point;
- int i;
- for (i = 0, point = edit->points; i < totpart; i++, point++) {
- point->flag &= ~PEP_EDIT_RECALC;
- }
- }
+ ParticleCacheKey **cache = edit->pathcache;
+ ParticleEditSettings *pset = &scene->toolsettings->particle;
+
+ ParticleSystem *psys = edit->psys;
+
+ ParticleData *pa = psys ? psys->particles : NULL;
+
+ int segments = 1 << pset->draw_step;
+ int totpart = edit->totpoint, recalc_set = 0;
+
+ segments = MAX2(segments, 4);
+
+ if (!cache || edit->totpoint != edit->totcached) {
+ /* Clear out old and create new empty path cache. */
+ psys_free_path_cache(edit->psys, edit);
+ cache = edit->pathcache = psys_alloc_path_cache_buffers(
+ &edit->pathcachebufs, totpart, segments + 1);
+ /* Set flag for update (child particles check this too). */
+ int i;
+ PTCacheEditPoint *point;
+ for (i = 0, point = edit->points; i < totpart; i++, point++) {
+ point->flag |= PEP_EDIT_RECALC;
+ }
+ recalc_set = 1;
+ }
+
+ const bool use_weight = (pset->brushtype == PE_BRUSH_WEIGHT) && (psys != NULL) &&
+ (psys->particles != NULL);
+
+ CacheEditrPathsIterData iter_data;
+ iter_data.object = ob;
+ iter_data.edit = edit;
+ iter_data.psmd = edit->psmd_eval;
+ iter_data.pa = pa;
+ iter_data.segments = segments;
+ iter_data.use_weight = use_weight;
+
+ if (use_weight) {
+ ; /* use weight painting colors now... */
+ }
+ else {
+ iter_data.sel_col[0] = (float)edit->sel_col[0] / 255.0f;
+ iter_data.sel_col[1] = (float)edit->sel_col[1] / 255.0f;
+ iter_data.sel_col[2] = (float)edit->sel_col[2] / 255.0f;
+ iter_data.nosel_col[0] = (float)edit->nosel_col[0] / 255.0f;
+ iter_data.nosel_col[1] = (float)edit->nosel_col[1] / 255.0f;
+ iter_data.nosel_col[2] = (float)edit->nosel_col[2] / 255.0f;
+ }
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
+ BLI_task_parallel_range(0, edit->totpoint, &iter_data, psys_cache_edit_paths_iter, &settings);
+
+ edit->totcached = totpart;
+
+ if (psys) {
+ ParticleSimulationData sim = {0};
+ sim.depsgraph = depsgraph;
+ sim.scene = scene;
+ sim.ob = ob;
+ sim.psys = psys;
+ sim.psmd = edit->psmd_eval;
+
+ psys_cache_child_paths(&sim, cfra, true, use_render_params);
+ }
+
+ /* clear recalc flag if set here */
+ if (recalc_set) {
+ PTCacheEditPoint *point;
+ int i;
+ for (i = 0, point = edit->points; i < totpart; i++, point++) {
+ point->flag &= ~PEP_EDIT_RECALC;
+ }
+ }
}
/************************************************/
-/* Particle Key handling */
+/* Particle Key handling */
/************************************************/
void copy_particle_key(ParticleKey *to, ParticleKey *from, int time)
{
- if (time) {
- memcpy(to, from, sizeof(ParticleKey));
- }
- else {
- float to_time = to->time;
- memcpy(to, from, sizeof(ParticleKey));
- to->time = to_time;
- }
+ if (time) {
+ memcpy(to, from, sizeof(ParticleKey));
+ }
+ else {
+ float to_time = to->time;
+ memcpy(to, from, sizeof(ParticleKey));
+ to->time = to_time;
+ }
}
void psys_get_from_key(ParticleKey *key, float loc[3], float vel[3], float rot[4], float *time)
{
- if (loc) copy_v3_v3(loc, key->co);
- if (vel) copy_v3_v3(vel, key->vel);
- if (rot) copy_qt_qt(rot, key->rot);
- if (time) *time = key->time;
+ if (loc)
+ copy_v3_v3(loc, key->co);
+ if (vel)
+ copy_v3_v3(vel, key->vel);
+ if (rot)
+ copy_qt_qt(rot, key->rot);
+ if (time)
+ *time = key->time;
}
static void triatomat(float *v1, float *v2, float *v3, float (*uv)[2], float mat[4][4])
{
- float det, w1, w2, d1[2], d2[2];
-
- memset(mat, 0, sizeof(float) * 4 * 4);
- mat[3][3] = 1.0f;
-
- /* first axis is the normal */
- normal_tri_v3(mat[2], v1, v2, v3);
-
- /* second axis along (1, 0) in uv space */
- if (uv) {
- d1[0] = uv[1][0] - uv[0][0];
- d1[1] = uv[1][1] - uv[0][1];
- d2[0] = uv[2][0] - uv[0][0];
- d2[1] = uv[2][1] - uv[0][1];
-
- det = d2[0] * d1[1] - d2[1] * d1[0];
-
- if (det != 0.0f) {
- det = 1.0f / det;
- w1 = -d2[1] * det;
- w2 = d1[1] * det;
-
- mat[1][0] = w1 * (v2[0] - v1[0]) + w2 * (v3[0] - v1[0]);
- mat[1][1] = w1 * (v2[1] - v1[1]) + w2 * (v3[1] - v1[1]);
- mat[1][2] = w1 * (v2[2] - v1[2]) + w2 * (v3[2] - v1[2]);
- normalize_v3(mat[1]);
- }
- else
- mat[1][0] = mat[1][1] = mat[1][2] = 0.0f;
- }
- else {
- sub_v3_v3v3(mat[1], v2, v1);
- normalize_v3(mat[1]);
- }
-
- /* third as a cross product */
- cross_v3_v3v3(mat[0], mat[1], mat[2]);
+ float det, w1, w2, d1[2], d2[2];
+
+ memset(mat, 0, sizeof(float) * 4 * 4);
+ mat[3][3] = 1.0f;
+
+ /* first axis is the normal */
+ normal_tri_v3(mat[2], v1, v2, v3);
+
+ /* second axis along (1, 0) in uv space */
+ if (uv) {
+ d1[0] = uv[1][0] - uv[0][0];
+ d1[1] = uv[1][1] - uv[0][1];
+ d2[0] = uv[2][0] - uv[0][0];
+ d2[1] = uv[2][1] - uv[0][1];
+
+ det = d2[0] * d1[1] - d2[1] * d1[0];
+
+ if (det != 0.0f) {
+ det = 1.0f / det;
+ w1 = -d2[1] * det;
+ w2 = d1[1] * det;
+
+ mat[1][0] = w1 * (v2[0] - v1[0]) + w2 * (v3[0] - v1[0]);
+ mat[1][1] = w1 * (v2[1] - v1[1]) + w2 * (v3[1] - v1[1]);
+ mat[1][2] = w1 * (v2[2] - v1[2]) + w2 * (v3[2] - v1[2]);
+ normalize_v3(mat[1]);
+ }
+ else
+ mat[1][0] = mat[1][1] = mat[1][2] = 0.0f;
+ }
+ else {
+ sub_v3_v3v3(mat[1], v2, v1);
+ normalize_v3(mat[1]);
+ }
+
+ /* third as a cross product */
+ cross_v3_v3v3(mat[0], mat[1], mat[2]);
}
static void psys_face_mat(Object *ob, Mesh *mesh, ParticleData *pa, float mat[4][4], int orco)
{
- float v[3][3];
- MFace *mface;
- OrigSpaceFace *osface;
- float (*orcodata)[3];
-
- int i = (ELEM(pa->num_dmcache, DMCACHE_ISCHILD, DMCACHE_NOTFOUND)) ? pa->num : pa->num_dmcache;
- if (i == -1 || i >= mesh->totface) { unit_m4(mat); return; }
-
- mface = &mesh->mface[i];
- osface = CustomData_get(&mesh->fdata, i, CD_ORIGSPACE);
-
- if (orco && (orcodata = CustomData_get_layer(&mesh->vdata, CD_ORCO))) {
- copy_v3_v3(v[0], orcodata[mface->v1]);
- copy_v3_v3(v[1], orcodata[mface->v2]);
- copy_v3_v3(v[2], orcodata[mface->v3]);
-
- /* ugly hack to use non-transformed orcos, since only those
- * give symmetric results for mirroring in particle mode */
- if (CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX))
- BKE_mesh_orco_verts_transform(ob->data, v, 3, 1);
- }
- else {
- copy_v3_v3(v[0], mesh->mvert[mface->v1].co);
- copy_v3_v3(v[1], mesh->mvert[mface->v2].co);
- copy_v3_v3(v[2], mesh->mvert[mface->v3].co);
- }
-
- triatomat(v[0], v[1], v[2], (osface) ? osface->uv : NULL, mat);
+ float v[3][3];
+ MFace *mface;
+ OrigSpaceFace *osface;
+ float(*orcodata)[3];
+
+ int i = (ELEM(pa->num_dmcache, DMCACHE_ISCHILD, DMCACHE_NOTFOUND)) ? pa->num : pa->num_dmcache;
+ if (i == -1 || i >= mesh->totface) {
+ unit_m4(mat);
+ return;
+ }
+
+ mface = &mesh->mface[i];
+ osface = CustomData_get(&mesh->fdata, i, CD_ORIGSPACE);
+
+ if (orco && (orcodata = CustomData_get_layer(&mesh->vdata, CD_ORCO))) {
+ copy_v3_v3(v[0], orcodata[mface->v1]);
+ copy_v3_v3(v[1], orcodata[mface->v2]);
+ copy_v3_v3(v[2], orcodata[mface->v3]);
+
+ /* ugly hack to use non-transformed orcos, since only those
+ * give symmetric results for mirroring in particle mode */
+ if (CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX))
+ BKE_mesh_orco_verts_transform(ob->data, v, 3, 1);
+ }
+ else {
+ copy_v3_v3(v[0], mesh->mvert[mface->v1].co);
+ copy_v3_v3(v[1], mesh->mvert[mface->v2].co);
+ copy_v3_v3(v[2], mesh->mvert[mface->v3].co);
+ }
+
+ triatomat(v[0], v[1], v[2], (osface) ? osface->uv : NULL, mat);
}
-void psys_mat_hair_to_object(Object *UNUSED(ob), Mesh *mesh, short from, ParticleData *pa, float hairmat[4][4])
+void psys_mat_hair_to_object(
+ Object *UNUSED(ob), Mesh *mesh, short from, ParticleData *pa, float hairmat[4][4])
{
- float vec[3];
+ float vec[3];
- /* can happen when called from a different object's modifier */
- if (!mesh) {
- unit_m4(hairmat);
- return;
- }
+ /* can happen when called from a different object's modifier */
+ if (!mesh) {
+ unit_m4(hairmat);
+ return;
+ }
- psys_face_mat(0, mesh, pa, hairmat, 0);
- psys_particle_on_dm(mesh, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, vec, 0, 0, 0, 0);
- copy_v3_v3(hairmat[3], vec);
+ psys_face_mat(0, mesh, pa, hairmat, 0);
+ psys_particle_on_dm(mesh, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, vec, 0, 0, 0, 0);
+ copy_v3_v3(hairmat[3], vec);
}
-void psys_mat_hair_to_orco(Object *ob, Mesh *mesh, short from, ParticleData *pa, float hairmat[4][4])
+void psys_mat_hair_to_orco(
+ Object *ob, Mesh *mesh, short from, ParticleData *pa, float hairmat[4][4])
{
- float vec[3], orco[3];
+ float vec[3], orco[3];
- psys_face_mat(ob, mesh, pa, hairmat, 1);
- psys_particle_on_dm(mesh, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, vec, 0, 0, 0, orco);
+ psys_face_mat(ob, mesh, pa, hairmat, 1);
+ psys_particle_on_dm(
+ mesh, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, vec, 0, 0, 0, orco);
- /* see psys_face_mat for why this function is called */
- if (CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX))
- BKE_mesh_orco_verts_transform(ob->data, &orco, 1, 1);
- copy_v3_v3(hairmat[3], orco);
+ /* see psys_face_mat for why this function is called */
+ if (CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX))
+ BKE_mesh_orco_verts_transform(ob->data, &orco, 1, 1);
+ copy_v3_v3(hairmat[3], orco);
}
void psys_vec_rot_to_face(Mesh *mesh, ParticleData *pa, float vec[3])
{
- float mat[4][4];
+ float mat[4][4];
- psys_face_mat(0, mesh, pa, mat, 0);
- transpose_m4(mat); /* cheap inverse for rotation matrix */
- mul_mat3_m4_v3(mat, vec);
+ psys_face_mat(0, mesh, pa, mat, 0);
+ transpose_m4(mat); /* cheap inverse for rotation matrix */
+ mul_mat3_m4_v3(mat, vec);
}
-void psys_mat_hair_to_global(Object *ob, Mesh *mesh, short from, ParticleData *pa, float hairmat[4][4])
+void psys_mat_hair_to_global(
+ Object *ob, Mesh *mesh, short from, ParticleData *pa, float hairmat[4][4])
{
- float facemat[4][4];
+ float facemat[4][4];
- psys_mat_hair_to_object(ob, mesh, from, pa, facemat);
+ psys_mat_hair_to_object(ob, mesh, from, pa, facemat);
- mul_m4_m4m4(hairmat, ob->obmat, facemat);
+ mul_m4_m4m4(hairmat, ob->obmat, facemat);
}
/************************************************/
-/* ParticleSettings handling */
+/* ParticleSettings handling */
/************************************************/
ModifierData *object_add_particle_system(Main *bmain, Scene *scene, Object *ob, const char *name)
{
- ParticleSystem *psys;
- ModifierData *md;
- ParticleSystemModifierData *psmd;
+ ParticleSystem *psys;
+ ModifierData *md;
+ ParticleSystemModifierData *psmd;
- if (!ob || ob->type != OB_MESH)
- return NULL;
+ if (!ob || ob->type != OB_MESH)
+ return NULL;
- if (name == NULL) {
- name = DATA_("ParticleSettings");
- }
+ if (name == NULL) {
+ name = DATA_("ParticleSettings");
+ }
- psys = ob->particlesystem.first;
- for (; psys; psys = psys->next)
- psys->flag &= ~PSYS_CURRENT;
+ psys = ob->particlesystem.first;
+ for (; psys; psys = psys->next)
+ psys->flag &= ~PSYS_CURRENT;
- psys = MEM_callocN(sizeof(ParticleSystem), "particle_system");
- psys->pointcache = BKE_ptcache_add(&psys->ptcaches);
- BLI_addtail(&ob->particlesystem, psys);
- psys_unique_name(ob, psys, name);
+ psys = MEM_callocN(sizeof(ParticleSystem), "particle_system");
+ psys->pointcache = BKE_ptcache_add(&psys->ptcaches);
+ BLI_addtail(&ob->particlesystem, psys);
+ psys_unique_name(ob, psys, name);
- psys->part = BKE_particlesettings_add(bmain, psys->name);
+ psys->part = BKE_particlesettings_add(bmain, psys->name);
- md = modifier_new(eModifierType_ParticleSystem);
- BLI_strncpy(md->name, psys->name, sizeof(md->name));
- modifier_unique_name(&ob->modifiers, md);
+ md = modifier_new(eModifierType_ParticleSystem);
+ BLI_strncpy(md->name, psys->name, sizeof(md->name));
+ modifier_unique_name(&ob->modifiers, md);
- psmd = (ParticleSystemModifierData *) md;
- psmd->psys = psys;
- BLI_addtail(&ob->modifiers, md);
+ psmd = (ParticleSystemModifierData *)md;
+ psmd->psys = psys;
+ BLI_addtail(&ob->modifiers, md);
- psys->totpart = 0;
- psys->flag = PSYS_CURRENT;
- psys->cfra = BKE_scene_frame_get_from_ctime(scene, CFRA + 1);
+ psys->totpart = 0;
+ psys->flag = PSYS_CURRENT;
+ psys->cfra = BKE_scene_frame_get_from_ctime(scene, CFRA + 1);
- DEG_relations_tag_update(bmain);
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- return md;
+ return md;
}
void object_remove_particle_system(Main *bmain, Scene *UNUSED(scene), Object *ob)
{
- ParticleSystem *psys = psys_get_current(ob);
- ParticleSystemModifierData *psmd;
- ModifierData *md;
-
- if (!psys)
- return;
-
- /* clear all other appearances of this pointer (like on smoke flow modifier) */
- if ((md = modifiers_findByType(ob, eModifierType_Smoke))) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
- if ((smd->type == MOD_SMOKE_TYPE_FLOW) && smd->flow && smd->flow->psys)
- if (smd->flow->psys == psys)
- smd->flow->psys = NULL;
- }
-
- if ((md = modifiers_findByType(ob, eModifierType_DynamicPaint))) {
- DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
- if (pmd->brush && pmd->brush->psys)
- if (pmd->brush->psys == psys)
- pmd->brush->psys = NULL;
- }
-
- /* clear modifier */
- psmd = psys_get_modifier(ob, psys);
- BLI_remlink(&ob->modifiers, psmd);
- modifier_free((ModifierData *)psmd);
-
- /* clear particle system */
- BLI_remlink(&ob->particlesystem, psys);
- if (psys->part) {
- id_us_min(&psys->part->id);
- }
- psys_free(ob, psys);
-
- if (ob->particlesystem.first)
- ((ParticleSystem *) ob->particlesystem.first)->flag |= PSYS_CURRENT;
- else
- ob->mode &= ~OB_MODE_PARTICLE_EDIT;
-
- DEG_relations_tag_update(bmain);
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
-
- /* Flush object mode. */
- DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
+ ParticleSystem *psys = psys_get_current(ob);
+ ParticleSystemModifierData *psmd;
+ ModifierData *md;
+
+ if (!psys)
+ return;
+
+ /* clear all other appearances of this pointer (like on smoke flow modifier) */
+ if ((md = modifiers_findByType(ob, eModifierType_Smoke))) {
+ SmokeModifierData *smd = (SmokeModifierData *)md;
+ if ((smd->type == MOD_SMOKE_TYPE_FLOW) && smd->flow && smd->flow->psys)
+ if (smd->flow->psys == psys)
+ smd->flow->psys = NULL;
+ }
+
+ if ((md = modifiers_findByType(ob, eModifierType_DynamicPaint))) {
+ DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
+ if (pmd->brush && pmd->brush->psys)
+ if (pmd->brush->psys == psys)
+ pmd->brush->psys = NULL;
+ }
+
+ /* clear modifier */
+ psmd = psys_get_modifier(ob, psys);
+ BLI_remlink(&ob->modifiers, psmd);
+ modifier_free((ModifierData *)psmd);
+
+ /* clear particle system */
+ BLI_remlink(&ob->particlesystem, psys);
+ if (psys->part) {
+ id_us_min(&psys->part->id);
+ }
+ psys_free(ob, psys);
+
+ if (ob->particlesystem.first)
+ ((ParticleSystem *)ob->particlesystem.first)->flag |= PSYS_CURRENT;
+ else
+ ob->mode &= ~OB_MODE_PARTICLE_EDIT;
+
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+
+ /* Flush object mode. */
+ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
}
static void default_particle_settings(ParticleSettings *part)
{
- part->type = PART_EMITTER;
- part->distr = PART_DISTR_JIT;
- part->draw_as = PART_DRAW_REND;
- part->ren_as = PART_DRAW_HALO;
- part->bb_uv_split = 1;
- part->flag = PART_EDISTR | PART_TRAND | PART_HIDE_ADVANCED_HAIR;
-
- part->sta = 1.0;
- part->end = 200.0;
- part->lifetime = 50.0;
- part->jitfac = 1.0;
- part->totpart = 1000;
- part->grid_res = 10;
- part->timetweak = 1.0;
- part->courant_target = 0.2;
-
- part->integrator = PART_INT_MIDPOINT;
- part->phystype = PART_PHYS_NEWTON;
- part->hair_step = 5;
- part->keys_step = 5;
- part->draw_step = 2;
- part->ren_step = 3;
- part->adapt_angle = 5;
- part->adapt_pix = 3;
- part->kink_axis = 2;
- part->kink_amp_clump = 1.f;
- part->kink_extra_steps = 4;
- part->clump_noise_size = 1.0f;
- part->reactevent = PART_EVENT_DEATH;
- part->disp = 100;
- part->from = PART_FROM_FACE;
-
- part->normfac = 1.0f;
-
- part->mass = 1.0;
- part->size = 0.05;
- part->childsize = 1.0;
-
- part->rotmode = PART_ROT_VEL;
- part->avemode = PART_AVE_VELOCITY;
-
- part->child_nbr = 10;
- part->ren_child_nbr = 100;
- part->childrad = 0.2f;
- part->childflat = 0.0f;
- part->clumppow = 0.0f;
- part->kink_amp = 0.2f;
- part->kink_freq = 2.0;
-
- part->rough1_size = 1.0;
- part->rough2_size = 1.0;
- part->rough_end_shape = 1.0;
-
- part->clength = 1.0f;
- part->clength_thres = 0.0f;
-
- part->draw = 0;
- part->draw_line[0] = 0.5;
- part->path_start = 0.0f;
- part->path_end = 1.0f;
-
- part->bb_size[0] = part->bb_size[1] = 1.0f;
-
- part->keyed_loops = 1;
-
- part->color_vec_max = 1.f;
- part->draw_col = PART_DRAW_COL_MAT;
-
- if (!part->effector_weights)
- part->effector_weights = BKE_effector_add_weights(NULL);
-
- part->omat = 1;
- part->use_modifier_stack = false;
- part->draw_size = 0.1f;
-
- part->shape_flag = PART_SHAPE_CLOSE_TIP;
- part->shape = 0.0f;
- part->rad_root = 1.0f;
- part->rad_tip = 0.0f;
- part->rad_scale = 0.01f;
+ part->type = PART_EMITTER;
+ part->distr = PART_DISTR_JIT;
+ part->draw_as = PART_DRAW_REND;
+ part->ren_as = PART_DRAW_HALO;
+ part->bb_uv_split = 1;
+ part->flag = PART_EDISTR | PART_TRAND | PART_HIDE_ADVANCED_HAIR;
+
+ part->sta = 1.0;
+ part->end = 200.0;
+ part->lifetime = 50.0;
+ part->jitfac = 1.0;
+ part->totpart = 1000;
+ part->grid_res = 10;
+ part->timetweak = 1.0;
+ part->courant_target = 0.2;
+
+ part->integrator = PART_INT_MIDPOINT;
+ part->phystype = PART_PHYS_NEWTON;
+ part->hair_step = 5;
+ part->keys_step = 5;
+ part->draw_step = 2;
+ part->ren_step = 3;
+ part->adapt_angle = 5;
+ part->adapt_pix = 3;
+ part->kink_axis = 2;
+ part->kink_amp_clump = 1.f;
+ part->kink_extra_steps = 4;
+ part->clump_noise_size = 1.0f;
+ part->reactevent = PART_EVENT_DEATH;
+ part->disp = 100;
+ part->from = PART_FROM_FACE;
+
+ part->normfac = 1.0f;
+
+ part->mass = 1.0;
+ part->size = 0.05;
+ part->childsize = 1.0;
+
+ part->rotmode = PART_ROT_VEL;
+ part->avemode = PART_AVE_VELOCITY;
+
+ part->child_nbr = 10;
+ part->ren_child_nbr = 100;
+ part->childrad = 0.2f;
+ part->childflat = 0.0f;
+ part->clumppow = 0.0f;
+ part->kink_amp = 0.2f;
+ part->kink_freq = 2.0;
+
+ part->rough1_size = 1.0;
+ part->rough2_size = 1.0;
+ part->rough_end_shape = 1.0;
+
+ part->clength = 1.0f;
+ part->clength_thres = 0.0f;
+
+ part->draw = 0;
+ part->draw_line[0] = 0.5;
+ part->path_start = 0.0f;
+ part->path_end = 1.0f;
+
+ part->bb_size[0] = part->bb_size[1] = 1.0f;
+
+ part->keyed_loops = 1;
+
+ part->color_vec_max = 1.f;
+ part->draw_col = PART_DRAW_COL_MAT;
+
+ if (!part->effector_weights)
+ part->effector_weights = BKE_effector_add_weights(NULL);
+
+ part->omat = 1;
+ part->use_modifier_stack = false;
+ part->draw_size = 0.1f;
+
+ part->shape_flag = PART_SHAPE_CLOSE_TIP;
+ part->shape = 0.0f;
+ part->rad_root = 1.0f;
+ part->rad_tip = 0.0f;
+ part->rad_scale = 0.01f;
}
-
ParticleSettings *BKE_particlesettings_add(Main *bmain, const char *name)
{
- ParticleSettings *part;
+ ParticleSettings *part;
- part = BKE_libblock_alloc(bmain, ID_PA, name, 0);
+ part = BKE_libblock_alloc(bmain, ID_PA, name, 0);
- default_particle_settings(part);
+ default_particle_settings(part);
- return part;
+ return part;
}
void BKE_particlesettings_clump_curve_init(ParticleSettings *part)
{
- CurveMapping *cumap = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ CurveMapping *cumap = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
- cumap->cm[0].curve[0].x = 0.0f;
- cumap->cm[0].curve[0].y = 1.0f;
- cumap->cm[0].curve[1].x = 1.0f;
- cumap->cm[0].curve[1].y = 1.0f;
+ cumap->cm[0].curve[0].x = 0.0f;
+ cumap->cm[0].curve[0].y = 1.0f;
+ cumap->cm[0].curve[1].x = 1.0f;
+ cumap->cm[0].curve[1].y = 1.0f;
- curvemapping_initialize(cumap);
+ curvemapping_initialize(cumap);
- part->clumpcurve = cumap;
+ part->clumpcurve = cumap;
}
void BKE_particlesettings_rough_curve_init(ParticleSettings *part)
{
- CurveMapping *cumap = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ CurveMapping *cumap = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
- cumap->cm[0].curve[0].x = 0.0f;
- cumap->cm[0].curve[0].y = 1.0f;
- cumap->cm[0].curve[1].x = 1.0f;
- cumap->cm[0].curve[1].y = 1.0f;
+ cumap->cm[0].curve[0].x = 0.0f;
+ cumap->cm[0].curve[0].y = 1.0f;
+ cumap->cm[0].curve[1].x = 1.0f;
+ cumap->cm[0].curve[1].y = 1.0f;
- curvemapping_initialize(cumap);
+ curvemapping_initialize(cumap);
- part->roughcurve = cumap;
+ part->roughcurve = cumap;
}
void BKE_particlesettings_twist_curve_init(ParticleSettings *part)
{
- CurveMapping *cumap = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ CurveMapping *cumap = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
- cumap->cm[0].curve[0].x = 0.0f;
- cumap->cm[0].curve[0].y = 1.0f;
- cumap->cm[0].curve[1].x = 1.0f;
- cumap->cm[0].curve[1].y = 1.0f;
+ cumap->cm[0].curve[0].x = 0.0f;
+ cumap->cm[0].curve[0].y = 1.0f;
+ cumap->cm[0].curve[1].x = 1.0f;
+ cumap->cm[0].curve[1].y = 1.0f;
- curvemapping_initialize(cumap);
+ curvemapping_initialize(cumap);
- part->twistcurve = cumap;
+ part->twistcurve = cumap;
}
/**
@@ -3289,974 +3570,1114 @@ void BKE_particlesettings_twist_curve_init(ParticleSettings *part)
*
* \param flag: Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
*/
-void BKE_particlesettings_copy_data(
- Main *UNUSED(bmain), ParticleSettings *part_dst, const ParticleSettings *part_src, const int UNUSED(flag))
+void BKE_particlesettings_copy_data(Main *UNUSED(bmain),
+ ParticleSettings *part_dst,
+ const ParticleSettings *part_src,
+ const int UNUSED(flag))
{
- part_dst->pd = BKE_partdeflect_copy(part_src->pd);
- part_dst->pd2 = BKE_partdeflect_copy(part_src->pd2);
- part_dst->effector_weights = MEM_dupallocN(part_src->effector_weights);
- part_dst->fluid = MEM_dupallocN(part_src->fluid);
-
- if (part_src->clumpcurve) {
- part_dst->clumpcurve = curvemapping_copy(part_src->clumpcurve);
- }
- if (part_src->roughcurve) {
- part_dst->roughcurve = curvemapping_copy(part_src->roughcurve);
- }
- if (part_src->twistcurve) {
- part_dst->twistcurve = curvemapping_copy(part_src->twistcurve);
- }
-
- part_dst->boids = boid_copy_settings(part_src->boids);
-
- for (int a = 0; a < MAX_MTEX; a++) {
- if (part_src->mtex[a]) {
- part_dst->mtex[a] = MEM_dupallocN(part_src->mtex[a]);
- }
- }
-
- BLI_duplicatelist(&part_dst->instance_weights, &part_src->instance_weights);
+ part_dst->pd = BKE_partdeflect_copy(part_src->pd);
+ part_dst->pd2 = BKE_partdeflect_copy(part_src->pd2);
+ part_dst->effector_weights = MEM_dupallocN(part_src->effector_weights);
+ part_dst->fluid = MEM_dupallocN(part_src->fluid);
+
+ if (part_src->clumpcurve) {
+ part_dst->clumpcurve = curvemapping_copy(part_src->clumpcurve);
+ }
+ if (part_src->roughcurve) {
+ part_dst->roughcurve = curvemapping_copy(part_src->roughcurve);
+ }
+ if (part_src->twistcurve) {
+ part_dst->twistcurve = curvemapping_copy(part_src->twistcurve);
+ }
+
+ part_dst->boids = boid_copy_settings(part_src->boids);
+
+ for (int a = 0; a < MAX_MTEX; a++) {
+ if (part_src->mtex[a]) {
+ part_dst->mtex[a] = MEM_dupallocN(part_src->mtex[a]);
+ }
+ }
+
+ BLI_duplicatelist(&part_dst->instance_weights, &part_src->instance_weights);
}
ParticleSettings *BKE_particlesettings_copy(Main *bmain, const ParticleSettings *part)
{
- ParticleSettings *part_copy;
- BKE_id_copy(bmain, &part->id, (ID **)&part_copy);
- return part_copy;
+ ParticleSettings *part_copy;
+ BKE_id_copy(bmain, &part->id, (ID **)&part_copy);
+ return part_copy;
}
void BKE_particlesettings_make_local(Main *bmain, ParticleSettings *part, const bool lib_local)
{
- BKE_id_make_local_generic(bmain, &part->id, true, lib_local);
+ BKE_id_make_local_generic(bmain, &part->id, true, lib_local);
}
/************************************************/
-/* Textures */
+/* Textures */
/************************************************/
-static int get_particle_uv(Mesh *mesh, ParticleData *pa, int index, const float fuv[4],
- char *name, float *texco, bool from_vert)
+static int get_particle_uv(Mesh *mesh,
+ ParticleData *pa,
+ int index,
+ const float fuv[4],
+ char *name,
+ float *texco,
+ bool from_vert)
{
- MFace *mf;
- MTFace *tf;
- int i;
-
- tf = CustomData_get_layer_named(&mesh->fdata, CD_MTFACE, name);
-
- if (tf == NULL)
- tf = mesh->mtface;
-
- if (tf == NULL)
- return 0;
-
- if (pa) {
- i = ELEM(pa->num_dmcache, DMCACHE_NOTFOUND, DMCACHE_ISCHILD) ? pa->num : pa->num_dmcache;
- if ((!from_vert && i >= mesh->totface) ||
- (from_vert && i >= mesh->totvert))
- {
- i = -1;
- }
- }
- else {
- i = index;
- }
-
- if (i == -1) {
- texco[0] = 0.0f;
- texco[1] = 0.0f;
- texco[2] = 0.0f;
- }
- else {
- if (from_vert) {
- mf = mesh->mface;
-
- /* This finds the first face to contain the emitting vertex,
- * this is not ideal, but is mostly fine as UV seams generally
- * map to equal-colored parts of a texture */
- for (int j = 0; j < mesh->totface; j++, mf++) {
- if (ELEM(i, mf->v1, mf->v2, mf->v3, mf->v4)) {
- i = j;
- break;
- }
- }
- }
- else {
- mf = &mesh->mface[i];
- }
-
- psys_interpolate_uvs(&tf[i], mf->v4, fuv, texco);
-
- texco[0] = texco[0] * 2.0f - 1.0f;
- texco[1] = texco[1] * 2.0f - 1.0f;
- texco[2] = 0.0f;
- }
-
- return 1;
+ MFace *mf;
+ MTFace *tf;
+ int i;
+
+ tf = CustomData_get_layer_named(&mesh->fdata, CD_MTFACE, name);
+
+ if (tf == NULL)
+ tf = mesh->mtface;
+
+ if (tf == NULL)
+ return 0;
+
+ if (pa) {
+ i = ELEM(pa->num_dmcache, DMCACHE_NOTFOUND, DMCACHE_ISCHILD) ? pa->num : pa->num_dmcache;
+ if ((!from_vert && i >= mesh->totface) || (from_vert && i >= mesh->totvert)) {
+ i = -1;
+ }
+ }
+ else {
+ i = index;
+ }
+
+ if (i == -1) {
+ texco[0] = 0.0f;
+ texco[1] = 0.0f;
+ texco[2] = 0.0f;
+ }
+ else {
+ if (from_vert) {
+ mf = mesh->mface;
+
+ /* This finds the first face to contain the emitting vertex,
+ * this is not ideal, but is mostly fine as UV seams generally
+ * map to equal-colored parts of a texture */
+ for (int j = 0; j < mesh->totface; j++, mf++) {
+ if (ELEM(i, mf->v1, mf->v2, mf->v3, mf->v4)) {
+ i = j;
+ break;
+ }
+ }
+ }
+ else {
+ mf = &mesh->mface[i];
+ }
+
+ psys_interpolate_uvs(&tf[i], mf->v4, fuv, texco);
+
+ texco[0] = texco[0] * 2.0f - 1.0f;
+ texco[1] = texco[1] * 2.0f - 1.0f;
+ texco[2] = 0.0f;
+ }
+
+ return 1;
}
-#define SET_PARTICLE_TEXTURE(type, pvalue, texfac) \
- if ((event & mtex->mapto) & type) { \
- pvalue = texture_value_blend(def, pvalue, value, texfac, blend); \
- } (void)0
-
-#define CLAMP_PARTICLE_TEXTURE_POS(type, pvalue) \
- if (event & type) { \
- CLAMP(pvalue, 0.0f, 1.0f); \
- } (void)0
-
-#define CLAMP_WARP_PARTICLE_TEXTURE_POS(type, pvalue) \
- if (event & type) { \
- if (pvalue < 0.0f) \
- pvalue = 1.0f + pvalue; \
- CLAMP(pvalue, 0.0f, 1.0f); \
- } (void)0
-
-#define CLAMP_PARTICLE_TEXTURE_POSNEG(type, pvalue) \
- if (event & type) { \
- CLAMP(pvalue, -1.0f, 1.0f); \
- } (void)0
-
-static void get_cpa_texture(Mesh *mesh, ParticleSystem *psys, ParticleSettings *part, ParticleData *par, int child_index, int face_index, const float fw[4], float *orco, ParticleTexture *ptex, int event, float cfra)
+#define SET_PARTICLE_TEXTURE(type, pvalue, texfac) \
+ if ((event & mtex->mapto) & type) { \
+ pvalue = texture_value_blend(def, pvalue, value, texfac, blend); \
+ } \
+ (void)0
+
+#define CLAMP_PARTICLE_TEXTURE_POS(type, pvalue) \
+ if (event & type) { \
+ CLAMP(pvalue, 0.0f, 1.0f); \
+ } \
+ (void)0
+
+#define CLAMP_WARP_PARTICLE_TEXTURE_POS(type, pvalue) \
+ if (event & type) { \
+ if (pvalue < 0.0f) \
+ pvalue = 1.0f + pvalue; \
+ CLAMP(pvalue, 0.0f, 1.0f); \
+ } \
+ (void)0
+
+#define CLAMP_PARTICLE_TEXTURE_POSNEG(type, pvalue) \
+ if (event & type) { \
+ CLAMP(pvalue, -1.0f, 1.0f); \
+ } \
+ (void)0
+
+static void get_cpa_texture(Mesh *mesh,
+ ParticleSystem *psys,
+ ParticleSettings *part,
+ ParticleData *par,
+ int child_index,
+ int face_index,
+ const float fw[4],
+ float *orco,
+ ParticleTexture *ptex,
+ int event,
+ float cfra)
{
- MTex *mtex, **mtexp = part->mtex;
- int m;
- float value, rgba[4], texvec[3];
-
- ptex->ivel = ptex->life = ptex->exist = ptex->size = ptex->damp =
- ptex->gravity = ptex->field = ptex->time = ptex->clump = ptex->kink_freq = ptex->kink_amp =
- ptex->effector = ptex->rough1 = ptex->rough2 = ptex->roughe = 1.0f;
- ptex->twist = 1.0f;
-
- ptex->length = 1.0f - part->randlength * psys_frand(psys, child_index + 26);
- ptex->length *= part->clength_thres < psys_frand(psys, child_index + 27) ? part->clength : 1.0f;
-
- for (m = 0; m < MAX_MTEX; m++, mtexp++) {
- mtex = *mtexp;
- if (mtex && mtex->tex && mtex->mapto) {
- float def = mtex->def_var;
- short blend = mtex->blendtype;
- short texco = mtex->texco;
-
- if (ELEM(texco, TEXCO_UV, TEXCO_ORCO) && (ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME) == 0 || part->distr == PART_DISTR_GRID))
- texco = TEXCO_GLOB;
-
- switch (texco) {
- case TEXCO_GLOB:
- copy_v3_v3(texvec, par->state.co);
- break;
- case TEXCO_OBJECT:
- copy_v3_v3(texvec, par->state.co);
- if (mtex->object)
- mul_m4_v3(mtex->object->imat, texvec);
- break;
- case TEXCO_UV:
- if (fw && get_particle_uv(mesh, NULL, face_index, fw, mtex->uvname,
- texvec, (part->from == PART_FROM_VERT)))
- {
- break;
- }
- /* no break, failed to get uv's, so let's try orco's */
- ATTR_FALLTHROUGH;
- case TEXCO_ORCO:
- copy_v3_v3(texvec, orco);
- break;
- case TEXCO_PARTICLE:
- /* texture coordinates in range [-1, 1] */
- texvec[0] = 2.f * (cfra - par->time) / (par->dietime - par->time) - 1.f;
- texvec[1] = 0.f;
- texvec[2] = 0.f;
- break;
- }
-
- externtex(mtex, texvec, &value, rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL, false, false);
-
- if ((event & mtex->mapto) & PAMAP_ROUGH)
- ptex->rough1 = ptex->rough2 = ptex->roughe = texture_value_blend(def, ptex->rough1, value, mtex->roughfac, blend);
-
- SET_PARTICLE_TEXTURE(PAMAP_LENGTH, ptex->length, mtex->lengthfac);
- SET_PARTICLE_TEXTURE(PAMAP_CLUMP, ptex->clump, mtex->clumpfac);
- SET_PARTICLE_TEXTURE(PAMAP_KINK_AMP, ptex->kink_amp, mtex->kinkampfac);
- SET_PARTICLE_TEXTURE(PAMAP_KINK_FREQ, ptex->kink_freq, mtex->kinkfac);
- SET_PARTICLE_TEXTURE(PAMAP_DENS, ptex->exist, mtex->padensfac);
- SET_PARTICLE_TEXTURE(PAMAP_TWIST, ptex->twist, mtex->twistfac);
- }
- }
-
- CLAMP_PARTICLE_TEXTURE_POS(PAMAP_LENGTH, ptex->length);
- CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_CLUMP, ptex->clump);
- CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_KINK_AMP, ptex->kink_amp);
- CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_KINK_FREQ, ptex->kink_freq);
- CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_ROUGH, ptex->rough1);
- CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_DENS, ptex->exist);
+ MTex *mtex, **mtexp = part->mtex;
+ int m;
+ float value, rgba[4], texvec[3];
+
+ ptex->ivel = ptex->life = ptex->exist = ptex->size = ptex->damp = ptex->gravity = ptex->field =
+ ptex->time = ptex->clump = ptex->kink_freq = ptex->kink_amp = ptex->effector = ptex->rough1 =
+ ptex->rough2 = ptex->roughe = 1.0f;
+ ptex->twist = 1.0f;
+
+ ptex->length = 1.0f - part->randlength * psys_frand(psys, child_index + 26);
+ ptex->length *= part->clength_thres < psys_frand(psys, child_index + 27) ? part->clength : 1.0f;
+
+ for (m = 0; m < MAX_MTEX; m++, mtexp++) {
+ mtex = *mtexp;
+ if (mtex && mtex->tex && mtex->mapto) {
+ float def = mtex->def_var;
+ short blend = mtex->blendtype;
+ short texco = mtex->texco;
+
+ if (ELEM(texco, TEXCO_UV, TEXCO_ORCO) &&
+ (ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME) == 0 ||
+ part->distr == PART_DISTR_GRID))
+ texco = TEXCO_GLOB;
+
+ switch (texco) {
+ case TEXCO_GLOB:
+ copy_v3_v3(texvec, par->state.co);
+ break;
+ case TEXCO_OBJECT:
+ copy_v3_v3(texvec, par->state.co);
+ if (mtex->object)
+ mul_m4_v3(mtex->object->imat, texvec);
+ break;
+ case TEXCO_UV:
+ if (fw && get_particle_uv(mesh,
+ NULL,
+ face_index,
+ fw,
+ mtex->uvname,
+ texvec,
+ (part->from == PART_FROM_VERT))) {
+ break;
+ }
+ /* no break, failed to get uv's, so let's try orco's */
+ ATTR_FALLTHROUGH;
+ case TEXCO_ORCO:
+ copy_v3_v3(texvec, orco);
+ break;
+ case TEXCO_PARTICLE:
+ /* texture coordinates in range [-1, 1] */
+ texvec[0] = 2.f * (cfra - par->time) / (par->dietime - par->time) - 1.f;
+ texvec[1] = 0.f;
+ texvec[2] = 0.f;
+ break;
+ }
+
+ externtex(mtex, texvec, &value, rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL, false, false);
+
+ if ((event & mtex->mapto) & PAMAP_ROUGH)
+ ptex->rough1 = ptex->rough2 = ptex->roughe = texture_value_blend(
+ def, ptex->rough1, value, mtex->roughfac, blend);
+
+ SET_PARTICLE_TEXTURE(PAMAP_LENGTH, ptex->length, mtex->lengthfac);
+ SET_PARTICLE_TEXTURE(PAMAP_CLUMP, ptex->clump, mtex->clumpfac);
+ SET_PARTICLE_TEXTURE(PAMAP_KINK_AMP, ptex->kink_amp, mtex->kinkampfac);
+ SET_PARTICLE_TEXTURE(PAMAP_KINK_FREQ, ptex->kink_freq, mtex->kinkfac);
+ SET_PARTICLE_TEXTURE(PAMAP_DENS, ptex->exist, mtex->padensfac);
+ SET_PARTICLE_TEXTURE(PAMAP_TWIST, ptex->twist, mtex->twistfac);
+ }
+ }
+
+ CLAMP_PARTICLE_TEXTURE_POS(PAMAP_LENGTH, ptex->length);
+ CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_CLUMP, ptex->clump);
+ CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_KINK_AMP, ptex->kink_amp);
+ CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_KINK_FREQ, ptex->kink_freq);
+ CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_ROUGH, ptex->rough1);
+ CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_DENS, ptex->exist);
}
-void psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTexture *ptex, int event, float cfra)
+void psys_get_texture(
+ ParticleSimulationData *sim, ParticleData *pa, ParticleTexture *ptex, int event, float cfra)
{
- Object *ob = sim->ob;
- Mesh *me = (Mesh *)ob->data;
- ParticleSettings *part = sim->psys->part;
- MTex **mtexp = part->mtex;
- MTex *mtex;
- int m;
- float value, rgba[4], co[3], texvec[3];
- int setvars = 0;
-
- /* initialize ptex */
- ptex->ivel = ptex->life = ptex->exist = ptex->size = ptex->damp =
- ptex->gravity = ptex->field = ptex->length = ptex->clump = ptex->kink_freq = ptex->kink_amp =
- ptex->effector = ptex->rough1 = ptex->rough2 = ptex->roughe = 1.0f;
- ptex->twist = 1.0f;
-
- ptex->time = (float)(pa - sim->psys->particles) / (float)sim->psys->totpart;
-
- for (m = 0; m < MAX_MTEX; m++, mtexp++) {
- mtex = *mtexp;
- if (mtex && mtex->tex && mtex->mapto) {
- float def = mtex->def_var;
- short blend = mtex->blendtype;
- short texco = mtex->texco;
-
- if (texco == TEXCO_UV && (ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME) == 0 || part->distr == PART_DISTR_GRID))
- texco = TEXCO_GLOB;
-
- switch (texco) {
- case TEXCO_GLOB:
- copy_v3_v3(texvec, pa->state.co);
- break;
- case TEXCO_OBJECT:
- copy_v3_v3(texvec, pa->state.co);
- if (mtex->object)
- mul_m4_v3(mtex->object->imat, texvec);
- break;
- case TEXCO_UV:
- if (get_particle_uv(sim->psmd->mesh_final, pa, 0, pa->fuv, mtex->uvname,
- texvec, (part->from == PART_FROM_VERT)))
- {
- break;
- }
- /* no break, failed to get uv's, so let's try orco's */
- ATTR_FALLTHROUGH;
- case TEXCO_ORCO:
- psys_particle_on_emitter(sim->psmd, sim->psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co, 0, 0, 0, texvec);
-
- if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) {
- BKE_mesh_texspace_calc(me);
- }
- sub_v3_v3(texvec, me->loc);
- if (me->size[0] != 0.0f) texvec[0] /= me->size[0];
- if (me->size[1] != 0.0f) texvec[1] /= me->size[1];
- if (me->size[2] != 0.0f) texvec[2] /= me->size[2];
- break;
- case TEXCO_PARTICLE:
- /* texture coordinates in range [-1, 1] */
- texvec[0] = 2.f * (cfra - pa->time) / (pa->dietime - pa->time) - 1.f;
- if (sim->psys->totpart > 0)
- texvec[1] = 2.f * (float)(pa - sim->psys->particles) / (float)sim->psys->totpart - 1.f;
- else
- texvec[1] = 0.0f;
- texvec[2] = 0.f;
- break;
- }
-
- externtex(mtex, texvec, &value, rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL, false, false);
-
- if ((event & mtex->mapto) & PAMAP_TIME) {
- /* the first time has to set the base value for time regardless of blend mode */
- if ((setvars & MAP_PA_TIME) == 0) {
- int flip = (mtex->timefac < 0.0f);
- float timefac = fabsf(mtex->timefac);
- ptex->time *= 1.0f - timefac;
- ptex->time += timefac * ((flip) ? 1.0f - value : value);
- setvars |= MAP_PA_TIME;
- }
- else
- ptex->time = texture_value_blend(def, ptex->time, value, mtex->timefac, blend);
- }
- SET_PARTICLE_TEXTURE(PAMAP_LIFE, ptex->life, mtex->lifefac);
- SET_PARTICLE_TEXTURE(PAMAP_DENS, ptex->exist, mtex->padensfac);
- SET_PARTICLE_TEXTURE(PAMAP_SIZE, ptex->size, mtex->sizefac);
- SET_PARTICLE_TEXTURE(PAMAP_IVEL, ptex->ivel, mtex->ivelfac);
- SET_PARTICLE_TEXTURE(PAMAP_FIELD, ptex->field, mtex->fieldfac);
- SET_PARTICLE_TEXTURE(PAMAP_GRAVITY, ptex->gravity, mtex->gravityfac);
- SET_PARTICLE_TEXTURE(PAMAP_DAMP, ptex->damp, mtex->dampfac);
- SET_PARTICLE_TEXTURE(PAMAP_LENGTH, ptex->length, mtex->lengthfac);
- SET_PARTICLE_TEXTURE(PAMAP_TWIST, ptex->twist, mtex->twistfac);
- }
- }
-
- CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_TIME, ptex->time);
- CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_LIFE, ptex->life);
- CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_DENS, ptex->exist);
- CLAMP_PARTICLE_TEXTURE_POS(PAMAP_SIZE, ptex->size);
- CLAMP_PARTICLE_TEXTURE_POSNEG(PAMAP_IVEL, ptex->ivel);
- CLAMP_PARTICLE_TEXTURE_POSNEG(PAMAP_FIELD, ptex->field);
- CLAMP_PARTICLE_TEXTURE_POSNEG(PAMAP_GRAVITY, ptex->gravity);
- CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_DAMP, ptex->damp);
- CLAMP_PARTICLE_TEXTURE_POS(PAMAP_LENGTH, ptex->length);
+ Object *ob = sim->ob;
+ Mesh *me = (Mesh *)ob->data;
+ ParticleSettings *part = sim->psys->part;
+ MTex **mtexp = part->mtex;
+ MTex *mtex;
+ int m;
+ float value, rgba[4], co[3], texvec[3];
+ int setvars = 0;
+
+ /* initialize ptex */
+ ptex->ivel = ptex->life = ptex->exist = ptex->size = ptex->damp = ptex->gravity = ptex->field =
+ ptex->length = ptex->clump = ptex->kink_freq = ptex->kink_amp = ptex->effector =
+ ptex->rough1 = ptex->rough2 = ptex->roughe = 1.0f;
+ ptex->twist = 1.0f;
+
+ ptex->time = (float)(pa - sim->psys->particles) / (float)sim->psys->totpart;
+
+ for (m = 0; m < MAX_MTEX; m++, mtexp++) {
+ mtex = *mtexp;
+ if (mtex && mtex->tex && mtex->mapto) {
+ float def = mtex->def_var;
+ short blend = mtex->blendtype;
+ short texco = mtex->texco;
+
+ if (texco == TEXCO_UV && (ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME) == 0 ||
+ part->distr == PART_DISTR_GRID))
+ texco = TEXCO_GLOB;
+
+ switch (texco) {
+ case TEXCO_GLOB:
+ copy_v3_v3(texvec, pa->state.co);
+ break;
+ case TEXCO_OBJECT:
+ copy_v3_v3(texvec, pa->state.co);
+ if (mtex->object)
+ mul_m4_v3(mtex->object->imat, texvec);
+ break;
+ case TEXCO_UV:
+ if (get_particle_uv(sim->psmd->mesh_final,
+ pa,
+ 0,
+ pa->fuv,
+ mtex->uvname,
+ texvec,
+ (part->from == PART_FROM_VERT))) {
+ break;
+ }
+ /* no break, failed to get uv's, so let's try orco's */
+ ATTR_FALLTHROUGH;
+ case TEXCO_ORCO:
+ psys_particle_on_emitter(sim->psmd,
+ sim->psys->part->from,
+ pa->num,
+ pa->num_dmcache,
+ pa->fuv,
+ pa->foffset,
+ co,
+ 0,
+ 0,
+ 0,
+ texvec);
+
+ if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) {
+ BKE_mesh_texspace_calc(me);
+ }
+ sub_v3_v3(texvec, me->loc);
+ if (me->size[0] != 0.0f)
+ texvec[0] /= me->size[0];
+ if (me->size[1] != 0.0f)
+ texvec[1] /= me->size[1];
+ if (me->size[2] != 0.0f)
+ texvec[2] /= me->size[2];
+ break;
+ case TEXCO_PARTICLE:
+ /* texture coordinates in range [-1, 1] */
+ texvec[0] = 2.f * (cfra - pa->time) / (pa->dietime - pa->time) - 1.f;
+ if (sim->psys->totpart > 0)
+ texvec[1] = 2.f * (float)(pa - sim->psys->particles) / (float)sim->psys->totpart - 1.f;
+ else
+ texvec[1] = 0.0f;
+ texvec[2] = 0.f;
+ break;
+ }
+
+ externtex(mtex, texvec, &value, rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL, false, false);
+
+ if ((event & mtex->mapto) & PAMAP_TIME) {
+ /* the first time has to set the base value for time regardless of blend mode */
+ if ((setvars & MAP_PA_TIME) == 0) {
+ int flip = (mtex->timefac < 0.0f);
+ float timefac = fabsf(mtex->timefac);
+ ptex->time *= 1.0f - timefac;
+ ptex->time += timefac * ((flip) ? 1.0f - value : value);
+ setvars |= MAP_PA_TIME;
+ }
+ else
+ ptex->time = texture_value_blend(def, ptex->time, value, mtex->timefac, blend);
+ }
+ SET_PARTICLE_TEXTURE(PAMAP_LIFE, ptex->life, mtex->lifefac);
+ SET_PARTICLE_TEXTURE(PAMAP_DENS, ptex->exist, mtex->padensfac);
+ SET_PARTICLE_TEXTURE(PAMAP_SIZE, ptex->size, mtex->sizefac);
+ SET_PARTICLE_TEXTURE(PAMAP_IVEL, ptex->ivel, mtex->ivelfac);
+ SET_PARTICLE_TEXTURE(PAMAP_FIELD, ptex->field, mtex->fieldfac);
+ SET_PARTICLE_TEXTURE(PAMAP_GRAVITY, ptex->gravity, mtex->gravityfac);
+ SET_PARTICLE_TEXTURE(PAMAP_DAMP, ptex->damp, mtex->dampfac);
+ SET_PARTICLE_TEXTURE(PAMAP_LENGTH, ptex->length, mtex->lengthfac);
+ SET_PARTICLE_TEXTURE(PAMAP_TWIST, ptex->twist, mtex->twistfac);
+ }
+ }
+
+ CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_TIME, ptex->time);
+ CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_LIFE, ptex->life);
+ CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_DENS, ptex->exist);
+ CLAMP_PARTICLE_TEXTURE_POS(PAMAP_SIZE, ptex->size);
+ CLAMP_PARTICLE_TEXTURE_POSNEG(PAMAP_IVEL, ptex->ivel);
+ CLAMP_PARTICLE_TEXTURE_POSNEG(PAMAP_FIELD, ptex->field);
+ CLAMP_PARTICLE_TEXTURE_POSNEG(PAMAP_GRAVITY, ptex->gravity);
+ CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_DAMP, ptex->damp);
+ CLAMP_PARTICLE_TEXTURE_POS(PAMAP_LENGTH, ptex->length);
}
/************************************************/
-/* Particle State */
+/* Particle State */
/************************************************/
float psys_get_timestep(ParticleSimulationData *sim)
{
- return 0.04f * sim->psys->part->timetweak;
+ return 0.04f * sim->psys->part->timetweak;
}
-float psys_get_child_time(ParticleSystem *psys, ChildParticle *cpa, float cfra, float *birthtime, float *dietime)
+float psys_get_child_time(
+ ParticleSystem *psys, ChildParticle *cpa, float cfra, float *birthtime, float *dietime)
{
- ParticleSettings *part = psys->part;
- float time, life;
-
- if (part->childtype == PART_CHILD_FACES) {
- int w = 0;
- time = 0.0;
- while (w < 4 && cpa->pa[w] >= 0) {
- time += cpa->w[w] * (psys->particles + cpa->pa[w])->time;
- w++;
- }
-
- life = part->lifetime * (1.0f - part->randlife * psys_frand(psys, cpa - psys->child + 25));
- }
- else {
- ParticleData *pa = psys->particles + cpa->parent;
-
- time = pa->time;
- life = pa->lifetime;
- }
-
- if (birthtime)
- *birthtime = time;
- if (dietime)
- *dietime = time + life;
-
- return (cfra - time) / life;
+ ParticleSettings *part = psys->part;
+ float time, life;
+
+ if (part->childtype == PART_CHILD_FACES) {
+ int w = 0;
+ time = 0.0;
+ while (w < 4 && cpa->pa[w] >= 0) {
+ time += cpa->w[w] * (psys->particles + cpa->pa[w])->time;
+ w++;
+ }
+
+ life = part->lifetime * (1.0f - part->randlife * psys_frand(psys, cpa - psys->child + 25));
+ }
+ else {
+ ParticleData *pa = psys->particles + cpa->parent;
+
+ time = pa->time;
+ life = pa->lifetime;
+ }
+
+ if (birthtime)
+ *birthtime = time;
+ if (dietime)
+ *dietime = time + life;
+
+ return (cfra - time) / life;
}
-float psys_get_child_size(ParticleSystem *psys, ChildParticle *cpa, float UNUSED(cfra), float *UNUSED(pa_time))
+float psys_get_child_size(ParticleSystem *psys,
+ ChildParticle *cpa,
+ float UNUSED(cfra),
+ float *UNUSED(pa_time))
{
- ParticleSettings *part = psys->part;
- float size; // time XXX
-
- if (part->childtype == PART_CHILD_FACES) {
- int w = 0;
- size = 0.0;
- while (w < 4 && cpa->pa[w] >= 0) {
- size += cpa->w[w] * (psys->particles + cpa->pa[w])->size;
- w++;
- }
- }
- else {
- size = psys->particles[cpa->parent].size;
- }
-
- size *= part->childsize;
-
- if (part->childrandsize != 0.0f)
- size *= 1.0f - part->childrandsize * psys_frand(psys, cpa - psys->child + 26);
-
- return size;
+ ParticleSettings *part = psys->part;
+ float size; // time XXX
+
+ if (part->childtype == PART_CHILD_FACES) {
+ int w = 0;
+ size = 0.0;
+ while (w < 4 && cpa->pa[w] >= 0) {
+ size += cpa->w[w] * (psys->particles + cpa->pa[w])->size;
+ w++;
+ }
+ }
+ else {
+ size = psys->particles[cpa->parent].size;
+ }
+
+ size *= part->childsize;
+
+ if (part->childrandsize != 0.0f)
+ size *= 1.0f - part->childrandsize * psys_frand(psys, cpa - psys->child + 26);
+
+ return size;
}
-static void get_child_modifier_parameters(ParticleSettings *part, ParticleThreadContext *ctx, ChildParticle *cpa, short cpa_from, int cpa_num, float *cpa_fuv, float *orco, ParticleTexture *ptex)
+static void get_child_modifier_parameters(ParticleSettings *part,
+ ParticleThreadContext *ctx,
+ ChildParticle *cpa,
+ short cpa_from,
+ int cpa_num,
+ float *cpa_fuv,
+ float *orco,
+ ParticleTexture *ptex)
{
- ParticleSystem *psys = ctx->sim.psys;
- int i = cpa - psys->child;
-
- get_cpa_texture(ctx->mesh, psys, part, psys->particles + cpa->pa[0], i, cpa_num, cpa_fuv, orco, ptex, PAMAP_DENS | PAMAP_CHILD, psys->cfra);
-
-
- if (ptex->exist < psys_frand(psys, i + 24))
- return;
-
- if (ctx->vg_length)
- ptex->length *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_length);
- if (ctx->vg_clump)
- ptex->clump *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_clump);
- if (ctx->vg_kink)
- ptex->kink_freq *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_kink);
- if (ctx->vg_rough1)
- ptex->rough1 *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_rough1);
- if (ctx->vg_rough2)
- ptex->rough2 *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_rough2);
- if (ctx->vg_roughe)
- ptex->roughe *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_roughe);
- if (ctx->vg_effector)
- ptex->effector *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_effector);
- if (ctx->vg_twist)
- ptex->twist *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_twist);
+ ParticleSystem *psys = ctx->sim.psys;
+ int i = cpa - psys->child;
+
+ get_cpa_texture(ctx->mesh,
+ psys,
+ part,
+ psys->particles + cpa->pa[0],
+ i,
+ cpa_num,
+ cpa_fuv,
+ orco,
+ ptex,
+ PAMAP_DENS | PAMAP_CHILD,
+ psys->cfra);
+
+ if (ptex->exist < psys_frand(psys, i + 24))
+ return;
+
+ if (ctx->vg_length)
+ ptex->length *= psys_interpolate_value_from_verts(
+ ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_length);
+ if (ctx->vg_clump)
+ ptex->clump *= psys_interpolate_value_from_verts(
+ ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_clump);
+ if (ctx->vg_kink)
+ ptex->kink_freq *= psys_interpolate_value_from_verts(
+ ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_kink);
+ if (ctx->vg_rough1)
+ ptex->rough1 *= psys_interpolate_value_from_verts(
+ ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_rough1);
+ if (ctx->vg_rough2)
+ ptex->rough2 *= psys_interpolate_value_from_verts(
+ ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_rough2);
+ if (ctx->vg_roughe)
+ ptex->roughe *= psys_interpolate_value_from_verts(
+ ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_roughe);
+ if (ctx->vg_effector)
+ ptex->effector *= psys_interpolate_value_from_verts(
+ ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_effector);
+ if (ctx->vg_twist)
+ ptex->twist *= psys_interpolate_value_from_verts(
+ ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_twist);
}
/* get's hair (or keyed) particles state at the "path time" specified in state->time */
-void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *state, const bool vel)
+void psys_get_particle_on_path(ParticleSimulationData *sim,
+ int p,
+ ParticleKey *state,
+ const bool vel)
{
- PARTICLE_PSMD;
- ParticleSystem *psys = sim->psys;
- ParticleSettings *part = sim->psys->part;
- Material *ma = give_current_material(sim->ob, part->omat);
- ParticleData *pa;
- ChildParticle *cpa;
- ParticleTexture ptex;
- ParticleKey *par = 0, keys[4], tstate;
- ParticleThreadContext ctx; /* fake thread context for child modifiers */
- ParticleInterpolationData pind;
-
- float t;
- float co[3], orco[3];
- float hairmat[4][4];
- int totpart = psys->totpart;
- int totchild = psys->totchild;
- short between = 0, edit = 0;
-
- int keyed = part->phystype & PART_PHYS_KEYED && psys->flag & PSYS_KEYED;
- int cached = !keyed && part->type != PART_HAIR;
-
- float *cpa_fuv; int cpa_num; short cpa_from;
-
- /* initialize keys to zero */
- memset(keys, 0, 4 * sizeof(ParticleKey));
-
- t = state->time;
- CLAMP(t, 0.0f, 1.0f);
-
- if (p < totpart) {
- /* interpolate pathcache directly if it exist */
- if (psys->pathcache) {
- ParticleCacheKey result;
- interpolate_pathcache(psys->pathcache[p], t, &result);
- copy_v3_v3(state->co, result.co);
- copy_v3_v3(state->vel, result.vel);
- copy_qt_qt(state->rot, result.rot);
- }
- /* otherwise interpolate with other means */
- else {
- pa = psys->particles + p;
-
- pind.keyed = keyed;
- pind.cache = cached ? psys->pointcache : NULL;
- pind.epoint = NULL;
- pind.bspline = (psys->part->flag & PART_HAIR_BSPLINE);
- /* pind.dm disabled in editmode means we don't get effectors taken into
- * account when subdividing for instance */
- pind.mesh = psys_in_edit_mode(sim->depsgraph, psys) ? NULL : psys->hair_out_mesh; /* XXX Sybren EEK */
- init_particle_interpolation(sim->ob, psys, pa, &pind);
- do_particle_interpolation(psys, p, pa, t, &pind, state);
-
- if (pind.mesh) {
- mul_m4_v3(sim->ob->obmat, state->co);
- mul_mat3_m4_v3(sim->ob->obmat, state->vel);
- }
- else if (!keyed && !cached && !(psys->flag & PSYS_GLOBAL_HAIR)) {
- if ((pa->flag & PARS_REKEY) == 0) {
- psys_mat_hair_to_global(sim->ob, sim->psmd->mesh_final, part->from, pa, hairmat);
- mul_m4_v3(hairmat, state->co);
- mul_mat3_m4_v3(hairmat, state->vel);
-
- if (sim->psys->effectors && (part->flag & PART_CHILD_GUIDE) == 0) {
- do_guides(sim->depsgraph, sim->psys->part, sim->psys->effectors, state, p, state->time);
- /* TODO: proper velocity handling */
- }
-
- if (psys->lattice_deform_data && edit == 0)
- calc_latt_deform(psys->lattice_deform_data, state->co, psys->lattice_strength);
- }
- }
- }
- }
- else if (totchild) {
- //invert_m4_m4(imat, ob->obmat);
-
- /* interpolate childcache directly if it exists */
- if (psys->childcache) {
- ParticleCacheKey result;
- interpolate_pathcache(psys->childcache[p - totpart], t, &result);
- copy_v3_v3(state->co, result.co);
- copy_v3_v3(state->vel, result.vel);
- copy_qt_qt(state->rot, result.rot);
- }
- else {
- float par_co[3], par_orco[3];
-
- cpa = psys->child + p - totpart;
-
- if (state->time < 0.0f)
- t = psys_get_child_time(psys, cpa, -state->time, NULL, NULL);
-
- if (totchild && part->childtype == PART_CHILD_FACES) {
- /* part->parents could still be 0 so we can't test with totparent */
- between = 1;
- }
- if (between) {
- int w = 0;
- float foffset;
-
- /* get parent states */
- while (w < 4 && cpa->pa[w] >= 0) {
- keys[w].time = state->time;
- psys_get_particle_on_path(sim, cpa->pa[w], keys + w, 1);
- w++;
- }
-
- /* get the original coordinates (orco) for texture usage */
- cpa_num = cpa->num;
-
- foffset = cpa->foffset;
- cpa_fuv = cpa->fuv;
- cpa_from = PART_FROM_FACE;
-
- psys_particle_on_emitter(psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa->fuv, foffset, co, 0, 0, 0, orco);
-
- /* we need to save the actual root position of the child for positioning it accurately to the surface of the emitter */
- //copy_v3_v3(cpa_1st, co);
-
- //mul_m4_v3(ob->obmat, cpa_1st);
-
- pa = psys->particles + cpa->parent;
-
- psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, par_co, 0, 0, 0, par_orco);
- if (part->type == PART_HAIR)
- psys_mat_hair_to_global(sim->ob, sim->psmd->mesh_final, psys->part->from, pa, hairmat);
- else
- unit_m4(hairmat);
-
- pa = 0;
- }
- else {
- /* get the parent state */
- keys->time = state->time;
- psys_get_particle_on_path(sim, cpa->parent, keys, 1);
-
- /* get the original coordinates (orco) for texture usage */
- pa = psys->particles + cpa->parent;
-
- cpa_from = part->from;
- cpa_num = pa->num;
- cpa_fuv = pa->fuv;
-
- psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, par_co, 0, 0, 0, par_orco);
- if (part->type == PART_HAIR) {
- psys_particle_on_emitter(psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa_fuv, pa->foffset, co, 0, 0, 0, orco);
- psys_mat_hair_to_global(sim->ob, sim->psmd->mesh_final, psys->part->from, pa, hairmat);
- }
- else {
- copy_v3_v3(orco, cpa->fuv);
- unit_m4(hairmat);
- }
- }
-
- /* get different child parameters from textures & vgroups */
- memset(&ctx, 0, sizeof(ParticleThreadContext));
- ctx.sim = *sim;
- ctx.mesh = psmd->mesh_final;
- ctx.ma = ma;
- /* TODO: assign vertex groups */
- get_child_modifier_parameters(part, &ctx, cpa, cpa_from, cpa_num, cpa_fuv, orco, &ptex);
-
- if (between) {
- int w = 0;
-
- state->co[0] = state->co[1] = state->co[2] = 0.0f;
- state->vel[0] = state->vel[1] = state->vel[2] = 0.0f;
-
- /* child position is the weighted sum of parent positions */
- while (w < 4 && cpa->pa[w] >= 0) {
- state->co[0] += cpa->w[w] * keys[w].co[0];
- state->co[1] += cpa->w[w] * keys[w].co[1];
- state->co[2] += cpa->w[w] * keys[w].co[2];
-
- state->vel[0] += cpa->w[w] * keys[w].vel[0];
- state->vel[1] += cpa->w[w] * keys[w].vel[1];
- state->vel[2] += cpa->w[w] * keys[w].vel[2];
- w++;
- }
- /* apply offset for correct positioning */
- //add_v3_v3(state->co, cpa_1st);
- }
- else {
- /* offset the child from the parent position */
- offset_child(cpa, keys, keys->rot, state, part->childflat, part->childrad);
- }
-
- par = keys;
-
- if (vel)
- copy_particle_key(&tstate, state, 1);
-
- /* apply different deformations to the child path */
- ParticleChildModifierContext modifier_ctx = {NULL};
- modifier_ctx.thread_ctx = NULL;
- modifier_ctx.sim = sim;
- modifier_ctx.ptex = &ptex;
- modifier_ctx.cpa = cpa;
- modifier_ctx.orco = orco;
- modifier_ctx.par_co = par->co;
- modifier_ctx.par_vel = par->vel;
- modifier_ctx.par_rot = par->rot;
- modifier_ctx.par_orco = par_orco;
- modifier_ctx.parent_keys = psys->childcache ? psys->childcache[p - totpart] : NULL;
- do_child_modifiers(&modifier_ctx, hairmat, state, t);
-
- /* try to estimate correct velocity */
- if (vel) {
- ParticleKey tstate_tmp;
- float length = len_v3(state->vel);
-
- if (t >= 0.001f) {
- tstate_tmp.time = t - 0.001f;
- psys_get_particle_on_path(sim, p, &tstate_tmp, 0);
- sub_v3_v3v3(state->vel, state->co, tstate_tmp.co);
- normalize_v3(state->vel);
- }
- else {
- tstate_tmp.time = t + 0.001f;
- psys_get_particle_on_path(sim, p, &tstate_tmp, 0);
- sub_v3_v3v3(state->vel, tstate_tmp.co, state->co);
- normalize_v3(state->vel);
- }
-
- mul_v3_fl(state->vel, length);
- }
- }
- }
+ PARTICLE_PSMD;
+ ParticleSystem *psys = sim->psys;
+ ParticleSettings *part = sim->psys->part;
+ Material *ma = give_current_material(sim->ob, part->omat);
+ ParticleData *pa;
+ ChildParticle *cpa;
+ ParticleTexture ptex;
+ ParticleKey *par = 0, keys[4], tstate;
+ ParticleThreadContext ctx; /* fake thread context for child modifiers */
+ ParticleInterpolationData pind;
+
+ float t;
+ float co[3], orco[3];
+ float hairmat[4][4];
+ int totpart = psys->totpart;
+ int totchild = psys->totchild;
+ short between = 0, edit = 0;
+
+ int keyed = part->phystype & PART_PHYS_KEYED && psys->flag & PSYS_KEYED;
+ int cached = !keyed && part->type != PART_HAIR;
+
+ float *cpa_fuv;
+ int cpa_num;
+ short cpa_from;
+
+ /* initialize keys to zero */
+ memset(keys, 0, 4 * sizeof(ParticleKey));
+
+ t = state->time;
+ CLAMP(t, 0.0f, 1.0f);
+
+ if (p < totpart) {
+ /* interpolate pathcache directly if it exist */
+ if (psys->pathcache) {
+ ParticleCacheKey result;
+ interpolate_pathcache(psys->pathcache[p], t, &result);
+ copy_v3_v3(state->co, result.co);
+ copy_v3_v3(state->vel, result.vel);
+ copy_qt_qt(state->rot, result.rot);
+ }
+ /* otherwise interpolate with other means */
+ else {
+ pa = psys->particles + p;
+
+ pind.keyed = keyed;
+ pind.cache = cached ? psys->pointcache : NULL;
+ pind.epoint = NULL;
+ pind.bspline = (psys->part->flag & PART_HAIR_BSPLINE);
+ /* pind.dm disabled in editmode means we don't get effectors taken into
+ * account when subdividing for instance */
+ pind.mesh = psys_in_edit_mode(sim->depsgraph, psys) ?
+ NULL :
+ psys->hair_out_mesh; /* XXX Sybren EEK */
+ init_particle_interpolation(sim->ob, psys, pa, &pind);
+ do_particle_interpolation(psys, p, pa, t, &pind, state);
+
+ if (pind.mesh) {
+ mul_m4_v3(sim->ob->obmat, state->co);
+ mul_mat3_m4_v3(sim->ob->obmat, state->vel);
+ }
+ else if (!keyed && !cached && !(psys->flag & PSYS_GLOBAL_HAIR)) {
+ if ((pa->flag & PARS_REKEY) == 0) {
+ psys_mat_hair_to_global(sim->ob, sim->psmd->mesh_final, part->from, pa, hairmat);
+ mul_m4_v3(hairmat, state->co);
+ mul_mat3_m4_v3(hairmat, state->vel);
+
+ if (sim->psys->effectors && (part->flag & PART_CHILD_GUIDE) == 0) {
+ do_guides(
+ sim->depsgraph, sim->psys->part, sim->psys->effectors, state, p, state->time);
+ /* TODO: proper velocity handling */
+ }
+
+ if (psys->lattice_deform_data && edit == 0)
+ calc_latt_deform(psys->lattice_deform_data, state->co, psys->lattice_strength);
+ }
+ }
+ }
+ }
+ else if (totchild) {
+ //invert_m4_m4(imat, ob->obmat);
+
+ /* interpolate childcache directly if it exists */
+ if (psys->childcache) {
+ ParticleCacheKey result;
+ interpolate_pathcache(psys->childcache[p - totpart], t, &result);
+ copy_v3_v3(state->co, result.co);
+ copy_v3_v3(state->vel, result.vel);
+ copy_qt_qt(state->rot, result.rot);
+ }
+ else {
+ float par_co[3], par_orco[3];
+
+ cpa = psys->child + p - totpart;
+
+ if (state->time < 0.0f)
+ t = psys_get_child_time(psys, cpa, -state->time, NULL, NULL);
+
+ if (totchild && part->childtype == PART_CHILD_FACES) {
+ /* part->parents could still be 0 so we can't test with totparent */
+ between = 1;
+ }
+ if (between) {
+ int w = 0;
+ float foffset;
+
+ /* get parent states */
+ while (w < 4 && cpa->pa[w] >= 0) {
+ keys[w].time = state->time;
+ psys_get_particle_on_path(sim, cpa->pa[w], keys + w, 1);
+ w++;
+ }
+
+ /* get the original coordinates (orco) for texture usage */
+ cpa_num = cpa->num;
+
+ foffset = cpa->foffset;
+ cpa_fuv = cpa->fuv;
+ cpa_from = PART_FROM_FACE;
+
+ psys_particle_on_emitter(
+ psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa->fuv, foffset, co, 0, 0, 0, orco);
+
+ /* we need to save the actual root position of the child for positioning it accurately to the surface of the emitter */
+ //copy_v3_v3(cpa_1st, co);
+
+ //mul_m4_v3(ob->obmat, cpa_1st);
+
+ pa = psys->particles + cpa->parent;
+
+ psys_particle_on_emitter(psmd,
+ part->from,
+ pa->num,
+ pa->num_dmcache,
+ pa->fuv,
+ pa->foffset,
+ par_co,
+ 0,
+ 0,
+ 0,
+ par_orco);
+ if (part->type == PART_HAIR)
+ psys_mat_hair_to_global(sim->ob, sim->psmd->mesh_final, psys->part->from, pa, hairmat);
+ else
+ unit_m4(hairmat);
+
+ pa = 0;
+ }
+ else {
+ /* get the parent state */
+ keys->time = state->time;
+ psys_get_particle_on_path(sim, cpa->parent, keys, 1);
+
+ /* get the original coordinates (orco) for texture usage */
+ pa = psys->particles + cpa->parent;
+
+ cpa_from = part->from;
+ cpa_num = pa->num;
+ cpa_fuv = pa->fuv;
+
+ psys_particle_on_emitter(psmd,
+ part->from,
+ pa->num,
+ pa->num_dmcache,
+ pa->fuv,
+ pa->foffset,
+ par_co,
+ 0,
+ 0,
+ 0,
+ par_orco);
+ if (part->type == PART_HAIR) {
+ psys_particle_on_emitter(
+ psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa_fuv, pa->foffset, co, 0, 0, 0, orco);
+ psys_mat_hair_to_global(sim->ob, sim->psmd->mesh_final, psys->part->from, pa, hairmat);
+ }
+ else {
+ copy_v3_v3(orco, cpa->fuv);
+ unit_m4(hairmat);
+ }
+ }
+
+ /* get different child parameters from textures & vgroups */
+ memset(&ctx, 0, sizeof(ParticleThreadContext));
+ ctx.sim = *sim;
+ ctx.mesh = psmd->mesh_final;
+ ctx.ma = ma;
+ /* TODO: assign vertex groups */
+ get_child_modifier_parameters(part, &ctx, cpa, cpa_from, cpa_num, cpa_fuv, orco, &ptex);
+
+ if (between) {
+ int w = 0;
+
+ state->co[0] = state->co[1] = state->co[2] = 0.0f;
+ state->vel[0] = state->vel[1] = state->vel[2] = 0.0f;
+
+ /* child position is the weighted sum of parent positions */
+ while (w < 4 && cpa->pa[w] >= 0) {
+ state->co[0] += cpa->w[w] * keys[w].co[0];
+ state->co[1] += cpa->w[w] * keys[w].co[1];
+ state->co[2] += cpa->w[w] * keys[w].co[2];
+
+ state->vel[0] += cpa->w[w] * keys[w].vel[0];
+ state->vel[1] += cpa->w[w] * keys[w].vel[1];
+ state->vel[2] += cpa->w[w] * keys[w].vel[2];
+ w++;
+ }
+ /* apply offset for correct positioning */
+ //add_v3_v3(state->co, cpa_1st);
+ }
+ else {
+ /* offset the child from the parent position */
+ offset_child(cpa, keys, keys->rot, state, part->childflat, part->childrad);
+ }
+
+ par = keys;
+
+ if (vel)
+ copy_particle_key(&tstate, state, 1);
+
+ /* apply different deformations to the child path */
+ ParticleChildModifierContext modifier_ctx = {NULL};
+ modifier_ctx.thread_ctx = NULL;
+ modifier_ctx.sim = sim;
+ modifier_ctx.ptex = &ptex;
+ modifier_ctx.cpa = cpa;
+ modifier_ctx.orco = orco;
+ modifier_ctx.par_co = par->co;
+ modifier_ctx.par_vel = par->vel;
+ modifier_ctx.par_rot = par->rot;
+ modifier_ctx.par_orco = par_orco;
+ modifier_ctx.parent_keys = psys->childcache ? psys->childcache[p - totpart] : NULL;
+ do_child_modifiers(&modifier_ctx, hairmat, state, t);
+
+ /* try to estimate correct velocity */
+ if (vel) {
+ ParticleKey tstate_tmp;
+ float length = len_v3(state->vel);
+
+ if (t >= 0.001f) {
+ tstate_tmp.time = t - 0.001f;
+ psys_get_particle_on_path(sim, p, &tstate_tmp, 0);
+ sub_v3_v3v3(state->vel, state->co, tstate_tmp.co);
+ normalize_v3(state->vel);
+ }
+ else {
+ tstate_tmp.time = t + 0.001f;
+ psys_get_particle_on_path(sim, p, &tstate_tmp, 0);
+ sub_v3_v3v3(state->vel, tstate_tmp.co, state->co);
+ normalize_v3(state->vel);
+ }
+
+ mul_v3_fl(state->vel, length);
+ }
+ }
+ }
}
/* gets particle's state at a time, returns 1 if particle exists and can be seen and 0 if not */
int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *state, int always)
{
- ParticleSystem *psys = sim->psys;
- ParticleSettings *part = psys->part;
- ParticleData *pa = NULL;
- ChildParticle *cpa = NULL;
- float cfra;
- int totpart = psys->totpart;
- float timestep = psys_get_timestep(sim);
-
- /* negative time means "use current time" */
- cfra = state->time > 0 ? state->time : DEG_get_ctime(sim->depsgraph);
-
- if (p >= totpart) {
- if (!psys->totchild)
- return 0;
-
- if (part->childtype == PART_CHILD_FACES) {
- if (!(psys->flag & PSYS_KEYED))
- return 0;
-
- cpa = psys->child + p - totpart;
-
- state->time = psys_get_child_time(psys, cpa, cfra, NULL, NULL);
-
- if (!always) {
- if ((state->time < 0.0f && !(part->flag & PART_UNBORN)) ||
- (state->time > 1.0f && !(part->flag & PART_DIED)))
- {
- return 0;
- }
- }
-
- state->time = (cfra - (part->sta + (part->end - part->sta) * psys_frand(psys, p + 23))) / (part->lifetime * psys_frand(psys, p + 24));
-
- psys_get_particle_on_path(sim, p, state, 1);
- return 1;
- }
- else {
- cpa = sim->psys->child + p - totpart;
- pa = sim->psys->particles + cpa->parent;
- }
- }
- else {
- pa = sim->psys->particles + p;
- }
-
- if (pa) {
- if (!always) {
- if ((cfra < pa->time && (part->flag & PART_UNBORN) == 0) ||
- (cfra >= pa->dietime && (part->flag & PART_DIED) == 0))
- {
- return 0;
- }
- }
-
- cfra = MIN2(cfra, pa->dietime);
- }
-
- if (sim->psys->flag & PSYS_KEYED) {
- state->time = -cfra;
- psys_get_particle_on_path(sim, p, state, 1);
- return 1;
- }
- else {
- if (cpa) {
- float mat[4][4];
- ParticleKey *key1;
- float t = (cfra - pa->time) / pa->lifetime;
- float par_orco[3] = {0.0f, 0.0f, 0.0f};
-
- key1 = &pa->state;
- offset_child(cpa, key1, key1->rot, state, part->childflat, part->childrad);
-
- CLAMP(t, 0.0f, 1.0f);
-
- unit_m4(mat);
- ParticleChildModifierContext modifier_ctx = {NULL};
- modifier_ctx.thread_ctx = NULL;
- modifier_ctx.sim = sim;
- modifier_ctx.ptex = NULL;
- modifier_ctx.cpa = cpa;
- modifier_ctx.orco = cpa->fuv;
- modifier_ctx.par_co = key1->co;
- modifier_ctx.par_vel = key1->vel;
- modifier_ctx.par_rot = key1->rot;
- modifier_ctx.par_orco = par_orco;
- modifier_ctx.parent_keys = psys->childcache ? psys->childcache[p - totpart] : NULL;
-
- do_child_modifiers(&modifier_ctx, mat, state, t);
-
- if (psys->lattice_deform_data)
- calc_latt_deform(psys->lattice_deform_data, state->co, psys->lattice_strength);
- }
- else {
- if (pa->state.time == cfra || ELEM(part->phystype, PART_PHYS_NO, PART_PHYS_KEYED))
- copy_particle_key(state, &pa->state, 1);
- else if (pa->prev_state.time == cfra)
- copy_particle_key(state, &pa->prev_state, 1);
- else {
- float dfra, frs_sec = sim->scene->r.frs_sec;
- /* let's interpolate to try to be as accurate as possible */
- if (pa->state.time + 2.f >= state->time && pa->prev_state.time - 2.f <= state->time) {
- if (pa->prev_state.time >= pa->state.time || pa->prev_state.time < 0.f) {
- /* prev_state is wrong so let's not use it, this can happen at frames 1, 0 or particle birth */
- dfra = state->time - pa->state.time;
-
- copy_particle_key(state, &pa->state, 1);
-
- madd_v3_v3v3fl(state->co, state->co, state->vel, dfra / frs_sec);
- }
- else {
- ParticleKey keys[4];
- float keytime;
-
- copy_particle_key(keys + 1, &pa->prev_state, 1);
- copy_particle_key(keys + 2, &pa->state, 1);
-
- dfra = keys[2].time - keys[1].time;
-
- keytime = (state->time - keys[1].time) / dfra;
-
- /* convert velocity to timestep size */
- mul_v3_fl(keys[1].vel, dfra * timestep);
- mul_v3_fl(keys[2].vel, dfra * timestep);
-
- psys_interpolate_particle(-1, keys, keytime, state, 1);
-
- /* convert back to real velocity */
- mul_v3_fl(state->vel, 1.f / (dfra * timestep));
-
- interp_v3_v3v3(state->ave, keys[1].ave, keys[2].ave, keytime);
- interp_qt_qtqt(state->rot, keys[1].rot, keys[2].rot, keytime);
- }
- }
- else if (pa->state.time + 1.f >= state->time && pa->state.time - 1.f <= state->time) {
- /* linear interpolation using only pa->state */
-
- dfra = state->time - pa->state.time;
-
- copy_particle_key(state, &pa->state, 1);
-
- madd_v3_v3v3fl(state->co, state->co, state->vel, dfra / frs_sec);
- }
- else {
- /* extrapolating over big ranges is not accurate so let's just give something close to reasonable back */
- copy_particle_key(state, &pa->state, 0);
- }
- }
-
- if (sim->psys->lattice_deform_data)
- calc_latt_deform(sim->psys->lattice_deform_data, state->co, psys->lattice_strength);
- }
-
- return 1;
- }
+ ParticleSystem *psys = sim->psys;
+ ParticleSettings *part = psys->part;
+ ParticleData *pa = NULL;
+ ChildParticle *cpa = NULL;
+ float cfra;
+ int totpart = psys->totpart;
+ float timestep = psys_get_timestep(sim);
+
+ /* negative time means "use current time" */
+ cfra = state->time > 0 ? state->time : DEG_get_ctime(sim->depsgraph);
+
+ if (p >= totpart) {
+ if (!psys->totchild)
+ return 0;
+
+ if (part->childtype == PART_CHILD_FACES) {
+ if (!(psys->flag & PSYS_KEYED))
+ return 0;
+
+ cpa = psys->child + p - totpart;
+
+ state->time = psys_get_child_time(psys, cpa, cfra, NULL, NULL);
+
+ if (!always) {
+ if ((state->time < 0.0f && !(part->flag & PART_UNBORN)) ||
+ (state->time > 1.0f && !(part->flag & PART_DIED))) {
+ return 0;
+ }
+ }
+
+ state->time = (cfra - (part->sta + (part->end - part->sta) * psys_frand(psys, p + 23))) /
+ (part->lifetime * psys_frand(psys, p + 24));
+
+ psys_get_particle_on_path(sim, p, state, 1);
+ return 1;
+ }
+ else {
+ cpa = sim->psys->child + p - totpart;
+ pa = sim->psys->particles + cpa->parent;
+ }
+ }
+ else {
+ pa = sim->psys->particles + p;
+ }
+
+ if (pa) {
+ if (!always) {
+ if ((cfra < pa->time && (part->flag & PART_UNBORN) == 0) ||
+ (cfra >= pa->dietime && (part->flag & PART_DIED) == 0)) {
+ return 0;
+ }
+ }
+
+ cfra = MIN2(cfra, pa->dietime);
+ }
+
+ if (sim->psys->flag & PSYS_KEYED) {
+ state->time = -cfra;
+ psys_get_particle_on_path(sim, p, state, 1);
+ return 1;
+ }
+ else {
+ if (cpa) {
+ float mat[4][4];
+ ParticleKey *key1;
+ float t = (cfra - pa->time) / pa->lifetime;
+ float par_orco[3] = {0.0f, 0.0f, 0.0f};
+
+ key1 = &pa->state;
+ offset_child(cpa, key1, key1->rot, state, part->childflat, part->childrad);
+
+ CLAMP(t, 0.0f, 1.0f);
+
+ unit_m4(mat);
+ ParticleChildModifierContext modifier_ctx = {NULL};
+ modifier_ctx.thread_ctx = NULL;
+ modifier_ctx.sim = sim;
+ modifier_ctx.ptex = NULL;
+ modifier_ctx.cpa = cpa;
+ modifier_ctx.orco = cpa->fuv;
+ modifier_ctx.par_co = key1->co;
+ modifier_ctx.par_vel = key1->vel;
+ modifier_ctx.par_rot = key1->rot;
+ modifier_ctx.par_orco = par_orco;
+ modifier_ctx.parent_keys = psys->childcache ? psys->childcache[p - totpart] : NULL;
+
+ do_child_modifiers(&modifier_ctx, mat, state, t);
+
+ if (psys->lattice_deform_data)
+ calc_latt_deform(psys->lattice_deform_data, state->co, psys->lattice_strength);
+ }
+ else {
+ if (pa->state.time == cfra || ELEM(part->phystype, PART_PHYS_NO, PART_PHYS_KEYED))
+ copy_particle_key(state, &pa->state, 1);
+ else if (pa->prev_state.time == cfra)
+ copy_particle_key(state, &pa->prev_state, 1);
+ else {
+ float dfra, frs_sec = sim->scene->r.frs_sec;
+ /* let's interpolate to try to be as accurate as possible */
+ if (pa->state.time + 2.f >= state->time && pa->prev_state.time - 2.f <= state->time) {
+ if (pa->prev_state.time >= pa->state.time || pa->prev_state.time < 0.f) {
+ /* prev_state is wrong so let's not use it, this can happen at frames 1, 0 or particle birth */
+ dfra = state->time - pa->state.time;
+
+ copy_particle_key(state, &pa->state, 1);
+
+ madd_v3_v3v3fl(state->co, state->co, state->vel, dfra / frs_sec);
+ }
+ else {
+ ParticleKey keys[4];
+ float keytime;
+
+ copy_particle_key(keys + 1, &pa->prev_state, 1);
+ copy_particle_key(keys + 2, &pa->state, 1);
+
+ dfra = keys[2].time - keys[1].time;
+
+ keytime = (state->time - keys[1].time) / dfra;
+
+ /* convert velocity to timestep size */
+ mul_v3_fl(keys[1].vel, dfra * timestep);
+ mul_v3_fl(keys[2].vel, dfra * timestep);
+
+ psys_interpolate_particle(-1, keys, keytime, state, 1);
+
+ /* convert back to real velocity */
+ mul_v3_fl(state->vel, 1.f / (dfra * timestep));
+
+ interp_v3_v3v3(state->ave, keys[1].ave, keys[2].ave, keytime);
+ interp_qt_qtqt(state->rot, keys[1].rot, keys[2].rot, keytime);
+ }
+ }
+ else if (pa->state.time + 1.f >= state->time && pa->state.time - 1.f <= state->time) {
+ /* linear interpolation using only pa->state */
+
+ dfra = state->time - pa->state.time;
+
+ copy_particle_key(state, &pa->state, 1);
+
+ madd_v3_v3v3fl(state->co, state->co, state->vel, dfra / frs_sec);
+ }
+ else {
+ /* extrapolating over big ranges is not accurate so let's just give something close to reasonable back */
+ copy_particle_key(state, &pa->state, 0);
+ }
+ }
+
+ if (sim->psys->lattice_deform_data)
+ calc_latt_deform(sim->psys->lattice_deform_data, state->co, psys->lattice_strength);
+ }
+
+ return 1;
+ }
}
-void psys_get_dupli_texture(ParticleSystem *psys, ParticleSettings *part,
- ParticleSystemModifierData *psmd, ParticleData *pa, ChildParticle *cpa,
- float uv[2], float orco[3])
+void psys_get_dupli_texture(ParticleSystem *psys,
+ ParticleSettings *part,
+ ParticleSystemModifierData *psmd,
+ ParticleData *pa,
+ ChildParticle *cpa,
+ float uv[2],
+ float orco[3])
{
- MFace *mface;
- MTFace *mtface;
- float loc[3];
- int num;
-
- /* XXX: on checking '(psmd->dm != NULL)'
- * This is incorrect but needed for metaball evaluation.
- * Ideally this would be calculated via the depsgraph, however with metaballs,
- * the entire scenes dupli's are scanned, which also looks into uncalculated data.
- *
- * For now just include this workaround as an alternative to crashing,
- * but longer term metaballs should behave in a more manageable way, see: T46622. */
-
- uv[0] = uv[1] = 0.f;
-
- /* Grid distribution doesn't support UV or emit from vertex mode */
- bool is_grid = (part->distr == PART_DISTR_GRID && part->from != PART_FROM_VERT);
-
- if (cpa) {
- if ((part->childtype == PART_CHILD_FACES) && (psmd->mesh_final != NULL)) {
- CustomData *mtf_data = &psmd->mesh_final->fdata;
- const int uv_idx = CustomData_get_render_layer(mtf_data, CD_MTFACE);
- mtface = CustomData_get_layer_n(mtf_data, CD_MTFACE, uv_idx);
-
- if (mtface && !is_grid) {
- mface = CustomData_get(&psmd->mesh_final->fdata, cpa->num, CD_MFACE);
- mtface += cpa->num;
- psys_interpolate_uvs(mtface, mface->v4, cpa->fuv, uv);
- }
-
- psys_particle_on_emitter(psmd, PART_FROM_FACE, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, loc, 0, 0, 0, orco);
- return;
- }
- else {
- pa = psys->particles + cpa->pa[0];
- }
- }
-
- if ((part->from == PART_FROM_FACE) && (psmd->mesh_final != NULL) && !is_grid) {
- CustomData *mtf_data = &psmd->mesh_final->fdata;
- const int uv_idx = CustomData_get_render_layer(mtf_data, CD_MTFACE);
- mtface = CustomData_get_layer_n(mtf_data, CD_MTFACE, uv_idx);
-
- num = pa->num_dmcache;
-
- if (num == DMCACHE_NOTFOUND)
- num = pa->num;
-
- if (num >= psmd->mesh_final->totface) {
- /* happens when simplify is enabled
- * gives invalid coords but would crash otherwise */
- num = DMCACHE_NOTFOUND;
- }
-
- if (mtface && !ELEM(num, DMCACHE_NOTFOUND, DMCACHE_ISCHILD)) {
- mface = CustomData_get(&psmd->mesh_final->fdata, num, CD_MFACE);
- mtface += num;
- psys_interpolate_uvs(mtface, mface->v4, pa->fuv, uv);
- }
- }
-
- psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, loc, 0, 0, 0, orco);
+ MFace *mface;
+ MTFace *mtface;
+ float loc[3];
+ int num;
+
+ /* XXX: on checking '(psmd->dm != NULL)'
+ * This is incorrect but needed for metaball evaluation.
+ * Ideally this would be calculated via the depsgraph, however with metaballs,
+ * the entire scenes dupli's are scanned, which also looks into uncalculated data.
+ *
+ * For now just include this workaround as an alternative to crashing,
+ * but longer term metaballs should behave in a more manageable way, see: T46622. */
+
+ uv[0] = uv[1] = 0.f;
+
+ /* Grid distribution doesn't support UV or emit from vertex mode */
+ bool is_grid = (part->distr == PART_DISTR_GRID && part->from != PART_FROM_VERT);
+
+ if (cpa) {
+ if ((part->childtype == PART_CHILD_FACES) && (psmd->mesh_final != NULL)) {
+ CustomData *mtf_data = &psmd->mesh_final->fdata;
+ const int uv_idx = CustomData_get_render_layer(mtf_data, CD_MTFACE);
+ mtface = CustomData_get_layer_n(mtf_data, CD_MTFACE, uv_idx);
+
+ if (mtface && !is_grid) {
+ mface = CustomData_get(&psmd->mesh_final->fdata, cpa->num, CD_MFACE);
+ mtface += cpa->num;
+ psys_interpolate_uvs(mtface, mface->v4, cpa->fuv, uv);
+ }
+
+ psys_particle_on_emitter(psmd,
+ PART_FROM_FACE,
+ cpa->num,
+ DMCACHE_ISCHILD,
+ cpa->fuv,
+ cpa->foffset,
+ loc,
+ 0,
+ 0,
+ 0,
+ orco);
+ return;
+ }
+ else {
+ pa = psys->particles + cpa->pa[0];
+ }
+ }
+
+ if ((part->from == PART_FROM_FACE) && (psmd->mesh_final != NULL) && !is_grid) {
+ CustomData *mtf_data = &psmd->mesh_final->fdata;
+ const int uv_idx = CustomData_get_render_layer(mtf_data, CD_MTFACE);
+ mtface = CustomData_get_layer_n(mtf_data, CD_MTFACE, uv_idx);
+
+ num = pa->num_dmcache;
+
+ if (num == DMCACHE_NOTFOUND)
+ num = pa->num;
+
+ if (num >= psmd->mesh_final->totface) {
+ /* happens when simplify is enabled
+ * gives invalid coords but would crash otherwise */
+ num = DMCACHE_NOTFOUND;
+ }
+
+ if (mtface && !ELEM(num, DMCACHE_NOTFOUND, DMCACHE_ISCHILD)) {
+ mface = CustomData_get(&psmd->mesh_final->fdata, num, CD_MFACE);
+ mtface += num;
+ psys_interpolate_uvs(mtface, mface->v4, pa->fuv, uv);
+ }
+ }
+
+ psys_particle_on_emitter(
+ psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, loc, 0, 0, 0, orco);
}
-void psys_get_dupli_path_transform(ParticleSimulationData *sim, ParticleData *pa, ChildParticle *cpa, ParticleCacheKey *cache, float mat[4][4], float *scale)
+void psys_get_dupli_path_transform(ParticleSimulationData *sim,
+ ParticleData *pa,
+ ChildParticle *cpa,
+ ParticleCacheKey *cache,
+ float mat[4][4],
+ float *scale)
{
- Object *ob = sim->ob;
- ParticleSystem *psys = sim->psys;
- ParticleSystemModifierData *psmd = sim->psmd;
- float loc[3], nor[3], vec[3], side[3], len;
- float xvec[3] = {-1.0, 0.0, 0.0}, nmat[3][3];
-
- sub_v3_v3v3(vec, (cache + cache->segments)->co, cache->co);
- len = normalize_v3(vec);
-
- if (pa == NULL && psys->part->childflat != PART_CHILD_FACES)
- pa = psys->particles + cpa->pa[0];
-
- if (pa)
- psys_particle_on_emitter(psmd, sim->psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, loc, nor, 0, 0, 0);
- else
- psys_particle_on_emitter(psmd, PART_FROM_FACE, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, loc, nor, 0, 0, 0);
-
- if (psys->part->rotmode == PART_ROT_VEL) {
- transpose_m3_m4(nmat, ob->imat);
- mul_m3_v3(nmat, nor);
- normalize_v3(nor);
-
- /* make sure that we get a proper side vector */
- if (fabsf(dot_v3v3(nor, vec)) > 0.999999f) {
- if (fabsf(dot_v3v3(nor, xvec)) > 0.999999f) {
- nor[0] = 0.0f;
- nor[1] = 1.0f;
- nor[2] = 0.0f;
- }
- else {
- nor[0] = 1.0f;
- nor[1] = 0.0f;
- nor[2] = 0.0f;
- }
- }
- cross_v3_v3v3(side, nor, vec);
- normalize_v3(side);
-
- /* rotate side vector around vec */
- if (psys->part->phasefac != 0) {
- float q_phase[4];
- float phasefac = psys->part->phasefac;
- if (psys->part->randphasefac != 0.0f)
- phasefac += psys->part->randphasefac * psys_frand(psys, (pa - psys->particles) + 20);
- axis_angle_to_quat(q_phase, vec, phasefac * (float)M_PI);
-
- mul_qt_v3(q_phase, side);
- }
-
- cross_v3_v3v3(nor, vec, side);
-
- unit_m4(mat);
- copy_v3_v3(mat[0], vec);
- copy_v3_v3(mat[1], side);
- copy_v3_v3(mat[2], nor);
- }
- else {
- quat_to_mat4(mat, pa->state.rot);
- }
-
- *scale = len;
+ Object *ob = sim->ob;
+ ParticleSystem *psys = sim->psys;
+ ParticleSystemModifierData *psmd = sim->psmd;
+ float loc[3], nor[3], vec[3], side[3], len;
+ float xvec[3] = {-1.0, 0.0, 0.0}, nmat[3][3];
+
+ sub_v3_v3v3(vec, (cache + cache->segments)->co, cache->co);
+ len = normalize_v3(vec);
+
+ if (pa == NULL && psys->part->childflat != PART_CHILD_FACES)
+ pa = psys->particles + cpa->pa[0];
+
+ if (pa)
+ psys_particle_on_emitter(psmd,
+ sim->psys->part->from,
+ pa->num,
+ pa->num_dmcache,
+ pa->fuv,
+ pa->foffset,
+ loc,
+ nor,
+ 0,
+ 0,
+ 0);
+ else
+ psys_particle_on_emitter(psmd,
+ PART_FROM_FACE,
+ cpa->num,
+ DMCACHE_ISCHILD,
+ cpa->fuv,
+ cpa->foffset,
+ loc,
+ nor,
+ 0,
+ 0,
+ 0);
+
+ if (psys->part->rotmode == PART_ROT_VEL) {
+ transpose_m3_m4(nmat, ob->imat);
+ mul_m3_v3(nmat, nor);
+ normalize_v3(nor);
+
+ /* make sure that we get a proper side vector */
+ if (fabsf(dot_v3v3(nor, vec)) > 0.999999f) {
+ if (fabsf(dot_v3v3(nor, xvec)) > 0.999999f) {
+ nor[0] = 0.0f;
+ nor[1] = 1.0f;
+ nor[2] = 0.0f;
+ }
+ else {
+ nor[0] = 1.0f;
+ nor[1] = 0.0f;
+ nor[2] = 0.0f;
+ }
+ }
+ cross_v3_v3v3(side, nor, vec);
+ normalize_v3(side);
+
+ /* rotate side vector around vec */
+ if (psys->part->phasefac != 0) {
+ float q_phase[4];
+ float phasefac = psys->part->phasefac;
+ if (psys->part->randphasefac != 0.0f)
+ phasefac += psys->part->randphasefac * psys_frand(psys, (pa - psys->particles) + 20);
+ axis_angle_to_quat(q_phase, vec, phasefac * (float)M_PI);
+
+ mul_qt_v3(q_phase, side);
+ }
+
+ cross_v3_v3v3(nor, vec, side);
+
+ unit_m4(mat);
+ copy_v3_v3(mat[0], vec);
+ copy_v3_v3(mat[1], side);
+ copy_v3_v3(mat[2], nor);
+ }
+ else {
+ quat_to_mat4(mat, pa->state.rot);
+ }
+
+ *scale = len;
}
void psys_apply_hair_lattice(Depsgraph *depsgraph, Scene *scene, Object *ob, ParticleSystem *psys)
{
- ParticleSimulationData sim = {0};
- sim.depsgraph = depsgraph;
- sim.scene = scene;
- sim.ob = ob;
- sim.psys = psys;
- sim.psmd = psys_get_modifier(ob, psys);
-
- psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
-
- if (psys->lattice_deform_data) {
- ParticleData *pa = psys->particles;
- HairKey *hkey;
- int p, h;
- float hairmat[4][4], imat[4][4];
-
- for (p = 0; p < psys->totpart; p++, pa++) {
- psys_mat_hair_to_global(sim.ob, sim.psmd->mesh_final, psys->part->from, pa, hairmat);
- invert_m4_m4(imat, hairmat);
-
- hkey = pa->hair;
- for (h = 0; h < pa->totkey; h++, hkey++) {
- mul_m4_v3(hairmat, hkey->co);
- calc_latt_deform(psys->lattice_deform_data, hkey->co, psys->lattice_strength);
- mul_m4_v3(imat, hkey->co);
- }
- }
-
- end_latt_deform(psys->lattice_deform_data);
- psys->lattice_deform_data = NULL;
-
- /* protect the applied shape */
- psys->flag |= PSYS_EDITED;
- }
+ ParticleSimulationData sim = {0};
+ sim.depsgraph = depsgraph;
+ sim.scene = scene;
+ sim.ob = ob;
+ sim.psys = psys;
+ sim.psmd = psys_get_modifier(ob, psys);
+
+ psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
+
+ if (psys->lattice_deform_data) {
+ ParticleData *pa = psys->particles;
+ HairKey *hkey;
+ int p, h;
+ float hairmat[4][4], imat[4][4];
+
+ for (p = 0; p < psys->totpart; p++, pa++) {
+ psys_mat_hair_to_global(sim.ob, sim.psmd->mesh_final, psys->part->from, pa, hairmat);
+ invert_m4_m4(imat, hairmat);
+
+ hkey = pa->hair;
+ for (h = 0; h < pa->totkey; h++, hkey++) {
+ mul_m4_v3(hairmat, hkey->co);
+ calc_latt_deform(psys->lattice_deform_data, hkey->co, psys->lattice_strength);
+ mul_m4_v3(imat, hkey->co);
+ }
+ }
+
+ end_latt_deform(psys->lattice_deform_data);
+ psys->lattice_deform_data = NULL;
+
+ /* protect the applied shape */
+ psys->flag |= PSYS_EDITED;
+ }
}
-
-
/* Draw Engine */
void (*BKE_particle_batch_cache_dirty_tag_cb)(ParticleSystem *psys, int mode) = NULL;
void (*BKE_particle_batch_cache_free_cb)(ParticleSystem *psys) = NULL;
void BKE_particle_batch_cache_dirty_tag(ParticleSystem *psys, int mode)
{
- if (psys->batch_cache) {
- BKE_particle_batch_cache_dirty_tag_cb(psys, mode);
- }
+ if (psys->batch_cache) {
+ BKE_particle_batch_cache_dirty_tag_cb(psys, mode);
+ }
}
void BKE_particle_batch_cache_free(ParticleSystem *psys)
{
- if (psys->batch_cache) {
- BKE_particle_batch_cache_free_cb(psys);
- }
+ if (psys->batch_cache) {
+ BKE_particle_batch_cache_free_cb(psys);
+ }
}
diff --git a/source/blender/blenkernel/intern/particle_child.c b/source/blender/blenkernel/intern/particle_child.c
index e5d25efe3d5..c967449248d 100644
--- a/source/blender/blenkernel/intern/particle_child.c
+++ b/source/blender/blenkernel/intern/particle_child.c
@@ -34,796 +34,873 @@
/* ------------------------------------------------------------------------- */
typedef struct ParticlePathIterator {
- ParticleCacheKey *key;
- int index;
- float time;
+ ParticleCacheKey *key;
+ int index;
+ float time;
- ParticleCacheKey *parent_key;
- float parent_rotation[4];
+ ParticleCacheKey *parent_key;
+ float parent_rotation[4];
} ParticlePathIterator;
-static void psys_path_iter_get(ParticlePathIterator *iter, ParticleCacheKey *keys, int totkeys,
- ParticleCacheKey *parent, int index)
+static void psys_path_iter_get(ParticlePathIterator *iter,
+ ParticleCacheKey *keys,
+ int totkeys,
+ ParticleCacheKey *parent,
+ int index)
{
- BLI_assert(index >= 0 && index < totkeys);
-
- iter->key = keys + index;
- iter->index = index;
- iter->time = (float)index / (float)(totkeys - 1);
-
- if (parent) {
- iter->parent_key = parent + index;
- if (index > 0)
- mul_qt_qtqt(iter->parent_rotation, iter->parent_key->rot, parent->rot);
- else
- copy_qt_qt(iter->parent_rotation, parent->rot);
- }
- else {
- iter->parent_key = NULL;
- unit_qt(iter->parent_rotation);
- }
+ BLI_assert(index >= 0 && index < totkeys);
+
+ iter->key = keys + index;
+ iter->index = index;
+ iter->time = (float)index / (float)(totkeys - 1);
+
+ if (parent) {
+ iter->parent_key = parent + index;
+ if (index > 0)
+ mul_qt_qtqt(iter->parent_rotation, iter->parent_key->rot, parent->rot);
+ else
+ copy_qt_qt(iter->parent_rotation, parent->rot);
+ }
+ else {
+ iter->parent_key = NULL;
+ unit_qt(iter->parent_rotation);
+ }
}
typedef struct ParticlePathModifier {
- struct ParticlePathModifier *next, *prev;
+ struct ParticlePathModifier *next, *prev;
- void (*apply)(ParticleCacheKey *keys, int totkeys, ParticleCacheKey *parent_keys);
+ void (*apply)(ParticleCacheKey *keys, int totkeys, ParticleCacheKey *parent_keys);
} ParticlePathModifier;
/* ------------------------------------------------------------------------- */
-static void do_kink_spiral_deform(ParticleKey *state, const float dir[3], const float kink[3],
- float time, float freq, float shape, float amplitude,
+static void do_kink_spiral_deform(ParticleKey *state,
+ const float dir[3],
+ const float kink[3],
+ float time,
+ float freq,
+ float shape,
+ float amplitude,
const float spiral_start[3])
{
- float result[3];
+ float result[3];
- CLAMP(time, 0.f, 1.f);
+ CLAMP(time, 0.f, 1.f);
- copy_v3_v3(result, state->co);
+ copy_v3_v3(result, state->co);
- {
- /* Creates a logarithmic spiral:
- * r(theta) = a * exp(b * theta)
- *
- * The "density" parameter b is defined by the shape parameter
- * and goes up to the Golden Spiral for 1.0
- * https://en.wikipedia.org/wiki/Golden_spiral
- */
- const float b = shape * (1.0f + sqrtf(5.0f)) / (float)M_PI * 0.25f;
- /* angle of the spiral against the curve (rotated opposite to make a smooth transition) */
- const float start_angle = ((b != 0.0f) ? atanf(1.0f / b) :
- (float)-M_PI_2) + (b > 0.0f ? -(float)M_PI_2 : (float)M_PI_2);
+ {
+ /* Creates a logarithmic spiral:
+ * r(theta) = a * exp(b * theta)
+ *
+ * The "density" parameter b is defined by the shape parameter
+ * and goes up to the Golden Spiral for 1.0
+ * https://en.wikipedia.org/wiki/Golden_spiral
+ */
+ const float b = shape * (1.0f + sqrtf(5.0f)) / (float)M_PI * 0.25f;
+ /* angle of the spiral against the curve (rotated opposite to make a smooth transition) */
+ const float start_angle = ((b != 0.0f) ? atanf(1.0f / b) : (float)-M_PI_2) +
+ (b > 0.0f ? -(float)M_PI_2 : (float)M_PI_2);
- float spiral_axis[3], rot[3][3];
- float vec[3];
+ float spiral_axis[3], rot[3][3];
+ float vec[3];
- float theta = freq * time * 2.0f * (float)M_PI;
- float radius = amplitude * expf(b * theta);
+ float theta = freq * time * 2.0f * (float)M_PI;
+ float radius = amplitude * expf(b * theta);
- /* a bit more intuitive than using negative frequency for this */
- if (amplitude < 0.0f)
- theta = -theta;
+ /* a bit more intuitive than using negative frequency for this */
+ if (amplitude < 0.0f)
+ theta = -theta;
- cross_v3_v3v3(spiral_axis, dir, kink);
- normalize_v3(spiral_axis);
+ cross_v3_v3v3(spiral_axis, dir, kink);
+ normalize_v3(spiral_axis);
- mul_v3_v3fl(vec, kink, -radius);
+ mul_v3_v3fl(vec, kink, -radius);
- axis_angle_normalized_to_mat3(rot, spiral_axis, theta);
- mul_m3_v3(rot, vec);
+ axis_angle_normalized_to_mat3(rot, spiral_axis, theta);
+ mul_m3_v3(rot, vec);
- madd_v3_v3fl(vec, kink, amplitude);
+ madd_v3_v3fl(vec, kink, amplitude);
- axis_angle_normalized_to_mat3(rot, spiral_axis, -start_angle);
- mul_m3_v3(rot, vec);
+ axis_angle_normalized_to_mat3(rot, spiral_axis, -start_angle);
+ mul_m3_v3(rot, vec);
- add_v3_v3v3(result, spiral_start, vec);
- }
+ add_v3_v3v3(result, spiral_start, vec);
+ }
- copy_v3_v3(state->co, result);
+ copy_v3_v3(state->co, result);
}
-static void do_kink_spiral(ParticleThreadContext *ctx, ParticleTexture *ptex, const float parent_orco[3],
- ChildParticle *cpa, const float orco[3], float hairmat[4][4],
- ParticleCacheKey *keys, ParticleCacheKey *parent_keys, int *r_totkeys, float *r_max_length)
+static void do_kink_spiral(ParticleThreadContext *ctx,
+ ParticleTexture *ptex,
+ const float parent_orco[3],
+ ChildParticle *cpa,
+ const float orco[3],
+ float hairmat[4][4],
+ ParticleCacheKey *keys,
+ ParticleCacheKey *parent_keys,
+ int *r_totkeys,
+ float *r_max_length)
{
- struct ParticleSettings *part = ctx->sim.psys->part;
- const int seed = ctx->sim.psys->child_seed + (int)(cpa - ctx->sim.psys->child);
- const int totkeys = ctx->segments + 1;
- const int extrakeys = ctx->extra_segments;
-
- float kink_amp_random = part->kink_amp_random;
- float kink_amp = part->kink_amp * (1.0f - kink_amp_random * psys_frand(ctx->sim.psys, 93541 + seed));
- float kink_freq = part->kink_freq;
- float kink_shape = part->kink_shape;
- float kink_axis_random = part->kink_axis_random;
- float rough1 = part->rough1;
- float rough2 = part->rough2;
- float rough_end = part->rough_end;
-
- ParticlePathIterator iter;
- ParticleCacheKey *key;
- int k;
-
- float dir[3];
- float spiral_start[3] = {0.0f, 0.0f, 0.0f};
- float spiral_start_time = 0.0f;
- float spiral_par_co[3] = {0.0f, 0.0f, 0.0f};
- float spiral_par_vel[3] = {0.0f, 0.0f, 0.0f};
- float spiral_par_rot[4] = {1.0f, 0.0f, 0.0f, 0.0f};
- float totlen;
- float cut_time;
- int start_index = 0, end_index = 0;
- float kink_base[3];
-
- if (ptex) {
- kink_amp *= ptex->kink_amp;
- kink_freq *= ptex->kink_freq;
- rough1 *= ptex->rough1;
- rough2 *= ptex->rough2;
- rough_end *= ptex->roughe;
- }
-
- cut_time = (totkeys - 1) * ptex->length;
- zero_v3(spiral_start);
-
- for (k = 0, key = keys; k < totkeys-1; k++, key++) {
- if ((float)(k + 1) >= cut_time) {
- float fac = cut_time - (float)k;
- ParticleCacheKey *par = parent_keys + k;
-
- start_index = k + 1;
- end_index = start_index + extrakeys;
-
- spiral_start_time = ((float)k + fac) / (float)(totkeys - 1);
- interp_v3_v3v3(spiral_start, key->co, (key+1)->co, fac);
-
- interp_v3_v3v3(spiral_par_co, par->co, (par+1)->co, fac);
- interp_v3_v3v3(spiral_par_vel, par->vel, (par+1)->vel, fac);
- interp_qt_qtqt(spiral_par_rot, par->rot, (par+1)->rot, fac);
-
- break;
- }
- }
-
- zero_v3(dir);
-
- zero_v3(kink_base);
- kink_base[part->kink_axis] = 1.0f;
- mul_mat3_m4_v3(ctx->sim.ob->obmat, kink_base);
-
- /* Fill in invariant part of modifier context. */
- ParticleChildModifierContext modifier_ctx = {NULL};
- modifier_ctx.thread_ctx = ctx;
- modifier_ctx.sim = &ctx->sim;
- modifier_ctx.ptex = ptex;
- modifier_ctx.cpa = cpa;
- modifier_ctx.orco = orco;
- modifier_ctx.parent_keys = parent_keys;
-
- for (k = 0, key = keys; k < end_index; k++, key++) {
- float par_time;
- float *par_co, *par_vel, *par_rot;
-
- psys_path_iter_get(&iter, keys, end_index, NULL, k);
- if (k < start_index) {
- sub_v3_v3v3(dir, (key+1)->co, key->co);
- normalize_v3(dir);
-
- par_time = (float)k / (float)(totkeys - 1);
- par_co = parent_keys[k].co;
- par_vel = parent_keys[k].vel;
- par_rot = parent_keys[k].rot;
- }
- else {
- float spiral_time = (float)(k - start_index) / (float)(extrakeys-1);
- float kink[3], tmp[3];
-
- /* use same time value for every point on the spiral */
- par_time = spiral_start_time;
- par_co = spiral_par_co;
- par_vel = spiral_par_vel;
- par_rot = spiral_par_rot;
-
- project_v3_v3v3(tmp, kink_base, dir);
- sub_v3_v3v3(kink, kink_base, tmp);
- normalize_v3(kink);
-
- if (kink_axis_random > 0.0f) {
- float a = kink_axis_random * (psys_frand(ctx->sim.psys, 7112 + seed) * 2.0f - 1.0f) * (float)M_PI;
- float rot[3][3];
-
- axis_angle_normalized_to_mat3(rot, dir, a);
- mul_m3_v3(rot, kink);
- }
-
- do_kink_spiral_deform((ParticleKey *)key, dir, kink, spiral_time, kink_freq, kink_shape, kink_amp, spiral_start);
- }
-
- /* Fill in variant part of modifier context. */
- modifier_ctx.par_co = par_co;
- modifier_ctx.par_vel = par_vel;
- modifier_ctx.par_rot = par_rot;
- modifier_ctx.par_orco = parent_orco;
-
- /* Apply different deformations to the child path/ */
- do_child_modifiers(&modifier_ctx, hairmat, (ParticleKey *)key, par_time);
- }
-
- totlen = 0.0f;
- for (k = 0, key = keys; k < end_index-1; k++, key++)
- totlen += len_v3v3((key+1)->co, key->co);
-
- *r_totkeys = end_index;
- *r_max_length = totlen;
+ struct ParticleSettings *part = ctx->sim.psys->part;
+ const int seed = ctx->sim.psys->child_seed + (int)(cpa - ctx->sim.psys->child);
+ const int totkeys = ctx->segments + 1;
+ const int extrakeys = ctx->extra_segments;
+
+ float kink_amp_random = part->kink_amp_random;
+ float kink_amp = part->kink_amp *
+ (1.0f - kink_amp_random * psys_frand(ctx->sim.psys, 93541 + seed));
+ float kink_freq = part->kink_freq;
+ float kink_shape = part->kink_shape;
+ float kink_axis_random = part->kink_axis_random;
+ float rough1 = part->rough1;
+ float rough2 = part->rough2;
+ float rough_end = part->rough_end;
+
+ ParticlePathIterator iter;
+ ParticleCacheKey *key;
+ int k;
+
+ float dir[3];
+ float spiral_start[3] = {0.0f, 0.0f, 0.0f};
+ float spiral_start_time = 0.0f;
+ float spiral_par_co[3] = {0.0f, 0.0f, 0.0f};
+ float spiral_par_vel[3] = {0.0f, 0.0f, 0.0f};
+ float spiral_par_rot[4] = {1.0f, 0.0f, 0.0f, 0.0f};
+ float totlen;
+ float cut_time;
+ int start_index = 0, end_index = 0;
+ float kink_base[3];
+
+ if (ptex) {
+ kink_amp *= ptex->kink_amp;
+ kink_freq *= ptex->kink_freq;
+ rough1 *= ptex->rough1;
+ rough2 *= ptex->rough2;
+ rough_end *= ptex->roughe;
+ }
+
+ cut_time = (totkeys - 1) * ptex->length;
+ zero_v3(spiral_start);
+
+ for (k = 0, key = keys; k < totkeys - 1; k++, key++) {
+ if ((float)(k + 1) >= cut_time) {
+ float fac = cut_time - (float)k;
+ ParticleCacheKey *par = parent_keys + k;
+
+ start_index = k + 1;
+ end_index = start_index + extrakeys;
+
+ spiral_start_time = ((float)k + fac) / (float)(totkeys - 1);
+ interp_v3_v3v3(spiral_start, key->co, (key + 1)->co, fac);
+
+ interp_v3_v3v3(spiral_par_co, par->co, (par + 1)->co, fac);
+ interp_v3_v3v3(spiral_par_vel, par->vel, (par + 1)->vel, fac);
+ interp_qt_qtqt(spiral_par_rot, par->rot, (par + 1)->rot, fac);
+
+ break;
+ }
+ }
+
+ zero_v3(dir);
+
+ zero_v3(kink_base);
+ kink_base[part->kink_axis] = 1.0f;
+ mul_mat3_m4_v3(ctx->sim.ob->obmat, kink_base);
+
+ /* Fill in invariant part of modifier context. */
+ ParticleChildModifierContext modifier_ctx = {NULL};
+ modifier_ctx.thread_ctx = ctx;
+ modifier_ctx.sim = &ctx->sim;
+ modifier_ctx.ptex = ptex;
+ modifier_ctx.cpa = cpa;
+ modifier_ctx.orco = orco;
+ modifier_ctx.parent_keys = parent_keys;
+
+ for (k = 0, key = keys; k < end_index; k++, key++) {
+ float par_time;
+ float *par_co, *par_vel, *par_rot;
+
+ psys_path_iter_get(&iter, keys, end_index, NULL, k);
+ if (k < start_index) {
+ sub_v3_v3v3(dir, (key + 1)->co, key->co);
+ normalize_v3(dir);
+
+ par_time = (float)k / (float)(totkeys - 1);
+ par_co = parent_keys[k].co;
+ par_vel = parent_keys[k].vel;
+ par_rot = parent_keys[k].rot;
+ }
+ else {
+ float spiral_time = (float)(k - start_index) / (float)(extrakeys - 1);
+ float kink[3], tmp[3];
+
+ /* use same time value for every point on the spiral */
+ par_time = spiral_start_time;
+ par_co = spiral_par_co;
+ par_vel = spiral_par_vel;
+ par_rot = spiral_par_rot;
+
+ project_v3_v3v3(tmp, kink_base, dir);
+ sub_v3_v3v3(kink, kink_base, tmp);
+ normalize_v3(kink);
+
+ if (kink_axis_random > 0.0f) {
+ float a = kink_axis_random * (psys_frand(ctx->sim.psys, 7112 + seed) * 2.0f - 1.0f) *
+ (float)M_PI;
+ float rot[3][3];
+
+ axis_angle_normalized_to_mat3(rot, dir, a);
+ mul_m3_v3(rot, kink);
+ }
+
+ do_kink_spiral_deform((ParticleKey *)key,
+ dir,
+ kink,
+ spiral_time,
+ kink_freq,
+ kink_shape,
+ kink_amp,
+ spiral_start);
+ }
+
+ /* Fill in variant part of modifier context. */
+ modifier_ctx.par_co = par_co;
+ modifier_ctx.par_vel = par_vel;
+ modifier_ctx.par_rot = par_rot;
+ modifier_ctx.par_orco = parent_orco;
+
+ /* Apply different deformations to the child path/ */
+ do_child_modifiers(&modifier_ctx, hairmat, (ParticleKey *)key, par_time);
+ }
+
+ totlen = 0.0f;
+ for (k = 0, key = keys; k < end_index - 1; k++, key++)
+ totlen += len_v3v3((key + 1)->co, key->co);
+
+ *r_totkeys = end_index;
+ *r_max_length = totlen;
}
/* ------------------------------------------------------------------------- */
-static bool check_path_length(int k, ParticleCacheKey *keys, ParticleCacheKey *key, float max_length, float step_length, float *cur_length, float dvec[3])
+static bool check_path_length(int k,
+ ParticleCacheKey *keys,
+ ParticleCacheKey *key,
+ float max_length,
+ float step_length,
+ float *cur_length,
+ float dvec[3])
{
- if (*cur_length + step_length > max_length) {
- sub_v3_v3v3(dvec, key->co, (key-1)->co);
- mul_v3_fl(dvec, (max_length - *cur_length) / step_length);
- add_v3_v3v3(key->co, (key-1)->co, dvec);
- keys->segments = k;
- /* something over the maximum step value */
- return false;
- }
- else {
- *cur_length += step_length;
- return true;
- }
+ if (*cur_length + step_length > max_length) {
+ sub_v3_v3v3(dvec, key->co, (key - 1)->co);
+ mul_v3_fl(dvec, (max_length - *cur_length) / step_length);
+ add_v3_v3v3(key->co, (key - 1)->co, dvec);
+ keys->segments = k;
+ /* something over the maximum step value */
+ return false;
+ }
+ else {
+ *cur_length += step_length;
+ return true;
+ }
}
-void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *modifiers,
- ChildParticle *cpa, ParticleTexture *ptex, const float orco[3], float hairmat[4][4],
- ParticleCacheKey *keys, ParticleCacheKey *parent_keys, const float parent_orco[3])
+void psys_apply_child_modifiers(ParticleThreadContext *ctx,
+ struct ListBase *modifiers,
+ ChildParticle *cpa,
+ ParticleTexture *ptex,
+ const float orco[3],
+ float hairmat[4][4],
+ ParticleCacheKey *keys,
+ ParticleCacheKey *parent_keys,
+ const float parent_orco[3])
{
- struct ParticleSettings *part = ctx->sim.psys->part;
- struct Material *ma = ctx->ma;
- const bool draw_col_ma = (part->draw_col == PART_DRAW_COL_MAT);
- const bool use_length_check = !ELEM(part->kink, PART_KINK_SPIRAL);
-
- ParticlePathModifier *mod;
- ParticleCacheKey *key;
- int totkeys, k;
- float max_length;
-
- /* TODO for the future: use true particle modifiers that work on the whole curve */
-
- (void)modifiers;
- (void)mod;
-
- if (part->kink == PART_KINK_SPIRAL) {
- do_kink_spiral(ctx, ptex, parent_orco, cpa, orco, hairmat, keys, parent_keys, &totkeys, &max_length);
- keys->segments = totkeys - 1;
- }
- else {
- /* Fill in invariant part of modifier context. */
- ParticleChildModifierContext modifier_ctx = {NULL};
- modifier_ctx.thread_ctx = ctx;
- modifier_ctx.sim = &ctx->sim;
- modifier_ctx.ptex = ptex;
- modifier_ctx.cpa = cpa;
- modifier_ctx.orco = orco;
- modifier_ctx.parent_keys = parent_keys;
-
- totkeys = ctx->segments + 1;
- max_length = ptex->length;
-
- for (k = 0, key = keys; k < totkeys; k++, key++) {
- ParticlePathIterator iter;
- psys_path_iter_get(&iter, keys, totkeys, parent_keys, k);
-
- ParticleKey *par = (ParticleKey *)iter.parent_key;
-
- /* Fill in variant part of modifier context. */
- modifier_ctx.par_co = par->co;
- modifier_ctx.par_vel = par->vel;
- modifier_ctx.par_rot = iter.parent_rotation;
- modifier_ctx.par_orco = parent_orco;
-
- /* Apply different deformations to the child path. */
- do_child_modifiers(&modifier_ctx, hairmat, (ParticleKey *)key, iter.time);
- }
- }
-
- {
- const float step_length = 1.0f / (float)(totkeys - 1);
- float cur_length = 0.0f;
-
- if (max_length <= 0.0f) {
- keys->segments = -1;
- totkeys = 0;
- }
-
- /* we have to correct velocity because of kink & clump */
- for (k = 0, key = keys; k < totkeys; ++k, ++key) {
- if (k >= 2) {
- sub_v3_v3v3((key-1)->vel, key->co, (key-2)->co);
- mul_v3_fl((key-1)->vel, 0.5);
- }
-
- if (use_length_check && k > 0) {
- float dvec[3];
- /* check if path needs to be cut before actual end of data points */
- if (!check_path_length(k, keys, key, max_length, step_length, &cur_length, dvec)) {
- /* last key */
- sub_v3_v3v3(key->vel, key->co, (key-1)->co);
- if (ma && draw_col_ma) {
- copy_v3_v3(key->col, &ma->r);
- }
- break;
- }
- }
- if (k == totkeys-1) {
- /* last key */
- sub_v3_v3v3(key->vel, key->co, (key-1)->co);
- }
-
- if (ma && draw_col_ma) {
- copy_v3_v3(key->col, &ma->r);
- }
- }
- }
+ struct ParticleSettings *part = ctx->sim.psys->part;
+ struct Material *ma = ctx->ma;
+ const bool draw_col_ma = (part->draw_col == PART_DRAW_COL_MAT);
+ const bool use_length_check = !ELEM(part->kink, PART_KINK_SPIRAL);
+
+ ParticlePathModifier *mod;
+ ParticleCacheKey *key;
+ int totkeys, k;
+ float max_length;
+
+ /* TODO for the future: use true particle modifiers that work on the whole curve */
+
+ (void)modifiers;
+ (void)mod;
+
+ if (part->kink == PART_KINK_SPIRAL) {
+ do_kink_spiral(
+ ctx, ptex, parent_orco, cpa, orco, hairmat, keys, parent_keys, &totkeys, &max_length);
+ keys->segments = totkeys - 1;
+ }
+ else {
+ /* Fill in invariant part of modifier context. */
+ ParticleChildModifierContext modifier_ctx = {NULL};
+ modifier_ctx.thread_ctx = ctx;
+ modifier_ctx.sim = &ctx->sim;
+ modifier_ctx.ptex = ptex;
+ modifier_ctx.cpa = cpa;
+ modifier_ctx.orco = orco;
+ modifier_ctx.parent_keys = parent_keys;
+
+ totkeys = ctx->segments + 1;
+ max_length = ptex->length;
+
+ for (k = 0, key = keys; k < totkeys; k++, key++) {
+ ParticlePathIterator iter;
+ psys_path_iter_get(&iter, keys, totkeys, parent_keys, k);
+
+ ParticleKey *par = (ParticleKey *)iter.parent_key;
+
+ /* Fill in variant part of modifier context. */
+ modifier_ctx.par_co = par->co;
+ modifier_ctx.par_vel = par->vel;
+ modifier_ctx.par_rot = iter.parent_rotation;
+ modifier_ctx.par_orco = parent_orco;
+
+ /* Apply different deformations to the child path. */
+ do_child_modifiers(&modifier_ctx, hairmat, (ParticleKey *)key, iter.time);
+ }
+ }
+
+ {
+ const float step_length = 1.0f / (float)(totkeys - 1);
+ float cur_length = 0.0f;
+
+ if (max_length <= 0.0f) {
+ keys->segments = -1;
+ totkeys = 0;
+ }
+
+ /* we have to correct velocity because of kink & clump */
+ for (k = 0, key = keys; k < totkeys; ++k, ++key) {
+ if (k >= 2) {
+ sub_v3_v3v3((key - 1)->vel, key->co, (key - 2)->co);
+ mul_v3_fl((key - 1)->vel, 0.5);
+ }
+
+ if (use_length_check && k > 0) {
+ float dvec[3];
+ /* check if path needs to be cut before actual end of data points */
+ if (!check_path_length(k, keys, key, max_length, step_length, &cur_length, dvec)) {
+ /* last key */
+ sub_v3_v3v3(key->vel, key->co, (key - 1)->co);
+ if (ma && draw_col_ma) {
+ copy_v3_v3(key->col, &ma->r);
+ }
+ break;
+ }
+ }
+ if (k == totkeys - 1) {
+ /* last key */
+ sub_v3_v3v3(key->vel, key->co, (key - 1)->co);
+ }
+
+ if (ma && draw_col_ma) {
+ copy_v3_v3(key->col, &ma->r);
+ }
+ }
+ }
}
/* ------------------------------------------------------------------------- */
-void do_kink(ParticleKey *state, const float par_co[3], const float par_vel[3], const float par_rot[4], float time, float freq, float shape,
- float amplitude, float flat, short type, short axis, float obmat[4][4], int smooth_start)
+void do_kink(ParticleKey *state,
+ const float par_co[3],
+ const float par_vel[3],
+ const float par_rot[4],
+ float time,
+ float freq,
+ float shape,
+ float amplitude,
+ float flat,
+ short type,
+ short axis,
+ float obmat[4][4],
+ int smooth_start)
{
- float kink[3] = {1.f, 0.f, 0.f}, par_vec[3], q1[4] = {1.f, 0.f, 0.f, 0.f};
- float t, dt = 1.f, result[3];
-
- if (ELEM(type, PART_KINK_NO, PART_KINK_SPIRAL))
- return;
-
- CLAMP(time, 0.f, 1.f);
-
- if (shape != 0.0f && !ELEM(type, PART_KINK_BRAID)) {
- if (shape < 0.0f)
- time = (float)pow(time, 1.f + shape);
- else
- time = (float)pow(time, 1.f / (1.f - shape));
- }
-
- t = time * freq * (float)M_PI;
-
- if (smooth_start) {
- dt = fabsf(t);
- /* smooth the beginning of kink */
- CLAMP(dt, 0.f, (float)M_PI);
- dt = sinf(dt / 2.f);
- }
-
- if (!ELEM(type, PART_KINK_RADIAL)) {
- float temp[3];
-
- kink[axis] = 1.f;
-
- if (obmat)
- mul_mat3_m4_v3(obmat, kink);
-
- mul_qt_v3(par_rot, kink);
-
- /* make sure kink is normal to strand */
- project_v3_v3v3(temp, kink, par_vel);
- sub_v3_v3(kink, temp);
- normalize_v3(kink);
- }
-
- copy_v3_v3(result, state->co);
- sub_v3_v3v3(par_vec, par_co, state->co);
-
- switch (type) {
- case PART_KINK_CURL:
- {
- float curl_offset[3];
-
- /* rotate kink vector around strand tangent */
- mul_v3_v3fl(curl_offset, kink, amplitude);
- axis_angle_to_quat(q1, par_vel, t);
- mul_qt_v3(q1, curl_offset);
-
- interp_v3_v3v3(par_vec, state->co, par_co, flat);
- add_v3_v3v3(result, par_vec, curl_offset);
- break;
- }
- case PART_KINK_RADIAL:
- {
- if (flat > 0.f) {
- float proj[3];
- /* flatten along strand */
- project_v3_v3v3(proj, par_vec, par_vel);
- madd_v3_v3fl(result, proj, flat);
- }
-
- madd_v3_v3fl(result, par_vec, -amplitude * sinf(t));
- break;
- }
- case PART_KINK_WAVE:
- {
- madd_v3_v3fl(result, kink, amplitude * sinf(t));
-
- if (flat > 0.f) {
- float proj[3];
- /* flatten along wave */
- project_v3_v3v3(proj, par_vec, kink);
- madd_v3_v3fl(result, proj, flat);
-
- /* flatten along strand */
- project_v3_v3v3(proj, par_vec, par_vel);
- madd_v3_v3fl(result, proj, flat);
- }
- break;
- }
- case PART_KINK_BRAID:
- {
- float y_vec[3] = {0.f, 1.f, 0.f};
- float z_vec[3] = {0.f, 0.f, 1.f};
- float vec_one[3], state_co[3];
- float inp_y, inp_z, length;
-
- if (par_rot) {
- mul_qt_v3(par_rot, y_vec);
- mul_qt_v3(par_rot, z_vec);
- }
-
- negate_v3(par_vec);
- normalize_v3_v3(vec_one, par_vec);
-
- inp_y = dot_v3v3(y_vec, vec_one);
- inp_z = dot_v3v3(z_vec, vec_one);
-
- if (inp_y > 0.5f) {
- copy_v3_v3(state_co, y_vec);
-
- mul_v3_fl(y_vec, amplitude * cosf(t));
- mul_v3_fl(z_vec, amplitude / 2.f * sinf(2.f * t));
- }
- else if (inp_z > 0.0f) {
- mul_v3_v3fl(state_co, z_vec, sinf((float)M_PI / 3.f));
- madd_v3_v3fl(state_co, y_vec, -0.5f);
-
- mul_v3_fl(y_vec, -amplitude * cosf(t + (float)M_PI / 3.f));
- mul_v3_fl(z_vec, amplitude / 2.f * cosf(2.f * t + (float)M_PI / 6.f));
- }
- else {
- mul_v3_v3fl(state_co, z_vec, -sinf((float)M_PI / 3.f));
- madd_v3_v3fl(state_co, y_vec, -0.5f);
-
- mul_v3_fl(y_vec, amplitude * -sinf(t + (float)M_PI / 6.f));
- mul_v3_fl(z_vec, amplitude / 2.f * -sinf(2.f * t + (float)M_PI / 3.f));
- }
-
- mul_v3_fl(state_co, amplitude);
- add_v3_v3(state_co, par_co);
- sub_v3_v3v3(par_vec, state->co, state_co);
-
- length = normalize_v3(par_vec);
- mul_v3_fl(par_vec, MIN2(length, amplitude / 2.f));
-
- add_v3_v3v3(state_co, par_co, y_vec);
- add_v3_v3(state_co, z_vec);
- add_v3_v3(state_co, par_vec);
-
- shape = 2.f * (float)M_PI * (1.f + shape);
-
- if (t < shape) {
- shape = t / shape;
- shape = (float)sqrt((double)shape);
- interp_v3_v3v3(result, result, state_co, shape);
- }
- else {
- copy_v3_v3(result, state_co);
- }
- break;
- }
- }
-
- /* blend the start of the kink */
- if (dt < 1.f)
- interp_v3_v3v3(state->co, state->co, result, dt);
- else
- copy_v3_v3(state->co, result);
+ float kink[3] = {1.f, 0.f, 0.f}, par_vec[3], q1[4] = {1.f, 0.f, 0.f, 0.f};
+ float t, dt = 1.f, result[3];
+
+ if (ELEM(type, PART_KINK_NO, PART_KINK_SPIRAL))
+ return;
+
+ CLAMP(time, 0.f, 1.f);
+
+ if (shape != 0.0f && !ELEM(type, PART_KINK_BRAID)) {
+ if (shape < 0.0f)
+ time = (float)pow(time, 1.f + shape);
+ else
+ time = (float)pow(time, 1.f / (1.f - shape));
+ }
+
+ t = time * freq * (float)M_PI;
+
+ if (smooth_start) {
+ dt = fabsf(t);
+ /* smooth the beginning of kink */
+ CLAMP(dt, 0.f, (float)M_PI);
+ dt = sinf(dt / 2.f);
+ }
+
+ if (!ELEM(type, PART_KINK_RADIAL)) {
+ float temp[3];
+
+ kink[axis] = 1.f;
+
+ if (obmat)
+ mul_mat3_m4_v3(obmat, kink);
+
+ mul_qt_v3(par_rot, kink);
+
+ /* make sure kink is normal to strand */
+ project_v3_v3v3(temp, kink, par_vel);
+ sub_v3_v3(kink, temp);
+ normalize_v3(kink);
+ }
+
+ copy_v3_v3(result, state->co);
+ sub_v3_v3v3(par_vec, par_co, state->co);
+
+ switch (type) {
+ case PART_KINK_CURL: {
+ float curl_offset[3];
+
+ /* rotate kink vector around strand tangent */
+ mul_v3_v3fl(curl_offset, kink, amplitude);
+ axis_angle_to_quat(q1, par_vel, t);
+ mul_qt_v3(q1, curl_offset);
+
+ interp_v3_v3v3(par_vec, state->co, par_co, flat);
+ add_v3_v3v3(result, par_vec, curl_offset);
+ break;
+ }
+ case PART_KINK_RADIAL: {
+ if (flat > 0.f) {
+ float proj[3];
+ /* flatten along strand */
+ project_v3_v3v3(proj, par_vec, par_vel);
+ madd_v3_v3fl(result, proj, flat);
+ }
+
+ madd_v3_v3fl(result, par_vec, -amplitude * sinf(t));
+ break;
+ }
+ case PART_KINK_WAVE: {
+ madd_v3_v3fl(result, kink, amplitude * sinf(t));
+
+ if (flat > 0.f) {
+ float proj[3];
+ /* flatten along wave */
+ project_v3_v3v3(proj, par_vec, kink);
+ madd_v3_v3fl(result, proj, flat);
+
+ /* flatten along strand */
+ project_v3_v3v3(proj, par_vec, par_vel);
+ madd_v3_v3fl(result, proj, flat);
+ }
+ break;
+ }
+ case PART_KINK_BRAID: {
+ float y_vec[3] = {0.f, 1.f, 0.f};
+ float z_vec[3] = {0.f, 0.f, 1.f};
+ float vec_one[3], state_co[3];
+ float inp_y, inp_z, length;
+
+ if (par_rot) {
+ mul_qt_v3(par_rot, y_vec);
+ mul_qt_v3(par_rot, z_vec);
+ }
+
+ negate_v3(par_vec);
+ normalize_v3_v3(vec_one, par_vec);
+
+ inp_y = dot_v3v3(y_vec, vec_one);
+ inp_z = dot_v3v3(z_vec, vec_one);
+
+ if (inp_y > 0.5f) {
+ copy_v3_v3(state_co, y_vec);
+
+ mul_v3_fl(y_vec, amplitude * cosf(t));
+ mul_v3_fl(z_vec, amplitude / 2.f * sinf(2.f * t));
+ }
+ else if (inp_z > 0.0f) {
+ mul_v3_v3fl(state_co, z_vec, sinf((float)M_PI / 3.f));
+ madd_v3_v3fl(state_co, y_vec, -0.5f);
+
+ mul_v3_fl(y_vec, -amplitude * cosf(t + (float)M_PI / 3.f));
+ mul_v3_fl(z_vec, amplitude / 2.f * cosf(2.f * t + (float)M_PI / 6.f));
+ }
+ else {
+ mul_v3_v3fl(state_co, z_vec, -sinf((float)M_PI / 3.f));
+ madd_v3_v3fl(state_co, y_vec, -0.5f);
+
+ mul_v3_fl(y_vec, amplitude * -sinf(t + (float)M_PI / 6.f));
+ mul_v3_fl(z_vec, amplitude / 2.f * -sinf(2.f * t + (float)M_PI / 3.f));
+ }
+
+ mul_v3_fl(state_co, amplitude);
+ add_v3_v3(state_co, par_co);
+ sub_v3_v3v3(par_vec, state->co, state_co);
+
+ length = normalize_v3(par_vec);
+ mul_v3_fl(par_vec, MIN2(length, amplitude / 2.f));
+
+ add_v3_v3v3(state_co, par_co, y_vec);
+ add_v3_v3(state_co, z_vec);
+ add_v3_v3(state_co, par_vec);
+
+ shape = 2.f * (float)M_PI * (1.f + shape);
+
+ if (t < shape) {
+ shape = t / shape;
+ shape = (float)sqrt((double)shape);
+ interp_v3_v3v3(result, result, state_co, shape);
+ }
+ else {
+ copy_v3_v3(result, state_co);
+ }
+ break;
+ }
+ }
+
+ /* blend the start of the kink */
+ if (dt < 1.f)
+ interp_v3_v3v3(state->co, state->co, result, dt);
+ else
+ copy_v3_v3(state->co, result);
}
-static float do_clump_level(float result[3], const float co[3], const float par_co[3], float time,
- float clumpfac, float clumppow, float pa_clump, CurveMapping *clumpcurve)
+static float do_clump_level(float result[3],
+ const float co[3],
+ const float par_co[3],
+ float time,
+ float clumpfac,
+ float clumppow,
+ float pa_clump,
+ CurveMapping *clumpcurve)
{
- float clump = 0.0f;
+ float clump = 0.0f;
- if (clumpcurve) {
- clump = pa_clump * (1.0f - clamp_f(curvemapping_evaluateF(clumpcurve, 0, time), 0.0f, 1.0f));
+ if (clumpcurve) {
+ clump = pa_clump * (1.0f - clamp_f(curvemapping_evaluateF(clumpcurve, 0, time), 0.0f, 1.0f));
- interp_v3_v3v3(result, co, par_co, clump);
- }
- else if (clumpfac != 0.0f) {
- float cpow;
+ interp_v3_v3v3(result, co, par_co, clump);
+ }
+ else if (clumpfac != 0.0f) {
+ float cpow;
- if (clumppow < 0.0f)
- cpow = 1.0f + clumppow;
- else
- cpow = 1.0f + 9.0f * clumppow;
+ if (clumppow < 0.0f)
+ cpow = 1.0f + clumppow;
+ else
+ cpow = 1.0f + 9.0f * clumppow;
- if (clumpfac < 0.0f) /* clump roots instead of tips */
- clump = -clumpfac * pa_clump * (float)pow(1.0 - (double)time, (double)cpow);
- else
- clump = clumpfac * pa_clump * (float)pow((double)time, (double)cpow);
+ if (clumpfac < 0.0f) /* clump roots instead of tips */
+ clump = -clumpfac * pa_clump * (float)pow(1.0 - (double)time, (double)cpow);
+ else
+ clump = clumpfac * pa_clump * (float)pow((double)time, (double)cpow);
- interp_v3_v3v3(result, co, par_co, clump);
- }
+ interp_v3_v3v3(result, co, par_co, clump);
+ }
- return clump;
+ return clump;
}
-float do_clump(ParticleKey *state, const float par_co[3], float time, const float orco_offset[3], float clumpfac, float clumppow, float pa_clump,
- bool use_clump_noise, float clump_noise_size, CurveMapping *clumpcurve)
+float do_clump(ParticleKey *state,
+ const float par_co[3],
+ float time,
+ const float orco_offset[3],
+ float clumpfac,
+ float clumppow,
+ float pa_clump,
+ bool use_clump_noise,
+ float clump_noise_size,
+ CurveMapping *clumpcurve)
{
- float clump;
+ float clump;
- if (use_clump_noise && clump_noise_size != 0.0f) {
- float center[3], noisevec[3];
- float da[4], pa[12];
+ if (use_clump_noise && clump_noise_size != 0.0f) {
+ float center[3], noisevec[3];
+ float da[4], pa[12];
- mul_v3_v3fl(noisevec, orco_offset, 1.0f / clump_noise_size);
- voronoi(noisevec[0], noisevec[1], noisevec[2], da, pa, 1.0f, 0);
- mul_v3_fl(&pa[0], clump_noise_size);
- add_v3_v3v3(center, par_co, &pa[0]);
+ mul_v3_v3fl(noisevec, orco_offset, 1.0f / clump_noise_size);
+ voronoi(noisevec[0], noisevec[1], noisevec[2], da, pa, 1.0f, 0);
+ mul_v3_fl(&pa[0], clump_noise_size);
+ add_v3_v3v3(center, par_co, &pa[0]);
- do_clump_level(state->co, state->co, center, time, clumpfac, clumppow, pa_clump, clumpcurve);
- }
+ do_clump_level(state->co, state->co, center, time, clumpfac, clumppow, pa_clump, clumpcurve);
+ }
- clump = do_clump_level(state->co, state->co, par_co, time, clumpfac, clumppow, pa_clump, clumpcurve);
+ clump = do_clump_level(
+ state->co, state->co, par_co, time, clumpfac, clumppow, pa_clump, clumpcurve);
- return clump;
+ return clump;
}
-static void do_rough(const float loc[3], float mat[4][4], float t, float fac, float size, float thres, ParticleKey *state)
+static void do_rough(const float loc[3],
+ float mat[4][4],
+ float t,
+ float fac,
+ float size,
+ float thres,
+ ParticleKey *state)
{
- float rough[3];
- float rco[3];
-
- if (thres != 0.0f) {
- if (fabsf((float)(-1.5f + loc[0] + loc[1] + loc[2])) < 1.5f * thres) {
- return;
- }
- }
-
- copy_v3_v3(rco, loc);
- mul_v3_fl(rco, t);
- rough[0] = -1.0f + 2.0f * BLI_gTurbulence(size, rco[0], rco[1], rco[2], 2, 0, 2);
- rough[1] = -1.0f + 2.0f * BLI_gTurbulence(size, rco[1], rco[2], rco[0], 2, 0, 2);
- rough[2] = -1.0f + 2.0f * BLI_gTurbulence(size, rco[2], rco[0], rco[1], 2, 0, 2);
-
- madd_v3_v3fl(state->co, mat[0], fac * rough[0]);
- madd_v3_v3fl(state->co, mat[1], fac * rough[1]);
- madd_v3_v3fl(state->co, mat[2], fac * rough[2]);
+ float rough[3];
+ float rco[3];
+
+ if (thres != 0.0f) {
+ if (fabsf((float)(-1.5f + loc[0] + loc[1] + loc[2])) < 1.5f * thres) {
+ return;
+ }
+ }
+
+ copy_v3_v3(rco, loc);
+ mul_v3_fl(rco, t);
+ rough[0] = -1.0f + 2.0f * BLI_gTurbulence(size, rco[0], rco[1], rco[2], 2, 0, 2);
+ rough[1] = -1.0f + 2.0f * BLI_gTurbulence(size, rco[1], rco[2], rco[0], 2, 0, 2);
+ rough[2] = -1.0f + 2.0f * BLI_gTurbulence(size, rco[2], rco[0], rco[1], 2, 0, 2);
+
+ madd_v3_v3fl(state->co, mat[0], fac * rough[0]);
+ madd_v3_v3fl(state->co, mat[1], fac * rough[1]);
+ madd_v3_v3fl(state->co, mat[2], fac * rough[2]);
}
-static void do_rough_end(const float loc[3], float mat[4][4], float t, float fac, float shape, ParticleKey *state)
+static void do_rough_end(
+ const float loc[3], float mat[4][4], float t, float fac, float shape, ParticleKey *state)
{
- float rough[2];
- float roughfac;
+ float rough[2];
+ float roughfac;
- roughfac = fac * (float)pow((double)t, shape);
- copy_v2_v2(rough, loc);
- rough[0] = -1.0f + 2.0f * rough[0];
- rough[1] = -1.0f + 2.0f * rough[1];
- mul_v2_fl(rough, roughfac);
+ roughfac = fac * (float)pow((double)t, shape);
+ copy_v2_v2(rough, loc);
+ rough[0] = -1.0f + 2.0f * rough[0];
+ rough[1] = -1.0f + 2.0f * rough[1];
+ mul_v2_fl(rough, roughfac);
- madd_v3_v3fl(state->co, mat[0], rough[0]);
- madd_v3_v3fl(state->co, mat[1], rough[1]);
+ madd_v3_v3fl(state->co, mat[0], rough[0]);
+ madd_v3_v3fl(state->co, mat[1], rough[1]);
}
-static void do_rough_curve(const float loc[3], float mat[4][4], float time, float fac, float size, CurveMapping *roughcurve, ParticleKey *state)
+static void do_rough_curve(const float loc[3],
+ float mat[4][4],
+ float time,
+ float fac,
+ float size,
+ CurveMapping *roughcurve,
+ ParticleKey *state)
{
- float rough[3];
- float rco[3];
+ float rough[3];
+ float rco[3];
- if (!roughcurve)
- return;
+ if (!roughcurve)
+ return;
- fac *= clamp_f(curvemapping_evaluateF(roughcurve, 0, time), 0.0f, 1.0f);
+ fac *= clamp_f(curvemapping_evaluateF(roughcurve, 0, time), 0.0f, 1.0f);
- copy_v3_v3(rco, loc);
- mul_v3_fl(rco, time);
- rough[0] = -1.0f + 2.0f * BLI_gTurbulence(size, rco[0], rco[1], rco[2], 2, 0, 2);
- rough[1] = -1.0f + 2.0f * BLI_gTurbulence(size, rco[1], rco[2], rco[0], 2, 0, 2);
- rough[2] = -1.0f + 2.0f * BLI_gTurbulence(size, rco[2], rco[0], rco[1], 2, 0, 2);
+ copy_v3_v3(rco, loc);
+ mul_v3_fl(rco, time);
+ rough[0] = -1.0f + 2.0f * BLI_gTurbulence(size, rco[0], rco[1], rco[2], 2, 0, 2);
+ rough[1] = -1.0f + 2.0f * BLI_gTurbulence(size, rco[1], rco[2], rco[0], 2, 0, 2);
+ rough[2] = -1.0f + 2.0f * BLI_gTurbulence(size, rco[2], rco[0], rco[1], 2, 0, 2);
- madd_v3_v3fl(state->co, mat[0], fac * rough[0]);
- madd_v3_v3fl(state->co, mat[1], fac * rough[1]);
- madd_v3_v3fl(state->co, mat[2], fac * rough[2]);
+ madd_v3_v3fl(state->co, mat[0], fac * rough[0]);
+ madd_v3_v3fl(state->co, mat[1], fac * rough[1]);
+ madd_v3_v3fl(state->co, mat[2], fac * rough[2]);
}
static int twist_num_segments(const ParticleChildModifierContext *modifier_ctx)
{
- ParticleThreadContext *thread_ctx = modifier_ctx->thread_ctx;
- return (thread_ctx != NULL) ? thread_ctx->segments
- : modifier_ctx->sim->psys->part->draw_step;
+ ParticleThreadContext *thread_ctx = modifier_ctx->thread_ctx;
+ return (thread_ctx != NULL) ? thread_ctx->segments : modifier_ctx->sim->psys->part->draw_step;
}
static void twist_get_axis(const ParticleChildModifierContext *modifier_ctx,
- const float time, float r_axis[3])
+ const float time,
+ float r_axis[3])
{
- const int num_segments = twist_num_segments(modifier_ctx);
- const int index = clamp_i(time * num_segments, 0, num_segments);
- if (index > 0) {
- sub_v3_v3v3(r_axis,
- modifier_ctx->parent_keys[index].co,
- modifier_ctx->parent_keys[index - 1].co);
- }
- else {
- sub_v3_v3v3(r_axis,
- modifier_ctx->parent_keys[index + 1].co,
- modifier_ctx->parent_keys[index].co);
- }
+ const int num_segments = twist_num_segments(modifier_ctx);
+ const int index = clamp_i(time * num_segments, 0, num_segments);
+ if (index > 0) {
+ sub_v3_v3v3(
+ r_axis, modifier_ctx->parent_keys[index].co, modifier_ctx->parent_keys[index - 1].co);
+ }
+ else {
+ sub_v3_v3v3(
+ r_axis, modifier_ctx->parent_keys[index + 1].co, modifier_ctx->parent_keys[index].co);
+ }
}
static float curvemapping_integrate_clamped(CurveMapping *curve,
- float start, float end, float step)
+ float start,
+ float end,
+ float step)
{
- float integral = 0.0f;
- float x = start;
- while (x < end) {
- float y = curvemapping_evaluateF(curve, 0, x);
- y = clamp_f(y, 0.0f, 1.0f);
- /* TODO(sergey): Clamp last step to end. */
- integral += y * step;
- x += step;
- }
- return integral;
+ float integral = 0.0f;
+ float x = start;
+ while (x < end) {
+ float y = curvemapping_evaluateF(curve, 0, x);
+ y = clamp_f(y, 0.0f, 1.0f);
+ /* TODO(sergey): Clamp last step to end. */
+ integral += y * step;
+ x += step;
+ }
+ return integral;
}
static void do_twist(const ParticleChildModifierContext *modifier_ctx,
- ParticleKey *state, const float time)
+ ParticleKey *state,
+ const float time)
{
- ParticleThreadContext *thread_ctx = modifier_ctx->thread_ctx;
- ParticleSimulationData *sim = modifier_ctx->sim;
- ParticleTexture *ptex = modifier_ctx->ptex;
- ParticleSettings *part = sim->psys->part;
- /* Early output checks. */
- if (modifier_ctx->parent_keys == NULL) {
- /* Cannot get axis of rotation... */
- return;
- }
- if (part->childtype != PART_CHILD_PARTICLES) {
- /* Interpolated children behave weird with twist. */
- return;
- }
- if (part->twist == 0.0f) {
- /* No twist along the strand. */
- return;
- }
- /* Dependent on whether it's threaded update or not, curve comes
- * from different places.
- */
- CurveMapping *twist_curve = NULL;
- if (part->child_flag & PART_CHILD_USE_TWIST_CURVE) {
- twist_curve = (thread_ctx != NULL) ? thread_ctx->twistcurve
- : part->twistcurve;
- }
- /* Axis of rotation. */
- float axis[3];
- twist_get_axis(modifier_ctx, time, axis);
- /* Angle of rotation. */
- float angle = part->twist;
- if (ptex != NULL) {
- angle *= (ptex->twist - 0.5f) * 2.0f;
- }
- if (twist_curve != NULL) {
- const int num_segments = twist_num_segments(modifier_ctx);
- angle *= curvemapping_integrate_clamped(twist_curve,
- 0.0f, time,
- 1.0f / num_segments);
- }
- else {
- angle *= time;
- }
- /* Perform rotation around parent curve. */
- float vec[3];
- sub_v3_v3v3(vec, state->co, modifier_ctx->par_co);
- rotate_v3_v3v3fl(state->co, vec, axis, angle * 2.0f * M_PI);
- add_v3_v3(state->co, modifier_ctx->par_co);
+ ParticleThreadContext *thread_ctx = modifier_ctx->thread_ctx;
+ ParticleSimulationData *sim = modifier_ctx->sim;
+ ParticleTexture *ptex = modifier_ctx->ptex;
+ ParticleSettings *part = sim->psys->part;
+ /* Early output checks. */
+ if (modifier_ctx->parent_keys == NULL) {
+ /* Cannot get axis of rotation... */
+ return;
+ }
+ if (part->childtype != PART_CHILD_PARTICLES) {
+ /* Interpolated children behave weird with twist. */
+ return;
+ }
+ if (part->twist == 0.0f) {
+ /* No twist along the strand. */
+ return;
+ }
+ /* Dependent on whether it's threaded update or not, curve comes
+ * from different places.
+ */
+ CurveMapping *twist_curve = NULL;
+ if (part->child_flag & PART_CHILD_USE_TWIST_CURVE) {
+ twist_curve = (thread_ctx != NULL) ? thread_ctx->twistcurve : part->twistcurve;
+ }
+ /* Axis of rotation. */
+ float axis[3];
+ twist_get_axis(modifier_ctx, time, axis);
+ /* Angle of rotation. */
+ float angle = part->twist;
+ if (ptex != NULL) {
+ angle *= (ptex->twist - 0.5f) * 2.0f;
+ }
+ if (twist_curve != NULL) {
+ const int num_segments = twist_num_segments(modifier_ctx);
+ angle *= curvemapping_integrate_clamped(twist_curve, 0.0f, time, 1.0f / num_segments);
+ }
+ else {
+ angle *= time;
+ }
+ /* Perform rotation around parent curve. */
+ float vec[3];
+ sub_v3_v3v3(vec, state->co, modifier_ctx->par_co);
+ rotate_v3_v3v3fl(state->co, vec, axis, angle * 2.0f * M_PI);
+ add_v3_v3(state->co, modifier_ctx->par_co);
}
void do_child_modifiers(const ParticleChildModifierContext *modifier_ctx,
- float mat[4][4], ParticleKey *state, float t)
+ float mat[4][4],
+ ParticleKey *state,
+ float t)
{
- ParticleThreadContext *ctx = modifier_ctx->thread_ctx;
- ParticleSimulationData *sim = modifier_ctx->sim;
- ParticleTexture *ptex = modifier_ctx->ptex;
- ChildParticle *cpa = modifier_ctx->cpa;
- ParticleSettings *part = sim->psys->part;
- CurveMapping *clumpcurve = NULL, *roughcurve = NULL;
- int i = cpa - sim->psys->child;
- int guided = 0;
-
- if (part->child_flag & PART_CHILD_USE_CLUMP_CURVE) {
- clumpcurve = (ctx != NULL) ? ctx->clumpcurve : part->clumpcurve;
- }
- if (part->child_flag & PART_CHILD_USE_ROUGH_CURVE) {
- roughcurve = (ctx != NULL) ? ctx->roughcurve : part->roughcurve;
- }
-
- float kink_amp = part->kink_amp;
- float kink_amp_clump = part->kink_amp_clump;
- float kink_freq = part->kink_freq;
- float rough1 = part->rough1;
- float rough2 = part->rough2;
- float rough_end = part->rough_end;
- const bool smooth_start = (sim->psys->part->childtype == PART_CHILD_FACES);
-
- if (ptex) {
- kink_amp *= ptex->kink_amp;
- kink_freq *= ptex->kink_freq;
- rough1 *= ptex->rough1;
- rough2 *= ptex->rough2;
- rough_end *= ptex->roughe;
- }
-
- do_twist(modifier_ctx, state, t);
-
- if (part->flag & PART_CHILD_EFFECT)
- /* state is safe to cast, since only co and vel are used */
- guided = do_guides(sim->depsgraph, sim->psys->part, sim->psys->effectors, (ParticleKey *)state, cpa->parent, t);
-
- if (guided == 0) {
- float orco_offset[3];
- float clump;
-
- sub_v3_v3v3(orco_offset, modifier_ctx->orco, modifier_ctx->par_orco);
- clump = do_clump(state,
- modifier_ctx->par_co,
- t,
- orco_offset,
- part->clumpfac,
- part->clumppow,
- ptex ? ptex->clump : 1.0f,
- part->child_flag & PART_CHILD_USE_CLUMP_NOISE,
- part->clump_noise_size,
- clumpcurve);
-
- if (kink_freq != 0.f) {
- kink_amp *= (1.f - kink_amp_clump * clump);
-
- do_kink(state,
- modifier_ctx->par_co,
- modifier_ctx->par_vel,
- modifier_ctx->par_rot,
- t,
- kink_freq,
- part->kink_shape,
- kink_amp,
- part->kink_flat,
- part->kink,
- part->kink_axis,
- sim->ob->obmat,
- smooth_start);
- }
- }
-
- if (roughcurve) {
- do_rough_curve(modifier_ctx->orco, mat, t, rough1, part->rough1_size, roughcurve, state);
- }
- else {
- if (rough1 > 0.f)
- do_rough(modifier_ctx->orco, mat, t, rough1, part->rough1_size, 0.0, state);
-
- if (rough2 > 0.f) {
- float vec[3];
- psys_frand_vec(sim->psys, i + 27, vec);
- do_rough(vec, mat, t, rough2, part->rough2_size, part->rough2_thres, state);
- }
-
- if (rough_end > 0.f) {
- float vec[3];
- psys_frand_vec(sim->psys, i + 27, vec);
- do_rough_end(vec, mat, t, rough_end, part->rough_end_shape, state);
- }
- }
+ ParticleThreadContext *ctx = modifier_ctx->thread_ctx;
+ ParticleSimulationData *sim = modifier_ctx->sim;
+ ParticleTexture *ptex = modifier_ctx->ptex;
+ ChildParticle *cpa = modifier_ctx->cpa;
+ ParticleSettings *part = sim->psys->part;
+ CurveMapping *clumpcurve = NULL, *roughcurve = NULL;
+ int i = cpa - sim->psys->child;
+ int guided = 0;
+
+ if (part->child_flag & PART_CHILD_USE_CLUMP_CURVE) {
+ clumpcurve = (ctx != NULL) ? ctx->clumpcurve : part->clumpcurve;
+ }
+ if (part->child_flag & PART_CHILD_USE_ROUGH_CURVE) {
+ roughcurve = (ctx != NULL) ? ctx->roughcurve : part->roughcurve;
+ }
+
+ float kink_amp = part->kink_amp;
+ float kink_amp_clump = part->kink_amp_clump;
+ float kink_freq = part->kink_freq;
+ float rough1 = part->rough1;
+ float rough2 = part->rough2;
+ float rough_end = part->rough_end;
+ const bool smooth_start = (sim->psys->part->childtype == PART_CHILD_FACES);
+
+ if (ptex) {
+ kink_amp *= ptex->kink_amp;
+ kink_freq *= ptex->kink_freq;
+ rough1 *= ptex->rough1;
+ rough2 *= ptex->rough2;
+ rough_end *= ptex->roughe;
+ }
+
+ do_twist(modifier_ctx, state, t);
+
+ if (part->flag & PART_CHILD_EFFECT)
+ /* state is safe to cast, since only co and vel are used */
+ guided = do_guides(sim->depsgraph,
+ sim->psys->part,
+ sim->psys->effectors,
+ (ParticleKey *)state,
+ cpa->parent,
+ t);
+
+ if (guided == 0) {
+ float orco_offset[3];
+ float clump;
+
+ sub_v3_v3v3(orco_offset, modifier_ctx->orco, modifier_ctx->par_orco);
+ clump = do_clump(state,
+ modifier_ctx->par_co,
+ t,
+ orco_offset,
+ part->clumpfac,
+ part->clumppow,
+ ptex ? ptex->clump : 1.0f,
+ part->child_flag & PART_CHILD_USE_CLUMP_NOISE,
+ part->clump_noise_size,
+ clumpcurve);
+
+ if (kink_freq != 0.f) {
+ kink_amp *= (1.f - kink_amp_clump * clump);
+
+ do_kink(state,
+ modifier_ctx->par_co,
+ modifier_ctx->par_vel,
+ modifier_ctx->par_rot,
+ t,
+ kink_freq,
+ part->kink_shape,
+ kink_amp,
+ part->kink_flat,
+ part->kink,
+ part->kink_axis,
+ sim->ob->obmat,
+ smooth_start);
+ }
+ }
+
+ if (roughcurve) {
+ do_rough_curve(modifier_ctx->orco, mat, t, rough1, part->rough1_size, roughcurve, state);
+ }
+ else {
+ if (rough1 > 0.f)
+ do_rough(modifier_ctx->orco, mat, t, rough1, part->rough1_size, 0.0, state);
+
+ if (rough2 > 0.f) {
+ float vec[3];
+ psys_frand_vec(sim->psys, i + 27, vec);
+ do_rough(vec, mat, t, rough2, part->rough2_size, part->rough2_thres, state);
+ }
+
+ if (rough_end > 0.f) {
+ float vec[3];
+ psys_frand_vec(sim->psys, i + 27, vec);
+ do_rough_end(vec, mat, t, rough_end, part->rough_end_shape, state);
+ }
+ }
}
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index fc8292531dc..facfc318426 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -50,375 +50,395 @@
static void alloc_child_particles(ParticleSystem *psys, int tot)
{
- if (psys->child) {
- /* only re-allocate if we have to */
- if (psys->part->childtype && psys->totchild == tot) {
- memset(psys->child, 0, tot*sizeof(ChildParticle));
- return;
- }
-
- MEM_freeN(psys->child);
- psys->child=NULL;
- psys->totchild=0;
- }
-
- if (psys->part->childtype) {
- psys->totchild= tot;
- if (psys->totchild)
- psys->child= MEM_callocN(psys->totchild*sizeof(ChildParticle), "child_particles");
- }
+ if (psys->child) {
+ /* only re-allocate if we have to */
+ if (psys->part->childtype && psys->totchild == tot) {
+ memset(psys->child, 0, tot * sizeof(ChildParticle));
+ return;
+ }
+
+ MEM_freeN(psys->child);
+ psys->child = NULL;
+ psys->totchild = 0;
+ }
+
+ if (psys->part->childtype) {
+ psys->totchild = tot;
+ if (psys->totchild)
+ psys->child = MEM_callocN(psys->totchild * sizeof(ChildParticle), "child_particles");
+ }
}
-static void distribute_simple_children(Scene *scene, Object *ob, Mesh *final_mesh, Mesh *deform_mesh, ParticleSystem *psys, const bool use_render_params)
+static void distribute_simple_children(Scene *scene,
+ Object *ob,
+ Mesh *final_mesh,
+ Mesh *deform_mesh,
+ ParticleSystem *psys,
+ const bool use_render_params)
{
- ChildParticle *cpa = NULL;
- int i, p;
- int child_nbr= psys_get_child_number(scene, psys, use_render_params);
- int totpart= psys_get_tot_child(scene, psys, use_render_params);
- RNG *rng = BLI_rng_new_srandom(31415926 + psys->seed + psys->child_seed);
-
- alloc_child_particles(psys, totpart);
-
- cpa = psys->child;
- for (i=0; i<child_nbr; i++) {
- for (p=0; p<psys->totpart; p++,cpa++) {
- float length=2.0;
- cpa->parent=p;
-
- /* create even spherical distribution inside unit sphere */
- while (length>=1.0f) {
- cpa->fuv[0]=2.0f*BLI_rng_get_float(rng)-1.0f;
- cpa->fuv[1]=2.0f*BLI_rng_get_float(rng)-1.0f;
- cpa->fuv[2]=2.0f*BLI_rng_get_float(rng)-1.0f;
- length=len_v3(cpa->fuv);
- }
-
- cpa->num=-1;
- }
- }
- /* dmcache must be updated for parent particles if children from faces is used */
- psys_calc_dmcache(ob, final_mesh, deform_mesh, psys);
-
- BLI_rng_free(rng);
+ ChildParticle *cpa = NULL;
+ int i, p;
+ int child_nbr = psys_get_child_number(scene, psys, use_render_params);
+ int totpart = psys_get_tot_child(scene, psys, use_render_params);
+ RNG *rng = BLI_rng_new_srandom(31415926 + psys->seed + psys->child_seed);
+
+ alloc_child_particles(psys, totpart);
+
+ cpa = psys->child;
+ for (i = 0; i < child_nbr; i++) {
+ for (p = 0; p < psys->totpart; p++, cpa++) {
+ float length = 2.0;
+ cpa->parent = p;
+
+ /* create even spherical distribution inside unit sphere */
+ while (length >= 1.0f) {
+ cpa->fuv[0] = 2.0f * BLI_rng_get_float(rng) - 1.0f;
+ cpa->fuv[1] = 2.0f * BLI_rng_get_float(rng) - 1.0f;
+ cpa->fuv[2] = 2.0f * BLI_rng_get_float(rng) - 1.0f;
+ length = len_v3(cpa->fuv);
+ }
+
+ cpa->num = -1;
+ }
+ }
+ /* dmcache must be updated for parent particles if children from faces is used */
+ psys_calc_dmcache(ob, final_mesh, deform_mesh, psys);
+
+ BLI_rng_free(rng);
}
static void distribute_grid(Mesh *mesh, ParticleSystem *psys)
{
- ParticleData *pa=NULL;
- float min[3], max[3], delta[3], d;
- MVert *mv, *mvert = mesh->mvert;
- int totvert=mesh->totvert, from=psys->part->from;
- int i, j, k, p, res=psys->part->grid_res, size[3], axis;
-
- /* find bounding box of dm */
- if (totvert > 0) {
- mv=mvert;
- copy_v3_v3(min, mv->co);
- copy_v3_v3(max, mv->co);
- mv++;
- for (i = 1; i < totvert; i++, mv++) {
- minmax_v3v3_v3(min, max, mv->co);
- }
- }
- else {
- zero_v3(min);
- zero_v3(max);
- }
-
- sub_v3_v3v3(delta, max, min);
-
- /* determine major axis */
- axis = axis_dominant_v3_single(delta);
-
- d = delta[axis]/(float)res;
-
- size[axis] = res;
- size[(axis+1)%3] = (int)ceil(delta[(axis+1)%3]/d);
- size[(axis+2)%3] = (int)ceil(delta[(axis+2)%3]/d);
-
- /* float errors grrr.. */
- size[(axis+1)%3] = MIN2(size[(axis+1)%3],res);
- size[(axis+2)%3] = MIN2(size[(axis+2)%3],res);
-
- size[0] = MAX2(size[0], 1);
- size[1] = MAX2(size[1], 1);
- size[2] = MAX2(size[2], 1);
-
- /* no full offset for flat/thin objects */
- min[0]+= d < delta[0] ? d/2.f : delta[0]/2.f;
- min[1]+= d < delta[1] ? d/2.f : delta[1]/2.f;
- min[2]+= d < delta[2] ? d/2.f : delta[2]/2.f;
-
- for (i=0,p=0,pa=psys->particles; i<res; i++) {
- for (j=0; j<res; j++) {
- for (k=0; k<res; k++,p++,pa++) {
- pa->fuv[0] = min[0] + (float)i*d;
- pa->fuv[1] = min[1] + (float)j*d;
- pa->fuv[2] = min[2] + (float)k*d;
- pa->flag |= PARS_UNEXIST;
- pa->hair_index = 0; /* abused in volume calculation */
- }
- }
- }
-
- /* enable particles near verts/edges/faces/inside surface */
- if (from==PART_FROM_VERT) {
- float vec[3];
-
- pa=psys->particles;
-
- min[0] -= d/2.0f;
- min[1] -= d/2.0f;
- min[2] -= d/2.0f;
-
- for (i=0,mv=mvert; i<totvert; i++,mv++) {
- sub_v3_v3v3(vec,mv->co,min);
- vec[0]/=delta[0];
- vec[1]/=delta[1];
- vec[2]/=delta[2];
- pa[((int)(vec[0] * (size[0] - 1)) * res +
- (int)(vec[1] * (size[1] - 1))) * res +
- (int)(vec[2] * (size[2] - 1))].flag &= ~PARS_UNEXIST;
- }
- }
- else if (ELEM(from,PART_FROM_FACE,PART_FROM_VOLUME)) {
- float co1[3], co2[3];
-
- MFace *mface= NULL, *mface_array;
- float v1[3], v2[3], v3[3], v4[4], lambda;
- int a, a1, a2, a0mul, a1mul, a2mul, totface;
- int amax= from==PART_FROM_FACE ? 3 : 1;
-
- totface = mesh->totface;
- mface = mface_array = mesh->mface;
-
- for (a=0; a<amax; a++) {
- if (a==0) { a0mul=res*res; a1mul=res; a2mul=1; }
- else if (a==1) { a0mul=res; a1mul=1; a2mul=res*res; }
- else { a0mul=1; a1mul=res*res; a2mul=res; }
-
- for (a1=0; a1<size[(a+1)%3]; a1++) {
- for (a2=0; a2<size[(a+2)%3]; a2++) {
- mface= mface_array;
-
- pa = psys->particles + a1*a1mul + a2*a2mul;
- copy_v3_v3(co1, pa->fuv);
- co1[a] -= d < delta[a] ? d/2.f : delta[a]/2.f;
- copy_v3_v3(co2, co1);
- co2[a] += delta[a] + 0.001f*d;
- co1[a] -= 0.001f*d;
-
- struct IsectRayPrecalc isect_precalc;
- float ray_direction[3];
- sub_v3_v3v3(ray_direction, co2, co1);
- isect_ray_tri_watertight_v3_precalc(&isect_precalc, ray_direction);
-
- /* lets intersect the faces */
- for (i=0; i<totface; i++,mface++) {
- copy_v3_v3(v1, mvert[mface->v1].co);
- copy_v3_v3(v2, mvert[mface->v2].co);
- copy_v3_v3(v3, mvert[mface->v3].co);
-
- bool intersects_tri = isect_ray_tri_watertight_v3(co1,
- &isect_precalc,
- v1, v2, v3,
- &lambda, NULL);
- if (intersects_tri) {
- if (from==PART_FROM_FACE)
- (pa+(int)(lambda*size[a])*a0mul)->flag &= ~PARS_UNEXIST;
- else /* store number of intersections */
- (pa+(int)(lambda*size[a])*a0mul)->hair_index++;
- }
-
- if (mface->v4 && (!intersects_tri || from==PART_FROM_VOLUME)) {
- copy_v3_v3(v4, mvert[mface->v4].co);
-
- if (isect_ray_tri_watertight_v3(
- co1,
- &isect_precalc,
- v1, v3, v4,
- &lambda, NULL))
- {
- if (from==PART_FROM_FACE)
- (pa+(int)(lambda*size[a])*a0mul)->flag &= ~PARS_UNEXIST;
- else
- (pa+(int)(lambda*size[a])*a0mul)->hair_index++;
- }
- }
- }
-
- if (from==PART_FROM_VOLUME) {
- int in=pa->hair_index%2;
- if (in) pa->hair_index++;
- for (i=0; i<size[0]; i++) {
- if (in || (pa+i*a0mul)->hair_index%2)
- (pa+i*a0mul)->flag &= ~PARS_UNEXIST;
- /* odd intersections == in->out / out->in */
- /* even intersections -> in stays same */
- in=(in + (pa+i*a0mul)->hair_index) % 2;
- }
- }
- }
- }
- }
- }
-
- if (psys->part->flag & PART_GRID_HEXAGONAL) {
- for (i=0,p=0,pa=psys->particles; i<res; i++) {
- for (j=0; j<res; j++) {
- for (k=0; k<res; k++,p++,pa++) {
- if (j%2)
- pa->fuv[0] += d/2.f;
-
- if (k%2) {
- pa->fuv[0] += d/2.f;
- pa->fuv[1] += d/2.f;
- }
- }
- }
- }
- }
-
- if (psys->part->flag & PART_GRID_INVERT) {
- for (i=0; i<size[0]; i++) {
- for (j=0; j<size[1]; j++) {
- pa=psys->particles + res*(i*res + j);
- for (k=0; k<size[2]; k++, pa++) {
- pa->flag ^= PARS_UNEXIST;
- }
- }
- }
- }
-
- if (psys->part->grid_rand > 0.f) {
- float rfac = d * psys->part->grid_rand;
- for (p=0,pa=psys->particles; p<psys->totpart; p++,pa++) {
- if (pa->flag & PARS_UNEXIST)
- continue;
-
- pa->fuv[0] += rfac * (psys_frand(psys, p + 31) - 0.5f);
- pa->fuv[1] += rfac * (psys_frand(psys, p + 32) - 0.5f);
- pa->fuv[2] += rfac * (psys_frand(psys, p + 33) - 0.5f);
- }
- }
+ ParticleData *pa = NULL;
+ float min[3], max[3], delta[3], d;
+ MVert *mv, *mvert = mesh->mvert;
+ int totvert = mesh->totvert, from = psys->part->from;
+ int i, j, k, p, res = psys->part->grid_res, size[3], axis;
+
+ /* find bounding box of dm */
+ if (totvert > 0) {
+ mv = mvert;
+ copy_v3_v3(min, mv->co);
+ copy_v3_v3(max, mv->co);
+ mv++;
+ for (i = 1; i < totvert; i++, mv++) {
+ minmax_v3v3_v3(min, max, mv->co);
+ }
+ }
+ else {
+ zero_v3(min);
+ zero_v3(max);
+ }
+
+ sub_v3_v3v3(delta, max, min);
+
+ /* determine major axis */
+ axis = axis_dominant_v3_single(delta);
+
+ d = delta[axis] / (float)res;
+
+ size[axis] = res;
+ size[(axis + 1) % 3] = (int)ceil(delta[(axis + 1) % 3] / d);
+ size[(axis + 2) % 3] = (int)ceil(delta[(axis + 2) % 3] / d);
+
+ /* float errors grrr.. */
+ size[(axis + 1) % 3] = MIN2(size[(axis + 1) % 3], res);
+ size[(axis + 2) % 3] = MIN2(size[(axis + 2) % 3], res);
+
+ size[0] = MAX2(size[0], 1);
+ size[1] = MAX2(size[1], 1);
+ size[2] = MAX2(size[2], 1);
+
+ /* no full offset for flat/thin objects */
+ min[0] += d < delta[0] ? d / 2.f : delta[0] / 2.f;
+ min[1] += d < delta[1] ? d / 2.f : delta[1] / 2.f;
+ min[2] += d < delta[2] ? d / 2.f : delta[2] / 2.f;
+
+ for (i = 0, p = 0, pa = psys->particles; i < res; i++) {
+ for (j = 0; j < res; j++) {
+ for (k = 0; k < res; k++, p++, pa++) {
+ pa->fuv[0] = min[0] + (float)i * d;
+ pa->fuv[1] = min[1] + (float)j * d;
+ pa->fuv[2] = min[2] + (float)k * d;
+ pa->flag |= PARS_UNEXIST;
+ pa->hair_index = 0; /* abused in volume calculation */
+ }
+ }
+ }
+
+ /* enable particles near verts/edges/faces/inside surface */
+ if (from == PART_FROM_VERT) {
+ float vec[3];
+
+ pa = psys->particles;
+
+ min[0] -= d / 2.0f;
+ min[1] -= d / 2.0f;
+ min[2] -= d / 2.0f;
+
+ for (i = 0, mv = mvert; i < totvert; i++, mv++) {
+ sub_v3_v3v3(vec, mv->co, min);
+ vec[0] /= delta[0];
+ vec[1] /= delta[1];
+ vec[2] /= delta[2];
+ pa[((int)(vec[0] * (size[0] - 1)) * res + (int)(vec[1] * (size[1] - 1))) * res +
+ (int)(vec[2] * (size[2] - 1))]
+ .flag &= ~PARS_UNEXIST;
+ }
+ }
+ else if (ELEM(from, PART_FROM_FACE, PART_FROM_VOLUME)) {
+ float co1[3], co2[3];
+
+ MFace *mface = NULL, *mface_array;
+ float v1[3], v2[3], v3[3], v4[4], lambda;
+ int a, a1, a2, a0mul, a1mul, a2mul, totface;
+ int amax = from == PART_FROM_FACE ? 3 : 1;
+
+ totface = mesh->totface;
+ mface = mface_array = mesh->mface;
+
+ for (a = 0; a < amax; a++) {
+ if (a == 0) {
+ a0mul = res * res;
+ a1mul = res;
+ a2mul = 1;
+ }
+ else if (a == 1) {
+ a0mul = res;
+ a1mul = 1;
+ a2mul = res * res;
+ }
+ else {
+ a0mul = 1;
+ a1mul = res * res;
+ a2mul = res;
+ }
+
+ for (a1 = 0; a1 < size[(a + 1) % 3]; a1++) {
+ for (a2 = 0; a2 < size[(a + 2) % 3]; a2++) {
+ mface = mface_array;
+
+ pa = psys->particles + a1 * a1mul + a2 * a2mul;
+ copy_v3_v3(co1, pa->fuv);
+ co1[a] -= d < delta[a] ? d / 2.f : delta[a] / 2.f;
+ copy_v3_v3(co2, co1);
+ co2[a] += delta[a] + 0.001f * d;
+ co1[a] -= 0.001f * d;
+
+ struct IsectRayPrecalc isect_precalc;
+ float ray_direction[3];
+ sub_v3_v3v3(ray_direction, co2, co1);
+ isect_ray_tri_watertight_v3_precalc(&isect_precalc, ray_direction);
+
+ /* lets intersect the faces */
+ for (i = 0; i < totface; i++, mface++) {
+ copy_v3_v3(v1, mvert[mface->v1].co);
+ copy_v3_v3(v2, mvert[mface->v2].co);
+ copy_v3_v3(v3, mvert[mface->v3].co);
+
+ bool intersects_tri = isect_ray_tri_watertight_v3(
+ co1, &isect_precalc, v1, v2, v3, &lambda, NULL);
+ if (intersects_tri) {
+ if (from == PART_FROM_FACE)
+ (pa + (int)(lambda * size[a]) * a0mul)->flag &= ~PARS_UNEXIST;
+ else /* store number of intersections */
+ (pa + (int)(lambda * size[a]) * a0mul)->hair_index++;
+ }
+
+ if (mface->v4 && (!intersects_tri || from == PART_FROM_VOLUME)) {
+ copy_v3_v3(v4, mvert[mface->v4].co);
+
+ if (isect_ray_tri_watertight_v3(co1, &isect_precalc, v1, v3, v4, &lambda, NULL)) {
+ if (from == PART_FROM_FACE)
+ (pa + (int)(lambda * size[a]) * a0mul)->flag &= ~PARS_UNEXIST;
+ else
+ (pa + (int)(lambda * size[a]) * a0mul)->hair_index++;
+ }
+ }
+ }
+
+ if (from == PART_FROM_VOLUME) {
+ int in = pa->hair_index % 2;
+ if (in)
+ pa->hair_index++;
+ for (i = 0; i < size[0]; i++) {
+ if (in || (pa + i * a0mul)->hair_index % 2)
+ (pa + i * a0mul)->flag &= ~PARS_UNEXIST;
+ /* odd intersections == in->out / out->in */
+ /* even intersections -> in stays same */
+ in = (in + (pa + i * a0mul)->hair_index) % 2;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (psys->part->flag & PART_GRID_HEXAGONAL) {
+ for (i = 0, p = 0, pa = psys->particles; i < res; i++) {
+ for (j = 0; j < res; j++) {
+ for (k = 0; k < res; k++, p++, pa++) {
+ if (j % 2)
+ pa->fuv[0] += d / 2.f;
+
+ if (k % 2) {
+ pa->fuv[0] += d / 2.f;
+ pa->fuv[1] += d / 2.f;
+ }
+ }
+ }
+ }
+ }
+
+ if (psys->part->flag & PART_GRID_INVERT) {
+ for (i = 0; i < size[0]; i++) {
+ for (j = 0; j < size[1]; j++) {
+ pa = psys->particles + res * (i * res + j);
+ for (k = 0; k < size[2]; k++, pa++) {
+ pa->flag ^= PARS_UNEXIST;
+ }
+ }
+ }
+ }
+
+ if (psys->part->grid_rand > 0.f) {
+ float rfac = d * psys->part->grid_rand;
+ for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++) {
+ if (pa->flag & PARS_UNEXIST)
+ continue;
+
+ pa->fuv[0] += rfac * (psys_frand(psys, p + 31) - 0.5f);
+ pa->fuv[1] += rfac * (psys_frand(psys, p + 32) - 0.5f);
+ pa->fuv[2] += rfac * (psys_frand(psys, p + 33) - 0.5f);
+ }
+ }
}
/* modified copy from rayshade.c */
static void hammersley_create(float *out, int n, int seed, float amount)
{
- RNG *rng;
+ RNG *rng;
- double offs[2], t;
+ double offs[2], t;
- rng = BLI_rng_new(31415926 + n + seed);
- offs[0] = BLI_rng_get_double(rng) + (double)amount;
- offs[1] = BLI_rng_get_double(rng) + (double)amount;
- BLI_rng_free(rng);
+ rng = BLI_rng_new(31415926 + n + seed);
+ offs[0] = BLI_rng_get_double(rng) + (double)amount;
+ offs[1] = BLI_rng_get_double(rng) + (double)amount;
+ BLI_rng_free(rng);
- for (int k = 0; k < n; k++) {
- BLI_hammersley_1d(k, &t);
+ for (int k = 0; k < n; k++) {
+ BLI_hammersley_1d(k, &t);
- out[2*k + 0] = fmod((double)k/(double)n + offs[0], 1.0);
- out[2*k + 1] = fmod(t + offs[1], 1.0);
- }
+ out[2 * k + 0] = fmod((double)k / (double)n + offs[0], 1.0);
+ out[2 * k + 1] = fmod(t + offs[1], 1.0);
+ }
}
/* almost exact copy of BLI_jitter_init */
static void init_mv_jit(float *jit, int num, int seed2, float amount)
{
- RNG *rng;
- float *jit2, x, rad1, rad2, rad3;
- int i, num2;
+ RNG *rng;
+ float *jit2, x, rad1, rad2, rad3;
+ int i, num2;
- if (num==0) return;
+ if (num == 0)
+ return;
- rad1= (float)(1.0f/sqrtf((float)num));
- rad2= (float)(1.0f/((float)num));
- rad3= (float)sqrtf((float)num)/((float)num);
+ rad1 = (float)(1.0f / sqrtf((float)num));
+ rad2 = (float)(1.0f / ((float)num));
+ rad3 = (float)sqrtf((float)num) / ((float)num);
- rng = BLI_rng_new(31415926 + num + seed2);
- x= 0;
- num2 = 2 * num;
- for (i=0; i<num2; i+=2) {
+ rng = BLI_rng_new(31415926 + num + seed2);
+ x = 0;
+ num2 = 2 * num;
+ for (i = 0; i < num2; i += 2) {
- jit[i] = x + amount*rad1*(0.5f - BLI_rng_get_float(rng));
- jit[i+1] = i/(2.0f*num) + amount*rad1*(0.5f - BLI_rng_get_float(rng));
+ jit[i] = x + amount * rad1 * (0.5f - BLI_rng_get_float(rng));
+ jit[i + 1] = i / (2.0f * num) + amount * rad1 * (0.5f - BLI_rng_get_float(rng));
- jit[i]-= (float)floor(jit[i]);
- jit[i+1]-= (float)floor(jit[i+1]);
+ jit[i] -= (float)floor(jit[i]);
+ jit[i + 1] -= (float)floor(jit[i + 1]);
- x+= rad3;
- x -= (float)floor(x);
- }
+ x += rad3;
+ x -= (float)floor(x);
+ }
- jit2= MEM_mallocN(12 + 2*sizeof(float)*num, "initjit");
+ jit2 = MEM_mallocN(12 + 2 * sizeof(float) * num, "initjit");
- for (i=0 ; i<4 ; i++) {
- BLI_jitterate1((float (*)[2])jit, (float (*)[2])jit2, num, rad1);
- BLI_jitterate1((float (*)[2])jit, (float (*)[2])jit2, num, rad1);
- BLI_jitterate2((float (*)[2])jit, (float (*)[2])jit2, num, rad2);
- }
- MEM_freeN(jit2);
- BLI_rng_free(rng);
+ for (i = 0; i < 4; i++) {
+ BLI_jitterate1((float(*)[2])jit, (float(*)[2])jit2, num, rad1);
+ BLI_jitterate1((float(*)[2])jit, (float(*)[2])jit2, num, rad1);
+ BLI_jitterate2((float(*)[2])jit, (float(*)[2])jit2, num, rad2);
+ }
+ MEM_freeN(jit2);
+ BLI_rng_free(rng);
}
static void psys_uv_to_w(float u, float v, int quad, float *w)
{
- float vert[4][3], co[3];
-
- if (!quad) {
- if (u+v > 1.0f)
- v= 1.0f-v;
- else
- u= 1.0f-u;
- }
-
- vert[0][0] = 0.0f; vert[0][1] = 0.0f; vert[0][2] = 0.0f;
- vert[1][0] = 1.0f; vert[1][1] = 0.0f; vert[1][2] = 0.0f;
- vert[2][0] = 1.0f; vert[2][1] = 1.0f; vert[2][2] = 0.0f;
-
- co[0] = u;
- co[1] = v;
- co[2] = 0.0f;
-
- if (quad) {
- vert[3][0] = 0.0f; vert[3][1] = 1.0f; vert[3][2] = 0.0f;
- interp_weights_poly_v3( w,vert, 4, co);
- }
- else {
- interp_weights_poly_v3( w,vert, 3, co);
- w[3] = 0.0f;
- }
+ float vert[4][3], co[3];
+
+ if (!quad) {
+ if (u + v > 1.0f)
+ v = 1.0f - v;
+ else
+ u = 1.0f - u;
+ }
+
+ vert[0][0] = 0.0f;
+ vert[0][1] = 0.0f;
+ vert[0][2] = 0.0f;
+ vert[1][0] = 1.0f;
+ vert[1][1] = 0.0f;
+ vert[1][2] = 0.0f;
+ vert[2][0] = 1.0f;
+ vert[2][1] = 1.0f;
+ vert[2][2] = 0.0f;
+
+ co[0] = u;
+ co[1] = v;
+ co[2] = 0.0f;
+
+ if (quad) {
+ vert[3][0] = 0.0f;
+ vert[3][1] = 1.0f;
+ vert[3][2] = 0.0f;
+ interp_weights_poly_v3(w, vert, 4, co);
+ }
+ else {
+ interp_weights_poly_v3(w, vert, 3, co);
+ w[3] = 0.0f;
+ }
}
/* Find the index in "sum" array before "value" is crossed. */
static int distribute_binary_search(float *sum, int n, float value)
{
- int mid, low = 0, high = n - 1;
+ int mid, low = 0, high = n - 1;
- if (high == low)
- return low;
+ if (high == low)
+ return low;
- if (sum[low] >= value)
- return low;
+ if (sum[low] >= value)
+ return low;
- if (sum[high - 1] < value)
- return high;
+ if (sum[high - 1] < value)
+ return high;
- while (low < high) {
- mid = (low + high) / 2;
+ while (low < high) {
+ mid = (low + high) / 2;
- if ((sum[mid] >= value) && (sum[mid - 1] < value))
- return mid;
+ if ((sum[mid] >= value) && (sum[mid - 1] < value))
+ return mid;
- if (sum[mid] > value) {
- high = mid - 1;
- }
- else {
- low = mid + 1;
- }
- }
+ if (sum[mid] > value) {
+ high = mid - 1;
+ }
+ else {
+ low = mid + 1;
+ }
+ }
- return low;
+ return low;
}
/* the max number if calls to rng_* funcs within psys_thread_distribute_particle
@@ -429,848 +449,884 @@ static int distribute_binary_search(float *sum, int n, float value)
#define ONLY_WORKING_WITH_PA_VERTS 0
static void distribute_from_verts_exec(ParticleTask *thread, ParticleData *pa, int p)
{
- ParticleThreadContext *ctx= thread->ctx;
- MFace *mface;
+ ParticleThreadContext *ctx = thread->ctx;
+ MFace *mface;
- mface = ctx->mesh->mface;
+ mface = ctx->mesh->mface;
- int rng_skip_tot = PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */
+ int rng_skip_tot = PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */
- /* TODO_PARTICLE - use original index */
- pa->num = ctx->index[p];
+ /* TODO_PARTICLE - use original index */
+ pa->num = ctx->index[p];
- zero_v4(pa->fuv);
+ zero_v4(pa->fuv);
- if (pa->num != DMCACHE_NOTFOUND && pa->num < ctx->mesh->totvert) {
+ if (pa->num != DMCACHE_NOTFOUND && pa->num < ctx->mesh->totvert) {
- /* This finds the first face to contain the emitting vertex,
- * this is not ideal, but is mostly fine as UV seams generally
- * map to equal-colored parts of a texture */
- for (int i = 0; i < ctx->mesh->totface; i++, mface++) {
- if (ELEM(pa->num, mface->v1, mface->v2, mface->v3, mface->v4)) {
- unsigned int *vert = &mface->v1;
+ /* This finds the first face to contain the emitting vertex,
+ * this is not ideal, but is mostly fine as UV seams generally
+ * map to equal-colored parts of a texture */
+ for (int i = 0; i < ctx->mesh->totface; i++, mface++) {
+ if (ELEM(pa->num, mface->v1, mface->v2, mface->v3, mface->v4)) {
+ unsigned int *vert = &mface->v1;
- for (int j = 0; j < 4; j++, vert++) {
- if (*vert == pa->num) {
- pa->fuv[j] = 1.0f;
- break;
- }
- }
+ for (int j = 0; j < 4; j++, vert++) {
+ if (*vert == pa->num) {
+ pa->fuv[j] = 1.0f;
+ break;
+ }
+ }
- break;
- }
- }
- }
+ break;
+ }
+ }
+ }
#if ONLY_WORKING_WITH_PA_VERTS
- if (ctx->tree) {
- KDTreeNearest_3d ptn[3];
- int w, maxw;
-
- psys_particle_on_dm(ctx->mesh,from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co1,0,0,0,orco1,0);
- BKE_mesh_orco_verts_transform(ob->data, &orco1, 1, 1);
- maxw = BLI_kdtree_3d_find_nearest_n(ctx->tree,orco1,ptn,3);
-
- for (w=0; w<maxw; w++) {
- pa->verts[w]=ptn->num;
- }
- }
+ if (ctx->tree) {
+ KDTreeNearest_3d ptn[3];
+ int w, maxw;
+
+ psys_particle_on_dm(
+ ctx->mesh, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co1, 0, 0, 0, orco1, 0);
+ BKE_mesh_orco_verts_transform(ob->data, &orco1, 1, 1);
+ maxw = BLI_kdtree_3d_find_nearest_n(ctx->tree, orco1, ptn, 3);
+
+ for (w = 0; w < maxw; w++) {
+ pa->verts[w] = ptn->num;
+ }
+ }
#endif
- BLI_assert(rng_skip_tot >= 0); /* should never be below zero */
- if (rng_skip_tot > 0) {
- BLI_rng_skip(thread->rng, rng_skip_tot);
- }
+ BLI_assert(rng_skip_tot >= 0); /* should never be below zero */
+ if (rng_skip_tot > 0) {
+ BLI_rng_skip(thread->rng, rng_skip_tot);
+ }
}
-static void distribute_from_faces_exec(ParticleTask *thread, ParticleData *pa, int p) {
- ParticleThreadContext *ctx= thread->ctx;
- Mesh *mesh = ctx->mesh;
- float randu, randv;
- int distr= ctx->distr;
- int i;
- int rng_skip_tot= PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */
-
- MFace *mface;
-
- pa->num = i = ctx->index[p];
- mface = &mesh->mface[i];
-
- switch (distr) {
- case PART_DISTR_JIT:
- if (ctx->jitlevel == 1) {
- if (mface->v4)
- psys_uv_to_w(0.5f, 0.5f, mface->v4, pa->fuv);
- else
- psys_uv_to_w(1.0f / 3.0f, 1.0f / 3.0f, mface->v4, pa->fuv);
- }
- else {
- float offset = fmod(ctx->jitoff[i] + (float)p, (float)ctx->jitlevel);
- if (!isnan(offset)) {
- psys_uv_to_w(ctx->jit[2*(int)offset], ctx->jit[2*(int)offset+1], mface->v4, pa->fuv);
- }
- }
- break;
- case PART_DISTR_RAND:
- randu= BLI_rng_get_float(thread->rng);
- randv= BLI_rng_get_float(thread->rng);
- rng_skip_tot -= 2;
-
- psys_uv_to_w(randu, randv, mface->v4, pa->fuv);
- break;
- }
- pa->foffset= 0.0f;
-
- BLI_assert(rng_skip_tot >= 0); /* should never be below zero */
- if (rng_skip_tot > 0) {
- BLI_rng_skip(thread->rng, rng_skip_tot);
- }
+static void distribute_from_faces_exec(ParticleTask *thread, ParticleData *pa, int p)
+{
+ ParticleThreadContext *ctx = thread->ctx;
+ Mesh *mesh = ctx->mesh;
+ float randu, randv;
+ int distr = ctx->distr;
+ int i;
+ int rng_skip_tot = PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */
+
+ MFace *mface;
+
+ pa->num = i = ctx->index[p];
+ mface = &mesh->mface[i];
+
+ switch (distr) {
+ case PART_DISTR_JIT:
+ if (ctx->jitlevel == 1) {
+ if (mface->v4)
+ psys_uv_to_w(0.5f, 0.5f, mface->v4, pa->fuv);
+ else
+ psys_uv_to_w(1.0f / 3.0f, 1.0f / 3.0f, mface->v4, pa->fuv);
+ }
+ else {
+ float offset = fmod(ctx->jitoff[i] + (float)p, (float)ctx->jitlevel);
+ if (!isnan(offset)) {
+ psys_uv_to_w(
+ ctx->jit[2 * (int)offset], ctx->jit[2 * (int)offset + 1], mface->v4, pa->fuv);
+ }
+ }
+ break;
+ case PART_DISTR_RAND:
+ randu = BLI_rng_get_float(thread->rng);
+ randv = BLI_rng_get_float(thread->rng);
+ rng_skip_tot -= 2;
+
+ psys_uv_to_w(randu, randv, mface->v4, pa->fuv);
+ break;
+ }
+ pa->foffset = 0.0f;
+
+ BLI_assert(rng_skip_tot >= 0); /* should never be below zero */
+ if (rng_skip_tot > 0) {
+ BLI_rng_skip(thread->rng, rng_skip_tot);
+ }
}
-static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa, int p) {
- ParticleThreadContext *ctx= thread->ctx;
- Mesh *mesh = ctx->mesh;
- float *v1, *v2, *v3, *v4, nor[3], co[3];
- float cur_d, min_d, randu, randv;
- int distr= ctx->distr;
- int i, intersect, tot;
- int rng_skip_tot= PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */
-
- MFace *mface;
- MVert *mvert = mesh->mvert;
-
- pa->num = i = ctx->index[p];
- mface = &mesh->mface[i];
-
- switch (distr) {
- case PART_DISTR_JIT:
- if (ctx->jitlevel == 1) {
- if (mface->v4)
- psys_uv_to_w(0.5f, 0.5f, mface->v4, pa->fuv);
- else
- psys_uv_to_w(1.0f / 3.0f, 1.0f / 3.0f, mface->v4, pa->fuv);
- }
- else {
- float offset = fmod(ctx->jitoff[i] + (float)p, (float)ctx->jitlevel);
- if (!isnan(offset)) {
- psys_uv_to_w(ctx->jit[2*(int)offset], ctx->jit[2*(int)offset+1], mface->v4, pa->fuv);
- }
- }
- break;
- case PART_DISTR_RAND:
- randu= BLI_rng_get_float(thread->rng);
- randv= BLI_rng_get_float(thread->rng);
- rng_skip_tot -= 2;
-
- psys_uv_to_w(randu, randv, mface->v4, pa->fuv);
- break;
- }
- pa->foffset= 0.0f;
-
- /* experimental */
- tot = mesh->totface;
-
- psys_interpolate_face(mvert,mface,0,0,pa->fuv,co,nor,0,0,0);
-
- normalize_v3(nor);
- negate_v3(nor);
-
- min_d=FLT_MAX;
- intersect=0;
-
- for (i=0, mface=mesh->mface; i<tot; i++,mface++) {
- if (i==pa->num) continue;
-
- v1=mvert[mface->v1].co;
- v2=mvert[mface->v2].co;
- v3=mvert[mface->v3].co;
-
- if (isect_ray_tri_v3(co, nor, v2, v3, v1, &cur_d, NULL)) {
- if (cur_d<min_d) {
- min_d=cur_d;
- pa->foffset=cur_d*0.5f; /* to the middle of volume */
- intersect=1;
- }
- }
- if (mface->v4) {
- v4=mvert[mface->v4].co;
-
- if (isect_ray_tri_v3(co, nor, v4, v1, v3, &cur_d, NULL)) {
- if (cur_d<min_d) {
- min_d=cur_d;
- pa->foffset=cur_d*0.5f; /* to the middle of volume */
- intersect=1;
- }
- }
- }
- }
- if (intersect==0)
- pa->foffset=0.0;
- else {
- switch (distr) {
- case PART_DISTR_JIT:
- pa->foffset *= ctx->jit[p % (2 * ctx->jitlevel)];
- break;
- case PART_DISTR_RAND:
- pa->foffset *= BLI_rng_get_float(thread->rng);
- rng_skip_tot--;
- break;
- }
- }
-
- BLI_assert(rng_skip_tot >= 0); /* should never be below zero */
- if (rng_skip_tot > 0) {
- BLI_rng_skip(thread->rng, rng_skip_tot);
- }
+static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa, int p)
+{
+ ParticleThreadContext *ctx = thread->ctx;
+ Mesh *mesh = ctx->mesh;
+ float *v1, *v2, *v3, *v4, nor[3], co[3];
+ float cur_d, min_d, randu, randv;
+ int distr = ctx->distr;
+ int i, intersect, tot;
+ int rng_skip_tot = PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */
+
+ MFace *mface;
+ MVert *mvert = mesh->mvert;
+
+ pa->num = i = ctx->index[p];
+ mface = &mesh->mface[i];
+
+ switch (distr) {
+ case PART_DISTR_JIT:
+ if (ctx->jitlevel == 1) {
+ if (mface->v4)
+ psys_uv_to_w(0.5f, 0.5f, mface->v4, pa->fuv);
+ else
+ psys_uv_to_w(1.0f / 3.0f, 1.0f / 3.0f, mface->v4, pa->fuv);
+ }
+ else {
+ float offset = fmod(ctx->jitoff[i] + (float)p, (float)ctx->jitlevel);
+ if (!isnan(offset)) {
+ psys_uv_to_w(
+ ctx->jit[2 * (int)offset], ctx->jit[2 * (int)offset + 1], mface->v4, pa->fuv);
+ }
+ }
+ break;
+ case PART_DISTR_RAND:
+ randu = BLI_rng_get_float(thread->rng);
+ randv = BLI_rng_get_float(thread->rng);
+ rng_skip_tot -= 2;
+
+ psys_uv_to_w(randu, randv, mface->v4, pa->fuv);
+ break;
+ }
+ pa->foffset = 0.0f;
+
+ /* experimental */
+ tot = mesh->totface;
+
+ psys_interpolate_face(mvert, mface, 0, 0, pa->fuv, co, nor, 0, 0, 0);
+
+ normalize_v3(nor);
+ negate_v3(nor);
+
+ min_d = FLT_MAX;
+ intersect = 0;
+
+ for (i = 0, mface = mesh->mface; i < tot; i++, mface++) {
+ if (i == pa->num)
+ continue;
+
+ v1 = mvert[mface->v1].co;
+ v2 = mvert[mface->v2].co;
+ v3 = mvert[mface->v3].co;
+
+ if (isect_ray_tri_v3(co, nor, v2, v3, v1, &cur_d, NULL)) {
+ if (cur_d < min_d) {
+ min_d = cur_d;
+ pa->foffset = cur_d * 0.5f; /* to the middle of volume */
+ intersect = 1;
+ }
+ }
+ if (mface->v4) {
+ v4 = mvert[mface->v4].co;
+
+ if (isect_ray_tri_v3(co, nor, v4, v1, v3, &cur_d, NULL)) {
+ if (cur_d < min_d) {
+ min_d = cur_d;
+ pa->foffset = cur_d * 0.5f; /* to the middle of volume */
+ intersect = 1;
+ }
+ }
+ }
+ }
+ if (intersect == 0)
+ pa->foffset = 0.0;
+ else {
+ switch (distr) {
+ case PART_DISTR_JIT:
+ pa->foffset *= ctx->jit[p % (2 * ctx->jitlevel)];
+ break;
+ case PART_DISTR_RAND:
+ pa->foffset *= BLI_rng_get_float(thread->rng);
+ rng_skip_tot--;
+ break;
+ }
+ }
+
+ BLI_assert(rng_skip_tot >= 0); /* should never be below zero */
+ if (rng_skip_tot > 0) {
+ BLI_rng_skip(thread->rng, rng_skip_tot);
+ }
}
-static void distribute_children_exec(ParticleTask *thread, ChildParticle *cpa, int p) {
- ParticleThreadContext *ctx= thread->ctx;
- Object *ob= ctx->sim.ob;
- Mesh *mesh = ctx->mesh;
- float orco1[3], co1[3], nor1[3];
- float randu, randv;
- int cfrom= ctx->cfrom;
- int i;
- int rng_skip_tot= PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */
-
- MFace *mf;
-
- if (ctx->index[p] < 0) {
- cpa->num=0;
- cpa->fuv[0]=cpa->fuv[1]=cpa->fuv[2]=cpa->fuv[3]=0.0f;
- cpa->pa[0]=cpa->pa[1]=cpa->pa[2]=cpa->pa[3]=0;
- return;
- }
-
- mf = &mesh->mface[ctx->index[p]];
-
- randu= BLI_rng_get_float(thread->rng);
- randv= BLI_rng_get_float(thread->rng);
- rng_skip_tot -= 2;
-
- psys_uv_to_w(randu, randv, mf->v4, cpa->fuv);
-
- cpa->num = ctx->index[p];
-
- if (ctx->tree) {
- KDTreeNearest_3d ptn[10];
- int w,maxw;//, do_seams;
- float maxd /*, mind,dd */, totw= 0.0f;
- int parent[10];
- float pweight[10];
-
- psys_particle_on_dm(mesh,cfrom,cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,co1,nor1,NULL,NULL,orco1);
- BKE_mesh_orco_verts_transform(ob->data, &orco1, 1, 1);
- maxw = BLI_kdtree_3d_find_nearest_n(ctx->tree,orco1,ptn,3);
-
- maxd=ptn[maxw-1].dist;
- /* mind=ptn[0].dist; */ /* UNUSED */
-
- /* the weights here could be done better */
- for (w=0; w<maxw; w++) {
- parent[w]=ptn[w].index;
- pweight[w]=(float)pow(2.0,(double)(-6.0f*ptn[w].dist/maxd));
- }
- for (;w<10; w++) {
- parent[w]=-1;
- pweight[w]=0.0f;
- }
-
- for (w=0,i=0; w<maxw && i<4; w++) {
- if (parent[w]>=0) {
- cpa->pa[i]=parent[w];
- cpa->w[i]=pweight[w];
- totw+=pweight[w];
- i++;
- }
- }
- for (;i<4; i++) {
- cpa->pa[i]=-1;
- cpa->w[i]=0.0f;
- }
-
- if (totw > 0.0f) {
- for (w = 0; w < 4; w++) {
- cpa->w[w] /= totw;
- }
- }
-
- cpa->parent=cpa->pa[0];
- }
-
- if (rng_skip_tot > 0) /* should never be below zero */
- BLI_rng_skip(thread->rng, rng_skip_tot);
+static void distribute_children_exec(ParticleTask *thread, ChildParticle *cpa, int p)
+{
+ ParticleThreadContext *ctx = thread->ctx;
+ Object *ob = ctx->sim.ob;
+ Mesh *mesh = ctx->mesh;
+ float orco1[3], co1[3], nor1[3];
+ float randu, randv;
+ int cfrom = ctx->cfrom;
+ int i;
+ int rng_skip_tot = PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */
+
+ MFace *mf;
+
+ if (ctx->index[p] < 0) {
+ cpa->num = 0;
+ cpa->fuv[0] = cpa->fuv[1] = cpa->fuv[2] = cpa->fuv[3] = 0.0f;
+ cpa->pa[0] = cpa->pa[1] = cpa->pa[2] = cpa->pa[3] = 0;
+ return;
+ }
+
+ mf = &mesh->mface[ctx->index[p]];
+
+ randu = BLI_rng_get_float(thread->rng);
+ randv = BLI_rng_get_float(thread->rng);
+ rng_skip_tot -= 2;
+
+ psys_uv_to_w(randu, randv, mf->v4, cpa->fuv);
+
+ cpa->num = ctx->index[p];
+
+ if (ctx->tree) {
+ KDTreeNearest_3d ptn[10];
+ int w, maxw; //, do_seams;
+ float maxd /*, mind,dd */, totw = 0.0f;
+ int parent[10];
+ float pweight[10];
+
+ psys_particle_on_dm(mesh,
+ cfrom,
+ cpa->num,
+ DMCACHE_ISCHILD,
+ cpa->fuv,
+ cpa->foffset,
+ co1,
+ nor1,
+ NULL,
+ NULL,
+ orco1);
+ BKE_mesh_orco_verts_transform(ob->data, &orco1, 1, 1);
+ maxw = BLI_kdtree_3d_find_nearest_n(ctx->tree, orco1, ptn, 3);
+
+ maxd = ptn[maxw - 1].dist;
+ /* mind=ptn[0].dist; */ /* UNUSED */
+
+ /* the weights here could be done better */
+ for (w = 0; w < maxw; w++) {
+ parent[w] = ptn[w].index;
+ pweight[w] = (float)pow(2.0, (double)(-6.0f * ptn[w].dist / maxd));
+ }
+ for (; w < 10; w++) {
+ parent[w] = -1;
+ pweight[w] = 0.0f;
+ }
+
+ for (w = 0, i = 0; w < maxw && i < 4; w++) {
+ if (parent[w] >= 0) {
+ cpa->pa[i] = parent[w];
+ cpa->w[i] = pweight[w];
+ totw += pweight[w];
+ i++;
+ }
+ }
+ for (; i < 4; i++) {
+ cpa->pa[i] = -1;
+ cpa->w[i] = 0.0f;
+ }
+
+ if (totw > 0.0f) {
+ for (w = 0; w < 4; w++) {
+ cpa->w[w] /= totw;
+ }
+ }
+
+ cpa->parent = cpa->pa[0];
+ }
+
+ if (rng_skip_tot > 0) /* should never be below zero */
+ BLI_rng_skip(thread->rng, rng_skip_tot);
}
-static void exec_distribute_parent(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
+static void exec_distribute_parent(TaskPool *__restrict UNUSED(pool),
+ void *taskdata,
+ int UNUSED(threadid))
{
- ParticleTask *task = taskdata;
- ParticleSystem *psys= task->ctx->sim.psys;
- ParticleData *pa;
- int p;
-
- BLI_rng_skip(task->rng, PSYS_RND_DIST_SKIP * task->begin);
-
- pa= psys->particles + task->begin;
- switch (psys->part->from) {
- case PART_FROM_FACE:
- for (p = task->begin; p < task->end; ++p, ++pa)
- distribute_from_faces_exec(task, pa, p);
- break;
- case PART_FROM_VOLUME:
- for (p = task->begin; p < task->end; ++p, ++pa)
- distribute_from_volume_exec(task, pa, p);
- break;
- case PART_FROM_VERT:
- for (p = task->begin; p < task->end; ++p, ++pa)
- distribute_from_verts_exec(task, pa, p);
- break;
- }
+ ParticleTask *task = taskdata;
+ ParticleSystem *psys = task->ctx->sim.psys;
+ ParticleData *pa;
+ int p;
+
+ BLI_rng_skip(task->rng, PSYS_RND_DIST_SKIP * task->begin);
+
+ pa = psys->particles + task->begin;
+ switch (psys->part->from) {
+ case PART_FROM_FACE:
+ for (p = task->begin; p < task->end; ++p, ++pa)
+ distribute_from_faces_exec(task, pa, p);
+ break;
+ case PART_FROM_VOLUME:
+ for (p = task->begin; p < task->end; ++p, ++pa)
+ distribute_from_volume_exec(task, pa, p);
+ break;
+ case PART_FROM_VERT:
+ for (p = task->begin; p < task->end; ++p, ++pa)
+ distribute_from_verts_exec(task, pa, p);
+ break;
+ }
}
-static void exec_distribute_child(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
+static void exec_distribute_child(TaskPool *__restrict UNUSED(pool),
+ void *taskdata,
+ int UNUSED(threadid))
{
- ParticleTask *task = taskdata;
- ParticleSystem *psys = task->ctx->sim.psys;
- ChildParticle *cpa;
- int p;
-
- /* RNG skipping at the beginning */
- cpa = psys->child;
- for (p = 0; p < task->begin; ++p, ++cpa) {
- BLI_rng_skip(task->rng, PSYS_RND_DIST_SKIP);
- }
-
- for (; p < task->end; ++p, ++cpa) {
- distribute_children_exec(task, cpa, p);
- }
+ ParticleTask *task = taskdata;
+ ParticleSystem *psys = task->ctx->sim.psys;
+ ChildParticle *cpa;
+ int p;
+
+ /* RNG skipping at the beginning */
+ cpa = psys->child;
+ for (p = 0; p < task->begin; ++p, ++cpa) {
+ BLI_rng_skip(task->rng, PSYS_RND_DIST_SKIP);
+ }
+
+ for (; p < task->end; ++p, ++cpa) {
+ distribute_children_exec(task, cpa, p);
+ }
}
static int distribute_compare_orig_index(const void *p1, const void *p2, void *user_data)
{
- int *orig_index = (int *) user_data;
- int index1 = orig_index[*(const int *)p1];
- int index2 = orig_index[*(const int *)p2];
-
- if (index1 < index2)
- return -1;
- else if (index1 == index2) {
- /* this pointer comparison appears to make qsort stable for glibc,
- * and apparently on solaris too, makes the renders reproducible */
- if (p1 < p2)
- return -1;
- else if (p1 == p2)
- return 0;
- else
- return 1;
- }
- else
- return 1;
+ int *orig_index = (int *)user_data;
+ int index1 = orig_index[*(const int *)p1];
+ int index2 = orig_index[*(const int *)p2];
+
+ if (index1 < index2)
+ return -1;
+ else if (index1 == index2) {
+ /* this pointer comparison appears to make qsort stable for glibc,
+ * and apparently on solaris too, makes the renders reproducible */
+ if (p1 < p2)
+ return -1;
+ else if (p1 == p2)
+ return 0;
+ else
+ return 1;
+ }
+ else
+ return 1;
}
static void distribute_invalid(ParticleSimulationData *sim, int from)
{
- Scene *scene = sim->scene;
- ParticleSystem *psys = sim->psys;
- const bool use_render_params = (DEG_get_mode(sim->depsgraph) == DAG_EVAL_RENDER);
-
- if (from == PART_FROM_CHILD) {
- ChildParticle *cpa;
- int p, totchild = psys_get_tot_child(scene, psys, use_render_params);
-
- if (psys->child && totchild) {
- for (p=0,cpa=psys->child; p<totchild; p++,cpa++) {
- cpa->fuv[0]=cpa->fuv[1]=cpa->fuv[2]=cpa->fuv[3] = 0.0;
- cpa->foffset= 0.0f;
- cpa->parent=0;
- cpa->pa[0]=cpa->pa[1]=cpa->pa[2]=cpa->pa[3]=0;
- cpa->num= -1;
- }
- }
- }
- else {
- PARTICLE_P;
- LOOP_PARTICLES {
- pa->fuv[0] = pa->fuv[1] = pa->fuv[2] = pa->fuv[3] = 0.0;
- pa->foffset= 0.0f;
- pa->num= -1;
- }
- }
+ Scene *scene = sim->scene;
+ ParticleSystem *psys = sim->psys;
+ const bool use_render_params = (DEG_get_mode(sim->depsgraph) == DAG_EVAL_RENDER);
+
+ if (from == PART_FROM_CHILD) {
+ ChildParticle *cpa;
+ int p, totchild = psys_get_tot_child(scene, psys, use_render_params);
+
+ if (psys->child && totchild) {
+ for (p = 0, cpa = psys->child; p < totchild; p++, cpa++) {
+ cpa->fuv[0] = cpa->fuv[1] = cpa->fuv[2] = cpa->fuv[3] = 0.0;
+ cpa->foffset = 0.0f;
+ cpa->parent = 0;
+ cpa->pa[0] = cpa->pa[1] = cpa->pa[2] = cpa->pa[3] = 0;
+ cpa->num = -1;
+ }
+ }
+ }
+ else {
+ PARTICLE_P;
+ LOOP_PARTICLES
+ {
+ pa->fuv[0] = pa->fuv[1] = pa->fuv[2] = pa->fuv[3] = 0.0;
+ pa->foffset = 0.0f;
+ pa->num = -1;
+ }
+ }
}
/* Creates a distribution of coordinates on a Mesh */
-static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, ParticleSimulationData *sim, int from)
+static int psys_thread_context_init_distribute(ParticleThreadContext *ctx,
+ ParticleSimulationData *sim,
+ int from)
{
- Scene *scene = sim->scene;
- Mesh *final_mesh = sim->psmd->mesh_final;
- Object *ob = sim->ob;
- ParticleSystem *psys= sim->psys;
- ParticleData *pa=0, *tpars= 0;
- ParticleSettings *part;
- ParticleSeam *seams= 0;
- KDTree_3d *tree=0;
- Mesh *mesh = NULL;
- float *jit= NULL;
- int i, p=0;
- int cfrom=0;
- int totelem=0, totpart, *particle_element=0, children=0, totseam=0;
- int jitlevel= 1, distr;
- float *element_weight=NULL,*jitter_offset=NULL, *vweight=NULL;
- float cur, maxweight=0.0, tweight, totweight, inv_totweight, co[3], nor[3], orco[3];
- RNG *rng = NULL;
-
- if (ELEM(NULL, ob, psys, psys->part))
- return 0;
-
- part=psys->part;
- totpart=psys->totpart;
- if (totpart==0)
- return 0;
-
- if (!final_mesh->runtime.deformed_only && !CustomData_get_layer(&final_mesh->fdata, CD_ORIGINDEX)) {
- printf("Can't create particles with the current modifier stack, disable destructive modifiers\n");
-// XXX error("Can't paint with the current modifier stack, disable destructive modifiers");
- return 0;
- }
-
- /* XXX This distribution code is totally broken in case from == PART_FROM_CHILD, it's always using finaldm
- * even if use_modifier_stack is unset... But making things consistent here break all existing edited
- * hair systems, so better wait for complete rewrite.
- */
-
- psys_thread_context_init(ctx, sim);
-
- const bool use_render_params = (DEG_get_mode(sim->depsgraph) == DAG_EVAL_RENDER);
-
- /* First handle special cases */
- if (from == PART_FROM_CHILD) {
- /* Simple children */
- if (part->childtype != PART_CHILD_FACES) {
- distribute_simple_children(scene, ob, final_mesh, sim->psmd->mesh_original, psys, use_render_params);
- return 0;
- }
- }
- else {
- /* Grid distribution */
- if (part->distr==PART_DISTR_GRID && from != PART_FROM_VERT) {
- if (psys->part->use_modifier_stack) {
- mesh = final_mesh;
- }
- else {
- BKE_id_copy_ex(NULL, ob->data, (ID **)&mesh, LIB_ID_COPY_LOCALIZE);
- }
- BKE_mesh_tessface_ensure(mesh);
-
- distribute_grid(mesh,psys);
-
- if (mesh != final_mesh) {
- BKE_id_free(NULL, mesh);
- }
-
- return 0;
- }
- }
-
- /* Create trees and original coordinates if needed */
- if (from == PART_FROM_CHILD) {
- distr = PART_DISTR_RAND;
- rng = BLI_rng_new_srandom(31415926 + psys->seed + psys->child_seed);
- mesh= final_mesh;
-
- /* BMESH ONLY */
- BKE_mesh_tessface_ensure(mesh);
-
- children=1;
-
- tree=BLI_kdtree_3d_new(totpart);
-
- for (p=0,pa=psys->particles; p<totpart; p++,pa++) {
- psys_particle_on_dm(mesh,part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co,nor,0,0,orco);
- BKE_mesh_orco_verts_transform(ob->data, &orco, 1, 1);
- BLI_kdtree_3d_insert(tree, p, orco);
- }
-
- BLI_kdtree_3d_balance(tree);
-
- totpart = psys_get_tot_child(scene, psys, use_render_params);
- cfrom = from = PART_FROM_FACE;
- }
- else {
- distr = part->distr;
-
- rng = BLI_rng_new_srandom(31415926 + psys->seed);
-
- if (psys->part->use_modifier_stack)
- mesh = final_mesh;
- else
- BKE_id_copy_ex(NULL, ob->data, (ID **)&mesh, LIB_ID_COPY_LOCALIZE);
-
- BKE_mesh_tessface_ensure(mesh);
-
- /* we need orco for consistent distributions */
- if (!CustomData_has_layer(&mesh->vdata, CD_ORCO)) {
- /* Orcos are stored in normalized 0..1 range by convention. */
- float (*orcodata)[3] = BKE_mesh_orco_verts_get(ob);
- BKE_mesh_orco_verts_transform(mesh, orcodata, mesh->totvert, false);
- CustomData_add_layer(&mesh->vdata, CD_ORCO, CD_ASSIGN, orcodata, mesh->totvert);
- }
-
- if (from == PART_FROM_VERT) {
- MVert *mv = mesh->mvert;
- float (*orcodata)[3] = CustomData_get_layer(&mesh->vdata, CD_ORCO);
- int totvert = mesh->totvert;
-
- tree=BLI_kdtree_3d_new(totvert);
-
- for (p=0; p<totvert; p++) {
- if (orcodata) {
- copy_v3_v3(co,orcodata[p]);
- BKE_mesh_orco_verts_transform(ob->data, &co, 1, 1);
- }
- else
- copy_v3_v3(co,mv[p].co);
- BLI_kdtree_3d_insert(tree, p, co);
- }
-
- BLI_kdtree_3d_balance(tree);
- }
- }
-
- /* Get total number of emission elements and allocate needed arrays */
- totelem = (from == PART_FROM_VERT) ? mesh->totvert : mesh->totface;
-
- if (totelem == 0) {
- distribute_invalid(sim, children ? PART_FROM_CHILD : 0);
-
- if (G.debug & G_DEBUG)
- fprintf(stderr,"Particle distribution error: Nothing to emit from!\n");
-
- if (mesh != final_mesh) BKE_id_free(NULL, mesh);
-
- BLI_kdtree_3d_free(tree);
- BLI_rng_free(rng);
-
- return 0;
- }
-
- element_weight = MEM_callocN(sizeof(float) * totelem, "particle_distribution_weights");
- particle_element = MEM_callocN(sizeof(int) * totpart, "particle_distribution_indexes");
- jitter_offset = MEM_callocN(sizeof(float) * totelem, "particle_distribution_jitoff");
-
- /* Calculate weights from face areas */
- if ((part->flag & PART_EDISTR || children) && from != PART_FROM_VERT) {
- MVert *v1, *v2, *v3, *v4;
- float totarea=0.f, co1[3], co2[3], co3[3], co4[3];
- float (*orcodata)[3];
-
- orcodata = CustomData_get_layer(&mesh->vdata, CD_ORCO);
-
- for (i=0; i<totelem; i++) {
- MFace *mf = &mesh->mface[i];
-
- if (orcodata) {
- /* Transform orcos from normalized 0..1 to object space. */
- copy_v3_v3(co1, orcodata[mf->v1]);
- copy_v3_v3(co2, orcodata[mf->v2]);
- copy_v3_v3(co3, orcodata[mf->v3]);
- BKE_mesh_orco_verts_transform(ob->data, &co1, 1, 1);
- BKE_mesh_orco_verts_transform(ob->data, &co2, 1, 1);
- BKE_mesh_orco_verts_transform(ob->data, &co3, 1, 1);
- if (mf->v4) {
- copy_v3_v3(co4, orcodata[mf->v4]);
- BKE_mesh_orco_verts_transform(ob->data, &co4, 1, 1);
- }
- }
- else {
- v1 = &mesh->mvert[mf->v1];
- v2 = &mesh->mvert[mf->v2];
- v3 = &mesh->mvert[mf->v3];
- copy_v3_v3(co1, v1->co);
- copy_v3_v3(co2, v2->co);
- copy_v3_v3(co3, v3->co);
- if (mf->v4) {
- v4 = &mesh->mvert[mf->v4];
- copy_v3_v3(co4, v4->co);
- }
- }
-
- cur = mf->v4 ? area_quad_v3(co1, co2, co3, co4) : area_tri_v3(co1, co2, co3);
-
- if (cur > maxweight)
- maxweight = cur;
-
- element_weight[i] = cur;
- totarea += cur;
- }
-
- for (i=0; i<totelem; i++)
- element_weight[i] /= totarea;
-
- maxweight /= totarea;
- }
- else {
- float min=1.0f/(float)(MIN2(totelem,totpart));
- for (i=0; i<totelem; i++)
- element_weight[i]=min;
- maxweight=min;
- }
-
- /* Calculate weights from vgroup */
- vweight = psys_cache_vgroup(mesh,psys,PSYS_VG_DENSITY);
-
- if (vweight) {
- if (from==PART_FROM_VERT) {
- for (i=0;i<totelem; i++)
- element_weight[i]*=vweight[i];
- }
- else { /* PART_FROM_FACE / PART_FROM_VOLUME */
- for (i=0;i<totelem; i++) {
- MFace *mf = &mesh->mface[i];
- tweight = vweight[mf->v1] + vweight[mf->v2] + vweight[mf->v3];
-
- if (mf->v4) {
- tweight += vweight[mf->v4];
- tweight /= 4.0f;
- }
- else {
- tweight /= 3.0f;
- }
-
- element_weight[i]*=tweight;
- }
- }
- MEM_freeN(vweight);
- }
-
- /* Calculate total weight of all elements */
- int totmapped = 0;
- totweight = 0.0f;
- for (i = 0; i < totelem; i++) {
- if (element_weight[i] > 0.0f) {
- totmapped++;
- totweight += element_weight[i];
- }
- }
-
- if (totmapped == 0) {
- /* We are not allowed to distribute particles anywhere... */
- if (mesh != final_mesh) {
- BKE_id_free(NULL, mesh);
- }
- BLI_kdtree_3d_free(tree);
- BLI_rng_free(rng);
- MEM_freeN(element_weight);
- MEM_freeN(particle_element);
- MEM_freeN(jitter_offset);
- return 0;
- }
-
- inv_totweight = 1.0f / totweight;
-
- /* Calculate cumulative weights.
- * We remove all null-weighted elements from element_sum, and create a new mapping
- * 'activ'_elem_index -> orig_elem_index.
- * This simplifies greatly the filtering of zero-weighted items - and can be much more efficient
- * especially in random case (reducing a lot the size of binary-searched array)...
- */
- float *element_sum = MEM_mallocN(sizeof(*element_sum) * totmapped, __func__);
- int *element_map = MEM_mallocN(sizeof(*element_map) * totmapped, __func__);
- int i_mapped = 0;
-
- for (i = 0; i < totelem && element_weight[i] == 0.0f; i++);
- element_sum[i_mapped] = element_weight[i] * inv_totweight;
- element_map[i_mapped] = i;
- i_mapped++;
- for (i++; i < totelem; i++) {
- if (element_weight[i] > 0.0f) {
- element_sum[i_mapped] = element_sum[i_mapped - 1] + element_weight[i] * inv_totweight;
- /* Skip elements which weight is so small that it does not affect the sum. */
- if (element_sum[i_mapped] > element_sum[i_mapped - 1]) {
- element_map[i_mapped] = i;
- i_mapped++;
- }
- }
- }
- totmapped = i_mapped;
-
- /* Finally assign elements to particles */
- if (part->flag & PART_TRAND) {
- for (p = 0; p < totpart; p++) {
- /* In theory element_sum[totmapped - 1] should be 1.0,
- * but due to float errors this is not necessarily always true, so scale pos accordingly. */
- const float pos = BLI_rng_get_float(rng) * element_sum[totmapped - 1];
- const int eidx = distribute_binary_search(element_sum, totmapped, pos);
- particle_element[p] = element_map[eidx];
- BLI_assert(pos <= element_sum[eidx]);
- BLI_assert(eidx ? (pos > element_sum[eidx - 1]) : (pos >= 0.0f));
- jitter_offset[particle_element[p]] = pos;
- }
- }
- else {
- double step, pos;
-
- step = (totpart < 2) ? 0.5 : 1.0 / (double)totpart;
- /* This is to address tricky issues with vertex-emitting when user tries (and expects) exact 1-1 vert/part
- * distribution (see T47983 and its two example files). It allows us to consider pos as
- * 'midpoint between v and v+1' (or 'p and p+1', depending whether we have more vertices than particles or not),
- * and avoid stumbling over float impression in element_sum.
- * Note: moved face and volume distribution to this as well (instead of starting at zero),
- * for the same reasons, see T52682. */
- pos = (totpart < totmapped) ? 0.5 / (double)totmapped : step * 0.5; /* We choose the smaller step. */
-
- for (i = 0, p = 0; p < totpart; p++, pos += step) {
- for ( ; (i < totmapped - 1) && (pos > (double)element_sum[i]); i++);
-
- particle_element[p] = element_map[i];
-
- jitter_offset[particle_element[p]] = pos;
- }
- }
-
- MEM_freeN(element_sum);
- MEM_freeN(element_map);
-
- /* For hair, sort by origindex (allows optimization's in rendering), */
- /* however with virtual parents the children need to be in random order. */
- if (part->type == PART_HAIR && !(part->childtype==PART_CHILD_FACES && part->parents != 0.0f)) {
- int *orig_index = NULL;
-
- if (from == PART_FROM_VERT) {
- if (mesh->totvert)
- orig_index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX);
- }
- else {
- if (mesh->totface)
- orig_index = CustomData_get_layer(&mesh->fdata, CD_ORIGINDEX);
- }
-
- if (orig_index) {
- BLI_qsort_r(particle_element, totpart, sizeof(int), distribute_compare_orig_index, orig_index);
- }
- }
-
- /* Create jittering if needed */
- if (distr==PART_DISTR_JIT && ELEM(from,PART_FROM_FACE,PART_FROM_VOLUME)) {
- jitlevel= part->userjit;
-
- if (jitlevel == 0) {
- jitlevel= totpart/totelem;
- if (part->flag & PART_EDISTR) jitlevel*= 2; /* looks better in general, not very scientific */
- if (jitlevel<3) jitlevel= 3;
- }
-
- jit= MEM_callocN((2+ jitlevel*2)*sizeof(float), "jit");
-
- /* for small amounts of particles we use regular jitter since it looks
- * a bit better, for larger amounts we switch to hammersley sequence
- * because it is much faster */
- if (jitlevel < 25)
- init_mv_jit(jit, jitlevel, psys->seed, part->jitfac);
- else
- hammersley_create(jit, jitlevel+1, psys->seed, part->jitfac);
- BLI_array_randomize(jit, 2*sizeof(float), jitlevel, psys->seed); /* for custom jit or even distribution */
- }
-
- /* Setup things for threaded distribution */
- ctx->tree= tree;
- ctx->seams= seams;
- ctx->totseam= totseam;
- ctx->sim.psys= psys;
- ctx->index= particle_element;
- ctx->jit= jit;
- ctx->jitlevel= jitlevel;
- ctx->jitoff= jitter_offset;
- ctx->weight= element_weight;
- ctx->maxweight= maxweight;
- ctx->cfrom= cfrom;
- ctx->distr= distr;
- ctx->mesh= mesh;
- ctx->tpars= tpars;
-
- if (children) {
- alloc_child_particles(psys, totpart);
- }
-
- BLI_rng_free(rng);
-
- return 1;
+ Scene *scene = sim->scene;
+ Mesh *final_mesh = sim->psmd->mesh_final;
+ Object *ob = sim->ob;
+ ParticleSystem *psys = sim->psys;
+ ParticleData *pa = 0, *tpars = 0;
+ ParticleSettings *part;
+ ParticleSeam *seams = 0;
+ KDTree_3d *tree = 0;
+ Mesh *mesh = NULL;
+ float *jit = NULL;
+ int i, p = 0;
+ int cfrom = 0;
+ int totelem = 0, totpart, *particle_element = 0, children = 0, totseam = 0;
+ int jitlevel = 1, distr;
+ float *element_weight = NULL, *jitter_offset = NULL, *vweight = NULL;
+ float cur, maxweight = 0.0, tweight, totweight, inv_totweight, co[3], nor[3], orco[3];
+ RNG *rng = NULL;
+
+ if (ELEM(NULL, ob, psys, psys->part))
+ return 0;
+
+ part = psys->part;
+ totpart = psys->totpart;
+ if (totpart == 0)
+ return 0;
+
+ if (!final_mesh->runtime.deformed_only &&
+ !CustomData_get_layer(&final_mesh->fdata, CD_ORIGINDEX)) {
+ printf(
+ "Can't create particles with the current modifier stack, disable destructive modifiers\n");
+ // XXX error("Can't paint with the current modifier stack, disable destructive modifiers");
+ return 0;
+ }
+
+ /* XXX This distribution code is totally broken in case from == PART_FROM_CHILD, it's always using finaldm
+ * even if use_modifier_stack is unset... But making things consistent here break all existing edited
+ * hair systems, so better wait for complete rewrite.
+ */
+
+ psys_thread_context_init(ctx, sim);
+
+ const bool use_render_params = (DEG_get_mode(sim->depsgraph) == DAG_EVAL_RENDER);
+
+ /* First handle special cases */
+ if (from == PART_FROM_CHILD) {
+ /* Simple children */
+ if (part->childtype != PART_CHILD_FACES) {
+ distribute_simple_children(
+ scene, ob, final_mesh, sim->psmd->mesh_original, psys, use_render_params);
+ return 0;
+ }
+ }
+ else {
+ /* Grid distribution */
+ if (part->distr == PART_DISTR_GRID && from != PART_FROM_VERT) {
+ if (psys->part->use_modifier_stack) {
+ mesh = final_mesh;
+ }
+ else {
+ BKE_id_copy_ex(NULL, ob->data, (ID **)&mesh, LIB_ID_COPY_LOCALIZE);
+ }
+ BKE_mesh_tessface_ensure(mesh);
+
+ distribute_grid(mesh, psys);
+
+ if (mesh != final_mesh) {
+ BKE_id_free(NULL, mesh);
+ }
+
+ return 0;
+ }
+ }
+
+ /* Create trees and original coordinates if needed */
+ if (from == PART_FROM_CHILD) {
+ distr = PART_DISTR_RAND;
+ rng = BLI_rng_new_srandom(31415926 + psys->seed + psys->child_seed);
+ mesh = final_mesh;
+
+ /* BMESH ONLY */
+ BKE_mesh_tessface_ensure(mesh);
+
+ children = 1;
+
+ tree = BLI_kdtree_3d_new(totpart);
+
+ for (p = 0, pa = psys->particles; p < totpart; p++, pa++) {
+ psys_particle_on_dm(
+ mesh, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co, nor, 0, 0, orco);
+ BKE_mesh_orco_verts_transform(ob->data, &orco, 1, 1);
+ BLI_kdtree_3d_insert(tree, p, orco);
+ }
+
+ BLI_kdtree_3d_balance(tree);
+
+ totpart = psys_get_tot_child(scene, psys, use_render_params);
+ cfrom = from = PART_FROM_FACE;
+ }
+ else {
+ distr = part->distr;
+
+ rng = BLI_rng_new_srandom(31415926 + psys->seed);
+
+ if (psys->part->use_modifier_stack)
+ mesh = final_mesh;
+ else
+ BKE_id_copy_ex(NULL, ob->data, (ID **)&mesh, LIB_ID_COPY_LOCALIZE);
+
+ BKE_mesh_tessface_ensure(mesh);
+
+ /* we need orco for consistent distributions */
+ if (!CustomData_has_layer(&mesh->vdata, CD_ORCO)) {
+ /* Orcos are stored in normalized 0..1 range by convention. */
+ float(*orcodata)[3] = BKE_mesh_orco_verts_get(ob);
+ BKE_mesh_orco_verts_transform(mesh, orcodata, mesh->totvert, false);
+ CustomData_add_layer(&mesh->vdata, CD_ORCO, CD_ASSIGN, orcodata, mesh->totvert);
+ }
+
+ if (from == PART_FROM_VERT) {
+ MVert *mv = mesh->mvert;
+ float(*orcodata)[3] = CustomData_get_layer(&mesh->vdata, CD_ORCO);
+ int totvert = mesh->totvert;
+
+ tree = BLI_kdtree_3d_new(totvert);
+
+ for (p = 0; p < totvert; p++) {
+ if (orcodata) {
+ copy_v3_v3(co, orcodata[p]);
+ BKE_mesh_orco_verts_transform(ob->data, &co, 1, 1);
+ }
+ else
+ copy_v3_v3(co, mv[p].co);
+ BLI_kdtree_3d_insert(tree, p, co);
+ }
+
+ BLI_kdtree_3d_balance(tree);
+ }
+ }
+
+ /* Get total number of emission elements and allocate needed arrays */
+ totelem = (from == PART_FROM_VERT) ? mesh->totvert : mesh->totface;
+
+ if (totelem == 0) {
+ distribute_invalid(sim, children ? PART_FROM_CHILD : 0);
+
+ if (G.debug & G_DEBUG)
+ fprintf(stderr, "Particle distribution error: Nothing to emit from!\n");
+
+ if (mesh != final_mesh)
+ BKE_id_free(NULL, mesh);
+
+ BLI_kdtree_3d_free(tree);
+ BLI_rng_free(rng);
+
+ return 0;
+ }
+
+ element_weight = MEM_callocN(sizeof(float) * totelem, "particle_distribution_weights");
+ particle_element = MEM_callocN(sizeof(int) * totpart, "particle_distribution_indexes");
+ jitter_offset = MEM_callocN(sizeof(float) * totelem, "particle_distribution_jitoff");
+
+ /* Calculate weights from face areas */
+ if ((part->flag & PART_EDISTR || children) && from != PART_FROM_VERT) {
+ MVert *v1, *v2, *v3, *v4;
+ float totarea = 0.f, co1[3], co2[3], co3[3], co4[3];
+ float(*orcodata)[3];
+
+ orcodata = CustomData_get_layer(&mesh->vdata, CD_ORCO);
+
+ for (i = 0; i < totelem; i++) {
+ MFace *mf = &mesh->mface[i];
+
+ if (orcodata) {
+ /* Transform orcos from normalized 0..1 to object space. */
+ copy_v3_v3(co1, orcodata[mf->v1]);
+ copy_v3_v3(co2, orcodata[mf->v2]);
+ copy_v3_v3(co3, orcodata[mf->v3]);
+ BKE_mesh_orco_verts_transform(ob->data, &co1, 1, 1);
+ BKE_mesh_orco_verts_transform(ob->data, &co2, 1, 1);
+ BKE_mesh_orco_verts_transform(ob->data, &co3, 1, 1);
+ if (mf->v4) {
+ copy_v3_v3(co4, orcodata[mf->v4]);
+ BKE_mesh_orco_verts_transform(ob->data, &co4, 1, 1);
+ }
+ }
+ else {
+ v1 = &mesh->mvert[mf->v1];
+ v2 = &mesh->mvert[mf->v2];
+ v3 = &mesh->mvert[mf->v3];
+ copy_v3_v3(co1, v1->co);
+ copy_v3_v3(co2, v2->co);
+ copy_v3_v3(co3, v3->co);
+ if (mf->v4) {
+ v4 = &mesh->mvert[mf->v4];
+ copy_v3_v3(co4, v4->co);
+ }
+ }
+
+ cur = mf->v4 ? area_quad_v3(co1, co2, co3, co4) : area_tri_v3(co1, co2, co3);
+
+ if (cur > maxweight)
+ maxweight = cur;
+
+ element_weight[i] = cur;
+ totarea += cur;
+ }
+
+ for (i = 0; i < totelem; i++)
+ element_weight[i] /= totarea;
+
+ maxweight /= totarea;
+ }
+ else {
+ float min = 1.0f / (float)(MIN2(totelem, totpart));
+ for (i = 0; i < totelem; i++)
+ element_weight[i] = min;
+ maxweight = min;
+ }
+
+ /* Calculate weights from vgroup */
+ vweight = psys_cache_vgroup(mesh, psys, PSYS_VG_DENSITY);
+
+ if (vweight) {
+ if (from == PART_FROM_VERT) {
+ for (i = 0; i < totelem; i++)
+ element_weight[i] *= vweight[i];
+ }
+ else { /* PART_FROM_FACE / PART_FROM_VOLUME */
+ for (i = 0; i < totelem; i++) {
+ MFace *mf = &mesh->mface[i];
+ tweight = vweight[mf->v1] + vweight[mf->v2] + vweight[mf->v3];
+
+ if (mf->v4) {
+ tweight += vweight[mf->v4];
+ tweight /= 4.0f;
+ }
+ else {
+ tweight /= 3.0f;
+ }
+
+ element_weight[i] *= tweight;
+ }
+ }
+ MEM_freeN(vweight);
+ }
+
+ /* Calculate total weight of all elements */
+ int totmapped = 0;
+ totweight = 0.0f;
+ for (i = 0; i < totelem; i++) {
+ if (element_weight[i] > 0.0f) {
+ totmapped++;
+ totweight += element_weight[i];
+ }
+ }
+
+ if (totmapped == 0) {
+ /* We are not allowed to distribute particles anywhere... */
+ if (mesh != final_mesh) {
+ BKE_id_free(NULL, mesh);
+ }
+ BLI_kdtree_3d_free(tree);
+ BLI_rng_free(rng);
+ MEM_freeN(element_weight);
+ MEM_freeN(particle_element);
+ MEM_freeN(jitter_offset);
+ return 0;
+ }
+
+ inv_totweight = 1.0f / totweight;
+
+ /* Calculate cumulative weights.
+ * We remove all null-weighted elements from element_sum, and create a new mapping
+ * 'activ'_elem_index -> orig_elem_index.
+ * This simplifies greatly the filtering of zero-weighted items - and can be much more efficient
+ * especially in random case (reducing a lot the size of binary-searched array)...
+ */
+ float *element_sum = MEM_mallocN(sizeof(*element_sum) * totmapped, __func__);
+ int *element_map = MEM_mallocN(sizeof(*element_map) * totmapped, __func__);
+ int i_mapped = 0;
+
+ for (i = 0; i < totelem && element_weight[i] == 0.0f; i++)
+ ;
+ element_sum[i_mapped] = element_weight[i] * inv_totweight;
+ element_map[i_mapped] = i;
+ i_mapped++;
+ for (i++; i < totelem; i++) {
+ if (element_weight[i] > 0.0f) {
+ element_sum[i_mapped] = element_sum[i_mapped - 1] + element_weight[i] * inv_totweight;
+ /* Skip elements which weight is so small that it does not affect the sum. */
+ if (element_sum[i_mapped] > element_sum[i_mapped - 1]) {
+ element_map[i_mapped] = i;
+ i_mapped++;
+ }
+ }
+ }
+ totmapped = i_mapped;
+
+ /* Finally assign elements to particles */
+ if (part->flag & PART_TRAND) {
+ for (p = 0; p < totpart; p++) {
+ /* In theory element_sum[totmapped - 1] should be 1.0,
+ * but due to float errors this is not necessarily always true, so scale pos accordingly. */
+ const float pos = BLI_rng_get_float(rng) * element_sum[totmapped - 1];
+ const int eidx = distribute_binary_search(element_sum, totmapped, pos);
+ particle_element[p] = element_map[eidx];
+ BLI_assert(pos <= element_sum[eidx]);
+ BLI_assert(eidx ? (pos > element_sum[eidx - 1]) : (pos >= 0.0f));
+ jitter_offset[particle_element[p]] = pos;
+ }
+ }
+ else {
+ double step, pos;
+
+ step = (totpart < 2) ? 0.5 : 1.0 / (double)totpart;
+ /* This is to address tricky issues with vertex-emitting when user tries (and expects) exact 1-1 vert/part
+ * distribution (see T47983 and its two example files). It allows us to consider pos as
+ * 'midpoint between v and v+1' (or 'p and p+1', depending whether we have more vertices than particles or not),
+ * and avoid stumbling over float impression in element_sum.
+ * Note: moved face and volume distribution to this as well (instead of starting at zero),
+ * for the same reasons, see T52682. */
+ pos = (totpart < totmapped) ? 0.5 / (double)totmapped :
+ step * 0.5; /* We choose the smaller step. */
+
+ for (i = 0, p = 0; p < totpart; p++, pos += step) {
+ for (; (i < totmapped - 1) && (pos > (double)element_sum[i]); i++)
+ ;
+
+ particle_element[p] = element_map[i];
+
+ jitter_offset[particle_element[p]] = pos;
+ }
+ }
+
+ MEM_freeN(element_sum);
+ MEM_freeN(element_map);
+
+ /* For hair, sort by origindex (allows optimization's in rendering), */
+ /* however with virtual parents the children need to be in random order. */
+ if (part->type == PART_HAIR && !(part->childtype == PART_CHILD_FACES && part->parents != 0.0f)) {
+ int *orig_index = NULL;
+
+ if (from == PART_FROM_VERT) {
+ if (mesh->totvert)
+ orig_index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX);
+ }
+ else {
+ if (mesh->totface)
+ orig_index = CustomData_get_layer(&mesh->fdata, CD_ORIGINDEX);
+ }
+
+ if (orig_index) {
+ BLI_qsort_r(
+ particle_element, totpart, sizeof(int), distribute_compare_orig_index, orig_index);
+ }
+ }
+
+ /* Create jittering if needed */
+ if (distr == PART_DISTR_JIT && ELEM(from, PART_FROM_FACE, PART_FROM_VOLUME)) {
+ jitlevel = part->userjit;
+
+ if (jitlevel == 0) {
+ jitlevel = totpart / totelem;
+ if (part->flag & PART_EDISTR)
+ jitlevel *= 2; /* looks better in general, not very scientific */
+ if (jitlevel < 3)
+ jitlevel = 3;
+ }
+
+ jit = MEM_callocN((2 + jitlevel * 2) * sizeof(float), "jit");
+
+ /* for small amounts of particles we use regular jitter since it looks
+ * a bit better, for larger amounts we switch to hammersley sequence
+ * because it is much faster */
+ if (jitlevel < 25)
+ init_mv_jit(jit, jitlevel, psys->seed, part->jitfac);
+ else
+ hammersley_create(jit, jitlevel + 1, psys->seed, part->jitfac);
+ BLI_array_randomize(
+ jit, 2 * sizeof(float), jitlevel, psys->seed); /* for custom jit or even distribution */
+ }
+
+ /* Setup things for threaded distribution */
+ ctx->tree = tree;
+ ctx->seams = seams;
+ ctx->totseam = totseam;
+ ctx->sim.psys = psys;
+ ctx->index = particle_element;
+ ctx->jit = jit;
+ ctx->jitlevel = jitlevel;
+ ctx->jitoff = jitter_offset;
+ ctx->weight = element_weight;
+ ctx->maxweight = maxweight;
+ ctx->cfrom = cfrom;
+ ctx->distr = distr;
+ ctx->mesh = mesh;
+ ctx->tpars = tpars;
+
+ if (children) {
+ alloc_child_particles(psys, totpart);
+ }
+
+ BLI_rng_free(rng);
+
+ return 1;
}
static void psys_task_init_distribute(ParticleTask *task, ParticleSimulationData *sim)
{
- /* init random number generator */
- int seed = 31415926 + sim->psys->seed;
+ /* init random number generator */
+ int seed = 31415926 + sim->psys->seed;
- task->rng = BLI_rng_new(seed);
+ task->rng = BLI_rng_new(seed);
}
static void distribute_particles_on_dm(ParticleSimulationData *sim, int from)
{
- TaskScheduler *task_scheduler;
- TaskPool *task_pool;
- ParticleThreadContext ctx;
- ParticleTask *tasks;
- Mesh *final_mesh = sim->psmd->mesh_final;
- int i, totpart, numtasks;
+ TaskScheduler *task_scheduler;
+ TaskPool *task_pool;
+ ParticleThreadContext ctx;
+ ParticleTask *tasks;
+ Mesh *final_mesh = sim->psmd->mesh_final;
+ int i, totpart, numtasks;
- /* create a task pool for distribution tasks */
- if (!psys_thread_context_init_distribute(&ctx, sim, from))
- return;
+ /* create a task pool for distribution tasks */
+ if (!psys_thread_context_init_distribute(&ctx, sim, from))
+ return;
- task_scheduler = BLI_task_scheduler_get();
- task_pool = BLI_task_pool_create(task_scheduler, &ctx);
+ task_scheduler = BLI_task_scheduler_get();
+ task_pool = BLI_task_pool_create(task_scheduler, &ctx);
- totpart = (from == PART_FROM_CHILD ? sim->psys->totchild : sim->psys->totpart);
- psys_tasks_create(&ctx, 0, totpart, &tasks, &numtasks);
- for (i = 0; i < numtasks; ++i) {
- ParticleTask *task = &tasks[i];
+ totpart = (from == PART_FROM_CHILD ? sim->psys->totchild : sim->psys->totpart);
+ psys_tasks_create(&ctx, 0, totpart, &tasks, &numtasks);
+ for (i = 0; i < numtasks; ++i) {
+ ParticleTask *task = &tasks[i];
- psys_task_init_distribute(task, sim);
- if (from == PART_FROM_CHILD)
- BLI_task_pool_push(task_pool, exec_distribute_child, task, false, TASK_PRIORITY_LOW);
- else
- BLI_task_pool_push(task_pool, exec_distribute_parent, task, false, TASK_PRIORITY_LOW);
- }
- BLI_task_pool_work_and_wait(task_pool);
+ psys_task_init_distribute(task, sim);
+ if (from == PART_FROM_CHILD)
+ BLI_task_pool_push(task_pool, exec_distribute_child, task, false, TASK_PRIORITY_LOW);
+ else
+ BLI_task_pool_push(task_pool, exec_distribute_parent, task, false, TASK_PRIORITY_LOW);
+ }
+ BLI_task_pool_work_and_wait(task_pool);
- BLI_task_pool_free(task_pool);
+ BLI_task_pool_free(task_pool);
- psys_calc_dmcache(sim->ob, final_mesh, sim->psmd->mesh_original, sim->psys);
+ psys_calc_dmcache(sim->ob, final_mesh, sim->psmd->mesh_original, sim->psys);
- if (ctx.mesh != final_mesh)
- BKE_id_free(NULL, ctx.mesh);
+ if (ctx.mesh != final_mesh)
+ BKE_id_free(NULL, ctx.mesh);
- psys_tasks_free(tasks, numtasks);
+ psys_tasks_free(tasks, numtasks);
- psys_thread_context_free(&ctx);
+ psys_thread_context_free(&ctx);
}
/* ready for future use, to emit particles without geometry */
static void distribute_particles_on_shape(ParticleSimulationData *sim, int UNUSED(from))
{
- distribute_invalid(sim, 0);
+ distribute_invalid(sim, 0);
- fprintf(stderr,"Shape emission not yet possible!\n");
+ fprintf(stderr, "Shape emission not yet possible!\n");
}
void distribute_particles(ParticleSimulationData *sim, int from)
{
- PARTICLE_PSMD;
- int distr_error=0;
-
- if (psmd) {
- if (psmd->mesh_final)
- distribute_particles_on_dm(sim, from);
- else
- distr_error=1;
- }
- else
- distribute_particles_on_shape(sim, from);
-
- if (distr_error) {
- distribute_invalid(sim, from);
-
- fprintf(stderr,"Particle distribution error!\n");
- }
+ PARTICLE_PSMD;
+ int distr_error = 0;
+
+ if (psmd) {
+ if (psmd->mesh_final)
+ distribute_particles_on_dm(sim, from);
+ else
+ distr_error = 1;
+ }
+ else
+ distribute_particles_on_shape(sim, from);
+
+ if (distr_error) {
+ distribute_invalid(sim, from);
+
+ fprintf(stderr, "Particle distribution error!\n");
+ }
}
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index 7ec50ead0bb..bf34e98c482 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -24,7 +24,6 @@
* \ingroup bke
*/
-
#include <stddef.h>
#include <stdlib.h>
@@ -88,1358 +87,1402 @@
/* fluid sim particle import */
#ifdef WITH_MOD_FLUID
-#include "DNA_object_fluidsim_types.h"
-#include "LBM_fluidsim.h"
-#include <zlib.h>
-#include <string.h>
+# include "DNA_object_fluidsim_types.h"
+# include "LBM_fluidsim.h"
+# include <zlib.h>
+# include <string.h>
-#endif // WITH_MOD_FLUID
+#endif // WITH_MOD_FLUID
static ThreadRWMutex psys_bvhtree_rwlock = BLI_RWLOCK_INITIALIZER;
/************************************************/
-/* Reacting to system events */
+/* Reacting to system events */
/************************************************/
static int particles_are_dynamic(ParticleSystem *psys)
{
- if (psys->pointcache->flag & PTCACHE_BAKED)
- return 0;
+ if (psys->pointcache->flag & PTCACHE_BAKED)
+ return 0;
- if (psys->part->type == PART_HAIR)
- return psys->flag & PSYS_HAIR_DYNAMICS;
- else
- return ELEM(psys->part->phystype, PART_PHYS_NEWTON, PART_PHYS_BOIDS, PART_PHYS_FLUID);
+ if (psys->part->type == PART_HAIR)
+ return psys->flag & PSYS_HAIR_DYNAMICS;
+ else
+ return ELEM(psys->part->phystype, PART_PHYS_NEWTON, PART_PHYS_BOIDS, PART_PHYS_FLUID);
}
float psys_get_current_display_percentage(ParticleSystem *psys, const bool use_render_params)
{
- ParticleSettings *part=psys->part;
+ ParticleSettings *part = psys->part;
- if ((use_render_params && !particles_are_dynamic(psys)) || /* non-dynamic particles can be rendered fully */
- (part->child_nbr && part->childtype) || /* display percentage applies to children */
- (psys->pointcache->flag & PTCACHE_BAKING)) /* baking is always done with full amount */
- {
- return 1.0f;
- }
+ if ((use_render_params &&
+ !particles_are_dynamic(psys)) || /* non-dynamic particles can be rendered fully */
+ (part->child_nbr && part->childtype) || /* display percentage applies to children */
+ (psys->pointcache->flag & PTCACHE_BAKING)) /* baking is always done with full amount */
+ {
+ return 1.0f;
+ }
- return psys->part->disp/100.0f;
+ return psys->part->disp / 100.0f;
}
static int tot_particles(ParticleSystem *psys, PTCacheID *pid)
{
- if (pid && psys->pointcache->flag & PTCACHE_EXTERNAL)
- return pid->cache->totpoint;
- else if (psys->part->distr == PART_DISTR_GRID && psys->part->from != PART_FROM_VERT)
- return psys->part->grid_res * psys->part->grid_res * psys->part->grid_res - psys->totunexist;
- else
- return psys->part->totpart - psys->totunexist;
+ if (pid && psys->pointcache->flag & PTCACHE_EXTERNAL)
+ return pid->cache->totpoint;
+ else if (psys->part->distr == PART_DISTR_GRID && psys->part->from != PART_FROM_VERT)
+ return psys->part->grid_res * psys->part->grid_res * psys->part->grid_res - psys->totunexist;
+ else
+ return psys->part->totpart - psys->totunexist;
}
void psys_reset(ParticleSystem *psys, int mode)
{
- PARTICLE_P;
-
- if (ELEM(mode, PSYS_RESET_ALL, PSYS_RESET_DEPSGRAPH)) {
- if (mode == PSYS_RESET_ALL || !(psys->flag & PSYS_EDITED)) {
- /* don't free if not absolutely necessary */
- if (psys->totpart != tot_particles(psys, NULL)) {
- psys_free_particles(psys);
- psys->totpart= 0;
- }
-
- psys->totkeyed= 0;
- psys->flag &= ~(PSYS_HAIR_DONE|PSYS_KEYED);
-
- if (psys->edit && psys->free_edit) {
- psys->free_edit(psys->edit);
- psys->edit = NULL;
- psys->free_edit = NULL;
- }
- }
- }
- else if (mode == PSYS_RESET_CACHE_MISS) {
- /* set all particles to be skipped */
- LOOP_PARTICLES {
- pa->flag |= PARS_NO_DISP;
- }
- }
-
- /* reset children */
- if (psys->child) {
- MEM_freeN(psys->child);
- psys->child= NULL;
- }
-
- psys->totchild= 0;
-
- /* reset path cache */
- psys_free_path_cache(psys, psys->edit);
-
- /* reset point cache */
- BKE_ptcache_invalidate(psys->pointcache);
-
- if (psys->fluid_springs) {
- MEM_freeN(psys->fluid_springs);
- psys->fluid_springs = NULL;
- }
-
- psys->tot_fluidsprings = psys->alloc_fluidsprings = 0;
+ PARTICLE_P;
+
+ if (ELEM(mode, PSYS_RESET_ALL, PSYS_RESET_DEPSGRAPH)) {
+ if (mode == PSYS_RESET_ALL || !(psys->flag & PSYS_EDITED)) {
+ /* don't free if not absolutely necessary */
+ if (psys->totpart != tot_particles(psys, NULL)) {
+ psys_free_particles(psys);
+ psys->totpart = 0;
+ }
+
+ psys->totkeyed = 0;
+ psys->flag &= ~(PSYS_HAIR_DONE | PSYS_KEYED);
+
+ if (psys->edit && psys->free_edit) {
+ psys->free_edit(psys->edit);
+ psys->edit = NULL;
+ psys->free_edit = NULL;
+ }
+ }
+ }
+ else if (mode == PSYS_RESET_CACHE_MISS) {
+ /* set all particles to be skipped */
+ LOOP_PARTICLES
+ {
+ pa->flag |= PARS_NO_DISP;
+ }
+ }
+
+ /* reset children */
+ if (psys->child) {
+ MEM_freeN(psys->child);
+ psys->child = NULL;
+ }
+
+ psys->totchild = 0;
+
+ /* reset path cache */
+ psys_free_path_cache(psys, psys->edit);
+
+ /* reset point cache */
+ BKE_ptcache_invalidate(psys->pointcache);
+
+ if (psys->fluid_springs) {
+ MEM_freeN(psys->fluid_springs);
+ psys->fluid_springs = NULL;
+ }
+
+ psys->tot_fluidsprings = psys->alloc_fluidsprings = 0;
}
void psys_unique_name(Object *object, ParticleSystem *psys, const char *defname)
{
- BLI_uniquename(&object->particlesystem, psys, defname, '.',
- offsetof(ParticleSystem, name), sizeof(psys->name));
+ BLI_uniquename(&object->particlesystem,
+ psys,
+ defname,
+ '.',
+ offsetof(ParticleSystem, name),
+ sizeof(psys->name));
}
static void realloc_particles(ParticleSimulationData *sim, int new_totpart)
{
- ParticleSystem *psys = sim->psys;
- ParticleSettings *part = psys->part;
- ParticleData *newpars = NULL;
- BoidParticle *newboids = NULL;
- PARTICLE_P;
- int totpart, totsaved = 0;
-
- if (new_totpart<0) {
- if ((part->distr == PART_DISTR_GRID) && (part->from != PART_FROM_VERT)) {
- totpart= part->grid_res;
- totpart*=totpart*totpart;
- }
- else
- totpart=part->totpart;
- }
- else
- totpart=new_totpart;
-
- if (totpart != psys->totpart) {
- if (psys->edit && psys->free_edit) {
- psys->free_edit(psys->edit);
- psys->edit = NULL;
- psys->free_edit = NULL;
- }
-
- if (totpart) {
- newpars= MEM_callocN(totpart*sizeof(ParticleData), "particles");
- if (newpars == NULL)
- return;
-
- if (psys->part->phystype == PART_PHYS_BOIDS) {
- newboids= MEM_callocN(totpart*sizeof(BoidParticle), "boid particles");
-
- if (newboids == NULL) {
- /* allocation error! */
- if (newpars)
- MEM_freeN(newpars);
- return;
- }
- }
- }
-
- if (psys->particles) {
- totsaved=MIN2(psys->totpart,totpart);
- /*save old pars*/
- if (totsaved) {
- memcpy(newpars,psys->particles,totsaved*sizeof(ParticleData));
-
- if (psys->particles->boid)
- memcpy(newboids, psys->particles->boid, totsaved*sizeof(BoidParticle));
- }
-
- if (psys->particles->keys)
- MEM_freeN(psys->particles->keys);
-
- if (psys->particles->boid)
- MEM_freeN(psys->particles->boid);
-
- for (p=0, pa=newpars; p<totsaved; p++, pa++) {
- if (pa->keys) {
- pa->keys= NULL;
- pa->totkey= 0;
- }
- }
-
- for (p=totsaved, pa=psys->particles+totsaved; p<psys->totpart; p++, pa++)
- if (pa->hair) MEM_freeN(pa->hair);
-
- MEM_freeN(psys->particles);
- psys_free_pdd(psys);
- }
-
- psys->particles=newpars;
- psys->totpart=totpart;
-
- if (newboids) {
- LOOP_PARTICLES {
- pa->boid = newboids++;
- }
- }
- }
-
- if (psys->child) {
- MEM_freeN(psys->child);
- psys->child=NULL;
- psys->totchild=0;
- }
+ ParticleSystem *psys = sim->psys;
+ ParticleSettings *part = psys->part;
+ ParticleData *newpars = NULL;
+ BoidParticle *newboids = NULL;
+ PARTICLE_P;
+ int totpart, totsaved = 0;
+
+ if (new_totpart < 0) {
+ if ((part->distr == PART_DISTR_GRID) && (part->from != PART_FROM_VERT)) {
+ totpart = part->grid_res;
+ totpart *= totpart * totpart;
+ }
+ else
+ totpart = part->totpart;
+ }
+ else
+ totpart = new_totpart;
+
+ if (totpart != psys->totpart) {
+ if (psys->edit && psys->free_edit) {
+ psys->free_edit(psys->edit);
+ psys->edit = NULL;
+ psys->free_edit = NULL;
+ }
+
+ if (totpart) {
+ newpars = MEM_callocN(totpart * sizeof(ParticleData), "particles");
+ if (newpars == NULL)
+ return;
+
+ if (psys->part->phystype == PART_PHYS_BOIDS) {
+ newboids = MEM_callocN(totpart * sizeof(BoidParticle), "boid particles");
+
+ if (newboids == NULL) {
+ /* allocation error! */
+ if (newpars)
+ MEM_freeN(newpars);
+ return;
+ }
+ }
+ }
+
+ if (psys->particles) {
+ totsaved = MIN2(psys->totpart, totpart);
+ /*save old pars*/
+ if (totsaved) {
+ memcpy(newpars, psys->particles, totsaved * sizeof(ParticleData));
+
+ if (psys->particles->boid)
+ memcpy(newboids, psys->particles->boid, totsaved * sizeof(BoidParticle));
+ }
+
+ if (psys->particles->keys)
+ MEM_freeN(psys->particles->keys);
+
+ if (psys->particles->boid)
+ MEM_freeN(psys->particles->boid);
+
+ for (p = 0, pa = newpars; p < totsaved; p++, pa++) {
+ if (pa->keys) {
+ pa->keys = NULL;
+ pa->totkey = 0;
+ }
+ }
+
+ for (p = totsaved, pa = psys->particles + totsaved; p < psys->totpart; p++, pa++)
+ if (pa->hair)
+ MEM_freeN(pa->hair);
+
+ MEM_freeN(psys->particles);
+ psys_free_pdd(psys);
+ }
+
+ psys->particles = newpars;
+ psys->totpart = totpart;
+
+ if (newboids) {
+ LOOP_PARTICLES
+ {
+ pa->boid = newboids++;
+ }
+ }
+ }
+
+ if (psys->child) {
+ MEM_freeN(psys->child);
+ psys->child = NULL;
+ psys->totchild = 0;
+ }
}
int psys_get_child_number(Scene *scene, ParticleSystem *psys, const bool use_render_params)
{
- int nbr;
+ int nbr;
- if (!psys->part->childtype)
- return 0;
+ if (!psys->part->childtype)
+ return 0;
- if (use_render_params)
- nbr= psys->part->ren_child_nbr;
- else
- nbr= psys->part->child_nbr;
+ if (use_render_params)
+ nbr = psys->part->ren_child_nbr;
+ else
+ nbr = psys->part->child_nbr;
- return get_render_child_particle_number(&scene->r, nbr, use_render_params);
+ return get_render_child_particle_number(&scene->r, nbr, use_render_params);
}
int psys_get_tot_child(Scene *scene, ParticleSystem *psys, const bool use_render_params)
{
- return psys->totpart*psys_get_child_number(scene, psys, use_render_params);
+ return psys->totpart * psys_get_child_number(scene, psys, use_render_params);
}
/************************************************/
-/* Distribution */
+/* Distribution */
/************************************************/
void psys_calc_dmcache(Object *ob, Mesh *mesh_final, Mesh *mesh_original, ParticleSystem *psys)
{
- /* use for building derived mesh mapping info:
- *
- * node: the allocated links - total derived mesh element count
- * nodearray: the array of nodes aligned with the base mesh's elements, so
- * each original elements can reference its derived elements
- */
- Mesh *me= (Mesh*)ob->data;
- bool use_modifier_stack= psys->part->use_modifier_stack;
- PARTICLE_P;
-
- /* CACHE LOCATIONS */
- if (!mesh_final->runtime.deformed_only) {
- /* Will use later to speed up subsurf/evaluated mesh. */
- LinkNode *node, *nodedmelem, **nodearray;
- int totdmelem, totelem, i, *origindex, *origindex_poly = NULL;
-
- if (psys->part->from == PART_FROM_VERT) {
- totdmelem = mesh_final->totvert;
-
- if (use_modifier_stack) {
- totelem= totdmelem;
- origindex= NULL;
- }
- else {
- totelem= me->totvert;
- origindex = CustomData_get_layer(&mesh_final->vdata, CD_ORIGINDEX);
- }
- }
- else { /* FROM_FACE/FROM_VOLUME */
- totdmelem= mesh_final->totface;
-
- if (use_modifier_stack) {
- totelem= totdmelem;
- origindex= NULL;
- origindex_poly= NULL;
- }
- else {
- totelem = mesh_original->totface;
- origindex = CustomData_get_layer(&mesh_final->fdata, CD_ORIGINDEX);
-
- /* for face lookups we need the poly origindex too */
- origindex_poly = CustomData_get_layer(&mesh_final->pdata, CD_ORIGINDEX);
- if (origindex_poly == NULL) {
- origindex= NULL;
- }
- }
- }
-
- nodedmelem= MEM_callocN(sizeof(LinkNode)*totdmelem, "psys node elems");
- nodearray= MEM_callocN(sizeof(LinkNode *)*totelem, "psys node array");
-
- for (i=0, node=nodedmelem; i<totdmelem; i++, node++) {
- int origindex_final;
- node->link = POINTER_FROM_INT(i);
-
- /* may be vertex or face origindex */
- if (use_modifier_stack) {
- origindex_final = i;
- }
- else {
- origindex_final = origindex ? origindex[i] : ORIGINDEX_NONE;
-
- /* if we have a poly source, do an index lookup */
- if (origindex_poly && origindex_final != ORIGINDEX_NONE) {
- origindex_final = origindex_poly[origindex_final];
- }
- }
-
- if (origindex_final != ORIGINDEX_NONE && origindex_final < totelem) {
- if (nodearray[origindex_final]) {
- /* prepend */
- node->next = nodearray[origindex_final];
- nodearray[origindex_final] = node;
- }
- else {
- nodearray[origindex_final] = node;
- }
- }
- }
-
- /* cache the verts/faces! */
- LOOP_PARTICLES {
- if (pa->num < 0) {
- pa->num_dmcache = DMCACHE_NOTFOUND;
- continue;
- }
-
- if (use_modifier_stack) {
- if (pa->num < totelem)
- pa->num_dmcache = DMCACHE_ISCHILD;
- else
- pa->num_dmcache = DMCACHE_NOTFOUND;
- }
- else {
- if (psys->part->from == PART_FROM_VERT) {
- if (pa->num < totelem && nodearray[pa->num])
- pa->num_dmcache= POINTER_AS_INT(nodearray[pa->num]->link);
- else
- pa->num_dmcache = DMCACHE_NOTFOUND;
- }
- else { /* FROM_FACE/FROM_VOLUME */
- pa->num_dmcache = psys_particle_dm_face_lookup(mesh_final, mesh_original, pa->num, pa->fuv, nodearray);
- }
- }
- }
-
- MEM_freeN(nodearray);
- MEM_freeN(nodedmelem);
- }
- else {
- /* TODO PARTICLE, make the following line unnecessary, each function
- * should know to use the num or num_dmcache, set the num_dmcache to
- * an invalid value, just in case */
-
- LOOP_PARTICLES {
- pa->num_dmcache = DMCACHE_NOTFOUND;
- }
- }
+ /* use for building derived mesh mapping info:
+ *
+ * node: the allocated links - total derived mesh element count
+ * nodearray: the array of nodes aligned with the base mesh's elements, so
+ * each original elements can reference its derived elements
+ */
+ Mesh *me = (Mesh *)ob->data;
+ bool use_modifier_stack = psys->part->use_modifier_stack;
+ PARTICLE_P;
+
+ /* CACHE LOCATIONS */
+ if (!mesh_final->runtime.deformed_only) {
+ /* Will use later to speed up subsurf/evaluated mesh. */
+ LinkNode *node, *nodedmelem, **nodearray;
+ int totdmelem, totelem, i, *origindex, *origindex_poly = NULL;
+
+ if (psys->part->from == PART_FROM_VERT) {
+ totdmelem = mesh_final->totvert;
+
+ if (use_modifier_stack) {
+ totelem = totdmelem;
+ origindex = NULL;
+ }
+ else {
+ totelem = me->totvert;
+ origindex = CustomData_get_layer(&mesh_final->vdata, CD_ORIGINDEX);
+ }
+ }
+ else { /* FROM_FACE/FROM_VOLUME */
+ totdmelem = mesh_final->totface;
+
+ if (use_modifier_stack) {
+ totelem = totdmelem;
+ origindex = NULL;
+ origindex_poly = NULL;
+ }
+ else {
+ totelem = mesh_original->totface;
+ origindex = CustomData_get_layer(&mesh_final->fdata, CD_ORIGINDEX);
+
+ /* for face lookups we need the poly origindex too */
+ origindex_poly = CustomData_get_layer(&mesh_final->pdata, CD_ORIGINDEX);
+ if (origindex_poly == NULL) {
+ origindex = NULL;
+ }
+ }
+ }
+
+ nodedmelem = MEM_callocN(sizeof(LinkNode) * totdmelem, "psys node elems");
+ nodearray = MEM_callocN(sizeof(LinkNode *) * totelem, "psys node array");
+
+ for (i = 0, node = nodedmelem; i < totdmelem; i++, node++) {
+ int origindex_final;
+ node->link = POINTER_FROM_INT(i);
+
+ /* may be vertex or face origindex */
+ if (use_modifier_stack) {
+ origindex_final = i;
+ }
+ else {
+ origindex_final = origindex ? origindex[i] : ORIGINDEX_NONE;
+
+ /* if we have a poly source, do an index lookup */
+ if (origindex_poly && origindex_final != ORIGINDEX_NONE) {
+ origindex_final = origindex_poly[origindex_final];
+ }
+ }
+
+ if (origindex_final != ORIGINDEX_NONE && origindex_final < totelem) {
+ if (nodearray[origindex_final]) {
+ /* prepend */
+ node->next = nodearray[origindex_final];
+ nodearray[origindex_final] = node;
+ }
+ else {
+ nodearray[origindex_final] = node;
+ }
+ }
+ }
+
+ /* cache the verts/faces! */
+ LOOP_PARTICLES
+ {
+ if (pa->num < 0) {
+ pa->num_dmcache = DMCACHE_NOTFOUND;
+ continue;
+ }
+
+ if (use_modifier_stack) {
+ if (pa->num < totelem)
+ pa->num_dmcache = DMCACHE_ISCHILD;
+ else
+ pa->num_dmcache = DMCACHE_NOTFOUND;
+ }
+ else {
+ if (psys->part->from == PART_FROM_VERT) {
+ if (pa->num < totelem && nodearray[pa->num])
+ pa->num_dmcache = POINTER_AS_INT(nodearray[pa->num]->link);
+ else
+ pa->num_dmcache = DMCACHE_NOTFOUND;
+ }
+ else { /* FROM_FACE/FROM_VOLUME */
+ pa->num_dmcache = psys_particle_dm_face_lookup(
+ mesh_final, mesh_original, pa->num, pa->fuv, nodearray);
+ }
+ }
+ }
+
+ MEM_freeN(nodearray);
+ MEM_freeN(nodedmelem);
+ }
+ else {
+ /* TODO PARTICLE, make the following line unnecessary, each function
+ * should know to use the num or num_dmcache, set the num_dmcache to
+ * an invalid value, just in case */
+
+ LOOP_PARTICLES
+ {
+ pa->num_dmcache = DMCACHE_NOTFOUND;
+ }
+ }
}
/* threaded child particle distribution and path caching */
void psys_thread_context_init(ParticleThreadContext *ctx, ParticleSimulationData *sim)
{
- memset(ctx, 0, sizeof(ParticleThreadContext));
- ctx->sim = *sim;
- ctx->mesh = ctx->sim.psmd->mesh_final;
- ctx->ma = give_current_material(sim->ob, sim->psys->part->omat);
+ memset(ctx, 0, sizeof(ParticleThreadContext));
+ ctx->sim = *sim;
+ ctx->mesh = ctx->sim.psmd->mesh_final;
+ ctx->ma = give_current_material(sim->ob, sim->psys->part->omat);
}
-#define MAX_PARTICLES_PER_TASK 256 /* XXX arbitrary - maybe use at least number of points instead for better balancing? */
+#define MAX_PARTICLES_PER_TASK \
+ 256 /* XXX arbitrary - maybe use at least number of points instead for better balancing? */
BLI_INLINE int ceil_ii(int a, int b)
{
- return (a + b - 1) / b;
+ return (a + b - 1) / b;
}
-void psys_tasks_create(ParticleThreadContext *ctx, int startpart, int endpart, ParticleTask **r_tasks, int *r_numtasks)
+void psys_tasks_create(ParticleThreadContext *ctx,
+ int startpart,
+ int endpart,
+ ParticleTask **r_tasks,
+ int *r_numtasks)
{
- ParticleTask *tasks;
- int numtasks = ceil_ii((endpart - startpart), MAX_PARTICLES_PER_TASK);
- float particles_per_task = (float)(endpart - startpart) / (float)numtasks, p, pnext;
- int i;
-
- tasks = MEM_callocN(sizeof(ParticleTask) * numtasks, "ParticleThread");
- *r_numtasks = numtasks;
- *r_tasks = tasks;
-
- p = (float)startpart;
- for (i = 0; i < numtasks; i++, p = pnext) {
- pnext = p + particles_per_task;
-
- tasks[i].ctx = ctx;
- tasks[i].begin = (int)p;
- tasks[i].end = min_ii((int)pnext, endpart);
- }
+ ParticleTask *tasks;
+ int numtasks = ceil_ii((endpart - startpart), MAX_PARTICLES_PER_TASK);
+ float particles_per_task = (float)(endpart - startpart) / (float)numtasks, p, pnext;
+ int i;
+
+ tasks = MEM_callocN(sizeof(ParticleTask) * numtasks, "ParticleThread");
+ *r_numtasks = numtasks;
+ *r_tasks = tasks;
+
+ p = (float)startpart;
+ for (i = 0; i < numtasks; i++, p = pnext) {
+ pnext = p + particles_per_task;
+
+ tasks[i].ctx = ctx;
+ tasks[i].begin = (int)p;
+ tasks[i].end = min_ii((int)pnext, endpart);
+ }
}
void psys_tasks_free(ParticleTask *tasks, int numtasks)
{
- int i;
+ int i;
- /* threads */
- for (i = 0; i < numtasks; ++i) {
- if (tasks[i].rng)
- BLI_rng_free(tasks[i].rng);
- if (tasks[i].rng_path)
- BLI_rng_free(tasks[i].rng_path);
- }
+ /* threads */
+ for (i = 0; i < numtasks; ++i) {
+ if (tasks[i].rng)
+ BLI_rng_free(tasks[i].rng);
+ if (tasks[i].rng_path)
+ BLI_rng_free(tasks[i].rng_path);
+ }
- MEM_freeN(tasks);
+ MEM_freeN(tasks);
}
void psys_thread_context_free(ParticleThreadContext *ctx)
{
- /* path caching */
- if (ctx->vg_length)
- MEM_freeN(ctx->vg_length);
- if (ctx->vg_clump)
- MEM_freeN(ctx->vg_clump);
- if (ctx->vg_kink)
- MEM_freeN(ctx->vg_kink);
- if (ctx->vg_rough1)
- MEM_freeN(ctx->vg_rough1);
- if (ctx->vg_rough2)
- MEM_freeN(ctx->vg_rough2);
- if (ctx->vg_roughe)
- MEM_freeN(ctx->vg_roughe);
- if (ctx->vg_twist)
- MEM_freeN(ctx->vg_twist);
-
- if (ctx->sim.psys->lattice_deform_data) {
- end_latt_deform(ctx->sim.psys->lattice_deform_data);
- ctx->sim.psys->lattice_deform_data = NULL;
- }
-
- /* distribution */
- if (ctx->jit) MEM_freeN(ctx->jit);
- if (ctx->jitoff) MEM_freeN(ctx->jitoff);
- if (ctx->weight) MEM_freeN(ctx->weight);
- if (ctx->index) MEM_freeN(ctx->index);
- if (ctx->seams) MEM_freeN(ctx->seams);
- //if (ctx->vertpart) MEM_freeN(ctx->vertpart);
- BLI_kdtree_3d_free(ctx->tree);
-
- if (ctx->clumpcurve != NULL) {
- curvemapping_free(ctx->clumpcurve);
- }
- if (ctx->roughcurve != NULL) {
- curvemapping_free(ctx->roughcurve);
- }
- if (ctx->twistcurve != NULL) {
- curvemapping_free(ctx->twistcurve);
- }
+ /* path caching */
+ if (ctx->vg_length)
+ MEM_freeN(ctx->vg_length);
+ if (ctx->vg_clump)
+ MEM_freeN(ctx->vg_clump);
+ if (ctx->vg_kink)
+ MEM_freeN(ctx->vg_kink);
+ if (ctx->vg_rough1)
+ MEM_freeN(ctx->vg_rough1);
+ if (ctx->vg_rough2)
+ MEM_freeN(ctx->vg_rough2);
+ if (ctx->vg_roughe)
+ MEM_freeN(ctx->vg_roughe);
+ if (ctx->vg_twist)
+ MEM_freeN(ctx->vg_twist);
+
+ if (ctx->sim.psys->lattice_deform_data) {
+ end_latt_deform(ctx->sim.psys->lattice_deform_data);
+ ctx->sim.psys->lattice_deform_data = NULL;
+ }
+
+ /* distribution */
+ if (ctx->jit)
+ MEM_freeN(ctx->jit);
+ if (ctx->jitoff)
+ MEM_freeN(ctx->jitoff);
+ if (ctx->weight)
+ MEM_freeN(ctx->weight);
+ if (ctx->index)
+ MEM_freeN(ctx->index);
+ if (ctx->seams)
+ MEM_freeN(ctx->seams);
+ //if (ctx->vertpart) MEM_freeN(ctx->vertpart);
+ BLI_kdtree_3d_free(ctx->tree);
+
+ if (ctx->clumpcurve != NULL) {
+ curvemapping_free(ctx->clumpcurve);
+ }
+ if (ctx->roughcurve != NULL) {
+ curvemapping_free(ctx->roughcurve);
+ }
+ if (ctx->twistcurve != NULL) {
+ curvemapping_free(ctx->twistcurve);
+ }
}
static void initialize_particle_texture(ParticleSimulationData *sim, ParticleData *pa, int p)
{
- ParticleSystem *psys = sim->psys;
- ParticleSettings *part = psys->part;
- ParticleTexture ptex;
-
- psys_get_texture(sim, pa, &ptex, PAMAP_INIT, 0.f);
-
- switch (part->type) {
- case PART_EMITTER:
- if (ptex.exist < psys_frand(psys, p + 125)) {
- pa->flag |= PARS_UNEXIST;
- }
- pa->time = part->sta + (part->end - part->sta)*ptex.time;
- break;
- case PART_HAIR:
- if (ptex.exist < psys_frand(psys, p + 125)) {
- pa->flag |= PARS_UNEXIST;
- }
- pa->time = 0.f;
- break;
- case PART_FLUID:
- break;
- }
+ ParticleSystem *psys = sim->psys;
+ ParticleSettings *part = psys->part;
+ ParticleTexture ptex;
+
+ psys_get_texture(sim, pa, &ptex, PAMAP_INIT, 0.f);
+
+ switch (part->type) {
+ case PART_EMITTER:
+ if (ptex.exist < psys_frand(psys, p + 125)) {
+ pa->flag |= PARS_UNEXIST;
+ }
+ pa->time = part->sta + (part->end - part->sta) * ptex.time;
+ break;
+ case PART_HAIR:
+ if (ptex.exist < psys_frand(psys, p + 125)) {
+ pa->flag |= PARS_UNEXIST;
+ }
+ pa->time = 0.f;
+ break;
+ case PART_FLUID:
+ break;
+ }
}
/* set particle parameters that don't change during particle's life */
void initialize_particle(ParticleSimulationData *sim, ParticleData *pa)
{
- ParticleSettings *part = sim->psys->part;
- float birth_time = (float)(pa - sim->psys->particles) / (float)sim->psys->totpart;
+ ParticleSettings *part = sim->psys->part;
+ float birth_time = (float)(pa - sim->psys->particles) / (float)sim->psys->totpart;
- pa->flag &= ~PARS_UNEXIST;
- pa->time = part->sta + (part->end - part->sta) * birth_time;
+ pa->flag &= ~PARS_UNEXIST;
+ pa->time = part->sta + (part->end - part->sta) * birth_time;
- pa->hair_index = 0;
- /* we can't reset to -1 anymore since we've figured out correct index in distribute_particles */
- /* usage other than straight after distribute has to handle this index by itself - jahka*/
- //pa->num_dmcache = DMCACHE_NOTFOUND; /* assume we don't have a derived mesh face */
+ pa->hair_index = 0;
+ /* we can't reset to -1 anymore since we've figured out correct index in distribute_particles */
+ /* usage other than straight after distribute has to handle this index by itself - jahka*/
+ //pa->num_dmcache = DMCACHE_NOTFOUND; /* assume we don't have a derived mesh face */
}
static void initialize_all_particles(ParticleSimulationData *sim)
{
- ParticleSystem *psys = sim->psys;
- ParticleSettings *part = psys->part;
- /* Grid distributionsets UNEXIST flag, need to take care of
- * it here because later this flag is being reset.
- *
- * We can't do it for any distribution, because it'll then
- * conflict with texture influence, which does not free
- * unexisting particles and only sets flag.
- *
- * It's not so bad, because only grid distribution sets
- * UNEXIST flag.
- */
- const bool emit_from_volume_grid = (part->distr == PART_DISTR_GRID) &&
- (!ELEM(part->from, PART_FROM_VERT, PART_FROM_CHILD));
- PARTICLE_P;
- LOOP_PARTICLES {
- if (!(emit_from_volume_grid && (pa->flag & PARS_UNEXIST) != 0)) {
- initialize_particle(sim, pa);
- }
- }
+ ParticleSystem *psys = sim->psys;
+ ParticleSettings *part = psys->part;
+ /* Grid distributionsets UNEXIST flag, need to take care of
+ * it here because later this flag is being reset.
+ *
+ * We can't do it for any distribution, because it'll then
+ * conflict with texture influence, which does not free
+ * unexisting particles and only sets flag.
+ *
+ * It's not so bad, because only grid distribution sets
+ * UNEXIST flag.
+ */
+ const bool emit_from_volume_grid = (part->distr == PART_DISTR_GRID) &&
+ (!ELEM(part->from, PART_FROM_VERT, PART_FROM_CHILD));
+ PARTICLE_P;
+ LOOP_PARTICLES
+ {
+ if (!(emit_from_volume_grid && (pa->flag & PARS_UNEXIST) != 0)) {
+ initialize_particle(sim, pa);
+ }
+ }
}
static void free_unexisting_particles(ParticleSimulationData *sim)
{
- ParticleSystem *psys = sim->psys;
- PARTICLE_P;
-
- psys->totunexist = 0;
-
- LOOP_PARTICLES {
- if (pa->flag & PARS_UNEXIST) {
- psys->totunexist++;
- }
- }
-
- if (psys->totpart && psys->totunexist == psys->totpart) {
- if (psys->particles->boid)
- MEM_freeN(psys->particles->boid);
-
- MEM_freeN(psys->particles);
- psys->particles = NULL;
- psys->totpart = psys->totunexist = 0;
- }
-
- if (psys->totunexist) {
- int newtotpart = psys->totpart - psys->totunexist;
- ParticleData *npa, *newpars;
-
- npa = newpars = MEM_callocN(newtotpart * sizeof(ParticleData), "particles");
-
- for (p=0, pa=psys->particles; p<newtotpart; p++, pa++, npa++) {
- while (pa->flag & PARS_UNEXIST)
- pa++;
-
- memcpy(npa, pa, sizeof(ParticleData));
- }
-
- if (psys->particles->boid)
- MEM_freeN(psys->particles->boid);
- MEM_freeN(psys->particles);
- psys->particles = newpars;
- psys->totpart -= psys->totunexist;
-
- if (psys->particles->boid) {
- BoidParticle *newboids = MEM_callocN(psys->totpart * sizeof(BoidParticle), "boid particles");
-
- LOOP_PARTICLES {
- pa->boid = newboids++;
- }
-
- }
- }
+ ParticleSystem *psys = sim->psys;
+ PARTICLE_P;
+
+ psys->totunexist = 0;
+
+ LOOP_PARTICLES
+ {
+ if (pa->flag & PARS_UNEXIST) {
+ psys->totunexist++;
+ }
+ }
+
+ if (psys->totpart && psys->totunexist == psys->totpart) {
+ if (psys->particles->boid)
+ MEM_freeN(psys->particles->boid);
+
+ MEM_freeN(psys->particles);
+ psys->particles = NULL;
+ psys->totpart = psys->totunexist = 0;
+ }
+
+ if (psys->totunexist) {
+ int newtotpart = psys->totpart - psys->totunexist;
+ ParticleData *npa, *newpars;
+
+ npa = newpars = MEM_callocN(newtotpart * sizeof(ParticleData), "particles");
+
+ for (p = 0, pa = psys->particles; p < newtotpart; p++, pa++, npa++) {
+ while (pa->flag & PARS_UNEXIST)
+ pa++;
+
+ memcpy(npa, pa, sizeof(ParticleData));
+ }
+
+ if (psys->particles->boid)
+ MEM_freeN(psys->particles->boid);
+ MEM_freeN(psys->particles);
+ psys->particles = newpars;
+ psys->totpart -= psys->totunexist;
+
+ if (psys->particles->boid) {
+ BoidParticle *newboids = MEM_callocN(psys->totpart * sizeof(BoidParticle), "boid particles");
+
+ LOOP_PARTICLES
+ {
+ pa->boid = newboids++;
+ }
+ }
+ }
}
static void get_angular_velocity_vector(short avemode, ParticleKey *state, float vec[3])
{
- switch (avemode) {
- case PART_AVE_VELOCITY:
- copy_v3_v3(vec, state->vel);
- break;
- case PART_AVE_HORIZONTAL:
- {
- float zvec[3];
- zvec[0] = zvec[1] = 0;
- zvec[2] = 1.f;
- cross_v3_v3v3(vec, state->vel, zvec);
- break;
- }
- case PART_AVE_VERTICAL:
- {
- float zvec[3], temp[3];
- zvec[0] = zvec[1] = 0;
- zvec[2] = 1.f;
- cross_v3_v3v3(temp, state->vel, zvec);
- cross_v3_v3v3(vec, temp, state->vel);
- break;
- }
- case PART_AVE_GLOBAL_X:
- vec[0] = 1.f;
- vec[1] = vec[2] = 0;
- break;
- case PART_AVE_GLOBAL_Y:
- vec[1] = 1.f;
- vec[0] = vec[2] = 0;
- break;
- case PART_AVE_GLOBAL_Z:
- vec[2] = 1.f;
- vec[0] = vec[1] = 0;
- break;
- }
+ switch (avemode) {
+ case PART_AVE_VELOCITY:
+ copy_v3_v3(vec, state->vel);
+ break;
+ case PART_AVE_HORIZONTAL: {
+ float zvec[3];
+ zvec[0] = zvec[1] = 0;
+ zvec[2] = 1.f;
+ cross_v3_v3v3(vec, state->vel, zvec);
+ break;
+ }
+ case PART_AVE_VERTICAL: {
+ float zvec[3], temp[3];
+ zvec[0] = zvec[1] = 0;
+ zvec[2] = 1.f;
+ cross_v3_v3v3(temp, state->vel, zvec);
+ cross_v3_v3v3(vec, temp, state->vel);
+ break;
+ }
+ case PART_AVE_GLOBAL_X:
+ vec[0] = 1.f;
+ vec[1] = vec[2] = 0;
+ break;
+ case PART_AVE_GLOBAL_Y:
+ vec[1] = 1.f;
+ vec[0] = vec[2] = 0;
+ break;
+ case PART_AVE_GLOBAL_Z:
+ vec[2] = 1.f;
+ vec[0] = vec[1] = 0;
+ break;
+ }
}
-void psys_get_birth_coords(ParticleSimulationData *sim, ParticleData *pa, ParticleKey *state, float dtime, float cfra)
+void psys_get_birth_coords(
+ ParticleSimulationData *sim, ParticleData *pa, ParticleKey *state, float dtime, float cfra)
{
- Object *ob = sim->ob;
- ParticleSystem *psys = sim->psys;
- ParticleSettings *part = psys->part;
- ParticleTexture ptex;
- float fac, phasefac, nor[3] = {0,0,0},loc[3],vel[3] = {0.0,0.0,0.0},rot[4],q2[4];
- float r_vel[3],r_ave[3],r_rot[4],vec[3],p_vel[3] = {0.0,0.0,0.0};
- float x_vec[3] = {1.0,0.0,0.0}, utan[3] = {0.0,1.0,0.0}, vtan[3] = {0.0,0.0,1.0}, rot_vec[3] = {0.0,0.0,0.0};
- float q_phase[4];
-
- const bool use_boids = ((part->phystype == PART_PHYS_BOIDS) &&
- (pa->boid != NULL));
- const bool use_tangents = ((use_boids == false) &&
- ((part->tanfac != 0.0f) || (part->rotmode == PART_ROT_NOR_TAN)));
-
- int p = pa - psys->particles;
-
- /* get birth location from object */
- if (use_tangents)
- psys_particle_on_emitter(sim->psmd, part->from,pa->num, pa->num_dmcache, pa->fuv,pa->foffset,loc,nor,utan,vtan,0);
- else
- psys_particle_on_emitter(sim->psmd, part->from,pa->num, pa->num_dmcache, pa->fuv,pa->foffset,loc,nor,0,0,0);
-
- /* get possible textural influence */
- psys_get_texture(sim, pa, &ptex, PAMAP_IVEL, cfra);
-
- /* particles live in global space so */
- /* let's convert: */
- /* -location */
- mul_m4_v3(ob->obmat, loc);
-
- /* -normal */
- mul_mat3_m4_v3(ob->obmat, nor);
- normalize_v3(nor);
-
- /* -tangent */
- if (use_tangents) {
- //float phase=vg_rot?2.0f*(psys_particle_value_from_verts(sim->psmd->dm,part->from,pa,vg_rot)-0.5f):0.0f;
- float phase=0.0f;
- mul_v3_fl(vtan,-cosf((float)M_PI*(part->tanphase+phase)));
- fac= -sinf((float)M_PI*(part->tanphase+phase));
- madd_v3_v3fl(vtan, utan, fac);
-
- mul_mat3_m4_v3(ob->obmat,vtan);
-
- copy_v3_v3(utan, nor);
- mul_v3_fl(utan,dot_v3v3(vtan,nor));
- sub_v3_v3(vtan, utan);
-
- normalize_v3(vtan);
- }
-
-
- /* -velocity (boids need this even if there's no random velocity) */
- if (part->randfac != 0.0f || (part->phystype==PART_PHYS_BOIDS && pa->boid)) {
- r_vel[0] = 2.0f * (psys_frand(psys, p + 10) - 0.5f);
- r_vel[1] = 2.0f * (psys_frand(psys, p + 11) - 0.5f);
- r_vel[2] = 2.0f * (psys_frand(psys, p + 12) - 0.5f);
-
- mul_mat3_m4_v3(ob->obmat, r_vel);
- normalize_v3(r_vel);
- }
-
- /* -angular velocity */
- if (part->avemode==PART_AVE_RAND) {
- r_ave[0] = 2.0f * (psys_frand(psys, p + 13) - 0.5f);
- r_ave[1] = 2.0f * (psys_frand(psys, p + 14) - 0.5f);
- r_ave[2] = 2.0f * (psys_frand(psys, p + 15) - 0.5f);
-
- mul_mat3_m4_v3(ob->obmat,r_ave);
- normalize_v3(r_ave);
- }
-
- /* -rotation */
- if (part->randrotfac != 0.0f) {
- r_rot[0] = 2.0f * (psys_frand(psys, p + 16) - 0.5f);
- r_rot[1] = 2.0f * (psys_frand(psys, p + 17) - 0.5f);
- r_rot[2] = 2.0f * (psys_frand(psys, p + 18) - 0.5f);
- r_rot[3] = 2.0f * (psys_frand(psys, p + 19) - 0.5f);
- normalize_qt(r_rot);
-
- mat4_to_quat(rot,ob->obmat);
- mul_qt_qtqt(r_rot,r_rot,rot);
- }
-
- if (use_boids) {
- float dvec[3], q[4], mat[3][3];
-
- copy_v3_v3(state->co,loc);
-
- /* boids don't get any initial velocity */
- zero_v3(state->vel);
-
- /* boids store direction in ave */
- if (fabsf(nor[2])==1.0f) {
- sub_v3_v3v3(state->ave, loc, ob->obmat[3]);
- normalize_v3(state->ave);
- }
- else {
- copy_v3_v3(state->ave, nor);
- }
-
- /* calculate rotation matrix */
- project_v3_v3v3(dvec, r_vel, state->ave);
- sub_v3_v3v3(mat[0], state->ave, dvec);
- normalize_v3(mat[0]);
- negate_v3_v3(mat[2], r_vel);
- normalize_v3(mat[2]);
- cross_v3_v3v3(mat[1], mat[2], mat[0]);
-
- /* apply rotation */
- mat3_to_quat_is_ok( q,mat);
- copy_qt_qt(state->rot, q);
- }
- else {
- /* conversion done so now we apply new: */
- /* -velocity from: */
-
- /* *reactions */
- if (dtime > 0.f) {
- sub_v3_v3v3(vel, pa->state.vel, pa->prev_state.vel);
- }
-
- /* *emitter velocity */
- if (dtime != 0.f && part->obfac != 0.f) {
- sub_v3_v3v3(vel, loc, state->co);
- mul_v3_fl(vel, part->obfac/dtime);
- }
-
- /* *emitter normal */
- if (part->normfac != 0.f)
- madd_v3_v3fl(vel, nor, part->normfac);
-
- /* *emitter tangent */
- if (sim->psmd && part->tanfac != 0.f)
- madd_v3_v3fl(vel, vtan, part->tanfac);
-
- /* *emitter object orientation */
- if (part->ob_vel[0] != 0.f) {
- normalize_v3_v3(vec, ob->obmat[0]);
- madd_v3_v3fl(vel, vec, part->ob_vel[0]);
- }
- if (part->ob_vel[1] != 0.f) {
- normalize_v3_v3(vec, ob->obmat[1]);
- madd_v3_v3fl(vel, vec, part->ob_vel[1]);
- }
- if (part->ob_vel[2] != 0.f) {
- normalize_v3_v3(vec, ob->obmat[2]);
- madd_v3_v3fl(vel, vec, part->ob_vel[2]);
- }
-
- /* *texture */
- /* TODO */
-
- /* *random */
- if (part->randfac != 0.f)
- madd_v3_v3fl(vel, r_vel, part->randfac);
-
- /* *particle */
- if (part->partfac != 0.f)
- madd_v3_v3fl(vel, p_vel, part->partfac);
-
- mul_v3_v3fl(state->vel, vel, ptex.ivel);
-
- /* -location from emitter */
- copy_v3_v3(state->co,loc);
-
- /* -rotation */
- unit_qt(state->rot);
-
- if (part->rotmode) {
- bool use_global_space;
-
- /* create vector into which rotation is aligned */
- switch (part->rotmode) {
- case PART_ROT_NOR:
- case PART_ROT_NOR_TAN:
- copy_v3_v3(rot_vec, nor);
- use_global_space = false;
- break;
- case PART_ROT_VEL:
- copy_v3_v3(rot_vec, vel);
- use_global_space = true;
- break;
- case PART_ROT_GLOB_X:
- case PART_ROT_GLOB_Y:
- case PART_ROT_GLOB_Z:
- rot_vec[part->rotmode - PART_ROT_GLOB_X] = 1.0f;
- use_global_space = true;
- break;
- case PART_ROT_OB_X:
- case PART_ROT_OB_Y:
- case PART_ROT_OB_Z:
- copy_v3_v3(rot_vec, ob->obmat[part->rotmode - PART_ROT_OB_X]);
- use_global_space = false;
- break;
- default:
- use_global_space = true;
- break;
- }
-
- /* create rotation quat */
-
-
- if (use_global_space) {
- negate_v3(rot_vec);
- vec_to_quat(q2, rot_vec, OB_POSX, OB_POSZ);
-
- /* randomize rotation quat */
- if (part->randrotfac != 0.0f) {
- interp_qt_qtqt(rot, q2, r_rot, part->randrotfac);
- }
- else {
- copy_qt_qt(rot, q2);
- }
- }
- else {
- /* calculate rotation in local-space */
- float q_obmat[4];
- float q_imat[4];
-
- mat4_to_quat(q_obmat, ob->obmat);
- invert_qt_qt_normalized(q_imat, q_obmat);
-
-
- if (part->rotmode != PART_ROT_NOR_TAN) {
- float rot_vec_local[3];
-
- /* rot_vec */
- negate_v3(rot_vec);
- copy_v3_v3(rot_vec_local, rot_vec);
- mul_qt_v3(q_imat, rot_vec_local);
- normalize_v3(rot_vec_local);
-
- vec_to_quat(q2, rot_vec_local, OB_POSX, OB_POSZ);
- }
- else {
- /* (part->rotmode == PART_ROT_NOR_TAN) */
- float tmat[3][3];
-
- /* note: utan_local is not taken from 'utan', we calculate from rot_vec/vtan */
- /* note: it looks like rotation phase may be applied twice (once with vtan, again below)
- * however this isn't the case - campbell */
- float *rot_vec_local = tmat[0];
- float *vtan_local = tmat[1];
- float *utan_local = tmat[2];
-
- /* use tangents */
- BLI_assert(use_tangents == true);
-
- /* rot_vec */
- copy_v3_v3(rot_vec_local, rot_vec);
- mul_qt_v3(q_imat, rot_vec_local);
-
- /* vtan_local */
- copy_v3_v3(vtan_local, vtan); /* flips, cant use */
- mul_qt_v3(q_imat, vtan_local);
-
- /* ensure orthogonal matrix (rot_vec aligned) */
- cross_v3_v3v3(utan_local, vtan_local, rot_vec_local);
- cross_v3_v3v3(vtan_local, utan_local, rot_vec_local);
-
- /* note: no need to normalize */
- mat3_to_quat(q2, tmat);
- }
-
- /* randomize rotation quat */
- if (part->randrotfac != 0.0f) {
- mul_qt_qtqt(r_rot, r_rot, q_imat);
- interp_qt_qtqt(rot, q2, r_rot, part->randrotfac);
- }
- else {
- copy_qt_qt(rot, q2);
- }
-
- mul_qt_qtqt(rot, q_obmat, rot);
- }
-
- /* rotation phase */
- phasefac = part->phasefac;
- if (part->randphasefac != 0.0f)
- phasefac += part->randphasefac * psys_frand(psys, p + 20);
- axis_angle_to_quat( q_phase,x_vec, phasefac*(float)M_PI);
-
- /* combine base rotation & phase */
- mul_qt_qtqt(state->rot, rot, q_phase);
- }
-
- /* -angular velocity */
-
- zero_v3(state->ave);
-
- if (part->avemode) {
- if (part->avemode == PART_AVE_RAND)
- copy_v3_v3(state->ave, r_ave);
- else
- get_angular_velocity_vector(part->avemode, state, state->ave);
-
- normalize_v3(state->ave);
- mul_v3_fl(state->ave, part->avefac);
- }
- }
+ Object *ob = sim->ob;
+ ParticleSystem *psys = sim->psys;
+ ParticleSettings *part = psys->part;
+ ParticleTexture ptex;
+ float fac, phasefac, nor[3] = {0, 0, 0}, loc[3], vel[3] = {0.0, 0.0, 0.0}, rot[4], q2[4];
+ float r_vel[3], r_ave[3], r_rot[4], vec[3], p_vel[3] = {0.0, 0.0, 0.0};
+ float x_vec[3] = {1.0, 0.0, 0.0}, utan[3] = {0.0, 1.0, 0.0}, vtan[3] = {0.0, 0.0, 1.0},
+ rot_vec[3] = {0.0, 0.0, 0.0};
+ float q_phase[4];
+
+ const bool use_boids = ((part->phystype == PART_PHYS_BOIDS) && (pa->boid != NULL));
+ const bool use_tangents = ((use_boids == false) &&
+ ((part->tanfac != 0.0f) || (part->rotmode == PART_ROT_NOR_TAN)));
+
+ int p = pa - psys->particles;
+
+ /* get birth location from object */
+ if (use_tangents)
+ psys_particle_on_emitter(sim->psmd,
+ part->from,
+ pa->num,
+ pa->num_dmcache,
+ pa->fuv,
+ pa->foffset,
+ loc,
+ nor,
+ utan,
+ vtan,
+ 0);
+ else
+ psys_particle_on_emitter(
+ sim->psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, loc, nor, 0, 0, 0);
+
+ /* get possible textural influence */
+ psys_get_texture(sim, pa, &ptex, PAMAP_IVEL, cfra);
+
+ /* particles live in global space so */
+ /* let's convert: */
+ /* -location */
+ mul_m4_v3(ob->obmat, loc);
+
+ /* -normal */
+ mul_mat3_m4_v3(ob->obmat, nor);
+ normalize_v3(nor);
+
+ /* -tangent */
+ if (use_tangents) {
+ //float phase=vg_rot?2.0f*(psys_particle_value_from_verts(sim->psmd->dm,part->from,pa,vg_rot)-0.5f):0.0f;
+ float phase = 0.0f;
+ mul_v3_fl(vtan, -cosf((float)M_PI * (part->tanphase + phase)));
+ fac = -sinf((float)M_PI * (part->tanphase + phase));
+ madd_v3_v3fl(vtan, utan, fac);
+
+ mul_mat3_m4_v3(ob->obmat, vtan);
+
+ copy_v3_v3(utan, nor);
+ mul_v3_fl(utan, dot_v3v3(vtan, nor));
+ sub_v3_v3(vtan, utan);
+
+ normalize_v3(vtan);
+ }
+
+ /* -velocity (boids need this even if there's no random velocity) */
+ if (part->randfac != 0.0f || (part->phystype == PART_PHYS_BOIDS && pa->boid)) {
+ r_vel[0] = 2.0f * (psys_frand(psys, p + 10) - 0.5f);
+ r_vel[1] = 2.0f * (psys_frand(psys, p + 11) - 0.5f);
+ r_vel[2] = 2.0f * (psys_frand(psys, p + 12) - 0.5f);
+
+ mul_mat3_m4_v3(ob->obmat, r_vel);
+ normalize_v3(r_vel);
+ }
+
+ /* -angular velocity */
+ if (part->avemode == PART_AVE_RAND) {
+ r_ave[0] = 2.0f * (psys_frand(psys, p + 13) - 0.5f);
+ r_ave[1] = 2.0f * (psys_frand(psys, p + 14) - 0.5f);
+ r_ave[2] = 2.0f * (psys_frand(psys, p + 15) - 0.5f);
+
+ mul_mat3_m4_v3(ob->obmat, r_ave);
+ normalize_v3(r_ave);
+ }
+
+ /* -rotation */
+ if (part->randrotfac != 0.0f) {
+ r_rot[0] = 2.0f * (psys_frand(psys, p + 16) - 0.5f);
+ r_rot[1] = 2.0f * (psys_frand(psys, p + 17) - 0.5f);
+ r_rot[2] = 2.0f * (psys_frand(psys, p + 18) - 0.5f);
+ r_rot[3] = 2.0f * (psys_frand(psys, p + 19) - 0.5f);
+ normalize_qt(r_rot);
+
+ mat4_to_quat(rot, ob->obmat);
+ mul_qt_qtqt(r_rot, r_rot, rot);
+ }
+
+ if (use_boids) {
+ float dvec[3], q[4], mat[3][3];
+
+ copy_v3_v3(state->co, loc);
+
+ /* boids don't get any initial velocity */
+ zero_v3(state->vel);
+
+ /* boids store direction in ave */
+ if (fabsf(nor[2]) == 1.0f) {
+ sub_v3_v3v3(state->ave, loc, ob->obmat[3]);
+ normalize_v3(state->ave);
+ }
+ else {
+ copy_v3_v3(state->ave, nor);
+ }
+
+ /* calculate rotation matrix */
+ project_v3_v3v3(dvec, r_vel, state->ave);
+ sub_v3_v3v3(mat[0], state->ave, dvec);
+ normalize_v3(mat[0]);
+ negate_v3_v3(mat[2], r_vel);
+ normalize_v3(mat[2]);
+ cross_v3_v3v3(mat[1], mat[2], mat[0]);
+
+ /* apply rotation */
+ mat3_to_quat_is_ok(q, mat);
+ copy_qt_qt(state->rot, q);
+ }
+ else {
+ /* conversion done so now we apply new: */
+ /* -velocity from: */
+
+ /* *reactions */
+ if (dtime > 0.f) {
+ sub_v3_v3v3(vel, pa->state.vel, pa->prev_state.vel);
+ }
+
+ /* *emitter velocity */
+ if (dtime != 0.f && part->obfac != 0.f) {
+ sub_v3_v3v3(vel, loc, state->co);
+ mul_v3_fl(vel, part->obfac / dtime);
+ }
+
+ /* *emitter normal */
+ if (part->normfac != 0.f)
+ madd_v3_v3fl(vel, nor, part->normfac);
+
+ /* *emitter tangent */
+ if (sim->psmd && part->tanfac != 0.f)
+ madd_v3_v3fl(vel, vtan, part->tanfac);
+
+ /* *emitter object orientation */
+ if (part->ob_vel[0] != 0.f) {
+ normalize_v3_v3(vec, ob->obmat[0]);
+ madd_v3_v3fl(vel, vec, part->ob_vel[0]);
+ }
+ if (part->ob_vel[1] != 0.f) {
+ normalize_v3_v3(vec, ob->obmat[1]);
+ madd_v3_v3fl(vel, vec, part->ob_vel[1]);
+ }
+ if (part->ob_vel[2] != 0.f) {
+ normalize_v3_v3(vec, ob->obmat[2]);
+ madd_v3_v3fl(vel, vec, part->ob_vel[2]);
+ }
+
+ /* *texture */
+ /* TODO */
+
+ /* *random */
+ if (part->randfac != 0.f)
+ madd_v3_v3fl(vel, r_vel, part->randfac);
+
+ /* *particle */
+ if (part->partfac != 0.f)
+ madd_v3_v3fl(vel, p_vel, part->partfac);
+
+ mul_v3_v3fl(state->vel, vel, ptex.ivel);
+
+ /* -location from emitter */
+ copy_v3_v3(state->co, loc);
+
+ /* -rotation */
+ unit_qt(state->rot);
+
+ if (part->rotmode) {
+ bool use_global_space;
+
+ /* create vector into which rotation is aligned */
+ switch (part->rotmode) {
+ case PART_ROT_NOR:
+ case PART_ROT_NOR_TAN:
+ copy_v3_v3(rot_vec, nor);
+ use_global_space = false;
+ break;
+ case PART_ROT_VEL:
+ copy_v3_v3(rot_vec, vel);
+ use_global_space = true;
+ break;
+ case PART_ROT_GLOB_X:
+ case PART_ROT_GLOB_Y:
+ case PART_ROT_GLOB_Z:
+ rot_vec[part->rotmode - PART_ROT_GLOB_X] = 1.0f;
+ use_global_space = true;
+ break;
+ case PART_ROT_OB_X:
+ case PART_ROT_OB_Y:
+ case PART_ROT_OB_Z:
+ copy_v3_v3(rot_vec, ob->obmat[part->rotmode - PART_ROT_OB_X]);
+ use_global_space = false;
+ break;
+ default:
+ use_global_space = true;
+ break;
+ }
+
+ /* create rotation quat */
+
+ if (use_global_space) {
+ negate_v3(rot_vec);
+ vec_to_quat(q2, rot_vec, OB_POSX, OB_POSZ);
+
+ /* randomize rotation quat */
+ if (part->randrotfac != 0.0f) {
+ interp_qt_qtqt(rot, q2, r_rot, part->randrotfac);
+ }
+ else {
+ copy_qt_qt(rot, q2);
+ }
+ }
+ else {
+ /* calculate rotation in local-space */
+ float q_obmat[4];
+ float q_imat[4];
+
+ mat4_to_quat(q_obmat, ob->obmat);
+ invert_qt_qt_normalized(q_imat, q_obmat);
+
+ if (part->rotmode != PART_ROT_NOR_TAN) {
+ float rot_vec_local[3];
+
+ /* rot_vec */
+ negate_v3(rot_vec);
+ copy_v3_v3(rot_vec_local, rot_vec);
+ mul_qt_v3(q_imat, rot_vec_local);
+ normalize_v3(rot_vec_local);
+
+ vec_to_quat(q2, rot_vec_local, OB_POSX, OB_POSZ);
+ }
+ else {
+ /* (part->rotmode == PART_ROT_NOR_TAN) */
+ float tmat[3][3];
+
+ /* note: utan_local is not taken from 'utan', we calculate from rot_vec/vtan */
+ /* note: it looks like rotation phase may be applied twice (once with vtan, again below)
+ * however this isn't the case - campbell */
+ float *rot_vec_local = tmat[0];
+ float *vtan_local = tmat[1];
+ float *utan_local = tmat[2];
+
+ /* use tangents */
+ BLI_assert(use_tangents == true);
+
+ /* rot_vec */
+ copy_v3_v3(rot_vec_local, rot_vec);
+ mul_qt_v3(q_imat, rot_vec_local);
+
+ /* vtan_local */
+ copy_v3_v3(vtan_local, vtan); /* flips, cant use */
+ mul_qt_v3(q_imat, vtan_local);
+
+ /* ensure orthogonal matrix (rot_vec aligned) */
+ cross_v3_v3v3(utan_local, vtan_local, rot_vec_local);
+ cross_v3_v3v3(vtan_local, utan_local, rot_vec_local);
+
+ /* note: no need to normalize */
+ mat3_to_quat(q2, tmat);
+ }
+
+ /* randomize rotation quat */
+ if (part->randrotfac != 0.0f) {
+ mul_qt_qtqt(r_rot, r_rot, q_imat);
+ interp_qt_qtqt(rot, q2, r_rot, part->randrotfac);
+ }
+ else {
+ copy_qt_qt(rot, q2);
+ }
+
+ mul_qt_qtqt(rot, q_obmat, rot);
+ }
+
+ /* rotation phase */
+ phasefac = part->phasefac;
+ if (part->randphasefac != 0.0f)
+ phasefac += part->randphasefac * psys_frand(psys, p + 20);
+ axis_angle_to_quat(q_phase, x_vec, phasefac * (float)M_PI);
+
+ /* combine base rotation & phase */
+ mul_qt_qtqt(state->rot, rot, q_phase);
+ }
+
+ /* -angular velocity */
+
+ zero_v3(state->ave);
+
+ if (part->avemode) {
+ if (part->avemode == PART_AVE_RAND)
+ copy_v3_v3(state->ave, r_ave);
+ else
+ get_angular_velocity_vector(part->avemode, state, state->ave);
+
+ normalize_v3(state->ave);
+ mul_v3_fl(state->ave, part->avefac);
+ }
+ }
}
/* recursively evaluate emitter parent anim at cfra */
-static void evaluate_emitter_anim(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float cfra)
+static void evaluate_emitter_anim(struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ float cfra)
{
- if (ob->parent)
- evaluate_emitter_anim(depsgraph, scene, ob->parent, cfra);
+ if (ob->parent)
+ evaluate_emitter_anim(depsgraph, scene, ob->parent, cfra);
- BKE_object_where_is_calc_time(depsgraph, scene, ob, cfra);
+ BKE_object_where_is_calc_time(depsgraph, scene, ob, cfra);
}
/* sets particle to the emitter surface with initial velocity & rotation */
void reset_particle(ParticleSimulationData *sim, ParticleData *pa, float dtime, float cfra)
{
- ParticleSystem *psys = sim->psys;
- ParticleSettings *part;
- ParticleTexture ptex;
- int p = pa - psys->particles;
- part=psys->part;
-
- /* get precise emitter matrix if particle is born */
- if (part->type != PART_HAIR && dtime > 0.f && pa->time < cfra && pa->time >= sim->psys->cfra) {
- evaluate_emitter_anim(sim->depsgraph, sim->scene, sim->ob, pa->time);
-
- psys->flag |= PSYS_OB_ANIM_RESTORE;
- }
-
- psys_get_birth_coords(sim, pa, &pa->state, dtime, cfra);
-
- /* Initialize particle settings which depends on texture.
- *
- * We could only do it now because we'll need to know coordinate
- * before sampling the texture.
- */
- initialize_particle_texture(sim, pa, p);
-
- if (part->phystype==PART_PHYS_BOIDS && pa->boid) {
- BoidParticle *bpa = pa->boid;
-
- /* and gravity in r_ve */
- bpa->gravity[0] = bpa->gravity[1] = 0.0f;
- bpa->gravity[2] = -1.0f;
- if ((sim->scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) &&
- (sim->scene->physics_settings.gravity[2] != 0.0f))
- {
- bpa->gravity[2] = sim->scene->physics_settings.gravity[2];
- }
-
- bpa->data.health = part->boids->health;
- bpa->data.mode = eBoidMode_InAir;
- bpa->data.state_id = ((BoidState*)part->boids->states.first)->id;
- bpa->data.acc[0]=bpa->data.acc[1]=bpa->data.acc[2]=0.0f;
- }
-
- if (part->type == PART_HAIR) {
- pa->lifetime = 100.0f;
- }
- else {
- /* initialize the lifetime, in case the texture coordinates
- * are from Particles/Strands, which would cause undefined values
- */
- pa->lifetime = part->lifetime * (1.0f - part->randlife * psys_frand(psys, p + 21));
- pa->dietime = pa->time + pa->lifetime;
-
- /* get possible textural influence */
- psys_get_texture(sim, pa, &ptex, PAMAP_LIFE, cfra);
-
- pa->lifetime = part->lifetime * ptex.life;
-
- if (part->randlife != 0.0f)
- pa->lifetime *= 1.0f - part->randlife * psys_frand(psys, p + 21);
- }
-
- pa->dietime = pa->time + pa->lifetime;
-
- if ((sim->psys->pointcache) &&
- (sim->psys->pointcache->flag & PTCACHE_BAKED) &&
- (sim->psys->pointcache->mem_cache.first))
- {
- float dietime = psys_get_dietime_from_cache(sim->psys->pointcache, p);
- pa->dietime = MIN2(pa->dietime, dietime);
- }
-
- if (pa->time > cfra)
- pa->alive = PARS_UNBORN;
- else if (pa->dietime <= cfra)
- pa->alive = PARS_DEAD;
- else
- pa->alive = PARS_ALIVE;
-
- pa->state.time = cfra;
+ ParticleSystem *psys = sim->psys;
+ ParticleSettings *part;
+ ParticleTexture ptex;
+ int p = pa - psys->particles;
+ part = psys->part;
+
+ /* get precise emitter matrix if particle is born */
+ if (part->type != PART_HAIR && dtime > 0.f && pa->time < cfra && pa->time >= sim->psys->cfra) {
+ evaluate_emitter_anim(sim->depsgraph, sim->scene, sim->ob, pa->time);
+
+ psys->flag |= PSYS_OB_ANIM_RESTORE;
+ }
+
+ psys_get_birth_coords(sim, pa, &pa->state, dtime, cfra);
+
+ /* Initialize particle settings which depends on texture.
+ *
+ * We could only do it now because we'll need to know coordinate
+ * before sampling the texture.
+ */
+ initialize_particle_texture(sim, pa, p);
+
+ if (part->phystype == PART_PHYS_BOIDS && pa->boid) {
+ BoidParticle *bpa = pa->boid;
+
+ /* and gravity in r_ve */
+ bpa->gravity[0] = bpa->gravity[1] = 0.0f;
+ bpa->gravity[2] = -1.0f;
+ if ((sim->scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) &&
+ (sim->scene->physics_settings.gravity[2] != 0.0f)) {
+ bpa->gravity[2] = sim->scene->physics_settings.gravity[2];
+ }
+
+ bpa->data.health = part->boids->health;
+ bpa->data.mode = eBoidMode_InAir;
+ bpa->data.state_id = ((BoidState *)part->boids->states.first)->id;
+ bpa->data.acc[0] = bpa->data.acc[1] = bpa->data.acc[2] = 0.0f;
+ }
+
+ if (part->type == PART_HAIR) {
+ pa->lifetime = 100.0f;
+ }
+ else {
+ /* initialize the lifetime, in case the texture coordinates
+ * are from Particles/Strands, which would cause undefined values
+ */
+ pa->lifetime = part->lifetime * (1.0f - part->randlife * psys_frand(psys, p + 21));
+ pa->dietime = pa->time + pa->lifetime;
+
+ /* get possible textural influence */
+ psys_get_texture(sim, pa, &ptex, PAMAP_LIFE, cfra);
+
+ pa->lifetime = part->lifetime * ptex.life;
+
+ if (part->randlife != 0.0f)
+ pa->lifetime *= 1.0f - part->randlife * psys_frand(psys, p + 21);
+ }
+
+ pa->dietime = pa->time + pa->lifetime;
+
+ if ((sim->psys->pointcache) && (sim->psys->pointcache->flag & PTCACHE_BAKED) &&
+ (sim->psys->pointcache->mem_cache.first)) {
+ float dietime = psys_get_dietime_from_cache(sim->psys->pointcache, p);
+ pa->dietime = MIN2(pa->dietime, dietime);
+ }
+
+ if (pa->time > cfra)
+ pa->alive = PARS_UNBORN;
+ else if (pa->dietime <= cfra)
+ pa->alive = PARS_DEAD;
+ else
+ pa->alive = PARS_ALIVE;
+
+ pa->state.time = cfra;
}
static void reset_all_particles(ParticleSimulationData *sim, float dtime, float cfra, int from)
{
- ParticleData *pa;
- int p, totpart=sim->psys->totpart;
+ ParticleData *pa;
+ int p, totpart = sim->psys->totpart;
- for (p=from, pa=sim->psys->particles+from; p<totpart; p++, pa++)
- reset_particle(sim, pa, dtime, cfra);
+ for (p = from, pa = sim->psys->particles + from; p < totpart; p++, pa++)
+ reset_particle(sim, pa, dtime, cfra);
}
/************************************************/
-/* Particle targets */
+/* Particle targets */
/************************************************/
ParticleSystem *psys_get_target_system(Object *ob, ParticleTarget *pt)
{
- ParticleSystem *psys = NULL;
+ ParticleSystem *psys = NULL;
- if (pt->ob == NULL || pt->ob == ob)
- psys = BLI_findlink(&ob->particlesystem, pt->psys-1);
- else
- psys = BLI_findlink(&pt->ob->particlesystem, pt->psys-1);
+ if (pt->ob == NULL || pt->ob == ob)
+ psys = BLI_findlink(&ob->particlesystem, pt->psys - 1);
+ else
+ psys = BLI_findlink(&pt->ob->particlesystem, pt->psys - 1);
- if (psys)
- pt->flag |= PTARGET_VALID;
- else
- pt->flag &= ~PTARGET_VALID;
+ if (psys)
+ pt->flag |= PTARGET_VALID;
+ else
+ pt->flag &= ~PTARGET_VALID;
- return psys;
+ return psys;
}
/************************************************/
-/* Keyed particles */
+/* Keyed particles */
/************************************************/
/* Counts valid keyed targets */
void psys_count_keyed_targets(ParticleSimulationData *sim)
{
- ParticleSystem *psys = sim->psys, *kpsys;
- ParticleTarget *pt = psys->targets.first;
- int keys_valid = 1;
- psys->totkeyed = 0;
-
- for (; pt; pt=pt->next) {
- kpsys = psys_get_target_system(sim->ob, pt);
-
- if (kpsys && kpsys->totpart) {
- psys->totkeyed += keys_valid;
- if (psys->flag & PSYS_KEYED_TIMING && pt->duration != 0.0f)
- psys->totkeyed += 1;
- }
- else {
- keys_valid = 0;
- }
- }
-
- psys->totkeyed *= psys->flag & PSYS_KEYED_TIMING ? 1 : psys->part->keyed_loops;
+ ParticleSystem *psys = sim->psys, *kpsys;
+ ParticleTarget *pt = psys->targets.first;
+ int keys_valid = 1;
+ psys->totkeyed = 0;
+
+ for (; pt; pt = pt->next) {
+ kpsys = psys_get_target_system(sim->ob, pt);
+
+ if (kpsys && kpsys->totpart) {
+ psys->totkeyed += keys_valid;
+ if (psys->flag & PSYS_KEYED_TIMING && pt->duration != 0.0f)
+ psys->totkeyed += 1;
+ }
+ else {
+ keys_valid = 0;
+ }
+ }
+
+ psys->totkeyed *= psys->flag & PSYS_KEYED_TIMING ? 1 : psys->part->keyed_loops;
}
static void set_keyed_keys(ParticleSimulationData *sim)
{
- ParticleSystem *psys = sim->psys;
- ParticleSimulationData ksim= {0};
- ParticleTarget *pt;
- PARTICLE_P;
- ParticleKey *key;
- int totpart = psys->totpart, k, totkeys = psys->totkeyed;
- int keyed_flag = 0;
-
- ksim.depsgraph = sim->depsgraph;
- ksim.scene = sim->scene;
-
- /* no proper targets so let's clear and bail out */
- if (psys->totkeyed==0) {
- free_keyed_keys(psys);
- psys->flag &= ~PSYS_KEYED;
- return;
- }
-
- if (totpart && psys->particles->totkey != totkeys) {
- free_keyed_keys(psys);
-
- key = MEM_callocN(totpart*totkeys*sizeof(ParticleKey), "Keyed keys");
-
- LOOP_PARTICLES {
- pa->keys = key;
- pa->totkey = totkeys;
- key += totkeys;
- }
- }
-
- psys->flag &= ~PSYS_KEYED;
-
-
- pt = psys->targets.first;
- for (k=0; k<totkeys; k++) {
- ksim.ob = pt->ob ? pt->ob : sim->ob;
- ksim.psys = BLI_findlink(&ksim.ob->particlesystem, pt->psys - 1);
- keyed_flag = (ksim.psys->flag & PSYS_KEYED);
- ksim.psys->flag &= ~PSYS_KEYED;
-
- LOOP_PARTICLES {
- key = pa->keys + k;
- key->time = -1.0; /* use current time */
-
- psys_get_particle_state(&ksim, p%ksim.psys->totpart, key, 1);
-
- if (psys->flag & PSYS_KEYED_TIMING) {
- key->time = pa->time + pt->time;
- if (pt->duration != 0.0f && k+1 < totkeys) {
- copy_particle_key(key+1, key, 1);
- (key+1)->time = pa->time + pt->time + pt->duration;
- }
- }
- else if (totkeys > 1)
- key->time = pa->time + (float)k / (float)(totkeys - 1) * pa->lifetime;
- else
- key->time = pa->time;
- }
-
- if (psys->flag & PSYS_KEYED_TIMING && pt->duration != 0.0f)
- k++;
-
- ksim.psys->flag |= keyed_flag;
-
- pt = (pt->next && pt->next->flag & PTARGET_VALID) ? pt->next : psys->targets.first;
- }
-
- psys->flag |= PSYS_KEYED;
+ ParticleSystem *psys = sim->psys;
+ ParticleSimulationData ksim = {0};
+ ParticleTarget *pt;
+ PARTICLE_P;
+ ParticleKey *key;
+ int totpart = psys->totpart, k, totkeys = psys->totkeyed;
+ int keyed_flag = 0;
+
+ ksim.depsgraph = sim->depsgraph;
+ ksim.scene = sim->scene;
+
+ /* no proper targets so let's clear and bail out */
+ if (psys->totkeyed == 0) {
+ free_keyed_keys(psys);
+ psys->flag &= ~PSYS_KEYED;
+ return;
+ }
+
+ if (totpart && psys->particles->totkey != totkeys) {
+ free_keyed_keys(psys);
+
+ key = MEM_callocN(totpart * totkeys * sizeof(ParticleKey), "Keyed keys");
+
+ LOOP_PARTICLES
+ {
+ pa->keys = key;
+ pa->totkey = totkeys;
+ key += totkeys;
+ }
+ }
+
+ psys->flag &= ~PSYS_KEYED;
+
+ pt = psys->targets.first;
+ for (k = 0; k < totkeys; k++) {
+ ksim.ob = pt->ob ? pt->ob : sim->ob;
+ ksim.psys = BLI_findlink(&ksim.ob->particlesystem, pt->psys - 1);
+ keyed_flag = (ksim.psys->flag & PSYS_KEYED);
+ ksim.psys->flag &= ~PSYS_KEYED;
+
+ LOOP_PARTICLES
+ {
+ key = pa->keys + k;
+ key->time = -1.0; /* use current time */
+
+ psys_get_particle_state(&ksim, p % ksim.psys->totpart, key, 1);
+
+ if (psys->flag & PSYS_KEYED_TIMING) {
+ key->time = pa->time + pt->time;
+ if (pt->duration != 0.0f && k + 1 < totkeys) {
+ copy_particle_key(key + 1, key, 1);
+ (key + 1)->time = pa->time + pt->time + pt->duration;
+ }
+ }
+ else if (totkeys > 1)
+ key->time = pa->time + (float)k / (float)(totkeys - 1) * pa->lifetime;
+ else
+ key->time = pa->time;
+ }
+
+ if (psys->flag & PSYS_KEYED_TIMING && pt->duration != 0.0f)
+ k++;
+
+ ksim.psys->flag |= keyed_flag;
+
+ pt = (pt->next && pt->next->flag & PTARGET_VALID) ? pt->next : psys->targets.first;
+ }
+
+ psys->flag |= PSYS_KEYED;
}
/************************************************/
-/* Point Cache */
+/* Point Cache */
/************************************************/
void psys_make_temp_pointcache(Object *ob, ParticleSystem *psys)
{
- PointCache *cache = psys->pointcache;
-
- if (cache->flag & PTCACHE_DISK_CACHE && BLI_listbase_is_empty(&cache->mem_cache)) {
- PTCacheID pid;
- BKE_ptcache_id_from_particles(&pid, ob, psys);
- cache->flag &= ~PTCACHE_DISK_CACHE;
- BKE_ptcache_disk_to_mem(&pid);
- cache->flag |= PTCACHE_DISK_CACHE;
- }
+ PointCache *cache = psys->pointcache;
+
+ if (cache->flag & PTCACHE_DISK_CACHE && BLI_listbase_is_empty(&cache->mem_cache)) {
+ PTCacheID pid;
+ BKE_ptcache_id_from_particles(&pid, ob, psys);
+ cache->flag &= ~PTCACHE_DISK_CACHE;
+ BKE_ptcache_disk_to_mem(&pid);
+ cache->flag |= PTCACHE_DISK_CACHE;
+ }
}
static void psys_clear_temp_pointcache(ParticleSystem *psys)
{
- if (psys->pointcache->flag & PTCACHE_DISK_CACHE)
- BKE_ptcache_free_mem(&psys->pointcache->mem_cache);
+ if (psys->pointcache->flag & PTCACHE_DISK_CACHE)
+ BKE_ptcache_free_mem(&psys->pointcache->mem_cache);
}
void psys_get_pointcache_start_end(Scene *scene, ParticleSystem *psys, int *sfra, int *efra)
{
- ParticleSettings *part = psys->part;
+ ParticleSettings *part = psys->part;
- *sfra = max_ii(1, (int)part->sta);
- *efra = min_ii((int)(part->end + part->lifetime + 1.0f), max_ii(scene->r.pefra, scene->r.efra));
+ *sfra = max_ii(1, (int)part->sta);
+ *efra = min_ii((int)(part->end + part->lifetime + 1.0f), max_ii(scene->r.pefra, scene->r.efra));
}
/************************************************/
-/* Effectors */
+/* Effectors */
/************************************************/
static void psys_update_particle_bvhtree(ParticleSystem *psys, float cfra)
{
- if (psys) {
- PARTICLE_P;
- int totpart = 0;
- bool need_rebuild;
-
- BLI_rw_mutex_lock(&psys_bvhtree_rwlock, THREAD_LOCK_READ);
- need_rebuild = !psys->bvhtree || psys->bvhtree_frame != cfra;
- BLI_rw_mutex_unlock(&psys_bvhtree_rwlock);
-
- if (need_rebuild) {
- LOOP_SHOWN_PARTICLES {
- totpart++;
- }
-
- BLI_rw_mutex_lock(&psys_bvhtree_rwlock, THREAD_LOCK_WRITE);
-
- BLI_bvhtree_free(psys->bvhtree);
- psys->bvhtree = BLI_bvhtree_new(totpart, 0.0, 4, 6);
-
- LOOP_SHOWN_PARTICLES {
- if (pa->alive == PARS_ALIVE) {
- if (pa->state.time == cfra)
- BLI_bvhtree_insert(psys->bvhtree, p, pa->prev_state.co, 1);
- else
- BLI_bvhtree_insert(psys->bvhtree, p, pa->state.co, 1);
- }
- }
- BLI_bvhtree_balance(psys->bvhtree);
-
- psys->bvhtree_frame = cfra;
-
- BLI_rw_mutex_unlock(&psys_bvhtree_rwlock);
- }
- }
+ if (psys) {
+ PARTICLE_P;
+ int totpart = 0;
+ bool need_rebuild;
+
+ BLI_rw_mutex_lock(&psys_bvhtree_rwlock, THREAD_LOCK_READ);
+ need_rebuild = !psys->bvhtree || psys->bvhtree_frame != cfra;
+ BLI_rw_mutex_unlock(&psys_bvhtree_rwlock);
+
+ if (need_rebuild) {
+ LOOP_SHOWN_PARTICLES
+ {
+ totpart++;
+ }
+
+ BLI_rw_mutex_lock(&psys_bvhtree_rwlock, THREAD_LOCK_WRITE);
+
+ BLI_bvhtree_free(psys->bvhtree);
+ psys->bvhtree = BLI_bvhtree_new(totpart, 0.0, 4, 6);
+
+ LOOP_SHOWN_PARTICLES
+ {
+ if (pa->alive == PARS_ALIVE) {
+ if (pa->state.time == cfra)
+ BLI_bvhtree_insert(psys->bvhtree, p, pa->prev_state.co, 1);
+ else
+ BLI_bvhtree_insert(psys->bvhtree, p, pa->state.co, 1);
+ }
+ }
+ BLI_bvhtree_balance(psys->bvhtree);
+
+ psys->bvhtree_frame = cfra;
+
+ BLI_rw_mutex_unlock(&psys_bvhtree_rwlock);
+ }
+ }
}
void psys_update_particle_tree(ParticleSystem *psys, float cfra)
{
- if (psys) {
- PARTICLE_P;
- int totpart = 0;
-
- if (!psys->tree || psys->tree_frame != cfra) {
- LOOP_SHOWN_PARTICLES {
- totpart++;
- }
-
- BLI_kdtree_3d_free(psys->tree);
- psys->tree = BLI_kdtree_3d_new(psys->totpart);
-
- LOOP_SHOWN_PARTICLES {
- if (pa->alive == PARS_ALIVE) {
- if (pa->state.time == cfra)
- BLI_kdtree_3d_insert(psys->tree, p, pa->prev_state.co);
- else
- BLI_kdtree_3d_insert(psys->tree, p, pa->state.co);
- }
- }
- BLI_kdtree_3d_balance(psys->tree);
-
- psys->tree_frame = cfra;
- }
- }
+ if (psys) {
+ PARTICLE_P;
+ int totpart = 0;
+
+ if (!psys->tree || psys->tree_frame != cfra) {
+ LOOP_SHOWN_PARTICLES
+ {
+ totpart++;
+ }
+
+ BLI_kdtree_3d_free(psys->tree);
+ psys->tree = BLI_kdtree_3d_new(psys->totpart);
+
+ LOOP_SHOWN_PARTICLES
+ {
+ if (pa->alive == PARS_ALIVE) {
+ if (pa->state.time == cfra)
+ BLI_kdtree_3d_insert(psys->tree, p, pa->prev_state.co);
+ else
+ BLI_kdtree_3d_insert(psys->tree, p, pa->state.co);
+ }
+ }
+ BLI_kdtree_3d_balance(psys->tree);
+
+ psys->tree_frame = cfra;
+ }
+ }
}
static void psys_update_effectors(ParticleSimulationData *sim)
{
- BKE_effectors_free(sim->psys->effectors);
- sim->psys->effectors = BKE_effectors_create(sim->depsgraph,
- sim->ob, sim->psys,
- sim->psys->part->effector_weights);
- precalc_guides(sim, sim->psys->effectors);
+ BKE_effectors_free(sim->psys->effectors);
+ sim->psys->effectors = BKE_effectors_create(
+ sim->depsgraph, sim->ob, sim->psys, sim->psys->part->effector_weights);
+ precalc_guides(sim, sim->psys->effectors);
}
-static void integrate_particle(ParticleSettings *part, ParticleData *pa, float dtime, float *external_acceleration,
- void (*force_func)(void *forcedata, ParticleKey *state, float *force, float *impulse),
- void *forcedata)
+static void integrate_particle(
+ ParticleSettings *part,
+ ParticleData *pa,
+ float dtime,
+ float *external_acceleration,
+ void (*force_func)(void *forcedata, ParticleKey *state, float *force, float *impulse),
+ void *forcedata)
{
-#define ZERO_F43 {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}
-
- ParticleKey states[5];
- float force[3], acceleration[3], impulse[3], dx[4][3] = ZERO_F43, dv[4][3] = ZERO_F43, oldpos[3];
- float pa_mass= (part->flag & PART_SIZEMASS ? part->mass * pa->size : part->mass);
- int i, steps=1;
- int integrator = part->integrator;
+#define ZERO_F43 \
+ { \
+ {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}, \
+ { \
+ 0.0f, 0.0f, 0.0f \
+ } \
+ }
+
+ ParticleKey states[5];
+ float force[3], acceleration[3], impulse[3], dx[4][3] = ZERO_F43, dv[4][3] = ZERO_F43, oldpos[3];
+ float pa_mass = (part->flag & PART_SIZEMASS ? part->mass * pa->size : part->mass);
+ int i, steps = 1;
+ int integrator = part->integrator;
#undef ZERO_F43
- copy_v3_v3(oldpos, pa->state.co);
-
- /* Verlet integration behaves strangely with moving emitters, so do first step with euler. */
- if (pa->prev_state.time < 0.f && integrator == PART_INT_VERLET)
- integrator = PART_INT_EULER;
-
- switch (integrator) {
- case PART_INT_EULER:
- steps=1;
- break;
- case PART_INT_MIDPOINT:
- steps=2;
- break;
- case PART_INT_RK4:
- steps=4;
- break;
- case PART_INT_VERLET:
- steps=1;
- break;
- }
-
- for (i=0; i<steps; i++) {
- copy_particle_key(states + i, &pa->state, 1);
- }
-
- states->time = 0.f;
-
- for (i=0; i<steps; i++) {
- zero_v3(force);
- zero_v3(impulse);
-
- force_func(forcedata, states+i, force, impulse);
-
- /* force to acceleration*/
- mul_v3_v3fl(acceleration, force, 1.0f/pa_mass);
-
- if (external_acceleration)
- add_v3_v3(acceleration, external_acceleration);
-
- /* calculate next state */
- add_v3_v3(states[i].vel, impulse);
-
- switch (integrator) {
- case PART_INT_EULER:
- madd_v3_v3v3fl(pa->state.co, states->co, states->vel, dtime);
- madd_v3_v3v3fl(pa->state.vel, states->vel, acceleration, dtime);
- break;
- case PART_INT_MIDPOINT:
- if (i==0) {
- madd_v3_v3v3fl(states[1].co, states->co, states->vel, dtime*0.5f);
- madd_v3_v3v3fl(states[1].vel, states->vel, acceleration, dtime*0.5f);
- states[1].time = dtime*0.5f;
- /*fra=sim->psys->cfra+0.5f*dfra;*/
- }
- else {
- madd_v3_v3v3fl(pa->state.co, states->co, states[1].vel, dtime);
- madd_v3_v3v3fl(pa->state.vel, states->vel, acceleration, dtime);
- }
- break;
- case PART_INT_RK4:
- switch (i) {
- case 0:
- copy_v3_v3(dx[0], states->vel);
- mul_v3_fl(dx[0], dtime);
- copy_v3_v3(dv[0], acceleration);
- mul_v3_fl(dv[0], dtime);
-
- madd_v3_v3v3fl(states[1].co, states->co, dx[0], 0.5f);
- madd_v3_v3v3fl(states[1].vel, states->vel, dv[0], 0.5f);
- states[1].time = dtime*0.5f;
- /*fra=sim->psys->cfra+0.5f*dfra;*/
- break;
- case 1:
- madd_v3_v3v3fl(dx[1], states->vel, dv[0], 0.5f);
- mul_v3_fl(dx[1], dtime);
- copy_v3_v3(dv[1], acceleration);
- mul_v3_fl(dv[1], dtime);
-
- madd_v3_v3v3fl(states[2].co, states->co, dx[1], 0.5f);
- madd_v3_v3v3fl(states[2].vel, states->vel, dv[1], 0.5f);
- states[2].time = dtime*0.5f;
- break;
- case 2:
- madd_v3_v3v3fl(dx[2], states->vel, dv[1], 0.5f);
- mul_v3_fl(dx[2], dtime);
- copy_v3_v3(dv[2], acceleration);
- mul_v3_fl(dv[2], dtime);
-
- add_v3_v3v3(states[3].co, states->co, dx[2]);
- add_v3_v3v3(states[3].vel, states->vel, dv[2]);
- states[3].time = dtime;
- /*fra=cfra;*/
- break;
- case 3:
- add_v3_v3v3(dx[3], states->vel, dv[2]);
- mul_v3_fl(dx[3], dtime);
- copy_v3_v3(dv[3], acceleration);
- mul_v3_fl(dv[3], dtime);
-
- madd_v3_v3v3fl(pa->state.co, states->co, dx[0], 1.0f/6.0f);
- madd_v3_v3fl(pa->state.co, dx[1], 1.0f/3.0f);
- madd_v3_v3fl(pa->state.co, dx[2], 1.0f/3.0f);
- madd_v3_v3fl(pa->state.co, dx[3], 1.0f/6.0f);
-
- madd_v3_v3v3fl(pa->state.vel, states->vel, dv[0], 1.0f/6.0f);
- madd_v3_v3fl(pa->state.vel, dv[1], 1.0f/3.0f);
- madd_v3_v3fl(pa->state.vel, dv[2], 1.0f/3.0f);
- madd_v3_v3fl(pa->state.vel, dv[3], 1.0f/6.0f);
- }
- break;
- case PART_INT_VERLET: /* Verlet integration */
- madd_v3_v3v3fl(pa->state.vel, pa->prev_state.vel, acceleration, dtime);
- madd_v3_v3v3fl(pa->state.co, pa->prev_state.co, pa->state.vel, dtime);
-
- sub_v3_v3v3(pa->state.vel, pa->state.co, oldpos);
- mul_v3_fl(pa->state.vel, 1.0f/dtime);
- break;
- }
- }
+ copy_v3_v3(oldpos, pa->state.co);
+
+ /* Verlet integration behaves strangely with moving emitters, so do first step with euler. */
+ if (pa->prev_state.time < 0.f && integrator == PART_INT_VERLET)
+ integrator = PART_INT_EULER;
+
+ switch (integrator) {
+ case PART_INT_EULER:
+ steps = 1;
+ break;
+ case PART_INT_MIDPOINT:
+ steps = 2;
+ break;
+ case PART_INT_RK4:
+ steps = 4;
+ break;
+ case PART_INT_VERLET:
+ steps = 1;
+ break;
+ }
+
+ for (i = 0; i < steps; i++) {
+ copy_particle_key(states + i, &pa->state, 1);
+ }
+
+ states->time = 0.f;
+
+ for (i = 0; i < steps; i++) {
+ zero_v3(force);
+ zero_v3(impulse);
+
+ force_func(forcedata, states + i, force, impulse);
+
+ /* force to acceleration*/
+ mul_v3_v3fl(acceleration, force, 1.0f / pa_mass);
+
+ if (external_acceleration)
+ add_v3_v3(acceleration, external_acceleration);
+
+ /* calculate next state */
+ add_v3_v3(states[i].vel, impulse);
+
+ switch (integrator) {
+ case PART_INT_EULER:
+ madd_v3_v3v3fl(pa->state.co, states->co, states->vel, dtime);
+ madd_v3_v3v3fl(pa->state.vel, states->vel, acceleration, dtime);
+ break;
+ case PART_INT_MIDPOINT:
+ if (i == 0) {
+ madd_v3_v3v3fl(states[1].co, states->co, states->vel, dtime * 0.5f);
+ madd_v3_v3v3fl(states[1].vel, states->vel, acceleration, dtime * 0.5f);
+ states[1].time = dtime * 0.5f;
+ /*fra=sim->psys->cfra+0.5f*dfra;*/
+ }
+ else {
+ madd_v3_v3v3fl(pa->state.co, states->co, states[1].vel, dtime);
+ madd_v3_v3v3fl(pa->state.vel, states->vel, acceleration, dtime);
+ }
+ break;
+ case PART_INT_RK4:
+ switch (i) {
+ case 0:
+ copy_v3_v3(dx[0], states->vel);
+ mul_v3_fl(dx[0], dtime);
+ copy_v3_v3(dv[0], acceleration);
+ mul_v3_fl(dv[0], dtime);
+
+ madd_v3_v3v3fl(states[1].co, states->co, dx[0], 0.5f);
+ madd_v3_v3v3fl(states[1].vel, states->vel, dv[0], 0.5f);
+ states[1].time = dtime * 0.5f;
+ /*fra=sim->psys->cfra+0.5f*dfra;*/
+ break;
+ case 1:
+ madd_v3_v3v3fl(dx[1], states->vel, dv[0], 0.5f);
+ mul_v3_fl(dx[1], dtime);
+ copy_v3_v3(dv[1], acceleration);
+ mul_v3_fl(dv[1], dtime);
+
+ madd_v3_v3v3fl(states[2].co, states->co, dx[1], 0.5f);
+ madd_v3_v3v3fl(states[2].vel, states->vel, dv[1], 0.5f);
+ states[2].time = dtime * 0.5f;
+ break;
+ case 2:
+ madd_v3_v3v3fl(dx[2], states->vel, dv[1], 0.5f);
+ mul_v3_fl(dx[2], dtime);
+ copy_v3_v3(dv[2], acceleration);
+ mul_v3_fl(dv[2], dtime);
+
+ add_v3_v3v3(states[3].co, states->co, dx[2]);
+ add_v3_v3v3(states[3].vel, states->vel, dv[2]);
+ states[3].time = dtime;
+ /*fra=cfra;*/
+ break;
+ case 3:
+ add_v3_v3v3(dx[3], states->vel, dv[2]);
+ mul_v3_fl(dx[3], dtime);
+ copy_v3_v3(dv[3], acceleration);
+ mul_v3_fl(dv[3], dtime);
+
+ madd_v3_v3v3fl(pa->state.co, states->co, dx[0], 1.0f / 6.0f);
+ madd_v3_v3fl(pa->state.co, dx[1], 1.0f / 3.0f);
+ madd_v3_v3fl(pa->state.co, dx[2], 1.0f / 3.0f);
+ madd_v3_v3fl(pa->state.co, dx[3], 1.0f / 6.0f);
+
+ madd_v3_v3v3fl(pa->state.vel, states->vel, dv[0], 1.0f / 6.0f);
+ madd_v3_v3fl(pa->state.vel, dv[1], 1.0f / 3.0f);
+ madd_v3_v3fl(pa->state.vel, dv[2], 1.0f / 3.0f);
+ madd_v3_v3fl(pa->state.vel, dv[3], 1.0f / 6.0f);
+ }
+ break;
+ case PART_INT_VERLET: /* Verlet integration */
+ madd_v3_v3v3fl(pa->state.vel, pa->prev_state.vel, acceleration, dtime);
+ madd_v3_v3v3fl(pa->state.co, pa->prev_state.co, pa->state.vel, dtime);
+
+ sub_v3_v3v3(pa->state.vel, pa->state.co, oldpos);
+ mul_v3_fl(pa->state.vel, 1.0f / dtime);
+ break;
+ }
+ }
}
/*********************************************************************************************************
@@ -1459,172 +1502,182 @@ static void integrate_particle(ParticleSettings *part, ParticleData *pa, float d
#define PSYS_FLUID_SPRINGS_INITIAL_SIZE 256
static ParticleSpring *sph_spring_add(ParticleSystem *psys, ParticleSpring *spring)
{
- /* Are more refs required? */
- if (psys->alloc_fluidsprings == 0 || psys->fluid_springs == NULL) {
- psys->alloc_fluidsprings = PSYS_FLUID_SPRINGS_INITIAL_SIZE;
- psys->fluid_springs = (ParticleSpring*)MEM_callocN(psys->alloc_fluidsprings * sizeof(ParticleSpring), "Particle Fluid Springs");
- }
- else if (psys->tot_fluidsprings == psys->alloc_fluidsprings) {
- /* Double the number of refs allocated */
- psys->alloc_fluidsprings *= 2;
- psys->fluid_springs = (ParticleSpring*)MEM_reallocN(psys->fluid_springs, psys->alloc_fluidsprings * sizeof(ParticleSpring));
- }
-
- memcpy(psys->fluid_springs + psys->tot_fluidsprings, spring, sizeof(ParticleSpring));
- psys->tot_fluidsprings++;
-
- return psys->fluid_springs + psys->tot_fluidsprings - 1;
+ /* Are more refs required? */
+ if (psys->alloc_fluidsprings == 0 || psys->fluid_springs == NULL) {
+ psys->alloc_fluidsprings = PSYS_FLUID_SPRINGS_INITIAL_SIZE;
+ psys->fluid_springs = (ParticleSpring *)MEM_callocN(
+ psys->alloc_fluidsprings * sizeof(ParticleSpring), "Particle Fluid Springs");
+ }
+ else if (psys->tot_fluidsprings == psys->alloc_fluidsprings) {
+ /* Double the number of refs allocated */
+ psys->alloc_fluidsprings *= 2;
+ psys->fluid_springs = (ParticleSpring *)MEM_reallocN(
+ psys->fluid_springs, psys->alloc_fluidsprings * sizeof(ParticleSpring));
+ }
+
+ memcpy(psys->fluid_springs + psys->tot_fluidsprings, spring, sizeof(ParticleSpring));
+ psys->tot_fluidsprings++;
+
+ return psys->fluid_springs + psys->tot_fluidsprings - 1;
}
static void sph_spring_delete(ParticleSystem *psys, int j)
{
- if (j != psys->tot_fluidsprings - 1)
- psys->fluid_springs[j] = psys->fluid_springs[psys->tot_fluidsprings - 1];
+ if (j != psys->tot_fluidsprings - 1)
+ psys->fluid_springs[j] = psys->fluid_springs[psys->tot_fluidsprings - 1];
- psys->tot_fluidsprings--;
+ psys->tot_fluidsprings--;
- if (psys->tot_fluidsprings < psys->alloc_fluidsprings/2 && psys->alloc_fluidsprings > PSYS_FLUID_SPRINGS_INITIAL_SIZE) {
- psys->alloc_fluidsprings /= 2;
- psys->fluid_springs = (ParticleSpring*)MEM_reallocN(psys->fluid_springs, psys->alloc_fluidsprings * sizeof(ParticleSpring));
- }
+ if (psys->tot_fluidsprings < psys->alloc_fluidsprings / 2 &&
+ psys->alloc_fluidsprings > PSYS_FLUID_SPRINGS_INITIAL_SIZE) {
+ psys->alloc_fluidsprings /= 2;
+ psys->fluid_springs = (ParticleSpring *)MEM_reallocN(
+ psys->fluid_springs, psys->alloc_fluidsprings * sizeof(ParticleSpring));
+ }
}
static void sph_springs_modify(ParticleSystem *psys, float dtime)
{
- SPHFluidSettings *fluid = psys->part->fluid;
- ParticleData *pa1, *pa2;
- ParticleSpring *spring = psys->fluid_springs;
+ SPHFluidSettings *fluid = psys->part->fluid;
+ ParticleData *pa1, *pa2;
+ ParticleSpring *spring = psys->fluid_springs;
- float h, d, Rij[3], rij, Lij;
- int i;
+ float h, d, Rij[3], rij, Lij;
+ int i;
- float yield_ratio = fluid->yield_ratio;
- float plasticity = fluid->plasticity_constant;
- /* scale things according to dtime */
- float timefix = 25.f * dtime;
+ float yield_ratio = fluid->yield_ratio;
+ float plasticity = fluid->plasticity_constant;
+ /* scale things according to dtime */
+ float timefix = 25.f * dtime;
- if ((fluid->flag & SPH_VISCOELASTIC_SPRINGS)==0 || fluid->spring_k == 0.f)
- return;
+ if ((fluid->flag & SPH_VISCOELASTIC_SPRINGS) == 0 || fluid->spring_k == 0.f)
+ return;
- /* Loop through the springs */
- for (i=0; i<psys->tot_fluidsprings; i++, spring++) {
- pa1 = psys->particles + spring->particle_index[0];
- pa2 = psys->particles + spring->particle_index[1];
+ /* Loop through the springs */
+ for (i = 0; i < psys->tot_fluidsprings; i++, spring++) {
+ pa1 = psys->particles + spring->particle_index[0];
+ pa2 = psys->particles + spring->particle_index[1];
- sub_v3_v3v3(Rij, pa2->prev_state.co, pa1->prev_state.co);
- rij = normalize_v3(Rij);
+ sub_v3_v3v3(Rij, pa2->prev_state.co, pa1->prev_state.co);
+ rij = normalize_v3(Rij);
- /* adjust rest length */
- Lij = spring->rest_length;
- d = yield_ratio * timefix * Lij;
+ /* adjust rest length */
+ Lij = spring->rest_length;
+ d = yield_ratio * timefix * Lij;
- if (rij > Lij + d) // Stretch
- spring->rest_length += plasticity * (rij - Lij - d) * timefix;
- else if (rij < Lij - d) // Compress
- spring->rest_length -= plasticity * (Lij - d - rij) * timefix;
+ if (rij > Lij + d) // Stretch
+ spring->rest_length += plasticity * (rij - Lij - d) * timefix;
+ else if (rij < Lij - d) // Compress
+ spring->rest_length -= plasticity * (Lij - d - rij) * timefix;
- h = 4.f*pa1->size;
+ h = 4.f * pa1->size;
- if (spring->rest_length > h)
- spring->delete_flag = 1;
- }
+ if (spring->rest_length > h)
+ spring->delete_flag = 1;
+ }
- /* Loop through springs backwaqrds - for efficient delete function */
- for (i=psys->tot_fluidsprings-1; i >= 0; i--) {
- if (psys->fluid_springs[i].delete_flag)
- sph_spring_delete(psys, i);
- }
+ /* Loop through springs backwaqrds - for efficient delete function */
+ for (i = psys->tot_fluidsprings - 1; i >= 0; i--) {
+ if (psys->fluid_springs[i].delete_flag)
+ sph_spring_delete(psys, i);
+ }
}
static EdgeHash *sph_springhash_build(ParticleSystem *psys)
{
- EdgeHash *springhash = NULL;
- ParticleSpring *spring;
- int i = 0;
+ EdgeHash *springhash = NULL;
+ ParticleSpring *spring;
+ int i = 0;
- springhash = BLI_edgehash_new_ex(__func__, psys->tot_fluidsprings);
+ springhash = BLI_edgehash_new_ex(__func__, psys->tot_fluidsprings);
- for (i=0, spring=psys->fluid_springs; i<psys->tot_fluidsprings; i++, spring++)
- BLI_edgehash_insert(springhash, spring->particle_index[0], spring->particle_index[1], POINTER_FROM_INT(i+1));
+ for (i = 0, spring = psys->fluid_springs; i < psys->tot_fluidsprings; i++, spring++)
+ BLI_edgehash_insert(
+ springhash, spring->particle_index[0], spring->particle_index[1], POINTER_FROM_INT(i + 1));
- return springhash;
+ return springhash;
}
#define SPH_NEIGHBORS 512
typedef struct SPHNeighbor {
- ParticleSystem *psys;
- int index;
+ ParticleSystem *psys;
+ int index;
} SPHNeighbor;
typedef struct SPHRangeData {
- SPHNeighbor neighbors[SPH_NEIGHBORS];
- int tot_neighbors;
+ SPHNeighbor neighbors[SPH_NEIGHBORS];
+ int tot_neighbors;
- float *data;
+ float *data;
- ParticleSystem *npsys;
- ParticleData *pa;
+ ParticleSystem *npsys;
+ ParticleData *pa;
- float h;
- float mass;
- float massfac;
- int use_size;
+ float h;
+ float mass;
+ float massfac;
+ int use_size;
} SPHRangeData;
-static void sph_evaluate_func(BVHTree *tree, ParticleSystem **psys, float co[3], SPHRangeData *pfr, float interaction_radius, BVHTree_RangeQuery callback)
+static void sph_evaluate_func(BVHTree *tree,
+ ParticleSystem **psys,
+ float co[3],
+ SPHRangeData *pfr,
+ float interaction_radius,
+ BVHTree_RangeQuery callback)
{
- int i;
+ int i;
- pfr->tot_neighbors = 0;
+ pfr->tot_neighbors = 0;
- for (i=0; i < 10 && psys[i]; i++) {
- pfr->npsys = psys[i];
- pfr->massfac = psys[i]->part->mass / pfr->mass;
- pfr->use_size = psys[i]->part->flag & PART_SIZEMASS;
+ for (i = 0; i < 10 && psys[i]; i++) {
+ pfr->npsys = psys[i];
+ pfr->massfac = psys[i]->part->mass / pfr->mass;
+ pfr->use_size = psys[i]->part->flag & PART_SIZEMASS;
- if (tree) {
- BLI_bvhtree_range_query(tree, co, interaction_radius, callback, pfr);
- break;
- }
- else {
- BLI_rw_mutex_lock(&psys_bvhtree_rwlock, THREAD_LOCK_READ);
+ if (tree) {
+ BLI_bvhtree_range_query(tree, co, interaction_radius, callback, pfr);
+ break;
+ }
+ else {
+ BLI_rw_mutex_lock(&psys_bvhtree_rwlock, THREAD_LOCK_READ);
- BLI_bvhtree_range_query(psys[i]->bvhtree, co, interaction_radius, callback, pfr);
+ BLI_bvhtree_range_query(psys[i]->bvhtree, co, interaction_radius, callback, pfr);
- BLI_rw_mutex_unlock(&psys_bvhtree_rwlock);
- }
- }
+ BLI_rw_mutex_unlock(&psys_bvhtree_rwlock);
+ }
+ }
}
static void sph_density_accum_cb(void *userdata, int index, const float co[3], float squared_dist)
{
- SPHRangeData *pfr = (SPHRangeData *)userdata;
- ParticleData *npa = pfr->npsys->particles + index;
- float q;
- float dist;
+ SPHRangeData *pfr = (SPHRangeData *)userdata;
+ ParticleData *npa = pfr->npsys->particles + index;
+ float q;
+ float dist;
- UNUSED_VARS(co);
+ UNUSED_VARS(co);
- if (npa == pfr->pa || squared_dist < FLT_EPSILON)
- return;
+ if (npa == pfr->pa || squared_dist < FLT_EPSILON)
+ return;
- /* Ugh! One particle has too many neighbors! If some aren't taken into
- * account, the forces will be biased by the tree search order. This
- * effectively adds energy to the system, and results in a churning motion.
- * But, we have to stop somewhere, and it's not the end of the world.
- * - jahka and z0r
- */
- if (pfr->tot_neighbors >= SPH_NEIGHBORS)
- return;
+ /* Ugh! One particle has too many neighbors! If some aren't taken into
+ * account, the forces will be biased by the tree search order. This
+ * effectively adds energy to the system, and results in a churning motion.
+ * But, we have to stop somewhere, and it's not the end of the world.
+ * - jahka and z0r
+ */
+ if (pfr->tot_neighbors >= SPH_NEIGHBORS)
+ return;
- pfr->neighbors[pfr->tot_neighbors].index = index;
- pfr->neighbors[pfr->tot_neighbors].psys = pfr->npsys;
- pfr->tot_neighbors++;
+ pfr->neighbors[pfr->tot_neighbors].index = index;
+ pfr->neighbors[pfr->tot_neighbors].psys = pfr->npsys;
+ pfr->tot_neighbors++;
- dist = sqrtf(squared_dist);
- q = (1.f - dist/pfr->h) * pfr->massfac;
+ dist = sqrtf(squared_dist);
+ q = (1.f - dist / pfr->h) * pfr->massfac;
- if (pfr->use_size)
- q *= npa->size;
+ if (pfr->use_size)
+ q *= npa->size;
- pfr->data[0] += q * q;
- pfr->data[1] += q * q * q;
+ pfr->data[0] += q * q;
+ pfr->data[1] += q * q * q;
}
/*
@@ -1632,556 +1685,580 @@ static void sph_density_accum_cb(void *userdata, int index, const float co[3], f
*/
static void sph_particle_courant(SPHData *sphdata, SPHRangeData *pfr)
{
- ParticleData *pa, *npa;
- int i;
- float flow[3], offset[3], dist;
-
- zero_v3(flow);
-
- dist = 0.0f;
- if (pfr->tot_neighbors > 0) {
- pa = pfr->pa;
- for (i=0; i < pfr->tot_neighbors; i++) {
- npa = pfr->neighbors[i].psys->particles + pfr->neighbors[i].index;
- sub_v3_v3v3(offset, pa->prev_state.co, npa->prev_state.co);
- dist += len_v3(offset);
- add_v3_v3(flow, npa->prev_state.vel);
- }
- dist += sphdata->psys[0]->part->fluid->radius; // TODO: remove this? - z0r
- sphdata->element_size = dist / pfr->tot_neighbors;
- mul_v3_v3fl(sphdata->flow, flow, 1.0f / pfr->tot_neighbors);
- }
- else {
- sphdata->element_size = FLT_MAX;
- copy_v3_v3(sphdata->flow, flow);
- }
+ ParticleData *pa, *npa;
+ int i;
+ float flow[3], offset[3], dist;
+
+ zero_v3(flow);
+
+ dist = 0.0f;
+ if (pfr->tot_neighbors > 0) {
+ pa = pfr->pa;
+ for (i = 0; i < pfr->tot_neighbors; i++) {
+ npa = pfr->neighbors[i].psys->particles + pfr->neighbors[i].index;
+ sub_v3_v3v3(offset, pa->prev_state.co, npa->prev_state.co);
+ dist += len_v3(offset);
+ add_v3_v3(flow, npa->prev_state.vel);
+ }
+ dist += sphdata->psys[0]->part->fluid->radius; // TODO: remove this? - z0r
+ sphdata->element_size = dist / pfr->tot_neighbors;
+ mul_v3_v3fl(sphdata->flow, flow, 1.0f / pfr->tot_neighbors);
+ }
+ else {
+ sphdata->element_size = FLT_MAX;
+ copy_v3_v3(sphdata->flow, flow);
+ }
}
static void sph_force_cb(void *sphdata_v, ParticleKey *state, float *force, float *UNUSED(impulse))
{
- SPHData *sphdata = (SPHData *)sphdata_v;
- ParticleSystem **psys = sphdata->psys;
- ParticleData *pa = sphdata->pa;
- SPHFluidSettings *fluid = psys[0]->part->fluid;
- ParticleSpring *spring = NULL;
- SPHRangeData pfr;
- SPHNeighbor *pfn;
- float *gravity = sphdata->gravity;
- EdgeHash *springhash = sphdata->eh;
-
- float q, u, rij, dv[3];
- float pressure, near_pressure;
-
- float visc = fluid->viscosity_omega;
- float stiff_visc = fluid->viscosity_beta * (fluid->flag & SPH_FAC_VISCOSITY ? fluid->viscosity_omega : 1.f);
-
- float inv_mass = 1.0f / sphdata->mass;
- float spring_constant = fluid->spring_k;
-
- /* 4.0 seems to be a pretty good value */
- float interaction_radius = fluid->radius * (fluid->flag & SPH_FAC_RADIUS ? 4.0f * pa->size : 1.0f);
- float h = interaction_radius * sphdata->hfac;
- /* 4.77 is an experimentally determined density factor */
- float rest_density = fluid->rest_density * (fluid->flag & SPH_FAC_DENSITY ? 4.77f : 1.f);
- float rest_length = fluid->rest_length * (fluid->flag & SPH_FAC_REST_LENGTH ? 2.588f * pa->size : 1.f);
-
- float stiffness = fluid->stiffness_k;
- float stiffness_near_fac = fluid->stiffness_knear * (fluid->flag & SPH_FAC_REPULSION ? fluid->stiffness_k : 1.f);
-
- ParticleData *npa;
- float vec[3];
- float vel[3];
- float co[3];
- float data[2];
- float density, near_density;
-
- int i, spring_index, index = pa - psys[0]->particles;
-
- data[0] = data[1] = 0;
- pfr.data = data;
- pfr.h = h;
- pfr.pa = pa;
- pfr.mass = sphdata->mass;
-
- sph_evaluate_func( NULL, psys, state->co, &pfr, interaction_radius, sph_density_accum_cb);
-
- density = data[0];
- near_density = data[1];
-
- pressure = stiffness * (density - rest_density);
- near_pressure = stiffness_near_fac * near_density;
-
- pfn = pfr.neighbors;
- for (i=0; i<pfr.tot_neighbors; i++, pfn++) {
- npa = pfn->psys->particles + pfn->index;
-
- madd_v3_v3v3fl(co, npa->prev_state.co, npa->prev_state.vel, state->time);
-
- sub_v3_v3v3(vec, co, state->co);
- rij = normalize_v3(vec);
-
- q = (1.f - rij/h) * pfn->psys->part->mass * inv_mass;
-
- if (pfn->psys->part->flag & PART_SIZEMASS)
- q *= npa->size;
-
- copy_v3_v3(vel, npa->prev_state.vel);
-
- /* Double Density Relaxation */
- madd_v3_v3fl(force, vec, -(pressure + near_pressure*q)*q);
-
- /* Viscosity */
- if (visc > 0.f || stiff_visc > 0.f) {
- sub_v3_v3v3(dv, vel, state->vel);
- u = dot_v3v3(vec, dv);
-
- if (u < 0.f && visc > 0.f)
- madd_v3_v3fl(force, vec, 0.5f * q * visc * u );
-
- if (u > 0.f && stiff_visc > 0.f)
- madd_v3_v3fl(force, vec, 0.5f * q * stiff_visc * u );
- }
-
- if (spring_constant > 0.f) {
- /* Viscoelastic spring force */
- if (pfn->psys == psys[0] && fluid->flag & SPH_VISCOELASTIC_SPRINGS && springhash) {
- /* BLI_edgehash_lookup appears to be thread-safe. - z0r */
- spring_index = POINTER_AS_INT(BLI_edgehash_lookup(springhash, index, pfn->index));
-
- if (spring_index) {
- spring = psys[0]->fluid_springs + spring_index - 1;
-
- madd_v3_v3fl(force, vec, -10.f * spring_constant * (1.f - rij/h) * (spring->rest_length - rij));
- }
- else if (fluid->spring_frames == 0 || (pa->prev_state.time-pa->time) <= fluid->spring_frames) {
- ParticleSpring temp_spring;
- temp_spring.particle_index[0] = index;
- temp_spring.particle_index[1] = pfn->index;
- temp_spring.rest_length = (fluid->flag & SPH_CURRENT_REST_LENGTH) ? rij : rest_length;
- temp_spring.delete_flag = 0;
-
- /* sph_spring_add is not thread-safe. - z0r */
- sph_spring_add(psys[0], &temp_spring);
- }
- }
- else {/* PART_SPRING_HOOKES - Hooke's spring force */
- madd_v3_v3fl(force, vec, -10.f * spring_constant * (1.f - rij/h) * (rest_length - rij));
- }
- }
- }
-
- /* Artificial buoyancy force in negative gravity direction */
- if (fluid->buoyancy > 0.f && gravity)
- madd_v3_v3fl(force, gravity, fluid->buoyancy * (density-rest_density));
-
- if (sphdata->pass == 0 && psys[0]->part->time_flag & PART_TIME_AUTOSF)
- sph_particle_courant(sphdata, &pfr);
- sphdata->pass++;
+ SPHData *sphdata = (SPHData *)sphdata_v;
+ ParticleSystem **psys = sphdata->psys;
+ ParticleData *pa = sphdata->pa;
+ SPHFluidSettings *fluid = psys[0]->part->fluid;
+ ParticleSpring *spring = NULL;
+ SPHRangeData pfr;
+ SPHNeighbor *pfn;
+ float *gravity = sphdata->gravity;
+ EdgeHash *springhash = sphdata->eh;
+
+ float q, u, rij, dv[3];
+ float pressure, near_pressure;
+
+ float visc = fluid->viscosity_omega;
+ float stiff_visc = fluid->viscosity_beta *
+ (fluid->flag & SPH_FAC_VISCOSITY ? fluid->viscosity_omega : 1.f);
+
+ float inv_mass = 1.0f / sphdata->mass;
+ float spring_constant = fluid->spring_k;
+
+ /* 4.0 seems to be a pretty good value */
+ float interaction_radius = fluid->radius *
+ (fluid->flag & SPH_FAC_RADIUS ? 4.0f * pa->size : 1.0f);
+ float h = interaction_radius * sphdata->hfac;
+ /* 4.77 is an experimentally determined density factor */
+ float rest_density = fluid->rest_density * (fluid->flag & SPH_FAC_DENSITY ? 4.77f : 1.f);
+ float rest_length = fluid->rest_length *
+ (fluid->flag & SPH_FAC_REST_LENGTH ? 2.588f * pa->size : 1.f);
+
+ float stiffness = fluid->stiffness_k;
+ float stiffness_near_fac = fluid->stiffness_knear *
+ (fluid->flag & SPH_FAC_REPULSION ? fluid->stiffness_k : 1.f);
+
+ ParticleData *npa;
+ float vec[3];
+ float vel[3];
+ float co[3];
+ float data[2];
+ float density, near_density;
+
+ int i, spring_index, index = pa - psys[0]->particles;
+
+ data[0] = data[1] = 0;
+ pfr.data = data;
+ pfr.h = h;
+ pfr.pa = pa;
+ pfr.mass = sphdata->mass;
+
+ sph_evaluate_func(NULL, psys, state->co, &pfr, interaction_radius, sph_density_accum_cb);
+
+ density = data[0];
+ near_density = data[1];
+
+ pressure = stiffness * (density - rest_density);
+ near_pressure = stiffness_near_fac * near_density;
+
+ pfn = pfr.neighbors;
+ for (i = 0; i < pfr.tot_neighbors; i++, pfn++) {
+ npa = pfn->psys->particles + pfn->index;
+
+ madd_v3_v3v3fl(co, npa->prev_state.co, npa->prev_state.vel, state->time);
+
+ sub_v3_v3v3(vec, co, state->co);
+ rij = normalize_v3(vec);
+
+ q = (1.f - rij / h) * pfn->psys->part->mass * inv_mass;
+
+ if (pfn->psys->part->flag & PART_SIZEMASS)
+ q *= npa->size;
+
+ copy_v3_v3(vel, npa->prev_state.vel);
+
+ /* Double Density Relaxation */
+ madd_v3_v3fl(force, vec, -(pressure + near_pressure * q) * q);
+
+ /* Viscosity */
+ if (visc > 0.f || stiff_visc > 0.f) {
+ sub_v3_v3v3(dv, vel, state->vel);
+ u = dot_v3v3(vec, dv);
+
+ if (u < 0.f && visc > 0.f)
+ madd_v3_v3fl(force, vec, 0.5f * q * visc * u);
+
+ if (u > 0.f && stiff_visc > 0.f)
+ madd_v3_v3fl(force, vec, 0.5f * q * stiff_visc * u);
+ }
+
+ if (spring_constant > 0.f) {
+ /* Viscoelastic spring force */
+ if (pfn->psys == psys[0] && fluid->flag & SPH_VISCOELASTIC_SPRINGS && springhash) {
+ /* BLI_edgehash_lookup appears to be thread-safe. - z0r */
+ spring_index = POINTER_AS_INT(BLI_edgehash_lookup(springhash, index, pfn->index));
+
+ if (spring_index) {
+ spring = psys[0]->fluid_springs + spring_index - 1;
+
+ madd_v3_v3fl(
+ force, vec, -10.f * spring_constant * (1.f - rij / h) * (spring->rest_length - rij));
+ }
+ else if (fluid->spring_frames == 0 ||
+ (pa->prev_state.time - pa->time) <= fluid->spring_frames) {
+ ParticleSpring temp_spring;
+ temp_spring.particle_index[0] = index;
+ temp_spring.particle_index[1] = pfn->index;
+ temp_spring.rest_length = (fluid->flag & SPH_CURRENT_REST_LENGTH) ? rij : rest_length;
+ temp_spring.delete_flag = 0;
+
+ /* sph_spring_add is not thread-safe. - z0r */
+ sph_spring_add(psys[0], &temp_spring);
+ }
+ }
+ else { /* PART_SPRING_HOOKES - Hooke's spring force */
+ madd_v3_v3fl(force, vec, -10.f * spring_constant * (1.f - rij / h) * (rest_length - rij));
+ }
+ }
+ }
+
+ /* Artificial buoyancy force in negative gravity direction */
+ if (fluid->buoyancy > 0.f && gravity)
+ madd_v3_v3fl(force, gravity, fluid->buoyancy * (density - rest_density));
+
+ if (sphdata->pass == 0 && psys[0]->part->time_flag & PART_TIME_AUTOSF)
+ sph_particle_courant(sphdata, &pfr);
+ sphdata->pass++;
}
-static void sphclassical_density_accum_cb(void *userdata, int index, const float co[3], float UNUSED(squared_dist))
+static void sphclassical_density_accum_cb(void *userdata,
+ int index,
+ const float co[3],
+ float UNUSED(squared_dist))
{
- SPHRangeData *pfr = (SPHRangeData *)userdata;
- ParticleData *npa = pfr->npsys->particles + index;
- float q;
- float qfac = 21.0f / (256.f * (float)M_PI);
- float rij, rij_h;
- float vec[3];
-
- /* Exclude particles that are more than 2h away. Can't use squared_dist here
- * because it is not accurate enough. Use current state, i.e. the output of
- * basic_integrate() - z0r */
- sub_v3_v3v3(vec, npa->state.co, co);
- rij = len_v3(vec);
- rij_h = rij / pfr->h;
- if (rij_h > 2.0f)
- return;
-
- /* Smoothing factor. Utilise the Wendland kernel. gnuplot:
- * q1(x) = (2.0 - x)**4 * ( 1.0 + 2.0 * x)
- * plot [0:2] q1(x) */
- q = qfac / pow3f(pfr->h) * pow4f(2.0f - rij_h) * ( 1.0f + 2.0f * rij_h);
- q *= pfr->npsys->part->mass;
-
- if (pfr->use_size)
- q *= pfr->pa->size;
-
- pfr->data[0] += q;
- pfr->data[1] += q / npa->sphdensity;
+ SPHRangeData *pfr = (SPHRangeData *)userdata;
+ ParticleData *npa = pfr->npsys->particles + index;
+ float q;
+ float qfac = 21.0f / (256.f * (float)M_PI);
+ float rij, rij_h;
+ float vec[3];
+
+ /* Exclude particles that are more than 2h away. Can't use squared_dist here
+ * because it is not accurate enough. Use current state, i.e. the output of
+ * basic_integrate() - z0r */
+ sub_v3_v3v3(vec, npa->state.co, co);
+ rij = len_v3(vec);
+ rij_h = rij / pfr->h;
+ if (rij_h > 2.0f)
+ return;
+
+ /* Smoothing factor. Utilise the Wendland kernel. gnuplot:
+ * q1(x) = (2.0 - x)**4 * ( 1.0 + 2.0 * x)
+ * plot [0:2] q1(x) */
+ q = qfac / pow3f(pfr->h) * pow4f(2.0f - rij_h) * (1.0f + 2.0f * rij_h);
+ q *= pfr->npsys->part->mass;
+
+ if (pfr->use_size)
+ q *= pfr->pa->size;
+
+ pfr->data[0] += q;
+ pfr->data[1] += q / npa->sphdensity;
}
-static void sphclassical_neighbour_accum_cb(void *userdata, int index, const float co[3], float UNUSED(squared_dist))
+static void sphclassical_neighbour_accum_cb(void *userdata,
+ int index,
+ const float co[3],
+ float UNUSED(squared_dist))
{
- SPHRangeData *pfr = (SPHRangeData *)userdata;
- ParticleData *npa = pfr->npsys->particles + index;
- float rij, rij_h;
- float vec[3];
-
- if (pfr->tot_neighbors >= SPH_NEIGHBORS)
- return;
-
- /* Exclude particles that are more than 2h away. Can't use squared_dist here
- * because it is not accurate enough. Use current state, i.e. the output of
- * basic_integrate() - z0r */
- sub_v3_v3v3(vec, npa->state.co, co);
- rij = len_v3(vec);
- rij_h = rij / pfr->h;
- if (rij_h > 2.0f)
- return;
-
- pfr->neighbors[pfr->tot_neighbors].index = index;
- pfr->neighbors[pfr->tot_neighbors].psys = pfr->npsys;
- pfr->tot_neighbors++;
+ SPHRangeData *pfr = (SPHRangeData *)userdata;
+ ParticleData *npa = pfr->npsys->particles + index;
+ float rij, rij_h;
+ float vec[3];
+
+ if (pfr->tot_neighbors >= SPH_NEIGHBORS)
+ return;
+
+ /* Exclude particles that are more than 2h away. Can't use squared_dist here
+ * because it is not accurate enough. Use current state, i.e. the output of
+ * basic_integrate() - z0r */
+ sub_v3_v3v3(vec, npa->state.co, co);
+ rij = len_v3(vec);
+ rij_h = rij / pfr->h;
+ if (rij_h > 2.0f)
+ return;
+
+ pfr->neighbors[pfr->tot_neighbors].index = index;
+ pfr->neighbors[pfr->tot_neighbors].psys = pfr->npsys;
+ pfr->tot_neighbors++;
}
-static void sphclassical_force_cb(void *sphdata_v, ParticleKey *state, float *force, float *UNUSED(impulse))
+static void sphclassical_force_cb(void *sphdata_v,
+ ParticleKey *state,
+ float *force,
+ float *UNUSED(impulse))
{
- SPHData *sphdata = (SPHData *)sphdata_v;
- ParticleSystem **psys = sphdata->psys;
- ParticleData *pa = sphdata->pa;
- SPHFluidSettings *fluid = psys[0]->part->fluid;
- SPHRangeData pfr;
- SPHNeighbor *pfn;
- float *gravity = sphdata->gravity;
-
- float dq, u, rij, dv[3];
- float pressure, npressure;
-
- float visc = fluid->viscosity_omega;
-
- float interaction_radius;
- float h, hinv;
- /* 4.77 is an experimentally determined density factor */
- float rest_density = fluid->rest_density * (fluid->flag & SPH_FAC_DENSITY ? 4.77f : 1.0f);
-
- // Use speed of sound squared
- float stiffness = pow2f(fluid->stiffness_k);
-
- ParticleData *npa;
- float vec[3];
- float co[3];
- float pressureTerm;
-
- int i;
-
- float qfac2 = 42.0f / (256.0f * (float)M_PI);
- float rij_h;
-
- /* 4.0 here is to be consistent with previous formulation/interface */
- interaction_radius = fluid->radius * (fluid->flag & SPH_FAC_RADIUS ? 4.0f * pa->size : 1.0f);
- h = interaction_radius * sphdata->hfac;
- hinv = 1.0f / h;
-
- pfr.h = h;
- pfr.pa = pa;
-
- sph_evaluate_func(NULL, psys, state->co, &pfr, interaction_radius, sphclassical_neighbour_accum_cb);
- pressure = stiffness * (pow7f(pa->sphdensity / rest_density) - 1.0f);
-
- /* multiply by mass so that we return a force, not accel */
- qfac2 *= sphdata->mass / pow3f(pfr.h);
-
- pfn = pfr.neighbors;
- for (i = 0; i < pfr.tot_neighbors; i++, pfn++) {
- npa = pfn->psys->particles + pfn->index;
- if (npa == pa) {
- /* we do not contribute to ourselves */
- continue;
- }
-
- /* Find vector to neighbor. Exclude particles that are more than 2h
- * away. Can't use current state here because it may have changed on
- * another thread - so do own mini integration. Unlike basic_integrate,
- * SPH integration depends on neighboring particles. - z0r */
- madd_v3_v3v3fl(co, npa->prev_state.co, npa->prev_state.vel, state->time);
- sub_v3_v3v3(vec, co, state->co);
- rij = normalize_v3(vec);
- rij_h = rij / pfr.h;
- if (rij_h > 2.0f)
- continue;
-
- npressure = stiffness * (pow7f(npa->sphdensity / rest_density) - 1.0f);
-
- /* First derivative of smoothing factor. Utilise the Wendland kernel.
- * gnuplot:
- * q2(x) = 2.0 * (2.0 - x)**4 - 4.0 * (2.0 - x)**3 * (1.0 + 2.0 * x)
- * plot [0:2] q2(x)
- * Particles > 2h away are excluded above. */
- dq = qfac2 * (2.0f * pow4f(2.0f - rij_h) - 4.0f * pow3f(2.0f - rij_h) * (1.0f + 2.0f * rij_h) );
-
- if (pfn->psys->part->flag & PART_SIZEMASS)
- dq *= npa->size;
-
- pressureTerm = pressure / pow2f(pa->sphdensity) + npressure / pow2f(npa->sphdensity);
-
- /* Note that 'minus' is removed, because vec = vecBA, not vecAB.
- * This applies to the viscosity calculation below, too. */
- madd_v3_v3fl(force, vec, pressureTerm * dq);
-
- /* Viscosity */
- if (visc > 0.0f) {
- sub_v3_v3v3(dv, npa->prev_state.vel, pa->prev_state.vel);
- u = dot_v3v3(vec, dv);
- /* Apply parameters */
- u *= -dq * hinv * visc / (0.5f * npa->sphdensity + 0.5f * pa->sphdensity);
- madd_v3_v3fl(force, vec, u);
- }
- }
-
- /* Artificial buoyancy force in negative gravity direction */
- if (fluid->buoyancy > 0.f && gravity)
- madd_v3_v3fl(force, gravity, fluid->buoyancy * (pa->sphdensity - rest_density));
-
- if (sphdata->pass == 0 && psys[0]->part->time_flag & PART_TIME_AUTOSF)
- sph_particle_courant(sphdata, &pfr);
- sphdata->pass++;
+ SPHData *sphdata = (SPHData *)sphdata_v;
+ ParticleSystem **psys = sphdata->psys;
+ ParticleData *pa = sphdata->pa;
+ SPHFluidSettings *fluid = psys[0]->part->fluid;
+ SPHRangeData pfr;
+ SPHNeighbor *pfn;
+ float *gravity = sphdata->gravity;
+
+ float dq, u, rij, dv[3];
+ float pressure, npressure;
+
+ float visc = fluid->viscosity_omega;
+
+ float interaction_radius;
+ float h, hinv;
+ /* 4.77 is an experimentally determined density factor */
+ float rest_density = fluid->rest_density * (fluid->flag & SPH_FAC_DENSITY ? 4.77f : 1.0f);
+
+ // Use speed of sound squared
+ float stiffness = pow2f(fluid->stiffness_k);
+
+ ParticleData *npa;
+ float vec[3];
+ float co[3];
+ float pressureTerm;
+
+ int i;
+
+ float qfac2 = 42.0f / (256.0f * (float)M_PI);
+ float rij_h;
+
+ /* 4.0 here is to be consistent with previous formulation/interface */
+ interaction_radius = fluid->radius * (fluid->flag & SPH_FAC_RADIUS ? 4.0f * pa->size : 1.0f);
+ h = interaction_radius * sphdata->hfac;
+ hinv = 1.0f / h;
+
+ pfr.h = h;
+ pfr.pa = pa;
+
+ sph_evaluate_func(
+ NULL, psys, state->co, &pfr, interaction_radius, sphclassical_neighbour_accum_cb);
+ pressure = stiffness * (pow7f(pa->sphdensity / rest_density) - 1.0f);
+
+ /* multiply by mass so that we return a force, not accel */
+ qfac2 *= sphdata->mass / pow3f(pfr.h);
+
+ pfn = pfr.neighbors;
+ for (i = 0; i < pfr.tot_neighbors; i++, pfn++) {
+ npa = pfn->psys->particles + pfn->index;
+ if (npa == pa) {
+ /* we do not contribute to ourselves */
+ continue;
+ }
+
+ /* Find vector to neighbor. Exclude particles that are more than 2h
+ * away. Can't use current state here because it may have changed on
+ * another thread - so do own mini integration. Unlike basic_integrate,
+ * SPH integration depends on neighboring particles. - z0r */
+ madd_v3_v3v3fl(co, npa->prev_state.co, npa->prev_state.vel, state->time);
+ sub_v3_v3v3(vec, co, state->co);
+ rij = normalize_v3(vec);
+ rij_h = rij / pfr.h;
+ if (rij_h > 2.0f)
+ continue;
+
+ npressure = stiffness * (pow7f(npa->sphdensity / rest_density) - 1.0f);
+
+ /* First derivative of smoothing factor. Utilise the Wendland kernel.
+ * gnuplot:
+ * q2(x) = 2.0 * (2.0 - x)**4 - 4.0 * (2.0 - x)**3 * (1.0 + 2.0 * x)
+ * plot [0:2] q2(x)
+ * Particles > 2h away are excluded above. */
+ dq = qfac2 * (2.0f * pow4f(2.0f - rij_h) - 4.0f * pow3f(2.0f - rij_h) * (1.0f + 2.0f * rij_h));
+
+ if (pfn->psys->part->flag & PART_SIZEMASS)
+ dq *= npa->size;
+
+ pressureTerm = pressure / pow2f(pa->sphdensity) + npressure / pow2f(npa->sphdensity);
+
+ /* Note that 'minus' is removed, because vec = vecBA, not vecAB.
+ * This applies to the viscosity calculation below, too. */
+ madd_v3_v3fl(force, vec, pressureTerm * dq);
+
+ /* Viscosity */
+ if (visc > 0.0f) {
+ sub_v3_v3v3(dv, npa->prev_state.vel, pa->prev_state.vel);
+ u = dot_v3v3(vec, dv);
+ /* Apply parameters */
+ u *= -dq * hinv * visc / (0.5f * npa->sphdensity + 0.5f * pa->sphdensity);
+ madd_v3_v3fl(force, vec, u);
+ }
+ }
+
+ /* Artificial buoyancy force in negative gravity direction */
+ if (fluid->buoyancy > 0.f && gravity)
+ madd_v3_v3fl(force, gravity, fluid->buoyancy * (pa->sphdensity - rest_density));
+
+ if (sphdata->pass == 0 && psys[0]->part->time_flag & PART_TIME_AUTOSF)
+ sph_particle_courant(sphdata, &pfr);
+ sphdata->pass++;
}
static void sphclassical_calc_dens(ParticleData *pa, float UNUSED(dfra), SPHData *sphdata)
{
- ParticleSystem **psys = sphdata->psys;
- SPHFluidSettings *fluid = psys[0]->part->fluid;
- /* 4.0 seems to be a pretty good value */
- float interaction_radius = fluid->radius * (fluid->flag & SPH_FAC_RADIUS ? 4.0f * psys[0]->part->size : 1.0f);
- SPHRangeData pfr;
- float data[2];
-
- data[0] = 0;
- data[1] = 0;
- pfr.data = data;
- pfr.h = interaction_radius * sphdata->hfac;
- pfr.pa = pa;
- pfr.mass = sphdata->mass;
-
- sph_evaluate_func( NULL, psys, pa->state.co, &pfr, interaction_radius, sphclassical_density_accum_cb);
- pa->sphdensity = min_ff(max_ff(data[0], fluid->rest_density * 0.9f), fluid->rest_density * 1.1f);
+ ParticleSystem **psys = sphdata->psys;
+ SPHFluidSettings *fluid = psys[0]->part->fluid;
+ /* 4.0 seems to be a pretty good value */
+ float interaction_radius = fluid->radius *
+ (fluid->flag & SPH_FAC_RADIUS ? 4.0f * psys[0]->part->size : 1.0f);
+ SPHRangeData pfr;
+ float data[2];
+
+ data[0] = 0;
+ data[1] = 0;
+ pfr.data = data;
+ pfr.h = interaction_radius * sphdata->hfac;
+ pfr.pa = pa;
+ pfr.mass = sphdata->mass;
+
+ sph_evaluate_func(
+ NULL, psys, pa->state.co, &pfr, interaction_radius, sphclassical_density_accum_cb);
+ pa->sphdensity = min_ff(max_ff(data[0], fluid->rest_density * 0.9f), fluid->rest_density * 1.1f);
}
void psys_sph_init(ParticleSimulationData *sim, SPHData *sphdata)
{
- ParticleTarget *pt;
- int i;
-
- // Add other coupled particle systems.
- sphdata->psys[0] = sim->psys;
- for (i=1, pt=sim->psys->targets.first; i<10; i++, pt=(pt?pt->next:NULL))
- sphdata->psys[i] = pt ? psys_get_target_system(sim->ob, pt) : NULL;
-
- if (psys_uses_gravity(sim))
- sphdata->gravity = sim->scene->physics_settings.gravity;
- else
- sphdata->gravity = NULL;
- sphdata->eh = sph_springhash_build(sim->psys);
-
- // These per-particle values should be overridden later, but just for
- // completeness we give them default values now.
- sphdata->pa = NULL;
- sphdata->mass = 1.0f;
-
- if (sim->psys->part->fluid->solver == SPH_SOLVER_DDR) {
- sphdata->force_cb = sph_force_cb;
- sphdata->density_cb = sph_density_accum_cb;
- sphdata->hfac = 1.0f;
- }
- else {
- /* SPH_SOLVER_CLASSICAL */
- sphdata->force_cb = sphclassical_force_cb;
- sphdata->density_cb = sphclassical_density_accum_cb;
- sphdata->hfac = 0.5f;
- }
-
+ ParticleTarget *pt;
+ int i;
+
+ // Add other coupled particle systems.
+ sphdata->psys[0] = sim->psys;
+ for (i = 1, pt = sim->psys->targets.first; i < 10; i++, pt = (pt ? pt->next : NULL))
+ sphdata->psys[i] = pt ? psys_get_target_system(sim->ob, pt) : NULL;
+
+ if (psys_uses_gravity(sim))
+ sphdata->gravity = sim->scene->physics_settings.gravity;
+ else
+ sphdata->gravity = NULL;
+ sphdata->eh = sph_springhash_build(sim->psys);
+
+ // These per-particle values should be overridden later, but just for
+ // completeness we give them default values now.
+ sphdata->pa = NULL;
+ sphdata->mass = 1.0f;
+
+ if (sim->psys->part->fluid->solver == SPH_SOLVER_DDR) {
+ sphdata->force_cb = sph_force_cb;
+ sphdata->density_cb = sph_density_accum_cb;
+ sphdata->hfac = 1.0f;
+ }
+ else {
+ /* SPH_SOLVER_CLASSICAL */
+ sphdata->force_cb = sphclassical_force_cb;
+ sphdata->density_cb = sphclassical_density_accum_cb;
+ sphdata->hfac = 0.5f;
+ }
}
void psys_sph_finalise(SPHData *sphdata)
{
- if (sphdata->eh) {
- BLI_edgehash_free(sphdata->eh, NULL);
- sphdata->eh = NULL;
- }
+ if (sphdata->eh) {
+ BLI_edgehash_free(sphdata->eh, NULL);
+ sphdata->eh = NULL;
+ }
}
/* Sample the density field at a point in space. */
void psys_sph_density(BVHTree *tree, SPHData *sphdata, float co[3], float vars[2])
{
- ParticleSystem **psys = sphdata->psys;
- SPHFluidSettings *fluid = psys[0]->part->fluid;
- /* 4.0 seems to be a pretty good value */
- float interaction_radius = fluid->radius * (fluid->flag & SPH_FAC_RADIUS ? 4.0f * psys[0]->part->size : 1.0f);
- SPHRangeData pfr;
- float density[2];
-
- density[0] = density[1] = 0.0f;
- pfr.data = density;
- pfr.h = interaction_radius * sphdata->hfac;
- pfr.mass = sphdata->mass;
-
- sph_evaluate_func(tree, psys, co, &pfr, interaction_radius, sphdata->density_cb);
-
- vars[0] = pfr.data[0];
- vars[1] = pfr.data[1];
+ ParticleSystem **psys = sphdata->psys;
+ SPHFluidSettings *fluid = psys[0]->part->fluid;
+ /* 4.0 seems to be a pretty good value */
+ float interaction_radius = fluid->radius *
+ (fluid->flag & SPH_FAC_RADIUS ? 4.0f * psys[0]->part->size : 1.0f);
+ SPHRangeData pfr;
+ float density[2];
+
+ density[0] = density[1] = 0.0f;
+ pfr.data = density;
+ pfr.h = interaction_radius * sphdata->hfac;
+ pfr.mass = sphdata->mass;
+
+ sph_evaluate_func(tree, psys, co, &pfr, interaction_radius, sphdata->density_cb);
+
+ vars[0] = pfr.data[0];
+ vars[1] = pfr.data[1];
}
-static void sph_integrate(ParticleSimulationData *sim, ParticleData *pa, float dfra, SPHData *sphdata)
+static void sph_integrate(ParticleSimulationData *sim,
+ ParticleData *pa,
+ float dfra,
+ SPHData *sphdata)
{
- ParticleSettings *part = sim->psys->part;
- // float timestep = psys_get_timestep(sim); // UNUSED
- float pa_mass = part->mass * (part->flag & PART_SIZEMASS ? pa->size : 1.f);
- float dtime = dfra*psys_get_timestep(sim);
- // int steps = 1; // UNUSED
- float effector_acceleration[3];
+ ParticleSettings *part = sim->psys->part;
+ // float timestep = psys_get_timestep(sim); // UNUSED
+ float pa_mass = part->mass * (part->flag & PART_SIZEMASS ? pa->size : 1.f);
+ float dtime = dfra * psys_get_timestep(sim);
+ // int steps = 1; // UNUSED
+ float effector_acceleration[3];
- sphdata->pa = pa;
- sphdata->mass = pa_mass;
- sphdata->pass = 0;
- //sphdata.element_size and sphdata.flow are set in the callback.
+ sphdata->pa = pa;
+ sphdata->mass = pa_mass;
+ sphdata->pass = 0;
+ //sphdata.element_size and sphdata.flow are set in the callback.
- /* restore previous state and treat gravity & effectors as external acceleration*/
- sub_v3_v3v3(effector_acceleration, pa->state.vel, pa->prev_state.vel);
- mul_v3_fl(effector_acceleration, 1.f/dtime);
+ /* restore previous state and treat gravity & effectors as external acceleration*/
+ sub_v3_v3v3(effector_acceleration, pa->state.vel, pa->prev_state.vel);
+ mul_v3_fl(effector_acceleration, 1.f / dtime);
- copy_particle_key(&pa->state, &pa->prev_state, 0);
+ copy_particle_key(&pa->state, &pa->prev_state, 0);
- integrate_particle(part, pa, dtime, effector_acceleration, sphdata->force_cb, sphdata);
+ integrate_particle(part, pa, dtime, effector_acceleration, sphdata->force_cb, sphdata);
}
/************************************************/
-/* Basic physics */
+/* Basic physics */
/************************************************/
typedef struct EfData {
- ParticleTexture ptex;
- ParticleSimulationData *sim;
- ParticleData *pa;
+ ParticleTexture ptex;
+ ParticleSimulationData *sim;
+ ParticleData *pa;
} EfData;
static void basic_force_cb(void *efdata_v, ParticleKey *state, float *force, float *impulse)
{
- EfData *efdata = (EfData *)efdata_v;
- ParticleSimulationData *sim = efdata->sim;
- ParticleSettings *part = sim->psys->part;
- ParticleData *pa = efdata->pa;
- EffectedPoint epoint;
- RNG *rng = sim->rng;
-
- /* add effectors */
- pd_point_from_particle(efdata->sim, efdata->pa, state, &epoint);
- if (part->type != PART_HAIR || part->effector_weights->flag & EFF_WEIGHT_DO_HAIR)
- BKE_effectors_apply(sim->psys->effectors, sim->colliders, part->effector_weights, &epoint, force, impulse);
-
- mul_v3_fl(force, efdata->ptex.field);
- mul_v3_fl(impulse, efdata->ptex.field);
-
- /* calculate air-particle interaction */
- if (part->dragfac != 0.0f)
- madd_v3_v3fl(force, state->vel, -part->dragfac * pa->size * pa->size * len_v3(state->vel));
-
- /* brownian force */
- if (part->brownfac != 0.0f) {
- force[0] += (BLI_rng_get_float(rng)-0.5f) * part->brownfac;
- force[1] += (BLI_rng_get_float(rng)-0.5f) * part->brownfac;
- force[2] += (BLI_rng_get_float(rng)-0.5f) * part->brownfac;
- }
-
- if (part->flag & PART_ROT_DYN && epoint.ave)
- copy_v3_v3(pa->state.ave, epoint.ave);
+ EfData *efdata = (EfData *)efdata_v;
+ ParticleSimulationData *sim = efdata->sim;
+ ParticleSettings *part = sim->psys->part;
+ ParticleData *pa = efdata->pa;
+ EffectedPoint epoint;
+ RNG *rng = sim->rng;
+
+ /* add effectors */
+ pd_point_from_particle(efdata->sim, efdata->pa, state, &epoint);
+ if (part->type != PART_HAIR || part->effector_weights->flag & EFF_WEIGHT_DO_HAIR)
+ BKE_effectors_apply(
+ sim->psys->effectors, sim->colliders, part->effector_weights, &epoint, force, impulse);
+
+ mul_v3_fl(force, efdata->ptex.field);
+ mul_v3_fl(impulse, efdata->ptex.field);
+
+ /* calculate air-particle interaction */
+ if (part->dragfac != 0.0f)
+ madd_v3_v3fl(force, state->vel, -part->dragfac * pa->size * pa->size * len_v3(state->vel));
+
+ /* brownian force */
+ if (part->brownfac != 0.0f) {
+ force[0] += (BLI_rng_get_float(rng) - 0.5f) * part->brownfac;
+ force[1] += (BLI_rng_get_float(rng) - 0.5f) * part->brownfac;
+ force[2] += (BLI_rng_get_float(rng) - 0.5f) * part->brownfac;
+ }
+
+ if (part->flag & PART_ROT_DYN && epoint.ave)
+ copy_v3_v3(pa->state.ave, epoint.ave);
}
/* gathers all forces that effect particles and calculates a new state for the particle */
static void basic_integrate(ParticleSimulationData *sim, int p, float dfra, float cfra)
{
- ParticleSettings *part = sim->psys->part;
- ParticleData *pa = sim->psys->particles + p;
- ParticleKey tkey;
- float dtime=dfra*psys_get_timestep(sim), time;
- float *gravity = NULL, gr[3];
- EfData efdata;
-
- psys_get_texture(sim, pa, &efdata.ptex, PAMAP_PHYSICS, cfra);
-
- efdata.pa = pa;
- efdata.sim = sim;
-
- /* add global acceleration (gravitation) */
- if (psys_uses_gravity(sim) &&
- /* normal gravity is too strong for hair so it's disabled by default */
- (part->type != PART_HAIR || part->effector_weights->flag & EFF_WEIGHT_DO_HAIR))
- {
- zero_v3(gr);
- madd_v3_v3fl(gr, sim->scene->physics_settings.gravity, part->effector_weights->global_gravity * efdata.ptex.gravity);
- gravity = gr;
- }
-
- /* maintain angular velocity */
- copy_v3_v3(pa->state.ave, pa->prev_state.ave);
-
- integrate_particle(part, pa, dtime, gravity, basic_force_cb, &efdata);
-
- /* damp affects final velocity */
- if (part->dampfac != 0.f)
- mul_v3_fl(pa->state.vel, 1.f - part->dampfac * efdata.ptex.damp * 25.f * dtime);
-
- //copy_v3_v3(pa->state.ave, states->ave);
-
- /* finally we do guides */
- time=(cfra-pa->time)/pa->lifetime;
- CLAMP(time, 0.0f, 1.0f);
-
- copy_v3_v3(tkey.co,pa->state.co);
- copy_v3_v3(tkey.vel,pa->state.vel);
- tkey.time=pa->state.time;
-
- if (part->type != PART_HAIR) {
- if (do_guides(sim->depsgraph, sim->psys->part, sim->psys->effectors, &tkey, p, time)) {
- copy_v3_v3(pa->state.co,tkey.co);
- /* guides don't produce valid velocity */
- sub_v3_v3v3(pa->state.vel, tkey.co, pa->prev_state.co);
- mul_v3_fl(pa->state.vel,1.0f/dtime);
- pa->state.time=tkey.time;
- }
- }
+ ParticleSettings *part = sim->psys->part;
+ ParticleData *pa = sim->psys->particles + p;
+ ParticleKey tkey;
+ float dtime = dfra * psys_get_timestep(sim), time;
+ float *gravity = NULL, gr[3];
+ EfData efdata;
+
+ psys_get_texture(sim, pa, &efdata.ptex, PAMAP_PHYSICS, cfra);
+
+ efdata.pa = pa;
+ efdata.sim = sim;
+
+ /* add global acceleration (gravitation) */
+ if (psys_uses_gravity(sim) &&
+ /* normal gravity is too strong for hair so it's disabled by default */
+ (part->type != PART_HAIR || part->effector_weights->flag & EFF_WEIGHT_DO_HAIR)) {
+ zero_v3(gr);
+ madd_v3_v3fl(gr,
+ sim->scene->physics_settings.gravity,
+ part->effector_weights->global_gravity * efdata.ptex.gravity);
+ gravity = gr;
+ }
+
+ /* maintain angular velocity */
+ copy_v3_v3(pa->state.ave, pa->prev_state.ave);
+
+ integrate_particle(part, pa, dtime, gravity, basic_force_cb, &efdata);
+
+ /* damp affects final velocity */
+ if (part->dampfac != 0.f)
+ mul_v3_fl(pa->state.vel, 1.f - part->dampfac * efdata.ptex.damp * 25.f * dtime);
+
+ //copy_v3_v3(pa->state.ave, states->ave);
+
+ /* finally we do guides */
+ time = (cfra - pa->time) / pa->lifetime;
+ CLAMP(time, 0.0f, 1.0f);
+
+ copy_v3_v3(tkey.co, pa->state.co);
+ copy_v3_v3(tkey.vel, pa->state.vel);
+ tkey.time = pa->state.time;
+
+ if (part->type != PART_HAIR) {
+ if (do_guides(sim->depsgraph, sim->psys->part, sim->psys->effectors, &tkey, p, time)) {
+ copy_v3_v3(pa->state.co, tkey.co);
+ /* guides don't produce valid velocity */
+ sub_v3_v3v3(pa->state.vel, tkey.co, pa->prev_state.co);
+ mul_v3_fl(pa->state.vel, 1.0f / dtime);
+ pa->state.time = tkey.time;
+ }
+ }
}
static void basic_rotate(ParticleSettings *part, ParticleData *pa, float dfra, float timestep)
{
- float rotfac, rot1[4], rot2[4] = {1.0,0.0,0.0,0.0}, dtime=dfra*timestep, extrotfac;
-
- if ((part->flag & PART_ROTATIONS) == 0) {
- unit_qt(pa->state.rot);
- return;
- }
-
- if (part->flag & PART_ROT_DYN) {
- extrotfac = len_v3(pa->state.ave);
- }
- else {
- extrotfac = 0.0f;
- }
-
- if ((part->flag & PART_ROT_DYN) && ELEM(part->avemode, PART_AVE_VELOCITY, PART_AVE_HORIZONTAL, PART_AVE_VERTICAL)) {
- float angle;
- float len1 = len_v3(pa->prev_state.vel);
- float len2 = len_v3(pa->state.vel);
- float vec[3];
-
- if (len1 == 0.0f || len2 == 0.0f) {
- zero_v3(pa->state.ave);
- }
- else {
- cross_v3_v3v3(pa->state.ave, pa->prev_state.vel, pa->state.vel);
- normalize_v3(pa->state.ave);
- angle = dot_v3v3(pa->prev_state.vel, pa->state.vel) / (len1 * len2);
- mul_v3_fl(pa->state.ave, saacos(angle) / dtime);
- }
-
- get_angular_velocity_vector(part->avemode, &pa->state, vec);
- axis_angle_to_quat(rot2, vec, dtime*part->avefac);
- }
-
- rotfac = len_v3(pa->state.ave);
- if (rotfac == 0.0f || (part->flag & PART_ROT_DYN)==0 || extrotfac == 0.0f) {
- unit_qt(rot1);
- }
- else {
- axis_angle_to_quat(rot1,pa->state.ave,rotfac*dtime);
- }
- mul_qt_qtqt(pa->state.rot,rot1,pa->prev_state.rot);
- mul_qt_qtqt(pa->state.rot,rot2,pa->state.rot);
-
- /* keep rotation quat in good health */
- normalize_qt(pa->state.rot);
+ float rotfac, rot1[4], rot2[4] = {1.0, 0.0, 0.0, 0.0}, dtime = dfra * timestep, extrotfac;
+
+ if ((part->flag & PART_ROTATIONS) == 0) {
+ unit_qt(pa->state.rot);
+ return;
+ }
+
+ if (part->flag & PART_ROT_DYN) {
+ extrotfac = len_v3(pa->state.ave);
+ }
+ else {
+ extrotfac = 0.0f;
+ }
+
+ if ((part->flag & PART_ROT_DYN) &&
+ ELEM(part->avemode, PART_AVE_VELOCITY, PART_AVE_HORIZONTAL, PART_AVE_VERTICAL)) {
+ float angle;
+ float len1 = len_v3(pa->prev_state.vel);
+ float len2 = len_v3(pa->state.vel);
+ float vec[3];
+
+ if (len1 == 0.0f || len2 == 0.0f) {
+ zero_v3(pa->state.ave);
+ }
+ else {
+ cross_v3_v3v3(pa->state.ave, pa->prev_state.vel, pa->state.vel);
+ normalize_v3(pa->state.ave);
+ angle = dot_v3v3(pa->prev_state.vel, pa->state.vel) / (len1 * len2);
+ mul_v3_fl(pa->state.ave, saacos(angle) / dtime);
+ }
+
+ get_angular_velocity_vector(part->avemode, &pa->state, vec);
+ axis_angle_to_quat(rot2, vec, dtime * part->avefac);
+ }
+
+ rotfac = len_v3(pa->state.ave);
+ if (rotfac == 0.0f || (part->flag & PART_ROT_DYN) == 0 || extrotfac == 0.0f) {
+ unit_qt(rot1);
+ }
+ else {
+ axis_angle_to_quat(rot1, pa->state.ave, rotfac * dtime);
+ }
+ mul_qt_qtqt(pa->state.rot, rot1, pa->prev_state.rot);
+ mul_qt_qtqt(pa->state.rot, rot2, pa->state.rot);
+
+ /* keep rotation quat in good health */
+ normalize_qt(pa->state.rot);
}
/************************************************
@@ -2198,652 +2275,690 @@ static void basic_rotate(ParticleSettings *part, ParticleData *pa, float dfra, f
#define COLLISION_ZERO 0.00001f
#define COLLISION_INIT_STEP 0.00008f
typedef float (*NRDistanceFunc)(float *p, float radius, ParticleCollisionElement *pce, float *nor);
-static float nr_signed_distance_to_plane(float *p, float radius, ParticleCollisionElement *pce, float *nor)
+static float nr_signed_distance_to_plane(float *p,
+ float radius,
+ ParticleCollisionElement *pce,
+ float *nor)
{
- float p0[3], e1[3], e2[3], d;
+ float p0[3], e1[3], e2[3], d;
- sub_v3_v3v3(e1, pce->x1, pce->x0);
- sub_v3_v3v3(e2, pce->x2, pce->x0);
- sub_v3_v3v3(p0, p, pce->x0);
+ sub_v3_v3v3(e1, pce->x1, pce->x0);
+ sub_v3_v3v3(e2, pce->x2, pce->x0);
+ sub_v3_v3v3(p0, p, pce->x0);
- cross_v3_v3v3(nor, e1, e2);
- normalize_v3(nor);
+ cross_v3_v3v3(nor, e1, e2);
+ normalize_v3(nor);
- d = dot_v3v3(p0, nor);
+ d = dot_v3v3(p0, nor);
- if (pce->inv_nor == -1) {
- if (d < 0.f)
- pce->inv_nor = 1;
- else
- pce->inv_nor = 0;
- }
+ if (pce->inv_nor == -1) {
+ if (d < 0.f)
+ pce->inv_nor = 1;
+ else
+ pce->inv_nor = 0;
+ }
- if (pce->inv_nor == 1) {
- negate_v3(nor);
- d = -d;
- }
+ if (pce->inv_nor == 1) {
+ negate_v3(nor);
+ d = -d;
+ }
- return d - radius;
+ return d - radius;
}
-static float nr_distance_to_edge(float *p, float radius, ParticleCollisionElement *pce, float *UNUSED(nor))
+static float nr_distance_to_edge(float *p,
+ float radius,
+ ParticleCollisionElement *pce,
+ float *UNUSED(nor))
{
- float v0[3], v1[3], v2[3], c[3];
+ float v0[3], v1[3], v2[3], c[3];
- sub_v3_v3v3(v0, pce->x1, pce->x0);
- sub_v3_v3v3(v1, p, pce->x0);
- sub_v3_v3v3(v2, p, pce->x1);
+ sub_v3_v3v3(v0, pce->x1, pce->x0);
+ sub_v3_v3v3(v1, p, pce->x0);
+ sub_v3_v3v3(v2, p, pce->x1);
- cross_v3_v3v3(c, v1, v2);
+ cross_v3_v3v3(c, v1, v2);
- return fabsf(len_v3(c)/len_v3(v0)) - radius;
+ return fabsf(len_v3(c) / len_v3(v0)) - radius;
}
-static float nr_distance_to_vert(float *p, float radius, ParticleCollisionElement *pce, float *UNUSED(nor))
+static float nr_distance_to_vert(float *p,
+ float radius,
+ ParticleCollisionElement *pce,
+ float *UNUSED(nor))
{
- return len_v3v3(p, pce->x0) - radius;
+ return len_v3v3(p, pce->x0) - radius;
}
-static void collision_interpolate_element(ParticleCollisionElement *pce, float t, float fac, ParticleCollision *col)
+static void collision_interpolate_element(ParticleCollisionElement *pce,
+ float t,
+ float fac,
+ ParticleCollision *col)
{
- /* t is the current time for newton rhapson */
- /* fac is the starting factor for current collision iteration */
- /* the col->fac's are factors for the particle subframe step start and end during collision modifier step */
- float f = fac + t*(1.f-fac);
- float mul = col->fac1 + f * (col->fac2-col->fac1);
- if (pce->tot > 0) {
- madd_v3_v3v3fl(pce->x0, pce->x[0], pce->v[0], mul);
-
- if (pce->tot > 1) {
- madd_v3_v3v3fl(pce->x1, pce->x[1], pce->v[1], mul);
-
- if (pce->tot > 2)
- madd_v3_v3v3fl(pce->x2, pce->x[2], pce->v[2], mul);
- }
- }
+ /* t is the current time for newton rhapson */
+ /* fac is the starting factor for current collision iteration */
+ /* the col->fac's are factors for the particle subframe step start and end during collision modifier step */
+ float f = fac + t * (1.f - fac);
+ float mul = col->fac1 + f * (col->fac2 - col->fac1);
+ if (pce->tot > 0) {
+ madd_v3_v3v3fl(pce->x0, pce->x[0], pce->v[0], mul);
+
+ if (pce->tot > 1) {
+ madd_v3_v3v3fl(pce->x1, pce->x[1], pce->v[1], mul);
+
+ if (pce->tot > 2)
+ madd_v3_v3v3fl(pce->x2, pce->x[2], pce->v[2], mul);
+ }
+ }
}
static void collision_point_velocity(ParticleCollisionElement *pce)
{
- float v[3];
+ float v[3];
- copy_v3_v3(pce->vel, pce->v[0]);
+ copy_v3_v3(pce->vel, pce->v[0]);
- if (pce->tot > 1) {
- sub_v3_v3v3(v, pce->v[1], pce->v[0]);
- madd_v3_v3fl(pce->vel, v, pce->uv[0]);
+ if (pce->tot > 1) {
+ sub_v3_v3v3(v, pce->v[1], pce->v[0]);
+ madd_v3_v3fl(pce->vel, v, pce->uv[0]);
- if (pce->tot > 2) {
- sub_v3_v3v3(v, pce->v[2], pce->v[0]);
- madd_v3_v3fl(pce->vel, v, pce->uv[1]);
- }
- }
+ if (pce->tot > 2) {
+ sub_v3_v3v3(v, pce->v[2], pce->v[0]);
+ madd_v3_v3fl(pce->vel, v, pce->uv[1]);
+ }
+ }
}
-static float collision_point_distance_with_normal(float p[3], ParticleCollisionElement *pce, float fac, ParticleCollision *col, float *nor)
+static float collision_point_distance_with_normal(
+ float p[3], ParticleCollisionElement *pce, float fac, ParticleCollision *col, float *nor)
{
- if (fac >= 0.f)
- collision_interpolate_element(pce, 0.f, fac, col);
-
- switch (pce->tot) {
- case 1:
- {
- sub_v3_v3v3(nor, p, pce->x0);
- return normalize_v3(nor);
- }
- case 2:
- {
- float u, e[3], vec[3];
- sub_v3_v3v3(e, pce->x1, pce->x0);
- sub_v3_v3v3(vec, p, pce->x0);
- u = dot_v3v3(vec, e) / dot_v3v3(e, e);
-
- madd_v3_v3v3fl(nor, vec, e, -u);
- return normalize_v3(nor);
- }
- case 3:
- return nr_signed_distance_to_plane(p, 0.f, pce, nor);
- }
- return 0;
+ if (fac >= 0.f)
+ collision_interpolate_element(pce, 0.f, fac, col);
+
+ switch (pce->tot) {
+ case 1: {
+ sub_v3_v3v3(nor, p, pce->x0);
+ return normalize_v3(nor);
+ }
+ case 2: {
+ float u, e[3], vec[3];
+ sub_v3_v3v3(e, pce->x1, pce->x0);
+ sub_v3_v3v3(vec, p, pce->x0);
+ u = dot_v3v3(vec, e) / dot_v3v3(e, e);
+
+ madd_v3_v3v3fl(nor, vec, e, -u);
+ return normalize_v3(nor);
+ }
+ case 3:
+ return nr_signed_distance_to_plane(p, 0.f, pce, nor);
+ }
+ return 0;
}
-static void collision_point_on_surface(float p[3], ParticleCollisionElement *pce, float fac, ParticleCollision *col, float *co)
+static void collision_point_on_surface(
+ float p[3], ParticleCollisionElement *pce, float fac, ParticleCollision *col, float *co)
{
- collision_interpolate_element(pce, 0.f, fac, col);
-
- switch (pce->tot) {
- case 1:
- {
- sub_v3_v3v3(co, p, pce->x0);
- normalize_v3(co);
- madd_v3_v3v3fl(co, pce->x0, co, col->radius);
- break;
- }
- case 2:
- {
- float u, e[3], vec[3], nor[3];
- sub_v3_v3v3(e, pce->x1, pce->x0);
- sub_v3_v3v3(vec, p, pce->x0);
- u = dot_v3v3(vec, e) / dot_v3v3(e, e);
-
- madd_v3_v3v3fl(nor, vec, e, -u);
- normalize_v3(nor);
-
- madd_v3_v3v3fl(co, pce->x0, e, pce->uv[0]);
- madd_v3_v3fl(co, nor, col->radius);
- break;
- }
- case 3:
- {
- float p0[3], e1[3], e2[3], nor[3];
-
- sub_v3_v3v3(e1, pce->x1, pce->x0);
- sub_v3_v3v3(e2, pce->x2, pce->x0);
- sub_v3_v3v3(p0, p, pce->x0);
-
- cross_v3_v3v3(nor, e1, e2);
- normalize_v3(nor);
-
- if (pce->inv_nor == 1)
- negate_v3(nor);
-
- madd_v3_v3v3fl(co, pce->x0, nor, col->radius);
- madd_v3_v3fl(co, e1, pce->uv[0]);
- madd_v3_v3fl(co, e2, pce->uv[1]);
- break;
- }
- }
+ collision_interpolate_element(pce, 0.f, fac, col);
+
+ switch (pce->tot) {
+ case 1: {
+ sub_v3_v3v3(co, p, pce->x0);
+ normalize_v3(co);
+ madd_v3_v3v3fl(co, pce->x0, co, col->radius);
+ break;
+ }
+ case 2: {
+ float u, e[3], vec[3], nor[3];
+ sub_v3_v3v3(e, pce->x1, pce->x0);
+ sub_v3_v3v3(vec, p, pce->x0);
+ u = dot_v3v3(vec, e) / dot_v3v3(e, e);
+
+ madd_v3_v3v3fl(nor, vec, e, -u);
+ normalize_v3(nor);
+
+ madd_v3_v3v3fl(co, pce->x0, e, pce->uv[0]);
+ madd_v3_v3fl(co, nor, col->radius);
+ break;
+ }
+ case 3: {
+ float p0[3], e1[3], e2[3], nor[3];
+
+ sub_v3_v3v3(e1, pce->x1, pce->x0);
+ sub_v3_v3v3(e2, pce->x2, pce->x0);
+ sub_v3_v3v3(p0, p, pce->x0);
+
+ cross_v3_v3v3(nor, e1, e2);
+ normalize_v3(nor);
+
+ if (pce->inv_nor == 1)
+ negate_v3(nor);
+
+ madd_v3_v3v3fl(co, pce->x0, nor, col->radius);
+ madd_v3_v3fl(co, e1, pce->uv[0]);
+ madd_v3_v3fl(co, e2, pce->uv[1]);
+ break;
+ }
+ }
}
/* find first root in range [0-1] starting from 0 */
-static float collision_newton_rhapson(ParticleCollision *col, float radius, ParticleCollisionElement *pce, NRDistanceFunc distance_func)
+static float collision_newton_rhapson(ParticleCollision *col,
+ float radius,
+ ParticleCollisionElement *pce,
+ NRDistanceFunc distance_func)
{
- float t0, t1, dt_init, d0, d1, dd, n[3];
- int iter;
-
- pce->inv_nor = -1;
-
- if (col->inv_total_time > 0.0f) {
- /* Initial step size should be small, but not too small or floating point
- * precision errors will appear. - z0r */
- dt_init = COLLISION_INIT_STEP * col->inv_total_time;
- }
- else {
- dt_init = 0.001f;
- }
-
- /* start from the beginning */
- t0 = 0.f;
- collision_interpolate_element(pce, t0, col->f, col);
- d0 = distance_func(col->co1, radius, pce, n);
- t1 = dt_init;
- d1 = 0.f;
-
- for (iter=0; iter<10; iter++) {//, itersum++) {
- /* get current location */
- collision_interpolate_element(pce, t1, col->f, col);
- interp_v3_v3v3(pce->p, col->co1, col->co2, t1);
-
- d1 = distance_func(pce->p, radius, pce, n);
-
- /* particle already inside face, so report collision */
- if (iter == 0 && d0 < 0.f && d0 > -radius) {
- copy_v3_v3(pce->p, col->co1);
- copy_v3_v3(pce->nor, n);
- pce->inside = 1;
- return 0.f;
- }
-
- /* Zero gradient (no movement relative to element). Can't step from
- * here. */
- if (d1 == d0) {
- /* If first iteration, try from other end where the gradient may be
- * greater. Note: code duplicated below. */
- if (iter == 0) {
- t0 = 1.f;
- collision_interpolate_element(pce, t0, col->f, col);
- d0 = distance_func(col->co2, radius, pce, n);
- t1 = 1.0f - dt_init;
- d1 = 0.f;
- continue;
- }
- else
- return -1.f;
- }
-
- dd = (t1-t0)/(d1-d0);
-
- t0 = t1;
- d0 = d1;
-
- t1 -= d1*dd;
-
- /* Particle moving away from plane could also mean a strangely rotating
- * face, so check from end. Note: code duplicated above. */
- if (iter == 0 && t1 < 0.f) {
- t0 = 1.f;
- collision_interpolate_element(pce, t0, col->f, col);
- d0 = distance_func(col->co2, radius, pce, n);
- t1 = 1.0f - dt_init;
- d1 = 0.f;
- continue;
- }
- else if (iter == 1 && (t1 < -COLLISION_ZERO || t1 > 1.f))
- return -1.f;
-
- if (d1 <= COLLISION_ZERO && d1 >= -COLLISION_ZERO) {
- if (t1 >= -COLLISION_ZERO && t1 <= 1.f) {
- if (distance_func == nr_signed_distance_to_plane)
- copy_v3_v3(pce->nor, n);
-
- CLAMP(t1, 0.f, 1.f);
-
- return t1;
- }
- else
- return -1.f;
- }
- }
- return -1.0;
+ float t0, t1, dt_init, d0, d1, dd, n[3];
+ int iter;
+
+ pce->inv_nor = -1;
+
+ if (col->inv_total_time > 0.0f) {
+ /* Initial step size should be small, but not too small or floating point
+ * precision errors will appear. - z0r */
+ dt_init = COLLISION_INIT_STEP * col->inv_total_time;
+ }
+ else {
+ dt_init = 0.001f;
+ }
+
+ /* start from the beginning */
+ t0 = 0.f;
+ collision_interpolate_element(pce, t0, col->f, col);
+ d0 = distance_func(col->co1, radius, pce, n);
+ t1 = dt_init;
+ d1 = 0.f;
+
+ for (iter = 0; iter < 10; iter++) { //, itersum++) {
+ /* get current location */
+ collision_interpolate_element(pce, t1, col->f, col);
+ interp_v3_v3v3(pce->p, col->co1, col->co2, t1);
+
+ d1 = distance_func(pce->p, radius, pce, n);
+
+ /* particle already inside face, so report collision */
+ if (iter == 0 && d0 < 0.f && d0 > -radius) {
+ copy_v3_v3(pce->p, col->co1);
+ copy_v3_v3(pce->nor, n);
+ pce->inside = 1;
+ return 0.f;
+ }
+
+ /* Zero gradient (no movement relative to element). Can't step from
+ * here. */
+ if (d1 == d0) {
+ /* If first iteration, try from other end where the gradient may be
+ * greater. Note: code duplicated below. */
+ if (iter == 0) {
+ t0 = 1.f;
+ collision_interpolate_element(pce, t0, col->f, col);
+ d0 = distance_func(col->co2, radius, pce, n);
+ t1 = 1.0f - dt_init;
+ d1 = 0.f;
+ continue;
+ }
+ else
+ return -1.f;
+ }
+
+ dd = (t1 - t0) / (d1 - d0);
+
+ t0 = t1;
+ d0 = d1;
+
+ t1 -= d1 * dd;
+
+ /* Particle moving away from plane could also mean a strangely rotating
+ * face, so check from end. Note: code duplicated above. */
+ if (iter == 0 && t1 < 0.f) {
+ t0 = 1.f;
+ collision_interpolate_element(pce, t0, col->f, col);
+ d0 = distance_func(col->co2, radius, pce, n);
+ t1 = 1.0f - dt_init;
+ d1 = 0.f;
+ continue;
+ }
+ else if (iter == 1 && (t1 < -COLLISION_ZERO || t1 > 1.f))
+ return -1.f;
+
+ if (d1 <= COLLISION_ZERO && d1 >= -COLLISION_ZERO) {
+ if (t1 >= -COLLISION_ZERO && t1 <= 1.f) {
+ if (distance_func == nr_signed_distance_to_plane)
+ copy_v3_v3(pce->nor, n);
+
+ CLAMP(t1, 0.f, 1.f);
+
+ return t1;
+ }
+ else
+ return -1.f;
+ }
+ }
+ return -1.0;
}
-static int collision_sphere_to_tri(ParticleCollision *col, float radius, ParticleCollisionElement *pce, float *t)
+static int collision_sphere_to_tri(ParticleCollision *col,
+ float radius,
+ ParticleCollisionElement *pce,
+ float *t)
{
- ParticleCollisionElement *result = &col->pce;
- float ct, u, v;
+ ParticleCollisionElement *result = &col->pce;
+ float ct, u, v;
- pce->inv_nor = -1;
- pce->inside = 0;
+ pce->inv_nor = -1;
+ pce->inside = 0;
- ct = collision_newton_rhapson(col, radius, pce, nr_signed_distance_to_plane);
+ ct = collision_newton_rhapson(col, radius, pce, nr_signed_distance_to_plane);
- if (ct >= 0.f && ct < *t && (result->inside==0 || pce->inside==1) ) {
- float e1[3], e2[3], p0[3];
- float e1e1, e1e2, e1p0, e2e2, e2p0, inv;
+ if (ct >= 0.f && ct < *t && (result->inside == 0 || pce->inside == 1)) {
+ float e1[3], e2[3], p0[3];
+ float e1e1, e1e2, e1p0, e2e2, e2p0, inv;
- sub_v3_v3v3(e1, pce->x1, pce->x0);
- sub_v3_v3v3(e2, pce->x2, pce->x0);
- /* XXX: add radius correction here? */
- sub_v3_v3v3(p0, pce->p, pce->x0);
+ sub_v3_v3v3(e1, pce->x1, pce->x0);
+ sub_v3_v3v3(e2, pce->x2, pce->x0);
+ /* XXX: add radius correction here? */
+ sub_v3_v3v3(p0, pce->p, pce->x0);
- e1e1 = dot_v3v3(e1, e1);
- e1e2 = dot_v3v3(e1, e2);
- e1p0 = dot_v3v3(e1, p0);
- e2e2 = dot_v3v3(e2, e2);
- e2p0 = dot_v3v3(e2, p0);
+ e1e1 = dot_v3v3(e1, e1);
+ e1e2 = dot_v3v3(e1, e2);
+ e1p0 = dot_v3v3(e1, p0);
+ e2e2 = dot_v3v3(e2, e2);
+ e2p0 = dot_v3v3(e2, p0);
- inv = 1.f/(e1e1 * e2e2 - e1e2 * e1e2);
- u = (e2e2 * e1p0 - e1e2 * e2p0) * inv;
- v = (e1e1 * e2p0 - e1e2 * e1p0) * inv;
+ inv = 1.f / (e1e1 * e2e2 - e1e2 * e1e2);
+ u = (e2e2 * e1p0 - e1e2 * e2p0) * inv;
+ v = (e1e1 * e2p0 - e1e2 * e1p0) * inv;
- if (u>=0.f && u<=1.f && v>=0.f && u+v<=1.f) {
- *result = *pce;
+ if (u >= 0.f && u <= 1.f && v >= 0.f && u + v <= 1.f) {
+ *result = *pce;
- /* normal already calculated in pce */
+ /* normal already calculated in pce */
- result->uv[0] = u;
- result->uv[1] = v;
+ result->uv[0] = u;
+ result->uv[1] = v;
- *t = ct;
- return 1;
- }
- }
- return 0;
+ *t = ct;
+ return 1;
+ }
+ }
+ return 0;
}
-static int collision_sphere_to_edges(ParticleCollision *col, float radius, ParticleCollisionElement *pce, float *t)
+static int collision_sphere_to_edges(ParticleCollision *col,
+ float radius,
+ ParticleCollisionElement *pce,
+ float *t)
{
- ParticleCollisionElement edge[3], *cur = NULL, *hit = NULL;
- ParticleCollisionElement *result = &col->pce;
+ ParticleCollisionElement edge[3], *cur = NULL, *hit = NULL;
+ ParticleCollisionElement *result = &col->pce;
- float ct;
- int i;
+ float ct;
+ int i;
- for (i=0; i<3; i++) {
- cur = edge+i;
- cur->x[0] = pce->x[i]; cur->x[1] = pce->x[(i+1)%3];
- cur->v[0] = pce->v[i]; cur->v[1] = pce->v[(i+1)%3];
- cur->tot = 2;
- cur->inside = 0;
+ for (i = 0; i < 3; i++) {
+ cur = edge + i;
+ cur->x[0] = pce->x[i];
+ cur->x[1] = pce->x[(i + 1) % 3];
+ cur->v[0] = pce->v[i];
+ cur->v[1] = pce->v[(i + 1) % 3];
+ cur->tot = 2;
+ cur->inside = 0;
- ct = collision_newton_rhapson(col, radius, cur, nr_distance_to_edge);
+ ct = collision_newton_rhapson(col, radius, cur, nr_distance_to_edge);
- if (ct >= 0.f && ct < *t) {
- float u, e[3], vec[3];
+ if (ct >= 0.f && ct < *t) {
+ float u, e[3], vec[3];
- sub_v3_v3v3(e, cur->x1, cur->x0);
- sub_v3_v3v3(vec, cur->p, cur->x0);
- u = dot_v3v3(vec, e) / dot_v3v3(e, e);
+ sub_v3_v3v3(e, cur->x1, cur->x0);
+ sub_v3_v3v3(vec, cur->p, cur->x0);
+ u = dot_v3v3(vec, e) / dot_v3v3(e, e);
- if (u < 0.f || u > 1.f)
- break;
+ if (u < 0.f || u > 1.f)
+ break;
- *result = *cur;
+ *result = *cur;
- madd_v3_v3v3fl(result->nor, vec, e, -u);
- normalize_v3(result->nor);
+ madd_v3_v3v3fl(result->nor, vec, e, -u);
+ normalize_v3(result->nor);
- result->uv[0] = u;
+ result->uv[0] = u;
+ hit = cur;
+ *t = ct;
+ }
+ }
- hit = cur;
- *t = ct;
- }
-
- }
-
- return hit != NULL;
+ return hit != NULL;
}
-static int collision_sphere_to_verts(ParticleCollision *col, float radius, ParticleCollisionElement *pce, float *t)
+static int collision_sphere_to_verts(ParticleCollision *col,
+ float radius,
+ ParticleCollisionElement *pce,
+ float *t)
{
- ParticleCollisionElement vert[3], *cur = NULL, *hit = NULL;
- ParticleCollisionElement *result = &col->pce;
-
- float ct;
- int i;
+ ParticleCollisionElement vert[3], *cur = NULL, *hit = NULL;
+ ParticleCollisionElement *result = &col->pce;
- for (i=0; i<3; i++) {
- cur = vert+i;
- cur->x[0] = pce->x[i];
- cur->v[0] = pce->v[i];
- cur->tot = 1;
- cur->inside = 0;
+ float ct;
+ int i;
- ct = collision_newton_rhapson(col, radius, cur, nr_distance_to_vert);
+ for (i = 0; i < 3; i++) {
+ cur = vert + i;
+ cur->x[0] = pce->x[i];
+ cur->v[0] = pce->v[i];
+ cur->tot = 1;
+ cur->inside = 0;
- if (ct >= 0.f && ct < *t) {
- *result = *cur;
+ ct = collision_newton_rhapson(col, radius, cur, nr_distance_to_vert);
- sub_v3_v3v3(result->nor, cur->p, cur->x0);
- normalize_v3(result->nor);
+ if (ct >= 0.f && ct < *t) {
+ *result = *cur;
- hit = cur;
- *t = ct;
- }
+ sub_v3_v3v3(result->nor, cur->p, cur->x0);
+ normalize_v3(result->nor);
- }
+ hit = cur;
+ *t = ct;
+ }
+ }
- return hit != NULL;
+ return hit != NULL;
}
/* Callback for BVHTree near test */
-void BKE_psys_collision_neartest_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
+void BKE_psys_collision_neartest_cb(void *userdata,
+ int index,
+ const BVHTreeRay *ray,
+ BVHTreeRayHit *hit)
{
- ParticleCollision *col = (ParticleCollision *) userdata;
- ParticleCollisionElement pce;
- const MVertTri *vt = &col->md->tri[index];
- MVert *x = col->md->x;
- MVert *v = col->md->current_v;
- float t = hit->dist/col->original_ray_length;
- int collision = 0;
-
- pce.x[0] = x[vt->tri[0]].co;
- pce.x[1] = x[vt->tri[1]].co;
- pce.x[2] = x[vt->tri[2]].co;
-
- pce.v[0] = v[vt->tri[0]].co;
- pce.v[1] = v[vt->tri[1]].co;
- pce.v[2] = v[vt->tri[2]].co;
-
- pce.tot = 3;
- pce.inside = 0;
- pce.index = index;
-
- collision = collision_sphere_to_tri(col, ray->radius, &pce, &t);
- if (col->pce.inside == 0) {
- collision += collision_sphere_to_edges(col, ray->radius, &pce, &t);
- collision += collision_sphere_to_verts(col, ray->radius, &pce, &t);
- }
-
- if (collision) {
- hit->dist = col->original_ray_length * t;
- hit->index = index;
-
- collision_point_velocity(&col->pce);
-
- col->hit = col->current;
- }
+ ParticleCollision *col = (ParticleCollision *)userdata;
+ ParticleCollisionElement pce;
+ const MVertTri *vt = &col->md->tri[index];
+ MVert *x = col->md->x;
+ MVert *v = col->md->current_v;
+ float t = hit->dist / col->original_ray_length;
+ int collision = 0;
+
+ pce.x[0] = x[vt->tri[0]].co;
+ pce.x[1] = x[vt->tri[1]].co;
+ pce.x[2] = x[vt->tri[2]].co;
+
+ pce.v[0] = v[vt->tri[0]].co;
+ pce.v[1] = v[vt->tri[1]].co;
+ pce.v[2] = v[vt->tri[2]].co;
+
+ pce.tot = 3;
+ pce.inside = 0;
+ pce.index = index;
+
+ collision = collision_sphere_to_tri(col, ray->radius, &pce, &t);
+ if (col->pce.inside == 0) {
+ collision += collision_sphere_to_edges(col, ray->radius, &pce, &t);
+ collision += collision_sphere_to_verts(col, ray->radius, &pce, &t);
+ }
+
+ if (collision) {
+ hit->dist = col->original_ray_length * t;
+ hit->index = index;
+
+ collision_point_velocity(&col->pce);
+
+ col->hit = col->current;
+ }
}
-static int collision_detect(ParticleData *pa, ParticleCollision *col, BVHTreeRayHit *hit, ListBase *colliders)
+static int collision_detect(ParticleData *pa,
+ ParticleCollision *col,
+ BVHTreeRayHit *hit,
+ ListBase *colliders)
{
- const int raycast_flag = BVH_RAYCAST_DEFAULT & ~(BVH_RAYCAST_WATERTIGHT);
- ColliderCache *coll;
- float ray_dir[3];
-
- if (BLI_listbase_is_empty(colliders))
- return 0;
-
- sub_v3_v3v3(ray_dir, col->co2, col->co1);
- hit->index = -1;
- hit->dist = col->original_ray_length = normalize_v3(ray_dir);
- col->pce.inside = 0;
-
- /* even if particle is stationary we want to check for moving colliders */
- /* if hit.dist is zero the bvhtree_ray_cast will just ignore everything */
- if (hit->dist == 0.0f)
- hit->dist = col->original_ray_length = 0.000001f;
-
- for (coll = colliders->first; coll; coll=coll->next) {
- /* for boids: don't check with current ground object; also skip if permeated */
- bool skip = false;
-
- for (int i = 0; i < col->skip_count; i++) {
- if (coll->ob == col->skip[i]) {
- skip = true;
- break;
- }
- }
-
- if (skip)
- continue;
-
- /* particles should not collide with emitter at birth */
- if (coll->ob == col->emitter && pa->time < col->cfra && pa->time >= col->old_cfra)
- continue;
-
- col->current = coll->ob;
- col->md = coll->collmd;
- col->fac1 = (col->old_cfra - coll->collmd->time_x) / (coll->collmd->time_xnew - coll->collmd->time_x);
- col->fac2 = (col->cfra - coll->collmd->time_x) / (coll->collmd->time_xnew - coll->collmd->time_x);
-
- if (col->md && col->md->bvhtree) {
- BLI_bvhtree_ray_cast_ex(
- col->md->bvhtree, col->co1, ray_dir, col->radius, hit,
- BKE_psys_collision_neartest_cb, col, raycast_flag);
- }
- }
-
- return hit->index >= 0;
+ const int raycast_flag = BVH_RAYCAST_DEFAULT & ~(BVH_RAYCAST_WATERTIGHT);
+ ColliderCache *coll;
+ float ray_dir[3];
+
+ if (BLI_listbase_is_empty(colliders))
+ return 0;
+
+ sub_v3_v3v3(ray_dir, col->co2, col->co1);
+ hit->index = -1;
+ hit->dist = col->original_ray_length = normalize_v3(ray_dir);
+ col->pce.inside = 0;
+
+ /* even if particle is stationary we want to check for moving colliders */
+ /* if hit.dist is zero the bvhtree_ray_cast will just ignore everything */
+ if (hit->dist == 0.0f)
+ hit->dist = col->original_ray_length = 0.000001f;
+
+ for (coll = colliders->first; coll; coll = coll->next) {
+ /* for boids: don't check with current ground object; also skip if permeated */
+ bool skip = false;
+
+ for (int i = 0; i < col->skip_count; i++) {
+ if (coll->ob == col->skip[i]) {
+ skip = true;
+ break;
+ }
+ }
+
+ if (skip)
+ continue;
+
+ /* particles should not collide with emitter at birth */
+ if (coll->ob == col->emitter && pa->time < col->cfra && pa->time >= col->old_cfra)
+ continue;
+
+ col->current = coll->ob;
+ col->md = coll->collmd;
+ col->fac1 = (col->old_cfra - coll->collmd->time_x) /
+ (coll->collmd->time_xnew - coll->collmd->time_x);
+ col->fac2 = (col->cfra - coll->collmd->time_x) /
+ (coll->collmd->time_xnew - coll->collmd->time_x);
+
+ if (col->md && col->md->bvhtree) {
+ BLI_bvhtree_ray_cast_ex(col->md->bvhtree,
+ col->co1,
+ ray_dir,
+ col->radius,
+ hit,
+ BKE_psys_collision_neartest_cb,
+ col,
+ raycast_flag);
+ }
+ }
+
+ return hit->index >= 0;
}
-static int collision_response(ParticleSimulationData *sim, ParticleData *pa, ParticleCollision *col, BVHTreeRayHit *hit, int kill, int dynamic_rotation)
+static int collision_response(ParticleSimulationData *sim,
+ ParticleData *pa,
+ ParticleCollision *col,
+ BVHTreeRayHit *hit,
+ int kill,
+ int dynamic_rotation)
{
- ParticleCollisionElement *pce = &col->pce;
- PartDeflect *pd = col->hit->pd;
- RNG *rng = sim->rng;
- /* point of collision */
- float co[3];
- /* location factor of collision between this iteration */
- float x = hit->dist/col->original_ray_length;
- /* time factor of collision between timestep */
- float f = col->f + x * (1.0f - col->f);
- /* time since previous collision (in seconds) */
- float dt1 = (f - col->f) * col->total_time;
- /* time left after collision (in seconds) */
- float dt2 = (1.0f - f) * col->total_time;
- /* did particle pass through the collision surface? */
- int through = (BLI_rng_get_float(rng) < pd->pdef_perm) ? 1 : 0;
-
- /* calculate exact collision location */
- interp_v3_v3v3(co, col->co1, col->co2, x);
-
- /* particle dies in collision */
- if (through == 0 && (kill || pd->flag & PDEFLE_KILL_PART)) {
- pa->alive = PARS_DYING;
- pa->dietime = col->old_cfra + (col->cfra - col->old_cfra) * f;
-
- copy_v3_v3(pa->state.co, co);
- interp_v3_v3v3(pa->state.vel, pa->prev_state.vel, pa->state.vel, f);
- interp_qt_qtqt(pa->state.rot, pa->prev_state.rot, pa->state.rot, f);
- interp_v3_v3v3(pa->state.ave, pa->prev_state.ave, pa->state.ave, f);
-
- /* particle is dead so we don't need to calculate further */
- return 0;
- }
- /* figure out velocity and other data after collision */
- else {
- /* velocity directly before collision to be modified into velocity directly after collision */
- float v0[3];
- /* normal component of v0 */
- float v0_nor[3];
- /* tangential component of v0 */
- float v0_tan[3];
- /* tangential component of collision surface velocity */
- float vc_tan[3];
- float v0_dot, vc_dot;
- float damp = pd->pdef_damp + pd->pdef_rdamp * 2 * (BLI_rng_get_float(rng) - 0.5f);
- float frict = pd->pdef_frict + pd->pdef_rfrict * 2 * (BLI_rng_get_float(rng) - 0.5f);
- float distance, nor[3], dot;
-
- CLAMP(damp,0.0f, 1.0f);
- CLAMP(frict,0.0f, 1.0f);
-
- /* get exact velocity right before collision */
- madd_v3_v3v3fl(v0, col->ve1, col->acc, dt1);
-
- /* convert collider velocity from 1/framestep to 1/s TODO: here we assume 1 frame step for collision modifier */
- mul_v3_fl(pce->vel, col->inv_timestep);
-
- /* calculate tangential particle velocity */
- v0_dot = dot_v3v3(pce->nor, v0);
- madd_v3_v3v3fl(v0_tan, v0, pce->nor, -v0_dot);
-
- /* calculate tangential collider velocity */
- vc_dot = dot_v3v3(pce->nor, pce->vel);
- madd_v3_v3v3fl(vc_tan, pce->vel, pce->nor, -vc_dot);
-
- /* handle friction effects (tangential and angular velocity) */
- if (frict > 0.0f) {
- /* angular <-> linear velocity */
- if (dynamic_rotation) {
- float vr_tan[3], v1_tan[3], ave[3];
-
- /* linear velocity of particle surface */
- cross_v3_v3v3(vr_tan, pce->nor, pa->state.ave);
- mul_v3_fl(vr_tan, pa->size);
-
- /* change to coordinates that move with the collision plane */
- sub_v3_v3v3(v1_tan, v0_tan, vc_tan);
-
- /* The resulting velocity is a weighted average of particle cm & surface
- * velocity. This weight (related to particle's moment of inertia) could
- * be made a parameter for angular <-> linear conversion.
- */
- madd_v3_v3fl(v1_tan, vr_tan, -0.4);
- mul_v3_fl(v1_tan, 1.0f/1.4f); /* 1/(1+0.4) */
-
- /* rolling friction is around 0.01 of sliding friction
- * (could be made a parameter) */
- mul_v3_fl(v1_tan, 1.0f - 0.01f * frict);
-
- /* surface_velocity is opposite to cm velocity */
- negate_v3_v3(vr_tan, v1_tan);
-
- /* get back to global coordinates */
- add_v3_v3(v1_tan, vc_tan);
-
- /* convert to angular velocity*/
- cross_v3_v3v3(ave, vr_tan, pce->nor);
- mul_v3_fl(ave, 1.0f/MAX2(pa->size, 0.001f));
-
- /* only friction will cause change in linear & angular velocity */
- interp_v3_v3v3(pa->state.ave, pa->state.ave, ave, frict);
- interp_v3_v3v3(v0_tan, v0_tan, v1_tan, frict);
- }
- else {
- /* just basic friction (unphysical due to the friction model used in Blender) */
- interp_v3_v3v3(v0_tan, v0_tan, vc_tan, frict);
- }
- }
-
- /* stickiness was possibly added before, so cancel that before calculating new normal velocity */
- /* otherwise particles go flying out of the surface because of high reversed sticky velocity */
- if (v0_dot < 0.0f) {
- v0_dot += pd->pdef_stickness;
- if (v0_dot > 0.0f)
- v0_dot = 0.0f;
- }
-
- /* damping and flipping of velocity around normal */
- v0_dot *= 1.0f - damp;
- vc_dot *= through ? damp : 1.0f;
-
- /* calculate normal particle velocity */
- /* special case for object hitting the particle from behind */
- if (through==0 && ((vc_dot>0.0f && v0_dot>0.0f && vc_dot>v0_dot) || (vc_dot<0.0f && v0_dot<0.0f && vc_dot<v0_dot)))
- mul_v3_v3fl(v0_nor, pce->nor, vc_dot);
- else if (v0_dot > 0.f)
- mul_v3_v3fl(v0_nor, pce->nor, vc_dot + v0_dot);
- else
- mul_v3_v3fl(v0_nor, pce->nor, vc_dot + (through ? 1.0f : -1.0f) * v0_dot);
-
- /* combine components together again */
- add_v3_v3v3(v0, v0_nor, v0_tan);
-
- if (col->boid) {
- /* keep boids above ground */
- BoidParticle *bpa = pa->boid;
- if (bpa->data.mode == eBoidMode_OnLand || co[2] <= col->boid_z) {
- co[2] = col->boid_z;
- v0[2] = 0.0f;
- }
- }
-
- /* re-apply acceleration to final location and velocity */
- madd_v3_v3v3fl(pa->state.co, co, v0, dt2);
- madd_v3_v3fl(pa->state.co, col->acc, 0.5f*dt2*dt2);
- madd_v3_v3v3fl(pa->state.vel, v0, col->acc, dt2);
-
- /* make sure particle stays on the right side of the surface */
- if (!through) {
- distance = collision_point_distance_with_normal(co, pce, -1.f, col, nor);
-
- if (distance < col->radius + COLLISION_MIN_DISTANCE)
- madd_v3_v3fl(co, nor, col->radius + COLLISION_MIN_DISTANCE - distance);
-
- dot = dot_v3v3(nor, v0);
- if (dot < 0.f)
- madd_v3_v3fl(v0, nor, -dot);
-
- distance = collision_point_distance_with_normal(pa->state.co, pce, 1.f, col, nor);
-
- if (distance < col->radius + COLLISION_MIN_DISTANCE)
- madd_v3_v3fl(pa->state.co, nor, col->radius + COLLISION_MIN_DISTANCE - distance);
-
- dot = dot_v3v3(nor, pa->state.vel);
- if (dot < 0.f)
- madd_v3_v3fl(pa->state.vel, nor, -dot);
- }
-
- /* add stickiness to surface */
- madd_v3_v3fl(pa->state.vel, pce->nor, -pd->pdef_stickness);
-
- /* set coordinates for next iteration */
- copy_v3_v3(col->co1, co);
- copy_v3_v3(col->co2, pa->state.co);
-
- copy_v3_v3(col->ve1, v0);
- copy_v3_v3(col->ve2, pa->state.vel);
-
- col->f = f;
- }
-
- /* if permeability random roll succeeded, disable collider for this sim step */
- if (through) {
- col->skip[col->skip_count++] = col->hit;
- }
-
- return 1;
+ ParticleCollisionElement *pce = &col->pce;
+ PartDeflect *pd = col->hit->pd;
+ RNG *rng = sim->rng;
+ /* point of collision */
+ float co[3];
+ /* location factor of collision between this iteration */
+ float x = hit->dist / col->original_ray_length;
+ /* time factor of collision between timestep */
+ float f = col->f + x * (1.0f - col->f);
+ /* time since previous collision (in seconds) */
+ float dt1 = (f - col->f) * col->total_time;
+ /* time left after collision (in seconds) */
+ float dt2 = (1.0f - f) * col->total_time;
+ /* did particle pass through the collision surface? */
+ int through = (BLI_rng_get_float(rng) < pd->pdef_perm) ? 1 : 0;
+
+ /* calculate exact collision location */
+ interp_v3_v3v3(co, col->co1, col->co2, x);
+
+ /* particle dies in collision */
+ if (through == 0 && (kill || pd->flag & PDEFLE_KILL_PART)) {
+ pa->alive = PARS_DYING;
+ pa->dietime = col->old_cfra + (col->cfra - col->old_cfra) * f;
+
+ copy_v3_v3(pa->state.co, co);
+ interp_v3_v3v3(pa->state.vel, pa->prev_state.vel, pa->state.vel, f);
+ interp_qt_qtqt(pa->state.rot, pa->prev_state.rot, pa->state.rot, f);
+ interp_v3_v3v3(pa->state.ave, pa->prev_state.ave, pa->state.ave, f);
+
+ /* particle is dead so we don't need to calculate further */
+ return 0;
+ }
+ /* figure out velocity and other data after collision */
+ else {
+ /* velocity directly before collision to be modified into velocity directly after collision */
+ float v0[3];
+ /* normal component of v0 */
+ float v0_nor[3];
+ /* tangential component of v0 */
+ float v0_tan[3];
+ /* tangential component of collision surface velocity */
+ float vc_tan[3];
+ float v0_dot, vc_dot;
+ float damp = pd->pdef_damp + pd->pdef_rdamp * 2 * (BLI_rng_get_float(rng) - 0.5f);
+ float frict = pd->pdef_frict + pd->pdef_rfrict * 2 * (BLI_rng_get_float(rng) - 0.5f);
+ float distance, nor[3], dot;
+
+ CLAMP(damp, 0.0f, 1.0f);
+ CLAMP(frict, 0.0f, 1.0f);
+
+ /* get exact velocity right before collision */
+ madd_v3_v3v3fl(v0, col->ve1, col->acc, dt1);
+
+ /* convert collider velocity from 1/framestep to 1/s TODO: here we assume 1 frame step for collision modifier */
+ mul_v3_fl(pce->vel, col->inv_timestep);
+
+ /* calculate tangential particle velocity */
+ v0_dot = dot_v3v3(pce->nor, v0);
+ madd_v3_v3v3fl(v0_tan, v0, pce->nor, -v0_dot);
+
+ /* calculate tangential collider velocity */
+ vc_dot = dot_v3v3(pce->nor, pce->vel);
+ madd_v3_v3v3fl(vc_tan, pce->vel, pce->nor, -vc_dot);
+
+ /* handle friction effects (tangential and angular velocity) */
+ if (frict > 0.0f) {
+ /* angular <-> linear velocity */
+ if (dynamic_rotation) {
+ float vr_tan[3], v1_tan[3], ave[3];
+
+ /* linear velocity of particle surface */
+ cross_v3_v3v3(vr_tan, pce->nor, pa->state.ave);
+ mul_v3_fl(vr_tan, pa->size);
+
+ /* change to coordinates that move with the collision plane */
+ sub_v3_v3v3(v1_tan, v0_tan, vc_tan);
+
+ /* The resulting velocity is a weighted average of particle cm & surface
+ * velocity. This weight (related to particle's moment of inertia) could
+ * be made a parameter for angular <-> linear conversion.
+ */
+ madd_v3_v3fl(v1_tan, vr_tan, -0.4);
+ mul_v3_fl(v1_tan, 1.0f / 1.4f); /* 1/(1+0.4) */
+
+ /* rolling friction is around 0.01 of sliding friction
+ * (could be made a parameter) */
+ mul_v3_fl(v1_tan, 1.0f - 0.01f * frict);
+
+ /* surface_velocity is opposite to cm velocity */
+ negate_v3_v3(vr_tan, v1_tan);
+
+ /* get back to global coordinates */
+ add_v3_v3(v1_tan, vc_tan);
+
+ /* convert to angular velocity*/
+ cross_v3_v3v3(ave, vr_tan, pce->nor);
+ mul_v3_fl(ave, 1.0f / MAX2(pa->size, 0.001f));
+
+ /* only friction will cause change in linear & angular velocity */
+ interp_v3_v3v3(pa->state.ave, pa->state.ave, ave, frict);
+ interp_v3_v3v3(v0_tan, v0_tan, v1_tan, frict);
+ }
+ else {
+ /* just basic friction (unphysical due to the friction model used in Blender) */
+ interp_v3_v3v3(v0_tan, v0_tan, vc_tan, frict);
+ }
+ }
+
+ /* stickiness was possibly added before, so cancel that before calculating new normal velocity */
+ /* otherwise particles go flying out of the surface because of high reversed sticky velocity */
+ if (v0_dot < 0.0f) {
+ v0_dot += pd->pdef_stickness;
+ if (v0_dot > 0.0f)
+ v0_dot = 0.0f;
+ }
+
+ /* damping and flipping of velocity around normal */
+ v0_dot *= 1.0f - damp;
+ vc_dot *= through ? damp : 1.0f;
+
+ /* calculate normal particle velocity */
+ /* special case for object hitting the particle from behind */
+ if (through == 0 && ((vc_dot > 0.0f && v0_dot > 0.0f && vc_dot > v0_dot) ||
+ (vc_dot < 0.0f && v0_dot < 0.0f && vc_dot < v0_dot)))
+ mul_v3_v3fl(v0_nor, pce->nor, vc_dot);
+ else if (v0_dot > 0.f)
+ mul_v3_v3fl(v0_nor, pce->nor, vc_dot + v0_dot);
+ else
+ mul_v3_v3fl(v0_nor, pce->nor, vc_dot + (through ? 1.0f : -1.0f) * v0_dot);
+
+ /* combine components together again */
+ add_v3_v3v3(v0, v0_nor, v0_tan);
+
+ if (col->boid) {
+ /* keep boids above ground */
+ BoidParticle *bpa = pa->boid;
+ if (bpa->data.mode == eBoidMode_OnLand || co[2] <= col->boid_z) {
+ co[2] = col->boid_z;
+ v0[2] = 0.0f;
+ }
+ }
+
+ /* re-apply acceleration to final location and velocity */
+ madd_v3_v3v3fl(pa->state.co, co, v0, dt2);
+ madd_v3_v3fl(pa->state.co, col->acc, 0.5f * dt2 * dt2);
+ madd_v3_v3v3fl(pa->state.vel, v0, col->acc, dt2);
+
+ /* make sure particle stays on the right side of the surface */
+ if (!through) {
+ distance = collision_point_distance_with_normal(co, pce, -1.f, col, nor);
+
+ if (distance < col->radius + COLLISION_MIN_DISTANCE)
+ madd_v3_v3fl(co, nor, col->radius + COLLISION_MIN_DISTANCE - distance);
+
+ dot = dot_v3v3(nor, v0);
+ if (dot < 0.f)
+ madd_v3_v3fl(v0, nor, -dot);
+
+ distance = collision_point_distance_with_normal(pa->state.co, pce, 1.f, col, nor);
+
+ if (distance < col->radius + COLLISION_MIN_DISTANCE)
+ madd_v3_v3fl(pa->state.co, nor, col->radius + COLLISION_MIN_DISTANCE - distance);
+
+ dot = dot_v3v3(nor, pa->state.vel);
+ if (dot < 0.f)
+ madd_v3_v3fl(pa->state.vel, nor, -dot);
+ }
+
+ /* add stickiness to surface */
+ madd_v3_v3fl(pa->state.vel, pce->nor, -pd->pdef_stickness);
+
+ /* set coordinates for next iteration */
+ copy_v3_v3(col->co1, co);
+ copy_v3_v3(col->co2, pa->state.co);
+
+ copy_v3_v3(col->ve1, v0);
+ copy_v3_v3(col->ve2, pa->state.vel);
+
+ col->f = f;
+ }
+
+ /* if permeability random roll succeeded, disable collider for this sim step */
+ if (through) {
+ col->skip[col->skip_count++] = col->hit;
+ }
+
+ return 1;
}
static void collision_fail(ParticleData *pa, ParticleCollision *col)
{
- /* final chance to prevent total failure, so stick to the surface and hope for the best */
- collision_point_on_surface(col->co1, &col->pce, 1.f, col, pa->state.co);
+ /* final chance to prevent total failure, so stick to the surface and hope for the best */
+ collision_point_on_surface(col->co1, &col->pce, 1.f, col, pa->state.co);
- copy_v3_v3(pa->state.vel, col->pce.vel);
- mul_v3_fl(pa->state.vel, col->inv_timestep);
+ copy_v3_v3(pa->state.vel, col->pce.vel);
+ mul_v3_fl(pa->state.vel, col->inv_timestep);
-
- /* printf("max iterations\n"); */
+ /* printf("max iterations\n"); */
}
/* Particle - Mesh collision detection and response
@@ -2857,443 +2972,466 @@ static void collision_fail(ParticleData *pa, ParticleCollision *col)
*/
static void collision_check(ParticleSimulationData *sim, int p, float dfra, float cfra)
{
- ParticleSettings *part = sim->psys->part;
- ParticleData *pa = sim->psys->particles + p;
- ParticleCollision col;
- BVHTreeRayHit hit;
- int collision_count=0;
-
- float timestep = psys_get_timestep(sim);
-
- memset(&col, 0, sizeof(ParticleCollision));
-
- col.total_time = timestep * dfra;
- col.inv_total_time = 1.0f/col.total_time;
- col.inv_timestep = 1.0f/timestep;
-
- col.cfra = cfra;
- col.old_cfra = sim->psys->cfra;
-
- /* get acceleration (from gravity, forcefields etc. to be re-applied in collision response) */
- sub_v3_v3v3(col.acc, pa->state.vel, pa->prev_state.vel);
- mul_v3_fl(col.acc, 1.f/col.total_time);
-
- /* set values for first iteration */
- copy_v3_v3(col.co1, pa->prev_state.co);
- copy_v3_v3(col.co2, pa->state.co);
- copy_v3_v3(col.ve1, pa->prev_state.vel);
- copy_v3_v3(col.ve2, pa->state.vel);
- col.f = 0.0f;
-
- col.radius = ((part->flag & PART_SIZE_DEFL) || (part->phystype == PART_PHYS_BOIDS)) ? pa->size : COLLISION_MIN_RADIUS;
-
- /* override for boids */
- if (part->phystype == PART_PHYS_BOIDS && part->boids->options & BOID_ALLOW_LAND) {
- col.boid = 1;
- col.boid_z = pa->state.co[2];
- col.skip[col.skip_count++] = pa->boid->ground;
- }
-
- /* 10 iterations to catch multiple collisions */
- while (collision_count < PARTICLE_COLLISION_MAX_COLLISIONS) {
- if (collision_detect(pa, &col, &hit, sim->colliders)) {
-
- collision_count++;
-
- if (collision_count == PARTICLE_COLLISION_MAX_COLLISIONS)
- collision_fail(pa, &col);
- else if (collision_response(sim, pa, &col, &hit, part->flag & PART_DIE_ON_COL, part->flag & PART_ROT_DYN)==0)
- return;
- }
- else
- return;
- }
+ ParticleSettings *part = sim->psys->part;
+ ParticleData *pa = sim->psys->particles + p;
+ ParticleCollision col;
+ BVHTreeRayHit hit;
+ int collision_count = 0;
+
+ float timestep = psys_get_timestep(sim);
+
+ memset(&col, 0, sizeof(ParticleCollision));
+
+ col.total_time = timestep * dfra;
+ col.inv_total_time = 1.0f / col.total_time;
+ col.inv_timestep = 1.0f / timestep;
+
+ col.cfra = cfra;
+ col.old_cfra = sim->psys->cfra;
+
+ /* get acceleration (from gravity, forcefields etc. to be re-applied in collision response) */
+ sub_v3_v3v3(col.acc, pa->state.vel, pa->prev_state.vel);
+ mul_v3_fl(col.acc, 1.f / col.total_time);
+
+ /* set values for first iteration */
+ copy_v3_v3(col.co1, pa->prev_state.co);
+ copy_v3_v3(col.co2, pa->state.co);
+ copy_v3_v3(col.ve1, pa->prev_state.vel);
+ copy_v3_v3(col.ve2, pa->state.vel);
+ col.f = 0.0f;
+
+ col.radius = ((part->flag & PART_SIZE_DEFL) || (part->phystype == PART_PHYS_BOIDS)) ?
+ pa->size :
+ COLLISION_MIN_RADIUS;
+
+ /* override for boids */
+ if (part->phystype == PART_PHYS_BOIDS && part->boids->options & BOID_ALLOW_LAND) {
+ col.boid = 1;
+ col.boid_z = pa->state.co[2];
+ col.skip[col.skip_count++] = pa->boid->ground;
+ }
+
+ /* 10 iterations to catch multiple collisions */
+ while (collision_count < PARTICLE_COLLISION_MAX_COLLISIONS) {
+ if (collision_detect(pa, &col, &hit, sim->colliders)) {
+
+ collision_count++;
+
+ if (collision_count == PARTICLE_COLLISION_MAX_COLLISIONS)
+ collision_fail(pa, &col);
+ else if (collision_response(
+ sim, pa, &col, &hit, part->flag & PART_DIE_ON_COL, part->flag & PART_ROT_DYN) ==
+ 0)
+ return;
+ }
+ else
+ return;
+ }
}
/************************************************/
-/* Hair */
+/* Hair */
/************************************************/
/* check if path cache or children need updating and do it if needed */
-static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, const bool use_render_params)
+static void psys_update_path_cache(ParticleSimulationData *sim,
+ float cfra,
+ const bool use_render_params)
{
- ParticleSystem *psys = sim->psys;
- ParticleSettings *part = psys->part;
- ParticleEditSettings *pset = &sim->scene->toolsettings->particle;
- int distr=0, alloc=0, skip=0;
-
- if ((psys->part->childtype && psys->totchild != psys_get_tot_child(sim->scene, psys, use_render_params)) || psys->recalc&ID_RECALC_PSYS_RESET)
- alloc=1;
-
- if (alloc || psys->recalc&ID_RECALC_PSYS_CHILD || (psys->vgroup[PSYS_VG_DENSITY] && (sim->ob && sim->ob->mode & OB_MODE_WEIGHT_PAINT)))
- distr=1;
-
- if (distr) {
- if (alloc)
- realloc_particles(sim, sim->psys->totpart);
-
- if (psys_get_tot_child(sim->scene, psys, use_render_params)) {
- /* don't generate children while computing the hair keys */
- if (!(psys->part->type == PART_HAIR) || (psys->flag & PSYS_HAIR_DONE)) {
- distribute_particles(sim, PART_FROM_CHILD);
-
- if (part->childtype==PART_CHILD_FACES && part->parents != 0.0f)
- psys_find_parents(sim, use_render_params);
- }
- }
- else
- psys_free_children(psys);
- }
-
- if ((part->type==PART_HAIR || psys->flag&PSYS_KEYED || psys->pointcache->flag & PTCACHE_BAKED)==0)
- skip = 1; /* only hair, keyed and baked stuff can have paths */
- else if (part->ren_as != PART_DRAW_PATH && !(part->type==PART_HAIR && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)))
- skip = 1; /* particle visualization must be set as path */
- else if (DEG_get_mode(sim->depsgraph) != DAG_EVAL_RENDER) {
- if (part->draw_as != PART_DRAW_REND)
- skip = 1; /* draw visualization */
- else if (psys->pointcache->flag & PTCACHE_BAKING)
- skip = 1; /* no need to cache paths while baking dynamics */
-
- else if (psys_in_edit_mode(sim->depsgraph, psys)) {
- if ((pset->flag & PE_DRAW_PART)==0)
- skip = 1;
- else if (part->childtype==0 && (psys->flag & PSYS_HAIR_DYNAMICS && psys->pointcache->flag & PTCACHE_BAKED)==0)
- skip = 1; /* in edit mode paths are needed for child particles and dynamic hair */
- }
- }
-
- if (!skip) {
- psys_cache_paths(sim, cfra, use_render_params);
-
- /* for render, child particle paths are computed on the fly */
- if (part->childtype) {
- if (!psys->totchild)
- skip = 1;
- else if (psys->part->type == PART_HAIR && (psys->flag & PSYS_HAIR_DONE)==0)
- skip = 1;
-
- if (!skip)
- psys_cache_child_paths(sim, cfra, 0, use_render_params);
- }
- }
- else if (psys->pathcache)
- psys_free_path_cache(psys, NULL);
+ ParticleSystem *psys = sim->psys;
+ ParticleSettings *part = psys->part;
+ ParticleEditSettings *pset = &sim->scene->toolsettings->particle;
+ int distr = 0, alloc = 0, skip = 0;
+
+ if ((psys->part->childtype &&
+ psys->totchild != psys_get_tot_child(sim->scene, psys, use_render_params)) ||
+ psys->recalc & ID_RECALC_PSYS_RESET)
+ alloc = 1;
+
+ if (alloc || psys->recalc & ID_RECALC_PSYS_CHILD ||
+ (psys->vgroup[PSYS_VG_DENSITY] && (sim->ob && sim->ob->mode & OB_MODE_WEIGHT_PAINT)))
+ distr = 1;
+
+ if (distr) {
+ if (alloc)
+ realloc_particles(sim, sim->psys->totpart);
+
+ if (psys_get_tot_child(sim->scene, psys, use_render_params)) {
+ /* don't generate children while computing the hair keys */
+ if (!(psys->part->type == PART_HAIR) || (psys->flag & PSYS_HAIR_DONE)) {
+ distribute_particles(sim, PART_FROM_CHILD);
+
+ if (part->childtype == PART_CHILD_FACES && part->parents != 0.0f)
+ psys_find_parents(sim, use_render_params);
+ }
+ }
+ else
+ psys_free_children(psys);
+ }
+
+ if ((part->type == PART_HAIR || psys->flag & PSYS_KEYED ||
+ psys->pointcache->flag & PTCACHE_BAKED) == 0)
+ skip = 1; /* only hair, keyed and baked stuff can have paths */
+ else if (part->ren_as != PART_DRAW_PATH &&
+ !(part->type == PART_HAIR && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)))
+ skip = 1; /* particle visualization must be set as path */
+ else if (DEG_get_mode(sim->depsgraph) != DAG_EVAL_RENDER) {
+ if (part->draw_as != PART_DRAW_REND)
+ skip = 1; /* draw visualization */
+ else if (psys->pointcache->flag & PTCACHE_BAKING)
+ skip = 1; /* no need to cache paths while baking dynamics */
+
+ else if (psys_in_edit_mode(sim->depsgraph, psys)) {
+ if ((pset->flag & PE_DRAW_PART) == 0)
+ skip = 1;
+ else if (part->childtype == 0 &&
+ (psys->flag & PSYS_HAIR_DYNAMICS && psys->pointcache->flag & PTCACHE_BAKED) == 0)
+ skip = 1; /* in edit mode paths are needed for child particles and dynamic hair */
+ }
+ }
+
+ if (!skip) {
+ psys_cache_paths(sim, cfra, use_render_params);
+
+ /* for render, child particle paths are computed on the fly */
+ if (part->childtype) {
+ if (!psys->totchild)
+ skip = 1;
+ else if (psys->part->type == PART_HAIR && (psys->flag & PSYS_HAIR_DONE) == 0)
+ skip = 1;
+
+ if (!skip)
+ psys_cache_child_paths(sim, cfra, 0, use_render_params);
+ }
+ }
+ else if (psys->pathcache)
+ psys_free_path_cache(psys, NULL);
}
static bool psys_hair_use_simulation(ParticleData *pa, float max_length)
{
- /* Minimum segment length relative to average length.
- * Hairs with segments below this length will be excluded from the simulation,
- * because otherwise the solver will become unstable.
- * The hair system should always make sure the hair segments have reasonable length ratios,
- * but this can happen in old files when e.g. cutting hair.
- */
- const float min_length = 0.1f * max_length;
-
- HairKey *key;
- int k;
-
- if (pa->totkey < 2)
- return false;
-
- for (k=1, key=pa->hair+1; k<pa->totkey; k++,key++) {
- float length = len_v3v3(key->co, (key-1)->co);
- if (length < min_length)
- return false;
- }
-
- return true;
+ /* Minimum segment length relative to average length.
+ * Hairs with segments below this length will be excluded from the simulation,
+ * because otherwise the solver will become unstable.
+ * The hair system should always make sure the hair segments have reasonable length ratios,
+ * but this can happen in old files when e.g. cutting hair.
+ */
+ const float min_length = 0.1f * max_length;
+
+ HairKey *key;
+ int k;
+
+ if (pa->totkey < 2)
+ return false;
+
+ for (k = 1, key = pa->hair + 1; k < pa->totkey; k++, key++) {
+ float length = len_v3v3(key->co, (key - 1)->co);
+ if (length < min_length)
+ return false;
+ }
+
+ return true;
}
static MDeformVert *hair_set_pinning(MDeformVert *dvert, float weight)
{
- if (dvert) {
- if (!dvert->totweight) {
- dvert->dw = MEM_callocN(sizeof(MDeformWeight), "deformWeight");
- dvert->totweight = 1;
- }
-
- dvert->dw->weight = weight;
- dvert++;
- }
- return dvert;
+ if (dvert) {
+ if (!dvert->totweight) {
+ dvert->dw = MEM_callocN(sizeof(MDeformWeight), "deformWeight");
+ dvert->totweight = 1;
+ }
+
+ dvert->dw->weight = weight;
+ dvert++;
+ }
+ return dvert;
}
-static void hair_create_input_mesh(ParticleSimulationData *sim, int totpoint, int totedge, Mesh **r_mesh, ClothHairData **r_hairdata)
+static void hair_create_input_mesh(ParticleSimulationData *sim,
+ int totpoint,
+ int totedge,
+ Mesh **r_mesh,
+ ClothHairData **r_hairdata)
{
- ParticleSystem *psys = sim->psys;
- ParticleSettings *part = psys->part;
- Mesh *mesh;
- ClothHairData *hairdata;
- MVert *mvert;
- MEdge *medge;
- MDeformVert *dvert;
- HairKey *key;
- PARTICLE_P;
- int k, hair_index;
- float hairmat[4][4];
- float max_length;
- float hair_radius;
-
- mesh = *r_mesh;
- if (!mesh) {
- *r_mesh = mesh = BKE_mesh_new_nomain(totpoint, totedge, 0, 0, 0);
- CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, mesh->totvert);
- BKE_mesh_update_customdata_pointers(mesh, false);
- }
- mvert = mesh->mvert;
- medge = mesh->medge;
- dvert = mesh->dvert;
-
- hairdata = *r_hairdata;
- if (!hairdata) {
- *r_hairdata = hairdata = MEM_mallocN(sizeof(ClothHairData) * totpoint, "hair data");
- }
-
- /* calculate maximum segment length */
- max_length = 0.0f;
- LOOP_PARTICLES {
- if (!(pa->flag & PARS_UNEXIST)) {
- for (k=1, key=pa->hair+1; k<pa->totkey; k++,key++) {
- float length = len_v3v3(key->co, (key-1)->co);
- if (max_length < length)
- max_length = length;
- }
- }
- }
-
- psys->clmd->sim_parms->vgroup_mass = 1;
-
- /* XXX placeholder for more flexible future hair settings */
- hair_radius = part->size;
-
- /* make vgroup for pin roots etc.. */
- hair_index = 1;
- LOOP_PARTICLES {
- if (!(pa->flag & PARS_UNEXIST)) {
- float root_mat[4][4];
- float bending_stiffness;
- bool use_hair;
-
- pa->hair_index = hair_index;
- use_hair = psys_hair_use_simulation(pa, max_length);
-
- psys_mat_hair_to_object(sim->ob, sim->psmd->mesh_final, psys->part->from, pa, hairmat);
- mul_m4_m4m4(root_mat, sim->ob->obmat, hairmat);
- normalize_m4(root_mat);
-
- bending_stiffness = CLAMPIS(1.0f - part->bending_random * psys_frand(psys, p + 666), 0.0f, 1.0f);
-
- for (k=0, key=pa->hair; k<pa->totkey; k++,key++) {
- ClothHairData *hair;
- float *co, *co_next;
-
- co = key->co;
- co_next = (key+1)->co;
-
- /* create fake root before actual root to resist bending */
- if (k==0) {
- hair = &psys->clmd->hairdata[pa->hair_index - 1];
- copy_v3_v3(hair->loc, root_mat[3]);
- copy_m3_m4(hair->rot, root_mat);
-
- hair->radius = hair_radius;
- hair->bending_stiffness = bending_stiffness;
-
- add_v3_v3v3(mvert->co, co, co);
- sub_v3_v3(mvert->co, co_next);
- mul_m4_v3(hairmat, mvert->co);
-
- medge->v1 = pa->hair_index - 1;
- medge->v2 = pa->hair_index;
-
- dvert = hair_set_pinning(dvert, 1.0f);
-
- mvert++;
- medge++;
- }
-
- /* store root transform in cloth data */
- hair = &psys->clmd->hairdata[pa->hair_index + k];
- copy_v3_v3(hair->loc, root_mat[3]);
- copy_m3_m4(hair->rot, root_mat);
-
- hair->radius = hair_radius;
- hair->bending_stiffness = bending_stiffness;
-
- copy_v3_v3(mvert->co, co);
- mul_m4_v3(hairmat, mvert->co);
-
- if (k) {
- medge->v1 = pa->hair_index + k - 1;
- medge->v2 = pa->hair_index + k;
- }
-
- /* roots and disabled hairs should be 1.0, the rest can be anything from 0.0 to 1.0 */
- if (use_hair)
- dvert = hair_set_pinning(dvert, key->weight);
- else
- dvert = hair_set_pinning(dvert, 1.0f);
-
- mvert++;
- if (k)
- medge++;
- }
-
- hair_index += pa->totkey + 1;
- }
- }
+ ParticleSystem *psys = sim->psys;
+ ParticleSettings *part = psys->part;
+ Mesh *mesh;
+ ClothHairData *hairdata;
+ MVert *mvert;
+ MEdge *medge;
+ MDeformVert *dvert;
+ HairKey *key;
+ PARTICLE_P;
+ int k, hair_index;
+ float hairmat[4][4];
+ float max_length;
+ float hair_radius;
+
+ mesh = *r_mesh;
+ if (!mesh) {
+ *r_mesh = mesh = BKE_mesh_new_nomain(totpoint, totedge, 0, 0, 0);
+ CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, mesh->totvert);
+ BKE_mesh_update_customdata_pointers(mesh, false);
+ }
+ mvert = mesh->mvert;
+ medge = mesh->medge;
+ dvert = mesh->dvert;
+
+ hairdata = *r_hairdata;
+ if (!hairdata) {
+ *r_hairdata = hairdata = MEM_mallocN(sizeof(ClothHairData) * totpoint, "hair data");
+ }
+
+ /* calculate maximum segment length */
+ max_length = 0.0f;
+ LOOP_PARTICLES
+ {
+ if (!(pa->flag & PARS_UNEXIST)) {
+ for (k = 1, key = pa->hair + 1; k < pa->totkey; k++, key++) {
+ float length = len_v3v3(key->co, (key - 1)->co);
+ if (max_length < length)
+ max_length = length;
+ }
+ }
+ }
+
+ psys->clmd->sim_parms->vgroup_mass = 1;
+
+ /* XXX placeholder for more flexible future hair settings */
+ hair_radius = part->size;
+
+ /* make vgroup for pin roots etc.. */
+ hair_index = 1;
+ LOOP_PARTICLES
+ {
+ if (!(pa->flag & PARS_UNEXIST)) {
+ float root_mat[4][4];
+ float bending_stiffness;
+ bool use_hair;
+
+ pa->hair_index = hair_index;
+ use_hair = psys_hair_use_simulation(pa, max_length);
+
+ psys_mat_hair_to_object(sim->ob, sim->psmd->mesh_final, psys->part->from, pa, hairmat);
+ mul_m4_m4m4(root_mat, sim->ob->obmat, hairmat);
+ normalize_m4(root_mat);
+
+ bending_stiffness = CLAMPIS(
+ 1.0f - part->bending_random * psys_frand(psys, p + 666), 0.0f, 1.0f);
+
+ for (k = 0, key = pa->hair; k < pa->totkey; k++, key++) {
+ ClothHairData *hair;
+ float *co, *co_next;
+
+ co = key->co;
+ co_next = (key + 1)->co;
+
+ /* create fake root before actual root to resist bending */
+ if (k == 0) {
+ hair = &psys->clmd->hairdata[pa->hair_index - 1];
+ copy_v3_v3(hair->loc, root_mat[3]);
+ copy_m3_m4(hair->rot, root_mat);
+
+ hair->radius = hair_radius;
+ hair->bending_stiffness = bending_stiffness;
+
+ add_v3_v3v3(mvert->co, co, co);
+ sub_v3_v3(mvert->co, co_next);
+ mul_m4_v3(hairmat, mvert->co);
+
+ medge->v1 = pa->hair_index - 1;
+ medge->v2 = pa->hair_index;
+
+ dvert = hair_set_pinning(dvert, 1.0f);
+
+ mvert++;
+ medge++;
+ }
+
+ /* store root transform in cloth data */
+ hair = &psys->clmd->hairdata[pa->hair_index + k];
+ copy_v3_v3(hair->loc, root_mat[3]);
+ copy_m3_m4(hair->rot, root_mat);
+
+ hair->radius = hair_radius;
+ hair->bending_stiffness = bending_stiffness;
+
+ copy_v3_v3(mvert->co, co);
+ mul_m4_v3(hairmat, mvert->co);
+
+ if (k) {
+ medge->v1 = pa->hair_index + k - 1;
+ medge->v2 = pa->hair_index + k;
+ }
+
+ /* roots and disabled hairs should be 1.0, the rest can be anything from 0.0 to 1.0 */
+ if (use_hair)
+ dvert = hair_set_pinning(dvert, key->weight);
+ else
+ dvert = hair_set_pinning(dvert, 1.0f);
+
+ mvert++;
+ if (k)
+ medge++;
+ }
+
+ hair_index += pa->totkey + 1;
+ }
+ }
}
static void do_hair_dynamics(ParticleSimulationData *sim)
{
- ParticleSystem *psys = sim->psys;
- PARTICLE_P;
- EffectorWeights *clmd_effweights;
- int totpoint;
- int totedge;
- float (*deformedVerts)[3];
- bool realloc_roots;
-
- if (!psys->clmd) {
- psys->clmd = (ClothModifierData*)modifier_new(eModifierType_Cloth);
- psys->clmd->sim_parms->goalspring = 0.0f;
- psys->clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_RESIST_SPRING_COMPRESS;
- psys->clmd->coll_parms->flags &= ~CLOTH_COLLSETTINGS_FLAG_SELF;
- }
-
- /* count simulated points */
- totpoint = 0;
- totedge = 0;
- LOOP_PARTICLES {
- if (!(pa->flag & PARS_UNEXIST)) {
- /* "out" dm contains all hairs */
- totedge += pa->totkey;
- totpoint += pa->totkey + 1; /* +1 for virtual root point */
- }
- }
-
- /* whether hair root info array has to be reallocated */
- realloc_roots = false;
- if (psys->hair_in_mesh) {
- Mesh *mesh = psys->hair_in_mesh;
- if (totpoint != mesh->totvert || totedge != mesh->totedge) {
- BKE_id_free(NULL, mesh);
- psys->hair_in_mesh = NULL;
- realloc_roots = true;
- }
- }
-
- if (!psys->hair_in_mesh || !psys->clmd->hairdata || realloc_roots) {
- if (psys->clmd->hairdata) {
- MEM_freeN(psys->clmd->hairdata);
- psys->clmd->hairdata = NULL;
- }
- }
-
- hair_create_input_mesh(sim, totpoint, totedge, &psys->hair_in_mesh, &psys->clmd->hairdata);
-
- if (psys->hair_out_mesh)
- BKE_id_free(NULL, psys->hair_out_mesh);
-
- psys->clmd->point_cache = psys->pointcache;
- /* for hair sim we replace the internal cloth effector weights temporarily
- * to use the particle settings
- */
- clmd_effweights = psys->clmd->sim_parms->effector_weights;
- psys->clmd->sim_parms->effector_weights = psys->part->effector_weights;
-
- BKE_id_copy_ex(NULL, &psys->hair_in_mesh->id, (ID **)&psys->hair_out_mesh, LIB_ID_COPY_LOCALIZE);
- deformedVerts = BKE_mesh_vertexCos_get(psys->hair_out_mesh, NULL);
- clothModifier_do(psys->clmd, sim->depsgraph, sim->scene, sim->ob, psys->hair_in_mesh, deformedVerts);
- BKE_mesh_apply_vert_coords(psys->hair_out_mesh, deformedVerts);
-
- MEM_freeN(deformedVerts);
-
- /* restore cloth effector weights */
- psys->clmd->sim_parms->effector_weights = clmd_effweights;
+ ParticleSystem *psys = sim->psys;
+ PARTICLE_P;
+ EffectorWeights *clmd_effweights;
+ int totpoint;
+ int totedge;
+ float(*deformedVerts)[3];
+ bool realloc_roots;
+
+ if (!psys->clmd) {
+ psys->clmd = (ClothModifierData *)modifier_new(eModifierType_Cloth);
+ psys->clmd->sim_parms->goalspring = 0.0f;
+ psys->clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_RESIST_SPRING_COMPRESS;
+ psys->clmd->coll_parms->flags &= ~CLOTH_COLLSETTINGS_FLAG_SELF;
+ }
+
+ /* count simulated points */
+ totpoint = 0;
+ totedge = 0;
+ LOOP_PARTICLES
+ {
+ if (!(pa->flag & PARS_UNEXIST)) {
+ /* "out" dm contains all hairs */
+ totedge += pa->totkey;
+ totpoint += pa->totkey + 1; /* +1 for virtual root point */
+ }
+ }
+
+ /* whether hair root info array has to be reallocated */
+ realloc_roots = false;
+ if (psys->hair_in_mesh) {
+ Mesh *mesh = psys->hair_in_mesh;
+ if (totpoint != mesh->totvert || totedge != mesh->totedge) {
+ BKE_id_free(NULL, mesh);
+ psys->hair_in_mesh = NULL;
+ realloc_roots = true;
+ }
+ }
+
+ if (!psys->hair_in_mesh || !psys->clmd->hairdata || realloc_roots) {
+ if (psys->clmd->hairdata) {
+ MEM_freeN(psys->clmd->hairdata);
+ psys->clmd->hairdata = NULL;
+ }
+ }
+
+ hair_create_input_mesh(sim, totpoint, totedge, &psys->hair_in_mesh, &psys->clmd->hairdata);
+
+ if (psys->hair_out_mesh)
+ BKE_id_free(NULL, psys->hair_out_mesh);
+
+ psys->clmd->point_cache = psys->pointcache;
+ /* for hair sim we replace the internal cloth effector weights temporarily
+ * to use the particle settings
+ */
+ clmd_effweights = psys->clmd->sim_parms->effector_weights;
+ psys->clmd->sim_parms->effector_weights = psys->part->effector_weights;
+
+ BKE_id_copy_ex(NULL, &psys->hair_in_mesh->id, (ID **)&psys->hair_out_mesh, LIB_ID_COPY_LOCALIZE);
+ deformedVerts = BKE_mesh_vertexCos_get(psys->hair_out_mesh, NULL);
+ clothModifier_do(
+ psys->clmd, sim->depsgraph, sim->scene, sim->ob, psys->hair_in_mesh, deformedVerts);
+ BKE_mesh_apply_vert_coords(psys->hair_out_mesh, deformedVerts);
+
+ MEM_freeN(deformedVerts);
+
+ /* restore cloth effector weights */
+ psys->clmd->sim_parms->effector_weights = clmd_effweights;
}
static void hair_step(ParticleSimulationData *sim, float cfra, const bool use_render_params)
{
- ParticleSystem *psys = sim->psys;
- ParticleSettings *part = psys->part;
- PARTICLE_P;
- float disp = psys_get_current_display_percentage(psys, use_render_params);
-
- LOOP_PARTICLES {
- pa->size = part->size;
- if (part->randsize > 0.0f)
- pa->size *= 1.0f - part->randsize * psys_frand(psys, p + 1);
-
- if (psys_frand(psys, p) > disp)
- pa->flag |= PARS_NO_DISP;
- else
- pa->flag &= ~PARS_NO_DISP;
- }
-
- if (psys->recalc & ID_RECALC_PSYS_RESET) {
- /* need this for changing subsurf levels */
- psys_calc_dmcache(sim->ob, sim->psmd->mesh_final, sim->psmd->mesh_original, psys);
-
- if (psys->clmd)
- cloth_free_modifier(psys->clmd);
- }
-
- /* dynamics with cloth simulation, psys->particles can be NULL with 0 particles [#25519] */
- if (psys->part->type==PART_HAIR && psys->flag & PSYS_HAIR_DYNAMICS && psys->particles)
- do_hair_dynamics(sim);
-
- /* following lines were removed r29079 but cause bug [#22811], see report for details */
- psys_update_effectors(sim);
- psys_update_path_cache(sim, cfra, use_render_params);
-
- psys->flag |= PSYS_HAIR_UPDATED;
+ ParticleSystem *psys = sim->psys;
+ ParticleSettings *part = psys->part;
+ PARTICLE_P;
+ float disp = psys_get_current_display_percentage(psys, use_render_params);
+
+ LOOP_PARTICLES
+ {
+ pa->size = part->size;
+ if (part->randsize > 0.0f)
+ pa->size *= 1.0f - part->randsize * psys_frand(psys, p + 1);
+
+ if (psys_frand(psys, p) > disp)
+ pa->flag |= PARS_NO_DISP;
+ else
+ pa->flag &= ~PARS_NO_DISP;
+ }
+
+ if (psys->recalc & ID_RECALC_PSYS_RESET) {
+ /* need this for changing subsurf levels */
+ psys_calc_dmcache(sim->ob, sim->psmd->mesh_final, sim->psmd->mesh_original, psys);
+
+ if (psys->clmd)
+ cloth_free_modifier(psys->clmd);
+ }
+
+ /* dynamics with cloth simulation, psys->particles can be NULL with 0 particles [#25519] */
+ if (psys->part->type == PART_HAIR && psys->flag & PSYS_HAIR_DYNAMICS && psys->particles)
+ do_hair_dynamics(sim);
+
+ /* following lines were removed r29079 but cause bug [#22811], see report for details */
+ psys_update_effectors(sim);
+ psys_update_path_cache(sim, cfra, use_render_params);
+
+ psys->flag |= PSYS_HAIR_UPDATED;
}
static void save_hair(ParticleSimulationData *sim, float UNUSED(cfra))
{
- Object *ob = sim->ob;
- ParticleSystem *psys = sim->psys;
- HairKey *key, *root;
- PARTICLE_P;
-
- invert_m4_m4(ob->imat, ob->obmat);
+ Object *ob = sim->ob;
+ ParticleSystem *psys = sim->psys;
+ HairKey *key, *root;
+ PARTICLE_P;
- psys->lattice_deform_data= psys_create_lattice_deform_data(sim);
+ invert_m4_m4(ob->imat, ob->obmat);
- if (psys->totpart==0) return;
+ psys->lattice_deform_data = psys_create_lattice_deform_data(sim);
- /* save new keys for elements if needed */
- LOOP_PARTICLES {
- /* first time alloc */
- if (pa->totkey==0 || pa->hair==NULL) {
- pa->hair = MEM_callocN((psys->part->hair_step + 1) * sizeof(HairKey), "HairKeys");
- pa->totkey = 0;
- }
+ if (psys->totpart == 0)
+ return;
- key = root = pa->hair;
- key += pa->totkey;
+ /* save new keys for elements if needed */
+ LOOP_PARTICLES
+ {
+ /* first time alloc */
+ if (pa->totkey == 0 || pa->hair == NULL) {
+ pa->hair = MEM_callocN((psys->part->hair_step + 1) * sizeof(HairKey), "HairKeys");
+ pa->totkey = 0;
+ }
- /* convert from global to geometry space */
- copy_v3_v3(key->co, pa->state.co);
- mul_m4_v3(ob->imat, key->co);
+ key = root = pa->hair;
+ key += pa->totkey;
- if (pa->totkey) {
- sub_v3_v3(key->co, root->co);
- psys_vec_rot_to_face(sim->psmd->mesh_final, pa, key->co);
- }
+ /* convert from global to geometry space */
+ copy_v3_v3(key->co, pa->state.co);
+ mul_m4_v3(ob->imat, key->co);
- key->time = pa->state.time;
+ if (pa->totkey) {
+ sub_v3_v3(key->co, root->co);
+ psys_vec_rot_to_face(sim->psmd->mesh_final, pa, key->co);
+ }
- key->weight = 1.0f - key->time / 100.0f;
+ key->time = pa->state.time;
- pa->totkey++;
+ key->weight = 1.0f - key->time / 100.0f;
- /* root is always in the origin of hair space so we set it to be so after the last key is saved*/
- if (pa->totkey == psys->part->hair_step + 1) {
- zero_v3(root->co);
- }
+ pa->totkey++;
- }
+ /* root is always in the origin of hair space so we set it to be so after the last key is saved*/
+ if (pa->totkey == psys->part->hair_step + 1) {
+ zero_v3(root->co);
+ }
+ }
}
/* Code for an adaptive time step based on the Courant-Friedrichs-Lewy
@@ -3309,611 +3447,620 @@ static const float TIMESTEP_EXPANSION_TOLERANCE = 1.5f;
* simulation. This should be called once per particle during a simulation
* step, after the velocity has been updated. element_size defines the scale of
* the simulation, and is typically the distance to neighboring particles. */
-static void update_courant_num(ParticleSimulationData *sim, ParticleData *pa,
- float dtime, SPHData *sphdata, SpinLock *spin)
+static void update_courant_num(
+ ParticleSimulationData *sim, ParticleData *pa, float dtime, SPHData *sphdata, SpinLock *spin)
{
- float relative_vel[3];
-
- sub_v3_v3v3(relative_vel, pa->prev_state.vel, sphdata->flow);
-
- const float courant_num = len_v3(relative_vel) * dtime / sphdata->element_size;
- if (sim->courant_num < courant_num) {
- BLI_spin_lock(spin);
- if (sim->courant_num < courant_num) {
- sim->courant_num = courant_num;
- }
- BLI_spin_unlock(spin);
- }
+ float relative_vel[3];
+
+ sub_v3_v3v3(relative_vel, pa->prev_state.vel, sphdata->flow);
+
+ const float courant_num = len_v3(relative_vel) * dtime / sphdata->element_size;
+ if (sim->courant_num < courant_num) {
+ BLI_spin_lock(spin);
+ if (sim->courant_num < courant_num) {
+ sim->courant_num = courant_num;
+ }
+ BLI_spin_unlock(spin);
+ }
}
static float get_base_time_step(ParticleSettings *part)
{
- return 1.0f / (float) (part->subframes + 1);
+ return 1.0f / (float)(part->subframes + 1);
}
/* Update time step size to suit current conditions. */
static void update_timestep(ParticleSystem *psys, ParticleSimulationData *sim)
{
- float dt_target;
- if (sim->courant_num == 0.0f)
- dt_target = 1.0f;
- else
- dt_target = psys->dt_frac * (psys->part->courant_target / sim->courant_num);
-
- /* Make sure the time step is reasonable. For some reason, the CLAMP macro
- * doesn't work here. The time step becomes too large. - z0r */
- if (dt_target < MIN_TIMESTEP)
- dt_target = MIN_TIMESTEP;
- else if (dt_target > get_base_time_step(psys->part))
- dt_target = get_base_time_step(psys->part);
-
- /* Decrease time step instantly, but increase slowly. */
- if (dt_target > psys->dt_frac)
- psys->dt_frac = interpf(dt_target, psys->dt_frac, TIMESTEP_EXPANSION_FACTOR);
- else
- psys->dt_frac = dt_target;
+ float dt_target;
+ if (sim->courant_num == 0.0f)
+ dt_target = 1.0f;
+ else
+ dt_target = psys->dt_frac * (psys->part->courant_target / sim->courant_num);
+
+ /* Make sure the time step is reasonable. For some reason, the CLAMP macro
+ * doesn't work here. The time step becomes too large. - z0r */
+ if (dt_target < MIN_TIMESTEP)
+ dt_target = MIN_TIMESTEP;
+ else if (dt_target > get_base_time_step(psys->part))
+ dt_target = get_base_time_step(psys->part);
+
+ /* Decrease time step instantly, but increase slowly. */
+ if (dt_target > psys->dt_frac)
+ psys->dt_frac = interpf(dt_target, psys->dt_frac, TIMESTEP_EXPANSION_FACTOR);
+ else
+ psys->dt_frac = dt_target;
}
static float sync_timestep(ParticleSystem *psys, float t_frac)
{
- /* Sync with frame end if it's close. */
- if (t_frac == 1.0f)
- return psys->dt_frac;
- else if (t_frac + (psys->dt_frac * TIMESTEP_EXPANSION_TOLERANCE) >= 1.0f)
- return 1.0f - t_frac;
- else
- return psys->dt_frac;
+ /* Sync with frame end if it's close. */
+ if (t_frac == 1.0f)
+ return psys->dt_frac;
+ else if (t_frac + (psys->dt_frac * TIMESTEP_EXPANSION_TOLERANCE) >= 1.0f)
+ return 1.0f - t_frac;
+ else
+ return psys->dt_frac;
}
/************************************************/
-/* System Core */
+/* System Core */
/************************************************/
typedef struct DynamicStepSolverTaskData {
- ParticleSimulationData *sim;
+ ParticleSimulationData *sim;
- float cfra;
- float timestep;
- float dtime;
+ float cfra;
+ float timestep;
+ float dtime;
- SpinLock spin;
+ SpinLock spin;
} DynamicStepSolverTaskData;
-static void dynamics_step_sph_ddr_task_cb_ex(
- void *__restrict userdata,
- const int p,
- const ParallelRangeTLS *__restrict tls)
+static void dynamics_step_sph_ddr_task_cb_ex(void *__restrict userdata,
+ const int p,
+ const ParallelRangeTLS *__restrict tls)
{
- DynamicStepSolverTaskData *data = userdata;
- ParticleSimulationData *sim = data->sim;
- ParticleSystem *psys = sim->psys;
- ParticleSettings *part = psys->part;
+ DynamicStepSolverTaskData *data = userdata;
+ ParticleSimulationData *sim = data->sim;
+ ParticleSystem *psys = sim->psys;
+ ParticleSettings *part = psys->part;
- SPHData *sphdata = tls->userdata_chunk;
+ SPHData *sphdata = tls->userdata_chunk;
- ParticleData *pa;
+ ParticleData *pa;
- if ((pa = psys->particles + p)->state.time <= 0.0f) {
- return;
- }
+ if ((pa = psys->particles + p)->state.time <= 0.0f) {
+ return;
+ }
- /* do global forces & effectors */
- basic_integrate(sim, p, pa->state.time, data->cfra);
+ /* do global forces & effectors */
+ basic_integrate(sim, p, pa->state.time, data->cfra);
- /* actual fluids calculations */
- sph_integrate(sim, pa, pa->state.time, sphdata);
+ /* actual fluids calculations */
+ sph_integrate(sim, pa, pa->state.time, sphdata);
- if (sim->colliders)
- collision_check(sim, p, pa->state.time, data->cfra);
+ if (sim->colliders)
+ collision_check(sim, p, pa->state.time, data->cfra);
- /* SPH particles are not physical particles, just interpolation
- * particles, thus rotation has not a direct sense for them */
- basic_rotate(part, pa, pa->state.time, data->timestep);
+ /* SPH particles are not physical particles, just interpolation
+ * particles, thus rotation has not a direct sense for them */
+ basic_rotate(part, pa, pa->state.time, data->timestep);
- if (part->time_flag & PART_TIME_AUTOSF) {
- update_courant_num(sim, pa, data->dtime, sphdata, &data->spin);
- }
+ if (part->time_flag & PART_TIME_AUTOSF) {
+ update_courant_num(sim, pa, data->dtime, sphdata, &data->spin);
+ }
}
static void dynamics_step_sph_classical_basic_integrate_task_cb_ex(
- void *__restrict userdata,
- const int p,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+ void *__restrict userdata, const int p, const ParallelRangeTLS *__restrict UNUSED(tls))
{
- DynamicStepSolverTaskData *data = userdata;
- ParticleSimulationData *sim = data->sim;
- ParticleSystem *psys = sim->psys;
+ DynamicStepSolverTaskData *data = userdata;
+ ParticleSimulationData *sim = data->sim;
+ ParticleSystem *psys = sim->psys;
- ParticleData *pa;
+ ParticleData *pa;
- if ((pa = psys->particles + p)->state.time <= 0.0f) {
- return;
- }
+ if ((pa = psys->particles + p)->state.time <= 0.0f) {
+ return;
+ }
- basic_integrate(sim, p, pa->state.time, data->cfra);
+ basic_integrate(sim, p, pa->state.time, data->cfra);
}
static void dynamics_step_sph_classical_calc_density_task_cb_ex(
- void *__restrict userdata,
- const int p,
- const ParallelRangeTLS *__restrict tls)
+ void *__restrict userdata, const int p, const ParallelRangeTLS *__restrict tls)
{
- DynamicStepSolverTaskData *data = userdata;
- ParticleSimulationData *sim = data->sim;
- ParticleSystem *psys = sim->psys;
+ DynamicStepSolverTaskData *data = userdata;
+ ParticleSimulationData *sim = data->sim;
+ ParticleSystem *psys = sim->psys;
- SPHData *sphdata = tls->userdata_chunk;
+ SPHData *sphdata = tls->userdata_chunk;
- ParticleData *pa;
+ ParticleData *pa;
- if ((pa = psys->particles + p)->state.time <= 0.0f) {
- return;
- }
+ if ((pa = psys->particles + p)->state.time <= 0.0f) {
+ return;
+ }
- sphclassical_calc_dens(pa, pa->state.time, sphdata);
+ sphclassical_calc_dens(pa, pa->state.time, sphdata);
}
static void dynamics_step_sph_classical_integrate_task_cb_ex(
- void *__restrict userdata,
- const int p,
- const ParallelRangeTLS *__restrict tls)
+ void *__restrict userdata, const int p, const ParallelRangeTLS *__restrict tls)
{
- DynamicStepSolverTaskData *data = userdata;
- ParticleSimulationData *sim = data->sim;
- ParticleSystem *psys = sim->psys;
- ParticleSettings *part = psys->part;
+ DynamicStepSolverTaskData *data = userdata;
+ ParticleSimulationData *sim = data->sim;
+ ParticleSystem *psys = sim->psys;
+ ParticleSettings *part = psys->part;
- SPHData *sphdata = tls->userdata_chunk;
+ SPHData *sphdata = tls->userdata_chunk;
- ParticleData *pa;
+ ParticleData *pa;
- if ((pa = psys->particles + p)->state.time <= 0.0f) {
- return;
- }
+ if ((pa = psys->particles + p)->state.time <= 0.0f) {
+ return;
+ }
- /* actual fluids calculations */
- sph_integrate(sim, pa, pa->state.time, sphdata);
+ /* actual fluids calculations */
+ sph_integrate(sim, pa, pa->state.time, sphdata);
- if (sim->colliders)
- collision_check(sim, p, pa->state.time, data->cfra);
+ if (sim->colliders)
+ collision_check(sim, p, pa->state.time, data->cfra);
- /* SPH particles are not physical particles, just interpolation
- * particles, thus rotation has not a direct sense for them */
- basic_rotate(part, pa, pa->state.time, data->timestep);
+ /* SPH particles are not physical particles, just interpolation
+ * particles, thus rotation has not a direct sense for them */
+ basic_rotate(part, pa, pa->state.time, data->timestep);
- if (part->time_flag & PART_TIME_AUTOSF) {
- update_courant_num(sim, pa, data->dtime, sphdata, &data->spin);
- }
+ if (part->time_flag & PART_TIME_AUTOSF) {
+ update_courant_num(sim, pa, data->dtime, sphdata, &data->spin);
+ }
}
/* unbaked particles are calculated dynamically */
static void dynamics_step(ParticleSimulationData *sim, float cfra)
{
- ParticleSystem *psys = sim->psys;
- ParticleSettings *part=psys->part;
- BoidBrainData bbd;
- ParticleTexture ptex;
- PARTICLE_P;
- float timestep;
- /* frame & time changes */
- float dfra, dtime;
- float birthtime, dietime;
-
- /* where have we gone in time since last time */
- dfra= cfra - psys->cfra;
-
- timestep = psys_get_timestep(sim);
- dtime= dfra*timestep;
-
- if (dfra < 0.0f) {
- LOOP_EXISTING_PARTICLES {
- psys_get_texture(sim, pa, &ptex, PAMAP_SIZE, cfra);
- pa->size = part->size*ptex.size;
- if (part->randsize > 0.0f)
- pa->size *= 1.0f - part->randsize * psys_frand(psys, p + 1);
-
- reset_particle(sim, pa, dtime, cfra);
- }
- return;
- }
-
- /* for now do both, boids us 'rng' */
- sim->rng = BLI_rng_new_srandom(31415926 + (int)cfra + psys->seed);
-
- psys_update_effectors(sim);
-
- if (part->type != PART_HAIR)
- sim->colliders = BKE_collider_cache_create(sim->depsgraph, sim->ob, part->collision_group);
-
- /* initialize physics type specific stuff */
- switch (part->phystype) {
- case PART_PHYS_BOIDS:
- {
- ParticleTarget *pt = psys->targets.first;
- bbd.sim = sim;
- bbd.part = part;
- bbd.cfra = cfra;
- bbd.dfra = dfra;
- bbd.timestep = timestep;
- bbd.rng = sim->rng;
-
- psys_update_particle_tree(psys, cfra);
-
- boids_precalc_rules(part, cfra);
-
- for (; pt; pt=pt->next) {
- ParticleSystem *psys_target = psys_get_target_system(sim->ob, pt);
- if (psys_target && psys_target != psys) {
- psys_update_particle_tree(psys_target, cfra);
- }
- }
- break;
- }
- case PART_PHYS_FLUID:
- {
- ParticleTarget *pt = psys->targets.first;
- psys_update_particle_bvhtree(psys, cfra);
-
- for (; pt; pt=pt->next) { /* Updating others systems particle tree for fluid-fluid interaction */
- if (pt->ob)
- psys_update_particle_bvhtree(BLI_findlink(&pt->ob->particlesystem, pt->psys-1), cfra);
- }
- break;
- }
- }
- /* initialize all particles for dynamics */
- LOOP_SHOWN_PARTICLES {
- copy_particle_key(&pa->prev_state,&pa->state,1);
-
- psys_get_texture(sim, pa, &ptex, PAMAP_SIZE, cfra);
-
- pa->size = part->size*ptex.size;
- if (part->randsize > 0.0f)
- pa->size *= 1.0f - part->randsize * psys_frand(psys, p + 1);
-
- birthtime = pa->time;
- dietime = pa->dietime;
-
- /* store this, so we can do multiple loops over particles */
- pa->state.time = dfra;
-
- if (dietime <= cfra && psys->cfra < dietime) {
- /* particle dies some time between this and last step */
- pa->state.time = dietime - ((birthtime > psys->cfra) ? birthtime : psys->cfra);
- pa->alive = PARS_DYING;
- }
- else if (birthtime <= cfra && birthtime >= psys->cfra) {
- /* particle is born some time between this and last step*/
- reset_particle(sim, pa, dfra*timestep, cfra);
- pa->alive = PARS_ALIVE;
- pa->state.time = cfra - birthtime;
- }
- else if (dietime < cfra) {
- /* nothing to be done when particle is dead */
- }
-
- /* only reset unborn particles if they're shown or if the particle is born soon*/
- if (pa->alive==PARS_UNBORN && (part->flag & PART_UNBORN || (cfra + psys->pointcache->step > pa->time))) {
- reset_particle(sim, pa, dtime, cfra);
- }
- else if (part->phystype == PART_PHYS_NO) {
- reset_particle(sim, pa, dtime, cfra);
- }
-
- if (ELEM(pa->alive, PARS_ALIVE, PARS_DYING)==0 || (pa->flag & (PARS_UNEXIST|PARS_NO_DISP)))
- pa->state.time = -1.f;
- }
-
- switch (part->phystype) {
- case PART_PHYS_NEWTON:
- {
- LOOP_DYNAMIC_PARTICLES {
- /* do global forces & effectors */
- basic_integrate(sim, p, pa->state.time, cfra);
-
- /* deflection */
- if (sim->colliders)
- collision_check(sim, p, pa->state.time, cfra);
-
- /* rotations */
- basic_rotate(part, pa, pa->state.time, timestep);
- }
- break;
- }
- case PART_PHYS_BOIDS:
- {
- LOOP_DYNAMIC_PARTICLES {
- bbd.goal_ob = NULL;
-
- boid_brain(&bbd, p, pa);
-
- if (pa->alive != PARS_DYING) {
- boid_body(&bbd, pa);
-
- /* deflection */
- if (sim->colliders)
- collision_check(sim, p, pa->state.time, cfra);
- }
- }
- break;
- }
- case PART_PHYS_FLUID:
- {
- SPHData sphdata;
- psys_sph_init(sim, &sphdata);
-
- DynamicStepSolverTaskData task_data = {
- .sim = sim, .cfra = cfra, .timestep = timestep, .dtime = dtime,
- };
-
- BLI_spin_init(&task_data.spin);
-
- if (part->fluid->solver == SPH_SOLVER_DDR) {
- /* Apply SPH forces using double-density relaxation algorithm
- * (Clavat et. al.) */
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (psys->totpart > 100);
- settings.userdata_chunk = &sphdata;
- settings.userdata_chunk_size = sizeof(sphdata);
- BLI_task_parallel_range(
- 0, psys->totpart,
- &task_data,
- dynamics_step_sph_ddr_task_cb_ex,
- &settings);
-
- sph_springs_modify(psys, timestep);
- }
- else {
- /* SPH_SOLVER_CLASSICAL */
- /* Apply SPH forces using classical algorithm (due to Gingold
- * and Monaghan). Note that, unlike double-density relaxation,
- * this algorithm is separated into distinct loops. */
-
- {
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (psys->totpart > 100);
- BLI_task_parallel_range(
- 0, psys->totpart,
- &task_data,
- dynamics_step_sph_classical_basic_integrate_task_cb_ex,
- &settings);
- }
-
- /* calculate summation density */
- /* Note that we could avoid copying sphdata for each thread here (it's only read here),
- * but doubt this would gain us anything except confusion... */
- {
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (psys->totpart > 100);
- settings.userdata_chunk = &sphdata;
- settings.userdata_chunk_size = sizeof(sphdata);
- BLI_task_parallel_range(
- 0, psys->totpart,
- &task_data,
- dynamics_step_sph_classical_calc_density_task_cb_ex,
- &settings);
- }
-
- /* do global forces & effectors */
- {
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (psys->totpart > 100);
- settings.userdata_chunk = &sphdata;
- settings.userdata_chunk_size = sizeof(sphdata);
- BLI_task_parallel_range(
- 0, psys->totpart,
- &task_data,
- dynamics_step_sph_classical_integrate_task_cb_ex,
- &settings);
- }
- }
-
- BLI_spin_end(&task_data.spin);
-
- psys_sph_finalise(&sphdata);
- break;
- }
- }
-
- /* finalize particle state and time after dynamics */
- LOOP_DYNAMIC_PARTICLES {
- if (pa->alive == PARS_DYING) {
- pa->alive=PARS_DEAD;
- pa->state.time=pa->dietime;
- }
- else
- pa->state.time=cfra;
- }
-
- BKE_collider_cache_free(&sim->colliders);
- BLI_rng_free(sim->rng);
- sim->rng = NULL;
+ ParticleSystem *psys = sim->psys;
+ ParticleSettings *part = psys->part;
+ BoidBrainData bbd;
+ ParticleTexture ptex;
+ PARTICLE_P;
+ float timestep;
+ /* frame & time changes */
+ float dfra, dtime;
+ float birthtime, dietime;
+
+ /* where have we gone in time since last time */
+ dfra = cfra - psys->cfra;
+
+ timestep = psys_get_timestep(sim);
+ dtime = dfra * timestep;
+
+ if (dfra < 0.0f) {
+ LOOP_EXISTING_PARTICLES
+ {
+ psys_get_texture(sim, pa, &ptex, PAMAP_SIZE, cfra);
+ pa->size = part->size * ptex.size;
+ if (part->randsize > 0.0f)
+ pa->size *= 1.0f - part->randsize * psys_frand(psys, p + 1);
+
+ reset_particle(sim, pa, dtime, cfra);
+ }
+ return;
+ }
+
+ /* for now do both, boids us 'rng' */
+ sim->rng = BLI_rng_new_srandom(31415926 + (int)cfra + psys->seed);
+
+ psys_update_effectors(sim);
+
+ if (part->type != PART_HAIR)
+ sim->colliders = BKE_collider_cache_create(sim->depsgraph, sim->ob, part->collision_group);
+
+ /* initialize physics type specific stuff */
+ switch (part->phystype) {
+ case PART_PHYS_BOIDS: {
+ ParticleTarget *pt = psys->targets.first;
+ bbd.sim = sim;
+ bbd.part = part;
+ bbd.cfra = cfra;
+ bbd.dfra = dfra;
+ bbd.timestep = timestep;
+ bbd.rng = sim->rng;
+
+ psys_update_particle_tree(psys, cfra);
+
+ boids_precalc_rules(part, cfra);
+
+ for (; pt; pt = pt->next) {
+ ParticleSystem *psys_target = psys_get_target_system(sim->ob, pt);
+ if (psys_target && psys_target != psys) {
+ psys_update_particle_tree(psys_target, cfra);
+ }
+ }
+ break;
+ }
+ case PART_PHYS_FLUID: {
+ ParticleTarget *pt = psys->targets.first;
+ psys_update_particle_bvhtree(psys, cfra);
+
+ for (; pt;
+ pt = pt->next) { /* Updating others systems particle tree for fluid-fluid interaction */
+ if (pt->ob)
+ psys_update_particle_bvhtree(BLI_findlink(&pt->ob->particlesystem, pt->psys - 1), cfra);
+ }
+ break;
+ }
+ }
+ /* initialize all particles for dynamics */
+ LOOP_SHOWN_PARTICLES
+ {
+ copy_particle_key(&pa->prev_state, &pa->state, 1);
+
+ psys_get_texture(sim, pa, &ptex, PAMAP_SIZE, cfra);
+
+ pa->size = part->size * ptex.size;
+ if (part->randsize > 0.0f)
+ pa->size *= 1.0f - part->randsize * psys_frand(psys, p + 1);
+
+ birthtime = pa->time;
+ dietime = pa->dietime;
+
+ /* store this, so we can do multiple loops over particles */
+ pa->state.time = dfra;
+
+ if (dietime <= cfra && psys->cfra < dietime) {
+ /* particle dies some time between this and last step */
+ pa->state.time = dietime - ((birthtime > psys->cfra) ? birthtime : psys->cfra);
+ pa->alive = PARS_DYING;
+ }
+ else if (birthtime <= cfra && birthtime >= psys->cfra) {
+ /* particle is born some time between this and last step*/
+ reset_particle(sim, pa, dfra * timestep, cfra);
+ pa->alive = PARS_ALIVE;
+ pa->state.time = cfra - birthtime;
+ }
+ else if (dietime < cfra) {
+ /* nothing to be done when particle is dead */
+ }
+
+ /* only reset unborn particles if they're shown or if the particle is born soon*/
+ if (pa->alive == PARS_UNBORN &&
+ (part->flag & PART_UNBORN || (cfra + psys->pointcache->step > pa->time))) {
+ reset_particle(sim, pa, dtime, cfra);
+ }
+ else if (part->phystype == PART_PHYS_NO) {
+ reset_particle(sim, pa, dtime, cfra);
+ }
+
+ if (ELEM(pa->alive, PARS_ALIVE, PARS_DYING) == 0 || (pa->flag & (PARS_UNEXIST | PARS_NO_DISP)))
+ pa->state.time = -1.f;
+ }
+
+ switch (part->phystype) {
+ case PART_PHYS_NEWTON: {
+ LOOP_DYNAMIC_PARTICLES
+ {
+ /* do global forces & effectors */
+ basic_integrate(sim, p, pa->state.time, cfra);
+
+ /* deflection */
+ if (sim->colliders)
+ collision_check(sim, p, pa->state.time, cfra);
+
+ /* rotations */
+ basic_rotate(part, pa, pa->state.time, timestep);
+ }
+ break;
+ }
+ case PART_PHYS_BOIDS: {
+ LOOP_DYNAMIC_PARTICLES
+ {
+ bbd.goal_ob = NULL;
+
+ boid_brain(&bbd, p, pa);
+
+ if (pa->alive != PARS_DYING) {
+ boid_body(&bbd, pa);
+
+ /* deflection */
+ if (sim->colliders)
+ collision_check(sim, p, pa->state.time, cfra);
+ }
+ }
+ break;
+ }
+ case PART_PHYS_FLUID: {
+ SPHData sphdata;
+ psys_sph_init(sim, &sphdata);
+
+ DynamicStepSolverTaskData task_data = {
+ .sim = sim,
+ .cfra = cfra,
+ .timestep = timestep,
+ .dtime = dtime,
+ };
+
+ BLI_spin_init(&task_data.spin);
+
+ if (part->fluid->solver == SPH_SOLVER_DDR) {
+ /* Apply SPH forces using double-density relaxation algorithm
+ * (Clavat et. al.) */
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (psys->totpart > 100);
+ settings.userdata_chunk = &sphdata;
+ settings.userdata_chunk_size = sizeof(sphdata);
+ BLI_task_parallel_range(
+ 0, psys->totpart, &task_data, dynamics_step_sph_ddr_task_cb_ex, &settings);
+
+ sph_springs_modify(psys, timestep);
+ }
+ else {
+ /* SPH_SOLVER_CLASSICAL */
+ /* Apply SPH forces using classical algorithm (due to Gingold
+ * and Monaghan). Note that, unlike double-density relaxation,
+ * this algorithm is separated into distinct loops. */
+
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (psys->totpart > 100);
+ BLI_task_parallel_range(0,
+ psys->totpart,
+ &task_data,
+ dynamics_step_sph_classical_basic_integrate_task_cb_ex,
+ &settings);
+ }
+
+ /* calculate summation density */
+ /* Note that we could avoid copying sphdata for each thread here (it's only read here),
+ * but doubt this would gain us anything except confusion... */
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (psys->totpart > 100);
+ settings.userdata_chunk = &sphdata;
+ settings.userdata_chunk_size = sizeof(sphdata);
+ BLI_task_parallel_range(0,
+ psys->totpart,
+ &task_data,
+ dynamics_step_sph_classical_calc_density_task_cb_ex,
+ &settings);
+ }
+
+ /* do global forces & effectors */
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (psys->totpart > 100);
+ settings.userdata_chunk = &sphdata;
+ settings.userdata_chunk_size = sizeof(sphdata);
+ BLI_task_parallel_range(0,
+ psys->totpart,
+ &task_data,
+ dynamics_step_sph_classical_integrate_task_cb_ex,
+ &settings);
+ }
+ }
+
+ BLI_spin_end(&task_data.spin);
+
+ psys_sph_finalise(&sphdata);
+ break;
+ }
+ }
+
+ /* finalize particle state and time after dynamics */
+ LOOP_DYNAMIC_PARTICLES
+ {
+ if (pa->alive == PARS_DYING) {
+ pa->alive = PARS_DEAD;
+ pa->state.time = pa->dietime;
+ }
+ else
+ pa->state.time = cfra;
+ }
+
+ BKE_collider_cache_free(&sim->colliders);
+ BLI_rng_free(sim->rng);
+ sim->rng = NULL;
}
static void update_children(ParticleSimulationData *sim, const bool use_render_params)
{
- if ((sim->psys->part->type == PART_HAIR) && (sim->psys->flag & PSYS_HAIR_DONE)==0)
- /* don't generate children while growing hair - waste of time */
- psys_free_children(sim->psys);
- else if (sim->psys->part->childtype) {
- if (sim->psys->totchild != psys_get_tot_child(sim->scene, sim->psys, use_render_params))
- distribute_particles(sim, PART_FROM_CHILD);
- else {
- /* Children are up to date, nothing to do. */
- }
- }
- else
- psys_free_children(sim->psys);
+ if ((sim->psys->part->type == PART_HAIR) && (sim->psys->flag & PSYS_HAIR_DONE) == 0)
+ /* don't generate children while growing hair - waste of time */
+ psys_free_children(sim->psys);
+ else if (sim->psys->part->childtype) {
+ if (sim->psys->totchild != psys_get_tot_child(sim->scene, sim->psys, use_render_params))
+ distribute_particles(sim, PART_FROM_CHILD);
+ else {
+ /* Children are up to date, nothing to do. */
+ }
+ }
+ else
+ psys_free_children(sim->psys);
}
/* updates cached particles' alive & other flags etc..*/
static void cached_step(ParticleSimulationData *sim, float cfra, const bool use_render_params)
{
- ParticleSystem *psys = sim->psys;
- ParticleSettings *part = psys->part;
- ParticleTexture ptex;
- PARTICLE_P;
- float disp, dietime;
-
- psys_update_effectors(sim);
-
- disp= psys_get_current_display_percentage(psys, use_render_params);
-
- LOOP_PARTICLES {
- psys_get_texture(sim, pa, &ptex, PAMAP_SIZE, cfra);
- pa->size = part->size*ptex.size;
- if (part->randsize > 0.0f)
- pa->size *= 1.0f - part->randsize * psys_frand(psys, p + 1);
-
- psys->lattice_deform_data = psys_create_lattice_deform_data(sim);
-
- dietime = pa->dietime;
-
- /* update alive status and push events */
- if (pa->time > cfra) {
- pa->alive = PARS_UNBORN;
- if (part->flag & PART_UNBORN && (psys->pointcache->flag & PTCACHE_EXTERNAL) == 0)
- reset_particle(sim, pa, 0.0f, cfra);
- }
- else if (dietime <= cfra)
- pa->alive = PARS_DEAD;
- else
- pa->alive = PARS_ALIVE;
-
- if (psys->lattice_deform_data) {
- end_latt_deform(psys->lattice_deform_data);
- psys->lattice_deform_data = NULL;
- }
-
- if (psys_frand(psys, p) > disp)
- pa->flag |= PARS_NO_DISP;
- else
- pa->flag &= ~PARS_NO_DISP;
- }
+ ParticleSystem *psys = sim->psys;
+ ParticleSettings *part = psys->part;
+ ParticleTexture ptex;
+ PARTICLE_P;
+ float disp, dietime;
+
+ psys_update_effectors(sim);
+
+ disp = psys_get_current_display_percentage(psys, use_render_params);
+
+ LOOP_PARTICLES
+ {
+ psys_get_texture(sim, pa, &ptex, PAMAP_SIZE, cfra);
+ pa->size = part->size * ptex.size;
+ if (part->randsize > 0.0f)
+ pa->size *= 1.0f - part->randsize * psys_frand(psys, p + 1);
+
+ psys->lattice_deform_data = psys_create_lattice_deform_data(sim);
+
+ dietime = pa->dietime;
+
+ /* update alive status and push events */
+ if (pa->time > cfra) {
+ pa->alive = PARS_UNBORN;
+ if (part->flag & PART_UNBORN && (psys->pointcache->flag & PTCACHE_EXTERNAL) == 0)
+ reset_particle(sim, pa, 0.0f, cfra);
+ }
+ else if (dietime <= cfra)
+ pa->alive = PARS_DEAD;
+ else
+ pa->alive = PARS_ALIVE;
+
+ if (psys->lattice_deform_data) {
+ end_latt_deform(psys->lattice_deform_data);
+ psys->lattice_deform_data = NULL;
+ }
+
+ if (psys_frand(psys, p) > disp)
+ pa->flag |= PARS_NO_DISP;
+ else
+ pa->flag &= ~PARS_NO_DISP;
+ }
}
-static void particles_fluid_step(
- ParticleSimulationData *sim, int UNUSED(cfra), const bool use_render_params)
+static void particles_fluid_step(ParticleSimulationData *sim,
+ int UNUSED(cfra),
+ const bool use_render_params)
{
- ParticleSystem *psys = sim->psys;
- if (psys->particles) {
- MEM_freeN(psys->particles);
- psys->particles = 0;
- psys->totpart = 0;
- }
-
- /* fluid sim particle import handling, actual loading of particles from file */
+ ParticleSystem *psys = sim->psys;
+ if (psys->particles) {
+ MEM_freeN(psys->particles);
+ psys->particles = 0;
+ psys->totpart = 0;
+ }
+
+ /* fluid sim particle import handling, actual loading of particles from file */
#ifdef WITH_MOD_FLUID
- {
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(sim->ob, eModifierType_Fluidsim);
-
- if ( fluidmd && fluidmd->fss) {
- FluidsimSettings *fss= fluidmd->fss;
- ParticleSettings *part = psys->part;
- ParticleData *pa=NULL;
- char filename[256];
- char debugStrBuffer[256];
- int curFrame = sim->scene->r.cfra -1; // warning - sync with derived mesh fsmesh loading
- int p, j, totpart;
- int readMask, activeParts = 0, fileParts = 0;
- gzFile gzf;
-
-// XXX if (ob==G.obedit) // off...
-// return;
-
- // ok, start loading
- BLI_join_dirfile(filename, sizeof(filename), fss->surfdataPath, OB_FLUIDSIM_SURF_PARTICLES_FNAME);
-
- BLI_path_abs(filename, modifier_path_relbase_from_global(sim->ob));
-
- BLI_path_frame(filename, curFrame, 0); // fixed #frame-no
-
- gzf = BLI_gzopen(filename, "rb");
- if (!gzf) {
- BLI_snprintf(debugStrBuffer, sizeof(debugStrBuffer),"readFsPartData::error - Unable to open file for reading '%s'\n", filename);
- // XXX bad level call elbeemDebugOut(debugStrBuffer);
- return;
- }
-
- gzread(gzf, &totpart, sizeof(totpart));
- totpart = (use_render_params) ? totpart:(part->disp*totpart) / 100;
-
- part->totpart= totpart;
- part->sta=part->end = 1.0f;
- part->lifetime = sim->scene->r.efra + 1;
-
- /* allocate particles */
- realloc_particles(sim, part->totpart);
-
- // set up reading mask
- readMask = fss->typeFlags;
-
- for (p=0, pa=psys->particles; p<totpart; p++, pa++) {
- int ptype=0;
-
- gzread(gzf, &ptype, sizeof( ptype ));
- if (ptype & readMask) {
- activeParts++;
-
- gzread(gzf, &(pa->size), sizeof(float));
-
- pa->size /= 10.0f;
-
- for (j=0; j<3; j++) {
- float wrf;
- gzread(gzf, &wrf, sizeof( wrf ));
- pa->state.co[j] = wrf;
- //fprintf(stderr,"Rj%d ",j);
- }
- for (j=0; j<3; j++) {
- float wrf;
- gzread(gzf, &wrf, sizeof( wrf ));
- pa->state.vel[j] = wrf;
- }
-
- zero_v3(pa->state.ave);
- unit_qt(pa->state.rot);
-
- pa->time = 1.f;
- pa->dietime = sim->scene->r.efra + 1;
- pa->lifetime = sim->scene->r.efra;
- pa->alive = PARS_ALIVE;
- //if (a < 25) fprintf(stderr,"FSPARTICLE debug set %s, a%d = %f,%f,%f, life=%f\n", filename, a, pa->co[0],pa->co[1],pa->co[2], pa->lifetime );
- }
- else {
- // skip...
- for (j=0; j<2*3+1; j++) {
- float wrf; gzread(gzf, &wrf, sizeof( wrf ));
- }
- }
- fileParts++;
- }
- gzclose(gzf);
-
- totpart = psys->totpart = activeParts;
- BLI_snprintf(debugStrBuffer,sizeof(debugStrBuffer),"readFsPartData::done - particles:%d, active:%d, file:%d, mask:%d\n", psys->totpart,activeParts,fileParts,readMask);
- // bad level call
- // XXX elbeemDebugOut(debugStrBuffer);
-
- } // fluid sim particles done
- }
+ {
+ FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(
+ sim->ob, eModifierType_Fluidsim);
+
+ if (fluidmd && fluidmd->fss) {
+ FluidsimSettings *fss = fluidmd->fss;
+ ParticleSettings *part = psys->part;
+ ParticleData *pa = NULL;
+ char filename[256];
+ char debugStrBuffer[256];
+ int curFrame = sim->scene->r.cfra - 1; // warning - sync with derived mesh fsmesh loading
+ int p, j, totpart;
+ int readMask, activeParts = 0, fileParts = 0;
+ gzFile gzf;
+
+ // XXX if (ob==G.obedit) // off...
+ // return;
+
+ // ok, start loading
+ BLI_join_dirfile(
+ filename, sizeof(filename), fss->surfdataPath, OB_FLUIDSIM_SURF_PARTICLES_FNAME);
+
+ BLI_path_abs(filename, modifier_path_relbase_from_global(sim->ob));
+
+ BLI_path_frame(filename, curFrame, 0); // fixed #frame-no
+
+ gzf = BLI_gzopen(filename, "rb");
+ if (!gzf) {
+ BLI_snprintf(debugStrBuffer,
+ sizeof(debugStrBuffer),
+ "readFsPartData::error - Unable to open file for reading '%s'\n",
+ filename);
+ // XXX bad level call elbeemDebugOut(debugStrBuffer);
+ return;
+ }
+
+ gzread(gzf, &totpart, sizeof(totpart));
+ totpart = (use_render_params) ? totpart : (part->disp * totpart) / 100;
+
+ part->totpart = totpart;
+ part->sta = part->end = 1.0f;
+ part->lifetime = sim->scene->r.efra + 1;
+
+ /* allocate particles */
+ realloc_particles(sim, part->totpart);
+
+ // set up reading mask
+ readMask = fss->typeFlags;
+
+ for (p = 0, pa = psys->particles; p < totpart; p++, pa++) {
+ int ptype = 0;
+
+ gzread(gzf, &ptype, sizeof(ptype));
+ if (ptype & readMask) {
+ activeParts++;
+
+ gzread(gzf, &(pa->size), sizeof(float));
+
+ pa->size /= 10.0f;
+
+ for (j = 0; j < 3; j++) {
+ float wrf;
+ gzread(gzf, &wrf, sizeof(wrf));
+ pa->state.co[j] = wrf;
+ //fprintf(stderr,"Rj%d ",j);
+ }
+ for (j = 0; j < 3; j++) {
+ float wrf;
+ gzread(gzf, &wrf, sizeof(wrf));
+ pa->state.vel[j] = wrf;
+ }
+
+ zero_v3(pa->state.ave);
+ unit_qt(pa->state.rot);
+
+ pa->time = 1.f;
+ pa->dietime = sim->scene->r.efra + 1;
+ pa->lifetime = sim->scene->r.efra;
+ pa->alive = PARS_ALIVE;
+ //if (a < 25) fprintf(stderr,"FSPARTICLE debug set %s, a%d = %f,%f,%f, life=%f\n", filename, a, pa->co[0],pa->co[1],pa->co[2], pa->lifetime );
+ }
+ else {
+ // skip...
+ for (j = 0; j < 2 * 3 + 1; j++) {
+ float wrf;
+ gzread(gzf, &wrf, sizeof(wrf));
+ }
+ }
+ fileParts++;
+ }
+ gzclose(gzf);
+
+ totpart = psys->totpart = activeParts;
+ BLI_snprintf(debugStrBuffer,
+ sizeof(debugStrBuffer),
+ "readFsPartData::done - particles:%d, active:%d, file:%d, mask:%d\n",
+ psys->totpart,
+ activeParts,
+ fileParts,
+ readMask);
+ // bad level call
+ // XXX elbeemDebugOut(debugStrBuffer);
+
+ } // fluid sim particles done
+ }
#else
- UNUSED_VARS(use_render_params);
-#endif // WITH_MOD_FLUID
+ UNUSED_VARS(use_render_params);
+#endif // WITH_MOD_FLUID
}
static int emit_particles(ParticleSimulationData *sim, PTCacheID *pid, float UNUSED(cfra))
{
- ParticleSystem *psys = sim->psys;
- int oldtotpart = psys->totpart;
- int totpart = tot_particles(psys, pid);
+ ParticleSystem *psys = sim->psys;
+ int oldtotpart = psys->totpart;
+ int totpart = tot_particles(psys, pid);
- if (totpart != oldtotpart)
- realloc_particles(sim, totpart);
+ if (totpart != oldtotpart)
+ realloc_particles(sim, totpart);
- return totpart - oldtotpart;
+ return totpart - oldtotpart;
}
/* Calculates the next state for all particles of the system
@@ -3924,549 +4071,543 @@ static int emit_particles(ParticleSimulationData *sim, PTCacheID *pid, float UNU
* 4. Save to cache */
static void system_step(ParticleSimulationData *sim, float cfra, const bool use_render_params)
{
- ParticleSystem *psys = sim->psys;
- ParticleSettings *part = psys->part;
- PointCache *cache = psys->pointcache;
- PTCacheID ptcacheid, *pid = NULL;
- PARTICLE_P;
- float disp, cache_cfra = cfra; /*, *vg_vel= 0, *vg_tan= 0, *vg_rot= 0, *vg_size= 0; */
- int startframe = 0, endframe = 100, oldtotpart = 0;
-
- /* cache shouldn't be used for hair or "continue physics" */
- if (part->type != PART_HAIR) {
- psys_clear_temp_pointcache(psys);
-
- /* set suitable cache range automatically */
- if ((cache->flag & (PTCACHE_BAKING|PTCACHE_BAKED))==0)
- psys_get_pointcache_start_end(sim->scene, psys, &cache->startframe, &cache->endframe);
-
- pid = &ptcacheid;
- BKE_ptcache_id_from_particles(pid, sim->ob, psys);
-
- BKE_ptcache_id_time(pid, sim->scene, 0.0f, &startframe, &endframe, NULL);
-
- /* clear everything on start frame, or when psys needs full reset! */
- if ((cfra == startframe) || (psys->recalc & ID_RECALC_PSYS_RESET)) {
- BKE_ptcache_id_reset(sim->scene, pid, PTCACHE_RESET_OUTDATED);
- BKE_ptcache_validate(cache, startframe);
- cache->flag &= ~PTCACHE_REDO_NEEDED;
- }
-
- CLAMP(cache_cfra, startframe, endframe);
- }
-
-/* 1. emit particles and redo particles if needed */
- oldtotpart = psys->totpart;
- if (emit_particles(sim, pid, cfra) || psys->recalc & ID_RECALC_PSYS_RESET) {
- distribute_particles(sim, part->from);
- initialize_all_particles(sim);
- /* reset only just created particles (on startframe all particles are recreated) */
- reset_all_particles(sim, 0.0, cfra, oldtotpart);
- free_unexisting_particles(sim);
-
- if (psys->fluid_springs) {
- MEM_freeN(psys->fluid_springs);
- psys->fluid_springs = NULL;
- }
-
- psys->tot_fluidsprings = psys->alloc_fluidsprings = 0;
-
- /* flag for possible explode modifiers after this system */
- sim->psmd->flag |= eParticleSystemFlag_Pars;
-
- BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_AFTER, cfra);
- }
-
-/* 2. try to read from the cache */
- if (pid) {
- int cache_result = BKE_ptcache_read(pid, cache_cfra, true);
-
- if (ELEM(cache_result, PTCACHE_READ_EXACT, PTCACHE_READ_INTERPOLATED)) {
- cached_step(sim, cfra, use_render_params);
- update_children(sim, use_render_params);
- psys_update_path_cache(sim, cfra, use_render_params);
-
- BKE_ptcache_validate(cache, (int)cache_cfra);
-
- if (cache_result == PTCACHE_READ_INTERPOLATED && cache->flag & PTCACHE_REDO_NEEDED)
- BKE_ptcache_write(pid, (int)cache_cfra);
-
- return;
- }
- /* Cache is supposed to be baked, but no data was found so bail out */
- else if (cache->flag & PTCACHE_BAKED) {
- psys_reset(psys, PSYS_RESET_CACHE_MISS);
- return;
- }
- else if (cache_result == PTCACHE_READ_OLD) {
- psys->cfra = (float)cache->simframe;
- cached_step(sim, psys->cfra, use_render_params);
- }
-
- /* if on second frame, write cache for first frame */
- if (psys->cfra == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact==0))
- BKE_ptcache_write(pid, startframe);
- }
- else
- BKE_ptcache_invalidate(cache);
-
-/* 3. do dynamics */
- /* set particles to be not calculated TODO: can't work with pointcache */
- disp= psys_get_current_display_percentage(psys, use_render_params);
-
- LOOP_PARTICLES {
- if (psys_frand(psys, p) > disp)
- pa->flag |= PARS_NO_DISP;
- else
- pa->flag &= ~PARS_NO_DISP;
- }
-
- if (psys->totpart) {
- int dframe, totframesback = 0;
- float t_frac, dt_frac;
-
- /* handle negative frame start at the first frame by doing
- * all the steps before the first frame */
- if ((int)cfra == startframe && part->sta < startframe)
- totframesback = (startframe - (int)part->sta);
-
- if (!(part->time_flag & PART_TIME_AUTOSF)) {
- /* Constant time step */
- psys->dt_frac = get_base_time_step(part);
- }
- else if ((int)cfra == startframe) {
- /* Variable time step; initialise to subframes */
- psys->dt_frac = get_base_time_step(part);
- }
- else if (psys->dt_frac < MIN_TIMESTEP) {
- /* Variable time step; subsequent frames */
- psys->dt_frac = MIN_TIMESTEP;
- }
-
- for (dframe=-totframesback; dframe<=0; dframe++) {
- /* simulate each subframe */
- dt_frac = psys->dt_frac;
- for (t_frac = dt_frac; t_frac <= 1.0f; t_frac += dt_frac) {
- sim->courant_num = 0.0f;
- dynamics_step(sim, cfra+dframe+t_frac - 1.f);
- psys->cfra = cfra+dframe+t_frac - 1.f;
-
- if (part->time_flag & PART_TIME_AUTOSF)
- update_timestep(psys, sim);
- /* Even without AUTOSF dt_frac may not add up to 1.0 due to float precision. */
- dt_frac = sync_timestep(psys, t_frac);
- }
- }
- }
-
-/* 4. only write cache starting from second frame */
- if (pid) {
- BKE_ptcache_validate(cache, (int)cache_cfra);
- if ((int)cache_cfra != startframe)
- BKE_ptcache_write(pid, (int)cache_cfra);
- }
-
- update_children(sim, use_render_params);
-
-/* cleanup */
- if (psys->lattice_deform_data) {
- end_latt_deform(psys->lattice_deform_data);
- psys->lattice_deform_data = NULL;
- }
+ ParticleSystem *psys = sim->psys;
+ ParticleSettings *part = psys->part;
+ PointCache *cache = psys->pointcache;
+ PTCacheID ptcacheid, *pid = NULL;
+ PARTICLE_P;
+ float disp, cache_cfra = cfra; /*, *vg_vel= 0, *vg_tan= 0, *vg_rot= 0, *vg_size= 0; */
+ int startframe = 0, endframe = 100, oldtotpart = 0;
+
+ /* cache shouldn't be used for hair or "continue physics" */
+ if (part->type != PART_HAIR) {
+ psys_clear_temp_pointcache(psys);
+
+ /* set suitable cache range automatically */
+ if ((cache->flag & (PTCACHE_BAKING | PTCACHE_BAKED)) == 0)
+ psys_get_pointcache_start_end(sim->scene, psys, &cache->startframe, &cache->endframe);
+
+ pid = &ptcacheid;
+ BKE_ptcache_id_from_particles(pid, sim->ob, psys);
+
+ BKE_ptcache_id_time(pid, sim->scene, 0.0f, &startframe, &endframe, NULL);
+
+ /* clear everything on start frame, or when psys needs full reset! */
+ if ((cfra == startframe) || (psys->recalc & ID_RECALC_PSYS_RESET)) {
+ BKE_ptcache_id_reset(sim->scene, pid, PTCACHE_RESET_OUTDATED);
+ BKE_ptcache_validate(cache, startframe);
+ cache->flag &= ~PTCACHE_REDO_NEEDED;
+ }
+
+ CLAMP(cache_cfra, startframe, endframe);
+ }
+
+ /* 1. emit particles and redo particles if needed */
+ oldtotpart = psys->totpart;
+ if (emit_particles(sim, pid, cfra) || psys->recalc & ID_RECALC_PSYS_RESET) {
+ distribute_particles(sim, part->from);
+ initialize_all_particles(sim);
+ /* reset only just created particles (on startframe all particles are recreated) */
+ reset_all_particles(sim, 0.0, cfra, oldtotpart);
+ free_unexisting_particles(sim);
+
+ if (psys->fluid_springs) {
+ MEM_freeN(psys->fluid_springs);
+ psys->fluid_springs = NULL;
+ }
+
+ psys->tot_fluidsprings = psys->alloc_fluidsprings = 0;
+
+ /* flag for possible explode modifiers after this system */
+ sim->psmd->flag |= eParticleSystemFlag_Pars;
+
+ BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_AFTER, cfra);
+ }
+
+ /* 2. try to read from the cache */
+ if (pid) {
+ int cache_result = BKE_ptcache_read(pid, cache_cfra, true);
+
+ if (ELEM(cache_result, PTCACHE_READ_EXACT, PTCACHE_READ_INTERPOLATED)) {
+ cached_step(sim, cfra, use_render_params);
+ update_children(sim, use_render_params);
+ psys_update_path_cache(sim, cfra, use_render_params);
+
+ BKE_ptcache_validate(cache, (int)cache_cfra);
+
+ if (cache_result == PTCACHE_READ_INTERPOLATED && cache->flag & PTCACHE_REDO_NEEDED)
+ BKE_ptcache_write(pid, (int)cache_cfra);
+
+ return;
+ }
+ /* Cache is supposed to be baked, but no data was found so bail out */
+ else if (cache->flag & PTCACHE_BAKED) {
+ psys_reset(psys, PSYS_RESET_CACHE_MISS);
+ return;
+ }
+ else if (cache_result == PTCACHE_READ_OLD) {
+ psys->cfra = (float)cache->simframe;
+ cached_step(sim, psys->cfra, use_render_params);
+ }
+
+ /* if on second frame, write cache for first frame */
+ if (psys->cfra == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact == 0))
+ BKE_ptcache_write(pid, startframe);
+ }
+ else
+ BKE_ptcache_invalidate(cache);
+
+ /* 3. do dynamics */
+ /* set particles to be not calculated TODO: can't work with pointcache */
+ disp = psys_get_current_display_percentage(psys, use_render_params);
+
+ LOOP_PARTICLES
+ {
+ if (psys_frand(psys, p) > disp)
+ pa->flag |= PARS_NO_DISP;
+ else
+ pa->flag &= ~PARS_NO_DISP;
+ }
+
+ if (psys->totpart) {
+ int dframe, totframesback = 0;
+ float t_frac, dt_frac;
+
+ /* handle negative frame start at the first frame by doing
+ * all the steps before the first frame */
+ if ((int)cfra == startframe && part->sta < startframe)
+ totframesback = (startframe - (int)part->sta);
+
+ if (!(part->time_flag & PART_TIME_AUTOSF)) {
+ /* Constant time step */
+ psys->dt_frac = get_base_time_step(part);
+ }
+ else if ((int)cfra == startframe) {
+ /* Variable time step; initialise to subframes */
+ psys->dt_frac = get_base_time_step(part);
+ }
+ else if (psys->dt_frac < MIN_TIMESTEP) {
+ /* Variable time step; subsequent frames */
+ psys->dt_frac = MIN_TIMESTEP;
+ }
+
+ for (dframe = -totframesback; dframe <= 0; dframe++) {
+ /* simulate each subframe */
+ dt_frac = psys->dt_frac;
+ for (t_frac = dt_frac; t_frac <= 1.0f; t_frac += dt_frac) {
+ sim->courant_num = 0.0f;
+ dynamics_step(sim, cfra + dframe + t_frac - 1.f);
+ psys->cfra = cfra + dframe + t_frac - 1.f;
+
+ if (part->time_flag & PART_TIME_AUTOSF)
+ update_timestep(psys, sim);
+ /* Even without AUTOSF dt_frac may not add up to 1.0 due to float precision. */
+ dt_frac = sync_timestep(psys, t_frac);
+ }
+ }
+ }
+
+ /* 4. only write cache starting from second frame */
+ if (pid) {
+ BKE_ptcache_validate(cache, (int)cache_cfra);
+ if ((int)cache_cfra != startframe)
+ BKE_ptcache_write(pid, (int)cache_cfra);
+ }
+
+ update_children(sim, use_render_params);
+
+ /* cleanup */
+ if (psys->lattice_deform_data) {
+ end_latt_deform(psys->lattice_deform_data);
+ psys->lattice_deform_data = NULL;
+ }
}
/* system type has changed so set sensible defaults and clear non applicable flags */
void psys_changed_type(Object *ob, ParticleSystem *psys)
{
- ParticleSettings *part = psys->part;
- PTCacheID pid;
+ ParticleSettings *part = psys->part;
+ PTCacheID pid;
- BKE_ptcache_id_from_particles(&pid, ob, psys);
+ BKE_ptcache_id_from_particles(&pid, ob, psys);
- if (part->phystype != PART_PHYS_KEYED)
- psys->flag &= ~PSYS_KEYED;
+ if (part->phystype != PART_PHYS_KEYED)
+ psys->flag &= ~PSYS_KEYED;
- if (part->type == PART_HAIR) {
- if (ELEM(part->ren_as, PART_DRAW_NOT, PART_DRAW_PATH, PART_DRAW_OB, PART_DRAW_GR)==0)
- part->ren_as = PART_DRAW_PATH;
+ if (part->type == PART_HAIR) {
+ if (ELEM(part->ren_as, PART_DRAW_NOT, PART_DRAW_PATH, PART_DRAW_OB, PART_DRAW_GR) == 0)
+ part->ren_as = PART_DRAW_PATH;
- if (part->distr == PART_DISTR_GRID)
- part->distr = PART_DISTR_JIT;
+ if (part->distr == PART_DISTR_GRID)
+ part->distr = PART_DISTR_JIT;
- if (ELEM(part->draw_as, PART_DRAW_NOT, PART_DRAW_REND, PART_DRAW_PATH)==0)
- part->draw_as = PART_DRAW_REND;
+ if (ELEM(part->draw_as, PART_DRAW_NOT, PART_DRAW_REND, PART_DRAW_PATH) == 0)
+ part->draw_as = PART_DRAW_REND;
- CLAMP(part->path_start, 0.0f, 100.0f);
- CLAMP(part->path_end, 0.0f, 100.0f);
+ CLAMP(part->path_start, 0.0f, 100.0f);
+ CLAMP(part->path_end, 0.0f, 100.0f);
- BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_ALL, 0);
- }
- else {
- free_hair(ob, psys, 1);
+ BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_ALL, 0);
+ }
+ else {
+ free_hair(ob, psys, 1);
- CLAMP(part->path_start, 0.0f, MAX2(100.0f, part->end + part->lifetime));
- CLAMP(part->path_end, 0.0f, MAX2(100.0f, part->end + part->lifetime));
- }
+ CLAMP(part->path_start, 0.0f, MAX2(100.0f, part->end + part->lifetime));
+ CLAMP(part->path_end, 0.0f, MAX2(100.0f, part->end + part->lifetime));
+ }
- psys_reset(psys, PSYS_RESET_ALL);
+ psys_reset(psys, PSYS_RESET_ALL);
}
void psys_check_boid_data(ParticleSystem *psys)
{
- BoidParticle *bpa;
- PARTICLE_P;
-
- pa = psys->particles;
-
- if (!pa)
- return;
-
- if (psys->part && psys->part->phystype==PART_PHYS_BOIDS) {
- if (!pa->boid) {
- bpa = MEM_callocN(psys->totpart * sizeof(BoidParticle), "Boid Data");
-
- LOOP_PARTICLES {
- pa->boid = bpa++;
- }
- }
- }
- else if (pa->boid) {
- MEM_freeN(pa->boid);
- LOOP_PARTICLES {
- pa->boid = NULL;
- }
- }
+ BoidParticle *bpa;
+ PARTICLE_P;
+
+ pa = psys->particles;
+
+ if (!pa)
+ return;
+
+ if (psys->part && psys->part->phystype == PART_PHYS_BOIDS) {
+ if (!pa->boid) {
+ bpa = MEM_callocN(psys->totpart * sizeof(BoidParticle), "Boid Data");
+
+ LOOP_PARTICLES
+ {
+ pa->boid = bpa++;
+ }
+ }
+ }
+ else if (pa->boid) {
+ MEM_freeN(pa->boid);
+ LOOP_PARTICLES
+ {
+ pa->boid = NULL;
+ }
+ }
}
void BKE_particlesettings_fluid_default_settings(ParticleSettings *part)
{
- SPHFluidSettings *fluid = part->fluid;
-
- fluid->spring_k = 0.f;
- fluid->plasticity_constant = 0.1f;
- fluid->yield_ratio = 0.1f;
- fluid->rest_length = 1.f;
- fluid->viscosity_omega = 2.f;
- fluid->viscosity_beta = 0.1f;
- fluid->stiffness_k = 1.f;
- fluid->stiffness_knear = 1.f;
- fluid->rest_density = 1.f;
- fluid->buoyancy = 0.f;
- fluid->radius = 1.f;
- fluid->flag |= SPH_FAC_REPULSION|SPH_FAC_DENSITY|SPH_FAC_RADIUS|SPH_FAC_VISCOSITY|SPH_FAC_REST_LENGTH;
+ SPHFluidSettings *fluid = part->fluid;
+
+ fluid->spring_k = 0.f;
+ fluid->plasticity_constant = 0.1f;
+ fluid->yield_ratio = 0.1f;
+ fluid->rest_length = 1.f;
+ fluid->viscosity_omega = 2.f;
+ fluid->viscosity_beta = 0.1f;
+ fluid->stiffness_k = 1.f;
+ fluid->stiffness_knear = 1.f;
+ fluid->rest_density = 1.f;
+ fluid->buoyancy = 0.f;
+ fluid->radius = 1.f;
+ fluid->flag |= SPH_FAC_REPULSION | SPH_FAC_DENSITY | SPH_FAC_RADIUS | SPH_FAC_VISCOSITY |
+ SPH_FAC_REST_LENGTH;
}
static void psys_prepare_physics(ParticleSimulationData *sim)
{
- ParticleSettings *part = sim->psys->part;
-
- if (ELEM(part->phystype, PART_PHYS_NO, PART_PHYS_KEYED)) {
- PTCacheID pid;
- BKE_ptcache_id_from_particles(&pid, sim->ob, sim->psys);
- BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_ALL, 0);
- }
- else {
- free_keyed_keys(sim->psys);
- sim->psys->flag &= ~PSYS_KEYED;
- }
-
- /* RNA Update must ensure this is true. */
- if (part->phystype == PART_PHYS_BOIDS) {
- BLI_assert(part->boids != NULL);
- }
- else if (part->phystype == PART_PHYS_FLUID) {
- BLI_assert(part->fluid != NULL);
- }
-
- psys_check_boid_data(sim->psys);
+ ParticleSettings *part = sim->psys->part;
+
+ if (ELEM(part->phystype, PART_PHYS_NO, PART_PHYS_KEYED)) {
+ PTCacheID pid;
+ BKE_ptcache_id_from_particles(&pid, sim->ob, sim->psys);
+ BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_ALL, 0);
+ }
+ else {
+ free_keyed_keys(sim->psys);
+ sim->psys->flag &= ~PSYS_KEYED;
+ }
+
+ /* RNA Update must ensure this is true. */
+ if (part->phystype == PART_PHYS_BOIDS) {
+ BLI_assert(part->boids != NULL);
+ }
+ else if (part->phystype == PART_PHYS_FLUID) {
+ BLI_assert(part->fluid != NULL);
+ }
+
+ psys_check_boid_data(sim->psys);
}
static int hair_needs_recalc(ParticleSystem *psys)
{
- if (!(psys->flag & PSYS_EDITED) && (!psys->edit || !psys->edit->edited) &&
- ((psys->flag & PSYS_HAIR_DONE)==0 || psys->recalc & ID_RECALC_PSYS_RESET || (psys->part->flag & PART_HAIR_REGROW && !psys->edit)))
- {
- return 1;
- }
+ if (!(psys->flag & PSYS_EDITED) && (!psys->edit || !psys->edit->edited) &&
+ ((psys->flag & PSYS_HAIR_DONE) == 0 || psys->recalc & ID_RECALC_PSYS_RESET ||
+ (psys->part->flag & PART_HAIR_REGROW && !psys->edit))) {
+ return 1;
+ }
- return 0;
+ return 0;
}
static ParticleSettings *particle_settings_localize(ParticleSettings *particle_settings)
{
- ParticleSettings *particle_settings_local;
- BKE_id_copy_ex(NULL,
- (ID *)&particle_settings->id,
- (ID **)&particle_settings_local,
- LIB_ID_COPY_LOCALIZE);
- return particle_settings_local;
+ ParticleSettings *particle_settings_local;
+ BKE_id_copy_ex(
+ NULL, (ID *)&particle_settings->id, (ID **)&particle_settings_local, LIB_ID_COPY_LOCALIZE);
+ return particle_settings_local;
}
static void particle_settings_free_local(ParticleSettings *particle_settings)
{
- BKE_libblock_free_datablock(&particle_settings->id, 0);
- BKE_libblock_free_data(&particle_settings->id, false);
- MEM_freeN(particle_settings);
+ BKE_libblock_free_datablock(&particle_settings->id, 0);
+ BKE_libblock_free_data(&particle_settings->id, false);
+ MEM_freeN(particle_settings);
}
/* main particle update call, checks that things are ok on the large scale and
* then advances in to actual particle calculations depending on particle type */
-void particle_system_update(struct Depsgraph *depsgraph, Scene *scene, Object *ob, ParticleSystem *psys, const bool use_render_params)
+void particle_system_update(struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ ParticleSystem *psys,
+ const bool use_render_params)
{
- ParticleSimulationData sim= {0};
- ParticleSettings *part = psys->part;
- ParticleSystem *psys_orig = psys_orig_get(psys);
- float cfra;
- ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
-
- /* drawdata is outdated after ANY change */
- if (psys->pdd) psys->pdd->flag &= ~PARTICLE_DRAW_DATA_UPDATED;
-
- if (!psys_check_enabled(ob, psys, use_render_params))
- return;
-
- cfra = DEG_get_ctime(depsgraph);
-
- sim.depsgraph = depsgraph;
- sim.scene = scene;
- sim.ob = ob;
- sim.psys = psys;
- sim.psmd = psmd;
-
- /* system was already updated from modifier stack */
- if (sim.psmd->flag & eParticleSystemFlag_psys_updated) {
- sim.psmd->flag &= ~eParticleSystemFlag_psys_updated;
- /* make sure it really was updated to cfra */
- if (psys->cfra == cfra)
- return;
- }
-
- if (!sim.psmd->mesh_final)
- return;
-
- if (part->from != PART_FROM_VERT) {
- BKE_mesh_tessface_ensure(sim.psmd->mesh_final);
- }
-
- /* to verify if we need to restore object afterwards */
- psys->flag &= ~PSYS_OB_ANIM_RESTORE;
-
- if (psys->recalc & ID_RECALC_PSYS_RESET)
- psys->totunexist = 0;
-
- /* setup necessary physics type dependent additional data if it doesn't yet exist */
- psys_prepare_physics(&sim);
-
- switch (part->type) {
- case PART_HAIR:
- {
- /* nothing to do so bail out early */
- if (psys->totpart == 0 && part->totpart == 0) {
- psys_free_path_cache(psys, NULL);
- free_hair(ob, psys, 0);
- psys->flag |= PSYS_HAIR_DONE;
- }
- /* (re-)create hair */
- else if (hair_needs_recalc(psys)) {
- float hcfra=0.0f;
- int i, recalc = psys->recalc;
-
- free_hair(ob, psys, 0);
-
- if (psys_orig->edit && psys_orig->free_edit) {
- psys_orig->free_edit(psys_orig->edit);
- psys_orig->edit = NULL;
- psys_orig->free_edit = NULL;
- }
-
- /* first step is negative so particles get killed and reset */
- psys->cfra= 1.0f;
-
- ParticleSettings *part_local = part;
- if ((part->flag & PART_HAIR_REGROW) == 0) {
- part_local = particle_settings_localize(part);
- psys->part = part_local;
- }
-
- for (i=0; i<=part->hair_step; i++) {
- hcfra=100.0f*(float)i/(float)psys->part->hair_step;
- if ((part->flag & PART_HAIR_REGROW)==0)
- BKE_animsys_evaluate_animdata(depsgraph, scene, &part_local->id, part_local->adt, hcfra, ADT_RECALC_ANIM);
- system_step(&sim, hcfra, use_render_params);
- psys->cfra = hcfra;
- psys->recalc = 0;
- save_hair(&sim, hcfra);
- }
-
- if (part_local != part) {
- particle_settings_free_local(part_local);
- psys->part = part;
- }
-
- psys->flag |= PSYS_HAIR_DONE;
- psys->recalc = recalc;
- }
- else if (psys->flag & PSYS_EDITED)
- psys->flag |= PSYS_HAIR_DONE;
-
- if (psys->flag & PSYS_HAIR_DONE)
- hair_step(&sim, cfra, use_render_params);
- break;
- }
- case PART_FLUID:
- {
- particles_fluid_step(&sim, (int)cfra, use_render_params);
- break;
- }
- default:
- {
- switch (part->phystype) {
- case PART_PHYS_NO:
- case PART_PHYS_KEYED:
- {
- PARTICLE_P;
- float disp = psys_get_current_display_percentage(psys, use_render_params);
- bool free_unexisting = false;
-
- /* Particles without dynamics haven't been reset yet because they don't use pointcache */
- if (psys->recalc & ID_RECALC_PSYS_RESET)
- psys_reset(psys, PSYS_RESET_ALL);
-
- if (emit_particles(&sim, NULL, cfra) || (psys->recalc & ID_RECALC_PSYS_RESET)) {
- free_keyed_keys(psys);
- distribute_particles(&sim, part->from);
- initialize_all_particles(&sim);
- free_unexisting = true;
-
- /* flag for possible explode modifiers after this system */
- sim.psmd->flag |= eParticleSystemFlag_Pars;
- }
-
- LOOP_EXISTING_PARTICLES {
- pa->size = part->size;
- if (part->randsize > 0.0f)
- pa->size *= 1.0f - part->randsize * psys_frand(psys, p + 1);
-
- reset_particle(&sim, pa, 0.0, cfra);
-
- if (psys_frand(psys, p) > disp)
- pa->flag |= PARS_NO_DISP;
- else
- pa->flag &= ~PARS_NO_DISP;
- }
-
- /* free unexisting after resetting particles */
- if (free_unexisting)
- free_unexisting_particles(&sim);
-
- if (part->phystype == PART_PHYS_KEYED) {
- psys_count_keyed_targets(&sim);
- set_keyed_keys(&sim);
- psys_update_path_cache(&sim, (int)cfra, use_render_params);
- }
- break;
- }
- default:
- {
- /* the main dynamic particle system step */
- system_step(&sim, cfra, use_render_params);
- break;
- }
- }
- break;
- }
- }
-
- /* make sure emitter is left at correct time (particle emission can change this) */
- if (psys->flag & PSYS_OB_ANIM_RESTORE) {
- evaluate_emitter_anim(depsgraph, scene, ob, cfra);
- psys->flag &= ~PSYS_OB_ANIM_RESTORE;
- }
-
- if (psys_orig->edit) {
- psys_orig->edit->flags |= PT_CACHE_EDIT_UPDATE_PARTICLE_FROM_EVAL;
- }
-
- psys->cfra = cfra;
- psys->recalc = 0;
-
- if (DEG_is_active(depsgraph)) {
- if (psys_orig != psys) {
- if (psys_orig->edit != NULL &&
- psys_orig->edit->psys == psys_orig)
- {
- psys_orig->edit->psys_eval = psys;
- psys_orig->edit->psmd_eval = psmd;
- }
- psys_orig->flag = (psys->flag & ~PSYS_SHARED_CACHES);
- psys_orig->cfra = psys->cfra;
- psys_orig->recalc = psys->recalc;
- }
- }
-
- /* save matrix for duplicators, at rendertime the actual dupliobject's matrix is used so don't update! */
- invert_m4_m4(psys->imat, ob->obmat);
-
- BKE_particle_batch_cache_dirty_tag(psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
+ ParticleSimulationData sim = {0};
+ ParticleSettings *part = psys->part;
+ ParticleSystem *psys_orig = psys_orig_get(psys);
+ float cfra;
+ ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
+
+ /* drawdata is outdated after ANY change */
+ if (psys->pdd)
+ psys->pdd->flag &= ~PARTICLE_DRAW_DATA_UPDATED;
+
+ if (!psys_check_enabled(ob, psys, use_render_params))
+ return;
+
+ cfra = DEG_get_ctime(depsgraph);
+
+ sim.depsgraph = depsgraph;
+ sim.scene = scene;
+ sim.ob = ob;
+ sim.psys = psys;
+ sim.psmd = psmd;
+
+ /* system was already updated from modifier stack */
+ if (sim.psmd->flag & eParticleSystemFlag_psys_updated) {
+ sim.psmd->flag &= ~eParticleSystemFlag_psys_updated;
+ /* make sure it really was updated to cfra */
+ if (psys->cfra == cfra)
+ return;
+ }
+
+ if (!sim.psmd->mesh_final)
+ return;
+
+ if (part->from != PART_FROM_VERT) {
+ BKE_mesh_tessface_ensure(sim.psmd->mesh_final);
+ }
+
+ /* to verify if we need to restore object afterwards */
+ psys->flag &= ~PSYS_OB_ANIM_RESTORE;
+
+ if (psys->recalc & ID_RECALC_PSYS_RESET)
+ psys->totunexist = 0;
+
+ /* setup necessary physics type dependent additional data if it doesn't yet exist */
+ psys_prepare_physics(&sim);
+
+ switch (part->type) {
+ case PART_HAIR: {
+ /* nothing to do so bail out early */
+ if (psys->totpart == 0 && part->totpart == 0) {
+ psys_free_path_cache(psys, NULL);
+ free_hair(ob, psys, 0);
+ psys->flag |= PSYS_HAIR_DONE;
+ }
+ /* (re-)create hair */
+ else if (hair_needs_recalc(psys)) {
+ float hcfra = 0.0f;
+ int i, recalc = psys->recalc;
+
+ free_hair(ob, psys, 0);
+
+ if (psys_orig->edit && psys_orig->free_edit) {
+ psys_orig->free_edit(psys_orig->edit);
+ psys_orig->edit = NULL;
+ psys_orig->free_edit = NULL;
+ }
+
+ /* first step is negative so particles get killed and reset */
+ psys->cfra = 1.0f;
+
+ ParticleSettings *part_local = part;
+ if ((part->flag & PART_HAIR_REGROW) == 0) {
+ part_local = particle_settings_localize(part);
+ psys->part = part_local;
+ }
+
+ for (i = 0; i <= part->hair_step; i++) {
+ hcfra = 100.0f * (float)i / (float)psys->part->hair_step;
+ if ((part->flag & PART_HAIR_REGROW) == 0)
+ BKE_animsys_evaluate_animdata(
+ depsgraph, scene, &part_local->id, part_local->adt, hcfra, ADT_RECALC_ANIM);
+ system_step(&sim, hcfra, use_render_params);
+ psys->cfra = hcfra;
+ psys->recalc = 0;
+ save_hair(&sim, hcfra);
+ }
+
+ if (part_local != part) {
+ particle_settings_free_local(part_local);
+ psys->part = part;
+ }
+
+ psys->flag |= PSYS_HAIR_DONE;
+ psys->recalc = recalc;
+ }
+ else if (psys->flag & PSYS_EDITED)
+ psys->flag |= PSYS_HAIR_DONE;
+
+ if (psys->flag & PSYS_HAIR_DONE)
+ hair_step(&sim, cfra, use_render_params);
+ break;
+ }
+ case PART_FLUID: {
+ particles_fluid_step(&sim, (int)cfra, use_render_params);
+ break;
+ }
+ default: {
+ switch (part->phystype) {
+ case PART_PHYS_NO:
+ case PART_PHYS_KEYED: {
+ PARTICLE_P;
+ float disp = psys_get_current_display_percentage(psys, use_render_params);
+ bool free_unexisting = false;
+
+ /* Particles without dynamics haven't been reset yet because they don't use pointcache */
+ if (psys->recalc & ID_RECALC_PSYS_RESET)
+ psys_reset(psys, PSYS_RESET_ALL);
+
+ if (emit_particles(&sim, NULL, cfra) || (psys->recalc & ID_RECALC_PSYS_RESET)) {
+ free_keyed_keys(psys);
+ distribute_particles(&sim, part->from);
+ initialize_all_particles(&sim);
+ free_unexisting = true;
+
+ /* flag for possible explode modifiers after this system */
+ sim.psmd->flag |= eParticleSystemFlag_Pars;
+ }
+
+ LOOP_EXISTING_PARTICLES
+ {
+ pa->size = part->size;
+ if (part->randsize > 0.0f)
+ pa->size *= 1.0f - part->randsize * psys_frand(psys, p + 1);
+
+ reset_particle(&sim, pa, 0.0, cfra);
+
+ if (psys_frand(psys, p) > disp)
+ pa->flag |= PARS_NO_DISP;
+ else
+ pa->flag &= ~PARS_NO_DISP;
+ }
+
+ /* free unexisting after resetting particles */
+ if (free_unexisting)
+ free_unexisting_particles(&sim);
+
+ if (part->phystype == PART_PHYS_KEYED) {
+ psys_count_keyed_targets(&sim);
+ set_keyed_keys(&sim);
+ psys_update_path_cache(&sim, (int)cfra, use_render_params);
+ }
+ break;
+ }
+ default: {
+ /* the main dynamic particle system step */
+ system_step(&sim, cfra, use_render_params);
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ /* make sure emitter is left at correct time (particle emission can change this) */
+ if (psys->flag & PSYS_OB_ANIM_RESTORE) {
+ evaluate_emitter_anim(depsgraph, scene, ob, cfra);
+ psys->flag &= ~PSYS_OB_ANIM_RESTORE;
+ }
+
+ if (psys_orig->edit) {
+ psys_orig->edit->flags |= PT_CACHE_EDIT_UPDATE_PARTICLE_FROM_EVAL;
+ }
+
+ psys->cfra = cfra;
+ psys->recalc = 0;
+
+ if (DEG_is_active(depsgraph)) {
+ if (psys_orig != psys) {
+ if (psys_orig->edit != NULL && psys_orig->edit->psys == psys_orig) {
+ psys_orig->edit->psys_eval = psys;
+ psys_orig->edit->psmd_eval = psmd;
+ }
+ psys_orig->flag = (psys->flag & ~PSYS_SHARED_CACHES);
+ psys_orig->cfra = psys->cfra;
+ psys_orig->recalc = psys->recalc;
+ }
+ }
+
+ /* save matrix for duplicators, at rendertime the actual dupliobject's matrix is used so don't update! */
+ invert_m4_m4(psys->imat, ob->obmat);
+
+ BKE_particle_batch_cache_dirty_tag(psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
}
/* ID looper */
void BKE_particlesystem_id_loop(ParticleSystem *psys, ParticleSystemIDFunc func, void *userdata)
{
- ParticleTarget *pt;
-
- func(psys, (ID **)&psys->part, userdata, IDWALK_CB_USER | IDWALK_CB_NEVER_NULL);
- func(psys, (ID **)&psys->target_ob, userdata, IDWALK_CB_NOP);
- func(psys, (ID **)&psys->parent, userdata, IDWALK_CB_NOP);
-
- for (pt = psys->targets.first; pt; pt = pt->next) {
- func(psys, (ID **)&pt->ob, userdata, IDWALK_CB_NOP);
- }
-
- /* Even though psys->part should never be NULL, this can happen as an exception during deletion.
- * See ID_REMAP_SKIP/FORCE/FLAG_NEVER_NULL_USAGE in BKE_library_remap. */
- if (psys->part && psys->part->phystype == PART_PHYS_BOIDS) {
- ParticleData *pa;
- int p;
-
- for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++) {
- func(psys, (ID **)&pa->boid->ground, userdata, IDWALK_CB_NOP);
- }
- }
+ ParticleTarget *pt;
+
+ func(psys, (ID **)&psys->part, userdata, IDWALK_CB_USER | IDWALK_CB_NEVER_NULL);
+ func(psys, (ID **)&psys->target_ob, userdata, IDWALK_CB_NOP);
+ func(psys, (ID **)&psys->parent, userdata, IDWALK_CB_NOP);
+
+ for (pt = psys->targets.first; pt; pt = pt->next) {
+ func(psys, (ID **)&pt->ob, userdata, IDWALK_CB_NOP);
+ }
+
+ /* Even though psys->part should never be NULL, this can happen as an exception during deletion.
+ * See ID_REMAP_SKIP/FORCE/FLAG_NEVER_NULL_USAGE in BKE_library_remap. */
+ if (psys->part && psys->part->phystype == PART_PHYS_BOIDS) {
+ ParticleData *pa;
+ int p;
+
+ for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++) {
+ func(psys, (ID **)&pa->boid->ground, userdata, IDWALK_CB_NOP);
+ }
+ }
}
void BKE_particlesystem_reset_all(struct Object *object)
{
- for (ModifierData *md = object->modifiers.first; md != NULL; md = md->next) {
- if (md->type != eModifierType_ParticleSystem) {
- continue;
- }
- ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;
- ParticleSystem *psys = psmd->psys;
- psys->recalc |= ID_RECALC_PSYS_RESET;
- }
+ for (ModifierData *md = object->modifiers.first; md != NULL; md = md->next) {
+ if (md->type != eModifierType_ParticleSystem) {
+ continue;
+ }
+ ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;
+ ParticleSystem *psys = psmd->psys;
+ psys->recalc |= ID_RECALC_PSYS_RESET;
+ }
}
/* **** Depsgraph evaluation **** */
-void BKE_particle_settings_eval_reset(
- struct Depsgraph *depsgraph,
- ParticleSettings *particle_settings)
+void BKE_particle_settings_eval_reset(struct Depsgraph *depsgraph,
+ ParticleSettings *particle_settings)
{
- DEG_debug_print_eval(depsgraph,
- __func__,
- particle_settings->id.name,
- particle_settings);
- particle_settings->id.recalc |= ID_RECALC_PSYS_RESET;
+ DEG_debug_print_eval(depsgraph, __func__, particle_settings->id.name, particle_settings);
+ particle_settings->id.recalc |= ID_RECALC_PSYS_RESET;
}
-void BKE_particle_system_eval_init(struct Depsgraph *depsgraph,
- Object *object)
+void BKE_particle_system_eval_init(struct Depsgraph *depsgraph, Object *object)
{
- DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
- for (ParticleSystem *psys = object->particlesystem.first;
- psys != NULL;
- psys = psys->next)
- {
- psys->recalc |= (psys->part->id.recalc & ID_RECALC_PSYS_ALL);
- }
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
+ for (ParticleSystem *psys = object->particlesystem.first; psys != NULL; psys = psys->next) {
+ psys->recalc |= (psys->part->id.recalc & ID_RECALC_PSYS_ALL);
+ }
}
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 62011513096..445205a513a 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -51,382 +51,374 @@
//#define PERFCNTRS
-#define STACK_FIXED_DEPTH 100
+#define STACK_FIXED_DEPTH 100
#define PBVH_THREADED_LIMIT 4
typedef struct PBVHStack {
- PBVHNode *node;
- bool revisiting;
+ PBVHNode *node;
+ bool revisiting;
} PBVHStack;
typedef struct PBVHIter {
- PBVH *bvh;
- BKE_pbvh_SearchCallback scb;
- void *search_data;
+ PBVH *bvh;
+ BKE_pbvh_SearchCallback scb;
+ void *search_data;
- PBVHStack *stack;
- int stacksize;
+ PBVHStack *stack;
+ int stacksize;
- PBVHStack stackfixed[STACK_FIXED_DEPTH];
- int stackspace;
+ PBVHStack stackfixed[STACK_FIXED_DEPTH];
+ int stackspace;
} PBVHIter;
void BB_reset(BB *bb)
{
- bb->bmin[0] = bb->bmin[1] = bb->bmin[2] = FLT_MAX;
- bb->bmax[0] = bb->bmax[1] = bb->bmax[2] = -FLT_MAX;
+ bb->bmin[0] = bb->bmin[1] = bb->bmin[2] = FLT_MAX;
+ bb->bmax[0] = bb->bmax[1] = bb->bmax[2] = -FLT_MAX;
}
/* Expand the bounding box to include a new coordinate */
void BB_expand(BB *bb, const float co[3])
{
- for (int i = 0; i < 3; ++i) {
- bb->bmin[i] = min_ff(bb->bmin[i], co[i]);
- bb->bmax[i] = max_ff(bb->bmax[i], co[i]);
- }
+ for (int i = 0; i < 3; ++i) {
+ bb->bmin[i] = min_ff(bb->bmin[i], co[i]);
+ bb->bmax[i] = max_ff(bb->bmax[i], co[i]);
+ }
}
/* Expand the bounding box to include another bounding box */
void BB_expand_with_bb(BB *bb, BB *bb2)
{
- for (int i = 0; i < 3; ++i) {
- bb->bmin[i] = min_ff(bb->bmin[i], bb2->bmin[i]);
- bb->bmax[i] = max_ff(bb->bmax[i], bb2->bmax[i]);
- }
+ for (int i = 0; i < 3; ++i) {
+ bb->bmin[i] = min_ff(bb->bmin[i], bb2->bmin[i]);
+ bb->bmax[i] = max_ff(bb->bmax[i], bb2->bmax[i]);
+ }
}
/* Return 0, 1, or 2 to indicate the widest axis of the bounding box */
int BB_widest_axis(const BB *bb)
{
- float dim[3];
+ float dim[3];
- for (int i = 0; i < 3; ++i)
- dim[i] = bb->bmax[i] - bb->bmin[i];
+ for (int i = 0; i < 3; ++i)
+ dim[i] = bb->bmax[i] - bb->bmin[i];
- if (dim[0] > dim[1]) {
- if (dim[0] > dim[2])
- return 0;
- else
- return 2;
- }
- else {
- if (dim[1] > dim[2])
- return 1;
- else
- return 2;
- }
+ if (dim[0] > dim[1]) {
+ if (dim[0] > dim[2])
+ return 0;
+ else
+ return 2;
+ }
+ else {
+ if (dim[1] > dim[2])
+ return 1;
+ else
+ return 2;
+ }
}
void BBC_update_centroid(BBC *bbc)
{
- for (int i = 0; i < 3; ++i)
- bbc->bcentroid[i] = (bbc->bmin[i] + bbc->bmax[i]) * 0.5f;
+ for (int i = 0; i < 3; ++i)
+ bbc->bcentroid[i] = (bbc->bmin[i] + bbc->bmax[i]) * 0.5f;
}
/* Not recursive */
static void update_node_vb(PBVH *bvh, PBVHNode *node)
{
- BB vb;
+ BB vb;
- BB_reset(&vb);
+ BB_reset(&vb);
- if (node->flag & PBVH_Leaf) {
- PBVHVertexIter vd;
+ if (node->flag & PBVH_Leaf) {
+ PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(bvh, node, vd, PBVH_ITER_ALL)
- {
- BB_expand(&vb, vd.co);
- }
- BKE_pbvh_vertex_iter_end;
- }
- else {
- BB_expand_with_bb(&vb,
- &bvh->nodes[node->children_offset].vb);
- BB_expand_with_bb(&vb,
- &bvh->nodes[node->children_offset + 1].vb);
- }
+ BKE_pbvh_vertex_iter_begin(bvh, node, vd, PBVH_ITER_ALL)
+ {
+ BB_expand(&vb, vd.co);
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+ else {
+ BB_expand_with_bb(&vb, &bvh->nodes[node->children_offset].vb);
+ BB_expand_with_bb(&vb, &bvh->nodes[node->children_offset + 1].vb);
+ }
- node->vb = vb;
+ node->vb = vb;
}
//void BKE_pbvh_node_BB_reset(PBVHNode *node)
//{
-// BB_reset(&node->vb);
+// BB_reset(&node->vb);
//}
//
//void BKE_pbvh_node_BB_expand(PBVHNode *node, float co[3])
//{
-// BB_expand(&node->vb, co);
+// BB_expand(&node->vb, co);
//}
static bool face_materials_match(const MPoly *f1, const MPoly *f2)
{
- return ((f1->flag & ME_SMOOTH) == (f2->flag & ME_SMOOTH) &&
- (f1->mat_nr == f2->mat_nr));
+ return ((f1->flag & ME_SMOOTH) == (f2->flag & ME_SMOOTH) && (f1->mat_nr == f2->mat_nr));
}
static bool grid_materials_match(const DMFlagMat *f1, const DMFlagMat *f2)
{
- return ((f1->flag & ME_SMOOTH) == (f2->flag & ME_SMOOTH) &&
- (f1->mat_nr == f2->mat_nr));
+ return ((f1->flag & ME_SMOOTH) == (f2->flag & ME_SMOOTH) && (f1->mat_nr == f2->mat_nr));
}
/* Adapted from BLI_kdopbvh.c */
/* Returns the index of the first element on the right of the partition */
-static int partition_indices(int *prim_indices, int lo, int hi, int axis,
- float mid, BBC *prim_bbc)
+static int partition_indices(int *prim_indices, int lo, int hi, int axis, float mid, BBC *prim_bbc)
{
- int i = lo, j = hi;
- for (;; ) {
- for (; prim_bbc[prim_indices[i]].bcentroid[axis] < mid; i++) ;
- for (; mid < prim_bbc[prim_indices[j]].bcentroid[axis]; j--) ;
+ int i = lo, j = hi;
+ for (;;) {
+ for (; prim_bbc[prim_indices[i]].bcentroid[axis] < mid; i++)
+ ;
+ for (; mid < prim_bbc[prim_indices[j]].bcentroid[axis]; j--)
+ ;
- if (!(i < j))
- return i;
+ if (!(i < j))
+ return i;
- SWAP(int, prim_indices[i], prim_indices[j]);
- i++;
- }
+ SWAP(int, prim_indices[i], prim_indices[j]);
+ i++;
+ }
}
/* Returns the index of the first element on the right of the partition */
static int partition_indices_material(PBVH *bvh, int lo, int hi)
{
- const MPoly *mpoly = bvh->mpoly;
- const MLoopTri *looptri = bvh->looptri;
- const DMFlagMat *flagmats = bvh->grid_flag_mats;
- const int *indices = bvh->prim_indices;
- const void *first;
- int i = lo, j = hi;
-
- if (bvh->looptri)
- first = &mpoly[looptri[bvh->prim_indices[lo]].poly];
- else
- first = &flagmats[bvh->prim_indices[lo]];
-
- for (;; ) {
- if (bvh->looptri) {
- for (; face_materials_match(first, &mpoly[looptri[indices[i]].poly]); i++) ;
- for (; !face_materials_match(first, &mpoly[looptri[indices[j]].poly]); j--) ;
- }
- else {
- for (; grid_materials_match(first, &flagmats[indices[i]]); i++) ;
- for (; !grid_materials_match(first, &flagmats[indices[j]]); j--) ;
- }
-
- if (!(i < j))
- return i;
-
- SWAP(int, bvh->prim_indices[i], bvh->prim_indices[j]);
- i++;
- }
+ const MPoly *mpoly = bvh->mpoly;
+ const MLoopTri *looptri = bvh->looptri;
+ const DMFlagMat *flagmats = bvh->grid_flag_mats;
+ const int *indices = bvh->prim_indices;
+ const void *first;
+ int i = lo, j = hi;
+
+ if (bvh->looptri)
+ first = &mpoly[looptri[bvh->prim_indices[lo]].poly];
+ else
+ first = &flagmats[bvh->prim_indices[lo]];
+
+ for (;;) {
+ if (bvh->looptri) {
+ for (; face_materials_match(first, &mpoly[looptri[indices[i]].poly]); i++)
+ ;
+ for (; !face_materials_match(first, &mpoly[looptri[indices[j]].poly]); j--)
+ ;
+ }
+ else {
+ for (; grid_materials_match(first, &flagmats[indices[i]]); i++)
+ ;
+ for (; !grid_materials_match(first, &flagmats[indices[j]]); j--)
+ ;
+ }
+
+ if (!(i < j))
+ return i;
+
+ SWAP(int, bvh->prim_indices[i], bvh->prim_indices[j]);
+ i++;
+ }
}
void pbvh_grow_nodes(PBVH *bvh, int totnode)
{
- if (UNLIKELY(totnode > bvh->node_mem_count)) {
- bvh->node_mem_count = bvh->node_mem_count + (bvh->node_mem_count / 3);
- if (bvh->node_mem_count < totnode)
- bvh->node_mem_count = totnode;
- bvh->nodes = MEM_recallocN(bvh->nodes, sizeof(PBVHNode) * bvh->node_mem_count);
- }
+ if (UNLIKELY(totnode > bvh->node_mem_count)) {
+ bvh->node_mem_count = bvh->node_mem_count + (bvh->node_mem_count / 3);
+ if (bvh->node_mem_count < totnode)
+ bvh->node_mem_count = totnode;
+ bvh->nodes = MEM_recallocN(bvh->nodes, sizeof(PBVHNode) * bvh->node_mem_count);
+ }
- bvh->totnode = totnode;
+ bvh->totnode = totnode;
}
/* Add a vertex to the map, with a positive value for unique vertices and
* a negative value for additional vertices */
-static int map_insert_vert(PBVH *bvh, GHash *map,
- unsigned int *face_verts,
- unsigned int *uniq_verts, int vertex)
-{
- void *key, **value_p;
-
- key = POINTER_FROM_INT(vertex);
- if (!BLI_ghash_ensure_p(map, key, &value_p)) {
- int value_i;
- if (BLI_BITMAP_TEST(bvh->vert_bitmap, vertex) == 0) {
- BLI_BITMAP_ENABLE(bvh->vert_bitmap, vertex);
- value_i = *uniq_verts;
- (*uniq_verts)++;
- }
- else {
- value_i = ~(*face_verts);
- (*face_verts)++;
- }
- *value_p = POINTER_FROM_INT(value_i);
- return value_i;
- }
- else {
- return POINTER_AS_INT(*value_p);
- }
+static int map_insert_vert(
+ PBVH *bvh, GHash *map, unsigned int *face_verts, unsigned int *uniq_verts, int vertex)
+{
+ void *key, **value_p;
+
+ key = POINTER_FROM_INT(vertex);
+ if (!BLI_ghash_ensure_p(map, key, &value_p)) {
+ int value_i;
+ if (BLI_BITMAP_TEST(bvh->vert_bitmap, vertex) == 0) {
+ BLI_BITMAP_ENABLE(bvh->vert_bitmap, vertex);
+ value_i = *uniq_verts;
+ (*uniq_verts)++;
+ }
+ else {
+ value_i = ~(*face_verts);
+ (*face_verts)++;
+ }
+ *value_p = POINTER_FROM_INT(value_i);
+ return value_i;
+ }
+ else {
+ return POINTER_AS_INT(*value_p);
+ }
}
/* Find vertices used by the faces in this node and update the draw buffers */
static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node)
{
- bool has_visible = false;
+ bool has_visible = false;
- node->uniq_verts = node->face_verts = 0;
- const int totface = node->totprim;
+ node->uniq_verts = node->face_verts = 0;
+ const int totface = node->totprim;
- /* reserve size is rough guess */
- GHash *map = BLI_ghash_int_new_ex("build_mesh_leaf_node gh", 2 * totface);
+ /* reserve size is rough guess */
+ GHash *map = BLI_ghash_int_new_ex("build_mesh_leaf_node gh", 2 * totface);
- int (*face_vert_indices)[3] = MEM_mallocN(sizeof(int[3]) * totface,
- "bvh node face vert indices");
+ int(*face_vert_indices)[3] = MEM_mallocN(sizeof(int[3]) * totface, "bvh node face vert indices");
- node->face_vert_indices = (const int (*)[3])face_vert_indices;
+ node->face_vert_indices = (const int(*)[3])face_vert_indices;
- for (int i = 0; i < totface; ++i) {
- const MLoopTri *lt = &bvh->looptri[node->prim_indices[i]];
- for (int j = 0; j < 3; ++j) {
- face_vert_indices[i][j] =
- map_insert_vert(bvh, map, &node->face_verts,
- &node->uniq_verts, bvh->mloop[lt->tri[j]].v);
- }
+ for (int i = 0; i < totface; ++i) {
+ const MLoopTri *lt = &bvh->looptri[node->prim_indices[i]];
+ for (int j = 0; j < 3; ++j) {
+ face_vert_indices[i][j] = map_insert_vert(
+ bvh, map, &node->face_verts, &node->uniq_verts, bvh->mloop[lt->tri[j]].v);
+ }
- if (!paint_is_face_hidden(lt, bvh->verts, bvh->mloop)) {
- has_visible = true;
- }
- }
+ if (!paint_is_face_hidden(lt, bvh->verts, bvh->mloop)) {
+ has_visible = true;
+ }
+ }
- int *vert_indices = MEM_callocN(sizeof(int) * (node->uniq_verts + node->face_verts),
- "bvh node vert indices");
- node->vert_indices = vert_indices;
+ int *vert_indices = MEM_callocN(sizeof(int) * (node->uniq_verts + node->face_verts),
+ "bvh node vert indices");
+ node->vert_indices = vert_indices;
- /* Build the vertex list, unique verts first */
- GHashIterator gh_iter;
- GHASH_ITER (gh_iter, map) {
- void *value = BLI_ghashIterator_getValue(&gh_iter);
- int ndx = POINTER_AS_INT(value);
+ /* Build the vertex list, unique verts first */
+ GHashIterator gh_iter;
+ GHASH_ITER (gh_iter, map) {
+ void *value = BLI_ghashIterator_getValue(&gh_iter);
+ int ndx = POINTER_AS_INT(value);
- if (ndx < 0)
- ndx = -ndx + node->uniq_verts - 1;
+ if (ndx < 0)
+ ndx = -ndx + node->uniq_verts - 1;
- vert_indices[ndx] =
- POINTER_AS_INT(BLI_ghashIterator_getKey(&gh_iter));
- }
+ vert_indices[ndx] = POINTER_AS_INT(BLI_ghashIterator_getKey(&gh_iter));
+ }
- for (int i = 0; i < totface; ++i) {
- const int sides = 3;
+ for (int i = 0; i < totface; ++i) {
+ const int sides = 3;
- for (int j = 0; j < sides; ++j) {
- if (face_vert_indices[i][j] < 0)
- face_vert_indices[i][j] =
- -face_vert_indices[i][j] +
- node->uniq_verts - 1;
- }
- }
+ for (int j = 0; j < sides; ++j) {
+ if (face_vert_indices[i][j] < 0)
+ face_vert_indices[i][j] = -face_vert_indices[i][j] + node->uniq_verts - 1;
+ }
+ }
- BKE_pbvh_node_mark_rebuild_draw(node);
+ BKE_pbvh_node_mark_rebuild_draw(node);
- BKE_pbvh_node_fully_hidden_set(node, !has_visible);
+ BKE_pbvh_node_fully_hidden_set(node, !has_visible);
- BLI_ghash_free(map, NULL, NULL);
+ BLI_ghash_free(map, NULL, NULL);
}
-static void update_vb(PBVH *bvh, PBVHNode *node, BBC *prim_bbc,
- int offset, int count)
+static void update_vb(PBVH *bvh, PBVHNode *node, BBC *prim_bbc, int offset, int count)
{
- BB_reset(&node->vb);
- for (int i = offset + count - 1; i >= offset; --i) {
- BB_expand_with_bb(&node->vb, (BB *)(&prim_bbc[bvh->prim_indices[i]]));
- }
- node->orig_vb = node->vb;
+ BB_reset(&node->vb);
+ for (int i = offset + count - 1; i >= offset; --i) {
+ BB_expand_with_bb(&node->vb, (BB *)(&prim_bbc[bvh->prim_indices[i]]));
+ }
+ node->orig_vb = node->vb;
}
/* Returns the number of visible quads in the nodes' grids. */
int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden,
- int *grid_indices, int totgrid,
+ int *grid_indices,
+ int totgrid,
int gridsize)
{
- const int gridarea = (gridsize - 1) * (gridsize - 1);
- int totquad = 0;
+ const int gridarea = (gridsize - 1) * (gridsize - 1);
+ int totquad = 0;
- /* grid hidden layer is present, so have to check each grid for
- * visibility */
+ /* grid hidden layer is present, so have to check each grid for
+ * visibility */
- for (int i = 0; i < totgrid; i++) {
- const BLI_bitmap *gh = grid_hidden[grid_indices[i]];
+ for (int i = 0; i < totgrid; i++) {
+ const BLI_bitmap *gh = grid_hidden[grid_indices[i]];
- if (gh) {
- /* grid hidden are present, have to check each element */
- for (int y = 0; y < gridsize - 1; y++) {
- for (int x = 0; x < gridsize - 1; x++) {
- if (!paint_is_grid_face_hidden(gh, gridsize, x, y))
- totquad++;
- }
- }
- }
- else
- totquad += gridarea;
- }
+ if (gh) {
+ /* grid hidden are present, have to check each element */
+ for (int y = 0; y < gridsize - 1; y++) {
+ for (int x = 0; x < gridsize - 1; x++) {
+ if (!paint_is_grid_face_hidden(gh, gridsize, x, y))
+ totquad++;
+ }
+ }
+ }
+ else
+ totquad += gridarea;
+ }
- return totquad;
+ return totquad;
}
static void build_grid_leaf_node(PBVH *bvh, PBVHNode *node)
{
- int totquads = BKE_pbvh_count_grid_quads(bvh->grid_hidden, node->prim_indices,
- node->totprim, bvh->gridkey.grid_size);
- BKE_pbvh_node_fully_hidden_set(node, (totquads == 0));
- BKE_pbvh_node_mark_rebuild_draw(node);
+ int totquads = BKE_pbvh_count_grid_quads(
+ bvh->grid_hidden, node->prim_indices, node->totprim, bvh->gridkey.grid_size);
+ BKE_pbvh_node_fully_hidden_set(node, (totquads == 0));
+ BKE_pbvh_node_mark_rebuild_draw(node);
}
-
-static void build_leaf(PBVH *bvh, int node_index, BBC *prim_bbc,
- int offset, int count)
+static void build_leaf(PBVH *bvh, int node_index, BBC *prim_bbc, int offset, int count)
{
- bvh->nodes[node_index].flag |= PBVH_Leaf;
+ bvh->nodes[node_index].flag |= PBVH_Leaf;
- bvh->nodes[node_index].prim_indices = bvh->prim_indices + offset;
- bvh->nodes[node_index].totprim = count;
+ bvh->nodes[node_index].prim_indices = bvh->prim_indices + offset;
+ bvh->nodes[node_index].totprim = count;
- /* Still need vb for searches */
- update_vb(bvh, &bvh->nodes[node_index], prim_bbc, offset, count);
+ /* Still need vb for searches */
+ update_vb(bvh, &bvh->nodes[node_index], prim_bbc, offset, count);
- if (bvh->looptri)
- build_mesh_leaf_node(bvh, bvh->nodes + node_index);
- else {
- build_grid_leaf_node(bvh, bvh->nodes + node_index);
- }
+ if (bvh->looptri)
+ build_mesh_leaf_node(bvh, bvh->nodes + node_index);
+ else {
+ build_grid_leaf_node(bvh, bvh->nodes + node_index);
+ }
}
/* Return zero if all primitives in the node can be drawn with the
* same material (including flat/smooth shading), non-zero otherwise */
static bool leaf_needs_material_split(PBVH *bvh, int offset, int count)
{
- if (count <= 1)
- return false;
+ if (count <= 1)
+ return false;
- if (bvh->looptri) {
- const MLoopTri *first = &bvh->looptri[bvh->prim_indices[offset]];
- const MPoly *mp = &bvh->mpoly[first->poly];
+ if (bvh->looptri) {
+ const MLoopTri *first = &bvh->looptri[bvh->prim_indices[offset]];
+ const MPoly *mp = &bvh->mpoly[first->poly];
- for (int i = offset + count - 1; i > offset; --i) {
- int prim = bvh->prim_indices[i];
- const MPoly *mp_other = &bvh->mpoly[bvh->looptri[prim].poly];
- if (!face_materials_match(mp, mp_other)) {
- return true;
- }
- }
- }
- else {
- const DMFlagMat *first = &bvh->grid_flag_mats[bvh->prim_indices[offset]];
+ for (int i = offset + count - 1; i > offset; --i) {
+ int prim = bvh->prim_indices[i];
+ const MPoly *mp_other = &bvh->mpoly[bvh->looptri[prim].poly];
+ if (!face_materials_match(mp, mp_other)) {
+ return true;
+ }
+ }
+ }
+ else {
+ const DMFlagMat *first = &bvh->grid_flag_mats[bvh->prim_indices[offset]];
- for (int i = offset + count - 1; i > offset; --i) {
- int prim = bvh->prim_indices[i];
- if (!grid_materials_match(first, &bvh->grid_flag_mats[prim]))
- return true;
- }
- }
+ for (int i = offset + count - 1; i > offset; --i) {
+ int prim = bvh->prim_indices[i];
+ if (!grid_materials_match(first, &bvh->grid_flag_mats[prim]))
+ return true;
+ }
+ }
- return false;
+ return false;
}
-
/* Recursively build a node in the tree
*
* vb is the voxel box around all of the primitives contained in
@@ -438,78 +430,76 @@ static bool leaf_needs_material_split(PBVH *bvh, int offset, int count)
* offset and start indicate a range in the array of primitive indices
*/
-static void build_sub(PBVH *bvh, int node_index, BB *cb, BBC *prim_bbc,
- int offset, int count)
-{
- int end;
- BB cb_backing;
-
- /* Decide whether this is a leaf or not */
- const bool below_leaf_limit = count <= bvh->leaf_limit;
- if (below_leaf_limit) {
- if (!leaf_needs_material_split(bvh, offset, count)) {
- build_leaf(bvh, node_index, prim_bbc, offset, count);
- return;
- }
- }
-
- /* Add two child nodes */
- bvh->nodes[node_index].children_offset = bvh->totnode;
- pbvh_grow_nodes(bvh, bvh->totnode + 2);
-
- /* Update parent node bounding box */
- update_vb(bvh, &bvh->nodes[node_index], prim_bbc, offset, count);
-
- if (!below_leaf_limit) {
- /* Find axis with widest range of primitive centroids */
- if (!cb) {
- cb = &cb_backing;
- BB_reset(cb);
- for (int i = offset + count - 1; i >= offset; --i)
- BB_expand(cb, prim_bbc[bvh->prim_indices[i]].bcentroid);
- }
- const int axis = BB_widest_axis(cb);
-
- /* Partition primitives along that axis */
- end = partition_indices(bvh->prim_indices,
- offset, offset + count - 1,
- axis,
- (cb->bmax[axis] + cb->bmin[axis]) * 0.5f,
- prim_bbc);
- }
- else {
- /* Partition primitives by material */
- end = partition_indices_material(bvh, offset, offset + count - 1);
- }
-
- /* Build children */
- build_sub(bvh, bvh->nodes[node_index].children_offset, NULL,
- prim_bbc, offset, end - offset);
- build_sub(bvh, bvh->nodes[node_index].children_offset + 1, NULL,
- prim_bbc, end, offset + count - end);
+static void build_sub(PBVH *bvh, int node_index, BB *cb, BBC *prim_bbc, int offset, int count)
+{
+ int end;
+ BB cb_backing;
+
+ /* Decide whether this is a leaf or not */
+ const bool below_leaf_limit = count <= bvh->leaf_limit;
+ if (below_leaf_limit) {
+ if (!leaf_needs_material_split(bvh, offset, count)) {
+ build_leaf(bvh, node_index, prim_bbc, offset, count);
+ return;
+ }
+ }
+
+ /* Add two child nodes */
+ bvh->nodes[node_index].children_offset = bvh->totnode;
+ pbvh_grow_nodes(bvh, bvh->totnode + 2);
+
+ /* Update parent node bounding box */
+ update_vb(bvh, &bvh->nodes[node_index], prim_bbc, offset, count);
+
+ if (!below_leaf_limit) {
+ /* Find axis with widest range of primitive centroids */
+ if (!cb) {
+ cb = &cb_backing;
+ BB_reset(cb);
+ for (int i = offset + count - 1; i >= offset; --i)
+ BB_expand(cb, prim_bbc[bvh->prim_indices[i]].bcentroid);
+ }
+ const int axis = BB_widest_axis(cb);
+
+ /* Partition primitives along that axis */
+ end = partition_indices(bvh->prim_indices,
+ offset,
+ offset + count - 1,
+ axis,
+ (cb->bmax[axis] + cb->bmin[axis]) * 0.5f,
+ prim_bbc);
+ }
+ else {
+ /* Partition primitives by material */
+ end = partition_indices_material(bvh, offset, offset + count - 1);
+ }
+
+ /* Build children */
+ build_sub(bvh, bvh->nodes[node_index].children_offset, NULL, prim_bbc, offset, end - offset);
+ build_sub(
+ bvh, bvh->nodes[node_index].children_offset + 1, NULL, prim_bbc, end, offset + count - end);
}
static void pbvh_build(PBVH *bvh, BB *cb, BBC *prim_bbc, int totprim)
{
- if (totprim != bvh->totprim) {
- bvh->totprim = totprim;
- if (bvh->nodes) MEM_freeN(bvh->nodes);
- if (bvh->prim_indices) MEM_freeN(bvh->prim_indices);
- bvh->prim_indices = MEM_mallocN(sizeof(int) * totprim,
- "bvh prim indices");
- for (int i = 0; i < totprim; ++i)
- bvh->prim_indices[i] = i;
- bvh->totnode = 0;
- if (bvh->node_mem_count < 100) {
- bvh->node_mem_count = 100;
- bvh->nodes = MEM_callocN(sizeof(PBVHNode) *
- bvh->node_mem_count,
- "bvh initial nodes");
- }
- }
-
- bvh->totnode = 1;
- build_sub(bvh, 0, cb, prim_bbc, 0, totprim);
+ if (totprim != bvh->totprim) {
+ bvh->totprim = totprim;
+ if (bvh->nodes)
+ MEM_freeN(bvh->nodes);
+ if (bvh->prim_indices)
+ MEM_freeN(bvh->prim_indices);
+ bvh->prim_indices = MEM_mallocN(sizeof(int) * totprim, "bvh prim indices");
+ for (int i = 0; i < totprim; ++i)
+ bvh->prim_indices[i] = i;
+ bvh->totnode = 0;
+ if (bvh->node_mem_count < 100) {
+ bvh->node_mem_count = 100;
+ bvh->nodes = MEM_callocN(sizeof(PBVHNode) * bvh->node_mem_count, "bvh initial nodes");
+ }
+ }
+
+ bvh->totnode = 1;
+ build_sub(bvh, 0, cb, prim_bbc, 0, totprim);
}
/**
@@ -518,959 +508,999 @@ static void pbvh_build(PBVH *bvh, BB *cb, BBC *prim_bbc, int totprim)
* \note Unlike mpoly/mloop/verts, looptri is **totally owned** by PBVH (which means it may rewrite it if needed,
* see #BKE_pbvh_apply_vertCos().
*/
-void BKE_pbvh_build_mesh(
- PBVH *bvh, const MPoly *mpoly, const MLoop *mloop, MVert *verts,
- int totvert, struct CustomData *vdata,
- const MLoopTri *looptri, int looptri_num)
+void BKE_pbvh_build_mesh(PBVH *bvh,
+ const MPoly *mpoly,
+ const MLoop *mloop,
+ MVert *verts,
+ int totvert,
+ struct CustomData *vdata,
+ const MLoopTri *looptri,
+ int looptri_num)
{
- BBC *prim_bbc = NULL;
- BB cb;
+ BBC *prim_bbc = NULL;
+ BB cb;
- bvh->type = PBVH_FACES;
- bvh->mpoly = mpoly;
- bvh->mloop = mloop;
- bvh->looptri = looptri;
- bvh->verts = verts;
- bvh->vert_bitmap = BLI_BITMAP_NEW(totvert, "bvh->vert_bitmap");
- bvh->totvert = totvert;
- bvh->leaf_limit = LEAF_LIMIT;
- bvh->vdata = vdata;
+ bvh->type = PBVH_FACES;
+ bvh->mpoly = mpoly;
+ bvh->mloop = mloop;
+ bvh->looptri = looptri;
+ bvh->verts = verts;
+ bvh->vert_bitmap = BLI_BITMAP_NEW(totvert, "bvh->vert_bitmap");
+ bvh->totvert = totvert;
+ bvh->leaf_limit = LEAF_LIMIT;
+ bvh->vdata = vdata;
- BB_reset(&cb);
+ BB_reset(&cb);
- /* For each face, store the AABB and the AABB centroid */
- prim_bbc = MEM_mallocN(sizeof(BBC) * looptri_num, "prim_bbc");
+ /* For each face, store the AABB and the AABB centroid */
+ prim_bbc = MEM_mallocN(sizeof(BBC) * looptri_num, "prim_bbc");
- for (int i = 0; i < looptri_num; ++i) {
- const MLoopTri *lt = &looptri[i];
- const int sides = 3;
- BBC *bbc = prim_bbc + i;
+ for (int i = 0; i < looptri_num; ++i) {
+ const MLoopTri *lt = &looptri[i];
+ const int sides = 3;
+ BBC *bbc = prim_bbc + i;
- BB_reset((BB *)bbc);
+ BB_reset((BB *)bbc);
- for (int j = 0; j < sides; ++j)
- BB_expand((BB *)bbc, verts[bvh->mloop[lt->tri[j]].v].co);
+ for (int j = 0; j < sides; ++j)
+ BB_expand((BB *)bbc, verts[bvh->mloop[lt->tri[j]].v].co);
- BBC_update_centroid(bbc);
+ BBC_update_centroid(bbc);
- BB_expand(&cb, bbc->bcentroid);
- }
+ BB_expand(&cb, bbc->bcentroid);
+ }
- if (looptri_num)
- pbvh_build(bvh, &cb, prim_bbc, looptri_num);
+ if (looptri_num)
+ pbvh_build(bvh, &cb, prim_bbc, looptri_num);
- MEM_freeN(prim_bbc);
- MEM_freeN(bvh->vert_bitmap);
+ MEM_freeN(prim_bbc);
+ MEM_freeN(bvh->vert_bitmap);
}
/* Do a full rebuild with on Grids data structure */
-void BKE_pbvh_build_grids(PBVH *bvh, CCGElem **grids,
- int totgrid, CCGKey *key, void **gridfaces, DMFlagMat *flagmats, BLI_bitmap **grid_hidden)
+void BKE_pbvh_build_grids(PBVH *bvh,
+ CCGElem **grids,
+ int totgrid,
+ CCGKey *key,
+ void **gridfaces,
+ DMFlagMat *flagmats,
+ BLI_bitmap **grid_hidden)
{
- const int gridsize = key->grid_size;
+ const int gridsize = key->grid_size;
- bvh->type = PBVH_GRIDS;
- bvh->grids = grids;
- bvh->gridfaces = gridfaces;
- bvh->grid_flag_mats = flagmats;
- bvh->totgrid = totgrid;
- bvh->gridkey = *key;
- bvh->grid_hidden = grid_hidden;
- bvh->leaf_limit = max_ii(LEAF_LIMIT / ((gridsize - 1) * (gridsize - 1)), 1);
+ bvh->type = PBVH_GRIDS;
+ bvh->grids = grids;
+ bvh->gridfaces = gridfaces;
+ bvh->grid_flag_mats = flagmats;
+ bvh->totgrid = totgrid;
+ bvh->gridkey = *key;
+ bvh->grid_hidden = grid_hidden;
+ bvh->leaf_limit = max_ii(LEAF_LIMIT / ((gridsize - 1) * (gridsize - 1)), 1);
- BB cb;
- BB_reset(&cb);
+ BB cb;
+ BB_reset(&cb);
- /* For each grid, store the AABB and the AABB centroid */
- BBC *prim_bbc = MEM_mallocN(sizeof(BBC) * totgrid, "prim_bbc");
+ /* For each grid, store the AABB and the AABB centroid */
+ BBC *prim_bbc = MEM_mallocN(sizeof(BBC) * totgrid, "prim_bbc");
- for (int i = 0; i < totgrid; ++i) {
- CCGElem *grid = grids[i];
- BBC *bbc = prim_bbc + i;
+ for (int i = 0; i < totgrid; ++i) {
+ CCGElem *grid = grids[i];
+ BBC *bbc = prim_bbc + i;
- BB_reset((BB *)bbc);
+ BB_reset((BB *)bbc);
- for (int j = 0; j < gridsize * gridsize; ++j)
- BB_expand((BB *)bbc, CCG_elem_offset_co(key, grid, j));
+ for (int j = 0; j < gridsize * gridsize; ++j)
+ BB_expand((BB *)bbc, CCG_elem_offset_co(key, grid, j));
- BBC_update_centroid(bbc);
+ BBC_update_centroid(bbc);
- BB_expand(&cb, bbc->bcentroid);
- }
+ BB_expand(&cb, bbc->bcentroid);
+ }
- if (totgrid)
- pbvh_build(bvh, &cb, prim_bbc, totgrid);
+ if (totgrid)
+ pbvh_build(bvh, &cb, prim_bbc, totgrid);
- MEM_freeN(prim_bbc);
+ MEM_freeN(prim_bbc);
}
PBVH *BKE_pbvh_new(void)
{
- PBVH *bvh = MEM_callocN(sizeof(PBVH), "pbvh");
+ PBVH *bvh = MEM_callocN(sizeof(PBVH), "pbvh");
- return bvh;
+ return bvh;
}
void BKE_pbvh_free(PBVH *bvh)
{
- for (int i = 0; i < bvh->totnode; ++i) {
- PBVHNode *node = &bvh->nodes[i];
+ for (int i = 0; i < bvh->totnode; ++i) {
+ PBVHNode *node = &bvh->nodes[i];
- if (node->flag & PBVH_Leaf) {
- if (node->draw_buffers)
- GPU_pbvh_buffers_free(node->draw_buffers);
- if (node->vert_indices)
- MEM_freeN((void *)node->vert_indices);
- if (node->face_vert_indices)
- MEM_freeN((void *)node->face_vert_indices);
- BKE_pbvh_node_layer_disp_free(node);
+ if (node->flag & PBVH_Leaf) {
+ if (node->draw_buffers)
+ GPU_pbvh_buffers_free(node->draw_buffers);
+ if (node->vert_indices)
+ MEM_freeN((void *)node->vert_indices);
+ if (node->face_vert_indices)
+ MEM_freeN((void *)node->face_vert_indices);
+ BKE_pbvh_node_layer_disp_free(node);
- if (node->bm_faces)
- BLI_gset_free(node->bm_faces, NULL);
- if (node->bm_unique_verts)
- BLI_gset_free(node->bm_unique_verts, NULL);
- if (node->bm_other_verts)
- BLI_gset_free(node->bm_other_verts, NULL);
- }
- }
+ if (node->bm_faces)
+ BLI_gset_free(node->bm_faces, NULL);
+ if (node->bm_unique_verts)
+ BLI_gset_free(node->bm_unique_verts, NULL);
+ if (node->bm_other_verts)
+ BLI_gset_free(node->bm_other_verts, NULL);
+ }
+ }
- if (bvh->deformed) {
- if (bvh->verts) {
- /* if pbvh was deformed, new memory was allocated for verts/faces -- free it */
+ if (bvh->deformed) {
+ if (bvh->verts) {
+ /* if pbvh was deformed, new memory was allocated for verts/faces -- free it */
- MEM_freeN((void *)bvh->verts);
- }
- }
+ MEM_freeN((void *)bvh->verts);
+ }
+ }
- if (bvh->looptri) {
- MEM_freeN((void *)bvh->looptri);
- }
+ if (bvh->looptri) {
+ MEM_freeN((void *)bvh->looptri);
+ }
- if (bvh->nodes)
- MEM_freeN(bvh->nodes);
+ if (bvh->nodes)
+ MEM_freeN(bvh->nodes);
- if (bvh->prim_indices)
- MEM_freeN(bvh->prim_indices);
+ if (bvh->prim_indices)
+ MEM_freeN(bvh->prim_indices);
- MEM_freeN(bvh);
+ MEM_freeN(bvh);
}
void BKE_pbvh_free_layer_disp(PBVH *bvh)
{
- for (int i = 0; i < bvh->totnode; ++i)
- BKE_pbvh_node_layer_disp_free(&bvh->nodes[i]);
+ for (int i = 0; i < bvh->totnode; ++i)
+ BKE_pbvh_node_layer_disp_free(&bvh->nodes[i]);
}
-static void pbvh_iter_begin(PBVHIter *iter, PBVH *bvh, BKE_pbvh_SearchCallback scb, void *search_data)
+static void pbvh_iter_begin(PBVHIter *iter,
+ PBVH *bvh,
+ BKE_pbvh_SearchCallback scb,
+ void *search_data)
{
- iter->bvh = bvh;
- iter->scb = scb;
- iter->search_data = search_data;
+ iter->bvh = bvh;
+ iter->scb = scb;
+ iter->search_data = search_data;
- iter->stack = iter->stackfixed;
- iter->stackspace = STACK_FIXED_DEPTH;
+ iter->stack = iter->stackfixed;
+ iter->stackspace = STACK_FIXED_DEPTH;
- iter->stack[0].node = bvh->nodes;
- iter->stack[0].revisiting = false;
- iter->stacksize = 1;
+ iter->stack[0].node = bvh->nodes;
+ iter->stack[0].revisiting = false;
+ iter->stacksize = 1;
}
static void pbvh_iter_end(PBVHIter *iter)
{
- if (iter->stackspace > STACK_FIXED_DEPTH)
- MEM_freeN(iter->stack);
+ if (iter->stackspace > STACK_FIXED_DEPTH)
+ MEM_freeN(iter->stack);
}
static void pbvh_stack_push(PBVHIter *iter, PBVHNode *node, bool revisiting)
{
- if (UNLIKELY(iter->stacksize == iter->stackspace)) {
- iter->stackspace *= 2;
- if (iter->stackspace != (STACK_FIXED_DEPTH * 2)) {
- iter->stack = MEM_reallocN(iter->stack, sizeof(PBVHStack) * iter->stackspace);
- }
- else {
- iter->stack = MEM_mallocN(sizeof(PBVHStack) * iter->stackspace, "PBVHStack");
- memcpy(iter->stack, iter->stackfixed, sizeof(PBVHStack) * iter->stacksize);
- }
- }
+ if (UNLIKELY(iter->stacksize == iter->stackspace)) {
+ iter->stackspace *= 2;
+ if (iter->stackspace != (STACK_FIXED_DEPTH * 2)) {
+ iter->stack = MEM_reallocN(iter->stack, sizeof(PBVHStack) * iter->stackspace);
+ }
+ else {
+ iter->stack = MEM_mallocN(sizeof(PBVHStack) * iter->stackspace, "PBVHStack");
+ memcpy(iter->stack, iter->stackfixed, sizeof(PBVHStack) * iter->stacksize);
+ }
+ }
- iter->stack[iter->stacksize].node = node;
- iter->stack[iter->stacksize].revisiting = revisiting;
- iter->stacksize++;
+ iter->stack[iter->stacksize].node = node;
+ iter->stack[iter->stacksize].revisiting = revisiting;
+ iter->stacksize++;
}
static PBVHNode *pbvh_iter_next(PBVHIter *iter)
{
- /* purpose here is to traverse tree, visiting child nodes before their
- * parents, this order is necessary for e.g. computing bounding boxes */
+ /* purpose here is to traverse tree, visiting child nodes before their
+ * parents, this order is necessary for e.g. computing bounding boxes */
- while (iter->stacksize) {
- /* pop node */
- iter->stacksize--;
- PBVHNode *node = iter->stack[iter->stacksize].node;
+ while (iter->stacksize) {
+ /* pop node */
+ iter->stacksize--;
+ PBVHNode *node = iter->stack[iter->stacksize].node;
- /* on a mesh with no faces this can happen
- * can remove this check if we know meshes have at least 1 face */
- if (node == NULL)
- return NULL;
+ /* on a mesh with no faces this can happen
+ * can remove this check if we know meshes have at least 1 face */
+ if (node == NULL)
+ return NULL;
- bool revisiting = iter->stack[iter->stacksize].revisiting;
+ bool revisiting = iter->stack[iter->stacksize].revisiting;
- /* revisiting node already checked */
- if (revisiting)
- return node;
+ /* revisiting node already checked */
+ if (revisiting)
+ return node;
- if (iter->scb && !iter->scb(node, iter->search_data))
- continue; /* don't traverse, outside of search zone */
+ if (iter->scb && !iter->scb(node, iter->search_data))
+ continue; /* don't traverse, outside of search zone */
- if (node->flag & PBVH_Leaf) {
- /* immediately hit leaf node */
- return node;
- }
- else {
- /* come back later when children are done */
- pbvh_stack_push(iter, node, true);
+ if (node->flag & PBVH_Leaf) {
+ /* immediately hit leaf node */
+ return node;
+ }
+ else {
+ /* come back later when children are done */
+ pbvh_stack_push(iter, node, true);
- /* push two child nodes on the stack */
- pbvh_stack_push(iter, iter->bvh->nodes + node->children_offset + 1, false);
- pbvh_stack_push(iter, iter->bvh->nodes + node->children_offset, false);
- }
- }
+ /* push two child nodes on the stack */
+ pbvh_stack_push(iter, iter->bvh->nodes + node->children_offset + 1, false);
+ pbvh_stack_push(iter, iter->bvh->nodes + node->children_offset, false);
+ }
+ }
- return NULL;
+ return NULL;
}
static PBVHNode *pbvh_iter_next_occluded(PBVHIter *iter)
{
- while (iter->stacksize) {
- /* pop node */
- iter->stacksize--;
- PBVHNode *node = iter->stack[iter->stacksize].node;
+ while (iter->stacksize) {
+ /* pop node */
+ iter->stacksize--;
+ PBVHNode *node = iter->stack[iter->stacksize].node;
- /* on a mesh with no faces this can happen
- * can remove this check if we know meshes have at least 1 face */
- if (node == NULL) return NULL;
+ /* on a mesh with no faces this can happen
+ * can remove this check if we know meshes have at least 1 face */
+ if (node == NULL)
+ return NULL;
- if (iter->scb && !iter->scb(node, iter->search_data)) continue; /* don't traverse, outside of search zone */
+ if (iter->scb && !iter->scb(node, iter->search_data))
+ continue; /* don't traverse, outside of search zone */
- if (node->flag & PBVH_Leaf) {
- /* immediately hit leaf node */
- return node;
- }
- else {
- pbvh_stack_push(iter, iter->bvh->nodes + node->children_offset + 1, false);
- pbvh_stack_push(iter, iter->bvh->nodes + node->children_offset, false);
- }
- }
+ if (node->flag & PBVH_Leaf) {
+ /* immediately hit leaf node */
+ return node;
+ }
+ else {
+ pbvh_stack_push(iter, iter->bvh->nodes + node->children_offset + 1, false);
+ pbvh_stack_push(iter, iter->bvh->nodes + node->children_offset, false);
+ }
+ }
- return NULL;
+ return NULL;
}
-void BKE_pbvh_search_gather(PBVH *bvh,
- BKE_pbvh_SearchCallback scb, void *search_data,
- PBVHNode ***r_array, int *r_tot)
+void BKE_pbvh_search_gather(
+ PBVH *bvh, BKE_pbvh_SearchCallback scb, void *search_data, PBVHNode ***r_array, int *r_tot)
{
- PBVHIter iter;
- PBVHNode **array = NULL, *node;
- int tot = 0, space = 0;
+ PBVHIter iter;
+ PBVHNode **array = NULL, *node;
+ int tot = 0, space = 0;
- pbvh_iter_begin(&iter, bvh, scb, search_data);
+ pbvh_iter_begin(&iter, bvh, scb, search_data);
- while ((node = pbvh_iter_next(&iter))) {
- if (node->flag & PBVH_Leaf) {
- if (UNLIKELY(tot == space)) {
- /* resize array if needed */
- space = (tot == 0) ? 32 : space * 2;
- array = MEM_recallocN_id(array, sizeof(PBVHNode *) * space, __func__);
- }
+ while ((node = pbvh_iter_next(&iter))) {
+ if (node->flag & PBVH_Leaf) {
+ if (UNLIKELY(tot == space)) {
+ /* resize array if needed */
+ space = (tot == 0) ? 32 : space * 2;
+ array = MEM_recallocN_id(array, sizeof(PBVHNode *) * space, __func__);
+ }
- array[tot] = node;
- tot++;
- }
- }
+ array[tot] = node;
+ tot++;
+ }
+ }
- pbvh_iter_end(&iter);
+ pbvh_iter_end(&iter);
- if (tot == 0 && array) {
- MEM_freeN(array);
- array = NULL;
- }
+ if (tot == 0 && array) {
+ MEM_freeN(array);
+ array = NULL;
+ }
- *r_array = array;
- *r_tot = tot;
+ *r_array = array;
+ *r_tot = tot;
}
void BKE_pbvh_search_callback(PBVH *bvh,
- BKE_pbvh_SearchCallback scb, void *search_data,
- BKE_pbvh_HitCallback hcb, void *hit_data)
+ BKE_pbvh_SearchCallback scb,
+ void *search_data,
+ BKE_pbvh_HitCallback hcb,
+ void *hit_data)
{
- PBVHIter iter;
- PBVHNode *node;
+ PBVHIter iter;
+ PBVHNode *node;
- pbvh_iter_begin(&iter, bvh, scb, search_data);
+ pbvh_iter_begin(&iter, bvh, scb, search_data);
- while ((node = pbvh_iter_next(&iter)))
- if (node->flag & PBVH_Leaf)
- hcb(node, hit_data);
+ while ((node = pbvh_iter_next(&iter)))
+ if (node->flag & PBVH_Leaf)
+ hcb(node, hit_data);
- pbvh_iter_end(&iter);
+ pbvh_iter_end(&iter);
}
typedef struct node_tree {
- PBVHNode *data;
+ PBVHNode *data;
- struct node_tree *left;
- struct node_tree *right;
+ struct node_tree *left;
+ struct node_tree *right;
} node_tree;
static void node_tree_insert(node_tree *tree, node_tree *new_node)
{
- if (new_node->data->tmin < tree->data->tmin) {
- if (tree->left) {
- node_tree_insert(tree->left, new_node);
- }
- else {
- tree->left = new_node;
- }
- }
- else {
- if (tree->right) {
- node_tree_insert(tree->right, new_node);
- }
- else {
- tree->right = new_node;
- }
- }
+ if (new_node->data->tmin < tree->data->tmin) {
+ if (tree->left) {
+ node_tree_insert(tree->left, new_node);
+ }
+ else {
+ tree->left = new_node;
+ }
+ }
+ else {
+ if (tree->right) {
+ node_tree_insert(tree->right, new_node);
+ }
+ else {
+ tree->right = new_node;
+ }
+ }
}
-static void traverse_tree(node_tree *tree, BKE_pbvh_HitOccludedCallback hcb, void *hit_data, float *tmin)
+static void traverse_tree(node_tree *tree,
+ BKE_pbvh_HitOccludedCallback hcb,
+ void *hit_data,
+ float *tmin)
{
- if (tree->left) traverse_tree(tree->left, hcb, hit_data, tmin);
+ if (tree->left)
+ traverse_tree(tree->left, hcb, hit_data, tmin);
- hcb(tree->data, hit_data, tmin);
+ hcb(tree->data, hit_data, tmin);
- if (tree->right) traverse_tree(tree->right, hcb, hit_data, tmin);
+ if (tree->right)
+ traverse_tree(tree->right, hcb, hit_data, tmin);
}
static void free_tree(node_tree *tree)
{
- if (tree->left) {
- free_tree(tree->left);
- tree->left = NULL;
- }
+ if (tree->left) {
+ free_tree(tree->left);
+ tree->left = NULL;
+ }
- if (tree->right) {
- free_tree(tree->right);
- tree->right = NULL;
- }
+ if (tree->right) {
+ free_tree(tree->right);
+ tree->right = NULL;
+ }
- free(tree);
+ free(tree);
}
float BKE_pbvh_node_get_tmin(PBVHNode *node)
{
- return node->tmin;
+ return node->tmin;
}
static void BKE_pbvh_search_callback_occluded(PBVH *bvh,
- BKE_pbvh_SearchCallback scb, void *search_data,
- BKE_pbvh_HitOccludedCallback hcb, void *hit_data)
+ BKE_pbvh_SearchCallback scb,
+ void *search_data,
+ BKE_pbvh_HitOccludedCallback hcb,
+ void *hit_data)
{
- PBVHIter iter;
- PBVHNode *node;
- node_tree *tree = NULL;
+ PBVHIter iter;
+ PBVHNode *node;
+ node_tree *tree = NULL;
- pbvh_iter_begin(&iter, bvh, scb, search_data);
+ pbvh_iter_begin(&iter, bvh, scb, search_data);
- while ((node = pbvh_iter_next_occluded(&iter))) {
- if (node->flag & PBVH_Leaf) {
- node_tree *new_node = malloc(sizeof(node_tree));
+ while ((node = pbvh_iter_next_occluded(&iter))) {
+ if (node->flag & PBVH_Leaf) {
+ node_tree *new_node = malloc(sizeof(node_tree));
- new_node->data = node;
+ new_node->data = node;
- new_node->left = NULL;
- new_node->right = NULL;
+ new_node->left = NULL;
+ new_node->right = NULL;
- if (tree) {
- node_tree_insert(tree, new_node);
- }
- else {
- tree = new_node;
- }
- }
- }
+ if (tree) {
+ node_tree_insert(tree, new_node);
+ }
+ else {
+ tree = new_node;
+ }
+ }
+ }
- pbvh_iter_end(&iter);
+ pbvh_iter_end(&iter);
- if (tree) {
- float tmin = FLT_MAX;
- traverse_tree(tree, hcb, hit_data, &tmin);
- free_tree(tree);
- }
+ if (tree) {
+ float tmin = FLT_MAX;
+ traverse_tree(tree, hcb, hit_data, &tmin);
+ free_tree(tree);
+ }
}
static bool update_search_cb(PBVHNode *node, void *data_v)
{
- int flag = POINTER_AS_INT(data_v);
+ int flag = POINTER_AS_INT(data_v);
- if (node->flag & PBVH_Leaf)
- return (node->flag & flag) != 0;
+ if (node->flag & PBVH_Leaf)
+ return (node->flag & flag) != 0;
- return true;
+ return true;
}
typedef struct PBVHUpdateData {
- PBVH *bvh;
- PBVHNode **nodes;
- int totnode;
+ PBVH *bvh;
+ PBVHNode **nodes;
+ int totnode;
- float (*fnors)[3];
- float (*vnors)[3];
- int flag;
+ float (*fnors)[3];
+ float (*vnors)[3];
+ int flag;
} PBVHUpdateData;
-static void pbvh_update_normals_accum_task_cb(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict UNUSED(tls))
-{
- PBVHUpdateData *data = userdata;
-
- PBVH *bvh = data->bvh;
- PBVHNode *node = data->nodes[n];
- float (*fnors)[3] = data->fnors;
- float (*vnors)[3] = data->vnors;
-
- if ((node->flag & PBVH_UpdateNormals)) {
- unsigned int mpoly_prev = UINT_MAX;
- float fn[3];
-
- const int *faces = node->prim_indices;
- const int totface = node->totprim;
-
- for (int i = 0; i < totface; ++i) {
- const MLoopTri *lt = &bvh->looptri[faces[i]];
- const unsigned int vtri[3] = {
- bvh->mloop[lt->tri[0]].v,
- bvh->mloop[lt->tri[1]].v,
- bvh->mloop[lt->tri[2]].v,
- };
- const int sides = 3;
-
- /* Face normal and mask */
- if (lt->poly != mpoly_prev) {
- const MPoly *mp = &bvh->mpoly[lt->poly];
- BKE_mesh_calc_poly_normal(mp, &bvh->mloop[mp->loopstart], bvh->verts, fn);
- mpoly_prev = lt->poly;
-
- if (fnors) {
- /* We can assume a face is only present in one node ever. */
- copy_v3_v3(fnors[lt->poly], fn);
- }
- }
-
- for (int j = sides; j--; ) {
- const int v = vtri[j];
-
- if (bvh->verts[v].flag & ME_VERT_PBVH_UPDATE) {
- /* Note: This avoids `lock, add_v3_v3, unlock` and is five to ten times quicker than a spinlock.
- * Not exact equivalent though, since atomicity is only ensured for one component
- * of the vector at a time, but here it shall not make any sensible difference. */
- for (int k = 3; k--; ) {
- atomic_add_and_fetch_fl(&vnors[v][k], fn[k]);
- }
- }
- }
- }
- }
-}
-
-static void pbvh_update_normals_store_task_cb(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict UNUSED(tls))
-{
- PBVHUpdateData *data = userdata;
- PBVH *bvh = data->bvh;
- PBVHNode *node = data->nodes[n];
- float (*vnors)[3] = data->vnors;
-
- if (node->flag & PBVH_UpdateNormals) {
- const int *verts = node->vert_indices;
- const int totvert = node->uniq_verts;
-
- for (int i = 0; i < totvert; ++i) {
- const int v = verts[i];
- MVert *mvert = &bvh->verts[v];
-
- /* mvert is shared between nodes, hence between threads. */
- if (atomic_fetch_and_and_char(&mvert->flag, (char)~ME_VERT_PBVH_UPDATE) & ME_VERT_PBVH_UPDATE) {
- normalize_v3(vnors[v]);
- normal_float_to_short_v3(mvert->no, vnors[v]);
- }
- }
-
- node->flag &= ~PBVH_UpdateNormals;
- }
-}
-
-static void pbvh_update_normals(PBVH *bvh, PBVHNode **nodes,
- int totnode, float (*fnors)[3])
-{
- float (*vnors)[3];
-
- if (bvh->type == PBVH_BMESH) {
- BLI_assert(fnors == NULL);
- pbvh_bmesh_normals_update(nodes, totnode);
- return;
- }
-
- if (bvh->type != PBVH_FACES)
- return;
-
- /* could be per node to save some memory, but also means
- * we have to store for each vertex which node it is in */
- vnors = MEM_callocN(sizeof(*vnors) * bvh->totvert, __func__);
-
- /* subtle assumptions:
- * - We know that for all edited vertices, the nodes with faces
- * adjacent to these vertices have been marked with PBVH_UpdateNormals.
- * This is true because if the vertex is inside the brush radius, the
- * bounding box of it's adjacent faces will be as well.
- * - However this is only true for the vertices that have actually been
- * edited, not for all vertices in the nodes marked for update, so we
- * can only update vertices marked with ME_VERT_PBVH_UPDATE.
- */
-
- PBVHUpdateData data = {
- .bvh = bvh, .nodes = nodes,
- .fnors = fnors, .vnors = vnors,
- };
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (totnode > PBVH_THREADED_LIMIT);
-
- BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_accum_task_cb, &settings);
-
- BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_store_task_cb, &settings);
+static void pbvh_update_normals_accum_task_cb(void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ PBVHUpdateData *data = userdata;
+
+ PBVH *bvh = data->bvh;
+ PBVHNode *node = data->nodes[n];
+ float(*fnors)[3] = data->fnors;
+ float(*vnors)[3] = data->vnors;
+
+ if ((node->flag & PBVH_UpdateNormals)) {
+ unsigned int mpoly_prev = UINT_MAX;
+ float fn[3];
+
+ const int *faces = node->prim_indices;
+ const int totface = node->totprim;
+
+ for (int i = 0; i < totface; ++i) {
+ const MLoopTri *lt = &bvh->looptri[faces[i]];
+ const unsigned int vtri[3] = {
+ bvh->mloop[lt->tri[0]].v,
+ bvh->mloop[lt->tri[1]].v,
+ bvh->mloop[lt->tri[2]].v,
+ };
+ const int sides = 3;
+
+ /* Face normal and mask */
+ if (lt->poly != mpoly_prev) {
+ const MPoly *mp = &bvh->mpoly[lt->poly];
+ BKE_mesh_calc_poly_normal(mp, &bvh->mloop[mp->loopstart], bvh->verts, fn);
+ mpoly_prev = lt->poly;
+
+ if (fnors) {
+ /* We can assume a face is only present in one node ever. */
+ copy_v3_v3(fnors[lt->poly], fn);
+ }
+ }
+
+ for (int j = sides; j--;) {
+ const int v = vtri[j];
+
+ if (bvh->verts[v].flag & ME_VERT_PBVH_UPDATE) {
+ /* Note: This avoids `lock, add_v3_v3, unlock` and is five to ten times quicker than a spinlock.
+ * Not exact equivalent though, since atomicity is only ensured for one component
+ * of the vector at a time, but here it shall not make any sensible difference. */
+ for (int k = 3; k--;) {
+ atomic_add_and_fetch_fl(&vnors[v][k], fn[k]);
+ }
+ }
+ }
+ }
+ }
+}
+
+static void pbvh_update_normals_store_task_cb(void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ PBVHUpdateData *data = userdata;
+ PBVH *bvh = data->bvh;
+ PBVHNode *node = data->nodes[n];
+ float(*vnors)[3] = data->vnors;
+
+ if (node->flag & PBVH_UpdateNormals) {
+ const int *verts = node->vert_indices;
+ const int totvert = node->uniq_verts;
+
+ for (int i = 0; i < totvert; ++i) {
+ const int v = verts[i];
+ MVert *mvert = &bvh->verts[v];
+
+ /* mvert is shared between nodes, hence between threads. */
+ if (atomic_fetch_and_and_char(&mvert->flag, (char)~ME_VERT_PBVH_UPDATE) &
+ ME_VERT_PBVH_UPDATE) {
+ normalize_v3(vnors[v]);
+ normal_float_to_short_v3(mvert->no, vnors[v]);
+ }
+ }
- MEM_freeN(vnors);
+ node->flag &= ~PBVH_UpdateNormals;
+ }
}
-static void pbvh_update_BB_redraw_task_cb(
- void *__restrict userdata,
- const int n,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void pbvh_update_normals(PBVH *bvh, PBVHNode **nodes, int totnode, float (*fnors)[3])
{
- PBVHUpdateData *data = userdata;
- PBVH *bvh = data->bvh;
- PBVHNode *node = data->nodes[n];
- const int flag = data->flag;
+ float(*vnors)[3];
- if ((flag & PBVH_UpdateBB) && (node->flag & PBVH_UpdateBB))
- /* don't clear flag yet, leave it for flushing later */
- /* Note that bvh usage is read-only here, so no need to thread-protect it. */
- update_node_vb(bvh, node);
+ if (bvh->type == PBVH_BMESH) {
+ BLI_assert(fnors == NULL);
+ pbvh_bmesh_normals_update(nodes, totnode);
+ return;
+ }
- if ((flag & PBVH_UpdateOriginalBB) && (node->flag & PBVH_UpdateOriginalBB))
- node->orig_vb = node->vb;
+ if (bvh->type != PBVH_FACES)
+ return;
- if ((flag & PBVH_UpdateRedraw) && (node->flag & PBVH_UpdateRedraw))
- node->flag &= ~PBVH_UpdateRedraw;
+ /* could be per node to save some memory, but also means
+ * we have to store for each vertex which node it is in */
+ vnors = MEM_callocN(sizeof(*vnors) * bvh->totvert, __func__);
+
+ /* subtle assumptions:
+ * - We know that for all edited vertices, the nodes with faces
+ * adjacent to these vertices have been marked with PBVH_UpdateNormals.
+ * This is true because if the vertex is inside the brush radius, the
+ * bounding box of it's adjacent faces will be as well.
+ * - However this is only true for the vertices that have actually been
+ * edited, not for all vertices in the nodes marked for update, so we
+ * can only update vertices marked with ME_VERT_PBVH_UPDATE.
+ */
+
+ PBVHUpdateData data = {
+ .bvh = bvh,
+ .nodes = nodes,
+ .fnors = fnors,
+ .vnors = vnors,
+ };
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (totnode > PBVH_THREADED_LIMIT);
+
+ BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_accum_task_cb, &settings);
+
+ BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_store_task_cb, &settings);
+
+ MEM_freeN(vnors);
+}
+
+static void pbvh_update_BB_redraw_task_cb(void *__restrict userdata,
+ const int n,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ PBVHUpdateData *data = userdata;
+ PBVH *bvh = data->bvh;
+ PBVHNode *node = data->nodes[n];
+ const int flag = data->flag;
+
+ if ((flag & PBVH_UpdateBB) && (node->flag & PBVH_UpdateBB))
+ /* don't clear flag yet, leave it for flushing later */
+ /* Note that bvh usage is read-only here, so no need to thread-protect it. */
+ update_node_vb(bvh, node);
+
+ if ((flag & PBVH_UpdateOriginalBB) && (node->flag & PBVH_UpdateOriginalBB))
+ node->orig_vb = node->vb;
+
+ if ((flag & PBVH_UpdateRedraw) && (node->flag & PBVH_UpdateRedraw))
+ node->flag &= ~PBVH_UpdateRedraw;
}
void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag)
{
- /* update BB, redraw flag */
- PBVHUpdateData data = {
- .bvh = bvh, .nodes = nodes,
- .flag = flag,
- };
+ /* update BB, redraw flag */
+ PBVHUpdateData data = {
+ .bvh = bvh,
+ .nodes = nodes,
+ .flag = flag,
+ };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (totnode > PBVH_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, pbvh_update_BB_redraw_task_cb, &settings);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (totnode > PBVH_THREADED_LIMIT);
+ BLI_task_parallel_range(0, totnode, &data, pbvh_update_BB_redraw_task_cb, &settings);
}
static int pbvh_get_buffers_update_flags(PBVH *bvh)
{
- int update_flags = 0;
- update_flags |= bvh->show_mask ? GPU_PBVH_BUFFERS_SHOW_MASK : 0;
- return update_flags;
+ int update_flags = 0;
+ update_flags |= bvh->show_mask ? GPU_PBVH_BUFFERS_SHOW_MASK : 0;
+ return update_flags;
}
static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode)
{
- /* can't be done in parallel with OpenGL */
- for (int n = 0; n < totnode; n++) {
- PBVHNode *node = nodes[n];
-
- if (node->flag & PBVH_RebuildDrawBuffers) {
- GPU_pbvh_buffers_free(node->draw_buffers);
- switch (bvh->type) {
- case PBVH_GRIDS:
- node->draw_buffers =
- GPU_pbvh_grid_buffers_build(
- node->totprim,
- bvh->grid_hidden);
- break;
- case PBVH_FACES:
- node->draw_buffers =
- GPU_pbvh_mesh_buffers_build(
- node->face_vert_indices,
- bvh->mpoly, bvh->mloop, bvh->looptri,
- bvh->verts,
- node->prim_indices,
- node->totprim);
- break;
- case PBVH_BMESH:
- node->draw_buffers =
- GPU_pbvh_bmesh_buffers_build(bvh->flags & PBVH_DYNTOPO_SMOOTH_SHADING);
- break;
- }
-
- node->flag &= ~PBVH_RebuildDrawBuffers;
- }
-
- if (node->flag & PBVH_UpdateDrawBuffers) {
- const int update_flags = pbvh_get_buffers_update_flags(bvh);
- switch (bvh->type) {
- case PBVH_GRIDS:
- GPU_pbvh_grid_buffers_update(
- node->draw_buffers,
- bvh->grids,
- bvh->grid_flag_mats,
- node->prim_indices,
- node->totprim,
- &bvh->gridkey,
- update_flags);
- break;
- case PBVH_FACES:
- GPU_pbvh_mesh_buffers_update(
- node->draw_buffers,
- bvh->verts,
- node->vert_indices,
- node->uniq_verts +
- node->face_verts,
- CustomData_get_layer(bvh->vdata, CD_PAINT_MASK),
- node->face_vert_indices,
- update_flags);
- break;
- case PBVH_BMESH:
- GPU_pbvh_bmesh_buffers_update(
- node->draw_buffers,
- bvh->bm,
- node->bm_faces,
- node->bm_unique_verts,
- node->bm_other_verts,
- update_flags);
- break;
- }
-
- node->flag &= ~PBVH_UpdateDrawBuffers;
- }
- }
+ /* can't be done in parallel with OpenGL */
+ for (int n = 0; n < totnode; n++) {
+ PBVHNode *node = nodes[n];
+
+ if (node->flag & PBVH_RebuildDrawBuffers) {
+ GPU_pbvh_buffers_free(node->draw_buffers);
+ switch (bvh->type) {
+ case PBVH_GRIDS:
+ node->draw_buffers = GPU_pbvh_grid_buffers_build(node->totprim, bvh->grid_hidden);
+ break;
+ case PBVH_FACES:
+ node->draw_buffers = GPU_pbvh_mesh_buffers_build(node->face_vert_indices,
+ bvh->mpoly,
+ bvh->mloop,
+ bvh->looptri,
+ bvh->verts,
+ node->prim_indices,
+ node->totprim);
+ break;
+ case PBVH_BMESH:
+ node->draw_buffers = GPU_pbvh_bmesh_buffers_build(bvh->flags &
+ PBVH_DYNTOPO_SMOOTH_SHADING);
+ break;
+ }
+
+ node->flag &= ~PBVH_RebuildDrawBuffers;
+ }
+
+ if (node->flag & PBVH_UpdateDrawBuffers) {
+ const int update_flags = pbvh_get_buffers_update_flags(bvh);
+ switch (bvh->type) {
+ case PBVH_GRIDS:
+ GPU_pbvh_grid_buffers_update(node->draw_buffers,
+ bvh->grids,
+ bvh->grid_flag_mats,
+ node->prim_indices,
+ node->totprim,
+ &bvh->gridkey,
+ update_flags);
+ break;
+ case PBVH_FACES:
+ GPU_pbvh_mesh_buffers_update(node->draw_buffers,
+ bvh->verts,
+ node->vert_indices,
+ node->uniq_verts + node->face_verts,
+ CustomData_get_layer(bvh->vdata, CD_PAINT_MASK),
+ node->face_vert_indices,
+ update_flags);
+ break;
+ case PBVH_BMESH:
+ GPU_pbvh_bmesh_buffers_update(node->draw_buffers,
+ bvh->bm,
+ node->bm_faces,
+ node->bm_unique_verts,
+ node->bm_other_verts,
+ update_flags);
+ break;
+ }
+
+ node->flag &= ~PBVH_UpdateDrawBuffers;
+ }
+ }
}
static int pbvh_flush_bb(PBVH *bvh, PBVHNode *node, int flag)
{
- int update = 0;
+ int update = 0;
- /* difficult to multithread well, we just do single threaded recursive */
- if (node->flag & PBVH_Leaf) {
- if (flag & PBVH_UpdateBB) {
- update |= (node->flag & PBVH_UpdateBB);
- node->flag &= ~PBVH_UpdateBB;
- }
+ /* difficult to multithread well, we just do single threaded recursive */
+ if (node->flag & PBVH_Leaf) {
+ if (flag & PBVH_UpdateBB) {
+ update |= (node->flag & PBVH_UpdateBB);
+ node->flag &= ~PBVH_UpdateBB;
+ }
- if (flag & PBVH_UpdateOriginalBB) {
- update |= (node->flag & PBVH_UpdateOriginalBB);
- node->flag &= ~PBVH_UpdateOriginalBB;
- }
+ if (flag & PBVH_UpdateOriginalBB) {
+ update |= (node->flag & PBVH_UpdateOriginalBB);
+ node->flag &= ~PBVH_UpdateOriginalBB;
+ }
- return update;
- }
- else {
- update |= pbvh_flush_bb(bvh, bvh->nodes + node->children_offset, flag);
- update |= pbvh_flush_bb(bvh, bvh->nodes + node->children_offset + 1, flag);
+ return update;
+ }
+ else {
+ update |= pbvh_flush_bb(bvh, bvh->nodes + node->children_offset, flag);
+ update |= pbvh_flush_bb(bvh, bvh->nodes + node->children_offset + 1, flag);
- if (update & PBVH_UpdateBB)
- update_node_vb(bvh, node);
- if (update & PBVH_UpdateOriginalBB)
- node->orig_vb = node->vb;
- }
+ if (update & PBVH_UpdateBB)
+ update_node_vb(bvh, node);
+ if (update & PBVH_UpdateOriginalBB)
+ node->orig_vb = node->vb;
+ }
- return update;
+ return update;
}
void BKE_pbvh_update(PBVH *bvh, int flag, float (*fnors)[3])
{
- if (!bvh->nodes)
- return;
+ if (!bvh->nodes)
+ return;
- PBVHNode **nodes;
- int totnode;
+ PBVHNode **nodes;
+ int totnode;
- BKE_pbvh_search_gather(bvh, update_search_cb, POINTER_FROM_INT(flag),
- &nodes, &totnode);
+ BKE_pbvh_search_gather(bvh, update_search_cb, POINTER_FROM_INT(flag), &nodes, &totnode);
- if (flag & PBVH_UpdateNormals)
- pbvh_update_normals(bvh, nodes, totnode, fnors);
+ if (flag & PBVH_UpdateNormals)
+ pbvh_update_normals(bvh, nodes, totnode, fnors);
- if (flag & (PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw))
- pbvh_update_BB_redraw(bvh, nodes, totnode, flag);
+ if (flag & (PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw))
+ pbvh_update_BB_redraw(bvh, nodes, totnode, flag);
- if (flag & (PBVH_UpdateBB | PBVH_UpdateOriginalBB))
- pbvh_flush_bb(bvh, bvh->nodes, flag);
+ if (flag & (PBVH_UpdateBB | PBVH_UpdateOriginalBB))
+ pbvh_flush_bb(bvh, bvh->nodes, flag);
- if (nodes) MEM_freeN(nodes);
+ if (nodes)
+ MEM_freeN(nodes);
}
void BKE_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3])
{
- PBVHIter iter;
- PBVHNode *node;
- BB bb;
+ PBVHIter iter;
+ PBVHNode *node;
+ BB bb;
- BB_reset(&bb);
+ BB_reset(&bb);
- pbvh_iter_begin(&iter, bvh, NULL, NULL);
+ pbvh_iter_begin(&iter, bvh, NULL, NULL);
- while ((node = pbvh_iter_next(&iter)))
- if (node->flag & PBVH_UpdateRedraw)
- BB_expand_with_bb(&bb, &node->vb);
+ while ((node = pbvh_iter_next(&iter)))
+ if (node->flag & PBVH_UpdateRedraw)
+ BB_expand_with_bb(&bb, &node->vb);
- pbvh_iter_end(&iter);
+ pbvh_iter_end(&iter);
- copy_v3_v3(bb_min, bb.bmin);
- copy_v3_v3(bb_max, bb.bmax);
+ copy_v3_v3(bb_min, bb.bmin);
+ copy_v3_v3(bb_max, bb.bmax);
}
void BKE_pbvh_get_grid_updates(PBVH *bvh, bool clear, void ***r_gridfaces, int *r_totface)
{
- GSet *face_set = BLI_gset_ptr_new(__func__);
- PBVHNode *node;
- PBVHIter iter;
+ GSet *face_set = BLI_gset_ptr_new(__func__);
+ PBVHNode *node;
+ PBVHIter iter;
- pbvh_iter_begin(&iter, bvh, NULL, NULL);
+ pbvh_iter_begin(&iter, bvh, NULL, NULL);
- while ((node = pbvh_iter_next(&iter))) {
- if (node->flag & PBVH_UpdateNormals) {
- for (unsigned i = 0; i < node->totprim; ++i) {
- void *face = bvh->gridfaces[node->prim_indices[i]];
- BLI_gset_add(face_set, face);
- }
+ while ((node = pbvh_iter_next(&iter))) {
+ if (node->flag & PBVH_UpdateNormals) {
+ for (unsigned i = 0; i < node->totprim; ++i) {
+ void *face = bvh->gridfaces[node->prim_indices[i]];
+ BLI_gset_add(face_set, face);
+ }
- if (clear)
- node->flag &= ~PBVH_UpdateNormals;
- }
- }
+ if (clear)
+ node->flag &= ~PBVH_UpdateNormals;
+ }
+ }
- pbvh_iter_end(&iter);
+ pbvh_iter_end(&iter);
- const int tot = BLI_gset_len(face_set);
- if (tot == 0) {
- *r_totface = 0;
- *r_gridfaces = NULL;
- BLI_gset_free(face_set, NULL);
- return;
- }
+ const int tot = BLI_gset_len(face_set);
+ if (tot == 0) {
+ *r_totface = 0;
+ *r_gridfaces = NULL;
+ BLI_gset_free(face_set, NULL);
+ return;
+ }
- void **faces = MEM_mallocN(sizeof(*faces) * tot, "PBVH Grid Faces");
+ void **faces = MEM_mallocN(sizeof(*faces) * tot, "PBVH Grid Faces");
- GSetIterator gs_iter;
- int i;
- GSET_ITER_INDEX (gs_iter, face_set, i) {
- faces[i] = BLI_gsetIterator_getKey(&gs_iter);
- }
+ GSetIterator gs_iter;
+ int i;
+ GSET_ITER_INDEX(gs_iter, face_set, i)
+ {
+ faces[i] = BLI_gsetIterator_getKey(&gs_iter);
+ }
- BLI_gset_free(face_set, NULL);
+ BLI_gset_free(face_set, NULL);
- *r_totface = tot;
- *r_gridfaces = faces;
+ *r_totface = tot;
+ *r_gridfaces = faces;
}
/***************************** PBVH Access ***********************************/
PBVHType BKE_pbvh_type(const PBVH *bvh)
{
- return bvh->type;
+ return bvh->type;
}
bool BKE_pbvh_has_faces(const PBVH *bvh)
{
- if (bvh->type == PBVH_BMESH) {
- return (bvh->bm->totface != 0);
- }
- else {
- return (bvh->totprim != 0);
- }
+ if (bvh->type == PBVH_BMESH) {
+ return (bvh->bm->totface != 0);
+ }
+ else {
+ return (bvh->totprim != 0);
+ }
}
void BKE_pbvh_bounding_box(const PBVH *bvh, float min[3], float max[3])
{
- if (bvh->totnode) {
- const BB *bb = &bvh->nodes[0].vb;
- copy_v3_v3(min, bb->bmin);
- copy_v3_v3(max, bb->bmax);
- }
- else {
- zero_v3(min);
- zero_v3(max);
- }
+ if (bvh->totnode) {
+ const BB *bb = &bvh->nodes[0].vb;
+ copy_v3_v3(min, bb->bmin);
+ copy_v3_v3(max, bb->bmax);
+ }
+ else {
+ zero_v3(min);
+ zero_v3(max);
+ }
}
BLI_bitmap **BKE_pbvh_grid_hidden(const PBVH *bvh)
{
- BLI_assert(bvh->type == PBVH_GRIDS);
- return bvh->grid_hidden;
+ BLI_assert(bvh->type == PBVH_GRIDS);
+ return bvh->grid_hidden;
}
void BKE_pbvh_get_grid_key(const PBVH *bvh, CCGKey *key)
{
- BLI_assert(bvh->type == PBVH_GRIDS);
- *key = bvh->gridkey;
+ BLI_assert(bvh->type == PBVH_GRIDS);
+ *key = bvh->gridkey;
}
struct CCGElem **BKE_pbvh_get_grids(const PBVH *bvh, int *num_grids)
{
- BLI_assert(bvh->type == PBVH_GRIDS);
- *num_grids = bvh->totgrid;
- return bvh->grids;
+ BLI_assert(bvh->type == PBVH_GRIDS);
+ *num_grids = bvh->totgrid;
+ return bvh->grids;
}
BMesh *BKE_pbvh_get_bmesh(PBVH *bvh)
{
- BLI_assert(bvh->type == PBVH_BMESH);
- return bvh->bm;
+ BLI_assert(bvh->type == PBVH_BMESH);
+ return bvh->bm;
}
/***************************** Node Access ***********************************/
void BKE_pbvh_node_mark_update(PBVHNode *node)
{
- node->flag |= PBVH_UpdateNormals | PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw;
+ node->flag |= PBVH_UpdateNormals | PBVH_UpdateBB | PBVH_UpdateOriginalBB |
+ PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw;
}
void BKE_pbvh_node_mark_rebuild_draw(PBVHNode *node)
{
- node->flag |= PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw;
+ node->flag |= PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw;
}
void BKE_pbvh_node_mark_redraw(PBVHNode *node)
{
- node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw;
+ node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw;
}
void BKE_pbvh_node_mark_normals_update(PBVHNode *node)
{
- node->flag |= PBVH_UpdateNormals;
+ node->flag |= PBVH_UpdateNormals;
}
-
void BKE_pbvh_node_fully_hidden_set(PBVHNode *node, int fully_hidden)
{
- BLI_assert(node->flag & PBVH_Leaf);
-
- if (fully_hidden)
- node->flag |= PBVH_FullyHidden;
- else
- node->flag &= ~PBVH_FullyHidden;
-}
-
-void BKE_pbvh_node_get_verts(
- PBVH *bvh, PBVHNode *node,
- const int **r_vert_indices, MVert **r_verts)
-{
- if (r_vert_indices) {
- *r_vert_indices = node->vert_indices;
- }
-
- if (r_verts) {
- *r_verts = bvh->verts;
- }
-}
-
-void BKE_pbvh_node_num_verts(
- PBVH *bvh, PBVHNode *node,
- int *r_uniquevert, int *r_totvert)
-{
- int tot;
-
- switch (bvh->type) {
- case PBVH_GRIDS:
- tot = node->totprim * bvh->gridkey.grid_area;
- if (r_totvert) *r_totvert = tot;
- if (r_uniquevert) *r_uniquevert = tot;
- break;
- case PBVH_FACES:
- if (r_totvert) *r_totvert = node->uniq_verts + node->face_verts;
- if (r_uniquevert) *r_uniquevert = node->uniq_verts;
- break;
- case PBVH_BMESH:
- tot = BLI_gset_len(node->bm_unique_verts);
- if (r_totvert) *r_totvert = tot + BLI_gset_len(node->bm_other_verts);
- if (r_uniquevert) *r_uniquevert = tot;
- break;
- }
-}
-
-void BKE_pbvh_node_get_grids(
- PBVH *bvh, PBVHNode *node,
- int **r_grid_indices, int *r_totgrid, int *r_maxgrid, int *r_gridsize, CCGElem ***r_griddata)
-{
- switch (bvh->type) {
- case PBVH_GRIDS:
- if (r_grid_indices) *r_grid_indices = node->prim_indices;
- if (r_totgrid) *r_totgrid = node->totprim;
- if (r_maxgrid) *r_maxgrid = bvh->totgrid;
- if (r_gridsize) *r_gridsize = bvh->gridkey.grid_size;
- if (r_griddata) *r_griddata = bvh->grids;
- break;
- case PBVH_FACES:
- case PBVH_BMESH:
- if (r_grid_indices) *r_grid_indices = NULL;
- if (r_totgrid) *r_totgrid = 0;
- if (r_maxgrid) *r_maxgrid = 0;
- if (r_gridsize) *r_gridsize = 0;
- if (r_griddata) *r_griddata = NULL;
- break;
- }
+ BLI_assert(node->flag & PBVH_Leaf);
+
+ if (fully_hidden)
+ node->flag |= PBVH_FullyHidden;
+ else
+ node->flag &= ~PBVH_FullyHidden;
+}
+
+void BKE_pbvh_node_get_verts(PBVH *bvh,
+ PBVHNode *node,
+ const int **r_vert_indices,
+ MVert **r_verts)
+{
+ if (r_vert_indices) {
+ *r_vert_indices = node->vert_indices;
+ }
+
+ if (r_verts) {
+ *r_verts = bvh->verts;
+ }
+}
+
+void BKE_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node, int *r_uniquevert, int *r_totvert)
+{
+ int tot;
+
+ switch (bvh->type) {
+ case PBVH_GRIDS:
+ tot = node->totprim * bvh->gridkey.grid_area;
+ if (r_totvert)
+ *r_totvert = tot;
+ if (r_uniquevert)
+ *r_uniquevert = tot;
+ break;
+ case PBVH_FACES:
+ if (r_totvert)
+ *r_totvert = node->uniq_verts + node->face_verts;
+ if (r_uniquevert)
+ *r_uniquevert = node->uniq_verts;
+ break;
+ case PBVH_BMESH:
+ tot = BLI_gset_len(node->bm_unique_verts);
+ if (r_totvert)
+ *r_totvert = tot + BLI_gset_len(node->bm_other_verts);
+ if (r_uniquevert)
+ *r_uniquevert = tot;
+ break;
+ }
+}
+
+void BKE_pbvh_node_get_grids(PBVH *bvh,
+ PBVHNode *node,
+ int **r_grid_indices,
+ int *r_totgrid,
+ int *r_maxgrid,
+ int *r_gridsize,
+ CCGElem ***r_griddata)
+{
+ switch (bvh->type) {
+ case PBVH_GRIDS:
+ if (r_grid_indices)
+ *r_grid_indices = node->prim_indices;
+ if (r_totgrid)
+ *r_totgrid = node->totprim;
+ if (r_maxgrid)
+ *r_maxgrid = bvh->totgrid;
+ if (r_gridsize)
+ *r_gridsize = bvh->gridkey.grid_size;
+ if (r_griddata)
+ *r_griddata = bvh->grids;
+ break;
+ case PBVH_FACES:
+ case PBVH_BMESH:
+ if (r_grid_indices)
+ *r_grid_indices = NULL;
+ if (r_totgrid)
+ *r_totgrid = 0;
+ if (r_maxgrid)
+ *r_maxgrid = 0;
+ if (r_gridsize)
+ *r_gridsize = 0;
+ if (r_griddata)
+ *r_griddata = NULL;
+ break;
+ }
}
void BKE_pbvh_node_get_BB(PBVHNode *node, float bb_min[3], float bb_max[3])
{
- copy_v3_v3(bb_min, node->vb.bmin);
- copy_v3_v3(bb_max, node->vb.bmax);
+ copy_v3_v3(bb_min, node->vb.bmin);
+ copy_v3_v3(bb_max, node->vb.bmax);
}
void BKE_pbvh_node_get_original_BB(PBVHNode *node, float bb_min[3], float bb_max[3])
{
- copy_v3_v3(bb_min, node->orig_vb.bmin);
- copy_v3_v3(bb_max, node->orig_vb.bmax);
+ copy_v3_v3(bb_min, node->orig_vb.bmin);
+ copy_v3_v3(bb_max, node->orig_vb.bmax);
}
void BKE_pbvh_node_get_proxies(PBVHNode *node, PBVHProxyNode **proxies, int *proxy_count)
{
- if (node->proxy_count > 0) {
- if (proxies) *proxies = node->proxies;
- if (proxy_count) *proxy_count = node->proxy_count;
- }
- else {
- if (proxies) *proxies = NULL;
- if (proxy_count) *proxy_count = 0;
- }
+ if (node->proxy_count > 0) {
+ if (proxies)
+ *proxies = node->proxies;
+ if (proxy_count)
+ *proxy_count = node->proxy_count;
+ }
+ else {
+ if (proxies)
+ *proxies = NULL;
+ if (proxy_count)
+ *proxy_count = 0;
+ }
}
-void BKE_pbvh_node_get_bm_orco_data(
- PBVHNode *node,
- int (**r_orco_tris)[3], int *r_orco_tris_num, float (**r_orco_coords)[3])
+void BKE_pbvh_node_get_bm_orco_data(PBVHNode *node,
+ int (**r_orco_tris)[3],
+ int *r_orco_tris_num,
+ float (**r_orco_coords)[3])
{
- *r_orco_tris = node->bm_ortri;
- *r_orco_tris_num = node->bm_tot_ortri;
- *r_orco_coords = node->bm_orco;
+ *r_orco_tris = node->bm_ortri;
+ *r_orco_tris_num = node->bm_tot_ortri;
+ *r_orco_coords = node->bm_orco;
}
/**
@@ -1480,513 +1510,535 @@ void BKE_pbvh_node_get_bm_orco_data(
*/
bool BKE_pbvh_node_vert_update_check_any(PBVH *bvh, PBVHNode *node)
{
- BLI_assert(bvh->type == PBVH_FACES);
- const int *verts = node->vert_indices;
- const int totvert = node->uniq_verts + node->face_verts;
+ BLI_assert(bvh->type == PBVH_FACES);
+ const int *verts = node->vert_indices;
+ const int totvert = node->uniq_verts + node->face_verts;
- for (int i = 0; i < totvert; ++i) {
- const int v = verts[i];
- const MVert *mvert = &bvh->verts[v];
+ for (int i = 0; i < totvert; ++i) {
+ const int v = verts[i];
+ const MVert *mvert = &bvh->verts[v];
- if (mvert->flag & ME_VERT_PBVH_UPDATE) {
- return true;
- }
- }
+ if (mvert->flag & ME_VERT_PBVH_UPDATE) {
+ return true;
+ }
+ }
- return false;
+ return false;
}
-
/********************************* Raycast ***********************************/
typedef struct {
- struct IsectRayAABB_Precalc ray;
- bool original;
+ struct IsectRayAABB_Precalc ray;
+ bool original;
} RaycastData;
static bool ray_aabb_intersect(PBVHNode *node, void *data_v)
{
- RaycastData *rcd = data_v;
- const float *bb_min, *bb_max;
+ RaycastData *rcd = data_v;
+ const float *bb_min, *bb_max;
- if (rcd->original) {
- /* BKE_pbvh_node_get_original_BB */
- bb_min = node->orig_vb.bmin;
- bb_max = node->orig_vb.bmax;
- }
- else {
- /* BKE_pbvh_node_get_BB */
- bb_min = node->vb.bmin;
- bb_max = node->vb.bmax;
- }
+ if (rcd->original) {
+ /* BKE_pbvh_node_get_original_BB */
+ bb_min = node->orig_vb.bmin;
+ bb_max = node->orig_vb.bmax;
+ }
+ else {
+ /* BKE_pbvh_node_get_BB */
+ bb_min = node->vb.bmin;
+ bb_max = node->vb.bmax;
+ }
- return isect_ray_aabb_v3(&rcd->ray, bb_min, bb_max, &node->tmin);
+ return isect_ray_aabb_v3(&rcd->ray, bb_min, bb_max, &node->tmin);
}
-void BKE_pbvh_raycast(
- PBVH *bvh, BKE_pbvh_HitOccludedCallback cb, void *data,
- const float ray_start[3], const float ray_normal[3],
- bool original)
+void BKE_pbvh_raycast(PBVH *bvh,
+ BKE_pbvh_HitOccludedCallback cb,
+ void *data,
+ const float ray_start[3],
+ const float ray_normal[3],
+ bool original)
{
- RaycastData rcd;
+ RaycastData rcd;
- isect_ray_aabb_v3_precalc(&rcd.ray, ray_start, ray_normal);
- rcd.original = original;
+ isect_ray_aabb_v3_precalc(&rcd.ray, ray_start, ray_normal);
+ rcd.original = original;
- BKE_pbvh_search_callback_occluded(bvh, ray_aabb_intersect, &rcd, cb, data);
+ BKE_pbvh_search_callback_occluded(bvh, ray_aabb_intersect, &rcd, cb, data);
}
-bool ray_face_intersection_quad(
- const float ray_start[3], const float ray_normal[3],
- const float t0[3], const float t1[3], const float t2[3], const float t3[3],
- float *depth)
+bool ray_face_intersection_quad(const float ray_start[3],
+ const float ray_normal[3],
+ const float t0[3],
+ const float t1[3],
+ const float t2[3],
+ const float t3[3],
+ float *depth)
{
- float depth_test;
+ float depth_test;
- if ((isect_ray_tri_epsilon_v3(
- ray_start, ray_normal, t0, t1, t2, &depth_test, NULL, 0.1f) && (depth_test < *depth)) ||
- (isect_ray_tri_epsilon_v3(
- ray_start, ray_normal, t0, t2, t3, &depth_test, NULL, 0.1f) && (depth_test < *depth)))
- {
- *depth = depth_test;
- return true;
- }
- else {
- return false;
- }
+ if ((isect_ray_tri_epsilon_v3(ray_start, ray_normal, t0, t1, t2, &depth_test, NULL, 0.1f) &&
+ (depth_test < *depth)) ||
+ (isect_ray_tri_epsilon_v3(ray_start, ray_normal, t0, t2, t3, &depth_test, NULL, 0.1f) &&
+ (depth_test < *depth))) {
+ *depth = depth_test;
+ return true;
+ }
+ else {
+ return false;
+ }
}
-bool ray_face_intersection_tri(
- const float ray_start[3], const float ray_normal[3],
- const float t0[3], const float t1[3], const float t2[3],
- float *depth)
+bool ray_face_intersection_tri(const float ray_start[3],
+ const float ray_normal[3],
+ const float t0[3],
+ const float t1[3],
+ const float t2[3],
+ float *depth)
{
- float depth_test;
+ float depth_test;
- if ((isect_ray_tri_epsilon_v3(
- ray_start, ray_normal, t0, t1, t2, &depth_test, NULL, 0.1f) && (depth_test < *depth)))
- {
- *depth = depth_test;
- return true;
- }
- else {
- return false;
- }
+ if ((isect_ray_tri_epsilon_v3(ray_start, ray_normal, t0, t1, t2, &depth_test, NULL, 0.1f) &&
+ (depth_test < *depth))) {
+ *depth = depth_test;
+ return true;
+ }
+ else {
+ return false;
+ }
}
/* Take advantage of the fact we know this wont be an intersection.
* Just handle ray-tri edges. */
-static float dist_squared_ray_to_tri_v3_fast(
- const float ray_origin[3], const float ray_direction[3],
- const float v0[3], const float v1[3], const float v2[3],
- float r_point[3], float *r_depth)
-{
- const float *tri[3] = {v0, v1, v2};
- float dist_sq_best = FLT_MAX;
- for (int i = 0, j = 2; i < 3; j = i++) {
- float point_test[3], depth_test = FLT_MAX;
- const float dist_sq_test = dist_squared_ray_to_seg_v3(
- ray_origin, ray_direction, tri[i], tri[j], point_test, &depth_test);
- if (dist_sq_test < dist_sq_best || i == 0) {
- copy_v3_v3(r_point, point_test);
- *r_depth = depth_test;
- dist_sq_best = dist_sq_test;
- }
- }
- return dist_sq_best;
-}
-
-bool ray_face_nearest_quad(
- const float ray_start[3], const float ray_normal[3],
- const float t0[3], const float t1[3], const float t2[3], const float t3[3],
- float *depth, float *dist_sq)
-{
- float dist_sq_test;
- float co[3], depth_test;
-
- if (((dist_sq_test = dist_squared_ray_to_tri_v3_fast(
- ray_start, ray_normal, t0, t1, t2, co, &depth_test)) < *dist_sq))
- {
- *dist_sq = dist_sq_test;
- *depth = depth_test;
- if (((dist_sq_test = dist_squared_ray_to_tri_v3_fast(
- ray_start, ray_normal, t0, t2, t3, co, &depth_test)) < *dist_sq))
- {
- *dist_sq = dist_sq_test;
- *depth = depth_test;
- }
- return true;
- }
- else {
- return false;
- }
-}
-
-bool ray_face_nearest_tri(
- const float ray_start[3], const float ray_normal[3],
- const float t0[3], const float t1[3], const float t2[3],
- float *depth, float *dist_sq)
-{
- float dist_sq_test;
- float co[3], depth_test;
-
- if (((dist_sq_test = dist_squared_ray_to_tri_v3_fast(
- ray_start, ray_normal, t0, t1, t2, co, &depth_test)) < *dist_sq))
- {
- *dist_sq = dist_sq_test;
- *depth = depth_test;
- return true;
- }
- else {
- return false;
- }
-}
-
-static bool pbvh_faces_node_raycast(
- PBVH *bvh, const PBVHNode *node,
- float (*origco)[3],
- const float ray_start[3], const float ray_normal[3],
- float *depth)
-{
- const MVert *vert = bvh->verts;
- const MLoop *mloop = bvh->mloop;
- const int *faces = node->prim_indices;
- int i, totface = node->totprim;
- bool hit = false;
-
- for (i = 0; i < totface; ++i) {
- const MLoopTri *lt = &bvh->looptri[faces[i]];
- const int *face_verts = node->face_vert_indices[i];
-
- if (paint_is_face_hidden(lt, vert, mloop))
- continue;
-
- if (origco) {
- /* intersect with backuped original coordinates */
- hit |= ray_face_intersection_tri(
- ray_start, ray_normal,
- origco[face_verts[0]],
- origco[face_verts[1]],
- origco[face_verts[2]],
- depth);
- }
- else {
- /* intersect with current coordinates */
- hit |= ray_face_intersection_tri(
- ray_start, ray_normal,
- vert[mloop[lt->tri[0]].v].co,
- vert[mloop[lt->tri[1]].v].co,
- vert[mloop[lt->tri[2]].v].co,
- depth);
- }
- }
-
- return hit;
-}
-
-static bool pbvh_grids_node_raycast(
- PBVH *bvh, PBVHNode *node,
- float (*origco)[3],
- const float ray_start[3], const float ray_normal[3],
- float *depth)
-{
- const int totgrid = node->totprim;
- const int gridsize = bvh->gridkey.grid_size;
- bool hit = false;
-
- for (int i = 0; i < totgrid; ++i) {
- CCGElem *grid = bvh->grids[node->prim_indices[i]];
- BLI_bitmap *gh;
-
- if (!grid)
- continue;
-
- gh = bvh->grid_hidden[node->prim_indices[i]];
-
- for (int y = 0; y < gridsize - 1; ++y) {
- for (int x = 0; x < gridsize - 1; ++x) {
- /* check if grid face is hidden */
- if (gh) {
- if (paint_is_grid_face_hidden(gh, gridsize, x, y))
- continue;
- }
-
- if (origco) {
- hit |= ray_face_intersection_quad(
- ray_start, ray_normal,
- origco[y * gridsize + x],
- origco[y * gridsize + x + 1],
- origco[(y + 1) * gridsize + x + 1],
- origco[(y + 1) * gridsize + x],
- depth);
- }
- else {
- hit |= ray_face_intersection_quad(
- ray_start, ray_normal,
- CCG_grid_elem_co(&bvh->gridkey, grid, x, y),
- CCG_grid_elem_co(&bvh->gridkey, grid, x + 1, y),
- CCG_grid_elem_co(&bvh->gridkey, grid, x + 1, y + 1),
- CCG_grid_elem_co(&bvh->gridkey, grid, x, y + 1),
- depth);
- }
- }
- }
-
- if (origco)
- origco += gridsize * gridsize;
- }
-
- return hit;
-}
-
-bool BKE_pbvh_node_raycast(
- PBVH *bvh, PBVHNode *node, float (*origco)[3], bool use_origco,
- const float ray_start[3], const float ray_normal[3],
- float *depth)
-{
- bool hit = false;
-
- if (node->flag & PBVH_FullyHidden)
- return false;
-
- switch (bvh->type) {
- case PBVH_FACES:
- hit |= pbvh_faces_node_raycast(
- bvh, node, origco,
- ray_start, ray_normal, depth);
- break;
- case PBVH_GRIDS:
- hit |= pbvh_grids_node_raycast(
- bvh, node, origco,
- ray_start, ray_normal, depth);
- break;
- case PBVH_BMESH:
- hit = pbvh_bmesh_node_raycast(
- node, ray_start, ray_normal, depth, use_origco);
- break;
- }
-
- return hit;
+static float dist_squared_ray_to_tri_v3_fast(const float ray_origin[3],
+ const float ray_direction[3],
+ const float v0[3],
+ const float v1[3],
+ const float v2[3],
+ float r_point[3],
+ float *r_depth)
+{
+ const float *tri[3] = {v0, v1, v2};
+ float dist_sq_best = FLT_MAX;
+ for (int i = 0, j = 2; i < 3; j = i++) {
+ float point_test[3], depth_test = FLT_MAX;
+ const float dist_sq_test = dist_squared_ray_to_seg_v3(
+ ray_origin, ray_direction, tri[i], tri[j], point_test, &depth_test);
+ if (dist_sq_test < dist_sq_best || i == 0) {
+ copy_v3_v3(r_point, point_test);
+ *r_depth = depth_test;
+ dist_sq_best = dist_sq_test;
+ }
+ }
+ return dist_sq_best;
+}
+
+bool ray_face_nearest_quad(const float ray_start[3],
+ const float ray_normal[3],
+ const float t0[3],
+ const float t1[3],
+ const float t2[3],
+ const float t3[3],
+ float *depth,
+ float *dist_sq)
+{
+ float dist_sq_test;
+ float co[3], depth_test;
+
+ if (((dist_sq_test = dist_squared_ray_to_tri_v3_fast(
+ ray_start, ray_normal, t0, t1, t2, co, &depth_test)) < *dist_sq)) {
+ *dist_sq = dist_sq_test;
+ *depth = depth_test;
+ if (((dist_sq_test = dist_squared_ray_to_tri_v3_fast(
+ ray_start, ray_normal, t0, t2, t3, co, &depth_test)) < *dist_sq)) {
+ *dist_sq = dist_sq_test;
+ *depth = depth_test;
+ }
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+bool ray_face_nearest_tri(const float ray_start[3],
+ const float ray_normal[3],
+ const float t0[3],
+ const float t1[3],
+ const float t2[3],
+ float *depth,
+ float *dist_sq)
+{
+ float dist_sq_test;
+ float co[3], depth_test;
+
+ if (((dist_sq_test = dist_squared_ray_to_tri_v3_fast(
+ ray_start, ray_normal, t0, t1, t2, co, &depth_test)) < *dist_sq)) {
+ *dist_sq = dist_sq_test;
+ *depth = depth_test;
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+static bool pbvh_faces_node_raycast(PBVH *bvh,
+ const PBVHNode *node,
+ float (*origco)[3],
+ const float ray_start[3],
+ const float ray_normal[3],
+ float *depth)
+{
+ const MVert *vert = bvh->verts;
+ const MLoop *mloop = bvh->mloop;
+ const int *faces = node->prim_indices;
+ int i, totface = node->totprim;
+ bool hit = false;
+
+ for (i = 0; i < totface; ++i) {
+ const MLoopTri *lt = &bvh->looptri[faces[i]];
+ const int *face_verts = node->face_vert_indices[i];
+
+ if (paint_is_face_hidden(lt, vert, mloop))
+ continue;
+
+ if (origco) {
+ /* intersect with backuped original coordinates */
+ hit |= ray_face_intersection_tri(ray_start,
+ ray_normal,
+ origco[face_verts[0]],
+ origco[face_verts[1]],
+ origco[face_verts[2]],
+ depth);
+ }
+ else {
+ /* intersect with current coordinates */
+ hit |= ray_face_intersection_tri(ray_start,
+ ray_normal,
+ vert[mloop[lt->tri[0]].v].co,
+ vert[mloop[lt->tri[1]].v].co,
+ vert[mloop[lt->tri[2]].v].co,
+ depth);
+ }
+ }
+
+ return hit;
+}
+
+static bool pbvh_grids_node_raycast(PBVH *bvh,
+ PBVHNode *node,
+ float (*origco)[3],
+ const float ray_start[3],
+ const float ray_normal[3],
+ float *depth)
+{
+ const int totgrid = node->totprim;
+ const int gridsize = bvh->gridkey.grid_size;
+ bool hit = false;
+
+ for (int i = 0; i < totgrid; ++i) {
+ CCGElem *grid = bvh->grids[node->prim_indices[i]];
+ BLI_bitmap *gh;
+
+ if (!grid)
+ continue;
+
+ gh = bvh->grid_hidden[node->prim_indices[i]];
+
+ for (int y = 0; y < gridsize - 1; ++y) {
+ for (int x = 0; x < gridsize - 1; ++x) {
+ /* check if grid face is hidden */
+ if (gh) {
+ if (paint_is_grid_face_hidden(gh, gridsize, x, y))
+ continue;
+ }
+
+ if (origco) {
+ hit |= ray_face_intersection_quad(ray_start,
+ ray_normal,
+ origco[y * gridsize + x],
+ origco[y * gridsize + x + 1],
+ origco[(y + 1) * gridsize + x + 1],
+ origco[(y + 1) * gridsize + x],
+ depth);
+ }
+ else {
+ hit |= ray_face_intersection_quad(ray_start,
+ ray_normal,
+ CCG_grid_elem_co(&bvh->gridkey, grid, x, y),
+ CCG_grid_elem_co(&bvh->gridkey, grid, x + 1, y),
+ CCG_grid_elem_co(&bvh->gridkey, grid, x + 1, y + 1),
+ CCG_grid_elem_co(&bvh->gridkey, grid, x, y + 1),
+ depth);
+ }
+ }
+ }
+
+ if (origco)
+ origco += gridsize * gridsize;
+ }
+
+ return hit;
+}
+
+bool BKE_pbvh_node_raycast(PBVH *bvh,
+ PBVHNode *node,
+ float (*origco)[3],
+ bool use_origco,
+ const float ray_start[3],
+ const float ray_normal[3],
+ float *depth)
+{
+ bool hit = false;
+
+ if (node->flag & PBVH_FullyHidden)
+ return false;
+
+ switch (bvh->type) {
+ case PBVH_FACES:
+ hit |= pbvh_faces_node_raycast(bvh, node, origco, ray_start, ray_normal, depth);
+ break;
+ case PBVH_GRIDS:
+ hit |= pbvh_grids_node_raycast(bvh, node, origco, ray_start, ray_normal, depth);
+ break;
+ case PBVH_BMESH:
+ hit = pbvh_bmesh_node_raycast(node, ray_start, ray_normal, depth, use_origco);
+ break;
+ }
+
+ return hit;
}
void BKE_pbvh_raycast_project_ray_root(
- PBVH *bvh, bool original,
- float ray_start[3], float ray_end[3], float ray_normal[3])
-{
- if (bvh->nodes) {
- float rootmin_start, rootmin_end;
- float bb_min_root[3], bb_max_root[3], bb_center[3], bb_diff[3];
- struct IsectRayAABB_Precalc ray;
- float ray_normal_inv[3];
- float offset = 1.0f + 1e-3f;
- float offset_vec[3] = {1e-3f, 1e-3f, 1e-3f};
-
- if (original)
- BKE_pbvh_node_get_original_BB(bvh->nodes, bb_min_root, bb_max_root);
- else
- BKE_pbvh_node_get_BB(bvh->nodes, bb_min_root, bb_max_root);
-
- /* slightly offset min and max in case we have a zero width node (due to a plane mesh for instance),
- * or faces very close to the bounding box boundary. */
- mid_v3_v3v3(bb_center, bb_max_root, bb_min_root);
- /* diff should be same for both min/max since it's calculated from center */
- sub_v3_v3v3(bb_diff, bb_max_root, bb_center);
- /* handles case of zero width bb */
- add_v3_v3(bb_diff, offset_vec);
- madd_v3_v3v3fl(bb_max_root, bb_center, bb_diff, offset);
- madd_v3_v3v3fl(bb_min_root, bb_center, bb_diff, -offset);
-
- /* first project start ray */
- isect_ray_aabb_v3_precalc(&ray, ray_start, ray_normal);
- if (!isect_ray_aabb_v3(&ray, bb_min_root, bb_max_root, &rootmin_start))
- return;
-
- /* then the end ray */
- mul_v3_v3fl(ray_normal_inv, ray_normal, -1.0);
- isect_ray_aabb_v3_precalc(&ray, ray_end, ray_normal_inv);
- /* unlikely to fail exiting if entering succeeded, still keep this here */
- if (!isect_ray_aabb_v3(&ray, bb_min_root, bb_max_root, &rootmin_end))
- return;
-
- madd_v3_v3v3fl(ray_start, ray_start, ray_normal, rootmin_start);
- madd_v3_v3v3fl(ray_end, ray_end, ray_normal_inv, rootmin_end);
- }
+ PBVH *bvh, bool original, float ray_start[3], float ray_end[3], float ray_normal[3])
+{
+ if (bvh->nodes) {
+ float rootmin_start, rootmin_end;
+ float bb_min_root[3], bb_max_root[3], bb_center[3], bb_diff[3];
+ struct IsectRayAABB_Precalc ray;
+ float ray_normal_inv[3];
+ float offset = 1.0f + 1e-3f;
+ float offset_vec[3] = {1e-3f, 1e-3f, 1e-3f};
+
+ if (original)
+ BKE_pbvh_node_get_original_BB(bvh->nodes, bb_min_root, bb_max_root);
+ else
+ BKE_pbvh_node_get_BB(bvh->nodes, bb_min_root, bb_max_root);
+
+ /* slightly offset min and max in case we have a zero width node (due to a plane mesh for instance),
+ * or faces very close to the bounding box boundary. */
+ mid_v3_v3v3(bb_center, bb_max_root, bb_min_root);
+ /* diff should be same for both min/max since it's calculated from center */
+ sub_v3_v3v3(bb_diff, bb_max_root, bb_center);
+ /* handles case of zero width bb */
+ add_v3_v3(bb_diff, offset_vec);
+ madd_v3_v3v3fl(bb_max_root, bb_center, bb_diff, offset);
+ madd_v3_v3v3fl(bb_min_root, bb_center, bb_diff, -offset);
+
+ /* first project start ray */
+ isect_ray_aabb_v3_precalc(&ray, ray_start, ray_normal);
+ if (!isect_ray_aabb_v3(&ray, bb_min_root, bb_max_root, &rootmin_start))
+ return;
+
+ /* then the end ray */
+ mul_v3_v3fl(ray_normal_inv, ray_normal, -1.0);
+ isect_ray_aabb_v3_precalc(&ray, ray_end, ray_normal_inv);
+ /* unlikely to fail exiting if entering succeeded, still keep this here */
+ if (!isect_ray_aabb_v3(&ray, bb_min_root, bb_max_root, &rootmin_end))
+ return;
+
+ madd_v3_v3v3fl(ray_start, ray_start, ray_normal, rootmin_start);
+ madd_v3_v3v3fl(ray_end, ray_end, ray_normal_inv, rootmin_end);
+ }
}
/* -------------------------------------------------------------------- */
typedef struct {
- struct DistRayAABB_Precalc dist_ray_to_aabb_precalc;
- bool original;
+ struct DistRayAABB_Precalc dist_ray_to_aabb_precalc;
+ bool original;
} FindNearestRayData;
static bool nearest_to_ray_aabb_dist_sq(PBVHNode *node, void *data_v)
{
- FindNearestRayData *rcd = data_v;
- const float *bb_min, *bb_max;
-
- if (rcd->original) {
- /* BKE_pbvh_node_get_original_BB */
- bb_min = node->orig_vb.bmin;
- bb_max = node->orig_vb.bmax;
- }
- else {
- /* BKE_pbvh_node_get_BB */
- bb_min = node->vb.bmin;
- bb_max = node->vb.bmax;
- }
-
- float co_dummy[3], depth;
- node->tmin = dist_squared_ray_to_aabb_v3(&rcd->dist_ray_to_aabb_precalc, bb_min, bb_max, co_dummy, &depth);
- /* Ideally we would skip distances outside the range. */
- return depth > 0.0f;
-}
-
-void BKE_pbvh_find_nearest_to_ray(
- PBVH *bvh, BKE_pbvh_SearchNearestCallback cb, void *data,
- const float ray_start[3], const float ray_normal[3],
- bool original)
-{
- FindNearestRayData ncd;
-
- dist_squared_ray_to_aabb_v3_precalc(&ncd.dist_ray_to_aabb_precalc, ray_start, ray_normal);
- ncd.original = original;
-
- BKE_pbvh_search_callback_occluded(bvh, nearest_to_ray_aabb_dist_sq, &ncd, cb, data);
-}
-
-
-static bool pbvh_faces_node_nearest_to_ray(
- PBVH *bvh, const PBVHNode *node,
- float (*origco)[3],
- const float ray_start[3], const float ray_normal[3],
- float *depth, float *dist_sq)
-{
- const MVert *vert = bvh->verts;
- const MLoop *mloop = bvh->mloop;
- const int *faces = node->prim_indices;
- int i, totface = node->totprim;
- bool hit = false;
-
- for (i = 0; i < totface; ++i) {
- const MLoopTri *lt = &bvh->looptri[faces[i]];
- const int *face_verts = node->face_vert_indices[i];
-
- if (paint_is_face_hidden(lt, vert, mloop))
- continue;
-
- if (origco) {
- /* intersect with backuped original coordinates */
- hit |= ray_face_nearest_tri(
- ray_start, ray_normal,
- origco[face_verts[0]],
- origco[face_verts[1]],
- origco[face_verts[2]],
- depth, dist_sq);
- }
- else {
- /* intersect with current coordinates */
- hit |= ray_face_nearest_tri(
- ray_start, ray_normal,
- vert[mloop[lt->tri[0]].v].co,
- vert[mloop[lt->tri[1]].v].co,
- vert[mloop[lt->tri[2]].v].co,
- depth, dist_sq);
- }
- }
-
- return hit;
-}
-
-static bool pbvh_grids_node_nearest_to_ray(
- PBVH *bvh, PBVHNode *node,
- float (*origco)[3],
- const float ray_start[3], const float ray_normal[3],
- float *depth, float *dist_sq)
-{
- const int totgrid = node->totprim;
- const int gridsize = bvh->gridkey.grid_size;
- bool hit = false;
-
- for (int i = 0; i < totgrid; ++i) {
- CCGElem *grid = bvh->grids[node->prim_indices[i]];
- BLI_bitmap *gh;
-
- if (!grid)
- continue;
-
- gh = bvh->grid_hidden[node->prim_indices[i]];
-
- for (int y = 0; y < gridsize - 1; ++y) {
- for (int x = 0; x < gridsize - 1; ++x) {
- /* check if grid face is hidden */
- if (gh) {
- if (paint_is_grid_face_hidden(gh, gridsize, x, y))
- continue;
- }
-
- if (origco) {
- hit |= ray_face_nearest_quad(
- ray_start, ray_normal,
- origco[y * gridsize + x],
- origco[y * gridsize + x + 1],
- origco[(y + 1) * gridsize + x + 1],
- origco[(y + 1) * gridsize + x],
- depth, dist_sq);
- }
- else {
- hit |= ray_face_nearest_quad(
- ray_start, ray_normal,
- CCG_grid_elem_co(&bvh->gridkey, grid, x, y),
- CCG_grid_elem_co(&bvh->gridkey, grid, x + 1, y),
- CCG_grid_elem_co(&bvh->gridkey, grid, x + 1, y + 1),
- CCG_grid_elem_co(&bvh->gridkey, grid, x, y + 1),
- depth, dist_sq);
- }
- }
- }
-
- if (origco)
- origco += gridsize * gridsize;
- }
-
- return hit;
-}
-
-bool BKE_pbvh_node_find_nearest_to_ray(
- PBVH *bvh, PBVHNode *node, float (*origco)[3], bool use_origco,
- const float ray_start[3], const float ray_normal[3],
- float *depth, float *dist_sq)
-{
- bool hit = false;
-
- if (node->flag & PBVH_FullyHidden)
- return false;
-
- switch (bvh->type) {
- case PBVH_FACES:
- hit |= pbvh_faces_node_nearest_to_ray(
- bvh, node, origco,
- ray_start, ray_normal, depth, dist_sq);
- break;
- case PBVH_GRIDS:
- hit |= pbvh_grids_node_nearest_to_ray(
- bvh, node, origco,
- ray_start, ray_normal, depth, dist_sq);
- break;
- case PBVH_BMESH:
- hit = pbvh_bmesh_node_nearest_to_ray(
- node, ray_start, ray_normal, depth, dist_sq, use_origco);
- break;
- }
-
- return hit;
+ FindNearestRayData *rcd = data_v;
+ const float *bb_min, *bb_max;
+
+ if (rcd->original) {
+ /* BKE_pbvh_node_get_original_BB */
+ bb_min = node->orig_vb.bmin;
+ bb_max = node->orig_vb.bmax;
+ }
+ else {
+ /* BKE_pbvh_node_get_BB */
+ bb_min = node->vb.bmin;
+ bb_max = node->vb.bmax;
+ }
+
+ float co_dummy[3], depth;
+ node->tmin = dist_squared_ray_to_aabb_v3(
+ &rcd->dist_ray_to_aabb_precalc, bb_min, bb_max, co_dummy, &depth);
+ /* Ideally we would skip distances outside the range. */
+ return depth > 0.0f;
+}
+
+void BKE_pbvh_find_nearest_to_ray(PBVH *bvh,
+ BKE_pbvh_SearchNearestCallback cb,
+ void *data,
+ const float ray_start[3],
+ const float ray_normal[3],
+ bool original)
+{
+ FindNearestRayData ncd;
+
+ dist_squared_ray_to_aabb_v3_precalc(&ncd.dist_ray_to_aabb_precalc, ray_start, ray_normal);
+ ncd.original = original;
+
+ BKE_pbvh_search_callback_occluded(bvh, nearest_to_ray_aabb_dist_sq, &ncd, cb, data);
+}
+
+static bool pbvh_faces_node_nearest_to_ray(PBVH *bvh,
+ const PBVHNode *node,
+ float (*origco)[3],
+ const float ray_start[3],
+ const float ray_normal[3],
+ float *depth,
+ float *dist_sq)
+{
+ const MVert *vert = bvh->verts;
+ const MLoop *mloop = bvh->mloop;
+ const int *faces = node->prim_indices;
+ int i, totface = node->totprim;
+ bool hit = false;
+
+ for (i = 0; i < totface; ++i) {
+ const MLoopTri *lt = &bvh->looptri[faces[i]];
+ const int *face_verts = node->face_vert_indices[i];
+
+ if (paint_is_face_hidden(lt, vert, mloop))
+ continue;
+
+ if (origco) {
+ /* intersect with backuped original coordinates */
+ hit |= ray_face_nearest_tri(ray_start,
+ ray_normal,
+ origco[face_verts[0]],
+ origco[face_verts[1]],
+ origco[face_verts[2]],
+ depth,
+ dist_sq);
+ }
+ else {
+ /* intersect with current coordinates */
+ hit |= ray_face_nearest_tri(ray_start,
+ ray_normal,
+ vert[mloop[lt->tri[0]].v].co,
+ vert[mloop[lt->tri[1]].v].co,
+ vert[mloop[lt->tri[2]].v].co,
+ depth,
+ dist_sq);
+ }
+ }
+
+ return hit;
+}
+
+static bool pbvh_grids_node_nearest_to_ray(PBVH *bvh,
+ PBVHNode *node,
+ float (*origco)[3],
+ const float ray_start[3],
+ const float ray_normal[3],
+ float *depth,
+ float *dist_sq)
+{
+ const int totgrid = node->totprim;
+ const int gridsize = bvh->gridkey.grid_size;
+ bool hit = false;
+
+ for (int i = 0; i < totgrid; ++i) {
+ CCGElem *grid = bvh->grids[node->prim_indices[i]];
+ BLI_bitmap *gh;
+
+ if (!grid)
+ continue;
+
+ gh = bvh->grid_hidden[node->prim_indices[i]];
+
+ for (int y = 0; y < gridsize - 1; ++y) {
+ for (int x = 0; x < gridsize - 1; ++x) {
+ /* check if grid face is hidden */
+ if (gh) {
+ if (paint_is_grid_face_hidden(gh, gridsize, x, y))
+ continue;
+ }
+
+ if (origco) {
+ hit |= ray_face_nearest_quad(ray_start,
+ ray_normal,
+ origco[y * gridsize + x],
+ origco[y * gridsize + x + 1],
+ origco[(y + 1) * gridsize + x + 1],
+ origco[(y + 1) * gridsize + x],
+ depth,
+ dist_sq);
+ }
+ else {
+ hit |= ray_face_nearest_quad(ray_start,
+ ray_normal,
+ CCG_grid_elem_co(&bvh->gridkey, grid, x, y),
+ CCG_grid_elem_co(&bvh->gridkey, grid, x + 1, y),
+ CCG_grid_elem_co(&bvh->gridkey, grid, x + 1, y + 1),
+ CCG_grid_elem_co(&bvh->gridkey, grid, x, y + 1),
+ depth,
+ dist_sq);
+ }
+ }
+ }
+
+ if (origco)
+ origco += gridsize * gridsize;
+ }
+
+ return hit;
+}
+
+bool BKE_pbvh_node_find_nearest_to_ray(PBVH *bvh,
+ PBVHNode *node,
+ float (*origco)[3],
+ bool use_origco,
+ const float ray_start[3],
+ const float ray_normal[3],
+ float *depth,
+ float *dist_sq)
+{
+ bool hit = false;
+
+ if (node->flag & PBVH_FullyHidden)
+ return false;
+
+ switch (bvh->type) {
+ case PBVH_FACES:
+ hit |= pbvh_faces_node_nearest_to_ray(
+ bvh, node, origco, ray_start, ray_normal, depth, dist_sq);
+ break;
+ case PBVH_GRIDS:
+ hit |= pbvh_grids_node_nearest_to_ray(
+ bvh, node, origco, ray_start, ray_normal, depth, dist_sq);
+ break;
+ case PBVH_BMESH:
+ hit = pbvh_bmesh_node_nearest_to_ray(
+ node, ray_start, ray_normal, depth, dist_sq, use_origco);
+ break;
+ }
+
+ return hit;
}
typedef enum {
- ISECT_INSIDE,
- ISECT_OUTSIDE,
- ISECT_INTERSECT,
+ ISECT_INSIDE,
+ ISECT_OUTSIDE,
+ ISECT_INTERSECT,
} PlaneAABBIsect;
/* Adapted from:
@@ -1998,349 +2050,349 @@ static PlaneAABBIsect test_planes_aabb(const float bb_min[3],
const float bb_max[3],
const float (*planes)[4])
{
- float vmin[3], vmax[3];
- PlaneAABBIsect ret = ISECT_INSIDE;
+ float vmin[3], vmax[3];
+ PlaneAABBIsect ret = ISECT_INSIDE;
- for (int i = 0; i < 4; ++i) {
- for (int axis = 0; axis < 3; ++axis) {
- if (planes[i][axis] > 0) {
- vmin[axis] = bb_min[axis];
- vmax[axis] = bb_max[axis];
- }
- else {
- vmin[axis] = bb_max[axis];
- vmax[axis] = bb_min[axis];
- }
- }
+ for (int i = 0; i < 4; ++i) {
+ for (int axis = 0; axis < 3; ++axis) {
+ if (planes[i][axis] > 0) {
+ vmin[axis] = bb_min[axis];
+ vmax[axis] = bb_max[axis];
+ }
+ else {
+ vmin[axis] = bb_max[axis];
+ vmax[axis] = bb_min[axis];
+ }
+ }
- if (dot_v3v3(planes[i], vmin) + planes[i][3] > 0)
- return ISECT_OUTSIDE;
- else if (dot_v3v3(planes[i], vmax) + planes[i][3] >= 0)
- ret = ISECT_INTERSECT;
- }
+ if (dot_v3v3(planes[i], vmin) + planes[i][3] > 0)
+ return ISECT_OUTSIDE;
+ else if (dot_v3v3(planes[i], vmax) + planes[i][3] >= 0)
+ ret = ISECT_INTERSECT;
+ }
- return ret;
+ return ret;
}
bool BKE_pbvh_node_planes_contain_AABB(PBVHNode *node, void *data)
{
- const float *bb_min, *bb_max;
- /* BKE_pbvh_node_get_BB */
- bb_min = node->vb.bmin;
- bb_max = node->vb.bmax;
+ const float *bb_min, *bb_max;
+ /* BKE_pbvh_node_get_BB */
+ bb_min = node->vb.bmin;
+ bb_max = node->vb.bmax;
- return test_planes_aabb(bb_min, bb_max, data) != ISECT_OUTSIDE;
+ return test_planes_aabb(bb_min, bb_max, data) != ISECT_OUTSIDE;
}
bool BKE_pbvh_node_planes_exclude_AABB(PBVHNode *node, void *data)
{
- const float *bb_min, *bb_max;
- /* BKE_pbvh_node_get_BB */
- bb_min = node->vb.bmin;
- bb_max = node->vb.bmax;
+ const float *bb_min, *bb_max;
+ /* BKE_pbvh_node_get_BB */
+ bb_min = node->vb.bmin;
+ bb_max = node->vb.bmax;
- return test_planes_aabb(bb_min, bb_max, data) != ISECT_INSIDE;
+ return test_planes_aabb(bb_min, bb_max, data) != ISECT_INSIDE;
}
struct PBVHNodeDrawCallbackData {
- void (*draw_fn)(void *user_data, GPUBatch *batch);
- void *user_data;
- bool fast;
- bool only_mask; /* Only draw nodes that have mask data. */
- bool wires;
+ void (*draw_fn)(void *user_data, GPUBatch *batch);
+ void *user_data;
+ bool fast;
+ bool only_mask; /* Only draw nodes that have mask data. */
+ bool wires;
};
static void pbvh_node_draw_cb(PBVHNode *node, void *data_v)
{
- struct PBVHNodeDrawCallbackData *data = data_v;
+ struct PBVHNodeDrawCallbackData *data = data_v;
- if (!(node->flag & PBVH_FullyHidden)) {
- GPUBatch *batch = GPU_pbvh_buffers_batch_get(node->draw_buffers, data->fast, data->wires);
- bool show_mask = GPU_pbvh_buffers_has_mask(node->draw_buffers);
- if (!data->only_mask || show_mask) {
- if (batch != NULL) {
- data->draw_fn(data->user_data, batch);
- }
- }
- }
+ if (!(node->flag & PBVH_FullyHidden)) {
+ GPUBatch *batch = GPU_pbvh_buffers_batch_get(node->draw_buffers, data->fast, data->wires);
+ bool show_mask = GPU_pbvh_buffers_has_mask(node->draw_buffers);
+ if (!data->only_mask || show_mask) {
+ if (batch != NULL) {
+ data->draw_fn(data->user_data, batch);
+ }
+ }
+ }
}
/**
* Version of #BKE_pbvh_draw that runs a callback.
*/
-void BKE_pbvh_draw_cb(
- PBVH *bvh, float (*planes)[4], float (*fnors)[3], bool fast, bool wires, bool only_mask,
- void (*draw_fn)(void *user_data, GPUBatch *batch), void *user_data)
-{
- struct PBVHNodeDrawCallbackData draw_data = {
- .only_mask = only_mask,
- .fast = fast,
- .wires = wires,
- .draw_fn = draw_fn,
- .user_data = user_data,
- };
- PBVHNode **nodes;
- int totnode;
-
- BKE_pbvh_search_gather(bvh, update_search_cb, POINTER_FROM_INT(PBVH_UpdateNormals | PBVH_UpdateDrawBuffers),
- &nodes, &totnode);
-
- pbvh_update_normals(bvh, nodes, totnode, fnors);
- pbvh_update_draw_buffers(bvh, nodes, totnode);
-
- if (nodes) MEM_freeN(nodes);
-
- if (planes) {
- BKE_pbvh_search_callback(
- bvh, BKE_pbvh_node_planes_contain_AABB,
- planes, pbvh_node_draw_cb, &draw_data);
- }
- else {
- BKE_pbvh_search_callback(
- bvh, NULL,
- NULL, pbvh_node_draw_cb, &draw_data);
- }
+void BKE_pbvh_draw_cb(PBVH *bvh,
+ float (*planes)[4],
+ float (*fnors)[3],
+ bool fast,
+ bool wires,
+ bool only_mask,
+ void (*draw_fn)(void *user_data, GPUBatch *batch),
+ void *user_data)
+{
+ struct PBVHNodeDrawCallbackData draw_data = {
+ .only_mask = only_mask,
+ .fast = fast,
+ .wires = wires,
+ .draw_fn = draw_fn,
+ .user_data = user_data,
+ };
+ PBVHNode **nodes;
+ int totnode;
+
+ BKE_pbvh_search_gather(bvh,
+ update_search_cb,
+ POINTER_FROM_INT(PBVH_UpdateNormals | PBVH_UpdateDrawBuffers),
+ &nodes,
+ &totnode);
+
+ pbvh_update_normals(bvh, nodes, totnode, fnors);
+ pbvh_update_draw_buffers(bvh, nodes, totnode);
+
+ if (nodes)
+ MEM_freeN(nodes);
+
+ if (planes) {
+ BKE_pbvh_search_callback(
+ bvh, BKE_pbvh_node_planes_contain_AABB, planes, pbvh_node_draw_cb, &draw_data);
+ }
+ else {
+ BKE_pbvh_search_callback(bvh, NULL, NULL, pbvh_node_draw_cb, &draw_data);
+ }
#if 0
- if (G.debug_value == 14)
- pbvh_draw_BB(bvh);
+ if (G.debug_value == 14)
+ pbvh_draw_BB(bvh);
#endif
}
-void BKE_pbvh_grids_update(PBVH *bvh, CCGElem **grids, void **gridfaces,
- DMFlagMat *flagmats, BLI_bitmap **grid_hidden)
+void BKE_pbvh_grids_update(
+ PBVH *bvh, CCGElem **grids, void **gridfaces, DMFlagMat *flagmats, BLI_bitmap **grid_hidden)
{
- bvh->grids = grids;
- bvh->gridfaces = gridfaces;
+ bvh->grids = grids;
+ bvh->gridfaces = gridfaces;
- if (flagmats != bvh->grid_flag_mats || bvh->grid_hidden != grid_hidden) {
- bvh->grid_flag_mats = flagmats;
- bvh->grid_hidden = grid_hidden;
+ if (flagmats != bvh->grid_flag_mats || bvh->grid_hidden != grid_hidden) {
+ bvh->grid_flag_mats = flagmats;
+ bvh->grid_hidden = grid_hidden;
- for (int a = 0; a < bvh->totnode; ++a)
- BKE_pbvh_node_mark_rebuild_draw(&bvh->nodes[a]);
- }
+ for (int a = 0; a < bvh->totnode; ++a)
+ BKE_pbvh_node_mark_rebuild_draw(&bvh->nodes[a]);
+ }
}
/* Get the node's displacement layer, creating it if necessary */
float *BKE_pbvh_node_layer_disp_get(PBVH *bvh, PBVHNode *node)
{
- if (!node->layer_disp) {
- int totvert = 0;
- BKE_pbvh_node_num_verts(bvh, node, &totvert, NULL);
- node->layer_disp = MEM_callocN(sizeof(float) * totvert, "layer disp");
- }
- return node->layer_disp;
+ if (!node->layer_disp) {
+ int totvert = 0;
+ BKE_pbvh_node_num_verts(bvh, node, &totvert, NULL);
+ node->layer_disp = MEM_callocN(sizeof(float) * totvert, "layer disp");
+ }
+ return node->layer_disp;
}
/* If the node has a displacement layer, free it and set to null */
void BKE_pbvh_node_layer_disp_free(PBVHNode *node)
{
- if (node->layer_disp) {
- MEM_freeN(node->layer_disp);
- node->layer_disp = NULL;
- }
+ if (node->layer_disp) {
+ MEM_freeN(node->layer_disp);
+ node->layer_disp = NULL;
+ }
}
float (*BKE_pbvh_get_vertCos(PBVH *pbvh))[3]
{
- float (*vertCos)[3] = NULL;
+ float(*vertCos)[3] = NULL;
- if (pbvh->verts) {
- MVert *mvert = pbvh->verts;
+ if (pbvh->verts) {
+ MVert *mvert = pbvh->verts;
- vertCos = MEM_callocN(3 * pbvh->totvert * sizeof(float), "BKE_pbvh_get_vertCoords");
- float *co = (float *)vertCos;
+ vertCos = MEM_callocN(3 * pbvh->totvert * sizeof(float), "BKE_pbvh_get_vertCoords");
+ float *co = (float *)vertCos;
- for (int a = 0; a < pbvh->totvert; a++, mvert++, co += 3) {
- copy_v3_v3(co, mvert->co);
- }
- }
+ for (int a = 0; a < pbvh->totvert; a++, mvert++, co += 3) {
+ copy_v3_v3(co, mvert->co);
+ }
+ }
- return vertCos;
+ return vertCos;
}
void BKE_pbvh_apply_vertCos(PBVH *pbvh, float (*vertCos)[3], const int totvert)
{
- if (totvert != pbvh->totvert) {
- BLI_assert(!"PBVH: Given deforming vcos number does not natch PBVH vertex number!");
- return;
- }
-
- if (!pbvh->deformed) {
- if (pbvh->verts) {
- /* if pbvh is not already deformed, verts/faces points to the */
- /* original data and applying new coords to this arrays would lead to */
- /* unneeded deformation -- duplicate verts/faces to avoid this */
+ if (totvert != pbvh->totvert) {
+ BLI_assert(!"PBVH: Given deforming vcos number does not natch PBVH vertex number!");
+ return;
+ }
- pbvh->verts = MEM_dupallocN(pbvh->verts);
- /* No need to dupalloc pbvh->looptri, this one is 'totally owned' by pbvh, it's never some mesh data. */
+ if (!pbvh->deformed) {
+ if (pbvh->verts) {
+ /* if pbvh is not already deformed, verts/faces points to the */
+ /* original data and applying new coords to this arrays would lead to */
+ /* unneeded deformation -- duplicate verts/faces to avoid this */
- pbvh->deformed = true;
- }
- }
+ pbvh->verts = MEM_dupallocN(pbvh->verts);
+ /* No need to dupalloc pbvh->looptri, this one is 'totally owned' by pbvh, it's never some mesh data. */
- if (pbvh->verts) {
- MVert *mvert = pbvh->verts;
- /* copy new verts coords */
- for (int a = 0; a < pbvh->totvert; ++a, ++mvert) {
- /* no need for float comparison here (memory is exactly equal or not) */
- if (memcmp(mvert->co, vertCos[a], sizeof(float[3])) != 0) {
- copy_v3_v3(mvert->co, vertCos[a]);
- mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
+ pbvh->deformed = true;
+ }
+ }
- /* coordinates are new -- normals should also be updated */
- BKE_mesh_calc_normals_looptri(
- pbvh->verts, pbvh->totvert,
- pbvh->mloop,
- pbvh->looptri, pbvh->totprim,
- NULL);
+ if (pbvh->verts) {
+ MVert *mvert = pbvh->verts;
+ /* copy new verts coords */
+ for (int a = 0; a < pbvh->totvert; ++a, ++mvert) {
+ /* no need for float comparison here (memory is exactly equal or not) */
+ if (memcmp(mvert->co, vertCos[a], sizeof(float[3])) != 0) {
+ copy_v3_v3(mvert->co, vertCos[a]);
+ mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
- for (int a = 0; a < pbvh->totnode; ++a)
- BKE_pbvh_node_mark_update(&pbvh->nodes[a]);
+ /* coordinates are new -- normals should also be updated */
+ BKE_mesh_calc_normals_looptri(
+ pbvh->verts, pbvh->totvert, pbvh->mloop, pbvh->looptri, pbvh->totprim, NULL);
- BKE_pbvh_update(pbvh, PBVH_UpdateBB, NULL);
- BKE_pbvh_update(pbvh, PBVH_UpdateOriginalBB, NULL);
+ for (int a = 0; a < pbvh->totnode; ++a)
+ BKE_pbvh_node_mark_update(&pbvh->nodes[a]);
- }
+ BKE_pbvh_update(pbvh, PBVH_UpdateBB, NULL);
+ BKE_pbvh_update(pbvh, PBVH_UpdateOriginalBB, NULL);
+ }
}
bool BKE_pbvh_isDeformed(PBVH *pbvh)
{
- return pbvh->deformed;
+ return pbvh->deformed;
}
/* Proxies */
PBVHProxyNode *BKE_pbvh_node_add_proxy(PBVH *bvh, PBVHNode *node)
{
- int index, totverts;
+ int index, totverts;
- index = node->proxy_count;
+ index = node->proxy_count;
- node->proxy_count++;
+ node->proxy_count++;
- if (node->proxies)
- node->proxies = MEM_reallocN(node->proxies, node->proxy_count * sizeof(PBVHProxyNode));
- else
- node->proxies = MEM_mallocN(sizeof(PBVHProxyNode), "PBVHNodeProxy");
+ if (node->proxies)
+ node->proxies = MEM_reallocN(node->proxies, node->proxy_count * sizeof(PBVHProxyNode));
+ else
+ node->proxies = MEM_mallocN(sizeof(PBVHProxyNode), "PBVHNodeProxy");
- BKE_pbvh_node_num_verts(bvh, node, &totverts, NULL);
- node->proxies[index].co = MEM_callocN(sizeof(float[3]) * totverts, "PBVHNodeProxy.co");
+ BKE_pbvh_node_num_verts(bvh, node, &totverts, NULL);
+ node->proxies[index].co = MEM_callocN(sizeof(float[3]) * totverts, "PBVHNodeProxy.co");
- return node->proxies + index;
+ return node->proxies + index;
}
void BKE_pbvh_node_free_proxies(PBVHNode *node)
{
- for (int p = 0; p < node->proxy_count; p++) {
- MEM_freeN(node->proxies[p].co);
- node->proxies[p].co = NULL;
- }
+ for (int p = 0; p < node->proxy_count; p++) {
+ MEM_freeN(node->proxies[p].co);
+ node->proxies[p].co = NULL;
+ }
- MEM_freeN(node->proxies);
- node->proxies = NULL;
+ MEM_freeN(node->proxies);
+ node->proxies = NULL;
- node->proxy_count = 0;
+ node->proxy_count = 0;
}
-void BKE_pbvh_gather_proxies(PBVH *pbvh, PBVHNode ***r_array, int *r_tot)
+void BKE_pbvh_gather_proxies(PBVH *pbvh, PBVHNode ***r_array, int *r_tot)
{
- PBVHNode **array = NULL;
- int tot = 0, space = 0;
+ PBVHNode **array = NULL;
+ int tot = 0, space = 0;
- for (int n = 0; n < pbvh->totnode; n++) {
- PBVHNode *node = pbvh->nodes + n;
+ for (int n = 0; n < pbvh->totnode; n++) {
+ PBVHNode *node = pbvh->nodes + n;
- if (node->proxy_count > 0) {
- if (tot == space) {
- /* resize array if needed */
- space = (tot == 0) ? 32 : space * 2;
- array = MEM_recallocN_id(array, sizeof(PBVHNode *) * space, __func__);
- }
+ if (node->proxy_count > 0) {
+ if (tot == space) {
+ /* resize array if needed */
+ space = (tot == 0) ? 32 : space * 2;
+ array = MEM_recallocN_id(array, sizeof(PBVHNode *) * space, __func__);
+ }
- array[tot] = node;
- tot++;
- }
- }
+ array[tot] = node;
+ tot++;
+ }
+ }
- if (tot == 0 && array) {
- MEM_freeN(array);
- array = NULL;
- }
+ if (tot == 0 && array) {
+ MEM_freeN(array);
+ array = NULL;
+ }
- *r_array = array;
- *r_tot = tot;
+ *r_array = array;
+ *r_tot = tot;
}
-void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node,
- PBVHVertexIter *vi, int mode)
+void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, PBVHVertexIter *vi, int mode)
{
- struct CCGElem **grids;
- struct MVert *verts;
- const int *vert_indices;
- int *grid_indices;
- int totgrid, gridsize, uniq_verts, totvert;
+ struct CCGElem **grids;
+ struct MVert *verts;
+ const int *vert_indices;
+ int *grid_indices;
+ int totgrid, gridsize, uniq_verts, totvert;
- vi->grid = NULL;
- vi->no = NULL;
- vi->fno = NULL;
- vi->mvert = NULL;
+ vi->grid = NULL;
+ vi->no = NULL;
+ vi->fno = NULL;
+ vi->mvert = NULL;
- BKE_pbvh_node_get_grids(bvh, node, &grid_indices, &totgrid, NULL, &gridsize, &grids);
- BKE_pbvh_node_num_verts(bvh, node, &uniq_verts, &totvert);
- BKE_pbvh_node_get_verts(bvh, node, &vert_indices, &verts);
- vi->key = &bvh->gridkey;
+ BKE_pbvh_node_get_grids(bvh, node, &grid_indices, &totgrid, NULL, &gridsize, &grids);
+ BKE_pbvh_node_num_verts(bvh, node, &uniq_verts, &totvert);
+ BKE_pbvh_node_get_verts(bvh, node, &vert_indices, &verts);
+ vi->key = &bvh->gridkey;
- vi->grids = grids;
- vi->grid_indices = grid_indices;
- vi->totgrid = (grids) ? totgrid : 1;
- vi->gridsize = gridsize;
+ vi->grids = grids;
+ vi->grid_indices = grid_indices;
+ vi->totgrid = (grids) ? totgrid : 1;
+ vi->gridsize = gridsize;
- if (mode == PBVH_ITER_ALL)
- vi->totvert = totvert;
- else
- vi->totvert = uniq_verts;
- vi->vert_indices = vert_indices;
- vi->mverts = verts;
+ if (mode == PBVH_ITER_ALL)
+ vi->totvert = totvert;
+ else
+ vi->totvert = uniq_verts;
+ vi->vert_indices = vert_indices;
+ vi->mverts = verts;
- if (bvh->type == PBVH_BMESH) {
- BLI_gsetIterator_init(&vi->bm_unique_verts, node->bm_unique_verts);
- BLI_gsetIterator_init(&vi->bm_other_verts, node->bm_other_verts);
- vi->bm_vdata = &bvh->bm->vdata;
- vi->cd_vert_mask_offset = CustomData_get_offset(vi->bm_vdata, CD_PAINT_MASK);
- }
+ if (bvh->type == PBVH_BMESH) {
+ BLI_gsetIterator_init(&vi->bm_unique_verts, node->bm_unique_verts);
+ BLI_gsetIterator_init(&vi->bm_other_verts, node->bm_other_verts);
+ vi->bm_vdata = &bvh->bm->vdata;
+ vi->cd_vert_mask_offset = CustomData_get_offset(vi->bm_vdata, CD_PAINT_MASK);
+ }
- vi->gh = NULL;
- if (vi->grids && mode == PBVH_ITER_UNIQUE)
- vi->grid_hidden = bvh->grid_hidden;
+ vi->gh = NULL;
+ if (vi->grids && mode == PBVH_ITER_UNIQUE)
+ vi->grid_hidden = bvh->grid_hidden;
- vi->mask = NULL;
- if (bvh->type == PBVH_FACES)
- vi->vmask = CustomData_get_layer(bvh->vdata, CD_PAINT_MASK);
+ vi->mask = NULL;
+ if (bvh->type == PBVH_FACES)
+ vi->vmask = CustomData_get_layer(bvh->vdata, CD_PAINT_MASK);
}
bool pbvh_has_mask(PBVH *bvh)
{
- switch (bvh->type) {
- case PBVH_GRIDS:
- return (bvh->gridkey.has_mask != 0);
- case PBVH_FACES:
- return (bvh->vdata && CustomData_get_layer(bvh->vdata,
- CD_PAINT_MASK));
- case PBVH_BMESH:
- return (bvh->bm && (CustomData_get_offset(&bvh->bm->vdata, CD_PAINT_MASK) != -1));
- }
+ switch (bvh->type) {
+ case PBVH_GRIDS:
+ return (bvh->gridkey.has_mask != 0);
+ case PBVH_FACES:
+ return (bvh->vdata && CustomData_get_layer(bvh->vdata, CD_PAINT_MASK));
+ case PBVH_BMESH:
+ return (bvh->bm && (CustomData_get_offset(&bvh->bm->vdata, CD_PAINT_MASK) != -1));
+ }
- return false;
+ return false;
}
void pbvh_show_diffuse_color_set(PBVH *bvh, bool show_diffuse_color)
{
- bvh->show_diffuse_color = !pbvh_has_mask(bvh) || show_diffuse_color;
+ bvh->show_diffuse_color = !pbvh_has_mask(bvh) || show_diffuse_color;
}
void pbvh_show_mask_set(PBVH *bvh, bool show_mask)
{
- bvh->show_mask = show_mask;
+ bvh->show_mask = show_mask;
}
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index c75a748574c..c007d5e3df7 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -78,53 +78,65 @@ static void pbvh_bmesh_verify(PBVH *bvh);
*/
#define BM_LOOPS_OF_VERT_ITER_BEGIN(l_iter_radial_, v_) \
-{ \
- struct { BMVert *v; BMEdge *e_iter, *e_first; BMLoop *l_iter_radial; } _iter; \
- _iter.v = v_; \
- if (_iter.v->e) { \
- _iter.e_iter = _iter.e_first = _iter.v->e; \
- do { \
- if (_iter.e_iter->l) { \
- _iter.l_iter_radial = _iter.e_iter->l; \
- do { \
- if (_iter.l_iter_radial->v == _iter.v) { \
- l_iter_radial_ = _iter.l_iter_radial;
+ { \
+ struct { \
+ BMVert *v; \
+ BMEdge *e_iter, *e_first; \
+ BMLoop *l_iter_radial; \
+ } _iter; \
+ _iter.v = v_; \
+ if (_iter.v->e) { \
+ _iter.e_iter = _iter.e_first = _iter.v->e; \
+ do { \
+ if (_iter.e_iter->l) { \
+ _iter.l_iter_radial = _iter.e_iter->l; \
+ do { \
+ if (_iter.l_iter_radial->v == _iter.v) { \
+ l_iter_radial_ = _iter.l_iter_radial;
#define BM_LOOPS_OF_VERT_ITER_END \
- } \
- } while ((_iter.l_iter_radial = _iter.l_iter_radial->radial_next) != _iter.e_iter->l); \
- } \
- } while ((_iter.e_iter = BM_DISK_EDGE_NEXT(_iter.e_iter, _iter.v)) != _iter.e_first); \
- } \
-} ((void)0)
+ } \
+ } \
+ while ((_iter.l_iter_radial = _iter.l_iter_radial->radial_next) != _iter.e_iter->l) \
+ ; \
+ } \
+ } \
+ while ((_iter.e_iter = BM_DISK_EDGE_NEXT(_iter.e_iter, _iter.v)) != _iter.e_first) \
+ ; \
+ } \
+ } \
+ ((void)0)
#define BM_FACES_OF_VERT_ITER_BEGIN(f_iter_, v_) \
-{ \
- BMLoop *l_iter_radial_; \
- BM_LOOPS_OF_VERT_ITER_BEGIN(l_iter_radial_, v_) { \
- f_iter_ = l_iter_radial_->f; \
+ { \
+ BMLoop *l_iter_radial_; \
+ BM_LOOPS_OF_VERT_ITER_BEGIN (l_iter_radial_, v_) { \
+ f_iter_ = l_iter_radial_->f;
#define BM_FACES_OF_VERT_ITER_END \
- } \
- BM_LOOPS_OF_VERT_ITER_END; \
-} ((void)0)
+ } \
+ BM_LOOPS_OF_VERT_ITER_END; \
+ } \
+ ((void)0)
static void bm_edges_from_tri(BMesh *bm, BMVert *v_tri[3], BMEdge *e_tri[3])
{
- e_tri[0] = BM_edge_create(bm, v_tri[0], v_tri[1], NULL, BM_CREATE_NO_DOUBLE);
- e_tri[1] = BM_edge_create(bm, v_tri[1], v_tri[2], NULL, BM_CREATE_NO_DOUBLE);
- e_tri[2] = BM_edge_create(bm, v_tri[2], v_tri[0], NULL, BM_CREATE_NO_DOUBLE);
+ e_tri[0] = BM_edge_create(bm, v_tri[0], v_tri[1], NULL, BM_CREATE_NO_DOUBLE);
+ e_tri[1] = BM_edge_create(bm, v_tri[1], v_tri[2], NULL, BM_CREATE_NO_DOUBLE);
+ e_tri[2] = BM_edge_create(bm, v_tri[2], v_tri[0], NULL, BM_CREATE_NO_DOUBLE);
}
BLI_INLINE void bm_face_as_array_index_tri(BMFace *f, int r_index[3])
{
- BMLoop *l = BM_FACE_FIRST_LOOP(f);
+ BMLoop *l = BM_FACE_FIRST_LOOP(f);
- BLI_assert(f->len == 3);
+ BLI_assert(f->len == 3);
- r_index[0] = BM_elem_index_get(l->v); l = l->next;
- r_index[1] = BM_elem_index_get(l->v); l = l->next;
- r_index[2] = BM_elem_index_get(l->v);
+ r_index[0] = BM_elem_index_get(l->v);
+ l = l->next;
+ r_index[1] = BM_elem_index_get(l->v);
+ l = l->next;
+ r_index[2] = BM_elem_index_get(l->v);
}
/**
@@ -146,17 +158,18 @@ BLI_INLINE void bm_face_as_array_index_tri(BMFace *f, int r_index[3])
*/
static BMFace *bm_face_exists_tri_from_loop_vert(BMLoop *l_radial_first, BMVert *v_opposite)
{
- BLI_assert(!ELEM(v_opposite, l_radial_first->v, l_radial_first->next->v, l_radial_first->prev->v));
- if (l_radial_first->radial_next != l_radial_first) {
- BMLoop *l_radial_iter = l_radial_first->radial_next;
- do {
- BLI_assert(l_radial_iter->f->len == 3);
- if (l_radial_iter->prev->v == v_opposite) {
- return l_radial_iter->f;
- }
- } while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_first);
- }
- return NULL;
+ BLI_assert(
+ !ELEM(v_opposite, l_radial_first->v, l_radial_first->next->v, l_radial_first->prev->v));
+ if (l_radial_first->radial_next != l_radial_first) {
+ BMLoop *l_radial_iter = l_radial_first->radial_next;
+ do {
+ BLI_assert(l_radial_iter->f->len == 3);
+ if (l_radial_iter->prev->v == v_opposite) {
+ return l_radial_iter->f;
+ }
+ } while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_first);
+ }
+ return NULL;
}
/**
@@ -165,246 +178,245 @@ static BMFace *bm_face_exists_tri_from_loop_vert(BMLoop *l_radial_first, BMVert
*/
static BMVert *bm_vert_hash_lookup_chain(GHash *deleted_verts, BMVert *v)
{
- while (true) {
- BMVert **v_next_p = (BMVert **)BLI_ghash_lookup_p(deleted_verts, v);
- if (v_next_p == NULL) {
- /* not remapped*/
- return v;
- }
- else if (*v_next_p == NULL) {
- /* removed and not remapped */
- return NULL;
- }
- else {
- /* remapped */
- v = *v_next_p;
- }
- }
+ while (true) {
+ BMVert **v_next_p = (BMVert **)BLI_ghash_lookup_p(deleted_verts, v);
+ if (v_next_p == NULL) {
+ /* not remapped*/
+ return v;
+ }
+ else if (*v_next_p == NULL) {
+ /* removed and not remapped */
+ return NULL;
+ }
+ else {
+ /* remapped */
+ v = *v_next_p;
+ }
+ }
}
/** \} */
-
/****************************** Building ******************************/
/* Update node data after splitting */
-static void pbvh_bmesh_node_finalize(
- PBVH *bvh, const int node_index,
- const int cd_vert_node_offset, const int cd_face_node_offset)
+static void pbvh_bmesh_node_finalize(PBVH *bvh,
+ const int node_index,
+ const int cd_vert_node_offset,
+ const int cd_face_node_offset)
{
- GSetIterator gs_iter;
- PBVHNode *n = &bvh->nodes[node_index];
- bool has_visible = false;
-
- /* Create vert hash sets */
- n->bm_unique_verts = BLI_gset_ptr_new("bm_unique_verts");
- n->bm_other_verts = BLI_gset_ptr_new("bm_other_verts");
-
- BB_reset(&n->vb);
-
- GSET_ITER (gs_iter, n->bm_faces) {
- BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
-
- /* Update ownership of faces */
- BM_ELEM_CD_SET_INT(f, cd_face_node_offset, node_index);
-
- /* Update vertices */
- BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
- BMLoop *l_iter = l_first;
-
- do {
- BMVert *v = l_iter->v;
- if (!BLI_gset_haskey(n->bm_unique_verts, v)) {
- if (BM_ELEM_CD_GET_INT(v, cd_vert_node_offset) != DYNTOPO_NODE_NONE) {
- BLI_gset_add(n->bm_other_verts, v);
- }
- else {
- BLI_gset_insert(n->bm_unique_verts, v);
- BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, node_index);
- }
- }
- /* Update node bounding box */
- BB_expand(&n->vb, v->co);
- } while ((l_iter = l_iter->next) != l_first);
-
- if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN))
- has_visible = true;
- }
-
- BLI_assert(n->vb.bmin[0] <= n->vb.bmax[0] &&
- n->vb.bmin[1] <= n->vb.bmax[1] &&
- n->vb.bmin[2] <= n->vb.bmax[2]);
-
- n->orig_vb = n->vb;
-
- /* Build GPU buffers for new node and update vertex normals */
- BKE_pbvh_node_mark_rebuild_draw(n);
-
- BKE_pbvh_node_fully_hidden_set(n, !has_visible);
- n->flag |= PBVH_UpdateNormals;
+ GSetIterator gs_iter;
+ PBVHNode *n = &bvh->nodes[node_index];
+ bool has_visible = false;
+
+ /* Create vert hash sets */
+ n->bm_unique_verts = BLI_gset_ptr_new("bm_unique_verts");
+ n->bm_other_verts = BLI_gset_ptr_new("bm_other_verts");
+
+ BB_reset(&n->vb);
+
+ GSET_ITER (gs_iter, n->bm_faces) {
+ BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
+
+ /* Update ownership of faces */
+ BM_ELEM_CD_SET_INT(f, cd_face_node_offset, node_index);
+
+ /* Update vertices */
+ BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
+ BMLoop *l_iter = l_first;
+
+ do {
+ BMVert *v = l_iter->v;
+ if (!BLI_gset_haskey(n->bm_unique_verts, v)) {
+ if (BM_ELEM_CD_GET_INT(v, cd_vert_node_offset) != DYNTOPO_NODE_NONE) {
+ BLI_gset_add(n->bm_other_verts, v);
+ }
+ else {
+ BLI_gset_insert(n->bm_unique_verts, v);
+ BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, node_index);
+ }
+ }
+ /* Update node bounding box */
+ BB_expand(&n->vb, v->co);
+ } while ((l_iter = l_iter->next) != l_first);
+
+ if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN))
+ has_visible = true;
+ }
+
+ BLI_assert(n->vb.bmin[0] <= n->vb.bmax[0] && n->vb.bmin[1] <= n->vb.bmax[1] &&
+ n->vb.bmin[2] <= n->vb.bmax[2]);
+
+ n->orig_vb = n->vb;
+
+ /* Build GPU buffers for new node and update vertex normals */
+ BKE_pbvh_node_mark_rebuild_draw(n);
+
+ BKE_pbvh_node_fully_hidden_set(n, !has_visible);
+ n->flag |= PBVH_UpdateNormals;
}
/* Recursively split the node if it exceeds the leaf_limit */
static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_index)
{
- const int cd_vert_node_offset = bvh->cd_vert_node_offset;
- const int cd_face_node_offset = bvh->cd_face_node_offset;
- PBVHNode *n = &bvh->nodes[node_index];
-
- if (BLI_gset_len(n->bm_faces) <= bvh->leaf_limit) {
- /* Node limit not exceeded */
- pbvh_bmesh_node_finalize(bvh, node_index, cd_vert_node_offset, cd_face_node_offset);
- return;
- }
-
- /* Calculate bounding box around primitive centroids */
- BB cb;
- BB_reset(&cb);
- GSetIterator gs_iter;
- GSET_ITER (gs_iter, n->bm_faces) {
- const BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
- const BBC *bbc = &bbc_array[BM_elem_index_get(f)];
-
- BB_expand(&cb, bbc->bcentroid);
- }
-
- /* Find widest axis and its midpoint */
- const int axis = BB_widest_axis(&cb);
- const float mid = (cb.bmax[axis] + cb.bmin[axis]) * 0.5f;
-
- /* Add two new child nodes */
- const int children = bvh->totnode;
- n->children_offset = children;
- pbvh_grow_nodes(bvh, bvh->totnode + 2);
-
- /* Array reallocated, update current node pointer */
- n = &bvh->nodes[node_index];
-
- /* Initialize children */
- PBVHNode *c1 = &bvh->nodes[children],
- *c2 = &bvh->nodes[children + 1];
- c1->flag |= PBVH_Leaf;
- c2->flag |= PBVH_Leaf;
- c1->bm_faces = BLI_gset_ptr_new_ex("bm_faces", BLI_gset_len(n->bm_faces) / 2);
- c2->bm_faces = BLI_gset_ptr_new_ex("bm_faces", BLI_gset_len(n->bm_faces) / 2);
-
- /* Partition the parent node's faces between the two children */
- GSET_ITER (gs_iter, n->bm_faces) {
- BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
- const BBC *bbc = &bbc_array[BM_elem_index_get(f)];
-
- if (bbc->bcentroid[axis] < mid)
- BLI_gset_insert(c1->bm_faces, f);
- else
- BLI_gset_insert(c2->bm_faces, f);
- }
-
- /* Enforce at least one primitive in each node */
- GSet *empty = NULL, *other;
- if (BLI_gset_len(c1->bm_faces) == 0) {
- empty = c1->bm_faces;
- other = c2->bm_faces;
- }
- else if (BLI_gset_len(c2->bm_faces) == 0) {
- empty = c2->bm_faces;
- other = c1->bm_faces;
- }
- if (empty) {
- GSET_ITER (gs_iter, other) {
- void *key = BLI_gsetIterator_getKey(&gs_iter);
- BLI_gset_insert(empty, key);
- BLI_gset_remove(other, key, NULL);
- break;
- }
- }
-
- /* Clear this node */
-
- /* Mark this node's unique verts as unclaimed */
- if (n->bm_unique_verts) {
- GSET_ITER (gs_iter, n->bm_unique_verts) {
- BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
- BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, DYNTOPO_NODE_NONE);
- }
- BLI_gset_free(n->bm_unique_verts, NULL);
- }
-
- /* Unclaim faces */
- GSET_ITER (gs_iter, n->bm_faces) {
- BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
- BM_ELEM_CD_SET_INT(f, cd_face_node_offset, DYNTOPO_NODE_NONE);
- }
- BLI_gset_free(n->bm_faces, NULL);
-
- if (n->bm_other_verts)
- BLI_gset_free(n->bm_other_verts, NULL);
-
- if (n->layer_disp)
- MEM_freeN(n->layer_disp);
-
- n->bm_faces = NULL;
- n->bm_unique_verts = NULL;
- n->bm_other_verts = NULL;
- n->layer_disp = NULL;
-
- if (n->draw_buffers) {
- GPU_pbvh_buffers_free(n->draw_buffers);
- n->draw_buffers = NULL;
- }
- n->flag &= ~PBVH_Leaf;
-
- /* Recurse */
- pbvh_bmesh_node_split(bvh, bbc_array, children);
- pbvh_bmesh_node_split(bvh, bbc_array, children + 1);
-
- /* Array maybe reallocated, update current node pointer */
- n = &bvh->nodes[node_index];
-
- /* Update bounding box */
- BB_reset(&n->vb);
- BB_expand_with_bb(&n->vb, &bvh->nodes[n->children_offset].vb);
- BB_expand_with_bb(&n->vb, &bvh->nodes[n->children_offset + 1].vb);
- n->orig_vb = n->vb;
+ const int cd_vert_node_offset = bvh->cd_vert_node_offset;
+ const int cd_face_node_offset = bvh->cd_face_node_offset;
+ PBVHNode *n = &bvh->nodes[node_index];
+
+ if (BLI_gset_len(n->bm_faces) <= bvh->leaf_limit) {
+ /* Node limit not exceeded */
+ pbvh_bmesh_node_finalize(bvh, node_index, cd_vert_node_offset, cd_face_node_offset);
+ return;
+ }
+
+ /* Calculate bounding box around primitive centroids */
+ BB cb;
+ BB_reset(&cb);
+ GSetIterator gs_iter;
+ GSET_ITER (gs_iter, n->bm_faces) {
+ const BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
+ const BBC *bbc = &bbc_array[BM_elem_index_get(f)];
+
+ BB_expand(&cb, bbc->bcentroid);
+ }
+
+ /* Find widest axis and its midpoint */
+ const int axis = BB_widest_axis(&cb);
+ const float mid = (cb.bmax[axis] + cb.bmin[axis]) * 0.5f;
+
+ /* Add two new child nodes */
+ const int children = bvh->totnode;
+ n->children_offset = children;
+ pbvh_grow_nodes(bvh, bvh->totnode + 2);
+
+ /* Array reallocated, update current node pointer */
+ n = &bvh->nodes[node_index];
+
+ /* Initialize children */
+ PBVHNode *c1 = &bvh->nodes[children], *c2 = &bvh->nodes[children + 1];
+ c1->flag |= PBVH_Leaf;
+ c2->flag |= PBVH_Leaf;
+ c1->bm_faces = BLI_gset_ptr_new_ex("bm_faces", BLI_gset_len(n->bm_faces) / 2);
+ c2->bm_faces = BLI_gset_ptr_new_ex("bm_faces", BLI_gset_len(n->bm_faces) / 2);
+
+ /* Partition the parent node's faces between the two children */
+ GSET_ITER (gs_iter, n->bm_faces) {
+ BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
+ const BBC *bbc = &bbc_array[BM_elem_index_get(f)];
+
+ if (bbc->bcentroid[axis] < mid)
+ BLI_gset_insert(c1->bm_faces, f);
+ else
+ BLI_gset_insert(c2->bm_faces, f);
+ }
+
+ /* Enforce at least one primitive in each node */
+ GSet *empty = NULL, *other;
+ if (BLI_gset_len(c1->bm_faces) == 0) {
+ empty = c1->bm_faces;
+ other = c2->bm_faces;
+ }
+ else if (BLI_gset_len(c2->bm_faces) == 0) {
+ empty = c2->bm_faces;
+ other = c1->bm_faces;
+ }
+ if (empty) {
+ GSET_ITER (gs_iter, other) {
+ void *key = BLI_gsetIterator_getKey(&gs_iter);
+ BLI_gset_insert(empty, key);
+ BLI_gset_remove(other, key, NULL);
+ break;
+ }
+ }
+
+ /* Clear this node */
+
+ /* Mark this node's unique verts as unclaimed */
+ if (n->bm_unique_verts) {
+ GSET_ITER (gs_iter, n->bm_unique_verts) {
+ BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
+ BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, DYNTOPO_NODE_NONE);
+ }
+ BLI_gset_free(n->bm_unique_verts, NULL);
+ }
+
+ /* Unclaim faces */
+ GSET_ITER (gs_iter, n->bm_faces) {
+ BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
+ BM_ELEM_CD_SET_INT(f, cd_face_node_offset, DYNTOPO_NODE_NONE);
+ }
+ BLI_gset_free(n->bm_faces, NULL);
+
+ if (n->bm_other_verts)
+ BLI_gset_free(n->bm_other_verts, NULL);
+
+ if (n->layer_disp)
+ MEM_freeN(n->layer_disp);
+
+ n->bm_faces = NULL;
+ n->bm_unique_verts = NULL;
+ n->bm_other_verts = NULL;
+ n->layer_disp = NULL;
+
+ if (n->draw_buffers) {
+ GPU_pbvh_buffers_free(n->draw_buffers);
+ n->draw_buffers = NULL;
+ }
+ n->flag &= ~PBVH_Leaf;
+
+ /* Recurse */
+ pbvh_bmesh_node_split(bvh, bbc_array, children);
+ pbvh_bmesh_node_split(bvh, bbc_array, children + 1);
+
+ /* Array maybe reallocated, update current node pointer */
+ n = &bvh->nodes[node_index];
+
+ /* Update bounding box */
+ BB_reset(&n->vb);
+ BB_expand_with_bb(&n->vb, &bvh->nodes[n->children_offset].vb);
+ BB_expand_with_bb(&n->vb, &bvh->nodes[n->children_offset + 1].vb);
+ n->orig_vb = n->vb;
}
/* Recursively split the node if it exceeds the leaf_limit */
static bool pbvh_bmesh_node_limit_ensure(PBVH *bvh, int node_index)
{
- GSet *bm_faces = bvh->nodes[node_index].bm_faces;
- const int bm_faces_size = BLI_gset_len(bm_faces);
- if (bm_faces_size <= bvh->leaf_limit) {
- /* Node limit not exceeded */
- return false;
- }
-
- /* For each BMFace, store the AABB and AABB centroid */
- BBC *bbc_array = MEM_mallocN(sizeof(BBC) * bm_faces_size, "BBC");
-
- GSetIterator gs_iter;
- int i;
- GSET_ITER_INDEX (gs_iter, bm_faces, i) {
- BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
- BBC *bbc = &bbc_array[i];
-
- BB_reset((BB *)bbc);
- BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
- BMLoop *l_iter = l_first;
- do {
- BB_expand((BB *)bbc, l_iter->v->co);
- } while ((l_iter = l_iter->next) != l_first);
- BBC_update_centroid(bbc);
-
- /* so we can do direct lookups on 'bbc_array' */
- BM_elem_index_set(f, i); /* set_dirty! */
- }
- /* likely this is already dirty */
- bvh->bm->elem_index_dirty |= BM_FACE;
-
- pbvh_bmesh_node_split(bvh, bbc_array, node_index);
-
- MEM_freeN(bbc_array);
-
- return true;
+ GSet *bm_faces = bvh->nodes[node_index].bm_faces;
+ const int bm_faces_size = BLI_gset_len(bm_faces);
+ if (bm_faces_size <= bvh->leaf_limit) {
+ /* Node limit not exceeded */
+ return false;
+ }
+
+ /* For each BMFace, store the AABB and AABB centroid */
+ BBC *bbc_array = MEM_mallocN(sizeof(BBC) * bm_faces_size, "BBC");
+
+ GSetIterator gs_iter;
+ int i;
+ GSET_ITER_INDEX(gs_iter, bm_faces, i)
+ {
+ BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
+ BBC *bbc = &bbc_array[i];
+
+ BB_reset((BB *)bbc);
+ BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
+ BMLoop *l_iter = l_first;
+ do {
+ BB_expand((BB *)bbc, l_iter->v->co);
+ } while ((l_iter = l_iter->next) != l_first);
+ BBC_update_centroid(bbc);
+
+ /* so we can do direct lookups on 'bbc_array' */
+ BM_elem_index_set(f, i); /* set_dirty! */
+ }
+ /* likely this is already dirty */
+ bvh->bm->elem_index_dirty |= BM_FACE;
+
+ pbvh_bmesh_node_split(bvh, bbc_array, node_index);
+
+ MEM_freeN(bbc_array);
+
+ return true;
}
/**********************************************************************/
@@ -412,304 +424,298 @@ static bool pbvh_bmesh_node_limit_ensure(PBVH *bvh, int node_index)
#if 0
static int pbvh_bmesh_node_offset_from_elem(PBVH *bvh, BMElem *ele)
{
- switch (ele->head.htype) {
- case BM_VERT:
- return bvh->cd_vert_node_offset;
- default:
- BLI_assert(ele->head.htype == BM_FACE);
- return bvh->cd_face_node_offset;
- }
+ switch (ele->head.htype) {
+ case BM_VERT:
+ return bvh->cd_vert_node_offset;
+ default:
+ BLI_assert(ele->head.htype == BM_FACE);
+ return bvh->cd_face_node_offset;
+ }
}
static int pbvh_bmesh_node_index_from_elem(PBVH *bvh, void *key)
{
- const int cd_node_offset = pbvh_bmesh_node_offset_from_elem(bvh, key);
- const int node_index = BM_ELEM_CD_GET_INT((BMElem *)key, cd_node_offset);
+ const int cd_node_offset = pbvh_bmesh_node_offset_from_elem(bvh, key);
+ const int node_index = BM_ELEM_CD_GET_INT((BMElem *)key, cd_node_offset);
- BLI_assert(node_index != DYNTOPO_NODE_NONE);
- BLI_assert(node_index < bvh->totnode);
- (void)bvh;
+ BLI_assert(node_index != DYNTOPO_NODE_NONE);
+ BLI_assert(node_index < bvh->totnode);
+ (void)bvh;
- return node_index;
+ return node_index;
}
static PBVHNode *pbvh_bmesh_node_from_elem(PBVH *bvh, void *key)
{
- return &bvh->nodes[pbvh_bmesh_node_index_from_elem(bvh, key)];
+ return &bvh->nodes[pbvh_bmesh_node_index_from_elem(bvh, key)];
}
/* typecheck */
-#define pbvh_bmesh_node_index_from_elem(bvh, key) ( \
- CHECK_TYPE_ANY(key, BMFace *, BMVert *), \
- pbvh_bmesh_node_index_from_elem(bvh, key))
-#define pbvh_bmesh_node_from_elem(bvh, key) ( \
- CHECK_TYPE_ANY(key, BMFace *, BMVert *), \
- pbvh_bmesh_node_from_elem(bvh, key))
+# define pbvh_bmesh_node_index_from_elem(bvh, key) \
+ (CHECK_TYPE_ANY(key, BMFace *, BMVert *), pbvh_bmesh_node_index_from_elem(bvh, key))
+# define pbvh_bmesh_node_from_elem(bvh, key) \
+ (CHECK_TYPE_ANY(key, BMFace *, BMVert *), pbvh_bmesh_node_from_elem(bvh, key))
#endif
BLI_INLINE int pbvh_bmesh_node_index_from_vert(PBVH *bvh, const BMVert *key)
{
- const int node_index = BM_ELEM_CD_GET_INT((const BMElem *)key, bvh->cd_vert_node_offset);
- BLI_assert(node_index != DYNTOPO_NODE_NONE);
- BLI_assert(node_index < bvh->totnode);
- return node_index;
+ const int node_index = BM_ELEM_CD_GET_INT((const BMElem *)key, bvh->cd_vert_node_offset);
+ BLI_assert(node_index != DYNTOPO_NODE_NONE);
+ BLI_assert(node_index < bvh->totnode);
+ return node_index;
}
BLI_INLINE int pbvh_bmesh_node_index_from_face(PBVH *bvh, const BMFace *key)
{
- const int node_index = BM_ELEM_CD_GET_INT((const BMElem *)key, bvh->cd_face_node_offset);
- BLI_assert(node_index != DYNTOPO_NODE_NONE);
- BLI_assert(node_index < bvh->totnode);
- return node_index;
+ const int node_index = BM_ELEM_CD_GET_INT((const BMElem *)key, bvh->cd_face_node_offset);
+ BLI_assert(node_index != DYNTOPO_NODE_NONE);
+ BLI_assert(node_index < bvh->totnode);
+ return node_index;
}
BLI_INLINE PBVHNode *pbvh_bmesh_node_from_vert(PBVH *bvh, const BMVert *key)
{
- return &bvh->nodes[pbvh_bmesh_node_index_from_vert(bvh, key)];
+ return &bvh->nodes[pbvh_bmesh_node_index_from_vert(bvh, key)];
}
BLI_INLINE PBVHNode *pbvh_bmesh_node_from_face(PBVH *bvh, const BMFace *key)
{
- return &bvh->nodes[pbvh_bmesh_node_index_from_face(bvh, key)];
+ return &bvh->nodes[pbvh_bmesh_node_index_from_face(bvh, key)];
}
-
static BMVert *pbvh_bmesh_vert_create(
- PBVH *bvh, int node_index,
- const float co[3], const float no[3],
- const int cd_vert_mask_offset)
+ PBVH *bvh, int node_index, const float co[3], const float no[3], const int cd_vert_mask_offset)
{
- PBVHNode *node = &bvh->nodes[node_index];
+ PBVHNode *node = &bvh->nodes[node_index];
- BLI_assert((bvh->totnode == 1 || node_index) && node_index <= bvh->totnode);
+ BLI_assert((bvh->totnode == 1 || node_index) && node_index <= bvh->totnode);
- /* avoid initializing customdata because its quite involved */
- BMVert *v = BM_vert_create(bvh->bm, co, NULL, BM_CREATE_SKIP_CD);
- CustomData_bmesh_set_default(&bvh->bm->vdata, &v->head.data);
+ /* avoid initializing customdata because its quite involved */
+ BMVert *v = BM_vert_create(bvh->bm, co, NULL, BM_CREATE_SKIP_CD);
+ CustomData_bmesh_set_default(&bvh->bm->vdata, &v->head.data);
- /* This value is logged below */
- copy_v3_v3(v->no, no);
+ /* This value is logged below */
+ copy_v3_v3(v->no, no);
- BLI_gset_insert(node->bm_unique_verts, v);
- BM_ELEM_CD_SET_INT(v, bvh->cd_vert_node_offset, node_index);
+ BLI_gset_insert(node->bm_unique_verts, v);
+ BM_ELEM_CD_SET_INT(v, bvh->cd_vert_node_offset, node_index);
- node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
+ node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
- /* Log the new vertex */
- BM_log_vert_added(bvh->bm_log, v, cd_vert_mask_offset);
+ /* Log the new vertex */
+ BM_log_vert_added(bvh->bm_log, v, cd_vert_mask_offset);
- return v;
+ return v;
}
/**
* \note Callers are responsible for checking if the face exists before adding.
*/
static BMFace *pbvh_bmesh_face_create(
- PBVH *bvh, int node_index,
- BMVert *v_tri[3], BMEdge *e_tri[3],
- const BMFace *f_example)
+ PBVH *bvh, int node_index, BMVert *v_tri[3], BMEdge *e_tri[3], const BMFace *f_example)
{
- PBVHNode *node = &bvh->nodes[node_index];
+ PBVHNode *node = &bvh->nodes[node_index];
- /* ensure we never add existing face */
- BLI_assert(!BM_face_exists(v_tri, 3));
+ /* ensure we never add existing face */
+ BLI_assert(!BM_face_exists(v_tri, 3));
- BMFace *f = BM_face_create(bvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NOP);
- f->head.hflag = f_example->head.hflag;
+ BMFace *f = BM_face_create(bvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NOP);
+ f->head.hflag = f_example->head.hflag;
- BLI_gset_insert(node->bm_faces, f);
- BM_ELEM_CD_SET_INT(f, bvh->cd_face_node_offset, node_index);
+ BLI_gset_insert(node->bm_faces, f);
+ BM_ELEM_CD_SET_INT(f, bvh->cd_face_node_offset, node_index);
- /* mark node for update */
- node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals;
- node->flag &= ~PBVH_FullyHidden;
+ /* mark node for update */
+ node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals;
+ node->flag &= ~PBVH_FullyHidden;
- /* Log the new face */
- BM_log_face_added(bvh->bm_log, f);
+ /* Log the new face */
+ BM_log_face_added(bvh->bm_log, f);
- return f;
+ return f;
}
/* Return the number of faces in 'node' that use vertex 'v' */
#if 0
static int pbvh_bmesh_node_vert_use_count(PBVH *bvh, PBVHNode *node, BMVert *v)
{
- BMFace *f;
- int count = 0;
-
- BM_FACES_OF_VERT_ITER_BEGIN(f, v) {
- PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, f);
- if (f_node == node) {
- count++;
- }
- }
- BM_FACES_OF_VERT_ITER_END;
-
- return count;
+ BMFace *f;
+ int count = 0;
+
+ BM_FACES_OF_VERT_ITER_BEGIN(f, v) {
+ PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, f);
+ if (f_node == node) {
+ count++;
+ }
+ }
+ BM_FACES_OF_VERT_ITER_END;
+
+ return count;
}
#endif
#define pbvh_bmesh_node_vert_use_count_is_equal(bvh, node, v, n) \
- (pbvh_bmesh_node_vert_use_count_at_most(bvh, node, v, (n) + 1) == n)
+ (pbvh_bmesh_node_vert_use_count_at_most(bvh, node, v, (n) + 1) == n)
-static int pbvh_bmesh_node_vert_use_count_at_most(PBVH *bvh, PBVHNode *node, BMVert *v, const int count_max)
+static int pbvh_bmesh_node_vert_use_count_at_most(PBVH *bvh,
+ PBVHNode *node,
+ BMVert *v,
+ const int count_max)
{
- int count = 0;
- BMFace *f;
-
- BM_FACES_OF_VERT_ITER_BEGIN(f, v) {
- PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, f);
- if (f_node == node) {
- count++;
- if (count == count_max) {
- return count;
- }
- }
- }
- BM_FACES_OF_VERT_ITER_END;
-
- return count;
+ int count = 0;
+ BMFace *f;
+
+ BM_FACES_OF_VERT_ITER_BEGIN (f, v) {
+ PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, f);
+ if (f_node == node) {
+ count++;
+ if (count == count_max) {
+ return count;
+ }
+ }
+ }
+ BM_FACES_OF_VERT_ITER_END;
+
+ return count;
}
/* Return a node that uses vertex 'v' other than its current owner */
static PBVHNode *pbvh_bmesh_vert_other_node_find(PBVH *bvh, BMVert *v)
{
- PBVHNode *current_node = pbvh_bmesh_node_from_vert(bvh, v);
- BMFace *f;
+ PBVHNode *current_node = pbvh_bmesh_node_from_vert(bvh, v);
+ BMFace *f;
- BM_FACES_OF_VERT_ITER_BEGIN(f, v) {
- PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, f);
+ BM_FACES_OF_VERT_ITER_BEGIN (f, v) {
+ PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, f);
- if (f_node != current_node) {
- return f_node;
- }
- }
- BM_FACES_OF_VERT_ITER_END;
+ if (f_node != current_node) {
+ return f_node;
+ }
+ }
+ BM_FACES_OF_VERT_ITER_END;
- return NULL;
+ return NULL;
}
-static void pbvh_bmesh_vert_ownership_transfer(
- PBVH *bvh, PBVHNode *new_owner,
- BMVert *v)
+static void pbvh_bmesh_vert_ownership_transfer(PBVH *bvh, PBVHNode *new_owner, BMVert *v)
{
- PBVHNode *current_owner = pbvh_bmesh_node_from_vert(bvh, v);
- /* mark node for update */
- current_owner->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
+ PBVHNode *current_owner = pbvh_bmesh_node_from_vert(bvh, v);
+ /* mark node for update */
+ current_owner->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
- BLI_assert(current_owner != new_owner);
+ BLI_assert(current_owner != new_owner);
- /* Remove current ownership */
- BLI_gset_remove(current_owner->bm_unique_verts, v, NULL);
+ /* Remove current ownership */
+ BLI_gset_remove(current_owner->bm_unique_verts, v, NULL);
- /* Set new ownership */
- BM_ELEM_CD_SET_INT(v, bvh->cd_vert_node_offset, new_owner - bvh->nodes);
- BLI_gset_insert(new_owner->bm_unique_verts, v);
- BLI_gset_remove(new_owner->bm_other_verts, v, NULL);
- BLI_assert(!BLI_gset_haskey(new_owner->bm_other_verts, v));
+ /* Set new ownership */
+ BM_ELEM_CD_SET_INT(v, bvh->cd_vert_node_offset, new_owner - bvh->nodes);
+ BLI_gset_insert(new_owner->bm_unique_verts, v);
+ BLI_gset_remove(new_owner->bm_other_verts, v, NULL);
+ BLI_assert(!BLI_gset_haskey(new_owner->bm_other_verts, v));
- /* mark node for update */
- new_owner->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
+ /* mark node for update */
+ new_owner->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
}
static void pbvh_bmesh_vert_remove(PBVH *bvh, BMVert *v)
{
- /* never match for first time */
- int f_node_index_prev = DYNTOPO_NODE_NONE;
-
- PBVHNode *v_node = pbvh_bmesh_node_from_vert(bvh, v);
- BLI_gset_remove(v_node->bm_unique_verts, v, NULL);
- BM_ELEM_CD_SET_INT(v, bvh->cd_vert_node_offset, DYNTOPO_NODE_NONE);
-
- /* Have to check each neighboring face's node */
- BMFace *f;
- BM_FACES_OF_VERT_ITER_BEGIN(f, v) {
- const int f_node_index = pbvh_bmesh_node_index_from_face(bvh, f);
-
- /* faces often share the same node,
- * quick check to avoid redundant #BLI_gset_remove calls */
- if (f_node_index_prev != f_node_index) {
- f_node_index_prev = f_node_index;
-
- PBVHNode *f_node = &bvh->nodes[f_node_index];
- f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
-
- /* Remove current ownership */
- BLI_gset_remove(f_node->bm_other_verts, v, NULL);
-
- BLI_assert(!BLI_gset_haskey(f_node->bm_unique_verts, v));
- BLI_assert(!BLI_gset_haskey(f_node->bm_other_verts, v));
- }
- }
- BM_FACES_OF_VERT_ITER_END;
+ /* never match for first time */
+ int f_node_index_prev = DYNTOPO_NODE_NONE;
+
+ PBVHNode *v_node = pbvh_bmesh_node_from_vert(bvh, v);
+ BLI_gset_remove(v_node->bm_unique_verts, v, NULL);
+ BM_ELEM_CD_SET_INT(v, bvh->cd_vert_node_offset, DYNTOPO_NODE_NONE);
+
+ /* Have to check each neighboring face's node */
+ BMFace *f;
+ BM_FACES_OF_VERT_ITER_BEGIN (f, v) {
+ const int f_node_index = pbvh_bmesh_node_index_from_face(bvh, f);
+
+ /* faces often share the same node,
+ * quick check to avoid redundant #BLI_gset_remove calls */
+ if (f_node_index_prev != f_node_index) {
+ f_node_index_prev = f_node_index;
+
+ PBVHNode *f_node = &bvh->nodes[f_node_index];
+ f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
+
+ /* Remove current ownership */
+ BLI_gset_remove(f_node->bm_other_verts, v, NULL);
+
+ BLI_assert(!BLI_gset_haskey(f_node->bm_unique_verts, v));
+ BLI_assert(!BLI_gset_haskey(f_node->bm_other_verts, v));
+ }
+ }
+ BM_FACES_OF_VERT_ITER_END;
}
static void pbvh_bmesh_face_remove(PBVH *bvh, BMFace *f)
{
- PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, f);
-
- /* Check if any of this face's vertices need to be removed
- * from the node */
- BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
- BMLoop *l_iter = l_first;
- do {
- BMVert *v = l_iter->v;
- if (pbvh_bmesh_node_vert_use_count_is_equal(bvh, f_node, v, 1)) {
- if (BLI_gset_haskey(f_node->bm_unique_verts, v)) {
- /* Find a different node that uses 'v' */
- PBVHNode *new_node;
-
- new_node = pbvh_bmesh_vert_other_node_find(bvh, v);
- BLI_assert(new_node || BM_vert_face_count_is_equal(v, 1));
-
- if (new_node) {
- pbvh_bmesh_vert_ownership_transfer(bvh, new_node, v);
- }
- }
- else {
- /* Remove from other verts */
- BLI_gset_remove(f_node->bm_other_verts, v, NULL);
- }
- }
- } while ((l_iter = l_iter->next) != l_first);
-
- /* Remove face from node and top level */
- BLI_gset_remove(f_node->bm_faces, f, NULL);
- BM_ELEM_CD_SET_INT(f, bvh->cd_face_node_offset, DYNTOPO_NODE_NONE);
-
- /* Log removed face */
- BM_log_face_removed(bvh->bm_log, f);
-
- /* mark node for update */
- f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals;
+ PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, f);
+
+ /* Check if any of this face's vertices need to be removed
+ * from the node */
+ BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
+ BMLoop *l_iter = l_first;
+ do {
+ BMVert *v = l_iter->v;
+ if (pbvh_bmesh_node_vert_use_count_is_equal(bvh, f_node, v, 1)) {
+ if (BLI_gset_haskey(f_node->bm_unique_verts, v)) {
+ /* Find a different node that uses 'v' */
+ PBVHNode *new_node;
+
+ new_node = pbvh_bmesh_vert_other_node_find(bvh, v);
+ BLI_assert(new_node || BM_vert_face_count_is_equal(v, 1));
+
+ if (new_node) {
+ pbvh_bmesh_vert_ownership_transfer(bvh, new_node, v);
+ }
+ }
+ else {
+ /* Remove from other verts */
+ BLI_gset_remove(f_node->bm_other_verts, v, NULL);
+ }
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+
+ /* Remove face from node and top level */
+ BLI_gset_remove(f_node->bm_faces, f, NULL);
+ BM_ELEM_CD_SET_INT(f, bvh->cd_face_node_offset, DYNTOPO_NODE_NONE);
+
+ /* Log removed face */
+ BM_log_face_removed(bvh->bm_log, f);
+
+ /* mark node for update */
+ f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals;
}
static void pbvh_bmesh_edge_loops(BLI_Buffer *buf, BMEdge *e)
{
- /* fast-path for most common case where an edge has 2 faces,
- * no need to iterate twice.
- * This assumes that the buffer */
- BMLoop **data = buf->data;
- BLI_assert(buf->alloc_count >= 2);
- if (LIKELY(BM_edge_loop_pair(e, &data[0], &data[1]))) {
- buf->count = 2;
- }
- else {
- BLI_buffer_reinit(buf, BM_edge_face_count(e));
- BM_iter_as_array(NULL, BM_LOOPS_OF_EDGE, e, buf->data, buf->count);
- }
+ /* fast-path for most common case where an edge has 2 faces,
+ * no need to iterate twice.
+ * This assumes that the buffer */
+ BMLoop **data = buf->data;
+ BLI_assert(buf->alloc_count >= 2);
+ if (LIKELY(BM_edge_loop_pair(e, &data[0], &data[1]))) {
+ buf->count = 2;
+ }
+ else {
+ BLI_buffer_reinit(buf, BM_edge_face_count(e));
+ BM_iter_as_array(NULL, BM_LOOPS_OF_EDGE, e, buf->data, buf->count);
+ }
}
static void pbvh_bmesh_node_drop_orig(PBVHNode *node)
{
- if (node->bm_orco)
- MEM_freeN(node->bm_orco);
- if (node->bm_ortri)
- MEM_freeN(node->bm_ortri);
- node->bm_orco = NULL;
- node->bm_ortri = NULL;
- node->bm_tot_ortri = 0;
+ if (node->bm_orco)
+ MEM_freeN(node->bm_orco);
+ if (node->bm_ortri)
+ MEM_freeN(node->bm_ortri);
+ node->bm_orco = NULL;
+ node->bm_ortri = NULL;
+ node->bm_tot_ortri = 0;
}
/****************************** EdgeQueue *****************************/
@@ -717,37 +723,39 @@ static void pbvh_bmesh_node_drop_orig(PBVHNode *node)
struct EdgeQueue;
typedef struct EdgeQueue {
- HeapSimple *heap;
- const float *center;
- float center_proj[3]; /* for when we use projected coords. */
- float radius_squared;
- float limit_len_squared;
+ HeapSimple *heap;
+ const float *center;
+ float center_proj[3]; /* for when we use projected coords. */
+ float radius_squared;
+ float limit_len_squared;
#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
- float limit_len;
+ float limit_len;
#endif
- bool (*edge_queue_tri_in_range)(const struct EdgeQueue *q, BMFace *f);
+ bool (*edge_queue_tri_in_range)(const struct EdgeQueue *q, BMFace *f);
- const float *view_normal;
+ const float *view_normal;
#ifdef USE_EDGEQUEUE_FRONTFACE
- unsigned int use_view_normal : 1;
+ unsigned int use_view_normal : 1;
#endif
} EdgeQueue;
typedef struct {
- EdgeQueue *q;
- BLI_mempool *pool;
- BMesh *bm;
- int cd_vert_mask_offset;
- int cd_vert_node_offset;
- int cd_face_node_offset;
+ EdgeQueue *q;
+ BLI_mempool *pool;
+ BMesh *bm;
+ int cd_vert_mask_offset;
+ int cd_vert_node_offset;
+ int cd_face_node_offset;
} EdgeQueueContext;
/* only tag'd edges are in the queue */
#ifdef USE_EDGEQUEUE_TAG
-# define EDGE_QUEUE_TEST(e) (BM_elem_flag_test((CHECK_TYPE_INLINE(e, BMEdge *), e), BM_ELEM_TAG))
-# define EDGE_QUEUE_ENABLE(e) BM_elem_flag_enable((CHECK_TYPE_INLINE(e, BMEdge *), e), BM_ELEM_TAG)
-# define EDGE_QUEUE_DISABLE(e) BM_elem_flag_disable((CHECK_TYPE_INLINE(e, BMEdge *), e), BM_ELEM_TAG)
+# define EDGE_QUEUE_TEST(e) (BM_elem_flag_test((CHECK_TYPE_INLINE(e, BMEdge *), e), BM_ELEM_TAG))
+# define EDGE_QUEUE_ENABLE(e) \
+ BM_elem_flag_enable((CHECK_TYPE_INLINE(e, BMEdge *), e), BM_ELEM_TAG)
+# define EDGE_QUEUE_DISABLE(e) \
+ BM_elem_flag_disable((CHECK_TYPE_INLINE(e, BMEdge *), e), BM_ELEM_TAG)
#endif
#ifdef USE_EDGEQUEUE_TAG_VERIFY
@@ -755,239 +763,225 @@ typedef struct {
* (it's a requirement that edges enter and leave a clean tag state) */
static void pbvh_bmesh_edge_tag_verify(PBVH *bvh)
{
- for (int n = 0; n < bvh->totnode; n++) {
- PBVHNode *node = &bvh->nodes[n];
- if (node->bm_faces) {
- GSetIterator gs_iter;
- GSET_ITER (gs_iter, node->bm_faces) {
- BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
- BMEdge *e_tri[3];
- BMLoop *l_iter;
-
- BLI_assert(f->len == 3);
- l_iter = BM_FACE_FIRST_LOOP(f);
- e_tri[0] = l_iter->e; l_iter = l_iter->next;
- e_tri[1] = l_iter->e; l_iter = l_iter->next;
- e_tri[2] = l_iter->e;
-
- BLI_assert((EDGE_QUEUE_TEST(e_tri[0]) == false) &&
- (EDGE_QUEUE_TEST(e_tri[1]) == false) &&
- (EDGE_QUEUE_TEST(e_tri[2]) == false));
- }
- }
- }
+ for (int n = 0; n < bvh->totnode; n++) {
+ PBVHNode *node = &bvh->nodes[n];
+ if (node->bm_faces) {
+ GSetIterator gs_iter;
+ GSET_ITER (gs_iter, node->bm_faces) {
+ BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
+ BMEdge *e_tri[3];
+ BMLoop *l_iter;
+
+ BLI_assert(f->len == 3);
+ l_iter = BM_FACE_FIRST_LOOP(f);
+ e_tri[0] = l_iter->e;
+ l_iter = l_iter->next;
+ e_tri[1] = l_iter->e;
+ l_iter = l_iter->next;
+ e_tri[2] = l_iter->e;
+
+ BLI_assert((EDGE_QUEUE_TEST(e_tri[0]) == false) && (EDGE_QUEUE_TEST(e_tri[1]) == false) &&
+ (EDGE_QUEUE_TEST(e_tri[2]) == false));
+ }
+ }
+ }
}
#endif
static bool edge_queue_tri_in_sphere(const EdgeQueue *q, BMFace *f)
{
- BMVert *v_tri[3];
- float c[3];
+ BMVert *v_tri[3];
+ float c[3];
- /* Get closest point in triangle to sphere center */
- BM_face_as_array_vert_tri(f, v_tri);
+ /* Get closest point in triangle to sphere center */
+ BM_face_as_array_vert_tri(f, v_tri);
- closest_on_tri_to_point_v3(c, q->center, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co);
+ closest_on_tri_to_point_v3(c, q->center, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co);
- /* Check if triangle intersects the sphere */
- return len_squared_v3v3(q->center, c) <= q->radius_squared;
+ /* Check if triangle intersects the sphere */
+ return len_squared_v3v3(q->center, c) <= q->radius_squared;
}
static bool edge_queue_tri_in_circle(const EdgeQueue *q, BMFace *f)
{
- BMVert *v_tri[3];
- float c[3];
- float tri_proj[3][3];
+ BMVert *v_tri[3];
+ float c[3];
+ float tri_proj[3][3];
- /* Get closest point in triangle to sphere center */
- BM_face_as_array_vert_tri(f, v_tri);
+ /* Get closest point in triangle to sphere center */
+ BM_face_as_array_vert_tri(f, v_tri);
- project_plane_normalized_v3_v3v3(tri_proj[0], v_tri[0]->co, q->view_normal);
- project_plane_normalized_v3_v3v3(tri_proj[1], v_tri[1]->co, q->view_normal);
- project_plane_normalized_v3_v3v3(tri_proj[2], v_tri[2]->co, q->view_normal);
+ project_plane_normalized_v3_v3v3(tri_proj[0], v_tri[0]->co, q->view_normal);
+ project_plane_normalized_v3_v3v3(tri_proj[1], v_tri[1]->co, q->view_normal);
+ project_plane_normalized_v3_v3v3(tri_proj[2], v_tri[2]->co, q->view_normal);
- closest_on_tri_to_point_v3(c, q->center_proj, tri_proj[0], tri_proj[1], tri_proj[2]);
+ closest_on_tri_to_point_v3(c, q->center_proj, tri_proj[0], tri_proj[1], tri_proj[2]);
- /* Check if triangle intersects the sphere */
- return len_squared_v3v3(q->center_proj, c) <= q->radius_squared;
+ /* Check if triangle intersects the sphere */
+ return len_squared_v3v3(q->center_proj, c) <= q->radius_squared;
}
/* Return true if the vertex mask is less than 1.0, false otherwise */
static bool check_mask(EdgeQueueContext *eq_ctx, BMVert *v)
{
- return BM_ELEM_CD_GET_FLOAT(v, eq_ctx->cd_vert_mask_offset) < 1.0f;
+ return BM_ELEM_CD_GET_FLOAT(v, eq_ctx->cd_vert_mask_offset) < 1.0f;
}
-static void edge_queue_insert(
- EdgeQueueContext *eq_ctx, BMEdge *e,
- float priority)
+static void edge_queue_insert(EdgeQueueContext *eq_ctx, BMEdge *e, float priority)
{
- /* Don't let topology update affect fully masked vertices. This used to
- * have a 50% mask cutoff, with the reasoning that you can't do a 50%
- * topology update. But this gives an ugly border in the mesh. The mask
- * should already make the brush move the vertices only 50%, which means
- * that topology updates will also happen less frequent, that should be
- * enough. */
- if (((eq_ctx->cd_vert_mask_offset == -1) ||
- (check_mask(eq_ctx, e->v1) || check_mask(eq_ctx, e->v2))) &&
- !(BM_elem_flag_test_bool(e->v1, BM_ELEM_HIDDEN) ||
- BM_elem_flag_test_bool(e->v2, BM_ELEM_HIDDEN)))
- {
- BMVert **pair = BLI_mempool_alloc(eq_ctx->pool);
- pair[0] = e->v1;
- pair[1] = e->v2;
- BLI_heapsimple_insert(eq_ctx->q->heap, priority, pair);
+ /* Don't let topology update affect fully masked vertices. This used to
+ * have a 50% mask cutoff, with the reasoning that you can't do a 50%
+ * topology update. But this gives an ugly border in the mesh. The mask
+ * should already make the brush move the vertices only 50%, which means
+ * that topology updates will also happen less frequent, that should be
+ * enough. */
+ if (((eq_ctx->cd_vert_mask_offset == -1) ||
+ (check_mask(eq_ctx, e->v1) || check_mask(eq_ctx, e->v2))) &&
+ !(BM_elem_flag_test_bool(e->v1, BM_ELEM_HIDDEN) ||
+ BM_elem_flag_test_bool(e->v2, BM_ELEM_HIDDEN))) {
+ BMVert **pair = BLI_mempool_alloc(eq_ctx->pool);
+ pair[0] = e->v1;
+ pair[1] = e->v2;
+ BLI_heapsimple_insert(eq_ctx->q->heap, priority, pair);
#ifdef USE_EDGEQUEUE_TAG
- BLI_assert(EDGE_QUEUE_TEST(e) == false);
- EDGE_QUEUE_ENABLE(e);
+ BLI_assert(EDGE_QUEUE_TEST(e) == false);
+ EDGE_QUEUE_ENABLE(e);
#endif
- }
+ }
}
-static void long_edge_queue_edge_add(
- EdgeQueueContext *eq_ctx,
- BMEdge *e)
+static void long_edge_queue_edge_add(EdgeQueueContext *eq_ctx, BMEdge *e)
{
#ifdef USE_EDGEQUEUE_TAG
- if (EDGE_QUEUE_TEST(e) == false)
+ if (EDGE_QUEUE_TEST(e) == false)
#endif
- {
- const float len_sq = BM_edge_calc_length_squared(e);
- if (len_sq > eq_ctx->q->limit_len_squared) {
- edge_queue_insert(eq_ctx, e, -len_sq);
- }
- }
+ {
+ const float len_sq = BM_edge_calc_length_squared(e);
+ if (len_sq > eq_ctx->q->limit_len_squared) {
+ edge_queue_insert(eq_ctx, e, -len_sq);
+ }
+ }
}
#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
static void long_edge_queue_edge_add_recursive(
- EdgeQueueContext *eq_ctx,
- BMLoop *l_edge, BMLoop *l_end,
- const float len_sq, float limit_len)
+ EdgeQueueContext *eq_ctx, BMLoop *l_edge, BMLoop *l_end, const float len_sq, float limit_len)
{
- BLI_assert(len_sq > SQUARE(limit_len));
-
-#ifdef USE_EDGEQUEUE_FRONTFACE
- if (eq_ctx->q->use_view_normal) {
- if (dot_v3v3(l_edge->f->no, eq_ctx->q->view_normal) < 0.0f) {
- return;
- }
- }
-#endif
+ BLI_assert(len_sq > SQUARE(limit_len));
+
+# ifdef USE_EDGEQUEUE_FRONTFACE
+ if (eq_ctx->q->use_view_normal) {
+ if (dot_v3v3(l_edge->f->no, eq_ctx->q->view_normal) < 0.0f) {
+ return;
+ }
+ }
+# endif
-#ifdef USE_EDGEQUEUE_TAG
- if (EDGE_QUEUE_TEST(l_edge->e) == false)
-#endif
- {
- edge_queue_insert(eq_ctx, l_edge->e, -len_sq);
- }
-
- /* temp support previous behavior! */
- if (UNLIKELY(G.debug_value == 1234)) {
- return;
- }
-
- if ((l_edge->radial_next != l_edge)) {
- /* how much longer we need to be to consider for subdividing
- * (avoids subdividing faces which are only *slightly* skinny) */
-#define EVEN_EDGELEN_THRESHOLD 1.2f
- /* how much the limit increases per recursion
- * (avoids performing subdvisions too far away) */
-#define EVEN_GENERATION_SCALE 1.6f
-
- const float len_sq_cmp = len_sq * EVEN_EDGELEN_THRESHOLD;
-
- limit_len *= EVEN_GENERATION_SCALE;
- const float limit_len_sq = SQUARE(limit_len);
-
- BMLoop *l_iter = l_edge;
- do {
- BMLoop *l_adjacent[2] = {l_iter->next, l_iter->prev};
- for (int i = 0; i < ARRAY_SIZE(l_adjacent); i++) {
- float len_sq_other = BM_edge_calc_length_squared(l_adjacent[i]->e);
- if (len_sq_other > max_ff(len_sq_cmp, limit_len_sq)) {
-// edge_queue_insert(eq_ctx, l_adjacent[i]->e, -len_sq_other);
- long_edge_queue_edge_add_recursive(
- eq_ctx, l_adjacent[i]->radial_next, l_adjacent[i],
- len_sq_other, limit_len);
- }
- }
- } while ((l_iter = l_iter->radial_next) != l_end);
-
-#undef EVEN_EDGELEN_THRESHOLD
-#undef EVEN_GENERATION_SCALE
- }
+# ifdef USE_EDGEQUEUE_TAG
+ if (EDGE_QUEUE_TEST(l_edge->e) == false)
+# endif
+ {
+ edge_queue_insert(eq_ctx, l_edge->e, -len_sq);
+ }
+
+ /* temp support previous behavior! */
+ if (UNLIKELY(G.debug_value == 1234)) {
+ return;
+ }
+
+ if ((l_edge->radial_next != l_edge)) {
+ /* how much longer we need to be to consider for subdividing
+ * (avoids subdividing faces which are only *slightly* skinny) */
+# define EVEN_EDGELEN_THRESHOLD 1.2f
+ /* how much the limit increases per recursion
+ * (avoids performing subdvisions too far away) */
+# define EVEN_GENERATION_SCALE 1.6f
+
+ const float len_sq_cmp = len_sq * EVEN_EDGELEN_THRESHOLD;
+
+ limit_len *= EVEN_GENERATION_SCALE;
+ const float limit_len_sq = SQUARE(limit_len);
+
+ BMLoop *l_iter = l_edge;
+ do {
+ BMLoop *l_adjacent[2] = {l_iter->next, l_iter->prev};
+ for (int i = 0; i < ARRAY_SIZE(l_adjacent); i++) {
+ float len_sq_other = BM_edge_calc_length_squared(l_adjacent[i]->e);
+ if (len_sq_other > max_ff(len_sq_cmp, limit_len_sq)) {
+ // edge_queue_insert(eq_ctx, l_adjacent[i]->e, -len_sq_other);
+ long_edge_queue_edge_add_recursive(
+ eq_ctx, l_adjacent[i]->radial_next, l_adjacent[i], len_sq_other, limit_len);
+ }
+ }
+ } while ((l_iter = l_iter->radial_next) != l_end);
+
+# undef EVEN_EDGELEN_THRESHOLD
+# undef EVEN_GENERATION_SCALE
+ }
}
-#endif /* USE_EDGEQUEUE_EVEN_SUBDIV */
+#endif /* USE_EDGEQUEUE_EVEN_SUBDIV */
-static void short_edge_queue_edge_add(
- EdgeQueueContext *eq_ctx,
- BMEdge *e)
+static void short_edge_queue_edge_add(EdgeQueueContext *eq_ctx, BMEdge *e)
{
#ifdef USE_EDGEQUEUE_TAG
- if (EDGE_QUEUE_TEST(e) == false)
+ if (EDGE_QUEUE_TEST(e) == false)
#endif
- {
- const float len_sq = BM_edge_calc_length_squared(e);
- if (len_sq < eq_ctx->q->limit_len_squared) {
- edge_queue_insert(eq_ctx, e, len_sq);
- }
- }
+ {
+ const float len_sq = BM_edge_calc_length_squared(e);
+ if (len_sq < eq_ctx->q->limit_len_squared) {
+ edge_queue_insert(eq_ctx, e, len_sq);
+ }
+ }
}
-static void long_edge_queue_face_add(
- EdgeQueueContext *eq_ctx,
- BMFace *f)
+static void long_edge_queue_face_add(EdgeQueueContext *eq_ctx, BMFace *f)
{
#ifdef USE_EDGEQUEUE_FRONTFACE
- if (eq_ctx->q->use_view_normal) {
- if (dot_v3v3(f->no, eq_ctx->q->view_normal) < 0.0f) {
- return;
- }
- }
+ if (eq_ctx->q->use_view_normal) {
+ if (dot_v3v3(f->no, eq_ctx->q->view_normal) < 0.0f) {
+ return;
+ }
+ }
#endif
- if (eq_ctx->q->edge_queue_tri_in_range(eq_ctx->q, f)) {
- /* Check each edge of the face */
- BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
- BMLoop *l_iter = l_first;
- do {
+ if (eq_ctx->q->edge_queue_tri_in_range(eq_ctx->q, f)) {
+ /* Check each edge of the face */
+ BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
+ BMLoop *l_iter = l_first;
+ do {
#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
- const float len_sq = BM_edge_calc_length_squared(l_iter->e);
- if (len_sq > eq_ctx->q->limit_len_squared) {
- long_edge_queue_edge_add_recursive(
- eq_ctx, l_iter->radial_next, l_iter,
- len_sq, eq_ctx->q->limit_len);
- }
+ const float len_sq = BM_edge_calc_length_squared(l_iter->e);
+ if (len_sq > eq_ctx->q->limit_len_squared) {
+ long_edge_queue_edge_add_recursive(
+ eq_ctx, l_iter->radial_next, l_iter, len_sq, eq_ctx->q->limit_len);
+ }
#else
- long_edge_queue_edge_add(eq_ctx, l_iter->e);
+ long_edge_queue_edge_add(eq_ctx, l_iter->e);
#endif
- } while ((l_iter = l_iter->next) != l_first);
- }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
}
-static void short_edge_queue_face_add(
- EdgeQueueContext *eq_ctx,
- BMFace *f)
+static void short_edge_queue_face_add(EdgeQueueContext *eq_ctx, BMFace *f)
{
#ifdef USE_EDGEQUEUE_FRONTFACE
- if (eq_ctx->q->use_view_normal) {
- if (dot_v3v3(f->no, eq_ctx->q->view_normal) < 0.0f) {
- return;
- }
- }
+ if (eq_ctx->q->use_view_normal) {
+ if (dot_v3v3(f->no, eq_ctx->q->view_normal) < 0.0f) {
+ return;
+ }
+ }
#endif
- if (eq_ctx->q->edge_queue_tri_in_range(eq_ctx->q, f)) {
- BMLoop *l_iter;
- BMLoop *l_first;
+ if (eq_ctx->q->edge_queue_tri_in_range(eq_ctx->q, f)) {
+ BMLoop *l_iter;
+ BMLoop *l_first;
- /* Check each edge of the face */
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- short_edge_queue_edge_add(eq_ctx, l_iter->e);
- } while ((l_iter = l_iter->next) != l_first);
- }
+ /* Check each edge of the face */
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ short_edge_queue_edge_add(eq_ctx, l_iter->e);
+ } while ((l_iter = l_iter->next) != l_first);
+ }
}
/* Create a priority queue containing vertex pairs connected by a long
@@ -999,57 +993,58 @@ static void short_edge_queue_face_add(
*
* The highest priority (lowest number) is given to the longest edge.
*/
-static void long_edge_queue_create(
- EdgeQueueContext *eq_ctx,
- PBVH *bvh, const float center[3], const float view_normal[3],
- float radius, const bool use_frontface, const bool use_projected)
+static void long_edge_queue_create(EdgeQueueContext *eq_ctx,
+ PBVH *bvh,
+ const float center[3],
+ const float view_normal[3],
+ float radius,
+ const bool use_frontface,
+ const bool use_projected)
{
- eq_ctx->q->heap = BLI_heapsimple_new();
- eq_ctx->q->center = center;
- eq_ctx->q->radius_squared = radius * radius;
- eq_ctx->q->limit_len_squared = bvh->bm_max_edge_len * bvh->bm_max_edge_len;
+ eq_ctx->q->heap = BLI_heapsimple_new();
+ eq_ctx->q->center = center;
+ eq_ctx->q->radius_squared = radius * radius;
+ eq_ctx->q->limit_len_squared = bvh->bm_max_edge_len * bvh->bm_max_edge_len;
#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
- eq_ctx->q->limit_len = bvh->bm_max_edge_len;
+ eq_ctx->q->limit_len = bvh->bm_max_edge_len;
#endif
- eq_ctx->q->view_normal = view_normal;
+ eq_ctx->q->view_normal = view_normal;
#ifdef USE_EDGEQUEUE_FRONTFACE
- eq_ctx->q->use_view_normal = use_frontface;
+ eq_ctx->q->use_view_normal = use_frontface;
#else
- UNUSED_VARS(use_frontface);
+ UNUSED_VARS(use_frontface);
#endif
- if (use_projected) {
- eq_ctx->q->edge_queue_tri_in_range = edge_queue_tri_in_circle;
- project_plane_normalized_v3_v3v3(eq_ctx->q->center_proj, center, view_normal);
- }
- else {
- eq_ctx->q->edge_queue_tri_in_range = edge_queue_tri_in_sphere;
- }
+ if (use_projected) {
+ eq_ctx->q->edge_queue_tri_in_range = edge_queue_tri_in_circle;
+ project_plane_normalized_v3_v3v3(eq_ctx->q->center_proj, center, view_normal);
+ }
+ else {
+ eq_ctx->q->edge_queue_tri_in_range = edge_queue_tri_in_sphere;
+ }
#ifdef USE_EDGEQUEUE_TAG_VERIFY
- pbvh_bmesh_edge_tag_verify(bvh);
+ pbvh_bmesh_edge_tag_verify(bvh);
#endif
- for (int n = 0; n < bvh->totnode; n++) {
- PBVHNode *node = &bvh->nodes[n];
+ for (int n = 0; n < bvh->totnode; n++) {
+ PBVHNode *node = &bvh->nodes[n];
- /* Check leaf nodes marked for topology update */
- if ((node->flag & PBVH_Leaf) &&
- (node->flag & PBVH_UpdateTopology) &&
- !(node->flag & PBVH_FullyHidden))
- {
- GSetIterator gs_iter;
+ /* Check leaf nodes marked for topology update */
+ if ((node->flag & PBVH_Leaf) && (node->flag & PBVH_UpdateTopology) &&
+ !(node->flag & PBVH_FullyHidden)) {
+ GSetIterator gs_iter;
- /* Check each face */
- GSET_ITER (gs_iter, node->bm_faces) {
- BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
+ /* Check each face */
+ GSET_ITER (gs_iter, node->bm_faces) {
+ BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
- long_edge_queue_face_add(eq_ctx, f);
- }
- }
- }
+ long_edge_queue_face_add(eq_ctx, f);
+ }
+ }
+ }
}
/* Create a priority queue containing vertex pairs connected by a
@@ -1061,605 +1056,600 @@ static void long_edge_queue_create(
*
* The highest priority (lowest number) is given to the shortest edge.
*/
-static void short_edge_queue_create(
- EdgeQueueContext *eq_ctx,
- PBVH *bvh, const float center[3], const float view_normal[3],
- float radius, const bool use_frontface, const bool use_projected)
+static void short_edge_queue_create(EdgeQueueContext *eq_ctx,
+ PBVH *bvh,
+ const float center[3],
+ const float view_normal[3],
+ float radius,
+ const bool use_frontface,
+ const bool use_projected)
{
- eq_ctx->q->heap = BLI_heapsimple_new();
- eq_ctx->q->center = center;
- eq_ctx->q->radius_squared = radius * radius;
- eq_ctx->q->limit_len_squared = bvh->bm_min_edge_len * bvh->bm_min_edge_len;
+ eq_ctx->q->heap = BLI_heapsimple_new();
+ eq_ctx->q->center = center;
+ eq_ctx->q->radius_squared = radius * radius;
+ eq_ctx->q->limit_len_squared = bvh->bm_min_edge_len * bvh->bm_min_edge_len;
#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
- eq_ctx->q->limit_len = bvh->bm_min_edge_len;
+ eq_ctx->q->limit_len = bvh->bm_min_edge_len;
#endif
- eq_ctx->q->view_normal = view_normal;
+ eq_ctx->q->view_normal = view_normal;
#ifdef USE_EDGEQUEUE_FRONTFACE
- eq_ctx->q->use_view_normal = use_frontface;
+ eq_ctx->q->use_view_normal = use_frontface;
#else
- UNUSED_VARS(use_frontface);
+ UNUSED_VARS(use_frontface);
#endif
- if (use_projected) {
- eq_ctx->q->edge_queue_tri_in_range = edge_queue_tri_in_circle;
- project_plane_normalized_v3_v3v3(eq_ctx->q->center_proj, center, view_normal);
- }
- else {
- eq_ctx->q->edge_queue_tri_in_range = edge_queue_tri_in_sphere;
- }
-
- for (int n = 0; n < bvh->totnode; n++) {
- PBVHNode *node = &bvh->nodes[n];
-
- /* Check leaf nodes marked for topology update */
- if ((node->flag & PBVH_Leaf) &&
- (node->flag & PBVH_UpdateTopology) &&
- !(node->flag & PBVH_FullyHidden))
- {
- GSetIterator gs_iter;
-
- /* Check each face */
- GSET_ITER (gs_iter, node->bm_faces) {
- BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
-
- short_edge_queue_face_add(eq_ctx, f);
- }
- }
- }
+ if (use_projected) {
+ eq_ctx->q->edge_queue_tri_in_range = edge_queue_tri_in_circle;
+ project_plane_normalized_v3_v3v3(eq_ctx->q->center_proj, center, view_normal);
+ }
+ else {
+ eq_ctx->q->edge_queue_tri_in_range = edge_queue_tri_in_sphere;
+ }
+
+ for (int n = 0; n < bvh->totnode; n++) {
+ PBVHNode *node = &bvh->nodes[n];
+
+ /* Check leaf nodes marked for topology update */
+ if ((node->flag & PBVH_Leaf) && (node->flag & PBVH_UpdateTopology) &&
+ !(node->flag & PBVH_FullyHidden)) {
+ GSetIterator gs_iter;
+
+ /* Check each face */
+ GSET_ITER (gs_iter, node->bm_faces) {
+ BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
+
+ short_edge_queue_face_add(eq_ctx, f);
+ }
+ }
+ }
}
/*************************** Topology update **************************/
-static void pbvh_bmesh_split_edge(
- EdgeQueueContext *eq_ctx, PBVH *bvh,
- BMEdge *e, BLI_Buffer *edge_loops)
+static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx,
+ PBVH *bvh,
+ BMEdge *e,
+ BLI_Buffer *edge_loops)
{
- float co_mid[3], no_mid[3];
-
- /* Get all faces adjacent to the edge */
- pbvh_bmesh_edge_loops(edge_loops, e);
-
- /* Create a new vertex in current node at the edge's midpoint */
- mid_v3_v3v3(co_mid, e->v1->co, e->v2->co);
- mid_v3_v3v3(no_mid, e->v1->no, e->v2->no);
- normalize_v3(no_mid);
-
- int node_index = BM_ELEM_CD_GET_INT(e->v1, eq_ctx->cd_vert_node_offset);
- BMVert *v_new = pbvh_bmesh_vert_create(bvh, node_index, co_mid, no_mid, eq_ctx->cd_vert_mask_offset);
-
- /* update paint mask */
- if (eq_ctx->cd_vert_mask_offset != -1) {
- float mask_v1 = BM_ELEM_CD_GET_FLOAT(e->v1, eq_ctx->cd_vert_mask_offset);
- float mask_v2 = BM_ELEM_CD_GET_FLOAT(e->v2, eq_ctx->cd_vert_mask_offset);
- float mask_v_new = 0.5f * (mask_v1 + mask_v2);
-
- BM_ELEM_CD_SET_FLOAT(v_new, eq_ctx->cd_vert_mask_offset, mask_v_new);
- }
-
- /* For each face, add two new triangles and delete the original */
- for (int i = 0; i < edge_loops->count; i++) {
- BMLoop *l_adj = BLI_buffer_at(edge_loops, BMLoop *, i);
- BMFace *f_adj = l_adj->f;
- BMFace *f_new;
- BMVert *v_opp, *v1, *v2;
- BMVert *v_tri[3];
- BMEdge *e_tri[3];
-
- BLI_assert(f_adj->len == 3);
- int ni = BM_ELEM_CD_GET_INT(f_adj, eq_ctx->cd_face_node_offset);
-
- /* Find the vertex not in the edge */
- v_opp = l_adj->prev->v;
-
- /* Get e->v1 and e->v2 in the order they appear in the
- * existing face so that the new faces' winding orders
- * match */
- v1 = l_adj->v;
- v2 = l_adj->next->v;
-
- if (ni != node_index && i == 0)
- pbvh_bmesh_vert_ownership_transfer(bvh, &bvh->nodes[ni], v_new);
-
- /**
- * The 2 new faces created and assigned to ``f_new`` have their
- * verts & edges shuffled around.
- *
- * - faces wind anticlockwise in this example.
- * - original edge is ``(v1, v2)``
- * - original face is ``(v1, v2, v3)``
- *
- * <pre>
- * + v3(v_opp)
- * /|\
- * / | \
- * / | \
- * e4/ | \ e3
- * / |e5 \
- * / | \
- * / e1 | e2 \
- * +-------+-------+
- * v1 v4(v_new) v2
- * (first) (second)
- * </pre>
- *
- * - f_new (first): ``v_tri=(v1, v4, v3), e_tri=(e1, e5, e4)``
- * - f_new (second): ``v_tri=(v4, v2, v3), e_tri=(e2, e3, e5)``
- */
-
- /* Create two new faces */
- v_tri[0] = v1;
- v_tri[1] = v_new;
- v_tri[2] = v_opp;
- bm_edges_from_tri(bvh->bm, v_tri, e_tri);
- f_new = pbvh_bmesh_face_create(bvh, ni, v_tri, e_tri, f_adj);
- long_edge_queue_face_add(eq_ctx, f_new);
-
- v_tri[0] = v_new;
- v_tri[1] = v2;
- /* v_tri[2] = v_opp; */ /* unchanged */
- e_tri[0] = BM_edge_create(bvh->bm, v_tri[0], v_tri[1], NULL, BM_CREATE_NO_DOUBLE);
- e_tri[2] = e_tri[1]; /* switched */
- e_tri[1] = BM_edge_create(bvh->bm, v_tri[1], v_tri[2], NULL, BM_CREATE_NO_DOUBLE);
- f_new = pbvh_bmesh_face_create(bvh, ni, v_tri, e_tri, f_adj);
- long_edge_queue_face_add(eq_ctx, f_new);
-
- /* Delete original */
- pbvh_bmesh_face_remove(bvh, f_adj);
- BM_face_kill(bvh->bm, f_adj);
-
- /* Ensure new vertex is in the node */
- if (!BLI_gset_haskey(bvh->nodes[ni].bm_unique_verts, v_new)) {
- BLI_gset_add(bvh->nodes[ni].bm_other_verts, v_new);
- }
-
- if (BM_vert_edge_count_is_over(v_opp, 8)) {
- BMIter bm_iter;
- BMEdge *e2;
-
- BM_ITER_ELEM (e2, &bm_iter, v_opp, BM_EDGES_OF_VERT) {
- long_edge_queue_edge_add(eq_ctx, e2);
- }
- }
- }
-
- BM_edge_kill(bvh->bm, e);
+ float co_mid[3], no_mid[3];
+
+ /* Get all faces adjacent to the edge */
+ pbvh_bmesh_edge_loops(edge_loops, e);
+
+ /* Create a new vertex in current node at the edge's midpoint */
+ mid_v3_v3v3(co_mid, e->v1->co, e->v2->co);
+ mid_v3_v3v3(no_mid, e->v1->no, e->v2->no);
+ normalize_v3(no_mid);
+
+ int node_index = BM_ELEM_CD_GET_INT(e->v1, eq_ctx->cd_vert_node_offset);
+ BMVert *v_new = pbvh_bmesh_vert_create(
+ bvh, node_index, co_mid, no_mid, eq_ctx->cd_vert_mask_offset);
+
+ /* update paint mask */
+ if (eq_ctx->cd_vert_mask_offset != -1) {
+ float mask_v1 = BM_ELEM_CD_GET_FLOAT(e->v1, eq_ctx->cd_vert_mask_offset);
+ float mask_v2 = BM_ELEM_CD_GET_FLOAT(e->v2, eq_ctx->cd_vert_mask_offset);
+ float mask_v_new = 0.5f * (mask_v1 + mask_v2);
+
+ BM_ELEM_CD_SET_FLOAT(v_new, eq_ctx->cd_vert_mask_offset, mask_v_new);
+ }
+
+ /* For each face, add two new triangles and delete the original */
+ for (int i = 0; i < edge_loops->count; i++) {
+ BMLoop *l_adj = BLI_buffer_at(edge_loops, BMLoop *, i);
+ BMFace *f_adj = l_adj->f;
+ BMFace *f_new;
+ BMVert *v_opp, *v1, *v2;
+ BMVert *v_tri[3];
+ BMEdge *e_tri[3];
+
+ BLI_assert(f_adj->len == 3);
+ int ni = BM_ELEM_CD_GET_INT(f_adj, eq_ctx->cd_face_node_offset);
+
+ /* Find the vertex not in the edge */
+ v_opp = l_adj->prev->v;
+
+ /* Get e->v1 and e->v2 in the order they appear in the
+ * existing face so that the new faces' winding orders
+ * match */
+ v1 = l_adj->v;
+ v2 = l_adj->next->v;
+
+ if (ni != node_index && i == 0)
+ pbvh_bmesh_vert_ownership_transfer(bvh, &bvh->nodes[ni], v_new);
+
+ /**
+ * The 2 new faces created and assigned to ``f_new`` have their
+ * verts & edges shuffled around.
+ *
+ * - faces wind anticlockwise in this example.
+ * - original edge is ``(v1, v2)``
+ * - original face is ``(v1, v2, v3)``
+ *
+ * <pre>
+ * + v3(v_opp)
+ * /|\
+ * / | \
+ * / | \
+ * e4/ | \ e3
+ * / |e5 \
+ * / | \
+ * / e1 | e2 \
+ * +-------+-------+
+ * v1 v4(v_new) v2
+ * (first) (second)
+ * </pre>
+ *
+ * - f_new (first): ``v_tri=(v1, v4, v3), e_tri=(e1, e5, e4)``
+ * - f_new (second): ``v_tri=(v4, v2, v3), e_tri=(e2, e3, e5)``
+ */
+
+ /* Create two new faces */
+ v_tri[0] = v1;
+ v_tri[1] = v_new;
+ v_tri[2] = v_opp;
+ bm_edges_from_tri(bvh->bm, v_tri, e_tri);
+ f_new = pbvh_bmesh_face_create(bvh, ni, v_tri, e_tri, f_adj);
+ long_edge_queue_face_add(eq_ctx, f_new);
+
+ v_tri[0] = v_new;
+ v_tri[1] = v2;
+ /* v_tri[2] = v_opp; */ /* unchanged */
+ e_tri[0] = BM_edge_create(bvh->bm, v_tri[0], v_tri[1], NULL, BM_CREATE_NO_DOUBLE);
+ e_tri[2] = e_tri[1]; /* switched */
+ e_tri[1] = BM_edge_create(bvh->bm, v_tri[1], v_tri[2], NULL, BM_CREATE_NO_DOUBLE);
+ f_new = pbvh_bmesh_face_create(bvh, ni, v_tri, e_tri, f_adj);
+ long_edge_queue_face_add(eq_ctx, f_new);
+
+ /* Delete original */
+ pbvh_bmesh_face_remove(bvh, f_adj);
+ BM_face_kill(bvh->bm, f_adj);
+
+ /* Ensure new vertex is in the node */
+ if (!BLI_gset_haskey(bvh->nodes[ni].bm_unique_verts, v_new)) {
+ BLI_gset_add(bvh->nodes[ni].bm_other_verts, v_new);
+ }
+
+ if (BM_vert_edge_count_is_over(v_opp, 8)) {
+ BMIter bm_iter;
+ BMEdge *e2;
+
+ BM_ITER_ELEM (e2, &bm_iter, v_opp, BM_EDGES_OF_VERT) {
+ long_edge_queue_edge_add(eq_ctx, e2);
+ }
+ }
+ }
+
+ BM_edge_kill(bvh->bm, e);
}
-static bool pbvh_bmesh_subdivide_long_edges(
- EdgeQueueContext *eq_ctx, PBVH *bvh,
- BLI_Buffer *edge_loops)
+static bool pbvh_bmesh_subdivide_long_edges(EdgeQueueContext *eq_ctx,
+ PBVH *bvh,
+ BLI_Buffer *edge_loops)
{
- bool any_subdivided = false;
+ bool any_subdivided = false;
- while (!BLI_heapsimple_is_empty(eq_ctx->q->heap)) {
- BMVert **pair = BLI_heapsimple_pop_min(eq_ctx->q->heap);
- BMVert *v1 = pair[0], *v2 = pair[1];
- BMEdge *e;
+ while (!BLI_heapsimple_is_empty(eq_ctx->q->heap)) {
+ BMVert **pair = BLI_heapsimple_pop_min(eq_ctx->q->heap);
+ BMVert *v1 = pair[0], *v2 = pair[1];
+ BMEdge *e;
- BLI_mempool_free(eq_ctx->pool, pair);
- pair = NULL;
+ BLI_mempool_free(eq_ctx->pool, pair);
+ pair = NULL;
- /* Check that the edge still exists */
- if (!(e = BM_edge_exists(v1, v2))) {
- continue;
- }
+ /* Check that the edge still exists */
+ if (!(e = BM_edge_exists(v1, v2))) {
+ continue;
+ }
#ifdef USE_EDGEQUEUE_TAG
- EDGE_QUEUE_DISABLE(e);
+ EDGE_QUEUE_DISABLE(e);
#endif
- /* At the moment edges never get shorter (subdiv will make new edges)
- * unlike collapse where edges can become longer. */
+ /* At the moment edges never get shorter (subdiv will make new edges)
+ * unlike collapse where edges can become longer. */
#if 0
- if (len_squared_v3v3(v1->co, v2->co) <= eq_ctx->q->limit_len_squared)
- continue;
+ if (len_squared_v3v3(v1->co, v2->co) <= eq_ctx->q->limit_len_squared)
+ continue;
#else
- BLI_assert(len_squared_v3v3(v1->co, v2->co) > eq_ctx->q->limit_len_squared);
+ BLI_assert(len_squared_v3v3(v1->co, v2->co) > eq_ctx->q->limit_len_squared);
#endif
- /* Check that the edge's vertices are still in the PBVH. It's
- * possible that an edge collapse has deleted adjacent faces
- * and the node has been split, thus leaving wire edges and
- * associated vertices. */
- if ((BM_ELEM_CD_GET_INT(e->v1, eq_ctx->cd_vert_node_offset) == DYNTOPO_NODE_NONE) ||
- (BM_ELEM_CD_GET_INT(e->v2, eq_ctx->cd_vert_node_offset) == DYNTOPO_NODE_NONE))
- {
- continue;
- }
+ /* Check that the edge's vertices are still in the PBVH. It's
+ * possible that an edge collapse has deleted adjacent faces
+ * and the node has been split, thus leaving wire edges and
+ * associated vertices. */
+ if ((BM_ELEM_CD_GET_INT(e->v1, eq_ctx->cd_vert_node_offset) == DYNTOPO_NODE_NONE) ||
+ (BM_ELEM_CD_GET_INT(e->v2, eq_ctx->cd_vert_node_offset) == DYNTOPO_NODE_NONE)) {
+ continue;
+ }
- any_subdivided = true;
+ any_subdivided = true;
- pbvh_bmesh_split_edge(eq_ctx, bvh, e, edge_loops);
- }
+ pbvh_bmesh_split_edge(eq_ctx, bvh, e, edge_loops);
+ }
#ifdef USE_EDGEQUEUE_TAG_VERIFY
- pbvh_bmesh_edge_tag_verify(bvh);
+ pbvh_bmesh_edge_tag_verify(bvh);
#endif
- return any_subdivided;
+ return any_subdivided;
}
-static void pbvh_bmesh_collapse_edge(
- PBVH *bvh, BMEdge *e,
- BMVert *v1, BMVert *v2,
- GHash *deleted_verts,
- BLI_Buffer *deleted_faces,
- EdgeQueueContext *eq_ctx)
+static void pbvh_bmesh_collapse_edge(PBVH *bvh,
+ BMEdge *e,
+ BMVert *v1,
+ BMVert *v2,
+ GHash *deleted_verts,
+ BLI_Buffer *deleted_faces,
+ EdgeQueueContext *eq_ctx)
{
- BMVert *v_del, *v_conn;
-
- /* one of the two vertices may be masked, select the correct one for deletion */
- if (BM_ELEM_CD_GET_FLOAT(v1, eq_ctx->cd_vert_mask_offset) <
- BM_ELEM_CD_GET_FLOAT(v2, eq_ctx->cd_vert_mask_offset))
- {
- v_del = v1;
- v_conn = v2;
- }
- else {
- v_del = v2;
- v_conn = v1;
- }
-
- /* Remove the merge vertex from the PBVH */
- pbvh_bmesh_vert_remove(bvh, v_del);
-
- /* Remove all faces adjacent to the edge */
- BMLoop *l_adj;
- while ((l_adj = e->l)) {
- BMFace *f_adj = l_adj->f;
-
- pbvh_bmesh_face_remove(bvh, f_adj);
- BM_face_kill(bvh->bm, f_adj);
- }
-
- /* Kill the edge */
- BLI_assert(BM_edge_is_wire(e));
- BM_edge_kill(bvh->bm, e);
-
- /* For all remaining faces of v_del, create a new face that is the
- * same except it uses v_conn instead of v_del */
- /* Note: this could be done with BM_vert_splice(), but that
- * requires handling other issues like duplicate edges, so doesn't
- * really buy anything. */
- BLI_buffer_clear(deleted_faces);
-
- BMLoop *l;
-
- BM_LOOPS_OF_VERT_ITER_BEGIN(l, v_del) {
- BMFace *existing_face;
-
- /* Get vertices, replace use of v_del with v_conn */
- // BM_iter_as_array(NULL, BM_VERTS_OF_FACE, f, (void **)v_tri, 3);
- BMFace *f = l->f;
+ BMVert *v_del, *v_conn;
+
+ /* one of the two vertices may be masked, select the correct one for deletion */
+ if (BM_ELEM_CD_GET_FLOAT(v1, eq_ctx->cd_vert_mask_offset) <
+ BM_ELEM_CD_GET_FLOAT(v2, eq_ctx->cd_vert_mask_offset)) {
+ v_del = v1;
+ v_conn = v2;
+ }
+ else {
+ v_del = v2;
+ v_conn = v1;
+ }
+
+ /* Remove the merge vertex from the PBVH */
+ pbvh_bmesh_vert_remove(bvh, v_del);
+
+ /* Remove all faces adjacent to the edge */
+ BMLoop *l_adj;
+ while ((l_adj = e->l)) {
+ BMFace *f_adj = l_adj->f;
+
+ pbvh_bmesh_face_remove(bvh, f_adj);
+ BM_face_kill(bvh->bm, f_adj);
+ }
+
+ /* Kill the edge */
+ BLI_assert(BM_edge_is_wire(e));
+ BM_edge_kill(bvh->bm, e);
+
+ /* For all remaining faces of v_del, create a new face that is the
+ * same except it uses v_conn instead of v_del */
+ /* Note: this could be done with BM_vert_splice(), but that
+ * requires handling other issues like duplicate edges, so doesn't
+ * really buy anything. */
+ BLI_buffer_clear(deleted_faces);
+
+ BMLoop *l;
+
+ BM_LOOPS_OF_VERT_ITER_BEGIN (l, v_del) {
+ BMFace *existing_face;
+
+ /* Get vertices, replace use of v_del with v_conn */
+ // BM_iter_as_array(NULL, BM_VERTS_OF_FACE, f, (void **)v_tri, 3);
+ BMFace *f = l->f;
#if 0
- BMVert *v_tri[3];
- BM_face_as_array_vert_tri(f, v_tri);
- for (int i = 0; i < 3; i++) {
- if (v_tri[i] == v_del) {
- v_tri[i] = v_conn;
- }
- }
+ BMVert *v_tri[3];
+ BM_face_as_array_vert_tri(f, v_tri);
+ for (int i = 0; i < 3; i++) {
+ if (v_tri[i] == v_del) {
+ v_tri[i] = v_conn;
+ }
+ }
#endif
- /* Check if a face using these vertices already exists. If so,
- * skip adding this face and mark the existing one for
- * deletion as well. Prevents extraneous "flaps" from being
- * created. */
+ /* Check if a face using these vertices already exists. If so,
+ * skip adding this face and mark the existing one for
+ * deletion as well. Prevents extraneous "flaps" from being
+ * created. */
#if 0
- if (UNLIKELY(existing_face = BM_face_exists(v_tri, 3)))
+ if (UNLIKELY(existing_face = BM_face_exists(v_tri, 3)))
#else
- if (UNLIKELY(existing_face = bm_face_exists_tri_from_loop_vert(l->next, v_conn)))
+ if (UNLIKELY(existing_face = bm_face_exists_tri_from_loop_vert(l->next, v_conn)))
#endif
- {
- BLI_buffer_append(deleted_faces, BMFace *, existing_face);
- }
- else {
- BMVert *v_tri[3] = {v_conn, l->next->v, l->prev->v};
-
- BLI_assert(!BM_face_exists(v_tri, 3));
- BMEdge *e_tri[3];
- PBVHNode *n = pbvh_bmesh_node_from_face(bvh, f);
- int ni = n - bvh->nodes;
- bm_edges_from_tri(bvh->bm, v_tri, e_tri);
- pbvh_bmesh_face_create(bvh, ni, v_tri, e_tri, f);
-
- /* Ensure that v_conn is in the new face's node */
- if (!BLI_gset_haskey(n->bm_unique_verts, v_conn)) {
- BLI_gset_add(n->bm_other_verts, v_conn);
- }
- }
-
- BLI_buffer_append(deleted_faces, BMFace *, f);
- }
- BM_LOOPS_OF_VERT_ITER_END;
-
- /* Delete the tagged faces */
- for (int i = 0; i < deleted_faces->count; i++) {
- BMFace *f_del = BLI_buffer_at(deleted_faces, BMFace *, i);
-
- /* Get vertices and edges of face */
- BLI_assert(f_del->len == 3);
- BMLoop *l_iter = BM_FACE_FIRST_LOOP(f_del);
- BMVert *v_tri[3];
- BMEdge *e_tri[3];
- v_tri[0] = l_iter->v; e_tri[0] = l_iter->e; l_iter = l_iter->next;
- v_tri[1] = l_iter->v; e_tri[1] = l_iter->e; l_iter = l_iter->next;
- v_tri[2] = l_iter->v; e_tri[2] = l_iter->e;
-
- /* Remove the face */
- pbvh_bmesh_face_remove(bvh, f_del);
- BM_face_kill(bvh->bm, f_del);
-
- /* Check if any of the face's edges are now unused by any
- * face, if so delete them */
- for (int j = 0; j < 3; j++) {
- if (BM_edge_is_wire(e_tri[j]))
- BM_edge_kill(bvh->bm, e_tri[j]);
- }
-
- /* Check if any of the face's vertices are now unused, if so
- * remove them from the PBVH */
- for (int j = 0; j < 3; j++) {
- if ((v_tri[j] != v_del) && (v_tri[j]->e == NULL)) {
- pbvh_bmesh_vert_remove(bvh, v_tri[j]);
-
- BM_log_vert_removed(bvh->bm_log, v_tri[j], eq_ctx->cd_vert_mask_offset);
-
- if (v_tri[j] == v_conn) {
- v_conn = NULL;
- }
- BLI_ghash_insert(deleted_verts, v_tri[j], NULL);
- BM_vert_kill(bvh->bm, v_tri[j]);
- }
- }
- }
-
- /* Move v_conn to the midpoint of v_conn and v_del (if v_conn still exists, it
- * may have been deleted above) */
- if (v_conn != NULL) {
- BM_log_vert_before_modified(bvh->bm_log, v_conn, eq_ctx->cd_vert_mask_offset);
- mid_v3_v3v3(v_conn->co, v_conn->co, v_del->co);
- add_v3_v3(v_conn->no, v_del->no);
- normalize_v3(v_conn->no);
-
- /* update boundboxes attached to the connected vertex
- * note that we can often get-away without this but causes T48779 */
- BM_LOOPS_OF_VERT_ITER_BEGIN(l, v_conn) {
- PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, l->f);
- f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals | PBVH_UpdateBB;
- }
- BM_LOOPS_OF_VERT_ITER_END;
- }
-
- /* Delete v_del */
- BLI_assert(!BM_vert_face_check(v_del));
- BM_log_vert_removed(bvh->bm_log, v_del, eq_ctx->cd_vert_mask_offset);
- /* v_conn == NULL is OK */
- BLI_ghash_insert(deleted_verts, v_del, v_conn);
- BM_vert_kill(bvh->bm, v_del);
+ {
+ BLI_buffer_append(deleted_faces, BMFace *, existing_face);
+ }
+ else
+ {
+ BMVert *v_tri[3] = {v_conn, l->next->v, l->prev->v};
+
+ BLI_assert(!BM_face_exists(v_tri, 3));
+ BMEdge *e_tri[3];
+ PBVHNode *n = pbvh_bmesh_node_from_face(bvh, f);
+ int ni = n - bvh->nodes;
+ bm_edges_from_tri(bvh->bm, v_tri, e_tri);
+ pbvh_bmesh_face_create(bvh, ni, v_tri, e_tri, f);
+
+ /* Ensure that v_conn is in the new face's node */
+ if (!BLI_gset_haskey(n->bm_unique_verts, v_conn)) {
+ BLI_gset_add(n->bm_other_verts, v_conn);
+ }
+ }
+
+ BLI_buffer_append(deleted_faces, BMFace *, f);
+ }
+ BM_LOOPS_OF_VERT_ITER_END;
+
+ /* Delete the tagged faces */
+ for (int i = 0; i < deleted_faces->count; i++) {
+ BMFace *f_del = BLI_buffer_at(deleted_faces, BMFace *, i);
+
+ /* Get vertices and edges of face */
+ BLI_assert(f_del->len == 3);
+ BMLoop *l_iter = BM_FACE_FIRST_LOOP(f_del);
+ BMVert *v_tri[3];
+ BMEdge *e_tri[3];
+ v_tri[0] = l_iter->v;
+ e_tri[0] = l_iter->e;
+ l_iter = l_iter->next;
+ v_tri[1] = l_iter->v;
+ e_tri[1] = l_iter->e;
+ l_iter = l_iter->next;
+ v_tri[2] = l_iter->v;
+ e_tri[2] = l_iter->e;
+
+ /* Remove the face */
+ pbvh_bmesh_face_remove(bvh, f_del);
+ BM_face_kill(bvh->bm, f_del);
+
+ /* Check if any of the face's edges are now unused by any
+ * face, if so delete them */
+ for (int j = 0; j < 3; j++) {
+ if (BM_edge_is_wire(e_tri[j]))
+ BM_edge_kill(bvh->bm, e_tri[j]);
+ }
+
+ /* Check if any of the face's vertices are now unused, if so
+ * remove them from the PBVH */
+ for (int j = 0; j < 3; j++) {
+ if ((v_tri[j] != v_del) && (v_tri[j]->e == NULL)) {
+ pbvh_bmesh_vert_remove(bvh, v_tri[j]);
+
+ BM_log_vert_removed(bvh->bm_log, v_tri[j], eq_ctx->cd_vert_mask_offset);
+
+ if (v_tri[j] == v_conn) {
+ v_conn = NULL;
+ }
+ BLI_ghash_insert(deleted_verts, v_tri[j], NULL);
+ BM_vert_kill(bvh->bm, v_tri[j]);
+ }
+ }
+ }
+
+ /* Move v_conn to the midpoint of v_conn and v_del (if v_conn still exists, it
+ * may have been deleted above) */
+ if (v_conn != NULL) {
+ BM_log_vert_before_modified(bvh->bm_log, v_conn, eq_ctx->cd_vert_mask_offset);
+ mid_v3_v3v3(v_conn->co, v_conn->co, v_del->co);
+ add_v3_v3(v_conn->no, v_del->no);
+ normalize_v3(v_conn->no);
+
+ /* update boundboxes attached to the connected vertex
+ * note that we can often get-away without this but causes T48779 */
+ BM_LOOPS_OF_VERT_ITER_BEGIN (l, v_conn) {
+ PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, l->f);
+ f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals | PBVH_UpdateBB;
+ }
+ BM_LOOPS_OF_VERT_ITER_END;
+ }
+
+ /* Delete v_del */
+ BLI_assert(!BM_vert_face_check(v_del));
+ BM_log_vert_removed(bvh->bm_log, v_del, eq_ctx->cd_vert_mask_offset);
+ /* v_conn == NULL is OK */
+ BLI_ghash_insert(deleted_verts, v_del, v_conn);
+ BM_vert_kill(bvh->bm, v_del);
}
-static bool pbvh_bmesh_collapse_short_edges(
- EdgeQueueContext *eq_ctx,
- PBVH *bvh,
- BLI_Buffer *deleted_faces)
+static bool pbvh_bmesh_collapse_short_edges(EdgeQueueContext *eq_ctx,
+ PBVH *bvh,
+ BLI_Buffer *deleted_faces)
{
- const float min_len_squared = bvh->bm_min_edge_len * bvh->bm_min_edge_len;
- bool any_collapsed = false;
- /* deleted verts point to vertices they were merged into, or NULL when removed. */
- GHash *deleted_verts = BLI_ghash_ptr_new("deleted_verts");
-
- while (!BLI_heapsimple_is_empty(eq_ctx->q->heap)) {
- BMVert **pair = BLI_heapsimple_pop_min(eq_ctx->q->heap);
- BMVert *v1 = pair[0], *v2 = pair[1];
- BLI_mempool_free(eq_ctx->pool, pair);
- pair = NULL;
-
- /* Check the verts still exist */
- if (!(v1 = bm_vert_hash_lookup_chain(deleted_verts, v1)) ||
- !(v2 = bm_vert_hash_lookup_chain(deleted_verts, v2)) ||
- (v1 == v2))
- {
- continue;
- }
-
- /* Check that the edge still exists */
- BMEdge *e;
- if (!(e = BM_edge_exists(v1, v2))) {
- continue;
- }
+ const float min_len_squared = bvh->bm_min_edge_len * bvh->bm_min_edge_len;
+ bool any_collapsed = false;
+ /* deleted verts point to vertices they were merged into, or NULL when removed. */
+ GHash *deleted_verts = BLI_ghash_ptr_new("deleted_verts");
+
+ while (!BLI_heapsimple_is_empty(eq_ctx->q->heap)) {
+ BMVert **pair = BLI_heapsimple_pop_min(eq_ctx->q->heap);
+ BMVert *v1 = pair[0], *v2 = pair[1];
+ BLI_mempool_free(eq_ctx->pool, pair);
+ pair = NULL;
+
+ /* Check the verts still exist */
+ if (!(v1 = bm_vert_hash_lookup_chain(deleted_verts, v1)) ||
+ !(v2 = bm_vert_hash_lookup_chain(deleted_verts, v2)) || (v1 == v2)) {
+ continue;
+ }
+
+ /* Check that the edge still exists */
+ BMEdge *e;
+ if (!(e = BM_edge_exists(v1, v2))) {
+ continue;
+ }
#ifdef USE_EDGEQUEUE_TAG
- EDGE_QUEUE_DISABLE(e);
+ EDGE_QUEUE_DISABLE(e);
#endif
- if (len_squared_v3v3(v1->co, v2->co) >= min_len_squared)
- continue;
+ if (len_squared_v3v3(v1->co, v2->co) >= min_len_squared)
+ continue;
- /* Check that the edge's vertices are still in the PBVH. It's
- * possible that an edge collapse has deleted adjacent faces
- * and the node has been split, thus leaving wire edges and
- * associated vertices. */
- if ((BM_ELEM_CD_GET_INT(e->v1, eq_ctx->cd_vert_node_offset) == DYNTOPO_NODE_NONE) ||
- (BM_ELEM_CD_GET_INT(e->v2, eq_ctx->cd_vert_node_offset) == DYNTOPO_NODE_NONE))
- {
- continue;
- }
+ /* Check that the edge's vertices are still in the PBVH. It's
+ * possible that an edge collapse has deleted adjacent faces
+ * and the node has been split, thus leaving wire edges and
+ * associated vertices. */
+ if ((BM_ELEM_CD_GET_INT(e->v1, eq_ctx->cd_vert_node_offset) == DYNTOPO_NODE_NONE) ||
+ (BM_ELEM_CD_GET_INT(e->v2, eq_ctx->cd_vert_node_offset) == DYNTOPO_NODE_NONE)) {
+ continue;
+ }
- any_collapsed = true;
+ any_collapsed = true;
- pbvh_bmesh_collapse_edge(bvh, e, v1, v2,
- deleted_verts,
- deleted_faces, eq_ctx);
- }
+ pbvh_bmesh_collapse_edge(bvh, e, v1, v2, deleted_verts, deleted_faces, eq_ctx);
+ }
- BLI_ghash_free(deleted_verts, NULL, NULL);
+ BLI_ghash_free(deleted_verts, NULL, NULL);
- return any_collapsed;
+ return any_collapsed;
}
/************************* Called from pbvh.c *************************/
-bool pbvh_bmesh_node_raycast(
- PBVHNode *node, const float ray_start[3],
- const float ray_normal[3], float *depth,
- bool use_original)
+bool pbvh_bmesh_node_raycast(PBVHNode *node,
+ const float ray_start[3],
+ const float ray_normal[3],
+ float *depth,
+ bool use_original)
{
- bool hit = false;
-
- if (use_original && node->bm_tot_ortri) {
- for (int i = 0; i < node->bm_tot_ortri; i++) {
- const int *t = node->bm_ortri[i];
- hit |= ray_face_intersection_tri(
- ray_start, ray_normal,
- node->bm_orco[t[0]],
- node->bm_orco[t[1]],
- node->bm_orco[t[2]],
- depth);
- }
- }
- else {
- GSetIterator gs_iter;
-
- GSET_ITER (gs_iter, node->bm_faces) {
- BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
-
- BLI_assert(f->len == 3);
- if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
- BMVert *v_tri[3];
-
- BM_face_as_array_vert_tri(f, v_tri);
- hit |= ray_face_intersection_tri(
- ray_start, ray_normal,
- v_tri[0]->co,
- v_tri[1]->co,
- v_tri[2]->co,
- depth);
- }
- }
- }
-
- return hit;
+ bool hit = false;
+
+ if (use_original && node->bm_tot_ortri) {
+ for (int i = 0; i < node->bm_tot_ortri; i++) {
+ const int *t = node->bm_ortri[i];
+ hit |= ray_face_intersection_tri(ray_start,
+ ray_normal,
+ node->bm_orco[t[0]],
+ node->bm_orco[t[1]],
+ node->bm_orco[t[2]],
+ depth);
+ }
+ }
+ else {
+ GSetIterator gs_iter;
+
+ GSET_ITER (gs_iter, node->bm_faces) {
+ BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
+
+ BLI_assert(f->len == 3);
+ if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
+ BMVert *v_tri[3];
+
+ BM_face_as_array_vert_tri(f, v_tri);
+ hit |= ray_face_intersection_tri(
+ ray_start, ray_normal, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co, depth);
+ }
+ }
+ }
+
+ return hit;
}
-bool BKE_pbvh_bmesh_node_raycast_detail(
- PBVHNode *node,
- const float ray_start[3], const float ray_normal[3],
- float *depth, float *r_edge_length)
+bool BKE_pbvh_bmesh_node_raycast_detail(PBVHNode *node,
+ const float ray_start[3],
+ const float ray_normal[3],
+ float *depth,
+ float *r_edge_length)
{
- if (node->flag & PBVH_FullyHidden)
- return 0;
-
- GSetIterator gs_iter;
- bool hit = false;
- BMFace *f_hit = NULL;
-
- GSET_ITER (gs_iter, node->bm_faces) {
- BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
-
- BLI_assert(f->len == 3);
- if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
- BMVert *v_tri[3];
- bool hit_local;
- BM_face_as_array_vert_tri(f, v_tri);
- hit_local = ray_face_intersection_tri(
- ray_start, ray_normal,
- v_tri[0]->co,
- v_tri[1]->co,
- v_tri[2]->co,
- depth);
-
- if (hit_local) {
- f_hit = f;
- hit = true;
- }
- }
- }
-
- if (hit) {
- BMVert *v_tri[3];
- BM_face_as_array_vert_tri(f_hit, v_tri);
- float len1 = len_squared_v3v3(v_tri[0]->co, v_tri[1]->co);
- float len2 = len_squared_v3v3(v_tri[1]->co, v_tri[2]->co);
- float len3 = len_squared_v3v3(v_tri[2]->co, v_tri[0]->co);
-
- /* detail returned will be set to the maximum allowed size, so take max here */
- *r_edge_length = sqrtf(max_fff(len1, len2, len3));
- }
-
- return hit;
+ if (node->flag & PBVH_FullyHidden)
+ return 0;
+
+ GSetIterator gs_iter;
+ bool hit = false;
+ BMFace *f_hit = NULL;
+
+ GSET_ITER (gs_iter, node->bm_faces) {
+ BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
+
+ BLI_assert(f->len == 3);
+ if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
+ BMVert *v_tri[3];
+ bool hit_local;
+ BM_face_as_array_vert_tri(f, v_tri);
+ hit_local = ray_face_intersection_tri(
+ ray_start, ray_normal, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co, depth);
+
+ if (hit_local) {
+ f_hit = f;
+ hit = true;
+ }
+ }
+ }
+
+ if (hit) {
+ BMVert *v_tri[3];
+ BM_face_as_array_vert_tri(f_hit, v_tri);
+ float len1 = len_squared_v3v3(v_tri[0]->co, v_tri[1]->co);
+ float len2 = len_squared_v3v3(v_tri[1]->co, v_tri[2]->co);
+ float len3 = len_squared_v3v3(v_tri[2]->co, v_tri[0]->co);
+
+ /* detail returned will be set to the maximum allowed size, so take max here */
+ *r_edge_length = sqrtf(max_fff(len1, len2, len3));
+ }
+
+ return hit;
}
-bool pbvh_bmesh_node_nearest_to_ray(
- PBVHNode *node, const float ray_start[3],
- const float ray_normal[3], float *depth, float *dist_sq,
- bool use_original)
+bool pbvh_bmesh_node_nearest_to_ray(PBVHNode *node,
+ const float ray_start[3],
+ const float ray_normal[3],
+ float *depth,
+ float *dist_sq,
+ bool use_original)
{
- bool hit = false;
-
- if (use_original && node->bm_tot_ortri) {
- for (int i = 0; i < node->bm_tot_ortri; i++) {
- const int *t = node->bm_ortri[i];
- hit |= ray_face_nearest_tri(
- ray_start, ray_normal,
- node->bm_orco[t[0]],
- node->bm_orco[t[1]],
- node->bm_orco[t[2]],
- depth, dist_sq);
- }
- }
- else {
- GSetIterator gs_iter;
-
- GSET_ITER (gs_iter, node->bm_faces) {
- BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
-
- BLI_assert(f->len == 3);
- if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
- BMVert *v_tri[3];
-
- BM_face_as_array_vert_tri(f, v_tri);
- hit |= ray_face_nearest_tri(
- ray_start, ray_normal,
- v_tri[0]->co,
- v_tri[1]->co,
- v_tri[2]->co,
- depth, dist_sq);
- }
- }
- }
-
- return hit;
+ bool hit = false;
+
+ if (use_original && node->bm_tot_ortri) {
+ for (int i = 0; i < node->bm_tot_ortri; i++) {
+ const int *t = node->bm_ortri[i];
+ hit |= ray_face_nearest_tri(ray_start,
+ ray_normal,
+ node->bm_orco[t[0]],
+ node->bm_orco[t[1]],
+ node->bm_orco[t[2]],
+ depth,
+ dist_sq);
+ }
+ }
+ else {
+ GSetIterator gs_iter;
+
+ GSET_ITER (gs_iter, node->bm_faces) {
+ BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
+
+ BLI_assert(f->len == 3);
+ if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
+ BMVert *v_tri[3];
+
+ BM_face_as_array_vert_tri(f, v_tri);
+ hit |= ray_face_nearest_tri(
+ ray_start, ray_normal, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co, depth, dist_sq);
+ }
+ }
+ }
+
+ return hit;
}
void pbvh_bmesh_normals_update(PBVHNode **nodes, int totnode)
{
- for (int n = 0; n < totnode; n++) {
- PBVHNode *node = nodes[n];
-
- if (node->flag & PBVH_UpdateNormals) {
- GSetIterator gs_iter;
-
- GSET_ITER (gs_iter, node->bm_faces) {
- BM_face_normal_update(BLI_gsetIterator_getKey(&gs_iter));
- }
- GSET_ITER (gs_iter, node->bm_unique_verts) {
- BM_vert_normal_update(BLI_gsetIterator_getKey(&gs_iter));
- }
- /* This should be unneeded normally */
- GSET_ITER (gs_iter, node->bm_other_verts) {
- BM_vert_normal_update(BLI_gsetIterator_getKey(&gs_iter));
- }
- node->flag &= ~PBVH_UpdateNormals;
- }
- }
+ for (int n = 0; n < totnode; n++) {
+ PBVHNode *node = nodes[n];
+
+ if (node->flag & PBVH_UpdateNormals) {
+ GSetIterator gs_iter;
+
+ GSET_ITER (gs_iter, node->bm_faces) {
+ BM_face_normal_update(BLI_gsetIterator_getKey(&gs_iter));
+ }
+ GSET_ITER (gs_iter, node->bm_unique_verts) {
+ BM_vert_normal_update(BLI_gsetIterator_getKey(&gs_iter));
+ }
+ /* This should be unneeded normally */
+ GSET_ITER (gs_iter, node->bm_other_verts) {
+ BM_vert_normal_update(BLI_gsetIterator_getKey(&gs_iter));
+ }
+ node->flag &= ~PBVH_UpdateNormals;
+ }
+ }
}
struct FastNodeBuildInfo {
- int totface; /* number of faces */
- int start; /* start of faces in array */
- struct FastNodeBuildInfo *child1;
- struct FastNodeBuildInfo *child2;
+ int totface; /* number of faces */
+ int start; /* start of faces in array */
+ struct FastNodeBuildInfo *child1;
+ struct FastNodeBuildInfo *child2;
};
/**
@@ -1668,432 +1658,440 @@ struct FastNodeBuildInfo {
* to a sub part of the arrays
*/
static void pbvh_bmesh_node_limit_ensure_fast(
- PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, struct FastNodeBuildInfo *node,
- MemArena *arena)
+ PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, struct FastNodeBuildInfo *node, MemArena *arena)
{
- struct FastNodeBuildInfo *child1, *child2;
-
- if (node->totface <= bvh->leaf_limit) {
- return;
- }
-
- /* Calculate bounding box around primitive centroids */
- BB cb;
- BB_reset(&cb);
- for (int i = 0; i < node->totface; i++) {
- BMFace *f = nodeinfo[i + node->start];
- BBC *bbc = &bbc_array[BM_elem_index_get(f)];
-
- BB_expand(&cb, bbc->bcentroid);
- }
-
- /* initialize the children */
-
- /* Find widest axis and its midpoint */
- const int axis = BB_widest_axis(&cb);
- const float mid = (cb.bmax[axis] + cb.bmin[axis]) * 0.5f;
-
- int num_child1 = 0, num_child2 = 0;
-
- /* split vertices along the middle line */
- const int end = node->start + node->totface;
- for (int i = node->start; i < end - num_child2; i++) {
- BMFace *f = nodeinfo[i];
- BBC *bbc = &bbc_array[BM_elem_index_get(f)];
-
- if (bbc->bcentroid[axis] > mid) {
- int i_iter = end - num_child2 - 1;
- int candidate = -1;
- /* found a face that should be part of another node, look for a face to substitute with */
-
- for (;i_iter > i; i_iter--) {
- BMFace *f_iter = nodeinfo[i_iter];
- const BBC *bbc_iter = &bbc_array[BM_elem_index_get(f_iter)];
- if (bbc_iter->bcentroid[axis] <= mid) {
- candidate = i_iter;
- break;
- }
- else {
- num_child2++;
- }
- }
-
- if (candidate != -1) {
- BMFace *tmp = nodeinfo[i];
- nodeinfo[i] = nodeinfo[candidate];
- nodeinfo[candidate] = tmp;
- /* increase both counts */
- num_child1++;
- num_child2++;
- }
- else {
- /* not finding candidate means second half of array part is full of
- * second node parts, just increase the number of child nodes for it */
- num_child2++;
- }
- }
- else {
- num_child1++;
- }
- }
-
- /* ensure at least one child in each node */
- if (num_child2 == 0) {
- num_child2++;
- num_child1--;
- }
- else if (num_child1 == 0) {
- num_child1++;
- num_child2--;
- }
-
- /* at this point, faces should have been split along the array range sequentially,
- * each sequential part belonging to one node only */
- BLI_assert((num_child1 + num_child2) == node->totface);
-
- node->child1 = child1 = BLI_memarena_alloc(arena, sizeof(struct FastNodeBuildInfo));
- node->child2 = child2 = BLI_memarena_alloc(arena, sizeof(struct FastNodeBuildInfo));
-
- child1->totface = num_child1;
- child1->start = node->start;
- child2->totface = num_child2;
- child2->start = node->start + num_child1;
- child1->child1 = child1->child2 = child2->child1 = child2->child2 = NULL;
-
- pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, child1, arena);
- pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, child2, arena);
+ struct FastNodeBuildInfo *child1, *child2;
+
+ if (node->totface <= bvh->leaf_limit) {
+ return;
+ }
+
+ /* Calculate bounding box around primitive centroids */
+ BB cb;
+ BB_reset(&cb);
+ for (int i = 0; i < node->totface; i++) {
+ BMFace *f = nodeinfo[i + node->start];
+ BBC *bbc = &bbc_array[BM_elem_index_get(f)];
+
+ BB_expand(&cb, bbc->bcentroid);
+ }
+
+ /* initialize the children */
+
+ /* Find widest axis and its midpoint */
+ const int axis = BB_widest_axis(&cb);
+ const float mid = (cb.bmax[axis] + cb.bmin[axis]) * 0.5f;
+
+ int num_child1 = 0, num_child2 = 0;
+
+ /* split vertices along the middle line */
+ const int end = node->start + node->totface;
+ for (int i = node->start; i < end - num_child2; i++) {
+ BMFace *f = nodeinfo[i];
+ BBC *bbc = &bbc_array[BM_elem_index_get(f)];
+
+ if (bbc->bcentroid[axis] > mid) {
+ int i_iter = end - num_child2 - 1;
+ int candidate = -1;
+ /* found a face that should be part of another node, look for a face to substitute with */
+
+ for (; i_iter > i; i_iter--) {
+ BMFace *f_iter = nodeinfo[i_iter];
+ const BBC *bbc_iter = &bbc_array[BM_elem_index_get(f_iter)];
+ if (bbc_iter->bcentroid[axis] <= mid) {
+ candidate = i_iter;
+ break;
+ }
+ else {
+ num_child2++;
+ }
+ }
+
+ if (candidate != -1) {
+ BMFace *tmp = nodeinfo[i];
+ nodeinfo[i] = nodeinfo[candidate];
+ nodeinfo[candidate] = tmp;
+ /* increase both counts */
+ num_child1++;
+ num_child2++;
+ }
+ else {
+ /* not finding candidate means second half of array part is full of
+ * second node parts, just increase the number of child nodes for it */
+ num_child2++;
+ }
+ }
+ else {
+ num_child1++;
+ }
+ }
+
+ /* ensure at least one child in each node */
+ if (num_child2 == 0) {
+ num_child2++;
+ num_child1--;
+ }
+ else if (num_child1 == 0) {
+ num_child1++;
+ num_child2--;
+ }
+
+ /* at this point, faces should have been split along the array range sequentially,
+ * each sequential part belonging to one node only */
+ BLI_assert((num_child1 + num_child2) == node->totface);
+
+ node->child1 = child1 = BLI_memarena_alloc(arena, sizeof(struct FastNodeBuildInfo));
+ node->child2 = child2 = BLI_memarena_alloc(arena, sizeof(struct FastNodeBuildInfo));
+
+ child1->totface = num_child1;
+ child1->start = node->start;
+ child2->totface = num_child2;
+ child2->start = node->start + num_child1;
+ child1->child1 = child1->child2 = child2->child1 = child2->child2 = NULL;
+
+ pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, child1, arena);
+ pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, child2, arena);
}
static void pbvh_bmesh_create_nodes_fast_recursive(
- PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array,
- struct FastNodeBuildInfo *node, int node_index)
+ PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, struct FastNodeBuildInfo *node, int node_index)
{
- PBVHNode *n = bvh->nodes + node_index;
- /* two cases, node does not have children or does have children */
- if (node->child1) {
- int children_offset = bvh->totnode;
-
- n->children_offset = children_offset;
- pbvh_grow_nodes(bvh, bvh->totnode + 2);
- pbvh_bmesh_create_nodes_fast_recursive(bvh, nodeinfo, bbc_array, node->child1, children_offset);
- pbvh_bmesh_create_nodes_fast_recursive(bvh, nodeinfo, bbc_array, node->child2, children_offset + 1);
-
- n = &bvh->nodes[node_index];
-
- /* Update bounding box */
- BB_reset(&n->vb);
- BB_expand_with_bb(&n->vb, &bvh->nodes[n->children_offset].vb);
- BB_expand_with_bb(&n->vb, &bvh->nodes[n->children_offset + 1].vb);
- n->orig_vb = n->vb;
- }
- else {
- /* node does not have children so it's a leaf node, populate with faces and tag accordingly
- * this is an expensive part but it's not so easily threadable due to vertex node indices */
- const int cd_vert_node_offset = bvh->cd_vert_node_offset;
- const int cd_face_node_offset = bvh->cd_face_node_offset;
-
- bool has_visible = false;
-
- n->flag = PBVH_Leaf;
- n->bm_faces = BLI_gset_ptr_new_ex("bm_faces", node->totface);
-
- /* Create vert hash sets */
- n->bm_unique_verts = BLI_gset_ptr_new("bm_unique_verts");
- n->bm_other_verts = BLI_gset_ptr_new("bm_other_verts");
-
- BB_reset(&n->vb);
-
- const int end = node->start + node->totface;
-
- for (int i = node->start; i < end; i++) {
- BMFace *f = nodeinfo[i];
- BBC *bbc = &bbc_array[BM_elem_index_get(f)];
-
- /* Update ownership of faces */
- BLI_gset_insert(n->bm_faces, f);
- BM_ELEM_CD_SET_INT(f, cd_face_node_offset, node_index);
-
- /* Update vertices */
- BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
- BMLoop *l_iter = l_first;
- do {
- BMVert *v = l_iter->v;
- if (!BLI_gset_haskey(n->bm_unique_verts, v)) {
- if (BM_ELEM_CD_GET_INT(v, cd_vert_node_offset) != DYNTOPO_NODE_NONE) {
- BLI_gset_add(n->bm_other_verts, v);
- }
- else {
- BLI_gset_insert(n->bm_unique_verts, v);
- BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, node_index);
- }
- }
- /* Update node bounding box */
- } while ((l_iter = l_iter->next) != l_first);
-
- if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN))
- has_visible = true;
-
- BB_expand_with_bb(&n->vb, (BB *)bbc);
- }
-
- BLI_assert(n->vb.bmin[0] <= n->vb.bmax[0] &&
- n->vb.bmin[1] <= n->vb.bmax[1] &&
- n->vb.bmin[2] <= n->vb.bmax[2]);
-
- n->orig_vb = n->vb;
-
- /* Build GPU buffers for new node and update vertex normals */
- BKE_pbvh_node_mark_rebuild_draw(n);
-
- BKE_pbvh_node_fully_hidden_set(n, !has_visible);
- n->flag |= PBVH_UpdateNormals;
- }
+ PBVHNode *n = bvh->nodes + node_index;
+ /* two cases, node does not have children or does have children */
+ if (node->child1) {
+ int children_offset = bvh->totnode;
+
+ n->children_offset = children_offset;
+ pbvh_grow_nodes(bvh, bvh->totnode + 2);
+ pbvh_bmesh_create_nodes_fast_recursive(
+ bvh, nodeinfo, bbc_array, node->child1, children_offset);
+ pbvh_bmesh_create_nodes_fast_recursive(
+ bvh, nodeinfo, bbc_array, node->child2, children_offset + 1);
+
+ n = &bvh->nodes[node_index];
+
+ /* Update bounding box */
+ BB_reset(&n->vb);
+ BB_expand_with_bb(&n->vb, &bvh->nodes[n->children_offset].vb);
+ BB_expand_with_bb(&n->vb, &bvh->nodes[n->children_offset + 1].vb);
+ n->orig_vb = n->vb;
+ }
+ else {
+ /* node does not have children so it's a leaf node, populate with faces and tag accordingly
+ * this is an expensive part but it's not so easily threadable due to vertex node indices */
+ const int cd_vert_node_offset = bvh->cd_vert_node_offset;
+ const int cd_face_node_offset = bvh->cd_face_node_offset;
+
+ bool has_visible = false;
+
+ n->flag = PBVH_Leaf;
+ n->bm_faces = BLI_gset_ptr_new_ex("bm_faces", node->totface);
+
+ /* Create vert hash sets */
+ n->bm_unique_verts = BLI_gset_ptr_new("bm_unique_verts");
+ n->bm_other_verts = BLI_gset_ptr_new("bm_other_verts");
+
+ BB_reset(&n->vb);
+
+ const int end = node->start + node->totface;
+
+ for (int i = node->start; i < end; i++) {
+ BMFace *f = nodeinfo[i];
+ BBC *bbc = &bbc_array[BM_elem_index_get(f)];
+
+ /* Update ownership of faces */
+ BLI_gset_insert(n->bm_faces, f);
+ BM_ELEM_CD_SET_INT(f, cd_face_node_offset, node_index);
+
+ /* Update vertices */
+ BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
+ BMLoop *l_iter = l_first;
+ do {
+ BMVert *v = l_iter->v;
+ if (!BLI_gset_haskey(n->bm_unique_verts, v)) {
+ if (BM_ELEM_CD_GET_INT(v, cd_vert_node_offset) != DYNTOPO_NODE_NONE) {
+ BLI_gset_add(n->bm_other_verts, v);
+ }
+ else {
+ BLI_gset_insert(n->bm_unique_verts, v);
+ BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, node_index);
+ }
+ }
+ /* Update node bounding box */
+ } while ((l_iter = l_iter->next) != l_first);
+
+ if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN))
+ has_visible = true;
+
+ BB_expand_with_bb(&n->vb, (BB *)bbc);
+ }
+
+ BLI_assert(n->vb.bmin[0] <= n->vb.bmax[0] && n->vb.bmin[1] <= n->vb.bmax[1] &&
+ n->vb.bmin[2] <= n->vb.bmax[2]);
+
+ n->orig_vb = n->vb;
+
+ /* Build GPU buffers for new node and update vertex normals */
+ BKE_pbvh_node_mark_rebuild_draw(n);
+
+ BKE_pbvh_node_fully_hidden_set(n, !has_visible);
+ n->flag |= PBVH_UpdateNormals;
+ }
}
-
/***************************** Public API *****************************/
/* Build a PBVH from a BMesh */
-void BKE_pbvh_build_bmesh(
- PBVH *bvh, BMesh *bm, bool smooth_shading, BMLog *log,
- const int cd_vert_node_offset, const int cd_face_node_offset)
+void BKE_pbvh_build_bmesh(PBVH *bvh,
+ BMesh *bm,
+ bool smooth_shading,
+ BMLog *log,
+ const int cd_vert_node_offset,
+ const int cd_face_node_offset)
{
- bvh->cd_vert_node_offset = cd_vert_node_offset;
- bvh->cd_face_node_offset = cd_face_node_offset;
- bvh->bm = bm;
+ bvh->cd_vert_node_offset = cd_vert_node_offset;
+ bvh->cd_face_node_offset = cd_face_node_offset;
+ bvh->bm = bm;
- BKE_pbvh_bmesh_detail_size_set(bvh, 0.75);
+ BKE_pbvh_bmesh_detail_size_set(bvh, 0.75);
- bvh->type = PBVH_BMESH;
- bvh->bm_log = log;
+ bvh->type = PBVH_BMESH;
+ bvh->bm_log = log;
- /* TODO: choose leaf limit better */
- bvh->leaf_limit = 100;
+ /* TODO: choose leaf limit better */
+ bvh->leaf_limit = 100;
- if (smooth_shading)
- bvh->flags |= PBVH_DYNTOPO_SMOOTH_SHADING;
+ if (smooth_shading)
+ bvh->flags |= PBVH_DYNTOPO_SMOOTH_SHADING;
- /* bounding box array of all faces, no need to recalculate every time */
- BBC *bbc_array = MEM_mallocN(sizeof(BBC) * bm->totface, "BBC");
- BMFace **nodeinfo = MEM_mallocN(sizeof(*nodeinfo) * bm->totface, "nodeinfo");
- MemArena *arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "fast PBVH node storage");
+ /* bounding box array of all faces, no need to recalculate every time */
+ BBC *bbc_array = MEM_mallocN(sizeof(BBC) * bm->totface, "BBC");
+ BMFace **nodeinfo = MEM_mallocN(sizeof(*nodeinfo) * bm->totface, "nodeinfo");
+ MemArena *arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "fast PBVH node storage");
- BMIter iter;
- BMFace *f;
- int i;
- BM_ITER_MESH_INDEX(f, &iter, bm, BM_FACES_OF_MESH, i) {
- BBC *bbc = &bbc_array[i];
- BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
- BMLoop *l_iter = l_first;
+ BMIter iter;
+ BMFace *f;
+ int i;
+ BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, i) {
+ BBC *bbc = &bbc_array[i];
+ BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
+ BMLoop *l_iter = l_first;
- BB_reset((BB *)bbc);
- do {
- BB_expand((BB *)bbc, l_iter->v->co);
- } while ((l_iter = l_iter->next) != l_first);
- BBC_update_centroid(bbc);
+ BB_reset((BB *)bbc);
+ do {
+ BB_expand((BB *)bbc, l_iter->v->co);
+ } while ((l_iter = l_iter->next) != l_first);
+ BBC_update_centroid(bbc);
- /* so we can do direct lookups on 'bbc_array' */
- BM_elem_index_set(f, i); /* set_dirty! */
- nodeinfo[i] = f;
- BM_ELEM_CD_SET_INT(f, cd_face_node_offset, DYNTOPO_NODE_NONE);
- }
+ /* so we can do direct lookups on 'bbc_array' */
+ BM_elem_index_set(f, i); /* set_dirty! */
+ nodeinfo[i] = f;
+ BM_ELEM_CD_SET_INT(f, cd_face_node_offset, DYNTOPO_NODE_NONE);
+ }
- BMVert *v;
- BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) {
- BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, DYNTOPO_NODE_NONE);
- }
+ BMVert *v;
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, DYNTOPO_NODE_NONE);
+ }
- /* likely this is already dirty */
- bm->elem_index_dirty |= BM_FACE;
+ /* likely this is already dirty */
+ bm->elem_index_dirty |= BM_FACE;
- /* setup root node */
- struct FastNodeBuildInfo rootnode = {0};
- rootnode.totface = bm->totface;
+ /* setup root node */
+ struct FastNodeBuildInfo rootnode = {0};
+ rootnode.totface = bm->totface;
- /* start recursion, assign faces to nodes accordingly */
- pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, &rootnode, arena);
+ /* start recursion, assign faces to nodes accordingly */
+ pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, &rootnode, arena);
- /* we now have all faces assigned to a node, next we need to assign those to the gsets of the nodes */
+ /* we now have all faces assigned to a node, next we need to assign those to the gsets of the nodes */
- /* Start with all faces in the root node */
- bvh->nodes = MEM_callocN(sizeof(PBVHNode), "PBVHNode");
- bvh->totnode = 1;
+ /* Start with all faces in the root node */
+ bvh->nodes = MEM_callocN(sizeof(PBVHNode), "PBVHNode");
+ bvh->totnode = 1;
- /* take root node and visit and populate children recursively */
- pbvh_bmesh_create_nodes_fast_recursive(bvh, nodeinfo, bbc_array, &rootnode, 0);
+ /* take root node and visit and populate children recursively */
+ pbvh_bmesh_create_nodes_fast_recursive(bvh, nodeinfo, bbc_array, &rootnode, 0);
- BLI_memarena_free(arena);
- MEM_freeN(bbc_array);
- MEM_freeN(nodeinfo);
+ BLI_memarena_free(arena);
+ MEM_freeN(bbc_array);
+ MEM_freeN(nodeinfo);
}
/* Collapse short edges, subdivide long edges */
-bool BKE_pbvh_bmesh_update_topology(
- PBVH *bvh, PBVHTopologyUpdateMode mode,
- const float center[3], const float view_normal[3],
- float radius, const bool use_frontface, const bool use_projected)
+bool BKE_pbvh_bmesh_update_topology(PBVH *bvh,
+ PBVHTopologyUpdateMode mode,
+ const float center[3],
+ const float view_normal[3],
+ float radius,
+ const bool use_frontface,
+ const bool use_projected)
{
- /* 2 is enough for edge faces - manifold edge */
- BLI_buffer_declare_static(BMLoop *, edge_loops, BLI_BUFFER_NOP, 2);
- BLI_buffer_declare_static(BMFace *, deleted_faces, BLI_BUFFER_NOP, 32);
- const int cd_vert_mask_offset = CustomData_get_offset(&bvh->bm->vdata, CD_PAINT_MASK);
- const int cd_vert_node_offset = bvh->cd_vert_node_offset;
- const int cd_face_node_offset = bvh->cd_face_node_offset;
-
- bool modified = false;
-
- if (view_normal) {
- BLI_assert(len_squared_v3(view_normal) != 0.0f);
- }
-
- if (mode & PBVH_Collapse) {
- EdgeQueue q;
- BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert *[2]), 0, 128, BLI_MEMPOOL_NOP);
- EdgeQueueContext eq_ctx = {
- &q, queue_pool, bvh->bm,
- cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset,
- };
-
- short_edge_queue_create(&eq_ctx, bvh, center, view_normal, radius, use_frontface, use_projected);
- modified |= pbvh_bmesh_collapse_short_edges(
- &eq_ctx, bvh, &deleted_faces);
- BLI_heapsimple_free(q.heap, NULL);
- BLI_mempool_destroy(queue_pool);
- }
-
- if (mode & PBVH_Subdivide) {
- EdgeQueue q;
- BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert *[2]), 0, 128, BLI_MEMPOOL_NOP);
- EdgeQueueContext eq_ctx = {
- &q, queue_pool, bvh->bm,
- cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset,
- };
-
- long_edge_queue_create(&eq_ctx, bvh, center, view_normal, radius, use_frontface, use_projected);
- modified |= pbvh_bmesh_subdivide_long_edges(
- &eq_ctx, bvh, &edge_loops);
- BLI_heapsimple_free(q.heap, NULL);
- BLI_mempool_destroy(queue_pool);
- }
-
- /* Unmark nodes */
- for (int n = 0; n < bvh->totnode; n++) {
- PBVHNode *node = &bvh->nodes[n];
-
- if (node->flag & PBVH_Leaf &&
- node->flag & PBVH_UpdateTopology)
- {
- node->flag &= ~PBVH_UpdateTopology;
- }
- }
- BLI_buffer_free(&edge_loops);
- BLI_buffer_free(&deleted_faces);
+ /* 2 is enough for edge faces - manifold edge */
+ BLI_buffer_declare_static(BMLoop *, edge_loops, BLI_BUFFER_NOP, 2);
+ BLI_buffer_declare_static(BMFace *, deleted_faces, BLI_BUFFER_NOP, 32);
+ const int cd_vert_mask_offset = CustomData_get_offset(&bvh->bm->vdata, CD_PAINT_MASK);
+ const int cd_vert_node_offset = bvh->cd_vert_node_offset;
+ const int cd_face_node_offset = bvh->cd_face_node_offset;
+
+ bool modified = false;
+
+ if (view_normal) {
+ BLI_assert(len_squared_v3(view_normal) != 0.0f);
+ }
+
+ if (mode & PBVH_Collapse) {
+ EdgeQueue q;
+ BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert * [2]), 0, 128, BLI_MEMPOOL_NOP);
+ EdgeQueueContext eq_ctx = {
+ &q,
+ queue_pool,
+ bvh->bm,
+ cd_vert_mask_offset,
+ cd_vert_node_offset,
+ cd_face_node_offset,
+ };
+
+ short_edge_queue_create(
+ &eq_ctx, bvh, center, view_normal, radius, use_frontface, use_projected);
+ modified |= pbvh_bmesh_collapse_short_edges(&eq_ctx, bvh, &deleted_faces);
+ BLI_heapsimple_free(q.heap, NULL);
+ BLI_mempool_destroy(queue_pool);
+ }
+
+ if (mode & PBVH_Subdivide) {
+ EdgeQueue q;
+ BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert * [2]), 0, 128, BLI_MEMPOOL_NOP);
+ EdgeQueueContext eq_ctx = {
+ &q,
+ queue_pool,
+ bvh->bm,
+ cd_vert_mask_offset,
+ cd_vert_node_offset,
+ cd_face_node_offset,
+ };
+
+ long_edge_queue_create(
+ &eq_ctx, bvh, center, view_normal, radius, use_frontface, use_projected);
+ modified |= pbvh_bmesh_subdivide_long_edges(&eq_ctx, bvh, &edge_loops);
+ BLI_heapsimple_free(q.heap, NULL);
+ BLI_mempool_destroy(queue_pool);
+ }
+
+ /* Unmark nodes */
+ for (int n = 0; n < bvh->totnode; n++) {
+ PBVHNode *node = &bvh->nodes[n];
+
+ if (node->flag & PBVH_Leaf && node->flag & PBVH_UpdateTopology) {
+ node->flag &= ~PBVH_UpdateTopology;
+ }
+ }
+ BLI_buffer_free(&edge_loops);
+ BLI_buffer_free(&deleted_faces);
#ifdef USE_VERIFY
- pbvh_bmesh_verify(bvh);
+ pbvh_bmesh_verify(bvh);
#endif
- return modified;
+ return modified;
}
-
/* In order to perform operations on the original node coordinates
* (currently just raycast), store the node's triangles and vertices.
*
* Skips triangles that are hidden. */
void BKE_pbvh_bmesh_node_save_orig(PBVHNode *node)
{
- /* Skip if original coords/triangles are already saved */
- if (node->bm_orco)
- return;
-
- const int totvert = BLI_gset_len(node->bm_unique_verts) +
- BLI_gset_len(node->bm_other_verts);
-
- const int tottri = BLI_gset_len(node->bm_faces);
-
- node->bm_orco = MEM_mallocN(sizeof(*node->bm_orco) * totvert, __func__);
- node->bm_ortri = MEM_mallocN(sizeof(*node->bm_ortri) * tottri, __func__);
-
- /* Copy out the vertices and assign a temporary index */
- int i = 0;
- GSetIterator gs_iter;
- GSET_ITER (gs_iter, node->bm_unique_verts) {
- BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
- copy_v3_v3(node->bm_orco[i], v->co);
- BM_elem_index_set(v, i); /* set_dirty! */
- i++;
- }
- GSET_ITER (gs_iter, node->bm_other_verts) {
- BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
- copy_v3_v3(node->bm_orco[i], v->co);
- BM_elem_index_set(v, i); /* set_dirty! */
- i++;
- }
-
- /* Copy the triangles */
- i = 0;
- GSET_ITER (gs_iter, node->bm_faces) {
- BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
-
- if (BM_elem_flag_test(f, BM_ELEM_HIDDEN))
- continue;
+ /* Skip if original coords/triangles are already saved */
+ if (node->bm_orco)
+ return;
+
+ const int totvert = BLI_gset_len(node->bm_unique_verts) + BLI_gset_len(node->bm_other_verts);
+
+ const int tottri = BLI_gset_len(node->bm_faces);
+
+ node->bm_orco = MEM_mallocN(sizeof(*node->bm_orco) * totvert, __func__);
+ node->bm_ortri = MEM_mallocN(sizeof(*node->bm_ortri) * tottri, __func__);
+
+ /* Copy out the vertices and assign a temporary index */
+ int i = 0;
+ GSetIterator gs_iter;
+ GSET_ITER (gs_iter, node->bm_unique_verts) {
+ BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
+ copy_v3_v3(node->bm_orco[i], v->co);
+ BM_elem_index_set(v, i); /* set_dirty! */
+ i++;
+ }
+ GSET_ITER (gs_iter, node->bm_other_verts) {
+ BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
+ copy_v3_v3(node->bm_orco[i], v->co);
+ BM_elem_index_set(v, i); /* set_dirty! */
+ i++;
+ }
+
+ /* Copy the triangles */
+ i = 0;
+ GSET_ITER (gs_iter, node->bm_faces) {
+ BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
+
+ if (BM_elem_flag_test(f, BM_ELEM_HIDDEN))
+ continue;
#if 0
- BMIter bm_iter;
- BMVert *v;
- int j = 0;
- BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) {
- node->bm_ortri[i][j] = BM_elem_index_get(v);
- j++;
- }
+ BMIter bm_iter;
+ BMVert *v;
+ int j = 0;
+ BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) {
+ node->bm_ortri[i][j] = BM_elem_index_get(v);
+ j++;
+ }
#else
- bm_face_as_array_index_tri(f, node->bm_ortri[i]);
+ bm_face_as_array_index_tri(f, node->bm_ortri[i]);
#endif
- i++;
- }
- node->bm_tot_ortri = i;
+ i++;
+ }
+ node->bm_tot_ortri = i;
}
void BKE_pbvh_bmesh_after_stroke(PBVH *bvh)
{
- for (int i = 0; i < bvh->totnode; i++) {
- PBVHNode *n = &bvh->nodes[i];
- if (n->flag & PBVH_Leaf) {
- /* Free orco/ortri data */
- pbvh_bmesh_node_drop_orig(n);
-
- /* Recursively split nodes that have gotten too many
- * elements */
- pbvh_bmesh_node_limit_ensure(bvh, i);
- }
- }
+ for (int i = 0; i < bvh->totnode; i++) {
+ PBVHNode *n = &bvh->nodes[i];
+ if (n->flag & PBVH_Leaf) {
+ /* Free orco/ortri data */
+ pbvh_bmesh_node_drop_orig(n);
+
+ /* Recursively split nodes that have gotten too many
+ * elements */
+ pbvh_bmesh_node_limit_ensure(bvh, i);
+ }
+ }
}
void BKE_pbvh_bmesh_detail_size_set(PBVH *bvh, float detail_size)
{
- bvh->bm_max_edge_len = detail_size;
- bvh->bm_min_edge_len = bvh->bm_max_edge_len * 0.4f;
+ bvh->bm_max_edge_len = detail_size;
+ bvh->bm_min_edge_len = bvh->bm_max_edge_len * 0.4f;
}
void BKE_pbvh_node_mark_topology_update(PBVHNode *node)
{
- node->flag |= PBVH_UpdateTopology;
+ node->flag |= PBVH_UpdateTopology;
}
GSet *BKE_pbvh_bmesh_node_unique_verts(PBVHNode *node)
{
- return node->bm_unique_verts;
+ return node->bm_unique_verts;
}
GSet *BKE_pbvh_bmesh_node_other_verts(PBVHNode *node)
{
- return node->bm_other_verts;
+ return node->bm_other_verts;
}
struct GSet *BKE_pbvh_bmesh_node_faces(PBVHNode *node)
{
- return node->bm_faces;
+ return node->bm_faces;
}
/****************************** Debugging *****************************/
@@ -2102,226 +2100,224 @@ struct GSet *BKE_pbvh_bmesh_node_faces(PBVHNode *node)
static void pbvh_bmesh_print(PBVH *bvh)
{
- fprintf(stderr, "\npbvh=%p\n", bvh);
- fprintf(stderr, "bm_face_to_node:\n");
-
- BMIter iter;
- BMFace *f;
- BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) {
- fprintf(stderr, " %d -> %d\n",
- BM_elem_index_get(f),
- pbvh_bmesh_node_index_from_face(bvh, f));
- }
-
- fprintf(stderr, "bm_vert_to_node:\n");
- BMVert *v;
- BM_ITER_MESH(v, &iter, bvh->bm, BM_FACES_OF_MESH) {
- fprintf(stderr, " %d -> %d\n",
- BM_elem_index_get(v),
- pbvh_bmesh_node_index_from_vert(bvh, v));
- }
-
- for (int n = 0; n < bvh->totnode; n++) {
- PBVHNode *node = &bvh->nodes[n];
- if (!(node->flag & PBVH_Leaf))
- continue;
-
- GSetIterator gs_iter;
- fprintf(stderr, "node %d\n faces:\n", n);
- GSET_ITER (gs_iter, node->bm_faces)
- fprintf(stderr, " %d\n",
- BM_elem_index_get((BMFace *)BLI_gsetIterator_getKey(&gs_iter)));
- fprintf(stderr, " unique verts:\n");
- GSET_ITER (gs_iter, node->bm_unique_verts)
- fprintf(stderr, " %d\n",
- BM_elem_index_get((BMVert *)BLI_gsetIterator_getKey(&gs_iter)));
- fprintf(stderr, " other verts:\n");
- GSET_ITER (gs_iter, node->bm_other_verts)
- fprintf(stderr, " %d\n",
- BM_elem_index_get((BMVert *)BLI_gsetIterator_getKey(&gs_iter)));
- }
+ fprintf(stderr, "\npbvh=%p\n", bvh);
+ fprintf(stderr, "bm_face_to_node:\n");
+
+ BMIter iter;
+ BMFace *f;
+ BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) {
+ fprintf(stderr, " %d -> %d\n",
+ BM_elem_index_get(f),
+ pbvh_bmesh_node_index_from_face(bvh, f));
+ }
+
+ fprintf(stderr, "bm_vert_to_node:\n");
+ BMVert *v;
+ BM_ITER_MESH(v, &iter, bvh->bm, BM_FACES_OF_MESH) {
+ fprintf(stderr, " %d -> %d\n",
+ BM_elem_index_get(v),
+ pbvh_bmesh_node_index_from_vert(bvh, v));
+ }
+
+ for (int n = 0; n < bvh->totnode; n++) {
+ PBVHNode *node = &bvh->nodes[n];
+ if (!(node->flag & PBVH_Leaf))
+ continue;
+
+ GSetIterator gs_iter;
+ fprintf(stderr, "node %d\n faces:\n", n);
+ GSET_ITER (gs_iter, node->bm_faces)
+ fprintf(stderr, " %d\n",
+ BM_elem_index_get((BMFace *)BLI_gsetIterator_getKey(&gs_iter)));
+ fprintf(stderr, " unique verts:\n");
+ GSET_ITER (gs_iter, node->bm_unique_verts)
+ fprintf(stderr, " %d\n",
+ BM_elem_index_get((BMVert *)BLI_gsetIterator_getKey(&gs_iter)));
+ fprintf(stderr, " other verts:\n");
+ GSET_ITER (gs_iter, node->bm_other_verts)
+ fprintf(stderr, " %d\n",
+ BM_elem_index_get((BMVert *)BLI_gsetIterator_getKey(&gs_iter)));
+ }
}
static void print_flag_factors(int flag)
{
- printf("flag=0x%x:\n", flag);
- for (int i = 0; i < 32; i++) {
- if (flag & (1 << i)) {
- printf(" %d (1 << %d)\n", 1 << i, i);
- }
- }
+ printf("flag=0x%x:\n", flag);
+ for (int i = 0; i < 32; i++) {
+ if (flag & (1 << i)) {
+ printf(" %d (1 << %d)\n", 1 << i, i);
+ }
+ }
}
#endif
-
#ifdef USE_VERIFY
static void pbvh_bmesh_verify(PBVH *bvh)
{
- /* build list of faces & verts to lookup */
- GSet *faces_all = BLI_gset_ptr_new_ex(__func__, bvh->bm->totface);
- BMIter iter;
-
- {
- BMFace *f;
- BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) {
- BLI_assert(BM_ELEM_CD_GET_INT(f, bvh->cd_face_node_offset) != DYNTOPO_NODE_NONE);
- BLI_gset_insert(faces_all, f);
- }
- }
-
- GSet *verts_all = BLI_gset_ptr_new_ex(__func__, bvh->bm->totvert);
- {
- BMVert *v;
- BM_ITER_MESH(v, &iter, bvh->bm, BM_VERTS_OF_MESH) {
- if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) != DYNTOPO_NODE_NONE) {
- BLI_gset_insert(verts_all, v);
- }
- }
- }
-
- /* Check vert/face counts */
- {
- int totface = 0, totvert = 0;
- for (int i = 0; i < bvh->totnode; i++) {
- PBVHNode *n = &bvh->nodes[i];
- totface += n->bm_faces ? BLI_gset_len(n->bm_faces) : 0;
- totvert += n->bm_unique_verts ? BLI_gset_len(n->bm_unique_verts) : 0;
- }
-
- BLI_assert(totface == BLI_gset_len(faces_all));
- BLI_assert(totvert == BLI_gset_len(verts_all));
- }
-
- {
- BMFace *f;
- BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) {
- BMIter bm_iter;
- BMVert *v;
- PBVHNode *n = pbvh_bmesh_node_lookup(bvh, f);
-
- /* Check that the face's node is a leaf */
- BLI_assert(n->flag & PBVH_Leaf);
-
- /* Check that the face's node knows it owns the face */
- BLI_assert(BLI_gset_haskey(n->bm_faces, f));
-
- /* Check the face's vertices... */
- BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) {
- PBVHNode *nv;
-
- /* Check that the vertex is in the node */
- BLI_assert(BLI_gset_haskey(n->bm_unique_verts, v) ^
- BLI_gset_haskey(n->bm_other_verts, v));
-
- /* Check that the vertex has a node owner */
- nv = pbvh_bmesh_node_lookup(bvh, v);
-
- /* Check that the vertex's node knows it owns the vert */
- BLI_assert(BLI_gset_haskey(nv->bm_unique_verts, v));
-
- /* Check that the vertex isn't duplicated as an 'other' vert */
- BLI_assert(!BLI_gset_haskey(nv->bm_other_verts, v));
- }
- }
- }
-
- /* Check verts */
- {
- BMVert *v;
- BM_ITER_MESH(v, &iter, bvh->bm, BM_VERTS_OF_MESH) {
- /* vertex isn't tracked */
- if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) == DYNTOPO_NODE_NONE) {
- continue;
- }
-
- PBVHNode *n = pbvh_bmesh_node_lookup(bvh, v);
-
- /* Check that the vert's node is a leaf */
- BLI_assert(n->flag & PBVH_Leaf);
-
- /* Check that the vert's node knows it owns the vert */
- BLI_assert(BLI_gset_haskey(n->bm_unique_verts, v));
-
- /* Check that the vertex isn't duplicated as an 'other' vert */
- BLI_assert(!BLI_gset_haskey(n->bm_other_verts, v));
-
- /* Check that the vert's node also contains one of the vert's
- * adjacent faces */
- bool found = false;
- BMIter bm_iter;
- BMFace *f = NULL;
- BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) {
- if (pbvh_bmesh_node_lookup(bvh, f) == n) {
- found = true;
- break;
- }
- }
- BLI_assert(found || f == NULL);
-
-#if 1
- /* total freak stuff, check if node exists somewhere else */
- /* Slow */
- for (int i = 0; i < bvh->totnode; i++) {
- PBVHNode *n_other = &bvh->nodes[i];
- if ((n != n_other) && (n_other->bm_unique_verts)) {
- BLI_assert(!BLI_gset_haskey(n_other->bm_unique_verts, v));
- }
- }
-#endif
- }
- }
-
-#if 0
- /* check that every vert belongs somewhere */
- /* Slow */
- BM_ITER_MESH (vi, &iter, bvh->bm, BM_VERTS_OF_MESH) {
- bool has_unique = false;
- for (int i = 0; i < bvh->totnode; i++) {
- PBVHNode *n = &bvh->nodes[i];
- if ((n->bm_unique_verts != NULL) && BLI_gset_haskey(n->bm_unique_verts, vi))
- has_unique = true;
- }
- BLI_assert(has_unique);
- vert_count++;
- }
-
- /* if totvert differs from number of verts inside the hash. hash-totvert is checked above */
- BLI_assert(vert_count == bvh->bm->totvert);
-#endif
+ /* build list of faces & verts to lookup */
+ GSet *faces_all = BLI_gset_ptr_new_ex(__func__, bvh->bm->totface);
+ BMIter iter;
+
+ {
+ BMFace *f;
+ BM_ITER_MESH (f, &iter, bvh->bm, BM_FACES_OF_MESH) {
+ BLI_assert(BM_ELEM_CD_GET_INT(f, bvh->cd_face_node_offset) != DYNTOPO_NODE_NONE);
+ BLI_gset_insert(faces_all, f);
+ }
+ }
+
+ GSet *verts_all = BLI_gset_ptr_new_ex(__func__, bvh->bm->totvert);
+ {
+ BMVert *v;
+ BM_ITER_MESH (v, &iter, bvh->bm, BM_VERTS_OF_MESH) {
+ if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) != DYNTOPO_NODE_NONE) {
+ BLI_gset_insert(verts_all, v);
+ }
+ }
+ }
+
+ /* Check vert/face counts */
+ {
+ int totface = 0, totvert = 0;
+ for (int i = 0; i < bvh->totnode; i++) {
+ PBVHNode *n = &bvh->nodes[i];
+ totface += n->bm_faces ? BLI_gset_len(n->bm_faces) : 0;
+ totvert += n->bm_unique_verts ? BLI_gset_len(n->bm_unique_verts) : 0;
+ }
+
+ BLI_assert(totface == BLI_gset_len(faces_all));
+ BLI_assert(totvert == BLI_gset_len(verts_all));
+ }
+
+ {
+ BMFace *f;
+ BM_ITER_MESH (f, &iter, bvh->bm, BM_FACES_OF_MESH) {
+ BMIter bm_iter;
+ BMVert *v;
+ PBVHNode *n = pbvh_bmesh_node_lookup(bvh, f);
+
+ /* Check that the face's node is a leaf */
+ BLI_assert(n->flag & PBVH_Leaf);
+
+ /* Check that the face's node knows it owns the face */
+ BLI_assert(BLI_gset_haskey(n->bm_faces, f));
+
+ /* Check the face's vertices... */
+ BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) {
+ PBVHNode *nv;
+
+ /* Check that the vertex is in the node */
+ BLI_assert(BLI_gset_haskey(n->bm_unique_verts, v) ^ BLI_gset_haskey(n->bm_other_verts, v));
+
+ /* Check that the vertex has a node owner */
+ nv = pbvh_bmesh_node_lookup(bvh, v);
+
+ /* Check that the vertex's node knows it owns the vert */
+ BLI_assert(BLI_gset_haskey(nv->bm_unique_verts, v));
+
+ /* Check that the vertex isn't duplicated as an 'other' vert */
+ BLI_assert(!BLI_gset_haskey(nv->bm_other_verts, v));
+ }
+ }
+ }
+
+ /* Check verts */
+ {
+ BMVert *v;
+ BM_ITER_MESH (v, &iter, bvh->bm, BM_VERTS_OF_MESH) {
+ /* vertex isn't tracked */
+ if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) == DYNTOPO_NODE_NONE) {
+ continue;
+ }
+
+ PBVHNode *n = pbvh_bmesh_node_lookup(bvh, v);
+
+ /* Check that the vert's node is a leaf */
+ BLI_assert(n->flag & PBVH_Leaf);
+
+ /* Check that the vert's node knows it owns the vert */
+ BLI_assert(BLI_gset_haskey(n->bm_unique_verts, v));
+
+ /* Check that the vertex isn't duplicated as an 'other' vert */
+ BLI_assert(!BLI_gset_haskey(n->bm_other_verts, v));
+
+ /* Check that the vert's node also contains one of the vert's
+ * adjacent faces */
+ bool found = false;
+ BMIter bm_iter;
+ BMFace *f = NULL;
+ BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) {
+ if (pbvh_bmesh_node_lookup(bvh, f) == n) {
+ found = true;
+ break;
+ }
+ }
+ BLI_assert(found || f == NULL);
+
+# if 1
+ /* total freak stuff, check if node exists somewhere else */
+ /* Slow */
+ for (int i = 0; i < bvh->totnode; i++) {
+ PBVHNode *n_other = &bvh->nodes[i];
+ if ((n != n_other) && (n_other->bm_unique_verts)) {
+ BLI_assert(!BLI_gset_haskey(n_other->bm_unique_verts, v));
+ }
+ }
+# endif
+ }
+ }
+
+# if 0
+ /* check that every vert belongs somewhere */
+ /* Slow */
+ BM_ITER_MESH (vi, &iter, bvh->bm, BM_VERTS_OF_MESH) {
+ bool has_unique = false;
+ for (int i = 0; i < bvh->totnode; i++) {
+ PBVHNode *n = &bvh->nodes[i];
+ if ((n->bm_unique_verts != NULL) && BLI_gset_haskey(n->bm_unique_verts, vi))
+ has_unique = true;
+ }
+ BLI_assert(has_unique);
+ vert_count++;
+ }
+
+ /* if totvert differs from number of verts inside the hash. hash-totvert is checked above */
+ BLI_assert(vert_count == bvh->bm->totvert);
+# endif
- /* Check that node elements are recorded in the top level */
- for (int i = 0; i < bvh->totnode; i++) {
- PBVHNode *n = &bvh->nodes[i];
- if (n->flag & PBVH_Leaf) {
- GSetIterator gs_iter;
-
- GSET_ITER (gs_iter, n->bm_faces) {
- BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
- PBVHNode *n_other = pbvh_bmesh_node_lookup(bvh, f);
- BLI_assert(n == n_other);
- BLI_assert(BLI_gset_haskey(faces_all, f));
- }
-
- GSET_ITER (gs_iter, n->bm_unique_verts) {
- BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
- PBVHNode *n_other = pbvh_bmesh_node_lookup(bvh, v);
- BLI_assert(!BLI_gset_haskey(n->bm_other_verts, v));
- BLI_assert(n == n_other);
- BLI_assert(BLI_gset_haskey(verts_all, v));
- }
-
- GSET_ITER (gs_iter, n->bm_other_verts) {
- BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
- /* this happens sometimes and seems harmless */
- // BLI_assert(!BM_vert_face_check(v));
- BLI_assert(BLI_gset_haskey(verts_all, v));
- }
- }
- }
-
- BLI_gset_free(faces_all, NULL);
- BLI_gset_free(verts_all, NULL);
+ /* Check that node elements are recorded in the top level */
+ for (int i = 0; i < bvh->totnode; i++) {
+ PBVHNode *n = &bvh->nodes[i];
+ if (n->flag & PBVH_Leaf) {
+ GSetIterator gs_iter;
+
+ GSET_ITER (gs_iter, n->bm_faces) {
+ BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
+ PBVHNode *n_other = pbvh_bmesh_node_lookup(bvh, f);
+ BLI_assert(n == n_other);
+ BLI_assert(BLI_gset_haskey(faces_all, f));
+ }
+
+ GSET_ITER (gs_iter, n->bm_unique_verts) {
+ BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
+ PBVHNode *n_other = pbvh_bmesh_node_lookup(bvh, v);
+ BLI_assert(!BLI_gset_haskey(n->bm_other_verts, v));
+ BLI_assert(n == n_other);
+ BLI_assert(BLI_gset_haskey(verts_all, v));
+ }
+
+ GSET_ITER (gs_iter, n->bm_other_verts) {
+ BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
+ /* this happens sometimes and seems harmless */
+ // BLI_assert(!BM_vert_face_check(v));
+ BLI_assert(BLI_gset_haskey(verts_all, v));
+ }
+ }
+ }
+
+ BLI_gset_free(faces_all, NULL);
+ BLI_gset_free(verts_all, NULL);
}
#endif
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index b9610179630..5fc41c560b2 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -23,146 +23,146 @@
/* Axis-aligned bounding box */
typedef struct {
- float bmin[3], bmax[3];
+ float bmin[3], bmax[3];
} BB;
/* Axis-aligned bounding box with centroid */
typedef struct {
- float bmin[3], bmax[3], bcentroid[3];
+ float bmin[3], bmax[3], bcentroid[3];
} BBC;
/* Note: this structure is getting large, might want to split it into
* union'd structs */
struct PBVHNode {
- /* Opaque handle for drawing code */
- struct GPU_PBVH_Buffers *draw_buffers;
-
- /* Voxel bounds */
- BB vb;
- BB orig_vb;
-
- /* For internal nodes, the offset of the children in the PBVH
- * 'nodes' array. */
- int children_offset;
-
- /* Pointer into the PBVH prim_indices array and the number of
- * primitives used by this leaf node.
- *
- * Used for leaf nodes in both mesh- and multires-based PBVHs.
- */
- int *prim_indices;
- unsigned int totprim;
-
- /* Array of indices into the mesh's MVert array. Contains the
- * indices of all vertices used by faces that are within this
- * node's bounding box.
- *
- * Note that a vertex might be used by a multiple faces, and
- * these faces might be in different leaf nodes. Such a vertex
- * will appear in the vert_indices array of each of those leaf
- * nodes.
- *
- * In order to support cases where you want access to multiple
- * nodes' vertices without duplication, the vert_indices array
- * is ordered such that the first part of the array, up to
- * index 'uniq_verts', contains "unique" vertex indices. These
- * vertices might not be truly unique to this node, but if
- * they appear in another node's vert_indices array, they will
- * be above that node's 'uniq_verts' value.
- *
- * Used for leaf nodes in a mesh-based PBVH (not multires.)
- */
- const int *vert_indices;
- unsigned int uniq_verts, face_verts;
-
- /* An array mapping face corners into the vert_indices
- * array. The array is sized to match 'totprim', and each of
- * the face's corners gets an index into the vert_indices
- * array, in the same order as the corners in the original
- * MLoopTri.
- *
- * Used for leaf nodes in a mesh-based PBVH (not multires.)
- */
- const int (*face_vert_indices)[3];
-
- /* Indicates whether this node is a leaf or not; also used for
- * marking various updates that need to be applied. */
- PBVHNodeFlags flag : 16;
-
- /* Used for raycasting: how close bb is to the ray point. */
- float tmin;
-
- /* Scalar displacements for sculpt mode's layer brush. */
- float *layer_disp;
-
- int proxy_count;
- PBVHProxyNode *proxies;
-
- /* Dyntopo */
- GSet *bm_faces;
- GSet *bm_unique_verts;
- GSet *bm_other_verts;
- float (*bm_orco)[3];
- int (*bm_ortri)[3];
- int bm_tot_ortri;
+ /* Opaque handle for drawing code */
+ struct GPU_PBVH_Buffers *draw_buffers;
+
+ /* Voxel bounds */
+ BB vb;
+ BB orig_vb;
+
+ /* For internal nodes, the offset of the children in the PBVH
+ * 'nodes' array. */
+ int children_offset;
+
+ /* Pointer into the PBVH prim_indices array and the number of
+ * primitives used by this leaf node.
+ *
+ * Used for leaf nodes in both mesh- and multires-based PBVHs.
+ */
+ int *prim_indices;
+ unsigned int totprim;
+
+ /* Array of indices into the mesh's MVert array. Contains the
+ * indices of all vertices used by faces that are within this
+ * node's bounding box.
+ *
+ * Note that a vertex might be used by a multiple faces, and
+ * these faces might be in different leaf nodes. Such a vertex
+ * will appear in the vert_indices array of each of those leaf
+ * nodes.
+ *
+ * In order to support cases where you want access to multiple
+ * nodes' vertices without duplication, the vert_indices array
+ * is ordered such that the first part of the array, up to
+ * index 'uniq_verts', contains "unique" vertex indices. These
+ * vertices might not be truly unique to this node, but if
+ * they appear in another node's vert_indices array, they will
+ * be above that node's 'uniq_verts' value.
+ *
+ * Used for leaf nodes in a mesh-based PBVH (not multires.)
+ */
+ const int *vert_indices;
+ unsigned int uniq_verts, face_verts;
+
+ /* An array mapping face corners into the vert_indices
+ * array. The array is sized to match 'totprim', and each of
+ * the face's corners gets an index into the vert_indices
+ * array, in the same order as the corners in the original
+ * MLoopTri.
+ *
+ * Used for leaf nodes in a mesh-based PBVH (not multires.)
+ */
+ const int (*face_vert_indices)[3];
+
+ /* Indicates whether this node is a leaf or not; also used for
+ * marking various updates that need to be applied. */
+ PBVHNodeFlags flag : 16;
+
+ /* Used for raycasting: how close bb is to the ray point. */
+ float tmin;
+
+ /* Scalar displacements for sculpt mode's layer brush. */
+ float *layer_disp;
+
+ int proxy_count;
+ PBVHProxyNode *proxies;
+
+ /* Dyntopo */
+ GSet *bm_faces;
+ GSet *bm_unique_verts;
+ GSet *bm_other_verts;
+ float (*bm_orco)[3];
+ int (*bm_ortri)[3];
+ int bm_tot_ortri;
};
typedef enum {
- PBVH_DYNTOPO_SMOOTH_SHADING = 1,
+ PBVH_DYNTOPO_SMOOTH_SHADING = 1,
} PBVHFlags;
typedef struct PBVHBMeshLog PBVHBMeshLog;
struct PBVH {
- PBVHType type;
- PBVHFlags flags;
+ PBVHType type;
+ PBVHFlags flags;
- PBVHNode *nodes;
- int node_mem_count, totnode;
+ PBVHNode *nodes;
+ int node_mem_count, totnode;
- int *prim_indices;
- int totprim;
- int totvert;
+ int *prim_indices;
+ int totprim;
+ int totvert;
- int leaf_limit;
+ int leaf_limit;
- /* Mesh data */
- MVert *verts;
- const MPoly *mpoly;
- const MLoop *mloop;
- const MLoopTri *looptri;
- CustomData *vdata;
+ /* Mesh data */
+ MVert *verts;
+ const MPoly *mpoly;
+ const MLoop *mloop;
+ const MLoopTri *looptri;
+ CustomData *vdata;
- /* Grid Data */
- CCGKey gridkey;
- CCGElem **grids;
- void **gridfaces;
- const DMFlagMat *grid_flag_mats;
- int totgrid;
- BLI_bitmap **grid_hidden;
+ /* Grid Data */
+ CCGKey gridkey;
+ CCGElem **grids;
+ void **gridfaces;
+ const DMFlagMat *grid_flag_mats;
+ int totgrid;
+ BLI_bitmap **grid_hidden;
- /* Only used during BVH build and update,
- * don't need to remain valid after */
- BLI_bitmap *vert_bitmap;
+ /* Only used during BVH build and update,
+ * don't need to remain valid after */
+ BLI_bitmap *vert_bitmap;
#ifdef PERFCNTRS
- int perf_modified;
+ int perf_modified;
#endif
- /* flag are verts/faces deformed */
- bool deformed;
+ /* flag are verts/faces deformed */
+ bool deformed;
- bool show_diffuse_color;
- bool show_mask;
+ bool show_diffuse_color;
+ bool show_mask;
- /* Dynamic topology */
- BMesh *bm;
- float bm_max_edge_len;
- float bm_min_edge_len;
- int cd_vert_node_offset;
- int cd_face_node_offset;
+ /* Dynamic topology */
+ BMesh *bm;
+ float bm_max_edge_len;
+ float bm_min_edge_len;
+ int cd_vert_node_offset;
+ int cd_face_node_offset;
- struct BMLog *bm_log;
+ struct BMLog *bm_log;
};
/* pbvh.c */
@@ -172,35 +172,50 @@ void BB_expand_with_bb(BB *bb, BB *bb2);
void BBC_update_centroid(BBC *bbc);
int BB_widest_axis(const BB *bb);
void pbvh_grow_nodes(PBVH *bvh, int totnode);
-bool ray_face_intersection_quad(
- const float ray_start[3], const float ray_normal[3],
- const float *t0, const float *t1, const float *t2, const float *t3,
- float *depth);
-bool ray_face_intersection_tri(
- const float ray_start[3], const float ray_normal[3],
- const float *t0, const float *t1, const float *t2,
- float *depth);
-
-bool ray_face_nearest_quad(
- const float ray_start[3], const float ray_normal[3],
- const float *t0, const float *t1, const float *t2, const float *t3,
- float *r_depth, float *r_dist_sq);
-bool ray_face_nearest_tri(
- const float ray_start[3], const float ray_normal[3],
- const float *t0, const float *t1, const float *t2,
- float *r_depth, float *r_dist_sq);
+bool ray_face_intersection_quad(const float ray_start[3],
+ const float ray_normal[3],
+ const float *t0,
+ const float *t1,
+ const float *t2,
+ const float *t3,
+ float *depth);
+bool ray_face_intersection_tri(const float ray_start[3],
+ const float ray_normal[3],
+ const float *t0,
+ const float *t1,
+ const float *t2,
+ float *depth);
+
+bool ray_face_nearest_quad(const float ray_start[3],
+ const float ray_normal[3],
+ const float *t0,
+ const float *t1,
+ const float *t2,
+ const float *t3,
+ float *r_depth,
+ float *r_dist_sq);
+bool ray_face_nearest_tri(const float ray_start[3],
+ const float ray_normal[3],
+ const float *t0,
+ const float *t1,
+ const float *t2,
+ float *r_depth,
+ float *r_dist_sq);
void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag);
/* pbvh_bmesh.c */
-bool pbvh_bmesh_node_raycast(
- PBVHNode *node, const float ray_start[3],
- const float ray_normal[3], float *dist,
- bool use_original);
-bool pbvh_bmesh_node_nearest_to_ray(
- PBVHNode *node, const float ray_start[3],
- const float ray_normal[3], float *depth, float *dist_sq,
- bool use_original);
+bool pbvh_bmesh_node_raycast(PBVHNode *node,
+ const float ray_start[3],
+ const float ray_normal[3],
+ float *dist,
+ bool use_original);
+bool pbvh_bmesh_node_nearest_to_ray(PBVHNode *node,
+ const float ray_start[3],
+ const float ray_normal[3],
+ float *depth,
+ float *dist_sq,
+ bool use_original);
void pbvh_bmesh_normals_update(PBVHNode **nodes, int totnode);
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 3371c3dbe48..2d3914090b1 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -21,7 +21,6 @@
* \ingroup bke
*/
-
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -76,11 +75,11 @@
/* both in intern */
#ifdef WITH_SMOKE
-#include "smoke_API.h"
+# include "smoke_API.h"
#endif
#ifdef WITH_OPENVDB
-#include "openvdb_capi.h"
+# include "openvdb_capi.h"
#endif
#ifdef WITH_LZO
@@ -89,14 +88,14 @@
# else
# include "minilzo.h"
# endif
-# define LZO_HEAP_ALLOC(var,size) \
- lzo_align_t __LZO_MMODEL var [ ((size) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t) ]
+# define LZO_HEAP_ALLOC(var, size) \
+ lzo_align_t __LZO_MMODEL var[((size) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t)]
#endif
-#define LZO_OUT_LEN(size) ((size) + (size) / 16 + 64 + 3)
+#define LZO_OUT_LEN(size) ((size) + (size) / 16 + 64 + 3)
#ifdef WITH_LZMA
-#include "LzmaLib.h"
+# include "LzmaLib.h"
#endif
/* needed for directory lookup */
@@ -106,15 +105,19 @@
# include "BLI_winstuff.h"
#endif
-#define PTCACHE_DATA_FROM(data, type, from) \
- if (data[type]) { \
- memcpy(data[type], from, ptcache_data_size[type]); \
- } (void)0
+#define PTCACHE_DATA_FROM(data, type, from) \
+ if (data[type]) { \
+ memcpy(data[type], from, ptcache_data_size[type]); \
+ } \
+ (void)0
-#define PTCACHE_DATA_TO(data, type, index, to) \
- if (data[type]) { \
- memcpy(to, (char *)(data)[type] + ((index) ? (index) * ptcache_data_size[type] : 0), ptcache_data_size[type]); \
- } (void)0
+#define PTCACHE_DATA_TO(data, type, index, to) \
+ if (data[type]) { \
+ memcpy(to, \
+ (char *)(data)[type] + ((index) ? (index)*ptcache_data_size[type] : 0), \
+ ptcache_data_size[type]); \
+ } \
+ (void)0
/* could be made into a pointcache option */
#define DURIAN_POINTCACHE_LIB_OK 1
@@ -122,775 +125,824 @@
static CLG_LogRef LOG = {"bke.pointcache"};
static int ptcache_data_size[] = {
- sizeof(unsigned int), // BPHYS_DATA_INDEX
- 3 * sizeof(float), // BPHYS_DATA_LOCATION
- 3 * sizeof(float), // BPHYS_DATA_VELOCITY
- 4 * sizeof(float), // BPHYS_DATA_ROTATION
- 3 * sizeof(float), // BPHYS_DATA_AVELOCITY / BPHYS_DATA_XCONST
- sizeof(float), // BPHYS_DATA_SIZE
- 3 * sizeof(float), // BPHYS_DATA_TIMES
- sizeof(BoidData), // case BPHYS_DATA_BOIDS
+ sizeof(unsigned int), // BPHYS_DATA_INDEX
+ 3 * sizeof(float), // BPHYS_DATA_LOCATION
+ 3 * sizeof(float), // BPHYS_DATA_VELOCITY
+ 4 * sizeof(float), // BPHYS_DATA_ROTATION
+ 3 * sizeof(float), // BPHYS_DATA_AVELOCITY / BPHYS_DATA_XCONST
+ sizeof(float), // BPHYS_DATA_SIZE
+ 3 * sizeof(float), // BPHYS_DATA_TIMES
+ sizeof(BoidData), // case BPHYS_DATA_BOIDS
};
static int ptcache_extra_datasize[] = {
- 0,
- sizeof(ParticleSpring),
+ 0,
+ sizeof(ParticleSpring),
};
/* forward declarations */
static int ptcache_file_compressed_read(PTCacheFile *pf, unsigned char *result, unsigned int len);
-static int ptcache_file_compressed_write(PTCacheFile *pf, unsigned char *in, unsigned int in_len, unsigned char *out, int mode);
+static int ptcache_file_compressed_write(
+ PTCacheFile *pf, unsigned char *in, unsigned int in_len, unsigned char *out, int mode);
static int ptcache_file_write(PTCacheFile *pf, const void *f, unsigned int tot, unsigned int size);
static int ptcache_file_read(PTCacheFile *pf, void *f, unsigned int tot, unsigned int size);
/* Common functions */
static int ptcache_basic_header_read(PTCacheFile *pf)
{
- int error=0;
+ int error = 0;
- /* Custom functions should read these basic elements too! */
- if (!error && !fread(&pf->totpoint, sizeof(unsigned int), 1, pf->fp))
- error = 1;
+ /* Custom functions should read these basic elements too! */
+ if (!error && !fread(&pf->totpoint, sizeof(unsigned int), 1, pf->fp))
+ error = 1;
- if (!error && !fread(&pf->data_types, sizeof(unsigned int), 1, pf->fp))
- error = 1;
+ if (!error && !fread(&pf->data_types, sizeof(unsigned int), 1, pf->fp))
+ error = 1;
- return !error;
+ return !error;
}
static int ptcache_basic_header_write(PTCacheFile *pf)
{
- /* Custom functions should write these basic elements too! */
- if (!fwrite(&pf->totpoint, sizeof(unsigned int), 1, pf->fp))
- return 0;
+ /* Custom functions should write these basic elements too! */
+ if (!fwrite(&pf->totpoint, sizeof(unsigned int), 1, pf->fp))
+ return 0;
- if (!fwrite(&pf->data_types, sizeof(unsigned int), 1, pf->fp))
- return 0;
+ if (!fwrite(&pf->data_types, sizeof(unsigned int), 1, pf->fp))
+ return 0;
- return 1;
+ return 1;
}
/* Softbody functions */
-static int ptcache_softbody_write(int index, void *soft_v, void **data, int UNUSED(cfra))
+static int ptcache_softbody_write(int index, void *soft_v, void **data, int UNUSED(cfra))
{
- SoftBody *soft= soft_v;
- BodyPoint *bp = soft->bpoint + index;
+ SoftBody *soft = soft_v;
+ BodyPoint *bp = soft->bpoint + index;
- PTCACHE_DATA_FROM(data, BPHYS_DATA_LOCATION, bp->pos);
- PTCACHE_DATA_FROM(data, BPHYS_DATA_VELOCITY, bp->vec);
+ PTCACHE_DATA_FROM(data, BPHYS_DATA_LOCATION, bp->pos);
+ PTCACHE_DATA_FROM(data, BPHYS_DATA_VELOCITY, bp->vec);
- return 1;
+ return 1;
}
-static void ptcache_softbody_read(int index, void *soft_v, void **data, float UNUSED(cfra), float *old_data)
+static void ptcache_softbody_read(
+ int index, void *soft_v, void **data, float UNUSED(cfra), float *old_data)
{
- SoftBody *soft= soft_v;
- BodyPoint *bp = soft->bpoint + index;
-
- if (old_data) {
- memcpy(bp->pos, data, 3 * sizeof(float));
- memcpy(bp->vec, data + 3, 3 * sizeof(float));
- }
- else {
- PTCACHE_DATA_TO(data, BPHYS_DATA_LOCATION, 0, bp->pos);
- PTCACHE_DATA_TO(data, BPHYS_DATA_VELOCITY, 0, bp->vec);
- }
+ SoftBody *soft = soft_v;
+ BodyPoint *bp = soft->bpoint + index;
+
+ if (old_data) {
+ memcpy(bp->pos, data, 3 * sizeof(float));
+ memcpy(bp->vec, data + 3, 3 * sizeof(float));
+ }
+ else {
+ PTCACHE_DATA_TO(data, BPHYS_DATA_LOCATION, 0, bp->pos);
+ PTCACHE_DATA_TO(data, BPHYS_DATA_VELOCITY, 0, bp->vec);
+ }
}
-static void ptcache_softbody_interpolate(int index, void *soft_v, void **data, float cfra, float cfra1, float cfra2, float *old_data)
+static void ptcache_softbody_interpolate(
+ int index, void *soft_v, void **data, float cfra, float cfra1, float cfra2, float *old_data)
{
- SoftBody *soft= soft_v;
- BodyPoint *bp = soft->bpoint + index;
- ParticleKey keys[4];
- float dfra;
+ SoftBody *soft = soft_v;
+ BodyPoint *bp = soft->bpoint + index;
+ ParticleKey keys[4];
+ float dfra;
- if (cfra1 == cfra2)
- return;
+ if (cfra1 == cfra2)
+ return;
- copy_v3_v3(keys[1].co, bp->pos);
- copy_v3_v3(keys[1].vel, bp->vec);
+ copy_v3_v3(keys[1].co, bp->pos);
+ copy_v3_v3(keys[1].vel, bp->vec);
- if (old_data) {
- memcpy(keys[2].co, old_data, 3 * sizeof(float));
- memcpy(keys[2].vel, old_data + 3, 3 * sizeof(float));
- }
- else
- BKE_ptcache_make_particle_key(keys+2, 0, data, cfra2);
+ if (old_data) {
+ memcpy(keys[2].co, old_data, 3 * sizeof(float));
+ memcpy(keys[2].vel, old_data + 3, 3 * sizeof(float));
+ }
+ else
+ BKE_ptcache_make_particle_key(keys + 2, 0, data, cfra2);
- dfra = cfra2 - cfra1;
+ dfra = cfra2 - cfra1;
- mul_v3_fl(keys[1].vel, dfra);
- mul_v3_fl(keys[2].vel, dfra);
+ mul_v3_fl(keys[1].vel, dfra);
+ mul_v3_fl(keys[2].vel, dfra);
- psys_interpolate_particle(-1, keys, (cfra - cfra1) / dfra, keys, 1);
+ psys_interpolate_particle(-1, keys, (cfra - cfra1) / dfra, keys, 1);
- mul_v3_fl(keys->vel, 1.0f / dfra);
+ mul_v3_fl(keys->vel, 1.0f / dfra);
- copy_v3_v3(bp->pos, keys->co);
- copy_v3_v3(bp->vec, keys->vel);
+ copy_v3_v3(bp->pos, keys->co);
+ copy_v3_v3(bp->vec, keys->vel);
}
-static int ptcache_softbody_totpoint(void *soft_v, int UNUSED(cfra))
+static int ptcache_softbody_totpoint(void *soft_v, int UNUSED(cfra))
{
- SoftBody *soft= soft_v;
- return soft->totpoint;
+ SoftBody *soft = soft_v;
+ return soft->totpoint;
}
static void ptcache_softbody_error(void *UNUSED(soft_v), const char *UNUSED(message))
{
- /* ignored for now */
+ /* ignored for now */
}
/* Particle functions */
void BKE_ptcache_make_particle_key(ParticleKey *key, int index, void **data, float time)
{
- PTCACHE_DATA_TO(data, BPHYS_DATA_LOCATION, index, key->co);
- PTCACHE_DATA_TO(data, BPHYS_DATA_VELOCITY, index, key->vel);
-
- /* no rotation info, so make something nice up */
- if (data[BPHYS_DATA_ROTATION]==NULL) {
- vec_to_quat(key->rot, key->vel, OB_NEGX, OB_POSZ);
- }
- else {
- PTCACHE_DATA_TO(data, BPHYS_DATA_ROTATION, index, key->rot);
- }
-
- PTCACHE_DATA_TO(data, BPHYS_DATA_AVELOCITY, index, key->ave);
- key->time = time;
+ PTCACHE_DATA_TO(data, BPHYS_DATA_LOCATION, index, key->co);
+ PTCACHE_DATA_TO(data, BPHYS_DATA_VELOCITY, index, key->vel);
+
+ /* no rotation info, so make something nice up */
+ if (data[BPHYS_DATA_ROTATION] == NULL) {
+ vec_to_quat(key->rot, key->vel, OB_NEGX, OB_POSZ);
+ }
+ else {
+ PTCACHE_DATA_TO(data, BPHYS_DATA_ROTATION, index, key->rot);
+ }
+
+ PTCACHE_DATA_TO(data, BPHYS_DATA_AVELOCITY, index, key->ave);
+ key->time = time;
}
-static int ptcache_particle_write(int index, void *psys_v, void **data, int cfra)
+static int ptcache_particle_write(int index, void *psys_v, void **data, int cfra)
{
- ParticleSystem *psys= psys_v;
- ParticleData *pa = psys->particles + index;
- BoidParticle *boid = (psys->part->phystype == PART_PHYS_BOIDS) ? pa->boid : NULL;
- float times[3];
- int step = psys->pointcache->step;
-
- /* No need to store unborn or died particles outside cache step bounds */
- if (data[BPHYS_DATA_INDEX] && (cfra < pa->time - step || cfra > pa->dietime + step))
- return 0;
-
- times[0] = pa->time;
- times[1] = pa->dietime;
- times[2] = pa->lifetime;
-
- PTCACHE_DATA_FROM(data, BPHYS_DATA_INDEX, &index);
- PTCACHE_DATA_FROM(data, BPHYS_DATA_LOCATION, pa->state.co);
- PTCACHE_DATA_FROM(data, BPHYS_DATA_VELOCITY, pa->state.vel);
- PTCACHE_DATA_FROM(data, BPHYS_DATA_ROTATION, pa->state.rot);
- PTCACHE_DATA_FROM(data, BPHYS_DATA_AVELOCITY, pa->state.ave);
- PTCACHE_DATA_FROM(data, BPHYS_DATA_SIZE, &pa->size);
- PTCACHE_DATA_FROM(data, BPHYS_DATA_TIMES, times);
-
- if (boid) {
- PTCACHE_DATA_FROM(data, BPHYS_DATA_BOIDS, &boid->data);
- }
-
- /* return flag 1+1=2 for newly born particles to copy exact birth location to previously cached frame */
- return 1 + (pa->state.time >= pa->time && pa->prev_state.time <= pa->time);
+ ParticleSystem *psys = psys_v;
+ ParticleData *pa = psys->particles + index;
+ BoidParticle *boid = (psys->part->phystype == PART_PHYS_BOIDS) ? pa->boid : NULL;
+ float times[3];
+ int step = psys->pointcache->step;
+
+ /* No need to store unborn or died particles outside cache step bounds */
+ if (data[BPHYS_DATA_INDEX] && (cfra < pa->time - step || cfra > pa->dietime + step))
+ return 0;
+
+ times[0] = pa->time;
+ times[1] = pa->dietime;
+ times[2] = pa->lifetime;
+
+ PTCACHE_DATA_FROM(data, BPHYS_DATA_INDEX, &index);
+ PTCACHE_DATA_FROM(data, BPHYS_DATA_LOCATION, pa->state.co);
+ PTCACHE_DATA_FROM(data, BPHYS_DATA_VELOCITY, pa->state.vel);
+ PTCACHE_DATA_FROM(data, BPHYS_DATA_ROTATION, pa->state.rot);
+ PTCACHE_DATA_FROM(data, BPHYS_DATA_AVELOCITY, pa->state.ave);
+ PTCACHE_DATA_FROM(data, BPHYS_DATA_SIZE, &pa->size);
+ PTCACHE_DATA_FROM(data, BPHYS_DATA_TIMES, times);
+
+ if (boid) {
+ PTCACHE_DATA_FROM(data, BPHYS_DATA_BOIDS, &boid->data);
+ }
+
+ /* return flag 1+1=2 for newly born particles to copy exact birth location to previously cached frame */
+ return 1 + (pa->state.time >= pa->time && pa->prev_state.time <= pa->time);
}
-static void ptcache_particle_read(int index, void *psys_v, void **data, float cfra, float *old_data)
+static void ptcache_particle_read(
+ int index, void *psys_v, void **data, float cfra, float *old_data)
{
- ParticleSystem *psys= psys_v;
- ParticleData *pa;
- BoidParticle *boid;
- float timestep = 0.04f * psys->part->timetweak;
-
- if (index >= psys->totpart)
- return;
-
- pa = psys->particles + index;
- boid = (psys->part->phystype == PART_PHYS_BOIDS) ? pa->boid : NULL;
-
- if (cfra > pa->state.time)
- memcpy(&pa->prev_state, &pa->state, sizeof(ParticleKey));
-
- if (old_data) {
- /* old format cache */
- memcpy(&pa->state, old_data, sizeof(ParticleKey));
- return;
- }
-
- BKE_ptcache_make_particle_key(&pa->state, 0, data, cfra);
-
- /* set frames cached before birth to birth time */
- if (cfra < pa->time)
- pa->state.time = pa->time;
- else if (cfra > pa->dietime)
- pa->state.time = pa->dietime;
-
- if (data[BPHYS_DATA_SIZE]) {
- PTCACHE_DATA_TO(data, BPHYS_DATA_SIZE, 0, &pa->size);
- }
-
- if (data[BPHYS_DATA_TIMES]) {
- float times[3];
- PTCACHE_DATA_TO(data, BPHYS_DATA_TIMES, 0, &times);
- pa->time = times[0];
- pa->dietime = times[1];
- pa->lifetime = times[2];
- }
-
- if (boid) {
- PTCACHE_DATA_TO(data, BPHYS_DATA_BOIDS, 0, &boid->data);
- }
-
- /* determine velocity from previous location */
- if (data[BPHYS_DATA_LOCATION] && !data[BPHYS_DATA_VELOCITY]) {
- if (cfra > pa->prev_state.time) {
- sub_v3_v3v3(pa->state.vel, pa->state.co, pa->prev_state.co);
- mul_v3_fl(pa->state.vel, (cfra - pa->prev_state.time) * timestep);
- }
- else {
- sub_v3_v3v3(pa->state.vel, pa->prev_state.co, pa->state.co);
- mul_v3_fl(pa->state.vel, (pa->prev_state.time - cfra) * timestep);
- }
- }
-
- /* default to no rotation */
- if (data[BPHYS_DATA_LOCATION] && !data[BPHYS_DATA_ROTATION]) {
- unit_qt(pa->state.rot);
- }
+ ParticleSystem *psys = psys_v;
+ ParticleData *pa;
+ BoidParticle *boid;
+ float timestep = 0.04f * psys->part->timetweak;
+
+ if (index >= psys->totpart)
+ return;
+
+ pa = psys->particles + index;
+ boid = (psys->part->phystype == PART_PHYS_BOIDS) ? pa->boid : NULL;
+
+ if (cfra > pa->state.time)
+ memcpy(&pa->prev_state, &pa->state, sizeof(ParticleKey));
+
+ if (old_data) {
+ /* old format cache */
+ memcpy(&pa->state, old_data, sizeof(ParticleKey));
+ return;
+ }
+
+ BKE_ptcache_make_particle_key(&pa->state, 0, data, cfra);
+
+ /* set frames cached before birth to birth time */
+ if (cfra < pa->time)
+ pa->state.time = pa->time;
+ else if (cfra > pa->dietime)
+ pa->state.time = pa->dietime;
+
+ if (data[BPHYS_DATA_SIZE]) {
+ PTCACHE_DATA_TO(data, BPHYS_DATA_SIZE, 0, &pa->size);
+ }
+
+ if (data[BPHYS_DATA_TIMES]) {
+ float times[3];
+ PTCACHE_DATA_TO(data, BPHYS_DATA_TIMES, 0, &times);
+ pa->time = times[0];
+ pa->dietime = times[1];
+ pa->lifetime = times[2];
+ }
+
+ if (boid) {
+ PTCACHE_DATA_TO(data, BPHYS_DATA_BOIDS, 0, &boid->data);
+ }
+
+ /* determine velocity from previous location */
+ if (data[BPHYS_DATA_LOCATION] && !data[BPHYS_DATA_VELOCITY]) {
+ if (cfra > pa->prev_state.time) {
+ sub_v3_v3v3(pa->state.vel, pa->state.co, pa->prev_state.co);
+ mul_v3_fl(pa->state.vel, (cfra - pa->prev_state.time) * timestep);
+ }
+ else {
+ sub_v3_v3v3(pa->state.vel, pa->prev_state.co, pa->state.co);
+ mul_v3_fl(pa->state.vel, (pa->prev_state.time - cfra) * timestep);
+ }
+ }
+
+ /* default to no rotation */
+ if (data[BPHYS_DATA_LOCATION] && !data[BPHYS_DATA_ROTATION]) {
+ unit_qt(pa->state.rot);
+ }
}
-static void ptcache_particle_interpolate(int index, void *psys_v, void **data, float cfra, float cfra1, float cfra2, float *old_data)
+static void ptcache_particle_interpolate(
+ int index, void *psys_v, void **data, float cfra, float cfra1, float cfra2, float *old_data)
{
- ParticleSystem *psys= psys_v;
- ParticleData *pa;
- ParticleKey keys[4];
- float dfra, timestep = 0.04f * psys->part->timetweak;
+ ParticleSystem *psys = psys_v;
+ ParticleData *pa;
+ ParticleKey keys[4];
+ float dfra, timestep = 0.04f * psys->part->timetweak;
- if (index >= psys->totpart)
- return;
+ if (index >= psys->totpart)
+ return;
- pa = psys->particles + index;
+ pa = psys->particles + index;
- /* particle wasn't read from first cache so can't interpolate */
- if ((int)cfra1 < pa->time - psys->pointcache->step || (int)cfra1 > pa->dietime + psys->pointcache->step)
- return;
+ /* particle wasn't read from first cache so can't interpolate */
+ if ((int)cfra1 < pa->time - psys->pointcache->step ||
+ (int)cfra1 > pa->dietime + psys->pointcache->step)
+ return;
- cfra = MIN2(cfra, pa->dietime);
- cfra1 = MIN2(cfra1, pa->dietime);
- cfra2 = MIN2(cfra2, pa->dietime);
+ cfra = MIN2(cfra, pa->dietime);
+ cfra1 = MIN2(cfra1, pa->dietime);
+ cfra2 = MIN2(cfra2, pa->dietime);
- if (cfra1 == cfra2)
- return;
+ if (cfra1 == cfra2)
+ return;
- memcpy(keys+1, &pa->state, sizeof(ParticleKey));
- if (old_data)
- memcpy(keys+2, old_data, sizeof(ParticleKey));
- else
- BKE_ptcache_make_particle_key(keys+2, 0, data, cfra2);
+ memcpy(keys + 1, &pa->state, sizeof(ParticleKey));
+ if (old_data)
+ memcpy(keys + 2, old_data, sizeof(ParticleKey));
+ else
+ BKE_ptcache_make_particle_key(keys + 2, 0, data, cfra2);
- /* determine velocity from previous location */
- if (data[BPHYS_DATA_LOCATION] && !data[BPHYS_DATA_VELOCITY]) {
- if (keys[1].time > keys[2].time) {
- sub_v3_v3v3(keys[2].vel, keys[1].co, keys[2].co);
- mul_v3_fl(keys[2].vel, (keys[1].time - keys[2].time) * timestep);
- }
- else {
- sub_v3_v3v3(keys[2].vel, keys[2].co, keys[1].co);
- mul_v3_fl(keys[2].vel, (keys[2].time - keys[1].time) * timestep);
- }
- }
+ /* determine velocity from previous location */
+ if (data[BPHYS_DATA_LOCATION] && !data[BPHYS_DATA_VELOCITY]) {
+ if (keys[1].time > keys[2].time) {
+ sub_v3_v3v3(keys[2].vel, keys[1].co, keys[2].co);
+ mul_v3_fl(keys[2].vel, (keys[1].time - keys[2].time) * timestep);
+ }
+ else {
+ sub_v3_v3v3(keys[2].vel, keys[2].co, keys[1].co);
+ mul_v3_fl(keys[2].vel, (keys[2].time - keys[1].time) * timestep);
+ }
+ }
- /* default to no rotation */
- if (data[BPHYS_DATA_LOCATION] && !data[BPHYS_DATA_ROTATION]) {
- unit_qt(keys[2].rot);
- }
+ /* default to no rotation */
+ if (data[BPHYS_DATA_LOCATION] && !data[BPHYS_DATA_ROTATION]) {
+ unit_qt(keys[2].rot);
+ }
- if (cfra > pa->time)
- cfra1 = MAX2(cfra1, pa->time);
+ if (cfra > pa->time)
+ cfra1 = MAX2(cfra1, pa->time);
- dfra = cfra2 - cfra1;
+ dfra = cfra2 - cfra1;
- mul_v3_fl(keys[1].vel, dfra * timestep);
- mul_v3_fl(keys[2].vel, dfra * timestep);
+ mul_v3_fl(keys[1].vel, dfra * timestep);
+ mul_v3_fl(keys[2].vel, dfra * timestep);
- psys_interpolate_particle(-1, keys, (cfra - cfra1) / dfra, &pa->state, 1);
- interp_qt_qtqt(pa->state.rot, keys[1].rot, keys[2].rot, (cfra - cfra1) / dfra);
+ psys_interpolate_particle(-1, keys, (cfra - cfra1) / dfra, &pa->state, 1);
+ interp_qt_qtqt(pa->state.rot, keys[1].rot, keys[2].rot, (cfra - cfra1) / dfra);
- mul_v3_fl(pa->state.vel, 1.f / (dfra * timestep));
+ mul_v3_fl(pa->state.vel, 1.f / (dfra * timestep));
- pa->state.time = cfra;
+ pa->state.time = cfra;
}
-static int ptcache_particle_totpoint(void *psys_v, int UNUSED(cfra))
+static int ptcache_particle_totpoint(void *psys_v, int UNUSED(cfra))
{
- ParticleSystem *psys = psys_v;
- return psys->totpart;
+ ParticleSystem *psys = psys_v;
+ return psys->totpart;
}
static void ptcache_particle_error(void *UNUSED(psys_v), const char *UNUSED(message))
{
- /* ignored for now */
+ /* ignored for now */
}
-static int ptcache_particle_totwrite(void *psys_v, int cfra)
+static int ptcache_particle_totwrite(void *psys_v, int cfra)
{
- ParticleSystem *psys = psys_v;
- ParticleData *pa= psys->particles;
- int p, step = psys->pointcache->step;
- int totwrite = 0;
+ ParticleSystem *psys = psys_v;
+ ParticleData *pa = psys->particles;
+ int p, step = psys->pointcache->step;
+ int totwrite = 0;
- if (cfra == 0)
- return psys->totpart;
+ if (cfra == 0)
+ return psys->totpart;
- for (p=0; p<psys->totpart; p++, pa++)
- totwrite += (cfra >= pa->time - step && cfra <= pa->dietime + step);
+ for (p = 0; p < psys->totpart; p++, pa++)
+ totwrite += (cfra >= pa->time - step && cfra <= pa->dietime + step);
- return totwrite;
+ return totwrite;
}
static void ptcache_particle_extra_write(void *psys_v, PTCacheMem *pm, int UNUSED(cfra))
{
- ParticleSystem *psys = psys_v;
- PTCacheExtra *extra = NULL;
+ ParticleSystem *psys = psys_v;
+ PTCacheExtra *extra = NULL;
- if (psys->part->phystype == PART_PHYS_FLUID &&
- psys->part->fluid && psys->part->fluid->flag & SPH_VISCOELASTIC_SPRINGS &&
- psys->tot_fluidsprings && psys->fluid_springs)
- {
- extra = MEM_callocN(sizeof(PTCacheExtra), "Point cache: fluid extra data");
+ if (psys->part->phystype == PART_PHYS_FLUID && psys->part->fluid &&
+ psys->part->fluid->flag & SPH_VISCOELASTIC_SPRINGS && psys->tot_fluidsprings &&
+ psys->fluid_springs) {
+ extra = MEM_callocN(sizeof(PTCacheExtra), "Point cache: fluid extra data");
- extra->type = BPHYS_EXTRA_FLUID_SPRINGS;
- extra->totdata = psys->tot_fluidsprings;
+ extra->type = BPHYS_EXTRA_FLUID_SPRINGS;
+ extra->totdata = psys->tot_fluidsprings;
- extra->data = MEM_callocN(extra->totdata * ptcache_extra_datasize[extra->type], "Point cache: extra data");
- memcpy(extra->data, psys->fluid_springs, extra->totdata * ptcache_extra_datasize[extra->type]);
+ extra->data = MEM_callocN(extra->totdata * ptcache_extra_datasize[extra->type],
+ "Point cache: extra data");
+ memcpy(extra->data, psys->fluid_springs, extra->totdata * ptcache_extra_datasize[extra->type]);
- BLI_addtail(&pm->extradata, extra);
- }
+ BLI_addtail(&pm->extradata, extra);
+ }
}
static void ptcache_particle_extra_read(void *psys_v, PTCacheMem *pm, float UNUSED(cfra))
{
- ParticleSystem *psys = psys_v;
- PTCacheExtra *extra = pm->extradata.first;
-
- for (; extra; extra=extra->next) {
- switch (extra->type) {
- case BPHYS_EXTRA_FLUID_SPRINGS:
- {
- if (psys->fluid_springs)
- MEM_freeN(psys->fluid_springs);
-
- psys->fluid_springs = MEM_dupallocN(extra->data);
- psys->tot_fluidsprings = psys->alloc_fluidsprings = extra->totdata;
- break;
- }
- }
- }
+ ParticleSystem *psys = psys_v;
+ PTCacheExtra *extra = pm->extradata.first;
+
+ for (; extra; extra = extra->next) {
+ switch (extra->type) {
+ case BPHYS_EXTRA_FLUID_SPRINGS: {
+ if (psys->fluid_springs)
+ MEM_freeN(psys->fluid_springs);
+
+ psys->fluid_springs = MEM_dupallocN(extra->data);
+ psys->tot_fluidsprings = psys->alloc_fluidsprings = extra->totdata;
+ break;
+ }
+ }
+ }
}
/* Cloth functions */
-static int ptcache_cloth_write(int index, void *cloth_v, void **data, int UNUSED(cfra))
+static int ptcache_cloth_write(int index, void *cloth_v, void **data, int UNUSED(cfra))
{
- ClothModifierData *clmd= cloth_v;
- Cloth *cloth= clmd->clothObject;
- ClothVertex *vert = cloth->verts + index;
+ ClothModifierData *clmd = cloth_v;
+ Cloth *cloth = clmd->clothObject;
+ ClothVertex *vert = cloth->verts + index;
- PTCACHE_DATA_FROM(data, BPHYS_DATA_LOCATION, vert->x);
- PTCACHE_DATA_FROM(data, BPHYS_DATA_VELOCITY, vert->v);
- PTCACHE_DATA_FROM(data, BPHYS_DATA_XCONST, vert->xconst);
+ PTCACHE_DATA_FROM(data, BPHYS_DATA_LOCATION, vert->x);
+ PTCACHE_DATA_FROM(data, BPHYS_DATA_VELOCITY, vert->v);
+ PTCACHE_DATA_FROM(data, BPHYS_DATA_XCONST, vert->xconst);
- return 1;
+ return 1;
}
-static void ptcache_cloth_read(int index, void *cloth_v, void **data, float UNUSED(cfra), float *old_data)
+static void ptcache_cloth_read(
+ int index, void *cloth_v, void **data, float UNUSED(cfra), float *old_data)
{
- ClothModifierData *clmd= cloth_v;
- Cloth *cloth= clmd->clothObject;
- ClothVertex *vert = cloth->verts + index;
-
- if (old_data) {
- memcpy(vert->x, data, 3 * sizeof(float));
- memcpy(vert->xconst, data + 3, 3 * sizeof(float));
- memcpy(vert->v, data + 6, 3 * sizeof(float));
- }
- else {
- PTCACHE_DATA_TO(data, BPHYS_DATA_LOCATION, 0, vert->x);
- PTCACHE_DATA_TO(data, BPHYS_DATA_VELOCITY, 0, vert->v);
- PTCACHE_DATA_TO(data, BPHYS_DATA_XCONST, 0, vert->xconst);
- }
+ ClothModifierData *clmd = cloth_v;
+ Cloth *cloth = clmd->clothObject;
+ ClothVertex *vert = cloth->verts + index;
+
+ if (old_data) {
+ memcpy(vert->x, data, 3 * sizeof(float));
+ memcpy(vert->xconst, data + 3, 3 * sizeof(float));
+ memcpy(vert->v, data + 6, 3 * sizeof(float));
+ }
+ else {
+ PTCACHE_DATA_TO(data, BPHYS_DATA_LOCATION, 0, vert->x);
+ PTCACHE_DATA_TO(data, BPHYS_DATA_VELOCITY, 0, vert->v);
+ PTCACHE_DATA_TO(data, BPHYS_DATA_XCONST, 0, vert->xconst);
+ }
}
-static void ptcache_cloth_interpolate(int index, void *cloth_v, void **data, float cfra, float cfra1, float cfra2, float *old_data)
+static void ptcache_cloth_interpolate(
+ int index, void *cloth_v, void **data, float cfra, float cfra1, float cfra2, float *old_data)
{
- ClothModifierData *clmd= cloth_v;
- Cloth *cloth= clmd->clothObject;
- ClothVertex *vert = cloth->verts + index;
- ParticleKey keys[4];
- float dfra;
+ ClothModifierData *clmd = cloth_v;
+ Cloth *cloth = clmd->clothObject;
+ ClothVertex *vert = cloth->verts + index;
+ ParticleKey keys[4];
+ float dfra;
- if (cfra1 == cfra2)
- return;
+ if (cfra1 == cfra2)
+ return;
- copy_v3_v3(keys[1].co, vert->x);
- copy_v3_v3(keys[1].vel, vert->v);
+ copy_v3_v3(keys[1].co, vert->x);
+ copy_v3_v3(keys[1].vel, vert->v);
- if (old_data) {
- memcpy(keys[2].co, old_data, 3 * sizeof(float));
- memcpy(keys[2].vel, old_data + 6, 3 * sizeof(float));
- }
- else
- BKE_ptcache_make_particle_key(keys+2, 0, data, cfra2);
+ if (old_data) {
+ memcpy(keys[2].co, old_data, 3 * sizeof(float));
+ memcpy(keys[2].vel, old_data + 6, 3 * sizeof(float));
+ }
+ else
+ BKE_ptcache_make_particle_key(keys + 2, 0, data, cfra2);
- dfra = cfra2 - cfra1;
+ dfra = cfra2 - cfra1;
- mul_v3_fl(keys[1].vel, dfra);
- mul_v3_fl(keys[2].vel, dfra);
+ mul_v3_fl(keys[1].vel, dfra);
+ mul_v3_fl(keys[2].vel, dfra);
- psys_interpolate_particle(-1, keys, (cfra - cfra1) / dfra, keys, 1);
+ psys_interpolate_particle(-1, keys, (cfra - cfra1) / dfra, keys, 1);
- mul_v3_fl(keys->vel, 1.0f / dfra);
+ mul_v3_fl(keys->vel, 1.0f / dfra);
- copy_v3_v3(vert->x, keys->co);
- copy_v3_v3(vert->v, keys->vel);
+ copy_v3_v3(vert->x, keys->co);
+ copy_v3_v3(vert->v, keys->vel);
- /* should vert->xconst be interpolated somehow too? - jahka */
+ /* should vert->xconst be interpolated somehow too? - jahka */
}
-static int ptcache_cloth_totpoint(void *cloth_v, int UNUSED(cfra))
+static int ptcache_cloth_totpoint(void *cloth_v, int UNUSED(cfra))
{
- ClothModifierData *clmd= cloth_v;
- return clmd->clothObject ? clmd->clothObject->mvert_num : 0;
+ ClothModifierData *clmd = cloth_v;
+ return clmd->clothObject ? clmd->clothObject->mvert_num : 0;
}
static void ptcache_cloth_error(void *cloth_v, const char *message)
{
- ClothModifierData *clmd= cloth_v;
- modifier_setError(&clmd->modifier, "%s", message);
+ ClothModifierData *clmd = cloth_v;
+ modifier_setError(&clmd->modifier, "%s", message);
}
#ifdef WITH_SMOKE
/* Smoke functions */
-static int ptcache_smoke_totpoint(void *smoke_v, int UNUSED(cfra))
+static int ptcache_smoke_totpoint(void *smoke_v, int UNUSED(cfra))
{
- SmokeModifierData *smd= (SmokeModifierData *)smoke_v;
- SmokeDomainSettings *sds = smd->domain;
-
- if (sds->fluid) {
- return sds->base_res[0]*sds->base_res[1]*sds->base_res[2];
- }
- else
- return 0;
+ SmokeModifierData *smd = (SmokeModifierData *)smoke_v;
+ SmokeDomainSettings *sds = smd->domain;
+
+ if (sds->fluid) {
+ return sds->base_res[0] * sds->base_res[1] * sds->base_res[2];
+ }
+ else
+ return 0;
}
static void ptcache_smoke_error(void *smoke_v, const char *message)
{
- SmokeModifierData *smd= (SmokeModifierData *)smoke_v;
- modifier_setError(&smd->modifier, "%s", message);
+ SmokeModifierData *smd = (SmokeModifierData *)smoke_v;
+ modifier_setError(&smd->modifier, "%s", message);
}
-#define SMOKE_CACHE_VERSION "1.04"
+# define SMOKE_CACHE_VERSION "1.04"
-static int ptcache_smoke_write(PTCacheFile *pf, void *smoke_v)
+static int ptcache_smoke_write(PTCacheFile *pf, void *smoke_v)
{
- SmokeModifierData *smd= (SmokeModifierData *)smoke_v;
- SmokeDomainSettings *sds = smd->domain;
- int ret = 0;
- int fluid_fields = BKE_smoke_get_data_flags(sds);
-
- /* version header */
- ptcache_file_write(pf, SMOKE_CACHE_VERSION, 4, sizeof(char));
- ptcache_file_write(pf, &fluid_fields, 1, sizeof(int));
- ptcache_file_write(pf, &sds->active_fields, 1, sizeof(int));
- ptcache_file_write(pf, &sds->res, 3, sizeof(int));
- ptcache_file_write(pf, &sds->dx, 1, sizeof(float));
-
- if (sds->fluid) {
- size_t res = sds->res[0]*sds->res[1]*sds->res[2];
- float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b;
- unsigned char *obstacles;
- unsigned int in_len = sizeof(float)*(unsigned int)res;
- unsigned char *out = (unsigned char *)MEM_callocN(LZO_OUT_LEN(in_len) * 4, "pointcache_lzo_buffer");
- //int mode = res >= 1000000 ? 2 : 1;
- int mode=1; // light
- if (sds->cache_comp == SM_CACHE_HEAVY) mode=2; // heavy
-
- smoke_export(sds->fluid, &dt, &dx, &dens, &react, &flame, &fuel, &heat, &heatold, &vx, &vy, &vz, &r, &g, &b, &obstacles);
-
- ptcache_file_compressed_write(pf, (unsigned char *)sds->shadow, in_len, out, mode);
- ptcache_file_compressed_write(pf, (unsigned char *)dens, in_len, out, mode);
- if (fluid_fields & SM_ACTIVE_HEAT) {
- ptcache_file_compressed_write(pf, (unsigned char *)heat, in_len, out, mode);
- ptcache_file_compressed_write(pf, (unsigned char *)heatold, in_len, out, mode);
- }
- if (fluid_fields & SM_ACTIVE_FIRE) {
- ptcache_file_compressed_write(pf, (unsigned char *)flame, in_len, out, mode);
- ptcache_file_compressed_write(pf, (unsigned char *)fuel, in_len, out, mode);
- ptcache_file_compressed_write(pf, (unsigned char *)react, in_len, out, mode);
- }
- if (fluid_fields & SM_ACTIVE_COLORS) {
- ptcache_file_compressed_write(pf, (unsigned char *)r, in_len, out, mode);
- ptcache_file_compressed_write(pf, (unsigned char *)g, in_len, out, mode);
- ptcache_file_compressed_write(pf, (unsigned char *)b, in_len, out, mode);
- }
- ptcache_file_compressed_write(pf, (unsigned char *)vx, in_len, out, mode);
- ptcache_file_compressed_write(pf, (unsigned char *)vy, in_len, out, mode);
- ptcache_file_compressed_write(pf, (unsigned char *)vz, in_len, out, mode);
- ptcache_file_compressed_write(pf, (unsigned char *)obstacles, (unsigned int)res, out, mode);
- ptcache_file_write(pf, &dt, 1, sizeof(float));
- ptcache_file_write(pf, &dx, 1, sizeof(float));
- ptcache_file_write(pf, &sds->p0, 3, sizeof(float));
- ptcache_file_write(pf, &sds->p1, 3, sizeof(float));
- ptcache_file_write(pf, &sds->dp0, 3, sizeof(float));
- ptcache_file_write(pf, &sds->shift, 3, sizeof(int));
- ptcache_file_write(pf, &sds->obj_shift_f, 3, sizeof(float));
- ptcache_file_write(pf, &sds->obmat, 16, sizeof(float));
- ptcache_file_write(pf, &sds->base_res, 3, sizeof(int));
- ptcache_file_write(pf, &sds->res_min, 3, sizeof(int));
- ptcache_file_write(pf, &sds->res_max, 3, sizeof(int));
- ptcache_file_write(pf, &sds->active_color, 3, sizeof(float));
-
- MEM_freeN(out);
-
- ret = 1;
- }
-
- if (sds->wt) {
- int res_big_array[3];
- int res_big;
- int res = sds->res[0]*sds->res[1]*sds->res[2];
- float *dens, *react, *fuel, *flame, *tcu, *tcv, *tcw, *r, *g, *b;
- unsigned int in_len = sizeof(float)*(unsigned int)res;
- unsigned int in_len_big;
- unsigned char *out;
- int mode;
-
- smoke_turbulence_get_res(sds->wt, res_big_array);
- res_big = res_big_array[0]*res_big_array[1]*res_big_array[2];
- //mode = res_big >= 1000000 ? 2 : 1;
- mode = 1; // light
- if (sds->cache_high_comp == SM_CACHE_HEAVY) mode=2; // heavy
-
- in_len_big = sizeof(float) * (unsigned int)res_big;
-
- smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
-
- out = (unsigned char *)MEM_callocN(LZO_OUT_LEN(in_len_big), "pointcache_lzo_buffer");
- ptcache_file_compressed_write(pf, (unsigned char *)dens, in_len_big, out, mode);
- if (fluid_fields & SM_ACTIVE_FIRE) {
- ptcache_file_compressed_write(pf, (unsigned char *)flame, in_len_big, out, mode);
- ptcache_file_compressed_write(pf, (unsigned char *)fuel, in_len_big, out, mode);
- ptcache_file_compressed_write(pf, (unsigned char *)react, in_len_big, out, mode);
- }
- if (fluid_fields & SM_ACTIVE_COLORS) {
- ptcache_file_compressed_write(pf, (unsigned char *)r, in_len_big, out, mode);
- ptcache_file_compressed_write(pf, (unsigned char *)g, in_len_big, out, mode);
- ptcache_file_compressed_write(pf, (unsigned char *)b, in_len_big, out, mode);
- }
- MEM_freeN(out);
-
- out = (unsigned char *)MEM_callocN(LZO_OUT_LEN(in_len), "pointcache_lzo_buffer");
- ptcache_file_compressed_write(pf, (unsigned char *)tcu, in_len, out, mode);
- ptcache_file_compressed_write(pf, (unsigned char *)tcv, in_len, out, mode);
- ptcache_file_compressed_write(pf, (unsigned char *)tcw, in_len, out, mode);
- MEM_freeN(out);
-
- ret = 1;
- }
-
- return ret;
+ SmokeModifierData *smd = (SmokeModifierData *)smoke_v;
+ SmokeDomainSettings *sds = smd->domain;
+ int ret = 0;
+ int fluid_fields = BKE_smoke_get_data_flags(sds);
+
+ /* version header */
+ ptcache_file_write(pf, SMOKE_CACHE_VERSION, 4, sizeof(char));
+ ptcache_file_write(pf, &fluid_fields, 1, sizeof(int));
+ ptcache_file_write(pf, &sds->active_fields, 1, sizeof(int));
+ ptcache_file_write(pf, &sds->res, 3, sizeof(int));
+ ptcache_file_write(pf, &sds->dx, 1, sizeof(float));
+
+ if (sds->fluid) {
+ size_t res = sds->res[0] * sds->res[1] * sds->res[2];
+ float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b;
+ unsigned char *obstacles;
+ unsigned int in_len = sizeof(float) * (unsigned int)res;
+ unsigned char *out = (unsigned char *)MEM_callocN(LZO_OUT_LEN(in_len) * 4,
+ "pointcache_lzo_buffer");
+ //int mode = res >= 1000000 ? 2 : 1;
+ int mode = 1; // light
+ if (sds->cache_comp == SM_CACHE_HEAVY)
+ mode = 2; // heavy
+
+ smoke_export(sds->fluid,
+ &dt,
+ &dx,
+ &dens,
+ &react,
+ &flame,
+ &fuel,
+ &heat,
+ &heatold,
+ &vx,
+ &vy,
+ &vz,
+ &r,
+ &g,
+ &b,
+ &obstacles);
+
+ ptcache_file_compressed_write(pf, (unsigned char *)sds->shadow, in_len, out, mode);
+ ptcache_file_compressed_write(pf, (unsigned char *)dens, in_len, out, mode);
+ if (fluid_fields & SM_ACTIVE_HEAT) {
+ ptcache_file_compressed_write(pf, (unsigned char *)heat, in_len, out, mode);
+ ptcache_file_compressed_write(pf, (unsigned char *)heatold, in_len, out, mode);
+ }
+ if (fluid_fields & SM_ACTIVE_FIRE) {
+ ptcache_file_compressed_write(pf, (unsigned char *)flame, in_len, out, mode);
+ ptcache_file_compressed_write(pf, (unsigned char *)fuel, in_len, out, mode);
+ ptcache_file_compressed_write(pf, (unsigned char *)react, in_len, out, mode);
+ }
+ if (fluid_fields & SM_ACTIVE_COLORS) {
+ ptcache_file_compressed_write(pf, (unsigned char *)r, in_len, out, mode);
+ ptcache_file_compressed_write(pf, (unsigned char *)g, in_len, out, mode);
+ ptcache_file_compressed_write(pf, (unsigned char *)b, in_len, out, mode);
+ }
+ ptcache_file_compressed_write(pf, (unsigned char *)vx, in_len, out, mode);
+ ptcache_file_compressed_write(pf, (unsigned char *)vy, in_len, out, mode);
+ ptcache_file_compressed_write(pf, (unsigned char *)vz, in_len, out, mode);
+ ptcache_file_compressed_write(pf, (unsigned char *)obstacles, (unsigned int)res, out, mode);
+ ptcache_file_write(pf, &dt, 1, sizeof(float));
+ ptcache_file_write(pf, &dx, 1, sizeof(float));
+ ptcache_file_write(pf, &sds->p0, 3, sizeof(float));
+ ptcache_file_write(pf, &sds->p1, 3, sizeof(float));
+ ptcache_file_write(pf, &sds->dp0, 3, sizeof(float));
+ ptcache_file_write(pf, &sds->shift, 3, sizeof(int));
+ ptcache_file_write(pf, &sds->obj_shift_f, 3, sizeof(float));
+ ptcache_file_write(pf, &sds->obmat, 16, sizeof(float));
+ ptcache_file_write(pf, &sds->base_res, 3, sizeof(int));
+ ptcache_file_write(pf, &sds->res_min, 3, sizeof(int));
+ ptcache_file_write(pf, &sds->res_max, 3, sizeof(int));
+ ptcache_file_write(pf, &sds->active_color, 3, sizeof(float));
+
+ MEM_freeN(out);
+
+ ret = 1;
+ }
+
+ if (sds->wt) {
+ int res_big_array[3];
+ int res_big;
+ int res = sds->res[0] * sds->res[1] * sds->res[2];
+ float *dens, *react, *fuel, *flame, *tcu, *tcv, *tcw, *r, *g, *b;
+ unsigned int in_len = sizeof(float) * (unsigned int)res;
+ unsigned int in_len_big;
+ unsigned char *out;
+ int mode;
+
+ smoke_turbulence_get_res(sds->wt, res_big_array);
+ res_big = res_big_array[0] * res_big_array[1] * res_big_array[2];
+ //mode = res_big >= 1000000 ? 2 : 1;
+ mode = 1; // light
+ if (sds->cache_high_comp == SM_CACHE_HEAVY)
+ mode = 2; // heavy
+
+ in_len_big = sizeof(float) * (unsigned int)res_big;
+
+ smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
+
+ out = (unsigned char *)MEM_callocN(LZO_OUT_LEN(in_len_big), "pointcache_lzo_buffer");
+ ptcache_file_compressed_write(pf, (unsigned char *)dens, in_len_big, out, mode);
+ if (fluid_fields & SM_ACTIVE_FIRE) {
+ ptcache_file_compressed_write(pf, (unsigned char *)flame, in_len_big, out, mode);
+ ptcache_file_compressed_write(pf, (unsigned char *)fuel, in_len_big, out, mode);
+ ptcache_file_compressed_write(pf, (unsigned char *)react, in_len_big, out, mode);
+ }
+ if (fluid_fields & SM_ACTIVE_COLORS) {
+ ptcache_file_compressed_write(pf, (unsigned char *)r, in_len_big, out, mode);
+ ptcache_file_compressed_write(pf, (unsigned char *)g, in_len_big, out, mode);
+ ptcache_file_compressed_write(pf, (unsigned char *)b, in_len_big, out, mode);
+ }
+ MEM_freeN(out);
+
+ out = (unsigned char *)MEM_callocN(LZO_OUT_LEN(in_len), "pointcache_lzo_buffer");
+ ptcache_file_compressed_write(pf, (unsigned char *)tcu, in_len, out, mode);
+ ptcache_file_compressed_write(pf, (unsigned char *)tcv, in_len, out, mode);
+ ptcache_file_compressed_write(pf, (unsigned char *)tcw, in_len, out, mode);
+ MEM_freeN(out);
+
+ ret = 1;
+ }
+
+ return ret;
}
/* read old smoke cache from 2.64 */
static int ptcache_smoke_read_old(PTCacheFile *pf, void *smoke_v)
{
- SmokeModifierData *smd= (SmokeModifierData *)smoke_v;
- SmokeDomainSettings *sds = smd->domain;
-
- if (sds->fluid) {
- const size_t res = sds->res[0] * sds->res[1] * sds->res[2];
- const unsigned int out_len = (unsigned int)res * sizeof(float);
- float dt, dx, *dens, *heat, *heatold, *vx, *vy, *vz;
- unsigned char *obstacles;
- float *tmp_array = MEM_callocN(out_len, "Smoke old cache tmp");
-
- int fluid_fields = BKE_smoke_get_data_flags(sds);
-
- /* Part part of the new cache header */
- sds->active_color[0] = 0.7f;
- sds->active_color[1] = 0.7f;
- sds->active_color[2] = 0.7f;
-
- smoke_export(sds->fluid, &dt, &dx, &dens, NULL, NULL, NULL, &heat, &heatold, &vx, &vy, &vz, NULL, NULL, NULL, &obstacles);
-
- ptcache_file_compressed_read(pf, (unsigned char *)sds->shadow, out_len);
- ptcache_file_compressed_read(pf, (unsigned char*)dens, out_len);
- ptcache_file_compressed_read(pf, (unsigned char*)tmp_array, out_len);
-
- if (fluid_fields & SM_ACTIVE_HEAT)
- {
- ptcache_file_compressed_read(pf, (unsigned char*)heat, out_len);
- ptcache_file_compressed_read(pf, (unsigned char*)heatold, out_len);
- }
- else
- {
- ptcache_file_compressed_read(pf, (unsigned char*)tmp_array, out_len);
- ptcache_file_compressed_read(pf, (unsigned char*)tmp_array, out_len);
- }
- ptcache_file_compressed_read(pf, (unsigned char*)vx, out_len);
- ptcache_file_compressed_read(pf, (unsigned char*)vy, out_len);
- ptcache_file_compressed_read(pf, (unsigned char*)vz, out_len);
- ptcache_file_compressed_read(pf, (unsigned char*)tmp_array, out_len);
- ptcache_file_compressed_read(pf, (unsigned char*)tmp_array, out_len);
- ptcache_file_compressed_read(pf, (unsigned char*)tmp_array, out_len);
- ptcache_file_compressed_read(pf, (unsigned char*)obstacles, (unsigned int)res);
- ptcache_file_read(pf, &dt, 1, sizeof(float));
- ptcache_file_read(pf, &dx, 1, sizeof(float));
-
- MEM_freeN(tmp_array);
-
- if (pf->data_types & (1<<BPHYS_DATA_SMOKE_HIGH) && sds->wt) {
- int res_big, res_big_array[3];
- float *tcu, *tcv, *tcw;
- unsigned int out_len_big;
- unsigned char *tmp_array_big;
- smoke_turbulence_get_res(sds->wt, res_big_array);
- res_big = res_big_array[0]*res_big_array[1]*res_big_array[2];
- out_len_big = sizeof(float) * (unsigned int)res_big;
-
- tmp_array_big = MEM_callocN(out_len_big, "Smoke old cache tmp");
-
- smoke_turbulence_export(sds->wt, &dens, NULL, NULL, NULL, NULL, NULL, NULL, &tcu, &tcv, &tcw);
-
- ptcache_file_compressed_read(pf, (unsigned char*)dens, out_len_big);
- ptcache_file_compressed_read(pf, (unsigned char*)tmp_array_big, out_len_big);
-
- ptcache_file_compressed_read(pf, (unsigned char*)tcu, out_len);
- ptcache_file_compressed_read(pf, (unsigned char*)tcv, out_len);
- ptcache_file_compressed_read(pf, (unsigned char*)tcw, out_len);
-
- MEM_freeN(tmp_array_big);
- }
- }
-
- return 1;
+ SmokeModifierData *smd = (SmokeModifierData *)smoke_v;
+ SmokeDomainSettings *sds = smd->domain;
+
+ if (sds->fluid) {
+ const size_t res = sds->res[0] * sds->res[1] * sds->res[2];
+ const unsigned int out_len = (unsigned int)res * sizeof(float);
+ float dt, dx, *dens, *heat, *heatold, *vx, *vy, *vz;
+ unsigned char *obstacles;
+ float *tmp_array = MEM_callocN(out_len, "Smoke old cache tmp");
+
+ int fluid_fields = BKE_smoke_get_data_flags(sds);
+
+ /* Part part of the new cache header */
+ sds->active_color[0] = 0.7f;
+ sds->active_color[1] = 0.7f;
+ sds->active_color[2] = 0.7f;
+
+ smoke_export(sds->fluid,
+ &dt,
+ &dx,
+ &dens,
+ NULL,
+ NULL,
+ NULL,
+ &heat,
+ &heatold,
+ &vx,
+ &vy,
+ &vz,
+ NULL,
+ NULL,
+ NULL,
+ &obstacles);
+
+ ptcache_file_compressed_read(pf, (unsigned char *)sds->shadow, out_len);
+ ptcache_file_compressed_read(pf, (unsigned char *)dens, out_len);
+ ptcache_file_compressed_read(pf, (unsigned char *)tmp_array, out_len);
+
+ if (fluid_fields & SM_ACTIVE_HEAT) {
+ ptcache_file_compressed_read(pf, (unsigned char *)heat, out_len);
+ ptcache_file_compressed_read(pf, (unsigned char *)heatold, out_len);
+ }
+ else {
+ ptcache_file_compressed_read(pf, (unsigned char *)tmp_array, out_len);
+ ptcache_file_compressed_read(pf, (unsigned char *)tmp_array, out_len);
+ }
+ ptcache_file_compressed_read(pf, (unsigned char *)vx, out_len);
+ ptcache_file_compressed_read(pf, (unsigned char *)vy, out_len);
+ ptcache_file_compressed_read(pf, (unsigned char *)vz, out_len);
+ ptcache_file_compressed_read(pf, (unsigned char *)tmp_array, out_len);
+ ptcache_file_compressed_read(pf, (unsigned char *)tmp_array, out_len);
+ ptcache_file_compressed_read(pf, (unsigned char *)tmp_array, out_len);
+ ptcache_file_compressed_read(pf, (unsigned char *)obstacles, (unsigned int)res);
+ ptcache_file_read(pf, &dt, 1, sizeof(float));
+ ptcache_file_read(pf, &dx, 1, sizeof(float));
+
+ MEM_freeN(tmp_array);
+
+ if (pf->data_types & (1 << BPHYS_DATA_SMOKE_HIGH) && sds->wt) {
+ int res_big, res_big_array[3];
+ float *tcu, *tcv, *tcw;
+ unsigned int out_len_big;
+ unsigned char *tmp_array_big;
+ smoke_turbulence_get_res(sds->wt, res_big_array);
+ res_big = res_big_array[0] * res_big_array[1] * res_big_array[2];
+ out_len_big = sizeof(float) * (unsigned int)res_big;
+
+ tmp_array_big = MEM_callocN(out_len_big, "Smoke old cache tmp");
+
+ smoke_turbulence_export(
+ sds->wt, &dens, NULL, NULL, NULL, NULL, NULL, NULL, &tcu, &tcv, &tcw);
+
+ ptcache_file_compressed_read(pf, (unsigned char *)dens, out_len_big);
+ ptcache_file_compressed_read(pf, (unsigned char *)tmp_array_big, out_len_big);
+
+ ptcache_file_compressed_read(pf, (unsigned char *)tcu, out_len);
+ ptcache_file_compressed_read(pf, (unsigned char *)tcv, out_len);
+ ptcache_file_compressed_read(pf, (unsigned char *)tcw, out_len);
+
+ MEM_freeN(tmp_array_big);
+ }
+ }
+
+ return 1;
}
static int ptcache_smoke_read(PTCacheFile *pf, void *smoke_v)
{
- SmokeModifierData *smd= (SmokeModifierData *)smoke_v;
- SmokeDomainSettings *sds = smd->domain;
- char version[4];
- int ch_res[3];
- float ch_dx;
- int fluid_fields = BKE_smoke_get_data_flags(sds);
- int cache_fields = 0;
- int active_fields = 0;
- int reallocate = 0;
-
- /* version header */
- ptcache_file_read(pf, version, 4, sizeof(char));
- if (!STREQLEN(version, SMOKE_CACHE_VERSION, 4))
- {
- /* reset file pointer */
- fseek(pf->fp, -4, SEEK_CUR);
- return ptcache_smoke_read_old(pf, smoke_v);
- }
-
- /* fluid info */
- ptcache_file_read(pf, &cache_fields, 1, sizeof(int));
- ptcache_file_read(pf, &active_fields, 1, sizeof(int));
- ptcache_file_read(pf, &ch_res, 3, sizeof(int));
- ptcache_file_read(pf, &ch_dx, 1, sizeof(float));
-
- /* check if resolution has changed */
- if (sds->res[0] != ch_res[0] ||
- sds->res[1] != ch_res[1] ||
- sds->res[2] != ch_res[2])
- {
- if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN)
- reallocate = 1;
- else
- return 0;
- }
- /* check if active fields have changed */
- if (fluid_fields != cache_fields ||
- active_fields != sds->active_fields)
- reallocate = 1;
-
- /* reallocate fluid if needed*/
- if (reallocate) {
- sds->active_fields = active_fields | cache_fields;
- BKE_smoke_reallocate_fluid(sds, ch_dx, ch_res, 1);
- sds->dx = ch_dx;
- copy_v3_v3_int(sds->res, ch_res);
- sds->total_cells = ch_res[0]*ch_res[1]*ch_res[2];
- if (sds->flags & MOD_SMOKE_HIGHRES) {
- BKE_smoke_reallocate_highres_fluid(sds, ch_dx, ch_res, 1);
- }
- }
-
- if (sds->fluid) {
- size_t res = sds->res[0]*sds->res[1]*sds->res[2];
- float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b;
- unsigned char *obstacles;
- unsigned int out_len = (unsigned int)res * sizeof(float);
-
- smoke_export(sds->fluid, &dt, &dx, &dens, &react, &flame, &fuel, &heat, &heatold, &vx, &vy, &vz, &r, &g, &b, &obstacles);
-
- ptcache_file_compressed_read(pf, (unsigned char *)sds->shadow, out_len);
- ptcache_file_compressed_read(pf, (unsigned char *)dens, out_len);
- if (cache_fields & SM_ACTIVE_HEAT) {
- ptcache_file_compressed_read(pf, (unsigned char *)heat, out_len);
- ptcache_file_compressed_read(pf, (unsigned char *)heatold, out_len);
- }
- if (cache_fields & SM_ACTIVE_FIRE) {
- ptcache_file_compressed_read(pf, (unsigned char *)flame, out_len);
- ptcache_file_compressed_read(pf, (unsigned char *)fuel, out_len);
- ptcache_file_compressed_read(pf, (unsigned char *)react, out_len);
- }
- if (cache_fields & SM_ACTIVE_COLORS) {
- ptcache_file_compressed_read(pf, (unsigned char *)r, out_len);
- ptcache_file_compressed_read(pf, (unsigned char *)g, out_len);
- ptcache_file_compressed_read(pf, (unsigned char *)b, out_len);
- }
- ptcache_file_compressed_read(pf, (unsigned char *)vx, out_len);
- ptcache_file_compressed_read(pf, (unsigned char *)vy, out_len);
- ptcache_file_compressed_read(pf, (unsigned char *)vz, out_len);
- ptcache_file_compressed_read(pf, (unsigned char *)obstacles, (unsigned int)res);
- ptcache_file_read(pf, &dt, 1, sizeof(float));
- ptcache_file_read(pf, &dx, 1, sizeof(float));
- ptcache_file_read(pf, &sds->p0, 3, sizeof(float));
- ptcache_file_read(pf, &sds->p1, 3, sizeof(float));
- ptcache_file_read(pf, &sds->dp0, 3, sizeof(float));
- ptcache_file_read(pf, &sds->shift, 3, sizeof(int));
- ptcache_file_read(pf, &sds->obj_shift_f, 3, sizeof(float));
- ptcache_file_read(pf, &sds->obmat, 16, sizeof(float));
- ptcache_file_read(pf, &sds->base_res, 3, sizeof(int));
- ptcache_file_read(pf, &sds->res_min, 3, sizeof(int));
- ptcache_file_read(pf, &sds->res_max, 3, sizeof(int));
- ptcache_file_read(pf, &sds->active_color, 3, sizeof(float));
- }
-
- if (pf->data_types & (1<<BPHYS_DATA_SMOKE_HIGH) && sds->wt) {
- int res = sds->res[0]*sds->res[1]*sds->res[2];
- int res_big, res_big_array[3];
- float *dens, *react, *fuel, *flame, *tcu, *tcv, *tcw, *r, *g, *b;
- unsigned int out_len = sizeof(float)*(unsigned int)res;
- unsigned int out_len_big;
-
- smoke_turbulence_get_res(sds->wt, res_big_array);
- res_big = res_big_array[0]*res_big_array[1]*res_big_array[2];
- out_len_big = sizeof(float) * (unsigned int)res_big;
-
- smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
-
- ptcache_file_compressed_read(pf, (unsigned char *)dens, out_len_big);
- if (cache_fields & SM_ACTIVE_FIRE) {
- ptcache_file_compressed_read(pf, (unsigned char *)flame, out_len_big);
- ptcache_file_compressed_read(pf, (unsigned char *)fuel, out_len_big);
- ptcache_file_compressed_read(pf, (unsigned char *)react, out_len_big);
- }
- if (cache_fields & SM_ACTIVE_COLORS) {
- ptcache_file_compressed_read(pf, (unsigned char *)r, out_len_big);
- ptcache_file_compressed_read(pf, (unsigned char *)g, out_len_big);
- ptcache_file_compressed_read(pf, (unsigned char *)b, out_len_big);
- }
-
- ptcache_file_compressed_read(pf, (unsigned char *)tcu, out_len);
- ptcache_file_compressed_read(pf, (unsigned char *)tcv, out_len);
- ptcache_file_compressed_read(pf, (unsigned char *)tcw, out_len);
- }
-
- return 1;
+ SmokeModifierData *smd = (SmokeModifierData *)smoke_v;
+ SmokeDomainSettings *sds = smd->domain;
+ char version[4];
+ int ch_res[3];
+ float ch_dx;
+ int fluid_fields = BKE_smoke_get_data_flags(sds);
+ int cache_fields = 0;
+ int active_fields = 0;
+ int reallocate = 0;
+
+ /* version header */
+ ptcache_file_read(pf, version, 4, sizeof(char));
+ if (!STREQLEN(version, SMOKE_CACHE_VERSION, 4)) {
+ /* reset file pointer */
+ fseek(pf->fp, -4, SEEK_CUR);
+ return ptcache_smoke_read_old(pf, smoke_v);
+ }
+
+ /* fluid info */
+ ptcache_file_read(pf, &cache_fields, 1, sizeof(int));
+ ptcache_file_read(pf, &active_fields, 1, sizeof(int));
+ ptcache_file_read(pf, &ch_res, 3, sizeof(int));
+ ptcache_file_read(pf, &ch_dx, 1, sizeof(float));
+
+ /* check if resolution has changed */
+ if (sds->res[0] != ch_res[0] || sds->res[1] != ch_res[1] || sds->res[2] != ch_res[2]) {
+ if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN)
+ reallocate = 1;
+ else
+ return 0;
+ }
+ /* check if active fields have changed */
+ if (fluid_fields != cache_fields || active_fields != sds->active_fields)
+ reallocate = 1;
+
+ /* reallocate fluid if needed*/
+ if (reallocate) {
+ sds->active_fields = active_fields | cache_fields;
+ BKE_smoke_reallocate_fluid(sds, ch_dx, ch_res, 1);
+ sds->dx = ch_dx;
+ copy_v3_v3_int(sds->res, ch_res);
+ sds->total_cells = ch_res[0] * ch_res[1] * ch_res[2];
+ if (sds->flags & MOD_SMOKE_HIGHRES) {
+ BKE_smoke_reallocate_highres_fluid(sds, ch_dx, ch_res, 1);
+ }
+ }
+
+ if (sds->fluid) {
+ size_t res = sds->res[0] * sds->res[1] * sds->res[2];
+ float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b;
+ unsigned char *obstacles;
+ unsigned int out_len = (unsigned int)res * sizeof(float);
+
+ smoke_export(sds->fluid,
+ &dt,
+ &dx,
+ &dens,
+ &react,
+ &flame,
+ &fuel,
+ &heat,
+ &heatold,
+ &vx,
+ &vy,
+ &vz,
+ &r,
+ &g,
+ &b,
+ &obstacles);
+
+ ptcache_file_compressed_read(pf, (unsigned char *)sds->shadow, out_len);
+ ptcache_file_compressed_read(pf, (unsigned char *)dens, out_len);
+ if (cache_fields & SM_ACTIVE_HEAT) {
+ ptcache_file_compressed_read(pf, (unsigned char *)heat, out_len);
+ ptcache_file_compressed_read(pf, (unsigned char *)heatold, out_len);
+ }
+ if (cache_fields & SM_ACTIVE_FIRE) {
+ ptcache_file_compressed_read(pf, (unsigned char *)flame, out_len);
+ ptcache_file_compressed_read(pf, (unsigned char *)fuel, out_len);
+ ptcache_file_compressed_read(pf, (unsigned char *)react, out_len);
+ }
+ if (cache_fields & SM_ACTIVE_COLORS) {
+ ptcache_file_compressed_read(pf, (unsigned char *)r, out_len);
+ ptcache_file_compressed_read(pf, (unsigned char *)g, out_len);
+ ptcache_file_compressed_read(pf, (unsigned char *)b, out_len);
+ }
+ ptcache_file_compressed_read(pf, (unsigned char *)vx, out_len);
+ ptcache_file_compressed_read(pf, (unsigned char *)vy, out_len);
+ ptcache_file_compressed_read(pf, (unsigned char *)vz, out_len);
+ ptcache_file_compressed_read(pf, (unsigned char *)obstacles, (unsigned int)res);
+ ptcache_file_read(pf, &dt, 1, sizeof(float));
+ ptcache_file_read(pf, &dx, 1, sizeof(float));
+ ptcache_file_read(pf, &sds->p0, 3, sizeof(float));
+ ptcache_file_read(pf, &sds->p1, 3, sizeof(float));
+ ptcache_file_read(pf, &sds->dp0, 3, sizeof(float));
+ ptcache_file_read(pf, &sds->shift, 3, sizeof(int));
+ ptcache_file_read(pf, &sds->obj_shift_f, 3, sizeof(float));
+ ptcache_file_read(pf, &sds->obmat, 16, sizeof(float));
+ ptcache_file_read(pf, &sds->base_res, 3, sizeof(int));
+ ptcache_file_read(pf, &sds->res_min, 3, sizeof(int));
+ ptcache_file_read(pf, &sds->res_max, 3, sizeof(int));
+ ptcache_file_read(pf, &sds->active_color, 3, sizeof(float));
+ }
+
+ if (pf->data_types & (1 << BPHYS_DATA_SMOKE_HIGH) && sds->wt) {
+ int res = sds->res[0] * sds->res[1] * sds->res[2];
+ int res_big, res_big_array[3];
+ float *dens, *react, *fuel, *flame, *tcu, *tcv, *tcw, *r, *g, *b;
+ unsigned int out_len = sizeof(float) * (unsigned int)res;
+ unsigned int out_len_big;
+
+ smoke_turbulence_get_res(sds->wt, res_big_array);
+ res_big = res_big_array[0] * res_big_array[1] * res_big_array[2];
+ out_len_big = sizeof(float) * (unsigned int)res_big;
+
+ smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
+
+ ptcache_file_compressed_read(pf, (unsigned char *)dens, out_len_big);
+ if (cache_fields & SM_ACTIVE_FIRE) {
+ ptcache_file_compressed_read(pf, (unsigned char *)flame, out_len_big);
+ ptcache_file_compressed_read(pf, (unsigned char *)fuel, out_len_big);
+ ptcache_file_compressed_read(pf, (unsigned char *)react, out_len_big);
+ }
+ if (cache_fields & SM_ACTIVE_COLORS) {
+ ptcache_file_compressed_read(pf, (unsigned char *)r, out_len_big);
+ ptcache_file_compressed_read(pf, (unsigned char *)g, out_len_big);
+ ptcache_file_compressed_read(pf, (unsigned char *)b, out_len_big);
+ }
+
+ ptcache_file_compressed_read(pf, (unsigned char *)tcu, out_len);
+ ptcache_file_compressed_read(pf, (unsigned char *)tcv, out_len);
+ ptcache_file_compressed_read(pf, (unsigned char *)tcw, out_len);
+ }
+
+ return 1;
}
-#ifdef WITH_OPENVDB
+# ifdef WITH_OPENVDB
/**
* Construct matrices which represent the fluid object, for low and high res:
* <pre>
@@ -905,766 +957,858 @@ static int ptcache_smoke_read(PTCacheFile *pf, void *smoke_v)
*/
static void compute_fluid_matrices(SmokeDomainSettings *sds)
{
- float bbox_min[3];
+ float bbox_min[3];
- copy_v3_v3(bbox_min, sds->p0);
+ copy_v3_v3(bbox_min, sds->p0);
- if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
- bbox_min[0] += (sds->cell_size[0] * (float)sds->res_min[0]);
- bbox_min[1] += (sds->cell_size[1] * (float)sds->res_min[1]);
- bbox_min[2] += (sds->cell_size[2] * (float)sds->res_min[2]);
- add_v3_v3(bbox_min, sds->obj_shift_f);
- }
+ if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
+ bbox_min[0] += (sds->cell_size[0] * (float)sds->res_min[0]);
+ bbox_min[1] += (sds->cell_size[1] * (float)sds->res_min[1]);
+ bbox_min[2] += (sds->cell_size[2] * (float)sds->res_min[2]);
+ add_v3_v3(bbox_min, sds->obj_shift_f);
+ }
- /* construct low res matrix */
- size_to_mat4(sds->fluidmat, sds->cell_size);
- copy_v3_v3(sds->fluidmat[3], bbox_min);
+ /* construct low res matrix */
+ size_to_mat4(sds->fluidmat, sds->cell_size);
+ copy_v3_v3(sds->fluidmat[3], bbox_min);
- /* The smoke simulator stores voxels cell-centered, whilst VDB is node
- * centered, so we offset the matrix by half a voxel to compensate. */
- madd_v3_v3fl(sds->fluidmat[3], sds->cell_size, 0.5f);
+ /* The smoke simulator stores voxels cell-centered, whilst VDB is node
+ * centered, so we offset the matrix by half a voxel to compensate. */
+ madd_v3_v3fl(sds->fluidmat[3], sds->cell_size, 0.5f);
- mul_m4_m4m4(sds->fluidmat, sds->obmat, sds->fluidmat);
+ mul_m4_m4m4(sds->fluidmat, sds->obmat, sds->fluidmat);
- if (sds->wt) {
- float voxel_size_high[3];
- /* construct high res matrix */
- mul_v3_v3fl(voxel_size_high, sds->cell_size, 1.0f / (float)(sds->amplify + 1));
- size_to_mat4(sds->fluidmat_wt, voxel_size_high);
- copy_v3_v3(sds->fluidmat_wt[3], bbox_min);
+ if (sds->wt) {
+ float voxel_size_high[3];
+ /* construct high res matrix */
+ mul_v3_v3fl(voxel_size_high, sds->cell_size, 1.0f / (float)(sds->amplify + 1));
+ size_to_mat4(sds->fluidmat_wt, voxel_size_high);
+ copy_v3_v3(sds->fluidmat_wt[3], bbox_min);
- /* Same here, add half a voxel to adjust the position of the fluid. */
- madd_v3_v3fl(sds->fluidmat_wt[3], voxel_size_high, 0.5f);
+ /* Same here, add half a voxel to adjust the position of the fluid. */
+ madd_v3_v3fl(sds->fluidmat_wt[3], voxel_size_high, 0.5f);
- mul_m4_m4m4(sds->fluidmat_wt, sds->obmat, sds->fluidmat_wt);
- }
+ mul_m4_m4m4(sds->fluidmat_wt, sds->obmat, sds->fluidmat_wt);
+ }
}
static int ptcache_smoke_openvdb_write(struct OpenVDBWriter *writer, void *smoke_v)
{
- SmokeModifierData *smd = (SmokeModifierData *)smoke_v;
- SmokeDomainSettings *sds = smd->domain;
-
- OpenVDBWriter_set_flags(writer, sds->openvdb_comp, (sds->data_depth == 16));
-
- OpenVDBWriter_add_meta_int(writer, "blender/smoke/active_fields", sds->active_fields);
- OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/resolution", sds->res);
- OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/min_resolution", sds->res_min);
- OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/max_resolution", sds->res_max);
- OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/base_resolution", sds->base_res);
- OpenVDBWriter_add_meta_v3(writer, "blender/smoke/min_bbox", sds->p0);
- OpenVDBWriter_add_meta_v3(writer, "blender/smoke/max_bbox", sds->p1);
- OpenVDBWriter_add_meta_v3(writer, "blender/smoke/dp0", sds->dp0);
- OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/shift", sds->shift);
- OpenVDBWriter_add_meta_v3(writer, "blender/smoke/obj_shift_f", sds->obj_shift_f);
- OpenVDBWriter_add_meta_v3(writer, "blender/smoke/active_color", sds->active_color);
- OpenVDBWriter_add_meta_mat4(writer, "blender/smoke/obmat", sds->obmat);
-
- int fluid_fields = BKE_smoke_get_data_flags(sds);
-
- struct OpenVDBFloatGrid *clip_grid = NULL;
-
- compute_fluid_matrices(sds);
-
- OpenVDBWriter_add_meta_int(writer, "blender/smoke/fluid_fields", fluid_fields);
-
- if (sds->wt) {
- struct OpenVDBFloatGrid *wt_density_grid;
- float *dens, *react, *fuel, *flame, *tcu, *tcv, *tcw, *r, *g, *b;
-
- smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
-
- wt_density_grid = OpenVDB_export_grid_fl(writer, "density", dens, sds->res_wt, sds->fluidmat_wt, sds->clipping, NULL);
- clip_grid = wt_density_grid;
-
- if (fluid_fields & SM_ACTIVE_FIRE) {
- OpenVDB_export_grid_fl(writer, "flame", flame, sds->res_wt, sds->fluidmat_wt, sds->clipping, wt_density_grid);
- OpenVDB_export_grid_fl(writer, "fuel", fuel, sds->res_wt, sds->fluidmat_wt, sds->clipping, wt_density_grid);
- OpenVDB_export_grid_fl(writer, "react", react, sds->res_wt, sds->fluidmat_wt, sds->clipping, wt_density_grid);
- }
-
- if (fluid_fields & SM_ACTIVE_COLORS) {
- OpenVDB_export_grid_vec(writer, "color", r, g, b, sds->res_wt, sds->fluidmat_wt, VEC_INVARIANT, true, sds->clipping, wt_density_grid);
- }
-
- OpenVDB_export_grid_vec(writer, "texture coordinates", tcu, tcv, tcw, sds->res, sds->fluidmat, VEC_INVARIANT, false, sds->clipping, wt_density_grid);
- }
-
- if (sds->fluid) {
- struct OpenVDBFloatGrid *density_grid;
- float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b;
- unsigned char *obstacles;
-
- smoke_export(sds->fluid, &dt, &dx, &dens, &react, &flame, &fuel, &heat,
- &heatold, &vx, &vy, &vz, &r, &g, &b, &obstacles);
-
- OpenVDBWriter_add_meta_fl(writer, "blender/smoke/dx", dx);
- OpenVDBWriter_add_meta_fl(writer, "blender/smoke/dt", dt);
-
- const char *name = (!sds->wt) ? "density" : "density_low";
- density_grid = OpenVDB_export_grid_fl(writer, name, dens, sds->res, sds->fluidmat, sds->clipping, NULL);
- clip_grid = sds->wt ? clip_grid : density_grid;
-
- OpenVDB_export_grid_fl(writer, "shadow", sds->shadow, sds->res, sds->fluidmat, sds->clipping, NULL);
-
- if (fluid_fields & SM_ACTIVE_HEAT) {
- OpenVDB_export_grid_fl(writer, "heat", heat, sds->res, sds->fluidmat, sds->clipping, clip_grid);
- OpenVDB_export_grid_fl(writer, "heat_old", heatold, sds->res, sds->fluidmat, sds->clipping, clip_grid);
- }
-
- if (fluid_fields & SM_ACTIVE_FIRE) {
- name = (!sds->wt) ? "flame" : "flame_low";
- OpenVDB_export_grid_fl(writer, name, flame, sds->res, sds->fluidmat, sds->clipping, density_grid);
- name = (!sds->wt) ? "fuel" : "fuel_low";
- OpenVDB_export_grid_fl(writer, name, fuel, sds->res, sds->fluidmat, sds->clipping, density_grid);
- name = (!sds->wt) ? "react" : "react_low";
- OpenVDB_export_grid_fl(writer, name, react, sds->res, sds->fluidmat, sds->clipping, density_grid);
- }
-
- if (fluid_fields & SM_ACTIVE_COLORS) {
- name = (!sds->wt) ? "color" : "color_low";
- OpenVDB_export_grid_vec(writer, name, r, g, b, sds->res, sds->fluidmat, VEC_INVARIANT, true, sds->clipping, density_grid);
- }
-
- OpenVDB_export_grid_vec(writer, "velocity", vx, vy, vz, sds->res, sds->fluidmat, VEC_CONTRAVARIANT_RELATIVE, false, sds->clipping, clip_grid);
- OpenVDB_export_grid_ch(writer, "obstacles", obstacles, sds->res, sds->fluidmat, sds->clipping, NULL);
- }
-
- return 1;
+ SmokeModifierData *smd = (SmokeModifierData *)smoke_v;
+ SmokeDomainSettings *sds = smd->domain;
+
+ OpenVDBWriter_set_flags(writer, sds->openvdb_comp, (sds->data_depth == 16));
+
+ OpenVDBWriter_add_meta_int(writer, "blender/smoke/active_fields", sds->active_fields);
+ OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/resolution", sds->res);
+ OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/min_resolution", sds->res_min);
+ OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/max_resolution", sds->res_max);
+ OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/base_resolution", sds->base_res);
+ OpenVDBWriter_add_meta_v3(writer, "blender/smoke/min_bbox", sds->p0);
+ OpenVDBWriter_add_meta_v3(writer, "blender/smoke/max_bbox", sds->p1);
+ OpenVDBWriter_add_meta_v3(writer, "blender/smoke/dp0", sds->dp0);
+ OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/shift", sds->shift);
+ OpenVDBWriter_add_meta_v3(writer, "blender/smoke/obj_shift_f", sds->obj_shift_f);
+ OpenVDBWriter_add_meta_v3(writer, "blender/smoke/active_color", sds->active_color);
+ OpenVDBWriter_add_meta_mat4(writer, "blender/smoke/obmat", sds->obmat);
+
+ int fluid_fields = BKE_smoke_get_data_flags(sds);
+
+ struct OpenVDBFloatGrid *clip_grid = NULL;
+
+ compute_fluid_matrices(sds);
+
+ OpenVDBWriter_add_meta_int(writer, "blender/smoke/fluid_fields", fluid_fields);
+
+ if (sds->wt) {
+ struct OpenVDBFloatGrid *wt_density_grid;
+ float *dens, *react, *fuel, *flame, *tcu, *tcv, *tcw, *r, *g, *b;
+
+ smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
+
+ wt_density_grid = OpenVDB_export_grid_fl(
+ writer, "density", dens, sds->res_wt, sds->fluidmat_wt, sds->clipping, NULL);
+ clip_grid = wt_density_grid;
+
+ if (fluid_fields & SM_ACTIVE_FIRE) {
+ OpenVDB_export_grid_fl(
+ writer, "flame", flame, sds->res_wt, sds->fluidmat_wt, sds->clipping, wt_density_grid);
+ OpenVDB_export_grid_fl(
+ writer, "fuel", fuel, sds->res_wt, sds->fluidmat_wt, sds->clipping, wt_density_grid);
+ OpenVDB_export_grid_fl(
+ writer, "react", react, sds->res_wt, sds->fluidmat_wt, sds->clipping, wt_density_grid);
+ }
+
+ if (fluid_fields & SM_ACTIVE_COLORS) {
+ OpenVDB_export_grid_vec(writer,
+ "color",
+ r,
+ g,
+ b,
+ sds->res_wt,
+ sds->fluidmat_wt,
+ VEC_INVARIANT,
+ true,
+ sds->clipping,
+ wt_density_grid);
+ }
+
+ OpenVDB_export_grid_vec(writer,
+ "texture coordinates",
+ tcu,
+ tcv,
+ tcw,
+ sds->res,
+ sds->fluidmat,
+ VEC_INVARIANT,
+ false,
+ sds->clipping,
+ wt_density_grid);
+ }
+
+ if (sds->fluid) {
+ struct OpenVDBFloatGrid *density_grid;
+ float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b;
+ unsigned char *obstacles;
+
+ smoke_export(sds->fluid,
+ &dt,
+ &dx,
+ &dens,
+ &react,
+ &flame,
+ &fuel,
+ &heat,
+ &heatold,
+ &vx,
+ &vy,
+ &vz,
+ &r,
+ &g,
+ &b,
+ &obstacles);
+
+ OpenVDBWriter_add_meta_fl(writer, "blender/smoke/dx", dx);
+ OpenVDBWriter_add_meta_fl(writer, "blender/smoke/dt", dt);
+
+ const char *name = (!sds->wt) ? "density" : "density_low";
+ density_grid = OpenVDB_export_grid_fl(
+ writer, name, dens, sds->res, sds->fluidmat, sds->clipping, NULL);
+ clip_grid = sds->wt ? clip_grid : density_grid;
+
+ OpenVDB_export_grid_fl(
+ writer, "shadow", sds->shadow, sds->res, sds->fluidmat, sds->clipping, NULL);
+
+ if (fluid_fields & SM_ACTIVE_HEAT) {
+ OpenVDB_export_grid_fl(
+ writer, "heat", heat, sds->res, sds->fluidmat, sds->clipping, clip_grid);
+ OpenVDB_export_grid_fl(
+ writer, "heat_old", heatold, sds->res, sds->fluidmat, sds->clipping, clip_grid);
+ }
+
+ if (fluid_fields & SM_ACTIVE_FIRE) {
+ name = (!sds->wt) ? "flame" : "flame_low";
+ OpenVDB_export_grid_fl(
+ writer, name, flame, sds->res, sds->fluidmat, sds->clipping, density_grid);
+ name = (!sds->wt) ? "fuel" : "fuel_low";
+ OpenVDB_export_grid_fl(
+ writer, name, fuel, sds->res, sds->fluidmat, sds->clipping, density_grid);
+ name = (!sds->wt) ? "react" : "react_low";
+ OpenVDB_export_grid_fl(
+ writer, name, react, sds->res, sds->fluidmat, sds->clipping, density_grid);
+ }
+
+ if (fluid_fields & SM_ACTIVE_COLORS) {
+ name = (!sds->wt) ? "color" : "color_low";
+ OpenVDB_export_grid_vec(writer,
+ name,
+ r,
+ g,
+ b,
+ sds->res,
+ sds->fluidmat,
+ VEC_INVARIANT,
+ true,
+ sds->clipping,
+ density_grid);
+ }
+
+ OpenVDB_export_grid_vec(writer,
+ "velocity",
+ vx,
+ vy,
+ vz,
+ sds->res,
+ sds->fluidmat,
+ VEC_CONTRAVARIANT_RELATIVE,
+ false,
+ sds->clipping,
+ clip_grid);
+ OpenVDB_export_grid_ch(
+ writer, "obstacles", obstacles, sds->res, sds->fluidmat, sds->clipping, NULL);
+ }
+
+ return 1;
}
static int ptcache_smoke_openvdb_read(struct OpenVDBReader *reader, void *smoke_v)
{
- SmokeModifierData *smd = (SmokeModifierData *)smoke_v;
-
- if (!smd) {
- return 0;
- }
-
- SmokeDomainSettings *sds = smd->domain;
-
- int fluid_fields = BKE_smoke_get_data_flags(sds);
- int active_fields, cache_fields = 0;
- int cache_res[3];
- float cache_dx;
- bool reallocate = false;
-
- OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/min_resolution", sds->res_min);
- OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/max_resolution", sds->res_max);
- OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/base_resolution", sds->base_res);
- OpenVDBReader_get_meta_v3(reader, "blender/smoke/min_bbox", sds->p0);
- OpenVDBReader_get_meta_v3(reader, "blender/smoke/max_bbox", sds->p1);
- OpenVDBReader_get_meta_v3(reader, "blender/smoke/dp0", sds->dp0);
- OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/shift", sds->shift);
- OpenVDBReader_get_meta_v3(reader, "blender/smoke/obj_shift_f", sds->obj_shift_f);
- OpenVDBReader_get_meta_v3(reader, "blender/smoke/active_color", sds->active_color);
- OpenVDBReader_get_meta_mat4(reader, "blender/smoke/obmat", sds->obmat);
- OpenVDBReader_get_meta_int(reader, "blender/smoke/fluid_fields", &cache_fields);
- OpenVDBReader_get_meta_int(reader, "blender/smoke/active_fields", &active_fields);
- OpenVDBReader_get_meta_fl(reader, "blender/smoke/dx", &cache_dx);
- OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/resolution", cache_res);
-
- /* check if resolution has changed */
- if (sds->res[0] != cache_res[0] ||
- sds->res[1] != cache_res[1] ||
- sds->res[2] != cache_res[2])
- {
- if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
- reallocate = true;
- }
- else {
- return 0;
- }
- }
-
- /* check if active fields have changed */
- if ((fluid_fields != cache_fields) || (active_fields != sds->active_fields)) {
- reallocate = true;
- }
-
- /* reallocate fluid if needed*/
- if (reallocate) {
- sds->active_fields = active_fields | cache_fields;
- BKE_smoke_reallocate_fluid(sds, cache_dx, cache_res, 1);
- sds->dx = cache_dx;
- copy_v3_v3_int(sds->res, cache_res);
- sds->total_cells = cache_res[0] * cache_res[1] * cache_res[2];
-
- if (sds->flags & MOD_SMOKE_HIGHRES) {
- BKE_smoke_reallocate_highres_fluid(sds, cache_dx, cache_res, 1);
- }
- }
-
- if (sds->fluid) {
- float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b;
- unsigned char *obstacles;
-
- smoke_export(sds->fluid, &dt, &dx, &dens, &react, &flame, &fuel, &heat,
- &heatold, &vx, &vy, &vz, &r, &g, &b, &obstacles);
-
- OpenVDBReader_get_meta_fl(reader, "blender/smoke/dt", &dt);
-
- OpenVDB_import_grid_fl(reader, "shadow", &sds->shadow, sds->res);
-
- const char *name = (!sds->wt) ? "density" : "density_low";
- OpenVDB_import_grid_fl(reader, name, &dens, sds->res);
-
- if (cache_fields & SM_ACTIVE_HEAT) {
- OpenVDB_import_grid_fl(reader, "heat", &heat, sds->res);
- OpenVDB_import_grid_fl(reader, "heat_old", &heatold, sds->res);
- }
-
- if (cache_fields & SM_ACTIVE_FIRE) {
- name = (!sds->wt) ? "flame" : "flame_low";
- OpenVDB_import_grid_fl(reader, name, &flame, sds->res);
- name = (!sds->wt) ? "fuel" : "fuel_low";
- OpenVDB_import_grid_fl(reader, name, &fuel, sds->res);
- name = (!sds->wt) ? "react" : "react_low";
- OpenVDB_import_grid_fl(reader, name, &react, sds->res);
- }
-
- if (cache_fields & SM_ACTIVE_COLORS) {
- name = (!sds->wt) ? "color" : "color_low";
- OpenVDB_import_grid_vec(reader, name, &r, &g, &b, sds->res);
- }
-
- OpenVDB_import_grid_vec(reader, "velocity", &vx, &vy, &vz, sds->res);
- OpenVDB_import_grid_ch(reader, "obstacles", &obstacles, sds->res);
- }
-
- if (sds->wt) {
- float *dens, *react, *fuel, *flame, *tcu, *tcv, *tcw, *r, *g, *b;
-
- smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
-
- OpenVDB_import_grid_fl(reader, "density", &dens, sds->res_wt);
-
- if (cache_fields & SM_ACTIVE_FIRE) {
- OpenVDB_import_grid_fl(reader, "flame", &flame, sds->res_wt);
- OpenVDB_import_grid_fl(reader, "fuel", &fuel, sds->res_wt);
- OpenVDB_import_grid_fl(reader, "react", &react, sds->res_wt);
- }
-
- if (cache_fields & SM_ACTIVE_COLORS) {
- OpenVDB_import_grid_vec(reader, "color", &r, &g, &b, sds->res_wt);
- }
-
- OpenVDB_import_grid_vec(reader, "texture coordinates", &tcu, &tcv, &tcw, sds->res);
- }
-
- OpenVDBReader_free(reader);
-
- return 1;
+ SmokeModifierData *smd = (SmokeModifierData *)smoke_v;
+
+ if (!smd) {
+ return 0;
+ }
+
+ SmokeDomainSettings *sds = smd->domain;
+
+ int fluid_fields = BKE_smoke_get_data_flags(sds);
+ int active_fields, cache_fields = 0;
+ int cache_res[3];
+ float cache_dx;
+ bool reallocate = false;
+
+ OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/min_resolution", sds->res_min);
+ OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/max_resolution", sds->res_max);
+ OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/base_resolution", sds->base_res);
+ OpenVDBReader_get_meta_v3(reader, "blender/smoke/min_bbox", sds->p0);
+ OpenVDBReader_get_meta_v3(reader, "blender/smoke/max_bbox", sds->p1);
+ OpenVDBReader_get_meta_v3(reader, "blender/smoke/dp0", sds->dp0);
+ OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/shift", sds->shift);
+ OpenVDBReader_get_meta_v3(reader, "blender/smoke/obj_shift_f", sds->obj_shift_f);
+ OpenVDBReader_get_meta_v3(reader, "blender/smoke/active_color", sds->active_color);
+ OpenVDBReader_get_meta_mat4(reader, "blender/smoke/obmat", sds->obmat);
+ OpenVDBReader_get_meta_int(reader, "blender/smoke/fluid_fields", &cache_fields);
+ OpenVDBReader_get_meta_int(reader, "blender/smoke/active_fields", &active_fields);
+ OpenVDBReader_get_meta_fl(reader, "blender/smoke/dx", &cache_dx);
+ OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/resolution", cache_res);
+
+ /* check if resolution has changed */
+ if (sds->res[0] != cache_res[0] || sds->res[1] != cache_res[1] || sds->res[2] != cache_res[2]) {
+ if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
+ reallocate = true;
+ }
+ else {
+ return 0;
+ }
+ }
+
+ /* check if active fields have changed */
+ if ((fluid_fields != cache_fields) || (active_fields != sds->active_fields)) {
+ reallocate = true;
+ }
+
+ /* reallocate fluid if needed*/
+ if (reallocate) {
+ sds->active_fields = active_fields | cache_fields;
+ BKE_smoke_reallocate_fluid(sds, cache_dx, cache_res, 1);
+ sds->dx = cache_dx;
+ copy_v3_v3_int(sds->res, cache_res);
+ sds->total_cells = cache_res[0] * cache_res[1] * cache_res[2];
+
+ if (sds->flags & MOD_SMOKE_HIGHRES) {
+ BKE_smoke_reallocate_highres_fluid(sds, cache_dx, cache_res, 1);
+ }
+ }
+
+ if (sds->fluid) {
+ float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b;
+ unsigned char *obstacles;
+
+ smoke_export(sds->fluid,
+ &dt,
+ &dx,
+ &dens,
+ &react,
+ &flame,
+ &fuel,
+ &heat,
+ &heatold,
+ &vx,
+ &vy,
+ &vz,
+ &r,
+ &g,
+ &b,
+ &obstacles);
+
+ OpenVDBReader_get_meta_fl(reader, "blender/smoke/dt", &dt);
+
+ OpenVDB_import_grid_fl(reader, "shadow", &sds->shadow, sds->res);
+
+ const char *name = (!sds->wt) ? "density" : "density_low";
+ OpenVDB_import_grid_fl(reader, name, &dens, sds->res);
+
+ if (cache_fields & SM_ACTIVE_HEAT) {
+ OpenVDB_import_grid_fl(reader, "heat", &heat, sds->res);
+ OpenVDB_import_grid_fl(reader, "heat_old", &heatold, sds->res);
+ }
+
+ if (cache_fields & SM_ACTIVE_FIRE) {
+ name = (!sds->wt) ? "flame" : "flame_low";
+ OpenVDB_import_grid_fl(reader, name, &flame, sds->res);
+ name = (!sds->wt) ? "fuel" : "fuel_low";
+ OpenVDB_import_grid_fl(reader, name, &fuel, sds->res);
+ name = (!sds->wt) ? "react" : "react_low";
+ OpenVDB_import_grid_fl(reader, name, &react, sds->res);
+ }
+
+ if (cache_fields & SM_ACTIVE_COLORS) {
+ name = (!sds->wt) ? "color" : "color_low";
+ OpenVDB_import_grid_vec(reader, name, &r, &g, &b, sds->res);
+ }
+
+ OpenVDB_import_grid_vec(reader, "velocity", &vx, &vy, &vz, sds->res);
+ OpenVDB_import_grid_ch(reader, "obstacles", &obstacles, sds->res);
+ }
+
+ if (sds->wt) {
+ float *dens, *react, *fuel, *flame, *tcu, *tcv, *tcw, *r, *g, *b;
+
+ smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
+
+ OpenVDB_import_grid_fl(reader, "density", &dens, sds->res_wt);
+
+ if (cache_fields & SM_ACTIVE_FIRE) {
+ OpenVDB_import_grid_fl(reader, "flame", &flame, sds->res_wt);
+ OpenVDB_import_grid_fl(reader, "fuel", &fuel, sds->res_wt);
+ OpenVDB_import_grid_fl(reader, "react", &react, sds->res_wt);
+ }
+
+ if (cache_fields & SM_ACTIVE_COLORS) {
+ OpenVDB_import_grid_vec(reader, "color", &r, &g, &b, sds->res_wt);
+ }
+
+ OpenVDB_import_grid_vec(reader, "texture coordinates", &tcu, &tcv, &tcw, sds->res);
+ }
+
+ OpenVDBReader_free(reader);
+
+ return 1;
}
-#endif
+# endif
-#else // WITH_SMOKE
-static int ptcache_smoke_totpoint(void *UNUSED(smoke_v), int UNUSED(cfra)) { return 0; }
-static void ptcache_smoke_error(void *UNUSED(smoke_v), const char *UNUSED(message)) { }
-static int ptcache_smoke_read(PTCacheFile *UNUSED(pf), void *UNUSED(smoke_v)) { return 0; }
-static int ptcache_smoke_write(PTCacheFile *UNUSED(pf), void *UNUSED(smoke_v)) { return 0; }
-#endif // WITH_SMOKE
+#else // WITH_SMOKE
+static int ptcache_smoke_totpoint(void *UNUSED(smoke_v), int UNUSED(cfra))
+{
+ return 0;
+}
+static void ptcache_smoke_error(void *UNUSED(smoke_v), const char *UNUSED(message))
+{
+}
+static int ptcache_smoke_read(PTCacheFile *UNUSED(pf), void *UNUSED(smoke_v))
+{
+ return 0;
+}
+static int ptcache_smoke_write(PTCacheFile *UNUSED(pf), void *UNUSED(smoke_v))
+{
+ return 0;
+}
+#endif // WITH_SMOKE
#if !defined(WITH_SMOKE) || !defined(WITH_OPENVDB)
static int ptcache_smoke_openvdb_write(struct OpenVDBWriter *writer, void *smoke_v)
{
- UNUSED_VARS(writer, smoke_v);
- return 0;
+ UNUSED_VARS(writer, smoke_v);
+ return 0;
}
static int ptcache_smoke_openvdb_read(struct OpenVDBReader *reader, void *smoke_v)
{
- UNUSED_VARS(reader, smoke_v);
- return 0;
+ UNUSED_VARS(reader, smoke_v);
+ return 0;
}
#endif
static int ptcache_dynamicpaint_totpoint(void *sd, int UNUSED(cfra))
{
- DynamicPaintSurface *surface = (DynamicPaintSurface*)sd;
+ DynamicPaintSurface *surface = (DynamicPaintSurface *)sd;
- if (!surface->data) return 0;
- else return surface->data->total_points;
+ if (!surface->data)
+ return 0;
+ else
+ return surface->data->total_points;
}
static void ptcache_dynamicpaint_error(void *UNUSED(sd), const char *UNUSED(message))
{
- /* ignored for now */
+ /* ignored for now */
}
#define DPAINT_CACHE_VERSION "1.01"
-static int ptcache_dynamicpaint_write(PTCacheFile *pf, void *dp_v)
+static int ptcache_dynamicpaint_write(PTCacheFile *pf, void *dp_v)
{
- DynamicPaintSurface *surface = (DynamicPaintSurface*)dp_v;
- int cache_compress = 1;
-
- /* version header */
- ptcache_file_write(pf, DPAINT_CACHE_VERSION, 1, sizeof(char) * 4);
-
- if (surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ && surface->data) {
- int total_points=surface->data->total_points;
- unsigned int in_len;
- unsigned char *out;
-
- /* cache type */
- ptcache_file_write(pf, &surface->type, 1, sizeof(int));
-
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- in_len = sizeof(PaintPoint) * total_points;
- }
- else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE ||
- surface->type == MOD_DPAINT_SURFACE_T_WEIGHT)
- {
- in_len = sizeof(float) * total_points;
- }
- else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
- in_len = sizeof(PaintWavePoint) * total_points;
- }
- else {
- return 0;
- }
-
- out = (unsigned char *)MEM_callocN(LZO_OUT_LEN(in_len), "pointcache_lzo_buffer");
-
- ptcache_file_compressed_write(pf, (unsigned char *)surface->data->type_data, in_len, out, cache_compress);
- MEM_freeN(out);
-
- }
- return 1;
+ DynamicPaintSurface *surface = (DynamicPaintSurface *)dp_v;
+ int cache_compress = 1;
+
+ /* version header */
+ ptcache_file_write(pf, DPAINT_CACHE_VERSION, 1, sizeof(char) * 4);
+
+ if (surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ && surface->data) {
+ int total_points = surface->data->total_points;
+ unsigned int in_len;
+ unsigned char *out;
+
+ /* cache type */
+ ptcache_file_write(pf, &surface->type, 1, sizeof(int));
+
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ in_len = sizeof(PaintPoint) * total_points;
+ }
+ else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE ||
+ surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
+ in_len = sizeof(float) * total_points;
+ }
+ else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
+ in_len = sizeof(PaintWavePoint) * total_points;
+ }
+ else {
+ return 0;
+ }
+
+ out = (unsigned char *)MEM_callocN(LZO_OUT_LEN(in_len), "pointcache_lzo_buffer");
+
+ ptcache_file_compressed_write(
+ pf, (unsigned char *)surface->data->type_data, in_len, out, cache_compress);
+ MEM_freeN(out);
+ }
+ return 1;
}
static int ptcache_dynamicpaint_read(PTCacheFile *pf, void *dp_v)
{
- DynamicPaintSurface *surface = (DynamicPaintSurface*)dp_v;
- char version[4];
-
- /* version header */
- ptcache_file_read(pf, version, 1, sizeof(char) * 4);
- if (!STREQLEN(version, DPAINT_CACHE_VERSION, 4)) {
- CLOG_ERROR(&LOG, "Dynamic Paint: Invalid cache version: '%c%c%c%c'!", UNPACK4(version));
- return 0;
- }
-
- if (surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ && surface->data) {
- unsigned int data_len;
- int surface_type;
-
- /* cache type */
- ptcache_file_read(pf, &surface_type, 1, sizeof(int));
-
- if (surface_type != surface->type)
- return 0;
-
- /* read surface data */
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- data_len = sizeof(PaintPoint);
- }
- else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE ||
- surface->type == MOD_DPAINT_SURFACE_T_WEIGHT)
- {
- data_len = sizeof(float);
- }
- else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
- data_len = sizeof(PaintWavePoint);
- }
- else {
- return 0;
- }
-
- ptcache_file_compressed_read(pf, (unsigned char *)surface->data->type_data, data_len*surface->data->total_points);
-
- }
- return 1;
+ DynamicPaintSurface *surface = (DynamicPaintSurface *)dp_v;
+ char version[4];
+
+ /* version header */
+ ptcache_file_read(pf, version, 1, sizeof(char) * 4);
+ if (!STREQLEN(version, DPAINT_CACHE_VERSION, 4)) {
+ CLOG_ERROR(&LOG, "Dynamic Paint: Invalid cache version: '%c%c%c%c'!", UNPACK4(version));
+ return 0;
+ }
+
+ if (surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ && surface->data) {
+ unsigned int data_len;
+ int surface_type;
+
+ /* cache type */
+ ptcache_file_read(pf, &surface_type, 1, sizeof(int));
+
+ if (surface_type != surface->type)
+ return 0;
+
+ /* read surface data */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ data_len = sizeof(PaintPoint);
+ }
+ else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE ||
+ surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
+ data_len = sizeof(float);
+ }
+ else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
+ data_len = sizeof(PaintWavePoint);
+ }
+ else {
+ return 0;
+ }
+
+ ptcache_file_compressed_read(
+ pf, (unsigned char *)surface->data->type_data, data_len * surface->data->total_points);
+ }
+ return 1;
}
/* Rigid Body functions */
-static int ptcache_rigidbody_write(int index, void *rb_v, void **data, int UNUSED(cfra))
+static int ptcache_rigidbody_write(int index, void *rb_v, void **data, int UNUSED(cfra))
{
- RigidBodyWorld *rbw = rb_v;
- Object *ob = NULL;
+ RigidBodyWorld *rbw = rb_v;
+ Object *ob = NULL;
- if (rbw->objects)
- ob = rbw->objects[index];
+ if (rbw->objects)
+ ob = rbw->objects[index];
- if (ob && ob->rigidbody_object) {
- RigidBodyOb *rbo = ob->rigidbody_object;
+ if (ob && ob->rigidbody_object) {
+ RigidBodyOb *rbo = ob->rigidbody_object;
- if (rbo->type == RBO_TYPE_ACTIVE) {
+ if (rbo->type == RBO_TYPE_ACTIVE) {
#ifdef WITH_BULLET
- RB_body_get_position(rbo->shared->physics_object, rbo->pos);
- RB_body_get_orientation(rbo->shared->physics_object, rbo->orn);
+ RB_body_get_position(rbo->shared->physics_object, rbo->pos);
+ RB_body_get_orientation(rbo->shared->physics_object, rbo->orn);
#endif
- PTCACHE_DATA_FROM(data, BPHYS_DATA_LOCATION, rbo->pos);
- PTCACHE_DATA_FROM(data, BPHYS_DATA_ROTATION, rbo->orn);
- }
- }
+ PTCACHE_DATA_FROM(data, BPHYS_DATA_LOCATION, rbo->pos);
+ PTCACHE_DATA_FROM(data, BPHYS_DATA_ROTATION, rbo->orn);
+ }
+ }
- return 1;
+ return 1;
}
-static void ptcache_rigidbody_read(int index, void *rb_v, void **data, float UNUSED(cfra), float *old_data)
+static void ptcache_rigidbody_read(
+ int index, void *rb_v, void **data, float UNUSED(cfra), float *old_data)
{
- RigidBodyWorld *rbw = rb_v;
- Object *ob = NULL;
-
- if (rbw->objects)
- ob = rbw->objects[index];
-
- if (ob && ob->rigidbody_object) {
- RigidBodyOb *rbo = ob->rigidbody_object;
-
- if (rbo->type == RBO_TYPE_ACTIVE) {
-
- if (old_data) {
- memcpy(rbo->pos, data, 3 * sizeof(float));
- memcpy(rbo->orn, data + 3, 4 * sizeof(float));
- }
- else {
- PTCACHE_DATA_TO(data, BPHYS_DATA_LOCATION, 0, rbo->pos);
- PTCACHE_DATA_TO(data, BPHYS_DATA_ROTATION, 0, rbo->orn);
- }
- }
- }
+ RigidBodyWorld *rbw = rb_v;
+ Object *ob = NULL;
+
+ if (rbw->objects)
+ ob = rbw->objects[index];
+
+ if (ob && ob->rigidbody_object) {
+ RigidBodyOb *rbo = ob->rigidbody_object;
+
+ if (rbo->type == RBO_TYPE_ACTIVE) {
+
+ if (old_data) {
+ memcpy(rbo->pos, data, 3 * sizeof(float));
+ memcpy(rbo->orn, data + 3, 4 * sizeof(float));
+ }
+ else {
+ PTCACHE_DATA_TO(data, BPHYS_DATA_LOCATION, 0, rbo->pos);
+ PTCACHE_DATA_TO(data, BPHYS_DATA_ROTATION, 0, rbo->orn);
+ }
+ }
+ }
}
-static void ptcache_rigidbody_interpolate(int index, void *rb_v, void **data, float cfra, float cfra1, float cfra2, float *old_data)
+static void ptcache_rigidbody_interpolate(
+ int index, void *rb_v, void **data, float cfra, float cfra1, float cfra2, float *old_data)
{
- RigidBodyWorld *rbw = rb_v;
- Object *ob = NULL;
+ RigidBodyWorld *rbw = rb_v;
+ Object *ob = NULL;
- if (rbw->objects)
- ob = rbw->objects[index];
+ if (rbw->objects)
+ ob = rbw->objects[index];
- if (ob && ob->rigidbody_object) {
- RigidBodyOb *rbo = ob->rigidbody_object;
+ if (ob && ob->rigidbody_object) {
+ RigidBodyOb *rbo = ob->rigidbody_object;
- if (rbo->type == RBO_TYPE_ACTIVE) {
- ParticleKey keys[4];
- ParticleKey result;
- float dfra;
+ if (rbo->type == RBO_TYPE_ACTIVE) {
+ ParticleKey keys[4];
+ ParticleKey result;
+ float dfra;
- memset(keys, 0, sizeof(keys));
+ memset(keys, 0, sizeof(keys));
- copy_v3_v3(keys[1].co, rbo->pos);
- copy_qt_qt(keys[1].rot, rbo->orn);
+ copy_v3_v3(keys[1].co, rbo->pos);
+ copy_qt_qt(keys[1].rot, rbo->orn);
- if (old_data) {
- memcpy(keys[2].co, data, 3 * sizeof(float));
- memcpy(keys[2].rot, data + 3, 4 * sizeof(float));
- }
- else {
- BKE_ptcache_make_particle_key(&keys[2], 0, data, cfra2);
- }
+ if (old_data) {
+ memcpy(keys[2].co, data, 3 * sizeof(float));
+ memcpy(keys[2].rot, data + 3, 4 * sizeof(float));
+ }
+ else {
+ BKE_ptcache_make_particle_key(&keys[2], 0, data, cfra2);
+ }
- dfra = cfra2 - cfra1;
+ dfra = cfra2 - cfra1;
- /* note: keys[0] and keys[3] unused for type < 1 (crappy) */
- psys_interpolate_particle(-1, keys, (cfra - cfra1) / dfra, &result, true);
- interp_qt_qtqt(result.rot, keys[1].rot, keys[2].rot, (cfra - cfra1) / dfra);
+ /* note: keys[0] and keys[3] unused for type < 1 (crappy) */
+ psys_interpolate_particle(-1, keys, (cfra - cfra1) / dfra, &result, true);
+ interp_qt_qtqt(result.rot, keys[1].rot, keys[2].rot, (cfra - cfra1) / dfra);
- copy_v3_v3(rbo->pos, result.co);
- copy_qt_qt(rbo->orn, result.rot);
- }
- }
+ copy_v3_v3(rbo->pos, result.co);
+ copy_qt_qt(rbo->orn, result.rot);
+ }
+ }
}
static int ptcache_rigidbody_totpoint(void *rb_v, int UNUSED(cfra))
{
- RigidBodyWorld *rbw = rb_v;
+ RigidBodyWorld *rbw = rb_v;
- return rbw->numbodies;
+ return rbw->numbodies;
}
static void ptcache_rigidbody_error(void *UNUSED(rb_v), const char *UNUSED(message))
{
- /* ignored for now */
+ /* ignored for now */
}
/* Creating ID's */
void BKE_ptcache_id_from_softbody(PTCacheID *pid, Object *ob, SoftBody *sb)
{
- memset(pid, 0, sizeof(PTCacheID));
+ memset(pid, 0, sizeof(PTCacheID));
- pid->ob= ob;
- pid->calldata= sb;
- pid->type= PTCACHE_TYPE_SOFTBODY;
- pid->cache= sb->shared->pointcache;
- pid->cache_ptr= &sb->shared->pointcache;
- pid->ptcaches= &sb->shared->ptcaches;
- pid->totpoint= pid->totwrite= ptcache_softbody_totpoint;
- pid->error = ptcache_softbody_error;
+ pid->ob = ob;
+ pid->calldata = sb;
+ pid->type = PTCACHE_TYPE_SOFTBODY;
+ pid->cache = sb->shared->pointcache;
+ pid->cache_ptr = &sb->shared->pointcache;
+ pid->ptcaches = &sb->shared->ptcaches;
+ pid->totpoint = pid->totwrite = ptcache_softbody_totpoint;
+ pid->error = ptcache_softbody_error;
- pid->write_point = ptcache_softbody_write;
- pid->read_point = ptcache_softbody_read;
- pid->interpolate_point = ptcache_softbody_interpolate;
+ pid->write_point = ptcache_softbody_write;
+ pid->read_point = ptcache_softbody_read;
+ pid->interpolate_point = ptcache_softbody_interpolate;
- pid->write_stream = NULL;
- pid->read_stream = NULL;
+ pid->write_stream = NULL;
+ pid->read_stream = NULL;
- pid->write_openvdb_stream = NULL;
- pid->read_openvdb_stream = NULL;
+ pid->write_openvdb_stream = NULL;
+ pid->read_openvdb_stream = NULL;
- pid->write_extra_data = NULL;
- pid->read_extra_data = NULL;
- pid->interpolate_extra_data = NULL;
+ pid->write_extra_data = NULL;
+ pid->read_extra_data = NULL;
+ pid->interpolate_extra_data = NULL;
- pid->write_header = ptcache_basic_header_write;
- pid->read_header = ptcache_basic_header_read;
+ pid->write_header = ptcache_basic_header_write;
+ pid->read_header = ptcache_basic_header_read;
- pid->data_types= (1<<BPHYS_DATA_LOCATION) | (1<<BPHYS_DATA_VELOCITY);
- pid->info_types= 0;
+ pid->data_types = (1 << BPHYS_DATA_LOCATION) | (1 << BPHYS_DATA_VELOCITY);
+ pid->info_types = 0;
- pid->stack_index = pid->cache->index;
+ pid->stack_index = pid->cache->index;
- pid->default_step = 10;
- pid->max_step = 20;
- pid->file_type = PTCACHE_FILE_PTCACHE;
+ pid->default_step = 10;
+ pid->max_step = 20;
+ pid->file_type = PTCACHE_FILE_PTCACHE;
}
void BKE_ptcache_id_from_particles(PTCacheID *pid, Object *ob, ParticleSystem *psys)
{
- memset(pid, 0, sizeof(PTCacheID));
-
- pid->ob= ob;
- pid->calldata= psys;
- pid->type= PTCACHE_TYPE_PARTICLES;
- pid->stack_index= psys->pointcache->index;
- pid->cache= psys->pointcache;
- pid->cache_ptr= &psys->pointcache;
- pid->ptcaches= &psys->ptcaches;
-
- if (psys->part->type != PART_HAIR)
- pid->flag |= PTCACHE_VEL_PER_SEC;
-
- pid->totpoint = ptcache_particle_totpoint;
- pid->totwrite = ptcache_particle_totwrite;
- pid->error = ptcache_particle_error;
-
- pid->write_point = ptcache_particle_write;
- pid->read_point = ptcache_particle_read;
- pid->interpolate_point = ptcache_particle_interpolate;
-
- pid->write_stream = NULL;
- pid->read_stream = NULL;
-
- pid->write_openvdb_stream = NULL;
- pid->read_openvdb_stream = NULL;
-
- pid->write_extra_data = NULL;
- pid->read_extra_data = NULL;
- pid->interpolate_extra_data = NULL;
-
- pid->write_header = ptcache_basic_header_write;
- pid->read_header = ptcache_basic_header_read;
-
- pid->data_types = (1<<BPHYS_DATA_LOCATION) | (1<<BPHYS_DATA_VELOCITY) | (1<<BPHYS_DATA_INDEX);
-
- if (psys->part->phystype == PART_PHYS_BOIDS)
- pid->data_types|= (1<<BPHYS_DATA_AVELOCITY) | (1<<BPHYS_DATA_ROTATION) | (1<<BPHYS_DATA_BOIDS);
- else if (psys->part->phystype == PART_PHYS_FLUID && psys->part->fluid && psys->part->fluid->flag & SPH_VISCOELASTIC_SPRINGS) {
- pid->write_extra_data = ptcache_particle_extra_write;
- pid->read_extra_data = ptcache_particle_extra_read;
- }
-
- if (psys->part->flag & PART_ROTATIONS) {
- pid->data_types|= (1<<BPHYS_DATA_ROTATION);
-
- if (psys->part->rotmode != PART_ROT_VEL ||
- psys->part->avemode == PART_AVE_RAND ||
- psys->part->avefac != 0.0f)
- {
- pid->data_types |= (1 << BPHYS_DATA_AVELOCITY);
- }
- }
-
- pid->info_types= (1<<BPHYS_DATA_TIMES);
-
- pid->default_step = 10;
- pid->max_step = 20;
- pid->file_type = PTCACHE_FILE_PTCACHE;
+ memset(pid, 0, sizeof(PTCacheID));
+
+ pid->ob = ob;
+ pid->calldata = psys;
+ pid->type = PTCACHE_TYPE_PARTICLES;
+ pid->stack_index = psys->pointcache->index;
+ pid->cache = psys->pointcache;
+ pid->cache_ptr = &psys->pointcache;
+ pid->ptcaches = &psys->ptcaches;
+
+ if (psys->part->type != PART_HAIR)
+ pid->flag |= PTCACHE_VEL_PER_SEC;
+
+ pid->totpoint = ptcache_particle_totpoint;
+ pid->totwrite = ptcache_particle_totwrite;
+ pid->error = ptcache_particle_error;
+
+ pid->write_point = ptcache_particle_write;
+ pid->read_point = ptcache_particle_read;
+ pid->interpolate_point = ptcache_particle_interpolate;
+
+ pid->write_stream = NULL;
+ pid->read_stream = NULL;
+
+ pid->write_openvdb_stream = NULL;
+ pid->read_openvdb_stream = NULL;
+
+ pid->write_extra_data = NULL;
+ pid->read_extra_data = NULL;
+ pid->interpolate_extra_data = NULL;
+
+ pid->write_header = ptcache_basic_header_write;
+ pid->read_header = ptcache_basic_header_read;
+
+ pid->data_types = (1 << BPHYS_DATA_LOCATION) | (1 << BPHYS_DATA_VELOCITY) |
+ (1 << BPHYS_DATA_INDEX);
+
+ if (psys->part->phystype == PART_PHYS_BOIDS)
+ pid->data_types |= (1 << BPHYS_DATA_AVELOCITY) | (1 << BPHYS_DATA_ROTATION) |
+ (1 << BPHYS_DATA_BOIDS);
+ else if (psys->part->phystype == PART_PHYS_FLUID && psys->part->fluid &&
+ psys->part->fluid->flag & SPH_VISCOELASTIC_SPRINGS) {
+ pid->write_extra_data = ptcache_particle_extra_write;
+ pid->read_extra_data = ptcache_particle_extra_read;
+ }
+
+ if (psys->part->flag & PART_ROTATIONS) {
+ pid->data_types |= (1 << BPHYS_DATA_ROTATION);
+
+ if (psys->part->rotmode != PART_ROT_VEL || psys->part->avemode == PART_AVE_RAND ||
+ psys->part->avefac != 0.0f) {
+ pid->data_types |= (1 << BPHYS_DATA_AVELOCITY);
+ }
+ }
+
+ pid->info_types = (1 << BPHYS_DATA_TIMES);
+
+ pid->default_step = 10;
+ pid->max_step = 20;
+ pid->file_type = PTCACHE_FILE_PTCACHE;
}
void BKE_ptcache_id_from_cloth(PTCacheID *pid, Object *ob, ClothModifierData *clmd)
{
- memset(pid, 0, sizeof(PTCacheID));
-
- pid->ob= ob;
- pid->calldata= clmd;
- pid->type= PTCACHE_TYPE_CLOTH;
- pid->stack_index= clmd->point_cache->index;
- pid->cache= clmd->point_cache;
- pid->cache_ptr= &clmd->point_cache;
- pid->ptcaches= &clmd->ptcaches;
- pid->totpoint= pid->totwrite= ptcache_cloth_totpoint;
- pid->error = ptcache_cloth_error;
-
- pid->write_point = ptcache_cloth_write;
- pid->read_point = ptcache_cloth_read;
- pid->interpolate_point = ptcache_cloth_interpolate;
-
- pid->write_openvdb_stream = NULL;
- pid->read_openvdb_stream = NULL;
-
- pid->write_stream = NULL;
- pid->read_stream = NULL;
-
- pid->write_extra_data = NULL;
- pid->read_extra_data = NULL;
- pid->interpolate_extra_data = NULL;
-
- pid->write_header = ptcache_basic_header_write;
- pid->read_header = ptcache_basic_header_read;
-
- pid->data_types= (1<<BPHYS_DATA_LOCATION) | (1<<BPHYS_DATA_VELOCITY) | (1<<BPHYS_DATA_XCONST);
- pid->info_types= 0;
-
- pid->default_step = 1;
- pid->max_step = 1;
- pid->file_type = PTCACHE_FILE_PTCACHE;
+ memset(pid, 0, sizeof(PTCacheID));
+
+ pid->ob = ob;
+ pid->calldata = clmd;
+ pid->type = PTCACHE_TYPE_CLOTH;
+ pid->stack_index = clmd->point_cache->index;
+ pid->cache = clmd->point_cache;
+ pid->cache_ptr = &clmd->point_cache;
+ pid->ptcaches = &clmd->ptcaches;
+ pid->totpoint = pid->totwrite = ptcache_cloth_totpoint;
+ pid->error = ptcache_cloth_error;
+
+ pid->write_point = ptcache_cloth_write;
+ pid->read_point = ptcache_cloth_read;
+ pid->interpolate_point = ptcache_cloth_interpolate;
+
+ pid->write_openvdb_stream = NULL;
+ pid->read_openvdb_stream = NULL;
+
+ pid->write_stream = NULL;
+ pid->read_stream = NULL;
+
+ pid->write_extra_data = NULL;
+ pid->read_extra_data = NULL;
+ pid->interpolate_extra_data = NULL;
+
+ pid->write_header = ptcache_basic_header_write;
+ pid->read_header = ptcache_basic_header_read;
+
+ pid->data_types = (1 << BPHYS_DATA_LOCATION) | (1 << BPHYS_DATA_VELOCITY) |
+ (1 << BPHYS_DATA_XCONST);
+ pid->info_types = 0;
+
+ pid->default_step = 1;
+ pid->max_step = 1;
+ pid->file_type = PTCACHE_FILE_PTCACHE;
}
void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct SmokeModifierData *smd)
{
- SmokeDomainSettings *sds = smd->domain;
+ SmokeDomainSettings *sds = smd->domain;
- memset(pid, 0, sizeof(PTCacheID));
+ memset(pid, 0, sizeof(PTCacheID));
- pid->ob= ob;
- pid->calldata= smd;
+ pid->ob = ob;
+ pid->calldata = smd;
- pid->type= PTCACHE_TYPE_SMOKE_DOMAIN;
- pid->stack_index= sds->point_cache[0]->index;
+ pid->type = PTCACHE_TYPE_SMOKE_DOMAIN;
+ pid->stack_index = sds->point_cache[0]->index;
- pid->cache= sds->point_cache[0];
- pid->cache_ptr= &(sds->point_cache[0]);
- pid->ptcaches= &(sds->ptcaches[0]);
+ pid->cache = sds->point_cache[0];
+ pid->cache_ptr = &(sds->point_cache[0]);
+ pid->ptcaches = &(sds->ptcaches[0]);
- pid->totpoint= pid->totwrite= ptcache_smoke_totpoint;
- pid->error = ptcache_smoke_error;
+ pid->totpoint = pid->totwrite = ptcache_smoke_totpoint;
+ pid->error = ptcache_smoke_error;
- pid->write_point = NULL;
- pid->read_point = NULL;
- pid->interpolate_point = NULL;
+ pid->write_point = NULL;
+ pid->read_point = NULL;
+ pid->interpolate_point = NULL;
- pid->read_stream = ptcache_smoke_read;
- pid->write_stream = ptcache_smoke_write;
+ pid->read_stream = ptcache_smoke_read;
+ pid->write_stream = ptcache_smoke_write;
- pid->write_openvdb_stream = ptcache_smoke_openvdb_write;
- pid->read_openvdb_stream = ptcache_smoke_openvdb_read;
+ pid->write_openvdb_stream = ptcache_smoke_openvdb_write;
+ pid->read_openvdb_stream = ptcache_smoke_openvdb_read;
- pid->write_extra_data = NULL;
- pid->read_extra_data = NULL;
- pid->interpolate_extra_data = NULL;
+ pid->write_extra_data = NULL;
+ pid->read_extra_data = NULL;
+ pid->interpolate_extra_data = NULL;
- pid->write_header = ptcache_basic_header_write;
- pid->read_header = ptcache_basic_header_read;
+ pid->write_header = ptcache_basic_header_write;
+ pid->read_header = ptcache_basic_header_read;
- pid->data_types= 0;
- pid->info_types= 0;
+ pid->data_types = 0;
+ pid->info_types = 0;
- if (sds->fluid)
- pid->data_types |= (1<<BPHYS_DATA_SMOKE_LOW);
- if (sds->wt)
- pid->data_types |= (1<<BPHYS_DATA_SMOKE_HIGH);
+ if (sds->fluid)
+ pid->data_types |= (1 << BPHYS_DATA_SMOKE_LOW);
+ if (sds->wt)
+ pid->data_types |= (1 << BPHYS_DATA_SMOKE_HIGH);
- pid->default_step = 1;
- pid->max_step = 1;
- pid->file_type = smd->domain->cache_file_format;
+ pid->default_step = 1;
+ pid->max_step = 1;
+ pid->file_type = smd->domain->cache_file_format;
}
void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid, Object *ob, DynamicPaintSurface *surface)
{
- memset(pid, 0, sizeof(PTCacheID));
+ memset(pid, 0, sizeof(PTCacheID));
- pid->ob= ob;
- pid->calldata= surface;
- pid->type= PTCACHE_TYPE_DYNAMICPAINT;
- pid->cache= surface->pointcache;
- pid->cache_ptr= &surface->pointcache;
- pid->ptcaches= &surface->ptcaches;
- pid->totpoint= pid->totwrite= ptcache_dynamicpaint_totpoint;
- pid->error = ptcache_dynamicpaint_error;
+ pid->ob = ob;
+ pid->calldata = surface;
+ pid->type = PTCACHE_TYPE_DYNAMICPAINT;
+ pid->cache = surface->pointcache;
+ pid->cache_ptr = &surface->pointcache;
+ pid->ptcaches = &surface->ptcaches;
+ pid->totpoint = pid->totwrite = ptcache_dynamicpaint_totpoint;
+ pid->error = ptcache_dynamicpaint_error;
- pid->write_point = NULL;
- pid->read_point = NULL;
- pid->interpolate_point = NULL;
+ pid->write_point = NULL;
+ pid->read_point = NULL;
+ pid->interpolate_point = NULL;
- pid->write_stream = ptcache_dynamicpaint_write;
- pid->read_stream = ptcache_dynamicpaint_read;
+ pid->write_stream = ptcache_dynamicpaint_write;
+ pid->read_stream = ptcache_dynamicpaint_read;
- pid->write_openvdb_stream = NULL;
- pid->read_openvdb_stream = NULL;
+ pid->write_openvdb_stream = NULL;
+ pid->read_openvdb_stream = NULL;
- pid->write_extra_data = NULL;
- pid->read_extra_data = NULL;
- pid->interpolate_extra_data = NULL;
+ pid->write_extra_data = NULL;
+ pid->read_extra_data = NULL;
+ pid->interpolate_extra_data = NULL;
- pid->write_header = ptcache_basic_header_write;
- pid->read_header = ptcache_basic_header_read;
+ pid->write_header = ptcache_basic_header_write;
+ pid->read_header = ptcache_basic_header_read;
- pid->data_types= BPHYS_DATA_DYNAMICPAINT;
- pid->info_types= 0;
+ pid->data_types = BPHYS_DATA_DYNAMICPAINT;
+ pid->info_types = 0;
- pid->stack_index = pid->cache->index;
+ pid->stack_index = pid->cache->index;
- pid->default_step = 1;
- pid->max_step = 1;
- pid->file_type = PTCACHE_FILE_PTCACHE;
+ pid->default_step = 1;
+ pid->max_step = 1;
+ pid->file_type = PTCACHE_FILE_PTCACHE;
}
void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, Object *ob, RigidBodyWorld *rbw)
{
- memset(pid, 0, sizeof(PTCacheID));
+ memset(pid, 0, sizeof(PTCacheID));
- pid->ob= ob;
- pid->calldata= rbw;
- pid->type= PTCACHE_TYPE_RIGIDBODY;
- pid->cache= rbw->shared->pointcache;
- pid->cache_ptr= &rbw->shared->pointcache;
- pid->ptcaches= &rbw->shared->ptcaches;
- pid->totpoint= pid->totwrite= ptcache_rigidbody_totpoint;
- pid->error = ptcache_rigidbody_error;
+ pid->ob = ob;
+ pid->calldata = rbw;
+ pid->type = PTCACHE_TYPE_RIGIDBODY;
+ pid->cache = rbw->shared->pointcache;
+ pid->cache_ptr = &rbw->shared->pointcache;
+ pid->ptcaches = &rbw->shared->ptcaches;
+ pid->totpoint = pid->totwrite = ptcache_rigidbody_totpoint;
+ pid->error = ptcache_rigidbody_error;
- pid->write_point = ptcache_rigidbody_write;
- pid->read_point = ptcache_rigidbody_read;
- pid->interpolate_point = ptcache_rigidbody_interpolate;
+ pid->write_point = ptcache_rigidbody_write;
+ pid->read_point = ptcache_rigidbody_read;
+ pid->interpolate_point = ptcache_rigidbody_interpolate;
- pid->write_stream = NULL;
- pid->read_stream = NULL;
+ pid->write_stream = NULL;
+ pid->read_stream = NULL;
- pid->write_openvdb_stream = NULL;
- pid->read_openvdb_stream = NULL;
+ pid->write_openvdb_stream = NULL;
+ pid->read_openvdb_stream = NULL;
- pid->write_extra_data = NULL;
- pid->read_extra_data = NULL;
- pid->interpolate_extra_data = NULL;
+ pid->write_extra_data = NULL;
+ pid->read_extra_data = NULL;
+ pid->interpolate_extra_data = NULL;
- pid->write_header = ptcache_basic_header_write;
- pid->read_header = ptcache_basic_header_read;
+ pid->write_header = ptcache_basic_header_write;
+ pid->read_header = ptcache_basic_header_read;
- pid->data_types= (1<<BPHYS_DATA_LOCATION) | (1<<BPHYS_DATA_ROTATION);
- pid->info_types= 0;
+ pid->data_types = (1 << BPHYS_DATA_LOCATION) | (1 << BPHYS_DATA_ROTATION);
+ pid->info_types = 0;
- pid->stack_index = pid->cache->index;
+ pid->stack_index = pid->cache->index;
- pid->default_step = 1;
- pid->max_step = 1;
- pid->file_type = PTCACHE_FILE_PTCACHE;
+ pid->default_step = 1;
+ pid->max_step = 1;
+ pid->file_type = PTCACHE_FILE_PTCACHE;
}
PTCacheID BKE_ptcache_id_find(Object *ob, Scene *scene, PointCache *cache)
{
- PTCacheID result = {0};
+ PTCacheID result = {0};
- ListBase pidlist;
- BKE_ptcache_ids_from_object(&pidlist, ob, scene, MAX_DUPLI_RECUR);
+ ListBase pidlist;
+ BKE_ptcache_ids_from_object(&pidlist, ob, scene, MAX_DUPLI_RECUR);
- for (PTCacheID *pid = pidlist.first; pid; pid = pid->next) {
- if (pid->cache == cache) {
- result = *pid;
- break;
- }
- }
+ for (PTCacheID *pid = pidlist.first; pid; pid = pid->next) {
+ if (pid->cache == cache) {
+ result = *pid;
+ break;
+ }
+ }
- BLI_freelistN(&pidlist);
+ BLI_freelistN(&pidlist);
- return result;
+ return result;
}
/* Callback which is used by point cache foreach() family of functions.
@@ -1683,173 +1827,155 @@ static bool foreach_object_particle_ptcache(Object *object,
ForeachPtcacheCb callback,
void *callback_user_data)
{
- PTCacheID pid;
- for (ParticleSystem *psys = object->particlesystem.first;
- psys != NULL;
- psys = psys->next)
- {
- if (psys->part==NULL) {
- continue;
- }
- /* Check to make sure point cache is actually used by the particles. */
- if (ELEM(psys->part->phystype, PART_PHYS_NO, PART_PHYS_KEYED)) {
- continue;
- }
- /* Hair needs to be included in id-list for cache edit mode to work. */
+ PTCacheID pid;
+ for (ParticleSystem *psys = object->particlesystem.first; psys != NULL; psys = psys->next) {
+ if (psys->part == NULL) {
+ continue;
+ }
+ /* Check to make sure point cache is actually used by the particles. */
+ if (ELEM(psys->part->phystype, PART_PHYS_NO, PART_PHYS_KEYED)) {
+ continue;
+ }
+ /* Hair needs to be included in id-list for cache edit mode to work. */
#if 0
- if ((psys->part->type == PART_HAIR) &&
- (psys->flag & PSYS_HAIR_DYNAMICS) == 0)
- {
- continue;
- }
+ if ((psys->part->type == PART_HAIR) &&
+ (psys->flag & PSYS_HAIR_DYNAMICS) == 0)
+ {
+ continue;
+ }
#endif
- if (psys->part->type == PART_FLUID) {
- continue;
- }
- BKE_ptcache_id_from_particles(&pid, object, psys);
- if (!callback(&pid, callback_user_data)) {
- return false;
- }
- }
- return true;
+ if (psys->part->type == PART_FLUID) {
+ continue;
+ }
+ BKE_ptcache_id_from_particles(&pid, object, psys);
+ if (!callback(&pid, callback_user_data)) {
+ return false;
+ }
+ }
+ return true;
}
static bool foreach_object_modifier_ptcache(Object *object,
ForeachPtcacheCb callback,
void *callback_user_data)
{
- PTCacheID pid;
- for (ModifierData *md = object->modifiers.first; md != NULL; md = md->next) {
- if (md->type == eModifierType_Cloth) {
- BKE_ptcache_id_from_cloth(&pid, object, (ClothModifierData*)md);
- if (!callback(&pid, callback_user_data)) {
- return false;
- }
- }
- else if (md->type == eModifierType_Smoke) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
- if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
- BKE_ptcache_id_from_smoke(&pid, object, (SmokeModifierData*)md);
- if (!callback(&pid, callback_user_data)) {
- return false;
- }
- }
- }
- else if (md->type == eModifierType_DynamicPaint) {
- DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
- if (pmd->canvas) {
- DynamicPaintSurface *surface = pmd->canvas->surfaces.first;
- for (; surface; surface=surface->next) {
- BKE_ptcache_id_from_dynamicpaint(&pid, object, surface);
- if (!callback(&pid, callback_user_data)) {
- return false;
- }
- }
- }
- }
- }
- return true;
+ PTCacheID pid;
+ for (ModifierData *md = object->modifiers.first; md != NULL; md = md->next) {
+ if (md->type == eModifierType_Cloth) {
+ BKE_ptcache_id_from_cloth(&pid, object, (ClothModifierData *)md);
+ if (!callback(&pid, callback_user_data)) {
+ return false;
+ }
+ }
+ else if (md->type == eModifierType_Smoke) {
+ SmokeModifierData *smd = (SmokeModifierData *)md;
+ if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
+ BKE_ptcache_id_from_smoke(&pid, object, (SmokeModifierData *)md);
+ if (!callback(&pid, callback_user_data)) {
+ return false;
+ }
+ }
+ }
+ else if (md->type == eModifierType_DynamicPaint) {
+ DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
+ if (pmd->canvas) {
+ DynamicPaintSurface *surface = pmd->canvas->surfaces.first;
+ for (; surface; surface = surface->next) {
+ BKE_ptcache_id_from_dynamicpaint(&pid, object, surface);
+ if (!callback(&pid, callback_user_data)) {
+ return false;
+ }
+ }
+ }
+ }
+ }
+ return true;
}
/* Return false if any of callbacks returned false. */
-static bool foreach_object_ptcache(Scene *scene,
- Object *object,
- int duplis,
- ForeachPtcacheCb callback,
- void *callback_user_data)
+static bool foreach_object_ptcache(
+ Scene *scene, Object *object, int duplis, ForeachPtcacheCb callback, void *callback_user_data)
{
- PTCacheID pid;
- /* Soft body. */
- if (object->soft != NULL) {
- BKE_ptcache_id_from_softbody(&pid, object, object->soft);
- if (!callback(&pid, callback_user_data)) {
- return false;
- }
- }
- /* Particle systems. */
- if (!foreach_object_particle_ptcache(object, callback, callback_user_data)) {
- return false;
- }
- /* Modifiers. */
- if (!foreach_object_modifier_ptcache(object, callback, callback_user_data)) {
- return false;
- }
- /* Rigid body. */
- if (scene != NULL &&
- object->rigidbody_object != NULL &&
- scene->rigidbody_world != NULL)
- {
- BKE_ptcache_id_from_rigidbody(&pid, object, scene->rigidbody_world);
- if (!callback(&pid, callback_user_data)) {
- return false;
- }
- }
- /* Consider all object in dupli groups to be part of the same object,
- * for baking with linking dupligroups. Once we have better overrides
- * this can be revisited so users select the local objects directly. */
- if (scene != NULL && (duplis-- > 0) && (object->instance_collection != NULL)) {
- FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(object->instance_collection,
- current_object)
- {
- if (current_object == object) {
- continue;
- }
- foreach_object_ptcache(scene,
- current_object,
- duplis,
- callback,
- callback_user_data);
- }
- FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
- }
- return true;
+ PTCacheID pid;
+ /* Soft body. */
+ if (object->soft != NULL) {
+ BKE_ptcache_id_from_softbody(&pid, object, object->soft);
+ if (!callback(&pid, callback_user_data)) {
+ return false;
+ }
+ }
+ /* Particle systems. */
+ if (!foreach_object_particle_ptcache(object, callback, callback_user_data)) {
+ return false;
+ }
+ /* Modifiers. */
+ if (!foreach_object_modifier_ptcache(object, callback, callback_user_data)) {
+ return false;
+ }
+ /* Rigid body. */
+ if (scene != NULL && object->rigidbody_object != NULL && scene->rigidbody_world != NULL) {
+ BKE_ptcache_id_from_rigidbody(&pid, object, scene->rigidbody_world);
+ if (!callback(&pid, callback_user_data)) {
+ return false;
+ }
+ }
+ /* Consider all object in dupli groups to be part of the same object,
+ * for baking with linking dupligroups. Once we have better overrides
+ * this can be revisited so users select the local objects directly. */
+ if (scene != NULL && (duplis-- > 0) && (object->instance_collection != NULL)) {
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (object->instance_collection, current_object) {
+ if (current_object == object) {
+ continue;
+ }
+ foreach_object_ptcache(scene, current_object, duplis, callback, callback_user_data);
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+ }
+ return true;
}
typedef struct PTCacheIDsFromObjectData {
- ListBase *list_base;
+ ListBase *list_base;
} PTCacheIDsFromObjectData;
static bool ptcache_ids_from_object_cb(PTCacheID *pid, void *userdata)
{
- PTCacheIDsFromObjectData *data = userdata;
- PTCacheID *own_pid = MEM_mallocN(sizeof(PTCacheID), "PTCacheID");
- *own_pid = *pid;
- BLI_addtail(data->list_base, own_pid);
- return true;
+ PTCacheIDsFromObjectData *data = userdata;
+ PTCacheID *own_pid = MEM_mallocN(sizeof(PTCacheID), "PTCacheID");
+ *own_pid = *pid;
+ BLI_addtail(data->list_base, own_pid);
+ return true;
}
void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob, Scene *scene, int duplis)
{
- PTCacheIDsFromObjectData data;
- lb->first = lb->last = NULL;
- data.list_base = lb;
- foreach_object_ptcache(
- scene, ob, duplis, ptcache_ids_from_object_cb, &data);
+ PTCacheIDsFromObjectData data;
+ lb->first = lb->last = NULL;
+ data.list_base = lb;
+ foreach_object_ptcache(scene, ob, duplis, ptcache_ids_from_object_cb, &data);
}
-static bool ptcache_object_has_cb(PTCacheID *UNUSED(pid),
- void *UNUSED(userdata))
+static bool ptcache_object_has_cb(PTCacheID *UNUSED(pid), void *UNUSED(userdata))
{
- return false;
+ return false;
}
bool BKE_ptcache_object_has(struct Scene *scene, struct Object *ob, int duplis)
{
- return !foreach_object_ptcache(
- scene, ob, duplis, ptcache_object_has_cb, NULL);
+ return !foreach_object_ptcache(scene, ob, duplis, ptcache_object_has_cb, NULL);
}
/* File handling */
static const char *ptcache_file_extension(const PTCacheID *pid)
{
- switch (pid->file_type) {
- default:
- case PTCACHE_FILE_PTCACHE:
- return PTCACHE_EXT;
- case PTCACHE_FILE_OPENVDB:
- return ".vdb";
- }
+ switch (pid->file_type) {
+ default:
+ case PTCACHE_FILE_PTCACHE:
+ return PTCACHE_EXT;
+ case PTCACHE_FILE_OPENVDB:
+ return ".vdb";
+ }
}
/**
@@ -1857,20 +1983,20 @@ static const char *ptcache_file_extension(const PTCacheID *pid)
*/
static int ptcache_frame_from_filename(const char *filename, const char *ext)
{
- const int frame_len = 6;
- const int ext_len = frame_len + strlen(ext);
- const int len = strlen(filename);
+ const int frame_len = 6;
+ const int ext_len = frame_len + strlen(ext);
+ const int len = strlen(filename);
- /* could crash if trying to copy a string out of this range */
- if (len > ext_len) {
- /* using frame_len here gives compile error (vla) */
- char num[/* frame_len */6 + 1];
- BLI_strncpy(num, filename + len - ext_len, sizeof(num));
+ /* could crash if trying to copy a string out of this range */
+ if (len > ext_len) {
+ /* using frame_len here gives compile error (vla) */
+ char num[/* frame_len */ 6 + 1];
+ BLI_strncpy(num, filename + len - ext_len, sizeof(num));
- return atoi(num);
- }
+ return atoi(num);
+ }
- return -1;
+ return -1;
}
/* Takes an Object ID and returns a unique name
@@ -1884,1162 +2010,1203 @@ static int ptcache_frame_from_filename(const char *filename, const char *ext)
static int ptcache_path(PTCacheID *pid, char *filename)
{
- Library *lib = (pid->ob) ? pid->ob->id.lib : NULL;
- const char *blendfilename= (lib && (pid->cache->flag & PTCACHE_IGNORE_LIBPATH)==0) ? lib->filepath: BKE_main_blendfile_path_from_global();
- size_t i;
-
- if (pid->cache->flag & PTCACHE_EXTERNAL) {
- strcpy(filename, pid->cache->path);
-
- if (BLI_path_is_rel(filename)) {
- BLI_path_abs(filename, blendfilename);
- }
-
- return BLI_add_slash(filename); /* new strlen() */
- }
- else if (G.relbase_valid || lib) {
- char file[MAX_PTCACHE_PATH]; /* we don't want the dir, only the file */
-
- BLI_split_file_part(blendfilename, file, sizeof(file));
- i = strlen(file);
-
- /* remove .blend */
- if (i > 6)
- file[i-6] = '\0';
-
- BLI_snprintf(filename, MAX_PTCACHE_PATH, "//"PTCACHE_PATH"%s", file); /* add blend file name to pointcache dir */
- BLI_path_abs(filename, blendfilename);
- return BLI_add_slash(filename); /* new strlen() */
- }
-
- /* use the temp path. this is weak but better then not using point cache at all */
- /* temporary directory is assumed to exist and ALWAYS has a trailing slash */
- BLI_snprintf(filename, MAX_PTCACHE_PATH, "%s"PTCACHE_PATH, BKE_tempdir_session());
-
- return BLI_add_slash(filename); /* new strlen() */
+ Library *lib = (pid->ob) ? pid->ob->id.lib : NULL;
+ const char *blendfilename = (lib && (pid->cache->flag & PTCACHE_IGNORE_LIBPATH) == 0) ?
+ lib->filepath :
+ BKE_main_blendfile_path_from_global();
+ size_t i;
+
+ if (pid->cache->flag & PTCACHE_EXTERNAL) {
+ strcpy(filename, pid->cache->path);
+
+ if (BLI_path_is_rel(filename)) {
+ BLI_path_abs(filename, blendfilename);
+ }
+
+ return BLI_add_slash(filename); /* new strlen() */
+ }
+ else if (G.relbase_valid || lib) {
+ char file[MAX_PTCACHE_PATH]; /* we don't want the dir, only the file */
+
+ BLI_split_file_part(blendfilename, file, sizeof(file));
+ i = strlen(file);
+
+ /* remove .blend */
+ if (i > 6)
+ file[i - 6] = '\0';
+
+ BLI_snprintf(filename,
+ MAX_PTCACHE_PATH,
+ "//" PTCACHE_PATH "%s",
+ file); /* add blend file name to pointcache dir */
+ BLI_path_abs(filename, blendfilename);
+ return BLI_add_slash(filename); /* new strlen() */
+ }
+
+ /* use the temp path. this is weak but better then not using point cache at all */
+ /* temporary directory is assumed to exist and ALWAYS has a trailing slash */
+ BLI_snprintf(filename, MAX_PTCACHE_PATH, "%s" PTCACHE_PATH, BKE_tempdir_session());
+
+ return BLI_add_slash(filename); /* new strlen() */
}
static int ptcache_filename(PTCacheID *pid, char *filename, int cfra, short do_path, short do_ext)
{
- int len=0;
- char *idname;
- char *newname;
- filename[0] = '\0';
- newname = filename;
-
- if (!G.relbase_valid && (pid->cache->flag & PTCACHE_EXTERNAL)==0) return 0; /* save blend file before using disk pointcache */
-
- /* start with temp dir */
- if (do_path) {
- len = ptcache_path(pid, filename);
- newname += len;
- }
- if (pid->cache->name[0] == '\0' && (pid->cache->flag & PTCACHE_EXTERNAL)==0) {
- idname = (pid->ob->id.name + 2);
- /* convert chars to hex so they are always a valid filename */
- while ('\0' != *idname) {
- BLI_snprintf(newname, MAX_PTCACHE_FILE, "%02X", (unsigned int)(*idname++));
- newname+=2;
- len += 2;
- }
- }
- else {
- int temp = (int)strlen(pid->cache->name);
- strcpy(newname, pid->cache->name);
- newname+=temp;
- len += temp;
- }
-
- if (do_ext) {
- if (pid->cache->index < 0)
- pid->cache->index = pid->stack_index = BKE_object_insert_ptcache(pid->ob);
-
- const char *ext = ptcache_file_extension(pid);
-
- if (pid->cache->flag & PTCACHE_EXTERNAL) {
- if (pid->cache->index >= 0)
- BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d_%02u%s", cfra, pid->stack_index, ext); /* always 6 chars */
- else
- BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d%s", cfra, ext); /* always 6 chars */
- }
- else {
- BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d_%02u%s", cfra, pid->stack_index, ext); /* always 6 chars */
- }
- len += 16;
- }
-
- return len; /* make sure the above string is always 16 chars */
+ int len = 0;
+ char *idname;
+ char *newname;
+ filename[0] = '\0';
+ newname = filename;
+
+ if (!G.relbase_valid && (pid->cache->flag & PTCACHE_EXTERNAL) == 0)
+ return 0; /* save blend file before using disk pointcache */
+
+ /* start with temp dir */
+ if (do_path) {
+ len = ptcache_path(pid, filename);
+ newname += len;
+ }
+ if (pid->cache->name[0] == '\0' && (pid->cache->flag & PTCACHE_EXTERNAL) == 0) {
+ idname = (pid->ob->id.name + 2);
+ /* convert chars to hex so they are always a valid filename */
+ while ('\0' != *idname) {
+ BLI_snprintf(newname, MAX_PTCACHE_FILE, "%02X", (unsigned int)(*idname++));
+ newname += 2;
+ len += 2;
+ }
+ }
+ else {
+ int temp = (int)strlen(pid->cache->name);
+ strcpy(newname, pid->cache->name);
+ newname += temp;
+ len += temp;
+ }
+
+ if (do_ext) {
+ if (pid->cache->index < 0)
+ pid->cache->index = pid->stack_index = BKE_object_insert_ptcache(pid->ob);
+
+ const char *ext = ptcache_file_extension(pid);
+
+ if (pid->cache->flag & PTCACHE_EXTERNAL) {
+ if (pid->cache->index >= 0)
+ BLI_snprintf(newname,
+ MAX_PTCACHE_FILE,
+ "_%06d_%02u%s",
+ cfra,
+ pid->stack_index,
+ ext); /* always 6 chars */
+ else
+ BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d%s", cfra, ext); /* always 6 chars */
+ }
+ else {
+ BLI_snprintf(newname,
+ MAX_PTCACHE_FILE,
+ "_%06d_%02u%s",
+ cfra,
+ pid->stack_index,
+ ext); /* always 6 chars */
+ }
+ len += 16;
+ }
+
+ return len; /* make sure the above string is always 16 chars */
}
/* youll need to close yourself after! */
static PTCacheFile *ptcache_file_open(PTCacheID *pid, int mode, int cfra)
{
- PTCacheFile *pf;
- FILE *fp = NULL;
- char filename[FILE_MAX * 2];
+ PTCacheFile *pf;
+ FILE *fp = NULL;
+ char filename[FILE_MAX * 2];
#ifndef DURIAN_POINTCACHE_LIB_OK
- /* don't allow writing for linked objects */
- if (pid->ob->id.lib && mode == PTCACHE_FILE_WRITE)
- return NULL;
+ /* don't allow writing for linked objects */
+ if (pid->ob->id.lib && mode == PTCACHE_FILE_WRITE)
+ return NULL;
#endif
- if (!G.relbase_valid && (pid->cache->flag & PTCACHE_EXTERNAL)==0) return NULL; /* save blend file before using disk pointcache */
-
- ptcache_filename(pid, filename, cfra, 1, 1);
-
- if (mode==PTCACHE_FILE_READ) {
- fp = BLI_fopen(filename, "rb");
- }
- else if (mode==PTCACHE_FILE_WRITE) {
- BLI_make_existing_file(filename); /* will create the dir if needs be, same as //textures is created */
- fp = BLI_fopen(filename, "wb");
- }
- else if (mode==PTCACHE_FILE_UPDATE) {
- BLI_make_existing_file(filename);
- fp = BLI_fopen(filename, "rb+");
- }
-
- if (!fp)
- return NULL;
-
- pf= MEM_mallocN(sizeof(PTCacheFile), "PTCacheFile");
- pf->fp= fp;
- pf->old_format = 0;
- pf->frame = cfra;
-
- return pf;
+ if (!G.relbase_valid && (pid->cache->flag & PTCACHE_EXTERNAL) == 0)
+ return NULL; /* save blend file before using disk pointcache */
+
+ ptcache_filename(pid, filename, cfra, 1, 1);
+
+ if (mode == PTCACHE_FILE_READ) {
+ fp = BLI_fopen(filename, "rb");
+ }
+ else if (mode == PTCACHE_FILE_WRITE) {
+ BLI_make_existing_file(
+ filename); /* will create the dir if needs be, same as //textures is created */
+ fp = BLI_fopen(filename, "wb");
+ }
+ else if (mode == PTCACHE_FILE_UPDATE) {
+ BLI_make_existing_file(filename);
+ fp = BLI_fopen(filename, "rb+");
+ }
+
+ if (!fp)
+ return NULL;
+
+ pf = MEM_mallocN(sizeof(PTCacheFile), "PTCacheFile");
+ pf->fp = fp;
+ pf->old_format = 0;
+ pf->frame = cfra;
+
+ return pf;
}
static void ptcache_file_close(PTCacheFile *pf)
{
- if (pf) {
- fclose(pf->fp);
- MEM_freeN(pf);
- }
+ if (pf) {
+ fclose(pf->fp);
+ MEM_freeN(pf);
+ }
}
static int ptcache_file_compressed_read(PTCacheFile *pf, unsigned char *result, unsigned int len)
{
- int r = 0;
- unsigned char compressed = 0;
- size_t in_len;
+ int r = 0;
+ unsigned char compressed = 0;
+ size_t in_len;
#ifdef WITH_LZO
- size_t out_len = len;
+ size_t out_len = len;
#endif
- unsigned char *in;
- unsigned char *props = MEM_callocN(16 * sizeof(char), "tmp");
-
- ptcache_file_read(pf, &compressed, 1, sizeof(unsigned char));
- if (compressed) {
- unsigned int size;
- ptcache_file_read(pf, &size, 1, sizeof(unsigned int));
- in_len = (size_t)size;
- if (in_len==0) {
- /* do nothing */
- }
- else {
- in = (unsigned char *)MEM_callocN(sizeof(unsigned char)*in_len, "pointcache_compressed_buffer");
- ptcache_file_read(pf, in, in_len, sizeof(unsigned char));
+ unsigned char *in;
+ unsigned char *props = MEM_callocN(16 * sizeof(char), "tmp");
+
+ ptcache_file_read(pf, &compressed, 1, sizeof(unsigned char));
+ if (compressed) {
+ unsigned int size;
+ ptcache_file_read(pf, &size, 1, sizeof(unsigned int));
+ in_len = (size_t)size;
+ if (in_len == 0) {
+ /* do nothing */
+ }
+ else {
+ in = (unsigned char *)MEM_callocN(sizeof(unsigned char) * in_len,
+ "pointcache_compressed_buffer");
+ ptcache_file_read(pf, in, in_len, sizeof(unsigned char));
#ifdef WITH_LZO
- if (compressed == 1)
- r = lzo1x_decompress_safe(in, (lzo_uint)in_len, result, (lzo_uint *)&out_len, NULL);
+ if (compressed == 1)
+ r = lzo1x_decompress_safe(in, (lzo_uint)in_len, result, (lzo_uint *)&out_len, NULL);
#endif
#ifdef WITH_LZMA
- if (compressed == 2) {
- size_t sizeOfIt;
- size_t leni = in_len, leno = len;
- ptcache_file_read(pf, &size, 1, sizeof(unsigned int));
- sizeOfIt = (size_t)size;
- ptcache_file_read(pf, props, sizeOfIt, sizeof(unsigned char));
- r = LzmaUncompress(result, &leno, in, &leni, props, sizeOfIt);
- }
+ if (compressed == 2) {
+ size_t sizeOfIt;
+ size_t leni = in_len, leno = len;
+ ptcache_file_read(pf, &size, 1, sizeof(unsigned int));
+ sizeOfIt = (size_t)size;
+ ptcache_file_read(pf, props, sizeOfIt, sizeof(unsigned char));
+ r = LzmaUncompress(result, &leno, in, &leni, props, sizeOfIt);
+ }
#endif
- MEM_freeN(in);
- }
- }
- else {
- ptcache_file_read(pf, result, len, sizeof(unsigned char));
- }
+ MEM_freeN(in);
+ }
+ }
+ else {
+ ptcache_file_read(pf, result, len, sizeof(unsigned char));
+ }
- MEM_freeN(props);
+ MEM_freeN(props);
- return r;
+ return r;
}
-static int ptcache_file_compressed_write(PTCacheFile *pf, unsigned char *in, unsigned int in_len, unsigned char *out, int mode)
+static int ptcache_file_compressed_write(
+ PTCacheFile *pf, unsigned char *in, unsigned int in_len, unsigned char *out, int mode)
{
- int r = 0;
- unsigned char compressed = 0;
- size_t out_len= 0;
- unsigned char *props = MEM_callocN(16 * sizeof(char), "tmp");
- size_t sizeOfIt = 5;
+ int r = 0;
+ unsigned char compressed = 0;
+ size_t out_len = 0;
+ unsigned char *props = MEM_callocN(16 * sizeof(char), "tmp");
+ size_t sizeOfIt = 5;
- (void)mode; /* unused when building w/o compression */
+ (void)mode; /* unused when building w/o compression */
#ifdef WITH_LZO
- out_len= LZO_OUT_LEN(in_len);
- if (mode == 1) {
- LZO_HEAP_ALLOC(wrkmem, LZO1X_MEM_COMPRESS);
-
- r = lzo1x_1_compress(in, (lzo_uint)in_len, out, (lzo_uint *)&out_len, wrkmem);
- if (!(r == LZO_E_OK) || (out_len >= in_len))
- compressed = 0;
- else
- compressed = 1;
- }
+ out_len = LZO_OUT_LEN(in_len);
+ if (mode == 1) {
+ LZO_HEAP_ALLOC(wrkmem, LZO1X_MEM_COMPRESS);
+
+ r = lzo1x_1_compress(in, (lzo_uint)in_len, out, (lzo_uint *)&out_len, wrkmem);
+ if (!(r == LZO_E_OK) || (out_len >= in_len))
+ compressed = 0;
+ else
+ compressed = 1;
+ }
#endif
#ifdef WITH_LZMA
- if (mode == 2) {
-
- r = LzmaCompress(out, &out_len, in, in_len, //assume sizeof(char)==1....
- props, &sizeOfIt, 5, 1 << 24, 3, 0, 2, 32, 2);
-
- if (!(r == SZ_OK) || (out_len >= in_len))
- compressed = 0;
- else
- compressed = 2;
- }
+ if (mode == 2) {
+
+ r = LzmaCompress(out,
+ &out_len,
+ in,
+ in_len, //assume sizeof(char)==1....
+ props,
+ &sizeOfIt,
+ 5,
+ 1 << 24,
+ 3,
+ 0,
+ 2,
+ 32,
+ 2);
+
+ if (!(r == SZ_OK) || (out_len >= in_len))
+ compressed = 0;
+ else
+ compressed = 2;
+ }
#endif
- ptcache_file_write(pf, &compressed, 1, sizeof(unsigned char));
- if (compressed) {
- unsigned int size = out_len;
- ptcache_file_write(pf, &size, 1, sizeof(unsigned int));
- ptcache_file_write(pf, out, out_len, sizeof(unsigned char));
- }
- else
- ptcache_file_write(pf, in, in_len, sizeof(unsigned char));
+ ptcache_file_write(pf, &compressed, 1, sizeof(unsigned char));
+ if (compressed) {
+ unsigned int size = out_len;
+ ptcache_file_write(pf, &size, 1, sizeof(unsigned int));
+ ptcache_file_write(pf, out, out_len, sizeof(unsigned char));
+ }
+ else
+ ptcache_file_write(pf, in, in_len, sizeof(unsigned char));
- if (compressed == 2) {
- unsigned int size = sizeOfIt;
- ptcache_file_write(pf, &sizeOfIt, 1, sizeof(unsigned int));
- ptcache_file_write(pf, props, size, sizeof(unsigned char));
- }
+ if (compressed == 2) {
+ unsigned int size = sizeOfIt;
+ ptcache_file_write(pf, &sizeOfIt, 1, sizeof(unsigned int));
+ ptcache_file_write(pf, props, size, sizeof(unsigned char));
+ }
- MEM_freeN(props);
+ MEM_freeN(props);
- return r;
+ return r;
}
static int ptcache_file_read(PTCacheFile *pf, void *f, unsigned int tot, unsigned int size)
{
- return (fread(f, size, tot, pf->fp) == tot);
+ return (fread(f, size, tot, pf->fp) == tot);
}
static int ptcache_file_write(PTCacheFile *pf, const void *f, unsigned int tot, unsigned int size)
{
- return (fwrite(f, size, tot, pf->fp) == tot);
+ return (fwrite(f, size, tot, pf->fp) == tot);
}
static int ptcache_file_data_read(PTCacheFile *pf)
{
- int i;
+ int i;
- for (i=0; i<BPHYS_TOT_DATA; i++) {
- if ((pf->data_types & (1<<i)) && !ptcache_file_read(pf, pf->cur[i], 1, ptcache_data_size[i]))
- return 0;
- }
+ for (i = 0; i < BPHYS_TOT_DATA; i++) {
+ if ((pf->data_types & (1 << i)) && !ptcache_file_read(pf, pf->cur[i], 1, ptcache_data_size[i]))
+ return 0;
+ }
- return 1;
+ return 1;
}
static int ptcache_file_data_write(PTCacheFile *pf)
{
- int i;
+ int i;
- for (i=0; i<BPHYS_TOT_DATA; i++) {
- if ((pf->data_types & (1<<i)) && !ptcache_file_write(pf, pf->cur[i], 1, ptcache_data_size[i]))
- return 0;
- }
+ for (i = 0; i < BPHYS_TOT_DATA; i++) {
+ if ((pf->data_types & (1 << i)) &&
+ !ptcache_file_write(pf, pf->cur[i], 1, ptcache_data_size[i]))
+ return 0;
+ }
- return 1;
+ return 1;
}
static int ptcache_file_header_begin_read(PTCacheFile *pf)
{
- unsigned int typeflag=0;
- int error=0;
- char bphysics[8];
+ unsigned int typeflag = 0;
+ int error = 0;
+ char bphysics[8];
- pf->data_types = 0;
+ pf->data_types = 0;
- if (fread(bphysics, sizeof(char), 8, pf->fp) != 8)
- error = 1;
+ if (fread(bphysics, sizeof(char), 8, pf->fp) != 8)
+ error = 1;
- if (!error && !STREQLEN(bphysics, "BPHYSICS", 8))
- error = 1;
+ if (!error && !STREQLEN(bphysics, "BPHYSICS", 8))
+ error = 1;
- if (!error && !fread(&typeflag, sizeof(unsigned int), 1, pf->fp))
- error = 1;
+ if (!error && !fread(&typeflag, sizeof(unsigned int), 1, pf->fp))
+ error = 1;
- pf->type = (typeflag & PTCACHE_TYPEFLAG_TYPEMASK);
- pf->flag = (typeflag & PTCACHE_TYPEFLAG_FLAGMASK);
+ pf->type = (typeflag & PTCACHE_TYPEFLAG_TYPEMASK);
+ pf->flag = (typeflag & PTCACHE_TYPEFLAG_FLAGMASK);
- /* if there was an error set file as it was */
- if (error)
- fseek(pf->fp, 0, SEEK_SET);
+ /* if there was an error set file as it was */
+ if (error)
+ fseek(pf->fp, 0, SEEK_SET);
- return !error;
+ return !error;
}
static int ptcache_file_header_begin_write(PTCacheFile *pf)
{
- const char *bphysics = "BPHYSICS";
- unsigned int typeflag = pf->type + pf->flag;
+ const char *bphysics = "BPHYSICS";
+ unsigned int typeflag = pf->type + pf->flag;
- if (fwrite(bphysics, sizeof(char), 8, pf->fp) != 8)
- return 0;
+ if (fwrite(bphysics, sizeof(char), 8, pf->fp) != 8)
+ return 0;
- if (!fwrite(&typeflag, sizeof(unsigned int), 1, pf->fp))
- return 0;
+ if (!fwrite(&typeflag, sizeof(unsigned int), 1, pf->fp))
+ return 0;
- return 1;
+ return 1;
}
/* Data pointer handling */
int BKE_ptcache_data_size(int data_type)
{
- return ptcache_data_size[data_type];
+ return ptcache_data_size[data_type];
}
static void ptcache_file_pointers_init(PTCacheFile *pf)
{
- int data_types = pf->data_types;
-
- pf->cur[BPHYS_DATA_INDEX] = (data_types & (1<<BPHYS_DATA_INDEX)) ? &pf->data.index : NULL;
- pf->cur[BPHYS_DATA_LOCATION] = (data_types & (1<<BPHYS_DATA_LOCATION)) ? &pf->data.loc : NULL;
- pf->cur[BPHYS_DATA_VELOCITY] = (data_types & (1<<BPHYS_DATA_VELOCITY)) ? &pf->data.vel : NULL;
- pf->cur[BPHYS_DATA_ROTATION] = (data_types & (1<<BPHYS_DATA_ROTATION)) ? &pf->data.rot : NULL;
- pf->cur[BPHYS_DATA_AVELOCITY] = (data_types & (1<<BPHYS_DATA_AVELOCITY))? &pf->data.ave : NULL;
- pf->cur[BPHYS_DATA_SIZE] = (data_types & (1<<BPHYS_DATA_SIZE)) ? &pf->data.size : NULL;
- pf->cur[BPHYS_DATA_TIMES] = (data_types & (1<<BPHYS_DATA_TIMES)) ? &pf->data.times : NULL;
- pf->cur[BPHYS_DATA_BOIDS] = (data_types & (1<<BPHYS_DATA_BOIDS)) ? &pf->data.boids : NULL;
+ int data_types = pf->data_types;
+
+ pf->cur[BPHYS_DATA_INDEX] = (data_types & (1 << BPHYS_DATA_INDEX)) ? &pf->data.index : NULL;
+ pf->cur[BPHYS_DATA_LOCATION] = (data_types & (1 << BPHYS_DATA_LOCATION)) ? &pf->data.loc : NULL;
+ pf->cur[BPHYS_DATA_VELOCITY] = (data_types & (1 << BPHYS_DATA_VELOCITY)) ? &pf->data.vel : NULL;
+ pf->cur[BPHYS_DATA_ROTATION] = (data_types & (1 << BPHYS_DATA_ROTATION)) ? &pf->data.rot : NULL;
+ pf->cur[BPHYS_DATA_AVELOCITY] = (data_types & (1 << BPHYS_DATA_AVELOCITY)) ? &pf->data.ave :
+ NULL;
+ pf->cur[BPHYS_DATA_SIZE] = (data_types & (1 << BPHYS_DATA_SIZE)) ? &pf->data.size : NULL;
+ pf->cur[BPHYS_DATA_TIMES] = (data_types & (1 << BPHYS_DATA_TIMES)) ? &pf->data.times : NULL;
+ pf->cur[BPHYS_DATA_BOIDS] = (data_types & (1 << BPHYS_DATA_BOIDS)) ? &pf->data.boids : NULL;
}
/* Check to see if point number "index" is in pm, uses binary search for index data. */
int BKE_ptcache_mem_index_find(PTCacheMem *pm, unsigned int index)
{
- if (pm->totpoint > 0 && pm->data[BPHYS_DATA_INDEX]) {
- unsigned int *data = pm->data[BPHYS_DATA_INDEX];
- unsigned int mid, low = 0, high = pm->totpoint - 1;
-
- if (index < *data || index > *(data+high))
- return -1;
-
- /* check simple case for continuous indexes first */
- if (index-*data < high && data[index-*data] == index)
- return index-*data;
-
- while (low <= high) {
- mid= (low + high)/2;
-
- if (data[mid] > index)
- high = mid - 1;
- else if (data[mid] < index)
- low = mid + 1;
- else
- return mid;
- }
-
- return -1;
- }
- else {
- return (index < pm->totpoint ? index : -1);
- }
+ if (pm->totpoint > 0 && pm->data[BPHYS_DATA_INDEX]) {
+ unsigned int *data = pm->data[BPHYS_DATA_INDEX];
+ unsigned int mid, low = 0, high = pm->totpoint - 1;
+
+ if (index < *data || index > *(data + high))
+ return -1;
+
+ /* check simple case for continuous indexes first */
+ if (index - *data < high && data[index - *data] == index)
+ return index - *data;
+
+ while (low <= high) {
+ mid = (low + high) / 2;
+
+ if (data[mid] > index)
+ high = mid - 1;
+ else if (data[mid] < index)
+ low = mid + 1;
+ else
+ return mid;
+ }
+
+ return -1;
+ }
+ else {
+ return (index < pm->totpoint ? index : -1);
+ }
}
void BKE_ptcache_mem_pointers_init(PTCacheMem *pm)
{
- int data_types = pm->data_types;
- int i;
+ int data_types = pm->data_types;
+ int i;
- for (i=0; i<BPHYS_TOT_DATA; i++)
- pm->cur[i] = ((data_types & (1<<i)) ? pm->data[i] : NULL);
+ for (i = 0; i < BPHYS_TOT_DATA; i++)
+ pm->cur[i] = ((data_types & (1 << i)) ? pm->data[i] : NULL);
}
void BKE_ptcache_mem_pointers_incr(PTCacheMem *pm)
{
- int i;
+ int i;
- for (i=0; i<BPHYS_TOT_DATA; i++) {
- if (pm->cur[i])
- pm->cur[i] = (char *)pm->cur[i] + ptcache_data_size[i];
- }
+ for (i = 0; i < BPHYS_TOT_DATA; i++) {
+ if (pm->cur[i])
+ pm->cur[i] = (char *)pm->cur[i] + ptcache_data_size[i];
+ }
}
-int BKE_ptcache_mem_pointers_seek(int point_index, PTCacheMem *pm)
+int BKE_ptcache_mem_pointers_seek(int point_index, PTCacheMem *pm)
{
- int data_types = pm->data_types;
- int i, index = BKE_ptcache_mem_index_find(pm, point_index);
-
- if (index < 0) {
- /* Can't give proper location without reallocation, so don't give any location.
- * Some points will be cached improperly, but this only happens with simulation
- * steps bigger than cache->step, so the cache has to be recalculated anyways
- * at some point.
- */
- return 0;
- }
-
- for (i=0; i<BPHYS_TOT_DATA; i++)
- pm->cur[i] = data_types & (1<<i) ? (char *)pm->data[i] + index * ptcache_data_size[i] : NULL;
-
- return 1;
+ int data_types = pm->data_types;
+ int i, index = BKE_ptcache_mem_index_find(pm, point_index);
+
+ if (index < 0) {
+ /* Can't give proper location without reallocation, so don't give any location.
+ * Some points will be cached improperly, but this only happens with simulation
+ * steps bigger than cache->step, so the cache has to be recalculated anyways
+ * at some point.
+ */
+ return 0;
+ }
+
+ for (i = 0; i < BPHYS_TOT_DATA; i++)
+ pm->cur[i] = data_types & (1 << i) ? (char *)pm->data[i] + index * ptcache_data_size[i] : NULL;
+
+ return 1;
}
static void ptcache_data_alloc(PTCacheMem *pm)
{
- int data_types = pm->data_types;
- int totpoint = pm->totpoint;
- int i;
-
- for (i=0; i<BPHYS_TOT_DATA; i++) {
- if (data_types & (1<<i))
- pm->data[i] = MEM_callocN(totpoint * ptcache_data_size[i], "PTCache Data");
- }
+ int data_types = pm->data_types;
+ int totpoint = pm->totpoint;
+ int i;
+
+ for (i = 0; i < BPHYS_TOT_DATA; i++) {
+ if (data_types & (1 << i))
+ pm->data[i] = MEM_callocN(totpoint * ptcache_data_size[i], "PTCache Data");
+ }
}
static void ptcache_data_free(PTCacheMem *pm)
{
- void **data = pm->data;
- int i;
+ void **data = pm->data;
+ int i;
- for (i=0; i<BPHYS_TOT_DATA; i++) {
- if (data[i])
- MEM_freeN(data[i]);
- }
+ for (i = 0; i < BPHYS_TOT_DATA; i++) {
+ if (data[i])
+ MEM_freeN(data[i]);
+ }
}
static void ptcache_data_copy(void *from[], void *to[])
{
- int i;
- for (i=0; i<BPHYS_TOT_DATA; i++) {
- /* note, durian file 03.4b_comp crashes if to[i] is not tested
- * its NULL, not sure if this should be fixed elsewhere but for now its needed */
- if (from[i] && to[i])
- memcpy(to[i], from[i], ptcache_data_size[i]);
- }
+ int i;
+ for (i = 0; i < BPHYS_TOT_DATA; i++) {
+ /* note, durian file 03.4b_comp crashes if to[i] is not tested
+ * its NULL, not sure if this should be fixed elsewhere but for now its needed */
+ if (from[i] && to[i])
+ memcpy(to[i], from[i], ptcache_data_size[i]);
+ }
}
static void ptcache_extra_free(PTCacheMem *pm)
{
- PTCacheExtra *extra = pm->extradata.first;
+ PTCacheExtra *extra = pm->extradata.first;
- if (extra) {
- for (; extra; extra=extra->next) {
- if (extra->data)
- MEM_freeN(extra->data);
- }
+ if (extra) {
+ for (; extra; extra = extra->next) {
+ if (extra->data)
+ MEM_freeN(extra->data);
+ }
- BLI_freelistN(&pm->extradata);
- }
+ BLI_freelistN(&pm->extradata);
+ }
}
static int ptcache_old_elemsize(PTCacheID *pid)
{
- if (pid->type==PTCACHE_TYPE_SOFTBODY)
- return 6 * sizeof(float);
- else if (pid->type==PTCACHE_TYPE_PARTICLES)
- return sizeof(ParticleKey);
- else if (pid->type==PTCACHE_TYPE_CLOTH)
- return 9 * sizeof(float);
-
- return 0;
+ if (pid->type == PTCACHE_TYPE_SOFTBODY)
+ return 6 * sizeof(float);
+ else if (pid->type == PTCACHE_TYPE_PARTICLES)
+ return sizeof(ParticleKey);
+ else if (pid->type == PTCACHE_TYPE_CLOTH)
+ return 9 * sizeof(float);
+
+ return 0;
}
static void ptcache_find_frames_around(PTCacheID *pid, unsigned int frame, int *fra1, int *fra2)
{
- if (pid->cache->flag & PTCACHE_DISK_CACHE) {
- int cfra1=frame, cfra2=frame+1;
-
- while (cfra1 >= pid->cache->startframe && !BKE_ptcache_id_exist(pid, cfra1))
- cfra1--;
-
- if (cfra1 < pid->cache->startframe)
- cfra1 = 0;
-
- while (cfra2 <= pid->cache->endframe && !BKE_ptcache_id_exist(pid, cfra2))
- cfra2++;
-
- if (cfra2 > pid->cache->endframe)
- cfra2 = 0;
-
- if (cfra1 && !cfra2) {
- *fra1 = 0;
- *fra2 = cfra1;
- }
- else {
- *fra1 = cfra1;
- *fra2 = cfra2;
- }
- }
- else if (pid->cache->mem_cache.first) {
- PTCacheMem *pm = pid->cache->mem_cache.first;
- PTCacheMem *pm2 = pid->cache->mem_cache.last;
-
- while (pm->next && pm->next->frame <= frame)
- pm= pm->next;
-
- if (pm2->frame < frame) {
- pm2 = NULL;
- }
- else {
- while (pm2->prev && pm2->prev->frame > frame) {
- pm2= pm2->prev;
- }
- }
-
- if (!pm2) {
- *fra1 = 0;
- *fra2 = pm->frame;
- }
- else {
- *fra1 = pm->frame;
- *fra2 = pm2->frame;
- }
- }
+ if (pid->cache->flag & PTCACHE_DISK_CACHE) {
+ int cfra1 = frame, cfra2 = frame + 1;
+
+ while (cfra1 >= pid->cache->startframe && !BKE_ptcache_id_exist(pid, cfra1))
+ cfra1--;
+
+ if (cfra1 < pid->cache->startframe)
+ cfra1 = 0;
+
+ while (cfra2 <= pid->cache->endframe && !BKE_ptcache_id_exist(pid, cfra2))
+ cfra2++;
+
+ if (cfra2 > pid->cache->endframe)
+ cfra2 = 0;
+
+ if (cfra1 && !cfra2) {
+ *fra1 = 0;
+ *fra2 = cfra1;
+ }
+ else {
+ *fra1 = cfra1;
+ *fra2 = cfra2;
+ }
+ }
+ else if (pid->cache->mem_cache.first) {
+ PTCacheMem *pm = pid->cache->mem_cache.first;
+ PTCacheMem *pm2 = pid->cache->mem_cache.last;
+
+ while (pm->next && pm->next->frame <= frame)
+ pm = pm->next;
+
+ if (pm2->frame < frame) {
+ pm2 = NULL;
+ }
+ else {
+ while (pm2->prev && pm2->prev->frame > frame) {
+ pm2 = pm2->prev;
+ }
+ }
+
+ if (!pm2) {
+ *fra1 = 0;
+ *fra2 = pm->frame;
+ }
+ else {
+ *fra1 = pm->frame;
+ *fra2 = pm2->frame;
+ }
+ }
}
static PTCacheMem *ptcache_disk_frame_to_mem(PTCacheID *pid, int cfra)
{
- PTCacheFile *pf = ptcache_file_open(pid, PTCACHE_FILE_READ, cfra);
- PTCacheMem *pm = NULL;
- unsigned int i, error = 0;
-
- if (pf == NULL)
- return NULL;
-
- if (!ptcache_file_header_begin_read(pf))
- error = 1;
-
- if (!error && (pf->type != pid->type || !pid->read_header(pf)))
- error = 1;
-
- if (!error) {
- pm = MEM_callocN(sizeof(PTCacheMem), "Pointcache mem");
-
- pm->totpoint = pf->totpoint;
- pm->data_types = pf->data_types;
- pm->frame = pf->frame;
-
- ptcache_data_alloc(pm);
-
- if (pf->flag & PTCACHE_TYPEFLAG_COMPRESS) {
- for (i=0; i<BPHYS_TOT_DATA; i++) {
- unsigned int out_len = pm->totpoint*ptcache_data_size[i];
- if (pf->data_types & (1<<i))
- ptcache_file_compressed_read(pf, (unsigned char *)(pm->data[i]), out_len);
- }
- }
- else {
- BKE_ptcache_mem_pointers_init(pm);
- ptcache_file_pointers_init(pf);
-
- for (i=0; i<pm->totpoint; i++) {
- if (!ptcache_file_data_read(pf)) {
- error = 1;
- break;
- }
- ptcache_data_copy(pf->cur, pm->cur);
- BKE_ptcache_mem_pointers_incr(pm);
- }
- }
- }
-
- if (!error && pf->flag & PTCACHE_TYPEFLAG_EXTRADATA) {
- unsigned int extratype = 0;
-
- while (ptcache_file_read(pf, &extratype, 1, sizeof(unsigned int))) {
- PTCacheExtra *extra = MEM_callocN(sizeof(PTCacheExtra), "Pointcache extradata");
-
- extra->type = extratype;
-
- ptcache_file_read(pf, &extra->totdata, 1, sizeof(unsigned int));
-
- extra->data = MEM_callocN(extra->totdata * ptcache_extra_datasize[extra->type], "Pointcache extradata->data");
-
- if (pf->flag & PTCACHE_TYPEFLAG_COMPRESS)
- ptcache_file_compressed_read(pf, (unsigned char *)(extra->data), extra->totdata*ptcache_extra_datasize[extra->type]);
- else
- ptcache_file_read(pf, extra->data, extra->totdata, ptcache_extra_datasize[extra->type]);
-
- BLI_addtail(&pm->extradata, extra);
- }
- }
-
- if (error && pm) {
- ptcache_data_free(pm);
- ptcache_extra_free(pm);
- MEM_freeN(pm);
- pm = NULL;
- }
-
- ptcache_file_close(pf);
-
- if (error && G.debug & G_DEBUG)
- printf("Error reading from disk cache\n");
-
- return pm;
+ PTCacheFile *pf = ptcache_file_open(pid, PTCACHE_FILE_READ, cfra);
+ PTCacheMem *pm = NULL;
+ unsigned int i, error = 0;
+
+ if (pf == NULL)
+ return NULL;
+
+ if (!ptcache_file_header_begin_read(pf))
+ error = 1;
+
+ if (!error && (pf->type != pid->type || !pid->read_header(pf)))
+ error = 1;
+
+ if (!error) {
+ pm = MEM_callocN(sizeof(PTCacheMem), "Pointcache mem");
+
+ pm->totpoint = pf->totpoint;
+ pm->data_types = pf->data_types;
+ pm->frame = pf->frame;
+
+ ptcache_data_alloc(pm);
+
+ if (pf->flag & PTCACHE_TYPEFLAG_COMPRESS) {
+ for (i = 0; i < BPHYS_TOT_DATA; i++) {
+ unsigned int out_len = pm->totpoint * ptcache_data_size[i];
+ if (pf->data_types & (1 << i))
+ ptcache_file_compressed_read(pf, (unsigned char *)(pm->data[i]), out_len);
+ }
+ }
+ else {
+ BKE_ptcache_mem_pointers_init(pm);
+ ptcache_file_pointers_init(pf);
+
+ for (i = 0; i < pm->totpoint; i++) {
+ if (!ptcache_file_data_read(pf)) {
+ error = 1;
+ break;
+ }
+ ptcache_data_copy(pf->cur, pm->cur);
+ BKE_ptcache_mem_pointers_incr(pm);
+ }
+ }
+ }
+
+ if (!error && pf->flag & PTCACHE_TYPEFLAG_EXTRADATA) {
+ unsigned int extratype = 0;
+
+ while (ptcache_file_read(pf, &extratype, 1, sizeof(unsigned int))) {
+ PTCacheExtra *extra = MEM_callocN(sizeof(PTCacheExtra), "Pointcache extradata");
+
+ extra->type = extratype;
+
+ ptcache_file_read(pf, &extra->totdata, 1, sizeof(unsigned int));
+
+ extra->data = MEM_callocN(extra->totdata * ptcache_extra_datasize[extra->type],
+ "Pointcache extradata->data");
+
+ if (pf->flag & PTCACHE_TYPEFLAG_COMPRESS)
+ ptcache_file_compressed_read(pf,
+ (unsigned char *)(extra->data),
+ extra->totdata * ptcache_extra_datasize[extra->type]);
+ else
+ ptcache_file_read(pf, extra->data, extra->totdata, ptcache_extra_datasize[extra->type]);
+
+ BLI_addtail(&pm->extradata, extra);
+ }
+ }
+
+ if (error && pm) {
+ ptcache_data_free(pm);
+ ptcache_extra_free(pm);
+ MEM_freeN(pm);
+ pm = NULL;
+ }
+
+ ptcache_file_close(pf);
+
+ if (error && G.debug & G_DEBUG)
+ printf("Error reading from disk cache\n");
+
+ return pm;
}
static int ptcache_mem_frame_to_disk(PTCacheID *pid, PTCacheMem *pm)
{
- PTCacheFile *pf = NULL;
- unsigned int i, error = 0;
-
- BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_FRAME, pm->frame);
-
- pf = ptcache_file_open(pid, PTCACHE_FILE_WRITE, pm->frame);
-
- if (pf == NULL) {
- if (G.debug & G_DEBUG)
- printf("Error opening disk cache file for writing\n");
- return 0;
- }
-
- pf->data_types = pm->data_types;
- pf->totpoint = pm->totpoint;
- pf->type = pid->type;
- pf->flag = 0;
-
- if (pm->extradata.first)
- pf->flag |= PTCACHE_TYPEFLAG_EXTRADATA;
-
- if (pid->cache->compression)
- pf->flag |= PTCACHE_TYPEFLAG_COMPRESS;
-
- if (!ptcache_file_header_begin_write(pf) || !pid->write_header(pf))
- error = 1;
-
- if (!error) {
- if (pid->cache->compression) {
- for (i=0; i<BPHYS_TOT_DATA; i++) {
- if (pm->data[i]) {
- unsigned int in_len = pm->totpoint*ptcache_data_size[i];
- unsigned char *out = (unsigned char *)MEM_callocN(LZO_OUT_LEN(in_len) * 4, "pointcache_lzo_buffer");
- ptcache_file_compressed_write(pf, (unsigned char *)(pm->data[i]), in_len, out, pid->cache->compression);
- MEM_freeN(out);
- }
- }
- }
- else {
- BKE_ptcache_mem_pointers_init(pm);
- ptcache_file_pointers_init(pf);
-
- for (i=0; i<pm->totpoint; i++) {
- ptcache_data_copy(pm->cur, pf->cur);
- if (!ptcache_file_data_write(pf)) {
- error = 1;
- break;
- }
- BKE_ptcache_mem_pointers_incr(pm);
- }
- }
- }
-
- if (!error && pm->extradata.first) {
- PTCacheExtra *extra = pm->extradata.first;
-
- for (; extra; extra=extra->next) {
- if (extra->data == NULL || extra->totdata == 0)
- continue;
-
- ptcache_file_write(pf, &extra->type, 1, sizeof(unsigned int));
- ptcache_file_write(pf, &extra->totdata, 1, sizeof(unsigned int));
-
- if (pid->cache->compression) {
- unsigned int in_len = extra->totdata * ptcache_extra_datasize[extra->type];
- unsigned char *out = (unsigned char *)MEM_callocN(LZO_OUT_LEN(in_len) * 4, "pointcache_lzo_buffer");
- ptcache_file_compressed_write(pf, (unsigned char *)(extra->data), in_len, out, pid->cache->compression);
- MEM_freeN(out);
- }
- else {
- ptcache_file_write(pf, extra->data, extra->totdata, ptcache_extra_datasize[extra->type]);
- }
- }
- }
-
- ptcache_file_close(pf);
-
- if (error && G.debug & G_DEBUG)
- printf("Error writing to disk cache\n");
-
- return error==0;
+ PTCacheFile *pf = NULL;
+ unsigned int i, error = 0;
+
+ BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_FRAME, pm->frame);
+
+ pf = ptcache_file_open(pid, PTCACHE_FILE_WRITE, pm->frame);
+
+ if (pf == NULL) {
+ if (G.debug & G_DEBUG)
+ printf("Error opening disk cache file for writing\n");
+ return 0;
+ }
+
+ pf->data_types = pm->data_types;
+ pf->totpoint = pm->totpoint;
+ pf->type = pid->type;
+ pf->flag = 0;
+
+ if (pm->extradata.first)
+ pf->flag |= PTCACHE_TYPEFLAG_EXTRADATA;
+
+ if (pid->cache->compression)
+ pf->flag |= PTCACHE_TYPEFLAG_COMPRESS;
+
+ if (!ptcache_file_header_begin_write(pf) || !pid->write_header(pf))
+ error = 1;
+
+ if (!error) {
+ if (pid->cache->compression) {
+ for (i = 0; i < BPHYS_TOT_DATA; i++) {
+ if (pm->data[i]) {
+ unsigned int in_len = pm->totpoint * ptcache_data_size[i];
+ unsigned char *out = (unsigned char *)MEM_callocN(LZO_OUT_LEN(in_len) * 4,
+ "pointcache_lzo_buffer");
+ ptcache_file_compressed_write(
+ pf, (unsigned char *)(pm->data[i]), in_len, out, pid->cache->compression);
+ MEM_freeN(out);
+ }
+ }
+ }
+ else {
+ BKE_ptcache_mem_pointers_init(pm);
+ ptcache_file_pointers_init(pf);
+
+ for (i = 0; i < pm->totpoint; i++) {
+ ptcache_data_copy(pm->cur, pf->cur);
+ if (!ptcache_file_data_write(pf)) {
+ error = 1;
+ break;
+ }
+ BKE_ptcache_mem_pointers_incr(pm);
+ }
+ }
+ }
+
+ if (!error && pm->extradata.first) {
+ PTCacheExtra *extra = pm->extradata.first;
+
+ for (; extra; extra = extra->next) {
+ if (extra->data == NULL || extra->totdata == 0)
+ continue;
+
+ ptcache_file_write(pf, &extra->type, 1, sizeof(unsigned int));
+ ptcache_file_write(pf, &extra->totdata, 1, sizeof(unsigned int));
+
+ if (pid->cache->compression) {
+ unsigned int in_len = extra->totdata * ptcache_extra_datasize[extra->type];
+ unsigned char *out = (unsigned char *)MEM_callocN(LZO_OUT_LEN(in_len) * 4,
+ "pointcache_lzo_buffer");
+ ptcache_file_compressed_write(
+ pf, (unsigned char *)(extra->data), in_len, out, pid->cache->compression);
+ MEM_freeN(out);
+ }
+ else {
+ ptcache_file_write(pf, extra->data, extra->totdata, ptcache_extra_datasize[extra->type]);
+ }
+ }
+ }
+
+ ptcache_file_close(pf);
+
+ if (error && G.debug & G_DEBUG)
+ printf("Error writing to disk cache\n");
+
+ return error == 0;
}
static int ptcache_read_stream(PTCacheID *pid, int cfra)
{
- PTCacheFile *pf = ptcache_file_open(pid, PTCACHE_FILE_READ, cfra);
- int error = 0;
-
- if (pid->read_stream == NULL)
- return 0;
-
- if (pf == NULL) {
- if (G.debug & G_DEBUG)
- printf("Error opening disk cache file for reading\n");
- return 0;
- }
-
- if (!ptcache_file_header_begin_read(pf)) {
- pid->error(pid->calldata, "Failed to read point cache file");
- error = 1;
- }
- else if (pf->type != pid->type) {
- pid->error(pid->calldata, "Point cache file has wrong type");
- error = 1;
- }
- else if (!pid->read_header(pf)) {
- pid->error(pid->calldata, "Failed to read point cache file header");
- error = 1;
- }
- else if (pf->totpoint != pid->totpoint(pid->calldata, cfra)) {
- pid->error(pid->calldata, "Number of points in cache does not match mesh");
- error = 1;
- }
-
- if (!error) {
- ptcache_file_pointers_init(pf);
-
- // we have stream reading here
- if (!pid->read_stream(pf, pid->calldata)) {
- pid->error(pid->calldata, "Failed to read point cache file data");
- error = 1;
- }
- }
-
- ptcache_file_close(pf);
-
- return error == 0;
+ PTCacheFile *pf = ptcache_file_open(pid, PTCACHE_FILE_READ, cfra);
+ int error = 0;
+
+ if (pid->read_stream == NULL)
+ return 0;
+
+ if (pf == NULL) {
+ if (G.debug & G_DEBUG)
+ printf("Error opening disk cache file for reading\n");
+ return 0;
+ }
+
+ if (!ptcache_file_header_begin_read(pf)) {
+ pid->error(pid->calldata, "Failed to read point cache file");
+ error = 1;
+ }
+ else if (pf->type != pid->type) {
+ pid->error(pid->calldata, "Point cache file has wrong type");
+ error = 1;
+ }
+ else if (!pid->read_header(pf)) {
+ pid->error(pid->calldata, "Failed to read point cache file header");
+ error = 1;
+ }
+ else if (pf->totpoint != pid->totpoint(pid->calldata, cfra)) {
+ pid->error(pid->calldata, "Number of points in cache does not match mesh");
+ error = 1;
+ }
+
+ if (!error) {
+ ptcache_file_pointers_init(pf);
+
+ // we have stream reading here
+ if (!pid->read_stream(pf, pid->calldata)) {
+ pid->error(pid->calldata, "Failed to read point cache file data");
+ error = 1;
+ }
+ }
+
+ ptcache_file_close(pf);
+
+ return error == 0;
}
static int ptcache_read_openvdb_stream(PTCacheID *pid, int cfra)
{
#ifdef WITH_OPENVDB
- char filename[FILE_MAX * 2];
+ char filename[FILE_MAX * 2];
- /* save blend file before using disk pointcache */
- if (!G.relbase_valid && (pid->cache->flag & PTCACHE_EXTERNAL) == 0)
- return 0;
+ /* save blend file before using disk pointcache */
+ if (!G.relbase_valid && (pid->cache->flag & PTCACHE_EXTERNAL) == 0)
+ return 0;
- ptcache_filename(pid, filename, cfra, 1, 1);
+ ptcache_filename(pid, filename, cfra, 1, 1);
- if (!BLI_exists(filename)) {
- return 0;
- }
+ if (!BLI_exists(filename)) {
+ return 0;
+ }
- struct OpenVDBReader *reader = OpenVDBReader_create();
- OpenVDBReader_open(reader, filename);
+ struct OpenVDBReader *reader = OpenVDBReader_create();
+ OpenVDBReader_open(reader, filename);
- if (!pid->read_openvdb_stream(reader, pid->calldata)) {
- return 0;
- }
+ if (!pid->read_openvdb_stream(reader, pid->calldata)) {
+ return 0;
+ }
- return 1;
+ return 1;
#else
- UNUSED_VARS(pid, cfra);
- return 0;
+ UNUSED_VARS(pid, cfra);
+ return 0;
#endif
}
static int ptcache_read(PTCacheID *pid, int cfra)
{
- PTCacheMem *pm = NULL;
- int i;
- int *index = &i;
+ PTCacheMem *pm = NULL;
+ int i;
+ int *index = &i;
- /* get a memory cache to read from */
- if (pid->cache->flag & PTCACHE_DISK_CACHE) {
- pm = ptcache_disk_frame_to_mem(pid, cfra);
- }
- else {
- pm = pid->cache->mem_cache.first;
+ /* get a memory cache to read from */
+ if (pid->cache->flag & PTCACHE_DISK_CACHE) {
+ pm = ptcache_disk_frame_to_mem(pid, cfra);
+ }
+ else {
+ pm = pid->cache->mem_cache.first;
- while (pm && pm->frame != cfra)
- pm = pm->next;
- }
+ while (pm && pm->frame != cfra)
+ pm = pm->next;
+ }
- /* read the cache */
- if (pm) {
- int totpoint = pm->totpoint;
+ /* read the cache */
+ if (pm) {
+ int totpoint = pm->totpoint;
- if ((pid->data_types & (1<<BPHYS_DATA_INDEX)) == 0) {
- int pid_totpoint = pid->totpoint(pid->calldata, cfra);
+ if ((pid->data_types & (1 << BPHYS_DATA_INDEX)) == 0) {
+ int pid_totpoint = pid->totpoint(pid->calldata, cfra);
- if (totpoint != pid_totpoint) {
- pid->error(pid->calldata, "Number of points in cache does not match mesh");
- totpoint = MIN2(totpoint, pid_totpoint);
- }
- }
+ if (totpoint != pid_totpoint) {
+ pid->error(pid->calldata, "Number of points in cache does not match mesh");
+ totpoint = MIN2(totpoint, pid_totpoint);
+ }
+ }
- BKE_ptcache_mem_pointers_init(pm);
+ BKE_ptcache_mem_pointers_init(pm);
- for (i=0; i<totpoint; i++) {
- if (pm->data_types & (1<<BPHYS_DATA_INDEX))
- index = pm->cur[BPHYS_DATA_INDEX];
+ for (i = 0; i < totpoint; i++) {
+ if (pm->data_types & (1 << BPHYS_DATA_INDEX))
+ index = pm->cur[BPHYS_DATA_INDEX];
- pid->read_point(*index, pid->calldata, pm->cur, (float)pm->frame, NULL);
+ pid->read_point(*index, pid->calldata, pm->cur, (float)pm->frame, NULL);
- BKE_ptcache_mem_pointers_incr(pm);
- }
+ BKE_ptcache_mem_pointers_incr(pm);
+ }
- if (pid->read_extra_data && pm->extradata.first)
- pid->read_extra_data(pid->calldata, pm, (float)pm->frame);
+ if (pid->read_extra_data && pm->extradata.first)
+ pid->read_extra_data(pid->calldata, pm, (float)pm->frame);
- /* clean up temporary memory cache */
- if (pid->cache->flag & PTCACHE_DISK_CACHE) {
- ptcache_data_free(pm);
- ptcache_extra_free(pm);
- MEM_freeN(pm);
- }
- }
+ /* clean up temporary memory cache */
+ if (pid->cache->flag & PTCACHE_DISK_CACHE) {
+ ptcache_data_free(pm);
+ ptcache_extra_free(pm);
+ MEM_freeN(pm);
+ }
+ }
- return 1;
+ return 1;
}
static int ptcache_interpolate(PTCacheID *pid, float cfra, int cfra1, int cfra2)
{
- PTCacheMem *pm = NULL;
- int i;
- int *index = &i;
-
- /* get a memory cache to read from */
- if (pid->cache->flag & PTCACHE_DISK_CACHE) {
- pm = ptcache_disk_frame_to_mem(pid, cfra2);
- }
- else {
- pm = pid->cache->mem_cache.first;
-
- while (pm && pm->frame != cfra2)
- pm = pm->next;
- }
-
- /* read the cache */
- if (pm) {
- int totpoint = pm->totpoint;
-
- if ((pid->data_types & (1<<BPHYS_DATA_INDEX)) == 0) {
- int pid_totpoint = pid->totpoint(pid->calldata, (int)cfra);
-
- if (totpoint != pid_totpoint) {
- pid->error(pid->calldata, "Number of points in cache does not match mesh");
- totpoint = MIN2(totpoint, pid_totpoint);
- }
- }
-
- BKE_ptcache_mem_pointers_init(pm);
-
- for (i=0; i<totpoint; i++) {
- if (pm->data_types & (1<<BPHYS_DATA_INDEX))
- index = pm->cur[BPHYS_DATA_INDEX];
-
- pid->interpolate_point(*index, pid->calldata, pm->cur, cfra, (float)cfra1, (float)cfra2, NULL);
- BKE_ptcache_mem_pointers_incr(pm);
- }
-
- if (pid->interpolate_extra_data && pm->extradata.first)
- pid->interpolate_extra_data(pid->calldata, pm, cfra, (float)cfra1, (float)cfra2);
-
- /* clean up temporary memory cache */
- if (pid->cache->flag & PTCACHE_DISK_CACHE) {
- ptcache_data_free(pm);
- ptcache_extra_free(pm);
- MEM_freeN(pm);
- }
- }
-
- return 1;
+ PTCacheMem *pm = NULL;
+ int i;
+ int *index = &i;
+
+ /* get a memory cache to read from */
+ if (pid->cache->flag & PTCACHE_DISK_CACHE) {
+ pm = ptcache_disk_frame_to_mem(pid, cfra2);
+ }
+ else {
+ pm = pid->cache->mem_cache.first;
+
+ while (pm && pm->frame != cfra2)
+ pm = pm->next;
+ }
+
+ /* read the cache */
+ if (pm) {
+ int totpoint = pm->totpoint;
+
+ if ((pid->data_types & (1 << BPHYS_DATA_INDEX)) == 0) {
+ int pid_totpoint = pid->totpoint(pid->calldata, (int)cfra);
+
+ if (totpoint != pid_totpoint) {
+ pid->error(pid->calldata, "Number of points in cache does not match mesh");
+ totpoint = MIN2(totpoint, pid_totpoint);
+ }
+ }
+
+ BKE_ptcache_mem_pointers_init(pm);
+
+ for (i = 0; i < totpoint; i++) {
+ if (pm->data_types & (1 << BPHYS_DATA_INDEX))
+ index = pm->cur[BPHYS_DATA_INDEX];
+
+ pid->interpolate_point(
+ *index, pid->calldata, pm->cur, cfra, (float)cfra1, (float)cfra2, NULL);
+ BKE_ptcache_mem_pointers_incr(pm);
+ }
+
+ if (pid->interpolate_extra_data && pm->extradata.first)
+ pid->interpolate_extra_data(pid->calldata, pm, cfra, (float)cfra1, (float)cfra2);
+
+ /* clean up temporary memory cache */
+ if (pid->cache->flag & PTCACHE_DISK_CACHE) {
+ ptcache_data_free(pm);
+ ptcache_extra_free(pm);
+ MEM_freeN(pm);
+ }
+ }
+
+ return 1;
}
/* reads cache from disk or memory */
/* possible to get old or interpolated result */
int BKE_ptcache_read(PTCacheID *pid, float cfra, bool no_extrapolate_old)
{
- int cfrai = (int)floor(cfra), cfra1=0, cfra2=0;
- int ret = 0;
-
- /* nothing to read to */
- if (pid->totpoint(pid->calldata, cfrai) == 0)
- return 0;
-
- if (pid->cache->flag & PTCACHE_READ_INFO) {
- pid->cache->flag &= ~PTCACHE_READ_INFO;
- ptcache_read(pid, 0);
- }
-
- /* first check if we have the actual frame cached */
- if (cfra == (float)cfrai && BKE_ptcache_id_exist(pid, cfrai))
- cfra1 = cfrai;
-
- /* no exact cache frame found so try to find cached frames around cfra */
- if (cfra1 == 0)
- ptcache_find_frames_around(pid, cfrai, &cfra1, &cfra2);
-
- if (cfra1 == 0 && cfra2 == 0)
- return 0;
-
- /* don't read old cache if already simulated past cached frame */
- if (no_extrapolate_old) {
- if (cfra1 == 0 && cfra2 && cfra2 <= pid->cache->simframe)
- return 0;
- if (cfra1 && cfra1 == cfra2)
- return 0;
- }
- else {
- /* avoid calling interpolate between the same frame values */
- if (cfra1 && cfra1 == cfra2)
- cfra1 = 0;
- }
-
- if (cfra1) {
- if (pid->file_type == PTCACHE_FILE_OPENVDB && pid->read_openvdb_stream) {
- if (!ptcache_read_openvdb_stream(pid, cfra1)) {
- return 0;
- }
- }
- else if (pid->read_stream) {
- if (!ptcache_read_stream(pid, cfra1))
- return 0;
- }
- else if (pid->read_point)
- ptcache_read(pid, cfra1);
- }
-
- if (cfra2) {
- if (pid->file_type == PTCACHE_FILE_OPENVDB && pid->read_openvdb_stream) {
- if (!ptcache_read_openvdb_stream(pid, cfra2)) {
- return 0;
- }
- }
- else if (pid->read_stream) {
- if (!ptcache_read_stream(pid, cfra2))
- return 0;
- }
- else if (pid->read_point) {
- if (cfra1 && cfra2 && pid->interpolate_point)
- ptcache_interpolate(pid, cfra, cfra1, cfra2);
- else
- ptcache_read(pid, cfra2);
- }
- }
-
- if (cfra1)
- ret = (cfra2 ? PTCACHE_READ_INTERPOLATED : PTCACHE_READ_EXACT);
- else if (cfra2) {
- ret = PTCACHE_READ_OLD;
- pid->cache->simframe = cfra2;
- }
-
- cfrai = (int)cfra;
- /* clear invalid cache frames so that better stuff can be simulated */
- if (pid->cache->flag & PTCACHE_OUTDATED) {
- BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_AFTER, cfrai);
- }
- else if (pid->cache->flag & PTCACHE_FRAMES_SKIPPED) {
- if (cfra <= pid->cache->last_exact)
- pid->cache->flag &= ~PTCACHE_FRAMES_SKIPPED;
-
- BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_AFTER, MAX2(cfrai, pid->cache->last_exact));
- }
-
- return ret;
+ int cfrai = (int)floor(cfra), cfra1 = 0, cfra2 = 0;
+ int ret = 0;
+
+ /* nothing to read to */
+ if (pid->totpoint(pid->calldata, cfrai) == 0)
+ return 0;
+
+ if (pid->cache->flag & PTCACHE_READ_INFO) {
+ pid->cache->flag &= ~PTCACHE_READ_INFO;
+ ptcache_read(pid, 0);
+ }
+
+ /* first check if we have the actual frame cached */
+ if (cfra == (float)cfrai && BKE_ptcache_id_exist(pid, cfrai))
+ cfra1 = cfrai;
+
+ /* no exact cache frame found so try to find cached frames around cfra */
+ if (cfra1 == 0)
+ ptcache_find_frames_around(pid, cfrai, &cfra1, &cfra2);
+
+ if (cfra1 == 0 && cfra2 == 0)
+ return 0;
+
+ /* don't read old cache if already simulated past cached frame */
+ if (no_extrapolate_old) {
+ if (cfra1 == 0 && cfra2 && cfra2 <= pid->cache->simframe)
+ return 0;
+ if (cfra1 && cfra1 == cfra2)
+ return 0;
+ }
+ else {
+ /* avoid calling interpolate between the same frame values */
+ if (cfra1 && cfra1 == cfra2)
+ cfra1 = 0;
+ }
+
+ if (cfra1) {
+ if (pid->file_type == PTCACHE_FILE_OPENVDB && pid->read_openvdb_stream) {
+ if (!ptcache_read_openvdb_stream(pid, cfra1)) {
+ return 0;
+ }
+ }
+ else if (pid->read_stream) {
+ if (!ptcache_read_stream(pid, cfra1))
+ return 0;
+ }
+ else if (pid->read_point)
+ ptcache_read(pid, cfra1);
+ }
+
+ if (cfra2) {
+ if (pid->file_type == PTCACHE_FILE_OPENVDB && pid->read_openvdb_stream) {
+ if (!ptcache_read_openvdb_stream(pid, cfra2)) {
+ return 0;
+ }
+ }
+ else if (pid->read_stream) {
+ if (!ptcache_read_stream(pid, cfra2))
+ return 0;
+ }
+ else if (pid->read_point) {
+ if (cfra1 && cfra2 && pid->interpolate_point)
+ ptcache_interpolate(pid, cfra, cfra1, cfra2);
+ else
+ ptcache_read(pid, cfra2);
+ }
+ }
+
+ if (cfra1)
+ ret = (cfra2 ? PTCACHE_READ_INTERPOLATED : PTCACHE_READ_EXACT);
+ else if (cfra2) {
+ ret = PTCACHE_READ_OLD;
+ pid->cache->simframe = cfra2;
+ }
+
+ cfrai = (int)cfra;
+ /* clear invalid cache frames so that better stuff can be simulated */
+ if (pid->cache->flag & PTCACHE_OUTDATED) {
+ BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_AFTER, cfrai);
+ }
+ else if (pid->cache->flag & PTCACHE_FRAMES_SKIPPED) {
+ if (cfra <= pid->cache->last_exact)
+ pid->cache->flag &= ~PTCACHE_FRAMES_SKIPPED;
+
+ BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_AFTER, MAX2(cfrai, pid->cache->last_exact));
+ }
+
+ return ret;
}
static int ptcache_write_stream(PTCacheID *pid, int cfra, int totpoint)
{
- PTCacheFile *pf = NULL;
- int error = 0;
+ PTCacheFile *pf = NULL;
+ int error = 0;
- BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_FRAME, cfra);
+ BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_FRAME, cfra);
- pf = ptcache_file_open(pid, PTCACHE_FILE_WRITE, cfra);
+ pf = ptcache_file_open(pid, PTCACHE_FILE_WRITE, cfra);
- if (pf==NULL) {
- if (G.debug & G_DEBUG)
- printf("Error opening disk cache file for writing\n");
- return 0;
- }
+ if (pf == NULL) {
+ if (G.debug & G_DEBUG)
+ printf("Error opening disk cache file for writing\n");
+ return 0;
+ }
- pf->data_types = pid->data_types;
- pf->totpoint = totpoint;
- pf->type = pid->type;
- pf->flag = 0;
+ pf->data_types = pid->data_types;
+ pf->totpoint = totpoint;
+ pf->type = pid->type;
+ pf->flag = 0;
- if (!error && (!ptcache_file_header_begin_write(pf) || !pid->write_header(pf)))
- error = 1;
+ if (!error && (!ptcache_file_header_begin_write(pf) || !pid->write_header(pf)))
+ error = 1;
- if (!error && pid->write_stream)
- pid->write_stream(pf, pid->calldata);
+ if (!error && pid->write_stream)
+ pid->write_stream(pf, pid->calldata);
- ptcache_file_close(pf);
+ ptcache_file_close(pf);
- if (error && G.debug & G_DEBUG)
- printf("Error writing to disk cache\n");
+ if (error && G.debug & G_DEBUG)
+ printf("Error writing to disk cache\n");
- return error == 0;
+ return error == 0;
}
static int ptcache_write_openvdb_stream(PTCacheID *pid, int cfra)
{
#ifdef WITH_OPENVDB
- struct OpenVDBWriter *writer = OpenVDBWriter_create();
- char filename[FILE_MAX * 2];
+ struct OpenVDBWriter *writer = OpenVDBWriter_create();
+ char filename[FILE_MAX * 2];
- BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_FRAME, cfra);
+ BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_FRAME, cfra);
- ptcache_filename(pid, filename, cfra, 1, 1);
- BLI_make_existing_file(filename);
+ ptcache_filename(pid, filename, cfra, 1, 1);
+ BLI_make_existing_file(filename);
- int error = pid->write_openvdb_stream(writer, pid->calldata);
+ int error = pid->write_openvdb_stream(writer, pid->calldata);
- OpenVDBWriter_write(writer, filename);
- OpenVDBWriter_free(writer);
+ OpenVDBWriter_write(writer, filename);
+ OpenVDBWriter_free(writer);
- return error == 0;
+ return error == 0;
#else
- UNUSED_VARS(pid, cfra);
- return 0;
+ UNUSED_VARS(pid, cfra);
+ return 0;
#endif
}
static int ptcache_write(PTCacheID *pid, int cfra, int overwrite)
{
- PointCache *cache = pid->cache;
- PTCacheMem *pm=NULL, *pm2=NULL;
- int totpoint = pid->totpoint(pid->calldata, cfra);
- int i, error = 0;
-
- pm = MEM_callocN(sizeof(PTCacheMem), "Pointcache mem");
-
- pm->totpoint = pid->totwrite(pid->calldata, cfra);
- pm->data_types = cfra ? pid->data_types : pid->info_types;
-
- ptcache_data_alloc(pm);
- BKE_ptcache_mem_pointers_init(pm);
-
- if (overwrite) {
- if (cache->flag & PTCACHE_DISK_CACHE) {
- int fra = cfra-1;
-
- while (fra >= cache->startframe && !BKE_ptcache_id_exist(pid, fra))
- fra--;
-
- pm2 = ptcache_disk_frame_to_mem(pid, fra);
- }
- else
- pm2 = cache->mem_cache.last;
- }
-
- if (pid->write_point) {
- for (i=0; i<totpoint; i++) {
- int write = pid->write_point(i, pid->calldata, pm->cur, cfra);
- if (write) {
- BKE_ptcache_mem_pointers_incr(pm);
-
- /* newly born particles have to be copied to previous cached frame */
- if (overwrite && write == 2 && pm2 && BKE_ptcache_mem_pointers_seek(i, pm2))
- pid->write_point(i, pid->calldata, pm2->cur, cfra);
- }
- }
- }
-
- if (pid->write_extra_data)
- pid->write_extra_data(pid->calldata, pm, cfra);
-
- pm->frame = cfra;
-
- if (cache->flag & PTCACHE_DISK_CACHE) {
- error += !ptcache_mem_frame_to_disk(pid, pm);
-
- // if (pm) /* pm is always set */
- {
- ptcache_data_free(pm);
- ptcache_extra_free(pm);
- MEM_freeN(pm);
- }
-
- if (pm2) {
- error += !ptcache_mem_frame_to_disk(pid, pm2);
- ptcache_data_free(pm2);
- ptcache_extra_free(pm2);
- MEM_freeN(pm2);
- }
- }
- else {
- BLI_addtail(&cache->mem_cache, pm);
- }
-
- return error;
+ PointCache *cache = pid->cache;
+ PTCacheMem *pm = NULL, *pm2 = NULL;
+ int totpoint = pid->totpoint(pid->calldata, cfra);
+ int i, error = 0;
+
+ pm = MEM_callocN(sizeof(PTCacheMem), "Pointcache mem");
+
+ pm->totpoint = pid->totwrite(pid->calldata, cfra);
+ pm->data_types = cfra ? pid->data_types : pid->info_types;
+
+ ptcache_data_alloc(pm);
+ BKE_ptcache_mem_pointers_init(pm);
+
+ if (overwrite) {
+ if (cache->flag & PTCACHE_DISK_CACHE) {
+ int fra = cfra - 1;
+
+ while (fra >= cache->startframe && !BKE_ptcache_id_exist(pid, fra))
+ fra--;
+
+ pm2 = ptcache_disk_frame_to_mem(pid, fra);
+ }
+ else
+ pm2 = cache->mem_cache.last;
+ }
+
+ if (pid->write_point) {
+ for (i = 0; i < totpoint; i++) {
+ int write = pid->write_point(i, pid->calldata, pm->cur, cfra);
+ if (write) {
+ BKE_ptcache_mem_pointers_incr(pm);
+
+ /* newly born particles have to be copied to previous cached frame */
+ if (overwrite && write == 2 && pm2 && BKE_ptcache_mem_pointers_seek(i, pm2))
+ pid->write_point(i, pid->calldata, pm2->cur, cfra);
+ }
+ }
+ }
+
+ if (pid->write_extra_data)
+ pid->write_extra_data(pid->calldata, pm, cfra);
+
+ pm->frame = cfra;
+
+ if (cache->flag & PTCACHE_DISK_CACHE) {
+ error += !ptcache_mem_frame_to_disk(pid, pm);
+
+ // if (pm) /* pm is always set */
+ {
+ ptcache_data_free(pm);
+ ptcache_extra_free(pm);
+ MEM_freeN(pm);
+ }
+
+ if (pm2) {
+ error += !ptcache_mem_frame_to_disk(pid, pm2);
+ ptcache_data_free(pm2);
+ ptcache_extra_free(pm2);
+ MEM_freeN(pm2);
+ }
+ }
+ else {
+ BLI_addtail(&cache->mem_cache, pm);
+ }
+
+ return error;
}
static int ptcache_write_needed(PTCacheID *pid, int cfra, int *overwrite)
{
- PointCache *cache = pid->cache;
- int ofra = 0, efra = cache->endframe;
-
- /* always start from scratch on the first frame */
- if (cfra && cfra == cache->startframe) {
- BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, cfra);
- cache->flag &= ~PTCACHE_REDO_NEEDED;
- return 1;
- }
-
- if (pid->cache->flag & PTCACHE_DISK_CACHE) {
- if (cfra==0 && cache->startframe > 0)
- return 1;
-
- /* find last cached frame */
- while (efra > cache->startframe && !BKE_ptcache_id_exist(pid, efra))
- efra--;
-
- /* find second last cached frame */
- ofra = efra-1;
- while (ofra > cache->startframe && !BKE_ptcache_id_exist(pid, ofra))
- ofra--;
- }
- else {
- PTCacheMem *pm = cache->mem_cache.last;
- /* don't write info file in memory */
- if (cfra == 0)
- return 0;
-
- if (pm == NULL)
- return 1;
-
- efra = pm->frame;
- ofra = (pm->prev ? pm->prev->frame : efra - cache->step);
- }
-
- if (efra >= cache->startframe && cfra > efra) {
- if (ofra >= cache->startframe && efra - ofra < cache->step) {
- /* overwrite previous frame */
- BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_FRAME, efra);
- *overwrite = 1;
- }
- return 1;
- }
-
- return 0;
+ PointCache *cache = pid->cache;
+ int ofra = 0, efra = cache->endframe;
+
+ /* always start from scratch on the first frame */
+ if (cfra && cfra == cache->startframe) {
+ BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, cfra);
+ cache->flag &= ~PTCACHE_REDO_NEEDED;
+ return 1;
+ }
+
+ if (pid->cache->flag & PTCACHE_DISK_CACHE) {
+ if (cfra == 0 && cache->startframe > 0)
+ return 1;
+
+ /* find last cached frame */
+ while (efra > cache->startframe && !BKE_ptcache_id_exist(pid, efra))
+ efra--;
+
+ /* find second last cached frame */
+ ofra = efra - 1;
+ while (ofra > cache->startframe && !BKE_ptcache_id_exist(pid, ofra))
+ ofra--;
+ }
+ else {
+ PTCacheMem *pm = cache->mem_cache.last;
+ /* don't write info file in memory */
+ if (cfra == 0)
+ return 0;
+
+ if (pm == NULL)
+ return 1;
+
+ efra = pm->frame;
+ ofra = (pm->prev ? pm->prev->frame : efra - cache->step);
+ }
+
+ if (efra >= cache->startframe && cfra > efra) {
+ if (ofra >= cache->startframe && efra - ofra < cache->step) {
+ /* overwrite previous frame */
+ BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_FRAME, efra);
+ *overwrite = 1;
+ }
+ return 1;
+ }
+
+ return 0;
}
/* writes cache to disk or memory */
int BKE_ptcache_write(PTCacheID *pid, unsigned int cfra)
{
- PointCache *cache = pid->cache;
- int totpoint = pid->totpoint(pid->calldata, cfra);
- int overwrite = 0, error = 0;
-
- if (totpoint == 0 || (cfra ? pid->data_types == 0 : pid->info_types == 0))
- return 0;
-
- if (ptcache_write_needed(pid, cfra, &overwrite)==0)
- return 0;
-
- if (pid->file_type == PTCACHE_FILE_OPENVDB && pid->write_openvdb_stream) {
- ptcache_write_openvdb_stream(pid, cfra);
- }
- else if (pid->write_stream) {
- ptcache_write_stream(pid, cfra, totpoint);
- }
- else if (pid->write_point) {
- error += ptcache_write(pid, cfra, overwrite);
- }
-
- /* Mark frames skipped if more than 1 frame forwards since last non-skipped frame. */
- if (cfra - cache->last_exact == 1 || cfra == cache->startframe) {
- cache->last_exact = cfra;
- cache->flag &= ~PTCACHE_FRAMES_SKIPPED;
- }
- /* Don't mark skipped when writing info file (frame 0) */
- else if (cfra)
- cache->flag |= PTCACHE_FRAMES_SKIPPED;
-
- /* Update timeline cache display */
- if (cfra && cache->cached_frames)
- cache->cached_frames[cfra-cache->startframe] = 1;
-
- BKE_ptcache_update_info(pid);
-
- return !error;
+ PointCache *cache = pid->cache;
+ int totpoint = pid->totpoint(pid->calldata, cfra);
+ int overwrite = 0, error = 0;
+
+ if (totpoint == 0 || (cfra ? pid->data_types == 0 : pid->info_types == 0))
+ return 0;
+
+ if (ptcache_write_needed(pid, cfra, &overwrite) == 0)
+ return 0;
+
+ if (pid->file_type == PTCACHE_FILE_OPENVDB && pid->write_openvdb_stream) {
+ ptcache_write_openvdb_stream(pid, cfra);
+ }
+ else if (pid->write_stream) {
+ ptcache_write_stream(pid, cfra, totpoint);
+ }
+ else if (pid->write_point) {
+ error += ptcache_write(pid, cfra, overwrite);
+ }
+
+ /* Mark frames skipped if more than 1 frame forwards since last non-skipped frame. */
+ if (cfra - cache->last_exact == 1 || cfra == cache->startframe) {
+ cache->last_exact = cfra;
+ cache->flag &= ~PTCACHE_FRAMES_SKIPPED;
+ }
+ /* Don't mark skipped when writing info file (frame 0) */
+ else if (cfra)
+ cache->flag |= PTCACHE_FRAMES_SKIPPED;
+
+ /* Update timeline cache display */
+ if (cfra && cache->cached_frames)
+ cache->cached_frames[cfra - cache->startframe] = 1;
+
+ BKE_ptcache_update_info(pid);
+
+ return !error;
}
/* youll need to close yourself after!
* mode - PTCACHE_CLEAR_ALL,
@@ -3048,549 +3215,552 @@ int BKE_ptcache_write(PTCacheID *pid, unsigned int cfra)
/* Clears & resets */
void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra)
{
- unsigned int len; /* store the length of the string */
- unsigned int sta, end;
+ unsigned int len; /* store the length of the string */
+ unsigned int sta, end;
- /* mode is same as fopen's modes */
- DIR *dir;
- struct dirent *de;
- char path[MAX_PTCACHE_PATH];
- char filename[MAX_PTCACHE_FILE];
- char path_full[MAX_PTCACHE_FILE];
- char ext[MAX_PTCACHE_PATH];
+ /* mode is same as fopen's modes */
+ DIR *dir;
+ struct dirent *de;
+ char path[MAX_PTCACHE_PATH];
+ char filename[MAX_PTCACHE_FILE];
+ char path_full[MAX_PTCACHE_FILE];
+ char ext[MAX_PTCACHE_PATH];
- if (!pid || !pid->cache || pid->cache->flag & PTCACHE_BAKED)
- return;
+ if (!pid || !pid->cache || pid->cache->flag & PTCACHE_BAKED)
+ return;
- if (pid->cache->flag & PTCACHE_IGNORE_CLEAR)
- return;
+ if (pid->cache->flag & PTCACHE_IGNORE_CLEAR)
+ return;
- sta = pid->cache->startframe;
- end = pid->cache->endframe;
+ sta = pid->cache->startframe;
+ end = pid->cache->endframe;
#ifndef DURIAN_POINTCACHE_LIB_OK
- /* don't allow clearing for linked objects */
- if (pid->ob->id.lib)
- return;
+ /* don't allow clearing for linked objects */
+ if (pid->ob->id.lib)
+ return;
#endif
- /*if (!G.relbase_valid) return; *//* save blend file before using pointcache */
-
- const char *fext = ptcache_file_extension(pid);
-
- /* clear all files in the temp dir with the prefix of the ID and the ".bphys" suffix */
- switch (mode) {
- case PTCACHE_CLEAR_ALL:
- case PTCACHE_CLEAR_BEFORE:
- case PTCACHE_CLEAR_AFTER:
- if (pid->cache->flag & PTCACHE_DISK_CACHE) {
- ptcache_path(pid, path);
-
- dir = opendir(path);
- if (dir==NULL)
- return;
-
- len = ptcache_filename(pid, filename, cfra, 0, 0); /* no path */
- /* append underscore terminator to ensure we don't match similar names
- * from objects whose names start with the same prefix
- */
- if (len < sizeof(filename) - 2) {
- BLI_strncpy(filename + len, "_", sizeof(filename) - 2 - len);
- len += 1;
- }
-
- BLI_snprintf(ext, sizeof(ext), "_%02u%s", pid->stack_index, fext);
-
- while ((de = readdir(dir)) != NULL) {
- if (strstr(de->d_name, ext)) { /* do we have the right extension?*/
- if (STREQLEN(filename, de->d_name, len)) { /* do we have the right prefix */
- if (mode == PTCACHE_CLEAR_ALL) {
- pid->cache->last_exact = MIN2(pid->cache->startframe, 0);
- BLI_join_dirfile(path_full, sizeof(path_full), path, de->d_name);
- BLI_delete(path_full, false, false);
- }
- else {
- /* read the number of the file */
- const int frame = ptcache_frame_from_filename(de->d_name, ext);
-
- if (frame != -1) {
- if ((mode == PTCACHE_CLEAR_BEFORE && frame < cfra) ||
- (mode == PTCACHE_CLEAR_AFTER && frame > cfra))
- {
- BLI_join_dirfile(path_full, sizeof(path_full), path, de->d_name);
- BLI_delete(path_full, false, false);
- if (pid->cache->cached_frames && frame >=sta && frame <= end)
- pid->cache->cached_frames[frame-sta] = 0;
- }
- }
- }
- }
- }
- }
- closedir(dir);
-
- if (mode == PTCACHE_CLEAR_ALL && pid->cache->cached_frames)
- memset(pid->cache->cached_frames, 0, MEM_allocN_len(pid->cache->cached_frames));
- }
- else {
- PTCacheMem *pm= pid->cache->mem_cache.first;
- PTCacheMem *link= NULL;
-
- if (mode == PTCACHE_CLEAR_ALL) {
- /*we want startframe if the cache starts before zero*/
- pid->cache->last_exact = MIN2(pid->cache->startframe, 0);
- for (; pm; pm=pm->next) {
- ptcache_data_free(pm);
- ptcache_extra_free(pm);
- }
- BLI_freelistN(&pid->cache->mem_cache);
-
- if (pid->cache->cached_frames)
- memset(pid->cache->cached_frames, 0, MEM_allocN_len(pid->cache->cached_frames));
- }
- else {
- while (pm) {
- if ((mode == PTCACHE_CLEAR_BEFORE && pm->frame < cfra) ||
- (mode == PTCACHE_CLEAR_AFTER && pm->frame > cfra))
- {
- link = pm;
- if (pid->cache->cached_frames && pm->frame >=sta && pm->frame <= end)
- pid->cache->cached_frames[pm->frame-sta] = 0;
- ptcache_data_free(pm);
- ptcache_extra_free(pm);
- pm = pm->next;
- BLI_freelinkN(&pid->cache->mem_cache, link);
- }
- else
- pm = pm->next;
- }
- }
- }
- break;
-
- case PTCACHE_CLEAR_FRAME:
- if (pid->cache->flag & PTCACHE_DISK_CACHE) {
- if (BKE_ptcache_id_exist(pid, cfra)) {
- ptcache_filename(pid, filename, cfra, 1, 1); /* no path */
- BLI_delete(filename, false, false);
- }
- }
- else {
- PTCacheMem *pm = pid->cache->mem_cache.first;
-
- for (; pm; pm=pm->next) {
- if (pm->frame == cfra) {
- ptcache_data_free(pm);
- ptcache_extra_free(pm);
- BLI_freelinkN(&pid->cache->mem_cache, pm);
- break;
- }
- }
- }
- if (pid->cache->cached_frames && cfra >= sta && cfra <= end)
- pid->cache->cached_frames[cfra-sta] = 0;
- break;
- }
-
- BKE_ptcache_update_info(pid);
+ /*if (!G.relbase_valid) return; */ /* save blend file before using pointcache */
+
+ const char *fext = ptcache_file_extension(pid);
+
+ /* clear all files in the temp dir with the prefix of the ID and the ".bphys" suffix */
+ switch (mode) {
+ case PTCACHE_CLEAR_ALL:
+ case PTCACHE_CLEAR_BEFORE:
+ case PTCACHE_CLEAR_AFTER:
+ if (pid->cache->flag & PTCACHE_DISK_CACHE) {
+ ptcache_path(pid, path);
+
+ dir = opendir(path);
+ if (dir == NULL)
+ return;
+
+ len = ptcache_filename(pid, filename, cfra, 0, 0); /* no path */
+ /* append underscore terminator to ensure we don't match similar names
+ * from objects whose names start with the same prefix
+ */
+ if (len < sizeof(filename) - 2) {
+ BLI_strncpy(filename + len, "_", sizeof(filename) - 2 - len);
+ len += 1;
+ }
+
+ BLI_snprintf(ext, sizeof(ext), "_%02u%s", pid->stack_index, fext);
+
+ while ((de = readdir(dir)) != NULL) {
+ if (strstr(de->d_name, ext)) { /* do we have the right extension?*/
+ if (STREQLEN(filename, de->d_name, len)) { /* do we have the right prefix */
+ if (mode == PTCACHE_CLEAR_ALL) {
+ pid->cache->last_exact = MIN2(pid->cache->startframe, 0);
+ BLI_join_dirfile(path_full, sizeof(path_full), path, de->d_name);
+ BLI_delete(path_full, false, false);
+ }
+ else {
+ /* read the number of the file */
+ const int frame = ptcache_frame_from_filename(de->d_name, ext);
+
+ if (frame != -1) {
+ if ((mode == PTCACHE_CLEAR_BEFORE && frame < cfra) ||
+ (mode == PTCACHE_CLEAR_AFTER && frame > cfra)) {
+ BLI_join_dirfile(path_full, sizeof(path_full), path, de->d_name);
+ BLI_delete(path_full, false, false);
+ if (pid->cache->cached_frames && frame >= sta && frame <= end)
+ pid->cache->cached_frames[frame - sta] = 0;
+ }
+ }
+ }
+ }
+ }
+ }
+ closedir(dir);
+
+ if (mode == PTCACHE_CLEAR_ALL && pid->cache->cached_frames)
+ memset(pid->cache->cached_frames, 0, MEM_allocN_len(pid->cache->cached_frames));
+ }
+ else {
+ PTCacheMem *pm = pid->cache->mem_cache.first;
+ PTCacheMem *link = NULL;
+
+ if (mode == PTCACHE_CLEAR_ALL) {
+ /*we want startframe if the cache starts before zero*/
+ pid->cache->last_exact = MIN2(pid->cache->startframe, 0);
+ for (; pm; pm = pm->next) {
+ ptcache_data_free(pm);
+ ptcache_extra_free(pm);
+ }
+ BLI_freelistN(&pid->cache->mem_cache);
+
+ if (pid->cache->cached_frames)
+ memset(pid->cache->cached_frames, 0, MEM_allocN_len(pid->cache->cached_frames));
+ }
+ else {
+ while (pm) {
+ if ((mode == PTCACHE_CLEAR_BEFORE && pm->frame < cfra) ||
+ (mode == PTCACHE_CLEAR_AFTER && pm->frame > cfra)) {
+ link = pm;
+ if (pid->cache->cached_frames && pm->frame >= sta && pm->frame <= end)
+ pid->cache->cached_frames[pm->frame - sta] = 0;
+ ptcache_data_free(pm);
+ ptcache_extra_free(pm);
+ pm = pm->next;
+ BLI_freelinkN(&pid->cache->mem_cache, link);
+ }
+ else
+ pm = pm->next;
+ }
+ }
+ }
+ break;
+
+ case PTCACHE_CLEAR_FRAME:
+ if (pid->cache->flag & PTCACHE_DISK_CACHE) {
+ if (BKE_ptcache_id_exist(pid, cfra)) {
+ ptcache_filename(pid, filename, cfra, 1, 1); /* no path */
+ BLI_delete(filename, false, false);
+ }
+ }
+ else {
+ PTCacheMem *pm = pid->cache->mem_cache.first;
+
+ for (; pm; pm = pm->next) {
+ if (pm->frame == cfra) {
+ ptcache_data_free(pm);
+ ptcache_extra_free(pm);
+ BLI_freelinkN(&pid->cache->mem_cache, pm);
+ break;
+ }
+ }
+ }
+ if (pid->cache->cached_frames && cfra >= sta && cfra <= end)
+ pid->cache->cached_frames[cfra - sta] = 0;
+ break;
+ }
+
+ BKE_ptcache_update_info(pid);
}
-int BKE_ptcache_id_exist(PTCacheID *pid, int cfra)
+int BKE_ptcache_id_exist(PTCacheID *pid, int cfra)
{
- if (!pid->cache)
- return 0;
+ if (!pid->cache)
+ return 0;
- if (cfra<pid->cache->startframe || cfra > pid->cache->endframe)
- return 0;
+ if (cfra < pid->cache->startframe || cfra > pid->cache->endframe)
+ return 0;
- if (pid->cache->cached_frames && pid->cache->cached_frames[cfra-pid->cache->startframe]==0)
- return 0;
+ if (pid->cache->cached_frames && pid->cache->cached_frames[cfra - pid->cache->startframe] == 0)
+ return 0;
- if (pid->cache->flag & PTCACHE_DISK_CACHE) {
- char filename[MAX_PTCACHE_FILE];
+ if (pid->cache->flag & PTCACHE_DISK_CACHE) {
+ char filename[MAX_PTCACHE_FILE];
- ptcache_filename(pid, filename, cfra, 1, 1);
+ ptcache_filename(pid, filename, cfra, 1, 1);
- return BLI_exists(filename);
- }
- else {
- PTCacheMem *pm = pid->cache->mem_cache.first;
+ return BLI_exists(filename);
+ }
+ else {
+ PTCacheMem *pm = pid->cache->mem_cache.first;
- for (; pm; pm=pm->next) {
- if (pm->frame==cfra)
- return 1;
- }
- return 0;
- }
+ for (; pm; pm = pm->next) {
+ if (pm->frame == cfra)
+ return 1;
+ }
+ return 0;
+ }
}
-void BKE_ptcache_id_time(PTCacheID *pid, Scene *scene, float cfra, int *startframe, int *endframe, float *timescale)
+void BKE_ptcache_id_time(
+ PTCacheID *pid, Scene *scene, float cfra, int *startframe, int *endframe, float *timescale)
{
- /* Object *ob; */ /* UNUSED */
- PointCache *cache;
- /* float offset; unused for now */
- float time, nexttime;
-
- /* TODO: this has to be sorted out once bsystem_time gets redone, */
- /* now caches can handle interpolating etc. too - jahka */
-
- /* time handling for point cache:
- * - simulation time is scaled by result of bsystem_time
- * - for offsetting time only time offset is taken into account, since
- * that's always the same and can't be animated. a timeoffset which
- * varies over time is not simple to support.
- * - field and motion blur offsets are currently ignored, proper solution
- * is probably to interpolate results from two frames for that ..
- */
-
- /* ob= pid->ob; */ /* UNUSED */
- cache= pid->cache;
-
- if (timescale) {
- time= BKE_scene_frame_get(scene);
- nexttime = BKE_scene_frame_get_from_ctime(scene, CFRA + 1.0f);
-
- *timescale= MAX2(nexttime - time, 0.0f);
- }
-
- if (startframe && endframe) {
- *startframe= cache->startframe;
- *endframe= cache->endframe;
- }
-
- /* verify cached_frames array is up to date */
- if (cache->cached_frames) {
- if (cache->cached_frames_len != (cache->endframe - cache->startframe + 1)) {
- MEM_freeN(cache->cached_frames);
- cache->cached_frames = NULL;
- cache->cached_frames_len = 0;
- }
- }
-
- if (cache->cached_frames==NULL && cache->endframe > cache->startframe) {
- unsigned int sta=cache->startframe;
- unsigned int end=cache->endframe;
-
- cache->cached_frames_len = cache->endframe - cache->startframe + 1;
- cache->cached_frames = MEM_callocN(sizeof(char) * cache->cached_frames_len, "cached frames array");
-
- if (pid->cache->flag & PTCACHE_DISK_CACHE) {
- /* mode is same as fopen's modes */
- DIR *dir;
- struct dirent *de;
- char path[MAX_PTCACHE_PATH];
- char filename[MAX_PTCACHE_FILE];
- char ext[MAX_PTCACHE_PATH];
- unsigned int len; /* store the length of the string */
-
- ptcache_path(pid, path);
-
- len = ptcache_filename(pid, filename, (int)cfra, 0, 0); /* no path */
-
- dir = opendir(path);
- if (dir==NULL)
- return;
-
- const char *fext = ptcache_file_extension(pid);
-
- BLI_snprintf(ext, sizeof(ext), "_%02u%s", pid->stack_index, fext);
-
- while ((de = readdir(dir)) != NULL) {
- if (strstr(de->d_name, ext)) { /* do we have the right extension?*/
- if (STREQLEN(filename, de->d_name, len)) { /* do we have the right prefix */
- /* read the number of the file */
- const int frame = ptcache_frame_from_filename(de->d_name, ext);
-
- if ((frame != -1) && (frame >= sta && frame <= end)) {
- cache->cached_frames[frame-sta] = 1;
- }
- }
- }
- }
- closedir(dir);
- }
- else {
- PTCacheMem *pm= pid->cache->mem_cache.first;
-
- while (pm) {
- if (pm->frame >= sta && pm->frame <= end)
- cache->cached_frames[pm->frame-sta] = 1;
- pm = pm->next;
- }
- }
- }
+ /* Object *ob; */ /* UNUSED */
+ PointCache *cache;
+ /* float offset; unused for now */
+ float time, nexttime;
+
+ /* TODO: this has to be sorted out once bsystem_time gets redone, */
+ /* now caches can handle interpolating etc. too - jahka */
+
+ /* time handling for point cache:
+ * - simulation time is scaled by result of bsystem_time
+ * - for offsetting time only time offset is taken into account, since
+ * that's always the same and can't be animated. a timeoffset which
+ * varies over time is not simple to support.
+ * - field and motion blur offsets are currently ignored, proper solution
+ * is probably to interpolate results from two frames for that ..
+ */
+
+ /* ob= pid->ob; */ /* UNUSED */
+ cache = pid->cache;
+
+ if (timescale) {
+ time = BKE_scene_frame_get(scene);
+ nexttime = BKE_scene_frame_get_from_ctime(scene, CFRA + 1.0f);
+
+ *timescale = MAX2(nexttime - time, 0.0f);
+ }
+
+ if (startframe && endframe) {
+ *startframe = cache->startframe;
+ *endframe = cache->endframe;
+ }
+
+ /* verify cached_frames array is up to date */
+ if (cache->cached_frames) {
+ if (cache->cached_frames_len != (cache->endframe - cache->startframe + 1)) {
+ MEM_freeN(cache->cached_frames);
+ cache->cached_frames = NULL;
+ cache->cached_frames_len = 0;
+ }
+ }
+
+ if (cache->cached_frames == NULL && cache->endframe > cache->startframe) {
+ unsigned int sta = cache->startframe;
+ unsigned int end = cache->endframe;
+
+ cache->cached_frames_len = cache->endframe - cache->startframe + 1;
+ cache->cached_frames = MEM_callocN(sizeof(char) * cache->cached_frames_len,
+ "cached frames array");
+
+ if (pid->cache->flag & PTCACHE_DISK_CACHE) {
+ /* mode is same as fopen's modes */
+ DIR *dir;
+ struct dirent *de;
+ char path[MAX_PTCACHE_PATH];
+ char filename[MAX_PTCACHE_FILE];
+ char ext[MAX_PTCACHE_PATH];
+ unsigned int len; /* store the length of the string */
+
+ ptcache_path(pid, path);
+
+ len = ptcache_filename(pid, filename, (int)cfra, 0, 0); /* no path */
+
+ dir = opendir(path);
+ if (dir == NULL)
+ return;
+
+ const char *fext = ptcache_file_extension(pid);
+
+ BLI_snprintf(ext, sizeof(ext), "_%02u%s", pid->stack_index, fext);
+
+ while ((de = readdir(dir)) != NULL) {
+ if (strstr(de->d_name, ext)) { /* do we have the right extension?*/
+ if (STREQLEN(filename, de->d_name, len)) { /* do we have the right prefix */
+ /* read the number of the file */
+ const int frame = ptcache_frame_from_filename(de->d_name, ext);
+
+ if ((frame != -1) && (frame >= sta && frame <= end)) {
+ cache->cached_frames[frame - sta] = 1;
+ }
+ }
+ }
+ }
+ closedir(dir);
+ }
+ else {
+ PTCacheMem *pm = pid->cache->mem_cache.first;
+
+ while (pm) {
+ if (pm->frame >= sta && pm->frame <= end)
+ cache->cached_frames[pm->frame - sta] = 1;
+ pm = pm->next;
+ }
+ }
+ }
}
-int BKE_ptcache_id_reset(Scene *scene, PTCacheID *pid, int mode)
+int BKE_ptcache_id_reset(Scene *scene, PTCacheID *pid, int mode)
{
- PointCache *cache;
- int reset, clear, after;
-
- if (!pid->cache)
- return 0;
-
- cache= pid->cache;
- reset= 0;
- clear= 0;
- after= 0;
-
- if (mode == PTCACHE_RESET_DEPSGRAPH) {
- if (!(cache->flag & PTCACHE_BAKED)) {
-
- after= 1;
- }
-
- cache->flag |= PTCACHE_OUTDATED;
- }
- else if (mode == PTCACHE_RESET_BAKED) {
- cache->flag |= PTCACHE_OUTDATED;
- }
- else if (mode == PTCACHE_RESET_OUTDATED) {
- reset = 1;
-
- if (cache->flag & PTCACHE_OUTDATED && !(cache->flag & PTCACHE_BAKED)) {
- clear= 1;
- cache->flag &= ~PTCACHE_OUTDATED;
- }
- }
-
- if (reset) {
- BKE_ptcache_invalidate(cache);
- cache->flag &= ~PTCACHE_REDO_NEEDED;
-
- if (pid->type == PTCACHE_TYPE_CLOTH)
- cloth_free_modifier(pid->calldata);
- else if (pid->type == PTCACHE_TYPE_SOFTBODY)
- sbFreeSimulation(pid->calldata);
- else if (pid->type == PTCACHE_TYPE_PARTICLES)
- psys_reset(pid->calldata, PSYS_RESET_DEPSGRAPH);
- else if (pid->type == PTCACHE_TYPE_DYNAMICPAINT)
- dynamicPaint_clearSurface(scene, (DynamicPaintSurface*)pid->calldata);
- }
- if (clear)
- BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
- else if (after)
- BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_AFTER, CFRA);
-
- return (reset || clear || after);
+ PointCache *cache;
+ int reset, clear, after;
+
+ if (!pid->cache)
+ return 0;
+
+ cache = pid->cache;
+ reset = 0;
+ clear = 0;
+ after = 0;
+
+ if (mode == PTCACHE_RESET_DEPSGRAPH) {
+ if (!(cache->flag & PTCACHE_BAKED)) {
+
+ after = 1;
+ }
+
+ cache->flag |= PTCACHE_OUTDATED;
+ }
+ else if (mode == PTCACHE_RESET_BAKED) {
+ cache->flag |= PTCACHE_OUTDATED;
+ }
+ else if (mode == PTCACHE_RESET_OUTDATED) {
+ reset = 1;
+
+ if (cache->flag & PTCACHE_OUTDATED && !(cache->flag & PTCACHE_BAKED)) {
+ clear = 1;
+ cache->flag &= ~PTCACHE_OUTDATED;
+ }
+ }
+
+ if (reset) {
+ BKE_ptcache_invalidate(cache);
+ cache->flag &= ~PTCACHE_REDO_NEEDED;
+
+ if (pid->type == PTCACHE_TYPE_CLOTH)
+ cloth_free_modifier(pid->calldata);
+ else if (pid->type == PTCACHE_TYPE_SOFTBODY)
+ sbFreeSimulation(pid->calldata);
+ else if (pid->type == PTCACHE_TYPE_PARTICLES)
+ psys_reset(pid->calldata, PSYS_RESET_DEPSGRAPH);
+ else if (pid->type == PTCACHE_TYPE_DYNAMICPAINT)
+ dynamicPaint_clearSurface(scene, (DynamicPaintSurface *)pid->calldata);
+ }
+ if (clear)
+ BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
+ else if (after)
+ BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_AFTER, CFRA);
+
+ return (reset || clear || after);
}
-int BKE_ptcache_object_reset(Scene *scene, Object *ob, int mode)
+int BKE_ptcache_object_reset(Scene *scene, Object *ob, int mode)
{
- PTCacheID pid;
- ParticleSystem *psys;
- ModifierData *md;
- int reset, skip;
-
- reset= 0;
- skip= 0;
-
- if (ob->soft) {
- BKE_ptcache_id_from_softbody(&pid, ob, ob->soft);
- reset |= BKE_ptcache_id_reset(scene, &pid, mode);
- }
-
- for (psys=ob->particlesystem.first; psys; psys=psys->next) {
- /* children or just redo can be calculated without resetting anything */
- if (psys->recalc & ID_RECALC_PSYS_REDO || psys->recalc & ID_RECALC_PSYS_CHILD)
- skip = 1;
- /* Baked cloth hair has to be checked too, because we don't want to reset */
- /* particles or cloth in that case -jahka */
- else if (psys->clmd) {
- BKE_ptcache_id_from_cloth(&pid, ob, psys->clmd);
- if (mode == PSYS_RESET_ALL || !(psys->part->type == PART_HAIR && (pid.cache->flag & PTCACHE_BAKED)))
- reset |= BKE_ptcache_id_reset(scene, &pid, mode);
- else
- skip = 1;
- }
-
- if (skip == 0 && psys->part) {
- BKE_ptcache_id_from_particles(&pid, ob, psys);
- reset |= BKE_ptcache_id_reset(scene, &pid, mode);
- }
- }
-
- for (md=ob->modifiers.first; md; md=md->next) {
- if (md->type == eModifierType_Cloth) {
- BKE_ptcache_id_from_cloth(&pid, ob, (ClothModifierData*)md);
- reset |= BKE_ptcache_id_reset(scene, &pid, mode);
- }
- if (md->type == eModifierType_Smoke) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
- if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
- BKE_ptcache_id_from_smoke(&pid, ob, (SmokeModifierData*)md);
- reset |= BKE_ptcache_id_reset(scene, &pid, mode);
- }
- }
- if (md->type == eModifierType_DynamicPaint) {
- DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
- if (pmd->canvas) {
- DynamicPaintSurface *surface = pmd->canvas->surfaces.first;
-
- for (; surface; surface=surface->next) {
- BKE_ptcache_id_from_dynamicpaint(&pid, ob, surface);
- reset |= BKE_ptcache_id_reset(scene, &pid, mode);
- }
- }
- }
- }
-
- if (scene->rigidbody_world && (ob->rigidbody_object || ob->rigidbody_constraint)) {
- if (ob->rigidbody_object)
- ob->rigidbody_object->flag |= RBO_FLAG_NEEDS_RESHAPE;
- BKE_ptcache_id_from_rigidbody(&pid, ob, scene->rigidbody_world);
- /* only flag as outdated, resetting should happen on start frame */
- pid.cache->flag |= PTCACHE_OUTDATED;
- }
-
- if (ob->type == OB_ARMATURE)
- BIK_clear_cache(ob->pose);
-
- return reset;
+ PTCacheID pid;
+ ParticleSystem *psys;
+ ModifierData *md;
+ int reset, skip;
+
+ reset = 0;
+ skip = 0;
+
+ if (ob->soft) {
+ BKE_ptcache_id_from_softbody(&pid, ob, ob->soft);
+ reset |= BKE_ptcache_id_reset(scene, &pid, mode);
+ }
+
+ for (psys = ob->particlesystem.first; psys; psys = psys->next) {
+ /* children or just redo can be calculated without resetting anything */
+ if (psys->recalc & ID_RECALC_PSYS_REDO || psys->recalc & ID_RECALC_PSYS_CHILD)
+ skip = 1;
+ /* Baked cloth hair has to be checked too, because we don't want to reset */
+ /* particles or cloth in that case -jahka */
+ else if (psys->clmd) {
+ BKE_ptcache_id_from_cloth(&pid, ob, psys->clmd);
+ if (mode == PSYS_RESET_ALL ||
+ !(psys->part->type == PART_HAIR && (pid.cache->flag & PTCACHE_BAKED)))
+ reset |= BKE_ptcache_id_reset(scene, &pid, mode);
+ else
+ skip = 1;
+ }
+
+ if (skip == 0 && psys->part) {
+ BKE_ptcache_id_from_particles(&pid, ob, psys);
+ reset |= BKE_ptcache_id_reset(scene, &pid, mode);
+ }
+ }
+
+ for (md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_Cloth) {
+ BKE_ptcache_id_from_cloth(&pid, ob, (ClothModifierData *)md);
+ reset |= BKE_ptcache_id_reset(scene, &pid, mode);
+ }
+ if (md->type == eModifierType_Smoke) {
+ SmokeModifierData *smd = (SmokeModifierData *)md;
+ if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
+ BKE_ptcache_id_from_smoke(&pid, ob, (SmokeModifierData *)md);
+ reset |= BKE_ptcache_id_reset(scene, &pid, mode);
+ }
+ }
+ if (md->type == eModifierType_DynamicPaint) {
+ DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
+ if (pmd->canvas) {
+ DynamicPaintSurface *surface = pmd->canvas->surfaces.first;
+
+ for (; surface; surface = surface->next) {
+ BKE_ptcache_id_from_dynamicpaint(&pid, ob, surface);
+ reset |= BKE_ptcache_id_reset(scene, &pid, mode);
+ }
+ }
+ }
+ }
+
+ if (scene->rigidbody_world && (ob->rigidbody_object || ob->rigidbody_constraint)) {
+ if (ob->rigidbody_object)
+ ob->rigidbody_object->flag |= RBO_FLAG_NEEDS_RESHAPE;
+ BKE_ptcache_id_from_rigidbody(&pid, ob, scene->rigidbody_world);
+ /* only flag as outdated, resetting should happen on start frame */
+ pid.cache->flag |= PTCACHE_OUTDATED;
+ }
+
+ if (ob->type == OB_ARMATURE)
+ BIK_clear_cache(ob->pose);
+
+ return reset;
}
/* Use this when quitting blender, with unsaved files */
void BKE_ptcache_remove(void)
{
- char path[MAX_PTCACHE_PATH];
- char path_full[MAX_PTCACHE_PATH];
- int rmdir = 1;
-
- ptcache_path(NULL, path);
-
- if (BLI_exists(path)) {
- /* The pointcache dir exists? - remove all pointcache */
-
- DIR *dir;
- struct dirent *de;
-
- dir = opendir(path);
- if (dir==NULL)
- return;
-
- while ((de = readdir(dir)) != NULL) {
- if (FILENAME_IS_CURRPAR(de->d_name)) {
- /* do nothing */
- }
- else if (strstr(de->d_name, PTCACHE_EXT)) { /* do we have the right extension?*/
- BLI_join_dirfile(path_full, sizeof(path_full), path, de->d_name);
- BLI_delete(path_full, false, false);
- }
- else {
- rmdir = 0; /* unknown file, don't remove the dir */
- }
- }
-
- closedir(dir);
- }
- else {
- rmdir = 0; /* path dosnt exist */
- }
-
- if (rmdir) {
- BLI_delete(path, true, false);
- }
+ char path[MAX_PTCACHE_PATH];
+ char path_full[MAX_PTCACHE_PATH];
+ int rmdir = 1;
+
+ ptcache_path(NULL, path);
+
+ if (BLI_exists(path)) {
+ /* The pointcache dir exists? - remove all pointcache */
+
+ DIR *dir;
+ struct dirent *de;
+
+ dir = opendir(path);
+ if (dir == NULL)
+ return;
+
+ while ((de = readdir(dir)) != NULL) {
+ if (FILENAME_IS_CURRPAR(de->d_name)) {
+ /* do nothing */
+ }
+ else if (strstr(de->d_name, PTCACHE_EXT)) { /* do we have the right extension?*/
+ BLI_join_dirfile(path_full, sizeof(path_full), path, de->d_name);
+ BLI_delete(path_full, false, false);
+ }
+ else {
+ rmdir = 0; /* unknown file, don't remove the dir */
+ }
+ }
+
+ closedir(dir);
+ }
+ else {
+ rmdir = 0; /* path dosnt exist */
+ }
+
+ if (rmdir) {
+ BLI_delete(path, true, false);
+ }
}
/* Point Cache handling */
PointCache *BKE_ptcache_add(ListBase *ptcaches)
{
- PointCache *cache;
+ PointCache *cache;
- cache= MEM_callocN(sizeof(PointCache), "PointCache");
- cache->startframe= 1;
- cache->endframe= 250;
- cache->step = 1;
- cache->index = -1;
+ cache = MEM_callocN(sizeof(PointCache), "PointCache");
+ cache->startframe = 1;
+ cache->endframe = 250;
+ cache->step = 1;
+ cache->index = -1;
- BLI_addtail(ptcaches, cache);
+ BLI_addtail(ptcaches, cache);
- return cache;
+ return cache;
}
void BKE_ptcache_free_mem(ListBase *mem_cache)
{
- PTCacheMem *pm = mem_cache->first;
+ PTCacheMem *pm = mem_cache->first;
- if (pm) {
- for (; pm; pm=pm->next) {
- ptcache_data_free(pm);
- ptcache_extra_free(pm);
- }
+ if (pm) {
+ for (; pm; pm = pm->next) {
+ ptcache_data_free(pm);
+ ptcache_extra_free(pm);
+ }
- BLI_freelistN(mem_cache);
- }
+ BLI_freelistN(mem_cache);
+ }
}
void BKE_ptcache_free(PointCache *cache)
{
- BKE_ptcache_free_mem(&cache->mem_cache);
- if (cache->edit && cache->free_edit)
- cache->free_edit(cache->edit);
- if (cache->cached_frames)
- MEM_freeN(cache->cached_frames);
- MEM_freeN(cache);
+ BKE_ptcache_free_mem(&cache->mem_cache);
+ if (cache->edit && cache->free_edit)
+ cache->free_edit(cache->edit);
+ if (cache->cached_frames)
+ MEM_freeN(cache->cached_frames);
+ MEM_freeN(cache);
}
void BKE_ptcache_free_list(ListBase *ptcaches)
{
- PointCache *cache;
+ PointCache *cache;
- while ((cache = BLI_pophead(ptcaches))) {
- BKE_ptcache_free(cache);
- }
+ while ((cache = BLI_pophead(ptcaches))) {
+ BKE_ptcache_free(cache);
+ }
}
static PointCache *ptcache_copy(PointCache *cache, const bool copy_data)
{
- PointCache *ncache;
+ PointCache *ncache;
- ncache= MEM_dupallocN(cache);
+ ncache = MEM_dupallocN(cache);
- BLI_listbase_clear(&ncache->mem_cache);
+ BLI_listbase_clear(&ncache->mem_cache);
- if (copy_data == false) {
- ncache->cached_frames = NULL;
- ncache->cached_frames_len = 0;
+ if (copy_data == false) {
+ ncache->cached_frames = NULL;
+ ncache->cached_frames_len = 0;
- /* flag is a mix of user settings and simulator/baking state */
- ncache->flag= ncache->flag & (PTCACHE_DISK_CACHE|PTCACHE_EXTERNAL|PTCACHE_IGNORE_LIBPATH);
- ncache->simframe= 0;
- }
- else {
- PTCacheMem *pm;
+ /* flag is a mix of user settings and simulator/baking state */
+ ncache->flag = ncache->flag & (PTCACHE_DISK_CACHE | PTCACHE_EXTERNAL | PTCACHE_IGNORE_LIBPATH);
+ ncache->simframe = 0;
+ }
+ else {
+ PTCacheMem *pm;
- for (pm = cache->mem_cache.first; pm; pm = pm->next) {
- PTCacheMem *pmn = MEM_dupallocN(pm);
- int i;
+ for (pm = cache->mem_cache.first; pm; pm = pm->next) {
+ PTCacheMem *pmn = MEM_dupallocN(pm);
+ int i;
- for (i = 0; i < BPHYS_TOT_DATA; i++) {
- if (pmn->data[i])
- pmn->data[i] = MEM_dupallocN(pm->data[i]);
- }
+ for (i = 0; i < BPHYS_TOT_DATA; i++) {
+ if (pmn->data[i])
+ pmn->data[i] = MEM_dupallocN(pm->data[i]);
+ }
- BKE_ptcache_mem_pointers_init(pm);
+ BKE_ptcache_mem_pointers_init(pm);
- BLI_addtail(&ncache->mem_cache, pmn);
- }
+ BLI_addtail(&ncache->mem_cache, pmn);
+ }
- if (ncache->cached_frames)
- ncache->cached_frames = MEM_dupallocN(cache->cached_frames);
- }
+ if (ncache->cached_frames)
+ ncache->cached_frames = MEM_dupallocN(cache->cached_frames);
+ }
- /* hmm, should these be copied over instead? */
- ncache->edit = NULL;
+ /* hmm, should these be copied over instead? */
+ ncache->edit = NULL;
- return ncache;
+ return ncache;
}
/* returns first point cache */
-PointCache *BKE_ptcache_copy_list(ListBase *ptcaches_new, const ListBase *ptcaches_old, const int flag)
+PointCache *BKE_ptcache_copy_list(ListBase *ptcaches_new,
+ const ListBase *ptcaches_old,
+ const int flag)
{
- PointCache *cache = ptcaches_old->first;
+ PointCache *cache = ptcaches_old->first;
- BLI_listbase_clear(ptcaches_new);
+ BLI_listbase_clear(ptcaches_new);
- for (; cache; cache=cache->next) {
- BLI_addtail(ptcaches_new, ptcache_copy(cache, (flag & LIB_ID_COPY_CACHES) != 0));
- }
+ for (; cache; cache = cache->next) {
+ BLI_addtail(ptcaches_new, ptcache_copy(cache, (flag & LIB_ID_COPY_CACHES) != 0));
+ }
- return ptcaches_new->first;
+ return ptcaches_new->first;
}
/* Disabled this code; this is being called on scene_update_tagged, and that in turn gets called on
@@ -3599,595 +3769,615 @@ PointCache *BKE_ptcache_copy_list(ListBase *ptcaches_new, const ListBase *ptcach
/* Baking */
void BKE_ptcache_quick_cache_all(Main *bmain, Scene *scene, ViewLayer *view_layer)
{
- PTCacheBaker baker;
-
- memset(&baker, 0, sizeof(baker));
- baker.bmain = bmain;
- baker.scene = scene;
- baker.view_layer = view_layer;
- baker.bake = 0;
- baker.render = 0;
- baker.anim_init = 0;
- baker.quick_step = scene->physics_settings.quick_cache_step;
-
- BKE_ptcache_bake(&baker);
+ PTCacheBaker baker;
+
+ memset(&baker, 0, sizeof(baker));
+ baker.bmain = bmain;
+ baker.scene = scene;
+ baker.view_layer = view_layer;
+ baker.bake = 0;
+ baker.render = 0;
+ baker.anim_init = 0;
+ baker.quick_step = scene->physics_settings.quick_cache_step;
+
+ BKE_ptcache_bake(&baker);
}
static void ptcache_dt_to_str(char *str, double dtime)
{
- if (dtime > 60.0) {
- if (dtime > 3600.0)
- sprintf(str, "%ih %im %is", (int)(dtime/3600), ((int)(dtime/60))%60, ((int)dtime) % 60);
- else
- sprintf(str, "%im %is", ((int)(dtime/60))%60, ((int)dtime) % 60);
- }
- else
- sprintf(str, "%is", ((int)dtime) % 60);
+ if (dtime > 60.0) {
+ if (dtime > 3600.0)
+ sprintf(
+ str, "%ih %im %is", (int)(dtime / 3600), ((int)(dtime / 60)) % 60, ((int)dtime) % 60);
+ else
+ sprintf(str, "%im %is", ((int)(dtime / 60)) % 60, ((int)dtime) % 60);
+ }
+ else
+ sprintf(str, "%is", ((int)dtime) % 60);
}
/* if bake is not given run simulations to current frame */
void BKE_ptcache_bake(PTCacheBaker *baker)
{
- Main *bmain = baker->bmain;
- Scene *scene = baker->scene;
- ViewLayer *view_layer = baker->view_layer;
- struct Depsgraph *depsgraph = baker->depsgraph;
- Scene *sce_iter; /* SETLOOPER macro only */
- Base *base;
- ListBase pidlist;
- PTCacheID *pid = &baker->pid;
- PointCache *cache = NULL;
- float frameleno = scene->r.framelen;
- int cfrao = CFRA;
- int startframe = MAXFRAME, endframe = baker->anim_init ? scene->r.sfra : CFRA;
- int bake = baker->bake;
- int render = baker->render;
-
- G.is_break = false;
-
- /* set caches to baking mode and figure out start frame */
- if (pid->ob) {
- /* cache/bake a single object */
- cache = pid->cache;
- if ((cache->flag & PTCACHE_BAKED)==0) {
- if (pid->type==PTCACHE_TYPE_PARTICLES) {
- ParticleSystem *psys= pid->calldata;
-
- /* a bit confusing, could make this work better in the UI */
- if (psys->part->type == PART_EMITTER)
- psys_get_pointcache_start_end(scene, pid->calldata, &cache->startframe, &cache->endframe);
- }
- else if (pid->type == PTCACHE_TYPE_SMOKE_HIGHRES) {
- /* get all pids from the object and search for smoke low res */
- ListBase pidlist2;
- PTCacheID *pid2;
- BKE_ptcache_ids_from_object(&pidlist2, pid->ob, scene, MAX_DUPLI_RECUR);
- for (pid2=pidlist2.first; pid2; pid2=pid2->next) {
- if (pid2->type == PTCACHE_TYPE_SMOKE_DOMAIN) {
- if (pid2->cache && !(pid2->cache->flag & PTCACHE_BAKED)) {
- if (bake || pid2->cache->flag & PTCACHE_REDO_NEEDED)
- BKE_ptcache_id_clear(pid2, PTCACHE_CLEAR_ALL, 0);
- if (bake) {
- pid2->cache->flag |= PTCACHE_BAKING;
- pid2->cache->flag &= ~PTCACHE_BAKED;
- }
- }
- }
- }
- BLI_freelistN(&pidlist2);
- }
-
- if (bake || cache->flag & PTCACHE_REDO_NEEDED)
- BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
-
- startframe = MAX2(cache->last_exact, cache->startframe);
-
- if (bake) {
- endframe = cache->endframe;
- cache->flag |= PTCACHE_BAKING;
- }
- else {
- endframe = MIN2(endframe, cache->endframe);
- }
-
- cache->flag &= ~PTCACHE_BAKED;
- }
- }
- else {
- for (SETLOOPER_VIEW_LAYER(scene, view_layer, sce_iter, base)) {
- /* cache/bake everything in the scene */
- BKE_ptcache_ids_from_object(&pidlist, base->object, scene, MAX_DUPLI_RECUR);
-
- for (pid=pidlist.first; pid; pid=pid->next) {
- cache = pid->cache;
- if ((cache->flag & PTCACHE_BAKED)==0) {
- if (pid->type==PTCACHE_TYPE_PARTICLES) {
- ParticleSystem *psys = (ParticleSystem*)pid->calldata;
- /* skip hair & keyed particles */
- if (psys->part->type == PART_HAIR || psys->part->phystype == PART_PHYS_KEYED)
- continue;
-
- psys_get_pointcache_start_end(scene, pid->calldata, &cache->startframe, &cache->endframe);
- }
-
- // XXX workaround for regression inroduced in ee3fadd, needs looking into
- if (pid->type == PTCACHE_TYPE_RIGIDBODY) {
- if ((cache->flag & PTCACHE_REDO_NEEDED || (cache->flag & PTCACHE_SIMULATION_VALID)==0) && (render || bake)) {
- BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
- }
- }
- else if (((cache->flag & PTCACHE_BAKED) == 0) && (render || bake)) {
- BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
- }
-
- startframe = MIN2(startframe, cache->startframe);
-
- if (bake || render) {
- cache->flag |= PTCACHE_BAKING;
-
- if (bake)
- endframe = MAX2(endframe, cache->endframe);
- }
-
- cache->flag &= ~PTCACHE_BAKED;
-
- }
- }
- BLI_freelistN(&pidlist);
- }
- }
-
- CFRA = startframe;
- scene->r.framelen = 1.0;
-
- /* bake */
-
- bool use_timer = false;
- double stime, ptime, ctime, fetd;
- char run[32], cur[32], etd[32];
- int cancel = 0;
-
- stime = ptime = PIL_check_seconds_timer();
-
- for (int fr = CFRA; fr <= endframe; fr += baker->quick_step, CFRA = fr) {
- BKE_scene_graph_update_for_newframe(depsgraph, bmain);
-
- if (baker->update_progress) {
- float progress = ((float)(CFRA - startframe)/(float)(endframe - startframe));
- baker->update_progress(baker->bake_job, progress, &cancel);
- }
-
- if (G.background) {
- printf("bake: frame %d :: %d\n", CFRA, endframe);
- }
- else {
- ctime = PIL_check_seconds_timer();
-
- fetd = (ctime - ptime) * (endframe - CFRA) / baker->quick_step;
-
- if (use_timer || fetd > 60.0) {
- use_timer = true;
-
- ptcache_dt_to_str(cur, ctime - ptime);
- ptcache_dt_to_str(run, ctime - stime);
- ptcache_dt_to_str(etd, fetd);
-
- printf("Baked for %s, current frame: %i/%i (%.3fs), ETC: %s\r",
- run, CFRA - startframe + 1, endframe - startframe + 1, ctime - ptime, etd);
- }
-
- ptime = ctime;
- }
-
- /* NOTE: breaking baking should leave calculated frames in cache, not clear it */
- if ((cancel || G.is_break)) {
- break;
- }
-
- CFRA += 1;
- }
-
- if (use_timer) {
- /* start with newline because of \r above */
- ptcache_dt_to_str(run, PIL_check_seconds_timer()-stime);
- printf("\nBake %s %s (%i frames simulated).\n", (cancel ? "canceled after" : "finished in"), run, CFRA - startframe);
- }
-
- /* clear baking flag */
- if (pid) {
- cache->flag &= ~(PTCACHE_BAKING|PTCACHE_REDO_NEEDED);
- cache->flag |= PTCACHE_SIMULATION_VALID;
- if (bake) {
- cache->flag |= PTCACHE_BAKED;
- /* write info file */
- if (cache->flag & PTCACHE_DISK_CACHE)
- BKE_ptcache_write(pid, 0);
- }
- }
- else {
- for (SETLOOPER_VIEW_LAYER(scene, view_layer, sce_iter, base)) {
- BKE_ptcache_ids_from_object(&pidlist, base->object, scene, MAX_DUPLI_RECUR);
-
- for (pid=pidlist.first; pid; pid=pid->next) {
- /* skip hair particles */
- if (pid->type==PTCACHE_TYPE_PARTICLES && ((ParticleSystem*)pid->calldata)->part->type == PART_HAIR)
- continue;
-
- cache = pid->cache;
-
- if (baker->quick_step > 1)
- cache->flag &= ~(PTCACHE_BAKING|PTCACHE_OUTDATED);
- else
- cache->flag &= ~(PTCACHE_BAKING|PTCACHE_REDO_NEEDED);
-
- cache->flag |= PTCACHE_SIMULATION_VALID;
-
- if (bake) {
- cache->flag |= PTCACHE_BAKED;
- if (cache->flag & PTCACHE_DISK_CACHE)
- BKE_ptcache_write(pid, 0);
- }
- }
- BLI_freelistN(&pidlist);
- }
- }
-
- scene->r.framelen = frameleno;
- CFRA = cfrao;
-
- if (bake) { /* already on cfra unless baking */
- BKE_scene_graph_update_for_newframe(depsgraph, bmain);
- }
-
- /* TODO: call redraw all windows somehow */
+ Main *bmain = baker->bmain;
+ Scene *scene = baker->scene;
+ ViewLayer *view_layer = baker->view_layer;
+ struct Depsgraph *depsgraph = baker->depsgraph;
+ Scene *sce_iter; /* SETLOOPER macro only */
+ Base *base;
+ ListBase pidlist;
+ PTCacheID *pid = &baker->pid;
+ PointCache *cache = NULL;
+ float frameleno = scene->r.framelen;
+ int cfrao = CFRA;
+ int startframe = MAXFRAME, endframe = baker->anim_init ? scene->r.sfra : CFRA;
+ int bake = baker->bake;
+ int render = baker->render;
+
+ G.is_break = false;
+
+ /* set caches to baking mode and figure out start frame */
+ if (pid->ob) {
+ /* cache/bake a single object */
+ cache = pid->cache;
+ if ((cache->flag & PTCACHE_BAKED) == 0) {
+ if (pid->type == PTCACHE_TYPE_PARTICLES) {
+ ParticleSystem *psys = pid->calldata;
+
+ /* a bit confusing, could make this work better in the UI */
+ if (psys->part->type == PART_EMITTER)
+ psys_get_pointcache_start_end(
+ scene, pid->calldata, &cache->startframe, &cache->endframe);
+ }
+ else if (pid->type == PTCACHE_TYPE_SMOKE_HIGHRES) {
+ /* get all pids from the object and search for smoke low res */
+ ListBase pidlist2;
+ PTCacheID *pid2;
+ BKE_ptcache_ids_from_object(&pidlist2, pid->ob, scene, MAX_DUPLI_RECUR);
+ for (pid2 = pidlist2.first; pid2; pid2 = pid2->next) {
+ if (pid2->type == PTCACHE_TYPE_SMOKE_DOMAIN) {
+ if (pid2->cache && !(pid2->cache->flag & PTCACHE_BAKED)) {
+ if (bake || pid2->cache->flag & PTCACHE_REDO_NEEDED)
+ BKE_ptcache_id_clear(pid2, PTCACHE_CLEAR_ALL, 0);
+ if (bake) {
+ pid2->cache->flag |= PTCACHE_BAKING;
+ pid2->cache->flag &= ~PTCACHE_BAKED;
+ }
+ }
+ }
+ }
+ BLI_freelistN(&pidlist2);
+ }
+
+ if (bake || cache->flag & PTCACHE_REDO_NEEDED)
+ BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
+
+ startframe = MAX2(cache->last_exact, cache->startframe);
+
+ if (bake) {
+ endframe = cache->endframe;
+ cache->flag |= PTCACHE_BAKING;
+ }
+ else {
+ endframe = MIN2(endframe, cache->endframe);
+ }
+
+ cache->flag &= ~PTCACHE_BAKED;
+ }
+ }
+ else {
+ for (SETLOOPER_VIEW_LAYER(scene, view_layer, sce_iter, base)) {
+ /* cache/bake everything in the scene */
+ BKE_ptcache_ids_from_object(&pidlist, base->object, scene, MAX_DUPLI_RECUR);
+
+ for (pid = pidlist.first; pid; pid = pid->next) {
+ cache = pid->cache;
+ if ((cache->flag & PTCACHE_BAKED) == 0) {
+ if (pid->type == PTCACHE_TYPE_PARTICLES) {
+ ParticleSystem *psys = (ParticleSystem *)pid->calldata;
+ /* skip hair & keyed particles */
+ if (psys->part->type == PART_HAIR || psys->part->phystype == PART_PHYS_KEYED)
+ continue;
+
+ psys_get_pointcache_start_end(
+ scene, pid->calldata, &cache->startframe, &cache->endframe);
+ }
+
+ // XXX workaround for regression inroduced in ee3fadd, needs looking into
+ if (pid->type == PTCACHE_TYPE_RIGIDBODY) {
+ if ((cache->flag & PTCACHE_REDO_NEEDED ||
+ (cache->flag & PTCACHE_SIMULATION_VALID) == 0) &&
+ (render || bake)) {
+ BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
+ }
+ }
+ else if (((cache->flag & PTCACHE_BAKED) == 0) && (render || bake)) {
+ BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
+ }
+
+ startframe = MIN2(startframe, cache->startframe);
+
+ if (bake || render) {
+ cache->flag |= PTCACHE_BAKING;
+
+ if (bake)
+ endframe = MAX2(endframe, cache->endframe);
+ }
+
+ cache->flag &= ~PTCACHE_BAKED;
+ }
+ }
+ BLI_freelistN(&pidlist);
+ }
+ }
+
+ CFRA = startframe;
+ scene->r.framelen = 1.0;
+
+ /* bake */
+
+ bool use_timer = false;
+ double stime, ptime, ctime, fetd;
+ char run[32], cur[32], etd[32];
+ int cancel = 0;
+
+ stime = ptime = PIL_check_seconds_timer();
+
+ for (int fr = CFRA; fr <= endframe; fr += baker->quick_step, CFRA = fr) {
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
+
+ if (baker->update_progress) {
+ float progress = ((float)(CFRA - startframe) / (float)(endframe - startframe));
+ baker->update_progress(baker->bake_job, progress, &cancel);
+ }
+
+ if (G.background) {
+ printf("bake: frame %d :: %d\n", CFRA, endframe);
+ }
+ else {
+ ctime = PIL_check_seconds_timer();
+
+ fetd = (ctime - ptime) * (endframe - CFRA) / baker->quick_step;
+
+ if (use_timer || fetd > 60.0) {
+ use_timer = true;
+
+ ptcache_dt_to_str(cur, ctime - ptime);
+ ptcache_dt_to_str(run, ctime - stime);
+ ptcache_dt_to_str(etd, fetd);
+
+ printf("Baked for %s, current frame: %i/%i (%.3fs), ETC: %s\r",
+ run,
+ CFRA - startframe + 1,
+ endframe - startframe + 1,
+ ctime - ptime,
+ etd);
+ }
+
+ ptime = ctime;
+ }
+
+ /* NOTE: breaking baking should leave calculated frames in cache, not clear it */
+ if ((cancel || G.is_break)) {
+ break;
+ }
+
+ CFRA += 1;
+ }
+
+ if (use_timer) {
+ /* start with newline because of \r above */
+ ptcache_dt_to_str(run, PIL_check_seconds_timer() - stime);
+ printf("\nBake %s %s (%i frames simulated).\n",
+ (cancel ? "canceled after" : "finished in"),
+ run,
+ CFRA - startframe);
+ }
+
+ /* clear baking flag */
+ if (pid) {
+ cache->flag &= ~(PTCACHE_BAKING | PTCACHE_REDO_NEEDED);
+ cache->flag |= PTCACHE_SIMULATION_VALID;
+ if (bake) {
+ cache->flag |= PTCACHE_BAKED;
+ /* write info file */
+ if (cache->flag & PTCACHE_DISK_CACHE)
+ BKE_ptcache_write(pid, 0);
+ }
+ }
+ else {
+ for (SETLOOPER_VIEW_LAYER(scene, view_layer, sce_iter, base)) {
+ BKE_ptcache_ids_from_object(&pidlist, base->object, scene, MAX_DUPLI_RECUR);
+
+ for (pid = pidlist.first; pid; pid = pid->next) {
+ /* skip hair particles */
+ if (pid->type == PTCACHE_TYPE_PARTICLES &&
+ ((ParticleSystem *)pid->calldata)->part->type == PART_HAIR)
+ continue;
+
+ cache = pid->cache;
+
+ if (baker->quick_step > 1)
+ cache->flag &= ~(PTCACHE_BAKING | PTCACHE_OUTDATED);
+ else
+ cache->flag &= ~(PTCACHE_BAKING | PTCACHE_REDO_NEEDED);
+
+ cache->flag |= PTCACHE_SIMULATION_VALID;
+
+ if (bake) {
+ cache->flag |= PTCACHE_BAKED;
+ if (cache->flag & PTCACHE_DISK_CACHE)
+ BKE_ptcache_write(pid, 0);
+ }
+ }
+ BLI_freelistN(&pidlist);
+ }
+ }
+
+ scene->r.framelen = frameleno;
+ CFRA = cfrao;
+
+ if (bake) { /* already on cfra unless baking */
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
+ }
+
+ /* TODO: call redraw all windows somehow */
}
/* Helpers */
void BKE_ptcache_disk_to_mem(PTCacheID *pid)
{
- PointCache *cache = pid->cache;
- PTCacheMem *pm = NULL;
- int baked = cache->flag & PTCACHE_BAKED;
- int cfra, sfra = cache->startframe, efra = cache->endframe;
+ PointCache *cache = pid->cache;
+ PTCacheMem *pm = NULL;
+ int baked = cache->flag & PTCACHE_BAKED;
+ int cfra, sfra = cache->startframe, efra = cache->endframe;
- /* Remove possible bake flag to allow clear */
- cache->flag &= ~PTCACHE_BAKED;
+ /* Remove possible bake flag to allow clear */
+ cache->flag &= ~PTCACHE_BAKED;
- /* PTCACHE_DISK_CACHE flag was cleared already */
- BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
+ /* PTCACHE_DISK_CACHE flag was cleared already */
+ BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
- /* restore possible bake flag */
- cache->flag |= baked;
+ /* restore possible bake flag */
+ cache->flag |= baked;
- for (cfra=sfra; cfra <= efra; cfra++) {
- pm = ptcache_disk_frame_to_mem(pid, cfra);
+ for (cfra = sfra; cfra <= efra; cfra++) {
+ pm = ptcache_disk_frame_to_mem(pid, cfra);
- if (pm)
- BLI_addtail(&pid->cache->mem_cache, pm);
- }
+ if (pm)
+ BLI_addtail(&pid->cache->mem_cache, pm);
+ }
}
void BKE_ptcache_mem_to_disk(PTCacheID *pid)
{
- PointCache *cache = pid->cache;
- PTCacheMem *pm = cache->mem_cache.first;
- int baked = cache->flag & PTCACHE_BAKED;
+ PointCache *cache = pid->cache;
+ PTCacheMem *pm = cache->mem_cache.first;
+ int baked = cache->flag & PTCACHE_BAKED;
- /* Remove possible bake flag to allow clear */
- cache->flag &= ~PTCACHE_BAKED;
+ /* Remove possible bake flag to allow clear */
+ cache->flag &= ~PTCACHE_BAKED;
- /* PTCACHE_DISK_CACHE flag was set already */
- BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
+ /* PTCACHE_DISK_CACHE flag was set already */
+ BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
- /* restore possible bake flag */
- cache->flag |= baked;
+ /* restore possible bake flag */
+ cache->flag |= baked;
- for (; pm; pm=pm->next) {
- if (ptcache_mem_frame_to_disk(pid, pm)==0) {
- cache->flag &= ~PTCACHE_DISK_CACHE;
- break;
- }
- }
+ for (; pm; pm = pm->next) {
+ if (ptcache_mem_frame_to_disk(pid, pm) == 0) {
+ cache->flag &= ~PTCACHE_DISK_CACHE;
+ break;
+ }
+ }
- /* write info file */
- if (cache->flag & PTCACHE_BAKED)
- BKE_ptcache_write(pid, 0);
+ /* write info file */
+ if (cache->flag & PTCACHE_BAKED)
+ BKE_ptcache_write(pid, 0);
}
void BKE_ptcache_toggle_disk_cache(PTCacheID *pid)
{
- PointCache *cache = pid->cache;
- int last_exact = cache->last_exact;
-
- if (!G.relbase_valid) {
- cache->flag &= ~PTCACHE_DISK_CACHE;
- if (G.debug & G_DEBUG)
- printf("File must be saved before using disk cache!\n");
- return;
- }
-
- if (cache->cached_frames) {
- MEM_freeN(cache->cached_frames);
- cache->cached_frames = NULL;
- cache->cached_frames_len = 0;
- }
-
- if (cache->flag & PTCACHE_DISK_CACHE)
- BKE_ptcache_mem_to_disk(pid);
- else
- BKE_ptcache_disk_to_mem(pid);
-
- cache->flag ^= PTCACHE_DISK_CACHE;
- BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
- cache->flag ^= PTCACHE_DISK_CACHE;
-
- cache->last_exact = last_exact;
-
- BKE_ptcache_id_time(pid, NULL, 0.0f, NULL, NULL, NULL);
-
- BKE_ptcache_update_info(pid);
-
- if ((cache->flag & PTCACHE_DISK_CACHE) == 0) {
- if (cache->index) {
- BKE_object_delete_ptcache(pid->ob, cache->index);
- cache->index = -1;
- }
- }
+ PointCache *cache = pid->cache;
+ int last_exact = cache->last_exact;
+
+ if (!G.relbase_valid) {
+ cache->flag &= ~PTCACHE_DISK_CACHE;
+ if (G.debug & G_DEBUG)
+ printf("File must be saved before using disk cache!\n");
+ return;
+ }
+
+ if (cache->cached_frames) {
+ MEM_freeN(cache->cached_frames);
+ cache->cached_frames = NULL;
+ cache->cached_frames_len = 0;
+ }
+
+ if (cache->flag & PTCACHE_DISK_CACHE)
+ BKE_ptcache_mem_to_disk(pid);
+ else
+ BKE_ptcache_disk_to_mem(pid);
+
+ cache->flag ^= PTCACHE_DISK_CACHE;
+ BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
+ cache->flag ^= PTCACHE_DISK_CACHE;
+
+ cache->last_exact = last_exact;
+
+ BKE_ptcache_id_time(pid, NULL, 0.0f, NULL, NULL, NULL);
+
+ BKE_ptcache_update_info(pid);
+
+ if ((cache->flag & PTCACHE_DISK_CACHE) == 0) {
+ if (cache->index) {
+ BKE_object_delete_ptcache(pid->ob, cache->index);
+ cache->index = -1;
+ }
+ }
}
void BKE_ptcache_disk_cache_rename(PTCacheID *pid, const char *name_src, const char *name_dst)
{
- char old_name[80];
- int len; /* store the length of the string */
- /* mode is same as fopen's modes */
- DIR *dir;
- struct dirent *de;
- char path[MAX_PTCACHE_PATH];
- char old_filename[MAX_PTCACHE_FILE];
- char new_path_full[MAX_PTCACHE_FILE];
- char old_path_full[MAX_PTCACHE_FILE];
- char ext[MAX_PTCACHE_PATH];
-
- /* save old name */
- BLI_strncpy(old_name, pid->cache->name, sizeof(old_name));
-
- /* get "from" filename */
- BLI_strncpy(pid->cache->name, name_src, sizeof(pid->cache->name));
-
- len = ptcache_filename(pid, old_filename, 0, 0, 0); /* no path */
-
- ptcache_path(pid, path);
- dir = opendir(path);
- if (dir==NULL) {
- BLI_strncpy(pid->cache->name, old_name, sizeof(pid->cache->name));
- return;
- }
-
- const char *fext = ptcache_file_extension(pid);
-
- BLI_snprintf(ext, sizeof(ext), "_%02u%s", pid->stack_index, fext);
-
- /* put new name into cache */
- BLI_strncpy(pid->cache->name, name_dst, sizeof(pid->cache->name));
-
- while ((de = readdir(dir)) != NULL) {
- if (strstr(de->d_name, ext)) { /* do we have the right extension?*/
- if (STREQLEN(old_filename, de->d_name, len)) { /* do we have the right prefix */
- /* read the number of the file */
- const int frame = ptcache_frame_from_filename(de->d_name, ext);
-
- if (frame != -1) {
- BLI_join_dirfile(old_path_full, sizeof(old_path_full), path, de->d_name);
- ptcache_filename(pid, new_path_full, frame, 1, 1);
- BLI_rename(old_path_full, new_path_full);
- }
- }
- }
- }
- closedir(dir);
-
- BLI_strncpy(pid->cache->name, old_name, sizeof(pid->cache->name));
+ char old_name[80];
+ int len; /* store the length of the string */
+ /* mode is same as fopen's modes */
+ DIR *dir;
+ struct dirent *de;
+ char path[MAX_PTCACHE_PATH];
+ char old_filename[MAX_PTCACHE_FILE];
+ char new_path_full[MAX_PTCACHE_FILE];
+ char old_path_full[MAX_PTCACHE_FILE];
+ char ext[MAX_PTCACHE_PATH];
+
+ /* save old name */
+ BLI_strncpy(old_name, pid->cache->name, sizeof(old_name));
+
+ /* get "from" filename */
+ BLI_strncpy(pid->cache->name, name_src, sizeof(pid->cache->name));
+
+ len = ptcache_filename(pid, old_filename, 0, 0, 0); /* no path */
+
+ ptcache_path(pid, path);
+ dir = opendir(path);
+ if (dir == NULL) {
+ BLI_strncpy(pid->cache->name, old_name, sizeof(pid->cache->name));
+ return;
+ }
+
+ const char *fext = ptcache_file_extension(pid);
+
+ BLI_snprintf(ext, sizeof(ext), "_%02u%s", pid->stack_index, fext);
+
+ /* put new name into cache */
+ BLI_strncpy(pid->cache->name, name_dst, sizeof(pid->cache->name));
+
+ while ((de = readdir(dir)) != NULL) {
+ if (strstr(de->d_name, ext)) { /* do we have the right extension?*/
+ if (STREQLEN(old_filename, de->d_name, len)) { /* do we have the right prefix */
+ /* read the number of the file */
+ const int frame = ptcache_frame_from_filename(de->d_name, ext);
+
+ if (frame != -1) {
+ BLI_join_dirfile(old_path_full, sizeof(old_path_full), path, de->d_name);
+ ptcache_filename(pid, new_path_full, frame, 1, 1);
+ BLI_rename(old_path_full, new_path_full);
+ }
+ }
+ }
+ }
+ closedir(dir);
+
+ BLI_strncpy(pid->cache->name, old_name, sizeof(pid->cache->name));
}
void BKE_ptcache_load_external(PTCacheID *pid)
{
- /*todo*/
- PointCache *cache = pid->cache;
- int len; /* store the length of the string */
- int info = 0;
- int start = MAXFRAME;
- int end = -1;
-
- /* mode is same as fopen's modes */
- DIR *dir;
- struct dirent *de;
- char path[MAX_PTCACHE_PATH];
- char filename[MAX_PTCACHE_FILE];
- char ext[MAX_PTCACHE_PATH];
-
- if (!cache)
- return;
-
- ptcache_path(pid, path);
-
- len = ptcache_filename(pid, filename, 1, 0, 0); /* no path */
-
- dir = opendir(path);
- if (dir==NULL)
- return;
-
- const char *fext = ptcache_file_extension(pid);
-
- if (cache->index >= 0)
- BLI_snprintf(ext, sizeof(ext), "_%02d%s", cache->index, fext);
- else
- BLI_strncpy(ext, fext, sizeof(ext));
-
- while ((de = readdir(dir)) != NULL) {
- if (strstr(de->d_name, ext)) { /* do we have the right extension?*/
- if (STREQLEN(filename, de->d_name, len)) { /* do we have the right prefix */
- /* read the number of the file */
- const int frame = ptcache_frame_from_filename(de->d_name, ext);
-
- if (frame != -1) {
- if (frame) {
- start = MIN2(start, frame);
- end = MAX2(end, frame);
- }
- else
- info = 1;
- }
- }
- }
- }
- closedir(dir);
-
- if (start != MAXFRAME) {
- PTCacheFile *pf;
-
- cache->startframe = start;
- cache->endframe = end;
- cache->totpoint = 0;
-
- if (pid->type == PTCACHE_TYPE_SMOKE_DOMAIN) {
- /* necessary info in every file */
- }
- /* read totpoint from info file (frame 0) */
- else if (info) {
- pf= ptcache_file_open(pid, PTCACHE_FILE_READ, 0);
-
- if (pf) {
- if (ptcache_file_header_begin_read(pf)) {
- if (pf->type == pid->type && pid->read_header(pf)) {
- cache->totpoint = pf->totpoint;
- cache->flag |= PTCACHE_READ_INFO;
- }
- else {
- cache->totpoint = 0;
- }
- }
- ptcache_file_close(pf);
- }
- }
- /* or from any old format cache file */
- else {
- float old_data[14];
- int elemsize = ptcache_old_elemsize(pid);
- pf= ptcache_file_open(pid, PTCACHE_FILE_READ, cache->startframe);
-
- if (pf) {
- while (ptcache_file_read(pf, old_data, 1, elemsize))
- cache->totpoint++;
-
- ptcache_file_close(pf);
- }
- }
- cache->flag |= (PTCACHE_BAKED|PTCACHE_DISK_CACHE|PTCACHE_SIMULATION_VALID);
- cache->flag &= ~(PTCACHE_OUTDATED|PTCACHE_FRAMES_SKIPPED);
- }
-
- /* make sure all new frames are loaded */
- if (cache->cached_frames) {
- MEM_freeN(cache->cached_frames);
- cache->cached_frames = NULL;
- cache->cached_frames_len = 0;
- }
- BKE_ptcache_update_info(pid);
+ /*todo*/
+ PointCache *cache = pid->cache;
+ int len; /* store the length of the string */
+ int info = 0;
+ int start = MAXFRAME;
+ int end = -1;
+
+ /* mode is same as fopen's modes */
+ DIR *dir;
+ struct dirent *de;
+ char path[MAX_PTCACHE_PATH];
+ char filename[MAX_PTCACHE_FILE];
+ char ext[MAX_PTCACHE_PATH];
+
+ if (!cache)
+ return;
+
+ ptcache_path(pid, path);
+
+ len = ptcache_filename(pid, filename, 1, 0, 0); /* no path */
+
+ dir = opendir(path);
+ if (dir == NULL)
+ return;
+
+ const char *fext = ptcache_file_extension(pid);
+
+ if (cache->index >= 0)
+ BLI_snprintf(ext, sizeof(ext), "_%02d%s", cache->index, fext);
+ else
+ BLI_strncpy(ext, fext, sizeof(ext));
+
+ while ((de = readdir(dir)) != NULL) {
+ if (strstr(de->d_name, ext)) { /* do we have the right extension?*/
+ if (STREQLEN(filename, de->d_name, len)) { /* do we have the right prefix */
+ /* read the number of the file */
+ const int frame = ptcache_frame_from_filename(de->d_name, ext);
+
+ if (frame != -1) {
+ if (frame) {
+ start = MIN2(start, frame);
+ end = MAX2(end, frame);
+ }
+ else
+ info = 1;
+ }
+ }
+ }
+ }
+ closedir(dir);
+
+ if (start != MAXFRAME) {
+ PTCacheFile *pf;
+
+ cache->startframe = start;
+ cache->endframe = end;
+ cache->totpoint = 0;
+
+ if (pid->type == PTCACHE_TYPE_SMOKE_DOMAIN) {
+ /* necessary info in every file */
+ }
+ /* read totpoint from info file (frame 0) */
+ else if (info) {
+ pf = ptcache_file_open(pid, PTCACHE_FILE_READ, 0);
+
+ if (pf) {
+ if (ptcache_file_header_begin_read(pf)) {
+ if (pf->type == pid->type && pid->read_header(pf)) {
+ cache->totpoint = pf->totpoint;
+ cache->flag |= PTCACHE_READ_INFO;
+ }
+ else {
+ cache->totpoint = 0;
+ }
+ }
+ ptcache_file_close(pf);
+ }
+ }
+ /* or from any old format cache file */
+ else {
+ float old_data[14];
+ int elemsize = ptcache_old_elemsize(pid);
+ pf = ptcache_file_open(pid, PTCACHE_FILE_READ, cache->startframe);
+
+ if (pf) {
+ while (ptcache_file_read(pf, old_data, 1, elemsize))
+ cache->totpoint++;
+
+ ptcache_file_close(pf);
+ }
+ }
+ cache->flag |= (PTCACHE_BAKED | PTCACHE_DISK_CACHE | PTCACHE_SIMULATION_VALID);
+ cache->flag &= ~(PTCACHE_OUTDATED | PTCACHE_FRAMES_SKIPPED);
+ }
+
+ /* make sure all new frames are loaded */
+ if (cache->cached_frames) {
+ MEM_freeN(cache->cached_frames);
+ cache->cached_frames = NULL;
+ cache->cached_frames_len = 0;
+ }
+ BKE_ptcache_update_info(pid);
}
void BKE_ptcache_update_info(PTCacheID *pid)
{
- PointCache *cache = pid->cache;
- PTCacheExtra *extra = NULL;
- int totframes = 0;
- char mem_info[64];
-
- if (cache->flag & PTCACHE_EXTERNAL) {
- int cfra = cache->startframe;
-
- for (; cfra <= cache->endframe; cfra++) {
- if (BKE_ptcache_id_exist(pid, cfra))
- totframes++;
- }
-
- /* smoke doesn't use frame 0 as info frame so can't check based on totpoint */
- if (pid->type == PTCACHE_TYPE_SMOKE_DOMAIN && totframes)
- BLI_snprintf(cache->info, sizeof(cache->info), IFACE_("%i frames found!"), totframes);
- else if (totframes && cache->totpoint)
- BLI_snprintf(cache->info, sizeof(cache->info), IFACE_("%i points found!"), cache->totpoint);
- else
- BLI_strncpy(cache->info, IFACE_("No valid data to read!"), sizeof(cache->info));
- return;
- }
-
- if (cache->flag & PTCACHE_DISK_CACHE) {
- if (pid->type == PTCACHE_TYPE_SMOKE_DOMAIN) {
- int totpoint = pid->totpoint(pid->calldata, 0);
-
- if (cache->totpoint > totpoint)
- BLI_snprintf(mem_info, sizeof(mem_info), IFACE_("%i cells + High Resolution cached"), totpoint);
- else
- BLI_snprintf(mem_info, sizeof(mem_info), IFACE_("%i cells cached"), totpoint);
- }
- else {
- int cfra = cache->startframe;
-
- for (; cfra <= cache->endframe; cfra++) {
- if (BKE_ptcache_id_exist(pid, cfra))
- totframes++;
- }
-
- BLI_snprintf(mem_info, sizeof(mem_info), IFACE_("%i frames on disk"), totframes);
- }
- }
- else {
- PTCacheMem *pm = cache->mem_cache.first;
- char formatted_tot[16];
- char formatted_mem[15];
- long long int bytes = 0.0f;
- int i;
-
- for (; pm; pm=pm->next) {
- for (i=0; i<BPHYS_TOT_DATA; i++)
- bytes += MEM_allocN_len(pm->data[i]);
-
- for (extra=pm->extradata.first; extra; extra=extra->next) {
- bytes += MEM_allocN_len(extra->data);
- bytes += sizeof(PTCacheExtra);
- }
-
- bytes += sizeof(PTCacheMem);
-
- totframes++;
- }
-
- BLI_str_format_int_grouped(formatted_tot, totframes);
- BLI_str_format_byte_unit(formatted_mem, bytes, true);
-
- BLI_snprintf(mem_info, sizeof(mem_info), IFACE_("%s frames in memory (%s)"), formatted_tot, formatted_mem);
- }
-
- if (cache->flag & PTCACHE_OUTDATED) {
- BLI_snprintf(cache->info, sizeof(cache->info), IFACE_("%s, cache is outdated!"), mem_info);
- }
- else if (cache->flag & PTCACHE_FRAMES_SKIPPED) {
- BLI_snprintf(cache->info, sizeof(cache->info), IFACE_("%s, not exact since frame %i"),
- mem_info, cache->last_exact);
- }
- else {
- BLI_snprintf(cache->info, sizeof(cache->info), "%s.", mem_info);
- }
+ PointCache *cache = pid->cache;
+ PTCacheExtra *extra = NULL;
+ int totframes = 0;
+ char mem_info[64];
+
+ if (cache->flag & PTCACHE_EXTERNAL) {
+ int cfra = cache->startframe;
+
+ for (; cfra <= cache->endframe; cfra++) {
+ if (BKE_ptcache_id_exist(pid, cfra))
+ totframes++;
+ }
+
+ /* smoke doesn't use frame 0 as info frame so can't check based on totpoint */
+ if (pid->type == PTCACHE_TYPE_SMOKE_DOMAIN && totframes)
+ BLI_snprintf(cache->info, sizeof(cache->info), IFACE_("%i frames found!"), totframes);
+ else if (totframes && cache->totpoint)
+ BLI_snprintf(cache->info, sizeof(cache->info), IFACE_("%i points found!"), cache->totpoint);
+ else
+ BLI_strncpy(cache->info, IFACE_("No valid data to read!"), sizeof(cache->info));
+ return;
+ }
+
+ if (cache->flag & PTCACHE_DISK_CACHE) {
+ if (pid->type == PTCACHE_TYPE_SMOKE_DOMAIN) {
+ int totpoint = pid->totpoint(pid->calldata, 0);
+
+ if (cache->totpoint > totpoint)
+ BLI_snprintf(
+ mem_info, sizeof(mem_info), IFACE_("%i cells + High Resolution cached"), totpoint);
+ else
+ BLI_snprintf(mem_info, sizeof(mem_info), IFACE_("%i cells cached"), totpoint);
+ }
+ else {
+ int cfra = cache->startframe;
+
+ for (; cfra <= cache->endframe; cfra++) {
+ if (BKE_ptcache_id_exist(pid, cfra))
+ totframes++;
+ }
+
+ BLI_snprintf(mem_info, sizeof(mem_info), IFACE_("%i frames on disk"), totframes);
+ }
+ }
+ else {
+ PTCacheMem *pm = cache->mem_cache.first;
+ char formatted_tot[16];
+ char formatted_mem[15];
+ long long int bytes = 0.0f;
+ int i;
+
+ for (; pm; pm = pm->next) {
+ for (i = 0; i < BPHYS_TOT_DATA; i++)
+ bytes += MEM_allocN_len(pm->data[i]);
+
+ for (extra = pm->extradata.first; extra; extra = extra->next) {
+ bytes += MEM_allocN_len(extra->data);
+ bytes += sizeof(PTCacheExtra);
+ }
+
+ bytes += sizeof(PTCacheMem);
+
+ totframes++;
+ }
+
+ BLI_str_format_int_grouped(formatted_tot, totframes);
+ BLI_str_format_byte_unit(formatted_mem, bytes, true);
+
+ BLI_snprintf(mem_info,
+ sizeof(mem_info),
+ IFACE_("%s frames in memory (%s)"),
+ formatted_tot,
+ formatted_mem);
+ }
+
+ if (cache->flag & PTCACHE_OUTDATED) {
+ BLI_snprintf(cache->info, sizeof(cache->info), IFACE_("%s, cache is outdated!"), mem_info);
+ }
+ else if (cache->flag & PTCACHE_FRAMES_SKIPPED) {
+ BLI_snprintf(cache->info,
+ sizeof(cache->info),
+ IFACE_("%s, not exact since frame %i"),
+ mem_info,
+ cache->last_exact);
+ }
+ else {
+ BLI_snprintf(cache->info, sizeof(cache->info), "%s.", mem_info);
+ }
}
void BKE_ptcache_validate(PointCache *cache, int framenr)
{
- if (cache) {
- cache->flag |= PTCACHE_SIMULATION_VALID;
- cache->simframe = framenr;
- }
+ if (cache) {
+ cache->flag |= PTCACHE_SIMULATION_VALID;
+ cache->simframe = framenr;
+ }
}
void BKE_ptcache_invalidate(PointCache *cache)
{
- if (cache) {
- cache->flag &= ~PTCACHE_SIMULATION_VALID;
- cache->simframe = 0;
- cache->last_exact = MIN2(cache->startframe, 0);
- }
+ if (cache) {
+ cache->flag &= ~PTCACHE_SIMULATION_VALID;
+ cache->simframe = 0;
+ cache->last_exact = MIN2(cache->startframe, 0);
+ }
}
diff --git a/source/blender/blenkernel/intern/report.c b/source/blender/blenkernel/intern/report.c
index e4de75ba42c..1319c6de835 100644
--- a/source/blender/blenkernel/intern/report.c
+++ b/source/blender/blenkernel/intern/report.c
@@ -39,293 +39,295 @@
const char *BKE_report_type_str(ReportType type)
{
- switch (type) {
- case RPT_DEBUG:
- return TIP_("Debug");
- case RPT_INFO:
- return TIP_("Info");
- case RPT_OPERATOR:
- return TIP_("Operator");
- case RPT_PROPERTY:
- return TIP_("Property");
- case RPT_WARNING:
- return TIP_("Warning");
- case RPT_ERROR:
- return TIP_("Error");
- case RPT_ERROR_INVALID_INPUT:
- return TIP_("Invalid Input Error");
- case RPT_ERROR_INVALID_CONTEXT:
- return TIP_("Invalid Context Error");
- case RPT_ERROR_OUT_OF_MEMORY:
- return TIP_("Out Of Memory Error");
- default:
- return TIP_("Undefined Type");
- }
+ switch (type) {
+ case RPT_DEBUG:
+ return TIP_("Debug");
+ case RPT_INFO:
+ return TIP_("Info");
+ case RPT_OPERATOR:
+ return TIP_("Operator");
+ case RPT_PROPERTY:
+ return TIP_("Property");
+ case RPT_WARNING:
+ return TIP_("Warning");
+ case RPT_ERROR:
+ return TIP_("Error");
+ case RPT_ERROR_INVALID_INPUT:
+ return TIP_("Invalid Input Error");
+ case RPT_ERROR_INVALID_CONTEXT:
+ return TIP_("Invalid Context Error");
+ case RPT_ERROR_OUT_OF_MEMORY:
+ return TIP_("Out Of Memory Error");
+ default:
+ return TIP_("Undefined Type");
+ }
}
void BKE_reports_init(ReportList *reports, int flag)
{
- if (!reports)
- return;
+ if (!reports)
+ return;
- memset(reports, 0, sizeof(ReportList));
+ memset(reports, 0, sizeof(ReportList));
- reports->storelevel = RPT_INFO;
- reports->printlevel = RPT_ERROR;
- reports->flag = flag;
+ reports->storelevel = RPT_INFO;
+ reports->printlevel = RPT_ERROR;
+ reports->flag = flag;
}
void BKE_reports_clear(ReportList *reports)
{
- Report *report, *report_next;
+ Report *report, *report_next;
- if (!reports)
- return;
+ if (!reports)
+ return;
- report = reports->list.first;
+ report = reports->list.first;
- while (report) {
- report_next = report->next;
- MEM_freeN((void *)report->message);
- MEM_freeN(report);
- report = report_next;
- }
+ while (report) {
+ report_next = report->next;
+ MEM_freeN((void *)report->message);
+ MEM_freeN(report);
+ report = report_next;
+ }
- BLI_listbase_clear(&reports->list);
+ BLI_listbase_clear(&reports->list);
}
void BKE_report(ReportList *reports, ReportType type, const char *_message)
{
- Report *report;
- int len;
- const char *message = TIP_(_message);
-
- /* in background mode always print otherwise there are cases the errors wont be displayed,
- * but still add to the report list since this is used for python exception handling */
- if (G.background || !reports || ((reports->flag & RPT_PRINT) && (type >= reports->printlevel))) {
- printf("%s: %s\n", BKE_report_type_str(type), message);
- fflush(stdout); /* this ensures the message is printed before a crash */
- }
-
- if (reports && (reports->flag & RPT_STORE) && (type >= reports->storelevel)) {
- char *message_alloc;
- report = MEM_callocN(sizeof(Report), "Report");
- report->type = type;
- report->typestr = BKE_report_type_str(type);
-
- len = strlen(message);
- message_alloc = MEM_callocN(sizeof(char) * (len + 1), "ReportMessage");
- memcpy(message_alloc, message, sizeof(char) * (len + 1));
- report->message = message_alloc;
- report->len = len;
- BLI_addtail(&reports->list, report);
- }
+ Report *report;
+ int len;
+ const char *message = TIP_(_message);
+
+ /* in background mode always print otherwise there are cases the errors wont be displayed,
+ * but still add to the report list since this is used for python exception handling */
+ if (G.background || !reports || ((reports->flag & RPT_PRINT) && (type >= reports->printlevel))) {
+ printf("%s: %s\n", BKE_report_type_str(type), message);
+ fflush(stdout); /* this ensures the message is printed before a crash */
+ }
+
+ if (reports && (reports->flag & RPT_STORE) && (type >= reports->storelevel)) {
+ char *message_alloc;
+ report = MEM_callocN(sizeof(Report), "Report");
+ report->type = type;
+ report->typestr = BKE_report_type_str(type);
+
+ len = strlen(message);
+ message_alloc = MEM_callocN(sizeof(char) * (len + 1), "ReportMessage");
+ memcpy(message_alloc, message, sizeof(char) * (len + 1));
+ report->message = message_alloc;
+ report->len = len;
+ BLI_addtail(&reports->list, report);
+ }
}
void BKE_reportf(ReportList *reports, ReportType type, const char *_format, ...)
{
- DynStr *ds;
- Report *report;
- va_list args;
- const char *format = TIP_(_format);
-
- if (G.background || !reports || ((reports->flag & RPT_PRINT) && (type >= reports->printlevel))) {
- printf("%s: ", BKE_report_type_str(type));
- va_start(args, _format);
- vprintf(format, args);
- va_end(args);
- fprintf(stdout, "\n"); /* otherwise each report needs to include a \n */
- fflush(stdout); /* this ensures the message is printed before a crash */
- }
-
- if (reports && (reports->flag & RPT_STORE) && (type >= reports->storelevel)) {
- report = MEM_callocN(sizeof(Report), "Report");
-
- ds = BLI_dynstr_new();
- va_start(args, _format);
- BLI_dynstr_vappendf(ds, format, args);
- va_end(args);
-
- report->message = BLI_dynstr_get_cstring(ds);
- report->len = BLI_dynstr_get_len(ds);
- BLI_dynstr_free(ds);
-
- report->type = type;
- report->typestr = BKE_report_type_str(type);
-
- BLI_addtail(&reports->list, report);
- }
+ DynStr *ds;
+ Report *report;
+ va_list args;
+ const char *format = TIP_(_format);
+
+ if (G.background || !reports || ((reports->flag & RPT_PRINT) && (type >= reports->printlevel))) {
+ printf("%s: ", BKE_report_type_str(type));
+ va_start(args, _format);
+ vprintf(format, args);
+ va_end(args);
+ fprintf(stdout, "\n"); /* otherwise each report needs to include a \n */
+ fflush(stdout); /* this ensures the message is printed before a crash */
+ }
+
+ if (reports && (reports->flag & RPT_STORE) && (type >= reports->storelevel)) {
+ report = MEM_callocN(sizeof(Report), "Report");
+
+ ds = BLI_dynstr_new();
+ va_start(args, _format);
+ BLI_dynstr_vappendf(ds, format, args);
+ va_end(args);
+
+ report->message = BLI_dynstr_get_cstring(ds);
+ report->len = BLI_dynstr_get_len(ds);
+ BLI_dynstr_free(ds);
+
+ report->type = type;
+ report->typestr = BKE_report_type_str(type);
+
+ BLI_addtail(&reports->list, report);
+ }
}
void BKE_reports_prepend(ReportList *reports, const char *_prepend)
{
- Report *report;
- DynStr *ds;
- const char *prepend = TIP_(_prepend);
+ Report *report;
+ DynStr *ds;
+ const char *prepend = TIP_(_prepend);
- if (!reports)
- return;
+ if (!reports)
+ return;
- for (report = reports->list.first; report; report = report->next) {
- ds = BLI_dynstr_new();
+ for (report = reports->list.first; report; report = report->next) {
+ ds = BLI_dynstr_new();
- BLI_dynstr_append(ds, prepend);
- BLI_dynstr_append(ds, report->message);
- MEM_freeN((void *)report->message);
+ BLI_dynstr_append(ds, prepend);
+ BLI_dynstr_append(ds, report->message);
+ MEM_freeN((void *)report->message);
- report->message = BLI_dynstr_get_cstring(ds);
- report->len = BLI_dynstr_get_len(ds);
+ report->message = BLI_dynstr_get_cstring(ds);
+ report->len = BLI_dynstr_get_len(ds);
- BLI_dynstr_free(ds);
- }
+ BLI_dynstr_free(ds);
+ }
}
void BKE_reports_prependf(ReportList *reports, const char *_prepend, ...)
{
- Report *report;
- DynStr *ds;
- va_list args;
- const char *prepend = TIP_(_prepend);
+ Report *report;
+ DynStr *ds;
+ va_list args;
+ const char *prepend = TIP_(_prepend);
- if (!reports)
- return;
+ if (!reports)
+ return;
- for (report = reports->list.first; report; report = report->next) {
- ds = BLI_dynstr_new();
- va_start(args, _prepend);
- BLI_dynstr_vappendf(ds, prepend, args);
- va_end(args);
+ for (report = reports->list.first; report; report = report->next) {
+ ds = BLI_dynstr_new();
+ va_start(args, _prepend);
+ BLI_dynstr_vappendf(ds, prepend, args);
+ va_end(args);
- BLI_dynstr_append(ds, report->message);
- MEM_freeN((void *)report->message);
+ BLI_dynstr_append(ds, report->message);
+ MEM_freeN((void *)report->message);
- report->message = BLI_dynstr_get_cstring(ds);
- report->len = BLI_dynstr_get_len(ds);
+ report->message = BLI_dynstr_get_cstring(ds);
+ report->len = BLI_dynstr_get_len(ds);
- BLI_dynstr_free(ds);
- }
+ BLI_dynstr_free(ds);
+ }
}
ReportType BKE_report_print_level(ReportList *reports)
{
- if (!reports)
- return RPT_ERROR;
+ if (!reports)
+ return RPT_ERROR;
- return reports->printlevel;
+ return reports->printlevel;
}
void BKE_report_print_level_set(ReportList *reports, ReportType level)
{
- if (!reports)
- return;
+ if (!reports)
+ return;
- reports->printlevel = level;
+ reports->printlevel = level;
}
ReportType BKE_report_store_level(ReportList *reports)
{
- if (!reports)
- return RPT_ERROR;
+ if (!reports)
+ return RPT_ERROR;
- return reports->storelevel;
+ return reports->storelevel;
}
void BKE_report_store_level_set(ReportList *reports, ReportType level)
{
- if (!reports)
- return;
+ if (!reports)
+ return;
- reports->storelevel = level;
+ reports->storelevel = level;
}
char *BKE_reports_string(ReportList *reports, ReportType level)
{
- Report *report;
- DynStr *ds;
- char *cstring;
+ Report *report;
+ DynStr *ds;
+ char *cstring;
- if (!reports || !reports->list.first)
- return NULL;
+ if (!reports || !reports->list.first)
+ return NULL;
- ds = BLI_dynstr_new();
- for (report = reports->list.first; report; report = report->next)
- if (report->type >= level)
- BLI_dynstr_appendf(ds, "%s: %s\n", report->typestr, report->message);
+ ds = BLI_dynstr_new();
+ for (report = reports->list.first; report; report = report->next)
+ if (report->type >= level)
+ BLI_dynstr_appendf(ds, "%s: %s\n", report->typestr, report->message);
- if (BLI_dynstr_get_len(ds))
- cstring = BLI_dynstr_get_cstring(ds);
- else
- cstring = NULL;
+ if (BLI_dynstr_get_len(ds))
+ cstring = BLI_dynstr_get_cstring(ds);
+ else
+ cstring = NULL;
- BLI_dynstr_free(ds);
- return cstring;
+ BLI_dynstr_free(ds);
+ return cstring;
}
void BKE_reports_print(ReportList *reports, ReportType level)
{
- char *cstring = BKE_reports_string(reports, level);
+ char *cstring = BKE_reports_string(reports, level);
- if (cstring == NULL)
- return;
+ if (cstring == NULL)
+ return;
- puts(cstring);
- fflush(stdout);
- MEM_freeN(cstring);
+ puts(cstring);
+ fflush(stdout);
+ MEM_freeN(cstring);
}
Report *BKE_reports_last_displayable(ReportList *reports)
{
- Report *report;
+ Report *report;
- for (report = reports->list.last; report; report = report->prev) {
- if (ELEM(report->type, RPT_ERROR, RPT_WARNING, RPT_INFO))
- return report;
- }
+ for (report = reports->list.last; report; report = report->prev) {
+ if (ELEM(report->type, RPT_ERROR, RPT_WARNING, RPT_INFO))
+ return report;
+ }
- return NULL;
+ return NULL;
}
bool BKE_reports_contain(ReportList *reports, ReportType level)
{
- Report *report;
- if (reports != NULL) {
- for (report = reports->list.first; report; report = report->next)
- if (report->type >= level)
- return true;
- }
- return false;
+ Report *report;
+ if (reports != NULL) {
+ for (report = reports->list.first; report; report = report->next)
+ if (report->type >= level)
+ return true;
+ }
+ return false;
}
bool BKE_report_write_file_fp(FILE *fp, ReportList *reports, const char *header)
{
- Report *report;
+ Report *report;
- if (header) {
- fputs(header, fp);
- }
+ if (header) {
+ fputs(header, fp);
+ }
- for (report = reports->list.first; report; report = report->next) {
- fprintf((FILE *)fp, "%s # %s\n", report->message, report->typestr);
- }
+ for (report = reports->list.first; report; report = report->next) {
+ fprintf((FILE *)fp, "%s # %s\n", report->message, report->typestr);
+ }
- return true;
+ return true;
}
bool BKE_report_write_file(const char *filepath, ReportList *reports, const char *header)
{
- FILE *fp;
+ FILE *fp;
- errno = 0;
- fp = BLI_fopen(filepath, "wb");
- if (fp == NULL) {
- fprintf(stderr, "Unable to save '%s': %s\n",
- filepath, errno ? strerror(errno) : "Unknown error opening file");
- return false;
- }
+ errno = 0;
+ fp = BLI_fopen(filepath, "wb");
+ if (fp == NULL) {
+ fprintf(stderr,
+ "Unable to save '%s': %s\n",
+ filepath,
+ errno ? strerror(errno) : "Unknown error opening file");
+ return false;
+ }
- BKE_report_write_file_fp(fp, reports, header);
+ BKE_report_write_file_fp(fp, reports, header);
- fclose(fp);
+ fclose(fp);
- return true;
+ return true;
}
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index 745c17c0919..78639b4ddb9 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -80,126 +80,136 @@ static CLG_LogRef LOG = {"bke.rigidbody"};
static void rigidbody_update_ob_array(RigidBodyWorld *rbw);
#else
-static void RB_dworld_remove_constraint(void *UNUSED(world), void *UNUSED(con)) {}
-static void RB_dworld_remove_body(void *UNUSED(world), void *UNUSED(body)) {}
-static void RB_dworld_delete(void *UNUSED(world)) {}
-static void RB_body_delete(void *UNUSED(body)) {}
-static void RB_shape_delete(void *UNUSED(shape)) {}
-static void RB_constraint_delete(void *UNUSED(con)) {}
+static void RB_dworld_remove_constraint(void *UNUSED(world), void *UNUSED(con))
+{
+}
+static void RB_dworld_remove_body(void *UNUSED(world), void *UNUSED(body))
+{
+}
+static void RB_dworld_delete(void *UNUSED(world))
+{
+}
+static void RB_body_delete(void *UNUSED(body))
+{
+}
+static void RB_shape_delete(void *UNUSED(shape))
+{
+}
+static void RB_constraint_delete(void *UNUSED(con))
+{
+}
#endif
/* Free rigidbody world */
void BKE_rigidbody_free_world(Scene *scene)
{
- bool is_orig = (scene->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0;
- RigidBodyWorld *rbw = scene->rigidbody_world;
- scene->rigidbody_world = NULL;
-
- /* sanity check */
- if (!rbw)
- return;
-
- if (is_orig && rbw->shared->physics_world) {
- /* free physics references, we assume that all physics objects in will have been added to the world */
- if (rbw->constraints) {
- FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->constraints, object)
- {
- if (object->rigidbody_constraint) {
- RigidBodyCon *rbc = object->rigidbody_constraint;
- if (rbc->physics_constraint) {
- RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint);
- }
- }
- }
- FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
- }
-
- if (rbw->group) {
- FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object)
- {
- BKE_rigidbody_free_object(object, rbw);
- }
- FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
- }
- /* free dynamics world */
- RB_dworld_delete(rbw->shared->physics_world);
- }
- if (rbw->objects)
- free(rbw->objects);
-
- if (is_orig) {
- /* free cache */
- BKE_ptcache_free_list(&(rbw->shared->ptcaches));
- rbw->shared->pointcache = NULL;
-
- MEM_freeN(rbw->shared);
- }
-
- /* free effector weights */
- if (rbw->effector_weights)
- MEM_freeN(rbw->effector_weights);
-
- /* free rigidbody world itself */
- MEM_freeN(rbw);
+ bool is_orig = (scene->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0;
+ RigidBodyWorld *rbw = scene->rigidbody_world;
+ scene->rigidbody_world = NULL;
+
+ /* sanity check */
+ if (!rbw)
+ return;
+
+ if (is_orig && rbw->shared->physics_world) {
+ /* free physics references, we assume that all physics objects in will have been added to the world */
+ if (rbw->constraints) {
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->constraints, object) {
+ if (object->rigidbody_constraint) {
+ RigidBodyCon *rbc = object->rigidbody_constraint;
+ if (rbc->physics_constraint) {
+ RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint);
+ }
+ }
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+ }
+
+ if (rbw->group) {
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->group, object) {
+ BKE_rigidbody_free_object(object, rbw);
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+ }
+ /* free dynamics world */
+ RB_dworld_delete(rbw->shared->physics_world);
+ }
+ if (rbw->objects)
+ free(rbw->objects);
+
+ if (is_orig) {
+ /* free cache */
+ BKE_ptcache_free_list(&(rbw->shared->ptcaches));
+ rbw->shared->pointcache = NULL;
+
+ MEM_freeN(rbw->shared);
+ }
+
+ /* free effector weights */
+ if (rbw->effector_weights)
+ MEM_freeN(rbw->effector_weights);
+
+ /* free rigidbody world itself */
+ MEM_freeN(rbw);
}
/* Free RigidBody settings and sim instances */
void BKE_rigidbody_free_object(Object *ob, RigidBodyWorld *rbw)
{
- bool is_orig = (ob->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0;
- RigidBodyOb *rbo = ob->rigidbody_object;
-
- /* sanity check */
- if (rbo == NULL)
- return;
-
- /* free physics references */
- if (is_orig) {
- if (rbo->shared->physics_object) {
- BLI_assert(rbw);
- if (rbw) {
- /* We can only remove the body from the world if the world is known.
- * The world is generally only unknown if it's an evaluated copy of
- * an object that's being freed, in which case this code isn't run anyway. */
- RB_dworld_remove_body(rbw->shared->physics_world, rbo->shared->physics_object);
- }
-
- RB_body_delete(rbo->shared->physics_object);
- rbo->shared->physics_object = NULL;
- }
-
- if (rbo->shared->physics_shape) {
- RB_shape_delete(rbo->shared->physics_shape);
- rbo->shared->physics_shape = NULL;
- }
-
- MEM_freeN(rbo->shared);
- }
-
- /* free data itself */
- MEM_freeN(rbo);
- ob->rigidbody_object = NULL;
+ bool is_orig = (ob->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0;
+ RigidBodyOb *rbo = ob->rigidbody_object;
+
+ /* sanity check */
+ if (rbo == NULL)
+ return;
+
+ /* free physics references */
+ if (is_orig) {
+ if (rbo->shared->physics_object) {
+ BLI_assert(rbw);
+ if (rbw) {
+ /* We can only remove the body from the world if the world is known.
+ * The world is generally only unknown if it's an evaluated copy of
+ * an object that's being freed, in which case this code isn't run anyway. */
+ RB_dworld_remove_body(rbw->shared->physics_world, rbo->shared->physics_object);
+ }
+
+ RB_body_delete(rbo->shared->physics_object);
+ rbo->shared->physics_object = NULL;
+ }
+
+ if (rbo->shared->physics_shape) {
+ RB_shape_delete(rbo->shared->physics_shape);
+ rbo->shared->physics_shape = NULL;
+ }
+
+ MEM_freeN(rbo->shared);
+ }
+
+ /* free data itself */
+ MEM_freeN(rbo);
+ ob->rigidbody_object = NULL;
}
/* Free RigidBody constraint and sim instance */
void BKE_rigidbody_free_constraint(Object *ob)
{
- RigidBodyCon *rbc = (ob) ? ob->rigidbody_constraint : NULL;
+ RigidBodyCon *rbc = (ob) ? ob->rigidbody_constraint : NULL;
- /* sanity check */
- if (rbc == NULL)
- return;
+ /* sanity check */
+ if (rbc == NULL)
+ return;
- /* free physics reference */
- if (rbc->physics_constraint) {
- RB_constraint_delete(rbc->physics_constraint);
- rbc->physics_constraint = NULL;
- }
+ /* free physics reference */
+ if (rbc->physics_constraint) {
+ RB_constraint_delete(rbc->physics_constraint);
+ rbc->physics_constraint = NULL;
+ }
- /* free data itself */
- MEM_freeN(rbc);
- ob->rigidbody_constraint = NULL;
+ /* free data itself */
+ MEM_freeN(rbc);
+ ob->rigidbody_constraint = NULL;
}
#ifdef WITH_BULLET
@@ -213,42 +223,42 @@ void BKE_rigidbody_free_constraint(Object *ob)
RigidBodyOb *BKE_rigidbody_copy_object(const Object *ob, const int flag)
{
- RigidBodyOb *rboN = NULL;
+ RigidBodyOb *rboN = NULL;
- if (ob->rigidbody_object) {
- /* just duplicate the whole struct first (to catch all the settings) */
- rboN = MEM_dupallocN(ob->rigidbody_object);
+ if (ob->rigidbody_object) {
+ /* just duplicate the whole struct first (to catch all the settings) */
+ rboN = MEM_dupallocN(ob->rigidbody_object);
- if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
- /* This is a regular copy, and not a CoW copy for depsgraph evaluation */
- rboN->shared = MEM_callocN(sizeof(*rboN->shared), "RigidBodyOb_Shared");
- }
+ if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
+ /* This is a regular copy, and not a CoW copy for depsgraph evaluation */
+ rboN->shared = MEM_callocN(sizeof(*rboN->shared), "RigidBodyOb_Shared");
+ }
- /* tag object as needing to be verified */
- rboN->flag |= RBO_FLAG_NEEDS_VALIDATE;
- }
+ /* tag object as needing to be verified */
+ rboN->flag |= RBO_FLAG_NEEDS_VALIDATE;
+ }
- /* return new copy of settings */
- return rboN;
+ /* return new copy of settings */
+ return rboN;
}
RigidBodyCon *BKE_rigidbody_copy_constraint(const Object *ob, const int UNUSED(flag))
{
- RigidBodyCon *rbcN = NULL;
+ RigidBodyCon *rbcN = NULL;
- if (ob->rigidbody_constraint) {
- /* just duplicate the whole struct first (to catch all the settings) */
- rbcN = MEM_dupallocN(ob->rigidbody_constraint);
+ if (ob->rigidbody_constraint) {
+ /* just duplicate the whole struct first (to catch all the settings) */
+ rbcN = MEM_dupallocN(ob->rigidbody_constraint);
- /* tag object as needing to be verified */
- rbcN->flag |= RBC_FLAG_NEEDS_VALIDATE;
+ /* tag object as needing to be verified */
+ rbcN->flag |= RBC_FLAG_NEEDS_VALIDATE;
- /* clear out all the fields which need to be revalidated later */
- rbcN->physics_constraint = NULL;
- }
+ /* clear out all the fields which need to be revalidated later */
+ rbcN->physics_constraint = NULL;
+ }
- /* return new copy of settings */
- return rbcN;
+ /* return new copy of settings */
+ return rbcN;
}
/* ************************************** */
@@ -257,49 +267,51 @@ RigidBodyCon *BKE_rigidbody_copy_constraint(const Object *ob, const int UNUSED(f
/* get the appropriate evaluated mesh based on rigid body mesh source */
static Mesh *rigidbody_get_mesh(Object *ob)
{
- switch (ob->rigidbody_object->mesh_source) {
- case RBO_MESH_DEFORM:
- return ob->runtime.mesh_deform_eval;
- case RBO_MESH_FINAL:
- return ob->runtime.mesh_eval;
- case RBO_MESH_BASE:
- /* This mesh may be used for computing looptris, which should be done
- * on the original; otherwise every time the CoW is recreated it will
- * have to be recomputed. */
- BLI_assert(ob->rigidbody_object->mesh_source == RBO_MESH_BASE);
- return ob->runtime.mesh_orig;
- }
-
- /* Just return something sensible so that at least Blender won't crash. */
- BLI_assert(!"Unknown mesh source");
- return ob->runtime.mesh_eval;
+ switch (ob->rigidbody_object->mesh_source) {
+ case RBO_MESH_DEFORM:
+ return ob->runtime.mesh_deform_eval;
+ case RBO_MESH_FINAL:
+ return ob->runtime.mesh_eval;
+ case RBO_MESH_BASE:
+ /* This mesh may be used for computing looptris, which should be done
+ * on the original; otherwise every time the CoW is recreated it will
+ * have to be recomputed. */
+ BLI_assert(ob->rigidbody_object->mesh_source == RBO_MESH_BASE);
+ return ob->runtime.mesh_orig;
+ }
+
+ /* Just return something sensible so that at least Blender won't crash. */
+ BLI_assert(!"Unknown mesh source");
+ return ob->runtime.mesh_eval;
}
/* create collision shape of mesh - convex hull */
-static rbCollisionShape *rigidbody_get_shape_convexhull_from_mesh(Object *ob, float margin, bool *can_embed)
+static rbCollisionShape *rigidbody_get_shape_convexhull_from_mesh(Object *ob,
+ float margin,
+ bool *can_embed)
{
- rbCollisionShape *shape = NULL;
- Mesh *mesh = NULL;
- MVert *mvert = NULL;
- int totvert = 0;
-
- if (ob->type == OB_MESH && ob->data) {
- mesh = rigidbody_get_mesh(ob);
- mvert = (mesh) ? mesh->mvert : NULL;
- totvert = (mesh) ? mesh->totvert : 0;
- }
- else {
- CLOG_ERROR(&LOG, "cannot make Convex Hull collision shape for non-Mesh object");
- }
-
- if (totvert) {
- shape = RB_shape_new_convex_hull((float *)mvert, sizeof(MVert), totvert, margin, can_embed);
- }
- else {
- CLOG_ERROR(&LOG, "no vertices to define Convex Hull collision shape with");
- }
-
- return shape;
+ rbCollisionShape *shape = NULL;
+ Mesh *mesh = NULL;
+ MVert *mvert = NULL;
+ int totvert = 0;
+
+ if (ob->type == OB_MESH && ob->data) {
+ mesh = rigidbody_get_mesh(ob);
+ mvert = (mesh) ? mesh->mvert : NULL;
+ totvert = (mesh) ? mesh->totvert : 0;
+ }
+ else {
+ CLOG_ERROR(&LOG, "cannot make Convex Hull collision shape for non-Mesh object");
+ }
+
+ if (totvert) {
+ shape = RB_shape_new_convex_hull((float *)mvert, sizeof(MVert), totvert, margin, can_embed);
+ }
+ else {
+ CLOG_ERROR(&LOG, "no vertices to define Convex Hull collision shape with");
+ }
+
+ return shape;
}
/* create collision shape of mesh - triangulated mesh
@@ -307,82 +319,83 @@ static rbCollisionShape *rigidbody_get_shape_convexhull_from_mesh(Object *ob, fl
*/
static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob)
{
- rbCollisionShape *shape = NULL;
-
- if (ob->type == OB_MESH) {
- Mesh *mesh = NULL;
- MVert *mvert;
- const MLoopTri *looptri;
- int totvert;
- int tottri;
- const MLoop *mloop;
-
- mesh = rigidbody_get_mesh(ob);
-
- /* ensure mesh validity, then grab data */
- if (mesh == NULL)
- return NULL;
-
- mvert = mesh->mvert;
- totvert = mesh->totvert;
- looptri = BKE_mesh_runtime_looptri_ensure(mesh);
- tottri = mesh->runtime.looptris.len;
- mloop = mesh->mloop;
-
- /* sanity checking - potential case when no data will be present */
- if ((totvert == 0) || (tottri == 0)) {
- CLOG_WARN(&LOG, "no geometry data converted for Mesh Collision Shape (ob = %s)", ob->id.name + 2);
- }
- else {
- rbMeshData *mdata;
- int i;
-
- /* init mesh data for collision shape */
- mdata = RB_trimesh_data_new(tottri, totvert);
-
- RB_trimesh_add_vertices(mdata, (float *)mvert, totvert, sizeof(MVert));
-
- /* loop over all faces, adding them as triangles to the collision shape
- * (so for some faces, more than triangle will get added)
- */
- if (mvert && looptri) {
- for (i = 0; i < tottri; i++) {
- /* add first triangle - verts 1,2,3 */
- const MLoopTri *lt = &looptri[i];
- int vtri[3];
-
- vtri[0] = mloop[lt->tri[0]].v;
- vtri[1] = mloop[lt->tri[1]].v;
- vtri[2] = mloop[lt->tri[2]].v;
-
- RB_trimesh_add_triangle_indices(mdata, i, UNPACK3(vtri));
- }
- }
-
- RB_trimesh_finish(mdata);
-
- /* construct collision shape
- *
- * These have been chosen to get better speed/accuracy tradeoffs with regards
- * to limitations of each:
- * - BVH-Triangle Mesh: for passive objects only. Despite having greater
- * speed/accuracy, they cannot be used for moving objects.
- * - GImpact Mesh: for active objects. These are slower and less stable,
- * but are more flexible for general usage.
- */
- if (ob->rigidbody_object->type == RBO_TYPE_PASSIVE) {
- shape = RB_shape_new_trimesh(mdata);
- }
- else {
- shape = RB_shape_new_gimpact_mesh(mdata);
- }
- }
- }
- else {
- CLOG_ERROR(&LOG, "cannot make Triangular Mesh collision shape for non-Mesh object");
- }
-
- return shape;
+ rbCollisionShape *shape = NULL;
+
+ if (ob->type == OB_MESH) {
+ Mesh *mesh = NULL;
+ MVert *mvert;
+ const MLoopTri *looptri;
+ int totvert;
+ int tottri;
+ const MLoop *mloop;
+
+ mesh = rigidbody_get_mesh(ob);
+
+ /* ensure mesh validity, then grab data */
+ if (mesh == NULL)
+ return NULL;
+
+ mvert = mesh->mvert;
+ totvert = mesh->totvert;
+ looptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ tottri = mesh->runtime.looptris.len;
+ mloop = mesh->mloop;
+
+ /* sanity checking - potential case when no data will be present */
+ if ((totvert == 0) || (tottri == 0)) {
+ CLOG_WARN(
+ &LOG, "no geometry data converted for Mesh Collision Shape (ob = %s)", ob->id.name + 2);
+ }
+ else {
+ rbMeshData *mdata;
+ int i;
+
+ /* init mesh data for collision shape */
+ mdata = RB_trimesh_data_new(tottri, totvert);
+
+ RB_trimesh_add_vertices(mdata, (float *)mvert, totvert, sizeof(MVert));
+
+ /* loop over all faces, adding them as triangles to the collision shape
+ * (so for some faces, more than triangle will get added)
+ */
+ if (mvert && looptri) {
+ for (i = 0; i < tottri; i++) {
+ /* add first triangle - verts 1,2,3 */
+ const MLoopTri *lt = &looptri[i];
+ int vtri[3];
+
+ vtri[0] = mloop[lt->tri[0]].v;
+ vtri[1] = mloop[lt->tri[1]].v;
+ vtri[2] = mloop[lt->tri[2]].v;
+
+ RB_trimesh_add_triangle_indices(mdata, i, UNPACK3(vtri));
+ }
+ }
+
+ RB_trimesh_finish(mdata);
+
+ /* construct collision shape
+ *
+ * These have been chosen to get better speed/accuracy tradeoffs with regards
+ * to limitations of each:
+ * - BVH-Triangle Mesh: for passive objects only. Despite having greater
+ * speed/accuracy, they cannot be used for moving objects.
+ * - GImpact Mesh: for active objects. These are slower and less stable,
+ * but are more flexible for general usage.
+ */
+ if (ob->rigidbody_object->type == RBO_TYPE_PASSIVE) {
+ shape = RB_shape_new_trimesh(mdata);
+ }
+ else {
+ shape = RB_shape_new_gimpact_mesh(mdata);
+ }
+ }
+ }
+ else {
+ CLOG_ERROR(&LOG, "cannot make Triangular Mesh collision shape for non-Mesh object");
+ }
+
+ return shape;
}
/* Create new physics sim collision shape for object and store it,
@@ -390,97 +403,99 @@ static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob)
*/
static void rigidbody_validate_sim_shape(Object *ob, bool rebuild)
{
- RigidBodyOb *rbo = ob->rigidbody_object;
- rbCollisionShape *new_shape = NULL;
- BoundBox *bb = NULL;
- float size[3] = {1.0f, 1.0f, 1.0f};
- float radius = 1.0f;
- float height = 1.0f;
- float capsule_height;
- float hull_margin = 0.0f;
- bool can_embed = true;
- bool has_volume;
-
- /* sanity check */
- if (rbo == NULL)
- return;
-
- /* don't create a new shape if we already have one and don't want to rebuild it */
- if (rbo->shared->physics_shape && !rebuild)
- return;
-
- /* if automatically determining dimensions, use the Object's boundbox
- * - assume that all quadrics are standing upright on local z-axis
- * - assume even distribution of mass around the Object's pivot
- * (i.e. Object pivot is centralized in boundbox)
- */
- // XXX: all dimensions are auto-determined now... later can add stored settings for this
- /* get object dimensions without scaling */
- bb = BKE_object_boundbox_get(ob);
- if (bb) {
- size[0] = (bb->vec[4][0] - bb->vec[0][0]);
- size[1] = (bb->vec[2][1] - bb->vec[0][1]);
- size[2] = (bb->vec[1][2] - bb->vec[0][2]);
- }
- mul_v3_fl(size, 0.5f);
-
- if (ELEM(rbo->shape, RB_SHAPE_CAPSULE, RB_SHAPE_CYLINDER, RB_SHAPE_CONE)) {
- /* take radius as largest x/y dimension, and height as z-dimension */
- radius = MAX2(size[0], size[1]);
- height = size[2];
- }
- else if (rbo->shape == RB_SHAPE_SPHERE) {
- /* take radius to the largest dimension to try and encompass everything */
- radius = MAX3(size[0], size[1], size[2]);
- }
-
- /* create new shape */
- switch (rbo->shape) {
- case RB_SHAPE_BOX:
- new_shape = RB_shape_new_box(size[0], size[1], size[2]);
- break;
-
- case RB_SHAPE_SPHERE:
- new_shape = RB_shape_new_sphere(radius);
- break;
-
- case RB_SHAPE_CAPSULE:
- capsule_height = (height - radius) * 2.0f;
- new_shape = RB_shape_new_capsule(radius, (capsule_height > 0.0f) ? capsule_height : 0.0f);
- break;
- case RB_SHAPE_CYLINDER:
- new_shape = RB_shape_new_cylinder(radius, height);
- break;
- case RB_SHAPE_CONE:
- new_shape = RB_shape_new_cone(radius, height * 2.0f);
- break;
-
- case RB_SHAPE_CONVEXH:
- /* try to emged collision margin */
- has_volume = (MIN3(size[0], size[1], size[2]) > 0.0f);
-
- if (!(rbo->flag & RBO_FLAG_USE_MARGIN) && has_volume)
- hull_margin = 0.04f;
- new_shape = rigidbody_get_shape_convexhull_from_mesh(ob, hull_margin, &can_embed);
- if (!(rbo->flag & RBO_FLAG_USE_MARGIN))
- rbo->margin = (can_embed && has_volume) ? 0.04f : 0.0f; /* RB_TODO ideally we shouldn't directly change the margin here */
- break;
- case RB_SHAPE_TRIMESH:
- new_shape = rigidbody_get_shape_trimesh_from_mesh(ob);
- break;
- }
- /* use box shape if we can't fall back to old shape */
- if (new_shape == NULL && rbo->shared->physics_shape == NULL) {
- new_shape = RB_shape_new_box(size[0], size[1], size[2]);
- }
- /* assign new collision shape if creation was successful */
- if (new_shape) {
- if (rbo->shared->physics_shape) {
- RB_shape_delete(rbo->shared->physics_shape);
- }
- rbo->shared->physics_shape = new_shape;
- RB_shape_set_margin(rbo->shared->physics_shape, RBO_GET_MARGIN(rbo));
- }
+ RigidBodyOb *rbo = ob->rigidbody_object;
+ rbCollisionShape *new_shape = NULL;
+ BoundBox *bb = NULL;
+ float size[3] = {1.0f, 1.0f, 1.0f};
+ float radius = 1.0f;
+ float height = 1.0f;
+ float capsule_height;
+ float hull_margin = 0.0f;
+ bool can_embed = true;
+ bool has_volume;
+
+ /* sanity check */
+ if (rbo == NULL)
+ return;
+
+ /* don't create a new shape if we already have one and don't want to rebuild it */
+ if (rbo->shared->physics_shape && !rebuild)
+ return;
+
+ /* if automatically determining dimensions, use the Object's boundbox
+ * - assume that all quadrics are standing upright on local z-axis
+ * - assume even distribution of mass around the Object's pivot
+ * (i.e. Object pivot is centralized in boundbox)
+ */
+ // XXX: all dimensions are auto-determined now... later can add stored settings for this
+ /* get object dimensions without scaling */
+ bb = BKE_object_boundbox_get(ob);
+ if (bb) {
+ size[0] = (bb->vec[4][0] - bb->vec[0][0]);
+ size[1] = (bb->vec[2][1] - bb->vec[0][1]);
+ size[2] = (bb->vec[1][2] - bb->vec[0][2]);
+ }
+ mul_v3_fl(size, 0.5f);
+
+ if (ELEM(rbo->shape, RB_SHAPE_CAPSULE, RB_SHAPE_CYLINDER, RB_SHAPE_CONE)) {
+ /* take radius as largest x/y dimension, and height as z-dimension */
+ radius = MAX2(size[0], size[1]);
+ height = size[2];
+ }
+ else if (rbo->shape == RB_SHAPE_SPHERE) {
+ /* take radius to the largest dimension to try and encompass everything */
+ radius = MAX3(size[0], size[1], size[2]);
+ }
+
+ /* create new shape */
+ switch (rbo->shape) {
+ case RB_SHAPE_BOX:
+ new_shape = RB_shape_new_box(size[0], size[1], size[2]);
+ break;
+
+ case RB_SHAPE_SPHERE:
+ new_shape = RB_shape_new_sphere(radius);
+ break;
+
+ case RB_SHAPE_CAPSULE:
+ capsule_height = (height - radius) * 2.0f;
+ new_shape = RB_shape_new_capsule(radius, (capsule_height > 0.0f) ? capsule_height : 0.0f);
+ break;
+ case RB_SHAPE_CYLINDER:
+ new_shape = RB_shape_new_cylinder(radius, height);
+ break;
+ case RB_SHAPE_CONE:
+ new_shape = RB_shape_new_cone(radius, height * 2.0f);
+ break;
+
+ case RB_SHAPE_CONVEXH:
+ /* try to emged collision margin */
+ has_volume = (MIN3(size[0], size[1], size[2]) > 0.0f);
+
+ if (!(rbo->flag & RBO_FLAG_USE_MARGIN) && has_volume)
+ hull_margin = 0.04f;
+ new_shape = rigidbody_get_shape_convexhull_from_mesh(ob, hull_margin, &can_embed);
+ if (!(rbo->flag & RBO_FLAG_USE_MARGIN))
+ rbo->margin = (can_embed && has_volume) ?
+ 0.04f :
+ 0.0f; /* RB_TODO ideally we shouldn't directly change the margin here */
+ break;
+ case RB_SHAPE_TRIMESH:
+ new_shape = rigidbody_get_shape_trimesh_from_mesh(ob);
+ break;
+ }
+ /* use box shape if we can't fall back to old shape */
+ if (new_shape == NULL && rbo->shared->physics_shape == NULL) {
+ new_shape = RB_shape_new_box(size[0], size[1], size[2]);
+ }
+ /* assign new collision shape if creation was successful */
+ if (new_shape) {
+ if (rbo->shared->physics_shape) {
+ RB_shape_delete(rbo->shared->physics_shape);
+ }
+ rbo->shared->physics_shape = new_shape;
+ RB_shape_set_margin(rbo->shared->physics_shape, RBO_GET_MARGIN(rbo));
+ }
}
/* --------------------- */
@@ -489,152 +504,151 @@ static void rigidbody_validate_sim_shape(Object *ob, bool rebuild)
// TODO: allow a parameter to specify method used to calculate this?
void BKE_rigidbody_calc_volume(Object *ob, float *r_vol)
{
- RigidBodyOb *rbo = ob->rigidbody_object;
-
- float size[3] = {1.0f, 1.0f, 1.0f};
- float radius = 1.0f;
- float height = 1.0f;
-
- float volume = 0.0f;
-
- /* if automatically determining dimensions, use the Object's boundbox
- * - assume that all quadrics are standing upright on local z-axis
- * - assume even distribution of mass around the Object's pivot
- * (i.e. Object pivot is centralized in boundbox)
- * - boundbox gives full width
- */
- // XXX: all dimensions are auto-determined now... later can add stored settings for this
- BKE_object_dimensions_get(ob, size);
-
- if (ELEM(rbo->shape, RB_SHAPE_CAPSULE, RB_SHAPE_CYLINDER, RB_SHAPE_CONE)) {
- /* take radius as largest x/y dimension, and height as z-dimension */
- radius = MAX2(size[0], size[1]) * 0.5f;
- height = size[2];
- }
- else if (rbo->shape == RB_SHAPE_SPHERE) {
- /* take radius to the largest dimension to try and encompass everything */
- radius = max_fff(size[0], size[1], size[2]) * 0.5f;
- }
-
- /* calculate volume as appropriate */
- switch (rbo->shape) {
- case RB_SHAPE_BOX:
- volume = size[0] * size[1] * size[2];
- break;
-
- case RB_SHAPE_SPHERE:
- volume = 4.0f / 3.0f * (float)M_PI * radius * radius * radius;
- break;
-
- /* for now, assume that capsule is close enough to a cylinder... */
- case RB_SHAPE_CAPSULE:
- case RB_SHAPE_CYLINDER:
- volume = (float)M_PI * radius * radius * height;
- break;
-
- case RB_SHAPE_CONE:
- volume = (float)M_PI / 3.0f * radius * radius * height;
- break;
-
- case RB_SHAPE_CONVEXH:
- case RB_SHAPE_TRIMESH:
- {
- if (ob->type == OB_MESH) {
- Mesh *mesh = rigidbody_get_mesh(ob);
- MVert *mvert;
- const MLoopTri *lt = NULL;
- int totvert, tottri = 0;
- const MLoop *mloop = NULL;
-
- /* ensure mesh validity, then grab data */
- if (mesh == NULL)
- return;
-
- mvert = mesh->mvert;
- totvert = mesh->totvert;
- lt = BKE_mesh_runtime_looptri_ensure(mesh);
- tottri = mesh->runtime.looptris.len;
- mloop = mesh->mloop;
-
- if (totvert > 0 && tottri > 0) {
- BKE_mesh_calc_volume(mvert, totvert, lt, tottri, mloop, &volume, NULL);
- }
- }
- else {
- /* rough estimate from boundbox as fallback */
- /* XXX could implement other types of geometry here (curves, etc.) */
- volume = size[0] * size[1] * size[2];
- }
- break;
- }
- }
-
- /* return the volume calculated */
- if (r_vol) *r_vol = volume;
+ RigidBodyOb *rbo = ob->rigidbody_object;
+
+ float size[3] = {1.0f, 1.0f, 1.0f};
+ float radius = 1.0f;
+ float height = 1.0f;
+
+ float volume = 0.0f;
+
+ /* if automatically determining dimensions, use the Object's boundbox
+ * - assume that all quadrics are standing upright on local z-axis
+ * - assume even distribution of mass around the Object's pivot
+ * (i.e. Object pivot is centralized in boundbox)
+ * - boundbox gives full width
+ */
+ // XXX: all dimensions are auto-determined now... later can add stored settings for this
+ BKE_object_dimensions_get(ob, size);
+
+ if (ELEM(rbo->shape, RB_SHAPE_CAPSULE, RB_SHAPE_CYLINDER, RB_SHAPE_CONE)) {
+ /* take radius as largest x/y dimension, and height as z-dimension */
+ radius = MAX2(size[0], size[1]) * 0.5f;
+ height = size[2];
+ }
+ else if (rbo->shape == RB_SHAPE_SPHERE) {
+ /* take radius to the largest dimension to try and encompass everything */
+ radius = max_fff(size[0], size[1], size[2]) * 0.5f;
+ }
+
+ /* calculate volume as appropriate */
+ switch (rbo->shape) {
+ case RB_SHAPE_BOX:
+ volume = size[0] * size[1] * size[2];
+ break;
+
+ case RB_SHAPE_SPHERE:
+ volume = 4.0f / 3.0f * (float)M_PI * radius * radius * radius;
+ break;
+
+ /* for now, assume that capsule is close enough to a cylinder... */
+ case RB_SHAPE_CAPSULE:
+ case RB_SHAPE_CYLINDER:
+ volume = (float)M_PI * radius * radius * height;
+ break;
+
+ case RB_SHAPE_CONE:
+ volume = (float)M_PI / 3.0f * radius * radius * height;
+ break;
+
+ case RB_SHAPE_CONVEXH:
+ case RB_SHAPE_TRIMESH: {
+ if (ob->type == OB_MESH) {
+ Mesh *mesh = rigidbody_get_mesh(ob);
+ MVert *mvert;
+ const MLoopTri *lt = NULL;
+ int totvert, tottri = 0;
+ const MLoop *mloop = NULL;
+
+ /* ensure mesh validity, then grab data */
+ if (mesh == NULL)
+ return;
+
+ mvert = mesh->mvert;
+ totvert = mesh->totvert;
+ lt = BKE_mesh_runtime_looptri_ensure(mesh);
+ tottri = mesh->runtime.looptris.len;
+ mloop = mesh->mloop;
+
+ if (totvert > 0 && tottri > 0) {
+ BKE_mesh_calc_volume(mvert, totvert, lt, tottri, mloop, &volume, NULL);
+ }
+ }
+ else {
+ /* rough estimate from boundbox as fallback */
+ /* XXX could implement other types of geometry here (curves, etc.) */
+ volume = size[0] * size[1] * size[2];
+ }
+ break;
+ }
+ }
+
+ /* return the volume calculated */
+ if (r_vol)
+ *r_vol = volume;
}
void BKE_rigidbody_calc_center_of_mass(Object *ob, float r_center[3])
{
- RigidBodyOb *rbo = ob->rigidbody_object;
-
- float size[3] = {1.0f, 1.0f, 1.0f};
- float height = 1.0f;
-
- zero_v3(r_center);
-
- /* if automatically determining dimensions, use the Object's boundbox
- * - assume that all quadrics are standing upright on local z-axis
- * - assume even distribution of mass around the Object's pivot
- * (i.e. Object pivot is centralized in boundbox)
- * - boundbox gives full width
- */
- // XXX: all dimensions are auto-determined now... later can add stored settings for this
- BKE_object_dimensions_get(ob, size);
-
- /* calculate volume as appropriate */
- switch (rbo->shape) {
- case RB_SHAPE_BOX:
- case RB_SHAPE_SPHERE:
- case RB_SHAPE_CAPSULE:
- case RB_SHAPE_CYLINDER:
- break;
-
- case RB_SHAPE_CONE:
- /* take radius as largest x/y dimension, and height as z-dimension */
- height = size[2];
- /* cone is geometrically centered on the median,
- * center of mass is 1/4 up from the base
- */
- r_center[2] = -0.25f * height;
- break;
-
- case RB_SHAPE_CONVEXH:
- case RB_SHAPE_TRIMESH:
- {
- if (ob->type == OB_MESH) {
- Mesh *mesh = rigidbody_get_mesh(ob);
- MVert *mvert;
- const MLoopTri *looptri;
- int totvert, tottri;
- const MLoop *mloop;
-
- /* ensure mesh validity, then grab data */
- if (mesh == NULL)
- return;
-
- mvert = mesh->mvert;
- totvert = mesh->totvert;
- looptri = BKE_mesh_runtime_looptri_ensure(mesh);
- tottri = mesh->runtime.looptris.len;
- mloop = mesh->mloop;
-
- if (totvert > 0 && tottri > 0) {
- BKE_mesh_calc_volume(mvert, totvert, looptri, tottri, mloop, NULL, r_center);
- }
- }
- break;
- }
- }
+ RigidBodyOb *rbo = ob->rigidbody_object;
+
+ float size[3] = {1.0f, 1.0f, 1.0f};
+ float height = 1.0f;
+
+ zero_v3(r_center);
+
+ /* if automatically determining dimensions, use the Object's boundbox
+ * - assume that all quadrics are standing upright on local z-axis
+ * - assume even distribution of mass around the Object's pivot
+ * (i.e. Object pivot is centralized in boundbox)
+ * - boundbox gives full width
+ */
+ // XXX: all dimensions are auto-determined now... later can add stored settings for this
+ BKE_object_dimensions_get(ob, size);
+
+ /* calculate volume as appropriate */
+ switch (rbo->shape) {
+ case RB_SHAPE_BOX:
+ case RB_SHAPE_SPHERE:
+ case RB_SHAPE_CAPSULE:
+ case RB_SHAPE_CYLINDER:
+ break;
+
+ case RB_SHAPE_CONE:
+ /* take radius as largest x/y dimension, and height as z-dimension */
+ height = size[2];
+ /* cone is geometrically centered on the median,
+ * center of mass is 1/4 up from the base
+ */
+ r_center[2] = -0.25f * height;
+ break;
+
+ case RB_SHAPE_CONVEXH:
+ case RB_SHAPE_TRIMESH: {
+ if (ob->type == OB_MESH) {
+ Mesh *mesh = rigidbody_get_mesh(ob);
+ MVert *mvert;
+ const MLoopTri *looptri;
+ int totvert, tottri;
+ const MLoop *mloop;
+
+ /* ensure mesh validity, then grab data */
+ if (mesh == NULL)
+ return;
+
+ mvert = mesh->mvert;
+ totvert = mesh->totvert;
+ looptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ tottri = mesh->runtime.looptris.len;
+ mloop = mesh->mloop;
+
+ if (totvert > 0 && tottri > 0) {
+ BKE_mesh_calc_volume(mvert, totvert, looptri, tottri, mloop, NULL, r_center);
+ }
+ }
+ break;
+ }
+ }
}
/* --------------------- */
@@ -646,125 +660,134 @@ void BKE_rigidbody_calc_center_of_mass(Object *ob, float r_center[3])
*/
static void rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, bool rebuild)
{
- RigidBodyOb *rbo = (ob) ? ob->rigidbody_object : NULL;
- float loc[3];
- float rot[4];
-
- /* sanity checks:
- * - object doesn't have RigidBody info already: then why is it here?
- */
- if (rbo == NULL)
- return;
-
- /* make sure collision shape exists */
- /* FIXME we shouldn't always have to rebuild collision shapes when rebuilding objects, but it's needed for constraints to update correctly */
- if (rbo->shared->physics_shape == NULL || rebuild)
- rigidbody_validate_sim_shape(ob, true);
-
- if (rbo->shared->physics_object) {
- RB_dworld_remove_body(rbw->shared->physics_world, rbo->shared->physics_object);
- }
- if (!rbo->shared->physics_object || rebuild) {
- /* remove rigid body if it already exists before creating a new one */
- if (rbo->shared->physics_object) {
- RB_body_delete(rbo->shared->physics_object);
- }
-
- mat4_to_loc_quat(loc, rot, ob->obmat);
-
- rbo->shared->physics_object = RB_body_new(rbo->shared->physics_shape, loc, rot);
-
- RB_body_set_friction(rbo->shared->physics_object, rbo->friction);
- RB_body_set_restitution(rbo->shared->physics_object, rbo->restitution);
-
- RB_body_set_damping(rbo->shared->physics_object, rbo->lin_damping, rbo->ang_damping);
- RB_body_set_sleep_thresh(rbo->shared->physics_object, rbo->lin_sleep_thresh, rbo->ang_sleep_thresh);
- RB_body_set_activation_state(rbo->shared->physics_object, rbo->flag & RBO_FLAG_USE_DEACTIVATION);
-
- if (rbo->type == RBO_TYPE_PASSIVE || rbo->flag & RBO_FLAG_START_DEACTIVATED)
- RB_body_deactivate(rbo->shared->physics_object);
-
-
- RB_body_set_linear_factor(rbo->shared->physics_object,
- (ob->protectflag & OB_LOCK_LOCX) == 0,
- (ob->protectflag & OB_LOCK_LOCY) == 0,
- (ob->protectflag & OB_LOCK_LOCZ) == 0);
- RB_body_set_angular_factor(rbo->shared->physics_object,
- (ob->protectflag & OB_LOCK_ROTX) == 0,
- (ob->protectflag & OB_LOCK_ROTY) == 0,
- (ob->protectflag & OB_LOCK_ROTZ) == 0);
-
- RB_body_set_mass(rbo->shared->physics_object, RBO_GET_MASS(rbo));
- RB_body_set_kinematic_state(rbo->shared->physics_object, rbo->flag & RBO_FLAG_KINEMATIC || rbo->flag & RBO_FLAG_DISABLED);
- }
-
- if (rbw && rbw->shared->physics_world)
- RB_dworld_add_body(rbw->shared->physics_world, rbo->shared->physics_object, rbo->col_groups);
+ RigidBodyOb *rbo = (ob) ? ob->rigidbody_object : NULL;
+ float loc[3];
+ float rot[4];
+
+ /* sanity checks:
+ * - object doesn't have RigidBody info already: then why is it here?
+ */
+ if (rbo == NULL)
+ return;
+
+ /* make sure collision shape exists */
+ /* FIXME we shouldn't always have to rebuild collision shapes when rebuilding objects, but it's needed for constraints to update correctly */
+ if (rbo->shared->physics_shape == NULL || rebuild)
+ rigidbody_validate_sim_shape(ob, true);
+
+ if (rbo->shared->physics_object) {
+ RB_dworld_remove_body(rbw->shared->physics_world, rbo->shared->physics_object);
+ }
+ if (!rbo->shared->physics_object || rebuild) {
+ /* remove rigid body if it already exists before creating a new one */
+ if (rbo->shared->physics_object) {
+ RB_body_delete(rbo->shared->physics_object);
+ }
+
+ mat4_to_loc_quat(loc, rot, ob->obmat);
+
+ rbo->shared->physics_object = RB_body_new(rbo->shared->physics_shape, loc, rot);
+
+ RB_body_set_friction(rbo->shared->physics_object, rbo->friction);
+ RB_body_set_restitution(rbo->shared->physics_object, rbo->restitution);
+
+ RB_body_set_damping(rbo->shared->physics_object, rbo->lin_damping, rbo->ang_damping);
+ RB_body_set_sleep_thresh(
+ rbo->shared->physics_object, rbo->lin_sleep_thresh, rbo->ang_sleep_thresh);
+ RB_body_set_activation_state(rbo->shared->physics_object,
+ rbo->flag & RBO_FLAG_USE_DEACTIVATION);
+
+ if (rbo->type == RBO_TYPE_PASSIVE || rbo->flag & RBO_FLAG_START_DEACTIVATED)
+ RB_body_deactivate(rbo->shared->physics_object);
+
+ RB_body_set_linear_factor(rbo->shared->physics_object,
+ (ob->protectflag & OB_LOCK_LOCX) == 0,
+ (ob->protectflag & OB_LOCK_LOCY) == 0,
+ (ob->protectflag & OB_LOCK_LOCZ) == 0);
+ RB_body_set_angular_factor(rbo->shared->physics_object,
+ (ob->protectflag & OB_LOCK_ROTX) == 0,
+ (ob->protectflag & OB_LOCK_ROTY) == 0,
+ (ob->protectflag & OB_LOCK_ROTZ) == 0);
+
+ RB_body_set_mass(rbo->shared->physics_object, RBO_GET_MASS(rbo));
+ RB_body_set_kinematic_state(rbo->shared->physics_object,
+ rbo->flag & RBO_FLAG_KINEMATIC || rbo->flag & RBO_FLAG_DISABLED);
+ }
+
+ if (rbw && rbw->shared->physics_world)
+ RB_dworld_add_body(rbw->shared->physics_world, rbo->shared->physics_object, rbo->col_groups);
}
/* --------------------- */
-static void rigidbody_constraint_init_spring(
- RigidBodyCon *rbc, void (*set_spring)(rbConstraint *, int, int),
- void (*set_stiffness)(rbConstraint *, int, float), void (*set_damping)(rbConstraint *, int, float))
+static void rigidbody_constraint_init_spring(RigidBodyCon *rbc,
+ void (*set_spring)(rbConstraint *, int, int),
+ void (*set_stiffness)(rbConstraint *, int, float),
+ void (*set_damping)(rbConstraint *, int, float))
{
- set_spring(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->flag & RBC_FLAG_USE_SPRING_X);
- set_stiffness(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->spring_stiffness_x);
- set_damping(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->spring_damping_x);
+ set_spring(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->flag & RBC_FLAG_USE_SPRING_X);
+ set_stiffness(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->spring_stiffness_x);
+ set_damping(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->spring_damping_x);
- set_spring(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->flag & RBC_FLAG_USE_SPRING_Y);
- set_stiffness(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->spring_stiffness_y);
- set_damping(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->spring_damping_y);
+ set_spring(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->flag & RBC_FLAG_USE_SPRING_Y);
+ set_stiffness(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->spring_stiffness_y);
+ set_damping(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->spring_damping_y);
- set_spring(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->flag & RBC_FLAG_USE_SPRING_Z);
- set_stiffness(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->spring_stiffness_z);
- set_damping(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->spring_damping_z);
+ set_spring(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->flag & RBC_FLAG_USE_SPRING_Z);
+ set_stiffness(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->spring_stiffness_z);
+ set_damping(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->spring_damping_z);
- set_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->flag & RBC_FLAG_USE_SPRING_ANG_X);
- set_stiffness(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->spring_stiffness_ang_x);
- set_damping(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->spring_damping_ang_x);
+ set_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->flag & RBC_FLAG_USE_SPRING_ANG_X);
+ set_stiffness(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->spring_stiffness_ang_x);
+ set_damping(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->spring_damping_ang_x);
- set_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->flag & RBC_FLAG_USE_SPRING_ANG_Y);
- set_stiffness(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->spring_stiffness_ang_y);
- set_damping(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->spring_damping_ang_y);
+ set_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->flag & RBC_FLAG_USE_SPRING_ANG_Y);
+ set_stiffness(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->spring_stiffness_ang_y);
+ set_damping(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->spring_damping_ang_y);
- set_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->flag & RBC_FLAG_USE_SPRING_ANG_Z);
- set_stiffness(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->spring_stiffness_ang_z);
- set_damping(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->spring_damping_ang_z);
+ set_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->flag & RBC_FLAG_USE_SPRING_ANG_Z);
+ set_stiffness(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->spring_stiffness_ang_z);
+ set_damping(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->spring_damping_ang_z);
}
-static void rigidbody_constraint_set_limits(
- RigidBodyCon *rbc, void (*set_limits)(rbConstraint *, int, float, float))
+static void rigidbody_constraint_set_limits(RigidBodyCon *rbc,
+ void (*set_limits)(rbConstraint *, int, float, float))
{
- if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_X)
- set_limits(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->limit_lin_x_lower, rbc->limit_lin_x_upper);
- else
- set_limits(rbc->physics_constraint, RB_LIMIT_LIN_X, 0.0f, -1.0f);
-
- if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_Y)
- set_limits(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->limit_lin_y_lower, rbc->limit_lin_y_upper);
- else
- set_limits(rbc->physics_constraint, RB_LIMIT_LIN_Y, 0.0f, -1.0f);
-
- if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_Z)
- set_limits(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->limit_lin_z_lower, rbc->limit_lin_z_upper);
- else
- set_limits(rbc->physics_constraint, RB_LIMIT_LIN_Z, 0.0f, -1.0f);
-
- if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_X)
- set_limits(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->limit_ang_x_lower, rbc->limit_ang_x_upper);
- else
- set_limits(rbc->physics_constraint, RB_LIMIT_ANG_X, 0.0f, -1.0f);
-
- if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_Y)
- set_limits(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->limit_ang_y_lower, rbc->limit_ang_y_upper);
- else
- set_limits(rbc->physics_constraint, RB_LIMIT_ANG_Y, 0.0f, -1.0f);
-
- if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_Z)
- set_limits(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->limit_ang_z_lower, rbc->limit_ang_z_upper);
- else
- set_limits(rbc->physics_constraint, RB_LIMIT_ANG_Z, 0.0f, -1.0f);
+ if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_X)
+ set_limits(
+ rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->limit_lin_x_lower, rbc->limit_lin_x_upper);
+ else
+ set_limits(rbc->physics_constraint, RB_LIMIT_LIN_X, 0.0f, -1.0f);
+
+ if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_Y)
+ set_limits(
+ rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->limit_lin_y_lower, rbc->limit_lin_y_upper);
+ else
+ set_limits(rbc->physics_constraint, RB_LIMIT_LIN_Y, 0.0f, -1.0f);
+
+ if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_Z)
+ set_limits(
+ rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->limit_lin_z_lower, rbc->limit_lin_z_upper);
+ else
+ set_limits(rbc->physics_constraint, RB_LIMIT_LIN_Z, 0.0f, -1.0f);
+
+ if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_X)
+ set_limits(
+ rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->limit_ang_x_lower, rbc->limit_ang_x_upper);
+ else
+ set_limits(rbc->physics_constraint, RB_LIMIT_ANG_X, 0.0f, -1.0f);
+
+ if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_Y)
+ set_limits(
+ rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->limit_ang_y_lower, rbc->limit_ang_y_upper);
+ else
+ set_limits(rbc->physics_constraint, RB_LIMIT_ANG_Y, 0.0f, -1.0f);
+
+ if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_Z)
+ set_limits(
+ rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->limit_ang_z_lower, rbc->limit_ang_z_upper);
+ else
+ set_limits(rbc->physics_constraint, RB_LIMIT_ANG_Z, 0.0f, -1.0f);
}
/**
@@ -774,143 +797,159 @@ static void rigidbody_constraint_set_limits(
*/
static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, bool rebuild)
{
- RigidBodyCon *rbc = (ob) ? ob->rigidbody_constraint : NULL;
- float loc[3];
- float rot[4];
- float lin_lower;
- float lin_upper;
- float ang_lower;
- float ang_upper;
-
- /* sanity checks:
- * - object should have a rigid body constraint
- * - rigid body constraint should have at least one constrained object
- */
- if (rbc == NULL) {
- return;
- }
-
- if (ELEM(NULL, rbc->ob1, rbc->ob1->rigidbody_object, rbc->ob2, rbc->ob2->rigidbody_object)) {
- if (rbc->physics_constraint) {
- RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint);
- RB_constraint_delete(rbc->physics_constraint);
- rbc->physics_constraint = NULL;
- }
- return;
- }
-
- if (rbc->physics_constraint && rebuild == false) {
- RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint);
- }
- if (rbc->physics_constraint == NULL || rebuild) {
- rbRigidBody *rb1 = rbc->ob1->rigidbody_object->shared->physics_object;
- rbRigidBody *rb2 = rbc->ob2->rigidbody_object->shared->physics_object;
-
- /* remove constraint if it already exists before creating a new one */
- if (rbc->physics_constraint) {
- RB_constraint_delete(rbc->physics_constraint);
- rbc->physics_constraint = NULL;
- }
-
- mat4_to_loc_quat(loc, rot, ob->obmat);
-
- if (rb1 && rb2) {
- switch (rbc->type) {
- case RBC_TYPE_POINT:
- rbc->physics_constraint = RB_constraint_new_point(loc, rb1, rb2);
- break;
- case RBC_TYPE_FIXED:
- rbc->physics_constraint = RB_constraint_new_fixed(loc, rot, rb1, rb2);
- break;
- case RBC_TYPE_HINGE:
- rbc->physics_constraint = RB_constraint_new_hinge(loc, rot, rb1, rb2);
- if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_Z) {
- RB_constraint_set_limits_hinge(rbc->physics_constraint, rbc->limit_ang_z_lower, rbc->limit_ang_z_upper);
- }
- else
- RB_constraint_set_limits_hinge(rbc->physics_constraint, 0.0f, -1.0f);
- break;
- case RBC_TYPE_SLIDER:
- rbc->physics_constraint = RB_constraint_new_slider(loc, rot, rb1, rb2);
- if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_X)
- RB_constraint_set_limits_slider(rbc->physics_constraint, rbc->limit_lin_x_lower, rbc->limit_lin_x_upper);
- else
- RB_constraint_set_limits_slider(rbc->physics_constraint, 0.0f, -1.0f);
- break;
- case RBC_TYPE_PISTON:
- rbc->physics_constraint = RB_constraint_new_piston(loc, rot, rb1, rb2);
- if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_X) {
- lin_lower = rbc->limit_lin_x_lower;
- lin_upper = rbc->limit_lin_x_upper;
- }
- else {
- lin_lower = 0.0f;
- lin_upper = -1.0f;
- }
- if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_X) {
- ang_lower = rbc->limit_ang_x_lower;
- ang_upper = rbc->limit_ang_x_upper;
- }
- else {
- ang_lower = 0.0f;
- ang_upper = -1.0f;
- }
- RB_constraint_set_limits_piston(rbc->physics_constraint, lin_lower, lin_upper, ang_lower, ang_upper);
- break;
- case RBC_TYPE_6DOF_SPRING:
- if (rbc->spring_type == RBC_SPRING_TYPE2) {
- rbc->physics_constraint = RB_constraint_new_6dof_spring2(loc, rot, rb1, rb2);
-
- rigidbody_constraint_init_spring(rbc, RB_constraint_set_spring_6dof_spring2, RB_constraint_set_stiffness_6dof_spring2, RB_constraint_set_damping_6dof_spring2);
-
- RB_constraint_set_equilibrium_6dof_spring2(rbc->physics_constraint);
-
- rigidbody_constraint_set_limits(rbc, RB_constraint_set_limits_6dof_spring2);
- }
- else {
- rbc->physics_constraint = RB_constraint_new_6dof_spring(loc, rot, rb1, rb2);
-
- rigidbody_constraint_init_spring(rbc, RB_constraint_set_spring_6dof_spring, RB_constraint_set_stiffness_6dof_spring, RB_constraint_set_damping_6dof_spring);
-
- RB_constraint_set_equilibrium_6dof_spring(rbc->physics_constraint);
-
- rigidbody_constraint_set_limits(rbc, RB_constraint_set_limits_6dof);
- }
- break;
- case RBC_TYPE_6DOF:
- rbc->physics_constraint = RB_constraint_new_6dof(loc, rot, rb1, rb2);
-
- rigidbody_constraint_set_limits(rbc, RB_constraint_set_limits_6dof);
- break;
- case RBC_TYPE_MOTOR:
- rbc->physics_constraint = RB_constraint_new_motor(loc, rot, rb1, rb2);
-
- RB_constraint_set_enable_motor(rbc->physics_constraint, rbc->flag & RBC_FLAG_USE_MOTOR_LIN, rbc->flag & RBC_FLAG_USE_MOTOR_ANG);
- RB_constraint_set_max_impulse_motor(rbc->physics_constraint, rbc->motor_lin_max_impulse, rbc->motor_ang_max_impulse);
- RB_constraint_set_target_velocity_motor(rbc->physics_constraint, rbc->motor_lin_target_velocity, rbc->motor_ang_target_velocity);
- break;
- }
- }
- else { /* can't create constraint without both rigid bodies */
- return;
- }
-
- RB_constraint_set_enabled(rbc->physics_constraint, rbc->flag & RBC_FLAG_ENABLED);
-
- if (rbc->flag & RBC_FLAG_USE_BREAKING)
- RB_constraint_set_breaking_threshold(rbc->physics_constraint, rbc->breaking_threshold);
- else
- RB_constraint_set_breaking_threshold(rbc->physics_constraint, FLT_MAX);
-
- if (rbc->flag & RBC_FLAG_OVERRIDE_SOLVER_ITERATIONS)
- RB_constraint_set_solver_iterations(rbc->physics_constraint, rbc->num_solver_iterations);
- else
- RB_constraint_set_solver_iterations(rbc->physics_constraint, -1);
- }
-
- if (rbw && rbw->shared->physics_world && rbc->physics_constraint) {
- RB_dworld_add_constraint(rbw->shared->physics_world, rbc->physics_constraint, rbc->flag & RBC_FLAG_DISABLE_COLLISIONS);
- }
+ RigidBodyCon *rbc = (ob) ? ob->rigidbody_constraint : NULL;
+ float loc[3];
+ float rot[4];
+ float lin_lower;
+ float lin_upper;
+ float ang_lower;
+ float ang_upper;
+
+ /* sanity checks:
+ * - object should have a rigid body constraint
+ * - rigid body constraint should have at least one constrained object
+ */
+ if (rbc == NULL) {
+ return;
+ }
+
+ if (ELEM(NULL, rbc->ob1, rbc->ob1->rigidbody_object, rbc->ob2, rbc->ob2->rigidbody_object)) {
+ if (rbc->physics_constraint) {
+ RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint);
+ RB_constraint_delete(rbc->physics_constraint);
+ rbc->physics_constraint = NULL;
+ }
+ return;
+ }
+
+ if (rbc->physics_constraint && rebuild == false) {
+ RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint);
+ }
+ if (rbc->physics_constraint == NULL || rebuild) {
+ rbRigidBody *rb1 = rbc->ob1->rigidbody_object->shared->physics_object;
+ rbRigidBody *rb2 = rbc->ob2->rigidbody_object->shared->physics_object;
+
+ /* remove constraint if it already exists before creating a new one */
+ if (rbc->physics_constraint) {
+ RB_constraint_delete(rbc->physics_constraint);
+ rbc->physics_constraint = NULL;
+ }
+
+ mat4_to_loc_quat(loc, rot, ob->obmat);
+
+ if (rb1 && rb2) {
+ switch (rbc->type) {
+ case RBC_TYPE_POINT:
+ rbc->physics_constraint = RB_constraint_new_point(loc, rb1, rb2);
+ break;
+ case RBC_TYPE_FIXED:
+ rbc->physics_constraint = RB_constraint_new_fixed(loc, rot, rb1, rb2);
+ break;
+ case RBC_TYPE_HINGE:
+ rbc->physics_constraint = RB_constraint_new_hinge(loc, rot, rb1, rb2);
+ if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_Z) {
+ RB_constraint_set_limits_hinge(
+ rbc->physics_constraint, rbc->limit_ang_z_lower, rbc->limit_ang_z_upper);
+ }
+ else
+ RB_constraint_set_limits_hinge(rbc->physics_constraint, 0.0f, -1.0f);
+ break;
+ case RBC_TYPE_SLIDER:
+ rbc->physics_constraint = RB_constraint_new_slider(loc, rot, rb1, rb2);
+ if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_X)
+ RB_constraint_set_limits_slider(
+ rbc->physics_constraint, rbc->limit_lin_x_lower, rbc->limit_lin_x_upper);
+ else
+ RB_constraint_set_limits_slider(rbc->physics_constraint, 0.0f, -1.0f);
+ break;
+ case RBC_TYPE_PISTON:
+ rbc->physics_constraint = RB_constraint_new_piston(loc, rot, rb1, rb2);
+ if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_X) {
+ lin_lower = rbc->limit_lin_x_lower;
+ lin_upper = rbc->limit_lin_x_upper;
+ }
+ else {
+ lin_lower = 0.0f;
+ lin_upper = -1.0f;
+ }
+ if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_X) {
+ ang_lower = rbc->limit_ang_x_lower;
+ ang_upper = rbc->limit_ang_x_upper;
+ }
+ else {
+ ang_lower = 0.0f;
+ ang_upper = -1.0f;
+ }
+ RB_constraint_set_limits_piston(
+ rbc->physics_constraint, lin_lower, lin_upper, ang_lower, ang_upper);
+ break;
+ case RBC_TYPE_6DOF_SPRING:
+ if (rbc->spring_type == RBC_SPRING_TYPE2) {
+ rbc->physics_constraint = RB_constraint_new_6dof_spring2(loc, rot, rb1, rb2);
+
+ rigidbody_constraint_init_spring(rbc,
+ RB_constraint_set_spring_6dof_spring2,
+ RB_constraint_set_stiffness_6dof_spring2,
+ RB_constraint_set_damping_6dof_spring2);
+
+ RB_constraint_set_equilibrium_6dof_spring2(rbc->physics_constraint);
+
+ rigidbody_constraint_set_limits(rbc, RB_constraint_set_limits_6dof_spring2);
+ }
+ else {
+ rbc->physics_constraint = RB_constraint_new_6dof_spring(loc, rot, rb1, rb2);
+
+ rigidbody_constraint_init_spring(rbc,
+ RB_constraint_set_spring_6dof_spring,
+ RB_constraint_set_stiffness_6dof_spring,
+ RB_constraint_set_damping_6dof_spring);
+
+ RB_constraint_set_equilibrium_6dof_spring(rbc->physics_constraint);
+
+ rigidbody_constraint_set_limits(rbc, RB_constraint_set_limits_6dof);
+ }
+ break;
+ case RBC_TYPE_6DOF:
+ rbc->physics_constraint = RB_constraint_new_6dof(loc, rot, rb1, rb2);
+
+ rigidbody_constraint_set_limits(rbc, RB_constraint_set_limits_6dof);
+ break;
+ case RBC_TYPE_MOTOR:
+ rbc->physics_constraint = RB_constraint_new_motor(loc, rot, rb1, rb2);
+
+ RB_constraint_set_enable_motor(rbc->physics_constraint,
+ rbc->flag & RBC_FLAG_USE_MOTOR_LIN,
+ rbc->flag & RBC_FLAG_USE_MOTOR_ANG);
+ RB_constraint_set_max_impulse_motor(
+ rbc->physics_constraint, rbc->motor_lin_max_impulse, rbc->motor_ang_max_impulse);
+ RB_constraint_set_target_velocity_motor(rbc->physics_constraint,
+ rbc->motor_lin_target_velocity,
+ rbc->motor_ang_target_velocity);
+ break;
+ }
+ }
+ else { /* can't create constraint without both rigid bodies */
+ return;
+ }
+
+ RB_constraint_set_enabled(rbc->physics_constraint, rbc->flag & RBC_FLAG_ENABLED);
+
+ if (rbc->flag & RBC_FLAG_USE_BREAKING)
+ RB_constraint_set_breaking_threshold(rbc->physics_constraint, rbc->breaking_threshold);
+ else
+ RB_constraint_set_breaking_threshold(rbc->physics_constraint, FLT_MAX);
+
+ if (rbc->flag & RBC_FLAG_OVERRIDE_SOLVER_ITERATIONS)
+ RB_constraint_set_solver_iterations(rbc->physics_constraint, rbc->num_solver_iterations);
+ else
+ RB_constraint_set_solver_iterations(rbc->physics_constraint, -1);
+ }
+
+ if (rbw && rbw->shared->physics_world && rbc->physics_constraint) {
+ RB_dworld_add_constraint(rbw->shared->physics_world,
+ rbc->physics_constraint,
+ rbc->flag & RBC_FLAG_DISABLE_COLLISIONS);
+ }
}
/* --------------------- */
@@ -919,19 +958,19 @@ static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, b
// NOTE: this does NOT update object references that the scene uses, in case those aren't ready yet!
void BKE_rigidbody_validate_sim_world(Scene *scene, RigidBodyWorld *rbw, bool rebuild)
{
- /* sanity checks */
- if (rbw == NULL)
- return;
-
- /* create new sim world */
- if (rebuild || rbw->shared->physics_world == NULL) {
- if (rbw->shared->physics_world)
- RB_dworld_delete(rbw->shared->physics_world);
- rbw->shared->physics_world = RB_dworld_new(scene->physics_settings.gravity);
- }
-
- RB_dworld_set_solver_iterations(rbw->shared->physics_world, rbw->num_solver_iterations);
- RB_dworld_set_split_impulse(rbw->shared->physics_world, rbw->flag & RBW_FLAG_USE_SPLIT_IMPULSE);
+ /* sanity checks */
+ if (rbw == NULL)
+ return;
+
+ /* create new sim world */
+ if (rebuild || rbw->shared->physics_world == NULL) {
+ if (rbw->shared->physics_world)
+ RB_dworld_delete(rbw->shared->physics_world);
+ rbw->shared->physics_world = RB_dworld_new(scene->physics_settings.gravity);
+ }
+
+ RB_dworld_set_solver_iterations(rbw->shared->physics_world, rbw->num_solver_iterations);
+ RB_dworld_set_split_impulse(rbw->shared->physics_world, rbw->flag & RBW_FLAG_USE_SPLIT_IMPULSE);
}
/* ************************************** */
@@ -940,255 +979,255 @@ void BKE_rigidbody_validate_sim_world(Scene *scene, RigidBodyWorld *rbw, bool re
/* Set up RigidBody world */
RigidBodyWorld *BKE_rigidbody_create_world(Scene *scene)
{
- /* try to get whatever RigidBody world that might be representing this already */
- RigidBodyWorld *rbw;
+ /* try to get whatever RigidBody world that might be representing this already */
+ RigidBodyWorld *rbw;
- /* sanity checks
- * - there must be a valid scene to add world to
- * - there mustn't be a sim world using this group already
- */
- if (scene == NULL)
- return NULL;
+ /* sanity checks
+ * - there must be a valid scene to add world to
+ * - there mustn't be a sim world using this group already
+ */
+ if (scene == NULL)
+ return NULL;
- /* create a new sim world */
- rbw = MEM_callocN(sizeof(RigidBodyWorld), "RigidBodyWorld");
- rbw->shared = MEM_callocN(sizeof(*rbw->shared), "RigidBodyWorld_Shared");
+ /* create a new sim world */
+ rbw = MEM_callocN(sizeof(RigidBodyWorld), "RigidBodyWorld");
+ rbw->shared = MEM_callocN(sizeof(*rbw->shared), "RigidBodyWorld_Shared");
- /* set default settings */
- rbw->effector_weights = BKE_effector_add_weights(NULL);
+ /* set default settings */
+ rbw->effector_weights = BKE_effector_add_weights(NULL);
- rbw->ltime = PSFRA;
+ rbw->ltime = PSFRA;
- rbw->time_scale = 1.0f;
+ rbw->time_scale = 1.0f;
- rbw->steps_per_second = 60; /* Bullet default (60 Hz) */
- rbw->num_solver_iterations = 10; /* 10 is bullet default */
+ rbw->steps_per_second = 60; /* Bullet default (60 Hz) */
+ rbw->num_solver_iterations = 10; /* 10 is bullet default */
- rbw->shared->pointcache = BKE_ptcache_add(&(rbw->shared->ptcaches));
- rbw->shared->pointcache->step = 1;
+ rbw->shared->pointcache = BKE_ptcache_add(&(rbw->shared->ptcaches));
+ rbw->shared->pointcache->step = 1;
- /* return this sim world */
- return rbw;
+ /* return this sim world */
+ return rbw;
}
RigidBodyWorld *BKE_rigidbody_world_copy(RigidBodyWorld *rbw, const int flag)
{
- RigidBodyWorld *rbw_copy = MEM_dupallocN(rbw);
-
- if (rbw->effector_weights) {
- rbw_copy->effector_weights = MEM_dupallocN(rbw->effector_weights);
- }
- if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- id_us_plus((ID *)rbw_copy->group);
- id_us_plus((ID *)rbw_copy->constraints);
- }
-
- if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
- /* This is a regular copy, and not a CoW copy for depsgraph evaluation */
- rbw_copy->shared = MEM_callocN(sizeof(*rbw_copy->shared), "RigidBodyWorld_Shared");
- BKE_ptcache_copy_list(&rbw_copy->shared->ptcaches, &rbw->shared->ptcaches, LIB_ID_COPY_CACHES);
- rbw_copy->shared->pointcache = rbw_copy->shared->ptcaches.first;
- }
-
- rbw_copy->objects = NULL;
- rbw_copy->numbodies = 0;
- rigidbody_update_ob_array(rbw_copy);
-
- return rbw_copy;
+ RigidBodyWorld *rbw_copy = MEM_dupallocN(rbw);
+
+ if (rbw->effector_weights) {
+ rbw_copy->effector_weights = MEM_dupallocN(rbw->effector_weights);
+ }
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id_us_plus((ID *)rbw_copy->group);
+ id_us_plus((ID *)rbw_copy->constraints);
+ }
+
+ if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
+ /* This is a regular copy, and not a CoW copy for depsgraph evaluation */
+ rbw_copy->shared = MEM_callocN(sizeof(*rbw_copy->shared), "RigidBodyWorld_Shared");
+ BKE_ptcache_copy_list(&rbw_copy->shared->ptcaches, &rbw->shared->ptcaches, LIB_ID_COPY_CACHES);
+ rbw_copy->shared->pointcache = rbw_copy->shared->ptcaches.first;
+ }
+
+ rbw_copy->objects = NULL;
+ rbw_copy->numbodies = 0;
+ rigidbody_update_ob_array(rbw_copy);
+
+ return rbw_copy;
}
void BKE_rigidbody_world_groups_relink(RigidBodyWorld *rbw)
{
- ID_NEW_REMAP(rbw->group);
- ID_NEW_REMAP(rbw->constraints);
- ID_NEW_REMAP(rbw->effector_weights->group);
+ ID_NEW_REMAP(rbw->group);
+ ID_NEW_REMAP(rbw->constraints);
+ ID_NEW_REMAP(rbw->effector_weights->group);
}
void BKE_rigidbody_world_id_loop(RigidBodyWorld *rbw, RigidbodyWorldIDFunc func, void *userdata)
{
- func(rbw, (ID **)&rbw->group, userdata, IDWALK_CB_NOP);
- func(rbw, (ID **)&rbw->constraints, userdata, IDWALK_CB_NOP);
- func(rbw, (ID **)&rbw->effector_weights->group, userdata, IDWALK_CB_NOP);
-
- if (rbw->objects) {
- int i;
- for (i = 0; i < rbw->numbodies; i++) {
- func(rbw, (ID **)&rbw->objects[i], userdata, IDWALK_CB_NOP);
- }
- }
+ func(rbw, (ID **)&rbw->group, userdata, IDWALK_CB_NOP);
+ func(rbw, (ID **)&rbw->constraints, userdata, IDWALK_CB_NOP);
+ func(rbw, (ID **)&rbw->effector_weights->group, userdata, IDWALK_CB_NOP);
+
+ if (rbw->objects) {
+ int i;
+ for (i = 0; i < rbw->numbodies; i++) {
+ func(rbw, (ID **)&rbw->objects[i], userdata, IDWALK_CB_NOP);
+ }
+ }
}
/* Add rigid body settings to the specified object */
RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type)
{
- RigidBodyOb *rbo;
- RigidBodyWorld *rbw = scene->rigidbody_world;
+ RigidBodyOb *rbo;
+ RigidBodyWorld *rbw = scene->rigidbody_world;
- /* sanity checks
- * - rigidbody world must exist
- * - object must exist
- * - cannot add rigid body if it already exists
- */
- if (ob == NULL || (ob->rigidbody_object != NULL))
- return NULL;
+ /* sanity checks
+ * - rigidbody world must exist
+ * - object must exist
+ * - cannot add rigid body if it already exists
+ */
+ if (ob == NULL || (ob->rigidbody_object != NULL))
+ return NULL;
- /* create new settings data, and link it up */
- rbo = MEM_callocN(sizeof(RigidBodyOb), "RigidBodyOb");
- rbo->shared = MEM_callocN(sizeof(*rbo->shared), "RigidBodyOb_Shared");
+ /* create new settings data, and link it up */
+ rbo = MEM_callocN(sizeof(RigidBodyOb), "RigidBodyOb");
+ rbo->shared = MEM_callocN(sizeof(*rbo->shared), "RigidBodyOb_Shared");
- /* set default settings */
- rbo->type = type;
+ /* set default settings */
+ rbo->type = type;
- rbo->mass = 1.0f;
+ rbo->mass = 1.0f;
- rbo->friction = 0.5f; /* best when non-zero. 0.5 is Bullet default */
- rbo->restitution = 0.0f; /* best when zero. 0.0 is Bullet default */
+ rbo->friction = 0.5f; /* best when non-zero. 0.5 is Bullet default */
+ rbo->restitution = 0.0f; /* best when zero. 0.0 is Bullet default */
- rbo->margin = 0.04f; /* 0.04 (in meters) is Bullet default */
+ rbo->margin = 0.04f; /* 0.04 (in meters) is Bullet default */
- rbo->lin_sleep_thresh = 0.4f; /* 0.4 is half of Bullet default */
- rbo->ang_sleep_thresh = 0.5f; /* 0.5 is half of Bullet default */
+ rbo->lin_sleep_thresh = 0.4f; /* 0.4 is half of Bullet default */
+ rbo->ang_sleep_thresh = 0.5f; /* 0.5 is half of Bullet default */
- rbo->lin_damping = 0.04f;
- rbo->ang_damping = 0.1f;
+ rbo->lin_damping = 0.04f;
+ rbo->ang_damping = 0.1f;
- rbo->col_groups = 1;
+ rbo->col_groups = 1;
- /* use triangle meshes for passive objects
- * use convex hulls for active objects since dynamic triangle meshes are very unstable
- */
- if (type == RBO_TYPE_ACTIVE)
- rbo->shape = RB_SHAPE_CONVEXH;
- else
- rbo->shape = RB_SHAPE_TRIMESH;
+ /* use triangle meshes for passive objects
+ * use convex hulls for active objects since dynamic triangle meshes are very unstable
+ */
+ if (type == RBO_TYPE_ACTIVE)
+ rbo->shape = RB_SHAPE_CONVEXH;
+ else
+ rbo->shape = RB_SHAPE_TRIMESH;
- rbo->mesh_source = RBO_MESH_DEFORM;
+ rbo->mesh_source = RBO_MESH_DEFORM;
- /* set initial transform */
- mat4_to_loc_quat(rbo->pos, rbo->orn, ob->obmat);
+ /* set initial transform */
+ mat4_to_loc_quat(rbo->pos, rbo->orn, ob->obmat);
- /* flag cache as outdated */
- BKE_rigidbody_cache_reset(rbw);
- rbo->flag |= (RBO_FLAG_NEEDS_VALIDATE | RBO_FLAG_NEEDS_RESHAPE);
+ /* flag cache as outdated */
+ BKE_rigidbody_cache_reset(rbw);
+ rbo->flag |= (RBO_FLAG_NEEDS_VALIDATE | RBO_FLAG_NEEDS_RESHAPE);
- /* return this object */
- return rbo;
+ /* return this object */
+ return rbo;
}
/* Add rigid body constraint to the specified object */
RigidBodyCon *BKE_rigidbody_create_constraint(Scene *scene, Object *ob, short type)
{
- RigidBodyCon *rbc;
- RigidBodyWorld *rbw = scene->rigidbody_world;
-
- /* sanity checks
- * - rigidbody world must exist
- * - object must exist
- * - cannot add constraint if it already exists
- */
- if (ob == NULL || (ob->rigidbody_constraint != NULL))
- return NULL;
-
- /* create new settings data, and link it up */
- rbc = MEM_callocN(sizeof(RigidBodyCon), "RigidBodyCon");
-
- /* set default settings */
- rbc->type = type;
-
- rbc->ob1 = NULL;
- rbc->ob2 = NULL;
-
- rbc->flag |= RBC_FLAG_ENABLED;
- rbc->flag |= RBC_FLAG_DISABLE_COLLISIONS;
- rbc->flag |= RBC_FLAG_NEEDS_VALIDATE;
-
- rbc->spring_type = RBC_SPRING_TYPE2;
-
- rbc->breaking_threshold = 10.0f; /* no good default here, just use 10 for now */
- rbc->num_solver_iterations = 10; /* 10 is Bullet default */
-
- rbc->limit_lin_x_lower = -1.0f;
- rbc->limit_lin_x_upper = 1.0f;
- rbc->limit_lin_y_lower = -1.0f;
- rbc->limit_lin_y_upper = 1.0f;
- rbc->limit_lin_z_lower = -1.0f;
- rbc->limit_lin_z_upper = 1.0f;
- rbc->limit_ang_x_lower = -M_PI_4;
- rbc->limit_ang_x_upper = M_PI_4;
- rbc->limit_ang_y_lower = -M_PI_4;
- rbc->limit_ang_y_upper = M_PI_4;
- rbc->limit_ang_z_lower = -M_PI_4;
- rbc->limit_ang_z_upper = M_PI_4;
-
- rbc->spring_damping_x = 0.5f;
- rbc->spring_damping_y = 0.5f;
- rbc->spring_damping_z = 0.5f;
- rbc->spring_damping_ang_x = 0.5f;
- rbc->spring_damping_ang_y = 0.5f;
- rbc->spring_damping_ang_z = 0.5f;
- rbc->spring_stiffness_x = 10.0f;
- rbc->spring_stiffness_y = 10.0f;
- rbc->spring_stiffness_z = 10.0f;
- rbc->spring_stiffness_ang_x = 10.0f;
- rbc->spring_stiffness_ang_y = 10.0f;
- rbc->spring_stiffness_ang_z = 10.0f;
-
- rbc->motor_lin_max_impulse = 1.0f;
- rbc->motor_lin_target_velocity = 1.0f;
- rbc->motor_ang_max_impulse = 1.0f;
- rbc->motor_ang_target_velocity = 1.0f;
-
- /* flag cache as outdated */
- BKE_rigidbody_cache_reset(rbw);
-
- /* return this object */
- return rbc;
+ RigidBodyCon *rbc;
+ RigidBodyWorld *rbw = scene->rigidbody_world;
+
+ /* sanity checks
+ * - rigidbody world must exist
+ * - object must exist
+ * - cannot add constraint if it already exists
+ */
+ if (ob == NULL || (ob->rigidbody_constraint != NULL))
+ return NULL;
+
+ /* create new settings data, and link it up */
+ rbc = MEM_callocN(sizeof(RigidBodyCon), "RigidBodyCon");
+
+ /* set default settings */
+ rbc->type = type;
+
+ rbc->ob1 = NULL;
+ rbc->ob2 = NULL;
+
+ rbc->flag |= RBC_FLAG_ENABLED;
+ rbc->flag |= RBC_FLAG_DISABLE_COLLISIONS;
+ rbc->flag |= RBC_FLAG_NEEDS_VALIDATE;
+
+ rbc->spring_type = RBC_SPRING_TYPE2;
+
+ rbc->breaking_threshold = 10.0f; /* no good default here, just use 10 for now */
+ rbc->num_solver_iterations = 10; /* 10 is Bullet default */
+
+ rbc->limit_lin_x_lower = -1.0f;
+ rbc->limit_lin_x_upper = 1.0f;
+ rbc->limit_lin_y_lower = -1.0f;
+ rbc->limit_lin_y_upper = 1.0f;
+ rbc->limit_lin_z_lower = -1.0f;
+ rbc->limit_lin_z_upper = 1.0f;
+ rbc->limit_ang_x_lower = -M_PI_4;
+ rbc->limit_ang_x_upper = M_PI_4;
+ rbc->limit_ang_y_lower = -M_PI_4;
+ rbc->limit_ang_y_upper = M_PI_4;
+ rbc->limit_ang_z_lower = -M_PI_4;
+ rbc->limit_ang_z_upper = M_PI_4;
+
+ rbc->spring_damping_x = 0.5f;
+ rbc->spring_damping_y = 0.5f;
+ rbc->spring_damping_z = 0.5f;
+ rbc->spring_damping_ang_x = 0.5f;
+ rbc->spring_damping_ang_y = 0.5f;
+ rbc->spring_damping_ang_z = 0.5f;
+ rbc->spring_stiffness_x = 10.0f;
+ rbc->spring_stiffness_y = 10.0f;
+ rbc->spring_stiffness_z = 10.0f;
+ rbc->spring_stiffness_ang_x = 10.0f;
+ rbc->spring_stiffness_ang_y = 10.0f;
+ rbc->spring_stiffness_ang_z = 10.0f;
+
+ rbc->motor_lin_max_impulse = 1.0f;
+ rbc->motor_lin_target_velocity = 1.0f;
+ rbc->motor_ang_max_impulse = 1.0f;
+ rbc->motor_ang_target_velocity = 1.0f;
+
+ /* flag cache as outdated */
+ BKE_rigidbody_cache_reset(rbw);
+
+ /* return this object */
+ return rbc;
}
void BKE_rigidbody_objects_collection_validate(Scene *scene, RigidBodyWorld *rbw)
{
- if (rbw->group != NULL) {
- FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object)
- {
- if (object->type != OB_MESH || object->rigidbody_object != NULL) {
- continue;
- }
- object->rigidbody_object = BKE_rigidbody_create_object(scene, object, RBO_TYPE_ACTIVE);
- }
- FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
- }
+ if (rbw->group != NULL) {
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->group, object) {
+ if (object->type != OB_MESH || object->rigidbody_object != NULL) {
+ continue;
+ }
+ object->rigidbody_object = BKE_rigidbody_create_object(scene, object, RBO_TYPE_ACTIVE);
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+ }
}
void BKE_rigidbody_constraints_collection_validate(Scene *scene, RigidBodyWorld *rbw)
{
- if (rbw->constraints != NULL) {
- FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->constraints, object)
- {
- if (object->rigidbody_constraint != NULL) {
- continue;
- }
- object->rigidbody_constraint = BKE_rigidbody_create_constraint(scene, object, RBC_TYPE_FIXED);
- }
- FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
- }
+ if (rbw->constraints != NULL) {
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->constraints, object) {
+ if (object->rigidbody_constraint != NULL) {
+ continue;
+ }
+ object->rigidbody_constraint = BKE_rigidbody_create_constraint(
+ scene, object, RBC_TYPE_FIXED);
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+ }
}
void BKE_rigidbody_main_collection_object_add(Main *bmain, Collection *collection, Object *object)
{
- for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
- RigidBodyWorld *rbw = scene->rigidbody_world;
-
- if (rbw == NULL) {
- continue;
- }
-
- if (rbw->group == collection && object->type == OB_MESH && object->rigidbody_object == NULL) {
- object->rigidbody_object = BKE_rigidbody_create_object(scene, object, RBO_TYPE_ACTIVE);
- }
- if (rbw->constraints == collection && object->rigidbody_constraint == NULL) {
- object->rigidbody_constraint = BKE_rigidbody_create_constraint(scene, object, RBC_TYPE_FIXED);
- }
- }
+ for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
+ RigidBodyWorld *rbw = scene->rigidbody_world;
+
+ if (rbw == NULL) {
+ continue;
+ }
+
+ if (rbw->group == collection && object->type == OB_MESH && object->rigidbody_object == NULL) {
+ object->rigidbody_object = BKE_rigidbody_create_object(scene, object, RBO_TYPE_ACTIVE);
+ }
+ if (rbw->constraints == collection && object->rigidbody_constraint == NULL) {
+ object->rigidbody_constraint = BKE_rigidbody_create_constraint(
+ scene, object, RBC_TYPE_FIXED);
+ }
+ }
}
/* ************************************** */
@@ -1200,207 +1239,216 @@ void BKE_rigidbody_main_collection_object_add(Main *bmain, Collection *collectio
*/
RigidBodyWorld *BKE_rigidbody_get_world(Scene *scene)
{
- /* sanity check */
- if (scene == NULL)
- return NULL;
+ /* sanity check */
+ if (scene == NULL)
+ return NULL;
- return scene->rigidbody_world;
+ return scene->rigidbody_world;
}
void BKE_rigidbody_remove_object(struct Main *bmain, Scene *scene, Object *ob)
{
- RigidBodyWorld *rbw = scene->rigidbody_world;
- RigidBodyCon *rbc;
- int i;
-
- if (rbw) {
-
- /* remove object from array */
- if (rbw && rbw->objects) {
- for (i = 0; i < rbw->numbodies; i++) {
- if (rbw->objects[i] == ob) {
- rbw->objects[i] = NULL;
- break;
- }
- }
- }
-
- /* remove object from rigid body constraints */
- if (rbw->constraints) {
- FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->constraints, obt)
- {
- if (obt && obt->rigidbody_constraint) {
- rbc = obt->rigidbody_constraint;
- if (ELEM(ob, rbc->ob1, rbc->ob2)) {
- BKE_rigidbody_remove_constraint(scene, obt);
- }
- }
- }
- FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
- }
- BKE_collection_object_remove(bmain, rbw->group, ob, false);
- }
-
- /* remove object's settings */
- BKE_rigidbody_free_object(ob, rbw);
-
- /* flag cache as outdated */
- BKE_rigidbody_cache_reset(rbw);
+ RigidBodyWorld *rbw = scene->rigidbody_world;
+ RigidBodyCon *rbc;
+ int i;
+
+ if (rbw) {
+
+ /* remove object from array */
+ if (rbw && rbw->objects) {
+ for (i = 0; i < rbw->numbodies; i++) {
+ if (rbw->objects[i] == ob) {
+ rbw->objects[i] = NULL;
+ break;
+ }
+ }
+ }
+
+ /* remove object from rigid body constraints */
+ if (rbw->constraints) {
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->constraints, obt) {
+ if (obt && obt->rigidbody_constraint) {
+ rbc = obt->rigidbody_constraint;
+ if (ELEM(ob, rbc->ob1, rbc->ob2)) {
+ BKE_rigidbody_remove_constraint(scene, obt);
+ }
+ }
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+ }
+ BKE_collection_object_remove(bmain, rbw->group, ob, false);
+ }
+
+ /* remove object's settings */
+ BKE_rigidbody_free_object(ob, rbw);
+
+ /* flag cache as outdated */
+ BKE_rigidbody_cache_reset(rbw);
}
void BKE_rigidbody_remove_constraint(Scene *scene, Object *ob)
{
- RigidBodyWorld *rbw = scene->rigidbody_world;
- RigidBodyCon *rbc = ob->rigidbody_constraint;
-
- /* remove from rigidbody world, free object won't do this */
- if (rbw && rbw->shared->physics_world && rbc->physics_constraint) {
- RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint);
- }
- /* remove object's settings */
- BKE_rigidbody_free_constraint(ob);
-
- /* flag cache as outdated */
- BKE_rigidbody_cache_reset(rbw);
+ RigidBodyWorld *rbw = scene->rigidbody_world;
+ RigidBodyCon *rbc = ob->rigidbody_constraint;
+
+ /* remove from rigidbody world, free object won't do this */
+ if (rbw && rbw->shared->physics_world && rbc->physics_constraint) {
+ RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint);
+ }
+ /* remove object's settings */
+ BKE_rigidbody_free_constraint(ob);
+
+ /* flag cache as outdated */
+ BKE_rigidbody_cache_reset(rbw);
}
-
/* ************************************** */
/* Simulation Interface - Bullet */
/* Update object array and rigid body count so they're in sync with the rigid body group */
static void rigidbody_update_ob_array(RigidBodyWorld *rbw)
{
- if (rbw->group == NULL) {
- rbw->numbodies = 0;
- rbw->objects = realloc(rbw->objects, 0);
- return;
- }
-
- int n = 0;
- FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object)
- {
- (void)object;
- n++;
- }
- FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
-
- if (rbw->numbodies != n) {
- rbw->numbodies = n;
- rbw->objects = realloc(rbw->objects, sizeof(Object *) * rbw->numbodies);
- }
-
- int i = 0;
- FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object)
- {
- rbw->objects[i] = object;
- i++;
- }
- FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+ if (rbw->group == NULL) {
+ rbw->numbodies = 0;
+ rbw->objects = realloc(rbw->objects, 0);
+ return;
+ }
+
+ int n = 0;
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->group, object) {
+ (void)object;
+ n++;
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+
+ if (rbw->numbodies != n) {
+ rbw->numbodies = n;
+ rbw->objects = realloc(rbw->objects, sizeof(Object *) * rbw->numbodies);
+ }
+
+ int i = 0;
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->group, object) {
+ rbw->objects[i] = object;
+ i++;
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
static void rigidbody_update_sim_world(Scene *scene, RigidBodyWorld *rbw)
{
- float adj_gravity[3];
-
- /* adjust gravity to take effector weights into account */
- if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
- copy_v3_v3(adj_gravity, scene->physics_settings.gravity);
- mul_v3_fl(adj_gravity, rbw->effector_weights->global_gravity * rbw->effector_weights->weight[0]);
- }
- else {
- zero_v3(adj_gravity);
- }
-
- /* update gravity, since this RNA setting is not part of RigidBody settings */
- RB_dworld_set_gravity(rbw->shared->physics_world, adj_gravity);
-
- /* update object array in case there are changes */
- rigidbody_update_ob_array(rbw);
-}
-
-static void rigidbody_update_sim_ob(Depsgraph *depsgraph, Scene *scene, RigidBodyWorld *rbw, Object *ob, RigidBodyOb *rbo)
-{
- float loc[3];
- float rot[4];
- float scale[3];
-
- /* only update if rigid body exists */
- if (rbo->shared->physics_object == NULL)
- return;
-
- if (rbo->shape == RB_SHAPE_TRIMESH && rbo->flag & RBO_FLAG_USE_DEFORM) {
- Mesh *mesh = ob->runtime.mesh_deform_eval;
- if (mesh) {
- MVert *mvert = mesh->mvert;
- int totvert = mesh->totvert;
- BoundBox *bb = BKE_object_boundbox_get(ob);
-
- RB_shape_trimesh_update(rbo->shared->physics_shape, (float *)mvert, totvert, sizeof(MVert), bb->vec[0], bb->vec[6]);
- }
- }
-
- mat4_decompose(loc, rot, scale, ob->obmat);
-
- /* update scale for all objects */
- RB_body_set_scale(rbo->shared->physics_object, scale);
- /* compensate for embedded convex hull collision margin */
- if (!(rbo->flag & RBO_FLAG_USE_MARGIN) && rbo->shape == RB_SHAPE_CONVEXH)
- RB_shape_set_margin(rbo->shared->physics_shape, RBO_GET_MARGIN(rbo) * MIN3(scale[0], scale[1], scale[2]));
-
- /* make transformed objects temporarily kinmatic so that they can be moved by the user during simulation */
- if (ob->flag & SELECT && G.moving & G_TRANSFORM_OBJ) {
- RB_body_set_kinematic_state(rbo->shared->physics_object, true);
- RB_body_set_mass(rbo->shared->physics_object, 0.0f);
- }
-
- /* update rigid body location and rotation for kinematic bodies */
- if (rbo->flag & RBO_FLAG_KINEMATIC || (ob->flag & SELECT && G.moving & G_TRANSFORM_OBJ)) {
- RB_body_activate(rbo->shared->physics_object);
- RB_body_set_loc_rot(rbo->shared->physics_object, loc, rot);
- }
- /* update influence of effectors - but don't do it on an effector */
- /* only dynamic bodies need effector update */
- else if (rbo->type == RBO_TYPE_ACTIVE && ((ob->pd == NULL) || (ob->pd->forcefield == PFIELD_NULL))) {
- EffectorWeights *effector_weights = rbw->effector_weights;
- EffectedPoint epoint;
- ListBase *effectors;
-
- /* get effectors present in the group specified by effector_weights */
- effectors = BKE_effectors_create(depsgraph, ob, NULL, effector_weights);
- if (effectors) {
- float eff_force[3] = {0.0f, 0.0f, 0.0f};
- float eff_loc[3], eff_vel[3];
-
- /* create dummy 'point' which represents last known position of object as result of sim */
- // XXX: this can create some inaccuracies with sim position, but is probably better than using unsimulated vals?
- RB_body_get_position(rbo->shared->physics_object, eff_loc);
- RB_body_get_linear_velocity(rbo->shared->physics_object, eff_vel);
-
- pd_point_from_loc(scene, eff_loc, eff_vel, 0, &epoint);
-
- /* calculate net force of effectors, and apply to sim object
- * - we use 'central force' since apply force requires a "relative position" which we don't have...
- */
- BKE_effectors_apply(effectors, NULL, effector_weights, &epoint, eff_force, NULL);
- if (G.f & G_DEBUG)
- printf("\tapplying force (%f,%f,%f) to '%s'\n", eff_force[0], eff_force[1], eff_force[2], ob->id.name + 2);
- /* activate object in case it is deactivated */
- if (!is_zero_v3(eff_force))
- RB_body_activate(rbo->shared->physics_object);
- RB_body_apply_central_force(rbo->shared->physics_object, eff_force);
- }
- else if (G.f & G_DEBUG)
- printf("\tno forces to apply to '%s'\n", ob->id.name + 2);
-
- /* cleanup */
- BKE_effectors_free(effectors);
- }
- /* NOTE: passive objects don't need to be updated since they don't move */
-
- /* NOTE: no other settings need to be explicitly updated here,
- * since RNA setters take care of the rest :)
- */
+ float adj_gravity[3];
+
+ /* adjust gravity to take effector weights into account */
+ if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
+ copy_v3_v3(adj_gravity, scene->physics_settings.gravity);
+ mul_v3_fl(adj_gravity,
+ rbw->effector_weights->global_gravity * rbw->effector_weights->weight[0]);
+ }
+ else {
+ zero_v3(adj_gravity);
+ }
+
+ /* update gravity, since this RNA setting is not part of RigidBody settings */
+ RB_dworld_set_gravity(rbw->shared->physics_world, adj_gravity);
+
+ /* update object array in case there are changes */
+ rigidbody_update_ob_array(rbw);
+}
+
+static void rigidbody_update_sim_ob(
+ Depsgraph *depsgraph, Scene *scene, RigidBodyWorld *rbw, Object *ob, RigidBodyOb *rbo)
+{
+ float loc[3];
+ float rot[4];
+ float scale[3];
+
+ /* only update if rigid body exists */
+ if (rbo->shared->physics_object == NULL)
+ return;
+
+ if (rbo->shape == RB_SHAPE_TRIMESH && rbo->flag & RBO_FLAG_USE_DEFORM) {
+ Mesh *mesh = ob->runtime.mesh_deform_eval;
+ if (mesh) {
+ MVert *mvert = mesh->mvert;
+ int totvert = mesh->totvert;
+ BoundBox *bb = BKE_object_boundbox_get(ob);
+
+ RB_shape_trimesh_update(rbo->shared->physics_shape,
+ (float *)mvert,
+ totvert,
+ sizeof(MVert),
+ bb->vec[0],
+ bb->vec[6]);
+ }
+ }
+
+ mat4_decompose(loc, rot, scale, ob->obmat);
+
+ /* update scale for all objects */
+ RB_body_set_scale(rbo->shared->physics_object, scale);
+ /* compensate for embedded convex hull collision margin */
+ if (!(rbo->flag & RBO_FLAG_USE_MARGIN) && rbo->shape == RB_SHAPE_CONVEXH)
+ RB_shape_set_margin(rbo->shared->physics_shape,
+ RBO_GET_MARGIN(rbo) * MIN3(scale[0], scale[1], scale[2]));
+
+ /* make transformed objects temporarily kinmatic so that they can be moved by the user during simulation */
+ if (ob->flag & SELECT && G.moving & G_TRANSFORM_OBJ) {
+ RB_body_set_kinematic_state(rbo->shared->physics_object, true);
+ RB_body_set_mass(rbo->shared->physics_object, 0.0f);
+ }
+
+ /* update rigid body location and rotation for kinematic bodies */
+ if (rbo->flag & RBO_FLAG_KINEMATIC || (ob->flag & SELECT && G.moving & G_TRANSFORM_OBJ)) {
+ RB_body_activate(rbo->shared->physics_object);
+ RB_body_set_loc_rot(rbo->shared->physics_object, loc, rot);
+ }
+ /* update influence of effectors - but don't do it on an effector */
+ /* only dynamic bodies need effector update */
+ else if (rbo->type == RBO_TYPE_ACTIVE &&
+ ((ob->pd == NULL) || (ob->pd->forcefield == PFIELD_NULL))) {
+ EffectorWeights *effector_weights = rbw->effector_weights;
+ EffectedPoint epoint;
+ ListBase *effectors;
+
+ /* get effectors present in the group specified by effector_weights */
+ effectors = BKE_effectors_create(depsgraph, ob, NULL, effector_weights);
+ if (effectors) {
+ float eff_force[3] = {0.0f, 0.0f, 0.0f};
+ float eff_loc[3], eff_vel[3];
+
+ /* create dummy 'point' which represents last known position of object as result of sim */
+ // XXX: this can create some inaccuracies with sim position, but is probably better than using unsimulated vals?
+ RB_body_get_position(rbo->shared->physics_object, eff_loc);
+ RB_body_get_linear_velocity(rbo->shared->physics_object, eff_vel);
+
+ pd_point_from_loc(scene, eff_loc, eff_vel, 0, &epoint);
+
+ /* calculate net force of effectors, and apply to sim object
+ * - we use 'central force' since apply force requires a "relative position" which we don't have...
+ */
+ BKE_effectors_apply(effectors, NULL, effector_weights, &epoint, eff_force, NULL);
+ if (G.f & G_DEBUG)
+ printf("\tapplying force (%f,%f,%f) to '%s'\n",
+ eff_force[0],
+ eff_force[1],
+ eff_force[2],
+ ob->id.name + 2);
+ /* activate object in case it is deactivated */
+ if (!is_zero_v3(eff_force))
+ RB_body_activate(rbo->shared->physics_object);
+ RB_body_apply_central_force(rbo->shared->physics_object, eff_force);
+ }
+ else if (G.f & G_DEBUG)
+ printf("\tno forces to apply to '%s'\n", ob->id.name + 2);
+
+ /* cleanup */
+ BKE_effectors_free(effectors);
+ }
+ /* NOTE: passive objects don't need to be updated since they don't move */
+
+ /* NOTE: no other settings need to be explicitly updated here,
+ * since RNA setters take care of the rest :)
+ */
}
/**
@@ -1408,250 +1456,252 @@ static void rigidbody_update_sim_ob(Depsgraph *depsgraph, Scene *scene, RigidBod
*
* \param rebuild: Rebuild entire simulation
*/
-static void rigidbody_update_simulation(Depsgraph *depsgraph, Scene *scene, RigidBodyWorld *rbw, bool rebuild)
-{
- float ctime = DEG_get_ctime(depsgraph);
-
- /* update world */
- if (rebuild)
- BKE_rigidbody_validate_sim_world(scene, rbw, true);
- rigidbody_update_sim_world(scene, rbw);
-
- /* XXX TODO For rebuild: remove all constraints first.
- * Otherwise we can end up deleting objects that are still
- * referenced by constraints, corrupting bullet's internal list.
- *
- * Memory management needs redesign here, this is just a dirty workaround.
- */
- if (rebuild && rbw->constraints) {
- FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->constraints, ob)
- {
- RigidBodyCon *rbc = ob->rigidbody_constraint;
- if (rbc && rbc->physics_constraint) {
- RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint);
- RB_constraint_delete(rbc->physics_constraint);
- rbc->physics_constraint = NULL;
- }
- }
- FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
- }
-
- /* update objects */
- FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, ob)
- {
- if (ob->type == OB_MESH) {
- /* validate that we've got valid object set up here... */
- RigidBodyOb *rbo = ob->rigidbody_object;
- /* update transformation matrix of the object so we don't get a frame of lag for simple animations */
- BKE_object_where_is_calc_time(depsgraph, scene, ob, ctime);
-
- /* TODO remove this whole block once we are sure we never get NULL rbo here anymore. */
- /* This cannot be done in CoW evaluation context anymore... */
- if (rbo == NULL) {
- BLI_assert(!"CoW object part of RBW object collection without RB object data, should not happen.\n");
- /* Since this object is included in the sim group but doesn't have
- * rigid body settings (perhaps it was added manually), add!
- * - assume object to be active? That is the default for newly added settings...
- */
- ob->rigidbody_object = BKE_rigidbody_create_object(scene, ob, RBO_TYPE_ACTIVE);
- rigidbody_validate_sim_object(rbw, ob, true);
-
- rbo = ob->rigidbody_object;
- }
- else {
- /* perform simulation data updates as tagged */
- /* refresh object... */
- if (rebuild) {
- /* World has been rebuilt so rebuild object */
- /* TODO(Sybren): rigidbody_validate_sim_object() can call rigidbody_validate_sim_shape(),
- * but neither resets the RBO_FLAG_NEEDS_RESHAPE flag nor calls RB_body_set_collision_shape().
- * This results in the collision shape being created twice, which is unnecessary. */
- rigidbody_validate_sim_object(rbw, ob, true);
- }
- else if (rbo->flag & RBO_FLAG_NEEDS_VALIDATE) {
- rigidbody_validate_sim_object(rbw, ob, false);
- }
- /* refresh shape... */
- if (rbo->flag & RBO_FLAG_NEEDS_RESHAPE) {
- /* mesh/shape data changed, so force shape refresh */
- rigidbody_validate_sim_shape(ob, true);
- /* now tell RB sim about it */
- // XXX: we assume that this can only get applied for active/passive shapes that will be included as rigidbodies
- RB_body_set_collision_shape(rbo->shared->physics_object, rbo->shared->physics_shape);
- }
- }
- rbo->flag &= ~(RBO_FLAG_NEEDS_VALIDATE | RBO_FLAG_NEEDS_RESHAPE);
-
- /* update simulation object... */
- rigidbody_update_sim_ob(depsgraph, scene, rbw, ob, rbo);
- }
- }
- FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
-
- /* update constraints */
- if (rbw->constraints == NULL) /* no constraints, move on */
- return;
-
- FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->constraints, ob)
- {
- /* validate that we've got valid object set up here... */
- RigidBodyCon *rbc = ob->rigidbody_constraint;
- /* update transformation matrix of the object so we don't get a frame of lag for simple animations */
- BKE_object_where_is_calc_time(depsgraph, scene, ob, ctime);
-
- /* TODO remove this whole block once we are sure we never get NULL rbo here anymore. */
- /* This cannot be done in CoW evaluation context anymore... */
- if (rbc == NULL) {
- BLI_assert(!"CoW object part of RBW constraints collection without RB constraint data, should not happen.\n");
- /* Since this object is included in the group but doesn't have
- * constraint settings (perhaps it was added manually), add!
- */
- ob->rigidbody_constraint = BKE_rigidbody_create_constraint(scene, ob, RBC_TYPE_FIXED);
- rigidbody_validate_sim_constraint(rbw, ob, true);
-
- rbc = ob->rigidbody_constraint;
- }
- else {
- /* perform simulation data updates as tagged */
- if (rebuild) {
- /* World has been rebuilt so rebuild constraint */
- rigidbody_validate_sim_constraint(rbw, ob, true);
- }
- else if (rbc->flag & RBC_FLAG_NEEDS_VALIDATE) {
- rigidbody_validate_sim_constraint(rbw, ob, false);
- }
- }
- rbc->flag &= ~RBC_FLAG_NEEDS_VALIDATE;
- }
- FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+static void rigidbody_update_simulation(Depsgraph *depsgraph,
+ Scene *scene,
+ RigidBodyWorld *rbw,
+ bool rebuild)
+{
+ float ctime = DEG_get_ctime(depsgraph);
+
+ /* update world */
+ if (rebuild)
+ BKE_rigidbody_validate_sim_world(scene, rbw, true);
+ rigidbody_update_sim_world(scene, rbw);
+
+ /* XXX TODO For rebuild: remove all constraints first.
+ * Otherwise we can end up deleting objects that are still
+ * referenced by constraints, corrupting bullet's internal list.
+ *
+ * Memory management needs redesign here, this is just a dirty workaround.
+ */
+ if (rebuild && rbw->constraints) {
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->constraints, ob) {
+ RigidBodyCon *rbc = ob->rigidbody_constraint;
+ if (rbc && rbc->physics_constraint) {
+ RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint);
+ RB_constraint_delete(rbc->physics_constraint);
+ rbc->physics_constraint = NULL;
+ }
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+ }
+
+ /* update objects */
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->group, ob) {
+ if (ob->type == OB_MESH) {
+ /* validate that we've got valid object set up here... */
+ RigidBodyOb *rbo = ob->rigidbody_object;
+ /* update transformation matrix of the object so we don't get a frame of lag for simple animations */
+ BKE_object_where_is_calc_time(depsgraph, scene, ob, ctime);
+
+ /* TODO remove this whole block once we are sure we never get NULL rbo here anymore. */
+ /* This cannot be done in CoW evaluation context anymore... */
+ if (rbo == NULL) {
+ BLI_assert(!"CoW object part of RBW object collection without RB object data, should not happen.\n");
+ /* Since this object is included in the sim group but doesn't have
+ * rigid body settings (perhaps it was added manually), add!
+ * - assume object to be active? That is the default for newly added settings...
+ */
+ ob->rigidbody_object = BKE_rigidbody_create_object(scene, ob, RBO_TYPE_ACTIVE);
+ rigidbody_validate_sim_object(rbw, ob, true);
+
+ rbo = ob->rigidbody_object;
+ }
+ else {
+ /* perform simulation data updates as tagged */
+ /* refresh object... */
+ if (rebuild) {
+ /* World has been rebuilt so rebuild object */
+ /* TODO(Sybren): rigidbody_validate_sim_object() can call rigidbody_validate_sim_shape(),
+ * but neither resets the RBO_FLAG_NEEDS_RESHAPE flag nor calls RB_body_set_collision_shape().
+ * This results in the collision shape being created twice, which is unnecessary. */
+ rigidbody_validate_sim_object(rbw, ob, true);
+ }
+ else if (rbo->flag & RBO_FLAG_NEEDS_VALIDATE) {
+ rigidbody_validate_sim_object(rbw, ob, false);
+ }
+ /* refresh shape... */
+ if (rbo->flag & RBO_FLAG_NEEDS_RESHAPE) {
+ /* mesh/shape data changed, so force shape refresh */
+ rigidbody_validate_sim_shape(ob, true);
+ /* now tell RB sim about it */
+ // XXX: we assume that this can only get applied for active/passive shapes that will be included as rigidbodies
+ RB_body_set_collision_shape(rbo->shared->physics_object, rbo->shared->physics_shape);
+ }
+ }
+ rbo->flag &= ~(RBO_FLAG_NEEDS_VALIDATE | RBO_FLAG_NEEDS_RESHAPE);
+
+ /* update simulation object... */
+ rigidbody_update_sim_ob(depsgraph, scene, rbw, ob, rbo);
+ }
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+
+ /* update constraints */
+ if (rbw->constraints == NULL) /* no constraints, move on */
+ return;
+
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->constraints, ob) {
+ /* validate that we've got valid object set up here... */
+ RigidBodyCon *rbc = ob->rigidbody_constraint;
+ /* update transformation matrix of the object so we don't get a frame of lag for simple animations */
+ BKE_object_where_is_calc_time(depsgraph, scene, ob, ctime);
+
+ /* TODO remove this whole block once we are sure we never get NULL rbo here anymore. */
+ /* This cannot be done in CoW evaluation context anymore... */
+ if (rbc == NULL) {
+ BLI_assert(!"CoW object part of RBW constraints collection without RB constraint data, should not happen.\n");
+ /* Since this object is included in the group but doesn't have
+ * constraint settings (perhaps it was added manually), add!
+ */
+ ob->rigidbody_constraint = BKE_rigidbody_create_constraint(scene, ob, RBC_TYPE_FIXED);
+ rigidbody_validate_sim_constraint(rbw, ob, true);
+
+ rbc = ob->rigidbody_constraint;
+ }
+ else {
+ /* perform simulation data updates as tagged */
+ if (rebuild) {
+ /* World has been rebuilt so rebuild constraint */
+ rigidbody_validate_sim_constraint(rbw, ob, true);
+ }
+ else if (rbc->flag & RBC_FLAG_NEEDS_VALIDATE) {
+ rigidbody_validate_sim_constraint(rbw, ob, false);
+ }
+ }
+ rbc->flag &= ~RBC_FLAG_NEEDS_VALIDATE;
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
static void rigidbody_update_simulation_post_step(Depsgraph *depsgraph, RigidBodyWorld *rbw)
{
- ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
-
- FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, ob)
- {
- Base *base = BKE_view_layer_base_find(view_layer, ob);
- RigidBodyOb *rbo = ob->rigidbody_object;
- /* Reset kinematic state for transformed objects. */
- if (rbo && base && (base->flag & BASE_SELECTED) && (G.moving & G_TRANSFORM_OBJ)) {
- RB_body_set_kinematic_state(rbo->shared->physics_object, rbo->flag & RBO_FLAG_KINEMATIC || rbo->flag & RBO_FLAG_DISABLED);
- RB_body_set_mass(rbo->shared->physics_object, RBO_GET_MASS(rbo));
- /* Deactivate passive objects so they don't interfere with deactivation of active objects. */
- if (rbo->type == RBO_TYPE_PASSIVE)
- RB_body_deactivate(rbo->shared->physics_object);
- }
- }
- FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+ ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
+
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->group, ob) {
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
+ RigidBodyOb *rbo = ob->rigidbody_object;
+ /* Reset kinematic state for transformed objects. */
+ if (rbo && base && (base->flag & BASE_SELECTED) && (G.moving & G_TRANSFORM_OBJ)) {
+ RB_body_set_kinematic_state(rbo->shared->physics_object,
+ rbo->flag & RBO_FLAG_KINEMATIC || rbo->flag & RBO_FLAG_DISABLED);
+ RB_body_set_mass(rbo->shared->physics_object, RBO_GET_MASS(rbo));
+ /* Deactivate passive objects so they don't interfere with deactivation of active objects. */
+ if (rbo->type == RBO_TYPE_PASSIVE)
+ RB_body_deactivate(rbo->shared->physics_object);
+ }
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
bool BKE_rigidbody_check_sim_running(RigidBodyWorld *rbw, float ctime)
{
- return (rbw && (rbw->flag & RBW_FLAG_MUTED) == 0 && ctime > rbw->shared->pointcache->startframe);
+ return (rbw && (rbw->flag & RBW_FLAG_MUTED) == 0 && ctime > rbw->shared->pointcache->startframe);
}
/* Sync rigid body and object transformations */
void BKE_rigidbody_sync_transforms(RigidBodyWorld *rbw, Object *ob, float ctime)
{
- RigidBodyOb *rbo = ob->rigidbody_object;
-
- /* keep original transform for kinematic and passive objects */
- if (ELEM(NULL, rbw, rbo) || rbo->flag & RBO_FLAG_KINEMATIC || rbo->type == RBO_TYPE_PASSIVE)
- return;
-
- /* use rigid body transform after cache start frame if objects is not being transformed */
- if (BKE_rigidbody_check_sim_running(rbw, ctime) && !(ob->flag & SELECT && G.moving & G_TRANSFORM_OBJ)) {
- float mat[4][4], size_mat[4][4], size[3];
-
- normalize_qt(rbo->orn); // RB_TODO investigate why quaternion isn't normalized at this point
- quat_to_mat4(mat, rbo->orn);
- copy_v3_v3(mat[3], rbo->pos);
-
- mat4_to_size(size, ob->obmat);
- size_to_mat4(size_mat, size);
- mul_m4_m4m4(mat, mat, size_mat);
-
- copy_m4_m4(ob->obmat, mat);
- }
- /* otherwise set rigid body transform to current obmat */
- else {
- mat4_to_loc_quat(rbo->pos, rbo->orn, ob->obmat);
- }
+ RigidBodyOb *rbo = ob->rigidbody_object;
+
+ /* keep original transform for kinematic and passive objects */
+ if (ELEM(NULL, rbw, rbo) || rbo->flag & RBO_FLAG_KINEMATIC || rbo->type == RBO_TYPE_PASSIVE)
+ return;
+
+ /* use rigid body transform after cache start frame if objects is not being transformed */
+ if (BKE_rigidbody_check_sim_running(rbw, ctime) &&
+ !(ob->flag & SELECT && G.moving & G_TRANSFORM_OBJ)) {
+ float mat[4][4], size_mat[4][4], size[3];
+
+ normalize_qt(rbo->orn); // RB_TODO investigate why quaternion isn't normalized at this point
+ quat_to_mat4(mat, rbo->orn);
+ copy_v3_v3(mat[3], rbo->pos);
+
+ mat4_to_size(size, ob->obmat);
+ size_to_mat4(size_mat, size);
+ mul_m4_m4m4(mat, mat, size_mat);
+
+ copy_m4_m4(ob->obmat, mat);
+ }
+ /* otherwise set rigid body transform to current obmat */
+ else {
+ mat4_to_loc_quat(rbo->pos, rbo->orn, ob->obmat);
+ }
}
/* Used when canceling transforms - return rigidbody and object to initial states */
-void BKE_rigidbody_aftertrans_update(Object *ob, float loc[3], float rot[3], float quat[4], float rotAxis[3], float rotAngle)
-{
- RigidBodyOb *rbo = ob->rigidbody_object;
- bool correct_delta = !(rbo->flag & RBO_FLAG_KINEMATIC || rbo->type == RBO_TYPE_PASSIVE);
-
- /* return rigid body and object to their initial states */
- copy_v3_v3(rbo->pos, ob->loc);
- copy_v3_v3(ob->loc, loc);
-
- if (correct_delta) {
- add_v3_v3(rbo->pos, ob->dloc);
- }
-
- if (ob->rotmode > 0) {
- float qt[4];
- eulO_to_quat(qt, ob->rot, ob->rotmode);
-
- if (correct_delta) {
- float dquat[4];
- eulO_to_quat(dquat, ob->drot, ob->rotmode);
-
- mul_qt_qtqt(rbo->orn, dquat, qt);
- }
- else {
- copy_qt_qt(rbo->orn, qt);
- }
-
- copy_v3_v3(ob->rot, rot);
- }
- else if (ob->rotmode == ROT_MODE_AXISANGLE) {
- float qt[4];
- axis_angle_to_quat(qt, ob->rotAxis, ob->rotAngle);
-
- if (correct_delta) {
- float dquat[4];
- axis_angle_to_quat(dquat, ob->drotAxis, ob->drotAngle);
-
- mul_qt_qtqt(rbo->orn, dquat, qt);
- }
- else {
- copy_qt_qt(rbo->orn, qt);
- }
-
- copy_v3_v3(ob->rotAxis, rotAxis);
- ob->rotAngle = rotAngle;
- }
- else {
- if (correct_delta) {
- mul_qt_qtqt(rbo->orn, ob->dquat, ob->quat);
- }
- else {
- copy_qt_qt(rbo->orn, ob->quat);
- }
-
- copy_qt_qt(ob->quat, quat);
- }
-
- if (rbo->shared->physics_object) {
- /* allow passive objects to return to original transform */
- if (rbo->type == RBO_TYPE_PASSIVE)
- RB_body_set_kinematic_state(rbo->shared->physics_object, true);
- RB_body_set_loc_rot(rbo->shared->physics_object, rbo->pos, rbo->orn);
- }
- // RB_TODO update rigid body physics object's loc/rot for dynamic objects here as well (needs to be done outside bullet's update loop)
+void BKE_rigidbody_aftertrans_update(
+ Object *ob, float loc[3], float rot[3], float quat[4], float rotAxis[3], float rotAngle)
+{
+ RigidBodyOb *rbo = ob->rigidbody_object;
+ bool correct_delta = !(rbo->flag & RBO_FLAG_KINEMATIC || rbo->type == RBO_TYPE_PASSIVE);
+
+ /* return rigid body and object to their initial states */
+ copy_v3_v3(rbo->pos, ob->loc);
+ copy_v3_v3(ob->loc, loc);
+
+ if (correct_delta) {
+ add_v3_v3(rbo->pos, ob->dloc);
+ }
+
+ if (ob->rotmode > 0) {
+ float qt[4];
+ eulO_to_quat(qt, ob->rot, ob->rotmode);
+
+ if (correct_delta) {
+ float dquat[4];
+ eulO_to_quat(dquat, ob->drot, ob->rotmode);
+
+ mul_qt_qtqt(rbo->orn, dquat, qt);
+ }
+ else {
+ copy_qt_qt(rbo->orn, qt);
+ }
+
+ copy_v3_v3(ob->rot, rot);
+ }
+ else if (ob->rotmode == ROT_MODE_AXISANGLE) {
+ float qt[4];
+ axis_angle_to_quat(qt, ob->rotAxis, ob->rotAngle);
+
+ if (correct_delta) {
+ float dquat[4];
+ axis_angle_to_quat(dquat, ob->drotAxis, ob->drotAngle);
+
+ mul_qt_qtqt(rbo->orn, dquat, qt);
+ }
+ else {
+ copy_qt_qt(rbo->orn, qt);
+ }
+
+ copy_v3_v3(ob->rotAxis, rotAxis);
+ ob->rotAngle = rotAngle;
+ }
+ else {
+ if (correct_delta) {
+ mul_qt_qtqt(rbo->orn, ob->dquat, ob->quat);
+ }
+ else {
+ copy_qt_qt(rbo->orn, ob->quat);
+ }
+
+ copy_qt_qt(ob->quat, quat);
+ }
+
+ if (rbo->shared->physics_object) {
+ /* allow passive objects to return to original transform */
+ if (rbo->type == RBO_TYPE_PASSIVE)
+ RB_body_set_kinematic_state(rbo->shared->physics_object, true);
+ RB_body_set_loc_rot(rbo->shared->physics_object, rbo->pos, rbo->orn);
+ }
+ // RB_TODO update rigid body physics object's loc/rot for dynamic objects here as well (needs to be done outside bullet's update loop)
}
void BKE_rigidbody_cache_reset(RigidBodyWorld *rbw)
{
- if (rbw) {
- rbw->shared->pointcache->flag |= PTCACHE_OUTDATED;
- }
+ if (rbw) {
+ rbw->shared->pointcache->flag |= PTCACHE_OUTDATED;
+ }
}
/* ------------------ */
@@ -1660,183 +1710,239 @@ void BKE_rigidbody_cache_reset(RigidBodyWorld *rbw)
/* NOTE: this needs to be called before frame update to work correctly */
void BKE_rigidbody_rebuild_world(Depsgraph *depsgraph, Scene *scene, float ctime)
{
- RigidBodyWorld *rbw = scene->rigidbody_world;
- PointCache *cache;
- PTCacheID pid;
- int startframe, endframe;
-
- BKE_ptcache_id_from_rigidbody(&pid, NULL, rbw);
- BKE_ptcache_id_time(&pid, scene, ctime, &startframe, &endframe, NULL);
- cache = rbw->shared->pointcache;
-
- /* flag cache as outdated if we don't have a world or number of objects in the simulation has changed */
- int n = 0;
- FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object)
- {
- (void)object;
- n++;
- }
- FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
-
- if (rbw->shared->physics_world == NULL || rbw->numbodies != n) {
- cache->flag |= PTCACHE_OUTDATED;
- }
-
- if (ctime == startframe + 1 && rbw->ltime == startframe) {
- if (cache->flag & PTCACHE_OUTDATED) {
- BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
- rigidbody_update_simulation(depsgraph, scene, rbw, true);
- BKE_ptcache_validate(cache, (int)ctime);
- cache->last_exact = 0;
- cache->flag &= ~PTCACHE_REDO_NEEDED;
- }
- }
+ RigidBodyWorld *rbw = scene->rigidbody_world;
+ PointCache *cache;
+ PTCacheID pid;
+ int startframe, endframe;
+
+ BKE_ptcache_id_from_rigidbody(&pid, NULL, rbw);
+ BKE_ptcache_id_time(&pid, scene, ctime, &startframe, &endframe, NULL);
+ cache = rbw->shared->pointcache;
+
+ /* flag cache as outdated if we don't have a world or number of objects in the simulation has changed */
+ int n = 0;
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->group, object) {
+ (void)object;
+ n++;
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+
+ if (rbw->shared->physics_world == NULL || rbw->numbodies != n) {
+ cache->flag |= PTCACHE_OUTDATED;
+ }
+
+ if (ctime == startframe + 1 && rbw->ltime == startframe) {
+ if (cache->flag & PTCACHE_OUTDATED) {
+ BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
+ rigidbody_update_simulation(depsgraph, scene, rbw, true);
+ BKE_ptcache_validate(cache, (int)ctime);
+ cache->last_exact = 0;
+ cache->flag &= ~PTCACHE_REDO_NEEDED;
+ }
+ }
}
/* Run RigidBody simulation for the specified physics world */
void BKE_rigidbody_do_simulation(Depsgraph *depsgraph, Scene *scene, float ctime)
{
- float timestep;
- RigidBodyWorld *rbw = scene->rigidbody_world;
- PointCache *cache;
- PTCacheID pid;
- int startframe, endframe;
-
- BKE_ptcache_id_from_rigidbody(&pid, NULL, rbw);
- BKE_ptcache_id_time(&pid, scene, ctime, &startframe, &endframe, NULL);
- cache = rbw->shared->pointcache;
-
- if (ctime <= startframe) {
- rbw->ltime = startframe;
- return;
- }
- /* make sure we don't go out of cache frame range */
- else if (ctime > endframe) {
- ctime = endframe;
- }
-
- /* don't try to run the simulation if we don't have a world yet but allow reading baked cache */
- if (rbw->shared->physics_world == NULL && !(cache->flag & PTCACHE_BAKED))
- return;
- else if (rbw->objects == NULL)
- rigidbody_update_ob_array(rbw);
-
- /* try to read from cache */
- // RB_TODO deal with interpolated, old and baked results
- bool can_simulate = (ctime == rbw->ltime + 1) && !(cache->flag & PTCACHE_BAKED);
-
- if (BKE_ptcache_read(&pid, ctime, can_simulate) == PTCACHE_READ_EXACT) {
- BKE_ptcache_validate(cache, (int)ctime);
- rbw->ltime = ctime;
- return;
- }
-
- if (!DEG_is_active(depsgraph)) {
- /* When the depsgraph is inactive we should neither write to the cache
- * nor run the simulation. */
- return;
- }
-
- /* advance simulation, we can only step one frame forward */
- if (compare_ff_relative(ctime, rbw->ltime + 1, FLT_EPSILON, 64)) {
- /* write cache for first frame when on second frame */
- if (rbw->ltime == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact == 0)) {
- BKE_ptcache_write(&pid, startframe);
- }
-
- /* update and validate simulation */
- rigidbody_update_simulation(depsgraph, scene, rbw, false);
-
- /* calculate how much time elapsed since last step in seconds */
- timestep = 1.0f / (float)FPS * (ctime - rbw->ltime) * rbw->time_scale;
- /* step simulation by the requested timestep, steps per second are adjusted to take time scale into account */
- RB_dworld_step_simulation(rbw->shared->physics_world, timestep, INT_MAX, 1.0f / (float)rbw->steps_per_second * min_ff(rbw->time_scale, 1.0f));
-
- rigidbody_update_simulation_post_step(depsgraph, rbw);
-
- /* write cache for current frame */
- BKE_ptcache_validate(cache, (int)ctime);
- BKE_ptcache_write(&pid, (unsigned int)ctime);
-
- rbw->ltime = ctime;
- }
+ float timestep;
+ RigidBodyWorld *rbw = scene->rigidbody_world;
+ PointCache *cache;
+ PTCacheID pid;
+ int startframe, endframe;
+
+ BKE_ptcache_id_from_rigidbody(&pid, NULL, rbw);
+ BKE_ptcache_id_time(&pid, scene, ctime, &startframe, &endframe, NULL);
+ cache = rbw->shared->pointcache;
+
+ if (ctime <= startframe) {
+ rbw->ltime = startframe;
+ return;
+ }
+ /* make sure we don't go out of cache frame range */
+ else if (ctime > endframe) {
+ ctime = endframe;
+ }
+
+ /* don't try to run the simulation if we don't have a world yet but allow reading baked cache */
+ if (rbw->shared->physics_world == NULL && !(cache->flag & PTCACHE_BAKED))
+ return;
+ else if (rbw->objects == NULL)
+ rigidbody_update_ob_array(rbw);
+
+ /* try to read from cache */
+ // RB_TODO deal with interpolated, old and baked results
+ bool can_simulate = (ctime == rbw->ltime + 1) && !(cache->flag & PTCACHE_BAKED);
+
+ if (BKE_ptcache_read(&pid, ctime, can_simulate) == PTCACHE_READ_EXACT) {
+ BKE_ptcache_validate(cache, (int)ctime);
+ rbw->ltime = ctime;
+ return;
+ }
+
+ if (!DEG_is_active(depsgraph)) {
+ /* When the depsgraph is inactive we should neither write to the cache
+ * nor run the simulation. */
+ return;
+ }
+
+ /* advance simulation, we can only step one frame forward */
+ if (compare_ff_relative(ctime, rbw->ltime + 1, FLT_EPSILON, 64)) {
+ /* write cache for first frame when on second frame */
+ if (rbw->ltime == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact == 0)) {
+ BKE_ptcache_write(&pid, startframe);
+ }
+
+ /* update and validate simulation */
+ rigidbody_update_simulation(depsgraph, scene, rbw, false);
+
+ /* calculate how much time elapsed since last step in seconds */
+ timestep = 1.0f / (float)FPS * (ctime - rbw->ltime) * rbw->time_scale;
+ /* step simulation by the requested timestep, steps per second are adjusted to take time scale into account */
+ RB_dworld_step_simulation(rbw->shared->physics_world,
+ timestep,
+ INT_MAX,
+ 1.0f / (float)rbw->steps_per_second * min_ff(rbw->time_scale, 1.0f));
+
+ rigidbody_update_simulation_post_step(depsgraph, rbw);
+
+ /* write cache for current frame */
+ BKE_ptcache_validate(cache, (int)ctime);
+ BKE_ptcache_write(&pid, (unsigned int)ctime);
+
+ rbw->ltime = ctime;
+ }
}
/* ************************************** */
-#else /* WITH_BULLET */
+#else /* WITH_BULLET */
/* stubs */
-#if defined(__GNUC__) || defined(__clang__)
-# pragma GCC diagnostic push
-# pragma GCC diagnostic ignored "-Wunused-parameter"
-#endif
+# if defined(__GNUC__) || defined(__clang__)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wunused-parameter"
+# endif
-struct RigidBodyOb *BKE_rigidbody_copy_object(const Object *ob, const int flag) { return NULL; }
-struct RigidBodyCon *BKE_rigidbody_copy_constraint(const Object *ob, const int flag) { return NULL; }
-void BKE_rigidbody_validate_sim_world(Scene *scene, RigidBodyWorld *rbw, bool rebuild) {}
-void BKE_rigidbody_calc_volume(Object *ob, float *r_vol) { if (r_vol) *r_vol = 0.0f; }
-void BKE_rigidbody_calc_center_of_mass(Object *ob, float r_center[3]) { zero_v3(r_center); }
-struct RigidBodyWorld *BKE_rigidbody_create_world(Scene *scene) { return NULL; }
-struct RigidBodyWorld *BKE_rigidbody_world_copy(RigidBodyWorld *rbw, const int flag) { return NULL; }
-void BKE_rigidbody_world_groups_relink(struct RigidBodyWorld *rbw) {}
-void BKE_rigidbody_world_id_loop(struct RigidBodyWorld *rbw, RigidbodyWorldIDFunc func, void *userdata) {}
-struct RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type) { return NULL; }
-struct RigidBodyCon *BKE_rigidbody_create_constraint(Scene *scene, Object *ob, short type) { return NULL; }
-struct RigidBodyWorld *BKE_rigidbody_get_world(Scene *scene) { return NULL; }
-void BKE_rigidbody_remove_object(struct Main *bmain, Scene *scene, Object *ob) {}
-void BKE_rigidbody_remove_constraint(Scene *scene, Object *ob) {}
-void BKE_rigidbody_sync_transforms(RigidBodyWorld *rbw, Object *ob, float ctime) {}
-void BKE_rigidbody_aftertrans_update(Object *ob, float loc[3], float rot[3], float quat[4], float rotAxis[3], float rotAngle) {}
-bool BKE_rigidbody_check_sim_running(RigidBodyWorld *rbw, float ctime) { return false; }
-void BKE_rigidbody_cache_reset(RigidBodyWorld *rbw) {}
-void BKE_rigidbody_rebuild_world(Depsgraph *depsgraph, Scene *scene, float ctime) {}
-void BKE_rigidbody_do_simulation(Depsgraph *depsgraph, Scene *scene, float ctime) {}
-void BKE_rigidbody_objects_collection_validate(Scene *scene, RigidBodyWorld *rbw) {}
-void BKE_rigidbody_constraints_collection_validate(Scene *scene, RigidBodyWorld *rbw) {}
-void BKE_rigidbody_main_collection_object_add(Main *bmain, Collection *collection, Object *object) {}
-
-#if defined(__GNUC__) || defined(__clang__)
-# pragma GCC diagnostic pop
-#endif
-
-#endif /* WITH_BULLET */
+struct RigidBodyOb *BKE_rigidbody_copy_object(const Object *ob, const int flag)
+{
+ return NULL;
+}
+struct RigidBodyCon *BKE_rigidbody_copy_constraint(const Object *ob, const int flag)
+{
+ return NULL;
+}
+void BKE_rigidbody_validate_sim_world(Scene *scene, RigidBodyWorld *rbw, bool rebuild)
+{
+}
+void BKE_rigidbody_calc_volume(Object *ob, float *r_vol)
+{
+ if (r_vol)
+ *r_vol = 0.0f;
+}
+void BKE_rigidbody_calc_center_of_mass(Object *ob, float r_center[3])
+{
+ zero_v3(r_center);
+}
+struct RigidBodyWorld *BKE_rigidbody_create_world(Scene *scene)
+{
+ return NULL;
+}
+struct RigidBodyWorld *BKE_rigidbody_world_copy(RigidBodyWorld *rbw, const int flag)
+{
+ return NULL;
+}
+void BKE_rigidbody_world_groups_relink(struct RigidBodyWorld *rbw)
+{
+}
+void BKE_rigidbody_world_id_loop(struct RigidBodyWorld *rbw,
+ RigidbodyWorldIDFunc func,
+ void *userdata)
+{
+}
+struct RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type)
+{
+ return NULL;
+}
+struct RigidBodyCon *BKE_rigidbody_create_constraint(Scene *scene, Object *ob, short type)
+{
+ return NULL;
+}
+struct RigidBodyWorld *BKE_rigidbody_get_world(Scene *scene)
+{
+ return NULL;
+}
+void BKE_rigidbody_remove_object(struct Main *bmain, Scene *scene, Object *ob)
+{
+}
+void BKE_rigidbody_remove_constraint(Scene *scene, Object *ob)
+{
+}
+void BKE_rigidbody_sync_transforms(RigidBodyWorld *rbw, Object *ob, float ctime)
+{
+}
+void BKE_rigidbody_aftertrans_update(
+ Object *ob, float loc[3], float rot[3], float quat[4], float rotAxis[3], float rotAngle)
+{
+}
+bool BKE_rigidbody_check_sim_running(RigidBodyWorld *rbw, float ctime)
+{
+ return false;
+}
+void BKE_rigidbody_cache_reset(RigidBodyWorld *rbw)
+{
+}
+void BKE_rigidbody_rebuild_world(Depsgraph *depsgraph, Scene *scene, float ctime)
+{
+}
+void BKE_rigidbody_do_simulation(Depsgraph *depsgraph, Scene *scene, float ctime)
+{
+}
+void BKE_rigidbody_objects_collection_validate(Scene *scene, RigidBodyWorld *rbw)
+{
+}
+void BKE_rigidbody_constraints_collection_validate(Scene *scene, RigidBodyWorld *rbw)
+{
+}
+void BKE_rigidbody_main_collection_object_add(Main *bmain, Collection *collection, Object *object)
+{
+}
+# if defined(__GNUC__) || defined(__clang__)
+# pragma GCC diagnostic pop
+# endif
+#endif /* WITH_BULLET */
/* -------------------- */
/* Depsgraph evaluation */
-void BKE_rigidbody_rebuild_sim(Depsgraph *depsgraph,
- Scene *scene)
+void BKE_rigidbody_rebuild_sim(Depsgraph *depsgraph, Scene *scene)
{
- float ctime = DEG_get_ctime(depsgraph);
- DEG_debug_print_eval_time(depsgraph, __func__, scene->id.name, scene, ctime);
- /* rebuild sim data (i.e. after resetting to start of timeline) */
- if (BKE_scene_check_rigidbody_active(scene)) {
- BKE_rigidbody_rebuild_world(depsgraph, scene, ctime);
- }
+ float ctime = DEG_get_ctime(depsgraph);
+ DEG_debug_print_eval_time(depsgraph, __func__, scene->id.name, scene, ctime);
+ /* rebuild sim data (i.e. after resetting to start of timeline) */
+ if (BKE_scene_check_rigidbody_active(scene)) {
+ BKE_rigidbody_rebuild_world(depsgraph, scene, ctime);
+ }
}
-void BKE_rigidbody_eval_simulation(Depsgraph *depsgraph,
- Scene *scene)
+void BKE_rigidbody_eval_simulation(Depsgraph *depsgraph, Scene *scene)
{
- float ctime = DEG_get_ctime(depsgraph);
- DEG_debug_print_eval_time(depsgraph, __func__, scene->id.name, scene, ctime);
-
- /* evaluate rigidbody sim */
- if (!BKE_scene_check_rigidbody_active(scene)) {
- return;
- }
- BKE_rigidbody_do_simulation(depsgraph, scene, ctime);
+ float ctime = DEG_get_ctime(depsgraph);
+ DEG_debug_print_eval_time(depsgraph, __func__, scene->id.name, scene, ctime);
+
+ /* evaluate rigidbody sim */
+ if (!BKE_scene_check_rigidbody_active(scene)) {
+ return;
+ }
+ BKE_rigidbody_do_simulation(depsgraph, scene, ctime);
}
-void BKE_rigidbody_object_sync_transforms(Depsgraph *depsgraph,
- Scene *scene,
- Object *ob)
+void BKE_rigidbody_object_sync_transforms(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- RigidBodyWorld *rbw = scene->rigidbody_world;
- float ctime = DEG_get_ctime(depsgraph);
- DEG_debug_print_eval_time(depsgraph, __func__, ob->id.name, ob, ctime);
- /* read values pushed into RBO from sim/cache... */
- BKE_rigidbody_sync_transforms(rbw, ob, ctime);
+ RigidBodyWorld *rbw = scene->rigidbody_world;
+ float ctime = DEG_get_ctime(depsgraph);
+ DEG_debug_print_eval_time(depsgraph, __func__, ob->id.name, ob, ctime);
+ /* read values pushed into RBO from sim/cache... */
+ BKE_rigidbody_sync_transforms(rbw, ob, ctime);
}
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 361459c7c18..5fad95c54e2 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -21,7 +21,6 @@
* \ingroup bke
*/
-
#include <stddef.h>
#include <stdio.h>
#include <string.h>
@@ -109,120 +108,120 @@ const char *RE_engine_id_CYCLES = "CYCLES";
void free_avicodecdata(AviCodecData *acd)
{
- if (acd) {
- if (acd->lpFormat) {
- MEM_freeN(acd->lpFormat);
- acd->lpFormat = NULL;
- acd->cbFormat = 0;
- }
- if (acd->lpParms) {
- MEM_freeN(acd->lpParms);
- acd->lpParms = NULL;
- acd->cbParms = 0;
- }
- }
+ if (acd) {
+ if (acd->lpFormat) {
+ MEM_freeN(acd->lpFormat);
+ acd->lpFormat = NULL;
+ acd->cbFormat = 0;
+ }
+ if (acd->lpParms) {
+ MEM_freeN(acd->lpParms);
+ acd->lpParms = NULL;
+ acd->cbParms = 0;
+ }
+ }
}
static void remove_sequencer_fcurves(Scene *sce)
{
- AnimData *adt = BKE_animdata_from_id(&sce->id);
+ AnimData *adt = BKE_animdata_from_id(&sce->id);
- if (adt && adt->action) {
- FCurve *fcu, *nextfcu;
+ if (adt && adt->action) {
+ FCurve *fcu, *nextfcu;
- for (fcu = adt->action->curves.first; fcu; fcu = nextfcu) {
- nextfcu = fcu->next;
+ for (fcu = adt->action->curves.first; fcu; fcu = nextfcu) {
+ nextfcu = fcu->next;
- if ((fcu->rna_path) && strstr(fcu->rna_path, "sequences_all")) {
- action_groups_remove_channel(adt->action, fcu);
- free_fcurve(fcu);
- }
- }
- }
+ if ((fcu->rna_path) && strstr(fcu->rna_path, "sequences_all")) {
+ action_groups_remove_channel(adt->action, fcu);
+ free_fcurve(fcu);
+ }
+ }
+ }
}
/* flag -- copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). */
ToolSettings *BKE_toolsettings_copy(ToolSettings *toolsettings, const int flag)
{
- if (toolsettings == NULL) {
- return NULL;
- }
- ToolSettings *ts = MEM_dupallocN(toolsettings);
- if (ts->vpaint) {
- ts->vpaint = MEM_dupallocN(ts->vpaint);
- BKE_paint_copy(&ts->vpaint->paint, &ts->vpaint->paint, flag);
- }
- if (ts->wpaint) {
- ts->wpaint = MEM_dupallocN(ts->wpaint);
- BKE_paint_copy(&ts->wpaint->paint, &ts->wpaint->paint, flag);
- }
- if (ts->sculpt) {
- ts->sculpt = MEM_dupallocN(ts->sculpt);
- BKE_paint_copy(&ts->sculpt->paint, &ts->sculpt->paint, flag);
- }
- if (ts->uvsculpt) {
- ts->uvsculpt = MEM_dupallocN(ts->uvsculpt);
- BKE_paint_copy(&ts->uvsculpt->paint, &ts->uvsculpt->paint, flag);
- }
- if (ts->gp_paint) {
- ts->gp_paint = MEM_dupallocN(ts->gp_paint);
- BKE_paint_copy(&ts->gp_paint->paint, &ts->gp_paint->paint, flag);
- }
-
- BKE_paint_copy(&ts->imapaint.paint, &ts->imapaint.paint, flag);
- ts->imapaint.paintcursor = NULL;
- ts->particle.paintcursor = NULL;
- ts->particle.scene = NULL;
- ts->particle.object = NULL;
-
- /* duplicate Grease Pencil interpolation curve */
- ts->gp_interpolate.custom_ipo = curvemapping_copy(ts->gp_interpolate.custom_ipo);
- /* duplicate Grease Pencil multiframe fallof */
- ts->gp_sculpt.cur_falloff = curvemapping_copy(ts->gp_sculpt.cur_falloff);
- ts->gp_sculpt.cur_primitive = curvemapping_copy(ts->gp_sculpt.cur_primitive);
- return ts;
+ if (toolsettings == NULL) {
+ return NULL;
+ }
+ ToolSettings *ts = MEM_dupallocN(toolsettings);
+ if (ts->vpaint) {
+ ts->vpaint = MEM_dupallocN(ts->vpaint);
+ BKE_paint_copy(&ts->vpaint->paint, &ts->vpaint->paint, flag);
+ }
+ if (ts->wpaint) {
+ ts->wpaint = MEM_dupallocN(ts->wpaint);
+ BKE_paint_copy(&ts->wpaint->paint, &ts->wpaint->paint, flag);
+ }
+ if (ts->sculpt) {
+ ts->sculpt = MEM_dupallocN(ts->sculpt);
+ BKE_paint_copy(&ts->sculpt->paint, &ts->sculpt->paint, flag);
+ }
+ if (ts->uvsculpt) {
+ ts->uvsculpt = MEM_dupallocN(ts->uvsculpt);
+ BKE_paint_copy(&ts->uvsculpt->paint, &ts->uvsculpt->paint, flag);
+ }
+ if (ts->gp_paint) {
+ ts->gp_paint = MEM_dupallocN(ts->gp_paint);
+ BKE_paint_copy(&ts->gp_paint->paint, &ts->gp_paint->paint, flag);
+ }
+
+ BKE_paint_copy(&ts->imapaint.paint, &ts->imapaint.paint, flag);
+ ts->imapaint.paintcursor = NULL;
+ ts->particle.paintcursor = NULL;
+ ts->particle.scene = NULL;
+ ts->particle.object = NULL;
+
+ /* duplicate Grease Pencil interpolation curve */
+ ts->gp_interpolate.custom_ipo = curvemapping_copy(ts->gp_interpolate.custom_ipo);
+ /* duplicate Grease Pencil multiframe fallof */
+ ts->gp_sculpt.cur_falloff = curvemapping_copy(ts->gp_sculpt.cur_falloff);
+ ts->gp_sculpt.cur_primitive = curvemapping_copy(ts->gp_sculpt.cur_primitive);
+ return ts;
}
void BKE_toolsettings_free(ToolSettings *toolsettings)
{
- if (toolsettings == NULL) {
- return;
- }
- if (toolsettings->vpaint) {
- BKE_paint_free(&toolsettings->vpaint->paint);
- MEM_freeN(toolsettings->vpaint);
- }
- if (toolsettings->wpaint) {
- BKE_paint_free(&toolsettings->wpaint->paint);
- MEM_freeN(toolsettings->wpaint);
- }
- if (toolsettings->sculpt) {
- BKE_paint_free(&toolsettings->sculpt->paint);
- MEM_freeN(toolsettings->sculpt);
- }
- if (toolsettings->uvsculpt) {
- BKE_paint_free(&toolsettings->uvsculpt->paint);
- MEM_freeN(toolsettings->uvsculpt);
- }
- if (toolsettings->gp_paint) {
- BKE_paint_free(&toolsettings->gp_paint->paint);
- MEM_freeN(toolsettings->gp_paint);
- }
- BKE_paint_free(&toolsettings->imapaint.paint);
-
- /* free Grease Pencil interpolation curve */
- if (toolsettings->gp_interpolate.custom_ipo) {
- curvemapping_free(toolsettings->gp_interpolate.custom_ipo);
- }
- /* free Grease Pencil multiframe falloff curve */
- if (toolsettings->gp_sculpt.cur_falloff) {
- curvemapping_free(toolsettings->gp_sculpt.cur_falloff);
- }
- if (toolsettings->gp_sculpt.cur_primitive) {
- curvemapping_free(toolsettings->gp_sculpt.cur_primitive);
- }
-
- MEM_freeN(toolsettings);
+ if (toolsettings == NULL) {
+ return;
+ }
+ if (toolsettings->vpaint) {
+ BKE_paint_free(&toolsettings->vpaint->paint);
+ MEM_freeN(toolsettings->vpaint);
+ }
+ if (toolsettings->wpaint) {
+ BKE_paint_free(&toolsettings->wpaint->paint);
+ MEM_freeN(toolsettings->wpaint);
+ }
+ if (toolsettings->sculpt) {
+ BKE_paint_free(&toolsettings->sculpt->paint);
+ MEM_freeN(toolsettings->sculpt);
+ }
+ if (toolsettings->uvsculpt) {
+ BKE_paint_free(&toolsettings->uvsculpt->paint);
+ MEM_freeN(toolsettings->uvsculpt);
+ }
+ if (toolsettings->gp_paint) {
+ BKE_paint_free(&toolsettings->gp_paint->paint);
+ MEM_freeN(toolsettings->gp_paint);
+ }
+ BKE_paint_free(&toolsettings->imapaint.paint);
+
+ /* free Grease Pencil interpolation curve */
+ if (toolsettings->gp_interpolate.custom_ipo) {
+ curvemapping_free(toolsettings->gp_interpolate.custom_ipo);
+ }
+ /* free Grease Pencil multiframe falloff curve */
+ if (toolsettings->gp_sculpt.cur_falloff) {
+ curvemapping_free(toolsettings->gp_sculpt.cur_falloff);
+ }
+ if (toolsettings->gp_sculpt.cur_primitive) {
+ curvemapping_free(toolsettings->gp_sculpt.cur_primitive);
+ }
+
+ MEM_freeN(toolsettings);
}
/**
@@ -235,738 +234,746 @@ void BKE_toolsettings_free(ToolSettings *toolsettings)
*/
void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, const int flag)
{
- /* We never handle usercount here for own data. */
- const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
-
- sce_dst->ed = NULL;
- sce_dst->depsgraph_hash = NULL;
- sce_dst->fps_info = NULL;
-
- /* Master Collection */
- if (sce_src->master_collection) {
- sce_dst->master_collection = BKE_collection_copy_master(bmain, sce_src->master_collection, flag);
- }
-
- /* View Layers */
- BLI_duplicatelist(&sce_dst->view_layers, &sce_src->view_layers);
- for (ViewLayer *view_layer_src = sce_src->view_layers.first, *view_layer_dst = sce_dst->view_layers.first;
- view_layer_src;
- view_layer_src = view_layer_src->next, view_layer_dst = view_layer_dst->next)
- {
- BKE_view_layer_copy_data(sce_dst, sce_src, view_layer_dst, view_layer_src, flag_subdata);
- }
-
- BLI_duplicatelist(&(sce_dst->markers), &(sce_src->markers));
- BLI_duplicatelist(&(sce_dst->transform_spaces), &(sce_src->transform_spaces));
- BLI_duplicatelist(&(sce_dst->r.views), &(sce_src->r.views));
- BKE_keyingsets_copy(&(sce_dst->keyingsets), &(sce_src->keyingsets));
-
- if (sce_src->nodetree) {
- /* Note: nodetree is *not* in bmain, however this specific case is handled at lower level
- * (see BKE_libblock_copy_ex()). */
- BKE_id_copy_ex(bmain, (ID *)sce_src->nodetree, (ID **)&sce_dst->nodetree, flag);
- BKE_libblock_relink_ex(bmain, sce_dst->nodetree, (void *)(&sce_src->id), &sce_dst->id, false);
- }
-
- if (sce_src->rigidbody_world) {
- sce_dst->rigidbody_world = BKE_rigidbody_world_copy(sce_src->rigidbody_world, flag_subdata);
- }
-
- /* copy color management settings */
- BKE_color_managed_display_settings_copy(&sce_dst->display_settings, &sce_src->display_settings);
- BKE_color_managed_view_settings_copy(&sce_dst->view_settings, &sce_src->view_settings);
- BKE_color_managed_colorspace_settings_copy(&sce_dst->sequencer_colorspace_settings, &sce_src->sequencer_colorspace_settings);
-
- BKE_color_managed_display_settings_copy(&sce_dst->r.im_format.display_settings, &sce_src->r.im_format.display_settings);
- BKE_color_managed_view_settings_copy(&sce_dst->r.im_format.view_settings, &sce_src->r.im_format.view_settings);
-
- BKE_color_managed_display_settings_copy(&sce_dst->r.bake.im_format.display_settings, &sce_src->r.bake.im_format.display_settings);
- BKE_color_managed_view_settings_copy(&sce_dst->r.bake.im_format.view_settings, &sce_src->r.bake.im_format.view_settings);
-
- curvemapping_copy_data(&sce_dst->r.mblur_shutter_curve, &sce_src->r.mblur_shutter_curve);
-
- /* tool settings */
- sce_dst->toolsettings = BKE_toolsettings_copy(sce_dst->toolsettings, flag_subdata);
-
- /* make a private copy of the avicodecdata */
- if (sce_src->r.avicodecdata) {
- sce_dst->r.avicodecdata = MEM_dupallocN(sce_src->r.avicodecdata);
- sce_dst->r.avicodecdata->lpFormat = MEM_dupallocN(sce_dst->r.avicodecdata->lpFormat);
- sce_dst->r.avicodecdata->lpParms = MEM_dupallocN(sce_dst->r.avicodecdata->lpParms);
- }
-
- if (sce_src->r.ffcodecdata.properties) { /* intentionally check sce_dst not sce_src. */ /* XXX ??? comment outdated... */
- sce_dst->r.ffcodecdata.properties = IDP_CopyProperty_ex(sce_src->r.ffcodecdata.properties, flag_subdata);
- }
-
- /* before scene copy */
- BKE_sound_create_scene(sce_dst);
-
- /* Copy sequencer, this is local data! */
- if (sce_src->ed) {
- sce_dst->ed = MEM_callocN(sizeof(*sce_dst->ed), __func__);
- sce_dst->ed->seqbasep = &sce_dst->ed->seqbase;
- BKE_sequence_base_dupli_recursive(
- sce_src, sce_dst, &sce_dst->ed->seqbase, &sce_src->ed->seqbase, SEQ_DUPE_ALL, flag_subdata);
- }
-
- if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
- BKE_previewimg_id_copy(&sce_dst->id, &sce_src->id);
- }
- else {
- sce_dst->preview = NULL;
- }
-
- sce_dst->eevee.light_cache = NULL;
- sce_dst->eevee.light_cache_info[0] = '\0';
- /* TODO Copy the cache. */
+ /* We never handle usercount here for own data. */
+ const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
+
+ sce_dst->ed = NULL;
+ sce_dst->depsgraph_hash = NULL;
+ sce_dst->fps_info = NULL;
+
+ /* Master Collection */
+ if (sce_src->master_collection) {
+ sce_dst->master_collection = BKE_collection_copy_master(
+ bmain, sce_src->master_collection, flag);
+ }
+
+ /* View Layers */
+ BLI_duplicatelist(&sce_dst->view_layers, &sce_src->view_layers);
+ for (ViewLayer *view_layer_src = sce_src->view_layers.first,
+ *view_layer_dst = sce_dst->view_layers.first;
+ view_layer_src;
+ view_layer_src = view_layer_src->next, view_layer_dst = view_layer_dst->next) {
+ BKE_view_layer_copy_data(sce_dst, sce_src, view_layer_dst, view_layer_src, flag_subdata);
+ }
+
+ BLI_duplicatelist(&(sce_dst->markers), &(sce_src->markers));
+ BLI_duplicatelist(&(sce_dst->transform_spaces), &(sce_src->transform_spaces));
+ BLI_duplicatelist(&(sce_dst->r.views), &(sce_src->r.views));
+ BKE_keyingsets_copy(&(sce_dst->keyingsets), &(sce_src->keyingsets));
+
+ if (sce_src->nodetree) {
+ /* Note: nodetree is *not* in bmain, however this specific case is handled at lower level
+ * (see BKE_libblock_copy_ex()). */
+ BKE_id_copy_ex(bmain, (ID *)sce_src->nodetree, (ID **)&sce_dst->nodetree, flag);
+ BKE_libblock_relink_ex(bmain, sce_dst->nodetree, (void *)(&sce_src->id), &sce_dst->id, false);
+ }
+
+ if (sce_src->rigidbody_world) {
+ sce_dst->rigidbody_world = BKE_rigidbody_world_copy(sce_src->rigidbody_world, flag_subdata);
+ }
+
+ /* copy color management settings */
+ BKE_color_managed_display_settings_copy(&sce_dst->display_settings, &sce_src->display_settings);
+ BKE_color_managed_view_settings_copy(&sce_dst->view_settings, &sce_src->view_settings);
+ BKE_color_managed_colorspace_settings_copy(&sce_dst->sequencer_colorspace_settings,
+ &sce_src->sequencer_colorspace_settings);
+
+ BKE_color_managed_display_settings_copy(&sce_dst->r.im_format.display_settings,
+ &sce_src->r.im_format.display_settings);
+ BKE_color_managed_view_settings_copy(&sce_dst->r.im_format.view_settings,
+ &sce_src->r.im_format.view_settings);
+
+ BKE_color_managed_display_settings_copy(&sce_dst->r.bake.im_format.display_settings,
+ &sce_src->r.bake.im_format.display_settings);
+ BKE_color_managed_view_settings_copy(&sce_dst->r.bake.im_format.view_settings,
+ &sce_src->r.bake.im_format.view_settings);
+
+ curvemapping_copy_data(&sce_dst->r.mblur_shutter_curve, &sce_src->r.mblur_shutter_curve);
+
+ /* tool settings */
+ sce_dst->toolsettings = BKE_toolsettings_copy(sce_dst->toolsettings, flag_subdata);
+
+ /* make a private copy of the avicodecdata */
+ if (sce_src->r.avicodecdata) {
+ sce_dst->r.avicodecdata = MEM_dupallocN(sce_src->r.avicodecdata);
+ sce_dst->r.avicodecdata->lpFormat = MEM_dupallocN(sce_dst->r.avicodecdata->lpFormat);
+ sce_dst->r.avicodecdata->lpParms = MEM_dupallocN(sce_dst->r.avicodecdata->lpParms);
+ }
+
+ if (sce_src->r.ffcodecdata.properties) {
+ /* intentionally check sce_dst not sce_src. */ /* XXX ??? comment outdated... */
+ sce_dst->r.ffcodecdata.properties = IDP_CopyProperty_ex(sce_src->r.ffcodecdata.properties,
+ flag_subdata);
+ }
+
+ /* before scene copy */
+ BKE_sound_create_scene(sce_dst);
+
+ /* Copy sequencer, this is local data! */
+ if (sce_src->ed) {
+ sce_dst->ed = MEM_callocN(sizeof(*sce_dst->ed), __func__);
+ sce_dst->ed->seqbasep = &sce_dst->ed->seqbase;
+ BKE_sequence_base_dupli_recursive(sce_src,
+ sce_dst,
+ &sce_dst->ed->seqbase,
+ &sce_src->ed->seqbase,
+ SEQ_DUPE_ALL,
+ flag_subdata);
+ }
+
+ if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
+ BKE_previewimg_id_copy(&sce_dst->id, &sce_src->id);
+ }
+ else {
+ sce_dst->preview = NULL;
+ }
+
+ sce_dst->eevee.light_cache = NULL;
+ sce_dst->eevee.light_cache_info[0] = '\0';
+ /* TODO Copy the cache. */
}
Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
{
- Scene *sce_copy;
-
- /* TODO this should/could most likely be replaced by call to more generic code at some point...
- * But for now, let's keep it well isolated here. */
- if (type == SCE_COPY_EMPTY) {
- ListBase rv;
-
- sce_copy = BKE_scene_add(bmain, sce->id.name + 2);
-
- rv = sce_copy->r.views;
- curvemapping_free_data(&sce_copy->r.mblur_shutter_curve);
- sce_copy->r = sce->r;
- sce_copy->r.views = rv;
- sce_copy->unit = sce->unit;
- sce_copy->physics_settings = sce->physics_settings;
- sce_copy->audio = sce->audio;
- sce_copy->eevee = sce->eevee;
- sce_copy->eevee.light_cache = NULL;
- sce_copy->eevee.light_cache_info[0] = '\0';
-
- if (sce->id.properties)
- sce_copy->id.properties = IDP_CopyProperty(sce->id.properties);
-
- MEM_freeN(sce_copy->toolsettings);
- BKE_sound_destroy_scene(sce_copy);
-
- /* copy color management settings */
- BKE_color_managed_display_settings_copy(&sce_copy->display_settings, &sce->display_settings);
- BKE_color_managed_view_settings_copy(&sce_copy->view_settings, &sce->view_settings);
- BKE_color_managed_colorspace_settings_copy(&sce_copy->sequencer_colorspace_settings, &sce->sequencer_colorspace_settings);
-
- BKE_color_managed_display_settings_copy(&sce_copy->r.im_format.display_settings, &sce->r.im_format.display_settings);
- BKE_color_managed_view_settings_copy(&sce_copy->r.im_format.view_settings, &sce->r.im_format.view_settings);
-
- BKE_color_managed_display_settings_copy(&sce_copy->r.bake.im_format.display_settings, &sce->r.bake.im_format.display_settings);
- BKE_color_managed_view_settings_copy(&sce_copy->r.bake.im_format.view_settings, &sce->r.bake.im_format.view_settings);
-
- curvemapping_copy_data(&sce_copy->r.mblur_shutter_curve, &sce->r.mblur_shutter_curve);
-
- /* viewport display settings */
- sce_copy->display = sce->display;
-
- /* tool settings */
- sce_copy->toolsettings = BKE_toolsettings_copy(sce->toolsettings, 0);
-
- /* make a private copy of the avicodecdata */
- if (sce->r.avicodecdata) {
- sce_copy->r.avicodecdata = MEM_dupallocN(sce->r.avicodecdata);
- sce_copy->r.avicodecdata->lpFormat = MEM_dupallocN(sce_copy->r.avicodecdata->lpFormat);
- sce_copy->r.avicodecdata->lpParms = MEM_dupallocN(sce_copy->r.avicodecdata->lpParms);
- }
-
- if (sce->r.ffcodecdata.properties) { /* intentionally check scen not sce. */
- sce_copy->r.ffcodecdata.properties = IDP_CopyProperty(sce->r.ffcodecdata.properties);
- }
-
- /* before scene copy */
- BKE_sound_create_scene(sce_copy);
-
- /* grease pencil */
- sce_copy->gpd = NULL;
-
- sce_copy->preview = NULL;
-
- return sce_copy;
- }
- else {
- BKE_id_copy_ex(bmain, (ID *)sce, (ID **)&sce_copy, LIB_ID_COPY_ACTIONS);
- id_us_min(&sce_copy->id);
- id_us_ensure_real(&sce_copy->id);
-
- /* Extra actions, most notably SCE_FULL_COPY also duplicates several 'children' datablocks... */
-
- if (type == SCE_COPY_FULL) {
- /* Copy Freestyle LineStyle datablocks. */
- for (ViewLayer *view_layer_dst = sce_copy->view_layers.first; view_layer_dst; view_layer_dst = view_layer_dst->next) {
- for (FreestyleLineSet *lineset = view_layer_dst->freestyle_config.linesets.first; lineset; lineset = lineset->next) {
- if (lineset->linestyle) {
- id_us_min(&lineset->linestyle->id);
- BKE_id_copy_ex(
- bmain,
- (ID *)lineset->linestyle,
- (ID **)&lineset->linestyle,
- LIB_ID_COPY_ACTIONS);
- }
- }
- }
-
- /* Full copy of world (included animations) */
- if (sce_copy->world) {
- id_us_min(&sce_copy->world->id);
- BKE_id_copy_ex(bmain, (ID *)sce_copy->world, (ID **)&sce_copy->world, LIB_ID_COPY_ACTIONS);
- }
-
- /* Full copy of GreasePencil. */
- if (sce_copy->gpd) {
- id_us_min(&sce_copy->gpd->id);
- BKE_id_copy_ex(bmain, (ID *)sce_copy->gpd, (ID **)&sce_copy->gpd, LIB_ID_COPY_ACTIONS);
- }
- }
- else {
- /* Remove sequencer if not full copy */
- /* XXX Why in Hell? :/ */
- remove_sequencer_fcurves(sce_copy);
- BKE_sequencer_editing_free(sce_copy, true);
- }
-
- /* NOTE: part of SCE_COPY_FULL operations
- * are done outside of blenkernel with ED_object_single_users! */
-
- return sce_copy;
- }
+ Scene *sce_copy;
+
+ /* TODO this should/could most likely be replaced by call to more generic code at some point...
+ * But for now, let's keep it well isolated here. */
+ if (type == SCE_COPY_EMPTY) {
+ ListBase rv;
+
+ sce_copy = BKE_scene_add(bmain, sce->id.name + 2);
+
+ rv = sce_copy->r.views;
+ curvemapping_free_data(&sce_copy->r.mblur_shutter_curve);
+ sce_copy->r = sce->r;
+ sce_copy->r.views = rv;
+ sce_copy->unit = sce->unit;
+ sce_copy->physics_settings = sce->physics_settings;
+ sce_copy->audio = sce->audio;
+ sce_copy->eevee = sce->eevee;
+ sce_copy->eevee.light_cache = NULL;
+ sce_copy->eevee.light_cache_info[0] = '\0';
+
+ if (sce->id.properties)
+ sce_copy->id.properties = IDP_CopyProperty(sce->id.properties);
+
+ MEM_freeN(sce_copy->toolsettings);
+ BKE_sound_destroy_scene(sce_copy);
+
+ /* copy color management settings */
+ BKE_color_managed_display_settings_copy(&sce_copy->display_settings, &sce->display_settings);
+ BKE_color_managed_view_settings_copy(&sce_copy->view_settings, &sce->view_settings);
+ BKE_color_managed_colorspace_settings_copy(&sce_copy->sequencer_colorspace_settings,
+ &sce->sequencer_colorspace_settings);
+
+ BKE_color_managed_display_settings_copy(&sce_copy->r.im_format.display_settings,
+ &sce->r.im_format.display_settings);
+ BKE_color_managed_view_settings_copy(&sce_copy->r.im_format.view_settings,
+ &sce->r.im_format.view_settings);
+
+ BKE_color_managed_display_settings_copy(&sce_copy->r.bake.im_format.display_settings,
+ &sce->r.bake.im_format.display_settings);
+ BKE_color_managed_view_settings_copy(&sce_copy->r.bake.im_format.view_settings,
+ &sce->r.bake.im_format.view_settings);
+
+ curvemapping_copy_data(&sce_copy->r.mblur_shutter_curve, &sce->r.mblur_shutter_curve);
+
+ /* viewport display settings */
+ sce_copy->display = sce->display;
+
+ /* tool settings */
+ sce_copy->toolsettings = BKE_toolsettings_copy(sce->toolsettings, 0);
+
+ /* make a private copy of the avicodecdata */
+ if (sce->r.avicodecdata) {
+ sce_copy->r.avicodecdata = MEM_dupallocN(sce->r.avicodecdata);
+ sce_copy->r.avicodecdata->lpFormat = MEM_dupallocN(sce_copy->r.avicodecdata->lpFormat);
+ sce_copy->r.avicodecdata->lpParms = MEM_dupallocN(sce_copy->r.avicodecdata->lpParms);
+ }
+
+ if (sce->r.ffcodecdata.properties) { /* intentionally check scen not sce. */
+ sce_copy->r.ffcodecdata.properties = IDP_CopyProperty(sce->r.ffcodecdata.properties);
+ }
+
+ /* before scene copy */
+ BKE_sound_create_scene(sce_copy);
+
+ /* grease pencil */
+ sce_copy->gpd = NULL;
+
+ sce_copy->preview = NULL;
+
+ return sce_copy;
+ }
+ else {
+ BKE_id_copy_ex(bmain, (ID *)sce, (ID **)&sce_copy, LIB_ID_COPY_ACTIONS);
+ id_us_min(&sce_copy->id);
+ id_us_ensure_real(&sce_copy->id);
+
+ /* Extra actions, most notably SCE_FULL_COPY also duplicates several 'children' datablocks... */
+
+ if (type == SCE_COPY_FULL) {
+ /* Copy Freestyle LineStyle datablocks. */
+ for (ViewLayer *view_layer_dst = sce_copy->view_layers.first; view_layer_dst;
+ view_layer_dst = view_layer_dst->next) {
+ for (FreestyleLineSet *lineset = view_layer_dst->freestyle_config.linesets.first; lineset;
+ lineset = lineset->next) {
+ if (lineset->linestyle) {
+ id_us_min(&lineset->linestyle->id);
+ BKE_id_copy_ex(
+ bmain, (ID *)lineset->linestyle, (ID **)&lineset->linestyle, LIB_ID_COPY_ACTIONS);
+ }
+ }
+ }
+
+ /* Full copy of world (included animations) */
+ if (sce_copy->world) {
+ id_us_min(&sce_copy->world->id);
+ BKE_id_copy_ex(bmain, (ID *)sce_copy->world, (ID **)&sce_copy->world, LIB_ID_COPY_ACTIONS);
+ }
+
+ /* Full copy of GreasePencil. */
+ if (sce_copy->gpd) {
+ id_us_min(&sce_copy->gpd->id);
+ BKE_id_copy_ex(bmain, (ID *)sce_copy->gpd, (ID **)&sce_copy->gpd, LIB_ID_COPY_ACTIONS);
+ }
+ }
+ else {
+ /* Remove sequencer if not full copy */
+ /* XXX Why in Hell? :/ */
+ remove_sequencer_fcurves(sce_copy);
+ BKE_sequencer_editing_free(sce_copy, true);
+ }
+
+ /* NOTE: part of SCE_COPY_FULL operations
+ * are done outside of blenkernel with ED_object_single_users! */
+
+ return sce_copy;
+ }
}
void BKE_scene_groups_relink(Scene *sce)
{
- if (sce->rigidbody_world)
- BKE_rigidbody_world_groups_relink(sce->rigidbody_world);
+ if (sce->rigidbody_world)
+ BKE_rigidbody_world_groups_relink(sce->rigidbody_world);
}
void BKE_scene_make_local(Main *bmain, Scene *sce, const bool lib_local)
{
- /* For now should work, may need more work though to support all possible corner cases
- * (also scene_copy probably needs some love). */
- BKE_id_make_local_generic(bmain, &sce->id, true, lib_local);
+ /* For now should work, may need more work though to support all possible corner cases
+ * (also scene_copy probably needs some love). */
+ BKE_id_make_local_generic(bmain, &sce->id, true, lib_local);
}
/** Free (or release) any data used by this scene (does not free the scene itself). */
void BKE_scene_free_ex(Scene *sce, const bool do_id_user)
{
- BKE_animdata_free((ID *)sce, false);
+ BKE_animdata_free((ID *)sce, false);
- BKE_sequencer_editing_free(sce, do_id_user);
+ BKE_sequencer_editing_free(sce, do_id_user);
- BKE_keyingsets_free(&sce->keyingsets);
+ BKE_keyingsets_free(&sce->keyingsets);
- /* is no lib link block, but scene extension */
- if (sce->nodetree) {
- ntreeFreeNestedTree(sce->nodetree);
- MEM_freeN(sce->nodetree);
- sce->nodetree = NULL;
- }
+ /* is no lib link block, but scene extension */
+ if (sce->nodetree) {
+ ntreeFreeNestedTree(sce->nodetree);
+ MEM_freeN(sce->nodetree);
+ sce->nodetree = NULL;
+ }
- if (sce->rigidbody_world) {
- BKE_rigidbody_free_world(sce);
- }
+ if (sce->rigidbody_world) {
+ BKE_rigidbody_free_world(sce);
+ }
- if (sce->r.avicodecdata) {
- free_avicodecdata(sce->r.avicodecdata);
- MEM_freeN(sce->r.avicodecdata);
- sce->r.avicodecdata = NULL;
- }
- if (sce->r.ffcodecdata.properties) {
- IDP_FreeProperty(sce->r.ffcodecdata.properties);
- MEM_freeN(sce->r.ffcodecdata.properties);
- sce->r.ffcodecdata.properties = NULL;
- }
+ if (sce->r.avicodecdata) {
+ free_avicodecdata(sce->r.avicodecdata);
+ MEM_freeN(sce->r.avicodecdata);
+ sce->r.avicodecdata = NULL;
+ }
+ if (sce->r.ffcodecdata.properties) {
+ IDP_FreeProperty(sce->r.ffcodecdata.properties);
+ MEM_freeN(sce->r.ffcodecdata.properties);
+ sce->r.ffcodecdata.properties = NULL;
+ }
- BLI_freelistN(&sce->markers);
- BLI_freelistN(&sce->transform_spaces);
- BLI_freelistN(&sce->r.views);
+ BLI_freelistN(&sce->markers);
+ BLI_freelistN(&sce->transform_spaces);
+ BLI_freelistN(&sce->r.views);
- BKE_toolsettings_free(sce->toolsettings);
- sce->toolsettings = NULL;
+ BKE_toolsettings_free(sce->toolsettings);
+ sce->toolsettings = NULL;
- BKE_scene_free_depsgraph_hash(sce);
+ BKE_scene_free_depsgraph_hash(sce);
- MEM_SAFE_FREE(sce->fps_info);
+ MEM_SAFE_FREE(sce->fps_info);
- BKE_sound_destroy_scene(sce);
+ BKE_sound_destroy_scene(sce);
- BKE_color_managed_view_settings_free(&sce->view_settings);
+ BKE_color_managed_view_settings_free(&sce->view_settings);
- BKE_previewimg_free(&sce->preview);
- curvemapping_free_data(&sce->r.mblur_shutter_curve);
+ BKE_previewimg_free(&sce->preview);
+ curvemapping_free_data(&sce->r.mblur_shutter_curve);
- for (ViewLayer *view_layer = sce->view_layers.first, *view_layer_next; view_layer; view_layer = view_layer_next) {
- view_layer_next = view_layer->next;
+ for (ViewLayer *view_layer = sce->view_layers.first, *view_layer_next; view_layer;
+ view_layer = view_layer_next) {
+ view_layer_next = view_layer->next;
- BLI_remlink(&sce->view_layers, view_layer);
- BKE_view_layer_free_ex(view_layer, do_id_user);
- }
+ BLI_remlink(&sce->view_layers, view_layer);
+ BKE_view_layer_free_ex(view_layer, do_id_user);
+ }
- /* Master Collection */
- // TODO: what to do with do_id_user? it's also true when just
- // closing the file which seems wrong? should decrement users
- // for objects directly in the master collection? then other
- // collections in the scene need to do it too?
- if (sce->master_collection) {
- BKE_collection_free(sce->master_collection);
- MEM_freeN(sce->master_collection);
- sce->master_collection = NULL;
- }
+ /* Master Collection */
+ // TODO: what to do with do_id_user? it's also true when just
+ // closing the file which seems wrong? should decrement users
+ // for objects directly in the master collection? then other
+ // collections in the scene need to do it too?
+ if (sce->master_collection) {
+ BKE_collection_free(sce->master_collection);
+ MEM_freeN(sce->master_collection);
+ sce->master_collection = NULL;
+ }
- if (sce->eevee.light_cache) {
- EEVEE_lightcache_free(sce->eevee.light_cache);
- sce->eevee.light_cache = NULL;
- }
+ if (sce->eevee.light_cache) {
+ EEVEE_lightcache_free(sce->eevee.light_cache);
+ sce->eevee.light_cache = NULL;
+ }
- /* These are freed on doversion. */
- BLI_assert(sce->layer_properties == NULL);
+ /* These are freed on doversion. */
+ BLI_assert(sce->layer_properties == NULL);
}
void BKE_scene_free(Scene *sce)
{
- BKE_scene_free_ex(sce, true);
+ BKE_scene_free_ex(sce, true);
}
void BKE_scene_init(Scene *sce)
{
- ParticleEditSettings *pset;
- int a;
- const char *colorspace_name;
- SceneRenderView *srv;
- CurveMapping *mblur_shutter_curve;
-
- BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(sce, id));
-
-
- sce->cursor.rotation_mode = ROT_MODE_XYZ;
- sce->cursor.rotation_quaternion[0] = 1.0f;
- sce->cursor.rotation_axis[1] = 1.0f;
-
- sce->r.mode = R_OSA;
- sce->r.cfra = 1;
- sce->r.sfra = 1;
- sce->r.efra = 250;
- sce->r.frame_step = 1;
- sce->r.xsch = 1920;
- sce->r.ysch = 1080;
- sce->r.xasp = 1;
- sce->r.yasp = 1;
- sce->r.tilex = 256;
- sce->r.tiley = 256;
- sce->r.size = 100;
-
- sce->r.im_format.planes = R_IMF_PLANES_RGBA;
- sce->r.im_format.imtype = R_IMF_IMTYPE_PNG;
- sce->r.im_format.depth = R_IMF_CHAN_DEPTH_8;
- sce->r.im_format.quality = 90;
- sce->r.im_format.compress = 15;
-
- sce->r.displaymode = R_OUTPUT_WINDOW;
- sce->r.framapto = 100;
- sce->r.images = 100;
- sce->r.framelen = 1.0;
- sce->r.blurfac = 0.5;
- sce->r.frs_sec = 24;
- sce->r.frs_sec_base = 1;
-
- /* OCIO_TODO: for forwards compatibility only, so if no tonecurve are used,
- * images would look in the same way as in current blender
- *
- * perhaps at some point should be completely deprecated?
- */
- sce->r.color_mgt_flag |= R_COLOR_MANAGEMENT;
-
- sce->r.gauss = 1.5;
- sce->r.dither_intensity = 1.0f;
-
- sce->r.bake_mode = 0;
- sce->r.bake_filter = 16;
- sce->r.bake_flag = R_BAKE_CLEAR;
- sce->r.bake_samples = 256;
- sce->r.bake_biasdist = 0.001;
-
- sce->r.bake.flag = R_BAKE_CLEAR;
- sce->r.bake.pass_filter = R_BAKE_PASS_FILTER_ALL;
- sce->r.bake.width = 512;
- sce->r.bake.height = 512;
- sce->r.bake.margin = 16;
- sce->r.bake.normal_space = R_BAKE_SPACE_TANGENT;
- sce->r.bake.normal_swizzle[0] = R_BAKE_POSX;
- sce->r.bake.normal_swizzle[1] = R_BAKE_POSY;
- sce->r.bake.normal_swizzle[2] = R_BAKE_POSZ;
- BLI_strncpy(sce->r.bake.filepath, U.renderdir, sizeof(sce->r.bake.filepath));
-
- sce->r.bake.im_format.planes = R_IMF_PLANES_RGBA;
- sce->r.bake.im_format.imtype = R_IMF_IMTYPE_PNG;
- sce->r.bake.im_format.depth = R_IMF_CHAN_DEPTH_8;
- sce->r.bake.im_format.quality = 90;
- sce->r.bake.im_format.compress = 15;
-
- sce->r.scemode = R_DOCOMP | R_DOSEQ | R_EXTENSION;
- sce->r.stamp = R_STAMP_TIME | R_STAMP_FRAME | R_STAMP_DATE | R_STAMP_CAMERA | R_STAMP_SCENE | R_STAMP_FILENAME | R_STAMP_RENDERTIME | R_STAMP_MEMORY;
- sce->r.stamp_font_id = 12;
- sce->r.fg_stamp[0] = sce->r.fg_stamp[1] = sce->r.fg_stamp[2] = 0.8f;
- sce->r.fg_stamp[3] = 1.0f;
- sce->r.bg_stamp[0] = sce->r.bg_stamp[1] = sce->r.bg_stamp[2] = 0.0f;
- sce->r.bg_stamp[3] = 0.25f;
-
- sce->r.seq_prev_type = OB_SOLID;
- sce->r.seq_rend_type = OB_SOLID;
- sce->r.seq_flag = 0;
-
- sce->r.threads = 1;
-
- sce->r.simplify_subsurf = 6;
- sce->r.simplify_particles = 1.0f;
-
- sce->r.border.xmin = 0.0f;
- sce->r.border.ymin = 0.0f;
- sce->r.border.xmax = 1.0f;
- sce->r.border.ymax = 1.0f;
-
- sce->r.preview_start_resolution = 64;
-
- sce->r.line_thickness_mode = R_LINE_THICKNESS_ABSOLUTE;
- sce->r.unit_line_thickness = 1.0f;
-
- mblur_shutter_curve = &sce->r.mblur_shutter_curve;
- curvemapping_set_defaults(mblur_shutter_curve, 1, 0.0f, 0.0f, 1.0f, 1.0f);
- curvemapping_initialize(mblur_shutter_curve);
- curvemap_reset(mblur_shutter_curve->cm,
- &mblur_shutter_curve->clipr,
- CURVE_PRESET_MAX,
- CURVEMAP_SLOPE_POS_NEG);
-
- sce->toolsettings = MEM_callocN(sizeof(struct ToolSettings), "Tool Settings Struct");
-
- sce->toolsettings->object_flag |= SCE_OBJECT_MODE_LOCK;
- sce->toolsettings->doublimit = 0.001;
- sce->toolsettings->vgroup_weight = 1.0f;
- sce->toolsettings->uvcalc_margin = 0.001f;
- sce->toolsettings->uvcalc_flag = UVCALC_TRANSFORM_CORRECT;
- sce->toolsettings->unwrapper = 1;
- sce->toolsettings->select_thresh = 0.01f;
-
- sce->toolsettings->selectmode = SCE_SELECT_VERTEX;
- sce->toolsettings->uv_selectmode = UV_SELECT_VERTEX;
- sce->toolsettings->autokey_mode = U.autokey_mode;
-
-
- sce->toolsettings->transform_pivot_point = V3D_AROUND_CENTER_MEDIAN;
- sce->toolsettings->snap_mode = SCE_SNAP_MODE_INCREMENT;
- sce->toolsettings->snap_node_mode = SCE_SNAP_MODE_GRID;
- sce->toolsettings->snap_uv_mode = SCE_SNAP_MODE_INCREMENT;
- sce->toolsettings->snap_transform_mode_flag = SCE_SNAP_TRANSFORM_MODE_TRANSLATE;
-
- sce->toolsettings->curve_paint_settings.curve_type = CU_BEZIER;
- sce->toolsettings->curve_paint_settings.flag |= CURVE_PAINT_FLAG_CORNERS_DETECT;
- sce->toolsettings->curve_paint_settings.error_threshold = 8;
- sce->toolsettings->curve_paint_settings.radius_max = 1.0f;
- sce->toolsettings->curve_paint_settings.corner_angle = DEG2RADF(70.0f);
-
- sce->toolsettings->statvis.overhang_axis = OB_NEGZ;
- sce->toolsettings->statvis.overhang_min = 0;
- sce->toolsettings->statvis.overhang_max = DEG2RADF(45.0f);
- sce->toolsettings->statvis.thickness_max = 0.1f;
- sce->toolsettings->statvis.thickness_samples = 1;
- sce->toolsettings->statvis.distort_min = DEG2RADF(5.0f);
- sce->toolsettings->statvis.distort_max = DEG2RADF(45.0f);
-
- sce->toolsettings->statvis.sharp_min = DEG2RADF(90.0f);
- sce->toolsettings->statvis.sharp_max = DEG2RADF(180.0f);
-
- sce->toolsettings->proportional_size = 1.0f;
-
- sce->toolsettings->imapaint.paint.flags |= PAINT_SHOW_BRUSH;
- sce->toolsettings->imapaint.normal_angle = 80;
- sce->toolsettings->imapaint.seam_bleed = 2;
-
- /* grease pencil multiframe falloff curve */
- sce->toolsettings->gp_sculpt.cur_falloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
- CurveMapping *gp_falloff_curve = sce->toolsettings->gp_sculpt.cur_falloff;
- curvemapping_initialize(gp_falloff_curve);
- curvemap_reset(
- gp_falloff_curve->cm,
- &gp_falloff_curve->clipr,
- CURVE_PRESET_GAUSS,
- CURVEMAP_SLOPE_POSITIVE);
-
- sce->toolsettings->gp_sculpt.cur_primitive = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
- CurveMapping *gp_primitive_curve = sce->toolsettings->gp_sculpt.cur_primitive;
- curvemapping_initialize(gp_primitive_curve);
- curvemap_reset(
- gp_primitive_curve->cm,
- &gp_primitive_curve->clipr,
- CURVE_PRESET_BELL,
- CURVEMAP_SLOPE_POSITIVE);
-
- sce->toolsettings->gp_sculpt.guide.spacing = 20.0f;
-
- sce->physics_settings.gravity[0] = 0.0f;
- sce->physics_settings.gravity[1] = 0.0f;
- sce->physics_settings.gravity[2] = -9.81f;
- sce->physics_settings.flag = PHYS_GLOBAL_GRAVITY;
-
- sce->unit.system = USER_UNIT_METRIC;
- sce->unit.scale_length = 1.0f;
- sce->unit.length_unit = bUnit_GetBaseUnitOfType(USER_UNIT_METRIC, B_UNIT_LENGTH);
- sce->unit.mass_unit = bUnit_GetBaseUnitOfType(USER_UNIT_METRIC, B_UNIT_MASS);
- sce->unit.time_unit = bUnit_GetBaseUnitOfType(USER_UNIT_METRIC, B_UNIT_TIME);
-
- pset = &sce->toolsettings->particle;
- pset->flag = PE_KEEP_LENGTHS | PE_LOCK_FIRST | PE_DEFLECT_EMITTER | PE_AUTO_VELOCITY;
- pset->emitterdist = 0.25f;
- pset->totrekey = 5;
- pset->totaddkey = 5;
- pset->brushtype = PE_BRUSH_COMB;
- pset->draw_step = 2;
- pset->fade_frames = 2;
- pset->selectmode = SCE_SELECT_PATH;
-
- for (a = 0; a < ARRAY_SIZE(pset->brush); a++) {
- pset->brush[a].strength = 0.5f;
- pset->brush[a].size = 50;
- pset->brush[a].step = 10;
- pset->brush[a].count = 10;
- }
- pset->brush[PE_BRUSH_CUT].strength = 1.0f;
-
- sce->r.ffcodecdata.audio_mixrate = 48000;
- sce->r.ffcodecdata.audio_volume = 1.0f;
- sce->r.ffcodecdata.audio_bitrate = 192;
- sce->r.ffcodecdata.audio_channels = 2;
-
- BLI_strncpy(sce->r.engine, RE_engine_id_BLENDER_EEVEE, sizeof(sce->r.engine));
-
- sce->audio.distance_model = 2.0f;
- sce->audio.doppler_factor = 1.0f;
- sce->audio.speed_of_sound = 343.3f;
- sce->audio.volume = 1.0f;
- sce->audio.flag = AUDIO_SYNC;
-
- BLI_strncpy(sce->r.pic, U.renderdir, sizeof(sce->r.pic));
-
- BLI_rctf_init(&sce->r.safety, 0.1f, 0.9f, 0.1f, 0.9f);
- sce->r.osa = 8;
-
- /* note; in header_info.c the scene copy happens..., if you add more to renderdata it has to be checked there */
-
- /* multiview - stereo */
- BKE_scene_add_render_view(sce, STEREO_LEFT_NAME);
- srv = sce->r.views.first;
- BLI_strncpy(srv->suffix, STEREO_LEFT_SUFFIX, sizeof(srv->suffix));
-
- BKE_scene_add_render_view(sce, STEREO_RIGHT_NAME);
- srv = sce->r.views.last;
- BLI_strncpy(srv->suffix, STEREO_RIGHT_SUFFIX, sizeof(srv->suffix));
-
- BKE_sound_create_scene(sce);
-
- /* color management */
- colorspace_name = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DEFAULT_SEQUENCER);
-
- BKE_color_managed_display_settings_init(&sce->display_settings);
- BKE_color_managed_view_settings_init_render(&sce->view_settings,
- &sce->display_settings,
- "Filmic");
- BLI_strncpy(sce->sequencer_colorspace_settings.name, colorspace_name,
- sizeof(sce->sequencer_colorspace_settings.name));
-
- /* Those next two sets (render and baking settings) are not currently in use,
- * but are exposed to RNA API and hence must have valid data. */
- BKE_color_managed_display_settings_init(&sce->r.im_format.display_settings);
- BKE_color_managed_view_settings_init_render(&sce->r.im_format.view_settings,
- &sce->r.im_format.display_settings,
- "Filmic");
-
- BKE_color_managed_display_settings_init(&sce->r.bake.im_format.display_settings);
- BKE_color_managed_view_settings_init_render(&sce->r.bake.im_format.view_settings,
- &sce->r.bake.im_format.display_settings,
- "Filmic");
-
- /* Safe Areas */
- copy_v2_fl2(sce->safe_areas.title, 10.0f / 100.0f, 5.0f / 100.0f);
- copy_v2_fl2(sce->safe_areas.action, 3.5f / 100.0f, 3.5f / 100.0f);
- copy_v2_fl2(sce->safe_areas.title_center, 17.5f / 100.0f, 5.0f / 100.0f);
- copy_v2_fl2(sce->safe_areas.action_center, 15.0f / 100.0f, 5.0f / 100.0f);
-
- sce->preview = NULL;
-
- /* GP Sculpt brushes */
- {
- GP_Sculpt_Settings *gset = &sce->toolsettings->gp_sculpt;
- GP_Sculpt_Data *gp_brush;
- float curcolor_add[3], curcolor_sub[3];
- ARRAY_SET_ITEMS(curcolor_add, 1.0f, 0.6f, 0.6f);
- ARRAY_SET_ITEMS(curcolor_sub, 0.6f, 0.6f, 1.0f);
-
- gp_brush = &gset->brush[GP_SCULPT_TYPE_SMOOTH];
- gp_brush->size = 25;
- gp_brush->strength = 0.3f;
- gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_SMOOTH_PRESSURE | GP_SCULPT_FLAG_ENABLE_CURSOR;
- copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
- copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
-
- gp_brush = &gset->brush[GP_SCULPT_TYPE_THICKNESS];
- gp_brush->size = 25;
- gp_brush->strength = 0.5f;
- gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR;
- copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
- copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
-
- gp_brush = &gset->brush[GP_SCULPT_TYPE_STRENGTH];
- gp_brush->size = 25;
- gp_brush->strength = 0.5f;
- gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR;
- copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
- copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
-
- gp_brush = &gset->brush[GP_SCULPT_TYPE_GRAB];
- gp_brush->size = 50;
- gp_brush->strength = 0.3f;
- gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR;
- copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
- copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
-
- gp_brush = &gset->brush[GP_SCULPT_TYPE_PUSH];
- gp_brush->size = 25;
- gp_brush->strength = 0.3f;
- gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR;
- copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
- copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
-
- gp_brush = &gset->brush[GP_SCULPT_TYPE_TWIST];
- gp_brush->size = 50;
- gp_brush->strength = 0.3f;
- gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR;
- copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
- copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
-
- gp_brush = &gset->brush[GP_SCULPT_TYPE_PINCH];
- gp_brush->size = 50;
- gp_brush->strength = 0.5f;
- gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR;
- copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
- copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
-
- gp_brush = &gset->brush[GP_SCULPT_TYPE_RANDOMIZE];
- gp_brush->size = 25;
- gp_brush->strength = 0.5f;
- gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR;
- copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
- copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
- }
-
- /* GP Stroke Placement */
- sce->toolsettings->gpencil_v3d_align = GP_PROJECT_VIEWSPACE;
- sce->toolsettings->gpencil_v2d_align = GP_PROJECT_VIEWSPACE;
- sce->toolsettings->gpencil_seq_align = GP_PROJECT_VIEWSPACE;
- sce->toolsettings->gpencil_ima_align = GP_PROJECT_VIEWSPACE;
-
- /* Annotations */
- sce->toolsettings->annotate_v3d_align = GP_PROJECT_VIEWSPACE | GP_PROJECT_CURSOR;
- sce->toolsettings->annotate_thickness = 3;
-
- for (int i = 0; i < ARRAY_SIZE(sce->orientation_slots); i++) {
- sce->orientation_slots[i].index_custom = -1;
- }
-
- /* Master Collection */
- sce->master_collection = BKE_collection_master_add();
-
- BKE_view_layer_add(sce, "View Layer");
-
- /* SceneDisplay */
- copy_v3_v3(sce->display.light_direction, (float[3]){M_SQRT1_3, M_SQRT1_3, M_SQRT1_3});
- sce->display.shadow_shift = 0.1f;
- sce->display.shadow_focus = 0.0f;
-
- sce->display.matcap_ssao_distance = 0.2f;
- sce->display.matcap_ssao_attenuation = 1.0f;
- sce->display.matcap_ssao_samples = 16;
-
- /* OpenGL Render. */
- BKE_screen_view3d_shading_init(&sce->display.shading);
-
- /* SceneEEVEE */
- sce->eevee.gi_diffuse_bounces = 3;
- sce->eevee.gi_cubemap_resolution = 512;
- sce->eevee.gi_visibility_resolution = 32;
- sce->eevee.gi_cubemap_draw_size = 0.3f;
- sce->eevee.gi_irradiance_draw_size = 0.1f;
- sce->eevee.gi_irradiance_smoothing = 0.1f;
- sce->eevee.gi_filter_quality = 1.0f;
-
- sce->eevee.taa_samples = 16;
- sce->eevee.taa_render_samples = 64;
-
- sce->eevee.sss_samples = 7;
- sce->eevee.sss_jitter_threshold = 0.3f;
-
- sce->eevee.ssr_quality = 0.25f;
- sce->eevee.ssr_max_roughness = 0.5f;
- sce->eevee.ssr_thickness = 0.2f;
- sce->eevee.ssr_border_fade = 0.075f;
- sce->eevee.ssr_firefly_fac = 10.0f;
-
- sce->eevee.volumetric_start = 0.1f;
- sce->eevee.volumetric_end = 100.0f;
- sce->eevee.volumetric_tile_size = 8;
- sce->eevee.volumetric_samples = 64;
- sce->eevee.volumetric_sample_distribution = 0.8f;
- sce->eevee.volumetric_light_clamp = 0.0f;
- sce->eevee.volumetric_shadow_samples = 16;
-
- sce->eevee.gtao_distance = 0.2f;
- sce->eevee.gtao_factor = 1.0f;
- sce->eevee.gtao_quality = 0.25f;
-
- sce->eevee.bokeh_max_size = 100.0f;
- sce->eevee.bokeh_threshold = 1.0f;
-
- copy_v3_fl(sce->eevee.bloom_color, 1.0f);
- sce->eevee.bloom_threshold = 0.8f;
- sce->eevee.bloom_knee = 0.5f;
- sce->eevee.bloom_intensity = 0.05f;
- sce->eevee.bloom_radius = 6.5f;
- sce->eevee.bloom_clamp = 0.0f;
-
- sce->eevee.motion_blur_samples = 8;
- sce->eevee.motion_blur_shutter = 0.5f;
-
- sce->eevee.shadow_method = SHADOW_ESM;
- sce->eevee.shadow_cube_size = 512;
- sce->eevee.shadow_cascade_size = 1024;
-
- sce->eevee.light_cache = NULL;
- sce->eevee.light_threshold = 0.01f;
-
- sce->eevee.overscan = 3.0f;
-
- sce->eevee.flag =
- SCE_EEVEE_VOLUMETRIC_LIGHTS |
- SCE_EEVEE_GTAO_BENT_NORMALS |
- SCE_EEVEE_GTAO_BOUNCE |
- SCE_EEVEE_TAA_REPROJECTION |
- SCE_EEVEE_SSR_HALF_RESOLUTION;
+ ParticleEditSettings *pset;
+ int a;
+ const char *colorspace_name;
+ SceneRenderView *srv;
+ CurveMapping *mblur_shutter_curve;
+
+ BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(sce, id));
+
+ sce->cursor.rotation_mode = ROT_MODE_XYZ;
+ sce->cursor.rotation_quaternion[0] = 1.0f;
+ sce->cursor.rotation_axis[1] = 1.0f;
+
+ sce->r.mode = R_OSA;
+ sce->r.cfra = 1;
+ sce->r.sfra = 1;
+ sce->r.efra = 250;
+ sce->r.frame_step = 1;
+ sce->r.xsch = 1920;
+ sce->r.ysch = 1080;
+ sce->r.xasp = 1;
+ sce->r.yasp = 1;
+ sce->r.tilex = 256;
+ sce->r.tiley = 256;
+ sce->r.size = 100;
+
+ sce->r.im_format.planes = R_IMF_PLANES_RGBA;
+ sce->r.im_format.imtype = R_IMF_IMTYPE_PNG;
+ sce->r.im_format.depth = R_IMF_CHAN_DEPTH_8;
+ sce->r.im_format.quality = 90;
+ sce->r.im_format.compress = 15;
+
+ sce->r.displaymode = R_OUTPUT_WINDOW;
+ sce->r.framapto = 100;
+ sce->r.images = 100;
+ sce->r.framelen = 1.0;
+ sce->r.blurfac = 0.5;
+ sce->r.frs_sec = 24;
+ sce->r.frs_sec_base = 1;
+
+ /* OCIO_TODO: for forwards compatibility only, so if no tonecurve are used,
+ * images would look in the same way as in current blender
+ *
+ * perhaps at some point should be completely deprecated?
+ */
+ sce->r.color_mgt_flag |= R_COLOR_MANAGEMENT;
+
+ sce->r.gauss = 1.5;
+ sce->r.dither_intensity = 1.0f;
+
+ sce->r.bake_mode = 0;
+ sce->r.bake_filter = 16;
+ sce->r.bake_flag = R_BAKE_CLEAR;
+ sce->r.bake_samples = 256;
+ sce->r.bake_biasdist = 0.001;
+
+ sce->r.bake.flag = R_BAKE_CLEAR;
+ sce->r.bake.pass_filter = R_BAKE_PASS_FILTER_ALL;
+ sce->r.bake.width = 512;
+ sce->r.bake.height = 512;
+ sce->r.bake.margin = 16;
+ sce->r.bake.normal_space = R_BAKE_SPACE_TANGENT;
+ sce->r.bake.normal_swizzle[0] = R_BAKE_POSX;
+ sce->r.bake.normal_swizzle[1] = R_BAKE_POSY;
+ sce->r.bake.normal_swizzle[2] = R_BAKE_POSZ;
+ BLI_strncpy(sce->r.bake.filepath, U.renderdir, sizeof(sce->r.bake.filepath));
+
+ sce->r.bake.im_format.planes = R_IMF_PLANES_RGBA;
+ sce->r.bake.im_format.imtype = R_IMF_IMTYPE_PNG;
+ sce->r.bake.im_format.depth = R_IMF_CHAN_DEPTH_8;
+ sce->r.bake.im_format.quality = 90;
+ sce->r.bake.im_format.compress = 15;
+
+ sce->r.scemode = R_DOCOMP | R_DOSEQ | R_EXTENSION;
+ sce->r.stamp = R_STAMP_TIME | R_STAMP_FRAME | R_STAMP_DATE | R_STAMP_CAMERA | R_STAMP_SCENE |
+ R_STAMP_FILENAME | R_STAMP_RENDERTIME | R_STAMP_MEMORY;
+ sce->r.stamp_font_id = 12;
+ sce->r.fg_stamp[0] = sce->r.fg_stamp[1] = sce->r.fg_stamp[2] = 0.8f;
+ sce->r.fg_stamp[3] = 1.0f;
+ sce->r.bg_stamp[0] = sce->r.bg_stamp[1] = sce->r.bg_stamp[2] = 0.0f;
+ sce->r.bg_stamp[3] = 0.25f;
+
+ sce->r.seq_prev_type = OB_SOLID;
+ sce->r.seq_rend_type = OB_SOLID;
+ sce->r.seq_flag = 0;
+
+ sce->r.threads = 1;
+
+ sce->r.simplify_subsurf = 6;
+ sce->r.simplify_particles = 1.0f;
+
+ sce->r.border.xmin = 0.0f;
+ sce->r.border.ymin = 0.0f;
+ sce->r.border.xmax = 1.0f;
+ sce->r.border.ymax = 1.0f;
+
+ sce->r.preview_start_resolution = 64;
+
+ sce->r.line_thickness_mode = R_LINE_THICKNESS_ABSOLUTE;
+ sce->r.unit_line_thickness = 1.0f;
+
+ mblur_shutter_curve = &sce->r.mblur_shutter_curve;
+ curvemapping_set_defaults(mblur_shutter_curve, 1, 0.0f, 0.0f, 1.0f, 1.0f);
+ curvemapping_initialize(mblur_shutter_curve);
+ curvemap_reset(mblur_shutter_curve->cm,
+ &mblur_shutter_curve->clipr,
+ CURVE_PRESET_MAX,
+ CURVEMAP_SLOPE_POS_NEG);
+
+ sce->toolsettings = MEM_callocN(sizeof(struct ToolSettings), "Tool Settings Struct");
+
+ sce->toolsettings->object_flag |= SCE_OBJECT_MODE_LOCK;
+ sce->toolsettings->doublimit = 0.001;
+ sce->toolsettings->vgroup_weight = 1.0f;
+ sce->toolsettings->uvcalc_margin = 0.001f;
+ sce->toolsettings->uvcalc_flag = UVCALC_TRANSFORM_CORRECT;
+ sce->toolsettings->unwrapper = 1;
+ sce->toolsettings->select_thresh = 0.01f;
+
+ sce->toolsettings->selectmode = SCE_SELECT_VERTEX;
+ sce->toolsettings->uv_selectmode = UV_SELECT_VERTEX;
+ sce->toolsettings->autokey_mode = U.autokey_mode;
+
+ sce->toolsettings->transform_pivot_point = V3D_AROUND_CENTER_MEDIAN;
+ sce->toolsettings->snap_mode = SCE_SNAP_MODE_INCREMENT;
+ sce->toolsettings->snap_node_mode = SCE_SNAP_MODE_GRID;
+ sce->toolsettings->snap_uv_mode = SCE_SNAP_MODE_INCREMENT;
+ sce->toolsettings->snap_transform_mode_flag = SCE_SNAP_TRANSFORM_MODE_TRANSLATE;
+
+ sce->toolsettings->curve_paint_settings.curve_type = CU_BEZIER;
+ sce->toolsettings->curve_paint_settings.flag |= CURVE_PAINT_FLAG_CORNERS_DETECT;
+ sce->toolsettings->curve_paint_settings.error_threshold = 8;
+ sce->toolsettings->curve_paint_settings.radius_max = 1.0f;
+ sce->toolsettings->curve_paint_settings.corner_angle = DEG2RADF(70.0f);
+
+ sce->toolsettings->statvis.overhang_axis = OB_NEGZ;
+ sce->toolsettings->statvis.overhang_min = 0;
+ sce->toolsettings->statvis.overhang_max = DEG2RADF(45.0f);
+ sce->toolsettings->statvis.thickness_max = 0.1f;
+ sce->toolsettings->statvis.thickness_samples = 1;
+ sce->toolsettings->statvis.distort_min = DEG2RADF(5.0f);
+ sce->toolsettings->statvis.distort_max = DEG2RADF(45.0f);
+
+ sce->toolsettings->statvis.sharp_min = DEG2RADF(90.0f);
+ sce->toolsettings->statvis.sharp_max = DEG2RADF(180.0f);
+
+ sce->toolsettings->proportional_size = 1.0f;
+
+ sce->toolsettings->imapaint.paint.flags |= PAINT_SHOW_BRUSH;
+ sce->toolsettings->imapaint.normal_angle = 80;
+ sce->toolsettings->imapaint.seam_bleed = 2;
+
+ /* grease pencil multiframe falloff curve */
+ sce->toolsettings->gp_sculpt.cur_falloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ CurveMapping *gp_falloff_curve = sce->toolsettings->gp_sculpt.cur_falloff;
+ curvemapping_initialize(gp_falloff_curve);
+ curvemap_reset(
+ gp_falloff_curve->cm, &gp_falloff_curve->clipr, CURVE_PRESET_GAUSS, CURVEMAP_SLOPE_POSITIVE);
+
+ sce->toolsettings->gp_sculpt.cur_primitive = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ CurveMapping *gp_primitive_curve = sce->toolsettings->gp_sculpt.cur_primitive;
+ curvemapping_initialize(gp_primitive_curve);
+ curvemap_reset(gp_primitive_curve->cm,
+ &gp_primitive_curve->clipr,
+ CURVE_PRESET_BELL,
+ CURVEMAP_SLOPE_POSITIVE);
+
+ sce->toolsettings->gp_sculpt.guide.spacing = 20.0f;
+
+ sce->physics_settings.gravity[0] = 0.0f;
+ sce->physics_settings.gravity[1] = 0.0f;
+ sce->physics_settings.gravity[2] = -9.81f;
+ sce->physics_settings.flag = PHYS_GLOBAL_GRAVITY;
+
+ sce->unit.system = USER_UNIT_METRIC;
+ sce->unit.scale_length = 1.0f;
+ sce->unit.length_unit = bUnit_GetBaseUnitOfType(USER_UNIT_METRIC, B_UNIT_LENGTH);
+ sce->unit.mass_unit = bUnit_GetBaseUnitOfType(USER_UNIT_METRIC, B_UNIT_MASS);
+ sce->unit.time_unit = bUnit_GetBaseUnitOfType(USER_UNIT_METRIC, B_UNIT_TIME);
+
+ pset = &sce->toolsettings->particle;
+ pset->flag = PE_KEEP_LENGTHS | PE_LOCK_FIRST | PE_DEFLECT_EMITTER | PE_AUTO_VELOCITY;
+ pset->emitterdist = 0.25f;
+ pset->totrekey = 5;
+ pset->totaddkey = 5;
+ pset->brushtype = PE_BRUSH_COMB;
+ pset->draw_step = 2;
+ pset->fade_frames = 2;
+ pset->selectmode = SCE_SELECT_PATH;
+
+ for (a = 0; a < ARRAY_SIZE(pset->brush); a++) {
+ pset->brush[a].strength = 0.5f;
+ pset->brush[a].size = 50;
+ pset->brush[a].step = 10;
+ pset->brush[a].count = 10;
+ }
+ pset->brush[PE_BRUSH_CUT].strength = 1.0f;
+
+ sce->r.ffcodecdata.audio_mixrate = 48000;
+ sce->r.ffcodecdata.audio_volume = 1.0f;
+ sce->r.ffcodecdata.audio_bitrate = 192;
+ sce->r.ffcodecdata.audio_channels = 2;
+
+ BLI_strncpy(sce->r.engine, RE_engine_id_BLENDER_EEVEE, sizeof(sce->r.engine));
+
+ sce->audio.distance_model = 2.0f;
+ sce->audio.doppler_factor = 1.0f;
+ sce->audio.speed_of_sound = 343.3f;
+ sce->audio.volume = 1.0f;
+ sce->audio.flag = AUDIO_SYNC;
+
+ BLI_strncpy(sce->r.pic, U.renderdir, sizeof(sce->r.pic));
+
+ BLI_rctf_init(&sce->r.safety, 0.1f, 0.9f, 0.1f, 0.9f);
+ sce->r.osa = 8;
+
+ /* note; in header_info.c the scene copy happens..., if you add more to renderdata it has to be checked there */
+
+ /* multiview - stereo */
+ BKE_scene_add_render_view(sce, STEREO_LEFT_NAME);
+ srv = sce->r.views.first;
+ BLI_strncpy(srv->suffix, STEREO_LEFT_SUFFIX, sizeof(srv->suffix));
+
+ BKE_scene_add_render_view(sce, STEREO_RIGHT_NAME);
+ srv = sce->r.views.last;
+ BLI_strncpy(srv->suffix, STEREO_RIGHT_SUFFIX, sizeof(srv->suffix));
+
+ BKE_sound_create_scene(sce);
+
+ /* color management */
+ colorspace_name = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DEFAULT_SEQUENCER);
+
+ BKE_color_managed_display_settings_init(&sce->display_settings);
+ BKE_color_managed_view_settings_init_render(
+ &sce->view_settings, &sce->display_settings, "Filmic");
+ BLI_strncpy(sce->sequencer_colorspace_settings.name,
+ colorspace_name,
+ sizeof(sce->sequencer_colorspace_settings.name));
+
+ /* Those next two sets (render and baking settings) are not currently in use,
+ * but are exposed to RNA API and hence must have valid data. */
+ BKE_color_managed_display_settings_init(&sce->r.im_format.display_settings);
+ BKE_color_managed_view_settings_init_render(
+ &sce->r.im_format.view_settings, &sce->r.im_format.display_settings, "Filmic");
+
+ BKE_color_managed_display_settings_init(&sce->r.bake.im_format.display_settings);
+ BKE_color_managed_view_settings_init_render(
+ &sce->r.bake.im_format.view_settings, &sce->r.bake.im_format.display_settings, "Filmic");
+
+ /* Safe Areas */
+ copy_v2_fl2(sce->safe_areas.title, 10.0f / 100.0f, 5.0f / 100.0f);
+ copy_v2_fl2(sce->safe_areas.action, 3.5f / 100.0f, 3.5f / 100.0f);
+ copy_v2_fl2(sce->safe_areas.title_center, 17.5f / 100.0f, 5.0f / 100.0f);
+ copy_v2_fl2(sce->safe_areas.action_center, 15.0f / 100.0f, 5.0f / 100.0f);
+
+ sce->preview = NULL;
+
+ /* GP Sculpt brushes */
+ {
+ GP_Sculpt_Settings *gset = &sce->toolsettings->gp_sculpt;
+ GP_Sculpt_Data *gp_brush;
+ float curcolor_add[3], curcolor_sub[3];
+ ARRAY_SET_ITEMS(curcolor_add, 1.0f, 0.6f, 0.6f);
+ ARRAY_SET_ITEMS(curcolor_sub, 0.6f, 0.6f, 1.0f);
+
+ gp_brush = &gset->brush[GP_SCULPT_TYPE_SMOOTH];
+ gp_brush->size = 25;
+ gp_brush->strength = 0.3f;
+ gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_SMOOTH_PRESSURE |
+ GP_SCULPT_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
+ copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
+
+ gp_brush = &gset->brush[GP_SCULPT_TYPE_THICKNESS];
+ gp_brush->size = 25;
+ gp_brush->strength = 0.5f;
+ gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
+ copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
+
+ gp_brush = &gset->brush[GP_SCULPT_TYPE_STRENGTH];
+ gp_brush->size = 25;
+ gp_brush->strength = 0.5f;
+ gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
+ copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
+
+ gp_brush = &gset->brush[GP_SCULPT_TYPE_GRAB];
+ gp_brush->size = 50;
+ gp_brush->strength = 0.3f;
+ gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
+ copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
+
+ gp_brush = &gset->brush[GP_SCULPT_TYPE_PUSH];
+ gp_brush->size = 25;
+ gp_brush->strength = 0.3f;
+ gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
+ copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
+
+ gp_brush = &gset->brush[GP_SCULPT_TYPE_TWIST];
+ gp_brush->size = 50;
+ gp_brush->strength = 0.3f;
+ gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
+ copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
+
+ gp_brush = &gset->brush[GP_SCULPT_TYPE_PINCH];
+ gp_brush->size = 50;
+ gp_brush->strength = 0.5f;
+ gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
+ copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
+
+ gp_brush = &gset->brush[GP_SCULPT_TYPE_RANDOMIZE];
+ gp_brush->size = 25;
+ gp_brush->strength = 0.5f;
+ gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
+ copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
+ }
+
+ /* GP Stroke Placement */
+ sce->toolsettings->gpencil_v3d_align = GP_PROJECT_VIEWSPACE;
+ sce->toolsettings->gpencil_v2d_align = GP_PROJECT_VIEWSPACE;
+ sce->toolsettings->gpencil_seq_align = GP_PROJECT_VIEWSPACE;
+ sce->toolsettings->gpencil_ima_align = GP_PROJECT_VIEWSPACE;
+
+ /* Annotations */
+ sce->toolsettings->annotate_v3d_align = GP_PROJECT_VIEWSPACE | GP_PROJECT_CURSOR;
+ sce->toolsettings->annotate_thickness = 3;
+
+ for (int i = 0; i < ARRAY_SIZE(sce->orientation_slots); i++) {
+ sce->orientation_slots[i].index_custom = -1;
+ }
+
+ /* Master Collection */
+ sce->master_collection = BKE_collection_master_add();
+
+ BKE_view_layer_add(sce, "View Layer");
+
+ /* SceneDisplay */
+ copy_v3_v3(sce->display.light_direction, (float[3]){M_SQRT1_3, M_SQRT1_3, M_SQRT1_3});
+ sce->display.shadow_shift = 0.1f;
+ sce->display.shadow_focus = 0.0f;
+
+ sce->display.matcap_ssao_distance = 0.2f;
+ sce->display.matcap_ssao_attenuation = 1.0f;
+ sce->display.matcap_ssao_samples = 16;
+
+ /* OpenGL Render. */
+ BKE_screen_view3d_shading_init(&sce->display.shading);
+
+ /* SceneEEVEE */
+ sce->eevee.gi_diffuse_bounces = 3;
+ sce->eevee.gi_cubemap_resolution = 512;
+ sce->eevee.gi_visibility_resolution = 32;
+ sce->eevee.gi_cubemap_draw_size = 0.3f;
+ sce->eevee.gi_irradiance_draw_size = 0.1f;
+ sce->eevee.gi_irradiance_smoothing = 0.1f;
+ sce->eevee.gi_filter_quality = 1.0f;
+
+ sce->eevee.taa_samples = 16;
+ sce->eevee.taa_render_samples = 64;
+
+ sce->eevee.sss_samples = 7;
+ sce->eevee.sss_jitter_threshold = 0.3f;
+
+ sce->eevee.ssr_quality = 0.25f;
+ sce->eevee.ssr_max_roughness = 0.5f;
+ sce->eevee.ssr_thickness = 0.2f;
+ sce->eevee.ssr_border_fade = 0.075f;
+ sce->eevee.ssr_firefly_fac = 10.0f;
+
+ sce->eevee.volumetric_start = 0.1f;
+ sce->eevee.volumetric_end = 100.0f;
+ sce->eevee.volumetric_tile_size = 8;
+ sce->eevee.volumetric_samples = 64;
+ sce->eevee.volumetric_sample_distribution = 0.8f;
+ sce->eevee.volumetric_light_clamp = 0.0f;
+ sce->eevee.volumetric_shadow_samples = 16;
+
+ sce->eevee.gtao_distance = 0.2f;
+ sce->eevee.gtao_factor = 1.0f;
+ sce->eevee.gtao_quality = 0.25f;
+
+ sce->eevee.bokeh_max_size = 100.0f;
+ sce->eevee.bokeh_threshold = 1.0f;
+
+ copy_v3_fl(sce->eevee.bloom_color, 1.0f);
+ sce->eevee.bloom_threshold = 0.8f;
+ sce->eevee.bloom_knee = 0.5f;
+ sce->eevee.bloom_intensity = 0.05f;
+ sce->eevee.bloom_radius = 6.5f;
+ sce->eevee.bloom_clamp = 0.0f;
+
+ sce->eevee.motion_blur_samples = 8;
+ sce->eevee.motion_blur_shutter = 0.5f;
+
+ sce->eevee.shadow_method = SHADOW_ESM;
+ sce->eevee.shadow_cube_size = 512;
+ sce->eevee.shadow_cascade_size = 1024;
+
+ sce->eevee.light_cache = NULL;
+ sce->eevee.light_threshold = 0.01f;
+
+ sce->eevee.overscan = 3.0f;
+
+ sce->eevee.flag = SCE_EEVEE_VOLUMETRIC_LIGHTS | SCE_EEVEE_GTAO_BENT_NORMALS |
+ SCE_EEVEE_GTAO_BOUNCE | SCE_EEVEE_TAA_REPROJECTION |
+ SCE_EEVEE_SSR_HALF_RESOLUTION;
}
Scene *BKE_scene_add(Main *bmain, const char *name)
{
- Scene *sce;
+ Scene *sce;
- sce = BKE_libblock_alloc(bmain, ID_SCE, name, 0);
- id_us_min(&sce->id);
- id_us_ensure_real(&sce->id);
+ sce = BKE_libblock_alloc(bmain, ID_SCE, name, 0);
+ id_us_min(&sce->id);
+ id_us_ensure_real(&sce->id);
- BKE_scene_init(sce);
+ BKE_scene_init(sce);
- return sce;
+ return sce;
}
/**
@@ -974,24 +981,26 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
*/
bool BKE_scene_object_find(Scene *scene, Object *ob)
{
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
- if (BLI_findptr(&view_layer->object_bases, ob, offsetof(Base, object))) {
- return true;
- }
- }
- return false;
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
+ view_layer = view_layer->next) {
+ if (BLI_findptr(&view_layer->object_bases, ob, offsetof(Base, object))) {
+ return true;
+ }
+ }
+ return false;
}
Object *BKE_scene_object_find_by_name(Scene *scene, const char *name)
{
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
- if (STREQ(base->object->id.name + 2, name)) {
- return base->object;
- }
- }
- }
- return NULL;
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
+ view_layer = view_layer->next) {
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (STREQ(base->object->id.name + 2, name)) {
+ return base->object;
+ }
+ }
+ }
+ return NULL;
}
/**
@@ -1001,317 +1010,318 @@ Object *BKE_scene_object_find_by_name(Scene *scene, const char *name)
*/
void BKE_scene_set_background(Main *bmain, Scene *scene)
{
- Object *ob;
+ Object *ob;
- /* check for cyclic sets, for reading old files but also for definite security (py?) */
- BKE_scene_validate_setscene(bmain, scene);
+ /* check for cyclic sets, for reading old files but also for definite security (py?) */
+ BKE_scene_validate_setscene(bmain, scene);
- /* deselect objects (for dataselect) */
- for (ob = bmain->objects.first; ob; ob = ob->id.next)
- ob->flag &= ~SELECT;
+ /* deselect objects (for dataselect) */
+ for (ob = bmain->objects.first; ob; ob = ob->id.next)
+ ob->flag &= ~SELECT;
- /* copy layers and flags from bases to objects */
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
- ob = base->object;
- /* collection patch... */
- BKE_scene_object_base_flag_sync_from_base(base);
- }
- }
- /* no full animation update, this to enable render code to work (render code calls own animation updates) */
+ /* copy layers and flags from bases to objects */
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
+ view_layer = view_layer->next) {
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ ob = base->object;
+ /* collection patch... */
+ BKE_scene_object_base_flag_sync_from_base(base);
+ }
+ }
+ /* no full animation update, this to enable render code to work (render code calls own animation updates) */
}
/* called from creator_args.c */
Scene *BKE_scene_set_name(Main *bmain, const char *name)
{
- Scene *sce = (Scene *)BKE_libblock_find_name(bmain, ID_SCE, name);
- if (sce) {
- BKE_scene_set_background(bmain, sce);
- printf("Scene switch for render: '%s' in file: '%s'\n", name, BKE_main_blendfile_path(bmain));
- return sce;
- }
+ Scene *sce = (Scene *)BKE_libblock_find_name(bmain, ID_SCE, name);
+ if (sce) {
+ BKE_scene_set_background(bmain, sce);
+ printf("Scene switch for render: '%s' in file: '%s'\n", name, BKE_main_blendfile_path(bmain));
+ return sce;
+ }
- printf("Can't find scene: '%s' in file: '%s'\n", name, BKE_main_blendfile_path(bmain));
- return NULL;
+ printf("Can't find scene: '%s' in file: '%s'\n", name, BKE_main_blendfile_path(bmain));
+ return NULL;
}
/* Used by metaballs, return *all* objects (including duplis) existing in the scene (including scene's sets) */
-int BKE_scene_base_iter_next(Depsgraph *depsgraph, SceneBaseIter *iter,
- Scene **scene, int val, Base **base, Object **ob)
-{
- bool run_again = true;
-
- /* init */
- if (val == 0) {
- iter->phase = F_START;
- iter->dupob = NULL;
- iter->duplilist = NULL;
- iter->dupli_refob = NULL;
- }
- else {
- /* run_again is set when a duplilist has been ended */
- while (run_again) {
- run_again = false;
-
- /* the first base */
- if (iter->phase == F_START) {
- ViewLayer *view_layer = (depsgraph) ?
- DEG_get_evaluated_view_layer(depsgraph) :
- BKE_view_layer_context_active_PLACEHOLDER(*scene);
- *base = view_layer->object_bases.first;
- if (*base) {
- *ob = (*base)->object;
- iter->phase = F_SCENE;
- }
- else {
- /* exception: empty scene layer */
- while ((*scene)->set) {
- (*scene) = (*scene)->set;
- ViewLayer *view_layer_set = BKE_view_layer_default_render((*scene));
- if (view_layer_set->object_bases.first) {
- *base = view_layer_set->object_bases.first;
- *ob = (*base)->object;
- iter->phase = F_SCENE;
- break;
- }
- }
- }
- }
- else {
- if (*base && iter->phase != F_DUPLI) {
- *base = (*base)->next;
- if (*base) {
- *ob = (*base)->object;
- }
- else {
- if (iter->phase == F_SCENE) {
- /* (*scene) is finished, now do the set */
- while ((*scene)->set) {
- (*scene) = (*scene)->set;
- ViewLayer *view_layer_set = BKE_view_layer_default_render((*scene));
- if (view_layer_set->object_bases.first) {
- *base = view_layer_set->object_bases.first;
- *ob = (*base)->object;
- break;
- }
- }
- }
- }
- }
- }
-
- if (*base == NULL) {
- iter->phase = F_START;
- }
- else {
- if (iter->phase != F_DUPLI) {
- if (depsgraph && (*base)->object->transflag & OB_DUPLI) {
- /* collections cannot be duplicated for metaballs yet,
- * this enters eternal loop because of
- * makeDispListMBall getting called inside of collection_duplilist */
- if ((*base)->object->instance_collection == NULL) {
- iter->duplilist = object_duplilist(depsgraph, (*scene), (*base)->object);
-
- iter->dupob = iter->duplilist->first;
-
- if (!iter->dupob) {
- free_object_duplilist(iter->duplilist);
- iter->duplilist = NULL;
- }
- iter->dupli_refob = NULL;
- }
- }
- }
- /* handle dupli's */
- if (iter->dupob) {
- (*base)->flag_legacy |= OB_FROMDUPLI;
- *ob = iter->dupob->ob;
- iter->phase = F_DUPLI;
-
- if (iter->dupli_refob != *ob) {
- if (iter->dupli_refob) {
- /* Restore previous object's real matrix. */
- copy_m4_m4(iter->dupli_refob->obmat, iter->omat);
- }
- /* Backup new object's real matrix. */
- iter->dupli_refob = *ob;
- copy_m4_m4(iter->omat, iter->dupli_refob->obmat);
- }
- copy_m4_m4((*ob)->obmat, iter->dupob->mat);
-
- iter->dupob = iter->dupob->next;
- }
- else if (iter->phase == F_DUPLI) {
- iter->phase = F_SCENE;
- (*base)->flag_legacy &= ~OB_FROMDUPLI;
-
- if (iter->dupli_refob) {
- /* Restore last object's real matrix. */
- copy_m4_m4(iter->dupli_refob->obmat, iter->omat);
- iter->dupli_refob = NULL;
- }
-
- free_object_duplilist(iter->duplilist);
- iter->duplilist = NULL;
- run_again = true;
- }
- }
- }
- }
-
- return iter->phase;
+int BKE_scene_base_iter_next(
+ Depsgraph *depsgraph, SceneBaseIter *iter, Scene **scene, int val, Base **base, Object **ob)
+{
+ bool run_again = true;
+
+ /* init */
+ if (val == 0) {
+ iter->phase = F_START;
+ iter->dupob = NULL;
+ iter->duplilist = NULL;
+ iter->dupli_refob = NULL;
+ }
+ else {
+ /* run_again is set when a duplilist has been ended */
+ while (run_again) {
+ run_again = false;
+
+ /* the first base */
+ if (iter->phase == F_START) {
+ ViewLayer *view_layer = (depsgraph) ? DEG_get_evaluated_view_layer(depsgraph) :
+ BKE_view_layer_context_active_PLACEHOLDER(*scene);
+ *base = view_layer->object_bases.first;
+ if (*base) {
+ *ob = (*base)->object;
+ iter->phase = F_SCENE;
+ }
+ else {
+ /* exception: empty scene layer */
+ while ((*scene)->set) {
+ (*scene) = (*scene)->set;
+ ViewLayer *view_layer_set = BKE_view_layer_default_render((*scene));
+ if (view_layer_set->object_bases.first) {
+ *base = view_layer_set->object_bases.first;
+ *ob = (*base)->object;
+ iter->phase = F_SCENE;
+ break;
+ }
+ }
+ }
+ }
+ else {
+ if (*base && iter->phase != F_DUPLI) {
+ *base = (*base)->next;
+ if (*base) {
+ *ob = (*base)->object;
+ }
+ else {
+ if (iter->phase == F_SCENE) {
+ /* (*scene) is finished, now do the set */
+ while ((*scene)->set) {
+ (*scene) = (*scene)->set;
+ ViewLayer *view_layer_set = BKE_view_layer_default_render((*scene));
+ if (view_layer_set->object_bases.first) {
+ *base = view_layer_set->object_bases.first;
+ *ob = (*base)->object;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (*base == NULL) {
+ iter->phase = F_START;
+ }
+ else {
+ if (iter->phase != F_DUPLI) {
+ if (depsgraph && (*base)->object->transflag & OB_DUPLI) {
+ /* collections cannot be duplicated for metaballs yet,
+ * this enters eternal loop because of
+ * makeDispListMBall getting called inside of collection_duplilist */
+ if ((*base)->object->instance_collection == NULL) {
+ iter->duplilist = object_duplilist(depsgraph, (*scene), (*base)->object);
+
+ iter->dupob = iter->duplilist->first;
+
+ if (!iter->dupob) {
+ free_object_duplilist(iter->duplilist);
+ iter->duplilist = NULL;
+ }
+ iter->dupli_refob = NULL;
+ }
+ }
+ }
+ /* handle dupli's */
+ if (iter->dupob) {
+ (*base)->flag_legacy |= OB_FROMDUPLI;
+ *ob = iter->dupob->ob;
+ iter->phase = F_DUPLI;
+
+ if (iter->dupli_refob != *ob) {
+ if (iter->dupli_refob) {
+ /* Restore previous object's real matrix. */
+ copy_m4_m4(iter->dupli_refob->obmat, iter->omat);
+ }
+ /* Backup new object's real matrix. */
+ iter->dupli_refob = *ob;
+ copy_m4_m4(iter->omat, iter->dupli_refob->obmat);
+ }
+ copy_m4_m4((*ob)->obmat, iter->dupob->mat);
+
+ iter->dupob = iter->dupob->next;
+ }
+ else if (iter->phase == F_DUPLI) {
+ iter->phase = F_SCENE;
+ (*base)->flag_legacy &= ~OB_FROMDUPLI;
+
+ if (iter->dupli_refob) {
+ /* Restore last object's real matrix. */
+ copy_m4_m4(iter->dupli_refob->obmat, iter->omat);
+ iter->dupli_refob = NULL;
+ }
+
+ free_object_duplilist(iter->duplilist);
+ iter->duplilist = NULL;
+ run_again = true;
+ }
+ }
+ }
+ }
+
+ return iter->phase;
}
Scene *BKE_scene_find_from_collection(const Main *bmain, const Collection *collection)
{
- for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
- for (ViewLayer *layer = scene->view_layers.first; layer; layer = layer->next) {
- if (BKE_view_layer_has_collection(layer, collection)) {
- return scene;
- }
- }
- }
+ for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
+ for (ViewLayer *layer = scene->view_layers.first; layer; layer = layer->next) {
+ if (BKE_view_layer_has_collection(layer, collection)) {
+ return scene;
+ }
+ }
+ }
- return NULL;
+ return NULL;
}
#ifdef DURIAN_CAMERA_SWITCH
Object *BKE_scene_camera_switch_find(Scene *scene)
{
- if (scene->r.mode & R_NO_CAMERA_SWITCH) {
- return NULL;
- }
-
- TimeMarker *m;
- int cfra = scene->r.cfra;
- int frame = -(MAXFRAME + 1);
- int min_frame = MAXFRAME + 1;
- Object *camera = NULL;
- Object *first_camera = NULL;
-
- for (m = scene->markers.first; m; m = m->next) {
- if (m->camera && (m->camera->restrictflag & OB_RESTRICT_RENDER) == 0) {
- if ((m->frame <= cfra) && (m->frame > frame)) {
- camera = m->camera;
- frame = m->frame;
-
- if (frame == cfra)
- break;
- }
-
- if (m->frame < min_frame) {
- first_camera = m->camera;
- min_frame = m->frame;
- }
- }
- }
-
- if (camera == NULL) {
- /* If there's no marker to the left of current frame,
- * use camera from left-most marker to solve all sort
- * of Schrodinger uncertainties.
- */
- return first_camera;
- }
-
- return camera;
+ if (scene->r.mode & R_NO_CAMERA_SWITCH) {
+ return NULL;
+ }
+
+ TimeMarker *m;
+ int cfra = scene->r.cfra;
+ int frame = -(MAXFRAME + 1);
+ int min_frame = MAXFRAME + 1;
+ Object *camera = NULL;
+ Object *first_camera = NULL;
+
+ for (m = scene->markers.first; m; m = m->next) {
+ if (m->camera && (m->camera->restrictflag & OB_RESTRICT_RENDER) == 0) {
+ if ((m->frame <= cfra) && (m->frame > frame)) {
+ camera = m->camera;
+ frame = m->frame;
+
+ if (frame == cfra)
+ break;
+ }
+
+ if (m->frame < min_frame) {
+ first_camera = m->camera;
+ min_frame = m->frame;
+ }
+ }
+ }
+
+ if (camera == NULL) {
+ /* If there's no marker to the left of current frame,
+ * use camera from left-most marker to solve all sort
+ * of Schrodinger uncertainties.
+ */
+ return first_camera;
+ }
+
+ return camera;
}
#endif
int BKE_scene_camera_switch_update(Scene *scene)
{
#ifdef DURIAN_CAMERA_SWITCH
- Object *camera = BKE_scene_camera_switch_find(scene);
- if (camera) {
- scene->camera = camera;
- DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
- return 1;
- }
+ Object *camera = BKE_scene_camera_switch_find(scene);
+ if (camera) {
+ scene->camera = camera;
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
+ return 1;
+ }
#else
- (void)scene;
+ (void)scene;
#endif
- return 0;
+ return 0;
}
char *BKE_scene_find_marker_name(Scene *scene, int frame)
{
- ListBase *markers = &scene->markers;
- TimeMarker *m1, *m2;
+ ListBase *markers = &scene->markers;
+ TimeMarker *m1, *m2;
- /* search through markers for match */
- for (m1 = markers->first, m2 = markers->last; m1 && m2; m1 = m1->next, m2 = m2->prev) {
- if (m1->frame == frame)
- return m1->name;
+ /* search through markers for match */
+ for (m1 = markers->first, m2 = markers->last; m1 && m2; m1 = m1->next, m2 = m2->prev) {
+ if (m1->frame == frame)
+ return m1->name;
- if (m1 == m2)
- break;
+ if (m1 == m2)
+ break;
- if (m2->frame == frame)
- return m2->name;
- }
+ if (m2->frame == frame)
+ return m2->name;
+ }
- return NULL;
+ return NULL;
}
/* return the current marker for this frame,
* we can have more than 1 marker per frame, this just returns the first :/ */
char *BKE_scene_find_last_marker_name(Scene *scene, int frame)
{
- TimeMarker *marker, *best_marker = NULL;
- int best_frame = -MAXFRAME * 2;
- for (marker = scene->markers.first; marker; marker = marker->next) {
- if (marker->frame == frame) {
- return marker->name;
- }
+ TimeMarker *marker, *best_marker = NULL;
+ int best_frame = -MAXFRAME * 2;
+ for (marker = scene->markers.first; marker; marker = marker->next) {
+ if (marker->frame == frame) {
+ return marker->name;
+ }
- if (marker->frame > best_frame && marker->frame < frame) {
- best_marker = marker;
- best_frame = marker->frame;
- }
- }
+ if (marker->frame > best_frame && marker->frame < frame) {
+ best_marker = marker;
+ best_frame = marker->frame;
+ }
+ }
- return best_marker ? best_marker->name : NULL;
+ return best_marker ? best_marker->name : NULL;
}
int BKE_scene_frame_snap_by_seconds(Scene *scene, double interval_in_seconds, int cfra)
{
- const int fps = round_db_to_int(FPS * interval_in_seconds);
- const int second_prev = cfra - mod_i(cfra, fps);
- const int second_next = second_prev + fps;
- const int delta_prev = cfra - second_prev;
- const int delta_next = second_next - cfra;
- return (delta_prev < delta_next) ? second_prev : second_next;
+ const int fps = round_db_to_int(FPS * interval_in_seconds);
+ const int second_prev = cfra - mod_i(cfra, fps);
+ const int second_next = second_prev + fps;
+ const int delta_prev = cfra - second_prev;
+ const int delta_next = second_next - cfra;
+ return (delta_prev < delta_next) ? second_prev : second_next;
}
void BKE_scene_remove_rigidbody_object(struct Main *bmain, Scene *scene, Object *ob)
{
- /* remove rigid body constraint from world before removing object */
- if (ob->rigidbody_constraint)
- BKE_rigidbody_remove_constraint(scene, ob);
- /* remove rigid body object from world before removing object */
- if (ob->rigidbody_object)
- BKE_rigidbody_remove_object(bmain, scene, ob);
+ /* remove rigid body constraint from world before removing object */
+ if (ob->rigidbody_constraint)
+ BKE_rigidbody_remove_constraint(scene, ob);
+ /* remove rigid body object from world before removing object */
+ if (ob->rigidbody_object)
+ BKE_rigidbody_remove_object(bmain, scene, ob);
}
/* checks for cycle, returns 1 if it's all OK */
bool BKE_scene_validate_setscene(Main *bmain, Scene *sce)
{
- Scene *sce_iter;
- int a, totscene;
+ Scene *sce_iter;
+ int a, totscene;
- if (sce->set == NULL) return true;
- totscene = BLI_listbase_count(&bmain->scenes);
+ if (sce->set == NULL)
+ return true;
+ totscene = BLI_listbase_count(&bmain->scenes);
- for (a = 0, sce_iter = sce; sce_iter->set; sce_iter = sce_iter->set, a++) {
- /* more iterations than scenes means we have a cycle */
- if (a > totscene) {
- /* the tested scene gets zero'ed, that's typically current scene */
- sce->set = NULL;
- return false;
- }
- }
+ for (a = 0, sce_iter = sce; sce_iter->set; sce_iter = sce_iter->set, a++) {
+ /* more iterations than scenes means we have a cycle */
+ if (a > totscene) {
+ /* the tested scene gets zero'ed, that's typically current scene */
+ sce->set = NULL;
+ return false;
+ }
+ }
- return true;
+ return true;
}
/* This function is needed to cope with fractional frames - including two Blender rendering features
@@ -1319,55 +1329,55 @@ bool BKE_scene_validate_setscene(Main *bmain, Scene *sce)
*/
float BKE_scene_frame_get(const Scene *scene)
{
- return BKE_scene_frame_get_from_ctime(scene, scene->r.cfra);
+ return BKE_scene_frame_get_from_ctime(scene, scene->r.cfra);
}
/* This function is used to obtain arbitrary fractional frames */
float BKE_scene_frame_get_from_ctime(const Scene *scene, const float frame)
{
- float ctime = frame;
- ctime += scene->r.subframe;
- ctime *= scene->r.framelen;
+ float ctime = frame;
+ ctime += scene->r.subframe;
+ ctime *= scene->r.framelen;
- return ctime;
+ return ctime;
}
/**
* Sets the frame int/float components.
*/
void BKE_scene_frame_set(struct Scene *scene, double cfra)
{
- double intpart;
- scene->r.subframe = modf(cfra, &intpart);
- scene->r.cfra = (int)intpart;
+ double intpart;
+ scene->r.subframe = modf(cfra, &intpart);
+ scene->r.cfra = (int)intpart;
}
-
/* -------------------------------------------------------------------- */
/** \name Scene Orientation Slots
* \{ */
TransformOrientationSlot *BKE_scene_orientation_slot_get(Scene *scene, int slot_index)
{
- if ((scene->orientation_slots[slot_index].flag & SELECT) == 0) {
- slot_index = SCE_ORIENT_DEFAULT;
- }
- return &scene->orientation_slots[slot_index];
+ if ((scene->orientation_slots[slot_index].flag & SELECT) == 0) {
+ slot_index = SCE_ORIENT_DEFAULT;
+ }
+ return &scene->orientation_slots[slot_index];
}
TransformOrientationSlot *BKE_scene_orientation_slot_get_from_flag(Scene *scene, int flag)
{
- BLI_assert(flag && !(flag & ~(V3D_GIZMO_SHOW_OBJECT_TRANSLATE | V3D_GIZMO_SHOW_OBJECT_ROTATE | V3D_GIZMO_SHOW_OBJECT_SCALE)));
- int slot_index = SCE_ORIENT_DEFAULT;
- if (flag & V3D_GIZMO_SHOW_OBJECT_TRANSLATE) {
- slot_index = SCE_ORIENT_TRANSLATE;
- }
- else if (flag & V3D_GIZMO_SHOW_OBJECT_ROTATE) {
- slot_index = SCE_ORIENT_ROTATE;
- }
- else if (flag & V3D_GIZMO_SHOW_OBJECT_SCALE) {
- slot_index = SCE_ORIENT_SCALE;
- }
- return BKE_scene_orientation_slot_get(scene, slot_index);
+ BLI_assert(flag && !(flag & ~(V3D_GIZMO_SHOW_OBJECT_TRANSLATE | V3D_GIZMO_SHOW_OBJECT_ROTATE |
+ V3D_GIZMO_SHOW_OBJECT_SCALE)));
+ int slot_index = SCE_ORIENT_DEFAULT;
+ if (flag & V3D_GIZMO_SHOW_OBJECT_TRANSLATE) {
+ slot_index = SCE_ORIENT_TRANSLATE;
+ }
+ else if (flag & V3D_GIZMO_SHOW_OBJECT_ROTATE) {
+ slot_index = SCE_ORIENT_ROTATE;
+ }
+ else if (flag & V3D_GIZMO_SHOW_OBJECT_SCALE) {
+ slot_index = SCE_ORIENT_SCALE;
+ }
+ return BKE_scene_orientation_slot_get(scene, slot_index);
}
/**
@@ -1378,19 +1388,20 @@ TransformOrientationSlot *BKE_scene_orientation_slot_get_from_flag(Scene *scene,
*/
void BKE_scene_orientation_slot_set_index(TransformOrientationSlot *orient_slot, int orientation)
{
- const bool is_custom = orientation >= V3D_ORIENT_CUSTOM;
- orient_slot->type = is_custom ? V3D_ORIENT_CUSTOM : orientation;
- orient_slot->index_custom = is_custom ? (orientation - V3D_ORIENT_CUSTOM) : -1;
+ const bool is_custom = orientation >= V3D_ORIENT_CUSTOM;
+ orient_slot->type = is_custom ? V3D_ORIENT_CUSTOM : orientation;
+ orient_slot->index_custom = is_custom ? (orientation - V3D_ORIENT_CUSTOM) : -1;
}
int BKE_scene_orientation_slot_get_index(const TransformOrientationSlot *orient_slot)
{
- return (orient_slot->type == V3D_ORIENT_CUSTOM) ? (orient_slot->type + orient_slot->index_custom) : orient_slot->type;
+ return (orient_slot->type == V3D_ORIENT_CUSTOM) ?
+ (orient_slot->type + orient_slot->index_custom) :
+ orient_slot->type;
}
/** \} */
-
/* That's like really a bummer, because currently animation data for armatures
* might want to use pose, and pose might be missing on the object.
* This happens when changing visible layers, which leads to situations when
@@ -1405,162 +1416,161 @@ int BKE_scene_orientation_slot_get_index(const TransformOrientationSlot *orient_
#ifdef POSE_ANIMATION_WORKAROUND
static void scene_armature_depsgraph_workaround(Main *bmain, Depsgraph *depsgraph)
{
- Object *ob;
- if (BLI_listbase_is_empty(&bmain->armatures) || !DEG_id_type_updated(depsgraph, ID_OB)) {
- return;
- }
- for (ob = bmain->objects.first; ob; ob = ob->id.next) {
- if (ob->type == OB_ARMATURE && ob->adt) {
- if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) {
- BKE_pose_rebuild(bmain, ob, ob->data, true);
- }
- }
- }
+ Object *ob;
+ if (BLI_listbase_is_empty(&bmain->armatures) || !DEG_id_type_updated(depsgraph, ID_OB)) {
+ return;
+ }
+ for (ob = bmain->objects.first; ob; ob = ob->id.next) {
+ if (ob->type == OB_ARMATURE && ob->adt) {
+ if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) {
+ BKE_pose_rebuild(bmain, ob, ob->data, true);
+ }
+ }
+ }
}
#endif
static bool check_rendered_viewport_visible(Main *bmain)
{
- wmWindowManager *wm = bmain->wm.first;
- wmWindow *window;
- for (window = wm->windows.first; window != NULL; window = window->next) {
- const bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
- Scene *scene = window->scene;
- RenderEngineType *type = RE_engines_find(scene->r.engine);
-
- if (type->draw_engine || !type->render) {
- continue;
- }
-
- for (ScrArea *area = screen->areabase.first; area != NULL; area = area->next) {
- View3D *v3d = area->spacedata.first;
- if (area->spacetype != SPACE_VIEW3D) {
- continue;
- }
- if (v3d->shading.type == OB_RENDER) {
- return true;
- }
- }
- }
- return false;
+ wmWindowManager *wm = bmain->wm.first;
+ wmWindow *window;
+ for (window = wm->windows.first; window != NULL; window = window->next) {
+ const bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
+ Scene *scene = window->scene;
+ RenderEngineType *type = RE_engines_find(scene->r.engine);
+
+ if (type->draw_engine || !type->render) {
+ continue;
+ }
+
+ for (ScrArea *area = screen->areabase.first; area != NULL; area = area->next) {
+ View3D *v3d = area->spacedata.first;
+ if (area->spacetype != SPACE_VIEW3D) {
+ continue;
+ }
+ if (v3d->shading.type == OB_RENDER) {
+ return true;
+ }
+ }
+ }
+ return false;
}
/* TODO(campbell): shouldn't we be able to use 'DEG_get_view_layer' here?
* Currently this is NULL on load, so don't. */
-static void prepare_mesh_for_viewport_render(
- Main *bmain, const ViewLayer *view_layer)
-{
- /* This is needed to prepare mesh to be used by the render
- * engine from the viewport rendering. We do loading here
- * so all the objects which shares the same mesh datablock
- * are nicely tagged for update and updated.
- *
- * This makes it so viewport render engine doesn't need to
- * call loading of the edit data for the mesh objects.
- */
-
- Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
- if (obedit) {
- Mesh *mesh = obedit->data;
- if ((obedit->type == OB_MESH) &&
- ((obedit->id.recalc & ID_RECALC_ALL) ||
- (mesh->id.recalc & ID_RECALC_ALL)))
- {
- if (check_rendered_viewport_visible(bmain)) {
- BMesh *bm = mesh->edit_mesh->bm;
- BM_mesh_bm_to_me(
- bmain, bm, mesh,
- (&(struct BMeshToMeshParams){
- .calc_object_remap = true,
- }));
- DEG_id_tag_update(&mesh->id, 0);
- }
- }
- }
+static void prepare_mesh_for_viewport_render(Main *bmain, const ViewLayer *view_layer)
+{
+ /* This is needed to prepare mesh to be used by the render
+ * engine from the viewport rendering. We do loading here
+ * so all the objects which shares the same mesh datablock
+ * are nicely tagged for update and updated.
+ *
+ * This makes it so viewport render engine doesn't need to
+ * call loading of the edit data for the mesh objects.
+ */
+
+ Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+ if (obedit) {
+ Mesh *mesh = obedit->data;
+ if ((obedit->type == OB_MESH) &&
+ ((obedit->id.recalc & ID_RECALC_ALL) || (mesh->id.recalc & ID_RECALC_ALL))) {
+ if (check_rendered_viewport_visible(bmain)) {
+ BMesh *bm = mesh->edit_mesh->bm;
+ BM_mesh_bm_to_me(bmain,
+ bm,
+ mesh,
+ (&(struct BMeshToMeshParams){
+ .calc_object_remap = true,
+ }));
+ DEG_id_tag_update(&mesh->id, 0);
+ }
+ }
+ }
}
/* TODO(sergey): This actually should become view_layer_graph or so.
* Same applies to update_for_newframe.
*/
-void BKE_scene_graph_update_tagged(Depsgraph *depsgraph,
- Main *bmain)
-{
- Scene *scene = DEG_get_input_scene(depsgraph);
- ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
-
- bool run_callbacks = DEG_id_type_any_updated(depsgraph);
- if (run_callbacks) {
- BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_DEPSGRAPH_UPDATE_PRE);
- }
-
- /* TODO(sergey): Some functions here are changing global state,
- * for example, clearing update tags from bmain.
- */
- /* (Re-)build dependency graph if needed. */
- DEG_graph_relations_update(depsgraph, bmain, scene, view_layer);
- /* Uncomment this to check if graph was properly tagged for update. */
- // DEG_debug_graph_relations_validate(depsgraph, bmain, scene);
- /* Flush editing data if needed. */
- prepare_mesh_for_viewport_render(bmain, view_layer);
- /* Flush recalc flags to dependencies. */
- DEG_graph_flush_update(bmain, depsgraph);
- /* Update all objects: drivers, matrices, displists, etc. flags set
- * by depgraph or manual, no layer check here, gets correct flushed.
- */
- DEG_evaluate_on_refresh(depsgraph);
- /* Update sound system animation (TODO, move to depsgraph). */
- BKE_sound_update_scene(bmain, scene);
-
- /* Notify python about depsgraph update */
- if (run_callbacks) {
- BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_DEPSGRAPH_UPDATE_POST);
- }
- /* Inform editors about possible changes. */
- DEG_ids_check_recalc(bmain, depsgraph, scene, view_layer, false);
- /* Clear recalc flags. */
- DEG_ids_clear_recalc(bmain, depsgraph);
+void BKE_scene_graph_update_tagged(Depsgraph *depsgraph, Main *bmain)
+{
+ Scene *scene = DEG_get_input_scene(depsgraph);
+ ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
+
+ bool run_callbacks = DEG_id_type_any_updated(depsgraph);
+ if (run_callbacks) {
+ BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_DEPSGRAPH_UPDATE_PRE);
+ }
+
+ /* TODO(sergey): Some functions here are changing global state,
+ * for example, clearing update tags from bmain.
+ */
+ /* (Re-)build dependency graph if needed. */
+ DEG_graph_relations_update(depsgraph, bmain, scene, view_layer);
+ /* Uncomment this to check if graph was properly tagged for update. */
+ // DEG_debug_graph_relations_validate(depsgraph, bmain, scene);
+ /* Flush editing data if needed. */
+ prepare_mesh_for_viewport_render(bmain, view_layer);
+ /* Flush recalc flags to dependencies. */
+ DEG_graph_flush_update(bmain, depsgraph);
+ /* Update all objects: drivers, matrices, displists, etc. flags set
+ * by depgraph or manual, no layer check here, gets correct flushed.
+ */
+ DEG_evaluate_on_refresh(depsgraph);
+ /* Update sound system animation (TODO, move to depsgraph). */
+ BKE_sound_update_scene(bmain, scene);
+
+ /* Notify python about depsgraph update */
+ if (run_callbacks) {
+ BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_DEPSGRAPH_UPDATE_POST);
+ }
+ /* Inform editors about possible changes. */
+ DEG_ids_check_recalc(bmain, depsgraph, scene, view_layer, false);
+ /* Clear recalc flags. */
+ DEG_ids_clear_recalc(bmain, depsgraph);
}
/* applies changes right away, does all sets too */
-void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph,
- Main *bmain)
-{
- Scene *scene = DEG_get_input_scene(depsgraph);
- ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
-
- /* TODO(sergey): Some functions here are changing global state,
- * for example, clearing update tags from bmain.
- */
- const float ctime = BKE_scene_frame_get(scene);
- /* Keep this first. */
- BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_FRAME_CHANGE_PRE);
- /* Update animated image textures for particles, modifiers, gpu, etc,
- * call this at the start so modifiers with textures don't lag 1 frame.
- */
- BKE_image_editors_update_frame(bmain, scene->r.cfra);
- BKE_sound_set_cfra(scene->r.cfra);
- DEG_graph_relations_update(depsgraph, bmain, scene, view_layer);
- /* Update animated cache files for modifiers.
- *
- * TODO(sergey): Make this a depsgraph node?
- */
- BKE_cachefile_update_frame(bmain, depsgraph, scene, ctime,
- (((double)scene->r.frs_sec) / (double)scene->r.frs_sec_base));
+void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph, Main *bmain)
+{
+ Scene *scene = DEG_get_input_scene(depsgraph);
+ ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
+
+ /* TODO(sergey): Some functions here are changing global state,
+ * for example, clearing update tags from bmain.
+ */
+ const float ctime = BKE_scene_frame_get(scene);
+ /* Keep this first. */
+ BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_FRAME_CHANGE_PRE);
+ /* Update animated image textures for particles, modifiers, gpu, etc,
+ * call this at the start so modifiers with textures don't lag 1 frame.
+ */
+ BKE_image_editors_update_frame(bmain, scene->r.cfra);
+ BKE_sound_set_cfra(scene->r.cfra);
+ DEG_graph_relations_update(depsgraph, bmain, scene, view_layer);
+ /* Update animated cache files for modifiers.
+ *
+ * TODO(sergey): Make this a depsgraph node?
+ */
+ BKE_cachefile_update_frame(bmain,
+ depsgraph,
+ scene,
+ ctime,
+ (((double)scene->r.frs_sec) / (double)scene->r.frs_sec_base));
#ifdef POSE_ANIMATION_WORKAROUND
- scene_armature_depsgraph_workaround(bmain, depsgraph);
+ scene_armature_depsgraph_workaround(bmain, depsgraph);
#endif
- /* Update all objects: drivers, matrices, displists, etc. flags set
- * by depgraph or manual, no layer check here, gets correct flushed.
- */
- DEG_evaluate_on_framechange(bmain, depsgraph, ctime);
- /* Update sound system animation (TODO, move to depsgraph). */
- BKE_sound_update_scene(bmain, scene);
- /* Notify editors and python about recalc. */
- BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_FRAME_CHANGE_POST);
- /* Inform editors about possible changes. */
- DEG_ids_check_recalc(bmain, depsgraph, scene, view_layer, true);
- /* clear recalc flags */
- DEG_ids_clear_recalc(bmain, depsgraph);
+ /* Update all objects: drivers, matrices, displists, etc. flags set
+ * by depgraph or manual, no layer check here, gets correct flushed.
+ */
+ DEG_evaluate_on_framechange(bmain, depsgraph, ctime);
+ /* Update sound system animation (TODO, move to depsgraph). */
+ BKE_sound_update_scene(bmain, scene);
+ /* Notify editors and python about recalc. */
+ BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_FRAME_CHANGE_POST);
+ /* Inform editors about possible changes. */
+ DEG_ids_check_recalc(bmain, depsgraph, scene, view_layer, true);
+ /* clear recalc flags */
+ DEG_ids_clear_recalc(bmain, depsgraph);
}
/** Ensures given scene/view_layer pair has a valid, up-to-date depsgraph.
@@ -1570,73 +1580,78 @@ void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph,
*/
void BKE_scene_view_layer_graph_evaluated_ensure(Main *bmain, Scene *scene, ViewLayer *view_layer)
{
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
- DEG_make_active(depsgraph);
- BKE_scene_graph_update_tagged(depsgraph, bmain);
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ DEG_make_active(depsgraph);
+ BKE_scene_graph_update_tagged(depsgraph, bmain);
}
/* return default view */
SceneRenderView *BKE_scene_add_render_view(Scene *sce, const char *name)
{
- SceneRenderView *srv;
+ SceneRenderView *srv;
- if (!name)
- name = DATA_("RenderView");
+ if (!name)
+ name = DATA_("RenderView");
- srv = MEM_callocN(sizeof(SceneRenderView), "new render view");
- BLI_strncpy(srv->name, name, sizeof(srv->name));
- BLI_uniquename(&sce->r.views, srv, DATA_("RenderView"), '.', offsetof(SceneRenderView, name), sizeof(srv->name));
- BLI_addtail(&sce->r.views, srv);
+ srv = MEM_callocN(sizeof(SceneRenderView), "new render view");
+ BLI_strncpy(srv->name, name, sizeof(srv->name));
+ BLI_uniquename(&sce->r.views,
+ srv,
+ DATA_("RenderView"),
+ '.',
+ offsetof(SceneRenderView, name),
+ sizeof(srv->name));
+ BLI_addtail(&sce->r.views, srv);
- return srv;
+ return srv;
}
bool BKE_scene_remove_render_view(Scene *scene, SceneRenderView *srv)
{
- const int act = BLI_findindex(&scene->r.views, srv);
+ const int act = BLI_findindex(&scene->r.views, srv);
- if (act == -1) {
- return false;
- }
- else if (scene->r.views.first == scene->r.views.last) {
- /* ensure 1 view is kept */
- return false;
- }
+ if (act == -1) {
+ return false;
+ }
+ else if (scene->r.views.first == scene->r.views.last) {
+ /* ensure 1 view is kept */
+ return false;
+ }
- BLI_remlink(&scene->r.views, srv);
- MEM_freeN(srv);
+ BLI_remlink(&scene->r.views, srv);
+ MEM_freeN(srv);
- scene->r.actview = 0;
+ scene->r.actview = 0;
- return true;
+ return true;
}
/* render simplification */
int get_render_subsurf_level(const RenderData *r, int lvl, bool for_render)
{
- if (r->mode & R_SIMPLIFY) {
- if (for_render)
- return min_ii(r->simplify_subsurf_render, lvl);
- else
- return min_ii(r->simplify_subsurf, lvl);
- }
- else {
- return lvl;
- }
+ if (r->mode & R_SIMPLIFY) {
+ if (for_render)
+ return min_ii(r->simplify_subsurf_render, lvl);
+ else
+ return min_ii(r->simplify_subsurf, lvl);
+ }
+ else {
+ return lvl;
+ }
}
int get_render_child_particle_number(const RenderData *r, int num, bool for_render)
{
- if (r->mode & R_SIMPLIFY) {
- if (for_render)
- return (int)(r->simplify_particles_render * num);
- else
- return (int)(r->simplify_particles * num);
- }
- else {
- return num;
- }
+ if (r->mode & R_SIMPLIFY) {
+ if (for_render)
+ return (int)(r->simplify_particles_render * num);
+ else
+ return (int)(r->simplify_particles * num);
+ }
+ else {
+ return num;
+ }
}
/**
@@ -1647,157 +1662,160 @@ int get_render_child_particle_number(const RenderData *r, int num, bool for_rend
*/
Base *_setlooper_base_step(Scene **sce_iter, ViewLayer *view_layer, Base *base)
{
- if (base && base->next) {
- /* Common case, step to the next. */
- return base->next;
- }
- else if ((base == NULL) && (view_layer != NULL)) {
- /* First time looping, return the scenes first base. */
- /* For the first loop we should get the layer from workspace when available. */
- if (view_layer->object_bases.first) {
- return (Base *)view_layer->object_bases.first;
- }
- /* No base on this scene layer. */
- goto next_set;
- }
- else {
-next_set:
- /* Reached the end, get the next base in the set. */
- while ((*sce_iter = (*sce_iter)->set)) {
- ViewLayer *view_layer_set = BKE_view_layer_default_render((*sce_iter));
- base = (Base *)view_layer_set->object_bases.first;
-
- if (base) {
- return base;
- }
- }
- }
-
- return NULL;
+ if (base && base->next) {
+ /* Common case, step to the next. */
+ return base->next;
+ }
+ else if ((base == NULL) && (view_layer != NULL)) {
+ /* First time looping, return the scenes first base. */
+ /* For the first loop we should get the layer from workspace when available. */
+ if (view_layer->object_bases.first) {
+ return (Base *)view_layer->object_bases.first;
+ }
+ /* No base on this scene layer. */
+ goto next_set;
+ }
+ else {
+ next_set:
+ /* Reached the end, get the next base in the set. */
+ while ((*sce_iter = (*sce_iter)->set)) {
+ ViewLayer *view_layer_set = BKE_view_layer_default_render((*sce_iter));
+ base = (Base *)view_layer_set->object_bases.first;
+
+ if (base) {
+ return base;
+ }
+ }
+ }
+
+ return NULL;
}
bool BKE_scene_use_shading_nodes_custom(Scene *scene)
{
- RenderEngineType *type = RE_engines_find(scene->r.engine);
- return (type && type->flag & RE_USE_SHADING_NODES_CUSTOM);
+ RenderEngineType *type = RE_engines_find(scene->r.engine);
+ return (type && type->flag & RE_USE_SHADING_NODES_CUSTOM);
}
bool BKE_scene_use_spherical_stereo(Scene *scene)
{
- RenderEngineType *type = RE_engines_find(scene->r.engine);
- return (type && type->flag & RE_USE_SPHERICAL_STEREO);
+ RenderEngineType *type = RE_engines_find(scene->r.engine);
+ return (type && type->flag & RE_USE_SPHERICAL_STEREO);
}
bool BKE_scene_uses_blender_eevee(const Scene *scene)
{
- return STREQ(scene->r.engine, RE_engine_id_BLENDER_EEVEE);
+ return STREQ(scene->r.engine, RE_engine_id_BLENDER_EEVEE);
}
bool BKE_scene_uses_blender_workbench(const Scene *scene)
{
- return STREQ(scene->r.engine, RE_engine_id_BLENDER_WORKBENCH);
+ return STREQ(scene->r.engine, RE_engine_id_BLENDER_WORKBENCH);
}
bool BKE_scene_uses_cycles(const Scene *scene)
{
- return STREQ(scene->r.engine, RE_engine_id_CYCLES);
+ return STREQ(scene->r.engine, RE_engine_id_CYCLES);
}
void BKE_scene_base_flag_to_objects(ViewLayer *view_layer)
{
- Base *base = view_layer->object_bases.first;
+ Base *base = view_layer->object_bases.first;
- while (base) {
- BKE_scene_object_base_flag_sync_from_base(base);
- base = base->next;
- }
+ while (base) {
+ BKE_scene_object_base_flag_sync_from_base(base);
+ base = base->next;
+ }
}
void BKE_scene_object_base_flag_sync_from_base(Base *base)
{
- Object *ob = base->object;
+ Object *ob = base->object;
- ob->flag = base->flag;
+ ob->flag = base->flag;
- if ((base->flag & BASE_SELECTED) != 0) {
- ob->flag |= SELECT;
- }
- else {
- ob->flag &= ~SELECT;
- }
+ if ((base->flag & BASE_SELECTED) != 0) {
+ ob->flag |= SELECT;
+ }
+ else {
+ ob->flag &= ~SELECT;
+ }
}
void BKE_scene_object_base_flag_sync_from_object(Base *base)
{
- Object *ob = base->object;
- base->flag = ob->flag;
+ Object *ob = base->object;
+ base->flag = ob->flag;
- if ((ob->flag & SELECT) != 0 && (base->flag & BASE_SELECTABLE) != 0) {
- base->flag |= BASE_SELECTED;
- }
- else {
- base->flag &= ~BASE_SELECTED;
- }
+ if ((ob->flag & SELECT) != 0 && (base->flag & BASE_SELECTABLE) != 0) {
+ base->flag |= BASE_SELECTED;
+ }
+ else {
+ base->flag &= ~BASE_SELECTED;
+ }
}
void BKE_scene_disable_color_management(Scene *scene)
{
- ColorManagedDisplaySettings *display_settings = &scene->display_settings;
- ColorManagedViewSettings *view_settings = &scene->view_settings;
- const char *view;
- const char *none_display_name;
+ ColorManagedDisplaySettings *display_settings = &scene->display_settings;
+ ColorManagedViewSettings *view_settings = &scene->view_settings;
+ const char *view;
+ const char *none_display_name;
- none_display_name = IMB_colormanagement_display_get_none_name();
+ none_display_name = IMB_colormanagement_display_get_none_name();
- BLI_strncpy(display_settings->display_device, none_display_name, sizeof(display_settings->display_device));
+ BLI_strncpy(display_settings->display_device,
+ none_display_name,
+ sizeof(display_settings->display_device));
- view = IMB_colormanagement_view_get_default_name(display_settings->display_device);
+ view = IMB_colormanagement_view_get_default_name(display_settings->display_device);
- if (view) {
- BLI_strncpy(view_settings->view_transform, view, sizeof(view_settings->view_transform));
- }
+ if (view) {
+ BLI_strncpy(view_settings->view_transform, view, sizeof(view_settings->view_transform));
+ }
}
bool BKE_scene_check_color_management_enabled(const Scene *scene)
{
- return !STREQ(scene->display_settings.display_device, "None");
+ return !STREQ(scene->display_settings.display_device, "None");
}
bool BKE_scene_check_rigidbody_active(const Scene *scene)
{
- return scene && scene->rigidbody_world && scene->rigidbody_world->group && !(scene->rigidbody_world->flag & RBW_FLAG_MUTED);
+ return scene && scene->rigidbody_world && scene->rigidbody_world->group &&
+ !(scene->rigidbody_world->flag & RBW_FLAG_MUTED);
}
int BKE_render_num_threads(const RenderData *rd)
{
- int threads;
+ int threads;
- /* override set from command line? */
- threads = BLI_system_num_threads_override_get();
+ /* override set from command line? */
+ threads = BLI_system_num_threads_override_get();
- if (threads > 0)
- return threads;
+ if (threads > 0)
+ return threads;
- /* fixed number of threads specified in scene? */
- if (rd->mode & R_FIXED_THREADS)
- threads = rd->threads;
- else
- threads = BLI_system_thread_count();
+ /* fixed number of threads specified in scene? */
+ if (rd->mode & R_FIXED_THREADS)
+ threads = rd->threads;
+ else
+ threads = BLI_system_thread_count();
- return max_ii(threads, 1);
+ return max_ii(threads, 1);
}
int BKE_scene_num_threads(const Scene *scene)
{
- return BKE_render_num_threads(&scene->r);
+ return BKE_render_num_threads(&scene->r);
}
int BKE_render_preview_pixel_size(const RenderData *r)
{
- if (r->preview_pixel_size == 0) {
- return (U.pixelsize > 1.5f) ? 2 : 1;
- }
- return r->preview_pixel_size;
+ if (r->preview_pixel_size == 0) {
+ return (U.pixelsize > 1.5f) ? 2 : 1;
+ }
+ return r->preview_pixel_size;
}
/* Apply the needed correction factor to value, based on unit_type (only length-related are affected currently)
@@ -1805,195 +1823,193 @@ int BKE_render_preview_pixel_size(const RenderData *r)
*/
double BKE_scene_unit_scale(const UnitSettings *unit, const int unit_type, double value)
{
- if (unit->system == USER_UNIT_NONE) {
- /* Never apply scale_length when not using a unit setting! */
- return value;
- }
-
- switch (unit_type) {
- case B_UNIT_LENGTH:
- return value * (double)unit->scale_length;
- case B_UNIT_AREA:
- case B_UNIT_POWER:
- return value * pow(unit->scale_length, 2);
- case B_UNIT_VOLUME:
- return value * pow(unit->scale_length, 3);
- case B_UNIT_MASS:
- return value * pow(unit->scale_length, 3);
- case B_UNIT_CAMERA: /* *Do not* use scene's unit scale for camera focal lens! See T42026. */
- default:
- return value;
- }
+ if (unit->system == USER_UNIT_NONE) {
+ /* Never apply scale_length when not using a unit setting! */
+ return value;
+ }
+
+ switch (unit_type) {
+ case B_UNIT_LENGTH:
+ return value * (double)unit->scale_length;
+ case B_UNIT_AREA:
+ case B_UNIT_POWER:
+ return value * pow(unit->scale_length, 2);
+ case B_UNIT_VOLUME:
+ return value * pow(unit->scale_length, 3);
+ case B_UNIT_MASS:
+ return value * pow(unit->scale_length, 3);
+ case B_UNIT_CAMERA: /* *Do not* use scene's unit scale for camera focal lens! See T42026. */
+ default:
+ return value;
+ }
}
/******************** multiview *************************/
int BKE_scene_multiview_num_views_get(const RenderData *rd)
{
- SceneRenderView *srv;
- int totviews = 0;
-
- if ((rd->scemode & R_MULTIVIEW) == 0)
- return 1;
-
- if (rd->views_format == SCE_VIEWS_FORMAT_STEREO_3D) {
- srv = BLI_findstring(&rd->views, STEREO_LEFT_NAME, offsetof(SceneRenderView, name));
- if ((srv && srv->viewflag & SCE_VIEW_DISABLE) == 0) {
- totviews++;
- }
-
- srv = BLI_findstring(&rd->views, STEREO_RIGHT_NAME, offsetof(SceneRenderView, name));
- if ((srv && srv->viewflag & SCE_VIEW_DISABLE) == 0) {
- totviews++;
- }
- }
- else {
- for (srv = rd->views.first; srv; srv = srv->next) {
- if ((srv->viewflag & SCE_VIEW_DISABLE) == 0) {
- totviews++;
- }
- }
- }
- return totviews;
+ SceneRenderView *srv;
+ int totviews = 0;
+
+ if ((rd->scemode & R_MULTIVIEW) == 0)
+ return 1;
+
+ if (rd->views_format == SCE_VIEWS_FORMAT_STEREO_3D) {
+ srv = BLI_findstring(&rd->views, STEREO_LEFT_NAME, offsetof(SceneRenderView, name));
+ if ((srv && srv->viewflag & SCE_VIEW_DISABLE) == 0) {
+ totviews++;
+ }
+
+ srv = BLI_findstring(&rd->views, STEREO_RIGHT_NAME, offsetof(SceneRenderView, name));
+ if ((srv && srv->viewflag & SCE_VIEW_DISABLE) == 0) {
+ totviews++;
+ }
+ }
+ else {
+ for (srv = rd->views.first; srv; srv = srv->next) {
+ if ((srv->viewflag & SCE_VIEW_DISABLE) == 0) {
+ totviews++;
+ }
+ }
+ }
+ return totviews;
}
bool BKE_scene_multiview_is_stereo3d(const RenderData *rd)
{
- SceneRenderView *srv[2];
+ SceneRenderView *srv[2];
- if ((rd->scemode & R_MULTIVIEW) == 0)
- return false;
+ if ((rd->scemode & R_MULTIVIEW) == 0)
+ return false;
- srv[0] = (SceneRenderView *)BLI_findstring(&rd->views, STEREO_LEFT_NAME, offsetof(SceneRenderView, name));
- srv[1] = (SceneRenderView *)BLI_findstring(&rd->views, STEREO_RIGHT_NAME, offsetof(SceneRenderView, name));
+ srv[0] = (SceneRenderView *)BLI_findstring(
+ &rd->views, STEREO_LEFT_NAME, offsetof(SceneRenderView, name));
+ srv[1] = (SceneRenderView *)BLI_findstring(
+ &rd->views, STEREO_RIGHT_NAME, offsetof(SceneRenderView, name));
- return (srv[0] && ((srv[0]->viewflag & SCE_VIEW_DISABLE) == 0) &&
- srv[1] && ((srv[1]->viewflag & SCE_VIEW_DISABLE) == 0));
+ return (srv[0] && ((srv[0]->viewflag & SCE_VIEW_DISABLE) == 0) && srv[1] &&
+ ((srv[1]->viewflag & SCE_VIEW_DISABLE) == 0));
}
/* return whether to render this SceneRenderView */
bool BKE_scene_multiview_is_render_view_active(const RenderData *rd, const SceneRenderView *srv)
{
- if (srv == NULL)
- return false;
+ if (srv == NULL)
+ return false;
- if ((rd->scemode & R_MULTIVIEW) == 0)
- return false;
+ if ((rd->scemode & R_MULTIVIEW) == 0)
+ return false;
- if ((srv->viewflag & SCE_VIEW_DISABLE))
- return false;
+ if ((srv->viewflag & SCE_VIEW_DISABLE))
+ return false;
- if (rd->views_format == SCE_VIEWS_FORMAT_MULTIVIEW)
- return true;
+ if (rd->views_format == SCE_VIEWS_FORMAT_MULTIVIEW)
+ return true;
- /* SCE_VIEWS_SETUP_BASIC */
- if (STREQ(srv->name, STEREO_LEFT_NAME) ||
- STREQ(srv->name, STEREO_RIGHT_NAME))
- {
- return true;
- }
+ /* SCE_VIEWS_SETUP_BASIC */
+ if (STREQ(srv->name, STEREO_LEFT_NAME) || STREQ(srv->name, STEREO_RIGHT_NAME)) {
+ return true;
+ }
- return false;
+ return false;
}
/* return true if viewname is the first or if the name is NULL or not found */
bool BKE_scene_multiview_is_render_view_first(const RenderData *rd, const char *viewname)
{
- SceneRenderView *srv;
+ SceneRenderView *srv;
- if ((rd->scemode & R_MULTIVIEW) == 0)
- return true;
+ if ((rd->scemode & R_MULTIVIEW) == 0)
+ return true;
- if ((!viewname) || (!viewname[0]))
- return true;
+ if ((!viewname) || (!viewname[0]))
+ return true;
- for (srv = rd->views.first; srv; srv = srv->next) {
- if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
- return STREQ(viewname, srv->name);
- }
- }
+ for (srv = rd->views.first; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
+ return STREQ(viewname, srv->name);
+ }
+ }
- return true;
+ return true;
}
/* return true if viewname is the last or if the name is NULL or not found */
bool BKE_scene_multiview_is_render_view_last(const RenderData *rd, const char *viewname)
{
- SceneRenderView *srv;
+ SceneRenderView *srv;
- if ((rd->scemode & R_MULTIVIEW) == 0)
- return true;
+ if ((rd->scemode & R_MULTIVIEW) == 0)
+ return true;
- if ((!viewname) || (!viewname[0]))
- return true;
+ if ((!viewname) || (!viewname[0]))
+ return true;
- for (srv = rd->views.last; srv; srv = srv->prev) {
- if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
- return STREQ(viewname, srv->name);
- }
- }
+ for (srv = rd->views.last; srv; srv = srv->prev) {
+ if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
+ return STREQ(viewname, srv->name);
+ }
+ }
- return true;
+ return true;
}
SceneRenderView *BKE_scene_multiview_render_view_findindex(const RenderData *rd, const int view_id)
{
- SceneRenderView *srv;
- size_t nr;
+ SceneRenderView *srv;
+ size_t nr;
- if ((rd->scemode & R_MULTIVIEW) == 0)
- return NULL;
+ if ((rd->scemode & R_MULTIVIEW) == 0)
+ return NULL;
- for (srv = rd->views.first, nr = 0; srv; srv = srv->next) {
- if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
- if (nr++ == view_id)
- return srv;
- }
- }
- return srv;
+ for (srv = rd->views.first, nr = 0; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
+ if (nr++ == view_id)
+ return srv;
+ }
+ }
+ return srv;
}
const char *BKE_scene_multiview_render_view_name_get(const RenderData *rd, const int view_id)
{
- SceneRenderView *srv = BKE_scene_multiview_render_view_findindex(rd, view_id);
+ SceneRenderView *srv = BKE_scene_multiview_render_view_findindex(rd, view_id);
- if (srv)
- return srv->name;
- else
- return "";
+ if (srv)
+ return srv->name;
+ else
+ return "";
}
int BKE_scene_multiview_view_id_get(const RenderData *rd, const char *viewname)
{
- SceneRenderView *srv;
- size_t nr;
+ SceneRenderView *srv;
+ size_t nr;
- if ((!rd) || ((rd->scemode & R_MULTIVIEW) == 0))
- return 0;
+ if ((!rd) || ((rd->scemode & R_MULTIVIEW) == 0))
+ return 0;
- if ((!viewname) || (!viewname[0]))
- return 0;
+ if ((!viewname) || (!viewname[0]))
+ return 0;
- for (srv = rd->views.first, nr = 0; srv; srv = srv->next) {
- if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
- if (STREQ(viewname, srv->name)) {
- return nr;
- }
- else {
- nr += 1;
- }
- }
- }
+ for (srv = rd->views.first, nr = 0; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
+ if (STREQ(viewname, srv->name)) {
+ return nr;
+ }
+ else {
+ nr += 1;
+ }
+ }
+ }
- return 0;
+ return 0;
}
-void BKE_scene_multiview_filepath_get(
- SceneRenderView *srv, const char *filepath,
- char *r_filepath)
+void BKE_scene_multiview_filepath_get(SceneRenderView *srv, const char *filepath, char *r_filepath)
{
- BLI_strncpy(r_filepath, filepath, FILE_MAX);
- BLI_path_suffix(r_filepath, FILE_MAX, srv->suffix, "");
+ BLI_strncpy(r_filepath, filepath, FILE_MAX);
+ BLI_path_suffix(r_filepath, FILE_MAX, srv->suffix, "");
}
/**
@@ -2002,260 +2018,254 @@ void BKE_scene_multiview_filepath_get(
* into the file name (e.g., ``Image_L.jpg``). That allows for the user to re-render
* individual views.
*/
-void BKE_scene_multiview_view_filepath_get(
- const RenderData *rd, const char *filepath, const char *viewname,
- char *r_filepath)
+void BKE_scene_multiview_view_filepath_get(const RenderData *rd,
+ const char *filepath,
+ const char *viewname,
+ char *r_filepath)
{
- SceneRenderView *srv;
- char suffix[FILE_MAX];
+ SceneRenderView *srv;
+ char suffix[FILE_MAX];
- srv = BLI_findstring(&rd->views, viewname, offsetof(SceneRenderView, name));
- if (srv)
- BLI_strncpy(suffix, srv->suffix, sizeof(suffix));
- else
- BLI_strncpy(suffix, viewname, sizeof(suffix));
+ srv = BLI_findstring(&rd->views, viewname, offsetof(SceneRenderView, name));
+ if (srv)
+ BLI_strncpy(suffix, srv->suffix, sizeof(suffix));
+ else
+ BLI_strncpy(suffix, viewname, sizeof(suffix));
- BLI_strncpy(r_filepath, filepath, FILE_MAX);
- BLI_path_suffix(r_filepath, FILE_MAX, suffix, "");
+ BLI_strncpy(r_filepath, filepath, FILE_MAX);
+ BLI_path_suffix(r_filepath, FILE_MAX, suffix, "");
}
const char *BKE_scene_multiview_view_suffix_get(const RenderData *rd, const char *viewname)
{
- SceneRenderView *srv;
+ SceneRenderView *srv;
- if ((viewname == NULL) || (viewname[0] == '\0'))
- return viewname;
+ if ((viewname == NULL) || (viewname[0] == '\0'))
+ return viewname;
- srv = BLI_findstring(&rd->views, viewname, offsetof(SceneRenderView, name));
- if (srv)
- return srv->suffix;
- else
- return viewname;
+ srv = BLI_findstring(&rd->views, viewname, offsetof(SceneRenderView, name));
+ if (srv)
+ return srv->suffix;
+ else
+ return viewname;
}
const char *BKE_scene_multiview_view_id_suffix_get(const RenderData *rd, const int view_id)
{
- if ((rd->scemode & R_MULTIVIEW) == 0) {
- return "";
- }
- else {
- const char *viewname = BKE_scene_multiview_render_view_name_get(rd, view_id);
- return BKE_scene_multiview_view_suffix_get(rd, viewname);
- }
-}
-
-void BKE_scene_multiview_view_prefix_get(Scene *scene, const char *name, char *rprefix, const char **rext)
-{
- SceneRenderView *srv;
- size_t index_act;
- const char *suf_act;
- const char delims[] = {'.', '\0'};
-
- rprefix[0] = '\0';
-
- /* begin of extension */
- index_act = BLI_str_rpartition(name, delims, rext, &suf_act);
- if (*rext == NULL)
- return;
- BLI_assert(index_act > 0);
- UNUSED_VARS_NDEBUG(index_act);
-
- for (srv = scene->r.views.first; srv; srv = srv->next) {
- if (BKE_scene_multiview_is_render_view_active(&scene->r, srv)) {
- size_t len = strlen(srv->suffix);
- if (strlen(*rext) >= len && STREQLEN(*rext - len, srv->suffix, len)) {
- BLI_strncpy(rprefix, name, strlen(name) - strlen(*rext) - len + 1);
- break;
- }
- }
- }
-}
-
-void BKE_scene_multiview_videos_dimensions_get(
- const RenderData *rd, const size_t width, const size_t height,
- size_t *r_width, size_t *r_height)
-{
- if ((rd->scemode & R_MULTIVIEW) &&
- rd->im_format.views_format == R_IMF_VIEWS_STEREO_3D)
- {
- IMB_stereo3d_write_dimensions(
- rd->im_format.stereo3d_format.display_mode,
- (rd->im_format.stereo3d_format.flag & S3D_SQUEEZED_FRAME) != 0,
- width, height,
- r_width, r_height);
- }
- else {
- *r_width = width;
- *r_height = height;
- }
+ if ((rd->scemode & R_MULTIVIEW) == 0) {
+ return "";
+ }
+ else {
+ const char *viewname = BKE_scene_multiview_render_view_name_get(rd, view_id);
+ return BKE_scene_multiview_view_suffix_get(rd, viewname);
+ }
+}
+
+void BKE_scene_multiview_view_prefix_get(Scene *scene,
+ const char *name,
+ char *rprefix,
+ const char **rext)
+{
+ SceneRenderView *srv;
+ size_t index_act;
+ const char *suf_act;
+ const char delims[] = {'.', '\0'};
+
+ rprefix[0] = '\0';
+
+ /* begin of extension */
+ index_act = BLI_str_rpartition(name, delims, rext, &suf_act);
+ if (*rext == NULL)
+ return;
+ BLI_assert(index_act > 0);
+ UNUSED_VARS_NDEBUG(index_act);
+
+ for (srv = scene->r.views.first; srv; srv = srv->next) {
+ if (BKE_scene_multiview_is_render_view_active(&scene->r, srv)) {
+ size_t len = strlen(srv->suffix);
+ if (strlen(*rext) >= len && STREQLEN(*rext - len, srv->suffix, len)) {
+ BLI_strncpy(rprefix, name, strlen(name) - strlen(*rext) - len + 1);
+ break;
+ }
+ }
+ }
+}
+
+void BKE_scene_multiview_videos_dimensions_get(const RenderData *rd,
+ const size_t width,
+ const size_t height,
+ size_t *r_width,
+ size_t *r_height)
+{
+ if ((rd->scemode & R_MULTIVIEW) && rd->im_format.views_format == R_IMF_VIEWS_STEREO_3D) {
+ IMB_stereo3d_write_dimensions(rd->im_format.stereo3d_format.display_mode,
+ (rd->im_format.stereo3d_format.flag & S3D_SQUEEZED_FRAME) != 0,
+ width,
+ height,
+ r_width,
+ r_height);
+ }
+ else {
+ *r_width = width;
+ *r_height = height;
+ }
}
int BKE_scene_multiview_num_videos_get(const RenderData *rd)
{
- if (BKE_imtype_is_movie(rd->im_format.imtype) == false)
- return 0;
+ if (BKE_imtype_is_movie(rd->im_format.imtype) == false)
+ return 0;
- if ((rd->scemode & R_MULTIVIEW) == 0)
- return 1;
+ if ((rd->scemode & R_MULTIVIEW) == 0)
+ return 1;
- if (rd->im_format.views_format == R_IMF_VIEWS_STEREO_3D) {
- return 1;
- }
- else {
- /* R_IMF_VIEWS_INDIVIDUAL */
- return BKE_scene_multiview_num_views_get(rd);
- }
+ if (rd->im_format.views_format == R_IMF_VIEWS_STEREO_3D) {
+ return 1;
+ }
+ else {
+ /* R_IMF_VIEWS_INDIVIDUAL */
+ return BKE_scene_multiview_num_views_get(rd);
+ }
}
/* Manipulation of depsgraph storage. */
/* This is a key which identifies depsgraph. */
typedef struct DepsgraphKey {
- ViewLayer *view_layer;
- /* TODO(sergey): Need to include window somehow (same layer might be in a
- * different states in different windows).
- */
+ ViewLayer *view_layer;
+ /* TODO(sergey): Need to include window somehow (same layer might be in a
+ * different states in different windows).
+ */
} DepsgraphKey;
static unsigned int depsgraph_key_hash(const void *key_v)
{
- const DepsgraphKey *key = key_v;
- unsigned int hash = BLI_ghashutil_ptrhash(key->view_layer);
- /* TODO(sergey): Include hash from other fields in the key. */
- return hash;
+ const DepsgraphKey *key = key_v;
+ unsigned int hash = BLI_ghashutil_ptrhash(key->view_layer);
+ /* TODO(sergey): Include hash from other fields in the key. */
+ return hash;
}
static bool depsgraph_key_compare(const void *key_a_v, const void *key_b_v)
{
- const DepsgraphKey *key_a = key_a_v;
- const DepsgraphKey *key_b = key_b_v;
- /* TODO(sergey): Compare rest of */
- return !(key_a->view_layer == key_b->view_layer);
+ const DepsgraphKey *key_a = key_a_v;
+ const DepsgraphKey *key_b = key_b_v;
+ /* TODO(sergey): Compare rest of */
+ return !(key_a->view_layer == key_b->view_layer);
}
static void depsgraph_key_free(void *key_v)
{
- DepsgraphKey *key = key_v;
- MEM_freeN(key);
+ DepsgraphKey *key = key_v;
+ MEM_freeN(key);
}
static void depsgraph_key_value_free(void *value)
{
- Depsgraph *depsgraph = value;
- DEG_graph_free(depsgraph);
+ Depsgraph *depsgraph = value;
+ DEG_graph_free(depsgraph);
}
void BKE_scene_allocate_depsgraph_hash(Scene *scene)
{
- scene->depsgraph_hash = BLI_ghash_new(depsgraph_key_hash,
- depsgraph_key_compare,
- "Scene Depsgraph Hash");
+ scene->depsgraph_hash = BLI_ghash_new(
+ depsgraph_key_hash, depsgraph_key_compare, "Scene Depsgraph Hash");
}
void BKE_scene_ensure_depsgraph_hash(Scene *scene)
{
- if (scene->depsgraph_hash == NULL) {
- BKE_scene_allocate_depsgraph_hash(scene);
- }
+ if (scene->depsgraph_hash == NULL) {
+ BKE_scene_allocate_depsgraph_hash(scene);
+ }
}
void BKE_scene_free_depsgraph_hash(Scene *scene)
{
- if (scene->depsgraph_hash == NULL) {
- return;
- }
- BLI_ghash_free(scene->depsgraph_hash,
- depsgraph_key_free,
- depsgraph_key_value_free);
+ if (scene->depsgraph_hash == NULL) {
+ return;
+ }
+ BLI_ghash_free(scene->depsgraph_hash, depsgraph_key_free, depsgraph_key_value_free);
}
/* Query depsgraph for a specific contexts. */
-Depsgraph *BKE_scene_get_depsgraph(Scene *scene,
- ViewLayer *view_layer,
- bool allocate)
-{
- BLI_assert(scene != NULL);
- BLI_assert(view_layer != NULL);
- /* Make sure hash itself exists. */
- if (allocate) {
- BKE_scene_ensure_depsgraph_hash(scene);
- }
- if (scene->depsgraph_hash == NULL) {
- return NULL;
- }
- /* Either ensure item is in the hash or simply return NULL if it's not,
- * depending on whether caller wants us to create depsgraph or not.
- */
- DepsgraphKey key;
- key.view_layer = view_layer;
- Depsgraph *depsgraph;
- if (allocate) {
- DepsgraphKey **key_ptr;
- Depsgraph **depsgraph_ptr;
- if (!BLI_ghash_ensure_p_ex(scene->depsgraph_hash,
- &key,
- (void ***)&key_ptr,
- (void ***)&depsgraph_ptr))
- {
- *key_ptr = MEM_mallocN(sizeof(DepsgraphKey), __func__);
- **key_ptr = key;
- *depsgraph_ptr = DEG_graph_new(scene, view_layer, DAG_EVAL_VIEWPORT);
- /* TODO(sergey): Would be cool to avoid string format print,
- * but is a bit tricky because we can't know in advance whether
- * we will ever enable debug messages for this depsgraph.
- */
- char name[1024];
- BLI_snprintf(name, sizeof(name), "%s :: %s", scene->id.name, view_layer->name);
- DEG_debug_name_set(*depsgraph_ptr, name);
- }
- depsgraph = *depsgraph_ptr;
- }
- else {
- depsgraph = BLI_ghash_lookup(scene->depsgraph_hash, &key);
- }
- return depsgraph;
+Depsgraph *BKE_scene_get_depsgraph(Scene *scene, ViewLayer *view_layer, bool allocate)
+{
+ BLI_assert(scene != NULL);
+ BLI_assert(view_layer != NULL);
+ /* Make sure hash itself exists. */
+ if (allocate) {
+ BKE_scene_ensure_depsgraph_hash(scene);
+ }
+ if (scene->depsgraph_hash == NULL) {
+ return NULL;
+ }
+ /* Either ensure item is in the hash or simply return NULL if it's not,
+ * depending on whether caller wants us to create depsgraph or not.
+ */
+ DepsgraphKey key;
+ key.view_layer = view_layer;
+ Depsgraph *depsgraph;
+ if (allocate) {
+ DepsgraphKey **key_ptr;
+ Depsgraph **depsgraph_ptr;
+ if (!BLI_ghash_ensure_p_ex(
+ scene->depsgraph_hash, &key, (void ***)&key_ptr, (void ***)&depsgraph_ptr)) {
+ *key_ptr = MEM_mallocN(sizeof(DepsgraphKey), __func__);
+ **key_ptr = key;
+ *depsgraph_ptr = DEG_graph_new(scene, view_layer, DAG_EVAL_VIEWPORT);
+ /* TODO(sergey): Would be cool to avoid string format print,
+ * but is a bit tricky because we can't know in advance whether
+ * we will ever enable debug messages for this depsgraph.
+ */
+ char name[1024];
+ BLI_snprintf(name, sizeof(name), "%s :: %s", scene->id.name, view_layer->name);
+ DEG_debug_name_set(*depsgraph_ptr, name);
+ }
+ depsgraph = *depsgraph_ptr;
+ }
+ else {
+ depsgraph = BLI_ghash_lookup(scene->depsgraph_hash, &key);
+ }
+ return depsgraph;
}
/* -------------------------------------------------------------------- */
/** \name Scene Orientation
* \{ */
-void BKE_scene_transform_orientation_remove(
- Scene *scene, TransformOrientation *orientation)
+void BKE_scene_transform_orientation_remove(Scene *scene, TransformOrientation *orientation)
{
- const int orientation_index = BKE_scene_transform_orientation_get_index(scene, orientation);
+ const int orientation_index = BKE_scene_transform_orientation_get_index(scene, orientation);
- for (int i = 0; i < ARRAY_SIZE(scene->orientation_slots); i++) {
- TransformOrientationSlot *orient_slot = &scene->orientation_slots[i];
- if (orient_slot->index_custom == orientation_index) {
- /* could also use orientation_index-- */
- orient_slot->type = V3D_ORIENT_GLOBAL;
- orient_slot->index_custom = -1;
- }
- }
+ for (int i = 0; i < ARRAY_SIZE(scene->orientation_slots); i++) {
+ TransformOrientationSlot *orient_slot = &scene->orientation_slots[i];
+ if (orient_slot->index_custom == orientation_index) {
+ /* could also use orientation_index-- */
+ orient_slot->type = V3D_ORIENT_GLOBAL;
+ orient_slot->index_custom = -1;
+ }
+ }
- BLI_freelinkN(&scene->transform_spaces, orientation);
+ BLI_freelinkN(&scene->transform_spaces, orientation);
}
-TransformOrientation *BKE_scene_transform_orientation_find(
- const Scene *scene, const int index)
+TransformOrientation *BKE_scene_transform_orientation_find(const Scene *scene, const int index)
{
- return BLI_findlink(&scene->transform_spaces, index);
+ return BLI_findlink(&scene->transform_spaces, index);
}
/**
* \return the index that \a orientation has within \a scene's transform-orientation list or -1 if not found.
*/
-int BKE_scene_transform_orientation_get_index(
- const Scene *scene, const TransformOrientation *orientation)
+int BKE_scene_transform_orientation_get_index(const Scene *scene,
+ const TransformOrientation *orientation)
{
- return BLI_findindex(&scene->transform_spaces, orientation);
+ return BLI_findindex(&scene->transform_spaces, orientation);
}
/** \} */
-
/* -------------------------------------------------------------------- */
/** \name Scene Cursor Rotation
*
@@ -2264,87 +2274,82 @@ int BKE_scene_transform_orientation_get_index(
void BKE_scene_cursor_rot_to_mat3(const View3DCursor *cursor, float mat[3][3])
{
- if (cursor->rotation_mode > 0) {
- eulO_to_mat3(mat, cursor->rotation_euler, cursor->rotation_mode);
- }
- else if (cursor->rotation_mode == ROT_MODE_AXISANGLE) {
- axis_angle_to_mat3(mat, cursor->rotation_axis, cursor->rotation_angle);
- }
- else {
- float tquat[4];
- normalize_qt_qt(tquat, cursor->rotation_quaternion);
- quat_to_mat3(mat, tquat);
- }
+ if (cursor->rotation_mode > 0) {
+ eulO_to_mat3(mat, cursor->rotation_euler, cursor->rotation_mode);
+ }
+ else if (cursor->rotation_mode == ROT_MODE_AXISANGLE) {
+ axis_angle_to_mat3(mat, cursor->rotation_axis, cursor->rotation_angle);
+ }
+ else {
+ float tquat[4];
+ normalize_qt_qt(tquat, cursor->rotation_quaternion);
+ quat_to_mat3(mat, tquat);
+ }
}
void BKE_scene_cursor_rot_to_quat(const View3DCursor *cursor, float quat[4])
{
- if (cursor->rotation_mode > 0) {
- eulO_to_quat(quat, cursor->rotation_euler, cursor->rotation_mode);
- }
- else if (cursor->rotation_mode == ROT_MODE_AXISANGLE) {
- axis_angle_to_quat(quat, cursor->rotation_axis, cursor->rotation_angle);
- }
- else {
- normalize_qt_qt(quat, cursor->rotation_quaternion);
- }
+ if (cursor->rotation_mode > 0) {
+ eulO_to_quat(quat, cursor->rotation_euler, cursor->rotation_mode);
+ }
+ else if (cursor->rotation_mode == ROT_MODE_AXISANGLE) {
+ axis_angle_to_quat(quat, cursor->rotation_axis, cursor->rotation_angle);
+ }
+ else {
+ normalize_qt_qt(quat, cursor->rotation_quaternion);
+ }
}
void BKE_scene_cursor_mat3_to_rot(View3DCursor *cursor, const float mat[3][3], bool use_compat)
{
- BLI_ASSERT_UNIT_M3(mat);
-
- switch (cursor->rotation_mode) {
- case ROT_MODE_QUAT:
- {
- mat3_normalized_to_quat(cursor->rotation_quaternion, mat);
- break;
- }
- case ROT_MODE_AXISANGLE:
- {
- mat3_to_axis_angle(cursor->rotation_axis, &cursor->rotation_angle, mat);
- break;
- }
- default:
- {
- if (use_compat) {
- mat3_to_compatible_eulO(cursor->rotation_euler, cursor->rotation_euler, cursor->rotation_mode, mat);
- }
- else {
- mat3_to_eulO(cursor->rotation_euler, cursor->rotation_mode, mat);
- }
- break;
- }
- }
+ BLI_ASSERT_UNIT_M3(mat);
+
+ switch (cursor->rotation_mode) {
+ case ROT_MODE_QUAT: {
+ mat3_normalized_to_quat(cursor->rotation_quaternion, mat);
+ break;
+ }
+ case ROT_MODE_AXISANGLE: {
+ mat3_to_axis_angle(cursor->rotation_axis, &cursor->rotation_angle, mat);
+ break;
+ }
+ default: {
+ if (use_compat) {
+ mat3_to_compatible_eulO(
+ cursor->rotation_euler, cursor->rotation_euler, cursor->rotation_mode, mat);
+ }
+ else {
+ mat3_to_eulO(cursor->rotation_euler, cursor->rotation_mode, mat);
+ }
+ break;
+ }
+ }
}
void BKE_scene_cursor_quat_to_rot(View3DCursor *cursor, const float quat[4], bool use_compat)
{
- BLI_ASSERT_UNIT_QUAT(quat);
-
- switch (cursor->rotation_mode) {
- case ROT_MODE_QUAT:
- {
- copy_qt_qt(cursor->rotation_quaternion, quat);
- break;
- }
- case ROT_MODE_AXISANGLE:
- {
- quat_to_axis_angle(cursor->rotation_axis, &cursor->rotation_angle, quat);
- break;
- }
- default:
- {
- if (use_compat) {
- quat_to_compatible_eulO(cursor->rotation_euler, cursor->rotation_euler, cursor->rotation_mode, quat);
- }
- else {
- quat_to_eulO(cursor->rotation_euler, cursor->rotation_mode, quat);
- }
- break;
- }
- }
+ BLI_ASSERT_UNIT_QUAT(quat);
+
+ switch (cursor->rotation_mode) {
+ case ROT_MODE_QUAT: {
+ copy_qt_qt(cursor->rotation_quaternion, quat);
+ break;
+ }
+ case ROT_MODE_AXISANGLE: {
+ quat_to_axis_angle(cursor->rotation_axis, &cursor->rotation_angle, quat);
+ break;
+ }
+ default: {
+ if (use_compat) {
+ quat_to_compatible_eulO(
+ cursor->rotation_euler, cursor->rotation_euler, cursor->rotation_mode, quat);
+ }
+ else {
+ quat_to_eulO(cursor->rotation_euler, cursor->rotation_mode, quat);
+ }
+ break;
+ }
+ }
}
-
/** \} */
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index 7b4b11674ed..9fa70d38574 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -55,231 +55,229 @@ static ListBase spacetypes = {NULL, NULL};
/* not SpaceType itself */
static void spacetype_free(SpaceType *st)
{
- ARegionType *art;
- PanelType *pt;
- HeaderType *ht;
+ ARegionType *art;
+ PanelType *pt;
+ HeaderType *ht;
- for (art = st->regiontypes.first; art; art = art->next) {
- BLI_freelistN(&art->drawcalls);
+ for (art = st->regiontypes.first; art; art = art->next) {
+ BLI_freelistN(&art->drawcalls);
- for (pt = art->paneltypes.first; pt; pt = pt->next) {
- if (pt->ext.free) {
- pt->ext.free(pt->ext.data);
- }
+ for (pt = art->paneltypes.first; pt; pt = pt->next) {
+ if (pt->ext.free) {
+ pt->ext.free(pt->ext.data);
+ }
- BLI_freelistN(&pt->children);
- }
+ BLI_freelistN(&pt->children);
+ }
- for (ht = art->headertypes.first; ht; ht = ht->next) {
- if (ht->ext.free) {
- ht->ext.free(ht->ext.data);
- }
- }
+ for (ht = art->headertypes.first; ht; ht = ht->next) {
+ if (ht->ext.free) {
+ ht->ext.free(ht->ext.data);
+ }
+ }
- BLI_freelistN(&art->paneltypes);
- BLI_freelistN(&art->headertypes);
- }
+ BLI_freelistN(&art->paneltypes);
+ BLI_freelistN(&art->headertypes);
+ }
- BLI_freelistN(&st->regiontypes);
+ BLI_freelistN(&st->regiontypes);
}
void BKE_spacetypes_free(void)
{
- SpaceType *st;
+ SpaceType *st;
- for (st = spacetypes.first; st; st = st->next) {
- spacetype_free(st);
- }
+ for (st = spacetypes.first; st; st = st->next) {
+ spacetype_free(st);
+ }
- BLI_freelistN(&spacetypes);
+ BLI_freelistN(&spacetypes);
}
SpaceType *BKE_spacetype_from_id(int spaceid)
{
- SpaceType *st;
+ SpaceType *st;
- for (st = spacetypes.first; st; st = st->next) {
- if (st->spaceid == spaceid)
- return st;
- }
- return NULL;
+ for (st = spacetypes.first; st; st = st->next) {
+ if (st->spaceid == spaceid)
+ return st;
+ }
+ return NULL;
}
ARegionType *BKE_regiontype_from_id_or_first(SpaceType *st, int regionid)
{
- ARegionType *art;
+ ARegionType *art;
- for (art = st->regiontypes.first; art; art = art->next)
- if (art->regionid == regionid)
- return art;
+ for (art = st->regiontypes.first; art; art = art->next)
+ if (art->regionid == regionid)
+ return art;
- printf("Error, region type %d missing in - name:\"%s\", id:%d\n", regionid, st->name, st->spaceid);
- return st->regiontypes.first;
+ printf(
+ "Error, region type %d missing in - name:\"%s\", id:%d\n", regionid, st->name, st->spaceid);
+ return st->regiontypes.first;
}
ARegionType *BKE_regiontype_from_id(SpaceType *st, int regionid)
{
- ARegionType *art;
+ ARegionType *art;
- for (art = st->regiontypes.first; art; art = art->next) {
- if (art->regionid == regionid) {
- return art;
- }
- }
- return NULL;
+ for (art = st->regiontypes.first; art; art = art->next) {
+ if (art->regionid == regionid) {
+ return art;
+ }
+ }
+ return NULL;
}
-
const ListBase *BKE_spacetypes_list(void)
{
- return &spacetypes;
+ return &spacetypes;
}
void BKE_spacetype_register(SpaceType *st)
{
- SpaceType *stype;
+ SpaceType *stype;
- /* sanity check */
- stype = BKE_spacetype_from_id(st->spaceid);
- if (stype) {
- printf("error: redefinition of spacetype %s\n", stype->name);
- spacetype_free(stype);
- MEM_freeN(stype);
- }
+ /* sanity check */
+ stype = BKE_spacetype_from_id(st->spaceid);
+ if (stype) {
+ printf("error: redefinition of spacetype %s\n", stype->name);
+ spacetype_free(stype);
+ MEM_freeN(stype);
+ }
- BLI_addtail(&spacetypes, st);
+ BLI_addtail(&spacetypes, st);
}
bool BKE_spacetype_exists(int spaceid)
{
- return BKE_spacetype_from_id(spaceid) != NULL;
+ return BKE_spacetype_from_id(spaceid) != NULL;
}
/* ***************** Space handling ********************** */
void BKE_spacedata_freelist(ListBase *lb)
{
- SpaceLink *sl;
- ARegion *ar;
+ SpaceLink *sl;
+ ARegion *ar;
- for (sl = lb->first; sl; sl = sl->next) {
- SpaceType *st = BKE_spacetype_from_id(sl->spacetype);
+ for (sl = lb->first; sl; sl = sl->next) {
+ SpaceType *st = BKE_spacetype_from_id(sl->spacetype);
- /* free regions for pushed spaces */
- for (ar = sl->regionbase.first; ar; ar = ar->next)
- BKE_area_region_free(st, ar);
+ /* free regions for pushed spaces */
+ for (ar = sl->regionbase.first; ar; ar = ar->next)
+ BKE_area_region_free(st, ar);
- BLI_freelistN(&sl->regionbase);
+ BLI_freelistN(&sl->regionbase);
- if (st && st->free)
- st->free(sl);
- }
+ if (st && st->free)
+ st->free(sl);
+ }
- BLI_freelistN(lb);
+ BLI_freelistN(lb);
}
static void panel_list_copy(ListBase *newlb, const ListBase *lb)
{
- BLI_listbase_clear(newlb);
- BLI_duplicatelist(newlb, lb);
+ BLI_listbase_clear(newlb);
+ BLI_duplicatelist(newlb, lb);
- /* copy panel pointers */
- Panel *newpa = newlb->first;
- Panel *pa = lb->first;
- for (; newpa; newpa = newpa->next, pa = pa->next) {
- newpa->activedata = NULL;
+ /* copy panel pointers */
+ Panel *newpa = newlb->first;
+ Panel *pa = lb->first;
+ for (; newpa; newpa = newpa->next, pa = pa->next) {
+ newpa->activedata = NULL;
- Panel *newpatab = newlb->first;
- Panel *patab = lb->first;
- while (newpatab) {
- if (newpa->paneltab == patab) {
- newpa->paneltab = newpatab;
- break;
- }
- newpatab = newpatab->next;
- patab = patab->next;
- }
+ Panel *newpatab = newlb->first;
+ Panel *patab = lb->first;
+ while (newpatab) {
+ if (newpa->paneltab == patab) {
+ newpa->paneltab = newpatab;
+ break;
+ }
+ newpatab = newpatab->next;
+ patab = patab->next;
+ }
- panel_list_copy(&newpa->children, &pa->children);
- }
+ panel_list_copy(&newpa->children, &pa->children);
+ }
}
ARegion *BKE_area_region_copy(SpaceType *st, ARegion *ar)
{
- ARegion *newar = MEM_dupallocN(ar);
+ ARegion *newar = MEM_dupallocN(ar);
- newar->prev = newar->next = NULL;
- BLI_listbase_clear(&newar->handlers);
- BLI_listbase_clear(&newar->uiblocks);
- BLI_listbase_clear(&newar->panels_category);
- BLI_listbase_clear(&newar->panels_category_active);
- BLI_listbase_clear(&newar->ui_lists);
- newar->visible = 0;
- newar->gizmo_map = NULL;
- newar->regiontimer = NULL;
- newar->headerstr = NULL;
- newar->draw_buffer = NULL;
+ newar->prev = newar->next = NULL;
+ BLI_listbase_clear(&newar->handlers);
+ BLI_listbase_clear(&newar->uiblocks);
+ BLI_listbase_clear(&newar->panels_category);
+ BLI_listbase_clear(&newar->panels_category_active);
+ BLI_listbase_clear(&newar->ui_lists);
+ newar->visible = 0;
+ newar->gizmo_map = NULL;
+ newar->regiontimer = NULL;
+ newar->headerstr = NULL;
+ newar->draw_buffer = NULL;
- /* use optional regiondata callback */
- if (ar->regiondata) {
- ARegionType *art = BKE_regiontype_from_id(st, ar->regiontype);
+ /* use optional regiondata callback */
+ if (ar->regiondata) {
+ ARegionType *art = BKE_regiontype_from_id(st, ar->regiontype);
- if (art && art->duplicate) {
- newar->regiondata = art->duplicate(ar->regiondata);
- }
- else if (ar->flag & RGN_FLAG_TEMP_REGIONDATA) {
- newar->regiondata = NULL;
- }
- else {
- newar->regiondata = MEM_dupallocN(ar->regiondata);
- }
- }
+ if (art && art->duplicate) {
+ newar->regiondata = art->duplicate(ar->regiondata);
+ }
+ else if (ar->flag & RGN_FLAG_TEMP_REGIONDATA) {
+ newar->regiondata = NULL;
+ }
+ else {
+ newar->regiondata = MEM_dupallocN(ar->regiondata);
+ }
+ }
- if (ar->v2d.tab_offset)
- newar->v2d.tab_offset = MEM_dupallocN(ar->v2d.tab_offset);
+ if (ar->v2d.tab_offset)
+ newar->v2d.tab_offset = MEM_dupallocN(ar->v2d.tab_offset);
- panel_list_copy(&newar->panels, &ar->panels);
+ panel_list_copy(&newar->panels, &ar->panels);
- BLI_listbase_clear(&newar->ui_previews);
- BLI_duplicatelist(&newar->ui_previews, &ar->ui_previews);
+ BLI_listbase_clear(&newar->ui_previews);
+ BLI_duplicatelist(&newar->ui_previews, &ar->ui_previews);
- return newar;
+ return newar;
}
-
/* from lb2 to lb1, lb1 is supposed to be freed */
static void region_copylist(SpaceType *st, ListBase *lb1, ListBase *lb2)
{
- ARegion *ar;
+ ARegion *ar;
- /* to be sure */
- BLI_listbase_clear(lb1);
+ /* to be sure */
+ BLI_listbase_clear(lb1);
- for (ar = lb2->first; ar; ar = ar->next) {
- ARegion *arnew = BKE_area_region_copy(st, ar);
- BLI_addtail(lb1, arnew);
- }
+ for (ar = lb2->first; ar; ar = ar->next) {
+ ARegion *arnew = BKE_area_region_copy(st, ar);
+ BLI_addtail(lb1, arnew);
+ }
}
-
/* lb1 should be empty */
void BKE_spacedata_copylist(ListBase *lb1, ListBase *lb2)
{
- SpaceLink *sl;
+ SpaceLink *sl;
- BLI_listbase_clear(lb1); /* to be sure */
+ BLI_listbase_clear(lb1); /* to be sure */
- for (sl = lb2->first; sl; sl = sl->next) {
- SpaceType *st = BKE_spacetype_from_id(sl->spacetype);
+ for (sl = lb2->first; sl; sl = sl->next) {
+ SpaceType *st = BKE_spacetype_from_id(sl->spacetype);
- if (st && st->duplicate) {
- SpaceLink *slnew = st->duplicate(sl);
+ if (st && st->duplicate) {
+ SpaceLink *slnew = st->duplicate(sl);
- BLI_addtail(lb1, slnew);
+ BLI_addtail(lb1, slnew);
- region_copylist(st, &slnew->regionbase, &sl->regionbase);
- }
- }
+ region_copylist(st, &slnew->regionbase, &sl->regionbase);
+ }
+ }
}
/* facility to set locks for drawing to survive (render) threads accessing drawing data */
@@ -287,18 +285,18 @@ void BKE_spacedata_copylist(ListBase *lb1, ListBase *lb2)
/* should be replaced in future by better local data handling for threads */
void BKE_spacedata_draw_locks(int set)
{
- SpaceType *st;
+ SpaceType *st;
- for (st = spacetypes.first; st; st = st->next) {
- ARegionType *art;
+ for (st = spacetypes.first; st; st = st->next) {
+ ARegionType *art;
- for (art = st->regiontypes.first; art; art = art->next) {
- if (set)
- art->do_lock = art->lock;
- else
- art->do_lock = false;
- }
- }
+ for (art = st->regiontypes.first; art; art = art->next) {
+ if (set)
+ art->do_lock = art->lock;
+ else
+ art->do_lock = false;
+ }
+ }
}
/**
@@ -306,38 +304,39 @@ void BKE_spacedata_draw_locks(int set)
*/
ARegion *BKE_spacedata_find_region_type(const SpaceLink *slink, const ScrArea *sa, int region_type)
{
- const bool is_slink_active = slink == sa->spacedata.first;
- const ListBase *regionbase = (is_slink_active) ?
- &sa->regionbase : &slink->regionbase;
- ARegion *ar = NULL;
+ const bool is_slink_active = slink == sa->spacedata.first;
+ const ListBase *regionbase = (is_slink_active) ? &sa->regionbase : &slink->regionbase;
+ ARegion *ar = NULL;
- BLI_assert(BLI_findindex(&sa->spacedata, slink) != -1);
- for (ar = regionbase->first; ar; ar = ar->next) {
- if (ar->regiontype == region_type) {
- break;
- }
- }
+ BLI_assert(BLI_findindex(&sa->spacedata, slink) != -1);
+ for (ar = regionbase->first; ar; ar = ar->next) {
+ if (ar->regiontype == region_type) {
+ break;
+ }
+ }
- /* Should really unit test this instead. */
- BLI_assert(!is_slink_active || ar == BKE_area_find_region_type(sa, region_type));
+ /* Should really unit test this instead. */
+ BLI_assert(!is_slink_active || ar == BKE_area_find_region_type(sa, region_type));
- return ar;
+ return ar;
}
-
-static void (*spacedata_id_remap_cb)(struct ScrArea *sa, struct SpaceLink *sl, ID *old_id, ID *new_id) = NULL;
+static void (*spacedata_id_remap_cb)(struct ScrArea *sa,
+ struct SpaceLink *sl,
+ ID *old_id,
+ ID *new_id) = NULL;
void BKE_spacedata_callback_id_remap_set(void (*func)(ScrArea *sa, SpaceLink *sl, ID *, ID *))
{
- spacedata_id_remap_cb = func;
+ spacedata_id_remap_cb = func;
}
/* UNUSED!!! */
void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID *id)
{
- if (spacedata_id_remap_cb) {
- spacedata_id_remap_cb(sa, sl, id, NULL);
- }
+ if (spacedata_id_remap_cb) {
+ spacedata_id_remap_cb(sa, sl, id, NULL);
+ }
}
/**
@@ -347,24 +346,24 @@ static void (*region_refresh_tag_gizmomap_callback)(struct wmGizmoMap *) = NULL;
void BKE_region_callback_refresh_tag_gizmomap_set(void (*callback)(struct wmGizmoMap *))
{
- region_refresh_tag_gizmomap_callback = callback;
+ region_refresh_tag_gizmomap_callback = callback;
}
void BKE_screen_gizmo_tag_refresh(struct bScreen *sc)
{
- if (region_refresh_tag_gizmomap_callback == NULL) {
- return;
- }
+ if (region_refresh_tag_gizmomap_callback == NULL) {
+ return;
+ }
- ScrArea *sa;
- ARegion *ar;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- for (ar = sa->regionbase.first; ar; ar = ar->next) {
- if (ar->gizmo_map != NULL) {
- region_refresh_tag_gizmomap_callback(ar->gizmo_map);
- }
- }
- }
+ ScrArea *sa;
+ ARegion *ar;
+ for (sa = sc->areabase.first; sa; sa = sa->next) {
+ for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->gizmo_map != NULL) {
+ region_refresh_tag_gizmomap_callback(ar->gizmo_map);
+ }
+ }
+ }
}
/**
@@ -374,288 +373,301 @@ static void (*region_free_gizmomap_callback)(struct wmGizmoMap *) = NULL;
void BKE_region_callback_free_gizmomap_set(void (*callback)(struct wmGizmoMap *))
{
- region_free_gizmomap_callback = callback;
+ region_free_gizmomap_callback = callback;
}
void BKE_area_region_panels_free(ListBase *lb)
{
- Panel *pa, *pa_next;
- for (pa = lb->first; pa; pa = pa_next) {
- pa_next = pa->next;
- if (pa->activedata) {
- MEM_freeN(pa->activedata);
- }
- BKE_area_region_panels_free(&pa->children);
- }
+ Panel *pa, *pa_next;
+ for (pa = lb->first; pa; pa = pa_next) {
+ pa_next = pa->next;
+ if (pa->activedata) {
+ MEM_freeN(pa->activedata);
+ }
+ BKE_area_region_panels_free(&pa->children);
+ }
- BLI_freelistN(lb);
+ BLI_freelistN(lb);
}
/* not region itself */
void BKE_area_region_free(SpaceType *st, ARegion *ar)
{
- uiList *uilst;
-
- if (st) {
- ARegionType *art = BKE_regiontype_from_id(st, ar->regiontype);
-
- if (art && art->free)
- art->free(ar);
-
- if (ar->regiondata)
- printf("regiondata free error\n");
- }
- else if (ar->type && ar->type->free)
- ar->type->free(ar);
-
- if (ar->v2d.tab_offset) {
- MEM_freeN(ar->v2d.tab_offset);
- ar->v2d.tab_offset = NULL;
- }
-
- BKE_area_region_panels_free(&ar->panels);
-
- for (uilst = ar->ui_lists.first; uilst; uilst = uilst->next) {
- if (uilst->dyn_data) {
- uiListDyn *dyn_data = uilst->dyn_data;
- if (dyn_data->items_filter_flags) {
- MEM_freeN(dyn_data->items_filter_flags);
- }
- if (dyn_data->items_filter_neworder) {
- MEM_freeN(dyn_data->items_filter_neworder);
- }
- MEM_freeN(dyn_data);
- }
- if (uilst->properties) {
- IDP_FreeProperty(uilst->properties);
- MEM_freeN(uilst->properties);
- }
- }
-
- if (ar->gizmo_map != NULL) {
- region_free_gizmomap_callback(ar->gizmo_map);
- }
-
- BLI_freelistN(&ar->ui_lists);
- BLI_freelistN(&ar->ui_previews);
- BLI_freelistN(&ar->panels_category);
- BLI_freelistN(&ar->panels_category_active);
+ uiList *uilst;
+
+ if (st) {
+ ARegionType *art = BKE_regiontype_from_id(st, ar->regiontype);
+
+ if (art && art->free)
+ art->free(ar);
+
+ if (ar->regiondata)
+ printf("regiondata free error\n");
+ }
+ else if (ar->type && ar->type->free)
+ ar->type->free(ar);
+
+ if (ar->v2d.tab_offset) {
+ MEM_freeN(ar->v2d.tab_offset);
+ ar->v2d.tab_offset = NULL;
+ }
+
+ BKE_area_region_panels_free(&ar->panels);
+
+ for (uilst = ar->ui_lists.first; uilst; uilst = uilst->next) {
+ if (uilst->dyn_data) {
+ uiListDyn *dyn_data = uilst->dyn_data;
+ if (dyn_data->items_filter_flags) {
+ MEM_freeN(dyn_data->items_filter_flags);
+ }
+ if (dyn_data->items_filter_neworder) {
+ MEM_freeN(dyn_data->items_filter_neworder);
+ }
+ MEM_freeN(dyn_data);
+ }
+ if (uilst->properties) {
+ IDP_FreeProperty(uilst->properties);
+ MEM_freeN(uilst->properties);
+ }
+ }
+
+ if (ar->gizmo_map != NULL) {
+ region_free_gizmomap_callback(ar->gizmo_map);
+ }
+
+ BLI_freelistN(&ar->ui_lists);
+ BLI_freelistN(&ar->ui_previews);
+ BLI_freelistN(&ar->panels_category);
+ BLI_freelistN(&ar->panels_category_active);
}
/* not area itself */
void BKE_screen_area_free(ScrArea *sa)
{
- SpaceType *st = BKE_spacetype_from_id(sa->spacetype);
- ARegion *ar;
+ SpaceType *st = BKE_spacetype_from_id(sa->spacetype);
+ ARegion *ar;
- for (ar = sa->regionbase.first; ar; ar = ar->next)
- BKE_area_region_free(st, ar);
+ for (ar = sa->regionbase.first; ar; ar = ar->next)
+ BKE_area_region_free(st, ar);
- MEM_SAFE_FREE(sa->global);
- BLI_freelistN(&sa->regionbase);
+ MEM_SAFE_FREE(sa->global);
+ BLI_freelistN(&sa->regionbase);
- BKE_spacedata_freelist(&sa->spacedata);
+ BKE_spacedata_freelist(&sa->spacedata);
- BLI_freelistN(&sa->actionzones);
+ BLI_freelistN(&sa->actionzones);
}
void BKE_screen_area_map_free(ScrAreaMap *area_map)
{
- for (ScrArea *area = area_map->areabase.first, *area_next; area; area = area_next) {
- area_next = area->next;
- BKE_screen_area_free(area);
- }
+ for (ScrArea *area = area_map->areabase.first, *area_next; area; area = area_next) {
+ area_next = area->next;
+ BKE_screen_area_free(area);
+ }
- BLI_freelistN(&area_map->vertbase);
- BLI_freelistN(&area_map->edgebase);
- BLI_freelistN(&area_map->areabase);
+ BLI_freelistN(&area_map->vertbase);
+ BLI_freelistN(&area_map->edgebase);
+ BLI_freelistN(&area_map->areabase);
}
/** Free (or release) any data used by this screen (does not free the screen itself). */
void BKE_screen_free(bScreen *sc)
{
- ARegion *ar;
+ ARegion *ar;
- /* No animdata here. */
+ /* No animdata here. */
- for (ar = sc->regionbase.first; ar; ar = ar->next)
- BKE_area_region_free(NULL, ar);
+ for (ar = sc->regionbase.first; ar; ar = ar->next)
+ BKE_area_region_free(NULL, ar);
- BLI_freelistN(&sc->regionbase);
+ BLI_freelistN(&sc->regionbase);
- BKE_screen_area_map_free(AREAMAP_FROM_SCREEN(sc));
+ BKE_screen_area_map_free(AREAMAP_FROM_SCREEN(sc));
- BKE_previewimg_free(&sc->preview);
+ BKE_previewimg_free(&sc->preview);
- /* Region and timer are freed by the window manager. */
- MEM_SAFE_FREE(sc->tool_tip);
+ /* Region and timer are freed by the window manager. */
+ MEM_SAFE_FREE(sc->tool_tip);
}
/* ***************** Screen edges & verts ***************** */
ScrEdge *BKE_screen_find_edge(bScreen *sc, ScrVert *v1, ScrVert *v2)
{
- ScrEdge *se;
+ ScrEdge *se;
- BKE_screen_sort_scrvert(&v1, &v2);
- for (se = sc->edgebase.first; se; se = se->next) {
- if (se->v1 == v1 && se->v2 == v2) {
- return se;
- }
- }
+ BKE_screen_sort_scrvert(&v1, &v2);
+ for (se = sc->edgebase.first; se; se = se->next) {
+ if (se->v1 == v1 && se->v2 == v2) {
+ return se;
+ }
+ }
- return NULL;
+ return NULL;
}
void BKE_screen_sort_scrvert(ScrVert **v1, ScrVert **v2)
{
- ScrVert *tmp;
+ ScrVert *tmp;
- if (*v1 > *v2) {
- tmp = *v1;
- *v1 = *v2;
- *v2 = tmp;
- }
+ if (*v1 > *v2) {
+ tmp = *v1;
+ *v1 = *v2;
+ *v2 = tmp;
+ }
}
void BKE_screen_remove_double_scrverts(bScreen *sc)
{
- ScrVert *v1, *verg;
- ScrEdge *se;
- ScrArea *sa;
-
- verg = sc->vertbase.first;
- while (verg) {
- if (verg->newv == NULL) { /* !!! */
- v1 = verg->next;
- while (v1) {
- if (v1->newv == NULL) { /* !?! */
- if (v1->vec.x == verg->vec.x && v1->vec.y == verg->vec.y) {
- /* printf("doublevert\n"); */
- v1->newv = verg;
- }
- }
- v1 = v1->next;
- }
- }
- verg = verg->next;
- }
-
- /* replace pointers in edges and faces */
- se = sc->edgebase.first;
- while (se) {
- if (se->v1->newv) se->v1 = se->v1->newv;
- if (se->v2->newv) se->v2 = se->v2->newv;
- /* edges changed: so.... */
- BKE_screen_sort_scrvert(&(se->v1), &(se->v2));
- se = se->next;
- }
- sa = sc->areabase.first;
- while (sa) {
- if (sa->v1->newv) sa->v1 = sa->v1->newv;
- if (sa->v2->newv) sa->v2 = sa->v2->newv;
- if (sa->v3->newv) sa->v3 = sa->v3->newv;
- if (sa->v4->newv) sa->v4 = sa->v4->newv;
- sa = sa->next;
- }
-
- /* remove */
- verg = sc->vertbase.first;
- while (verg) {
- v1 = verg->next;
- if (verg->newv) {
- BLI_remlink(&sc->vertbase, verg);
- MEM_freeN(verg);
- }
- verg = v1;
- }
-
+ ScrVert *v1, *verg;
+ ScrEdge *se;
+ ScrArea *sa;
+
+ verg = sc->vertbase.first;
+ while (verg) {
+ if (verg->newv == NULL) { /* !!! */
+ v1 = verg->next;
+ while (v1) {
+ if (v1->newv == NULL) { /* !?! */
+ if (v1->vec.x == verg->vec.x && v1->vec.y == verg->vec.y) {
+ /* printf("doublevert\n"); */
+ v1->newv = verg;
+ }
+ }
+ v1 = v1->next;
+ }
+ }
+ verg = verg->next;
+ }
+
+ /* replace pointers in edges and faces */
+ se = sc->edgebase.first;
+ while (se) {
+ if (se->v1->newv)
+ se->v1 = se->v1->newv;
+ if (se->v2->newv)
+ se->v2 = se->v2->newv;
+ /* edges changed: so.... */
+ BKE_screen_sort_scrvert(&(se->v1), &(se->v2));
+ se = se->next;
+ }
+ sa = sc->areabase.first;
+ while (sa) {
+ if (sa->v1->newv)
+ sa->v1 = sa->v1->newv;
+ if (sa->v2->newv)
+ sa->v2 = sa->v2->newv;
+ if (sa->v3->newv)
+ sa->v3 = sa->v3->newv;
+ if (sa->v4->newv)
+ sa->v4 = sa->v4->newv;
+ sa = sa->next;
+ }
+
+ /* remove */
+ verg = sc->vertbase.first;
+ while (verg) {
+ v1 = verg->next;
+ if (verg->newv) {
+ BLI_remlink(&sc->vertbase, verg);
+ MEM_freeN(verg);
+ }
+ verg = v1;
+ }
}
void BKE_screen_remove_double_scredges(bScreen *sc)
{
- ScrEdge *verg, *se, *sn;
+ ScrEdge *verg, *se, *sn;
- /* compare */
- verg = sc->edgebase.first;
- while (verg) {
- se = verg->next;
- while (se) {
- sn = se->next;
- if (verg->v1 == se->v1 && verg->v2 == se->v2) {
- BLI_remlink(&sc->edgebase, se);
- MEM_freeN(se);
- }
- se = sn;
- }
- verg = verg->next;
- }
+ /* compare */
+ verg = sc->edgebase.first;
+ while (verg) {
+ se = verg->next;
+ while (se) {
+ sn = se->next;
+ if (verg->v1 == se->v1 && verg->v2 == se->v2) {
+ BLI_remlink(&sc->edgebase, se);
+ MEM_freeN(se);
+ }
+ se = sn;
+ }
+ verg = verg->next;
+ }
}
void BKE_screen_remove_unused_scredges(bScreen *sc)
{
- ScrEdge *se, *sen;
- ScrArea *sa;
- int a = 0;
-
- /* sets flags when edge is used in area */
- sa = sc->areabase.first;
- while (sa) {
- se = BKE_screen_find_edge(sc, sa->v1, sa->v2);
- if (se == NULL) printf("error: area %d edge 1 doesn't exist\n", a);
- else se->flag = 1;
- se = BKE_screen_find_edge(sc, sa->v2, sa->v3);
- if (se == NULL) printf("error: area %d edge 2 doesn't exist\n", a);
- else se->flag = 1;
- se = BKE_screen_find_edge(sc, sa->v3, sa->v4);
- if (se == NULL) printf("error: area %d edge 3 doesn't exist\n", a);
- else se->flag = 1;
- se = BKE_screen_find_edge(sc, sa->v4, sa->v1);
- if (se == NULL) printf("error: area %d edge 4 doesn't exist\n", a);
- else se->flag = 1;
- sa = sa->next;
- a++;
- }
- se = sc->edgebase.first;
- while (se) {
- sen = se->next;
- if (se->flag == 0) {
- BLI_remlink(&sc->edgebase, se);
- MEM_freeN(se);
- }
- else {
- se->flag = 0;
- }
- se = sen;
- }
+ ScrEdge *se, *sen;
+ ScrArea *sa;
+ int a = 0;
+
+ /* sets flags when edge is used in area */
+ sa = sc->areabase.first;
+ while (sa) {
+ se = BKE_screen_find_edge(sc, sa->v1, sa->v2);
+ if (se == NULL)
+ printf("error: area %d edge 1 doesn't exist\n", a);
+ else
+ se->flag = 1;
+ se = BKE_screen_find_edge(sc, sa->v2, sa->v3);
+ if (se == NULL)
+ printf("error: area %d edge 2 doesn't exist\n", a);
+ else
+ se->flag = 1;
+ se = BKE_screen_find_edge(sc, sa->v3, sa->v4);
+ if (se == NULL)
+ printf("error: area %d edge 3 doesn't exist\n", a);
+ else
+ se->flag = 1;
+ se = BKE_screen_find_edge(sc, sa->v4, sa->v1);
+ if (se == NULL)
+ printf("error: area %d edge 4 doesn't exist\n", a);
+ else
+ se->flag = 1;
+ sa = sa->next;
+ a++;
+ }
+ se = sc->edgebase.first;
+ while (se) {
+ sen = se->next;
+ if (se->flag == 0) {
+ BLI_remlink(&sc->edgebase, se);
+ MEM_freeN(se);
+ }
+ else {
+ se->flag = 0;
+ }
+ se = sen;
+ }
}
void BKE_screen_remove_unused_scrverts(bScreen *sc)
{
- ScrVert *sv, *svn;
- ScrEdge *se;
+ ScrVert *sv, *svn;
+ ScrEdge *se;
- /* we assume edges are ok */
+ /* we assume edges are ok */
- se = sc->edgebase.first;
- while (se) {
- se->v1->flag = 1;
- se->v2->flag = 1;
- se = se->next;
- }
+ se = sc->edgebase.first;
+ while (se) {
+ se->v1->flag = 1;
+ se->v2->flag = 1;
+ se = se->next;
+ }
- sv = sc->vertbase.first;
- while (sv) {
- svn = sv->next;
- if (sv->flag == 0) {
- BLI_remlink(&sc->vertbase, sv);
- MEM_freeN(sv);
- }
- else {
- sv->flag = 0;
- }
- sv = svn;
- }
+ sv = sc->vertbase.first;
+ while (sv) {
+ svn = sv->next;
+ if (sv->flag == 0) {
+ BLI_remlink(&sc->vertbase, sv);
+ MEM_freeN(sv);
+ }
+ else {
+ sv->flag = 0;
+ }
+ sv = svn;
+ }
}
/* ***************** Utilities ********************** */
@@ -668,45 +680,45 @@ void BKE_screen_remove_unused_scrverts(bScreen *sc)
*/
ARegion *BKE_area_find_region_type(const ScrArea *sa, int region_type)
{
- if (sa) {
- for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
- if (ar->regiontype == region_type)
- return ar;
- }
- }
+ if (sa) {
+ for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->regiontype == region_type)
+ return ar;
+ }
+ }
- return NULL;
+ return NULL;
}
ARegion *BKE_area_find_region_active_win(ScrArea *sa)
{
- if (sa) {
- ARegion *ar = BLI_findlink(&sa->regionbase, sa->region_active_win);
- if (ar && (ar->regiontype == RGN_TYPE_WINDOW)) {
- return ar;
- }
+ if (sa) {
+ ARegion *ar = BLI_findlink(&sa->regionbase, sa->region_active_win);
+ if (ar && (ar->regiontype == RGN_TYPE_WINDOW)) {
+ return ar;
+ }
- /* fallback to any */
- return BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
- }
- return NULL;
+ /* fallback to any */
+ return BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+ }
+ return NULL;
}
ARegion *BKE_area_find_region_xy(ScrArea *sa, const int regiontype, int x, int y)
{
- ARegion *ar_found = NULL;
- if (sa) {
- ARegion *ar;
- for (ar = sa->regionbase.first; ar; ar = ar->next) {
- if ((regiontype == RGN_TYPE_ANY) || (ar->regiontype == regiontype)) {
- if (BLI_rcti_isect_pt(&ar->winrct, x, y)) {
- ar_found = ar;
- break;
- }
- }
- }
- }
- return ar_found;
+ ARegion *ar_found = NULL;
+ if (sa) {
+ ARegion *ar;
+ for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ if ((regiontype == RGN_TYPE_ANY) || (ar->regiontype == regiontype)) {
+ if (BLI_rcti_isect_pt(&ar->winrct, x, y)) {
+ ar_found = ar;
+ break;
+ }
+ }
+ }
+ }
+ return ar_found;
}
/**
@@ -715,15 +727,15 @@ ARegion *BKE_area_find_region_xy(ScrArea *sa, const int regiontype, int x, int y
*/
ScrArea *BKE_screen_find_area_from_space(struct bScreen *sc, SpaceLink *sl)
{
- ScrArea *sa;
+ ScrArea *sa;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- if (BLI_findindex(&sa->spacedata, sl) != -1) {
- break;
- }
- }
+ for (sa = sc->areabase.first; sa; sa = sa->next) {
+ if (BLI_findindex(&sa->spacedata, sl) != -1) {
+ break;
+ }
+ }
- return sa;
+ return sa;
}
/**
@@ -732,92 +744,95 @@ ScrArea *BKE_screen_find_area_from_space(struct bScreen *sc, SpaceLink *sl)
*/
ScrArea *BKE_screen_find_big_area(bScreen *sc, const int spacetype, const short min)
{
- ScrArea *sa, *big = NULL;
- int size, maxsize = 0;
-
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- if ((spacetype == SPACE_TYPE_ANY) || (sa->spacetype == spacetype)) {
- if (min <= sa->winx && min <= sa->winy) {
- size = sa->winx * sa->winy;
- if (size > maxsize) {
- maxsize = size;
- big = sa;
- }
- }
- }
- }
-
- return big;
-}
-
-ScrArea *BKE_screen_area_map_find_area_xy(const ScrAreaMap *areamap, const int spacetype, int x, int y)
-{
- for (ScrArea *sa = areamap->areabase.first; sa; sa = sa->next) {
- if (BLI_rcti_isect_pt(&sa->totrct, x, y)) {
- if ((spacetype == SPACE_TYPE_ANY) || (sa->spacetype == spacetype)) {
- return sa;
- }
- break;
- }
- }
- return NULL;
+ ScrArea *sa, *big = NULL;
+ int size, maxsize = 0;
+
+ for (sa = sc->areabase.first; sa; sa = sa->next) {
+ if ((spacetype == SPACE_TYPE_ANY) || (sa->spacetype == spacetype)) {
+ if (min <= sa->winx && min <= sa->winy) {
+ size = sa->winx * sa->winy;
+ if (size > maxsize) {
+ maxsize = size;
+ big = sa;
+ }
+ }
+ }
+ }
+
+ return big;
+}
+
+ScrArea *BKE_screen_area_map_find_area_xy(const ScrAreaMap *areamap,
+ const int spacetype,
+ int x,
+ int y)
+{
+ for (ScrArea *sa = areamap->areabase.first; sa; sa = sa->next) {
+ if (BLI_rcti_isect_pt(&sa->totrct, x, y)) {
+ if ((spacetype == SPACE_TYPE_ANY) || (sa->spacetype == spacetype)) {
+ return sa;
+ }
+ break;
+ }
+ }
+ return NULL;
}
ScrArea *BKE_screen_find_area_xy(bScreen *sc, const int spacetype, int x, int y)
{
- return BKE_screen_area_map_find_area_xy(AREAMAP_FROM_SCREEN(sc), spacetype, x, y);
+ return BKE_screen_area_map_find_area_xy(AREAMAP_FROM_SCREEN(sc), spacetype, x, y);
}
void BKE_screen_view3d_sync(View3D *v3d, struct Scene *scene)
{
- if (v3d->scenelock && v3d->localvd == NULL) {
- v3d->camera = scene->camera;
+ if (v3d->scenelock && v3d->localvd == NULL) {
+ v3d->camera = scene->camera;
- if (v3d->camera == NULL) {
- ARegion *ar;
+ if (v3d->camera == NULL) {
+ ARegion *ar;
- for (ar = v3d->regionbase.first; ar; ar = ar->next) {
- if (ar->regiontype == RGN_TYPE_WINDOW) {
- RegionView3D *rv3d = ar->regiondata;
- if (rv3d->persp == RV3D_CAMOB)
- rv3d->persp = RV3D_PERSP;
- }
- }
- }
- }
+ for (ar = v3d->regionbase.first; ar; ar = ar->next) {
+ if (ar->regiontype == RGN_TYPE_WINDOW) {
+ RegionView3D *rv3d = ar->regiondata;
+ if (rv3d->persp == RV3D_CAMOB)
+ rv3d->persp = RV3D_PERSP;
+ }
+ }
+ }
+ }
}
void BKE_screen_view3d_scene_sync(bScreen *sc, Scene *scene)
{
- /* are there cameras in the views that are not in the scene? */
- ScrArea *sa;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
- if (sl->spacetype == SPACE_VIEW3D) {
- View3D *v3d = (View3D *) sl;
- BKE_screen_view3d_sync(v3d, scene);
- }
- }
- }
+ /* are there cameras in the views that are not in the scene? */
+ ScrArea *sa;
+ for (sa = sc->areabase.first; sa; sa = sa->next) {
+ SpaceLink *sl;
+ for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ BKE_screen_view3d_sync(v3d, scene);
+ }
+ }
+ }
}
void BKE_screen_view3d_shading_init(View3DShading *shading)
{
- memset(shading, 0, sizeof(*shading));
+ memset(shading, 0, sizeof(*shading));
- shading->type = OB_SOLID;
- shading->prev_type = OB_SOLID;
- shading->flag = V3D_SHADING_SPECULAR_HIGHLIGHT | V3D_SHADING_XRAY_BONE;
- shading->light = V3D_LIGHTING_STUDIO;
- shading->shadow_intensity = 0.5f;
- shading->xray_alpha = 0.5f;
- shading->xray_alpha_wire = 0.5f;
- shading->cavity_valley_factor = 1.0f;
- shading->cavity_ridge_factor = 1.0f;
- shading->curvature_ridge_factor = 1.0f;
- shading->curvature_valley_factor = 1.0f;
- copy_v3_fl(shading->single_color, 0.8f);
- copy_v3_fl(shading->background_color, 0.05f);
+ shading->type = OB_SOLID;
+ shading->prev_type = OB_SOLID;
+ shading->flag = V3D_SHADING_SPECULAR_HIGHLIGHT | V3D_SHADING_XRAY_BONE;
+ shading->light = V3D_LIGHTING_STUDIO;
+ shading->shadow_intensity = 0.5f;
+ shading->xray_alpha = 0.5f;
+ shading->xray_alpha_wire = 0.5f;
+ shading->cavity_valley_factor = 1.0f;
+ shading->cavity_ridge_factor = 1.0f;
+ shading->curvature_ridge_factor = 1.0f;
+ shading->curvature_valley_factor = 1.0f;
+ copy_v3_fl(shading->single_color, 0.8f);
+ copy_v3_fl(shading->background_color, 0.05f);
}
/* magic zoom calculation, no idea what
@@ -830,44 +845,44 @@ void BKE_screen_view3d_shading_init(View3DShading *shading)
*/
float BKE_screen_view3d_zoom_to_fac(float camzoom)
{
- return powf(((float)M_SQRT2 + camzoom / 50.0f), 2.0f) / 4.0f;
+ return powf(((float)M_SQRT2 + camzoom / 50.0f), 2.0f) / 4.0f;
}
float BKE_screen_view3d_zoom_from_fac(float zoomfac)
{
- return ((sqrtf(4.0f * zoomfac) - (float)M_SQRT2) * 50.0f);
+ return ((sqrtf(4.0f * zoomfac) - (float)M_SQRT2) * 50.0f);
}
bool BKE_screen_is_fullscreen_area(const bScreen *screen)
{
- return ELEM(screen->state, SCREENMAXIMIZED, SCREENFULL);
+ return ELEM(screen->state, SCREENMAXIMIZED, SCREENFULL);
}
bool BKE_screen_is_used(const bScreen *screen)
{
- return (screen->winid != 0);
+ return (screen->winid != 0);
}
void BKE_screen_header_alignment_reset(bScreen *screen)
{
- int alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
- if (ar->regiontype == RGN_TYPE_HEADER) {
- if (ELEM(sa->spacetype, SPACE_FILE, SPACE_USERPREF, SPACE_OUTLINER, SPACE_PROPERTIES)) {
- ar->alignment = RGN_ALIGN_TOP;
- continue;
- }
- ar->alignment = alignment;
- }
- if (ar->regiontype == RGN_TYPE_FOOTER) {
- if (ELEM(sa->spacetype, SPACE_FILE, SPACE_USERPREF, SPACE_OUTLINER, SPACE_PROPERTIES)) {
- ar->alignment = RGN_ALIGN_BOTTOM;
- continue;
- }
- ar->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_TOP : RGN_ALIGN_BOTTOM;
- }
- }
- }
- screen->do_refresh = true;
+ int alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->regiontype == RGN_TYPE_HEADER) {
+ if (ELEM(sa->spacetype, SPACE_FILE, SPACE_USERPREF, SPACE_OUTLINER, SPACE_PROPERTIES)) {
+ ar->alignment = RGN_ALIGN_TOP;
+ continue;
+ }
+ ar->alignment = alignment;
+ }
+ if (ar->regiontype == RGN_TYPE_FOOTER) {
+ if (ELEM(sa->spacetype, SPACE_FILE, SPACE_USERPREF, SPACE_OUTLINER, SPACE_PROPERTIES)) {
+ ar->alignment = RGN_ALIGN_BOTTOM;
+ continue;
+ }
+ ar->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_TOP : RGN_ALIGN_BOTTOM;
+ }
+ }
+ }
+ screen->do_refresh = true;
}
diff --git a/source/blender/blenkernel/intern/seqcache.c b/source/blender/blenkernel/intern/seqcache.c
index 14d6fb0a17e..7024bafd988 100644
--- a/source/blender/blenkernel/intern/seqcache.c
+++ b/source/blender/blenkernel/intern/seqcache.c
@@ -22,7 +22,7 @@
#include <stddef.h>
-#include "BLI_sys_types.h" /* for intptr_t */
+#include "BLI_sys_types.h" /* for intptr_t */
#include "MEM_guardedalloc.h"
@@ -39,25 +39,25 @@
#include "BKE_scene.h"
typedef struct SeqCacheKey {
- struct Sequence *seq;
- SeqRenderData context;
- float cfra;
- eSeqStripElemIBuf type;
+ struct Sequence *seq;
+ SeqRenderData context;
+ float cfra;
+ eSeqStripElemIBuf type;
} SeqCacheKey;
typedef struct SeqPreprocessCacheElem {
- struct SeqPreprocessCacheElem *next, *prev;
+ struct SeqPreprocessCacheElem *next, *prev;
- struct Sequence *seq;
- SeqRenderData context;
- eSeqStripElemIBuf type;
+ struct Sequence *seq;
+ SeqRenderData context;
+ eSeqStripElemIBuf type;
- ImBuf *ibuf;
+ ImBuf *ibuf;
} SeqPreprocessCacheElem;
typedef struct SeqPreprocessCache {
- int cfra;
- ListBase elems;
+ int cfra;
+ ListBase elems;
} SeqPreprocessCache;
static struct MovieCache *moviecache = NULL;
@@ -67,215 +67,219 @@ static void preprocessed_cache_destruct(void);
static bool seq_cmp_render_data(const SeqRenderData *a, const SeqRenderData *b)
{
- return ((a->preview_render_size != b->preview_render_size) ||
- (a->rectx != b->rectx) ||
- (a->recty != b->recty) ||
- (a->bmain != b->bmain) ||
- (a->scene != b->scene) ||
- (a->motion_blur_shutter != b->motion_blur_shutter) ||
- (a->motion_blur_samples != b->motion_blur_samples) ||
- (a->scene->r.views_format != b->scene->r.views_format) ||
- (a->view_id != b->view_id));
+ return ((a->preview_render_size != b->preview_render_size) || (a->rectx != b->rectx) ||
+ (a->recty != b->recty) || (a->bmain != b->bmain) || (a->scene != b->scene) ||
+ (a->motion_blur_shutter != b->motion_blur_shutter) ||
+ (a->motion_blur_samples != b->motion_blur_samples) ||
+ (a->scene->r.views_format != b->scene->r.views_format) || (a->view_id != b->view_id));
}
static unsigned int seq_hash_render_data(const SeqRenderData *a)
{
- unsigned int rval = a->rectx + a->recty;
+ unsigned int rval = a->rectx + a->recty;
- rval ^= a->preview_render_size;
- rval ^= ((intptr_t) a->bmain) << 6;
- rval ^= ((intptr_t) a->scene) << 6;
- rval ^= (int)(a->motion_blur_shutter * 100.0f) << 10;
- rval ^= a->motion_blur_samples << 16;
- rval ^= ((a->scene->r.views_format * 2) + a->view_id) << 24;
+ rval ^= a->preview_render_size;
+ rval ^= ((intptr_t)a->bmain) << 6;
+ rval ^= ((intptr_t)a->scene) << 6;
+ rval ^= (int)(a->motion_blur_shutter * 100.0f) << 10;
+ rval ^= a->motion_blur_samples << 16;
+ rval ^= ((a->scene->r.views_format * 2) + a->view_id) << 24;
- return rval;
+ return rval;
}
static unsigned int seqcache_hashhash(const void *key_)
{
- const SeqCacheKey *key = key_;
- unsigned int rval = seq_hash_render_data(&key->context);
+ const SeqCacheKey *key = key_;
+ unsigned int rval = seq_hash_render_data(&key->context);
- rval ^= *(const unsigned int *) &key->cfra;
- rval += key->type;
- rval ^= ((intptr_t) key->seq) << 6;
+ rval ^= *(const unsigned int *)&key->cfra;
+ rval += key->type;
+ rval ^= ((intptr_t)key->seq) << 6;
- return rval;
+ return rval;
}
static bool seqcache_hashcmp(const void *a_, const void *b_)
{
- const SeqCacheKey *a = a_;
- const SeqCacheKey *b = b_;
+ const SeqCacheKey *a = a_;
+ const SeqCacheKey *b = b_;
- return ((a->seq != b->seq) ||
- (a->cfra != b->cfra) ||
- (a->type != b->type) ||
- seq_cmp_render_data(&a->context, &b->context));
+ return ((a->seq != b->seq) || (a->cfra != b->cfra) || (a->type != b->type) ||
+ seq_cmp_render_data(&a->context, &b->context));
}
void BKE_sequencer_cache_destruct(void)
{
- if (moviecache)
- IMB_moviecache_free(moviecache);
+ if (moviecache)
+ IMB_moviecache_free(moviecache);
- preprocessed_cache_destruct();
+ preprocessed_cache_destruct();
}
void BKE_sequencer_cache_cleanup(void)
{
- if (moviecache) {
- IMB_moviecache_free(moviecache);
- moviecache = IMB_moviecache_create("seqcache", sizeof(SeqCacheKey), seqcache_hashhash, seqcache_hashcmp);
- }
+ if (moviecache) {
+ IMB_moviecache_free(moviecache);
+ moviecache = IMB_moviecache_create(
+ "seqcache", sizeof(SeqCacheKey), seqcache_hashhash, seqcache_hashcmp);
+ }
- BKE_sequencer_preprocessed_cache_cleanup();
+ BKE_sequencer_preprocessed_cache_cleanup();
}
static bool seqcache_key_check_seq(ImBuf *UNUSED(ibuf), void *userkey, void *userdata)
{
- SeqCacheKey *key = (SeqCacheKey *) userkey;
- Sequence *seq = (Sequence *) userdata;
+ SeqCacheKey *key = (SeqCacheKey *)userkey;
+ Sequence *seq = (Sequence *)userdata;
- return key->seq == seq;
+ return key->seq == seq;
}
void BKE_sequencer_cache_cleanup_sequence(Sequence *seq)
{
- if (moviecache)
- IMB_moviecache_cleanup(moviecache, seqcache_key_check_seq, seq);
+ if (moviecache)
+ IMB_moviecache_cleanup(moviecache, seqcache_key_check_seq, seq);
}
-struct ImBuf *BKE_sequencer_cache_get(const SeqRenderData *context, Sequence *seq, float cfra, eSeqStripElemIBuf type)
+struct ImBuf *BKE_sequencer_cache_get(const SeqRenderData *context,
+ Sequence *seq,
+ float cfra,
+ eSeqStripElemIBuf type)
{
- if (moviecache && seq) {
- SeqCacheKey key;
+ if (moviecache && seq) {
+ SeqCacheKey key;
- key.seq = seq;
- key.context = *context;
- key.cfra = cfra - seq->start;
- key.type = type;
+ key.seq = seq;
+ key.context = *context;
+ key.cfra = cfra - seq->start;
+ key.type = type;
- return IMB_moviecache_get(moviecache, &key);
- }
+ return IMB_moviecache_get(moviecache, &key);
+ }
- return NULL;
+ return NULL;
}
-void BKE_sequencer_cache_put(const SeqRenderData *context, Sequence *seq, float cfra, eSeqStripElemIBuf type, ImBuf *i)
+void BKE_sequencer_cache_put(
+ const SeqRenderData *context, Sequence *seq, float cfra, eSeqStripElemIBuf type, ImBuf *i)
{
- SeqCacheKey key;
+ SeqCacheKey key;
- if (i == NULL || context->skip_cache) {
- return;
- }
+ if (i == NULL || context->skip_cache) {
+ return;
+ }
- if (!moviecache) {
- moviecache = IMB_moviecache_create("seqcache", sizeof(SeqCacheKey), seqcache_hashhash, seqcache_hashcmp);
- }
+ if (!moviecache) {
+ moviecache = IMB_moviecache_create(
+ "seqcache", sizeof(SeqCacheKey), seqcache_hashhash, seqcache_hashcmp);
+ }
- key.seq = seq;
- key.context = *context;
- key.cfra = cfra - seq->start;
- key.type = type;
+ key.seq = seq;
+ key.context = *context;
+ key.cfra = cfra - seq->start;
+ key.type = type;
- IMB_moviecache_put(moviecache, &key, i);
+ IMB_moviecache_put(moviecache, &key, i);
}
void BKE_sequencer_preprocessed_cache_cleanup(void)
{
- SeqPreprocessCacheElem *elem;
+ SeqPreprocessCacheElem *elem;
- if (!preprocess_cache)
- return;
+ if (!preprocess_cache)
+ return;
- for (elem = preprocess_cache->elems.first; elem; elem = elem->next) {
- IMB_freeImBuf(elem->ibuf);
- }
- BLI_freelistN(&preprocess_cache->elems);
+ for (elem = preprocess_cache->elems.first; elem; elem = elem->next) {
+ IMB_freeImBuf(elem->ibuf);
+ }
+ BLI_freelistN(&preprocess_cache->elems);
- BLI_listbase_clear(&preprocess_cache->elems);
+ BLI_listbase_clear(&preprocess_cache->elems);
}
static void preprocessed_cache_destruct(void)
{
- if (!preprocess_cache)
- return;
+ if (!preprocess_cache)
+ return;
- BKE_sequencer_preprocessed_cache_cleanup();
+ BKE_sequencer_preprocessed_cache_cleanup();
- MEM_freeN(preprocess_cache);
- preprocess_cache = NULL;
+ MEM_freeN(preprocess_cache);
+ preprocess_cache = NULL;
}
-ImBuf *BKE_sequencer_preprocessed_cache_get(const SeqRenderData *context, Sequence *seq, float cfra, eSeqStripElemIBuf type)
+ImBuf *BKE_sequencer_preprocessed_cache_get(const SeqRenderData *context,
+ Sequence *seq,
+ float cfra,
+ eSeqStripElemIBuf type)
{
- SeqPreprocessCacheElem *elem;
+ SeqPreprocessCacheElem *elem;
- if (!preprocess_cache)
- return NULL;
+ if (!preprocess_cache)
+ return NULL;
- if (preprocess_cache->cfra != cfra)
- return NULL;
+ if (preprocess_cache->cfra != cfra)
+ return NULL;
- for (elem = preprocess_cache->elems.first; elem; elem = elem->next) {
- if (elem->seq != seq)
- continue;
+ for (elem = preprocess_cache->elems.first; elem; elem = elem->next) {
+ if (elem->seq != seq)
+ continue;
- if (elem->type != type)
- continue;
+ if (elem->type != type)
+ continue;
- if (seq_cmp_render_data(&elem->context, context) != 0)
- continue;
+ if (seq_cmp_render_data(&elem->context, context) != 0)
+ continue;
- IMB_refImBuf(elem->ibuf);
- return elem->ibuf;
- }
+ IMB_refImBuf(elem->ibuf);
+ return elem->ibuf;
+ }
- return NULL;
+ return NULL;
}
-void BKE_sequencer_preprocessed_cache_put(const SeqRenderData *context, Sequence *seq, float cfra, eSeqStripElemIBuf type, ImBuf *ibuf)
+void BKE_sequencer_preprocessed_cache_put(
+ const SeqRenderData *context, Sequence *seq, float cfra, eSeqStripElemIBuf type, ImBuf *ibuf)
{
- SeqPreprocessCacheElem *elem;
+ SeqPreprocessCacheElem *elem;
- if (!preprocess_cache) {
- preprocess_cache = MEM_callocN(sizeof(SeqPreprocessCache), "sequencer preprocessed cache");
- }
- else {
- if (preprocess_cache->cfra != cfra)
- BKE_sequencer_preprocessed_cache_cleanup();
- }
+ if (!preprocess_cache) {
+ preprocess_cache = MEM_callocN(sizeof(SeqPreprocessCache), "sequencer preprocessed cache");
+ }
+ else {
+ if (preprocess_cache->cfra != cfra)
+ BKE_sequencer_preprocessed_cache_cleanup();
+ }
- elem = MEM_callocN(sizeof(SeqPreprocessCacheElem), "sequencer preprocessed cache element");
+ elem = MEM_callocN(sizeof(SeqPreprocessCacheElem), "sequencer preprocessed cache element");
- elem->seq = seq;
- elem->type = type;
- elem->context = *context;
- elem->ibuf = ibuf;
+ elem->seq = seq;
+ elem->type = type;
+ elem->context = *context;
+ elem->ibuf = ibuf;
- preprocess_cache->cfra = cfra;
+ preprocess_cache->cfra = cfra;
- IMB_refImBuf(ibuf);
+ IMB_refImBuf(ibuf);
- BLI_addtail(&preprocess_cache->elems, elem);
+ BLI_addtail(&preprocess_cache->elems, elem);
}
void BKE_sequencer_preprocessed_cache_cleanup_sequence(Sequence *seq)
{
- SeqPreprocessCacheElem *elem, *elem_next;
+ SeqPreprocessCacheElem *elem, *elem_next;
- if (!preprocess_cache)
- return;
+ if (!preprocess_cache)
+ return;
- for (elem = preprocess_cache->elems.first; elem; elem = elem_next) {
- elem_next = elem->next;
+ for (elem = preprocess_cache->elems.first; elem; elem = elem_next) {
+ elem_next = elem->next;
- if (elem->seq == seq) {
- IMB_freeImBuf(elem->ibuf);
+ if (elem->seq == seq) {
+ IMB_freeImBuf(elem->ibuf);
- BLI_freelinkN(&preprocess_cache->elems, elem);
- }
- }
+ BLI_freelinkN(&preprocess_cache->elems, elem);
+ }
+ }
}
diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c
index 6ef3f980c85..fa596c875a8 100644
--- a/source/blender/blenkernel/intern/seqeffects.c
+++ b/source/blender/blenkernel/intern/seqeffects.c
@@ -24,7 +24,6 @@
* \ingroup bke
*/
-
#include <string.h>
#include <math.h>
#include <stdlib.h>
@@ -61,557 +60,641 @@
#include "BLF_api.h"
-static void slice_get_byte_buffers(
- const SeqRenderData *context, const ImBuf *ibuf1, const ImBuf *ibuf2,
- const ImBuf *ibuf3, const ImBuf *out, int start_line, unsigned char **rect1,
- unsigned char **rect2, unsigned char **rect3, unsigned char **rect_out)
+static void slice_get_byte_buffers(const SeqRenderData *context,
+ const ImBuf *ibuf1,
+ const ImBuf *ibuf2,
+ const ImBuf *ibuf3,
+ const ImBuf *out,
+ int start_line,
+ unsigned char **rect1,
+ unsigned char **rect2,
+ unsigned char **rect3,
+ unsigned char **rect_out)
{
- int offset = 4 * start_line * context->rectx;
+ int offset = 4 * start_line * context->rectx;
- *rect1 = (unsigned char *)ibuf1->rect + offset;
- *rect_out = (unsigned char *)out->rect + offset;
+ *rect1 = (unsigned char *)ibuf1->rect + offset;
+ *rect_out = (unsigned char *)out->rect + offset;
- if (ibuf2)
- *rect2 = (unsigned char *)ibuf2->rect + offset;
+ if (ibuf2)
+ *rect2 = (unsigned char *)ibuf2->rect + offset;
- if (ibuf3)
- *rect3 = (unsigned char *)ibuf3->rect + offset;
+ if (ibuf3)
+ *rect3 = (unsigned char *)ibuf3->rect + offset;
}
-static void slice_get_float_buffers(
- const SeqRenderData *context, const ImBuf *ibuf1, const ImBuf *ibuf2,
- const ImBuf *ibuf3, const ImBuf *out, int start_line,
- float **rect1, float **rect2, float **rect3, float **rect_out)
+static void slice_get_float_buffers(const SeqRenderData *context,
+ const ImBuf *ibuf1,
+ const ImBuf *ibuf2,
+ const ImBuf *ibuf3,
+ const ImBuf *out,
+ int start_line,
+ float **rect1,
+ float **rect2,
+ float **rect3,
+ float **rect_out)
{
- int offset = 4 * start_line * context->rectx;
+ int offset = 4 * start_line * context->rectx;
- *rect1 = ibuf1->rect_float + offset;
- *rect_out = out->rect_float + offset;
+ *rect1 = ibuf1->rect_float + offset;
+ *rect_out = out->rect_float + offset;
- if (ibuf2)
- *rect2 = ibuf2->rect_float + offset;
+ if (ibuf2)
+ *rect2 = ibuf2->rect_float + offset;
- if (ibuf3)
- *rect3 = ibuf3->rect_float + offset;
+ if (ibuf3)
+ *rect3 = ibuf3->rect_float + offset;
}
/*********************** Glow effect *************************/
enum {
- GlowR = 0,
- GlowG = 1,
- GlowB = 2,
- GlowA = 3,
+ GlowR = 0,
+ GlowG = 1,
+ GlowB = 2,
+ GlowA = 3,
};
-static ImBuf *prepare_effect_imbufs(const SeqRenderData *context, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3)
-{
- ImBuf *out;
- Scene *scene = context->scene;
- int x = context->rectx;
- int y = context->recty;
-
- if (!ibuf1 && !ibuf2 && !ibuf3) {
- /* hmmm, global float option ? */
- out = IMB_allocImBuf(x, y, 32, IB_rect);
- }
- else if ((ibuf1 && ibuf1->rect_float) ||
- (ibuf2 && ibuf2->rect_float) ||
- (ibuf3 && ibuf3->rect_float))
- {
- /* if any inputs are rectfloat, output is float too */
-
- out = IMB_allocImBuf(x, y, 32, IB_rectfloat);
- }
- else {
- out = IMB_allocImBuf(x, y, 32, IB_rect);
- }
-
- if (out->rect_float) {
- if (ibuf1 && !ibuf1->rect_float) {
- BKE_sequencer_imbuf_to_sequencer_space(scene, ibuf1, true);
- }
-
- if (ibuf2 && !ibuf2->rect_float) {
- BKE_sequencer_imbuf_to_sequencer_space(scene, ibuf2, true);
- }
-
- if (ibuf3 && !ibuf3->rect_float) {
- BKE_sequencer_imbuf_to_sequencer_space(scene, ibuf3, true);
- }
-
- IMB_colormanagement_assign_float_colorspace(out, scene->sequencer_colorspace_settings.name);
- }
- else {
- if (ibuf1 && !ibuf1->rect) {
- IMB_rect_from_float(ibuf1);
- }
-
- if (ibuf2 && !ibuf2->rect) {
- IMB_rect_from_float(ibuf2);
- }
-
- if (ibuf3 && !ibuf3->rect) {
- IMB_rect_from_float(ibuf3);
- }
- }
-
- /* If effect only affecting a single channel, forward input's metadata to the output. */
- if (ibuf1 != NULL && ibuf1 == ibuf2 && ibuf2 == ibuf3) {
- IMB_metadata_copy(out, ibuf1);
- }
-
- return out;
+static ImBuf *prepare_effect_imbufs(const SeqRenderData *context,
+ ImBuf *ibuf1,
+ ImBuf *ibuf2,
+ ImBuf *ibuf3)
+{
+ ImBuf *out;
+ Scene *scene = context->scene;
+ int x = context->rectx;
+ int y = context->recty;
+
+ if (!ibuf1 && !ibuf2 && !ibuf3) {
+ /* hmmm, global float option ? */
+ out = IMB_allocImBuf(x, y, 32, IB_rect);
+ }
+ else if ((ibuf1 && ibuf1->rect_float) || (ibuf2 && ibuf2->rect_float) ||
+ (ibuf3 && ibuf3->rect_float)) {
+ /* if any inputs are rectfloat, output is float too */
+
+ out = IMB_allocImBuf(x, y, 32, IB_rectfloat);
+ }
+ else {
+ out = IMB_allocImBuf(x, y, 32, IB_rect);
+ }
+
+ if (out->rect_float) {
+ if (ibuf1 && !ibuf1->rect_float) {
+ BKE_sequencer_imbuf_to_sequencer_space(scene, ibuf1, true);
+ }
+
+ if (ibuf2 && !ibuf2->rect_float) {
+ BKE_sequencer_imbuf_to_sequencer_space(scene, ibuf2, true);
+ }
+
+ if (ibuf3 && !ibuf3->rect_float) {
+ BKE_sequencer_imbuf_to_sequencer_space(scene, ibuf3, true);
+ }
+
+ IMB_colormanagement_assign_float_colorspace(out, scene->sequencer_colorspace_settings.name);
+ }
+ else {
+ if (ibuf1 && !ibuf1->rect) {
+ IMB_rect_from_float(ibuf1);
+ }
+
+ if (ibuf2 && !ibuf2->rect) {
+ IMB_rect_from_float(ibuf2);
+ }
+
+ if (ibuf3 && !ibuf3->rect) {
+ IMB_rect_from_float(ibuf3);
+ }
+ }
+
+ /* If effect only affecting a single channel, forward input's metadata to the output. */
+ if (ibuf1 != NULL && ibuf1 == ibuf2 && ibuf2 == ibuf3) {
+ IMB_metadata_copy(out, ibuf1);
+ }
+
+ return out;
}
/*********************** Alpha Over *************************/
static void init_alpha_over_or_under(Sequence *seq)
{
- Sequence *seq1 = seq->seq1;
- Sequence *seq2 = seq->seq2;
-
- seq->seq2 = seq1;
- seq->seq1 = seq2;
-}
-
-static void do_alphaover_effect_byte(
- float facf0, float facf1, int x, int y,
- unsigned char *rect1, unsigned char *rect2, unsigned char *out)
-{
- float fac2, mfac, fac, fac4;
- int xo;
- unsigned char *cp1, *cp2, *rt;
- float tempc[4], rt1[4], rt2[4];
-
- xo = x;
- cp1 = rect1;
- cp2 = rect2;
- rt = out;
-
- fac2 = facf0;
- fac4 = facf1;
-
- while (y--) {
- x = xo;
- while (x--) {
- /* rt = rt1 over rt2 (alpha from rt1) */
-
- straight_uchar_to_premul_float(rt1, cp1);
- straight_uchar_to_premul_float(rt2, cp2);
-
- fac = fac2;
- mfac = 1.0f - fac2 * rt1[3];
-
- if (fac <= 0.0f) *((unsigned int *) rt) = *((unsigned int *) cp2);
- else if (mfac <= 0.0f) *((unsigned int *) rt) = *((unsigned int *) cp1);
- else {
- tempc[0] = fac * rt1[0] + mfac * rt2[0];
- tempc[1] = fac * rt1[1] + mfac * rt2[1];
- tempc[2] = fac * rt1[2] + mfac * rt2[2];
- tempc[3] = fac * rt1[3] + mfac * rt2[3];
-
- premul_float_to_straight_uchar(rt, tempc);
- }
- cp1 += 4; cp2 += 4; rt += 4;
- }
-
- if (y == 0) break;
- y--;
-
- x = xo;
- while (x--) {
- straight_uchar_to_premul_float(rt1, cp1);
- straight_uchar_to_premul_float(rt2, cp2);
-
- fac = fac4;
- mfac = 1.0f - (fac4 * rt1[3]);
-
- if (fac <= 0.0f) *((unsigned int *) rt) = *((unsigned int *) cp2);
- else if (mfac <= 0.0f) *((unsigned int *) rt) = *((unsigned int *) cp1);
- else {
- tempc[0] = fac * rt1[0] + mfac * rt2[0];
- tempc[1] = fac * rt1[1] + mfac * rt2[1];
- tempc[2] = fac * rt1[2] + mfac * rt2[2];
- tempc[3] = fac * rt1[3] + mfac * rt2[3];
-
- premul_float_to_straight_uchar(rt, tempc);
- }
- cp1 += 4; cp2 += 4; rt += 4;
- }
- }
+ Sequence *seq1 = seq->seq1;
+ Sequence *seq2 = seq->seq2;
+
+ seq->seq2 = seq1;
+ seq->seq1 = seq2;
+}
+
+static void do_alphaover_effect_byte(float facf0,
+ float facf1,
+ int x,
+ int y,
+ unsigned char *rect1,
+ unsigned char *rect2,
+ unsigned char *out)
+{
+ float fac2, mfac, fac, fac4;
+ int xo;
+ unsigned char *cp1, *cp2, *rt;
+ float tempc[4], rt1[4], rt2[4];
+
+ xo = x;
+ cp1 = rect1;
+ cp2 = rect2;
+ rt = out;
+
+ fac2 = facf0;
+ fac4 = facf1;
+
+ while (y--) {
+ x = xo;
+ while (x--) {
+ /* rt = rt1 over rt2 (alpha from rt1) */
+
+ straight_uchar_to_premul_float(rt1, cp1);
+ straight_uchar_to_premul_float(rt2, cp2);
+
+ fac = fac2;
+ mfac = 1.0f - fac2 * rt1[3];
+
+ if (fac <= 0.0f)
+ *((unsigned int *)rt) = *((unsigned int *)cp2);
+ else if (mfac <= 0.0f)
+ *((unsigned int *)rt) = *((unsigned int *)cp1);
+ else {
+ tempc[0] = fac * rt1[0] + mfac * rt2[0];
+ tempc[1] = fac * rt1[1] + mfac * rt2[1];
+ tempc[2] = fac * rt1[2] + mfac * rt2[2];
+ tempc[3] = fac * rt1[3] + mfac * rt2[3];
+
+ premul_float_to_straight_uchar(rt, tempc);
+ }
+ cp1 += 4;
+ cp2 += 4;
+ rt += 4;
+ }
+
+ if (y == 0)
+ break;
+ y--;
+
+ x = xo;
+ while (x--) {
+ straight_uchar_to_premul_float(rt1, cp1);
+ straight_uchar_to_premul_float(rt2, cp2);
+
+ fac = fac4;
+ mfac = 1.0f - (fac4 * rt1[3]);
+
+ if (fac <= 0.0f)
+ *((unsigned int *)rt) = *((unsigned int *)cp2);
+ else if (mfac <= 0.0f)
+ *((unsigned int *)rt) = *((unsigned int *)cp1);
+ else {
+ tempc[0] = fac * rt1[0] + mfac * rt2[0];
+ tempc[1] = fac * rt1[1] + mfac * rt2[1];
+ tempc[2] = fac * rt1[2] + mfac * rt2[2];
+ tempc[3] = fac * rt1[3] + mfac * rt2[3];
+
+ premul_float_to_straight_uchar(rt, tempc);
+ }
+ cp1 += 4;
+ cp2 += 4;
+ rt += 4;
+ }
+ }
}
static void do_alphaover_effect_float(
- float facf0, float facf1, int x, int y,
- float *rect1, float *rect2, float *out)
-{
- float fac2, mfac, fac, fac4;
- int xo;
- float *rt1, *rt2, *rt;
-
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
-
- fac2 = facf0;
- fac4 = facf1;
-
- while (y--) {
- x = xo;
- while (x--) {
- /* rt = rt1 over rt2 (alpha from rt1) */
-
- fac = fac2;
- mfac = 1.0f - (fac2 * rt1[3]);
-
- if (fac <= 0.0f) {
- memcpy(rt, rt2, 4 * sizeof(float));
- }
- else if (mfac <= 0) {
- memcpy(rt, rt1, 4 * sizeof(float));
- }
- else {
- rt[0] = fac * rt1[0] + mfac * rt2[0];
- rt[1] = fac * rt1[1] + mfac * rt2[1];
- rt[2] = fac * rt1[2] + mfac * rt2[2];
- rt[3] = fac * rt1[3] + mfac * rt2[3];
- }
- rt1 += 4; rt2 += 4; rt += 4;
- }
-
- if (y == 0)
- break;
- y--;
-
- x = xo;
- while (x--) {
- fac = fac4;
- mfac = 1.0f - (fac4 * rt1[3]);
-
- if (fac <= 0.0f) {
- memcpy(rt, rt2, 4 * sizeof(float));
- }
- else if (mfac <= 0.0f) {
- memcpy(rt, rt1, 4 * sizeof(float));
- }
- else {
- rt[0] = fac * rt1[0] + mfac * rt2[0];
- rt[1] = fac * rt1[1] + mfac * rt2[1];
- rt[2] = fac * rt1[2] + mfac * rt2[2];
- rt[3] = fac * rt1[3] + mfac * rt2[3];
- }
- rt1 += 4; rt2 += 4; rt += 4;
- }
- }
-}
-
-static void do_alphaover_effect(
- const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra), float facf0,
- float facf1, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3),
- int start_line, int total_lines, ImBuf *out)
-{
- if (out->rect_float) {
- float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
-
- slice_get_float_buffers(context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
-
- do_alphaover_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
- }
- else {
- unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
-
- slice_get_byte_buffers(context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
-
- do_alphaover_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
- }
+ float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out)
+{
+ float fac2, mfac, fac, fac4;
+ int xo;
+ float *rt1, *rt2, *rt;
+
+ xo = x;
+ rt1 = rect1;
+ rt2 = rect2;
+ rt = out;
+
+ fac2 = facf0;
+ fac4 = facf1;
+
+ while (y--) {
+ x = xo;
+ while (x--) {
+ /* rt = rt1 over rt2 (alpha from rt1) */
+
+ fac = fac2;
+ mfac = 1.0f - (fac2 * rt1[3]);
+
+ if (fac <= 0.0f) {
+ memcpy(rt, rt2, 4 * sizeof(float));
+ }
+ else if (mfac <= 0) {
+ memcpy(rt, rt1, 4 * sizeof(float));
+ }
+ else {
+ rt[0] = fac * rt1[0] + mfac * rt2[0];
+ rt[1] = fac * rt1[1] + mfac * rt2[1];
+ rt[2] = fac * rt1[2] + mfac * rt2[2];
+ rt[3] = fac * rt1[3] + mfac * rt2[3];
+ }
+ rt1 += 4;
+ rt2 += 4;
+ rt += 4;
+ }
+
+ if (y == 0)
+ break;
+ y--;
+
+ x = xo;
+ while (x--) {
+ fac = fac4;
+ mfac = 1.0f - (fac4 * rt1[3]);
+
+ if (fac <= 0.0f) {
+ memcpy(rt, rt2, 4 * sizeof(float));
+ }
+ else if (mfac <= 0.0f) {
+ memcpy(rt, rt1, 4 * sizeof(float));
+ }
+ else {
+ rt[0] = fac * rt1[0] + mfac * rt2[0];
+ rt[1] = fac * rt1[1] + mfac * rt2[1];
+ rt[2] = fac * rt1[2] + mfac * rt2[2];
+ rt[3] = fac * rt1[3] + mfac * rt2[3];
+ }
+ rt1 += 4;
+ rt2 += 4;
+ rt += 4;
+ }
+ }
+}
+
+static void do_alphaover_effect(const SeqRenderData *context,
+ Sequence *UNUSED(seq),
+ float UNUSED(cfra),
+ float facf0,
+ float facf1,
+ ImBuf *ibuf1,
+ ImBuf *ibuf2,
+ ImBuf *UNUSED(ibuf3),
+ int start_line,
+ int total_lines,
+ ImBuf *out)
+{
+ if (out->rect_float) {
+ float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
+
+ slice_get_float_buffers(
+ context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
+
+ do_alphaover_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ }
+ else {
+ unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
+
+ slice_get_byte_buffers(
+ context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
+
+ do_alphaover_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ }
}
/*********************** Alpha Under *************************/
-static void do_alphaunder_effect_byte(
- float facf0, float facf1, int x, int y,
- unsigned char *rect1, unsigned char *rect2, unsigned char *out)
-{
- float fac2, fac, fac4;
- int xo;
- unsigned char *cp1, *cp2, *rt;
- float tempc[4], rt1[4], rt2[4];
-
- xo = x;
- cp1 = rect1;
- cp2 = rect2;
- rt = out;
-
- fac2 = facf0;
- fac4 = facf1;
-
- while (y--) {
- x = xo;
- while (x--) {
- /* rt = rt1 under rt2 (alpha from rt2) */
- straight_uchar_to_premul_float(rt1, cp1);
- straight_uchar_to_premul_float(rt2, cp2);
-
- /* this complex optimization is because the
- * 'skybuf' can be crossed in
- */
- if (rt2[3] <= 0.0f && fac2 >= 1.0f) *((unsigned int *) rt) = *((unsigned int *) cp1);
- else if (rt2[3] >= 1.0f) *((unsigned int *) rt) = *((unsigned int *) cp2);
- else {
- fac = (fac2 * (1.0f - rt2[3]));
-
- if (fac <= 0) *((unsigned int *) rt) = *((unsigned int *) cp2);
- else {
- tempc[0] = (fac * rt1[0] + rt2[0]);
- tempc[1] = (fac * rt1[1] + rt2[1]);
- tempc[2] = (fac * rt1[2] + rt2[2]);
- tempc[3] = (fac * rt1[3] + rt2[3]);
-
- premul_float_to_straight_uchar(rt, tempc);
- }
- }
- cp1 += 4; cp2 += 4; rt += 4;
- }
-
- if (y == 0)
- break;
- y--;
-
- x = xo;
- while (x--) {
- straight_uchar_to_premul_float(rt1, cp1);
- straight_uchar_to_premul_float(rt2, cp2);
-
- if (rt2[3] <= 0.0f && fac4 >= 1.0f) *((unsigned int *) rt) = *((unsigned int *) cp1);
- else if (rt2[3] >= 1.0f) *((unsigned int *) rt) = *((unsigned int *) cp2);
- else {
- fac = (fac4 * (1.0f - rt2[3]));
-
- if (fac <= 0) *((unsigned int *)rt) = *((unsigned int *)cp2);
- else {
- tempc[0] = (fac * rt1[0] + rt2[0]);
- tempc[1] = (fac * rt1[1] + rt2[1]);
- tempc[2] = (fac * rt1[2] + rt2[2]);
- tempc[3] = (fac * rt1[3] + rt2[3]);
-
- premul_float_to_straight_uchar(rt, tempc);
- }
- }
- cp1 += 4; cp2 += 4; rt += 4;
- }
- }
+static void do_alphaunder_effect_byte(float facf0,
+ float facf1,
+ int x,
+ int y,
+ unsigned char *rect1,
+ unsigned char *rect2,
+ unsigned char *out)
+{
+ float fac2, fac, fac4;
+ int xo;
+ unsigned char *cp1, *cp2, *rt;
+ float tempc[4], rt1[4], rt2[4];
+
+ xo = x;
+ cp1 = rect1;
+ cp2 = rect2;
+ rt = out;
+
+ fac2 = facf0;
+ fac4 = facf1;
+
+ while (y--) {
+ x = xo;
+ while (x--) {
+ /* rt = rt1 under rt2 (alpha from rt2) */
+ straight_uchar_to_premul_float(rt1, cp1);
+ straight_uchar_to_premul_float(rt2, cp2);
+
+ /* this complex optimization is because the
+ * 'skybuf' can be crossed in
+ */
+ if (rt2[3] <= 0.0f && fac2 >= 1.0f)
+ *((unsigned int *)rt) = *((unsigned int *)cp1);
+ else if (rt2[3] >= 1.0f)
+ *((unsigned int *)rt) = *((unsigned int *)cp2);
+ else {
+ fac = (fac2 * (1.0f - rt2[3]));
+
+ if (fac <= 0)
+ *((unsigned int *)rt) = *((unsigned int *)cp2);
+ else {
+ tempc[0] = (fac * rt1[0] + rt2[0]);
+ tempc[1] = (fac * rt1[1] + rt2[1]);
+ tempc[2] = (fac * rt1[2] + rt2[2]);
+ tempc[3] = (fac * rt1[3] + rt2[3]);
+
+ premul_float_to_straight_uchar(rt, tempc);
+ }
+ }
+ cp1 += 4;
+ cp2 += 4;
+ rt += 4;
+ }
+
+ if (y == 0)
+ break;
+ y--;
+
+ x = xo;
+ while (x--) {
+ straight_uchar_to_premul_float(rt1, cp1);
+ straight_uchar_to_premul_float(rt2, cp2);
+
+ if (rt2[3] <= 0.0f && fac4 >= 1.0f)
+ *((unsigned int *)rt) = *((unsigned int *)cp1);
+ else if (rt2[3] >= 1.0f)
+ *((unsigned int *)rt) = *((unsigned int *)cp2);
+ else {
+ fac = (fac4 * (1.0f - rt2[3]));
+
+ if (fac <= 0)
+ *((unsigned int *)rt) = *((unsigned int *)cp2);
+ else {
+ tempc[0] = (fac * rt1[0] + rt2[0]);
+ tempc[1] = (fac * rt1[1] + rt2[1]);
+ tempc[2] = (fac * rt1[2] + rt2[2]);
+ tempc[3] = (fac * rt1[3] + rt2[3]);
+
+ premul_float_to_straight_uchar(rt, tempc);
+ }
+ }
+ cp1 += 4;
+ cp2 += 4;
+ rt += 4;
+ }
+ }
}
static void do_alphaunder_effect_float(
- float facf0, float facf1, int x, int y,
- float *rect1, float *rect2, float *out)
-{
- float fac2, fac, fac4;
- int xo;
- float *rt1, *rt2, *rt;
-
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
-
- fac2 = facf0;
- fac4 = facf1;
-
- while (y--) {
- x = xo;
- while (x--) {
- /* rt = rt1 under rt2 (alpha from rt2) */
-
- /* this complex optimization is because the
- * 'skybuf' can be crossed in
- */
- if (rt2[3] <= 0 && fac2 >= 1.0f) {
- memcpy(rt, rt1, 4 * sizeof(float));
- }
- else if (rt2[3] >= 1.0f) {
- memcpy(rt, rt2, 4 * sizeof(float));
- }
- else {
- fac = fac2 * (1.0f - rt2[3]);
-
- if (fac == 0) {
- memcpy(rt, rt2, 4 * sizeof(float));
- }
- else {
- rt[0] = fac * rt1[0] + rt2[0];
- rt[1] = fac * rt1[1] + rt2[1];
- rt[2] = fac * rt1[2] + rt2[2];
- rt[3] = fac * rt1[3] + rt2[3];
- }
- }
- rt1 += 4; rt2 += 4; rt += 4;
- }
-
- if (y == 0)
- break;
- y--;
-
- x = xo;
- while (x--) {
- if (rt2[3] <= 0 && fac4 >= 1.0f) {
- memcpy(rt, rt1, 4 * sizeof(float));
- }
- else if (rt2[3] >= 1.0f) {
- memcpy(rt, rt2, 4 * sizeof(float));
- }
- else {
- fac = fac4 * (1.0f - rt2[3]);
-
- if (fac == 0) {
- memcpy(rt, rt2, 4 * sizeof(float));
- }
- else {
- rt[0] = fac * rt1[0] + rt2[0];
- rt[1] = fac * rt1[1] + rt2[1];
- rt[2] = fac * rt1[2] + rt2[2];
- rt[3] = fac * rt1[3] + rt2[3];
- }
- }
- rt1 += 4; rt2 += 4; rt += 4;
- }
- }
-}
-
-static void do_alphaunder_effect(
- const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra),
- float facf0, float facf1, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3),
- int start_line, int total_lines, ImBuf *out)
-{
- if (out->rect_float) {
- float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
-
- slice_get_float_buffers(context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
-
- do_alphaunder_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
- }
- else {
- unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
-
- slice_get_byte_buffers(context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
-
- do_alphaunder_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
- }
+ float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out)
+{
+ float fac2, fac, fac4;
+ int xo;
+ float *rt1, *rt2, *rt;
+
+ xo = x;
+ rt1 = rect1;
+ rt2 = rect2;
+ rt = out;
+
+ fac2 = facf0;
+ fac4 = facf1;
+
+ while (y--) {
+ x = xo;
+ while (x--) {
+ /* rt = rt1 under rt2 (alpha from rt2) */
+
+ /* this complex optimization is because the
+ * 'skybuf' can be crossed in
+ */
+ if (rt2[3] <= 0 && fac2 >= 1.0f) {
+ memcpy(rt, rt1, 4 * sizeof(float));
+ }
+ else if (rt2[3] >= 1.0f) {
+ memcpy(rt, rt2, 4 * sizeof(float));
+ }
+ else {
+ fac = fac2 * (1.0f - rt2[3]);
+
+ if (fac == 0) {
+ memcpy(rt, rt2, 4 * sizeof(float));
+ }
+ else {
+ rt[0] = fac * rt1[0] + rt2[0];
+ rt[1] = fac * rt1[1] + rt2[1];
+ rt[2] = fac * rt1[2] + rt2[2];
+ rt[3] = fac * rt1[3] + rt2[3];
+ }
+ }
+ rt1 += 4;
+ rt2 += 4;
+ rt += 4;
+ }
+
+ if (y == 0)
+ break;
+ y--;
+
+ x = xo;
+ while (x--) {
+ if (rt2[3] <= 0 && fac4 >= 1.0f) {
+ memcpy(rt, rt1, 4 * sizeof(float));
+ }
+ else if (rt2[3] >= 1.0f) {
+ memcpy(rt, rt2, 4 * sizeof(float));
+ }
+ else {
+ fac = fac4 * (1.0f - rt2[3]);
+
+ if (fac == 0) {
+ memcpy(rt, rt2, 4 * sizeof(float));
+ }
+ else {
+ rt[0] = fac * rt1[0] + rt2[0];
+ rt[1] = fac * rt1[1] + rt2[1];
+ rt[2] = fac * rt1[2] + rt2[2];
+ rt[3] = fac * rt1[3] + rt2[3];
+ }
+ }
+ rt1 += 4;
+ rt2 += 4;
+ rt += 4;
+ }
+ }
+}
+
+static void do_alphaunder_effect(const SeqRenderData *context,
+ Sequence *UNUSED(seq),
+ float UNUSED(cfra),
+ float facf0,
+ float facf1,
+ ImBuf *ibuf1,
+ ImBuf *ibuf2,
+ ImBuf *UNUSED(ibuf3),
+ int start_line,
+ int total_lines,
+ ImBuf *out)
+{
+ if (out->rect_float) {
+ float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
+
+ slice_get_float_buffers(
+ context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
+
+ do_alphaunder_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ }
+ else {
+ unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
+
+ slice_get_byte_buffers(
+ context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
+
+ do_alphaunder_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ }
}
/*********************** Cross *************************/
-static void do_cross_effect_byte(
- float facf0, float facf1, int x, int y,
- unsigned char *rect1, unsigned char *rect2, unsigned char *out)
-{
- int fac1, fac2, fac3, fac4;
- int xo;
- unsigned char *rt1, *rt2, *rt;
-
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
-
- fac2 = (int) (256.0f * facf0);
- fac1 = 256 - fac2;
- fac4 = (int) (256.0f * facf1);
- fac3 = 256 - fac4;
-
- while (y--) {
- x = xo;
- while (x--) {
- rt[0] = (fac1 * rt1[0] + fac2 * rt2[0]) >> 8;
- rt[1] = (fac1 * rt1[1] + fac2 * rt2[1]) >> 8;
- rt[2] = (fac1 * rt1[2] + fac2 * rt2[2]) >> 8;
- rt[3] = (fac1 * rt1[3] + fac2 * rt2[3]) >> 8;
-
- rt1 += 4; rt2 += 4; rt += 4;
- }
-
- if (y == 0)
- break;
- y--;
-
- x = xo;
- while (x--) {
- rt[0] = (fac3 * rt1[0] + fac4 * rt2[0]) >> 8;
- rt[1] = (fac3 * rt1[1] + fac4 * rt2[1]) >> 8;
- rt[2] = (fac3 * rt1[2] + fac4 * rt2[2]) >> 8;
- rt[3] = (fac3 * rt1[3] + fac4 * rt2[3]) >> 8;
-
- rt1 += 4; rt2 += 4; rt += 4;
- }
-
- }
-}
-
-static void do_cross_effect_float(float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out)
-{
- float fac1, fac2, fac3, fac4;
- int xo;
- float *rt1, *rt2, *rt;
-
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
-
- fac2 = facf0;
- fac1 = 1.0f - fac2;
- fac4 = facf1;
- fac3 = 1.0f - fac4;
-
- while (y--) {
- x = xo;
- while (x--) {
- rt[0] = fac1 * rt1[0] + fac2 * rt2[0];
- rt[1] = fac1 * rt1[1] + fac2 * rt2[1];
- rt[2] = fac1 * rt1[2] + fac2 * rt2[2];
- rt[3] = fac1 * rt1[3] + fac2 * rt2[3];
-
- rt1 += 4; rt2 += 4; rt += 4;
- }
-
- if (y == 0)
- break;
- y--;
-
- x = xo;
- while (x--) {
- rt[0] = fac3 * rt1[0] + fac4 * rt2[0];
- rt[1] = fac3 * rt1[1] + fac4 * rt2[1];
- rt[2] = fac3 * rt1[2] + fac4 * rt2[2];
- rt[3] = fac3 * rt1[3] + fac4 * rt2[3];
-
- rt1 += 4; rt2 += 4; rt += 4;
- }
-
- }
-}
-
-static void do_cross_effect(
- const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra),
- float facf0, float facf1, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3),
- int start_line, int total_lines, ImBuf *out)
-{
- if (out->rect_float) {
- float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
-
- slice_get_float_buffers(context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
-
- do_cross_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
- }
- else {
- unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
-
- slice_get_byte_buffers(context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
-
- do_cross_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
- }
+static void do_cross_effect_byte(float facf0,
+ float facf1,
+ int x,
+ int y,
+ unsigned char *rect1,
+ unsigned char *rect2,
+ unsigned char *out)
+{
+ int fac1, fac2, fac3, fac4;
+ int xo;
+ unsigned char *rt1, *rt2, *rt;
+
+ xo = x;
+ rt1 = rect1;
+ rt2 = rect2;
+ rt = out;
+
+ fac2 = (int)(256.0f * facf0);
+ fac1 = 256 - fac2;
+ fac4 = (int)(256.0f * facf1);
+ fac3 = 256 - fac4;
+
+ while (y--) {
+ x = xo;
+ while (x--) {
+ rt[0] = (fac1 * rt1[0] + fac2 * rt2[0]) >> 8;
+ rt[1] = (fac1 * rt1[1] + fac2 * rt2[1]) >> 8;
+ rt[2] = (fac1 * rt1[2] + fac2 * rt2[2]) >> 8;
+ rt[3] = (fac1 * rt1[3] + fac2 * rt2[3]) >> 8;
+
+ rt1 += 4;
+ rt2 += 4;
+ rt += 4;
+ }
+
+ if (y == 0)
+ break;
+ y--;
+
+ x = xo;
+ while (x--) {
+ rt[0] = (fac3 * rt1[0] + fac4 * rt2[0]) >> 8;
+ rt[1] = (fac3 * rt1[1] + fac4 * rt2[1]) >> 8;
+ rt[2] = (fac3 * rt1[2] + fac4 * rt2[2]) >> 8;
+ rt[3] = (fac3 * rt1[3] + fac4 * rt2[3]) >> 8;
+
+ rt1 += 4;
+ rt2 += 4;
+ rt += 4;
+ }
+ }
+}
+
+static void do_cross_effect_float(
+ float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out)
+{
+ float fac1, fac2, fac3, fac4;
+ int xo;
+ float *rt1, *rt2, *rt;
+
+ xo = x;
+ rt1 = rect1;
+ rt2 = rect2;
+ rt = out;
+
+ fac2 = facf0;
+ fac1 = 1.0f - fac2;
+ fac4 = facf1;
+ fac3 = 1.0f - fac4;
+
+ while (y--) {
+ x = xo;
+ while (x--) {
+ rt[0] = fac1 * rt1[0] + fac2 * rt2[0];
+ rt[1] = fac1 * rt1[1] + fac2 * rt2[1];
+ rt[2] = fac1 * rt1[2] + fac2 * rt2[2];
+ rt[3] = fac1 * rt1[3] + fac2 * rt2[3];
+
+ rt1 += 4;
+ rt2 += 4;
+ rt += 4;
+ }
+
+ if (y == 0)
+ break;
+ y--;
+
+ x = xo;
+ while (x--) {
+ rt[0] = fac3 * rt1[0] + fac4 * rt2[0];
+ rt[1] = fac3 * rt1[1] + fac4 * rt2[1];
+ rt[2] = fac3 * rt1[2] + fac4 * rt2[2];
+ rt[3] = fac3 * rt1[3] + fac4 * rt2[3];
+
+ rt1 += 4;
+ rt2 += 4;
+ rt += 4;
+ }
+ }
+}
+
+static void do_cross_effect(const SeqRenderData *context,
+ Sequence *UNUSED(seq),
+ float UNUSED(cfra),
+ float facf0,
+ float facf1,
+ ImBuf *ibuf1,
+ ImBuf *ibuf2,
+ ImBuf *UNUSED(ibuf3),
+ int start_line,
+ int total_lines,
+ ImBuf *out)
+{
+ if (out->rect_float) {
+ float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
+
+ slice_get_float_buffers(
+ context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
+
+ do_cross_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ }
+ else {
+ unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
+
+ slice_get_byte_buffers(
+ context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
+
+ do_cross_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ }
}
/*********************** Gamma Cross *************************/
@@ -635,111 +718,117 @@ static float valid_inv_gamma;
static void makeGammaTables(float gamma)
{
- /* we need two tables: one forward, one backward */
- int i;
-
- valid_gamma = gamma;
- valid_inv_gamma = 1.0f / gamma;
- color_step = 1.0f / RE_GAMMA_TABLE_SIZE;
- inv_color_step = (float) RE_GAMMA_TABLE_SIZE;
-
- /* We could squeeze out the two range tables to gain some memory */
- for (i = 0; i < RE_GAMMA_TABLE_SIZE; i++) {
- color_domain_table[i] = i * color_step;
- gamma_range_table[i] = pow(color_domain_table[i], valid_gamma);
- inv_gamma_range_table[i] = pow(color_domain_table[i], valid_inv_gamma);
- }
-
- /* The end of the table should match 1.0 carefully. In order to avoid
- * rounding errors, we just set this explicitly. The last segment may
- * have a different length than the other segments, but our
- * interpolation is insensitive to that
- */
- color_domain_table[RE_GAMMA_TABLE_SIZE] = 1.0;
- gamma_range_table[RE_GAMMA_TABLE_SIZE] = 1.0;
- inv_gamma_range_table[RE_GAMMA_TABLE_SIZE] = 1.0;
-
- /* To speed up calculations, we make these calc factor tables. They are
- * multiplication factors used in scaling the interpolation
- */
- for (i = 0; i < RE_GAMMA_TABLE_SIZE; i++) {
- gamfactor_table[i] = inv_color_step * (gamma_range_table[i + 1] - gamma_range_table[i]);
- inv_gamfactor_table[i] = inv_color_step * (inv_gamma_range_table[i + 1] - inv_gamma_range_table[i]);
- }
-
+ /* we need two tables: one forward, one backward */
+ int i;
+
+ valid_gamma = gamma;
+ valid_inv_gamma = 1.0f / gamma;
+ color_step = 1.0f / RE_GAMMA_TABLE_SIZE;
+ inv_color_step = (float)RE_GAMMA_TABLE_SIZE;
+
+ /* We could squeeze out the two range tables to gain some memory */
+ for (i = 0; i < RE_GAMMA_TABLE_SIZE; i++) {
+ color_domain_table[i] = i * color_step;
+ gamma_range_table[i] = pow(color_domain_table[i], valid_gamma);
+ inv_gamma_range_table[i] = pow(color_domain_table[i], valid_inv_gamma);
+ }
+
+ /* The end of the table should match 1.0 carefully. In order to avoid
+ * rounding errors, we just set this explicitly. The last segment may
+ * have a different length than the other segments, but our
+ * interpolation is insensitive to that
+ */
+ color_domain_table[RE_GAMMA_TABLE_SIZE] = 1.0;
+ gamma_range_table[RE_GAMMA_TABLE_SIZE] = 1.0;
+ inv_gamma_range_table[RE_GAMMA_TABLE_SIZE] = 1.0;
+
+ /* To speed up calculations, we make these calc factor tables. They are
+ * multiplication factors used in scaling the interpolation
+ */
+ for (i = 0; i < RE_GAMMA_TABLE_SIZE; i++) {
+ gamfactor_table[i] = inv_color_step * (gamma_range_table[i + 1] - gamma_range_table[i]);
+ inv_gamfactor_table[i] = inv_color_step *
+ (inv_gamma_range_table[i + 1] - inv_gamma_range_table[i]);
+ }
}
static float gammaCorrect(float c)
{
- int i;
- float res;
+ int i;
+ float res;
- i = floorf(c * inv_color_step);
- /* Clip to range [0, 1]: outside, just do the complete calculation.
- * We may have some performance problems here. Stretching up the LUT
- * may help solve that, by exchanging LUT size for the interpolation.
- * Negative colors are explicitly handled.
- */
- if (UNLIKELY(i < 0)) res = -powf(-c, valid_gamma);
- else if (i >= RE_GAMMA_TABLE_SIZE) res = powf(c, valid_gamma);
- else res = gamma_range_table[i] +
- ((c - color_domain_table[i]) * gamfactor_table[i]);
+ i = floorf(c * inv_color_step);
+ /* Clip to range [0, 1]: outside, just do the complete calculation.
+ * We may have some performance problems here. Stretching up the LUT
+ * may help solve that, by exchanging LUT size for the interpolation.
+ * Negative colors are explicitly handled.
+ */
+ if (UNLIKELY(i < 0))
+ res = -powf(-c, valid_gamma);
+ else if (i >= RE_GAMMA_TABLE_SIZE)
+ res = powf(c, valid_gamma);
+ else
+ res = gamma_range_table[i] + ((c - color_domain_table[i]) * gamfactor_table[i]);
- return res;
+ return res;
}
/* ------------------------------------------------------------------------- */
static float invGammaCorrect(float c)
{
- int i;
- float res = 0.0;
+ int i;
+ float res = 0.0;
- i = floorf(c * inv_color_step);
- /* Negative colors are explicitly handled */
- if (UNLIKELY(i < 0)) res = -powf(-c, valid_inv_gamma);
- else if (i >= RE_GAMMA_TABLE_SIZE) res = powf(c, valid_inv_gamma);
- else res = inv_gamma_range_table[i] +
- ((c - color_domain_table[i]) * inv_gamfactor_table[i]);
+ i = floorf(c * inv_color_step);
+ /* Negative colors are explicitly handled */
+ if (UNLIKELY(i < 0))
+ res = -powf(-c, valid_inv_gamma);
+ else if (i >= RE_GAMMA_TABLE_SIZE)
+ res = powf(c, valid_inv_gamma);
+ else
+ res = inv_gamma_range_table[i] + ((c - color_domain_table[i]) * inv_gamfactor_table[i]);
- return res;
+ return res;
}
static void gamtabs(float gamma)
{
- float val, igamma = 1.0f / gamma;
- int a;
-
- /* gamtab: in short, out short */
- for (a = 0; a < 65536; a++) {
- val = a;
- val /= 65535.0f;
-
- if (gamma == 2.0f)
- val = sqrtf(val);
- else if (gamma != 1.0f)
- val = powf(val, igamma);
-
- gamtab[a] = (65535.99f * val);
- }
- /* inverse gamtab1 : in byte, out short */
- for (a = 1; a <= 256; a++) {
- if (gamma == 2.0f) igamtab1[a - 1] = a * a - 1;
- else if (gamma == 1.0f) igamtab1[a - 1] = 256 * a - 1;
- else {
- val = a / 256.0f;
- igamtab1[a - 1] = (65535.0 * pow(val, gamma)) - 1;
- }
- }
+ float val, igamma = 1.0f / gamma;
+ int a;
+
+ /* gamtab: in short, out short */
+ for (a = 0; a < 65536; a++) {
+ val = a;
+ val /= 65535.0f;
+
+ if (gamma == 2.0f)
+ val = sqrtf(val);
+ else if (gamma != 1.0f)
+ val = powf(val, igamma);
+
+ gamtab[a] = (65535.99f * val);
+ }
+ /* inverse gamtab1 : in byte, out short */
+ for (a = 1; a <= 256; a++) {
+ if (gamma == 2.0f)
+ igamtab1[a - 1] = a * a - 1;
+ else if (gamma == 1.0f)
+ igamtab1[a - 1] = 256 * a - 1;
+ else {
+ val = a / 256.0f;
+ igamtab1[a - 1] = (65535.0 * pow(val, gamma)) - 1;
+ }
+ }
}
static void build_gammatabs(void)
{
- if (gamma_tabs_init == false) {
- gamtabs(2.0f);
- makeGammaTables(2.0f);
- gamma_tabs_init = true;
- }
+ if (gamma_tabs_init == false) {
+ gamtabs(2.0f);
+ makeGammaTables(2.0f);
+ gamma_tabs_init = true;
+ }
}
static void init_gammacross(Sequence *UNUSED(seq))
@@ -754,1756 +843,2022 @@ static void free_gammacross(Sequence *UNUSED(seq), const bool UNUSED(do_id_user)
{
}
-static void do_gammacross_effect_byte(
- float facf0, float UNUSED(facf1), int x, int y, unsigned char *rect1,
- unsigned char *rect2, unsigned char *out)
+static void do_gammacross_effect_byte(float facf0,
+ float UNUSED(facf1),
+ int x,
+ int y,
+ unsigned char *rect1,
+ unsigned char *rect2,
+ unsigned char *out)
{
- float fac1, fac2;
- int xo;
- unsigned char *cp1, *cp2, *rt;
- float rt1[4], rt2[4], tempc[4];
+ float fac1, fac2;
+ int xo;
+ unsigned char *cp1, *cp2, *rt;
+ float rt1[4], rt2[4], tempc[4];
- xo = x;
- cp1 = rect1;
- cp2 = rect2;
- rt = out;
+ xo = x;
+ cp1 = rect1;
+ cp2 = rect2;
+ rt = out;
- fac2 = facf0;
- fac1 = 1.0f - fac2;
+ fac2 = facf0;
+ fac1 = 1.0f - fac2;
- while (y--) {
- x = xo;
- while (x--) {
- straight_uchar_to_premul_float(rt1, cp1);
- straight_uchar_to_premul_float(rt2, cp2);
+ while (y--) {
+ x = xo;
+ while (x--) {
+ straight_uchar_to_premul_float(rt1, cp1);
+ straight_uchar_to_premul_float(rt2, cp2);
- tempc[0] = gammaCorrect(fac1 * invGammaCorrect(rt1[0]) + fac2 * invGammaCorrect(rt2[0]));
- tempc[1] = gammaCorrect(fac1 * invGammaCorrect(rt1[1]) + fac2 * invGammaCorrect(rt2[1]));
- tempc[2] = gammaCorrect(fac1 * invGammaCorrect(rt1[2]) + fac2 * invGammaCorrect(rt2[2]));
- tempc[3] = gammaCorrect(fac1 * invGammaCorrect(rt1[3]) + fac2 * invGammaCorrect(rt2[3]));
+ tempc[0] = gammaCorrect(fac1 * invGammaCorrect(rt1[0]) + fac2 * invGammaCorrect(rt2[0]));
+ tempc[1] = gammaCorrect(fac1 * invGammaCorrect(rt1[1]) + fac2 * invGammaCorrect(rt2[1]));
+ tempc[2] = gammaCorrect(fac1 * invGammaCorrect(rt1[2]) + fac2 * invGammaCorrect(rt2[2]));
+ tempc[3] = gammaCorrect(fac1 * invGammaCorrect(rt1[3]) + fac2 * invGammaCorrect(rt2[3]));
- premul_float_to_straight_uchar(rt, tempc);
- cp1 += 4; cp2 += 4; rt += 4;
- }
+ premul_float_to_straight_uchar(rt, tempc);
+ cp1 += 4;
+ cp2 += 4;
+ rt += 4;
+ }
- if (y == 0)
- break;
- y--;
+ if (y == 0)
+ break;
+ y--;
- x = xo;
- while (x--) {
- straight_uchar_to_premul_float(rt1, cp1);
- straight_uchar_to_premul_float(rt2, cp2);
+ x = xo;
+ while (x--) {
+ straight_uchar_to_premul_float(rt1, cp1);
+ straight_uchar_to_premul_float(rt2, cp2);
- tempc[0] = gammaCorrect(fac1 * invGammaCorrect(rt1[0]) + fac2 * invGammaCorrect(rt2[0]));
- tempc[1] = gammaCorrect(fac1 * invGammaCorrect(rt1[1]) + fac2 * invGammaCorrect(rt2[1]));
- tempc[2] = gammaCorrect(fac1 * invGammaCorrect(rt1[2]) + fac2 * invGammaCorrect(rt2[2]));
- tempc[3] = gammaCorrect(fac1 * invGammaCorrect(rt1[3]) + fac2 * invGammaCorrect(rt2[3]));
+ tempc[0] = gammaCorrect(fac1 * invGammaCorrect(rt1[0]) + fac2 * invGammaCorrect(rt2[0]));
+ tempc[1] = gammaCorrect(fac1 * invGammaCorrect(rt1[1]) + fac2 * invGammaCorrect(rt2[1]));
+ tempc[2] = gammaCorrect(fac1 * invGammaCorrect(rt1[2]) + fac2 * invGammaCorrect(rt2[2]));
+ tempc[3] = gammaCorrect(fac1 * invGammaCorrect(rt1[3]) + fac2 * invGammaCorrect(rt2[3]));
- premul_float_to_straight_uchar(rt, tempc);
- cp1 += 4; cp2 += 4; rt += 4;
- }
- }
+ premul_float_to_straight_uchar(rt, tempc);
+ cp1 += 4;
+ cp2 += 4;
+ rt += 4;
+ }
+ }
}
static void do_gammacross_effect_float(
- float facf0, float UNUSED(facf1), int x, int y, float *rect1,
- float *rect2, float *out)
+ float facf0, float UNUSED(facf1), int x, int y, float *rect1, float *rect2, float *out)
{
- float fac1, fac2;
- int xo;
- float *rt1, *rt2, *rt;
+ float fac1, fac2;
+ int xo;
+ float *rt1, *rt2, *rt;
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
+ xo = x;
+ rt1 = rect1;
+ rt2 = rect2;
+ rt = out;
- fac2 = facf0;
- fac1 = 1.0f - fac2;
+ fac2 = facf0;
+ fac1 = 1.0f - fac2;
- while (y--) {
- x = xo * 4;
- while (x--) {
- *rt = gammaCorrect(fac1 * invGammaCorrect(*rt1) + fac2 * invGammaCorrect(*rt2));
- rt1++; rt2++; rt++;
- }
+ while (y--) {
+ x = xo * 4;
+ while (x--) {
+ *rt = gammaCorrect(fac1 * invGammaCorrect(*rt1) + fac2 * invGammaCorrect(*rt2));
+ rt1++;
+ rt2++;
+ rt++;
+ }
- if (y == 0)
- break;
- y--;
+ if (y == 0)
+ break;
+ y--;
- x = xo * 4;
- while (x--) {
- *rt = gammaCorrect(fac1 * invGammaCorrect(*rt1) + fac2 * invGammaCorrect(*rt2));
+ x = xo * 4;
+ while (x--) {
+ *rt = gammaCorrect(fac1 * invGammaCorrect(*rt1) + fac2 * invGammaCorrect(*rt2));
- rt1++; rt2++; rt++;
- }
- }
+ rt1++;
+ rt2++;
+ rt++;
+ }
+ }
}
-static struct ImBuf *gammacross_init_execution(const SeqRenderData *context, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3)
+static struct ImBuf *gammacross_init_execution(const SeqRenderData *context,
+ ImBuf *ibuf1,
+ ImBuf *ibuf2,
+ ImBuf *ibuf3)
{
- ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3);
- build_gammatabs();
+ ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3);
+ build_gammatabs();
- return out;
+ return out;
}
-static void do_gammacross_effect(
- const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra),
- float facf0, float facf1, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3),
- int start_line, int total_lines, ImBuf *out)
+static void do_gammacross_effect(const SeqRenderData *context,
+ Sequence *UNUSED(seq),
+ float UNUSED(cfra),
+ float facf0,
+ float facf1,
+ ImBuf *ibuf1,
+ ImBuf *ibuf2,
+ ImBuf *UNUSED(ibuf3),
+ int start_line,
+ int total_lines,
+ ImBuf *out)
{
- if (out->rect_float) {
- float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
+ if (out->rect_float) {
+ float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
- slice_get_float_buffers(context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
+ slice_get_float_buffers(
+ context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_gammacross_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
- }
- else {
- unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
+ do_gammacross_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ }
+ else {
+ unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
- slice_get_byte_buffers(context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
+ slice_get_byte_buffers(
+ context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_gammacross_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
- }
+ do_gammacross_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ }
}
/*********************** Add *************************/
-static void do_add_effect_byte(
- float facf0, float facf1, int x, int y,
- unsigned char *rect1, unsigned char *rect2, unsigned char *out)
-{
- int xo, fac1, fac3;
- unsigned char *cp1, *cp2, *rt;
-
- xo = x;
- cp1 = rect1;
- cp2 = rect2;
- rt = out;
-
- fac1 = (int)(256.0f * facf0);
- fac3 = (int)(256.0f * facf1);
-
- while (y--) {
- x = xo;
-
- while (x--) {
- const int m = fac1 * (int)cp2[3];
- rt[0] = min_ii(cp1[0] + ((m * cp2[0]) >> 16), 255);
- rt[1] = min_ii(cp1[1] + ((m * cp2[1]) >> 16), 255);
- rt[2] = min_ii(cp1[2] + ((m * cp2[2]) >> 16), 255);
- rt[3] = cp1[3];
-
- cp1 += 4; cp2 += 4; rt += 4;
- }
-
- if (y == 0)
- break;
- y--;
-
- x = xo;
- while (x--) {
- const int m = fac3 * (int)cp2[3];
- rt[0] = min_ii(cp1[0] + ((m * cp2[0]) >> 16), 255);
- rt[1] = min_ii(cp1[1] + ((m * cp2[1]) >> 16), 255);
- rt[2] = min_ii(cp1[2] + ((m * cp2[2]) >> 16), 255);
- rt[3] = cp1[3];
-
- cp1 += 4; cp2 += 4; rt += 4;
- }
- }
-}
-
-static void do_add_effect_float(float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out)
-{
- int xo;
- float fac1, fac3;
- float *rt1, *rt2, *rt;
-
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
-
- fac1 = facf0;
- fac3 = facf1;
-
- while (y--) {
- x = xo;
- while (x--) {
- const float m = (1.0f - (rt1[3] * (1.0f - fac1))) * rt2[3];
- rt[0] = rt1[0] + m * rt2[0];
- rt[1] = rt1[1] + m * rt2[1];
- rt[2] = rt1[2] + m * rt2[2];
- rt[3] = rt1[3];
-
- rt1 += 4; rt2 += 4; rt += 4;
- }
-
- if (y == 0)
- break;
- y--;
-
- x = xo;
- while (x--) {
- const float m = (1.0f - (rt1[3] * (1.0f - fac3))) * rt2[3];
- rt[0] = rt1[0] + m * rt2[0];
- rt[1] = rt1[1] + m * rt2[1];
- rt[2] = rt1[2] + m * rt2[2];
- rt[3] = rt1[3];
-
- rt1 += 4; rt2 += 4; rt += 4;
- }
- }
-}
-
-static void do_add_effect(
- const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra), float facf0, float facf1,
- ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), int start_line, int total_lines, ImBuf *out)
-{
- if (out->rect_float) {
- float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
-
- slice_get_float_buffers(context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
-
- do_add_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
- }
- else {
- unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
-
- slice_get_byte_buffers(context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
-
- do_add_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
- }
+static void do_add_effect_byte(float facf0,
+ float facf1,
+ int x,
+ int y,
+ unsigned char *rect1,
+ unsigned char *rect2,
+ unsigned char *out)
+{
+ int xo, fac1, fac3;
+ unsigned char *cp1, *cp2, *rt;
+
+ xo = x;
+ cp1 = rect1;
+ cp2 = rect2;
+ rt = out;
+
+ fac1 = (int)(256.0f * facf0);
+ fac3 = (int)(256.0f * facf1);
+
+ while (y--) {
+ x = xo;
+
+ while (x--) {
+ const int m = fac1 * (int)cp2[3];
+ rt[0] = min_ii(cp1[0] + ((m * cp2[0]) >> 16), 255);
+ rt[1] = min_ii(cp1[1] + ((m * cp2[1]) >> 16), 255);
+ rt[2] = min_ii(cp1[2] + ((m * cp2[2]) >> 16), 255);
+ rt[3] = cp1[3];
+
+ cp1 += 4;
+ cp2 += 4;
+ rt += 4;
+ }
+
+ if (y == 0)
+ break;
+ y--;
+
+ x = xo;
+ while (x--) {
+ const int m = fac3 * (int)cp2[3];
+ rt[0] = min_ii(cp1[0] + ((m * cp2[0]) >> 16), 255);
+ rt[1] = min_ii(cp1[1] + ((m * cp2[1]) >> 16), 255);
+ rt[2] = min_ii(cp1[2] + ((m * cp2[2]) >> 16), 255);
+ rt[3] = cp1[3];
+
+ cp1 += 4;
+ cp2 += 4;
+ rt += 4;
+ }
+ }
+}
+
+static void do_add_effect_float(
+ float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out)
+{
+ int xo;
+ float fac1, fac3;
+ float *rt1, *rt2, *rt;
+
+ xo = x;
+ rt1 = rect1;
+ rt2 = rect2;
+ rt = out;
+
+ fac1 = facf0;
+ fac3 = facf1;
+
+ while (y--) {
+ x = xo;
+ while (x--) {
+ const float m = (1.0f - (rt1[3] * (1.0f - fac1))) * rt2[3];
+ rt[0] = rt1[0] + m * rt2[0];
+ rt[1] = rt1[1] + m * rt2[1];
+ rt[2] = rt1[2] + m * rt2[2];
+ rt[3] = rt1[3];
+
+ rt1 += 4;
+ rt2 += 4;
+ rt += 4;
+ }
+
+ if (y == 0)
+ break;
+ y--;
+
+ x = xo;
+ while (x--) {
+ const float m = (1.0f - (rt1[3] * (1.0f - fac3))) * rt2[3];
+ rt[0] = rt1[0] + m * rt2[0];
+ rt[1] = rt1[1] + m * rt2[1];
+ rt[2] = rt1[2] + m * rt2[2];
+ rt[3] = rt1[3];
+
+ rt1 += 4;
+ rt2 += 4;
+ rt += 4;
+ }
+ }
+}
+
+static void do_add_effect(const SeqRenderData *context,
+ Sequence *UNUSED(seq),
+ float UNUSED(cfra),
+ float facf0,
+ float facf1,
+ ImBuf *ibuf1,
+ ImBuf *ibuf2,
+ ImBuf *UNUSED(ibuf3),
+ int start_line,
+ int total_lines,
+ ImBuf *out)
+{
+ if (out->rect_float) {
+ float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
+
+ slice_get_float_buffers(
+ context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
+
+ do_add_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ }
+ else {
+ unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
+
+ slice_get_byte_buffers(
+ context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
+
+ do_add_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ }
}
/*********************** Sub *************************/
-static void do_sub_effect_byte(
- float facf0, float facf1, int x, int y,
- unsigned char *rect1, unsigned char *rect2, unsigned char *out)
-{
- int xo, fac1, fac3;
- unsigned char *cp1, *cp2, *rt;
-
- xo = x;
- cp1 = rect1;
- cp2 = rect2;
- rt = out;
-
- fac1 = (int) (256.0f * facf0);
- fac3 = (int) (256.0f * facf1);
-
- while (y--) {
- x = xo;
- while (x--) {
- const int m = fac1 * (int)cp2[3];
- rt[0] = max_ii(cp1[0] - ((m * cp2[0]) >> 16), 0);
- rt[1] = max_ii(cp1[1] - ((m * cp2[1]) >> 16), 0);
- rt[2] = max_ii(cp1[2] - ((m * cp2[2]) >> 16), 0);
- rt[3] = cp1[3];
-
- cp1 += 4; cp2 += 4; rt += 4;
- }
-
- if (y == 0)
- break;
- y--;
-
- x = xo;
- while (x--) {
- const int m = fac3 * (int)cp2[3];
- rt[0] = max_ii(cp1[0] - ((m * cp2[0]) >> 16), 0);
- rt[1] = max_ii(cp1[1] - ((m * cp2[1]) >> 16), 0);
- rt[2] = max_ii(cp1[2] - ((m * cp2[2]) >> 16), 0);
- rt[3] = cp1[3];
-
- cp1 += 4; cp2 += 4; rt += 4;
- }
- }
+static void do_sub_effect_byte(float facf0,
+ float facf1,
+ int x,
+ int y,
+ unsigned char *rect1,
+ unsigned char *rect2,
+ unsigned char *out)
+{
+ int xo, fac1, fac3;
+ unsigned char *cp1, *cp2, *rt;
+
+ xo = x;
+ cp1 = rect1;
+ cp2 = rect2;
+ rt = out;
+
+ fac1 = (int)(256.0f * facf0);
+ fac3 = (int)(256.0f * facf1);
+
+ while (y--) {
+ x = xo;
+ while (x--) {
+ const int m = fac1 * (int)cp2[3];
+ rt[0] = max_ii(cp1[0] - ((m * cp2[0]) >> 16), 0);
+ rt[1] = max_ii(cp1[1] - ((m * cp2[1]) >> 16), 0);
+ rt[2] = max_ii(cp1[2] - ((m * cp2[2]) >> 16), 0);
+ rt[3] = cp1[3];
+
+ cp1 += 4;
+ cp2 += 4;
+ rt += 4;
+ }
+
+ if (y == 0)
+ break;
+ y--;
+
+ x = xo;
+ while (x--) {
+ const int m = fac3 * (int)cp2[3];
+ rt[0] = max_ii(cp1[0] - ((m * cp2[0]) >> 16), 0);
+ rt[1] = max_ii(cp1[1] - ((m * cp2[1]) >> 16), 0);
+ rt[2] = max_ii(cp1[2] - ((m * cp2[2]) >> 16), 0);
+ rt[3] = cp1[3];
+
+ cp1 += 4;
+ cp2 += 4;
+ rt += 4;
+ }
+ }
}
static void do_sub_effect_float(
- float UNUSED(facf0), float facf1, int x, int y,
- float *rect1, float *rect2, float *out)
-{
- int xo;
- float /* fac1, */ fac3_inv;
- float *rt1, *rt2, *rt;
-
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
-
- /* UNUSED */
- // fac1 = facf0;
- fac3_inv = 1.0f - facf1;
-
- while (y--) {
- x = xo;
- while (x--) {
- const float m = (1.0f - (rt1[3] * fac3_inv)) * rt2[3];
- rt[0] = max_ff(rt1[0] - m * rt2[0], 0.0f);
- rt[1] = max_ff(rt1[1] - m * rt2[1], 0.0f);
- rt[2] = max_ff(rt1[2] - m * rt2[2], 0.0f);
- rt[3] = rt1[3];
-
- rt1 += 4; rt2 += 4; rt += 4;
- }
-
- if (y == 0)
- break;
- y--;
-
- x = xo;
- while (x--) {
- const float m = (1.0f - (rt1[3] * fac3_inv)) * rt2[3];
- rt[0] = max_ff(rt1[0] - m * rt2[0], 0.0f);
- rt[1] = max_ff(rt1[1] - m * rt2[1], 0.0f);
- rt[2] = max_ff(rt1[2] - m * rt2[2], 0.0f);
- rt[3] = rt1[3];
-
- rt1 += 4; rt2 += 4; rt += 4;
- }
- }
-}
-
-static void do_sub_effect(
- const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra), float facf0, float facf1,
- ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), int start_line, int total_lines, ImBuf *out)
-{
- if (out->rect_float) {
- float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
-
- slice_get_float_buffers(context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
-
- do_sub_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
- }
- else {
- unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
-
- slice_get_byte_buffers(context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
-
- do_sub_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
- }
+ float UNUSED(facf0), float facf1, int x, int y, float *rect1, float *rect2, float *out)
+{
+ int xo;
+ float /* fac1, */ fac3_inv;
+ float *rt1, *rt2, *rt;
+
+ xo = x;
+ rt1 = rect1;
+ rt2 = rect2;
+ rt = out;
+
+ /* UNUSED */
+ // fac1 = facf0;
+ fac3_inv = 1.0f - facf1;
+
+ while (y--) {
+ x = xo;
+ while (x--) {
+ const float m = (1.0f - (rt1[3] * fac3_inv)) * rt2[3];
+ rt[0] = max_ff(rt1[0] - m * rt2[0], 0.0f);
+ rt[1] = max_ff(rt1[1] - m * rt2[1], 0.0f);
+ rt[2] = max_ff(rt1[2] - m * rt2[2], 0.0f);
+ rt[3] = rt1[3];
+
+ rt1 += 4;
+ rt2 += 4;
+ rt += 4;
+ }
+
+ if (y == 0)
+ break;
+ y--;
+
+ x = xo;
+ while (x--) {
+ const float m = (1.0f - (rt1[3] * fac3_inv)) * rt2[3];
+ rt[0] = max_ff(rt1[0] - m * rt2[0], 0.0f);
+ rt[1] = max_ff(rt1[1] - m * rt2[1], 0.0f);
+ rt[2] = max_ff(rt1[2] - m * rt2[2], 0.0f);
+ rt[3] = rt1[3];
+
+ rt1 += 4;
+ rt2 += 4;
+ rt += 4;
+ }
+ }
+}
+
+static void do_sub_effect(const SeqRenderData *context,
+ Sequence *UNUSED(seq),
+ float UNUSED(cfra),
+ float facf0,
+ float facf1,
+ ImBuf *ibuf1,
+ ImBuf *ibuf2,
+ ImBuf *UNUSED(ibuf3),
+ int start_line,
+ int total_lines,
+ ImBuf *out)
+{
+ if (out->rect_float) {
+ float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
+
+ slice_get_float_buffers(
+ context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
+
+ do_sub_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ }
+ else {
+ unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
+
+ slice_get_byte_buffers(
+ context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
+
+ do_sub_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ }
}
/*********************** Drop *************************/
/* Must be > 0 or add precopy, etc to the function */
-#define XOFF 8
-#define YOFF 8
-
-static void do_drop_effect_byte(
- float facf0, float facf1, int x, int y,
- unsigned char *rect2i, unsigned char *rect1i, unsigned char *outi)
-{
- int temp, fac, fac1, fac2;
- unsigned char *rt1, *rt2, *out;
- int field = 1;
-
- const int width = x;
- const int height = y;
- const int xoff = min_ii(XOFF, width);
- const int yoff = min_ii(YOFF, height);
-
- fac1 = (int) (70.0f * facf0);
- fac2 = (int) (70.0f * facf1);
-
- rt2 = rect2i + yoff * 4 * width;
- rt1 = rect1i;
- out = outi;
- for (y = 0; y < height - yoff; y++) {
- if (field) fac = fac1;
- else fac = fac2;
- field = !field;
-
- memcpy(out, rt1, sizeof(*out) * xoff * 4);
- rt1 += xoff * 4;
- out += xoff * 4;
-
- for (x = xoff; x < width; x++) {
- temp = ((fac * rt2[3]) >> 8);
-
- *(out++) = MAX2(0, *rt1 - temp); rt1++;
- *(out++) = MAX2(0, *rt1 - temp); rt1++;
- *(out++) = MAX2(0, *rt1 - temp); rt1++;
- *(out++) = MAX2(0, *rt1 - temp); rt1++;
- rt2 += 4;
- }
- rt2 += xoff * 4;
- }
- memcpy(out, rt1, sizeof(*out) * yoff * 4 * width);
+#define XOFF 8
+#define YOFF 8
+
+static void do_drop_effect_byte(float facf0,
+ float facf1,
+ int x,
+ int y,
+ unsigned char *rect2i,
+ unsigned char *rect1i,
+ unsigned char *outi)
+{
+ int temp, fac, fac1, fac2;
+ unsigned char *rt1, *rt2, *out;
+ int field = 1;
+
+ const int width = x;
+ const int height = y;
+ const int xoff = min_ii(XOFF, width);
+ const int yoff = min_ii(YOFF, height);
+
+ fac1 = (int)(70.0f * facf0);
+ fac2 = (int)(70.0f * facf1);
+
+ rt2 = rect2i + yoff * 4 * width;
+ rt1 = rect1i;
+ out = outi;
+ for (y = 0; y < height - yoff; y++) {
+ if (field)
+ fac = fac1;
+ else
+ fac = fac2;
+ field = !field;
+
+ memcpy(out, rt1, sizeof(*out) * xoff * 4);
+ rt1 += xoff * 4;
+ out += xoff * 4;
+
+ for (x = xoff; x < width; x++) {
+ temp = ((fac * rt2[3]) >> 8);
+
+ *(out++) = MAX2(0, *rt1 - temp);
+ rt1++;
+ *(out++) = MAX2(0, *rt1 - temp);
+ rt1++;
+ *(out++) = MAX2(0, *rt1 - temp);
+ rt1++;
+ *(out++) = MAX2(0, *rt1 - temp);
+ rt1++;
+ rt2 += 4;
+ }
+ rt2 += xoff * 4;
+ }
+ memcpy(out, rt1, sizeof(*out) * yoff * 4 * width);
}
static void do_drop_effect_float(
- float facf0, float facf1, int x, int y,
- float *rect2i, float *rect1i, float *outi)
-{
- float temp, fac, fac1, fac2;
- float *rt1, *rt2, *out;
- int field = 1;
-
- const int width = x;
- const int height = y;
- const int xoff = min_ii(XOFF, width);
- const int yoff = min_ii(YOFF, height);
-
- fac1 = 70.0f * facf0;
- fac2 = 70.0f * facf1;
-
- rt2 = rect2i + yoff * 4 * width;
- rt1 = rect1i;
- out = outi;
- for (y = 0; y < height - yoff; y++) {
- if (field) fac = fac1;
- else fac = fac2;
- field = !field;
-
- memcpy(out, rt1, sizeof(*out) * xoff * 4);
- rt1 += xoff * 4;
- out += xoff * 4;
-
- for (x = xoff; x < width; x++) {
- temp = fac * rt2[3];
-
- *(out++) = MAX2(0.0f, *rt1 - temp); rt1++;
- *(out++) = MAX2(0.0f, *rt1 - temp); rt1++;
- *(out++) = MAX2(0.0f, *rt1 - temp); rt1++;
- *(out++) = MAX2(0.0f, *rt1 - temp); rt1++;
- rt2 += 4;
- }
- rt2 += xoff * 4;
- }
- memcpy(out, rt1, sizeof(*out) * yoff * 4 * width);
+ float facf0, float facf1, int x, int y, float *rect2i, float *rect1i, float *outi)
+{
+ float temp, fac, fac1, fac2;
+ float *rt1, *rt2, *out;
+ int field = 1;
+
+ const int width = x;
+ const int height = y;
+ const int xoff = min_ii(XOFF, width);
+ const int yoff = min_ii(YOFF, height);
+
+ fac1 = 70.0f * facf0;
+ fac2 = 70.0f * facf1;
+
+ rt2 = rect2i + yoff * 4 * width;
+ rt1 = rect1i;
+ out = outi;
+ for (y = 0; y < height - yoff; y++) {
+ if (field)
+ fac = fac1;
+ else
+ fac = fac2;
+ field = !field;
+
+ memcpy(out, rt1, sizeof(*out) * xoff * 4);
+ rt1 += xoff * 4;
+ out += xoff * 4;
+
+ for (x = xoff; x < width; x++) {
+ temp = fac * rt2[3];
+
+ *(out++) = MAX2(0.0f, *rt1 - temp);
+ rt1++;
+ *(out++) = MAX2(0.0f, *rt1 - temp);
+ rt1++;
+ *(out++) = MAX2(0.0f, *rt1 - temp);
+ rt1++;
+ *(out++) = MAX2(0.0f, *rt1 - temp);
+ rt1++;
+ rt2 += 4;
+ }
+ rt2 += xoff * 4;
+ }
+ memcpy(out, rt1, sizeof(*out) * yoff * 4 * width);
}
/*********************** Mul *************************/
-static void do_mul_effect_byte(
- float facf0, float facf1, int x, int y,
- unsigned char *rect1, unsigned char *rect2, unsigned char *out)
+static void do_mul_effect_byte(float facf0,
+ float facf1,
+ int x,
+ int y,
+ unsigned char *rect1,
+ unsigned char *rect2,
+ unsigned char *out)
{
- int xo, fac1, fac3;
- unsigned char *rt1, *rt2, *rt;
+ int xo, fac1, fac3;
+ unsigned char *rt1, *rt2, *rt;
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
+ xo = x;
+ rt1 = rect1;
+ rt2 = rect2;
+ rt = out;
- fac1 = (int)(256.0f * facf0);
- fac3 = (int)(256.0f * facf1);
+ fac1 = (int)(256.0f * facf0);
+ fac3 = (int)(256.0f * facf1);
- /* formula:
- * fac * (a * b) + (1 - fac) * a => fac * a * (b - 1) + axaux = c * px + py * s; //+centx
- * yaux = -s * px + c * py; //+centy
- */
+ /* formula:
+ * fac * (a * b) + (1 - fac) * a => fac * a * (b - 1) + axaux = c * px + py * s; //+centx
+ * yaux = -s * px + c * py; //+centy
+ */
- while (y--) {
+ while (y--) {
- x = xo;
- while (x--) {
+ x = xo;
+ while (x--) {
- rt[0] = rt1[0] + ((fac1 * rt1[0] * (rt2[0] - 255)) >> 16);
- rt[1] = rt1[1] + ((fac1 * rt1[1] * (rt2[1] - 255)) >> 16);
- rt[2] = rt1[2] + ((fac1 * rt1[2] * (rt2[2] - 255)) >> 16);
- rt[3] = rt1[3] + ((fac1 * rt1[3] * (rt2[3] - 255)) >> 16);
+ rt[0] = rt1[0] + ((fac1 * rt1[0] * (rt2[0] - 255)) >> 16);
+ rt[1] = rt1[1] + ((fac1 * rt1[1] * (rt2[1] - 255)) >> 16);
+ rt[2] = rt1[2] + ((fac1 * rt1[2] * (rt2[2] - 255)) >> 16);
+ rt[3] = rt1[3] + ((fac1 * rt1[3] * (rt2[3] - 255)) >> 16);
- rt1 += 4; rt2 += 4; rt += 4;
- }
+ rt1 += 4;
+ rt2 += 4;
+ rt += 4;
+ }
- if (y == 0) break;
- y--;
+ if (y == 0)
+ break;
+ y--;
- x = xo;
- while (x--) {
+ x = xo;
+ while (x--) {
- rt[0] = rt1[0] + ((fac3 * rt1[0] * (rt2[0] - 255)) >> 16);
- rt[1] = rt1[1] + ((fac3 * rt1[1] * (rt2[1] - 255)) >> 16);
- rt[2] = rt1[2] + ((fac3 * rt1[2] * (rt2[2] - 255)) >> 16);
- rt[3] = rt1[3] + ((fac3 * rt1[3] * (rt2[3] - 255)) >> 16);
+ rt[0] = rt1[0] + ((fac3 * rt1[0] * (rt2[0] - 255)) >> 16);
+ rt[1] = rt1[1] + ((fac3 * rt1[1] * (rt2[1] - 255)) >> 16);
+ rt[2] = rt1[2] + ((fac3 * rt1[2] * (rt2[2] - 255)) >> 16);
+ rt[3] = rt1[3] + ((fac3 * rt1[3] * (rt2[3] - 255)) >> 16);
- rt1 += 4; rt2 += 4; rt += 4;
- }
- }
+ rt1 += 4;
+ rt2 += 4;
+ rt += 4;
+ }
+ }
}
static void do_mul_effect_float(
- float facf0, float facf1, int x, int y,
- float *rect1, float *rect2, float *out)
-{
- int xo;
- float fac1, fac3;
- float *rt1, *rt2, *rt;
-
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
-
- fac1 = facf0;
- fac3 = facf1;
-
- /* formula:
- * fac * (a * b) + (1 - fac) * a => fac * a * (b - 1) + a
- */
-
- while (y--) {
- x = xo;
- while (x--) {
- rt[0] = rt1[0] + fac1 * rt1[0] * (rt2[0] - 1.0f);
- rt[1] = rt1[1] + fac1 * rt1[1] * (rt2[1] - 1.0f);
- rt[2] = rt1[2] + fac1 * rt1[2] * (rt2[2] - 1.0f);
- rt[3] = rt1[3] + fac1 * rt1[3] * (rt2[3] - 1.0f);
-
- rt1 += 4; rt2 += 4; rt += 4;
- }
-
- if (y == 0)
- break;
- y--;
-
- x = xo;
- while (x--) {
- rt[0] = rt1[0] + fac3 * rt1[0] * (rt2[0] - 1.0f);
- rt[1] = rt1[1] + fac3 * rt1[1] * (rt2[1] - 1.0f);
- rt[2] = rt1[2] + fac3 * rt1[2] * (rt2[2] - 1.0f);
- rt[3] = rt1[3] + fac3 * rt1[3] * (rt2[3] - 1.0f);
-
- rt1 += 4; rt2 += 4; rt += 4;
- }
- }
-}
-
-static void do_mul_effect(
- const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra), float facf0, float facf1,
- ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), int start_line, int total_lines, ImBuf *out)
-{
- if (out->rect_float) {
- float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
-
- slice_get_float_buffers(context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
-
- do_mul_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
- }
- else {
- unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
-
- slice_get_byte_buffers(context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
-
- do_mul_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
- }
+ float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out)
+{
+ int xo;
+ float fac1, fac3;
+ float *rt1, *rt2, *rt;
+
+ xo = x;
+ rt1 = rect1;
+ rt2 = rect2;
+ rt = out;
+
+ fac1 = facf0;
+ fac3 = facf1;
+
+ /* formula:
+ * fac * (a * b) + (1 - fac) * a => fac * a * (b - 1) + a
+ */
+
+ while (y--) {
+ x = xo;
+ while (x--) {
+ rt[0] = rt1[0] + fac1 * rt1[0] * (rt2[0] - 1.0f);
+ rt[1] = rt1[1] + fac1 * rt1[1] * (rt2[1] - 1.0f);
+ rt[2] = rt1[2] + fac1 * rt1[2] * (rt2[2] - 1.0f);
+ rt[3] = rt1[3] + fac1 * rt1[3] * (rt2[3] - 1.0f);
+
+ rt1 += 4;
+ rt2 += 4;
+ rt += 4;
+ }
+
+ if (y == 0)
+ break;
+ y--;
+
+ x = xo;
+ while (x--) {
+ rt[0] = rt1[0] + fac3 * rt1[0] * (rt2[0] - 1.0f);
+ rt[1] = rt1[1] + fac3 * rt1[1] * (rt2[1] - 1.0f);
+ rt[2] = rt1[2] + fac3 * rt1[2] * (rt2[2] - 1.0f);
+ rt[3] = rt1[3] + fac3 * rt1[3] * (rt2[3] - 1.0f);
+
+ rt1 += 4;
+ rt2 += 4;
+ rt += 4;
+ }
+ }
+}
+
+static void do_mul_effect(const SeqRenderData *context,
+ Sequence *UNUSED(seq),
+ float UNUSED(cfra),
+ float facf0,
+ float facf1,
+ ImBuf *ibuf1,
+ ImBuf *ibuf2,
+ ImBuf *UNUSED(ibuf3),
+ int start_line,
+ int total_lines,
+ ImBuf *out)
+{
+ if (out->rect_float) {
+ float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
+
+ slice_get_float_buffers(
+ context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
+
+ do_mul_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ }
+ else {
+ unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
+
+ slice_get_byte_buffers(
+ context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
+
+ do_mul_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ }
}
/*********************** Blend Mode ***************************************/
-typedef void (*IMB_blend_func_byte)(unsigned char *dst, const unsigned char *src1, const unsigned char *src2);
+typedef void (*IMB_blend_func_byte)(unsigned char *dst,
+ const unsigned char *src1,
+ const unsigned char *src2);
typedef void (*IMB_blend_func_float)(float *dst, const float *src1, const float *src2);
-BLI_INLINE void apply_blend_function_byte(
- float facf0, float facf1, int x, int y,
- unsigned char *rect1, unsigned char *rect2, unsigned char *out, IMB_blend_func_byte blend_function)
-{
- int xo;
- unsigned char *rt1, *rt2, *rt;
- unsigned int achannel;
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
- while (y--) {
- for (x = xo; x > 0; x--) {
- achannel = rt1[3];
- rt1[3] = (unsigned int) achannel * facf0;
- blend_function(rt, rt1, rt2);
- rt1[3] = achannel;
- rt[3] = rt1[3];
- rt1 += 4;
- rt2 += 4;
- rt += 4;
- }
- if (y == 0) {
- break;
- }
- y--;
- for (x = xo; x > 0; x--) {
- achannel = rt1[3];
- rt1[3] = (unsigned int) achannel * facf1;
- blend_function(rt, rt1, rt2);
- rt1[3] = achannel;
- rt[3] = rt1[3];
- rt1 += 4;
- rt2 += 4;
- rt += 4;
- }
- }
-}
-
-BLI_INLINE void apply_blend_function_float(
- float facf0, float facf1, int x, int y,
- float *rect1, float *rect2, float *out, IMB_blend_func_float blend_function)
-{
- int xo;
- float *rt1, *rt2, *rt;
- float achannel;
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
- while (y--) {
- for (x = xo; x > 0; x--) {
- achannel = rt1[3];
- rt1[3] = achannel * facf0;
- blend_function(rt, rt1, rt2);
- rt1[3] = achannel;
- rt[3] = rt1[3];
- rt1 += 4;
- rt2 += 4;
- rt += 4;
- }
- if (y == 0) {
- break;
- }
- y--;
- for (x = xo; x > 0; x--) {
- achannel = rt1[3];
- rt1[3] = achannel * facf1;
- blend_function(rt, rt1, rt2);
- rt1[3] = achannel;
- rt[3] = rt1[3];
- rt1 += 4;
- rt2 += 4;
- rt += 4;
- }
- }
+BLI_INLINE void apply_blend_function_byte(float facf0,
+ float facf1,
+ int x,
+ int y,
+ unsigned char *rect1,
+ unsigned char *rect2,
+ unsigned char *out,
+ IMB_blend_func_byte blend_function)
+{
+ int xo;
+ unsigned char *rt1, *rt2, *rt;
+ unsigned int achannel;
+ xo = x;
+ rt1 = rect1;
+ rt2 = rect2;
+ rt = out;
+ while (y--) {
+ for (x = xo; x > 0; x--) {
+ achannel = rt1[3];
+ rt1[3] = (unsigned int)achannel * facf0;
+ blend_function(rt, rt1, rt2);
+ rt1[3] = achannel;
+ rt[3] = rt1[3];
+ rt1 += 4;
+ rt2 += 4;
+ rt += 4;
+ }
+ if (y == 0) {
+ break;
+ }
+ y--;
+ for (x = xo; x > 0; x--) {
+ achannel = rt1[3];
+ rt1[3] = (unsigned int)achannel * facf1;
+ blend_function(rt, rt1, rt2);
+ rt1[3] = achannel;
+ rt[3] = rt1[3];
+ rt1 += 4;
+ rt2 += 4;
+ rt += 4;
+ }
+ }
+}
+
+BLI_INLINE void apply_blend_function_float(float facf0,
+ float facf1,
+ int x,
+ int y,
+ float *rect1,
+ float *rect2,
+ float *out,
+ IMB_blend_func_float blend_function)
+{
+ int xo;
+ float *rt1, *rt2, *rt;
+ float achannel;
+ xo = x;
+ rt1 = rect1;
+ rt2 = rect2;
+ rt = out;
+ while (y--) {
+ for (x = xo; x > 0; x--) {
+ achannel = rt1[3];
+ rt1[3] = achannel * facf0;
+ blend_function(rt, rt1, rt2);
+ rt1[3] = achannel;
+ rt[3] = rt1[3];
+ rt1 += 4;
+ rt2 += 4;
+ rt += 4;
+ }
+ if (y == 0) {
+ break;
+ }
+ y--;
+ for (x = xo; x > 0; x--) {
+ achannel = rt1[3];
+ rt1[3] = achannel * facf1;
+ blend_function(rt, rt1, rt2);
+ rt1[3] = achannel;
+ rt[3] = rt1[3];
+ rt1 += 4;
+ rt2 += 4;
+ rt += 4;
+ }
+ }
}
static void do_blend_effect_float(
- float facf0, float facf1, int x, int y,
- float *rect1, float *rect2, int btype, float *out)
-{
- switch (btype) {
- case SEQ_TYPE_ADD:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_add_float);
- break;
- case SEQ_TYPE_SUB:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_sub_float);
- break;
- case SEQ_TYPE_MUL:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_mul_float);
- break;
- case SEQ_TYPE_DARKEN:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_darken_float);
- break;
- case SEQ_TYPE_BURN:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_burn_float);
- break;
- case SEQ_TYPE_LINEAR_BURN:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_linearburn_float);
- break;
- case SEQ_TYPE_SCREEN:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_screen_float);
- break;
- case SEQ_TYPE_LIGHTEN:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_lighten_float);
- break;
- case SEQ_TYPE_DODGE:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_dodge_float);
- break;
- case SEQ_TYPE_OVERLAY:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_overlay_float);
- break;
- case SEQ_TYPE_SOFT_LIGHT:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_softlight_float);
- break;
- case SEQ_TYPE_HARD_LIGHT:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_hardlight_float);
- break;
- case SEQ_TYPE_PIN_LIGHT:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_pinlight_float);
- break;
- case SEQ_TYPE_LIN_LIGHT:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_linearlight_float);
- break;
- case SEQ_TYPE_VIVID_LIGHT:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_vividlight_float);
- break;
- case SEQ_TYPE_BLEND_COLOR:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_color_float);
- break;
- case SEQ_TYPE_HUE:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_hue_float);
- break;
- case SEQ_TYPE_SATURATION:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_saturation_float);
- break;
- case SEQ_TYPE_VALUE:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_luminosity_float);
- break;
- case SEQ_TYPE_DIFFERENCE:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_difference_float);
- break;
- case SEQ_TYPE_EXCLUSION:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_exclusion_float);
- break;
- default:
- break;
- }
-}
-
-static void do_blend_effect_byte(
- float facf0, float facf1, int x, int y,
- unsigned char *rect1, unsigned char *rect2, int btype, unsigned char *out)
-{
- switch (btype) {
- case SEQ_TYPE_ADD:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_add_byte);
- break;
- case SEQ_TYPE_SUB:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_sub_byte);
- break;
- case SEQ_TYPE_MUL:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_mul_byte);
- break;
- case SEQ_TYPE_DARKEN:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_darken_byte);
- break;
- case SEQ_TYPE_BURN:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_burn_byte);
- break;
- case SEQ_TYPE_LINEAR_BURN:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_linearburn_byte);
- break;
- case SEQ_TYPE_SCREEN:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_screen_byte);
- break;
- case SEQ_TYPE_LIGHTEN:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_lighten_byte);
- break;
- case SEQ_TYPE_DODGE:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_dodge_byte);
- break;
- case SEQ_TYPE_OVERLAY:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_overlay_byte);
- break;
- case SEQ_TYPE_SOFT_LIGHT:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_softlight_byte);
- break;
- case SEQ_TYPE_HARD_LIGHT:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_hardlight_byte);
- break;
- case SEQ_TYPE_PIN_LIGHT:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_pinlight_byte);
- break;
- case SEQ_TYPE_LIN_LIGHT:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_linearlight_byte);
- break;
- case SEQ_TYPE_VIVID_LIGHT:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_vividlight_byte);
- break;
- case SEQ_TYPE_BLEND_COLOR:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_color_byte);
- break;
- case SEQ_TYPE_HUE:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_hue_byte);
- break;
- case SEQ_TYPE_SATURATION:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_saturation_byte);
- break;
- case SEQ_TYPE_VALUE:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_luminosity_byte);
- break;
- case SEQ_TYPE_DIFFERENCE:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_difference_byte);
- break;
- case SEQ_TYPE_EXCLUSION:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_exclusion_byte);
- break;
- default:
- break;
- }
-}
-
-static void do_blend_mode_effect(
- const SeqRenderData *context, Sequence *seq, float UNUSED(cfra), float facf0, float facf1,
- ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), int start_line, int total_lines, ImBuf *out)
-{
- if (out->rect_float) {
- float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
- slice_get_float_buffers(context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_blend_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, seq->blend_mode, rect_out);
- }
- else {
- unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
- slice_get_byte_buffers(context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_blend_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, seq->blend_mode, rect_out);
- }
+ float facf0, float facf1, int x, int y, float *rect1, float *rect2, int btype, float *out)
+{
+ switch (btype) {
+ case SEQ_TYPE_ADD:
+ apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_add_float);
+ break;
+ case SEQ_TYPE_SUB:
+ apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_sub_float);
+ break;
+ case SEQ_TYPE_MUL:
+ apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_mul_float);
+ break;
+ case SEQ_TYPE_DARKEN:
+ apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_darken_float);
+ break;
+ case SEQ_TYPE_BURN:
+ apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_burn_float);
+ break;
+ case SEQ_TYPE_LINEAR_BURN:
+ apply_blend_function_float(
+ facf0, facf1, x, y, rect1, rect2, out, blend_color_linearburn_float);
+ break;
+ case SEQ_TYPE_SCREEN:
+ apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_screen_float);
+ break;
+ case SEQ_TYPE_LIGHTEN:
+ apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_lighten_float);
+ break;
+ case SEQ_TYPE_DODGE:
+ apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_dodge_float);
+ break;
+ case SEQ_TYPE_OVERLAY:
+ apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_overlay_float);
+ break;
+ case SEQ_TYPE_SOFT_LIGHT:
+ apply_blend_function_float(
+ facf0, facf1, x, y, rect1, rect2, out, blend_color_softlight_float);
+ break;
+ case SEQ_TYPE_HARD_LIGHT:
+ apply_blend_function_float(
+ facf0, facf1, x, y, rect1, rect2, out, blend_color_hardlight_float);
+ break;
+ case SEQ_TYPE_PIN_LIGHT:
+ apply_blend_function_float(
+ facf0, facf1, x, y, rect1, rect2, out, blend_color_pinlight_float);
+ break;
+ case SEQ_TYPE_LIN_LIGHT:
+ apply_blend_function_float(
+ facf0, facf1, x, y, rect1, rect2, out, blend_color_linearlight_float);
+ break;
+ case SEQ_TYPE_VIVID_LIGHT:
+ apply_blend_function_float(
+ facf0, facf1, x, y, rect1, rect2, out, blend_color_vividlight_float);
+ break;
+ case SEQ_TYPE_BLEND_COLOR:
+ apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_color_float);
+ break;
+ case SEQ_TYPE_HUE:
+ apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_hue_float);
+ break;
+ case SEQ_TYPE_SATURATION:
+ apply_blend_function_float(
+ facf0, facf1, x, y, rect1, rect2, out, blend_color_saturation_float);
+ break;
+ case SEQ_TYPE_VALUE:
+ apply_blend_function_float(
+ facf0, facf1, x, y, rect1, rect2, out, blend_color_luminosity_float);
+ break;
+ case SEQ_TYPE_DIFFERENCE:
+ apply_blend_function_float(
+ facf0, facf1, x, y, rect1, rect2, out, blend_color_difference_float);
+ break;
+ case SEQ_TYPE_EXCLUSION:
+ apply_blend_function_float(
+ facf0, facf1, x, y, rect1, rect2, out, blend_color_exclusion_float);
+ break;
+ default:
+ break;
+ }
+}
+
+static void do_blend_effect_byte(float facf0,
+ float facf1,
+ int x,
+ int y,
+ unsigned char *rect1,
+ unsigned char *rect2,
+ int btype,
+ unsigned char *out)
+{
+ switch (btype) {
+ case SEQ_TYPE_ADD:
+ apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_add_byte);
+ break;
+ case SEQ_TYPE_SUB:
+ apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_sub_byte);
+ break;
+ case SEQ_TYPE_MUL:
+ apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_mul_byte);
+ break;
+ case SEQ_TYPE_DARKEN:
+ apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_darken_byte);
+ break;
+ case SEQ_TYPE_BURN:
+ apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_burn_byte);
+ break;
+ case SEQ_TYPE_LINEAR_BURN:
+ apply_blend_function_byte(
+ facf0, facf1, x, y, rect1, rect2, out, blend_color_linearburn_byte);
+ break;
+ case SEQ_TYPE_SCREEN:
+ apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_screen_byte);
+ break;
+ case SEQ_TYPE_LIGHTEN:
+ apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_lighten_byte);
+ break;
+ case SEQ_TYPE_DODGE:
+ apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_dodge_byte);
+ break;
+ case SEQ_TYPE_OVERLAY:
+ apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_overlay_byte);
+ break;
+ case SEQ_TYPE_SOFT_LIGHT:
+ apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_softlight_byte);
+ break;
+ case SEQ_TYPE_HARD_LIGHT:
+ apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_hardlight_byte);
+ break;
+ case SEQ_TYPE_PIN_LIGHT:
+ apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_pinlight_byte);
+ break;
+ case SEQ_TYPE_LIN_LIGHT:
+ apply_blend_function_byte(
+ facf0, facf1, x, y, rect1, rect2, out, blend_color_linearlight_byte);
+ break;
+ case SEQ_TYPE_VIVID_LIGHT:
+ apply_blend_function_byte(
+ facf0, facf1, x, y, rect1, rect2, out, blend_color_vividlight_byte);
+ break;
+ case SEQ_TYPE_BLEND_COLOR:
+ apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_color_byte);
+ break;
+ case SEQ_TYPE_HUE:
+ apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_hue_byte);
+ break;
+ case SEQ_TYPE_SATURATION:
+ apply_blend_function_byte(
+ facf0, facf1, x, y, rect1, rect2, out, blend_color_saturation_byte);
+ break;
+ case SEQ_TYPE_VALUE:
+ apply_blend_function_byte(
+ facf0, facf1, x, y, rect1, rect2, out, blend_color_luminosity_byte);
+ break;
+ case SEQ_TYPE_DIFFERENCE:
+ apply_blend_function_byte(
+ facf0, facf1, x, y, rect1, rect2, out, blend_color_difference_byte);
+ break;
+ case SEQ_TYPE_EXCLUSION:
+ apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_exclusion_byte);
+ break;
+ default:
+ break;
+ }
+}
+
+static void do_blend_mode_effect(const SeqRenderData *context,
+ Sequence *seq,
+ float UNUSED(cfra),
+ float facf0,
+ float facf1,
+ ImBuf *ibuf1,
+ ImBuf *ibuf2,
+ ImBuf *UNUSED(ibuf3),
+ int start_line,
+ int total_lines,
+ ImBuf *out)
+{
+ if (out->rect_float) {
+ float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
+ slice_get_float_buffers(
+ context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
+ do_blend_effect_float(
+ facf0, facf1, context->rectx, total_lines, rect1, rect2, seq->blend_mode, rect_out);
+ }
+ else {
+ unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
+ slice_get_byte_buffers(
+ context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
+ do_blend_effect_byte(
+ facf0, facf1, context->rectx, total_lines, rect1, rect2, seq->blend_mode, rect_out);
+ }
}
/*********************** Color Mix Effect *************************/
static void init_colormix_effect(Sequence *seq)
{
- ColorMixVars *data;
-
- if (seq->effectdata) {
- MEM_freeN(seq->effectdata);
- }
- seq->effectdata = MEM_callocN(sizeof(ColorMixVars), "colormixvars");
- data = (ColorMixVars *) seq->effectdata;
- data->blend_effect = SEQ_TYPE_OVERLAY;
- data->factor = 1.0f;
-}
-
-static void do_colormix_effect(
- const SeqRenderData *context, Sequence *seq, float UNUSED(cfra), float UNUSED(facf0), float UNUSED(facf1),
- ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), int start_line, int total_lines, ImBuf *out)
-{
- float facf;
-
- ColorMixVars *data = seq->effectdata;
- facf = data->factor;
-
- if (out->rect_float) {
- float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
- slice_get_float_buffers(context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_blend_effect_float(facf, facf, context->rectx, total_lines, rect1, rect2, data->blend_effect, rect_out);
- }
- else {
- unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
- slice_get_byte_buffers(context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_blend_effect_byte(facf, facf, context->rectx, total_lines, rect1, rect2, data->blend_effect, rect_out);
- }
+ ColorMixVars *data;
+
+ if (seq->effectdata) {
+ MEM_freeN(seq->effectdata);
+ }
+ seq->effectdata = MEM_callocN(sizeof(ColorMixVars), "colormixvars");
+ data = (ColorMixVars *)seq->effectdata;
+ data->blend_effect = SEQ_TYPE_OVERLAY;
+ data->factor = 1.0f;
+}
+
+static void do_colormix_effect(const SeqRenderData *context,
+ Sequence *seq,
+ float UNUSED(cfra),
+ float UNUSED(facf0),
+ float UNUSED(facf1),
+ ImBuf *ibuf1,
+ ImBuf *ibuf2,
+ ImBuf *UNUSED(ibuf3),
+ int start_line,
+ int total_lines,
+ ImBuf *out)
+{
+ float facf;
+
+ ColorMixVars *data = seq->effectdata;
+ facf = data->factor;
+
+ if (out->rect_float) {
+ float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
+ slice_get_float_buffers(
+ context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
+ do_blend_effect_float(
+ facf, facf, context->rectx, total_lines, rect1, rect2, data->blend_effect, rect_out);
+ }
+ else {
+ unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
+ slice_get_byte_buffers(
+ context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
+ do_blend_effect_byte(
+ facf, facf, context->rectx, total_lines, rect1, rect2, data->blend_effect, rect_out);
+ }
}
/*********************** Wipe *************************/
typedef struct WipeZone {
- float angle;
- int flip;
- int xo, yo;
- int width;
- float pythangle;
+ float angle;
+ int flip;
+ int xo, yo;
+ int width;
+ float pythangle;
} WipeZone;
static void precalc_wipe_zone(WipeZone *wipezone, WipeVars *wipe, int xo, int yo)
{
- wipezone->flip = (wipe->angle < 0.0f);
- wipezone->angle = tanf(fabsf(wipe->angle));
- wipezone->xo = xo;
- wipezone->yo = yo;
- wipezone->width = (int)(wipe->edgeWidth * ((xo + yo) / 2.0f));
- wipezone->pythangle = 1.0f / sqrtf(wipezone->angle * wipezone->angle + 1.0f);
+ wipezone->flip = (wipe->angle < 0.0f);
+ wipezone->angle = tanf(fabsf(wipe->angle));
+ wipezone->xo = xo;
+ wipezone->yo = yo;
+ wipezone->width = (int)(wipe->edgeWidth * ((xo + yo) / 2.0f));
+ wipezone->pythangle = 1.0f / sqrtf(wipezone->angle * wipezone->angle + 1.0f);
}
/* This function calculates the blur band for the wipe effects */
static float in_band(float width, float dist, int side, int dir)
{
- float alpha;
+ float alpha;
- if (width == 0)
- return (float)side;
+ if (width == 0)
+ return (float)side;
- if (width < dist)
- return (float)side;
+ if (width < dist)
+ return (float)side;
- if (side == 1)
- alpha = (dist + 0.5f * width) / (width);
- else
- alpha = (0.5f * width - dist) / (width);
+ if (side == 1)
+ alpha = (dist + 0.5f * width) / (width);
+ else
+ alpha = (0.5f * width - dist) / (width);
- if (dir == 0)
- alpha = 1 - alpha;
+ if (dir == 0)
+ alpha = 1 - alpha;
- return alpha;
+ return alpha;
}
static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float facf0)
{
- float posx, posy, hyp, hyp2, angle, hwidth, b1, b2, b3, pointdist;
- /* some future stuff */
- /* float hyp3, hyp4, b4, b5 */
- float temp1, temp2, temp3, temp4; /* some placeholder variables */
- int xo = wipezone->xo;
- int yo = wipezone->yo;
- float halfx = xo * 0.5f;
- float halfy = yo * 0.5f;
- float widthf, output = 0;
- WipeVars *wipe = (WipeVars *)seq->effectdata;
- int width;
-
- if (wipezone->flip) x = xo - x;
- angle = wipezone->angle;
-
- if (wipe->forward) {
- posx = facf0 * xo;
- posy = facf0 * yo;
- }
- else {
- posx = xo - facf0 * xo;
- posy = yo - facf0 * yo;
- }
-
- switch (wipe->wipetype) {
- case DO_SINGLE_WIPE:
- width = min_ii(wipezone->width, facf0 * yo);
- width = min_ii(width, yo - facf0 * yo);
-
- if (angle == 0.0f) {
- b1 = posy;
- b2 = y;
- hyp = fabsf(y - posy);
- }
- else {
- b1 = posy - (-angle) * posx;
- b2 = y - (-angle) * x;
- hyp = fabsf(angle * x + y + (-posy - angle * posx)) * wipezone->pythangle;
- }
-
- if (angle < 0) {
- temp1 = b1;
- b1 = b2;
- b2 = temp1;
- }
-
- if (wipe->forward) {
- if (b1 < b2)
- output = in_band(width, hyp, 1, 1);
- else
- output = in_band(width, hyp, 0, 1);
- }
- else {
- if (b1 < b2)
- output = in_band(width, hyp, 0, 1);
- else
- output = in_band(width, hyp, 1, 1);
- }
- break;
-
- case DO_DOUBLE_WIPE:
- if (!wipe->forward)
- facf0 = 1.0f - facf0; /* Go the other direction */
-
- width = wipezone->width; /* calculate the blur width */
- hwidth = width * 0.5f;
- if (angle == 0) {
- b1 = posy * 0.5f;
- b3 = yo - posy * 0.5f;
- b2 = y;
-
- hyp = fabsf(y - posy * 0.5f);
- hyp2 = fabsf(y - (yo - posy * 0.5f));
- }
- else {
- b1 = posy * 0.5f - (-angle) * posx * 0.5f;
- b3 = (yo - posy * 0.5f) - (-angle) * (xo - posx * 0.5f);
- b2 = y - (-angle) * x;
-
- hyp = fabsf(angle * x + y + (-posy * 0.5f - angle * posx * 0.5f)) * wipezone->pythangle;
- hyp2 = fabsf(angle * x + y + (-(yo - posy * 0.5f) - angle * (xo - posx * 0.5f))) * wipezone->pythangle;
- }
-
- hwidth = min_ff(hwidth, fabsf(b3 - b1) / 2.0f);
-
- if (b2 < b1 && b2 < b3) {
- output = in_band(hwidth, hyp, 0, 1);
- }
- else if (b2 > b1 && b2 > b3) {
- output = in_band(hwidth, hyp2, 0, 1);
- }
- else {
- if (hyp < hwidth && hyp2 > hwidth)
- output = in_band(hwidth, hyp, 1, 1);
- else if (hyp > hwidth && hyp2 < hwidth)
- output = in_band(hwidth, hyp2, 1, 1);
- else
- output = in_band(hwidth, hyp2, 1, 1) * in_band(hwidth, hyp, 1, 1);
- }
- if (!wipe->forward) output = 1 - output;
- break;
- case DO_CLOCK_WIPE:
- /*
- * temp1: angle of effect center in rads
- * temp2: angle of line through (halfx, halfy) and (x, y) in rads
- * temp3: angle of low side of blur
- * temp4: angle of high side of blur
- */
- output = 1.0f - facf0;
- widthf = wipe->edgeWidth * 2.0f * (float)M_PI;
- temp1 = 2.0f * (float)M_PI * facf0;
-
- if (wipe->forward) {
- temp1 = 2.0f * (float)M_PI - temp1;
- }
-
- x = x - halfx;
- y = y - halfy;
-
- temp2 = asin(abs(y) / hypot(x, y));
- if (x <= 0 && y >= 0) temp2 = (float)M_PI - temp2;
- else if (x <= 0 && y <= 0) temp2 += (float)M_PI;
- else if (x >= 0 && y <= 0) temp2 = 2.0f * (float)M_PI - temp2;
-
- if (wipe->forward) {
- temp3 = temp1 - (widthf * 0.5f) * facf0;
- temp4 = temp1 + (widthf * 0.5f) * (1 - facf0);
- }
- else {
- temp3 = temp1 - (widthf * 0.5f) * (1 - facf0);
- temp4 = temp1 + (widthf * 0.5f) * facf0;
- }
- if (temp3 < 0) temp3 = 0;
- if (temp4 > 2.0f * (float)M_PI) temp4 = 2.0f * (float)M_PI;
-
-
- if (temp2 < temp3) output = 0;
- else if (temp2 > temp4) output = 1;
- else output = (temp2 - temp3) / (temp4 - temp3);
- if (x == 0 && y == 0) output = 1;
- if (output != output) output = 1;
- if (wipe->forward) output = 1 - output;
- break;
- case DO_IRIS_WIPE:
- if (xo > yo) yo = xo;
- else xo = yo;
-
- if (!wipe->forward) facf0 = 1 - facf0;
-
- width = wipezone->width;
- hwidth = width * 0.5f;
-
- temp1 = (halfx - (halfx) * facf0);
- pointdist = hypotf(temp1, temp1);
-
- temp2 = hypotf(halfx - x, halfy - y);
- if (temp2 > pointdist) output = in_band(hwidth, fabsf(temp2 - pointdist), 0, 1);
- else output = in_band(hwidth, fabsf(temp2 - pointdist), 1, 1);
-
- if (!wipe->forward) output = 1 - output;
-
- break;
- }
- if (output < 0) output = 0;
- else if (output > 1) output = 1;
- return output;
+ float posx, posy, hyp, hyp2, angle, hwidth, b1, b2, b3, pointdist;
+ /* some future stuff */
+ /* float hyp3, hyp4, b4, b5 */
+ float temp1, temp2, temp3, temp4; /* some placeholder variables */
+ int xo = wipezone->xo;
+ int yo = wipezone->yo;
+ float halfx = xo * 0.5f;
+ float halfy = yo * 0.5f;
+ float widthf, output = 0;
+ WipeVars *wipe = (WipeVars *)seq->effectdata;
+ int width;
+
+ if (wipezone->flip)
+ x = xo - x;
+ angle = wipezone->angle;
+
+ if (wipe->forward) {
+ posx = facf0 * xo;
+ posy = facf0 * yo;
+ }
+ else {
+ posx = xo - facf0 * xo;
+ posy = yo - facf0 * yo;
+ }
+
+ switch (wipe->wipetype) {
+ case DO_SINGLE_WIPE:
+ width = min_ii(wipezone->width, facf0 * yo);
+ width = min_ii(width, yo - facf0 * yo);
+
+ if (angle == 0.0f) {
+ b1 = posy;
+ b2 = y;
+ hyp = fabsf(y - posy);
+ }
+ else {
+ b1 = posy - (-angle) * posx;
+ b2 = y - (-angle) * x;
+ hyp = fabsf(angle * x + y + (-posy - angle * posx)) * wipezone->pythangle;
+ }
+
+ if (angle < 0) {
+ temp1 = b1;
+ b1 = b2;
+ b2 = temp1;
+ }
+
+ if (wipe->forward) {
+ if (b1 < b2)
+ output = in_band(width, hyp, 1, 1);
+ else
+ output = in_band(width, hyp, 0, 1);
+ }
+ else {
+ if (b1 < b2)
+ output = in_band(width, hyp, 0, 1);
+ else
+ output = in_band(width, hyp, 1, 1);
+ }
+ break;
+
+ case DO_DOUBLE_WIPE:
+ if (!wipe->forward)
+ facf0 = 1.0f - facf0; /* Go the other direction */
+
+ width = wipezone->width; /* calculate the blur width */
+ hwidth = width * 0.5f;
+ if (angle == 0) {
+ b1 = posy * 0.5f;
+ b3 = yo - posy * 0.5f;
+ b2 = y;
+
+ hyp = fabsf(y - posy * 0.5f);
+ hyp2 = fabsf(y - (yo - posy * 0.5f));
+ }
+ else {
+ b1 = posy * 0.5f - (-angle) * posx * 0.5f;
+ b3 = (yo - posy * 0.5f) - (-angle) * (xo - posx * 0.5f);
+ b2 = y - (-angle) * x;
+
+ hyp = fabsf(angle * x + y + (-posy * 0.5f - angle * posx * 0.5f)) * wipezone->pythangle;
+ hyp2 = fabsf(angle * x + y + (-(yo - posy * 0.5f) - angle * (xo - posx * 0.5f))) *
+ wipezone->pythangle;
+ }
+
+ hwidth = min_ff(hwidth, fabsf(b3 - b1) / 2.0f);
+
+ if (b2 < b1 && b2 < b3) {
+ output = in_band(hwidth, hyp, 0, 1);
+ }
+ else if (b2 > b1 && b2 > b3) {
+ output = in_band(hwidth, hyp2, 0, 1);
+ }
+ else {
+ if (hyp < hwidth && hyp2 > hwidth)
+ output = in_band(hwidth, hyp, 1, 1);
+ else if (hyp > hwidth && hyp2 < hwidth)
+ output = in_band(hwidth, hyp2, 1, 1);
+ else
+ output = in_band(hwidth, hyp2, 1, 1) * in_band(hwidth, hyp, 1, 1);
+ }
+ if (!wipe->forward)
+ output = 1 - output;
+ break;
+ case DO_CLOCK_WIPE:
+ /*
+ * temp1: angle of effect center in rads
+ * temp2: angle of line through (halfx, halfy) and (x, y) in rads
+ * temp3: angle of low side of blur
+ * temp4: angle of high side of blur
+ */
+ output = 1.0f - facf0;
+ widthf = wipe->edgeWidth * 2.0f * (float)M_PI;
+ temp1 = 2.0f * (float)M_PI * facf0;
+
+ if (wipe->forward) {
+ temp1 = 2.0f * (float)M_PI - temp1;
+ }
+
+ x = x - halfx;
+ y = y - halfy;
+
+ temp2 = asin(abs(y) / hypot(x, y));
+ if (x <= 0 && y >= 0)
+ temp2 = (float)M_PI - temp2;
+ else if (x <= 0 && y <= 0)
+ temp2 += (float)M_PI;
+ else if (x >= 0 && y <= 0)
+ temp2 = 2.0f * (float)M_PI - temp2;
+
+ if (wipe->forward) {
+ temp3 = temp1 - (widthf * 0.5f) * facf0;
+ temp4 = temp1 + (widthf * 0.5f) * (1 - facf0);
+ }
+ else {
+ temp3 = temp1 - (widthf * 0.5f) * (1 - facf0);
+ temp4 = temp1 + (widthf * 0.5f) * facf0;
+ }
+ if (temp3 < 0)
+ temp3 = 0;
+ if (temp4 > 2.0f * (float)M_PI)
+ temp4 = 2.0f * (float)M_PI;
+
+ if (temp2 < temp3)
+ output = 0;
+ else if (temp2 > temp4)
+ output = 1;
+ else
+ output = (temp2 - temp3) / (temp4 - temp3);
+ if (x == 0 && y == 0)
+ output = 1;
+ if (output != output)
+ output = 1;
+ if (wipe->forward)
+ output = 1 - output;
+ break;
+ case DO_IRIS_WIPE:
+ if (xo > yo)
+ yo = xo;
+ else
+ xo = yo;
+
+ if (!wipe->forward)
+ facf0 = 1 - facf0;
+
+ width = wipezone->width;
+ hwidth = width * 0.5f;
+
+ temp1 = (halfx - (halfx)*facf0);
+ pointdist = hypotf(temp1, temp1);
+
+ temp2 = hypotf(halfx - x, halfy - y);
+ if (temp2 > pointdist)
+ output = in_band(hwidth, fabsf(temp2 - pointdist), 0, 1);
+ else
+ output = in_band(hwidth, fabsf(temp2 - pointdist), 1, 1);
+
+ if (!wipe->forward)
+ output = 1 - output;
+
+ break;
+ }
+ if (output < 0)
+ output = 0;
+ else if (output > 1)
+ output = 1;
+ return output;
}
static void init_wipe_effect(Sequence *seq)
{
- if (seq->effectdata)
- MEM_freeN(seq->effectdata);
+ if (seq->effectdata)
+ MEM_freeN(seq->effectdata);
- seq->effectdata = MEM_callocN(sizeof(WipeVars), "wipevars");
+ seq->effectdata = MEM_callocN(sizeof(WipeVars), "wipevars");
}
static int num_inputs_wipe(void)
{
- return 2;
+ return 2;
}
static void free_wipe_effect(Sequence *seq, const bool UNUSED(do_id_user))
{
- if (seq->effectdata)
- MEM_freeN(seq->effectdata);
+ if (seq->effectdata)
+ MEM_freeN(seq->effectdata);
- seq->effectdata = NULL;
+ seq->effectdata = NULL;
}
static void copy_wipe_effect(Sequence *dst, Sequence *src, const int UNUSED(flag))
{
- dst->effectdata = MEM_dupallocN(src->effectdata);
-}
-
-static void do_wipe_effect_byte(
- Sequence *seq, float facf0, float UNUSED(facf1), int x, int y,
- unsigned char *rect1, unsigned char *rect2, unsigned char *out)
-{
- WipeZone wipezone;
- WipeVars *wipe = (WipeVars *)seq->effectdata;
- int xo, yo;
- unsigned char *cp1, *cp2, *rt;
-
- precalc_wipe_zone(&wipezone, wipe, x, y);
-
- cp1 = rect1;
- cp2 = rect2;
- rt = out;
-
- xo = x;
- yo = y;
- for (y = 0; y < yo; y++) {
- for (x = 0; x < xo; x++) {
- float check = check_zone(&wipezone, x, y, seq, facf0);
- if (check) {
- if (cp1) {
- float rt1[4], rt2[4], tempc[4];
-
- straight_uchar_to_premul_float(rt1, cp1);
- straight_uchar_to_premul_float(rt2, cp2);
-
- tempc[0] = rt1[0] * check + rt2[0] * (1 - check);
- tempc[1] = rt1[1] * check + rt2[1] * (1 - check);
- tempc[2] = rt1[2] * check + rt2[2] * (1 - check);
- tempc[3] = rt1[3] * check + rt2[3] * (1 - check);
-
- premul_float_to_straight_uchar(rt, tempc);
- }
- else {
- rt[0] = 0;
- rt[1] = 0;
- rt[2] = 0;
- rt[3] = 255;
- }
- }
- else {
- if (cp2) {
- rt[0] = cp2[0];
- rt[1] = cp2[1];
- rt[2] = cp2[2];
- rt[3] = cp2[3];
- }
- else {
- rt[0] = 0;
- rt[1] = 0;
- rt[2] = 0;
- rt[3] = 255;
- }
- }
-
- rt += 4;
- if (cp1 != NULL) {
- cp1 += 4;
- }
- if (cp2 != NULL) {
- cp2 += 4;
- }
- }
- }
-}
-
-static void do_wipe_effect_float(
- Sequence *seq, float facf0, float UNUSED(facf1), int x, int y,
- float *rect1, float *rect2, float *out)
-{
- WipeZone wipezone;
- WipeVars *wipe = (WipeVars *)seq->effectdata;
- int xo, yo;
- float *rt1, *rt2, *rt;
-
- precalc_wipe_zone(&wipezone, wipe, x, y);
-
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
-
- xo = x;
- yo = y;
- for (y = 0; y < yo; y++) {
- for (x = 0; x < xo; x++) {
- float check = check_zone(&wipezone, x, y, seq, facf0);
- if (check) {
- if (rt1) {
- rt[0] = rt1[0] * check + rt2[0] * (1 - check);
- rt[1] = rt1[1] * check + rt2[1] * (1 - check);
- rt[2] = rt1[2] * check + rt2[2] * (1 - check);
- rt[3] = rt1[3] * check + rt2[3] * (1 - check);
- }
- else {
- rt[0] = 0;
- rt[1] = 0;
- rt[2] = 0;
- rt[3] = 1.0;
- }
- }
- else {
- if (rt2) {
- rt[0] = rt2[0];
- rt[1] = rt2[1];
- rt[2] = rt2[2];
- rt[3] = rt2[3];
- }
- else {
- rt[0] = 0;
- rt[1] = 0;
- rt[2] = 0;
- rt[3] = 1.0;
- }
- }
-
- rt += 4;
- if (rt1 != NULL) {
- rt1 += 4;
- }
- if (rt2 != NULL) {
- rt2 += 4;
- }
- }
- }
-}
-
-static ImBuf *do_wipe_effect(
- const SeqRenderData *context, Sequence *seq, float UNUSED(cfra), float facf0, float facf1,
- ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3)
-{
- ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3);
-
- if (out->rect_float) {
- do_wipe_effect_float(
- seq, facf0, facf1, context->rectx, context->recty, ibuf1->rect_float,
- ibuf2->rect_float, out->rect_float);
- }
- else {
- do_wipe_effect_byte(
- seq, facf0, facf1, context->rectx, context->recty, (unsigned char *) ibuf1->rect,
- (unsigned char *) ibuf2->rect, (unsigned char *) out->rect);
- }
-
- return out;
+ dst->effectdata = MEM_dupallocN(src->effectdata);
+}
+
+static void do_wipe_effect_byte(Sequence *seq,
+ float facf0,
+ float UNUSED(facf1),
+ int x,
+ int y,
+ unsigned char *rect1,
+ unsigned char *rect2,
+ unsigned char *out)
+{
+ WipeZone wipezone;
+ WipeVars *wipe = (WipeVars *)seq->effectdata;
+ int xo, yo;
+ unsigned char *cp1, *cp2, *rt;
+
+ precalc_wipe_zone(&wipezone, wipe, x, y);
+
+ cp1 = rect1;
+ cp2 = rect2;
+ rt = out;
+
+ xo = x;
+ yo = y;
+ for (y = 0; y < yo; y++) {
+ for (x = 0; x < xo; x++) {
+ float check = check_zone(&wipezone, x, y, seq, facf0);
+ if (check) {
+ if (cp1) {
+ float rt1[4], rt2[4], tempc[4];
+
+ straight_uchar_to_premul_float(rt1, cp1);
+ straight_uchar_to_premul_float(rt2, cp2);
+
+ tempc[0] = rt1[0] * check + rt2[0] * (1 - check);
+ tempc[1] = rt1[1] * check + rt2[1] * (1 - check);
+ tempc[2] = rt1[2] * check + rt2[2] * (1 - check);
+ tempc[3] = rt1[3] * check + rt2[3] * (1 - check);
+
+ premul_float_to_straight_uchar(rt, tempc);
+ }
+ else {
+ rt[0] = 0;
+ rt[1] = 0;
+ rt[2] = 0;
+ rt[3] = 255;
+ }
+ }
+ else {
+ if (cp2) {
+ rt[0] = cp2[0];
+ rt[1] = cp2[1];
+ rt[2] = cp2[2];
+ rt[3] = cp2[3];
+ }
+ else {
+ rt[0] = 0;
+ rt[1] = 0;
+ rt[2] = 0;
+ rt[3] = 255;
+ }
+ }
+
+ rt += 4;
+ if (cp1 != NULL) {
+ cp1 += 4;
+ }
+ if (cp2 != NULL) {
+ cp2 += 4;
+ }
+ }
+ }
+}
+
+static void do_wipe_effect_float(Sequence *seq,
+ float facf0,
+ float UNUSED(facf1),
+ int x,
+ int y,
+ float *rect1,
+ float *rect2,
+ float *out)
+{
+ WipeZone wipezone;
+ WipeVars *wipe = (WipeVars *)seq->effectdata;
+ int xo, yo;
+ float *rt1, *rt2, *rt;
+
+ precalc_wipe_zone(&wipezone, wipe, x, y);
+
+ rt1 = rect1;
+ rt2 = rect2;
+ rt = out;
+
+ xo = x;
+ yo = y;
+ for (y = 0; y < yo; y++) {
+ for (x = 0; x < xo; x++) {
+ float check = check_zone(&wipezone, x, y, seq, facf0);
+ if (check) {
+ if (rt1) {
+ rt[0] = rt1[0] * check + rt2[0] * (1 - check);
+ rt[1] = rt1[1] * check + rt2[1] * (1 - check);
+ rt[2] = rt1[2] * check + rt2[2] * (1 - check);
+ rt[3] = rt1[3] * check + rt2[3] * (1 - check);
+ }
+ else {
+ rt[0] = 0;
+ rt[1] = 0;
+ rt[2] = 0;
+ rt[3] = 1.0;
+ }
+ }
+ else {
+ if (rt2) {
+ rt[0] = rt2[0];
+ rt[1] = rt2[1];
+ rt[2] = rt2[2];
+ rt[3] = rt2[3];
+ }
+ else {
+ rt[0] = 0;
+ rt[1] = 0;
+ rt[2] = 0;
+ rt[3] = 1.0;
+ }
+ }
+
+ rt += 4;
+ if (rt1 != NULL) {
+ rt1 += 4;
+ }
+ if (rt2 != NULL) {
+ rt2 += 4;
+ }
+ }
+ }
+}
+
+static ImBuf *do_wipe_effect(const SeqRenderData *context,
+ Sequence *seq,
+ float UNUSED(cfra),
+ float facf0,
+ float facf1,
+ ImBuf *ibuf1,
+ ImBuf *ibuf2,
+ ImBuf *ibuf3)
+{
+ ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3);
+
+ if (out->rect_float) {
+ do_wipe_effect_float(seq,
+ facf0,
+ facf1,
+ context->rectx,
+ context->recty,
+ ibuf1->rect_float,
+ ibuf2->rect_float,
+ out->rect_float);
+ }
+ else {
+ do_wipe_effect_byte(seq,
+ facf0,
+ facf1,
+ context->rectx,
+ context->recty,
+ (unsigned char *)ibuf1->rect,
+ (unsigned char *)ibuf2->rect,
+ (unsigned char *)out->rect);
+ }
+
+ return out;
}
/*********************** Transform *************************/
static void init_transform_effect(Sequence *seq)
{
- TransformVars *transform;
+ TransformVars *transform;
- if (seq->effectdata)
- MEM_freeN(seq->effectdata);
+ if (seq->effectdata)
+ MEM_freeN(seq->effectdata);
- seq->effectdata = MEM_callocN(sizeof(TransformVars), "transformvars");
+ seq->effectdata = MEM_callocN(sizeof(TransformVars), "transformvars");
- transform = (TransformVars *) seq->effectdata;
+ transform = (TransformVars *)seq->effectdata;
- transform->ScalexIni = 1.0f;
- transform->ScaleyIni = 1.0f;
+ transform->ScalexIni = 1.0f;
+ transform->ScaleyIni = 1.0f;
- transform->xIni = 0.0f;
- transform->yIni = 0.0f;
+ transform->xIni = 0.0f;
+ transform->yIni = 0.0f;
- transform->rotIni = 0.0f;
+ transform->rotIni = 0.0f;
- transform->interpolation = 1;
- transform->percent = 1;
- transform->uniform_scale = 0;
+ transform->interpolation = 1;
+ transform->percent = 1;
+ transform->uniform_scale = 0;
}
static int num_inputs_transform(void)
{
- return 1;
+ return 1;
}
static void free_transform_effect(Sequence *seq, const bool UNUSED(do_id_user))
{
- if (seq->effectdata) MEM_freeN(seq->effectdata);
- seq->effectdata = NULL;
+ if (seq->effectdata)
+ MEM_freeN(seq->effectdata);
+ seq->effectdata = NULL;
}
static void copy_transform_effect(Sequence *dst, Sequence *src, const int UNUSED(flag))
{
- dst->effectdata = MEM_dupallocN(src->effectdata);
-}
-
-static void transform_image(
- int x, int y, ImBuf *ibuf1, ImBuf *out, float scale_x, float scale_y,
- float translate_x, float translate_y, float rotate, int interpolation)
-{
- int xo, yo, xi, yi;
- float xt, yt, xr, yr;
- float s, c;
-
- xo = x;
- yo = y;
-
- /* Rotate */
- s = sinf(rotate);
- c = cosf(rotate);
-
- for (yi = 0; yi < yo; yi++) {
- for (xi = 0; xi < xo; xi++) {
- /* translate point */
- xt = xi - translate_x;
- yt = yi - translate_y;
-
- /* rotate point with center ref */
- xr = c * xt + s * yt;
- yr = -s * xt + c * yt;
-
- /* scale point with center ref */
- xt = xr / scale_x;
- yt = yr / scale_y;
-
- /* undo reference center point */
- xt += (xo / 2.0f);
- yt += (yo / 2.0f);
-
- /* interpolate */
- switch (interpolation) {
- case 0:
- nearest_interpolation(ibuf1, out, xt, yt, xi, yi);
- break;
- case 1:
- bilinear_interpolation(ibuf1, out, xt, yt, xi, yi);
- break;
- case 2:
- bicubic_interpolation(ibuf1, out, xt, yt, xi, yi);
- break;
- }
- }
- }
-}
-
-static void do_transform(Scene *scene, Sequence *seq, float UNUSED(facf0), int x, int y, ImBuf *ibuf1, ImBuf *out)
-{
- TransformVars *transform = (TransformVars *) seq->effectdata;
- float scale_x, scale_y, translate_x, translate_y, rotate_radians;
-
- /* Scale */
- if (transform->uniform_scale) {
- scale_x = scale_y = transform->ScalexIni;
- }
- else {
- scale_x = transform->ScalexIni;
- scale_y = transform->ScaleyIni;
- }
-
- /* Translate */
- if (!transform->percent) {
- float rd_s = (scene->r.size / 100.0f);
-
- translate_x = transform->xIni * rd_s + (x / 2.0f);
- translate_y = transform->yIni * rd_s + (y / 2.0f);
- }
- else {
- translate_x = x * (transform->xIni / 100.0f) + (x / 2.0f);
- translate_y = y * (transform->yIni / 100.0f) + (y / 2.0f);
- }
-
- /* Rotate */
- rotate_radians = DEG2RADF(transform->rotIni);
-
- transform_image(x, y, ibuf1, out, scale_x, scale_y, translate_x, translate_y, rotate_radians, transform->interpolation);
-}
-
-
-static ImBuf *do_transform_effect(
- const SeqRenderData *context, Sequence *seq, float UNUSED(cfra), float facf0,
- float UNUSED(facf1), ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3)
-{
- ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3);
-
- do_transform(context->scene, seq, facf0, context->rectx, context->recty, ibuf1, out);
-
- return out;
+ dst->effectdata = MEM_dupallocN(src->effectdata);
+}
+
+static void transform_image(int x,
+ int y,
+ ImBuf *ibuf1,
+ ImBuf *out,
+ float scale_x,
+ float scale_y,
+ float translate_x,
+ float translate_y,
+ float rotate,
+ int interpolation)
+{
+ int xo, yo, xi, yi;
+ float xt, yt, xr, yr;
+ float s, c;
+
+ xo = x;
+ yo = y;
+
+ /* Rotate */
+ s = sinf(rotate);
+ c = cosf(rotate);
+
+ for (yi = 0; yi < yo; yi++) {
+ for (xi = 0; xi < xo; xi++) {
+ /* translate point */
+ xt = xi - translate_x;
+ yt = yi - translate_y;
+
+ /* rotate point with center ref */
+ xr = c * xt + s * yt;
+ yr = -s * xt + c * yt;
+
+ /* scale point with center ref */
+ xt = xr / scale_x;
+ yt = yr / scale_y;
+
+ /* undo reference center point */
+ xt += (xo / 2.0f);
+ yt += (yo / 2.0f);
+
+ /* interpolate */
+ switch (interpolation) {
+ case 0:
+ nearest_interpolation(ibuf1, out, xt, yt, xi, yi);
+ break;
+ case 1:
+ bilinear_interpolation(ibuf1, out, xt, yt, xi, yi);
+ break;
+ case 2:
+ bicubic_interpolation(ibuf1, out, xt, yt, xi, yi);
+ break;
+ }
+ }
+ }
+}
+
+static void do_transform(
+ Scene *scene, Sequence *seq, float UNUSED(facf0), int x, int y, ImBuf *ibuf1, ImBuf *out)
+{
+ TransformVars *transform = (TransformVars *)seq->effectdata;
+ float scale_x, scale_y, translate_x, translate_y, rotate_radians;
+
+ /* Scale */
+ if (transform->uniform_scale) {
+ scale_x = scale_y = transform->ScalexIni;
+ }
+ else {
+ scale_x = transform->ScalexIni;
+ scale_y = transform->ScaleyIni;
+ }
+
+ /* Translate */
+ if (!transform->percent) {
+ float rd_s = (scene->r.size / 100.0f);
+
+ translate_x = transform->xIni * rd_s + (x / 2.0f);
+ translate_y = transform->yIni * rd_s + (y / 2.0f);
+ }
+ else {
+ translate_x = x * (transform->xIni / 100.0f) + (x / 2.0f);
+ translate_y = y * (transform->yIni / 100.0f) + (y / 2.0f);
+ }
+
+ /* Rotate */
+ rotate_radians = DEG2RADF(transform->rotIni);
+
+ transform_image(x,
+ y,
+ ibuf1,
+ out,
+ scale_x,
+ scale_y,
+ translate_x,
+ translate_y,
+ rotate_radians,
+ transform->interpolation);
+}
+
+static ImBuf *do_transform_effect(const SeqRenderData *context,
+ Sequence *seq,
+ float UNUSED(cfra),
+ float facf0,
+ float UNUSED(facf1),
+ ImBuf *ibuf1,
+ ImBuf *ibuf2,
+ ImBuf *ibuf3)
+{
+ ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3);
+
+ do_transform(context->scene, seq, facf0, context->rectx, context->recty, ibuf1, out);
+
+ return out;
}
/*********************** Glow *************************/
static void RVBlurBitmap2_float(float *map, int width, int height, float blur, int quality)
-/* MUUUCCH better than the previous blur. */
-/* We do the blurring in two passes which is a whole lot faster. */
-/* I changed the math around to implement an actual Gaussian */
-/* distribution. */
+/* MUUUCCH better than the previous blur. */
+/* We do the blurring in two passes which is a whole lot faster. */
+/* I changed the math around to implement an actual Gaussian */
+/* distribution. */
/* */
-/* Watch out though, it tends to misbehaven with large blur values on */
-/* a small bitmap. Avoid avoid avoid. */
+/* Watch out though, it tends to misbehaven with large blur values on */
+/* a small bitmap. Avoid avoid avoid. */
/*=============================== */
{
- float *temp = NULL, *swap;
- float *filter = NULL;
- int x, y, i, fx, fy;
- int index, ix, halfWidth;
- float fval, k, curColor[4], curColor2[4], weight = 0;
-
- /* If we're not really blurring, bail out */
- if (blur <= 0)
- return;
-
- /* Allocate memory for the tempmap and the blur filter matrix */
- temp = MEM_mallocN((width * height * 4 * sizeof(float)), "blurbitmaptemp");
- if (!temp)
- return;
-
- /* Allocate memory for the filter elements */
- halfWidth = ((quality + 1) * blur);
- filter = (float *)MEM_mallocN(sizeof(float) * halfWidth * 2, "blurbitmapfilter");
- if (!filter) {
- MEM_freeN(temp);
- return;
- }
-
- /* Apparently we're calculating a bell curve based on the standard deviation (or radius)
- * This code is based on an example posted to comp.graphics.algorithms by
- * Blancmange (bmange@airdmhor.gen.nz)
- */
-
- k = -1.0f / (2.0f * (float)M_PI * blur * blur);
-
- for (ix = 0; ix < halfWidth; ix++) {
- weight = (float)exp(k * (ix * ix));
- filter[halfWidth - ix] = weight;
- filter[halfWidth + ix] = weight;
- }
- filter[0] = weight;
-
- /* Normalize the array */
- fval = 0;
- for (ix = 0; ix < halfWidth * 2; ix++)
- fval += filter[ix];
-
- for (ix = 0; ix < halfWidth * 2; ix++)
- filter[ix] /= fval;
-
- /* Blur the rows */
- for (y = 0; y < height; y++) {
- /* Do the left & right strips */
- for (x = 0; x < halfWidth; x++) {
- fx = 0;
- zero_v4(curColor);
- zero_v4(curColor2);
-
- for (i = x - halfWidth; i < x + halfWidth; i++) {
- if ((i >= 0) && (i < width)) {
- index = (i + y * width) * 4;
- madd_v4_v4fl(curColor, map + index, filter[fx]);
-
- index = (width - 1 - i + y * width) * 4;
- madd_v4_v4fl(curColor2, map + index, filter[fx]);
- }
- fx++;
- }
- index = (x + y * width) * 4;
- copy_v4_v4(temp + index, curColor);
-
- index = (width - 1 - x + y * width) * 4;
- copy_v4_v4(temp + index, curColor2);
- }
-
- /* Do the main body */
- for (x = halfWidth; x < width - halfWidth; x++) {
- fx = 0;
- zero_v4(curColor);
- for (i = x - halfWidth; i < x + halfWidth; i++) {
- index = (i + y * width) * 4;
- madd_v4_v4fl(curColor, map + index, filter[fx]);
- fx++;
- }
- index = (x + y * width) * 4;
- copy_v4_v4(temp + index, curColor);
- }
- }
-
- /* Swap buffers */
- swap = temp; temp = map; map = swap;
-
- /* Blur the columns */
- for (x = 0; x < width; x++) {
- /* Do the top & bottom strips */
- for (y = 0; y < halfWidth; y++) {
- fy = 0;
- zero_v4(curColor);
- zero_v4(curColor2);
- for (i = y - halfWidth; i < y + halfWidth; i++) {
- if ((i >= 0) && (i < height)) {
- /* Bottom */
- index = (x + i * width) * 4;
- madd_v4_v4fl(curColor, map + index, filter[fy]);
-
- /* Top */
- index = (x + (height - 1 - i) * width) * 4;
- madd_v4_v4fl(curColor2, map + index, filter[fy]);
- }
- fy++;
- }
- index = (x + y * width) * 4;
- copy_v4_v4(temp + index, curColor);
-
- index = (x + (height - 1 - y) * width) * 4;
- copy_v4_v4(temp + index, curColor2);
- }
-
- /* Do the main body */
- for (y = halfWidth; y < height - halfWidth; y++) {
- fy = 0;
- zero_v4(curColor);
- for (i = y - halfWidth; i < y + halfWidth; i++) {
- index = (x + i * width) * 4;
- madd_v4_v4fl(curColor, map + index, filter[fy]);
- fy++;
- }
- index = (x + y * width) * 4;
- copy_v4_v4(temp + index, curColor);
- }
- }
-
- /* Swap buffers */
- swap = temp; temp = map; /* map = swap; */ /* UNUSED */
-
- /* Tidy up */
- MEM_freeN(filter);
- MEM_freeN(temp);
+ float *temp = NULL, *swap;
+ float *filter = NULL;
+ int x, y, i, fx, fy;
+ int index, ix, halfWidth;
+ float fval, k, curColor[4], curColor2[4], weight = 0;
+
+ /* If we're not really blurring, bail out */
+ if (blur <= 0)
+ return;
+
+ /* Allocate memory for the tempmap and the blur filter matrix */
+ temp = MEM_mallocN((width * height * 4 * sizeof(float)), "blurbitmaptemp");
+ if (!temp)
+ return;
+
+ /* Allocate memory for the filter elements */
+ halfWidth = ((quality + 1) * blur);
+ filter = (float *)MEM_mallocN(sizeof(float) * halfWidth * 2, "blurbitmapfilter");
+ if (!filter) {
+ MEM_freeN(temp);
+ return;
+ }
+
+ /* Apparently we're calculating a bell curve based on the standard deviation (or radius)
+ * This code is based on an example posted to comp.graphics.algorithms by
+ * Blancmange (bmange@airdmhor.gen.nz)
+ */
+
+ k = -1.0f / (2.0f * (float)M_PI * blur * blur);
+
+ for (ix = 0; ix < halfWidth; ix++) {
+ weight = (float)exp(k * (ix * ix));
+ filter[halfWidth - ix] = weight;
+ filter[halfWidth + ix] = weight;
+ }
+ filter[0] = weight;
+
+ /* Normalize the array */
+ fval = 0;
+ for (ix = 0; ix < halfWidth * 2; ix++)
+ fval += filter[ix];
+
+ for (ix = 0; ix < halfWidth * 2; ix++)
+ filter[ix] /= fval;
+
+ /* Blur the rows */
+ for (y = 0; y < height; y++) {
+ /* Do the left & right strips */
+ for (x = 0; x < halfWidth; x++) {
+ fx = 0;
+ zero_v4(curColor);
+ zero_v4(curColor2);
+
+ for (i = x - halfWidth; i < x + halfWidth; i++) {
+ if ((i >= 0) && (i < width)) {
+ index = (i + y * width) * 4;
+ madd_v4_v4fl(curColor, map + index, filter[fx]);
+
+ index = (width - 1 - i + y * width) * 4;
+ madd_v4_v4fl(curColor2, map + index, filter[fx]);
+ }
+ fx++;
+ }
+ index = (x + y * width) * 4;
+ copy_v4_v4(temp + index, curColor);
+
+ index = (width - 1 - x + y * width) * 4;
+ copy_v4_v4(temp + index, curColor2);
+ }
+
+ /* Do the main body */
+ for (x = halfWidth; x < width - halfWidth; x++) {
+ fx = 0;
+ zero_v4(curColor);
+ for (i = x - halfWidth; i < x + halfWidth; i++) {
+ index = (i + y * width) * 4;
+ madd_v4_v4fl(curColor, map + index, filter[fx]);
+ fx++;
+ }
+ index = (x + y * width) * 4;
+ copy_v4_v4(temp + index, curColor);
+ }
+ }
+
+ /* Swap buffers */
+ swap = temp;
+ temp = map;
+ map = swap;
+
+ /* Blur the columns */
+ for (x = 0; x < width; x++) {
+ /* Do the top & bottom strips */
+ for (y = 0; y < halfWidth; y++) {
+ fy = 0;
+ zero_v4(curColor);
+ zero_v4(curColor2);
+ for (i = y - halfWidth; i < y + halfWidth; i++) {
+ if ((i >= 0) && (i < height)) {
+ /* Bottom */
+ index = (x + i * width) * 4;
+ madd_v4_v4fl(curColor, map + index, filter[fy]);
+
+ /* Top */
+ index = (x + (height - 1 - i) * width) * 4;
+ madd_v4_v4fl(curColor2, map + index, filter[fy]);
+ }
+ fy++;
+ }
+ index = (x + y * width) * 4;
+ copy_v4_v4(temp + index, curColor);
+
+ index = (x + (height - 1 - y) * width) * 4;
+ copy_v4_v4(temp + index, curColor2);
+ }
+
+ /* Do the main body */
+ for (y = halfWidth; y < height - halfWidth; y++) {
+ fy = 0;
+ zero_v4(curColor);
+ for (i = y - halfWidth; i < y + halfWidth; i++) {
+ index = (x + i * width) * 4;
+ madd_v4_v4fl(curColor, map + index, filter[fy]);
+ fy++;
+ }
+ index = (x + y * width) * 4;
+ copy_v4_v4(temp + index, curColor);
+ }
+ }
+
+ /* Swap buffers */
+ swap = temp;
+ temp = map; /* map = swap; */ /* UNUSED */
+
+ /* Tidy up */
+ MEM_freeN(filter);
+ MEM_freeN(temp);
}
static void RVAddBitmaps_float(float *a, float *b, float *c, int width, int height)
{
- int x, y, index;
+ int x, y, index;
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x++) {
- index = (x + y * width) * 4;
- c[index + GlowR] = min_ff(1.0f, a[index + GlowR] + b[index + GlowR]);
- c[index + GlowG] = min_ff(1.0f, a[index + GlowG] + b[index + GlowG]);
- c[index + GlowB] = min_ff(1.0f, a[index + GlowB] + b[index + GlowB]);
- c[index + GlowA] = min_ff(1.0f, a[index + GlowA] + b[index + GlowA]);
- }
- }
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ index = (x + y * width) * 4;
+ c[index + GlowR] = min_ff(1.0f, a[index + GlowR] + b[index + GlowR]);
+ c[index + GlowG] = min_ff(1.0f, a[index + GlowG] + b[index + GlowG]);
+ c[index + GlowB] = min_ff(1.0f, a[index + GlowB] + b[index + GlowB]);
+ c[index + GlowA] = min_ff(1.0f, a[index + GlowA] + b[index + GlowA]);
+ }
+ }
}
static void RVIsolateHighlights_float(
- float *in, float *out, int width, int height,
- float threshold, float boost, float clamp)
-{
- int x, y, index;
- float intensity;
-
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x++) {
- index = (x + y * width) * 4;
-
- /* Isolate the intensity */
- intensity = (in[index + GlowR] + in[index + GlowG] + in[index + GlowB] - threshold);
- if (intensity > 0) {
- out[index + GlowR] = min_ff(clamp, (in[index + GlowR] * boost * intensity));
- out[index + GlowG] = min_ff(clamp, (in[index + GlowG] * boost * intensity));
- out[index + GlowB] = min_ff(clamp, (in[index + GlowB] * boost * intensity));
- out[index + GlowA] = min_ff(clamp, (in[index + GlowA] * boost * intensity));
- }
- else {
- out[index + GlowR] = 0;
- out[index + GlowG] = 0;
- out[index + GlowB] = 0;
- out[index + GlowA] = 0;
- }
- }
- }
+ float *in, float *out, int width, int height, float threshold, float boost, float clamp)
+{
+ int x, y, index;
+ float intensity;
+
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ index = (x + y * width) * 4;
+
+ /* Isolate the intensity */
+ intensity = (in[index + GlowR] + in[index + GlowG] + in[index + GlowB] - threshold);
+ if (intensity > 0) {
+ out[index + GlowR] = min_ff(clamp, (in[index + GlowR] * boost * intensity));
+ out[index + GlowG] = min_ff(clamp, (in[index + GlowG] * boost * intensity));
+ out[index + GlowB] = min_ff(clamp, (in[index + GlowB] * boost * intensity));
+ out[index + GlowA] = min_ff(clamp, (in[index + GlowA] * boost * intensity));
+ }
+ else {
+ out[index + GlowR] = 0;
+ out[index + GlowG] = 0;
+ out[index + GlowB] = 0;
+ out[index + GlowA] = 0;
+ }
+ }
+ }
}
static void init_glow_effect(Sequence *seq)
{
- GlowVars *glow;
+ GlowVars *glow;
- if (seq->effectdata)
- MEM_freeN(seq->effectdata);
+ if (seq->effectdata)
+ MEM_freeN(seq->effectdata);
- seq->effectdata = MEM_callocN(sizeof(GlowVars), "glowvars");
+ seq->effectdata = MEM_callocN(sizeof(GlowVars), "glowvars");
- glow = (GlowVars *)seq->effectdata;
- glow->fMini = 0.25;
- glow->fClamp = 1.0;
- glow->fBoost = 0.5;
- glow->dDist = 3.0;
- glow->dQuality = 3;
- glow->bNoComp = 0;
+ glow = (GlowVars *)seq->effectdata;
+ glow->fMini = 0.25;
+ glow->fClamp = 1.0;
+ glow->fBoost = 0.5;
+ glow->dDist = 3.0;
+ glow->dQuality = 3;
+ glow->bNoComp = 0;
}
static int num_inputs_glow(void)
{
- return 1;
+ return 1;
}
static void free_glow_effect(Sequence *seq, const bool UNUSED(do_id_user))
{
- if (seq->effectdata)
- MEM_freeN(seq->effectdata);
+ if (seq->effectdata)
+ MEM_freeN(seq->effectdata);
- seq->effectdata = NULL;
+ seq->effectdata = NULL;
}
static void copy_glow_effect(Sequence *dst, Sequence *src, const int UNUSED(flag))
{
- dst->effectdata = MEM_dupallocN(src->effectdata);
-}
-
-static void do_glow_effect_byte(
- Sequence *seq, int render_size, float facf0, float UNUSED(facf1), int x, int y,
- unsigned char *rect1, unsigned char *UNUSED(rect2), unsigned char *out)
-{
- float *outbuf, *inbuf;
- GlowVars *glow = (GlowVars *)seq->effectdata;
-
- inbuf = MEM_mallocN(4 * sizeof(float) * x * y, "glow effect input");
- outbuf = MEM_mallocN(4 * sizeof(float) * x * y, "glow effect output");
-
- IMB_buffer_float_from_byte(inbuf, rect1, IB_PROFILE_SRGB, IB_PROFILE_SRGB, false, x, y, x, x);
- IMB_buffer_float_premultiply(inbuf, x, y);
-
- RVIsolateHighlights_float(inbuf, outbuf, x, y, glow->fMini * 3.0f, glow->fBoost * facf0, glow->fClamp);
- RVBlurBitmap2_float(outbuf, x, y, glow->dDist * (render_size / 100.0f), glow->dQuality);
- if (!glow->bNoComp)
- RVAddBitmaps_float(inbuf, outbuf, outbuf, x, y);
-
- IMB_buffer_float_unpremultiply(outbuf, x, y);
- IMB_buffer_byte_from_float(out, outbuf, 4, 0.0f, IB_PROFILE_SRGB, IB_PROFILE_SRGB, false, x, y, x, x);
-
- MEM_freeN(inbuf);
- MEM_freeN(outbuf);
-}
-
-static void do_glow_effect_float(
- Sequence *seq, int render_size, float facf0, float UNUSED(facf1), int x, int y,
- float *rect1, float *UNUSED(rect2), float *out)
-{
- float *outbuf = out;
- float *inbuf = rect1;
- GlowVars *glow = (GlowVars *)seq->effectdata;
-
- RVIsolateHighlights_float(inbuf, outbuf, x, y, glow->fMini * 3.0f, glow->fBoost * facf0, glow->fClamp);
- RVBlurBitmap2_float(outbuf, x, y, glow->dDist * (render_size / 100.0f), glow->dQuality);
- if (!glow->bNoComp)
- RVAddBitmaps_float(inbuf, outbuf, outbuf, x, y);
-}
-
-static ImBuf *do_glow_effect(
- const SeqRenderData *context, Sequence *seq, float UNUSED(cfra), float facf0, float facf1,
- ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3)
-{
- ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3);
-
- int render_size = 100 * context->rectx / context->scene->r.xsch;
-
- if (out->rect_float) {
- do_glow_effect_float(
- seq, render_size, facf0, facf1, context->rectx, context->recty,
- ibuf1->rect_float, ibuf2->rect_float, out->rect_float);
- }
- else {
- do_glow_effect_byte(
- seq, render_size, facf0, facf1, context->rectx, context->recty,
- (unsigned char *) ibuf1->rect, (unsigned char *) ibuf2->rect, (unsigned char *) out->rect);
- }
-
- return out;
+ dst->effectdata = MEM_dupallocN(src->effectdata);
+}
+
+static void do_glow_effect_byte(Sequence *seq,
+ int render_size,
+ float facf0,
+ float UNUSED(facf1),
+ int x,
+ int y,
+ unsigned char *rect1,
+ unsigned char *UNUSED(rect2),
+ unsigned char *out)
+{
+ float *outbuf, *inbuf;
+ GlowVars *glow = (GlowVars *)seq->effectdata;
+
+ inbuf = MEM_mallocN(4 * sizeof(float) * x * y, "glow effect input");
+ outbuf = MEM_mallocN(4 * sizeof(float) * x * y, "glow effect output");
+
+ IMB_buffer_float_from_byte(inbuf, rect1, IB_PROFILE_SRGB, IB_PROFILE_SRGB, false, x, y, x, x);
+ IMB_buffer_float_premultiply(inbuf, x, y);
+
+ RVIsolateHighlights_float(
+ inbuf, outbuf, x, y, glow->fMini * 3.0f, glow->fBoost * facf0, glow->fClamp);
+ RVBlurBitmap2_float(outbuf, x, y, glow->dDist * (render_size / 100.0f), glow->dQuality);
+ if (!glow->bNoComp)
+ RVAddBitmaps_float(inbuf, outbuf, outbuf, x, y);
+
+ IMB_buffer_float_unpremultiply(outbuf, x, y);
+ IMB_buffer_byte_from_float(
+ out, outbuf, 4, 0.0f, IB_PROFILE_SRGB, IB_PROFILE_SRGB, false, x, y, x, x);
+
+ MEM_freeN(inbuf);
+ MEM_freeN(outbuf);
+}
+
+static void do_glow_effect_float(Sequence *seq,
+ int render_size,
+ float facf0,
+ float UNUSED(facf1),
+ int x,
+ int y,
+ float *rect1,
+ float *UNUSED(rect2),
+ float *out)
+{
+ float *outbuf = out;
+ float *inbuf = rect1;
+ GlowVars *glow = (GlowVars *)seq->effectdata;
+
+ RVIsolateHighlights_float(
+ inbuf, outbuf, x, y, glow->fMini * 3.0f, glow->fBoost * facf0, glow->fClamp);
+ RVBlurBitmap2_float(outbuf, x, y, glow->dDist * (render_size / 100.0f), glow->dQuality);
+ if (!glow->bNoComp)
+ RVAddBitmaps_float(inbuf, outbuf, outbuf, x, y);
+}
+
+static ImBuf *do_glow_effect(const SeqRenderData *context,
+ Sequence *seq,
+ float UNUSED(cfra),
+ float facf0,
+ float facf1,
+ ImBuf *ibuf1,
+ ImBuf *ibuf2,
+ ImBuf *ibuf3)
+{
+ ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3);
+
+ int render_size = 100 * context->rectx / context->scene->r.xsch;
+
+ if (out->rect_float) {
+ do_glow_effect_float(seq,
+ render_size,
+ facf0,
+ facf1,
+ context->rectx,
+ context->recty,
+ ibuf1->rect_float,
+ ibuf2->rect_float,
+ out->rect_float);
+ }
+ else {
+ do_glow_effect_byte(seq,
+ render_size,
+ facf0,
+ facf1,
+ context->rectx,
+ context->recty,
+ (unsigned char *)ibuf1->rect,
+ (unsigned char *)ibuf2->rect,
+ (unsigned char *)out->rect);
+ }
+
+ return out;
}
/*********************** Solid color *************************/
static void init_solid_color(Sequence *seq)
{
- SolidColorVars *cv;
+ SolidColorVars *cv;
- if (seq->effectdata)
- MEM_freeN(seq->effectdata);
+ if (seq->effectdata)
+ MEM_freeN(seq->effectdata);
- seq->effectdata = MEM_callocN(sizeof(SolidColorVars), "solidcolor");
+ seq->effectdata = MEM_callocN(sizeof(SolidColorVars), "solidcolor");
- cv = (SolidColorVars *)seq->effectdata;
- cv->col[0] = cv->col[1] = cv->col[2] = 0.5;
+ cv = (SolidColorVars *)seq->effectdata;
+ cv->col[0] = cv->col[1] = cv->col[2] = 0.5;
}
static int num_inputs_color(void)
{
- return 0;
+ return 0;
}
static void free_solid_color(Sequence *seq, const bool UNUSED(do_id_user))
{
- if (seq->effectdata)
- MEM_freeN(seq->effectdata);
+ if (seq->effectdata)
+ MEM_freeN(seq->effectdata);
- seq->effectdata = NULL;
+ seq->effectdata = NULL;
}
static void copy_solid_color(Sequence *dst, Sequence *src, const int UNUSED(flag))
{
- dst->effectdata = MEM_dupallocN(src->effectdata);
+ dst->effectdata = MEM_dupallocN(src->effectdata);
}
static int early_out_color(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1))
{
- return EARLY_NO_INPUT;
-}
-
-static ImBuf *do_solid_color(
- const SeqRenderData *context, Sequence *seq, float UNUSED(cfra), float facf0, float facf1,
- ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3)
-{
- ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3);
-
- SolidColorVars *cv = (SolidColorVars *)seq->effectdata;
-
- unsigned char *rect;
- float *rect_float;
- int x; /*= context->rectx;*/ /*UNUSED*/
- int y; /*= context->recty;*/ /*UNUSED*/
-
- if (out->rect) {
- unsigned char col0[3];
- unsigned char col1[3];
-
- col0[0] = facf0 * cv->col[0] * 255;
- col0[1] = facf0 * cv->col[1] * 255;
- col0[2] = facf0 * cv->col[2] * 255;
-
- col1[0] = facf1 * cv->col[0] * 255;
- col1[1] = facf1 * cv->col[1] * 255;
- col1[2] = facf1 * cv->col[2] * 255;
-
- rect = (unsigned char *)out->rect;
-
- for (y = 0; y < out->y; y++) {
- for (x = 0; x < out->x; x++, rect += 4) {
- rect[0] = col0[0];
- rect[1] = col0[1];
- rect[2] = col0[2];
- rect[3] = 255;
- }
- y++;
- if (y < out->y) {
- for (x = 0; x < out->x; x++, rect += 4) {
- rect[0] = col1[0];
- rect[1] = col1[1];
- rect[2] = col1[2];
- rect[3] = 255;
- }
- }
- }
-
- }
- else if (out->rect_float) {
- float col0[3];
- float col1[3];
-
- col0[0] = facf0 * cv->col[0];
- col0[1] = facf0 * cv->col[1];
- col0[2] = facf0 * cv->col[2];
-
- col1[0] = facf1 * cv->col[0];
- col1[1] = facf1 * cv->col[1];
- col1[2] = facf1 * cv->col[2];
-
- rect_float = out->rect_float;
-
- for (y = 0; y < out->y; y++) {
- for (x = 0; x < out->x; x++, rect_float += 4) {
- rect_float[0] = col0[0];
- rect_float[1] = col0[1];
- rect_float[2] = col0[2];
- rect_float[3] = 1.0;
- }
- y++;
- if (y < out->y) {
- for (x = 0; x < out->x; x++, rect_float += 4) {
- rect_float[0] = col1[0];
- rect_float[1] = col1[1];
- rect_float[2] = col1[2];
- rect_float[3] = 1.0;
- }
- }
- }
- }
- return out;
+ return EARLY_NO_INPUT;
+}
+
+static ImBuf *do_solid_color(const SeqRenderData *context,
+ Sequence *seq,
+ float UNUSED(cfra),
+ float facf0,
+ float facf1,
+ ImBuf *ibuf1,
+ ImBuf *ibuf2,
+ ImBuf *ibuf3)
+{
+ ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3);
+
+ SolidColorVars *cv = (SolidColorVars *)seq->effectdata;
+
+ unsigned char *rect;
+ float *rect_float;
+ int x; /*= context->rectx;*/ /*UNUSED*/
+ int y; /*= context->recty;*/ /*UNUSED*/
+
+ if (out->rect) {
+ unsigned char col0[3];
+ unsigned char col1[3];
+
+ col0[0] = facf0 * cv->col[0] * 255;
+ col0[1] = facf0 * cv->col[1] * 255;
+ col0[2] = facf0 * cv->col[2] * 255;
+
+ col1[0] = facf1 * cv->col[0] * 255;
+ col1[1] = facf1 * cv->col[1] * 255;
+ col1[2] = facf1 * cv->col[2] * 255;
+
+ rect = (unsigned char *)out->rect;
+
+ for (y = 0; y < out->y; y++) {
+ for (x = 0; x < out->x; x++, rect += 4) {
+ rect[0] = col0[0];
+ rect[1] = col0[1];
+ rect[2] = col0[2];
+ rect[3] = 255;
+ }
+ y++;
+ if (y < out->y) {
+ for (x = 0; x < out->x; x++, rect += 4) {
+ rect[0] = col1[0];
+ rect[1] = col1[1];
+ rect[2] = col1[2];
+ rect[3] = 255;
+ }
+ }
+ }
+ }
+ else if (out->rect_float) {
+ float col0[3];
+ float col1[3];
+
+ col0[0] = facf0 * cv->col[0];
+ col0[1] = facf0 * cv->col[1];
+ col0[2] = facf0 * cv->col[2];
+
+ col1[0] = facf1 * cv->col[0];
+ col1[1] = facf1 * cv->col[1];
+ col1[2] = facf1 * cv->col[2];
+
+ rect_float = out->rect_float;
+
+ for (y = 0; y < out->y; y++) {
+ for (x = 0; x < out->x; x++, rect_float += 4) {
+ rect_float[0] = col0[0];
+ rect_float[1] = col0[1];
+ rect_float[2] = col0[2];
+ rect_float[3] = 1.0;
+ }
+ y++;
+ if (y < out->y) {
+ for (x = 0; x < out->x; x++, rect_float += 4) {
+ rect_float[0] = col1[0];
+ rect_float[1] = col1[1];
+ rect_float[2] = col1[2];
+ rect_float[3] = 1.0;
+ }
+ }
+ }
+ }
+ return out;
}
/*********************** Mulitcam *************************/
@@ -2511,50 +2866,55 @@ static ImBuf *do_solid_color(
/* no effect inputs for multicam, we use give_ibuf_seq */
static int num_inputs_multicam(void)
{
- return 0;
+ return 0;
}
static int early_out_multicam(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1))
{
- return EARLY_NO_INPUT;
+ return EARLY_NO_INPUT;
}
-static ImBuf *do_multicam(
- const SeqRenderData *context, Sequence *seq, float cfra, float UNUSED(facf0), float UNUSED(facf1),
- ImBuf *UNUSED(ibuf1), ImBuf *UNUSED(ibuf2), ImBuf *UNUSED(ibuf3))
+static ImBuf *do_multicam(const SeqRenderData *context,
+ Sequence *seq,
+ float cfra,
+ float UNUSED(facf0),
+ float UNUSED(facf1),
+ ImBuf *UNUSED(ibuf1),
+ ImBuf *UNUSED(ibuf2),
+ ImBuf *UNUSED(ibuf3))
{
- ImBuf *i;
- ImBuf *out;
- Editing *ed;
- ListBase *seqbasep;
+ ImBuf *i;
+ ImBuf *out;
+ Editing *ed;
+ ListBase *seqbasep;
- if (seq->multicam_source == 0 || seq->multicam_source >= seq->machine) {
- return NULL;
- }
+ if (seq->multicam_source == 0 || seq->multicam_source >= seq->machine) {
+ return NULL;
+ }
- ed = context->scene->ed;
- if (!ed) {
- return NULL;
- }
- seqbasep = BKE_sequence_seqbase(&ed->seqbase, seq);
- if (!seqbasep) {
- return NULL;
- }
+ ed = context->scene->ed;
+ if (!ed) {
+ return NULL;
+ }
+ seqbasep = BKE_sequence_seqbase(&ed->seqbase, seq);
+ if (!seqbasep) {
+ return NULL;
+ }
- i = BKE_sequencer_give_ibuf_seqbase(context, cfra, seq->multicam_source, seqbasep);
- if (!i) {
- return NULL;
- }
+ i = BKE_sequencer_give_ibuf_seqbase(context, cfra, seq->multicam_source, seqbasep);
+ if (!i) {
+ return NULL;
+ }
- if (BKE_sequencer_input_have_to_preprocess(context, seq, cfra)) {
- out = IMB_dupImBuf(i);
- IMB_freeImBuf(i);
- }
- else {
- out = i;
- }
+ if (BKE_sequencer_input_have_to_preprocess(context, seq, cfra)) {
+ out = IMB_dupImBuf(i);
+ IMB_freeImBuf(i);
+ }
+ else {
+ out = i;
+ }
- return out;
+ return out;
}
/*********************** Adjustment *************************/
@@ -2562,307 +2922,330 @@ static ImBuf *do_multicam(
/* no effect inputs for adjustment, we use give_ibuf_seq */
static int num_inputs_adjustment(void)
{
- return 0;
+ return 0;
}
static int early_out_adjustment(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1))
{
- return EARLY_NO_INPUT;
+ return EARLY_NO_INPUT;
}
static ImBuf *do_adjustment_impl(const SeqRenderData *context, Sequence *seq, float cfra)
{
- Editing *ed;
- ListBase *seqbasep;
- ImBuf *i = NULL;
+ Editing *ed;
+ ListBase *seqbasep;
+ ImBuf *i = NULL;
- ed = context->scene->ed;
+ ed = context->scene->ed;
- seqbasep = BKE_sequence_seqbase(&ed->seqbase, seq);
+ seqbasep = BKE_sequence_seqbase(&ed->seqbase, seq);
- if (seq->machine > 1) {
- i = BKE_sequencer_give_ibuf_seqbase(context, cfra, seq->machine - 1, seqbasep);
- }
+ if (seq->machine > 1) {
+ i = BKE_sequencer_give_ibuf_seqbase(context, cfra, seq->machine - 1, seqbasep);
+ }
- /* found nothing? so let's work the way up the metastrip stack, so
- * that it is possible to group a bunch of adjustment strips into
- * a metastrip and have that work on everything below the metastrip
- */
+ /* found nothing? so let's work the way up the metastrip stack, so
+ * that it is possible to group a bunch of adjustment strips into
+ * a metastrip and have that work on everything below the metastrip
+ */
- if (!i) {
- Sequence *meta;
+ if (!i) {
+ Sequence *meta;
- meta = BKE_sequence_metastrip(&ed->seqbase, NULL, seq);
+ meta = BKE_sequence_metastrip(&ed->seqbase, NULL, seq);
- if (meta) {
- i = do_adjustment_impl(context, meta, cfra);
- }
- }
+ if (meta) {
+ i = do_adjustment_impl(context, meta, cfra);
+ }
+ }
- return i;
+ return i;
}
-static ImBuf *do_adjustment(
- const SeqRenderData *context, Sequence *seq, float cfra, float UNUSED(facf0), float UNUSED(facf1),
- ImBuf *UNUSED(ibuf1), ImBuf *UNUSED(ibuf2), ImBuf *UNUSED(ibuf3))
+static ImBuf *do_adjustment(const SeqRenderData *context,
+ Sequence *seq,
+ float cfra,
+ float UNUSED(facf0),
+ float UNUSED(facf1),
+ ImBuf *UNUSED(ibuf1),
+ ImBuf *UNUSED(ibuf2),
+ ImBuf *UNUSED(ibuf3))
{
- ImBuf *i = NULL;
- ImBuf *out;
- Editing *ed;
+ ImBuf *i = NULL;
+ ImBuf *out;
+ Editing *ed;
- ed = context->scene->ed;
+ ed = context->scene->ed;
- if (!ed) {
- return NULL;
- }
+ if (!ed) {
+ return NULL;
+ }
- i = do_adjustment_impl(context, seq, cfra);
+ i = do_adjustment_impl(context, seq, cfra);
- if (BKE_sequencer_input_have_to_preprocess(context, seq, cfra)) {
- out = IMB_dupImBuf(i);
- if (out) {
- IMB_metadata_copy(out, i);
- }
- IMB_freeImBuf(i);
- }
- else {
- out = i;
- }
+ if (BKE_sequencer_input_have_to_preprocess(context, seq, cfra)) {
+ out = IMB_dupImBuf(i);
+ if (out) {
+ IMB_metadata_copy(out, i);
+ }
+ IMB_freeImBuf(i);
+ }
+ else {
+ out = i;
+ }
- return out;
+ return out;
}
/*********************** Speed *************************/
static void init_speed_effect(Sequence *seq)
{
- SpeedControlVars *v;
+ SpeedControlVars *v;
- if (seq->effectdata)
- MEM_freeN(seq->effectdata);
+ if (seq->effectdata)
+ MEM_freeN(seq->effectdata);
- seq->effectdata = MEM_callocN(sizeof(SpeedControlVars), "speedcontrolvars");
+ seq->effectdata = MEM_callocN(sizeof(SpeedControlVars), "speedcontrolvars");
- v = (SpeedControlVars *)seq->effectdata;
- v->globalSpeed = 1.0;
- v->frameMap = NULL;
- v->flags |= SEQ_SPEED_INTEGRATE; /* should be default behavior */
- v->length = 0;
+ v = (SpeedControlVars *)seq->effectdata;
+ v->globalSpeed = 1.0;
+ v->frameMap = NULL;
+ v->flags |= SEQ_SPEED_INTEGRATE; /* should be default behavior */
+ v->length = 0;
}
static void load_speed_effect(Sequence *seq)
{
- SpeedControlVars *v = (SpeedControlVars *)seq->effectdata;
+ SpeedControlVars *v = (SpeedControlVars *)seq->effectdata;
- v->frameMap = NULL;
- v->length = 0;
+ v->frameMap = NULL;
+ v->length = 0;
}
static int num_inputs_speed(void)
{
- return 1;
+ return 1;
}
static void free_speed_effect(Sequence *seq, const bool UNUSED(do_id_user))
{
- SpeedControlVars *v = (SpeedControlVars *)seq->effectdata;
- if (v->frameMap)
- MEM_freeN(v->frameMap);
- if (seq->effectdata)
- MEM_freeN(seq->effectdata);
- seq->effectdata = NULL;
+ SpeedControlVars *v = (SpeedControlVars *)seq->effectdata;
+ if (v->frameMap)
+ MEM_freeN(v->frameMap);
+ if (seq->effectdata)
+ MEM_freeN(seq->effectdata);
+ seq->effectdata = NULL;
}
static void copy_speed_effect(Sequence *dst, Sequence *src, const int UNUSED(flag))
{
- SpeedControlVars *v;
- dst->effectdata = MEM_dupallocN(src->effectdata);
- v = (SpeedControlVars *)dst->effectdata;
- v->frameMap = NULL;
- v->length = 0;
+ SpeedControlVars *v;
+ dst->effectdata = MEM_dupallocN(src->effectdata);
+ v = (SpeedControlVars *)dst->effectdata;
+ v->frameMap = NULL;
+ v->length = 0;
}
static int early_out_speed(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1))
{
- return EARLY_USE_INPUT_1;
+ return EARLY_USE_INPUT_1;
}
static void store_icu_yrange_speed(Sequence *seq, short UNUSED(adrcode), float *ymin, float *ymax)
{
- SpeedControlVars *v = (SpeedControlVars *)seq->effectdata;
+ SpeedControlVars *v = (SpeedControlVars *)seq->effectdata;
- /* if not already done, load / initialize data */
- BKE_sequence_get_effect(seq);
+ /* if not already done, load / initialize data */
+ BKE_sequence_get_effect(seq);
- if ((v->flags & SEQ_SPEED_INTEGRATE) != 0) {
- *ymin = -100.0;
- *ymax = 100.0;
- }
- else {
- if (v->flags & SEQ_SPEED_COMPRESS_IPO_Y) {
- *ymin = 0.0;
- *ymax = 1.0;
- }
- else {
- *ymin = 0.0;
- *ymax = seq->len;
- }
- }
+ if ((v->flags & SEQ_SPEED_INTEGRATE) != 0) {
+ *ymin = -100.0;
+ *ymax = 100.0;
+ }
+ else {
+ if (v->flags & SEQ_SPEED_COMPRESS_IPO_Y) {
+ *ymin = 0.0;
+ *ymax = 1.0;
+ }
+ else {
+ *ymin = 0.0;
+ *ymax = seq->len;
+ }
+ }
}
void BKE_sequence_effect_speed_rebuild_map(Scene *scene, Sequence *seq, bool force)
{
- int cfra;
- float fallback_fac = 1.0f;
- SpeedControlVars *v = (SpeedControlVars *) seq->effectdata;
- FCurve *fcu = NULL;
- int flags = v->flags;
-
- /* if not already done, load / initialize data */
- BKE_sequence_get_effect(seq);
-
- if ((force == false) &&
- (seq->len == v->length) &&
- (v->frameMap != NULL))
- {
- return;
- }
- if ((seq->seq1 == NULL) || (seq->len < 1)) {
- /* make coverity happy and check for (CID 598) input strip ... */
- return;
- }
-
- /* XXX - new in 2.5x. should we use the animation system this way?
- * The fcurve is needed because many frames need evaluating at once - campbell */
- fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "speed_factor", 0, NULL);
-
-
- if (!v->frameMap || v->length != seq->len) {
- if (v->frameMap) MEM_freeN(v->frameMap);
-
- v->length = seq->len;
-
- v->frameMap = MEM_callocN(sizeof(float) * v->length, "speedcontrol frameMap");
- }
-
- fallback_fac = 1.0;
-
- if (seq->flag & SEQ_USE_EFFECT_DEFAULT_FADE) {
- if ((seq->seq1->enddisp != seq->seq1->start) &&
- (seq->seq1->len != 0))
- {
- fallback_fac = (float) seq->seq1->len / (float) (seq->seq1->enddisp - seq->seq1->start);
- flags = SEQ_SPEED_INTEGRATE;
- fcu = NULL;
- }
- }
- else {
- /* if there is no fcurve, use value as simple multiplier */
- if (!fcu) {
- fallback_fac = seq->speed_fader; /* same as speed_factor in rna*/
- }
- }
-
- if (flags & SEQ_SPEED_INTEGRATE) {
- float cursor = 0;
- float facf;
-
- v->frameMap[0] = 0;
- v->lastValidFrame = 0;
-
- for (cfra = 1; cfra < v->length; cfra++) {
- if (fcu) {
- facf = evaluate_fcurve(fcu, seq->startdisp + cfra);
- }
- else {
- facf = fallback_fac;
- }
- facf *= v->globalSpeed;
-
- cursor += facf;
-
- if (cursor >= seq->seq1->len) {
- v->frameMap[cfra] = seq->seq1->len - 1;
- }
- else {
- v->frameMap[cfra] = cursor;
- v->lastValidFrame = cfra;
- }
- }
- }
- else {
- float facf;
-
- v->lastValidFrame = 0;
- for (cfra = 0; cfra < v->length; cfra++) {
-
- if (fcu) {
- facf = evaluate_fcurve(fcu, seq->startdisp + cfra);
- }
- else {
- facf = fallback_fac;
- }
-
- if (flags & SEQ_SPEED_COMPRESS_IPO_Y) {
- facf *= seq->seq1->len;
- }
- facf *= v->globalSpeed;
-
- if (facf >= seq->seq1->len) {
- facf = seq->seq1->len - 1;
- }
- else {
- v->lastValidFrame = cfra;
- }
- v->frameMap[cfra] = facf;
- }
- }
-}
-
-static ImBuf *do_speed_effect(
- const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra),
- float facf0, float facf1, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3)
-{
- ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3);
-
- if (out->rect_float) {
- do_cross_effect_float(
- facf0, facf1, context->rectx, context->recty,
- ibuf1->rect_float, ibuf2->rect_float, out->rect_float);
- }
- else {
- do_cross_effect_byte(
- facf0, facf1, context->rectx, context->recty,
- (unsigned char *) ibuf1->rect, (unsigned char *) ibuf2->rect, (unsigned char *) out->rect);
- }
- return out;
+ int cfra;
+ float fallback_fac = 1.0f;
+ SpeedControlVars *v = (SpeedControlVars *)seq->effectdata;
+ FCurve *fcu = NULL;
+ int flags = v->flags;
+
+ /* if not already done, load / initialize data */
+ BKE_sequence_get_effect(seq);
+
+ if ((force == false) && (seq->len == v->length) && (v->frameMap != NULL)) {
+ return;
+ }
+ if ((seq->seq1 == NULL) || (seq->len < 1)) {
+ /* make coverity happy and check for (CID 598) input strip ... */
+ return;
+ }
+
+ /* XXX - new in 2.5x. should we use the animation system this way?
+ * The fcurve is needed because many frames need evaluating at once - campbell */
+ fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "speed_factor", 0, NULL);
+
+ if (!v->frameMap || v->length != seq->len) {
+ if (v->frameMap)
+ MEM_freeN(v->frameMap);
+
+ v->length = seq->len;
+
+ v->frameMap = MEM_callocN(sizeof(float) * v->length, "speedcontrol frameMap");
+ }
+
+ fallback_fac = 1.0;
+
+ if (seq->flag & SEQ_USE_EFFECT_DEFAULT_FADE) {
+ if ((seq->seq1->enddisp != seq->seq1->start) && (seq->seq1->len != 0)) {
+ fallback_fac = (float)seq->seq1->len / (float)(seq->seq1->enddisp - seq->seq1->start);
+ flags = SEQ_SPEED_INTEGRATE;
+ fcu = NULL;
+ }
+ }
+ else {
+ /* if there is no fcurve, use value as simple multiplier */
+ if (!fcu) {
+ fallback_fac = seq->speed_fader; /* same as speed_factor in rna*/
+ }
+ }
+
+ if (flags & SEQ_SPEED_INTEGRATE) {
+ float cursor = 0;
+ float facf;
+
+ v->frameMap[0] = 0;
+ v->lastValidFrame = 0;
+
+ for (cfra = 1; cfra < v->length; cfra++) {
+ if (fcu) {
+ facf = evaluate_fcurve(fcu, seq->startdisp + cfra);
+ }
+ else {
+ facf = fallback_fac;
+ }
+ facf *= v->globalSpeed;
+
+ cursor += facf;
+
+ if (cursor >= seq->seq1->len) {
+ v->frameMap[cfra] = seq->seq1->len - 1;
+ }
+ else {
+ v->frameMap[cfra] = cursor;
+ v->lastValidFrame = cfra;
+ }
+ }
+ }
+ else {
+ float facf;
+
+ v->lastValidFrame = 0;
+ for (cfra = 0; cfra < v->length; cfra++) {
+
+ if (fcu) {
+ facf = evaluate_fcurve(fcu, seq->startdisp + cfra);
+ }
+ else {
+ facf = fallback_fac;
+ }
+
+ if (flags & SEQ_SPEED_COMPRESS_IPO_Y) {
+ facf *= seq->seq1->len;
+ }
+ facf *= v->globalSpeed;
+
+ if (facf >= seq->seq1->len) {
+ facf = seq->seq1->len - 1;
+ }
+ else {
+ v->lastValidFrame = cfra;
+ }
+ v->frameMap[cfra] = facf;
+ }
+ }
+}
+
+static ImBuf *do_speed_effect(const SeqRenderData *context,
+ Sequence *UNUSED(seq),
+ float UNUSED(cfra),
+ float facf0,
+ float facf1,
+ ImBuf *ibuf1,
+ ImBuf *ibuf2,
+ ImBuf *ibuf3)
+{
+ ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3);
+
+ if (out->rect_float) {
+ do_cross_effect_float(facf0,
+ facf1,
+ context->rectx,
+ context->recty,
+ ibuf1->rect_float,
+ ibuf2->rect_float,
+ out->rect_float);
+ }
+ else {
+ do_cross_effect_byte(facf0,
+ facf1,
+ context->rectx,
+ context->recty,
+ (unsigned char *)ibuf1->rect,
+ (unsigned char *)ibuf2->rect,
+ (unsigned char *)out->rect);
+ }
+ return out;
}
/*********************** overdrop *************************/
-static void do_overdrop_effect(
- const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra), float facf0, float facf1,
- ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), int start_line, int total_lines, ImBuf *out)
+static void do_overdrop_effect(const SeqRenderData *context,
+ Sequence *UNUSED(seq),
+ float UNUSED(cfra),
+ float facf0,
+ float facf1,
+ ImBuf *ibuf1,
+ ImBuf *ibuf2,
+ ImBuf *UNUSED(ibuf3),
+ int start_line,
+ int total_lines,
+ ImBuf *out)
{
- int x = context->rectx;
- int y = total_lines;
+ int x = context->rectx;
+ int y = total_lines;
- if (out->rect_float) {
- float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
+ if (out->rect_float) {
+ float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
- slice_get_float_buffers(context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
+ slice_get_float_buffers(
+ context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_drop_effect_float(facf0, facf1, x, y, rect1, rect2, rect_out);
- do_alphaover_effect_float(facf0, facf1, x, y, rect1, rect2, rect_out);
- }
- else {
- unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
+ do_drop_effect_float(facf0, facf1, x, y, rect1, rect2, rect_out);
+ do_alphaover_effect_float(facf0, facf1, x, y, rect1, rect2, rect_out);
+ }
+ else {
+ unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
- slice_get_byte_buffers(context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
+ slice_get_byte_buffers(
+ context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_drop_effect_byte(facf0, facf1, x, y, rect1, rect2, rect_out);
- do_alphaover_effect_byte(facf0, facf1, x, y, rect1, rect2, rect_out);
- }
+ do_drop_effect_byte(facf0, facf1, x, y, rect1, rect2, rect_out);
+ do_alphaover_effect_byte(facf0, facf1, x, y, rect1, rect2, rect_out);
+ }
}
/*********************** Gaussian Blur *************************/
@@ -2877,997 +3260,944 @@ static void do_overdrop_effect(
static void init_gaussian_blur_effect(Sequence *seq)
{
- if (seq->effectdata)
- MEM_freeN(seq->effectdata);
+ if (seq->effectdata)
+ MEM_freeN(seq->effectdata);
- seq->effectdata = MEM_callocN(sizeof(WipeVars), "wipevars");
+ seq->effectdata = MEM_callocN(sizeof(WipeVars), "wipevars");
}
static int num_inputs_gaussian_blur(void)
{
- return 1;
+ return 1;
}
static void free_gaussian_blur_effect(Sequence *seq, const bool UNUSED(do_id_user))
{
- if (seq->effectdata)
- MEM_freeN(seq->effectdata);
+ if (seq->effectdata)
+ MEM_freeN(seq->effectdata);
- seq->effectdata = NULL;
+ seq->effectdata = NULL;
}
static void copy_gaussian_blur_effect(Sequence *dst, Sequence *src, const int UNUSED(flag))
{
- dst->effectdata = MEM_dupallocN(src->effectdata);
+ dst->effectdata = MEM_dupallocN(src->effectdata);
}
static int early_out_gaussian_blur(Sequence *seq, float UNUSED(facf0), float UNUSED(facf1))
{
- GaussianBlurVars *data = seq->effectdata;
- if (data->size_x == 0.0f && data->size_y == 0) {
- return EARLY_USE_INPUT_1;
- }
- return EARLY_DO_EFFECT;
+ GaussianBlurVars *data = seq->effectdata;
+ if (data->size_x == 0.0f && data->size_y == 0) {
+ return EARLY_USE_INPUT_1;
+ }
+ return EARLY_DO_EFFECT;
}
/* TODO(sergey): De-duplicate with compositor. */
static float *make_gaussian_blur_kernel(float rad, int size)
{
- float *gausstab, sum, val;
- float fac;
- int i, n;
+ float *gausstab, sum, val;
+ float fac;
+ int i, n;
- n = 2 * size + 1;
+ n = 2 * size + 1;
- gausstab = (float *)MEM_mallocN(sizeof(float) * n, __func__);
+ gausstab = (float *)MEM_mallocN(sizeof(float) * n, __func__);
- sum = 0.0f;
- fac = (rad > 0.0f ? 1.0f / rad : 0.0f);
- for (i = -size; i <= size; i++) {
- val = RE_filter_value(R_FILTER_GAUSS, (float)i * fac);
- sum += val;
- gausstab[i + size] = val;
- }
+ sum = 0.0f;
+ fac = (rad > 0.0f ? 1.0f / rad : 0.0f);
+ for (i = -size; i <= size; i++) {
+ val = RE_filter_value(R_FILTER_GAUSS, (float)i * fac);
+ sum += val;
+ gausstab[i + size] = val;
+ }
- sum = 1.0f / sum;
- for (i = 0; i < n; i++)
- gausstab[i] *= sum;
+ sum = 1.0f / sum;
+ for (i = 0; i < n; i++)
+ gausstab[i] *= sum;
- return gausstab;
+ return gausstab;
}
-static void do_gaussian_blur_effect_byte_x(
- Sequence *seq,
- int start_line,
- int x, int y,
- int frame_width,
- int UNUSED(frame_height),
- unsigned char *rect,
- unsigned char *out)
+static void do_gaussian_blur_effect_byte_x(Sequence *seq,
+ int start_line,
+ int x,
+ int y,
+ int frame_width,
+ int UNUSED(frame_height),
+ unsigned char *rect,
+ unsigned char *out)
{
#define INDEX(_x, _y) (((_y) * (x) + (_x)) * 4)
- GaussianBlurVars *data = seq->effectdata;
- const int size_x = (int) (data->size_x + 0.5f);
- int i, j;
-
- /* Make gaussian weight table. */
- float *gausstab_x;
- gausstab_x = make_gaussian_blur_kernel(data->size_x, size_x);
-
- for (i = 0; i < y; ++i) {
- for (j = 0; j < x; ++j) {
- int out_index = INDEX(j, i);
- float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- float accum_weight = 0.0f;
-
- for (int current_x = j - size_x;
- current_x <= j + size_x;
- ++current_x)
- {
- if (current_x < 0 || current_x >= frame_width) {
- /* Out of bounds. */
- continue;
- }
- int index = INDEX(current_x, i + start_line);
- float weight = gausstab_x[current_x - j + size_x];
- accum[0] += rect[index] * weight;
- accum[1] += rect[index + 1] * weight;
- accum[2] += rect[index + 2] * weight;
- accum[3] += rect[index + 3] * weight;
- accum_weight += weight;
- }
-
- float inv_accum_weight = 1.0f / accum_weight;
- out[out_index + 0] = accum[0] * inv_accum_weight;
- out[out_index + 1] = accum[1] * inv_accum_weight;
- out[out_index + 2] = accum[2] * inv_accum_weight;
- out[out_index + 3] = accum[3] * inv_accum_weight;
- }
- }
-
- MEM_freeN(gausstab_x);
+ GaussianBlurVars *data = seq->effectdata;
+ const int size_x = (int)(data->size_x + 0.5f);
+ int i, j;
+
+ /* Make gaussian weight table. */
+ float *gausstab_x;
+ gausstab_x = make_gaussian_blur_kernel(data->size_x, size_x);
+
+ for (i = 0; i < y; ++i) {
+ for (j = 0; j < x; ++j) {
+ int out_index = INDEX(j, i);
+ float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ float accum_weight = 0.0f;
+
+ for (int current_x = j - size_x; current_x <= j + size_x; ++current_x) {
+ if (current_x < 0 || current_x >= frame_width) {
+ /* Out of bounds. */
+ continue;
+ }
+ int index = INDEX(current_x, i + start_line);
+ float weight = gausstab_x[current_x - j + size_x];
+ accum[0] += rect[index] * weight;
+ accum[1] += rect[index + 1] * weight;
+ accum[2] += rect[index + 2] * weight;
+ accum[3] += rect[index + 3] * weight;
+ accum_weight += weight;
+ }
+
+ float inv_accum_weight = 1.0f / accum_weight;
+ out[out_index + 0] = accum[0] * inv_accum_weight;
+ out[out_index + 1] = accum[1] * inv_accum_weight;
+ out[out_index + 2] = accum[2] * inv_accum_weight;
+ out[out_index + 3] = accum[3] * inv_accum_weight;
+ }
+ }
+
+ MEM_freeN(gausstab_x);
#undef INDEX
}
-static void do_gaussian_blur_effect_byte_y(
- Sequence *seq,
- int start_line,
- int x, int y,
- int UNUSED(frame_width),
- int frame_height,
- unsigned char *rect,
- unsigned char *out)
+static void do_gaussian_blur_effect_byte_y(Sequence *seq,
+ int start_line,
+ int x,
+ int y,
+ int UNUSED(frame_width),
+ int frame_height,
+ unsigned char *rect,
+ unsigned char *out)
{
#define INDEX(_x, _y) (((_y) * (x) + (_x)) * 4)
- GaussianBlurVars *data = seq->effectdata;
- const int size_y = (int) (data->size_y + 0.5f);
- int i, j;
-
- /* Make gaussian weight table. */
- float *gausstab_y;
- gausstab_y = make_gaussian_blur_kernel(data->size_y, size_y);
-
- for (i = 0; i < y; ++i) {
- for (j = 0; j < x; ++j) {
- int out_index = INDEX(j, i);
- float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- float accum_weight = 0.0f;
- for (int current_y = i - size_y;
- current_y <= i + size_y;
- ++current_y)
- {
- if (current_y < -start_line ||
- current_y + start_line >= frame_height)
- {
- /* Out of bounds. */
- continue;
- }
- int index = INDEX(j, current_y + start_line);
- float weight = gausstab_y[current_y - i + size_y];
- accum[0] += rect[index] * weight;
- accum[1] += rect[index + 1] * weight;
- accum[2] += rect[index + 2] * weight;
- accum[3] += rect[index + 3] * weight;
- accum_weight += weight;
- }
- float inv_accum_weight = 1.0f / accum_weight;
- out[out_index + 0] = accum[0] * inv_accum_weight;
- out[out_index + 1] = accum[1] * inv_accum_weight;
- out[out_index + 2] = accum[2] * inv_accum_weight;
- out[out_index + 3] = accum[3] * inv_accum_weight;
- }
- }
-
- MEM_freeN(gausstab_y);
+ GaussianBlurVars *data = seq->effectdata;
+ const int size_y = (int)(data->size_y + 0.5f);
+ int i, j;
+
+ /* Make gaussian weight table. */
+ float *gausstab_y;
+ gausstab_y = make_gaussian_blur_kernel(data->size_y, size_y);
+
+ for (i = 0; i < y; ++i) {
+ for (j = 0; j < x; ++j) {
+ int out_index = INDEX(j, i);
+ float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ float accum_weight = 0.0f;
+ for (int current_y = i - size_y; current_y <= i + size_y; ++current_y) {
+ if (current_y < -start_line || current_y + start_line >= frame_height) {
+ /* Out of bounds. */
+ continue;
+ }
+ int index = INDEX(j, current_y + start_line);
+ float weight = gausstab_y[current_y - i + size_y];
+ accum[0] += rect[index] * weight;
+ accum[1] += rect[index + 1] * weight;
+ accum[2] += rect[index + 2] * weight;
+ accum[3] += rect[index + 3] * weight;
+ accum_weight += weight;
+ }
+ float inv_accum_weight = 1.0f / accum_weight;
+ out[out_index + 0] = accum[0] * inv_accum_weight;
+ out[out_index + 1] = accum[1] * inv_accum_weight;
+ out[out_index + 2] = accum[2] * inv_accum_weight;
+ out[out_index + 3] = accum[3] * inv_accum_weight;
+ }
+ }
+
+ MEM_freeN(gausstab_y);
#undef INDEX
}
-static void do_gaussian_blur_effect_float_x(
- Sequence *seq,
- int start_line,
- int x, int y,
- int frame_width,
- int UNUSED(frame_height),
- float *rect,
- float *out)
+static void do_gaussian_blur_effect_float_x(Sequence *seq,
+ int start_line,
+ int x,
+ int y,
+ int frame_width,
+ int UNUSED(frame_height),
+ float *rect,
+ float *out)
{
#define INDEX(_x, _y) (((_y) * (x) + (_x)) * 4)
- GaussianBlurVars *data = seq->effectdata;
- const int size_x = (int) (data->size_x + 0.5f);
- int i, j;
-
- /* Make gaussian weight table. */
- float *gausstab_x;
- gausstab_x = make_gaussian_blur_kernel(data->size_x, size_x);
-
- for (i = 0; i < y; ++i) {
- for (j = 0; j < x; ++j) {
- int out_index = INDEX(j, i);
- float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- float accum_weight = 0.0f;
- for (int current_x = j - size_x;
- current_x <= j + size_x;
- ++current_x)
- {
- if (current_x < 0 || current_x >= frame_width) {
- /* Out of bounds. */
- continue;
- }
- int index = INDEX(current_x, i + start_line);
- float weight = gausstab_x[current_x - j + size_x];
- madd_v4_v4fl(accum, &rect[index], weight);
- accum_weight += weight;
- }
- mul_v4_v4fl(&out[out_index], accum, 1.0f / accum_weight);
- }
- }
-
- MEM_freeN(gausstab_x);
+ GaussianBlurVars *data = seq->effectdata;
+ const int size_x = (int)(data->size_x + 0.5f);
+ int i, j;
+
+ /* Make gaussian weight table. */
+ float *gausstab_x;
+ gausstab_x = make_gaussian_blur_kernel(data->size_x, size_x);
+
+ for (i = 0; i < y; ++i) {
+ for (j = 0; j < x; ++j) {
+ int out_index = INDEX(j, i);
+ float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ float accum_weight = 0.0f;
+ for (int current_x = j - size_x; current_x <= j + size_x; ++current_x) {
+ if (current_x < 0 || current_x >= frame_width) {
+ /* Out of bounds. */
+ continue;
+ }
+ int index = INDEX(current_x, i + start_line);
+ float weight = gausstab_x[current_x - j + size_x];
+ madd_v4_v4fl(accum, &rect[index], weight);
+ accum_weight += weight;
+ }
+ mul_v4_v4fl(&out[out_index], accum, 1.0f / accum_weight);
+ }
+ }
+
+ MEM_freeN(gausstab_x);
#undef INDEX
}
-static void do_gaussian_blur_effect_float_y(
- Sequence *seq,
- int start_line,
- int x, int y,
- int UNUSED(frame_width),
- int frame_height,
- float *rect,
- float *out)
+static void do_gaussian_blur_effect_float_y(Sequence *seq,
+ int start_line,
+ int x,
+ int y,
+ int UNUSED(frame_width),
+ int frame_height,
+ float *rect,
+ float *out)
{
#define INDEX(_x, _y) (((_y) * (x) + (_x)) * 4)
- GaussianBlurVars *data = seq->effectdata;
- const int size_y = (int) (data->size_y + 0.5f);
- int i, j;
-
- /* Make gaussian weight table. */
- float *gausstab_y;
- gausstab_y = make_gaussian_blur_kernel(data->size_y, size_y);
-
- for (i = 0; i < y; ++i) {
- for (j = 0; j < x; ++j) {
- int out_index = INDEX(j, i);
- float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- float accum_weight = 0.0f;
- for (int current_y = i - size_y;
- current_y <= i + size_y;
- ++current_y)
- {
- if (current_y < -start_line ||
- current_y + start_line >= frame_height)
- {
- /* Out of bounds. */
- continue;
- }
- int index = INDEX(j, current_y + start_line);
- float weight = gausstab_y[current_y - i + size_y];
- madd_v4_v4fl(accum, &rect[index], weight);
- accum_weight += weight;
- }
- mul_v4_v4fl(&out[out_index], accum, 1.0f / accum_weight);
- }
- }
-
- MEM_freeN(gausstab_y);
+ GaussianBlurVars *data = seq->effectdata;
+ const int size_y = (int)(data->size_y + 0.5f);
+ int i, j;
+
+ /* Make gaussian weight table. */
+ float *gausstab_y;
+ gausstab_y = make_gaussian_blur_kernel(data->size_y, size_y);
+
+ for (i = 0; i < y; ++i) {
+ for (j = 0; j < x; ++j) {
+ int out_index = INDEX(j, i);
+ float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ float accum_weight = 0.0f;
+ for (int current_y = i - size_y; current_y <= i + size_y; ++current_y) {
+ if (current_y < -start_line || current_y + start_line >= frame_height) {
+ /* Out of bounds. */
+ continue;
+ }
+ int index = INDEX(j, current_y + start_line);
+ float weight = gausstab_y[current_y - i + size_y];
+ madd_v4_v4fl(accum, &rect[index], weight);
+ accum_weight += weight;
+ }
+ mul_v4_v4fl(&out[out_index], accum, 1.0f / accum_weight);
+ }
+ }
+
+ MEM_freeN(gausstab_y);
#undef INDEX
}
-static void do_gaussian_blur_effect_x_cb(
- const SeqRenderData *context,
- Sequence *seq,
- ImBuf *ibuf,
- int start_line,
- int total_lines,
- ImBuf *out)
-{
- if (out->rect_float) {
- float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
-
- slice_get_float_buffers(
- context,
- ibuf,
- NULL,
- NULL,
- out,
- start_line,
- &rect1,
- &rect2,
- NULL,
- &rect_out);
-
- do_gaussian_blur_effect_float_x(
- seq,
- start_line,
- context->rectx,
- total_lines,
- context->rectx,
- context->recty,
- ibuf->rect_float,
- rect_out);
- }
- else {
- unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
-
- slice_get_byte_buffers(
- context,
- ibuf,
- NULL,
- NULL,
- out,
- start_line,
- &rect1,
- &rect2,
- NULL,
- &rect_out);
-
- do_gaussian_blur_effect_byte_x(
- seq,
- start_line,
- context->rectx,
- total_lines,
- context->rectx,
- context->recty,
- (unsigned char *) ibuf->rect,
- rect_out);
- }
-}
-
-static void do_gaussian_blur_effect_y_cb(
- const SeqRenderData *context,
- Sequence *seq,
- ImBuf *ibuf,
- int start_line,
- int total_lines,
- ImBuf *out)
-{
- if (out->rect_float) {
- float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
-
- slice_get_float_buffers(
- context,
- ibuf,
- NULL,
- NULL,
- out,
- start_line,
- &rect1,
- &rect2,
- NULL,
- &rect_out);
-
- do_gaussian_blur_effect_float_y(
- seq,
- start_line,
- context->rectx,
- total_lines,
- context->rectx,
- context->recty,
- ibuf->rect_float,
- rect_out);
- }
- else {
- unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
-
- slice_get_byte_buffers(
- context,
- ibuf,
- NULL,
- NULL,
- out,
- start_line,
- &rect1,
- &rect2,
- NULL,
- &rect_out);
-
- do_gaussian_blur_effect_byte_y(
- seq,
- start_line,
- context->rectx,
- total_lines,
- context->rectx,
- context->recty,
- (unsigned char *) ibuf->rect,
- rect_out);
- }
+static void do_gaussian_blur_effect_x_cb(const SeqRenderData *context,
+ Sequence *seq,
+ ImBuf *ibuf,
+ int start_line,
+ int total_lines,
+ ImBuf *out)
+{
+ if (out->rect_float) {
+ float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
+
+ slice_get_float_buffers(
+ context, ibuf, NULL, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
+
+ do_gaussian_blur_effect_float_x(seq,
+ start_line,
+ context->rectx,
+ total_lines,
+ context->rectx,
+ context->recty,
+ ibuf->rect_float,
+ rect_out);
+ }
+ else {
+ unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
+
+ slice_get_byte_buffers(
+ context, ibuf, NULL, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
+
+ do_gaussian_blur_effect_byte_x(seq,
+ start_line,
+ context->rectx,
+ total_lines,
+ context->rectx,
+ context->recty,
+ (unsigned char *)ibuf->rect,
+ rect_out);
+ }
+}
+
+static void do_gaussian_blur_effect_y_cb(const SeqRenderData *context,
+ Sequence *seq,
+ ImBuf *ibuf,
+ int start_line,
+ int total_lines,
+ ImBuf *out)
+{
+ if (out->rect_float) {
+ float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
+
+ slice_get_float_buffers(
+ context, ibuf, NULL, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
+
+ do_gaussian_blur_effect_float_y(seq,
+ start_line,
+ context->rectx,
+ total_lines,
+ context->rectx,
+ context->recty,
+ ibuf->rect_float,
+ rect_out);
+ }
+ else {
+ unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
+
+ slice_get_byte_buffers(
+ context, ibuf, NULL, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
+
+ do_gaussian_blur_effect_byte_y(seq,
+ start_line,
+ context->rectx,
+ total_lines,
+ context->rectx,
+ context->recty,
+ (unsigned char *)ibuf->rect,
+ rect_out);
+ }
}
typedef struct RenderGaussianBlurEffectInitData {
- const SeqRenderData *context;
- Sequence *seq;
- ImBuf *ibuf;
- ImBuf *out;
+ const SeqRenderData *context;
+ Sequence *seq;
+ ImBuf *ibuf;
+ ImBuf *out;
} RenderGaussianBlurEffectInitData;
typedef struct RenderGaussianBlurEffectThread {
- const SeqRenderData *context;
- Sequence *seq;
- ImBuf *ibuf;
- ImBuf *out;
- int start_line, tot_line;
+ const SeqRenderData *context;
+ Sequence *seq;
+ ImBuf *ibuf;
+ ImBuf *out;
+ int start_line, tot_line;
} RenderGaussianBlurEffectThread;
-static void render_effect_execute_init_handle(
- void *handle_v,
- int start_line,
- int tot_line,
- void *init_data_v)
+static void render_effect_execute_init_handle(void *handle_v,
+ int start_line,
+ int tot_line,
+ void *init_data_v)
{
- RenderGaussianBlurEffectThread *handle = (RenderGaussianBlurEffectThread *) handle_v;
- RenderGaussianBlurEffectInitData *init_data = (RenderGaussianBlurEffectInitData *) init_data_v;
+ RenderGaussianBlurEffectThread *handle = (RenderGaussianBlurEffectThread *)handle_v;
+ RenderGaussianBlurEffectInitData *init_data = (RenderGaussianBlurEffectInitData *)init_data_v;
- handle->context = init_data->context;
- handle->seq = init_data->seq;
- handle->ibuf = init_data->ibuf;
- handle->out = init_data->out;
+ handle->context = init_data->context;
+ handle->seq = init_data->seq;
+ handle->ibuf = init_data->ibuf;
+ handle->out = init_data->out;
- handle->start_line = start_line;
- handle->tot_line = tot_line;
+ handle->start_line = start_line;
+ handle->tot_line = tot_line;
}
static void *render_effect_execute_do_x_thread(void *thread_data_v)
{
- RenderGaussianBlurEffectThread *thread_data = (RenderGaussianBlurEffectThread *) thread_data_v;
- do_gaussian_blur_effect_x_cb(
- thread_data->context,
- thread_data->seq,
- thread_data->ibuf,
- thread_data->start_line,
- thread_data->tot_line,
- thread_data->out);
- return NULL;
+ RenderGaussianBlurEffectThread *thread_data = (RenderGaussianBlurEffectThread *)thread_data_v;
+ do_gaussian_blur_effect_x_cb(thread_data->context,
+ thread_data->seq,
+ thread_data->ibuf,
+ thread_data->start_line,
+ thread_data->tot_line,
+ thread_data->out);
+ return NULL;
}
static void *render_effect_execute_do_y_thread(void *thread_data_v)
{
- RenderGaussianBlurEffectThread *thread_data = (RenderGaussianBlurEffectThread *) thread_data_v;
- do_gaussian_blur_effect_y_cb(
- thread_data->context,
- thread_data->seq,
- thread_data->ibuf,
- thread_data->start_line,
- thread_data->tot_line,
- thread_data->out);
+ RenderGaussianBlurEffectThread *thread_data = (RenderGaussianBlurEffectThread *)thread_data_v;
+ do_gaussian_blur_effect_y_cb(thread_data->context,
+ thread_data->seq,
+ thread_data->ibuf,
+ thread_data->start_line,
+ thread_data->tot_line,
+ thread_data->out);
- return NULL;
+ return NULL;
}
-static ImBuf *do_gaussian_blur_effect(
- const SeqRenderData *context,
- Sequence *seq,
- float UNUSED(cfra),
- float UNUSED(facf0),
- float UNUSED(facf1),
- ImBuf *ibuf1,
- ImBuf *UNUSED(ibuf2),
- ImBuf *UNUSED(ibuf3))
+static ImBuf *do_gaussian_blur_effect(const SeqRenderData *context,
+ Sequence *seq,
+ float UNUSED(cfra),
+ float UNUSED(facf0),
+ float UNUSED(facf1),
+ ImBuf *ibuf1,
+ ImBuf *UNUSED(ibuf2),
+ ImBuf *UNUSED(ibuf3))
{
- ImBuf *out = prepare_effect_imbufs(context, ibuf1, NULL, NULL);
+ ImBuf *out = prepare_effect_imbufs(context, ibuf1, NULL, NULL);
- RenderGaussianBlurEffectInitData init_data;
+ RenderGaussianBlurEffectInitData init_data;
- init_data.context = context;
- init_data.seq = seq;
- init_data.ibuf = ibuf1;
- init_data.out = out;
+ init_data.context = context;
+ init_data.seq = seq;
+ init_data.ibuf = ibuf1;
+ init_data.out = out;
- IMB_processor_apply_threaded(
- out->y,
- sizeof(RenderGaussianBlurEffectThread),
- &init_data,
- render_effect_execute_init_handle,
- render_effect_execute_do_x_thread);
+ IMB_processor_apply_threaded(out->y,
+ sizeof(RenderGaussianBlurEffectThread),
+ &init_data,
+ render_effect_execute_init_handle,
+ render_effect_execute_do_x_thread);
- ibuf1 = out;
- init_data.ibuf = ibuf1;
- out = prepare_effect_imbufs(context, ibuf1, NULL, NULL);
- init_data.out = out;
+ ibuf1 = out;
+ init_data.ibuf = ibuf1;
+ out = prepare_effect_imbufs(context, ibuf1, NULL, NULL);
+ init_data.out = out;
- IMB_processor_apply_threaded(
- out->y,
- sizeof(RenderGaussianBlurEffectThread),
- &init_data,
- render_effect_execute_init_handle,
- render_effect_execute_do_y_thread);
+ IMB_processor_apply_threaded(out->y,
+ sizeof(RenderGaussianBlurEffectThread),
+ &init_data,
+ render_effect_execute_init_handle,
+ render_effect_execute_do_y_thread);
- IMB_freeImBuf(ibuf1);
+ IMB_freeImBuf(ibuf1);
- return out;
+ return out;
}
/*********************** text *************************/
static void init_text_effect(Sequence *seq)
{
- TextVars *data;
+ TextVars *data;
- if (seq->effectdata)
- MEM_freeN(seq->effectdata);
+ if (seq->effectdata)
+ MEM_freeN(seq->effectdata);
- data = seq->effectdata = MEM_callocN(sizeof(TextVars), "textvars");
- data->text_font = NULL;
- data->text_blf_id = -1;
- data->text_size = 30;
+ data = seq->effectdata = MEM_callocN(sizeof(TextVars), "textvars");
+ data->text_font = NULL;
+ data->text_blf_id = -1;
+ data->text_size = 30;
- copy_v4_fl(data->color, 1.0f);
- data->shadow_color[3] = 1.0f;
+ copy_v4_fl(data->color, 1.0f);
+ data->shadow_color[3] = 1.0f;
- BLI_strncpy(data->text, "Text", sizeof(data->text));
+ BLI_strncpy(data->text, "Text", sizeof(data->text));
- data->loc[0] = 0.5f;
- data->align = SEQ_TEXT_ALIGN_X_CENTER;
- data->align_y = SEQ_TEXT_ALIGN_Y_BOTTOM;
+ data->loc[0] = 0.5f;
+ data->align = SEQ_TEXT_ALIGN_X_CENTER;
+ data->align_y = SEQ_TEXT_ALIGN_Y_BOTTOM;
}
void BKE_sequencer_text_font_unload(TextVars *data, const bool do_id_user)
{
- if (data) {
- /* Unlink the VFont */
- if (do_id_user && data->text_font != NULL) {
- id_us_min(&data->text_font->id);
- data->text_font = NULL;
- }
+ if (data) {
+ /* Unlink the VFont */
+ if (do_id_user && data->text_font != NULL) {
+ id_us_min(&data->text_font->id);
+ data->text_font = NULL;
+ }
- /* Unload the BLF font. */
- if (data->text_blf_id >= 0) {
- BLF_unload_id(data->text_blf_id);
- }
- }
+ /* Unload the BLF font. */
+ if (data->text_blf_id >= 0) {
+ BLF_unload_id(data->text_blf_id);
+ }
+ }
}
void BKE_sequencer_text_font_load(TextVars *data, const bool do_id_user)
{
- if (data->text_font != NULL) {
- if (do_id_user) {
- id_us_plus(&data->text_font->id);
- }
+ if (data->text_font != NULL) {
+ if (do_id_user) {
+ id_us_plus(&data->text_font->id);
+ }
- char path[FILE_MAX];
- STRNCPY(path, data->text_font->name);
- BLI_assert(BLI_thread_is_main());
- BLI_path_abs(path, BKE_main_blendfile_path_from_global());
+ char path[FILE_MAX];
+ STRNCPY(path, data->text_font->name);
+ BLI_assert(BLI_thread_is_main());
+ BLI_path_abs(path, BKE_main_blendfile_path_from_global());
- data->text_blf_id = BLF_load(path);
- }
+ data->text_blf_id = BLF_load(path);
+ }
}
static void free_text_effect(Sequence *seq, const bool do_id_user)
{
- TextVars *data = seq->effectdata;
- BKE_sequencer_text_font_unload(data, do_id_user);
+ TextVars *data = seq->effectdata;
+ BKE_sequencer_text_font_unload(data, do_id_user);
- if (data) {
- MEM_freeN(data);
- seq->effectdata = NULL;
- }
+ if (data) {
+ MEM_freeN(data);
+ seq->effectdata = NULL;
+ }
}
static void load_text_effect(Sequence *seq)
{
- TextVars *data = seq->effectdata;
- BKE_sequencer_text_font_load(data, false);
+ TextVars *data = seq->effectdata;
+ BKE_sequencer_text_font_load(data, false);
}
static void copy_text_effect(Sequence *dst, Sequence *src, const int flag)
{
- dst->effectdata = MEM_dupallocN(src->effectdata);
- TextVars *data = dst->effectdata;
+ dst->effectdata = MEM_dupallocN(src->effectdata);
+ TextVars *data = dst->effectdata;
- data->text_blf_id = -1;
- BKE_sequencer_text_font_load(data, (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0);
+ data->text_blf_id = -1;
+ BKE_sequencer_text_font_load(data, (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0);
}
static int num_inputs_text(void)
{
- return 0;
+ return 0;
}
static int early_out_text(Sequence *seq, float UNUSED(facf0), float UNUSED(facf1))
{
- TextVars *data = seq->effectdata;
- if (data->text[0] == 0 || data->text_size < 1 ||
- ((data->color[3] == 0.0f) && (data->shadow_color[3] == 0.0f || (data->flag & SEQ_TEXT_SHADOW) == 0)))
- {
- return EARLY_USE_INPUT_1;
- }
- return EARLY_NO_INPUT;
-}
-
-static ImBuf *do_text_effect(
- const SeqRenderData *context, Sequence *seq, float UNUSED(cfra), float UNUSED(facf0), float UNUSED(facf1),
- ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3)
-{
- ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3);
- TextVars *data = seq->effectdata;
- int width = out->x;
- int height = out->y;
- struct ColorManagedDisplay *display;
- const char *display_device;
- int font = blf_mono_font_render;
- int line_height;
- int y_ofs, x, y;
- float proxy_size_comp;
-
- if (data->text_blf_id == SEQ_FONT_NOT_LOADED) {
- data->text_blf_id = -1;
-
- if (data->text_font) {
- data->text_blf_id = BLF_load(data->text_font->name);
- }
- }
-
- if (data->text_blf_id >= 0) {
- font = data->text_blf_id;
- }
-
- display_device = context->scene->display_settings.display_device;
- display = IMB_colormanagement_display_get_named(display_device);
-
- /* Compensate text size for preview render size. */
- if (ELEM(context->preview_render_size, SEQ_PROXY_RENDER_SIZE_SCENE, SEQ_PROXY_RENDER_SIZE_FULL)) {
- proxy_size_comp = context->scene->r.size / 100.0f;
- }
- else if (context->preview_render_size == SEQ_PROXY_RENDER_SIZE_100) {
- proxy_size_comp = 1.0f;
- }
- else {
- proxy_size_comp = context->preview_render_size / 100.0f;
- }
-
- /* set before return */
- BLF_size(font, proxy_size_comp * data->text_size, 72);
-
- BLF_enable(font, BLF_WORD_WRAP);
-
- /* use max width to enable newlines only */
- BLF_wordwrap(font, (data->wrap_width != 0.0f) ? data->wrap_width * width : -1);
-
- BLF_buffer(font, out->rect_float, (unsigned char *)out->rect, width, height, out->channels, display);
-
- line_height = BLF_height_max(font);
-
- y_ofs = -BLF_descender(font);
-
- x = (data->loc[0] * width);
- y = (data->loc[1] * height) + y_ofs;
-
- if ((data->align == SEQ_TEXT_ALIGN_X_LEFT) &&
- (data->align_y == SEQ_TEXT_ALIGN_Y_TOP))
- {
- y -= line_height;
- }
- else {
- /* vars for calculating wordwrap */
- struct {
- struct ResultBLF info;
- rctf rect;
- } wrap;
-
- BLF_boundbox_ex(font, data->text, sizeof(data->text), &wrap.rect, &wrap.info);
-
- if (data->align == SEQ_TEXT_ALIGN_X_RIGHT) {
- x -= BLI_rctf_size_x(&wrap.rect);
- }
- else if (data->align == SEQ_TEXT_ALIGN_X_CENTER) {
- x -= BLI_rctf_size_x(&wrap.rect) / 2;
- }
-
- if (data->align_y == SEQ_TEXT_ALIGN_Y_TOP) {
- y -= line_height;
- }
- else if (data->align_y == SEQ_TEXT_ALIGN_Y_BOTTOM) {
- y += (wrap.info.lines - 1) * line_height;
- }
- else if (data->align_y == SEQ_TEXT_ALIGN_Y_CENTER) {
- y += (((wrap.info.lines - 1) / 2) * line_height) - (line_height / 2);
- }
- }
-
- /* BLF_SHADOW won't work with buffers, instead use cheap shadow trick */
- if (data->flag & SEQ_TEXT_SHADOW) {
- int fontx, fonty;
- fontx = BLF_width_max(font);
- fonty = line_height;
- BLF_position(font, x + max_ii(fontx / 25, 1), y + max_ii(fonty / 25, 1), 0.0f);
- BLF_buffer_col(font, data->shadow_color);
- BLF_draw_buffer(font, data->text, BLF_DRAW_STR_DUMMY_MAX);
- }
-
- BLF_position(font, x, y, 0.0f);
- BLF_buffer_col(font, data->color);
- BLF_draw_buffer(font, data->text, BLF_DRAW_STR_DUMMY_MAX);
-
- BLF_buffer(font, NULL, NULL, 0, 0, 0, NULL);
-
- BLF_disable(font, BLF_WORD_WRAP);
-
- return out;
+ TextVars *data = seq->effectdata;
+ if (data->text[0] == 0 || data->text_size < 1 ||
+ ((data->color[3] == 0.0f) &&
+ (data->shadow_color[3] == 0.0f || (data->flag & SEQ_TEXT_SHADOW) == 0))) {
+ return EARLY_USE_INPUT_1;
+ }
+ return EARLY_NO_INPUT;
+}
+
+static ImBuf *do_text_effect(const SeqRenderData *context,
+ Sequence *seq,
+ float UNUSED(cfra),
+ float UNUSED(facf0),
+ float UNUSED(facf1),
+ ImBuf *ibuf1,
+ ImBuf *ibuf2,
+ ImBuf *ibuf3)
+{
+ ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3);
+ TextVars *data = seq->effectdata;
+ int width = out->x;
+ int height = out->y;
+ struct ColorManagedDisplay *display;
+ const char *display_device;
+ int font = blf_mono_font_render;
+ int line_height;
+ int y_ofs, x, y;
+ float proxy_size_comp;
+
+ if (data->text_blf_id == SEQ_FONT_NOT_LOADED) {
+ data->text_blf_id = -1;
+
+ if (data->text_font) {
+ data->text_blf_id = BLF_load(data->text_font->name);
+ }
+ }
+
+ if (data->text_blf_id >= 0) {
+ font = data->text_blf_id;
+ }
+
+ display_device = context->scene->display_settings.display_device;
+ display = IMB_colormanagement_display_get_named(display_device);
+
+ /* Compensate text size for preview render size. */
+ if (ELEM(
+ context->preview_render_size, SEQ_PROXY_RENDER_SIZE_SCENE, SEQ_PROXY_RENDER_SIZE_FULL)) {
+ proxy_size_comp = context->scene->r.size / 100.0f;
+ }
+ else if (context->preview_render_size == SEQ_PROXY_RENDER_SIZE_100) {
+ proxy_size_comp = 1.0f;
+ }
+ else {
+ proxy_size_comp = context->preview_render_size / 100.0f;
+ }
+
+ /* set before return */
+ BLF_size(font, proxy_size_comp * data->text_size, 72);
+
+ BLF_enable(font, BLF_WORD_WRAP);
+
+ /* use max width to enable newlines only */
+ BLF_wordwrap(font, (data->wrap_width != 0.0f) ? data->wrap_width * width : -1);
+
+ BLF_buffer(
+ font, out->rect_float, (unsigned char *)out->rect, width, height, out->channels, display);
+
+ line_height = BLF_height_max(font);
+
+ y_ofs = -BLF_descender(font);
+
+ x = (data->loc[0] * width);
+ y = (data->loc[1] * height) + y_ofs;
+
+ if ((data->align == SEQ_TEXT_ALIGN_X_LEFT) && (data->align_y == SEQ_TEXT_ALIGN_Y_TOP)) {
+ y -= line_height;
+ }
+ else {
+ /* vars for calculating wordwrap */
+ struct {
+ struct ResultBLF info;
+ rctf rect;
+ } wrap;
+
+ BLF_boundbox_ex(font, data->text, sizeof(data->text), &wrap.rect, &wrap.info);
+
+ if (data->align == SEQ_TEXT_ALIGN_X_RIGHT) {
+ x -= BLI_rctf_size_x(&wrap.rect);
+ }
+ else if (data->align == SEQ_TEXT_ALIGN_X_CENTER) {
+ x -= BLI_rctf_size_x(&wrap.rect) / 2;
+ }
+
+ if (data->align_y == SEQ_TEXT_ALIGN_Y_TOP) {
+ y -= line_height;
+ }
+ else if (data->align_y == SEQ_TEXT_ALIGN_Y_BOTTOM) {
+ y += (wrap.info.lines - 1) * line_height;
+ }
+ else if (data->align_y == SEQ_TEXT_ALIGN_Y_CENTER) {
+ y += (((wrap.info.lines - 1) / 2) * line_height) - (line_height / 2);
+ }
+ }
+
+ /* BLF_SHADOW won't work with buffers, instead use cheap shadow trick */
+ if (data->flag & SEQ_TEXT_SHADOW) {
+ int fontx, fonty;
+ fontx = BLF_width_max(font);
+ fonty = line_height;
+ BLF_position(font, x + max_ii(fontx / 25, 1), y + max_ii(fonty / 25, 1), 0.0f);
+ BLF_buffer_col(font, data->shadow_color);
+ BLF_draw_buffer(font, data->text, BLF_DRAW_STR_DUMMY_MAX);
+ }
+
+ BLF_position(font, x, y, 0.0f);
+ BLF_buffer_col(font, data->color);
+ BLF_draw_buffer(font, data->text, BLF_DRAW_STR_DUMMY_MAX);
+
+ BLF_buffer(font, NULL, NULL, 0, 0, 0, NULL);
+
+ BLF_disable(font, BLF_WORD_WRAP);
+
+ return out;
}
/*********************** sequence effect factory *************************/
static void init_noop(Sequence *UNUSED(seq))
{
-
}
static void load_noop(Sequence *UNUSED(seq))
{
-
}
static void free_noop(Sequence *UNUSED(seq), const bool UNUSED(do_id_user))
{
-
}
static int num_inputs_default(void)
{
- return 2;
+ return 2;
}
static void copy_effect_default(Sequence *dst, Sequence *src, const int UNUSED(flag))
{
- dst->effectdata = MEM_dupallocN(src->effectdata);
+ dst->effectdata = MEM_dupallocN(src->effectdata);
}
static void free_effect_default(Sequence *seq, const bool UNUSED(do_id_user))
{
- if (seq->effectdata)
- MEM_freeN(seq->effectdata);
+ if (seq->effectdata)
+ MEM_freeN(seq->effectdata);
- seq->effectdata = NULL;
+ seq->effectdata = NULL;
}
static int early_out_noop(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1))
{
- return EARLY_DO_EFFECT;
+ return EARLY_DO_EFFECT;
}
static int early_out_fade(Sequence *UNUSED(seq), float facf0, float facf1)
{
- if (facf0 == 0.0f && facf1 == 0.0f) {
- return EARLY_USE_INPUT_1;
- }
- else if (facf0 == 1.0f && facf1 == 1.0f) {
- return EARLY_USE_INPUT_2;
- }
- return EARLY_DO_EFFECT;
+ if (facf0 == 0.0f && facf1 == 0.0f) {
+ return EARLY_USE_INPUT_1;
+ }
+ else if (facf0 == 1.0f && facf1 == 1.0f) {
+ return EARLY_USE_INPUT_2;
+ }
+ return EARLY_DO_EFFECT;
}
static int early_out_mul_input2(Sequence *UNUSED(seq), float facf0, float facf1)
{
- if (facf0 == 0.0f && facf1 == 0.0f) {
- return EARLY_USE_INPUT_1;
- }
- return EARLY_DO_EFFECT;
+ if (facf0 == 0.0f && facf1 == 0.0f) {
+ return EARLY_USE_INPUT_1;
+ }
+ return EARLY_DO_EFFECT;
}
-static void store_icu_yrange_noop(Sequence *UNUSED(seq), short UNUSED(adrcode), float *UNUSED(ymin), float *UNUSED(ymax))
+static void store_icu_yrange_noop(Sequence *UNUSED(seq),
+ short UNUSED(adrcode),
+ float *UNUSED(ymin),
+ float *UNUSED(ymax))
{
- /* defaults are fine */
+ /* defaults are fine */
}
-static void get_default_fac_noop(Sequence *UNUSED(seq), float UNUSED(cfra), float *facf0, float *facf1)
+static void get_default_fac_noop(Sequence *UNUSED(seq),
+ float UNUSED(cfra),
+ float *facf0,
+ float *facf1)
{
- *facf0 = *facf1 = 1.0;
+ *facf0 = *facf1 = 1.0;
}
static void get_default_fac_fade(Sequence *seq, float cfra, float *facf0, float *facf1)
{
- *facf0 = (float)(cfra - seq->startdisp);
- *facf1 = (float)(*facf0 + 0.5f);
- *facf0 /= seq->len;
- *facf1 /= seq->len;
+ *facf0 = (float)(cfra - seq->startdisp);
+ *facf1 = (float)(*facf0 + 0.5f);
+ *facf0 /= seq->len;
+ *facf1 /= seq->len;
}
-static struct ImBuf *init_execution(const SeqRenderData *context, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3)
+static struct ImBuf *init_execution(const SeqRenderData *context,
+ ImBuf *ibuf1,
+ ImBuf *ibuf2,
+ ImBuf *ibuf3)
{
- ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3);
+ ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3);
- return out;
+ return out;
}
static struct SeqEffectHandle get_sequence_effect_impl(int seq_type)
{
- struct SeqEffectHandle rval;
- int sequence_type = seq_type;
-
- rval.multithreaded = false;
- rval.supports_mask = false;
- rval.init = init_noop;
- rval.num_inputs = num_inputs_default;
- rval.load = load_noop;
- rval.free = free_noop;
- rval.early_out = early_out_noop;
- rval.get_default_fac = get_default_fac_noop;
- rval.store_icu_yrange = store_icu_yrange_noop;
- rval.execute = NULL;
- rval.init_execution = init_execution;
- rval.execute_slice = NULL;
- rval.copy = NULL;
-
- switch (sequence_type) {
- case SEQ_TYPE_CROSS:
- rval.multithreaded = true;
- rval.execute_slice = do_cross_effect;
- rval.early_out = early_out_fade;
- rval.get_default_fac = get_default_fac_fade;
- break;
- case SEQ_TYPE_GAMCROSS:
- rval.multithreaded = true;
- rval.init = init_gammacross;
- rval.load = load_gammacross;
- rval.free = free_gammacross;
- rval.early_out = early_out_fade;
- rval.get_default_fac = get_default_fac_fade;
- rval.init_execution = gammacross_init_execution;
- rval.execute_slice = do_gammacross_effect;
- break;
- case SEQ_TYPE_ADD:
- rval.multithreaded = true;
- rval.execute_slice = do_add_effect;
- rval.early_out = early_out_mul_input2;
- break;
- case SEQ_TYPE_SUB:
- rval.multithreaded = true;
- rval.execute_slice = do_sub_effect;
- rval.early_out = early_out_mul_input2;
- break;
- case SEQ_TYPE_MUL:
- rval.multithreaded = true;
- rval.execute_slice = do_mul_effect;
- rval.early_out = early_out_mul_input2;
- break;
- case SEQ_TYPE_SCREEN:
- case SEQ_TYPE_OVERLAY:
- case SEQ_TYPE_BURN:
- case SEQ_TYPE_LINEAR_BURN:
- case SEQ_TYPE_DARKEN:
- case SEQ_TYPE_LIGHTEN:
- case SEQ_TYPE_DODGE:
- case SEQ_TYPE_SOFT_LIGHT:
- case SEQ_TYPE_HARD_LIGHT:
- case SEQ_TYPE_PIN_LIGHT:
- case SEQ_TYPE_LIN_LIGHT:
- case SEQ_TYPE_VIVID_LIGHT:
- case SEQ_TYPE_BLEND_COLOR:
- case SEQ_TYPE_HUE:
- case SEQ_TYPE_SATURATION:
- case SEQ_TYPE_VALUE:
- case SEQ_TYPE_DIFFERENCE:
- case SEQ_TYPE_EXCLUSION:
- rval.multithreaded = true;
- rval.execute_slice = do_blend_mode_effect;
- rval.early_out = early_out_mul_input2;
- break;
- case SEQ_TYPE_COLORMIX:
- rval.multithreaded = true;
- rval.init = init_colormix_effect;
- rval.free = free_effect_default;
- rval.copy = copy_effect_default;
- rval.execute_slice = do_colormix_effect;
- rval.early_out = early_out_mul_input2;
- break;
- case SEQ_TYPE_ALPHAOVER:
- rval.multithreaded = true;
- rval.init = init_alpha_over_or_under;
- rval.execute_slice = do_alphaover_effect;
- break;
- case SEQ_TYPE_OVERDROP:
- rval.multithreaded = true;
- rval.execute_slice = do_overdrop_effect;
- break;
- case SEQ_TYPE_ALPHAUNDER:
- rval.multithreaded = true;
- rval.init = init_alpha_over_or_under;
- rval.execute_slice = do_alphaunder_effect;
- break;
- case SEQ_TYPE_WIPE:
- rval.init = init_wipe_effect;
- rval.num_inputs = num_inputs_wipe;
- rval.free = free_wipe_effect;
- rval.copy = copy_wipe_effect;
- rval.early_out = early_out_fade;
- rval.get_default_fac = get_default_fac_fade;
- rval.execute = do_wipe_effect;
- break;
- case SEQ_TYPE_GLOW:
- rval.init = init_glow_effect;
- rval.num_inputs = num_inputs_glow;
- rval.free = free_glow_effect;
- rval.copy = copy_glow_effect;
- rval.execute = do_glow_effect;
- break;
- case SEQ_TYPE_TRANSFORM:
- rval.init = init_transform_effect;
- rval.num_inputs = num_inputs_transform;
- rval.free = free_transform_effect;
- rval.copy = copy_transform_effect;
- rval.execute = do_transform_effect;
- break;
- case SEQ_TYPE_SPEED:
- rval.init = init_speed_effect;
- rval.num_inputs = num_inputs_speed;
- rval.load = load_speed_effect;
- rval.free = free_speed_effect;
- rval.copy = copy_speed_effect;
- rval.execute = do_speed_effect;
- rval.early_out = early_out_speed;
- rval.store_icu_yrange = store_icu_yrange_speed;
- break;
- case SEQ_TYPE_COLOR:
- rval.init = init_solid_color;
- rval.num_inputs = num_inputs_color;
- rval.early_out = early_out_color;
- rval.free = free_solid_color;
- rval.copy = copy_solid_color;
- rval.execute = do_solid_color;
- break;
- case SEQ_TYPE_MULTICAM:
- rval.num_inputs = num_inputs_multicam;
- rval.early_out = early_out_multicam;
- rval.execute = do_multicam;
- break;
- case SEQ_TYPE_ADJUSTMENT:
- rval.supports_mask = true;
- rval.num_inputs = num_inputs_adjustment;
- rval.early_out = early_out_adjustment;
- rval.execute = do_adjustment;
- break;
- case SEQ_TYPE_GAUSSIAN_BLUR:
- rval.init = init_gaussian_blur_effect;
- rval.num_inputs = num_inputs_gaussian_blur;
- rval.free = free_gaussian_blur_effect;
- rval.copy = copy_gaussian_blur_effect;
- rval.early_out = early_out_gaussian_blur;
- rval.execute = do_gaussian_blur_effect;
- break;
- case SEQ_TYPE_TEXT:
- rval.num_inputs = num_inputs_text;
- rval.init = init_text_effect;
- rval.free = free_text_effect;
- rval.load = load_text_effect;
- rval.copy = copy_text_effect;
- rval.early_out = early_out_text;
- rval.execute = do_text_effect;
- break;
- }
-
- return rval;
+ struct SeqEffectHandle rval;
+ int sequence_type = seq_type;
+
+ rval.multithreaded = false;
+ rval.supports_mask = false;
+ rval.init = init_noop;
+ rval.num_inputs = num_inputs_default;
+ rval.load = load_noop;
+ rval.free = free_noop;
+ rval.early_out = early_out_noop;
+ rval.get_default_fac = get_default_fac_noop;
+ rval.store_icu_yrange = store_icu_yrange_noop;
+ rval.execute = NULL;
+ rval.init_execution = init_execution;
+ rval.execute_slice = NULL;
+ rval.copy = NULL;
+
+ switch (sequence_type) {
+ case SEQ_TYPE_CROSS:
+ rval.multithreaded = true;
+ rval.execute_slice = do_cross_effect;
+ rval.early_out = early_out_fade;
+ rval.get_default_fac = get_default_fac_fade;
+ break;
+ case SEQ_TYPE_GAMCROSS:
+ rval.multithreaded = true;
+ rval.init = init_gammacross;
+ rval.load = load_gammacross;
+ rval.free = free_gammacross;
+ rval.early_out = early_out_fade;
+ rval.get_default_fac = get_default_fac_fade;
+ rval.init_execution = gammacross_init_execution;
+ rval.execute_slice = do_gammacross_effect;
+ break;
+ case SEQ_TYPE_ADD:
+ rval.multithreaded = true;
+ rval.execute_slice = do_add_effect;
+ rval.early_out = early_out_mul_input2;
+ break;
+ case SEQ_TYPE_SUB:
+ rval.multithreaded = true;
+ rval.execute_slice = do_sub_effect;
+ rval.early_out = early_out_mul_input2;
+ break;
+ case SEQ_TYPE_MUL:
+ rval.multithreaded = true;
+ rval.execute_slice = do_mul_effect;
+ rval.early_out = early_out_mul_input2;
+ break;
+ case SEQ_TYPE_SCREEN:
+ case SEQ_TYPE_OVERLAY:
+ case SEQ_TYPE_BURN:
+ case SEQ_TYPE_LINEAR_BURN:
+ case SEQ_TYPE_DARKEN:
+ case SEQ_TYPE_LIGHTEN:
+ case SEQ_TYPE_DODGE:
+ case SEQ_TYPE_SOFT_LIGHT:
+ case SEQ_TYPE_HARD_LIGHT:
+ case SEQ_TYPE_PIN_LIGHT:
+ case SEQ_TYPE_LIN_LIGHT:
+ case SEQ_TYPE_VIVID_LIGHT:
+ case SEQ_TYPE_BLEND_COLOR:
+ case SEQ_TYPE_HUE:
+ case SEQ_TYPE_SATURATION:
+ case SEQ_TYPE_VALUE:
+ case SEQ_TYPE_DIFFERENCE:
+ case SEQ_TYPE_EXCLUSION:
+ rval.multithreaded = true;
+ rval.execute_slice = do_blend_mode_effect;
+ rval.early_out = early_out_mul_input2;
+ break;
+ case SEQ_TYPE_COLORMIX:
+ rval.multithreaded = true;
+ rval.init = init_colormix_effect;
+ rval.free = free_effect_default;
+ rval.copy = copy_effect_default;
+ rval.execute_slice = do_colormix_effect;
+ rval.early_out = early_out_mul_input2;
+ break;
+ case SEQ_TYPE_ALPHAOVER:
+ rval.multithreaded = true;
+ rval.init = init_alpha_over_or_under;
+ rval.execute_slice = do_alphaover_effect;
+ break;
+ case SEQ_TYPE_OVERDROP:
+ rval.multithreaded = true;
+ rval.execute_slice = do_overdrop_effect;
+ break;
+ case SEQ_TYPE_ALPHAUNDER:
+ rval.multithreaded = true;
+ rval.init = init_alpha_over_or_under;
+ rval.execute_slice = do_alphaunder_effect;
+ break;
+ case SEQ_TYPE_WIPE:
+ rval.init = init_wipe_effect;
+ rval.num_inputs = num_inputs_wipe;
+ rval.free = free_wipe_effect;
+ rval.copy = copy_wipe_effect;
+ rval.early_out = early_out_fade;
+ rval.get_default_fac = get_default_fac_fade;
+ rval.execute = do_wipe_effect;
+ break;
+ case SEQ_TYPE_GLOW:
+ rval.init = init_glow_effect;
+ rval.num_inputs = num_inputs_glow;
+ rval.free = free_glow_effect;
+ rval.copy = copy_glow_effect;
+ rval.execute = do_glow_effect;
+ break;
+ case SEQ_TYPE_TRANSFORM:
+ rval.init = init_transform_effect;
+ rval.num_inputs = num_inputs_transform;
+ rval.free = free_transform_effect;
+ rval.copy = copy_transform_effect;
+ rval.execute = do_transform_effect;
+ break;
+ case SEQ_TYPE_SPEED:
+ rval.init = init_speed_effect;
+ rval.num_inputs = num_inputs_speed;
+ rval.load = load_speed_effect;
+ rval.free = free_speed_effect;
+ rval.copy = copy_speed_effect;
+ rval.execute = do_speed_effect;
+ rval.early_out = early_out_speed;
+ rval.store_icu_yrange = store_icu_yrange_speed;
+ break;
+ case SEQ_TYPE_COLOR:
+ rval.init = init_solid_color;
+ rval.num_inputs = num_inputs_color;
+ rval.early_out = early_out_color;
+ rval.free = free_solid_color;
+ rval.copy = copy_solid_color;
+ rval.execute = do_solid_color;
+ break;
+ case SEQ_TYPE_MULTICAM:
+ rval.num_inputs = num_inputs_multicam;
+ rval.early_out = early_out_multicam;
+ rval.execute = do_multicam;
+ break;
+ case SEQ_TYPE_ADJUSTMENT:
+ rval.supports_mask = true;
+ rval.num_inputs = num_inputs_adjustment;
+ rval.early_out = early_out_adjustment;
+ rval.execute = do_adjustment;
+ break;
+ case SEQ_TYPE_GAUSSIAN_BLUR:
+ rval.init = init_gaussian_blur_effect;
+ rval.num_inputs = num_inputs_gaussian_blur;
+ rval.free = free_gaussian_blur_effect;
+ rval.copy = copy_gaussian_blur_effect;
+ rval.early_out = early_out_gaussian_blur;
+ rval.execute = do_gaussian_blur_effect;
+ break;
+ case SEQ_TYPE_TEXT:
+ rval.num_inputs = num_inputs_text;
+ rval.init = init_text_effect;
+ rval.free = free_text_effect;
+ rval.load = load_text_effect;
+ rval.copy = copy_text_effect;
+ rval.early_out = early_out_text;
+ rval.execute = do_text_effect;
+ break;
+ }
+
+ return rval;
}
struct SeqEffectHandle BKE_sequence_get_effect(Sequence *seq)
{
- struct SeqEffectHandle rval = {false, false, NULL};
+ struct SeqEffectHandle rval = {false, false, NULL};
- if (seq->type & SEQ_TYPE_EFFECT) {
- rval = get_sequence_effect_impl(seq->type);
- if ((seq->flag & SEQ_EFFECT_NOT_LOADED) != 0) {
- rval.load(seq);
- seq->flag &= ~SEQ_EFFECT_NOT_LOADED;
- }
- }
+ if (seq->type & SEQ_TYPE_EFFECT) {
+ rval = get_sequence_effect_impl(seq->type);
+ if ((seq->flag & SEQ_EFFECT_NOT_LOADED) != 0) {
+ rval.load(seq);
+ seq->flag &= ~SEQ_EFFECT_NOT_LOADED;
+ }
+ }
- return rval;
+ return rval;
}
struct SeqEffectHandle BKE_sequence_get_blend(Sequence *seq)
{
- struct SeqEffectHandle rval = {false, false, NULL};
+ struct SeqEffectHandle rval = {false, false, NULL};
- if (seq->blend_mode != 0) {
- if ((seq->flag & SEQ_EFFECT_NOT_LOADED) != 0) {
- /* load the effect first */
- rval = get_sequence_effect_impl(seq->type);
- rval.load(seq);
- }
+ if (seq->blend_mode != 0) {
+ if ((seq->flag & SEQ_EFFECT_NOT_LOADED) != 0) {
+ /* load the effect first */
+ rval = get_sequence_effect_impl(seq->type);
+ rval.load(seq);
+ }
- rval = get_sequence_effect_impl(seq->blend_mode);
- if ((seq->flag & SEQ_EFFECT_NOT_LOADED) != 0) {
- /* now load the blend and unset unloaded flag */
- rval.load(seq);
- seq->flag &= ~SEQ_EFFECT_NOT_LOADED;
- }
- }
+ rval = get_sequence_effect_impl(seq->blend_mode);
+ if ((seq->flag & SEQ_EFFECT_NOT_LOADED) != 0) {
+ /* now load the blend and unset unloaded flag */
+ rval.load(seq);
+ seq->flag &= ~SEQ_EFFECT_NOT_LOADED;
+ }
+ }
- return rval;
+ return rval;
}
int BKE_sequence_effect_get_num_inputs(int seq_type)
{
- struct SeqEffectHandle rval = get_sequence_effect_impl(seq_type);
+ struct SeqEffectHandle rval = get_sequence_effect_impl(seq_type);
- int cnt = rval.num_inputs();
- if (rval.execute || (rval.execute_slice && rval.init_execution)) {
- return cnt;
- }
- return 0;
+ int cnt = rval.num_inputs();
+ if (rval.execute || (rval.execute_slice && rval.init_execution)) {
+ return cnt;
+ }
+ return 0;
}
int BKE_sequence_effect_get_supports_mask(int seq_type)
{
- struct SeqEffectHandle rval = get_sequence_effect_impl(seq_type);
+ struct SeqEffectHandle rval = get_sequence_effect_impl(seq_type);
- return rval.supports_mask;
+ return rval.supports_mask;
}
diff --git a/source/blender/blenkernel/intern/seqmodifier.c b/source/blender/blenkernel/intern/seqmodifier.c
index ce0928f8ff1..29a5d556aef 100644
--- a/source/blender/blenkernel/intern/seqmodifier.c
+++ b/source/blender/blenkernel/intern/seqmodifier.c
@@ -49,611 +49,660 @@ static bool modifierTypesInit = false;
/*********************** Modifiers *************************/
-typedef void (*modifier_apply_threaded_cb) (int width, int height, unsigned char *rect, float *rect_float,
- unsigned char *mask_rect, float *mask_rect_float, void *data_v);
+typedef void (*modifier_apply_threaded_cb)(int width,
+ int height,
+ unsigned char *rect,
+ float *rect_float,
+ unsigned char *mask_rect,
+ float *mask_rect_float,
+ void *data_v);
typedef struct ModifierInitData {
- ImBuf *ibuf;
- ImBuf *mask;
- void *user_data;
+ ImBuf *ibuf;
+ ImBuf *mask;
+ void *user_data;
- modifier_apply_threaded_cb apply_callback;
+ modifier_apply_threaded_cb apply_callback;
} ModifierInitData;
typedef struct ModifierThread {
- int width, height;
+ int width, height;
- unsigned char *rect, *mask_rect;
- float *rect_float, *mask_rect_float;
+ unsigned char *rect, *mask_rect;
+ float *rect_float, *mask_rect_float;
- void *user_data;
+ void *user_data;
- modifier_apply_threaded_cb apply_callback;
+ modifier_apply_threaded_cb apply_callback;
} ModifierThread;
-
-static ImBuf *modifier_mask_get(SequenceModifierData *smd, const SeqRenderData *context, int cfra, int fra_offset, bool make_float)
+static ImBuf *modifier_mask_get(SequenceModifierData *smd,
+ const SeqRenderData *context,
+ int cfra,
+ int fra_offset,
+ bool make_float)
{
- return BKE_sequencer_render_mask_input(context, smd->mask_input_type, smd->mask_sequence, smd->mask_id, cfra, fra_offset, make_float);
+ return BKE_sequencer_render_mask_input(context,
+ smd->mask_input_type,
+ smd->mask_sequence,
+ smd->mask_id,
+ cfra,
+ fra_offset,
+ make_float);
}
static void modifier_init_handle(void *handle_v, int start_line, int tot_line, void *init_data_v)
{
- ModifierThread *handle = (ModifierThread *) handle_v;
- ModifierInitData *init_data = (ModifierInitData *) init_data_v;
- ImBuf *ibuf = init_data->ibuf;
- ImBuf *mask = init_data->mask;
+ ModifierThread *handle = (ModifierThread *)handle_v;
+ ModifierInitData *init_data = (ModifierInitData *)init_data_v;
+ ImBuf *ibuf = init_data->ibuf;
+ ImBuf *mask = init_data->mask;
- int offset = 4 * start_line * ibuf->x;
+ int offset = 4 * start_line * ibuf->x;
- memset(handle, 0, sizeof(ModifierThread));
+ memset(handle, 0, sizeof(ModifierThread));
- handle->width = ibuf->x;
- handle->height = tot_line;
- handle->apply_callback = init_data->apply_callback;
- handle->user_data = init_data->user_data;
+ handle->width = ibuf->x;
+ handle->height = tot_line;
+ handle->apply_callback = init_data->apply_callback;
+ handle->user_data = init_data->user_data;
- if (ibuf->rect)
- handle->rect = (unsigned char *) ibuf->rect + offset;
+ if (ibuf->rect)
+ handle->rect = (unsigned char *)ibuf->rect + offset;
- if (ibuf->rect_float)
- handle->rect_float = ibuf->rect_float + offset;
+ if (ibuf->rect_float)
+ handle->rect_float = ibuf->rect_float + offset;
- if (mask) {
- if (mask->rect)
- handle->mask_rect = (unsigned char *) mask->rect + offset;
+ if (mask) {
+ if (mask->rect)
+ handle->mask_rect = (unsigned char *)mask->rect + offset;
- if (mask->rect_float)
- handle->mask_rect_float = mask->rect_float + offset;
- }
- else {
- handle->mask_rect = NULL;
- handle->mask_rect_float = NULL;
- }
+ if (mask->rect_float)
+ handle->mask_rect_float = mask->rect_float + offset;
+ }
+ else {
+ handle->mask_rect = NULL;
+ handle->mask_rect_float = NULL;
+ }
}
static void *modifier_do_thread(void *thread_data_v)
{
- ModifierThread *td = (ModifierThread *) thread_data_v;
+ ModifierThread *td = (ModifierThread *)thread_data_v;
- td->apply_callback(td->width, td->height, td->rect, td->rect_float, td->mask_rect, td->mask_rect_float, td->user_data);
+ td->apply_callback(td->width,
+ td->height,
+ td->rect,
+ td->rect_float,
+ td->mask_rect,
+ td->mask_rect_float,
+ td->user_data);
- return NULL;
+ return NULL;
}
-static void modifier_apply_threaded(ImBuf *ibuf, ImBuf *mask, modifier_apply_threaded_cb apply_callback, void *user_data)
+static void modifier_apply_threaded(ImBuf *ibuf,
+ ImBuf *mask,
+ modifier_apply_threaded_cb apply_callback,
+ void *user_data)
{
- ModifierInitData init_data;
+ ModifierInitData init_data;
- init_data.ibuf = ibuf;
- init_data.mask = mask;
- init_data.user_data = user_data;
+ init_data.ibuf = ibuf;
+ init_data.mask = mask;
+ init_data.user_data = user_data;
- init_data.apply_callback = apply_callback;
+ init_data.apply_callback = apply_callback;
- IMB_processor_apply_threaded(ibuf->y, sizeof(ModifierThread), &init_data,
- modifier_init_handle, modifier_do_thread);
+ IMB_processor_apply_threaded(
+ ibuf->y, sizeof(ModifierThread), &init_data, modifier_init_handle, modifier_do_thread);
}
/* **** Color Balance Modifier **** */
static void colorBalance_init_data(SequenceModifierData *smd)
{
- ColorBalanceModifierData *cbmd = (ColorBalanceModifierData *) smd;
- int c;
+ ColorBalanceModifierData *cbmd = (ColorBalanceModifierData *)smd;
+ int c;
- cbmd->color_multiply = 1.0f;
+ cbmd->color_multiply = 1.0f;
- for (c = 0; c < 3; c++) {
- cbmd->color_balance.lift[c] = 1.0f;
- cbmd->color_balance.gamma[c] = 1.0f;
- cbmd->color_balance.gain[c] = 1.0f;
- }
+ for (c = 0; c < 3; c++) {
+ cbmd->color_balance.lift[c] = 1.0f;
+ cbmd->color_balance.gamma[c] = 1.0f;
+ cbmd->color_balance.gain[c] = 1.0f;
+ }
}
static void colorBalance_apply(SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
{
- ColorBalanceModifierData *cbmd = (ColorBalanceModifierData *) smd;
+ ColorBalanceModifierData *cbmd = (ColorBalanceModifierData *)smd;
- BKE_sequencer_color_balance_apply(&cbmd->color_balance, ibuf, cbmd->color_multiply, false, mask);
+ BKE_sequencer_color_balance_apply(&cbmd->color_balance, ibuf, cbmd->color_multiply, false, mask);
}
static SequenceModifierTypeInfo seqModifier_ColorBalance = {
- CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Color Balance"), /* name */
- "ColorBalanceModifierData", /* struct_name */
- sizeof(ColorBalanceModifierData), /* struct_size */
- colorBalance_init_data, /* init_data */
- NULL, /* free_data */
- NULL, /* copy_data */
- colorBalance_apply, /* apply */
+ CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Color Balance"), /* name */
+ "ColorBalanceModifierData", /* struct_name */
+ sizeof(ColorBalanceModifierData), /* struct_size */
+ colorBalance_init_data, /* init_data */
+ NULL, /* free_data */
+ NULL, /* copy_data */
+ colorBalance_apply, /* apply */
};
/* **** White Balance Modifier **** */
static void whiteBalance_init_data(SequenceModifierData *smd)
{
- WhiteBalanceModifierData *cbmd = (WhiteBalanceModifierData *) smd;
- copy_v3_fl(cbmd->white_value, 1.0f);
+ WhiteBalanceModifierData *cbmd = (WhiteBalanceModifierData *)smd;
+ copy_v3_fl(cbmd->white_value, 1.0f);
}
typedef struct WhiteBalanceThreadData {
- float white[3];
+ float white[3];
} WhiteBalanceThreadData;
-static void whiteBalance_apply_threaded(int width, int height, unsigned char *rect, float *rect_float,
- unsigned char *mask_rect, float *mask_rect_float, void *data_v)
+static void whiteBalance_apply_threaded(int width,
+ int height,
+ unsigned char *rect,
+ float *rect_float,
+ unsigned char *mask_rect,
+ float *mask_rect_float,
+ void *data_v)
{
- int x, y;
- float multiplier[3];
+ int x, y;
+ float multiplier[3];
- WhiteBalanceThreadData *data = (WhiteBalanceThreadData *) data_v;
+ WhiteBalanceThreadData *data = (WhiteBalanceThreadData *)data_v;
- multiplier[0] = (data->white[0] != 0.0f) ? 1.0f / data->white[0] : FLT_MAX;
- multiplier[1] = (data->white[1] != 0.0f) ? 1.0f / data->white[1] : FLT_MAX;
- multiplier[2] = (data->white[2] != 0.0f) ? 1.0f / data->white[2] : FLT_MAX;
+ multiplier[0] = (data->white[0] != 0.0f) ? 1.0f / data->white[0] : FLT_MAX;
+ multiplier[1] = (data->white[1] != 0.0f) ? 1.0f / data->white[1] : FLT_MAX;
+ multiplier[2] = (data->white[2] != 0.0f) ? 1.0f / data->white[2] : FLT_MAX;
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x++) {
- int pixel_index = (y * width + x) * 4;
- float rgba[4], result[4], mask[3] = {1.0f, 1.0f, 1.0f};
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ int pixel_index = (y * width + x) * 4;
+ float rgba[4], result[4], mask[3] = {1.0f, 1.0f, 1.0f};
- if (rect_float) {
- copy_v3_v3(rgba, rect_float + pixel_index);
- }
- else {
- straight_uchar_to_premul_float(rgba, rect + pixel_index);
- }
+ if (rect_float) {
+ copy_v3_v3(rgba, rect_float + pixel_index);
+ }
+ else {
+ straight_uchar_to_premul_float(rgba, rect + pixel_index);
+ }
- copy_v4_v4(result, rgba);
+ copy_v4_v4(result, rgba);
#if 0
- mul_v3_v3(result, multiplier);
+ mul_v3_v3(result, multiplier);
#else
- /* similar to division without the clipping */
- for (int i = 0; i < 3; i++) {
- result[i] = 1.0f - powf(1.0f - rgba[i], multiplier[i]);
- }
+ /* similar to division without the clipping */
+ for (int i = 0; i < 3; i++) {
+ result[i] = 1.0f - powf(1.0f - rgba[i], multiplier[i]);
+ }
#endif
- if (mask_rect_float) {
- copy_v3_v3(mask, mask_rect_float + pixel_index);
- }
- else if (mask_rect) {
- rgb_uchar_to_float(mask, mask_rect + pixel_index);
- }
-
- result[0] = rgba[0] * (1.0f - mask[0]) + result[0] * mask[0];
- result[1] = rgba[1] * (1.0f - mask[1]) + result[1] * mask[1];
- result[2] = rgba[2] * (1.0f - mask[2]) + result[2] * mask[2];
-
- if (rect_float) {
- copy_v3_v3(rect_float + pixel_index, result);
- }
- else {
- premul_float_to_straight_uchar(rect + pixel_index, result);
- }
- }
- }
+ if (mask_rect_float) {
+ copy_v3_v3(mask, mask_rect_float + pixel_index);
+ }
+ else if (mask_rect) {
+ rgb_uchar_to_float(mask, mask_rect + pixel_index);
+ }
+
+ result[0] = rgba[0] * (1.0f - mask[0]) + result[0] * mask[0];
+ result[1] = rgba[1] * (1.0f - mask[1]) + result[1] * mask[1];
+ result[2] = rgba[2] * (1.0f - mask[2]) + result[2] * mask[2];
+
+ if (rect_float) {
+ copy_v3_v3(rect_float + pixel_index, result);
+ }
+ else {
+ premul_float_to_straight_uchar(rect + pixel_index, result);
+ }
+ }
+ }
}
static void whiteBalance_apply(SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
{
- WhiteBalanceThreadData data;
- WhiteBalanceModifierData *wbmd = (WhiteBalanceModifierData *) smd;
+ WhiteBalanceThreadData data;
+ WhiteBalanceModifierData *wbmd = (WhiteBalanceModifierData *)smd;
- copy_v3_v3(data.white, wbmd->white_value);
+ copy_v3_v3(data.white, wbmd->white_value);
- modifier_apply_threaded(ibuf, mask, whiteBalance_apply_threaded, &data);
+ modifier_apply_threaded(ibuf, mask, whiteBalance_apply_threaded, &data);
}
static SequenceModifierTypeInfo seqModifier_WhiteBalance = {
- CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "White Balance"), /* name */
- "WhiteBalanceModifierData", /* struct_name */
- sizeof(WhiteBalanceModifierData), /* struct_size */
- whiteBalance_init_data, /* init_data */
- NULL, /* free_data */
- NULL, /* copy_data */
- whiteBalance_apply, /* apply */
+ CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "White Balance"), /* name */
+ "WhiteBalanceModifierData", /* struct_name */
+ sizeof(WhiteBalanceModifierData), /* struct_size */
+ whiteBalance_init_data, /* init_data */
+ NULL, /* free_data */
+ NULL, /* copy_data */
+ whiteBalance_apply, /* apply */
};
/* **** Curves Modifier **** */
static void curves_init_data(SequenceModifierData *smd)
{
- CurvesModifierData *cmd = (CurvesModifierData *) smd;
+ CurvesModifierData *cmd = (CurvesModifierData *)smd;
- curvemapping_set_defaults(&cmd->curve_mapping, 4, 0.0f, 0.0f, 1.0f, 1.0f);
+ curvemapping_set_defaults(&cmd->curve_mapping, 4, 0.0f, 0.0f, 1.0f, 1.0f);
}
static void curves_free_data(SequenceModifierData *smd)
{
- CurvesModifierData *cmd = (CurvesModifierData *) smd;
+ CurvesModifierData *cmd = (CurvesModifierData *)smd;
- curvemapping_free_data(&cmd->curve_mapping);
+ curvemapping_free_data(&cmd->curve_mapping);
}
static void curves_copy_data(SequenceModifierData *target, SequenceModifierData *smd)
{
- CurvesModifierData *cmd = (CurvesModifierData *) smd;
- CurvesModifierData *cmd_target = (CurvesModifierData *) target;
+ CurvesModifierData *cmd = (CurvesModifierData *)smd;
+ CurvesModifierData *cmd_target = (CurvesModifierData *)target;
- curvemapping_copy_data(&cmd_target->curve_mapping, &cmd->curve_mapping);
+ curvemapping_copy_data(&cmd_target->curve_mapping, &cmd->curve_mapping);
}
-static void curves_apply_threaded(int width, int height, unsigned char *rect, float *rect_float,
- unsigned char *mask_rect, float *mask_rect_float, void *data_v)
+static void curves_apply_threaded(int width,
+ int height,
+ unsigned char *rect,
+ float *rect_float,
+ unsigned char *mask_rect,
+ float *mask_rect_float,
+ void *data_v)
{
- CurveMapping *curve_mapping = (CurveMapping *) data_v;
- int x, y;
-
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x++) {
- int pixel_index = (y * width + x) * 4;
-
- if (rect_float) {
- float *pixel = rect_float + pixel_index;
- float result[3];
-
- curvemapping_evaluate_premulRGBF(curve_mapping, result, pixel);
-
- if (mask_rect_float) {
- const float *m = mask_rect_float + pixel_index;
-
- pixel[0] = pixel[0] * (1.0f - m[0]) + result[0] * m[0];
- pixel[1] = pixel[1] * (1.0f - m[1]) + result[1] * m[1];
- pixel[2] = pixel[2] * (1.0f - m[2]) + result[2] * m[2];
- }
- else {
- pixel[0] = result[0];
- pixel[1] = result[1];
- pixel[2] = result[2];
- }
- }
- if (rect) {
- unsigned char *pixel = rect + pixel_index;
- float result[3], tempc[4];
-
- straight_uchar_to_premul_float(tempc, pixel);
-
- curvemapping_evaluate_premulRGBF(curve_mapping, result, tempc);
-
- if (mask_rect) {
- float t[3];
-
- rgb_uchar_to_float(t, mask_rect + pixel_index);
-
- tempc[0] = tempc[0] * (1.0f - t[0]) + result[0] * t[0];
- tempc[1] = tempc[1] * (1.0f - t[1]) + result[1] * t[1];
- tempc[2] = tempc[2] * (1.0f - t[2]) + result[2] * t[2];
- }
- else {
- tempc[0] = result[0];
- tempc[1] = result[1];
- tempc[2] = result[2];
- }
-
- premul_float_to_straight_uchar(pixel, tempc);
- }
- }
- }
+ CurveMapping *curve_mapping = (CurveMapping *)data_v;
+ int x, y;
+
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ int pixel_index = (y * width + x) * 4;
+
+ if (rect_float) {
+ float *pixel = rect_float + pixel_index;
+ float result[3];
+
+ curvemapping_evaluate_premulRGBF(curve_mapping, result, pixel);
+
+ if (mask_rect_float) {
+ const float *m = mask_rect_float + pixel_index;
+
+ pixel[0] = pixel[0] * (1.0f - m[0]) + result[0] * m[0];
+ pixel[1] = pixel[1] * (1.0f - m[1]) + result[1] * m[1];
+ pixel[2] = pixel[2] * (1.0f - m[2]) + result[2] * m[2];
+ }
+ else {
+ pixel[0] = result[0];
+ pixel[1] = result[1];
+ pixel[2] = result[2];
+ }
+ }
+ if (rect) {
+ unsigned char *pixel = rect + pixel_index;
+ float result[3], tempc[4];
+
+ straight_uchar_to_premul_float(tempc, pixel);
+
+ curvemapping_evaluate_premulRGBF(curve_mapping, result, tempc);
+
+ if (mask_rect) {
+ float t[3];
+
+ rgb_uchar_to_float(t, mask_rect + pixel_index);
+
+ tempc[0] = tempc[0] * (1.0f - t[0]) + result[0] * t[0];
+ tempc[1] = tempc[1] * (1.0f - t[1]) + result[1] * t[1];
+ tempc[2] = tempc[2] * (1.0f - t[2]) + result[2] * t[2];
+ }
+ else {
+ tempc[0] = result[0];
+ tempc[1] = result[1];
+ tempc[2] = result[2];
+ }
+
+ premul_float_to_straight_uchar(pixel, tempc);
+ }
+ }
+ }
}
static void curves_apply(struct SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
{
- CurvesModifierData *cmd = (CurvesModifierData *) smd;
+ CurvesModifierData *cmd = (CurvesModifierData *)smd;
- float black[3] = {0.0f, 0.0f, 0.0f};
- float white[3] = {1.0f, 1.0f, 1.0f};
+ float black[3] = {0.0f, 0.0f, 0.0f};
+ float white[3] = {1.0f, 1.0f, 1.0f};
- curvemapping_initialize(&cmd->curve_mapping);
+ curvemapping_initialize(&cmd->curve_mapping);
- curvemapping_premultiply(&cmd->curve_mapping, 0);
- curvemapping_set_black_white(&cmd->curve_mapping, black, white);
+ curvemapping_premultiply(&cmd->curve_mapping, 0);
+ curvemapping_set_black_white(&cmd->curve_mapping, black, white);
- modifier_apply_threaded(ibuf, mask, curves_apply_threaded, &cmd->curve_mapping);
+ modifier_apply_threaded(ibuf, mask, curves_apply_threaded, &cmd->curve_mapping);
- curvemapping_premultiply(&cmd->curve_mapping, 1);
+ curvemapping_premultiply(&cmd->curve_mapping, 1);
}
static SequenceModifierTypeInfo seqModifier_Curves = {
- CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Curves"), /* name */
- "CurvesModifierData", /* struct_name */
- sizeof(CurvesModifierData), /* struct_size */
- curves_init_data, /* init_data */
- curves_free_data, /* free_data */
- curves_copy_data, /* copy_data */
- curves_apply, /* apply */
+ CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Curves"), /* name */
+ "CurvesModifierData", /* struct_name */
+ sizeof(CurvesModifierData), /* struct_size */
+ curves_init_data, /* init_data */
+ curves_free_data, /* free_data */
+ curves_copy_data, /* copy_data */
+ curves_apply, /* apply */
};
/* **** Hue Correct Modifier **** */
static void hue_correct_init_data(SequenceModifierData *smd)
{
- HueCorrectModifierData *hcmd = (HueCorrectModifierData *) smd;
- int c;
+ HueCorrectModifierData *hcmd = (HueCorrectModifierData *)smd;
+ int c;
- curvemapping_set_defaults(&hcmd->curve_mapping, 1, 0.0f, 0.0f, 1.0f, 1.0f);
- hcmd->curve_mapping.preset = CURVE_PRESET_MID9;
+ curvemapping_set_defaults(&hcmd->curve_mapping, 1, 0.0f, 0.0f, 1.0f, 1.0f);
+ hcmd->curve_mapping.preset = CURVE_PRESET_MID9;
- for (c = 0; c < 3; c++) {
- CurveMap *cuma = &hcmd->curve_mapping.cm[c];
+ for (c = 0; c < 3; c++) {
+ CurveMap *cuma = &hcmd->curve_mapping.cm[c];
- curvemap_reset(cuma, &hcmd->curve_mapping.clipr, hcmd->curve_mapping.preset, CURVEMAP_SLOPE_POSITIVE);
- }
+ curvemap_reset(
+ cuma, &hcmd->curve_mapping.clipr, hcmd->curve_mapping.preset, CURVEMAP_SLOPE_POSITIVE);
+ }
- /* default to showing Saturation */
- hcmd->curve_mapping.cur = 1;
+ /* default to showing Saturation */
+ hcmd->curve_mapping.cur = 1;
}
static void hue_correct_free_data(SequenceModifierData *smd)
{
- HueCorrectModifierData *hcmd = (HueCorrectModifierData *) smd;
+ HueCorrectModifierData *hcmd = (HueCorrectModifierData *)smd;
- curvemapping_free_data(&hcmd->curve_mapping);
+ curvemapping_free_data(&hcmd->curve_mapping);
}
static void hue_correct_copy_data(SequenceModifierData *target, SequenceModifierData *smd)
{
- HueCorrectModifierData *hcmd = (HueCorrectModifierData *) smd;
- HueCorrectModifierData *hcmd_target = (HueCorrectModifierData *) target;
+ HueCorrectModifierData *hcmd = (HueCorrectModifierData *)smd;
+ HueCorrectModifierData *hcmd_target = (HueCorrectModifierData *)target;
- curvemapping_copy_data(&hcmd_target->curve_mapping, &hcmd->curve_mapping);
+ curvemapping_copy_data(&hcmd_target->curve_mapping, &hcmd->curve_mapping);
}
-static void hue_correct_apply_threaded(int width, int height, unsigned char *rect, float *rect_float,
- unsigned char *mask_rect, float *mask_rect_float, void *data_v)
+static void hue_correct_apply_threaded(int width,
+ int height,
+ unsigned char *rect,
+ float *rect_float,
+ unsigned char *mask_rect,
+ float *mask_rect_float,
+ void *data_v)
{
- CurveMapping *curve_mapping = (CurveMapping *) data_v;
- int x, y;
-
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x++) {
- int pixel_index = (y * width + x) * 4;
- float pixel[3], result[3], mask[3] = {1.0f, 1.0f, 1.0f};
- float hsv[3], f;
-
- if (rect_float)
- copy_v3_v3(pixel, rect_float + pixel_index);
- else
- rgb_uchar_to_float(pixel, rect + pixel_index);
-
- rgb_to_hsv(pixel[0], pixel[1], pixel[2], hsv, hsv + 1, hsv + 2);
-
- /* adjust hue, scaling returned default 0.5 up to 1 */
- f = curvemapping_evaluateF(curve_mapping, 0, hsv[0]);
- hsv[0] += f - 0.5f;
-
- /* adjust saturation, scaling returned default 0.5 up to 1 */
- f = curvemapping_evaluateF(curve_mapping, 1, hsv[0]);
- hsv[1] *= (f * 2.0f);
-
- /* adjust value, scaling returned default 0.5 up to 1 */
- f = curvemapping_evaluateF(curve_mapping, 2, hsv[0]);
- hsv[2] *= (f * 2.f);
-
- hsv[0] = hsv[0] - floorf(hsv[0]); /* mod 1.0 */
- CLAMP(hsv[1], 0.0f, 1.0f);
-
- /* convert back to rgb */
- hsv_to_rgb(hsv[0], hsv[1], hsv[2], result, result + 1, result + 2);
-
- if (mask_rect_float)
- copy_v3_v3(mask, mask_rect_float + pixel_index);
- else if (mask_rect)
- rgb_uchar_to_float(mask, mask_rect + pixel_index);
-
- result[0] = pixel[0] * (1.0f - mask[0]) + result[0] * mask[0];
- result[1] = pixel[1] * (1.0f - mask[1]) + result[1] * mask[1];
- result[2] = pixel[2] * (1.0f - mask[2]) + result[2] * mask[2];
-
- if (rect_float)
- copy_v3_v3(rect_float + pixel_index, result);
- else
- rgb_float_to_uchar(rect + pixel_index, result);
- }
- }
+ CurveMapping *curve_mapping = (CurveMapping *)data_v;
+ int x, y;
+
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ int pixel_index = (y * width + x) * 4;
+ float pixel[3], result[3], mask[3] = {1.0f, 1.0f, 1.0f};
+ float hsv[3], f;
+
+ if (rect_float)
+ copy_v3_v3(pixel, rect_float + pixel_index);
+ else
+ rgb_uchar_to_float(pixel, rect + pixel_index);
+
+ rgb_to_hsv(pixel[0], pixel[1], pixel[2], hsv, hsv + 1, hsv + 2);
+
+ /* adjust hue, scaling returned default 0.5 up to 1 */
+ f = curvemapping_evaluateF(curve_mapping, 0, hsv[0]);
+ hsv[0] += f - 0.5f;
+
+ /* adjust saturation, scaling returned default 0.5 up to 1 */
+ f = curvemapping_evaluateF(curve_mapping, 1, hsv[0]);
+ hsv[1] *= (f * 2.0f);
+
+ /* adjust value, scaling returned default 0.5 up to 1 */
+ f = curvemapping_evaluateF(curve_mapping, 2, hsv[0]);
+ hsv[2] *= (f * 2.f);
+
+ hsv[0] = hsv[0] - floorf(hsv[0]); /* mod 1.0 */
+ CLAMP(hsv[1], 0.0f, 1.0f);
+
+ /* convert back to rgb */
+ hsv_to_rgb(hsv[0], hsv[1], hsv[2], result, result + 1, result + 2);
+
+ if (mask_rect_float)
+ copy_v3_v3(mask, mask_rect_float + pixel_index);
+ else if (mask_rect)
+ rgb_uchar_to_float(mask, mask_rect + pixel_index);
+
+ result[0] = pixel[0] * (1.0f - mask[0]) + result[0] * mask[0];
+ result[1] = pixel[1] * (1.0f - mask[1]) + result[1] * mask[1];
+ result[2] = pixel[2] * (1.0f - mask[2]) + result[2] * mask[2];
+
+ if (rect_float)
+ copy_v3_v3(rect_float + pixel_index, result);
+ else
+ rgb_float_to_uchar(rect + pixel_index, result);
+ }
+ }
}
static void hue_correct_apply(struct SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
{
- HueCorrectModifierData *hcmd = (HueCorrectModifierData *) smd;
+ HueCorrectModifierData *hcmd = (HueCorrectModifierData *)smd;
- curvemapping_initialize(&hcmd->curve_mapping);
+ curvemapping_initialize(&hcmd->curve_mapping);
- modifier_apply_threaded(ibuf, mask, hue_correct_apply_threaded, &hcmd->curve_mapping);
+ modifier_apply_threaded(ibuf, mask, hue_correct_apply_threaded, &hcmd->curve_mapping);
}
static SequenceModifierTypeInfo seqModifier_HueCorrect = {
- CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Hue Correct"), /* name */
- "HueCorrectModifierData", /* struct_name */
- sizeof(HueCorrectModifierData), /* struct_size */
- hue_correct_init_data, /* init_data */
- hue_correct_free_data, /* free_data */
- hue_correct_copy_data, /* copy_data */
- hue_correct_apply, /* apply */
+ CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Hue Correct"), /* name */
+ "HueCorrectModifierData", /* struct_name */
+ sizeof(HueCorrectModifierData), /* struct_size */
+ hue_correct_init_data, /* init_data */
+ hue_correct_free_data, /* free_data */
+ hue_correct_copy_data, /* copy_data */
+ hue_correct_apply, /* apply */
};
/* **** Bright/Contrast Modifier **** */
typedef struct BrightContrastThreadData {
- float bright;
- float contrast;
+ float bright;
+ float contrast;
} BrightContrastThreadData;
-static void brightcontrast_apply_threaded(int width, int height, unsigned char *rect, float *rect_float,
- unsigned char *mask_rect, float *mask_rect_float, void *data_v)
+static void brightcontrast_apply_threaded(int width,
+ int height,
+ unsigned char *rect,
+ float *rect_float,
+ unsigned char *mask_rect,
+ float *mask_rect_float,
+ void *data_v)
{
- BrightContrastThreadData *data = (BrightContrastThreadData *) data_v;
- int x, y;
-
- float i;
- int c;
- float a, b, v;
- float brightness = data->bright / 100.0f;
- float contrast = data->contrast;
- float delta = contrast / 200.0f;
-
- a = 1.0f - delta * 2.0f;
- /*
- * The algorithm is by Werner D. Streidt
- * (http://visca.com/ffactory/archives/5-99/msg00021.html)
- * Extracted of OpenCV demhist.c
- */
- if (contrast > 0) {
- a = 1.0f / a;
- b = a * (brightness - delta);
- }
- else {
- delta *= -1;
- b = a * (brightness + delta);
- }
-
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x++) {
- int pixel_index = (y * width + x) * 4;
-
- if (rect) {
- unsigned char *pixel = rect + pixel_index;
-
- for (c = 0; c < 3; c++) {
- i = (float) pixel[c] / 255.0f;
- v = a * i + b;
-
- if (mask_rect) {
- unsigned char *m = mask_rect + pixel_index;
- float t = (float) m[c] / 255.0f;
-
- v = (float) pixel[c] / 255.0f * (1.0f - t) + v * t;
- }
-
- pixel[c] = unit_float_to_uchar_clamp(v);
- }
- }
- else if (rect_float) {
- float *pixel = rect_float + pixel_index;
-
- for (c = 0; c < 3; c++) {
- i = pixel[c];
- v = a * i + b;
-
- if (mask_rect_float) {
- const float *m = mask_rect_float + pixel_index;
-
- pixel[c] = pixel[c] * (1.0f - m[c]) + v * m[c];
- }
- else
- pixel[c] = v;
- }
- }
- }
- }
+ BrightContrastThreadData *data = (BrightContrastThreadData *)data_v;
+ int x, y;
+
+ float i;
+ int c;
+ float a, b, v;
+ float brightness = data->bright / 100.0f;
+ float contrast = data->contrast;
+ float delta = contrast / 200.0f;
+
+ a = 1.0f - delta * 2.0f;
+ /*
+ * The algorithm is by Werner D. Streidt
+ * (http://visca.com/ffactory/archives/5-99/msg00021.html)
+ * Extracted of OpenCV demhist.c
+ */
+ if (contrast > 0) {
+ a = 1.0f / a;
+ b = a * (brightness - delta);
+ }
+ else {
+ delta *= -1;
+ b = a * (brightness + delta);
+ }
+
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ int pixel_index = (y * width + x) * 4;
+
+ if (rect) {
+ unsigned char *pixel = rect + pixel_index;
+
+ for (c = 0; c < 3; c++) {
+ i = (float)pixel[c] / 255.0f;
+ v = a * i + b;
+
+ if (mask_rect) {
+ unsigned char *m = mask_rect + pixel_index;
+ float t = (float)m[c] / 255.0f;
+
+ v = (float)pixel[c] / 255.0f * (1.0f - t) + v * t;
+ }
+
+ pixel[c] = unit_float_to_uchar_clamp(v);
+ }
+ }
+ else if (rect_float) {
+ float *pixel = rect_float + pixel_index;
+
+ for (c = 0; c < 3; c++) {
+ i = pixel[c];
+ v = a * i + b;
+
+ if (mask_rect_float) {
+ const float *m = mask_rect_float + pixel_index;
+
+ pixel[c] = pixel[c] * (1.0f - m[c]) + v * m[c];
+ }
+ else
+ pixel[c] = v;
+ }
+ }
+ }
+ }
}
static void brightcontrast_apply(struct SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
{
- BrightContrastModifierData *bcmd = (BrightContrastModifierData *) smd;
- BrightContrastThreadData data;
+ BrightContrastModifierData *bcmd = (BrightContrastModifierData *)smd;
+ BrightContrastThreadData data;
- data.bright = bcmd->bright;
- data.contrast = bcmd->contrast;
+ data.bright = bcmd->bright;
+ data.contrast = bcmd->contrast;
- modifier_apply_threaded(ibuf, mask, brightcontrast_apply_threaded, &data);
+ modifier_apply_threaded(ibuf, mask, brightcontrast_apply_threaded, &data);
}
static SequenceModifierTypeInfo seqModifier_BrightContrast = {
- CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Bright/Contrast"), /* name */
- "BrightContrastModifierData", /* struct_name */
- sizeof(BrightContrastModifierData), /* struct_size */
- NULL, /* init_data */
- NULL, /* free_data */
- NULL, /* copy_data */
- brightcontrast_apply, /* apply */
+ CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Bright/Contrast"), /* name */
+ "BrightContrastModifierData", /* struct_name */
+ sizeof(BrightContrastModifierData), /* struct_size */
+ NULL, /* init_data */
+ NULL, /* free_data */
+ NULL, /* copy_data */
+ brightcontrast_apply, /* apply */
};
/* **** Mask Modifier **** */
-static void maskmodifier_apply_threaded(int width, int height, unsigned char *rect, float *rect_float,
- unsigned char *mask_rect, float *mask_rect_float, void *UNUSED(data_v))
+static void maskmodifier_apply_threaded(int width,
+ int height,
+ unsigned char *rect,
+ float *rect_float,
+ unsigned char *mask_rect,
+ float *mask_rect_float,
+ void *UNUSED(data_v))
{
- int x, y;
-
- if (rect && !mask_rect)
- return;
-
- if (rect_float && !mask_rect_float)
- return;
-
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x++) {
- int pixel_index = (y * width + x) * 4;
-
- if (rect) {
- unsigned char *pixel = rect + pixel_index;
- unsigned char *mask_pixel = mask_rect + pixel_index;
- unsigned char mask = min_iii(mask_pixel[0], mask_pixel[1], mask_pixel[2]);
-
- /* byte buffer is straight, so only affect on alpha itself,
- * this is the only way to alpha-over byte strip after
- * applying mask modifier.
- */
- pixel[3] = (float)(pixel[3] * mask) / 255.0f;
- }
- else if (rect_float) {
- int c;
- float *pixel = rect_float + pixel_index;
- const float *mask_pixel = mask_rect_float + pixel_index;
- float mask = min_fff(mask_pixel[0], mask_pixel[1], mask_pixel[2]);
-
- /* float buffers are premultiplied, so need to premul color
- * as well to make it easy to alpha-over masted strip.
- */
- for (c = 0; c < 4; c++)
- pixel[c] = pixel[c] * mask;
- }
- }
- }
+ int x, y;
+
+ if (rect && !mask_rect)
+ return;
+
+ if (rect_float && !mask_rect_float)
+ return;
+
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ int pixel_index = (y * width + x) * 4;
+
+ if (rect) {
+ unsigned char *pixel = rect + pixel_index;
+ unsigned char *mask_pixel = mask_rect + pixel_index;
+ unsigned char mask = min_iii(mask_pixel[0], mask_pixel[1], mask_pixel[2]);
+
+ /* byte buffer is straight, so only affect on alpha itself,
+ * this is the only way to alpha-over byte strip after
+ * applying mask modifier.
+ */
+ pixel[3] = (float)(pixel[3] * mask) / 255.0f;
+ }
+ else if (rect_float) {
+ int c;
+ float *pixel = rect_float + pixel_index;
+ const float *mask_pixel = mask_rect_float + pixel_index;
+ float mask = min_fff(mask_pixel[0], mask_pixel[1], mask_pixel[2]);
+
+ /* float buffers are premultiplied, so need to premul color
+ * as well to make it easy to alpha-over masted strip.
+ */
+ for (c = 0; c < 4; c++)
+ pixel[c] = pixel[c] * mask;
+ }
+ }
+ }
}
static void maskmodifier_apply(struct SequenceModifierData *UNUSED(smd), ImBuf *ibuf, ImBuf *mask)
{
- // SequencerMaskModifierData *bcmd = (SequencerMaskModifierData *)smd;
+ // SequencerMaskModifierData *bcmd = (SequencerMaskModifierData *)smd;
- modifier_apply_threaded(ibuf, mask, maskmodifier_apply_threaded, NULL);
+ modifier_apply_threaded(ibuf, mask, maskmodifier_apply_threaded, NULL);
}
static SequenceModifierTypeInfo seqModifier_Mask = {
- CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Mask"), /* name */
- "SequencerMaskModifierData", /* struct_name */
- sizeof(SequencerMaskModifierData), /* struct_size */
- NULL, /* init_data */
- NULL, /* free_data */
- NULL, /* copy_data */
- maskmodifier_apply, /* apply */
+ CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Mask"), /* name */
+ "SequencerMaskModifierData", /* struct_name */
+ sizeof(SequencerMaskModifierData), /* struct_size */
+ NULL, /* init_data */
+ NULL, /* free_data */
+ NULL, /* copy_data */
+ maskmodifier_apply, /* apply */
};
/* **** Tonemap Modifier **** */
typedef struct AvgLogLum {
- SequencerTonemapModifierData *tmmd;
- struct ColorSpace *colorspace;
- float al;
- float auto_key;
- float lav;
- float cav[4];
- float igm;
+ SequencerTonemapModifierData *tmmd;
+ struct ColorSpace *colorspace;
+ float al;
+ float auto_key;
+ float lav;
+ float cav[4];
+ float igm;
} AvgLogLum;
static void tonemapmodifier_init_data(SequenceModifierData *smd)
{
- SequencerTonemapModifierData *tmmd = (SequencerTonemapModifierData *) smd;
- /* Same as tonemap compositor node. */
- tmmd->type = SEQ_TONEMAP_RD_PHOTORECEPTOR;
- tmmd->key = 0.18f;
- tmmd->offset = 1.0f;
- tmmd->gamma = 1.0f;
- tmmd->intensity = 0.0f;
- tmmd->contrast = 0.0f;
- tmmd->adaptation = 1.0f;
- tmmd->correction = 0.0f;
+ SequencerTonemapModifierData *tmmd = (SequencerTonemapModifierData *)smd;
+ /* Same as tonemap compositor node. */
+ tmmd->type = SEQ_TONEMAP_RD_PHOTORECEPTOR;
+ tmmd->key = 0.18f;
+ tmmd->offset = 1.0f;
+ tmmd->gamma = 1.0f;
+ tmmd->intensity = 0.0f;
+ tmmd->contrast = 0.0f;
+ tmmd->adaptation = 1.0f;
+ tmmd->correction = 0.0f;
}
static void tonemapmodifier_apply_threaded_simple(int width,
@@ -664,55 +713,55 @@ static void tonemapmodifier_apply_threaded_simple(int width,
float *mask_rect_float,
void *data_v)
{
- AvgLogLum *avg = (AvgLogLum *)data_v;
- for (int y = 0; y < height; y++) {
- for (int x = 0; x < width; x++) {
- int pixel_index = (y * width + x) * 4;
- float input[4], output[4], mask[3] = {1.0f, 1.0f, 1.0f};
- /* Get input value. */
- if (rect_float) {
- copy_v4_v4(input, &rect_float[pixel_index]);
- }
- else {
- straight_uchar_to_premul_float(input, &rect[pixel_index]);
- }
- IMB_colormanagement_colorspace_to_scene_linear_v3(input, avg->colorspace);
- copy_v4_v4(output, input);
- /* Get mask value. */
- if (mask_rect_float) {
- copy_v3_v3(mask, mask_rect_float + pixel_index);
- }
- else if (mask_rect) {
- rgb_uchar_to_float(mask, mask_rect + pixel_index);
- }
- /* Apply correction. */
- mul_v3_fl(output, avg->al);
- float dr = output[0] + avg->tmmd->offset;
- float dg = output[1] + avg->tmmd->offset;
- float db = output[2] + avg->tmmd->offset;
- output[0] /= ((dr == 0.0f) ? 1.0f : dr);
- output[1] /= ((dg == 0.0f) ? 1.0f : dg);
- output[2] /= ((db == 0.0f) ? 1.0f : db);
- const float igm = avg->igm;
- if (igm != 0.0f) {
- output[0] = powf(max_ff(output[0], 0.0f), igm);
- output[1] = powf(max_ff(output[1], 0.0f), igm);
- output[2] = powf(max_ff(output[2], 0.0f), igm);
- }
- /* Apply mask. */
- output[0] = input[0] * (1.0f - mask[0]) + output[0] * mask[0];
- output[1] = input[1] * (1.0f - mask[1]) + output[1] * mask[1];
- output[2] = input[2] * (1.0f - mask[2]) + output[2] * mask[2];
- /* Copy result back. */
- IMB_colormanagement_scene_linear_to_colorspace_v3(output, avg->colorspace);
- if (rect_float) {
- copy_v4_v4(&rect_float[pixel_index], output);
- }
- else {
- premul_float_to_straight_uchar(&rect[pixel_index], output);
- }
- }
- }
+ AvgLogLum *avg = (AvgLogLum *)data_v;
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ int pixel_index = (y * width + x) * 4;
+ float input[4], output[4], mask[3] = {1.0f, 1.0f, 1.0f};
+ /* Get input value. */
+ if (rect_float) {
+ copy_v4_v4(input, &rect_float[pixel_index]);
+ }
+ else {
+ straight_uchar_to_premul_float(input, &rect[pixel_index]);
+ }
+ IMB_colormanagement_colorspace_to_scene_linear_v3(input, avg->colorspace);
+ copy_v4_v4(output, input);
+ /* Get mask value. */
+ if (mask_rect_float) {
+ copy_v3_v3(mask, mask_rect_float + pixel_index);
+ }
+ else if (mask_rect) {
+ rgb_uchar_to_float(mask, mask_rect + pixel_index);
+ }
+ /* Apply correction. */
+ mul_v3_fl(output, avg->al);
+ float dr = output[0] + avg->tmmd->offset;
+ float dg = output[1] + avg->tmmd->offset;
+ float db = output[2] + avg->tmmd->offset;
+ output[0] /= ((dr == 0.0f) ? 1.0f : dr);
+ output[1] /= ((dg == 0.0f) ? 1.0f : dg);
+ output[2] /= ((db == 0.0f) ? 1.0f : db);
+ const float igm = avg->igm;
+ if (igm != 0.0f) {
+ output[0] = powf(max_ff(output[0], 0.0f), igm);
+ output[1] = powf(max_ff(output[1], 0.0f), igm);
+ output[2] = powf(max_ff(output[2], 0.0f), igm);
+ }
+ /* Apply mask. */
+ output[0] = input[0] * (1.0f - mask[0]) + output[0] * mask[0];
+ output[1] = input[1] * (1.0f - mask[1]) + output[1] * mask[1];
+ output[2] = input[2] * (1.0f - mask[2]) + output[2] * mask[2];
+ /* Copy result back. */
+ IMB_colormanagement_scene_linear_to_colorspace_v3(output, avg->colorspace);
+ if (rect_float) {
+ copy_v4_v4(&rect_float[pixel_index], output);
+ }
+ else {
+ premul_float_to_straight_uchar(&rect[pixel_index], output);
+ }
+ }
+ }
}
static void tonemapmodifier_apply_threaded_photoreceptor(int width,
@@ -723,132 +772,123 @@ static void tonemapmodifier_apply_threaded_photoreceptor(int width,
float *mask_rect_float,
void *data_v)
{
- AvgLogLum *avg = (AvgLogLum *)data_v;
- const float f = expf(-avg->tmmd->intensity);
- const float m = (avg->tmmd->contrast > 0.0f) ? avg->tmmd->contrast : (0.3f + 0.7f * powf(avg->auto_key, 1.4f));
- const float ic = 1.0f - avg->tmmd->correction, ia = 1.0f - avg->tmmd->adaptation;
- for (int y = 0; y < height; y++) {
- for (int x = 0; x < width; x++) {
- int pixel_index = (y * width + x) * 4;
- float input[4], output[4], mask[3] = {1.0f, 1.0f, 1.0f};
- /* Get input value. */
- if (rect_float) {
- copy_v4_v4(input, &rect_float[pixel_index]);
- }
- else {
- straight_uchar_to_premul_float(input, &rect[pixel_index]);
- }
- IMB_colormanagement_colorspace_to_scene_linear_v3(input, avg->colorspace);
- copy_v4_v4(output, input);
- /* Get mask value. */
- if (mask_rect_float) {
- copy_v3_v3(mask, mask_rect_float + pixel_index);
- }
- else if (mask_rect) {
- rgb_uchar_to_float(mask, mask_rect + pixel_index);
- }
- /* Apply correction. */
- const float L = IMB_colormanagement_get_luminance(output);
- float I_l = output[0] + ic * (L - output[0]);
- float I_g = avg->cav[0] + ic * (avg->lav - avg->cav[0]);
- float I_a = I_l + ia * (I_g - I_l);
- output[0] /= (output[0] + powf(f * I_a, m));
- I_l = output[1] + ic * (L - output[1]);
- I_g = avg->cav[1] + ic * (avg->lav - avg->cav[1]);
- I_a = I_l + ia * (I_g - I_l);
- output[1] /= (output[1] + powf(f * I_a, m));
- I_l = output[2] + ic * (L - output[2]);
- I_g = avg->cav[2] + ic * (avg->lav - avg->cav[2]);
- I_a = I_l + ia * (I_g - I_l);
- output[2] /= (output[2] + powf(f * I_a, m));
- /* Apply mask. */
- output[0] = input[0] * (1.0f - mask[0]) + output[0] * mask[0];
- output[1] = input[1] * (1.0f - mask[1]) + output[1] * mask[1];
- output[2] = input[2] * (1.0f - mask[2]) + output[2] * mask[2];
- /* Copy result back. */
- IMB_colormanagement_scene_linear_to_colorspace_v3(output, avg->colorspace);
- if (rect_float) {
- copy_v4_v4(&rect_float[pixel_index], output);
- }
- else {
- premul_float_to_straight_uchar(&rect[pixel_index], output);
- }
- }
- }
+ AvgLogLum *avg = (AvgLogLum *)data_v;
+ const float f = expf(-avg->tmmd->intensity);
+ const float m = (avg->tmmd->contrast > 0.0f) ? avg->tmmd->contrast :
+ (0.3f + 0.7f * powf(avg->auto_key, 1.4f));
+ const float ic = 1.0f - avg->tmmd->correction, ia = 1.0f - avg->tmmd->adaptation;
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ int pixel_index = (y * width + x) * 4;
+ float input[4], output[4], mask[3] = {1.0f, 1.0f, 1.0f};
+ /* Get input value. */
+ if (rect_float) {
+ copy_v4_v4(input, &rect_float[pixel_index]);
+ }
+ else {
+ straight_uchar_to_premul_float(input, &rect[pixel_index]);
+ }
+ IMB_colormanagement_colorspace_to_scene_linear_v3(input, avg->colorspace);
+ copy_v4_v4(output, input);
+ /* Get mask value. */
+ if (mask_rect_float) {
+ copy_v3_v3(mask, mask_rect_float + pixel_index);
+ }
+ else if (mask_rect) {
+ rgb_uchar_to_float(mask, mask_rect + pixel_index);
+ }
+ /* Apply correction. */
+ const float L = IMB_colormanagement_get_luminance(output);
+ float I_l = output[0] + ic * (L - output[0]);
+ float I_g = avg->cav[0] + ic * (avg->lav - avg->cav[0]);
+ float I_a = I_l + ia * (I_g - I_l);
+ output[0] /= (output[0] + powf(f * I_a, m));
+ I_l = output[1] + ic * (L - output[1]);
+ I_g = avg->cav[1] + ic * (avg->lav - avg->cav[1]);
+ I_a = I_l + ia * (I_g - I_l);
+ output[1] /= (output[1] + powf(f * I_a, m));
+ I_l = output[2] + ic * (L - output[2]);
+ I_g = avg->cav[2] + ic * (avg->lav - avg->cav[2]);
+ I_a = I_l + ia * (I_g - I_l);
+ output[2] /= (output[2] + powf(f * I_a, m));
+ /* Apply mask. */
+ output[0] = input[0] * (1.0f - mask[0]) + output[0] * mask[0];
+ output[1] = input[1] * (1.0f - mask[1]) + output[1] * mask[1];
+ output[2] = input[2] * (1.0f - mask[2]) + output[2] * mask[2];
+ /* Copy result back. */
+ IMB_colormanagement_scene_linear_to_colorspace_v3(output, avg->colorspace);
+ if (rect_float) {
+ copy_v4_v4(&rect_float[pixel_index], output);
+ }
+ else {
+ premul_float_to_straight_uchar(&rect[pixel_index], output);
+ }
+ }
+ }
}
-static void tonemapmodifier_apply(struct SequenceModifierData *smd,
- ImBuf *ibuf,
- ImBuf *mask)
+static void tonemapmodifier_apply(struct SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
{
- SequencerTonemapModifierData *tmmd = (SequencerTonemapModifierData *) smd;
- AvgLogLum data;
- data.tmmd = tmmd;
- data.colorspace = (ibuf->rect_float != NULL)
- ? ibuf->float_colorspace
- : ibuf->rect_colorspace;
- float lsum = 0.0f;
- int p = ibuf->x * ibuf->y;
- float *fp = ibuf->rect_float;
- unsigned char *cp = (unsigned char *)ibuf->rect;
- float avl, maxl = -FLT_MAX, minl = FLT_MAX;
- const float sc = 1.0f / p;
- float Lav = 0.f;
- float cav[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- while (p--) {
- float pixel[4];
- if (fp != NULL) {
- copy_v4_v4(pixel, fp);
- }
- else {
- straight_uchar_to_premul_float(pixel, cp);
- }
- IMB_colormanagement_colorspace_to_scene_linear_v3(pixel, data.colorspace);
- float L = IMB_colormanagement_get_luminance(pixel);
- Lav += L;
- add_v3_v3(cav, pixel);
- lsum += logf(max_ff(L, 0.0f) + 1e-5f);
- maxl = (L > maxl) ? L : maxl;
- minl = (L < minl) ? L : minl;
- if (fp != NULL) {
- fp += 4;
- }
- else {
- cp += 4;
- }
- }
- data.lav = Lav * sc;
- mul_v3_v3fl(data.cav, cav, sc);
- maxl = logf(maxl + 1e-5f);
- minl = logf(minl + 1e-5f);
- avl = lsum * sc;
- data.auto_key = (maxl > minl) ? ((maxl - avl) / (maxl - minl)) : 1.0f;
- float al = expf(avl);
- data.al = (al == 0.0f) ? 0.0f : (tmmd->key / al);
- data.igm = (tmmd->gamma == 0.0f) ? 1.0f : (1.0f / tmmd->gamma);
-
- if (tmmd->type == SEQ_TONEMAP_RD_PHOTORECEPTOR) {
- modifier_apply_threaded(ibuf,
- mask,
- tonemapmodifier_apply_threaded_photoreceptor,
- &data);
- }
- else /* if (tmmd->type == SEQ_TONEMAP_RD_SIMPLE) */ {
- modifier_apply_threaded(ibuf,
- mask,
- tonemapmodifier_apply_threaded_simple,
- &data);
- }
+ SequencerTonemapModifierData *tmmd = (SequencerTonemapModifierData *)smd;
+ AvgLogLum data;
+ data.tmmd = tmmd;
+ data.colorspace = (ibuf->rect_float != NULL) ? ibuf->float_colorspace : ibuf->rect_colorspace;
+ float lsum = 0.0f;
+ int p = ibuf->x * ibuf->y;
+ float *fp = ibuf->rect_float;
+ unsigned char *cp = (unsigned char *)ibuf->rect;
+ float avl, maxl = -FLT_MAX, minl = FLT_MAX;
+ const float sc = 1.0f / p;
+ float Lav = 0.f;
+ float cav[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ while (p--) {
+ float pixel[4];
+ if (fp != NULL) {
+ copy_v4_v4(pixel, fp);
+ }
+ else {
+ straight_uchar_to_premul_float(pixel, cp);
+ }
+ IMB_colormanagement_colorspace_to_scene_linear_v3(pixel, data.colorspace);
+ float L = IMB_colormanagement_get_luminance(pixel);
+ Lav += L;
+ add_v3_v3(cav, pixel);
+ lsum += logf(max_ff(L, 0.0f) + 1e-5f);
+ maxl = (L > maxl) ? L : maxl;
+ minl = (L < minl) ? L : minl;
+ if (fp != NULL) {
+ fp += 4;
+ }
+ else {
+ cp += 4;
+ }
+ }
+ data.lav = Lav * sc;
+ mul_v3_v3fl(data.cav, cav, sc);
+ maxl = logf(maxl + 1e-5f);
+ minl = logf(minl + 1e-5f);
+ avl = lsum * sc;
+ data.auto_key = (maxl > minl) ? ((maxl - avl) / (maxl - minl)) : 1.0f;
+ float al = expf(avl);
+ data.al = (al == 0.0f) ? 0.0f : (tmmd->key / al);
+ data.igm = (tmmd->gamma == 0.0f) ? 1.0f : (1.0f / tmmd->gamma);
+
+ if (tmmd->type == SEQ_TONEMAP_RD_PHOTORECEPTOR) {
+ modifier_apply_threaded(ibuf, mask, tonemapmodifier_apply_threaded_photoreceptor, &data);
+ }
+ else /* if (tmmd->type == SEQ_TONEMAP_RD_SIMPLE) */ {
+ modifier_apply_threaded(ibuf, mask, tonemapmodifier_apply_threaded_simple, &data);
+ }
}
static SequenceModifierTypeInfo seqModifier_Tonemap = {
- CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Tonemap"), /* name */
- "SequencerTonemapModifierData", /* struct_name */
- sizeof(SequencerTonemapModifierData), /* struct_size */
- tonemapmodifier_init_data, /* init_data */
- NULL, /* free_data */
- NULL, /* copy_data */
- tonemapmodifier_apply, /* apply */
+ CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Tonemap"), /* name */
+ "SequencerTonemapModifierData", /* struct_name */
+ sizeof(SequencerTonemapModifierData), /* struct_size */
+ tonemapmodifier_init_data, /* init_data */
+ NULL, /* free_data */
+ NULL, /* copy_data */
+ tonemapmodifier_apply, /* apply */
};
/*********************** Modifier functions *************************/
@@ -857,171 +897,174 @@ static void sequence_modifier_type_info_init(void)
{
#define INIT_TYPE(typeName) (modifiersTypes[seqModifierType_##typeName] = &seqModifier_##typeName)
- INIT_TYPE(ColorBalance);
- INIT_TYPE(Curves);
- INIT_TYPE(HueCorrect);
- INIT_TYPE(BrightContrast);
- INIT_TYPE(Mask);
- INIT_TYPE(WhiteBalance);
- INIT_TYPE(Tonemap);
+ INIT_TYPE(ColorBalance);
+ INIT_TYPE(Curves);
+ INIT_TYPE(HueCorrect);
+ INIT_TYPE(BrightContrast);
+ INIT_TYPE(Mask);
+ INIT_TYPE(WhiteBalance);
+ INIT_TYPE(Tonemap);
#undef INIT_TYPE
}
const SequenceModifierTypeInfo *BKE_sequence_modifier_type_info_get(int type)
{
- if (!modifierTypesInit) {
- sequence_modifier_type_info_init();
- modifierTypesInit = true;
- }
+ if (!modifierTypesInit) {
+ sequence_modifier_type_info_init();
+ modifierTypesInit = true;
+ }
- return modifiersTypes[type];
+ return modifiersTypes[type];
}
SequenceModifierData *BKE_sequence_modifier_new(Sequence *seq, const char *name, int type)
{
- SequenceModifierData *smd;
- const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(type);
+ SequenceModifierData *smd;
+ const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(type);
- smd = MEM_callocN(smti->struct_size, "sequence modifier");
+ smd = MEM_callocN(smti->struct_size, "sequence modifier");
- smd->type = type;
- smd->flag |= SEQUENCE_MODIFIER_EXPANDED;
+ smd->type = type;
+ smd->flag |= SEQUENCE_MODIFIER_EXPANDED;
- if (!name || !name[0])
- BLI_strncpy(smd->name, smti->name, sizeof(smd->name));
- else
- BLI_strncpy(smd->name, name, sizeof(smd->name));
+ if (!name || !name[0])
+ BLI_strncpy(smd->name, smti->name, sizeof(smd->name));
+ else
+ BLI_strncpy(smd->name, name, sizeof(smd->name));
- BLI_addtail(&seq->modifiers, smd);
+ BLI_addtail(&seq->modifiers, smd);
- BKE_sequence_modifier_unique_name(seq, smd);
+ BKE_sequence_modifier_unique_name(seq, smd);
- if (smti->init_data)
- smti->init_data(smd);
+ if (smti->init_data)
+ smti->init_data(smd);
- return smd;
+ return smd;
}
bool BKE_sequence_modifier_remove(Sequence *seq, SequenceModifierData *smd)
{
- if (BLI_findindex(&seq->modifiers, smd) == -1)
- return false;
+ if (BLI_findindex(&seq->modifiers, smd) == -1)
+ return false;
- BLI_remlink(&seq->modifiers, smd);
- BKE_sequence_modifier_free(smd);
+ BLI_remlink(&seq->modifiers, smd);
+ BKE_sequence_modifier_free(smd);
- return true;
+ return true;
}
void BKE_sequence_modifier_clear(Sequence *seq)
{
- SequenceModifierData *smd, *smd_next;
+ SequenceModifierData *smd, *smd_next;
- for (smd = seq->modifiers.first; smd; smd = smd_next) {
- smd_next = smd->next;
- BKE_sequence_modifier_free(smd);
- }
+ for (smd = seq->modifiers.first; smd; smd = smd_next) {
+ smd_next = smd->next;
+ BKE_sequence_modifier_free(smd);
+ }
- BLI_listbase_clear(&seq->modifiers);
+ BLI_listbase_clear(&seq->modifiers);
}
void BKE_sequence_modifier_free(SequenceModifierData *smd)
{
- const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
+ const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
- if (smti && smti->free_data) {
- smti->free_data(smd);
- }
+ if (smti && smti->free_data) {
+ smti->free_data(smd);
+ }
- MEM_freeN(smd);
+ MEM_freeN(smd);
}
void BKE_sequence_modifier_unique_name(Sequence *seq, SequenceModifierData *smd)
{
- const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
-
- BLI_uniquename(&seq->modifiers, smd, CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, smti->name), '.',
- offsetof(SequenceModifierData, name), sizeof(smd->name));
+ const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
+
+ BLI_uniquename(&seq->modifiers,
+ smd,
+ CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, smti->name),
+ '.',
+ offsetof(SequenceModifierData, name),
+ sizeof(smd->name));
}
SequenceModifierData *BKE_sequence_modifier_find_by_name(Sequence *seq, const char *name)
{
- return BLI_findstring(&(seq->modifiers), name, offsetof(SequenceModifierData, name));
+ return BLI_findstring(&(seq->modifiers), name, offsetof(SequenceModifierData, name));
}
-ImBuf *BKE_sequence_modifier_apply_stack(const SeqRenderData *context, Sequence *seq, ImBuf *ibuf, int cfra)
+ImBuf *BKE_sequence_modifier_apply_stack(const SeqRenderData *context,
+ Sequence *seq,
+ ImBuf *ibuf,
+ int cfra)
{
- SequenceModifierData *smd;
- ImBuf *processed_ibuf = ibuf;
-
- if (seq->modifiers.first && (seq->flag & SEQ_USE_LINEAR_MODIFIERS)) {
- processed_ibuf = IMB_dupImBuf(ibuf);
- BKE_sequencer_imbuf_from_sequencer_space(context->scene, processed_ibuf);
- }
-
- for (smd = seq->modifiers.first; smd; smd = smd->next) {
- const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
-
- /* could happen if modifier is being removed or not exists in current version of blender */
- if (!smti)
- continue;
-
- /* modifier is muted, do nothing */
- if (smd->flag & SEQUENCE_MODIFIER_MUTE)
- continue;
-
- if (smti->apply) {
- int frame_offset;
- if (smd->mask_time == SEQUENCE_MASK_TIME_RELATIVE) {
- frame_offset = seq->start;
- }
- else /*if (smd->mask_time == SEQUENCE_MASK_TIME_ABSOLUTE)*/ {
- frame_offset = 0;
- }
-
- ImBuf *mask = modifier_mask_get(smd,
- context,
- cfra,
- frame_offset,
- ibuf->rect_float != NULL);
-
- if (processed_ibuf == ibuf)
- processed_ibuf = IMB_dupImBuf(ibuf);
-
- smti->apply(smd, processed_ibuf, mask);
-
- if (mask)
- IMB_freeImBuf(mask);
- }
- }
-
- if (seq->modifiers.first && (seq->flag & SEQ_USE_LINEAR_MODIFIERS)) {
- BKE_sequencer_imbuf_to_sequencer_space(context->scene, processed_ibuf, false);
- }
-
- return processed_ibuf;
+ SequenceModifierData *smd;
+ ImBuf *processed_ibuf = ibuf;
+
+ if (seq->modifiers.first && (seq->flag & SEQ_USE_LINEAR_MODIFIERS)) {
+ processed_ibuf = IMB_dupImBuf(ibuf);
+ BKE_sequencer_imbuf_from_sequencer_space(context->scene, processed_ibuf);
+ }
+
+ for (smd = seq->modifiers.first; smd; smd = smd->next) {
+ const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
+
+ /* could happen if modifier is being removed or not exists in current version of blender */
+ if (!smti)
+ continue;
+
+ /* modifier is muted, do nothing */
+ if (smd->flag & SEQUENCE_MODIFIER_MUTE)
+ continue;
+
+ if (smti->apply) {
+ int frame_offset;
+ if (smd->mask_time == SEQUENCE_MASK_TIME_RELATIVE) {
+ frame_offset = seq->start;
+ }
+ else /*if (smd->mask_time == SEQUENCE_MASK_TIME_ABSOLUTE)*/ {
+ frame_offset = 0;
+ }
+
+ ImBuf *mask = modifier_mask_get(smd, context, cfra, frame_offset, ibuf->rect_float != NULL);
+
+ if (processed_ibuf == ibuf)
+ processed_ibuf = IMB_dupImBuf(ibuf);
+
+ smti->apply(smd, processed_ibuf, mask);
+
+ if (mask)
+ IMB_freeImBuf(mask);
+ }
+ }
+
+ if (seq->modifiers.first && (seq->flag & SEQ_USE_LINEAR_MODIFIERS)) {
+ BKE_sequencer_imbuf_to_sequencer_space(context->scene, processed_ibuf, false);
+ }
+
+ return processed_ibuf;
}
void BKE_sequence_modifier_list_copy(Sequence *seqn, Sequence *seq)
{
- SequenceModifierData *smd;
+ SequenceModifierData *smd;
- for (smd = seq->modifiers.first; smd; smd = smd->next) {
- SequenceModifierData *smdn;
- const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
+ for (smd = seq->modifiers.first; smd; smd = smd->next) {
+ SequenceModifierData *smdn;
+ const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
- smdn = MEM_dupallocN(smd);
+ smdn = MEM_dupallocN(smd);
- if (smti && smti->copy_data)
- smti->copy_data(smdn, smd);
+ if (smti && smti->copy_data)
+ smti->copy_data(smdn, smd);
- smdn->next = smdn->prev = NULL;
- BLI_addtail(&seqn->modifiers, smdn);
- }
+ smdn->next = smdn->prev = NULL;
+ BLI_addtail(&seqn->modifiers, smdn);
+ }
}
int BKE_sequence_supports_modifiers(Sequence *seq)
{
- return !ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD);
+ return !ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD);
}
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index 9609a4ab1f4..4af06606ef0 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -95,15 +95,18 @@
/* mutable state for sequencer */
typedef struct SeqRenderState {
- LinkNode *scene_parents;
+ LinkNode *scene_parents;
} SeqRenderState;
-static ImBuf *seq_render_strip_stack(
- const SeqRenderData *context, SeqRenderState *state, ListBase *seqbasep,
- float cfra, int chanshown);
-static ImBuf *seq_render_strip(
- const SeqRenderData *context, SeqRenderState *state,
- Sequence *seq, float cfra);
+static ImBuf *seq_render_strip_stack(const SeqRenderData *context,
+ SeqRenderState *state,
+ ListBase *seqbasep,
+ float cfra,
+ int chanshown);
+static ImBuf *seq_render_strip(const SeqRenderData *context,
+ SeqRenderState *state,
+ Sequence *seq,
+ float cfra);
static void seq_free_animdata(Scene *scene, Sequence *seq);
static ImBuf *seq_render_mask(const SeqRenderData *context, Mask *mask, float nr, bool make_float);
static int seq_num_files(Scene *scene, char views_format, const bool is_multiview);
@@ -115,45 +118,47 @@ ListBase seqbase_clipboard;
int seqbase_clipboard_frame;
SequencerDrawView sequencer_view3d_cb = NULL; /* NULL in background mode */
-#if 0 /* unused function */
+#if 0 /* unused function */
static void printf_strip(Sequence *seq)
{
- fprintf(stderr, "name: '%s', len:%d, start:%d, (startofs:%d, endofs:%d), "
- "(startstill:%d, endstill:%d), machine:%d, (startdisp:%d, enddisp:%d)\n",
- seq->name, seq->len, seq->start, seq->startofs, seq->endofs, seq->startstill, seq->endstill, seq->machine,
- seq->startdisp, seq->enddisp);
+ fprintf(stderr, "name: '%s', len:%d, start:%d, (startofs:%d, endofs:%d), "
+ "(startstill:%d, endstill:%d), machine:%d, (startdisp:%d, enddisp:%d)\n",
+ seq->name, seq->len, seq->start, seq->startofs, seq->endofs, seq->startstill, seq->endstill, seq->machine,
+ seq->startdisp, seq->enddisp);
- fprintf(stderr, "\tseq_tx_set_final_left: %d %d\n\n", seq_tx_get_final_left(seq, 0),
- seq_tx_get_final_right(seq, 0));
+ fprintf(stderr, "\tseq_tx_set_final_left: %d %d\n\n", seq_tx_get_final_left(seq, 0),
+ seq_tx_get_final_right(seq, 0));
}
#endif
static void sequencer_state_init(SeqRenderState *state)
{
- state->scene_parents = NULL;
+ state->scene_parents = NULL;
}
-int BKE_sequencer_base_recursive_apply(ListBase *seqbase, int (*apply_func)(Sequence *seq, void *), void *arg)
+int BKE_sequencer_base_recursive_apply(ListBase *seqbase,
+ int (*apply_func)(Sequence *seq, void *),
+ void *arg)
{
- Sequence *iseq;
- for (iseq = seqbase->first; iseq; iseq = iseq->next) {
- if (BKE_sequencer_recursive_apply(iseq, apply_func, arg) == -1)
- return -1; /* bail out */
- }
- return 1;
+ Sequence *iseq;
+ for (iseq = seqbase->first; iseq; iseq = iseq->next) {
+ if (BKE_sequencer_recursive_apply(iseq, apply_func, arg) == -1)
+ return -1; /* bail out */
+ }
+ return 1;
}
int BKE_sequencer_recursive_apply(Sequence *seq, int (*apply_func)(Sequence *, void *), void *arg)
{
- int ret = apply_func(seq, arg);
+ int ret = apply_func(seq, arg);
- if (ret == -1)
- return -1; /* bail out */
+ if (ret == -1)
+ return -1; /* bail out */
- if (ret && seq->seqbase.first)
- ret = BKE_sequencer_base_recursive_apply(&seq->seqbase, apply_func, arg);
+ if (ret && seq->seqbase.first)
+ ret = BKE_sequencer_base_recursive_apply(&seq->seqbase, apply_func, arg);
- return ret;
+ return ret;
}
/*********************** alloc / free functions *************************/
@@ -162,158 +167,160 @@ int BKE_sequencer_recursive_apply(Sequence *seq, int (*apply_func)(Sequence *, v
static void free_proxy_seq(Sequence *seq)
{
- if (seq->strip && seq->strip->proxy && seq->strip->proxy->anim) {
- IMB_free_anim(seq->strip->proxy->anim);
- seq->strip->proxy->anim = NULL;
- }
+ if (seq->strip && seq->strip->proxy && seq->strip->proxy->anim) {
+ IMB_free_anim(seq->strip->proxy->anim);
+ seq->strip->proxy->anim = NULL;
+ }
}
static void seq_free_strip(Strip *strip)
{
- strip->us--;
- if (strip->us > 0)
- return;
- if (strip->us < 0) {
- printf("error: negative users in strip\n");
- return;
- }
+ strip->us--;
+ if (strip->us > 0)
+ return;
+ if (strip->us < 0) {
+ printf("error: negative users in strip\n");
+ return;
+ }
- if (strip->stripdata) {
- MEM_freeN(strip->stripdata);
- }
+ if (strip->stripdata) {
+ MEM_freeN(strip->stripdata);
+ }
- if (strip->proxy) {
- if (strip->proxy->anim) {
- IMB_free_anim(strip->proxy->anim);
- }
+ if (strip->proxy) {
+ if (strip->proxy->anim) {
+ IMB_free_anim(strip->proxy->anim);
+ }
- MEM_freeN(strip->proxy);
- }
- if (strip->crop) {
- MEM_freeN(strip->crop);
- }
- if (strip->transform) {
- MEM_freeN(strip->transform);
- }
+ MEM_freeN(strip->proxy);
+ }
+ if (strip->crop) {
+ MEM_freeN(strip->crop);
+ }
+ if (strip->transform) {
+ MEM_freeN(strip->transform);
+ }
- MEM_freeN(strip);
+ MEM_freeN(strip);
}
/* only give option to skip cache locally (static func) */
-static void BKE_sequence_free_ex(Scene *scene, Sequence *seq, const bool do_cache, const bool do_id_user)
+static void BKE_sequence_free_ex(Scene *scene,
+ Sequence *seq,
+ const bool do_cache,
+ const bool do_id_user)
{
- if (seq->strip)
- seq_free_strip(seq->strip);
+ if (seq->strip)
+ seq_free_strip(seq->strip);
- BKE_sequence_free_anim(seq);
+ BKE_sequence_free_anim(seq);
- if (seq->type & SEQ_TYPE_EFFECT) {
- struct SeqEffectHandle sh = BKE_sequence_get_effect(seq);
- sh.free(seq, do_id_user);
- }
+ if (seq->type & SEQ_TYPE_EFFECT) {
+ struct SeqEffectHandle sh = BKE_sequence_get_effect(seq);
+ sh.free(seq, do_id_user);
+ }
- if (seq->sound && do_id_user) {
- id_us_min(((ID *)seq->sound));
- }
+ if (seq->sound && do_id_user) {
+ id_us_min(((ID *)seq->sound));
+ }
- if (seq->stereo3d_format) {
- MEM_freeN(seq->stereo3d_format);
- }
+ if (seq->stereo3d_format) {
+ MEM_freeN(seq->stereo3d_format);
+ }
- /* clipboard has no scene and will never have a sound handle or be active
- * same goes to sequences copy for proxy rebuild job
- */
- if (scene) {
- Editing *ed = scene->ed;
+ /* clipboard has no scene and will never have a sound handle or be active
+ * same goes to sequences copy for proxy rebuild job
+ */
+ if (scene) {
+ Editing *ed = scene->ed;
- if (ed->act_seq == seq)
- ed->act_seq = NULL;
+ if (ed->act_seq == seq)
+ ed->act_seq = NULL;
- if (seq->scene_sound && ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE))
- BKE_sound_remove_scene_sound(scene, seq->scene_sound);
+ if (seq->scene_sound && ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE))
+ BKE_sound_remove_scene_sound(scene, seq->scene_sound);
- seq_free_animdata(scene, seq);
- }
+ seq_free_animdata(scene, seq);
+ }
- if (seq->prop) {
- IDP_FreeProperty_ex(seq->prop, do_id_user);
- MEM_freeN(seq->prop);
- }
+ if (seq->prop) {
+ IDP_FreeProperty_ex(seq->prop, do_id_user);
+ MEM_freeN(seq->prop);
+ }
- /* free modifiers */
- BKE_sequence_modifier_clear(seq);
+ /* free modifiers */
+ BKE_sequence_modifier_clear(seq);
- /* free cached data used by this strip,
- * also invalidate cache for all dependent sequences
- *
- * be _very_ careful here, invalidating cache loops over the scene sequences and
- * assumes the listbase is valid for all strips, this may not be the case if lists are being freed.
- * this is optional BKE_sequence_invalidate_cache
- */
- if (do_cache) {
- if (scene) {
- BKE_sequence_invalidate_cache(scene, seq);
- }
- }
+ /* free cached data used by this strip,
+ * also invalidate cache for all dependent sequences
+ *
+ * be _very_ careful here, invalidating cache loops over the scene sequences and
+ * assumes the listbase is valid for all strips, this may not be the case if lists are being freed.
+ * this is optional BKE_sequence_invalidate_cache
+ */
+ if (do_cache) {
+ if (scene) {
+ BKE_sequence_invalidate_cache(scene, seq);
+ }
+ }
- MEM_freeN(seq);
+ MEM_freeN(seq);
}
void BKE_sequence_free(Scene *scene, Sequence *seq)
{
- BKE_sequence_free_ex(scene, seq, true, true);
+ BKE_sequence_free_ex(scene, seq, true, true);
}
/* Function to free imbuf and anim data on changes */
void BKE_sequence_free_anim(Sequence *seq)
{
- while (seq->anims.last) {
- StripAnim *sanim = seq->anims.last;
+ while (seq->anims.last) {
+ StripAnim *sanim = seq->anims.last;
- if (sanim->anim) {
- IMB_free_anim(sanim->anim);
- sanim->anim = NULL;
- }
+ if (sanim->anim) {
+ IMB_free_anim(sanim->anim);
+ sanim->anim = NULL;
+ }
- BLI_freelinkN(&seq->anims, sanim);
- }
- BLI_listbase_clear(&seq->anims);
+ BLI_freelinkN(&seq->anims, sanim);
+ }
+ BLI_listbase_clear(&seq->anims);
}
/* cache must be freed before calling this function
* since it leaves the seqbase in an invalid state */
static void seq_free_sequence_recurse(Scene *scene, Sequence *seq, const bool do_id_user)
{
- Sequence *iseq, *iseq_next;
+ Sequence *iseq, *iseq_next;
- for (iseq = seq->seqbase.first; iseq; iseq = iseq_next) {
- iseq_next = iseq->next;
- seq_free_sequence_recurse(scene, iseq, do_id_user);
- }
+ for (iseq = seq->seqbase.first; iseq; iseq = iseq_next) {
+ iseq_next = iseq->next;
+ seq_free_sequence_recurse(scene, iseq, do_id_user);
+ }
- BKE_sequence_free_ex(scene, seq, false, do_id_user);
+ BKE_sequence_free_ex(scene, seq, false, do_id_user);
}
-
Editing *BKE_sequencer_editing_get(Scene *scene, bool alloc)
{
- if (alloc) {
- BKE_sequencer_editing_ensure(scene);
- }
- return scene->ed;
+ if (alloc) {
+ BKE_sequencer_editing_ensure(scene);
+ }
+ return scene->ed;
}
void BKE_sequencer_free_clipboard(void)
{
- Sequence *seq, *nseq;
+ Sequence *seq, *nseq;
- BKE_sequencer_base_clipboard_pointers_free(&seqbase_clipboard);
+ BKE_sequencer_base_clipboard_pointers_free(&seqbase_clipboard);
- for (seq = seqbase_clipboard.first; seq; seq = nseq) {
- nseq = seq->next;
- seq_free_sequence_recurse(NULL, seq, false);
- }
- BLI_listbase_clear(&seqbase_clipboard);
+ for (seq = seqbase_clipboard.first; seq; seq = nseq) {
+ nseq = seq->next;
+ seq_free_sequence_recurse(NULL, seq, false);
+ }
+ BLI_listbase_clear(&seqbase_clipboard);
}
/* -------------------------------------------------------------------- */
@@ -326,146 +333,145 @@ void BKE_sequencer_free_clipboard(void)
#define ID_PT (*id_pt)
static void seqclipboard_ptr_free(Main *UNUSED(bmain), ID **id_pt)
{
- if (ID_PT) {
- BLI_assert(ID_PT->newid != NULL);
- MEM_freeN(ID_PT);
- ID_PT = NULL;
- }
+ if (ID_PT) {
+ BLI_assert(ID_PT->newid != NULL);
+ MEM_freeN(ID_PT);
+ ID_PT = NULL;
+ }
}
static void seqclipboard_ptr_store(Main *UNUSED(bmain), ID **id_pt)
{
- if (ID_PT) {
- ID *id_prev = ID_PT;
- ID_PT = MEM_dupallocN(ID_PT);
- ID_PT->newid = id_prev;
- }
+ if (ID_PT) {
+ ID *id_prev = ID_PT;
+ ID_PT = MEM_dupallocN(ID_PT);
+ ID_PT->newid = id_prev;
+ }
}
static void seqclipboard_ptr_restore(Main *bmain, ID **id_pt)
{
- if (ID_PT) {
- const ListBase *lb = which_libbase(bmain, GS(ID_PT->name));
- void *id_restore;
-
- BLI_assert(ID_PT->newid != NULL);
- if (BLI_findindex(lb, (ID_PT)->newid) != -1) {
- /* the pointer is still valid */
- id_restore = (ID_PT)->newid;
- }
- else {
- /* the pointer of the same name still exists */
- id_restore = BLI_findstring(lb, (ID_PT)->name + 2, offsetof(ID, name) + 2);
- }
-
- if (id_restore == NULL) {
- /* check for a data with the same filename */
- switch (GS(ID_PT->name)) {
- case ID_SO:
- {
- id_restore = BLI_findstring(lb, ((bSound *)ID_PT)->name, offsetof(bSound, name));
- if (id_restore == NULL) {
- id_restore = BKE_sound_new_file(bmain, ((bSound *)ID_PT)->name);
- (ID_PT)->newid = id_restore; /* reuse next time */
- }
- break;
- }
- case ID_MC:
- {
- id_restore = BLI_findstring(lb, ((MovieClip *)ID_PT)->name, offsetof(MovieClip, name));
- if (id_restore == NULL) {
- id_restore = BKE_movieclip_file_add(bmain, ((MovieClip *)ID_PT)->name);
- (ID_PT)->newid = id_restore; /* reuse next time */
- }
- break;
- }
- default:
- break;
- }
- }
-
- /* Replace with pointer to actual datablock. */
- seqclipboard_ptr_free(bmain, id_pt);
- ID_PT = id_restore;
- }
+ if (ID_PT) {
+ const ListBase *lb = which_libbase(bmain, GS(ID_PT->name));
+ void *id_restore;
+
+ BLI_assert(ID_PT->newid != NULL);
+ if (BLI_findindex(lb, (ID_PT)->newid) != -1) {
+ /* the pointer is still valid */
+ id_restore = (ID_PT)->newid;
+ }
+ else {
+ /* the pointer of the same name still exists */
+ id_restore = BLI_findstring(lb, (ID_PT)->name + 2, offsetof(ID, name) + 2);
+ }
+
+ if (id_restore == NULL) {
+ /* check for a data with the same filename */
+ switch (GS(ID_PT->name)) {
+ case ID_SO: {
+ id_restore = BLI_findstring(lb, ((bSound *)ID_PT)->name, offsetof(bSound, name));
+ if (id_restore == NULL) {
+ id_restore = BKE_sound_new_file(bmain, ((bSound *)ID_PT)->name);
+ (ID_PT)->newid = id_restore; /* reuse next time */
+ }
+ break;
+ }
+ case ID_MC: {
+ id_restore = BLI_findstring(lb, ((MovieClip *)ID_PT)->name, offsetof(MovieClip, name));
+ if (id_restore == NULL) {
+ id_restore = BKE_movieclip_file_add(bmain, ((MovieClip *)ID_PT)->name);
+ (ID_PT)->newid = id_restore; /* reuse next time */
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ /* Replace with pointer to actual datablock. */
+ seqclipboard_ptr_free(bmain, id_pt);
+ ID_PT = id_restore;
+ }
}
#undef ID_PT
-static void sequence_clipboard_pointers(Main *bmain, Sequence *seq, void (*callback)(Main *, ID **))
+static void sequence_clipboard_pointers(Main *bmain,
+ Sequence *seq,
+ void (*callback)(Main *, ID **))
{
- callback(bmain, (ID **)&seq->scene);
- callback(bmain, (ID **)&seq->scene_camera);
- callback(bmain, (ID **)&seq->clip);
- callback(bmain, (ID **)&seq->mask);
- callback(bmain, (ID **)&seq->sound);
+ callback(bmain, (ID **)&seq->scene);
+ callback(bmain, (ID **)&seq->scene_camera);
+ callback(bmain, (ID **)&seq->clip);
+ callback(bmain, (ID **)&seq->mask);
+ callback(bmain, (ID **)&seq->sound);
- if (seq->type == SEQ_TYPE_TEXT && seq->effectdata) {
- TextVars *text_data = seq->effectdata;
- callback(bmain, (ID **)&text_data->text_font);
- }
+ if (seq->type == SEQ_TYPE_TEXT && seq->effectdata) {
+ TextVars *text_data = seq->effectdata;
+ callback(bmain, (ID **)&text_data->text_font);
+ }
}
/* recursive versions of functions above */
void BKE_sequencer_base_clipboard_pointers_free(ListBase *seqbase)
{
- Sequence *seq;
- for (seq = seqbase->first; seq; seq = seq->next) {
- sequence_clipboard_pointers(NULL, seq, seqclipboard_ptr_free);
- BKE_sequencer_base_clipboard_pointers_free(&seq->seqbase);
- }
+ Sequence *seq;
+ for (seq = seqbase->first; seq; seq = seq->next) {
+ sequence_clipboard_pointers(NULL, seq, seqclipboard_ptr_free);
+ BKE_sequencer_base_clipboard_pointers_free(&seq->seqbase);
+ }
}
void BKE_sequencer_base_clipboard_pointers_store(Main *bmain, ListBase *seqbase)
{
- Sequence *seq;
- for (seq = seqbase->first; seq; seq = seq->next) {
- sequence_clipboard_pointers(bmain, seq, seqclipboard_ptr_store);
- BKE_sequencer_base_clipboard_pointers_store(bmain, &seq->seqbase);
- }
+ Sequence *seq;
+ for (seq = seqbase->first; seq; seq = seq->next) {
+ sequence_clipboard_pointers(bmain, seq, seqclipboard_ptr_store);
+ BKE_sequencer_base_clipboard_pointers_store(bmain, &seq->seqbase);
+ }
}
void BKE_sequencer_base_clipboard_pointers_restore(ListBase *seqbase, Main *bmain)
{
- Sequence *seq;
- for (seq = seqbase->first; seq; seq = seq->next) {
- sequence_clipboard_pointers(bmain, seq, seqclipboard_ptr_restore);
- BKE_sequencer_base_clipboard_pointers_restore(&seq->seqbase, bmain);
- }
+ Sequence *seq;
+ for (seq = seqbase->first; seq; seq = seq->next) {
+ sequence_clipboard_pointers(bmain, seq, seqclipboard_ptr_restore);
+ BKE_sequencer_base_clipboard_pointers_restore(&seq->seqbase, bmain);
+ }
}
/* end clipboard pointer mess */
-
Editing *BKE_sequencer_editing_ensure(Scene *scene)
{
- if (scene->ed == NULL) {
- Editing *ed;
+ if (scene->ed == NULL) {
+ Editing *ed;
- ed = scene->ed = MEM_callocN(sizeof(Editing), "addseq");
- ed->seqbasep = &ed->seqbase;
- }
+ ed = scene->ed = MEM_callocN(sizeof(Editing), "addseq");
+ ed->seqbasep = &ed->seqbase;
+ }
- return scene->ed;
+ return scene->ed;
}
void BKE_sequencer_editing_free(Scene *scene, const bool do_id_user)
{
- Editing *ed = scene->ed;
- Sequence *seq;
+ Editing *ed = scene->ed;
+ Sequence *seq;
- if (ed == NULL)
- return;
+ if (ed == NULL)
+ return;
- /* this may not be the active scene!, could be smarter about this */
- BKE_sequencer_cache_cleanup();
+ /* this may not be the active scene!, could be smarter about this */
+ BKE_sequencer_cache_cleanup();
- SEQ_BEGIN (ed, seq)
- {
- /* handle cache freeing above */
- BKE_sequence_free_ex(scene, seq, false, do_id_user);
- } SEQ_END;
+ SEQ_BEGIN (ed, seq) {
+ /* handle cache freeing above */
+ BKE_sequence_free_ex(scene, seq, false, do_id_user);
+ }
+ SEQ_END;
- BLI_freelistN(&ed->metastack);
+ BLI_freelistN(&ed->metastack);
- MEM_freeN(ed);
+ MEM_freeN(ed);
- scene->ed = NULL;
+ scene->ed = NULL;
}
/*********************** Sequencer color space functions *************************/
@@ -473,129 +479,139 @@ void BKE_sequencer_editing_free(Scene *scene, const bool do_id_user)
static void sequencer_imbuf_assign_spaces(Scene *scene, ImBuf *ibuf)
{
#if 0
- /* Bute buffer is supposed to be in sequencer working space already. */
- if (ibuf->rect != NULL) {
- IMB_colormanagement_assign_rect_colorspace(ibuf, scene->sequencer_colorspace_settings.name);
- }
+ /* Bute buffer is supposed to be in sequencer working space already. */
+ if (ibuf->rect != NULL) {
+ IMB_colormanagement_assign_rect_colorspace(ibuf, scene->sequencer_colorspace_settings.name);
+ }
#endif
- if (ibuf->rect_float != NULL) {
- IMB_colormanagement_assign_float_colorspace(ibuf, scene->sequencer_colorspace_settings.name);
- }
+ if (ibuf->rect_float != NULL) {
+ IMB_colormanagement_assign_float_colorspace(ibuf, scene->sequencer_colorspace_settings.name);
+ }
}
void BKE_sequencer_imbuf_to_sequencer_space(Scene *scene, ImBuf *ibuf, bool make_float)
{
- /* Early output check: if both buffers are NULL we have nothing to convert. */
- if (ibuf->rect_float == NULL && ibuf->rect == NULL) {
- return;
- }
- /* Get common conversion settings. */
- const char *to_colorspace = scene->sequencer_colorspace_settings.name;
- /* Perform actual conversion logic. */
- if (ibuf->rect_float == NULL) {
- /* We are not requested to give float buffer and byte buffer is already
- * in thee required colorspace. Can skip doing anything here.
- */
- const char *from_colorspace = IMB_colormanagement_get_rect_colorspace(ibuf);
- if (!make_float && STREQ(from_colorspace, to_colorspace)) {
- return;
- }
- if (false) {
- /* The idea here is to provide as fast playback as possible and
- * enforcing float buffer here (a) uses more cache memory (b) might
- * make some other effects slower to apply.
- *
- * However, this might also have negative effect by adding weird
- * artifacts which will then not happen in final render.
- */
- IMB_colormanagement_transform_byte_threaded(
- (unsigned char *)ibuf->rect, ibuf->x, ibuf->y, ibuf->channels,
- from_colorspace, to_colorspace);
- }
- else {
- /* We perform conversion to a float buffer so we don't worry about
- * precision loss.
- */
- imb_addrectfloatImBuf(ibuf);
- IMB_colormanagement_transform_from_byte_threaded(
- ibuf->rect_float, (unsigned char *)ibuf->rect,
- ibuf->x, ibuf->y, ibuf->channels,
- from_colorspace, to_colorspace);
- /* We don't need byte buffer anymore. */
- imb_freerectImBuf(ibuf);
- }
- }
- else {
- const char *from_colorspace = IMB_colormanagement_get_float_colorspace(ibuf);
- /* Unknown input color space, can't perform conversion. */
- if (from_colorspace == NULL || from_colorspace[0] == '\0') {
- return;
- }
- /* We don't want both byte and float buffers around: they'll either run
- * out of sync or conversion of byte buffer will loose precision in there.
- */
- if (ibuf->rect != NULL) {
- imb_freerectImBuf(ibuf);
- }
- IMB_colormanagement_transform_threaded(ibuf->rect_float,
- ibuf->x, ibuf->y, ibuf->channels,
- from_colorspace, to_colorspace,
- true);
- }
- sequencer_imbuf_assign_spaces(scene, ibuf);
+ /* Early output check: if both buffers are NULL we have nothing to convert. */
+ if (ibuf->rect_float == NULL && ibuf->rect == NULL) {
+ return;
+ }
+ /* Get common conversion settings. */
+ const char *to_colorspace = scene->sequencer_colorspace_settings.name;
+ /* Perform actual conversion logic. */
+ if (ibuf->rect_float == NULL) {
+ /* We are not requested to give float buffer and byte buffer is already
+ * in thee required colorspace. Can skip doing anything here.
+ */
+ const char *from_colorspace = IMB_colormanagement_get_rect_colorspace(ibuf);
+ if (!make_float && STREQ(from_colorspace, to_colorspace)) {
+ return;
+ }
+ if (false) {
+ /* The idea here is to provide as fast playback as possible and
+ * enforcing float buffer here (a) uses more cache memory (b) might
+ * make some other effects slower to apply.
+ *
+ * However, this might also have negative effect by adding weird
+ * artifacts which will then not happen in final render.
+ */
+ IMB_colormanagement_transform_byte_threaded((unsigned char *)ibuf->rect,
+ ibuf->x,
+ ibuf->y,
+ ibuf->channels,
+ from_colorspace,
+ to_colorspace);
+ }
+ else {
+ /* We perform conversion to a float buffer so we don't worry about
+ * precision loss.
+ */
+ imb_addrectfloatImBuf(ibuf);
+ IMB_colormanagement_transform_from_byte_threaded(ibuf->rect_float,
+ (unsigned char *)ibuf->rect,
+ ibuf->x,
+ ibuf->y,
+ ibuf->channels,
+ from_colorspace,
+ to_colorspace);
+ /* We don't need byte buffer anymore. */
+ imb_freerectImBuf(ibuf);
+ }
+ }
+ else {
+ const char *from_colorspace = IMB_colormanagement_get_float_colorspace(ibuf);
+ /* Unknown input color space, can't perform conversion. */
+ if (from_colorspace == NULL || from_colorspace[0] == '\0') {
+ return;
+ }
+ /* We don't want both byte and float buffers around: they'll either run
+ * out of sync or conversion of byte buffer will loose precision in there.
+ */
+ if (ibuf->rect != NULL) {
+ imb_freerectImBuf(ibuf);
+ }
+ IMB_colormanagement_transform_threaded(
+ ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, to_colorspace, true);
+ }
+ sequencer_imbuf_assign_spaces(scene, ibuf);
}
void BKE_sequencer_imbuf_from_sequencer_space(Scene *scene, ImBuf *ibuf)
{
- const char *from_colorspace = scene->sequencer_colorspace_settings.name;
- const char *to_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR);
+ const char *from_colorspace = scene->sequencer_colorspace_settings.name;
+ const char *to_colorspace = IMB_colormanagement_role_colorspace_name_get(
+ COLOR_ROLE_SCENE_LINEAR);
- if (!ibuf->rect_float)
- return;
+ if (!ibuf->rect_float)
+ return;
- if (to_colorspace && to_colorspace[0] != '\0') {
- IMB_colormanagement_transform_threaded(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels,
- from_colorspace, to_colorspace, true);
- IMB_colormanagement_assign_float_colorspace(ibuf, to_colorspace);
- }
+ if (to_colorspace && to_colorspace[0] != '\0') {
+ IMB_colormanagement_transform_threaded(
+ ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, to_colorspace, true);
+ IMB_colormanagement_assign_float_colorspace(ibuf, to_colorspace);
+ }
}
void BKE_sequencer_pixel_from_sequencer_space_v4(struct Scene *scene, float pixel[4])
{
- const char *from_colorspace = scene->sequencer_colorspace_settings.name;
- const char *to_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR);
+ const char *from_colorspace = scene->sequencer_colorspace_settings.name;
+ const char *to_colorspace = IMB_colormanagement_role_colorspace_name_get(
+ COLOR_ROLE_SCENE_LINEAR);
- if (to_colorspace && to_colorspace[0] != '\0') {
- IMB_colormanagement_transform_v4(pixel, from_colorspace, to_colorspace);
- }
- else {
- /* if no color management enables fallback to legacy conversion */
- srgb_to_linearrgb_v4(pixel, pixel);
- }
+ if (to_colorspace && to_colorspace[0] != '\0') {
+ IMB_colormanagement_transform_v4(pixel, from_colorspace, to_colorspace);
+ }
+ else {
+ /* if no color management enables fallback to legacy conversion */
+ srgb_to_linearrgb_v4(pixel, pixel);
+ }
}
/*********************** sequencer pipeline functions *************************/
-void BKE_sequencer_new_render_data(
- Main *bmain, struct Depsgraph *depsgraph, Scene *scene, int rectx, int recty,
- int preview_render_size, int for_render,
- SeqRenderData *r_context)
-{
- r_context->bmain = bmain;
- r_context->depsgraph = depsgraph;
- r_context->scene = scene;
- r_context->rectx = rectx;
- r_context->recty = recty;
- r_context->preview_render_size = preview_render_size;
- r_context->for_render = for_render;
- r_context->motion_blur_samples = 0;
- r_context->motion_blur_shutter = 0;
- r_context->skip_cache = false;
- r_context->is_proxy_render = false;
- r_context->view_id = 0;
- r_context->gpu_offscreen = NULL;
- r_context->gpu_samples = (scene->r.mode & R_OSA) ? scene->r.osa : 0;
- r_context->gpu_full_samples = (r_context->gpu_samples) && (scene->r.scemode & R_FULL_SAMPLE);
+void BKE_sequencer_new_render_data(Main *bmain,
+ struct Depsgraph *depsgraph,
+ Scene *scene,
+ int rectx,
+ int recty,
+ int preview_render_size,
+ int for_render,
+ SeqRenderData *r_context)
+{
+ r_context->bmain = bmain;
+ r_context->depsgraph = depsgraph;
+ r_context->scene = scene;
+ r_context->rectx = rectx;
+ r_context->recty = recty;
+ r_context->preview_render_size = preview_render_size;
+ r_context->for_render = for_render;
+ r_context->motion_blur_samples = 0;
+ r_context->motion_blur_shutter = 0;
+ r_context->skip_cache = false;
+ r_context->is_proxy_render = false;
+ r_context->view_id = 0;
+ r_context->gpu_offscreen = NULL;
+ r_context->gpu_samples = (scene->r.mode & R_OSA) ? scene->r.osa : 0;
+ r_context->gpu_full_samples = (r_context->gpu_samples) && (scene->r.scemode & R_FULL_SAMPLE);
}
/* ************************* iterator ************************** */
@@ -608,1252 +624,1323 @@ void BKE_sequencer_new_render_data(
static void seq_count(ListBase *seqbase, int *tot)
{
- Sequence *seq;
+ Sequence *seq;
- for (seq = seqbase->first; seq; seq = seq->next) {
- (*tot)++;
+ for (seq = seqbase->first; seq; seq = seq->next) {
+ (*tot)++;
- if (seq->seqbase.first)
- seq_count(&seq->seqbase, tot);
- }
+ if (seq->seqbase.first)
+ seq_count(&seq->seqbase, tot);
+ }
}
static void seq_build_array(ListBase *seqbase, Sequence ***array, int depth)
{
- Sequence *seq;
+ Sequence *seq;
- for (seq = seqbase->first; seq; seq = seq->next) {
- seq->depth = depth;
+ for (seq = seqbase->first; seq; seq = seq->next) {
+ seq->depth = depth;
- if (seq->seqbase.first)
- seq_build_array(&seq->seqbase, array, depth + 1);
+ if (seq->seqbase.first)
+ seq_build_array(&seq->seqbase, array, depth + 1);
- **array = seq;
- (*array)++;
- }
+ **array = seq;
+ (*array)++;
+ }
}
static void seq_array(Editing *ed, Sequence ***seqarray, int *tot, bool use_pointer)
{
- Sequence **array;
+ Sequence **array;
- *seqarray = NULL;
- *tot = 0;
+ *seqarray = NULL;
+ *tot = 0;
- if (ed == NULL)
- return;
+ if (ed == NULL)
+ return;
- if (use_pointer)
- seq_count(ed->seqbasep, tot);
- else
- seq_count(&ed->seqbase, tot);
+ if (use_pointer)
+ seq_count(ed->seqbasep, tot);
+ else
+ seq_count(&ed->seqbase, tot);
- if (*tot == 0)
- return;
+ if (*tot == 0)
+ return;
- *seqarray = array = MEM_mallocN(sizeof(Sequence *) * (*tot), "SeqArray");
- if (use_pointer)
- seq_build_array(ed->seqbasep, &array, 0);
- else
- seq_build_array(&ed->seqbase, &array, 0);
+ *seqarray = array = MEM_mallocN(sizeof(Sequence *) * (*tot), "SeqArray");
+ if (use_pointer)
+ seq_build_array(ed->seqbasep, &array, 0);
+ else
+ seq_build_array(&ed->seqbase, &array, 0);
}
void BKE_sequence_iterator_begin(Editing *ed, SeqIterator *iter, bool use_pointer)
{
- memset(iter, 0, sizeof(*iter));
- seq_array(ed, &iter->array, &iter->tot, use_pointer);
+ memset(iter, 0, sizeof(*iter));
+ seq_array(ed, &iter->array, &iter->tot, use_pointer);
- if (iter->tot) {
- iter->cur = 0;
- iter->seq = iter->array[iter->cur];
- iter->valid = 1;
- }
+ if (iter->tot) {
+ iter->cur = 0;
+ iter->seq = iter->array[iter->cur];
+ iter->valid = 1;
+ }
}
void BKE_sequence_iterator_next(SeqIterator *iter)
{
- if (++iter->cur < iter->tot)
- iter->seq = iter->array[iter->cur];
- else
- iter->valid = 0;
+ if (++iter->cur < iter->tot)
+ iter->seq = iter->array[iter->cur];
+ else
+ iter->valid = 0;
}
void BKE_sequence_iterator_end(SeqIterator *iter)
{
- if (iter->array)
- MEM_freeN(iter->array);
+ if (iter->array)
+ MEM_freeN(iter->array);
- iter->valid = 0;
+ iter->valid = 0;
}
static int metaseq_start(Sequence *metaseq)
{
- return metaseq->start + metaseq->startofs;
+ return metaseq->start + metaseq->startofs;
}
static int metaseq_end(Sequence *metaseq)
{
- return metaseq->start + metaseq->len - metaseq->endofs;
+ return metaseq->start + metaseq->len - metaseq->endofs;
}
-static void seq_update_sound_bounds_recursive_rec(Scene *scene, Sequence *metaseq, int start, int end)
+static void seq_update_sound_bounds_recursive_rec(Scene *scene,
+ Sequence *metaseq,
+ int start,
+ int end)
{
- Sequence *seq;
+ Sequence *seq;
- /* for sound we go over full meta tree to update bounds of the sound strips,
- * since sound is played outside of evaluating the imbufs, */
- for (seq = metaseq->seqbase.first; seq; seq = seq->next) {
- if (seq->type == SEQ_TYPE_META) {
- seq_update_sound_bounds_recursive_rec(scene, seq, max_ii(start, metaseq_start(seq)),
- min_ii(end, metaseq_end(seq)));
- }
- else if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE)) {
- if (seq->scene_sound) {
- int startofs = seq->startofs;
- int endofs = seq->endofs;
- if (seq->startofs + seq->start < start)
- startofs = start - seq->start;
+ /* for sound we go over full meta tree to update bounds of the sound strips,
+ * since sound is played outside of evaluating the imbufs, */
+ for (seq = metaseq->seqbase.first; seq; seq = seq->next) {
+ if (seq->type == SEQ_TYPE_META) {
+ seq_update_sound_bounds_recursive_rec(
+ scene, seq, max_ii(start, metaseq_start(seq)), min_ii(end, metaseq_end(seq)));
+ }
+ else if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE)) {
+ if (seq->scene_sound) {
+ int startofs = seq->startofs;
+ int endofs = seq->endofs;
+ if (seq->startofs + seq->start < start)
+ startofs = start - seq->start;
- if (seq->start + seq->len - seq->endofs > end)
- endofs = seq->start + seq->len - end;
+ if (seq->start + seq->len - seq->endofs > end)
+ endofs = seq->start + seq->len - end;
- BKE_sound_move_scene_sound(scene, seq->scene_sound, seq->start + startofs,
- seq->start + seq->len - endofs, startofs + seq->anim_startofs);
- }
- }
- }
+ BKE_sound_move_scene_sound(scene,
+ seq->scene_sound,
+ seq->start + startofs,
+ seq->start + seq->len - endofs,
+ startofs + seq->anim_startofs);
+ }
+ }
+ }
}
static void seq_update_sound_bounds_recursive(Scene *scene, Sequence *metaseq)
{
- seq_update_sound_bounds_recursive_rec(scene, metaseq, metaseq_start(metaseq), metaseq_end(metaseq));
+ seq_update_sound_bounds_recursive_rec(
+ scene, metaseq, metaseq_start(metaseq), metaseq_end(metaseq));
}
void BKE_sequence_calc_disp(Scene *scene, Sequence *seq)
{
- if (seq->startofs && seq->startstill)
- seq->startstill = 0;
- if (seq->endofs && seq->endstill)
- seq->endstill = 0;
+ if (seq->startofs && seq->startstill)
+ seq->startstill = 0;
+ if (seq->endofs && seq->endstill)
+ seq->endstill = 0;
- seq->startdisp = seq->start + seq->startofs - seq->startstill;
- seq->enddisp = seq->start + seq->len - seq->endofs + seq->endstill;
+ seq->startdisp = seq->start + seq->startofs - seq->startstill;
+ seq->enddisp = seq->start + seq->len - seq->endofs + seq->endstill;
- seq->handsize = 10.0; /* 10 frames */
- if (seq->enddisp - seq->startdisp < 10) {
- seq->handsize = (float)(0.5 * (seq->enddisp - seq->startdisp));
- }
- else if (seq->enddisp - seq->startdisp > 250) {
- seq->handsize = (float)((seq->enddisp - seq->startdisp) / 25);
- }
+ seq->handsize = 10.0; /* 10 frames */
+ if (seq->enddisp - seq->startdisp < 10) {
+ seq->handsize = (float)(0.5 * (seq->enddisp - seq->startdisp));
+ }
+ else if (seq->enddisp - seq->startdisp > 250) {
+ seq->handsize = (float)((seq->enddisp - seq->startdisp) / 25);
+ }
- if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE)) {
- BKE_sequencer_update_sound_bounds(scene, seq);
- }
- else if (seq->type == SEQ_TYPE_META) {
- seq_update_sound_bounds_recursive(scene, seq);
- }
+ if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE)) {
+ BKE_sequencer_update_sound_bounds(scene, seq);
+ }
+ else if (seq->type == SEQ_TYPE_META) {
+ seq_update_sound_bounds_recursive(scene, seq);
+ }
}
void BKE_sequence_calc(Scene *scene, Sequence *seq)
{
- Sequence *seqm;
- int min, max;
-
- /* check all metas recursively */
- seqm = seq->seqbase.first;
- while (seqm) {
- if (seqm->seqbase.first) BKE_sequence_calc(scene, seqm);
- seqm = seqm->next;
- }
-
- /* effects and meta: automatic start and end */
-
- if (seq->type & SEQ_TYPE_EFFECT) {
- /* pointers */
- if (seq->seq2 == NULL)
- seq->seq2 = seq->seq1;
- if (seq->seq3 == NULL)
- seq->seq3 = seq->seq1;
-
- /* effecten go from seq1 -> seq2: test */
-
- /* we take the largest start and smallest end */
-
- // seq->start = seq->startdisp = MAX2(seq->seq1->startdisp, seq->seq2->startdisp);
- // seq->enddisp = MIN2(seq->seq1->enddisp, seq->seq2->enddisp);
-
- if (seq->seq1) {
- /* XXX These resets should not be necessary, but users used to be able to
- * edit effect's length, leading to strange results. See [#29190] */
- seq->startofs = seq->endofs = seq->startstill = seq->endstill = 0;
- seq->start = seq->startdisp = max_iii(seq->seq1->startdisp, seq->seq2->startdisp, seq->seq3->startdisp);
- seq->enddisp = min_iii(seq->seq1->enddisp, seq->seq2->enddisp, seq->seq3->enddisp);
- /* we cant help if strips don't overlap, it wont give useful results.
- * but at least ensure 'len' is never negative which causes bad bugs elsewhere. */
- if (seq->enddisp < seq->startdisp) {
- /* simple start/end swap */
- seq->start = seq->enddisp;
- seq->enddisp = seq->startdisp;
- seq->startdisp = seq->start;
- seq->flag |= SEQ_INVALID_EFFECT;
- }
- else {
- seq->flag &= ~SEQ_INVALID_EFFECT;
- }
-
- seq->len = seq->enddisp - seq->startdisp;
- }
- else {
- BKE_sequence_calc_disp(scene, seq);
- }
- }
- else {
- if (seq->type == SEQ_TYPE_META) {
- seqm = seq->seqbase.first;
- if (seqm) {
- min = MAXFRAME * 2;
- max = -MAXFRAME * 2;
- while (seqm) {
- if (seqm->startdisp < min) min = seqm->startdisp;
- if (seqm->enddisp > max) max = seqm->enddisp;
- seqm = seqm->next;
- }
- seq->start = min + seq->anim_startofs;
- seq->len = max - min;
- seq->len -= seq->anim_startofs;
- seq->len -= seq->anim_endofs;
- }
- seq_update_sound_bounds_recursive(scene, seq);
- }
- BKE_sequence_calc_disp(scene, seq);
- }
-}
-
-static void seq_multiview_name(
- Scene *scene, const int view_id, const char *prefix, const char *ext,
- char *r_path, size_t r_size)
-{
- const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, view_id);
- BLI_snprintf(r_path, r_size, "%s%s%s", prefix, suffix, ext);
+ Sequence *seqm;
+ int min, max;
+
+ /* check all metas recursively */
+ seqm = seq->seqbase.first;
+ while (seqm) {
+ if (seqm->seqbase.first)
+ BKE_sequence_calc(scene, seqm);
+ seqm = seqm->next;
+ }
+
+ /* effects and meta: automatic start and end */
+
+ if (seq->type & SEQ_TYPE_EFFECT) {
+ /* pointers */
+ if (seq->seq2 == NULL)
+ seq->seq2 = seq->seq1;
+ if (seq->seq3 == NULL)
+ seq->seq3 = seq->seq1;
+
+ /* effecten go from seq1 -> seq2: test */
+
+ /* we take the largest start and smallest end */
+
+ // seq->start = seq->startdisp = MAX2(seq->seq1->startdisp, seq->seq2->startdisp);
+ // seq->enddisp = MIN2(seq->seq1->enddisp, seq->seq2->enddisp);
+
+ if (seq->seq1) {
+ /* XXX These resets should not be necessary, but users used to be able to
+ * edit effect's length, leading to strange results. See [#29190] */
+ seq->startofs = seq->endofs = seq->startstill = seq->endstill = 0;
+ seq->start = seq->startdisp = max_iii(
+ seq->seq1->startdisp, seq->seq2->startdisp, seq->seq3->startdisp);
+ seq->enddisp = min_iii(seq->seq1->enddisp, seq->seq2->enddisp, seq->seq3->enddisp);
+ /* we cant help if strips don't overlap, it wont give useful results.
+ * but at least ensure 'len' is never negative which causes bad bugs elsewhere. */
+ if (seq->enddisp < seq->startdisp) {
+ /* simple start/end swap */
+ seq->start = seq->enddisp;
+ seq->enddisp = seq->startdisp;
+ seq->startdisp = seq->start;
+ seq->flag |= SEQ_INVALID_EFFECT;
+ }
+ else {
+ seq->flag &= ~SEQ_INVALID_EFFECT;
+ }
+
+ seq->len = seq->enddisp - seq->startdisp;
+ }
+ else {
+ BKE_sequence_calc_disp(scene, seq);
+ }
+ }
+ else {
+ if (seq->type == SEQ_TYPE_META) {
+ seqm = seq->seqbase.first;
+ if (seqm) {
+ min = MAXFRAME * 2;
+ max = -MAXFRAME * 2;
+ while (seqm) {
+ if (seqm->startdisp < min)
+ min = seqm->startdisp;
+ if (seqm->enddisp > max)
+ max = seqm->enddisp;
+ seqm = seqm->next;
+ }
+ seq->start = min + seq->anim_startofs;
+ seq->len = max - min;
+ seq->len -= seq->anim_startofs;
+ seq->len -= seq->anim_endofs;
+ }
+ seq_update_sound_bounds_recursive(scene, seq);
+ }
+ BKE_sequence_calc_disp(scene, seq);
+ }
+}
+
+static void seq_multiview_name(Scene *scene,
+ const int view_id,
+ const char *prefix,
+ const char *ext,
+ char *r_path,
+ size_t r_size)
+{
+ const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, view_id);
+ BLI_snprintf(r_path, r_size, "%s%s%s", prefix, suffix, ext);
}
/* note: caller should run BKE_sequence_calc(scene, seq) after */
void BKE_sequence_reload_new_file(Scene *scene, Sequence *seq, const bool lock_range)
{
- char path[FILE_MAX];
- int prev_startdisp = 0, prev_enddisp = 0;
- /* note: don't rename the strip, will break animation curves */
-
- if (ELEM(seq->type,
- SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE, SEQ_TYPE_SOUND_RAM,
- SEQ_TYPE_SCENE, SEQ_TYPE_META, SEQ_TYPE_MOVIECLIP, SEQ_TYPE_MASK) == 0)
- {
- return;
- }
-
- if (lock_range) {
- /* keep so we don't have to move the actual start and end points (only the data) */
- BKE_sequence_calc_disp(scene, seq);
- prev_startdisp = seq->startdisp;
- prev_enddisp = seq->enddisp;
- }
-
- switch (seq->type) {
- case SEQ_TYPE_IMAGE:
- {
- /* Hack? */
- size_t olen = MEM_allocN_len(seq->strip->stripdata) / sizeof(StripElem);
-
- seq->len = olen;
- seq->len -= seq->anim_startofs;
- seq->len -= seq->anim_endofs;
- if (seq->len < 0) {
- seq->len = 0;
- }
- break;
- }
- case SEQ_TYPE_MOVIE:
- {
- StripAnim *sanim;
- bool is_multiview_loaded = false;
- const bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 &&
- (scene->r.scemode & R_MULTIVIEW) != 0;
-
- BLI_join_dirfile(path, sizeof(path), seq->strip->dir,
- seq->strip->stripdata->name);
- BLI_path_abs(path, BKE_main_blendfile_path_from_global());
-
- BKE_sequence_free_anim(seq);
-
- if (is_multiview && (seq->views_format == R_IMF_VIEWS_INDIVIDUAL)) {
- char prefix[FILE_MAX];
- const char *ext = NULL;
- const int totfiles = seq_num_files(scene, seq->views_format, true);
- int i = 0;
-
- BKE_scene_multiview_view_prefix_get(scene, path, prefix, &ext);
-
- if (prefix[0] != '\0') {
- for (i = 0; i < totfiles; i++) {
- struct anim *anim;
- char str[FILE_MAX];
-
- seq_multiview_name(scene, i, prefix, ext, str, FILE_MAX);
- anim = openanim(str, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
- seq->streamindex, seq->strip->colorspace_settings.name);
-
- if (anim) {
- seq_anim_add_suffix(scene, anim, i);
- sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
- BLI_addtail(&seq->anims, sanim);
- sanim->anim = anim;
- }
- }
- is_multiview_loaded = true;
- }
- }
-
- if (is_multiview_loaded == false) {
- struct anim *anim;
- anim = openanim(path, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
- seq->streamindex, seq->strip->colorspace_settings.name);
- if (anim) {
- sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
- BLI_addtail(&seq->anims, sanim);
- sanim->anim = anim;
- }
- }
-
- /* use the first video as reference for everything */
- sanim = seq->anims.first;
-
- if ((!sanim) || (!sanim->anim)) {
- return;
- }
-
- IMB_anim_load_metadata(sanim->anim);
-
- seq->len = IMB_anim_get_duration(sanim->anim, seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN);
-
- seq->anim_preseek = IMB_anim_get_preseek(sanim->anim);
-
- seq->len -= seq->anim_startofs;
- seq->len -= seq->anim_endofs;
- if (seq->len < 0) {
- seq->len = 0;
- }
- break;
- }
- case SEQ_TYPE_MOVIECLIP:
- if (seq->clip == NULL)
- return;
-
- seq->len = BKE_movieclip_get_duration(seq->clip);
-
- seq->len -= seq->anim_startofs;
- seq->len -= seq->anim_endofs;
- if (seq->len < 0) {
- seq->len = 0;
- }
- break;
- case SEQ_TYPE_MASK:
- if (seq->mask == NULL)
- return;
- seq->len = BKE_mask_get_duration(seq->mask);
- seq->len -= seq->anim_startofs;
- seq->len -= seq->anim_endofs;
- if (seq->len < 0) {
- seq->len = 0;
- }
- break;
- case SEQ_TYPE_SOUND_RAM:
+ char path[FILE_MAX];
+ int prev_startdisp = 0, prev_enddisp = 0;
+ /* note: don't rename the strip, will break animation curves */
+
+ if (ELEM(seq->type,
+ SEQ_TYPE_MOVIE,
+ SEQ_TYPE_IMAGE,
+ SEQ_TYPE_SOUND_RAM,
+ SEQ_TYPE_SCENE,
+ SEQ_TYPE_META,
+ SEQ_TYPE_MOVIECLIP,
+ SEQ_TYPE_MASK) == 0) {
+ return;
+ }
+
+ if (lock_range) {
+ /* keep so we don't have to move the actual start and end points (only the data) */
+ BKE_sequence_calc_disp(scene, seq);
+ prev_startdisp = seq->startdisp;
+ prev_enddisp = seq->enddisp;
+ }
+
+ switch (seq->type) {
+ case SEQ_TYPE_IMAGE: {
+ /* Hack? */
+ size_t olen = MEM_allocN_len(seq->strip->stripdata) / sizeof(StripElem);
+
+ seq->len = olen;
+ seq->len -= seq->anim_startofs;
+ seq->len -= seq->anim_endofs;
+ if (seq->len < 0) {
+ seq->len = 0;
+ }
+ break;
+ }
+ case SEQ_TYPE_MOVIE: {
+ StripAnim *sanim;
+ bool is_multiview_loaded = false;
+ const bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 &&
+ (scene->r.scemode & R_MULTIVIEW) != 0;
+
+ BLI_join_dirfile(path, sizeof(path), seq->strip->dir, seq->strip->stripdata->name);
+ BLI_path_abs(path, BKE_main_blendfile_path_from_global());
+
+ BKE_sequence_free_anim(seq);
+
+ if (is_multiview && (seq->views_format == R_IMF_VIEWS_INDIVIDUAL)) {
+ char prefix[FILE_MAX];
+ const char *ext = NULL;
+ const int totfiles = seq_num_files(scene, seq->views_format, true);
+ int i = 0;
+
+ BKE_scene_multiview_view_prefix_get(scene, path, prefix, &ext);
+
+ if (prefix[0] != '\0') {
+ for (i = 0; i < totfiles; i++) {
+ struct anim *anim;
+ char str[FILE_MAX];
+
+ seq_multiview_name(scene, i, prefix, ext, str, FILE_MAX);
+ anim = openanim(str,
+ IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex,
+ seq->strip->colorspace_settings.name);
+
+ if (anim) {
+ seq_anim_add_suffix(scene, anim, i);
+ sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
+ BLI_addtail(&seq->anims, sanim);
+ sanim->anim = anim;
+ }
+ }
+ is_multiview_loaded = true;
+ }
+ }
+
+ if (is_multiview_loaded == false) {
+ struct anim *anim;
+ anim = openanim(path,
+ IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex,
+ seq->strip->colorspace_settings.name);
+ if (anim) {
+ sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
+ BLI_addtail(&seq->anims, sanim);
+ sanim->anim = anim;
+ }
+ }
+
+ /* use the first video as reference for everything */
+ sanim = seq->anims.first;
+
+ if ((!sanim) || (!sanim->anim)) {
+ return;
+ }
+
+ IMB_anim_load_metadata(sanim->anim);
+
+ seq->len = IMB_anim_get_duration(
+ sanim->anim, seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN);
+
+ seq->anim_preseek = IMB_anim_get_preseek(sanim->anim);
+
+ seq->len -= seq->anim_startofs;
+ seq->len -= seq->anim_endofs;
+ if (seq->len < 0) {
+ seq->len = 0;
+ }
+ break;
+ }
+ case SEQ_TYPE_MOVIECLIP:
+ if (seq->clip == NULL)
+ return;
+
+ seq->len = BKE_movieclip_get_duration(seq->clip);
+
+ seq->len -= seq->anim_startofs;
+ seq->len -= seq->anim_endofs;
+ if (seq->len < 0) {
+ seq->len = 0;
+ }
+ break;
+ case SEQ_TYPE_MASK:
+ if (seq->mask == NULL)
+ return;
+ seq->len = BKE_mask_get_duration(seq->mask);
+ seq->len -= seq->anim_startofs;
+ seq->len -= seq->anim_endofs;
+ if (seq->len < 0) {
+ seq->len = 0;
+ }
+ break;
+ case SEQ_TYPE_SOUND_RAM:
#ifdef WITH_AUDASPACE
- if (!seq->sound)
- return;
- seq->len = ceil((double)AUD_getInfo(seq->sound->playback_handle).length * FPS);
- seq->len -= seq->anim_startofs;
- seq->len -= seq->anim_endofs;
- if (seq->len < 0) {
- seq->len = 0;
- }
+ if (!seq->sound)
+ return;
+ seq->len = ceil((double)AUD_getInfo(seq->sound->playback_handle).length * FPS);
+ seq->len -= seq->anim_startofs;
+ seq->len -= seq->anim_endofs;
+ if (seq->len < 0) {
+ seq->len = 0;
+ }
#else
- return;
+ return;
#endif
- break;
- case SEQ_TYPE_SCENE:
- {
- seq->len = (seq->scene) ? seq->scene->r.efra - seq->scene->r.sfra + 1 : 0;
- seq->len -= seq->anim_startofs;
- seq->len -= seq->anim_endofs;
- if (seq->len < 0) {
- seq->len = 0;
- }
- break;
- }
- }
-
- free_proxy_seq(seq);
-
- if (lock_range) {
- BKE_sequence_tx_set_final_left(seq, prev_startdisp);
- BKE_sequence_tx_set_final_right(seq, prev_enddisp);
- BKE_sequence_single_fix(seq);
- }
-
- BKE_sequence_calc(scene, seq);
+ break;
+ case SEQ_TYPE_SCENE: {
+ seq->len = (seq->scene) ? seq->scene->r.efra - seq->scene->r.sfra + 1 : 0;
+ seq->len -= seq->anim_startofs;
+ seq->len -= seq->anim_endofs;
+ if (seq->len < 0) {
+ seq->len = 0;
+ }
+ break;
+ }
+ }
+
+ free_proxy_seq(seq);
+
+ if (lock_range) {
+ BKE_sequence_tx_set_final_left(seq, prev_startdisp);
+ BKE_sequence_tx_set_final_right(seq, prev_enddisp);
+ BKE_sequence_single_fix(seq);
+ }
+
+ BKE_sequence_calc(scene, seq);
}
void BKE_sequencer_sort(Scene *scene)
{
- /* all strips together per kind, and in order of y location ("machine") */
- ListBase seqbase, effbase;
- Editing *ed = BKE_sequencer_editing_get(scene, false);
- Sequence *seq, *seqt;
-
- if (ed == NULL)
- return;
-
- BLI_listbase_clear(&seqbase);
- BLI_listbase_clear(&effbase);
-
- while ((seq = BLI_pophead(ed->seqbasep))) {
-
- if (seq->type & SEQ_TYPE_EFFECT) {
- seqt = effbase.first;
- while (seqt) {
- if (seqt->machine >= seq->machine) {
- BLI_insertlinkbefore(&effbase, seqt, seq);
- break;
- }
- seqt = seqt->next;
- }
- if (seqt == NULL)
- BLI_addtail(&effbase, seq);
- }
- else {
- seqt = seqbase.first;
- while (seqt) {
- if (seqt->machine >= seq->machine) {
- BLI_insertlinkbefore(&seqbase, seqt, seq);
- break;
- }
- seqt = seqt->next;
- }
- if (seqt == NULL)
- BLI_addtail(&seqbase, seq);
- }
- }
-
- BLI_movelisttolist(&seqbase, &effbase);
- *(ed->seqbasep) = seqbase;
+ /* all strips together per kind, and in order of y location ("machine") */
+ ListBase seqbase, effbase;
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ Sequence *seq, *seqt;
+
+ if (ed == NULL)
+ return;
+
+ BLI_listbase_clear(&seqbase);
+ BLI_listbase_clear(&effbase);
+
+ while ((seq = BLI_pophead(ed->seqbasep))) {
+
+ if (seq->type & SEQ_TYPE_EFFECT) {
+ seqt = effbase.first;
+ while (seqt) {
+ if (seqt->machine >= seq->machine) {
+ BLI_insertlinkbefore(&effbase, seqt, seq);
+ break;
+ }
+ seqt = seqt->next;
+ }
+ if (seqt == NULL)
+ BLI_addtail(&effbase, seq);
+ }
+ else {
+ seqt = seqbase.first;
+ while (seqt) {
+ if (seqt->machine >= seq->machine) {
+ BLI_insertlinkbefore(&seqbase, seqt, seq);
+ break;
+ }
+ seqt = seqt->next;
+ }
+ if (seqt == NULL)
+ BLI_addtail(&seqbase, seq);
+ }
+ }
+
+ BLI_movelisttolist(&seqbase, &effbase);
+ *(ed->seqbasep) = seqbase;
}
/** Comparison function suitable to be used with BLI_listbase_sort()... */
int BKE_sequencer_cmp_time_startdisp(const void *a, const void *b)
{
- const Sequence *seq_a = a;
- const Sequence *seq_b = b;
+ const Sequence *seq_a = a;
+ const Sequence *seq_b = b;
- return (seq_a->startdisp > seq_b->startdisp);
+ return (seq_a->startdisp > seq_b->startdisp);
}
static int clear_scene_in_allseqs_cb(Sequence *seq, void *arg_pt)
{
- if (seq->scene == (Scene *)arg_pt)
- seq->scene = NULL;
- return 1;
+ if (seq->scene == (Scene *)arg_pt)
+ seq->scene = NULL;
+ return 1;
}
void BKE_sequencer_clear_scene_in_allseqs(Main *bmain, Scene *scene)
{
- Scene *scene_iter;
+ Scene *scene_iter;
- /* when a scene is deleted: test all seqs */
- for (scene_iter = bmain->scenes.first; scene_iter; scene_iter = scene_iter->id.next) {
- if (scene_iter != scene && scene_iter->ed) {
- BKE_sequencer_base_recursive_apply(&scene_iter->ed->seqbase, clear_scene_in_allseqs_cb, scene);
- }
- }
+ /* when a scene is deleted: test all seqs */
+ for (scene_iter = bmain->scenes.first; scene_iter; scene_iter = scene_iter->id.next) {
+ if (scene_iter != scene && scene_iter->ed) {
+ BKE_sequencer_base_recursive_apply(
+ &scene_iter->ed->seqbase, clear_scene_in_allseqs_cb, scene);
+ }
+ }
}
typedef struct SeqUniqueInfo {
- Sequence *seq;
- char name_src[SEQ_NAME_MAXSTR];
- char name_dest[SEQ_NAME_MAXSTR];
- int count;
- int match;
+ Sequence *seq;
+ char name_src[SEQ_NAME_MAXSTR];
+ char name_dest[SEQ_NAME_MAXSTR];
+ int count;
+ int match;
} SeqUniqueInfo;
static void seqbase_unique_name(ListBase *seqbasep, SeqUniqueInfo *sui)
{
- Sequence *seq;
- for (seq = seqbasep->first; seq; seq = seq->next) {
- if ((sui->seq != seq) && STREQ(sui->name_dest, seq->name + 2)) {
- /* SEQ_NAME_MAXSTR -4 for the number, -1 for \0, - 2 for prefix */
- BLI_snprintf(sui->name_dest, sizeof(sui->name_dest), "%.*s.%03d", SEQ_NAME_MAXSTR - 4 - 1 - 2,
- sui->name_src, sui->count++);
- sui->match = 1; /* be sure to re-scan */
- }
- }
+ Sequence *seq;
+ for (seq = seqbasep->first; seq; seq = seq->next) {
+ if ((sui->seq != seq) && STREQ(sui->name_dest, seq->name + 2)) {
+ /* SEQ_NAME_MAXSTR -4 for the number, -1 for \0, - 2 for prefix */
+ BLI_snprintf(sui->name_dest,
+ sizeof(sui->name_dest),
+ "%.*s.%03d",
+ SEQ_NAME_MAXSTR - 4 - 1 - 2,
+ sui->name_src,
+ sui->count++);
+ sui->match = 1; /* be sure to re-scan */
+ }
+ }
}
static int seqbase_unique_name_recursive_cb(Sequence *seq, void *arg_pt)
{
- if (seq->seqbase.first)
- seqbase_unique_name(&seq->seqbase, (SeqUniqueInfo *)arg_pt);
- return 1;
+ if (seq->seqbase.first)
+ seqbase_unique_name(&seq->seqbase, (SeqUniqueInfo *)arg_pt);
+ return 1;
}
void BKE_sequence_base_unique_name_recursive(ListBase *seqbasep, Sequence *seq)
{
- SeqUniqueInfo sui;
- char *dot;
- sui.seq = seq;
- BLI_strncpy(sui.name_src, seq->name + 2, sizeof(sui.name_src));
- BLI_strncpy(sui.name_dest, seq->name + 2, sizeof(sui.name_dest));
+ SeqUniqueInfo sui;
+ char *dot;
+ sui.seq = seq;
+ BLI_strncpy(sui.name_src, seq->name + 2, sizeof(sui.name_src));
+ BLI_strncpy(sui.name_dest, seq->name + 2, sizeof(sui.name_dest));
- sui.count = 1;
- sui.match = 1; /* assume the worst to start the loop */
+ sui.count = 1;
+ sui.match = 1; /* assume the worst to start the loop */
- /* Strip off the suffix */
- if ((dot = strrchr(sui.name_src, '.'))) {
- *dot = '\0';
- dot++;
+ /* Strip off the suffix */
+ if ((dot = strrchr(sui.name_src, '.'))) {
+ *dot = '\0';
+ dot++;
- if (*dot)
- sui.count = atoi(dot) + 1;
- }
+ if (*dot)
+ sui.count = atoi(dot) + 1;
+ }
- while (sui.match) {
- sui.match = 0;
- seqbase_unique_name(seqbasep, &sui);
- BKE_sequencer_base_recursive_apply(seqbasep, seqbase_unique_name_recursive_cb, &sui);
- }
+ while (sui.match) {
+ sui.match = 0;
+ seqbase_unique_name(seqbasep, &sui);
+ BKE_sequencer_base_recursive_apply(seqbasep, seqbase_unique_name_recursive_cb, &sui);
+ }
- BLI_strncpy(seq->name + 2, sui.name_dest, sizeof(seq->name) - 2);
+ BLI_strncpy(seq->name + 2, sui.name_dest, sizeof(seq->name) - 2);
}
static const char *give_seqname_by_type(int type)
{
- switch (type) {
- case SEQ_TYPE_META: return "Meta";
- case SEQ_TYPE_IMAGE: return "Image";
- case SEQ_TYPE_SCENE: return "Scene";
- case SEQ_TYPE_MOVIE: return "Movie";
- case SEQ_TYPE_MOVIECLIP: return "Clip";
- case SEQ_TYPE_MASK: return "Mask";
- case SEQ_TYPE_SOUND_RAM: return "Audio";
- case SEQ_TYPE_CROSS: return "Cross";
- case SEQ_TYPE_GAMCROSS: return "Gamma Cross";
- case SEQ_TYPE_ADD: return "Add";
- case SEQ_TYPE_SUB: return "Sub";
- case SEQ_TYPE_MUL: return "Mul";
- case SEQ_TYPE_ALPHAOVER: return "Alpha Over";
- case SEQ_TYPE_ALPHAUNDER: return "Alpha Under";
- case SEQ_TYPE_OVERDROP: return "Over Drop";
- case SEQ_TYPE_COLORMIX: return "Color Mix";
- case SEQ_TYPE_WIPE: return "Wipe";
- case SEQ_TYPE_GLOW: return "Glow";
- case SEQ_TYPE_TRANSFORM: return "Transform";
- case SEQ_TYPE_COLOR: return "Color";
- case SEQ_TYPE_MULTICAM: return "Multicam";
- case SEQ_TYPE_ADJUSTMENT: return "Adjustment";
- case SEQ_TYPE_SPEED: return "Speed";
- case SEQ_TYPE_GAUSSIAN_BLUR: return "Gaussian Blur";
- case SEQ_TYPE_TEXT: return "Text";
- default:
- return NULL;
- }
+ switch (type) {
+ case SEQ_TYPE_META:
+ return "Meta";
+ case SEQ_TYPE_IMAGE:
+ return "Image";
+ case SEQ_TYPE_SCENE:
+ return "Scene";
+ case SEQ_TYPE_MOVIE:
+ return "Movie";
+ case SEQ_TYPE_MOVIECLIP:
+ return "Clip";
+ case SEQ_TYPE_MASK:
+ return "Mask";
+ case SEQ_TYPE_SOUND_RAM:
+ return "Audio";
+ case SEQ_TYPE_CROSS:
+ return "Cross";
+ case SEQ_TYPE_GAMCROSS:
+ return "Gamma Cross";
+ case SEQ_TYPE_ADD:
+ return "Add";
+ case SEQ_TYPE_SUB:
+ return "Sub";
+ case SEQ_TYPE_MUL:
+ return "Mul";
+ case SEQ_TYPE_ALPHAOVER:
+ return "Alpha Over";
+ case SEQ_TYPE_ALPHAUNDER:
+ return "Alpha Under";
+ case SEQ_TYPE_OVERDROP:
+ return "Over Drop";
+ case SEQ_TYPE_COLORMIX:
+ return "Color Mix";
+ case SEQ_TYPE_WIPE:
+ return "Wipe";
+ case SEQ_TYPE_GLOW:
+ return "Glow";
+ case SEQ_TYPE_TRANSFORM:
+ return "Transform";
+ case SEQ_TYPE_COLOR:
+ return "Color";
+ case SEQ_TYPE_MULTICAM:
+ return "Multicam";
+ case SEQ_TYPE_ADJUSTMENT:
+ return "Adjustment";
+ case SEQ_TYPE_SPEED:
+ return "Speed";
+ case SEQ_TYPE_GAUSSIAN_BLUR:
+ return "Gaussian Blur";
+ case SEQ_TYPE_TEXT:
+ return "Text";
+ default:
+ return NULL;
+ }
}
const char *BKE_sequence_give_name(Sequence *seq)
{
- const char *name = give_seqname_by_type(seq->type);
+ const char *name = give_seqname_by_type(seq->type);
- if (!name) {
- if (!(seq->type & SEQ_TYPE_EFFECT)) {
- return seq->strip->dir;
- }
- else {
- return "Effect";
- }
- }
- return name;
+ if (!name) {
+ if (!(seq->type & SEQ_TYPE_EFFECT)) {
+ return seq->strip->dir;
+ }
+ else {
+ return "Effect";
+ }
+ }
+ return name;
}
ListBase *BKE_sequence_seqbase_get(Sequence *seq, int *r_offset)
{
- ListBase *seqbase = NULL;
-
- switch (seq->type) {
- case SEQ_TYPE_META:
- {
- seqbase = &seq->seqbase;
- *r_offset = seq->start;
- break;
- }
- case SEQ_TYPE_SCENE:
- {
- if (seq->flag & SEQ_SCENE_STRIPS) {
- Editing *ed = BKE_sequencer_editing_get(seq->scene, false);
- if (ed) {
- seqbase = &ed->seqbase;
- *r_offset = seq->scene->r.sfra;
- }
- }
- break;
- }
- }
-
- return seqbase;
+ ListBase *seqbase = NULL;
+
+ switch (seq->type) {
+ case SEQ_TYPE_META: {
+ seqbase = &seq->seqbase;
+ *r_offset = seq->start;
+ break;
+ }
+ case SEQ_TYPE_SCENE: {
+ if (seq->flag & SEQ_SCENE_STRIPS) {
+ Editing *ed = BKE_sequencer_editing_get(seq->scene, false);
+ if (ed) {
+ seqbase = &ed->seqbase;
+ *r_offset = seq->scene->r.sfra;
+ }
+ }
+ break;
+ }
+ }
+
+ return seqbase;
}
/*********************** DO THE SEQUENCE *************************/
static void make_black_ibuf(ImBuf *ibuf)
{
- unsigned int *rect;
- float *rect_float;
- int tot;
+ unsigned int *rect;
+ float *rect_float;
+ int tot;
- if (ibuf == NULL || (ibuf->rect == NULL && ibuf->rect_float == NULL)) {
- return;
- }
+ if (ibuf == NULL || (ibuf->rect == NULL && ibuf->rect_float == NULL)) {
+ return;
+ }
- tot = ibuf->x * ibuf->y;
+ tot = ibuf->x * ibuf->y;
- rect = ibuf->rect;
- rect_float = ibuf->rect_float;
+ rect = ibuf->rect;
+ rect_float = ibuf->rect_float;
- if (rect) {
- memset(rect, 0, tot * sizeof(char) * 4);
- }
+ if (rect) {
+ memset(rect, 0, tot * sizeof(char) * 4);
+ }
- if (rect_float) {
- memset(rect_float, 0, tot * sizeof(float) * 4);
- }
+ if (rect_float) {
+ memset(rect_float, 0, tot * sizeof(float) * 4);
+ }
}
static void multibuf(ImBuf *ibuf, const float fmul)
{
- char *rt;
- float *rt_float;
+ char *rt;
+ float *rt_float;
- int a;
+ int a;
- rt = (char *)ibuf->rect;
- rt_float = ibuf->rect_float;
+ rt = (char *)ibuf->rect;
+ rt_float = ibuf->rect_float;
- if (rt) {
- const int imul = (int)(256.0f * fmul);
- a = ibuf->x * ibuf->y;
- while (a--) {
- rt[0] = min_ii((imul * rt[0]) >> 8, 255);
- rt[1] = min_ii((imul * rt[1]) >> 8, 255);
- rt[2] = min_ii((imul * rt[2]) >> 8, 255);
- rt[3] = min_ii((imul * rt[3]) >> 8, 255);
+ if (rt) {
+ const int imul = (int)(256.0f * fmul);
+ a = ibuf->x * ibuf->y;
+ while (a--) {
+ rt[0] = min_ii((imul * rt[0]) >> 8, 255);
+ rt[1] = min_ii((imul * rt[1]) >> 8, 255);
+ rt[2] = min_ii((imul * rt[2]) >> 8, 255);
+ rt[3] = min_ii((imul * rt[3]) >> 8, 255);
- rt += 4;
- }
- }
- if (rt_float) {
- a = ibuf->x * ibuf->y;
- while (a--) {
- rt_float[0] *= fmul;
- rt_float[1] *= fmul;
- rt_float[2] *= fmul;
- rt_float[3] *= fmul;
+ rt += 4;
+ }
+ }
+ if (rt_float) {
+ a = ibuf->x * ibuf->y;
+ while (a--) {
+ rt_float[0] *= fmul;
+ rt_float[1] *= fmul;
+ rt_float[2] *= fmul;
+ rt_float[3] *= fmul;
- rt_float += 4;
- }
- }
+ rt_float += 4;
+ }
+ }
}
static float give_stripelem_index(Sequence *seq, float cfra)
{
- float nr;
- int sta = seq->start;
- int end = seq->start + seq->len - 1;
-
- if (seq->type & SEQ_TYPE_EFFECT) {
- end = seq->enddisp;
- }
-
- if (end < sta) {
- return -1;
- }
-
- if (seq->flag & SEQ_REVERSE_FRAMES) {
- /*reverse frame in this sequence */
- if (cfra <= sta) nr = end - sta;
- else if (cfra >= end) nr = 0;
- else nr = end - cfra;
- }
- else {
- if (cfra <= sta) nr = 0;
- else if (cfra >= end) nr = end - sta;
- else nr = cfra - sta;
- }
-
- if (seq->strobe < 1.0f) seq->strobe = 1.0f;
-
- if (seq->strobe > 1.0f) {
- nr -= fmodf((double)nr, (double)seq->strobe);
- }
-
- return nr;
+ float nr;
+ int sta = seq->start;
+ int end = seq->start + seq->len - 1;
+
+ if (seq->type & SEQ_TYPE_EFFECT) {
+ end = seq->enddisp;
+ }
+
+ if (end < sta) {
+ return -1;
+ }
+
+ if (seq->flag & SEQ_REVERSE_FRAMES) {
+ /*reverse frame in this sequence */
+ if (cfra <= sta)
+ nr = end - sta;
+ else if (cfra >= end)
+ nr = 0;
+ else
+ nr = end - cfra;
+ }
+ else {
+ if (cfra <= sta)
+ nr = 0;
+ else if (cfra >= end)
+ nr = end - sta;
+ else
+ nr = cfra - sta;
+ }
+
+ if (seq->strobe < 1.0f)
+ seq->strobe = 1.0f;
+
+ if (seq->strobe > 1.0f) {
+ nr -= fmodf((double)nr, (double)seq->strobe);
+ }
+
+ return nr;
}
StripElem *BKE_sequencer_give_stripelem(Sequence *seq, int cfra)
{
- StripElem *se = seq->strip->stripdata;
+ StripElem *se = seq->strip->stripdata;
- if (seq->type == SEQ_TYPE_IMAGE) {
- /* only IMAGE strips use the whole array, MOVIE strips use only the first element,
- * all other strips don't use this...
- */
+ if (seq->type == SEQ_TYPE_IMAGE) {
+ /* only IMAGE strips use the whole array, MOVIE strips use only the first element,
+ * all other strips don't use this...
+ */
- int nr = (int) give_stripelem_index(seq, cfra);
+ int nr = (int)give_stripelem_index(seq, cfra);
- if (nr == -1 || se == NULL)
- return NULL;
+ if (nr == -1 || se == NULL)
+ return NULL;
- se += nr + seq->anim_startofs;
- }
- return se;
+ se += nr + seq->anim_startofs;
+ }
+ return se;
}
static int evaluate_seq_frame_gen(Sequence **seq_arr, ListBase *seqbase, int cfra, int chanshown)
{
- /* Use arbitrary sized linked list, the size could be over MAXSEQ. */
- LinkNodePair effect_inputs = {NULL, NULL};
- int totseq = 0;
-
- memset(seq_arr, 0, sizeof(Sequence *) * (MAXSEQ + 1));
-
- for (Sequence *seq = seqbase->first; seq; seq = seq->next) {
- if ((seq->startdisp <= cfra) && (seq->enddisp > cfra)) {
- if ((seq->type & SEQ_TYPE_EFFECT) && !(seq->flag & SEQ_MUTE)) {
-
- if (seq->seq1) {
- BLI_linklist_append_alloca(&effect_inputs, seq->seq1);
- }
-
- if (seq->seq2) {
- BLI_linklist_append_alloca(&effect_inputs, seq->seq2);
- }
-
- if (seq->seq3) {
- BLI_linklist_append_alloca(&effect_inputs, seq->seq3);
- }
- }
-
- seq_arr[seq->machine] = seq;
- totseq++;
- }
- }
-
- /* Drop strips which are used for effect inputs, we don't want
- * them to blend into render stack in any other way than effect
- * string rendering.
- */
- for (LinkNode *seq_item = effect_inputs.list; seq_item; seq_item = seq_item->next) {
- Sequence *seq = seq_item->link;
- /* It's possible that effetc strip would be placed to the same
- * 'machine' as it's inputs. We don't want to clear such strips
- * from the stack.
- */
- if (seq_arr[seq->machine] && seq_arr[seq->machine]->type & SEQ_TYPE_EFFECT) {
- continue;
- }
- /* If we're shown a specified channel, then we want to see the stirps
- * which belongs to this machine.
- */
- if (chanshown != 0 && chanshown <= seq->machine) {
- continue;
- }
- seq_arr[seq->machine] = NULL;
- }
-
- return totseq;
+ /* Use arbitrary sized linked list, the size could be over MAXSEQ. */
+ LinkNodePair effect_inputs = {NULL, NULL};
+ int totseq = 0;
+
+ memset(seq_arr, 0, sizeof(Sequence *) * (MAXSEQ + 1));
+
+ for (Sequence *seq = seqbase->first; seq; seq = seq->next) {
+ if ((seq->startdisp <= cfra) && (seq->enddisp > cfra)) {
+ if ((seq->type & SEQ_TYPE_EFFECT) && !(seq->flag & SEQ_MUTE)) {
+
+ if (seq->seq1) {
+ BLI_linklist_append_alloca(&effect_inputs, seq->seq1);
+ }
+
+ if (seq->seq2) {
+ BLI_linklist_append_alloca(&effect_inputs, seq->seq2);
+ }
+
+ if (seq->seq3) {
+ BLI_linklist_append_alloca(&effect_inputs, seq->seq3);
+ }
+ }
+
+ seq_arr[seq->machine] = seq;
+ totseq++;
+ }
+ }
+
+ /* Drop strips which are used for effect inputs, we don't want
+ * them to blend into render stack in any other way than effect
+ * string rendering.
+ */
+ for (LinkNode *seq_item = effect_inputs.list; seq_item; seq_item = seq_item->next) {
+ Sequence *seq = seq_item->link;
+ /* It's possible that effetc strip would be placed to the same
+ * 'machine' as it's inputs. We don't want to clear such strips
+ * from the stack.
+ */
+ if (seq_arr[seq->machine] && seq_arr[seq->machine]->type & SEQ_TYPE_EFFECT) {
+ continue;
+ }
+ /* If we're shown a specified channel, then we want to see the stirps
+ * which belongs to this machine.
+ */
+ if (chanshown != 0 && chanshown <= seq->machine) {
+ continue;
+ }
+ seq_arr[seq->machine] = NULL;
+ }
+
+ return totseq;
}
int BKE_sequencer_evaluate_frame(Scene *scene, int cfra)
{
- Editing *ed = BKE_sequencer_editing_get(scene, false);
- Sequence *seq_arr[MAXSEQ + 1];
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ Sequence *seq_arr[MAXSEQ + 1];
- if (ed == NULL)
- return 0;
+ if (ed == NULL)
+ return 0;
- return evaluate_seq_frame_gen(seq_arr, ed->seqbasep, cfra, 0);
+ return evaluate_seq_frame_gen(seq_arr, ed->seqbasep, cfra, 0);
}
static bool video_seq_is_rendered(Sequence *seq)
{
- return (seq && !(seq->flag & SEQ_MUTE) && seq->type != SEQ_TYPE_SOUND_RAM);
+ return (seq && !(seq->flag & SEQ_MUTE) && seq->type != SEQ_TYPE_SOUND_RAM);
}
static int get_shown_sequences(ListBase *seqbasep, int cfra, int chanshown, Sequence **seq_arr_out)
{
- Sequence *seq_arr[MAXSEQ + 1];
- int b = chanshown;
- int cnt = 0;
+ Sequence *seq_arr[MAXSEQ + 1];
+ int b = chanshown;
+ int cnt = 0;
- if (b > MAXSEQ) {
- return 0;
- }
+ if (b > MAXSEQ) {
+ return 0;
+ }
- if (evaluate_seq_frame_gen(seq_arr, seqbasep, cfra, chanshown)) {
- if (b == 0) {
- b = MAXSEQ;
- }
- for (; b > 0; b--) {
- if (video_seq_is_rendered(seq_arr[b])) {
- break;
- }
- }
- }
+ if (evaluate_seq_frame_gen(seq_arr, seqbasep, cfra, chanshown)) {
+ if (b == 0) {
+ b = MAXSEQ;
+ }
+ for (; b > 0; b--) {
+ if (video_seq_is_rendered(seq_arr[b])) {
+ break;
+ }
+ }
+ }
- chanshown = b;
+ chanshown = b;
- for (; b > 0; b--) {
- if (video_seq_is_rendered(seq_arr[b])) {
- if (seq_arr[b]->blend_mode == SEQ_BLEND_REPLACE) {
- break;
- }
- }
- }
+ for (; b > 0; b--) {
+ if (video_seq_is_rendered(seq_arr[b])) {
+ if (seq_arr[b]->blend_mode == SEQ_BLEND_REPLACE) {
+ break;
+ }
+ }
+ }
- for (; b <= chanshown && b >= 0; b++) {
- if (video_seq_is_rendered(seq_arr[b])) {
- seq_arr_out[cnt++] = seq_arr[b];
- }
- }
+ for (; b <= chanshown && b >= 0; b++) {
+ if (video_seq_is_rendered(seq_arr[b])) {
+ seq_arr_out[cnt++] = seq_arr[b];
+ }
+ }
- return cnt;
+ return cnt;
}
/*********************** proxy management *************************/
typedef struct SeqIndexBuildContext {
- struct IndexBuildContext *index_context;
-
- int tc_flags;
- int size_flags;
- int quality;
- bool overwrite;
- int view_id;
-
- Main *bmain;
- Depsgraph *depsgraph;
- Scene *scene;
- Sequence *seq, *orig_seq;
+ struct IndexBuildContext *index_context;
+
+ int tc_flags;
+ int size_flags;
+ int quality;
+ bool overwrite;
+ int view_id;
+
+ Main *bmain;
+ Depsgraph *depsgraph;
+ Scene *scene;
+ Sequence *seq, *orig_seq;
} SeqIndexBuildContext;
#define PROXY_MAXFILE (2 * FILE_MAXDIR + FILE_MAXFILE)
static IMB_Proxy_Size seq_rendersize_to_proxysize(int size)
{
- if (size >= 100) {
- return IMB_PROXY_NONE;
- }
- if (size >= 99) {
- return IMB_PROXY_100;
- }
- if (size >= 75) {
- return IMB_PROXY_75;
- }
- if (size >= 50) {
- return IMB_PROXY_50;
- }
- return IMB_PROXY_25;
+ if (size >= 100) {
+ return IMB_PROXY_NONE;
+ }
+ if (size >= 99) {
+ return IMB_PROXY_100;
+ }
+ if (size >= 75) {
+ return IMB_PROXY_75;
+ }
+ if (size >= 50) {
+ return IMB_PROXY_50;
+ }
+ return IMB_PROXY_25;
}
static double seq_rendersize_to_scale_factor(int size)
{
- if (size >= 99) {
- return 1.0;
- }
- if (size >= 75) {
- return 0.75;
- }
- if (size >= 50) {
- return 0.50;
- }
- return 0.25;
+ if (size >= 99) {
+ return 1.0;
+ }
+ if (size >= 75) {
+ return 0.75;
+ }
+ if (size >= 50) {
+ return 0.50;
+ }
+ return 0.25;
}
/* the number of files will vary according to the stereo format */
static int seq_num_files(Scene *scene, char views_format, const bool is_multiview)
{
- if (!is_multiview) {
- return 1;
- }
- else if (views_format == R_IMF_VIEWS_STEREO_3D) {
- return 1;
- }
- /* R_IMF_VIEWS_INDIVIDUAL */
- else {
- return BKE_scene_multiview_num_views_get(&scene->r);
- }
+ if (!is_multiview) {
+ return 1;
+ }
+ else if (views_format == R_IMF_VIEWS_STEREO_3D) {
+ return 1;
+ }
+ /* R_IMF_VIEWS_INDIVIDUAL */
+ else {
+ return BKE_scene_multiview_num_views_get(&scene->r);
+ }
}
static void seq_proxy_index_dir_set(struct anim *anim, const char *base_dir)
{
- char dir[FILE_MAX];
- char fname[FILE_MAXFILE];
+ char dir[FILE_MAX];
+ char fname[FILE_MAXFILE];
- IMB_anim_get_fname(anim, fname, FILE_MAXFILE);
- BLI_strncpy(dir, base_dir, sizeof(dir));
- BLI_path_append(dir, sizeof(dir), fname);
- IMB_anim_set_index_dir(anim, dir);
+ IMB_anim_get_fname(anim, fname, FILE_MAXFILE);
+ BLI_strncpy(dir, base_dir, sizeof(dir));
+ BLI_path_append(dir, sizeof(dir), fname);
+ IMB_anim_set_index_dir(anim, dir);
}
static void seq_open_anim_file(Scene *scene, Sequence *seq, bool openfile)
{
- char dir[FILE_MAX];
- char name[FILE_MAX];
- StripProxy *proxy;
- bool use_proxy;
- bool is_multiview_loaded = false;
- Editing *ed = scene->ed;
- const bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 && (scene->r.scemode & R_MULTIVIEW) != 0;
-
- if ((seq->anims.first != NULL) && (((StripAnim *)seq->anims.first)->anim != NULL)) {
- return;
- }
-
- /* reset all the previously created anims */
- BKE_sequence_free_anim(seq);
-
- BLI_join_dirfile(name, sizeof(name),
- seq->strip->dir, seq->strip->stripdata->name);
- BLI_path_abs(name, BKE_main_blendfile_path_from_global());
-
- proxy = seq->strip->proxy;
-
- use_proxy = proxy && ((proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR) != 0 ||
- (ed->proxy_storage == SEQ_EDIT_PROXY_DIR_STORAGE));
-
- if (use_proxy) {
- if (ed->proxy_storage == SEQ_EDIT_PROXY_DIR_STORAGE) {
- if (ed->proxy_dir[0] == 0)
- BLI_strncpy(dir, "//BL_proxy", sizeof(dir));
- else
- BLI_strncpy(dir, ed->proxy_dir, sizeof(dir));
- }
- else {
- BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
- }
- BLI_path_abs(dir, BKE_main_blendfile_path_from_global());
- }
-
- if (is_multiview && seq->views_format == R_IMF_VIEWS_INDIVIDUAL) {
- int totfiles = seq_num_files(scene, seq->views_format, true);
- char prefix[FILE_MAX];
- const char *ext = NULL;
- int i;
-
- BKE_scene_multiview_view_prefix_get(scene, name, prefix, &ext);
-
- if (prefix[0] != '\0') {
- for (i = 0; i < totfiles; i++) {
- const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, i);
- char str[FILE_MAX];
- StripAnim *sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
-
- BLI_addtail(&seq->anims, sanim);
-
- BLI_snprintf(str, sizeof(str), "%s%s%s", prefix, suffix, ext);
-
- if (openfile) {
- sanim->anim = openanim(
- str, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
- seq->streamindex, seq->strip->colorspace_settings.name);
- }
- else {
- sanim->anim = openanim_noload(
- str, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
- seq->streamindex, seq->strip->colorspace_settings.name);
- }
-
- if (sanim->anim) {
- /* we already have the suffix */
- IMB_suffix_anim(sanim->anim, suffix);
- }
- else {
- if (openfile) {
- sanim->anim = openanim(
- name, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
- seq->streamindex, seq->strip->colorspace_settings.name);
- }
- else {
- sanim->anim = openanim_noload(
- name, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
- seq->streamindex, seq->strip->colorspace_settings.name);
- }
-
- /* no individual view files - monoscopic, stereo 3d or exr multiview */
- totfiles = 1;
- }
-
- if (sanim->anim && use_proxy) {
- seq_proxy_index_dir_set(sanim->anim, dir);
- }
- }
- is_multiview_loaded = true;
- }
- }
-
- if (is_multiview_loaded == false) {
- StripAnim *sanim;
-
- sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
- BLI_addtail(&seq->anims, sanim);
-
- if (openfile) {
- sanim->anim = openanim(
- name, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
- seq->streamindex, seq->strip->colorspace_settings.name);
- }
- else {
- sanim->anim = openanim_noload(
- name, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
- seq->streamindex, seq->strip->colorspace_settings.name);
- }
-
- if (sanim->anim && use_proxy) {
- seq_proxy_index_dir_set(sanim->anim, dir);
- }
- }
-}
-
-static bool seq_proxy_get_fname(Editing *ed, Sequence *seq, int cfra, int render_size, char *name, const int view_id)
-{
- int frameno;
- char dir[PROXY_MAXFILE];
- StripAnim *sanim;
- char suffix[24] = {'\0'};
-
- StripProxy *proxy = seq->strip->proxy;
- if (!proxy) {
- return false;
- }
-
- /* MOVIE tracks (only exception: custom files) are now handled
- * internally by ImBuf module for various reasons: proper time code
- * support, quicker index build, using one file instead
- * of a full directory of jpeg files, etc. Trying to support old
- * and new method at once could lead to funny effects, if people
- * have both, a directory full of jpeg files and proxy avis, so
- * sorry folks, please rebuild your proxies... */
-
- sanim = BLI_findlink(&seq->anims, view_id);
-
- if (ed->proxy_storage == SEQ_EDIT_PROXY_DIR_STORAGE) {
- char fname[FILE_MAXFILE];
- if (ed->proxy_dir[0] == 0)
- BLI_strncpy(dir, "//BL_proxy", sizeof(dir));
- else
- BLI_strncpy(dir, ed->proxy_dir, sizeof(dir));
-
- if (sanim && sanim->anim) {
- IMB_anim_get_fname(sanim->anim, fname, FILE_MAXFILE);
- }
- else if (seq->type == SEQ_TYPE_IMAGE) {
- fname[0] = 0;
- }
- else {
- /* We could make a name here, except non-movie's don't generate proxies,
- * cancel until other types of sequence strips are supported. */
- return false;
- }
- BLI_path_append(dir, sizeof(dir), fname);
- BLI_path_abs(name, BKE_main_blendfile_path_from_global());
- }
- else if ((proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR) && (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE)) {
- BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
- }
- else if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE) {
- BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
- }
- else if (sanim && sanim->anim && (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR)) {
- char fname[FILE_MAXFILE];
- BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
- IMB_anim_get_fname(sanim->anim, fname, FILE_MAXFILE);
- BLI_path_append(dir, sizeof(dir), fname);
- }
- else if (seq->type == SEQ_TYPE_IMAGE) {
- if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR)
- BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
- else
- BLI_snprintf(dir, PROXY_MAXFILE, "%s/BL_proxy", seq->strip->dir);
- }
- else {
- return false;
- }
-
- if (view_id > 0)
- BLI_snprintf(suffix, sizeof(suffix), "_%d", view_id);
-
- if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE &&
- ed->proxy_storage != SEQ_EDIT_PROXY_DIR_STORAGE)
- {
- char fname[FILE_MAXFILE];
- BLI_join_dirfile(fname, PROXY_MAXFILE, dir, proxy->file);
- BLI_path_abs(fname, BKE_main_blendfile_path_from_global());
- if (suffix[0] != '\0') {
- /* TODO(sergey): This will actually append suffix after extension
- * which is weird but how was originally coded in multiview branch.
- */
- BLI_snprintf(name, PROXY_MAXFILE, "%s_%s", fname, suffix);
- }
- else {
- BLI_strncpy(name, fname, PROXY_MAXFILE);
- }
-
- return true;
- }
-
- /* generate a separate proxy directory for each preview size */
-
- if (seq->type == SEQ_TYPE_IMAGE) {
- BLI_snprintf(name, PROXY_MAXFILE, "%s/images/%d/%s_proxy%s", dir, render_size,
- BKE_sequencer_give_stripelem(seq, cfra)->name, suffix);
- frameno = 1;
- }
- else {
- frameno = (int)give_stripelem_index(seq, cfra) + seq->anim_startofs;
- BLI_snprintf(name, PROXY_MAXFILE, "%s/proxy_misc/%d/####%s", dir, render_size, suffix);
- }
-
- BLI_path_abs(name, BKE_main_blendfile_path_from_global());
- BLI_path_frame(name, frameno, 0);
-
- strcat(name, ".jpg");
-
- return true;
+ char dir[FILE_MAX];
+ char name[FILE_MAX];
+ StripProxy *proxy;
+ bool use_proxy;
+ bool is_multiview_loaded = false;
+ Editing *ed = scene->ed;
+ const bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 &&
+ (scene->r.scemode & R_MULTIVIEW) != 0;
+
+ if ((seq->anims.first != NULL) && (((StripAnim *)seq->anims.first)->anim != NULL)) {
+ return;
+ }
+
+ /* reset all the previously created anims */
+ BKE_sequence_free_anim(seq);
+
+ BLI_join_dirfile(name, sizeof(name), seq->strip->dir, seq->strip->stripdata->name);
+ BLI_path_abs(name, BKE_main_blendfile_path_from_global());
+
+ proxy = seq->strip->proxy;
+
+ use_proxy = proxy && ((proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR) != 0 ||
+ (ed->proxy_storage == SEQ_EDIT_PROXY_DIR_STORAGE));
+
+ if (use_proxy) {
+ if (ed->proxy_storage == SEQ_EDIT_PROXY_DIR_STORAGE) {
+ if (ed->proxy_dir[0] == 0)
+ BLI_strncpy(dir, "//BL_proxy", sizeof(dir));
+ else
+ BLI_strncpy(dir, ed->proxy_dir, sizeof(dir));
+ }
+ else {
+ BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
+ }
+ BLI_path_abs(dir, BKE_main_blendfile_path_from_global());
+ }
+
+ if (is_multiview && seq->views_format == R_IMF_VIEWS_INDIVIDUAL) {
+ int totfiles = seq_num_files(scene, seq->views_format, true);
+ char prefix[FILE_MAX];
+ const char *ext = NULL;
+ int i;
+
+ BKE_scene_multiview_view_prefix_get(scene, name, prefix, &ext);
+
+ if (prefix[0] != '\0') {
+ for (i = 0; i < totfiles; i++) {
+ const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, i);
+ char str[FILE_MAX];
+ StripAnim *sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
+
+ BLI_addtail(&seq->anims, sanim);
+
+ BLI_snprintf(str, sizeof(str), "%s%s%s", prefix, suffix, ext);
+
+ if (openfile) {
+ sanim->anim = openanim(str,
+ IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex,
+ seq->strip->colorspace_settings.name);
+ }
+ else {
+ sanim->anim = openanim_noload(str,
+ IB_rect |
+ ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex,
+ seq->strip->colorspace_settings.name);
+ }
+
+ if (sanim->anim) {
+ /* we already have the suffix */
+ IMB_suffix_anim(sanim->anim, suffix);
+ }
+ else {
+ if (openfile) {
+ sanim->anim = openanim(name,
+ IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex,
+ seq->strip->colorspace_settings.name);
+ }
+ else {
+ sanim->anim = openanim_noload(name,
+ IB_rect |
+ ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex,
+ seq->strip->colorspace_settings.name);
+ }
+
+ /* no individual view files - monoscopic, stereo 3d or exr multiview */
+ totfiles = 1;
+ }
+
+ if (sanim->anim && use_proxy) {
+ seq_proxy_index_dir_set(sanim->anim, dir);
+ }
+ }
+ is_multiview_loaded = true;
+ }
+ }
+
+ if (is_multiview_loaded == false) {
+ StripAnim *sanim;
+
+ sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
+ BLI_addtail(&seq->anims, sanim);
+
+ if (openfile) {
+ sanim->anim = openanim(name,
+ IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex,
+ seq->strip->colorspace_settings.name);
+ }
+ else {
+ sanim->anim = openanim_noload(name,
+ IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex,
+ seq->strip->colorspace_settings.name);
+ }
+
+ if (sanim->anim && use_proxy) {
+ seq_proxy_index_dir_set(sanim->anim, dir);
+ }
+ }
+}
+
+static bool seq_proxy_get_fname(
+ Editing *ed, Sequence *seq, int cfra, int render_size, char *name, const int view_id)
+{
+ int frameno;
+ char dir[PROXY_MAXFILE];
+ StripAnim *sanim;
+ char suffix[24] = {'\0'};
+
+ StripProxy *proxy = seq->strip->proxy;
+ if (!proxy) {
+ return false;
+ }
+
+ /* MOVIE tracks (only exception: custom files) are now handled
+ * internally by ImBuf module for various reasons: proper time code
+ * support, quicker index build, using one file instead
+ * of a full directory of jpeg files, etc. Trying to support old
+ * and new method at once could lead to funny effects, if people
+ * have both, a directory full of jpeg files and proxy avis, so
+ * sorry folks, please rebuild your proxies... */
+
+ sanim = BLI_findlink(&seq->anims, view_id);
+
+ if (ed->proxy_storage == SEQ_EDIT_PROXY_DIR_STORAGE) {
+ char fname[FILE_MAXFILE];
+ if (ed->proxy_dir[0] == 0)
+ BLI_strncpy(dir, "//BL_proxy", sizeof(dir));
+ else
+ BLI_strncpy(dir, ed->proxy_dir, sizeof(dir));
+
+ if (sanim && sanim->anim) {
+ IMB_anim_get_fname(sanim->anim, fname, FILE_MAXFILE);
+ }
+ else if (seq->type == SEQ_TYPE_IMAGE) {
+ fname[0] = 0;
+ }
+ else {
+ /* We could make a name here, except non-movie's don't generate proxies,
+ * cancel until other types of sequence strips are supported. */
+ return false;
+ }
+ BLI_path_append(dir, sizeof(dir), fname);
+ BLI_path_abs(name, BKE_main_blendfile_path_from_global());
+ }
+ else if ((proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR) &&
+ (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE)) {
+ BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
+ }
+ else if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE) {
+ BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
+ }
+ else if (sanim && sanim->anim && (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR)) {
+ char fname[FILE_MAXFILE];
+ BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
+ IMB_anim_get_fname(sanim->anim, fname, FILE_MAXFILE);
+ BLI_path_append(dir, sizeof(dir), fname);
+ }
+ else if (seq->type == SEQ_TYPE_IMAGE) {
+ if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_DIR)
+ BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
+ else
+ BLI_snprintf(dir, PROXY_MAXFILE, "%s/BL_proxy", seq->strip->dir);
+ }
+ else {
+ return false;
+ }
+
+ if (view_id > 0)
+ BLI_snprintf(suffix, sizeof(suffix), "_%d", view_id);
+
+ if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE &&
+ ed->proxy_storage != SEQ_EDIT_PROXY_DIR_STORAGE) {
+ char fname[FILE_MAXFILE];
+ BLI_join_dirfile(fname, PROXY_MAXFILE, dir, proxy->file);
+ BLI_path_abs(fname, BKE_main_blendfile_path_from_global());
+ if (suffix[0] != '\0') {
+ /* TODO(sergey): This will actually append suffix after extension
+ * which is weird but how was originally coded in multiview branch.
+ */
+ BLI_snprintf(name, PROXY_MAXFILE, "%s_%s", fname, suffix);
+ }
+ else {
+ BLI_strncpy(name, fname, PROXY_MAXFILE);
+ }
+
+ return true;
+ }
+
+ /* generate a separate proxy directory for each preview size */
+
+ if (seq->type == SEQ_TYPE_IMAGE) {
+ BLI_snprintf(name,
+ PROXY_MAXFILE,
+ "%s/images/%d/%s_proxy%s",
+ dir,
+ render_size,
+ BKE_sequencer_give_stripelem(seq, cfra)->name,
+ suffix);
+ frameno = 1;
+ }
+ else {
+ frameno = (int)give_stripelem_index(seq, cfra) + seq->anim_startofs;
+ BLI_snprintf(name, PROXY_MAXFILE, "%s/proxy_misc/%d/####%s", dir, render_size, suffix);
+ }
+
+ BLI_path_abs(name, BKE_main_blendfile_path_from_global());
+ BLI_path_frame(name, frameno, 0);
+
+ strcat(name, ".jpg");
+
+ return true;
}
static ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int cfra)
{
- char name[PROXY_MAXFILE];
- IMB_Proxy_Size psize = seq_rendersize_to_proxysize(context->preview_render_size);
- int size_flags;
- int render_size = context->preview_render_size;
- StripProxy *proxy = seq->strip->proxy;
- Editing *ed = context->scene->ed;
- StripAnim *sanim;
-
- if (!(seq->flag & SEQ_USE_PROXY)) {
- return NULL;
- }
-
- /* dirty hack to distinguish 100% render size from PROXY_100 */
- if (render_size == 99) {
- render_size = 100;
- }
-
- size_flags = proxy->build_size_flags;
-
- /* only use proxies, if they are enabled (even if present!) */
- if (psize == IMB_PROXY_NONE || ((size_flags & psize) != psize)) {
- return NULL;
- }
-
- if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE) {
- int frameno = (int)give_stripelem_index(seq, cfra) + seq->anim_startofs;
- if (proxy->anim == NULL) {
- if (seq_proxy_get_fname(ed, seq, cfra, render_size, name, context->view_id) == 0) {
- return NULL;
- }
-
- proxy->anim = openanim(name, IB_rect, 0, seq->strip->colorspace_settings.name);
- }
- if (proxy->anim == NULL) {
- return NULL;
- }
-
- seq_open_anim_file(context->scene, seq, true);
- sanim = seq->anims.first;
-
- frameno = IMB_anim_index_get_frame_index(sanim ? sanim->anim : NULL, seq->strip->proxy->tc, frameno);
-
- return IMB_anim_absolute(proxy->anim, frameno, IMB_TC_NONE, IMB_PROXY_NONE);
- }
-
- if (seq_proxy_get_fname(ed, seq, cfra, render_size, name, context->view_id) == 0) {
- return NULL;
- }
-
- if (BLI_exists(name)) {
- ImBuf *ibuf = IMB_loadiffname(name, IB_rect, NULL);
-
- if (ibuf)
- sequencer_imbuf_assign_spaces(context->scene, ibuf);
-
- return ibuf;
- }
- else {
- return NULL;
- }
-}
-
-static void seq_proxy_build_frame(
- const SeqRenderData *context, SeqRenderState *state,
- Sequence *seq, int cfra,
- int proxy_render_size, const bool overwrite)
-{
- char name[PROXY_MAXFILE];
- int quality;
- int rectx, recty;
- int ok;
- ImBuf *ibuf_tmp, *ibuf;
- Editing *ed = context->scene->ed;
-
- if (!seq_proxy_get_fname(ed, seq, cfra, proxy_render_size, name, context->view_id)) {
- return;
- }
-
- if (!overwrite && BLI_exists(name)) {
- return;
- }
+ char name[PROXY_MAXFILE];
+ IMB_Proxy_Size psize = seq_rendersize_to_proxysize(context->preview_render_size);
+ int size_flags;
+ int render_size = context->preview_render_size;
+ StripProxy *proxy = seq->strip->proxy;
+ Editing *ed = context->scene->ed;
+ StripAnim *sanim;
+
+ if (!(seq->flag & SEQ_USE_PROXY)) {
+ return NULL;
+ }
+
+ /* dirty hack to distinguish 100% render size from PROXY_100 */
+ if (render_size == 99) {
+ render_size = 100;
+ }
+
+ size_flags = proxy->build_size_flags;
+
+ /* only use proxies, if they are enabled (even if present!) */
+ if (psize == IMB_PROXY_NONE || ((size_flags & psize) != psize)) {
+ return NULL;
+ }
+
+ if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE) {
+ int frameno = (int)give_stripelem_index(seq, cfra) + seq->anim_startofs;
+ if (proxy->anim == NULL) {
+ if (seq_proxy_get_fname(ed, seq, cfra, render_size, name, context->view_id) == 0) {
+ return NULL;
+ }
+
+ proxy->anim = openanim(name, IB_rect, 0, seq->strip->colorspace_settings.name);
+ }
+ if (proxy->anim == NULL) {
+ return NULL;
+ }
+
+ seq_open_anim_file(context->scene, seq, true);
+ sanim = seq->anims.first;
+
+ frameno = IMB_anim_index_get_frame_index(
+ sanim ? sanim->anim : NULL, seq->strip->proxy->tc, frameno);
+
+ return IMB_anim_absolute(proxy->anim, frameno, IMB_TC_NONE, IMB_PROXY_NONE);
+ }
+
+ if (seq_proxy_get_fname(ed, seq, cfra, render_size, name, context->view_id) == 0) {
+ return NULL;
+ }
+
+ if (BLI_exists(name)) {
+ ImBuf *ibuf = IMB_loadiffname(name, IB_rect, NULL);
+
+ if (ibuf)
+ sequencer_imbuf_assign_spaces(context->scene, ibuf);
+
+ return ibuf;
+ }
+ else {
+ return NULL;
+ }
+}
+
+static void seq_proxy_build_frame(const SeqRenderData *context,
+ SeqRenderState *state,
+ Sequence *seq,
+ int cfra,
+ int proxy_render_size,
+ const bool overwrite)
+{
+ char name[PROXY_MAXFILE];
+ int quality;
+ int rectx, recty;
+ int ok;
+ ImBuf *ibuf_tmp, *ibuf;
+ Editing *ed = context->scene->ed;
+
+ if (!seq_proxy_get_fname(ed, seq, cfra, proxy_render_size, name, context->view_id)) {
+ return;
+ }
+
+ if (!overwrite && BLI_exists(name)) {
+ return;
+ }
+
+ ibuf_tmp = seq_render_strip(context, state, seq, cfra);
+
+ rectx = (proxy_render_size * ibuf_tmp->x) / 100;
+ recty = (proxy_render_size * ibuf_tmp->y) / 100;
+
+ if (ibuf_tmp->x != rectx || ibuf_tmp->y != recty) {
+ ibuf = IMB_dupImBuf(ibuf_tmp);
+ IMB_metadata_copy(ibuf, ibuf_tmp);
+ IMB_freeImBuf(ibuf_tmp);
+ IMB_scalefastImBuf(ibuf, (short)rectx, (short)recty);
+ }
+ else {
+ ibuf = ibuf_tmp;
+ }
+
+ /* depth = 32 is intentionally left in, otherwise ALPHA channels
+ * won't work... */
+ quality = seq->strip->proxy->quality;
+ ibuf->ftype = IMB_FTYPE_JPG;
+ ibuf->foptions.quality = quality;
- ibuf_tmp = seq_render_strip(context, state, seq, cfra);
+ /* unsupported feature only confuses other s/w */
+ if (ibuf->planes == 32)
+ ibuf->planes = 24;
- rectx = (proxy_render_size * ibuf_tmp->x) / 100;
- recty = (proxy_render_size * ibuf_tmp->y) / 100;
+ BLI_make_existing_file(name);
- if (ibuf_tmp->x != rectx || ibuf_tmp->y != recty) {
- ibuf = IMB_dupImBuf(ibuf_tmp);
- IMB_metadata_copy(ibuf, ibuf_tmp);
- IMB_freeImBuf(ibuf_tmp);
- IMB_scalefastImBuf(ibuf, (short)rectx, (short)recty);
- }
- else {
- ibuf = ibuf_tmp;
- }
+ ok = IMB_saveiff(ibuf, name, IB_rect | IB_zbuf | IB_zbuffloat);
+ if (ok == 0) {
+ perror(name);
+ }
- /* depth = 32 is intentionally left in, otherwise ALPHA channels
- * won't work... */
- quality = seq->strip->proxy->quality;
- ibuf->ftype = IMB_FTYPE_JPG;
- ibuf->foptions.quality = quality;
-
- /* unsupported feature only confuses other s/w */
- if (ibuf->planes == 32)
- ibuf->planes = 24;
-
- BLI_make_existing_file(name);
-
- ok = IMB_saveiff(ibuf, name, IB_rect | IB_zbuf | IB_zbuffloat);
- if (ok == 0) {
- perror(name);
- }
-
- IMB_freeImBuf(ibuf);
+ IMB_freeImBuf(ibuf);
}
/**
@@ -1862,36 +1949,35 @@ static void seq_proxy_build_frame(
*/
static bool seq_proxy_multiview_context_invalid(Sequence *seq, Scene *scene, const int view_id)
{
- if ((scene->r.scemode & R_MULTIVIEW) == 0)
- return false;
+ if ((scene->r.scemode & R_MULTIVIEW) == 0)
+ return false;
- if ((seq->type == SEQ_TYPE_IMAGE) && (seq->views_format == R_IMF_VIEWS_INDIVIDUAL)) {
- static char prefix[FILE_MAX];
- static const char *ext = NULL;
- char str[FILE_MAX];
+ if ((seq->type == SEQ_TYPE_IMAGE) && (seq->views_format == R_IMF_VIEWS_INDIVIDUAL)) {
+ static char prefix[FILE_MAX];
+ static const char *ext = NULL;
+ char str[FILE_MAX];
- if (view_id == 0) {
- char path[FILE_MAX];
- BLI_join_dirfile(path, sizeof(path), seq->strip->dir,
- seq->strip->stripdata->name);
- BLI_path_abs(path, BKE_main_blendfile_path_from_global());
- BKE_scene_multiview_view_prefix_get(scene, path, prefix, &ext);
- }
- else {
- prefix[0] = '\0';
- }
+ if (view_id == 0) {
+ char path[FILE_MAX];
+ BLI_join_dirfile(path, sizeof(path), seq->strip->dir, seq->strip->stripdata->name);
+ BLI_path_abs(path, BKE_main_blendfile_path_from_global());
+ BKE_scene_multiview_view_prefix_get(scene, path, prefix, &ext);
+ }
+ else {
+ prefix[0] = '\0';
+ }
- if (prefix[0] == '\0')
- return view_id != 0;
+ if (prefix[0] == '\0')
+ return view_id != 0;
- seq_multiview_name(scene, view_id, prefix, ext, str, FILE_MAX);
+ seq_multiview_name(scene, view_id, prefix, ext, str, FILE_MAX);
- if (BLI_access(str, R_OK) == 0)
- return false;
- else
- return view_id != 0;
- }
- return false;
+ if (BLI_access(str, R_OK) == 0)
+ return false;
+ else
+ return view_id != 0;
+ }
+ return false;
}
/**
@@ -1899,504 +1985,542 @@ static bool seq_proxy_multiview_context_invalid(Sequence *seq, Scene *scene, con
*/
static int seq_proxy_context_count(Sequence *seq, Scene *scene)
{
- int num_views = 1;
-
- if ((scene->r.scemode & R_MULTIVIEW) == 0)
- return 1;
-
- switch (seq->type) {
- case SEQ_TYPE_MOVIE:
- {
- num_views = BLI_listbase_count(&seq->anims);
- break;
- }
- case SEQ_TYPE_IMAGE:
- {
- switch (seq->views_format) {
- case R_IMF_VIEWS_INDIVIDUAL:
- num_views = BKE_scene_multiview_num_views_get(&scene->r);
- break;
- case R_IMF_VIEWS_STEREO_3D:
- num_views = 2;
- break;
- case R_IMF_VIEWS_MULTIVIEW:
- /* not supported at the moment */
- /* pass through */
- default:
- num_views = 1;
- }
- break;
- }
- }
-
- return num_views;
-}
-
-void BKE_sequencer_proxy_rebuild_context(
- Main *bmain, Depsgraph *depsgraph, Scene *scene,
- Sequence *seq, struct GSet *file_list, ListBase *queue)
-{
- SeqIndexBuildContext *context;
- Sequence *nseq;
- LinkData *link;
- int num_files;
- int i;
-
- if (!seq->strip || !seq->strip->proxy) {
- return;
- }
-
- if (!(seq->flag & SEQ_USE_PROXY)) {
- return;
- }
-
- num_files = seq_proxy_context_count(seq, scene);
-
- for (i = 0; i < num_files; i++) {
- if (seq_proxy_multiview_context_invalid(seq, scene, i))
- continue;
-
- context = MEM_callocN(sizeof(SeqIndexBuildContext), "seq proxy rebuild context");
-
- nseq = BKE_sequence_dupli_recursive(scene, scene, NULL, seq, 0);
-
- context->tc_flags = nseq->strip->proxy->build_tc_flags;
- context->size_flags = nseq->strip->proxy->build_size_flags;
- context->quality = nseq->strip->proxy->quality;
- context->overwrite = (nseq->strip->proxy->build_flags & SEQ_PROXY_SKIP_EXISTING) == 0;
-
- context->bmain = bmain;
- context->depsgraph = depsgraph;
- context->scene = scene;
- context->orig_seq = seq;
- context->seq = nseq;
-
- context->view_id = i; /* only for images */
-
- link = BLI_genericNodeN(context);
- BLI_addtail(queue, link);
-
- if (nseq->type == SEQ_TYPE_MOVIE) {
- StripAnim *sanim;
-
- seq_open_anim_file(scene, nseq, true);
- sanim = BLI_findlink(&nseq->anims, i);
-
- if (sanim->anim) {
- context->index_context = IMB_anim_index_rebuild_context(sanim->anim,
- context->tc_flags, context->size_flags, context->quality,
- context->overwrite, file_list);
- }
- }
- }
-}
-
-void BKE_sequencer_proxy_rebuild(SeqIndexBuildContext *context, short *stop, short *do_update, float *progress)
-{
- const bool overwrite = context->overwrite;
- SeqRenderData render_context;
- Sequence *seq = context->seq;
- Scene *scene = context->scene;
- Main *bmain = context->bmain;
- int cfra;
-
- if (seq->type == SEQ_TYPE_MOVIE) {
- if (context->index_context) {
- IMB_anim_index_rebuild(context->index_context, stop, do_update, progress);
- }
-
- return;
- }
-
- if (!(seq->flag & SEQ_USE_PROXY)) {
- return;
- }
-
- /* that's why it is called custom... */
- if (seq->strip->proxy && seq->strip->proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE) {
- return;
- }
-
- /* fail safe code */
-
- BKE_sequencer_new_render_data(
- bmain, context->depsgraph, context->scene,
- (scene->r.size * (float) scene->r.xsch) / 100.0f + 0.5f,
- (scene->r.size * (float) scene->r.ysch) / 100.0f + 0.5f, 100,
- false,
- &render_context);
-
- render_context.skip_cache = true;
- render_context.is_proxy_render = true;
- render_context.view_id = context->view_id;
-
- SeqRenderState state;
- sequencer_state_init(&state);
-
- for (cfra = seq->startdisp + seq->startstill; cfra < seq->enddisp - seq->endstill; cfra++) {
- if (context->size_flags & IMB_PROXY_25) {
- seq_proxy_build_frame(&render_context, &state, seq, cfra, 25, overwrite);
- }
- if (context->size_flags & IMB_PROXY_50) {
- seq_proxy_build_frame(&render_context, &state, seq, cfra, 50, overwrite);
- }
- if (context->size_flags & IMB_PROXY_75) {
- seq_proxy_build_frame(&render_context, &state, seq, cfra, 75, overwrite);
- }
- if (context->size_flags & IMB_PROXY_100) {
- seq_proxy_build_frame(&render_context, &state, seq, cfra, 100, overwrite);
- }
-
- *progress = (float) (cfra - seq->startdisp - seq->startstill) / (seq->enddisp - seq->endstill - seq->startdisp - seq->startstill);
- *do_update = true;
-
- if (*stop || G.is_break)
- break;
- }
+ int num_views = 1;
+
+ if ((scene->r.scemode & R_MULTIVIEW) == 0)
+ return 1;
+
+ switch (seq->type) {
+ case SEQ_TYPE_MOVIE: {
+ num_views = BLI_listbase_count(&seq->anims);
+ break;
+ }
+ case SEQ_TYPE_IMAGE: {
+ switch (seq->views_format) {
+ case R_IMF_VIEWS_INDIVIDUAL:
+ num_views = BKE_scene_multiview_num_views_get(&scene->r);
+ break;
+ case R_IMF_VIEWS_STEREO_3D:
+ num_views = 2;
+ break;
+ case R_IMF_VIEWS_MULTIVIEW:
+ /* not supported at the moment */
+ /* pass through */
+ default:
+ num_views = 1;
+ }
+ break;
+ }
+ }
+
+ return num_views;
+}
+
+void BKE_sequencer_proxy_rebuild_context(Main *bmain,
+ Depsgraph *depsgraph,
+ Scene *scene,
+ Sequence *seq,
+ struct GSet *file_list,
+ ListBase *queue)
+{
+ SeqIndexBuildContext *context;
+ Sequence *nseq;
+ LinkData *link;
+ int num_files;
+ int i;
+
+ if (!seq->strip || !seq->strip->proxy) {
+ return;
+ }
+
+ if (!(seq->flag & SEQ_USE_PROXY)) {
+ return;
+ }
+
+ num_files = seq_proxy_context_count(seq, scene);
+
+ for (i = 0; i < num_files; i++) {
+ if (seq_proxy_multiview_context_invalid(seq, scene, i))
+ continue;
+
+ context = MEM_callocN(sizeof(SeqIndexBuildContext), "seq proxy rebuild context");
+
+ nseq = BKE_sequence_dupli_recursive(scene, scene, NULL, seq, 0);
+
+ context->tc_flags = nseq->strip->proxy->build_tc_flags;
+ context->size_flags = nseq->strip->proxy->build_size_flags;
+ context->quality = nseq->strip->proxy->quality;
+ context->overwrite = (nseq->strip->proxy->build_flags & SEQ_PROXY_SKIP_EXISTING) == 0;
+
+ context->bmain = bmain;
+ context->depsgraph = depsgraph;
+ context->scene = scene;
+ context->orig_seq = seq;
+ context->seq = nseq;
+
+ context->view_id = i; /* only for images */
+
+ link = BLI_genericNodeN(context);
+ BLI_addtail(queue, link);
+
+ if (nseq->type == SEQ_TYPE_MOVIE) {
+ StripAnim *sanim;
+
+ seq_open_anim_file(scene, nseq, true);
+ sanim = BLI_findlink(&nseq->anims, i);
+
+ if (sanim->anim) {
+ context->index_context = IMB_anim_index_rebuild_context(sanim->anim,
+ context->tc_flags,
+ context->size_flags,
+ context->quality,
+ context->overwrite,
+ file_list);
+ }
+ }
+ }
+}
+
+void BKE_sequencer_proxy_rebuild(SeqIndexBuildContext *context,
+ short *stop,
+ short *do_update,
+ float *progress)
+{
+ const bool overwrite = context->overwrite;
+ SeqRenderData render_context;
+ Sequence *seq = context->seq;
+ Scene *scene = context->scene;
+ Main *bmain = context->bmain;
+ int cfra;
+
+ if (seq->type == SEQ_TYPE_MOVIE) {
+ if (context->index_context) {
+ IMB_anim_index_rebuild(context->index_context, stop, do_update, progress);
+ }
+
+ return;
+ }
+
+ if (!(seq->flag & SEQ_USE_PROXY)) {
+ return;
+ }
+
+ /* that's why it is called custom... */
+ if (seq->strip->proxy && seq->strip->proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE) {
+ return;
+ }
+
+ /* fail safe code */
+
+ BKE_sequencer_new_render_data(bmain,
+ context->depsgraph,
+ context->scene,
+ (scene->r.size * (float)scene->r.xsch) / 100.0f + 0.5f,
+ (scene->r.size * (float)scene->r.ysch) / 100.0f + 0.5f,
+ 100,
+ false,
+ &render_context);
+
+ render_context.skip_cache = true;
+ render_context.is_proxy_render = true;
+ render_context.view_id = context->view_id;
+
+ SeqRenderState state;
+ sequencer_state_init(&state);
+
+ for (cfra = seq->startdisp + seq->startstill; cfra < seq->enddisp - seq->endstill; cfra++) {
+ if (context->size_flags & IMB_PROXY_25) {
+ seq_proxy_build_frame(&render_context, &state, seq, cfra, 25, overwrite);
+ }
+ if (context->size_flags & IMB_PROXY_50) {
+ seq_proxy_build_frame(&render_context, &state, seq, cfra, 50, overwrite);
+ }
+ if (context->size_flags & IMB_PROXY_75) {
+ seq_proxy_build_frame(&render_context, &state, seq, cfra, 75, overwrite);
+ }
+ if (context->size_flags & IMB_PROXY_100) {
+ seq_proxy_build_frame(&render_context, &state, seq, cfra, 100, overwrite);
+ }
+
+ *progress = (float)(cfra - seq->startdisp - seq->startstill) /
+ (seq->enddisp - seq->endstill - seq->startdisp - seq->startstill);
+ *do_update = true;
+
+ if (*stop || G.is_break)
+ break;
+ }
}
void BKE_sequencer_proxy_rebuild_finish(SeqIndexBuildContext *context, bool stop)
{
- if (context->index_context) {
- StripAnim *sanim;
+ if (context->index_context) {
+ StripAnim *sanim;
- for (sanim = context->seq->anims.first; sanim; sanim = sanim->next)
- IMB_close_anim_proxies(sanim->anim);
+ for (sanim = context->seq->anims.first; sanim; sanim = sanim->next)
+ IMB_close_anim_proxies(sanim->anim);
- for (sanim = context->orig_seq->anims.first; sanim; sanim = sanim->next)
- IMB_close_anim_proxies(sanim->anim);
+ for (sanim = context->orig_seq->anims.first; sanim; sanim = sanim->next)
+ IMB_close_anim_proxies(sanim->anim);
- IMB_anim_index_rebuild_finish(context->index_context, stop);
- }
+ IMB_anim_index_rebuild_finish(context->index_context, stop);
+ }
- seq_free_sequence_recurse(NULL, context->seq, true);
+ seq_free_sequence_recurse(NULL, context->seq, true);
- MEM_freeN(context);
+ MEM_freeN(context);
}
void BKE_sequencer_proxy_set(struct Sequence *seq, bool value)
{
- if (value) {
- seq->flag |= SEQ_USE_PROXY;
- if (seq->strip->proxy == NULL) {
- seq->strip->proxy = MEM_callocN(sizeof(struct StripProxy), "StripProxy");
- seq->strip->proxy->quality = 90;
- seq->strip->proxy->build_tc_flags = SEQ_PROXY_TC_ALL;
- seq->strip->proxy->build_size_flags = SEQ_PROXY_IMAGE_SIZE_25;
- }
- }
- else {
- seq->flag &= ~SEQ_USE_PROXY;
- }
+ if (value) {
+ seq->flag |= SEQ_USE_PROXY;
+ if (seq->strip->proxy == NULL) {
+ seq->strip->proxy = MEM_callocN(sizeof(struct StripProxy), "StripProxy");
+ seq->strip->proxy->quality = 90;
+ seq->strip->proxy->build_tc_flags = SEQ_PROXY_TC_ALL;
+ seq->strip->proxy->build_size_flags = SEQ_PROXY_IMAGE_SIZE_25;
+ }
+ }
+ else {
+ seq->flag &= ~SEQ_USE_PROXY;
+ }
}
/*********************** color balance *************************/
static StripColorBalance calc_cb(StripColorBalance *cb_)
{
- StripColorBalance cb = *cb_;
- int c;
-
- for (c = 0; c < 3; c++) {
- cb.lift[c] = 2.0f - cb.lift[c];
- }
-
- if (cb.flag & SEQ_COLOR_BALANCE_INVERSE_LIFT) {
- for (c = 0; c < 3; c++) {
- /* tweak to give more subtle results
- * values above 1.0 are scaled */
- if (cb.lift[c] > 1.0f)
- cb.lift[c] = pow(cb.lift[c] - 1.0f, 2.0) + 1.0;
-
- cb.lift[c] = 2.0f - cb.lift[c];
- }
- }
-
- if (cb.flag & SEQ_COLOR_BALANCE_INVERSE_GAIN) {
- for (c = 0; c < 3; c++) {
- if (cb.gain[c] != 0.0f) {
- cb.gain[c] = 1.0f / cb.gain[c];
- }
- else {
- cb.gain[c] = 1000000; /* should be enough :) */
- }
- }
- }
-
- if (!(cb.flag & SEQ_COLOR_BALANCE_INVERSE_GAMMA)) {
- for (c = 0; c < 3; c++) {
- if (cb.gamma[c] != 0.0f) {
- cb.gamma[c] = 1.0f / cb.gamma[c];
- }
- else {
- cb.gamma[c] = 1000000; /* should be enough :) */
- }
- }
- }
-
- return cb;
+ StripColorBalance cb = *cb_;
+ int c;
+
+ for (c = 0; c < 3; c++) {
+ cb.lift[c] = 2.0f - cb.lift[c];
+ }
+
+ if (cb.flag & SEQ_COLOR_BALANCE_INVERSE_LIFT) {
+ for (c = 0; c < 3; c++) {
+ /* tweak to give more subtle results
+ * values above 1.0 are scaled */
+ if (cb.lift[c] > 1.0f)
+ cb.lift[c] = pow(cb.lift[c] - 1.0f, 2.0) + 1.0;
+
+ cb.lift[c] = 2.0f - cb.lift[c];
+ }
+ }
+
+ if (cb.flag & SEQ_COLOR_BALANCE_INVERSE_GAIN) {
+ for (c = 0; c < 3; c++) {
+ if (cb.gain[c] != 0.0f) {
+ cb.gain[c] = 1.0f / cb.gain[c];
+ }
+ else {
+ cb.gain[c] = 1000000; /* should be enough :) */
+ }
+ }
+ }
+
+ if (!(cb.flag & SEQ_COLOR_BALANCE_INVERSE_GAMMA)) {
+ for (c = 0; c < 3; c++) {
+ if (cb.gamma[c] != 0.0f) {
+ cb.gamma[c] = 1.0f / cb.gamma[c];
+ }
+ else {
+ cb.gamma[c] = 1000000; /* should be enough :) */
+ }
+ }
+ }
+
+ return cb;
}
/* note: lift is actually 2-lift */
-MINLINE float color_balance_fl(float in, const float lift, const float gain, const float gamma, const float mul)
+MINLINE float color_balance_fl(
+ float in, const float lift, const float gain, const float gamma, const float mul)
{
- float x = (((in - 1.0f) * lift) + 1.0f) * gain;
+ float x = (((in - 1.0f) * lift) + 1.0f) * gain;
- /* prevent NaN */
- if (x < 0.f)
- x = 0.f;
+ /* prevent NaN */
+ if (x < 0.f)
+ x = 0.f;
- return powf(x, gamma) * mul;
+ return powf(x, gamma) * mul;
}
-static void make_cb_table_float(float lift, float gain, float gamma,
- float *table, float mul)
+static void make_cb_table_float(float lift, float gain, float gamma, float *table, float mul)
{
- int y;
+ int y;
- for (y = 0; y < 256; y++) {
- float v = color_balance_fl((float)y * (1.0f / 255.0f), lift, gain, gamma, mul);
+ for (y = 0; y < 256; y++) {
+ float v = color_balance_fl((float)y * (1.0f / 255.0f), lift, gain, gamma, mul);
- table[y] = v;
- }
+ table[y] = v;
+ }
}
-static void color_balance_byte_byte(StripColorBalance *cb_, unsigned char *rect, unsigned char *mask_rect, int width, int height, float mul)
+static void color_balance_byte_byte(StripColorBalance *cb_,
+ unsigned char *rect,
+ unsigned char *mask_rect,
+ int width,
+ int height,
+ float mul)
{
- //unsigned char cb_tab[3][256];
- unsigned char *cp = rect;
- unsigned char *e = cp + width * 4 * height;
- unsigned char *m = mask_rect;
+ //unsigned char cb_tab[3][256];
+ unsigned char *cp = rect;
+ unsigned char *e = cp + width * 4 * height;
+ unsigned char *m = mask_rect;
- StripColorBalance cb = calc_cb(cb_);
+ StripColorBalance cb = calc_cb(cb_);
- while (cp < e) {
- float p[4];
- int c;
+ while (cp < e) {
+ float p[4];
+ int c;
- straight_uchar_to_premul_float(p, cp);
+ straight_uchar_to_premul_float(p, cp);
- for (c = 0; c < 3; c++) {
- float t = color_balance_fl(p[c], cb.lift[c], cb.gain[c], cb.gamma[c], mul);
+ for (c = 0; c < 3; c++) {
+ float t = color_balance_fl(p[c], cb.lift[c], cb.gain[c], cb.gamma[c], mul);
- if (m) {
- float m_normal = (float) m[c] / 255.0f;
+ if (m) {
+ float m_normal = (float)m[c] / 255.0f;
- p[c] = p[c] * (1.0f - m_normal) + t * m_normal;
- }
- else
- p[c] = t;
- }
+ p[c] = p[c] * (1.0f - m_normal) + t * m_normal;
+ }
+ else
+ p[c] = t;
+ }
- premul_float_to_straight_uchar(cp, p);
+ premul_float_to_straight_uchar(cp, p);
- cp += 4;
- if (m)
- m += 4;
- }
+ cp += 4;
+ if (m)
+ m += 4;
+ }
}
-static void color_balance_byte_float(StripColorBalance *cb_, unsigned char *rect, float *rect_float, unsigned char *mask_rect, int width, int height, float mul)
+static void color_balance_byte_float(StripColorBalance *cb_,
+ unsigned char *rect,
+ float *rect_float,
+ unsigned char *mask_rect,
+ int width,
+ int height,
+ float mul)
{
- float cb_tab[4][256];
- int c, i;
- unsigned char *p = rect;
- unsigned char *e = p + width * 4 * height;
- unsigned char *m = mask_rect;
- float *o;
- StripColorBalance cb;
+ float cb_tab[4][256];
+ int c, i;
+ unsigned char *p = rect;
+ unsigned char *e = p + width * 4 * height;
+ unsigned char *m = mask_rect;
+ float *o;
+ StripColorBalance cb;
- o = rect_float;
+ o = rect_float;
- cb = calc_cb(cb_);
+ cb = calc_cb(cb_);
- for (c = 0; c < 3; c++) {
- make_cb_table_float(cb.lift[c], cb.gain[c], cb.gamma[c], cb_tab[c], mul);
- }
+ for (c = 0; c < 3; c++) {
+ make_cb_table_float(cb.lift[c], cb.gain[c], cb.gamma[c], cb_tab[c], mul);
+ }
- for (i = 0; i < 256; i++) {
- cb_tab[3][i] = ((float)i) * (1.0f / 255.0f);
- }
+ for (i = 0; i < 256; i++) {
+ cb_tab[3][i] = ((float)i) * (1.0f / 255.0f);
+ }
- while (p < e) {
- if (m) {
- float t[3] = {m[0] / 255.0f, m[1] / 255.0f, m[2] / 255.0f};
+ while (p < e) {
+ if (m) {
+ float t[3] = {m[0] / 255.0f, m[1] / 255.0f, m[2] / 255.0f};
- p[0] = p[0] * (1.0f - t[0]) + t[0] * cb_tab[0][p[0]];
- p[1] = p[1] * (1.0f - t[1]) + t[1] * cb_tab[1][p[1]];
- p[2] = p[2] * (1.0f - t[2]) + t[2] * cb_tab[2][p[2]];
+ p[0] = p[0] * (1.0f - t[0]) + t[0] * cb_tab[0][p[0]];
+ p[1] = p[1] * (1.0f - t[1]) + t[1] * cb_tab[1][p[1]];
+ p[2] = p[2] * (1.0f - t[2]) + t[2] * cb_tab[2][p[2]];
- m += 4;
- }
- else {
- o[0] = cb_tab[0][p[0]];
- o[1] = cb_tab[1][p[1]];
- o[2] = cb_tab[2][p[2]];
- }
+ m += 4;
+ }
+ else {
+ o[0] = cb_tab[0][p[0]];
+ o[1] = cb_tab[1][p[1]];
+ o[2] = cb_tab[2][p[2]];
+ }
- o[3] = cb_tab[3][p[3]];
+ o[3] = cb_tab[3][p[3]];
- p += 4; o += 4;
- }
+ p += 4;
+ o += 4;
+ }
}
-static void color_balance_float_float(StripColorBalance *cb_, float *rect_float, float *mask_rect_float, int width, int height, float mul)
+static void color_balance_float_float(StripColorBalance *cb_,
+ float *rect_float,
+ float *mask_rect_float,
+ int width,
+ int height,
+ float mul)
{
- float *p = rect_float;
- const float *e = rect_float + width * 4 * height;
- const float *m = mask_rect_float;
- StripColorBalance cb = calc_cb(cb_);
+ float *p = rect_float;
+ const float *e = rect_float + width * 4 * height;
+ const float *m = mask_rect_float;
+ StripColorBalance cb = calc_cb(cb_);
- while (p < e) {
- int c;
- for (c = 0; c < 3; c++) {
- float t = color_balance_fl(p[c], cb.lift[c], cb.gain[c], cb.gamma[c], mul);
+ while (p < e) {
+ int c;
+ for (c = 0; c < 3; c++) {
+ float t = color_balance_fl(p[c], cb.lift[c], cb.gain[c], cb.gamma[c], mul);
- if (m)
- p[c] = p[c] * (1.0f - m[c]) + t * m[c];
- else
- p[c] = t;
- }
+ if (m)
+ p[c] = p[c] * (1.0f - m[c]) + t * m[c];
+ else
+ p[c] = t;
+ }
- p += 4;
- if (m)
- m += 4;
- }
+ p += 4;
+ if (m)
+ m += 4;
+ }
}
typedef struct ColorBalanceInitData {
- StripColorBalance *cb;
- ImBuf *ibuf;
- float mul;
- ImBuf *mask;
- bool make_float;
+ StripColorBalance *cb;
+ ImBuf *ibuf;
+ float mul;
+ ImBuf *mask;
+ bool make_float;
} ColorBalanceInitData;
typedef struct ColorBalanceThread {
- StripColorBalance *cb;
- float mul;
+ StripColorBalance *cb;
+ float mul;
- int width, height;
+ int width, height;
- unsigned char *rect, *mask_rect;
- float *rect_float, *mask_rect_float;
+ unsigned char *rect, *mask_rect;
+ float *rect_float, *mask_rect_float;
- bool make_float;
+ bool make_float;
} ColorBalanceThread;
-static void color_balance_init_handle(void *handle_v, int start_line, int tot_line, void *init_data_v)
+static void color_balance_init_handle(void *handle_v,
+ int start_line,
+ int tot_line,
+ void *init_data_v)
{
- ColorBalanceThread *handle = (ColorBalanceThread *) handle_v;
- ColorBalanceInitData *init_data = (ColorBalanceInitData *) init_data_v;
- ImBuf *ibuf = init_data->ibuf;
- ImBuf *mask = init_data->mask;
+ ColorBalanceThread *handle = (ColorBalanceThread *)handle_v;
+ ColorBalanceInitData *init_data = (ColorBalanceInitData *)init_data_v;
+ ImBuf *ibuf = init_data->ibuf;
+ ImBuf *mask = init_data->mask;
- int offset = 4 * start_line * ibuf->x;
+ int offset = 4 * start_line * ibuf->x;
- memset(handle, 0, sizeof(ColorBalanceThread));
+ memset(handle, 0, sizeof(ColorBalanceThread));
- handle->cb = init_data->cb;
- handle->mul = init_data->mul;
- handle->width = ibuf->x;
- handle->height = tot_line;
- handle->make_float = init_data->make_float;
+ handle->cb = init_data->cb;
+ handle->mul = init_data->mul;
+ handle->width = ibuf->x;
+ handle->height = tot_line;
+ handle->make_float = init_data->make_float;
- if (ibuf->rect)
- handle->rect = (unsigned char *) ibuf->rect + offset;
+ if (ibuf->rect)
+ handle->rect = (unsigned char *)ibuf->rect + offset;
- if (ibuf->rect_float)
- handle->rect_float = ibuf->rect_float + offset;
+ if (ibuf->rect_float)
+ handle->rect_float = ibuf->rect_float + offset;
- if (mask) {
- if (mask->rect)
- handle->mask_rect = (unsigned char *) mask->rect + offset;
+ if (mask) {
+ if (mask->rect)
+ handle->mask_rect = (unsigned char *)mask->rect + offset;
- if (mask->rect_float)
- handle->mask_rect_float = mask->rect_float + offset;
- }
- else {
- handle->mask_rect = NULL;
- handle->mask_rect_float = NULL;
- }
+ if (mask->rect_float)
+ handle->mask_rect_float = mask->rect_float + offset;
+ }
+ else {
+ handle->mask_rect = NULL;
+ handle->mask_rect_float = NULL;
+ }
}
static void *color_balance_do_thread(void *thread_data_v)
{
- ColorBalanceThread *thread_data = (ColorBalanceThread *) thread_data_v;
- StripColorBalance *cb = thread_data->cb;
- int width = thread_data->width, height = thread_data->height;
- unsigned char *rect = thread_data->rect;
- unsigned char *mask_rect = thread_data->mask_rect;
- float *rect_float = thread_data->rect_float;
- float *mask_rect_float = thread_data->mask_rect_float;
- float mul = thread_data->mul;
+ ColorBalanceThread *thread_data = (ColorBalanceThread *)thread_data_v;
+ StripColorBalance *cb = thread_data->cb;
+ int width = thread_data->width, height = thread_data->height;
+ unsigned char *rect = thread_data->rect;
+ unsigned char *mask_rect = thread_data->mask_rect;
+ float *rect_float = thread_data->rect_float;
+ float *mask_rect_float = thread_data->mask_rect_float;
+ float mul = thread_data->mul;
- if (rect_float) {
- color_balance_float_float(cb, rect_float, mask_rect_float, width, height, mul);
- }
- else if (thread_data->make_float) {
- color_balance_byte_float(cb, rect, rect_float, mask_rect, width, height, mul);
- }
- else {
- color_balance_byte_byte(cb, rect, mask_rect, width, height, mul);
- }
+ if (rect_float) {
+ color_balance_float_float(cb, rect_float, mask_rect_float, width, height, mul);
+ }
+ else if (thread_data->make_float) {
+ color_balance_byte_float(cb, rect, rect_float, mask_rect, width, height, mul);
+ }
+ else {
+ color_balance_byte_byte(cb, rect, mask_rect, width, height, mul);
+ }
- return NULL;
+ return NULL;
}
/* cfra is offset by fra_offset only in case we are using a real mask. */
-ImBuf *BKE_sequencer_render_mask_input(
- const SeqRenderData *context, int mask_input_type, Sequence *mask_sequence, Mask *mask_id,
- int cfra, int fra_offset, bool make_float)
-{
- ImBuf *mask_input = NULL;
-
- if (mask_input_type == SEQUENCE_MASK_INPUT_STRIP) {
- if (mask_sequence) {
- SeqRenderState state;
- sequencer_state_init(&state);
-
- mask_input = seq_render_strip(context, &state, mask_sequence, cfra);
-
- if (make_float) {
- if (!mask_input->rect_float)
- IMB_float_from_rect(mask_input);
- }
- else {
- if (!mask_input->rect)
- IMB_rect_from_float(mask_input);
- }
- }
- }
- else if (mask_input_type == SEQUENCE_MASK_INPUT_ID) {
- mask_input = seq_render_mask(context, mask_id, cfra - fra_offset, make_float);
- }
-
- return mask_input;
-}
-
-void BKE_sequencer_color_balance_apply(StripColorBalance *cb, ImBuf *ibuf, float mul, bool make_float, ImBuf *mask_input)
-{
- ColorBalanceInitData init_data;
-
- if (!ibuf->rect_float && make_float)
- imb_addrectfloatImBuf(ibuf);
-
- init_data.cb = cb;
- init_data.ibuf = ibuf;
- init_data.mul = mul;
- init_data.make_float = make_float;
- init_data.mask = mask_input;
-
- IMB_processor_apply_threaded(ibuf->y, sizeof(ColorBalanceThread), &init_data,
- color_balance_init_handle, color_balance_do_thread);
-
- /* color balance either happens on float buffer or byte buffer, but never on both,
- * free byte buffer if there's float buffer since float buffer would be used for
- * color balance in favor of byte buffer
- */
- if (ibuf->rect_float && ibuf->rect)
- imb_freerectImBuf(ibuf);
+ImBuf *BKE_sequencer_render_mask_input(const SeqRenderData *context,
+ int mask_input_type,
+ Sequence *mask_sequence,
+ Mask *mask_id,
+ int cfra,
+ int fra_offset,
+ bool make_float)
+{
+ ImBuf *mask_input = NULL;
+
+ if (mask_input_type == SEQUENCE_MASK_INPUT_STRIP) {
+ if (mask_sequence) {
+ SeqRenderState state;
+ sequencer_state_init(&state);
+
+ mask_input = seq_render_strip(context, &state, mask_sequence, cfra);
+
+ if (make_float) {
+ if (!mask_input->rect_float)
+ IMB_float_from_rect(mask_input);
+ }
+ else {
+ if (!mask_input->rect)
+ IMB_rect_from_float(mask_input);
+ }
+ }
+ }
+ else if (mask_input_type == SEQUENCE_MASK_INPUT_ID) {
+ mask_input = seq_render_mask(context, mask_id, cfra - fra_offset, make_float);
+ }
+
+ return mask_input;
+}
+
+void BKE_sequencer_color_balance_apply(
+ StripColorBalance *cb, ImBuf *ibuf, float mul, bool make_float, ImBuf *mask_input)
+{
+ ColorBalanceInitData init_data;
+
+ if (!ibuf->rect_float && make_float)
+ imb_addrectfloatImBuf(ibuf);
+
+ init_data.cb = cb;
+ init_data.ibuf = ibuf;
+ init_data.mul = mul;
+ init_data.make_float = make_float;
+ init_data.mask = mask_input;
+
+ IMB_processor_apply_threaded(ibuf->y,
+ sizeof(ColorBalanceThread),
+ &init_data,
+ color_balance_init_handle,
+ color_balance_do_thread);
+
+ /* color balance either happens on float buffer or byte buffer, but never on both,
+ * free byte buffer if there's float buffer since float buffer would be used for
+ * color balance in favor of byte buffer
+ */
+ if (ibuf->rect_float && ibuf->rect)
+ imb_freerectImBuf(ibuf);
}
/*
@@ -2417,1446 +2541,1500 @@ void BKE_sequencer_color_balance_apply(StripColorBalance *cb, ImBuf *ibuf, float
* - Premultiply
*/
-bool BKE_sequencer_input_have_to_preprocess(const SeqRenderData *context, Sequence *seq, float UNUSED(cfra))
-{
- float mul;
-
- if (context->is_proxy_render) {
- return false;
- }
-
- if (seq->flag & (SEQ_FILTERY | SEQ_USE_CROP | SEQ_USE_TRANSFORM | SEQ_FLIPX | SEQ_FLIPY | SEQ_MAKE_FLOAT)) {
- return true;
- }
-
- mul = seq->mul;
-
- if (seq->blend_mode == SEQ_BLEND_REPLACE) {
- mul *= seq->blend_opacity / 100.0f;
- }
-
- if (mul != 1.0f) {
- return true;
- }
-
- if (seq->sat != 1.0f) {
- return true;
- }
-
- if (seq->modifiers.first) {
- return true;
- }
-
- return false;
-}
-
-static ImBuf *input_preprocess(const SeqRenderData *context, Sequence *seq, float cfra, ImBuf *ibuf,
- const bool is_proxy_image, const bool is_preprocessed)
-{
- Scene *scene = context->scene;
- float mul;
-
- ibuf = IMB_makeSingleUser(ibuf);
-
- if ((seq->flag & SEQ_FILTERY) &&
- !ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_MOVIECLIP))
- {
- IMB_filtery(ibuf);
- }
-
- if (seq->flag & (SEQ_USE_CROP | SEQ_USE_TRANSFORM)) {
- StripCrop c = {0};
- StripTransform t = {0};
- int sx, sy, dx, dy;
-
- if (is_proxy_image) {
- double f = seq_rendersize_to_scale_factor(context->preview_render_size);
-
- if (f != 1.0) {
- IMB_scalefastImBuf(ibuf, ibuf->x / f, ibuf->y / f);
- }
- }
-
- if (seq->flag & SEQ_USE_CROP && seq->strip->crop) {
- c = *seq->strip->crop;
- }
- if (seq->flag & SEQ_USE_TRANSFORM && seq->strip->transform) {
- t = *seq->strip->transform;
- }
-
- if (is_preprocessed) {
- double xscale = scene->r.xsch ? ((double)context->rectx / (double)scene->r.xsch) : 1.0;
- double yscale = scene->r.ysch ? ((double)context->recty / (double)scene->r.ysch) : 1.0;
- if (seq->flag & SEQ_USE_TRANSFORM) {
- t.xofs *= xscale;
- t.yofs *= yscale;
- }
- if (seq->flag & SEQ_USE_CROP) {
- c.left *= xscale;
- c.right *= xscale;
- c.top *= yscale;
- c.bottom *= yscale;
- }
- }
-
- sx = ibuf->x - c.left - c.right;
- sy = ibuf->y - c.top - c.bottom;
-
- if (seq->flag & SEQ_USE_TRANSFORM) {
- if (is_preprocessed) {
- dx = context->rectx;
- dy = context->recty;
- }
- else {
- dx = scene->r.xsch;
- dy = scene->r.ysch;
- }
- }
- else {
- dx = sx;
- dy = sy;
- }
-
- if (c.top + c.bottom >= ibuf->y ||
- c.left + c.right >= ibuf->x ||
- t.xofs >= dx || t.yofs >= dy)
- {
- make_black_ibuf(ibuf);
- }
- else {
- ImBuf *i = IMB_allocImBuf(dx, dy, 32, ibuf->rect_float ? IB_rectfloat : IB_rect);
-
- IMB_rectcpy(i, ibuf, t.xofs, t.yofs, c.left, c.bottom, sx, sy);
- sequencer_imbuf_assign_spaces(scene, i);
-
- IMB_metadata_copy(i, ibuf);
- IMB_freeImBuf(ibuf);
-
- ibuf = i;
- }
- }
-
- if (seq->flag & SEQ_FLIPX) {
- IMB_flipx(ibuf);
- }
-
- if (seq->flag & SEQ_FLIPY) {
- IMB_flipy(ibuf);
- }
-
- if (seq->sat != 1.0f) {
- IMB_saturation(ibuf, seq->sat);
- }
-
- mul = seq->mul;
-
- if (seq->blend_mode == SEQ_BLEND_REPLACE) {
- mul *= seq->blend_opacity / 100.0f;
- }
-
- if (seq->flag & SEQ_MAKE_FLOAT) {
- if (!ibuf->rect_float) {
- BKE_sequencer_imbuf_to_sequencer_space(scene, ibuf, true);
- }
-
- if (ibuf->rect) {
- imb_freerectImBuf(ibuf);
- }
- }
-
- if (mul != 1.0f) {
- multibuf(ibuf, mul);
- }
-
- if (ibuf->x != context->rectx || ibuf->y != context->recty) {
- if (scene->r.mode & R_OSA) {
- IMB_scaleImBuf(ibuf, (short)context->rectx, (short)context->recty);
- }
- else {
- IMB_scalefastImBuf(ibuf, (short)context->rectx, (short)context->recty);
- }
- }
-
- if (seq->modifiers.first) {
- ImBuf *ibuf_new = BKE_sequence_modifier_apply_stack(context, seq, ibuf, cfra);
-
- if (ibuf_new != ibuf) {
- IMB_metadata_copy(ibuf_new, ibuf);
- IMB_freeImBuf(ibuf);
- ibuf = ibuf_new;
- }
- }
-
- return ibuf;
+bool BKE_sequencer_input_have_to_preprocess(const SeqRenderData *context,
+ Sequence *seq,
+ float UNUSED(cfra))
+{
+ float mul;
+
+ if (context->is_proxy_render) {
+ return false;
+ }
+
+ if (seq->flag &
+ (SEQ_FILTERY | SEQ_USE_CROP | SEQ_USE_TRANSFORM | SEQ_FLIPX | SEQ_FLIPY | SEQ_MAKE_FLOAT)) {
+ return true;
+ }
+
+ mul = seq->mul;
+
+ if (seq->blend_mode == SEQ_BLEND_REPLACE) {
+ mul *= seq->blend_opacity / 100.0f;
+ }
+
+ if (mul != 1.0f) {
+ return true;
+ }
+
+ if (seq->sat != 1.0f) {
+ return true;
+ }
+
+ if (seq->modifiers.first) {
+ return true;
+ }
+
+ return false;
+}
+
+static ImBuf *input_preprocess(const SeqRenderData *context,
+ Sequence *seq,
+ float cfra,
+ ImBuf *ibuf,
+ const bool is_proxy_image,
+ const bool is_preprocessed)
+{
+ Scene *scene = context->scene;
+ float mul;
+
+ ibuf = IMB_makeSingleUser(ibuf);
+
+ if ((seq->flag & SEQ_FILTERY) && !ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_MOVIECLIP)) {
+ IMB_filtery(ibuf);
+ }
+
+ if (seq->flag & (SEQ_USE_CROP | SEQ_USE_TRANSFORM)) {
+ StripCrop c = {0};
+ StripTransform t = {0};
+ int sx, sy, dx, dy;
+
+ if (is_proxy_image) {
+ double f = seq_rendersize_to_scale_factor(context->preview_render_size);
+
+ if (f != 1.0) {
+ IMB_scalefastImBuf(ibuf, ibuf->x / f, ibuf->y / f);
+ }
+ }
+
+ if (seq->flag & SEQ_USE_CROP && seq->strip->crop) {
+ c = *seq->strip->crop;
+ }
+ if (seq->flag & SEQ_USE_TRANSFORM && seq->strip->transform) {
+ t = *seq->strip->transform;
+ }
+
+ if (is_preprocessed) {
+ double xscale = scene->r.xsch ? ((double)context->rectx / (double)scene->r.xsch) : 1.0;
+ double yscale = scene->r.ysch ? ((double)context->recty / (double)scene->r.ysch) : 1.0;
+ if (seq->flag & SEQ_USE_TRANSFORM) {
+ t.xofs *= xscale;
+ t.yofs *= yscale;
+ }
+ if (seq->flag & SEQ_USE_CROP) {
+ c.left *= xscale;
+ c.right *= xscale;
+ c.top *= yscale;
+ c.bottom *= yscale;
+ }
+ }
+
+ sx = ibuf->x - c.left - c.right;
+ sy = ibuf->y - c.top - c.bottom;
+
+ if (seq->flag & SEQ_USE_TRANSFORM) {
+ if (is_preprocessed) {
+ dx = context->rectx;
+ dy = context->recty;
+ }
+ else {
+ dx = scene->r.xsch;
+ dy = scene->r.ysch;
+ }
+ }
+ else {
+ dx = sx;
+ dy = sy;
+ }
+
+ if (c.top + c.bottom >= ibuf->y || c.left + c.right >= ibuf->x || t.xofs >= dx ||
+ t.yofs >= dy) {
+ make_black_ibuf(ibuf);
+ }
+ else {
+ ImBuf *i = IMB_allocImBuf(dx, dy, 32, ibuf->rect_float ? IB_rectfloat : IB_rect);
+
+ IMB_rectcpy(i, ibuf, t.xofs, t.yofs, c.left, c.bottom, sx, sy);
+ sequencer_imbuf_assign_spaces(scene, i);
+
+ IMB_metadata_copy(i, ibuf);
+ IMB_freeImBuf(ibuf);
+
+ ibuf = i;
+ }
+ }
+
+ if (seq->flag & SEQ_FLIPX) {
+ IMB_flipx(ibuf);
+ }
+
+ if (seq->flag & SEQ_FLIPY) {
+ IMB_flipy(ibuf);
+ }
+
+ if (seq->sat != 1.0f) {
+ IMB_saturation(ibuf, seq->sat);
+ }
+
+ mul = seq->mul;
+
+ if (seq->blend_mode == SEQ_BLEND_REPLACE) {
+ mul *= seq->blend_opacity / 100.0f;
+ }
+
+ if (seq->flag & SEQ_MAKE_FLOAT) {
+ if (!ibuf->rect_float) {
+ BKE_sequencer_imbuf_to_sequencer_space(scene, ibuf, true);
+ }
+
+ if (ibuf->rect) {
+ imb_freerectImBuf(ibuf);
+ }
+ }
+
+ if (mul != 1.0f) {
+ multibuf(ibuf, mul);
+ }
+
+ if (ibuf->x != context->rectx || ibuf->y != context->recty) {
+ if (scene->r.mode & R_OSA) {
+ IMB_scaleImBuf(ibuf, (short)context->rectx, (short)context->recty);
+ }
+ else {
+ IMB_scalefastImBuf(ibuf, (short)context->rectx, (short)context->recty);
+ }
+ }
+
+ if (seq->modifiers.first) {
+ ImBuf *ibuf_new = BKE_sequence_modifier_apply_stack(context, seq, ibuf, cfra);
+
+ if (ibuf_new != ibuf) {
+ IMB_metadata_copy(ibuf_new, ibuf);
+ IMB_freeImBuf(ibuf);
+ ibuf = ibuf_new;
+ }
+ }
+
+ return ibuf;
}
static ImBuf *copy_from_ibuf_still(const SeqRenderData *context, Sequence *seq, float nr)
{
- ImBuf *rval = NULL;
- ImBuf *ibuf = NULL;
+ ImBuf *rval = NULL;
+ ImBuf *ibuf = NULL;
- if (nr == 0) {
- ibuf = BKE_sequencer_cache_get(context, seq, seq->start, SEQ_STRIPELEM_IBUF_STARTSTILL);
- }
- else if (nr == seq->len - 1) {
- ibuf = BKE_sequencer_cache_get(context, seq, seq->start, SEQ_STRIPELEM_IBUF_ENDSTILL);
- }
+ if (nr == 0) {
+ ibuf = BKE_sequencer_cache_get(context, seq, seq->start, SEQ_STRIPELEM_IBUF_STARTSTILL);
+ }
+ else if (nr == seq->len - 1) {
+ ibuf = BKE_sequencer_cache_get(context, seq, seq->start, SEQ_STRIPELEM_IBUF_ENDSTILL);
+ }
- if (ibuf) {
- rval = IMB_dupImBuf(ibuf);
- IMB_metadata_copy(rval, ibuf);
- IMB_freeImBuf(ibuf);
- }
+ if (ibuf) {
+ rval = IMB_dupImBuf(ibuf);
+ IMB_metadata_copy(rval, ibuf);
+ IMB_freeImBuf(ibuf);
+ }
- return rval;
+ return rval;
}
static void copy_to_ibuf_still(const SeqRenderData *context, Sequence *seq, float nr, ImBuf *ibuf)
{
- /* warning: ibuf may be NULL if the video fails to load */
- if (nr == 0 || nr == seq->len - 1) {
- /* we have to store a copy, since the passed ibuf
- * could be preprocessed afterwards (thereby silently
- * changing the cached image... */
- ImBuf *oibuf = ibuf;
- ibuf = IMB_dupImBuf(oibuf);
+ /* warning: ibuf may be NULL if the video fails to load */
+ if (nr == 0 || nr == seq->len - 1) {
+ /* we have to store a copy, since the passed ibuf
+ * could be preprocessed afterwards (thereby silently
+ * changing the cached image... */
+ ImBuf *oibuf = ibuf;
+ ibuf = IMB_dupImBuf(oibuf);
- if (ibuf) {
- IMB_metadata_copy(ibuf, oibuf);
- sequencer_imbuf_assign_spaces(context->scene, ibuf);
- }
+ if (ibuf) {
+ IMB_metadata_copy(ibuf, oibuf);
+ sequencer_imbuf_assign_spaces(context->scene, ibuf);
+ }
- if (nr == 0) {
- BKE_sequencer_cache_put(context, seq, seq->start, SEQ_STRIPELEM_IBUF_STARTSTILL, ibuf);
- }
+ if (nr == 0) {
+ BKE_sequencer_cache_put(context, seq, seq->start, SEQ_STRIPELEM_IBUF_STARTSTILL, ibuf);
+ }
- if (nr == seq->len - 1) {
- BKE_sequencer_cache_put(context, seq, seq->start, SEQ_STRIPELEM_IBUF_ENDSTILL, ibuf);
- }
+ if (nr == seq->len - 1) {
+ BKE_sequencer_cache_put(context, seq, seq->start, SEQ_STRIPELEM_IBUF_ENDSTILL, ibuf);
+ }
- IMB_freeImBuf(ibuf);
- }
+ IMB_freeImBuf(ibuf);
+ }
}
/*********************** strip rendering functions *************************/
typedef struct RenderEffectInitData {
- struct SeqEffectHandle *sh;
- const SeqRenderData *context;
- Sequence *seq;
- float cfra, facf0, facf1;
- ImBuf *ibuf1, *ibuf2, *ibuf3;
+ struct SeqEffectHandle *sh;
+ const SeqRenderData *context;
+ Sequence *seq;
+ float cfra, facf0, facf1;
+ ImBuf *ibuf1, *ibuf2, *ibuf3;
- ImBuf *out;
+ ImBuf *out;
} RenderEffectInitData;
typedef struct RenderEffectThread {
- struct SeqEffectHandle *sh;
- const SeqRenderData *context;
- Sequence *seq;
- float cfra, facf0, facf1;
- ImBuf *ibuf1, *ibuf2, *ibuf3;
-
- ImBuf *out;
- int start_line, tot_line;
+ struct SeqEffectHandle *sh;
+ const SeqRenderData *context;
+ Sequence *seq;
+ float cfra, facf0, facf1;
+ ImBuf *ibuf1, *ibuf2, *ibuf3;
+
+ ImBuf *out;
+ int start_line, tot_line;
} RenderEffectThread;
-static void render_effect_execute_init_handle(void *handle_v, int start_line, int tot_line, void *init_data_v)
+static void render_effect_execute_init_handle(void *handle_v,
+ int start_line,
+ int tot_line,
+ void *init_data_v)
{
- RenderEffectThread *handle = (RenderEffectThread *) handle_v;
- RenderEffectInitData *init_data = (RenderEffectInitData *) init_data_v;
+ RenderEffectThread *handle = (RenderEffectThread *)handle_v;
+ RenderEffectInitData *init_data = (RenderEffectInitData *)init_data_v;
- handle->sh = init_data->sh;
- handle->context = init_data->context;
- handle->seq = init_data->seq;
- handle->cfra = init_data->cfra;
- handle->facf0 = init_data->facf0;
- handle->facf1 = init_data->facf1;
- handle->ibuf1 = init_data->ibuf1;
- handle->ibuf2 = init_data->ibuf2;
- handle->ibuf3 = init_data->ibuf3;
- handle->out = init_data->out;
+ handle->sh = init_data->sh;
+ handle->context = init_data->context;
+ handle->seq = init_data->seq;
+ handle->cfra = init_data->cfra;
+ handle->facf0 = init_data->facf0;
+ handle->facf1 = init_data->facf1;
+ handle->ibuf1 = init_data->ibuf1;
+ handle->ibuf2 = init_data->ibuf2;
+ handle->ibuf3 = init_data->ibuf3;
+ handle->out = init_data->out;
- handle->start_line = start_line;
- handle->tot_line = tot_line;
+ handle->start_line = start_line;
+ handle->tot_line = tot_line;
}
static void *render_effect_execute_do_thread(void *thread_data_v)
{
- RenderEffectThread *thread_data = (RenderEffectThread *) thread_data_v;
-
- thread_data->sh->execute_slice(thread_data->context, thread_data->seq, thread_data->cfra,
- thread_data->facf0, thread_data->facf1, thread_data->ibuf1,
- thread_data->ibuf2, thread_data->ibuf3, thread_data->start_line,
- thread_data->tot_line, thread_data->out);
-
- return NULL;
-}
-
-static ImBuf *seq_render_effect_execute_threaded(struct SeqEffectHandle *sh, const SeqRenderData *context, Sequence *seq,
- float cfra, float facf0, float facf1,
- ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3)
-{
- RenderEffectInitData init_data;
- ImBuf *out = sh->init_execution(context, ibuf1, ibuf2, ibuf3);
-
- init_data.sh = sh;
- init_data.context = context;
- init_data.seq = seq;
- init_data.cfra = cfra;
- init_data.facf0 = facf0;
- init_data.facf1 = facf1;
- init_data.ibuf1 = ibuf1;
- init_data.ibuf2 = ibuf2;
- init_data.ibuf3 = ibuf3;
- init_data.out = out;
-
- IMB_processor_apply_threaded(out->y, sizeof(RenderEffectThread), &init_data,
- render_effect_execute_init_handle, render_effect_execute_do_thread);
-
- return out;
-}
-
-static ImBuf *seq_render_effect_strip_impl(
- const SeqRenderData *context, SeqRenderState *state,
- Sequence *seq, float cfra)
-{
- Scene *scene = context->scene;
- float fac, facf;
- int early_out;
- int i;
- struct SeqEffectHandle sh = BKE_sequence_get_effect(seq);
- FCurve *fcu = NULL;
- ImBuf *ibuf[3];
- Sequence *input[3];
- ImBuf *out = NULL;
-
- ibuf[0] = ibuf[1] = ibuf[2] = NULL;
-
- input[0] = seq->seq1; input[1] = seq->seq2; input[2] = seq->seq3;
-
- if (!sh.execute && !(sh.execute_slice && sh.init_execution)) {
- /* effect not supported in this version... */
- out = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect);
- return out;
- }
-
- if (seq->flag & SEQ_USE_EFFECT_DEFAULT_FADE) {
- sh.get_default_fac(seq, cfra, &fac, &facf);
- facf = fac;
- }
- else {
- fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "effect_fader", 0, NULL);
- if (fcu) {
- fac = facf = evaluate_fcurve(fcu, cfra);
- }
- else {
- fac = facf = seq->effect_fader;
- }
- }
-
- early_out = sh.early_out(seq, fac, facf);
-
- switch (early_out) {
- case EARLY_NO_INPUT:
- out = sh.execute(context, seq, cfra, fac, facf, NULL, NULL, NULL);
- break;
- case EARLY_DO_EFFECT:
- for (i = 0; i < 3; i++) {
- if (input[i])
- ibuf[i] = seq_render_strip(context, state, input[i], cfra);
- }
-
- if (ibuf[0] && ibuf[1]) {
- if (sh.multithreaded)
- out = seq_render_effect_execute_threaded(&sh, context, seq, cfra, fac, facf, ibuf[0], ibuf[1], ibuf[2]);
- else
- out = sh.execute(context, seq, cfra, fac, facf, ibuf[0], ibuf[1], ibuf[2]);
- }
- break;
- case EARLY_USE_INPUT_1:
- if (input[0]) {
- ibuf[0] = seq_render_strip(context, state, input[0], cfra);
- }
- if (ibuf[0]) {
- if (BKE_sequencer_input_have_to_preprocess(context, seq, cfra)) {
- out = IMB_dupImBuf(ibuf[0]);
- }
- else {
- out = ibuf[0];
- IMB_refImBuf(out);
- }
- }
- break;
- case EARLY_USE_INPUT_2:
- if (input[1]) {
- ibuf[1] = seq_render_strip(context, state, input[1], cfra);
- }
- if (ibuf[1]) {
- if (BKE_sequencer_input_have_to_preprocess(context, seq, cfra)) {
- out = IMB_dupImBuf(ibuf[1]);
- }
- else {
- out = ibuf[1];
- IMB_refImBuf(out);
- }
- }
- break;
- }
-
- for (i = 0; i < 3; i++) {
- IMB_freeImBuf(ibuf[i]);
- }
-
- if (out == NULL) {
- out = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect);
- }
-
- return out;
-}
-
-static ImBuf *seq_render_image_strip(const SeqRenderData *context, Sequence *seq, float nr, float cfra)
-{
- ImBuf *ibuf = NULL;
- char name[FILE_MAX];
- bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 &&
- (context->scene->r.scemode & R_MULTIVIEW) != 0;
- StripElem *s_elem = BKE_sequencer_give_stripelem(seq, cfra);
- int flag;
-
- if (s_elem) {
- BLI_join_dirfile(name, sizeof(name), seq->strip->dir, s_elem->name);
- BLI_path_abs(name, BKE_main_blendfile_path_from_global());
- }
-
- flag = IB_rect | IB_metadata;
- if (seq->alpha_mode == SEQ_ALPHA_PREMUL)
- flag |= IB_alphamode_premul;
-
- if (!s_elem) {
- /* don't do anything */
- }
- else if (is_multiview) {
- const int totfiles = seq_num_files(context->scene, seq->views_format, true);
- int totviews;
- struct ImBuf **ibufs_arr;
- char prefix[FILE_MAX];
- const char *ext = NULL;
- int i;
-
- if (totfiles > 1) {
- BKE_scene_multiview_view_prefix_get(context->scene, name, prefix, &ext);
- if (prefix[0] == '\0') {
- goto monoview_image;
- }
- }
- else {
- prefix[0] = '\0';
- }
-
- totviews = BKE_scene_multiview_num_views_get(&context->scene->r);
- ibufs_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs");
-
- for (i = 0; i < totfiles; i++) {
-
- if (prefix[0] == '\0') {
- ibufs_arr[i] = IMB_loadiffname(name, flag, seq->strip->colorspace_settings.name);
- }
- else {
- char str[FILE_MAX];
- seq_multiview_name(context->scene, i, prefix, ext, str, FILE_MAX);
- ibufs_arr[i] = IMB_loadiffname(str, flag, seq->strip->colorspace_settings.name);
- }
-
- if (ibufs_arr[i]) {
- /* we don't need both (speed reasons)! */
- if (ibufs_arr[i]->rect_float && ibufs_arr[i]->rect)
- imb_freerectImBuf(ibufs_arr[i]);
- }
- }
-
- if (seq->views_format == R_IMF_VIEWS_STEREO_3D && ibufs_arr[0])
- IMB_ImBufFromStereo3d(seq->stereo3d_format, ibufs_arr[0], &ibufs_arr[0], &ibufs_arr[1]);
-
- for (i = 0; i < totviews; i++) {
- if (ibufs_arr[i]) {
- SeqRenderData localcontext = *context;
- localcontext.view_id = i;
-
- /* all sequencer color is done in SRGB space, linear gives odd crossfades */
- BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibufs_arr[i], false);
-
- if (i != context->view_id) {
- copy_to_ibuf_still(&localcontext, seq, nr, ibufs_arr[i]);
- BKE_sequencer_cache_put(&localcontext, seq, cfra, SEQ_STRIPELEM_IBUF, ibufs_arr[i]);
- }
- }
- }
-
- /* return the original requested ImBuf */
- ibuf = ibufs_arr[context->view_id];
- if (ibuf) {
- s_elem->orig_width = ibufs_arr[0]->x;
- s_elem->orig_height = ibufs_arr[0]->y;
- }
-
- /* "remove" the others (decrease their refcount) */
- for (i = 0; i < totviews; i++) {
- if (ibufs_arr[i] != ibuf) {
- IMB_freeImBuf(ibufs_arr[i]);
- }
- }
-
- MEM_freeN(ibufs_arr);
- }
- else {
-monoview_image:
- if ((ibuf = IMB_loadiffname(name, flag, seq->strip->colorspace_settings.name))) {
- /* we don't need both (speed reasons)! */
- if (ibuf->rect_float && ibuf->rect)
- imb_freerectImBuf(ibuf);
-
- /* all sequencer color is done in SRGB space, linear gives odd crossfades */
- BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false);
-
- s_elem->orig_width = ibuf->x;
- s_elem->orig_height = ibuf->y;
- }
- }
-
- return ibuf;
-}
-
-static ImBuf *seq_render_movie_strip(const SeqRenderData *context, Sequence *seq, float nr, float cfra)
-{
- ImBuf *ibuf = NULL;
- StripAnim *sanim;
- bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 &&
- (context->scene->r.scemode & R_MULTIVIEW) != 0;
-
- /* load all the videos */
- seq_open_anim_file(context->scene, seq, false);
-
- if (is_multiview) {
- ImBuf **ibuf_arr;
- const int totfiles = seq_num_files(context->scene, seq->views_format, true);
- int totviews;
- int i;
-
- if (totfiles != BLI_listbase_count_at_most(&seq->anims, totfiles + 1))
- goto monoview_movie;
-
- totviews = BKE_scene_multiview_num_views_get(&context->scene->r);
- ibuf_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs");
-
- for (i = 0, sanim = seq->anims.first; sanim; sanim = sanim->next, i++) {
- if (sanim->anim) {
- IMB_Proxy_Size proxy_size = seq_rendersize_to_proxysize(context->preview_render_size);
- IMB_anim_set_preseek(sanim->anim, seq->anim_preseek);
-
- ibuf_arr[i] = IMB_anim_absolute(sanim->anim, nr + seq->anim_startofs,
- seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
- proxy_size);
-
- /* fetching for requested proxy size failed, try fetching the original instead */
- if (!ibuf_arr[i] && proxy_size != IMB_PROXY_NONE) {
- ibuf_arr[i] = IMB_anim_absolute(sanim->anim, nr + seq->anim_startofs,
- seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
- IMB_PROXY_NONE);
- }
- if (ibuf_arr[i]) {
- /* we don't need both (speed reasons)! */
- if (ibuf_arr[i]->rect_float && ibuf_arr[i]->rect)
- imb_freerectImBuf(ibuf_arr[i]);
- }
- }
- }
-
- if (seq->views_format == R_IMF_VIEWS_STEREO_3D) {
- if (ibuf_arr[0]) {
- IMB_ImBufFromStereo3d(seq->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]);
- }
- else {
- /* probably proxy hasn't been created yet */
- MEM_freeN(ibuf_arr);
- return NULL;
- }
- }
-
- for (i = 0; i < totviews; i++) {
- SeqRenderData localcontext = *context;
- localcontext.view_id = i;
-
- if (ibuf_arr[i]) {
- /* all sequencer color is done in SRGB space, linear gives odd crossfades */
- BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf_arr[i], false);
- }
- if (i != context->view_id) {
- copy_to_ibuf_still(&localcontext, seq, nr, ibuf_arr[i]);
- BKE_sequencer_cache_put(&localcontext, seq, cfra, SEQ_STRIPELEM_IBUF, ibuf_arr[i]);
- }
- }
-
- /* return the original requested ImBuf */
- ibuf = ibuf_arr[context->view_id];
- if (ibuf) {
- seq->strip->stripdata->orig_width = ibuf->x;
- seq->strip->stripdata->orig_height = ibuf->y;
- }
-
- /* "remove" the others (decrease their refcount) */
- for (i = 0; i < totviews; i++) {
- if (ibuf_arr[i] != ibuf) {
- IMB_freeImBuf(ibuf_arr[i]);
- }
- }
-
- MEM_freeN(ibuf_arr);
- }
- else {
-monoview_movie:
- sanim = seq->anims.first;
- if (sanim && sanim->anim) {
- IMB_Proxy_Size proxy_size = seq_rendersize_to_proxysize(context->preview_render_size);
- IMB_anim_set_preseek(sanim->anim, seq->anim_preseek);
-
- ibuf = IMB_anim_absolute(sanim->anim, nr + seq->anim_startofs,
- seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
- proxy_size);
-
- /* fetching for requested proxy size failed, try fetching the original instead */
- if (!ibuf && proxy_size != IMB_PROXY_NONE) {
- ibuf = IMB_anim_absolute(sanim->anim, nr + seq->anim_startofs,
- seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
- IMB_PROXY_NONE);
- }
- if (ibuf) {
- BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false);
-
- /* we don't need both (speed reasons)! */
- if (ibuf->rect_float && ibuf->rect) {
- imb_freerectImBuf(ibuf);
- }
-
- seq->strip->stripdata->orig_width = ibuf->x;
- seq->strip->stripdata->orig_height = ibuf->y;
- }
- }
- }
- return ibuf;
+ RenderEffectThread *thread_data = (RenderEffectThread *)thread_data_v;
+
+ thread_data->sh->execute_slice(thread_data->context,
+ thread_data->seq,
+ thread_data->cfra,
+ thread_data->facf0,
+ thread_data->facf1,
+ thread_data->ibuf1,
+ thread_data->ibuf2,
+ thread_data->ibuf3,
+ thread_data->start_line,
+ thread_data->tot_line,
+ thread_data->out);
+
+ return NULL;
+}
+
+static ImBuf *seq_render_effect_execute_threaded(struct SeqEffectHandle *sh,
+ const SeqRenderData *context,
+ Sequence *seq,
+ float cfra,
+ float facf0,
+ float facf1,
+ ImBuf *ibuf1,
+ ImBuf *ibuf2,
+ ImBuf *ibuf3)
+{
+ RenderEffectInitData init_data;
+ ImBuf *out = sh->init_execution(context, ibuf1, ibuf2, ibuf3);
+
+ init_data.sh = sh;
+ init_data.context = context;
+ init_data.seq = seq;
+ init_data.cfra = cfra;
+ init_data.facf0 = facf0;
+ init_data.facf1 = facf1;
+ init_data.ibuf1 = ibuf1;
+ init_data.ibuf2 = ibuf2;
+ init_data.ibuf3 = ibuf3;
+ init_data.out = out;
+
+ IMB_processor_apply_threaded(out->y,
+ sizeof(RenderEffectThread),
+ &init_data,
+ render_effect_execute_init_handle,
+ render_effect_execute_do_thread);
+
+ return out;
+}
+
+static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context,
+ SeqRenderState *state,
+ Sequence *seq,
+ float cfra)
+{
+ Scene *scene = context->scene;
+ float fac, facf;
+ int early_out;
+ int i;
+ struct SeqEffectHandle sh = BKE_sequence_get_effect(seq);
+ FCurve *fcu = NULL;
+ ImBuf *ibuf[3];
+ Sequence *input[3];
+ ImBuf *out = NULL;
+
+ ibuf[0] = ibuf[1] = ibuf[2] = NULL;
+
+ input[0] = seq->seq1;
+ input[1] = seq->seq2;
+ input[2] = seq->seq3;
+
+ if (!sh.execute && !(sh.execute_slice && sh.init_execution)) {
+ /* effect not supported in this version... */
+ out = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect);
+ return out;
+ }
+
+ if (seq->flag & SEQ_USE_EFFECT_DEFAULT_FADE) {
+ sh.get_default_fac(seq, cfra, &fac, &facf);
+ facf = fac;
+ }
+ else {
+ fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "effect_fader", 0, NULL);
+ if (fcu) {
+ fac = facf = evaluate_fcurve(fcu, cfra);
+ }
+ else {
+ fac = facf = seq->effect_fader;
+ }
+ }
+
+ early_out = sh.early_out(seq, fac, facf);
+
+ switch (early_out) {
+ case EARLY_NO_INPUT:
+ out = sh.execute(context, seq, cfra, fac, facf, NULL, NULL, NULL);
+ break;
+ case EARLY_DO_EFFECT:
+ for (i = 0; i < 3; i++) {
+ if (input[i])
+ ibuf[i] = seq_render_strip(context, state, input[i], cfra);
+ }
+
+ if (ibuf[0] && ibuf[1]) {
+ if (sh.multithreaded)
+ out = seq_render_effect_execute_threaded(
+ &sh, context, seq, cfra, fac, facf, ibuf[0], ibuf[1], ibuf[2]);
+ else
+ out = sh.execute(context, seq, cfra, fac, facf, ibuf[0], ibuf[1], ibuf[2]);
+ }
+ break;
+ case EARLY_USE_INPUT_1:
+ if (input[0]) {
+ ibuf[0] = seq_render_strip(context, state, input[0], cfra);
+ }
+ if (ibuf[0]) {
+ if (BKE_sequencer_input_have_to_preprocess(context, seq, cfra)) {
+ out = IMB_dupImBuf(ibuf[0]);
+ }
+ else {
+ out = ibuf[0];
+ IMB_refImBuf(out);
+ }
+ }
+ break;
+ case EARLY_USE_INPUT_2:
+ if (input[1]) {
+ ibuf[1] = seq_render_strip(context, state, input[1], cfra);
+ }
+ if (ibuf[1]) {
+ if (BKE_sequencer_input_have_to_preprocess(context, seq, cfra)) {
+ out = IMB_dupImBuf(ibuf[1]);
+ }
+ else {
+ out = ibuf[1];
+ IMB_refImBuf(out);
+ }
+ }
+ break;
+ }
+
+ for (i = 0; i < 3; i++) {
+ IMB_freeImBuf(ibuf[i]);
+ }
+
+ if (out == NULL) {
+ out = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect);
+ }
+
+ return out;
+}
+
+static ImBuf *seq_render_image_strip(const SeqRenderData *context,
+ Sequence *seq,
+ float nr,
+ float cfra)
+{
+ ImBuf *ibuf = NULL;
+ char name[FILE_MAX];
+ bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 &&
+ (context->scene->r.scemode & R_MULTIVIEW) != 0;
+ StripElem *s_elem = BKE_sequencer_give_stripelem(seq, cfra);
+ int flag;
+
+ if (s_elem) {
+ BLI_join_dirfile(name, sizeof(name), seq->strip->dir, s_elem->name);
+ BLI_path_abs(name, BKE_main_blendfile_path_from_global());
+ }
+
+ flag = IB_rect | IB_metadata;
+ if (seq->alpha_mode == SEQ_ALPHA_PREMUL)
+ flag |= IB_alphamode_premul;
+
+ if (!s_elem) {
+ /* don't do anything */
+ }
+ else if (is_multiview) {
+ const int totfiles = seq_num_files(context->scene, seq->views_format, true);
+ int totviews;
+ struct ImBuf **ibufs_arr;
+ char prefix[FILE_MAX];
+ const char *ext = NULL;
+ int i;
+
+ if (totfiles > 1) {
+ BKE_scene_multiview_view_prefix_get(context->scene, name, prefix, &ext);
+ if (prefix[0] == '\0') {
+ goto monoview_image;
+ }
+ }
+ else {
+ prefix[0] = '\0';
+ }
+
+ totviews = BKE_scene_multiview_num_views_get(&context->scene->r);
+ ibufs_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs");
+
+ for (i = 0; i < totfiles; i++) {
+
+ if (prefix[0] == '\0') {
+ ibufs_arr[i] = IMB_loadiffname(name, flag, seq->strip->colorspace_settings.name);
+ }
+ else {
+ char str[FILE_MAX];
+ seq_multiview_name(context->scene, i, prefix, ext, str, FILE_MAX);
+ ibufs_arr[i] = IMB_loadiffname(str, flag, seq->strip->colorspace_settings.name);
+ }
+
+ if (ibufs_arr[i]) {
+ /* we don't need both (speed reasons)! */
+ if (ibufs_arr[i]->rect_float && ibufs_arr[i]->rect)
+ imb_freerectImBuf(ibufs_arr[i]);
+ }
+ }
+
+ if (seq->views_format == R_IMF_VIEWS_STEREO_3D && ibufs_arr[0])
+ IMB_ImBufFromStereo3d(seq->stereo3d_format, ibufs_arr[0], &ibufs_arr[0], &ibufs_arr[1]);
+
+ for (i = 0; i < totviews; i++) {
+ if (ibufs_arr[i]) {
+ SeqRenderData localcontext = *context;
+ localcontext.view_id = i;
+
+ /* all sequencer color is done in SRGB space, linear gives odd crossfades */
+ BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibufs_arr[i], false);
+
+ if (i != context->view_id) {
+ copy_to_ibuf_still(&localcontext, seq, nr, ibufs_arr[i]);
+ BKE_sequencer_cache_put(&localcontext, seq, cfra, SEQ_STRIPELEM_IBUF, ibufs_arr[i]);
+ }
+ }
+ }
+
+ /* return the original requested ImBuf */
+ ibuf = ibufs_arr[context->view_id];
+ if (ibuf) {
+ s_elem->orig_width = ibufs_arr[0]->x;
+ s_elem->orig_height = ibufs_arr[0]->y;
+ }
+
+ /* "remove" the others (decrease their refcount) */
+ for (i = 0; i < totviews; i++) {
+ if (ibufs_arr[i] != ibuf) {
+ IMB_freeImBuf(ibufs_arr[i]);
+ }
+ }
+
+ MEM_freeN(ibufs_arr);
+ }
+ else {
+ monoview_image:
+ if ((ibuf = IMB_loadiffname(name, flag, seq->strip->colorspace_settings.name))) {
+ /* we don't need both (speed reasons)! */
+ if (ibuf->rect_float && ibuf->rect)
+ imb_freerectImBuf(ibuf);
+
+ /* all sequencer color is done in SRGB space, linear gives odd crossfades */
+ BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false);
+
+ s_elem->orig_width = ibuf->x;
+ s_elem->orig_height = ibuf->y;
+ }
+ }
+
+ return ibuf;
+}
+
+static ImBuf *seq_render_movie_strip(const SeqRenderData *context,
+ Sequence *seq,
+ float nr,
+ float cfra)
+{
+ ImBuf *ibuf = NULL;
+ StripAnim *sanim;
+ bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 &&
+ (context->scene->r.scemode & R_MULTIVIEW) != 0;
+
+ /* load all the videos */
+ seq_open_anim_file(context->scene, seq, false);
+
+ if (is_multiview) {
+ ImBuf **ibuf_arr;
+ const int totfiles = seq_num_files(context->scene, seq->views_format, true);
+ int totviews;
+ int i;
+
+ if (totfiles != BLI_listbase_count_at_most(&seq->anims, totfiles + 1))
+ goto monoview_movie;
+
+ totviews = BKE_scene_multiview_num_views_get(&context->scene->r);
+ ibuf_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs");
+
+ for (i = 0, sanim = seq->anims.first; sanim; sanim = sanim->next, i++) {
+ if (sanim->anim) {
+ IMB_Proxy_Size proxy_size = seq_rendersize_to_proxysize(context->preview_render_size);
+ IMB_anim_set_preseek(sanim->anim, seq->anim_preseek);
+
+ ibuf_arr[i] = IMB_anim_absolute(sanim->anim,
+ nr + seq->anim_startofs,
+ seq->strip->proxy ? seq->strip->proxy->tc :
+ IMB_TC_RECORD_RUN,
+ proxy_size);
+
+ /* fetching for requested proxy size failed, try fetching the original instead */
+ if (!ibuf_arr[i] && proxy_size != IMB_PROXY_NONE) {
+ ibuf_arr[i] = IMB_anim_absolute(sanim->anim,
+ nr + seq->anim_startofs,
+ seq->strip->proxy ? seq->strip->proxy->tc :
+ IMB_TC_RECORD_RUN,
+ IMB_PROXY_NONE);
+ }
+ if (ibuf_arr[i]) {
+ /* we don't need both (speed reasons)! */
+ if (ibuf_arr[i]->rect_float && ibuf_arr[i]->rect)
+ imb_freerectImBuf(ibuf_arr[i]);
+ }
+ }
+ }
+
+ if (seq->views_format == R_IMF_VIEWS_STEREO_3D) {
+ if (ibuf_arr[0]) {
+ IMB_ImBufFromStereo3d(seq->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]);
+ }
+ else {
+ /* probably proxy hasn't been created yet */
+ MEM_freeN(ibuf_arr);
+ return NULL;
+ }
+ }
+
+ for (i = 0; i < totviews; i++) {
+ SeqRenderData localcontext = *context;
+ localcontext.view_id = i;
+
+ if (ibuf_arr[i]) {
+ /* all sequencer color is done in SRGB space, linear gives odd crossfades */
+ BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf_arr[i], false);
+ }
+ if (i != context->view_id) {
+ copy_to_ibuf_still(&localcontext, seq, nr, ibuf_arr[i]);
+ BKE_sequencer_cache_put(&localcontext, seq, cfra, SEQ_STRIPELEM_IBUF, ibuf_arr[i]);
+ }
+ }
+
+ /* return the original requested ImBuf */
+ ibuf = ibuf_arr[context->view_id];
+ if (ibuf) {
+ seq->strip->stripdata->orig_width = ibuf->x;
+ seq->strip->stripdata->orig_height = ibuf->y;
+ }
+
+ /* "remove" the others (decrease their refcount) */
+ for (i = 0; i < totviews; i++) {
+ if (ibuf_arr[i] != ibuf) {
+ IMB_freeImBuf(ibuf_arr[i]);
+ }
+ }
+
+ MEM_freeN(ibuf_arr);
+ }
+ else {
+ monoview_movie:
+ sanim = seq->anims.first;
+ if (sanim && sanim->anim) {
+ IMB_Proxy_Size proxy_size = seq_rendersize_to_proxysize(context->preview_render_size);
+ IMB_anim_set_preseek(sanim->anim, seq->anim_preseek);
+
+ ibuf = IMB_anim_absolute(sanim->anim,
+ nr + seq->anim_startofs,
+ seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
+ proxy_size);
+
+ /* fetching for requested proxy size failed, try fetching the original instead */
+ if (!ibuf && proxy_size != IMB_PROXY_NONE) {
+ ibuf = IMB_anim_absolute(sanim->anim,
+ nr + seq->anim_startofs,
+ seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
+ IMB_PROXY_NONE);
+ }
+ if (ibuf) {
+ BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false);
+
+ /* we don't need both (speed reasons)! */
+ if (ibuf->rect_float && ibuf->rect) {
+ imb_freerectImBuf(ibuf);
+ }
+
+ seq->strip->stripdata->orig_width = ibuf->x;
+ seq->strip->stripdata->orig_height = ibuf->y;
+ }
+ }
+ }
+ return ibuf;
}
static ImBuf *seq_render_movieclip_strip(const SeqRenderData *context, Sequence *seq, float nr)
{
- ImBuf *ibuf = NULL;
- MovieClipUser user;
- float tloc[2], tscale, tangle;
-
- if (!seq->clip) {
- return NULL;
- }
-
- memset(&user, 0, sizeof(MovieClipUser));
-
- BKE_movieclip_user_set_frame(&user, nr + seq->anim_startofs + seq->clip->start_frame);
-
- user.render_flag |= MCLIP_PROXY_RENDER_USE_FALLBACK_RENDER;
-
- user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL;
- switch (seq_rendersize_to_proxysize(context->preview_render_size)) {
- case IMB_PROXY_NONE:
- user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL;
- break;
- case IMB_PROXY_100:
- user.render_size = MCLIP_PROXY_RENDER_SIZE_100;
- break;
- case IMB_PROXY_75:
- user.render_size = MCLIP_PROXY_RENDER_SIZE_75;
- break;
- case IMB_PROXY_50:
- user.render_size = MCLIP_PROXY_RENDER_SIZE_50;
- break;
- case IMB_PROXY_25:
- user.render_size = MCLIP_PROXY_RENDER_SIZE_25;
- break;
- }
-
- if (seq->clip_flag & SEQ_MOVIECLIP_RENDER_UNDISTORTED) {
- user.render_flag |= MCLIP_PROXY_RENDER_UNDISTORT;
- }
-
- if (seq->clip_flag & SEQ_MOVIECLIP_RENDER_STABILIZED) {
- ibuf = BKE_movieclip_get_stable_ibuf(seq->clip, &user, tloc, &tscale, &tangle, 0);
- }
- else {
- ibuf = BKE_movieclip_get_ibuf_flag(seq->clip, &user, seq->clip->flag, MOVIECLIP_CACHE_SKIP);
- }
-
- return ibuf;
+ ImBuf *ibuf = NULL;
+ MovieClipUser user;
+ float tloc[2], tscale, tangle;
+
+ if (!seq->clip) {
+ return NULL;
+ }
+
+ memset(&user, 0, sizeof(MovieClipUser));
+
+ BKE_movieclip_user_set_frame(&user, nr + seq->anim_startofs + seq->clip->start_frame);
+
+ user.render_flag |= MCLIP_PROXY_RENDER_USE_FALLBACK_RENDER;
+
+ user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL;
+ switch (seq_rendersize_to_proxysize(context->preview_render_size)) {
+ case IMB_PROXY_NONE:
+ user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL;
+ break;
+ case IMB_PROXY_100:
+ user.render_size = MCLIP_PROXY_RENDER_SIZE_100;
+ break;
+ case IMB_PROXY_75:
+ user.render_size = MCLIP_PROXY_RENDER_SIZE_75;
+ break;
+ case IMB_PROXY_50:
+ user.render_size = MCLIP_PROXY_RENDER_SIZE_50;
+ break;
+ case IMB_PROXY_25:
+ user.render_size = MCLIP_PROXY_RENDER_SIZE_25;
+ break;
+ }
+
+ if (seq->clip_flag & SEQ_MOVIECLIP_RENDER_UNDISTORTED) {
+ user.render_flag |= MCLIP_PROXY_RENDER_UNDISTORT;
+ }
+
+ if (seq->clip_flag & SEQ_MOVIECLIP_RENDER_STABILIZED) {
+ ibuf = BKE_movieclip_get_stable_ibuf(seq->clip, &user, tloc, &tscale, &tangle, 0);
+ }
+ else {
+ ibuf = BKE_movieclip_get_ibuf_flag(seq->clip, &user, seq->clip->flag, MOVIECLIP_CACHE_SKIP);
+ }
+
+ return ibuf;
}
-
static ImBuf *seq_render_mask(const SeqRenderData *context, Mask *mask, float nr, bool make_float)
{
- /* TODO - add option to rasterize to alpha imbuf? */
- ImBuf *ibuf = NULL;
- float *maskbuf;
- int i;
-
- if (!mask) {
- return NULL;
- }
- else {
- AnimData *adt;
- Mask *mask_temp;
- MaskRasterHandle *mr_handle;
+ /* TODO - add option to rasterize to alpha imbuf? */
+ ImBuf *ibuf = NULL;
+ float *maskbuf;
+ int i;
- mask_temp = BKE_mask_copy_nolib(mask);
+ if (!mask) {
+ return NULL;
+ }
+ else {
+ AnimData *adt;
+ Mask *mask_temp;
+ MaskRasterHandle *mr_handle;
- BKE_mask_evaluate(mask_temp, mask->sfra + nr, true);
+ mask_temp = BKE_mask_copy_nolib(mask);
- /* anim-data */
- adt = BKE_animdata_from_id(&mask->id);
- BKE_animsys_evaluate_animdata(context->depsgraph, context->scene, &mask_temp->id, adt, nr, ADT_RECALC_ANIM);
+ BKE_mask_evaluate(mask_temp, mask->sfra + nr, true);
- maskbuf = MEM_mallocN(sizeof(float) * context->rectx * context->recty, __func__);
+ /* anim-data */
+ adt = BKE_animdata_from_id(&mask->id);
+ BKE_animsys_evaluate_animdata(
+ context->depsgraph, context->scene, &mask_temp->id, adt, nr, ADT_RECALC_ANIM);
- mr_handle = BKE_maskrasterize_handle_new();
+ maskbuf = MEM_mallocN(sizeof(float) * context->rectx * context->recty, __func__);
- BKE_maskrasterize_handle_init(mr_handle, mask_temp, context->rectx, context->recty, true, true, true);
+ mr_handle = BKE_maskrasterize_handle_new();
- BKE_mask_free(mask_temp);
- MEM_freeN(mask_temp);
+ BKE_maskrasterize_handle_init(
+ mr_handle, mask_temp, context->rectx, context->recty, true, true, true);
- BKE_maskrasterize_buffer(mr_handle, context->rectx, context->recty, maskbuf);
+ BKE_mask_free(mask_temp);
+ MEM_freeN(mask_temp);
- BKE_maskrasterize_handle_free(mr_handle);
- }
+ BKE_maskrasterize_buffer(mr_handle, context->rectx, context->recty, maskbuf);
+ BKE_maskrasterize_handle_free(mr_handle);
+ }
- if (make_float) {
- /* pixels */
- const float *fp_src;
- float *fp_dst;
+ if (make_float) {
+ /* pixels */
+ const float *fp_src;
+ float *fp_dst;
- ibuf = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rectfloat);
+ ibuf = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rectfloat);
- fp_src = maskbuf;
- fp_dst = ibuf->rect_float;
- i = context->rectx * context->recty;
- while (--i) {
- fp_dst[0] = fp_dst[1] = fp_dst[2] = *fp_src;
- fp_dst[3] = 1.0f;
+ fp_src = maskbuf;
+ fp_dst = ibuf->rect_float;
+ i = context->rectx * context->recty;
+ while (--i) {
+ fp_dst[0] = fp_dst[1] = fp_dst[2] = *fp_src;
+ fp_dst[3] = 1.0f;
- fp_src += 1;
- fp_dst += 4;
- }
- }
- else {
- /* pixels */
- const float *fp_src;
- unsigned char *ub_dst;
+ fp_src += 1;
+ fp_dst += 4;
+ }
+ }
+ else {
+ /* pixels */
+ const float *fp_src;
+ unsigned char *ub_dst;
- ibuf = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect);
+ ibuf = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect);
- fp_src = maskbuf;
- ub_dst = (unsigned char *)ibuf->rect;
- i = context->rectx * context->recty;
- while (--i) {
- ub_dst[0] = ub_dst[1] = ub_dst[2] = (unsigned char)(*fp_src * 255.0f); /* already clamped */
- ub_dst[3] = 255;
+ fp_src = maskbuf;
+ ub_dst = (unsigned char *)ibuf->rect;
+ i = context->rectx * context->recty;
+ while (--i) {
+ ub_dst[0] = ub_dst[1] = ub_dst[2] = (unsigned char)(*fp_src * 255.0f); /* already clamped */
+ ub_dst[3] = 255;
- fp_src += 1;
- ub_dst += 4;
- }
- }
+ fp_src += 1;
+ ub_dst += 4;
+ }
+ }
- MEM_freeN(maskbuf);
+ MEM_freeN(maskbuf);
- return ibuf;
+ return ibuf;
}
static ImBuf *seq_render_mask_strip(const SeqRenderData *context, Sequence *seq, float nr)
{
- bool make_float = (seq->flag & SEQ_MAKE_FLOAT) != 0;
+ bool make_float = (seq->flag & SEQ_MAKE_FLOAT) != 0;
- return seq_render_mask(context, seq->mask, nr, make_float);
+ return seq_render_mask(context, seq->mask, nr, make_float);
}
-static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq, float nr, float cfra)
+static ImBuf *seq_render_scene_strip(const SeqRenderData *context,
+ Sequence *seq,
+ float nr,
+ float cfra)
{
- ImBuf *ibuf = NULL;
- double frame;
- Object *camera;
+ ImBuf *ibuf = NULL;
+ double frame;
+ Object *camera;
- struct {
- int scemode;
- int cfra;
- float subframe;
+ struct {
+ int scemode;
+ int cfra;
+ float subframe;
#ifdef DURIAN_CAMERA_SWITCH
- int mode;
+ int mode;
#endif
- } orig_data;
-
- /* Old info:
- * Hack! This function can be called from do_render_seq(), in that case
- * the seq->scene can already have a Render initialized with same name,
- * so we have to use a default name. (compositor uses scene name to
- * find render).
- * However, when called from within the UI (image preview in sequencer)
- * we do want to use scene Render, that way the render result is defined
- * for display in render/imagewindow
- *
- * Hmm, don't see, why we can't do that all the time,
- * and since G.is_rendering is uhm, gone... (Peter)
- */
-
- /* New info:
- * Using the same name for the renders works just fine as the do_render_seq()
- * render is not used while the scene strips are rendered.
- *
- * However rendering from UI (through sequencer_preview_area_draw) can crash in
- * very many cases since other renders (material preview, an actual render etc.)
- * can be started while this sequence preview render is running. The only proper
- * solution is to make the sequencer preview render a proper job, which can be
- * stopped when needed. This would also give a nice progress bar for the preview
- * space so that users know there's something happening.
- *
- * As a result the active scene now only uses OpenGL rendering for the sequencer
- * preview. This is far from nice, but is the only way to prevent crashes at this
- * time.
- *
- * -jahka
- */
-
- const bool is_rendering = G.is_rendering;
- const bool is_background = G.background;
- const bool do_seq_gl = is_rendering ?
- 0 /* (context->scene->r.seq_flag & R_SEQ_GL_REND) */ :
- (context->scene->r.seq_prev_type) != OB_RENDER;
- // bool have_seq = false; /* UNUSED */
- bool have_comp = false;
- bool use_gpencil = true;
- /* do we need to re-evaluate the frame after rendering? */
- bool is_frame_update = false;
- Scene *scene;
- int is_thread_main = BLI_thread_is_main();
-
- /* don't refer to seq->scene above this point!, it can be NULL */
- if (seq->scene == NULL) {
- return NULL;
- }
-
- scene = seq->scene;
- frame = (double)scene->r.sfra + (double)nr + (double)seq->anim_startofs;
-
- // have_seq = (scene->r.scemode & R_DOSEQ) && scene->ed && scene->ed->seqbase.first); /* UNUSED */
- have_comp = (scene->r.scemode & R_DOCOMP) && scene->use_nodes && scene->nodetree;
-
- /* Get view layer for the strip. */
- ViewLayer *view_layer = BKE_view_layer_default_render(scene);
- /* Depsgraph will be NULL when doing rendering. */
- Depsgraph *depsgraph = NULL;
-
- orig_data.scemode = scene->r.scemode;
- orig_data.cfra = scene->r.cfra;
- orig_data.subframe = scene->r.subframe;
+ } orig_data;
+
+ /* Old info:
+ * Hack! This function can be called from do_render_seq(), in that case
+ * the seq->scene can already have a Render initialized with same name,
+ * so we have to use a default name. (compositor uses scene name to
+ * find render).
+ * However, when called from within the UI (image preview in sequencer)
+ * we do want to use scene Render, that way the render result is defined
+ * for display in render/imagewindow
+ *
+ * Hmm, don't see, why we can't do that all the time,
+ * and since G.is_rendering is uhm, gone... (Peter)
+ */
+
+ /* New info:
+ * Using the same name for the renders works just fine as the do_render_seq()
+ * render is not used while the scene strips are rendered.
+ *
+ * However rendering from UI (through sequencer_preview_area_draw) can crash in
+ * very many cases since other renders (material preview, an actual render etc.)
+ * can be started while this sequence preview render is running. The only proper
+ * solution is to make the sequencer preview render a proper job, which can be
+ * stopped when needed. This would also give a nice progress bar for the preview
+ * space so that users know there's something happening.
+ *
+ * As a result the active scene now only uses OpenGL rendering for the sequencer
+ * preview. This is far from nice, but is the only way to prevent crashes at this
+ * time.
+ *
+ * -jahka
+ */
+
+ const bool is_rendering = G.is_rendering;
+ const bool is_background = G.background;
+ const bool do_seq_gl = is_rendering ? 0 /* (context->scene->r.seq_flag & R_SEQ_GL_REND) */ :
+ (context->scene->r.seq_prev_type) != OB_RENDER;
+ // bool have_seq = false; /* UNUSED */
+ bool have_comp = false;
+ bool use_gpencil = true;
+ /* do we need to re-evaluate the frame after rendering? */
+ bool is_frame_update = false;
+ Scene *scene;
+ int is_thread_main = BLI_thread_is_main();
+
+ /* don't refer to seq->scene above this point!, it can be NULL */
+ if (seq->scene == NULL) {
+ return NULL;
+ }
+
+ scene = seq->scene;
+ frame = (double)scene->r.sfra + (double)nr + (double)seq->anim_startofs;
+
+ // have_seq = (scene->r.scemode & R_DOSEQ) && scene->ed && scene->ed->seqbase.first); /* UNUSED */
+ have_comp = (scene->r.scemode & R_DOCOMP) && scene->use_nodes && scene->nodetree;
+
+ /* Get view layer for the strip. */
+ ViewLayer *view_layer = BKE_view_layer_default_render(scene);
+ /* Depsgraph will be NULL when doing rendering. */
+ Depsgraph *depsgraph = NULL;
+
+ orig_data.scemode = scene->r.scemode;
+ orig_data.cfra = scene->r.cfra;
+ orig_data.subframe = scene->r.subframe;
#ifdef DURIAN_CAMERA_SWITCH
- orig_data.mode = scene->r.mode;
+ orig_data.mode = scene->r.mode;
#endif
- BKE_scene_frame_set(scene, frame);
+ BKE_scene_frame_set(scene, frame);
- if (seq->scene_camera) {
- camera = seq->scene_camera;
- }
- else {
- BKE_scene_camera_switch_update(scene);
- camera = scene->camera;
- }
+ if (seq->scene_camera) {
+ camera = seq->scene_camera;
+ }
+ else {
+ BKE_scene_camera_switch_update(scene);
+ camera = scene->camera;
+ }
- if (have_comp == false && camera == NULL) {
- goto finally;
- }
+ if (have_comp == false && camera == NULL) {
+ goto finally;
+ }
- if (seq->flag & SEQ_SCENE_NO_GPENCIL) {
- use_gpencil = false;
- }
+ if (seq->flag & SEQ_SCENE_NO_GPENCIL) {
+ use_gpencil = false;
+ }
- /* prevent eternal loop */
- scene->r.scemode &= ~R_DOSEQ;
+ /* prevent eternal loop */
+ scene->r.scemode &= ~R_DOSEQ;
#ifdef DURIAN_CAMERA_SWITCH
- /* stooping to new low's in hackyness :( */
- scene->r.mode |= R_NO_CAMERA_SWITCH;
+ /* stooping to new low's in hackyness :( */
+ scene->r.mode |= R_NO_CAMERA_SWITCH;
#endif
- is_frame_update = (orig_data.cfra != scene->r.cfra) || (orig_data.subframe != scene->r.subframe);
-
- if ((sequencer_view3d_cb && do_seq_gl && camera) && is_thread_main) {
- char err_out[256] = "unknown";
- const int width = (scene->r.xsch * scene->r.size) / 100;
- const int height = (scene->r.ysch * scene->r.size) / 100;
- const bool use_background = (scene->r.alphamode == R_ADDSKY);
- const char *viewname = BKE_scene_multiview_render_view_name_get(&scene->r, context->view_id);
-
- unsigned int draw_flags = SEQ_OFSDRAW_NONE;
- draw_flags |= (use_gpencil) ? SEQ_OFSDRAW_USE_GPENCIL : 0;
- draw_flags |= (use_background) ? SEQ_OFSDRAW_USE_BACKGROUND : 0;
- draw_flags |= (context->gpu_full_samples) ? SEQ_OFSDRAW_USE_FULL_SAMPLE : 0;
- draw_flags |= (context->scene->r.seq_flag & R_SEQ_SOLID_TEX) ? SEQ_OFSDRAW_USE_SOLID_TEX : 0;
- draw_flags |= (context->scene->r.seq_flag & R_SEQ_CAMERA_DOF) ? SEQ_OFSDRAW_USE_CAMERA_DOF : 0;
-
- /* for old scene this can be uninitialized,
- * should probably be added to do_versions at some point if the functionality stays */
- if (context->scene->r.seq_prev_type == 0)
- context->scene->r.seq_prev_type = 3 /* == OB_SOLID */;
-
- /* opengl offscreen render */
- depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
- BKE_scene_graph_update_for_newframe(depsgraph, context->bmain);
- ibuf = sequencer_view3d_cb(
- /* set for OpenGL render (NULL when scrubbing) */
- depsgraph, scene,
- context->scene->r.seq_prev_type,
- camera, width, height, IB_rect,
- draw_flags,
- scene->r.alphamode, context->gpu_samples, viewname,
- context->gpu_offscreen, err_out);
- if (ibuf == NULL) {
- fprintf(stderr, "seq_render_scene_strip failed to get opengl buffer: %s\n", err_out);
- }
- }
- else {
- Render *re = RE_GetSceneRender(scene);
- const int totviews = BKE_scene_multiview_num_views_get(&scene->r);
- int i;
- ImBuf **ibufs_arr;
-
- ibufs_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs");
-
- /* XXX: this if can be removed when sequence preview rendering uses the job system
- *
- * disable rendered preview for sequencer while rendering -- it's very much possible
- * that preview render will went into conflict with final render
- *
- * When rendering from command line renderer is called from main thread, in this
- * case it's always safe to render scene here
- */
- if (!is_thread_main || is_rendering == false || is_background || context->for_render) {
- if (re == NULL)
- re = RE_NewSceneRender(scene);
-
- RE_BlenderFrame(re, context->bmain, scene, view_layer, camera, frame, false);
-
- /* restore previous state after it was toggled on & off by RE_BlenderFrame */
- G.is_rendering = is_rendering;
- }
-
- for (i = 0; i < totviews; i++) {
- SeqRenderData localcontext = *context;
- RenderResult rres;
-
- localcontext.view_id = i;
-
- RE_AcquireResultImage(re, &rres, i);
-
- if (rres.rectf) {
- ibufs_arr[i] = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rectfloat);
- memcpy(ibufs_arr[i]->rect_float, rres.rectf, 4 * sizeof(float) * rres.rectx * rres.recty);
-
- if (rres.rectz) {
- addzbuffloatImBuf(ibufs_arr[i]);
- memcpy(ibufs_arr[i]->zbuf_float, rres.rectz, sizeof(float) * rres.rectx * rres.recty);
- }
-
- /* float buffers in the sequencer are not linear */
- BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibufs_arr[i], false);
- }
- else if (rres.rect32) {
- ibufs_arr[i] = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rect);
- memcpy(ibufs_arr[i]->rect, rres.rect32, 4 * rres.rectx * rres.recty);
- }
-
- if (i != context->view_id) {
- copy_to_ibuf_still(&localcontext, seq, nr, ibufs_arr[i]);
- BKE_sequencer_cache_put(&localcontext, seq, cfra, SEQ_STRIPELEM_IBUF, ibufs_arr[i]);
- }
-
- RE_ReleaseResultImage(re);
- }
-
- /* return the original requested ImBuf */
- ibuf = ibufs_arr[context->view_id];
-
- /* "remove" the others (decrease their refcount) */
- for (i = 0; i < totviews; i++) {
- if (ibufs_arr[i] != ibuf) {
- IMB_freeImBuf(ibufs_arr[i]);
- }
- }
- MEM_freeN(ibufs_arr);
- }
-
+ is_frame_update = (orig_data.cfra != scene->r.cfra) || (orig_data.subframe != scene->r.subframe);
+
+ if ((sequencer_view3d_cb && do_seq_gl && camera) && is_thread_main) {
+ char err_out[256] = "unknown";
+ const int width = (scene->r.xsch * scene->r.size) / 100;
+ const int height = (scene->r.ysch * scene->r.size) / 100;
+ const bool use_background = (scene->r.alphamode == R_ADDSKY);
+ const char *viewname = BKE_scene_multiview_render_view_name_get(&scene->r, context->view_id);
+
+ unsigned int draw_flags = SEQ_OFSDRAW_NONE;
+ draw_flags |= (use_gpencil) ? SEQ_OFSDRAW_USE_GPENCIL : 0;
+ draw_flags |= (use_background) ? SEQ_OFSDRAW_USE_BACKGROUND : 0;
+ draw_flags |= (context->gpu_full_samples) ? SEQ_OFSDRAW_USE_FULL_SAMPLE : 0;
+ draw_flags |= (context->scene->r.seq_flag & R_SEQ_SOLID_TEX) ? SEQ_OFSDRAW_USE_SOLID_TEX : 0;
+ draw_flags |= (context->scene->r.seq_flag & R_SEQ_CAMERA_DOF) ? SEQ_OFSDRAW_USE_CAMERA_DOF : 0;
+
+ /* for old scene this can be uninitialized,
+ * should probably be added to do_versions at some point if the functionality stays */
+ if (context->scene->r.seq_prev_type == 0)
+ context->scene->r.seq_prev_type = 3 /* == OB_SOLID */;
+
+ /* opengl offscreen render */
+ depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ BKE_scene_graph_update_for_newframe(depsgraph, context->bmain);
+ ibuf = sequencer_view3d_cb(
+ /* set for OpenGL render (NULL when scrubbing) */
+ depsgraph,
+ scene,
+ context->scene->r.seq_prev_type,
+ camera,
+ width,
+ height,
+ IB_rect,
+ draw_flags,
+ scene->r.alphamode,
+ context->gpu_samples,
+ viewname,
+ context->gpu_offscreen,
+ err_out);
+ if (ibuf == NULL) {
+ fprintf(stderr, "seq_render_scene_strip failed to get opengl buffer: %s\n", err_out);
+ }
+ }
+ else {
+ Render *re = RE_GetSceneRender(scene);
+ const int totviews = BKE_scene_multiview_num_views_get(&scene->r);
+ int i;
+ ImBuf **ibufs_arr;
+
+ ibufs_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs");
+
+ /* XXX: this if can be removed when sequence preview rendering uses the job system
+ *
+ * disable rendered preview for sequencer while rendering -- it's very much possible
+ * that preview render will went into conflict with final render
+ *
+ * When rendering from command line renderer is called from main thread, in this
+ * case it's always safe to render scene here
+ */
+ if (!is_thread_main || is_rendering == false || is_background || context->for_render) {
+ if (re == NULL)
+ re = RE_NewSceneRender(scene);
+
+ RE_BlenderFrame(re, context->bmain, scene, view_layer, camera, frame, false);
+
+ /* restore previous state after it was toggled on & off by RE_BlenderFrame */
+ G.is_rendering = is_rendering;
+ }
+
+ for (i = 0; i < totviews; i++) {
+ SeqRenderData localcontext = *context;
+ RenderResult rres;
+
+ localcontext.view_id = i;
+
+ RE_AcquireResultImage(re, &rres, i);
+
+ if (rres.rectf) {
+ ibufs_arr[i] = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rectfloat);
+ memcpy(ibufs_arr[i]->rect_float, rres.rectf, 4 * sizeof(float) * rres.rectx * rres.recty);
+
+ if (rres.rectz) {
+ addzbuffloatImBuf(ibufs_arr[i]);
+ memcpy(ibufs_arr[i]->zbuf_float, rres.rectz, sizeof(float) * rres.rectx * rres.recty);
+ }
+
+ /* float buffers in the sequencer are not linear */
+ BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibufs_arr[i], false);
+ }
+ else if (rres.rect32) {
+ ibufs_arr[i] = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rect);
+ memcpy(ibufs_arr[i]->rect, rres.rect32, 4 * rres.rectx * rres.recty);
+ }
+
+ if (i != context->view_id) {
+ copy_to_ibuf_still(&localcontext, seq, nr, ibufs_arr[i]);
+ BKE_sequencer_cache_put(&localcontext, seq, cfra, SEQ_STRIPELEM_IBUF, ibufs_arr[i]);
+ }
+
+ RE_ReleaseResultImage(re);
+ }
+
+ /* return the original requested ImBuf */
+ ibuf = ibufs_arr[context->view_id];
+
+ /* "remove" the others (decrease their refcount) */
+ for (i = 0; i < totviews; i++) {
+ if (ibufs_arr[i] != ibuf) {
+ IMB_freeImBuf(ibufs_arr[i]);
+ }
+ }
+ MEM_freeN(ibufs_arr);
+ }
finally:
- /* restore */
- scene->r.scemode = orig_data.scemode;
- scene->r.cfra = orig_data.cfra;
- scene->r.subframe = orig_data.subframe;
+ /* restore */
+ scene->r.scemode = orig_data.scemode;
+ scene->r.cfra = orig_data.cfra;
+ scene->r.subframe = orig_data.subframe;
- if (is_frame_update && (depsgraph != NULL)) {
- BKE_scene_graph_update_for_newframe(depsgraph, context->bmain);
- }
+ if (is_frame_update && (depsgraph != NULL)) {
+ BKE_scene_graph_update_for_newframe(depsgraph, context->bmain);
+ }
#ifdef DURIAN_CAMERA_SWITCH
- /* stooping to new low's in hackyness :( */
- scene->r.mode &= ~(orig_data.mode & R_NO_CAMERA_SWITCH);
+ /* stooping to new low's in hackyness :( */
+ scene->r.mode &= ~(orig_data.mode & R_NO_CAMERA_SWITCH);
#endif
- return ibuf;
+ return ibuf;
}
/**
* Used for meta-strips & scenes with #SEQ_SCENE_STRIPS flag set.
*/
-static ImBuf *do_render_strip_seqbase(
- const SeqRenderData *context, SeqRenderState *state,
- Sequence *seq, float nr, bool use_preprocess)
-{
- ImBuf *meta_ibuf = NULL, *ibuf = NULL;
- ListBase *seqbase = NULL;
- int offset;
-
- seqbase = BKE_sequence_seqbase_get(seq, &offset);
-
- if (seqbase && !BLI_listbase_is_empty(seqbase)) {
- meta_ibuf = seq_render_strip_stack(
- context, state, seqbase,
- /* scene strips don't have their start taken into account */
- nr + offset, 0);
- }
-
- if (meta_ibuf) {
- ibuf = meta_ibuf;
- if (ibuf && use_preprocess) {
- ImBuf *i = IMB_dupImBuf(ibuf);
-
- IMB_freeImBuf(ibuf);
-
- ibuf = i;
- }
- }
-
- return ibuf;
-}
-
-static ImBuf *do_render_strip_uncached(
- const SeqRenderData *context, SeqRenderState *state,
- Sequence *seq, float cfra)
-{
- ImBuf *ibuf = NULL;
- float nr = give_stripelem_index(seq, cfra);
- int type = (seq->type & SEQ_TYPE_EFFECT && seq->type != SEQ_TYPE_SPEED) ? SEQ_TYPE_EFFECT : seq->type;
- bool use_preprocess = BKE_sequencer_input_have_to_preprocess(context, seq, cfra);
-
- switch (type) {
- case SEQ_TYPE_META:
- {
- ibuf = do_render_strip_seqbase(context, state, seq, nr, use_preprocess);
- break;
- }
-
- case SEQ_TYPE_SCENE:
- {
- if (seq->flag & SEQ_SCENE_STRIPS) {
- if (seq->scene && (context->scene != seq->scene)) {
- /* recusrive check */
- if (BLI_linklist_index(state->scene_parents, seq->scene) != -1) {
- break;
- }
- LinkNode scene_parent = { .next = state->scene_parents, .link = seq->scene, };
- state->scene_parents = &scene_parent;
- /* end check */
-
- /* Use the Scene Seq's scene for the context when rendering the scene's sequences
- * (necessary for Multicam Selector among others).
- */
- SeqRenderData local_context = *context;
- local_context.scene = seq->scene;
-
- ibuf = do_render_strip_seqbase(&local_context, state, seq, nr, use_preprocess);
-
- /* step back in the list */
- state->scene_parents = state->scene_parents->next;
- }
- }
- else {
- /* scene can be NULL after deletions */
- ibuf = seq_render_scene_strip(context, seq, nr, cfra);
-
- /* Scene strips update all animation, so we need to restore original state.*/
- BKE_animsys_evaluate_all_animation(context->bmain, context->depsgraph, context->scene, cfra);
-
- copy_to_ibuf_still(context, seq, nr, ibuf);
- }
- break;
- }
-
- case SEQ_TYPE_SPEED:
- {
- ImBuf *child_ibuf = NULL;
-
- float f_cfra;
- SpeedControlVars *s = (SpeedControlVars *)seq->effectdata;
-
- BKE_sequence_effect_speed_rebuild_map(context->scene, seq, false);
-
- /* weeek! */
- f_cfra = seq->start + s->frameMap[(int)nr];
-
- child_ibuf = seq_render_strip(context, state, seq->seq1, f_cfra);
-
- if (child_ibuf) {
- ibuf = child_ibuf;
- if (ibuf && use_preprocess) {
- ImBuf *i = IMB_dupImBuf(ibuf);
-
- IMB_freeImBuf(ibuf);
-
- ibuf = i;
- }
- }
- break;
- }
-
- case SEQ_TYPE_EFFECT:
- {
- ibuf = seq_render_effect_strip_impl(context, state, seq, seq->start + nr);
- break;
- }
-
- case SEQ_TYPE_IMAGE:
- {
- ibuf = seq_render_image_strip(context, seq, nr, cfra);
- copy_to_ibuf_still(context, seq, nr, ibuf);
- break;
- }
-
- case SEQ_TYPE_MOVIE:
- {
- ibuf = seq_render_movie_strip(context, seq, nr, cfra);
- copy_to_ibuf_still(context, seq, nr, ibuf);
- break;
- }
-
- case SEQ_TYPE_MOVIECLIP:
- {
- ibuf = seq_render_movieclip_strip(context, seq, nr);
-
- if (ibuf) {
- /* duplicate frame so movie cache wouldn't be confused by sequencer's stuff */
- ImBuf *i = IMB_dupImBuf(ibuf);
- IMB_freeImBuf(ibuf);
- ibuf = i;
-
- if (ibuf->rect_float)
- BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false);
-
- copy_to_ibuf_still(context, seq, nr, ibuf);
- }
-
- break;
- }
-
- case SEQ_TYPE_MASK:
- {
- /* ibuf is always new */
- ibuf = seq_render_mask_strip(context, seq, nr);
-
- copy_to_ibuf_still(context, seq, nr, ibuf);
- break;
- }
- }
-
- if (ibuf)
- sequencer_imbuf_assign_spaces(context->scene, ibuf);
-
- return ibuf;
-}
-
-static ImBuf *seq_render_strip(
- const SeqRenderData *context, SeqRenderState *state,
- Sequence *seq, float cfra)
-{
- ImBuf *ibuf = NULL;
- bool use_preprocess = false;
- bool is_proxy_image = false;
- float nr = give_stripelem_index(seq, cfra);
- /* all effects are handled similarly with the exception of speed effect */
- int type = (seq->type & SEQ_TYPE_EFFECT && seq->type != SEQ_TYPE_SPEED) ? SEQ_TYPE_EFFECT : seq->type;
- bool is_preprocessed = !ELEM(type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE, SEQ_TYPE_SCENE, SEQ_TYPE_MOVIECLIP);
-
- ibuf = BKE_sequencer_cache_get(context, seq, cfra, SEQ_STRIPELEM_IBUF);
-
- if (ibuf == NULL) {
- ibuf = copy_from_ibuf_still(context, seq, nr);
-
- if (ibuf == NULL) {
- ibuf = BKE_sequencer_preprocessed_cache_get(context, seq, cfra, SEQ_STRIPELEM_IBUF);
-
- if (ibuf == NULL) {
- /* MOVIECLIPs have their own proxy management */
- if (seq->type != SEQ_TYPE_MOVIECLIP) {
- ibuf = seq_proxy_fetch(context, seq, cfra);
- is_proxy_image = (ibuf != NULL);
- }
-
- if (ibuf == NULL)
- ibuf = do_render_strip_uncached(context, state, seq, cfra);
-
- if (ibuf) {
- if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_MOVIECLIP)) {
- is_proxy_image = (context->preview_render_size != 100);
- }
- BKE_sequencer_preprocessed_cache_put(context, seq, cfra, SEQ_STRIPELEM_IBUF, ibuf);
- }
- }
- }
-
- if (ibuf)
- use_preprocess = BKE_sequencer_input_have_to_preprocess(context, seq, cfra);
- }
- else {
- /* currently, we cache preprocessed images in SEQ_STRIPELEM_IBUF,
- * but not(!) on SEQ_STRIPELEM_IBUF_ENDSTILL and ..._STARTSTILL
- * so, no need in check for preprocess here
- */
- }
-
- if (ibuf == NULL) {
- ibuf = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect);
- sequencer_imbuf_assign_spaces(context->scene, ibuf);
- }
-
- if (context->is_proxy_render == false &&
- (ibuf->x != context->rectx || ibuf->y != context->recty))
- {
- use_preprocess = true;
- }
-
- if (use_preprocess)
- ibuf = input_preprocess(context, seq, cfra, ibuf, is_proxy_image, is_preprocessed);
+static ImBuf *do_render_strip_seqbase(const SeqRenderData *context,
+ SeqRenderState *state,
+ Sequence *seq,
+ float nr,
+ bool use_preprocess)
+{
+ ImBuf *meta_ibuf = NULL, *ibuf = NULL;
+ ListBase *seqbase = NULL;
+ int offset;
+
+ seqbase = BKE_sequence_seqbase_get(seq, &offset);
+
+ if (seqbase && !BLI_listbase_is_empty(seqbase)) {
+ meta_ibuf = seq_render_strip_stack(context,
+ state,
+ seqbase,
+ /* scene strips don't have their start taken into account */
+ nr + offset,
+ 0);
+ }
+
+ if (meta_ibuf) {
+ ibuf = meta_ibuf;
+ if (ibuf && use_preprocess) {
+ ImBuf *i = IMB_dupImBuf(ibuf);
+
+ IMB_freeImBuf(ibuf);
+
+ ibuf = i;
+ }
+ }
+
+ return ibuf;
+}
+
+static ImBuf *do_render_strip_uncached(const SeqRenderData *context,
+ SeqRenderState *state,
+ Sequence *seq,
+ float cfra)
+{
+ ImBuf *ibuf = NULL;
+ float nr = give_stripelem_index(seq, cfra);
+ int type = (seq->type & SEQ_TYPE_EFFECT && seq->type != SEQ_TYPE_SPEED) ? SEQ_TYPE_EFFECT :
+ seq->type;
+ bool use_preprocess = BKE_sequencer_input_have_to_preprocess(context, seq, cfra);
+
+ switch (type) {
+ case SEQ_TYPE_META: {
+ ibuf = do_render_strip_seqbase(context, state, seq, nr, use_preprocess);
+ break;
+ }
+
+ case SEQ_TYPE_SCENE: {
+ if (seq->flag & SEQ_SCENE_STRIPS) {
+ if (seq->scene && (context->scene != seq->scene)) {
+ /* recusrive check */
+ if (BLI_linklist_index(state->scene_parents, seq->scene) != -1) {
+ break;
+ }
+ LinkNode scene_parent = {
+ .next = state->scene_parents,
+ .link = seq->scene,
+ };
+ state->scene_parents = &scene_parent;
+ /* end check */
+
+ /* Use the Scene Seq's scene for the context when rendering the scene's sequences
+ * (necessary for Multicam Selector among others).
+ */
+ SeqRenderData local_context = *context;
+ local_context.scene = seq->scene;
+
+ ibuf = do_render_strip_seqbase(&local_context, state, seq, nr, use_preprocess);
+
+ /* step back in the list */
+ state->scene_parents = state->scene_parents->next;
+ }
+ }
+ else {
+ /* scene can be NULL after deletions */
+ ibuf = seq_render_scene_strip(context, seq, nr, cfra);
+
+ /* Scene strips update all animation, so we need to restore original state.*/
+ BKE_animsys_evaluate_all_animation(
+ context->bmain, context->depsgraph, context->scene, cfra);
+
+ copy_to_ibuf_still(context, seq, nr, ibuf);
+ }
+ break;
+ }
+
+ case SEQ_TYPE_SPEED: {
+ ImBuf *child_ibuf = NULL;
+
+ float f_cfra;
+ SpeedControlVars *s = (SpeedControlVars *)seq->effectdata;
+
+ BKE_sequence_effect_speed_rebuild_map(context->scene, seq, false);
+
+ /* weeek! */
+ f_cfra = seq->start + s->frameMap[(int)nr];
+
+ child_ibuf = seq_render_strip(context, state, seq->seq1, f_cfra);
+
+ if (child_ibuf) {
+ ibuf = child_ibuf;
+ if (ibuf && use_preprocess) {
+ ImBuf *i = IMB_dupImBuf(ibuf);
+
+ IMB_freeImBuf(ibuf);
+
+ ibuf = i;
+ }
+ }
+ break;
+ }
+
+ case SEQ_TYPE_EFFECT: {
+ ibuf = seq_render_effect_strip_impl(context, state, seq, seq->start + nr);
+ break;
+ }
+
+ case SEQ_TYPE_IMAGE: {
+ ibuf = seq_render_image_strip(context, seq, nr, cfra);
+ copy_to_ibuf_still(context, seq, nr, ibuf);
+ break;
+ }
+
+ case SEQ_TYPE_MOVIE: {
+ ibuf = seq_render_movie_strip(context, seq, nr, cfra);
+ copy_to_ibuf_still(context, seq, nr, ibuf);
+ break;
+ }
+
+ case SEQ_TYPE_MOVIECLIP: {
+ ibuf = seq_render_movieclip_strip(context, seq, nr);
+
+ if (ibuf) {
+ /* duplicate frame so movie cache wouldn't be confused by sequencer's stuff */
+ ImBuf *i = IMB_dupImBuf(ibuf);
+ IMB_freeImBuf(ibuf);
+ ibuf = i;
+
+ if (ibuf->rect_float)
+ BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false);
+
+ copy_to_ibuf_still(context, seq, nr, ibuf);
+ }
+
+ break;
+ }
+
+ case SEQ_TYPE_MASK: {
+ /* ibuf is always new */
+ ibuf = seq_render_mask_strip(context, seq, nr);
+
+ copy_to_ibuf_still(context, seq, nr, ibuf);
+ break;
+ }
+ }
+
+ if (ibuf)
+ sequencer_imbuf_assign_spaces(context->scene, ibuf);
+
+ return ibuf;
+}
+
+static ImBuf *seq_render_strip(const SeqRenderData *context,
+ SeqRenderState *state,
+ Sequence *seq,
+ float cfra)
+{
+ ImBuf *ibuf = NULL;
+ bool use_preprocess = false;
+ bool is_proxy_image = false;
+ float nr = give_stripelem_index(seq, cfra);
+ /* all effects are handled similarly with the exception of speed effect */
+ int type = (seq->type & SEQ_TYPE_EFFECT && seq->type != SEQ_TYPE_SPEED) ? SEQ_TYPE_EFFECT :
+ seq->type;
+ bool is_preprocessed = !ELEM(
+ type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE, SEQ_TYPE_SCENE, SEQ_TYPE_MOVIECLIP);
- BKE_sequencer_cache_put(context, seq, cfra, SEQ_STRIPELEM_IBUF, ibuf);
+ ibuf = BKE_sequencer_cache_get(context, seq, cfra, SEQ_STRIPELEM_IBUF);
- return ibuf;
-}
+ if (ibuf == NULL) {
+ ibuf = copy_from_ibuf_still(context, seq, nr);
-/*********************** strip stack rendering functions *************************/
+ if (ibuf == NULL) {
+ ibuf = BKE_sequencer_preprocessed_cache_get(context, seq, cfra, SEQ_STRIPELEM_IBUF);
-static bool seq_must_swap_input_in_blend_mode(Sequence *seq)
-{
- bool swap_input = false;
+ if (ibuf == NULL) {
+ /* MOVIECLIPs have their own proxy management */
+ if (seq->type != SEQ_TYPE_MOVIECLIP) {
+ ibuf = seq_proxy_fetch(context, seq, cfra);
+ is_proxy_image = (ibuf != NULL);
+ }
- /* bad hack, to fix crazy input ordering of
- * those two effects */
+ if (ibuf == NULL)
+ ibuf = do_render_strip_uncached(context, state, seq, cfra);
+
+ if (ibuf) {
+ if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_MOVIECLIP)) {
+ is_proxy_image = (context->preview_render_size != 100);
+ }
+ BKE_sequencer_preprocessed_cache_put(context, seq, cfra, SEQ_STRIPELEM_IBUF, ibuf);
+ }
+ }
+ }
+
+ if (ibuf)
+ use_preprocess = BKE_sequencer_input_have_to_preprocess(context, seq, cfra);
+ }
+ else {
+ /* currently, we cache preprocessed images in SEQ_STRIPELEM_IBUF,
+ * but not(!) on SEQ_STRIPELEM_IBUF_ENDSTILL and ..._STARTSTILL
+ * so, no need in check for preprocess here
+ */
+ }
+
+ if (ibuf == NULL) {
+ ibuf = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect);
+ sequencer_imbuf_assign_spaces(context->scene, ibuf);
+ }
+
+ if (context->is_proxy_render == false &&
+ (ibuf->x != context->rectx || ibuf->y != context->recty)) {
+ use_preprocess = true;
+ }
+
+ if (use_preprocess)
+ ibuf = input_preprocess(context, seq, cfra, ibuf, is_proxy_image, is_preprocessed);
- if (ELEM(seq->blend_mode, SEQ_TYPE_ALPHAOVER, SEQ_TYPE_ALPHAUNDER, SEQ_TYPE_OVERDROP)) {
- swap_input = true;
- }
+ BKE_sequencer_cache_put(context, seq, cfra, SEQ_STRIPELEM_IBUF, ibuf);
- return swap_input;
+ return ibuf;
}
-static int seq_get_early_out_for_blend_mode(Sequence *seq)
-{
- struct SeqEffectHandle sh = BKE_sequence_get_blend(seq);
- float facf = seq->blend_opacity / 100.0f;
- int early_out = sh.early_out(seq, facf, facf);
-
- if (ELEM(early_out, EARLY_DO_EFFECT, EARLY_NO_INPUT)) {
- return early_out;
- }
-
- if (seq_must_swap_input_in_blend_mode(seq)) {
- if (early_out == EARLY_USE_INPUT_2) {
- return EARLY_USE_INPUT_1;
- }
- else if (early_out == EARLY_USE_INPUT_1) {
- return EARLY_USE_INPUT_2;
- }
- }
- return early_out;
-}
+/*********************** strip stack rendering functions *************************/
-static ImBuf *seq_render_strip_stack_apply_effect(const SeqRenderData *context, Sequence *seq,
- float cfra, ImBuf *ibuf1, ImBuf *ibuf2)
+static bool seq_must_swap_input_in_blend_mode(Sequence *seq)
{
- ImBuf *out;
- struct SeqEffectHandle sh = BKE_sequence_get_blend(seq);
- float facf = seq->blend_opacity / 100.0f;
- int swap_input = seq_must_swap_input_in_blend_mode(seq);
+ bool swap_input = false;
+
+ /* bad hack, to fix crazy input ordering of
+ * those two effects */
- if (swap_input) {
- if (sh.multithreaded)
- out = seq_render_effect_execute_threaded(&sh, context, seq, cfra, facf, facf, ibuf2, ibuf1, NULL);
- else
- out = sh.execute(context, seq, cfra, facf, facf, ibuf2, ibuf1, NULL);
- }
- else {
- if (sh.multithreaded)
- out = seq_render_effect_execute_threaded(&sh, context, seq, cfra, facf, facf, ibuf1, ibuf2, NULL);
- else
- out = sh.execute(context, seq, cfra, facf, facf, ibuf1, ibuf2, NULL);
- }
+ if (ELEM(seq->blend_mode, SEQ_TYPE_ALPHAOVER, SEQ_TYPE_ALPHAUNDER, SEQ_TYPE_OVERDROP)) {
+ swap_input = true;
+ }
- return out;
+ return swap_input;
}
-static ImBuf *seq_render_strip_stack(
- const SeqRenderData *context, SeqRenderState *state, ListBase *seqbasep,
- float cfra, int chanshown)
+static int seq_get_early_out_for_blend_mode(Sequence *seq)
{
- Sequence *seq_arr[MAXSEQ + 1];
- int count;
- int i;
- ImBuf *out = NULL;
-
- count = get_shown_sequences(seqbasep, cfra, chanshown, (Sequence **)&seq_arr);
-
- if (count == 0) {
- return NULL;
- }
+ struct SeqEffectHandle sh = BKE_sequence_get_blend(seq);
+ float facf = seq->blend_opacity / 100.0f;
+ int early_out = sh.early_out(seq, facf, facf);
+
+ if (ELEM(early_out, EARLY_DO_EFFECT, EARLY_NO_INPUT)) {
+ return early_out;
+ }
+
+ if (seq_must_swap_input_in_blend_mode(seq)) {
+ if (early_out == EARLY_USE_INPUT_2) {
+ return EARLY_USE_INPUT_1;
+ }
+ else if (early_out == EARLY_USE_INPUT_1) {
+ return EARLY_USE_INPUT_2;
+ }
+ }
+ return early_out;
+}
+
+static ImBuf *seq_render_strip_stack_apply_effect(
+ const SeqRenderData *context, Sequence *seq, float cfra, ImBuf *ibuf1, ImBuf *ibuf2)
+{
+ ImBuf *out;
+ struct SeqEffectHandle sh = BKE_sequence_get_blend(seq);
+ float facf = seq->blend_opacity / 100.0f;
+ int swap_input = seq_must_swap_input_in_blend_mode(seq);
+
+ if (swap_input) {
+ if (sh.multithreaded)
+ out = seq_render_effect_execute_threaded(
+ &sh, context, seq, cfra, facf, facf, ibuf2, ibuf1, NULL);
+ else
+ out = sh.execute(context, seq, cfra, facf, facf, ibuf2, ibuf1, NULL);
+ }
+ else {
+ if (sh.multithreaded)
+ out = seq_render_effect_execute_threaded(
+ &sh, context, seq, cfra, facf, facf, ibuf1, ibuf2, NULL);
+ else
+ out = sh.execute(context, seq, cfra, facf, facf, ibuf1, ibuf2, NULL);
+ }
+
+ return out;
+}
+
+static ImBuf *seq_render_strip_stack(const SeqRenderData *context,
+ SeqRenderState *state,
+ ListBase *seqbasep,
+ float cfra,
+ int chanshown)
+{
+ Sequence *seq_arr[MAXSEQ + 1];
+ int count;
+ int i;
+ ImBuf *out = NULL;
+
+ count = get_shown_sequences(seqbasep, cfra, chanshown, (Sequence **)&seq_arr);
+
+ if (count == 0) {
+ return NULL;
+ }
#if 0 /* commentind since this breaks keyframing, since it resets the value on draw */
- if (scene->r.cfra != cfra) {
- /* XXX for prefetch and overlay offset!..., very bad!!! */
- AnimData *adt = BKE_animdata_from_id(&scene->id);
- BKE_animsys_evaluate_animdata(scene, &scene->id, adt, cfra, ADT_RECALC_ANIM);
- }
+ if (scene->r.cfra != cfra) {
+ /* XXX for prefetch and overlay offset!..., very bad!!! */
+ AnimData *adt = BKE_animdata_from_id(&scene->id);
+ BKE_animsys_evaluate_animdata(scene, &scene->id, adt, cfra, ADT_RECALC_ANIM);
+ }
#endif
- out = BKE_sequencer_cache_get(context, seq_arr[count - 1], cfra, SEQ_STRIPELEM_IBUF_COMP);
-
- if (out) {
- return out;
- }
-
- if (count == 1) {
- Sequence *seq = seq_arr[0];
-
- /* Some of the blend modes are unclear how to apply with only single input,
- * or some of them will just produce an empty result..
- */
- if (ELEM(seq->blend_mode, SEQ_BLEND_REPLACE, SEQ_TYPE_CROSS, SEQ_TYPE_ALPHAOVER)) {
- int early_out;
- if (seq->blend_mode == SEQ_BLEND_REPLACE) {
- early_out = EARLY_NO_INPUT;
- }
- else {
- early_out = seq_get_early_out_for_blend_mode(seq);
- }
-
- if (ELEM(early_out, EARLY_NO_INPUT, EARLY_USE_INPUT_2)) {
- out = seq_render_strip(context, state, seq, cfra);
- }
- else if (early_out == EARLY_USE_INPUT_1) {
- out = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect);
- }
- else {
- out = seq_render_strip(context, state, seq, cfra);
-
- if (early_out == EARLY_DO_EFFECT) {
- ImBuf *ibuf1 = IMB_allocImBuf(context->rectx, context->recty, 32,
- out->rect_float ? IB_rectfloat : IB_rect);
- ImBuf *ibuf2 = out;
-
- out = seq_render_strip_stack_apply_effect(context, seq, cfra, ibuf1, ibuf2);
- if (out) {
- IMB_metadata_copy(out, ibuf2);
- }
-
- IMB_freeImBuf(ibuf1);
- IMB_freeImBuf(ibuf2);
- }
- }
- }
- else {
- out = seq_render_strip(context, state, seq, cfra);
- }
-
- BKE_sequencer_cache_put(context, seq, cfra, SEQ_STRIPELEM_IBUF_COMP, out);
-
- return out;
- }
-
- for (i = count - 1; i >= 0; i--) {
- int early_out;
- Sequence *seq = seq_arr[i];
-
- out = BKE_sequencer_cache_get(context, seq, cfra, SEQ_STRIPELEM_IBUF_COMP);
-
- if (out) {
- break;
- }
- if (seq->blend_mode == SEQ_BLEND_REPLACE) {
- out = seq_render_strip(context, state, seq, cfra);
- break;
- }
-
- early_out = seq_get_early_out_for_blend_mode(seq);
-
- switch (early_out) {
- case EARLY_NO_INPUT:
- case EARLY_USE_INPUT_2:
- out = seq_render_strip(context, state, seq, cfra);
- break;
- case EARLY_USE_INPUT_1:
- if (i == 0) {
- out = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect);
- }
- break;
- case EARLY_DO_EFFECT:
- if (i == 0) {
- ImBuf *ibuf1 = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect);
- ImBuf *ibuf2 = seq_render_strip(context, state, seq, cfra);
-
- out = seq_render_strip_stack_apply_effect(context, seq, cfra, ibuf1, ibuf2);
-
- IMB_freeImBuf(ibuf1);
- IMB_freeImBuf(ibuf2);
- }
-
- break;
- }
- if (out) {
- break;
- }
- }
-
- BKE_sequencer_cache_put(context, seq_arr[i], cfra, SEQ_STRIPELEM_IBUF_COMP, out);
-
- i++;
-
- for (; i < count; i++) {
- Sequence *seq = seq_arr[i];
-
- if (seq_get_early_out_for_blend_mode(seq) == EARLY_DO_EFFECT) {
- ImBuf *ibuf1 = out;
- ImBuf *ibuf2 = seq_render_strip(context, state, seq, cfra);
-
- out = seq_render_strip_stack_apply_effect(context, seq, cfra, ibuf1, ibuf2);
-
- IMB_freeImBuf(ibuf1);
- IMB_freeImBuf(ibuf2);
- }
-
- BKE_sequencer_cache_put(context, seq_arr[i], cfra, SEQ_STRIPELEM_IBUF_COMP, out);
- }
-
- return out;
+ out = BKE_sequencer_cache_get(context, seq_arr[count - 1], cfra, SEQ_STRIPELEM_IBUF_COMP);
+
+ if (out) {
+ return out;
+ }
+
+ if (count == 1) {
+ Sequence *seq = seq_arr[0];
+
+ /* Some of the blend modes are unclear how to apply with only single input,
+ * or some of them will just produce an empty result..
+ */
+ if (ELEM(seq->blend_mode, SEQ_BLEND_REPLACE, SEQ_TYPE_CROSS, SEQ_TYPE_ALPHAOVER)) {
+ int early_out;
+ if (seq->blend_mode == SEQ_BLEND_REPLACE) {
+ early_out = EARLY_NO_INPUT;
+ }
+ else {
+ early_out = seq_get_early_out_for_blend_mode(seq);
+ }
+
+ if (ELEM(early_out, EARLY_NO_INPUT, EARLY_USE_INPUT_2)) {
+ out = seq_render_strip(context, state, seq, cfra);
+ }
+ else if (early_out == EARLY_USE_INPUT_1) {
+ out = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect);
+ }
+ else {
+ out = seq_render_strip(context, state, seq, cfra);
+
+ if (early_out == EARLY_DO_EFFECT) {
+ ImBuf *ibuf1 = IMB_allocImBuf(
+ context->rectx, context->recty, 32, out->rect_float ? IB_rectfloat : IB_rect);
+ ImBuf *ibuf2 = out;
+
+ out = seq_render_strip_stack_apply_effect(context, seq, cfra, ibuf1, ibuf2);
+ if (out) {
+ IMB_metadata_copy(out, ibuf2);
+ }
+
+ IMB_freeImBuf(ibuf1);
+ IMB_freeImBuf(ibuf2);
+ }
+ }
+ }
+ else {
+ out = seq_render_strip(context, state, seq, cfra);
+ }
+
+ BKE_sequencer_cache_put(context, seq, cfra, SEQ_STRIPELEM_IBUF_COMP, out);
+
+ return out;
+ }
+
+ for (i = count - 1; i >= 0; i--) {
+ int early_out;
+ Sequence *seq = seq_arr[i];
+
+ out = BKE_sequencer_cache_get(context, seq, cfra, SEQ_STRIPELEM_IBUF_COMP);
+
+ if (out) {
+ break;
+ }
+ if (seq->blend_mode == SEQ_BLEND_REPLACE) {
+ out = seq_render_strip(context, state, seq, cfra);
+ break;
+ }
+
+ early_out = seq_get_early_out_for_blend_mode(seq);
+
+ switch (early_out) {
+ case EARLY_NO_INPUT:
+ case EARLY_USE_INPUT_2:
+ out = seq_render_strip(context, state, seq, cfra);
+ break;
+ case EARLY_USE_INPUT_1:
+ if (i == 0) {
+ out = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect);
+ }
+ break;
+ case EARLY_DO_EFFECT:
+ if (i == 0) {
+ ImBuf *ibuf1 = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect);
+ ImBuf *ibuf2 = seq_render_strip(context, state, seq, cfra);
+
+ out = seq_render_strip_stack_apply_effect(context, seq, cfra, ibuf1, ibuf2);
+
+ IMB_freeImBuf(ibuf1);
+ IMB_freeImBuf(ibuf2);
+ }
+
+ break;
+ }
+ if (out) {
+ break;
+ }
+ }
+
+ BKE_sequencer_cache_put(context, seq_arr[i], cfra, SEQ_STRIPELEM_IBUF_COMP, out);
+
+ i++;
+
+ for (; i < count; i++) {
+ Sequence *seq = seq_arr[i];
+
+ if (seq_get_early_out_for_blend_mode(seq) == EARLY_DO_EFFECT) {
+ ImBuf *ibuf1 = out;
+ ImBuf *ibuf2 = seq_render_strip(context, state, seq, cfra);
+
+ out = seq_render_strip_stack_apply_effect(context, seq, cfra, ibuf1, ibuf2);
+
+ IMB_freeImBuf(ibuf1);
+ IMB_freeImBuf(ibuf2);
+ }
+
+ BKE_sequencer_cache_put(context, seq_arr[i], cfra, SEQ_STRIPELEM_IBUF_COMP, out);
+ }
+
+ return out;
}
/*
@@ -3866,41 +4044,44 @@ static ImBuf *seq_render_strip_stack(
ImBuf *BKE_sequencer_give_ibuf(const SeqRenderData *context, float cfra, int chanshown)
{
- Editing *ed = BKE_sequencer_editing_get(context->scene, false);
- ListBase *seqbasep;
+ Editing *ed = BKE_sequencer_editing_get(context->scene, false);
+ ListBase *seqbasep;
- if (ed == NULL) return NULL;
+ if (ed == NULL)
+ return NULL;
- if ((chanshown < 0) && !BLI_listbase_is_empty(&ed->metastack)) {
- int count = BLI_listbase_count(&ed->metastack);
- count = max_ii(count + chanshown, 0);
- seqbasep = ((MetaStack *)BLI_findlink(&ed->metastack, count))->oldbasep;
- }
- else {
- seqbasep = ed->seqbasep;
- }
+ if ((chanshown < 0) && !BLI_listbase_is_empty(&ed->metastack)) {
+ int count = BLI_listbase_count(&ed->metastack);
+ count = max_ii(count + chanshown, 0);
+ seqbasep = ((MetaStack *)BLI_findlink(&ed->metastack, count))->oldbasep;
+ }
+ else {
+ seqbasep = ed->seqbasep;
+ }
- SeqRenderState state;
- sequencer_state_init(&state);
+ SeqRenderState state;
+ sequencer_state_init(&state);
- return seq_render_strip_stack(context, &state, seqbasep, cfra, chanshown);
+ return seq_render_strip_stack(context, &state, seqbasep, cfra, chanshown);
}
-ImBuf *BKE_sequencer_give_ibuf_seqbase(const SeqRenderData *context, float cfra, int chanshown, ListBase *seqbasep)
+ImBuf *BKE_sequencer_give_ibuf_seqbase(const SeqRenderData *context,
+ float cfra,
+ int chanshown,
+ ListBase *seqbasep)
{
- SeqRenderState state;
- sequencer_state_init(&state);
+ SeqRenderState state;
+ sequencer_state_init(&state);
- return seq_render_strip_stack(context, &state, seqbasep, cfra, chanshown);
+ return seq_render_strip_stack(context, &state, seqbasep, cfra, chanshown);
}
-
ImBuf *BKE_sequencer_give_ibuf_direct(const SeqRenderData *context, float cfra, Sequence *seq)
{
- SeqRenderState state;
- sequencer_state_init(&state);
+ SeqRenderState state;
+ sequencer_state_init(&state);
- return seq_render_strip(context, &state, seq, cfra);
+ return seq_render_strip(context, &state, seq, cfra);
}
/* *********************** threading api ******************* */
@@ -3909,324 +4090,318 @@ static ListBase running_threads;
static ListBase prefetch_wait;
static ListBase prefetch_done;
-static pthread_mutex_t queue_lock = PTHREAD_MUTEX_INITIALIZER;
-static pthread_mutex_t wakeup_lock = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t wakeup_cond = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t queue_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t wakeup_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t wakeup_cond = PTHREAD_COND_INITIALIZER;
//static pthread_mutex_t prefetch_ready_lock = PTHREAD_MUTEX_INITIALIZER;
//static pthread_cond_t prefetch_ready_cond = PTHREAD_COND_INITIALIZER;
-static pthread_mutex_t frame_done_lock = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t frame_done_cond = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t frame_done_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t frame_done_cond = PTHREAD_COND_INITIALIZER;
static volatile bool seq_thread_shutdown = true;
static volatile int seq_last_given_monoton_cfra = 0;
static int monoton_cfra = 0;
typedef struct PrefetchThread {
- struct PrefetchThread *next, *prev;
+ struct PrefetchThread *next, *prev;
- Scene *scene;
- struct PrefetchQueueElem *current;
- pthread_t pthread;
- int running;
+ Scene *scene;
+ struct PrefetchQueueElem *current;
+ pthread_t pthread;
+ int running;
} PrefetchThread;
typedef struct PrefetchQueueElem {
- struct PrefetchQueueElem *next, *prev;
+ struct PrefetchQueueElem *next, *prev;
- int rectx;
- int recty;
- float cfra;
- int chanshown;
- int preview_render_size;
+ int rectx;
+ int recty;
+ float cfra;
+ int chanshown;
+ int preview_render_size;
- int monoton_cfra;
+ int monoton_cfra;
- ImBuf *ibuf;
+ ImBuf *ibuf;
} PrefetchQueueElem;
-void BKE_sequencer_give_ibuf_prefetch_request(const SeqRenderData *context, float cfra, int chanshown)
+void BKE_sequencer_give_ibuf_prefetch_request(const SeqRenderData *context,
+ float cfra,
+ int chanshown)
{
- PrefetchQueueElem *e;
- if (seq_thread_shutdown) {
- return;
- }
+ PrefetchQueueElem *e;
+ if (seq_thread_shutdown) {
+ return;
+ }
- e = MEM_callocN(sizeof(PrefetchQueueElem), "prefetch_queue_elem");
- e->rectx = context->rectx;
- e->recty = context->recty;
- e->cfra = cfra;
- e->chanshown = chanshown;
- e->preview_render_size = context->preview_render_size;
- e->monoton_cfra = monoton_cfra++;
+ e = MEM_callocN(sizeof(PrefetchQueueElem), "prefetch_queue_elem");
+ e->rectx = context->rectx;
+ e->recty = context->recty;
+ e->cfra = cfra;
+ e->chanshown = chanshown;
+ e->preview_render_size = context->preview_render_size;
+ e->monoton_cfra = monoton_cfra++;
- pthread_mutex_lock(&queue_lock);
- BLI_addtail(&prefetch_wait, e);
- pthread_mutex_unlock(&queue_lock);
+ pthread_mutex_lock(&queue_lock);
+ BLI_addtail(&prefetch_wait, e);
+ pthread_mutex_unlock(&queue_lock);
- pthread_mutex_lock(&wakeup_lock);
- pthread_cond_signal(&wakeup_cond);
- pthread_mutex_unlock(&wakeup_lock);
+ pthread_mutex_lock(&wakeup_lock);
+ pthread_cond_signal(&wakeup_cond);
+ pthread_mutex_unlock(&wakeup_lock);
}
ImBuf *BKE_sequencer_give_ibuf_threaded(const SeqRenderData *context, float cfra, int chanshown)
{
- PrefetchQueueElem *e = NULL;
- bool found_something = false;
-
- if (seq_thread_shutdown) {
- return BKE_sequencer_give_ibuf(context, cfra, chanshown);
- }
-
- while (!e) {
- bool success = false;
- pthread_mutex_lock(&queue_lock);
-
- for (e = prefetch_done.first; e; e = e->next) {
- if (cfra == e->cfra &&
- chanshown == e->chanshown &&
- context->rectx == e->rectx &&
- context->recty == e->recty &&
- context->preview_render_size == e->preview_render_size)
- {
- success = true;
- found_something = true;
- break;
- }
- }
-
- if (!e) {
- for (e = prefetch_wait.first; e; e = e->next) {
- if (cfra == e->cfra &&
- chanshown == e->chanshown &&
- context->rectx == e->rectx &&
- context->recty == e->recty &&
- context->preview_render_size == e->preview_render_size)
- {
- found_something = true;
- break;
- }
- }
- }
-
- if (!e) {
- PrefetchThread *tslot;
-
- for (tslot = running_threads.first;
- tslot;
- tslot = tslot->next)
- {
- if (tslot->current &&
- cfra == tslot->current->cfra &&
- chanshown == tslot->current->chanshown &&
- context->rectx == tslot->current->rectx &&
- context->recty == tslot->current->recty &&
- context->preview_render_size == tslot->current->preview_render_size)
- {
- found_something = true;
- break;
- }
- }
- }
-
- /* e->ibuf is unrefed by render thread on next round. */
-
- if (e) {
- seq_last_given_monoton_cfra = e->monoton_cfra;
- }
-
- pthread_mutex_unlock(&queue_lock);
-
- if (!success) {
- e = NULL;
-
- if (!found_something) {
- fprintf(stderr, "SEQ-THREAD: Requested frame not in queue ???\n");
- break;
- }
- pthread_mutex_lock(&frame_done_lock);
- pthread_cond_wait(&frame_done_cond, &frame_done_lock);
- pthread_mutex_unlock(&frame_done_lock);
- }
- }
-
- return e ? e->ibuf : NULL;
+ PrefetchQueueElem *e = NULL;
+ bool found_something = false;
+
+ if (seq_thread_shutdown) {
+ return BKE_sequencer_give_ibuf(context, cfra, chanshown);
+ }
+
+ while (!e) {
+ bool success = false;
+ pthread_mutex_lock(&queue_lock);
+
+ for (e = prefetch_done.first; e; e = e->next) {
+ if (cfra == e->cfra && chanshown == e->chanshown && context->rectx == e->rectx &&
+ context->recty == e->recty && context->preview_render_size == e->preview_render_size) {
+ success = true;
+ found_something = true;
+ break;
+ }
+ }
+
+ if (!e) {
+ for (e = prefetch_wait.first; e; e = e->next) {
+ if (cfra == e->cfra && chanshown == e->chanshown && context->rectx == e->rectx &&
+ context->recty == e->recty && context->preview_render_size == e->preview_render_size) {
+ found_something = true;
+ break;
+ }
+ }
+ }
+
+ if (!e) {
+ PrefetchThread *tslot;
+
+ for (tslot = running_threads.first; tslot; tslot = tslot->next) {
+ if (tslot->current && cfra == tslot->current->cfra &&
+ chanshown == tslot->current->chanshown && context->rectx == tslot->current->rectx &&
+ context->recty == tslot->current->recty &&
+ context->preview_render_size == tslot->current->preview_render_size) {
+ found_something = true;
+ break;
+ }
+ }
+ }
+
+ /* e->ibuf is unrefed by render thread on next round. */
+
+ if (e) {
+ seq_last_given_monoton_cfra = e->monoton_cfra;
+ }
+
+ pthread_mutex_unlock(&queue_lock);
+
+ if (!success) {
+ e = NULL;
+
+ if (!found_something) {
+ fprintf(stderr, "SEQ-THREAD: Requested frame not in queue ???\n");
+ break;
+ }
+ pthread_mutex_lock(&frame_done_lock);
+ pthread_cond_wait(&frame_done_cond, &frame_done_lock);
+ pthread_mutex_unlock(&frame_done_lock);
+ }
+ }
+
+ return e ? e->ibuf : NULL;
}
/* check whether sequence cur depends on seq */
bool BKE_sequence_check_depend(Sequence *seq, Sequence *cur)
{
- if (cur->seq1 == seq || cur->seq2 == seq || cur->seq3 == seq)
- return true;
+ if (cur->seq1 == seq || cur->seq2 == seq || cur->seq3 == seq)
+ return true;
- /* sequences are not intersecting in time, assume no dependency exists between them */
- if (cur->enddisp < seq->startdisp || cur->startdisp > seq->enddisp)
- return false;
+ /* sequences are not intersecting in time, assume no dependency exists between them */
+ if (cur->enddisp < seq->startdisp || cur->startdisp > seq->enddisp)
+ return false;
- /* checking sequence is below reference one, not dependent on it */
- if (cur->machine < seq->machine)
- return false;
+ /* checking sequence is below reference one, not dependent on it */
+ if (cur->machine < seq->machine)
+ return false;
- /* sequence is not blending with lower machines, no dependency here occurs
- * check for non-effects only since effect could use lower machines as input
- */
- if ((cur->type & SEQ_TYPE_EFFECT) == 0 &&
- ((cur->blend_mode == SEQ_BLEND_REPLACE) ||
- (cur->blend_mode == SEQ_TYPE_CROSS && cur->blend_opacity == 100.0f)))
- {
- return false;
- }
+ /* sequence is not blending with lower machines, no dependency here occurs
+ * check for non-effects only since effect could use lower machines as input
+ */
+ if ((cur->type & SEQ_TYPE_EFFECT) == 0 &&
+ ((cur->blend_mode == SEQ_BLEND_REPLACE) ||
+ (cur->blend_mode == SEQ_TYPE_CROSS && cur->blend_opacity == 100.0f))) {
+ return false;
+ }
- return true;
+ return true;
}
static void sequence_do_invalidate_dependent(Sequence *seq, ListBase *seqbase)
{
- Sequence *cur;
+ Sequence *cur;
- for (cur = seqbase->first; cur; cur = cur->next) {
- if (cur == seq)
- continue;
+ for (cur = seqbase->first; cur; cur = cur->next) {
+ if (cur == seq)
+ continue;
- if (BKE_sequence_check_depend(seq, cur)) {
- BKE_sequencer_cache_cleanup_sequence(cur);
- BKE_sequencer_preprocessed_cache_cleanup_sequence(cur);
- }
+ if (BKE_sequence_check_depend(seq, cur)) {
+ BKE_sequencer_cache_cleanup_sequence(cur);
+ BKE_sequencer_preprocessed_cache_cleanup_sequence(cur);
+ }
- if (cur->seqbase.first)
- sequence_do_invalidate_dependent(seq, &cur->seqbase);
- }
+ if (cur->seqbase.first)
+ sequence_do_invalidate_dependent(seq, &cur->seqbase);
+ }
}
-static void sequence_invalidate_cache(Scene *scene, Sequence *seq, bool invalidate_self, bool invalidate_preprocess)
+static void sequence_invalidate_cache(Scene *scene,
+ Sequence *seq,
+ bool invalidate_self,
+ bool invalidate_preprocess)
{
- Editing *ed = scene->ed;
+ Editing *ed = scene->ed;
- /* invalidate cache for current sequence */
- if (invalidate_self) {
- /* Animation structure holds some buffers inside,
- * so for proper cache invalidation we need to
- * re-open the animation.
- */
- BKE_sequence_free_anim(seq);
- BKE_sequencer_cache_cleanup_sequence(seq);
- }
+ /* invalidate cache for current sequence */
+ if (invalidate_self) {
+ /* Animation structure holds some buffers inside,
+ * so for proper cache invalidation we need to
+ * re-open the animation.
+ */
+ BKE_sequence_free_anim(seq);
+ BKE_sequencer_cache_cleanup_sequence(seq);
+ }
- /* if invalidation is invoked from sequence free routine, effectdata would be NULL here */
- if (seq->effectdata && seq->type == SEQ_TYPE_SPEED)
- BKE_sequence_effect_speed_rebuild_map(scene, seq, true);
+ /* if invalidation is invoked from sequence free routine, effectdata would be NULL here */
+ if (seq->effectdata && seq->type == SEQ_TYPE_SPEED)
+ BKE_sequence_effect_speed_rebuild_map(scene, seq, true);
- if (invalidate_preprocess)
- BKE_sequencer_preprocessed_cache_cleanup_sequence(seq);
+ if (invalidate_preprocess)
+ BKE_sequencer_preprocessed_cache_cleanup_sequence(seq);
- /* invalidate cache for all dependent sequences */
+ /* invalidate cache for all dependent sequences */
- /* NOTE: can not use SEQ_BEGIN/SEQ_END here because that macro will change sequence's depth,
- * which makes transformation routines work incorrect
- */
- sequence_do_invalidate_dependent(seq, &ed->seqbase);
+ /* NOTE: can not use SEQ_BEGIN/SEQ_END here because that macro will change sequence's depth,
+ * which makes transformation routines work incorrect
+ */
+ sequence_do_invalidate_dependent(seq, &ed->seqbase);
}
void BKE_sequence_invalidate_cache(Scene *scene, Sequence *seq)
{
- sequence_invalidate_cache(scene, seq, true, true);
+ sequence_invalidate_cache(scene, seq, true, true);
}
void BKE_sequence_invalidate_dependent(Scene *scene, Sequence *seq)
{
- sequence_invalidate_cache(scene, seq, false, true);
+ sequence_invalidate_cache(scene, seq, false, true);
}
void BKE_sequence_invalidate_cache_for_modifier(Scene *scene, Sequence *seq)
{
- sequence_invalidate_cache(scene, seq, true, false);
+ sequence_invalidate_cache(scene, seq, true, false);
}
void BKE_sequencer_free_imbuf(Scene *scene, ListBase *seqbase, bool for_render)
{
- Sequence *seq;
-
- BKE_sequencer_cache_cleanup();
+ Sequence *seq;
- for (seq = seqbase->first; seq; seq = seq->next) {
- if (for_render && CFRA >= seq->startdisp && CFRA <= seq->enddisp) {
- continue;
- }
+ BKE_sequencer_cache_cleanup();
- if (seq->strip) {
- if (seq->type == SEQ_TYPE_MOVIE) {
- BKE_sequence_free_anim(seq);
- }
- if (seq->type == SEQ_TYPE_SPEED) {
- BKE_sequence_effect_speed_rebuild_map(scene, seq, true);
- }
- }
- if (seq->type == SEQ_TYPE_META) {
- BKE_sequencer_free_imbuf(scene, &seq->seqbase, for_render);
- }
- if (seq->type == SEQ_TYPE_SCENE) {
- /* FIXME: recurs downwards,
- * but do recurs protection somehow! */
- }
- }
+ for (seq = seqbase->first; seq; seq = seq->next) {
+ if (for_render && CFRA >= seq->startdisp && CFRA <= seq->enddisp) {
+ continue;
+ }
+ if (seq->strip) {
+ if (seq->type == SEQ_TYPE_MOVIE) {
+ BKE_sequence_free_anim(seq);
+ }
+ if (seq->type == SEQ_TYPE_SPEED) {
+ BKE_sequence_effect_speed_rebuild_map(scene, seq, true);
+ }
+ }
+ if (seq->type == SEQ_TYPE_META) {
+ BKE_sequencer_free_imbuf(scene, &seq->seqbase, for_render);
+ }
+ if (seq->type == SEQ_TYPE_SCENE) {
+ /* FIXME: recurs downwards,
+ * but do recurs protection somehow! */
+ }
+ }
}
-static bool update_changed_seq_recurs(Scene *scene, Sequence *seq, Sequence *changed_seq, int len_change, int ibuf_change)
+static bool update_changed_seq_recurs(
+ Scene *scene, Sequence *seq, Sequence *changed_seq, int len_change, int ibuf_change)
{
- Sequence *subseq;
- bool free_imbuf = false;
+ Sequence *subseq;
+ bool free_imbuf = false;
- /* recurs downwards to see if this seq depends on the changed seq */
+ /* recurs downwards to see if this seq depends on the changed seq */
- if (seq == NULL)
- return false;
+ if (seq == NULL)
+ return false;
- if (seq == changed_seq)
- free_imbuf = true;
+ if (seq == changed_seq)
+ free_imbuf = true;
- for (subseq = seq->seqbase.first; subseq; subseq = subseq->next)
- if (update_changed_seq_recurs(scene, subseq, changed_seq, len_change, ibuf_change))
- free_imbuf = true;
+ for (subseq = seq->seqbase.first; subseq; subseq = subseq->next)
+ if (update_changed_seq_recurs(scene, subseq, changed_seq, len_change, ibuf_change))
+ free_imbuf = true;
- if (seq->seq1)
- if (update_changed_seq_recurs(scene, seq->seq1, changed_seq, len_change, ibuf_change))
- free_imbuf = true;
- if (seq->seq2 && (seq->seq2 != seq->seq1))
- if (update_changed_seq_recurs(scene, seq->seq2, changed_seq, len_change, ibuf_change))
- free_imbuf = true;
- if (seq->seq3 && (seq->seq3 != seq->seq1) && (seq->seq3 != seq->seq2))
- if (update_changed_seq_recurs(scene, seq->seq3, changed_seq, len_change, ibuf_change))
- free_imbuf = true;
+ if (seq->seq1)
+ if (update_changed_seq_recurs(scene, seq->seq1, changed_seq, len_change, ibuf_change))
+ free_imbuf = true;
+ if (seq->seq2 && (seq->seq2 != seq->seq1))
+ if (update_changed_seq_recurs(scene, seq->seq2, changed_seq, len_change, ibuf_change))
+ free_imbuf = true;
+ if (seq->seq3 && (seq->seq3 != seq->seq1) && (seq->seq3 != seq->seq2))
+ if (update_changed_seq_recurs(scene, seq->seq3, changed_seq, len_change, ibuf_change))
+ free_imbuf = true;
- if (free_imbuf) {
- if (ibuf_change) {
- if (seq->type == SEQ_TYPE_MOVIE) {
- BKE_sequence_free_anim(seq);
- }
- else if (seq->type == SEQ_TYPE_SPEED) {
- BKE_sequence_effect_speed_rebuild_map(scene, seq, true);
- }
- }
+ if (free_imbuf) {
+ if (ibuf_change) {
+ if (seq->type == SEQ_TYPE_MOVIE) {
+ BKE_sequence_free_anim(seq);
+ }
+ else if (seq->type == SEQ_TYPE_SPEED) {
+ BKE_sequence_effect_speed_rebuild_map(scene, seq, true);
+ }
+ }
- if (len_change)
- BKE_sequence_calc(scene, seq);
- }
+ if (len_change)
+ BKE_sequence_calc(scene, seq);
+ }
- return free_imbuf;
+ return free_imbuf;
}
-void BKE_sequencer_update_changed_seq_and_deps(Scene *scene, Sequence *changed_seq, int len_change, int ibuf_change)
+void BKE_sequencer_update_changed_seq_and_deps(Scene *scene,
+ Sequence *changed_seq,
+ int len_change,
+ int ibuf_change)
{
- Editing *ed = BKE_sequencer_editing_get(scene, false);
- Sequence *seq;
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ Sequence *seq;
- if (ed == NULL) return;
+ if (ed == NULL)
+ return;
- for (seq = ed->seqbase.first; seq; seq = seq->next)
- update_changed_seq_recurs(scene, seq, changed_seq, len_change, ibuf_change);
+ for (seq = ed->seqbase.first; seq; seq = seq->next)
+ update_changed_seq_recurs(scene, seq, changed_seq, len_change, ibuf_change);
}
/* seq funcs's for transforming internally
@@ -4237,178 +4412,177 @@ void BKE_sequencer_update_changed_seq_and_deps(Scene *scene, Sequence *changed_s
*/
static int seq_tx_get_start(Sequence *seq)
{
- return seq->start;
+ return seq->start;
}
static int seq_tx_get_end(Sequence *seq)
{
- return seq->start + seq->len;
+ return seq->start + seq->len;
}
int BKE_sequence_tx_get_final_left(Sequence *seq, bool metaclip)
{
- if (metaclip && seq->tmp) {
- /* return the range clipped by the parents range */
- return max_ii(BKE_sequence_tx_get_final_left(seq, false), BKE_sequence_tx_get_final_left((Sequence *)seq->tmp, true));
- }
- else {
- return (seq->start - seq->startstill) + seq->startofs;
- }
-
+ if (metaclip && seq->tmp) {
+ /* return the range clipped by the parents range */
+ return max_ii(BKE_sequence_tx_get_final_left(seq, false),
+ BKE_sequence_tx_get_final_left((Sequence *)seq->tmp, true));
+ }
+ else {
+ return (seq->start - seq->startstill) + seq->startofs;
+ }
}
int BKE_sequence_tx_get_final_right(Sequence *seq, bool metaclip)
{
- if (metaclip && seq->tmp) {
- /* return the range clipped by the parents range */
- return min_ii(BKE_sequence_tx_get_final_right(seq, false), BKE_sequence_tx_get_final_right((Sequence *)seq->tmp, true));
- }
- else {
- return ((seq->start + seq->len) + seq->endstill) - seq->endofs;
- }
+ if (metaclip && seq->tmp) {
+ /* return the range clipped by the parents range */
+ return min_ii(BKE_sequence_tx_get_final_right(seq, false),
+ BKE_sequence_tx_get_final_right((Sequence *)seq->tmp, true));
+ }
+ else {
+ return ((seq->start + seq->len) + seq->endstill) - seq->endofs;
+ }
}
void BKE_sequence_tx_set_final_left(Sequence *seq, int val)
{
- if (val < (seq)->start) {
- seq->startstill = abs(val - (seq)->start);
- seq->startofs = 0;
- }
- else {
- seq->startofs = abs(val - (seq)->start);
- seq->startstill = 0;
- }
+ if (val < (seq)->start) {
+ seq->startstill = abs(val - (seq)->start);
+ seq->startofs = 0;
+ }
+ else {
+ seq->startofs = abs(val - (seq)->start);
+ seq->startstill = 0;
+ }
}
void BKE_sequence_tx_set_final_right(Sequence *seq, int val)
{
- if (val > (seq)->start + (seq)->len) {
- seq->endstill = abs(val - (seq->start + (seq)->len));
- seq->endofs = 0;
- }
- else {
- seq->endofs = abs(val - ((seq)->start + (seq)->len));
- seq->endstill = 0;
- }
+ if (val > (seq)->start + (seq)->len) {
+ seq->endstill = abs(val - (seq->start + (seq)->len));
+ seq->endofs = 0;
+ }
+ else {
+ seq->endofs = abs(val - ((seq)->start + (seq)->len));
+ seq->endstill = 0;
+ }
}
/* used so we can do a quick check for single image seq
* since they work a bit differently to normal image seq's (during transform) */
bool BKE_sequence_single_check(Sequence *seq)
{
- return ((seq->len == 1) &&
- (seq->type == SEQ_TYPE_IMAGE ||
- ((seq->type & SEQ_TYPE_EFFECT) &&
- BKE_sequence_effect_get_num_inputs(seq->type) == 0)));
+ return ((seq->len == 1) &&
+ (seq->type == SEQ_TYPE_IMAGE ||
+ ((seq->type & SEQ_TYPE_EFFECT) && BKE_sequence_effect_get_num_inputs(seq->type) == 0)));
}
/* check if the selected seq's reference unselected seq's */
bool BKE_sequence_base_isolated_sel_check(ListBase *seqbase)
{
- Sequence *seq;
- /* is there more than 1 select */
- bool ok = false;
-
- for (seq = seqbase->first; seq; seq = seq->next) {
- if (seq->flag & SELECT) {
- ok = true;
- break;
- }
- }
-
- if (ok == false)
- return false;
-
- /* test relationships */
- for (seq = seqbase->first; seq; seq = seq->next) {
- if ((seq->type & SEQ_TYPE_EFFECT) == 0)
- continue;
-
- if (seq->flag & SELECT) {
- if ((seq->seq1 && (seq->seq1->flag & SELECT) == 0) ||
- (seq->seq2 && (seq->seq2->flag & SELECT) == 0) ||
- (seq->seq3 && (seq->seq3->flag & SELECT) == 0) )
- {
- return false;
- }
- }
- else {
- if ((seq->seq1 && (seq->seq1->flag & SELECT)) ||
- (seq->seq2 && (seq->seq2->flag & SELECT)) ||
- (seq->seq3 && (seq->seq3->flag & SELECT)) )
- {
- return false;
- }
- }
- }
-
- return true;
+ Sequence *seq;
+ /* is there more than 1 select */
+ bool ok = false;
+
+ for (seq = seqbase->first; seq; seq = seq->next) {
+ if (seq->flag & SELECT) {
+ ok = true;
+ break;
+ }
+ }
+
+ if (ok == false)
+ return false;
+
+ /* test relationships */
+ for (seq = seqbase->first; seq; seq = seq->next) {
+ if ((seq->type & SEQ_TYPE_EFFECT) == 0)
+ continue;
+
+ if (seq->flag & SELECT) {
+ if ((seq->seq1 && (seq->seq1->flag & SELECT) == 0) ||
+ (seq->seq2 && (seq->seq2->flag & SELECT) == 0) ||
+ (seq->seq3 && (seq->seq3->flag & SELECT) == 0)) {
+ return false;
+ }
+ }
+ else {
+ if ((seq->seq1 && (seq->seq1->flag & SELECT)) || (seq->seq2 && (seq->seq2->flag & SELECT)) ||
+ (seq->seq3 && (seq->seq3->flag & SELECT))) {
+ return false;
+ }
+ }
+ }
+
+ return true;
}
/* use to impose limits when dragging/extending - so impossible situations don't happen
* Cant use the SEQ_LEFTSEL and SEQ_LEFTSEL directly because the strip may be in a metastrip */
void BKE_sequence_tx_handle_xlimits(Sequence *seq, int leftflag, int rightflag)
{
- if (leftflag) {
- if (BKE_sequence_tx_get_final_left(seq, false) >= BKE_sequence_tx_get_final_right(seq, false)) {
- BKE_sequence_tx_set_final_left(seq, BKE_sequence_tx_get_final_right(seq, false) - 1);
- }
+ if (leftflag) {
+ if (BKE_sequence_tx_get_final_left(seq, false) >=
+ BKE_sequence_tx_get_final_right(seq, false)) {
+ BKE_sequence_tx_set_final_left(seq, BKE_sequence_tx_get_final_right(seq, false) - 1);
+ }
- if (BKE_sequence_single_check(seq) == 0) {
- if (BKE_sequence_tx_get_final_left(seq, false) >= seq_tx_get_end(seq)) {
- BKE_sequence_tx_set_final_left(seq, seq_tx_get_end(seq) - 1);
- }
+ if (BKE_sequence_single_check(seq) == 0) {
+ if (BKE_sequence_tx_get_final_left(seq, false) >= seq_tx_get_end(seq)) {
+ BKE_sequence_tx_set_final_left(seq, seq_tx_get_end(seq) - 1);
+ }
- /* dosnt work now - TODO */
+ /* dosnt work now - TODO */
#if 0
- if (seq_tx_get_start(seq) >= seq_tx_get_final_right(seq, 0)) {
- int ofs;
- ofs = seq_tx_get_start(seq) - seq_tx_get_final_right(seq, 0);
- seq->start -= ofs;
- seq_tx_set_final_left(seq, seq_tx_get_final_left(seq, 0) + ofs);
- }
+ if (seq_tx_get_start(seq) >= seq_tx_get_final_right(seq, 0)) {
+ int ofs;
+ ofs = seq_tx_get_start(seq) - seq_tx_get_final_right(seq, 0);
+ seq->start -= ofs;
+ seq_tx_set_final_left(seq, seq_tx_get_final_left(seq, 0) + ofs);
+ }
#endif
- }
- }
+ }
+ }
- if (rightflag) {
- if (BKE_sequence_tx_get_final_right(seq, false) <= BKE_sequence_tx_get_final_left(seq, false)) {
- BKE_sequence_tx_set_final_right(seq, BKE_sequence_tx_get_final_left(seq, false) + 1);
- }
+ if (rightflag) {
+ if (BKE_sequence_tx_get_final_right(seq, false) <=
+ BKE_sequence_tx_get_final_left(seq, false)) {
+ BKE_sequence_tx_set_final_right(seq, BKE_sequence_tx_get_final_left(seq, false) + 1);
+ }
- if (BKE_sequence_single_check(seq) == 0) {
- if (BKE_sequence_tx_get_final_right(seq, false) <= seq_tx_get_start(seq)) {
- BKE_sequence_tx_set_final_right(seq, seq_tx_get_start(seq) + 1);
- }
- }
- }
+ if (BKE_sequence_single_check(seq) == 0) {
+ if (BKE_sequence_tx_get_final_right(seq, false) <= seq_tx_get_start(seq)) {
+ BKE_sequence_tx_set_final_right(seq, seq_tx_get_start(seq) + 1);
+ }
+ }
+ }
- /* sounds cannot be extended past their endpoints */
- if (seq->type == SEQ_TYPE_SOUND_RAM) {
- seq->startstill = 0;
- seq->endstill = 0;
- }
+ /* sounds cannot be extended past their endpoints */
+ if (seq->type == SEQ_TYPE_SOUND_RAM) {
+ seq->startstill = 0;
+ seq->endstill = 0;
+ }
}
void BKE_sequence_single_fix(Sequence *seq)
{
- int left, start, offset;
- if (!BKE_sequence_single_check(seq))
- return;
+ int left, start, offset;
+ if (!BKE_sequence_single_check(seq))
+ return;
- /* make sure the image is always at the start since there is only one,
- * adjusting its start should be ok */
- left = BKE_sequence_tx_get_final_left(seq, false);
- start = seq->start;
- if (start != left) {
- offset = left - start;
- BKE_sequence_tx_set_final_left(seq, BKE_sequence_tx_get_final_left(seq, false) - offset);
- BKE_sequence_tx_set_final_right(seq, BKE_sequence_tx_get_final_right(seq, false) - offset);
- seq->start += offset;
- }
+ /* make sure the image is always at the start since there is only one,
+ * adjusting its start should be ok */
+ left = BKE_sequence_tx_get_final_left(seq, false);
+ start = seq->start;
+ if (start != left) {
+ offset = left - start;
+ BKE_sequence_tx_set_final_left(seq, BKE_sequence_tx_get_final_left(seq, false) - offset);
+ BKE_sequence_tx_set_final_right(seq, BKE_sequence_tx_get_final_right(seq, false) - offset);
+ seq->start += offset;
+ }
}
bool BKE_sequence_tx_test(Sequence *seq)
{
- return !(seq->type & SEQ_TYPE_EFFECT) || (BKE_sequence_effect_get_num_inputs(seq->type) == 0);
+ return !(seq->type & SEQ_TYPE_EFFECT) || (BKE_sequence_effect_get_num_inputs(seq->type) == 0);
}
/**
@@ -4419,436 +4593,443 @@ bool BKE_sequence_tx_test(Sequence *seq)
*/
bool BKE_sequence_tx_fullupdate_test(Sequence *seq)
{
- return BKE_sequence_tx_test(seq) && ELEM(seq->type, SEQ_TYPE_ADJUSTMENT, SEQ_TYPE_MULTICAM);
+ return BKE_sequence_tx_test(seq) && ELEM(seq->type, SEQ_TYPE_ADJUSTMENT, SEQ_TYPE_MULTICAM);
}
static bool seq_overlap(Sequence *seq1, Sequence *seq2)
{
- return (seq1 != seq2 && seq1->machine == seq2->machine &&
- ((seq1->enddisp <= seq2->startdisp) || (seq1->startdisp >= seq2->enddisp)) == 0);
+ return (seq1 != seq2 && seq1->machine == seq2->machine &&
+ ((seq1->enddisp <= seq2->startdisp) || (seq1->startdisp >= seq2->enddisp)) == 0);
}
bool BKE_sequence_test_overlap(ListBase *seqbasep, Sequence *test)
{
- Sequence *seq;
+ Sequence *seq;
- seq = seqbasep->first;
- while (seq) {
- if (seq_overlap(test, seq))
- return true;
+ seq = seqbasep->first;
+ while (seq) {
+ if (seq_overlap(test, seq))
+ return true;
- seq = seq->next;
- }
- return false;
+ seq = seq->next;
+ }
+ return false;
}
-
void BKE_sequence_translate(Scene *evil_scene, Sequence *seq, int delta)
{
- BKE_sequencer_offset_animdata(evil_scene, seq, delta);
- seq->start += delta;
+ BKE_sequencer_offset_animdata(evil_scene, seq, delta);
+ seq->start += delta;
- if (seq->type == SEQ_TYPE_META) {
- Sequence *seq_child;
- for (seq_child = seq->seqbase.first; seq_child; seq_child = seq_child->next) {
- BKE_sequence_translate(evil_scene, seq_child, delta);
- }
- }
+ if (seq->type == SEQ_TYPE_META) {
+ Sequence *seq_child;
+ for (seq_child = seq->seqbase.first; seq_child; seq_child = seq_child->next) {
+ BKE_sequence_translate(evil_scene, seq_child, delta);
+ }
+ }
- BKE_sequence_calc_disp(evil_scene, seq);
+ BKE_sequence_calc_disp(evil_scene, seq);
}
void BKE_sequence_sound_init(Scene *scene, Sequence *seq)
{
- if (seq->type == SEQ_TYPE_META) {
- Sequence *seq_child;
- for (seq_child = seq->seqbase.first; seq_child; seq_child = seq_child->next) {
- BKE_sequence_sound_init(scene, seq_child);
- }
- }
- else {
- if (seq->sound) {
- seq->scene_sound = BKE_sound_add_scene_sound_defaults(scene, seq);
- }
- if (seq->scene) {
- seq->scene_sound = BKE_sound_scene_add_scene_sound_defaults(scene, seq);
- }
- }
+ if (seq->type == SEQ_TYPE_META) {
+ Sequence *seq_child;
+ for (seq_child = seq->seqbase.first; seq_child; seq_child = seq_child->next) {
+ BKE_sequence_sound_init(scene, seq_child);
+ }
+ }
+ else {
+ if (seq->sound) {
+ seq->scene_sound = BKE_sound_add_scene_sound_defaults(scene, seq);
+ }
+ if (seq->scene) {
+ seq->scene_sound = BKE_sound_scene_add_scene_sound_defaults(scene, seq);
+ }
+ }
}
Sequence *BKE_sequencer_foreground_frame_get(Scene *scene, int frame)
{
- Editing *ed = BKE_sequencer_editing_get(scene, false);
- Sequence *seq, *best_seq = NULL;
- int best_machine = -1;
-
- if (!ed) return NULL;
-
- for (seq = ed->seqbasep->first; seq; seq = seq->next) {
- if (seq->flag & SEQ_MUTE || seq->startdisp > frame || seq->enddisp <= frame)
- continue;
- /* Only use strips that generate an image, not ones that combine
- * other strips or apply some effect. */
- if (ELEM(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_META, SEQ_TYPE_SCENE,
- SEQ_TYPE_MOVIE, SEQ_TYPE_COLOR, SEQ_TYPE_TEXT))
- {
- if (seq->machine > best_machine) {
- best_seq = seq;
- best_machine = seq->machine;
- }
- }
- }
- return best_seq;
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ Sequence *seq, *best_seq = NULL;
+ int best_machine = -1;
+
+ if (!ed)
+ return NULL;
+
+ for (seq = ed->seqbasep->first; seq; seq = seq->next) {
+ if (seq->flag & SEQ_MUTE || seq->startdisp > frame || seq->enddisp <= frame)
+ continue;
+ /* Only use strips that generate an image, not ones that combine
+ * other strips or apply some effect. */
+ if (ELEM(seq->type,
+ SEQ_TYPE_IMAGE,
+ SEQ_TYPE_META,
+ SEQ_TYPE_SCENE,
+ SEQ_TYPE_MOVIE,
+ SEQ_TYPE_COLOR,
+ SEQ_TYPE_TEXT)) {
+ if (seq->machine > best_machine) {
+ best_seq = seq;
+ best_machine = seq->machine;
+ }
+ }
+ }
+ return best_seq;
}
/* return 0 if there weren't enough space */
-bool BKE_sequence_base_shuffle_ex(ListBase *seqbasep, Sequence *test, Scene *evil_scene, int channel_delta)
-{
- const int orig_machine = test->machine;
- BLI_assert(ELEM(channel_delta, -1, 1));
-
- test->machine += channel_delta;
- BKE_sequence_calc(evil_scene, test);
- while (BKE_sequence_test_overlap(seqbasep, test)) {
- if ((channel_delta > 0) ? (test->machine >= MAXSEQ) : (test->machine < 1)) {
- break;
- }
-
- test->machine += channel_delta;
- BKE_sequence_calc(evil_scene, test); // XXX - I don't think this is needed since were only moving vertically, Campbell.
- }
-
- if ((test->machine < 1) || (test->machine > MAXSEQ)) {
- /* Blender 2.4x would remove the strip.
- * nicer to move it to the end */
-
- Sequence *seq;
- int new_frame = test->enddisp;
-
- for (seq = seqbasep->first; seq; seq = seq->next) {
- if (seq->machine == orig_machine)
- new_frame = max_ii(new_frame, seq->enddisp);
- }
-
- test->machine = orig_machine;
- new_frame = new_frame + (test->start - test->startdisp); /* adjust by the startdisp */
- BKE_sequence_translate(evil_scene, test, new_frame - test->start);
-
- BKE_sequence_calc(evil_scene, test);
- return false;
- }
- else {
- return true;
- }
+bool BKE_sequence_base_shuffle_ex(ListBase *seqbasep,
+ Sequence *test,
+ Scene *evil_scene,
+ int channel_delta)
+{
+ const int orig_machine = test->machine;
+ BLI_assert(ELEM(channel_delta, -1, 1));
+
+ test->machine += channel_delta;
+ BKE_sequence_calc(evil_scene, test);
+ while (BKE_sequence_test_overlap(seqbasep, test)) {
+ if ((channel_delta > 0) ? (test->machine >= MAXSEQ) : (test->machine < 1)) {
+ break;
+ }
+
+ test->machine += channel_delta;
+ BKE_sequence_calc(
+ evil_scene,
+ test); // XXX - I don't think this is needed since were only moving vertically, Campbell.
+ }
+
+ if ((test->machine < 1) || (test->machine > MAXSEQ)) {
+ /* Blender 2.4x would remove the strip.
+ * nicer to move it to the end */
+
+ Sequence *seq;
+ int new_frame = test->enddisp;
+
+ for (seq = seqbasep->first; seq; seq = seq->next) {
+ if (seq->machine == orig_machine)
+ new_frame = max_ii(new_frame, seq->enddisp);
+ }
+
+ test->machine = orig_machine;
+ new_frame = new_frame + (test->start - test->startdisp); /* adjust by the startdisp */
+ BKE_sequence_translate(evil_scene, test, new_frame - test->start);
+
+ BKE_sequence_calc(evil_scene, test);
+ return false;
+ }
+ else {
+ return true;
+ }
}
bool BKE_sequence_base_shuffle(ListBase *seqbasep, Sequence *test, Scene *evil_scene)
{
- return BKE_sequence_base_shuffle_ex(seqbasep, test, evil_scene, 1);
+ return BKE_sequence_base_shuffle_ex(seqbasep, test, evil_scene, 1);
}
static int shuffle_seq_time_offset_test(ListBase *seqbasep, char dir)
{
- int offset = 0;
- Sequence *seq, *seq_other;
-
- for (seq = seqbasep->first; seq; seq = seq->next) {
- if (seq->tmp) {
- for (seq_other = seqbasep->first; seq_other; seq_other = seq_other->next) {
- if (!seq_other->tmp && seq_overlap(seq, seq_other)) {
- if (dir == 'L') {
- offset = min_ii(offset, seq_other->startdisp - seq->enddisp);
- }
- else {
- offset = max_ii(offset, seq_other->enddisp - seq->startdisp);
- }
- }
- }
- }
- }
- return offset;
+ int offset = 0;
+ Sequence *seq, *seq_other;
+
+ for (seq = seqbasep->first; seq; seq = seq->next) {
+ if (seq->tmp) {
+ for (seq_other = seqbasep->first; seq_other; seq_other = seq_other->next) {
+ if (!seq_other->tmp && seq_overlap(seq, seq_other)) {
+ if (dir == 'L') {
+ offset = min_ii(offset, seq_other->startdisp - seq->enddisp);
+ }
+ else {
+ offset = max_ii(offset, seq_other->enddisp - seq->startdisp);
+ }
+ }
+ }
+ }
+ }
+ return offset;
}
static int shuffle_seq_time_offset(Scene *scene, ListBase *seqbasep, char dir)
{
- int ofs = 0;
- int tot_ofs = 0;
- Sequence *seq;
- while ( (ofs = shuffle_seq_time_offset_test(seqbasep, dir)) ) {
- for (seq = seqbasep->first; seq; seq = seq->next) {
- if (seq->tmp) {
- /* seq_test_overlap only tests display values */
- seq->startdisp += ofs;
- seq->enddisp += ofs;
- }
- }
+ int ofs = 0;
+ int tot_ofs = 0;
+ Sequence *seq;
+ while ((ofs = shuffle_seq_time_offset_test(seqbasep, dir))) {
+ for (seq = seqbasep->first; seq; seq = seq->next) {
+ if (seq->tmp) {
+ /* seq_test_overlap only tests display values */
+ seq->startdisp += ofs;
+ seq->enddisp += ofs;
+ }
+ }
- tot_ofs += ofs;
- }
+ tot_ofs += ofs;
+ }
- for (seq = seqbasep->first; seq; seq = seq->next) {
- if (seq->tmp)
- BKE_sequence_calc_disp(scene, seq); /* corrects dummy startdisp/enddisp values */
- }
+ for (seq = seqbasep->first; seq; seq = seq->next) {
+ if (seq->tmp)
+ BKE_sequence_calc_disp(scene, seq); /* corrects dummy startdisp/enddisp values */
+ }
- return tot_ofs;
+ return tot_ofs;
}
bool BKE_sequence_base_shuffle_time(ListBase *seqbasep, Scene *evil_scene)
{
- /* note: seq->tmp is used to tag strips to move */
+ /* note: seq->tmp is used to tag strips to move */
- Sequence *seq;
+ Sequence *seq;
- int offset_l = shuffle_seq_time_offset(evil_scene, seqbasep, 'L');
- int offset_r = shuffle_seq_time_offset(evil_scene, seqbasep, 'R');
- int offset = (-offset_l < offset_r) ? offset_l : offset_r;
+ int offset_l = shuffle_seq_time_offset(evil_scene, seqbasep, 'L');
+ int offset_r = shuffle_seq_time_offset(evil_scene, seqbasep, 'R');
+ int offset = (-offset_l < offset_r) ? offset_l : offset_r;
- if (offset) {
- for (seq = seqbasep->first; seq; seq = seq->next) {
- if (seq->tmp) {
- BKE_sequence_translate(evil_scene, seq, offset);
- seq->flag &= ~SEQ_OVERLAP;
- }
- }
- }
+ if (offset) {
+ for (seq = seqbasep->first; seq; seq = seq->next) {
+ if (seq->tmp) {
+ BKE_sequence_translate(evil_scene, seq, offset);
+ seq->flag &= ~SEQ_OVERLAP;
+ }
+ }
+ }
- return offset ? false : true;
+ return offset ? false : true;
}
/* Unlike _update_sound_ funcs, these ones take info from audaspace to update sequence length! */
#ifdef WITH_AUDASPACE
static bool sequencer_refresh_sound_length_recursive(Scene *scene, ListBase *seqbase)
{
- Sequence *seq;
- bool changed = false;
-
- for (seq = seqbase->first; seq; seq = seq->next) {
- if (seq->type == SEQ_TYPE_META) {
- if (sequencer_refresh_sound_length_recursive(scene, &seq->seqbase)) {
- BKE_sequence_calc(scene, seq);
- changed = true;
- }
- }
- else if (seq->type == SEQ_TYPE_SOUND_RAM) {
- AUD_SoundInfo info = AUD_getInfo(seq->sound->playback_handle);
- int old = seq->len;
- float fac;
-
- seq->len = (int)ceil((double)info.length * FPS);
- fac = (float)seq->len / (float)old;
- old = seq->startofs;
- seq->startofs *= fac;
- seq->endofs *= fac;
- seq->start += (old - seq->startofs); /* So that visual/"real" start frame does not change! */
-
- BKE_sequence_calc(scene, seq);
- changed = true;
- }
- }
- return changed;
+ Sequence *seq;
+ bool changed = false;
+
+ for (seq = seqbase->first; seq; seq = seq->next) {
+ if (seq->type == SEQ_TYPE_META) {
+ if (sequencer_refresh_sound_length_recursive(scene, &seq->seqbase)) {
+ BKE_sequence_calc(scene, seq);
+ changed = true;
+ }
+ }
+ else if (seq->type == SEQ_TYPE_SOUND_RAM) {
+ AUD_SoundInfo info = AUD_getInfo(seq->sound->playback_handle);
+ int old = seq->len;
+ float fac;
+
+ seq->len = (int)ceil((double)info.length * FPS);
+ fac = (float)seq->len / (float)old;
+ old = seq->startofs;
+ seq->startofs *= fac;
+ seq->endofs *= fac;
+ seq->start += (old - seq->startofs); /* So that visual/"real" start frame does not change! */
+
+ BKE_sequence_calc(scene, seq);
+ changed = true;
+ }
+ }
+ return changed;
}
#endif
void BKE_sequencer_refresh_sound_length(Scene *scene)
{
#ifdef WITH_AUDASPACE
- if (scene->ed) {
- sequencer_refresh_sound_length_recursive(scene, &scene->ed->seqbase);
- }
+ if (scene->ed) {
+ sequencer_refresh_sound_length_recursive(scene, &scene->ed->seqbase);
+ }
#else
- (void)scene;
+ (void)scene;
#endif
}
void BKE_sequencer_update_sound_bounds_all(Scene *scene)
{
- Editing *ed = scene->ed;
+ Editing *ed = scene->ed;
- if (ed) {
- Sequence *seq;
+ if (ed) {
+ Sequence *seq;
- for (seq = ed->seqbase.first; seq; seq = seq->next) {
- if (seq->type == SEQ_TYPE_META) {
- seq_update_sound_bounds_recursive(scene, seq);
- }
- else if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE)) {
- BKE_sequencer_update_sound_bounds(scene, seq);
- }
- }
- }
+ for (seq = ed->seqbase.first; seq; seq = seq->next) {
+ if (seq->type == SEQ_TYPE_META) {
+ seq_update_sound_bounds_recursive(scene, seq);
+ }
+ else if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE)) {
+ BKE_sequencer_update_sound_bounds(scene, seq);
+ }
+ }
+ }
}
void BKE_sequencer_update_sound_bounds(Scene *scene, Sequence *seq)
{
- if (seq->type == SEQ_TYPE_SCENE) {
- if (seq->scene_sound) {
- /* We have to take into account start frame of the sequence's scene! */
- int startofs = seq->startofs + seq->anim_startofs + seq->scene->r.sfra;
+ if (seq->type == SEQ_TYPE_SCENE) {
+ if (seq->scene_sound) {
+ /* We have to take into account start frame of the sequence's scene! */
+ int startofs = seq->startofs + seq->anim_startofs + seq->scene->r.sfra;
- BKE_sound_move_scene_sound(scene, seq->scene_sound, seq->startdisp, seq->enddisp, startofs);
- }
- }
- else {
- BKE_sound_move_scene_sound_defaults(scene, seq);
- }
- /* mute is set in seq_update_muting_recursive */
+ BKE_sound_move_scene_sound(scene, seq->scene_sound, seq->startdisp, seq->enddisp, startofs);
+ }
+ }
+ else {
+ BKE_sound_move_scene_sound_defaults(scene, seq);
+ }
+ /* mute is set in seq_update_muting_recursive */
}
static void seq_update_muting_recursive(ListBase *seqbasep, Sequence *metaseq, int mute)
{
- Sequence *seq;
- int seqmute;
+ Sequence *seq;
+ int seqmute;
- /* for sound we go over full meta tree to update muted state,
- * since sound is played outside of evaluating the imbufs, */
- for (seq = seqbasep->first; seq; seq = seq->next) {
- seqmute = (mute || (seq->flag & SEQ_MUTE));
+ /* for sound we go over full meta tree to update muted state,
+ * since sound is played outside of evaluating the imbufs, */
+ for (seq = seqbasep->first; seq; seq = seq->next) {
+ seqmute = (mute || (seq->flag & SEQ_MUTE));
- if (seq->type == SEQ_TYPE_META) {
- /* if this is the current meta sequence, unmute because
- * all sequences above this were set to mute */
- if (seq == metaseq)
- seqmute = 0;
+ if (seq->type == SEQ_TYPE_META) {
+ /* if this is the current meta sequence, unmute because
+ * all sequences above this were set to mute */
+ if (seq == metaseq)
+ seqmute = 0;
- seq_update_muting_recursive(&seq->seqbase, metaseq, seqmute);
- }
- else if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE)) {
- if (seq->scene_sound) {
- BKE_sound_mute_scene_sound(seq->scene_sound, seqmute);
- }
- }
- }
+ seq_update_muting_recursive(&seq->seqbase, metaseq, seqmute);
+ }
+ else if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE)) {
+ if (seq->scene_sound) {
+ BKE_sound_mute_scene_sound(seq->scene_sound, seqmute);
+ }
+ }
+ }
}
void BKE_sequencer_update_muting(Editing *ed)
{
- if (ed) {
- /* mute all sounds up to current metastack list */
- MetaStack *ms = ed->metastack.last;
+ if (ed) {
+ /* mute all sounds up to current metastack list */
+ MetaStack *ms = ed->metastack.last;
- if (ms)
- seq_update_muting_recursive(&ed->seqbase, ms->parseq, 1);
- else
- seq_update_muting_recursive(&ed->seqbase, NULL, 0);
- }
+ if (ms)
+ seq_update_muting_recursive(&ed->seqbase, ms->parseq, 1);
+ else
+ seq_update_muting_recursive(&ed->seqbase, NULL, 0);
+ }
}
static void seq_update_sound_recursive(Scene *scene, ListBase *seqbasep, bSound *sound)
{
- Sequence *seq;
+ Sequence *seq;
- for (seq = seqbasep->first; seq; seq = seq->next) {
- if (seq->type == SEQ_TYPE_META) {
- seq_update_sound_recursive(scene, &seq->seqbase, sound);
- }
- else if (seq->type == SEQ_TYPE_SOUND_RAM) {
- if (seq->scene_sound && sound == seq->sound) {
- BKE_sound_update_scene_sound(seq->scene_sound, sound);
- }
- }
- }
+ for (seq = seqbasep->first; seq; seq = seq->next) {
+ if (seq->type == SEQ_TYPE_META) {
+ seq_update_sound_recursive(scene, &seq->seqbase, sound);
+ }
+ else if (seq->type == SEQ_TYPE_SOUND_RAM) {
+ if (seq->scene_sound && sound == seq->sound) {
+ BKE_sound_update_scene_sound(seq->scene_sound, sound);
+ }
+ }
+ }
}
void BKE_sequencer_update_sound(Scene *scene, bSound *sound)
{
- if (scene->ed) {
- seq_update_sound_recursive(scene, &scene->ed->seqbase, sound);
- }
+ if (scene->ed) {
+ seq_update_sound_recursive(scene, &scene->ed->seqbase, sound);
+ }
}
/* in cases where we done know the sequence's listbase */
ListBase *BKE_sequence_seqbase(ListBase *seqbase, Sequence *seq)
{
- Sequence *iseq;
- ListBase *lb = NULL;
+ Sequence *iseq;
+ ListBase *lb = NULL;
- for (iseq = seqbase->first; iseq; iseq = iseq->next) {
- if (seq == iseq) {
- return seqbase;
- }
- else if (iseq->seqbase.first && (lb = BKE_sequence_seqbase(&iseq->seqbase, seq))) {
- return lb;
- }
- }
+ for (iseq = seqbase->first; iseq; iseq = iseq->next) {
+ if (seq == iseq) {
+ return seqbase;
+ }
+ else if (iseq->seqbase.first && (lb = BKE_sequence_seqbase(&iseq->seqbase, seq))) {
+ return lb;
+ }
+ }
- return NULL;
+ return NULL;
}
Sequence *BKE_sequence_metastrip(ListBase *seqbase, Sequence *meta, Sequence *seq)
{
- Sequence *iseq;
+ Sequence *iseq;
- for (iseq = seqbase->first; iseq; iseq = iseq->next) {
- Sequence *rval;
+ for (iseq = seqbase->first; iseq; iseq = iseq->next) {
+ Sequence *rval;
- if (seq == iseq) {
- return meta;
- }
- else if (iseq->seqbase.first &&
- (rval = BKE_sequence_metastrip(&iseq->seqbase, iseq, seq)))
- {
- return rval;
- }
- }
+ if (seq == iseq) {
+ return meta;
+ }
+ else if (iseq->seqbase.first && (rval = BKE_sequence_metastrip(&iseq->seqbase, iseq, seq))) {
+ return rval;
+ }
+ }
- return NULL;
+ return NULL;
}
int BKE_sequence_swap(Sequence *seq_a, Sequence *seq_b, const char **error_str)
{
- char name[sizeof(seq_a->name)];
-
- if (seq_a->len != seq_b->len) {
- *error_str = N_("Strips must be the same length");
- return 0;
- }
-
- /* type checking, could be more advanced but disallow sound vs non-sound copy */
- if (seq_a->type != seq_b->type) {
- if (seq_a->type == SEQ_TYPE_SOUND_RAM || seq_b->type == SEQ_TYPE_SOUND_RAM) {
- *error_str = N_("Strips were not compatible");
- return 0;
- }
-
- /* disallow effects to swap with non-effects strips */
- if ((seq_a->type & SEQ_TYPE_EFFECT) != (seq_b->type & SEQ_TYPE_EFFECT)) {
- *error_str = N_("Strips were not compatible");
- return 0;
- }
-
- if ((seq_a->type & SEQ_TYPE_EFFECT) && (seq_b->type & SEQ_TYPE_EFFECT)) {
- if (BKE_sequence_effect_get_num_inputs(seq_a->type) != BKE_sequence_effect_get_num_inputs(seq_b->type)) {
- *error_str = N_("Strips must have the same number of inputs");
- return 0;
- }
- }
- }
-
- SWAP(Sequence, *seq_a, *seq_b);
-
- /* swap back names so animation fcurves don't get swapped */
- BLI_strncpy(name, seq_a->name + 2, sizeof(name));
- BLI_strncpy(seq_a->name + 2, seq_b->name + 2, sizeof(seq_b->name) - 2);
- BLI_strncpy(seq_b->name + 2, name, sizeof(seq_b->name) - 2);
-
- /* swap back opacity, and overlay mode */
- SWAP(int, seq_a->blend_mode, seq_b->blend_mode);
- SWAP(float, seq_a->blend_opacity, seq_b->blend_opacity);
-
-
- SWAP(Sequence *, seq_a->prev, seq_b->prev);
- SWAP(Sequence *, seq_a->next, seq_b->next);
- SWAP(int, seq_a->start, seq_b->start);
- SWAP(int, seq_a->startofs, seq_b->startofs);
- SWAP(int, seq_a->endofs, seq_b->endofs);
- SWAP(int, seq_a->startstill, seq_b->startstill);
- SWAP(int, seq_a->endstill, seq_b->endstill);
- SWAP(int, seq_a->machine, seq_b->machine);
- SWAP(int, seq_a->startdisp, seq_b->startdisp);
- SWAP(int, seq_a->enddisp, seq_b->enddisp);
-
- return 1;
+ char name[sizeof(seq_a->name)];
+
+ if (seq_a->len != seq_b->len) {
+ *error_str = N_("Strips must be the same length");
+ return 0;
+ }
+
+ /* type checking, could be more advanced but disallow sound vs non-sound copy */
+ if (seq_a->type != seq_b->type) {
+ if (seq_a->type == SEQ_TYPE_SOUND_RAM || seq_b->type == SEQ_TYPE_SOUND_RAM) {
+ *error_str = N_("Strips were not compatible");
+ return 0;
+ }
+
+ /* disallow effects to swap with non-effects strips */
+ if ((seq_a->type & SEQ_TYPE_EFFECT) != (seq_b->type & SEQ_TYPE_EFFECT)) {
+ *error_str = N_("Strips were not compatible");
+ return 0;
+ }
+
+ if ((seq_a->type & SEQ_TYPE_EFFECT) && (seq_b->type & SEQ_TYPE_EFFECT)) {
+ if (BKE_sequence_effect_get_num_inputs(seq_a->type) !=
+ BKE_sequence_effect_get_num_inputs(seq_b->type)) {
+ *error_str = N_("Strips must have the same number of inputs");
+ return 0;
+ }
+ }
+ }
+
+ SWAP(Sequence, *seq_a, *seq_b);
+
+ /* swap back names so animation fcurves don't get swapped */
+ BLI_strncpy(name, seq_a->name + 2, sizeof(name));
+ BLI_strncpy(seq_a->name + 2, seq_b->name + 2, sizeof(seq_b->name) - 2);
+ BLI_strncpy(seq_b->name + 2, name, sizeof(seq_b->name) - 2);
+
+ /* swap back opacity, and overlay mode */
+ SWAP(int, seq_a->blend_mode, seq_b->blend_mode);
+ SWAP(float, seq_a->blend_opacity, seq_b->blend_opacity);
+
+ SWAP(Sequence *, seq_a->prev, seq_b->prev);
+ SWAP(Sequence *, seq_a->next, seq_b->next);
+ SWAP(int, seq_a->start, seq_b->start);
+ SWAP(int, seq_a->startofs, seq_b->startofs);
+ SWAP(int, seq_a->endofs, seq_b->endofs);
+ SWAP(int, seq_a->startstill, seq_b->startstill);
+ SWAP(int, seq_a->endstill, seq_b->endstill);
+ SWAP(int, seq_a->machine, seq_b->machine);
+ SWAP(int, seq_a->startdisp, seq_b->startdisp);
+ SWAP(int, seq_a->enddisp, seq_b->enddisp);
+
+ return 1;
}
/* prefix + [" + escaped_name + "] + \0 */
@@ -4856,120 +5037,123 @@ int BKE_sequence_swap(Sequence *seq_a, Sequence *seq_b, const char **error_str)
static size_t sequencer_rna_path_prefix(char str[SEQ_RNAPATH_MAXSTR], const char *name)
{
- char name_esc[SEQ_NAME_MAXSTR * 2];
+ char name_esc[SEQ_NAME_MAXSTR * 2];
- BLI_strescape(name_esc, name, sizeof(name_esc));
- return BLI_snprintf_rlen(str, SEQ_RNAPATH_MAXSTR, "sequence_editor.sequences_all[\"%s\"]", name_esc);
+ BLI_strescape(name_esc, name, sizeof(name_esc));
+ return BLI_snprintf_rlen(
+ str, SEQ_RNAPATH_MAXSTR, "sequence_editor.sequences_all[\"%s\"]", name_esc);
}
/* XXX - hackish function needed for transforming strips! TODO - have some better solution */
void BKE_sequencer_offset_animdata(Scene *scene, Sequence *seq, int ofs)
{
- char str[SEQ_RNAPATH_MAXSTR];
- size_t str_len;
- FCurve *fcu;
-
- if (scene->adt == NULL || ofs == 0 || scene->adt->action == NULL)
- return;
-
- str_len = sequencer_rna_path_prefix(str, seq->name + 2);
-
- for (fcu = scene->adt->action->curves.first; fcu; fcu = fcu->next) {
- if (STREQLEN(fcu->rna_path, str, str_len)) {
- unsigned int i;
- if (fcu->bezt) {
- for (i = 0; i < fcu->totvert; i++) {
- BezTriple *bezt = &fcu->bezt[i];
- bezt->vec[0][0] += ofs;
- bezt->vec[1][0] += ofs;
- bezt->vec[2][0] += ofs;
- }
- }
- if (fcu->fpt) {
- for (i = 0; i < fcu->totvert; i++) {
- FPoint *fpt = &fcu->fpt[i];
- fpt->vec[0] += ofs;
- }
- }
- }
- }
+ char str[SEQ_RNAPATH_MAXSTR];
+ size_t str_len;
+ FCurve *fcu;
+
+ if (scene->adt == NULL || ofs == 0 || scene->adt->action == NULL)
+ return;
+
+ str_len = sequencer_rna_path_prefix(str, seq->name + 2);
+
+ for (fcu = scene->adt->action->curves.first; fcu; fcu = fcu->next) {
+ if (STREQLEN(fcu->rna_path, str, str_len)) {
+ unsigned int i;
+ if (fcu->bezt) {
+ for (i = 0; i < fcu->totvert; i++) {
+ BezTriple *bezt = &fcu->bezt[i];
+ bezt->vec[0][0] += ofs;
+ bezt->vec[1][0] += ofs;
+ bezt->vec[2][0] += ofs;
+ }
+ }
+ if (fcu->fpt) {
+ for (i = 0; i < fcu->totvert; i++) {
+ FPoint *fpt = &fcu->fpt[i];
+ fpt->vec[0] += ofs;
+ }
+ }
+ }
+ }
}
void BKE_sequencer_dupe_animdata(Scene *scene, const char *name_src, const char *name_dst)
{
- char str_from[SEQ_RNAPATH_MAXSTR];
- size_t str_from_len;
- FCurve *fcu;
- FCurve *fcu_last;
- FCurve *fcu_cpy;
- ListBase lb = {NULL, NULL};
+ char str_from[SEQ_RNAPATH_MAXSTR];
+ size_t str_from_len;
+ FCurve *fcu;
+ FCurve *fcu_last;
+ FCurve *fcu_cpy;
+ ListBase lb = {NULL, NULL};
- if (scene->adt == NULL || scene->adt->action == NULL)
- return;
+ if (scene->adt == NULL || scene->adt->action == NULL)
+ return;
- str_from_len = sequencer_rna_path_prefix(str_from, name_src);
+ str_from_len = sequencer_rna_path_prefix(str_from, name_src);
- fcu_last = scene->adt->action->curves.last;
+ fcu_last = scene->adt->action->curves.last;
- for (fcu = scene->adt->action->curves.first; fcu && fcu->prev != fcu_last; fcu = fcu->next) {
- if (STREQLEN(fcu->rna_path, str_from, str_from_len)) {
- fcu_cpy = copy_fcurve(fcu);
- BLI_addtail(&lb, fcu_cpy);
- }
- }
+ for (fcu = scene->adt->action->curves.first; fcu && fcu->prev != fcu_last; fcu = fcu->next) {
+ if (STREQLEN(fcu->rna_path, str_from, str_from_len)) {
+ fcu_cpy = copy_fcurve(fcu);
+ BLI_addtail(&lb, fcu_cpy);
+ }
+ }
- /* notice validate is 0, keep this because the seq may not be added to the scene yet */
- BKE_animdata_fix_paths_rename(&scene->id, scene->adt, NULL, "sequence_editor.sequences_all", name_src, name_dst, 0, 0, 0);
+ /* notice validate is 0, keep this because the seq may not be added to the scene yet */
+ BKE_animdata_fix_paths_rename(
+ &scene->id, scene->adt, NULL, "sequence_editor.sequences_all", name_src, name_dst, 0, 0, 0);
- /* add the original fcurves back */
- BLI_movelisttolist(&scene->adt->action->curves, &lb);
+ /* add the original fcurves back */
+ BLI_movelisttolist(&scene->adt->action->curves, &lb);
}
/* XXX - hackish function needed to remove all fcurves belonging to a sequencer strip */
static void seq_free_animdata(Scene *scene, Sequence *seq)
{
- char str[SEQ_RNAPATH_MAXSTR];
- size_t str_len;
- FCurve *fcu;
+ char str[SEQ_RNAPATH_MAXSTR];
+ size_t str_len;
+ FCurve *fcu;
- if (scene->adt == NULL || scene->adt->action == NULL)
- return;
+ if (scene->adt == NULL || scene->adt->action == NULL)
+ return;
- str_len = sequencer_rna_path_prefix(str, seq->name + 2);
+ str_len = sequencer_rna_path_prefix(str, seq->name + 2);
- fcu = scene->adt->action->curves.first;
+ fcu = scene->adt->action->curves.first;
- while (fcu) {
- if (STREQLEN(fcu->rna_path, str, str_len)) {
- FCurve *next_fcu = fcu->next;
+ while (fcu) {
+ if (STREQLEN(fcu->rna_path, str, str_len)) {
+ FCurve *next_fcu = fcu->next;
- BLI_remlink(&scene->adt->action->curves, fcu);
- free_fcurve(fcu);
+ BLI_remlink(&scene->adt->action->curves, fcu);
+ free_fcurve(fcu);
- fcu = next_fcu;
- }
- else {
- fcu = fcu->next;
- }
- }
+ fcu = next_fcu;
+ }
+ else {
+ fcu = fcu->next;
+ }
+ }
}
#undef SEQ_RNAPATH_MAXSTR
Sequence *BKE_sequence_get_by_name(ListBase *seqbase, const char *name, bool recursive)
{
- Sequence *iseq = NULL;
- Sequence *rseq = NULL;
+ Sequence *iseq = NULL;
+ Sequence *rseq = NULL;
- for (iseq = seqbase->first; iseq; iseq = iseq->next) {
- if (STREQ(name, iseq->name + 2))
- return iseq;
- else if (recursive && (iseq->seqbase.first) && (rseq = BKE_sequence_get_by_name(&iseq->seqbase, name, 1))) {
- return rseq;
- }
- }
+ for (iseq = seqbase->first; iseq; iseq = iseq->next) {
+ if (STREQ(name, iseq->name + 2))
+ return iseq;
+ else if (recursive && (iseq->seqbase.first) &&
+ (rseq = BKE_sequence_get_by_name(&iseq->seqbase, name, 1))) {
+ return rseq;
+ }
+ }
- return NULL;
+ return NULL;
}
/**
@@ -4978,754 +5162,764 @@ Sequence *BKE_sequence_get_by_name(ListBase *seqbase, const char *name, bool rec
*/
Sequence *BKE_sequencer_from_elem(ListBase *seqbase, StripElem *se)
{
- Sequence *iseq;
+ Sequence *iseq;
- for (iseq = seqbase->first; iseq; iseq = iseq->next) {
- Sequence *seq_found;
- if ((iseq->strip && iseq->strip->stripdata) &&
- (ARRAY_HAS_ITEM(se, iseq->strip->stripdata, iseq->len)))
- {
- break;
- }
- else if ((seq_found = BKE_sequencer_from_elem(&iseq->seqbase, se))) {
- iseq = seq_found;
- break;
- }
- }
+ for (iseq = seqbase->first; iseq; iseq = iseq->next) {
+ Sequence *seq_found;
+ if ((iseq->strip && iseq->strip->stripdata) &&
+ (ARRAY_HAS_ITEM(se, iseq->strip->stripdata, iseq->len))) {
+ break;
+ }
+ else if ((seq_found = BKE_sequencer_from_elem(&iseq->seqbase, se))) {
+ iseq = seq_found;
+ break;
+ }
+ }
- return iseq;
+ return iseq;
}
Sequence *BKE_sequencer_active_get(Scene *scene)
{
- Editing *ed = BKE_sequencer_editing_get(scene, false);
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
- if (ed == NULL)
- return NULL;
+ if (ed == NULL)
+ return NULL;
- return ed->act_seq;
+ return ed->act_seq;
}
void BKE_sequencer_active_set(Scene *scene, Sequence *seq)
{
- Editing *ed = BKE_sequencer_editing_get(scene, false);
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
- if (ed == NULL)
- return;
+ if (ed == NULL)
+ return;
- ed->act_seq = seq;
+ ed->act_seq = seq;
}
int BKE_sequencer_active_get_pair(Scene *scene, Sequence **seq_act, Sequence **seq_other)
{
- Editing *ed = BKE_sequencer_editing_get(scene, false);
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
- *seq_act = BKE_sequencer_active_get(scene);
+ *seq_act = BKE_sequencer_active_get(scene);
- if (*seq_act == NULL) {
- return 0;
- }
- else {
- Sequence *seq;
+ if (*seq_act == NULL) {
+ return 0;
+ }
+ else {
+ Sequence *seq;
- *seq_other = NULL;
+ *seq_other = NULL;
- for (seq = ed->seqbasep->first; seq; seq = seq->next) {
- if (seq->flag & SELECT && (seq != (*seq_act))) {
- if (*seq_other) {
- return 0;
- }
- else {
- *seq_other = seq;
- }
- }
- }
+ for (seq = ed->seqbasep->first; seq; seq = seq->next) {
+ if (seq->flag & SELECT && (seq != (*seq_act))) {
+ if (*seq_other) {
+ return 0;
+ }
+ else {
+ *seq_other = seq;
+ }
+ }
+ }
- return (*seq_other != NULL);
- }
+ return (*seq_other != NULL);
+ }
}
Mask *BKE_sequencer_mask_get(Scene *scene)
{
- Sequence *seq_act = BKE_sequencer_active_get(scene);
+ Sequence *seq_act = BKE_sequencer_active_get(scene);
- if (seq_act && seq_act->type == SEQ_TYPE_MASK) {
- return seq_act->mask;
- }
- else {
- return NULL;
- }
+ if (seq_act && seq_act->type == SEQ_TYPE_MASK) {
+ return seq_act->mask;
+ }
+ else {
+ return NULL;
+ }
}
/* api like funcs for adding */
static void seq_load_apply(Main *bmain, Scene *scene, Sequence *seq, SeqLoadInfo *seq_load)
{
- if (seq) {
- BLI_strncpy_utf8(seq->name + 2, seq_load->name, sizeof(seq->name) - 2);
- BLI_utf8_invalid_strip(seq->name + 2, strlen(seq->name + 2));
- BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq);
+ if (seq) {
+ BLI_strncpy_utf8(seq->name + 2, seq_load->name, sizeof(seq->name) - 2);
+ BLI_utf8_invalid_strip(seq->name + 2, strlen(seq->name + 2));
+ BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq);
- if (seq_load->flag & SEQ_LOAD_FRAME_ADVANCE) {
- seq_load->start_frame += (seq->enddisp - seq->startdisp);
- }
+ if (seq_load->flag & SEQ_LOAD_FRAME_ADVANCE) {
+ seq_load->start_frame += (seq->enddisp - seq->startdisp);
+ }
- if (seq_load->flag & SEQ_LOAD_REPLACE_SEL) {
- seq_load->flag |= SELECT;
- BKE_sequencer_active_set(scene, seq);
- }
+ if (seq_load->flag & SEQ_LOAD_REPLACE_SEL) {
+ seq_load->flag |= SELECT;
+ BKE_sequencer_active_set(scene, seq);
+ }
- if (seq_load->flag & SEQ_LOAD_SOUND_MONO) {
- seq->sound->flags |= SOUND_FLAGS_MONO;
- BKE_sound_load(bmain, seq->sound);
- }
+ if (seq_load->flag & SEQ_LOAD_SOUND_MONO) {
+ seq->sound->flags |= SOUND_FLAGS_MONO;
+ BKE_sound_load(bmain, seq->sound);
+ }
- if (seq_load->flag & SEQ_LOAD_SOUND_CACHE) {
- if (seq->sound)
- BKE_sound_cache(seq->sound);
- }
+ if (seq_load->flag & SEQ_LOAD_SOUND_CACHE) {
+ if (seq->sound)
+ BKE_sound_cache(seq->sound);
+ }
- seq_load->tot_success++;
- }
- else {
- seq_load->tot_error++;
- }
+ seq_load->tot_success++;
+ }
+ else {
+ seq_load->tot_error++;
+ }
}
Sequence *BKE_sequence_alloc(ListBase *lb, int cfra, int machine)
{
- Sequence *seq;
+ Sequence *seq;
- seq = MEM_callocN(sizeof(Sequence), "addseq");
- BLI_addtail(lb, seq);
+ seq = MEM_callocN(sizeof(Sequence), "addseq");
+ BLI_addtail(lb, seq);
- *( (short *)seq->name) = ID_SEQ;
- seq->name[2] = 0;
+ *((short *)seq->name) = ID_SEQ;
+ seq->name[2] = 0;
- seq->flag = SELECT;
- seq->start = cfra;
- seq->machine = machine;
- seq->sat = 1.0;
- seq->mul = 1.0;
- seq->blend_opacity = 100.0;
- seq->volume = 1.0f;
- seq->pitch = 1.0f;
- seq->scene_sound = NULL;
+ seq->flag = SELECT;
+ seq->start = cfra;
+ seq->machine = machine;
+ seq->sat = 1.0;
+ seq->mul = 1.0;
+ seq->blend_opacity = 100.0;
+ seq->volume = 1.0f;
+ seq->pitch = 1.0f;
+ seq->scene_sound = NULL;
- seq->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Sequence Stereo Format");
+ seq->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Sequence Stereo Format");
- return seq;
+ return seq;
}
void BKE_sequence_alpha_mode_from_extension(Sequence *seq)
{
- if (seq->strip && seq->strip->stripdata) {
- const char *filename = seq->strip->stripdata->name;
- seq->alpha_mode = BKE_image_alpha_mode_from_extension_ex(filename);
- }
+ if (seq->strip && seq->strip->stripdata) {
+ const char *filename = seq->strip->stripdata->name;
+ seq->alpha_mode = BKE_image_alpha_mode_from_extension_ex(filename);
+ }
}
void BKE_sequence_init_colorspace(Sequence *seq)
{
- if (seq->strip && seq->strip->stripdata) {
- char name[FILE_MAX];
- ImBuf *ibuf;
+ if (seq->strip && seq->strip->stripdata) {
+ char name[FILE_MAX];
+ ImBuf *ibuf;
- BLI_join_dirfile(name, sizeof(name), seq->strip->dir, seq->strip->stripdata->name);
- BLI_path_abs(name, BKE_main_blendfile_path_from_global());
+ BLI_join_dirfile(name, sizeof(name), seq->strip->dir, seq->strip->stripdata->name);
+ BLI_path_abs(name, BKE_main_blendfile_path_from_global());
- /* initialize input color space */
- if (seq->type == SEQ_TYPE_IMAGE) {
- ibuf = IMB_loadiffname(name, IB_test | IB_alphamode_detect, seq->strip->colorspace_settings.name);
+ /* initialize input color space */
+ if (seq->type == SEQ_TYPE_IMAGE) {
+ ibuf = IMB_loadiffname(
+ name, IB_test | IB_alphamode_detect, seq->strip->colorspace_settings.name);
- /* byte images are default to straight alpha, however sequencer
- * works in premul space, so mark strip to be premultiplied first
- */
- seq->alpha_mode = SEQ_ALPHA_STRAIGHT;
- if (ibuf) {
- if (ibuf->flags & IB_alphamode_premul)
- seq->alpha_mode = IMA_ALPHA_PREMUL;
+ /* byte images are default to straight alpha, however sequencer
+ * works in premul space, so mark strip to be premultiplied first
+ */
+ seq->alpha_mode = SEQ_ALPHA_STRAIGHT;
+ if (ibuf) {
+ if (ibuf->flags & IB_alphamode_premul)
+ seq->alpha_mode = IMA_ALPHA_PREMUL;
- IMB_freeImBuf(ibuf);
- }
- }
- }
+ IMB_freeImBuf(ibuf);
+ }
+ }
+ }
}
float BKE_sequence_get_fps(Scene *scene, Sequence *seq)
{
- switch (seq->type) {
- case SEQ_TYPE_MOVIE:
- {
- seq_open_anim_file(scene, seq, true);
- if (BLI_listbase_is_empty(&seq->anims)) {
- return 0.0f;
- }
- StripAnim *strip_anim = seq->anims.first;
- if (strip_anim->anim == NULL) {
- return 0.0f;
- }
- short frs_sec;
- float frs_sec_base;
- if (IMB_anim_get_fps(strip_anim->anim, &frs_sec, &frs_sec_base, true)) {
- return (float)frs_sec / frs_sec_base;
- }
- break;
- }
- case SEQ_TYPE_MOVIECLIP:
- if (seq->clip != NULL) {
- return BKE_movieclip_get_fps(seq->clip);
- }
- break;
- case SEQ_TYPE_SCENE:
- if (seq->scene != NULL) {
- return (float)seq->scene->r.frs_sec / seq->scene->r.frs_sec_base;
- }
- break;
- }
- return 0.0f;
+ switch (seq->type) {
+ case SEQ_TYPE_MOVIE: {
+ seq_open_anim_file(scene, seq, true);
+ if (BLI_listbase_is_empty(&seq->anims)) {
+ return 0.0f;
+ }
+ StripAnim *strip_anim = seq->anims.first;
+ if (strip_anim->anim == NULL) {
+ return 0.0f;
+ }
+ short frs_sec;
+ float frs_sec_base;
+ if (IMB_anim_get_fps(strip_anim->anim, &frs_sec, &frs_sec_base, true)) {
+ return (float)frs_sec / frs_sec_base;
+ }
+ break;
+ }
+ case SEQ_TYPE_MOVIECLIP:
+ if (seq->clip != NULL) {
+ return BKE_movieclip_get_fps(seq->clip);
+ }
+ break;
+ case SEQ_TYPE_SCENE:
+ if (seq->scene != NULL) {
+ return (float)seq->scene->r.frs_sec / seq->scene->r.frs_sec_base;
+ }
+ break;
+ }
+ return 0.0f;
}
/* NOTE: this function doesn't fill in image names */
Sequence *BKE_sequencer_add_image_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load)
{
- Scene *scene = CTX_data_scene(C); /* only for active seq */
- Sequence *seq;
- Strip *strip;
+ Scene *scene = CTX_data_scene(C); /* only for active seq */
+ Sequence *seq;
+ Strip *strip;
- seq = BKE_sequence_alloc(seqbasep, seq_load->start_frame, seq_load->channel);
- seq->type = SEQ_TYPE_IMAGE;
- seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */
+ seq = BKE_sequence_alloc(seqbasep, seq_load->start_frame, seq_load->channel);
+ seq->type = SEQ_TYPE_IMAGE;
+ seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */
- /* basic defaults */
- seq->strip = strip = MEM_callocN(sizeof(Strip), "strip");
+ /* basic defaults */
+ seq->strip = strip = MEM_callocN(sizeof(Strip), "strip");
- seq->len = seq_load->len ? seq_load->len : 1;
- strip->us = 1;
- strip->stripdata = MEM_callocN(seq->len * sizeof(StripElem), "stripelem");
- BLI_strncpy(strip->dir, seq_load->path, sizeof(strip->dir));
+ seq->len = seq_load->len ? seq_load->len : 1;
+ strip->us = 1;
+ strip->stripdata = MEM_callocN(seq->len * sizeof(StripElem), "stripelem");
+ BLI_strncpy(strip->dir, seq_load->path, sizeof(strip->dir));
- if (seq_load->stereo3d_format)
- *seq->stereo3d_format = *seq_load->stereo3d_format;
+ if (seq_load->stereo3d_format)
+ *seq->stereo3d_format = *seq_load->stereo3d_format;
- seq->views_format = seq_load->views_format;
- seq->flag |= seq_load->flag & SEQ_USE_VIEWS;
+ seq->views_format = seq_load->views_format;
+ seq->flag |= seq_load->flag & SEQ_USE_VIEWS;
- seq_load_apply(CTX_data_main(C), scene, seq, seq_load);
+ seq_load_apply(CTX_data_main(C), scene, seq, seq_load);
- return seq;
+ return seq;
}
#ifdef WITH_AUDASPACE
Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load)
{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C); /* only for sound */
- Editing *ed = BKE_sequencer_editing_get(scene, false);
- bSound *sound;
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C); /* only for sound */
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ bSound *sound;
- Sequence *seq; /* generic strip vars */
- Strip *strip;
- StripElem *se;
+ Sequence *seq; /* generic strip vars */
+ Strip *strip;
+ StripElem *se;
- AUD_SoundInfo info;
+ AUD_SoundInfo info;
- sound = BKE_sound_new_file(bmain, seq_load->path); /* handles relative paths */
+ sound = BKE_sound_new_file(bmain, seq_load->path); /* handles relative paths */
- if (sound->playback_handle == NULL) {
- BKE_id_free(bmain, sound);
- return NULL;
- }
+ if (sound->playback_handle == NULL) {
+ BKE_id_free(bmain, sound);
+ return NULL;
+ }
- info = AUD_getInfo(sound->playback_handle);
+ info = AUD_getInfo(sound->playback_handle);
- if (info.specs.channels == AUD_CHANNELS_INVALID) {
- BKE_id_free(bmain, sound);
- return NULL;
- }
+ if (info.specs.channels == AUD_CHANNELS_INVALID) {
+ BKE_id_free(bmain, sound);
+ return NULL;
+ }
- seq = BKE_sequence_alloc(seqbasep, seq_load->start_frame, seq_load->channel);
+ seq = BKE_sequence_alloc(seqbasep, seq_load->start_frame, seq_load->channel);
- seq->type = SEQ_TYPE_SOUND_RAM;
- seq->sound = sound;
- BLI_strncpy(seq->name + 2, "Sound", SEQ_NAME_MAXSTR - 2);
- BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq);
+ seq->type = SEQ_TYPE_SOUND_RAM;
+ seq->sound = sound;
+ BLI_strncpy(seq->name + 2, "Sound", SEQ_NAME_MAXSTR - 2);
+ BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq);
- /* basic defaults */
- seq->strip = strip = MEM_callocN(sizeof(Strip), "strip");
- /* We add a very small negative offset here, because ceil(132.0) == 133.0, not nice with videos, see T47135. */
- seq->len = (int)ceil((double)info.length * FPS - 1e-4);
- strip->us = 1;
+ /* basic defaults */
+ seq->strip = strip = MEM_callocN(sizeof(Strip), "strip");
+ /* We add a very small negative offset here, because ceil(132.0) == 133.0, not nice with videos, see T47135. */
+ seq->len = (int)ceil((double)info.length * FPS - 1e-4);
+ strip->us = 1;
- /* we only need 1 element to store the filename */
- strip->stripdata = se = MEM_callocN(sizeof(StripElem), "stripelem");
+ /* we only need 1 element to store the filename */
+ strip->stripdata = se = MEM_callocN(sizeof(StripElem), "stripelem");
- BLI_split_dirfile(seq_load->path, strip->dir, se->name, sizeof(strip->dir), sizeof(se->name));
+ BLI_split_dirfile(seq_load->path, strip->dir, se->name, sizeof(strip->dir), sizeof(se->name));
- seq->scene_sound = BKE_sound_add_scene_sound(scene, seq, seq_load->start_frame, seq_load->start_frame + seq->len, 0);
+ seq->scene_sound = BKE_sound_add_scene_sound(
+ scene, seq, seq_load->start_frame, seq_load->start_frame + seq->len, 0);
- BKE_sequence_calc_disp(scene, seq);
+ BKE_sequence_calc_disp(scene, seq);
- /* last active name */
- BLI_strncpy(ed->act_sounddir, strip->dir, FILE_MAXDIR);
+ /* last active name */
+ BLI_strncpy(ed->act_sounddir, strip->dir, FILE_MAXDIR);
- seq_load_apply(bmain, scene, seq, seq_load);
+ seq_load_apply(bmain, scene, seq, seq_load);
- return seq;
+ return seq;
}
-#else // WITH_AUDASPACE
+#else // WITH_AUDASPACE
Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load)
{
- (void) C;
- (void) seqbasep;
- (void) seq_load;
- return NULL;
+ (void)C;
+ (void)seqbasep;
+ (void)seq_load;
+ return NULL;
}
-#endif // WITH_AUDASPACE
+#endif // WITH_AUDASPACE
static void seq_anim_add_suffix(Scene *scene, struct anim *anim, const int view_id)
{
- const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, view_id);
- IMB_suffix_anim(anim, suffix);
+ const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, view_id);
+ IMB_suffix_anim(anim, suffix);
}
Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load)
{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C); /* only for sound */
- char path[sizeof(seq_load->path)];
-
- Sequence *seq; /* generic strip vars */
- Strip *strip;
- StripElem *se;
- char colorspace[64] = "\0"; /* MAX_COLORSPACE_NAME */
- bool is_multiview_loaded = false;
- const bool is_multiview = (seq_load->flag & SEQ_USE_VIEWS) != 0;
- const int totfiles = seq_num_files(scene, seq_load->views_format, is_multiview);
- struct anim **anim_arr;
- int i;
-
- BLI_strncpy(path, seq_load->path, sizeof(path));
- BLI_path_abs(path, BKE_main_blendfile_path(bmain));
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C); /* only for sound */
+ char path[sizeof(seq_load->path)];
+
+ Sequence *seq; /* generic strip vars */
+ Strip *strip;
+ StripElem *se;
+ char colorspace[64] = "\0"; /* MAX_COLORSPACE_NAME */
+ bool is_multiview_loaded = false;
+ const bool is_multiview = (seq_load->flag & SEQ_USE_VIEWS) != 0;
+ const int totfiles = seq_num_files(scene, seq_load->views_format, is_multiview);
+ struct anim **anim_arr;
+ int i;
+
+ BLI_strncpy(path, seq_load->path, sizeof(path));
+ BLI_path_abs(path, BKE_main_blendfile_path(bmain));
+
+ anim_arr = MEM_callocN(sizeof(struct anim *) * totfiles, "Video files");
+
+ if (is_multiview && (seq_load->views_format == R_IMF_VIEWS_INDIVIDUAL)) {
+ char prefix[FILE_MAX];
+ const char *ext = NULL;
+ size_t j = 0;
+
+ BKE_scene_multiview_view_prefix_get(scene, path, prefix, &ext);
- anim_arr = MEM_callocN(sizeof(struct anim *) * totfiles, "Video files");
-
- if (is_multiview && (seq_load->views_format == R_IMF_VIEWS_INDIVIDUAL)) {
- char prefix[FILE_MAX];
- const char *ext = NULL;
- size_t j = 0;
+ if (prefix[0] != '\0') {
+ for (i = 0; i < totfiles; i++) {
+ char str[FILE_MAX];
- BKE_scene_multiview_view_prefix_get(scene, path, prefix, &ext);
+ seq_multiview_name(scene, i, prefix, ext, str, FILE_MAX);
+ anim_arr[j] = openanim(str, IB_rect, 0, colorspace);
- if (prefix[0] != '\0') {
- for (i = 0; i < totfiles; i++) {
- char str[FILE_MAX];
+ if (anim_arr[j]) {
+ seq_anim_add_suffix(scene, anim_arr[j], i);
+ j++;
+ }
+ }
- seq_multiview_name(scene, i, prefix, ext, str, FILE_MAX);
- anim_arr[j] = openanim(str, IB_rect, 0, colorspace);
+ if (j == 0) {
+ MEM_freeN(anim_arr);
+ return NULL;
+ }
+ is_multiview_loaded = true;
+ }
+ }
- if (anim_arr[j]) {
- seq_anim_add_suffix(scene, anim_arr[j], i);
- j++;
- }
- }
+ if (is_multiview_loaded == false) {
+ anim_arr[0] = openanim(path, IB_rect, 0, colorspace);
- if (j == 0) {
- MEM_freeN(anim_arr);
- return NULL;
- }
- is_multiview_loaded = true;
- }
- }
+ if (anim_arr[0] == NULL) {
+ MEM_freeN(anim_arr);
+ return NULL;
+ }
+ }
- if (is_multiview_loaded == false) {
- anim_arr[0] = openanim(path, IB_rect, 0, colorspace);
+ seq = BKE_sequence_alloc(seqbasep, seq_load->start_frame, seq_load->channel);
- if (anim_arr[0] == NULL) {
- MEM_freeN(anim_arr);
- return NULL;
- }
- }
+ /* multiview settings */
+ if (seq_load->stereo3d_format) {
+ *seq->stereo3d_format = *seq_load->stereo3d_format;
+ seq->views_format = seq_load->views_format;
+ }
+ seq->flag |= seq_load->flag & SEQ_USE_VIEWS;
- seq = BKE_sequence_alloc(seqbasep, seq_load->start_frame, seq_load->channel);
+ seq->type = SEQ_TYPE_MOVIE;
+ seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */
- /* multiview settings */
- if (seq_load->stereo3d_format) {
- *seq->stereo3d_format = *seq_load->stereo3d_format;
- seq->views_format = seq_load->views_format;
- }
- seq->flag |= seq_load->flag & SEQ_USE_VIEWS;
-
- seq->type = SEQ_TYPE_MOVIE;
- seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */
-
- for (i = 0; i < totfiles; i++) {
- if (anim_arr[i]) {
- StripAnim *sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
- BLI_addtail(&seq->anims, sanim);
- sanim->anim = anim_arr[i];
- }
- else {
- break;
- }
- }
-
- IMB_anim_load_metadata(anim_arr[0]);
-
- seq->anim_preseek = IMB_anim_get_preseek(anim_arr[0]);
- BLI_strncpy(seq->name + 2, "Movie", SEQ_NAME_MAXSTR - 2);
- BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq);
-
- /* adjust scene's frame rate settings to match */
- if (seq_load->flag & SEQ_LOAD_SYNC_FPS) {
- IMB_anim_get_fps(anim_arr[0], &scene->r.frs_sec, &scene->r.frs_sec_base, true);
- }
-
- /* basic defaults */
- seq->strip = strip = MEM_callocN(sizeof(Strip), "strip");
- seq->len = IMB_anim_get_duration(anim_arr[0], IMB_TC_RECORD_RUN);
- strip->us = 1;
-
- BLI_strncpy(seq->strip->colorspace_settings.name, colorspace, sizeof(seq->strip->colorspace_settings.name));
-
- /* we only need 1 element for MOVIE strips */
- strip->stripdata = se = MEM_callocN(sizeof(StripElem), "stripelem");
-
- BLI_split_dirfile(seq_load->path, strip->dir, se->name, sizeof(strip->dir), sizeof(se->name));
-
- BKE_sequence_calc_disp(scene, seq);
-
- if (seq_load->name[0] == '\0')
- BLI_strncpy(seq_load->name, se->name, sizeof(seq_load->name));
-
- if (seq_load->flag & SEQ_LOAD_MOVIE_SOUND) {
- int start_frame_back = seq_load->start_frame;
- seq_load->channel++;
-
- seq_load->seq_sound = BKE_sequencer_add_sound_strip(C, seqbasep, seq_load);
-
- seq_load->start_frame = start_frame_back;
- seq_load->channel--;
- }
-
- /* can be NULL */
- seq_load_apply(CTX_data_main(C), scene, seq, seq_load);
-
- MEM_freeN(anim_arr);
- return seq;
-}
-
-static Sequence *seq_dupli(
- const Scene *scene_src, Scene *scene_dst, ListBase *new_seq_list, Sequence *seq, int dupe_flag, const int flag)
-{
- Sequence *seqn = MEM_dupallocN(seq);
-
- seq->tmp = seqn;
- seqn->strip = MEM_dupallocN(seq->strip);
-
- seqn->stereo3d_format = MEM_dupallocN(seq->stereo3d_format);
-
- /* XXX: add F-Curve duplication stuff? */
-
- if (seq->strip->crop) {
- seqn->strip->crop = MEM_dupallocN(seq->strip->crop);
- }
-
- if (seq->strip->transform) {
- seqn->strip->transform = MEM_dupallocN(seq->strip->transform);
- }
-
- if (seq->strip->proxy) {
- seqn->strip->proxy = MEM_dupallocN(seq->strip->proxy);
- seqn->strip->proxy->anim = NULL;
- }
-
- if (seq->prop) {
- seqn->prop = IDP_CopyProperty_ex(seq->prop, flag);
- }
-
- if (seqn->modifiers.first) {
- BLI_listbase_clear(&seqn->modifiers);
-
- BKE_sequence_modifier_list_copy(seqn, seq);
- }
-
- if (seq->type == SEQ_TYPE_META) {
- seqn->strip->stripdata = NULL;
-
- BLI_listbase_clear(&seqn->seqbase);
- /* WATCH OUT!!! - This metastrip is not recursively duplicated here - do this after!!! */
- /* - seq_dupli_recursive(&seq->seqbase, &seqn->seqbase);*/
- }
- else if (seq->type == SEQ_TYPE_SCENE) {
- seqn->strip->stripdata = NULL;
- if (seq->scene_sound)
- seqn->scene_sound = BKE_sound_scene_add_scene_sound_defaults(scene_dst, seqn);
- }
- else if (seq->type == SEQ_TYPE_MOVIECLIP) {
- /* avoid assert */
- }
- else if (seq->type == SEQ_TYPE_MASK) {
- /* avoid assert */
- }
- else if (seq->type == SEQ_TYPE_MOVIE) {
- seqn->strip->stripdata =
- MEM_dupallocN(seq->strip->stripdata);
- BLI_listbase_clear(&seqn->anims);
- }
- else if (seq->type == SEQ_TYPE_SOUND_RAM) {
- seqn->strip->stripdata =
- MEM_dupallocN(seq->strip->stripdata);
- if (seq->scene_sound)
- seqn->scene_sound = BKE_sound_add_scene_sound_defaults(scene_dst, seqn);
-
- if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- id_us_plus((ID *)seqn->sound);
- }
- }
- else if (seq->type == SEQ_TYPE_IMAGE) {
- seqn->strip->stripdata =
- MEM_dupallocN(seq->strip->stripdata);
- }
- else if (seq->type & SEQ_TYPE_EFFECT) {
- struct SeqEffectHandle sh;
- sh = BKE_sequence_get_effect(seq);
- if (sh.copy)
- sh.copy(seq, seqn, flag);
-
- seqn->strip->stripdata = NULL;
-
- }
- else {
- /* sequence type not handled in duplicate! Expect a crash now... */
- BLI_assert(0);
- }
-
- /* When using SEQ_DUPE_UNIQUE_NAME, it is mandatory to add new sequences in relevant container
- * (scene or meta's one), *before* checking for unique names. Otherwise the meta's list is empty
- * and hence we miss all seqs in that meta that have already been duplicated (see T55668).
- * Note that unique name check itslef could be done at a later step in calling code, once all seqs
- * have bee duplicated (that was first, simpler solution), but then handling of animation data will
- * be broken (see T60194). */
- if (new_seq_list != NULL) {
- BLI_addtail(new_seq_list, seqn);
- }
-
- if (scene_src == scene_dst) {
- if (dupe_flag & SEQ_DUPE_UNIQUE_NAME) {
- BKE_sequence_base_unique_name_recursive(&scene_dst->ed->seqbase, seqn);
- }
-
- if (dupe_flag & SEQ_DUPE_ANIM) {
- BKE_sequencer_dupe_animdata(scene_dst, seq->name + 2, seqn->name + 2);
- }
- }
-
- return seqn;
+ for (i = 0; i < totfiles; i++) {
+ if (anim_arr[i]) {
+ StripAnim *sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim");
+ BLI_addtail(&seq->anims, sanim);
+ sanim->anim = anim_arr[i];
+ }
+ else {
+ break;
+ }
+ }
+
+ IMB_anim_load_metadata(anim_arr[0]);
+
+ seq->anim_preseek = IMB_anim_get_preseek(anim_arr[0]);
+ BLI_strncpy(seq->name + 2, "Movie", SEQ_NAME_MAXSTR - 2);
+ BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq);
+
+ /* adjust scene's frame rate settings to match */
+ if (seq_load->flag & SEQ_LOAD_SYNC_FPS) {
+ IMB_anim_get_fps(anim_arr[0], &scene->r.frs_sec, &scene->r.frs_sec_base, true);
+ }
+
+ /* basic defaults */
+ seq->strip = strip = MEM_callocN(sizeof(Strip), "strip");
+ seq->len = IMB_anim_get_duration(anim_arr[0], IMB_TC_RECORD_RUN);
+ strip->us = 1;
+
+ BLI_strncpy(seq->strip->colorspace_settings.name,
+ colorspace,
+ sizeof(seq->strip->colorspace_settings.name));
+
+ /* we only need 1 element for MOVIE strips */
+ strip->stripdata = se = MEM_callocN(sizeof(StripElem), "stripelem");
+
+ BLI_split_dirfile(seq_load->path, strip->dir, se->name, sizeof(strip->dir), sizeof(se->name));
+
+ BKE_sequence_calc_disp(scene, seq);
+
+ if (seq_load->name[0] == '\0')
+ BLI_strncpy(seq_load->name, se->name, sizeof(seq_load->name));
+
+ if (seq_load->flag & SEQ_LOAD_MOVIE_SOUND) {
+ int start_frame_back = seq_load->start_frame;
+ seq_load->channel++;
+
+ seq_load->seq_sound = BKE_sequencer_add_sound_strip(C, seqbasep, seq_load);
+
+ seq_load->start_frame = start_frame_back;
+ seq_load->channel--;
+ }
+
+ /* can be NULL */
+ seq_load_apply(CTX_data_main(C), scene, seq, seq_load);
+
+ MEM_freeN(anim_arr);
+ return seq;
+}
+
+static Sequence *seq_dupli(const Scene *scene_src,
+ Scene *scene_dst,
+ ListBase *new_seq_list,
+ Sequence *seq,
+ int dupe_flag,
+ const int flag)
+{
+ Sequence *seqn = MEM_dupallocN(seq);
+
+ seq->tmp = seqn;
+ seqn->strip = MEM_dupallocN(seq->strip);
+
+ seqn->stereo3d_format = MEM_dupallocN(seq->stereo3d_format);
+
+ /* XXX: add F-Curve duplication stuff? */
+
+ if (seq->strip->crop) {
+ seqn->strip->crop = MEM_dupallocN(seq->strip->crop);
+ }
+
+ if (seq->strip->transform) {
+ seqn->strip->transform = MEM_dupallocN(seq->strip->transform);
+ }
+
+ if (seq->strip->proxy) {
+ seqn->strip->proxy = MEM_dupallocN(seq->strip->proxy);
+ seqn->strip->proxy->anim = NULL;
+ }
+
+ if (seq->prop) {
+ seqn->prop = IDP_CopyProperty_ex(seq->prop, flag);
+ }
+
+ if (seqn->modifiers.first) {
+ BLI_listbase_clear(&seqn->modifiers);
+
+ BKE_sequence_modifier_list_copy(seqn, seq);
+ }
+
+ if (seq->type == SEQ_TYPE_META) {
+ seqn->strip->stripdata = NULL;
+
+ BLI_listbase_clear(&seqn->seqbase);
+ /* WATCH OUT!!! - This metastrip is not recursively duplicated here - do this after!!! */
+ /* - seq_dupli_recursive(&seq->seqbase, &seqn->seqbase);*/
+ }
+ else if (seq->type == SEQ_TYPE_SCENE) {
+ seqn->strip->stripdata = NULL;
+ if (seq->scene_sound)
+ seqn->scene_sound = BKE_sound_scene_add_scene_sound_defaults(scene_dst, seqn);
+ }
+ else if (seq->type == SEQ_TYPE_MOVIECLIP) {
+ /* avoid assert */
+ }
+ else if (seq->type == SEQ_TYPE_MASK) {
+ /* avoid assert */
+ }
+ else if (seq->type == SEQ_TYPE_MOVIE) {
+ seqn->strip->stripdata = MEM_dupallocN(seq->strip->stripdata);
+ BLI_listbase_clear(&seqn->anims);
+ }
+ else if (seq->type == SEQ_TYPE_SOUND_RAM) {
+ seqn->strip->stripdata = MEM_dupallocN(seq->strip->stripdata);
+ if (seq->scene_sound)
+ seqn->scene_sound = BKE_sound_add_scene_sound_defaults(scene_dst, seqn);
+
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id_us_plus((ID *)seqn->sound);
+ }
+ }
+ else if (seq->type == SEQ_TYPE_IMAGE) {
+ seqn->strip->stripdata = MEM_dupallocN(seq->strip->stripdata);
+ }
+ else if (seq->type & SEQ_TYPE_EFFECT) {
+ struct SeqEffectHandle sh;
+ sh = BKE_sequence_get_effect(seq);
+ if (sh.copy)
+ sh.copy(seq, seqn, flag);
+
+ seqn->strip->stripdata = NULL;
+ }
+ else {
+ /* sequence type not handled in duplicate! Expect a crash now... */
+ BLI_assert(0);
+ }
+
+ /* When using SEQ_DUPE_UNIQUE_NAME, it is mandatory to add new sequences in relevant container
+ * (scene or meta's one), *before* checking for unique names. Otherwise the meta's list is empty
+ * and hence we miss all seqs in that meta that have already been duplicated (see T55668).
+ * Note that unique name check itslef could be done at a later step in calling code, once all seqs
+ * have bee duplicated (that was first, simpler solution), but then handling of animation data will
+ * be broken (see T60194). */
+ if (new_seq_list != NULL) {
+ BLI_addtail(new_seq_list, seqn);
+ }
+
+ if (scene_src == scene_dst) {
+ if (dupe_flag & SEQ_DUPE_UNIQUE_NAME) {
+ BKE_sequence_base_unique_name_recursive(&scene_dst->ed->seqbase, seqn);
+ }
+
+ if (dupe_flag & SEQ_DUPE_ANIM) {
+ BKE_sequencer_dupe_animdata(scene_dst, seq->name + 2, seqn->name + 2);
+ }
+ }
+
+ return seqn;
}
static void seq_new_fix_links_recursive(Sequence *seq)
{
- SequenceModifierData *smd;
-
- if (seq->type & SEQ_TYPE_EFFECT) {
- if (seq->seq1 && seq->seq1->tmp) seq->seq1 = seq->seq1->tmp;
- if (seq->seq2 && seq->seq2->tmp) seq->seq2 = seq->seq2->tmp;
- if (seq->seq3 && seq->seq3->tmp) seq->seq3 = seq->seq3->tmp;
- }
- else if (seq->type == SEQ_TYPE_META) {
- Sequence *seqn;
- for (seqn = seq->seqbase.first; seqn; seqn = seqn->next) {
- seq_new_fix_links_recursive(seqn);
- }
- }
-
- for (smd = seq->modifiers.first; smd; smd = smd->next) {
- if (smd->mask_sequence && smd->mask_sequence->tmp)
- smd->mask_sequence = smd->mask_sequence->tmp;
- }
-}
-
-static Sequence *sequence_dupli_recursive_do(
- const Scene *scene_src, Scene *scene_dst, ListBase *new_seq_list, Sequence *seq, const int dupe_flag)
-{
- Sequence *seqn;
-
- seq->tmp = NULL;
- seqn = seq_dupli(scene_src, scene_dst, new_seq_list, seq, dupe_flag, 0);
- if (seq->type == SEQ_TYPE_META) {
- Sequence *s;
- for (s = seq->seqbase.first; s; s = s->next) {
- sequence_dupli_recursive_do(scene_src, scene_dst, &seqn->seqbase, s, dupe_flag);
- }
- }
-
- return seqn;
+ SequenceModifierData *smd;
+
+ if (seq->type & SEQ_TYPE_EFFECT) {
+ if (seq->seq1 && seq->seq1->tmp)
+ seq->seq1 = seq->seq1->tmp;
+ if (seq->seq2 && seq->seq2->tmp)
+ seq->seq2 = seq->seq2->tmp;
+ if (seq->seq3 && seq->seq3->tmp)
+ seq->seq3 = seq->seq3->tmp;
+ }
+ else if (seq->type == SEQ_TYPE_META) {
+ Sequence *seqn;
+ for (seqn = seq->seqbase.first; seqn; seqn = seqn->next) {
+ seq_new_fix_links_recursive(seqn);
+ }
+ }
+
+ for (smd = seq->modifiers.first; smd; smd = smd->next) {
+ if (smd->mask_sequence && smd->mask_sequence->tmp)
+ smd->mask_sequence = smd->mask_sequence->tmp;
+ }
+}
+
+static Sequence *sequence_dupli_recursive_do(const Scene *scene_src,
+ Scene *scene_dst,
+ ListBase *new_seq_list,
+ Sequence *seq,
+ const int dupe_flag)
+{
+ Sequence *seqn;
+
+ seq->tmp = NULL;
+ seqn = seq_dupli(scene_src, scene_dst, new_seq_list, seq, dupe_flag, 0);
+ if (seq->type == SEQ_TYPE_META) {
+ Sequence *s;
+ for (s = seq->seqbase.first; s; s = s->next) {
+ sequence_dupli_recursive_do(scene_src, scene_dst, &seqn->seqbase, s, dupe_flag);
+ }
+ }
+
+ return seqn;
}
Sequence *BKE_sequence_dupli_recursive(
- const Scene *scene_src, Scene *scene_dst,
- ListBase *new_seq_list, Sequence *seq, int dupe_flag)
-{
- Sequence *seqn = sequence_dupli_recursive_do(scene_src, scene_dst, new_seq_list, seq, dupe_flag);
-
- /* This does not need to be in recursive call itself, since it is already recursive... */
- seq_new_fix_links_recursive(seqn);
-
- return seqn;
-}
-
-void BKE_sequence_base_dupli_recursive(
- const Scene *scene_src, Scene *scene_dst, ListBase *nseqbase, const ListBase *seqbase,
- int dupe_flag, const int flag)
-{
- Sequence *seq;
- Sequence *seqn = NULL;
- Sequence *last_seq = BKE_sequencer_active_get((Scene *)scene_src);
- /* always include meta's strips */
- int dupe_flag_recursive = dupe_flag | SEQ_DUPE_ALL;
-
- for (seq = seqbase->first; seq; seq = seq->next) {
- seq->tmp = NULL;
- if ((seq->flag & SELECT) || (dupe_flag & SEQ_DUPE_ALL)) {
- seqn = seq_dupli(scene_src, scene_dst, nseqbase, seq, dupe_flag, flag);
- if (seqn) { /*should never fail */
- if (dupe_flag & SEQ_DUPE_CONTEXT) {
- seq->flag &= ~SEQ_ALLSEL;
- seqn->flag &= ~(SEQ_LEFTSEL + SEQ_RIGHTSEL + SEQ_LOCK);
- }
-
- if (seq->type == SEQ_TYPE_META) {
- BKE_sequence_base_dupli_recursive(
- scene_src, scene_dst, &seqn->seqbase, &seq->seqbase,
- dupe_flag_recursive, flag);
- }
-
- if (dupe_flag & SEQ_DUPE_CONTEXT) {
- if (seq == last_seq) {
- BKE_sequencer_active_set(scene_dst, seqn);
- }
- }
- }
- }
- }
-
- /* fix modifier linking */
- for (seq = nseqbase->first; seq; seq = seq->next) {
- seq_new_fix_links_recursive(seq);
- }
+ const Scene *scene_src, Scene *scene_dst, ListBase *new_seq_list, Sequence *seq, int dupe_flag)
+{
+ Sequence *seqn = sequence_dupli_recursive_do(scene_src, scene_dst, new_seq_list, seq, dupe_flag);
+
+ /* This does not need to be in recursive call itself, since it is already recursive... */
+ seq_new_fix_links_recursive(seqn);
+
+ return seqn;
+}
+
+void BKE_sequence_base_dupli_recursive(const Scene *scene_src,
+ Scene *scene_dst,
+ ListBase *nseqbase,
+ const ListBase *seqbase,
+ int dupe_flag,
+ const int flag)
+{
+ Sequence *seq;
+ Sequence *seqn = NULL;
+ Sequence *last_seq = BKE_sequencer_active_get((Scene *)scene_src);
+ /* always include meta's strips */
+ int dupe_flag_recursive = dupe_flag | SEQ_DUPE_ALL;
+
+ for (seq = seqbase->first; seq; seq = seq->next) {
+ seq->tmp = NULL;
+ if ((seq->flag & SELECT) || (dupe_flag & SEQ_DUPE_ALL)) {
+ seqn = seq_dupli(scene_src, scene_dst, nseqbase, seq, dupe_flag, flag);
+ if (seqn) { /*should never fail */
+ if (dupe_flag & SEQ_DUPE_CONTEXT) {
+ seq->flag &= ~SEQ_ALLSEL;
+ seqn->flag &= ~(SEQ_LEFTSEL + SEQ_RIGHTSEL + SEQ_LOCK);
+ }
+
+ if (seq->type == SEQ_TYPE_META) {
+ BKE_sequence_base_dupli_recursive(
+ scene_src, scene_dst, &seqn->seqbase, &seq->seqbase, dupe_flag_recursive, flag);
+ }
+
+ if (dupe_flag & SEQ_DUPE_CONTEXT) {
+ if (seq == last_seq) {
+ BKE_sequencer_active_set(scene_dst, seqn);
+ }
+ }
+ }
+ }
+ }
+
+ /* fix modifier linking */
+ for (seq = nseqbase->first; seq; seq = seq->next) {
+ seq_new_fix_links_recursive(seq);
+ }
}
/* called on draw, needs to be fast,
* we could cache and use a flag if we want to make checks for file paths resolving for eg. */
bool BKE_sequence_is_valid_check(Sequence *seq)
{
- switch (seq->type) {
- case SEQ_TYPE_MASK:
- return (seq->mask != NULL);
- case SEQ_TYPE_MOVIECLIP:
- return (seq->clip != NULL);
- case SEQ_TYPE_SCENE:
- return (seq->scene != NULL);
- case SEQ_TYPE_SOUND_RAM:
- return (seq->sound != NULL);
- }
+ switch (seq->type) {
+ case SEQ_TYPE_MASK:
+ return (seq->mask != NULL);
+ case SEQ_TYPE_MOVIECLIP:
+ return (seq->clip != NULL);
+ case SEQ_TYPE_SCENE:
+ return (seq->scene != NULL);
+ case SEQ_TYPE_SOUND_RAM:
+ return (seq->sound != NULL);
+ }
- return true;
+ return true;
}
-int BKE_sequencer_find_next_prev_edit(
- Scene *scene, int cfra, const short side,
- const bool do_skip_mute, const bool do_center, const bool do_unselected)
+int BKE_sequencer_find_next_prev_edit(Scene *scene,
+ int cfra,
+ const short side,
+ const bool do_skip_mute,
+ const bool do_center,
+ const bool do_unselected)
{
- Editing *ed = BKE_sequencer_editing_get(scene, false);
- Sequence *seq;
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ Sequence *seq;
- int dist, best_dist, best_frame = cfra;
- int seq_frames[2], seq_frames_tot;
+ int dist, best_dist, best_frame = cfra;
+ int seq_frames[2], seq_frames_tot;
- /* in case where both is passed, frame just finds the nearest end while frame_left the nearest start */
+ /* in case where both is passed, frame just finds the nearest end while frame_left the nearest start */
- best_dist = MAXFRAME * 2;
+ best_dist = MAXFRAME * 2;
- if (ed == NULL) return cfra;
+ if (ed == NULL)
+ return cfra;
- for (seq = ed->seqbasep->first; seq; seq = seq->next) {
- int i;
+ for (seq = ed->seqbasep->first; seq; seq = seq->next) {
+ int i;
- if (do_skip_mute && (seq->flag & SEQ_MUTE)) {
- continue;
- }
+ if (do_skip_mute && (seq->flag & SEQ_MUTE)) {
+ continue;
+ }
- if (do_unselected && (seq->flag & SELECT))
- continue;
+ if (do_unselected && (seq->flag & SELECT))
+ continue;
- if (do_center) {
- seq_frames[0] = (seq->startdisp + seq->enddisp) / 2;
- seq_frames_tot = 1;
- }
- else {
- seq_frames[0] = seq->startdisp;
- seq_frames[1] = seq->enddisp;
+ if (do_center) {
+ seq_frames[0] = (seq->startdisp + seq->enddisp) / 2;
+ seq_frames_tot = 1;
+ }
+ else {
+ seq_frames[0] = seq->startdisp;
+ seq_frames[1] = seq->enddisp;
- seq_frames_tot = 2;
- }
+ seq_frames_tot = 2;
+ }
- for (i = 0; i < seq_frames_tot; i++) {
- const int seq_frame = seq_frames[i];
+ for (i = 0; i < seq_frames_tot; i++) {
+ const int seq_frame = seq_frames[i];
- dist = MAXFRAME * 2;
+ dist = MAXFRAME * 2;
- switch (side) {
- case SEQ_SIDE_LEFT:
- if (seq_frame < cfra) {
- dist = cfra - seq_frame;
- }
- break;
- case SEQ_SIDE_RIGHT:
- if (seq_frame > cfra) {
- dist = seq_frame - cfra;
- }
- break;
- case SEQ_SIDE_BOTH:
- dist = abs(seq_frame - cfra);
- break;
- }
+ switch (side) {
+ case SEQ_SIDE_LEFT:
+ if (seq_frame < cfra) {
+ dist = cfra - seq_frame;
+ }
+ break;
+ case SEQ_SIDE_RIGHT:
+ if (seq_frame > cfra) {
+ dist = seq_frame - cfra;
+ }
+ break;
+ case SEQ_SIDE_BOTH:
+ dist = abs(seq_frame - cfra);
+ break;
+ }
- if (dist < best_dist) {
- best_frame = seq_frame;
- best_dist = dist;
- }
- }
- }
+ if (dist < best_dist) {
+ best_frame = seq_frame;
+ best_dist = dist;
+ }
+ }
+ }
- return best_frame;
+ return best_frame;
}
static void sequencer_all_free_anim_ibufs(ListBase *seqbase, int cfra)
{
- for (Sequence *seq = seqbase->first; seq != NULL; seq = seq->next) {
- if (seq->enddisp < cfra || seq->startdisp > cfra) {
- BKE_sequence_free_anim(seq);
- }
- if (seq->type == SEQ_TYPE_META) {
- sequencer_all_free_anim_ibufs(&seq->seqbase, cfra);
- }
- }
+ for (Sequence *seq = seqbase->first; seq != NULL; seq = seq->next) {
+ if (seq->enddisp < cfra || seq->startdisp > cfra) {
+ BKE_sequence_free_anim(seq);
+ }
+ if (seq->type == SEQ_TYPE_META) {
+ sequencer_all_free_anim_ibufs(&seq->seqbase, cfra);
+ }
+ }
}
void BKE_sequencer_all_free_anim_ibufs(Main *bmain, int cfra)
{
- BKE_sequencer_cache_cleanup();
- for (Scene *scene = bmain->scenes.first;
- scene != NULL;
- scene = scene->id.next)
- {
- Editing *ed = BKE_sequencer_editing_get(scene, false);
- if (ed == NULL) {
- /* Ignore scenes without sequencer. */
- continue;
- }
- sequencer_all_free_anim_ibufs(&ed->seqbase, cfra);
- }
+ BKE_sequencer_cache_cleanup();
+ for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ if (ed == NULL) {
+ /* Ignore scenes without sequencer. */
+ continue;
+ }
+ sequencer_all_free_anim_ibufs(&ed->seqbase, cfra);
+ }
}
diff --git a/source/blender/blenkernel/intern/shader_fx.c b/source/blender/blenkernel/intern/shader_fx.c
index 6bd120f64a9..98dbc3fc989 100644
--- a/source/blender/blenkernel/intern/shader_fx.c
+++ b/source/blender/blenkernel/intern/shader_fx.c
@@ -21,7 +21,6 @@
* \ingroup bke
*/
-
#include <stdio.h>
#include "MEM_guardedalloc.h"
@@ -50,7 +49,7 @@
#include "FX_shader_types.h"
-static ShaderFxTypeInfo *shader_fx_types[NUM_SHADER_FX_TYPES] = { NULL };
+static ShaderFxTypeInfo *shader_fx_types[NUM_SHADER_FX_TYPES] = {NULL};
/* *************************************************** */
/* Methods - Evaluation Loops, etc. */
@@ -58,181 +57,193 @@ static ShaderFxTypeInfo *shader_fx_types[NUM_SHADER_FX_TYPES] = { NULL };
/* check if exist grease pencil effects */
bool BKE_shaderfx_has_gpencil(Object *ob)
{
- ShaderFxData *fx;
- for (fx = ob->shader_fx.first; fx; fx = fx->next) {
- const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
- if (fxi->type == eShaderFxType_GpencilType) {
- return true;
- }
- }
- return false;
+ ShaderFxData *fx;
+ for (fx = ob->shader_fx.first; fx; fx = fx->next) {
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+ if (fxi->type == eShaderFxType_GpencilType) {
+ return true;
+ }
+ }
+ return false;
}
void BKE_shaderfx_init(void)
{
- /* Initialize shaders */
- shaderfx_type_init(shader_fx_types); /* FX_shader_util.c */
+ /* Initialize shaders */
+ shaderfx_type_init(shader_fx_types); /* FX_shader_util.c */
}
ShaderFxData *BKE_shaderfx_new(int type)
{
- const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(type);
- ShaderFxData *fx = MEM_callocN(fxi->struct_size, fxi->struct_name);
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(type);
+ ShaderFxData *fx = MEM_callocN(fxi->struct_size, fxi->struct_name);
- /* note, this name must be made unique later */
- BLI_strncpy(fx->name, DATA_(fxi->name), sizeof(fx->name));
+ /* note, this name must be made unique later */
+ BLI_strncpy(fx->name, DATA_(fxi->name), sizeof(fx->name));
- fx->type = type;
- fx->mode = eShaderFxMode_Realtime | eShaderFxMode_Render | eShaderFxMode_Expanded;
- fx->flag = eShaderFxFlag_StaticOverride_Local;
+ fx->type = type;
+ fx->mode = eShaderFxMode_Realtime | eShaderFxMode_Render | eShaderFxMode_Expanded;
+ fx->flag = eShaderFxFlag_StaticOverride_Local;
- if (fxi->flags & eShaderFxTypeFlag_EnableInEditmode)
- fx->mode |= eShaderFxMode_Editmode;
+ if (fxi->flags & eShaderFxTypeFlag_EnableInEditmode)
+ fx->mode |= eShaderFxMode_Editmode;
- if (fxi->initData) fxi->initData(fx);
+ if (fxi->initData)
+ fxi->initData(fx);
- return fx;
+ return fx;
}
-static void shaderfx_free_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag)
+static void shaderfx_free_data_id_us_cb(void *UNUSED(userData),
+ Object *UNUSED(ob),
+ ID **idpoin,
+ int cb_flag)
{
- ID *id = *idpoin;
- if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
- id_us_min(id);
- }
+ ID *id = *idpoin;
+ if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
+ id_us_min(id);
+ }
}
void BKE_shaderfx_free_ex(ShaderFxData *fx, const int flag)
{
- const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
- if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- if (fxi->foreachIDLink) {
- fxi->foreachIDLink(fx, NULL, shaderfx_free_data_id_us_cb, NULL);
- }
- else if (fxi->foreachObjectLink) {
- fxi->foreachObjectLink(fx, NULL, (ShaderFxObjectWalkFunc)shaderfx_free_data_id_us_cb, NULL);
- }
- }
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ if (fxi->foreachIDLink) {
+ fxi->foreachIDLink(fx, NULL, shaderfx_free_data_id_us_cb, NULL);
+ }
+ else if (fxi->foreachObjectLink) {
+ fxi->foreachObjectLink(fx, NULL, (ShaderFxObjectWalkFunc)shaderfx_free_data_id_us_cb, NULL);
+ }
+ }
- if (fxi->freeData) fxi->freeData(fx);
- if (fx->error) MEM_freeN(fx->error);
+ if (fxi->freeData)
+ fxi->freeData(fx);
+ if (fx->error)
+ MEM_freeN(fx->error);
- MEM_freeN(fx);
+ MEM_freeN(fx);
}
void BKE_shaderfx_free(ShaderFxData *fx)
{
- BKE_shaderfx_free_ex(fx, 0);
+ BKE_shaderfx_free_ex(fx, 0);
}
/* check unique name */
bool BKE_shaderfx_unique_name(ListBase *shaders, ShaderFxData *fx)
{
- if (shaders && fx) {
- const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
- return BLI_uniquename(shaders, fx, DATA_(fxi->name), '.', offsetof(ShaderFxData, name), sizeof(fx->name));
- }
- return false;
+ if (shaders && fx) {
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+ return BLI_uniquename(
+ shaders, fx, DATA_(fxi->name), '.', offsetof(ShaderFxData, name), sizeof(fx->name));
+ }
+ return false;
}
bool BKE_shaderfx_dependsOnTime(ShaderFxData *fx)
{
- const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
- return fxi->dependsOnTime && fxi->dependsOnTime(fx);
+ return fxi->dependsOnTime && fxi->dependsOnTime(fx);
}
const ShaderFxTypeInfo *BKE_shaderfxType_getInfo(ShaderFxType type)
{
- /* type unsigned, no need to check < 0 */
- if (type < NUM_SHADER_FX_TYPES && shader_fx_types[type]->name[0] != '\0') {
- return shader_fx_types[type];
- }
- else {
- return NULL;
- }
+ /* type unsigned, no need to check < 0 */
+ if (type < NUM_SHADER_FX_TYPES && shader_fx_types[type]->name[0] != '\0') {
+ return shader_fx_types[type];
+ }
+ else {
+ return NULL;
+ }
}
void BKE_shaderfx_copyData_generic(const ShaderFxData *fx_src, ShaderFxData *fx_dst)
{
- const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx_src->type);
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx_src->type);
- /* fx_dst may have already be fully initialized with some extra allocated data,
- * we need to free it now to avoid memleak. */
- if (fxi->freeData) {
- fxi->freeData(fx_dst);
- }
+ /* fx_dst may have already be fully initialized with some extra allocated data,
+ * we need to free it now to avoid memleak. */
+ if (fxi->freeData) {
+ fxi->freeData(fx_dst);
+ }
- const size_t data_size = sizeof(ShaderFxData);
- const char *fx_src_data = ((const char *)fx_src) + data_size;
- char *fx_dst_data = ((char *)fx_dst) + data_size;
- BLI_assert(data_size <= (size_t)fxi->struct_size);
- memcpy(fx_dst_data, fx_src_data, (size_t)fxi->struct_size - data_size);
+ const size_t data_size = sizeof(ShaderFxData);
+ const char *fx_src_data = ((const char *)fx_src) + data_size;
+ char *fx_dst_data = ((char *)fx_dst) + data_size;
+ BLI_assert(data_size <= (size_t)fxi->struct_size);
+ memcpy(fx_dst_data, fx_src_data, (size_t)fxi->struct_size - data_size);
}
-static void shaderfx_copy_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag)
+static void shaderfx_copy_data_id_us_cb(void *UNUSED(userData),
+ Object *UNUSED(ob),
+ ID **idpoin,
+ int cb_flag)
{
- ID *id = *idpoin;
- if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
- id_us_plus(id);
- }
+ ID *id = *idpoin;
+ if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
+ id_us_plus(id);
+ }
}
void BKE_shaderfx_copyData_ex(ShaderFxData *fx, ShaderFxData *target, const int flag)
{
- const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
- target->mode = fx->mode;
- target->flag = fx->flag;
+ target->mode = fx->mode;
+ target->flag = fx->flag;
- if (fxi->copyData) {
- fxi->copyData(fx, target);
- }
+ if (fxi->copyData) {
+ fxi->copyData(fx, target);
+ }
- if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- if (fxi->foreachIDLink) {
- fxi->foreachIDLink(target, NULL, shaderfx_copy_data_id_us_cb, NULL);
- }
- else if (fxi->foreachObjectLink) {
- fxi->foreachObjectLink(target, NULL, (ShaderFxObjectWalkFunc)shaderfx_copy_data_id_us_cb, NULL);
- }
- }
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ if (fxi->foreachIDLink) {
+ fxi->foreachIDLink(target, NULL, shaderfx_copy_data_id_us_cb, NULL);
+ }
+ else if (fxi->foreachObjectLink) {
+ fxi->foreachObjectLink(
+ target, NULL, (ShaderFxObjectWalkFunc)shaderfx_copy_data_id_us_cb, NULL);
+ }
+ }
}
void BKE_shaderfx_copyData(ShaderFxData *fx, ShaderFxData *target)
{
- BKE_shaderfx_copyData_ex(fx, target, 0);
+ BKE_shaderfx_copyData_ex(fx, target, 0);
}
ShaderFxData *BKE_shaderfx_findByType(Object *ob, ShaderFxType type)
{
- ShaderFxData *fx = ob->shader_fx.first;
+ ShaderFxData *fx = ob->shader_fx.first;
- for (; fx; fx = fx->next)
- if (fx->type == type)
- break;
+ for (; fx; fx = fx->next)
+ if (fx->type == type)
+ break;
- return fx;
+ return fx;
}
void BKE_shaderfx_foreachIDLink(Object *ob, ShaderFxIDWalkFunc walk, void *userData)
{
- ShaderFxData *fx = ob->shader_fx.first;
+ ShaderFxData *fx = ob->shader_fx.first;
- for (; fx; fx = fx->next) {
- const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+ for (; fx; fx = fx->next) {
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
- if (fxi->foreachIDLink) fxi->foreachIDLink(fx, ob, walk, userData);
- else if (fxi->foreachObjectLink) {
- /* each Object can masquerade as an ID, so this should be OK */
- ShaderFxObjectWalkFunc fp = (ShaderFxObjectWalkFunc)walk;
- fxi->foreachObjectLink(fx, ob, fp, userData);
- }
- }
+ if (fxi->foreachIDLink)
+ fxi->foreachIDLink(fx, ob, walk, userData);
+ else if (fxi->foreachObjectLink) {
+ /* each Object can masquerade as an ID, so this should be OK */
+ ShaderFxObjectWalkFunc fp = (ShaderFxObjectWalkFunc)walk;
+ fxi->foreachObjectLink(fx, ob, fp, userData);
+ }
+ }
}
ShaderFxData *BKE_shaderfx_findByName(Object *ob, const char *name)
{
- return BLI_findstring(&(ob->shader_fx), name, offsetof(ShaderFxData, name));
+ return BLI_findstring(&(ob->shader_fx), name, offsetof(ShaderFxData, name));
}
diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c
index 4c219fa14f2..7a9ccc66824 100644
--- a/source/blender/blenkernel/intern/shrinkwrap.c
+++ b/source/blender/blenkernel/intern/shrinkwrap.c
@@ -48,7 +48,7 @@
#include "BKE_deform.h"
#include "BKE_editmesh.h"
-#include "BKE_mesh.h" /* for OMP limits. */
+#include "BKE_mesh.h" /* for OMP limits. */
#include "BKE_subsurf.h"
#include "BKE_mesh_runtime.h"
@@ -69,261 +69,271 @@
#define OUT_OF_MEMORY() ((void)printf("Shrinkwrap: Out of memory\n"))
typedef struct ShrinkwrapCalcData {
- ShrinkwrapModifierData *smd; //shrinkwrap modifier data
+ ShrinkwrapModifierData *smd; //shrinkwrap modifier data
- struct Object *ob; //object we are applying shrinkwrap to
+ struct Object *ob; //object we are applying shrinkwrap to
- struct MVert *vert; //Array of verts being projected (to fetch normals or other data)
- float(*vertexCos)[3]; //vertexs being shrinkwraped
- int numVerts;
+ struct MVert *vert; //Array of verts being projected (to fetch normals or other data)
+ float (*vertexCos)[3]; //vertexs being shrinkwraped
+ int numVerts;
- struct MDeformVert *dvert; //Pointer to mdeform array
- int vgroup; //Vertex group num
- bool invert_vgroup; /* invert vertex group influence */
+ struct MDeformVert *dvert; //Pointer to mdeform array
+ int vgroup; //Vertex group num
+ bool invert_vgroup; /* invert vertex group influence */
- struct Mesh *target; //mesh we are shrinking to
- struct SpaceTransform local2target; //transform to move between local and target space
- struct ShrinkwrapTreeData *tree; // mesh BVH tree data
+ struct Mesh *target; //mesh we are shrinking to
+ struct SpaceTransform local2target; //transform to move between local and target space
+ struct ShrinkwrapTreeData *tree; // mesh BVH tree data
- struct Object *aux_target;
+ struct Object *aux_target;
- float keepDist; //Distance to keep above target surface (units are in local space)
+ float keepDist; //Distance to keep above target surface (units are in local space)
} ShrinkwrapCalcData;
typedef struct ShrinkwrapCalcCBData {
- ShrinkwrapCalcData *calc;
+ ShrinkwrapCalcData *calc;
- ShrinkwrapTreeData *tree;
- ShrinkwrapTreeData *aux_tree;
+ ShrinkwrapTreeData *tree;
+ ShrinkwrapTreeData *aux_tree;
- float *proj_axis;
- SpaceTransform *local2aux;
+ float *proj_axis;
+ SpaceTransform *local2aux;
} ShrinkwrapCalcCBData;
-
/* Checks if the modifier needs target normals with these settings. */
bool BKE_shrinkwrap_needs_normals(int shrinkType, int shrinkMode)
{
- return (shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) ||
- (shrinkType != MOD_SHRINKWRAP_NEAREST_VERTEX && shrinkMode == MOD_SHRINKWRAP_ABOVE_SURFACE);
+ return (shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) ||
+ (shrinkType != MOD_SHRINKWRAP_NEAREST_VERTEX &&
+ shrinkMode == MOD_SHRINKWRAP_ABOVE_SURFACE);
}
/* Initializes the mesh data structure from the given mesh and settings. */
-bool BKE_shrinkwrap_init_tree(ShrinkwrapTreeData *data, Mesh *mesh, int shrinkType, int shrinkMode, bool force_normals)
+bool BKE_shrinkwrap_init_tree(
+ ShrinkwrapTreeData *data, Mesh *mesh, int shrinkType, int shrinkMode, bool force_normals)
{
- memset(data, 0, sizeof(*data));
+ memset(data, 0, sizeof(*data));
- if (!mesh || mesh->totvert <= 0) {
- return false;
- }
+ if (!mesh || mesh->totvert <= 0) {
+ return false;
+ }
- data->mesh = mesh;
+ data->mesh = mesh;
- if (shrinkType == MOD_SHRINKWRAP_NEAREST_VERTEX) {
- data->bvh = BKE_bvhtree_from_mesh_get(&data->treeData, mesh, BVHTREE_FROM_VERTS, 2);
+ if (shrinkType == MOD_SHRINKWRAP_NEAREST_VERTEX) {
+ data->bvh = BKE_bvhtree_from_mesh_get(&data->treeData, mesh, BVHTREE_FROM_VERTS, 2);
- return data->bvh != NULL;
- }
- else {
- if (mesh->totpoly <= 0) {
- return false;
- }
+ return data->bvh != NULL;
+ }
+ else {
+ if (mesh->totpoly <= 0) {
+ return false;
+ }
- data->bvh = BKE_bvhtree_from_mesh_get(&data->treeData, mesh, BVHTREE_FROM_LOOPTRI, 4);
+ data->bvh = BKE_bvhtree_from_mesh_get(&data->treeData, mesh, BVHTREE_FROM_LOOPTRI, 4);
- if (data->bvh == NULL) {
- return false;
- }
+ if (data->bvh == NULL) {
+ return false;
+ }
- if (force_normals || BKE_shrinkwrap_needs_normals(shrinkType, shrinkMode)) {
- data->pnors = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
- if ((mesh->flag & ME_AUTOSMOOTH) != 0) {
- data->clnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
- }
- }
+ if (force_normals || BKE_shrinkwrap_needs_normals(shrinkType, shrinkMode)) {
+ data->pnors = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
+ if ((mesh->flag & ME_AUTOSMOOTH) != 0) {
+ data->clnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
+ }
+ }
- if (shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) {
- data->boundary = mesh->runtime.shrinkwrap_data;
- }
+ if (shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) {
+ data->boundary = mesh->runtime.shrinkwrap_data;
+ }
- return true;
- }
+ return true;
+ }
}
/* Frees the tree data if necessary. */
void BKE_shrinkwrap_free_tree(ShrinkwrapTreeData *data)
{
- free_bvhtree_from_mesh(&data->treeData);
+ free_bvhtree_from_mesh(&data->treeData);
}
/* Free boundary data for target project */
void BKE_shrinkwrap_discard_boundary_data(struct Mesh *mesh)
{
- struct ShrinkwrapBoundaryData *data = mesh->runtime.shrinkwrap_data;
+ struct ShrinkwrapBoundaryData *data = mesh->runtime.shrinkwrap_data;
- if (data != NULL) {
- MEM_freeN((void *)data->edge_is_boundary);
- MEM_freeN((void *)data->looptri_has_boundary);
- MEM_freeN((void *)data->vert_boundary_id);
- MEM_freeN((void *)data->boundary_verts);
+ if (data != NULL) {
+ MEM_freeN((void *)data->edge_is_boundary);
+ MEM_freeN((void *)data->looptri_has_boundary);
+ MEM_freeN((void *)data->vert_boundary_id);
+ MEM_freeN((void *)data->boundary_verts);
- MEM_freeN(data);
- }
+ MEM_freeN(data);
+ }
- mesh->runtime.shrinkwrap_data = NULL;
+ mesh->runtime.shrinkwrap_data = NULL;
}
/* Accumulate edge for average boundary edge direction. */
-static void merge_vert_dir(ShrinkwrapBoundaryVertData *vdata, signed char *status, int index, const float edge_dir[3], signed char side)
+static void merge_vert_dir(ShrinkwrapBoundaryVertData *vdata,
+ signed char *status,
+ int index,
+ const float edge_dir[3],
+ signed char side)
{
- BLI_assert(index >= 0);
- float *direction = vdata[index].direction;
-
- /* Invert the direction vector if either:
- * - This is the second edge and both edges have the vertex as start or end.
- * - For third and above, if it points in the wrong direction.
- */
- if (status[index] >= 0 ? status[index] == side : dot_v3v3(direction, edge_dir) < 0) {
- sub_v3_v3(direction, edge_dir);
- }
- else {
- add_v3_v3(direction, edge_dir);
- }
-
- status[index] = (status[index] == 0) ? side : -1;
+ BLI_assert(index >= 0);
+ float *direction = vdata[index].direction;
+
+ /* Invert the direction vector if either:
+ * - This is the second edge and both edges have the vertex as start or end.
+ * - For third and above, if it points in the wrong direction.
+ */
+ if (status[index] >= 0 ? status[index] == side : dot_v3v3(direction, edge_dir) < 0) {
+ sub_v3_v3(direction, edge_dir);
+ }
+ else {
+ add_v3_v3(direction, edge_dir);
+ }
+
+ status[index] = (status[index] == 0) ? side : -1;
}
static ShrinkwrapBoundaryData *shrinkwrap_build_boundary_data(struct Mesh *mesh)
{
- const MLoop *mloop = mesh->mloop;
- const MEdge *medge = mesh->medge;
- const MVert *mvert = mesh->mvert;
+ const MLoop *mloop = mesh->mloop;
+ const MEdge *medge = mesh->medge;
+ const MVert *mvert = mesh->mvert;
- /* Count faces per edge (up to 2). */
- char *edge_mode = MEM_calloc_arrayN((size_t)mesh->totedge, sizeof(char), __func__);
+ /* Count faces per edge (up to 2). */
+ char *edge_mode = MEM_calloc_arrayN((size_t)mesh->totedge, sizeof(char), __func__);
- for (int i = 0; i < mesh->totloop; i++) {
- unsigned int eidx = mloop[i].e;
+ for (int i = 0; i < mesh->totloop; i++) {
+ unsigned int eidx = mloop[i].e;
- if (edge_mode[eidx] < 2) {
- edge_mode[eidx]++;
- }
- }
+ if (edge_mode[eidx] < 2) {
+ edge_mode[eidx]++;
+ }
+ }
- /* Build the boundary edge bitmask. */
- BLI_bitmap *edge_is_boundary = BLI_BITMAP_NEW(mesh->totedge, "ShrinkwrapBoundaryData::edge_is_boundary");
- unsigned int num_boundary_edges = 0;
+ /* Build the boundary edge bitmask. */
+ BLI_bitmap *edge_is_boundary = BLI_BITMAP_NEW(mesh->totedge,
+ "ShrinkwrapBoundaryData::edge_is_boundary");
+ unsigned int num_boundary_edges = 0;
- for (int i = 0; i < mesh->totedge; i++) {
- edge_mode[i] = (edge_mode[i] == 1);
+ for (int i = 0; i < mesh->totedge; i++) {
+ edge_mode[i] = (edge_mode[i] == 1);
- if (edge_mode[i]) {
- BLI_BITMAP_ENABLE(edge_is_boundary, i);
- num_boundary_edges++;
- }
- }
+ if (edge_mode[i]) {
+ BLI_BITMAP_ENABLE(edge_is_boundary, i);
+ num_boundary_edges++;
+ }
+ }
- /* If no boundary, return NULL. */
- if (num_boundary_edges == 0) {
- MEM_freeN(edge_is_boundary);
- MEM_freeN(edge_mode);
- return NULL;
- }
+ /* If no boundary, return NULL. */
+ if (num_boundary_edges == 0) {
+ MEM_freeN(edge_is_boundary);
+ MEM_freeN(edge_mode);
+ return NULL;
+ }
- /* Allocate the data object. */
- ShrinkwrapBoundaryData *data = MEM_callocN(sizeof(ShrinkwrapBoundaryData), "ShrinkwrapBoundaryData");
+ /* Allocate the data object. */
+ ShrinkwrapBoundaryData *data = MEM_callocN(sizeof(ShrinkwrapBoundaryData),
+ "ShrinkwrapBoundaryData");
- data->edge_is_boundary = edge_is_boundary;
+ data->edge_is_boundary = edge_is_boundary;
- /* Build the boundary looptri bitmask. */
- const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
- int totlooptri = BKE_mesh_runtime_looptri_len(mesh);
+ /* Build the boundary looptri bitmask. */
+ const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ int totlooptri = BKE_mesh_runtime_looptri_len(mesh);
- BLI_bitmap *looptri_has_boundary = BLI_BITMAP_NEW(totlooptri, "ShrinkwrapBoundaryData::looptri_is_boundary");
+ BLI_bitmap *looptri_has_boundary = BLI_BITMAP_NEW(totlooptri,
+ "ShrinkwrapBoundaryData::looptri_is_boundary");
- for (int i = 0; i < totlooptri; i++) {
- int edges[3];
- BKE_mesh_looptri_get_real_edges(mesh, &mlooptri[i], edges);
+ for (int i = 0; i < totlooptri; i++) {
+ int edges[3];
+ BKE_mesh_looptri_get_real_edges(mesh, &mlooptri[i], edges);
- for (int j = 0; j < 3; j++) {
- if (edges[j] >= 0 && edge_mode[edges[j]]) {
- BLI_BITMAP_ENABLE(looptri_has_boundary, i);
- break;
- }
- }
- }
+ for (int j = 0; j < 3; j++) {
+ if (edges[j] >= 0 && edge_mode[edges[j]]) {
+ BLI_BITMAP_ENABLE(looptri_has_boundary, i);
+ break;
+ }
+ }
+ }
- data->looptri_has_boundary = looptri_has_boundary;
+ data->looptri_has_boundary = looptri_has_boundary;
- /* Find boundary vertices and build a mapping table for compact storage of data. */
- int *vert_boundary_id = MEM_calloc_arrayN((size_t)mesh->totvert, sizeof(int), "ShrinkwrapBoundaryData::vert_boundary_id");
+ /* Find boundary vertices and build a mapping table for compact storage of data. */
+ int *vert_boundary_id = MEM_calloc_arrayN(
+ (size_t)mesh->totvert, sizeof(int), "ShrinkwrapBoundaryData::vert_boundary_id");
- for (int i = 0; i < mesh->totedge; i++) {
- if (edge_mode[i]) {
- const MEdge *edge = &medge[i];
+ for (int i = 0; i < mesh->totedge; i++) {
+ if (edge_mode[i]) {
+ const MEdge *edge = &medge[i];
- vert_boundary_id[edge->v1] = 1;
- vert_boundary_id[edge->v2] = 1;
- }
- }
+ vert_boundary_id[edge->v1] = 1;
+ vert_boundary_id[edge->v2] = 1;
+ }
+ }
- unsigned int num_boundary_verts = 0;
+ unsigned int num_boundary_verts = 0;
- for (int i = 0; i < mesh->totvert; i++) {
- vert_boundary_id[i] = (vert_boundary_id[i] != 0) ? (int)num_boundary_verts++ : -1;
- }
+ for (int i = 0; i < mesh->totvert; i++) {
+ vert_boundary_id[i] = (vert_boundary_id[i] != 0) ? (int)num_boundary_verts++ : -1;
+ }
- data->vert_boundary_id = vert_boundary_id;
- data->num_boundary_verts = num_boundary_verts;
+ data->vert_boundary_id = vert_boundary_id;
+ data->num_boundary_verts = num_boundary_verts;
- /* Compute average directions. */
- ShrinkwrapBoundaryVertData *boundary_verts = MEM_calloc_arrayN(num_boundary_verts, sizeof(*boundary_verts), "ShrinkwrapBoundaryData::boundary_verts");
+ /* Compute average directions. */
+ ShrinkwrapBoundaryVertData *boundary_verts = MEM_calloc_arrayN(
+ num_boundary_verts, sizeof(*boundary_verts), "ShrinkwrapBoundaryData::boundary_verts");
- signed char *vert_status = MEM_calloc_arrayN(num_boundary_verts, sizeof(char), __func__);
+ signed char *vert_status = MEM_calloc_arrayN(num_boundary_verts, sizeof(char), __func__);
- for (int i = 0; i < mesh->totedge; i++) {
- if (edge_mode[i]) {
- const MEdge *edge = &medge[i];
+ for (int i = 0; i < mesh->totedge; i++) {
+ if (edge_mode[i]) {
+ const MEdge *edge = &medge[i];
- float dir[3];
- sub_v3_v3v3(dir, mvert[edge->v2].co, mvert[edge->v1].co);
- normalize_v3(dir);
+ float dir[3];
+ sub_v3_v3v3(dir, mvert[edge->v2].co, mvert[edge->v1].co);
+ normalize_v3(dir);
- merge_vert_dir(boundary_verts, vert_status, vert_boundary_id[edge->v1], dir, 1);
- merge_vert_dir(boundary_verts, vert_status, vert_boundary_id[edge->v2], dir, 2);
- }
- }
+ merge_vert_dir(boundary_verts, vert_status, vert_boundary_id[edge->v1], dir, 1);
+ merge_vert_dir(boundary_verts, vert_status, vert_boundary_id[edge->v2], dir, 2);
+ }
+ }
- MEM_freeN(vert_status);
+ MEM_freeN(vert_status);
- /* Finalize average direction and compute normal. */
- for (int i = 0; i < mesh->totvert; i++) {
- int bidx = vert_boundary_id[i];
+ /* Finalize average direction and compute normal. */
+ for (int i = 0; i < mesh->totvert; i++) {
+ int bidx = vert_boundary_id[i];
- if (bidx >= 0) {
- ShrinkwrapBoundaryVertData *vdata = &boundary_verts[bidx];
- float no[3], tmp[3];
+ if (bidx >= 0) {
+ ShrinkwrapBoundaryVertData *vdata = &boundary_verts[bidx];
+ float no[3], tmp[3];
- normalize_v3(vdata->direction);
+ normalize_v3(vdata->direction);
- normal_short_to_float_v3(no, mesh->mvert[i].no);
- cross_v3_v3v3(tmp, no, vdata->direction);
- cross_v3_v3v3(vdata->normal_plane, tmp, no);
- normalize_v3(vdata->normal_plane);
- }
- }
+ normal_short_to_float_v3(no, mesh->mvert[i].no);
+ cross_v3_v3v3(tmp, no, vdata->direction);
+ cross_v3_v3v3(vdata->normal_plane, tmp, no);
+ normalize_v3(vdata->normal_plane);
+ }
+ }
- data->boundary_verts = boundary_verts;
+ data->boundary_verts = boundary_verts;
- MEM_freeN(edge_mode);
- return data;
+ MEM_freeN(edge_mode);
+ return data;
}
void BKE_shrinkwrap_compute_boundary_data(struct Mesh *mesh)
{
- BKE_shrinkwrap_discard_boundary_data(mesh);
+ BKE_shrinkwrap_discard_boundary_data(mesh);
- mesh->runtime.shrinkwrap_data = shrinkwrap_build_boundary_data(mesh);
+ mesh->runtime.shrinkwrap_data = shrinkwrap_build_boundary_data(mesh);
}
/*
@@ -332,88 +342,87 @@ void BKE_shrinkwrap_compute_boundary_data(struct Mesh *mesh)
* it builds a kdtree of vertexs we can attach to and then
* for each vertex performs a nearest vertex search on the tree
*/
-static void shrinkwrap_calc_nearest_vertex_cb_ex(
- void *__restrict userdata,
- const int i,
- const ParallelRangeTLS *__restrict tls)
+static void shrinkwrap_calc_nearest_vertex_cb_ex(void *__restrict userdata,
+ const int i,
+ const ParallelRangeTLS *__restrict tls)
{
- ShrinkwrapCalcCBData *data = userdata;
-
- ShrinkwrapCalcData *calc = data->calc;
- BVHTreeFromMesh *treeData = &data->tree->treeData;
- BVHTreeNearest *nearest = tls->userdata_chunk;
-
- float *co = calc->vertexCos[i];
- float tmp_co[3];
- float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup);
-
- if (calc->invert_vgroup) {
- weight = 1.0f - weight;
- }
-
- if (weight == 0.0f) {
- return;
- }
-
- /* Convert the vertex to tree coordinates */
- if (calc->vert) {
- copy_v3_v3(tmp_co, calc->vert[i].co);
- }
- else {
- copy_v3_v3(tmp_co, co);
- }
- BLI_space_transform_apply(&calc->local2target, tmp_co);
-
- /* Use local proximity heuristics (to reduce the nearest search)
- *
- * If we already had an hit before.. we assume this vertex is going to have a close hit to that other vertex
- * so we can initiate the "nearest.dist" with the expected value to that last hit.
- * This will lead in pruning of the search tree. */
- if (nearest->index != -1)
- nearest->dist_sq = len_squared_v3v3(tmp_co, nearest->co);
- else
- nearest->dist_sq = FLT_MAX;
-
- BLI_bvhtree_find_nearest(treeData->tree, tmp_co, nearest, treeData->nearest_callback, treeData);
-
-
- /* Found the nearest vertex */
- if (nearest->index != -1) {
- /* Adjusting the vertex weight,
- * so that after interpolating it keeps a certain distance from the nearest position */
- if (nearest->dist_sq > FLT_EPSILON) {
- const float dist = sqrtf(nearest->dist_sq);
- weight *= (dist - calc->keepDist) / dist;
- }
-
- /* Convert the coordinates back to mesh coordinates */
- copy_v3_v3(tmp_co, nearest->co);
- BLI_space_transform_invert(&calc->local2target, tmp_co);
-
- interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */
- }
+ ShrinkwrapCalcCBData *data = userdata;
+
+ ShrinkwrapCalcData *calc = data->calc;
+ BVHTreeFromMesh *treeData = &data->tree->treeData;
+ BVHTreeNearest *nearest = tls->userdata_chunk;
+
+ float *co = calc->vertexCos[i];
+ float tmp_co[3];
+ float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup);
+
+ if (calc->invert_vgroup) {
+ weight = 1.0f - weight;
+ }
+
+ if (weight == 0.0f) {
+ return;
+ }
+
+ /* Convert the vertex to tree coordinates */
+ if (calc->vert) {
+ copy_v3_v3(tmp_co, calc->vert[i].co);
+ }
+ else {
+ copy_v3_v3(tmp_co, co);
+ }
+ BLI_space_transform_apply(&calc->local2target, tmp_co);
+
+ /* Use local proximity heuristics (to reduce the nearest search)
+ *
+ * If we already had an hit before.. we assume this vertex is going to have a close hit to that other vertex
+ * so we can initiate the "nearest.dist" with the expected value to that last hit.
+ * This will lead in pruning of the search tree. */
+ if (nearest->index != -1)
+ nearest->dist_sq = len_squared_v3v3(tmp_co, nearest->co);
+ else
+ nearest->dist_sq = FLT_MAX;
+
+ BLI_bvhtree_find_nearest(treeData->tree, tmp_co, nearest, treeData->nearest_callback, treeData);
+
+ /* Found the nearest vertex */
+ if (nearest->index != -1) {
+ /* Adjusting the vertex weight,
+ * so that after interpolating it keeps a certain distance from the nearest position */
+ if (nearest->dist_sq > FLT_EPSILON) {
+ const float dist = sqrtf(nearest->dist_sq);
+ weight *= (dist - calc->keepDist) / dist;
+ }
+
+ /* Convert the coordinates back to mesh coordinates */
+ copy_v3_v3(tmp_co, nearest->co);
+ BLI_space_transform_invert(&calc->local2target, tmp_co);
+
+ interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */
+ }
}
static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
{
- BVHTreeNearest nearest = NULL_BVHTreeNearest;
-
- /* Setup nearest */
- nearest.index = -1;
- nearest.dist_sq = FLT_MAX;
-
- ShrinkwrapCalcCBData data = { .calc = calc, .tree = calc->tree, };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT);
- settings.userdata_chunk = &nearest;
- settings.userdata_chunk_size = sizeof(nearest);
- BLI_task_parallel_range(0, calc->numVerts,
- &data, shrinkwrap_calc_nearest_vertex_cb_ex,
- &settings);
+ BVHTreeNearest nearest = NULL_BVHTreeNearest;
+
+ /* Setup nearest */
+ nearest.index = -1;
+ nearest.dist_sq = FLT_MAX;
+
+ ShrinkwrapCalcCBData data = {
+ .calc = calc,
+ .tree = calc->tree,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT);
+ settings.userdata_chunk = &nearest;
+ settings.userdata_chunk_size = sizeof(nearest);
+ BLI_task_parallel_range(
+ 0, calc->numVerts, &data, shrinkwrap_calc_nearest_vertex_cb_ex, &settings);
}
-
/*
* This function raycast a single vertex and updates the hit if the "hit" is considered valid.
* Returns true if "hit" was updated.
@@ -422,267 +431,280 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
* - MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE (front faces hits are ignored)
* - MOD_SHRINKWRAP_CULL_TARGET_BACKFACE (back faces hits are ignored)
*/
-bool BKE_shrinkwrap_project_normal(
- char options, const float vert[3], const float dir[3],
- const float ray_radius, const SpaceTransform *transf,
- ShrinkwrapTreeData *tree, BVHTreeRayHit *hit)
+bool BKE_shrinkwrap_project_normal(char options,
+ const float vert[3],
+ const float dir[3],
+ const float ray_radius,
+ const SpaceTransform *transf,
+ ShrinkwrapTreeData *tree,
+ BVHTreeRayHit *hit)
{
- /* don't use this because this dist value could be incompatible
- * this value used by the callback for comparing prev/new dist values.
- * also, at the moment there is no need to have a corrected 'dist' value */
-// #define USE_DIST_CORRECT
+ /* don't use this because this dist value could be incompatible
+ * this value used by the callback for comparing prev/new dist values.
+ * also, at the moment there is no need to have a corrected 'dist' value */
+ // #define USE_DIST_CORRECT
- float tmp_co[3], tmp_no[3];
- const float *co, *no;
- BVHTreeRayHit hit_tmp;
+ float tmp_co[3], tmp_no[3];
+ const float *co, *no;
+ BVHTreeRayHit hit_tmp;
- /* Copy from hit (we need to convert hit rays from one space coordinates to the other */
- memcpy(&hit_tmp, hit, sizeof(hit_tmp));
+ /* Copy from hit (we need to convert hit rays from one space coordinates to the other */
+ memcpy(&hit_tmp, hit, sizeof(hit_tmp));
- /* Apply space transform (TODO readjust dist) */
- if (transf) {
- copy_v3_v3(tmp_co, vert);
- BLI_space_transform_apply(transf, tmp_co);
- co = tmp_co;
+ /* Apply space transform (TODO readjust dist) */
+ if (transf) {
+ copy_v3_v3(tmp_co, vert);
+ BLI_space_transform_apply(transf, tmp_co);
+ co = tmp_co;
- copy_v3_v3(tmp_no, dir);
- BLI_space_transform_apply_normal(transf, tmp_no);
- no = tmp_no;
+ copy_v3_v3(tmp_no, dir);
+ BLI_space_transform_apply_normal(transf, tmp_no);
+ no = tmp_no;
#ifdef USE_DIST_CORRECT
- hit_tmp.dist *= mat4_to_scale(((SpaceTransform *)transf)->local2target);
+ hit_tmp.dist *= mat4_to_scale(((SpaceTransform *)transf)->local2target);
#endif
- }
- else {
- co = vert;
- no = dir;
- }
-
- hit_tmp.index = -1;
-
- BLI_bvhtree_ray_cast(tree->bvh, co, no, ray_radius, &hit_tmp, tree->treeData.raycast_callback, &tree->treeData);
-
- if (hit_tmp.index != -1) {
- /* invert the normal first so face culling works on rotated objects */
- if (transf) {
- BLI_space_transform_invert_normal(transf, hit_tmp.no);
- }
-
- if (options & MOD_SHRINKWRAP_CULL_TARGET_MASK) {
- /* apply backface */
- const float dot = dot_v3v3(dir, hit_tmp.no);
- if (((options & MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE) && dot <= 0.0f) ||
- ((options & MOD_SHRINKWRAP_CULL_TARGET_BACKFACE) && dot >= 0.0f))
- {
- return false; /* Ignore hit */
- }
- }
-
- if (transf) {
- /* Inverting space transform (TODO make coeherent with the initial dist readjust) */
- BLI_space_transform_invert(transf, hit_tmp.co);
+ }
+ else {
+ co = vert;
+ no = dir;
+ }
+
+ hit_tmp.index = -1;
+
+ BLI_bvhtree_ray_cast(
+ tree->bvh, co, no, ray_radius, &hit_tmp, tree->treeData.raycast_callback, &tree->treeData);
+
+ if (hit_tmp.index != -1) {
+ /* invert the normal first so face culling works on rotated objects */
+ if (transf) {
+ BLI_space_transform_invert_normal(transf, hit_tmp.no);
+ }
+
+ if (options & MOD_SHRINKWRAP_CULL_TARGET_MASK) {
+ /* apply backface */
+ const float dot = dot_v3v3(dir, hit_tmp.no);
+ if (((options & MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE) && dot <= 0.0f) ||
+ ((options & MOD_SHRINKWRAP_CULL_TARGET_BACKFACE) && dot >= 0.0f)) {
+ return false; /* Ignore hit */
+ }
+ }
+
+ if (transf) {
+ /* Inverting space transform (TODO make coeherent with the initial dist readjust) */
+ BLI_space_transform_invert(transf, hit_tmp.co);
#ifdef USE_DIST_CORRECT
- hit_tmp.dist = len_v3v3(vert, hit_tmp.co);
+ hit_tmp.dist = len_v3v3(vert, hit_tmp.co);
#endif
- }
+ }
- BLI_assert(hit_tmp.dist <= hit->dist);
+ BLI_assert(hit_tmp.dist <= hit->dist);
- memcpy(hit, &hit_tmp, sizeof(hit_tmp));
- return true;
- }
- return false;
+ memcpy(hit, &hit_tmp, sizeof(hit_tmp));
+ return true;
+ }
+ return false;
}
-static void shrinkwrap_calc_normal_projection_cb_ex(
- void *__restrict userdata,
- const int i,
- const ParallelRangeTLS *__restrict tls)
+static void shrinkwrap_calc_normal_projection_cb_ex(void *__restrict userdata,
+ const int i,
+ const ParallelRangeTLS *__restrict tls)
{
- ShrinkwrapCalcCBData *data = userdata;
-
- ShrinkwrapCalcData *calc = data->calc;
- ShrinkwrapTreeData *tree = data->tree;
- ShrinkwrapTreeData *aux_tree = data->aux_tree;
-
- float *proj_axis = data->proj_axis;
- SpaceTransform *local2aux = data->local2aux;
-
- BVHTreeRayHit *hit = tls->userdata_chunk;
-
- const float proj_limit_squared = calc->smd->projLimit * calc->smd->projLimit;
- float *co = calc->vertexCos[i];
- float tmp_co[3], tmp_no[3];
- float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup);
-
- if (calc->invert_vgroup) {
- weight = 1.0f - weight;
- }
-
- if (weight == 0.0f) {
- return;
- }
-
- if (calc->vert != NULL && calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) {
- /* calc->vert contains verts from evaluated mesh. */
- /* These coordinates are deformed by vertexCos only for normal projection (to get correct normals) */
- /* for other cases calc->verts contains undeformed coordinates and vertexCos should be used */
- copy_v3_v3(tmp_co, calc->vert[i].co);
- normal_short_to_float_v3(tmp_no, calc->vert[i].no);
- }
- else {
- copy_v3_v3(tmp_co, co);
- copy_v3_v3(tmp_no, proj_axis);
- }
-
- hit->index = -1;
- hit->dist = BVH_RAYCAST_DIST_MAX; /* TODO: we should use FLT_MAX here, but sweepsphere code isn't prepared for that */
-
- bool is_aux = false;
-
- /* Project over positive direction of axis */
- if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR) {
- if (aux_tree) {
- if (BKE_shrinkwrap_project_normal(
- 0, tmp_co, tmp_no, 0.0,
- local2aux, aux_tree, hit))
- {
- is_aux = true;
- }
- }
-
- if (BKE_shrinkwrap_project_normal(
- calc->smd->shrinkOpts, tmp_co, tmp_no, 0.0,
- &calc->local2target, tree, hit))
- {
- is_aux = false;
- }
- }
-
- /* Project over negative direction of axis */
- if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR) {
- float inv_no[3];
- negate_v3_v3(inv_no, tmp_no);
-
- char options = calc->smd->shrinkOpts;
-
- if ((options & MOD_SHRINKWRAP_INVERT_CULL_TARGET) && (options & MOD_SHRINKWRAP_CULL_TARGET_MASK)) {
- options ^= MOD_SHRINKWRAP_CULL_TARGET_MASK;
- }
-
- if (aux_tree) {
- if (BKE_shrinkwrap_project_normal(
- 0, tmp_co, inv_no, 0.0,
- local2aux, aux_tree, hit))
- {
- is_aux = true;
- }
- }
-
- if (BKE_shrinkwrap_project_normal(
- options, tmp_co, inv_no, 0.0,
- &calc->local2target, tree, hit))
- {
- is_aux = false;
- }
- }
-
- /* don't set the initial dist (which is more efficient),
- * because its calculated in the targets space, we want the dist in our own space */
- if (proj_limit_squared != 0.0f) {
- if (hit->index != -1 && len_squared_v3v3(hit->co, co) > proj_limit_squared) {
- hit->index = -1;
- }
- }
-
- if (hit->index != -1) {
- if (is_aux) {
- BKE_shrinkwrap_snap_point_to_surface(
- aux_tree, local2aux, calc->smd->shrinkMode,
- hit->index, hit->co, hit->no, calc->keepDist, tmp_co, hit->co);
- }
- else {
- BKE_shrinkwrap_snap_point_to_surface(
- tree, &calc->local2target, calc->smd->shrinkMode,
- hit->index, hit->co, hit->no, calc->keepDist, tmp_co, hit->co);
- }
-
- interp_v3_v3v3(co, co, hit->co, weight);
- }
+ ShrinkwrapCalcCBData *data = userdata;
+
+ ShrinkwrapCalcData *calc = data->calc;
+ ShrinkwrapTreeData *tree = data->tree;
+ ShrinkwrapTreeData *aux_tree = data->aux_tree;
+
+ float *proj_axis = data->proj_axis;
+ SpaceTransform *local2aux = data->local2aux;
+
+ BVHTreeRayHit *hit = tls->userdata_chunk;
+
+ const float proj_limit_squared = calc->smd->projLimit * calc->smd->projLimit;
+ float *co = calc->vertexCos[i];
+ float tmp_co[3], tmp_no[3];
+ float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup);
+
+ if (calc->invert_vgroup) {
+ weight = 1.0f - weight;
+ }
+
+ if (weight == 0.0f) {
+ return;
+ }
+
+ if (calc->vert != NULL && calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) {
+ /* calc->vert contains verts from evaluated mesh. */
+ /* These coordinates are deformed by vertexCos only for normal projection (to get correct normals) */
+ /* for other cases calc->verts contains undeformed coordinates and vertexCos should be used */
+ copy_v3_v3(tmp_co, calc->vert[i].co);
+ normal_short_to_float_v3(tmp_no, calc->vert[i].no);
+ }
+ else {
+ copy_v3_v3(tmp_co, co);
+ copy_v3_v3(tmp_no, proj_axis);
+ }
+
+ hit->index = -1;
+ hit->dist =
+ BVH_RAYCAST_DIST_MAX; /* TODO: we should use FLT_MAX here, but sweepsphere code isn't prepared for that */
+
+ bool is_aux = false;
+
+ /* Project over positive direction of axis */
+ if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR) {
+ if (aux_tree) {
+ if (BKE_shrinkwrap_project_normal(0, tmp_co, tmp_no, 0.0, local2aux, aux_tree, hit)) {
+ is_aux = true;
+ }
+ }
+
+ if (BKE_shrinkwrap_project_normal(
+ calc->smd->shrinkOpts, tmp_co, tmp_no, 0.0, &calc->local2target, tree, hit)) {
+ is_aux = false;
+ }
+ }
+
+ /* Project over negative direction of axis */
+ if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR) {
+ float inv_no[3];
+ negate_v3_v3(inv_no, tmp_no);
+
+ char options = calc->smd->shrinkOpts;
+
+ if ((options & MOD_SHRINKWRAP_INVERT_CULL_TARGET) &&
+ (options & MOD_SHRINKWRAP_CULL_TARGET_MASK)) {
+ options ^= MOD_SHRINKWRAP_CULL_TARGET_MASK;
+ }
+
+ if (aux_tree) {
+ if (BKE_shrinkwrap_project_normal(0, tmp_co, inv_no, 0.0, local2aux, aux_tree, hit)) {
+ is_aux = true;
+ }
+ }
+
+ if (BKE_shrinkwrap_project_normal(
+ options, tmp_co, inv_no, 0.0, &calc->local2target, tree, hit)) {
+ is_aux = false;
+ }
+ }
+
+ /* don't set the initial dist (which is more efficient),
+ * because its calculated in the targets space, we want the dist in our own space */
+ if (proj_limit_squared != 0.0f) {
+ if (hit->index != -1 && len_squared_v3v3(hit->co, co) > proj_limit_squared) {
+ hit->index = -1;
+ }
+ }
+
+ if (hit->index != -1) {
+ if (is_aux) {
+ BKE_shrinkwrap_snap_point_to_surface(aux_tree,
+ local2aux,
+ calc->smd->shrinkMode,
+ hit->index,
+ hit->co,
+ hit->no,
+ calc->keepDist,
+ tmp_co,
+ hit->co);
+ }
+ else {
+ BKE_shrinkwrap_snap_point_to_surface(tree,
+ &calc->local2target,
+ calc->smd->shrinkMode,
+ hit->index,
+ hit->co,
+ hit->no,
+ calc->keepDist,
+ tmp_co,
+ hit->co);
+ }
+
+ interp_v3_v3v3(co, co, hit->co, weight);
+ }
}
static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc)
{
- /* Options about projection direction */
- float proj_axis[3] = {0.0f, 0.0f, 0.0f};
-
- /* Raycast and tree stuff */
-
- /** \note 'hit.dist' is kept in the targets space, this is only used
- * for finding the best hit, to get the real dist,
- * measure the len_v3v3() from the input coord to hit.co */
- BVHTreeRayHit hit;
-
- /* auxiliary target */
- Mesh *auxMesh = NULL;
- ShrinkwrapTreeData *aux_tree = NULL;
- ShrinkwrapTreeData aux_tree_stack;
- SpaceTransform local2aux;
-
- /* If the user doesn't allows to project in any direction of projection axis
- * then there's nothing todo. */
- if ((calc->smd->shrinkOpts & (MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR | MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR)) == 0)
- return;
-
- /* Prepare data to retrieve the direction in which we should project each vertex */
- if (calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) {
- if (calc->vert == NULL) return;
- }
- else {
- /* The code supports any axis that is a combination of X,Y,Z
- * although currently UI only allows to set the 3 different axis */
- if (calc->smd->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS) proj_axis[0] = 1.0f;
- if (calc->smd->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS) proj_axis[1] = 1.0f;
- if (calc->smd->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS) proj_axis[2] = 1.0f;
-
- normalize_v3(proj_axis);
-
- /* Invalid projection direction */
- if (len_squared_v3(proj_axis) < FLT_EPSILON) {
- return;
- }
- }
-
- if (calc->aux_target) {
- auxMesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(calc->aux_target, false);
- if (!auxMesh)
- return;
- BLI_SPACE_TRANSFORM_SETUP(&local2aux, calc->ob, calc->aux_target);
- }
-
- if (BKE_shrinkwrap_init_tree(&aux_tree_stack, auxMesh, calc->smd->shrinkType, calc->smd->shrinkMode, false)) {
- aux_tree = &aux_tree_stack;
- }
-
- /* After successfully build the trees, start projection vertices. */
- ShrinkwrapCalcCBData data = {
- .calc = calc, .tree = calc->tree, .aux_tree = aux_tree,
- .proj_axis = proj_axis, .local2aux = &local2aux,
- };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT);
- settings.userdata_chunk = &hit;
- settings.userdata_chunk_size = sizeof(hit);
- BLI_task_parallel_range(0, calc->numVerts,
- &data,
- shrinkwrap_calc_normal_projection_cb_ex,
- &settings);
-
- /* free data structures */
- if (aux_tree) {
- BKE_shrinkwrap_free_tree(aux_tree);
- }
+ /* Options about projection direction */
+ float proj_axis[3] = {0.0f, 0.0f, 0.0f};
+
+ /* Raycast and tree stuff */
+
+ /** \note 'hit.dist' is kept in the targets space, this is only used
+ * for finding the best hit, to get the real dist,
+ * measure the len_v3v3() from the input coord to hit.co */
+ BVHTreeRayHit hit;
+
+ /* auxiliary target */
+ Mesh *auxMesh = NULL;
+ ShrinkwrapTreeData *aux_tree = NULL;
+ ShrinkwrapTreeData aux_tree_stack;
+ SpaceTransform local2aux;
+
+ /* If the user doesn't allows to project in any direction of projection axis
+ * then there's nothing todo. */
+ if ((calc->smd->shrinkOpts &
+ (MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR | MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR)) == 0)
+ return;
+
+ /* Prepare data to retrieve the direction in which we should project each vertex */
+ if (calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) {
+ if (calc->vert == NULL)
+ return;
+ }
+ else {
+ /* The code supports any axis that is a combination of X,Y,Z
+ * although currently UI only allows to set the 3 different axis */
+ if (calc->smd->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS)
+ proj_axis[0] = 1.0f;
+ if (calc->smd->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS)
+ proj_axis[1] = 1.0f;
+ if (calc->smd->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS)
+ proj_axis[2] = 1.0f;
+
+ normalize_v3(proj_axis);
+
+ /* Invalid projection direction */
+ if (len_squared_v3(proj_axis) < FLT_EPSILON) {
+ return;
+ }
+ }
+
+ if (calc->aux_target) {
+ auxMesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(calc->aux_target, false);
+ if (!auxMesh)
+ return;
+ BLI_SPACE_TRANSFORM_SETUP(&local2aux, calc->ob, calc->aux_target);
+ }
+
+ if (BKE_shrinkwrap_init_tree(
+ &aux_tree_stack, auxMesh, calc->smd->shrinkType, calc->smd->shrinkMode, false)) {
+ aux_tree = &aux_tree_stack;
+ }
+
+ /* After successfully build the trees, start projection vertices. */
+ ShrinkwrapCalcCBData data = {
+ .calc = calc,
+ .tree = calc->tree,
+ .aux_tree = aux_tree,
+ .proj_axis = proj_axis,
+ .local2aux = &local2aux,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT);
+ settings.userdata_chunk = &hit;
+ settings.userdata_chunk_size = sizeof(hit);
+ BLI_task_parallel_range(
+ 0, calc->numVerts, &data, shrinkwrap_calc_normal_projection_cb_ex, &settings);
+
+ /* free data structures */
+ if (aux_tree) {
+ BKE_shrinkwrap_free_tree(aux_tree);
+ }
}
/*
@@ -702,331 +724,375 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc)
//#define TRACE_TARGET_PROJECT
typedef struct TargetProjectTriData {
- const float **vtri_co;
- const float (*vtri_no)[3];
- const float *point_co;
+ const float **vtri_co;
+ const float (*vtri_no)[3];
+ const float *point_co;
- float n0_minus_n2[3], n1_minus_n2[3];
- float c0_minus_c2[3], c1_minus_c2[3];
+ float n0_minus_n2[3], n1_minus_n2[3];
+ float c0_minus_c2[3], c1_minus_c2[3];
- /* Current interpolated position and normal. */
- float co_interp[3], no_interp[3];
+ /* Current interpolated position and normal. */
+ float co_interp[3], no_interp[3];
} TargetProjectTriData;
/* Computes the deviation of the equation system from goal. */
static void target_project_tri_deviation(void *userdata, const float x[3], float r_delta[3])
{
- TargetProjectTriData *data = userdata;
+ TargetProjectTriData *data = userdata;
- float w[3] = { x[0], x[1], 1.0f - x[0] - x[1] };
- interp_v3_v3v3v3(data->co_interp, data->vtri_co[0], data->vtri_co[1], data->vtri_co[2], w);
- interp_v3_v3v3v3(data->no_interp, data->vtri_no[0], data->vtri_no[1], data->vtri_no[2], w);
+ float w[3] = {x[0], x[1], 1.0f - x[0] - x[1]};
+ interp_v3_v3v3v3(data->co_interp, data->vtri_co[0], data->vtri_co[1], data->vtri_co[2], w);
+ interp_v3_v3v3v3(data->no_interp, data->vtri_no[0], data->vtri_no[1], data->vtri_no[2], w);
- madd_v3_v3v3fl(r_delta, data->co_interp, data->no_interp, x[2]);
- sub_v3_v3(r_delta, data->point_co);
+ madd_v3_v3v3fl(r_delta, data->co_interp, data->no_interp, x[2]);
+ sub_v3_v3(r_delta, data->point_co);
}
/* Computes the Jacobian matrix of the equation system. */
static void target_project_tri_jacobian(void *userdata, const float x[3], float r_jacobian[3][3])
{
- TargetProjectTriData *data = userdata;
+ TargetProjectTriData *data = userdata;
- madd_v3_v3v3fl(r_jacobian[0], data->c0_minus_c2, data->n0_minus_n2, x[2]);
- madd_v3_v3v3fl(r_jacobian[1], data->c1_minus_c2, data->n1_minus_n2, x[2]);
+ madd_v3_v3v3fl(r_jacobian[0], data->c0_minus_c2, data->n0_minus_n2, x[2]);
+ madd_v3_v3v3fl(r_jacobian[1], data->c1_minus_c2, data->n1_minus_n2, x[2]);
- copy_v3_v3(r_jacobian[2], data->vtri_no[2]);
- madd_v3_v3fl(r_jacobian[2], data->n0_minus_n2, x[0]);
- madd_v3_v3fl(r_jacobian[2], data->n1_minus_n2, x[1]);
+ copy_v3_v3(r_jacobian[2], data->vtri_no[2]);
+ madd_v3_v3fl(r_jacobian[2], data->n0_minus_n2, x[0]);
+ madd_v3_v3fl(r_jacobian[2], data->n1_minus_n2, x[1]);
}
/* Clamp barycentric weights to the triangle. */
static void target_project_tri_clamp(float x[3])
{
- if (x[0] < 0.0f) {
- x[0] = 0.0f;
- }
- if (x[1] < 0.0f) {
- x[1] = 0.0f;
- }
- if (x[0] + x[1] > 1.0f) {
- x[0] = x[0] / (x[0] + x[1]);
- x[1] = 1.0f - x[0];
- }
+ if (x[0] < 0.0f) {
+ x[0] = 0.0f;
+ }
+ if (x[1] < 0.0f) {
+ x[1] = 0.0f;
+ }
+ if (x[0] + x[1] > 1.0f) {
+ x[0] = x[0] / (x[0] + x[1]);
+ x[1] = 1.0f - x[0];
+ }
}
/* Correct the Newton's method step to keep the coordinates within the triangle. */
-static bool target_project_tri_correct(void *UNUSED(userdata), const float x[3], float step[3], float x_next[3])
+static bool target_project_tri_correct(void *UNUSED(userdata),
+ const float x[3],
+ float step[3],
+ float x_next[3])
{
- /* Insignificant correction threshold */
- const float epsilon = 1e-6f;
- const float dir_epsilon = 0.05f;
- bool fixed = false, locked = false;
-
- /* Weight 0 and 1 boundary check. */
- for (int i = 0; i < 2; i++) {
- if (step[i] > x[i]) {
- if (step[i] > dir_epsilon * fabsf(step[1 - i])) {
- /* Abort if the solution is clearly outside the domain. */
- if (x[i] < epsilon) {
- return false;
- }
-
- /* Scale a significant step down to arrive at the boundary. */
- mul_v3_fl(step, x[i] / step[i]);
- fixed = true;
- }
- else {
- /* Reset precision errors to stay at the boundary. */
- step[i] = x[i];
- fixed = locked = true;
- }
- }
- }
-
- /* Weight 2 boundary check. */
- float sum = x[0] + x[1];
- float sstep = step[0] + step[1];
-
- if (sum - sstep > 1.0f) {
- if (sstep < -dir_epsilon * (fabsf(step[0]) + fabsf(step[1]))) {
- /* Abort if the solution is clearly outside the domain. */
- if (sum > 1.0f - epsilon) {
- return false;
- }
-
- /* Scale a significant step down to arrive at the boundary. */
- mul_v3_fl(step, (1.0f - sum) / -sstep);
- fixed = true;
- }
- else {
- /* Reset precision errors to stay at the boundary. */
- if (locked) {
- step[0] = step[1] = 0.0f;
- }
- else {
- step[0] -= 0.5f * sstep;
- step[1] = -step[0];
- fixed = true;
- }
- }
- }
-
- /* Recompute and clamp the new coordinates after step correction. */
- if (fixed) {
- sub_v3_v3v3(x_next, x, step);
- target_project_tri_clamp(x_next);
- }
-
- return true;
+ /* Insignificant correction threshold */
+ const float epsilon = 1e-6f;
+ const float dir_epsilon = 0.05f;
+ bool fixed = false, locked = false;
+
+ /* Weight 0 and 1 boundary check. */
+ for (int i = 0; i < 2; i++) {
+ if (step[i] > x[i]) {
+ if (step[i] > dir_epsilon * fabsf(step[1 - i])) {
+ /* Abort if the solution is clearly outside the domain. */
+ if (x[i] < epsilon) {
+ return false;
+ }
+
+ /* Scale a significant step down to arrive at the boundary. */
+ mul_v3_fl(step, x[i] / step[i]);
+ fixed = true;
+ }
+ else {
+ /* Reset precision errors to stay at the boundary. */
+ step[i] = x[i];
+ fixed = locked = true;
+ }
+ }
+ }
+
+ /* Weight 2 boundary check. */
+ float sum = x[0] + x[1];
+ float sstep = step[0] + step[1];
+
+ if (sum - sstep > 1.0f) {
+ if (sstep < -dir_epsilon * (fabsf(step[0]) + fabsf(step[1]))) {
+ /* Abort if the solution is clearly outside the domain. */
+ if (sum > 1.0f - epsilon) {
+ return false;
+ }
+
+ /* Scale a significant step down to arrive at the boundary. */
+ mul_v3_fl(step, (1.0f - sum) / -sstep);
+ fixed = true;
+ }
+ else {
+ /* Reset precision errors to stay at the boundary. */
+ if (locked) {
+ step[0] = step[1] = 0.0f;
+ }
+ else {
+ step[0] -= 0.5f * sstep;
+ step[1] = -step[0];
+ fixed = true;
+ }
+ }
+ }
+
+ /* Recompute and clamp the new coordinates after step correction. */
+ if (fixed) {
+ sub_v3_v3v3(x_next, x, step);
+ target_project_tri_clamp(x_next);
+ }
+
+ return true;
}
-static bool target_project_solve_point_tri(
- const float *vtri_co[3], const float vtri_no[3][3], const float point_co[3],
- const float hit_co[3], float hit_dist_sq,
- float r_hit_co[3], float r_hit_no[3])
+static bool target_project_solve_point_tri(const float *vtri_co[3],
+ const float vtri_no[3][3],
+ const float point_co[3],
+ const float hit_co[3],
+ float hit_dist_sq,
+ float r_hit_co[3],
+ float r_hit_no[3])
{
- float x[3], tmp[3];
- float dist = sqrtf(hit_dist_sq);
- float epsilon = dist * 1.0e-5f;
+ float x[3], tmp[3];
+ float dist = sqrtf(hit_dist_sq);
+ float epsilon = dist * 1.0e-5f;
- CLAMP_MIN(epsilon, 1.0e-5f);
+ CLAMP_MIN(epsilon, 1.0e-5f);
- /* Initial solution vector: barycentric weights plus distance along normal. */
- interp_weights_tri_v3(x, UNPACK3(vtri_co), hit_co);
+ /* Initial solution vector: barycentric weights plus distance along normal. */
+ interp_weights_tri_v3(x, UNPACK3(vtri_co), hit_co);
- interp_v3_v3v3v3(r_hit_no, UNPACK3(vtri_no), x);
- sub_v3_v3v3(tmp, point_co, hit_co);
+ interp_v3_v3v3v3(r_hit_no, UNPACK3(vtri_no), x);
+ sub_v3_v3v3(tmp, point_co, hit_co);
- x[2] = (dot_v3v3(tmp, r_hit_no) < 0) ? -dist : dist;
+ x[2] = (dot_v3v3(tmp, r_hit_no) < 0) ? -dist : dist;
- /* Solve the equations iteratively. */
- TargetProjectTriData tri_data = { .vtri_co = vtri_co, .vtri_no = vtri_no, .point_co = point_co, };
+ /* Solve the equations iteratively. */
+ TargetProjectTriData tri_data = {
+ .vtri_co = vtri_co,
+ .vtri_no = vtri_no,
+ .point_co = point_co,
+ };
- sub_v3_v3v3(tri_data.n0_minus_n2, vtri_no[0], vtri_no[2]);
- sub_v3_v3v3(tri_data.n1_minus_n2, vtri_no[1], vtri_no[2]);
- sub_v3_v3v3(tri_data.c0_minus_c2, vtri_co[0], vtri_co[2]);
- sub_v3_v3v3(tri_data.c1_minus_c2, vtri_co[1], vtri_co[2]);
+ sub_v3_v3v3(tri_data.n0_minus_n2, vtri_no[0], vtri_no[2]);
+ sub_v3_v3v3(tri_data.n1_minus_n2, vtri_no[1], vtri_no[2]);
+ sub_v3_v3v3(tri_data.c0_minus_c2, vtri_co[0], vtri_co[2]);
+ sub_v3_v3v3(tri_data.c1_minus_c2, vtri_co[1], vtri_co[2]);
- target_project_tri_clamp(x);
+ target_project_tri_clamp(x);
#ifdef TRACE_TARGET_PROJECT
- const bool trace = true;
+ const bool trace = true;
#else
- const bool trace = false;
+ const bool trace = false;
#endif
- bool ok = BLI_newton3d_solve(target_project_tri_deviation, target_project_tri_jacobian, target_project_tri_correct, &tri_data, epsilon, 20, trace, x, x);
+ bool ok = BLI_newton3d_solve(target_project_tri_deviation,
+ target_project_tri_jacobian,
+ target_project_tri_correct,
+ &tri_data,
+ epsilon,
+ 20,
+ trace,
+ x,
+ x);
- if (ok) {
- copy_v3_v3(r_hit_co, tri_data.co_interp);
- copy_v3_v3(r_hit_no, tri_data.no_interp);
+ if (ok) {
+ copy_v3_v3(r_hit_co, tri_data.co_interp);
+ copy_v3_v3(r_hit_no, tri_data.no_interp);
- return true;
- }
+ return true;
+ }
- return false;
+ return false;
}
-static bool update_hit(BVHTreeNearest *nearest, int index, const float co[3], const float hit_co[3], const float hit_no[3])
+static bool update_hit(BVHTreeNearest *nearest,
+ int index,
+ const float co[3],
+ const float hit_co[3],
+ const float hit_no[3])
{
- float dist_sq = len_squared_v3v3(hit_co, co);
+ float dist_sq = len_squared_v3v3(hit_co, co);
- if (dist_sq < nearest->dist_sq) {
+ if (dist_sq < nearest->dist_sq) {
#ifdef TRACE_TARGET_PROJECT
- printf("===> %d (%.3f,%.3f,%.3f) %g < %g\n", index, UNPACK3(hit_co), dist_sq, nearest->dist_sq);
+ printf(
+ "===> %d (%.3f,%.3f,%.3f) %g < %g\n", index, UNPACK3(hit_co), dist_sq, nearest->dist_sq);
#endif
- nearest->index = index;
- nearest->dist_sq = dist_sq;
- copy_v3_v3(nearest->co, hit_co);
- normalize_v3_v3(nearest->no, hit_no);
- return true;
- }
-
- return false;
+ nearest->index = index;
+ nearest->dist_sq = dist_sq;
+ copy_v3_v3(nearest->co, hit_co);
+ normalize_v3_v3(nearest->no, hit_no);
+ return true;
+ }
+
+ return false;
}
/* Target projection on a non-manifold boundary edge - treats it like an infinitely thin cylinder. */
-static void target_project_edge(const ShrinkwrapTreeData *tree, int index, const float co[3], BVHTreeNearest *nearest, int eidx)
+static void target_project_edge(const ShrinkwrapTreeData *tree,
+ int index,
+ const float co[3],
+ BVHTreeNearest *nearest,
+ int eidx)
{
- const BVHTreeFromMesh *data = &tree->treeData;
- const MEdge *edge = &tree->mesh->medge[eidx];
- const float *vedge_co[2] = { data->vert[edge->v1].co, data->vert[edge->v2].co };
+ const BVHTreeFromMesh *data = &tree->treeData;
+ const MEdge *edge = &tree->mesh->medge[eidx];
+ const float *vedge_co[2] = {data->vert[edge->v1].co, data->vert[edge->v2].co};
#ifdef TRACE_TARGET_PROJECT
- printf("EDGE %d (%.3f,%.3f,%.3f) (%.3f,%.3f,%.3f)\n", eidx, UNPACK3(vedge_co[0]), UNPACK3(vedge_co[1]));
+ printf("EDGE %d (%.3f,%.3f,%.3f) (%.3f,%.3f,%.3f)\n",
+ eidx,
+ UNPACK3(vedge_co[0]),
+ UNPACK3(vedge_co[1]));
#endif
- /* Retrieve boundary vertex IDs */
- const int *vert_boundary_id = tree->boundary->vert_boundary_id;
- int bid1 = vert_boundary_id[edge->v1], bid2 = vert_boundary_id[edge->v2];
+ /* Retrieve boundary vertex IDs */
+ const int *vert_boundary_id = tree->boundary->vert_boundary_id;
+ int bid1 = vert_boundary_id[edge->v1], bid2 = vert_boundary_id[edge->v2];
- if (bid1 < 0 || bid2 < 0) {
- return;
- }
+ if (bid1 < 0 || bid2 < 0) {
+ return;
+ }
- /* Retrieve boundary vertex normals and align them to direction. */
- const ShrinkwrapBoundaryVertData *boundary_verts = tree->boundary->boundary_verts;
- float vedge_dir[2][3], dir[3];
+ /* Retrieve boundary vertex normals and align them to direction. */
+ const ShrinkwrapBoundaryVertData *boundary_verts = tree->boundary->boundary_verts;
+ float vedge_dir[2][3], dir[3];
- copy_v3_v3(vedge_dir[0], boundary_verts[bid1].normal_plane);
- copy_v3_v3(vedge_dir[1], boundary_verts[bid2].normal_plane);
+ copy_v3_v3(vedge_dir[0], boundary_verts[bid1].normal_plane);
+ copy_v3_v3(vedge_dir[1], boundary_verts[bid2].normal_plane);
- sub_v3_v3v3(dir, vedge_co[1], vedge_co[0]);
+ sub_v3_v3v3(dir, vedge_co[1], vedge_co[0]);
- if (dot_v3v3(boundary_verts[bid1].direction, dir) < 0) {
- negate_v3(vedge_dir[0]);
- }
- if (dot_v3v3(boundary_verts[bid2].direction, dir) < 0) {
- negate_v3(vedge_dir[1]);
- }
+ if (dot_v3v3(boundary_verts[bid1].direction, dir) < 0) {
+ negate_v3(vedge_dir[0]);
+ }
+ if (dot_v3v3(boundary_verts[bid2].direction, dir) < 0) {
+ negate_v3(vedge_dir[1]);
+ }
- /* Solve a quadratic equation: lerp(d0,d1,x) * (co - lerp(v0,v1,x)) = 0 */
- float d0v0 = dot_v3v3(vedge_dir[0], vedge_co[0]), d0v1 = dot_v3v3(vedge_dir[0], vedge_co[1]);
- float d1v0 = dot_v3v3(vedge_dir[1], vedge_co[0]), d1v1 = dot_v3v3(vedge_dir[1], vedge_co[1]);
- float d0co = dot_v3v3(vedge_dir[0], co);
+ /* Solve a quadratic equation: lerp(d0,d1,x) * (co - lerp(v0,v1,x)) = 0 */
+ float d0v0 = dot_v3v3(vedge_dir[0], vedge_co[0]), d0v1 = dot_v3v3(vedge_dir[0], vedge_co[1]);
+ float d1v0 = dot_v3v3(vedge_dir[1], vedge_co[0]), d1v1 = dot_v3v3(vedge_dir[1], vedge_co[1]);
+ float d0co = dot_v3v3(vedge_dir[0], co);
- float a = d0v1 - d0v0 + d1v0 - d1v1;
- float b = 2 * d0v0 - d0v1 - d0co - d1v0 + dot_v3v3(vedge_dir[1], co);
- float c = d0co - d0v0;
- float det = b * b - 4 * a * c;
+ float a = d0v1 - d0v0 + d1v0 - d1v1;
+ float b = 2 * d0v0 - d0v1 - d0co - d1v0 + dot_v3v3(vedge_dir[1], co);
+ float c = d0co - d0v0;
+ float det = b * b - 4 * a * c;
- if (det >= 0) {
- const float epsilon = 1e-6f;
- float sdet = sqrtf(det);
- float hit_co[3], hit_no[3];
+ if (det >= 0) {
+ const float epsilon = 1e-6f;
+ float sdet = sqrtf(det);
+ float hit_co[3], hit_no[3];
- for (int i = (det > 0 ? 2 : 0); i >= 0; i -= 2) {
- float x = (- b + ((float)i - 1) * sdet) / (2 * a);
+ for (int i = (det > 0 ? 2 : 0); i >= 0; i -= 2) {
+ float x = (-b + ((float)i - 1) * sdet) / (2 * a);
- if (x >= -epsilon && x <= 1.0f + epsilon) {
- CLAMP(x, 0, 1);
+ if (x >= -epsilon && x <= 1.0f + epsilon) {
+ CLAMP(x, 0, 1);
- float vedge_no[2][3];
- normal_short_to_float_v3(vedge_no[0], data->vert[edge->v1].no);
- normal_short_to_float_v3(vedge_no[1], data->vert[edge->v2].no);
+ float vedge_no[2][3];
+ normal_short_to_float_v3(vedge_no[0], data->vert[edge->v1].no);
+ normal_short_to_float_v3(vedge_no[1], data->vert[edge->v2].no);
- interp_v3_v3v3(hit_co, vedge_co[0], vedge_co[1], x);
- interp_v3_v3v3(hit_no, vedge_no[0], vedge_no[1], x);
+ interp_v3_v3v3(hit_co, vedge_co[0], vedge_co[1], x);
+ interp_v3_v3v3(hit_no, vedge_no[0], vedge_no[1], x);
- update_hit(nearest, index, co, hit_co, hit_no);
- }
- }
- }
+ update_hit(nearest, index, co, hit_co, hit_no);
+ }
+ }
+ }
}
/* Target normal projection BVH callback - based on mesh_looptri_nearest_point. */
-static void mesh_looptri_target_project(void *userdata, int index, const float co[3], BVHTreeNearest *nearest)
+static void mesh_looptri_target_project(void *userdata,
+ int index,
+ const float co[3],
+ BVHTreeNearest *nearest)
{
- const ShrinkwrapTreeData *tree = (ShrinkwrapTreeData *)userdata;
- const BVHTreeFromMesh *data = &tree->treeData;
- const MLoopTri *lt = &data->looptri[index];
- const MLoop *loop[3] = { &data->loop[lt->tri[0]], &data->loop[lt->tri[1]], &data->loop[lt->tri[2]] };
- const MVert *vtri[3] = { &data->vert[loop[0]->v], &data->vert[loop[1]->v], &data->vert[loop[2]->v] };
- const float *vtri_co[3] = { vtri[0]->co, vtri[1]->co, vtri[2]->co };
- float raw_hit_co[3], hit_co[3], hit_no[3], dist_sq, vtri_no[3][3];
-
- /* First find the closest point and bail out if it's worse than the current solution. */
- closest_on_tri_to_point_v3(raw_hit_co, co, UNPACK3(vtri_co));
- dist_sq = len_squared_v3v3(co, raw_hit_co);
+ const ShrinkwrapTreeData *tree = (ShrinkwrapTreeData *)userdata;
+ const BVHTreeFromMesh *data = &tree->treeData;
+ const MLoopTri *lt = &data->looptri[index];
+ const MLoop *loop[3] = {
+ &data->loop[lt->tri[0]], &data->loop[lt->tri[1]], &data->loop[lt->tri[2]]};
+ const MVert *vtri[3] = {
+ &data->vert[loop[0]->v], &data->vert[loop[1]->v], &data->vert[loop[2]->v]};
+ const float *vtri_co[3] = {vtri[0]->co, vtri[1]->co, vtri[2]->co};
+ float raw_hit_co[3], hit_co[3], hit_no[3], dist_sq, vtri_no[3][3];
+
+ /* First find the closest point and bail out if it's worse than the current solution. */
+ closest_on_tri_to_point_v3(raw_hit_co, co, UNPACK3(vtri_co));
+ dist_sq = len_squared_v3v3(co, raw_hit_co);
#ifdef TRACE_TARGET_PROJECT
- printf("TRIANGLE %d (%.3f,%.3f,%.3f) (%.3f,%.3f,%.3f) (%.3f,%.3f,%.3f) %g %g\n",
- index, UNPACK3(vtri_co[0]), UNPACK3(vtri_co[1]), UNPACK3(vtri_co[2]), dist_sq, nearest->dist_sq);
+ printf("TRIANGLE %d (%.3f,%.3f,%.3f) (%.3f,%.3f,%.3f) (%.3f,%.3f,%.3f) %g %g\n",
+ index,
+ UNPACK3(vtri_co[0]),
+ UNPACK3(vtri_co[1]),
+ UNPACK3(vtri_co[2]),
+ dist_sq,
+ nearest->dist_sq);
#endif
- if (dist_sq >= nearest->dist_sq)
- return;
-
- /* Decode normals */
- normal_short_to_float_v3(vtri_no[0], vtri[0]->no);
- normal_short_to_float_v3(vtri_no[1], vtri[1]->no);
- normal_short_to_float_v3(vtri_no[2], vtri[2]->no);
-
- /* Solve the equations for the triangle */
- if (target_project_solve_point_tri(vtri_co, vtri_no, co, raw_hit_co, dist_sq, hit_co, hit_no)) {
- update_hit(nearest, index, co, hit_co, hit_no);
- }
- /* Boundary edges */
- else if (tree->boundary && BLI_BITMAP_TEST(tree->boundary->looptri_has_boundary, index)) {
- const BLI_bitmap *is_boundary = tree->boundary->edge_is_boundary;
- int edges[3];
-
- BKE_mesh_looptri_get_real_edges(tree->mesh, lt, edges);
-
- for (int i = 0; i < 3; i++) {
- if (edges[i] >= 0 && BLI_BITMAP_TEST(is_boundary, edges[i])) {
- target_project_edge(tree, index, co, nearest, edges[i]);
- }
- }
- }
+ if (dist_sq >= nearest->dist_sq)
+ return;
+
+ /* Decode normals */
+ normal_short_to_float_v3(vtri_no[0], vtri[0]->no);
+ normal_short_to_float_v3(vtri_no[1], vtri[1]->no);
+ normal_short_to_float_v3(vtri_no[2], vtri[2]->no);
+
+ /* Solve the equations for the triangle */
+ if (target_project_solve_point_tri(vtri_co, vtri_no, co, raw_hit_co, dist_sq, hit_co, hit_no)) {
+ update_hit(nearest, index, co, hit_co, hit_no);
+ }
+ /* Boundary edges */
+ else if (tree->boundary && BLI_BITMAP_TEST(tree->boundary->looptri_has_boundary, index)) {
+ const BLI_bitmap *is_boundary = tree->boundary->edge_is_boundary;
+ int edges[3];
+
+ BKE_mesh_looptri_get_real_edges(tree->mesh, lt, edges);
+
+ for (int i = 0; i < 3; i++) {
+ if (edges[i] >= 0 && BLI_BITMAP_TEST(is_boundary, edges[i])) {
+ target_project_edge(tree, index, co, nearest, edges[i]);
+ }
+ }
+ }
}
/*
* Maps the point to the nearest surface, either by simple nearest, or by target normal projection.
*/
-void BKE_shrinkwrap_find_nearest_surface(struct ShrinkwrapTreeData *tree, BVHTreeNearest *nearest, float co[3], int type)
+void BKE_shrinkwrap_find_nearest_surface(struct ShrinkwrapTreeData *tree,
+ BVHTreeNearest *nearest,
+ float co[3],
+ int type)
{
- BVHTreeFromMesh *treeData = &tree->treeData;
+ BVHTreeFromMesh *treeData = &tree->treeData;
- if (type == MOD_SHRINKWRAP_TARGET_PROJECT) {
+ if (type == MOD_SHRINKWRAP_TARGET_PROJECT) {
#ifdef TRACE_TARGET_PROJECT
- printf("====== TARGET PROJECT START ======\n");
+ printf("====== TARGET PROJECT START ======\n");
#endif
- BLI_bvhtree_find_nearest_ex(tree->bvh, co, nearest, mesh_looptri_target_project, tree, BVH_NEAREST_OPTIMAL_ORDER);
+ BLI_bvhtree_find_nearest_ex(
+ tree->bvh, co, nearest, mesh_looptri_target_project, tree, BVH_NEAREST_OPTIMAL_ORDER);
#ifdef TRACE_TARGET_PROJECT
- printf("====== TARGET PROJECT END: %d %g ======\n", nearest->index, nearest->dist_sq);
+ printf("====== TARGET PROJECT END: %d %g ======\n", nearest->index, nearest->dist_sq);
#endif
- if (nearest->index < 0) {
- /* fallback to simple nearest */
- BLI_bvhtree_find_nearest(tree->bvh, co, nearest, treeData->nearest_callback, treeData);
- }
- }
- else {
- BLI_bvhtree_find_nearest(tree->bvh, co, nearest, treeData->nearest_callback, treeData);
- }
+ if (nearest->index < 0) {
+ /* fallback to simple nearest */
+ BLI_bvhtree_find_nearest(tree->bvh, co, nearest, treeData->nearest_callback, treeData);
+ }
+ }
+ else {
+ BLI_bvhtree_find_nearest(tree->bvh, co, nearest, treeData->nearest_callback, treeData);
+ }
}
/*
@@ -1035,67 +1101,72 @@ void BKE_shrinkwrap_find_nearest_surface(struct ShrinkwrapTreeData *tree, BVHTre
* it builds a BVHTree from the target mesh and then performs a
* NN matches for each vertex
*/
-static void shrinkwrap_calc_nearest_surface_point_cb_ex(
- void *__restrict userdata,
- const int i,
- const ParallelRangeTLS *__restrict tls)
+static void shrinkwrap_calc_nearest_surface_point_cb_ex(void *__restrict userdata,
+ const int i,
+ const ParallelRangeTLS *__restrict tls)
{
- ShrinkwrapCalcCBData *data = userdata;
-
- ShrinkwrapCalcData *calc = data->calc;
- BVHTreeNearest *nearest = tls->userdata_chunk;
-
- float *co = calc->vertexCos[i];
- float tmp_co[3];
- float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup);
-
- if (calc->invert_vgroup) {
- weight = 1.0f - weight;
- }
-
- if (weight == 0.0f) {
- return;
- }
-
- /* Convert the vertex to tree coordinates */
- if (calc->vert) {
- copy_v3_v3(tmp_co, calc->vert[i].co);
- }
- else {
- copy_v3_v3(tmp_co, co);
- }
- BLI_space_transform_apply(&calc->local2target, tmp_co);
-
- /* Use local proximity heuristics (to reduce the nearest search)
- *
- * If we already had an hit before.. we assume this vertex is going to have a close hit to that other vertex
- * so we can initiate the "nearest.dist" with the expected value to that last hit.
- * This will lead in pruning of the search tree. */
- if (nearest->index != -1) {
- if (calc->smd->shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) {
- /* Heuristic doesn't work because of additional restrictions. */
- nearest->index = -1;
- nearest->dist_sq = FLT_MAX;
- }
- else {
- nearest->dist_sq = len_squared_v3v3(tmp_co, nearest->co);
- }
- }
- else
- nearest->dist_sq = FLT_MAX;
-
- BKE_shrinkwrap_find_nearest_surface(data->tree, nearest, tmp_co, calc->smd->shrinkType);
-
- /* Found the nearest vertex */
- if (nearest->index != -1) {
- BKE_shrinkwrap_snap_point_to_surface(
- data->tree, NULL, calc->smd->shrinkMode,
- nearest->index, nearest->co, nearest->no, calc->keepDist, tmp_co, tmp_co);
-
- /* Convert the coordinates back to mesh coordinates */
- BLI_space_transform_invert(&calc->local2target, tmp_co);
- interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */
- }
+ ShrinkwrapCalcCBData *data = userdata;
+
+ ShrinkwrapCalcData *calc = data->calc;
+ BVHTreeNearest *nearest = tls->userdata_chunk;
+
+ float *co = calc->vertexCos[i];
+ float tmp_co[3];
+ float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup);
+
+ if (calc->invert_vgroup) {
+ weight = 1.0f - weight;
+ }
+
+ if (weight == 0.0f) {
+ return;
+ }
+
+ /* Convert the vertex to tree coordinates */
+ if (calc->vert) {
+ copy_v3_v3(tmp_co, calc->vert[i].co);
+ }
+ else {
+ copy_v3_v3(tmp_co, co);
+ }
+ BLI_space_transform_apply(&calc->local2target, tmp_co);
+
+ /* Use local proximity heuristics (to reduce the nearest search)
+ *
+ * If we already had an hit before.. we assume this vertex is going to have a close hit to that other vertex
+ * so we can initiate the "nearest.dist" with the expected value to that last hit.
+ * This will lead in pruning of the search tree. */
+ if (nearest->index != -1) {
+ if (calc->smd->shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) {
+ /* Heuristic doesn't work because of additional restrictions. */
+ nearest->index = -1;
+ nearest->dist_sq = FLT_MAX;
+ }
+ else {
+ nearest->dist_sq = len_squared_v3v3(tmp_co, nearest->co);
+ }
+ }
+ else
+ nearest->dist_sq = FLT_MAX;
+
+ BKE_shrinkwrap_find_nearest_surface(data->tree, nearest, tmp_co, calc->smd->shrinkType);
+
+ /* Found the nearest vertex */
+ if (nearest->index != -1) {
+ BKE_shrinkwrap_snap_point_to_surface(data->tree,
+ NULL,
+ calc->smd->shrinkMode,
+ nearest->index,
+ nearest->co,
+ nearest->no,
+ calc->keepDist,
+ tmp_co,
+ tmp_co);
+
+ /* Convert the coordinates back to mesh coordinates */
+ BLI_space_transform_invert(&calc->local2target, tmp_co);
+ interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */
+ }
}
/**
@@ -1105,92 +1176,101 @@ static void shrinkwrap_calc_nearest_surface_point_cb_ex(
* \param transform: transform from the hit coordinate space to the object space; may be null
* \param r_no: output in hit coordinate space; may be shared with inputs
*/
-void BKE_shrinkwrap_compute_smooth_normal(
- const struct ShrinkwrapTreeData *tree, const struct SpaceTransform *transform,
- int looptri_idx, const float hit_co[3], const float hit_no[3], float r_no[3])
+void BKE_shrinkwrap_compute_smooth_normal(const struct ShrinkwrapTreeData *tree,
+ const struct SpaceTransform *transform,
+ int looptri_idx,
+ const float hit_co[3],
+ const float hit_no[3],
+ float r_no[3])
{
- const BVHTreeFromMesh *treeData = &tree->treeData;
- const MLoopTri *tri = &treeData->looptri[looptri_idx];
-
- /* Interpolate smooth normals if enabled. */
- if ((tree->mesh->mpoly[tri->poly].flag & ME_SMOOTH) != 0) {
- const MVert *verts[] = {
- &treeData->vert[treeData->loop[tri->tri[0]].v],
- &treeData->vert[treeData->loop[tri->tri[1]].v],
- &treeData->vert[treeData->loop[tri->tri[2]].v],
- };
- float w[3], no[3][3], tmp_co[3];
-
- /* Custom and auto smooth split normals. */
- if (tree->clnors) {
- copy_v3_v3(no[0], tree->clnors[tri->tri[0]]);
- copy_v3_v3(no[1], tree->clnors[tri->tri[1]]);
- copy_v3_v3(no[2], tree->clnors[tri->tri[2]]);
- }
- /* Ordinary vertex normals. */
- else {
- normal_short_to_float_v3(no[0], verts[0]->no);
- normal_short_to_float_v3(no[1], verts[1]->no);
- normal_short_to_float_v3(no[2], verts[2]->no);
- }
-
- /* Barycentric weights from hit point. */
- copy_v3_v3(tmp_co, hit_co);
-
- if (transform) {
- BLI_space_transform_apply(transform, tmp_co);
- }
-
- interp_weights_tri_v3(w, verts[0]->co, verts[1]->co, verts[2]->co, tmp_co);
-
- /* Interpolate using weights. */
- interp_v3_v3v3v3(r_no, no[0], no[1], no[2], w);
-
- if (transform) {
- BLI_space_transform_invert_normal(transform, r_no);
- }
- else {
- normalize_v3(r_no);
- }
- }
- /* Use the polygon normal if flat. */
- else if (tree->pnors != NULL) {
- copy_v3_v3(r_no, tree->pnors[tri->poly]);
- }
- /* Finally fallback to the looptri normal. */
- else {
- copy_v3_v3(r_no, hit_no);
- }
+ const BVHTreeFromMesh *treeData = &tree->treeData;
+ const MLoopTri *tri = &treeData->looptri[looptri_idx];
+
+ /* Interpolate smooth normals if enabled. */
+ if ((tree->mesh->mpoly[tri->poly].flag & ME_SMOOTH) != 0) {
+ const MVert *verts[] = {
+ &treeData->vert[treeData->loop[tri->tri[0]].v],
+ &treeData->vert[treeData->loop[tri->tri[1]].v],
+ &treeData->vert[treeData->loop[tri->tri[2]].v],
+ };
+ float w[3], no[3][3], tmp_co[3];
+
+ /* Custom and auto smooth split normals. */
+ if (tree->clnors) {
+ copy_v3_v3(no[0], tree->clnors[tri->tri[0]]);
+ copy_v3_v3(no[1], tree->clnors[tri->tri[1]]);
+ copy_v3_v3(no[2], tree->clnors[tri->tri[2]]);
+ }
+ /* Ordinary vertex normals. */
+ else {
+ normal_short_to_float_v3(no[0], verts[0]->no);
+ normal_short_to_float_v3(no[1], verts[1]->no);
+ normal_short_to_float_v3(no[2], verts[2]->no);
+ }
+
+ /* Barycentric weights from hit point. */
+ copy_v3_v3(tmp_co, hit_co);
+
+ if (transform) {
+ BLI_space_transform_apply(transform, tmp_co);
+ }
+
+ interp_weights_tri_v3(w, verts[0]->co, verts[1]->co, verts[2]->co, tmp_co);
+
+ /* Interpolate using weights. */
+ interp_v3_v3v3v3(r_no, no[0], no[1], no[2], w);
+
+ if (transform) {
+ BLI_space_transform_invert_normal(transform, r_no);
+ }
+ else {
+ normalize_v3(r_no);
+ }
+ }
+ /* Use the polygon normal if flat. */
+ else if (tree->pnors != NULL) {
+ copy_v3_v3(r_no, tree->pnors[tri->poly]);
+ }
+ /* Finally fallback to the looptri normal. */
+ else {
+ copy_v3_v3(r_no, hit_no);
+ }
}
/* Helper for MOD_SHRINKWRAP_INSIDE, MOD_SHRINKWRAP_OUTSIDE and MOD_SHRINKWRAP_OUTSIDE_SURFACE. */
-static void shrinkwrap_snap_with_side(float r_point_co[3], const float point_co[3], const float hit_co[3], const float hit_no[3], float goal_dist, float forcesign, bool forcesnap)
+static void shrinkwrap_snap_with_side(float r_point_co[3],
+ const float point_co[3],
+ const float hit_co[3],
+ const float hit_no[3],
+ float goal_dist,
+ float forcesign,
+ bool forcesnap)
{
- float dist = len_v3v3(point_co, hit_co);
-
- /* If exactly on the surface, push out along normal */
- if (dist < FLT_EPSILON) {
- if (forcesnap || goal_dist > 0) {
- madd_v3_v3v3fl(r_point_co, hit_co, hit_no, goal_dist * forcesign);
- }
- else {
- copy_v3_v3(r_point_co, hit_co);
- }
- }
- /* Move to the correct side if needed */
- else {
- float delta[3];
- sub_v3_v3v3(delta, point_co, hit_co);
- float dsign = signf(dot_v3v3(delta, hit_no) * forcesign);
-
- /* If on the wrong side or too close, move to correct */
- if (forcesnap || dsign * dist < goal_dist) {
- interp_v3_v3v3(r_point_co, point_co, hit_co, (dist - goal_dist * dsign) / dist);
- }
- else {
- copy_v3_v3(r_point_co, point_co);
- }
- }
+ float dist = len_v3v3(point_co, hit_co);
+
+ /* If exactly on the surface, push out along normal */
+ if (dist < FLT_EPSILON) {
+ if (forcesnap || goal_dist > 0) {
+ madd_v3_v3v3fl(r_point_co, hit_co, hit_no, goal_dist * forcesign);
+ }
+ else {
+ copy_v3_v3(r_point_co, hit_co);
+ }
+ }
+ /* Move to the correct side if needed */
+ else {
+ float delta[3];
+ sub_v3_v3v3(delta, point_co, hit_co);
+ float dsign = signf(dot_v3v3(delta, hit_no) * forcesign);
+
+ /* If on the wrong side or too close, move to correct */
+ if (forcesnap || dsign * dist < goal_dist) {
+ interp_v3_v3v3(r_point_co, point_co, hit_co, (dist - goal_dist * dsign) / dist);
+ }
+ else {
+ copy_v3_v3(r_point_co, point_co);
+ }
+ }
}
/**
@@ -1200,174 +1280,187 @@ static void shrinkwrap_snap_with_side(float r_point_co[3], const float point_co[
* \param transform: transform from the hit coordinate space to the object space; may be null
* \param r_point_co: may be the same memory location as point_co, hit_co, or hit_no.
*/
-void BKE_shrinkwrap_snap_point_to_surface(
- const struct ShrinkwrapTreeData *tree, const struct SpaceTransform *transform,
- int mode, int hit_idx, const float hit_co[3], const float hit_no[3], float goal_dist,
- const float point_co[3], float r_point_co[3])
+void BKE_shrinkwrap_snap_point_to_surface(const struct ShrinkwrapTreeData *tree,
+ const struct SpaceTransform *transform,
+ int mode,
+ int hit_idx,
+ const float hit_co[3],
+ const float hit_no[3],
+ float goal_dist,
+ const float point_co[3],
+ float r_point_co[3])
{
- float dist, tmp[3];
-
- switch (mode) {
- /* Offsets along the line between point_co and hit_co. */
- case MOD_SHRINKWRAP_ON_SURFACE:
- if (goal_dist != 0 && (dist = len_v3v3(point_co, hit_co)) > FLT_EPSILON) {
- interp_v3_v3v3(r_point_co, point_co, hit_co, (dist - goal_dist) / dist);
- }
- else {
- copy_v3_v3(r_point_co, hit_co);
- }
- break;
-
- case MOD_SHRINKWRAP_INSIDE:
- shrinkwrap_snap_with_side(r_point_co, point_co, hit_co, hit_no, goal_dist, -1, false);
- break;
-
- case MOD_SHRINKWRAP_OUTSIDE:
- shrinkwrap_snap_with_side(r_point_co, point_co, hit_co, hit_no, goal_dist, +1, false);
- break;
-
- case MOD_SHRINKWRAP_OUTSIDE_SURFACE:
- if (goal_dist != 0) {
- shrinkwrap_snap_with_side(r_point_co, point_co, hit_co, hit_no, goal_dist, +1, true);
- }
- else {
- copy_v3_v3(r_point_co, hit_co);
- }
- break;
-
- /* Offsets along the normal */
- case MOD_SHRINKWRAP_ABOVE_SURFACE:
- if (goal_dist != 0) {
- BKE_shrinkwrap_compute_smooth_normal(tree, transform, hit_idx, hit_co, hit_no, tmp);
- madd_v3_v3v3fl(r_point_co, hit_co, tmp, goal_dist);
- }
- else {
- copy_v3_v3(r_point_co, hit_co);
- }
- break;
-
- default:
- printf("Unknown Shrinkwrap surface snap mode: %d\n", mode);
- copy_v3_v3(r_point_co, hit_co);
- }
+ float dist, tmp[3];
+
+ switch (mode) {
+ /* Offsets along the line between point_co and hit_co. */
+ case MOD_SHRINKWRAP_ON_SURFACE:
+ if (goal_dist != 0 && (dist = len_v3v3(point_co, hit_co)) > FLT_EPSILON) {
+ interp_v3_v3v3(r_point_co, point_co, hit_co, (dist - goal_dist) / dist);
+ }
+ else {
+ copy_v3_v3(r_point_co, hit_co);
+ }
+ break;
+
+ case MOD_SHRINKWRAP_INSIDE:
+ shrinkwrap_snap_with_side(r_point_co, point_co, hit_co, hit_no, goal_dist, -1, false);
+ break;
+
+ case MOD_SHRINKWRAP_OUTSIDE:
+ shrinkwrap_snap_with_side(r_point_co, point_co, hit_co, hit_no, goal_dist, +1, false);
+ break;
+
+ case MOD_SHRINKWRAP_OUTSIDE_SURFACE:
+ if (goal_dist != 0) {
+ shrinkwrap_snap_with_side(r_point_co, point_co, hit_co, hit_no, goal_dist, +1, true);
+ }
+ else {
+ copy_v3_v3(r_point_co, hit_co);
+ }
+ break;
+
+ /* Offsets along the normal */
+ case MOD_SHRINKWRAP_ABOVE_SURFACE:
+ if (goal_dist != 0) {
+ BKE_shrinkwrap_compute_smooth_normal(tree, transform, hit_idx, hit_co, hit_no, tmp);
+ madd_v3_v3v3fl(r_point_co, hit_co, tmp, goal_dist);
+ }
+ else {
+ copy_v3_v3(r_point_co, hit_co);
+ }
+ break;
+
+ default:
+ printf("Unknown Shrinkwrap surface snap mode: %d\n", mode);
+ copy_v3_v3(r_point_co, hit_co);
+ }
}
static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
{
- BVHTreeNearest nearest = NULL_BVHTreeNearest;
-
- /* Setup nearest */
- nearest.index = -1;
- nearest.dist_sq = FLT_MAX;
-
- /* Find the nearest vertex */
- ShrinkwrapCalcCBData data = { .calc = calc, .tree = calc->tree, };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT);
- settings.userdata_chunk = &nearest;
- settings.userdata_chunk_size = sizeof(nearest);
- BLI_task_parallel_range(0, calc->numVerts,
- &data,
- shrinkwrap_calc_nearest_surface_point_cb_ex,
- &settings);
+ BVHTreeNearest nearest = NULL_BVHTreeNearest;
+
+ /* Setup nearest */
+ nearest.index = -1;
+ nearest.dist_sq = FLT_MAX;
+
+ /* Find the nearest vertex */
+ ShrinkwrapCalcCBData data = {
+ .calc = calc,
+ .tree = calc->tree,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT);
+ settings.userdata_chunk = &nearest;
+ settings.userdata_chunk_size = sizeof(nearest);
+ BLI_task_parallel_range(
+ 0, calc->numVerts, &data, shrinkwrap_calc_nearest_surface_point_cb_ex, &settings);
}
/* Main shrinkwrap function */
-void shrinkwrapModifier_deform(
- ShrinkwrapModifierData *smd, const ModifierEvalContext *ctx,
- struct Scene *scene, Object *ob, Mesh *mesh,
- MDeformVert *dvert, const int defgrp_index, float (*vertexCos)[3], int numVerts)
+void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd,
+ const ModifierEvalContext *ctx,
+ struct Scene *scene,
+ Object *ob,
+ Mesh *mesh,
+ MDeformVert *dvert,
+ const int defgrp_index,
+ float (*vertexCos)[3],
+ int numVerts)
{
- DerivedMesh *ss_mesh = NULL;
- ShrinkwrapCalcData calc = NULL_ShrinkwrapCalcData;
-
- /* remove loop dependencies on derived meshes (TODO should this be done elsewhere?) */
- if (smd->target == ob) smd->target = NULL;
- if (smd->auxTarget == ob) smd->auxTarget = NULL;
-
-
- /* Configure Shrinkwrap calc data */
- calc.smd = smd;
- calc.ob = ob;
- calc.numVerts = numVerts;
- calc.vertexCos = vertexCos;
- calc.dvert = dvert;
- calc.vgroup = defgrp_index;
- calc.invert_vgroup = (smd->shrinkOpts & MOD_SHRINKWRAP_INVERT_VGROUP) != 0;
-
- if (smd->target != NULL) {
- Object *ob_target = DEG_get_evaluated_object(ctx->depsgraph, smd->target);
- calc.target = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_target, false);
-
- /* TODO there might be several "bugs" on non-uniform scales matrixs
- * because it will no longer be nearest surface, not sphere projection
- * because space has been deformed */
- BLI_SPACE_TRANSFORM_SETUP(&calc.local2target, ob, ob_target);
-
- /* TODO: smd->keepDist is in global units.. must change to local */
- calc.keepDist = smd->keepDist;
- }
- calc.aux_target = DEG_get_evaluated_object(ctx->depsgraph, smd->auxTarget);
-
- if (mesh != NULL && smd->shrinkType == MOD_SHRINKWRAP_PROJECT) {
- /* Setup arrays to get vertexs positions, normals and deform weights */
- calc.vert = mesh->mvert;
-
- /* Using vertexs positions/normals as if a subsurface was applied */
- if (smd->subsurfLevels) {
- SubsurfModifierData ssmd = {{NULL}};
- ssmd.subdivType = ME_CC_SUBSURF; /* catmull clark */
- ssmd.levels = smd->subsurfLevels; /* levels */
-
- /* TODO to be moved to Mesh once we are done with changes in subsurf code. */
- DerivedMesh *dm = CDDM_from_mesh(mesh);
-
- ss_mesh = subsurf_make_derived_from_derived(dm, &ssmd, scene, NULL, (ob->mode & OB_MODE_EDIT) ? SUBSURF_IN_EDIT_MODE : 0);
-
- if (ss_mesh) {
- calc.vert = ss_mesh->getVertDataArray(ss_mesh, CD_MVERT);
- if (calc.vert) {
- /* TRICKY: this code assumes subsurface will have the transformed original vertices
- * in their original order at the end of the vert array. */
- calc.vert = calc.vert + ss_mesh->getNumVerts(ss_mesh) - dm->getNumVerts(dm);
- }
- }
-
- /* Just to make sure we are not leaving any memory behind */
- BLI_assert(ssmd.emCache == NULL);
- BLI_assert(ssmd.mCache == NULL);
-
- dm->release(dm);
- }
- }
-
- /* Projecting target defined - lets work! */
- ShrinkwrapTreeData tree;
-
- if (BKE_shrinkwrap_init_tree(&tree, calc.target, smd->shrinkType, smd->shrinkMode, false)) {
- calc.tree = &tree;
-
- switch (smd->shrinkType) {
- case MOD_SHRINKWRAP_NEAREST_SURFACE:
- case MOD_SHRINKWRAP_TARGET_PROJECT:
- TIMEIT_BENCH(shrinkwrap_calc_nearest_surface_point(&calc), deform_surface);
- break;
-
- case MOD_SHRINKWRAP_PROJECT:
- TIMEIT_BENCH(shrinkwrap_calc_normal_projection(&calc), deform_project);
- break;
-
- case MOD_SHRINKWRAP_NEAREST_VERTEX:
- TIMEIT_BENCH(shrinkwrap_calc_nearest_vertex(&calc), deform_vertex);
- break;
- }
-
- BKE_shrinkwrap_free_tree(&tree);
- }
-
- /* free memory */
- if (ss_mesh)
- ss_mesh->release(ss_mesh);
+ DerivedMesh *ss_mesh = NULL;
+ ShrinkwrapCalcData calc = NULL_ShrinkwrapCalcData;
+
+ /* remove loop dependencies on derived meshes (TODO should this be done elsewhere?) */
+ if (smd->target == ob)
+ smd->target = NULL;
+ if (smd->auxTarget == ob)
+ smd->auxTarget = NULL;
+
+ /* Configure Shrinkwrap calc data */
+ calc.smd = smd;
+ calc.ob = ob;
+ calc.numVerts = numVerts;
+ calc.vertexCos = vertexCos;
+ calc.dvert = dvert;
+ calc.vgroup = defgrp_index;
+ calc.invert_vgroup = (smd->shrinkOpts & MOD_SHRINKWRAP_INVERT_VGROUP) != 0;
+
+ if (smd->target != NULL) {
+ Object *ob_target = DEG_get_evaluated_object(ctx->depsgraph, smd->target);
+ calc.target = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_target, false);
+
+ /* TODO there might be several "bugs" on non-uniform scales matrixs
+ * because it will no longer be nearest surface, not sphere projection
+ * because space has been deformed */
+ BLI_SPACE_TRANSFORM_SETUP(&calc.local2target, ob, ob_target);
+
+ /* TODO: smd->keepDist is in global units.. must change to local */
+ calc.keepDist = smd->keepDist;
+ }
+ calc.aux_target = DEG_get_evaluated_object(ctx->depsgraph, smd->auxTarget);
+
+ if (mesh != NULL && smd->shrinkType == MOD_SHRINKWRAP_PROJECT) {
+ /* Setup arrays to get vertexs positions, normals and deform weights */
+ calc.vert = mesh->mvert;
+
+ /* Using vertexs positions/normals as if a subsurface was applied */
+ if (smd->subsurfLevels) {
+ SubsurfModifierData ssmd = {{NULL}};
+ ssmd.subdivType = ME_CC_SUBSURF; /* catmull clark */
+ ssmd.levels = smd->subsurfLevels; /* levels */
+
+ /* TODO to be moved to Mesh once we are done with changes in subsurf code. */
+ DerivedMesh *dm = CDDM_from_mesh(mesh);
+
+ ss_mesh = subsurf_make_derived_from_derived(
+ dm, &ssmd, scene, NULL, (ob->mode & OB_MODE_EDIT) ? SUBSURF_IN_EDIT_MODE : 0);
+
+ if (ss_mesh) {
+ calc.vert = ss_mesh->getVertDataArray(ss_mesh, CD_MVERT);
+ if (calc.vert) {
+ /* TRICKY: this code assumes subsurface will have the transformed original vertices
+ * in their original order at the end of the vert array. */
+ calc.vert = calc.vert + ss_mesh->getNumVerts(ss_mesh) - dm->getNumVerts(dm);
+ }
+ }
+
+ /* Just to make sure we are not leaving any memory behind */
+ BLI_assert(ssmd.emCache == NULL);
+ BLI_assert(ssmd.mCache == NULL);
+
+ dm->release(dm);
+ }
+ }
+
+ /* Projecting target defined - lets work! */
+ ShrinkwrapTreeData tree;
+
+ if (BKE_shrinkwrap_init_tree(&tree, calc.target, smd->shrinkType, smd->shrinkMode, false)) {
+ calc.tree = &tree;
+
+ switch (smd->shrinkType) {
+ case MOD_SHRINKWRAP_NEAREST_SURFACE:
+ case MOD_SHRINKWRAP_TARGET_PROJECT:
+ TIMEIT_BENCH(shrinkwrap_calc_nearest_surface_point(&calc), deform_surface);
+ break;
+
+ case MOD_SHRINKWRAP_PROJECT:
+ TIMEIT_BENCH(shrinkwrap_calc_normal_projection(&calc), deform_project);
+ break;
+
+ case MOD_SHRINKWRAP_NEAREST_VERTEX:
+ TIMEIT_BENCH(shrinkwrap_calc_nearest_vertex(&calc), deform_vertex);
+ break;
+ }
+
+ BKE_shrinkwrap_free_tree(&tree);
+ }
+
+ /* free memory */
+ if (ss_mesh)
+ ss_mesh->release(ss_mesh);
}
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c
index 122bb5a19c5..23cdf802c81 100644
--- a/source/blender/blenkernel/intern/smoke.c
+++ b/source/blender/blenkernel/intern/smoke.c
@@ -21,7 +21,6 @@
* \ingroup bke
*/
-
/* Part of the code copied from elbeem fluid library, copyright by Nils Thuerey */
#include "MEM_guardedalloc.h"
@@ -89,11 +88,11 @@
#ifdef WITH_SMOKE
-#include "smoke_API.h"
+# include "smoke_API.h"
-#include "BLI_task.h"
-#include "BLI_kdtree.h"
-#include "BLI_voxel.h"
+# include "BLI_task.h"
+# include "BLI_kdtree.h"
+# include "BLI_voxel.h"
static ThreadMutex object_update_lock = BLI_MUTEX_INITIALIZER;
@@ -103,26 +102,66 @@ struct Scene;
struct SmokeModifierData;
// timestep default value for nice appearance 0.1f
-#define DT_DEFAULT 0.1f
+# define DT_DEFAULT 0.1f
-#define ADD_IF_LOWER_POS(a, b) (min_ff((a) + (b), max_ff((a), (b))))
-#define ADD_IF_LOWER_NEG(a, b) (max_ff((a) + (b), min_ff((a), (b))))
-#define ADD_IF_LOWER(a, b) (((b) > 0) ? ADD_IF_LOWER_POS((a), (b)) : ADD_IF_LOWER_NEG((a), (b)))
+# define ADD_IF_LOWER_POS(a, b) (min_ff((a) + (b), max_ff((a), (b))))
+# define ADD_IF_LOWER_NEG(a, b) (max_ff((a) + (b), min_ff((a), (b))))
+# define ADD_IF_LOWER(a, b) (((b) > 0) ? ADD_IF_LOWER_POS((a), (b)) : ADD_IF_LOWER_NEG((a), (b)))
#else /* WITH_SMOKE */
/* Stubs to use when smoke is disabled */
-struct WTURBULENCE *smoke_turbulence_init(int *UNUSED(res), int UNUSED(amplify), int UNUSED(noisetype), const char *UNUSED(noisefile_path), int UNUSED(use_fire), int UNUSED(use_colors)) { return NULL; }
+struct WTURBULENCE *smoke_turbulence_init(int *UNUSED(res),
+ int UNUSED(amplify),
+ int UNUSED(noisetype),
+ const char *UNUSED(noisefile_path),
+ int UNUSED(use_fire),
+ int UNUSED(use_colors))
+{
+ return NULL;
+}
//struct FLUID_3D *smoke_init(int *UNUSED(res), float *UNUSED(dx), float *UNUSED(dtdef), int UNUSED(use_heat), int UNUSED(use_fire), int UNUSED(use_colors)) { return NULL; }
-void smoke_free(struct FLUID_3D *UNUSED(fluid)) {}
-float *smoke_get_density(struct FLUID_3D *UNUSED(fluid)) { return NULL; }
-void smoke_turbulence_free(struct WTURBULENCE *UNUSED(wt)) {}
-void smoke_initWaveletBlenderRNA(struct WTURBULENCE *UNUSED(wt), float *UNUSED(strength)) {}
-void smoke_initBlenderRNA(struct FLUID_3D *UNUSED(fluid), float *UNUSED(alpha), float *UNUSED(beta), float *UNUSED(dt_factor), float *UNUSED(vorticity),
- int *UNUSED(border_colli), float *UNUSED(burning_rate), float *UNUSED(flame_smoke), float *UNUSED(flame_smoke_color),
- float *UNUSED(flame_vorticity), float *UNUSED(flame_ignition_temp), float *UNUSED(flame_max_temp)) {}
-struct Mesh *smokeModifier_do(SmokeModifierData *UNUSED(smd), Depsgraph *UNUSED(depsgraph), Scene *UNUSED(scene), Object *UNUSED(ob), Mesh *UNUSED(me)) { return NULL; }
-float BKE_smoke_get_velocity_at(struct Object *UNUSED(ob), float UNUSED(position[3]), float UNUSED(velocity[3])) { return 0.0f; }
+void smoke_free(struct FLUID_3D *UNUSED(fluid))
+{
+}
+float *smoke_get_density(struct FLUID_3D *UNUSED(fluid))
+{
+ return NULL;
+}
+void smoke_turbulence_free(struct WTURBULENCE *UNUSED(wt))
+{
+}
+void smoke_initWaveletBlenderRNA(struct WTURBULENCE *UNUSED(wt), float *UNUSED(strength))
+{
+}
+void smoke_initBlenderRNA(struct FLUID_3D *UNUSED(fluid),
+ float *UNUSED(alpha),
+ float *UNUSED(beta),
+ float *UNUSED(dt_factor),
+ float *UNUSED(vorticity),
+ int *UNUSED(border_colli),
+ float *UNUSED(burning_rate),
+ float *UNUSED(flame_smoke),
+ float *UNUSED(flame_smoke_color),
+ float *UNUSED(flame_vorticity),
+ float *UNUSED(flame_ignition_temp),
+ float *UNUSED(flame_max_temp))
+{
+}
+struct Mesh *smokeModifier_do(SmokeModifierData *UNUSED(smd),
+ Depsgraph *UNUSED(depsgraph),
+ Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ Mesh *UNUSED(me))
+{
+ return NULL;
+}
+float BKE_smoke_get_velocity_at(struct Object *UNUSED(ob),
+ float UNUSED(position[3]),
+ float UNUSED(velocity[3]))
+{
+ return 0.0f;
+}
#endif /* WITH_SMOKE */
@@ -130,613 +169,616 @@ float BKE_smoke_get_velocity_at(struct Object *UNUSED(ob), float UNUSED(position
void BKE_smoke_reallocate_fluid(SmokeDomainSettings *sds, float dx, int res[3], int free_old)
{
- int use_heat = (sds->active_fields & SM_ACTIVE_HEAT);
- int use_fire = (sds->active_fields & SM_ACTIVE_FIRE);
- int use_colors = (sds->active_fields & SM_ACTIVE_COLORS);
-
- if (free_old && sds->fluid)
- smoke_free(sds->fluid);
- if (!min_iii(res[0], res[1], res[2])) {
- sds->fluid = NULL;
- return;
- }
- sds->fluid = smoke_init(res, dx, DT_DEFAULT, use_heat, use_fire, use_colors);
- smoke_initBlenderRNA(sds->fluid, &(sds->alpha), &(sds->beta), &(sds->time_scale), &(sds->vorticity), &(sds->border_collisions),
- &(sds->burning_rate), &(sds->flame_smoke), sds->flame_smoke_color, &(sds->flame_vorticity), &(sds->flame_ignition), &(sds->flame_max_temp));
-
- /* reallocate shadow buffer */
- if (sds->shadow)
- MEM_freeN(sds->shadow);
- sds->shadow = MEM_callocN(sizeof(float) * res[0] * res[1] * res[2], "SmokeDomainShadow");
+ int use_heat = (sds->active_fields & SM_ACTIVE_HEAT);
+ int use_fire = (sds->active_fields & SM_ACTIVE_FIRE);
+ int use_colors = (sds->active_fields & SM_ACTIVE_COLORS);
+
+ if (free_old && sds->fluid)
+ smoke_free(sds->fluid);
+ if (!min_iii(res[0], res[1], res[2])) {
+ sds->fluid = NULL;
+ return;
+ }
+ sds->fluid = smoke_init(res, dx, DT_DEFAULT, use_heat, use_fire, use_colors);
+ smoke_initBlenderRNA(sds->fluid,
+ &(sds->alpha),
+ &(sds->beta),
+ &(sds->time_scale),
+ &(sds->vorticity),
+ &(sds->border_collisions),
+ &(sds->burning_rate),
+ &(sds->flame_smoke),
+ sds->flame_smoke_color,
+ &(sds->flame_vorticity),
+ &(sds->flame_ignition),
+ &(sds->flame_max_temp));
+
+ /* reallocate shadow buffer */
+ if (sds->shadow)
+ MEM_freeN(sds->shadow);
+ sds->shadow = MEM_callocN(sizeof(float) * res[0] * res[1] * res[2], "SmokeDomainShadow");
}
-void BKE_smoke_reallocate_highres_fluid(SmokeDomainSettings *sds, float dx, int res[3], int free_old)
+void BKE_smoke_reallocate_highres_fluid(SmokeDomainSettings *sds,
+ float dx,
+ int res[3],
+ int free_old)
{
- int use_fire = (sds->active_fields & (SM_ACTIVE_HEAT | SM_ACTIVE_FIRE));
- int use_colors = (sds->active_fields & SM_ACTIVE_COLORS);
+ int use_fire = (sds->active_fields & (SM_ACTIVE_HEAT | SM_ACTIVE_FIRE));
+ int use_colors = (sds->active_fields & SM_ACTIVE_COLORS);
- if (free_old && sds->wt)
- smoke_turbulence_free(sds->wt);
- if (!min_iii(res[0], res[1], res[2])) {
- sds->wt = NULL;
- return;
- }
+ if (free_old && sds->wt)
+ smoke_turbulence_free(sds->wt);
+ if (!min_iii(res[0], res[1], res[2])) {
+ sds->wt = NULL;
+ return;
+ }
- /* smoke_turbulence_init uses non-threadsafe functions from fftw3 lib (like fftw_plan & co). */
- BLI_thread_lock(LOCK_FFTW);
+ /* smoke_turbulence_init uses non-threadsafe functions from fftw3 lib (like fftw_plan & co). */
+ BLI_thread_lock(LOCK_FFTW);
- sds->wt = smoke_turbulence_init(res, sds->amplify + 1, sds->noise, BKE_tempdir_session(), use_fire, use_colors);
+ sds->wt = smoke_turbulence_init(
+ res, sds->amplify + 1, sds->noise, BKE_tempdir_session(), use_fire, use_colors);
- BLI_thread_unlock(LOCK_FFTW);
+ BLI_thread_unlock(LOCK_FFTW);
- sds->res_wt[0] = res[0] * (sds->amplify + 1);
- sds->res_wt[1] = res[1] * (sds->amplify + 1);
- sds->res_wt[2] = res[2] * (sds->amplify + 1);
- sds->dx_wt = dx / (sds->amplify + 1);
- smoke_initWaveletBlenderRNA(sds->wt, &(sds->strength));
+ sds->res_wt[0] = res[0] * (sds->amplify + 1);
+ sds->res_wt[1] = res[1] * (sds->amplify + 1);
+ sds->res_wt[2] = res[2] * (sds->amplify + 1);
+ sds->dx_wt = dx / (sds->amplify + 1);
+ smoke_initWaveletBlenderRNA(sds->wt, &(sds->strength));
}
/* convert global position to domain cell space */
static void smoke_pos_to_cell(SmokeDomainSettings *sds, float pos[3])
{
- mul_m4_v3(sds->imat, pos);
- sub_v3_v3(pos, sds->p0);
- pos[0] *= 1.0f / sds->cell_size[0];
- pos[1] *= 1.0f / sds->cell_size[1];
- pos[2] *= 1.0f / sds->cell_size[2];
+ mul_m4_v3(sds->imat, pos);
+ sub_v3_v3(pos, sds->p0);
+ pos[0] *= 1.0f / sds->cell_size[0];
+ pos[1] *= 1.0f / sds->cell_size[1];
+ pos[2] *= 1.0f / sds->cell_size[2];
}
/* set domain transformations and base resolution from object mesh */
-static void smoke_set_domain_from_mesh(SmokeDomainSettings *sds, Object *ob, Mesh *me, bool init_resolution)
+static void smoke_set_domain_from_mesh(SmokeDomainSettings *sds,
+ Object *ob,
+ Mesh *me,
+ bool init_resolution)
{
- size_t i;
- float min[3] = {FLT_MAX, FLT_MAX, FLT_MAX}, max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
- float size[3];
- MVert *verts = me->mvert;
- float scale = 0.0;
- int res;
-
- res = sds->maxres;
-
- // get BB of domain
- for (i = 0; i < me->totvert; i++)
- {
- // min BB
- min[0] = MIN2(min[0], verts[i].co[0]);
- min[1] = MIN2(min[1], verts[i].co[1]);
- min[2] = MIN2(min[2], verts[i].co[2]);
-
- // max BB
- max[0] = MAX2(max[0], verts[i].co[0]);
- max[1] = MAX2(max[1], verts[i].co[1]);
- max[2] = MAX2(max[2], verts[i].co[2]);
- }
-
- /* set domain bounds */
- copy_v3_v3(sds->p0, min);
- copy_v3_v3(sds->p1, max);
- sds->dx = 1.0f / res;
-
- /* calculate domain dimensions */
- sub_v3_v3v3(size, max, min);
- if (init_resolution) {
- zero_v3_int(sds->base_res);
- copy_v3_v3(sds->cell_size, size);
- }
- /* apply object scale */
- for (i = 0; i < 3; i++) {
- size[i] = fabsf(size[i] * ob->scale[i]);
- }
- copy_v3_v3(sds->global_size, size);
- copy_v3_v3(sds->dp0, min);
-
- invert_m4_m4(sds->imat, ob->obmat);
-
- // prevent crash when initializing a plane as domain
- if (!init_resolution || (size[0] < FLT_EPSILON) || (size[1] < FLT_EPSILON) || (size[2] < FLT_EPSILON))
- return;
-
- /* define grid resolutions from longest domain side */
- if (size[0] >= MAX2(size[1], size[2])) {
- scale = res / size[0];
- sds->scale = size[0] / fabsf(ob->scale[0]);
- sds->base_res[0] = res;
- sds->base_res[1] = max_ii((int)(size[1] * scale + 0.5f), 4);
- sds->base_res[2] = max_ii((int)(size[2] * scale + 0.5f), 4);
- }
- else if (size[1] >= MAX2(size[0], size[2])) {
- scale = res / size[1];
- sds->scale = size[1] / fabsf(ob->scale[1]);
- sds->base_res[0] = max_ii((int)(size[0] * scale + 0.5f), 4);
- sds->base_res[1] = res;
- sds->base_res[2] = max_ii((int)(size[2] * scale + 0.5f), 4);
- }
- else {
- scale = res / size[2];
- sds->scale = size[2] / fabsf(ob->scale[2]);
- sds->base_res[0] = max_ii((int)(size[0] * scale + 0.5f), 4);
- sds->base_res[1] = max_ii((int)(size[1] * scale + 0.5f), 4);
- sds->base_res[2] = res;
- }
-
- /* set cell size */
- sds->cell_size[0] /= (float)sds->base_res[0];
- sds->cell_size[1] /= (float)sds->base_res[1];
- sds->cell_size[2] /= (float)sds->base_res[2];
+ size_t i;
+ float min[3] = {FLT_MAX, FLT_MAX, FLT_MAX}, max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
+ float size[3];
+ MVert *verts = me->mvert;
+ float scale = 0.0;
+ int res;
+
+ res = sds->maxres;
+
+ // get BB of domain
+ for (i = 0; i < me->totvert; i++) {
+ // min BB
+ min[0] = MIN2(min[0], verts[i].co[0]);
+ min[1] = MIN2(min[1], verts[i].co[1]);
+ min[2] = MIN2(min[2], verts[i].co[2]);
+
+ // max BB
+ max[0] = MAX2(max[0], verts[i].co[0]);
+ max[1] = MAX2(max[1], verts[i].co[1]);
+ max[2] = MAX2(max[2], verts[i].co[2]);
+ }
+
+ /* set domain bounds */
+ copy_v3_v3(sds->p0, min);
+ copy_v3_v3(sds->p1, max);
+ sds->dx = 1.0f / res;
+
+ /* calculate domain dimensions */
+ sub_v3_v3v3(size, max, min);
+ if (init_resolution) {
+ zero_v3_int(sds->base_res);
+ copy_v3_v3(sds->cell_size, size);
+ }
+ /* apply object scale */
+ for (i = 0; i < 3; i++) {
+ size[i] = fabsf(size[i] * ob->scale[i]);
+ }
+ copy_v3_v3(sds->global_size, size);
+ copy_v3_v3(sds->dp0, min);
+
+ invert_m4_m4(sds->imat, ob->obmat);
+
+ // prevent crash when initializing a plane as domain
+ if (!init_resolution || (size[0] < FLT_EPSILON) || (size[1] < FLT_EPSILON) ||
+ (size[2] < FLT_EPSILON))
+ return;
+
+ /* define grid resolutions from longest domain side */
+ if (size[0] >= MAX2(size[1], size[2])) {
+ scale = res / size[0];
+ sds->scale = size[0] / fabsf(ob->scale[0]);
+ sds->base_res[0] = res;
+ sds->base_res[1] = max_ii((int)(size[1] * scale + 0.5f), 4);
+ sds->base_res[2] = max_ii((int)(size[2] * scale + 0.5f), 4);
+ }
+ else if (size[1] >= MAX2(size[0], size[2])) {
+ scale = res / size[1];
+ sds->scale = size[1] / fabsf(ob->scale[1]);
+ sds->base_res[0] = max_ii((int)(size[0] * scale + 0.5f), 4);
+ sds->base_res[1] = res;
+ sds->base_res[2] = max_ii((int)(size[2] * scale + 0.5f), 4);
+ }
+ else {
+ scale = res / size[2];
+ sds->scale = size[2] / fabsf(ob->scale[2]);
+ sds->base_res[0] = max_ii((int)(size[0] * scale + 0.5f), 4);
+ sds->base_res[1] = max_ii((int)(size[1] * scale + 0.5f), 4);
+ sds->base_res[2] = res;
+ }
+
+ /* set cell size */
+ sds->cell_size[0] /= (float)sds->base_res[0];
+ sds->cell_size[1] /= (float)sds->base_res[1];
+ sds->cell_size[2] /= (float)sds->base_res[2];
}
static int smokeModifier_init(SmokeModifierData *smd, Object *ob, int scene_framenr, Mesh *me)
{
- if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && !smd->domain->fluid)
- {
- SmokeDomainSettings *sds = smd->domain;
- int res[3];
- /* set domain dimensions from mesh */
- smoke_set_domain_from_mesh(sds, ob, me, true);
- /* reset domain values */
- zero_v3_int(sds->shift);
- zero_v3(sds->shift_f);
- add_v3_fl(sds->shift_f, 0.5f);
- zero_v3(sds->prev_loc);
- mul_m4_v3(ob->obmat, sds->prev_loc);
- copy_m4_m4(sds->obmat, ob->obmat);
-
- /* set resolutions */
- if (smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
- res[0] = res[1] = res[2] = 1; /* use minimum res for adaptive init */
- }
- else {
- copy_v3_v3_int(res, sds->base_res);
- }
- copy_v3_v3_int(sds->res, res);
- sds->total_cells = sds->res[0] * sds->res[1] * sds->res[2];
- sds->res_min[0] = sds->res_min[1] = sds->res_min[2] = 0;
- copy_v3_v3_int(sds->res_max, res);
-
- /* allocate fluid */
- BKE_smoke_reallocate_fluid(sds, sds->dx, sds->res, 0);
-
- smd->time = scene_framenr;
-
- /* allocate highres fluid */
- if (sds->flags & MOD_SMOKE_HIGHRES) {
- BKE_smoke_reallocate_highres_fluid(sds, sds->dx, sds->res, 0);
- }
- /* allocate shadow buffer */
- if (!sds->shadow)
- sds->shadow = MEM_callocN(sizeof(float) * sds->res[0] * sds->res[1] * sds->res[2], "SmokeDomainShadow");
-
- return 1;
- }
- else if ((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow)
- {
- smd->time = scene_framenr;
-
- return 1;
- }
- else if ((smd->type & MOD_SMOKE_TYPE_COLL))
- {
- if (!smd->coll)
- {
- smokeModifier_createType(smd);
- }
-
- smd->time = scene_framenr;
-
- return 1;
- }
-
- return 2;
+ if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && !smd->domain->fluid) {
+ SmokeDomainSettings *sds = smd->domain;
+ int res[3];
+ /* set domain dimensions from mesh */
+ smoke_set_domain_from_mesh(sds, ob, me, true);
+ /* reset domain values */
+ zero_v3_int(sds->shift);
+ zero_v3(sds->shift_f);
+ add_v3_fl(sds->shift_f, 0.5f);
+ zero_v3(sds->prev_loc);
+ mul_m4_v3(ob->obmat, sds->prev_loc);
+ copy_m4_m4(sds->obmat, ob->obmat);
+
+ /* set resolutions */
+ if (smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
+ res[0] = res[1] = res[2] = 1; /* use minimum res for adaptive init */
+ }
+ else {
+ copy_v3_v3_int(res, sds->base_res);
+ }
+ copy_v3_v3_int(sds->res, res);
+ sds->total_cells = sds->res[0] * sds->res[1] * sds->res[2];
+ sds->res_min[0] = sds->res_min[1] = sds->res_min[2] = 0;
+ copy_v3_v3_int(sds->res_max, res);
+
+ /* allocate fluid */
+ BKE_smoke_reallocate_fluid(sds, sds->dx, sds->res, 0);
+
+ smd->time = scene_framenr;
+
+ /* allocate highres fluid */
+ if (sds->flags & MOD_SMOKE_HIGHRES) {
+ BKE_smoke_reallocate_highres_fluid(sds, sds->dx, sds->res, 0);
+ }
+ /* allocate shadow buffer */
+ if (!sds->shadow)
+ sds->shadow = MEM_callocN(sizeof(float) * sds->res[0] * sds->res[1] * sds->res[2],
+ "SmokeDomainShadow");
+
+ return 1;
+ }
+ else if ((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) {
+ smd->time = scene_framenr;
+
+ return 1;
+ }
+ else if ((smd->type & MOD_SMOKE_TYPE_COLL)) {
+ if (!smd->coll) {
+ smokeModifier_createType(smd);
+ }
+
+ smd->time = scene_framenr;
+
+ return 1;
+ }
+
+ return 2;
}
#endif /* WITH_SMOKE */
static void smokeModifier_freeDomain(SmokeModifierData *smd)
{
- if (smd->domain)
- {
- if (smd->domain->shadow)
- MEM_freeN(smd->domain->shadow);
- smd->domain->shadow = NULL;
+ if (smd->domain) {
+ if (smd->domain->shadow)
+ MEM_freeN(smd->domain->shadow);
+ smd->domain->shadow = NULL;
- if (smd->domain->fluid)
- smoke_free(smd->domain->fluid);
+ if (smd->domain->fluid)
+ smoke_free(smd->domain->fluid);
- if (smd->domain->fluid_mutex)
- BLI_rw_mutex_free(smd->domain->fluid_mutex);
+ if (smd->domain->fluid_mutex)
+ BLI_rw_mutex_free(smd->domain->fluid_mutex);
- if (smd->domain->wt)
- smoke_turbulence_free(smd->domain->wt);
+ if (smd->domain->wt)
+ smoke_turbulence_free(smd->domain->wt);
- if (smd->domain->effector_weights)
- MEM_freeN(smd->domain->effector_weights);
- smd->domain->effector_weights = NULL;
+ if (smd->domain->effector_weights)
+ MEM_freeN(smd->domain->effector_weights);
+ smd->domain->effector_weights = NULL;
- if (!(smd->modifier.flag & eModifierFlag_SharedCaches)) {
- BKE_ptcache_free_list(&(smd->domain->ptcaches[0]));
- smd->domain->point_cache[0] = NULL;
- }
+ if (!(smd->modifier.flag & eModifierFlag_SharedCaches)) {
+ BKE_ptcache_free_list(&(smd->domain->ptcaches[0]));
+ smd->domain->point_cache[0] = NULL;
+ }
- if (smd->domain->coba) {
- MEM_freeN(smd->domain->coba);
- }
+ if (smd->domain->coba) {
+ MEM_freeN(smd->domain->coba);
+ }
- MEM_freeN(smd->domain);
- smd->domain = NULL;
- }
+ MEM_freeN(smd->domain);
+ smd->domain = NULL;
+ }
}
static void smokeModifier_freeFlow(SmokeModifierData *smd)
{
- if (smd->flow)
- {
- if (smd->flow->mesh) BKE_id_free(NULL, smd->flow->mesh);
- if (smd->flow->verts_old) MEM_freeN(smd->flow->verts_old);
- MEM_freeN(smd->flow);
- smd->flow = NULL;
- }
+ if (smd->flow) {
+ if (smd->flow->mesh)
+ BKE_id_free(NULL, smd->flow->mesh);
+ if (smd->flow->verts_old)
+ MEM_freeN(smd->flow->verts_old);
+ MEM_freeN(smd->flow);
+ smd->flow = NULL;
+ }
}
static void smokeModifier_freeCollision(SmokeModifierData *smd)
{
- if (smd->coll)
- {
- SmokeCollSettings *scs = smd->coll;
-
- if (scs->numverts)
- {
- if (scs->verts_old)
- {
- MEM_freeN(scs->verts_old);
- scs->verts_old = NULL;
- }
- }
-
- if (smd->coll->mesh)
- BKE_id_free(NULL, smd->coll->mesh);
- smd->coll->mesh = NULL;
-
- MEM_freeN(smd->coll);
- smd->coll = NULL;
- }
+ if (smd->coll) {
+ SmokeCollSettings *scs = smd->coll;
+
+ if (scs->numverts) {
+ if (scs->verts_old) {
+ MEM_freeN(scs->verts_old);
+ scs->verts_old = NULL;
+ }
+ }
+
+ if (smd->coll->mesh)
+ BKE_id_free(NULL, smd->coll->mesh);
+ smd->coll->mesh = NULL;
+
+ MEM_freeN(smd->coll);
+ smd->coll = NULL;
+ }
}
void smokeModifier_reset_turbulence(struct SmokeModifierData *smd)
{
- if (smd && smd->domain && smd->domain->wt)
- {
- smoke_turbulence_free(smd->domain->wt);
- smd->domain->wt = NULL;
- }
+ if (smd && smd->domain && smd->domain->wt) {
+ smoke_turbulence_free(smd->domain->wt);
+ smd->domain->wt = NULL;
+ }
}
static void smokeModifier_reset_ex(struct SmokeModifierData *smd, bool need_lock)
{
- if (smd)
- {
- if (smd->domain)
- {
- if (smd->domain->shadow)
- MEM_freeN(smd->domain->shadow);
- smd->domain->shadow = NULL;
-
- if (smd->domain->fluid)
- {
- if (need_lock)
- BLI_rw_mutex_lock(smd->domain->fluid_mutex, THREAD_LOCK_WRITE);
-
- smoke_free(smd->domain->fluid);
- smd->domain->fluid = NULL;
-
- if (need_lock)
- BLI_rw_mutex_unlock(smd->domain->fluid_mutex);
- }
-
- smokeModifier_reset_turbulence(smd);
-
- smd->time = -1;
- smd->domain->total_cells = 0;
- smd->domain->active_fields = 0;
- }
- else if (smd->flow)
- {
- if (smd->flow->verts_old) MEM_freeN(smd->flow->verts_old);
- smd->flow->verts_old = NULL;
- smd->flow->numverts = 0;
- }
- else if (smd->coll)
- {
- SmokeCollSettings *scs = smd->coll;
-
- if (scs->numverts && scs->verts_old)
- {
- MEM_freeN(scs->verts_old);
- scs->verts_old = NULL;
- }
- }
- }
+ if (smd) {
+ if (smd->domain) {
+ if (smd->domain->shadow)
+ MEM_freeN(smd->domain->shadow);
+ smd->domain->shadow = NULL;
+
+ if (smd->domain->fluid) {
+ if (need_lock)
+ BLI_rw_mutex_lock(smd->domain->fluid_mutex, THREAD_LOCK_WRITE);
+
+ smoke_free(smd->domain->fluid);
+ smd->domain->fluid = NULL;
+
+ if (need_lock)
+ BLI_rw_mutex_unlock(smd->domain->fluid_mutex);
+ }
+
+ smokeModifier_reset_turbulence(smd);
+
+ smd->time = -1;
+ smd->domain->total_cells = 0;
+ smd->domain->active_fields = 0;
+ }
+ else if (smd->flow) {
+ if (smd->flow->verts_old)
+ MEM_freeN(smd->flow->verts_old);
+ smd->flow->verts_old = NULL;
+ smd->flow->numverts = 0;
+ }
+ else if (smd->coll) {
+ SmokeCollSettings *scs = smd->coll;
+
+ if (scs->numverts && scs->verts_old) {
+ MEM_freeN(scs->verts_old);
+ scs->verts_old = NULL;
+ }
+ }
+ }
}
void smokeModifier_reset(struct SmokeModifierData *smd)
{
- smokeModifier_reset_ex(smd, true);
+ smokeModifier_reset_ex(smd, true);
}
void smokeModifier_free(SmokeModifierData *smd)
{
- if (smd)
- {
- smokeModifier_freeDomain(smd);
- smokeModifier_freeFlow(smd);
- smokeModifier_freeCollision(smd);
- }
+ if (smd) {
+ smokeModifier_freeDomain(smd);
+ smokeModifier_freeFlow(smd);
+ smokeModifier_freeCollision(smd);
+ }
}
void smokeModifier_createType(struct SmokeModifierData *smd)
{
- if (smd)
- {
- if (smd->type & MOD_SMOKE_TYPE_DOMAIN)
- {
- if (smd->domain)
- smokeModifier_freeDomain(smd);
-
- smd->domain = MEM_callocN(sizeof(SmokeDomainSettings), "SmokeDomain");
-
- smd->domain->smd = smd;
-
- smd->domain->point_cache[0] = BKE_ptcache_add(&(smd->domain->ptcaches[0]));
- smd->domain->point_cache[0]->flag |= PTCACHE_DISK_CACHE;
- smd->domain->point_cache[0]->step = 1;
-
- /* Deprecated */
- smd->domain->point_cache[1] = NULL;
- BLI_listbase_clear(&smd->domain->ptcaches[1]);
- /* set some standard values */
- smd->domain->fluid = NULL;
- smd->domain->fluid_mutex = BLI_rw_mutex_alloc();
- smd->domain->wt = NULL;
- smd->domain->eff_group = NULL;
- smd->domain->fluid_group = NULL;
- smd->domain->coll_group = NULL;
- smd->domain->maxres = 32;
- smd->domain->amplify = 1;
- smd->domain->alpha = -0.001;
- smd->domain->beta = 0.1;
- smd->domain->time_scale = 1.0;
- smd->domain->vorticity = 2.0;
- smd->domain->border_collisions = SM_BORDER_OPEN; // open domain
- smd->domain->flags = MOD_SMOKE_DISSOLVE_LOG;
- smd->domain->highres_sampling = SM_HRES_FULLSAMPLE;
- smd->domain->strength = 2.0;
- smd->domain->noise = MOD_SMOKE_NOISEWAVE;
- smd->domain->diss_speed = 5;
- smd->domain->active_fields = 0;
-
- smd->domain->adapt_margin = 4;
- smd->domain->adapt_res = 0;
- smd->domain->adapt_threshold = 0.02f;
-
- smd->domain->burning_rate = 0.75f;
- smd->domain->flame_smoke = 1.0f;
- smd->domain->flame_vorticity = 0.5f;
- smd->domain->flame_ignition = 1.5f;
- smd->domain->flame_max_temp = 3.0f;
- /* color */
- smd->domain->flame_smoke_color[0] = 0.7f;
- smd->domain->flame_smoke_color[1] = 0.7f;
- smd->domain->flame_smoke_color[2] = 0.7f;
-
- smd->domain->viewsettings = MOD_SMOKE_VIEW_SHOW_HIGHRES;
- smd->domain->effector_weights = BKE_effector_add_weights(NULL);
+ if (smd) {
+ if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
+ if (smd->domain)
+ smokeModifier_freeDomain(smd);
+
+ smd->domain = MEM_callocN(sizeof(SmokeDomainSettings), "SmokeDomain");
+
+ smd->domain->smd = smd;
+
+ smd->domain->point_cache[0] = BKE_ptcache_add(&(smd->domain->ptcaches[0]));
+ smd->domain->point_cache[0]->flag |= PTCACHE_DISK_CACHE;
+ smd->domain->point_cache[0]->step = 1;
+
+ /* Deprecated */
+ smd->domain->point_cache[1] = NULL;
+ BLI_listbase_clear(&smd->domain->ptcaches[1]);
+ /* set some standard values */
+ smd->domain->fluid = NULL;
+ smd->domain->fluid_mutex = BLI_rw_mutex_alloc();
+ smd->domain->wt = NULL;
+ smd->domain->eff_group = NULL;
+ smd->domain->fluid_group = NULL;
+ smd->domain->coll_group = NULL;
+ smd->domain->maxres = 32;
+ smd->domain->amplify = 1;
+ smd->domain->alpha = -0.001;
+ smd->domain->beta = 0.1;
+ smd->domain->time_scale = 1.0;
+ smd->domain->vorticity = 2.0;
+ smd->domain->border_collisions = SM_BORDER_OPEN; // open domain
+ smd->domain->flags = MOD_SMOKE_DISSOLVE_LOG;
+ smd->domain->highres_sampling = SM_HRES_FULLSAMPLE;
+ smd->domain->strength = 2.0;
+ smd->domain->noise = MOD_SMOKE_NOISEWAVE;
+ smd->domain->diss_speed = 5;
+ smd->domain->active_fields = 0;
+
+ smd->domain->adapt_margin = 4;
+ smd->domain->adapt_res = 0;
+ smd->domain->adapt_threshold = 0.02f;
+
+ smd->domain->burning_rate = 0.75f;
+ smd->domain->flame_smoke = 1.0f;
+ smd->domain->flame_vorticity = 0.5f;
+ smd->domain->flame_ignition = 1.5f;
+ smd->domain->flame_max_temp = 3.0f;
+ /* color */
+ smd->domain->flame_smoke_color[0] = 0.7f;
+ smd->domain->flame_smoke_color[1] = 0.7f;
+ smd->domain->flame_smoke_color[2] = 0.7f;
+
+ smd->domain->viewsettings = MOD_SMOKE_VIEW_SHOW_HIGHRES;
+ smd->domain->effector_weights = BKE_effector_add_weights(NULL);
#ifdef WITH_OPENVDB_BLOSC
- smd->domain->openvdb_comp = VDB_COMPRESSION_BLOSC;
+ smd->domain->openvdb_comp = VDB_COMPRESSION_BLOSC;
#else
- smd->domain->openvdb_comp = VDB_COMPRESSION_ZIP;
+ smd->domain->openvdb_comp = VDB_COMPRESSION_ZIP;
#endif
- smd->domain->data_depth = 0;
- smd->domain->cache_file_format = PTCACHE_FILE_PTCACHE;
-
- smd->domain->display_thickness = 1.0f;
- smd->domain->slice_method = MOD_SMOKE_SLICE_VIEW_ALIGNED;
- smd->domain->axis_slice_method = AXIS_SLICE_FULL;
- smd->domain->slice_per_voxel = 5.0f;
- smd->domain->slice_depth = 0.5f;
- smd->domain->slice_axis = 0;
- smd->domain->vector_scale = 1.0f;
-
- smd->domain->coba = NULL;
- smd->domain->coba_field = FLUID_FIELD_DENSITY;
-
- smd->domain->clipping = 1e-3f;
- }
- else if (smd->type & MOD_SMOKE_TYPE_FLOW)
- {
- if (smd->flow)
- smokeModifier_freeFlow(smd);
-
- smd->flow = MEM_callocN(sizeof(SmokeFlowSettings), "SmokeFlow");
-
- smd->flow->smd = smd;
-
- /* set some standard values */
- smd->flow->density = 1.0f;
- smd->flow->fuel_amount = 1.0f;
- smd->flow->temp = 1.0f;
- smd->flow->flags = MOD_SMOKE_FLOW_ABSOLUTE | MOD_SMOKE_FLOW_USE_PART_SIZE;
- smd->flow->vel_multi = 1.0f;
- smd->flow->volume_density = 0.0f;
- smd->flow->surface_distance = 1.5f;
- smd->flow->source = MOD_SMOKE_FLOW_SOURCE_MESH;
- smd->flow->texture_size = 1.0f;
- smd->flow->particle_size = 1.0f;
- smd->flow->subframes = 0;
-
- smd->flow->color[0] = 0.7f;
- smd->flow->color[1] = 0.7f;
- smd->flow->color[2] = 0.7f;
-
- smd->flow->mesh = NULL;
- smd->flow->psys = NULL;
-
- }
- else if (smd->type & MOD_SMOKE_TYPE_COLL)
- {
- if (smd->coll)
- smokeModifier_freeCollision(smd);
-
- smd->coll = MEM_callocN(sizeof(SmokeCollSettings), "SmokeColl");
-
- smd->coll->smd = smd;
- smd->coll->verts_old = NULL;
- smd->coll->numverts = 0;
- smd->coll->type = 0; // static obstacle
- smd->coll->mesh = NULL;
- }
- }
+ smd->domain->data_depth = 0;
+ smd->domain->cache_file_format = PTCACHE_FILE_PTCACHE;
+
+ smd->domain->display_thickness = 1.0f;
+ smd->domain->slice_method = MOD_SMOKE_SLICE_VIEW_ALIGNED;
+ smd->domain->axis_slice_method = AXIS_SLICE_FULL;
+ smd->domain->slice_per_voxel = 5.0f;
+ smd->domain->slice_depth = 0.5f;
+ smd->domain->slice_axis = 0;
+ smd->domain->vector_scale = 1.0f;
+
+ smd->domain->coba = NULL;
+ smd->domain->coba_field = FLUID_FIELD_DENSITY;
+
+ smd->domain->clipping = 1e-3f;
+ }
+ else if (smd->type & MOD_SMOKE_TYPE_FLOW) {
+ if (smd->flow)
+ smokeModifier_freeFlow(smd);
+
+ smd->flow = MEM_callocN(sizeof(SmokeFlowSettings), "SmokeFlow");
+
+ smd->flow->smd = smd;
+
+ /* set some standard values */
+ smd->flow->density = 1.0f;
+ smd->flow->fuel_amount = 1.0f;
+ smd->flow->temp = 1.0f;
+ smd->flow->flags = MOD_SMOKE_FLOW_ABSOLUTE | MOD_SMOKE_FLOW_USE_PART_SIZE;
+ smd->flow->vel_multi = 1.0f;
+ smd->flow->volume_density = 0.0f;
+ smd->flow->surface_distance = 1.5f;
+ smd->flow->source = MOD_SMOKE_FLOW_SOURCE_MESH;
+ smd->flow->texture_size = 1.0f;
+ smd->flow->particle_size = 1.0f;
+ smd->flow->subframes = 0;
+
+ smd->flow->color[0] = 0.7f;
+ smd->flow->color[1] = 0.7f;
+ smd->flow->color[2] = 0.7f;
+
+ smd->flow->mesh = NULL;
+ smd->flow->psys = NULL;
+ }
+ else if (smd->type & MOD_SMOKE_TYPE_COLL) {
+ if (smd->coll)
+ smokeModifier_freeCollision(smd);
+
+ smd->coll = MEM_callocN(sizeof(SmokeCollSettings), "SmokeColl");
+
+ smd->coll->smd = smd;
+ smd->coll->verts_old = NULL;
+ smd->coll->numverts = 0;
+ smd->coll->type = 0; // static obstacle
+ smd->coll->mesh = NULL;
+ }
+ }
}
-void smokeModifier_copy(const struct SmokeModifierData *smd, struct SmokeModifierData *tsmd, const int flag)
+void smokeModifier_copy(const struct SmokeModifierData *smd,
+ struct SmokeModifierData *tsmd,
+ const int flag)
{
- tsmd->type = smd->type;
- tsmd->time = smd->time;
-
- smokeModifier_createType(tsmd);
-
- if (tsmd->domain) {
- SmokeDomainSettings *tsds = tsmd->domain;
- SmokeDomainSettings *sds = smd->domain;
-
- BKE_ptcache_free_list(&(tsds->ptcaches[0]));
-
- if (flag & LIB_ID_CREATE_NO_MAIN) {
- /* Share the cache with the original object's modifier. */
- tsmd->modifier.flag |= eModifierFlag_SharedCaches;
- tsds->point_cache[0] = sds->point_cache[0];
- tsds->ptcaches[0] = sds->ptcaches[0];
- }
- else {
- tsds->point_cache[0] = BKE_ptcache_copy_list(&(tsds->ptcaches[0]), &(sds->ptcaches[0]), flag);
- }
-
- tsds->fluid_group = sds->fluid_group;
- tsds->coll_group = sds->coll_group;
-
- tsds->adapt_margin = sds->adapt_margin;
- tsds->adapt_res = sds->adapt_res;
- tsds->adapt_threshold = sds->adapt_threshold;
-
- tsds->alpha = sds->alpha;
- tsds->beta = sds->beta;
- tsds->amplify = sds->amplify;
- tsds->maxres = sds->maxres;
- tsds->flags = sds->flags;
- tsds->highres_sampling = sds->highres_sampling;
- tsds->viewsettings = sds->viewsettings;
- tsds->noise = sds->noise;
- tsds->diss_speed = sds->diss_speed;
- tsds->strength = sds->strength;
-
- tsds->border_collisions = sds->border_collisions;
- tsds->vorticity = sds->vorticity;
- tsds->time_scale = sds->time_scale;
-
- tsds->burning_rate = sds->burning_rate;
- tsds->flame_smoke = sds->flame_smoke;
- tsds->flame_vorticity = sds->flame_vorticity;
- tsds->flame_ignition = sds->flame_ignition;
- tsds->flame_max_temp = sds->flame_max_temp;
- copy_v3_v3(tsds->flame_smoke_color, sds->flame_smoke_color);
-
- MEM_freeN(tsds->effector_weights);
- tsds->effector_weights = MEM_dupallocN(sds->effector_weights);
- tsds->openvdb_comp = sds->openvdb_comp;
- tsds->data_depth = sds->data_depth;
- tsds->cache_file_format = sds->cache_file_format;
-
- tsds->display_thickness = sds->display_thickness;
- tsds->slice_method = sds->slice_method;
- tsds->axis_slice_method = sds->axis_slice_method;
- tsds->slice_per_voxel = sds->slice_per_voxel;
- tsds->slice_depth = sds->slice_depth;
- tsds->slice_axis = sds->slice_axis;
- tsds->interp_method = sds->interp_method;
- tsds->draw_velocity = sds->draw_velocity;
- tsds->vector_draw_type = sds->vector_draw_type;
- tsds->vector_scale = sds->vector_scale;
-
- tsds->use_coba = sds->use_coba;
- tsds->coba_field = sds->coba_field;
- if (sds->coba) {
- tsds->coba = MEM_dupallocN(sds->coba);
- }
-
- tsds->clipping = sds->clipping;
- }
- else if (tsmd->flow) {
- SmokeFlowSettings *tsfs = tsmd->flow;
- SmokeFlowSettings *sfs = smd->flow;
-
- tsfs->psys = sfs->psys;
- tsfs->noise_texture = sfs->noise_texture;
-
- tsfs->vel_multi = sfs->vel_multi;
- tsfs->vel_normal = sfs->vel_normal;
- tsfs->vel_random = sfs->vel_random;
-
- tsfs->density = sfs->density;
- copy_v3_v3(tsfs->color, sfs->color);
- tsfs->fuel_amount = sfs->fuel_amount;
- tsfs->temp = sfs->temp;
- tsfs->volume_density = sfs->volume_density;
- tsfs->surface_distance = sfs->surface_distance;
- tsfs->particle_size = sfs->particle_size;
- tsfs->subframes = sfs->subframes;
-
- tsfs->texture_size = sfs->texture_size;
- tsfs->texture_offset = sfs->texture_offset;
- BLI_strncpy(tsfs->uvlayer_name, sfs->uvlayer_name, sizeof(tsfs->uvlayer_name));
- tsfs->vgroup_density = sfs->vgroup_density;
-
- tsfs->type = sfs->type;
- tsfs->source = sfs->source;
- tsfs->texture_type = sfs->texture_type;
- tsfs->flags = sfs->flags;
- }
- else if (tsmd->coll) {
- /* leave it as initialized, collision settings is mostly caches */
- }
+ tsmd->type = smd->type;
+ tsmd->time = smd->time;
+
+ smokeModifier_createType(tsmd);
+
+ if (tsmd->domain) {
+ SmokeDomainSettings *tsds = tsmd->domain;
+ SmokeDomainSettings *sds = smd->domain;
+
+ BKE_ptcache_free_list(&(tsds->ptcaches[0]));
+
+ if (flag & LIB_ID_CREATE_NO_MAIN) {
+ /* Share the cache with the original object's modifier. */
+ tsmd->modifier.flag |= eModifierFlag_SharedCaches;
+ tsds->point_cache[0] = sds->point_cache[0];
+ tsds->ptcaches[0] = sds->ptcaches[0];
+ }
+ else {
+ tsds->point_cache[0] = BKE_ptcache_copy_list(
+ &(tsds->ptcaches[0]), &(sds->ptcaches[0]), flag);
+ }
+
+ tsds->fluid_group = sds->fluid_group;
+ tsds->coll_group = sds->coll_group;
+
+ tsds->adapt_margin = sds->adapt_margin;
+ tsds->adapt_res = sds->adapt_res;
+ tsds->adapt_threshold = sds->adapt_threshold;
+
+ tsds->alpha = sds->alpha;
+ tsds->beta = sds->beta;
+ tsds->amplify = sds->amplify;
+ tsds->maxres = sds->maxres;
+ tsds->flags = sds->flags;
+ tsds->highres_sampling = sds->highres_sampling;
+ tsds->viewsettings = sds->viewsettings;
+ tsds->noise = sds->noise;
+ tsds->diss_speed = sds->diss_speed;
+ tsds->strength = sds->strength;
+
+ tsds->border_collisions = sds->border_collisions;
+ tsds->vorticity = sds->vorticity;
+ tsds->time_scale = sds->time_scale;
+
+ tsds->burning_rate = sds->burning_rate;
+ tsds->flame_smoke = sds->flame_smoke;
+ tsds->flame_vorticity = sds->flame_vorticity;
+ tsds->flame_ignition = sds->flame_ignition;
+ tsds->flame_max_temp = sds->flame_max_temp;
+ copy_v3_v3(tsds->flame_smoke_color, sds->flame_smoke_color);
+
+ MEM_freeN(tsds->effector_weights);
+ tsds->effector_weights = MEM_dupallocN(sds->effector_weights);
+ tsds->openvdb_comp = sds->openvdb_comp;
+ tsds->data_depth = sds->data_depth;
+ tsds->cache_file_format = sds->cache_file_format;
+
+ tsds->display_thickness = sds->display_thickness;
+ tsds->slice_method = sds->slice_method;
+ tsds->axis_slice_method = sds->axis_slice_method;
+ tsds->slice_per_voxel = sds->slice_per_voxel;
+ tsds->slice_depth = sds->slice_depth;
+ tsds->slice_axis = sds->slice_axis;
+ tsds->interp_method = sds->interp_method;
+ tsds->draw_velocity = sds->draw_velocity;
+ tsds->vector_draw_type = sds->vector_draw_type;
+ tsds->vector_scale = sds->vector_scale;
+
+ tsds->use_coba = sds->use_coba;
+ tsds->coba_field = sds->coba_field;
+ if (sds->coba) {
+ tsds->coba = MEM_dupallocN(sds->coba);
+ }
+
+ tsds->clipping = sds->clipping;
+ }
+ else if (tsmd->flow) {
+ SmokeFlowSettings *tsfs = tsmd->flow;
+ SmokeFlowSettings *sfs = smd->flow;
+
+ tsfs->psys = sfs->psys;
+ tsfs->noise_texture = sfs->noise_texture;
+
+ tsfs->vel_multi = sfs->vel_multi;
+ tsfs->vel_normal = sfs->vel_normal;
+ tsfs->vel_random = sfs->vel_random;
+
+ tsfs->density = sfs->density;
+ copy_v3_v3(tsfs->color, sfs->color);
+ tsfs->fuel_amount = sfs->fuel_amount;
+ tsfs->temp = sfs->temp;
+ tsfs->volume_density = sfs->volume_density;
+ tsfs->surface_distance = sfs->surface_distance;
+ tsfs->particle_size = sfs->particle_size;
+ tsfs->subframes = sfs->subframes;
+
+ tsfs->texture_size = sfs->texture_size;
+ tsfs->texture_offset = sfs->texture_offset;
+ BLI_strncpy(tsfs->uvlayer_name, sfs->uvlayer_name, sizeof(tsfs->uvlayer_name));
+ tsfs->vgroup_density = sfs->vgroup_density;
+
+ tsfs->type = sfs->type;
+ tsfs->source = sfs->source;
+ tsfs->texture_type = sfs->texture_type;
+ tsfs->flags = sfs->flags;
+ }
+ else if (tsmd->coll) {
+ /* leave it as initialized, collision settings is mostly caches */
+ }
}
#ifdef WITH_SMOKE
// forward declaration
static void smoke_calc_transparency(SmokeDomainSettings *sds, ViewLayer *view_layer);
-static float calc_voxel_transp(float *result, float *input, int res[3], int *pixel, float *tRay, float correct);
+static float calc_voxel_transp(
+ float *result, float *input, int res[3], int *pixel, float *tRay, float correct);
static int get_light(ViewLayer *view_layer, float *light)
{
- Base *base_tmp = NULL;
- int found_light = 0;
-
- // try to find a lamp, preferably local
- for (base_tmp = FIRSTBASE(view_layer); base_tmp; base_tmp = base_tmp->next) {
- if (base_tmp->object->type == OB_LAMP) {
- Light *la = base_tmp->object->data;
-
- if (la->type == LA_LOCAL) {
- copy_v3_v3(light, base_tmp->object->obmat[3]);
- return 1;
- }
- else if (!found_light) {
- copy_v3_v3(light, base_tmp->object->obmat[3]);
- found_light = 1;
- }
- }
- }
-
- return found_light;
+ Base *base_tmp = NULL;
+ int found_light = 0;
+
+ // try to find a lamp, preferably local
+ for (base_tmp = FIRSTBASE(view_layer); base_tmp; base_tmp = base_tmp->next) {
+ if (base_tmp->object->type == OB_LAMP) {
+ Light *la = base_tmp->object->data;
+
+ if (la->type == LA_LOCAL) {
+ copy_v3_v3(light, base_tmp->object->obmat[3]);
+ return 1;
+ }
+ else if (!found_light) {
+ copy_v3_v3(light, base_tmp->object->obmat[3]);
+ found_light = 1;
+ }
+ }
+ }
+
+ return found_light;
}
/**********************************************************
@@ -744,256 +786,277 @@ static int get_light(ViewLayer *view_layer, float *light)
**********************************************************/
typedef struct ObstaclesFromDMData {
- SmokeDomainSettings *sds;
- const MVert *mvert;
- const MLoop *mloop;
- const MLoopTri *looptri;
- BVHTreeFromMesh *tree;
- unsigned char *obstacle_map;
-
- bool has_velocity;
- float *vert_vel;
- float *velocityX, *velocityY, *velocityZ;
- int *num_obstacles;
+ SmokeDomainSettings *sds;
+ const MVert *mvert;
+ const MLoop *mloop;
+ const MLoopTri *looptri;
+ BVHTreeFromMesh *tree;
+ unsigned char *obstacle_map;
+
+ bool has_velocity;
+ float *vert_vel;
+ float *velocityX, *velocityY, *velocityZ;
+ int *num_obstacles;
} ObstaclesFromDMData;
-static void obstacles_from_mesh_task_cb(
- void *__restrict userdata,
- const int z,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void obstacles_from_mesh_task_cb(void *__restrict userdata,
+ const int z,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- ObstaclesFromDMData *data = userdata;
- SmokeDomainSettings *sds = data->sds;
-
- /* slightly rounded-up sqrt(3 * (0.5)^2) == max. distance of cell boundary along the diagonal */
- const float surface_distance = 0.867f;
-
- for (int x = sds->res_min[0]; x < sds->res_max[0]; x++) {
- for (int y = sds->res_min[1]; y < sds->res_max[1]; y++) {
- const int index = smoke_get_index(x - sds->res_min[0], sds->res[0], y - sds->res_min[1], sds->res[1], z - sds->res_min[2]);
-
- float ray_start[3] = {(float)x + 0.5f, (float)y + 0.5f, (float)z + 0.5f};
- BVHTreeNearest nearest = {0};
- nearest.index = -1;
- nearest.dist_sq = surface_distance * surface_distance; /* find_nearest uses squared distance */
-
- /* find the nearest point on the mesh */
- if (BLI_bvhtree_find_nearest(data->tree->tree, ray_start, &nearest, data->tree->nearest_callback, data->tree) != -1) {
- const MLoopTri *lt = &data->looptri[nearest.index];
- float weights[3];
- int v1, v2, v3;
-
- /* calculate barycentric weights for nearest point */
- v1 = data->mloop[lt->tri[0]].v;
- v2 = data->mloop[lt->tri[1]].v;
- v3 = data->mloop[lt->tri[2]].v;
- interp_weights_tri_v3(weights, data->mvert[v1].co, data->mvert[v2].co, data->mvert[v3].co, nearest.co);
-
- // DG TODO
- if (data->has_velocity)
- {
- /* apply object velocity */
- {
- float hit_vel[3];
- interp_v3_v3v3v3(hit_vel, &data->vert_vel[v1 * 3], &data->vert_vel[v2 * 3], &data->vert_vel[v3 * 3], weights);
- data->velocityX[index] += hit_vel[0];
- data->velocityY[index] += hit_vel[1];
- data->velocityZ[index] += hit_vel[2];
- }
- }
-
- /* tag obstacle cells */
- data->obstacle_map[index] = 1;
-
- if (data->has_velocity) {
- data->obstacle_map[index] |= 8;
- data->num_obstacles[index]++;
- }
- }
- }
- }
+ ObstaclesFromDMData *data = userdata;
+ SmokeDomainSettings *sds = data->sds;
+
+ /* slightly rounded-up sqrt(3 * (0.5)^2) == max. distance of cell boundary along the diagonal */
+ const float surface_distance = 0.867f;
+
+ for (int x = sds->res_min[0]; x < sds->res_max[0]; x++) {
+ for (int y = sds->res_min[1]; y < sds->res_max[1]; y++) {
+ const int index = smoke_get_index(
+ x - sds->res_min[0], sds->res[0], y - sds->res_min[1], sds->res[1], z - sds->res_min[2]);
+
+ float ray_start[3] = {(float)x + 0.5f, (float)y + 0.5f, (float)z + 0.5f};
+ BVHTreeNearest nearest = {0};
+ nearest.index = -1;
+ nearest.dist_sq = surface_distance *
+ surface_distance; /* find_nearest uses squared distance */
+
+ /* find the nearest point on the mesh */
+ if (BLI_bvhtree_find_nearest(
+ data->tree->tree, ray_start, &nearest, data->tree->nearest_callback, data->tree) !=
+ -1) {
+ const MLoopTri *lt = &data->looptri[nearest.index];
+ float weights[3];
+ int v1, v2, v3;
+
+ /* calculate barycentric weights for nearest point */
+ v1 = data->mloop[lt->tri[0]].v;
+ v2 = data->mloop[lt->tri[1]].v;
+ v3 = data->mloop[lt->tri[2]].v;
+ interp_weights_tri_v3(
+ weights, data->mvert[v1].co, data->mvert[v2].co, data->mvert[v3].co, nearest.co);
+
+ // DG TODO
+ if (data->has_velocity) {
+ /* apply object velocity */
+ {
+ float hit_vel[3];
+ interp_v3_v3v3v3(hit_vel,
+ &data->vert_vel[v1 * 3],
+ &data->vert_vel[v2 * 3],
+ &data->vert_vel[v3 * 3],
+ weights);
+ data->velocityX[index] += hit_vel[0];
+ data->velocityY[index] += hit_vel[1];
+ data->velocityZ[index] += hit_vel[2];
+ }
+ }
+
+ /* tag obstacle cells */
+ data->obstacle_map[index] = 1;
+
+ if (data->has_velocity) {
+ data->obstacle_map[index] |= 8;
+ data->num_obstacles[index]++;
+ }
+ }
+ }
+ }
}
-static void obstacles_from_mesh(
- Object *coll_ob, SmokeDomainSettings *sds, SmokeCollSettings *scs,
- unsigned char *obstacle_map, float *velocityX, float *velocityY, float *velocityZ, int *num_obstacles, float dt)
+static void obstacles_from_mesh(Object *coll_ob,
+ SmokeDomainSettings *sds,
+ SmokeCollSettings *scs,
+ unsigned char *obstacle_map,
+ float *velocityX,
+ float *velocityY,
+ float *velocityZ,
+ int *num_obstacles,
+ float dt)
{
- if (!scs->mesh) return;
- {
- Mesh *me = NULL;
- MVert *mvert = NULL;
- const MLoopTri *looptri;
- const MLoop *mloop;
- BVHTreeFromMesh treeData = {NULL};
- int numverts, i;
-
- float *vert_vel = NULL;
- bool has_velocity = false;
-
- me = BKE_mesh_copy_for_eval(scs->mesh, true);
- BKE_mesh_ensure_normals(me);
- mvert = me->mvert;
- mloop = me->mloop;
- looptri = BKE_mesh_runtime_looptri_ensure(me);
- numverts = me->totvert;
-
- // DG TODO
- // if (scs->type > SM_COLL_STATIC)
- // if line above is used, the code is in trouble if the object moves but is declared as "does not move"
-
- {
- vert_vel = MEM_callocN(sizeof(float) * numverts * 3, "smoke_obs_velocity");
-
- if (scs->numverts != numverts || !scs->verts_old) {
- if (scs->verts_old) MEM_freeN(scs->verts_old);
-
- scs->verts_old = MEM_callocN(sizeof(float) * numverts * 3, "smoke_obs_verts_old");
- scs->numverts = numverts;
- }
- else {
- has_velocity = true;
- }
- }
-
- /* Transform collider vertices to
- * domain grid space for fast lookups */
- for (i = 0; i < numverts; i++) {
- float n[3];
- float co[3];
-
- /* vert pos */
- mul_m4_v3(coll_ob->obmat, mvert[i].co);
- smoke_pos_to_cell(sds, mvert[i].co);
-
- /* vert normal */
- normal_short_to_float_v3(n, mvert[i].no);
- mul_mat3_m4_v3(coll_ob->obmat, n);
- mul_mat3_m4_v3(sds->imat, n);
- normalize_v3(n);
- normal_float_to_short_v3(mvert[i].no, n);
-
- /* vert velocity */
- add_v3fl_v3fl_v3i(co, mvert[i].co, sds->shift);
- if (has_velocity)
- {
- sub_v3_v3v3(&vert_vel[i * 3], co, &scs->verts_old[i * 3]);
- mul_v3_fl(&vert_vel[i * 3], sds->dx / dt);
- }
- copy_v3_v3(&scs->verts_old[i * 3], co);
- }
-
- if (BKE_bvhtree_from_mesh_get(&treeData, me, BVHTREE_FROM_LOOPTRI, 4)) {
- ObstaclesFromDMData data = {
- .sds = sds, .mvert = mvert, .mloop = mloop, .looptri = looptri,
- .tree = &treeData, .obstacle_map = obstacle_map,
- .has_velocity = has_velocity, .vert_vel = vert_vel,
- .velocityX = velocityX, .velocityY = velocityY, .velocityZ = velocityZ,
- .num_obstacles = num_obstacles,
- };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
- BLI_task_parallel_range(sds->res_min[2], sds->res_max[2],
- &data,
- obstacles_from_mesh_task_cb,
- &settings);
- }
- /* free bvh tree */
- free_bvhtree_from_mesh(&treeData);
- BKE_id_free(NULL, me);
-
- if (vert_vel) MEM_freeN(vert_vel);
- }
+ if (!scs->mesh)
+ return;
+ {
+ Mesh *me = NULL;
+ MVert *mvert = NULL;
+ const MLoopTri *looptri;
+ const MLoop *mloop;
+ BVHTreeFromMesh treeData = {NULL};
+ int numverts, i;
+
+ float *vert_vel = NULL;
+ bool has_velocity = false;
+
+ me = BKE_mesh_copy_for_eval(scs->mesh, true);
+ BKE_mesh_ensure_normals(me);
+ mvert = me->mvert;
+ mloop = me->mloop;
+ looptri = BKE_mesh_runtime_looptri_ensure(me);
+ numverts = me->totvert;
+
+ // DG TODO
+ // if (scs->type > SM_COLL_STATIC)
+ // if line above is used, the code is in trouble if the object moves but is declared as "does not move"
+
+ {
+ vert_vel = MEM_callocN(sizeof(float) * numverts * 3, "smoke_obs_velocity");
+
+ if (scs->numverts != numverts || !scs->verts_old) {
+ if (scs->verts_old)
+ MEM_freeN(scs->verts_old);
+
+ scs->verts_old = MEM_callocN(sizeof(float) * numverts * 3, "smoke_obs_verts_old");
+ scs->numverts = numverts;
+ }
+ else {
+ has_velocity = true;
+ }
+ }
+
+ /* Transform collider vertices to
+ * domain grid space for fast lookups */
+ for (i = 0; i < numverts; i++) {
+ float n[3];
+ float co[3];
+
+ /* vert pos */
+ mul_m4_v3(coll_ob->obmat, mvert[i].co);
+ smoke_pos_to_cell(sds, mvert[i].co);
+
+ /* vert normal */
+ normal_short_to_float_v3(n, mvert[i].no);
+ mul_mat3_m4_v3(coll_ob->obmat, n);
+ mul_mat3_m4_v3(sds->imat, n);
+ normalize_v3(n);
+ normal_float_to_short_v3(mvert[i].no, n);
+
+ /* vert velocity */
+ add_v3fl_v3fl_v3i(co, mvert[i].co, sds->shift);
+ if (has_velocity) {
+ sub_v3_v3v3(&vert_vel[i * 3], co, &scs->verts_old[i * 3]);
+ mul_v3_fl(&vert_vel[i * 3], sds->dx / dt);
+ }
+ copy_v3_v3(&scs->verts_old[i * 3], co);
+ }
+
+ if (BKE_bvhtree_from_mesh_get(&treeData, me, BVHTREE_FROM_LOOPTRI, 4)) {
+ ObstaclesFromDMData data = {
+ .sds = sds,
+ .mvert = mvert,
+ .mloop = mloop,
+ .looptri = looptri,
+ .tree = &treeData,
+ .obstacle_map = obstacle_map,
+ .has_velocity = has_velocity,
+ .vert_vel = vert_vel,
+ .velocityX = velocityX,
+ .velocityY = velocityY,
+ .velocityZ = velocityZ,
+ .num_obstacles = num_obstacles,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
+ BLI_task_parallel_range(
+ sds->res_min[2], sds->res_max[2], &data, obstacles_from_mesh_task_cb, &settings);
+ }
+ /* free bvh tree */
+ free_bvhtree_from_mesh(&treeData);
+ BKE_id_free(NULL, me);
+
+ if (vert_vel)
+ MEM_freeN(vert_vel);
+ }
}
/* Animated obstacles: dx_step = ((x_new - x_old) / totalsteps) * substep */
-static void update_obstacles(Depsgraph *depsgraph, Object *ob, SmokeDomainSettings *sds, float dt,
- int UNUSED(substep), int UNUSED(totalsteps))
+static void update_obstacles(Depsgraph *depsgraph,
+ Object *ob,
+ SmokeDomainSettings *sds,
+ float dt,
+ int UNUSED(substep),
+ int UNUSED(totalsteps))
{
- Object **collobjs = NULL;
- unsigned int numcollobj = 0;
-
- unsigned int collIndex;
- unsigned char *obstacles = smoke_get_obstacle(sds->fluid);
- float *velx = NULL;
- float *vely = NULL;
- float *velz = NULL;
- float *velxOrig = smoke_get_velocity_x(sds->fluid);
- float *velyOrig = smoke_get_velocity_y(sds->fluid);
- float *velzOrig = smoke_get_velocity_z(sds->fluid);
- float *density = smoke_get_density(sds->fluid);
- float *fuel = smoke_get_fuel(sds->fluid);
- float *flame = smoke_get_flame(sds->fluid);
- float *r = smoke_get_color_r(sds->fluid);
- float *g = smoke_get_color_g(sds->fluid);
- float *b = smoke_get_color_b(sds->fluid);
- unsigned int z;
-
- int *num_obstacles = MEM_callocN(sizeof(int) * sds->res[0] * sds->res[1] * sds->res[2], "smoke_num_obstacles");
-
- smoke_get_ob_velocity(sds->fluid, &velx, &vely, &velz);
-
- // TODO: delete old obstacle flags
- for (z = 0; z < sds->res[0] * sds->res[1] * sds->res[2]; z++)
- {
- if (obstacles[z] & 8) // Do not delete static obstacles
- {
- obstacles[z] = 0;
- }
-
- velx[z] = 0;
- vely[z] = 0;
- velz[z] = 0;
- }
-
-
- collobjs = BKE_collision_objects_create(depsgraph, ob, sds->coll_group, &numcollobj, eModifierType_Smoke);
-
- // update obstacle tags in cells
- for (collIndex = 0; collIndex < numcollobj; collIndex++)
- {
- Object *collob = collobjs[collIndex];
- SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(collob, eModifierType_Smoke);
-
- // DG TODO: check if modifier is active?
-
- if ((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll)
- {
- SmokeCollSettings *scs = smd2->coll;
- obstacles_from_mesh(collob, sds, scs, obstacles, velx, vely, velz, num_obstacles, dt);
- }
- }
-
- BKE_collision_objects_free(collobjs);
-
- /* obstacle cells should not contain any velocity from the smoke simulation */
- for (z = 0; z < sds->res[0] * sds->res[1] * sds->res[2]; z++)
- {
- if (obstacles[z])
- {
- velxOrig[z] = 0;
- velyOrig[z] = 0;
- velzOrig[z] = 0;
- density[z] = 0;
- if (fuel) {
- fuel[z] = 0;
- flame[z] = 0;
- }
- if (r) {
- r[z] = 0;
- g[z] = 0;
- b[z] = 0;
- }
- }
- /* average velocities from multiple obstacles in one cell */
- if (num_obstacles[z]) {
- velx[z] /= num_obstacles[z];
- vely[z] /= num_obstacles[z];
- velz[z] /= num_obstacles[z];
- }
- }
-
- MEM_freeN(num_obstacles);
+ Object **collobjs = NULL;
+ unsigned int numcollobj = 0;
+
+ unsigned int collIndex;
+ unsigned char *obstacles = smoke_get_obstacle(sds->fluid);
+ float *velx = NULL;
+ float *vely = NULL;
+ float *velz = NULL;
+ float *velxOrig = smoke_get_velocity_x(sds->fluid);
+ float *velyOrig = smoke_get_velocity_y(sds->fluid);
+ float *velzOrig = smoke_get_velocity_z(sds->fluid);
+ float *density = smoke_get_density(sds->fluid);
+ float *fuel = smoke_get_fuel(sds->fluid);
+ float *flame = smoke_get_flame(sds->fluid);
+ float *r = smoke_get_color_r(sds->fluid);
+ float *g = smoke_get_color_g(sds->fluid);
+ float *b = smoke_get_color_b(sds->fluid);
+ unsigned int z;
+
+ int *num_obstacles = MEM_callocN(sizeof(int) * sds->res[0] * sds->res[1] * sds->res[2],
+ "smoke_num_obstacles");
+
+ smoke_get_ob_velocity(sds->fluid, &velx, &vely, &velz);
+
+ // TODO: delete old obstacle flags
+ for (z = 0; z < sds->res[0] * sds->res[1] * sds->res[2]; z++) {
+ if (obstacles[z] & 8) // Do not delete static obstacles
+ {
+ obstacles[z] = 0;
+ }
+
+ velx[z] = 0;
+ vely[z] = 0;
+ velz[z] = 0;
+ }
+
+ collobjs = BKE_collision_objects_create(
+ depsgraph, ob, sds->coll_group, &numcollobj, eModifierType_Smoke);
+
+ // update obstacle tags in cells
+ for (collIndex = 0; collIndex < numcollobj; collIndex++) {
+ Object *collob = collobjs[collIndex];
+ SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(collob,
+ eModifierType_Smoke);
+
+ // DG TODO: check if modifier is active?
+
+ if ((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll) {
+ SmokeCollSettings *scs = smd2->coll;
+ obstacles_from_mesh(collob, sds, scs, obstacles, velx, vely, velz, num_obstacles, dt);
+ }
+ }
+
+ BKE_collision_objects_free(collobjs);
+
+ /* obstacle cells should not contain any velocity from the smoke simulation */
+ for (z = 0; z < sds->res[0] * sds->res[1] * sds->res[2]; z++) {
+ if (obstacles[z]) {
+ velxOrig[z] = 0;
+ velyOrig[z] = 0;
+ velzOrig[z] = 0;
+ density[z] = 0;
+ if (fuel) {
+ fuel[z] = 0;
+ flame[z] = 0;
+ }
+ if (r) {
+ r[z] = 0;
+ g[z] = 0;
+ b[z] = 0;
+ }
+ }
+ /* average velocities from multiple obstacles in one cell */
+ if (num_obstacles[z]) {
+ velx[z] /= num_obstacles[z];
+ vely[z] /= num_obstacles[z];
+ velz[z] /= num_obstacles[z];
+ }
+ }
+
+ MEM_freeN(num_obstacles);
}
/**********************************************************
@@ -1001,2162 +1064,2484 @@ static void update_obstacles(Depsgraph *depsgraph, Object *ob, SmokeDomainSettin
**********************************************************/
typedef struct EmissionMap {
- float *influence;
- float *influence_high;
- float *velocity;
- int min[3], max[3], res[3];
- int hmin[3], hmax[3], hres[3];
- int total_cells, valid;
+ float *influence;
+ float *influence_high;
+ float *velocity;
+ int min[3], max[3], res[3];
+ int hmin[3], hmax[3], hres[3];
+ int total_cells, valid;
} EmissionMap;
static void em_boundInsert(EmissionMap *em, float point[3])
{
- int i = 0;
- if (!em->valid) {
- for (; i < 3; i++) {
- em->min[i] = (int)floor(point[i]);
- em->max[i] = (int)ceil(point[i]);
- }
- em->valid = 1;
- }
- else {
- for (; i < 3; i++) {
- if (point[i] < em->min[i]) em->min[i] = (int)floor(point[i]);
- if (point[i] > em->max[i]) em->max[i] = (int)ceil(point[i]);
- }
- }
+ int i = 0;
+ if (!em->valid) {
+ for (; i < 3; i++) {
+ em->min[i] = (int)floor(point[i]);
+ em->max[i] = (int)ceil(point[i]);
+ }
+ em->valid = 1;
+ }
+ else {
+ for (; i < 3; i++) {
+ if (point[i] < em->min[i])
+ em->min[i] = (int)floor(point[i]);
+ if (point[i] > em->max[i])
+ em->max[i] = (int)ceil(point[i]);
+ }
+ }
}
-static void clampBoundsInDomain(SmokeDomainSettings *sds, int min[3], int max[3], float *min_vel, float *max_vel, int margin, float dt)
+static void clampBoundsInDomain(SmokeDomainSettings *sds,
+ int min[3],
+ int max[3],
+ float *min_vel,
+ float *max_vel,
+ int margin,
+ float dt)
{
- int i;
- for (i = 0; i < 3; i++) {
- int adapt = (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) ? sds->adapt_res : 0;
- /* add margin */
- min[i] -= margin;
- max[i] += margin;
-
- /* adapt to velocity */
- if (min_vel && min_vel[i] < 0.0f) {
- min[i] += (int)floor(min_vel[i] * dt);
- }
- if (max_vel && max_vel[i] > 0.0f) {
- max[i] += (int)ceil(max_vel[i] * dt);
- }
-
- /* clamp within domain max size */
- CLAMP(min[i], -adapt, sds->base_res[i] + adapt);
- CLAMP(max[i], -adapt, sds->base_res[i] + adapt);
- }
+ int i;
+ for (i = 0; i < 3; i++) {
+ int adapt = (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) ? sds->adapt_res : 0;
+ /* add margin */
+ min[i] -= margin;
+ max[i] += margin;
+
+ /* adapt to velocity */
+ if (min_vel && min_vel[i] < 0.0f) {
+ min[i] += (int)floor(min_vel[i] * dt);
+ }
+ if (max_vel && max_vel[i] > 0.0f) {
+ max[i] += (int)ceil(max_vel[i] * dt);
+ }
+
+ /* clamp within domain max size */
+ CLAMP(min[i], -adapt, sds->base_res[i] + adapt);
+ CLAMP(max[i], -adapt, sds->base_res[i] + adapt);
+ }
}
static void em_allocateData(EmissionMap *em, bool use_velocity, int hires_mul)
{
- int i, res[3];
-
- for (i = 0; i < 3; i++) {
- res[i] = em->max[i] - em->min[i];
- if (res[i] <= 0)
- return;
- }
- em->total_cells = res[0] * res[1] * res[2];
- copy_v3_v3_int(em->res, res);
-
-
- em->influence = MEM_callocN(sizeof(float) * em->total_cells, "smoke_flow_influence");
- if (use_velocity)
- em->velocity = MEM_callocN(sizeof(float) * em->total_cells * 3, "smoke_flow_velocity");
-
- /* allocate high resolution map if required */
- if (hires_mul > 1) {
- int total_cells_high = em->total_cells * (hires_mul * hires_mul * hires_mul);
-
- for (i = 0; i < 3; i++) {
- em->hmin[i] = em->min[i] * hires_mul;
- em->hmax[i] = em->max[i] * hires_mul;
- em->hres[i] = em->res[i] * hires_mul;
- }
-
- em->influence_high = MEM_callocN(sizeof(float) * total_cells_high, "smoke_flow_influence_high");
- }
- em->valid = 1;
+ int i, res[3];
+
+ for (i = 0; i < 3; i++) {
+ res[i] = em->max[i] - em->min[i];
+ if (res[i] <= 0)
+ return;
+ }
+ em->total_cells = res[0] * res[1] * res[2];
+ copy_v3_v3_int(em->res, res);
+
+ em->influence = MEM_callocN(sizeof(float) * em->total_cells, "smoke_flow_influence");
+ if (use_velocity)
+ em->velocity = MEM_callocN(sizeof(float) * em->total_cells * 3, "smoke_flow_velocity");
+
+ /* allocate high resolution map if required */
+ if (hires_mul > 1) {
+ int total_cells_high = em->total_cells * (hires_mul * hires_mul * hires_mul);
+
+ for (i = 0; i < 3; i++) {
+ em->hmin[i] = em->min[i] * hires_mul;
+ em->hmax[i] = em->max[i] * hires_mul;
+ em->hres[i] = em->res[i] * hires_mul;
+ }
+
+ em->influence_high = MEM_callocN(sizeof(float) * total_cells_high,
+ "smoke_flow_influence_high");
+ }
+ em->valid = 1;
}
static void em_freeData(EmissionMap *em)
{
- if (em->influence)
- MEM_freeN(em->influence);
- if (em->influence_high)
- MEM_freeN(em->influence_high);
- if (em->velocity)
- MEM_freeN(em->velocity);
+ if (em->influence)
+ MEM_freeN(em->influence);
+ if (em->influence_high)
+ MEM_freeN(em->influence_high);
+ if (em->velocity)
+ MEM_freeN(em->velocity);
}
-static void em_combineMaps(EmissionMap *output, EmissionMap *em2, int hires_multiplier, int additive, float sample_size)
+static void em_combineMaps(
+ EmissionMap *output, EmissionMap *em2, int hires_multiplier, int additive, float sample_size)
{
- int i, x, y, z;
-
- /* copyfill input 1 struct and clear output for new allocation */
- EmissionMap em1;
- memcpy(&em1, output, sizeof(EmissionMap));
- memset(output, 0, sizeof(EmissionMap));
-
- for (i = 0; i < 3; i++) {
- if (em1.valid) {
- output->min[i] = MIN2(em1.min[i], em2->min[i]);
- output->max[i] = MAX2(em1.max[i], em2->max[i]);
- }
- else {
- output->min[i] = em2->min[i];
- output->max[i] = em2->max[i];
- }
- }
- /* allocate output map */
- em_allocateData(output, (em1.velocity || em2->velocity), hires_multiplier);
-
- /* base resolution inputs */
- for (x = output->min[0]; x < output->max[0]; x++)
- for (y = output->min[1]; y < output->max[1]; y++)
- for (z = output->min[2]; z < output->max[2]; z++) {
- int index_out = smoke_get_index(x - output->min[0], output->res[0], y - output->min[1], output->res[1], z - output->min[2]);
-
- /* initialize with first input if in range */
- if (x >= em1.min[0] && x < em1.max[0] &&
- y >= em1.min[1] && y < em1.max[1] &&
- z >= em1.min[2] && z < em1.max[2])
- {
- int index_in = smoke_get_index(x - em1.min[0], em1.res[0], y - em1.min[1], em1.res[1], z - em1.min[2]);
-
- /* values */
- output->influence[index_out] = em1.influence[index_in];
- if (output->velocity && em1.velocity) {
- copy_v3_v3(&output->velocity[index_out * 3], &em1.velocity[index_in * 3]);
- }
- }
-
- /* apply second input if in range */
- if (x >= em2->min[0] && x < em2->max[0] &&
- y >= em2->min[1] && y < em2->max[1] &&
- z >= em2->min[2] && z < em2->max[2])
- {
- int index_in = smoke_get_index(x - em2->min[0], em2->res[0], y - em2->min[1], em2->res[1], z - em2->min[2]);
-
- /* values */
- if (additive) {
- output->influence[index_out] += em2->influence[index_in] * sample_size;
- }
- else {
- output->influence[index_out] = MAX2(em2->influence[index_in], output->influence[index_out]);
- }
- if (output->velocity && em2->velocity) {
- /* last sample replaces the velocity */
- output->velocity[index_out * 3] = ADD_IF_LOWER(output->velocity[index_out * 3], em2->velocity[index_in * 3]);
- output->velocity[index_out * 3 + 1] = ADD_IF_LOWER(output->velocity[index_out * 3 + 1], em2->velocity[index_in * 3 + 1]);
- output->velocity[index_out * 3 + 2] = ADD_IF_LOWER(output->velocity[index_out * 3 + 2], em2->velocity[index_in * 3 + 2]);
- }
- }
- } // low res loop
-
-
-
- /* initialize high resolution input if available */
- if (output->influence_high) {
- for (x = output->hmin[0]; x < output->hmax[0]; x++)
- for (y = output->hmin[1]; y < output->hmax[1]; y++)
- for (z = output->hmin[2]; z < output->hmax[2]; z++) {
- int index_out = smoke_get_index(x - output->hmin[0], output->hres[0], y - output->hmin[1], output->hres[1], z - output->hmin[2]);
-
- /* initialize with first input if in range */
- if (x >= em1.hmin[0] && x < em1.hmax[0] &&
- y >= em1.hmin[1] && y < em1.hmax[1] &&
- z >= em1.hmin[2] && z < em1.hmax[2])
- {
- int index_in = smoke_get_index(x - em1.hmin[0], em1.hres[0], y - em1.hmin[1], em1.hres[1], z - em1.hmin[2]);
- /* values */
- output->influence_high[index_out] = em1.influence_high[index_in];
- }
-
- /* apply second input if in range */
- if (x >= em2->hmin[0] && x < em2->hmax[0] &&
- y >= em2->hmin[1] && y < em2->hmax[1] &&
- z >= em2->hmin[2] && z < em2->hmax[2])
- {
- int index_in = smoke_get_index(x - em2->hmin[0], em2->hres[0], y - em2->hmin[1], em2->hres[1], z - em2->hmin[2]);
-
- /* values */
- if (additive) {
- output->influence_high[index_out] += em2->influence_high[index_in] * sample_size;
- }
- else {
- output->influence_high[index_out] = MAX2(em2->influence_high[index_in], output->influence_high[index_out]);
- }
- }
- } // high res loop
- }
-
- /* free original data */
- em_freeData(&em1);
+ int i, x, y, z;
+
+ /* copyfill input 1 struct and clear output for new allocation */
+ EmissionMap em1;
+ memcpy(&em1, output, sizeof(EmissionMap));
+ memset(output, 0, sizeof(EmissionMap));
+
+ for (i = 0; i < 3; i++) {
+ if (em1.valid) {
+ output->min[i] = MIN2(em1.min[i], em2->min[i]);
+ output->max[i] = MAX2(em1.max[i], em2->max[i]);
+ }
+ else {
+ output->min[i] = em2->min[i];
+ output->max[i] = em2->max[i];
+ }
+ }
+ /* allocate output map */
+ em_allocateData(output, (em1.velocity || em2->velocity), hires_multiplier);
+
+ /* base resolution inputs */
+ for (x = output->min[0]; x < output->max[0]; x++)
+ for (y = output->min[1]; y < output->max[1]; y++)
+ for (z = output->min[2]; z < output->max[2]; z++) {
+ int index_out = smoke_get_index(x - output->min[0],
+ output->res[0],
+ y - output->min[1],
+ output->res[1],
+ z - output->min[2]);
+
+ /* initialize with first input if in range */
+ if (x >= em1.min[0] && x < em1.max[0] && y >= em1.min[1] && y < em1.max[1] &&
+ z >= em1.min[2] && z < em1.max[2]) {
+ int index_in = smoke_get_index(
+ x - em1.min[0], em1.res[0], y - em1.min[1], em1.res[1], z - em1.min[2]);
+
+ /* values */
+ output->influence[index_out] = em1.influence[index_in];
+ if (output->velocity && em1.velocity) {
+ copy_v3_v3(&output->velocity[index_out * 3], &em1.velocity[index_in * 3]);
+ }
+ }
+
+ /* apply second input if in range */
+ if (x >= em2->min[0] && x < em2->max[0] && y >= em2->min[1] && y < em2->max[1] &&
+ z >= em2->min[2] && z < em2->max[2]) {
+ int index_in = smoke_get_index(
+ x - em2->min[0], em2->res[0], y - em2->min[1], em2->res[1], z - em2->min[2]);
+
+ /* values */
+ if (additive) {
+ output->influence[index_out] += em2->influence[index_in] * sample_size;
+ }
+ else {
+ output->influence[index_out] = MAX2(em2->influence[index_in],
+ output->influence[index_out]);
+ }
+ if (output->velocity && em2->velocity) {
+ /* last sample replaces the velocity */
+ output->velocity[index_out * 3] = ADD_IF_LOWER(output->velocity[index_out * 3],
+ em2->velocity[index_in * 3]);
+ output->velocity[index_out * 3 + 1] = ADD_IF_LOWER(output->velocity[index_out * 3 + 1],
+ em2->velocity[index_in * 3 + 1]);
+ output->velocity[index_out * 3 + 2] = ADD_IF_LOWER(output->velocity[index_out * 3 + 2],
+ em2->velocity[index_in * 3 + 2]);
+ }
+ }
+ } // low res loop
+
+ /* initialize high resolution input if available */
+ if (output->influence_high) {
+ for (x = output->hmin[0]; x < output->hmax[0]; x++)
+ for (y = output->hmin[1]; y < output->hmax[1]; y++)
+ for (z = output->hmin[2]; z < output->hmax[2]; z++) {
+ int index_out = smoke_get_index(x - output->hmin[0],
+ output->hres[0],
+ y - output->hmin[1],
+ output->hres[1],
+ z - output->hmin[2]);
+
+ /* initialize with first input if in range */
+ if (x >= em1.hmin[0] && x < em1.hmax[0] && y >= em1.hmin[1] && y < em1.hmax[1] &&
+ z >= em1.hmin[2] && z < em1.hmax[2]) {
+ int index_in = smoke_get_index(
+ x - em1.hmin[0], em1.hres[0], y - em1.hmin[1], em1.hres[1], z - em1.hmin[2]);
+ /* values */
+ output->influence_high[index_out] = em1.influence_high[index_in];
+ }
+
+ /* apply second input if in range */
+ if (x >= em2->hmin[0] && x < em2->hmax[0] && y >= em2->hmin[1] && y < em2->hmax[1] &&
+ z >= em2->hmin[2] && z < em2->hmax[2]) {
+ int index_in = smoke_get_index(
+ x - em2->hmin[0], em2->hres[0], y - em2->hmin[1], em2->hres[1], z - em2->hmin[2]);
+
+ /* values */
+ if (additive) {
+ output->influence_high[index_out] += em2->influence_high[index_in] * sample_size;
+ }
+ else {
+ output->influence_high[index_out] = MAX2(em2->influence_high[index_in],
+ output->influence_high[index_out]);
+ }
+ }
+ } // high res loop
+ }
+
+ /* free original data */
+ em_freeData(&em1);
}
typedef struct EmitFromParticlesData {
- SmokeFlowSettings *sfs;
- KDTree_3d *tree;
- int hires_multiplier;
+ SmokeFlowSettings *sfs;
+ KDTree_3d *tree;
+ int hires_multiplier;
- EmissionMap *em;
- float *particle_vel;
- float hr;
+ EmissionMap *em;
+ float *particle_vel;
+ float hr;
- int *min, *max, *res;
+ int *min, *max, *res;
- float solid;
- float smooth;
- float hr_smooth;
+ float solid;
+ float smooth;
+ float hr_smooth;
} EmitFromParticlesData;
-static void emit_from_particles_task_cb(
- void *__restrict userdata,
- const int z,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void emit_from_particles_task_cb(void *__restrict userdata,
+ const int z,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- EmitFromParticlesData *data = userdata;
- SmokeFlowSettings *sfs = data->sfs;
- EmissionMap *em = data->em;
- const int hires_multiplier = data->hires_multiplier;
-
- for (int x = data->min[0]; x < data->max[0]; x++) {
- for (int y = data->min[1]; y < data->max[1]; y++) {
- /* take low res samples where possible */
- if (hires_multiplier <= 1 || !(x % hires_multiplier || y % hires_multiplier || z % hires_multiplier)) {
- /* get low res space coordinates */
- const int lx = x / hires_multiplier;
- const int ly = y / hires_multiplier;
- const int lz = z / hires_multiplier;
-
- const int index = smoke_get_index(lx - em->min[0], em->res[0], ly - em->min[1], em->res[1], lz - em->min[2]);
- const float ray_start[3] = {((float)lx) + 0.5f, ((float)ly) + 0.5f, ((float)lz) + 0.5f};
-
- /* find particle distance from the kdtree */
- KDTreeNearest_3d nearest;
- const float range = data->solid + data->smooth;
- BLI_kdtree_3d_find_nearest(data->tree, ray_start, &nearest);
-
- if (nearest.dist < range) {
- em->influence[index] = (nearest.dist < data->solid) ?
- 1.0f : (1.0f - (nearest.dist - data->solid) / data->smooth);
- /* Uses particle velocity as initial velocity for smoke */
- if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && (sfs->psys->part->phystype != PART_PHYS_NO)) {
- madd_v3_v3fl(&em->velocity[index * 3], &data->particle_vel[nearest.index * 3], sfs->vel_multi);
- }
- }
- }
-
- /* take high res samples if required */
- if (hires_multiplier > 1) {
- /* get low res space coordinates */
- const float lx = ((float)x) * data->hr;
- const float ly = ((float)y) * data->hr;
- const float lz = ((float)z) * data->hr;
-
- const int index = smoke_get_index(
- x - data->min[0], data->res[0], y - data->min[1], data->res[1], z - data->min[2]);
- const float ray_start[3] = {lx + 0.5f * data->hr, ly + 0.5f * data->hr, lz + 0.5f * data->hr};
-
- /* find particle distance from the kdtree */
- KDTreeNearest_3d nearest;
- const float range = data->solid + data->hr_smooth;
- BLI_kdtree_3d_find_nearest(data->tree, ray_start, &nearest);
-
- if (nearest.dist < range) {
- em->influence_high[index] = (nearest.dist < data->solid) ?
- 1.0f : (1.0f - (nearest.dist - data->solid) / data->smooth);
- }
- }
-
- }
- }
+ EmitFromParticlesData *data = userdata;
+ SmokeFlowSettings *sfs = data->sfs;
+ EmissionMap *em = data->em;
+ const int hires_multiplier = data->hires_multiplier;
+
+ for (int x = data->min[0]; x < data->max[0]; x++) {
+ for (int y = data->min[1]; y < data->max[1]; y++) {
+ /* take low res samples where possible */
+ if (hires_multiplier <= 1 ||
+ !(x % hires_multiplier || y % hires_multiplier || z % hires_multiplier)) {
+ /* get low res space coordinates */
+ const int lx = x / hires_multiplier;
+ const int ly = y / hires_multiplier;
+ const int lz = z / hires_multiplier;
+
+ const int index = smoke_get_index(
+ lx - em->min[0], em->res[0], ly - em->min[1], em->res[1], lz - em->min[2]);
+ const float ray_start[3] = {((float)lx) + 0.5f, ((float)ly) + 0.5f, ((float)lz) + 0.5f};
+
+ /* find particle distance from the kdtree */
+ KDTreeNearest_3d nearest;
+ const float range = data->solid + data->smooth;
+ BLI_kdtree_3d_find_nearest(data->tree, ray_start, &nearest);
+
+ if (nearest.dist < range) {
+ em->influence[index] = (nearest.dist < data->solid) ?
+ 1.0f :
+ (1.0f - (nearest.dist - data->solid) / data->smooth);
+ /* Uses particle velocity as initial velocity for smoke */
+ if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY &&
+ (sfs->psys->part->phystype != PART_PHYS_NO)) {
+ madd_v3_v3fl(
+ &em->velocity[index * 3], &data->particle_vel[nearest.index * 3], sfs->vel_multi);
+ }
+ }
+ }
+
+ /* take high res samples if required */
+ if (hires_multiplier > 1) {
+ /* get low res space coordinates */
+ const float lx = ((float)x) * data->hr;
+ const float ly = ((float)y) * data->hr;
+ const float lz = ((float)z) * data->hr;
+
+ const int index = smoke_get_index(
+ x - data->min[0], data->res[0], y - data->min[1], data->res[1], z - data->min[2]);
+ const float ray_start[3] = {
+ lx + 0.5f * data->hr, ly + 0.5f * data->hr, lz + 0.5f * data->hr};
+
+ /* find particle distance from the kdtree */
+ KDTreeNearest_3d nearest;
+ const float range = data->solid + data->hr_smooth;
+ BLI_kdtree_3d_find_nearest(data->tree, ray_start, &nearest);
+
+ if (nearest.dist < range) {
+ em->influence_high[index] = (nearest.dist < data->solid) ?
+ 1.0f :
+ (1.0f - (nearest.dist - data->solid) / data->smooth);
+ }
+ }
+ }
+ }
}
-static void emit_from_particles(
- Object *flow_ob, SmokeDomainSettings *sds, SmokeFlowSettings *sfs, EmissionMap *em, Depsgraph *depsgraph, Scene *scene, float dt)
+static void emit_from_particles(Object *flow_ob,
+ SmokeDomainSettings *sds,
+ SmokeFlowSettings *sfs,
+ EmissionMap *em,
+ Depsgraph *depsgraph,
+ Scene *scene,
+ float dt)
{
- if (sfs && sfs->psys && sfs->psys->part && ELEM(sfs->psys->part->type, PART_EMITTER, PART_FLUID)) // is particle system selected
- {
- ParticleSimulationData sim;
- ParticleSystem *psys = sfs->psys;
- float *particle_pos;
- float *particle_vel;
- int totpart = psys->totpart, totchild;
- int p = 0;
- int valid_particles = 0;
- int bounds_margin = 1;
-
- /* radius based flow */
- const float solid = sfs->particle_size * 0.5f;
- const float smooth = 0.5f; /* add 0.5 cells of linear falloff to reduce aliasing */
- int hires_multiplier = 1;
- KDTree_3d *tree = NULL;
-
- sim.depsgraph = depsgraph;
- sim.scene = scene;
- sim.ob = flow_ob;
- sim.psys = psys;
- sim.psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
-
- /* prepare curvemapping tables */
- if ((psys->part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && psys->part->clumpcurve)
- curvemapping_changed_all(psys->part->clumpcurve);
- if ((psys->part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && psys->part->roughcurve)
- curvemapping_changed_all(psys->part->roughcurve);
- if ((psys->part->child_flag & PART_CHILD_USE_TWIST_CURVE) && psys->part->twistcurve)
- curvemapping_changed_all(psys->part->twistcurve);
-
- /* initialize particle cache */
- if (psys->part->type == PART_HAIR) {
- // TODO: PART_HAIR not supported whatsoever
- totchild = 0;
- }
- else {
- totchild = psys->totchild * psys->part->disp / 100;
- }
-
- particle_pos = MEM_callocN(sizeof(float) * (totpart + totchild) * 3, "smoke_flow_particles");
- particle_vel = MEM_callocN(sizeof(float) * (totpart + totchild) * 3, "smoke_flow_particles");
-
- /* setup particle radius emission if enabled */
- if (sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE) {
- tree = BLI_kdtree_3d_new(psys->totpart + psys->totchild);
-
- /* check need for high resolution map */
- if ((sds->flags & MOD_SMOKE_HIGHRES) && (sds->highres_sampling == SM_HRES_FULLSAMPLE)) {
- hires_multiplier = sds->amplify + 1;
- }
-
- bounds_margin = (int)ceil(solid + smooth);
- }
-
- /* calculate local position for each particle */
- for (p = 0; p < totpart + totchild; p++)
- {
- ParticleKey state;
- float *pos;
- if (p < totpart) {
- if (psys->particles[p].flag & (PARS_NO_DISP | PARS_UNEXIST))
- continue;
- }
- else {
- /* handle child particle */
- ChildParticle *cpa = &psys->child[p - totpart];
- if (psys->particles[cpa->parent].flag & (PARS_NO_DISP | PARS_UNEXIST))
- continue;
- }
-
- state.time = DEG_get_ctime(depsgraph); /* use depsgraph time */
- if (psys_get_particle_state(&sim, p, &state, 0) == 0)
- continue;
-
- /* location */
- pos = &particle_pos[valid_particles * 3];
- copy_v3_v3(pos, state.co);
- smoke_pos_to_cell(sds, pos);
-
- /* velocity */
- copy_v3_v3(&particle_vel[valid_particles * 3], state.vel);
- mul_mat3_m4_v3(sds->imat, &particle_vel[valid_particles * 3]);
-
- if (sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE) {
- BLI_kdtree_3d_insert(tree, valid_particles, pos);
- }
-
- /* calculate emission map bounds */
- em_boundInsert(em, pos);
- valid_particles++;
- }
-
- /* set emission map */
- clampBoundsInDomain(sds, em->min, em->max, NULL, NULL, bounds_margin, dt);
- em_allocateData(em, sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY, hires_multiplier);
-
- if (!(sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE)) {
- for (p = 0; p < valid_particles; p++)
- {
- int cell[3];
- size_t i = 0;
- size_t index = 0;
- int badcell = 0;
-
- /* 1. get corresponding cell */
- cell[0] = floor(particle_pos[p * 3]) - em->min[0];
- cell[1] = floor(particle_pos[p * 3 + 1]) - em->min[1];
- cell[2] = floor(particle_pos[p * 3 + 2]) - em->min[2];
- /* check if cell is valid (in the domain boundary) */
- for (i = 0; i < 3; i++) {
- if ((cell[i] > em->res[i] - 1) || (cell[i] < 0)) {
- badcell = 1;
- break;
- }
- }
- if (badcell)
- continue;
- /* get cell index */
- index = smoke_get_index(cell[0], em->res[0], cell[1], em->res[1], cell[2]);
- /* Add influence to emission map */
- em->influence[index] = 1.0f;
- /* Uses particle velocity as initial velocity for smoke */
- if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && (psys->part->phystype != PART_PHYS_NO))
- {
- madd_v3_v3fl(&em->velocity[index * 3], &particle_vel[p * 3], sfs->vel_multi);
- }
- } // particles loop
- }
- else if (valid_particles > 0) { // MOD_SMOKE_FLOW_USE_PART_SIZE
- int min[3], max[3], res[3];
- const float hr = 1.0f / ((float)hires_multiplier);
- /* slightly adjust high res antialias smoothness based on number of divisions
- * to allow smaller details but yet not differing too much from the low res size */
- const float hr_smooth = smooth * powf(hr, 1.0f / 3.0f);
-
- /* setup loop bounds */
- for (int i = 0; i < 3; i++) {
- min[i] = em->min[i] * hires_multiplier;
- max[i] = em->max[i] * hires_multiplier;
- res[i] = em->res[i] * hires_multiplier;
- }
-
- BLI_kdtree_3d_balance(tree);
-
- EmitFromParticlesData data = {
- .sfs = sfs, .tree = tree, .hires_multiplier = hires_multiplier, .hr = hr,
- .em = em, .particle_vel = particle_vel, .min = min, .max = max, .res = res,
- .solid = solid, .smooth = smooth, .hr_smooth = hr_smooth,
- };
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
- BLI_task_parallel_range(min[2], max[2],
- &data,
- emit_from_particles_task_cb,
- &settings);
- }
-
- if (sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE) {
- BLI_kdtree_3d_free(tree);
- }
-
- /* free data */
- if (particle_pos)
- MEM_freeN(particle_pos);
- if (particle_vel)
- MEM_freeN(particle_vel);
- }
+ if (sfs && sfs->psys && sfs->psys->part &&
+ ELEM(sfs->psys->part->type, PART_EMITTER, PART_FLUID)) // is particle system selected
+ {
+ ParticleSimulationData sim;
+ ParticleSystem *psys = sfs->psys;
+ float *particle_pos;
+ float *particle_vel;
+ int totpart = psys->totpart, totchild;
+ int p = 0;
+ int valid_particles = 0;
+ int bounds_margin = 1;
+
+ /* radius based flow */
+ const float solid = sfs->particle_size * 0.5f;
+ const float smooth = 0.5f; /* add 0.5 cells of linear falloff to reduce aliasing */
+ int hires_multiplier = 1;
+ KDTree_3d *tree = NULL;
+
+ sim.depsgraph = depsgraph;
+ sim.scene = scene;
+ sim.ob = flow_ob;
+ sim.psys = psys;
+ sim.psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
+
+ /* prepare curvemapping tables */
+ if ((psys->part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && psys->part->clumpcurve)
+ curvemapping_changed_all(psys->part->clumpcurve);
+ if ((psys->part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && psys->part->roughcurve)
+ curvemapping_changed_all(psys->part->roughcurve);
+ if ((psys->part->child_flag & PART_CHILD_USE_TWIST_CURVE) && psys->part->twistcurve)
+ curvemapping_changed_all(psys->part->twistcurve);
+
+ /* initialize particle cache */
+ if (psys->part->type == PART_HAIR) {
+ // TODO: PART_HAIR not supported whatsoever
+ totchild = 0;
+ }
+ else {
+ totchild = psys->totchild * psys->part->disp / 100;
+ }
+
+ particle_pos = MEM_callocN(sizeof(float) * (totpart + totchild) * 3, "smoke_flow_particles");
+ particle_vel = MEM_callocN(sizeof(float) * (totpart + totchild) * 3, "smoke_flow_particles");
+
+ /* setup particle radius emission if enabled */
+ if (sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE) {
+ tree = BLI_kdtree_3d_new(psys->totpart + psys->totchild);
+
+ /* check need for high resolution map */
+ if ((sds->flags & MOD_SMOKE_HIGHRES) && (sds->highres_sampling == SM_HRES_FULLSAMPLE)) {
+ hires_multiplier = sds->amplify + 1;
+ }
+
+ bounds_margin = (int)ceil(solid + smooth);
+ }
+
+ /* calculate local position for each particle */
+ for (p = 0; p < totpart + totchild; p++) {
+ ParticleKey state;
+ float *pos;
+ if (p < totpart) {
+ if (psys->particles[p].flag & (PARS_NO_DISP | PARS_UNEXIST))
+ continue;
+ }
+ else {
+ /* handle child particle */
+ ChildParticle *cpa = &psys->child[p - totpart];
+ if (psys->particles[cpa->parent].flag & (PARS_NO_DISP | PARS_UNEXIST))
+ continue;
+ }
+
+ state.time = DEG_get_ctime(depsgraph); /* use depsgraph time */
+ if (psys_get_particle_state(&sim, p, &state, 0) == 0)
+ continue;
+
+ /* location */
+ pos = &particle_pos[valid_particles * 3];
+ copy_v3_v3(pos, state.co);
+ smoke_pos_to_cell(sds, pos);
+
+ /* velocity */
+ copy_v3_v3(&particle_vel[valid_particles * 3], state.vel);
+ mul_mat3_m4_v3(sds->imat, &particle_vel[valid_particles * 3]);
+
+ if (sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE) {
+ BLI_kdtree_3d_insert(tree, valid_particles, pos);
+ }
+
+ /* calculate emission map bounds */
+ em_boundInsert(em, pos);
+ valid_particles++;
+ }
+
+ /* set emission map */
+ clampBoundsInDomain(sds, em->min, em->max, NULL, NULL, bounds_margin, dt);
+ em_allocateData(em, sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY, hires_multiplier);
+
+ if (!(sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE)) {
+ for (p = 0; p < valid_particles; p++) {
+ int cell[3];
+ size_t i = 0;
+ size_t index = 0;
+ int badcell = 0;
+
+ /* 1. get corresponding cell */
+ cell[0] = floor(particle_pos[p * 3]) - em->min[0];
+ cell[1] = floor(particle_pos[p * 3 + 1]) - em->min[1];
+ cell[2] = floor(particle_pos[p * 3 + 2]) - em->min[2];
+ /* check if cell is valid (in the domain boundary) */
+ for (i = 0; i < 3; i++) {
+ if ((cell[i] > em->res[i] - 1) || (cell[i] < 0)) {
+ badcell = 1;
+ break;
+ }
+ }
+ if (badcell)
+ continue;
+ /* get cell index */
+ index = smoke_get_index(cell[0], em->res[0], cell[1], em->res[1], cell[2]);
+ /* Add influence to emission map */
+ em->influence[index] = 1.0f;
+ /* Uses particle velocity as initial velocity for smoke */
+ if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && (psys->part->phystype != PART_PHYS_NO)) {
+ madd_v3_v3fl(&em->velocity[index * 3], &particle_vel[p * 3], sfs->vel_multi);
+ }
+ } // particles loop
+ }
+ else if (valid_particles > 0) { // MOD_SMOKE_FLOW_USE_PART_SIZE
+ int min[3], max[3], res[3];
+ const float hr = 1.0f / ((float)hires_multiplier);
+ /* slightly adjust high res antialias smoothness based on number of divisions
+ * to allow smaller details but yet not differing too much from the low res size */
+ const float hr_smooth = smooth * powf(hr, 1.0f / 3.0f);
+
+ /* setup loop bounds */
+ for (int i = 0; i < 3; i++) {
+ min[i] = em->min[i] * hires_multiplier;
+ max[i] = em->max[i] * hires_multiplier;
+ res[i] = em->res[i] * hires_multiplier;
+ }
+
+ BLI_kdtree_3d_balance(tree);
+
+ EmitFromParticlesData data = {
+ .sfs = sfs,
+ .tree = tree,
+ .hires_multiplier = hires_multiplier,
+ .hr = hr,
+ .em = em,
+ .particle_vel = particle_vel,
+ .min = min,
+ .max = max,
+ .res = res,
+ .solid = solid,
+ .smooth = smooth,
+ .hr_smooth = hr_smooth,
+ };
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
+ BLI_task_parallel_range(min[2], max[2], &data, emit_from_particles_task_cb, &settings);
+ }
+
+ if (sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE) {
+ BLI_kdtree_3d_free(tree);
+ }
+
+ /* free data */
+ if (particle_pos)
+ MEM_freeN(particle_pos);
+ if (particle_vel)
+ MEM_freeN(particle_vel);
+ }
}
-static void sample_mesh(
- SmokeFlowSettings *sfs,
- const MVert *mvert, const MLoop *mloop, const MLoopTri *mlooptri, const MLoopUV *mloopuv,
- float *influence_map, float *velocity_map, int index, const int base_res[3], float flow_center[3],
- BVHTreeFromMesh *treeData, const float ray_start[3], const float *vert_vel,
- bool has_velocity, int defgrp_index, MDeformVert *dvert,
- float x, float y, float z)
+static void sample_mesh(SmokeFlowSettings *sfs,
+ const MVert *mvert,
+ const MLoop *mloop,
+ const MLoopTri *mlooptri,
+ const MLoopUV *mloopuv,
+ float *influence_map,
+ float *velocity_map,
+ int index,
+ const int base_res[3],
+ float flow_center[3],
+ BVHTreeFromMesh *treeData,
+ const float ray_start[3],
+ const float *vert_vel,
+ bool has_velocity,
+ int defgrp_index,
+ MDeformVert *dvert,
+ float x,
+ float y,
+ float z)
{
- float ray_dir[3] = {1.0f, 0.0f, 0.0f};
- BVHTreeRayHit hit = {0};
- BVHTreeNearest nearest = {0};
-
- float volume_factor = 0.0f;
- float sample_str = 0.0f;
-
- hit.index = -1;
- hit.dist = 9999;
- nearest.index = -1;
- nearest.dist_sq = sfs->surface_distance * sfs->surface_distance; /* find_nearest uses squared distance */
-
- /* Check volume collision */
- if (sfs->volume_density) {
- if (BLI_bvhtree_ray_cast(treeData->tree, ray_start, ray_dir, 0.0f, &hit, treeData->raycast_callback, treeData) != -1) {
- float dot = ray_dir[0] * hit.no[0] + ray_dir[1] * hit.no[1] + ray_dir[2] * hit.no[2];
- /* If ray and hit face normal are facing same direction
- * hit point is inside a closed mesh. */
- if (dot >= 0) {
- /* Also cast a ray in opposite direction to make sure
- * point is at least surrounded by two faces */
- negate_v3(ray_dir);
- hit.index = -1;
- hit.dist = 9999;
-
- BLI_bvhtree_ray_cast(treeData->tree, ray_start, ray_dir, 0.0f, &hit, treeData->raycast_callback, treeData);
- if (hit.index != -1) {
- volume_factor = sfs->volume_density;
- }
- }
- }
- }
-
- /* find the nearest point on the mesh */
- if (BLI_bvhtree_find_nearest(treeData->tree, ray_start, &nearest, treeData->nearest_callback, treeData) != -1) {
- float weights[3];
- int v1, v2, v3, f_index = nearest.index;
- float n1[3], n2[3], n3[3], hit_normal[3];
-
- /* emit from surface based on distance */
- if (sfs->surface_distance) {
- sample_str = sqrtf(nearest.dist_sq) / sfs->surface_distance;
- CLAMP(sample_str, 0.0f, 1.0f);
- sample_str = pow(1.0f - sample_str, 0.5f);
- }
- else
- sample_str = 0.0f;
-
- /* calculate barycentric weights for nearest point */
- v1 = mloop[mlooptri[f_index].tri[0]].v;
- v2 = mloop[mlooptri[f_index].tri[1]].v;
- v3 = mloop[mlooptri[f_index].tri[2]].v;
- interp_weights_tri_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, nearest.co);
-
- if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && velocity_map) {
- /* apply normal directional velocity */
- if (sfs->vel_normal) {
- /* interpolate vertex normal vectors to get nearest point normal */
- normal_short_to_float_v3(n1, mvert[v1].no);
- normal_short_to_float_v3(n2, mvert[v2].no);
- normal_short_to_float_v3(n3, mvert[v3].no);
- interp_v3_v3v3v3(hit_normal, n1, n2, n3, weights);
- normalize_v3(hit_normal);
- /* apply normal directional and random velocity
- * - TODO: random disabled for now since it doesn't really work well as pressure calc smoothens it out... */
- velocity_map[index * 3] += hit_normal[0] * sfs->vel_normal * 0.25f;
- velocity_map[index * 3 + 1] += hit_normal[1] * sfs->vel_normal * 0.25f;
- velocity_map[index * 3 + 2] += hit_normal[2] * sfs->vel_normal * 0.25f;
- /* TODO: for fire emitted from mesh surface we can use
- * Vf = Vs + (Ps/Pf - 1)*S to model gaseous expansion from solid to fuel */
- }
- /* apply object velocity */
- if (has_velocity && sfs->vel_multi) {
- float hit_vel[3];
- interp_v3_v3v3v3(hit_vel, &vert_vel[v1 * 3], &vert_vel[v2 * 3], &vert_vel[v3 * 3], weights);
- velocity_map[index * 3] += hit_vel[0] * sfs->vel_multi;
- velocity_map[index * 3 + 1] += hit_vel[1] * sfs->vel_multi;
- velocity_map[index * 3 + 2] += hit_vel[2] * sfs->vel_multi;
- }
- }
-
- /* apply vertex group influence if used */
- if (defgrp_index != -1 && dvert) {
- float weight_mask = defvert_find_weight(&dvert[v1], defgrp_index) * weights[0] +
- defvert_find_weight(&dvert[v2], defgrp_index) * weights[1] +
- defvert_find_weight(&dvert[v3], defgrp_index) * weights[2];
- sample_str *= weight_mask;
- }
-
- /* apply emission texture */
- if ((sfs->flags & MOD_SMOKE_FLOW_TEXTUREEMIT) && sfs->noise_texture) {
- float tex_co[3] = {0};
- TexResult texres;
-
- if (sfs->texture_type == MOD_SMOKE_FLOW_TEXTURE_MAP_AUTO) {
- tex_co[0] = ((x - flow_center[0]) / base_res[0]) / sfs->texture_size;
- tex_co[1] = ((y - flow_center[1]) / base_res[1]) / sfs->texture_size;
- tex_co[2] = ((z - flow_center[2]) / base_res[2] - sfs->texture_offset) / sfs->texture_size;
- }
- else if (mloopuv) {
- const float *uv[3];
- uv[0] = mloopuv[mlooptri[f_index].tri[0]].uv;
- uv[1] = mloopuv[mlooptri[f_index].tri[1]].uv;
- uv[2] = mloopuv[mlooptri[f_index].tri[2]].uv;
-
- interp_v2_v2v2v2(tex_co, UNPACK3(uv), weights);
-
- /* map between -1.0f and 1.0f */
- tex_co[0] = tex_co[0] * 2.0f - 1.0f;
- tex_co[1] = tex_co[1] * 2.0f - 1.0f;
- tex_co[2] = sfs->texture_offset;
- }
- texres.nor = NULL;
- BKE_texture_get_value(NULL, sfs->noise_texture, tex_co, &texres, false);
- sample_str *= texres.tin;
- }
- }
-
- /* multiply initial velocity by emitter influence */
- if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && velocity_map) {
- mul_v3_fl(&velocity_map[index * 3], sample_str);
- }
-
- /* apply final influence based on volume factor */
- influence_map[index] = MAX2(volume_factor, sample_str);
+ float ray_dir[3] = {1.0f, 0.0f, 0.0f};
+ BVHTreeRayHit hit = {0};
+ BVHTreeNearest nearest = {0};
+
+ float volume_factor = 0.0f;
+ float sample_str = 0.0f;
+
+ hit.index = -1;
+ hit.dist = 9999;
+ nearest.index = -1;
+ nearest.dist_sq = sfs->surface_distance *
+ sfs->surface_distance; /* find_nearest uses squared distance */
+
+ /* Check volume collision */
+ if (sfs->volume_density) {
+ if (BLI_bvhtree_ray_cast(treeData->tree,
+ ray_start,
+ ray_dir,
+ 0.0f,
+ &hit,
+ treeData->raycast_callback,
+ treeData) != -1) {
+ float dot = ray_dir[0] * hit.no[0] + ray_dir[1] * hit.no[1] + ray_dir[2] * hit.no[2];
+ /* If ray and hit face normal are facing same direction
+ * hit point is inside a closed mesh. */
+ if (dot >= 0) {
+ /* Also cast a ray in opposite direction to make sure
+ * point is at least surrounded by two faces */
+ negate_v3(ray_dir);
+ hit.index = -1;
+ hit.dist = 9999;
+
+ BLI_bvhtree_ray_cast(
+ treeData->tree, ray_start, ray_dir, 0.0f, &hit, treeData->raycast_callback, treeData);
+ if (hit.index != -1) {
+ volume_factor = sfs->volume_density;
+ }
+ }
+ }
+ }
+
+ /* find the nearest point on the mesh */
+ if (BLI_bvhtree_find_nearest(
+ treeData->tree, ray_start, &nearest, treeData->nearest_callback, treeData) != -1) {
+ float weights[3];
+ int v1, v2, v3, f_index = nearest.index;
+ float n1[3], n2[3], n3[3], hit_normal[3];
+
+ /* emit from surface based on distance */
+ if (sfs->surface_distance) {
+ sample_str = sqrtf(nearest.dist_sq) / sfs->surface_distance;
+ CLAMP(sample_str, 0.0f, 1.0f);
+ sample_str = pow(1.0f - sample_str, 0.5f);
+ }
+ else
+ sample_str = 0.0f;
+
+ /* calculate barycentric weights for nearest point */
+ v1 = mloop[mlooptri[f_index].tri[0]].v;
+ v2 = mloop[mlooptri[f_index].tri[1]].v;
+ v3 = mloop[mlooptri[f_index].tri[2]].v;
+ interp_weights_tri_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, nearest.co);
+
+ if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && velocity_map) {
+ /* apply normal directional velocity */
+ if (sfs->vel_normal) {
+ /* interpolate vertex normal vectors to get nearest point normal */
+ normal_short_to_float_v3(n1, mvert[v1].no);
+ normal_short_to_float_v3(n2, mvert[v2].no);
+ normal_short_to_float_v3(n3, mvert[v3].no);
+ interp_v3_v3v3v3(hit_normal, n1, n2, n3, weights);
+ normalize_v3(hit_normal);
+ /* apply normal directional and random velocity
+ * - TODO: random disabled for now since it doesn't really work well as pressure calc smoothens it out... */
+ velocity_map[index * 3] += hit_normal[0] * sfs->vel_normal * 0.25f;
+ velocity_map[index * 3 + 1] += hit_normal[1] * sfs->vel_normal * 0.25f;
+ velocity_map[index * 3 + 2] += hit_normal[2] * sfs->vel_normal * 0.25f;
+ /* TODO: for fire emitted from mesh surface we can use
+ * Vf = Vs + (Ps/Pf - 1)*S to model gaseous expansion from solid to fuel */
+ }
+ /* apply object velocity */
+ if (has_velocity && sfs->vel_multi) {
+ float hit_vel[3];
+ interp_v3_v3v3v3(
+ hit_vel, &vert_vel[v1 * 3], &vert_vel[v2 * 3], &vert_vel[v3 * 3], weights);
+ velocity_map[index * 3] += hit_vel[0] * sfs->vel_multi;
+ velocity_map[index * 3 + 1] += hit_vel[1] * sfs->vel_multi;
+ velocity_map[index * 3 + 2] += hit_vel[2] * sfs->vel_multi;
+ }
+ }
+
+ /* apply vertex group influence if used */
+ if (defgrp_index != -1 && dvert) {
+ float weight_mask = defvert_find_weight(&dvert[v1], defgrp_index) * weights[0] +
+ defvert_find_weight(&dvert[v2], defgrp_index) * weights[1] +
+ defvert_find_weight(&dvert[v3], defgrp_index) * weights[2];
+ sample_str *= weight_mask;
+ }
+
+ /* apply emission texture */
+ if ((sfs->flags & MOD_SMOKE_FLOW_TEXTUREEMIT) && sfs->noise_texture) {
+ float tex_co[3] = {0};
+ TexResult texres;
+
+ if (sfs->texture_type == MOD_SMOKE_FLOW_TEXTURE_MAP_AUTO) {
+ tex_co[0] = ((x - flow_center[0]) / base_res[0]) / sfs->texture_size;
+ tex_co[1] = ((y - flow_center[1]) / base_res[1]) / sfs->texture_size;
+ tex_co[2] = ((z - flow_center[2]) / base_res[2] - sfs->texture_offset) / sfs->texture_size;
+ }
+ else if (mloopuv) {
+ const float *uv[3];
+ uv[0] = mloopuv[mlooptri[f_index].tri[0]].uv;
+ uv[1] = mloopuv[mlooptri[f_index].tri[1]].uv;
+ uv[2] = mloopuv[mlooptri[f_index].tri[2]].uv;
+
+ interp_v2_v2v2v2(tex_co, UNPACK3(uv), weights);
+
+ /* map between -1.0f and 1.0f */
+ tex_co[0] = tex_co[0] * 2.0f - 1.0f;
+ tex_co[1] = tex_co[1] * 2.0f - 1.0f;
+ tex_co[2] = sfs->texture_offset;
+ }
+ texres.nor = NULL;
+ BKE_texture_get_value(NULL, sfs->noise_texture, tex_co, &texres, false);
+ sample_str *= texres.tin;
+ }
+ }
+
+ /* multiply initial velocity by emitter influence */
+ if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && velocity_map) {
+ mul_v3_fl(&velocity_map[index * 3], sample_str);
+ }
+
+ /* apply final influence based on volume factor */
+ influence_map[index] = MAX2(volume_factor, sample_str);
}
typedef struct EmitFromDMData {
- SmokeDomainSettings *sds;
- SmokeFlowSettings *sfs;
- const MVert *mvert;
- const MLoop *mloop;
- const MLoopTri *mlooptri;
- const MLoopUV *mloopuv;
- MDeformVert *dvert;
- int defgrp_index;
-
- BVHTreeFromMesh *tree;
- int hires_multiplier;
- float hr;
-
- EmissionMap *em;
- bool has_velocity;
- float *vert_vel;
-
- float *flow_center;
- int *min, *max, *res;
+ SmokeDomainSettings *sds;
+ SmokeFlowSettings *sfs;
+ const MVert *mvert;
+ const MLoop *mloop;
+ const MLoopTri *mlooptri;
+ const MLoopUV *mloopuv;
+ MDeformVert *dvert;
+ int defgrp_index;
+
+ BVHTreeFromMesh *tree;
+ int hires_multiplier;
+ float hr;
+
+ EmissionMap *em;
+ bool has_velocity;
+ float *vert_vel;
+
+ float *flow_center;
+ int *min, *max, *res;
} EmitFromDMData;
-static void emit_from_mesh_task_cb(
- void *__restrict userdata,
- const int z,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void emit_from_mesh_task_cb(void *__restrict userdata,
+ const int z,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- EmitFromDMData *data = userdata;
- EmissionMap *em = data->em;
- const int hires_multiplier = data->hires_multiplier;
-
- for (int x = data->min[0]; x < data->max[0]; x++) {
- for (int y = data->min[1]; y < data->max[1]; y++) {
- /* take low res samples where possible */
- if (hires_multiplier <= 1 || !(x % hires_multiplier || y % hires_multiplier || z % hires_multiplier)) {
- /* get low res space coordinates */
- const int lx = x / hires_multiplier;
- const int ly = y / hires_multiplier;
- const int lz = z / hires_multiplier;
-
- const int index = smoke_get_index(
- lx - em->min[0], em->res[0], ly - em->min[1], em->res[1], lz - em->min[2]);
- const float ray_start[3] = {((float)lx) + 0.5f, ((float)ly) + 0.5f, ((float)lz) + 0.5f};
-
- sample_mesh(
- data->sfs, data->mvert, data->mloop, data->mlooptri, data->mloopuv,
- em->influence, em->velocity, index, data->sds->base_res, data->flow_center,
- data->tree, ray_start, data->vert_vel, data->has_velocity, data->defgrp_index, data->dvert,
- (float)lx, (float)ly, (float)lz);
- }
-
- /* take high res samples if required */
- if (hires_multiplier > 1) {
- /* get low res space coordinates */
- const float lx = ((float)x) * data->hr;
- const float ly = ((float)y) * data->hr;
- const float lz = ((float)z) * data->hr;
-
- const int index = smoke_get_index(
- x - data->min[0], data->res[0], y - data->min[1], data->res[1], z - data->min[2]);
- const float ray_start[3] = {lx + 0.5f * data->hr, ly + 0.5f * data->hr, lz + 0.5f * data->hr};
-
- sample_mesh(
- data->sfs, data->mvert, data->mloop, data->mlooptri, data->mloopuv,
- em->influence_high, NULL, index, data->sds->base_res, data->flow_center,
- data->tree, ray_start, data->vert_vel, data->has_velocity, data->defgrp_index, data->dvert,
- /* x,y,z needs to be always lowres */
- lx, ly, lz);
- }
- }
- }
+ EmitFromDMData *data = userdata;
+ EmissionMap *em = data->em;
+ const int hires_multiplier = data->hires_multiplier;
+
+ for (int x = data->min[0]; x < data->max[0]; x++) {
+ for (int y = data->min[1]; y < data->max[1]; y++) {
+ /* take low res samples where possible */
+ if (hires_multiplier <= 1 ||
+ !(x % hires_multiplier || y % hires_multiplier || z % hires_multiplier)) {
+ /* get low res space coordinates */
+ const int lx = x / hires_multiplier;
+ const int ly = y / hires_multiplier;
+ const int lz = z / hires_multiplier;
+
+ const int index = smoke_get_index(
+ lx - em->min[0], em->res[0], ly - em->min[1], em->res[1], lz - em->min[2]);
+ const float ray_start[3] = {((float)lx) + 0.5f, ((float)ly) + 0.5f, ((float)lz) + 0.5f};
+
+ sample_mesh(data->sfs,
+ data->mvert,
+ data->mloop,
+ data->mlooptri,
+ data->mloopuv,
+ em->influence,
+ em->velocity,
+ index,
+ data->sds->base_res,
+ data->flow_center,
+ data->tree,
+ ray_start,
+ data->vert_vel,
+ data->has_velocity,
+ data->defgrp_index,
+ data->dvert,
+ (float)lx,
+ (float)ly,
+ (float)lz);
+ }
+
+ /* take high res samples if required */
+ if (hires_multiplier > 1) {
+ /* get low res space coordinates */
+ const float lx = ((float)x) * data->hr;
+ const float ly = ((float)y) * data->hr;
+ const float lz = ((float)z) * data->hr;
+
+ const int index = smoke_get_index(
+ x - data->min[0], data->res[0], y - data->min[1], data->res[1], z - data->min[2]);
+ const float ray_start[3] = {
+ lx + 0.5f * data->hr, ly + 0.5f * data->hr, lz + 0.5f * data->hr};
+
+ sample_mesh(data->sfs,
+ data->mvert,
+ data->mloop,
+ data->mlooptri,
+ data->mloopuv,
+ em->influence_high,
+ NULL,
+ index,
+ data->sds->base_res,
+ data->flow_center,
+ data->tree,
+ ray_start,
+ data->vert_vel,
+ data->has_velocity,
+ data->defgrp_index,
+ data->dvert,
+ /* x,y,z needs to be always lowres */
+ lx,
+ ly,
+ lz);
+ }
+ }
+ }
}
-static void emit_from_mesh(Object *flow_ob, SmokeDomainSettings *sds, SmokeFlowSettings *sfs, EmissionMap *em, float dt)
+static void emit_from_mesh(
+ Object *flow_ob, SmokeDomainSettings *sds, SmokeFlowSettings *sfs, EmissionMap *em, float dt)
{
- if (sfs->mesh) {
- Mesh *me;
- int defgrp_index = sfs->vgroup_density - 1;
- MDeformVert *dvert = NULL;
- MVert *mvert = NULL;
- const MLoopTri *mlooptri = NULL;
- const MLoopUV *mloopuv = NULL;
- const MLoop *mloop = NULL;
- BVHTreeFromMesh treeData = {NULL};
- int numOfVerts, i;
- float flow_center[3] = {0};
-
- float *vert_vel = NULL;
- int has_velocity = 0;
- int min[3], max[3], res[3];
- int hires_multiplier = 1;
-
- /* copy mesh for thread safety because we modify it,
- * main issue is its VertArray being modified, then replaced and freed
- */
- me = BKE_mesh_copy_for_eval(sfs->mesh, true);
-
- /* Duplicate vertices to modify. */
- if (me->mvert) {
- me->mvert = MEM_dupallocN(me->mvert);
- CustomData_set_layer(&me->vdata, CD_MVERT, me->mvert);
- }
-
- BKE_mesh_ensure_normals(me);
- mvert = me->mvert;
- numOfVerts = me->totvert;
- dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT);
- mloopuv = CustomData_get_layer_named(&me->ldata, CD_MLOOPUV, sfs->uvlayer_name);
- mloop = me->mloop;
- mlooptri = BKE_mesh_runtime_looptri_ensure(me);
-
- if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) {
- vert_vel = MEM_callocN(sizeof(float) * numOfVerts * 3, "smoke_flow_velocity");
-
- if (sfs->numverts != numOfVerts || !sfs->verts_old) {
- if (sfs->verts_old) MEM_freeN(sfs->verts_old);
- sfs->verts_old = MEM_callocN(sizeof(float) * numOfVerts * 3, "smoke_flow_verts_old");
- sfs->numverts = numOfVerts;
- }
- else {
- has_velocity = 1;
- }
- }
-
- /* Transform mesh vertices to
- * domain grid space for fast lookups */
- for (i = 0; i < numOfVerts; i++) {
- float n[3];
- /* vert pos */
- mul_m4_v3(flow_ob->obmat, mvert[i].co);
- smoke_pos_to_cell(sds, mvert[i].co);
- /* vert normal */
- normal_short_to_float_v3(n, mvert[i].no);
- mul_mat3_m4_v3(flow_ob->obmat, n);
- mul_mat3_m4_v3(sds->imat, n);
- normalize_v3(n);
- normal_float_to_short_v3(mvert[i].no, n);
- /* vert velocity */
- if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) {
- float co[3];
- add_v3fl_v3fl_v3i(co, mvert[i].co, sds->shift);
- if (has_velocity) {
- sub_v3_v3v3(&vert_vel[i * 3], co, &sfs->verts_old[i * 3]);
- mul_v3_fl(&vert_vel[i * 3], sds->dx / dt);
- }
- copy_v3_v3(&sfs->verts_old[i * 3], co);
- }
-
- /* calculate emission map bounds */
- em_boundInsert(em, mvert[i].co);
- }
- mul_m4_v3(flow_ob->obmat, flow_center);
- smoke_pos_to_cell(sds, flow_center);
-
- /* check need for high resolution map */
- if ((sds->flags & MOD_SMOKE_HIGHRES) && (sds->highres_sampling == SM_HRES_FULLSAMPLE)) {
- hires_multiplier = sds->amplify + 1;
- }
-
- /* set emission map */
- clampBoundsInDomain(sds, em->min, em->max, NULL, NULL, (int)ceil(sfs->surface_distance), dt);
- em_allocateData(em, sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY, hires_multiplier);
-
- /* setup loop bounds */
- for (i = 0; i < 3; i++) {
- min[i] = em->min[i] * hires_multiplier;
- max[i] = em->max[i] * hires_multiplier;
- res[i] = em->res[i] * hires_multiplier;
- }
-
- if (BKE_bvhtree_from_mesh_get(&treeData, me, BVHTREE_FROM_LOOPTRI, 4)) {
- const float hr = 1.0f / ((float)hires_multiplier);
-
- EmitFromDMData data = {
- .sds = sds, .sfs = sfs,
- .mvert = mvert, .mloop = mloop, .mlooptri = mlooptri, .mloopuv = mloopuv,
- .dvert = dvert, .defgrp_index = defgrp_index,
- .tree = &treeData, .hires_multiplier = hires_multiplier, .hr = hr,
- .em = em, .has_velocity = has_velocity, .vert_vel = vert_vel,
- .flow_center = flow_center, .min = min, .max = max, .res = res,
- };
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
- BLI_task_parallel_range(min[2], max[2],
- &data,
- emit_from_mesh_task_cb,
- &settings);
- }
- /* free bvh tree */
- free_bvhtree_from_mesh(&treeData);
-
- if (vert_vel) {
- MEM_freeN(vert_vel);
- }
-
- if (me->mvert) {
- MEM_freeN(me->mvert);
- }
- BKE_id_free(NULL, me);
- }
+ if (sfs->mesh) {
+ Mesh *me;
+ int defgrp_index = sfs->vgroup_density - 1;
+ MDeformVert *dvert = NULL;
+ MVert *mvert = NULL;
+ const MLoopTri *mlooptri = NULL;
+ const MLoopUV *mloopuv = NULL;
+ const MLoop *mloop = NULL;
+ BVHTreeFromMesh treeData = {NULL};
+ int numOfVerts, i;
+ float flow_center[3] = {0};
+
+ float *vert_vel = NULL;
+ int has_velocity = 0;
+ int min[3], max[3], res[3];
+ int hires_multiplier = 1;
+
+ /* copy mesh for thread safety because we modify it,
+ * main issue is its VertArray being modified, then replaced and freed
+ */
+ me = BKE_mesh_copy_for_eval(sfs->mesh, true);
+
+ /* Duplicate vertices to modify. */
+ if (me->mvert) {
+ me->mvert = MEM_dupallocN(me->mvert);
+ CustomData_set_layer(&me->vdata, CD_MVERT, me->mvert);
+ }
+
+ BKE_mesh_ensure_normals(me);
+ mvert = me->mvert;
+ numOfVerts = me->totvert;
+ dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT);
+ mloopuv = CustomData_get_layer_named(&me->ldata, CD_MLOOPUV, sfs->uvlayer_name);
+ mloop = me->mloop;
+ mlooptri = BKE_mesh_runtime_looptri_ensure(me);
+
+ if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) {
+ vert_vel = MEM_callocN(sizeof(float) * numOfVerts * 3, "smoke_flow_velocity");
+
+ if (sfs->numverts != numOfVerts || !sfs->verts_old) {
+ if (sfs->verts_old)
+ MEM_freeN(sfs->verts_old);
+ sfs->verts_old = MEM_callocN(sizeof(float) * numOfVerts * 3, "smoke_flow_verts_old");
+ sfs->numverts = numOfVerts;
+ }
+ else {
+ has_velocity = 1;
+ }
+ }
+
+ /* Transform mesh vertices to
+ * domain grid space for fast lookups */
+ for (i = 0; i < numOfVerts; i++) {
+ float n[3];
+ /* vert pos */
+ mul_m4_v3(flow_ob->obmat, mvert[i].co);
+ smoke_pos_to_cell(sds, mvert[i].co);
+ /* vert normal */
+ normal_short_to_float_v3(n, mvert[i].no);
+ mul_mat3_m4_v3(flow_ob->obmat, n);
+ mul_mat3_m4_v3(sds->imat, n);
+ normalize_v3(n);
+ normal_float_to_short_v3(mvert[i].no, n);
+ /* vert velocity */
+ if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) {
+ float co[3];
+ add_v3fl_v3fl_v3i(co, mvert[i].co, sds->shift);
+ if (has_velocity) {
+ sub_v3_v3v3(&vert_vel[i * 3], co, &sfs->verts_old[i * 3]);
+ mul_v3_fl(&vert_vel[i * 3], sds->dx / dt);
+ }
+ copy_v3_v3(&sfs->verts_old[i * 3], co);
+ }
+
+ /* calculate emission map bounds */
+ em_boundInsert(em, mvert[i].co);
+ }
+ mul_m4_v3(flow_ob->obmat, flow_center);
+ smoke_pos_to_cell(sds, flow_center);
+
+ /* check need for high resolution map */
+ if ((sds->flags & MOD_SMOKE_HIGHRES) && (sds->highres_sampling == SM_HRES_FULLSAMPLE)) {
+ hires_multiplier = sds->amplify + 1;
+ }
+
+ /* set emission map */
+ clampBoundsInDomain(sds, em->min, em->max, NULL, NULL, (int)ceil(sfs->surface_distance), dt);
+ em_allocateData(em, sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY, hires_multiplier);
+
+ /* setup loop bounds */
+ for (i = 0; i < 3; i++) {
+ min[i] = em->min[i] * hires_multiplier;
+ max[i] = em->max[i] * hires_multiplier;
+ res[i] = em->res[i] * hires_multiplier;
+ }
+
+ if (BKE_bvhtree_from_mesh_get(&treeData, me, BVHTREE_FROM_LOOPTRI, 4)) {
+ const float hr = 1.0f / ((float)hires_multiplier);
+
+ EmitFromDMData data = {
+ .sds = sds,
+ .sfs = sfs,
+ .mvert = mvert,
+ .mloop = mloop,
+ .mlooptri = mlooptri,
+ .mloopuv = mloopuv,
+ .dvert = dvert,
+ .defgrp_index = defgrp_index,
+ .tree = &treeData,
+ .hires_multiplier = hires_multiplier,
+ .hr = hr,
+ .em = em,
+ .has_velocity = has_velocity,
+ .vert_vel = vert_vel,
+ .flow_center = flow_center,
+ .min = min,
+ .max = max,
+ .res = res,
+ };
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
+ BLI_task_parallel_range(min[2], max[2], &data, emit_from_mesh_task_cb, &settings);
+ }
+ /* free bvh tree */
+ free_bvhtree_from_mesh(&treeData);
+
+ if (vert_vel) {
+ MEM_freeN(vert_vel);
+ }
+
+ if (me->mvert) {
+ MEM_freeN(me->mvert);
+ }
+ BKE_id_free(NULL, me);
+ }
}
/**********************************************************
* Smoke step
**********************************************************/
-static void adjustDomainResolution(SmokeDomainSettings *sds, int new_shift[3], EmissionMap *emaps, unsigned int numflowobj, float dt)
+static void adjustDomainResolution(SmokeDomainSettings *sds,
+ int new_shift[3],
+ EmissionMap *emaps,
+ unsigned int numflowobj,
+ float dt)
{
- const int block_size = sds->amplify + 1;
- int min[3] = {32767, 32767, 32767}, max[3] = {-32767, -32767, -32767}, res[3];
- int total_cells = 1, res_changed = 0, shift_changed = 0;
- float min_vel[3], max_vel[3];
- int x, y, z;
- float *density = smoke_get_density(sds->fluid);
- float *fuel = smoke_get_fuel(sds->fluid);
- float *bigdensity = smoke_turbulence_get_density(sds->wt);
- float *bigfuel = smoke_turbulence_get_fuel(sds->wt);
- float *vx = smoke_get_velocity_x(sds->fluid);
- float *vy = smoke_get_velocity_y(sds->fluid);
- float *vz = smoke_get_velocity_z(sds->fluid);
- int wt_res[3];
-
- if (sds->flags & MOD_SMOKE_HIGHRES && sds->wt) {
- smoke_turbulence_get_res(sds->wt, wt_res);
- }
-
- INIT_MINMAX(min_vel, max_vel);
-
- /* Calculate bounds for current domain content */
- for (x = sds->res_min[0]; x < sds->res_max[0]; x++)
- for (y = sds->res_min[1]; y < sds->res_max[1]; y++)
- for (z = sds->res_min[2]; z < sds->res_max[2]; z++)
- {
- int xn = x - new_shift[0];
- int yn = y - new_shift[1];
- int zn = z - new_shift[2];
- int index;
- float max_den;
-
- /* skip if cell already belongs to new area */
- if (xn >= min[0] && xn <= max[0] && yn >= min[1] && yn <= max[1] && zn >= min[2] && zn <= max[2])
- continue;
-
- index = smoke_get_index(x - sds->res_min[0], sds->res[0], y - sds->res_min[1], sds->res[1], z - sds->res_min[2]);
- max_den = (fuel) ? MAX2(density[index], fuel[index]) : density[index];
-
- /* check high resolution bounds if max density isnt already high enough */
- if (max_den < sds->adapt_threshold && sds->flags & MOD_SMOKE_HIGHRES && sds->wt) {
- int i, j, k;
- /* high res grid index */
- int xx = (x - sds->res_min[0]) * block_size;
- int yy = (y - sds->res_min[1]) * block_size;
- int zz = (z - sds->res_min[2]) * block_size;
-
- for (i = 0; i < block_size; i++)
- for (j = 0; j < block_size; j++)
- for (k = 0; k < block_size; k++)
- {
- int big_index = smoke_get_index(xx + i, wt_res[0], yy + j, wt_res[1], zz + k);
- float den = (bigfuel) ? MAX2(bigdensity[big_index], bigfuel[big_index]) : bigdensity[big_index];
- if (den > max_den) {
- max_den = den;
- }
- }
- }
-
- /* content bounds (use shifted coordinates) */
- if (max_den >= sds->adapt_threshold) {
- if (min[0] > xn) min[0] = xn;
- if (min[1] > yn) min[1] = yn;
- if (min[2] > zn) min[2] = zn;
- if (max[0] < xn) max[0] = xn;
- if (max[1] < yn) max[1] = yn;
- if (max[2] < zn) max[2] = zn;
- }
-
- /* velocity bounds */
- if (min_vel[0] > vx[index]) min_vel[0] = vx[index];
- if (min_vel[1] > vy[index]) min_vel[1] = vy[index];
- if (min_vel[2] > vz[index]) min_vel[2] = vz[index];
- if (max_vel[0] < vx[index]) max_vel[0] = vx[index];
- if (max_vel[1] < vy[index]) max_vel[1] = vy[index];
- if (max_vel[2] < vz[index]) max_vel[2] = vz[index];
- }
-
- /* also apply emission maps */
- for (int i = 0; i < numflowobj; i++) {
- EmissionMap *em = &emaps[i];
-
- for (x = em->min[0]; x < em->max[0]; x++)
- for (y = em->min[1]; y < em->max[1]; y++)
- for (z = em->min[2]; z < em->max[2]; z++)
- {
- int index = smoke_get_index(x - em->min[0], em->res[0], y - em->min[1], em->res[1], z - em->min[2]);
- float max_den = em->influence[index];
-
- /* density bounds */
- if (max_den >= sds->adapt_threshold) {
- if (min[0] > x) min[0] = x;
- if (min[1] > y) min[1] = y;
- if (min[2] > z) min[2] = z;
- if (max[0] < x) max[0] = x;
- if (max[1] < y) max[1] = y;
- if (max[2] < z) max[2] = z;
- }
- }
- }
-
- /* calculate new bounds based on these values */
- mul_v3_fl(min_vel, 1.0f / sds->dx);
- mul_v3_fl(max_vel, 1.0f / sds->dx);
- clampBoundsInDomain(sds, min, max, min_vel, max_vel, sds->adapt_margin + 1, dt);
-
- for (int i = 0; i < 3; i++) {
- /* calculate new resolution */
- res[i] = max[i] - min[i];
- total_cells *= res[i];
-
- if (new_shift[i])
- shift_changed = 1;
-
- /* if no content set minimum dimensions */
- if (res[i] <= 0) {
- int j;
- for (j = 0; j < 3; j++) {
- min[j] = 0;
- max[j] = 1;
- res[j] = 1;
- }
- res_changed = 1;
- total_cells = 1;
- break;
- }
- if (min[i] != sds->res_min[i] || max[i] != sds->res_max[i])
- res_changed = 1;
- }
-
- if (res_changed || shift_changed) {
- struct FLUID_3D *fluid_old = sds->fluid;
- struct WTURBULENCE *turb_old = sds->wt;
- /* allocate new fluid data */
- BKE_smoke_reallocate_fluid(sds, sds->dx, res, 0);
- if (sds->flags & MOD_SMOKE_HIGHRES) {
- BKE_smoke_reallocate_highres_fluid(sds, sds->dx, res, 0);
- }
-
- /* copy values from old fluid to new */
- if (sds->total_cells > 1 && total_cells > 1) {
- /* low res smoke */
- float *o_dens, *o_react, *o_flame, *o_fuel, *o_heat, *o_heatold, *o_vx, *o_vy, *o_vz, *o_r, *o_g, *o_b;
- float *n_dens, *n_react, *n_flame, *n_fuel, *n_heat, *n_heatold, *n_vx, *n_vy, *n_vz, *n_r, *n_g, *n_b;
- float dummy;
- unsigned char *dummy_p;
- /* high res smoke */
- int wt_res_old[3];
- float *o_wt_dens, *o_wt_react, *o_wt_flame, *o_wt_fuel, *o_wt_tcu, *o_wt_tcv, *o_wt_tcw, *o_wt_r, *o_wt_g, *o_wt_b;
- float *n_wt_dens, *n_wt_react, *n_wt_flame, *n_wt_fuel, *n_wt_tcu, *n_wt_tcv, *n_wt_tcw, *n_wt_r, *n_wt_g, *n_wt_b;
-
- smoke_export(fluid_old, &dummy, &dummy, &o_dens, &o_react, &o_flame, &o_fuel, &o_heat, &o_heatold, &o_vx, &o_vy, &o_vz, &o_r, &o_g, &o_b, &dummy_p);
- smoke_export(sds->fluid, &dummy, &dummy, &n_dens, &n_react, &n_flame, &n_fuel, &n_heat, &n_heatold, &n_vx, &n_vy, &n_vz, &n_r, &n_g, &n_b, &dummy_p);
-
- if (sds->flags & MOD_SMOKE_HIGHRES) {
- smoke_turbulence_export(turb_old, &o_wt_dens, &o_wt_react, &o_wt_flame, &o_wt_fuel, &o_wt_r, &o_wt_g, &o_wt_b, &o_wt_tcu, &o_wt_tcv, &o_wt_tcw);
- smoke_turbulence_get_res(turb_old, wt_res_old);
- smoke_turbulence_export(sds->wt, &n_wt_dens, &n_wt_react, &n_wt_flame, &n_wt_fuel, &n_wt_r, &n_wt_g, &n_wt_b, &n_wt_tcu, &n_wt_tcv, &n_wt_tcw);
- }
-
-
- for (x = sds->res_min[0]; x < sds->res_max[0]; x++)
- for (y = sds->res_min[1]; y < sds->res_max[1]; y++)
- for (z = sds->res_min[2]; z < sds->res_max[2]; z++)
- {
- /* old grid index */
- int xo = x - sds->res_min[0];
- int yo = y - sds->res_min[1];
- int zo = z - sds->res_min[2];
- int index_old = smoke_get_index(xo, sds->res[0], yo, sds->res[1], zo);
- /* new grid index */
- int xn = x - min[0] - new_shift[0];
- int yn = y - min[1] - new_shift[1];
- int zn = z - min[2] - new_shift[2];
- int index_new = smoke_get_index(xn, res[0], yn, res[1], zn);
-
- /* skip if outside new domain */
- if (xn < 0 || xn >= res[0] ||
- yn < 0 || yn >= res[1] ||
- zn < 0 || zn >= res[2])
- continue;
-
- /* copy data */
- n_dens[index_new] = o_dens[index_old];
- /* heat */
- if (n_heat && o_heat) {
- n_heat[index_new] = o_heat[index_old];
- n_heatold[index_new] = o_heatold[index_old];
- }
- /* fuel */
- if (n_fuel && o_fuel) {
- n_flame[index_new] = o_flame[index_old];
- n_fuel[index_new] = o_fuel[index_old];
- n_react[index_new] = o_react[index_old];
- }
- /* color */
- if (o_r && n_r) {
- n_r[index_new] = o_r[index_old];
- n_g[index_new] = o_g[index_old];
- n_b[index_new] = o_b[index_old];
- }
- n_vx[index_new] = o_vx[index_old];
- n_vy[index_new] = o_vy[index_old];
- n_vz[index_new] = o_vz[index_old];
-
- if (sds->flags & MOD_SMOKE_HIGHRES && turb_old) {
- int i, j, k;
- /* old grid index */
- int xx_o = xo * block_size;
- int yy_o = yo * block_size;
- int zz_o = zo * block_size;
- /* new grid index */
- int xx_n = xn * block_size;
- int yy_n = yn * block_size;
- int zz_n = zn * block_size;
-
- n_wt_tcu[index_new] = o_wt_tcu[index_old];
- n_wt_tcv[index_new] = o_wt_tcv[index_old];
- n_wt_tcw[index_new] = o_wt_tcw[index_old];
-
- for (i = 0; i < block_size; i++)
- for (j = 0; j < block_size; j++)
- for (k = 0; k < block_size; k++)
- {
- int big_index_old = smoke_get_index(xx_o + i, wt_res_old[0], yy_o + j, wt_res_old[1], zz_o + k);
- int big_index_new = smoke_get_index(xx_n + i, sds->res_wt[0], yy_n + j, sds->res_wt[1], zz_n + k);
- /* copy data */
- n_wt_dens[big_index_new] = o_wt_dens[big_index_old];
- if (n_wt_flame && o_wt_flame) {
- n_wt_flame[big_index_new] = o_wt_flame[big_index_old];
- n_wt_fuel[big_index_new] = o_wt_fuel[big_index_old];
- n_wt_react[big_index_new] = o_wt_react[big_index_old];
- }
- if (n_wt_r && o_wt_r) {
- n_wt_r[big_index_new] = o_wt_r[big_index_old];
- n_wt_g[big_index_new] = o_wt_g[big_index_old];
- n_wt_b[big_index_new] = o_wt_b[big_index_old];
- }
- }
- }
- }
- }
- smoke_free(fluid_old);
- if (turb_old)
- smoke_turbulence_free(turb_old);
-
- /* set new domain dimensions */
- copy_v3_v3_int(sds->res_min, min);
- copy_v3_v3_int(sds->res_max, max);
- copy_v3_v3_int(sds->res, res);
- sds->total_cells = total_cells;
- }
+ const int block_size = sds->amplify + 1;
+ int min[3] = {32767, 32767, 32767}, max[3] = {-32767, -32767, -32767}, res[3];
+ int total_cells = 1, res_changed = 0, shift_changed = 0;
+ float min_vel[3], max_vel[3];
+ int x, y, z;
+ float *density = smoke_get_density(sds->fluid);
+ float *fuel = smoke_get_fuel(sds->fluid);
+ float *bigdensity = smoke_turbulence_get_density(sds->wt);
+ float *bigfuel = smoke_turbulence_get_fuel(sds->wt);
+ float *vx = smoke_get_velocity_x(sds->fluid);
+ float *vy = smoke_get_velocity_y(sds->fluid);
+ float *vz = smoke_get_velocity_z(sds->fluid);
+ int wt_res[3];
+
+ if (sds->flags & MOD_SMOKE_HIGHRES && sds->wt) {
+ smoke_turbulence_get_res(sds->wt, wt_res);
+ }
+
+ INIT_MINMAX(min_vel, max_vel);
+
+ /* Calculate bounds for current domain content */
+ for (x = sds->res_min[0]; x < sds->res_max[0]; x++)
+ for (y = sds->res_min[1]; y < sds->res_max[1]; y++)
+ for (z = sds->res_min[2]; z < sds->res_max[2]; z++) {
+ int xn = x - new_shift[0];
+ int yn = y - new_shift[1];
+ int zn = z - new_shift[2];
+ int index;
+ float max_den;
+
+ /* skip if cell already belongs to new area */
+ if (xn >= min[0] && xn <= max[0] && yn >= min[1] && yn <= max[1] && zn >= min[2] &&
+ zn <= max[2])
+ continue;
+
+ index = smoke_get_index(x - sds->res_min[0],
+ sds->res[0],
+ y - sds->res_min[1],
+ sds->res[1],
+ z - sds->res_min[2]);
+ max_den = (fuel) ? MAX2(density[index], fuel[index]) : density[index];
+
+ /* check high resolution bounds if max density isnt already high enough */
+ if (max_den < sds->adapt_threshold && sds->flags & MOD_SMOKE_HIGHRES && sds->wt) {
+ int i, j, k;
+ /* high res grid index */
+ int xx = (x - sds->res_min[0]) * block_size;
+ int yy = (y - sds->res_min[1]) * block_size;
+ int zz = (z - sds->res_min[2]) * block_size;
+
+ for (i = 0; i < block_size; i++)
+ for (j = 0; j < block_size; j++)
+ for (k = 0; k < block_size; k++) {
+ int big_index = smoke_get_index(xx + i, wt_res[0], yy + j, wt_res[1], zz + k);
+ float den = (bigfuel) ? MAX2(bigdensity[big_index], bigfuel[big_index]) :
+ bigdensity[big_index];
+ if (den > max_den) {
+ max_den = den;
+ }
+ }
+ }
+
+ /* content bounds (use shifted coordinates) */
+ if (max_den >= sds->adapt_threshold) {
+ if (min[0] > xn)
+ min[0] = xn;
+ if (min[1] > yn)
+ min[1] = yn;
+ if (min[2] > zn)
+ min[2] = zn;
+ if (max[0] < xn)
+ max[0] = xn;
+ if (max[1] < yn)
+ max[1] = yn;
+ if (max[2] < zn)
+ max[2] = zn;
+ }
+
+ /* velocity bounds */
+ if (min_vel[0] > vx[index])
+ min_vel[0] = vx[index];
+ if (min_vel[1] > vy[index])
+ min_vel[1] = vy[index];
+ if (min_vel[2] > vz[index])
+ min_vel[2] = vz[index];
+ if (max_vel[0] < vx[index])
+ max_vel[0] = vx[index];
+ if (max_vel[1] < vy[index])
+ max_vel[1] = vy[index];
+ if (max_vel[2] < vz[index])
+ max_vel[2] = vz[index];
+ }
+
+ /* also apply emission maps */
+ for (int i = 0; i < numflowobj; i++) {
+ EmissionMap *em = &emaps[i];
+
+ for (x = em->min[0]; x < em->max[0]; x++)
+ for (y = em->min[1]; y < em->max[1]; y++)
+ for (z = em->min[2]; z < em->max[2]; z++) {
+ int index = smoke_get_index(
+ x - em->min[0], em->res[0], y - em->min[1], em->res[1], z - em->min[2]);
+ float max_den = em->influence[index];
+
+ /* density bounds */
+ if (max_den >= sds->adapt_threshold) {
+ if (min[0] > x)
+ min[0] = x;
+ if (min[1] > y)
+ min[1] = y;
+ if (min[2] > z)
+ min[2] = z;
+ if (max[0] < x)
+ max[0] = x;
+ if (max[1] < y)
+ max[1] = y;
+ if (max[2] < z)
+ max[2] = z;
+ }
+ }
+ }
+
+ /* calculate new bounds based on these values */
+ mul_v3_fl(min_vel, 1.0f / sds->dx);
+ mul_v3_fl(max_vel, 1.0f / sds->dx);
+ clampBoundsInDomain(sds, min, max, min_vel, max_vel, sds->adapt_margin + 1, dt);
+
+ for (int i = 0; i < 3; i++) {
+ /* calculate new resolution */
+ res[i] = max[i] - min[i];
+ total_cells *= res[i];
+
+ if (new_shift[i])
+ shift_changed = 1;
+
+ /* if no content set minimum dimensions */
+ if (res[i] <= 0) {
+ int j;
+ for (j = 0; j < 3; j++) {
+ min[j] = 0;
+ max[j] = 1;
+ res[j] = 1;
+ }
+ res_changed = 1;
+ total_cells = 1;
+ break;
+ }
+ if (min[i] != sds->res_min[i] || max[i] != sds->res_max[i])
+ res_changed = 1;
+ }
+
+ if (res_changed || shift_changed) {
+ struct FLUID_3D *fluid_old = sds->fluid;
+ struct WTURBULENCE *turb_old = sds->wt;
+ /* allocate new fluid data */
+ BKE_smoke_reallocate_fluid(sds, sds->dx, res, 0);
+ if (sds->flags & MOD_SMOKE_HIGHRES) {
+ BKE_smoke_reallocate_highres_fluid(sds, sds->dx, res, 0);
+ }
+
+ /* copy values from old fluid to new */
+ if (sds->total_cells > 1 && total_cells > 1) {
+ /* low res smoke */
+ float *o_dens, *o_react, *o_flame, *o_fuel, *o_heat, *o_heatold, *o_vx, *o_vy, *o_vz, *o_r,
+ *o_g, *o_b;
+ float *n_dens, *n_react, *n_flame, *n_fuel, *n_heat, *n_heatold, *n_vx, *n_vy, *n_vz, *n_r,
+ *n_g, *n_b;
+ float dummy;
+ unsigned char *dummy_p;
+ /* high res smoke */
+ int wt_res_old[3];
+ float *o_wt_dens, *o_wt_react, *o_wt_flame, *o_wt_fuel, *o_wt_tcu, *o_wt_tcv, *o_wt_tcw,
+ *o_wt_r, *o_wt_g, *o_wt_b;
+ float *n_wt_dens, *n_wt_react, *n_wt_flame, *n_wt_fuel, *n_wt_tcu, *n_wt_tcv, *n_wt_tcw,
+ *n_wt_r, *n_wt_g, *n_wt_b;
+
+ smoke_export(fluid_old,
+ &dummy,
+ &dummy,
+ &o_dens,
+ &o_react,
+ &o_flame,
+ &o_fuel,
+ &o_heat,
+ &o_heatold,
+ &o_vx,
+ &o_vy,
+ &o_vz,
+ &o_r,
+ &o_g,
+ &o_b,
+ &dummy_p);
+ smoke_export(sds->fluid,
+ &dummy,
+ &dummy,
+ &n_dens,
+ &n_react,
+ &n_flame,
+ &n_fuel,
+ &n_heat,
+ &n_heatold,
+ &n_vx,
+ &n_vy,
+ &n_vz,
+ &n_r,
+ &n_g,
+ &n_b,
+ &dummy_p);
+
+ if (sds->flags & MOD_SMOKE_HIGHRES) {
+ smoke_turbulence_export(turb_old,
+ &o_wt_dens,
+ &o_wt_react,
+ &o_wt_flame,
+ &o_wt_fuel,
+ &o_wt_r,
+ &o_wt_g,
+ &o_wt_b,
+ &o_wt_tcu,
+ &o_wt_tcv,
+ &o_wt_tcw);
+ smoke_turbulence_get_res(turb_old, wt_res_old);
+ smoke_turbulence_export(sds->wt,
+ &n_wt_dens,
+ &n_wt_react,
+ &n_wt_flame,
+ &n_wt_fuel,
+ &n_wt_r,
+ &n_wt_g,
+ &n_wt_b,
+ &n_wt_tcu,
+ &n_wt_tcv,
+ &n_wt_tcw);
+ }
+
+ for (x = sds->res_min[0]; x < sds->res_max[0]; x++)
+ for (y = sds->res_min[1]; y < sds->res_max[1]; y++)
+ for (z = sds->res_min[2]; z < sds->res_max[2]; z++) {
+ /* old grid index */
+ int xo = x - sds->res_min[0];
+ int yo = y - sds->res_min[1];
+ int zo = z - sds->res_min[2];
+ int index_old = smoke_get_index(xo, sds->res[0], yo, sds->res[1], zo);
+ /* new grid index */
+ int xn = x - min[0] - new_shift[0];
+ int yn = y - min[1] - new_shift[1];
+ int zn = z - min[2] - new_shift[2];
+ int index_new = smoke_get_index(xn, res[0], yn, res[1], zn);
+
+ /* skip if outside new domain */
+ if (xn < 0 || xn >= res[0] || yn < 0 || yn >= res[1] || zn < 0 || zn >= res[2])
+ continue;
+
+ /* copy data */
+ n_dens[index_new] = o_dens[index_old];
+ /* heat */
+ if (n_heat && o_heat) {
+ n_heat[index_new] = o_heat[index_old];
+ n_heatold[index_new] = o_heatold[index_old];
+ }
+ /* fuel */
+ if (n_fuel && o_fuel) {
+ n_flame[index_new] = o_flame[index_old];
+ n_fuel[index_new] = o_fuel[index_old];
+ n_react[index_new] = o_react[index_old];
+ }
+ /* color */
+ if (o_r && n_r) {
+ n_r[index_new] = o_r[index_old];
+ n_g[index_new] = o_g[index_old];
+ n_b[index_new] = o_b[index_old];
+ }
+ n_vx[index_new] = o_vx[index_old];
+ n_vy[index_new] = o_vy[index_old];
+ n_vz[index_new] = o_vz[index_old];
+
+ if (sds->flags & MOD_SMOKE_HIGHRES && turb_old) {
+ int i, j, k;
+ /* old grid index */
+ int xx_o = xo * block_size;
+ int yy_o = yo * block_size;
+ int zz_o = zo * block_size;
+ /* new grid index */
+ int xx_n = xn * block_size;
+ int yy_n = yn * block_size;
+ int zz_n = zn * block_size;
+
+ n_wt_tcu[index_new] = o_wt_tcu[index_old];
+ n_wt_tcv[index_new] = o_wt_tcv[index_old];
+ n_wt_tcw[index_new] = o_wt_tcw[index_old];
+
+ for (i = 0; i < block_size; i++)
+ for (j = 0; j < block_size; j++)
+ for (k = 0; k < block_size; k++) {
+ int big_index_old = smoke_get_index(
+ xx_o + i, wt_res_old[0], yy_o + j, wt_res_old[1], zz_o + k);
+ int big_index_new = smoke_get_index(
+ xx_n + i, sds->res_wt[0], yy_n + j, sds->res_wt[1], zz_n + k);
+ /* copy data */
+ n_wt_dens[big_index_new] = o_wt_dens[big_index_old];
+ if (n_wt_flame && o_wt_flame) {
+ n_wt_flame[big_index_new] = o_wt_flame[big_index_old];
+ n_wt_fuel[big_index_new] = o_wt_fuel[big_index_old];
+ n_wt_react[big_index_new] = o_wt_react[big_index_old];
+ }
+ if (n_wt_r && o_wt_r) {
+ n_wt_r[big_index_new] = o_wt_r[big_index_old];
+ n_wt_g[big_index_new] = o_wt_g[big_index_old];
+ n_wt_b[big_index_new] = o_wt_b[big_index_old];
+ }
+ }
+ }
+ }
+ }
+ smoke_free(fluid_old);
+ if (turb_old)
+ smoke_turbulence_free(turb_old);
+
+ /* set new domain dimensions */
+ copy_v3_v3_int(sds->res_min, min);
+ copy_v3_v3_int(sds->res_max, max);
+ copy_v3_v3_int(sds->res, res);
+ sds->total_cells = total_cells;
+ }
}
-BLI_INLINE void apply_outflow_fields(int index, float *density, float *heat, float *fuel, float *react, float *color_r, float *color_g, float *color_b)
+BLI_INLINE void apply_outflow_fields(int index,
+ float *density,
+ float *heat,
+ float *fuel,
+ float *react,
+ float *color_r,
+ float *color_g,
+ float *color_b)
{
- density[index] = 0.f;
- if (heat) {
- heat[index] = 0.f;
- }
- if (fuel) {
- fuel[index] = 0.f;
- react[index] = 0.f;
- }
- if (color_r) {
- color_r[index] = 0.f;
- color_g[index] = 0.f;
- color_b[index] = 0.f;
- }
+ density[index] = 0.f;
+ if (heat) {
+ heat[index] = 0.f;
+ }
+ if (fuel) {
+ fuel[index] = 0.f;
+ react[index] = 0.f;
+ }
+ if (color_r) {
+ color_r[index] = 0.f;
+ color_g[index] = 0.f;
+ color_b[index] = 0.f;
+ }
}
-BLI_INLINE void apply_inflow_fields(SmokeFlowSettings *sfs, float emission_value, int index, float *density, float *heat, float *fuel, float *react, float *color_r, float *color_g, float *color_b)
+BLI_INLINE void apply_inflow_fields(SmokeFlowSettings *sfs,
+ float emission_value,
+ int index,
+ float *density,
+ float *heat,
+ float *fuel,
+ float *react,
+ float *color_r,
+ float *color_g,
+ float *color_b)
{
- int absolute_flow = (sfs->flags & MOD_SMOKE_FLOW_ABSOLUTE);
- float dens_old = density[index];
- // float fuel_old = (fuel) ? fuel[index] : 0.0f; /* UNUSED */
- float dens_flow = (sfs->type == MOD_SMOKE_FLOW_TYPE_FIRE) ? 0.0f : emission_value * sfs->density;
- float fuel_flow = emission_value * sfs->fuel_amount;
- /* add heat */
- if (heat && emission_value > 0.0f) {
- heat[index] = ADD_IF_LOWER(heat[index], sfs->temp);
- }
- /* absolute */
- if (absolute_flow) {
- if (sfs->type != MOD_SMOKE_FLOW_TYPE_FIRE) {
- if (dens_flow > density[index])
- density[index] = dens_flow;
- }
- if (sfs->type != MOD_SMOKE_FLOW_TYPE_SMOKE && fuel && fuel_flow) {
- if (fuel_flow > fuel[index])
- fuel[index] = fuel_flow;
- }
- }
- /* additive */
- else {
- if (sfs->type != MOD_SMOKE_FLOW_TYPE_FIRE) {
- density[index] += dens_flow;
- CLAMP(density[index], 0.0f, 1.0f);
- }
- if (sfs->type != MOD_SMOKE_FLOW_TYPE_SMOKE && fuel && sfs->fuel_amount) {
- fuel[index] += fuel_flow;
- CLAMP(fuel[index], 0.0f, 10.0f);
- }
- }
-
- /* set color */
- if (color_r && dens_flow) {
- float total_dens = density[index] / (dens_old + dens_flow);
- color_r[index] = (color_r[index] + sfs->color[0] * dens_flow) * total_dens;
- color_g[index] = (color_g[index] + sfs->color[1] * dens_flow) * total_dens;
- color_b[index] = (color_b[index] + sfs->color[2] * dens_flow) * total_dens;
- }
-
- /* set fire reaction coordinate */
- if (fuel && fuel[index] > FLT_EPSILON) {
- /* instead of using 1.0 for all new fuel add slight falloff
- * to reduce flow blockiness */
- float value = 1.0f - pow2f(1.0f - emission_value);
-
- if (value > react[index]) {
- float f = fuel_flow / fuel[index];
- react[index] = value * f + (1.0f - f) * react[index];
- CLAMP(react[index], 0.0f, value);
- }
- }
+ int absolute_flow = (sfs->flags & MOD_SMOKE_FLOW_ABSOLUTE);
+ float dens_old = density[index];
+ // float fuel_old = (fuel) ? fuel[index] : 0.0f; /* UNUSED */
+ float dens_flow = (sfs->type == MOD_SMOKE_FLOW_TYPE_FIRE) ? 0.0f : emission_value * sfs->density;
+ float fuel_flow = emission_value * sfs->fuel_amount;
+ /* add heat */
+ if (heat && emission_value > 0.0f) {
+ heat[index] = ADD_IF_LOWER(heat[index], sfs->temp);
+ }
+ /* absolute */
+ if (absolute_flow) {
+ if (sfs->type != MOD_SMOKE_FLOW_TYPE_FIRE) {
+ if (dens_flow > density[index])
+ density[index] = dens_flow;
+ }
+ if (sfs->type != MOD_SMOKE_FLOW_TYPE_SMOKE && fuel && fuel_flow) {
+ if (fuel_flow > fuel[index])
+ fuel[index] = fuel_flow;
+ }
+ }
+ /* additive */
+ else {
+ if (sfs->type != MOD_SMOKE_FLOW_TYPE_FIRE) {
+ density[index] += dens_flow;
+ CLAMP(density[index], 0.0f, 1.0f);
+ }
+ if (sfs->type != MOD_SMOKE_FLOW_TYPE_SMOKE && fuel && sfs->fuel_amount) {
+ fuel[index] += fuel_flow;
+ CLAMP(fuel[index], 0.0f, 10.0f);
+ }
+ }
+
+ /* set color */
+ if (color_r && dens_flow) {
+ float total_dens = density[index] / (dens_old + dens_flow);
+ color_r[index] = (color_r[index] + sfs->color[0] * dens_flow) * total_dens;
+ color_g[index] = (color_g[index] + sfs->color[1] * dens_flow) * total_dens;
+ color_b[index] = (color_b[index] + sfs->color[2] * dens_flow) * total_dens;
+ }
+
+ /* set fire reaction coordinate */
+ if (fuel && fuel[index] > FLT_EPSILON) {
+ /* instead of using 1.0 for all new fuel add slight falloff
+ * to reduce flow blockiness */
+ float value = 1.0f - pow2f(1.0f - emission_value);
+
+ if (value > react[index]) {
+ float f = fuel_flow / fuel[index];
+ react[index] = value * f + (1.0f - f) * react[index];
+ CLAMP(react[index], 0.0f, value);
+ }
+ }
}
static void update_flowsfluids(
- Depsgraph *depsgraph, Scene *scene, Object *ob, SmokeDomainSettings *sds, float dt)
+ Depsgraph *depsgraph, Scene *scene, Object *ob, SmokeDomainSettings *sds, float dt)
{
- Object **flowobjs = NULL;
- EmissionMap *emaps = NULL;
- unsigned int numflowobj = 0;
- unsigned int flowIndex;
- int new_shift[3] = {0};
- int active_fields = sds->active_fields;
-
- /* calculate domain shift for current frame if using adaptive domain */
- if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
- int total_shift[3];
- float frame_shift_f[3];
- float ob_loc[3] = {0};
-
- mul_m4_v3(ob->obmat, ob_loc);
-
- sub_v3_v3v3(frame_shift_f, ob_loc, sds->prev_loc);
- copy_v3_v3(sds->prev_loc, ob_loc);
- /* convert global space shift to local "cell" space */
- mul_mat3_m4_v3(sds->imat, frame_shift_f);
- frame_shift_f[0] = frame_shift_f[0] / sds->cell_size[0];
- frame_shift_f[1] = frame_shift_f[1] / sds->cell_size[1];
- frame_shift_f[2] = frame_shift_f[2] / sds->cell_size[2];
- /* add to total shift */
- add_v3_v3(sds->shift_f, frame_shift_f);
- /* convert to integer */
- total_shift[0] = (int)(floorf(sds->shift_f[0]));
- total_shift[1] = (int)(floorf(sds->shift_f[1]));
- total_shift[2] = (int)(floorf(sds->shift_f[2]));
- sub_v3_v3v3_int(new_shift, total_shift, sds->shift);
- copy_v3_v3_int(sds->shift, total_shift);
-
- /* calculate new domain boundary points so that smoke doesn't slide on sub-cell movement */
- sds->p0[0] = sds->dp0[0] - sds->cell_size[0] * (sds->shift_f[0] - total_shift[0] - 0.5f);
- sds->p0[1] = sds->dp0[1] - sds->cell_size[1] * (sds->shift_f[1] - total_shift[1] - 0.5f);
- sds->p0[2] = sds->dp0[2] - sds->cell_size[2] * (sds->shift_f[2] - total_shift[2] - 0.5f);
- sds->p1[0] = sds->p0[0] + sds->cell_size[0] * sds->base_res[0];
- sds->p1[1] = sds->p0[1] + sds->cell_size[1] * sds->base_res[1];
- sds->p1[2] = sds->p0[2] + sds->cell_size[2] * sds->base_res[2];
- }
-
- flowobjs = BKE_collision_objects_create(depsgraph, ob, sds->fluid_group, &numflowobj, eModifierType_Smoke);
-
- /* init emission maps for each flow */
- emaps = MEM_callocN(sizeof(struct EmissionMap) * numflowobj, "smoke_flow_maps");
-
- /* Prepare flow emission maps */
- for (flowIndex = 0; flowIndex < numflowobj; flowIndex++)
- {
- Object *collob = flowobjs[flowIndex];
- SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(collob, eModifierType_Smoke);
-
- // check for initialized smoke object
- if ((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow)
- {
- // we got nice flow object
- SmokeFlowSettings *sfs = smd2->flow;
- int subframes = sfs->subframes;
- EmissionMap *em = &emaps[flowIndex];
-
- /* just sample flow directly to emission map if no subframes */
- if (!subframes) {
- if (sfs->source == MOD_SMOKE_FLOW_SOURCE_PARTICLES) {
- emit_from_particles(collob, sds, sfs, em, depsgraph, scene, dt);
- }
- else {
- emit_from_mesh(collob, sds, sfs, em, dt);
- }
- }
- /* sample subframes */
- else {
-#if 0
- int scene_frame = (int)DEG_get_ctime(depsgraph);
-#endif
- // float scene_subframe = scene->r.subframe; // UNUSED
- int subframe;
- for (subframe = 0; subframe <= subframes; subframe++) {
- EmissionMap em_temp = {NULL};
- float sample_size = 1.0f / (float)(subframes+1);
-#if 0
- float prev_frame_pos = sample_size * (float)(subframe+1);
-#endif
- float sdt = dt * sample_size;
- int hires_multiplier = 1;
-
- if ((sds->flags & MOD_SMOKE_HIGHRES) && (sds->highres_sampling == SM_HRES_FULLSAMPLE)) {
- hires_multiplier = sds->amplify + 1;
- }
-
- /* TODO: setting the scene frame no longer works with the new depsgraph. */
-#if 0
- /* set scene frame to match previous frame + subframe
- * or use current frame for last sample */
- if (subframe < subframes) {
- scene->r.cfra = scene_frame - 1;
- scene->r.subframe = prev_frame_pos;
- }
- else {
- scene->r.cfra = scene_frame;
- scene->r.subframe = 0.0f;
- }
-#endif
-
- if (sfs->source == MOD_SMOKE_FLOW_SOURCE_PARTICLES) {
- /* emit_from_particles() updates timestep internally */
- emit_from_particles(collob, sds, sfs, &em_temp, depsgraph, scene, sdt);
- if (!(sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE)) {
- hires_multiplier = 1;
- }
- }
- else { /* MOD_SMOKE_FLOW_SOURCE_MESH */
- /* update flow object frame */
- BLI_mutex_lock(&object_update_lock);
- BKE_object_modifier_update_subframe(depsgraph, scene, collob, true, 5, DEG_get_ctime(depsgraph), eModifierType_Smoke);
- BLI_mutex_unlock(&object_update_lock);
-
- /* apply flow */
- emit_from_mesh(collob, sds, sfs, &em_temp, sdt);
- }
-
- /* combine emission maps */
- em_combineMaps(em, &em_temp, hires_multiplier, !(sfs->flags & MOD_SMOKE_FLOW_ABSOLUTE), sample_size);
- em_freeData(&em_temp);
- }
- }
-
- /* update required data fields */
- if (em->total_cells && sfs->type != MOD_SMOKE_FLOW_TYPE_OUTFLOW) {
- /* activate heat field if flow produces any heat */
- if (sfs->temp) {
- active_fields |= SM_ACTIVE_HEAT;
- }
- /* activate fuel field if flow adds any fuel */
- if (sfs->type != MOD_SMOKE_FLOW_TYPE_SMOKE && sfs->fuel_amount) {
- active_fields |= SM_ACTIVE_FIRE;
- }
- /* activate color field if flows add smoke with varying colors */
- if (sfs->type != MOD_SMOKE_FLOW_TYPE_FIRE && sfs->density) {
- if (!(active_fields & SM_ACTIVE_COLOR_SET)) {
- copy_v3_v3(sds->active_color, sfs->color);
- active_fields |= SM_ACTIVE_COLOR_SET;
- }
- else if (!equals_v3v3(sds->active_color, sfs->color)) {
- copy_v3_v3(sds->active_color, sfs->color);
- active_fields |= SM_ACTIVE_COLORS;
- }
- }
- }
- }
- }
-
- /* monitor active fields based on domain settings */
- /* if domain has fire, activate new fields if required */
- if (active_fields & SM_ACTIVE_FIRE) {
- /* heat is always needed for fire */
- active_fields |= SM_ACTIVE_HEAT;
- /* also activate colors if domain smoke color differs from active color */
- if (!(active_fields & SM_ACTIVE_COLOR_SET)) {
- copy_v3_v3(sds->active_color, sds->flame_smoke_color);
- active_fields |= SM_ACTIVE_COLOR_SET;
- }
- else if (!equals_v3v3(sds->active_color, sds->flame_smoke_color)) {
- copy_v3_v3(sds->active_color, sds->flame_smoke_color);
- active_fields |= SM_ACTIVE_COLORS;
- }
- }
-
- /* Adjust domain size if needed */
- if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
- adjustDomainResolution(sds, new_shift, emaps, numflowobj, dt);
- }
-
- /* Initialize new data fields if any */
- if (active_fields & SM_ACTIVE_HEAT) {
- smoke_ensure_heat(sds->fluid);
- }
- if (active_fields & SM_ACTIVE_FIRE) {
- smoke_ensure_fire(sds->fluid, sds->wt);
- }
- if (active_fields & SM_ACTIVE_COLORS) {
- /* initialize all smoke with "active_color" */
- smoke_ensure_colors(sds->fluid, sds->wt, sds->active_color[0], sds->active_color[1], sds->active_color[2]);
- }
- sds->active_fields = active_fields;
-
- /* Apply emission data */
- if (sds->fluid) {
- for (flowIndex = 0; flowIndex < numflowobj; flowIndex++)
- {
- Object *collob = flowobjs[flowIndex];
- SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(collob, eModifierType_Smoke);
-
- // check for initialized smoke object
- if ((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow)
- {
- // we got nice flow object
- SmokeFlowSettings *sfs = smd2->flow;
- EmissionMap *em = &emaps[flowIndex];
-
- float *density = smoke_get_density(sds->fluid);
- float *color_r = smoke_get_color_r(sds->fluid);
- float *color_g = smoke_get_color_g(sds->fluid);
- float *color_b = smoke_get_color_b(sds->fluid);
- float *fuel = smoke_get_fuel(sds->fluid);
- float *react = smoke_get_react(sds->fluid);
- float *bigdensity = smoke_turbulence_get_density(sds->wt);
- float *bigfuel = smoke_turbulence_get_fuel(sds->wt);
- float *bigreact = smoke_turbulence_get_react(sds->wt);
- float *bigcolor_r = smoke_turbulence_get_color_r(sds->wt);
- float *bigcolor_g = smoke_turbulence_get_color_g(sds->wt);
- float *bigcolor_b = smoke_turbulence_get_color_b(sds->wt);
- float *heat = smoke_get_heat(sds->fluid);
- float *velocity_x = smoke_get_velocity_x(sds->fluid);
- float *velocity_y = smoke_get_velocity_y(sds->fluid);
- float *velocity_z = smoke_get_velocity_z(sds->fluid);
- //unsigned char *obstacle = smoke_get_obstacle(sds->fluid);
- // DG TODO UNUSED unsigned char *obstacleAnim = smoke_get_obstacle_anim(sds->fluid);
- int bigres[3];
- float *velocity_map = em->velocity;
- float *emission_map = em->influence;
- float *emission_map_high = em->influence_high;
-
- int ii, jj, kk, gx, gy, gz, ex, ey, ez, dx, dy, dz, block_size;
- size_t e_index, d_index, index_big;
-
- // loop through every emission map cell
- for (gx = em->min[0]; gx < em->max[0]; gx++)
- for (gy = em->min[1]; gy < em->max[1]; gy++)
- for (gz = em->min[2]; gz < em->max[2]; gz++)
- {
- /* get emission map index */
- ex = gx - em->min[0];
- ey = gy - em->min[1];
- ez = gz - em->min[2];
- e_index = smoke_get_index(ex, em->res[0], ey, em->res[1], ez);
-
- /* get domain index */
- dx = gx - sds->res_min[0];
- dy = gy - sds->res_min[1];
- dz = gz - sds->res_min[2];
- d_index = smoke_get_index(dx, sds->res[0], dy, sds->res[1], dz);
- /* make sure emission cell is inside the new domain boundary */
- if (dx < 0 || dy < 0 || dz < 0 || dx >= sds->res[0] || dy >= sds->res[1] || dz >= sds->res[2]) continue;
-
- if (sfs->type == MOD_SMOKE_FLOW_TYPE_OUTFLOW) { // outflow
- apply_outflow_fields(d_index, density, heat, fuel, react, color_r, color_g, color_b);
- }
- else { // inflow
- apply_inflow_fields(sfs, emission_map[e_index], d_index, density, heat, fuel, react, color_r, color_g, color_b);
-
- /* initial velocity */
- if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) {
- velocity_x[d_index] = ADD_IF_LOWER(velocity_x[d_index], velocity_map[e_index * 3]);
- velocity_y[d_index] = ADD_IF_LOWER(velocity_y[d_index], velocity_map[e_index * 3 + 1]);
- velocity_z[d_index] = ADD_IF_LOWER(velocity_z[d_index], velocity_map[e_index * 3 + 2]);
- }
- }
-
- /* loop through high res blocks if high res enabled */
- if (bigdensity) {
- // neighbor cell emission densities (for high resolution smoke smooth interpolation)
- float c000, c001, c010, c011, c100, c101, c110, c111;
-
- smoke_turbulence_get_res(sds->wt, bigres);
- block_size = sds->amplify + 1; // high res block size
-
- c000 = (ex > 0 && ey > 0 && ez > 0) ? emission_map[smoke_get_index(ex - 1, em->res[0], ey - 1, em->res[1], ez - 1)] : 0;
- c001 = (ex > 0 && ey > 0) ? emission_map[smoke_get_index(ex - 1, em->res[0], ey - 1, em->res[1], ez)] : 0;
- c010 = (ex > 0 && ez > 0) ? emission_map[smoke_get_index(ex - 1, em->res[0], ey, em->res[1], ez - 1)] : 0;
- c011 = (ex > 0) ? emission_map[smoke_get_index(ex - 1, em->res[0], ey, em->res[1], ez)] : 0;
-
- c100 = (ey > 0 && ez > 0) ? emission_map[smoke_get_index(ex, em->res[0], ey - 1, em->res[1], ez - 1)] : 0;
- c101 = (ey > 0) ? emission_map[smoke_get_index(ex, em->res[0], ey - 1, em->res[1], ez)] : 0;
- c110 = (ez > 0) ? emission_map[smoke_get_index(ex, em->res[0], ey, em->res[1], ez - 1)] : 0;
- c111 = emission_map[smoke_get_index(ex, em->res[0], ey, em->res[1], ez)]; // this cell
-
- for (ii = 0; ii < block_size; ii++)
- for (jj = 0; jj < block_size; jj++)
- for (kk = 0; kk < block_size; kk++)
- {
-
- float fx, fy, fz, interpolated_value;
- int shift_x = 0, shift_y = 0, shift_z = 0;
-
-
- /* Use full sample emission map if enabled and available */
- if ((sds->highres_sampling == SM_HRES_FULLSAMPLE) && emission_map_high) {
- interpolated_value = emission_map_high[smoke_get_index(ex * block_size + ii, em->res[0] * block_size, ey * block_size + jj, em->res[1] * block_size, ez * block_size + kk)]; // this cell
- }
- else if (sds->highres_sampling == SM_HRES_NEAREST) {
- /* without interpolation use same low resolution
- * block value for all hi-res blocks */
- interpolated_value = c111;
- }
- /* Fall back to interpolated */
- else
- {
- /* get relative block position
- * for interpolation smoothing */
- fx = (float)ii / block_size + 0.5f / block_size;
- fy = (float)jj / block_size + 0.5f / block_size;
- fz = (float)kk / block_size + 0.5f / block_size;
-
- /* calculate trilinear interpolation */
- interpolated_value = c000 * (1 - fx) * (1 - fy) * (1 - fz) +
- c100 * fx * (1 - fy) * (1 - fz) +
- c010 * (1 - fx) * fy * (1 - fz) +
- c001 * (1 - fx) * (1 - fy) * fz +
- c101 * fx * (1 - fy) * fz +
- c011 * (1 - fx) * fy * fz +
- c110 * fx * fy * (1 - fz) +
- c111 * fx * fy * fz;
-
-
- /* add some contrast / sharpness
- * depending on hi-res block size */
- interpolated_value = (interpolated_value - 0.4f) * (block_size / 2) + 0.4f;
- CLAMP(interpolated_value, 0.0f, 1.0f);
-
- /* shift smoke block index
- * (because pixel center is actually
- * in halfway of the low res block) */
- shift_x = (dx < 1) ? 0 : block_size / 2;
- shift_y = (dy < 1) ? 0 : block_size / 2;
- shift_z = (dz < 1) ? 0 : block_size / 2;
- }
-
- /* get shifted index for current high resolution block */
- index_big = smoke_get_index(block_size * dx + ii - shift_x, bigres[0], block_size * dy + jj - shift_y, bigres[1], block_size * dz + kk - shift_z);
-
- if (sfs->type == MOD_SMOKE_FLOW_TYPE_OUTFLOW) { // outflow
- if (interpolated_value) {
- apply_outflow_fields(index_big, bigdensity, NULL, bigfuel, bigreact, bigcolor_r, bigcolor_g, bigcolor_b);
- }
- }
- else { // inflow
- apply_inflow_fields(sfs, interpolated_value, index_big, bigdensity, NULL, bigfuel, bigreact, bigcolor_r, bigcolor_g, bigcolor_b);
- }
- } // hires loop
- } // bigdensity
- } // low res loop
-
- // free emission maps
- em_freeData(em);
-
- } // end emission
- }
- }
-
- BKE_collision_objects_free(flowobjs);
- if (emaps)
- MEM_freeN(emaps);
+ Object **flowobjs = NULL;
+ EmissionMap *emaps = NULL;
+ unsigned int numflowobj = 0;
+ unsigned int flowIndex;
+ int new_shift[3] = {0};
+ int active_fields = sds->active_fields;
+
+ /* calculate domain shift for current frame if using adaptive domain */
+ if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
+ int total_shift[3];
+ float frame_shift_f[3];
+ float ob_loc[3] = {0};
+
+ mul_m4_v3(ob->obmat, ob_loc);
+
+ sub_v3_v3v3(frame_shift_f, ob_loc, sds->prev_loc);
+ copy_v3_v3(sds->prev_loc, ob_loc);
+ /* convert global space shift to local "cell" space */
+ mul_mat3_m4_v3(sds->imat, frame_shift_f);
+ frame_shift_f[0] = frame_shift_f[0] / sds->cell_size[0];
+ frame_shift_f[1] = frame_shift_f[1] / sds->cell_size[1];
+ frame_shift_f[2] = frame_shift_f[2] / sds->cell_size[2];
+ /* add to total shift */
+ add_v3_v3(sds->shift_f, frame_shift_f);
+ /* convert to integer */
+ total_shift[0] = (int)(floorf(sds->shift_f[0]));
+ total_shift[1] = (int)(floorf(sds->shift_f[1]));
+ total_shift[2] = (int)(floorf(sds->shift_f[2]));
+ sub_v3_v3v3_int(new_shift, total_shift, sds->shift);
+ copy_v3_v3_int(sds->shift, total_shift);
+
+ /* calculate new domain boundary points so that smoke doesn't slide on sub-cell movement */
+ sds->p0[0] = sds->dp0[0] - sds->cell_size[0] * (sds->shift_f[0] - total_shift[0] - 0.5f);
+ sds->p0[1] = sds->dp0[1] - sds->cell_size[1] * (sds->shift_f[1] - total_shift[1] - 0.5f);
+ sds->p0[2] = sds->dp0[2] - sds->cell_size[2] * (sds->shift_f[2] - total_shift[2] - 0.5f);
+ sds->p1[0] = sds->p0[0] + sds->cell_size[0] * sds->base_res[0];
+ sds->p1[1] = sds->p0[1] + sds->cell_size[1] * sds->base_res[1];
+ sds->p1[2] = sds->p0[2] + sds->cell_size[2] * sds->base_res[2];
+ }
+
+ flowobjs = BKE_collision_objects_create(
+ depsgraph, ob, sds->fluid_group, &numflowobj, eModifierType_Smoke);
+
+ /* init emission maps for each flow */
+ emaps = MEM_callocN(sizeof(struct EmissionMap) * numflowobj, "smoke_flow_maps");
+
+ /* Prepare flow emission maps */
+ for (flowIndex = 0; flowIndex < numflowobj; flowIndex++) {
+ Object *collob = flowobjs[flowIndex];
+ SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(collob,
+ eModifierType_Smoke);
+
+ // check for initialized smoke object
+ if ((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) {
+ // we got nice flow object
+ SmokeFlowSettings *sfs = smd2->flow;
+ int subframes = sfs->subframes;
+ EmissionMap *em = &emaps[flowIndex];
+
+ /* just sample flow directly to emission map if no subframes */
+ if (!subframes) {
+ if (sfs->source == MOD_SMOKE_FLOW_SOURCE_PARTICLES) {
+ emit_from_particles(collob, sds, sfs, em, depsgraph, scene, dt);
+ }
+ else {
+ emit_from_mesh(collob, sds, sfs, em, dt);
+ }
+ }
+ /* sample subframes */
+ else {
+# if 0
+ int scene_frame = (int)DEG_get_ctime(depsgraph);
+# endif
+ // float scene_subframe = scene->r.subframe; // UNUSED
+ int subframe;
+ for (subframe = 0; subframe <= subframes; subframe++) {
+ EmissionMap em_temp = {NULL};
+ float sample_size = 1.0f / (float)(subframes + 1);
+# if 0
+ float prev_frame_pos = sample_size * (float)(subframe+1);
+# endif
+ float sdt = dt * sample_size;
+ int hires_multiplier = 1;
+
+ if ((sds->flags & MOD_SMOKE_HIGHRES) && (sds->highres_sampling == SM_HRES_FULLSAMPLE)) {
+ hires_multiplier = sds->amplify + 1;
+ }
+
+ /* TODO: setting the scene frame no longer works with the new depsgraph. */
+# if 0
+ /* set scene frame to match previous frame + subframe
+ * or use current frame for last sample */
+ if (subframe < subframes) {
+ scene->r.cfra = scene_frame - 1;
+ scene->r.subframe = prev_frame_pos;
+ }
+ else {
+ scene->r.cfra = scene_frame;
+ scene->r.subframe = 0.0f;
+ }
+# endif
+
+ if (sfs->source == MOD_SMOKE_FLOW_SOURCE_PARTICLES) {
+ /* emit_from_particles() updates timestep internally */
+ emit_from_particles(collob, sds, sfs, &em_temp, depsgraph, scene, sdt);
+ if (!(sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE)) {
+ hires_multiplier = 1;
+ }
+ }
+ else { /* MOD_SMOKE_FLOW_SOURCE_MESH */
+ /* update flow object frame */
+ BLI_mutex_lock(&object_update_lock);
+ BKE_object_modifier_update_subframe(
+ depsgraph, scene, collob, true, 5, DEG_get_ctime(depsgraph), eModifierType_Smoke);
+ BLI_mutex_unlock(&object_update_lock);
+
+ /* apply flow */
+ emit_from_mesh(collob, sds, sfs, &em_temp, sdt);
+ }
+
+ /* combine emission maps */
+ em_combineMaps(em,
+ &em_temp,
+ hires_multiplier,
+ !(sfs->flags & MOD_SMOKE_FLOW_ABSOLUTE),
+ sample_size);
+ em_freeData(&em_temp);
+ }
+ }
+
+ /* update required data fields */
+ if (em->total_cells && sfs->type != MOD_SMOKE_FLOW_TYPE_OUTFLOW) {
+ /* activate heat field if flow produces any heat */
+ if (sfs->temp) {
+ active_fields |= SM_ACTIVE_HEAT;
+ }
+ /* activate fuel field if flow adds any fuel */
+ if (sfs->type != MOD_SMOKE_FLOW_TYPE_SMOKE && sfs->fuel_amount) {
+ active_fields |= SM_ACTIVE_FIRE;
+ }
+ /* activate color field if flows add smoke with varying colors */
+ if (sfs->type != MOD_SMOKE_FLOW_TYPE_FIRE && sfs->density) {
+ if (!(active_fields & SM_ACTIVE_COLOR_SET)) {
+ copy_v3_v3(sds->active_color, sfs->color);
+ active_fields |= SM_ACTIVE_COLOR_SET;
+ }
+ else if (!equals_v3v3(sds->active_color, sfs->color)) {
+ copy_v3_v3(sds->active_color, sfs->color);
+ active_fields |= SM_ACTIVE_COLORS;
+ }
+ }
+ }
+ }
+ }
+
+ /* monitor active fields based on domain settings */
+ /* if domain has fire, activate new fields if required */
+ if (active_fields & SM_ACTIVE_FIRE) {
+ /* heat is always needed for fire */
+ active_fields |= SM_ACTIVE_HEAT;
+ /* also activate colors if domain smoke color differs from active color */
+ if (!(active_fields & SM_ACTIVE_COLOR_SET)) {
+ copy_v3_v3(sds->active_color, sds->flame_smoke_color);
+ active_fields |= SM_ACTIVE_COLOR_SET;
+ }
+ else if (!equals_v3v3(sds->active_color, sds->flame_smoke_color)) {
+ copy_v3_v3(sds->active_color, sds->flame_smoke_color);
+ active_fields |= SM_ACTIVE_COLORS;
+ }
+ }
+
+ /* Adjust domain size if needed */
+ if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
+ adjustDomainResolution(sds, new_shift, emaps, numflowobj, dt);
+ }
+
+ /* Initialize new data fields if any */
+ if (active_fields & SM_ACTIVE_HEAT) {
+ smoke_ensure_heat(sds->fluid);
+ }
+ if (active_fields & SM_ACTIVE_FIRE) {
+ smoke_ensure_fire(sds->fluid, sds->wt);
+ }
+ if (active_fields & SM_ACTIVE_COLORS) {
+ /* initialize all smoke with "active_color" */
+ smoke_ensure_colors(
+ sds->fluid, sds->wt, sds->active_color[0], sds->active_color[1], sds->active_color[2]);
+ }
+ sds->active_fields = active_fields;
+
+ /* Apply emission data */
+ if (sds->fluid) {
+ for (flowIndex = 0; flowIndex < numflowobj; flowIndex++) {
+ Object *collob = flowobjs[flowIndex];
+ SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(collob,
+ eModifierType_Smoke);
+
+ // check for initialized smoke object
+ if ((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) {
+ // we got nice flow object
+ SmokeFlowSettings *sfs = smd2->flow;
+ EmissionMap *em = &emaps[flowIndex];
+
+ float *density = smoke_get_density(sds->fluid);
+ float *color_r = smoke_get_color_r(sds->fluid);
+ float *color_g = smoke_get_color_g(sds->fluid);
+ float *color_b = smoke_get_color_b(sds->fluid);
+ float *fuel = smoke_get_fuel(sds->fluid);
+ float *react = smoke_get_react(sds->fluid);
+ float *bigdensity = smoke_turbulence_get_density(sds->wt);
+ float *bigfuel = smoke_turbulence_get_fuel(sds->wt);
+ float *bigreact = smoke_turbulence_get_react(sds->wt);
+ float *bigcolor_r = smoke_turbulence_get_color_r(sds->wt);
+ float *bigcolor_g = smoke_turbulence_get_color_g(sds->wt);
+ float *bigcolor_b = smoke_turbulence_get_color_b(sds->wt);
+ float *heat = smoke_get_heat(sds->fluid);
+ float *velocity_x = smoke_get_velocity_x(sds->fluid);
+ float *velocity_y = smoke_get_velocity_y(sds->fluid);
+ float *velocity_z = smoke_get_velocity_z(sds->fluid);
+ //unsigned char *obstacle = smoke_get_obstacle(sds->fluid);
+ // DG TODO UNUSED unsigned char *obstacleAnim = smoke_get_obstacle_anim(sds->fluid);
+ int bigres[3];
+ float *velocity_map = em->velocity;
+ float *emission_map = em->influence;
+ float *emission_map_high = em->influence_high;
+
+ int ii, jj, kk, gx, gy, gz, ex, ey, ez, dx, dy, dz, block_size;
+ size_t e_index, d_index, index_big;
+
+ // loop through every emission map cell
+ for (gx = em->min[0]; gx < em->max[0]; gx++)
+ for (gy = em->min[1]; gy < em->max[1]; gy++)
+ for (gz = em->min[2]; gz < em->max[2]; gz++) {
+ /* get emission map index */
+ ex = gx - em->min[0];
+ ey = gy - em->min[1];
+ ez = gz - em->min[2];
+ e_index = smoke_get_index(ex, em->res[0], ey, em->res[1], ez);
+
+ /* get domain index */
+ dx = gx - sds->res_min[0];
+ dy = gy - sds->res_min[1];
+ dz = gz - sds->res_min[2];
+ d_index = smoke_get_index(dx, sds->res[0], dy, sds->res[1], dz);
+ /* make sure emission cell is inside the new domain boundary */
+ if (dx < 0 || dy < 0 || dz < 0 || dx >= sds->res[0] || dy >= sds->res[1] ||
+ dz >= sds->res[2])
+ continue;
+
+ if (sfs->type == MOD_SMOKE_FLOW_TYPE_OUTFLOW) { // outflow
+ apply_outflow_fields(
+ d_index, density, heat, fuel, react, color_r, color_g, color_b);
+ }
+ else { // inflow
+ apply_inflow_fields(sfs,
+ emission_map[e_index],
+ d_index,
+ density,
+ heat,
+ fuel,
+ react,
+ color_r,
+ color_g,
+ color_b);
+
+ /* initial velocity */
+ if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) {
+ velocity_x[d_index] = ADD_IF_LOWER(velocity_x[d_index],
+ velocity_map[e_index * 3]);
+ velocity_y[d_index] = ADD_IF_LOWER(velocity_y[d_index],
+ velocity_map[e_index * 3 + 1]);
+ velocity_z[d_index] = ADD_IF_LOWER(velocity_z[d_index],
+ velocity_map[e_index * 3 + 2]);
+ }
+ }
+
+ /* loop through high res blocks if high res enabled */
+ if (bigdensity) {
+ // neighbor cell emission densities (for high resolution smoke smooth interpolation)
+ float c000, c001, c010, c011, c100, c101, c110, c111;
+
+ smoke_turbulence_get_res(sds->wt, bigres);
+ block_size = sds->amplify + 1; // high res block size
+
+ c000 = (ex > 0 && ey > 0 && ez > 0) ?
+ emission_map[smoke_get_index(
+ ex - 1, em->res[0], ey - 1, em->res[1], ez - 1)] :
+ 0;
+ c001 =
+ (ex > 0 && ey > 0) ?
+ emission_map[smoke_get_index(ex - 1, em->res[0], ey - 1, em->res[1], ez)] :
+ 0;
+ c010 =
+ (ex > 0 && ez > 0) ?
+ emission_map[smoke_get_index(ex - 1, em->res[0], ey, em->res[1], ez - 1)] :
+ 0;
+ c011 = (ex > 0) ?
+ emission_map[smoke_get_index(ex - 1, em->res[0], ey, em->res[1], ez)] :
+ 0;
+
+ c100 =
+ (ey > 0 && ez > 0) ?
+ emission_map[smoke_get_index(ex, em->res[0], ey - 1, em->res[1], ez - 1)] :
+ 0;
+ c101 = (ey > 0) ?
+ emission_map[smoke_get_index(ex, em->res[0], ey - 1, em->res[1], ez)] :
+ 0;
+ c110 = (ez > 0) ?
+ emission_map[smoke_get_index(ex, em->res[0], ey, em->res[1], ez - 1)] :
+ 0;
+ c111 = emission_map[smoke_get_index(
+ ex, em->res[0], ey, em->res[1], ez)]; // this cell
+
+ for (ii = 0; ii < block_size; ii++)
+ for (jj = 0; jj < block_size; jj++)
+ for (kk = 0; kk < block_size; kk++) {
+
+ float fx, fy, fz, interpolated_value;
+ int shift_x = 0, shift_y = 0, shift_z = 0;
+
+ /* Use full sample emission map if enabled and available */
+ if ((sds->highres_sampling == SM_HRES_FULLSAMPLE) && emission_map_high) {
+ interpolated_value =
+ emission_map_high[smoke_get_index(ex * block_size + ii,
+ em->res[0] * block_size,
+ ey * block_size + jj,
+ em->res[1] * block_size,
+ ez * block_size + kk)]; // this cell
+ }
+ else if (sds->highres_sampling == SM_HRES_NEAREST) {
+ /* without interpolation use same low resolution
+ * block value for all hi-res blocks */
+ interpolated_value = c111;
+ }
+ /* Fall back to interpolated */
+ else {
+ /* get relative block position
+ * for interpolation smoothing */
+ fx = (float)ii / block_size + 0.5f / block_size;
+ fy = (float)jj / block_size + 0.5f / block_size;
+ fz = (float)kk / block_size + 0.5f / block_size;
+
+ /* calculate trilinear interpolation */
+ interpolated_value = c000 * (1 - fx) * (1 - fy) * (1 - fz) +
+ c100 * fx * (1 - fy) * (1 - fz) +
+ c010 * (1 - fx) * fy * (1 - fz) +
+ c001 * (1 - fx) * (1 - fy) * fz +
+ c101 * fx * (1 - fy) * fz +
+ c011 * (1 - fx) * fy * fz +
+ c110 * fx * fy * (1 - fz) + c111 * fx * fy * fz;
+
+ /* add some contrast / sharpness
+ * depending on hi-res block size */
+ interpolated_value = (interpolated_value - 0.4f) * (block_size / 2) + 0.4f;
+ CLAMP(interpolated_value, 0.0f, 1.0f);
+
+ /* shift smoke block index
+ * (because pixel center is actually
+ * in halfway of the low res block) */
+ shift_x = (dx < 1) ? 0 : block_size / 2;
+ shift_y = (dy < 1) ? 0 : block_size / 2;
+ shift_z = (dz < 1) ? 0 : block_size / 2;
+ }
+
+ /* get shifted index for current high resolution block */
+ index_big = smoke_get_index(block_size * dx + ii - shift_x,
+ bigres[0],
+ block_size * dy + jj - shift_y,
+ bigres[1],
+ block_size * dz + kk - shift_z);
+
+ if (sfs->type == MOD_SMOKE_FLOW_TYPE_OUTFLOW) { // outflow
+ if (interpolated_value) {
+ apply_outflow_fields(index_big,
+ bigdensity,
+ NULL,
+ bigfuel,
+ bigreact,
+ bigcolor_r,
+ bigcolor_g,
+ bigcolor_b);
+ }
+ }
+ else { // inflow
+ apply_inflow_fields(sfs,
+ interpolated_value,
+ index_big,
+ bigdensity,
+ NULL,
+ bigfuel,
+ bigreact,
+ bigcolor_r,
+ bigcolor_g,
+ bigcolor_b);
+ }
+ } // hires loop
+ } // bigdensity
+ } // low res loop
+
+ // free emission maps
+ em_freeData(em);
+
+ } // end emission
+ }
+ }
+
+ BKE_collision_objects_free(flowobjs);
+ if (emaps)
+ MEM_freeN(emaps);
}
typedef struct UpdateEffectorsData {
- Scene *scene;
- SmokeDomainSettings *sds;
- ListBase *effectors;
-
- float *density;
- float *fuel;
- float *force_x;
- float *force_y;
- float *force_z;
- float *velocity_x;
- float *velocity_y;
- float *velocity_z;
- unsigned char *obstacle;
+ Scene *scene;
+ SmokeDomainSettings *sds;
+ ListBase *effectors;
+
+ float *density;
+ float *fuel;
+ float *force_x;
+ float *force_y;
+ float *force_z;
+ float *velocity_x;
+ float *velocity_y;
+ float *velocity_z;
+ unsigned char *obstacle;
} UpdateEffectorsData;
-static void update_effectors_task_cb(
- void *__restrict userdata,
- const int x,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void update_effectors_task_cb(void *__restrict userdata,
+ const int x,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- UpdateEffectorsData *data = userdata;
- SmokeDomainSettings *sds = data->sds;
-
- for (int y = 0; y < sds->res[1]; y++) {
- for (int z = 0; z < sds->res[2]; z++)
- {
- EffectedPoint epoint;
- float mag;
- float voxelCenter[3] = {0, 0, 0}, vel[3] = {0, 0, 0}, retvel[3] = {0, 0, 0};
- const unsigned int index = smoke_get_index(x, sds->res[0], y, sds->res[1], z);
-
- if (((data->fuel ? MAX2(data->density[index], data->fuel[index]) : data->density[index]) < FLT_EPSILON) ||
- data->obstacle[index])
- {
- continue;
- }
-
- vel[0] = data->velocity_x[index];
- vel[1] = data->velocity_y[index];
- vel[2] = data->velocity_z[index];
-
- /* convert vel to global space */
- mag = len_v3(vel);
- mul_mat3_m4_v3(sds->obmat, vel);
- normalize_v3(vel);
- mul_v3_fl(vel, mag);
-
- voxelCenter[0] = sds->p0[0] + sds->cell_size[0] * ((float)(x + sds->res_min[0]) + 0.5f);
- voxelCenter[1] = sds->p0[1] + sds->cell_size[1] * ((float)(y + sds->res_min[1]) + 0.5f);
- voxelCenter[2] = sds->p0[2] + sds->cell_size[2] * ((float)(z + sds->res_min[2]) + 0.5f);
- mul_m4_v3(sds->obmat, voxelCenter);
-
- pd_point_from_loc(data->scene, voxelCenter, vel, index, &epoint);
- BKE_effectors_apply(data->effectors, NULL, sds->effector_weights, &epoint, retvel, NULL);
-
- /* convert retvel to local space */
- mag = len_v3(retvel);
- mul_mat3_m4_v3(sds->imat, retvel);
- normalize_v3(retvel);
- mul_v3_fl(retvel, mag);
-
- // TODO dg - do in force!
- data->force_x[index] = min_ff(max_ff(-1.0f, retvel[0] * 0.2f), 1.0f);
- data->force_y[index] = min_ff(max_ff(-1.0f, retvel[1] * 0.2f), 1.0f);
- data->force_z[index] = min_ff(max_ff(-1.0f, retvel[2] * 0.2f), 1.0f);
- }
- }
+ UpdateEffectorsData *data = userdata;
+ SmokeDomainSettings *sds = data->sds;
+
+ for (int y = 0; y < sds->res[1]; y++) {
+ for (int z = 0; z < sds->res[2]; z++) {
+ EffectedPoint epoint;
+ float mag;
+ float voxelCenter[3] = {0, 0, 0}, vel[3] = {0, 0, 0}, retvel[3] = {0, 0, 0};
+ const unsigned int index = smoke_get_index(x, sds->res[0], y, sds->res[1], z);
+
+ if (((data->fuel ? MAX2(data->density[index], data->fuel[index]) : data->density[index]) <
+ FLT_EPSILON) ||
+ data->obstacle[index]) {
+ continue;
+ }
+
+ vel[0] = data->velocity_x[index];
+ vel[1] = data->velocity_y[index];
+ vel[2] = data->velocity_z[index];
+
+ /* convert vel to global space */
+ mag = len_v3(vel);
+ mul_mat3_m4_v3(sds->obmat, vel);
+ normalize_v3(vel);
+ mul_v3_fl(vel, mag);
+
+ voxelCenter[0] = sds->p0[0] + sds->cell_size[0] * ((float)(x + sds->res_min[0]) + 0.5f);
+ voxelCenter[1] = sds->p0[1] + sds->cell_size[1] * ((float)(y + sds->res_min[1]) + 0.5f);
+ voxelCenter[2] = sds->p0[2] + sds->cell_size[2] * ((float)(z + sds->res_min[2]) + 0.5f);
+ mul_m4_v3(sds->obmat, voxelCenter);
+
+ pd_point_from_loc(data->scene, voxelCenter, vel, index, &epoint);
+ BKE_effectors_apply(data->effectors, NULL, sds->effector_weights, &epoint, retvel, NULL);
+
+ /* convert retvel to local space */
+ mag = len_v3(retvel);
+ mul_mat3_m4_v3(sds->imat, retvel);
+ normalize_v3(retvel);
+ mul_v3_fl(retvel, mag);
+
+ // TODO dg - do in force!
+ data->force_x[index] = min_ff(max_ff(-1.0f, retvel[0] * 0.2f), 1.0f);
+ data->force_y[index] = min_ff(max_ff(-1.0f, retvel[1] * 0.2f), 1.0f);
+ data->force_z[index] = min_ff(max_ff(-1.0f, retvel[2] * 0.2f), 1.0f);
+ }
+ }
}
-static void update_effectors(Depsgraph *depsgraph, Scene *scene, Object *ob, SmokeDomainSettings *sds, float UNUSED(dt))
+static void update_effectors(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, SmokeDomainSettings *sds, float UNUSED(dt))
{
- ListBase *effectors;
- /* make sure smoke flow influence is 0.0f */
- sds->effector_weights->weight[PFIELD_SMOKEFLOW] = 0.0f;
- effectors = BKE_effectors_create(depsgraph, ob, NULL, sds->effector_weights);
-
- if (effectors) {
- // precalculate wind forces
- UpdateEffectorsData data;
- data.scene = scene;
- data.sds = sds;
- data.effectors = effectors;
- data.density = smoke_get_density(sds->fluid);
- data.fuel = smoke_get_fuel(sds->fluid);
- data.force_x = smoke_get_force_x(sds->fluid);
- data.force_y = smoke_get_force_y(sds->fluid);
- data.force_z = smoke_get_force_z(sds->fluid);
- data.velocity_x = smoke_get_velocity_x(sds->fluid);
- data.velocity_y = smoke_get_velocity_y(sds->fluid);
- data.velocity_z = smoke_get_velocity_z(sds->fluid);
- data.obstacle = smoke_get_obstacle(sds->fluid);
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
- BLI_task_parallel_range(0, sds->res[0],
- &data,
- update_effectors_task_cb,
- &settings);
- }
-
- BKE_effectors_free(effectors);
+ ListBase *effectors;
+ /* make sure smoke flow influence is 0.0f */
+ sds->effector_weights->weight[PFIELD_SMOKEFLOW] = 0.0f;
+ effectors = BKE_effectors_create(depsgraph, ob, NULL, sds->effector_weights);
+
+ if (effectors) {
+ // precalculate wind forces
+ UpdateEffectorsData data;
+ data.scene = scene;
+ data.sds = sds;
+ data.effectors = effectors;
+ data.density = smoke_get_density(sds->fluid);
+ data.fuel = smoke_get_fuel(sds->fluid);
+ data.force_x = smoke_get_force_x(sds->fluid);
+ data.force_y = smoke_get_force_y(sds->fluid);
+ data.force_z = smoke_get_force_z(sds->fluid);
+ data.velocity_x = smoke_get_velocity_x(sds->fluid);
+ data.velocity_y = smoke_get_velocity_y(sds->fluid);
+ data.velocity_z = smoke_get_velocity_z(sds->fluid);
+ data.obstacle = smoke_get_obstacle(sds->fluid);
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
+ BLI_task_parallel_range(0, sds->res[0], &data, update_effectors_task_cb, &settings);
+ }
+
+ BKE_effectors_free(effectors);
}
-static void step(
- Depsgraph *depsgraph,
- Scene *scene, Object *ob, SmokeModifierData *smd, Mesh *domain_me, float fps)
+static void step(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ SmokeModifierData *smd,
+ Mesh *domain_me,
+ float fps)
{
- SmokeDomainSettings *sds = smd->domain;
- /* stability values copied from wturbulence.cpp */
- const int maxSubSteps = 25;
- float maxVel;
- // maxVel should be 1.5 (1.5 cell max movement) * dx (cell size)
-
- float dt;
- float maxVelMag = 0.0f;
- int totalSubsteps;
- int substep = 0;
- float dtSubdiv;
- float gravity[3] = {0.0f, 0.0f, -1.0f};
- float gravity_mag;
-
- /* update object state */
- invert_m4_m4(sds->imat, ob->obmat);
- copy_m4_m4(sds->obmat, ob->obmat);
- smoke_set_domain_from_mesh(sds, ob, domain_me, (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) != 0);
-
- /* use global gravity if enabled */
- if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
- copy_v3_v3(gravity, scene->physics_settings.gravity);
- /* map default value to 1.0 */
- mul_v3_fl(gravity, 1.0f / 9.810f);
- }
- /* convert gravity to domain space */
- gravity_mag = len_v3(gravity);
- mul_mat3_m4_v3(sds->imat, gravity);
- normalize_v3(gravity);
- mul_v3_fl(gravity, gravity_mag);
-
- /* adapt timestep for different framerates, dt = 0.1 is at 25fps */
- dt = DT_DEFAULT * (25.0f / fps);
- // maximum timestep/"CFL" constraint: dt < 5.0 *dx / maxVel
- maxVel = (sds->dx * 5.0f);
-
- maxVelMag = sqrtf(maxVelMag) * dt * sds->time_scale;
- totalSubsteps = (int)((maxVelMag / maxVel) + 1.0f); /* always round up */
- totalSubsteps = (totalSubsteps < 1) ? 1 : totalSubsteps;
- totalSubsteps = (totalSubsteps > maxSubSteps) ? maxSubSteps : totalSubsteps;
-
- /* Disable substeps for now, since it results in numerical instability */
- totalSubsteps = 1.0f;
-
- dtSubdiv = (float)dt / (float)totalSubsteps;
-
- // printf("totalSubsteps: %d, maxVelMag: %f, dt: %f\n", totalSubsteps, maxVelMag, dt);
-
- for (substep = 0; substep < totalSubsteps; substep++)
- {
- // calc animated obstacle velocities
- update_flowsfluids(depsgraph, scene, ob, sds, dtSubdiv);
- update_obstacles(depsgraph, ob, sds, dtSubdiv, substep, totalSubsteps);
-
- if (sds->total_cells > 1) {
- update_effectors(depsgraph, scene, ob, sds, dtSubdiv); // DG TODO? problem --> uses forces instead of velocity, need to check how they need to be changed with variable dt
- smoke_step(sds->fluid, gravity, dtSubdiv);
- }
- }
+ SmokeDomainSettings *sds = smd->domain;
+ /* stability values copied from wturbulence.cpp */
+ const int maxSubSteps = 25;
+ float maxVel;
+ // maxVel should be 1.5 (1.5 cell max movement) * dx (cell size)
+
+ float dt;
+ float maxVelMag = 0.0f;
+ int totalSubsteps;
+ int substep = 0;
+ float dtSubdiv;
+ float gravity[3] = {0.0f, 0.0f, -1.0f};
+ float gravity_mag;
+
+ /* update object state */
+ invert_m4_m4(sds->imat, ob->obmat);
+ copy_m4_m4(sds->obmat, ob->obmat);
+ smoke_set_domain_from_mesh(sds, ob, domain_me, (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) != 0);
+
+ /* use global gravity if enabled */
+ if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
+ copy_v3_v3(gravity, scene->physics_settings.gravity);
+ /* map default value to 1.0 */
+ mul_v3_fl(gravity, 1.0f / 9.810f);
+ }
+ /* convert gravity to domain space */
+ gravity_mag = len_v3(gravity);
+ mul_mat3_m4_v3(sds->imat, gravity);
+ normalize_v3(gravity);
+ mul_v3_fl(gravity, gravity_mag);
+
+ /* adapt timestep for different framerates, dt = 0.1 is at 25fps */
+ dt = DT_DEFAULT * (25.0f / fps);
+ // maximum timestep/"CFL" constraint: dt < 5.0 *dx / maxVel
+ maxVel = (sds->dx * 5.0f);
+
+ maxVelMag = sqrtf(maxVelMag) * dt * sds->time_scale;
+ totalSubsteps = (int)((maxVelMag / maxVel) + 1.0f); /* always round up */
+ totalSubsteps = (totalSubsteps < 1) ? 1 : totalSubsteps;
+ totalSubsteps = (totalSubsteps > maxSubSteps) ? maxSubSteps : totalSubsteps;
+
+ /* Disable substeps for now, since it results in numerical instability */
+ totalSubsteps = 1.0f;
+
+ dtSubdiv = (float)dt / (float)totalSubsteps;
+
+ // printf("totalSubsteps: %d, maxVelMag: %f, dt: %f\n", totalSubsteps, maxVelMag, dt);
+
+ for (substep = 0; substep < totalSubsteps; substep++) {
+ // calc animated obstacle velocities
+ update_flowsfluids(depsgraph, scene, ob, sds, dtSubdiv);
+ update_obstacles(depsgraph, ob, sds, dtSubdiv, substep, totalSubsteps);
+
+ if (sds->total_cells > 1) {
+ update_effectors(
+ depsgraph,
+ scene,
+ ob,
+ sds,
+ dtSubdiv); // DG TODO? problem --> uses forces instead of velocity, need to check how they need to be changed with variable dt
+ smoke_step(sds->fluid, gravity, dtSubdiv);
+ }
+ }
}
static Mesh *createDomainGeometry(SmokeDomainSettings *sds, Object *ob)
{
- Mesh *result;
- MVert *mverts;
- MPoly *mpolys;
- MLoop *mloops;
- float min[3];
- float max[3];
- float *co;
- MPoly *mp;
- MLoop *ml;
-
- int num_verts = 8;
- int num_faces = 6;
- int i;
- float ob_loc[3] = {0};
- float ob_cache_loc[3] = {0};
-
- /* dont generate any mesh if there isnt any content */
- if (sds->total_cells <= 1) {
- num_verts = 0;
- num_faces = 0;
- }
-
- result = BKE_mesh_new_nomain(num_verts, 0, 0, num_faces * 4, num_faces);
- mverts = result->mvert;
- mpolys = result->mpoly;
- mloops = result->mloop;
-
- if (num_verts) {
- /* volume bounds */
- madd_v3fl_v3fl_v3fl_v3i(min, sds->p0, sds->cell_size, sds->res_min);
- madd_v3fl_v3fl_v3fl_v3i(max, sds->p0, sds->cell_size, sds->res_max);
-
- /* set vertices */
- /* top slab */
- co = mverts[0].co; co[0] = min[0]; co[1] = min[1]; co[2] = max[2];
- co = mverts[1].co; co[0] = max[0]; co[1] = min[1]; co[2] = max[2];
- co = mverts[2].co; co[0] = max[0]; co[1] = max[1]; co[2] = max[2];
- co = mverts[3].co; co[0] = min[0]; co[1] = max[1]; co[2] = max[2];
- /* bottom slab */
- co = mverts[4].co; co[0] = min[0]; co[1] = min[1]; co[2] = min[2];
- co = mverts[5].co; co[0] = max[0]; co[1] = min[1]; co[2] = min[2];
- co = mverts[6].co; co[0] = max[0]; co[1] = max[1]; co[2] = min[2];
- co = mverts[7].co; co[0] = min[0]; co[1] = max[1]; co[2] = min[2];
-
- /* create faces */
- /* top */
- mp = &mpolys[0]; ml = &mloops[0 * 4]; mp->loopstart = 0 * 4; mp->totloop = 4;
- ml[0].v = 0; ml[1].v = 1; ml[2].v = 2; ml[3].v = 3;
- /* right */
- mp = &mpolys[1]; ml = &mloops[1 * 4]; mp->loopstart = 1 * 4; mp->totloop = 4;
- ml[0].v = 2; ml[1].v = 1; ml[2].v = 5; ml[3].v = 6;
- /* bottom */
- mp = &mpolys[2]; ml = &mloops[2 * 4]; mp->loopstart = 2 * 4; mp->totloop = 4;
- ml[0].v = 7; ml[1].v = 6; ml[2].v = 5; ml[3].v = 4;
- /* left */
- mp = &mpolys[3]; ml = &mloops[3 * 4]; mp->loopstart = 3 * 4; mp->totloop = 4;
- ml[0].v = 0; ml[1].v = 3; ml[2].v = 7; ml[3].v = 4;
- /* front */
- mp = &mpolys[4]; ml = &mloops[4 * 4]; mp->loopstart = 4 * 4; mp->totloop = 4;
- ml[0].v = 3; ml[1].v = 2; ml[2].v = 6; ml[3].v = 7;
- /* back */
- mp = &mpolys[5]; ml = &mloops[5 * 4]; mp->loopstart = 5 * 4; mp->totloop = 4;
- ml[0].v = 1; ml[1].v = 0; ml[2].v = 4; ml[3].v = 5;
-
- /* calculate required shift to match domain's global position
- * it was originally simulated at (if object moves without smoke step) */
- invert_m4_m4(ob->imat, ob->obmat);
- mul_m4_v3(ob->obmat, ob_loc);
- mul_m4_v3(sds->obmat, ob_cache_loc);
- sub_v3_v3v3(sds->obj_shift_f, ob_cache_loc, ob_loc);
- /* convert shift to local space and apply to vertices */
- mul_mat3_m4_v3(ob->imat, sds->obj_shift_f);
- /* apply */
- for (i = 0; i < num_verts; i++) {
- add_v3_v3(mverts[i].co, sds->obj_shift_f);
- }
- }
-
- BKE_mesh_calc_edges(result, false, false);
- result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
- return result;
+ Mesh *result;
+ MVert *mverts;
+ MPoly *mpolys;
+ MLoop *mloops;
+ float min[3];
+ float max[3];
+ float *co;
+ MPoly *mp;
+ MLoop *ml;
+
+ int num_verts = 8;
+ int num_faces = 6;
+ int i;
+ float ob_loc[3] = {0};
+ float ob_cache_loc[3] = {0};
+
+ /* dont generate any mesh if there isnt any content */
+ if (sds->total_cells <= 1) {
+ num_verts = 0;
+ num_faces = 0;
+ }
+
+ result = BKE_mesh_new_nomain(num_verts, 0, 0, num_faces * 4, num_faces);
+ mverts = result->mvert;
+ mpolys = result->mpoly;
+ mloops = result->mloop;
+
+ if (num_verts) {
+ /* volume bounds */
+ madd_v3fl_v3fl_v3fl_v3i(min, sds->p0, sds->cell_size, sds->res_min);
+ madd_v3fl_v3fl_v3fl_v3i(max, sds->p0, sds->cell_size, sds->res_max);
+
+ /* set vertices */
+ /* top slab */
+ co = mverts[0].co;
+ co[0] = min[0];
+ co[1] = min[1];
+ co[2] = max[2];
+ co = mverts[1].co;
+ co[0] = max[0];
+ co[1] = min[1];
+ co[2] = max[2];
+ co = mverts[2].co;
+ co[0] = max[0];
+ co[1] = max[1];
+ co[2] = max[2];
+ co = mverts[3].co;
+ co[0] = min[0];
+ co[1] = max[1];
+ co[2] = max[2];
+ /* bottom slab */
+ co = mverts[4].co;
+ co[0] = min[0];
+ co[1] = min[1];
+ co[2] = min[2];
+ co = mverts[5].co;
+ co[0] = max[0];
+ co[1] = min[1];
+ co[2] = min[2];
+ co = mverts[6].co;
+ co[0] = max[0];
+ co[1] = max[1];
+ co[2] = min[2];
+ co = mverts[7].co;
+ co[0] = min[0];
+ co[1] = max[1];
+ co[2] = min[2];
+
+ /* create faces */
+ /* top */
+ mp = &mpolys[0];
+ ml = &mloops[0 * 4];
+ mp->loopstart = 0 * 4;
+ mp->totloop = 4;
+ ml[0].v = 0;
+ ml[1].v = 1;
+ ml[2].v = 2;
+ ml[3].v = 3;
+ /* right */
+ mp = &mpolys[1];
+ ml = &mloops[1 * 4];
+ mp->loopstart = 1 * 4;
+ mp->totloop = 4;
+ ml[0].v = 2;
+ ml[1].v = 1;
+ ml[2].v = 5;
+ ml[3].v = 6;
+ /* bottom */
+ mp = &mpolys[2];
+ ml = &mloops[2 * 4];
+ mp->loopstart = 2 * 4;
+ mp->totloop = 4;
+ ml[0].v = 7;
+ ml[1].v = 6;
+ ml[2].v = 5;
+ ml[3].v = 4;
+ /* left */
+ mp = &mpolys[3];
+ ml = &mloops[3 * 4];
+ mp->loopstart = 3 * 4;
+ mp->totloop = 4;
+ ml[0].v = 0;
+ ml[1].v = 3;
+ ml[2].v = 7;
+ ml[3].v = 4;
+ /* front */
+ mp = &mpolys[4];
+ ml = &mloops[4 * 4];
+ mp->loopstart = 4 * 4;
+ mp->totloop = 4;
+ ml[0].v = 3;
+ ml[1].v = 2;
+ ml[2].v = 6;
+ ml[3].v = 7;
+ /* back */
+ mp = &mpolys[5];
+ ml = &mloops[5 * 4];
+ mp->loopstart = 5 * 4;
+ mp->totloop = 4;
+ ml[0].v = 1;
+ ml[1].v = 0;
+ ml[2].v = 4;
+ ml[3].v = 5;
+
+ /* calculate required shift to match domain's global position
+ * it was originally simulated at (if object moves without smoke step) */
+ invert_m4_m4(ob->imat, ob->obmat);
+ mul_m4_v3(ob->obmat, ob_loc);
+ mul_m4_v3(sds->obmat, ob_cache_loc);
+ sub_v3_v3v3(sds->obj_shift_f, ob_cache_loc, ob_loc);
+ /* convert shift to local space and apply to vertices */
+ mul_mat3_m4_v3(ob->imat, sds->obj_shift_f);
+ /* apply */
+ for (i = 0; i < num_verts; i++) {
+ add_v3_v3(mverts[i].co, sds->obj_shift_f);
+ }
+ }
+
+ BKE_mesh_calc_edges(result, false, false);
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ return result;
}
static void smokeModifier_process(
- SmokeModifierData *smd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me)
+ SmokeModifierData *smd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me)
{
- const int scene_framenr = (int)DEG_get_ctime(depsgraph);
-
- if ((smd->type & MOD_SMOKE_TYPE_FLOW))
- {
- if (scene_framenr >= smd->time)
- smokeModifier_init(smd, ob, scene_framenr, me);
-
- if (smd->flow->mesh) BKE_id_free(NULL, smd->flow->mesh);
- smd->flow->mesh = BKE_mesh_copy_for_eval(me, false);
-
- if (scene_framenr > smd->time)
- {
- smd->time = scene_framenr;
- }
- else if (scene_framenr < smd->time)
- {
- smd->time = scene_framenr;
- smokeModifier_reset_ex(smd, false);
- }
- }
- else if (smd->type & MOD_SMOKE_TYPE_COLL)
- {
- if (scene_framenr >= smd->time)
- smokeModifier_init(smd, ob, scene_framenr, me);
-
- if (smd->coll)
- {
- if (smd->coll->mesh)
- BKE_id_free(NULL, smd->coll->mesh);
-
- smd->coll->mesh = BKE_mesh_copy_for_eval(me, false);
- }
-
- smd->time = scene_framenr;
- if (scene_framenr < smd->time)
- {
- smokeModifier_reset_ex(smd, false);
- }
- }
- else if (smd->type & MOD_SMOKE_TYPE_DOMAIN)
- {
- SmokeDomainSettings *sds = smd->domain;
- PointCache *cache = NULL;
- PTCacheID pid;
- int startframe, endframe, framenr;
- float timescale;
-
- framenr = scene_framenr;
-
- cache = sds->point_cache[0];
- BKE_ptcache_id_from_smoke(&pid, ob, smd);
- BKE_ptcache_id_time(&pid, scene, framenr, &startframe, &endframe, &timescale);
-
- if (!smd->domain->fluid || framenr == startframe)
- {
- BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
- smokeModifier_reset_ex(smd, false);
- BKE_ptcache_validate(cache, framenr);
- cache->flag &= ~PTCACHE_REDO_NEEDED;
- }
-
- if (!smd->domain->fluid && (framenr != startframe) && (smd->domain->flags & MOD_SMOKE_FILE_LOAD) == 0 && (cache->flag & PTCACHE_BAKED) == 0)
- return;
-
- smd->domain->flags &= ~MOD_SMOKE_FILE_LOAD;
- CLAMP(framenr, startframe, endframe);
-
- /* If already viewing a pre/after frame, no need to reload */
- if ((smd->time == framenr) && (framenr != scene_framenr))
- return;
-
- if (smokeModifier_init(smd, ob, scene_framenr, me) == 0)
- {
- printf("bad smokeModifier_init\n");
- return;
- }
-
- /* only calculate something when we advanced a single frame */
- /* don't simulate if viewing start frame, but scene frame is not real start frame */
- bool can_simulate = (framenr == (int)smd->time + 1) && (framenr == scene_framenr);
-
- /* try to read from cache */
- if (BKE_ptcache_read(&pid, (float)framenr, can_simulate) == PTCACHE_READ_EXACT) {
- BKE_ptcache_validate(cache, framenr);
- smd->time = framenr;
- return;
- }
-
- if (!can_simulate)
- return;
-
-#ifdef DEBUG_TIME
- double start = PIL_check_seconds_timer();
-#endif
-
- /* if on second frame, write cache for first frame */
- if ((int)smd->time == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact == 0)) {
- BKE_ptcache_write(&pid, startframe);
- }
-
- // set new time
- smd->time = scene_framenr;
-
- /* do simulation */
-
- // simulate the actual smoke (c++ code in intern/smoke)
- // DG: interesting commenting this line + deactivating loading of noise files
- if (framenr != startframe)
- {
- if (sds->flags & MOD_SMOKE_DISSOLVE) {
- /* low res dissolve */
- smoke_dissolve(sds->fluid, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG);
- /* high res dissolve */
- if (sds->wt) {
- smoke_dissolve_wavelet(sds->wt, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG);
- }
-
- }
-
- step(depsgraph, scene, ob, smd, me, scene->r.frs_sec / scene->r.frs_sec_base);
- }
-
- // create shadows before writing cache so they get stored
- smoke_calc_transparency(sds, DEG_get_evaluated_view_layer(depsgraph));
-
- if (sds->wt && sds->total_cells > 1) {
- smoke_turbulence_step(sds->wt, sds->fluid);
- }
-
- BKE_ptcache_validate(cache, framenr);
- if (framenr != startframe)
- BKE_ptcache_write(&pid, framenr);
-
-#ifdef DEBUG_TIME
- double end = PIL_check_seconds_timer();
- printf("Frame: %d, Time: %f\n\n", (int)smd->time, (float)(end - start));
-#endif
- }
+ const int scene_framenr = (int)DEG_get_ctime(depsgraph);
+
+ if ((smd->type & MOD_SMOKE_TYPE_FLOW)) {
+ if (scene_framenr >= smd->time)
+ smokeModifier_init(smd, ob, scene_framenr, me);
+
+ if (smd->flow->mesh)
+ BKE_id_free(NULL, smd->flow->mesh);
+ smd->flow->mesh = BKE_mesh_copy_for_eval(me, false);
+
+ if (scene_framenr > smd->time) {
+ smd->time = scene_framenr;
+ }
+ else if (scene_framenr < smd->time) {
+ smd->time = scene_framenr;
+ smokeModifier_reset_ex(smd, false);
+ }
+ }
+ else if (smd->type & MOD_SMOKE_TYPE_COLL) {
+ if (scene_framenr >= smd->time)
+ smokeModifier_init(smd, ob, scene_framenr, me);
+
+ if (smd->coll) {
+ if (smd->coll->mesh)
+ BKE_id_free(NULL, smd->coll->mesh);
+
+ smd->coll->mesh = BKE_mesh_copy_for_eval(me, false);
+ }
+
+ smd->time = scene_framenr;
+ if (scene_framenr < smd->time) {
+ smokeModifier_reset_ex(smd, false);
+ }
+ }
+ else if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
+ SmokeDomainSettings *sds = smd->domain;
+ PointCache *cache = NULL;
+ PTCacheID pid;
+ int startframe, endframe, framenr;
+ float timescale;
+
+ framenr = scene_framenr;
+
+ cache = sds->point_cache[0];
+ BKE_ptcache_id_from_smoke(&pid, ob, smd);
+ BKE_ptcache_id_time(&pid, scene, framenr, &startframe, &endframe, &timescale);
+
+ if (!smd->domain->fluid || framenr == startframe) {
+ BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
+ smokeModifier_reset_ex(smd, false);
+ BKE_ptcache_validate(cache, framenr);
+ cache->flag &= ~PTCACHE_REDO_NEEDED;
+ }
+
+ if (!smd->domain->fluid && (framenr != startframe) &&
+ (smd->domain->flags & MOD_SMOKE_FILE_LOAD) == 0 && (cache->flag & PTCACHE_BAKED) == 0)
+ return;
+
+ smd->domain->flags &= ~MOD_SMOKE_FILE_LOAD;
+ CLAMP(framenr, startframe, endframe);
+
+ /* If already viewing a pre/after frame, no need to reload */
+ if ((smd->time == framenr) && (framenr != scene_framenr))
+ return;
+
+ if (smokeModifier_init(smd, ob, scene_framenr, me) == 0) {
+ printf("bad smokeModifier_init\n");
+ return;
+ }
+
+ /* only calculate something when we advanced a single frame */
+ /* don't simulate if viewing start frame, but scene frame is not real start frame */
+ bool can_simulate = (framenr == (int)smd->time + 1) && (framenr == scene_framenr);
+
+ /* try to read from cache */
+ if (BKE_ptcache_read(&pid, (float)framenr, can_simulate) == PTCACHE_READ_EXACT) {
+ BKE_ptcache_validate(cache, framenr);
+ smd->time = framenr;
+ return;
+ }
+
+ if (!can_simulate)
+ return;
+
+# ifdef DEBUG_TIME
+ double start = PIL_check_seconds_timer();
+# endif
+
+ /* if on second frame, write cache for first frame */
+ if ((int)smd->time == startframe &&
+ (cache->flag & PTCACHE_OUTDATED || cache->last_exact == 0)) {
+ BKE_ptcache_write(&pid, startframe);
+ }
+
+ // set new time
+ smd->time = scene_framenr;
+
+ /* do simulation */
+
+ // simulate the actual smoke (c++ code in intern/smoke)
+ // DG: interesting commenting this line + deactivating loading of noise files
+ if (framenr != startframe) {
+ if (sds->flags & MOD_SMOKE_DISSOLVE) {
+ /* low res dissolve */
+ smoke_dissolve(sds->fluid, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG);
+ /* high res dissolve */
+ if (sds->wt) {
+ smoke_dissolve_wavelet(sds->wt, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG);
+ }
+ }
+
+ step(depsgraph, scene, ob, smd, me, scene->r.frs_sec / scene->r.frs_sec_base);
+ }
+
+ // create shadows before writing cache so they get stored
+ smoke_calc_transparency(sds, DEG_get_evaluated_view_layer(depsgraph));
+
+ if (sds->wt && sds->total_cells > 1) {
+ smoke_turbulence_step(sds->wt, sds->fluid);
+ }
+
+ BKE_ptcache_validate(cache, framenr);
+ if (framenr != startframe)
+ BKE_ptcache_write(&pid, framenr);
+
+# ifdef DEBUG_TIME
+ double end = PIL_check_seconds_timer();
+ printf("Frame: %d, Time: %f\n\n", (int)smd->time, (float)(end - start));
+# endif
+ }
}
struct Mesh *smokeModifier_do(
- SmokeModifierData *smd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me)
+ SmokeModifierData *smd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me)
{
- /* lock so preview render does not read smoke data while it gets modified */
- if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain)
- BLI_rw_mutex_lock(smd->domain->fluid_mutex, THREAD_LOCK_WRITE);
-
- smokeModifier_process(smd, depsgraph, scene, ob, me);
-
- if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain)
- BLI_rw_mutex_unlock(smd->domain->fluid_mutex);
-
- /* return generated geometry for adaptive domain */
- Mesh *result;
- if (smd->type & MOD_SMOKE_TYPE_DOMAIN && smd->domain &&
- smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN &&
- smd->domain->base_res[0])
- {
- result = createDomainGeometry(smd->domain, ob);
- }
- else {
- result = BKE_mesh_copy_for_eval(me, false);
- }
- /* XXX This is really not a nice hack, but until root of the problem is understood,
- * this should be an acceptable workaround I think.
- * See T58492 for details on the issue. */
- result->texflag |= ME_AUTOSPACE;
- return result;
+ /* lock so preview render does not read smoke data while it gets modified */
+ if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain)
+ BLI_rw_mutex_lock(smd->domain->fluid_mutex, THREAD_LOCK_WRITE);
+
+ smokeModifier_process(smd, depsgraph, scene, ob, me);
+
+ if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain)
+ BLI_rw_mutex_unlock(smd->domain->fluid_mutex);
+
+ /* return generated geometry for adaptive domain */
+ Mesh *result;
+ if (smd->type & MOD_SMOKE_TYPE_DOMAIN && smd->domain &&
+ smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN && smd->domain->base_res[0]) {
+ result = createDomainGeometry(smd->domain, ob);
+ }
+ else {
+ result = BKE_mesh_copy_for_eval(me, false);
+ }
+ /* XXX This is really not a nice hack, but until root of the problem is understood,
+ * this should be an acceptable workaround I think.
+ * See T58492 for details on the issue. */
+ result->texflag |= ME_AUTOSPACE;
+ return result;
}
-static float calc_voxel_transp(float *result, float *input, int res[3], int *pixel, float *tRay, float correct)
+static float calc_voxel_transp(
+ float *result, float *input, int res[3], int *pixel, float *tRay, float correct)
{
- const size_t index = smoke_get_index(pixel[0], res[0], pixel[1], res[1], pixel[2]);
+ const size_t index = smoke_get_index(pixel[0], res[0], pixel[1], res[1], pixel[2]);
- // T_ray *= T_vox
- *tRay *= expf(input[index] * correct);
+ // T_ray *= T_vox
+ *tRay *= expf(input[index] * correct);
- if (result[index] < 0.0f)
- {
- result[index] = *tRay;
- }
+ if (result[index] < 0.0f) {
+ result[index] = *tRay;
+ }
- return *tRay;
+ return *tRay;
}
-static void bresenham_linie_3D(int x1, int y1, int z1, int x2, int y2, int z2, float *tRay, bresenham_callback cb, float *result, float *input, int res[3], float correct)
+static void bresenham_linie_3D(int x1,
+ int y1,
+ int z1,
+ int x2,
+ int y2,
+ int z2,
+ float *tRay,
+ bresenham_callback cb,
+ float *result,
+ float *input,
+ int res[3],
+ float correct)
{
- int dx, dy, dz, i, l, m, n, x_inc, y_inc, z_inc, err_1, err_2, dx2, dy2, dz2;
- int pixel[3];
-
- pixel[0] = x1;
- pixel[1] = y1;
- pixel[2] = z1;
-
- dx = x2 - x1;
- dy = y2 - y1;
- dz = z2 - z1;
-
- x_inc = (dx < 0) ? -1 : 1;
- l = abs(dx);
- y_inc = (dy < 0) ? -1 : 1;
- m = abs(dy);
- z_inc = (dz < 0) ? -1 : 1;
- n = abs(dz);
- dx2 = l << 1;
- dy2 = m << 1;
- dz2 = n << 1;
-
- if ((l >= m) && (l >= n)) {
- err_1 = dy2 - l;
- err_2 = dz2 - l;
- for (i = 0; i < l; i++) {
- if (cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON)
- break;
- if (err_1 > 0) {
- pixel[1] += y_inc;
- err_1 -= dx2;
- }
- if (err_2 > 0) {
- pixel[2] += z_inc;
- err_2 -= dx2;
- }
- err_1 += dy2;
- err_2 += dz2;
- pixel[0] += x_inc;
- }
- }
- else if ((m >= l) && (m >= n)) {
- err_1 = dx2 - m;
- err_2 = dz2 - m;
- for (i = 0; i < m; i++) {
- if (cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON)
- break;
- if (err_1 > 0) {
- pixel[0] += x_inc;
- err_1 -= dy2;
- }
- if (err_2 > 0) {
- pixel[2] += z_inc;
- err_2 -= dy2;
- }
- err_1 += dx2;
- err_2 += dz2;
- pixel[1] += y_inc;
- }
- }
- else {
- err_1 = dy2 - n;
- err_2 = dx2 - n;
- for (i = 0; i < n; i++) {
- if (cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON)
- break;
- if (err_1 > 0) {
- pixel[1] += y_inc;
- err_1 -= dz2;
- }
- if (err_2 > 0) {
- pixel[0] += x_inc;
- err_2 -= dz2;
- }
- err_1 += dy2;
- err_2 += dx2;
- pixel[2] += z_inc;
- }
- }
- cb(result, input, res, pixel, tRay, correct);
+ int dx, dy, dz, i, l, m, n, x_inc, y_inc, z_inc, err_1, err_2, dx2, dy2, dz2;
+ int pixel[3];
+
+ pixel[0] = x1;
+ pixel[1] = y1;
+ pixel[2] = z1;
+
+ dx = x2 - x1;
+ dy = y2 - y1;
+ dz = z2 - z1;
+
+ x_inc = (dx < 0) ? -1 : 1;
+ l = abs(dx);
+ y_inc = (dy < 0) ? -1 : 1;
+ m = abs(dy);
+ z_inc = (dz < 0) ? -1 : 1;
+ n = abs(dz);
+ dx2 = l << 1;
+ dy2 = m << 1;
+ dz2 = n << 1;
+
+ if ((l >= m) && (l >= n)) {
+ err_1 = dy2 - l;
+ err_2 = dz2 - l;
+ for (i = 0; i < l; i++) {
+ if (cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON)
+ break;
+ if (err_1 > 0) {
+ pixel[1] += y_inc;
+ err_1 -= dx2;
+ }
+ if (err_2 > 0) {
+ pixel[2] += z_inc;
+ err_2 -= dx2;
+ }
+ err_1 += dy2;
+ err_2 += dz2;
+ pixel[0] += x_inc;
+ }
+ }
+ else if ((m >= l) && (m >= n)) {
+ err_1 = dx2 - m;
+ err_2 = dz2 - m;
+ for (i = 0; i < m; i++) {
+ if (cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON)
+ break;
+ if (err_1 > 0) {
+ pixel[0] += x_inc;
+ err_1 -= dy2;
+ }
+ if (err_2 > 0) {
+ pixel[2] += z_inc;
+ err_2 -= dy2;
+ }
+ err_1 += dx2;
+ err_2 += dz2;
+ pixel[1] += y_inc;
+ }
+ }
+ else {
+ err_1 = dy2 - n;
+ err_2 = dx2 - n;
+ for (i = 0; i < n; i++) {
+ if (cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON)
+ break;
+ if (err_1 > 0) {
+ pixel[1] += y_inc;
+ err_1 -= dz2;
+ }
+ if (err_2 > 0) {
+ pixel[0] += x_inc;
+ err_2 -= dz2;
+ }
+ err_1 += dy2;
+ err_2 += dx2;
+ pixel[2] += z_inc;
+ }
+ }
+ cb(result, input, res, pixel, tRay, correct);
}
static void smoke_calc_transparency(SmokeDomainSettings *sds, ViewLayer *view_layer)
{
- float bv[6] = {0};
- float light[3];
- int a, z, slabsize = sds->res[0] * sds->res[1], size = sds->res[0] * sds->res[1] * sds->res[2];
- float *density = smoke_get_density(sds->fluid);
- float correct = -7.0f * sds->dx;
-
- if (!get_light(view_layer, light)) return;
-
- /* convert light pos to sim cell space */
- mul_m4_v3(sds->imat, light);
- light[0] = (light[0] - sds->p0[0]) / sds->cell_size[0] - 0.5f - (float)sds->res_min[0];
- light[1] = (light[1] - sds->p0[1]) / sds->cell_size[1] - 0.5f - (float)sds->res_min[1];
- light[2] = (light[2] - sds->p0[2]) / sds->cell_size[2] - 0.5f - (float)sds->res_min[2];
-
- for (a = 0; a < size; a++)
- sds->shadow[a] = -1.0f;
-
- /* calculate domain bounds in sim cell space */
- // 0,2,4 = 0.0f
- bv[1] = (float)sds->res[0]; // x
- bv[3] = (float)sds->res[1]; // y
- bv[5] = (float)sds->res[2]; // z
-
- for (z = 0; z < sds->res[2]; z++)
- {
- size_t index = z * slabsize;
- int x, y;
-
- for (y = 0; y < sds->res[1]; y++)
- for (x = 0; x < sds->res[0]; x++, index++)
- {
- float voxelCenter[3];
- float pos[3];
- int cell[3];
- float tRay = 1.0;
-
- if (sds->shadow[index] >= 0.0f)
- continue;
- voxelCenter[0] = (float)x;
- voxelCenter[1] = (float)y;
- voxelCenter[2] = (float)z;
-
- // get starting cell (light pos)
- if (BLI_bvhtree_bb_raycast(bv, light, voxelCenter, pos) > FLT_EPSILON)
- {
- // we're ouside -> use point on side of domain
- cell[0] = (int)floor(pos[0]);
- cell[1] = (int)floor(pos[1]);
- cell[2] = (int)floor(pos[2]);
- }
- else {
- // we're inside -> use light itself
- cell[0] = (int)floor(light[0]);
- cell[1] = (int)floor(light[1]);
- cell[2] = (int)floor(light[2]);
- }
- /* clamp within grid bounds */
- CLAMP(cell[0], 0, sds->res[0] - 1);
- CLAMP(cell[1], 0, sds->res[1] - 1);
- CLAMP(cell[2], 0, sds->res[2] - 1);
-
- bresenham_linie_3D(cell[0], cell[1], cell[2], x, y, z, &tRay, calc_voxel_transp, sds->shadow, density, sds->res, correct);
-
- // convention -> from a RGBA float array, use G value for tRay
- sds->shadow[index] = tRay;
- }
- }
+ float bv[6] = {0};
+ float light[3];
+ int a, z, slabsize = sds->res[0] * sds->res[1], size = sds->res[0] * sds->res[1] * sds->res[2];
+ float *density = smoke_get_density(sds->fluid);
+ float correct = -7.0f * sds->dx;
+
+ if (!get_light(view_layer, light))
+ return;
+
+ /* convert light pos to sim cell space */
+ mul_m4_v3(sds->imat, light);
+ light[0] = (light[0] - sds->p0[0]) / sds->cell_size[0] - 0.5f - (float)sds->res_min[0];
+ light[1] = (light[1] - sds->p0[1]) / sds->cell_size[1] - 0.5f - (float)sds->res_min[1];
+ light[2] = (light[2] - sds->p0[2]) / sds->cell_size[2] - 0.5f - (float)sds->res_min[2];
+
+ for (a = 0; a < size; a++)
+ sds->shadow[a] = -1.0f;
+
+ /* calculate domain bounds in sim cell space */
+ // 0,2,4 = 0.0f
+ bv[1] = (float)sds->res[0]; // x
+ bv[3] = (float)sds->res[1]; // y
+ bv[5] = (float)sds->res[2]; // z
+
+ for (z = 0; z < sds->res[2]; z++) {
+ size_t index = z * slabsize;
+ int x, y;
+
+ for (y = 0; y < sds->res[1]; y++)
+ for (x = 0; x < sds->res[0]; x++, index++) {
+ float voxelCenter[3];
+ float pos[3];
+ int cell[3];
+ float tRay = 1.0;
+
+ if (sds->shadow[index] >= 0.0f)
+ continue;
+ voxelCenter[0] = (float)x;
+ voxelCenter[1] = (float)y;
+ voxelCenter[2] = (float)z;
+
+ // get starting cell (light pos)
+ if (BLI_bvhtree_bb_raycast(bv, light, voxelCenter, pos) > FLT_EPSILON) {
+ // we're ouside -> use point on side of domain
+ cell[0] = (int)floor(pos[0]);
+ cell[1] = (int)floor(pos[1]);
+ cell[2] = (int)floor(pos[2]);
+ }
+ else {
+ // we're inside -> use light itself
+ cell[0] = (int)floor(light[0]);
+ cell[1] = (int)floor(light[1]);
+ cell[2] = (int)floor(light[2]);
+ }
+ /* clamp within grid bounds */
+ CLAMP(cell[0], 0, sds->res[0] - 1);
+ CLAMP(cell[1], 0, sds->res[1] - 1);
+ CLAMP(cell[2], 0, sds->res[2] - 1);
+
+ bresenham_linie_3D(cell[0],
+ cell[1],
+ cell[2],
+ x,
+ y,
+ z,
+ &tRay,
+ calc_voxel_transp,
+ sds->shadow,
+ density,
+ sds->res,
+ correct);
+
+ // convention -> from a RGBA float array, use G value for tRay
+ sds->shadow[index] = tRay;
+ }
+ }
}
/* get smoke velocity and density at given coordinates
* returns fluid density or -1.0f if outside domain. */
float BKE_smoke_get_velocity_at(struct Object *ob, float position[3], float velocity[3])
{
- SmokeModifierData *smd = (SmokeModifierData *)modifiers_findByType(ob, eModifierType_Smoke);
- zero_v3(velocity);
-
- if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && smd->domain->fluid) {
- SmokeDomainSettings *sds = smd->domain;
- float time_mult = 25.f * DT_DEFAULT;
- float vel_mag;
- float *velX = smoke_get_velocity_x(sds->fluid);
- float *velY = smoke_get_velocity_y(sds->fluid);
- float *velZ = smoke_get_velocity_z(sds->fluid);
- float density = 0.0f, fuel = 0.0f;
- float pos[3];
- copy_v3_v3(pos, position);
- smoke_pos_to_cell(sds, pos);
-
- /* check if point is outside domain max bounds */
- if (pos[0] < sds->res_min[0] || pos[1] < sds->res_min[1] || pos[2] < sds->res_min[2]) return -1.0f;
- if (pos[0] > sds->res_max[0] || pos[1] > sds->res_max[1] || pos[2] > sds->res_max[2]) return -1.0f;
-
- /* map pos between 0.0 - 1.0 */
- pos[0] = (pos[0] - sds->res_min[0]) / ((float)sds->res[0]);
- pos[1] = (pos[1] - sds->res_min[1]) / ((float)sds->res[1]);
- pos[2] = (pos[2] - sds->res_min[2]) / ((float)sds->res[2]);
-
-
- /* check if point is outside active area */
- if (smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
- if (pos[0] < 0.0f || pos[1] < 0.0f || pos[2] < 0.0f) return 0.0f;
- if (pos[0] > 1.0f || pos[1] > 1.0f || pos[2] > 1.0f) return 0.0f;
- }
-
- /* get interpolated velocity */
- velocity[0] = BLI_voxel_sample_trilinear(velX, sds->res, pos) * sds->global_size[0] * time_mult;
- velocity[1] = BLI_voxel_sample_trilinear(velY, sds->res, pos) * sds->global_size[1] * time_mult;
- velocity[2] = BLI_voxel_sample_trilinear(velZ, sds->res, pos) * sds->global_size[2] * time_mult;
-
- /* convert velocity direction to global space */
- vel_mag = len_v3(velocity);
- mul_mat3_m4_v3(sds->obmat, velocity);
- normalize_v3(velocity);
- mul_v3_fl(velocity, vel_mag);
-
- /* use max value of fuel or smoke density */
- density = BLI_voxel_sample_trilinear(smoke_get_density(sds->fluid), sds->res, pos);
- if (smoke_has_fuel(sds->fluid)) {
- fuel = BLI_voxel_sample_trilinear(smoke_get_fuel(sds->fluid), sds->res, pos);
- }
- return MAX2(density, fuel);
- }
- return -1.0f;
+ SmokeModifierData *smd = (SmokeModifierData *)modifiers_findByType(ob, eModifierType_Smoke);
+ zero_v3(velocity);
+
+ if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && smd->domain->fluid) {
+ SmokeDomainSettings *sds = smd->domain;
+ float time_mult = 25.f * DT_DEFAULT;
+ float vel_mag;
+ float *velX = smoke_get_velocity_x(sds->fluid);
+ float *velY = smoke_get_velocity_y(sds->fluid);
+ float *velZ = smoke_get_velocity_z(sds->fluid);
+ float density = 0.0f, fuel = 0.0f;
+ float pos[3];
+ copy_v3_v3(pos, position);
+ smoke_pos_to_cell(sds, pos);
+
+ /* check if point is outside domain max bounds */
+ if (pos[0] < sds->res_min[0] || pos[1] < sds->res_min[1] || pos[2] < sds->res_min[2])
+ return -1.0f;
+ if (pos[0] > sds->res_max[0] || pos[1] > sds->res_max[1] || pos[2] > sds->res_max[2])
+ return -1.0f;
+
+ /* map pos between 0.0 - 1.0 */
+ pos[0] = (pos[0] - sds->res_min[0]) / ((float)sds->res[0]);
+ pos[1] = (pos[1] - sds->res_min[1]) / ((float)sds->res[1]);
+ pos[2] = (pos[2] - sds->res_min[2]) / ((float)sds->res[2]);
+
+ /* check if point is outside active area */
+ if (smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
+ if (pos[0] < 0.0f || pos[1] < 0.0f || pos[2] < 0.0f)
+ return 0.0f;
+ if (pos[0] > 1.0f || pos[1] > 1.0f || pos[2] > 1.0f)
+ return 0.0f;
+ }
+
+ /* get interpolated velocity */
+ velocity[0] = BLI_voxel_sample_trilinear(velX, sds->res, pos) * sds->global_size[0] *
+ time_mult;
+ velocity[1] = BLI_voxel_sample_trilinear(velY, sds->res, pos) * sds->global_size[1] *
+ time_mult;
+ velocity[2] = BLI_voxel_sample_trilinear(velZ, sds->res, pos) * sds->global_size[2] *
+ time_mult;
+
+ /* convert velocity direction to global space */
+ vel_mag = len_v3(velocity);
+ mul_mat3_m4_v3(sds->obmat, velocity);
+ normalize_v3(velocity);
+ mul_v3_fl(velocity, vel_mag);
+
+ /* use max value of fuel or smoke density */
+ density = BLI_voxel_sample_trilinear(smoke_get_density(sds->fluid), sds->res, pos);
+ if (smoke_has_fuel(sds->fluid)) {
+ fuel = BLI_voxel_sample_trilinear(smoke_get_fuel(sds->fluid), sds->res, pos);
+ }
+ return MAX2(density, fuel);
+ }
+ return -1.0f;
}
int BKE_smoke_get_data_flags(SmokeDomainSettings *sds)
{
- int flags = 0;
-
- if (sds->fluid) {
- if (smoke_has_heat(sds->fluid))
- flags |= SM_ACTIVE_HEAT;
- if (smoke_has_fuel(sds->fluid))
- flags |= SM_ACTIVE_FIRE;
- if (smoke_has_colors(sds->fluid))
- flags |= SM_ACTIVE_COLORS;
- }
-
- return flags;
+ int flags = 0;
+
+ if (sds->fluid) {
+ if (smoke_has_heat(sds->fluid))
+ flags |= SM_ACTIVE_HEAT;
+ if (smoke_has_fuel(sds->fluid))
+ flags |= SM_ACTIVE_FIRE;
+ if (smoke_has_colors(sds->fluid))
+ flags |= SM_ACTIVE_COLORS;
+ }
+
+ return flags;
}
#endif /* WITH_SMOKE */
bool BKE_smoke_show_highres(Scene *scene, SmokeDomainSettings *sds)
{
- if ((sds->viewsettings & MOD_SMOKE_VIEW_SHOW_HIGHRES) == 0) {
- return false;
- }
- if (scene->r.mode & R_SIMPLIFY) {
- return !scene->r.simplify_smoke_ignore_highres;
- }
- return true;
+ if ((sds->viewsettings & MOD_SMOKE_VIEW_SHOW_HIGHRES) == 0) {
+ return false;
+ }
+ if (scene->r.mode & R_SIMPLIFY) {
+ return !scene->r.simplify_smoke_ignore_highres;
+ }
+ return true;
}
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index 2e0d4719339..ba7e26e817a 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -21,12 +21,11 @@
* \ingroup bke
*/
-
/**
* variables on the UI for now
* <pre>
* float mediafrict; friction to env
- * float nodemass; softbody mass of *vertex*
+ * float nodemass; softbody mass of *vertex*
* float grav; softbody amount of gravitation to apply
*
* float goalspring; softbody goal springs
@@ -34,12 +33,11 @@
* float mingoal; quick limits for goal
* float maxgoal;
*
- * float inspring; softbody inner springs
+ * float inspring; softbody inner springs
* float infrict; softbody inner springs friction
* </pre>
*/
-
#include <math.h>
#include <stdlib.h>
#include <string.h>
@@ -79,90 +77,86 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
-#include "PIL_time.h"
+#include "PIL_time.h"
static CLG_LogRef LOG = {"bke.softbody"};
/* callbacks for errors and interrupts and some goo */
static int (*SB_localInterruptCallBack)(void) = NULL;
-
/* ********** soft body engine ******* */
-typedef enum {SB_EDGE=1, SB_BEND=2, SB_STIFFQUAD=3, SB_HANDLE=4} type_spring;
+typedef enum { SB_EDGE = 1, SB_BEND = 2, SB_STIFFQUAD = 3, SB_HANDLE = 4 } type_spring;
typedef struct BodySpring {
- int v1, v2;
- float len, cf, load;
- float ext_force[3]; /* edges colliding and sailing */
- type_spring springtype;
- short flag;
+ int v1, v2;
+ float len, cf, load;
+ float ext_force[3]; /* edges colliding and sailing */
+ type_spring springtype;
+ short flag;
} BodySpring;
typedef struct BodyFace {
- int v1, v2, v3;
- float ext_force[3]; /* faces colliding */
- short flag;
+ int v1, v2, v3;
+ float ext_force[3]; /* faces colliding */
+ short flag;
} BodyFace;
typedef struct ReferenceVert {
- float pos[3]; /* position relative to com */
- float mass; /* node mass */
+ float pos[3]; /* position relative to com */
+ float mass; /* node mass */
} ReferenceVert;
typedef struct ReferenceState {
- float com[3]; /* center of mass*/
- ReferenceVert *ivert; /* list of initial values */
+ float com[3]; /* center of mass*/
+ ReferenceVert *ivert; /* list of initial values */
} ReferenceState;
-
/*private scratch pad for caching and other data only needed when alive*/
typedef struct SBScratch {
- GHash *colliderhash;
- short needstobuildcollider;
- short flag;
- BodyFace *bodyface;
- int totface;
- float aabbmin[3], aabbmax[3];
- ReferenceState Ref;
+ GHash *colliderhash;
+ short needstobuildcollider;
+ short flag;
+ BodyFace *bodyface;
+ int totface;
+ float aabbmin[3], aabbmax[3];
+ ReferenceState Ref;
} SBScratch;
-typedef struct SB_thread_context {
- Scene *scene;
- Object *ob;
- float forcetime;
- float timenow;
- int ifirst;
- int ilast;
- ListBase *effectors;
- int do_deflector;
- float fieldfactor;
- float windfactor;
- int nr;
- int tot;
+typedef struct SB_thread_context {
+ Scene *scene;
+ Object *ob;
+ float forcetime;
+ float timenow;
+ int ifirst;
+ int ilast;
+ ListBase *effectors;
+ int do_deflector;
+ float fieldfactor;
+ float windfactor;
+ int nr;
+ int tot;
} SB_thread_context;
#define MID_PRESERVE 1
-#define SOFTGOALSNAP 0.999f
+#define SOFTGOALSNAP 0.999f
/* if bp-> goal is above make it a *forced follow original* and skip all ODE stuff for this bp
* removes *unnecessary* stiffness from ODE system
*/
#define HEUNWARNLIMIT 1 /* 500 would be fine i think for detecting severe *stiff* stuff */
-
-#define BSF_INTERSECT 1 /* edge intersects collider face */
+#define BSF_INTERSECT 1 /* edge intersects collider face */
/* private definitions for bodypoint states */
-#define SBF_DOFUZZY 1 /* Bodypoint do fuzzy */
-#define SBF_OUTOFCOLLISION 2 /* Bodypoint does not collide */
-
-
-#define BFF_INTERSECT 1 /* collider edge intrudes face */
-#define BFF_CLOSEVERT 2 /* collider vertex repulses face */
+#define SBF_DOFUZZY 1 /* Bodypoint do fuzzy */
+#define SBF_OUTOFCOLLISION 2 /* Bodypoint does not collide */
+#define BFF_INTERSECT 1 /* collider edge intrudes face */
+#define BFF_CLOSEVERT 2 /* collider vertex repulses face */
-static float SoftHeunTol = 1.0f; /* humm .. this should be calculated from sb parameters and sizes */
+static float SoftHeunTol =
+ 1.0f; /* humm .. this should be calculated from sb parameters and sizes */
/* local prototypes */
static void free_softbody_intern(SoftBody *sb);
@@ -176,7 +170,7 @@ static float sb_grav_force_scale(Object *UNUSED(ob))
* put it to a function here, so we can add user options later without touching simulation code
*/
{
- return (0.001f);
+ return (0.001f);
}
static float sb_fric_force_scale(Object *UNUSED(ob))
@@ -184,27 +178,27 @@ static float sb_fric_force_scale(Object *UNUSED(ob))
* put it to a function here, so we can add user options later without touching simulation code
*/
{
- return (0.01f);
+ return (0.01f);
}
static float sb_time_scale(Object *ob)
/* defining the frames to *real* time relation */
{
- SoftBody *sb= ob->soft; /* is supposed to be there */
- if (sb) {
- return(sb->physics_speed);
- /* hrms .. this could be IPO as well :)
- * estimated range [0.001 sluggish slug - 100.0 very fast (i hope ODE solver can handle that)]
- * 1 approx = a unit 1 pendulum at g = 9.8 [earth conditions] has period 65 frames
- * theory would give a 50 frames period .. so there must be something inaccurate .. looking for that (BM)
- */
- }
- return (1.0f);
- /*
- * this would be frames/sec independent timing assuming 25 fps is default
- * but does not work very well with NLA
- * return (25.0f/scene->r.frs_sec)
- */
+ SoftBody *sb = ob->soft; /* is supposed to be there */
+ if (sb) {
+ return (sb->physics_speed);
+ /* hrms .. this could be IPO as well :)
+ * estimated range [0.001 sluggish slug - 100.0 very fast (i hope ODE solver can handle that)]
+ * 1 approx = a unit 1 pendulum at g = 9.8 [earth conditions] has period 65 frames
+ * theory would give a 50 frames period .. so there must be something inaccurate .. looking for that (BM)
+ */
+ }
+ return (1.0f);
+ /*
+ * this would be frames/sec independent timing assuming 25 fps is default
+ * but does not work very well with NLA
+ * return (25.0f/scene->r.frs_sec)
+ */
}
/*--- frame based timing ---*/
@@ -218,33 +212,35 @@ static float sb_time_scale(Object *ob)
*/
/* animate sb->maxgoal, sb->mingoal */
-static float _final_goal(Object *ob, BodyPoint *bp)/*jow_go_for2_5 */
-{
- float f = -1999.99f;
- if (ob) {
- SoftBody *sb= ob->soft; /* is supposed to be there */
- if (!(ob->softflag & OB_SB_GOAL)) return (0.0f);
- if (sb&&bp) {
- if (bp->goal < 0.0f) return (0.0f);
- f = sb->mingoal + bp->goal * fabsf(sb->maxgoal - sb->mingoal);
- f = pow(f, 4.0f);
- return (f);
- }
- }
- CLOG_ERROR(&LOG, "sb or bp == NULL");
- return f; /*using crude but spot able values some times helps debuggin */
+static float _final_goal(Object *ob, BodyPoint *bp) /*jow_go_for2_5 */
+{
+ float f = -1999.99f;
+ if (ob) {
+ SoftBody *sb = ob->soft; /* is supposed to be there */
+ if (!(ob->softflag & OB_SB_GOAL))
+ return (0.0f);
+ if (sb && bp) {
+ if (bp->goal < 0.0f)
+ return (0.0f);
+ f = sb->mingoal + bp->goal * fabsf(sb->maxgoal - sb->mingoal);
+ f = pow(f, 4.0f);
+ return (f);
+ }
+ }
+ CLOG_ERROR(&LOG, "sb or bp == NULL");
+ return f; /*using crude but spot able values some times helps debuggin */
}
static float _final_mass(Object *ob, BodyPoint *bp)
{
- if (ob) {
- SoftBody *sb= ob->soft; /* is supposed to be there */
- if (sb&&bp) {
- return(bp->mass*sb->nodemass);
- }
- }
- CLOG_ERROR(&LOG, "sb or bp == NULL");
- return 1.0f;
+ if (ob) {
+ SoftBody *sb = ob->soft; /* is supposed to be there */
+ if (sb && bp) {
+ return (bp->mass * sb->nodemass);
+ }
+ }
+ CLOG_ERROR(&LOG, "sb or bp == NULL");
+ return 1.0f;
}
/* helper functions for everything is animateble jow_go_for2_5 ------*/
@@ -263,466 +259,472 @@ static float _final_mass(Object *ob, BodyPoint *bp)
static const int CCD_SAVETY = 190561;
typedef struct ccdf_minmax {
- float minx, miny, minz, maxx, maxy, maxz;
+ float minx, miny, minz, maxx, maxy, maxz;
} ccdf_minmax;
-
typedef struct ccd_Mesh {
- int mvert_num, tri_num;
- const MVert *mvert;
- const MVert *mprevvert;
- const MVertTri *tri;
- int savety;
- ccdf_minmax *mima;
- /* Axis Aligned Bounding Box AABB */
- float bbmin[3];
- float bbmax[3];
+ int mvert_num, tri_num;
+ const MVert *mvert;
+ const MVert *mprevvert;
+ const MVertTri *tri;
+ int savety;
+ ccdf_minmax *mima;
+ /* Axis Aligned Bounding Box AABB */
+ float bbmin[3];
+ float bbmax[3];
} ccd_Mesh;
-
static ccd_Mesh *ccd_mesh_make(Object *ob)
{
- CollisionModifierData *cmd;
- ccd_Mesh *pccd_M = NULL;
- ccdf_minmax *mima;
- const MVertTri *vt;
- float hull;
- int i;
-
- cmd =(CollisionModifierData *)modifiers_findByType(ob, eModifierType_Collision);
-
- /* first some paranoia checks */
- if (!cmd) return NULL;
- if (!cmd->mvert_num || !cmd->tri_num) return NULL;
-
- pccd_M = MEM_mallocN(sizeof(ccd_Mesh), "ccd_Mesh");
- pccd_M->mvert_num = cmd->mvert_num;
- pccd_M->tri_num = cmd->tri_num;
- pccd_M->savety = CCD_SAVETY;
- pccd_M->bbmin[0]=pccd_M->bbmin[1]=pccd_M->bbmin[2]=1e30f;
- pccd_M->bbmax[0]=pccd_M->bbmax[1]=pccd_M->bbmax[2]=-1e30f;
- pccd_M->mprevvert=NULL;
-
- /* blow it up with forcefield ranges */
- hull = max_ff(ob->pd->pdef_sbift, ob->pd->pdef_sboft);
-
- /* alloc and copy verts*/
- pccd_M->mvert = MEM_dupallocN(cmd->xnew);
- /* note that xnew coords are already in global space, */
- /* determine the ortho BB */
- for (i = 0; i < pccd_M->mvert_num; i++) {
- const float *v;
-
- /* evaluate limits */
- v = pccd_M->mvert[i].co;
- pccd_M->bbmin[0] = min_ff(pccd_M->bbmin[0], v[0] - hull);
- pccd_M->bbmin[1] = min_ff(pccd_M->bbmin[1], v[1] - hull);
- pccd_M->bbmin[2] = min_ff(pccd_M->bbmin[2], v[2] - hull);
-
- pccd_M->bbmax[0] = max_ff(pccd_M->bbmax[0], v[0] + hull);
- pccd_M->bbmax[1] = max_ff(pccd_M->bbmax[1], v[1] + hull);
- pccd_M->bbmax[2] = max_ff(pccd_M->bbmax[2], v[2] + hull);
-
- }
- /* alloc and copy faces*/
- pccd_M->tri = MEM_dupallocN(cmd->tri);
-
- /* OBBs for idea1 */
- pccd_M->mima = MEM_mallocN(sizeof(ccdf_minmax) * pccd_M->tri_num, "ccd_Mesh_Faces_mima");
-
-
- /* anyhoo we need to walk the list of faces and find OBB they live in */
- for (i = 0, mima = pccd_M->mima, vt = pccd_M->tri; i < pccd_M->tri_num; i++, mima++, vt++) {
- const float *v;
-
- mima->minx=mima->miny=mima->minz=1e30f;
- mima->maxx=mima->maxy=mima->maxz=-1e30f;
-
- v = pccd_M->mvert[vt->tri[0]].co;
- mima->minx = min_ff(mima->minx, v[0] - hull);
- mima->miny = min_ff(mima->miny, v[1] - hull);
- mima->minz = min_ff(mima->minz, v[2] - hull);
- mima->maxx = max_ff(mima->maxx, v[0] + hull);
- mima->maxy = max_ff(mima->maxy, v[1] + hull);
- mima->maxz = max_ff(mima->maxz, v[2] + hull);
-
- v = pccd_M->mvert[vt->tri[1]].co;
- mima->minx = min_ff(mima->minx, v[0] - hull);
- mima->miny = min_ff(mima->miny, v[1] - hull);
- mima->minz = min_ff(mima->minz, v[2] - hull);
- mima->maxx = max_ff(mima->maxx, v[0] + hull);
- mima->maxy = max_ff(mima->maxy, v[1] + hull);
- mima->maxz = max_ff(mima->maxz, v[2] + hull);
-
- v = pccd_M->mvert[vt->tri[2]].co;
- mima->minx = min_ff(mima->minx, v[0] - hull);
- mima->miny = min_ff(mima->miny, v[1] - hull);
- mima->minz = min_ff(mima->minz, v[2] - hull);
- mima->maxx = max_ff(mima->maxx, v[0] + hull);
- mima->maxy = max_ff(mima->maxy, v[1] + hull);
- mima->maxz = max_ff(mima->maxz, v[2] + hull);
- }
-
- return pccd_M;
+ CollisionModifierData *cmd;
+ ccd_Mesh *pccd_M = NULL;
+ ccdf_minmax *mima;
+ const MVertTri *vt;
+ float hull;
+ int i;
+
+ cmd = (CollisionModifierData *)modifiers_findByType(ob, eModifierType_Collision);
+
+ /* first some paranoia checks */
+ if (!cmd)
+ return NULL;
+ if (!cmd->mvert_num || !cmd->tri_num)
+ return NULL;
+
+ pccd_M = MEM_mallocN(sizeof(ccd_Mesh), "ccd_Mesh");
+ pccd_M->mvert_num = cmd->mvert_num;
+ pccd_M->tri_num = cmd->tri_num;
+ pccd_M->savety = CCD_SAVETY;
+ pccd_M->bbmin[0] = pccd_M->bbmin[1] = pccd_M->bbmin[2] = 1e30f;
+ pccd_M->bbmax[0] = pccd_M->bbmax[1] = pccd_M->bbmax[2] = -1e30f;
+ pccd_M->mprevvert = NULL;
+
+ /* blow it up with forcefield ranges */
+ hull = max_ff(ob->pd->pdef_sbift, ob->pd->pdef_sboft);
+
+ /* alloc and copy verts*/
+ pccd_M->mvert = MEM_dupallocN(cmd->xnew);
+ /* note that xnew coords are already in global space, */
+ /* determine the ortho BB */
+ for (i = 0; i < pccd_M->mvert_num; i++) {
+ const float *v;
+
+ /* evaluate limits */
+ v = pccd_M->mvert[i].co;
+ pccd_M->bbmin[0] = min_ff(pccd_M->bbmin[0], v[0] - hull);
+ pccd_M->bbmin[1] = min_ff(pccd_M->bbmin[1], v[1] - hull);
+ pccd_M->bbmin[2] = min_ff(pccd_M->bbmin[2], v[2] - hull);
+
+ pccd_M->bbmax[0] = max_ff(pccd_M->bbmax[0], v[0] + hull);
+ pccd_M->bbmax[1] = max_ff(pccd_M->bbmax[1], v[1] + hull);
+ pccd_M->bbmax[2] = max_ff(pccd_M->bbmax[2], v[2] + hull);
+ }
+ /* alloc and copy faces*/
+ pccd_M->tri = MEM_dupallocN(cmd->tri);
+
+ /* OBBs for idea1 */
+ pccd_M->mima = MEM_mallocN(sizeof(ccdf_minmax) * pccd_M->tri_num, "ccd_Mesh_Faces_mima");
+
+ /* anyhoo we need to walk the list of faces and find OBB they live in */
+ for (i = 0, mima = pccd_M->mima, vt = pccd_M->tri; i < pccd_M->tri_num; i++, mima++, vt++) {
+ const float *v;
+
+ mima->minx = mima->miny = mima->minz = 1e30f;
+ mima->maxx = mima->maxy = mima->maxz = -1e30f;
+
+ v = pccd_M->mvert[vt->tri[0]].co;
+ mima->minx = min_ff(mima->minx, v[0] - hull);
+ mima->miny = min_ff(mima->miny, v[1] - hull);
+ mima->minz = min_ff(mima->minz, v[2] - hull);
+ mima->maxx = max_ff(mima->maxx, v[0] + hull);
+ mima->maxy = max_ff(mima->maxy, v[1] + hull);
+ mima->maxz = max_ff(mima->maxz, v[2] + hull);
+
+ v = pccd_M->mvert[vt->tri[1]].co;
+ mima->minx = min_ff(mima->minx, v[0] - hull);
+ mima->miny = min_ff(mima->miny, v[1] - hull);
+ mima->minz = min_ff(mima->minz, v[2] - hull);
+ mima->maxx = max_ff(mima->maxx, v[0] + hull);
+ mima->maxy = max_ff(mima->maxy, v[1] + hull);
+ mima->maxz = max_ff(mima->maxz, v[2] + hull);
+
+ v = pccd_M->mvert[vt->tri[2]].co;
+ mima->minx = min_ff(mima->minx, v[0] - hull);
+ mima->miny = min_ff(mima->miny, v[1] - hull);
+ mima->minz = min_ff(mima->minz, v[2] - hull);
+ mima->maxx = max_ff(mima->maxx, v[0] + hull);
+ mima->maxy = max_ff(mima->maxy, v[1] + hull);
+ mima->maxz = max_ff(mima->maxz, v[2] + hull);
+ }
+
+ return pccd_M;
}
static void ccd_mesh_update(Object *ob, ccd_Mesh *pccd_M)
{
- CollisionModifierData *cmd;
- ccdf_minmax *mima;
- const MVertTri *vt;
- float hull;
- int i;
-
- cmd =(CollisionModifierData *)modifiers_findByType(ob, eModifierType_Collision);
-
- /* first some paranoia checks */
- if (!cmd) return;
- if (!cmd->mvert_num || !cmd->tri_num) return;
-
- if ((pccd_M->mvert_num != cmd->mvert_num) ||
- (pccd_M->tri_num != cmd->tri_num))
- {
- return;
- }
-
- pccd_M->bbmin[0]=pccd_M->bbmin[1]=pccd_M->bbmin[2]=1e30f;
- pccd_M->bbmax[0]=pccd_M->bbmax[1]=pccd_M->bbmax[2]=-1e30f;
-
-
- /* blow it up with forcefield ranges */
- hull = max_ff(ob->pd->pdef_sbift, ob->pd->pdef_sboft);
-
- /* rotate current to previous */
- if (pccd_M->mprevvert) MEM_freeN((void *)pccd_M->mprevvert);
- pccd_M->mprevvert = pccd_M->mvert;
- /* alloc and copy verts*/
- pccd_M->mvert = MEM_dupallocN(cmd->xnew);
- /* note that xnew coords are already in global space, */
- /* determine the ortho BB */
- for (i=0; i < pccd_M->mvert_num; i++) {
- const float *v;
-
- /* evaluate limits */
- v = pccd_M->mvert[i].co;
- pccd_M->bbmin[0] = min_ff(pccd_M->bbmin[0], v[0] - hull);
- pccd_M->bbmin[1] = min_ff(pccd_M->bbmin[1], v[1] - hull);
- pccd_M->bbmin[2] = min_ff(pccd_M->bbmin[2], v[2] - hull);
-
- pccd_M->bbmax[0] = max_ff(pccd_M->bbmax[0], v[0] + hull);
- pccd_M->bbmax[1] = max_ff(pccd_M->bbmax[1], v[1] + hull);
- pccd_M->bbmax[2] = max_ff(pccd_M->bbmax[2], v[2] + hull);
-
- /* evaluate limits */
- v = pccd_M->mprevvert[i].co;
- pccd_M->bbmin[0] = min_ff(pccd_M->bbmin[0], v[0] - hull);
- pccd_M->bbmin[1] = min_ff(pccd_M->bbmin[1], v[1] - hull);
- pccd_M->bbmin[2] = min_ff(pccd_M->bbmin[2], v[2] - hull);
-
- pccd_M->bbmax[0] = max_ff(pccd_M->bbmax[0], v[0] + hull);
- pccd_M->bbmax[1] = max_ff(pccd_M->bbmax[1], v[1] + hull);
- pccd_M->bbmax[2] = max_ff(pccd_M->bbmax[2], v[2] + hull);
-
- }
-
- /* anyhoo we need to walk the list of faces and find OBB they live in */
- for (i = 0, mima = pccd_M->mima, vt = pccd_M->tri; i < pccd_M->tri_num; i++, mima++, vt++) {
- const float *v;
-
- mima->minx=mima->miny=mima->minz=1e30f;
- mima->maxx=mima->maxy=mima->maxz=-1e30f;
-
- /* mvert */
- v = pccd_M->mvert[vt->tri[0]].co;
- mima->minx = min_ff(mima->minx, v[0] - hull);
- mima->miny = min_ff(mima->miny, v[1] - hull);
- mima->minz = min_ff(mima->minz, v[2] - hull);
- mima->maxx = max_ff(mima->maxx, v[0] + hull);
- mima->maxy = max_ff(mima->maxy, v[1] + hull);
- mima->maxz = max_ff(mima->maxz, v[2] + hull);
-
- v = pccd_M->mvert[vt->tri[1]].co;
- mima->minx = min_ff(mima->minx, v[0] - hull);
- mima->miny = min_ff(mima->miny, v[1] - hull);
- mima->minz = min_ff(mima->minz, v[2] - hull);
- mima->maxx = max_ff(mima->maxx, v[0] + hull);
- mima->maxy = max_ff(mima->maxy, v[1] + hull);
- mima->maxz = max_ff(mima->maxz, v[2] + hull);
-
- v = pccd_M->mvert[vt->tri[2]].co;
- mima->minx = min_ff(mima->minx, v[0] - hull);
- mima->miny = min_ff(mima->miny, v[1] - hull);
- mima->minz = min_ff(mima->minz, v[2] - hull);
- mima->maxx = max_ff(mima->maxx, v[0] + hull);
- mima->maxy = max_ff(mima->maxy, v[1] + hull);
- mima->maxz = max_ff(mima->maxz, v[2] + hull);
-
-
- /* mprevvert */
- v = pccd_M->mprevvert[vt->tri[0]].co;
- mima->minx = min_ff(mima->minx, v[0] - hull);
- mima->miny = min_ff(mima->miny, v[1] - hull);
- mima->minz = min_ff(mima->minz, v[2] - hull);
- mima->maxx = max_ff(mima->maxx, v[0] + hull);
- mima->maxy = max_ff(mima->maxy, v[1] + hull);
- mima->maxz = max_ff(mima->maxz, v[2] + hull);
-
- v = pccd_M->mprevvert[vt->tri[1]].co;
- mima->minx = min_ff(mima->minx, v[0] - hull);
- mima->miny = min_ff(mima->miny, v[1] - hull);
- mima->minz = min_ff(mima->minz, v[2] - hull);
- mima->maxx = max_ff(mima->maxx, v[0] + hull);
- mima->maxy = max_ff(mima->maxy, v[1] + hull);
- mima->maxz = max_ff(mima->maxz, v[2] + hull);
-
- v = pccd_M->mprevvert[vt->tri[2]].co;
- mima->minx = min_ff(mima->minx, v[0] - hull);
- mima->miny = min_ff(mima->miny, v[1] - hull);
- mima->minz = min_ff(mima->minz, v[2] - hull);
- mima->maxx = max_ff(mima->maxx, v[0] + hull);
- mima->maxy = max_ff(mima->maxy, v[1] + hull);
- mima->maxz = max_ff(mima->maxz, v[2] + hull);
- }
- return;
+ CollisionModifierData *cmd;
+ ccdf_minmax *mima;
+ const MVertTri *vt;
+ float hull;
+ int i;
+
+ cmd = (CollisionModifierData *)modifiers_findByType(ob, eModifierType_Collision);
+
+ /* first some paranoia checks */
+ if (!cmd)
+ return;
+ if (!cmd->mvert_num || !cmd->tri_num)
+ return;
+
+ if ((pccd_M->mvert_num != cmd->mvert_num) || (pccd_M->tri_num != cmd->tri_num)) {
+ return;
+ }
+
+ pccd_M->bbmin[0] = pccd_M->bbmin[1] = pccd_M->bbmin[2] = 1e30f;
+ pccd_M->bbmax[0] = pccd_M->bbmax[1] = pccd_M->bbmax[2] = -1e30f;
+
+ /* blow it up with forcefield ranges */
+ hull = max_ff(ob->pd->pdef_sbift, ob->pd->pdef_sboft);
+
+ /* rotate current to previous */
+ if (pccd_M->mprevvert)
+ MEM_freeN((void *)pccd_M->mprevvert);
+ pccd_M->mprevvert = pccd_M->mvert;
+ /* alloc and copy verts*/
+ pccd_M->mvert = MEM_dupallocN(cmd->xnew);
+ /* note that xnew coords are already in global space, */
+ /* determine the ortho BB */
+ for (i = 0; i < pccd_M->mvert_num; i++) {
+ const float *v;
+
+ /* evaluate limits */
+ v = pccd_M->mvert[i].co;
+ pccd_M->bbmin[0] = min_ff(pccd_M->bbmin[0], v[0] - hull);
+ pccd_M->bbmin[1] = min_ff(pccd_M->bbmin[1], v[1] - hull);
+ pccd_M->bbmin[2] = min_ff(pccd_M->bbmin[2], v[2] - hull);
+
+ pccd_M->bbmax[0] = max_ff(pccd_M->bbmax[0], v[0] + hull);
+ pccd_M->bbmax[1] = max_ff(pccd_M->bbmax[1], v[1] + hull);
+ pccd_M->bbmax[2] = max_ff(pccd_M->bbmax[2], v[2] + hull);
+
+ /* evaluate limits */
+ v = pccd_M->mprevvert[i].co;
+ pccd_M->bbmin[0] = min_ff(pccd_M->bbmin[0], v[0] - hull);
+ pccd_M->bbmin[1] = min_ff(pccd_M->bbmin[1], v[1] - hull);
+ pccd_M->bbmin[2] = min_ff(pccd_M->bbmin[2], v[2] - hull);
+
+ pccd_M->bbmax[0] = max_ff(pccd_M->bbmax[0], v[0] + hull);
+ pccd_M->bbmax[1] = max_ff(pccd_M->bbmax[1], v[1] + hull);
+ pccd_M->bbmax[2] = max_ff(pccd_M->bbmax[2], v[2] + hull);
+ }
+
+ /* anyhoo we need to walk the list of faces and find OBB they live in */
+ for (i = 0, mima = pccd_M->mima, vt = pccd_M->tri; i < pccd_M->tri_num; i++, mima++, vt++) {
+ const float *v;
+
+ mima->minx = mima->miny = mima->minz = 1e30f;
+ mima->maxx = mima->maxy = mima->maxz = -1e30f;
+
+ /* mvert */
+ v = pccd_M->mvert[vt->tri[0]].co;
+ mima->minx = min_ff(mima->minx, v[0] - hull);
+ mima->miny = min_ff(mima->miny, v[1] - hull);
+ mima->minz = min_ff(mima->minz, v[2] - hull);
+ mima->maxx = max_ff(mima->maxx, v[0] + hull);
+ mima->maxy = max_ff(mima->maxy, v[1] + hull);
+ mima->maxz = max_ff(mima->maxz, v[2] + hull);
+
+ v = pccd_M->mvert[vt->tri[1]].co;
+ mima->minx = min_ff(mima->minx, v[0] - hull);
+ mima->miny = min_ff(mima->miny, v[1] - hull);
+ mima->minz = min_ff(mima->minz, v[2] - hull);
+ mima->maxx = max_ff(mima->maxx, v[0] + hull);
+ mima->maxy = max_ff(mima->maxy, v[1] + hull);
+ mima->maxz = max_ff(mima->maxz, v[2] + hull);
+
+ v = pccd_M->mvert[vt->tri[2]].co;
+ mima->minx = min_ff(mima->minx, v[0] - hull);
+ mima->miny = min_ff(mima->miny, v[1] - hull);
+ mima->minz = min_ff(mima->minz, v[2] - hull);
+ mima->maxx = max_ff(mima->maxx, v[0] + hull);
+ mima->maxy = max_ff(mima->maxy, v[1] + hull);
+ mima->maxz = max_ff(mima->maxz, v[2] + hull);
+
+ /* mprevvert */
+ v = pccd_M->mprevvert[vt->tri[0]].co;
+ mima->minx = min_ff(mima->minx, v[0] - hull);
+ mima->miny = min_ff(mima->miny, v[1] - hull);
+ mima->minz = min_ff(mima->minz, v[2] - hull);
+ mima->maxx = max_ff(mima->maxx, v[0] + hull);
+ mima->maxy = max_ff(mima->maxy, v[1] + hull);
+ mima->maxz = max_ff(mima->maxz, v[2] + hull);
+
+ v = pccd_M->mprevvert[vt->tri[1]].co;
+ mima->minx = min_ff(mima->minx, v[0] - hull);
+ mima->miny = min_ff(mima->miny, v[1] - hull);
+ mima->minz = min_ff(mima->minz, v[2] - hull);
+ mima->maxx = max_ff(mima->maxx, v[0] + hull);
+ mima->maxy = max_ff(mima->maxy, v[1] + hull);
+ mima->maxz = max_ff(mima->maxz, v[2] + hull);
+
+ v = pccd_M->mprevvert[vt->tri[2]].co;
+ mima->minx = min_ff(mima->minx, v[0] - hull);
+ mima->miny = min_ff(mima->miny, v[1] - hull);
+ mima->minz = min_ff(mima->minz, v[2] - hull);
+ mima->maxx = max_ff(mima->maxx, v[0] + hull);
+ mima->maxy = max_ff(mima->maxy, v[1] + hull);
+ mima->maxz = max_ff(mima->maxz, v[2] + hull);
+ }
+ return;
}
static void ccd_mesh_free(ccd_Mesh *ccdm)
{
- if (ccdm && (ccdm->savety == CCD_SAVETY )) { /*make sure we're not nuking objects we don't know*/
- MEM_freeN((void *)ccdm->mvert);
- MEM_freeN((void *)ccdm->tri);
- if (ccdm->mprevvert) MEM_freeN((void *)ccdm->mprevvert);
- MEM_freeN(ccdm->mima);
- MEM_freeN(ccdm);
- ccdm = NULL;
- }
+ if (ccdm && (ccdm->savety == CCD_SAVETY)) { /*make sure we're not nuking objects we don't know*/
+ MEM_freeN((void *)ccdm->mvert);
+ MEM_freeN((void *)ccdm->tri);
+ if (ccdm->mprevvert)
+ MEM_freeN((void *)ccdm->mprevvert);
+ MEM_freeN(ccdm->mima);
+ MEM_freeN(ccdm);
+ ccdm = NULL;
+ }
}
static void ccd_build_deflector_hash_single(GHash *hash, Object *ob)
{
- /* only with deflecting set */
- if (ob->pd && ob->pd->deflect) {
- void **val_p;
- if (!BLI_ghash_ensure_p(hash, ob, &val_p)) {
- ccd_Mesh *ccdmesh = ccd_mesh_make(ob);
- *val_p = ccdmesh;
- }
- }
+ /* only with deflecting set */
+ if (ob->pd && ob->pd->deflect) {
+ void **val_p;
+ if (!BLI_ghash_ensure_p(hash, ob, &val_p)) {
+ ccd_Mesh *ccdmesh = ccd_mesh_make(ob);
+ *val_p = ccdmesh;
+ }
+ }
}
/**
* \note collection overrides scene when not NULL.
*/
-static void ccd_build_deflector_hash(Depsgraph *depsgraph, Collection *collection, Object *vertexowner, GHash *hash)
+static void ccd_build_deflector_hash(Depsgraph *depsgraph,
+ Collection *collection,
+ Object *vertexowner,
+ GHash *hash)
{
- if (!hash) return;
+ if (!hash)
+ return;
- unsigned int numobjects;
- Object **objects = BKE_collision_objects_create(depsgraph, vertexowner, collection, &numobjects, eModifierType_Collision);
+ unsigned int numobjects;
+ Object **objects = BKE_collision_objects_create(
+ depsgraph, vertexowner, collection, &numobjects, eModifierType_Collision);
- for (int i = 0; i < numobjects; i++) {
- Object *ob = objects[i];
+ for (int i = 0; i < numobjects; i++) {
+ Object *ob = objects[i];
- if (ob->type == OB_MESH) {
- ccd_build_deflector_hash_single(hash, ob);
- }
- }
+ if (ob->type == OB_MESH) {
+ ccd_build_deflector_hash_single(hash, ob);
+ }
+ }
- BKE_collision_objects_free(objects);
+ BKE_collision_objects_free(objects);
}
static void ccd_update_deflector_hash_single(GHash *hash, Object *ob)
{
- if (ob->pd && ob->pd->deflect) {
- ccd_Mesh *ccdmesh = BLI_ghash_lookup(hash, ob);
- if (ccdmesh) {
- ccd_mesh_update(ob, ccdmesh);
- }
- }
+ if (ob->pd && ob->pd->deflect) {
+ ccd_Mesh *ccdmesh = BLI_ghash_lookup(hash, ob);
+ if (ccdmesh) {
+ ccd_mesh_update(ob, ccdmesh);
+ }
+ }
}
/**
* \note collection overrides scene when not NULL.
*/
-static void ccd_update_deflector_hash(Depsgraph *depsgraph, Collection *collection, Object *vertexowner, GHash *hash)
+static void ccd_update_deflector_hash(Depsgraph *depsgraph,
+ Collection *collection,
+ Object *vertexowner,
+ GHash *hash)
{
- if ((!hash) || (!vertexowner)) return;
+ if ((!hash) || (!vertexowner))
+ return;
- unsigned int numobjects;
- Object **objects = BKE_collision_objects_create(depsgraph, vertexowner, collection, &numobjects, eModifierType_Collision);
+ unsigned int numobjects;
+ Object **objects = BKE_collision_objects_create(
+ depsgraph, vertexowner, collection, &numobjects, eModifierType_Collision);
- for (int i = 0; i < numobjects; i++) {
- Object *ob = objects[i];
+ for (int i = 0; i < numobjects; i++) {
+ Object *ob = objects[i];
- if (ob->type == OB_MESH) {
- ccd_update_deflector_hash_single(hash, ob);
- }
- }
+ if (ob->type == OB_MESH) {
+ ccd_update_deflector_hash_single(hash, ob);
+ }
+ }
- BKE_collision_objects_free(objects);
+ BKE_collision_objects_free(objects);
}
/*--- collider caching and dicing ---*/
-
static int count_mesh_quads(Mesh *me)
{
- int a, result = 0;
- const MPoly *mp = me->mpoly;
+ int a, result = 0;
+ const MPoly *mp = me->mpoly;
- if (mp) {
- for (a = me->totpoly; a > 0; a--, mp++) {
- if (mp->totloop == 4) {
- result++;
- }
- }
- }
- return result;
+ if (mp) {
+ for (a = me->totpoly; a > 0; a--, mp++) {
+ if (mp->totloop == 4) {
+ result++;
+ }
+ }
+ }
+ return result;
}
static void add_mesh_quad_diag_springs(Object *ob)
{
- Mesh *me= ob->data;
- /*BodyPoint *bp;*/ /*UNUSED*/
- int a;
-
- if (ob->soft) {
- int nofquads;
- //float s_shear = ob->soft->shearstiff*ob->soft->shearstiff;
-
- nofquads = count_mesh_quads(me);
- if (nofquads) {
- const MLoop *mloop = me->mloop;
- const MPoly *mp = me->mpoly;
- BodySpring *bs;
-
- /* resize spring-array to hold additional quad springs */
- ob->soft->bspring = MEM_recallocN(ob->soft->bspring, sizeof(BodySpring) * (ob->soft->totspring + nofquads * 2));
-
- /* fill the tail */
- a = 0;
- bs = &ob->soft->bspring[ob->soft->totspring];
- /*bp= ob->soft->bpoint; */ /*UNUSED*/
- for (a = me->totpoly; a > 0; a--, mp++) {
- if (mp->totloop == 4) {
- bs->v1 = mloop[mp->loopstart + 0].v;
- bs->v2 = mloop[mp->loopstart + 2].v;
- bs->springtype = SB_STIFFQUAD;
- bs++;
- bs->v1 = mloop[mp->loopstart + 1].v;
- bs->v2 = mloop[mp->loopstart + 3].v;
- bs->springtype = SB_STIFFQUAD;
- bs++;
- }
- }
-
- /* now we can announce new springs */
- ob->soft->totspring += nofquads * 2;
- }
- }
+ Mesh *me = ob->data;
+ /*BodyPoint *bp;*/ /*UNUSED*/
+ int a;
+
+ if (ob->soft) {
+ int nofquads;
+ //float s_shear = ob->soft->shearstiff*ob->soft->shearstiff;
+
+ nofquads = count_mesh_quads(me);
+ if (nofquads) {
+ const MLoop *mloop = me->mloop;
+ const MPoly *mp = me->mpoly;
+ BodySpring *bs;
+
+ /* resize spring-array to hold additional quad springs */
+ ob->soft->bspring = MEM_recallocN(ob->soft->bspring,
+ sizeof(BodySpring) * (ob->soft->totspring + nofquads * 2));
+
+ /* fill the tail */
+ a = 0;
+ bs = &ob->soft->bspring[ob->soft->totspring];
+ /*bp= ob->soft->bpoint; */ /*UNUSED*/
+ for (a = me->totpoly; a > 0; a--, mp++) {
+ if (mp->totloop == 4) {
+ bs->v1 = mloop[mp->loopstart + 0].v;
+ bs->v2 = mloop[mp->loopstart + 2].v;
+ bs->springtype = SB_STIFFQUAD;
+ bs++;
+ bs->v1 = mloop[mp->loopstart + 1].v;
+ bs->v2 = mloop[mp->loopstart + 3].v;
+ bs->springtype = SB_STIFFQUAD;
+ bs++;
+ }
+ }
+
+ /* now we can announce new springs */
+ ob->soft->totspring += nofquads * 2;
+ }
+ }
}
static void add_2nd_order_roller(Object *ob, float UNUSED(stiffness), int *counter, int addsprings)
{
- /*assume we have a softbody*/
- SoftBody *sb= ob->soft; /* is supposed to be there */
- BodyPoint *bp, *bpo;
- BodySpring *bs, *bs2, *bs3= NULL;
- int a, b, c, notthis= 0, v0;
- if (!sb->bspring) {return;} /* we are 2nd order here so 1rst should have been build :) */
- /* first run counting second run adding */
- *counter = 0;
- if (addsprings) bs3 = ob->soft->bspring+ob->soft->totspring;
- for (a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
- /*scan for neighborhood*/
- bpo = NULL;
- v0 = (sb->totpoint-a);
- for (b=bp->nofsprings;b>0;b--) {
- bs = sb->bspring + bp->springs[b-1];
- /*nasty thing here that springs have two ends
- so here we have to make sure we examine the other */
- if (v0 == bs->v1) {
- bpo = sb->bpoint+bs->v2;
- notthis = bs->v2;
- }
- else {
- if (v0 == bs->v2) {
- bpo = sb->bpoint+bs->v1;
- notthis = bs->v1;
- }
- else {
- CLOG_ERROR(&LOG, "oops we should not get here");
- }
- }
- if (bpo) {/* so now we have a 2nd order humpdidump */
- for (c=bpo->nofsprings;c>0;c--) {
- bs2 = sb->bspring + bpo->springs[c-1];
- if ((bs2->v1 != notthis) && (bs2->v1 > v0)) {
- (*counter)++;/*hit */
- if (addsprings) {
- bs3->v1= v0;
- bs3->v2= bs2->v1;
- bs3->springtype = SB_BEND;
- bs3++;
- }
- }
- if ((bs2->v2 !=notthis)&&(bs2->v2 > v0)) {
- (*counter)++; /* hit */
- if (addsprings) {
- bs3->v1= v0;
- bs3->v2= bs2->v2;
- bs3->springtype = SB_BEND;
- bs3++;
- }
-
- }
- }
-
- }
-
- }
- /*scan for neighborhood done*/
- }
+ /*assume we have a softbody*/
+ SoftBody *sb = ob->soft; /* is supposed to be there */
+ BodyPoint *bp, *bpo;
+ BodySpring *bs, *bs2, *bs3 = NULL;
+ int a, b, c, notthis = 0, v0;
+ if (!sb->bspring) {
+ return;
+ } /* we are 2nd order here so 1rst should have been build :) */
+ /* first run counting second run adding */
+ *counter = 0;
+ if (addsprings)
+ bs3 = ob->soft->bspring + ob->soft->totspring;
+ for (a = sb->totpoint, bp = sb->bpoint; a > 0; a--, bp++) {
+ /*scan for neighborhood*/
+ bpo = NULL;
+ v0 = (sb->totpoint - a);
+ for (b = bp->nofsprings; b > 0; b--) {
+ bs = sb->bspring + bp->springs[b - 1];
+ /*nasty thing here that springs have two ends
+ so here we have to make sure we examine the other */
+ if (v0 == bs->v1) {
+ bpo = sb->bpoint + bs->v2;
+ notthis = bs->v2;
+ }
+ else {
+ if (v0 == bs->v2) {
+ bpo = sb->bpoint + bs->v1;
+ notthis = bs->v1;
+ }
+ else {
+ CLOG_ERROR(&LOG, "oops we should not get here");
+ }
+ }
+ if (bpo) { /* so now we have a 2nd order humpdidump */
+ for (c = bpo->nofsprings; c > 0; c--) {
+ bs2 = sb->bspring + bpo->springs[c - 1];
+ if ((bs2->v1 != notthis) && (bs2->v1 > v0)) {
+ (*counter)++; /*hit */
+ if (addsprings) {
+ bs3->v1 = v0;
+ bs3->v2 = bs2->v1;
+ bs3->springtype = SB_BEND;
+ bs3++;
+ }
+ }
+ if ((bs2->v2 != notthis) && (bs2->v2 > v0)) {
+ (*counter)++; /* hit */
+ if (addsprings) {
+ bs3->v1 = v0;
+ bs3->v2 = bs2->v2;
+ bs3->springtype = SB_BEND;
+ bs3++;
+ }
+ }
+ }
+ }
+ }
+ /*scan for neighborhood done*/
+ }
}
-
static void add_2nd_order_springs(Object *ob, float stiffness)
{
- int counter = 0;
- BodySpring *bs_new;
- stiffness *=stiffness;
+ int counter = 0;
+ BodySpring *bs_new;
+ stiffness *= stiffness;
- add_2nd_order_roller(ob, stiffness, &counter, 0); /* counting */
- if (counter) {
- /* resize spring-array to hold additional springs */
- bs_new= MEM_callocN((ob->soft->totspring + counter )*sizeof(BodySpring), "bodyspring");
- memcpy(bs_new, ob->soft->bspring, (ob->soft->totspring )*sizeof(BodySpring));
+ add_2nd_order_roller(ob, stiffness, &counter, 0); /* counting */
+ if (counter) {
+ /* resize spring-array to hold additional springs */
+ bs_new = MEM_callocN((ob->soft->totspring + counter) * sizeof(BodySpring), "bodyspring");
+ memcpy(bs_new, ob->soft->bspring, (ob->soft->totspring) * sizeof(BodySpring));
- if (ob->soft->bspring)
- MEM_freeN(ob->soft->bspring);
- ob->soft->bspring = bs_new;
+ if (ob->soft->bspring)
+ MEM_freeN(ob->soft->bspring);
+ ob->soft->bspring = bs_new;
- add_2nd_order_roller(ob, stiffness, &counter, 1); /* adding */
- ob->soft->totspring += counter;
- }
+ add_2nd_order_roller(ob, stiffness, &counter, 1); /* adding */
+ ob->soft->totspring += counter;
+ }
}
static void add_bp_springlist(BodyPoint *bp, int springID)
{
- int *newlist;
+ int *newlist;
- if (bp->springs == NULL) {
- bp->springs = MEM_callocN(sizeof(int), "bpsprings");
- bp->springs[0] = springID;
- bp->nofsprings = 1;
- }
- else {
- bp->nofsprings++;
- newlist = MEM_callocN(bp->nofsprings * sizeof(int), "bpsprings");
- memcpy(newlist, bp->springs, (bp->nofsprings-1)* sizeof(int));
- MEM_freeN(bp->springs);
- bp->springs = newlist;
- bp->springs[bp->nofsprings-1] = springID;
- }
+ if (bp->springs == NULL) {
+ bp->springs = MEM_callocN(sizeof(int), "bpsprings");
+ bp->springs[0] = springID;
+ bp->nofsprings = 1;
+ }
+ else {
+ bp->nofsprings++;
+ newlist = MEM_callocN(bp->nofsprings * sizeof(int), "bpsprings");
+ memcpy(newlist, bp->springs, (bp->nofsprings - 1) * sizeof(int));
+ MEM_freeN(bp->springs);
+ bp->springs = newlist;
+ bp->springs[bp->nofsprings - 1] = springID;
+ }
}
/**
@@ -731,193 +733,197 @@ static void add_bp_springlist(BodyPoint *bp, int springID)
*/
static void build_bps_springlist(Object *ob)
{
- SoftBody *sb= ob->soft; /* is supposed to be there */
- BodyPoint *bp;
- BodySpring *bs;
- int a, b;
-
- if (sb==NULL) return; /* paranoya check */
-
- for (a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
- /* throw away old list */
- if (bp->springs) {
- MEM_freeN(bp->springs);
- bp->springs=NULL;
- }
- /* scan for attached inner springs */
- for (b=sb->totspring, bs= sb->bspring; b>0; b--, bs++) {
- if (( (sb->totpoint-a) == bs->v1) ) {
- add_bp_springlist(bp, sb->totspring -b);
- }
- if (( (sb->totpoint-a) == bs->v2) ) {
- add_bp_springlist(bp, sb->totspring -b);
- }
- }/*for springs*/
- }/*for bp*/
+ SoftBody *sb = ob->soft; /* is supposed to be there */
+ BodyPoint *bp;
+ BodySpring *bs;
+ int a, b;
+
+ if (sb == NULL)
+ return; /* paranoya check */
+
+ for (a = sb->totpoint, bp = sb->bpoint; a > 0; a--, bp++) {
+ /* throw away old list */
+ if (bp->springs) {
+ MEM_freeN(bp->springs);
+ bp->springs = NULL;
+ }
+ /* scan for attached inner springs */
+ for (b = sb->totspring, bs = sb->bspring; b > 0; b--, bs++) {
+ if (((sb->totpoint - a) == bs->v1)) {
+ add_bp_springlist(bp, sb->totspring - b);
+ }
+ if (((sb->totpoint - a) == bs->v2)) {
+ add_bp_springlist(bp, sb->totspring - b);
+ }
+ } /*for springs*/
+ } /*for bp*/
}
static void calculate_collision_balls(Object *ob)
{
- SoftBody *sb= ob->soft; /* is supposed to be there */
- BodyPoint *bp;
- BodySpring *bs;
- int a, b, akku_count;
- float min, max, akku;
-
- if (sb==NULL) return; /* paranoya check */
-
- for (a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
- bp->colball=0;
- akku =0.0f;
- akku_count=0;
- min = 1e22f;
- max = -1e22f;
- /* first estimation based on attached */
- for (b=bp->nofsprings;b>0;b--) {
- bs = sb->bspring + bp->springs[b-1];
- if (bs->springtype == SB_EDGE) {
- akku += bs->len;
- akku_count++;
- min = min_ff(bs->len, min);
- max = max_ff(bs->len, max);
- }
- }
-
- if (akku_count > 0) {
- if (sb->sbc_mode == SBC_MODE_MANUAL) {
- bp->colball=sb->colball;
- }
- if (sb->sbc_mode == SBC_MODE_AVG) {
- bp->colball = akku/(float)akku_count*sb->colball;
- }
- if (sb->sbc_mode == SBC_MODE_MIN) {
- bp->colball=min*sb->colball;
- }
- if (sb->sbc_mode == SBC_MODE_MAX) {
- bp->colball=max*sb->colball;
- }
- if (sb->sbc_mode == SBC_MODE_AVGMINMAX) {
- bp->colball = (min + max)/2.0f*sb->colball;
- }
- }
- else bp->colball=0;
- }/*for bp*/
+ SoftBody *sb = ob->soft; /* is supposed to be there */
+ BodyPoint *bp;
+ BodySpring *bs;
+ int a, b, akku_count;
+ float min, max, akku;
+
+ if (sb == NULL)
+ return; /* paranoya check */
+
+ for (a = sb->totpoint, bp = sb->bpoint; a > 0; a--, bp++) {
+ bp->colball = 0;
+ akku = 0.0f;
+ akku_count = 0;
+ min = 1e22f;
+ max = -1e22f;
+ /* first estimation based on attached */
+ for (b = bp->nofsprings; b > 0; b--) {
+ bs = sb->bspring + bp->springs[b - 1];
+ if (bs->springtype == SB_EDGE) {
+ akku += bs->len;
+ akku_count++;
+ min = min_ff(bs->len, min);
+ max = max_ff(bs->len, max);
+ }
+ }
+
+ if (akku_count > 0) {
+ if (sb->sbc_mode == SBC_MODE_MANUAL) {
+ bp->colball = sb->colball;
+ }
+ if (sb->sbc_mode == SBC_MODE_AVG) {
+ bp->colball = akku / (float)akku_count * sb->colball;
+ }
+ if (sb->sbc_mode == SBC_MODE_MIN) {
+ bp->colball = min * sb->colball;
+ }
+ if (sb->sbc_mode == SBC_MODE_MAX) {
+ bp->colball = max * sb->colball;
+ }
+ if (sb->sbc_mode == SBC_MODE_AVGMINMAX) {
+ bp->colball = (min + max) / 2.0f * sb->colball;
+ }
+ }
+ else
+ bp->colball = 0;
+ } /*for bp*/
}
-
/* creates new softbody if didn't exist yet, makes new points and springs arrays */
static void renew_softbody(Scene *scene, Object *ob, int totpoint, int totspring)
{
- SoftBody *sb;
- int i;
- short softflag;
- if (ob->soft==NULL) ob->soft= sbNew(scene);
- else free_softbody_intern(ob->soft);
- sb= ob->soft;
- softflag=ob->softflag;
-
- if (totpoint) {
- sb->totpoint= totpoint;
- sb->totspring= totspring;
-
- sb->bpoint= MEM_mallocN(totpoint*sizeof(BodyPoint), "bodypoint");
- if (totspring)
- sb->bspring= MEM_mallocN(totspring*sizeof(BodySpring), "bodyspring");
-
- /* initialize BodyPoint array */
- for (i=0; i<totpoint; i++) {
- BodyPoint *bp = &sb->bpoint[i];
-
-
- /* hum as far as i see this is overridden by _final_goal() now jow_go_for2_5 */
- /* sadly breaks compatibility with older versions */
- /* but makes goals behave the same for meshes, lattices and curves */
- if (softflag & OB_SB_GOAL) {
- bp->goal= sb->defgoal;
- }
- else {
- bp->goal= 0.0f;
- /* so this will definily be below SOFTGOALSNAP */
- }
-
- bp->nofsprings= 0;
- bp->springs= NULL;
- bp->choke = 0.0f;
- bp->choke2 = 0.0f;
- bp->frozen = 1.0f;
- bp->colball = 0.0f;
- bp->loc_flag = 0;
- bp->springweight = 1.0f;
- bp->mass = 1.0f;
- }
- }
+ SoftBody *sb;
+ int i;
+ short softflag;
+ if (ob->soft == NULL)
+ ob->soft = sbNew(scene);
+ else
+ free_softbody_intern(ob->soft);
+ sb = ob->soft;
+ softflag = ob->softflag;
+
+ if (totpoint) {
+ sb->totpoint = totpoint;
+ sb->totspring = totspring;
+
+ sb->bpoint = MEM_mallocN(totpoint * sizeof(BodyPoint), "bodypoint");
+ if (totspring)
+ sb->bspring = MEM_mallocN(totspring * sizeof(BodySpring), "bodyspring");
+
+ /* initialize BodyPoint array */
+ for (i = 0; i < totpoint; i++) {
+ BodyPoint *bp = &sb->bpoint[i];
+
+ /* hum as far as i see this is overridden by _final_goal() now jow_go_for2_5 */
+ /* sadly breaks compatibility with older versions */
+ /* but makes goals behave the same for meshes, lattices and curves */
+ if (softflag & OB_SB_GOAL) {
+ bp->goal = sb->defgoal;
+ }
+ else {
+ bp->goal = 0.0f;
+ /* so this will definily be below SOFTGOALSNAP */
+ }
+
+ bp->nofsprings = 0;
+ bp->springs = NULL;
+ bp->choke = 0.0f;
+ bp->choke2 = 0.0f;
+ bp->frozen = 1.0f;
+ bp->colball = 0.0f;
+ bp->loc_flag = 0;
+ bp->springweight = 1.0f;
+ bp->mass = 1.0f;
+ }
+ }
}
static void free_softbody_baked(SoftBody *sb)
{
- SBVertex *key;
- int k;
+ SBVertex *key;
+ int k;
- for (k=0; k<sb->totkey; k++) {
- key= *(sb->keys + k);
- if (key) MEM_freeN(key);
- }
- if (sb->keys) MEM_freeN(sb->keys);
+ for (k = 0; k < sb->totkey; k++) {
+ key = *(sb->keys + k);
+ if (key)
+ MEM_freeN(key);
+ }
+ if (sb->keys)
+ MEM_freeN(sb->keys);
- sb->keys= NULL;
- sb->totkey= 0;
+ sb->keys = NULL;
+ sb->totkey = 0;
}
static void free_scratch(SoftBody *sb)
{
- if (sb->scratch) {
- /* todo make sure everything is cleaned up nicly */
- if (sb->scratch->colliderhash) {
- BLI_ghash_free(
- sb->scratch->colliderhash, NULL,
- (GHashValFreeFP) ccd_mesh_free); /*this hoepfully will free all caches*/
- sb->scratch->colliderhash = NULL;
- }
- if (sb->scratch->bodyface) {
- MEM_freeN(sb->scratch->bodyface);
- }
- if (sb->scratch->Ref.ivert) {
- MEM_freeN(sb->scratch->Ref.ivert);
- }
- MEM_freeN(sb->scratch);
- sb->scratch = NULL;
- }
-
+ if (sb->scratch) {
+ /* todo make sure everything is cleaned up nicly */
+ if (sb->scratch->colliderhash) {
+ BLI_ghash_free(sb->scratch->colliderhash,
+ NULL,
+ (GHashValFreeFP)ccd_mesh_free); /*this hoepfully will free all caches*/
+ sb->scratch->colliderhash = NULL;
+ }
+ if (sb->scratch->bodyface) {
+ MEM_freeN(sb->scratch->bodyface);
+ }
+ if (sb->scratch->Ref.ivert) {
+ MEM_freeN(sb->scratch->Ref.ivert);
+ }
+ MEM_freeN(sb->scratch);
+ sb->scratch = NULL;
+ }
}
/* only frees internal data */
static void free_softbody_intern(SoftBody *sb)
{
- if (sb) {
- int a;
- BodyPoint *bp;
+ if (sb) {
+ int a;
+ BodyPoint *bp;
- if (sb->bpoint) {
- for (a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
- /* free spring list */
- if (bp->springs != NULL) {
- MEM_freeN(bp->springs);
- }
- }
- MEM_freeN(sb->bpoint);
- }
+ if (sb->bpoint) {
+ for (a = sb->totpoint, bp = sb->bpoint; a > 0; a--, bp++) {
+ /* free spring list */
+ if (bp->springs != NULL) {
+ MEM_freeN(bp->springs);
+ }
+ }
+ MEM_freeN(sb->bpoint);
+ }
- if (sb->bspring) MEM_freeN(sb->bspring);
+ if (sb->bspring)
+ MEM_freeN(sb->bspring);
- sb->totpoint= sb->totspring= 0;
- sb->bpoint= NULL;
- sb->bspring= NULL;
+ sb->totpoint = sb->totspring = 0;
+ sb->bpoint = NULL;
+ sb->bspring = NULL;
- free_scratch(sb);
- free_softbody_baked(sb);
- }
+ free_scratch(sb);
+ free_softbody_baked(sb);
+ }
}
-
/* ************ dynamics ********** */
/* the most general (micro physics correct) way to do collision
@@ -952,1491 +958,1536 @@ static void free_softbody_intern(SoftBody *sb)
*/
static int query_external_colliders(Depsgraph *depsgraph, Collection *collection)
{
- unsigned int numobjects;
- Object **objects = BKE_collision_objects_create(depsgraph, NULL, collection, &numobjects, eModifierType_Collision);
- BKE_collision_objects_free(objects);
+ unsigned int numobjects;
+ Object **objects = BKE_collision_objects_create(
+ depsgraph, NULL, collection, &numobjects, eModifierType_Collision);
+ BKE_collision_objects_free(objects);
- return (numobjects != 0);
+ return (numobjects != 0);
}
/* --- dependency information functions*/
-
/* +++ the aabb "force" section*/
-static int sb_detect_aabb_collisionCached(float UNUSED(force[3]), struct Object *vertexowner, float UNUSED(time))
-{
- Object *ob;
- SoftBody *sb=vertexowner->soft;
- GHash *hash;
- GHashIterator *ihash;
- float aabbmin[3], aabbmax[3];
- int deflected=0;
+static int sb_detect_aabb_collisionCached(float UNUSED(force[3]),
+ struct Object *vertexowner,
+ float UNUSED(time))
+{
+ Object *ob;
+ SoftBody *sb = vertexowner->soft;
+ GHash *hash;
+ GHashIterator *ihash;
+ float aabbmin[3], aabbmax[3];
+ int deflected = 0;
#if 0
- int a;
+ int a;
#endif
- if ((sb == NULL) || (sb->scratch ==NULL)) return 0;
- copy_v3_v3(aabbmin, sb->scratch->aabbmin);
- copy_v3_v3(aabbmax, sb->scratch->aabbmax);
-
- hash = vertexowner->soft->scratch->colliderhash;
- ihash = BLI_ghashIterator_new(hash);
- while (!BLI_ghashIterator_done(ihash)) {
-
- ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash);
- ob = BLI_ghashIterator_getKey (ihash);
- {
- /* only with deflecting set */
- if (ob->pd && ob->pd->deflect) {
- if (ccdm) {
- if ((aabbmax[0] < ccdm->bbmin[0]) ||
- (aabbmax[1] < ccdm->bbmin[1]) ||
- (aabbmax[2] < ccdm->bbmin[2]) ||
- (aabbmin[0] > ccdm->bbmax[0]) ||
- (aabbmin[1] > ccdm->bbmax[1]) ||
- (aabbmin[2] > ccdm->bbmax[2]) )
- {
- /* boxes don't intersect */
- BLI_ghashIterator_step(ihash);
- continue;
- }
-
- /* so now we have the 2 boxes overlapping */
- /* forces actually not used */
- deflected = 2;
-
- }
- else {
- /*aye that should be cached*/
- CLOG_ERROR(&LOG, "missing cache error");
- BLI_ghashIterator_step(ihash);
- continue;
- }
- } /* if (ob->pd && ob->pd->deflect) */
- BLI_ghashIterator_step(ihash);
- }
- } /* while () */
- BLI_ghashIterator_free(ihash);
- return deflected;
+ if ((sb == NULL) || (sb->scratch == NULL))
+ return 0;
+ copy_v3_v3(aabbmin, sb->scratch->aabbmin);
+ copy_v3_v3(aabbmax, sb->scratch->aabbmax);
+
+ hash = vertexowner->soft->scratch->colliderhash;
+ ihash = BLI_ghashIterator_new(hash);
+ while (!BLI_ghashIterator_done(ihash)) {
+
+ ccd_Mesh *ccdm = BLI_ghashIterator_getValue(ihash);
+ ob = BLI_ghashIterator_getKey(ihash);
+ {
+ /* only with deflecting set */
+ if (ob->pd && ob->pd->deflect) {
+ if (ccdm) {
+ if ((aabbmax[0] < ccdm->bbmin[0]) || (aabbmax[1] < ccdm->bbmin[1]) ||
+ (aabbmax[2] < ccdm->bbmin[2]) || (aabbmin[0] > ccdm->bbmax[0]) ||
+ (aabbmin[1] > ccdm->bbmax[1]) || (aabbmin[2] > ccdm->bbmax[2])) {
+ /* boxes don't intersect */
+ BLI_ghashIterator_step(ihash);
+ continue;
+ }
+
+ /* so now we have the 2 boxes overlapping */
+ /* forces actually not used */
+ deflected = 2;
+ }
+ else {
+ /*aye that should be cached*/
+ CLOG_ERROR(&LOG, "missing cache error");
+ BLI_ghashIterator_step(ihash);
+ continue;
+ }
+ } /* if (ob->pd && ob->pd->deflect) */
+ BLI_ghashIterator_step(ihash);
+ }
+ } /* while () */
+ BLI_ghashIterator_free(ihash);
+ return deflected;
}
/* --- the aabb section*/
-
/* +++ the face external section*/
-static int sb_detect_face_pointCached(float face_v1[3], float face_v2[3], float face_v3[3], float *damp,
- float force[3], struct Object *vertexowner, float time)
-{
- Object *ob;
- GHash *hash;
- GHashIterator *ihash;
- float nv1[3], edge1[3], edge2[3], d_nvect[3], aabbmin[3], aabbmax[3];
- float facedist, outerfacethickness, tune = 10.f;
- int a, deflected=0;
-
- aabbmin[0] = min_fff(face_v1[0], face_v2[0], face_v3[0]);
- aabbmin[1] = min_fff(face_v1[1], face_v2[1], face_v3[1]);
- aabbmin[2] = min_fff(face_v1[2], face_v2[2], face_v3[2]);
- aabbmax[0] = max_fff(face_v1[0], face_v2[0], face_v3[0]);
- aabbmax[1] = max_fff(face_v1[1], face_v2[1], face_v3[1]);
- aabbmax[2] = max_fff(face_v1[2], face_v2[2], face_v3[2]);
-
- /* calculate face normal once again SIGH */
- sub_v3_v3v3(edge1, face_v1, face_v2);
- sub_v3_v3v3(edge2, face_v3, face_v2);
- cross_v3_v3v3(d_nvect, edge2, edge1);
- normalize_v3(d_nvect);
-
-
- hash = vertexowner->soft->scratch->colliderhash;
- ihash = BLI_ghashIterator_new(hash);
- while (!BLI_ghashIterator_done(ihash)) {
-
- ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash);
- ob = BLI_ghashIterator_getKey (ihash);
- {
- /* only with deflecting set */
- if (ob->pd && ob->pd->deflect) {
- const MVert *mvert= NULL;
- const MVert *mprevvert= NULL;
- if (ccdm) {
- mvert = ccdm->mvert;
- a = ccdm->mvert_num;
- mprevvert= ccdm->mprevvert;
- outerfacethickness = ob->pd->pdef_sboft;
- if ((aabbmax[0] < ccdm->bbmin[0]) ||
- (aabbmax[1] < ccdm->bbmin[1]) ||
- (aabbmax[2] < ccdm->bbmin[2]) ||
- (aabbmin[0] > ccdm->bbmax[0]) ||
- (aabbmin[1] > ccdm->bbmax[1]) ||
- (aabbmin[2] > ccdm->bbmax[2]) )
- {
- /* boxes don't intersect */
- BLI_ghashIterator_step(ihash);
- continue;
- }
-
- }
- else {
- /*aye that should be cached*/
- CLOG_ERROR(&LOG, "missing cache error");
- BLI_ghashIterator_step(ihash);
- continue;
- }
-
-
- /* use mesh*/
- if (mvert) {
- while (a) {
- copy_v3_v3(nv1, mvert[a-1].co);
- if (mprevvert) {
- mul_v3_fl(nv1, time);
- madd_v3_v3fl(nv1, mprevvert[a - 1].co, 1.0f - time);
- }
- /* origin to face_v2*/
- sub_v3_v3(nv1, face_v2);
- facedist = dot_v3v3(nv1, d_nvect);
- if (ABS(facedist)<outerfacethickness) {
- if (isect_point_tri_prism_v3(nv1, face_v1, face_v2, face_v3) ) {
- float df;
- if (facedist > 0) {
- df = (outerfacethickness-facedist)/outerfacethickness;
- }
- else {
- df = (outerfacethickness+facedist)/outerfacethickness;
- }
-
- *damp=df*tune*ob->pd->pdef_sbdamp;
-
- df = 0.01f * expf(-100.0f * df);
- madd_v3_v3fl(force, d_nvect, -df);
- deflected = 3;
- }
- }
- a--;
- }/* while (a)*/
- } /* if (mvert) */
- } /* if (ob->pd && ob->pd->deflect) */
- BLI_ghashIterator_step(ihash);
- }
- } /* while () */
- BLI_ghashIterator_free(ihash);
- return deflected;
-}
-
-
-static int sb_detect_face_collisionCached(float face_v1[3], float face_v2[3], float face_v3[3], float *damp,
- float force[3], struct Object *vertexowner, float time)
-{
- Object *ob;
- GHash *hash;
- GHashIterator *ihash;
- float nv1[3], nv2[3], nv3[3], edge1[3], edge2[3], d_nvect[3], aabbmin[3], aabbmax[3];
- float t, tune = 10.0f;
- int a, deflected=0;
-
- aabbmin[0] = min_fff(face_v1[0], face_v2[0], face_v3[0]);
- aabbmin[1] = min_fff(face_v1[1], face_v2[1], face_v3[1]);
- aabbmin[2] = min_fff(face_v1[2], face_v2[2], face_v3[2]);
- aabbmax[0] = max_fff(face_v1[0], face_v2[0], face_v3[0]);
- aabbmax[1] = max_fff(face_v1[1], face_v2[1], face_v3[1]);
- aabbmax[2] = max_fff(face_v1[2], face_v2[2], face_v3[2]);
-
- hash = vertexowner->soft->scratch->colliderhash;
- ihash = BLI_ghashIterator_new(hash);
- while (!BLI_ghashIterator_done(ihash)) {
-
- ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash);
- ob = BLI_ghashIterator_getKey (ihash);
- {
- /* only with deflecting set */
- if (ob->pd && ob->pd->deflect) {
- const MVert *mvert = NULL;
- const MVert *mprevvert = NULL;
- const MVertTri *vt = NULL;
- const ccdf_minmax *mima = NULL;
-
- if (ccdm) {
- mvert = ccdm->mvert;
- vt = ccdm->tri;
- mprevvert = ccdm->mprevvert;
- mima = ccdm->mima;
- a = ccdm->tri_num;
-
- if ((aabbmax[0] < ccdm->bbmin[0]) ||
- (aabbmax[1] < ccdm->bbmin[1]) ||
- (aabbmax[2] < ccdm->bbmin[2]) ||
- (aabbmin[0] > ccdm->bbmax[0]) ||
- (aabbmin[1] > ccdm->bbmax[1]) ||
- (aabbmin[2] > ccdm->bbmax[2]) )
- {
- /* boxes don't intersect */
- BLI_ghashIterator_step(ihash);
- continue;
- }
-
- }
- else {
- /*aye that should be cached*/
- CLOG_ERROR(&LOG, "missing cache error");
- BLI_ghashIterator_step(ihash);
- continue;
- }
-
-
- /* use mesh*/
- while (a--) {
- if ((aabbmax[0] < mima->minx) ||
- (aabbmin[0] > mima->maxx) ||
- (aabbmax[1] < mima->miny) ||
- (aabbmin[1] > mima->maxy) ||
- (aabbmax[2] < mima->minz) ||
- (aabbmin[2] > mima->maxz))
- {
- mima++;
- vt++;
- continue;
- }
-
-
- if (mvert) {
-
- copy_v3_v3(nv1, mvert[vt->tri[0]].co);
- copy_v3_v3(nv2, mvert[vt->tri[1]].co);
- copy_v3_v3(nv3, mvert[vt->tri[2]].co);
-
- if (mprevvert) {
- mul_v3_fl(nv1, time);
- madd_v3_v3fl(nv1, mprevvert[vt->tri[0]].co, 1.0f - time);
-
- mul_v3_fl(nv2, time);
- madd_v3_v3fl(nv2, mprevvert[vt->tri[1]].co, 1.0f - time);
-
- mul_v3_fl(nv3, time);
- madd_v3_v3fl(nv3, mprevvert[vt->tri[2]].co, 1.0f - time);
- }
- }
-
- /* switch origin to be nv2*/
- sub_v3_v3v3(edge1, nv1, nv2);
- sub_v3_v3v3(edge2, nv3, nv2);
- cross_v3_v3v3(d_nvect, edge2, edge1);
- normalize_v3(d_nvect);
- if (isect_line_segment_tri_v3(nv1, nv2, face_v1, face_v2, face_v3, &t, NULL) ||
- isect_line_segment_tri_v3(nv2, nv3, face_v1, face_v2, face_v3, &t, NULL) ||
- isect_line_segment_tri_v3(nv3, nv1, face_v1, face_v2, face_v3, &t, NULL) )
- {
- madd_v3_v3fl(force, d_nvect, -0.5f);
- *damp=tune*ob->pd->pdef_sbdamp;
- deflected = 2;
- }
- mima++;
- vt++;
- }/* while a */
- } /* if (ob->pd && ob->pd->deflect) */
- BLI_ghashIterator_step(ihash);
- }
- } /* while () */
- BLI_ghashIterator_free(ihash);
- return deflected;
+static int sb_detect_face_pointCached(float face_v1[3],
+ float face_v2[3],
+ float face_v3[3],
+ float *damp,
+ float force[3],
+ struct Object *vertexowner,
+ float time)
+{
+ Object *ob;
+ GHash *hash;
+ GHashIterator *ihash;
+ float nv1[3], edge1[3], edge2[3], d_nvect[3], aabbmin[3], aabbmax[3];
+ float facedist, outerfacethickness, tune = 10.f;
+ int a, deflected = 0;
+
+ aabbmin[0] = min_fff(face_v1[0], face_v2[0], face_v3[0]);
+ aabbmin[1] = min_fff(face_v1[1], face_v2[1], face_v3[1]);
+ aabbmin[2] = min_fff(face_v1[2], face_v2[2], face_v3[2]);
+ aabbmax[0] = max_fff(face_v1[0], face_v2[0], face_v3[0]);
+ aabbmax[1] = max_fff(face_v1[1], face_v2[1], face_v3[1]);
+ aabbmax[2] = max_fff(face_v1[2], face_v2[2], face_v3[2]);
+
+ /* calculate face normal once again SIGH */
+ sub_v3_v3v3(edge1, face_v1, face_v2);
+ sub_v3_v3v3(edge2, face_v3, face_v2);
+ cross_v3_v3v3(d_nvect, edge2, edge1);
+ normalize_v3(d_nvect);
+
+ hash = vertexowner->soft->scratch->colliderhash;
+ ihash = BLI_ghashIterator_new(hash);
+ while (!BLI_ghashIterator_done(ihash)) {
+
+ ccd_Mesh *ccdm = BLI_ghashIterator_getValue(ihash);
+ ob = BLI_ghashIterator_getKey(ihash);
+ {
+ /* only with deflecting set */
+ if (ob->pd && ob->pd->deflect) {
+ const MVert *mvert = NULL;
+ const MVert *mprevvert = NULL;
+ if (ccdm) {
+ mvert = ccdm->mvert;
+ a = ccdm->mvert_num;
+ mprevvert = ccdm->mprevvert;
+ outerfacethickness = ob->pd->pdef_sboft;
+ if ((aabbmax[0] < ccdm->bbmin[0]) || (aabbmax[1] < ccdm->bbmin[1]) ||
+ (aabbmax[2] < ccdm->bbmin[2]) || (aabbmin[0] > ccdm->bbmax[0]) ||
+ (aabbmin[1] > ccdm->bbmax[1]) || (aabbmin[2] > ccdm->bbmax[2])) {
+ /* boxes don't intersect */
+ BLI_ghashIterator_step(ihash);
+ continue;
+ }
+ }
+ else {
+ /*aye that should be cached*/
+ CLOG_ERROR(&LOG, "missing cache error");
+ BLI_ghashIterator_step(ihash);
+ continue;
+ }
+
+ /* use mesh*/
+ if (mvert) {
+ while (a) {
+ copy_v3_v3(nv1, mvert[a - 1].co);
+ if (mprevvert) {
+ mul_v3_fl(nv1, time);
+ madd_v3_v3fl(nv1, mprevvert[a - 1].co, 1.0f - time);
+ }
+ /* origin to face_v2*/
+ sub_v3_v3(nv1, face_v2);
+ facedist = dot_v3v3(nv1, d_nvect);
+ if (ABS(facedist) < outerfacethickness) {
+ if (isect_point_tri_prism_v3(nv1, face_v1, face_v2, face_v3)) {
+ float df;
+ if (facedist > 0) {
+ df = (outerfacethickness - facedist) / outerfacethickness;
+ }
+ else {
+ df = (outerfacethickness + facedist) / outerfacethickness;
+ }
+
+ *damp = df * tune * ob->pd->pdef_sbdamp;
+
+ df = 0.01f * expf(-100.0f * df);
+ madd_v3_v3fl(force, d_nvect, -df);
+ deflected = 3;
+ }
+ }
+ a--;
+ } /* while (a)*/
+ } /* if (mvert) */
+ } /* if (ob->pd && ob->pd->deflect) */
+ BLI_ghashIterator_step(ihash);
+ }
+ } /* while () */
+ BLI_ghashIterator_free(ihash);
+ return deflected;
+}
+
+static int sb_detect_face_collisionCached(float face_v1[3],
+ float face_v2[3],
+ float face_v3[3],
+ float *damp,
+ float force[3],
+ struct Object *vertexowner,
+ float time)
+{
+ Object *ob;
+ GHash *hash;
+ GHashIterator *ihash;
+ float nv1[3], nv2[3], nv3[3], edge1[3], edge2[3], d_nvect[3], aabbmin[3], aabbmax[3];
+ float t, tune = 10.0f;
+ int a, deflected = 0;
+
+ aabbmin[0] = min_fff(face_v1[0], face_v2[0], face_v3[0]);
+ aabbmin[1] = min_fff(face_v1[1], face_v2[1], face_v3[1]);
+ aabbmin[2] = min_fff(face_v1[2], face_v2[2], face_v3[2]);
+ aabbmax[0] = max_fff(face_v1[0], face_v2[0], face_v3[0]);
+ aabbmax[1] = max_fff(face_v1[1], face_v2[1], face_v3[1]);
+ aabbmax[2] = max_fff(face_v1[2], face_v2[2], face_v3[2]);
+
+ hash = vertexowner->soft->scratch->colliderhash;
+ ihash = BLI_ghashIterator_new(hash);
+ while (!BLI_ghashIterator_done(ihash)) {
+
+ ccd_Mesh *ccdm = BLI_ghashIterator_getValue(ihash);
+ ob = BLI_ghashIterator_getKey(ihash);
+ {
+ /* only with deflecting set */
+ if (ob->pd && ob->pd->deflect) {
+ const MVert *mvert = NULL;
+ const MVert *mprevvert = NULL;
+ const MVertTri *vt = NULL;
+ const ccdf_minmax *mima = NULL;
+
+ if (ccdm) {
+ mvert = ccdm->mvert;
+ vt = ccdm->tri;
+ mprevvert = ccdm->mprevvert;
+ mima = ccdm->mima;
+ a = ccdm->tri_num;
+
+ if ((aabbmax[0] < ccdm->bbmin[0]) || (aabbmax[1] < ccdm->bbmin[1]) ||
+ (aabbmax[2] < ccdm->bbmin[2]) || (aabbmin[0] > ccdm->bbmax[0]) ||
+ (aabbmin[1] > ccdm->bbmax[1]) || (aabbmin[2] > ccdm->bbmax[2])) {
+ /* boxes don't intersect */
+ BLI_ghashIterator_step(ihash);
+ continue;
+ }
+ }
+ else {
+ /*aye that should be cached*/
+ CLOG_ERROR(&LOG, "missing cache error");
+ BLI_ghashIterator_step(ihash);
+ continue;
+ }
+
+ /* use mesh*/
+ while (a--) {
+ if ((aabbmax[0] < mima->minx) || (aabbmin[0] > mima->maxx) ||
+ (aabbmax[1] < mima->miny) || (aabbmin[1] > mima->maxy) ||
+ (aabbmax[2] < mima->minz) || (aabbmin[2] > mima->maxz)) {
+ mima++;
+ vt++;
+ continue;
+ }
+
+ if (mvert) {
+
+ copy_v3_v3(nv1, mvert[vt->tri[0]].co);
+ copy_v3_v3(nv2, mvert[vt->tri[1]].co);
+ copy_v3_v3(nv3, mvert[vt->tri[2]].co);
+
+ if (mprevvert) {
+ mul_v3_fl(nv1, time);
+ madd_v3_v3fl(nv1, mprevvert[vt->tri[0]].co, 1.0f - time);
+
+ mul_v3_fl(nv2, time);
+ madd_v3_v3fl(nv2, mprevvert[vt->tri[1]].co, 1.0f - time);
+
+ mul_v3_fl(nv3, time);
+ madd_v3_v3fl(nv3, mprevvert[vt->tri[2]].co, 1.0f - time);
+ }
+ }
+
+ /* switch origin to be nv2*/
+ sub_v3_v3v3(edge1, nv1, nv2);
+ sub_v3_v3v3(edge2, nv3, nv2);
+ cross_v3_v3v3(d_nvect, edge2, edge1);
+ normalize_v3(d_nvect);
+ if (isect_line_segment_tri_v3(nv1, nv2, face_v1, face_v2, face_v3, &t, NULL) ||
+ isect_line_segment_tri_v3(nv2, nv3, face_v1, face_v2, face_v3, &t, NULL) ||
+ isect_line_segment_tri_v3(nv3, nv1, face_v1, face_v2, face_v3, &t, NULL)) {
+ madd_v3_v3fl(force, d_nvect, -0.5f);
+ *damp = tune * ob->pd->pdef_sbdamp;
+ deflected = 2;
+ }
+ mima++;
+ vt++;
+ } /* while a */
+ } /* if (ob->pd && ob->pd->deflect) */
+ BLI_ghashIterator_step(ihash);
+ }
+ } /* while () */
+ BLI_ghashIterator_free(ihash);
+ return deflected;
}
-
-
static void scan_for_ext_face_forces(Object *ob, float timenow)
{
- SoftBody *sb = ob->soft;
- BodyFace *bf;
- int a;
- float damp=0.0f, choke=1.0f;
- float tune = -10.0f;
- float feedback[3];
-
- if (sb && sb->scratch->totface) {
-
-
- bf = sb->scratch->bodyface;
- for (a=0; a<sb->scratch->totface; a++, bf++) {
- bf->ext_force[0]=bf->ext_force[1]=bf->ext_force[2]=0.0f;
-/*+++edges intruding*/
- bf->flag &= ~BFF_INTERSECT;
- zero_v3(feedback);
- if (sb_detect_face_collisionCached(
- sb->bpoint[bf->v1].pos, sb->bpoint[bf->v2].pos, sb->bpoint[bf->v3].pos,
- &damp, feedback, ob, timenow))
- {
- madd_v3_v3fl(sb->bpoint[bf->v1].force, feedback, tune);
- madd_v3_v3fl(sb->bpoint[bf->v2].force, feedback, tune);
- madd_v3_v3fl(sb->bpoint[bf->v3].force, feedback, tune);
-// madd_v3_v3fl(bf->ext_force, feedback, tune);
- bf->flag |= BFF_INTERSECT;
- choke = min_ff(max_ff(damp, choke), 1.0f);
- }
-/*---edges intruding*/
-
-/*+++ close vertices*/
- if (( bf->flag & BFF_INTERSECT)==0) {
- bf->flag &= ~BFF_CLOSEVERT;
- tune = -1.0f;
- zero_v3(feedback);
- if (sb_detect_face_pointCached(
- sb->bpoint[bf->v1].pos, sb->bpoint[bf->v2].pos, sb->bpoint[bf->v3].pos,
- &damp, feedback, ob, timenow))
- {
- madd_v3_v3fl(sb->bpoint[bf->v1].force, feedback, tune);
- madd_v3_v3fl(sb->bpoint[bf->v2].force, feedback, tune);
- madd_v3_v3fl(sb->bpoint[bf->v3].force, feedback, tune);
-// madd_v3_v3fl(bf->ext_force, feedback, tune);
- bf->flag |= BFF_CLOSEVERT;
- choke = min_ff(max_ff(damp, choke), 1.0f);
- }
- }
-/*--- close vertices*/
- }
- bf = sb->scratch->bodyface;
- for (a=0; a<sb->scratch->totface; a++, bf++) {
- if (( bf->flag & BFF_INTERSECT) || ( bf->flag & BFF_CLOSEVERT)) {
- sb->bpoint[bf->v1].choke2 = max_ff(sb->bpoint[bf->v1].choke2, choke);
- sb->bpoint[bf->v2].choke2 = max_ff(sb->bpoint[bf->v2].choke2, choke);
- sb->bpoint[bf->v3].choke2 = max_ff(sb->bpoint[bf->v3].choke2, choke);
- }
- }
- }
+ SoftBody *sb = ob->soft;
+ BodyFace *bf;
+ int a;
+ float damp = 0.0f, choke = 1.0f;
+ float tune = -10.0f;
+ float feedback[3];
+
+ if (sb && sb->scratch->totface) {
+
+ bf = sb->scratch->bodyface;
+ for (a = 0; a < sb->scratch->totface; a++, bf++) {
+ bf->ext_force[0] = bf->ext_force[1] = bf->ext_force[2] = 0.0f;
+ /*+++edges intruding*/
+ bf->flag &= ~BFF_INTERSECT;
+ zero_v3(feedback);
+ if (sb_detect_face_collisionCached(sb->bpoint[bf->v1].pos,
+ sb->bpoint[bf->v2].pos,
+ sb->bpoint[bf->v3].pos,
+ &damp,
+ feedback,
+ ob,
+ timenow)) {
+ madd_v3_v3fl(sb->bpoint[bf->v1].force, feedback, tune);
+ madd_v3_v3fl(sb->bpoint[bf->v2].force, feedback, tune);
+ madd_v3_v3fl(sb->bpoint[bf->v3].force, feedback, tune);
+ // madd_v3_v3fl(bf->ext_force, feedback, tune);
+ bf->flag |= BFF_INTERSECT;
+ choke = min_ff(max_ff(damp, choke), 1.0f);
+ }
+ /*---edges intruding*/
+
+ /*+++ close vertices*/
+ if ((bf->flag & BFF_INTERSECT) == 0) {
+ bf->flag &= ~BFF_CLOSEVERT;
+ tune = -1.0f;
+ zero_v3(feedback);
+ if (sb_detect_face_pointCached(sb->bpoint[bf->v1].pos,
+ sb->bpoint[bf->v2].pos,
+ sb->bpoint[bf->v3].pos,
+ &damp,
+ feedback,
+ ob,
+ timenow)) {
+ madd_v3_v3fl(sb->bpoint[bf->v1].force, feedback, tune);
+ madd_v3_v3fl(sb->bpoint[bf->v2].force, feedback, tune);
+ madd_v3_v3fl(sb->bpoint[bf->v3].force, feedback, tune);
+ // madd_v3_v3fl(bf->ext_force, feedback, tune);
+ bf->flag |= BFF_CLOSEVERT;
+ choke = min_ff(max_ff(damp, choke), 1.0f);
+ }
+ }
+ /*--- close vertices*/
+ }
+ bf = sb->scratch->bodyface;
+ for (a = 0; a < sb->scratch->totface; a++, bf++) {
+ if ((bf->flag & BFF_INTERSECT) || (bf->flag & BFF_CLOSEVERT)) {
+ sb->bpoint[bf->v1].choke2 = max_ff(sb->bpoint[bf->v1].choke2, choke);
+ sb->bpoint[bf->v2].choke2 = max_ff(sb->bpoint[bf->v2].choke2, choke);
+ sb->bpoint[bf->v3].choke2 = max_ff(sb->bpoint[bf->v3].choke2, choke);
+ }
+ }
+ }
}
/* --- the face external section*/
-
/* +++ the spring external section*/
-static int sb_detect_edge_collisionCached(float edge_v1[3], float edge_v2[3], float *damp,
- float force[3], struct Object *vertexowner, float time)
-{
- Object *ob;
- GHash *hash;
- GHashIterator *ihash;
- float nv1[3], nv2[3], nv3[3], edge1[3], edge2[3], d_nvect[3], aabbmin[3], aabbmax[3];
- float t, el;
- int a, deflected=0;
-
- minmax_v3v3_v3(aabbmin, aabbmax, edge_v1);
- minmax_v3v3_v3(aabbmin, aabbmax, edge_v2);
-
- el = len_v3v3(edge_v1, edge_v2);
-
- hash = vertexowner->soft->scratch->colliderhash;
- ihash = BLI_ghashIterator_new(hash);
- while (!BLI_ghashIterator_done(ihash)) {
-
- ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash);
- ob = BLI_ghashIterator_getKey (ihash);
- {
- /* only with deflecting set */
- if (ob->pd && ob->pd->deflect) {
- const MVert *mvert = NULL;
- const MVert *mprevvert = NULL;
- const MVertTri *vt = NULL;
- const ccdf_minmax *mima = NULL;
-
- if (ccdm) {
- mvert = ccdm->mvert;
- mprevvert = ccdm->mprevvert;
- vt = ccdm->tri;
- mima = ccdm->mima;
- a = ccdm->tri_num;
-
- if ((aabbmax[0] < ccdm->bbmin[0]) ||
- (aabbmax[1] < ccdm->bbmin[1]) ||
- (aabbmax[2] < ccdm->bbmin[2]) ||
- (aabbmin[0] > ccdm->bbmax[0]) ||
- (aabbmin[1] > ccdm->bbmax[1]) ||
- (aabbmin[2] > ccdm->bbmax[2]) )
- {
- /* boxes don't intersect */
- BLI_ghashIterator_step(ihash);
- continue;
- }
-
- }
- else {
- /*aye that should be cached*/
- CLOG_ERROR(&LOG, "missing cache error");
- BLI_ghashIterator_step(ihash);
- continue;
- }
-
-
- /* use mesh*/
- while (a--) {
- if ((aabbmax[0] < mima->minx) ||
- (aabbmin[0] > mima->maxx) ||
- (aabbmax[1] < mima->miny) ||
- (aabbmin[1] > mima->maxy) ||
- (aabbmax[2] < mima->minz) ||
- (aabbmin[2] > mima->maxz))
- {
- mima++;
- vt++;
- continue;
- }
-
-
- if (mvert) {
-
- copy_v3_v3(nv1, mvert[vt->tri[0]].co);
- copy_v3_v3(nv2, mvert[vt->tri[1]].co);
- copy_v3_v3(nv3, mvert[vt->tri[2]].co);
-
- if (mprevvert) {
- mul_v3_fl(nv1, time);
- madd_v3_v3fl(nv1, mprevvert[vt->tri[0]].co, 1.0f - time);
-
- mul_v3_fl(nv2, time);
- madd_v3_v3fl(nv2, mprevvert[vt->tri[1]].co, 1.0f - time);
-
- mul_v3_fl(nv3, time);
- madd_v3_v3fl(nv3, mprevvert[vt->tri[2]].co, 1.0f - time);
- }
- }
-
- /* switch origin to be nv2*/
- sub_v3_v3v3(edge1, nv1, nv2);
- sub_v3_v3v3(edge2, nv3, nv2);
-
- cross_v3_v3v3(d_nvect, edge2, edge1);
- normalize_v3(d_nvect);
- if (isect_line_segment_tri_v3(edge_v1, edge_v2, nv1, nv2, nv3, &t, NULL)) {
- float v1[3], v2[3];
- float intrusiondepth, i1, i2;
- sub_v3_v3v3(v1, edge_v1, nv2);
- sub_v3_v3v3(v2, edge_v2, nv2);
- i1 = dot_v3v3(v1, d_nvect);
- i2 = dot_v3v3(v2, d_nvect);
- intrusiondepth = -min_ff(i1, i2) / el;
- madd_v3_v3fl(force, d_nvect, intrusiondepth);
- *damp=ob->pd->pdef_sbdamp;
- deflected = 2;
- }
-
- mima++;
- vt++;
- }/* while a */
- } /* if (ob->pd && ob->pd->deflect) */
- BLI_ghashIterator_step(ihash);
- }
- } /* while () */
- BLI_ghashIterator_free(ihash);
- return deflected;
-}
-
-static void _scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow, int ifirst, int ilast, struct ListBase *effectors)
-{
- SoftBody *sb = ob->soft;
- int a;
- float damp;
- float feedback[3];
-
- if (sb && sb->totspring) {
- for (a=ifirst; a<ilast; a++) {
- BodySpring *bs = &sb->bspring[a];
- bs->ext_force[0]=bs->ext_force[1]=bs->ext_force[2]=0.0f;
- feedback[0]=feedback[1]=feedback[2]=0.0f;
- bs->flag &= ~BSF_INTERSECT;
-
- if (bs->springtype == SB_EDGE) {
- /* +++ springs colliding */
- if (ob->softflag & OB_SB_EDGECOLL) {
- if (sb_detect_edge_collisionCached(
- sb->bpoint[bs->v1].pos, sb->bpoint[bs->v2].pos,
- &damp, feedback, ob, timenow))
- {
- add_v3_v3(bs->ext_force, feedback);
- bs->flag |= BSF_INTERSECT;
- //bs->cf=damp;
- bs->cf=sb->choke*0.01f;
- }
- }
- /* ---- springs colliding */
-
- /* +++ springs seeing wind ... n stuff depending on their orientation*/
- /* note we don't use sb->mediafrict but use sb->aeroedge for magnitude of effect*/
- if (sb->aeroedge) {
- float vel[3], sp[3], pr[3], force[3];
- float f, windfactor = 0.25f;
- /*see if we have wind*/
- if (effectors) {
- EffectedPoint epoint;
- float speed[3] = {0.0f, 0.0f, 0.0f};
- float pos[3];
- mid_v3_v3v3(pos, sb->bpoint[bs->v1].pos, sb->bpoint[bs->v2].pos);
- mid_v3_v3v3(vel, sb->bpoint[bs->v1].vec, sb->bpoint[bs->v2].vec);
- pd_point_from_soft(scene, pos, vel, -1, &epoint);
- BKE_effectors_apply(effectors, NULL, sb->effector_weights, &epoint, force, speed);
-
- mul_v3_fl(speed, windfactor);
- add_v3_v3(vel, speed);
- }
- /* media in rest */
- else {
- add_v3_v3v3(vel, sb->bpoint[bs->v1].vec, sb->bpoint[bs->v2].vec);
- }
- f = normalize_v3(vel);
- f = -0.0001f*f*f*sb->aeroedge;
- /* (todo) add a nice angle dependent function done for now BUT */
- /* still there could be some nice drag/lift function, but who needs it */
-
- sub_v3_v3v3(sp, sb->bpoint[bs->v1].pos, sb->bpoint[bs->v2].pos);
- project_v3_v3v3(pr, vel, sp);
- sub_v3_v3(vel, pr);
- normalize_v3(vel);
- if (ob->softflag & OB_SB_AERO_ANGLE) {
- normalize_v3(sp);
- madd_v3_v3fl(bs->ext_force, vel, f * (1.0f - fabsf(dot_v3v3(vel, sp))));
- }
- else {
- madd_v3_v3fl(bs->ext_force, vel, f); // to keep compatible with 2.45 release files
- }
- }
- /* --- springs seeing wind */
- }
- }
- }
+static int sb_detect_edge_collisionCached(float edge_v1[3],
+ float edge_v2[3],
+ float *damp,
+ float force[3],
+ struct Object *vertexowner,
+ float time)
+{
+ Object *ob;
+ GHash *hash;
+ GHashIterator *ihash;
+ float nv1[3], nv2[3], nv3[3], edge1[3], edge2[3], d_nvect[3], aabbmin[3], aabbmax[3];
+ float t, el;
+ int a, deflected = 0;
+
+ minmax_v3v3_v3(aabbmin, aabbmax, edge_v1);
+ minmax_v3v3_v3(aabbmin, aabbmax, edge_v2);
+
+ el = len_v3v3(edge_v1, edge_v2);
+
+ hash = vertexowner->soft->scratch->colliderhash;
+ ihash = BLI_ghashIterator_new(hash);
+ while (!BLI_ghashIterator_done(ihash)) {
+
+ ccd_Mesh *ccdm = BLI_ghashIterator_getValue(ihash);
+ ob = BLI_ghashIterator_getKey(ihash);
+ {
+ /* only with deflecting set */
+ if (ob->pd && ob->pd->deflect) {
+ const MVert *mvert = NULL;
+ const MVert *mprevvert = NULL;
+ const MVertTri *vt = NULL;
+ const ccdf_minmax *mima = NULL;
+
+ if (ccdm) {
+ mvert = ccdm->mvert;
+ mprevvert = ccdm->mprevvert;
+ vt = ccdm->tri;
+ mima = ccdm->mima;
+ a = ccdm->tri_num;
+
+ if ((aabbmax[0] < ccdm->bbmin[0]) || (aabbmax[1] < ccdm->bbmin[1]) ||
+ (aabbmax[2] < ccdm->bbmin[2]) || (aabbmin[0] > ccdm->bbmax[0]) ||
+ (aabbmin[1] > ccdm->bbmax[1]) || (aabbmin[2] > ccdm->bbmax[2])) {
+ /* boxes don't intersect */
+ BLI_ghashIterator_step(ihash);
+ continue;
+ }
+ }
+ else {
+ /*aye that should be cached*/
+ CLOG_ERROR(&LOG, "missing cache error");
+ BLI_ghashIterator_step(ihash);
+ continue;
+ }
+
+ /* use mesh*/
+ while (a--) {
+ if ((aabbmax[0] < mima->minx) || (aabbmin[0] > mima->maxx) ||
+ (aabbmax[1] < mima->miny) || (aabbmin[1] > mima->maxy) ||
+ (aabbmax[2] < mima->minz) || (aabbmin[2] > mima->maxz)) {
+ mima++;
+ vt++;
+ continue;
+ }
+
+ if (mvert) {
+
+ copy_v3_v3(nv1, mvert[vt->tri[0]].co);
+ copy_v3_v3(nv2, mvert[vt->tri[1]].co);
+ copy_v3_v3(nv3, mvert[vt->tri[2]].co);
+
+ if (mprevvert) {
+ mul_v3_fl(nv1, time);
+ madd_v3_v3fl(nv1, mprevvert[vt->tri[0]].co, 1.0f - time);
+
+ mul_v3_fl(nv2, time);
+ madd_v3_v3fl(nv2, mprevvert[vt->tri[1]].co, 1.0f - time);
+
+ mul_v3_fl(nv3, time);
+ madd_v3_v3fl(nv3, mprevvert[vt->tri[2]].co, 1.0f - time);
+ }
+ }
+
+ /* switch origin to be nv2*/
+ sub_v3_v3v3(edge1, nv1, nv2);
+ sub_v3_v3v3(edge2, nv3, nv2);
+
+ cross_v3_v3v3(d_nvect, edge2, edge1);
+ normalize_v3(d_nvect);
+ if (isect_line_segment_tri_v3(edge_v1, edge_v2, nv1, nv2, nv3, &t, NULL)) {
+ float v1[3], v2[3];
+ float intrusiondepth, i1, i2;
+ sub_v3_v3v3(v1, edge_v1, nv2);
+ sub_v3_v3v3(v2, edge_v2, nv2);
+ i1 = dot_v3v3(v1, d_nvect);
+ i2 = dot_v3v3(v2, d_nvect);
+ intrusiondepth = -min_ff(i1, i2) / el;
+ madd_v3_v3fl(force, d_nvect, intrusiondepth);
+ *damp = ob->pd->pdef_sbdamp;
+ deflected = 2;
+ }
+
+ mima++;
+ vt++;
+ } /* while a */
+ } /* if (ob->pd && ob->pd->deflect) */
+ BLI_ghashIterator_step(ihash);
+ }
+ } /* while () */
+ BLI_ghashIterator_free(ihash);
+ return deflected;
+}
+
+static void _scan_for_ext_spring_forces(
+ Scene *scene, Object *ob, float timenow, int ifirst, int ilast, struct ListBase *effectors)
+{
+ SoftBody *sb = ob->soft;
+ int a;
+ float damp;
+ float feedback[3];
+
+ if (sb && sb->totspring) {
+ for (a = ifirst; a < ilast; a++) {
+ BodySpring *bs = &sb->bspring[a];
+ bs->ext_force[0] = bs->ext_force[1] = bs->ext_force[2] = 0.0f;
+ feedback[0] = feedback[1] = feedback[2] = 0.0f;
+ bs->flag &= ~BSF_INTERSECT;
+
+ if (bs->springtype == SB_EDGE) {
+ /* +++ springs colliding */
+ if (ob->softflag & OB_SB_EDGECOLL) {
+ if (sb_detect_edge_collisionCached(
+ sb->bpoint[bs->v1].pos, sb->bpoint[bs->v2].pos, &damp, feedback, ob, timenow)) {
+ add_v3_v3(bs->ext_force, feedback);
+ bs->flag |= BSF_INTERSECT;
+ //bs->cf=damp;
+ bs->cf = sb->choke * 0.01f;
+ }
+ }
+ /* ---- springs colliding */
+
+ /* +++ springs seeing wind ... n stuff depending on their orientation*/
+ /* note we don't use sb->mediafrict but use sb->aeroedge for magnitude of effect*/
+ if (sb->aeroedge) {
+ float vel[3], sp[3], pr[3], force[3];
+ float f, windfactor = 0.25f;
+ /*see if we have wind*/
+ if (effectors) {
+ EffectedPoint epoint;
+ float speed[3] = {0.0f, 0.0f, 0.0f};
+ float pos[3];
+ mid_v3_v3v3(pos, sb->bpoint[bs->v1].pos, sb->bpoint[bs->v2].pos);
+ mid_v3_v3v3(vel, sb->bpoint[bs->v1].vec, sb->bpoint[bs->v2].vec);
+ pd_point_from_soft(scene, pos, vel, -1, &epoint);
+ BKE_effectors_apply(effectors, NULL, sb->effector_weights, &epoint, force, speed);
+
+ mul_v3_fl(speed, windfactor);
+ add_v3_v3(vel, speed);
+ }
+ /* media in rest */
+ else {
+ add_v3_v3v3(vel, sb->bpoint[bs->v1].vec, sb->bpoint[bs->v2].vec);
+ }
+ f = normalize_v3(vel);
+ f = -0.0001f * f * f * sb->aeroedge;
+ /* (todo) add a nice angle dependent function done for now BUT */
+ /* still there could be some nice drag/lift function, but who needs it */
+
+ sub_v3_v3v3(sp, sb->bpoint[bs->v1].pos, sb->bpoint[bs->v2].pos);
+ project_v3_v3v3(pr, vel, sp);
+ sub_v3_v3(vel, pr);
+ normalize_v3(vel);
+ if (ob->softflag & OB_SB_AERO_ANGLE) {
+ normalize_v3(sp);
+ madd_v3_v3fl(bs->ext_force, vel, f * (1.0f - fabsf(dot_v3v3(vel, sp))));
+ }
+ else {
+ madd_v3_v3fl(bs->ext_force, vel, f); // to keep compatible with 2.45 release files
+ }
+ }
+ /* --- springs seeing wind */
+ }
+ }
+ }
}
static void *exec_scan_for_ext_spring_forces(void *data)
{
- SB_thread_context *pctx = (SB_thread_context*)data;
- _scan_for_ext_spring_forces(pctx->scene, pctx->ob, pctx->timenow, pctx->ifirst, pctx->ilast, pctx->effectors);
- return NULL;
-}
-
-static void sb_sfesf_threads_run(struct Depsgraph *depsgraph, Scene *scene, struct Object *ob, float timenow, int totsprings, int *UNUSED(ptr_to_break_func(void)))
-{
- ListBase threads;
- SB_thread_context *sb_threads;
- int i, totthread, left, dec;
- int lowsprings =100; /* wild guess .. may increase with better thread management 'above' or even be UI option sb->spawn_cf_threads_nopts */
-
- ListBase *effectors = BKE_effectors_create(depsgraph, ob, NULL, ob->soft->effector_weights);
-
- /* figure the number of threads while preventing pretty pointless threading overhead */
- totthread= BKE_scene_num_threads(scene);
- /* what if we got zillions of CPUs running but less to spread*/
- while ((totsprings/totthread < lowsprings) && (totthread > 1)) {
- totthread--;
- }
-
- sb_threads= MEM_callocN(sizeof(SB_thread_context)*totthread, "SBSpringsThread");
- memset(sb_threads, 0, sizeof(SB_thread_context)*totthread);
- left = totsprings;
- dec = totsprings/totthread +1;
- for (i=0; i<totthread; i++) {
- sb_threads[i].scene = scene;
- sb_threads[i].ob = ob;
- sb_threads[i].forcetime = 0.0; // not used here
- sb_threads[i].timenow = timenow;
- sb_threads[i].ilast = left;
- left = left - dec;
- if (left >0) {
- sb_threads[i].ifirst = left;
- }
- else
- sb_threads[i].ifirst = 0;
- sb_threads[i].effectors = effectors;
- sb_threads[i].do_deflector = false;// not used here
- sb_threads[i].fieldfactor = 0.0f;// not used here
- sb_threads[i].windfactor = 0.0f;// not used here
- sb_threads[i].nr= i;
- sb_threads[i].tot= totthread;
- }
- if (totthread > 1) {
- BLI_threadpool_init(&threads, exec_scan_for_ext_spring_forces, totthread);
-
- for (i=0; i<totthread; i++)
- BLI_threadpool_insert(&threads, &sb_threads[i]);
-
- BLI_threadpool_end(&threads);
- }
- else
- exec_scan_for_ext_spring_forces(&sb_threads[0]);
- /* clean up */
- MEM_freeN(sb_threads);
-
- BKE_effectors_free(effectors);
+ SB_thread_context *pctx = (SB_thread_context *)data;
+ _scan_for_ext_spring_forces(
+ pctx->scene, pctx->ob, pctx->timenow, pctx->ifirst, pctx->ilast, pctx->effectors);
+ return NULL;
+}
+
+static void sb_sfesf_threads_run(struct Depsgraph *depsgraph,
+ Scene *scene,
+ struct Object *ob,
+ float timenow,
+ int totsprings,
+ int *UNUSED(ptr_to_break_func(void)))
+{
+ ListBase threads;
+ SB_thread_context *sb_threads;
+ int i, totthread, left, dec;
+ int lowsprings =
+ 100; /* wild guess .. may increase with better thread management 'above' or even be UI option sb->spawn_cf_threads_nopts */
+
+ ListBase *effectors = BKE_effectors_create(depsgraph, ob, NULL, ob->soft->effector_weights);
+
+ /* figure the number of threads while preventing pretty pointless threading overhead */
+ totthread = BKE_scene_num_threads(scene);
+ /* what if we got zillions of CPUs running but less to spread*/
+ while ((totsprings / totthread < lowsprings) && (totthread > 1)) {
+ totthread--;
+ }
+
+ sb_threads = MEM_callocN(sizeof(SB_thread_context) * totthread, "SBSpringsThread");
+ memset(sb_threads, 0, sizeof(SB_thread_context) * totthread);
+ left = totsprings;
+ dec = totsprings / totthread + 1;
+ for (i = 0; i < totthread; i++) {
+ sb_threads[i].scene = scene;
+ sb_threads[i].ob = ob;
+ sb_threads[i].forcetime = 0.0; // not used here
+ sb_threads[i].timenow = timenow;
+ sb_threads[i].ilast = left;
+ left = left - dec;
+ if (left > 0) {
+ sb_threads[i].ifirst = left;
+ }
+ else
+ sb_threads[i].ifirst = 0;
+ sb_threads[i].effectors = effectors;
+ sb_threads[i].do_deflector = false; // not used here
+ sb_threads[i].fieldfactor = 0.0f; // not used here
+ sb_threads[i].windfactor = 0.0f; // not used here
+ sb_threads[i].nr = i;
+ sb_threads[i].tot = totthread;
+ }
+ if (totthread > 1) {
+ BLI_threadpool_init(&threads, exec_scan_for_ext_spring_forces, totthread);
+
+ for (i = 0; i < totthread; i++)
+ BLI_threadpool_insert(&threads, &sb_threads[i]);
+
+ BLI_threadpool_end(&threads);
+ }
+ else
+ exec_scan_for_ext_spring_forces(&sb_threads[0]);
+ /* clean up */
+ MEM_freeN(sb_threads);
+
+ BKE_effectors_free(effectors);
}
-
/* --- the spring external section*/
-static int choose_winner(float *w, float *pos, float *a, float *b, float *c, float *ca, float *cb, float *cc)
-{
- float mindist, cp;
- int winner =1;
- mindist = fabsf(dot_v3v3(pos, a));
-
- cp = fabsf(dot_v3v3(pos, b));
- if ( mindist < cp ) {
- mindist = cp;
- winner =2;
- }
-
- cp = fabsf(dot_v3v3(pos, c));
- if (mindist < cp ) {
- mindist = cp;
- winner =3;
- }
- switch (winner) {
- case 1: copy_v3_v3(w, ca); break;
- case 2: copy_v3_v3(w, cb); break;
- case 3: copy_v3_v3(w, cc);
- }
- return(winner);
-}
-
-
-
-static int sb_detect_vertex_collisionCached(
- float opco[3], float facenormal[3], float *damp,
- float force[3], struct Object *vertexowner,
- float time, float vel[3], float *intrusion)
-{
- Object *ob= NULL;
- GHash *hash;
- GHashIterator *ihash;
- float nv1[3], nv2[3], nv3[3], edge1[3], edge2[3], d_nvect[3], dv1[3], ve[3], avel[3] = {0.0, 0.0, 0.0},
- vv1[3], vv2[3], vv3[3], coledge[3] = {0.0f, 0.0f, 0.0f}, mindistedge = 1000.0f,
- outerforceaccu[3], innerforceaccu[3],
- facedist, /* n_mag, */ /* UNUSED */ force_mag_norm, minx, miny, minz, maxx, maxy, maxz,
- innerfacethickness = -0.5f, outerfacethickness = 0.2f,
- ee = 5.0f, ff = 0.1f, fa=1;
- int a, deflected=0, cavel=0, ci=0;
-/* init */
- *intrusion = 0.0f;
- hash = vertexowner->soft->scratch->colliderhash;
- ihash = BLI_ghashIterator_new(hash);
- outerforceaccu[0]=outerforceaccu[1]=outerforceaccu[2]=0.0f;
- innerforceaccu[0]=innerforceaccu[1]=innerforceaccu[2]=0.0f;
-/* go */
- while (!BLI_ghashIterator_done(ihash)) {
-
- ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash);
- ob = BLI_ghashIterator_getKey (ihash);
- {
- /* only with deflecting set */
- if (ob->pd && ob->pd->deflect) {
- const MVert *mvert = NULL;
- const MVert *mprevvert = NULL;
- const MVertTri *vt = NULL;
- const ccdf_minmax *mima = NULL;
-
- if (ccdm) {
- mvert = ccdm->mvert;
- mprevvert = ccdm->mprevvert;
- vt = ccdm->tri;
- mima = ccdm->mima;
- a = ccdm->tri_num;
-
- minx = ccdm->bbmin[0];
- miny = ccdm->bbmin[1];
- minz = ccdm->bbmin[2];
-
- maxx = ccdm->bbmax[0];
- maxy = ccdm->bbmax[1];
- maxz = ccdm->bbmax[2];
-
- if ((opco[0] < minx) ||
- (opco[1] < miny) ||
- (opco[2] < minz) ||
- (opco[0] > maxx) ||
- (opco[1] > maxy) ||
- (opco[2] > maxz) )
- {
- /* outside the padded boundbox --> collision object is too far away */
- BLI_ghashIterator_step(ihash);
- continue;
- }
- }
- else {
- /*aye that should be cached*/
- CLOG_ERROR(&LOG, "missing cache error");
- BLI_ghashIterator_step(ihash);
- continue;
- }
-
- /* do object level stuff */
- /* need to have user control for that since it depends on model scale */
- innerfacethickness = -ob->pd->pdef_sbift;
- outerfacethickness = ob->pd->pdef_sboft;
- fa = (ff*outerfacethickness-outerfacethickness);
- fa *= fa;
- fa = 1.0f/fa;
- avel[0]=avel[1]=avel[2]=0.0f;
- /* use mesh*/
- while (a--) {
- if ((opco[0] < mima->minx) ||
- (opco[0] > mima->maxx) ||
- (opco[1] < mima->miny) ||
- (opco[1] > mima->maxy) ||
- (opco[2] < mima->minz) ||
- (opco[2] > mima->maxz))
- {
- mima++;
- vt++;
- continue;
- }
-
- if (mvert) {
-
- copy_v3_v3(nv1, mvert[vt->tri[0]].co);
- copy_v3_v3(nv2, mvert[vt->tri[1]].co);
- copy_v3_v3(nv3, mvert[vt->tri[2]].co);
-
- if (mprevvert) {
- /* grab the average speed of the collider vertices
- * before we spoil nvX
- * humm could be done once a SB steps but then we' need to store that too
- * since the AABB reduced propabitlty to get here drasticallly
- * it might be a nice tradeof CPU <--> memory
- */
- sub_v3_v3v3(vv1, nv1, mprevvert[vt->tri[0]].co);
- sub_v3_v3v3(vv2, nv2, mprevvert[vt->tri[1]].co);
- sub_v3_v3v3(vv3, nv3, mprevvert[vt->tri[2]].co);
-
- mul_v3_fl(nv1, time);
- madd_v3_v3fl(nv1, mprevvert[vt->tri[0]].co, 1.0f - time);
-
- mul_v3_fl(nv2, time);
- madd_v3_v3fl(nv2, mprevvert[vt->tri[1]].co, 1.0f - time);
-
- mul_v3_fl(nv3, time);
- madd_v3_v3fl(nv3, mprevvert[vt->tri[2]].co, 1.0f - time);
- }
- }
-
- /* switch origin to be nv2*/
- sub_v3_v3v3(edge1, nv1, nv2);
- sub_v3_v3v3(edge2, nv3, nv2);
- sub_v3_v3v3(dv1, opco, nv2); /* abuse dv1 to have vertex in question at *origin* of triangle */
-
- cross_v3_v3v3(d_nvect, edge2, edge1);
- /* n_mag = */ /* UNUSED */ normalize_v3(d_nvect);
- facedist = dot_v3v3(dv1, d_nvect);
- // so rules are
- //
-
- if ((facedist > innerfacethickness) && (facedist < outerfacethickness)) {
- if (isect_point_tri_prism_v3(opco, nv1, nv2, nv3) ) {
- force_mag_norm =(float)exp(-ee*facedist);
- if (facedist > outerfacethickness*ff)
- force_mag_norm =(float)force_mag_norm*fa*(facedist - outerfacethickness)*(facedist - outerfacethickness);
- *damp=ob->pd->pdef_sbdamp;
- if (facedist > 0.0f) {
- *damp *= (1.0f - facedist/outerfacethickness);
- madd_v3_v3fl(outerforceaccu, d_nvect, force_mag_norm);
- deflected = 3;
-
- }
- else {
- madd_v3_v3fl(innerforceaccu, d_nvect, force_mag_norm);
- if (deflected < 2) deflected = 2;
- }
- if ((mprevvert) && (*damp > 0.0f)) {
- choose_winner(ve, opco, nv1, nv2, nv3, vv1, vv2, vv3);
- add_v3_v3(avel, ve);
- cavel ++;
- }
- *intrusion += facedist;
- ci++;
- }
- }
-
- mima++;
- vt++;
- }/* while a */
- } /* if (ob->pd && ob->pd->deflect) */
- BLI_ghashIterator_step(ihash);
- }
- } /* while () */
-
- if (deflected == 1) { // no face but 'outer' edge cylinder sees vert
- force_mag_norm =(float)exp(-ee*mindistedge);
- if (mindistedge > outerfacethickness*ff)
- force_mag_norm =(float)force_mag_norm*fa*(mindistedge - outerfacethickness)*(mindistedge - outerfacethickness);
- madd_v3_v3fl(force, coledge, force_mag_norm);
- *damp=ob->pd->pdef_sbdamp;
- if (mindistedge > 0.0f) {
- *damp *= (1.0f - mindistedge/outerfacethickness);
- }
-
- }
- if (deflected == 2) { // face inner detected
- add_v3_v3(force, innerforceaccu);
- }
- if (deflected == 3) { // face outer detected
- add_v3_v3(force, outerforceaccu);
- }
-
- BLI_ghashIterator_free(ihash);
- if (cavel) mul_v3_fl(avel, 1.0f/(float)cavel);
- copy_v3_v3(vel, avel);
- if (ci) *intrusion /= ci;
- if (deflected) {
- normalize_v3_v3(facenormal, force);
- }
- return deflected;
+static int choose_winner(
+ float *w, float *pos, float *a, float *b, float *c, float *ca, float *cb, float *cc)
+{
+ float mindist, cp;
+ int winner = 1;
+ mindist = fabsf(dot_v3v3(pos, a));
+
+ cp = fabsf(dot_v3v3(pos, b));
+ if (mindist < cp) {
+ mindist = cp;
+ winner = 2;
+ }
+
+ cp = fabsf(dot_v3v3(pos, c));
+ if (mindist < cp) {
+ mindist = cp;
+ winner = 3;
+ }
+ switch (winner) {
+ case 1:
+ copy_v3_v3(w, ca);
+ break;
+ case 2:
+ copy_v3_v3(w, cb);
+ break;
+ case 3:
+ copy_v3_v3(w, cc);
+ }
+ return (winner);
+}
+
+static int sb_detect_vertex_collisionCached(float opco[3],
+ float facenormal[3],
+ float *damp,
+ float force[3],
+ struct Object *vertexowner,
+ float time,
+ float vel[3],
+ float *intrusion)
+{
+ Object *ob = NULL;
+ GHash *hash;
+ GHashIterator *ihash;
+ float nv1[3], nv2[3], nv3[3], edge1[3], edge2[3], d_nvect[3], dv1[3], ve[3],
+ avel[3] = {0.0, 0.0, 0.0}, vv1[3], vv2[3], vv3[3], coledge[3] = {0.0f, 0.0f, 0.0f},
+ mindistedge = 1000.0f, outerforceaccu[3], innerforceaccu[3], facedist,
+ /* n_mag, */ /* UNUSED */ force_mag_norm, minx, miny, minz, maxx, maxy, maxz,
+ innerfacethickness = -0.5f, outerfacethickness = 0.2f, ee = 5.0f, ff = 0.1f, fa = 1;
+ int a, deflected = 0, cavel = 0, ci = 0;
+ /* init */
+ *intrusion = 0.0f;
+ hash = vertexowner->soft->scratch->colliderhash;
+ ihash = BLI_ghashIterator_new(hash);
+ outerforceaccu[0] = outerforceaccu[1] = outerforceaccu[2] = 0.0f;
+ innerforceaccu[0] = innerforceaccu[1] = innerforceaccu[2] = 0.0f;
+ /* go */
+ while (!BLI_ghashIterator_done(ihash)) {
+
+ ccd_Mesh *ccdm = BLI_ghashIterator_getValue(ihash);
+ ob = BLI_ghashIterator_getKey(ihash);
+ {
+ /* only with deflecting set */
+ if (ob->pd && ob->pd->deflect) {
+ const MVert *mvert = NULL;
+ const MVert *mprevvert = NULL;
+ const MVertTri *vt = NULL;
+ const ccdf_minmax *mima = NULL;
+
+ if (ccdm) {
+ mvert = ccdm->mvert;
+ mprevvert = ccdm->mprevvert;
+ vt = ccdm->tri;
+ mima = ccdm->mima;
+ a = ccdm->tri_num;
+
+ minx = ccdm->bbmin[0];
+ miny = ccdm->bbmin[1];
+ minz = ccdm->bbmin[2];
+
+ maxx = ccdm->bbmax[0];
+ maxy = ccdm->bbmax[1];
+ maxz = ccdm->bbmax[2];
+
+ if ((opco[0] < minx) || (opco[1] < miny) || (opco[2] < minz) || (opco[0] > maxx) ||
+ (opco[1] > maxy) || (opco[2] > maxz)) {
+ /* outside the padded boundbox --> collision object is too far away */
+ BLI_ghashIterator_step(ihash);
+ continue;
+ }
+ }
+ else {
+ /*aye that should be cached*/
+ CLOG_ERROR(&LOG, "missing cache error");
+ BLI_ghashIterator_step(ihash);
+ continue;
+ }
+
+ /* do object level stuff */
+ /* need to have user control for that since it depends on model scale */
+ innerfacethickness = -ob->pd->pdef_sbift;
+ outerfacethickness = ob->pd->pdef_sboft;
+ fa = (ff * outerfacethickness - outerfacethickness);
+ fa *= fa;
+ fa = 1.0f / fa;
+ avel[0] = avel[1] = avel[2] = 0.0f;
+ /* use mesh*/
+ while (a--) {
+ if ((opco[0] < mima->minx) || (opco[0] > mima->maxx) || (opco[1] < mima->miny) ||
+ (opco[1] > mima->maxy) || (opco[2] < mima->minz) || (opco[2] > mima->maxz)) {
+ mima++;
+ vt++;
+ continue;
+ }
+
+ if (mvert) {
+
+ copy_v3_v3(nv1, mvert[vt->tri[0]].co);
+ copy_v3_v3(nv2, mvert[vt->tri[1]].co);
+ copy_v3_v3(nv3, mvert[vt->tri[2]].co);
+
+ if (mprevvert) {
+ /* grab the average speed of the collider vertices
+ * before we spoil nvX
+ * humm could be done once a SB steps but then we' need to store that too
+ * since the AABB reduced propabitlty to get here drasticallly
+ * it might be a nice tradeof CPU <--> memory
+ */
+ sub_v3_v3v3(vv1, nv1, mprevvert[vt->tri[0]].co);
+ sub_v3_v3v3(vv2, nv2, mprevvert[vt->tri[1]].co);
+ sub_v3_v3v3(vv3, nv3, mprevvert[vt->tri[2]].co);
+
+ mul_v3_fl(nv1, time);
+ madd_v3_v3fl(nv1, mprevvert[vt->tri[0]].co, 1.0f - time);
+
+ mul_v3_fl(nv2, time);
+ madd_v3_v3fl(nv2, mprevvert[vt->tri[1]].co, 1.0f - time);
+
+ mul_v3_fl(nv3, time);
+ madd_v3_v3fl(nv3, mprevvert[vt->tri[2]].co, 1.0f - time);
+ }
+ }
+
+ /* switch origin to be nv2*/
+ sub_v3_v3v3(edge1, nv1, nv2);
+ sub_v3_v3v3(edge2, nv3, nv2);
+ sub_v3_v3v3(
+ dv1, opco, nv2); /* abuse dv1 to have vertex in question at *origin* of triangle */
+
+ cross_v3_v3v3(d_nvect, edge2, edge1);
+ /* n_mag = */ /* UNUSED */ normalize_v3(d_nvect);
+ facedist = dot_v3v3(dv1, d_nvect);
+ // so rules are
+ //
+
+ if ((facedist > innerfacethickness) && (facedist < outerfacethickness)) {
+ if (isect_point_tri_prism_v3(opco, nv1, nv2, nv3)) {
+ force_mag_norm = (float)exp(-ee * facedist);
+ if (facedist > outerfacethickness * ff)
+ force_mag_norm = (float)force_mag_norm * fa * (facedist - outerfacethickness) *
+ (facedist - outerfacethickness);
+ *damp = ob->pd->pdef_sbdamp;
+ if (facedist > 0.0f) {
+ *damp *= (1.0f - facedist / outerfacethickness);
+ madd_v3_v3fl(outerforceaccu, d_nvect, force_mag_norm);
+ deflected = 3;
+ }
+ else {
+ madd_v3_v3fl(innerforceaccu, d_nvect, force_mag_norm);
+ if (deflected < 2)
+ deflected = 2;
+ }
+ if ((mprevvert) && (*damp > 0.0f)) {
+ choose_winner(ve, opco, nv1, nv2, nv3, vv1, vv2, vv3);
+ add_v3_v3(avel, ve);
+ cavel++;
+ }
+ *intrusion += facedist;
+ ci++;
+ }
+ }
+
+ mima++;
+ vt++;
+ } /* while a */
+ } /* if (ob->pd && ob->pd->deflect) */
+ BLI_ghashIterator_step(ihash);
+ }
+ } /* while () */
+
+ if (deflected == 1) { // no face but 'outer' edge cylinder sees vert
+ force_mag_norm = (float)exp(-ee * mindistedge);
+ if (mindistedge > outerfacethickness * ff)
+ force_mag_norm = (float)force_mag_norm * fa * (mindistedge - outerfacethickness) *
+ (mindistedge - outerfacethickness);
+ madd_v3_v3fl(force, coledge, force_mag_norm);
+ *damp = ob->pd->pdef_sbdamp;
+ if (mindistedge > 0.0f) {
+ *damp *= (1.0f - mindistedge / outerfacethickness);
+ }
+ }
+ if (deflected == 2) { // face inner detected
+ add_v3_v3(force, innerforceaccu);
+ }
+ if (deflected == 3) { // face outer detected
+ add_v3_v3(force, outerforceaccu);
+ }
+
+ BLI_ghashIterator_free(ihash);
+ if (cavel)
+ mul_v3_fl(avel, 1.0f / (float)cavel);
+ copy_v3_v3(vel, avel);
+ if (ci)
+ *intrusion /= ci;
+ if (deflected) {
+ normalize_v3_v3(facenormal, force);
+ }
+ return deflected;
}
-
/* sandbox to plug in various deflection algos */
-static int sb_deflect_face(Object *ob, float *actpos, float *facenormal, float *force, float *cf, float time, float *vel, float *intrusion)
-{
- float s_actpos[3];
- int deflected;
- copy_v3_v3(s_actpos, actpos);
- deflected= sb_detect_vertex_collisionCached(s_actpos, facenormal, cf, force, ob, time, vel, intrusion);
- //deflected= sb_detect_vertex_collisionCachedEx(s_actpos, facenormal, cf, force, ob, time, vel, intrusion);
- return(deflected);
+static int sb_deflect_face(Object *ob,
+ float *actpos,
+ float *facenormal,
+ float *force,
+ float *cf,
+ float time,
+ float *vel,
+ float *intrusion)
+{
+ float s_actpos[3];
+ int deflected;
+ copy_v3_v3(s_actpos, actpos);
+ deflected = sb_detect_vertex_collisionCached(
+ s_actpos, facenormal, cf, force, ob, time, vel, intrusion);
+ //deflected= sb_detect_vertex_collisionCachedEx(s_actpos, facenormal, cf, force, ob, time, vel, intrusion);
+ return (deflected);
}
/* hiding this for now .. but the jacobian may pop up on other tasks .. so i'd like to keep it */
#if 0
static void dfdx_spring(int ia, int ic, int op, float dir[3], float L, float len, float factor)
{
- float m, delta_ij;
- int i, j;
- if (L < len) {
- for (i=0;i<3;i++) {
- for (j=0;j<3;j++) {
- delta_ij = (i==j ? (1.0f): (0.0f));
- m=factor*(dir[i]*dir[j] + (1-L/len)*(delta_ij - dir[i]*dir[j]));
- EIG_linear_solver_matrix_add(ia+i, op+ic+j, m);
- }
- }
- }
- else {
- for (i=0;i<3;i++) {
- for (j=0;j<3;j++) {
- m=factor*dir[i]*dir[j];
- EIG_linear_solver_matrix_add(ia+i, op+ic+j, m);
- }
- }
- }
+ float m, delta_ij;
+ int i, j;
+ if (L < len) {
+ for (i=0;i<3;i++) {
+ for (j=0;j<3;j++) {
+ delta_ij = (i==j ? (1.0f): (0.0f));
+ m=factor*(dir[i]*dir[j] + (1-L/len)*(delta_ij - dir[i]*dir[j]));
+ EIG_linear_solver_matrix_add(ia+i, op+ic+j, m);
+ }
+ }
+ }
+ else {
+ for (i=0;i<3;i++) {
+ for (j=0;j<3;j++) {
+ m=factor*dir[i]*dir[j];
+ EIG_linear_solver_matrix_add(ia+i, op+ic+j, m);
+ }
+ }
+ }
}
static void dfdx_goal(int ia, int ic, int op, float factor)
{
- int i;
- for (i=0;i<3;i++) EIG_linear_solver_matrix_add(ia+i, op+ic+i, factor);
+ int i;
+ for (i=0;i<3;i++) EIG_linear_solver_matrix_add(ia+i, op+ic+i, factor);
}
static void dfdv_goal(int ia, int ic, float factor)
{
- int i;
- for (i=0;i<3;i++) EIG_linear_solver_matrix_add(ia+i, ic+i, factor);
+ int i;
+ for (i=0;i<3;i++) EIG_linear_solver_matrix_add(ia+i, ic+i, factor);
}
-#endif /* if 0 */
+#endif /* if 0 */
-static void sb_spring_force(Object *ob, int bpi, BodySpring *bs, float iks, float UNUSED(forcetime))
+static void sb_spring_force(
+ Object *ob, int bpi, BodySpring *bs, float iks, float UNUSED(forcetime))
{
- SoftBody *sb= ob->soft; /* is supposed to be there */
- BodyPoint *bp1, *bp2;
+ SoftBody *sb = ob->soft; /* is supposed to be there */
+ BodyPoint *bp1, *bp2;
- float dir[3], dvel[3];
- float distance, forcefactor, kd, absvel, projvel, kw;
-#if 0 /* UNUSED */
- int ia, ic;
+ float dir[3], dvel[3];
+ float distance, forcefactor, kd, absvel, projvel, kw;
+#if 0 /* UNUSED */
+ int ia, ic;
#endif
- /* prepare depending on which side of the spring we are on */
- if (bpi == bs->v1) {
- bp1 = &sb->bpoint[bs->v1];
- bp2 = &sb->bpoint[bs->v2];
-#if 0 /* UNUSED */
- ia =3*bs->v1;
- ic =3*bs->v2;
+ /* prepare depending on which side of the spring we are on */
+ if (bpi == bs->v1) {
+ bp1 = &sb->bpoint[bs->v1];
+ bp2 = &sb->bpoint[bs->v2];
+#if 0 /* UNUSED */
+ ia =3*bs->v1;
+ ic =3*bs->v2;
#endif
- }
- else if (bpi == bs->v2) {
- bp1 = &sb->bpoint[bs->v2];
- bp2 = &sb->bpoint[bs->v1];
-#if 0 /* UNUSED */
- ia =3*bs->v2;
- ic =3*bs->v1;
+ }
+ else if (bpi == bs->v2) {
+ bp1 = &sb->bpoint[bs->v2];
+ bp2 = &sb->bpoint[bs->v1];
+#if 0 /* UNUSED */
+ ia =3*bs->v2;
+ ic =3*bs->v1;
#endif
- }
- else {
- /* TODO make this debug option */
- CLOG_WARN(&LOG, "bodypoint <bpi> is not attached to spring <*bs>");
- return;
- }
-
- /* do bp1 <--> bp2 elastic */
- sub_v3_v3v3(dir, bp1->pos, bp2->pos);
- distance = normalize_v3(dir);
- if (bs->len < distance)
- iks = 1.0f/(1.0f-sb->inspring)-1.0f ;/* inner spring constants function */
- else
- iks = 1.0f/(1.0f-sb->inpush)-1.0f ;/* inner spring constants function */
-
- if (bs->len > 0.0f) /* check for degenerated springs */
- forcefactor = iks/bs->len;
- else
- forcefactor = iks;
- kw = (bp1->springweight+bp2->springweight)/2.0f;
- kw = kw * kw;
- kw = kw * kw;
- switch (bs->springtype) {
- case SB_EDGE:
- case SB_HANDLE:
- forcefactor *= kw;
- break;
- case SB_BEND:
- forcefactor *= sb->secondspring * kw;
- break;
- case SB_STIFFQUAD:
- forcefactor *= sb->shearstiff * sb->shearstiff * kw;
- break;
- default:
- break;
- }
-
-
- madd_v3_v3fl(bp1->force, dir, (bs->len - distance) * forcefactor);
-
- /* do bp1 <--> bp2 viscous */
- sub_v3_v3v3(dvel, bp1->vec, bp2->vec);
- kd = sb->infrict * sb_fric_force_scale(ob);
- absvel = normalize_v3(dvel);
- projvel = dot_v3v3(dir, dvel);
- kd *= absvel * projvel;
- madd_v3_v3fl(bp1->force, dir, -kd);
+ }
+ else {
+ /* TODO make this debug option */
+ CLOG_WARN(&LOG, "bodypoint <bpi> is not attached to spring <*bs>");
+ return;
+ }
+
+ /* do bp1 <--> bp2 elastic */
+ sub_v3_v3v3(dir, bp1->pos, bp2->pos);
+ distance = normalize_v3(dir);
+ if (bs->len < distance)
+ iks = 1.0f / (1.0f - sb->inspring) - 1.0f; /* inner spring constants function */
+ else
+ iks = 1.0f / (1.0f - sb->inpush) - 1.0f; /* inner spring constants function */
+
+ if (bs->len > 0.0f) /* check for degenerated springs */
+ forcefactor = iks / bs->len;
+ else
+ forcefactor = iks;
+ kw = (bp1->springweight + bp2->springweight) / 2.0f;
+ kw = kw * kw;
+ kw = kw * kw;
+ switch (bs->springtype) {
+ case SB_EDGE:
+ case SB_HANDLE:
+ forcefactor *= kw;
+ break;
+ case SB_BEND:
+ forcefactor *= sb->secondspring * kw;
+ break;
+ case SB_STIFFQUAD:
+ forcefactor *= sb->shearstiff * sb->shearstiff * kw;
+ break;
+ default:
+ break;
+ }
+
+ madd_v3_v3fl(bp1->force, dir, (bs->len - distance) * forcefactor);
+
+ /* do bp1 <--> bp2 viscous */
+ sub_v3_v3v3(dvel, bp1->vec, bp2->vec);
+ kd = sb->infrict * sb_fric_force_scale(ob);
+ absvel = normalize_v3(dvel);
+ projvel = dot_v3v3(dir, dvel);
+ kd *= absvel * projvel;
+ madd_v3_v3fl(bp1->force, dir, -kd);
}
-
/* since this is definitely the most CPU consuming task here .. try to spread it */
/* core function _softbody_calc_forces_slice_in_a_thread */
/* result is int to be able to flag user break */
-static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, float forcetime, float timenow, int ifirst, int ilast, int *UNUSED(ptr_to_break_func(void)), ListBase *effectors, int do_deflector, float fieldfactor, float windfactor)
-{
- float iks;
- int bb, do_selfcollision, do_springcollision, do_aero;
- int number_of_points_here = ilast - ifirst;
- SoftBody *sb = ob->soft; /* is supposed to be there */
- BodyPoint *bp;
-
- /* initialize */
- if (sb) {
- /* check conditions for various options */
- /* +++ could be done on object level to squeeze out the last bits of it */
- do_selfcollision=((ob->softflag & OB_SB_EDGES) && (sb->bspring)&& (ob->softflag & OB_SB_SELF));
- do_springcollision=do_deflector && (ob->softflag & OB_SB_EDGES) &&(ob->softflag & OB_SB_EDGECOLL);
- do_aero=((sb->aeroedge)&& (ob->softflag & OB_SB_EDGES));
- /* --- could be done on object level to squeeze out the last bits of it */
- }
- else {
- CLOG_ERROR(&LOG, "expected a SB here");
- return (999);
- }
-
-/* debugerin */
- if (sb->totpoint < ifirst) {
- printf("Aye 998");
- return (998);
- }
-/* debugerin */
-
-
- bp = &sb->bpoint[ifirst];
- for (bb=number_of_points_here; bb>0; bb--, bp++) {
- /* clear forces accumulator */
- bp->force[0] = bp->force[1] = bp->force[2] = 0.0;
- /* naive ball self collision */
- /* needs to be done if goal snaps or not */
- if (do_selfcollision) {
- int attached;
- BodyPoint *obp;
- BodySpring *bs;
- int c, b;
- float velcenter[3], dvel[3], def[3];
- float distance;
- float compare;
- float bstune = sb->ballstiff;
-
- /* running in a slice we must not assume anything done with obp neither alter the data of obp */
- for (c=sb->totpoint, obp= sb->bpoint; c>0; c--, obp++) {
- compare = (obp->colball + bp->colball);
- sub_v3_v3v3(def, bp->pos, obp->pos);
- /* rather check the AABBoxes before ever calculating the real distance */
- /* mathematically it is completely nuts, but performance is pretty much (3) times faster */
- if ((ABS(def[0]) > compare) || (ABS(def[1]) > compare) || (ABS(def[2]) > compare)) continue;
- distance = normalize_v3(def);
- if (distance < compare ) {
- /* exclude body points attached with a spring */
- attached = 0;
- for (b=obp->nofsprings;b>0;b--) {
- bs = sb->bspring + obp->springs[b-1];
- if (( ilast-bb == bs->v2) || ( ilast-bb == bs->v1)) {
- attached=1;
- continue;
- }
- }
- if (!attached) {
- float f = bstune / (distance) + bstune / (compare * compare) * distance - 2.0f * bstune / compare;
-
- mid_v3_v3v3(velcenter, bp->vec, obp->vec);
- sub_v3_v3v3(dvel, velcenter, bp->vec);
- mul_v3_fl(dvel, _final_mass(ob, bp));
-
- madd_v3_v3fl(bp->force, def, f * (1.0f - sb->balldamp));
- madd_v3_v3fl(bp->force, dvel, sb->balldamp);
- }
- }
- }
- }
- /* naive ball self collision done */
-
- if (_final_goal(ob, bp) < SOFTGOALSNAP) { /* omit this bp when it snaps */
- float auxvect[3];
- float velgoal[3];
-
- /* do goal stuff */
- if (ob->softflag & OB_SB_GOAL) {
- /* true elastic goal */
- float ks, kd;
- sub_v3_v3v3(auxvect, bp->pos, bp->origT);
- ks = 1.0f / (1.0f - _final_goal(ob, bp) * sb->goalspring) - 1.0f;
- bp->force[0]+= -ks*(auxvect[0]);
- bp->force[1]+= -ks*(auxvect[1]);
- bp->force[2]+= -ks*(auxvect[2]);
-
- /* calculate damping forces generated by goals*/
- sub_v3_v3v3(velgoal, bp->origS, bp->origE);
- kd = sb->goalfrict * sb_fric_force_scale(ob);
- add_v3_v3v3(auxvect, velgoal, bp->vec);
-
- if (forcetime > 0.0f) { /* make sure friction does not become rocket motor on time reversal */
- bp->force[0]-= kd * (auxvect[0]);
- bp->force[1]-= kd * (auxvect[1]);
- bp->force[2]-= kd * (auxvect[2]);
- }
- else {
- bp->force[0]-= kd * (velgoal[0] - bp->vec[0]);
- bp->force[1]-= kd * (velgoal[1] - bp->vec[1]);
- bp->force[2]-= kd * (velgoal[2] - bp->vec[2]);
- }
- }
- /* done goal stuff */
-
- /* gravitation */
- if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
- float gravity[3];
- copy_v3_v3(gravity, scene->physics_settings.gravity);
- mul_v3_fl(gravity, sb_grav_force_scale(ob)*_final_mass(ob, bp)*sb->effector_weights->global_gravity); /* individual mass of node here */
- add_v3_v3(bp->force, gravity);
- }
-
- /* particle field & vortex */
- if (effectors) {
- EffectedPoint epoint;
- float kd;
- float force[3] = {0.0f, 0.0f, 0.0f};
- float speed[3] = {0.0f, 0.0f, 0.0f};
- float eval_sb_fric_force_scale = sb_fric_force_scale(ob); /* just for calling function once */
- pd_point_from_soft(scene, bp->pos, bp->vec, sb->bpoint-bp, &epoint);
- BKE_effectors_apply(effectors, NULL, sb->effector_weights, &epoint, force, speed);
-
- /* apply forcefield*/
- mul_v3_fl(force, fieldfactor * eval_sb_fric_force_scale);
- add_v3_v3(bp->force, force);
-
- /* BP friction in moving media */
- kd= sb->mediafrict * eval_sb_fric_force_scale;
- bp->force[0] -= kd * (bp->vec[0] + windfactor*speed[0]/eval_sb_fric_force_scale);
- bp->force[1] -= kd * (bp->vec[1] + windfactor*speed[1]/eval_sb_fric_force_scale);
- bp->force[2] -= kd * (bp->vec[2] + windfactor*speed[2]/eval_sb_fric_force_scale);
- /* now we'll have nice centrifugal effect for vortex */
-
- }
- else {
- /* BP friction in media (not) moving*/
- float kd = sb->mediafrict * sb_fric_force_scale(ob);
- /* assume it to be proportional to actual velocity */
- bp->force[0]-= bp->vec[0]*kd;
- bp->force[1]-= bp->vec[1]*kd;
- bp->force[2]-= bp->vec[2]*kd;
- /* friction in media done */
- }
- /* +++cached collision targets */
- bp->choke = 0.0f;
- bp->choke2 = 0.0f;
- bp->loc_flag &= ~SBF_DOFUZZY;
- if (do_deflector && !(bp->loc_flag & SBF_OUTOFCOLLISION) ) {
- float cfforce[3], defforce[3] ={0.0f, 0.0f, 0.0f}, vel[3] = {0.0f, 0.0f, 0.0f}, facenormal[3], cf = 1.0f, intrusion;
- float kd = 1.0f;
-
- if (sb_deflect_face(ob, bp->pos, facenormal, defforce, &cf, timenow, vel, &intrusion)) {
- if (intrusion < 0.0f) {
- sb->scratch->flag |= SBF_DOFUZZY;
- bp->loc_flag |= SBF_DOFUZZY;
- bp->choke = sb->choke*0.01f;
- }
-
- sub_v3_v3v3(cfforce, bp->vec, vel);
- madd_v3_v3fl(bp->force, cfforce, -cf * 50.0f);
-
- madd_v3_v3fl(bp->force, defforce, kd);
- }
-
- }
- /* ---cached collision targets */
-
- /* +++springs */
- iks = 1.0f/(1.0f-sb->inspring)-1.0f ;/* inner spring constants function */
- if (ob->softflag & OB_SB_EDGES) {
- if (sb->bspring) { /* spring list exists at all ? */
- int b;
- BodySpring *bs;
- for (b=bp->nofsprings;b>0;b--) {
- bs = sb->bspring + bp->springs[b-1];
- if (do_springcollision || do_aero) {
- add_v3_v3(bp->force, bs->ext_force);
- if (bs->flag & BSF_INTERSECT)
- bp->choke = bs->cf;
-
- }
- // sb_spring_force(Object *ob, int bpi, BodySpring *bs, float iks, float forcetime)
- sb_spring_force(ob, ilast-bb, bs, iks, forcetime);
- }/* loop springs */
- }/* existing spring list */
- }/*any edges*/
- /* ---springs */
- }/*omit on snap */
- }/*loop all bp's*/
- return 0; /*done fine*/
+static int _softbody_calc_forces_slice_in_a_thread(Scene *scene,
+ Object *ob,
+ float forcetime,
+ float timenow,
+ int ifirst,
+ int ilast,
+ int *UNUSED(ptr_to_break_func(void)),
+ ListBase *effectors,
+ int do_deflector,
+ float fieldfactor,
+ float windfactor)
+{
+ float iks;
+ int bb, do_selfcollision, do_springcollision, do_aero;
+ int number_of_points_here = ilast - ifirst;
+ SoftBody *sb = ob->soft; /* is supposed to be there */
+ BodyPoint *bp;
+
+ /* initialize */
+ if (sb) {
+ /* check conditions for various options */
+ /* +++ could be done on object level to squeeze out the last bits of it */
+ do_selfcollision = ((ob->softflag & OB_SB_EDGES) && (sb->bspring) &&
+ (ob->softflag & OB_SB_SELF));
+ do_springcollision = do_deflector && (ob->softflag & OB_SB_EDGES) &&
+ (ob->softflag & OB_SB_EDGECOLL);
+ do_aero = ((sb->aeroedge) && (ob->softflag & OB_SB_EDGES));
+ /* --- could be done on object level to squeeze out the last bits of it */
+ }
+ else {
+ CLOG_ERROR(&LOG, "expected a SB here");
+ return (999);
+ }
+
+ /* debugerin */
+ if (sb->totpoint < ifirst) {
+ printf("Aye 998");
+ return (998);
+ }
+ /* debugerin */
+
+ bp = &sb->bpoint[ifirst];
+ for (bb = number_of_points_here; bb > 0; bb--, bp++) {
+ /* clear forces accumulator */
+ bp->force[0] = bp->force[1] = bp->force[2] = 0.0;
+ /* naive ball self collision */
+ /* needs to be done if goal snaps or not */
+ if (do_selfcollision) {
+ int attached;
+ BodyPoint *obp;
+ BodySpring *bs;
+ int c, b;
+ float velcenter[3], dvel[3], def[3];
+ float distance;
+ float compare;
+ float bstune = sb->ballstiff;
+
+ /* running in a slice we must not assume anything done with obp neither alter the data of obp */
+ for (c = sb->totpoint, obp = sb->bpoint; c > 0; c--, obp++) {
+ compare = (obp->colball + bp->colball);
+ sub_v3_v3v3(def, bp->pos, obp->pos);
+ /* rather check the AABBoxes before ever calculating the real distance */
+ /* mathematically it is completely nuts, but performance is pretty much (3) times faster */
+ if ((ABS(def[0]) > compare) || (ABS(def[1]) > compare) || (ABS(def[2]) > compare))
+ continue;
+ distance = normalize_v3(def);
+ if (distance < compare) {
+ /* exclude body points attached with a spring */
+ attached = 0;
+ for (b = obp->nofsprings; b > 0; b--) {
+ bs = sb->bspring + obp->springs[b - 1];
+ if ((ilast - bb == bs->v2) || (ilast - bb == bs->v1)) {
+ attached = 1;
+ continue;
+ }
+ }
+ if (!attached) {
+ float f = bstune / (distance) + bstune / (compare * compare) * distance -
+ 2.0f * bstune / compare;
+
+ mid_v3_v3v3(velcenter, bp->vec, obp->vec);
+ sub_v3_v3v3(dvel, velcenter, bp->vec);
+ mul_v3_fl(dvel, _final_mass(ob, bp));
+
+ madd_v3_v3fl(bp->force, def, f * (1.0f - sb->balldamp));
+ madd_v3_v3fl(bp->force, dvel, sb->balldamp);
+ }
+ }
+ }
+ }
+ /* naive ball self collision done */
+
+ if (_final_goal(ob, bp) < SOFTGOALSNAP) { /* omit this bp when it snaps */
+ float auxvect[3];
+ float velgoal[3];
+
+ /* do goal stuff */
+ if (ob->softflag & OB_SB_GOAL) {
+ /* true elastic goal */
+ float ks, kd;
+ sub_v3_v3v3(auxvect, bp->pos, bp->origT);
+ ks = 1.0f / (1.0f - _final_goal(ob, bp) * sb->goalspring) - 1.0f;
+ bp->force[0] += -ks * (auxvect[0]);
+ bp->force[1] += -ks * (auxvect[1]);
+ bp->force[2] += -ks * (auxvect[2]);
+
+ /* calculate damping forces generated by goals*/
+ sub_v3_v3v3(velgoal, bp->origS, bp->origE);
+ kd = sb->goalfrict * sb_fric_force_scale(ob);
+ add_v3_v3v3(auxvect, velgoal, bp->vec);
+
+ if (forcetime >
+ 0.0f) { /* make sure friction does not become rocket motor on time reversal */
+ bp->force[0] -= kd * (auxvect[0]);
+ bp->force[1] -= kd * (auxvect[1]);
+ bp->force[2] -= kd * (auxvect[2]);
+ }
+ else {
+ bp->force[0] -= kd * (velgoal[0] - bp->vec[0]);
+ bp->force[1] -= kd * (velgoal[1] - bp->vec[1]);
+ bp->force[2] -= kd * (velgoal[2] - bp->vec[2]);
+ }
+ }
+ /* done goal stuff */
+
+ /* gravitation */
+ if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
+ float gravity[3];
+ copy_v3_v3(gravity, scene->physics_settings.gravity);
+ mul_v3_fl(gravity,
+ sb_grav_force_scale(ob) * _final_mass(ob, bp) *
+ sb->effector_weights->global_gravity); /* individual mass of node here */
+ add_v3_v3(bp->force, gravity);
+ }
+
+ /* particle field & vortex */
+ if (effectors) {
+ EffectedPoint epoint;
+ float kd;
+ float force[3] = {0.0f, 0.0f, 0.0f};
+ float speed[3] = {0.0f, 0.0f, 0.0f};
+ float eval_sb_fric_force_scale = sb_fric_force_scale(
+ ob); /* just for calling function once */
+ pd_point_from_soft(scene, bp->pos, bp->vec, sb->bpoint - bp, &epoint);
+ BKE_effectors_apply(effectors, NULL, sb->effector_weights, &epoint, force, speed);
+
+ /* apply forcefield*/
+ mul_v3_fl(force, fieldfactor * eval_sb_fric_force_scale);
+ add_v3_v3(bp->force, force);
+
+ /* BP friction in moving media */
+ kd = sb->mediafrict * eval_sb_fric_force_scale;
+ bp->force[0] -= kd * (bp->vec[0] + windfactor * speed[0] / eval_sb_fric_force_scale);
+ bp->force[1] -= kd * (bp->vec[1] + windfactor * speed[1] / eval_sb_fric_force_scale);
+ bp->force[2] -= kd * (bp->vec[2] + windfactor * speed[2] / eval_sb_fric_force_scale);
+ /* now we'll have nice centrifugal effect for vortex */
+ }
+ else {
+ /* BP friction in media (not) moving*/
+ float kd = sb->mediafrict * sb_fric_force_scale(ob);
+ /* assume it to be proportional to actual velocity */
+ bp->force[0] -= bp->vec[0] * kd;
+ bp->force[1] -= bp->vec[1] * kd;
+ bp->force[2] -= bp->vec[2] * kd;
+ /* friction in media done */
+ }
+ /* +++cached collision targets */
+ bp->choke = 0.0f;
+ bp->choke2 = 0.0f;
+ bp->loc_flag &= ~SBF_DOFUZZY;
+ if (do_deflector && !(bp->loc_flag & SBF_OUTOFCOLLISION)) {
+ float cfforce[3], defforce[3] = {0.0f, 0.0f, 0.0f}, vel[3] = {0.0f, 0.0f, 0.0f},
+ facenormal[3], cf = 1.0f, intrusion;
+ float kd = 1.0f;
+
+ if (sb_deflect_face(ob, bp->pos, facenormal, defforce, &cf, timenow, vel, &intrusion)) {
+ if (intrusion < 0.0f) {
+ sb->scratch->flag |= SBF_DOFUZZY;
+ bp->loc_flag |= SBF_DOFUZZY;
+ bp->choke = sb->choke * 0.01f;
+ }
+
+ sub_v3_v3v3(cfforce, bp->vec, vel);
+ madd_v3_v3fl(bp->force, cfforce, -cf * 50.0f);
+
+ madd_v3_v3fl(bp->force, defforce, kd);
+ }
+ }
+ /* ---cached collision targets */
+
+ /* +++springs */
+ iks = 1.0f / (1.0f - sb->inspring) - 1.0f; /* inner spring constants function */
+ if (ob->softflag & OB_SB_EDGES) {
+ if (sb->bspring) { /* spring list exists at all ? */
+ int b;
+ BodySpring *bs;
+ for (b = bp->nofsprings; b > 0; b--) {
+ bs = sb->bspring + bp->springs[b - 1];
+ if (do_springcollision || do_aero) {
+ add_v3_v3(bp->force, bs->ext_force);
+ if (bs->flag & BSF_INTERSECT)
+ bp->choke = bs->cf;
+ }
+ // sb_spring_force(Object *ob, int bpi, BodySpring *bs, float iks, float forcetime)
+ sb_spring_force(ob, ilast - bb, bs, iks, forcetime);
+ } /* loop springs */
+ } /* existing spring list */
+ } /*any edges*/
+ /* ---springs */
+ } /*omit on snap */
+ } /*loop all bp's*/
+ return 0; /*done fine*/
}
static void *exec_softbody_calc_forces(void *data)
{
- SB_thread_context *pctx = (SB_thread_context*)data;
- _softbody_calc_forces_slice_in_a_thread(pctx->scene, pctx->ob, pctx->forcetime, pctx->timenow, pctx->ifirst, pctx->ilast, NULL, pctx->effectors, pctx->do_deflector, pctx->fieldfactor, pctx->windfactor);
- return NULL;
-}
-
-static void sb_cf_threads_run(Scene *scene, Object *ob, float forcetime, float timenow, int totpoint, int *UNUSED(ptr_to_break_func(void)), struct ListBase *effectors, int do_deflector, float fieldfactor, float windfactor)
-{
- ListBase threads;
- SB_thread_context *sb_threads;
- int i, totthread, left, dec;
- int lowpoints =100; /* wild guess .. may increase with better thread management 'above' or even be UI option sb->spawn_cf_threads_nopts */
-
- /* figure the number of threads while preventing pretty pointless threading overhead */
- totthread= BKE_scene_num_threads(scene);
- /* what if we got zillions of CPUs running but less to spread*/
- while ((totpoint/totthread < lowpoints) && (totthread > 1)) {
- totthread--;
- }
-
- /* printf("sb_cf_threads_run spawning %d threads\n", totthread); */
-
- sb_threads= MEM_callocN(sizeof(SB_thread_context)*totthread, "SBThread");
- memset(sb_threads, 0, sizeof(SB_thread_context)*totthread);
- left = totpoint;
- dec = totpoint/totthread +1;
- for (i=0; i<totthread; i++) {
- sb_threads[i].scene = scene;
- sb_threads[i].ob = ob;
- sb_threads[i].forcetime = forcetime;
- sb_threads[i].timenow = timenow;
- sb_threads[i].ilast = left;
- left = left - dec;
- if (left >0) {
- sb_threads[i].ifirst = left;
- }
- else
- sb_threads[i].ifirst = 0;
- sb_threads[i].effectors = effectors;
- sb_threads[i].do_deflector = do_deflector;
- sb_threads[i].fieldfactor = fieldfactor;
- sb_threads[i].windfactor = windfactor;
- sb_threads[i].nr= i;
- sb_threads[i].tot= totthread;
- }
-
-
- if (totthread > 1) {
- BLI_threadpool_init(&threads, exec_softbody_calc_forces, totthread);
-
- for (i=0; i<totthread; i++)
- BLI_threadpool_insert(&threads, &sb_threads[i]);
-
- BLI_threadpool_end(&threads);
- }
- else
- exec_softbody_calc_forces(&sb_threads[0]);
- /* clean up */
- MEM_freeN(sb_threads);
-}
-
-static void softbody_calc_forces(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float forcetime, float timenow)
-{
- /* rule we never alter free variables :bp->vec bp->pos in here !
- * this will ruin adaptive stepsize AKA heun! (BM)
- */
- SoftBody *sb= ob->soft; /* is supposed to be there */
- /*BodyPoint *bproot;*/ /* UNUSED */
- /* float gravity; */ /* UNUSED */
- /* float iks; */
- float fieldfactor = -1.0f, windfactor = 0.25;
- int do_deflector /*, do_selfcollision*/, do_springcollision, do_aero;
-
- /* gravity = sb->grav * sb_grav_force_scale(ob); */ /* UNUSED */
-
- /* check conditions for various options */
- do_deflector= query_external_colliders(depsgraph, sb->collision_group);
- /* do_selfcollision=((ob->softflag & OB_SB_EDGES) && (sb->bspring)&& (ob->softflag & OB_SB_SELF)); */ /* UNUSED */
- do_springcollision=do_deflector && (ob->softflag & OB_SB_EDGES) &&(ob->softflag & OB_SB_EDGECOLL);
- do_aero=((sb->aeroedge)&& (ob->softflag & OB_SB_EDGES));
-
- /* iks = 1.0f/(1.0f-sb->inspring)-1.0f; */ /* inner spring constants function */ /* UNUSED */
- /* bproot= sb->bpoint; */ /* need this for proper spring addressing */ /* UNUSED */
-
- if (do_springcollision || do_aero)
- sb_sfesf_threads_run(depsgraph, scene, ob, timenow, sb->totspring, NULL);
-
- /* after spring scan because it uses Effoctors too */
- ListBase *effectors = BKE_effectors_create(depsgraph, ob, NULL, sb->effector_weights);
-
- if (do_deflector) {
- float defforce[3];
- do_deflector = sb_detect_aabb_collisionCached(defforce, ob, timenow);
- }
-
- sb_cf_threads_run(scene, ob, forcetime, timenow, sb->totpoint, NULL, effectors, do_deflector, fieldfactor, windfactor);
-
- /* finally add forces caused by face collision */
- if (ob->softflag & OB_SB_FACECOLL) scan_for_ext_face_forces(ob, timenow);
-
- /* finish matrix and solve */
- BKE_effectors_free(effectors);
+ SB_thread_context *pctx = (SB_thread_context *)data;
+ _softbody_calc_forces_slice_in_a_thread(pctx->scene,
+ pctx->ob,
+ pctx->forcetime,
+ pctx->timenow,
+ pctx->ifirst,
+ pctx->ilast,
+ NULL,
+ pctx->effectors,
+ pctx->do_deflector,
+ pctx->fieldfactor,
+ pctx->windfactor);
+ return NULL;
+}
+
+static void sb_cf_threads_run(Scene *scene,
+ Object *ob,
+ float forcetime,
+ float timenow,
+ int totpoint,
+ int *UNUSED(ptr_to_break_func(void)),
+ struct ListBase *effectors,
+ int do_deflector,
+ float fieldfactor,
+ float windfactor)
+{
+ ListBase threads;
+ SB_thread_context *sb_threads;
+ int i, totthread, left, dec;
+ int lowpoints =
+ 100; /* wild guess .. may increase with better thread management 'above' or even be UI option sb->spawn_cf_threads_nopts */
+
+ /* figure the number of threads while preventing pretty pointless threading overhead */
+ totthread = BKE_scene_num_threads(scene);
+ /* what if we got zillions of CPUs running but less to spread*/
+ while ((totpoint / totthread < lowpoints) && (totthread > 1)) {
+ totthread--;
+ }
+
+ /* printf("sb_cf_threads_run spawning %d threads\n", totthread); */
+
+ sb_threads = MEM_callocN(sizeof(SB_thread_context) * totthread, "SBThread");
+ memset(sb_threads, 0, sizeof(SB_thread_context) * totthread);
+ left = totpoint;
+ dec = totpoint / totthread + 1;
+ for (i = 0; i < totthread; i++) {
+ sb_threads[i].scene = scene;
+ sb_threads[i].ob = ob;
+ sb_threads[i].forcetime = forcetime;
+ sb_threads[i].timenow = timenow;
+ sb_threads[i].ilast = left;
+ left = left - dec;
+ if (left > 0) {
+ sb_threads[i].ifirst = left;
+ }
+ else
+ sb_threads[i].ifirst = 0;
+ sb_threads[i].effectors = effectors;
+ sb_threads[i].do_deflector = do_deflector;
+ sb_threads[i].fieldfactor = fieldfactor;
+ sb_threads[i].windfactor = windfactor;
+ sb_threads[i].nr = i;
+ sb_threads[i].tot = totthread;
+ }
+
+ if (totthread > 1) {
+ BLI_threadpool_init(&threads, exec_softbody_calc_forces, totthread);
+
+ for (i = 0; i < totthread; i++)
+ BLI_threadpool_insert(&threads, &sb_threads[i]);
+
+ BLI_threadpool_end(&threads);
+ }
+ else
+ exec_softbody_calc_forces(&sb_threads[0]);
+ /* clean up */
+ MEM_freeN(sb_threads);
+}
+
+static void softbody_calc_forces(
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob, float forcetime, float timenow)
+{
+ /* rule we never alter free variables :bp->vec bp->pos in here !
+ * this will ruin adaptive stepsize AKA heun! (BM)
+ */
+ SoftBody *sb = ob->soft; /* is supposed to be there */
+ /*BodyPoint *bproot;*/ /* UNUSED */
+ /* float gravity; */ /* UNUSED */
+ /* float iks; */
+ float fieldfactor = -1.0f, windfactor = 0.25;
+ int do_deflector /*, do_selfcollision*/, do_springcollision, do_aero;
+
+ /* gravity = sb->grav * sb_grav_force_scale(ob); */ /* UNUSED */
+
+ /* check conditions for various options */
+ do_deflector = query_external_colliders(depsgraph, sb->collision_group);
+ /* do_selfcollision=((ob->softflag & OB_SB_EDGES) && (sb->bspring)&& (ob->softflag & OB_SB_SELF)); */ /* UNUSED */
+ do_springcollision = do_deflector && (ob->softflag & OB_SB_EDGES) &&
+ (ob->softflag & OB_SB_EDGECOLL);
+ do_aero = ((sb->aeroedge) && (ob->softflag & OB_SB_EDGES));
+
+ /* iks = 1.0f/(1.0f-sb->inspring)-1.0f; */ /* inner spring constants function */ /* UNUSED */
+ /* bproot= sb->bpoint; */ /* need this for proper spring addressing */ /* UNUSED */
+
+ if (do_springcollision || do_aero)
+ sb_sfesf_threads_run(depsgraph, scene, ob, timenow, sb->totspring, NULL);
+
+ /* after spring scan because it uses Effoctors too */
+ ListBase *effectors = BKE_effectors_create(depsgraph, ob, NULL, sb->effector_weights);
+
+ if (do_deflector) {
+ float defforce[3];
+ do_deflector = sb_detect_aabb_collisionCached(defforce, ob, timenow);
+ }
+
+ sb_cf_threads_run(scene,
+ ob,
+ forcetime,
+ timenow,
+ sb->totpoint,
+ NULL,
+ effectors,
+ do_deflector,
+ fieldfactor,
+ windfactor);
+
+ /* finally add forces caused by face collision */
+ if (ob->softflag & OB_SB_FACECOLL)
+ scan_for_ext_face_forces(ob, timenow);
+
+ /* finish matrix and solve */
+ BKE_effectors_free(effectors);
}
static void softbody_apply_forces(Object *ob, float forcetime, int mode, float *err, int mid_flags)
{
- /* time evolution */
- /* actually does an explicit euler step mode == 0 */
- /* or heun ~ 2nd order runge-kutta steps, mode 1, 2 */
- SoftBody *sb= ob->soft; /* is supposed to be there */
- BodyPoint *bp;
- float dx[3] = {0}, dv[3], aabbmin[3], aabbmax[3], cm[3] = {0.0f, 0.0f, 0.0f};
- float timeovermass/*, freezeloc=0.00001f, freezeforce=0.00000000001f*/;
- float maxerrpos= 0.0f, maxerrvel = 0.0f;
- int a, fuzzy=0;
+ /* time evolution */
+ /* actually does an explicit euler step mode == 0 */
+ /* or heun ~ 2nd order runge-kutta steps, mode 1, 2 */
+ SoftBody *sb = ob->soft; /* is supposed to be there */
+ BodyPoint *bp;
+ float dx[3] = {0}, dv[3], aabbmin[3], aabbmax[3], cm[3] = {0.0f, 0.0f, 0.0f};
+ float timeovermass /*, freezeloc=0.00001f, freezeforce=0.00000000001f*/;
+ float maxerrpos = 0.0f, maxerrvel = 0.0f;
+ int a, fuzzy = 0;
- forcetime *= sb_time_scale(ob);
+ forcetime *= sb_time_scale(ob);
- aabbmin[0]=aabbmin[1]=aabbmin[2] = 1e20f;
- aabbmax[0]=aabbmax[1]=aabbmax[2] = -1e20f;
+ aabbmin[0] = aabbmin[1] = aabbmin[2] = 1e20f;
+ aabbmax[0] = aabbmax[1] = aabbmax[2] = -1e20f;
- /* old one with homogeneous masses */
- /* claim a minimum mass for vertex */
+ /* old one with homogeneous masses */
+ /* claim a minimum mass for vertex */
#if 0
- if (sb->nodemass > 0.009999f) timeovermass = forcetime / sb->nodemass;
- else timeovermass = forcetime / 0.009999f;
+ if (sb->nodemass > 0.009999f) timeovermass = forcetime / sb->nodemass;
+ else timeovermass = forcetime / 0.009999f;
#endif
- for (a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
-/* now we have individual masses */
-/* claim a minimum mass for vertex */
- if (_final_mass(ob, bp) > 0.009999f) timeovermass = forcetime/_final_mass(ob, bp);
- else timeovermass = forcetime/0.009999f;
-
-
- if (_final_goal(ob, bp) < SOFTGOALSNAP) {
- /* this makes t~ = t */
- if (mid_flags & MID_PRESERVE) copy_v3_v3(dx, bp->vec);
-
- /* so here is (v)' = a(cceleration) = sum(F_springs)/m + gravitation + some friction forces + more forces*/
- /* the ( ... )' operator denotes derivate respective time */
- /* the euler step for velocity then becomes */
- /* v(t + dt) = v(t) + a(t) * dt */
- mul_v3_fl(bp->force, timeovermass);/* individual mass of node here */
- /* some nasty if's to have heun in here too */
- copy_v3_v3(dv, bp->force);
-
- if (mode == 1) {
- copy_v3_v3(bp->prevvec, bp->vec);
- copy_v3_v3(bp->prevdv, dv);
- }
-
- if (mode ==2) {
- /* be optimistic and execute step */
- bp->vec[0] = bp->prevvec[0] + 0.5f * (dv[0] + bp->prevdv[0]);
- bp->vec[1] = bp->prevvec[1] + 0.5f * (dv[1] + bp->prevdv[1]);
- bp->vec[2] = bp->prevvec[2] + 0.5f * (dv[2] + bp->prevdv[2]);
- /* compare euler to heun to estimate error for step sizing */
- maxerrvel = max_ff(maxerrvel, fabsf(dv[0] - bp->prevdv[0]));
- maxerrvel = max_ff(maxerrvel, fabsf(dv[1] - bp->prevdv[1]));
- maxerrvel = max_ff(maxerrvel, fabsf(dv[2] - bp->prevdv[2]));
- }
- else { add_v3_v3(bp->vec, bp->force); }
-
- /* this makes t~ = t+dt */
- if (!(mid_flags & MID_PRESERVE)) copy_v3_v3(dx, bp->vec);
-
- /* so here is (x)'= v(elocity) */
- /* the euler step for location then becomes */
- /* x(t + dt) = x(t) + v(t~) * dt */
- mul_v3_fl(dx, forcetime);
-
- /* the freezer coming sooner or later */
+ for (a = sb->totpoint, bp = sb->bpoint; a > 0; a--, bp++) {
+ /* now we have individual masses */
+ /* claim a minimum mass for vertex */
+ if (_final_mass(ob, bp) > 0.009999f)
+ timeovermass = forcetime / _final_mass(ob, bp);
+ else
+ timeovermass = forcetime / 0.009999f;
+
+ if (_final_goal(ob, bp) < SOFTGOALSNAP) {
+ /* this makes t~ = t */
+ if (mid_flags & MID_PRESERVE)
+ copy_v3_v3(dx, bp->vec);
+
+ /* so here is (v)' = a(cceleration) = sum(F_springs)/m + gravitation + some friction forces + more forces*/
+ /* the ( ... )' operator denotes derivate respective time */
+ /* the euler step for velocity then becomes */
+ /* v(t + dt) = v(t) + a(t) * dt */
+ mul_v3_fl(bp->force, timeovermass); /* individual mass of node here */
+ /* some nasty if's to have heun in here too */
+ copy_v3_v3(dv, bp->force);
+
+ if (mode == 1) {
+ copy_v3_v3(bp->prevvec, bp->vec);
+ copy_v3_v3(bp->prevdv, dv);
+ }
+
+ if (mode == 2) {
+ /* be optimistic and execute step */
+ bp->vec[0] = bp->prevvec[0] + 0.5f * (dv[0] + bp->prevdv[0]);
+ bp->vec[1] = bp->prevvec[1] + 0.5f * (dv[1] + bp->prevdv[1]);
+ bp->vec[2] = bp->prevvec[2] + 0.5f * (dv[2] + bp->prevdv[2]);
+ /* compare euler to heun to estimate error for step sizing */
+ maxerrvel = max_ff(maxerrvel, fabsf(dv[0] - bp->prevdv[0]));
+ maxerrvel = max_ff(maxerrvel, fabsf(dv[1] - bp->prevdv[1]));
+ maxerrvel = max_ff(maxerrvel, fabsf(dv[2] - bp->prevdv[2]));
+ }
+ else {
+ add_v3_v3(bp->vec, bp->force);
+ }
+
+ /* this makes t~ = t+dt */
+ if (!(mid_flags & MID_PRESERVE))
+ copy_v3_v3(dx, bp->vec);
+
+ /* so here is (x)'= v(elocity) */
+ /* the euler step for location then becomes */
+ /* x(t + dt) = x(t) + v(t~) * dt */
+ mul_v3_fl(dx, forcetime);
+
+ /* the freezer coming sooner or later */
#if 0
- if ((dot_v3v3(dx, dx)<freezeloc )&&(dot_v3v3(bp->force, bp->force)<freezeforce )) {
- bp->frozen /=2;
- }
- else {
- bp->frozen = min_ff(bp->frozen*1.05f, 1.0f);
- }
- mul_v3_fl(dx, bp->frozen);
+ if ((dot_v3v3(dx, dx)<freezeloc )&&(dot_v3v3(bp->force, bp->force)<freezeforce )) {
+ bp->frozen /=2;
+ }
+ else {
+ bp->frozen = min_ff(bp->frozen*1.05f, 1.0f);
+ }
+ mul_v3_fl(dx, bp->frozen);
#endif
- /* again some nasty if's to have heun in here too */
- if (mode ==1) {
- copy_v3_v3(bp->prevpos, bp->pos);
- copy_v3_v3(bp->prevdx, dx);
- }
-
- if (mode ==2) {
- bp->pos[0] = bp->prevpos[0] + 0.5f * ( dx[0] + bp->prevdx[0]);
- bp->pos[1] = bp->prevpos[1] + 0.5f * ( dx[1] + bp->prevdx[1]);
- bp->pos[2] = bp->prevpos[2] + 0.5f * ( dx[2] + bp->prevdx[2]);
- maxerrpos = max_ff(maxerrpos, fabsf(dx[0] - bp->prevdx[0]));
- maxerrpos = max_ff(maxerrpos, fabsf(dx[1] - bp->prevdx[1]));
- maxerrpos = max_ff(maxerrpos, fabsf(dx[2] - bp->prevdx[2]));
-
- /* bp->choke is set when we need to pull a vertex or edge out of the collider.
- * the collider object signals to get out by pushing hard. on the other hand
- * we don't want to end up in deep space so we add some <viscosity>
- * to balance that out */
- if (bp->choke2 > 0.0f) {
- mul_v3_fl(bp->vec, (1.0f - bp->choke2));
- }
- if (bp->choke > 0.0f) {
- mul_v3_fl(bp->vec, (1.0f - bp->choke));
- }
-
- }
- else {
- add_v3_v3(bp->pos, dx);
- }
- }/*snap*/
- /* so while we are looping BPs anyway do statistics on the fly */
- minmax_v3v3_v3(aabbmin, aabbmax, bp->pos);
- if (bp->loc_flag & SBF_DOFUZZY) fuzzy =1;
- } /*for*/
-
- if (sb->totpoint) mul_v3_fl(cm, 1.0f/sb->totpoint);
- if (sb->scratch) {
- copy_v3_v3(sb->scratch->aabbmin, aabbmin);
- copy_v3_v3(sb->scratch->aabbmax, aabbmax);
- }
-
- if (err) { /* so step size will be controlled by biggest difference in slope */
- if (sb->solverflags & SBSO_OLDERR)
- *err = max_ff(maxerrpos, maxerrvel);
- else
- *err = maxerrpos;
- //printf("EP %f EV %f\n", maxerrpos, maxerrvel);
- if (fuzzy) {
- *err /= sb->fuzzyness;
- }
- }
+ /* again some nasty if's to have heun in here too */
+ if (mode == 1) {
+ copy_v3_v3(bp->prevpos, bp->pos);
+ copy_v3_v3(bp->prevdx, dx);
+ }
+
+ if (mode == 2) {
+ bp->pos[0] = bp->prevpos[0] + 0.5f * (dx[0] + bp->prevdx[0]);
+ bp->pos[1] = bp->prevpos[1] + 0.5f * (dx[1] + bp->prevdx[1]);
+ bp->pos[2] = bp->prevpos[2] + 0.5f * (dx[2] + bp->prevdx[2]);
+ maxerrpos = max_ff(maxerrpos, fabsf(dx[0] - bp->prevdx[0]));
+ maxerrpos = max_ff(maxerrpos, fabsf(dx[1] - bp->prevdx[1]));
+ maxerrpos = max_ff(maxerrpos, fabsf(dx[2] - bp->prevdx[2]));
+
+ /* bp->choke is set when we need to pull a vertex or edge out of the collider.
+ * the collider object signals to get out by pushing hard. on the other hand
+ * we don't want to end up in deep space so we add some <viscosity>
+ * to balance that out */
+ if (bp->choke2 > 0.0f) {
+ mul_v3_fl(bp->vec, (1.0f - bp->choke2));
+ }
+ if (bp->choke > 0.0f) {
+ mul_v3_fl(bp->vec, (1.0f - bp->choke));
+ }
+ }
+ else {
+ add_v3_v3(bp->pos, dx);
+ }
+ } /*snap*/
+ /* so while we are looping BPs anyway do statistics on the fly */
+ minmax_v3v3_v3(aabbmin, aabbmax, bp->pos);
+ if (bp->loc_flag & SBF_DOFUZZY)
+ fuzzy = 1;
+ } /*for*/
+
+ if (sb->totpoint)
+ mul_v3_fl(cm, 1.0f / sb->totpoint);
+ if (sb->scratch) {
+ copy_v3_v3(sb->scratch->aabbmin, aabbmin);
+ copy_v3_v3(sb->scratch->aabbmax, aabbmax);
+ }
+
+ if (err) { /* so step size will be controlled by biggest difference in slope */
+ if (sb->solverflags & SBSO_OLDERR)
+ *err = max_ff(maxerrpos, maxerrvel);
+ else
+ *err = maxerrpos;
+ //printf("EP %f EV %f\n", maxerrpos, maxerrvel);
+ if (fuzzy) {
+ *err /= sb->fuzzyness;
+ }
+ }
}
/* used by heun when it overshoots */
static void softbody_restore_prev_step(Object *ob)
{
- SoftBody *sb= ob->soft; /* is supposed to be there*/
- BodyPoint *bp;
- int a;
+ SoftBody *sb = ob->soft; /* is supposed to be there*/
+ BodyPoint *bp;
+ int a;
- for (a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
- copy_v3_v3(bp->vec, bp->prevvec);
- copy_v3_v3(bp->pos, bp->prevpos);
- }
+ for (a = sb->totpoint, bp = sb->bpoint; a > 0; a--, bp++) {
+ copy_v3_v3(bp->vec, bp->prevvec);
+ copy_v3_v3(bp->pos, bp->prevpos);
+ }
}
#if 0
static void softbody_store_step(Object *ob)
{
- SoftBody *sb= ob->soft; /* is supposed to be there*/
- BodyPoint *bp;
- int a;
+ SoftBody *sb= ob->soft; /* is supposed to be there*/
+ BodyPoint *bp;
+ int a;
- for (a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
- copy_v3_v3(bp->prevvec, bp->vec);
- copy_v3_v3(bp->prevpos, bp->pos);
- }
+ for (a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
+ copy_v3_v3(bp->prevvec, bp->vec);
+ copy_v3_v3(bp->prevpos, bp->pos);
+ }
}
/* used by predictors and correctors */
static void softbody_store_state(Object *ob, float *ppos, float *pvel)
{
- SoftBody *sb= ob->soft; /* is supposed to be there*/
- BodyPoint *bp;
- int a;
- float *pp=ppos, *pv=pvel;
+ SoftBody *sb= ob->soft; /* is supposed to be there*/
+ BodyPoint *bp;
+ int a;
+ float *pp=ppos, *pv=pvel;
- for (a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
+ for (a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
- copy_v3_v3(pv, bp->vec);
- pv+=3;
+ copy_v3_v3(pv, bp->vec);
+ pv+=3;
- copy_v3_v3(pp, bp->pos);
- pp+=3;
- }
+ copy_v3_v3(pp, bp->pos);
+ pp+=3;
+ }
}
/* used by predictors and correctors */
static void softbody_retrieve_state(Object *ob, float *ppos, float *pvel)
{
- SoftBody *sb= ob->soft; /* is supposed to be there*/
- BodyPoint *bp;
- int a;
- float *pp=ppos, *pv=pvel;
+ SoftBody *sb= ob->soft; /* is supposed to be there*/
+ BodyPoint *bp;
+ int a;
+ float *pp=ppos, *pv=pvel;
- for (a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
+ for (a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
- copy_v3_v3(bp->vec, pv);
- pv+=3;
+ copy_v3_v3(bp->vec, pv);
+ pv+=3;
- copy_v3_v3(bp->pos, pp);
- pp+=3;
- }
+ copy_v3_v3(bp->pos, pp);
+ pp+=3;
+ }
}
/* used by predictors and correctors */
static void softbody_swap_state(Object *ob, float *ppos, float *pvel)
{
- SoftBody *sb= ob->soft; /* is supposed to be there*/
- BodyPoint *bp;
- int a;
- float *pp=ppos, *pv=pvel;
- float temp[3];
+ SoftBody *sb= ob->soft; /* is supposed to be there*/
+ BodyPoint *bp;
+ int a;
+ float *pp=ppos, *pv=pvel;
+ float temp[3];
- for (a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
+ for (a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
- copy_v3_v3(temp, bp->vec);
- copy_v3_v3(bp->vec, pv);
- copy_v3_v3(pv, temp);
- pv+=3;
+ copy_v3_v3(temp, bp->vec);
+ copy_v3_v3(bp->vec, pv);
+ copy_v3_v3(pv, temp);
+ pv+=3;
- copy_v3_v3(temp, bp->pos);
- copy_v3_v3(bp->pos, pp);
- copy_v3_v3(pp, temp);
- pp+=3;
- }
+ copy_v3_v3(temp, bp->pos);
+ copy_v3_v3(bp->pos, pp);
+ copy_v3_v3(pp, temp);
+ pp+=3;
+ }
}
#endif
-
/* care for bodypoints taken out of the 'ordinary' solver step
* because they are screwed to goal by bolts
* they just need to move along with the goal in time
@@ -2445,66 +2496,63 @@ static void softbody_swap_state(Object *ob, float *ppos, float *pvel)
*/
static void softbody_apply_goalsnap(Object *ob)
{
- SoftBody *sb= ob->soft; /* is supposed to be there */
- BodyPoint *bp;
- int a;
+ SoftBody *sb = ob->soft; /* is supposed to be there */
+ BodyPoint *bp;
+ int a;
- for (a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
- if (_final_goal(ob, bp) >= SOFTGOALSNAP) {
- copy_v3_v3(bp->prevpos, bp->pos);
- copy_v3_v3(bp->pos, bp->origT);
- }
- }
+ for (a = sb->totpoint, bp = sb->bpoint; a > 0; a--, bp++) {
+ if (_final_goal(ob, bp) >= SOFTGOALSNAP) {
+ copy_v3_v3(bp->prevpos, bp->pos);
+ copy_v3_v3(bp->pos, bp->origT);
+ }
+ }
}
-
static void apply_spring_memory(Object *ob)
{
- SoftBody *sb = ob->soft;
- BodySpring *bs;
- BodyPoint *bp1, *bp2;
- int a;
- float b, l, r;
-
- if (sb && sb->totspring) {
- b = sb->plastic;
- for (a=0; a<sb->totspring; a++) {
- bs = &sb->bspring[a];
- bp1 =&sb->bpoint[bs->v1];
- bp2 =&sb->bpoint[bs->v2];
- l = len_v3v3(bp1->pos, bp2->pos);
- r = bs->len/l;
- if (( r > 1.05f) || (r < 0.95f)) {
- bs->len = ((100.0f - b) * bs->len + b*l)/100.0f;
- }
- }
- }
+ SoftBody *sb = ob->soft;
+ BodySpring *bs;
+ BodyPoint *bp1, *bp2;
+ int a;
+ float b, l, r;
+
+ if (sb && sb->totspring) {
+ b = sb->plastic;
+ for (a = 0; a < sb->totspring; a++) {
+ bs = &sb->bspring[a];
+ bp1 = &sb->bpoint[bs->v1];
+ bp2 = &sb->bpoint[bs->v2];
+ l = len_v3v3(bp1->pos, bp2->pos);
+ r = bs->len / l;
+ if ((r > 1.05f) || (r < 0.95f)) {
+ bs->len = ((100.0f - b) * bs->len + b * l) / 100.0f;
+ }
+ }
+ }
}
/* expects full initialized softbody */
static void interpolate_exciter(Object *ob, int timescale, int time)
{
- SoftBody *sb= ob->soft;
- BodyPoint *bp;
- float f;
- int a;
-
- f = (float)time/(float)timescale;
+ SoftBody *sb = ob->soft;
+ BodyPoint *bp;
+ float f;
+ int a;
- for (a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
- bp->origT[0] = bp->origS[0] + f*(bp->origE[0] - bp->origS[0]);
- bp->origT[1] = bp->origS[1] + f*(bp->origE[1] - bp->origS[1]);
- bp->origT[2] = bp->origS[2] + f*(bp->origE[2] - bp->origS[2]);
- if (_final_goal(ob, bp) >= SOFTGOALSNAP) {
- bp->vec[0] = bp->origE[0] - bp->origS[0];
- bp->vec[1] = bp->origE[1] - bp->origS[1];
- bp->vec[2] = bp->origE[2] - bp->origS[2];
- }
- }
+ f = (float)time / (float)timescale;
+ for (a = sb->totpoint, bp = sb->bpoint; a > 0; a--, bp++) {
+ bp->origT[0] = bp->origS[0] + f * (bp->origE[0] - bp->origS[0]);
+ bp->origT[1] = bp->origS[1] + f * (bp->origE[1] - bp->origS[1]);
+ bp->origT[2] = bp->origS[2] + f * (bp->origE[2] - bp->origS[2]);
+ if (_final_goal(ob, bp) >= SOFTGOALSNAP) {
+ bp->vec[0] = bp->origE[0] - bp->origS[0];
+ bp->vec[1] = bp->origE[1] - bp->origS[1];
+ bp->vec[2] = bp->origE[2] - bp->origS[2];
+ }
+ }
}
-
/* ************ convertors ********** */
/* for each object type we need;
@@ -2515,174 +2563,168 @@ static void interpolate_exciter(Object *ob, int timescale, int time)
/* Spring length are caculted from'raw' mesh vertices that are NOT altered by modifier stack. */
static void springs_from_mesh(Object *ob)
{
- SoftBody *sb;
- Mesh *me= ob->data;
- BodyPoint *bp;
- int a;
- float scale =1.0f;
-
- sb= ob->soft;
- if (me && sb) {
- /* using bp->origS as a container for spring calculations here
- * will be overwritten sbObjectStep() to receive
- * actual modifier stack positions
- */
- if (me->totvert) {
- bp= ob->soft->bpoint;
- for (a=0; a<me->totvert; a++, bp++) {
- copy_v3_v3(bp->origS, me->mvert[a].co);
- mul_m4_v3(ob->obmat, bp->origS);
- }
-
- }
- /* recalculate spring length for meshes here */
- /* public version shrink to fit */
- if (sb->springpreload != 0 ) {
- scale = sb->springpreload / 100.0f;
- }
- for (a=0; a<sb->totspring; a++) {
- BodySpring *bs = &sb->bspring[a];
- bs->len= scale*len_v3v3(sb->bpoint[bs->v1].origS, sb->bpoint[bs->v2].origS);
- }
- }
+ SoftBody *sb;
+ Mesh *me = ob->data;
+ BodyPoint *bp;
+ int a;
+ float scale = 1.0f;
+
+ sb = ob->soft;
+ if (me && sb) {
+ /* using bp->origS as a container for spring calculations here
+ * will be overwritten sbObjectStep() to receive
+ * actual modifier stack positions
+ */
+ if (me->totvert) {
+ bp = ob->soft->bpoint;
+ for (a = 0; a < me->totvert; a++, bp++) {
+ copy_v3_v3(bp->origS, me->mvert[a].co);
+ mul_m4_v3(ob->obmat, bp->origS);
+ }
+ }
+ /* recalculate spring length for meshes here */
+ /* public version shrink to fit */
+ if (sb->springpreload != 0) {
+ scale = sb->springpreload / 100.0f;
+ }
+ for (a = 0; a < sb->totspring; a++) {
+ BodySpring *bs = &sb->bspring[a];
+ bs->len = scale * len_v3v3(sb->bpoint[bs->v1].origS, sb->bpoint[bs->v2].origS);
+ }
+ }
}
-
-
-
/* makes totally fresh start situation */
static void mesh_to_softbody(Scene *scene, Object *ob)
{
- SoftBody *sb;
- Mesh *me= ob->data;
- MEdge *medge= me->medge;
- BodyPoint *bp;
- BodySpring *bs;
- int a, totedge;
- int defgroup_index, defgroup_index_mass, defgroup_index_spring;
-
- if (ob->softflag & OB_SB_EDGES) totedge= me->totedge;
- else totedge= 0;
-
- /* renew ends with ob->soft with points and edges, also checks & makes ob->soft */
- renew_softbody(scene, ob, me->totvert, totedge);
-
- /* we always make body points */
- sb = ob->soft;
- bp= sb->bpoint;
-
- defgroup_index = me->dvert ? (sb->vertgroup - 1) : -1;
- defgroup_index_mass = me->dvert ? defgroup_name_index(ob, sb->namedVG_Mass) : -1;
- defgroup_index_spring = me->dvert ? defgroup_name_index(ob, sb->namedVG_Spring_K) : -1;
-
- for (a=0; a<me->totvert; a++, bp++) {
- /* get scalar values needed *per vertex* from vertex group functions,
- * so we can *paint* them nicly ..
- * they are normalized [0.0..1.0] so may be we need amplitude for scale
- * which can be done by caller but still .. i'd like it to go this way
- */
-
- if (ob->softflag & OB_SB_GOAL) {
- BLI_assert(bp->goal == sb->defgoal);
- }
- if ((ob->softflag & OB_SB_GOAL) && (defgroup_index != -1)) {
- bp->goal *= defvert_find_weight(&me->dvert[a], defgroup_index);
- }
-
- /* to proof the concept
- * this enables per vertex *mass painting*
- */
-
- if (defgroup_index_mass != -1) {
- bp->mass *= defvert_find_weight(&me->dvert[a], defgroup_index_mass);
- }
-
- if (defgroup_index_spring != -1) {
- bp->springweight *= defvert_find_weight(&me->dvert[a], defgroup_index_spring);
- }
- }
-
- /* but we only optionally add body edge springs */
- if (ob->softflag & OB_SB_EDGES) {
- if (medge) {
- bs= sb->bspring;
- for (a=me->totedge; a>0; a--, medge++, bs++) {
- bs->v1= medge->v1;
- bs->v2= medge->v2;
- bs->springtype=SB_EDGE;
- }
-
-
- /* insert *diagonal* springs in quads if desired */
- if (ob->softflag & OB_SB_QUADS) {
- add_mesh_quad_diag_springs(ob);
- }
-
- build_bps_springlist(ob); /* scan for springs attached to bodypoints ONCE */
- /* insert *other second order* springs if desired */
- if (sb->secondspring > 0.0000001f) {
- add_2nd_order_springs(ob, sb->secondspring); /* exploits the first run of build_bps_springlist(ob);*/
- build_bps_springlist(ob); /* yes we need to do it again*/
- }
- springs_from_mesh(ob); /* write the 'rest'-length of the springs */
- if (ob->softflag & OB_SB_SELF) { calculate_collision_balls(ob); }
-
- }
-
- }
-
+ SoftBody *sb;
+ Mesh *me = ob->data;
+ MEdge *medge = me->medge;
+ BodyPoint *bp;
+ BodySpring *bs;
+ int a, totedge;
+ int defgroup_index, defgroup_index_mass, defgroup_index_spring;
+
+ if (ob->softflag & OB_SB_EDGES)
+ totedge = me->totedge;
+ else
+ totedge = 0;
+
+ /* renew ends with ob->soft with points and edges, also checks & makes ob->soft */
+ renew_softbody(scene, ob, me->totvert, totedge);
+
+ /* we always make body points */
+ sb = ob->soft;
+ bp = sb->bpoint;
+
+ defgroup_index = me->dvert ? (sb->vertgroup - 1) : -1;
+ defgroup_index_mass = me->dvert ? defgroup_name_index(ob, sb->namedVG_Mass) : -1;
+ defgroup_index_spring = me->dvert ? defgroup_name_index(ob, sb->namedVG_Spring_K) : -1;
+
+ for (a = 0; a < me->totvert; a++, bp++) {
+ /* get scalar values needed *per vertex* from vertex group functions,
+ * so we can *paint* them nicly ..
+ * they are normalized [0.0..1.0] so may be we need amplitude for scale
+ * which can be done by caller but still .. i'd like it to go this way
+ */
+
+ if (ob->softflag & OB_SB_GOAL) {
+ BLI_assert(bp->goal == sb->defgoal);
+ }
+ if ((ob->softflag & OB_SB_GOAL) && (defgroup_index != -1)) {
+ bp->goal *= defvert_find_weight(&me->dvert[a], defgroup_index);
+ }
+
+ /* to proof the concept
+ * this enables per vertex *mass painting*
+ */
+
+ if (defgroup_index_mass != -1) {
+ bp->mass *= defvert_find_weight(&me->dvert[a], defgroup_index_mass);
+ }
+
+ if (defgroup_index_spring != -1) {
+ bp->springweight *= defvert_find_weight(&me->dvert[a], defgroup_index_spring);
+ }
+ }
+
+ /* but we only optionally add body edge springs */
+ if (ob->softflag & OB_SB_EDGES) {
+ if (medge) {
+ bs = sb->bspring;
+ for (a = me->totedge; a > 0; a--, medge++, bs++) {
+ bs->v1 = medge->v1;
+ bs->v2 = medge->v2;
+ bs->springtype = SB_EDGE;
+ }
+
+ /* insert *diagonal* springs in quads if desired */
+ if (ob->softflag & OB_SB_QUADS) {
+ add_mesh_quad_diag_springs(ob);
+ }
+
+ build_bps_springlist(ob); /* scan for springs attached to bodypoints ONCE */
+ /* insert *other second order* springs if desired */
+ if (sb->secondspring > 0.0000001f) {
+ add_2nd_order_springs(
+ ob, sb->secondspring); /* exploits the first run of build_bps_springlist(ob);*/
+ build_bps_springlist(ob); /* yes we need to do it again*/
+ }
+ springs_from_mesh(ob); /* write the 'rest'-length of the springs */
+ if (ob->softflag & OB_SB_SELF) {
+ calculate_collision_balls(ob);
+ }
+ }
+ }
}
static void mesh_faces_to_scratch(Object *ob)
{
- SoftBody *sb= ob->soft;
- const Mesh *me = ob->data;
- MLoopTri *looptri, *lt;
- BodyFace *bodyface;
- int a;
- /* alloc and copy faces*/
-
- sb->scratch->totface = poly_to_tri_count(me->totpoly, me->totloop);
- looptri = lt = MEM_mallocN(sizeof(*looptri) * sb->scratch->totface, __func__);
- BKE_mesh_recalc_looptri(
- me->mloop, me->mpoly,
- me->mvert,
- me->totloop, me->totpoly,
- looptri);
-
- bodyface = sb->scratch->bodyface = MEM_mallocN(sizeof(BodyFace) * sb->scratch->totface, "SB_body_Faces");
-
- for (a = 0; a < sb->scratch->totface; a++, lt++, bodyface++) {
- bodyface->v1 = me->mloop[lt->tri[0]].v;
- bodyface->v2 = me->mloop[lt->tri[1]].v;
- bodyface->v3 = me->mloop[lt->tri[2]].v;
- zero_v3(bodyface->ext_force);
- bodyface->ext_force[0] = bodyface->ext_force[1] = bodyface->ext_force[2] = 0.0f;
- bodyface->flag = 0;
- }
-
- MEM_freeN(looptri);
+ SoftBody *sb = ob->soft;
+ const Mesh *me = ob->data;
+ MLoopTri *looptri, *lt;
+ BodyFace *bodyface;
+ int a;
+ /* alloc and copy faces*/
+
+ sb->scratch->totface = poly_to_tri_count(me->totpoly, me->totloop);
+ looptri = lt = MEM_mallocN(sizeof(*looptri) * sb->scratch->totface, __func__);
+ BKE_mesh_recalc_looptri(me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, looptri);
+
+ bodyface = sb->scratch->bodyface = MEM_mallocN(sizeof(BodyFace) * sb->scratch->totface,
+ "SB_body_Faces");
+
+ for (a = 0; a < sb->scratch->totface; a++, lt++, bodyface++) {
+ bodyface->v1 = me->mloop[lt->tri[0]].v;
+ bodyface->v2 = me->mloop[lt->tri[1]].v;
+ bodyface->v3 = me->mloop[lt->tri[2]].v;
+ zero_v3(bodyface->ext_force);
+ bodyface->ext_force[0] = bodyface->ext_force[1] = bodyface->ext_force[2] = 0.0f;
+ bodyface->flag = 0;
+ }
+
+ MEM_freeN(looptri);
}
static void reference_to_scratch(Object *ob)
{
- SoftBody *sb= ob->soft;
- ReferenceVert *rp;
- BodyPoint *bp;
- float accu_pos[3] ={0.f, 0.f, 0.f};
- float accu_mass = 0.f;
- int a;
-
- sb->scratch->Ref.ivert = MEM_mallocN(sizeof(ReferenceVert)*sb->totpoint, "SB_Reference");
- bp= ob->soft->bpoint;
- rp= sb->scratch->Ref.ivert;
- for (a=0; a<sb->totpoint; a++, rp++, bp++) {
- copy_v3_v3(rp->pos, bp->pos);
- add_v3_v3(accu_pos, bp->pos);
- accu_mass += _final_mass(ob, bp);
- }
- mul_v3_fl(accu_pos, 1.0f/accu_mass);
- copy_v3_v3(sb->scratch->Ref.com, accu_pos);
- /* printf("reference_to_scratch\n"); */
+ SoftBody *sb = ob->soft;
+ ReferenceVert *rp;
+ BodyPoint *bp;
+ float accu_pos[3] = {0.f, 0.f, 0.f};
+ float accu_mass = 0.f;
+ int a;
+
+ sb->scratch->Ref.ivert = MEM_mallocN(sizeof(ReferenceVert) * sb->totpoint, "SB_Reference");
+ bp = ob->soft->bpoint;
+ rp = sb->scratch->Ref.ivert;
+ for (a = 0; a < sb->totpoint; a++, rp++, bp++) {
+ copy_v3_v3(rp->pos, bp->pos);
+ add_v3_v3(accu_pos, bp->pos);
+ accu_mass += _final_mass(ob, bp);
+ }
+ mul_v3_fl(accu_pos, 1.0f / accu_mass);
+ copy_v3_v3(sb->scratch->Ref.com, accu_pos);
+ /* printf("reference_to_scratch\n"); */
}
/*
@@ -2691,284 +2733,284 @@ static void reference_to_scratch(Object *ob)
*/
static float globallen(float *v1, float *v2, Object *ob)
{
- float p1[3], p2[3];
- copy_v3_v3(p1, v1);
- mul_m4_v3(ob->obmat, p1);
- copy_v3_v3(p2, v2);
- mul_m4_v3(ob->obmat, p2);
- return len_v3v3(p1, p2);
-}
-
-static void makelatticesprings(Lattice *lt, BodySpring *bs, int dostiff, Object *ob)
-{
- BPoint *bp=lt->def, *bpu;
- int u, v, w, dv, dw, bpc=0, bpuc;
-
- dv= lt->pntsu;
- dw= dv*lt->pntsv;
-
- for (w=0; w<lt->pntsw; w++) {
-
- for (v=0; v<lt->pntsv; v++) {
-
- for (u=0, bpuc=0, bpu=NULL; u<lt->pntsu; u++, bp++, bpc++) {
-
- if (w) {
- bs->v1 = bpc;
- bs->v2 = bpc-dw;
- bs->springtype=SB_EDGE;
- bs->len= globallen((bp-dw)->vec, bp->vec, ob);
- bs++;
- }
- if (v) {
- bs->v1 = bpc;
- bs->v2 = bpc-dv;
- bs->springtype=SB_EDGE;
- bs->len= globallen((bp-dv)->vec, bp->vec, ob);
- bs++;
- }
- if (u) {
- bs->v1 = bpuc;
- bs->v2 = bpc;
- bs->springtype=SB_EDGE;
- bs->len= globallen((bpu)->vec, bp->vec, ob);
- bs++;
- }
-
- if (dostiff) {
-
- if (w) {
- if ( v && u ) {
- bs->v1 = bpc;
- bs->v2 = bpc-dw-dv-1;
- bs->springtype=SB_BEND;
- bs->len= globallen((bp-dw-dv-1)->vec, bp->vec, ob);
- bs++;
- }
- if ( (v < lt->pntsv-1) && (u != 0) ) {
- bs->v1 = bpc;
- bs->v2 = bpc-dw+dv-1;
- bs->springtype=SB_BEND;
- bs->len= globallen((bp-dw+dv-1)->vec, bp->vec, ob);
- bs++;
- }
- }
-
- if (w < lt->pntsw -1) {
- if ( v && u ) {
- bs->v1 = bpc;
- bs->v2 = bpc+dw-dv-1;
- bs->springtype=SB_BEND;
- bs->len= globallen((bp+dw-dv-1)->vec, bp->vec, ob);
- bs++;
- }
- if ( (v < lt->pntsv-1) && (u != 0) ) {
- bs->v1 = bpc;
- bs->v2 = bpc+dw+dv-1;
- bs->springtype=SB_BEND;
- bs->len= globallen((bp+dw+dv-1)->vec, bp->vec, ob);
- bs++;
- }
- }
- }
- bpu = bp;
- bpuc = bpc;
- }
- }
- }
+ float p1[3], p2[3];
+ copy_v3_v3(p1, v1);
+ mul_m4_v3(ob->obmat, p1);
+ copy_v3_v3(p2, v2);
+ mul_m4_v3(ob->obmat, p2);
+ return len_v3v3(p1, p2);
+}
+
+static void makelatticesprings(Lattice *lt, BodySpring *bs, int dostiff, Object *ob)
+{
+ BPoint *bp = lt->def, *bpu;
+ int u, v, w, dv, dw, bpc = 0, bpuc;
+
+ dv = lt->pntsu;
+ dw = dv * lt->pntsv;
+
+ for (w = 0; w < lt->pntsw; w++) {
+
+ for (v = 0; v < lt->pntsv; v++) {
+
+ for (u = 0, bpuc = 0, bpu = NULL; u < lt->pntsu; u++, bp++, bpc++) {
+
+ if (w) {
+ bs->v1 = bpc;
+ bs->v2 = bpc - dw;
+ bs->springtype = SB_EDGE;
+ bs->len = globallen((bp - dw)->vec, bp->vec, ob);
+ bs++;
+ }
+ if (v) {
+ bs->v1 = bpc;
+ bs->v2 = bpc - dv;
+ bs->springtype = SB_EDGE;
+ bs->len = globallen((bp - dv)->vec, bp->vec, ob);
+ bs++;
+ }
+ if (u) {
+ bs->v1 = bpuc;
+ bs->v2 = bpc;
+ bs->springtype = SB_EDGE;
+ bs->len = globallen((bpu)->vec, bp->vec, ob);
+ bs++;
+ }
+
+ if (dostiff) {
+
+ if (w) {
+ if (v && u) {
+ bs->v1 = bpc;
+ bs->v2 = bpc - dw - dv - 1;
+ bs->springtype = SB_BEND;
+ bs->len = globallen((bp - dw - dv - 1)->vec, bp->vec, ob);
+ bs++;
+ }
+ if ((v < lt->pntsv - 1) && (u != 0)) {
+ bs->v1 = bpc;
+ bs->v2 = bpc - dw + dv - 1;
+ bs->springtype = SB_BEND;
+ bs->len = globallen((bp - dw + dv - 1)->vec, bp->vec, ob);
+ bs++;
+ }
+ }
+
+ if (w < lt->pntsw - 1) {
+ if (v && u) {
+ bs->v1 = bpc;
+ bs->v2 = bpc + dw - dv - 1;
+ bs->springtype = SB_BEND;
+ bs->len = globallen((bp + dw - dv - 1)->vec, bp->vec, ob);
+ bs++;
+ }
+ if ((v < lt->pntsv - 1) && (u != 0)) {
+ bs->v1 = bpc;
+ bs->v2 = bpc + dw + dv - 1;
+ bs->springtype = SB_BEND;
+ bs->len = globallen((bp + dw + dv - 1)->vec, bp->vec, ob);
+ bs++;
+ }
+ }
+ }
+ bpu = bp;
+ bpuc = bpc;
+ }
+ }
+ }
}
-
/* makes totally fresh start situation */
static void lattice_to_softbody(Scene *scene, Object *ob)
{
- Lattice *lt= ob->data;
- SoftBody *sb;
- int totvert, totspring = 0, a;
- BodyPoint *bp;
- BPoint *bpnt = lt->def;
- int defgroup_index, defgroup_index_mass, defgroup_index_spring;
-
- totvert= lt->pntsu*lt->pntsv*lt->pntsw;
-
- if (ob->softflag & OB_SB_EDGES) {
- totspring = ((lt->pntsu - 1) * lt->pntsv +
- (lt->pntsv - 1) * lt->pntsu) * lt->pntsw +
- lt->pntsu*lt->pntsv * (lt->pntsw - 1);
- if (ob->softflag & OB_SB_QUADS) {
- totspring += 4 * (lt->pntsu - 1) * (lt->pntsv -1) * (lt->pntsw - 1);
- }
- }
-
-
- /* renew ends with ob->soft with points and edges, also checks & makes ob->soft */
- renew_softbody(scene, ob, totvert, totspring);
- sb= ob->soft; /* can be created in renew_softbody() */
- bp = sb->bpoint;
-
- defgroup_index = lt->dvert ? (sb->vertgroup - 1) : -1;
- defgroup_index_mass = lt->dvert ? defgroup_name_index(ob, sb->namedVG_Mass) : -1;
- defgroup_index_spring = lt->dvert ? defgroup_name_index(ob, sb->namedVG_Spring_K) : -1;
-
- /* same code used as for mesh vertices */
- for (a = 0; a < totvert; a++, bp++, bpnt++) {
-
- if (ob->softflag & OB_SB_GOAL) {
- BLI_assert(bp->goal == sb->defgoal);
- }
-
- if ((ob->softflag & OB_SB_GOAL) && (defgroup_index != -1)) {
- bp->goal *= defvert_find_weight(&lt->dvert[a], defgroup_index);
- }
- else {
- bp->goal *= bpnt->weight;
- }
-
- if (defgroup_index_mass != -1) {
- bp->mass *= defvert_find_weight(&lt->dvert[a], defgroup_index_mass);
- }
-
- if (defgroup_index_spring != -1) {
- bp->springweight *= defvert_find_weight(&lt->dvert[a], defgroup_index_spring);
- }
- }
-
-
- /* create some helper edges to enable SB lattice to be useful at all */
- if (ob->softflag & OB_SB_EDGES) {
- makelatticesprings(lt, ob->soft->bspring, ob->softflag & OB_SB_QUADS, ob);
- build_bps_springlist(ob); /* link bps to springs */
- }
+ Lattice *lt = ob->data;
+ SoftBody *sb;
+ int totvert, totspring = 0, a;
+ BodyPoint *bp;
+ BPoint *bpnt = lt->def;
+ int defgroup_index, defgroup_index_mass, defgroup_index_spring;
+
+ totvert = lt->pntsu * lt->pntsv * lt->pntsw;
+
+ if (ob->softflag & OB_SB_EDGES) {
+ totspring = ((lt->pntsu - 1) * lt->pntsv + (lt->pntsv - 1) * lt->pntsu) * lt->pntsw +
+ lt->pntsu * lt->pntsv * (lt->pntsw - 1);
+ if (ob->softflag & OB_SB_QUADS) {
+ totspring += 4 * (lt->pntsu - 1) * (lt->pntsv - 1) * (lt->pntsw - 1);
+ }
+ }
+
+ /* renew ends with ob->soft with points and edges, also checks & makes ob->soft */
+ renew_softbody(scene, ob, totvert, totspring);
+ sb = ob->soft; /* can be created in renew_softbody() */
+ bp = sb->bpoint;
+
+ defgroup_index = lt->dvert ? (sb->vertgroup - 1) : -1;
+ defgroup_index_mass = lt->dvert ? defgroup_name_index(ob, sb->namedVG_Mass) : -1;
+ defgroup_index_spring = lt->dvert ? defgroup_name_index(ob, sb->namedVG_Spring_K) : -1;
+
+ /* same code used as for mesh vertices */
+ for (a = 0; a < totvert; a++, bp++, bpnt++) {
+
+ if (ob->softflag & OB_SB_GOAL) {
+ BLI_assert(bp->goal == sb->defgoal);
+ }
+
+ if ((ob->softflag & OB_SB_GOAL) && (defgroup_index != -1)) {
+ bp->goal *= defvert_find_weight(&lt->dvert[a], defgroup_index);
+ }
+ else {
+ bp->goal *= bpnt->weight;
+ }
+
+ if (defgroup_index_mass != -1) {
+ bp->mass *= defvert_find_weight(&lt->dvert[a], defgroup_index_mass);
+ }
+
+ if (defgroup_index_spring != -1) {
+ bp->springweight *= defvert_find_weight(&lt->dvert[a], defgroup_index_spring);
+ }
+ }
+
+ /* create some helper edges to enable SB lattice to be useful at all */
+ if (ob->softflag & OB_SB_EDGES) {
+ makelatticesprings(lt, ob->soft->bspring, ob->softflag & OB_SB_QUADS, ob);
+ build_bps_springlist(ob); /* link bps to springs */
+ }
}
/* makes totally fresh start situation */
static void curve_surf_to_softbody(Scene *scene, Object *ob)
{
- Curve *cu= ob->data;
- SoftBody *sb;
- BodyPoint *bp;
- BodySpring *bs;
- Nurb *nu;
- BezTriple *bezt;
- BPoint *bpnt;
- int a, curindex=0;
- int totvert, totspring = 0, setgoal=0;
-
- totvert= BKE_nurbList_verts_count(&cu->nurb);
-
- if (ob->softflag & OB_SB_EDGES) {
- if (ob->type==OB_CURVE) {
- totspring = totvert - BLI_listbase_count(&cu->nurb);
- }
- }
-
- /* renew ends with ob->soft with points and edges, also checks & makes ob->soft */
- renew_softbody(scene, ob, totvert, totspring);
- sb= ob->soft; /* can be created in renew_softbody() */
-
- /* set vars now */
- bp= sb->bpoint;
- bs= sb->bspring;
-
- /* weights from bpoints, same code used as for mesh vertices */
- /* if ((ob->softflag & OB_SB_GOAL) && sb->vertgroup) 2.4x hack*/
- /* new! take the weights from curve vertex anyhow */
- if (ob->softflag & OB_SB_GOAL)
- setgoal= 1;
-
- for (nu= cu->nurb.first; nu; nu= nu->next) {
- if (nu->bezt) {
- /* bezier case ; this is nicly said naive; who ever wrote this part, it was not me (JOW) :) */
- /* a: never ever make tangent handles (sub) and or (ob)ject to collision */
- /* b: rather calculate them using some C2 (C2= continuous in second derivate -> no jump in bending ) condition */
- /* not too hard to do, but needs some more code to care for; some one may want look at it JOW 2010/06/12*/
- for (bezt=nu->bezt, a=0; a<nu->pntsu; a++, bezt++, bp+=3, curindex+=3) {
- if (setgoal) {
- bp->goal *= bezt->weight;
-
- /* all three triples */
- (bp+1)->goal= bp->goal;
- (bp+2)->goal= bp->goal;
- /*do not collide handles */
- (bp+1)->loc_flag |= SBF_OUTOFCOLLISION;
- (bp+2)->loc_flag |= SBF_OUTOFCOLLISION;
- }
-
- if (totspring) {
- if (a>0) {
- bs->v1= curindex-3;
- bs->v2= curindex;
- bs->springtype=SB_HANDLE;
- bs->len = globallen((bezt-1)->vec[0], bezt->vec[0], ob);
- bs++;
- }
- bs->v1= curindex;
- bs->v2= curindex+1;
- bs->springtype=SB_HANDLE;
- bs->len = globallen(bezt->vec[0], bezt->vec[1], ob);
- bs++;
-
- bs->v1= curindex+1;
- bs->v2= curindex+2;
- bs->springtype=SB_HANDLE;
- bs->len = globallen(bezt->vec[1], bezt->vec[2], ob);
- bs++;
- }
- }
- }
- else {
- for (bpnt=nu->bp, a=0; a<nu->pntsu*nu->pntsv; a++, bpnt++, bp++, curindex++) {
- if (setgoal) {
- bp->goal *= bpnt->weight;
- }
- if (totspring && a>0) {
- bs->v1= curindex-1;
- bs->v2= curindex;
- bs->springtype=SB_EDGE;
- bs->len= globallen( (bpnt-1)->vec, bpnt->vec, ob );
- bs++;
- }
- }
- }
- }
-
- if (totspring) {
- build_bps_springlist(ob); /* link bps to springs */
- if (ob->softflag & OB_SB_SELF) { calculate_collision_balls(ob); }
- }
+ Curve *cu = ob->data;
+ SoftBody *sb;
+ BodyPoint *bp;
+ BodySpring *bs;
+ Nurb *nu;
+ BezTriple *bezt;
+ BPoint *bpnt;
+ int a, curindex = 0;
+ int totvert, totspring = 0, setgoal = 0;
+
+ totvert = BKE_nurbList_verts_count(&cu->nurb);
+
+ if (ob->softflag & OB_SB_EDGES) {
+ if (ob->type == OB_CURVE) {
+ totspring = totvert - BLI_listbase_count(&cu->nurb);
+ }
+ }
+
+ /* renew ends with ob->soft with points and edges, also checks & makes ob->soft */
+ renew_softbody(scene, ob, totvert, totspring);
+ sb = ob->soft; /* can be created in renew_softbody() */
+
+ /* set vars now */
+ bp = sb->bpoint;
+ bs = sb->bspring;
+
+ /* weights from bpoints, same code used as for mesh vertices */
+ /* if ((ob->softflag & OB_SB_GOAL) && sb->vertgroup) 2.4x hack*/
+ /* new! take the weights from curve vertex anyhow */
+ if (ob->softflag & OB_SB_GOAL)
+ setgoal = 1;
+
+ for (nu = cu->nurb.first; nu; nu = nu->next) {
+ if (nu->bezt) {
+ /* bezier case ; this is nicly said naive; who ever wrote this part, it was not me (JOW) :) */
+ /* a: never ever make tangent handles (sub) and or (ob)ject to collision */
+ /* b: rather calculate them using some C2 (C2= continuous in second derivate -> no jump in bending ) condition */
+ /* not too hard to do, but needs some more code to care for; some one may want look at it JOW 2010/06/12*/
+ for (bezt = nu->bezt, a = 0; a < nu->pntsu; a++, bezt++, bp += 3, curindex += 3) {
+ if (setgoal) {
+ bp->goal *= bezt->weight;
+
+ /* all three triples */
+ (bp + 1)->goal = bp->goal;
+ (bp + 2)->goal = bp->goal;
+ /*do not collide handles */
+ (bp + 1)->loc_flag |= SBF_OUTOFCOLLISION;
+ (bp + 2)->loc_flag |= SBF_OUTOFCOLLISION;
+ }
+
+ if (totspring) {
+ if (a > 0) {
+ bs->v1 = curindex - 3;
+ bs->v2 = curindex;
+ bs->springtype = SB_HANDLE;
+ bs->len = globallen((bezt - 1)->vec[0], bezt->vec[0], ob);
+ bs++;
+ }
+ bs->v1 = curindex;
+ bs->v2 = curindex + 1;
+ bs->springtype = SB_HANDLE;
+ bs->len = globallen(bezt->vec[0], bezt->vec[1], ob);
+ bs++;
+
+ bs->v1 = curindex + 1;
+ bs->v2 = curindex + 2;
+ bs->springtype = SB_HANDLE;
+ bs->len = globallen(bezt->vec[1], bezt->vec[2], ob);
+ bs++;
+ }
+ }
+ }
+ else {
+ for (bpnt = nu->bp, a = 0; a < nu->pntsu * nu->pntsv; a++, bpnt++, bp++, curindex++) {
+ if (setgoal) {
+ bp->goal *= bpnt->weight;
+ }
+ if (totspring && a > 0) {
+ bs->v1 = curindex - 1;
+ bs->v2 = curindex;
+ bs->springtype = SB_EDGE;
+ bs->len = globallen((bpnt - 1)->vec, bpnt->vec, ob);
+ bs++;
+ }
+ }
+ }
+ }
+
+ if (totspring) {
+ build_bps_springlist(ob); /* link bps to springs */
+ if (ob->softflag & OB_SB_SELF) {
+ calculate_collision_balls(ob);
+ }
+ }
}
/* copies softbody result back in object */
static void softbody_to_object(Object *ob, float (*vertexCos)[3], int numVerts, int local)
{
- SoftBody *sb= ob->soft;
- if (sb) {
- BodyPoint *bp= sb->bpoint;
- int a;
- if (sb->solverflags & SBSO_ESTIMATEIPO) {SB_estimate_transform(ob, sb->lcom, sb->lrot, sb->lscale);}
- /* inverse matrix is not uptodate... */
- invert_m4_m4(ob->imat, ob->obmat);
+ SoftBody *sb = ob->soft;
+ if (sb) {
+ BodyPoint *bp = sb->bpoint;
+ int a;
+ if (sb->solverflags & SBSO_ESTIMATEIPO) {
+ SB_estimate_transform(ob, sb->lcom, sb->lrot, sb->lscale);
+ }
+ /* inverse matrix is not uptodate... */
+ invert_m4_m4(ob->imat, ob->obmat);
- for (a=0; a<numVerts; a++, bp++) {
- copy_v3_v3(vertexCos[a], bp->pos);
- if (local==0)
- mul_m4_v3(ob->imat, vertexCos[a]); /* softbody is in global coords, baked optionally not */
- }
- }
+ for (a = 0; a < numVerts; a++, bp++) {
+ copy_v3_v3(vertexCos[a], bp->pos);
+ if (local == 0)
+ mul_m4_v3(ob->imat, vertexCos[a]); /* softbody is in global coords, baked optionally not */
+ }
+ }
}
/* +++ ************ maintaining scratch *************** */
static void sb_new_scratch(SoftBody *sb)
{
- if (!sb) return;
- sb->scratch = MEM_callocN(sizeof(SBScratch), "SBScratch");
- sb->scratch->colliderhash = BLI_ghash_ptr_new("sb_new_scratch gh");
- sb->scratch->bodyface = NULL;
- sb->scratch->totface = 0;
- sb->scratch->aabbmax[0]=sb->scratch->aabbmax[1]=sb->scratch->aabbmax[2] = 1.0e30f;
- sb->scratch->aabbmin[0]=sb->scratch->aabbmin[1]=sb->scratch->aabbmin[2] = -1.0e30f;
- sb->scratch->Ref.ivert = NULL;
-
+ if (!sb)
+ return;
+ sb->scratch = MEM_callocN(sizeof(SBScratch), "SBScratch");
+ sb->scratch->colliderhash = BLI_ghash_ptr_new("sb_new_scratch gh");
+ sb->scratch->bodyface = NULL;
+ sb->scratch->totface = 0;
+ sb->scratch->aabbmax[0] = sb->scratch->aabbmax[1] = sb->scratch->aabbmax[2] = 1.0e30f;
+ sb->scratch->aabbmin[0] = sb->scratch->aabbmin[1] = sb->scratch->aabbmin[2] = -1.0e30f;
+ sb->scratch->Ref.ivert = NULL;
}
/* --- ************ maintaining scratch *************** */
@@ -2977,134 +3019,135 @@ static void sb_new_scratch(SoftBody *sb)
/* allocates and initializes general main data */
SoftBody *sbNew(Scene *scene)
{
- SoftBody *sb;
-
- sb= MEM_callocN(sizeof(SoftBody), "softbody");
+ SoftBody *sb;
- sb->mediafrict= 0.5f;
- sb->nodemass= 1.0f;
- sb->grav= 9.8f;
- sb->physics_speed= 1.0f;
- sb->rklimit= 0.1f;
+ sb = MEM_callocN(sizeof(SoftBody), "softbody");
- sb->goalspring= 0.5f;
- sb->goalfrict= 0.0f;
- sb->mingoal= 0.0f;
- sb->maxgoal= 1.0f;
- sb->defgoal= 0.7f;
+ sb->mediafrict = 0.5f;
+ sb->nodemass = 1.0f;
+ sb->grav = 9.8f;
+ sb->physics_speed = 1.0f;
+ sb->rklimit = 0.1f;
- sb->inspring= 0.5f;
- sb->infrict= 0.5f;
- /*todo backward file compat should copy inspring to inpush while reading old files*/
- sb->inpush = 0.5f;
+ sb->goalspring = 0.5f;
+ sb->goalfrict = 0.0f;
+ sb->mingoal = 0.0f;
+ sb->maxgoal = 1.0f;
+ sb->defgoal = 0.7f;
- sb->interval= 10;
- sb->sfra= scene->r.sfra;
- sb->efra= scene->r.efra;
+ sb->inspring = 0.5f;
+ sb->infrict = 0.5f;
+ /*todo backward file compat should copy inspring to inpush while reading old files*/
+ sb->inpush = 0.5f;
- sb->colball = 0.49f;
- sb->balldamp = 0.50f;
- sb->ballstiff= 1.0f;
- sb->sbc_mode = 1;
+ sb->interval = 10;
+ sb->sfra = scene->r.sfra;
+ sb->efra = scene->r.efra;
+ sb->colball = 0.49f;
+ sb->balldamp = 0.50f;
+ sb->ballstiff = 1.0f;
+ sb->sbc_mode = 1;
- sb->minloops = 10;
- sb->maxloops = 300;
+ sb->minloops = 10;
+ sb->maxloops = 300;
- sb->choke = 3;
- sb_new_scratch(sb);
- /*todo backward file compat should set sb->shearstiff = 1.0f while reading old files*/
- sb->shearstiff = 1.0f;
- sb->solverflags |= SBSO_OLDERR;
+ sb->choke = 3;
+ sb_new_scratch(sb);
+ /*todo backward file compat should set sb->shearstiff = 1.0f while reading old files*/
+ sb->shearstiff = 1.0f;
+ sb->solverflags |= SBSO_OLDERR;
- sb->shared = MEM_callocN(sizeof(*sb->shared), "SoftBody_Shared");
- sb->shared->pointcache = BKE_ptcache_add(&sb->shared->ptcaches);
+ sb->shared = MEM_callocN(sizeof(*sb->shared), "SoftBody_Shared");
+ sb->shared->pointcache = BKE_ptcache_add(&sb->shared->ptcaches);
- if (!sb->effector_weights)
- sb->effector_weights = BKE_effector_add_weights(NULL);
+ if (!sb->effector_weights)
+ sb->effector_weights = BKE_effector_add_weights(NULL);
- sb->last_frame= MINFRAME-1;
+ sb->last_frame = MINFRAME - 1;
- return sb;
+ return sb;
}
/* frees all */
void sbFree(Object *ob)
{
- SoftBody *sb = ob->soft;
- if (sb == NULL) {
- return;
- }
+ SoftBody *sb = ob->soft;
+ if (sb == NULL) {
+ return;
+ }
- free_softbody_intern(sb);
+ free_softbody_intern(sb);
- if ((ob->id.tag & LIB_TAG_NO_MAIN) == 0) {
- /* Only free shared data on non-CoW copies */
- BKE_ptcache_free_list(&sb->shared->ptcaches);
- sb->shared->pointcache = NULL;
- MEM_freeN(sb->shared);
- }
- if (sb->effector_weights)
- MEM_freeN(sb->effector_weights);
- MEM_freeN(sb);
+ if ((ob->id.tag & LIB_TAG_NO_MAIN) == 0) {
+ /* Only free shared data on non-CoW copies */
+ BKE_ptcache_free_list(&sb->shared->ptcaches);
+ sb->shared->pointcache = NULL;
+ MEM_freeN(sb->shared);
+ }
+ if (sb->effector_weights)
+ MEM_freeN(sb->effector_weights);
+ MEM_freeN(sb);
- ob->soft = NULL;
+ ob->soft = NULL;
}
void sbFreeSimulation(SoftBody *sb)
{
- free_softbody_intern(sb);
+ free_softbody_intern(sb);
}
/* makes totally fresh start situation */
void sbObjectToSoftbody(Object *ob)
{
- //ob->softflag |= OB_SB_REDO;
+ //ob->softflag |= OB_SB_REDO;
- free_softbody_intern(ob->soft);
+ free_softbody_intern(ob->soft);
}
static int object_has_edges(Object *ob)
{
- if (ob->type==OB_MESH) {
- return ((Mesh*) ob->data)->totedge;
- }
- else if (ob->type==OB_LATTICE) {
- return 1;
- }
- else {
- return 0;
- }
+ if (ob->type == OB_MESH) {
+ return ((Mesh *)ob->data)->totedge;
+ }
+ else if (ob->type == OB_LATTICE) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
}
/* SB global visible functions */
void sbSetInterruptCallBack(int (*f)(void))
{
- SB_localInterruptCallBack = f;
+ SB_localInterruptCallBack = f;
}
-static void softbody_update_positions(Object *ob, SoftBody *sb, float (*vertexCos)[3], int numVerts)
+static void softbody_update_positions(Object *ob,
+ SoftBody *sb,
+ float (*vertexCos)[3],
+ int numVerts)
{
- BodyPoint *bp;
- int a;
+ BodyPoint *bp;
+ int a;
- if (!sb || !sb->bpoint)
- return;
+ if (!sb || !sb->bpoint)
+ return;
- for (a=0, bp=sb->bpoint; a<numVerts; a++, bp++) {
- /* store where goals are now */
- copy_v3_v3(bp->origS, bp->origE);
- /* copy the position of the goals at desired end time */
- copy_v3_v3(bp->origE, vertexCos[a]);
- /* vertexCos came from local world, go global */
- mul_m4_v3(ob->obmat, bp->origE);
- /* just to be save give bp->origT a defined value
- * will be calculated in interpolate_exciter() */
- copy_v3_v3(bp->origT, bp->origE);
- }
+ for (a = 0, bp = sb->bpoint; a < numVerts; a++, bp++) {
+ /* store where goals are now */
+ copy_v3_v3(bp->origS, bp->origE);
+ /* copy the position of the goals at desired end time */
+ copy_v3_v3(bp->origE, vertexCos[a]);
+ /* vertexCos came from local world, go global */
+ mul_m4_v3(ob->obmat, bp->origE);
+ /* just to be save give bp->origT a defined value
+ * will be calculated in interpolate_exciter() */
+ copy_v3_v3(bp->origT, bp->origE);
+ }
}
-
/* void SB_estimate_transform */
/* input Object *ob out (says any object that can do SB like mesh, lattice, curve )
* output float lloc[3], float lrot[3][3], float lscale[3][3]
@@ -3122,366 +3165,383 @@ static void softbody_update_positions(Object *ob, SoftBody *sb, float (*vertexCo
void SB_estimate_transform(Object *ob, float lloc[3], float lrot[3][3], float lscale[3][3])
{
- BodyPoint *bp;
- ReferenceVert *rp;
- SoftBody *sb = NULL;
- float (*opos)[3];
- float (*rpos)[3];
- float com[3], rcom[3];
- int a;
-
- if (!ob ||!ob->soft) return; /* why did we get here ? */
- sb= ob->soft;
- if (!sb || !sb->bpoint) return;
- opos= MEM_callocN((sb->totpoint)*3*sizeof(float), "SB_OPOS");
- rpos= MEM_callocN((sb->totpoint)*3*sizeof(float), "SB_RPOS");
- /* might filter vertex selection with a vertex group */
- for (a=0, bp=sb->bpoint, rp=sb->scratch->Ref.ivert; a<sb->totpoint; a++, bp++, rp++) {
- copy_v3_v3(rpos[a], rp->pos);
- copy_v3_v3(opos[a], bp->pos);
- }
-
- vcloud_estimate_transform_v3(sb->totpoint, opos, NULL, rpos, NULL, com, rcom, lrot, lscale);
- //sub_v3_v3(com, rcom);
- if (lloc) copy_v3_v3(lloc, com);
- copy_v3_v3(sb->lcom, com);
- if (lscale) copy_m3_m3(sb->lscale, lscale);
- if (lrot) copy_m3_m3(sb->lrot, lrot);
-
-
- MEM_freeN(opos);
- MEM_freeN(rpos);
+ BodyPoint *bp;
+ ReferenceVert *rp;
+ SoftBody *sb = NULL;
+ float(*opos)[3];
+ float(*rpos)[3];
+ float com[3], rcom[3];
+ int a;
+
+ if (!ob || !ob->soft)
+ return; /* why did we get here ? */
+ sb = ob->soft;
+ if (!sb || !sb->bpoint)
+ return;
+ opos = MEM_callocN((sb->totpoint) * 3 * sizeof(float), "SB_OPOS");
+ rpos = MEM_callocN((sb->totpoint) * 3 * sizeof(float), "SB_RPOS");
+ /* might filter vertex selection with a vertex group */
+ for (a = 0, bp = sb->bpoint, rp = sb->scratch->Ref.ivert; a < sb->totpoint; a++, bp++, rp++) {
+ copy_v3_v3(rpos[a], rp->pos);
+ copy_v3_v3(opos[a], bp->pos);
+ }
+
+ vcloud_estimate_transform_v3(sb->totpoint, opos, NULL, rpos, NULL, com, rcom, lrot, lscale);
+ //sub_v3_v3(com, rcom);
+ if (lloc)
+ copy_v3_v3(lloc, com);
+ copy_v3_v3(sb->lcom, com);
+ if (lscale)
+ copy_m3_m3(sb->lscale, lscale);
+ if (lrot)
+ copy_m3_m3(sb->lrot, lrot);
+
+ MEM_freeN(opos);
+ MEM_freeN(rpos);
}
static void softbody_reset(Object *ob, SoftBody *sb, float (*vertexCos)[3], int numVerts)
{
- BodyPoint *bp;
- int a;
-
- for (a=0, bp=sb->bpoint; a<numVerts; a++, bp++) {
- copy_v3_v3(bp->pos, vertexCos[a]);
- mul_m4_v3(ob->obmat, bp->pos); /* yep, sofbody is global coords*/
- copy_v3_v3(bp->origS, bp->pos);
- copy_v3_v3(bp->origE, bp->pos);
- copy_v3_v3(bp->origT, bp->pos);
- bp->vec[0] = bp->vec[1] = bp->vec[2] = 0.0f;
-
- /* the bp->prev*'s are for rolling back from a canceled try to propagate in time
- * adaptive step size algo in a nutshell:
- * 1. set scheduled time step to new dtime
- * 2. try to advance the scheduled time step, being optimistic execute it
- * 3. check for success
- * 3.a we 're fine continue, may be we can increase scheduled time again ?? if so, do so!
- * 3.b we did exceed error limit --> roll back, shorten the scheduled time and try again at 2.
- * 4. check if we did reach dtime
- * 4.a nope we need to do some more at 2.
- * 4.b yup we're done
- */
-
- copy_v3_v3(bp->prevpos, bp->pos);
- copy_v3_v3(bp->prevvec, bp->vec);
- copy_v3_v3(bp->prevdx, bp->vec);
- copy_v3_v3(bp->prevdv, bp->vec);
- }
-
- /* make a nice clean scratch struc */
- free_scratch(sb); /* clear if any */
- sb_new_scratch(sb); /* make a new */
- sb->scratch->needstobuildcollider=1;
- zero_v3(sb->lcom);
- unit_m3(sb->lrot);
- unit_m3(sb->lscale);
-
-
-
- /* copy some info to scratch */
- /* we only need that if we want to reconstruct IPO */
- if (1) {
- reference_to_scratch(ob);
- SB_estimate_transform(ob, NULL, NULL, NULL);
- SB_estimate_transform(ob, NULL, NULL, NULL);
- }
- switch (ob->type) {
- case OB_MESH:
- if (ob->softflag & OB_SB_FACECOLL) mesh_faces_to_scratch(ob);
- break;
- case OB_LATTICE:
- break;
- case OB_CURVE:
- case OB_SURF:
- break;
- default:
- break;
- }
-}
-
-static void softbody_step(struct Depsgraph *depsgraph, Scene *scene, Object *ob, SoftBody *sb, float dtime)
-{
- /* the simulator */
- float forcetime;
- double sct, sst;
-
-
- sst=PIL_check_seconds_timer();
- /* Integration back in time is possible in theory, but pretty useless here.
- * So we refuse to do so. Since we do not know anything about 'outside' changes
- * especially colliders we refuse to go more than 10 frames.
- */
- if (dtime < 0 || dtime > 10.5f) return;
-
- ccd_update_deflector_hash(depsgraph, sb->collision_group, ob, sb->scratch->colliderhash);
-
- if (sb->scratch->needstobuildcollider) {
- ccd_build_deflector_hash(depsgraph, sb->collision_group, ob, sb->scratch->colliderhash);
- sb->scratch->needstobuildcollider=0;
- }
-
- if (sb->solver_ID < 2) {
- /* special case of 2nd order Runge-Kutta type AKA Heun */
- int mid_flags=0;
- float err = 0;
- float forcetimemax = 1.0f; /* set defaults guess we shall do one frame */
- float forcetimemin = 0.01f; /* set defaults guess 1/100 is tight enough */
- float timedone =0.0; /* how far did we get without violating error condition */
- /* loops = counter for emergency brake
- * we don't want to lock up the system if physics fail */
- int loops = 0;
-
- SoftHeunTol = sb->rklimit; /* humm .. this should be calculated from sb parameters and sizes */
- /* adjust loop limits */
- if (sb->minloops > 0) forcetimemax = dtime / sb->minloops;
- if (sb->maxloops > 0) forcetimemin = dtime / sb->maxloops;
-
- if (sb->solver_ID>0) mid_flags |= MID_PRESERVE;
-
- forcetime = forcetimemax; /* hope for integrating in one step */
- while ( (ABS(timedone) < ABS(dtime)) && (loops < 2000) ) {
- /* set goals in time */
- interpolate_exciter(ob, 200, (int)(200.0f*(timedone/dtime)));
-
- sb->scratch->flag &= ~SBF_DOFUZZY;
- /* do predictive euler step */
- softbody_calc_forces(depsgraph, scene, ob, forcetime, timedone/dtime);
-
- softbody_apply_forces(ob, forcetime, 1, NULL, mid_flags);
-
- /* crop new slope values to do averaged slope step */
- softbody_calc_forces(depsgraph, scene, ob, forcetime, timedone/dtime);
-
- softbody_apply_forces(ob, forcetime, 2, &err, mid_flags);
- softbody_apply_goalsnap(ob);
-
- if (err > SoftHeunTol) { /* error needs to be scaled to some quantity */
-
- if (forcetime > forcetimemin) {
- forcetime = max_ff(forcetime / 2.0f, forcetimemin);
- softbody_restore_prev_step(ob);
- //printf("down, ");
- }
- else {
- timedone += forcetime;
- }
- }
- else {
- float newtime = forcetime * 1.1f; /* hope for 1.1 times better conditions in next step */
-
- if (sb->scratch->flag & SBF_DOFUZZY) {
- //if (err > SoftHeunTol/(2.0f*sb->fuzzyness)) { /* stay with this stepsize unless err really small */
- newtime = forcetime;
- //}
- }
- else {
- if (err > SoftHeunTol/2.0f) { /* stay with this stepsize unless err really small */
- newtime = forcetime;
- }
- }
- timedone += forcetime;
- newtime = min_ff(forcetimemax, max_ff(newtime, forcetimemin));
- //if (newtime > forcetime) printf("up, ");
- if (forcetime > 0.0f)
- forcetime = min_ff(dtime - timedone, newtime);
- else
- forcetime = max_ff(dtime - timedone, newtime);
- }
- loops++;
- if (sb->solverflags & SBSO_MONITOR ) {
- sct = PIL_check_seconds_timer();
- if (sct - sst > 0.5) printf("%3.0f%% \r", 100.0f * timedone / dtime);
- }
- /* ask for user break */
- if (SB_localInterruptCallBack && SB_localInterruptCallBack()) break;
-
- }
- /* move snapped to final position */
- interpolate_exciter(ob, 2, 2);
- softbody_apply_goalsnap(ob);
-
- // if (G.debug & G_DEBUG) {
- if (sb->solverflags & SBSO_MONITOR ) {
- if (loops > HEUNWARNLIMIT) /* monitor high loop counts */
- printf("\r needed %d steps/frame", loops);
- }
-
- }
- else if (sb->solver_ID == 2) {
- /* do semi "fake" implicit euler */
- //removed
- }/*SOLVER SELECT*/
- else if (sb->solver_ID == 4) {
- /* do semi "fake" implicit euler */
- }/*SOLVER SELECT*/
- else if (sb->solver_ID == 3) {
- /* do "stupid" semi "fake" implicit euler */
- //removed
-
- }/*SOLVER SELECT*/
- else {
- CLOG_ERROR(&LOG, "softbody no valid solver ID!");
- }/*SOLVER SELECT*/
- if (sb->plastic) { apply_spring_memory(ob);}
-
- if (sb->solverflags & SBSO_MONITOR ) {
- sct=PIL_check_seconds_timer();
- if ((sct - sst > 0.5) || (G.debug & G_DEBUG)) printf(" solver time %f sec %s\n", sct-sst, ob->id.name);
- }
+ BodyPoint *bp;
+ int a;
+
+ for (a = 0, bp = sb->bpoint; a < numVerts; a++, bp++) {
+ copy_v3_v3(bp->pos, vertexCos[a]);
+ mul_m4_v3(ob->obmat, bp->pos); /* yep, sofbody is global coords*/
+ copy_v3_v3(bp->origS, bp->pos);
+ copy_v3_v3(bp->origE, bp->pos);
+ copy_v3_v3(bp->origT, bp->pos);
+ bp->vec[0] = bp->vec[1] = bp->vec[2] = 0.0f;
+
+ /* the bp->prev*'s are for rolling back from a canceled try to propagate in time
+ * adaptive step size algo in a nutshell:
+ * 1. set scheduled time step to new dtime
+ * 2. try to advance the scheduled time step, being optimistic execute it
+ * 3. check for success
+ * 3.a we 're fine continue, may be we can increase scheduled time again ?? if so, do so!
+ * 3.b we did exceed error limit --> roll back, shorten the scheduled time and try again at 2.
+ * 4. check if we did reach dtime
+ * 4.a nope we need to do some more at 2.
+ * 4.b yup we're done
+ */
+
+ copy_v3_v3(bp->prevpos, bp->pos);
+ copy_v3_v3(bp->prevvec, bp->vec);
+ copy_v3_v3(bp->prevdx, bp->vec);
+ copy_v3_v3(bp->prevdv, bp->vec);
+ }
+
+ /* make a nice clean scratch struc */
+ free_scratch(sb); /* clear if any */
+ sb_new_scratch(sb); /* make a new */
+ sb->scratch->needstobuildcollider = 1;
+ zero_v3(sb->lcom);
+ unit_m3(sb->lrot);
+ unit_m3(sb->lscale);
+
+ /* copy some info to scratch */
+ /* we only need that if we want to reconstruct IPO */
+ if (1) {
+ reference_to_scratch(ob);
+ SB_estimate_transform(ob, NULL, NULL, NULL);
+ SB_estimate_transform(ob, NULL, NULL, NULL);
+ }
+ switch (ob->type) {
+ case OB_MESH:
+ if (ob->softflag & OB_SB_FACECOLL)
+ mesh_faces_to_scratch(ob);
+ break;
+ case OB_LATTICE:
+ break;
+ case OB_CURVE:
+ case OB_SURF:
+ break;
+ default:
+ break;
+ }
+}
+
+static void softbody_step(
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob, SoftBody *sb, float dtime)
+{
+ /* the simulator */
+ float forcetime;
+ double sct, sst;
+
+ sst = PIL_check_seconds_timer();
+ /* Integration back in time is possible in theory, but pretty useless here.
+ * So we refuse to do so. Since we do not know anything about 'outside' changes
+ * especially colliders we refuse to go more than 10 frames.
+ */
+ if (dtime < 0 || dtime > 10.5f)
+ return;
+
+ ccd_update_deflector_hash(depsgraph, sb->collision_group, ob, sb->scratch->colliderhash);
+
+ if (sb->scratch->needstobuildcollider) {
+ ccd_build_deflector_hash(depsgraph, sb->collision_group, ob, sb->scratch->colliderhash);
+ sb->scratch->needstobuildcollider = 0;
+ }
+
+ if (sb->solver_ID < 2) {
+ /* special case of 2nd order Runge-Kutta type AKA Heun */
+ int mid_flags = 0;
+ float err = 0;
+ float forcetimemax = 1.0f; /* set defaults guess we shall do one frame */
+ float forcetimemin = 0.01f; /* set defaults guess 1/100 is tight enough */
+ float timedone = 0.0; /* how far did we get without violating error condition */
+ /* loops = counter for emergency brake
+ * we don't want to lock up the system if physics fail */
+ int loops = 0;
+
+ SoftHeunTol = sb->rklimit; /* humm .. this should be calculated from sb parameters and sizes */
+ /* adjust loop limits */
+ if (sb->minloops > 0)
+ forcetimemax = dtime / sb->minloops;
+ if (sb->maxloops > 0)
+ forcetimemin = dtime / sb->maxloops;
+
+ if (sb->solver_ID > 0)
+ mid_flags |= MID_PRESERVE;
+
+ forcetime = forcetimemax; /* hope for integrating in one step */
+ while ((ABS(timedone) < ABS(dtime)) && (loops < 2000)) {
+ /* set goals in time */
+ interpolate_exciter(ob, 200, (int)(200.0f * (timedone / dtime)));
+
+ sb->scratch->flag &= ~SBF_DOFUZZY;
+ /* do predictive euler step */
+ softbody_calc_forces(depsgraph, scene, ob, forcetime, timedone / dtime);
+
+ softbody_apply_forces(ob, forcetime, 1, NULL, mid_flags);
+
+ /* crop new slope values to do averaged slope step */
+ softbody_calc_forces(depsgraph, scene, ob, forcetime, timedone / dtime);
+
+ softbody_apply_forces(ob, forcetime, 2, &err, mid_flags);
+ softbody_apply_goalsnap(ob);
+
+ if (err > SoftHeunTol) { /* error needs to be scaled to some quantity */
+
+ if (forcetime > forcetimemin) {
+ forcetime = max_ff(forcetime / 2.0f, forcetimemin);
+ softbody_restore_prev_step(ob);
+ //printf("down, ");
+ }
+ else {
+ timedone += forcetime;
+ }
+ }
+ else {
+ float newtime = forcetime * 1.1f; /* hope for 1.1 times better conditions in next step */
+
+ if (sb->scratch->flag & SBF_DOFUZZY) {
+ //if (err > SoftHeunTol/(2.0f*sb->fuzzyness)) { /* stay with this stepsize unless err really small */
+ newtime = forcetime;
+ //}
+ }
+ else {
+ if (err > SoftHeunTol / 2.0f) { /* stay with this stepsize unless err really small */
+ newtime = forcetime;
+ }
+ }
+ timedone += forcetime;
+ newtime = min_ff(forcetimemax, max_ff(newtime, forcetimemin));
+ //if (newtime > forcetime) printf("up, ");
+ if (forcetime > 0.0f)
+ forcetime = min_ff(dtime - timedone, newtime);
+ else
+ forcetime = max_ff(dtime - timedone, newtime);
+ }
+ loops++;
+ if (sb->solverflags & SBSO_MONITOR) {
+ sct = PIL_check_seconds_timer();
+ if (sct - sst > 0.5)
+ printf("%3.0f%% \r", 100.0f * timedone / dtime);
+ }
+ /* ask for user break */
+ if (SB_localInterruptCallBack && SB_localInterruptCallBack())
+ break;
+ }
+ /* move snapped to final position */
+ interpolate_exciter(ob, 2, 2);
+ softbody_apply_goalsnap(ob);
+
+ // if (G.debug & G_DEBUG) {
+ if (sb->solverflags & SBSO_MONITOR) {
+ if (loops > HEUNWARNLIMIT) /* monitor high loop counts */
+ printf("\r needed %d steps/frame", loops);
+ }
+ }
+ else if (sb->solver_ID == 2) {
+ /* do semi "fake" implicit euler */
+ //removed
+ } /*SOLVER SELECT*/
+ else if (sb->solver_ID == 4) {
+ /* do semi "fake" implicit euler */
+ } /*SOLVER SELECT*/
+ else if (sb->solver_ID == 3) {
+ /* do "stupid" semi "fake" implicit euler */
+ //removed
+
+ } /*SOLVER SELECT*/
+ else {
+ CLOG_ERROR(&LOG, "softbody no valid solver ID!");
+ } /*SOLVER SELECT*/
+ if (sb->plastic) {
+ apply_spring_memory(ob);
+ }
+
+ if (sb->solverflags & SBSO_MONITOR) {
+ sct = PIL_check_seconds_timer();
+ if ((sct - sst > 0.5) || (G.debug & G_DEBUG))
+ printf(" solver time %f sec %s\n", sct - sst, ob->id.name);
+ }
}
static void sbStoreLastFrame(struct Depsgraph *depsgraph, Object *object, float framenr)
{
- if (!DEG_is_active(depsgraph)) {
- return;
- }
- Object *object_orig = DEG_get_original_object(object);
- object->soft->last_frame = framenr;
- object_orig->soft->last_frame = framenr;
+ if (!DEG_is_active(depsgraph)) {
+ return;
+ }
+ Object *object_orig = DEG_get_original_object(object);
+ object->soft->last_frame = framenr;
+ object_orig->soft->last_frame = framenr;
}
/* simulates one step. framenr is in frames */
-void sbObjectStep(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], int numVerts)
-{
- SoftBody *sb= ob->soft;
- PointCache *cache;
- PTCacheID pid;
- float dtime, timescale;
- int framedelta, framenr, startframe, endframe;
- int cache_result;
- cache= sb->shared->pointcache;
-
- framenr= (int)cfra;
- framedelta= framenr - cache->simframe;
-
- BKE_ptcache_id_from_softbody(&pid, ob, sb);
- BKE_ptcache_id_time(&pid, scene, framenr, &startframe, &endframe, &timescale);
-
- /* check for changes in mesh, should only happen in case the mesh
- * structure changes during an animation */
- if (sb->bpoint && numVerts != sb->totpoint) {
- BKE_ptcache_invalidate(cache);
- return;
- }
-
- /* clamp frame ranges */
- if (framenr < startframe) {
- BKE_ptcache_invalidate(cache);
- return;
- }
- else if (framenr > endframe) {
- framenr = endframe;
- }
-
- /* verify if we need to create the softbody data */
- if (sb->bpoint == NULL ||
- ((ob->softflag & OB_SB_EDGES) && !ob->soft->bspring && object_has_edges(ob)))
- {
-
- switch (ob->type) {
- case OB_MESH:
- mesh_to_softbody(scene, ob);
- break;
- case OB_LATTICE:
- lattice_to_softbody(scene, ob);
- break;
- case OB_CURVE:
- case OB_SURF:
- curve_surf_to_softbody(scene, ob);
- break;
- default:
- renew_softbody(scene, ob, numVerts, 0);
- break;
- }
-
- softbody_update_positions(ob, sb, vertexCos, numVerts);
- softbody_reset(ob, sb, vertexCos, numVerts);
- }
-
- /* still no points? go away */
- if (sb->totpoint==0) {
- return;
- }
- if (framenr == startframe) {
- BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
-
- /* first frame, no simulation to do, just set the positions */
- softbody_update_positions(ob, sb, vertexCos, numVerts);
-
- BKE_ptcache_validate(cache, framenr);
- cache->flag &= ~PTCACHE_REDO_NEEDED;
-
- sbStoreLastFrame(depsgraph, ob, framenr);
-
- return;
- }
-
- /* try to read from cache */
- bool can_write_cache = DEG_is_active(depsgraph);
- bool can_simulate = (framenr == sb->last_frame + 1) && !(cache->flag & PTCACHE_BAKED) && can_write_cache;
-
- cache_result = BKE_ptcache_read(&pid, (float)framenr+scene->r.subframe, can_simulate);
-
- if (cache_result == PTCACHE_READ_EXACT || cache_result == PTCACHE_READ_INTERPOLATED ||
- (!can_simulate && cache_result == PTCACHE_READ_OLD))
- {
- softbody_to_object(ob, vertexCos, numVerts, sb->local);
-
- BKE_ptcache_validate(cache, framenr);
-
- if (cache_result == PTCACHE_READ_INTERPOLATED && cache->flag & PTCACHE_REDO_NEEDED && can_write_cache)
- BKE_ptcache_write(&pid, framenr);
-
- sbStoreLastFrame(depsgraph, ob, framenr);
-
- return;
- }
- else if (cache_result==PTCACHE_READ_OLD) {
- ; /* do nothing */
- }
- else if (/*ob->id.lib || */(cache->flag & PTCACHE_BAKED)) { /* "library linking & pointcaches" has to be solved properly at some point */
- /* if baked and nothing in cache, do nothing */
- if (can_write_cache) {
- BKE_ptcache_invalidate(cache);
- }
- return;
- }
-
- if (!can_simulate)
- return;
-
- /* if on second frame, write cache for first frame */
- if (cache->simframe == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact==0))
- BKE_ptcache_write(&pid, startframe);
-
- softbody_update_positions(ob, sb, vertexCos, numVerts);
-
- /* checking time: */
- dtime = framedelta*timescale;
-
- /* do simulation */
- softbody_step(depsgraph, scene, ob, sb, dtime);
-
- softbody_to_object(ob, vertexCos, numVerts, 0);
-
- BKE_ptcache_validate(cache, framenr);
- BKE_ptcache_write(&pid, framenr);
-
- sbStoreLastFrame(depsgraph, ob, framenr);
+void sbObjectStep(struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ float cfra,
+ float (*vertexCos)[3],
+ int numVerts)
+{
+ SoftBody *sb = ob->soft;
+ PointCache *cache;
+ PTCacheID pid;
+ float dtime, timescale;
+ int framedelta, framenr, startframe, endframe;
+ int cache_result;
+ cache = sb->shared->pointcache;
+
+ framenr = (int)cfra;
+ framedelta = framenr - cache->simframe;
+
+ BKE_ptcache_id_from_softbody(&pid, ob, sb);
+ BKE_ptcache_id_time(&pid, scene, framenr, &startframe, &endframe, &timescale);
+
+ /* check for changes in mesh, should only happen in case the mesh
+ * structure changes during an animation */
+ if (sb->bpoint && numVerts != sb->totpoint) {
+ BKE_ptcache_invalidate(cache);
+ return;
+ }
+
+ /* clamp frame ranges */
+ if (framenr < startframe) {
+ BKE_ptcache_invalidate(cache);
+ return;
+ }
+ else if (framenr > endframe) {
+ framenr = endframe;
+ }
+
+ /* verify if we need to create the softbody data */
+ if (sb->bpoint == NULL ||
+ ((ob->softflag & OB_SB_EDGES) && !ob->soft->bspring && object_has_edges(ob))) {
+
+ switch (ob->type) {
+ case OB_MESH:
+ mesh_to_softbody(scene, ob);
+ break;
+ case OB_LATTICE:
+ lattice_to_softbody(scene, ob);
+ break;
+ case OB_CURVE:
+ case OB_SURF:
+ curve_surf_to_softbody(scene, ob);
+ break;
+ default:
+ renew_softbody(scene, ob, numVerts, 0);
+ break;
+ }
+
+ softbody_update_positions(ob, sb, vertexCos, numVerts);
+ softbody_reset(ob, sb, vertexCos, numVerts);
+ }
+
+ /* still no points? go away */
+ if (sb->totpoint == 0) {
+ return;
+ }
+ if (framenr == startframe) {
+ BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
+
+ /* first frame, no simulation to do, just set the positions */
+ softbody_update_positions(ob, sb, vertexCos, numVerts);
+
+ BKE_ptcache_validate(cache, framenr);
+ cache->flag &= ~PTCACHE_REDO_NEEDED;
+
+ sbStoreLastFrame(depsgraph, ob, framenr);
+
+ return;
+ }
+
+ /* try to read from cache */
+ bool can_write_cache = DEG_is_active(depsgraph);
+ bool can_simulate = (framenr == sb->last_frame + 1) && !(cache->flag & PTCACHE_BAKED) &&
+ can_write_cache;
+
+ cache_result = BKE_ptcache_read(&pid, (float)framenr + scene->r.subframe, can_simulate);
+
+ if (cache_result == PTCACHE_READ_EXACT || cache_result == PTCACHE_READ_INTERPOLATED ||
+ (!can_simulate && cache_result == PTCACHE_READ_OLD)) {
+ softbody_to_object(ob, vertexCos, numVerts, sb->local);
+
+ BKE_ptcache_validate(cache, framenr);
+
+ if (cache_result == PTCACHE_READ_INTERPOLATED && cache->flag & PTCACHE_REDO_NEEDED &&
+ can_write_cache)
+ BKE_ptcache_write(&pid, framenr);
+
+ sbStoreLastFrame(depsgraph, ob, framenr);
+
+ return;
+ }
+ else if (cache_result == PTCACHE_READ_OLD) {
+ ; /* do nothing */
+ }
+ else if (/*ob->id.lib || */ (
+ cache->flag &
+ PTCACHE_BAKED)) { /* "library linking & pointcaches" has to be solved properly at some point */
+ /* if baked and nothing in cache, do nothing */
+ if (can_write_cache) {
+ BKE_ptcache_invalidate(cache);
+ }
+ return;
+ }
+
+ if (!can_simulate)
+ return;
+
+ /* if on second frame, write cache for first frame */
+ if (cache->simframe == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact == 0))
+ BKE_ptcache_write(&pid, startframe);
+
+ softbody_update_positions(ob, sb, vertexCos, numVerts);
+
+ /* checking time: */
+ dtime = framedelta * timescale;
+
+ /* do simulation */
+ softbody_step(depsgraph, scene, ob, sb, dtime);
+
+ softbody_to_object(ob, vertexCos, numVerts, 0);
+
+ BKE_ptcache_validate(cache, framenr);
+ BKE_ptcache_write(&pid, framenr);
+
+ sbStoreLastFrame(depsgraph, ob, framenr);
}
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index c909f00702d..383542fa335 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -63,86 +63,86 @@ static char **audio_device_names = NULL;
bSound *BKE_sound_new_file(struct Main *bmain, const char *filepath)
{
- bSound *sound;
- const char *path;
- char str[FILE_MAX];
+ bSound *sound;
+ const char *path;
+ char str[FILE_MAX];
- BLI_strncpy(str, filepath, sizeof(str));
+ BLI_strncpy(str, filepath, sizeof(str));
- path = BKE_main_blendfile_path(bmain);
+ path = BKE_main_blendfile_path(bmain);
- BLI_path_abs(str, path);
+ BLI_path_abs(str, path);
- sound = BKE_libblock_alloc(bmain, ID_SO, BLI_path_basename(filepath), 0);
- BLI_strncpy(sound->name, filepath, FILE_MAX);
- /* sound->type = SOUND_TYPE_FILE; */ /* XXX unused currently */
+ sound = BKE_libblock_alloc(bmain, ID_SO, BLI_path_basename(filepath), 0);
+ BLI_strncpy(sound->name, filepath, FILE_MAX);
+ /* sound->type = SOUND_TYPE_FILE; */ /* XXX unused currently */
- BKE_sound_load(bmain, sound);
+ BKE_sound_load(bmain, sound);
- return sound;
+ return sound;
}
bSound *BKE_sound_new_file_exists_ex(struct Main *bmain, const char *filepath, bool *r_exists)
{
- bSound *sound;
- char str[FILE_MAX], strtest[FILE_MAX];
-
- BLI_strncpy(str, filepath, sizeof(str));
- BLI_path_abs(str, BKE_main_blendfile_path(bmain));
-
- /* first search an identical filepath */
- for (sound = bmain->sounds.first; sound; sound = sound->id.next) {
- BLI_strncpy(strtest, sound->name, sizeof(sound->name));
- BLI_path_abs(strtest, ID_BLEND_PATH(bmain, &sound->id));
-
- if (BLI_path_cmp(strtest, str) == 0) {
- id_us_plus(&sound->id); /* officially should not, it doesn't link here! */
- if (r_exists)
- *r_exists = true;
- return sound;
- }
- }
-
- if (r_exists)
- *r_exists = false;
- return BKE_sound_new_file(bmain, filepath);
+ bSound *sound;
+ char str[FILE_MAX], strtest[FILE_MAX];
+
+ BLI_strncpy(str, filepath, sizeof(str));
+ BLI_path_abs(str, BKE_main_blendfile_path(bmain));
+
+ /* first search an identical filepath */
+ for (sound = bmain->sounds.first; sound; sound = sound->id.next) {
+ BLI_strncpy(strtest, sound->name, sizeof(sound->name));
+ BLI_path_abs(strtest, ID_BLEND_PATH(bmain, &sound->id));
+
+ if (BLI_path_cmp(strtest, str) == 0) {
+ id_us_plus(&sound->id); /* officially should not, it doesn't link here! */
+ if (r_exists)
+ *r_exists = true;
+ return sound;
+ }
+ }
+
+ if (r_exists)
+ *r_exists = false;
+ return BKE_sound_new_file(bmain, filepath);
}
bSound *BKE_sound_new_file_exists(struct Main *bmain, const char *filepath)
{
- return BKE_sound_new_file_exists_ex(bmain, filepath, NULL);
+ return BKE_sound_new_file_exists_ex(bmain, filepath, NULL);
}
/** Free (or release) any data used by this sound (does not free the sound itself). */
void BKE_sound_free(bSound *sound)
{
- /* No animdata here. */
+ /* No animdata here. */
- if (sound->packedfile) {
- freePackedFile(sound->packedfile);
- sound->packedfile = NULL;
- }
+ if (sound->packedfile) {
+ freePackedFile(sound->packedfile);
+ sound->packedfile = NULL;
+ }
#ifdef WITH_AUDASPACE
- if (sound->handle) {
- AUD_Sound_free(sound->handle);
- sound->handle = NULL;
- sound->playback_handle = NULL;
- }
-
- if (sound->cache) {
- AUD_Sound_free(sound->cache);
- sound->cache = NULL;
- }
-
- BKE_sound_free_waveform(sound);
-
-#endif /* WITH_AUDASPACE */
- if (sound->spinlock) {
- BLI_spin_end(sound->spinlock);
- MEM_freeN(sound->spinlock);
- sound->spinlock = NULL;
- }
+ if (sound->handle) {
+ AUD_Sound_free(sound->handle);
+ sound->handle = NULL;
+ sound->playback_handle = NULL;
+ }
+
+ if (sound->cache) {
+ AUD_Sound_free(sound->cache);
+ sound->cache = NULL;
+ }
+
+ BKE_sound_free_waveform(sound);
+
+#endif /* WITH_AUDASPACE */
+ if (sound->spinlock) {
+ BLI_spin_end(sound->spinlock);
+ MEM_freeN(sound->spinlock);
+ sound->spinlock = NULL;
+ }
}
/**
@@ -153,833 +153,968 @@ void BKE_sound_free(bSound *sound)
*
* \param flag: Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
*/
-void BKE_sound_copy_data(Main *bmain, bSound *sound_dst, const bSound *UNUSED(sound_src), const int UNUSED(flag))
+void BKE_sound_copy_data(Main *bmain,
+ bSound *sound_dst,
+ const bSound *UNUSED(sound_src),
+ const int UNUSED(flag))
{
- sound_dst->handle = NULL;
- sound_dst->cache = NULL;
- sound_dst->waveform = NULL;
- sound_dst->playback_handle = NULL;
- sound_dst->spinlock = NULL; /* Think this is OK? Otherwise, easy to create new spinlock here... */
-
- /* Just to be sure, should not have any value actually after reading time. */
- sound_dst->ipo = NULL;
- sound_dst->newpackedfile = NULL;
-
- if (sound_dst->packedfile) {
- sound_dst->packedfile = dupPackedFile(sound_dst->packedfile);
- }
-
- /* Initialize whole runtime (audaspace) stuff. */
- BKE_sound_load(bmain, sound_dst);
+ sound_dst->handle = NULL;
+ sound_dst->cache = NULL;
+ sound_dst->waveform = NULL;
+ sound_dst->playback_handle = NULL;
+ sound_dst->spinlock =
+ NULL; /* Think this is OK? Otherwise, easy to create new spinlock here... */
+
+ /* Just to be sure, should not have any value actually after reading time. */
+ sound_dst->ipo = NULL;
+ sound_dst->newpackedfile = NULL;
+
+ if (sound_dst->packedfile) {
+ sound_dst->packedfile = dupPackedFile(sound_dst->packedfile);
+ }
+
+ /* Initialize whole runtime (audaspace) stuff. */
+ BKE_sound_load(bmain, sound_dst);
}
void BKE_sound_make_local(Main *bmain, bSound *sound, const bool lib_local)
{
- BKE_id_make_local_generic(bmain, &sound->id, true, lib_local);
+ BKE_id_make_local_generic(bmain, &sound->id, true, lib_local);
}
#ifdef WITH_AUDASPACE
static const char *force_device = NULL;
-#ifdef WITH_JACK
+# ifdef WITH_JACK
static void sound_sync_callback(void *data, int mode, float time)
{
- // Ugly: Blender doesn't like it when the animation is played back during rendering
- if (G.is_rendering)
- return;
-
- struct Main *bmain = (struct Main *)data;
- struct Scene *scene;
-
- scene = bmain->scenes.first;
- while (scene) {
- if (scene->audio.flag & AUDIO_SYNC) {
- if (mode)
- BKE_sound_play_scene(scene);
- else
- BKE_sound_stop_scene(scene);
- if (scene->playback_handle)
- AUD_Handle_setPosition(scene->playback_handle, time);
- }
- scene = scene->id.next;
- }
+ // Ugly: Blender doesn't like it when the animation is played back during rendering
+ if (G.is_rendering)
+ return;
+
+ struct Main *bmain = (struct Main *)data;
+ struct Scene *scene;
+
+ scene = bmain->scenes.first;
+ while (scene) {
+ if (scene->audio.flag & AUDIO_SYNC) {
+ if (mode)
+ BKE_sound_play_scene(scene);
+ else
+ BKE_sound_stop_scene(scene);
+ if (scene->playback_handle)
+ AUD_Handle_setPosition(scene->playback_handle, time);
+ }
+ scene = scene->id.next;
+ }
}
-#endif
+# endif
void BKE_sound_force_device(const char *device)
{
- force_device = device;
+ force_device = device;
}
void BKE_sound_init_once(void)
{
- AUD_initOnce();
- atexit(BKE_sound_exit_once);
+ AUD_initOnce();
+ atexit(BKE_sound_exit_once);
}
static AUD_Device *sound_device = NULL;
void *BKE_sound_get_device(void)
{
- return sound_device;
+ return sound_device;
}
void BKE_sound_init(struct Main *bmain)
{
- /* Make sure no instance of the sound system is running, otherwise we get leaks. */
- BKE_sound_exit();
-
- AUD_DeviceSpecs specs;
- int device, buffersize;
- const char *device_name;
-
- device = U.audiodevice;
- buffersize = U.mixbufsize;
- specs.channels = U.audiochannels;
- specs.format = U.audioformat;
- specs.rate = U.audiorate;
-
- if (force_device == NULL) {
- int i;
- char **names = BKE_sound_get_device_names();
- device_name = names[0];
-
- /* make sure device is within the bounds of the array */
- for (i = 0; names[i]; i++) {
- if (i == device) {
- device_name = names[i];
- }
- }
- }
- else
- device_name = force_device;
-
- if (buffersize < 128)
- buffersize = 1024;
-
- if (specs.rate < AUD_RATE_8000)
- specs.rate = AUD_RATE_48000;
-
- if (specs.format <= AUD_FORMAT_INVALID)
- specs.format = AUD_FORMAT_S16;
-
- if (specs.channels <= AUD_CHANNELS_INVALID)
- specs.channels = AUD_CHANNELS_STEREO;
-
- if (!(sound_device = AUD_init(device_name, specs, buffersize, "Blender")))
- sound_device = AUD_init("Null", specs, buffersize, "Blender");
-
- BKE_sound_init_main(bmain);
+ /* Make sure no instance of the sound system is running, otherwise we get leaks. */
+ BKE_sound_exit();
+
+ AUD_DeviceSpecs specs;
+ int device, buffersize;
+ const char *device_name;
+
+ device = U.audiodevice;
+ buffersize = U.mixbufsize;
+ specs.channels = U.audiochannels;
+ specs.format = U.audioformat;
+ specs.rate = U.audiorate;
+
+ if (force_device == NULL) {
+ int i;
+ char **names = BKE_sound_get_device_names();
+ device_name = names[0];
+
+ /* make sure device is within the bounds of the array */
+ for (i = 0; names[i]; i++) {
+ if (i == device) {
+ device_name = names[i];
+ }
+ }
+ }
+ else
+ device_name = force_device;
+
+ if (buffersize < 128)
+ buffersize = 1024;
+
+ if (specs.rate < AUD_RATE_8000)
+ specs.rate = AUD_RATE_48000;
+
+ if (specs.format <= AUD_FORMAT_INVALID)
+ specs.format = AUD_FORMAT_S16;
+
+ if (specs.channels <= AUD_CHANNELS_INVALID)
+ specs.channels = AUD_CHANNELS_STEREO;
+
+ if (!(sound_device = AUD_init(device_name, specs, buffersize, "Blender")))
+ sound_device = AUD_init("Null", specs, buffersize, "Blender");
+
+ BKE_sound_init_main(bmain);
}
void BKE_sound_init_main(struct Main *bmain)
{
-#ifdef WITH_JACK
- if (sound_device)
- AUD_setSynchronizerCallback(sound_sync_callback, bmain);
-#else
- (void)bmain; /* unused */
-#endif
+# ifdef WITH_JACK
+ if (sound_device)
+ AUD_setSynchronizerCallback(sound_sync_callback, bmain);
+# else
+ (void)bmain; /* unused */
+# endif
}
void BKE_sound_exit(void)
{
- AUD_exit(sound_device);
- sound_device = NULL;
+ AUD_exit(sound_device);
+ sound_device = NULL;
}
void BKE_sound_exit_once(void)
{
- AUD_exit(sound_device);
- sound_device = NULL;
- AUD_exitOnce();
-
- if (audio_device_names != NULL) {
- int i;
- for (i = 0; audio_device_names[i]; i++) {
- free(audio_device_names[i]);
- }
- free(audio_device_names);
- audio_device_names = NULL;
- }
+ AUD_exit(sound_device);
+ sound_device = NULL;
+ AUD_exitOnce();
+
+ if (audio_device_names != NULL) {
+ int i;
+ for (i = 0; audio_device_names[i]; i++) {
+ free(audio_device_names[i]);
+ }
+ free(audio_device_names);
+ audio_device_names = NULL;
+ }
}
/* XXX unused currently */
-#if 0
+# if 0
bSound *BKE_sound_new_buffer(struct Main *bmain, bSound *source)
{
- bSound *sound = NULL;
+ bSound *sound = NULL;
- char name[MAX_ID_NAME + 5];
- strcpy(name, "buf_");
- strcpy(name + 4, source->id.name);
+ char name[MAX_ID_NAME + 5];
+ strcpy(name, "buf_");
+ strcpy(name + 4, source->id.name);
- sound = BKE_libblock_alloc(bmain, ID_SO, name);
+ sound = BKE_libblock_alloc(bmain, ID_SO, name);
- sound->child_sound = source;
- sound->type = SOUND_TYPE_BUFFER;
+ sound->child_sound = source;
+ sound->type = SOUND_TYPE_BUFFER;
- sound_load(bmain, sound);
+ sound_load(bmain, sound);
- return sound;
+ return sound;
}
bSound *BKE_sound_new_limiter(struct Main *bmain, bSound *source, float start, float end)
{
- bSound *sound = NULL;
+ bSound *sound = NULL;
- char name[MAX_ID_NAME + 5];
- strcpy(name, "lim_");
- strcpy(name + 4, source->id.name);
+ char name[MAX_ID_NAME + 5];
+ strcpy(name, "lim_");
+ strcpy(name + 4, source->id.name);
- sound = BKE_libblock_alloc(bmain, ID_SO, name);
+ sound = BKE_libblock_alloc(bmain, ID_SO, name);
- sound->child_sound = source;
- sound->start = start;
- sound->end = end;
- sound->type = SOUND_TYPE_LIMITER;
+ sound->child_sound = source;
+ sound->start = start;
+ sound->end = end;
+ sound->type = SOUND_TYPE_LIMITER;
- sound_load(bmain, sound);
+ sound_load(bmain, sound);
- return sound;
+ return sound;
}
-#endif
+# endif
void BKE_sound_cache(bSound *sound)
{
- sound->flags |= SOUND_FLAGS_CACHING;
- if (sound->cache)
- AUD_Sound_free(sound->cache);
-
- sound->cache = AUD_Sound_cache(sound->handle);
- if (sound->cache)
- sound->playback_handle = sound->cache;
- else
- sound->playback_handle = sound->handle;
+ sound->flags |= SOUND_FLAGS_CACHING;
+ if (sound->cache)
+ AUD_Sound_free(sound->cache);
+
+ sound->cache = AUD_Sound_cache(sound->handle);
+ if (sound->cache)
+ sound->playback_handle = sound->cache;
+ else
+ sound->playback_handle = sound->handle;
}
void BKE_sound_delete_cache(bSound *sound)
{
- sound->flags &= ~SOUND_FLAGS_CACHING;
- if (sound->cache) {
- AUD_Sound_free(sound->cache);
- sound->cache = NULL;
- sound->playback_handle = sound->handle;
- }
+ sound->flags &= ~SOUND_FLAGS_CACHING;
+ if (sound->cache) {
+ AUD_Sound_free(sound->cache);
+ sound->cache = NULL;
+ sound->playback_handle = sound->handle;
+ }
}
void BKE_sound_load(struct Main *bmain, bSound *sound)
{
- if (sound) {
- if (sound->cache) {
- AUD_Sound_free(sound->cache);
- sound->cache = NULL;
- }
+ if (sound) {
+ if (sound->cache) {
+ AUD_Sound_free(sound->cache);
+ sound->cache = NULL;
+ }
- if (sound->handle) {
- AUD_Sound_free(sound->handle);
- sound->handle = NULL;
- sound->playback_handle = NULL;
- }
+ if (sound->handle) {
+ AUD_Sound_free(sound->handle);
+ sound->handle = NULL;
+ sound->playback_handle = NULL;
+ }
- BKE_sound_free_waveform(sound);
+ BKE_sound_free_waveform(sound);
/* XXX unused currently */
-#if 0
- switch (sound->type)
- {
- case SOUND_TYPE_FILE:
-#endif
- {
- char fullpath[FILE_MAX];
-
- /* load sound */
- PackedFile *pf = sound->packedfile;
-
- /* don't modify soundact->sound->name, only change a copy */
- BLI_strncpy(fullpath, sound->name, sizeof(fullpath));
- BLI_path_abs(fullpath, ID_BLEND_PATH(bmain, &sound->id));
-
- /* but we need a packed file then */
- if (pf)
- sound->handle = AUD_Sound_bufferFile((unsigned char *) pf->data, pf->size);
- /* or else load it from disk */
- else
- sound->handle = AUD_Sound_file(fullpath);
- }
+# if 0
+ switch (sound->type)
+ {
+ case SOUND_TYPE_FILE:
+# endif
+ {
+ char fullpath[FILE_MAX];
+
+ /* load sound */
+ PackedFile *pf = sound->packedfile;
+
+ /* don't modify soundact->sound->name, only change a copy */
+ BLI_strncpy(fullpath, sound->name, sizeof(fullpath));
+ BLI_path_abs(fullpath, ID_BLEND_PATH(bmain, &sound->id));
+
+ /* but we need a packed file then */
+ if (pf)
+ sound->handle = AUD_Sound_bufferFile((unsigned char *)pf->data, pf->size);
+ /* or else load it from disk */
+ else
+ sound->handle = AUD_Sound_file(fullpath);
+ }
/* XXX unused currently */
-#if 0
- break;
- }
- case SOUND_TYPE_BUFFER:
- if (sound->child_sound && sound->child_sound->handle)
- sound->handle = AUD_bufferSound(sound->child_sound->handle);
- break;
- case SOUND_TYPE_LIMITER:
- if (sound->child_sound && sound->child_sound->handle)
- sound->handle = AUD_limitSound(sound->child_sound, sound->start, sound->end);
- break;
- }
-#endif
- if (sound->flags & SOUND_FLAGS_MONO) {
- void *handle = AUD_Sound_rechannel(sound->handle, AUD_CHANNELS_MONO);
- AUD_Sound_free(sound->handle);
- sound->handle = handle;
- }
-
- if (sound->flags & SOUND_FLAGS_CACHING) {
- sound->cache = AUD_Sound_cache(sound->handle);
- }
-
- if (sound->cache)
- sound->playback_handle = sound->cache;
- else
- sound->playback_handle = sound->handle;
-
- BKE_sound_update_sequencer(bmain, sound);
- }
+# if 0
+ break;
+ }
+ case SOUND_TYPE_BUFFER:
+ if (sound->child_sound && sound->child_sound->handle)
+ sound->handle = AUD_bufferSound(sound->child_sound->handle);
+ break;
+ case SOUND_TYPE_LIMITER:
+ if (sound->child_sound && sound->child_sound->handle)
+ sound->handle = AUD_limitSound(sound->child_sound, sound->start, sound->end);
+ break;
+ }
+# endif
+ if (sound->flags & SOUND_FLAGS_MONO) {
+ void *handle = AUD_Sound_rechannel(sound->handle, AUD_CHANNELS_MONO);
+ AUD_Sound_free(sound->handle);
+ sound->handle = handle;
+ }
+
+ if (sound->flags & SOUND_FLAGS_CACHING) {
+ sound->cache = AUD_Sound_cache(sound->handle);
+ }
+
+ if (sound->cache)
+ sound->playback_handle = sound->cache;
+ else
+ sound->playback_handle = sound->handle;
+
+ BKE_sound_update_sequencer(bmain, sound);
+ }
}
AUD_Device *BKE_sound_mixdown(struct Scene *scene, AUD_DeviceSpecs specs, int start, float volume)
{
- return AUD_openMixdownDevice(specs, scene->sound_scene, volume, start / FPS);
+ return AUD_openMixdownDevice(specs, scene->sound_scene, volume, start / FPS);
}
void BKE_sound_create_scene(struct Scene *scene)
{
- /* should be done in version patch, but this gets called before */
- if (scene->r.frs_sec_base == 0)
- scene->r.frs_sec_base = 1;
-
- scene->sound_scene = AUD_Sequence_create(FPS, scene->audio.flag & AUDIO_MUTE);
- AUD_Sequence_setSpeedOfSound(scene->sound_scene, scene->audio.speed_of_sound);
- AUD_Sequence_setDopplerFactor(scene->sound_scene, scene->audio.doppler_factor);
- AUD_Sequence_setDistanceModel(scene->sound_scene, scene->audio.distance_model);
- scene->playback_handle = NULL;
- scene->sound_scrub_handle = NULL;
- scene->speaker_handles = NULL;
+ /* should be done in version patch, but this gets called before */
+ if (scene->r.frs_sec_base == 0)
+ scene->r.frs_sec_base = 1;
+
+ scene->sound_scene = AUD_Sequence_create(FPS, scene->audio.flag & AUDIO_MUTE);
+ AUD_Sequence_setSpeedOfSound(scene->sound_scene, scene->audio.speed_of_sound);
+ AUD_Sequence_setDopplerFactor(scene->sound_scene, scene->audio.doppler_factor);
+ AUD_Sequence_setDistanceModel(scene->sound_scene, scene->audio.distance_model);
+ scene->playback_handle = NULL;
+ scene->sound_scrub_handle = NULL;
+ scene->speaker_handles = NULL;
}
void BKE_sound_destroy_scene(struct Scene *scene)
{
- if (scene->playback_handle)
- AUD_Handle_stop(scene->playback_handle);
- if (scene->sound_scrub_handle)
- AUD_Handle_stop(scene->sound_scrub_handle);
- if (scene->sound_scene)
- AUD_Sequence_free(scene->sound_scene);
- if (scene->speaker_handles)
- AUD_destroySet(scene->speaker_handles);
+ if (scene->playback_handle)
+ AUD_Handle_stop(scene->playback_handle);
+ if (scene->sound_scrub_handle)
+ AUD_Handle_stop(scene->sound_scrub_handle);
+ if (scene->sound_scene)
+ AUD_Sequence_free(scene->sound_scene);
+ if (scene->speaker_handles)
+ AUD_destroySet(scene->speaker_handles);
}
void BKE_sound_reset_scene_specs(struct Scene *scene)
{
- AUD_Specs specs;
+ AUD_Specs specs;
- specs.channels = AUD_Device_getChannels(sound_device);
- specs.rate = AUD_Device_getRate(sound_device);
+ specs.channels = AUD_Device_getChannels(sound_device);
+ specs.rate = AUD_Device_getRate(sound_device);
- AUD_Sequence_setSpecs(scene->sound_scene, specs);
+ AUD_Sequence_setSpecs(scene->sound_scene, specs);
}
void BKE_sound_mute_scene(struct Scene *scene, int muted)
{
- if (scene->sound_scene)
- AUD_Sequence_setMuted(scene->sound_scene, muted);
+ if (scene->sound_scene)
+ AUD_Sequence_setMuted(scene->sound_scene, muted);
}
void BKE_sound_update_fps(struct Scene *scene)
{
- if (scene->sound_scene)
- AUD_Sequence_setFPS(scene->sound_scene, FPS);
+ if (scene->sound_scene)
+ AUD_Sequence_setFPS(scene->sound_scene, FPS);
- BKE_sequencer_refresh_sound_length(scene);
+ BKE_sequencer_refresh_sound_length(scene);
}
void BKE_sound_update_scene_listener(struct Scene *scene)
{
- AUD_Sequence_setSpeedOfSound(scene->sound_scene, scene->audio.speed_of_sound);
- AUD_Sequence_setDopplerFactor(scene->sound_scene, scene->audio.doppler_factor);
- AUD_Sequence_setDistanceModel(scene->sound_scene, scene->audio.distance_model);
+ AUD_Sequence_setSpeedOfSound(scene->sound_scene, scene->audio.speed_of_sound);
+ AUD_Sequence_setDopplerFactor(scene->sound_scene, scene->audio.doppler_factor);
+ AUD_Sequence_setDistanceModel(scene->sound_scene, scene->audio.distance_model);
}
-void *BKE_sound_scene_add_scene_sound(struct Scene *scene, struct Sequence *sequence,
- int startframe, int endframe, int frameskip)
+void *BKE_sound_scene_add_scene_sound(
+ struct Scene *scene, struct Sequence *sequence, int startframe, int endframe, int frameskip)
{
- if (sequence->scene && scene != sequence->scene) {
- const double fps = FPS;
- return AUD_Sequence_add(scene->sound_scene, sequence->scene->sound_scene,
- startframe / fps, endframe / fps, frameskip / fps);
- }
- return NULL;
+ if (sequence->scene && scene != sequence->scene) {
+ const double fps = FPS;
+ return AUD_Sequence_add(scene->sound_scene,
+ sequence->scene->sound_scene,
+ startframe / fps,
+ endframe / fps,
+ frameskip / fps);
+ }
+ return NULL;
}
void *BKE_sound_scene_add_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence)
{
- return BKE_sound_scene_add_scene_sound(scene, sequence,
- sequence->startdisp, sequence->enddisp,
- sequence->startofs + sequence->anim_startofs);
+ return BKE_sound_scene_add_scene_sound(scene,
+ sequence,
+ sequence->startdisp,
+ sequence->enddisp,
+ sequence->startofs + sequence->anim_startofs);
}
-void *BKE_sound_add_scene_sound(struct Scene *scene, struct Sequence *sequence, int startframe, int endframe, int frameskip)
+void *BKE_sound_add_scene_sound(
+ struct Scene *scene, struct Sequence *sequence, int startframe, int endframe, int frameskip)
{
- /* Happens when sequence's sound datablock was removed. */
- if (sequence->sound == NULL) {
- return NULL;
- }
- const double fps = FPS;
- void *handle = AUD_Sequence_add(scene->sound_scene, sequence->sound->playback_handle,
- startframe / fps, endframe / fps, frameskip / fps);
- AUD_SequenceEntry_setMuted(handle, (sequence->flag & SEQ_MUTE) != 0);
- AUD_SequenceEntry_setAnimationData(handle, AUD_AP_VOLUME, CFRA, &sequence->volume, 0);
- AUD_SequenceEntry_setAnimationData(handle, AUD_AP_PITCH, CFRA, &sequence->pitch, 0);
- AUD_SequenceEntry_setAnimationData(handle, AUD_AP_PANNING, CFRA, &sequence->pan, 0);
- return handle;
+ /* Happens when sequence's sound datablock was removed. */
+ if (sequence->sound == NULL) {
+ return NULL;
+ }
+ const double fps = FPS;
+ void *handle = AUD_Sequence_add(scene->sound_scene,
+ sequence->sound->playback_handle,
+ startframe / fps,
+ endframe / fps,
+ frameskip / fps);
+ AUD_SequenceEntry_setMuted(handle, (sequence->flag & SEQ_MUTE) != 0);
+ AUD_SequenceEntry_setAnimationData(handle, AUD_AP_VOLUME, CFRA, &sequence->volume, 0);
+ AUD_SequenceEntry_setAnimationData(handle, AUD_AP_PITCH, CFRA, &sequence->pitch, 0);
+ AUD_SequenceEntry_setAnimationData(handle, AUD_AP_PANNING, CFRA, &sequence->pan, 0);
+ return handle;
}
void *BKE_sound_add_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence)
{
- return BKE_sound_add_scene_sound(scene, sequence,
- sequence->startdisp, sequence->enddisp,
- sequence->startofs + sequence->anim_startofs);
+ return BKE_sound_add_scene_sound(scene,
+ sequence,
+ sequence->startdisp,
+ sequence->enddisp,
+ sequence->startofs + sequence->anim_startofs);
}
void BKE_sound_remove_scene_sound(struct Scene *scene, void *handle)
{
- AUD_Sequence_remove(scene->sound_scene, handle);
+ AUD_Sequence_remove(scene->sound_scene, handle);
}
void BKE_sound_mute_scene_sound(void *handle, char mute)
{
- AUD_SequenceEntry_setMuted(handle, mute);
+ AUD_SequenceEntry_setMuted(handle, mute);
}
-void BKE_sound_move_scene_sound(struct Scene *scene, void *handle, int startframe, int endframe, int frameskip)
+void BKE_sound_move_scene_sound(
+ struct Scene *scene, void *handle, int startframe, int endframe, int frameskip)
{
- const double fps = FPS;
- AUD_SequenceEntry_move(handle, startframe / fps, endframe / fps, frameskip / fps);
+ const double fps = FPS;
+ AUD_SequenceEntry_move(handle, startframe / fps, endframe / fps, frameskip / fps);
}
void BKE_sound_move_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence)
{
- if (sequence->scene_sound) {
- BKE_sound_move_scene_sound(scene, sequence->scene_sound,
- sequence->startdisp, sequence->enddisp,
- sequence->startofs + sequence->anim_startofs);
- }
+ if (sequence->scene_sound) {
+ BKE_sound_move_scene_sound(scene,
+ sequence->scene_sound,
+ sequence->startdisp,
+ sequence->enddisp,
+ sequence->startofs + sequence->anim_startofs);
+ }
}
void BKE_sound_update_scene_sound(void *handle, bSound *sound)
{
- AUD_SequenceEntry_setSound(handle, sound->playback_handle);
+ AUD_SequenceEntry_setSound(handle, sound->playback_handle);
}
void BKE_sound_set_cfra(int cfra)
{
- sound_cfra = cfra;
+ sound_cfra = cfra;
}
void BKE_sound_set_scene_volume(struct Scene *scene, float volume)
{
- AUD_Sequence_setAnimationData(scene->sound_scene, AUD_AP_VOLUME, CFRA, &volume,
- (scene->audio.flag & AUDIO_VOLUME_ANIMATED) != 0);
+ AUD_Sequence_setAnimationData(scene->sound_scene,
+ AUD_AP_VOLUME,
+ CFRA,
+ &volume,
+ (scene->audio.flag & AUDIO_VOLUME_ANIMATED) != 0);
}
void BKE_sound_set_scene_sound_volume(void *handle, float volume, char animated)
{
- AUD_SequenceEntry_setAnimationData(handle, AUD_AP_VOLUME, sound_cfra, &volume, animated);
+ AUD_SequenceEntry_setAnimationData(handle, AUD_AP_VOLUME, sound_cfra, &volume, animated);
}
void BKE_sound_set_scene_sound_pitch(void *handle, float pitch, char animated)
{
- AUD_SequenceEntry_setAnimationData(handle, AUD_AP_PITCH, sound_cfra, &pitch, animated);
+ AUD_SequenceEntry_setAnimationData(handle, AUD_AP_PITCH, sound_cfra, &pitch, animated);
}
void BKE_sound_set_scene_sound_pan(void *handle, float pan, char animated)
{
- printf("%s\n", __func__);
- AUD_SequenceEntry_setAnimationData(handle, AUD_AP_PANNING, sound_cfra, &pan, animated);
+ printf("%s\n", __func__);
+ AUD_SequenceEntry_setAnimationData(handle, AUD_AP_PANNING, sound_cfra, &pan, animated);
}
void BKE_sound_update_sequencer(struct Main *main, bSound *sound)
{
- struct Scene *scene;
+ struct Scene *scene;
- for (scene = main->scenes.first; scene; scene = scene->id.next) {
- BKE_sequencer_update_sound(scene, sound);
- }
+ for (scene = main->scenes.first; scene; scene = scene->id.next) {
+ BKE_sequencer_update_sound(scene, sound);
+ }
}
static void sound_start_play_scene(struct Scene *scene)
{
- if (scene->playback_handle)
- AUD_Handle_stop(scene->playback_handle);
+ if (scene->playback_handle)
+ AUD_Handle_stop(scene->playback_handle);
- BKE_sound_reset_scene_specs(scene);
+ BKE_sound_reset_scene_specs(scene);
- if ((scene->playback_handle = AUD_Device_play(sound_device, scene->sound_scene, 1)))
- AUD_Handle_setLoopCount(scene->playback_handle, -1);
+ if ((scene->playback_handle = AUD_Device_play(sound_device, scene->sound_scene, 1)))
+ AUD_Handle_setLoopCount(scene->playback_handle, -1);
}
void BKE_sound_play_scene(struct Scene *scene)
{
- AUD_Status status;
- const float cur_time = (float)((double)CFRA / FPS);
+ AUD_Status status;
+ const float cur_time = (float)((double)CFRA / FPS);
- AUD_Device_lock(sound_device);
+ AUD_Device_lock(sound_device);
- status = scene->playback_handle ? AUD_Handle_getStatus(scene->playback_handle) : AUD_STATUS_INVALID;
+ status = scene->playback_handle ? AUD_Handle_getStatus(scene->playback_handle) :
+ AUD_STATUS_INVALID;
- if (status == AUD_STATUS_INVALID) {
- sound_start_play_scene(scene);
+ if (status == AUD_STATUS_INVALID) {
+ sound_start_play_scene(scene);
- if (!scene->playback_handle) {
- AUD_Device_unlock(sound_device);
- return;
- }
- }
+ if (!scene->playback_handle) {
+ AUD_Device_unlock(sound_device);
+ return;
+ }
+ }
- if (status != AUD_STATUS_PLAYING) {
- AUD_Handle_setPosition(scene->playback_handle, cur_time);
- AUD_Handle_resume(scene->playback_handle);
- }
+ if (status != AUD_STATUS_PLAYING) {
+ AUD_Handle_setPosition(scene->playback_handle, cur_time);
+ AUD_Handle_resume(scene->playback_handle);
+ }
- if (scene->audio.flag & AUDIO_SYNC)
- AUD_playSynchronizer();
+ if (scene->audio.flag & AUDIO_SYNC)
+ AUD_playSynchronizer();
- AUD_Device_unlock(sound_device);
+ AUD_Device_unlock(sound_device);
}
void BKE_sound_stop_scene(struct Scene *scene)
{
- if (scene->playback_handle) {
- AUD_Handle_pause(scene->playback_handle);
+ if (scene->playback_handle) {
+ AUD_Handle_pause(scene->playback_handle);
- if (scene->audio.flag & AUDIO_SYNC)
- AUD_stopSynchronizer();
- }
+ if (scene->audio.flag & AUDIO_SYNC)
+ AUD_stopSynchronizer();
+ }
}
void BKE_sound_seek_scene(struct Main *bmain, struct Scene *scene)
{
- AUD_Status status;
- bScreen *screen;
- int animation_playing;
-
- const float one_frame = (float)(1.0 / FPS);
- const float cur_time = (float)((double)CFRA / FPS);
-
- AUD_Device_lock(sound_device);
-
- status = scene->playback_handle ? AUD_Handle_getStatus(scene->playback_handle) : AUD_STATUS_INVALID;
-
- if (status == AUD_STATUS_INVALID) {
- sound_start_play_scene(scene);
-
- if (!scene->playback_handle) {
- AUD_Device_unlock(sound_device);
- return;
- }
-
- AUD_Handle_pause(scene->playback_handle);
- }
-
- animation_playing = 0;
- for (screen = bmain->screens.first; screen; screen = screen->id.next) {
- if (screen->animtimer) {
- animation_playing = 1;
- break;
- }
- }
-
- if (scene->audio.flag & AUDIO_SCRUB && !animation_playing) {
- AUD_Handle_setPosition(scene->playback_handle, cur_time);
- if (scene->audio.flag & AUDIO_SYNC) {
- AUD_seekSynchronizer(scene->playback_handle, cur_time);
- }
- AUD_Handle_resume(scene->playback_handle);
- if (scene->sound_scrub_handle && AUD_Handle_getStatus(scene->sound_scrub_handle) != AUD_STATUS_INVALID) {
- AUD_Handle_setPosition(scene->sound_scrub_handle, 0);
- }
- else {
- if (scene->sound_scrub_handle) {
- AUD_Handle_stop(scene->sound_scrub_handle);
- }
- scene->sound_scrub_handle = AUD_pauseAfter(scene->playback_handle, one_frame);
- }
- }
- else {
- if (scene->audio.flag & AUDIO_SYNC) {
- AUD_seekSynchronizer(scene->playback_handle, cur_time);
- }
- else {
- if (status == AUD_STATUS_PLAYING) {
- AUD_Handle_setPosition(scene->playback_handle, cur_time);
- }
- }
- }
-
- AUD_Device_unlock(sound_device);
+ AUD_Status status;
+ bScreen *screen;
+ int animation_playing;
+
+ const float one_frame = (float)(1.0 / FPS);
+ const float cur_time = (float)((double)CFRA / FPS);
+
+ AUD_Device_lock(sound_device);
+
+ status = scene->playback_handle ? AUD_Handle_getStatus(scene->playback_handle) :
+ AUD_STATUS_INVALID;
+
+ if (status == AUD_STATUS_INVALID) {
+ sound_start_play_scene(scene);
+
+ if (!scene->playback_handle) {
+ AUD_Device_unlock(sound_device);
+ return;
+ }
+
+ AUD_Handle_pause(scene->playback_handle);
+ }
+
+ animation_playing = 0;
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ if (screen->animtimer) {
+ animation_playing = 1;
+ break;
+ }
+ }
+
+ if (scene->audio.flag & AUDIO_SCRUB && !animation_playing) {
+ AUD_Handle_setPosition(scene->playback_handle, cur_time);
+ if (scene->audio.flag & AUDIO_SYNC) {
+ AUD_seekSynchronizer(scene->playback_handle, cur_time);
+ }
+ AUD_Handle_resume(scene->playback_handle);
+ if (scene->sound_scrub_handle &&
+ AUD_Handle_getStatus(scene->sound_scrub_handle) != AUD_STATUS_INVALID) {
+ AUD_Handle_setPosition(scene->sound_scrub_handle, 0);
+ }
+ else {
+ if (scene->sound_scrub_handle) {
+ AUD_Handle_stop(scene->sound_scrub_handle);
+ }
+ scene->sound_scrub_handle = AUD_pauseAfter(scene->playback_handle, one_frame);
+ }
+ }
+ else {
+ if (scene->audio.flag & AUDIO_SYNC) {
+ AUD_seekSynchronizer(scene->playback_handle, cur_time);
+ }
+ else {
+ if (status == AUD_STATUS_PLAYING) {
+ AUD_Handle_setPosition(scene->playback_handle, cur_time);
+ }
+ }
+ }
+
+ AUD_Device_unlock(sound_device);
}
float BKE_sound_sync_scene(struct Scene *scene)
{
- // Ugly: Blender doesn't like it when the animation is played back during rendering
- if (G.is_rendering)
- return NAN_FLT;
-
- if (scene->playback_handle) {
- if (scene->audio.flag & AUDIO_SYNC)
- return AUD_getSynchronizerPosition(scene->playback_handle);
- else
- return AUD_Handle_getPosition(scene->playback_handle);
- }
- return NAN_FLT;
+ // Ugly: Blender doesn't like it when the animation is played back during rendering
+ if (G.is_rendering)
+ return NAN_FLT;
+
+ if (scene->playback_handle) {
+ if (scene->audio.flag & AUDIO_SYNC)
+ return AUD_getSynchronizerPosition(scene->playback_handle);
+ else
+ return AUD_Handle_getPosition(scene->playback_handle);
+ }
+ return NAN_FLT;
}
int BKE_sound_scene_playing(struct Scene *scene)
{
- // Ugly: Blender doesn't like it when the animation is played back during rendering
- if (G.is_rendering)
- return -1;
-
- if (scene->audio.flag & AUDIO_SYNC)
- return AUD_isSynchronizerPlaying();
- else
- return -1;
+ // Ugly: Blender doesn't like it when the animation is played back during rendering
+ if (G.is_rendering)
+ return -1;
+
+ if (scene->audio.flag & AUDIO_SYNC)
+ return AUD_isSynchronizerPlaying();
+ else
+ return -1;
}
void BKE_sound_free_waveform(bSound *sound)
{
- if ((sound->tags & SOUND_TAGS_WAVEFORM_NO_RELOAD) == 0) {
- SoundWaveform *waveform = sound->waveform;
- if (waveform) {
- if (waveform->data) {
- MEM_freeN(waveform->data);
- }
- MEM_freeN(waveform);
- }
-
- sound->waveform = NULL;
- }
- /* This tag is only valid once. */
- sound->tags &= ~SOUND_TAGS_WAVEFORM_NO_RELOAD;
+ if ((sound->tags & SOUND_TAGS_WAVEFORM_NO_RELOAD) == 0) {
+ SoundWaveform *waveform = sound->waveform;
+ if (waveform) {
+ if (waveform->data) {
+ MEM_freeN(waveform->data);
+ }
+ MEM_freeN(waveform);
+ }
+
+ sound->waveform = NULL;
+ }
+ /* This tag is only valid once. */
+ sound->tags &= ~SOUND_TAGS_WAVEFORM_NO_RELOAD;
}
void BKE_sound_read_waveform(bSound *sound, short *stop)
{
- AUD_SoundInfo info = AUD_getInfo(sound->playback_handle);
- SoundWaveform *waveform = MEM_mallocN(sizeof(SoundWaveform), "SoundWaveform");
-
- if (info.length > 0) {
- int length = info.length * SOUND_WAVE_SAMPLES_PER_SECOND;
-
- waveform->data = MEM_mallocN(length * sizeof(float) * 3, "SoundWaveform.samples");
- waveform->length = AUD_readSound(sound->playback_handle, waveform->data, length, SOUND_WAVE_SAMPLES_PER_SECOND, stop);
- }
- else {
- /* Create an empty waveform here if the sound couldn't be
- * read. This indicates that reading the waveform is "done",
- * whereas just setting sound->waveform to NULL causes other
- * code to think the waveform still needs to be created. */
- waveform->data = NULL;
- waveform->length = 0;
- }
-
- if (*stop) {
- if (waveform->data) {
- MEM_freeN(waveform->data);
- }
- MEM_freeN(waveform);
- BLI_spin_lock(sound->spinlock);
- sound->tags &= ~SOUND_TAGS_WAVEFORM_LOADING;
- BLI_spin_unlock(sound->spinlock);
- return;
- }
-
- BKE_sound_free_waveform(sound);
-
- BLI_spin_lock(sound->spinlock);
- sound->waveform = waveform;
- sound->tags &= ~SOUND_TAGS_WAVEFORM_LOADING;
- BLI_spin_unlock(sound->spinlock);
+ AUD_SoundInfo info = AUD_getInfo(sound->playback_handle);
+ SoundWaveform *waveform = MEM_mallocN(sizeof(SoundWaveform), "SoundWaveform");
+
+ if (info.length > 0) {
+ int length = info.length * SOUND_WAVE_SAMPLES_PER_SECOND;
+
+ waveform->data = MEM_mallocN(length * sizeof(float) * 3, "SoundWaveform.samples");
+ waveform->length = AUD_readSound(
+ sound->playback_handle, waveform->data, length, SOUND_WAVE_SAMPLES_PER_SECOND, stop);
+ }
+ else {
+ /* Create an empty waveform here if the sound couldn't be
+ * read. This indicates that reading the waveform is "done",
+ * whereas just setting sound->waveform to NULL causes other
+ * code to think the waveform still needs to be created. */
+ waveform->data = NULL;
+ waveform->length = 0;
+ }
+
+ if (*stop) {
+ if (waveform->data) {
+ MEM_freeN(waveform->data);
+ }
+ MEM_freeN(waveform);
+ BLI_spin_lock(sound->spinlock);
+ sound->tags &= ~SOUND_TAGS_WAVEFORM_LOADING;
+ BLI_spin_unlock(sound->spinlock);
+ return;
+ }
+
+ BKE_sound_free_waveform(sound);
+
+ BLI_spin_lock(sound->spinlock);
+ sound->waveform = waveform;
+ sound->tags &= ~SOUND_TAGS_WAVEFORM_LOADING;
+ BLI_spin_unlock(sound->spinlock);
}
static void sound_update_base(Scene *scene, Base *base, void *new_set)
{
- Object *ob = base->object;
- NlaTrack *track;
- NlaStrip *strip;
- Speaker *speaker;
- float quat[4];
-
- if ((ob->id.tag & LIB_TAG_DOIT) == 0) {
- return;
- }
-
- ob->id.tag &= ~LIB_TAG_DOIT;
-
- if ((ob->type != OB_SPEAKER) || !ob->adt) {
- return;
- }
-
- for (track = ob->adt->nla_tracks.first; track; track = track->next) {
- for (strip = track->strips.first; strip; strip = strip->next) {
- if (strip->type != NLASTRIP_TYPE_SOUND) {
- continue;
- }
- speaker = (Speaker *)ob->data;
-
- if (AUD_removeSet(scene->speaker_handles, strip->speaker_handle)) {
- if (speaker->sound) {
- AUD_SequenceEntry_move(strip->speaker_handle, (double)strip->start / FPS, FLT_MAX, 0);
- }
- else {
- AUD_Sequence_remove(scene->sound_scene, strip->speaker_handle);
- strip->speaker_handle = NULL;
- }
- }
- else {
- if (speaker->sound) {
- strip->speaker_handle = AUD_Sequence_add(scene->sound_scene,
- speaker->sound->playback_handle,
- (double)strip->start / FPS, FLT_MAX, 0);
- AUD_SequenceEntry_setRelative(strip->speaker_handle, 0);
- }
- }
-
- if (strip->speaker_handle) {
- const bool mute = ((strip->flag & NLASTRIP_FLAG_MUTED) || (speaker->flag & SPK_MUTED));
- AUD_addSet(new_set, strip->speaker_handle);
- AUD_SequenceEntry_setVolumeMaximum(strip->speaker_handle, speaker->volume_max);
- AUD_SequenceEntry_setVolumeMinimum(strip->speaker_handle, speaker->volume_min);
- AUD_SequenceEntry_setDistanceMaximum(strip->speaker_handle, speaker->distance_max);
- AUD_SequenceEntry_setDistanceReference(strip->speaker_handle, speaker->distance_reference);
- AUD_SequenceEntry_setAttenuation(strip->speaker_handle, speaker->attenuation);
- AUD_SequenceEntry_setConeAngleOuter(strip->speaker_handle, speaker->cone_angle_outer);
- AUD_SequenceEntry_setConeAngleInner(strip->speaker_handle, speaker->cone_angle_inner);
- AUD_SequenceEntry_setConeVolumeOuter(strip->speaker_handle, speaker->cone_volume_outer);
-
- mat4_to_quat(quat, ob->obmat);
- AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_LOCATION, CFRA, ob->obmat[3], 1);
- AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_ORIENTATION, CFRA, quat, 1);
- AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_VOLUME, CFRA, &speaker->volume, 1);
- AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_PITCH, CFRA, &speaker->pitch, 1);
- AUD_SequenceEntry_setSound(strip->speaker_handle, speaker->sound->playback_handle);
- AUD_SequenceEntry_setMuted(strip->speaker_handle, mute);
- }
- }
- }
+ Object *ob = base->object;
+ NlaTrack *track;
+ NlaStrip *strip;
+ Speaker *speaker;
+ float quat[4];
+
+ if ((ob->id.tag & LIB_TAG_DOIT) == 0) {
+ return;
+ }
+
+ ob->id.tag &= ~LIB_TAG_DOIT;
+
+ if ((ob->type != OB_SPEAKER) || !ob->adt) {
+ return;
+ }
+
+ for (track = ob->adt->nla_tracks.first; track; track = track->next) {
+ for (strip = track->strips.first; strip; strip = strip->next) {
+ if (strip->type != NLASTRIP_TYPE_SOUND) {
+ continue;
+ }
+ speaker = (Speaker *)ob->data;
+
+ if (AUD_removeSet(scene->speaker_handles, strip->speaker_handle)) {
+ if (speaker->sound) {
+ AUD_SequenceEntry_move(strip->speaker_handle, (double)strip->start / FPS, FLT_MAX, 0);
+ }
+ else {
+ AUD_Sequence_remove(scene->sound_scene, strip->speaker_handle);
+ strip->speaker_handle = NULL;
+ }
+ }
+ else {
+ if (speaker->sound) {
+ strip->speaker_handle = AUD_Sequence_add(scene->sound_scene,
+ speaker->sound->playback_handle,
+ (double)strip->start / FPS,
+ FLT_MAX,
+ 0);
+ AUD_SequenceEntry_setRelative(strip->speaker_handle, 0);
+ }
+ }
+
+ if (strip->speaker_handle) {
+ const bool mute = ((strip->flag & NLASTRIP_FLAG_MUTED) || (speaker->flag & SPK_MUTED));
+ AUD_addSet(new_set, strip->speaker_handle);
+ AUD_SequenceEntry_setVolumeMaximum(strip->speaker_handle, speaker->volume_max);
+ AUD_SequenceEntry_setVolumeMinimum(strip->speaker_handle, speaker->volume_min);
+ AUD_SequenceEntry_setDistanceMaximum(strip->speaker_handle, speaker->distance_max);
+ AUD_SequenceEntry_setDistanceReference(strip->speaker_handle, speaker->distance_reference);
+ AUD_SequenceEntry_setAttenuation(strip->speaker_handle, speaker->attenuation);
+ AUD_SequenceEntry_setConeAngleOuter(strip->speaker_handle, speaker->cone_angle_outer);
+ AUD_SequenceEntry_setConeAngleInner(strip->speaker_handle, speaker->cone_angle_inner);
+ AUD_SequenceEntry_setConeVolumeOuter(strip->speaker_handle, speaker->cone_volume_outer);
+
+ mat4_to_quat(quat, ob->obmat);
+ AUD_SequenceEntry_setAnimationData(
+ strip->speaker_handle, AUD_AP_LOCATION, CFRA, ob->obmat[3], 1);
+ AUD_SequenceEntry_setAnimationData(
+ strip->speaker_handle, AUD_AP_ORIENTATION, CFRA, quat, 1);
+ AUD_SequenceEntry_setAnimationData(
+ strip->speaker_handle, AUD_AP_VOLUME, CFRA, &speaker->volume, 1);
+ AUD_SequenceEntry_setAnimationData(
+ strip->speaker_handle, AUD_AP_PITCH, CFRA, &speaker->pitch, 1);
+ AUD_SequenceEntry_setSound(strip->speaker_handle, speaker->sound->playback_handle);
+ AUD_SequenceEntry_setMuted(strip->speaker_handle, mute);
+ }
+ }
+ }
}
void BKE_sound_update_scene(Main *bmain, Scene *scene)
{
- Base *base;
- Scene *sce_it;
-
- void *new_set = AUD_createSet();
- void *handle;
- float quat[4];
-
- /* cheap test to skip looping over all objects (no speakers is a common case) */
- if (!BLI_listbase_is_empty(&bmain->speakers)) {
- BKE_main_id_tag_listbase(&bmain->objects, LIB_TAG_DOIT, true);
-
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
- for (base = view_layer->object_bases.first; base; base = base->next) {
- sound_update_base(scene, base, new_set);
- }
- }
-
- for (SETLOOPER_SET_ONLY(scene, sce_it, base)) {
- sound_update_base(scene, base, new_set);
- }
-
- }
-
- while ((handle = AUD_getSet(scene->speaker_handles))) {
- AUD_Sequence_remove(scene->sound_scene, handle);
- }
-
- if (scene->camera) {
- mat4_to_quat(quat, scene->camera->obmat);
- AUD_Sequence_setAnimationData(scene->sound_scene, AUD_AP_LOCATION, CFRA, scene->camera->obmat[3], 1);
- AUD_Sequence_setAnimationData(scene->sound_scene, AUD_AP_ORIENTATION, CFRA, quat, 1);
- }
-
- AUD_destroySet(scene->speaker_handles);
- scene->speaker_handles = new_set;
+ Base *base;
+ Scene *sce_it;
+
+ void *new_set = AUD_createSet();
+ void *handle;
+ float quat[4];
+
+ /* cheap test to skip looping over all objects (no speakers is a common case) */
+ if (!BLI_listbase_is_empty(&bmain->speakers)) {
+ BKE_main_id_tag_listbase(&bmain->objects, LIB_TAG_DOIT, true);
+
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
+ view_layer = view_layer->next) {
+ for (base = view_layer->object_bases.first; base; base = base->next) {
+ sound_update_base(scene, base, new_set);
+ }
+ }
+
+ for (SETLOOPER_SET_ONLY(scene, sce_it, base)) {
+ sound_update_base(scene, base, new_set);
+ }
+ }
+
+ while ((handle = AUD_getSet(scene->speaker_handles))) {
+ AUD_Sequence_remove(scene->sound_scene, handle);
+ }
+
+ if (scene->camera) {
+ mat4_to_quat(quat, scene->camera->obmat);
+ AUD_Sequence_setAnimationData(
+ scene->sound_scene, AUD_AP_LOCATION, CFRA, scene->camera->obmat[3], 1);
+ AUD_Sequence_setAnimationData(scene->sound_scene, AUD_AP_ORIENTATION, CFRA, quat, 1);
+ }
+
+ AUD_destroySet(scene->speaker_handles);
+ scene->speaker_handles = new_set;
}
void *BKE_sound_get_factory(void *sound)
{
- return ((bSound *)sound)->playback_handle;
+ return ((bSound *)sound)->playback_handle;
}
/* stupid wrapper because AUD_C-API.h includes Python.h which makesrna doesn't like */
float BKE_sound_get_length(bSound *sound)
{
- AUD_SoundInfo info = AUD_getInfo(sound->playback_handle);
+ AUD_SoundInfo info = AUD_getInfo(sound->playback_handle);
- return info.length;
+ return info.length;
}
char **BKE_sound_get_device_names(void)
{
- if (audio_device_names == NULL) {
- audio_device_names = AUD_getDeviceNames();
- }
+ if (audio_device_names == NULL) {
+ audio_device_names = AUD_getDeviceNames();
+ }
- return audio_device_names;
+ return audio_device_names;
}
-#else /* WITH_AUDASPACE */
+#else /* WITH_AUDASPACE */
-#include "BLI_utildefines.h"
+# include "BLI_utildefines.h"
-void BKE_sound_force_device(const char *UNUSED(device)) {}
-void BKE_sound_init_once(void) {}
-void BKE_sound_init(struct Main *UNUSED(bmain)) {}
-void BKE_sound_exit(void) {}
-void BKE_sound_exit_once(void) {}
-void BKE_sound_cache(struct bSound *UNUSED(sound)) {}
-void BKE_sound_delete_cache(struct bSound *UNUSED(sound)) {}
-void BKE_sound_load(struct Main *UNUSED(bmain), struct bSound *UNUSED(sound)) {}
-void BKE_sound_create_scene(struct Scene *UNUSED(scene)) {}
-void BKE_sound_destroy_scene(struct Scene *UNUSED(scene)) {}
-void BKE_sound_reset_scene_specs(struct Scene *UNUSED(scene)) {}
-void BKE_sound_mute_scene(struct Scene *UNUSED(scene), int UNUSED(muted)) {}
-void *BKE_sound_scene_add_scene_sound(struct Scene *UNUSED(scene), struct Sequence *UNUSED(sequence),
- int UNUSED(startframe), int UNUSED(endframe), int UNUSED(frameskip)) { return NULL; }
+void BKE_sound_force_device(const char *UNUSED(device))
+{
+}
+void BKE_sound_init_once(void)
+{
+}
+void BKE_sound_init(struct Main *UNUSED(bmain))
+{
+}
+void BKE_sound_exit(void)
+{
+}
+void BKE_sound_exit_once(void)
+{
+}
+void BKE_sound_cache(struct bSound *UNUSED(sound))
+{
+}
+void BKE_sound_delete_cache(struct bSound *UNUSED(sound))
+{
+}
+void BKE_sound_load(struct Main *UNUSED(bmain), struct bSound *UNUSED(sound))
+{
+}
+void BKE_sound_create_scene(struct Scene *UNUSED(scene))
+{
+}
+void BKE_sound_destroy_scene(struct Scene *UNUSED(scene))
+{
+}
+void BKE_sound_reset_scene_specs(struct Scene *UNUSED(scene))
+{
+}
+void BKE_sound_mute_scene(struct Scene *UNUSED(scene), int UNUSED(muted))
+{
+}
+void *BKE_sound_scene_add_scene_sound(struct Scene *UNUSED(scene),
+ struct Sequence *UNUSED(sequence),
+ int UNUSED(startframe),
+ int UNUSED(endframe),
+ int UNUSED(frameskip))
+{
+ return NULL;
+}
void *BKE_sound_scene_add_scene_sound_defaults(struct Scene *UNUSED(scene),
- struct Sequence *UNUSED(sequence)) { return NULL; }
-void *BKE_sound_add_scene_sound(struct Scene *UNUSED(scene), struct Sequence *UNUSED(sequence), int UNUSED(startframe),
- int UNUSED(endframe), int UNUSED(frameskip)) { return NULL; }
-void *BKE_sound_add_scene_sound_defaults(struct Scene *UNUSED(scene), struct Sequence *UNUSED(sequence)) { return NULL; }
-void BKE_sound_remove_scene_sound(struct Scene *UNUSED(scene), void *UNUSED(handle)) {}
-void BKE_sound_mute_scene_sound(void *UNUSED(handle), char UNUSED(mute)) {}
-void BKE_sound_move_scene_sound(struct Scene *UNUSED(scene), void *UNUSED(handle), int UNUSED(startframe),
- int UNUSED(endframe), int UNUSED(frameskip)) {}
-void BKE_sound_move_scene_sound_defaults(struct Scene *UNUSED(scene), struct Sequence *UNUSED(sequence)) {}
-void BKE_sound_play_scene(struct Scene *UNUSED(scene)) {}
-void BKE_sound_stop_scene(struct Scene *UNUSED(scene)) {}
-void BKE_sound_seek_scene(struct Main *UNUSED(bmain), struct Scene *UNUSED(scene)) {}
-float BKE_sound_sync_scene(struct Scene *UNUSED(scene)) { return NAN_FLT; }
-int BKE_sound_scene_playing(struct Scene *UNUSED(scene)) { return -1; }
-void BKE_sound_read_waveform(struct bSound *sound, short *stop) { UNUSED_VARS(sound, stop); }
-void BKE_sound_init_main(struct Main *UNUSED(bmain)) {}
-void BKE_sound_set_cfra(int UNUSED(cfra)) {}
-void BKE_sound_update_sequencer(struct Main *UNUSED(main), struct bSound *UNUSED(sound)) {}
-void BKE_sound_update_scene(struct Main *UNUSED(bmain), struct Scene *UNUSED(scene)) {}
-void BKE_sound_update_scene_sound(void *UNUSED(handle), struct bSound *UNUSED(sound)) {}
-void BKE_sound_update_scene_listener(struct Scene *UNUSED(scene)) {}
-void BKE_sound_update_fps(struct Scene *UNUSED(scene)) {}
-void BKE_sound_set_scene_sound_volume(void *UNUSED(handle), float UNUSED(volume), char UNUSED(animated)) {}
-void BKE_sound_set_scene_sound_pan(void *UNUSED(handle), float UNUSED(pan), char UNUSED(animated)) {}
-void BKE_sound_set_scene_volume(struct Scene *UNUSED(scene), float UNUSED(volume)) {}
-void BKE_sound_set_scene_sound_pitch(void *UNUSED(handle), float UNUSED(pitch), char UNUSED(animated)) {}
-float BKE_sound_get_length(struct bSound *UNUSED(sound)) { return 0; }
-char **BKE_sound_get_device_names(void) { static char *names[1] = {NULL}; return names; }
-
-#endif /* WITH_AUDASPACE */
+ struct Sequence *UNUSED(sequence))
+{
+ return NULL;
+}
+void *BKE_sound_add_scene_sound(struct Scene *UNUSED(scene),
+ struct Sequence *UNUSED(sequence),
+ int UNUSED(startframe),
+ int UNUSED(endframe),
+ int UNUSED(frameskip))
+{
+ return NULL;
+}
+void *BKE_sound_add_scene_sound_defaults(struct Scene *UNUSED(scene),
+ struct Sequence *UNUSED(sequence))
+{
+ return NULL;
+}
+void BKE_sound_remove_scene_sound(struct Scene *UNUSED(scene), void *UNUSED(handle))
+{
+}
+void BKE_sound_mute_scene_sound(void *UNUSED(handle), char UNUSED(mute))
+{
+}
+void BKE_sound_move_scene_sound(struct Scene *UNUSED(scene),
+ void *UNUSED(handle),
+ int UNUSED(startframe),
+ int UNUSED(endframe),
+ int UNUSED(frameskip))
+{
+}
+void BKE_sound_move_scene_sound_defaults(struct Scene *UNUSED(scene),
+ struct Sequence *UNUSED(sequence))
+{
+}
+void BKE_sound_play_scene(struct Scene *UNUSED(scene))
+{
+}
+void BKE_sound_stop_scene(struct Scene *UNUSED(scene))
+{
+}
+void BKE_sound_seek_scene(struct Main *UNUSED(bmain), struct Scene *UNUSED(scene))
+{
+}
+float BKE_sound_sync_scene(struct Scene *UNUSED(scene))
+{
+ return NAN_FLT;
+}
+int BKE_sound_scene_playing(struct Scene *UNUSED(scene))
+{
+ return -1;
+}
+void BKE_sound_read_waveform(struct bSound *sound, short *stop)
+{
+ UNUSED_VARS(sound, stop);
+}
+void BKE_sound_init_main(struct Main *UNUSED(bmain))
+{
+}
+void BKE_sound_set_cfra(int UNUSED(cfra))
+{
+}
+void BKE_sound_update_sequencer(struct Main *UNUSED(main), struct bSound *UNUSED(sound))
+{
+}
+void BKE_sound_update_scene(struct Main *UNUSED(bmain), struct Scene *UNUSED(scene))
+{
+}
+void BKE_sound_update_scene_sound(void *UNUSED(handle), struct bSound *UNUSED(sound))
+{
+}
+void BKE_sound_update_scene_listener(struct Scene *UNUSED(scene))
+{
+}
+void BKE_sound_update_fps(struct Scene *UNUSED(scene))
+{
+}
+void BKE_sound_set_scene_sound_volume(void *UNUSED(handle),
+ float UNUSED(volume),
+ char UNUSED(animated))
+{
+}
+void BKE_sound_set_scene_sound_pan(void *UNUSED(handle), float UNUSED(pan), char UNUSED(animated))
+{
+}
+void BKE_sound_set_scene_volume(struct Scene *UNUSED(scene), float UNUSED(volume))
+{
+}
+void BKE_sound_set_scene_sound_pitch(void *UNUSED(handle),
+ float UNUSED(pitch),
+ char UNUSED(animated))
+{
+}
+float BKE_sound_get_length(struct bSound *UNUSED(sound))
+{
+ return 0;
+}
+char **BKE_sound_get_device_names(void)
+{
+ static char *names[1] = {NULL};
+ return names;
+}
+
+#endif /* WITH_AUDASPACE */
diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c
index 70ca76d409b..8565fde4565 100644
--- a/source/blender/blenkernel/intern/speaker.c
+++ b/source/blender/blenkernel/intern/speaker.c
@@ -32,31 +32,31 @@
void BKE_speaker_init(Speaker *spk)
{
- BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(spk, id));
+ BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(spk, id));
- spk->attenuation = 1.0f;
- spk->cone_angle_inner = 360.0f;
- spk->cone_angle_outer = 360.0f;
- spk->cone_volume_outer = 1.0f;
- spk->distance_max = FLT_MAX;
- spk->distance_reference = 1.0f;
- spk->flag = 0;
- spk->pitch = 1.0f;
- spk->sound = NULL;
- spk->volume = 1.0f;
- spk->volume_max = 1.0f;
- spk->volume_min = 0.0f;
+ spk->attenuation = 1.0f;
+ spk->cone_angle_inner = 360.0f;
+ spk->cone_angle_outer = 360.0f;
+ spk->cone_volume_outer = 1.0f;
+ spk->distance_max = FLT_MAX;
+ spk->distance_reference = 1.0f;
+ spk->flag = 0;
+ spk->pitch = 1.0f;
+ spk->sound = NULL;
+ spk->volume = 1.0f;
+ spk->volume_max = 1.0f;
+ spk->volume_min = 0.0f;
}
void *BKE_speaker_add(Main *bmain, const char *name)
{
- Speaker *spk;
+ Speaker *spk;
- spk = BKE_libblock_alloc(bmain, ID_SPK, name, 0);
+ spk = BKE_libblock_alloc(bmain, ID_SPK, name, 0);
- BKE_speaker_init(spk);
+ BKE_speaker_init(spk);
- return spk;
+ return spk;
}
/**
@@ -67,24 +67,27 @@ void *BKE_speaker_add(Main *bmain, const char *name)
*
* \param flag: Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
*/
-void BKE_speaker_copy_data(Main *UNUSED(bmain), Speaker *UNUSED(spk_dst), const Speaker *UNUSED(spk_src), const int UNUSED(flag))
+void BKE_speaker_copy_data(Main *UNUSED(bmain),
+ Speaker *UNUSED(spk_dst),
+ const Speaker *UNUSED(spk_src),
+ const int UNUSED(flag))
{
- /* Nothing to do! */
+ /* Nothing to do! */
}
Speaker *BKE_speaker_copy(Main *bmain, const Speaker *spk)
{
- Speaker *spk_copy;
- BKE_id_copy(bmain, &spk->id, (ID **)&spk_copy);
- return spk_copy;
+ Speaker *spk_copy;
+ BKE_id_copy(bmain, &spk->id, (ID **)&spk_copy);
+ return spk_copy;
}
void BKE_speaker_make_local(Main *bmain, Speaker *spk, const bool lib_local)
{
- BKE_id_make_local_generic(bmain, &spk->id, true, lib_local);
+ BKE_id_make_local_generic(bmain, &spk->id, true, lib_local);
}
void BKE_speaker_free(Speaker *spk)
{
- BKE_animdata_free((ID *)spk, false);
+ BKE_animdata_free((ID *)spk, false);
}
diff --git a/source/blender/blenkernel/intern/studiolight.c b/source/blender/blenkernel/intern/studiolight.c
index 38975f9a227..7a95ec3055e 100644
--- a/source/blender/blenkernel/intern/studiolight.c
+++ b/source/blender/blenkernel/intern/studiolight.c
@@ -46,7 +46,6 @@
#include "MEM_guardedalloc.h"
-
/* Statics */
static ListBase studiolights;
static int last_studiolight_id = 0;
@@ -94,133 +93,141 @@ static const char *STUDIOLIGHT_MATCAP_DEFAULT = "basic_1.exr";
* texel_size[2] : UV size of a pixel in this texture.
* pixel[] : pointer to the current pixel.
*/
-#define ITER_PIXELS(type, src, channels, width, height) \
-{ \
- float texel_size[2]; \
- texel_size[0] = 1.0f / width; \
- texel_size[1] = 1.0f / height; \
- type (*pixel_)[channels] = (type (*)[channels])src; \
- for (float y = 0.5 * texel_size[1]; y < 1.0; y += texel_size[1]) { \
- for (float x = 0.5 * texel_size[0]; x < 1.0; x += texel_size[0], pixel_++) { \
- type *pixel = *pixel_;
-
-#define ITER_PIXELS_END \
- } \
- } \
-} ((void)0)
+#define ITER_PIXELS(type, src, channels, width, height) \
+ { \
+ float texel_size[2]; \
+ texel_size[0] = 1.0f / width; \
+ texel_size[1] = 1.0f / height; \
+ type(*pixel_)[channels] = (type(*)[channels])src; \
+ for (float y = 0.5 * texel_size[1]; y < 1.0; y += texel_size[1]) { \
+ for (float x = 0.5 * texel_size[0]; x < 1.0; x += texel_size[0], pixel_++) { \
+ type *pixel = *pixel_;
+
+#define ITER_PIXELS_END \
+ } \
+ } \
+ } \
+ ((void)0)
/* FUNCTIONS */
-#define IMB_SAFE_FREE(p) do { \
-if (p) { \
- IMB_freeImBuf(p); \
- p = NULL; \
-} \
-} while (0)
-
-#define GPU_TEXTURE_SAFE_FREE(p) do { \
-if (p) { \
- GPU_texture_free(p); \
- p = NULL; \
-} \
-} while (0)
+#define IMB_SAFE_FREE(p) \
+ do { \
+ if (p) { \
+ IMB_freeImBuf(p); \
+ p = NULL; \
+ } \
+ } while (0)
+
+#define GPU_TEXTURE_SAFE_FREE(p) \
+ do { \
+ if (p) { \
+ GPU_texture_free(p); \
+ p = NULL; \
+ } \
+ } while (0)
static void studiolight_free(struct StudioLight *sl)
{
-#define STUDIOLIGHT_DELETE_ICON(s) { \
- if (s != 0) { \
- BKE_icon_delete(s); \
- s = 0; \
- } \
-}
- if (sl->free_function) {
- sl->free_function(sl, sl->free_function_data);
- }
- STUDIOLIGHT_DELETE_ICON(sl->icon_id_radiance);
- STUDIOLIGHT_DELETE_ICON(sl->icon_id_irradiance);
- STUDIOLIGHT_DELETE_ICON(sl->icon_id_matcap);
- STUDIOLIGHT_DELETE_ICON(sl->icon_id_matcap_flipped);
+#define STUDIOLIGHT_DELETE_ICON(s) \
+ { \
+ if (s != 0) { \
+ BKE_icon_delete(s); \
+ s = 0; \
+ } \
+ }
+ if (sl->free_function) {
+ sl->free_function(sl, sl->free_function_data);
+ }
+ STUDIOLIGHT_DELETE_ICON(sl->icon_id_radiance);
+ STUDIOLIGHT_DELETE_ICON(sl->icon_id_irradiance);
+ STUDIOLIGHT_DELETE_ICON(sl->icon_id_matcap);
+ STUDIOLIGHT_DELETE_ICON(sl->icon_id_matcap_flipped);
#undef STUDIOLIGHT_DELETE_ICON
- for (int index = 0; index < 6; index++) {
- IMB_SAFE_FREE(sl->radiance_cubemap_buffers[index]);
- }
- GPU_TEXTURE_SAFE_FREE(sl->equirect_radiance_gputexture);
- GPU_TEXTURE_SAFE_FREE(sl->equirect_irradiance_gputexture);
- IMB_SAFE_FREE(sl->equirect_radiance_buffer);
- IMB_SAFE_FREE(sl->equirect_irradiance_buffer);
- MEM_SAFE_FREE(sl->path_irr_cache);
- MEM_SAFE_FREE(sl->path_sh_cache);
- MEM_SAFE_FREE(sl);
+ for (int index = 0; index < 6; index++) {
+ IMB_SAFE_FREE(sl->radiance_cubemap_buffers[index]);
+ }
+ GPU_TEXTURE_SAFE_FREE(sl->equirect_radiance_gputexture);
+ GPU_TEXTURE_SAFE_FREE(sl->equirect_irradiance_gputexture);
+ IMB_SAFE_FREE(sl->equirect_radiance_buffer);
+ IMB_SAFE_FREE(sl->equirect_irradiance_buffer);
+ MEM_SAFE_FREE(sl->path_irr_cache);
+ MEM_SAFE_FREE(sl->path_sh_cache);
+ MEM_SAFE_FREE(sl);
}
static struct StudioLight *studiolight_create(int flag)
{
- struct StudioLight *sl = MEM_callocN(sizeof(*sl), __func__);
- sl->path[0] = 0x00;
- sl->name[0] = 0x00;
- sl->path_irr_cache = NULL;
- sl->path_sh_cache = NULL;
- sl->free_function = NULL;
- sl->flag = flag;
- sl->index = ++last_studiolight_id;
- if (flag & STUDIOLIGHT_TYPE_STUDIO) {
- sl->icon_id_irradiance = BKE_icon_ensure_studio_light(sl, STUDIOLIGHT_ICON_ID_TYPE_IRRADIANCE);
- }
- else if (flag & STUDIOLIGHT_TYPE_MATCAP) {
- sl->icon_id_matcap = BKE_icon_ensure_studio_light(sl, STUDIOLIGHT_ICON_ID_TYPE_MATCAP);
- sl->icon_id_matcap_flipped = BKE_icon_ensure_studio_light(sl, STUDIOLIGHT_ICON_ID_TYPE_MATCAP_FLIPPED);
- }
- else {
- sl->icon_id_radiance = BKE_icon_ensure_studio_light(sl, STUDIOLIGHT_ICON_ID_TYPE_RADIANCE);
- }
-
- for (int index = 0; index < 6; index++) {
- sl->radiance_cubemap_buffers[index] = NULL;
- }
-
- return sl;
+ struct StudioLight *sl = MEM_callocN(sizeof(*sl), __func__);
+ sl->path[0] = 0x00;
+ sl->name[0] = 0x00;
+ sl->path_irr_cache = NULL;
+ sl->path_sh_cache = NULL;
+ sl->free_function = NULL;
+ sl->flag = flag;
+ sl->index = ++last_studiolight_id;
+ if (flag & STUDIOLIGHT_TYPE_STUDIO) {
+ sl->icon_id_irradiance = BKE_icon_ensure_studio_light(sl, STUDIOLIGHT_ICON_ID_TYPE_IRRADIANCE);
+ }
+ else if (flag & STUDIOLIGHT_TYPE_MATCAP) {
+ sl->icon_id_matcap = BKE_icon_ensure_studio_light(sl, STUDIOLIGHT_ICON_ID_TYPE_MATCAP);
+ sl->icon_id_matcap_flipped = BKE_icon_ensure_studio_light(
+ sl, STUDIOLIGHT_ICON_ID_TYPE_MATCAP_FLIPPED);
+ }
+ else {
+ sl->icon_id_radiance = BKE_icon_ensure_studio_light(sl, STUDIOLIGHT_ICON_ID_TYPE_RADIANCE);
+ }
+
+ for (int index = 0; index < 6; index++) {
+ sl->radiance_cubemap_buffers[index] = NULL;
+ }
+
+ return sl;
}
#define STUDIOLIGHT_FILE_VERSION 1
-#define READ_VAL(type, parser, id, val, lines) do { \
- for (LinkNode *line = lines; line; line = line->next) { \
- char *val_str, *str = line->link; \
- if ((val_str = strstr(str, id " "))) { \
- val_str += sizeof(id); /* Skip id + spacer. */ \
- val = parser(val_str); \
- } \
- } \
-} while (0)
+#define READ_VAL(type, parser, id, val, lines) \
+ do { \
+ for (LinkNode *line = lines; line; line = line->next) { \
+ char *val_str, *str = line->link; \
+ if ((val_str = strstr(str, id " "))) { \
+ val_str += sizeof(id); /* Skip id + spacer. */ \
+ val = parser(val_str); \
+ } \
+ } \
+ } while (0)
#define READ_FVAL(id, val, lines) READ_VAL(float, atof, id, val, lines)
#define READ_IVAL(id, val, lines) READ_VAL(int, atoi, id, val, lines)
-#define READ_VEC3(id, val, lines) do { \
- READ_FVAL(id ".x", val[0], lines); \
- READ_FVAL(id ".y", val[1], lines); \
- READ_FVAL(id ".z", val[2], lines); \
-} while (0)
-
-#define READ_SOLIDLIGHT(sl, i, lines) do { \
- READ_IVAL("light[" STRINGIFY(i) "].flag", sl[i].flag, lines); \
- READ_FVAL("light[" STRINGIFY(i) "].smooth", sl[i].smooth, lines); \
- READ_VEC3("light[" STRINGIFY(i) "].col", sl[i].col, lines); \
- READ_VEC3("light[" STRINGIFY(i) "].spec", sl[i].spec, lines); \
- READ_VEC3("light[" STRINGIFY(i) "].vec", sl[i].vec, lines); \
-} while (0)
+#define READ_VEC3(id, val, lines) \
+ do { \
+ READ_FVAL(id ".x", val[0], lines); \
+ READ_FVAL(id ".y", val[1], lines); \
+ READ_FVAL(id ".z", val[2], lines); \
+ } while (0)
+
+#define READ_SOLIDLIGHT(sl, i, lines) \
+ do { \
+ READ_IVAL("light[" STRINGIFY(i) "].flag", sl[i].flag, lines); \
+ READ_FVAL("light[" STRINGIFY(i) "].smooth", sl[i].smooth, lines); \
+ READ_VEC3("light[" STRINGIFY(i) "].col", sl[i].col, lines); \
+ READ_VEC3("light[" STRINGIFY(i) "].spec", sl[i].spec, lines); \
+ READ_VEC3("light[" STRINGIFY(i) "].vec", sl[i].vec, lines); \
+ } while (0)
static void studiolight_load_solid_light(StudioLight *sl)
{
- LinkNode *lines = BLI_file_read_as_lines(sl->path);
- if (lines) {
- READ_VEC3("light_ambient", sl->light_ambient, lines);
- READ_SOLIDLIGHT(sl->light, 0, lines);
- READ_SOLIDLIGHT(sl->light, 1, lines);
- READ_SOLIDLIGHT(sl->light, 2, lines);
- READ_SOLIDLIGHT(sl->light, 3, lines);
- }
- BLI_file_free_lines(lines);
+ LinkNode *lines = BLI_file_read_as_lines(sl->path);
+ if (lines) {
+ READ_VEC3("light_ambient", sl->light_ambient, lines);
+ READ_SOLIDLIGHT(sl->light, 0, lines);
+ READ_SOLIDLIGHT(sl->light, 1, lines);
+ READ_SOLIDLIGHT(sl->light, 2, lines);
+ READ_SOLIDLIGHT(sl->light, 3, lines);
+ }
+ BLI_file_free_lines(lines);
}
#undef READ_SOLIDLIGHT
@@ -231,42 +238,44 @@ static void studiolight_load_solid_light(StudioLight *sl)
#define WRITE_FVAL(str, id, val) (BLI_dynstr_appendf(str, id " %f\n", val))
#define WRITE_IVAL(str, id, val) (BLI_dynstr_appendf(str, id " %d\n", val))
-#define WRITE_VEC3(str, id, val) do { \
- WRITE_FVAL(str, id ".x", val[0]); \
- WRITE_FVAL(str, id ".y", val[1]); \
- WRITE_FVAL(str, id ".z", val[2]); \
-} while (0)
-
-#define WRITE_SOLIDLIGHT(str, sl, i) do { \
- WRITE_IVAL(str, "light[" STRINGIFY(i) "].flag", sl[i].flag); \
- WRITE_FVAL(str, "light[" STRINGIFY(i) "].smooth", sl[i].smooth); \
- WRITE_VEC3(str, "light[" STRINGIFY(i) "].col", sl[i].col); \
- WRITE_VEC3(str, "light[" STRINGIFY(i) "].spec", sl[i].spec); \
- WRITE_VEC3(str, "light[" STRINGIFY(i) "].vec", sl[i].vec); \
-} while (0)
+#define WRITE_VEC3(str, id, val) \
+ do { \
+ WRITE_FVAL(str, id ".x", val[0]); \
+ WRITE_FVAL(str, id ".y", val[1]); \
+ WRITE_FVAL(str, id ".z", val[2]); \
+ } while (0)
+
+#define WRITE_SOLIDLIGHT(str, sl, i) \
+ do { \
+ WRITE_IVAL(str, "light[" STRINGIFY(i) "].flag", sl[i].flag); \
+ WRITE_FVAL(str, "light[" STRINGIFY(i) "].smooth", sl[i].smooth); \
+ WRITE_VEC3(str, "light[" STRINGIFY(i) "].col", sl[i].col); \
+ WRITE_VEC3(str, "light[" STRINGIFY(i) "].spec", sl[i].spec); \
+ WRITE_VEC3(str, "light[" STRINGIFY(i) "].vec", sl[i].vec); \
+ } while (0)
static void studiolight_write_solid_light(StudioLight *sl)
{
- FILE *fp = BLI_fopen(sl->path, "wb");
- if (fp) {
- DynStr *str = BLI_dynstr_new();
-
- /* Very dumb ascii format. One value per line separated by a space. */
- WRITE_IVAL(str, "version", STUDIOLIGHT_FILE_VERSION);
- WRITE_VEC3(str, "light_ambient", sl->light_ambient);
- WRITE_SOLIDLIGHT(str, sl->light, 0);
- WRITE_SOLIDLIGHT(str, sl->light, 1);
- WRITE_SOLIDLIGHT(str, sl->light, 2);
- WRITE_SOLIDLIGHT(str, sl->light, 3);
-
- char *cstr = BLI_dynstr_get_cstring(str);
-
- fwrite(cstr, BLI_dynstr_get_len(str), 1, fp);
- fclose(fp);
-
- MEM_freeN(cstr);
- BLI_dynstr_free(str);
- }
+ FILE *fp = BLI_fopen(sl->path, "wb");
+ if (fp) {
+ DynStr *str = BLI_dynstr_new();
+
+ /* Very dumb ascii format. One value per line separated by a space. */
+ WRITE_IVAL(str, "version", STUDIOLIGHT_FILE_VERSION);
+ WRITE_VEC3(str, "light_ambient", sl->light_ambient);
+ WRITE_SOLIDLIGHT(str, sl->light, 0);
+ WRITE_SOLIDLIGHT(str, sl->light, 1);
+ WRITE_SOLIDLIGHT(str, sl->light, 2);
+ WRITE_SOLIDLIGHT(str, sl->light, 3);
+
+ char *cstr = BLI_dynstr_get_cstring(str);
+
+ fwrite(cstr, BLI_dynstr_get_len(str), 1, fp);
+ fclose(fp);
+
+ MEM_freeN(cstr);
+ BLI_dynstr_free(str);
+ }
}
#undef WRITE_SOLIDLIGHT
@@ -276,203 +285,217 @@ static void studiolight_write_solid_light(StudioLight *sl)
static void direction_to_equirect(float r[2], const float dir[3])
{
- r[0] = (atan2f(dir[1], dir[0]) - M_PI) / -(M_PI * 2);
- r[1] = (acosf(dir[2] / 1.0) - M_PI) / -M_PI;
+ r[0] = (atan2f(dir[1], dir[0]) - M_PI) / -(M_PI * 2);
+ r[1] = (acosf(dir[2] / 1.0) - M_PI) / -M_PI;
}
static void equirect_to_direction(float r[3], float u, float v)
{
- float phi = (-(M_PI * 2)) * u + M_PI;
- float theta = -M_PI * v + M_PI;
- float sin_theta = sinf(theta);
- r[0] = sin_theta * cosf(phi);
- r[1] = sin_theta * sinf(phi);
- r[2] = cosf(theta);
+ float phi = (-(M_PI * 2)) * u + M_PI;
+ float theta = -M_PI * v + M_PI;
+ float sin_theta = sinf(theta);
+ r[0] = sin_theta * cosf(phi);
+ r[1] = sin_theta * sinf(phi);
+ r[2] = cosf(theta);
}
-static void UNUSED_FUNCTION(direction_to_cube_face_uv)(float r_uv[2], int *r_face, const float dir[3])
+static void UNUSED_FUNCTION(direction_to_cube_face_uv)(float r_uv[2],
+ int *r_face,
+ const float dir[3])
{
- if (fabsf(dir[0]) > fabsf(dir[1]) && fabsf(dir[0]) > fabsf(dir[2])) {
- bool is_pos = (dir[0] > 0.0f);
- *r_face = is_pos ? STUDIOLIGHT_X_POS : STUDIOLIGHT_X_NEG;
- r_uv[0] = dir[2] / fabsf(dir[0]) * (is_pos ? 1 : -1);
- r_uv[1] = dir[1] / fabsf(dir[0]) * (is_pos ? -1 : -1);
- }
- else if (fabsf(dir[1]) > fabsf(dir[0]) && fabsf(dir[1]) > fabsf(dir[2])) {
- bool is_pos = (dir[1] > 0.0f);
- *r_face = is_pos ? STUDIOLIGHT_Y_POS : STUDIOLIGHT_Y_NEG;
- r_uv[0] = dir[0] / fabsf(dir[1]) * (is_pos ? 1 : 1);
- r_uv[1] = dir[2] / fabsf(dir[1]) * (is_pos ? -1 : 1);
- }
- else {
- bool is_pos = (dir[2] > 0.0f);
- *r_face = is_pos ? STUDIOLIGHT_Z_NEG : STUDIOLIGHT_Z_POS;
- r_uv[0] = dir[0] / fabsf(dir[2]) * (is_pos ? -1 : 1);
- r_uv[1] = dir[1] / fabsf(dir[2]) * (is_pos ? -1 : -1);
- }
- r_uv[0] = r_uv[0] * 0.5f + 0.5f;
- r_uv[1] = r_uv[1] * 0.5f + 0.5f;
+ if (fabsf(dir[0]) > fabsf(dir[1]) && fabsf(dir[0]) > fabsf(dir[2])) {
+ bool is_pos = (dir[0] > 0.0f);
+ *r_face = is_pos ? STUDIOLIGHT_X_POS : STUDIOLIGHT_X_NEG;
+ r_uv[0] = dir[2] / fabsf(dir[0]) * (is_pos ? 1 : -1);
+ r_uv[1] = dir[1] / fabsf(dir[0]) * (is_pos ? -1 : -1);
+ }
+ else if (fabsf(dir[1]) > fabsf(dir[0]) && fabsf(dir[1]) > fabsf(dir[2])) {
+ bool is_pos = (dir[1] > 0.0f);
+ *r_face = is_pos ? STUDIOLIGHT_Y_POS : STUDIOLIGHT_Y_NEG;
+ r_uv[0] = dir[0] / fabsf(dir[1]) * (is_pos ? 1 : 1);
+ r_uv[1] = dir[2] / fabsf(dir[1]) * (is_pos ? -1 : 1);
+ }
+ else {
+ bool is_pos = (dir[2] > 0.0f);
+ *r_face = is_pos ? STUDIOLIGHT_Z_NEG : STUDIOLIGHT_Z_POS;
+ r_uv[0] = dir[0] / fabsf(dir[2]) * (is_pos ? -1 : 1);
+ r_uv[1] = dir[1] / fabsf(dir[2]) * (is_pos ? -1 : -1);
+ }
+ r_uv[0] = r_uv[0] * 0.5f + 0.5f;
+ r_uv[1] = r_uv[1] * 0.5f + 0.5f;
}
static void cube_face_uv_to_direction(float r_dir[3], float x, float y, int face)
{
- const float conversion_matrices[6][3][3] = {
- {{ 0.0f, 0.0f, 1.0f}, {0.0f, -1.0f, 0.0f}, { 1.0f, 0.0f, 0.0f}},
- {{ 0.0f, 0.0f, -1.0f}, {0.0f, -1.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}},
- {{ 1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, { 0.0f, 1.0f, 0.0f}},
- {{ 1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, { 0.0f, -1.0f, 0.0f}},
- {{ 1.0f, 0.0f, 0.0f}, {0.0f, -1.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}},
- {{-1.0f, 0.0f, 0.0f}, {0.0f, -1.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}},
- };
-
- copy_v3_fl3(r_dir, x * 2.0f - 1.0f, y * 2.0f - 1.0f, 1.0f);
- mul_m3_v3(conversion_matrices[face], r_dir);
- normalize_v3(r_dir);
+ const float conversion_matrices[6][3][3] = {
+ {{0.0f, 0.0f, 1.0f}, {0.0f, -1.0f, 0.0f}, {1.0f, 0.0f, 0.0f}},
+ {{0.0f, 0.0f, -1.0f}, {0.0f, -1.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}},
+ {{1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 1.0f, 0.0f}},
+ {{1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, {0.0f, -1.0f, 0.0f}},
+ {{1.0f, 0.0f, 0.0f}, {0.0f, -1.0f, 0.0f}, {0.0f, 0.0f, -1.0f}},
+ {{-1.0f, 0.0f, 0.0f}, {0.0f, -1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}},
+ };
+
+ copy_v3_fl3(r_dir, x * 2.0f - 1.0f, y * 2.0f - 1.0f, 1.0f);
+ mul_m3_v3(conversion_matrices[face], r_dir);
+ normalize_v3(r_dir);
}
static void studiolight_load_equirect_image(StudioLight *sl)
{
- if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
- ImBuf *ibuf = NULL;
- ibuf = IMB_loadiffname(sl->path, 0, NULL);
- if (ibuf == NULL) {
- float *colbuf = MEM_mallocN(sizeof(float[4]), __func__);
- copy_v4_fl4(colbuf, 1.0f, 0.0f, 1.0f, 1.0f);
- ibuf = IMB_allocFromBuffer(NULL, colbuf, 1, 1);
- }
- IMB_float_from_rect(ibuf);
- sl->equirect_radiance_buffer = ibuf;
- }
- sl->flag |= STUDIOLIGHT_EXTERNAL_IMAGE_LOADED;
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ ImBuf *ibuf = NULL;
+ ibuf = IMB_loadiffname(sl->path, 0, NULL);
+ if (ibuf == NULL) {
+ float *colbuf = MEM_mallocN(sizeof(float[4]), __func__);
+ copy_v4_fl4(colbuf, 1.0f, 0.0f, 1.0f, 1.0f);
+ ibuf = IMB_allocFromBuffer(NULL, colbuf, 1, 1);
+ }
+ IMB_float_from_rect(ibuf);
+ sl->equirect_radiance_buffer = ibuf;
+ }
+ sl->flag |= STUDIOLIGHT_EXTERNAL_IMAGE_LOADED;
}
static void studiolight_create_equirect_radiance_gputexture(StudioLight *sl)
{
- if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
- char error[256];
- BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
- ImBuf *ibuf = sl->equirect_radiance_buffer;
-
- if (sl->flag & STUDIOLIGHT_TYPE_MATCAP) {
- float *gpu_matcap_3components = MEM_callocN(sizeof(float[3]) * ibuf->x * ibuf->y, __func__);
-
- float (*offset4)[4] = (float (*)[4])ibuf->rect_float;
- float (*offset3)[3] = (float (*)[3])gpu_matcap_3components;
- for (int i = 0; i < ibuf->x * ibuf->y; i++, offset4++, offset3++) {
- copy_v3_v3(*offset3, *offset4);
- }
-
- sl->equirect_radiance_gputexture = GPU_texture_create_nD(
- ibuf->x, ibuf->y, 0, 2, gpu_matcap_3components, GPU_R11F_G11F_B10F, GPU_DATA_FLOAT, 0, false, error);
-
- MEM_SAFE_FREE(gpu_matcap_3components);
- }
- else {
- sl->equirect_radiance_gputexture = GPU_texture_create_2d(
- ibuf->x, ibuf->y, GPU_RGBA16F, ibuf->rect_float, error);
- GPUTexture *tex = sl->equirect_radiance_gputexture;
- GPU_texture_bind(tex, 0);
- GPU_texture_filter_mode(tex, true);
- GPU_texture_wrap_mode(tex, true);
- GPU_texture_unbind(tex);
- }
- }
- sl->flag |= STUDIOLIGHT_EQUIRECT_RADIANCE_GPUTEXTURE;
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ char error[256];
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
+ ImBuf *ibuf = sl->equirect_radiance_buffer;
+
+ if (sl->flag & STUDIOLIGHT_TYPE_MATCAP) {
+ float *gpu_matcap_3components = MEM_callocN(sizeof(float[3]) * ibuf->x * ibuf->y, __func__);
+
+ float(*offset4)[4] = (float(*)[4])ibuf->rect_float;
+ float(*offset3)[3] = (float(*)[3])gpu_matcap_3components;
+ for (int i = 0; i < ibuf->x * ibuf->y; i++, offset4++, offset3++) {
+ copy_v3_v3(*offset3, *offset4);
+ }
+
+ sl->equirect_radiance_gputexture = GPU_texture_create_nD(ibuf->x,
+ ibuf->y,
+ 0,
+ 2,
+ gpu_matcap_3components,
+ GPU_R11F_G11F_B10F,
+ GPU_DATA_FLOAT,
+ 0,
+ false,
+ error);
+
+ MEM_SAFE_FREE(gpu_matcap_3components);
+ }
+ else {
+ sl->equirect_radiance_gputexture = GPU_texture_create_2d(
+ ibuf->x, ibuf->y, GPU_RGBA16F, ibuf->rect_float, error);
+ GPUTexture *tex = sl->equirect_radiance_gputexture;
+ GPU_texture_bind(tex, 0);
+ GPU_texture_filter_mode(tex, true);
+ GPU_texture_wrap_mode(tex, true);
+ GPU_texture_unbind(tex);
+ }
+ }
+ sl->flag |= STUDIOLIGHT_EQUIRECT_RADIANCE_GPUTEXTURE;
}
static void studiolight_create_equirect_irradiance_gputexture(StudioLight *sl)
{
- if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
- char error[256];
- BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECT_IRRADIANCE_IMAGE_CALCULATED);
- ImBuf *ibuf = sl->equirect_irradiance_buffer;
- sl->equirect_irradiance_gputexture = GPU_texture_create_2d(
- ibuf->x, ibuf->y, GPU_RGBA16F, ibuf->rect_float, error);
- GPUTexture *tex = sl->equirect_irradiance_gputexture;
- GPU_texture_bind(tex, 0);
- GPU_texture_filter_mode(tex, true);
- GPU_texture_wrap_mode(tex, true);
- GPU_texture_unbind(tex);
- }
- sl->flag |= STUDIOLIGHT_EQUIRECT_IRRADIANCE_GPUTEXTURE;
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ char error[256];
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECT_IRRADIANCE_IMAGE_CALCULATED);
+ ImBuf *ibuf = sl->equirect_irradiance_buffer;
+ sl->equirect_irradiance_gputexture = GPU_texture_create_2d(
+ ibuf->x, ibuf->y, GPU_RGBA16F, ibuf->rect_float, error);
+ GPUTexture *tex = sl->equirect_irradiance_gputexture;
+ GPU_texture_bind(tex, 0);
+ GPU_texture_filter_mode(tex, true);
+ GPU_texture_wrap_mode(tex, true);
+ GPU_texture_unbind(tex);
+ }
+ sl->flag |= STUDIOLIGHT_EQUIRECT_IRRADIANCE_GPUTEXTURE;
}
static void studiolight_calculate_radiance(ImBuf *ibuf, float color[4], const float direction[3])
{
- float uv[2];
- direction_to_equirect(uv, direction);
- nearest_interpolation_color_wrap(ibuf, NULL, color, uv[0] * ibuf->x, uv[1] * ibuf->y);
+ float uv[2];
+ direction_to_equirect(uv, direction);
+ nearest_interpolation_color_wrap(ibuf, NULL, color, uv[0] * ibuf->x, uv[1] * ibuf->y);
}
-static void studiolight_calculate_radiance_buffer(
- ImBuf *ibuf, float *colbuf,
- const int index_x, const int index_y, const int index_z,
- const float xsign, const float ysign, const float zsign)
+static void studiolight_calculate_radiance_buffer(ImBuf *ibuf,
+ float *colbuf,
+ const int index_x,
+ const int index_y,
+ const int index_z,
+ const float xsign,
+ const float ysign,
+ const float zsign)
{
- ITER_PIXELS(float, colbuf, 4,
- STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE,
- STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE)
- {
- float direction[3];
- direction[index_x] = xsign * (x - 0.5f);
- direction[index_y] = ysign * (y - 0.5f);
- direction[index_z] = zsign * 0.5f;
- normalize_v3(direction);
- studiolight_calculate_radiance(ibuf, pixel, direction);
- }
- ITER_PIXELS_END;
+ ITER_PIXELS(
+ float, colbuf, 4, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE)
+ {
+ float direction[3];
+ direction[index_x] = xsign * (x - 0.5f);
+ direction[index_y] = ysign * (y - 0.5f);
+ direction[index_z] = zsign * 0.5f;
+ normalize_v3(direction);
+ studiolight_calculate_radiance(ibuf, pixel, direction);
+ }
+ ITER_PIXELS_END;
}
static void studiolight_calculate_radiance_cubemap_buffers(StudioLight *sl)
{
- if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
- BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
- ImBuf *ibuf = sl->equirect_radiance_buffer;
- if (ibuf) {
- float *colbuf = MEM_mallocN(SQUARE(STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) * sizeof(float[4]), __func__);
-
- /* front */
- studiolight_calculate_radiance_buffer(ibuf, colbuf, 0, 2, 1, 1, -1, 1);
- sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_POS] = IMB_allocFromBuffer(
- NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
-
- /* back */
- studiolight_calculate_radiance_buffer(ibuf, colbuf, 0, 2, 1, 1, 1, -1);
- sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_NEG] = IMB_allocFromBuffer(
- NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
-
- /* left */
- studiolight_calculate_radiance_buffer(ibuf, colbuf, 2, 1, 0, 1, -1, 1);
- sl->radiance_cubemap_buffers[STUDIOLIGHT_X_POS] = IMB_allocFromBuffer(
- NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
-
- /* right */
- studiolight_calculate_radiance_buffer(ibuf, colbuf, 2, 1, 0, -1, -1, -1);
- sl->radiance_cubemap_buffers[STUDIOLIGHT_X_NEG] = IMB_allocFromBuffer(
- NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
-
- /* top */
- studiolight_calculate_radiance_buffer(ibuf, colbuf, 0, 1, 2, -1, -1, 1);
- sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_NEG] = IMB_allocFromBuffer(
- NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
-
- /* bottom */
- studiolight_calculate_radiance_buffer(ibuf, colbuf, 0, 1, 2, 1, -1, -1);
- sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_POS] = IMB_allocFromBuffer(
- NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
+ ImBuf *ibuf = sl->equirect_radiance_buffer;
+ if (ibuf) {
+ float *colbuf = MEM_mallocN(SQUARE(STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) * sizeof(float[4]),
+ __func__);
+
+ /* front */
+ studiolight_calculate_radiance_buffer(ibuf, colbuf, 0, 2, 1, 1, -1, 1);
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_POS] = IMB_allocFromBuffer(
+ NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+
+ /* back */
+ studiolight_calculate_radiance_buffer(ibuf, colbuf, 0, 2, 1, 1, 1, -1);
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_NEG] = IMB_allocFromBuffer(
+ NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+
+ /* left */
+ studiolight_calculate_radiance_buffer(ibuf, colbuf, 2, 1, 0, 1, -1, 1);
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_X_POS] = IMB_allocFromBuffer(
+ NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+
+ /* right */
+ studiolight_calculate_radiance_buffer(ibuf, colbuf, 2, 1, 0, -1, -1, -1);
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_X_NEG] = IMB_allocFromBuffer(
+ NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+
+ /* top */
+ studiolight_calculate_radiance_buffer(ibuf, colbuf, 0, 1, 2, -1, -1, 1);
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_NEG] = IMB_allocFromBuffer(
+ NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+
+ /* bottom */
+ studiolight_calculate_radiance_buffer(ibuf, colbuf, 0, 1, 2, 1, -1, -1);
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_POS] = IMB_allocFromBuffer(
+ NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
#if 0
- IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_X_POS], "/tmp/studiolight_radiance_left.png", IB_rectfloat);
- IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_X_NEG], "/tmp/studiolight_radiance_right.png", IB_rectfloat);
- IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_POS], "/tmp/studiolight_radiance_front.png", IB_rectfloat);
- IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_NEG], "/tmp/studiolight_radiance_back.png", IB_rectfloat);
- IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_POS], "/tmp/studiolight_radiance_bottom.png", IB_rectfloat);
- IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_NEG], "/tmp/studiolight_radiance_top.png", IB_rectfloat);
+ IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_X_POS], "/tmp/studiolight_radiance_left.png", IB_rectfloat);
+ IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_X_NEG], "/tmp/studiolight_radiance_right.png", IB_rectfloat);
+ IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_POS], "/tmp/studiolight_radiance_front.png", IB_rectfloat);
+ IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_NEG], "/tmp/studiolight_radiance_back.png", IB_rectfloat);
+ IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_POS], "/tmp/studiolight_radiance_bottom.png", IB_rectfloat);
+ IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_NEG], "/tmp/studiolight_radiance_top.png", IB_rectfloat);
#endif
- MEM_freeN(colbuf);
- }
- }
- sl->flag |= STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED;
+ MEM_freeN(colbuf);
+ }
+ }
+ sl->flag |= STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED;
}
/*
@@ -480,236 +503,262 @@ static void studiolight_calculate_radiance_cubemap_buffers(StudioLight *sl)
*/
BLI_INLINE float area_element(float x, float y)
{
- return atan2(x * y, sqrtf(x * x + y * y + 1));
+ return atan2(x * y, sqrtf(x * x + y * y + 1));
}
BLI_INLINE float texel_solid_angle(float x, float y, float halfpix)
{
- float v1x = (x - halfpix) * 2.0f - 1.0f;
- float v1y = (y - halfpix) * 2.0f - 1.0f;
- float v2x = (x + halfpix) * 2.0f - 1.0f;
- float v2y = (y + halfpix) * 2.0f - 1.0f;
+ float v1x = (x - halfpix) * 2.0f - 1.0f;
+ float v1y = (y - halfpix) * 2.0f - 1.0f;
+ float v2x = (x + halfpix) * 2.0f - 1.0f;
+ float v2y = (y + halfpix) * 2.0f - 1.0f;
- return area_element(v1x, v1y) - area_element(v1x, v2y) - area_element(v2x, v1y) + area_element(v2x, v2y);
+ return area_element(v1x, v1y) - area_element(v1x, v2y) - area_element(v2x, v1y) +
+ area_element(v2x, v2y);
}
-static void studiolight_calculate_cubemap_vector_weight(float normal[3], float *weight, int face, float x, float y)
+static void studiolight_calculate_cubemap_vector_weight(
+ float normal[3], float *weight, int face, float x, float y)
{
- const float halfpix = 0.5f / STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE;
- cube_face_uv_to_direction(normal, x, y, face);
- *weight = texel_solid_angle(x, y, halfpix);
+ const float halfpix = 0.5f / STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE;
+ cube_face_uv_to_direction(normal, x, y, face);
+ *weight = texel_solid_angle(x, y, halfpix);
}
static void studiolight_spherical_harmonics_calculate_coefficients(StudioLight *sl, float (*sh)[3])
{
- float weight_accum = 0.0f;
- memset(sh, 0, sizeof(float) * 3 * STUDIOLIGHT_SH_COEFS_LEN);
-
- for (int face = 0; face < 6; face++) {
- ITER_PIXELS(float, sl->radiance_cubemap_buffers[face]->rect_float, 4,
- STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE,
- STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE)
- {
- float color[3], cubevec[3], weight;
- studiolight_calculate_cubemap_vector_weight(cubevec, &weight, face, x, y);
- mul_v3_v3fl(color, pixel, weight);
- weight_accum += weight;
-
- int i = 0;
- /* L0 */
- madd_v3_v3fl(sh[i++], color, 0.2822095f);
+ float weight_accum = 0.0f;
+ memset(sh, 0, sizeof(float) * 3 * STUDIOLIGHT_SH_COEFS_LEN);
+
+ for (int face = 0; face < 6; face++) {
+ ITER_PIXELS(float,
+ sl->radiance_cubemap_buffers[face]->rect_float,
+ 4,
+ STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE,
+ STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE)
+ {
+ float color[3], cubevec[3], weight;
+ studiolight_calculate_cubemap_vector_weight(cubevec, &weight, face, x, y);
+ mul_v3_v3fl(color, pixel, weight);
+ weight_accum += weight;
+
+ int i = 0;
+ /* L0 */
+ madd_v3_v3fl(sh[i++], color, 0.2822095f);
#if STUDIOLIGHT_SH_BANDS > 1 /* L1 */
- const float nx = cubevec[0];
- const float ny = cubevec[1];
- const float nz = cubevec[2];
- madd_v3_v3fl(sh[i++], color, -0.488603f * nz);
- madd_v3_v3fl(sh[i++], color, 0.488603f * ny);
- madd_v3_v3fl(sh[i++], color, -0.488603f * nx);
+ const float nx = cubevec[0];
+ const float ny = cubevec[1];
+ const float nz = cubevec[2];
+ madd_v3_v3fl(sh[i++], color, -0.488603f * nz);
+ madd_v3_v3fl(sh[i++], color, 0.488603f * ny);
+ madd_v3_v3fl(sh[i++], color, -0.488603f * nx);
#endif
#if STUDIOLIGHT_SH_BANDS > 2 /* L2 */
- const float nx2 = SQUARE(nx);
- const float ny2 = SQUARE(ny);
- const float nz2 = SQUARE(nz);
- madd_v3_v3fl(sh[i++], color, 1.092548f * nx * nz);
- madd_v3_v3fl(sh[i++], color, -1.092548f * nz * ny);
- madd_v3_v3fl(sh[i++], color, 0.315392f * (3.0f * ny2 - 1.0f));
- madd_v3_v3fl(sh[i++], color, 1.092548f * nx * ny);
- madd_v3_v3fl(sh[i++], color, 0.546274f * (nx2 - nz2));
+ const float nx2 = SQUARE(nx);
+ const float ny2 = SQUARE(ny);
+ const float nz2 = SQUARE(nz);
+ madd_v3_v3fl(sh[i++], color, 1.092548f * nx * nz);
+ madd_v3_v3fl(sh[i++], color, -1.092548f * nz * ny);
+ madd_v3_v3fl(sh[i++], color, 0.315392f * (3.0f * ny2 - 1.0f));
+ madd_v3_v3fl(sh[i++], color, 1.092548f * nx * ny);
+ madd_v3_v3fl(sh[i++], color, 0.546274f * (nx2 - nz2));
#endif
- /* Bypass L3 Because final irradiance does not need it. */
+ /* Bypass L3 Because final irradiance does not need it. */
#if STUDIOLIGHT_SH_BANDS > 4 /* L4 */
- const float nx4 = SQUARE(nx2);
- const float ny4 = SQUARE(ny2);
- const float nz4 = SQUARE(nz2);
- madd_v3_v3fl(sh[i++], color, 2.5033429417967046f * nx * nz * (nx2 - nz2));
- madd_v3_v3fl(sh[i++], color, -1.7701307697799304f * nz * ny * (3.0f * nx2 - nz2));
- madd_v3_v3fl(sh[i++], color, 0.9461746957575601f * nz * nx * (-1.0f + 7.0f * ny2));
- madd_v3_v3fl(sh[i++], color, -0.6690465435572892f * nz * ny * (-3.0f + 7.0f * ny2));
- madd_v3_v3fl(sh[i++], color, (105.0f * ny4 - 90.0f * ny2 + 9.0f) / 28.359261614f);
- madd_v3_v3fl(sh[i++], color, -0.6690465435572892f * nx * ny * (-3.0f + 7.0f * ny2));
- madd_v3_v3fl(sh[i++], color, 0.9461746957575601f * (nx2 - nz2) * (-1.0f + 7.0f * ny2));
- madd_v3_v3fl(sh[i++], color, -1.7701307697799304f * nx * ny * (nx2 - 3.0f * nz2));
- madd_v3_v3fl(sh[i++], color, 0.6258357354491761f * (nx4 - 6.0f * nz2 * nx2 + nz4));
+ const float nx4 = SQUARE(nx2);
+ const float ny4 = SQUARE(ny2);
+ const float nz4 = SQUARE(nz2);
+ madd_v3_v3fl(sh[i++], color, 2.5033429417967046f * nx * nz * (nx2 - nz2));
+ madd_v3_v3fl(sh[i++], color, -1.7701307697799304f * nz * ny * (3.0f * nx2 - nz2));
+ madd_v3_v3fl(sh[i++], color, 0.9461746957575601f * nz * nx * (-1.0f + 7.0f * ny2));
+ madd_v3_v3fl(sh[i++], color, -0.6690465435572892f * nz * ny * (-3.0f + 7.0f * ny2));
+ madd_v3_v3fl(sh[i++], color, (105.0f * ny4 - 90.0f * ny2 + 9.0f) / 28.359261614f);
+ madd_v3_v3fl(sh[i++], color, -0.6690465435572892f * nx * ny * (-3.0f + 7.0f * ny2));
+ madd_v3_v3fl(sh[i++], color, 0.9461746957575601f * (nx2 - nz2) * (-1.0f + 7.0f * ny2));
+ madd_v3_v3fl(sh[i++], color, -1.7701307697799304f * nx * ny * (nx2 - 3.0f * nz2));
+ madd_v3_v3fl(sh[i++], color, 0.6258357354491761f * (nx4 - 6.0f * nz2 * nx2 + nz4));
#endif
- }
- ITER_PIXELS_END;
- }
-
- /* The sum of solid angle should be equal to the solid angle of the sphere (4 PI),
- * so normalize in order to make our weightAccum exactly match 4 PI. */
- for (int i = 0; i < STUDIOLIGHT_SH_COEFS_LEN; ++i) {
- mul_v3_fl(sh[i], M_PI * 4.0f / weight_accum);
- }
+ }
+ ITER_PIXELS_END;
+ }
+
+ /* The sum of solid angle should be equal to the solid angle of the sphere (4 PI),
+ * so normalize in order to make our weightAccum exactly match 4 PI. */
+ for (int i = 0; i < STUDIOLIGHT_SH_COEFS_LEN; ++i) {
+ mul_v3_fl(sh[i], M_PI * 4.0f / weight_accum);
+ }
}
/* Take monochrome SH as input */
static float studiolight_spherical_harmonics_lambda_get(float *sh, float max_laplacian)
{
- /* From Peter-Pike Sloan's Stupid SH Tricks http://www.ppsloan.org/publications/StupidSH36.pdf */
- float table_l[STUDIOLIGHT_SH_BANDS];
- float table_b[STUDIOLIGHT_SH_BANDS];
-
- float lambda = 0.0f;
-
- table_l[0] = 0.0f;
- table_b[0] = 0.0f;
- int index = 1;
- for (int level = 1; level < STUDIOLIGHT_SH_BANDS; level++) {
- table_l[level] = (float)(SQUARE(level) * SQUARE(level + 1));
-
- float b = 0.0f;
- for (int m = -1; m <= level; m++) {
- b += SQUARE(sh[index++]);
- }
- table_b[level] = b;
- }
-
- float squared_lamplacian = 0.0f;
- for (int level = 1; level < STUDIOLIGHT_SH_BANDS; level++) {
- squared_lamplacian += table_l[level] * table_b[level];
- }
-
- const float target_squared_laplacian = max_laplacian * max_laplacian;
- if (squared_lamplacian <= target_squared_laplacian) {
- return lambda;
- }
-
- const int no_iterations = 10000000;
- for (int i = 0; i < no_iterations; ++i) {
- float f = 0.0f;
- float fd = 0.0f;
-
- for (int level = 1; level < STUDIOLIGHT_SH_BANDS; ++level) {
- f += table_l[level] * table_b[level] / SQUARE(1.0f + lambda * table_l[level]);
- fd += (2.0f * SQUARE(table_l[level]) * table_b[level]) / CUBE(1.0f + lambda * table_l[level]);
- }
-
- f = target_squared_laplacian - f;
-
- float delta = -f / fd;
- lambda += delta;
-
- if (ABS(delta) < 1e-6f) {
- break;
- }
- }
-
- return lambda;
+ /* From Peter-Pike Sloan's Stupid SH Tricks http://www.ppsloan.org/publications/StupidSH36.pdf */
+ float table_l[STUDIOLIGHT_SH_BANDS];
+ float table_b[STUDIOLIGHT_SH_BANDS];
+
+ float lambda = 0.0f;
+
+ table_l[0] = 0.0f;
+ table_b[0] = 0.0f;
+ int index = 1;
+ for (int level = 1; level < STUDIOLIGHT_SH_BANDS; level++) {
+ table_l[level] = (float)(SQUARE(level) * SQUARE(level + 1));
+
+ float b = 0.0f;
+ for (int m = -1; m <= level; m++) {
+ b += SQUARE(sh[index++]);
+ }
+ table_b[level] = b;
+ }
+
+ float squared_lamplacian = 0.0f;
+ for (int level = 1; level < STUDIOLIGHT_SH_BANDS; level++) {
+ squared_lamplacian += table_l[level] * table_b[level];
+ }
+
+ const float target_squared_laplacian = max_laplacian * max_laplacian;
+ if (squared_lamplacian <= target_squared_laplacian) {
+ return lambda;
+ }
+
+ const int no_iterations = 10000000;
+ for (int i = 0; i < no_iterations; ++i) {
+ float f = 0.0f;
+ float fd = 0.0f;
+
+ for (int level = 1; level < STUDIOLIGHT_SH_BANDS; ++level) {
+ f += table_l[level] * table_b[level] / SQUARE(1.0f + lambda * table_l[level]);
+ fd += (2.0f * SQUARE(table_l[level]) * table_b[level]) /
+ CUBE(1.0f + lambda * table_l[level]);
+ }
+
+ f = target_squared_laplacian - f;
+
+ float delta = -f / fd;
+ lambda += delta;
+
+ if (ABS(delta) < 1e-6f) {
+ break;
+ }
+ }
+
+ return lambda;
}
static void studiolight_spherical_harmonics_apply_windowing(float (*sh)[3], float max_laplacian)
{
- if (max_laplacian <= 0.0f)
- return;
-
- float sh_r[STUDIOLIGHT_SH_COEFS_LEN];
- float sh_g[STUDIOLIGHT_SH_COEFS_LEN];
- float sh_b[STUDIOLIGHT_SH_COEFS_LEN];
- for (int i = 0; i < STUDIOLIGHT_SH_COEFS_LEN; i++) {
- sh_r[i] = sh[i][0];
- sh_g[i] = sh[i][1];
- sh_b[i] = sh[i][2];
- }
- float lambda_r = studiolight_spherical_harmonics_lambda_get(sh_r, max_laplacian);
- float lambda_g = studiolight_spherical_harmonics_lambda_get(sh_g, max_laplacian);
- float lambda_b = studiolight_spherical_harmonics_lambda_get(sh_b, max_laplacian);
-
- /* Apply windowing lambda */
- int index = 0;
- for (int level = 0; level < STUDIOLIGHT_SH_BANDS; level++) {
- float s[3];
- s[0] = 1.0f / (1.0f + lambda_r * SQUARE(level) * SQUARE(level + 1.0f));
- s[1] = 1.0f / (1.0f + lambda_g * SQUARE(level) * SQUARE(level + 1.0f));
- s[2] = 1.0f / (1.0f + lambda_b * SQUARE(level) * SQUARE(level + 1.0f));
-
- for (int m = -1; m <= level; m++) {
- mul_v3_v3(sh[index++], s);
- }
- }
+ if (max_laplacian <= 0.0f)
+ return;
+
+ float sh_r[STUDIOLIGHT_SH_COEFS_LEN];
+ float sh_g[STUDIOLIGHT_SH_COEFS_LEN];
+ float sh_b[STUDIOLIGHT_SH_COEFS_LEN];
+ for (int i = 0; i < STUDIOLIGHT_SH_COEFS_LEN; i++) {
+ sh_r[i] = sh[i][0];
+ sh_g[i] = sh[i][1];
+ sh_b[i] = sh[i][2];
+ }
+ float lambda_r = studiolight_spherical_harmonics_lambda_get(sh_r, max_laplacian);
+ float lambda_g = studiolight_spherical_harmonics_lambda_get(sh_g, max_laplacian);
+ float lambda_b = studiolight_spherical_harmonics_lambda_get(sh_b, max_laplacian);
+
+ /* Apply windowing lambda */
+ int index = 0;
+ for (int level = 0; level < STUDIOLIGHT_SH_BANDS; level++) {
+ float s[3];
+ s[0] = 1.0f / (1.0f + lambda_r * SQUARE(level) * SQUARE(level + 1.0f));
+ s[1] = 1.0f / (1.0f + lambda_g * SQUARE(level) * SQUARE(level + 1.0f));
+ s[2] = 1.0f / (1.0f + lambda_b * SQUARE(level) * SQUARE(level + 1.0f));
+
+ for (int m = -1; m <= level; m++) {
+ mul_v3_v3(sh[index++], s);
+ }
+ }
}
-static float studiolight_spherical_harmonics_geomerics_eval(const float normal[3], float sh0, float sh1, float sh2, float sh3)
+static float studiolight_spherical_harmonics_geomerics_eval(
+ const float normal[3], float sh0, float sh1, float sh2, float sh3)
{
- /* Use Geomerics non-linear SH. */
- /* http://www.geomerics.com/wp-content/uploads/2015/08/CEDEC_Geomerics_ReconstructingDiffuseLighting1.pdf */
- float R0 = sh0 * M_1_PI;
+ /* Use Geomerics non-linear SH. */
+ /* http://www.geomerics.com/wp-content/uploads/2015/08/CEDEC_Geomerics_ReconstructingDiffuseLighting1.pdf */
+ float R0 = sh0 * M_1_PI;
- float R1[3] = {-sh3, sh2, -sh1};
- mul_v3_fl(R1, 0.5f * M_1_PI * 1.5f); /* 1.5f is to improve the contrast a bit. */
- float lenR1 = len_v3(R1);
- mul_v3_fl(R1, 1.0f / lenR1);
- float q = 0.5f * (1.0f + dot_v3v3(R1, normal));
+ float R1[3] = {-sh3, sh2, -sh1};
+ mul_v3_fl(R1, 0.5f * M_1_PI * 1.5f); /* 1.5f is to improve the contrast a bit. */
+ float lenR1 = len_v3(R1);
+ mul_v3_fl(R1, 1.0f / lenR1);
+ float q = 0.5f * (1.0f + dot_v3v3(R1, normal));
- float p = 1.0f + 2.0f * lenR1 / R0;
- float a = (1.0f - lenR1 / R0) / (1.0f + lenR1 / R0);
+ float p = 1.0f + 2.0f * lenR1 / R0;
+ float a = (1.0f - lenR1 / R0) / (1.0f + lenR1 / R0);
- return R0 * (a + (1.0f - a) * (p + 1.0f) * powf(q, p));
+ return R0 * (a + (1.0f - a) * (p + 1.0f) * powf(q, p));
}
-BLI_INLINE void studiolight_spherical_harmonics_eval(StudioLight *sl, float color[3], const float normal[3])
+BLI_INLINE void studiolight_spherical_harmonics_eval(StudioLight *sl,
+ float color[3],
+ const float normal[3])
{
#if STUDIOLIGHT_SH_BANDS == 2
- float (*sh)[3] = (float (*)[3])sl->spherical_harmonics_coefs;
- for (int i = 0; i < 3; ++i) {
- color[i] = studiolight_spherical_harmonics_geomerics_eval(normal, sh[0][i], sh[1][i], sh[2][i], sh[3][i]);
- }
- return;
+ float(*sh)[3] = (float(*)[3])sl->spherical_harmonics_coefs;
+ for (int i = 0; i < 3; ++i) {
+ color[i] = studiolight_spherical_harmonics_geomerics_eval(
+ normal, sh[0][i], sh[1][i], sh[2][i], sh[3][i]);
+ }
+ return;
#else
- /* L0 */
- mul_v3_v3fl(color, sl->spherical_harmonics_coefs[0], 0.282095f);
+ /* L0 */
+ mul_v3_v3fl(color, sl->spherical_harmonics_coefs[0], 0.282095f);
# if STUDIOLIGHT_SH_BANDS > 1 /* L1 */
- const float nx = normal[0];
- const float ny = normal[1];
- const float nz = normal[2];
- madd_v3_v3fl(color, sl->spherical_harmonics_coefs[1], -0.488603f * nz);
- madd_v3_v3fl(color, sl->spherical_harmonics_coefs[2], 0.488603f * ny);
- madd_v3_v3fl(color, sl->spherical_harmonics_coefs[3], -0.488603f * nx);
+ const float nx = normal[0];
+ const float ny = normal[1];
+ const float nz = normal[2];
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[1], -0.488603f * nz);
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[2], 0.488603f * ny);
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[3], -0.488603f * nx);
# endif
# if STUDIOLIGHT_SH_BANDS > 2 /* L2 */
- const float nx2 = SQUARE(nx);
- const float ny2 = SQUARE(ny);
- const float nz2 = SQUARE(nz);
- madd_v3_v3fl(color, sl->spherical_harmonics_coefs[4], 1.092548f * nx * nz);
- madd_v3_v3fl(color, sl->spherical_harmonics_coefs[5], -1.092548f * nz * ny);
- madd_v3_v3fl(color, sl->spherical_harmonics_coefs[6], 0.315392f * (3.0f * ny2 - 1.0f));
- madd_v3_v3fl(color, sl->spherical_harmonics_coefs[7], -1.092548 * nx * ny);
- madd_v3_v3fl(color, sl->spherical_harmonics_coefs[8], 0.546274 * (nx2 - nz2));
+ const float nx2 = SQUARE(nx);
+ const float ny2 = SQUARE(ny);
+ const float nz2 = SQUARE(nz);
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[4], 1.092548f * nx * nz);
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[5], -1.092548f * nz * ny);
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[6], 0.315392f * (3.0f * ny2 - 1.0f));
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[7], -1.092548 * nx * ny);
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[8], 0.546274 * (nx2 - nz2));
# endif
- /* L3 coefs are 0 */
+ /* L3 coefs are 0 */
# if STUDIOLIGHT_SH_BANDS > 4 /* L4 */
- const float nx4 = SQUARE(nx2);
- const float ny4 = SQUARE(ny2);
- const float nz4 = SQUARE(nz2);
- madd_v3_v3fl(color, sl->spherical_harmonics_coefs[9], 2.5033429417967046f * nx * nz * (nx2 - nz2));
- madd_v3_v3fl(color, sl->spherical_harmonics_coefs[10], -1.7701307697799304f * nz * ny * (3.0f * nx2 - nz2));
- madd_v3_v3fl(color, sl->spherical_harmonics_coefs[11], 0.9461746957575601f * nz * nx * (-1.0f + 7.0f * ny2));
- madd_v3_v3fl(color, sl->spherical_harmonics_coefs[12], -0.6690465435572892f * nz * ny * (-3.0f + 7.0f * ny2));
- madd_v3_v3fl(color, sl->spherical_harmonics_coefs[13], (105.0f * ny4 - 90.0f * ny2 + 9.0f) / 28.359261614f);
- madd_v3_v3fl(color, sl->spherical_harmonics_coefs[14], -0.6690465435572892f * nx * ny * (-3.0f + 7.0f * ny2));
- madd_v3_v3fl(color, sl->spherical_harmonics_coefs[15], 0.9461746957575601f * (nx2 - nz2) * (-1.0f + 7.0f * ny2));
- madd_v3_v3fl(color, sl->spherical_harmonics_coefs[16], -1.7701307697799304f * nx * ny * (nx2 - 3.0f * nz2));
- madd_v3_v3fl(color, sl->spherical_harmonics_coefs[17], 0.6258357354491761f * (nx4 - 6.0f * nz2 * nx2 + nz4));
+ const float nx4 = SQUARE(nx2);
+ const float ny4 = SQUARE(ny2);
+ const float nz4 = SQUARE(nz2);
+ madd_v3_v3fl(
+ color, sl->spherical_harmonics_coefs[9], 2.5033429417967046f * nx * nz * (nx2 - nz2));
+ madd_v3_v3fl(color,
+ sl->spherical_harmonics_coefs[10],
+ -1.7701307697799304f * nz * ny * (3.0f * nx2 - nz2));
+ madd_v3_v3fl(color,
+ sl->spherical_harmonics_coefs[11],
+ 0.9461746957575601f * nz * nx * (-1.0f + 7.0f * ny2));
+ madd_v3_v3fl(color,
+ sl->spherical_harmonics_coefs[12],
+ -0.6690465435572892f * nz * ny * (-3.0f + 7.0f * ny2));
+ madd_v3_v3fl(color,
+ sl->spherical_harmonics_coefs[13],
+ (105.0f * ny4 - 90.0f * ny2 + 9.0f) / 28.359261614f);
+ madd_v3_v3fl(color,
+ sl->spherical_harmonics_coefs[14],
+ -0.6690465435572892f * nx * ny * (-3.0f + 7.0f * ny2));
+ madd_v3_v3fl(color,
+ sl->spherical_harmonics_coefs[15],
+ 0.9461746957575601f * (nx2 - nz2) * (-1.0f + 7.0f * ny2));
+ madd_v3_v3fl(color,
+ sl->spherical_harmonics_coefs[16],
+ -1.7701307697799304f * nx * ny * (nx2 - 3.0f * nz2));
+ madd_v3_v3fl(color,
+ sl->spherical_harmonics_coefs[17],
+ 0.6258357354491761f * (nx4 - 6.0f * nz2 * nx2 + nz4));
# endif
#endif
}
@@ -717,339 +766,358 @@ BLI_INLINE void studiolight_spherical_harmonics_eval(StudioLight *sl, float colo
/* This modify the radiance into irradiance. */
static void studiolight_spherical_harmonics_apply_band_factors(StudioLight *sl, float (*sh)[3])
{
- static float sl_sh_band_factors[5] = {
- 1.0f,
- 2.0f / 3.0f,
- 1.0f / 4.0f,
- 0.0f,
- -1.0f / 24.0f,
- };
-
- int index = 0, dst_idx = 0;
- for (int band = 0; band < STUDIOLIGHT_SH_BANDS; band++) {
- for (int m = 0; m < SQUARE(band + 1) - SQUARE(band); m++) {
- /* Skip L3 */
- if (band != 3) {
- mul_v3_v3fl(sl->spherical_harmonics_coefs[dst_idx++], sh[index], sl_sh_band_factors[band]);
- }
- index++;
- }
- }
+ static float sl_sh_band_factors[5] = {
+ 1.0f,
+ 2.0f / 3.0f,
+ 1.0f / 4.0f,
+ 0.0f,
+ -1.0f / 24.0f,
+ };
+
+ int index = 0, dst_idx = 0;
+ for (int band = 0; band < STUDIOLIGHT_SH_BANDS; band++) {
+ for (int m = 0; m < SQUARE(band + 1) - SQUARE(band); m++) {
+ /* Skip L3 */
+ if (band != 3) {
+ mul_v3_v3fl(sl->spherical_harmonics_coefs[dst_idx++], sh[index], sl_sh_band_factors[band]);
+ }
+ index++;
+ }
+ }
}
static void studiolight_calculate_diffuse_light(StudioLight *sl)
{
- /* init light to black */
- if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
- BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED);
-
- float sh_coefs[STUDIOLIGHT_SH_COEFS_LEN][3];
- studiolight_spherical_harmonics_calculate_coefficients(sl, sh_coefs);
- studiolight_spherical_harmonics_apply_windowing(sh_coefs, STUDIOLIGHT_SH_WINDOWING);
- studiolight_spherical_harmonics_apply_band_factors(sl, sh_coefs);
-
- if (sl->flag & STUDIOLIGHT_USER_DEFINED) {
- FILE *fp = BLI_fopen(sl->path_sh_cache, "wb");
- if (fp) {
- fwrite(sl->spherical_harmonics_coefs, sizeof(sl->spherical_harmonics_coefs), 1, fp);
- fclose(fp);
- }
- }
- }
- sl->flag |= STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED;
+ /* init light to black */
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED);
+
+ float sh_coefs[STUDIOLIGHT_SH_COEFS_LEN][3];
+ studiolight_spherical_harmonics_calculate_coefficients(sl, sh_coefs);
+ studiolight_spherical_harmonics_apply_windowing(sh_coefs, STUDIOLIGHT_SH_WINDOWING);
+ studiolight_spherical_harmonics_apply_band_factors(sl, sh_coefs);
+
+ if (sl->flag & STUDIOLIGHT_USER_DEFINED) {
+ FILE *fp = BLI_fopen(sl->path_sh_cache, "wb");
+ if (fp) {
+ fwrite(sl->spherical_harmonics_coefs, sizeof(sl->spherical_harmonics_coefs), 1, fp);
+ fclose(fp);
+ }
+ }
+ }
+ sl->flag |= STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED;
}
-BLI_INLINE void studiolight_evaluate_specular_radiance_buffer(
- ImBuf *radiance_buffer, const float normal[3], float color[3],
- int xoffset, int yoffset, int zoffset, float zsign)
+BLI_INLINE void studiolight_evaluate_specular_radiance_buffer(ImBuf *radiance_buffer,
+ const float normal[3],
+ float color[3],
+ int xoffset,
+ int yoffset,
+ int zoffset,
+ float zsign)
{
- if (radiance_buffer == NULL) {
- return;
- }
-
- float accum[3] = {0.0f, 0.0f, 0.0f};
- float accum_weight = 0.00001f;
- ITER_PIXELS(float, radiance_buffer->rect_float, 4,
- STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE,
- STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE)
- {
- float direction[3];
- direction[zoffset] = zsign * 0.5f;
- direction[xoffset] = x - 0.5f;
- direction[yoffset] = y - 0.5f;
- normalize_v3(direction);
- float weight = dot_v3v3(direction, normal) > 0.95f ? 1.0f : 0.0f;
- // float solid_angle = texel_solid_angle(x, y, texel_size[0] * 0.5f);
- madd_v3_v3fl(accum, pixel, weight);
- accum_weight += weight;
- }
- ITER_PIXELS_END;
-
- madd_v3_v3fl(color, accum, 1.0f / accum_weight);
+ if (radiance_buffer == NULL) {
+ return;
+ }
+
+ float accum[3] = {0.0f, 0.0f, 0.0f};
+ float accum_weight = 0.00001f;
+ ITER_PIXELS(float,
+ radiance_buffer->rect_float,
+ 4,
+ STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE,
+ STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE)
+ {
+ float direction[3];
+ direction[zoffset] = zsign * 0.5f;
+ direction[xoffset] = x - 0.5f;
+ direction[yoffset] = y - 0.5f;
+ normalize_v3(direction);
+ float weight = dot_v3v3(direction, normal) > 0.95f ? 1.0f : 0.0f;
+ // float solid_angle = texel_solid_angle(x, y, texel_size[0] * 0.5f);
+ madd_v3_v3fl(accum, pixel, weight);
+ accum_weight += weight;
+ }
+ ITER_PIXELS_END;
+
+ madd_v3_v3fl(color, accum, 1.0f / accum_weight);
}
#ifdef STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE
static void studiolight_irradiance_eval(StudioLight *sl, float color[3], const float normal[3])
{
- copy_v3_fl(color, 0.0f);
-
- /* XXX: This is madness, iterating over all cubemap pixels for each destination pixels
- * even if their weight is 0.0f.
- * It should use hemisphere, cosine sampling at least. */
-
- /* back */
- studiolight_evaluate_specular_radiance_buffer(
- sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_POS], normal, color, 0, 2, 1, 1);
- /* front */
- studiolight_evaluate_specular_radiance_buffer(
- sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_NEG], normal, color, 0, 2, 1, -1);
-
- /* left */
- studiolight_evaluate_specular_radiance_buffer(
- sl->radiance_cubemap_buffers[STUDIOLIGHT_X_POS], normal, color, 1, 2, 0, 1);
- /* right */
- studiolight_evaluate_specular_radiance_buffer(
- sl->radiance_cubemap_buffers[STUDIOLIGHT_X_NEG], normal, color, 1, 2, 0, -1);
-
- /* top */
- studiolight_evaluate_specular_radiance_buffer(
- sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_POS], normal, color, 0, 1, 2, 1);
- /* bottom */
- studiolight_evaluate_specular_radiance_buffer(
- sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_NEG], normal, color, 0, 1, 2, -1);
-
- mul_v3_fl(color, 1.0 / M_PI);
+ copy_v3_fl(color, 0.0f);
+
+ /* XXX: This is madness, iterating over all cubemap pixels for each destination pixels
+ * even if their weight is 0.0f.
+ * It should use hemisphere, cosine sampling at least. */
+
+ /* back */
+ studiolight_evaluate_specular_radiance_buffer(
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_POS], normal, color, 0, 2, 1, 1);
+ /* front */
+ studiolight_evaluate_specular_radiance_buffer(
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_NEG], normal, color, 0, 2, 1, -1);
+
+ /* left */
+ studiolight_evaluate_specular_radiance_buffer(
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_X_POS], normal, color, 1, 2, 0, 1);
+ /* right */
+ studiolight_evaluate_specular_radiance_buffer(
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_X_NEG], normal, color, 1, 2, 0, -1);
+
+ /* top */
+ studiolight_evaluate_specular_radiance_buffer(
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_POS], normal, color, 0, 1, 2, 1);
+ /* bottom */
+ studiolight_evaluate_specular_radiance_buffer(
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_NEG], normal, color, 0, 1, 2, -1);
+
+ mul_v3_fl(color, 1.0 / M_PI);
}
#endif
static float brdf_approx(float spec_color, float roughness, float NV)
{
- /* Very rough own approx. We don't need it to be correct, just fast.
- * Just simulate fresnel effect with roughness attenuation. */
- float fresnel = exp2(-8.35f * NV) * (1.0f - roughness);
- return spec_color * (1.0f - fresnel) + fresnel;
+ /* Very rough own approx. We don't need it to be correct, just fast.
+ * Just simulate fresnel effect with roughness attenuation. */
+ float fresnel = exp2(-8.35f * NV) * (1.0f - roughness);
+ return spec_color * (1.0f - fresnel) + fresnel;
}
/* NL need to be unclamped. w in [0..1] range. */
static float wrapped_lighting(float NL, float w)
{
- float w_1 = w + 1.0f;
- return max_ff((NL + w) / (w_1 * w_1), 0.0f);
+ float w_1 = w + 1.0f;
+ return max_ff((NL + w) / (w_1 * w_1), 0.0f);
}
-static float blinn_specular(
- const float L[3], const float I[3], const float N[3], float R[3], float NL, float roughness, float wrap)
+static float blinn_specular(const float L[3],
+ const float I[3],
+ const float N[3],
+ float R[3],
+ float NL,
+ float roughness,
+ float wrap)
{
- float half_dir[3];
- float wrapped_NL = dot_v3v3(L, R);
- add_v3_v3v3(half_dir, L, I);
- normalize_v3(half_dir);
- float spec_angle = max_ff(dot_v3v3(half_dir, N), 0.0f);
+ float half_dir[3];
+ float wrapped_NL = dot_v3v3(L, R);
+ add_v3_v3v3(half_dir, L, I);
+ normalize_v3(half_dir);
+ float spec_angle = max_ff(dot_v3v3(half_dir, N), 0.0f);
- float gloss = 1.0f - roughness;
- /* Reduce gloss for smooth light. (simulate bigger light) */
- gloss *= 1.0f - wrap;
- float shininess = exp2(10.0f * gloss + 1.0f);
+ float gloss = 1.0f - roughness;
+ /* Reduce gloss for smooth light. (simulate bigger light) */
+ gloss *= 1.0f - wrap;
+ float shininess = exp2(10.0f * gloss + 1.0f);
- /* Pi is already divided in the light power.
- * normalization_factor = (shininess + 8.0) / (8.0 * M_PI) */
- float normalization_factor = shininess * 0.125f + 1.0f;
- float spec_light = powf(spec_angle, shininess) * max_ff(NL, 0.0f) * normalization_factor;
+ /* Pi is already divided in the light power.
+ * normalization_factor = (shininess + 8.0) / (8.0 * M_PI) */
+ float normalization_factor = shininess * 0.125f + 1.0f;
+ float spec_light = powf(spec_angle, shininess) * max_ff(NL, 0.0f) * normalization_factor;
- /* Simulate Env. light. */
- float w = wrap * (1.0 - roughness) + roughness;
- float spec_env = wrapped_lighting(wrapped_NL, w);
+ /* Simulate Env. light. */
+ float w = wrap * (1.0 - roughness) + roughness;
+ float spec_env = wrapped_lighting(wrapped_NL, w);
- float w2 = wrap * wrap;
+ float w2 = wrap * wrap;
- return spec_light * (1.0 - w2) + spec_env * w2;
+ return spec_light * (1.0 - w2) + spec_env * w2;
}
/* Keep in sync with the glsl shader function get_world_lighting() */
static void studiolight_lights_eval(StudioLight *sl, float color[3], const float normal[3])
{
- float R[3], I[3] = {0.0f, 0.0f, 1.0f}, N[3] = {normal[0], normal[2], -normal[1]};
- const float roughness = 0.5f;
- const float diffuse_color = 0.8f;
- const float specular_color = brdf_approx(0.05f, roughness, N[2]);
- float diff_light[3], spec_light[3];
-
- /* Ambient lighting */
- copy_v3_v3(diff_light, sl->light_ambient);
- copy_v3_v3(spec_light, sl->light_ambient);
-
- reflect_v3_v3v3(R, I, N);
- for (int i = 0; i < 3; ++i) {
- SolidLight *light = &sl->light[i];
- if (light->flag) {
- /* Diffuse lighting */
- float NL = dot_v3v3(light->vec, N);
- float diff = wrapped_lighting(NL, light->smooth);
- madd_v3_v3fl(diff_light, light->col, diff);
- /* Specular lighting */
- float spec = blinn_specular(light->vec, I, N, R, NL, roughness, light->smooth);
- madd_v3_v3fl(spec_light, light->spec, spec);
- }
- }
-
- /* Multiply result by surface colors. */
- mul_v3_fl(diff_light, diffuse_color * (1.0 - specular_color));
- mul_v3_fl(spec_light, specular_color);
-
- add_v3_v3v3(color, diff_light, spec_light);
+ float R[3], I[3] = {0.0f, 0.0f, 1.0f}, N[3] = {normal[0], normal[2], -normal[1]};
+ const float roughness = 0.5f;
+ const float diffuse_color = 0.8f;
+ const float specular_color = brdf_approx(0.05f, roughness, N[2]);
+ float diff_light[3], spec_light[3];
+
+ /* Ambient lighting */
+ copy_v3_v3(diff_light, sl->light_ambient);
+ copy_v3_v3(spec_light, sl->light_ambient);
+
+ reflect_v3_v3v3(R, I, N);
+ for (int i = 0; i < 3; ++i) {
+ SolidLight *light = &sl->light[i];
+ if (light->flag) {
+ /* Diffuse lighting */
+ float NL = dot_v3v3(light->vec, N);
+ float diff = wrapped_lighting(NL, light->smooth);
+ madd_v3_v3fl(diff_light, light->col, diff);
+ /* Specular lighting */
+ float spec = blinn_specular(light->vec, I, N, R, NL, roughness, light->smooth);
+ madd_v3_v3fl(spec_light, light->spec, spec);
+ }
+ }
+
+ /* Multiply result by surface colors. */
+ mul_v3_fl(diff_light, diffuse_color * (1.0 - specular_color));
+ mul_v3_fl(spec_light, specular_color);
+
+ add_v3_v3v3(color, diff_light, spec_light);
}
static bool studiolight_load_irradiance_equirect_image(StudioLight *sl)
{
#ifdef STUDIOLIGHT_LOAD_CACHED_FILES
- if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
- ImBuf *ibuf = NULL;
- ibuf = IMB_loadiffname(sl->path_irr_cache, 0, NULL);
- if (ibuf) {
- IMB_float_from_rect(ibuf);
- sl->equirect_irradiance_buffer = ibuf;
- sl->flag |= STUDIOLIGHT_EQUIRECT_IRRADIANCE_IMAGE_CALCULATED;
- return true;
- }
- }
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ ImBuf *ibuf = NULL;
+ ibuf = IMB_loadiffname(sl->path_irr_cache, 0, NULL);
+ if (ibuf) {
+ IMB_float_from_rect(ibuf);
+ sl->equirect_irradiance_buffer = ibuf;
+ sl->flag |= STUDIOLIGHT_EQUIRECT_IRRADIANCE_IMAGE_CALCULATED;
+ return true;
+ }
+ }
#else
- UNUSED_VARS(sl);
+ UNUSED_VARS(sl);
#endif
- return false;
+ return false;
}
static bool studiolight_load_spherical_harmonics_coefficients(StudioLight *sl)
{
#ifdef STUDIOLIGHT_LOAD_CACHED_FILES
- if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
- FILE *fp = BLI_fopen(sl->path_sh_cache, "rb");
- if (fp) {
- if (fread((void *)(sl->spherical_harmonics_coefs), sizeof(sl->spherical_harmonics_coefs), 1, fp)) {
- sl->flag |= STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED;
- fclose(fp);
- return true;
- }
- fclose(fp);
- }
- }
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ FILE *fp = BLI_fopen(sl->path_sh_cache, "rb");
+ if (fp) {
+ if (fread((void *)(sl->spherical_harmonics_coefs),
+ sizeof(sl->spherical_harmonics_coefs),
+ 1,
+ fp)) {
+ sl->flag |= STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED;
+ fclose(fp);
+ return true;
+ }
+ fclose(fp);
+ }
+ }
#else
- UNUSED_VARS(sl);
+ UNUSED_VARS(sl);
#endif
- return false;
+ return false;
}
static void studiolight_calculate_irradiance_equirect_image(StudioLight *sl)
{
- if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
#ifdef STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE
- BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED);
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED);
#else
- BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED);
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED);
#endif
- float *colbuf = MEM_mallocN(STUDIOLIGHT_IRRADIANCE_EQUIRECT_WIDTH * STUDIOLIGHT_IRRADIANCE_EQUIRECT_HEIGHT * sizeof(float[4]), __func__);
-
- ITER_PIXELS(float, colbuf, 4,
- STUDIOLIGHT_IRRADIANCE_EQUIRECT_WIDTH,
- STUDIOLIGHT_IRRADIANCE_EQUIRECT_HEIGHT)
- {
- float dir[3];
- equirect_to_direction(dir, x, y);
+ float *colbuf = MEM_mallocN(STUDIOLIGHT_IRRADIANCE_EQUIRECT_WIDTH *
+ STUDIOLIGHT_IRRADIANCE_EQUIRECT_HEIGHT * sizeof(float[4]),
+ __func__);
+
+ ITER_PIXELS(float,
+ colbuf,
+ 4,
+ STUDIOLIGHT_IRRADIANCE_EQUIRECT_WIDTH,
+ STUDIOLIGHT_IRRADIANCE_EQUIRECT_HEIGHT)
+ {
+ float dir[3];
+ equirect_to_direction(dir, x, y);
#ifdef STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE
- studiolight_irradiance_eval(sl, pixel, dir);
+ studiolight_irradiance_eval(sl, pixel, dir);
#else
- studiolight_spherical_harmonics_eval(sl, pixel, dir);
+ studiolight_spherical_harmonics_eval(sl, pixel, dir);
#endif
- pixel[3] = 1.0f;
- }
- ITER_PIXELS_END;
+ pixel[3] = 1.0f;
+ }
+ ITER_PIXELS_END;
- sl->equirect_irradiance_buffer = IMB_allocFromBuffer(
- NULL, colbuf,
- STUDIOLIGHT_IRRADIANCE_EQUIRECT_WIDTH,
- STUDIOLIGHT_IRRADIANCE_EQUIRECT_HEIGHT);
- MEM_freeN(colbuf);
+ sl->equirect_irradiance_buffer = IMB_allocFromBuffer(NULL,
+ colbuf,
+ STUDIOLIGHT_IRRADIANCE_EQUIRECT_WIDTH,
+ STUDIOLIGHT_IRRADIANCE_EQUIRECT_HEIGHT);
+ MEM_freeN(colbuf);
#ifdef STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE
- /*
- * Only store cached files when using STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE
- */
- if (sl->flag & STUDIOLIGHT_USER_DEFINED) {
- IMB_saveiff(sl->equirect_irradiance_buffer, sl->path_irr_cache, IB_rectfloat);
- }
+ /*
+ * Only store cached files when using STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE
+ */
+ if (sl->flag & STUDIOLIGHT_USER_DEFINED) {
+ IMB_saveiff(sl->equirect_irradiance_buffer, sl->path_irr_cache, IB_rectfloat);
+ }
#endif
- }
- sl->flag |= STUDIOLIGHT_EQUIRECT_IRRADIANCE_IMAGE_CALCULATED;
+ }
+ sl->flag |= STUDIOLIGHT_EQUIRECT_IRRADIANCE_IMAGE_CALCULATED;
}
static StudioLight *studiolight_add_file(const char *path, int flag)
{
- char filename[FILE_MAXFILE];
- BLI_split_file_part(path, filename, FILE_MAXFILE);
-
- if ((((flag & STUDIOLIGHT_TYPE_STUDIO) != 0) && BLI_path_extension_check(filename, ".sl")) ||
- BLI_path_extension_check_array(filename, imb_ext_image))
- {
- StudioLight *sl = studiolight_create(STUDIOLIGHT_EXTERNAL_FILE | flag);
- BLI_strncpy(sl->name, filename, FILE_MAXFILE);
- BLI_strncpy(sl->path, path, FILE_MAXFILE);
-
- if ((flag & STUDIOLIGHT_TYPE_STUDIO) != 0) {
- studiolight_load_solid_light(sl);
- }
- else {
- sl->path_irr_cache = BLI_string_joinN(path, ".irr");
- sl->path_sh_cache = BLI_string_joinN(path, ".sh2");
- }
- BLI_addtail(&studiolights, sl);
- return sl;
- }
- return NULL;
+ char filename[FILE_MAXFILE];
+ BLI_split_file_part(path, filename, FILE_MAXFILE);
+
+ if ((((flag & STUDIOLIGHT_TYPE_STUDIO) != 0) && BLI_path_extension_check(filename, ".sl")) ||
+ BLI_path_extension_check_array(filename, imb_ext_image)) {
+ StudioLight *sl = studiolight_create(STUDIOLIGHT_EXTERNAL_FILE | flag);
+ BLI_strncpy(sl->name, filename, FILE_MAXFILE);
+ BLI_strncpy(sl->path, path, FILE_MAXFILE);
+
+ if ((flag & STUDIOLIGHT_TYPE_STUDIO) != 0) {
+ studiolight_load_solid_light(sl);
+ }
+ else {
+ sl->path_irr_cache = BLI_string_joinN(path, ".irr");
+ sl->path_sh_cache = BLI_string_joinN(path, ".sh2");
+ }
+ BLI_addtail(&studiolights, sl);
+ return sl;
+ }
+ return NULL;
}
-static void studiolight_add_files_from_datafolder(const int folder_id, const char *subfolder, int flag)
+static void studiolight_add_files_from_datafolder(const int folder_id,
+ const char *subfolder,
+ int flag)
{
- struct direntry *dir;
- const char *folder = BKE_appdir_folder_id(folder_id, subfolder);
- if (folder) {
- uint totfile = BLI_filelist_dir_contents(folder, &dir);
- int i;
- for (i = 0; i < totfile; i++) {
- if ((dir[i].type & S_IFREG)) {
- studiolight_add_file(dir[i].path, flag);
- }
- }
- BLI_filelist_free(dir, totfile);
- dir = NULL;
- }
+ struct direntry *dir;
+ const char *folder = BKE_appdir_folder_id(folder_id, subfolder);
+ if (folder) {
+ uint totfile = BLI_filelist_dir_contents(folder, &dir);
+ int i;
+ for (i = 0; i < totfile; i++) {
+ if ((dir[i].type & S_IFREG)) {
+ studiolight_add_file(dir[i].path, flag);
+ }
+ }
+ BLI_filelist_free(dir, totfile);
+ dir = NULL;
+ }
}
static int studiolight_flag_cmp_order(const StudioLight *sl)
{
- /* Internal studiolights before external studio lights */
- if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
- return 1;
- }
- return 0;
+ /* Internal studiolights before external studio lights */
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ return 1;
+ }
+ return 0;
}
static int studiolight_cmp(const void *a, const void *b)
{
- const StudioLight *sl1 = a;
- const StudioLight *sl2 = b;
-
- const int flagorder1 = studiolight_flag_cmp_order(sl1);
- const int flagorder2 = studiolight_flag_cmp_order(sl2);
-
- if (flagorder1 < flagorder2) {
- return -1;
- }
- else if (flagorder1 > flagorder2) {
- return 1;
- }
- else {
- return BLI_strcasecmp(sl1->name, sl2->name);
- }
+ const StudioLight *sl1 = a;
+ const StudioLight *sl2 = b;
+
+ const int flagorder1 = studiolight_flag_cmp_order(sl1);
+ const int flagorder2 = studiolight_flag_cmp_order(sl2);
+
+ if (flagorder1 < flagorder2) {
+ return -1;
+ }
+ else if (flagorder1 > flagorder2) {
+ return 1;
+ }
+ else {
+ return BLI_strcasecmp(sl1->name, sl2->name);
+ }
}
/* icons */
@@ -1059,12 +1127,12 @@ static int studiolight_cmp(const void *a, const void *b)
* in uv space for the alpha mask falloff. */
static uint alpha_circle_mask(float u, float v, float inner_edge, float outer_edge)
{
- /* Coords from center. */
- float co[2] = {u - 0.5f, v - 0.5f};
- float dist = len_v2(co);
- float alpha = 1.0f + (inner_edge - dist) / (outer_edge - inner_edge);
- uint mask = (uint)floorf(255.0f * min_ff(max_ff(alpha, 0.0f), 1.0f));
- return mask << 24;
+ /* Coords from center. */
+ float co[2] = {u - 0.5f, v - 0.5f};
+ float dist = len_v2(co);
+ float alpha = 1.0f + (inner_edge - dist) / (outer_edge - inner_edge);
+ uint mask = (uint)floorf(255.0f * min_ff(max_ff(alpha, 0.0f), 1.0f));
+ return mask << 24;
}
/* Percentage of the icon that the preview sphere covers. */
@@ -1075,287 +1143,281 @@ static uint alpha_circle_mask(float u, float v, float inner_edge, float outer_ed
/* Remaps normalized UV [0..1] to a sphere normal around (0.5, 0.5) */
static void sphere_normal_from_uv(float normal[3], float u, float v)
{
- normal[0] = u * 2.0f - 1.0f;
- normal[1] = v * 2.0f - 1.0f;
- float dist = len_v2(normal);
- normal[2] = sqrtf(1.0f - SQUARE(dist));
+ normal[0] = u * 2.0f - 1.0f;
+ normal[1] = v * 2.0f - 1.0f;
+ float dist = len_v2(normal);
+ normal[2] = sqrtf(1.0f - SQUARE(dist));
}
static void studiolight_radiance_preview(uint *icon_buffer, StudioLight *sl)
{
- BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
-
- ITER_PIXELS(uint, icon_buffer, 1,
- STUDIOLIGHT_ICON_SIZE,
- STUDIOLIGHT_ICON_SIZE)
- {
- float dy = RESCALE_COORD(y);
- float dx = RESCALE_COORD(x);
-
- uint alphamask = alpha_circle_mask(dx, dy, 0.5f - texel_size[0], 0.5f);
- if (alphamask != 0) {
- float normal[3], direction[3], color[4];
- float incoming[3] = {0.0f, 0.0f, -1.0f};
- sphere_normal_from_uv(normal, dx, dy);
- reflect_v3_v3v3(direction, incoming, normal);
- /* We want to see horizon not poles. */
- SWAP(float, direction[1], direction[2]);
- direction[1] = -direction[1];
-
- studiolight_calculate_radiance(sl->equirect_radiance_buffer, color, direction);
-
- *pixel = rgb_to_cpack(
- linearrgb_to_srgb(color[0]),
- linearrgb_to_srgb(color[1]),
- linearrgb_to_srgb(color[2])) | alphamask;
- }
- else {
- *pixel = 0x0;
- }
- }
- ITER_PIXELS_END;
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
+
+ ITER_PIXELS(uint, icon_buffer, 1, STUDIOLIGHT_ICON_SIZE, STUDIOLIGHT_ICON_SIZE)
+ {
+ float dy = RESCALE_COORD(y);
+ float dx = RESCALE_COORD(x);
+
+ uint alphamask = alpha_circle_mask(dx, dy, 0.5f - texel_size[0], 0.5f);
+ if (alphamask != 0) {
+ float normal[3], direction[3], color[4];
+ float incoming[3] = {0.0f, 0.0f, -1.0f};
+ sphere_normal_from_uv(normal, dx, dy);
+ reflect_v3_v3v3(direction, incoming, normal);
+ /* We want to see horizon not poles. */
+ SWAP(float, direction[1], direction[2]);
+ direction[1] = -direction[1];
+
+ studiolight_calculate_radiance(sl->equirect_radiance_buffer, color, direction);
+
+ *pixel = rgb_to_cpack(linearrgb_to_srgb(color[0]),
+ linearrgb_to_srgb(color[1]),
+ linearrgb_to_srgb(color[2])) |
+ alphamask;
+ }
+ else {
+ *pixel = 0x0;
+ }
+ }
+ ITER_PIXELS_END;
}
static void studiolight_matcap_preview(uint *icon_buffer, StudioLight *sl, bool flipped)
{
- BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
-
- ImBuf *ibuf = sl->equirect_radiance_buffer;
-
- ITER_PIXELS(uint, icon_buffer, 1,
- STUDIOLIGHT_ICON_SIZE,
- STUDIOLIGHT_ICON_SIZE)
- {
- float dy = RESCALE_COORD(y);
- float dx = RESCALE_COORD(x);
- if (flipped) {
- dx = 1.0f - dx;
- }
-
- float color[4];
- nearest_interpolation_color(ibuf, NULL, color, dx * ibuf->x - 1.0f, dy * ibuf->y - 1.0f);
-
- uint alphamask = alpha_circle_mask(dx, dy, 0.5f - texel_size[0], 0.5f);
-
- *pixel = rgb_to_cpack(
- linearrgb_to_srgb(color[0]),
- linearrgb_to_srgb(color[1]),
- linearrgb_to_srgb(color[2])) | alphamask;
- }
- ITER_PIXELS_END;
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
+
+ ImBuf *ibuf = sl->equirect_radiance_buffer;
+
+ ITER_PIXELS(uint, icon_buffer, 1, STUDIOLIGHT_ICON_SIZE, STUDIOLIGHT_ICON_SIZE)
+ {
+ float dy = RESCALE_COORD(y);
+ float dx = RESCALE_COORD(x);
+ if (flipped) {
+ dx = 1.0f - dx;
+ }
+
+ float color[4];
+ nearest_interpolation_color(ibuf, NULL, color, dx * ibuf->x - 1.0f, dy * ibuf->y - 1.0f);
+
+ uint alphamask = alpha_circle_mask(dx, dy, 0.5f - texel_size[0], 0.5f);
+
+ *pixel = rgb_to_cpack(linearrgb_to_srgb(color[0]),
+ linearrgb_to_srgb(color[1]),
+ linearrgb_to_srgb(color[2])) |
+ alphamask;
+ }
+ ITER_PIXELS_END;
}
static void studiolight_irradiance_preview(uint *icon_buffer, StudioLight *sl)
{
- ITER_PIXELS(uint, icon_buffer, 1,
- STUDIOLIGHT_ICON_SIZE,
- STUDIOLIGHT_ICON_SIZE)
- {
- float dy = RESCALE_COORD(y);
- float dx = RESCALE_COORD(x);
-
- uint alphamask = alpha_circle_mask(dx, dy, 0.5f - texel_size[0], 0.5f);
- if (alphamask != 0) {
- float normal[3], color[3];
- sphere_normal_from_uv(normal, dx, dy);
- /* We want to see horizon not poles. */
- SWAP(float, normal[1], normal[2]);
- normal[1] = -normal[1];
-
- studiolight_lights_eval(sl, color, normal);
-
- *pixel = rgb_to_cpack(
- linearrgb_to_srgb(color[0]),
- linearrgb_to_srgb(color[1]),
- linearrgb_to_srgb(color[2])) | alphamask;
- }
- else {
- *pixel = 0x0;
- }
- }
- ITER_PIXELS_END;
+ ITER_PIXELS(uint, icon_buffer, 1, STUDIOLIGHT_ICON_SIZE, STUDIOLIGHT_ICON_SIZE)
+ {
+ float dy = RESCALE_COORD(y);
+ float dx = RESCALE_COORD(x);
+
+ uint alphamask = alpha_circle_mask(dx, dy, 0.5f - texel_size[0], 0.5f);
+ if (alphamask != 0) {
+ float normal[3], color[3];
+ sphere_normal_from_uv(normal, dx, dy);
+ /* We want to see horizon not poles. */
+ SWAP(float, normal[1], normal[2]);
+ normal[1] = -normal[1];
+
+ studiolight_lights_eval(sl, color, normal);
+
+ *pixel = rgb_to_cpack(linearrgb_to_srgb(color[0]),
+ linearrgb_to_srgb(color[1]),
+ linearrgb_to_srgb(color[2])) |
+ alphamask;
+ }
+ else {
+ *pixel = 0x0;
+ }
+ }
+ ITER_PIXELS_END;
}
/* API */
void BKE_studiolight_init(void)
{
- /* Add default studio light */
- StudioLight *sl = studiolight_create(
- STUDIOLIGHT_INTERNAL | STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED | STUDIOLIGHT_TYPE_STUDIO);
- BLI_strncpy(sl->name, "Default", FILE_MAXFILE);
-
- copy_v3_fl3(sl->light_ambient, 0.025000, 0.025000, 0.025000);
-
- copy_v4_fl4(sl->light[0].vec, -0.580952, 0.228571, 0.781185, 0.0);
- copy_v4_fl4(sl->light[0].col, 0.900000, 0.900000, 0.900000, 1.000000);
- copy_v4_fl4(sl->light[0].spec, 0.318547, 0.318547, 0.318547, 1.000000);
- sl->light[0].flag = 1;
- sl->light[0].smooth = 0.1;
-
- copy_v4_fl4(sl->light[1].vec, 0.788218, 0.593482, -0.162765, 0.0);
- copy_v4_fl4(sl->light[1].col, 0.267115, 0.269928, 0.358840, 1.000000);
- copy_v4_fl4(sl->light[1].spec, 0.090838, 0.090838, 0.090838, 1.000000);
- sl->light[1].flag = 1;
- sl->light[1].smooth = 0.25;
-
- copy_v4_fl4(sl->light[2].vec, 0.696472, -0.696472, -0.172785, 0.0);
- copy_v4_fl4(sl->light[2].col, 0.293216, 0.304662, 0.401968, 1.000000);
- copy_v4_fl4(sl->light[2].spec, 0.069399, 0.020331, 0.020331, 1.000000);
- sl->light[2].flag = 1;
- sl->light[2].smooth = 0.5;
-
- copy_v4_fl4(sl->light[3].vec, 0.021053, -0.989474, 0.143173, 0.0);
- copy_v4_fl4(sl->light[3].col, 0.0, 0.0, 0.0, 1.0);
- copy_v4_fl4(sl->light[3].spec, 0.072234, 0.082253, 0.162642, 1.000000);
- sl->light[3].flag = 1;
- sl->light[3].smooth = 0.7;
-
- BLI_addtail(&studiolights, sl);
-
- /* go over the preset folder and add a studiolight for every image with its path */
- /* for portable installs (where USER and SYSTEM paths are the same), only go over LOCAL datafiles once */
- /* Also reserve icon space for it. */
- if (!BKE_appdir_app_is_portable_install()) {
- studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES,
- STUDIOLIGHT_LIGHTS_FOLDER,
- STUDIOLIGHT_TYPE_STUDIO | STUDIOLIGHT_USER_DEFINED);
- studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES,
- STUDIOLIGHT_WORLD_FOLDER,
- STUDIOLIGHT_TYPE_WORLD | STUDIOLIGHT_USER_DEFINED);
- studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES,
- STUDIOLIGHT_MATCAP_FOLDER,
- STUDIOLIGHT_TYPE_MATCAP | STUDIOLIGHT_USER_DEFINED);
- }
- studiolight_add_files_from_datafolder(BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_LIGHTS_FOLDER, STUDIOLIGHT_TYPE_STUDIO);
- studiolight_add_files_from_datafolder(BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_WORLD_FOLDER, STUDIOLIGHT_TYPE_WORLD);
- studiolight_add_files_from_datafolder(BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_MATCAP_FOLDER, STUDIOLIGHT_TYPE_MATCAP);
-
- /* sort studio lights on filename. */
- BLI_listbase_sort(&studiolights, studiolight_cmp);
+ /* Add default studio light */
+ StudioLight *sl = studiolight_create(STUDIOLIGHT_INTERNAL |
+ STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED |
+ STUDIOLIGHT_TYPE_STUDIO);
+ BLI_strncpy(sl->name, "Default", FILE_MAXFILE);
+
+ copy_v3_fl3(sl->light_ambient, 0.025000, 0.025000, 0.025000);
+
+ copy_v4_fl4(sl->light[0].vec, -0.580952, 0.228571, 0.781185, 0.0);
+ copy_v4_fl4(sl->light[0].col, 0.900000, 0.900000, 0.900000, 1.000000);
+ copy_v4_fl4(sl->light[0].spec, 0.318547, 0.318547, 0.318547, 1.000000);
+ sl->light[0].flag = 1;
+ sl->light[0].smooth = 0.1;
+
+ copy_v4_fl4(sl->light[1].vec, 0.788218, 0.593482, -0.162765, 0.0);
+ copy_v4_fl4(sl->light[1].col, 0.267115, 0.269928, 0.358840, 1.000000);
+ copy_v4_fl4(sl->light[1].spec, 0.090838, 0.090838, 0.090838, 1.000000);
+ sl->light[1].flag = 1;
+ sl->light[1].smooth = 0.25;
+
+ copy_v4_fl4(sl->light[2].vec, 0.696472, -0.696472, -0.172785, 0.0);
+ copy_v4_fl4(sl->light[2].col, 0.293216, 0.304662, 0.401968, 1.000000);
+ copy_v4_fl4(sl->light[2].spec, 0.069399, 0.020331, 0.020331, 1.000000);
+ sl->light[2].flag = 1;
+ sl->light[2].smooth = 0.5;
+
+ copy_v4_fl4(sl->light[3].vec, 0.021053, -0.989474, 0.143173, 0.0);
+ copy_v4_fl4(sl->light[3].col, 0.0, 0.0, 0.0, 1.0);
+ copy_v4_fl4(sl->light[3].spec, 0.072234, 0.082253, 0.162642, 1.000000);
+ sl->light[3].flag = 1;
+ sl->light[3].smooth = 0.7;
+
+ BLI_addtail(&studiolights, sl);
+
+ /* go over the preset folder and add a studiolight for every image with its path */
+ /* for portable installs (where USER and SYSTEM paths are the same), only go over LOCAL datafiles once */
+ /* Also reserve icon space for it. */
+ if (!BKE_appdir_app_is_portable_install()) {
+ studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES,
+ STUDIOLIGHT_LIGHTS_FOLDER,
+ STUDIOLIGHT_TYPE_STUDIO | STUDIOLIGHT_USER_DEFINED);
+ studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES,
+ STUDIOLIGHT_WORLD_FOLDER,
+ STUDIOLIGHT_TYPE_WORLD | STUDIOLIGHT_USER_DEFINED);
+ studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES,
+ STUDIOLIGHT_MATCAP_FOLDER,
+ STUDIOLIGHT_TYPE_MATCAP | STUDIOLIGHT_USER_DEFINED);
+ }
+ studiolight_add_files_from_datafolder(
+ BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_LIGHTS_FOLDER, STUDIOLIGHT_TYPE_STUDIO);
+ studiolight_add_files_from_datafolder(
+ BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_WORLD_FOLDER, STUDIOLIGHT_TYPE_WORLD);
+ studiolight_add_files_from_datafolder(
+ BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_MATCAP_FOLDER, STUDIOLIGHT_TYPE_MATCAP);
+
+ /* sort studio lights on filename. */
+ BLI_listbase_sort(&studiolights, studiolight_cmp);
}
void BKE_studiolight_free(void)
{
- struct StudioLight *sl;
- while ((sl = BLI_pophead(&studiolights))) {
- studiolight_free(sl);
- }
+ struct StudioLight *sl;
+ while ((sl = BLI_pophead(&studiolights))) {
+ studiolight_free(sl);
+ }
}
struct StudioLight *BKE_studiolight_find_default(int flag)
{
- const char *default_name = "";
-
- if (flag & STUDIOLIGHT_TYPE_WORLD) {
- default_name = STUDIOLIGHT_WORLD_DEFAULT;
- }
- else if (flag & STUDIOLIGHT_TYPE_MATCAP) {
- default_name = STUDIOLIGHT_MATCAP_DEFAULT;
- }
-
- LISTBASE_FOREACH(StudioLight *, sl, &studiolights) {
- if ((sl->flag & flag) && STREQ(sl->name, default_name)) {
- return sl;
- }
- }
-
- LISTBASE_FOREACH(StudioLight *, sl, &studiolights) {
- if ((sl->flag & flag)) {
- return sl;
- }
- }
- return NULL;
+ const char *default_name = "";
+
+ if (flag & STUDIOLIGHT_TYPE_WORLD) {
+ default_name = STUDIOLIGHT_WORLD_DEFAULT;
+ }
+ else if (flag & STUDIOLIGHT_TYPE_MATCAP) {
+ default_name = STUDIOLIGHT_MATCAP_DEFAULT;
+ }
+
+ LISTBASE_FOREACH (StudioLight *, sl, &studiolights) {
+ if ((sl->flag & flag) && STREQ(sl->name, default_name)) {
+ return sl;
+ }
+ }
+
+ LISTBASE_FOREACH (StudioLight *, sl, &studiolights) {
+ if ((sl->flag & flag)) {
+ return sl;
+ }
+ }
+ return NULL;
}
struct StudioLight *BKE_studiolight_find(const char *name, int flag)
{
- LISTBASE_FOREACH(StudioLight *, sl, &studiolights) {
- if (STREQLEN(sl->name, name, FILE_MAXFILE)) {
- if ((sl->flag & flag)) {
- return sl;
- }
- else {
- /* flags do not match, so use default */
- return BKE_studiolight_find_default(flag);
- }
- }
- }
- /* When not found, use the default studio light */
- return BKE_studiolight_find_default(flag);
+ LISTBASE_FOREACH (StudioLight *, sl, &studiolights) {
+ if (STREQLEN(sl->name, name, FILE_MAXFILE)) {
+ if ((sl->flag & flag)) {
+ return sl;
+ }
+ else {
+ /* flags do not match, so use default */
+ return BKE_studiolight_find_default(flag);
+ }
+ }
+ }
+ /* When not found, use the default studio light */
+ return BKE_studiolight_find_default(flag);
}
struct StudioLight *BKE_studiolight_findindex(int index, int flag)
{
- LISTBASE_FOREACH(StudioLight *, sl, &studiolights) {
- if (sl->index == index) {
- return sl;
- }
- }
- /* When not found, use the default studio light */
- return BKE_studiolight_find_default(flag);
+ LISTBASE_FOREACH (StudioLight *, sl, &studiolights) {
+ if (sl->index == index) {
+ return sl;
+ }
+ }
+ /* When not found, use the default studio light */
+ return BKE_studiolight_find_default(flag);
}
struct ListBase *BKE_studiolight_listbase(void)
{
- return &studiolights;
+ return &studiolights;
}
void BKE_studiolight_preview(uint *icon_buffer, StudioLight *sl, int icon_id_type)
{
- switch (icon_id_type) {
- case STUDIOLIGHT_ICON_ID_TYPE_RADIANCE:
- default:
- {
- studiolight_radiance_preview(icon_buffer, sl);
- break;
- }
- case STUDIOLIGHT_ICON_ID_TYPE_IRRADIANCE:
- {
- studiolight_irradiance_preview(icon_buffer, sl);
- break;
- }
- case STUDIOLIGHT_ICON_ID_TYPE_MATCAP:
- {
- studiolight_matcap_preview(icon_buffer, sl, false);
- break;
- }
- case STUDIOLIGHT_ICON_ID_TYPE_MATCAP_FLIPPED:
- {
- studiolight_matcap_preview(icon_buffer, sl, true);
- break;
- }
- }
+ switch (icon_id_type) {
+ case STUDIOLIGHT_ICON_ID_TYPE_RADIANCE:
+ default: {
+ studiolight_radiance_preview(icon_buffer, sl);
+ break;
+ }
+ case STUDIOLIGHT_ICON_ID_TYPE_IRRADIANCE: {
+ studiolight_irradiance_preview(icon_buffer, sl);
+ break;
+ }
+ case STUDIOLIGHT_ICON_ID_TYPE_MATCAP: {
+ studiolight_matcap_preview(icon_buffer, sl, false);
+ break;
+ }
+ case STUDIOLIGHT_ICON_ID_TYPE_MATCAP_FLIPPED: {
+ studiolight_matcap_preview(icon_buffer, sl, true);
+ break;
+ }
+ }
}
/* Ensure state of Studiolights */
void BKE_studiolight_ensure_flag(StudioLight *sl, int flag)
{
- if ((sl->flag & flag) == flag) {
- return;
- }
-
- if ((flag & STUDIOLIGHT_EXTERNAL_IMAGE_LOADED)) {
- studiolight_load_equirect_image(sl);
- }
- if ((flag & STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED)) {
- studiolight_calculate_radiance_cubemap_buffers(sl);
- }
- if ((flag & STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED)) {
- if (!studiolight_load_spherical_harmonics_coefficients(sl)) {
- studiolight_calculate_diffuse_light(sl);
- }
- }
- if ((flag & STUDIOLIGHT_EQUIRECT_RADIANCE_GPUTEXTURE)) {
- studiolight_create_equirect_radiance_gputexture(sl);
- }
- if ((flag & STUDIOLIGHT_EQUIRECT_IRRADIANCE_GPUTEXTURE)) {
- studiolight_create_equirect_irradiance_gputexture(sl);
- }
- if ((flag & STUDIOLIGHT_EQUIRECT_IRRADIANCE_IMAGE_CALCULATED)) {
- if (!studiolight_load_irradiance_equirect_image(sl)) {
- studiolight_calculate_irradiance_equirect_image(sl);
- }
- }
+ if ((sl->flag & flag) == flag) {
+ return;
+ }
+
+ if ((flag & STUDIOLIGHT_EXTERNAL_IMAGE_LOADED)) {
+ studiolight_load_equirect_image(sl);
+ }
+ if ((flag & STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED)) {
+ studiolight_calculate_radiance_cubemap_buffers(sl);
+ }
+ if ((flag & STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED)) {
+ if (!studiolight_load_spherical_harmonics_coefficients(sl)) {
+ studiolight_calculate_diffuse_light(sl);
+ }
+ }
+ if ((flag & STUDIOLIGHT_EQUIRECT_RADIANCE_GPUTEXTURE)) {
+ studiolight_create_equirect_radiance_gputexture(sl);
+ }
+ if ((flag & STUDIOLIGHT_EQUIRECT_IRRADIANCE_GPUTEXTURE)) {
+ studiolight_create_equirect_irradiance_gputexture(sl);
+ }
+ if ((flag & STUDIOLIGHT_EQUIRECT_IRRADIANCE_IMAGE_CALCULATED)) {
+ if (!studiolight_load_irradiance_equirect_image(sl)) {
+ studiolight_calculate_irradiance_equirect_image(sl);
+ }
+ }
}
/*
@@ -1363,73 +1425,78 @@ void BKE_studiolight_ensure_flag(StudioLight *sl, int flag)
*/
void BKE_studiolight_remove(StudioLight *sl)
{
- if (sl->flag & STUDIOLIGHT_USER_DEFINED) {
- BLI_remlink(&studiolights, sl);
- studiolight_free(sl);
- }
+ if (sl->flag & STUDIOLIGHT_USER_DEFINED) {
+ BLI_remlink(&studiolights, sl);
+ studiolight_free(sl);
+ }
}
StudioLight *BKE_studiolight_load(const char *path, int type)
{
- StudioLight *sl = studiolight_add_file(path, type | STUDIOLIGHT_USER_DEFINED);
- return sl;
+ StudioLight *sl = studiolight_add_file(path, type | STUDIOLIGHT_USER_DEFINED);
+ return sl;
}
-StudioLight *BKE_studiolight_create(const char *path, const SolidLight light[4], const float light_ambient[3])
+StudioLight *BKE_studiolight_create(const char *path,
+ const SolidLight light[4],
+ const float light_ambient[3])
{
- StudioLight *sl = studiolight_create(STUDIOLIGHT_EXTERNAL_FILE | STUDIOLIGHT_USER_DEFINED | STUDIOLIGHT_TYPE_STUDIO);
+ StudioLight *sl = studiolight_create(STUDIOLIGHT_EXTERNAL_FILE | STUDIOLIGHT_USER_DEFINED |
+ STUDIOLIGHT_TYPE_STUDIO);
- char filename[FILE_MAXFILE];
- BLI_split_file_part(path, filename, FILE_MAXFILE);
- STRNCPY(sl->path, path);
- STRNCPY(sl->name, filename);
+ char filename[FILE_MAXFILE];
+ BLI_split_file_part(path, filename, FILE_MAXFILE);
+ STRNCPY(sl->path, path);
+ STRNCPY(sl->name, filename);
- memcpy(sl->light, light, sizeof(*light) * 4);
- memcpy(sl->light_ambient, light_ambient, sizeof(*light_ambient) * 3);
+ memcpy(sl->light, light, sizeof(*light) * 4);
+ memcpy(sl->light_ambient, light_ambient, sizeof(*light_ambient) * 3);
- studiolight_write_solid_light(sl);
+ studiolight_write_solid_light(sl);
- BLI_addtail(&studiolights, sl);
- return sl;
+ BLI_addtail(&studiolights, sl);
+ return sl;
}
/* Only useful for workbench while editing the userprefs. */
StudioLight *BKE_studiolight_studio_edit_get(void)
{
- static StudioLight sl = {0};
- sl.flag = STUDIOLIGHT_TYPE_STUDIO;
+ static StudioLight sl = {0};
+ sl.flag = STUDIOLIGHT_TYPE_STUDIO;
- memcpy(sl.light, U.light_param, sizeof(*sl.light) * 4);
- memcpy(sl.light_ambient, U.light_ambient, sizeof(*sl.light_ambient) * 3);
+ memcpy(sl.light, U.light_param, sizeof(*sl.light) * 4);
+ memcpy(sl.light_ambient, U.light_ambient, sizeof(*sl.light_ambient) * 3);
- return &sl;
+ return &sl;
}
void BKE_studiolight_refresh(void)
{
- BKE_studiolight_free();
- BKE_studiolight_init();
+ BKE_studiolight_free();
+ BKE_studiolight_init();
}
-void BKE_studiolight_set_free_function(StudioLight *sl, StudioLightFreeFunction *free_function, void *data)
+void BKE_studiolight_set_free_function(StudioLight *sl,
+ StudioLightFreeFunction *free_function,
+ void *data)
{
- sl->free_function = free_function;
- sl->free_function_data = data;
+ sl->free_function = free_function;
+ sl->free_function_data = data;
}
void BKE_studiolight_unset_icon_id(StudioLight *sl, int icon_id)
{
- BLI_assert(sl != NULL);
- if (sl->icon_id_radiance == icon_id) {
- sl->icon_id_radiance = 0;
- }
- if (sl->icon_id_irradiance == icon_id) {
- sl->icon_id_irradiance = 0;
- }
- if (sl->icon_id_matcap == icon_id) {
- sl->icon_id_matcap = 0;
- }
- if (sl->icon_id_matcap_flipped == icon_id) {
- sl->icon_id_matcap_flipped = 0;
- }
+ BLI_assert(sl != NULL);
+ if (sl->icon_id_radiance == icon_id) {
+ sl->icon_id_radiance = 0;
+ }
+ if (sl->icon_id_irradiance == icon_id) {
+ sl->icon_id_irradiance = 0;
+ }
+ if (sl->icon_id_matcap == icon_id) {
+ sl->icon_id_matcap = 0;
+ }
+ if (sl->icon_id_matcap_flipped == icon_id) {
+ sl->icon_id_matcap_flipped = 0;
+ }
}
diff --git a/source/blender/blenkernel/intern/subdiv.c b/source/blender/blenkernel/intern/subdiv.c
index 48a7cb8f8d2..1f7cb225fc7 100644
--- a/source/blender/blenkernel/intern/subdiv.c
+++ b/source/blender/blenkernel/intern/subdiv.c
@@ -40,62 +40,56 @@
/* ========================== CONVERSION HELPERS ============================ */
-eSubdivFVarLinearInterpolation
-BKE_subdiv_fvar_interpolation_from_uv_smooth(int uv_smooth)
+eSubdivFVarLinearInterpolation BKE_subdiv_fvar_interpolation_from_uv_smooth(int uv_smooth)
{
- switch (uv_smooth) {
- case SUBSURF_UV_SMOOTH_NONE:
- return SUBDIV_FVAR_LINEAR_INTERPOLATION_ALL;
- case SUBSURF_UV_SMOOTH_PRESERVE_CORNERS:
- return SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY;
- case SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_AND_JUNCTIONS:
- return SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_AND_JUNCTIONS;
- case SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_JUNCTIONS_AND_CONCAVE:
- return SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_JUNCTIONS_AND_CONCAVE;
- case SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES:
- return SUBDIV_FVAR_LINEAR_INTERPOLATION_BOUNDARIES;
- case SUBSURF_UV_SMOOTH_ALL:
- return SUBDIV_FVAR_LINEAR_INTERPOLATION_NONE;
- }
- BLI_assert(!"Unknown uv smooth flag");
- return SUBDIV_FVAR_LINEAR_INTERPOLATION_ALL;
+ switch (uv_smooth) {
+ case SUBSURF_UV_SMOOTH_NONE:
+ return SUBDIV_FVAR_LINEAR_INTERPOLATION_ALL;
+ case SUBSURF_UV_SMOOTH_PRESERVE_CORNERS:
+ return SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY;
+ case SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_AND_JUNCTIONS:
+ return SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_AND_JUNCTIONS;
+ case SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_JUNCTIONS_AND_CONCAVE:
+ return SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_JUNCTIONS_AND_CONCAVE;
+ case SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES:
+ return SUBDIV_FVAR_LINEAR_INTERPOLATION_BOUNDARIES;
+ case SUBSURF_UV_SMOOTH_ALL:
+ return SUBDIV_FVAR_LINEAR_INTERPOLATION_NONE;
+ }
+ BLI_assert(!"Unknown uv smooth flag");
+ return SUBDIV_FVAR_LINEAR_INTERPOLATION_ALL;
}
/* ================================ SETTINGS ================================ */
static bool check_mesh_has_non_quad(const Mesh *mesh)
{
- for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) {
- const MPoly *poly = &mesh->mpoly[poly_index];
- if (poly->totloop != 4) {
- return true;
- }
- }
- return false;
+ for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) {
+ const MPoly *poly = &mesh->mpoly[poly_index];
+ if (poly->totloop != 4) {
+ return true;
+ }
+ }
+ return false;
}
-void BKE_subdiv_settings_validate_for_mesh(SubdivSettings *settings,
- const Mesh *mesh)
+void BKE_subdiv_settings_validate_for_mesh(SubdivSettings *settings, const Mesh *mesh)
{
- if (settings->level != 1) {
- return;
- }
- if (check_mesh_has_non_quad(mesh)) {
- settings->level = 2;
- }
+ if (settings->level != 1) {
+ return;
+ }
+ if (check_mesh_has_non_quad(mesh)) {
+ settings->level = 2;
+ }
}
-bool BKE_subdiv_settings_equal(const SubdivSettings *settings_a,
- const SubdivSettings *settings_b)
+bool BKE_subdiv_settings_equal(const SubdivSettings *settings_a, const SubdivSettings *settings_b)
{
- return
- (settings_a->is_simple == settings_b->is_simple &&
- settings_a->is_adaptive == settings_b->is_adaptive &&
- settings_a->level == settings_b->level &&
- settings_a->vtx_boundary_interpolation ==
- settings_b->vtx_boundary_interpolation &&
- settings_a->fvar_linear_interpolation ==
- settings_b->fvar_linear_interpolation);
+ return (settings_a->is_simple == settings_b->is_simple &&
+ settings_a->is_adaptive == settings_b->is_adaptive &&
+ settings_a->level == settings_b->level &&
+ settings_a->vtx_boundary_interpolation == settings_b->vtx_boundary_interpolation &&
+ settings_a->fvar_linear_interpolation == settings_b->fvar_linear_interpolation);
}
/* ============================== CONSTRUCTION ============================== */
@@ -105,44 +99,42 @@ bool BKE_subdiv_settings_equal(const SubdivSettings *settings_a,
Subdiv *BKE_subdiv_new_from_converter(const SubdivSettings *settings,
struct OpenSubdiv_Converter *converter)
{
- SubdivStats stats;
- BKE_subdiv_stats_init(&stats);
- BKE_subdiv_stats_begin(&stats, SUBDIV_STATS_TOPOLOGY_REFINER_CREATION_TIME);
- OpenSubdiv_TopologyRefinerSettings topology_refiner_settings;
- topology_refiner_settings.level = settings->level;
- topology_refiner_settings.is_adaptive = settings->is_adaptive;
- struct OpenSubdiv_TopologyRefiner *osd_topology_refiner = NULL;
- if (converter->getNumVertices(converter) != 0) {
- osd_topology_refiner =
- openSubdiv_createTopologyRefinerFromConverter(
- converter, &topology_refiner_settings);
- }
- else {
- /* TODO(sergey): Check whether original geometry had any vertices.
- * The thing here is: OpenSubdiv can only deal with faces, but our
- * side of subdiv also deals with loose vertices and edges. */
- }
- Subdiv *subdiv = MEM_callocN(sizeof(Subdiv), "subdiv from converetr");
- subdiv->settings = *settings;
- subdiv->topology_refiner = osd_topology_refiner;
- subdiv->evaluator = NULL;
- subdiv->displacement_evaluator = NULL;
- BKE_subdiv_stats_end(&stats, SUBDIV_STATS_TOPOLOGY_REFINER_CREATION_TIME);
- subdiv->stats = stats;
- return subdiv;
+ SubdivStats stats;
+ BKE_subdiv_stats_init(&stats);
+ BKE_subdiv_stats_begin(&stats, SUBDIV_STATS_TOPOLOGY_REFINER_CREATION_TIME);
+ OpenSubdiv_TopologyRefinerSettings topology_refiner_settings;
+ topology_refiner_settings.level = settings->level;
+ topology_refiner_settings.is_adaptive = settings->is_adaptive;
+ struct OpenSubdiv_TopologyRefiner *osd_topology_refiner = NULL;
+ if (converter->getNumVertices(converter) != 0) {
+ osd_topology_refiner = openSubdiv_createTopologyRefinerFromConverter(
+ converter, &topology_refiner_settings);
+ }
+ else {
+ /* TODO(sergey): Check whether original geometry had any vertices.
+ * The thing here is: OpenSubdiv can only deal with faces, but our
+ * side of subdiv also deals with loose vertices and edges. */
+ }
+ Subdiv *subdiv = MEM_callocN(sizeof(Subdiv), "subdiv from converetr");
+ subdiv->settings = *settings;
+ subdiv->topology_refiner = osd_topology_refiner;
+ subdiv->evaluator = NULL;
+ subdiv->displacement_evaluator = NULL;
+ BKE_subdiv_stats_end(&stats, SUBDIV_STATS_TOPOLOGY_REFINER_CREATION_TIME);
+ subdiv->stats = stats;
+ return subdiv;
}
-Subdiv *BKE_subdiv_new_from_mesh(const SubdivSettings *settings,
- const Mesh *mesh)
+Subdiv *BKE_subdiv_new_from_mesh(const SubdivSettings *settings, const Mesh *mesh)
{
- if (mesh->totvert == 0) {
- return NULL;
- }
- OpenSubdiv_Converter converter;
- BKE_subdiv_converter_init_for_mesh(&converter, settings, mesh);
- Subdiv *subdiv = BKE_subdiv_new_from_converter(settings, &converter);
- BKE_subdiv_converter_free(&converter);
- return subdiv;
+ if (mesh->totvert == 0) {
+ return NULL;
+ }
+ OpenSubdiv_Converter converter;
+ BKE_subdiv_converter_init_for_mesh(&converter, settings, mesh);
+ Subdiv *subdiv = BKE_subdiv_new_from_converter(settings, &converter);
+ BKE_subdiv_converter_free(&converter);
+ return subdiv;
}
/* Creation with cached-aware semantic. */
@@ -151,84 +143,79 @@ Subdiv *BKE_subdiv_update_from_converter(Subdiv *subdiv,
const SubdivSettings *settings,
OpenSubdiv_Converter *converter)
{
- /* Check if the existing descriptor can be re-used. */
- bool can_reuse_subdiv = true;
- if (subdiv != NULL && subdiv->topology_refiner != NULL) {
- if (!BKE_subdiv_settings_equal(&subdiv->settings, settings)) {
- can_reuse_subdiv = false;
- }
- else {
- BKE_subdiv_stats_begin(
- &subdiv->stats, SUBDIV_STATS_TOPOLOGY_COMPARE);
- can_reuse_subdiv = openSubdiv_topologyRefinerCompareWithConverter(
- subdiv->topology_refiner, converter);
- BKE_subdiv_stats_end(
- &subdiv->stats, SUBDIV_STATS_TOPOLOGY_COMPARE);
- }
- }
- else {
- can_reuse_subdiv = false;
- }
- if (can_reuse_subdiv) {
- return subdiv;
- }
- /* Create new subdiv. */
- if (subdiv != NULL) {
- BKE_subdiv_free(subdiv);
- }
- return BKE_subdiv_new_from_converter(settings, converter);
+ /* Check if the existing descriptor can be re-used. */
+ bool can_reuse_subdiv = true;
+ if (subdiv != NULL && subdiv->topology_refiner != NULL) {
+ if (!BKE_subdiv_settings_equal(&subdiv->settings, settings)) {
+ can_reuse_subdiv = false;
+ }
+ else {
+ BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_TOPOLOGY_COMPARE);
+ can_reuse_subdiv = openSubdiv_topologyRefinerCompareWithConverter(subdiv->topology_refiner,
+ converter);
+ BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_TOPOLOGY_COMPARE);
+ }
+ }
+ else {
+ can_reuse_subdiv = false;
+ }
+ if (can_reuse_subdiv) {
+ return subdiv;
+ }
+ /* Create new subdiv. */
+ if (subdiv != NULL) {
+ BKE_subdiv_free(subdiv);
+ }
+ return BKE_subdiv_new_from_converter(settings, converter);
}
Subdiv *BKE_subdiv_update_from_mesh(Subdiv *subdiv,
const SubdivSettings *settings,
const Mesh *mesh)
{
- OpenSubdiv_Converter converter;
- BKE_subdiv_converter_init_for_mesh(&converter, settings, mesh);
- subdiv = BKE_subdiv_update_from_converter(subdiv, settings, &converter);
- BKE_subdiv_converter_free(&converter);
- return subdiv;
+ OpenSubdiv_Converter converter;
+ BKE_subdiv_converter_init_for_mesh(&converter, settings, mesh);
+ subdiv = BKE_subdiv_update_from_converter(subdiv, settings, &converter);
+ BKE_subdiv_converter_free(&converter);
+ return subdiv;
}
/* Memory release. */
void BKE_subdiv_free(Subdiv *subdiv)
{
- if (subdiv->evaluator != NULL) {
- openSubdiv_deleteEvaluator(subdiv->evaluator);
- }
- if (subdiv->topology_refiner != NULL) {
- openSubdiv_deleteTopologyRefiner(subdiv->topology_refiner);
- }
- BKE_subdiv_displacement_detach(subdiv);
- if (subdiv->cache_.face_ptex_offset != NULL) {
- MEM_freeN(subdiv->cache_.face_ptex_offset);
- }
- MEM_freeN(subdiv);
+ if (subdiv->evaluator != NULL) {
+ openSubdiv_deleteEvaluator(subdiv->evaluator);
+ }
+ if (subdiv->topology_refiner != NULL) {
+ openSubdiv_deleteTopologyRefiner(subdiv->topology_refiner);
+ }
+ BKE_subdiv_displacement_detach(subdiv);
+ if (subdiv->cache_.face_ptex_offset != NULL) {
+ MEM_freeN(subdiv->cache_.face_ptex_offset);
+ }
+ MEM_freeN(subdiv);
}
/* =========================== PTEX FACES AND GRIDS ========================= */
int *BKE_subdiv_face_ptex_offset_get(Subdiv *subdiv)
{
- if (subdiv->cache_.face_ptex_offset != NULL) {
- return subdiv->cache_.face_ptex_offset;
- }
- OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
- if (topology_refiner == NULL) {
- return NULL;
- }
- const int num_coarse_faces =
- topology_refiner->getNumFaces(topology_refiner);
- subdiv->cache_.face_ptex_offset = MEM_malloc_arrayN(
- num_coarse_faces, sizeof(int), "subdiv face_ptex_offset");
- int ptex_offset = 0;
- for (int face_index = 0; face_index < num_coarse_faces; face_index++) {
- const int num_ptex_faces =
- topology_refiner->getNumFacePtexFaces(
- topology_refiner, face_index);
- subdiv->cache_.face_ptex_offset[face_index] = ptex_offset;
- ptex_offset += num_ptex_faces;
- }
- return subdiv->cache_.face_ptex_offset;
+ if (subdiv->cache_.face_ptex_offset != NULL) {
+ return subdiv->cache_.face_ptex_offset;
+ }
+ OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
+ if (topology_refiner == NULL) {
+ return NULL;
+ }
+ const int num_coarse_faces = topology_refiner->getNumFaces(topology_refiner);
+ subdiv->cache_.face_ptex_offset = MEM_malloc_arrayN(
+ num_coarse_faces, sizeof(int), "subdiv face_ptex_offset");
+ int ptex_offset = 0;
+ for (int face_index = 0; face_index < num_coarse_faces; face_index++) {
+ const int num_ptex_faces = topology_refiner->getNumFacePtexFaces(topology_refiner, face_index);
+ subdiv->cache_.face_ptex_offset[face_index] = ptex_offset;
+ ptex_offset += num_ptex_faces;
+ }
+ return subdiv->cache_.face_ptex_offset;
}
diff --git a/source/blender/blenkernel/intern/subdiv_ccg.c b/source/blender/blenkernel/intern/subdiv_ccg.c
index c262ccfe16f..41ef2bd4b04 100644
--- a/source/blender/blenkernel/intern/subdiv_ccg.c
+++ b/source/blender/blenkernel/intern/subdiv_ccg.c
@@ -44,14 +44,11 @@
* Various forward declarations.
*/
-static void subdiv_ccg_average_all_boundaries_and_corners(
- SubdivCCG *subdiv_ccg,
- CCGKey *key);
+static void subdiv_ccg_average_all_boundaries_and_corners(SubdivCCG *subdiv_ccg, CCGKey *key);
-static void subdiv_ccg_average_inner_face_grids(
- SubdivCCG *subdiv_ccg,
- CCGKey *key,
- SubdivCCGFace *face);
+static void subdiv_ccg_average_inner_face_grids(SubdivCCG *subdiv_ccg,
+ CCGKey *key,
+ SubdivCCGFace *face);
/* =============================================================================
* Generally useful internal helpers.
@@ -60,112 +57,104 @@ static void subdiv_ccg_average_inner_face_grids(
/* Number of floats in per-vertex elements. */
static int num_element_float_get(const SubdivCCG *subdiv_ccg)
{
- /* We always have 3 floats for coordinate. */
- int num_floats = 3;
- if (subdiv_ccg->has_normal) {
- num_floats += 3;
- }
- if (subdiv_ccg->has_mask) {
- num_floats += 1;
- }
- return num_floats;
+ /* We always have 3 floats for coordinate. */
+ int num_floats = 3;
+ if (subdiv_ccg->has_normal) {
+ num_floats += 3;
+ }
+ if (subdiv_ccg->has_mask) {
+ num_floats += 1;
+ }
+ return num_floats;
}
/* Per-vertex element size in bytes. */
static int element_size_bytes_get(const SubdivCCG *subdiv_ccg)
{
- return sizeof(float) * num_element_float_get(subdiv_ccg);
+ return sizeof(float) * num_element_float_get(subdiv_ccg);
}
/* =============================================================================
* Internal helpers for CCG creation.
*/
-static void subdiv_ccg_init_layers(SubdivCCG *subdiv_ccg,
- const SubdivToCCGSettings *settings)
+static void subdiv_ccg_init_layers(SubdivCCG *subdiv_ccg, const SubdivToCCGSettings *settings)
{
- /* CCG always contains coordinates. Rest of layers are coming after them. */
- int layer_offset = sizeof(float) * 3;
- /* Mask. */
- if (settings->need_mask) {
- subdiv_ccg->has_mask = true;
- subdiv_ccg->mask_offset = layer_offset;
- layer_offset += sizeof(float);
- }
- else {
- subdiv_ccg->has_mask = false;
- subdiv_ccg->mask_offset = -1;
- }
- /* Normals.
- *
- * NOTE: Keep them at the end, matching old CCGDM. Doesn't really matter
- * here, but some other area might in theory depend memory layout. */
- if (settings->need_normal) {
- subdiv_ccg->has_normal = true;
- subdiv_ccg->normal_offset = layer_offset;
- layer_offset += sizeof(float) * 3;
- }
- else {
- subdiv_ccg->has_normal = false;
- subdiv_ccg->normal_offset = -1;
- }
+ /* CCG always contains coordinates. Rest of layers are coming after them. */
+ int layer_offset = sizeof(float) * 3;
+ /* Mask. */
+ if (settings->need_mask) {
+ subdiv_ccg->has_mask = true;
+ subdiv_ccg->mask_offset = layer_offset;
+ layer_offset += sizeof(float);
+ }
+ else {
+ subdiv_ccg->has_mask = false;
+ subdiv_ccg->mask_offset = -1;
+ }
+ /* Normals.
+ *
+ * NOTE: Keep them at the end, matching old CCGDM. Doesn't really matter
+ * here, but some other area might in theory depend memory layout. */
+ if (settings->need_normal) {
+ subdiv_ccg->has_normal = true;
+ subdiv_ccg->normal_offset = layer_offset;
+ layer_offset += sizeof(float) * 3;
+ }
+ else {
+ subdiv_ccg->has_normal = false;
+ subdiv_ccg->normal_offset = -1;
+ }
}
/* TODO(sergey): Make it more accessible function. */
-static int topology_refiner_count_face_corners(
- OpenSubdiv_TopologyRefiner *topology_refiner)
+static int topology_refiner_count_face_corners(OpenSubdiv_TopologyRefiner *topology_refiner)
{
- const int num_faces = topology_refiner->getNumFaces(topology_refiner);
- int num_corners = 0;
- for (int face_index = 0; face_index < num_faces; face_index++) {
- num_corners += topology_refiner->getNumFaceVertices(
- topology_refiner, face_index);
- }
- return num_corners;
+ const int num_faces = topology_refiner->getNumFaces(topology_refiner);
+ int num_corners = 0;
+ for (int face_index = 0; face_index < num_faces; face_index++) {
+ num_corners += topology_refiner->getNumFaceVertices(topology_refiner, face_index);
+ }
+ return num_corners;
}
/* NOTE: Grid size and layer flags are to be filled in before calling this
* function. */
static void subdiv_ccg_alloc_elements(SubdivCCG *subdiv_ccg, Subdiv *subdiv)
{
- OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
- const int element_size = element_size_bytes_get(subdiv_ccg);
- /* Allocate memory for surface grids. */
- const int num_faces = topology_refiner->getNumFaces(topology_refiner);
- const int num_grids = topology_refiner_count_face_corners(topology_refiner);
- const int grid_size = BKE_subdiv_grid_size_from_level(subdiv_ccg->level);
- const int grid_area = grid_size * grid_size;
- subdiv_ccg->num_grids = num_grids;
- subdiv_ccg->grids =
- MEM_calloc_arrayN(num_grids, sizeof(CCGElem *), "subdiv ccg grids");
- subdiv_ccg->grids_storage = MEM_calloc_arrayN(
- num_grids, ((size_t)grid_area) * element_size,
- "subdiv ccg grids storage");
- const size_t grid_size_in_bytes = (size_t)grid_area * element_size;
- for (int grid_index = 0; grid_index < num_grids; grid_index++) {
- const size_t grid_offset = grid_size_in_bytes * grid_index;
- subdiv_ccg->grids[grid_index] =
- (CCGElem *)&subdiv_ccg->grids_storage[grid_offset];
- }
- /* Grid material flags. */
- subdiv_ccg->grid_flag_mats = MEM_calloc_arrayN(
- num_grids, sizeof(DMFlagMat), "ccg grid material flags");
- /* Grid hidden flags. */
- subdiv_ccg->grid_hidden = MEM_calloc_arrayN(
- num_grids, sizeof(BLI_bitmap *), "ccg grid material flags");
- for (int grid_index = 0; grid_index < num_grids; grid_index++) {
- subdiv_ccg->grid_hidden[grid_index] =
- BLI_BITMAP_NEW(grid_area, "ccg grid hidden");
- }
- /* TODO(sergey): Allocate memory for loose elements. */
- /* Allocate memory for faces. */
- subdiv_ccg->num_faces = num_faces;
- if (num_faces) {
- subdiv_ccg->faces = MEM_calloc_arrayN(
- num_faces, sizeof(SubdivCCGFace), "Subdiv CCG faces");
- subdiv_ccg->grid_faces = MEM_calloc_arrayN(
- num_grids, sizeof(SubdivCCGFace *), "Subdiv CCG grid faces");
- }
+ OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
+ const int element_size = element_size_bytes_get(subdiv_ccg);
+ /* Allocate memory for surface grids. */
+ const int num_faces = topology_refiner->getNumFaces(topology_refiner);
+ const int num_grids = topology_refiner_count_face_corners(topology_refiner);
+ const int grid_size = BKE_subdiv_grid_size_from_level(subdiv_ccg->level);
+ const int grid_area = grid_size * grid_size;
+ subdiv_ccg->num_grids = num_grids;
+ subdiv_ccg->grids = MEM_calloc_arrayN(num_grids, sizeof(CCGElem *), "subdiv ccg grids");
+ subdiv_ccg->grids_storage = MEM_calloc_arrayN(
+ num_grids, ((size_t)grid_area) * element_size, "subdiv ccg grids storage");
+ const size_t grid_size_in_bytes = (size_t)grid_area * element_size;
+ for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+ const size_t grid_offset = grid_size_in_bytes * grid_index;
+ subdiv_ccg->grids[grid_index] = (CCGElem *)&subdiv_ccg->grids_storage[grid_offset];
+ }
+ /* Grid material flags. */
+ subdiv_ccg->grid_flag_mats = MEM_calloc_arrayN(
+ num_grids, sizeof(DMFlagMat), "ccg grid material flags");
+ /* Grid hidden flags. */
+ subdiv_ccg->grid_hidden = MEM_calloc_arrayN(
+ num_grids, sizeof(BLI_bitmap *), "ccg grid material flags");
+ for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+ subdiv_ccg->grid_hidden[grid_index] = BLI_BITMAP_NEW(grid_area, "ccg grid hidden");
+ }
+ /* TODO(sergey): Allocate memory for loose elements. */
+ /* Allocate memory for faces. */
+ subdiv_ccg->num_faces = num_faces;
+ if (num_faces) {
+ subdiv_ccg->faces = MEM_calloc_arrayN(num_faces, sizeof(SubdivCCGFace), "Subdiv CCG faces");
+ subdiv_ccg->grid_faces = MEM_calloc_arrayN(
+ num_grids, sizeof(SubdivCCGFace *), "Subdiv CCG grid faces");
+ }
}
/* =============================================================================
@@ -173,569 +162,497 @@ static void subdiv_ccg_alloc_elements(SubdivCCG *subdiv_ccg, Subdiv *subdiv)
*/
typedef struct CCGEvalGridsData {
- SubdivCCG *subdiv_ccg;
- Subdiv *subdiv;
- int *face_ptex_offset;
- SubdivCCGMaskEvaluator *mask_evaluator;
- SubdivCCGMaterialFlagsEvaluator *material_flags_evaluator;
+ SubdivCCG *subdiv_ccg;
+ Subdiv *subdiv;
+ int *face_ptex_offset;
+ SubdivCCGMaskEvaluator *mask_evaluator;
+ SubdivCCGMaterialFlagsEvaluator *material_flags_evaluator;
} CCGEvalGridsData;
-static void subdiv_ccg_eval_grid_element(
- CCGEvalGridsData *data,
- const int ptex_face_index,
- const float u, const float v,
- unsigned char *element)
+static void subdiv_ccg_eval_grid_element(CCGEvalGridsData *data,
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ unsigned char *element)
{
- Subdiv *subdiv = data->subdiv;
- SubdivCCG *subdiv_ccg = data->subdiv_ccg;
- if (subdiv->displacement_evaluator != NULL) {
- BKE_subdiv_eval_final_point(
- subdiv, ptex_face_index, u, v, (float *)element);
- }
- else if (subdiv_ccg->has_normal) {
- BKE_subdiv_eval_limit_point_and_normal(
- subdiv, ptex_face_index, u, v,
- (float *)element,
- (float *)(element + subdiv_ccg->normal_offset));
- }
- else {
- BKE_subdiv_eval_limit_point(
- subdiv, ptex_face_index, u, v, (float *)element);
- }
- if (subdiv_ccg->has_mask) {
- float *mask_value_ptr = (float *)(element + subdiv_ccg->mask_offset);
- if (data->mask_evaluator != NULL) {
- *mask_value_ptr = data->mask_evaluator->eval_mask(
- data->mask_evaluator, ptex_face_index, u, v);
- }
- else {
- *mask_value_ptr = 0.0f;
- }
- }
+ Subdiv *subdiv = data->subdiv;
+ SubdivCCG *subdiv_ccg = data->subdiv_ccg;
+ if (subdiv->displacement_evaluator != NULL) {
+ BKE_subdiv_eval_final_point(subdiv, ptex_face_index, u, v, (float *)element);
+ }
+ else if (subdiv_ccg->has_normal) {
+ BKE_subdiv_eval_limit_point_and_normal(subdiv,
+ ptex_face_index,
+ u,
+ v,
+ (float *)element,
+ (float *)(element + subdiv_ccg->normal_offset));
+ }
+ else {
+ BKE_subdiv_eval_limit_point(subdiv, ptex_face_index, u, v, (float *)element);
+ }
+ if (subdiv_ccg->has_mask) {
+ float *mask_value_ptr = (float *)(element + subdiv_ccg->mask_offset);
+ if (data->mask_evaluator != NULL) {
+ *mask_value_ptr = data->mask_evaluator->eval_mask(
+ data->mask_evaluator, ptex_face_index, u, v);
+ }
+ else {
+ *mask_value_ptr = 0.0f;
+ }
+ }
}
-static void subdiv_ccg_eval_regular_grid(CCGEvalGridsData *data,
- const int face_index)
+static void subdiv_ccg_eval_regular_grid(CCGEvalGridsData *data, const int face_index)
{
- SubdivCCG *subdiv_ccg = data->subdiv_ccg;
- const int ptex_face_index = data->face_ptex_offset[face_index];
- const int grid_size = subdiv_ccg->grid_size;
- const float grid_size_1_inv = 1.0f / (float)(grid_size - 1);
- const int element_size = element_size_bytes_get(subdiv_ccg);
- SubdivCCGFace *faces = subdiv_ccg->faces;
- SubdivCCGFace **grid_faces = subdiv_ccg->grid_faces;
- const SubdivCCGFace *face = &faces[face_index];
- for (int corner = 0; corner < face->num_grids; corner++) {
- const int grid_index = face->start_grid_index + corner;
- unsigned char *grid = (unsigned char *)subdiv_ccg->grids[grid_index];
- for (int y = 0; y < grid_size; y++) {
- const float grid_v = (float)y * grid_size_1_inv;
- for (int x = 0; x < grid_size; x++) {
- const float grid_u = (float)x * grid_size_1_inv;
- float u, v;
- BKE_subdiv_rotate_grid_to_quad(
- corner, grid_u, grid_v, &u, &v);
- const size_t grid_element_index = (size_t)y * grid_size + x;
- const size_t grid_element_offset =
- grid_element_index * element_size;
- subdiv_ccg_eval_grid_element(
- data,
- ptex_face_index, u, v,
- &grid[grid_element_offset]);
- }
- }
- /* Assign grid's face. */
- grid_faces[grid_index] = &faces[face_index];
- /* Assign material flags. */
- subdiv_ccg->grid_flag_mats[grid_index] =
- data->material_flags_evaluator->eval_material_flags(
- data->material_flags_evaluator, face_index);
- }
+ SubdivCCG *subdiv_ccg = data->subdiv_ccg;
+ const int ptex_face_index = data->face_ptex_offset[face_index];
+ const int grid_size = subdiv_ccg->grid_size;
+ const float grid_size_1_inv = 1.0f / (float)(grid_size - 1);
+ const int element_size = element_size_bytes_get(subdiv_ccg);
+ SubdivCCGFace *faces = subdiv_ccg->faces;
+ SubdivCCGFace **grid_faces = subdiv_ccg->grid_faces;
+ const SubdivCCGFace *face = &faces[face_index];
+ for (int corner = 0; corner < face->num_grids; corner++) {
+ const int grid_index = face->start_grid_index + corner;
+ unsigned char *grid = (unsigned char *)subdiv_ccg->grids[grid_index];
+ for (int y = 0; y < grid_size; y++) {
+ const float grid_v = (float)y * grid_size_1_inv;
+ for (int x = 0; x < grid_size; x++) {
+ const float grid_u = (float)x * grid_size_1_inv;
+ float u, v;
+ BKE_subdiv_rotate_grid_to_quad(corner, grid_u, grid_v, &u, &v);
+ const size_t grid_element_index = (size_t)y * grid_size + x;
+ const size_t grid_element_offset = grid_element_index * element_size;
+ subdiv_ccg_eval_grid_element(data, ptex_face_index, u, v, &grid[grid_element_offset]);
+ }
+ }
+ /* Assign grid's face. */
+ grid_faces[grid_index] = &faces[face_index];
+ /* Assign material flags. */
+ subdiv_ccg->grid_flag_mats[grid_index] = data->material_flags_evaluator->eval_material_flags(
+ data->material_flags_evaluator, face_index);
+ }
}
-static void subdiv_ccg_eval_special_grid(CCGEvalGridsData *data,
- const int face_index)
+static void subdiv_ccg_eval_special_grid(CCGEvalGridsData *data, const int face_index)
{
- SubdivCCG *subdiv_ccg = data->subdiv_ccg;
- const int grid_size = subdiv_ccg->grid_size;
- const float grid_size_1_inv = 1.0f / (float)(grid_size - 1);
- const int element_size = element_size_bytes_get(subdiv_ccg);
- SubdivCCGFace *faces = subdiv_ccg->faces;
- SubdivCCGFace **grid_faces = subdiv_ccg->grid_faces;
- const SubdivCCGFace *face = &faces[face_index];
- for (int corner = 0; corner < face->num_grids; corner++) {
- const int grid_index = face->start_grid_index + corner;
- const int ptex_face_index =
- data->face_ptex_offset[face_index] + corner;
- unsigned char *grid = (unsigned char *)subdiv_ccg->grids[grid_index];
- for (int y = 0; y < grid_size; y++) {
- const float u = 1.0f - ((float)y * grid_size_1_inv);
- for (int x = 0; x < grid_size; x++) {
- const float v = 1.0f - ((float)x * grid_size_1_inv);
- const size_t grid_element_index = (size_t)y * grid_size + x;
- const size_t grid_element_offset =
- grid_element_index * element_size;
- subdiv_ccg_eval_grid_element(
- data,
- ptex_face_index, u, v,
- &grid[grid_element_offset]);
- }
- }
- /* Assign grid's face. */
- grid_faces[grid_index] = &faces[face_index];
- /* Assign material flags. */
- subdiv_ccg->grid_flag_mats[grid_index] =
- data->material_flags_evaluator->eval_material_flags(
- data->material_flags_evaluator, face_index);
- }
+ SubdivCCG *subdiv_ccg = data->subdiv_ccg;
+ const int grid_size = subdiv_ccg->grid_size;
+ const float grid_size_1_inv = 1.0f / (float)(grid_size - 1);
+ const int element_size = element_size_bytes_get(subdiv_ccg);
+ SubdivCCGFace *faces = subdiv_ccg->faces;
+ SubdivCCGFace **grid_faces = subdiv_ccg->grid_faces;
+ const SubdivCCGFace *face = &faces[face_index];
+ for (int corner = 0; corner < face->num_grids; corner++) {
+ const int grid_index = face->start_grid_index + corner;
+ const int ptex_face_index = data->face_ptex_offset[face_index] + corner;
+ unsigned char *grid = (unsigned char *)subdiv_ccg->grids[grid_index];
+ for (int y = 0; y < grid_size; y++) {
+ const float u = 1.0f - ((float)y * grid_size_1_inv);
+ for (int x = 0; x < grid_size; x++) {
+ const float v = 1.0f - ((float)x * grid_size_1_inv);
+ const size_t grid_element_index = (size_t)y * grid_size + x;
+ const size_t grid_element_offset = grid_element_index * element_size;
+ subdiv_ccg_eval_grid_element(data, ptex_face_index, u, v, &grid[grid_element_offset]);
+ }
+ }
+ /* Assign grid's face. */
+ grid_faces[grid_index] = &faces[face_index];
+ /* Assign material flags. */
+ subdiv_ccg->grid_flag_mats[grid_index] = data->material_flags_evaluator->eval_material_flags(
+ data->material_flags_evaluator, face_index);
+ }
}
-static void subdiv_ccg_eval_grids_task(
- void *__restrict userdata_v,
- const int face_index,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void subdiv_ccg_eval_grids_task(void *__restrict userdata_v,
+ const int face_index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- CCGEvalGridsData *data = userdata_v;
- SubdivCCG *subdiv_ccg = data->subdiv_ccg;
- SubdivCCGFace *face = &subdiv_ccg->faces[face_index];
- if (face->num_grids == 4) {
- subdiv_ccg_eval_regular_grid(data, face_index);
- }
- else {
- subdiv_ccg_eval_special_grid(data, face_index);
- }
+ CCGEvalGridsData *data = userdata_v;
+ SubdivCCG *subdiv_ccg = data->subdiv_ccg;
+ SubdivCCGFace *face = &subdiv_ccg->faces[face_index];
+ if (face->num_grids == 4) {
+ subdiv_ccg_eval_regular_grid(data, face_index);
+ }
+ else {
+ subdiv_ccg_eval_special_grid(data, face_index);
+ }
}
-static bool subdiv_ccg_evaluate_grids(
- SubdivCCG *subdiv_ccg,
- Subdiv *subdiv,
- SubdivCCGMaskEvaluator *mask_evaluator,
- SubdivCCGMaterialFlagsEvaluator *material_flags_evaluator)
+static bool subdiv_ccg_evaluate_grids(SubdivCCG *subdiv_ccg,
+ Subdiv *subdiv,
+ SubdivCCGMaskEvaluator *mask_evaluator,
+ SubdivCCGMaterialFlagsEvaluator *material_flags_evaluator)
{
- OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
- const int num_faces = topology_refiner->getNumFaces(topology_refiner);
- /* Initialize data passed to all the tasks. */
- CCGEvalGridsData data;
- data.subdiv_ccg = subdiv_ccg;
- data.subdiv = subdiv;
- data.face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv);
- data.mask_evaluator = mask_evaluator;
- data.material_flags_evaluator = material_flags_evaluator;
- /* Threaded grids evaluation. */
- ParallelRangeSettings parallel_range_settings;
- BLI_parallel_range_settings_defaults(&parallel_range_settings);
- BLI_task_parallel_range(0, num_faces,
- &data,
- subdiv_ccg_eval_grids_task,
- &parallel_range_settings);
- /* If displacement is used, need to calculate normals after all final
- * coordinates are known. */
- if (subdiv->displacement_evaluator != NULL) {
- BKE_subdiv_ccg_recalc_normals(subdiv_ccg);
- }
- return true;
+ OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
+ const int num_faces = topology_refiner->getNumFaces(topology_refiner);
+ /* Initialize data passed to all the tasks. */
+ CCGEvalGridsData data;
+ data.subdiv_ccg = subdiv_ccg;
+ data.subdiv = subdiv;
+ data.face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv);
+ data.mask_evaluator = mask_evaluator;
+ data.material_flags_evaluator = material_flags_evaluator;
+ /* Threaded grids evaluation. */
+ ParallelRangeSettings parallel_range_settings;
+ BLI_parallel_range_settings_defaults(&parallel_range_settings);
+ BLI_task_parallel_range(
+ 0, num_faces, &data, subdiv_ccg_eval_grids_task, &parallel_range_settings);
+ /* If displacement is used, need to calculate normals after all final
+ * coordinates are known. */
+ if (subdiv->displacement_evaluator != NULL) {
+ BKE_subdiv_ccg_recalc_normals(subdiv_ccg);
+ }
+ return true;
}
/* Initialize face descriptors, assuming memory for them was already
* allocated. */
static void subdiv_ccg_init_faces(SubdivCCG *subdiv_ccg)
{
- Subdiv *subdiv = subdiv_ccg->subdiv;
- OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
- const int num_faces = subdiv_ccg->num_faces;
- int corner_index = 0;
- for (int face_index = 0; face_index < num_faces; face_index++) {
- const int num_corners = topology_refiner->getNumFaceVertices(
- topology_refiner, face_index);
- subdiv_ccg->faces[face_index].num_grids = num_corners;
- subdiv_ccg->faces[face_index].start_grid_index = corner_index;
- corner_index += num_corners;
- }
+ Subdiv *subdiv = subdiv_ccg->subdiv;
+ OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
+ const int num_faces = subdiv_ccg->num_faces;
+ int corner_index = 0;
+ for (int face_index = 0; face_index < num_faces; face_index++) {
+ const int num_corners = topology_refiner->getNumFaceVertices(topology_refiner, face_index);
+ subdiv_ccg->faces[face_index].num_grids = num_corners;
+ subdiv_ccg->faces[face_index].start_grid_index = corner_index;
+ corner_index += num_corners;
+ }
}
/* TODO(sergey): Consider making it generic enough to be fit into BLI. */
typedef struct StaticOrHeapIntStorage {
- int static_storage[64];
- int static_storage_size;
- int *heap_storage;
- int heap_storage_size;
+ int static_storage[64];
+ int static_storage_size;
+ int *heap_storage;
+ int heap_storage_size;
} StaticOrHeapIntStorage;
static void static_or_heap_storage_init(StaticOrHeapIntStorage *storage)
{
- storage->static_storage_size =
- sizeof(storage->static_storage) / sizeof(*storage->static_storage);
- storage->heap_storage = NULL;
- storage->heap_storage_size = 0;
+ storage->static_storage_size = sizeof(storage->static_storage) /
+ sizeof(*storage->static_storage);
+ storage->heap_storage = NULL;
+ storage->heap_storage_size = 0;
}
-static int *static_or_heap_storage_get(StaticOrHeapIntStorage *storage,
- int size)
+static int *static_or_heap_storage_get(StaticOrHeapIntStorage *storage, int size)
{
- /* Requested size small enough to be fit into stack allocated memory. */
- if (size <= storage->static_storage_size) {
- return storage->static_storage;
- }
- /* Make sure heap ius big enough. */
- if (size > storage->heap_storage_size) {
- MEM_SAFE_FREE(storage->heap_storage);
- storage->heap_storage = MEM_malloc_arrayN(
- size, sizeof(int), "int storage");
- storage->heap_storage_size = size;
- }
- return storage->heap_storage;
+ /* Requested size small enough to be fit into stack allocated memory. */
+ if (size <= storage->static_storage_size) {
+ return storage->static_storage;
+ }
+ /* Make sure heap ius big enough. */
+ if (size > storage->heap_storage_size) {
+ MEM_SAFE_FREE(storage->heap_storage);
+ storage->heap_storage = MEM_malloc_arrayN(size, sizeof(int), "int storage");
+ storage->heap_storage_size = size;
+ }
+ return storage->heap_storage;
}
static void static_or_heap_storage_free(StaticOrHeapIntStorage *storage)
{
- MEM_SAFE_FREE(storage->heap_storage);
+ MEM_SAFE_FREE(storage->heap_storage);
}
-static void subdiv_ccg_allocate_adjacent_edges(SubdivCCG *subdiv_ccg,
- const int num_edges)
+static void subdiv_ccg_allocate_adjacent_edges(SubdivCCG *subdiv_ccg, const int num_edges)
{
- subdiv_ccg->num_adjacent_edges = num_edges;
- subdiv_ccg->adjacent_edges = MEM_calloc_arrayN(
- subdiv_ccg->num_adjacent_edges,
- sizeof(*subdiv_ccg->adjacent_edges),
- "ccg adjacent edges");
+ subdiv_ccg->num_adjacent_edges = num_edges;
+ subdiv_ccg->adjacent_edges = MEM_calloc_arrayN(
+ subdiv_ccg->num_adjacent_edges, sizeof(*subdiv_ccg->adjacent_edges), "ccg adjacent edges");
}
/* Returns storage where boundary elements are to be stored. */
-static CCGElem **subdiv_ccg_adjacent_edge_add_face(
- SubdivCCG *subdiv_ccg,
- SubdivCCGAdjacentEdge *adjacent_edge,
- SubdivCCGFace *face)
+static CCGElem **subdiv_ccg_adjacent_edge_add_face(SubdivCCG *subdiv_ccg,
+ SubdivCCGAdjacentEdge *adjacent_edge,
+ SubdivCCGFace *face)
{
- const int grid_size = subdiv_ccg->grid_size * 2;
- const int adjacent_face_index = adjacent_edge->num_adjacent_faces;
- ++adjacent_edge->num_adjacent_faces;
- /* Store new adjacent face. */
- adjacent_edge->faces = MEM_reallocN(
- adjacent_edge->faces,
- adjacent_edge->num_adjacent_faces * sizeof(*adjacent_edge->faces));
- adjacent_edge->faces[adjacent_face_index] = face;
- /* Allocate memory for the boundary elements. */
- adjacent_edge->boundary_elements = MEM_reallocN(
- adjacent_edge->boundary_elements,
- adjacent_edge->num_adjacent_faces *
- sizeof(*adjacent_edge->boundary_elements));
- adjacent_edge->boundary_elements[adjacent_face_index] =
- MEM_malloc_arrayN(
- grid_size * 2, sizeof(CCGElem *), "ccg adjacent boundary");
- return adjacent_edge->boundary_elements[adjacent_face_index];
+ const int grid_size = subdiv_ccg->grid_size * 2;
+ const int adjacent_face_index = adjacent_edge->num_adjacent_faces;
+ ++adjacent_edge->num_adjacent_faces;
+ /* Store new adjacent face. */
+ adjacent_edge->faces = MEM_reallocN(
+ adjacent_edge->faces, adjacent_edge->num_adjacent_faces * sizeof(*adjacent_edge->faces));
+ adjacent_edge->faces[adjacent_face_index] = face;
+ /* Allocate memory for the boundary elements. */
+ adjacent_edge->boundary_elements = MEM_reallocN(adjacent_edge->boundary_elements,
+ adjacent_edge->num_adjacent_faces *
+ sizeof(*adjacent_edge->boundary_elements));
+ adjacent_edge->boundary_elements[adjacent_face_index] = MEM_malloc_arrayN(
+ grid_size * 2, sizeof(CCGElem *), "ccg adjacent boundary");
+ return adjacent_edge->boundary_elements[adjacent_face_index];
}
static void subdiv_ccg_init_faces_edge_neighborhood(SubdivCCG *subdiv_ccg)
{
- Subdiv *subdiv = subdiv_ccg->subdiv;
- SubdivCCGFace *faces = subdiv_ccg->faces;
- OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
- const int num_edges = topology_refiner->getNumEdges(topology_refiner);
- const int grid_size = subdiv_ccg->grid_size;
- if (num_edges == 0) {
- /* Early output, nothing to do in this case. */
- return;
- }
- subdiv_ccg_allocate_adjacent_edges(subdiv_ccg, num_edges);
- /* Initialize storage. */
- StaticOrHeapIntStorage face_vertices_storage;
- StaticOrHeapIntStorage face_edges_storage;
- static_or_heap_storage_init(&face_vertices_storage);
- static_or_heap_storage_init(&face_edges_storage);
- /* Key to access elements. */
- CCGKey key;
- BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
- /* Store adjacency for all faces. */
- const int num_faces = subdiv_ccg->num_faces;
- for (int face_index = 0; face_index < num_faces; face_index++) {
- SubdivCCGFace *face = &faces[face_index];
- const int num_face_grids = face->num_grids;
- const int num_face_edges = num_face_grids;
- int *face_vertices = static_or_heap_storage_get(
- &face_vertices_storage, num_face_edges);
- topology_refiner->getFaceVertices(
- topology_refiner, face_index, face_vertices);
- /* Note that order of edges is same as order of MLoops, which also
- * means it's the same as order of grids. */
- int *face_edges = static_or_heap_storage_get(
- &face_edges_storage, num_face_edges);
- topology_refiner->getFaceEdges(
- topology_refiner, face_index, face_edges);
- /* Store grids adjacency for this edge. */
- for (int corner = 0; corner < num_face_edges; corner++) {
- const int vertex_index = face_vertices[corner];
- const int edge_index = face_edges[corner];
- int edge_vertices[2];
- topology_refiner->getEdgeVertices(
- topology_refiner, edge_index, edge_vertices);
- const bool is_edge_flipped = (edge_vertices[0] != vertex_index);
- /* Grid which is adjacent to the current corner. */
- const int current_grid_index = face->start_grid_index + corner;
- CCGElem *current_grid = subdiv_ccg->grids[current_grid_index];
- /* Grid which is adjacent to the next corner. */
- const int next_grid_index =
- face->start_grid_index + (corner + 1) % num_face_grids;
- CCGElem *next_grid = subdiv_ccg->grids[next_grid_index];
- /* Add new face to the adjacent edge. */
- SubdivCCGAdjacentEdge *adjacent_edge =
- &subdiv_ccg->adjacent_edges[edge_index];
- CCGElem **boundary_elements = subdiv_ccg_adjacent_edge_add_face(
- subdiv_ccg, adjacent_edge, face);
- /* Fill CCG elements along the edge. */
- int boundary_element_index = 0;
- if (is_edge_flipped) {
- for (int i = 0; i < grid_size; i++) {
- boundary_elements[boundary_element_index++] =
- CCG_grid_elem(&key,
- next_grid,
- grid_size - i - 1,
- grid_size - 1);
- }
- for (int i = 0; i < grid_size; i++) {
- boundary_elements[boundary_element_index++] =
- CCG_grid_elem(&key,
- current_grid,
- grid_size - 1,
- i);
- }
- }
- else {
- for (int i = 0; i < grid_size; i++) {
- boundary_elements[boundary_element_index++] =
- CCG_grid_elem(&key,
- current_grid,
- grid_size - 1,
- grid_size - i - 1);
- }
- for (int i = 0; i < grid_size; i++) {
- boundary_elements[boundary_element_index++] =
- CCG_grid_elem(&key,
- next_grid,
- i,
- grid_size - 1);
- }
- }
- }
- }
- /* Free possibly heap-allocated storage. */
- static_or_heap_storage_free(&face_vertices_storage);
- static_or_heap_storage_free(&face_edges_storage);
+ Subdiv *subdiv = subdiv_ccg->subdiv;
+ SubdivCCGFace *faces = subdiv_ccg->faces;
+ OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
+ const int num_edges = topology_refiner->getNumEdges(topology_refiner);
+ const int grid_size = subdiv_ccg->grid_size;
+ if (num_edges == 0) {
+ /* Early output, nothing to do in this case. */
+ return;
+ }
+ subdiv_ccg_allocate_adjacent_edges(subdiv_ccg, num_edges);
+ /* Initialize storage. */
+ StaticOrHeapIntStorage face_vertices_storage;
+ StaticOrHeapIntStorage face_edges_storage;
+ static_or_heap_storage_init(&face_vertices_storage);
+ static_or_heap_storage_init(&face_edges_storage);
+ /* Key to access elements. */
+ CCGKey key;
+ BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
+ /* Store adjacency for all faces. */
+ const int num_faces = subdiv_ccg->num_faces;
+ for (int face_index = 0; face_index < num_faces; face_index++) {
+ SubdivCCGFace *face = &faces[face_index];
+ const int num_face_grids = face->num_grids;
+ const int num_face_edges = num_face_grids;
+ int *face_vertices = static_or_heap_storage_get(&face_vertices_storage, num_face_edges);
+ topology_refiner->getFaceVertices(topology_refiner, face_index, face_vertices);
+ /* Note that order of edges is same as order of MLoops, which also
+ * means it's the same as order of grids. */
+ int *face_edges = static_or_heap_storage_get(&face_edges_storage, num_face_edges);
+ topology_refiner->getFaceEdges(topology_refiner, face_index, face_edges);
+ /* Store grids adjacency for this edge. */
+ for (int corner = 0; corner < num_face_edges; corner++) {
+ const int vertex_index = face_vertices[corner];
+ const int edge_index = face_edges[corner];
+ int edge_vertices[2];
+ topology_refiner->getEdgeVertices(topology_refiner, edge_index, edge_vertices);
+ const bool is_edge_flipped = (edge_vertices[0] != vertex_index);
+ /* Grid which is adjacent to the current corner. */
+ const int current_grid_index = face->start_grid_index + corner;
+ CCGElem *current_grid = subdiv_ccg->grids[current_grid_index];
+ /* Grid which is adjacent to the next corner. */
+ const int next_grid_index = face->start_grid_index + (corner + 1) % num_face_grids;
+ CCGElem *next_grid = subdiv_ccg->grids[next_grid_index];
+ /* Add new face to the adjacent edge. */
+ SubdivCCGAdjacentEdge *adjacent_edge = &subdiv_ccg->adjacent_edges[edge_index];
+ CCGElem **boundary_elements = subdiv_ccg_adjacent_edge_add_face(
+ subdiv_ccg, adjacent_edge, face);
+ /* Fill CCG elements along the edge. */
+ int boundary_element_index = 0;
+ if (is_edge_flipped) {
+ for (int i = 0; i < grid_size; i++) {
+ boundary_elements[boundary_element_index++] = CCG_grid_elem(
+ &key, next_grid, grid_size - i - 1, grid_size - 1);
+ }
+ for (int i = 0; i < grid_size; i++) {
+ boundary_elements[boundary_element_index++] = CCG_grid_elem(
+ &key, current_grid, grid_size - 1, i);
+ }
+ }
+ else {
+ for (int i = 0; i < grid_size; i++) {
+ boundary_elements[boundary_element_index++] = CCG_grid_elem(
+ &key, current_grid, grid_size - 1, grid_size - i - 1);
+ }
+ for (int i = 0; i < grid_size; i++) {
+ boundary_elements[boundary_element_index++] = CCG_grid_elem(
+ &key, next_grid, i, grid_size - 1);
+ }
+ }
+ }
+ }
+ /* Free possibly heap-allocated storage. */
+ static_or_heap_storage_free(&face_vertices_storage);
+ static_or_heap_storage_free(&face_edges_storage);
}
-static void subdiv_ccg_allocate_adjacent_vertices(SubdivCCG *subdiv_ccg,
- const int num_vertices)
+static void subdiv_ccg_allocate_adjacent_vertices(SubdivCCG *subdiv_ccg, const int num_vertices)
{
- subdiv_ccg->num_adjacent_vertices = num_vertices;
- subdiv_ccg->adjacent_vertices = MEM_calloc_arrayN(
- subdiv_ccg->num_adjacent_vertices,
- sizeof(*subdiv_ccg->adjacent_vertices),
- "ccg adjacent vertices");
+ subdiv_ccg->num_adjacent_vertices = num_vertices;
+ subdiv_ccg->adjacent_vertices = MEM_calloc_arrayN(subdiv_ccg->num_adjacent_vertices,
+ sizeof(*subdiv_ccg->adjacent_vertices),
+ "ccg adjacent vertices");
}
/* Returns storage where corner elements are to be stored. This is a pointer
* to the actual storage. */
-static CCGElem **subdiv_ccg_adjacent_vertex_add_face(
- SubdivCCGAdjacentVertex *adjacent_vertex,
- SubdivCCGFace *face)
+static CCGElem **subdiv_ccg_adjacent_vertex_add_face(SubdivCCGAdjacentVertex *adjacent_vertex,
+ SubdivCCGFace *face)
{
- const int adjacent_face_index = adjacent_vertex->num_adjacent_faces;
- ++adjacent_vertex->num_adjacent_faces;
- /* Store new adjacent face. */
- adjacent_vertex->faces = MEM_reallocN(
- adjacent_vertex->faces,
- adjacent_vertex->num_adjacent_faces *
- sizeof(*adjacent_vertex->faces));
- adjacent_vertex->faces[adjacent_face_index] = face;
- /* Allocate memory for the boundary elements. */
- adjacent_vertex->corner_elements = MEM_reallocN(
- adjacent_vertex->corner_elements,
- adjacent_vertex->num_adjacent_faces *
- sizeof(*adjacent_vertex->corner_elements));
- return &adjacent_vertex->corner_elements[adjacent_face_index];
+ const int adjacent_face_index = adjacent_vertex->num_adjacent_faces;
+ ++adjacent_vertex->num_adjacent_faces;
+ /* Store new adjacent face. */
+ adjacent_vertex->faces = MEM_reallocN(adjacent_vertex->faces,
+ adjacent_vertex->num_adjacent_faces *
+ sizeof(*adjacent_vertex->faces));
+ adjacent_vertex->faces[adjacent_face_index] = face;
+ /* Allocate memory for the boundary elements. */
+ adjacent_vertex->corner_elements = MEM_reallocN(adjacent_vertex->corner_elements,
+ adjacent_vertex->num_adjacent_faces *
+ sizeof(*adjacent_vertex->corner_elements));
+ return &adjacent_vertex->corner_elements[adjacent_face_index];
}
static void subdiv_ccg_init_faces_vertex_neighborhood(SubdivCCG *subdiv_ccg)
{
- Subdiv *subdiv = subdiv_ccg->subdiv;
- SubdivCCGFace *faces = subdiv_ccg->faces;
- OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
- const int num_vertices =
- topology_refiner->getNumVertices(topology_refiner);
- const int grid_size = subdiv_ccg->grid_size;
- if (num_vertices == 0) {
- /* Early output, nothing to do in this case. */
- return;
- }
- subdiv_ccg_allocate_adjacent_vertices(subdiv_ccg, num_vertices);
- /* Initialize storage. */
- StaticOrHeapIntStorage face_vertices_storage;
- static_or_heap_storage_init(&face_vertices_storage);
- /* Key to access elements. */
- CCGKey key;
- BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
- /* Store adjacency for all faces. */
- const int num_faces = subdiv_ccg->num_faces;
- for (int face_index = 0; face_index < num_faces; face_index++) {
- SubdivCCGFace *face = &faces[face_index];
- const int num_face_grids = face->num_grids;
- const int num_face_edges = num_face_grids;
- int *face_vertices = static_or_heap_storage_get(
- &face_vertices_storage, num_face_edges);
- topology_refiner->getFaceVertices(
- topology_refiner, face_index, face_vertices);
- for (int corner = 0; corner < num_face_edges; corner++) {
- const int vertex_index = face_vertices[corner];
- /* Grid which is adjacent to the current corner. */
- const int grid_index = face->start_grid_index + corner;
- CCGElem *grid = subdiv_ccg->grids[grid_index];
- /* Add new face to the adjacent edge. */
- SubdivCCGAdjacentVertex *adjacent_vertex =
- &subdiv_ccg->adjacent_vertices[vertex_index];
- CCGElem **corner_element = subdiv_ccg_adjacent_vertex_add_face(
- adjacent_vertex, face);
- *corner_element = CCG_grid_elem(
- &key, grid, grid_size - 1, grid_size - 1);
- }
- }
- /* Free possibly heap-allocated storage. */
- static_or_heap_storage_free(&face_vertices_storage);
+ Subdiv *subdiv = subdiv_ccg->subdiv;
+ SubdivCCGFace *faces = subdiv_ccg->faces;
+ OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
+ const int num_vertices = topology_refiner->getNumVertices(topology_refiner);
+ const int grid_size = subdiv_ccg->grid_size;
+ if (num_vertices == 0) {
+ /* Early output, nothing to do in this case. */
+ return;
+ }
+ subdiv_ccg_allocate_adjacent_vertices(subdiv_ccg, num_vertices);
+ /* Initialize storage. */
+ StaticOrHeapIntStorage face_vertices_storage;
+ static_or_heap_storage_init(&face_vertices_storage);
+ /* Key to access elements. */
+ CCGKey key;
+ BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
+ /* Store adjacency for all faces. */
+ const int num_faces = subdiv_ccg->num_faces;
+ for (int face_index = 0; face_index < num_faces; face_index++) {
+ SubdivCCGFace *face = &faces[face_index];
+ const int num_face_grids = face->num_grids;
+ const int num_face_edges = num_face_grids;
+ int *face_vertices = static_or_heap_storage_get(&face_vertices_storage, num_face_edges);
+ topology_refiner->getFaceVertices(topology_refiner, face_index, face_vertices);
+ for (int corner = 0; corner < num_face_edges; corner++) {
+ const int vertex_index = face_vertices[corner];
+ /* Grid which is adjacent to the current corner. */
+ const int grid_index = face->start_grid_index + corner;
+ CCGElem *grid = subdiv_ccg->grids[grid_index];
+ /* Add new face to the adjacent edge. */
+ SubdivCCGAdjacentVertex *adjacent_vertex = &subdiv_ccg->adjacent_vertices[vertex_index];
+ CCGElem **corner_element = subdiv_ccg_adjacent_vertex_add_face(adjacent_vertex, face);
+ *corner_element = CCG_grid_elem(&key, grid, grid_size - 1, grid_size - 1);
+ }
+ }
+ /* Free possibly heap-allocated storage. */
+ static_or_heap_storage_free(&face_vertices_storage);
}
static void subdiv_ccg_init_faces_neighborhood(SubdivCCG *subdiv_ccg)
{
- subdiv_ccg_init_faces_edge_neighborhood(subdiv_ccg);
- subdiv_ccg_init_faces_vertex_neighborhood(subdiv_ccg);
+ subdiv_ccg_init_faces_edge_neighborhood(subdiv_ccg);
+ subdiv_ccg_init_faces_vertex_neighborhood(subdiv_ccg);
}
/* =============================================================================
* Creation / evaluation.
*/
-SubdivCCG *BKE_subdiv_to_ccg(
- Subdiv *subdiv,
- const SubdivToCCGSettings *settings,
- SubdivCCGMaskEvaluator *mask_evaluator,
- SubdivCCGMaterialFlagsEvaluator *material_flags_evaluator)
+SubdivCCG *BKE_subdiv_to_ccg(Subdiv *subdiv,
+ const SubdivToCCGSettings *settings,
+ SubdivCCGMaskEvaluator *mask_evaluator,
+ SubdivCCGMaterialFlagsEvaluator *material_flags_evaluator)
{
- BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
- SubdivCCG *subdiv_ccg = MEM_callocN(sizeof(SubdivCCG), "subdiv ccg");
- subdiv_ccg->subdiv = subdiv;
- subdiv_ccg->level = bitscan_forward_i(settings->resolution - 1);
- subdiv_ccg->grid_size = BKE_subdiv_grid_size_from_level(subdiv_ccg->level);
- subdiv_ccg_init_layers(subdiv_ccg, settings);
- subdiv_ccg_alloc_elements(subdiv_ccg, subdiv);
- subdiv_ccg_init_faces(subdiv_ccg);
- subdiv_ccg_init_faces_neighborhood(subdiv_ccg);
- if (!subdiv_ccg_evaluate_grids(
- subdiv_ccg, subdiv, mask_evaluator, material_flags_evaluator))
- {
- BKE_subdiv_ccg_destroy(subdiv_ccg);
- BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
- return NULL;
- }
- BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
- return subdiv_ccg;
+ BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
+ SubdivCCG *subdiv_ccg = MEM_callocN(sizeof(SubdivCCG), "subdiv ccg");
+ subdiv_ccg->subdiv = subdiv;
+ subdiv_ccg->level = bitscan_forward_i(settings->resolution - 1);
+ subdiv_ccg->grid_size = BKE_subdiv_grid_size_from_level(subdiv_ccg->level);
+ subdiv_ccg_init_layers(subdiv_ccg, settings);
+ subdiv_ccg_alloc_elements(subdiv_ccg, subdiv);
+ subdiv_ccg_init_faces(subdiv_ccg);
+ subdiv_ccg_init_faces_neighborhood(subdiv_ccg);
+ if (!subdiv_ccg_evaluate_grids(subdiv_ccg, subdiv, mask_evaluator, material_flags_evaluator)) {
+ BKE_subdiv_ccg_destroy(subdiv_ccg);
+ BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
+ return NULL;
+ }
+ BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
+ return subdiv_ccg;
}
-Mesh *BKE_subdiv_to_ccg_mesh(
- Subdiv *subdiv,
- const SubdivToCCGSettings *settings,
- const Mesh *coarse_mesh)
+Mesh *BKE_subdiv_to_ccg_mesh(Subdiv *subdiv,
+ const SubdivToCCGSettings *settings,
+ const Mesh *coarse_mesh)
{
- /* Make sure evaluator is ready. */
- BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
- if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh)) {
- if (coarse_mesh->totpoly) {
- return false;
- }
- }
- BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
- SubdivCCGMaskEvaluator mask_evaluator;
- bool has_mask = BKE_subdiv_ccg_mask_init_from_paint(
- &mask_evaluator, coarse_mesh);
- SubdivCCGMaterialFlagsEvaluator material_flags_evaluator;
- BKE_subdiv_ccg_material_flags_init_from_mesh(
- &material_flags_evaluator, coarse_mesh);
- SubdivCCG *subdiv_ccg = BKE_subdiv_to_ccg(
- subdiv,
- settings,
- has_mask ? &mask_evaluator : NULL,
- &material_flags_evaluator);
- if (has_mask) {
- mask_evaluator.free(&mask_evaluator);
- }
- material_flags_evaluator.free(&material_flags_evaluator);
- if (subdiv_ccg == NULL) {
- return NULL;
- }
- Mesh *result = BKE_mesh_new_nomain_from_template(
- coarse_mesh, 0, 0, 0, 0, 0);
- result->runtime.subdiv_ccg = subdiv_ccg;
- return result;
+ /* Make sure evaluator is ready. */
+ BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
+ if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh)) {
+ if (coarse_mesh->totpoly) {
+ return false;
+ }
+ }
+ BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
+ SubdivCCGMaskEvaluator mask_evaluator;
+ bool has_mask = BKE_subdiv_ccg_mask_init_from_paint(&mask_evaluator, coarse_mesh);
+ SubdivCCGMaterialFlagsEvaluator material_flags_evaluator;
+ BKE_subdiv_ccg_material_flags_init_from_mesh(&material_flags_evaluator, coarse_mesh);
+ SubdivCCG *subdiv_ccg = BKE_subdiv_to_ccg(
+ subdiv, settings, has_mask ? &mask_evaluator : NULL, &material_flags_evaluator);
+ if (has_mask) {
+ mask_evaluator.free(&mask_evaluator);
+ }
+ material_flags_evaluator.free(&material_flags_evaluator);
+ if (subdiv_ccg == NULL) {
+ return NULL;
+ }
+ Mesh *result = BKE_mesh_new_nomain_from_template(coarse_mesh, 0, 0, 0, 0, 0);
+ result->runtime.subdiv_ccg = subdiv_ccg;
+ return result;
}
void BKE_subdiv_ccg_destroy(SubdivCCG *subdiv_ccg)
{
- const int num_grids = subdiv_ccg->num_grids;
- MEM_SAFE_FREE(subdiv_ccg->grids);
- MEM_SAFE_FREE(subdiv_ccg->grids_storage);
- MEM_SAFE_FREE(subdiv_ccg->edges);
- MEM_SAFE_FREE(subdiv_ccg->vertices);
- MEM_SAFE_FREE(subdiv_ccg->grid_flag_mats);
- if (subdiv_ccg->grid_hidden != NULL) {
- for (int grid_index = 0; grid_index < num_grids; grid_index++) {
- MEM_freeN(subdiv_ccg->grid_hidden[grid_index]);
- }
- MEM_freeN(subdiv_ccg->grid_hidden);
- }
- if (subdiv_ccg->subdiv != NULL) {
- BKE_subdiv_free(subdiv_ccg->subdiv);
- }
- MEM_SAFE_FREE(subdiv_ccg->faces);
- MEM_SAFE_FREE(subdiv_ccg->grid_faces);
- /* Free map of adjacent edges. */
- for (int i = 0; i < subdiv_ccg->num_adjacent_edges; i++) {
- SubdivCCGAdjacentEdge *adjacent_edge = &subdiv_ccg->adjacent_edges[i];
- for (int face_index = 0;
- face_index < adjacent_edge->num_adjacent_faces;
- face_index++)
- {
- MEM_SAFE_FREE(adjacent_edge->boundary_elements[face_index]);
- }
- MEM_SAFE_FREE(adjacent_edge->faces);
- MEM_SAFE_FREE(adjacent_edge->boundary_elements);
- }
- MEM_SAFE_FREE(subdiv_ccg->adjacent_edges);
- /* Free map of adjacent vertices. */
- for (int i = 0; i < subdiv_ccg->num_adjacent_vertices; i++) {
- SubdivCCGAdjacentVertex *adjacent_vertex =
- &subdiv_ccg->adjacent_vertices[i];
- MEM_SAFE_FREE(adjacent_vertex->faces);
- MEM_SAFE_FREE(adjacent_vertex->corner_elements);
- }
- MEM_SAFE_FREE(subdiv_ccg->adjacent_vertices);
- MEM_freeN(subdiv_ccg);
+ const int num_grids = subdiv_ccg->num_grids;
+ MEM_SAFE_FREE(subdiv_ccg->grids);
+ MEM_SAFE_FREE(subdiv_ccg->grids_storage);
+ MEM_SAFE_FREE(subdiv_ccg->edges);
+ MEM_SAFE_FREE(subdiv_ccg->vertices);
+ MEM_SAFE_FREE(subdiv_ccg->grid_flag_mats);
+ if (subdiv_ccg->grid_hidden != NULL) {
+ for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+ MEM_freeN(subdiv_ccg->grid_hidden[grid_index]);
+ }
+ MEM_freeN(subdiv_ccg->grid_hidden);
+ }
+ if (subdiv_ccg->subdiv != NULL) {
+ BKE_subdiv_free(subdiv_ccg->subdiv);
+ }
+ MEM_SAFE_FREE(subdiv_ccg->faces);
+ MEM_SAFE_FREE(subdiv_ccg->grid_faces);
+ /* Free map of adjacent edges. */
+ for (int i = 0; i < subdiv_ccg->num_adjacent_edges; i++) {
+ SubdivCCGAdjacentEdge *adjacent_edge = &subdiv_ccg->adjacent_edges[i];
+ for (int face_index = 0; face_index < adjacent_edge->num_adjacent_faces; face_index++) {
+ MEM_SAFE_FREE(adjacent_edge->boundary_elements[face_index]);
+ }
+ MEM_SAFE_FREE(adjacent_edge->faces);
+ MEM_SAFE_FREE(adjacent_edge->boundary_elements);
+ }
+ MEM_SAFE_FREE(subdiv_ccg->adjacent_edges);
+ /* Free map of adjacent vertices. */
+ for (int i = 0; i < subdiv_ccg->num_adjacent_vertices; i++) {
+ SubdivCCGAdjacentVertex *adjacent_vertex = &subdiv_ccg->adjacent_vertices[i];
+ MEM_SAFE_FREE(adjacent_vertex->faces);
+ MEM_SAFE_FREE(adjacent_vertex->corner_elements);
+ }
+ MEM_SAFE_FREE(subdiv_ccg->adjacent_vertices);
+ MEM_freeN(subdiv_ccg);
}
void BKE_subdiv_ccg_key(CCGKey *key, const SubdivCCG *subdiv_ccg, int level)
{
- key->level = level;
- key->elem_size = element_size_bytes_get(subdiv_ccg);
- key->grid_size = BKE_subdiv_grid_size_from_level(level);
- key->grid_area = key->grid_size * key->grid_size;
- key->grid_bytes = key->elem_size * key->grid_area;
+ key->level = level;
+ key->elem_size = element_size_bytes_get(subdiv_ccg);
+ key->grid_size = BKE_subdiv_grid_size_from_level(level);
+ key->grid_area = key->grid_size * key->grid_size;
+ key->grid_bytes = key->elem_size * key->grid_area;
- key->normal_offset = subdiv_ccg->normal_offset;
- key->mask_offset = subdiv_ccg->mask_offset;
+ key->normal_offset = subdiv_ccg->normal_offset;
+ key->mask_offset = subdiv_ccg->mask_offset;
- key->has_normals = subdiv_ccg->has_normal;
- key->has_mask = subdiv_ccg->has_mask;
+ key->has_normals = subdiv_ccg->has_normal;
+ key->has_mask = subdiv_ccg->has_mask;
}
void BKE_subdiv_ccg_key_top_level(CCGKey *key, const SubdivCCG *subdiv_ccg)
{
- BKE_subdiv_ccg_key(key, subdiv_ccg, subdiv_ccg->level);
+ BKE_subdiv_ccg_key(key, subdiv_ccg, subdiv_ccg->level);
}
/* =============================================================================
@@ -743,12 +660,12 @@ void BKE_subdiv_ccg_key_top_level(CCGKey *key, const SubdivCCG *subdiv_ccg)
*/
typedef struct RecalcInnerNormalsData {
- SubdivCCG *subdiv_ccg;
- CCGKey *key;
+ SubdivCCG *subdiv_ccg;
+ CCGKey *key;
} RecalcInnerNormalsData;
typedef struct RecalcInnerNormalsTLSData {
- float (*face_normals)[3];
+ float (*face_normals)[3];
} RecalcInnerNormalsTLSData;
/* Evaluate high-res face normals, for faces which corresponds to grid elements
@@ -756,219 +673,201 @@ typedef struct RecalcInnerNormalsTLSData {
* {(x, y), {x + 1, y}, {x + 1, y + 1}, {x, y + 1}}
*
* The result is stored in normals storage from TLS. */
-static void subdiv_ccg_recalc_inner_face_normals(
- SubdivCCG *subdiv_ccg,
- CCGKey *key,
- RecalcInnerNormalsTLSData *tls,
- const int grid_index)
+static void subdiv_ccg_recalc_inner_face_normals(SubdivCCG *subdiv_ccg,
+ CCGKey *key,
+ RecalcInnerNormalsTLSData *tls,
+ const int grid_index)
{
- const int grid_size = subdiv_ccg->grid_size;
- const int grid_size_1 = grid_size - 1;
- CCGElem *grid = subdiv_ccg->grids[grid_index];
- if (tls->face_normals == NULL) {
- tls->face_normals = MEM_malloc_arrayN(
- grid_size_1 * grid_size_1,
- 3 * sizeof(float),
- "CCG TLS normals");
- }
- for (int y = 0; y < grid_size -1; y++) {
- for (int x = 0; x < grid_size - 1; x++) {
- CCGElem *grid_elements[4] = {
- CCG_grid_elem(key, grid, x, y + 1),
- CCG_grid_elem(key, grid, x + 1, y + 1),
- CCG_grid_elem(key, grid, x + 1, y),
- CCG_grid_elem(key, grid, x, y),
- };
- float *co[4] = {
- CCG_elem_co(key, grid_elements[0]),
- CCG_elem_co(key, grid_elements[1]),
- CCG_elem_co(key, grid_elements[2]),
- CCG_elem_co(key, grid_elements[3]),
- };
- const int face_index = y * grid_size_1 + x;
- float *face_normal = tls->face_normals[face_index];
- normal_quad_v3(face_normal, co[0], co[1], co[2], co[3]);
- }
- }
+ const int grid_size = subdiv_ccg->grid_size;
+ const int grid_size_1 = grid_size - 1;
+ CCGElem *grid = subdiv_ccg->grids[grid_index];
+ if (tls->face_normals == NULL) {
+ tls->face_normals = MEM_malloc_arrayN(
+ grid_size_1 * grid_size_1, 3 * sizeof(float), "CCG TLS normals");
+ }
+ for (int y = 0; y < grid_size - 1; y++) {
+ for (int x = 0; x < grid_size - 1; x++) {
+ CCGElem *grid_elements[4] = {
+ CCG_grid_elem(key, grid, x, y + 1),
+ CCG_grid_elem(key, grid, x + 1, y + 1),
+ CCG_grid_elem(key, grid, x + 1, y),
+ CCG_grid_elem(key, grid, x, y),
+ };
+ float *co[4] = {
+ CCG_elem_co(key, grid_elements[0]),
+ CCG_elem_co(key, grid_elements[1]),
+ CCG_elem_co(key, grid_elements[2]),
+ CCG_elem_co(key, grid_elements[3]),
+ };
+ const int face_index = y * grid_size_1 + x;
+ float *face_normal = tls->face_normals[face_index];
+ normal_quad_v3(face_normal, co[0], co[1], co[2], co[3]);
+ }
+ }
}
/* Average normals at every grid element, using adjacent faces normals. */
-static void subdiv_ccg_average_inner_face_normals(
- SubdivCCG *subdiv_ccg,
- CCGKey *key,
- RecalcInnerNormalsTLSData *tls,
- const int grid_index)
+static void subdiv_ccg_average_inner_face_normals(SubdivCCG *subdiv_ccg,
+ CCGKey *key,
+ RecalcInnerNormalsTLSData *tls,
+ const int grid_index)
{
- const int grid_size = subdiv_ccg->grid_size;
- const int grid_size_1 = grid_size - 1;
- CCGElem *grid = subdiv_ccg->grids[grid_index];
- const float (*face_normals)[3] = tls->face_normals;
- for (int y = 0; y < grid_size; y++) {
- for (int x = 0; x < grid_size; x++) {
- float normal_acc[3] = {0.0f, 0.0f, 0.0f};
- int counter = 0;
- /* Accumulate normals of all adjacent faces. */
- if (x < grid_size_1 && y < grid_size_1) {
- add_v3_v3(normal_acc, face_normals[y * grid_size_1 + x]);
- counter++;
- }
- if (x >= 1) {
- if (y < grid_size_1) {
- add_v3_v3(normal_acc,
- face_normals[y * grid_size_1 + (x - 1)]);
- counter++;
- }
- if (y >= 1) {
- add_v3_v3(normal_acc,
- face_normals[(y - 1) * grid_size_1 + (x - 1)]);
- counter++;
- }
- }
- if (y >= 1 && x < grid_size_1) {
- add_v3_v3(normal_acc, face_normals[(y - 1) * grid_size_1 + x]);
- counter++;
- }
- /* Normalize and store. */
- mul_v3_v3fl(CCG_grid_elem_no(key, grid, x, y),
- normal_acc,
- 1.0f / (float)counter);
- }
- }
+ const int grid_size = subdiv_ccg->grid_size;
+ const int grid_size_1 = grid_size - 1;
+ CCGElem *grid = subdiv_ccg->grids[grid_index];
+ const float(*face_normals)[3] = tls->face_normals;
+ for (int y = 0; y < grid_size; y++) {
+ for (int x = 0; x < grid_size; x++) {
+ float normal_acc[3] = {0.0f, 0.0f, 0.0f};
+ int counter = 0;
+ /* Accumulate normals of all adjacent faces. */
+ if (x < grid_size_1 && y < grid_size_1) {
+ add_v3_v3(normal_acc, face_normals[y * grid_size_1 + x]);
+ counter++;
+ }
+ if (x >= 1) {
+ if (y < grid_size_1) {
+ add_v3_v3(normal_acc, face_normals[y * grid_size_1 + (x - 1)]);
+ counter++;
+ }
+ if (y >= 1) {
+ add_v3_v3(normal_acc, face_normals[(y - 1) * grid_size_1 + (x - 1)]);
+ counter++;
+ }
+ }
+ if (y >= 1 && x < grid_size_1) {
+ add_v3_v3(normal_acc, face_normals[(y - 1) * grid_size_1 + x]);
+ counter++;
+ }
+ /* Normalize and store. */
+ mul_v3_v3fl(CCG_grid_elem_no(key, grid, x, y), normal_acc, 1.0f / (float)counter);
+ }
+ }
}
-static void subdiv_ccg_recalc_inner_normal_task(
- void *__restrict userdata_v,
- const int grid_index,
- const ParallelRangeTLS *__restrict tls_v)
+static void subdiv_ccg_recalc_inner_normal_task(void *__restrict userdata_v,
+ const int grid_index,
+ const ParallelRangeTLS *__restrict tls_v)
{
- RecalcInnerNormalsData *data = userdata_v;
- RecalcInnerNormalsTLSData *tls = tls_v->userdata_chunk;
- subdiv_ccg_recalc_inner_face_normals(
- data->subdiv_ccg, data->key, tls, grid_index);
- subdiv_ccg_average_inner_face_normals(
- data->subdiv_ccg, data->key, tls, grid_index);
+ RecalcInnerNormalsData *data = userdata_v;
+ RecalcInnerNormalsTLSData *tls = tls_v->userdata_chunk;
+ subdiv_ccg_recalc_inner_face_normals(data->subdiv_ccg, data->key, tls, grid_index);
+ subdiv_ccg_average_inner_face_normals(data->subdiv_ccg, data->key, tls, grid_index);
}
-static void subdiv_ccg_recalc_inner_normal_finalize(
- void *__restrict UNUSED(userdata),
- void *__restrict tls_v)
+static void subdiv_ccg_recalc_inner_normal_finalize(void *__restrict UNUSED(userdata),
+ void *__restrict tls_v)
{
- RecalcInnerNormalsTLSData *tls = tls_v;
- MEM_SAFE_FREE(tls->face_normals);
+ RecalcInnerNormalsTLSData *tls = tls_v;
+ MEM_SAFE_FREE(tls->face_normals);
}
/* Recalculate normals which corresponds to non-boundaries elements of grids. */
static void subdiv_ccg_recalc_inner_grid_normals(SubdivCCG *subdiv_ccg)
{
- CCGKey key;
- BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
- RecalcInnerNormalsData data = {
- .subdiv_ccg = subdiv_ccg,
- .key = &key,
- };
- RecalcInnerNormalsTLSData tls_data = {NULL};
- ParallelRangeSettings parallel_range_settings;
- BLI_parallel_range_settings_defaults(&parallel_range_settings);
- parallel_range_settings.userdata_chunk = &tls_data;
- parallel_range_settings.userdata_chunk_size = sizeof(tls_data);
- parallel_range_settings.func_finalize =
- subdiv_ccg_recalc_inner_normal_finalize;
- BLI_task_parallel_range(0, subdiv_ccg->num_grids,
- &data,
- subdiv_ccg_recalc_inner_normal_task,
- &parallel_range_settings);
+ CCGKey key;
+ BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
+ RecalcInnerNormalsData data = {
+ .subdiv_ccg = subdiv_ccg,
+ .key = &key,
+ };
+ RecalcInnerNormalsTLSData tls_data = {NULL};
+ ParallelRangeSettings parallel_range_settings;
+ BLI_parallel_range_settings_defaults(&parallel_range_settings);
+ parallel_range_settings.userdata_chunk = &tls_data;
+ parallel_range_settings.userdata_chunk_size = sizeof(tls_data);
+ parallel_range_settings.func_finalize = subdiv_ccg_recalc_inner_normal_finalize;
+ BLI_task_parallel_range(0,
+ subdiv_ccg->num_grids,
+ &data,
+ subdiv_ccg_recalc_inner_normal_task,
+ &parallel_range_settings);
}
void BKE_subdiv_ccg_recalc_normals(SubdivCCG *subdiv_ccg)
{
- if (!subdiv_ccg->has_normal) {
- /* Grids don't have normals, can do early output. */
- return;
- }
- subdiv_ccg_recalc_inner_grid_normals(subdiv_ccg);
- BKE_subdiv_ccg_average_grids(subdiv_ccg);
+ if (!subdiv_ccg->has_normal) {
+ /* Grids don't have normals, can do early output. */
+ return;
+ }
+ subdiv_ccg_recalc_inner_grid_normals(subdiv_ccg);
+ BKE_subdiv_ccg_average_grids(subdiv_ccg);
}
typedef struct RecalcModifiedInnerNormalsData {
- SubdivCCG *subdiv_ccg;
- CCGKey *key;
- SubdivCCGFace **effected_ccg_faces;
+ SubdivCCG *subdiv_ccg;
+ CCGKey *key;
+ SubdivCCGFace **effected_ccg_faces;
} RecalcModifiedInnerNormalsData;
-static void subdiv_ccg_recalc_modified_inner_normal_task(
- void *__restrict userdata_v,
- const int face_index,
- const ParallelRangeTLS *__restrict tls_v)
+static void subdiv_ccg_recalc_modified_inner_normal_task(void *__restrict userdata_v,
+ const int face_index,
+ const ParallelRangeTLS *__restrict tls_v)
{
- RecalcModifiedInnerNormalsData *data = userdata_v;
- SubdivCCG *subdiv_ccg = data->subdiv_ccg;
- CCGKey *key = data->key;
- RecalcInnerNormalsTLSData *tls = tls_v->userdata_chunk;
- SubdivCCGFace **faces = data->effected_ccg_faces;
- SubdivCCGFace *face = faces[face_index];
- const int num_face_grids = face->num_grids;
- for (int i = 0; i < num_face_grids; i++) {
- const int grid_index = face->start_grid_index + i;
- subdiv_ccg_recalc_inner_face_normals(
- data->subdiv_ccg, data->key, tls, grid_index);
- subdiv_ccg_average_inner_face_normals(
- data->subdiv_ccg, data->key, tls, grid_index);
- }
- subdiv_ccg_average_inner_face_grids(subdiv_ccg, key, face);
+ RecalcModifiedInnerNormalsData *data = userdata_v;
+ SubdivCCG *subdiv_ccg = data->subdiv_ccg;
+ CCGKey *key = data->key;
+ RecalcInnerNormalsTLSData *tls = tls_v->userdata_chunk;
+ SubdivCCGFace **faces = data->effected_ccg_faces;
+ SubdivCCGFace *face = faces[face_index];
+ const int num_face_grids = face->num_grids;
+ for (int i = 0; i < num_face_grids; i++) {
+ const int grid_index = face->start_grid_index + i;
+ subdiv_ccg_recalc_inner_face_normals(data->subdiv_ccg, data->key, tls, grid_index);
+ subdiv_ccg_average_inner_face_normals(data->subdiv_ccg, data->key, tls, grid_index);
+ }
+ subdiv_ccg_average_inner_face_grids(subdiv_ccg, key, face);
}
-static void subdiv_ccg_recalc_modified_inner_normal_finalize(
- void *__restrict UNUSED(userdata),
- void *__restrict tls_v)
+static void subdiv_ccg_recalc_modified_inner_normal_finalize(void *__restrict UNUSED(userdata),
+ void *__restrict tls_v)
{
- RecalcInnerNormalsTLSData *tls = tls_v;
- MEM_SAFE_FREE(tls->face_normals);
+ RecalcInnerNormalsTLSData *tls = tls_v;
+ MEM_SAFE_FREE(tls->face_normals);
}
-static void subdiv_ccg_recalc_modified_inner_grid_normals(
- SubdivCCG *subdiv_ccg,
- struct CCGFace **effected_faces,
- int num_effected_faces)
+static void subdiv_ccg_recalc_modified_inner_grid_normals(SubdivCCG *subdiv_ccg,
+ struct CCGFace **effected_faces,
+ int num_effected_faces)
{
- CCGKey key;
- BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
- RecalcModifiedInnerNormalsData data = {
- .subdiv_ccg = subdiv_ccg,
- .key = &key,
- .effected_ccg_faces = (SubdivCCGFace **)effected_faces,
- };
- RecalcInnerNormalsTLSData tls_data = {NULL};
- ParallelRangeSettings parallel_range_settings;
- BLI_parallel_range_settings_defaults(&parallel_range_settings);
- parallel_range_settings.userdata_chunk = &tls_data;
- parallel_range_settings.userdata_chunk_size = sizeof(tls_data);
- parallel_range_settings.func_finalize =
- subdiv_ccg_recalc_modified_inner_normal_finalize;
- BLI_task_parallel_range(0, num_effected_faces,
- &data,
- subdiv_ccg_recalc_modified_inner_normal_task,
- &parallel_range_settings);
+ CCGKey key;
+ BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
+ RecalcModifiedInnerNormalsData data = {
+ .subdiv_ccg = subdiv_ccg,
+ .key = &key,
+ .effected_ccg_faces = (SubdivCCGFace **)effected_faces,
+ };
+ RecalcInnerNormalsTLSData tls_data = {NULL};
+ ParallelRangeSettings parallel_range_settings;
+ BLI_parallel_range_settings_defaults(&parallel_range_settings);
+ parallel_range_settings.userdata_chunk = &tls_data;
+ parallel_range_settings.userdata_chunk_size = sizeof(tls_data);
+ parallel_range_settings.func_finalize = subdiv_ccg_recalc_modified_inner_normal_finalize;
+ BLI_task_parallel_range(0,
+ num_effected_faces,
+ &data,
+ subdiv_ccg_recalc_modified_inner_normal_task,
+ &parallel_range_settings);
}
void BKE_subdiv_ccg_update_normals(SubdivCCG *subdiv_ccg,
struct CCGFace **effected_faces,
int num_effected_faces)
{
- if (!subdiv_ccg->has_normal) {
- /* Grids don't have normals, can do early output. */
- return;
- }
- if (num_effected_faces == 0) {
- /* No faces changed, so nothing to do here. */
- return;
- }
- subdiv_ccg_recalc_modified_inner_grid_normals(
- subdiv_ccg, effected_faces, num_effected_faces);
- /* TODO(sergey): Only average elements which are adjacent to modified
- * faces. */
- CCGKey key;
- BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
- subdiv_ccg_average_all_boundaries_and_corners(subdiv_ccg, &key);
+ if (!subdiv_ccg->has_normal) {
+ /* Grids don't have normals, can do early output. */
+ return;
+ }
+ if (num_effected_faces == 0) {
+ /* No faces changed, so nothing to do here. */
+ return;
+ }
+ subdiv_ccg_recalc_modified_inner_grid_normals(subdiv_ccg, effected_faces, num_effected_faces);
+ /* TODO(sergey): Only average elements which are adjacent to modified
+ * faces. */
+ CCGKey key;
+ BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
+ subdiv_ccg_average_all_boundaries_and_corners(subdiv_ccg, &key);
}
/* =============================================================================
@@ -976,15 +875,15 @@ void BKE_subdiv_ccg_update_normals(SubdivCCG *subdiv_ccg,
*/
typedef struct AverageInnerGridsData {
- SubdivCCG *subdiv_ccg;
- CCGKey *key;
+ SubdivCCG *subdiv_ccg;
+ CCGKey *key;
} AverageInnerGridsData;
static void average_grid_element_value_v3(float a[3], float b[3])
{
- add_v3_v3(a, b);
- mul_v3_fl(a, 0.5f);
- copy_v3_v3(b, a);
+ add_v3_v3(a, b);
+ mul_v3_fl(a, 0.5f);
+ copy_v3_v3(b, a);
}
static void average_grid_element(SubdivCCG *subdiv_ccg,
@@ -992,33 +891,32 @@ static void average_grid_element(SubdivCCG *subdiv_ccg,
CCGElem *grid_element_a,
CCGElem *grid_element_b)
{
- average_grid_element_value_v3(CCG_elem_co(key, grid_element_a),
- CCG_elem_co(key, grid_element_b));
- if (subdiv_ccg->has_normal) {
- average_grid_element_value_v3(CCG_elem_no(key, grid_element_a),
- CCG_elem_no(key, grid_element_b));
- }
- if (subdiv_ccg->has_mask) {
- float mask =
- (*CCG_elem_mask(key, grid_element_a) +
- *CCG_elem_mask(key, grid_element_b)) * 0.5f;
- *CCG_elem_mask(key, grid_element_a) = mask;
- *CCG_elem_mask(key, grid_element_b) = mask;
- }
+ average_grid_element_value_v3(CCG_elem_co(key, grid_element_a),
+ CCG_elem_co(key, grid_element_b));
+ if (subdiv_ccg->has_normal) {
+ average_grid_element_value_v3(CCG_elem_no(key, grid_element_a),
+ CCG_elem_no(key, grid_element_b));
+ }
+ if (subdiv_ccg->has_mask) {
+ float mask = (*CCG_elem_mask(key, grid_element_a) + *CCG_elem_mask(key, grid_element_b)) *
+ 0.5f;
+ *CCG_elem_mask(key, grid_element_a) = mask;
+ *CCG_elem_mask(key, grid_element_b) = mask;
+ }
}
/* Accumulator to hold data during averaging. */
typedef struct GridElementAccumulator {
- float co[3];
- float no[3];
- float mask;
+ float co[3];
+ float no[3];
+ float mask;
} GridElementAccumulator;
static void element_accumulator_init(GridElementAccumulator *accumulator)
{
- zero_v3(accumulator->co);
- zero_v3(accumulator->no);
- accumulator->mask = 0.0f;
+ zero_v3(accumulator->co);
+ zero_v3(accumulator->no);
+ accumulator->mask = 0.0f;
}
static void element_accumulator_add(GridElementAccumulator *accumulator,
@@ -1026,21 +924,20 @@ static void element_accumulator_add(GridElementAccumulator *accumulator,
CCGKey *key,
/*const*/ CCGElem *grid_element)
{
- add_v3_v3(accumulator->co, CCG_elem_co(key, grid_element));
- if (subdiv_ccg->has_normal) {
- add_v3_v3(accumulator->no, CCG_elem_no(key, grid_element));
- }
- if (subdiv_ccg->has_mask) {
- accumulator->mask += *CCG_elem_mask(key, grid_element);
- }
+ add_v3_v3(accumulator->co, CCG_elem_co(key, grid_element));
+ if (subdiv_ccg->has_normal) {
+ add_v3_v3(accumulator->no, CCG_elem_no(key, grid_element));
+ }
+ if (subdiv_ccg->has_mask) {
+ accumulator->mask += *CCG_elem_mask(key, grid_element);
+ }
}
-static void element_accumulator_mul_fl(GridElementAccumulator *accumulator,
- const float f)
+static void element_accumulator_mul_fl(GridElementAccumulator *accumulator, const float f)
{
- mul_v3_fl(accumulator->co, f);
- mul_v3_fl(accumulator->no, f);
- accumulator->mask *= f;
+ mul_v3_fl(accumulator->co, f);
+ mul_v3_fl(accumulator->no, f);
+ accumulator->mask *= f;
}
static void element_accumulator_copy(SubdivCCG *subdiv_ccg,
@@ -1048,285 +945,266 @@ static void element_accumulator_copy(SubdivCCG *subdiv_ccg,
CCGElem *destination,
const GridElementAccumulator *accumulator)
{
- copy_v3_v3(CCG_elem_co(key, destination), accumulator->co);
- if (subdiv_ccg->has_normal) {
- copy_v3_v3(CCG_elem_no(key, destination), accumulator->no);
- }
- if (subdiv_ccg->has_mask) {
- *CCG_elem_mask(key, destination) = accumulator->mask;
- }
+ copy_v3_v3(CCG_elem_co(key, destination), accumulator->co);
+ if (subdiv_ccg->has_normal) {
+ copy_v3_v3(CCG_elem_no(key, destination), accumulator->no);
+ }
+ if (subdiv_ccg->has_mask) {
+ *CCG_elem_mask(key, destination) = accumulator->mask;
+ }
}
-static void subdiv_ccg_average_inner_face_grids(
- SubdivCCG *subdiv_ccg,
- CCGKey *key,
- SubdivCCGFace *face)
+static void subdiv_ccg_average_inner_face_grids(SubdivCCG *subdiv_ccg,
+ CCGKey *key,
+ SubdivCCGFace *face)
{
- CCGElem **grids = subdiv_ccg->grids;
- const int num_face_grids = face->num_grids;
- const int grid_size = subdiv_ccg->grid_size;
- CCGElem *prev_grid = grids[face->start_grid_index + num_face_grids - 1];
- for (int corner = 0; corner < num_face_grids; corner++) {
- CCGElem *grid = grids[face->start_grid_index + corner];
- for (int i = 0; i < grid_size; i++) {
- CCGElem *prev_grid_element = CCG_grid_elem(key, prev_grid, i, 0);
- CCGElem *grid_element = CCG_grid_elem(key, grid, 0, i);
- average_grid_element(
- subdiv_ccg, key, prev_grid_element, grid_element);
- }
- prev_grid = grid;
- }
-
+ CCGElem **grids = subdiv_ccg->grids;
+ const int num_face_grids = face->num_grids;
+ const int grid_size = subdiv_ccg->grid_size;
+ CCGElem *prev_grid = grids[face->start_grid_index + num_face_grids - 1];
+ for (int corner = 0; corner < num_face_grids; corner++) {
+ CCGElem *grid = grids[face->start_grid_index + corner];
+ for (int i = 0; i < grid_size; i++) {
+ CCGElem *prev_grid_element = CCG_grid_elem(key, prev_grid, i, 0);
+ CCGElem *grid_element = CCG_grid_elem(key, grid, 0, i);
+ average_grid_element(subdiv_ccg, key, prev_grid_element, grid_element);
+ }
+ prev_grid = grid;
+ }
}
-static void subdiv_ccg_average_inner_grids_task(
- void *__restrict userdata_v,
- const int face_index,
- const ParallelRangeTLS *__restrict UNUSED(tls_v))
+static void subdiv_ccg_average_inner_grids_task(void *__restrict userdata_v,
+ const int face_index,
+ const ParallelRangeTLS *__restrict UNUSED(tls_v))
{
- AverageInnerGridsData *data = userdata_v;
- SubdivCCG *subdiv_ccg = data->subdiv_ccg;
- CCGKey *key = data->key;
- SubdivCCGFace *faces = subdiv_ccg->faces;
- SubdivCCGFace *face = &faces[face_index];
- subdiv_ccg_average_inner_face_grids(subdiv_ccg, key, face);
+ AverageInnerGridsData *data = userdata_v;
+ SubdivCCG *subdiv_ccg = data->subdiv_ccg;
+ CCGKey *key = data->key;
+ SubdivCCGFace *faces = subdiv_ccg->faces;
+ SubdivCCGFace *face = &faces[face_index];
+ subdiv_ccg_average_inner_face_grids(subdiv_ccg, key, face);
}
typedef struct AverageGridsBoundariesData {
- SubdivCCG *subdiv_ccg;
- CCGKey *key;
+ SubdivCCG *subdiv_ccg;
+ CCGKey *key;
} AverageGridsBoundariesData;
typedef struct AverageGridsBoundariesTLSData {
- GridElementAccumulator *accumulators;
+ GridElementAccumulator *accumulators;
} AverageGridsBoundariesTLSData;
-static void subdiv_ccg_average_grids_boundary(
- SubdivCCG *subdiv_ccg,
- CCGKey *key,
- SubdivCCGAdjacentEdge *adjacent_edge,
- AverageGridsBoundariesTLSData *tls)
+static void subdiv_ccg_average_grids_boundary(SubdivCCG *subdiv_ccg,
+ CCGKey *key,
+ SubdivCCGAdjacentEdge *adjacent_edge,
+ AverageGridsBoundariesTLSData *tls)
{
- const int num_adjacent_faces = adjacent_edge->num_adjacent_faces;
- const int grid_size2 = subdiv_ccg->grid_size * 2;
- if (num_adjacent_faces == 1) {
- /* Nothing to average with. */
- return;
- }
- if (tls->accumulators == NULL) {
- tls->accumulators = MEM_calloc_arrayN(sizeof(GridElementAccumulator),
- grid_size2,
- "average accumulators");
- }
- else {
- for (int i = 1; i < grid_size2 - 1; i++) {
- element_accumulator_init(&tls->accumulators[i]);
- }
- }
- for (int face_index = 0; face_index < num_adjacent_faces; face_index++) {
- for (int i = 1; i < grid_size2 - 1; i++) {
- CCGElem *grid_element =
- adjacent_edge->boundary_elements[face_index][i];
- element_accumulator_add(
- &tls->accumulators[i], subdiv_ccg, key, grid_element);
- }
- }
- for (int i = 1; i < grid_size2 -1; i++) {
- element_accumulator_mul_fl(
- &tls->accumulators[i], 1.0f / (float)num_adjacent_faces);
- }
- /* Copy averaged value to all the other faces. */
- for (int face_index = 0; face_index < num_adjacent_faces; face_index++) {
- for (int i = 1; i < grid_size2 - 1; i++) {
- CCGElem *grid_element =
- adjacent_edge->boundary_elements[face_index][i];
- element_accumulator_copy(
- subdiv_ccg, key, grid_element, &tls->accumulators[i]);
- }
- }
+ const int num_adjacent_faces = adjacent_edge->num_adjacent_faces;
+ const int grid_size2 = subdiv_ccg->grid_size * 2;
+ if (num_adjacent_faces == 1) {
+ /* Nothing to average with. */
+ return;
+ }
+ if (tls->accumulators == NULL) {
+ tls->accumulators = MEM_calloc_arrayN(
+ sizeof(GridElementAccumulator), grid_size2, "average accumulators");
+ }
+ else {
+ for (int i = 1; i < grid_size2 - 1; i++) {
+ element_accumulator_init(&tls->accumulators[i]);
+ }
+ }
+ for (int face_index = 0; face_index < num_adjacent_faces; face_index++) {
+ for (int i = 1; i < grid_size2 - 1; i++) {
+ CCGElem *grid_element = adjacent_edge->boundary_elements[face_index][i];
+ element_accumulator_add(&tls->accumulators[i], subdiv_ccg, key, grid_element);
+ }
+ }
+ for (int i = 1; i < grid_size2 - 1; i++) {
+ element_accumulator_mul_fl(&tls->accumulators[i], 1.0f / (float)num_adjacent_faces);
+ }
+ /* Copy averaged value to all the other faces. */
+ for (int face_index = 0; face_index < num_adjacent_faces; face_index++) {
+ for (int i = 1; i < grid_size2 - 1; i++) {
+ CCGElem *grid_element = adjacent_edge->boundary_elements[face_index][i];
+ element_accumulator_copy(subdiv_ccg, key, grid_element, &tls->accumulators[i]);
+ }
+ }
}
-static void subdiv_ccg_average_grids_boundaries_task(
- void *__restrict userdata_v,
- const int adjacent_edge_index,
- const ParallelRangeTLS *__restrict tls_v)
+static void subdiv_ccg_average_grids_boundaries_task(void *__restrict userdata_v,
+ const int adjacent_edge_index,
+ const ParallelRangeTLS *__restrict tls_v)
{
- AverageGridsBoundariesData *data = userdata_v;
- AverageGridsBoundariesTLSData *tls = tls_v->userdata_chunk;
- SubdivCCG *subdiv_ccg = data->subdiv_ccg;
- CCGKey *key = data->key;
- SubdivCCGAdjacentEdge *adjacent_edge =
- &subdiv_ccg->adjacent_edges[adjacent_edge_index];
- subdiv_ccg_average_grids_boundary(subdiv_ccg, key, adjacent_edge, tls);
+ AverageGridsBoundariesData *data = userdata_v;
+ AverageGridsBoundariesTLSData *tls = tls_v->userdata_chunk;
+ SubdivCCG *subdiv_ccg = data->subdiv_ccg;
+ CCGKey *key = data->key;
+ SubdivCCGAdjacentEdge *adjacent_edge = &subdiv_ccg->adjacent_edges[adjacent_edge_index];
+ subdiv_ccg_average_grids_boundary(subdiv_ccg, key, adjacent_edge, tls);
}
-static void subdiv_ccg_average_grids_boundaries_finalize(
- void *__restrict UNUSED(userdata),
- void *__restrict tls_v)
+static void subdiv_ccg_average_grids_boundaries_finalize(void *__restrict UNUSED(userdata),
+ void *__restrict tls_v)
{
- AverageGridsBoundariesTLSData *tls = tls_v;
- MEM_SAFE_FREE(tls->accumulators);
+ AverageGridsBoundariesTLSData *tls = tls_v;
+ MEM_SAFE_FREE(tls->accumulators);
}
typedef struct AverageGridsCornerData {
- SubdivCCG *subdiv_ccg;
- CCGKey *key;
+ SubdivCCG *subdiv_ccg;
+ CCGKey *key;
} AverageGridsCornerData;
-static void subdiv_ccg_average_grids_corners(
- SubdivCCG *subdiv_ccg,
- CCGKey *key,
- SubdivCCGAdjacentVertex *adjacent_vertex)
+static void subdiv_ccg_average_grids_corners(SubdivCCG *subdiv_ccg,
+ CCGKey *key,
+ SubdivCCGAdjacentVertex *adjacent_vertex)
{
- const int num_adjacent_faces = adjacent_vertex->num_adjacent_faces;
- if (num_adjacent_faces == 1) {
- /* Nothing to average with. */
- return;
- }
- GridElementAccumulator accumulator;
- element_accumulator_init(&accumulator);
- for (int face_index = 0; face_index < num_adjacent_faces; face_index++) {
- CCGElem *grid_element = adjacent_vertex->corner_elements[face_index];
- element_accumulator_add(&accumulator, subdiv_ccg, key, grid_element);
- }
- element_accumulator_mul_fl(&accumulator, 1.0f / (float)num_adjacent_faces);
- /* Copy averaged value to all the other faces. */
- for (int face_index = 0; face_index < num_adjacent_faces; face_index++) {
- CCGElem *grid_element = adjacent_vertex->corner_elements[face_index];
- element_accumulator_copy(subdiv_ccg, key, grid_element, &accumulator);
- }
+ const int num_adjacent_faces = adjacent_vertex->num_adjacent_faces;
+ if (num_adjacent_faces == 1) {
+ /* Nothing to average with. */
+ return;
+ }
+ GridElementAccumulator accumulator;
+ element_accumulator_init(&accumulator);
+ for (int face_index = 0; face_index < num_adjacent_faces; face_index++) {
+ CCGElem *grid_element = adjacent_vertex->corner_elements[face_index];
+ element_accumulator_add(&accumulator, subdiv_ccg, key, grid_element);
+ }
+ element_accumulator_mul_fl(&accumulator, 1.0f / (float)num_adjacent_faces);
+ /* Copy averaged value to all the other faces. */
+ for (int face_index = 0; face_index < num_adjacent_faces; face_index++) {
+ CCGElem *grid_element = adjacent_vertex->corner_elements[face_index];
+ element_accumulator_copy(subdiv_ccg, key, grid_element, &accumulator);
+ }
}
-static void subdiv_ccg_average_grids_corners_task(
- void *__restrict userdata_v,
- const int adjacent_vertex_index,
- const ParallelRangeTLS *__restrict UNUSED(tls_v))
+static void subdiv_ccg_average_grids_corners_task(void *__restrict userdata_v,
+ const int adjacent_vertex_index,
+ const ParallelRangeTLS *__restrict UNUSED(tls_v))
{
- AverageGridsCornerData *data = userdata_v;
- SubdivCCG *subdiv_ccg = data->subdiv_ccg;
- CCGKey *key = data->key;
- SubdivCCGAdjacentVertex *adjacent_vertex =
- &subdiv_ccg->adjacent_vertices[adjacent_vertex_index];
- subdiv_ccg_average_grids_corners(subdiv_ccg, key, adjacent_vertex);
+ AverageGridsCornerData *data = userdata_v;
+ SubdivCCG *subdiv_ccg = data->subdiv_ccg;
+ CCGKey *key = data->key;
+ SubdivCCGAdjacentVertex *adjacent_vertex = &subdiv_ccg->adjacent_vertices[adjacent_vertex_index];
+ subdiv_ccg_average_grids_corners(subdiv_ccg, key, adjacent_vertex);
}
-static void subdiv_ccg_average_all_boundaries(
- SubdivCCG *subdiv_ccg,
- CCGKey *key)
+static void subdiv_ccg_average_all_boundaries(SubdivCCG *subdiv_ccg, CCGKey *key)
{
- ParallelRangeSettings parallel_range_settings;
- BLI_parallel_range_settings_defaults(&parallel_range_settings);
- AverageGridsBoundariesData boundaries_data = {
- .subdiv_ccg = subdiv_ccg,
- .key = key,
- };
- AverageGridsBoundariesTLSData tls_data = {NULL};
- parallel_range_settings.userdata_chunk = &tls_data;
- parallel_range_settings.userdata_chunk_size = sizeof(tls_data);
- parallel_range_settings.func_finalize =
- subdiv_ccg_average_grids_boundaries_finalize;
- BLI_task_parallel_range(0, subdiv_ccg->num_adjacent_edges,
- &boundaries_data,
- subdiv_ccg_average_grids_boundaries_task,
- &parallel_range_settings);
+ ParallelRangeSettings parallel_range_settings;
+ BLI_parallel_range_settings_defaults(&parallel_range_settings);
+ AverageGridsBoundariesData boundaries_data = {
+ .subdiv_ccg = subdiv_ccg,
+ .key = key,
+ };
+ AverageGridsBoundariesTLSData tls_data = {NULL};
+ parallel_range_settings.userdata_chunk = &tls_data;
+ parallel_range_settings.userdata_chunk_size = sizeof(tls_data);
+ parallel_range_settings.func_finalize = subdiv_ccg_average_grids_boundaries_finalize;
+ BLI_task_parallel_range(0,
+ subdiv_ccg->num_adjacent_edges,
+ &boundaries_data,
+ subdiv_ccg_average_grids_boundaries_task,
+ &parallel_range_settings);
}
-static void subdiv_ccg_average_all_corners(
- SubdivCCG *subdiv_ccg,
- CCGKey *key)
+static void subdiv_ccg_average_all_corners(SubdivCCG *subdiv_ccg, CCGKey *key)
{
- ParallelRangeSettings parallel_range_settings;
- BLI_parallel_range_settings_defaults(&parallel_range_settings);
- AverageGridsCornerData corner_data = {
- .subdiv_ccg = subdiv_ccg,
- .key = key,
- };
- BLI_task_parallel_range(0, subdiv_ccg->num_adjacent_vertices,
- &corner_data,
- subdiv_ccg_average_grids_corners_task,
- &parallel_range_settings);
+ ParallelRangeSettings parallel_range_settings;
+ BLI_parallel_range_settings_defaults(&parallel_range_settings);
+ AverageGridsCornerData corner_data = {
+ .subdiv_ccg = subdiv_ccg,
+ .key = key,
+ };
+ BLI_task_parallel_range(0,
+ subdiv_ccg->num_adjacent_vertices,
+ &corner_data,
+ subdiv_ccg_average_grids_corners_task,
+ &parallel_range_settings);
}
-static void subdiv_ccg_average_all_boundaries_and_corners(
- SubdivCCG *subdiv_ccg,
- CCGKey *key)
+static void subdiv_ccg_average_all_boundaries_and_corners(SubdivCCG *subdiv_ccg, CCGKey *key)
{
- subdiv_ccg_average_all_boundaries(subdiv_ccg, key);
- subdiv_ccg_average_all_corners(subdiv_ccg, key);
+ subdiv_ccg_average_all_boundaries(subdiv_ccg, key);
+ subdiv_ccg_average_all_corners(subdiv_ccg, key);
}
void BKE_subdiv_ccg_average_grids(SubdivCCG *subdiv_ccg)
{
- CCGKey key;
- BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
- ParallelRangeSettings parallel_range_settings;
- BLI_parallel_range_settings_defaults(&parallel_range_settings);
- /* Average inner boundaries of grids (within one face), across faces
- * from different face-corners. */
- AverageInnerGridsData inner_data = {
- .subdiv_ccg = subdiv_ccg,
- .key = &key,
- };
- BLI_task_parallel_range(0, subdiv_ccg->num_faces,
- &inner_data,
- subdiv_ccg_average_inner_grids_task,
- &parallel_range_settings);
- subdiv_ccg_average_all_boundaries_and_corners(subdiv_ccg, &key);
+ CCGKey key;
+ BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
+ ParallelRangeSettings parallel_range_settings;
+ BLI_parallel_range_settings_defaults(&parallel_range_settings);
+ /* Average inner boundaries of grids (within one face), across faces
+ * from different face-corners. */
+ AverageInnerGridsData inner_data = {
+ .subdiv_ccg = subdiv_ccg,
+ .key = &key,
+ };
+ BLI_task_parallel_range(0,
+ subdiv_ccg->num_faces,
+ &inner_data,
+ subdiv_ccg_average_inner_grids_task,
+ &parallel_range_settings);
+ subdiv_ccg_average_all_boundaries_and_corners(subdiv_ccg, &key);
}
typedef struct StitchFacesInnerGridsData {
- SubdivCCG *subdiv_ccg;
- CCGKey *key;
- struct CCGFace **effected_ccg_faces;
+ SubdivCCG *subdiv_ccg;
+ CCGKey *key;
+ struct CCGFace **effected_ccg_faces;
} StitchFacesInnerGridsData;
static void subdiv_ccg_stitch_face_inner_grids_task(
- void *__restrict userdata_v,
- const int face_index,
- const ParallelRangeTLS *__restrict UNUSED(tls_v))
+ void *__restrict userdata_v,
+ const int face_index,
+ const ParallelRangeTLS *__restrict UNUSED(tls_v))
{
- StitchFacesInnerGridsData *data = userdata_v;
- SubdivCCG *subdiv_ccg = data->subdiv_ccg;
- CCGKey *key = data->key;
- struct CCGFace **effected_ccg_faces = data->effected_ccg_faces;
- struct CCGFace *effected_ccg_face = effected_ccg_faces[face_index];
- SubdivCCGFace *face = (SubdivCCGFace *)effected_ccg_face;
- subdiv_ccg_average_inner_face_grids(subdiv_ccg, key, face);
+ StitchFacesInnerGridsData *data = userdata_v;
+ SubdivCCG *subdiv_ccg = data->subdiv_ccg;
+ CCGKey *key = data->key;
+ struct CCGFace **effected_ccg_faces = data->effected_ccg_faces;
+ struct CCGFace *effected_ccg_face = effected_ccg_faces[face_index];
+ SubdivCCGFace *face = (SubdivCCGFace *)effected_ccg_face;
+ subdiv_ccg_average_inner_face_grids(subdiv_ccg, key, face);
}
void BKE_subdiv_ccg_average_stitch_faces(SubdivCCG *subdiv_ccg,
struct CCGFace **effected_faces,
int num_effected_faces)
{
- CCGKey key;
- BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
- StitchFacesInnerGridsData data = {
- .subdiv_ccg = subdiv_ccg,
- .key = &key,
- .effected_ccg_faces = effected_faces,
- };
- ParallelRangeSettings parallel_range_settings;
- BLI_parallel_range_settings_defaults(&parallel_range_settings);
- BLI_task_parallel_range(0, num_effected_faces,
- &data,
- subdiv_ccg_stitch_face_inner_grids_task,
- &parallel_range_settings);
- /* TODO(sergey): Only average elements which are adjacent to modified
- * faces. */
- subdiv_ccg_average_all_boundaries_and_corners(subdiv_ccg, &key);
+ CCGKey key;
+ BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
+ StitchFacesInnerGridsData data = {
+ .subdiv_ccg = subdiv_ccg,
+ .key = &key,
+ .effected_ccg_faces = effected_faces,
+ };
+ ParallelRangeSettings parallel_range_settings;
+ BLI_parallel_range_settings_defaults(&parallel_range_settings);
+ BLI_task_parallel_range(0,
+ num_effected_faces,
+ &data,
+ subdiv_ccg_stitch_face_inner_grids_task,
+ &parallel_range_settings);
+ /* TODO(sergey): Only average elements which are adjacent to modified
+ * faces. */
+ subdiv_ccg_average_all_boundaries_and_corners(subdiv_ccg, &key);
}
-void BKE_subdiv_ccg_topology_counters(
- const SubdivCCG *subdiv_ccg,
- int *r_num_vertices, int *r_num_edges,
- int *r_num_faces, int *r_num_loops)
+void BKE_subdiv_ccg_topology_counters(const SubdivCCG *subdiv_ccg,
+ int *r_num_vertices,
+ int *r_num_edges,
+ int *r_num_faces,
+ int *r_num_loops)
{
- const int num_grids = subdiv_ccg->num_grids;
- const int grid_size = subdiv_ccg->grid_size;
- const int grid_area = grid_size * grid_size;
- const int num_edges_per_grid = 2 * (grid_size * (grid_size - 1));
- *r_num_vertices = num_grids * grid_area;
- *r_num_edges = num_grids * num_edges_per_grid;
- *r_num_faces = num_grids * (grid_size - 1) * (grid_size - 1);
- *r_num_loops = *r_num_faces * 4;
+ const int num_grids = subdiv_ccg->num_grids;
+ const int grid_size = subdiv_ccg->grid_size;
+ const int grid_area = grid_size * grid_size;
+ const int num_edges_per_grid = 2 * (grid_size * (grid_size - 1));
+ *r_num_vertices = num_grids * grid_area;
+ *r_num_edges = num_grids * num_edges_per_grid;
+ *r_num_faces = num_grids * (grid_size - 1) * (grid_size - 1);
+ *r_num_loops = *r_num_faces * 4;
}
diff --git a/source/blender/blenkernel/intern/subdiv_ccg_mask.c b/source/blender/blenkernel/intern/subdiv_ccg_mask.c
index ec9dfd30f16..0c02303dc2f 100644
--- a/source/blender/blenkernel/intern/subdiv_ccg_mask.c
+++ b/source/blender/blenkernel/intern/subdiv_ccg_mask.c
@@ -36,80 +36,78 @@
#include "MEM_guardedalloc.h"
typedef struct PolyCornerIndex {
- int poly_index;
- int corner;
+ int poly_index;
+ int corner;
} PolyCornerIndex;
typedef struct GridPaintMaskData {
- // int grid_size;
- const MPoly *mpoly;
- const GridPaintMask *grid_paint_mask;
- /* Indexed by ptex face index, contains polygon/corner which corresponds
- * to it.
- *
- * NOTE: For quad polygon this is an index of first corner only, since
- * there we only have one ptex.
- */
- PolyCornerIndex *ptex_poly_corner;
+ // int grid_size;
+ const MPoly *mpoly;
+ const GridPaintMask *grid_paint_mask;
+ /* Indexed by ptex face index, contains polygon/corner which corresponds
+ * to it.
+ *
+ * NOTE: For quad polygon this is an index of first corner only, since
+ * there we only have one ptex.
+ */
+ PolyCornerIndex *ptex_poly_corner;
} GridPaintMaskData;
-static int mask_get_grid_and_coord(
- SubdivCCGMaskEvaluator *mask_evaluator,
- const int ptex_face_index, const float u, const float v,
- const GridPaintMask **r_mask_grid,
- float *grid_u, float *grid_v)
+static int mask_get_grid_and_coord(SubdivCCGMaskEvaluator *mask_evaluator,
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ const GridPaintMask **r_mask_grid,
+ float *grid_u,
+ float *grid_v)
{
- GridPaintMaskData *data = mask_evaluator->user_data;
- const PolyCornerIndex *poly_corner =
- &data->ptex_poly_corner[ptex_face_index];
- const MPoly *poly = &data->mpoly[poly_corner->poly_index];
- const int start_grid_index = poly->loopstart + poly_corner->corner;
- int corner = 0;
- if (poly->totloop == 4) {
- float corner_u, corner_v;
- corner = BKE_subdiv_rotate_quad_to_corner(u, v, &corner_u, &corner_v);
- *r_mask_grid =
- &data->grid_paint_mask[start_grid_index + corner];
- BKE_subdiv_ptex_face_uv_to_grid_uv(corner_u, corner_v, grid_u, grid_v);
- }
- else {
- *r_mask_grid =
- &data->grid_paint_mask[start_grid_index];
- BKE_subdiv_ptex_face_uv_to_grid_uv(u, v, grid_u, grid_v);
- }
- return corner;
+ GridPaintMaskData *data = mask_evaluator->user_data;
+ const PolyCornerIndex *poly_corner = &data->ptex_poly_corner[ptex_face_index];
+ const MPoly *poly = &data->mpoly[poly_corner->poly_index];
+ const int start_grid_index = poly->loopstart + poly_corner->corner;
+ int corner = 0;
+ if (poly->totloop == 4) {
+ float corner_u, corner_v;
+ corner = BKE_subdiv_rotate_quad_to_corner(u, v, &corner_u, &corner_v);
+ *r_mask_grid = &data->grid_paint_mask[start_grid_index + corner];
+ BKE_subdiv_ptex_face_uv_to_grid_uv(corner_u, corner_v, grid_u, grid_v);
+ }
+ else {
+ *r_mask_grid = &data->grid_paint_mask[start_grid_index];
+ BKE_subdiv_ptex_face_uv_to_grid_uv(u, v, grid_u, grid_v);
+ }
+ return corner;
}
BLI_INLINE float read_mask_grid(const GridPaintMask *mask_grid,
- const float grid_u, const float grid_v)
+ const float grid_u,
+ const float grid_v)
{
- if (mask_grid->data == NULL) {
- return 0;
- }
- const int grid_size = BKE_subdiv_grid_size_from_level(mask_grid->level);
- const int x = (grid_u * (grid_size - 1) + 0.5f);
- const int y = (grid_v * (grid_size - 1) + 0.5f);
- return mask_grid->data[y * grid_size + x];
+ if (mask_grid->data == NULL) {
+ return 0;
+ }
+ const int grid_size = BKE_subdiv_grid_size_from_level(mask_grid->level);
+ const int x = (grid_u * (grid_size - 1) + 0.5f);
+ const int y = (grid_v * (grid_size - 1) + 0.5f);
+ return mask_grid->data[y * grid_size + x];
}
static float eval_mask(SubdivCCGMaskEvaluator *mask_evaluator,
const int ptex_face_index,
- const float u, const float v)
+ const float u,
+ const float v)
{
- const GridPaintMask *mask_grid;
- float grid_u, grid_v;
- mask_get_grid_and_coord(mask_evaluator,
- ptex_face_index, u, v,
- &mask_grid,
- &grid_u, &grid_v);
- return read_mask_grid(mask_grid, grid_u, grid_v);
+ const GridPaintMask *mask_grid;
+ float grid_u, grid_v;
+ mask_get_grid_and_coord(mask_evaluator, ptex_face_index, u, v, &mask_grid, &grid_u, &grid_v);
+ return read_mask_grid(mask_grid, grid_u, grid_v);
}
static void free_mask_data(SubdivCCGMaskEvaluator *mask_evaluator)
{
- GridPaintMaskData *data = mask_evaluator->user_data;
- MEM_freeN(data->ptex_poly_corner);
- MEM_freeN(data);
+ GridPaintMaskData *data = mask_evaluator->user_data;
+ MEM_freeN(data->ptex_poly_corner);
+ MEM_freeN(data);
}
/* TODO(sergey): This seems to be generally used information, which almost
@@ -117,74 +115,67 @@ static void free_mask_data(SubdivCCGMaskEvaluator *mask_evaluator)
*/
static int count_num_ptex_faces(const Mesh *mesh)
{
- int num_ptex_faces = 0;
- const MPoly *mpoly = mesh->mpoly;
- for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) {
- const MPoly *poly = &mpoly[poly_index];
- num_ptex_faces += (poly->totloop == 4) ? 1 : poly->totloop;
- }
- return num_ptex_faces;
+ int num_ptex_faces = 0;
+ const MPoly *mpoly = mesh->mpoly;
+ for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) {
+ const MPoly *poly = &mpoly[poly_index];
+ num_ptex_faces += (poly->totloop == 4) ? 1 : poly->totloop;
+ }
+ return num_ptex_faces;
}
-static void mask_data_init_mapping(SubdivCCGMaskEvaluator *mask_evaluator,
- const Mesh *mesh)
+static void mask_data_init_mapping(SubdivCCGMaskEvaluator *mask_evaluator, const Mesh *mesh)
{
- GridPaintMaskData *data = mask_evaluator->user_data;
- const MPoly *mpoly = mesh->mpoly;
- const int num_ptex_faces = count_num_ptex_faces(mesh);
- /* Allocate memory. */
- data->ptex_poly_corner = MEM_malloc_arrayN(num_ptex_faces,
- sizeof(*data->ptex_poly_corner),
- "ptex poly corner");
- /* Fill in offsets. */
- int ptex_face_index = 0;
- PolyCornerIndex *ptex_poly_corner = data->ptex_poly_corner;
- for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) {
- const MPoly *poly = &mpoly[poly_index];
- if (poly->totloop == 4) {
- ptex_poly_corner[ptex_face_index].poly_index = poly_index;
- ptex_poly_corner[ptex_face_index].corner = 0;
- ptex_face_index++;
- }
- else {
- for (int corner = 0; corner < poly->totloop; corner++) {
- ptex_poly_corner[ptex_face_index].poly_index = poly_index;
- ptex_poly_corner[ptex_face_index].corner = corner;
- ptex_face_index++;
- }
- }
- }
+ GridPaintMaskData *data = mask_evaluator->user_data;
+ const MPoly *mpoly = mesh->mpoly;
+ const int num_ptex_faces = count_num_ptex_faces(mesh);
+ /* Allocate memory. */
+ data->ptex_poly_corner = MEM_malloc_arrayN(
+ num_ptex_faces, sizeof(*data->ptex_poly_corner), "ptex poly corner");
+ /* Fill in offsets. */
+ int ptex_face_index = 0;
+ PolyCornerIndex *ptex_poly_corner = data->ptex_poly_corner;
+ for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) {
+ const MPoly *poly = &mpoly[poly_index];
+ if (poly->totloop == 4) {
+ ptex_poly_corner[ptex_face_index].poly_index = poly_index;
+ ptex_poly_corner[ptex_face_index].corner = 0;
+ ptex_face_index++;
+ }
+ else {
+ for (int corner = 0; corner < poly->totloop; corner++) {
+ ptex_poly_corner[ptex_face_index].poly_index = poly_index;
+ ptex_poly_corner[ptex_face_index].corner = corner;
+ ptex_face_index++;
+ }
+ }
+ }
}
-static void mask_init_data(SubdivCCGMaskEvaluator *mask_evaluator,
- const Mesh *mesh)
+static void mask_init_data(SubdivCCGMaskEvaluator *mask_evaluator, const Mesh *mesh)
{
- GridPaintMaskData *data = mask_evaluator->user_data;
- data->mpoly = mesh->mpoly;
- data->grid_paint_mask =
- CustomData_get_layer(&mesh->ldata, CD_GRID_PAINT_MASK);
- mask_data_init_mapping(mask_evaluator, mesh);
+ GridPaintMaskData *data = mask_evaluator->user_data;
+ data->mpoly = mesh->mpoly;
+ data->grid_paint_mask = CustomData_get_layer(&mesh->ldata, CD_GRID_PAINT_MASK);
+ mask_data_init_mapping(mask_evaluator, mesh);
}
static void mask_init_functions(SubdivCCGMaskEvaluator *mask_evaluator)
{
- mask_evaluator->eval_mask = eval_mask;
- mask_evaluator->free = free_mask_data;
+ mask_evaluator->eval_mask = eval_mask;
+ mask_evaluator->free = free_mask_data;
}
-bool BKE_subdiv_ccg_mask_init_from_paint(
- SubdivCCGMaskEvaluator *mask_evaluator,
- const struct Mesh *mesh)
+bool BKE_subdiv_ccg_mask_init_from_paint(SubdivCCGMaskEvaluator *mask_evaluator,
+ const struct Mesh *mesh)
{
- GridPaintMask *grid_paint_mask =
- CustomData_get_layer(&mesh->ldata, CD_GRID_PAINT_MASK);
- if (grid_paint_mask == NULL) {
- return false;
- }
- /* Allocate all required memory. */
- mask_evaluator->user_data = MEM_callocN(sizeof(GridPaintMaskData),
- "mask from grid data");
- mask_init_data(mask_evaluator, mesh);
- mask_init_functions(mask_evaluator);
- return true;
+ GridPaintMask *grid_paint_mask = CustomData_get_layer(&mesh->ldata, CD_GRID_PAINT_MASK);
+ if (grid_paint_mask == NULL) {
+ return false;
+ }
+ /* Allocate all required memory. */
+ mask_evaluator->user_data = MEM_callocN(sizeof(GridPaintMaskData), "mask from grid data");
+ mask_init_data(mask_evaluator, mesh);
+ mask_init_functions(mask_evaluator);
+ return true;
}
diff --git a/source/blender/blenkernel/intern/subdiv_ccg_material.c b/source/blender/blenkernel/intern/subdiv_ccg_material.c
index 1e086e00e25..9a81eb11989 100644
--- a/source/blender/blenkernel/intern/subdiv_ccg_material.c
+++ b/source/blender/blenkernel/intern/subdiv_ccg_material.c
@@ -28,40 +28,36 @@
#include "DNA_mesh_types.h"
typedef struct CCGMaterialFromMeshData {
- const Mesh *mesh;
+ const Mesh *mesh;
} CCGMaterialFromMeshData;
static DMFlagMat subdiv_ccg_material_flags_eval(
- SubdivCCGMaterialFlagsEvaluator *material_flags_evaluator,
- const int coarse_face_index)
+ SubdivCCGMaterialFlagsEvaluator *material_flags_evaluator, const int coarse_face_index)
{
- CCGMaterialFromMeshData *data =
- (CCGMaterialFromMeshData *)material_flags_evaluator->user_data;
- const Mesh *mesh = data->mesh;
- BLI_assert(coarse_face_index < mesh->totpoly);
- const MPoly *mpoly = mesh->mpoly;
- const MPoly *poly = &mpoly[coarse_face_index];
- DMFlagMat material_flags;
- material_flags.flag = poly->flag;
- material_flags.mat_nr = poly->mat_nr;
- return material_flags;
+ CCGMaterialFromMeshData *data = (CCGMaterialFromMeshData *)material_flags_evaluator->user_data;
+ const Mesh *mesh = data->mesh;
+ BLI_assert(coarse_face_index < mesh->totpoly);
+ const MPoly *mpoly = mesh->mpoly;
+ const MPoly *poly = &mpoly[coarse_face_index];
+ DMFlagMat material_flags;
+ material_flags.flag = poly->flag;
+ material_flags.mat_nr = poly->mat_nr;
+ return material_flags;
}
static void subdiv_ccg_material_flags_free(
- SubdivCCGMaterialFlagsEvaluator *material_flags_evaluator)
+ SubdivCCGMaterialFlagsEvaluator *material_flags_evaluator)
{
- MEM_freeN(material_flags_evaluator->user_data);
+ MEM_freeN(material_flags_evaluator->user_data);
}
void BKE_subdiv_ccg_material_flags_init_from_mesh(
- SubdivCCGMaterialFlagsEvaluator *material_flags_evaluator,
- const Mesh *mesh)
+ SubdivCCGMaterialFlagsEvaluator *material_flags_evaluator, const Mesh *mesh)
{
- CCGMaterialFromMeshData *data = MEM_mallocN(
- sizeof(CCGMaterialFromMeshData), "ccg material eval");
- data->mesh = mesh;
- material_flags_evaluator->eval_material_flags =
- subdiv_ccg_material_flags_eval;
- material_flags_evaluator->free = subdiv_ccg_material_flags_free;
- material_flags_evaluator->user_data = data;
+ CCGMaterialFromMeshData *data = MEM_mallocN(sizeof(CCGMaterialFromMeshData),
+ "ccg material eval");
+ data->mesh = mesh;
+ material_flags_evaluator->eval_material_flags = subdiv_ccg_material_flags_eval;
+ material_flags_evaluator->free = subdiv_ccg_material_flags_free;
+ material_flags_evaluator->user_data = data;
}
diff --git a/source/blender/blenkernel/intern/subdiv_converter.c b/source/blender/blenkernel/intern/subdiv_converter.c
index 7c9410fba72..d5c75503500 100644
--- a/source/blender/blenkernel/intern/subdiv_converter.c
+++ b/source/blender/blenkernel/intern/subdiv_converter.c
@@ -29,43 +29,42 @@
void BKE_subdiv_converter_free(struct OpenSubdiv_Converter *converter)
{
- if (converter->freeUserData) {
- converter->freeUserData(converter);
- }
+ if (converter->freeUserData) {
+ converter->freeUserData(converter);
+ }
}
-int BKE_subdiv_converter_vtx_boundary_interpolation_from_settings(
- const SubdivSettings *settings)
+int BKE_subdiv_converter_vtx_boundary_interpolation_from_settings(const SubdivSettings *settings)
{
- switch (settings->vtx_boundary_interpolation) {
- case SUBDIV_VTX_BOUNDARY_NONE:
- return OSD_VTX_BOUNDARY_NONE;
- case SUBDIV_VTX_BOUNDARY_EDGE_ONLY:
- return OSD_VTX_BOUNDARY_EDGE_ONLY;
- case SUBDIV_VTX_BOUNDARY_EDGE_AND_CORNER:
- return OSD_VTX_BOUNDARY_EDGE_AND_CORNER;
- }
- BLI_assert(!"Unknown vtx boundary interpolation");
- return OSD_VTX_BOUNDARY_EDGE_ONLY;
+ switch (settings->vtx_boundary_interpolation) {
+ case SUBDIV_VTX_BOUNDARY_NONE:
+ return OSD_VTX_BOUNDARY_NONE;
+ case SUBDIV_VTX_BOUNDARY_EDGE_ONLY:
+ return OSD_VTX_BOUNDARY_EDGE_ONLY;
+ case SUBDIV_VTX_BOUNDARY_EDGE_AND_CORNER:
+ return OSD_VTX_BOUNDARY_EDGE_AND_CORNER;
+ }
+ BLI_assert(!"Unknown vtx boundary interpolation");
+ return OSD_VTX_BOUNDARY_EDGE_ONLY;
}
-/*OpenSubdiv_FVarLinearInterpolation*/ int
-BKE_subdiv_converter_fvar_linear_from_settings(const SubdivSettings *settings)
+/*OpenSubdiv_FVarLinearInterpolation*/ int BKE_subdiv_converter_fvar_linear_from_settings(
+ const SubdivSettings *settings)
{
- switch (settings->fvar_linear_interpolation) {
- case SUBDIV_FVAR_LINEAR_INTERPOLATION_NONE:
- return OSD_FVAR_LINEAR_INTERPOLATION_NONE;
- case SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY:
- return OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY;
- case SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_AND_JUNCTIONS:
- return OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_PLUS1;
- case SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_JUNCTIONS_AND_CONCAVE:
- return OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_PLUS2;
- case SUBDIV_FVAR_LINEAR_INTERPOLATION_BOUNDARIES:
- return OSD_FVAR_LINEAR_INTERPOLATION_BOUNDARIES;
- case SUBDIV_FVAR_LINEAR_INTERPOLATION_ALL:
- return OSD_FVAR_LINEAR_INTERPOLATION_ALL;
- }
- BLI_assert(!"Unknown fvar linear interpolation");
- return OSD_FVAR_LINEAR_INTERPOLATION_NONE;
+ switch (settings->fvar_linear_interpolation) {
+ case SUBDIV_FVAR_LINEAR_INTERPOLATION_NONE:
+ return OSD_FVAR_LINEAR_INTERPOLATION_NONE;
+ case SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY:
+ return OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY;
+ case SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_AND_JUNCTIONS:
+ return OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_PLUS1;
+ case SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_JUNCTIONS_AND_CONCAVE:
+ return OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_PLUS2;
+ case SUBDIV_FVAR_LINEAR_INTERPOLATION_BOUNDARIES:
+ return OSD_FVAR_LINEAR_INTERPOLATION_BOUNDARIES;
+ case SUBDIV_FVAR_LINEAR_INTERPOLATION_ALL:
+ return OSD_FVAR_LINEAR_INTERPOLATION_ALL;
+ }
+ BLI_assert(!"Unknown fvar linear interpolation");
+ return OSD_FVAR_LINEAR_INTERPOLATION_NONE;
}
diff --git a/source/blender/blenkernel/intern/subdiv_converter.h b/source/blender/blenkernel/intern/subdiv_converter.h
index 2cf016659ca..fb0e84ade13 100644
--- a/source/blender/blenkernel/intern/subdiv_converter.h
+++ b/source/blender/blenkernel/intern/subdiv_converter.h
@@ -46,12 +46,10 @@ void BKE_subdiv_converter_free(struct OpenSubdiv_Converter *converter);
/* TODO(sergey): Find a way to make it OpenSubdiv_VtxBoundaryInterpolation,
* without breaking compilation without OpenSubdiv. */
-int BKE_subdiv_converter_vtx_boundary_interpolation_from_settings(
- const SubdivSettings *settings);
+int BKE_subdiv_converter_vtx_boundary_interpolation_from_settings(const SubdivSettings *settings);
/* TODO(sergey): Find a way to make it OpenSubdiv_FVarLinearInterpolation,
* without breaking compilation without OpenSubdiv. */
-int BKE_subdiv_converter_fvar_linear_from_settings(
- const SubdivSettings *settings);
+int BKE_subdiv_converter_fvar_linear_from_settings(const SubdivSettings *settings);
-#endif /* __SUBDIV_CONVERTER_H__ */
+#endif /* __SUBDIV_CONVERTER_H__ */
diff --git a/source/blender/blenkernel/intern/subdiv_converter_mesh.c b/source/blender/blenkernel/intern/subdiv_converter_mesh.c
index eda6b522b85..fc0c5db4466 100644
--- a/source/blender/blenkernel/intern/subdiv_converter_mesh.c
+++ b/source/blender/blenkernel/intern/subdiv_converter_mesh.c
@@ -45,215 +45,199 @@
#define BUGGY_SIMPLE_SCHEME_WORKAROUND 1
typedef struct ConverterStorage {
- SubdivSettings settings;
- const Mesh *mesh;
- /* Indexed by loop index, value denotes index of face-varying vertex
- * which corresponds to the UV coordinate.
- */
- int *loop_uv_indices;
- int num_uv_coordinates;
- /* Indexed by coarse mesh elements, gives index of corresponding element
- * with ignoring all non-manifold entities.
- *
- * NOTE: This isn't strictly speaking manifold, this is more like non-loose
- * geometry index. As in, index of element as if there were no loose edges
- * or vertices in the mesh.
- */
- int *manifold_vertex_index;
- /* Indexed by vertex index from mesh, corresponds to whether this vertex has
- * infinite sharpness due to non-manifol topology.
- */
- BLI_bitmap *infinite_sharp_vertices_map;
- /* Reverse mapping to above. */
- int *manifold_vertex_index_reverse;
- int *manifold_edge_index_reverse;
- /* Number of non-loose elements. */
- int num_manifold_vertices;
- int num_manifold_edges;
+ SubdivSettings settings;
+ const Mesh *mesh;
+ /* Indexed by loop index, value denotes index of face-varying vertex
+ * which corresponds to the UV coordinate.
+ */
+ int *loop_uv_indices;
+ int num_uv_coordinates;
+ /* Indexed by coarse mesh elements, gives index of corresponding element
+ * with ignoring all non-manifold entities.
+ *
+ * NOTE: This isn't strictly speaking manifold, this is more like non-loose
+ * geometry index. As in, index of element as if there were no loose edges
+ * or vertices in the mesh.
+ */
+ int *manifold_vertex_index;
+ /* Indexed by vertex index from mesh, corresponds to whether this vertex has
+ * infinite sharpness due to non-manifol topology.
+ */
+ BLI_bitmap *infinite_sharp_vertices_map;
+ /* Reverse mapping to above. */
+ int *manifold_vertex_index_reverse;
+ int *manifold_edge_index_reverse;
+ /* Number of non-loose elements. */
+ int num_manifold_vertices;
+ int num_manifold_edges;
} ConverterStorage;
-static OpenSubdiv_SchemeType get_scheme_type(
- const OpenSubdiv_Converter *converter)
+static OpenSubdiv_SchemeType get_scheme_type(const OpenSubdiv_Converter *converter)
{
#if BUGGY_SIMPLE_SCHEME_WORKAROUND
- (void) converter;
- return OSD_SCHEME_CATMARK;
+ (void)converter;
+ return OSD_SCHEME_CATMARK;
#else
- ConverterStorage *storage = converter->user_data;
- if (storage->settings.is_simple) {
- return OSD_SCHEME_BILINEAR;
- }
- else {
- return OSD_SCHEME_CATMARK;
- }
+ ConverterStorage *storage = converter->user_data;
+ if (storage->settings.is_simple) {
+ return OSD_SCHEME_BILINEAR;
+ }
+ else {
+ return OSD_SCHEME_CATMARK;
+ }
#endif
}
static OpenSubdiv_VtxBoundaryInterpolation get_vtx_boundary_interpolation(
- const struct OpenSubdiv_Converter *converter) {
- ConverterStorage *storage = converter->user_data;
- return BKE_subdiv_converter_vtx_boundary_interpolation_from_settings(
- &storage->settings);
+ const struct OpenSubdiv_Converter *converter)
+{
+ ConverterStorage *storage = converter->user_data;
+ return BKE_subdiv_converter_vtx_boundary_interpolation_from_settings(&storage->settings);
}
static OpenSubdiv_FVarLinearInterpolation get_fvar_linear_interpolation(
- const OpenSubdiv_Converter *converter)
+ const OpenSubdiv_Converter *converter)
{
- ConverterStorage *storage = converter->user_data;
- return BKE_subdiv_converter_fvar_linear_from_settings(&storage->settings);
+ ConverterStorage *storage = converter->user_data;
+ return BKE_subdiv_converter_fvar_linear_from_settings(&storage->settings);
}
-static bool specifies_full_topology(
- const OpenSubdiv_Converter *UNUSED(converter))
+static bool specifies_full_topology(const OpenSubdiv_Converter *UNUSED(converter))
{
- return false;
+ return false;
}
static int get_num_faces(const OpenSubdiv_Converter *converter)
{
- ConverterStorage *storage = converter->user_data;
- return storage->mesh->totpoly;
+ ConverterStorage *storage = converter->user_data;
+ return storage->mesh->totpoly;
}
static int get_num_edges(const OpenSubdiv_Converter *converter)
{
- ConverterStorage *storage = converter->user_data;
- return storage->num_manifold_edges;
+ ConverterStorage *storage = converter->user_data;
+ return storage->num_manifold_edges;
}
static int get_num_vertices(const OpenSubdiv_Converter *converter)
{
- ConverterStorage *storage = converter->user_data;
- return storage->num_manifold_vertices;
+ ConverterStorage *storage = converter->user_data;
+ return storage->num_manifold_vertices;
}
-static int get_num_face_vertices(const OpenSubdiv_Converter *converter,
- int manifold_face_index)
+static int get_num_face_vertices(const OpenSubdiv_Converter *converter, int manifold_face_index)
{
- ConverterStorage *storage = converter->user_data;
- return storage->mesh->mpoly[manifold_face_index].totloop;
+ ConverterStorage *storage = converter->user_data;
+ return storage->mesh->mpoly[manifold_face_index].totloop;
}
static void get_face_vertices(const OpenSubdiv_Converter *converter,
int manifold_face_index,
int *manifold_face_vertices)
{
- ConverterStorage *storage = converter->user_data;
- const MPoly *poly = &storage->mesh->mpoly[manifold_face_index];
- const MLoop *mloop = storage->mesh->mloop;
- for (int corner = 0; corner < poly->totloop; corner++) {
- manifold_face_vertices[corner] = storage->manifold_vertex_index[
- mloop[poly->loopstart + corner].v];
- }
+ ConverterStorage *storage = converter->user_data;
+ const MPoly *poly = &storage->mesh->mpoly[manifold_face_index];
+ const MLoop *mloop = storage->mesh->mloop;
+ for (int corner = 0; corner < poly->totloop; corner++) {
+ manifold_face_vertices[corner] =
+ storage->manifold_vertex_index[mloop[poly->loopstart + corner].v];
+ }
}
static void get_edge_vertices(const OpenSubdiv_Converter *converter,
int manifold_edge_index,
int *manifold_edge_vertices)
{
- ConverterStorage *storage = converter->user_data;
- const int edge_index =
- storage->manifold_edge_index_reverse[manifold_edge_index];
- const MEdge *edge = &storage->mesh->medge[edge_index];
- manifold_edge_vertices[0] = storage->manifold_vertex_index[edge->v1];
- manifold_edge_vertices[1] = storage->manifold_vertex_index[edge->v2];
+ ConverterStorage *storage = converter->user_data;
+ const int edge_index = storage->manifold_edge_index_reverse[manifold_edge_index];
+ const MEdge *edge = &storage->mesh->medge[edge_index];
+ manifold_edge_vertices[0] = storage->manifold_vertex_index[edge->v1];
+ manifold_edge_vertices[1] = storage->manifold_vertex_index[edge->v2];
}
-static float get_edge_sharpness(const OpenSubdiv_Converter *converter,
- int manifold_edge_index)
+static float get_edge_sharpness(const OpenSubdiv_Converter *converter, int manifold_edge_index)
{
- ConverterStorage *storage = converter->user_data;
+ ConverterStorage *storage = converter->user_data;
#if BUGGY_SIMPLE_SCHEME_WORKAROUND
- if (storage->settings.is_simple) {
- return 10.0f;
- }
+ if (storage->settings.is_simple) {
+ return 10.0f;
+ }
#endif
- if (!storage->settings.use_creases) {
- return 0.0f;
- }
- const int edge_index =
- storage->manifold_edge_index_reverse[manifold_edge_index];
- const MEdge *medge = storage->mesh->medge;
- const float edge_crease = (float)medge[edge_index].crease / 255.0f;
- return edge_crease * edge_crease * 10.0f;
+ if (!storage->settings.use_creases) {
+ return 0.0f;
+ }
+ const int edge_index = storage->manifold_edge_index_reverse[manifold_edge_index];
+ const MEdge *medge = storage->mesh->medge;
+ const float edge_crease = (float)medge[edge_index].crease / 255.0f;
+ return edge_crease * edge_crease * 10.0f;
}
static bool is_infinite_sharp_vertex(const OpenSubdiv_Converter *converter,
int manifold_vertex_index)
{
- ConverterStorage *storage = converter->user_data;
+ ConverterStorage *storage = converter->user_data;
#if BUGGY_SIMPLE_SCHEME_WORKAROUND
- if (storage->settings.is_simple) {
- return true;
- }
+ if (storage->settings.is_simple) {
+ return true;
+ }
#endif
- const int vertex_index =
- storage->manifold_vertex_index_reverse[manifold_vertex_index];
- return BLI_BITMAP_TEST_BOOL(storage->infinite_sharp_vertices_map,
- vertex_index);
+ const int vertex_index = storage->manifold_vertex_index_reverse[manifold_vertex_index];
+ return BLI_BITMAP_TEST_BOOL(storage->infinite_sharp_vertices_map, vertex_index);
}
static float get_vertex_sharpness(const OpenSubdiv_Converter *converter,
int UNUSED(manifold_vertex_index))
{
- ConverterStorage *storage = converter->user_data;
- if (!storage->settings.use_creases) {
- return 0.0f;
- }
- return 0.0f;
+ ConverterStorage *storage = converter->user_data;
+ if (!storage->settings.use_creases) {
+ return 0.0f;
+ }
+ return 0.0f;
}
static int get_num_uv_layers(const OpenSubdiv_Converter *converter)
{
- ConverterStorage *storage = converter->user_data;
- const Mesh *mesh = storage->mesh;
- return CustomData_number_of_layers(&mesh->ldata, CD_MLOOPUV);
+ ConverterStorage *storage = converter->user_data;
+ const Mesh *mesh = storage->mesh;
+ return CustomData_number_of_layers(&mesh->ldata, CD_MLOOPUV);
}
-static void precalc_uv_layer(const OpenSubdiv_Converter *converter,
- const int layer_index)
+static void precalc_uv_layer(const OpenSubdiv_Converter *converter, const int layer_index)
{
- ConverterStorage *storage = converter->user_data;
- const Mesh *mesh = storage->mesh;
- const MPoly *mpoly = mesh->mpoly;
- const MLoop *mloop = mesh->mloop;
- const MLoopUV *mloopuv = CustomData_get_layer_n(
- &mesh->ldata, CD_MLOOPUV, layer_index);
- const int num_poly = mesh->totpoly;
- const int num_vert = mesh->totvert;
- const float limit[2] = {STD_UV_CONNECT_LIMIT, STD_UV_CONNECT_LIMIT};
- /* Initialize memory required for the operations. */
- if (storage->loop_uv_indices == NULL) {
- storage->loop_uv_indices = MEM_malloc_arrayN(
- mesh->totloop, sizeof(int), "loop uv vertex index");
- }
- UvVertMap *uv_vert_map = BKE_mesh_uv_vert_map_create(
- mpoly, mloop, mloopuv,
- num_poly, num_vert,
- limit,
- false, true);
- /* NOTE: First UV vertex is supposed to be always marked as separate. */
- storage->num_uv_coordinates = -1;
- for (int vertex_index = 0; vertex_index < num_vert; ++vertex_index) {
- const UvMapVert *uv_vert = BKE_mesh_uv_vert_map_get_vert(uv_vert_map,
- vertex_index);
- while (uv_vert != NULL) {
- if (uv_vert->separate) {
- storage->num_uv_coordinates++;
- }
- const MPoly *mp = &mpoly[uv_vert->poly_index];
- const int global_loop_index = mp->loopstart +
- uv_vert->loop_of_poly_index;
- storage->loop_uv_indices[global_loop_index] =
- storage->num_uv_coordinates;
- uv_vert = uv_vert->next;
- }
- }
- /* So far this value was used as a 0-based index, actual number of UV
- * vertices is 1 more.
- */
- storage->num_uv_coordinates += 1;
- BKE_mesh_uv_vert_map_free(uv_vert_map);
+ ConverterStorage *storage = converter->user_data;
+ const Mesh *mesh = storage->mesh;
+ const MPoly *mpoly = mesh->mpoly;
+ const MLoop *mloop = mesh->mloop;
+ const MLoopUV *mloopuv = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPUV, layer_index);
+ const int num_poly = mesh->totpoly;
+ const int num_vert = mesh->totvert;
+ const float limit[2] = {STD_UV_CONNECT_LIMIT, STD_UV_CONNECT_LIMIT};
+ /* Initialize memory required for the operations. */
+ if (storage->loop_uv_indices == NULL) {
+ storage->loop_uv_indices = MEM_malloc_arrayN(
+ mesh->totloop, sizeof(int), "loop uv vertex index");
+ }
+ UvVertMap *uv_vert_map = BKE_mesh_uv_vert_map_create(
+ mpoly, mloop, mloopuv, num_poly, num_vert, limit, false, true);
+ /* NOTE: First UV vertex is supposed to be always marked as separate. */
+ storage->num_uv_coordinates = -1;
+ for (int vertex_index = 0; vertex_index < num_vert; ++vertex_index) {
+ const UvMapVert *uv_vert = BKE_mesh_uv_vert_map_get_vert(uv_vert_map, vertex_index);
+ while (uv_vert != NULL) {
+ if (uv_vert->separate) {
+ storage->num_uv_coordinates++;
+ }
+ const MPoly *mp = &mpoly[uv_vert->poly_index];
+ const int global_loop_index = mp->loopstart + uv_vert->loop_of_poly_index;
+ storage->loop_uv_indices[global_loop_index] = storage->num_uv_coordinates;
+ uv_vert = uv_vert->next;
+ }
+ }
+ /* So far this value was used as a 0-based index, actual number of UV
+ * vertices is 1 more.
+ */
+ storage->num_uv_coordinates += 1;
+ BKE_mesh_uv_vert_map_free(uv_vert_map);
}
static void finish_uv_layer(const OpenSubdiv_Converter *UNUSED(converter))
@@ -262,64 +246,64 @@ static void finish_uv_layer(const OpenSubdiv_Converter *UNUSED(converter))
static int get_num_uvs(const OpenSubdiv_Converter *converter)
{
- ConverterStorage *storage = converter->user_data;
- return storage->num_uv_coordinates;
+ ConverterStorage *storage = converter->user_data;
+ return storage->num_uv_coordinates;
}
static int get_face_corner_uv_index(const OpenSubdiv_Converter *converter,
const int face_index,
const int corner)
{
- ConverterStorage *storage = converter->user_data;
- const MPoly *mp = &storage->mesh->mpoly[face_index];
- return storage->loop_uv_indices[mp->loopstart + corner];
+ ConverterStorage *storage = converter->user_data;
+ const MPoly *mp = &storage->mesh->mpoly[face_index];
+ return storage->loop_uv_indices[mp->loopstart + corner];
}
static void free_user_data(const OpenSubdiv_Converter *converter)
{
- ConverterStorage *user_data = converter->user_data;
- MEM_SAFE_FREE(user_data->loop_uv_indices);
- MEM_freeN(user_data->manifold_vertex_index);
- MEM_freeN(user_data->infinite_sharp_vertices_map);
- MEM_freeN(user_data->manifold_vertex_index_reverse);
- MEM_freeN(user_data->manifold_edge_index_reverse);
- MEM_freeN(user_data);
+ ConverterStorage *user_data = converter->user_data;
+ MEM_SAFE_FREE(user_data->loop_uv_indices);
+ MEM_freeN(user_data->manifold_vertex_index);
+ MEM_freeN(user_data->infinite_sharp_vertices_map);
+ MEM_freeN(user_data->manifold_vertex_index_reverse);
+ MEM_freeN(user_data->manifold_edge_index_reverse);
+ MEM_freeN(user_data);
}
static void init_functions(OpenSubdiv_Converter *converter)
{
- converter->getSchemeType = get_scheme_type;
- converter->getVtxBoundaryInterpolation = get_vtx_boundary_interpolation;
- converter->getFVarLinearInterpolation = get_fvar_linear_interpolation;
- converter->specifiesFullTopology = specifies_full_topology;
-
- converter->getNumFaces = get_num_faces;
- converter->getNumEdges = get_num_edges;
- converter->getNumVertices = get_num_vertices;
-
- converter->getNumFaceVertices = get_num_face_vertices;
- converter->getFaceVertices = get_face_vertices;
- converter->getFaceEdges = NULL;
-
- converter->getEdgeVertices = get_edge_vertices;
- converter->getNumEdgeFaces = NULL;
- converter->getEdgeFaces = NULL;
- converter->getEdgeSharpness = get_edge_sharpness;
-
- converter->getNumVertexEdges = NULL;
- converter->getVertexEdges = NULL;
- converter->getNumVertexFaces = NULL;
- converter->getVertexFaces = NULL;
- converter->isInfiniteSharpVertex = is_infinite_sharp_vertex;
- converter->getVertexSharpness = get_vertex_sharpness;
-
- converter->getNumUVLayers = get_num_uv_layers;
- converter->precalcUVLayer = precalc_uv_layer;
- converter->finishUVLayer = finish_uv_layer;
- converter->getNumUVCoordinates = get_num_uvs;
- converter->getFaceCornerUVIndex = get_face_corner_uv_index;
-
- converter->freeUserData = free_user_data;
+ converter->getSchemeType = get_scheme_type;
+ converter->getVtxBoundaryInterpolation = get_vtx_boundary_interpolation;
+ converter->getFVarLinearInterpolation = get_fvar_linear_interpolation;
+ converter->specifiesFullTopology = specifies_full_topology;
+
+ converter->getNumFaces = get_num_faces;
+ converter->getNumEdges = get_num_edges;
+ converter->getNumVertices = get_num_vertices;
+
+ converter->getNumFaceVertices = get_num_face_vertices;
+ converter->getFaceVertices = get_face_vertices;
+ converter->getFaceEdges = NULL;
+
+ converter->getEdgeVertices = get_edge_vertices;
+ converter->getNumEdgeFaces = NULL;
+ converter->getEdgeFaces = NULL;
+ converter->getEdgeSharpness = get_edge_sharpness;
+
+ converter->getNumVertexEdges = NULL;
+ converter->getVertexEdges = NULL;
+ converter->getNumVertexFaces = NULL;
+ converter->getVertexFaces = NULL;
+ converter->isInfiniteSharpVertex = is_infinite_sharp_vertex;
+ converter->getVertexSharpness = get_vertex_sharpness;
+
+ converter->getNumUVLayers = get_num_uv_layers;
+ converter->precalcUVLayer = precalc_uv_layer;
+ converter->finishUVLayer = finish_uv_layer;
+ converter->getNumUVCoordinates = get_num_uvs;
+ converter->getFaceCornerUVIndex = get_face_corner_uv_index;
+
+ converter->freeUserData = free_user_data;
}
static void initialize_manifold_index_array(const BLI_bitmap *used_map,
@@ -328,101 +312,97 @@ static void initialize_manifold_index_array(const BLI_bitmap *used_map,
int **indices_reverse_r,
int *num_manifold_elements_r)
{
- int *indices = NULL;
- if (indices_r != NULL) {
- indices = MEM_malloc_arrayN(
- num_elements, sizeof(int), "manifold indices");
- }
- int *indices_reverse = NULL;
- if (indices_reverse_r != NULL) {
- indices_reverse = MEM_malloc_arrayN(
- num_elements, sizeof(int), "manifold indices reverse");
- }
- int offset = 0;
- for (int i = 0; i < num_elements; i++) {
- if (BLI_BITMAP_TEST_BOOL(used_map, i)) {
- if (indices != NULL) {
- indices[i] = i - offset;
- }
- if (indices_reverse != NULL) {
- indices_reverse[i - offset] = i;
- }
- }
- else {
- if (indices != NULL) {
- indices[i] = -1;
- }
- offset++;
- }
- }
- if (indices_r != NULL) {
- *indices_r = indices;
- }
- if (indices_reverse_r != NULL) {
- *indices_reverse_r = indices_reverse;
- }
- *num_manifold_elements_r = num_elements - offset;
+ int *indices = NULL;
+ if (indices_r != NULL) {
+ indices = MEM_malloc_arrayN(num_elements, sizeof(int), "manifold indices");
+ }
+ int *indices_reverse = NULL;
+ if (indices_reverse_r != NULL) {
+ indices_reverse = MEM_malloc_arrayN(num_elements, sizeof(int), "manifold indices reverse");
+ }
+ int offset = 0;
+ for (int i = 0; i < num_elements; i++) {
+ if (BLI_BITMAP_TEST_BOOL(used_map, i)) {
+ if (indices != NULL) {
+ indices[i] = i - offset;
+ }
+ if (indices_reverse != NULL) {
+ indices_reverse[i - offset] = i;
+ }
+ }
+ else {
+ if (indices != NULL) {
+ indices[i] = -1;
+ }
+ offset++;
+ }
+ }
+ if (indices_r != NULL) {
+ *indices_r = indices;
+ }
+ if (indices_reverse_r != NULL) {
+ *indices_reverse_r = indices_reverse;
+ }
+ *num_manifold_elements_r = num_elements - offset;
}
static void initialize_manifold_indices(ConverterStorage *storage)
{
- const Mesh *mesh = storage->mesh;
- const MEdge *medge = mesh->medge;
- const MLoop *mloop = mesh->mloop;
- const MPoly *mpoly = mesh->mpoly;
- /* Set bits of elements which are not loose. */
- BLI_bitmap *vert_used_map = BLI_BITMAP_NEW(mesh->totvert, "vert used map");
- BLI_bitmap *edge_used_map = BLI_BITMAP_NEW(mesh->totedge, "edge used map");
- for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) {
- const MPoly *poly = &mpoly[poly_index];
- for (int corner = 0; corner < poly->totloop; corner++) {
- const MLoop *loop = &mloop[poly->loopstart + corner];
- BLI_BITMAP_ENABLE(vert_used_map, loop->v);
- BLI_BITMAP_ENABLE(edge_used_map, loop->e);
- }
- }
- initialize_manifold_index_array(vert_used_map,
- mesh->totvert,
- &storage->manifold_vertex_index,
- &storage->manifold_vertex_index_reverse,
- &storage->num_manifold_vertices);
- initialize_manifold_index_array(edge_used_map,
- mesh->totedge,
- NULL,
- &storage->manifold_edge_index_reverse,
- &storage->num_manifold_edges);
- /* Initialize infinite sharp mapping. */
- storage->infinite_sharp_vertices_map =
- BLI_BITMAP_NEW(mesh->totvert, "vert used map");
- for (int edge_index = 0; edge_index < mesh->totedge; edge_index++) {
- if (!BLI_BITMAP_TEST_BOOL(edge_used_map, edge_index)) {
- const MEdge *edge = &medge[edge_index];
- BLI_BITMAP_ENABLE(storage->infinite_sharp_vertices_map, edge->v1);
- BLI_BITMAP_ENABLE(storage->infinite_sharp_vertices_map, edge->v2);
- }
- }
- /* Free working variables. */
- MEM_freeN(vert_used_map);
- MEM_freeN(edge_used_map);
+ const Mesh *mesh = storage->mesh;
+ const MEdge *medge = mesh->medge;
+ const MLoop *mloop = mesh->mloop;
+ const MPoly *mpoly = mesh->mpoly;
+ /* Set bits of elements which are not loose. */
+ BLI_bitmap *vert_used_map = BLI_BITMAP_NEW(mesh->totvert, "vert used map");
+ BLI_bitmap *edge_used_map = BLI_BITMAP_NEW(mesh->totedge, "edge used map");
+ for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) {
+ const MPoly *poly = &mpoly[poly_index];
+ for (int corner = 0; corner < poly->totloop; corner++) {
+ const MLoop *loop = &mloop[poly->loopstart + corner];
+ BLI_BITMAP_ENABLE(vert_used_map, loop->v);
+ BLI_BITMAP_ENABLE(edge_used_map, loop->e);
+ }
+ }
+ initialize_manifold_index_array(vert_used_map,
+ mesh->totvert,
+ &storage->manifold_vertex_index,
+ &storage->manifold_vertex_index_reverse,
+ &storage->num_manifold_vertices);
+ initialize_manifold_index_array(edge_used_map,
+ mesh->totedge,
+ NULL,
+ &storage->manifold_edge_index_reverse,
+ &storage->num_manifold_edges);
+ /* Initialize infinite sharp mapping. */
+ storage->infinite_sharp_vertices_map = BLI_BITMAP_NEW(mesh->totvert, "vert used map");
+ for (int edge_index = 0; edge_index < mesh->totedge; edge_index++) {
+ if (!BLI_BITMAP_TEST_BOOL(edge_used_map, edge_index)) {
+ const MEdge *edge = &medge[edge_index];
+ BLI_BITMAP_ENABLE(storage->infinite_sharp_vertices_map, edge->v1);
+ BLI_BITMAP_ENABLE(storage->infinite_sharp_vertices_map, edge->v2);
+ }
+ }
+ /* Free working variables. */
+ MEM_freeN(vert_used_map);
+ MEM_freeN(edge_used_map);
}
static void init_user_data(OpenSubdiv_Converter *converter,
const SubdivSettings *settings,
const Mesh *mesh)
{
- ConverterStorage *user_data =
- MEM_mallocN(sizeof(ConverterStorage), __func__);
- user_data->settings = *settings;
- user_data->mesh = mesh;
- user_data->loop_uv_indices = NULL;
- initialize_manifold_indices(user_data);
- converter->user_data = user_data;
+ ConverterStorage *user_data = MEM_mallocN(sizeof(ConverterStorage), __func__);
+ user_data->settings = *settings;
+ user_data->mesh = mesh;
+ user_data->loop_uv_indices = NULL;
+ initialize_manifold_indices(user_data);
+ converter->user_data = user_data;
}
void BKE_subdiv_converter_init_for_mesh(struct OpenSubdiv_Converter *converter,
const SubdivSettings *settings,
const Mesh *mesh)
{
- init_functions(converter);
- init_user_data(converter, settings, mesh);
+ init_functions(converter);
+ init_user_data(converter, settings, mesh);
}
diff --git a/source/blender/blenkernel/intern/subdiv_displacement.c b/source/blender/blenkernel/intern/subdiv_displacement.c
index bd801366ec5..7e1acde9450 100644
--- a/source/blender/blenkernel/intern/subdiv_displacement.c
+++ b/source/blender/blenkernel/intern/subdiv_displacement.c
@@ -29,12 +29,12 @@
void BKE_subdiv_displacement_detach(Subdiv *subdiv)
{
- if (subdiv->displacement_evaluator == NULL) {
- return;
- }
- if (subdiv->displacement_evaluator->free != NULL) {
- subdiv->displacement_evaluator->free(subdiv->displacement_evaluator);
- }
- MEM_freeN(subdiv->displacement_evaluator);
- subdiv->displacement_evaluator = NULL;
+ if (subdiv->displacement_evaluator == NULL) {
+ return;
+ }
+ if (subdiv->displacement_evaluator->free != NULL) {
+ subdiv->displacement_evaluator->free(subdiv->displacement_evaluator);
+ }
+ MEM_freeN(subdiv->displacement_evaluator);
+ subdiv->displacement_evaluator = NULL;
}
diff --git a/source/blender/blenkernel/intern/subdiv_displacement_multires.c b/source/blender/blenkernel/intern/subdiv_displacement_multires.c
index 527b3beae36..1f78cf4eb3b 100644
--- a/source/blender/blenkernel/intern/subdiv_displacement_multires.c
+++ b/source/blender/blenkernel/intern/subdiv_displacement_multires.c
@@ -38,409 +38,378 @@
#include "MEM_guardedalloc.h"
typedef struct PolyCornerIndex {
- int poly_index;
- int corner;
+ int poly_index;
+ int corner;
} PolyCornerIndex;
typedef struct MultiresDisplacementData {
- Subdiv *subdiv;
- int grid_size;
- /* Mesh is used to read external displacement. */
- Mesh *mesh;
- const MPoly *mpoly;
- const MDisps *mdisps;
- /* Indexed by ptex face index, contains polygon/corner which corresponds
- * to it.
- *
- * NOTE: For quad polygon this is an index of first corner only, since
- * there we only have one ptex. */
- PolyCornerIndex *ptex_poly_corner;
- /* Indexed by coarse face index, returns first ptex face index corresponding
- * to that coarse face. */
- int *face_ptex_offset;
- /* Sanity check, is used in debug builds.
- * Controls that initialize() was called prior to eval_displacement(). */
- bool is_initialized;
+ Subdiv *subdiv;
+ int grid_size;
+ /* Mesh is used to read external displacement. */
+ Mesh *mesh;
+ const MPoly *mpoly;
+ const MDisps *mdisps;
+ /* Indexed by ptex face index, contains polygon/corner which corresponds
+ * to it.
+ *
+ * NOTE: For quad polygon this is an index of first corner only, since
+ * there we only have one ptex. */
+ PolyCornerIndex *ptex_poly_corner;
+ /* Indexed by coarse face index, returns first ptex face index corresponding
+ * to that coarse face. */
+ int *face_ptex_offset;
+ /* Sanity check, is used in debug builds.
+ * Controls that initialize() was called prior to eval_displacement(). */
+ bool is_initialized;
} MultiresDisplacementData;
/* Denotes which grid to use to average value of the displacement read from the
* grid which corresponds to the ptex face. */
typedef enum eAverageWith {
- AVERAGE_WITH_NONE,
- AVERAGE_WITH_ALL,
- AVERAGE_WITH_PREV,
- AVERAGE_WITH_NEXT,
+ AVERAGE_WITH_NONE,
+ AVERAGE_WITH_ALL,
+ AVERAGE_WITH_PREV,
+ AVERAGE_WITH_NEXT,
} eAverageWith;
-static int displacement_get_grid_and_coord(
- SubdivDisplacement *displacement,
- const int ptex_face_index, const float u, const float v,
- const MDisps **r_displacement_grid,
- float *grid_u, float *grid_v)
+static int displacement_get_grid_and_coord(SubdivDisplacement *displacement,
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ const MDisps **r_displacement_grid,
+ float *grid_u,
+ float *grid_v)
{
- MultiresDisplacementData *data = displacement->user_data;
- const PolyCornerIndex *poly_corner =
- &data->ptex_poly_corner[ptex_face_index];
- const MPoly *poly = &data->mpoly[poly_corner->poly_index];
- const int start_grid_index = poly->loopstart + poly_corner->corner;
- int corner = 0;
- if (poly->totloop == 4) {
- float corner_u, corner_v;
- corner = BKE_subdiv_rotate_quad_to_corner(u, v, &corner_u, &corner_v);
- *r_displacement_grid = &data->mdisps[start_grid_index + corner];
- BKE_subdiv_ptex_face_uv_to_grid_uv(corner_u, corner_v, grid_u, grid_v);
- }
- else {
- *r_displacement_grid = &data->mdisps[start_grid_index];
- BKE_subdiv_ptex_face_uv_to_grid_uv(u, v, grid_u, grid_v);
- }
- return corner;
+ MultiresDisplacementData *data = displacement->user_data;
+ const PolyCornerIndex *poly_corner = &data->ptex_poly_corner[ptex_face_index];
+ const MPoly *poly = &data->mpoly[poly_corner->poly_index];
+ const int start_grid_index = poly->loopstart + poly_corner->corner;
+ int corner = 0;
+ if (poly->totloop == 4) {
+ float corner_u, corner_v;
+ corner = BKE_subdiv_rotate_quad_to_corner(u, v, &corner_u, &corner_v);
+ *r_displacement_grid = &data->mdisps[start_grid_index + corner];
+ BKE_subdiv_ptex_face_uv_to_grid_uv(corner_u, corner_v, grid_u, grid_v);
+ }
+ else {
+ *r_displacement_grid = &data->mdisps[start_grid_index];
+ BKE_subdiv_ptex_face_uv_to_grid_uv(u, v, grid_u, grid_v);
+ }
+ return corner;
}
-static const MDisps *displacement_get_other_grid(
- SubdivDisplacement *displacement,
- const int ptex_face_index, const int corner,
- const int corner_delta)
+static const MDisps *displacement_get_other_grid(SubdivDisplacement *displacement,
+ const int ptex_face_index,
+ const int corner,
+ const int corner_delta)
{
- MultiresDisplacementData *data = displacement->user_data;
- const PolyCornerIndex *poly_corner =
- &data->ptex_poly_corner[ptex_face_index];
- const MPoly *poly = &data->mpoly[poly_corner->poly_index];
- const int effective_corner = (poly->totloop == 4) ? corner
- : poly_corner->corner;
- const int next_corner =
- (effective_corner + corner_delta + poly->totloop) % poly->totloop;
- return &data->mdisps[poly->loopstart + next_corner];
+ MultiresDisplacementData *data = displacement->user_data;
+ const PolyCornerIndex *poly_corner = &data->ptex_poly_corner[ptex_face_index];
+ const MPoly *poly = &data->mpoly[poly_corner->poly_index];
+ const int effective_corner = (poly->totloop == 4) ? corner : poly_corner->corner;
+ const int next_corner = (effective_corner + corner_delta + poly->totloop) % poly->totloop;
+ return &data->mdisps[poly->loopstart + next_corner];
}
-BLI_INLINE eAverageWith read_displacement_grid(
- const MDisps *displacement_grid,
- const int grid_size,
- const float grid_u, const float grid_v,
- float r_tangent_D[3])
+BLI_INLINE eAverageWith read_displacement_grid(const MDisps *displacement_grid,
+ const int grid_size,
+ const float grid_u,
+ const float grid_v,
+ float r_tangent_D[3])
{
- if (displacement_grid->disps == NULL) {
- zero_v3(r_tangent_D);
- return AVERAGE_WITH_NONE;
- }
- const int x = (grid_u * (grid_size - 1) + 0.5f);
- const int y = (grid_v * (grid_size - 1) + 0.5f);
- copy_v3_v3(r_tangent_D, displacement_grid->disps[y * grid_size + x]);
- if (x == 0 && y == 0) {
- return AVERAGE_WITH_ALL;
- }
- else if (x == 0) {
- return AVERAGE_WITH_PREV;
- }
- else if (y == 0) {
- return AVERAGE_WITH_NEXT;
- }
- return AVERAGE_WITH_NONE;
+ if (displacement_grid->disps == NULL) {
+ zero_v3(r_tangent_D);
+ return AVERAGE_WITH_NONE;
+ }
+ const int x = (grid_u * (grid_size - 1) + 0.5f);
+ const int y = (grid_v * (grid_size - 1) + 0.5f);
+ copy_v3_v3(r_tangent_D, displacement_grid->disps[y * grid_size + x]);
+ if (x == 0 && y == 0) {
+ return AVERAGE_WITH_ALL;
+ }
+ else if (x == 0) {
+ return AVERAGE_WITH_PREV;
+ }
+ else if (y == 0) {
+ return AVERAGE_WITH_NEXT;
+ }
+ return AVERAGE_WITH_NONE;
}
-static void average_convert_grid_coord_to_ptex(
- const MPoly *poly,
- const int corner, const float grid_u, const float grid_v,
- float *r_ptex_face_u, float *r_ptex_face_v)
+static void average_convert_grid_coord_to_ptex(const MPoly *poly,
+ const int corner,
+ const float grid_u,
+ const float grid_v,
+ float *r_ptex_face_u,
+ float *r_ptex_face_v)
{
- if (poly->totloop == 4) {
- BKE_subdiv_rotate_grid_to_quad(corner, grid_u, grid_v,
- r_ptex_face_u, r_ptex_face_v);
- }
- else {
- BKE_subdiv_grid_uv_to_ptex_face_uv(
- grid_u, grid_v,
- r_ptex_face_u, r_ptex_face_v);
- }
+ if (poly->totloop == 4) {
+ BKE_subdiv_rotate_grid_to_quad(corner, grid_u, grid_v, r_ptex_face_u, r_ptex_face_v);
+ }
+ else {
+ BKE_subdiv_grid_uv_to_ptex_face_uv(grid_u, grid_v, r_ptex_face_u, r_ptex_face_v);
+ }
}
-static void average_construct_tangent_matrix(
- Subdiv *subdiv,
- const MPoly *poly,
- const int ptex_face_index, const int corner,
- const float u, const float v,
- float r_tangent_matrix[3][3])
+static void average_construct_tangent_matrix(Subdiv *subdiv,
+ const MPoly *poly,
+ const int ptex_face_index,
+ const int corner,
+ const float u,
+ const float v,
+ float r_tangent_matrix[3][3])
{
- const bool is_quad = (poly->totloop == 4);
- const int quad_corner = is_quad ? corner : 0;
- float dummy_P[3], dPdu[3], dPdv[3];
- BKE_subdiv_eval_limit_point_and_derivatives(
- subdiv, ptex_face_index, u, v, dummy_P, dPdu, dPdv);
- BKE_multires_construct_tangent_matrix(
- r_tangent_matrix, dPdu, dPdv, quad_corner);
+ const bool is_quad = (poly->totloop == 4);
+ const int quad_corner = is_quad ? corner : 0;
+ float dummy_P[3], dPdu[3], dPdv[3];
+ BKE_subdiv_eval_limit_point_and_derivatives(subdiv, ptex_face_index, u, v, dummy_P, dPdu, dPdv);
+ BKE_multires_construct_tangent_matrix(r_tangent_matrix, dPdu, dPdv, quad_corner);
}
-static void average_read_displacement_tangent(
- MultiresDisplacementData *data,
- const MDisps *other_displacement_grid,
- const float grid_u, const float grid_v,
- float r_tangent_D[3])
+static void average_read_displacement_tangent(MultiresDisplacementData *data,
+ const MDisps *other_displacement_grid,
+ const float grid_u,
+ const float grid_v,
+ float r_tangent_D[3])
{
- read_displacement_grid(
- other_displacement_grid, data->grid_size, grid_u, grid_v,
- r_tangent_D);
+ read_displacement_grid(other_displacement_grid, data->grid_size, grid_u, grid_v, r_tangent_D);
}
-static void average_read_displacement_object(
- MultiresDisplacementData *data,
- const MDisps *displacement_grid,
- const float grid_u, const float grid_v,
- const int ptex_face_index,
- const int corner_index,
- float r_D[3])
+static void average_read_displacement_object(MultiresDisplacementData *data,
+ const MDisps *displacement_grid,
+ const float grid_u,
+ const float grid_v,
+ const int ptex_face_index,
+ const int corner_index,
+ float r_D[3])
{
- const PolyCornerIndex *poly_corner =
- &data->ptex_poly_corner[ptex_face_index];
- const MPoly *poly = &data->mpoly[poly_corner->poly_index];
- /* Get (u, v) coordinate within the other ptex face which corresponds to
- * the grid coordinates. */
- float u, v;
- average_convert_grid_coord_to_ptex(
- poly, corner_index, grid_u, grid_v, &u, &v);
- /* Construct tangent matrix which corresponds to partial derivatives
- * calculated for the other ptex face. */
- float tangent_matrix[3][3];
- average_construct_tangent_matrix(
- data->subdiv, poly,
- ptex_face_index, corner_index, u, v,
- tangent_matrix);
- /* Read displacement from other grid in a tangent space. */
- float tangent_D[3];
- average_read_displacement_tangent(
- data, displacement_grid, grid_u, grid_v, tangent_D);
- /* Convert displacement to object space. */
- mul_v3_m3v3(r_D, tangent_matrix, tangent_D);
+ const PolyCornerIndex *poly_corner = &data->ptex_poly_corner[ptex_face_index];
+ const MPoly *poly = &data->mpoly[poly_corner->poly_index];
+ /* Get (u, v) coordinate within the other ptex face which corresponds to
+ * the grid coordinates. */
+ float u, v;
+ average_convert_grid_coord_to_ptex(poly, corner_index, grid_u, grid_v, &u, &v);
+ /* Construct tangent matrix which corresponds to partial derivatives
+ * calculated for the other ptex face. */
+ float tangent_matrix[3][3];
+ average_construct_tangent_matrix(
+ data->subdiv, poly, ptex_face_index, corner_index, u, v, tangent_matrix);
+ /* Read displacement from other grid in a tangent space. */
+ float tangent_D[3];
+ average_read_displacement_tangent(data, displacement_grid, grid_u, grid_v, tangent_D);
+ /* Convert displacement to object space. */
+ mul_v3_m3v3(r_D, tangent_matrix, tangent_D);
}
-static void average_get_other_ptex_and_corner(
- MultiresDisplacementData *data,
- const int ptex_face_index, const int corner,
- const int corner_delta,
- int *r_other_ptex_face_index, int *r_other_corner_index)
+static void average_get_other_ptex_and_corner(MultiresDisplacementData *data,
+ const int ptex_face_index,
+ const int corner,
+ const int corner_delta,
+ int *r_other_ptex_face_index,
+ int *r_other_corner_index)
{
- const PolyCornerIndex *poly_corner =
- &data->ptex_poly_corner[ptex_face_index];
- const MPoly *poly = &data->mpoly[poly_corner->poly_index];
- const int num_corners = poly->totloop;
- const bool is_quad = (num_corners == 4);
- const int poly_index = poly - data->mpoly;
- const int start_ptex_face_index = data->face_ptex_offset[poly_index];
- *r_other_corner_index =
- (corner + corner_delta + num_corners) % num_corners;
- *r_other_ptex_face_index =
- is_quad ? start_ptex_face_index
- : start_ptex_face_index + *r_other_corner_index;
+ const PolyCornerIndex *poly_corner = &data->ptex_poly_corner[ptex_face_index];
+ const MPoly *poly = &data->mpoly[poly_corner->poly_index];
+ const int num_corners = poly->totloop;
+ const bool is_quad = (num_corners == 4);
+ const int poly_index = poly - data->mpoly;
+ const int start_ptex_face_index = data->face_ptex_offset[poly_index];
+ *r_other_corner_index = (corner + corner_delta + num_corners) % num_corners;
+ *r_other_ptex_face_index = is_quad ? start_ptex_face_index :
+ start_ptex_face_index + *r_other_corner_index;
}
/* NOTE: Grid coordinates are relatiev to the other grid already. */
static void average_with_other(SubdivDisplacement *displacement,
- const int ptex_face_index, const int corner,
- const float grid_u, const float grid_v,
- const int corner_delta,
- float r_D[3])
+ const int ptex_face_index,
+ const int corner,
+ const float grid_u,
+ const float grid_v,
+ const int corner_delta,
+ float r_D[3])
{
- MultiresDisplacementData *data = displacement->user_data;
- const MDisps *other_displacement_grid = displacement_get_other_grid(
- displacement, ptex_face_index, corner, corner_delta);
- int other_ptex_face_index, other_corner_index;
- average_get_other_ptex_and_corner(
- data, ptex_face_index, corner, corner_delta,
- &other_ptex_face_index, &other_corner_index);
- /* Get displacement in object space. */
- float other_D[3];
- average_read_displacement_object(
- data,
- other_displacement_grid, grid_u, grid_v,
- other_ptex_face_index, other_corner_index,
- other_D);
- /* Average result with the other displacement vector. */
- add_v3_v3(r_D, other_D);
- mul_v3_fl(r_D, 0.5f);
+ MultiresDisplacementData *data = displacement->user_data;
+ const MDisps *other_displacement_grid = displacement_get_other_grid(
+ displacement, ptex_face_index, corner, corner_delta);
+ int other_ptex_face_index, other_corner_index;
+ average_get_other_ptex_and_corner(
+ data, ptex_face_index, corner, corner_delta, &other_ptex_face_index, &other_corner_index);
+ /* Get displacement in object space. */
+ float other_D[3];
+ average_read_displacement_object(data,
+ other_displacement_grid,
+ grid_u,
+ grid_v,
+ other_ptex_face_index,
+ other_corner_index,
+ other_D);
+ /* Average result with the other displacement vector. */
+ add_v3_v3(r_D, other_D);
+ mul_v3_fl(r_D, 0.5f);
}
-
static void average_with_all(SubdivDisplacement *displacement,
- const int ptex_face_index, const int corner,
+ const int ptex_face_index,
+ const int corner,
const float UNUSED(grid_u),
const float UNUSED(grid_v),
float r_D[3])
{
- MultiresDisplacementData *data = displacement->user_data;
- const PolyCornerIndex *poly_corner =
- &data->ptex_poly_corner[ptex_face_index];
- const MPoly *poly = &data->mpoly[poly_corner->poly_index];
- const int num_corners = poly->totloop;
- for (int corner_delta = 1; corner_delta < num_corners; corner_delta++) {
- average_with_other(
- displacement, ptex_face_index, corner, 0.0f, 0.0f, corner_delta,
- r_D);
- }
+ MultiresDisplacementData *data = displacement->user_data;
+ const PolyCornerIndex *poly_corner = &data->ptex_poly_corner[ptex_face_index];
+ const MPoly *poly = &data->mpoly[poly_corner->poly_index];
+ const int num_corners = poly->totloop;
+ for (int corner_delta = 1; corner_delta < num_corners; corner_delta++) {
+ average_with_other(displacement, ptex_face_index, corner, 0.0f, 0.0f, corner_delta, r_D);
+ }
}
static void average_with_next(SubdivDisplacement *displacement,
- const int ptex_face_index, const int corner,
- const float grid_u, const float UNUSED(grid_v),
+ const int ptex_face_index,
+ const int corner,
+ const float grid_u,
+ const float UNUSED(grid_v),
float r_D[3])
{
- average_with_other(
- displacement, ptex_face_index, corner, 0.0f, grid_u, 1, r_D);
+ average_with_other(displacement, ptex_face_index, corner, 0.0f, grid_u, 1, r_D);
}
static void average_with_prev(SubdivDisplacement *displacement,
- const int ptex_face_index, const int corner,
- const float UNUSED(grid_u), const float grid_v,
- float r_D[3])
+ const int ptex_face_index,
+ const int corner,
+ const float UNUSED(grid_u),
+ const float grid_v,
+ float r_D[3])
{
- average_with_other(
- displacement, ptex_face_index, corner, grid_v, 0.0f, -1, r_D);
+ average_with_other(displacement, ptex_face_index, corner, grid_v, 0.0f, -1, r_D);
}
static void average_displacement(SubdivDisplacement *displacement,
eAverageWith average_with,
- const int ptex_face_index, const int corner,
- const float grid_u, const float grid_v,
+ const int ptex_face_index,
+ const int corner,
+ const float grid_u,
+ const float grid_v,
float r_D[3])
{
- switch (average_with) {
- case AVERAGE_WITH_ALL:
- average_with_all(displacement,
- ptex_face_index, corner,
- grid_u, grid_v,
- r_D);
- break;
- case AVERAGE_WITH_PREV:
- average_with_prev(displacement,
- ptex_face_index, corner,
- grid_u, grid_v,
- r_D);
- break;
- case AVERAGE_WITH_NEXT:
- average_with_next(displacement,
- ptex_face_index, corner,
- grid_u, grid_v,
- r_D);
- break;
- case AVERAGE_WITH_NONE:
- break;
- }
+ switch (average_with) {
+ case AVERAGE_WITH_ALL:
+ average_with_all(displacement, ptex_face_index, corner, grid_u, grid_v, r_D);
+ break;
+ case AVERAGE_WITH_PREV:
+ average_with_prev(displacement, ptex_face_index, corner, grid_u, grid_v, r_D);
+ break;
+ case AVERAGE_WITH_NEXT:
+ average_with_next(displacement, ptex_face_index, corner, grid_u, grid_v, r_D);
+ break;
+ case AVERAGE_WITH_NONE:
+ break;
+ }
}
static int displacement_get_face_corner(MultiresDisplacementData *data,
const int ptex_face_index,
- const float u, const float v)
+ const float u,
+ const float v)
{
- const PolyCornerIndex *poly_corner =
- &data->ptex_poly_corner[ptex_face_index];
- const MPoly *poly = &data->mpoly[poly_corner->poly_index];
- const int num_corners = poly->totloop;
- const bool is_quad = (num_corners == 4);
- if (is_quad) {
- float dummy_corner_u, dummy_corner_v;
- return BKE_subdiv_rotate_quad_to_corner(
- u, v, &dummy_corner_u, &dummy_corner_v);
- }
- else {
- return poly_corner->corner;
- }
+ const PolyCornerIndex *poly_corner = &data->ptex_poly_corner[ptex_face_index];
+ const MPoly *poly = &data->mpoly[poly_corner->poly_index];
+ const int num_corners = poly->totloop;
+ const bool is_quad = (num_corners == 4);
+ if (is_quad) {
+ float dummy_corner_u, dummy_corner_v;
+ return BKE_subdiv_rotate_quad_to_corner(u, v, &dummy_corner_u, &dummy_corner_v);
+ }
+ else {
+ return poly_corner->corner;
+ }
}
static void initialize(SubdivDisplacement *displacement)
{
- MultiresDisplacementData *data = displacement->user_data;
- Mesh *mesh = data->mesh;
- /* Make sure external displacement is read. */
- CustomData_external_read(
- &mesh->ldata, &mesh->id, CD_MASK_MDISPS, mesh->totloop);
- data->is_initialized = true;
+ MultiresDisplacementData *data = displacement->user_data;
+ Mesh *mesh = data->mesh;
+ /* Make sure external displacement is read. */
+ CustomData_external_read(&mesh->ldata, &mesh->id, CD_MASK_MDISPS, mesh->totloop);
+ data->is_initialized = true;
}
static void eval_displacement(SubdivDisplacement *displacement,
const int ptex_face_index,
- const float u, const float v,
- const float dPdu[3], const float dPdv[3],
+ const float u,
+ const float v,
+ const float dPdu[3],
+ const float dPdv[3],
float r_D[3])
{
- MultiresDisplacementData *data = displacement->user_data;
- BLI_assert(data->is_initialized);
- const int grid_size = data->grid_size;
- /* Get displacement in tangent space. */
- const MDisps *displacement_grid;
- float grid_u, grid_v;
- const int corner_of_quad = displacement_get_grid_and_coord(
- displacement,
- ptex_face_index, u, v,
- &displacement_grid,
- &grid_u, &grid_v);
- /* Read displacement from the current displacement grid and see if any
- * averaging is needed. */
- float tangent_D[3];
- eAverageWith average_with =
- read_displacement_grid(displacement_grid, grid_size,
- grid_u, grid_v,
- tangent_D);
- /* Convert it to the object space. */
- float tangent_matrix[3][3];
- BKE_multires_construct_tangent_matrix(
- tangent_matrix, dPdu, dPdv, corner_of_quad);
- mul_v3_m3v3(r_D, tangent_matrix, tangent_D);
- /* For the boundary points of grid average two (or all) neighbor grids. */
- const int corner = displacement_get_face_corner(
- data, ptex_face_index, u, v);
- average_displacement(displacement,
- average_with,
- ptex_face_index, corner,
- grid_u, grid_v,
- r_D);
+ MultiresDisplacementData *data = displacement->user_data;
+ BLI_assert(data->is_initialized);
+ const int grid_size = data->grid_size;
+ /* Get displacement in tangent space. */
+ const MDisps *displacement_grid;
+ float grid_u, grid_v;
+ const int corner_of_quad = displacement_get_grid_and_coord(
+ displacement, ptex_face_index, u, v, &displacement_grid, &grid_u, &grid_v);
+ /* Read displacement from the current displacement grid and see if any
+ * averaging is needed. */
+ float tangent_D[3];
+ eAverageWith average_with = read_displacement_grid(
+ displacement_grid, grid_size, grid_u, grid_v, tangent_D);
+ /* Convert it to the object space. */
+ float tangent_matrix[3][3];
+ BKE_multires_construct_tangent_matrix(tangent_matrix, dPdu, dPdv, corner_of_quad);
+ mul_v3_m3v3(r_D, tangent_matrix, tangent_D);
+ /* For the boundary points of grid average two (or all) neighbor grids. */
+ const int corner = displacement_get_face_corner(data, ptex_face_index, u, v);
+ average_displacement(displacement, average_with, ptex_face_index, corner, grid_u, grid_v, r_D);
}
static void free_displacement(SubdivDisplacement *displacement)
{
- MultiresDisplacementData *data = displacement->user_data;
- MEM_freeN(data->ptex_poly_corner);
- MEM_freeN(data);
+ MultiresDisplacementData *data = displacement->user_data;
+ MEM_freeN(data->ptex_poly_corner);
+ MEM_freeN(data);
}
/* TODO(sergey): This seems to be generally used information, which almost
* worth adding to a subdiv itself, with possible cache of the value. */
static int count_num_ptex_faces(const Mesh *mesh)
{
- int num_ptex_faces = 0;
- const MPoly *mpoly = mesh->mpoly;
- for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) {
- const MPoly *poly = &mpoly[poly_index];
- num_ptex_faces += (poly->totloop == 4) ? 1 : poly->totloop;
- }
- return num_ptex_faces;
+ int num_ptex_faces = 0;
+ const MPoly *mpoly = mesh->mpoly;
+ for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) {
+ const MPoly *poly = &mpoly[poly_index];
+ num_ptex_faces += (poly->totloop == 4) ? 1 : poly->totloop;
+ }
+ return num_ptex_faces;
}
-static void displacement_data_init_mapping(SubdivDisplacement *displacement,
- const Mesh *mesh)
+static void displacement_data_init_mapping(SubdivDisplacement *displacement, const Mesh *mesh)
{
- MultiresDisplacementData *data = displacement->user_data;
- const MPoly *mpoly = mesh->mpoly;
- const int num_ptex_faces = count_num_ptex_faces(mesh);
- /* Allocate memory. */
- data->ptex_poly_corner = MEM_malloc_arrayN(num_ptex_faces,
- sizeof(*data->ptex_poly_corner),
- "ptex poly corner");
- /* Fill in offsets. */
- int ptex_face_index = 0;
- PolyCornerIndex *ptex_poly_corner = data->ptex_poly_corner;
- for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) {
- const MPoly *poly = &mpoly[poly_index];
- if (poly->totloop == 4) {
- ptex_poly_corner[ptex_face_index].poly_index = poly_index;
- ptex_poly_corner[ptex_face_index].corner = 0;
- ptex_face_index++;
- }
- else {
- for (int corner = 0; corner < poly->totloop; corner++) {
- ptex_poly_corner[ptex_face_index].poly_index = poly_index;
- ptex_poly_corner[ptex_face_index].corner = corner;
- ptex_face_index++;
- }
- }
- }
+ MultiresDisplacementData *data = displacement->user_data;
+ const MPoly *mpoly = mesh->mpoly;
+ const int num_ptex_faces = count_num_ptex_faces(mesh);
+ /* Allocate memory. */
+ data->ptex_poly_corner = MEM_malloc_arrayN(
+ num_ptex_faces, sizeof(*data->ptex_poly_corner), "ptex poly corner");
+ /* Fill in offsets. */
+ int ptex_face_index = 0;
+ PolyCornerIndex *ptex_poly_corner = data->ptex_poly_corner;
+ for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) {
+ const MPoly *poly = &mpoly[poly_index];
+ if (poly->totloop == 4) {
+ ptex_poly_corner[ptex_face_index].poly_index = poly_index;
+ ptex_poly_corner[ptex_face_index].corner = 0;
+ ptex_face_index++;
+ }
+ else {
+ for (int corner = 0; corner < poly->totloop; corner++) {
+ ptex_poly_corner[ptex_face_index].poly_index = poly_index;
+ ptex_poly_corner[ptex_face_index].corner = corner;
+ ptex_face_index++;
+ }
+ }
+ }
}
static void displacement_init_data(SubdivDisplacement *displacement,
@@ -448,43 +417,42 @@ static void displacement_init_data(SubdivDisplacement *displacement,
Mesh *mesh,
const MultiresModifierData *mmd)
{
- MultiresDisplacementData *data = displacement->user_data;
- data->subdiv = subdiv;
- data->grid_size = BKE_subdiv_grid_size_from_level(mmd->totlvl);
- data->mesh = mesh;
- data->mpoly = mesh->mpoly;
- data->mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS);
- data->face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv);
- data->is_initialized = false;
- displacement_data_init_mapping(displacement, mesh);
+ MultiresDisplacementData *data = displacement->user_data;
+ data->subdiv = subdiv;
+ data->grid_size = BKE_subdiv_grid_size_from_level(mmd->totlvl);
+ data->mesh = mesh;
+ data->mpoly = mesh->mpoly;
+ data->mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS);
+ data->face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv);
+ data->is_initialized = false;
+ displacement_data_init_mapping(displacement, mesh);
}
static void displacement_init_functions(SubdivDisplacement *displacement)
{
- displacement->initialize = initialize;
- displacement->eval_displacement = eval_displacement;
- displacement->free = free_displacement;
+ displacement->initialize = initialize;
+ displacement->eval_displacement = eval_displacement;
+ displacement->free = free_displacement;
}
-void BKE_subdiv_displacement_attach_from_multires(
- Subdiv *subdiv,
- Mesh *mesh,
- const MultiresModifierData *mmd)
+void BKE_subdiv_displacement_attach_from_multires(Subdiv *subdiv,
+ Mesh *mesh,
+ const MultiresModifierData *mmd)
{
- /* Make sure we don't have previously assigned displacement. */
- BKE_subdiv_displacement_detach(subdiv);
- /* It is possible to have mesh without MDISPS layer. Happens when using
- * dynamic topology. */
- if (!CustomData_has_layer(&mesh->ldata, CD_MDISPS)) {
- return;
- }
- /* Allocate all required memory. */
- SubdivDisplacement *displacement = MEM_callocN(sizeof(SubdivDisplacement),
- "multires displacement");
- displacement->user_data = MEM_callocN(sizeof(MultiresDisplacementData),
- "multires displacement data");
- displacement_init_data(displacement, subdiv, mesh, mmd);
- displacement_init_functions(displacement);
- /* Finish. */
- subdiv->displacement_evaluator = displacement;
+ /* Make sure we don't have previously assigned displacement. */
+ BKE_subdiv_displacement_detach(subdiv);
+ /* It is possible to have mesh without MDISPS layer. Happens when using
+ * dynamic topology. */
+ if (!CustomData_has_layer(&mesh->ldata, CD_MDISPS)) {
+ return;
+ }
+ /* Allocate all required memory. */
+ SubdivDisplacement *displacement = MEM_callocN(sizeof(SubdivDisplacement),
+ "multires displacement");
+ displacement->user_data = MEM_callocN(sizeof(MultiresDisplacementData),
+ "multires displacement data");
+ displacement_init_data(displacement, subdiv, mesh, mmd);
+ displacement_init_functions(displacement);
+ /* Finish. */
+ subdiv->displacement_evaluator = displacement;
}
diff --git a/source/blender/blenkernel/intern/subdiv_eval.c b/source/blender/blenkernel/intern/subdiv_eval.c
index 7fcedd35e69..34f0eeaab7b 100644
--- a/source/blender/blenkernel/intern/subdiv_eval.c
+++ b/source/blender/blenkernel/intern/subdiv_eval.c
@@ -40,237 +40,198 @@
bool BKE_subdiv_eval_begin(Subdiv *subdiv)
{
- BKE_subdiv_stats_reset(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE);
- if (subdiv->topology_refiner == NULL) {
- /* Happens on input mesh with just loose geometry,
- * or when OpenSubdiv is disabled */
- return false;
- }
- else if (subdiv->evaluator == NULL) {
- BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE);
- subdiv->evaluator = openSubdiv_createEvaluatorFromTopologyRefiner(
- subdiv->topology_refiner);
- BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE);
- if (subdiv->evaluator == NULL) {
- return false;
- }
- }
- else {
- /* TODO(sergey): Check for topology change. */
- }
- BKE_subdiv_eval_init_displacement(subdiv);
- return true;
+ BKE_subdiv_stats_reset(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE);
+ if (subdiv->topology_refiner == NULL) {
+ /* Happens on input mesh with just loose geometry,
+ * or when OpenSubdiv is disabled */
+ return false;
+ }
+ else if (subdiv->evaluator == NULL) {
+ BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE);
+ subdiv->evaluator = openSubdiv_createEvaluatorFromTopologyRefiner(subdiv->topology_refiner);
+ BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE);
+ if (subdiv->evaluator == NULL) {
+ return false;
+ }
+ }
+ else {
+ /* TODO(sergey): Check for topology change. */
+ }
+ BKE_subdiv_eval_init_displacement(subdiv);
+ return true;
}
static void set_coarse_positions(Subdiv *subdiv, const Mesh *mesh)
{
- const MVert *mvert = mesh->mvert;
- const MLoop *mloop = mesh->mloop;
- const MPoly *mpoly = mesh->mpoly;
- /* Mark vertices which needs new coordinates. */
- /* TODO(sergey): This is annoying to calculate this on every update,
- * maybe it's better to cache this mapping. Or make it possible to have
- * OpenSubdiv's vertices match mesh ones? */
- BLI_bitmap *vertex_used_map =
- BLI_BITMAP_NEW(mesh->totvert, "vert used map");
- for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) {
- const MPoly *poly = &mpoly[poly_index];
- for (int corner = 0; corner < poly->totloop; corner++) {
- const MLoop *loop = &mloop[poly->loopstart + corner];
- BLI_BITMAP_ENABLE(vertex_used_map, loop->v);
- }
- }
- for (int vertex_index = 0, manifold_veretx_index = 0;
- vertex_index < mesh->totvert;
- vertex_index++)
- {
- if (!BLI_BITMAP_TEST_BOOL(vertex_used_map, vertex_index)) {
- continue;
- }
- const MVert *vertex = &mvert[vertex_index];
- subdiv->evaluator->setCoarsePositions(
- subdiv->evaluator,
- vertex->co,
- manifold_veretx_index, 1);
- manifold_veretx_index++;
- }
- MEM_freeN(vertex_used_map);
+ const MVert *mvert = mesh->mvert;
+ const MLoop *mloop = mesh->mloop;
+ const MPoly *mpoly = mesh->mpoly;
+ /* Mark vertices which needs new coordinates. */
+ /* TODO(sergey): This is annoying to calculate this on every update,
+ * maybe it's better to cache this mapping. Or make it possible to have
+ * OpenSubdiv's vertices match mesh ones? */
+ BLI_bitmap *vertex_used_map = BLI_BITMAP_NEW(mesh->totvert, "vert used map");
+ for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) {
+ const MPoly *poly = &mpoly[poly_index];
+ for (int corner = 0; corner < poly->totloop; corner++) {
+ const MLoop *loop = &mloop[poly->loopstart + corner];
+ BLI_BITMAP_ENABLE(vertex_used_map, loop->v);
+ }
+ }
+ for (int vertex_index = 0, manifold_veretx_index = 0; vertex_index < mesh->totvert;
+ vertex_index++) {
+ if (!BLI_BITMAP_TEST_BOOL(vertex_used_map, vertex_index)) {
+ continue;
+ }
+ const MVert *vertex = &mvert[vertex_index];
+ subdiv->evaluator->setCoarsePositions(subdiv->evaluator, vertex->co, manifold_veretx_index, 1);
+ manifold_veretx_index++;
+ }
+ MEM_freeN(vertex_used_map);
}
static void set_face_varying_data_from_uv(Subdiv *subdiv,
const MLoopUV *mloopuv,
const int layer_index)
{
- OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
- OpenSubdiv_Evaluator *evaluator = subdiv->evaluator;
- const int num_faces = topology_refiner->getNumFaces(topology_refiner);
- const MLoopUV *mluv = mloopuv;
- /* TODO(sergey): OpenSubdiv's C-API converter can change winding of
- * loops of a face, need to watch for that, to prevent wrong UVs assigned.
- */
- for (int face_index = 0; face_index < num_faces; ++face_index) {
- const int num_face_vertices = topology_refiner->getNumFaceVertices(
- topology_refiner, face_index);
- const int *uv_indicies = topology_refiner->getFaceFVarValueIndices(
- topology_refiner, face_index, layer_index);
- for (int vertex_index = 0;
- vertex_index < num_face_vertices;
- vertex_index++, mluv++)
- {
- evaluator->setFaceVaryingData(evaluator,
- layer_index,
- mluv->uv,
- uv_indicies[vertex_index],
- 1);
- }
- }
+ OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
+ OpenSubdiv_Evaluator *evaluator = subdiv->evaluator;
+ const int num_faces = topology_refiner->getNumFaces(topology_refiner);
+ const MLoopUV *mluv = mloopuv;
+ /* TODO(sergey): OpenSubdiv's C-API converter can change winding of
+ * loops of a face, need to watch for that, to prevent wrong UVs assigned.
+ */
+ for (int face_index = 0; face_index < num_faces; ++face_index) {
+ const int num_face_vertices = topology_refiner->getNumFaceVertices(topology_refiner,
+ face_index);
+ const int *uv_indicies = topology_refiner->getFaceFVarValueIndices(
+ topology_refiner, face_index, layer_index);
+ for (int vertex_index = 0; vertex_index < num_face_vertices; vertex_index++, mluv++) {
+ evaluator->setFaceVaryingData(
+ evaluator, layer_index, mluv->uv, uv_indicies[vertex_index], 1);
+ }
+ }
}
bool BKE_subdiv_eval_update_from_mesh(Subdiv *subdiv, const Mesh *mesh)
{
- if (!BKE_subdiv_eval_begin(subdiv)) {
- return false;
- }
- if (subdiv->evaluator == NULL) {
- /* NOTE: This situation is supposed to be handled by begin(). */
- BLI_assert(!"Is not supposed to happen");
- return false;
- }
- /* Set coordinates of base mesh vertices. */
- set_coarse_positions(subdiv, mesh);
- /* Set face-varyign data to UV maps. */
- const int num_uv_layers =
- CustomData_number_of_layers(&mesh->ldata, CD_MLOOPUV);
- for (int layer_index = 0; layer_index < num_uv_layers; layer_index++) {
- const MLoopUV *mloopuv = CustomData_get_layer_n(
- &mesh->ldata, CD_MLOOPUV, layer_index);
- set_face_varying_data_from_uv(subdiv, mloopuv, layer_index);
- }
- /* Update evaluator to the new coarse geometry. */
- BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_EVALUATOR_REFINE);
- subdiv->evaluator->refine(subdiv->evaluator);
- BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_EVALUATOR_REFINE);
- return true;
+ if (!BKE_subdiv_eval_begin(subdiv)) {
+ return false;
+ }
+ if (subdiv->evaluator == NULL) {
+ /* NOTE: This situation is supposed to be handled by begin(). */
+ BLI_assert(!"Is not supposed to happen");
+ return false;
+ }
+ /* Set coordinates of base mesh vertices. */
+ set_coarse_positions(subdiv, mesh);
+ /* Set face-varyign data to UV maps. */
+ const int num_uv_layers = CustomData_number_of_layers(&mesh->ldata, CD_MLOOPUV);
+ for (int layer_index = 0; layer_index < num_uv_layers; layer_index++) {
+ const MLoopUV *mloopuv = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPUV, layer_index);
+ set_face_varying_data_from_uv(subdiv, mloopuv, layer_index);
+ }
+ /* Update evaluator to the new coarse geometry. */
+ BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_EVALUATOR_REFINE);
+ subdiv->evaluator->refine(subdiv->evaluator);
+ BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_EVALUATOR_REFINE);
+ return true;
}
void BKE_subdiv_eval_init_displacement(Subdiv *subdiv)
{
- if (subdiv->displacement_evaluator == NULL) {
- return;
- }
- if (subdiv->displacement_evaluator->initialize == NULL) {
- return;
- }
- subdiv->displacement_evaluator->initialize(subdiv->displacement_evaluator);
+ if (subdiv->displacement_evaluator == NULL) {
+ return;
+ }
+ if (subdiv->displacement_evaluator->initialize == NULL) {
+ return;
+ }
+ subdiv->displacement_evaluator->initialize(subdiv->displacement_evaluator);
}
/* ========================== Single point queries ========================== */
void BKE_subdiv_eval_limit_point(
- Subdiv *subdiv,
- const int ptex_face_index,
- const float u, const float v,
- float r_P[3])
+ Subdiv *subdiv, const int ptex_face_index, const float u, const float v, float r_P[3])
{
- BKE_subdiv_eval_limit_point_and_derivatives(subdiv,
- ptex_face_index,
- u, v,
- r_P, NULL, NULL);
+ BKE_subdiv_eval_limit_point_and_derivatives(subdiv, ptex_face_index, u, v, r_P, NULL, NULL);
}
-void BKE_subdiv_eval_limit_point_and_derivatives(
- Subdiv *subdiv,
- const int ptex_face_index,
- const float u, const float v,
- float r_P[3], float r_dPdu[3], float r_dPdv[3])
+void BKE_subdiv_eval_limit_point_and_derivatives(Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ float r_P[3],
+ float r_dPdu[3],
+ float r_dPdv[3])
{
- subdiv->evaluator->evaluateLimit(subdiv->evaluator,
- ptex_face_index,
- u, v,
- r_P, r_dPdu, r_dPdv);
+ subdiv->evaluator->evaluateLimit(subdiv->evaluator, ptex_face_index, u, v, r_P, r_dPdu, r_dPdv);
}
-void BKE_subdiv_eval_limit_point_and_normal(
- Subdiv *subdiv,
- const int ptex_face_index,
- const float u, const float v,
- float r_P[3], float r_N[3])
+void BKE_subdiv_eval_limit_point_and_normal(Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ float r_P[3],
+ float r_N[3])
{
- float dPdu[3], dPdv[3];
- BKE_subdiv_eval_limit_point_and_derivatives(subdiv,
- ptex_face_index,
- u, v,
- r_P, dPdu, dPdv);
- cross_v3_v3v3(r_N, dPdu, dPdv);
- normalize_v3(r_N);
+ float dPdu[3], dPdv[3];
+ BKE_subdiv_eval_limit_point_and_derivatives(subdiv, ptex_face_index, u, v, r_P, dPdu, dPdv);
+ cross_v3_v3v3(r_N, dPdu, dPdv);
+ normalize_v3(r_N);
}
-void BKE_subdiv_eval_limit_point_and_short_normal(
- Subdiv *subdiv,
- const int ptex_face_index,
- const float u, const float v,
- float r_P[3], short r_N[3])
+void BKE_subdiv_eval_limit_point_and_short_normal(Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ float r_P[3],
+ short r_N[3])
{
- float N_float[3];
- BKE_subdiv_eval_limit_point_and_normal(subdiv,
- ptex_face_index,
- u, v,
- r_P, N_float);
- normal_float_to_short_v3(r_N, N_float);
+ float N_float[3];
+ BKE_subdiv_eval_limit_point_and_normal(subdiv, ptex_face_index, u, v, r_P, N_float);
+ normal_float_to_short_v3(r_N, N_float);
}
-void BKE_subdiv_eval_face_varying(
- Subdiv *subdiv,
- const int face_varying_channel,
- const int ptex_face_index,
- const float u, const float v,
- float r_face_varying[2])
+void BKE_subdiv_eval_face_varying(Subdiv *subdiv,
+ const int face_varying_channel,
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ float r_face_varying[2])
{
- subdiv->evaluator->evaluateFaceVarying(subdiv->evaluator,
- face_varying_channel,
- ptex_face_index,
- u, v,
- r_face_varying);
+ subdiv->evaluator->evaluateFaceVarying(
+ subdiv->evaluator, face_varying_channel, ptex_face_index, u, v, r_face_varying);
}
-void BKE_subdiv_eval_displacement(
- Subdiv *subdiv,
- const int ptex_face_index,
- const float u, const float v,
- const float dPdu[3], const float dPdv[3],
- float r_D[3])
+void BKE_subdiv_eval_displacement(Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ const float dPdu[3],
+ const float dPdv[3],
+ float r_D[3])
{
- if (subdiv->displacement_evaluator == NULL) {
- zero_v3(r_D);
- return;
- }
- subdiv->displacement_evaluator->eval_displacement(
- subdiv->displacement_evaluator,
- ptex_face_index,
- u, v,
- dPdu, dPdv,
- r_D);
+ if (subdiv->displacement_evaluator == NULL) {
+ zero_v3(r_D);
+ return;
+ }
+ subdiv->displacement_evaluator->eval_displacement(
+ subdiv->displacement_evaluator, ptex_face_index, u, v, dPdu, dPdv, r_D);
}
void BKE_subdiv_eval_final_point(
- Subdiv *subdiv,
- const int ptex_face_index,
- const float u, const float v,
- float r_P[3])
+ Subdiv *subdiv, const int ptex_face_index, const float u, const float v, float r_P[3])
{
- if (subdiv->displacement_evaluator) {
- float dPdu[3], dPdv[3], D[3];
- BKE_subdiv_eval_limit_point_and_derivatives(
- subdiv, ptex_face_index, u, v, r_P, dPdu, dPdv);
- BKE_subdiv_eval_displacement(subdiv,
- ptex_face_index, u, v,
- dPdu, dPdv,
- D);
- add_v3_v3(r_P, D);
- }
- else {
- BKE_subdiv_eval_limit_point(subdiv, ptex_face_index, u, v, r_P);
- }
+ if (subdiv->displacement_evaluator) {
+ float dPdu[3], dPdv[3], D[3];
+ BKE_subdiv_eval_limit_point_and_derivatives(subdiv, ptex_face_index, u, v, r_P, dPdu, dPdv);
+ BKE_subdiv_eval_displacement(subdiv, ptex_face_index, u, v, dPdu, dPdv, D);
+ add_v3_v3(r_P, D);
+ }
+ else {
+ BKE_subdiv_eval_limit_point(subdiv, ptex_face_index, u, v, r_P);
+ }
}
/* =================== Patch queries at given resolution =================== */
@@ -282,118 +243,115 @@ static void buffer_apply_offset(void **buffer, const int offset)
}
/* Write given number of floats to the beginning of given buffer. */
-static void buffer_write_float_value(void **buffer,
- const float *values_buffer, int num_values)
+static void buffer_write_float_value(void **buffer, const float *values_buffer, int num_values)
{
- memcpy(*buffer, values_buffer, sizeof(float) * num_values);
+ memcpy(*buffer, values_buffer, sizeof(float) * num_values);
}
/* Similar to above, just operates with short values. */
-static void buffer_write_short_value(void **buffer,
- const short *values_buffer, int num_values)
+static void buffer_write_short_value(void **buffer, const short *values_buffer, int num_values)
{
- memcpy(*buffer, values_buffer, sizeof(short) * num_values);
+ memcpy(*buffer, values_buffer, sizeof(short) * num_values);
}
-void BKE_subdiv_eval_limit_patch_resolution_point(
- Subdiv *subdiv,
- const int ptex_face_index,
- const int resolution,
- void *buffer, const int offset, const int stride)
+void BKE_subdiv_eval_limit_patch_resolution_point(Subdiv *subdiv,
+ const int ptex_face_index,
+ const int resolution,
+ void *buffer,
+ const int offset,
+ const int stride)
{
- buffer_apply_offset(&buffer, offset);
- const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
- for (int y = 0; y < resolution; y++) {
- const float v = y * inv_resolution_1;
- for (int x = 0; x < resolution; x++) {
- const float u = x * inv_resolution_1;
- BKE_subdiv_eval_limit_point(subdiv,
- ptex_face_index,
- u, v,
- buffer);
- buffer_apply_offset(&buffer, stride);
- }
- }
+ buffer_apply_offset(&buffer, offset);
+ const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
+ for (int y = 0; y < resolution; y++) {
+ const float v = y * inv_resolution_1;
+ for (int x = 0; x < resolution; x++) {
+ const float u = x * inv_resolution_1;
+ BKE_subdiv_eval_limit_point(subdiv, ptex_face_index, u, v, buffer);
+ buffer_apply_offset(&buffer, stride);
+ }
+ }
}
-void BKE_subdiv_eval_limit_patch_resolution_point_and_derivatives(
- Subdiv *subdiv,
- const int ptex_face_index,
- const int resolution,
- void *point_buffer, const int point_offset, const int point_stride,
- void *du_buffer, const int du_offset, const int du_stride,
- void *dv_buffer, const int dv_offset, const int dv_stride)
+void BKE_subdiv_eval_limit_patch_resolution_point_and_derivatives(Subdiv *subdiv,
+ const int ptex_face_index,
+ const int resolution,
+ void *point_buffer,
+ const int point_offset,
+ const int point_stride,
+ void *du_buffer,
+ const int du_offset,
+ const int du_stride,
+ void *dv_buffer,
+ const int dv_offset,
+ const int dv_stride)
{
- buffer_apply_offset(&point_buffer, point_offset);
- buffer_apply_offset(&du_buffer, du_offset);
- buffer_apply_offset(&dv_buffer, dv_offset);
- const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
- for (int y = 0; y < resolution; y++) {
- const float v = y * inv_resolution_1;
- for (int x = 0; x < resolution; x++) {
- const float u = x * inv_resolution_1;
- BKE_subdiv_eval_limit_point_and_derivatives(
- subdiv,
- ptex_face_index,
- u, v,
- point_buffer, du_buffer, dv_buffer);
- buffer_apply_offset(&point_buffer, point_stride);
- buffer_apply_offset(&du_buffer, du_stride);
- buffer_apply_offset(&dv_buffer, dv_stride);
- }
- }
+ buffer_apply_offset(&point_buffer, point_offset);
+ buffer_apply_offset(&du_buffer, du_offset);
+ buffer_apply_offset(&dv_buffer, dv_offset);
+ const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
+ for (int y = 0; y < resolution; y++) {
+ const float v = y * inv_resolution_1;
+ for (int x = 0; x < resolution; x++) {
+ const float u = x * inv_resolution_1;
+ BKE_subdiv_eval_limit_point_and_derivatives(
+ subdiv, ptex_face_index, u, v, point_buffer, du_buffer, dv_buffer);
+ buffer_apply_offset(&point_buffer, point_stride);
+ buffer_apply_offset(&du_buffer, du_stride);
+ buffer_apply_offset(&dv_buffer, dv_stride);
+ }
+ }
}
-void BKE_subdiv_eval_limit_patch_resolution_point_and_normal(
- Subdiv *subdiv,
- const int ptex_face_index,
- const int resolution,
- void *point_buffer, const int point_offset, const int point_stride,
- void *normal_buffer, const int normal_offset, const int normal_stride)
+void BKE_subdiv_eval_limit_patch_resolution_point_and_normal(Subdiv *subdiv,
+ const int ptex_face_index,
+ const int resolution,
+ void *point_buffer,
+ const int point_offset,
+ const int point_stride,
+ void *normal_buffer,
+ const int normal_offset,
+ const int normal_stride)
{
- buffer_apply_offset(&point_buffer, point_offset);
- buffer_apply_offset(&normal_buffer, normal_offset);
- const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
- for (int y = 0; y < resolution; y++) {
- const float v = y * inv_resolution_1;
- for (int x = 0; x < resolution; x++) {
- const float u = x * inv_resolution_1;
- float normal[3];
- BKE_subdiv_eval_limit_point_and_normal(
- subdiv,
- ptex_face_index,
- u, v,
- point_buffer, normal);
- buffer_write_float_value(&normal_buffer, normal, 3);
- buffer_apply_offset(&point_buffer, point_stride);
- buffer_apply_offset(&normal_buffer, normal_stride);
- }
- }
+ buffer_apply_offset(&point_buffer, point_offset);
+ buffer_apply_offset(&normal_buffer, normal_offset);
+ const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
+ for (int y = 0; y < resolution; y++) {
+ const float v = y * inv_resolution_1;
+ for (int x = 0; x < resolution; x++) {
+ const float u = x * inv_resolution_1;
+ float normal[3];
+ BKE_subdiv_eval_limit_point_and_normal(subdiv, ptex_face_index, u, v, point_buffer, normal);
+ buffer_write_float_value(&normal_buffer, normal, 3);
+ buffer_apply_offset(&point_buffer, point_stride);
+ buffer_apply_offset(&normal_buffer, normal_stride);
+ }
+ }
}
-void BKE_subdiv_eval_limit_patch_resolution_point_and_short_normal(
- Subdiv *subdiv,
- const int ptex_face_index,
- const int resolution,
- void *point_buffer, const int point_offset, const int point_stride,
- void *normal_buffer, const int normal_offset, const int normal_stride)
+void BKE_subdiv_eval_limit_patch_resolution_point_and_short_normal(Subdiv *subdiv,
+ const int ptex_face_index,
+ const int resolution,
+ void *point_buffer,
+ const int point_offset,
+ const int point_stride,
+ void *normal_buffer,
+ const int normal_offset,
+ const int normal_stride)
{
- buffer_apply_offset(&point_buffer, point_offset);
- buffer_apply_offset(&normal_buffer, normal_offset);
- const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
- for (int y = 0; y < resolution; y++) {
- const float v = y * inv_resolution_1;
- for (int x = 0; x < resolution; x++) {
- const float u = x * inv_resolution_1;
- short normal[3];
- BKE_subdiv_eval_limit_point_and_short_normal(
- subdiv,
- ptex_face_index,
- u, v,
- point_buffer, normal);
- buffer_write_short_value(&normal_buffer, normal, 3);
- buffer_apply_offset(&point_buffer, point_stride);
- buffer_apply_offset(&normal_buffer, normal_stride);
- }
- }
+ buffer_apply_offset(&point_buffer, point_offset);
+ buffer_apply_offset(&normal_buffer, normal_offset);
+ const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
+ for (int y = 0; y < resolution; y++) {
+ const float v = y * inv_resolution_1;
+ for (int x = 0; x < resolution; x++) {
+ const float u = x * inv_resolution_1;
+ short normal[3];
+ BKE_subdiv_eval_limit_point_and_short_normal(
+ subdiv, ptex_face_index, u, v, point_buffer, normal);
+ buffer_write_short_value(&normal_buffer, normal, 3);
+ buffer_apply_offset(&point_buffer, point_stride);
+ buffer_apply_offset(&normal_buffer, normal_stride);
+ }
+ }
}
diff --git a/source/blender/blenkernel/intern/subdiv_foreach.c b/source/blender/blenkernel/intern/subdiv_foreach.c
index bb01bfd587a..98afbef6c0a 100644
--- a/source/blender/blenkernel/intern/subdiv_foreach.c
+++ b/source/blender/blenkernel/intern/subdiv_foreach.c
@@ -47,34 +47,32 @@
/* Number of ptex faces for a given polygon. */
BLI_INLINE int num_ptex_faces_per_poly_get(const MPoly *poly)
{
- return (poly->totloop == 4) ? 1 : poly->totloop;
+ return (poly->totloop == 4) ? 1 : poly->totloop;
}
BLI_INLINE int num_edges_per_ptex_face_get(const int resolution)
{
- return 2 * (resolution - 1) * resolution;
+ return 2 * (resolution - 1) * resolution;
}
BLI_INLINE int num_inner_edges_per_ptex_face_get(const int resolution)
{
- if (resolution < 2) {
- return 0;
- }
- return (resolution - 2) * resolution +
- (resolution - 1) * (resolution - 1);
+ if (resolution < 2) {
+ return 0;
+ }
+ return (resolution - 2) * resolution + (resolution - 1) * (resolution - 1);
}
/* Number of subdivision polygons per ptex face. */
BLI_INLINE int num_polys_per_ptex_get(const int resolution)
{
- return (resolution - 1) * (resolution - 1);
+ return (resolution - 1) * (resolution - 1);
}
/* Subdivision resolution per given polygon's ptex faces. */
BLI_INLINE int ptex_face_resolution_get(const MPoly *poly, int resolution)
{
- return (poly->totloop == 4) ? (resolution)
- : ((resolution >> 1) + 1);
+ return (poly->totloop == 4) ? (resolution) : ((resolution >> 1) + 1);
}
/* =============================================================================
@@ -82,46 +80,46 @@ BLI_INLINE int ptex_face_resolution_get(const MPoly *poly, int resolution)
*/
typedef struct SubdivForeachTaskContext {
- const Mesh *coarse_mesh;
- const SubdivToMeshSettings *settings;
- /* Callbacks. */
- const SubdivForeachContext *foreach_context;
- /* Counters of geometry in subdivided mesh, initialized as a part of
- * offsets calculation.
- */
- int num_subdiv_vertices;
- int num_subdiv_edges;
- int num_subdiv_loops;
- int num_subdiv_polygons;
- /* Offsets of various geometry in the subdivision mesh arrays. */
- int vertices_corner_offset;
- int vertices_edge_offset;
- int vertices_inner_offset;
- int edge_boundary_offset;
- int edge_inner_offset;
- /* Indexed by coarse polygon index, indicates offset in subdivided mesh
- * vertices, edges and polygons arrays, where first element of the poly
- * begins.
- */
- int *subdiv_vertex_offset;
- int *subdiv_edge_offset;
- int *subdiv_polygon_offset;
- /* Indexed by base face index, element indicates total number of ptex faces
- * created for preceding base faces.
- */
- int *face_ptex_offset;
- /* Bitmap indicating whether vertex was used already or not.
- * - During patch evaluation indicates whether coarse vertex was already
- * evaluated and its position on limit is already known.
- */
- BLI_bitmap *coarse_vertices_used_map;
- /* Bitmap indicating whether edge was used already or not. This includes:
- * - During context initialization it indicates whether subdivided vertices
- * for corresponding edge were already calculated or not.
- * - During patch evaluation it indicates whether vertices along this edge
- * were already evaluated.
- */
- BLI_bitmap *coarse_edges_used_map;
+ const Mesh *coarse_mesh;
+ const SubdivToMeshSettings *settings;
+ /* Callbacks. */
+ const SubdivForeachContext *foreach_context;
+ /* Counters of geometry in subdivided mesh, initialized as a part of
+ * offsets calculation.
+ */
+ int num_subdiv_vertices;
+ int num_subdiv_edges;
+ int num_subdiv_loops;
+ int num_subdiv_polygons;
+ /* Offsets of various geometry in the subdivision mesh arrays. */
+ int vertices_corner_offset;
+ int vertices_edge_offset;
+ int vertices_inner_offset;
+ int edge_boundary_offset;
+ int edge_inner_offset;
+ /* Indexed by coarse polygon index, indicates offset in subdivided mesh
+ * vertices, edges and polygons arrays, where first element of the poly
+ * begins.
+ */
+ int *subdiv_vertex_offset;
+ int *subdiv_edge_offset;
+ int *subdiv_polygon_offset;
+ /* Indexed by base face index, element indicates total number of ptex faces
+ * created for preceding base faces.
+ */
+ int *face_ptex_offset;
+ /* Bitmap indicating whether vertex was used already or not.
+ * - During patch evaluation indicates whether coarse vertex was already
+ * evaluated and its position on limit is already known.
+ */
+ BLI_bitmap *coarse_vertices_used_map;
+ /* Bitmap indicating whether edge was used already or not. This includes:
+ * - During context initialization it indicates whether subdivided vertices
+ * for corresponding edge were already calculated or not.
+ * - During patch evaluation it indicates whether vertices along this edge
+ * were already evaluated.
+ */
+ BLI_bitmap *coarse_edges_used_map;
} SubdivForeachTaskContext;
/* =============================================================================
@@ -130,26 +128,24 @@ typedef struct SubdivForeachTaskContext {
static void *subdiv_foreach_tls_alloc(SubdivForeachTaskContext *ctx)
{
- const SubdivForeachContext *foreach_context = ctx->foreach_context;
- void *tls = NULL;
- if (foreach_context->user_data_tls_size != 0) {
- tls = MEM_mallocN(foreach_context->user_data_tls_size, "tls");
- memcpy(tls,
- foreach_context->user_data_tls,
- foreach_context->user_data_tls_size);
- }
- return tls;
+ const SubdivForeachContext *foreach_context = ctx->foreach_context;
+ void *tls = NULL;
+ if (foreach_context->user_data_tls_size != 0) {
+ tls = MEM_mallocN(foreach_context->user_data_tls_size, "tls");
+ memcpy(tls, foreach_context->user_data_tls, foreach_context->user_data_tls_size);
+ }
+ return tls;
}
static void subdiv_foreach_tls_free(SubdivForeachTaskContext *ctx, void *tls)
{
- if (tls == NULL) {
- return;
- }
- if (ctx->foreach_context != NULL) {
- ctx->foreach_context->user_data_tls_free(tls);
- }
- MEM_freeN(tls);
+ if (tls == NULL) {
+ return;
+ }
+ if (ctx->foreach_context != NULL) {
+ ctx->foreach_context->user_data_tls_free(tls);
+ }
+ MEM_freeN(tls);
}
/* =============================================================================
@@ -159,171 +155,143 @@ static void subdiv_foreach_tls_free(SubdivForeachTaskContext *ctx, void *tls)
/* NOTE: Expects edge map to be zeroed. */
static void subdiv_foreach_ctx_count(SubdivForeachTaskContext *ctx)
{
- /* Reset counters. */
- ctx->num_subdiv_vertices = 0;
- ctx->num_subdiv_edges = 0;
- ctx->num_subdiv_loops = 0;
- ctx->num_subdiv_polygons = 0;
- /* Static geometry counters. */
- const int resolution = ctx->settings->resolution;
- const int no_quad_patch_resolution = ((resolution >> 1) + 1);
- const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
- const int num_inner_vertices_per_quad = (resolution - 2) * (resolution - 2);
- const int num_inner_vertices_per_noquad_patch =
- (no_quad_patch_resolution - 2) * (no_quad_patch_resolution - 2);
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MLoop *coarse_mloop = coarse_mesh->mloop;
- const MPoly *coarse_mpoly = coarse_mesh->mpoly;
- ctx->num_subdiv_vertices = coarse_mesh->totvert;
- ctx->num_subdiv_edges =
- coarse_mesh->totedge * (num_subdiv_vertices_per_coarse_edge + 1);
- /* Calculate extra vertices and edges createdd by non-loose geometry. */
- for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) {
- const MPoly *coarse_poly = &coarse_mpoly[poly_index];
- const int num_ptex_faces_per_poly =
- num_ptex_faces_per_poly_get(coarse_poly);
- for (int corner = 0; corner < coarse_poly->totloop; corner++) {
- const MLoop *loop = &coarse_mloop[coarse_poly->loopstart + corner];
- const bool is_edge_used =
- BLI_BITMAP_TEST_BOOL(ctx->coarse_edges_used_map, loop->e);
- /* Edges which aren't counted yet. */
- if (!is_edge_used) {
- BLI_BITMAP_ENABLE(ctx->coarse_edges_used_map, loop->e);
- ctx->num_subdiv_vertices += num_subdiv_vertices_per_coarse_edge;
- }
- }
- /* Inner vertices of polygon. */
- if (num_ptex_faces_per_poly == 1) {
- ctx->num_subdiv_vertices += num_inner_vertices_per_quad;
- ctx->num_subdiv_edges +=
- num_edges_per_ptex_face_get(resolution - 2) +
- 4 * num_subdiv_vertices_per_coarse_edge;
- ctx->num_subdiv_polygons += num_polys_per_ptex_get(resolution);
- }
- else {
- ctx->num_subdiv_vertices +=
- 1 +
- num_ptex_faces_per_poly * (no_quad_patch_resolution - 2) +
- num_ptex_faces_per_poly * num_inner_vertices_per_noquad_patch;
- ctx->num_subdiv_edges +=
- num_ptex_faces_per_poly *
- (num_inner_edges_per_ptex_face_get(
- no_quad_patch_resolution - 1) +
- (no_quad_patch_resolution - 2) +
- num_subdiv_vertices_per_coarse_edge);
- if (no_quad_patch_resolution >= 3) {
- ctx->num_subdiv_edges += coarse_poly->totloop;
- }
- ctx->num_subdiv_polygons +=
- num_ptex_faces_per_poly *
- num_polys_per_ptex_get(no_quad_patch_resolution);
- }
- }
- /* Calculate extra vertices createdd by loose edges. */
- for (int edge_index = 0; edge_index < coarse_mesh->totedge; edge_index++) {
- if (!BLI_BITMAP_TEST_BOOL(ctx->coarse_edges_used_map, edge_index)) {
- ctx->num_subdiv_vertices += num_subdiv_vertices_per_coarse_edge;
- }
- }
- ctx->num_subdiv_loops = ctx->num_subdiv_polygons * 4;
+ /* Reset counters. */
+ ctx->num_subdiv_vertices = 0;
+ ctx->num_subdiv_edges = 0;
+ ctx->num_subdiv_loops = 0;
+ ctx->num_subdiv_polygons = 0;
+ /* Static geometry counters. */
+ const int resolution = ctx->settings->resolution;
+ const int no_quad_patch_resolution = ((resolution >> 1) + 1);
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ const int num_inner_vertices_per_quad = (resolution - 2) * (resolution - 2);
+ const int num_inner_vertices_per_noquad_patch = (no_quad_patch_resolution - 2) *
+ (no_quad_patch_resolution - 2);
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ ctx->num_subdiv_vertices = coarse_mesh->totvert;
+ ctx->num_subdiv_edges = coarse_mesh->totedge * (num_subdiv_vertices_per_coarse_edge + 1);
+ /* Calculate extra vertices and edges createdd by non-loose geometry. */
+ for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) {
+ const MPoly *coarse_poly = &coarse_mpoly[poly_index];
+ const int num_ptex_faces_per_poly = num_ptex_faces_per_poly_get(coarse_poly);
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const MLoop *loop = &coarse_mloop[coarse_poly->loopstart + corner];
+ const bool is_edge_used = BLI_BITMAP_TEST_BOOL(ctx->coarse_edges_used_map, loop->e);
+ /* Edges which aren't counted yet. */
+ if (!is_edge_used) {
+ BLI_BITMAP_ENABLE(ctx->coarse_edges_used_map, loop->e);
+ ctx->num_subdiv_vertices += num_subdiv_vertices_per_coarse_edge;
+ }
+ }
+ /* Inner vertices of polygon. */
+ if (num_ptex_faces_per_poly == 1) {
+ ctx->num_subdiv_vertices += num_inner_vertices_per_quad;
+ ctx->num_subdiv_edges += num_edges_per_ptex_face_get(resolution - 2) +
+ 4 * num_subdiv_vertices_per_coarse_edge;
+ ctx->num_subdiv_polygons += num_polys_per_ptex_get(resolution);
+ }
+ else {
+ ctx->num_subdiv_vertices += 1 + num_ptex_faces_per_poly * (no_quad_patch_resolution - 2) +
+ num_ptex_faces_per_poly * num_inner_vertices_per_noquad_patch;
+ ctx->num_subdiv_edges += num_ptex_faces_per_poly *
+ (num_inner_edges_per_ptex_face_get(no_quad_patch_resolution - 1) +
+ (no_quad_patch_resolution - 2) +
+ num_subdiv_vertices_per_coarse_edge);
+ if (no_quad_patch_resolution >= 3) {
+ ctx->num_subdiv_edges += coarse_poly->totloop;
+ }
+ ctx->num_subdiv_polygons += num_ptex_faces_per_poly *
+ num_polys_per_ptex_get(no_quad_patch_resolution);
+ }
+ }
+ /* Calculate extra vertices createdd by loose edges. */
+ for (int edge_index = 0; edge_index < coarse_mesh->totedge; edge_index++) {
+ if (!BLI_BITMAP_TEST_BOOL(ctx->coarse_edges_used_map, edge_index)) {
+ ctx->num_subdiv_vertices += num_subdiv_vertices_per_coarse_edge;
+ }
+ }
+ ctx->num_subdiv_loops = ctx->num_subdiv_polygons * 4;
}
static void subdiv_foreach_ctx_init_offsets(SubdivForeachTaskContext *ctx)
{
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- const int resolution = ctx->settings->resolution;
- const int resolution_2 = resolution - 2;
- const int resolution_2_squared = resolution_2 * resolution_2;
- const int no_quad_patch_resolution = ((resolution >> 1) + 1);
- const int num_irregular_vertices_per_patch =
- (no_quad_patch_resolution - 2) * (no_quad_patch_resolution - 1);
- const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
- const int num_subdiv_edges_per_coarse_edge = resolution - 1;
- /* Constant offsets in arrays. */
- ctx->vertices_corner_offset = 0;
- ctx->vertices_edge_offset = coarse_mesh->totvert;
- ctx->vertices_inner_offset =
- ctx->vertices_edge_offset +
- coarse_mesh->totedge * num_subdiv_vertices_per_coarse_edge;
- ctx->edge_boundary_offset = 0;
- ctx->edge_inner_offset =
- ctx->edge_boundary_offset +
- coarse_mesh->totedge * num_subdiv_edges_per_coarse_edge;
- /* "Indexed" offsets. */
- const MPoly *coarse_mpoly = coarse_mesh->mpoly;
- int vertex_offset = 0;
- int edge_offset = 0;
- int polygon_offset = 0;
- for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) {
- const MPoly *coarse_poly = &coarse_mpoly[poly_index];
- const int num_ptex_faces_per_poly =
- num_ptex_faces_per_poly_get(coarse_poly);
- ctx->subdiv_vertex_offset[poly_index] = vertex_offset;
- ctx->subdiv_edge_offset[poly_index] = edge_offset;
- ctx->subdiv_polygon_offset[poly_index] = polygon_offset;
- if (num_ptex_faces_per_poly == 1) {
- vertex_offset += resolution_2_squared;
- edge_offset += num_edges_per_ptex_face_get(resolution - 2) +
- 4 * num_subdiv_vertices_per_coarse_edge;
- polygon_offset += num_polys_per_ptex_get(resolution);
- }
- else {
- vertex_offset +=
- 1 +
- num_ptex_faces_per_poly * num_irregular_vertices_per_patch;
- edge_offset +=
- num_ptex_faces_per_poly *
- (num_inner_edges_per_ptex_face_get(
- no_quad_patch_resolution - 1) +
- (no_quad_patch_resolution - 2) +
- num_subdiv_vertices_per_coarse_edge);
- if (no_quad_patch_resolution >= 3) {
- edge_offset += coarse_poly->totloop;
- }
- polygon_offset +=
- num_ptex_faces_per_poly *
- num_polys_per_ptex_get(no_quad_patch_resolution);
- }
- }
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const int resolution = ctx->settings->resolution;
+ const int resolution_2 = resolution - 2;
+ const int resolution_2_squared = resolution_2 * resolution_2;
+ const int no_quad_patch_resolution = ((resolution >> 1) + 1);
+ const int num_irregular_vertices_per_patch = (no_quad_patch_resolution - 2) *
+ (no_quad_patch_resolution - 1);
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ const int num_subdiv_edges_per_coarse_edge = resolution - 1;
+ /* Constant offsets in arrays. */
+ ctx->vertices_corner_offset = 0;
+ ctx->vertices_edge_offset = coarse_mesh->totvert;
+ ctx->vertices_inner_offset = ctx->vertices_edge_offset +
+ coarse_mesh->totedge * num_subdiv_vertices_per_coarse_edge;
+ ctx->edge_boundary_offset = 0;
+ ctx->edge_inner_offset = ctx->edge_boundary_offset +
+ coarse_mesh->totedge * num_subdiv_edges_per_coarse_edge;
+ /* "Indexed" offsets. */
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ int vertex_offset = 0;
+ int edge_offset = 0;
+ int polygon_offset = 0;
+ for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) {
+ const MPoly *coarse_poly = &coarse_mpoly[poly_index];
+ const int num_ptex_faces_per_poly = num_ptex_faces_per_poly_get(coarse_poly);
+ ctx->subdiv_vertex_offset[poly_index] = vertex_offset;
+ ctx->subdiv_edge_offset[poly_index] = edge_offset;
+ ctx->subdiv_polygon_offset[poly_index] = polygon_offset;
+ if (num_ptex_faces_per_poly == 1) {
+ vertex_offset += resolution_2_squared;
+ edge_offset += num_edges_per_ptex_face_get(resolution - 2) +
+ 4 * num_subdiv_vertices_per_coarse_edge;
+ polygon_offset += num_polys_per_ptex_get(resolution);
+ }
+ else {
+ vertex_offset += 1 + num_ptex_faces_per_poly * num_irregular_vertices_per_patch;
+ edge_offset += num_ptex_faces_per_poly *
+ (num_inner_edges_per_ptex_face_get(no_quad_patch_resolution - 1) +
+ (no_quad_patch_resolution - 2) + num_subdiv_vertices_per_coarse_edge);
+ if (no_quad_patch_resolution >= 3) {
+ edge_offset += coarse_poly->totloop;
+ }
+ polygon_offset += num_ptex_faces_per_poly * num_polys_per_ptex_get(no_quad_patch_resolution);
+ }
+ }
}
-static void subdiv_foreach_ctx_init(Subdiv *subdiv,
- SubdivForeachTaskContext *ctx)
+static void subdiv_foreach_ctx_init(Subdiv *subdiv, SubdivForeachTaskContext *ctx)
{
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- /* Allocate maps and offsets. */
- ctx->coarse_vertices_used_map =
- BLI_BITMAP_NEW(coarse_mesh->totvert, "vertices used map");
- ctx->coarse_edges_used_map =
- BLI_BITMAP_NEW(coarse_mesh->totedge, "edges used map");
- ctx->subdiv_vertex_offset = MEM_malloc_arrayN(
- coarse_mesh->totpoly,
- sizeof(*ctx->subdiv_vertex_offset),
- "vertex_offset");
- ctx->subdiv_edge_offset = MEM_malloc_arrayN(
- coarse_mesh->totpoly,
- sizeof(*ctx->subdiv_edge_offset),
- "subdiv_edge_offset");
- ctx->subdiv_polygon_offset = MEM_malloc_arrayN(
- coarse_mesh->totpoly,
- sizeof(*ctx->subdiv_polygon_offset),
- "subdiv_edge_offset");
- /* Initialize all offsets. */
- subdiv_foreach_ctx_init_offsets(ctx);
- /* Calculate number of geometry in the result subdivision mesh. */
- subdiv_foreach_ctx_count(ctx);
- /* Re-set maps which were used at this step. */
- BLI_bitmap_set_all(ctx->coarse_edges_used_map, false, coarse_mesh->totedge);
- ctx->face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv);
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ /* Allocate maps and offsets. */
+ ctx->coarse_vertices_used_map = BLI_BITMAP_NEW(coarse_mesh->totvert, "vertices used map");
+ ctx->coarse_edges_used_map = BLI_BITMAP_NEW(coarse_mesh->totedge, "edges used map");
+ ctx->subdiv_vertex_offset = MEM_malloc_arrayN(
+ coarse_mesh->totpoly, sizeof(*ctx->subdiv_vertex_offset), "vertex_offset");
+ ctx->subdiv_edge_offset = MEM_malloc_arrayN(
+ coarse_mesh->totpoly, sizeof(*ctx->subdiv_edge_offset), "subdiv_edge_offset");
+ ctx->subdiv_polygon_offset = MEM_malloc_arrayN(
+ coarse_mesh->totpoly, sizeof(*ctx->subdiv_polygon_offset), "subdiv_edge_offset");
+ /* Initialize all offsets. */
+ subdiv_foreach_ctx_init_offsets(ctx);
+ /* Calculate number of geometry in the result subdivision mesh. */
+ subdiv_foreach_ctx_count(ctx);
+ /* Re-set maps which were used at this step. */
+ BLI_bitmap_set_all(ctx->coarse_edges_used_map, false, coarse_mesh->totedge);
+ ctx->face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv);
}
static void subdiv_foreach_ctx_free(SubdivForeachTaskContext *ctx)
{
- MEM_freeN(ctx->coarse_vertices_used_map);
- MEM_freeN(ctx->coarse_edges_used_map);
- MEM_freeN(ctx->subdiv_vertex_offset);
- MEM_freeN(ctx->subdiv_edge_offset);
- MEM_freeN(ctx->subdiv_polygon_offset);
+ MEM_freeN(ctx->coarse_vertices_used_map);
+ MEM_freeN(ctx->coarse_edges_used_map);
+ MEM_freeN(ctx->subdiv_vertex_offset);
+ MEM_freeN(ctx->subdiv_edge_offset);
+ MEM_freeN(ctx->subdiv_polygon_offset);
}
/* =============================================================================
@@ -333,479 +301,409 @@ static void subdiv_foreach_ctx_free(SubdivForeachTaskContext *ctx)
/* Traversal of corner vertices. They are coming from coarse vertices. */
static void subdiv_foreach_corner_vertices_regular_do(
- SubdivForeachTaskContext *ctx,
- void *tls,
- const MPoly *coarse_poly,
- SubdivForeachVertexFromCornerCb vertex_corner,
- bool check_usage)
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly,
+ SubdivForeachVertexFromCornerCb vertex_corner,
+ bool check_usage)
{
- const float weights[4][2] = {{0.0f, 0.0f},
- {1.0f, 0.0f},
- {1.0f, 1.0f},
- {0.0f, 1.0f}};
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MLoop *coarse_mloop = coarse_mesh->mloop;
- const int coarse_poly_index = coarse_poly - coarse_mesh->mpoly;
- const int ptex_face_index = ctx->face_ptex_offset[coarse_poly_index];
- for (int corner = 0; corner < coarse_poly->totloop; corner++) {
- const MLoop *coarse_loop =
- &coarse_mloop[coarse_poly->loopstart + corner];
- if (check_usage &&
- BLI_BITMAP_TEST_AND_SET_ATOMIC(ctx->coarse_vertices_used_map,
- coarse_loop->v))
- {
- continue;
- }
- const int coarse_vertex_index = coarse_loop->v;
- const int subdiv_vertex_index =
- ctx->vertices_corner_offset + coarse_vertex_index;
- const float u = weights[corner][0];
- const float v = weights[corner][1];
- vertex_corner(
- ctx->foreach_context,
- tls,
- ptex_face_index,
- u, v,
- coarse_vertex_index,
- coarse_poly_index,
- 0,
- subdiv_vertex_index);
- }
+ const float weights[4][2] = {{0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f}, {0.0f, 1.0f}};
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ const int coarse_poly_index = coarse_poly - coarse_mesh->mpoly;
+ const int ptex_face_index = ctx->face_ptex_offset[coarse_poly_index];
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const MLoop *coarse_loop = &coarse_mloop[coarse_poly->loopstart + corner];
+ if (check_usage &&
+ BLI_BITMAP_TEST_AND_SET_ATOMIC(ctx->coarse_vertices_used_map, coarse_loop->v)) {
+ continue;
+ }
+ const int coarse_vertex_index = coarse_loop->v;
+ const int subdiv_vertex_index = ctx->vertices_corner_offset + coarse_vertex_index;
+ const float u = weights[corner][0];
+ const float v = weights[corner][1];
+ vertex_corner(ctx->foreach_context,
+ tls,
+ ptex_face_index,
+ u,
+ v,
+ coarse_vertex_index,
+ coarse_poly_index,
+ 0,
+ subdiv_vertex_index);
+ }
}
-static void subdiv_foreach_corner_vertices_regular(
- SubdivForeachTaskContext *ctx,
- void *tls,
- const MPoly *coarse_poly)
+static void subdiv_foreach_corner_vertices_regular(SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
{
- subdiv_foreach_corner_vertices_regular_do(
- ctx, tls, coarse_poly, ctx->foreach_context->vertex_corner, true);
+ subdiv_foreach_corner_vertices_regular_do(
+ ctx, tls, coarse_poly, ctx->foreach_context->vertex_corner, true);
}
static void subdiv_foreach_corner_vertices_special_do(
- SubdivForeachTaskContext *ctx,
- void *tls,
- const MPoly *coarse_poly,
- SubdivForeachVertexFromCornerCb vertex_corner,
- bool check_usage)
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly,
+ SubdivForeachVertexFromCornerCb vertex_corner,
+ bool check_usage)
{
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MLoop *coarse_mloop = coarse_mesh->mloop;
- const int coarse_poly_index = coarse_poly - coarse_mesh->mpoly;
- int ptex_face_index = ctx->face_ptex_offset[coarse_poly_index];
- for (int corner = 0;
- corner < coarse_poly->totloop;
- corner++, ptex_face_index++)
- {
- const MLoop *coarse_loop =
- &coarse_mloop[coarse_poly->loopstart + corner];
- if (check_usage &&
- BLI_BITMAP_TEST_AND_SET_ATOMIC(ctx->coarse_vertices_used_map,
- coarse_loop->v))
- {
- continue;
- }
- const int coarse_vertex_index = coarse_loop->v;
- const int subdiv_vertex_index =
- ctx->vertices_corner_offset + coarse_vertex_index;
- vertex_corner(
- ctx->foreach_context,
- tls,
- ptex_face_index,
- 0.0f, 0.0f,
- coarse_vertex_index,
- coarse_poly_index,
- corner,
- subdiv_vertex_index);
- }
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ const int coarse_poly_index = coarse_poly - coarse_mesh->mpoly;
+ int ptex_face_index = ctx->face_ptex_offset[coarse_poly_index];
+ for (int corner = 0; corner < coarse_poly->totloop; corner++, ptex_face_index++) {
+ const MLoop *coarse_loop = &coarse_mloop[coarse_poly->loopstart + corner];
+ if (check_usage &&
+ BLI_BITMAP_TEST_AND_SET_ATOMIC(ctx->coarse_vertices_used_map, coarse_loop->v)) {
+ continue;
+ }
+ const int coarse_vertex_index = coarse_loop->v;
+ const int subdiv_vertex_index = ctx->vertices_corner_offset + coarse_vertex_index;
+ vertex_corner(ctx->foreach_context,
+ tls,
+ ptex_face_index,
+ 0.0f,
+ 0.0f,
+ coarse_vertex_index,
+ coarse_poly_index,
+ corner,
+ subdiv_vertex_index);
+ }
}
-static void subdiv_foreach_corner_vertices_special(
- SubdivForeachTaskContext *ctx,
- void *tls,
- const MPoly *coarse_poly)
+static void subdiv_foreach_corner_vertices_special(SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
{
- subdiv_foreach_corner_vertices_special_do(
- ctx, tls, coarse_poly, ctx->foreach_context->vertex_corner, true);
+ subdiv_foreach_corner_vertices_special_do(
+ ctx, tls, coarse_poly, ctx->foreach_context->vertex_corner, true);
}
static void subdiv_foreach_corner_vertices(SubdivForeachTaskContext *ctx,
void *tls,
const MPoly *coarse_poly)
{
- if (coarse_poly->totloop == 4) {
- subdiv_foreach_corner_vertices_regular(ctx, tls, coarse_poly);
- }
- else {
- subdiv_foreach_corner_vertices_special(ctx, tls, coarse_poly);
- }
+ if (coarse_poly->totloop == 4) {
+ subdiv_foreach_corner_vertices_regular(ctx, tls, coarse_poly);
+ }
+ else {
+ subdiv_foreach_corner_vertices_special(ctx, tls, coarse_poly);
+ }
}
-static void subdiv_foreach_every_corner_vertices_regular(
- SubdivForeachTaskContext *ctx,
- void *tls,
- const MPoly *coarse_poly)
+static void subdiv_foreach_every_corner_vertices_regular(SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
{
- subdiv_foreach_corner_vertices_regular_do(
- ctx, tls, coarse_poly,
- ctx->foreach_context->vertex_every_corner,
- false);
+ subdiv_foreach_corner_vertices_regular_do(
+ ctx, tls, coarse_poly, ctx->foreach_context->vertex_every_corner, false);
}
-static void subdiv_foreach_every_corner_vertices_special(
- SubdivForeachTaskContext *ctx,
- void *tls,
- const MPoly *coarse_poly)
+static void subdiv_foreach_every_corner_vertices_special(SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
{
- subdiv_foreach_corner_vertices_special_do(
- ctx, tls, coarse_poly,
- ctx->foreach_context->vertex_every_corner,
- false);
+ subdiv_foreach_corner_vertices_special_do(
+ ctx, tls, coarse_poly, ctx->foreach_context->vertex_every_corner, false);
}
-static void subdiv_foreach_every_corner_vertices(
- SubdivForeachTaskContext *ctx,
- void *tls)
+static void subdiv_foreach_every_corner_vertices(SubdivForeachTaskContext *ctx, void *tls)
{
- if (ctx->foreach_context->vertex_every_corner == NULL) {
- return;
- }
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MPoly *coarse_mpoly = coarse_mesh->mpoly;
- for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) {
- const MPoly *coarse_poly = &coarse_mpoly[poly_index];
- if (coarse_poly->totloop == 4) {
- subdiv_foreach_every_corner_vertices_regular(ctx, tls, coarse_poly);
- }
- else {
- subdiv_foreach_every_corner_vertices_special(ctx, tls, coarse_poly);
- }
- }
+ if (ctx->foreach_context->vertex_every_corner == NULL) {
+ return;
+ }
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) {
+ const MPoly *coarse_poly = &coarse_mpoly[poly_index];
+ if (coarse_poly->totloop == 4) {
+ subdiv_foreach_every_corner_vertices_regular(ctx, tls, coarse_poly);
+ }
+ else {
+ subdiv_foreach_every_corner_vertices_special(ctx, tls, coarse_poly);
+ }
+ }
}
/* Traverse of edge vertices. They are coming from coarse edges. */
-static void subdiv_foreach_edge_vertices_regular_do(
- SubdivForeachTaskContext *ctx,
- void *tls,
- const MPoly *coarse_poly,
- SubdivForeachVertexFromEdgeCb vertex_edge,
- bool check_usage)
+static void subdiv_foreach_edge_vertices_regular_do(SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly,
+ SubdivForeachVertexFromEdgeCb vertex_edge,
+ bool check_usage)
{
- const int resolution = ctx->settings->resolution;
- const int resolution_1 = resolution - 1;
- const float inv_resolution_1 = 1.0f / (float)resolution_1;
- const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MEdge *coarse_medge = coarse_mesh->medge;
- const MLoop *coarse_mloop = coarse_mesh->mloop;
- const MPoly *coarse_mpoly = coarse_mesh->mpoly;
- const int coarse_poly_index = coarse_poly - coarse_mpoly;
- const int poly_index = coarse_poly - coarse_mesh->mpoly;
- const int ptex_face_index = ctx->face_ptex_offset[poly_index];
- for (int corner = 0; corner < coarse_poly->totloop; corner++) {
- const MLoop *coarse_loop =
- &coarse_mloop[coarse_poly->loopstart + corner];
- const int coarse_edge_index = coarse_loop->e;
- if (check_usage &&
- BLI_BITMAP_TEST_AND_SET_ATOMIC(ctx->coarse_edges_used_map,
- coarse_edge_index))
- {
- continue;
- }
- const MEdge *coarse_edge = &coarse_medge[coarse_edge_index];
- const bool flip = (coarse_edge->v2 == coarse_loop->v);
- int subdiv_vertex_index =
- ctx->vertices_edge_offset +
- coarse_edge_index * num_subdiv_vertices_per_coarse_edge;
- for (int vertex_index = 0;
- vertex_index < num_subdiv_vertices_per_coarse_edge;
- vertex_index++, subdiv_vertex_index++)
- {
- float fac = (vertex_index + 1) * inv_resolution_1;
- if (flip) {
- fac = 1.0f - fac;
- }
- if (corner >= 2) {
- fac = 1.0f - fac;
- }
- float u, v;
- if ((corner & 1) == 0) {
- u = fac;
- v = (corner == 2) ? 1.0f : 0.0f;
- }
- else {
- u = (corner == 1) ? 1.0f : 0.0f;
- v = fac;
- }
- vertex_edge(
- ctx->foreach_context,
- tls,
- ptex_face_index,
- u, v,
- coarse_edge_index,
- coarse_poly_index,
- 0,
- subdiv_vertex_index);
- }
- }
+ const int resolution = ctx->settings->resolution;
+ const int resolution_1 = resolution - 1;
+ const float inv_resolution_1 = 1.0f / (float)resolution_1;
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_medge = coarse_mesh->medge;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const int coarse_poly_index = coarse_poly - coarse_mpoly;
+ const int poly_index = coarse_poly - coarse_mesh->mpoly;
+ const int ptex_face_index = ctx->face_ptex_offset[poly_index];
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const MLoop *coarse_loop = &coarse_mloop[coarse_poly->loopstart + corner];
+ const int coarse_edge_index = coarse_loop->e;
+ if (check_usage &&
+ BLI_BITMAP_TEST_AND_SET_ATOMIC(ctx->coarse_edges_used_map, coarse_edge_index)) {
+ continue;
+ }
+ const MEdge *coarse_edge = &coarse_medge[coarse_edge_index];
+ const bool flip = (coarse_edge->v2 == coarse_loop->v);
+ int subdiv_vertex_index = ctx->vertices_edge_offset +
+ coarse_edge_index * num_subdiv_vertices_per_coarse_edge;
+ for (int vertex_index = 0; vertex_index < num_subdiv_vertices_per_coarse_edge;
+ vertex_index++, subdiv_vertex_index++) {
+ float fac = (vertex_index + 1) * inv_resolution_1;
+ if (flip) {
+ fac = 1.0f - fac;
+ }
+ if (corner >= 2) {
+ fac = 1.0f - fac;
+ }
+ float u, v;
+ if ((corner & 1) == 0) {
+ u = fac;
+ v = (corner == 2) ? 1.0f : 0.0f;
+ }
+ else {
+ u = (corner == 1) ? 1.0f : 0.0f;
+ v = fac;
+ }
+ vertex_edge(ctx->foreach_context,
+ tls,
+ ptex_face_index,
+ u,
+ v,
+ coarse_edge_index,
+ coarse_poly_index,
+ 0,
+ subdiv_vertex_index);
+ }
+ }
}
-static void subdiv_foreach_edge_vertices_regular(
- SubdivForeachTaskContext *ctx,
- void *tls,
- const MPoly *coarse_poly)
+static void subdiv_foreach_edge_vertices_regular(SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
{
- subdiv_foreach_edge_vertices_regular_do(
- ctx, tls, coarse_poly,
- ctx->foreach_context->vertex_edge,
- true);
+ subdiv_foreach_edge_vertices_regular_do(
+ ctx, tls, coarse_poly, ctx->foreach_context->vertex_edge, true);
}
-static void subdiv_foreach_edge_vertices_special_do(
- SubdivForeachTaskContext *ctx,
- void *tls,
- const MPoly *coarse_poly,
- SubdivForeachVertexFromEdgeCb vertex_edge,
- bool check_usage)
+static void subdiv_foreach_edge_vertices_special_do(SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly,
+ SubdivForeachVertexFromEdgeCb vertex_edge,
+ bool check_usage)
{
- const int resolution = ctx->settings->resolution;
- const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
- const int num_vertices_per_ptex_edge = ((resolution >> 1) + 1);
- const float inv_ptex_resolution_1 =
- 1.0f / (float)(num_vertices_per_ptex_edge - 1);
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MEdge *coarse_medge = coarse_mesh->medge;
- const MLoop *coarse_mloop = coarse_mesh->mloop;
- const MPoly *coarse_mpoly = coarse_mesh->mpoly;
- const int coarse_poly_index = coarse_poly - coarse_mpoly;
- const int poly_index = coarse_poly - coarse_mesh->mpoly;
- const int ptex_face_start_index = ctx->face_ptex_offset[poly_index];
- int ptex_face_index = ptex_face_start_index;
- for (int corner = 0;
- corner < coarse_poly->totloop;
- corner++, ptex_face_index++)
- {
- const MLoop *coarse_loop =
- &coarse_mloop[coarse_poly->loopstart + corner];
- const int coarse_edge_index = coarse_loop->e;
- if (check_usage &&
- BLI_BITMAP_TEST_AND_SET_ATOMIC(ctx->coarse_edges_used_map,
- coarse_edge_index))
- {
- continue;
- }
- const MEdge *coarse_edge = &coarse_medge[coarse_edge_index];
- const bool flip = (coarse_edge->v2 == coarse_loop->v);
- int subdiv_vertex_index =
- ctx->vertices_edge_offset +
- coarse_edge_index * num_subdiv_vertices_per_coarse_edge;
- int veretx_delta = 1;
- if (flip) {
- subdiv_vertex_index += num_subdiv_vertices_per_coarse_edge - 1;
- veretx_delta = -1;
- }
- for (int vertex_index = 1;
- vertex_index < num_vertices_per_ptex_edge;
- vertex_index++, subdiv_vertex_index += veretx_delta)
- {
- const float u = vertex_index * inv_ptex_resolution_1;
- vertex_edge(
- ctx->foreach_context,
- tls,
- ptex_face_index,
- u, 0.0f,
- coarse_edge_index,
- coarse_poly_index,
- corner,
- subdiv_vertex_index);
- }
- const int next_corner = (corner + 1) % coarse_poly->totloop;
- const int next_ptex_face_index = ptex_face_start_index + next_corner;
- for (int vertex_index = 1;
- vertex_index < num_vertices_per_ptex_edge - 1;
- vertex_index++, subdiv_vertex_index += veretx_delta)
- {
- const float v = 1.0f - vertex_index * inv_ptex_resolution_1;
- vertex_edge(
- ctx->foreach_context,
- tls,
- next_ptex_face_index,
- 0.0f, v,
- coarse_edge_index,
- coarse_poly_index,
- next_corner,
- subdiv_vertex_index);
- }
- }
+ const int resolution = ctx->settings->resolution;
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ const int num_vertices_per_ptex_edge = ((resolution >> 1) + 1);
+ const float inv_ptex_resolution_1 = 1.0f / (float)(num_vertices_per_ptex_edge - 1);
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_medge = coarse_mesh->medge;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const int coarse_poly_index = coarse_poly - coarse_mpoly;
+ const int poly_index = coarse_poly - coarse_mesh->mpoly;
+ const int ptex_face_start_index = ctx->face_ptex_offset[poly_index];
+ int ptex_face_index = ptex_face_start_index;
+ for (int corner = 0; corner < coarse_poly->totloop; corner++, ptex_face_index++) {
+ const MLoop *coarse_loop = &coarse_mloop[coarse_poly->loopstart + corner];
+ const int coarse_edge_index = coarse_loop->e;
+ if (check_usage &&
+ BLI_BITMAP_TEST_AND_SET_ATOMIC(ctx->coarse_edges_used_map, coarse_edge_index)) {
+ continue;
+ }
+ const MEdge *coarse_edge = &coarse_medge[coarse_edge_index];
+ const bool flip = (coarse_edge->v2 == coarse_loop->v);
+ int subdiv_vertex_index = ctx->vertices_edge_offset +
+ coarse_edge_index * num_subdiv_vertices_per_coarse_edge;
+ int veretx_delta = 1;
+ if (flip) {
+ subdiv_vertex_index += num_subdiv_vertices_per_coarse_edge - 1;
+ veretx_delta = -1;
+ }
+ for (int vertex_index = 1; vertex_index < num_vertices_per_ptex_edge;
+ vertex_index++, subdiv_vertex_index += veretx_delta) {
+ const float u = vertex_index * inv_ptex_resolution_1;
+ vertex_edge(ctx->foreach_context,
+ tls,
+ ptex_face_index,
+ u,
+ 0.0f,
+ coarse_edge_index,
+ coarse_poly_index,
+ corner,
+ subdiv_vertex_index);
+ }
+ const int next_corner = (corner + 1) % coarse_poly->totloop;
+ const int next_ptex_face_index = ptex_face_start_index + next_corner;
+ for (int vertex_index = 1; vertex_index < num_vertices_per_ptex_edge - 1;
+ vertex_index++, subdiv_vertex_index += veretx_delta) {
+ const float v = 1.0f - vertex_index * inv_ptex_resolution_1;
+ vertex_edge(ctx->foreach_context,
+ tls,
+ next_ptex_face_index,
+ 0.0f,
+ v,
+ coarse_edge_index,
+ coarse_poly_index,
+ next_corner,
+ subdiv_vertex_index);
+ }
+ }
}
-static void subdiv_foreach_edge_vertices_special(
- SubdivForeachTaskContext *ctx,
- void *tls,
- const MPoly *coarse_poly)
+static void subdiv_foreach_edge_vertices_special(SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
{
- subdiv_foreach_edge_vertices_special_do(
- ctx, tls, coarse_poly,
- ctx->foreach_context->vertex_edge,
- true);
+ subdiv_foreach_edge_vertices_special_do(
+ ctx, tls, coarse_poly, ctx->foreach_context->vertex_edge, true);
}
-static void subdiv_foreach_edge_vertices(
- SubdivForeachTaskContext *ctx,
- void *tls,
- const MPoly *coarse_poly)
+static void subdiv_foreach_edge_vertices(SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
{
- if (coarse_poly->totloop == 4) {
- subdiv_foreach_edge_vertices_regular(ctx, tls, coarse_poly);
- }
- else {
- subdiv_foreach_edge_vertices_special(ctx, tls, coarse_poly);
- }
+ if (coarse_poly->totloop == 4) {
+ subdiv_foreach_edge_vertices_regular(ctx, tls, coarse_poly);
+ }
+ else {
+ subdiv_foreach_edge_vertices_special(ctx, tls, coarse_poly);
+ }
}
-static void subdiv_foreach_every_edge_vertices_regular(
- SubdivForeachTaskContext *ctx,
- void *tls,
- const MPoly *coarse_poly)
+static void subdiv_foreach_every_edge_vertices_regular(SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
{
- subdiv_foreach_edge_vertices_regular_do(
- ctx, tls, coarse_poly,
- ctx->foreach_context->vertex_every_edge,
- false);
+ subdiv_foreach_edge_vertices_regular_do(
+ ctx, tls, coarse_poly, ctx->foreach_context->vertex_every_edge, false);
}
-static void subdiv_foreach_every_edge_vertices_special(
- SubdivForeachTaskContext *ctx,
- void *tls,
- const MPoly *coarse_poly)
+static void subdiv_foreach_every_edge_vertices_special(SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
{
- subdiv_foreach_edge_vertices_special_do(
- ctx, tls, coarse_poly,
- ctx->foreach_context->vertex_every_edge,
- false);
+ subdiv_foreach_edge_vertices_special_do(
+ ctx, tls, coarse_poly, ctx->foreach_context->vertex_every_edge, false);
}
-static void subdiv_foreach_every_edge_vertices(
- SubdivForeachTaskContext *ctx,
- void *tls)
+static void subdiv_foreach_every_edge_vertices(SubdivForeachTaskContext *ctx, void *tls)
{
- if (ctx->foreach_context->vertex_every_edge == NULL) {
- return;
- }
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MPoly *coarse_mpoly = coarse_mesh->mpoly;
- for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) {
- const MPoly *coarse_poly = &coarse_mpoly[poly_index];
- if (coarse_poly->totloop == 4) {
- subdiv_foreach_every_edge_vertices_regular(ctx, tls, coarse_poly);
- }
- else {
- subdiv_foreach_every_edge_vertices_special(ctx, tls, coarse_poly);
- }
- }
+ if (ctx->foreach_context->vertex_every_edge == NULL) {
+ return;
+ }
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) {
+ const MPoly *coarse_poly = &coarse_mpoly[poly_index];
+ if (coarse_poly->totloop == 4) {
+ subdiv_foreach_every_edge_vertices_regular(ctx, tls, coarse_poly);
+ }
+ else {
+ subdiv_foreach_every_edge_vertices_special(ctx, tls, coarse_poly);
+ }
+ }
}
/* Traversal of inner vertices, they are coming from ptex patches. */
-static void subdiv_foreach_inner_vertices_regular(
- SubdivForeachTaskContext *ctx,
- void *tls,
- const MPoly *coarse_poly)
+static void subdiv_foreach_inner_vertices_regular(SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
{
- const int resolution = ctx->settings->resolution;
- const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- const int coarse_poly_index = coarse_poly - coarse_mesh->mpoly;
- const int ptex_face_index = ctx->face_ptex_offset[coarse_poly_index];
- const int start_vertex_index = ctx->subdiv_vertex_offset[coarse_poly_index];
- int subdiv_vertex_index =
- ctx->vertices_inner_offset + start_vertex_index;
- for (int y = 1; y < resolution - 1; y++) {
- const float v = y * inv_resolution_1;
- for (int x = 1; x < resolution - 1; x++, subdiv_vertex_index++) {
- const float u = x * inv_resolution_1;
- ctx->foreach_context->vertex_inner(
- ctx->foreach_context,
- tls,
- ptex_face_index,
- u, v,
- coarse_poly_index, 0,
- subdiv_vertex_index);
- }
- }
+ const int resolution = ctx->settings->resolution;
+ const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const int coarse_poly_index = coarse_poly - coarse_mesh->mpoly;
+ const int ptex_face_index = ctx->face_ptex_offset[coarse_poly_index];
+ const int start_vertex_index = ctx->subdiv_vertex_offset[coarse_poly_index];
+ int subdiv_vertex_index = ctx->vertices_inner_offset + start_vertex_index;
+ for (int y = 1; y < resolution - 1; y++) {
+ const float v = y * inv_resolution_1;
+ for (int x = 1; x < resolution - 1; x++, subdiv_vertex_index++) {
+ const float u = x * inv_resolution_1;
+ ctx->foreach_context->vertex_inner(ctx->foreach_context,
+ tls,
+ ptex_face_index,
+ u,
+ v,
+ coarse_poly_index,
+ 0,
+ subdiv_vertex_index);
+ }
+ }
}
-static void subdiv_foreach_inner_vertices_special(
- SubdivForeachTaskContext *ctx,
- void *tls,
- const MPoly *coarse_poly)
+static void subdiv_foreach_inner_vertices_special(SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
{
- const int resolution = ctx->settings->resolution;
- const int ptex_face_resolution = ptex_face_resolution_get(
- coarse_poly, resolution);
- const float inv_ptex_face_resolution_1 =
- 1.0f / (float)(ptex_face_resolution - 1);
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- const int coarse_poly_index = coarse_poly - coarse_mesh->mpoly;
- int ptex_face_index = ctx->face_ptex_offset[coarse_poly_index];
- const int start_vertex_index = ctx->subdiv_vertex_offset[coarse_poly_index];
- int subdiv_vertex_index = ctx->vertices_inner_offset + start_vertex_index;
- ctx->foreach_context->vertex_inner(
- ctx->foreach_context,
- tls,
- ptex_face_index,
- 1.0f, 1.0f,
- coarse_poly_index, 0,
- subdiv_vertex_index);
- subdiv_vertex_index++;
- for (int corner = 0;
- corner < coarse_poly->totloop;
- corner++, ptex_face_index++)
- {
- for (int y = 1; y < ptex_face_resolution - 1; y++) {
- const float v = y * inv_ptex_face_resolution_1;
- for (int x = 1;
- x < ptex_face_resolution; x++,
- subdiv_vertex_index++)
- {
- const float u = x * inv_ptex_face_resolution_1;
- ctx->foreach_context->vertex_inner(
- ctx->foreach_context,
- tls,
- ptex_face_index,
- u, v,
- coarse_poly_index, corner,
- subdiv_vertex_index);
- }
- }
- }
+ const int resolution = ctx->settings->resolution;
+ const int ptex_face_resolution = ptex_face_resolution_get(coarse_poly, resolution);
+ const float inv_ptex_face_resolution_1 = 1.0f / (float)(ptex_face_resolution - 1);
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const int coarse_poly_index = coarse_poly - coarse_mesh->mpoly;
+ int ptex_face_index = ctx->face_ptex_offset[coarse_poly_index];
+ const int start_vertex_index = ctx->subdiv_vertex_offset[coarse_poly_index];
+ int subdiv_vertex_index = ctx->vertices_inner_offset + start_vertex_index;
+ ctx->foreach_context->vertex_inner(ctx->foreach_context,
+ tls,
+ ptex_face_index,
+ 1.0f,
+ 1.0f,
+ coarse_poly_index,
+ 0,
+ subdiv_vertex_index);
+ subdiv_vertex_index++;
+ for (int corner = 0; corner < coarse_poly->totloop; corner++, ptex_face_index++) {
+ for (int y = 1; y < ptex_face_resolution - 1; y++) {
+ const float v = y * inv_ptex_face_resolution_1;
+ for (int x = 1; x < ptex_face_resolution; x++, subdiv_vertex_index++) {
+ const float u = x * inv_ptex_face_resolution_1;
+ ctx->foreach_context->vertex_inner(ctx->foreach_context,
+ tls,
+ ptex_face_index,
+ u,
+ v,
+ coarse_poly_index,
+ corner,
+ subdiv_vertex_index);
+ }
+ }
+ }
}
-static void subdiv_foreach_inner_vertices(
- SubdivForeachTaskContext *ctx,
- void *tls,
- const MPoly *coarse_poly)
+static void subdiv_foreach_inner_vertices(SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
{
- if (coarse_poly->totloop == 4) {
- subdiv_foreach_inner_vertices_regular(ctx, tls, coarse_poly);
- }
- else {
- subdiv_foreach_inner_vertices_special(ctx, tls, coarse_poly);
- }
+ if (coarse_poly->totloop == 4) {
+ subdiv_foreach_inner_vertices_regular(ctx, tls, coarse_poly);
+ }
+ else {
+ subdiv_foreach_inner_vertices_special(ctx, tls, coarse_poly);
+ }
}
/* Traverse all vertices which are emitted from given coarse polygon. */
-static void subdiv_foreach_vertices(SubdivForeachTaskContext *ctx,
- void *tls,
- const int poly_index)
+static void subdiv_foreach_vertices(SubdivForeachTaskContext *ctx, void *tls, const int poly_index)
{
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MPoly *coarse_mpoly = coarse_mesh->mpoly;
- const MPoly *coarse_poly = &coarse_mpoly[poly_index];
- if (ctx->foreach_context->vertex_inner != NULL) {
- subdiv_foreach_inner_vertices(ctx, tls, coarse_poly);
- }
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const MPoly *coarse_poly = &coarse_mpoly[poly_index];
+ if (ctx->foreach_context->vertex_inner != NULL) {
+ subdiv_foreach_inner_vertices(ctx, tls, coarse_poly);
+ }
}
/* =============================================================================
@@ -820,23 +718,16 @@ static int subdiv_foreach_edges_row(SubdivForeachTaskContext *ctx,
const int start_vertex_index,
const int num_edges_per_row)
{
- int subdiv_edge_index = start_subdiv_edge_index;
- int vertex_index = start_vertex_index;
- for (int edge_index = 0;
- edge_index < num_edges_per_row - 1;
- edge_index++, subdiv_edge_index++)
- {
- const int v1 = vertex_index;
- const int v2 = vertex_index + 1;
- ctx->foreach_context->edge(
- ctx->foreach_context,
- tls,
- coarse_edge_index,
- subdiv_edge_index,
- v1, v2);
- vertex_index += 1;
- }
- return subdiv_edge_index;
+ int subdiv_edge_index = start_subdiv_edge_index;
+ int vertex_index = start_vertex_index;
+ for (int edge_index = 0; edge_index < num_edges_per_row - 1; edge_index++, subdiv_edge_index++) {
+ const int v1 = vertex_index;
+ const int v2 = vertex_index + 1;
+ ctx->foreach_context->edge(
+ ctx->foreach_context, tls, coarse_edge_index, subdiv_edge_index, v1, v2);
+ vertex_index += 1;
+ }
+ return subdiv_edge_index;
}
/* TODO(sergey): Coarse edges are always NONE, consider getting rid of them. */
@@ -848,30 +739,23 @@ static int subdiv_foreach_edges_column(SubdivForeachTaskContext *ctx,
const int start_vertex_index,
const int num_edges_per_row)
{
- int subdiv_edge_index = start_subdiv_edge_index;
- int vertex_index = start_vertex_index;
- for (int edge_index = 0;
- edge_index < num_edges_per_row;
- edge_index++, subdiv_edge_index++)
- {
- int coarse_edge_index = ORIGINDEX_NONE;
- if (edge_index == 0) {
- coarse_edge_index = coarse_start_edge_index;
- }
- else if (edge_index == num_edges_per_row - 1) {
- coarse_edge_index = coarse_end_edge_index;
- }
- const int v1 = vertex_index;
- const int v2 = vertex_index + num_edges_per_row;
- ctx->foreach_context->edge(
- ctx->foreach_context,
- tls,
- coarse_edge_index,
- subdiv_edge_index,
- v1, v2);
- vertex_index += 1;
- }
- return subdiv_edge_index;
+ int subdiv_edge_index = start_subdiv_edge_index;
+ int vertex_index = start_vertex_index;
+ for (int edge_index = 0; edge_index < num_edges_per_row; edge_index++, subdiv_edge_index++) {
+ int coarse_edge_index = ORIGINDEX_NONE;
+ if (edge_index == 0) {
+ coarse_edge_index = coarse_start_edge_index;
+ }
+ else if (edge_index == num_edges_per_row - 1) {
+ coarse_edge_index = coarse_end_edge_index;
+ }
+ const int v1 = vertex_index;
+ const int v2 = vertex_index + num_edges_per_row;
+ ctx->foreach_context->edge(
+ ctx->foreach_context, tls, coarse_edge_index, subdiv_edge_index, v1, v2);
+ vertex_index += 1;
+ }
+ return subdiv_edge_index;
}
/* Defines edges between inner vertices of patch, and also edges to the
@@ -892,330 +776,250 @@ static int subdiv_foreach_edges_column(SubdivForeachTaskContext *ctx,
* This is illustrate which parts of geometry is created by code below.
*/
-static void subdiv_foreach_edges_all_patches_regular(
- SubdivForeachTaskContext *ctx,
- void *tls,
- const MPoly *coarse_poly)
+static void subdiv_foreach_edges_all_patches_regular(SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
{
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MEdge *coarse_medge = coarse_mesh->medge;
- const MLoop *coarse_mloop = coarse_mesh->mloop;
- const MPoly *coarse_mpoly = coarse_mesh->mpoly;
- const int poly_index = coarse_poly - coarse_mpoly;
- const int resolution = ctx->settings->resolution;
- const int start_vertex_index =
- ctx->vertices_inner_offset +
- ctx->subdiv_vertex_offset[poly_index];
- const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
- int subdiv_edge_index =
- ctx->edge_inner_offset + ctx->subdiv_edge_offset[poly_index];
- /* Traverse bottom row of edges (0-1, 1-2). */
- subdiv_edge_index = subdiv_foreach_edges_row(
- ctx,
- tls,
- ORIGINDEX_NONE,
- subdiv_edge_index,
- start_vertex_index,
- resolution - 2);
- /* Traverse remaining edges. */
- for (int row = 0; row < resolution - 3; row++) {
- const int start_row_vertex_index =
- start_vertex_index + row * (resolution - 2);
- /* Traverse vertical columns.
- *
- * At first iteration it will be edges (0-3. 1-4, 2-5), then it
- * will be (3-6, 4-7, 5-8) and so on.
- */
- subdiv_edge_index = subdiv_foreach_edges_column(
- ctx,
- tls,
- ORIGINDEX_NONE,
- ORIGINDEX_NONE,
- subdiv_edge_index,
- start_row_vertex_index,
- resolution - 2);
- /* Create horizontal edge row.
- *
- * At first iteration it will be edges (3-4, 4-5), then it will be
- * (6-7, 7-8) and so on.
- */
- subdiv_edge_index = subdiv_foreach_edges_row(
- ctx,
- tls,
- ORIGINDEX_NONE,
- subdiv_edge_index,
- start_row_vertex_index + resolution - 2,
- resolution - 2);
- }
- /* Connect inner part of patch to boundary. */
- for (int corner = 0; corner < coarse_poly->totloop; corner++) {
- const MLoop *coarse_loop =
- &coarse_mloop[coarse_poly->loopstart + corner];
- const MEdge *coarse_edge = &coarse_medge[coarse_loop->e];
- const int start_edge_vertex = ctx->vertices_edge_offset +
- coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
- const bool flip = (coarse_edge->v2 == coarse_loop->v);
- int side_start_index = start_vertex_index;
- int side_stride = 0;
- /* Calculate starting veretx of corresponding inner part of ptex. */
- if (corner == 0) {
- side_stride = 1;
- }
- else if (corner == 1) {
- side_start_index += resolution - 3;
- side_stride = resolution - 2;
- }
- else if (corner == 2) {
- side_start_index += num_subdiv_vertices_per_coarse_edge *
- num_subdiv_vertices_per_coarse_edge - 1;
- side_stride = -1;
- }
- else if (corner == 3) {
- side_start_index += num_subdiv_vertices_per_coarse_edge *
- (num_subdiv_vertices_per_coarse_edge - 1);
- side_stride = -(resolution - 2);
- }
- for (int i = 0; i < resolution - 2; i++, subdiv_edge_index++) {
- const int v1 = (flip)
- ? (start_edge_vertex + (resolution - i - 3))
- : (start_edge_vertex + i);
- const int v2 = side_start_index + side_stride * i;
- ctx->foreach_context->edge(
- ctx->foreach_context,
- tls,
- ORIGINDEX_NONE,
- subdiv_edge_index,
- v1, v2);
- }
- }
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_medge = coarse_mesh->medge;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const int poly_index = coarse_poly - coarse_mpoly;
+ const int resolution = ctx->settings->resolution;
+ const int start_vertex_index = ctx->vertices_inner_offset +
+ ctx->subdiv_vertex_offset[poly_index];
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ int subdiv_edge_index = ctx->edge_inner_offset + ctx->subdiv_edge_offset[poly_index];
+ /* Traverse bottom row of edges (0-1, 1-2). */
+ subdiv_edge_index = subdiv_foreach_edges_row(
+ ctx, tls, ORIGINDEX_NONE, subdiv_edge_index, start_vertex_index, resolution - 2);
+ /* Traverse remaining edges. */
+ for (int row = 0; row < resolution - 3; row++) {
+ const int start_row_vertex_index = start_vertex_index + row * (resolution - 2);
+ /* Traverse vertical columns.
+ *
+ * At first iteration it will be edges (0-3. 1-4, 2-5), then it
+ * will be (3-6, 4-7, 5-8) and so on.
+ */
+ subdiv_edge_index = subdiv_foreach_edges_column(ctx,
+ tls,
+ ORIGINDEX_NONE,
+ ORIGINDEX_NONE,
+ subdiv_edge_index,
+ start_row_vertex_index,
+ resolution - 2);
+ /* Create horizontal edge row.
+ *
+ * At first iteration it will be edges (3-4, 4-5), then it will be
+ * (6-7, 7-8) and so on.
+ */
+ subdiv_edge_index = subdiv_foreach_edges_row(ctx,
+ tls,
+ ORIGINDEX_NONE,
+ subdiv_edge_index,
+ start_row_vertex_index + resolution - 2,
+ resolution - 2);
+ }
+ /* Connect inner part of patch to boundary. */
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const MLoop *coarse_loop = &coarse_mloop[coarse_poly->loopstart + corner];
+ const MEdge *coarse_edge = &coarse_medge[coarse_loop->e];
+ const int start_edge_vertex = ctx->vertices_edge_offset +
+ coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
+ const bool flip = (coarse_edge->v2 == coarse_loop->v);
+ int side_start_index = start_vertex_index;
+ int side_stride = 0;
+ /* Calculate starting veretx of corresponding inner part of ptex. */
+ if (corner == 0) {
+ side_stride = 1;
+ }
+ else if (corner == 1) {
+ side_start_index += resolution - 3;
+ side_stride = resolution - 2;
+ }
+ else if (corner == 2) {
+ side_start_index += num_subdiv_vertices_per_coarse_edge *
+ num_subdiv_vertices_per_coarse_edge -
+ 1;
+ side_stride = -1;
+ }
+ else if (corner == 3) {
+ side_start_index += num_subdiv_vertices_per_coarse_edge *
+ (num_subdiv_vertices_per_coarse_edge - 1);
+ side_stride = -(resolution - 2);
+ }
+ for (int i = 0; i < resolution - 2; i++, subdiv_edge_index++) {
+ const int v1 = (flip) ? (start_edge_vertex + (resolution - i - 3)) : (start_edge_vertex + i);
+ const int v2 = side_start_index + side_stride * i;
+ ctx->foreach_context->edge(
+ ctx->foreach_context, tls, ORIGINDEX_NONE, subdiv_edge_index, v1, v2);
+ }
+ }
}
-static void subdiv_foreach_edges_all_patches_special(
- SubdivForeachTaskContext *ctx,
- void *tls,
- const MPoly *coarse_poly)
+static void subdiv_foreach_edges_all_patches_special(SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
{
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MEdge *coarse_medge = coarse_mesh->medge;
- const MLoop *coarse_mloop = coarse_mesh->mloop;
- const MPoly *coarse_mpoly = coarse_mesh->mpoly;
- const int poly_index = coarse_poly - coarse_mpoly;
- const int resolution = ctx->settings->resolution;
- const int ptex_face_resolution =
- ptex_face_resolution_get(coarse_poly, resolution);
- const int ptex_face_inner_resolution = ptex_face_resolution - 2;
- const int num_inner_vertices_per_ptex =
- (ptex_face_resolution - 1) * (ptex_face_resolution - 2);
- const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
- const int center_vertex_index =
- ctx->vertices_inner_offset +
- ctx->subdiv_vertex_offset[poly_index];
- const int start_vertex_index = center_vertex_index + 1;
- int subdiv_edge_index =
- ctx->edge_inner_offset + ctx->subdiv_edge_offset[poly_index];
- /* Traverse inner ptex edges. */
- for (int corner = 0; corner < coarse_poly->totloop; corner++) {
- const int start_ptex_face_vertex_index =
- start_vertex_index + corner * num_inner_vertices_per_ptex;
- /* Similar steps to regular patch case. */
- subdiv_edge_index = subdiv_foreach_edges_row(
- ctx,
- tls,
- ORIGINDEX_NONE,
- subdiv_edge_index,
- start_ptex_face_vertex_index,
- ptex_face_inner_resolution + 1);
- for (int row = 0; row < ptex_face_inner_resolution - 1; row++) {
- const int start_row_vertex_index =
- start_ptex_face_vertex_index +
- row * (ptex_face_inner_resolution + 1);
- subdiv_edge_index = subdiv_foreach_edges_column(
- ctx,
- tls,
- ORIGINDEX_NONE,
- ORIGINDEX_NONE,
- subdiv_edge_index,
- start_row_vertex_index,
- ptex_face_inner_resolution + 1);
- subdiv_edge_index = subdiv_foreach_edges_row(
- ctx,
- tls,
- ORIGINDEX_NONE,
- subdiv_edge_index,
- start_row_vertex_index + ptex_face_inner_resolution + 1,
- ptex_face_inner_resolution + 1);
- }
- }
- /* Create connections between ptex faces. */
- for (int corner = 0; corner < coarse_poly->totloop; corner++) {
- const int next_corner = (corner + 1) % coarse_poly->totloop;
- int current_patch_vertex_index =
- start_vertex_index + corner * num_inner_vertices_per_ptex +
- ptex_face_inner_resolution;
- int next_path_vertex_index =
- start_vertex_index + next_corner * num_inner_vertices_per_ptex +
- num_inner_vertices_per_ptex - ptex_face_resolution + 1;
- for (int row = 0;
- row < ptex_face_inner_resolution;
- row++, subdiv_edge_index++)
- {
- const int v1 = current_patch_vertex_index;
- const int v2 = next_path_vertex_index;
- ctx->foreach_context->edge(
- ctx->foreach_context,
- tls,
- ORIGINDEX_NONE,
- subdiv_edge_index,
- v1, v2);
- current_patch_vertex_index += ptex_face_inner_resolution + 1;
- next_path_vertex_index += 1;
- }
- }
- /* Create edges from center. */
- if (ptex_face_resolution >= 3) {
- for (int corner = 0;
- corner < coarse_poly->totloop;
- corner++, subdiv_edge_index++)
- {
- const int current_patch_end_vertex_index =
- start_vertex_index + corner * num_inner_vertices_per_ptex +
- num_inner_vertices_per_ptex - 1;
- const int v1 = center_vertex_index;
- const int v2 = current_patch_end_vertex_index;
- ctx->foreach_context->edge(
- ctx->foreach_context,
- tls,
- ORIGINDEX_NONE,
- subdiv_edge_index,
- v1, v2);
- }
- }
- /* Connect inner path of patch to boundary. */
- const MLoop *prev_coarse_loop =
- &coarse_mloop[coarse_poly->loopstart + coarse_poly->totloop - 1];
- for (int corner = 0; corner < coarse_poly->totloop; corner++) {
- const MLoop *coarse_loop =
- &coarse_mloop[coarse_poly->loopstart + corner];
- {
- const MEdge *coarse_edge = &coarse_medge[coarse_loop->e];
- const int start_edge_vertex = ctx->vertices_edge_offset +
- coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
- const bool flip = (coarse_edge->v2 == coarse_loop->v);
- int side_start_index;
- if (ptex_face_resolution >= 3) {
- side_start_index =
- start_vertex_index + num_inner_vertices_per_ptex * corner;
- }
- else {
- side_start_index = center_vertex_index;
- }
- for (int i = 0; i < ptex_face_resolution - 1;
- i++,
- subdiv_edge_index++)
- {
- const int v1 = (flip)
- ? (start_edge_vertex + (resolution - i - 3))
- : (start_edge_vertex + i);
- const int v2 = side_start_index + i;
- ctx->foreach_context->edge(
- ctx->foreach_context,
- tls,
- ORIGINDEX_NONE,
- subdiv_edge_index,
- v1, v2);
- }
- }
- if (ptex_face_resolution >= 3) {
- const MEdge *coarse_edge = &coarse_medge[prev_coarse_loop->e];
- const int start_edge_vertex = ctx->vertices_edge_offset +
- prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
- const bool flip = (coarse_edge->v2 == coarse_loop->v);
- int side_start_index =
- start_vertex_index + num_inner_vertices_per_ptex * corner;
- for (int i = 0;
- i < ptex_face_resolution - 2;
- i++, subdiv_edge_index++)
- {
- const int v1 = (flip)
- ? (start_edge_vertex + (resolution - i - 3))
- : (start_edge_vertex + i);
- const int v2 = side_start_index +
- (ptex_face_inner_resolution + 1) * i;
- ctx->foreach_context->edge(
- ctx->foreach_context,
- tls,
- ORIGINDEX_NONE,
- subdiv_edge_index,
- v1, v2);
- }
- }
- prev_coarse_loop = coarse_loop;
- }
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_medge = coarse_mesh->medge;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const int poly_index = coarse_poly - coarse_mpoly;
+ const int resolution = ctx->settings->resolution;
+ const int ptex_face_resolution = ptex_face_resolution_get(coarse_poly, resolution);
+ const int ptex_face_inner_resolution = ptex_face_resolution - 2;
+ const int num_inner_vertices_per_ptex = (ptex_face_resolution - 1) * (ptex_face_resolution - 2);
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ const int center_vertex_index = ctx->vertices_inner_offset +
+ ctx->subdiv_vertex_offset[poly_index];
+ const int start_vertex_index = center_vertex_index + 1;
+ int subdiv_edge_index = ctx->edge_inner_offset + ctx->subdiv_edge_offset[poly_index];
+ /* Traverse inner ptex edges. */
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const int start_ptex_face_vertex_index = start_vertex_index +
+ corner * num_inner_vertices_per_ptex;
+ /* Similar steps to regular patch case. */
+ subdiv_edge_index = subdiv_foreach_edges_row(ctx,
+ tls,
+ ORIGINDEX_NONE,
+ subdiv_edge_index,
+ start_ptex_face_vertex_index,
+ ptex_face_inner_resolution + 1);
+ for (int row = 0; row < ptex_face_inner_resolution - 1; row++) {
+ const int start_row_vertex_index = start_ptex_face_vertex_index +
+ row * (ptex_face_inner_resolution + 1);
+ subdiv_edge_index = subdiv_foreach_edges_column(ctx,
+ tls,
+ ORIGINDEX_NONE,
+ ORIGINDEX_NONE,
+ subdiv_edge_index,
+ start_row_vertex_index,
+ ptex_face_inner_resolution + 1);
+ subdiv_edge_index = subdiv_foreach_edges_row(ctx,
+ tls,
+ ORIGINDEX_NONE,
+ subdiv_edge_index,
+ start_row_vertex_index +
+ ptex_face_inner_resolution + 1,
+ ptex_face_inner_resolution + 1);
+ }
+ }
+ /* Create connections between ptex faces. */
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const int next_corner = (corner + 1) % coarse_poly->totloop;
+ int current_patch_vertex_index = start_vertex_index + corner * num_inner_vertices_per_ptex +
+ ptex_face_inner_resolution;
+ int next_path_vertex_index = start_vertex_index + next_corner * num_inner_vertices_per_ptex +
+ num_inner_vertices_per_ptex - ptex_face_resolution + 1;
+ for (int row = 0; row < ptex_face_inner_resolution; row++, subdiv_edge_index++) {
+ const int v1 = current_patch_vertex_index;
+ const int v2 = next_path_vertex_index;
+ ctx->foreach_context->edge(
+ ctx->foreach_context, tls, ORIGINDEX_NONE, subdiv_edge_index, v1, v2);
+ current_patch_vertex_index += ptex_face_inner_resolution + 1;
+ next_path_vertex_index += 1;
+ }
+ }
+ /* Create edges from center. */
+ if (ptex_face_resolution >= 3) {
+ for (int corner = 0; corner < coarse_poly->totloop; corner++, subdiv_edge_index++) {
+ const int current_patch_end_vertex_index = start_vertex_index +
+ corner * num_inner_vertices_per_ptex +
+ num_inner_vertices_per_ptex - 1;
+ const int v1 = center_vertex_index;
+ const int v2 = current_patch_end_vertex_index;
+ ctx->foreach_context->edge(
+ ctx->foreach_context, tls, ORIGINDEX_NONE, subdiv_edge_index, v1, v2);
+ }
+ }
+ /* Connect inner path of patch to boundary. */
+ const MLoop *prev_coarse_loop = &coarse_mloop[coarse_poly->loopstart + coarse_poly->totloop - 1];
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const MLoop *coarse_loop = &coarse_mloop[coarse_poly->loopstart + corner];
+ {
+ const MEdge *coarse_edge = &coarse_medge[coarse_loop->e];
+ const int start_edge_vertex = ctx->vertices_edge_offset +
+ coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
+ const bool flip = (coarse_edge->v2 == coarse_loop->v);
+ int side_start_index;
+ if (ptex_face_resolution >= 3) {
+ side_start_index = start_vertex_index + num_inner_vertices_per_ptex * corner;
+ }
+ else {
+ side_start_index = center_vertex_index;
+ }
+ for (int i = 0; i < ptex_face_resolution - 1; i++, subdiv_edge_index++) {
+ const int v1 = (flip) ? (start_edge_vertex + (resolution - i - 3)) :
+ (start_edge_vertex + i);
+ const int v2 = side_start_index + i;
+ ctx->foreach_context->edge(
+ ctx->foreach_context, tls, ORIGINDEX_NONE, subdiv_edge_index, v1, v2);
+ }
+ }
+ if (ptex_face_resolution >= 3) {
+ const MEdge *coarse_edge = &coarse_medge[prev_coarse_loop->e];
+ const int start_edge_vertex = ctx->vertices_edge_offset +
+ prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
+ const bool flip = (coarse_edge->v2 == coarse_loop->v);
+ int side_start_index = start_vertex_index + num_inner_vertices_per_ptex * corner;
+ for (int i = 0; i < ptex_face_resolution - 2; i++, subdiv_edge_index++) {
+ const int v1 = (flip) ? (start_edge_vertex + (resolution - i - 3)) :
+ (start_edge_vertex + i);
+ const int v2 = side_start_index + (ptex_face_inner_resolution + 1) * i;
+ ctx->foreach_context->edge(
+ ctx->foreach_context, tls, ORIGINDEX_NONE, subdiv_edge_index, v1, v2);
+ }
+ }
+ prev_coarse_loop = coarse_loop;
+ }
}
-static void subdiv_foreach_edges_all_patches(
- SubdivForeachTaskContext *ctx,
- void *tls,
- const MPoly *coarse_poly)
+static void subdiv_foreach_edges_all_patches(SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
{
- if (coarse_poly->totloop == 4) {
- subdiv_foreach_edges_all_patches_regular(ctx, tls, coarse_poly);
- }
- else {
- subdiv_foreach_edges_all_patches_special(ctx, tls, coarse_poly);
- }
+ if (coarse_poly->totloop == 4) {
+ subdiv_foreach_edges_all_patches_regular(ctx, tls, coarse_poly);
+ }
+ else {
+ subdiv_foreach_edges_all_patches_special(ctx, tls, coarse_poly);
+ }
}
-static void subdiv_foreach_edges(SubdivForeachTaskContext *ctx,
- void *tls,
- int poly_index)
+static void subdiv_foreach_edges(SubdivForeachTaskContext *ctx, void *tls, int poly_index)
{
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MPoly *coarse_mpoly = coarse_mesh->mpoly;
- const MPoly *coarse_poly = &coarse_mpoly[poly_index];
- subdiv_foreach_edges_all_patches(ctx, tls, coarse_poly);
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const MPoly *coarse_poly = &coarse_mpoly[poly_index];
+ subdiv_foreach_edges_all_patches(ctx, tls, coarse_poly);
}
-static void subdiv_foreach_boundary_edges(
- SubdivForeachTaskContext *ctx,
- void *tls,
- int coarse_edge_index)
+static void subdiv_foreach_boundary_edges(SubdivForeachTaskContext *ctx,
+ void *tls,
+ int coarse_edge_index)
{
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MEdge *coarse_medge = coarse_mesh->medge;
- const MEdge *coarse_edge = &coarse_medge[coarse_edge_index];
- const int resolution = ctx->settings->resolution;
- const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
- const int num_subdiv_edges_per_coarse_edge = resolution - 1;
- int subdiv_edge_index =
- ctx->edge_boundary_offset +
- coarse_edge_index * num_subdiv_edges_per_coarse_edge;
- int last_vertex_index = ctx->vertices_corner_offset + coarse_edge->v1;
- for (int i = 0;
- i < num_subdiv_edges_per_coarse_edge - 1;
- i++, subdiv_edge_index++)
- {
- const int v1 = last_vertex_index;
- const int v2 =
- ctx->vertices_edge_offset +
- coarse_edge_index * num_subdiv_vertices_per_coarse_edge +
- i;
- ctx->foreach_context->edge(
- ctx->foreach_context,
- tls,
- coarse_edge_index,
- subdiv_edge_index,
- v1, v2);
- last_vertex_index = v2;
- }
- const int v1 = last_vertex_index;
- const int v2 = ctx->vertices_corner_offset + coarse_edge->v2;
- ctx->foreach_context->edge(
- ctx->foreach_context,
- tls,
- coarse_edge_index,
- subdiv_edge_index,
- v1, v2);
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_medge = coarse_mesh->medge;
+ const MEdge *coarse_edge = &coarse_medge[coarse_edge_index];
+ const int resolution = ctx->settings->resolution;
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ const int num_subdiv_edges_per_coarse_edge = resolution - 1;
+ int subdiv_edge_index = ctx->edge_boundary_offset +
+ coarse_edge_index * num_subdiv_edges_per_coarse_edge;
+ int last_vertex_index = ctx->vertices_corner_offset + coarse_edge->v1;
+ for (int i = 0; i < num_subdiv_edges_per_coarse_edge - 1; i++, subdiv_edge_index++) {
+ const int v1 = last_vertex_index;
+ const int v2 = ctx->vertices_edge_offset +
+ coarse_edge_index * num_subdiv_vertices_per_coarse_edge + i;
+ ctx->foreach_context->edge(
+ ctx->foreach_context, tls, coarse_edge_index, subdiv_edge_index, v1, v2);
+ last_vertex_index = v2;
+ }
+ const int v1 = last_vertex_index;
+ const int v2 = ctx->vertices_corner_offset + coarse_edge->v2;
+ ctx->foreach_context->edge(
+ ctx->foreach_context, tls, coarse_edge_index, subdiv_edge_index, v1, v2);
}
/* =============================================================================
@@ -1224,844 +1028,829 @@ static void subdiv_foreach_boundary_edges(
static void rotate_indices(const int rot, int *a, int *b, int *c, int *d)
{
- int values[4] = {*a, *b, *c, *d};
- *a = values[(0 - rot + 4) % 4];
- *b = values[(1 - rot + 4) % 4];
- *c = values[(2 - rot + 4) % 4];
- *d = values[(3 - rot + 4) % 4];
+ int values[4] = {*a, *b, *c, *d};
+ *a = values[(0 - rot + 4) % 4];
+ *b = values[(1 - rot + 4) % 4];
+ *c = values[(2 - rot + 4) % 4];
+ *d = values[(3 - rot + 4) % 4];
}
-static void subdiv_foreach_loops_of_poly(
- SubdivForeachTaskContext *ctx,
- void *tls,
- int subdiv_loop_start_index,
- const int ptex_face_index,
- const int coarse_poly_index,
- const int coarse_corner_index,
- const int rotation,
- /*const*/ int v0, /*const*/ int e0,
- /*const*/ int v1, /*const*/ int e1,
- /*const*/ int v2, /*const*/ int e2,
- /*const*/ int v3, /*const*/ int e3,
- const float u, const float v,
- const float du, const float dv)
+static void subdiv_foreach_loops_of_poly(SubdivForeachTaskContext *ctx,
+ void *tls,
+ int subdiv_loop_start_index,
+ const int ptex_face_index,
+ const int coarse_poly_index,
+ const int coarse_corner_index,
+ const int rotation,
+ /*const*/ int v0,
+ /*const*/ int e0,
+ /*const*/ int v1,
+ /*const*/ int e1,
+ /*const*/ int v2,
+ /*const*/ int e2,
+ /*const*/ int v3,
+ /*const*/ int e3,
+ const float u,
+ const float v,
+ const float du,
+ const float dv)
{
- rotate_indices(rotation, &v0, &v1, &v2, &v3);
- rotate_indices(rotation, &e0, &e1, &e2, &e3);
- ctx->foreach_context->loop(
- ctx->foreach_context,
- tls,
- ptex_face_index, u, v,
- ORIGINDEX_NONE,
- coarse_poly_index,
- coarse_corner_index,
- subdiv_loop_start_index + 0,
- v0, e0);
- ctx->foreach_context->loop(
- ctx->foreach_context,
- tls,
- ptex_face_index, u + du, v,
- ORIGINDEX_NONE,
- coarse_poly_index,
- coarse_corner_index,
- subdiv_loop_start_index + 1,
- v1, e1);
- ctx->foreach_context->loop(
- ctx->foreach_context,
- tls,
- ptex_face_index, u + du, v + dv,
- ORIGINDEX_NONE,
- coarse_poly_index,
- coarse_corner_index,
- subdiv_loop_start_index + 2,
- v2, e2);
- ctx->foreach_context->loop(
- ctx->foreach_context,
- tls,
- ptex_face_index, u, v + dv,
- ORIGINDEX_NONE,
- coarse_poly_index,
- coarse_corner_index,
- subdiv_loop_start_index + 3,
- v3, e3);
+ rotate_indices(rotation, &v0, &v1, &v2, &v3);
+ rotate_indices(rotation, &e0, &e1, &e2, &e3);
+ ctx->foreach_context->loop(ctx->foreach_context,
+ tls,
+ ptex_face_index,
+ u,
+ v,
+ ORIGINDEX_NONE,
+ coarse_poly_index,
+ coarse_corner_index,
+ subdiv_loop_start_index + 0,
+ v0,
+ e0);
+ ctx->foreach_context->loop(ctx->foreach_context,
+ tls,
+ ptex_face_index,
+ u + du,
+ v,
+ ORIGINDEX_NONE,
+ coarse_poly_index,
+ coarse_corner_index,
+ subdiv_loop_start_index + 1,
+ v1,
+ e1);
+ ctx->foreach_context->loop(ctx->foreach_context,
+ tls,
+ ptex_face_index,
+ u + du,
+ v + dv,
+ ORIGINDEX_NONE,
+ coarse_poly_index,
+ coarse_corner_index,
+ subdiv_loop_start_index + 2,
+ v2,
+ e2);
+ ctx->foreach_context->loop(ctx->foreach_context,
+ tls,
+ ptex_face_index,
+ u,
+ v + dv,
+ ORIGINDEX_NONE,
+ coarse_poly_index,
+ coarse_corner_index,
+ subdiv_loop_start_index + 3,
+ v3,
+ e3);
}
static void subdiv_foreach_loops_regular(SubdivForeachTaskContext *ctx,
void *tls,
const MPoly *coarse_poly)
{
- const int resolution = ctx->settings->resolution;
- /* Base/coarse mesh information. */
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MEdge *coarse_medge = coarse_mesh->medge;
- const MLoop *coarse_mloop = coarse_mesh->mloop;
- const MPoly *coarse_mpoly = coarse_mesh->mpoly;
- const int coarse_poly_index = coarse_poly - coarse_mpoly;
- const int ptex_resolution =
- ptex_face_resolution_get(coarse_poly, resolution);
- const int ptex_inner_resolution = ptex_resolution - 2;
- const int num_subdiv_edges_per_coarse_edge = resolution - 1;
- const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
- const float inv_ptex_resolution_1 = 1.0f / (float)(ptex_resolution - 1);
- const int ptex_face_index = ctx->face_ptex_offset[coarse_poly_index];
- const int start_vertex_index =
- ctx->vertices_inner_offset +
- ctx->subdiv_vertex_offset[coarse_poly_index];
- const int start_edge_index =
- ctx->edge_inner_offset +
- ctx->subdiv_edge_offset[coarse_poly_index];
- const int start_poly_index = ctx->subdiv_polygon_offset[coarse_poly_index];
- const int start_loop_index = 4 * start_poly_index;
- const float du = inv_ptex_resolution_1;
- const float dv = inv_ptex_resolution_1;
- /* Hi-poly subdivided mesh. */
- int subdiv_loop_index = start_loop_index;
- /* Loops for inner part of ptex. */
- for (int y = 1; y < ptex_resolution - 2; y++) {
- const float v = y * inv_ptex_resolution_1;
- const int inner_y = y - 1;
- for (int x = 1; x < ptex_resolution - 2; x++, subdiv_loop_index += 4) {
- const int inner_x = x - 1;
- const float u = x * inv_ptex_resolution_1;
- /* Vertex indices ordered counter-clockwise. */
- const int v0 = start_vertex_index +
- (inner_y * ptex_inner_resolution + inner_x);
- const int v1 = v0 + 1;
- const int v2 = v0 + ptex_inner_resolution + 1;
- const int v3 = v0 + ptex_inner_resolution;
- /* Edge indices ordered counter-clockwise. */
- const int e0 = start_edge_index +
- (inner_y * (2 * ptex_inner_resolution - 1) + inner_x);
- const int e1 = e0 + ptex_inner_resolution;
- const int e2 = e0 + (2 * ptex_inner_resolution - 1);
- const int e3 = e0 + ptex_inner_resolution - 1;
- subdiv_foreach_loops_of_poly(
- ctx, tls, subdiv_loop_index, ptex_face_index,
- coarse_poly_index, 0,
- 0,
- v0, e0, v1, e1, v2, e2, v3, e3,
- u, v, du, dv);
- }
- }
- /* Loops for faces connecting inner ptex part with boundary. */
- const MLoop *prev_coarse_loop =
- &coarse_mloop[coarse_poly->loopstart + coarse_poly->totloop - 1];
- for (int corner = 0; corner < coarse_poly->totloop; corner++) {
- const MLoop *coarse_loop =
- &coarse_mloop[coarse_poly->loopstart + corner];
- const MEdge *coarse_edge = &coarse_medge[coarse_loop->e];
- const MEdge *prev_coarse_edge = &coarse_medge[prev_coarse_loop->e];
- const int start_edge_vertex = ctx->vertices_edge_offset +
- coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
- const bool flip = (coarse_edge->v2 == coarse_loop->v);
- int side_start_index = start_vertex_index;
- int side_stride = 0;
- int v0 = ctx->vertices_corner_offset + coarse_loop->v;
- int v3, e3;
- int e2_offset, e2_stride;
- float u, v, delta_u, delta_v;
- if (prev_coarse_loop->v == prev_coarse_edge->v1) {
- v3 = ctx->vertices_edge_offset +
- prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge +
- num_subdiv_vertices_per_coarse_edge - 1;
- e3 = ctx->edge_boundary_offset +
- prev_coarse_loop->e * num_subdiv_edges_per_coarse_edge +
- num_subdiv_edges_per_coarse_edge - 1;
- }
- else {
- v3 = ctx->vertices_edge_offset +
- prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
- e3 = ctx->edge_boundary_offset +
- prev_coarse_loop->e * num_subdiv_edges_per_coarse_edge;
- }
- /* Calculate starting veretx of corresponding inner part of ptex. */
- if (corner == 0) {
- side_stride = 1;
- e2_offset = 0;
- e2_stride = 1;
- u = 0.0f;
- v = 0.0f;
- delta_u = du;
- delta_v = 0.0f;
- }
- else if (corner == 1) {
- side_start_index += resolution - 3;
- side_stride = resolution - 2;
- e2_offset = 2 * num_subdiv_edges_per_coarse_edge - 4;
- e2_stride = 2 * num_subdiv_edges_per_coarse_edge - 3;
- u = 1.0f - du;
- v = 0;
- delta_u = 0.0f;
- delta_v = dv;
- }
- else if (corner == 2) {
- side_start_index += num_subdiv_vertices_per_coarse_edge *
- num_subdiv_vertices_per_coarse_edge - 1;
- side_stride = -1;
- e2_offset = num_edges_per_ptex_face_get(resolution - 2) - 1;
- e2_stride = -1;
- u = 1.0f - du;
- v = 1.0f - dv;
- delta_u = -du;
- delta_v = 0.0f;
- }
- else if (corner == 3) {
- side_start_index += num_subdiv_vertices_per_coarse_edge *
- (num_subdiv_vertices_per_coarse_edge - 1);
- side_stride = -(resolution - 2);
- e2_offset = num_edges_per_ptex_face_get(resolution - 2) -
- (2 * num_subdiv_edges_per_coarse_edge - 3);
- e2_stride = -(2 * num_subdiv_edges_per_coarse_edge - 3);
- u = 0.0f;
- v = 1.0f - dv;
- delta_u = 0.0f;
- delta_v = -dv;
- }
- for (int i = 0; i < resolution - 2; i++, subdiv_loop_index += 4) {
- int v1;
- if (flip) {
- v1 = start_edge_vertex + (resolution - i - 3);
- }
- else {
- v1 = start_edge_vertex + i;
- }
- const int v2 = side_start_index + side_stride * i;
- int e0;
- if (flip) {
- e0 = ctx->edge_boundary_offset +
- coarse_loop->e * num_subdiv_edges_per_coarse_edge +
- num_subdiv_edges_per_coarse_edge - i - 1;
- }
- else {
- e0 = ctx->edge_boundary_offset +
- coarse_loop->e * num_subdiv_edges_per_coarse_edge +
- i;
- }
- int e1 = start_edge_index +
- num_edges_per_ptex_face_get(resolution - 2) +
- corner * num_subdiv_vertices_per_coarse_edge +
- i;
- int e2;
- if (i == 0) {
- e2 = start_edge_index +
- num_edges_per_ptex_face_get(resolution - 2) +
- ((corner - 1 + coarse_poly->totloop) %
- coarse_poly->totloop) *
- num_subdiv_vertices_per_coarse_edge +
- num_subdiv_vertices_per_coarse_edge - 1;
- }
- else {
- e2 = start_edge_index + e2_offset + e2_stride * (i - 1);
- }
- subdiv_foreach_loops_of_poly(
- ctx, tls, subdiv_loop_index, ptex_face_index,
- coarse_poly_index, corner,
- corner,
- v0, e0, v1, e1, v2, e2, v3, e3,
- u + delta_u * i, v + delta_v * i, du, dv);
- v0 = v1;
- v3 = v2;
- e3 = e1;
- }
- prev_coarse_loop = coarse_loop;
- }
+ const int resolution = ctx->settings->resolution;
+ /* Base/coarse mesh information. */
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_medge = coarse_mesh->medge;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const int coarse_poly_index = coarse_poly - coarse_mpoly;
+ const int ptex_resolution = ptex_face_resolution_get(coarse_poly, resolution);
+ const int ptex_inner_resolution = ptex_resolution - 2;
+ const int num_subdiv_edges_per_coarse_edge = resolution - 1;
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ const float inv_ptex_resolution_1 = 1.0f / (float)(ptex_resolution - 1);
+ const int ptex_face_index = ctx->face_ptex_offset[coarse_poly_index];
+ const int start_vertex_index = ctx->vertices_inner_offset +
+ ctx->subdiv_vertex_offset[coarse_poly_index];
+ const int start_edge_index = ctx->edge_inner_offset + ctx->subdiv_edge_offset[coarse_poly_index];
+ const int start_poly_index = ctx->subdiv_polygon_offset[coarse_poly_index];
+ const int start_loop_index = 4 * start_poly_index;
+ const float du = inv_ptex_resolution_1;
+ const float dv = inv_ptex_resolution_1;
+ /* Hi-poly subdivided mesh. */
+ int subdiv_loop_index = start_loop_index;
+ /* Loops for inner part of ptex. */
+ for (int y = 1; y < ptex_resolution - 2; y++) {
+ const float v = y * inv_ptex_resolution_1;
+ const int inner_y = y - 1;
+ for (int x = 1; x < ptex_resolution - 2; x++, subdiv_loop_index += 4) {
+ const int inner_x = x - 1;
+ const float u = x * inv_ptex_resolution_1;
+ /* Vertex indices ordered counter-clockwise. */
+ const int v0 = start_vertex_index + (inner_y * ptex_inner_resolution + inner_x);
+ const int v1 = v0 + 1;
+ const int v2 = v0 + ptex_inner_resolution + 1;
+ const int v3 = v0 + ptex_inner_resolution;
+ /* Edge indices ordered counter-clockwise. */
+ const int e0 = start_edge_index + (inner_y * (2 * ptex_inner_resolution - 1) + inner_x);
+ const int e1 = e0 + ptex_inner_resolution;
+ const int e2 = e0 + (2 * ptex_inner_resolution - 1);
+ const int e3 = e0 + ptex_inner_resolution - 1;
+ subdiv_foreach_loops_of_poly(ctx,
+ tls,
+ subdiv_loop_index,
+ ptex_face_index,
+ coarse_poly_index,
+ 0,
+ 0,
+ v0,
+ e0,
+ v1,
+ e1,
+ v2,
+ e2,
+ v3,
+ e3,
+ u,
+ v,
+ du,
+ dv);
+ }
+ }
+ /* Loops for faces connecting inner ptex part with boundary. */
+ const MLoop *prev_coarse_loop = &coarse_mloop[coarse_poly->loopstart + coarse_poly->totloop - 1];
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const MLoop *coarse_loop = &coarse_mloop[coarse_poly->loopstart + corner];
+ const MEdge *coarse_edge = &coarse_medge[coarse_loop->e];
+ const MEdge *prev_coarse_edge = &coarse_medge[prev_coarse_loop->e];
+ const int start_edge_vertex = ctx->vertices_edge_offset +
+ coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
+ const bool flip = (coarse_edge->v2 == coarse_loop->v);
+ int side_start_index = start_vertex_index;
+ int side_stride = 0;
+ int v0 = ctx->vertices_corner_offset + coarse_loop->v;
+ int v3, e3;
+ int e2_offset, e2_stride;
+ float u, v, delta_u, delta_v;
+ if (prev_coarse_loop->v == prev_coarse_edge->v1) {
+ v3 = ctx->vertices_edge_offset + prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge +
+ num_subdiv_vertices_per_coarse_edge - 1;
+ e3 = ctx->edge_boundary_offset + prev_coarse_loop->e * num_subdiv_edges_per_coarse_edge +
+ num_subdiv_edges_per_coarse_edge - 1;
+ }
+ else {
+ v3 = ctx->vertices_edge_offset + prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
+ e3 = ctx->edge_boundary_offset + prev_coarse_loop->e * num_subdiv_edges_per_coarse_edge;
+ }
+ /* Calculate starting veretx of corresponding inner part of ptex. */
+ if (corner == 0) {
+ side_stride = 1;
+ e2_offset = 0;
+ e2_stride = 1;
+ u = 0.0f;
+ v = 0.0f;
+ delta_u = du;
+ delta_v = 0.0f;
+ }
+ else if (corner == 1) {
+ side_start_index += resolution - 3;
+ side_stride = resolution - 2;
+ e2_offset = 2 * num_subdiv_edges_per_coarse_edge - 4;
+ e2_stride = 2 * num_subdiv_edges_per_coarse_edge - 3;
+ u = 1.0f - du;
+ v = 0;
+ delta_u = 0.0f;
+ delta_v = dv;
+ }
+ else if (corner == 2) {
+ side_start_index += num_subdiv_vertices_per_coarse_edge *
+ num_subdiv_vertices_per_coarse_edge -
+ 1;
+ side_stride = -1;
+ e2_offset = num_edges_per_ptex_face_get(resolution - 2) - 1;
+ e2_stride = -1;
+ u = 1.0f - du;
+ v = 1.0f - dv;
+ delta_u = -du;
+ delta_v = 0.0f;
+ }
+ else if (corner == 3) {
+ side_start_index += num_subdiv_vertices_per_coarse_edge *
+ (num_subdiv_vertices_per_coarse_edge - 1);
+ side_stride = -(resolution - 2);
+ e2_offset = num_edges_per_ptex_face_get(resolution - 2) -
+ (2 * num_subdiv_edges_per_coarse_edge - 3);
+ e2_stride = -(2 * num_subdiv_edges_per_coarse_edge - 3);
+ u = 0.0f;
+ v = 1.0f - dv;
+ delta_u = 0.0f;
+ delta_v = -dv;
+ }
+ for (int i = 0; i < resolution - 2; i++, subdiv_loop_index += 4) {
+ int v1;
+ if (flip) {
+ v1 = start_edge_vertex + (resolution - i - 3);
+ }
+ else {
+ v1 = start_edge_vertex + i;
+ }
+ const int v2 = side_start_index + side_stride * i;
+ int e0;
+ if (flip) {
+ e0 = ctx->edge_boundary_offset + coarse_loop->e * num_subdiv_edges_per_coarse_edge +
+ num_subdiv_edges_per_coarse_edge - i - 1;
+ }
+ else {
+ e0 = ctx->edge_boundary_offset + coarse_loop->e * num_subdiv_edges_per_coarse_edge + i;
+ }
+ int e1 = start_edge_index + num_edges_per_ptex_face_get(resolution - 2) +
+ corner * num_subdiv_vertices_per_coarse_edge + i;
+ int e2;
+ if (i == 0) {
+ e2 = start_edge_index + num_edges_per_ptex_face_get(resolution - 2) +
+ ((corner - 1 + coarse_poly->totloop) % coarse_poly->totloop) *
+ num_subdiv_vertices_per_coarse_edge +
+ num_subdiv_vertices_per_coarse_edge - 1;
+ }
+ else {
+ e2 = start_edge_index + e2_offset + e2_stride * (i - 1);
+ }
+ subdiv_foreach_loops_of_poly(ctx,
+ tls,
+ subdiv_loop_index,
+ ptex_face_index,
+ coarse_poly_index,
+ corner,
+ corner,
+ v0,
+ e0,
+ v1,
+ e1,
+ v2,
+ e2,
+ v3,
+ e3,
+ u + delta_u * i,
+ v + delta_v * i,
+ du,
+ dv);
+ v0 = v1;
+ v3 = v2;
+ e3 = e1;
+ }
+ prev_coarse_loop = coarse_loop;
+ }
}
static void subdiv_foreach_loops_special(SubdivForeachTaskContext *ctx,
void *tls,
const MPoly *coarse_poly)
{
- const int resolution = ctx->settings->resolution;
- /* Base/coarse mesh information. */
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MEdge *coarse_medge = coarse_mesh->medge;
- const MLoop *coarse_mloop = coarse_mesh->mloop;
- const MPoly *coarse_mpoly = coarse_mesh->mpoly;
- const int coarse_poly_index = coarse_poly - coarse_mpoly;
- const int ptex_face_resolution =
- ptex_face_resolution_get(coarse_poly, resolution);
- const int ptex_face_inner_resolution = ptex_face_resolution - 2;
- const float inv_ptex_resolution_1 =
- 1.0f / (float)(ptex_face_resolution - 1);
- const int num_inner_vertices_per_ptex =
- (ptex_face_resolution - 1) * (ptex_face_resolution - 2);
- const int num_inner_edges_per_ptex_face =
- num_inner_edges_per_ptex_face_get(
- ptex_face_inner_resolution + 1);
- const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
- const int num_subdiv_edges_per_coarse_edge = resolution - 1;
- const int ptex_face_index = ctx->face_ptex_offset[coarse_poly_index];
- const int center_vertex_index =
- ctx->vertices_inner_offset +
- ctx->subdiv_vertex_offset[coarse_poly_index];
- const int start_vertex_index = center_vertex_index + 1;
- const int start_inner_vertex_index = center_vertex_index + 1;
- const int start_edge_index = ctx->edge_inner_offset +
- ctx->subdiv_edge_offset[coarse_poly_index];
- const int start_poly_index = ctx->subdiv_polygon_offset[coarse_poly_index];
- const int start_loop_index = 4 * start_poly_index;
- const float du = inv_ptex_resolution_1;
- const float dv = inv_ptex_resolution_1;
- /* Hi-poly subdivided mesh. */
- int subdiv_loop_index = start_loop_index;
- for (int corner = 0; corner < coarse_poly->totloop; corner++) {
- const int corner_vertex_index =
- start_vertex_index + corner * num_inner_vertices_per_ptex;
- const int corner_edge_index =
- start_edge_index + corner * num_inner_edges_per_ptex_face;
- for (int y = 1; y < ptex_face_inner_resolution; y++) {
- const float v = y * inv_ptex_resolution_1;
- const int inner_y = y - 1;
- for (int x = 1;
- x < ptex_face_inner_resolution + 1;
- x++, subdiv_loop_index += 4)
- {
- const int inner_x = x - 1;
- const float u = x * inv_ptex_resolution_1;
- /* Vertex indices ordered counter-clockwise. */
- const int v0 =
- corner_vertex_index +
- (inner_y * (ptex_face_inner_resolution + 1) + inner_x);
- const int v1 = v0 + 1;
- const int v2 = v0 + ptex_face_inner_resolution + 2;
- const int v3 = v0 + ptex_face_inner_resolution + 1;
- /* Edge indices ordered counter-clockwise. */
- const int e0 = corner_edge_index +
- (inner_y * (2 * ptex_face_inner_resolution + 1) + inner_x);
- const int e1 = e0 + ptex_face_inner_resolution + 1;
- const int e2 = e0 + (2 * ptex_face_inner_resolution + 1);
- const int e3 = e0 + ptex_face_inner_resolution;
- subdiv_foreach_loops_of_poly(
- ctx, tls, subdiv_loop_index, ptex_face_index + corner,
- coarse_poly_index, corner,
- 0,
- v0, e0, v1, e1, v2, e2, v3, e3,
- u, v, du, dv);
- }
- }
- }
- /* Create connections between ptex faces. */
- for (int corner = 0; corner < coarse_poly->totloop; corner++) {
- const int next_corner = (corner + 1) % coarse_poly->totloop;
- const int corner_edge_index =
- start_edge_index + corner * num_inner_edges_per_ptex_face;
- const int next_corner_edge_index =
- start_edge_index + next_corner * num_inner_edges_per_ptex_face;
- int current_patch_vertex_index =
- start_inner_vertex_index +
- corner * num_inner_vertices_per_ptex +
- ptex_face_inner_resolution;
- int next_path_vertex_index =
- start_inner_vertex_index +
- next_corner * num_inner_vertices_per_ptex +
- num_inner_vertices_per_ptex - ptex_face_resolution + 1;
- int v0 = current_patch_vertex_index;
- int v1 = next_path_vertex_index;
- current_patch_vertex_index += ptex_face_inner_resolution + 1;
- next_path_vertex_index += 1;
- int e0 = start_edge_index +
- coarse_poly->totloop * num_inner_edges_per_ptex_face +
- corner * (ptex_face_resolution - 2);
- int e1 = next_corner_edge_index + num_inner_edges_per_ptex_face -
- ptex_face_resolution + 2;
- int e3 = corner_edge_index + 2 * ptex_face_resolution - 4;
- for (int row = 1;
- row < ptex_face_inner_resolution;
- row++, subdiv_loop_index += 4)
- {
- const int v2 = next_path_vertex_index;
- const int v3 = current_patch_vertex_index;
- const int e2 = e0 + 1;
- const float u = row * du;
- const float v = 1.0f - dv;
- subdiv_foreach_loops_of_poly(
- ctx, tls, subdiv_loop_index, ptex_face_index + next_corner,
- coarse_poly_index, next_corner,
- 3,
- v0, e0, v1, e1, v2, e2, v3, e3,
- u, v, du, dv);
- current_patch_vertex_index += ptex_face_inner_resolution + 1;
- next_path_vertex_index += 1;
- v0 = v3;
- v1 = v2;
- e0 = e2;
- e1 += 1;
- e3 += 2 * ptex_face_resolution - 3;
- }
- }
- /* Create loops from center. */
- if (ptex_face_resolution >= 3) {
- const int start_center_edge_index =
- start_edge_index +
- (num_inner_edges_per_ptex_face +
- ptex_face_inner_resolution) * coarse_poly->totloop;
- const int start_boundary_edge =
- start_edge_index +
- coarse_poly->totloop * num_inner_edges_per_ptex_face +
- ptex_face_inner_resolution - 1;
- for (int corner = 0, prev_corner = coarse_poly->totloop - 1;
- corner < coarse_poly->totloop;
- prev_corner = corner, corner++, subdiv_loop_index += 4)
- {
- const int corner_edge_index =
- start_edge_index +
- corner * num_inner_edges_per_ptex_face;
- const int current_patch_end_vertex_index =
- start_vertex_index + corner * num_inner_vertices_per_ptex +
- num_inner_vertices_per_ptex - 1;
- const int prev_current_patch_end_vertex_index =
- start_vertex_index + prev_corner *
- num_inner_vertices_per_ptex +
- num_inner_vertices_per_ptex - 1;
- const int v0 = center_vertex_index;
- const int v1 = prev_current_patch_end_vertex_index;
- const int v2 = current_patch_end_vertex_index - 1;
- const int v3 = current_patch_end_vertex_index;
- const int e0 = start_center_edge_index + prev_corner;
- const int e1 = start_boundary_edge +
- prev_corner * (ptex_face_inner_resolution);
- const int e2 = corner_edge_index +
- num_inner_edges_per_ptex_face - 1;
- const int e3 = start_center_edge_index + corner;
- const float u = 1.0f - du;
- const float v = 1.0f - dv;
- subdiv_foreach_loops_of_poly(
- ctx, tls, subdiv_loop_index,
- ptex_face_index + corner,
- coarse_poly_index, corner,
- 2,
- v0, e0, v1, e1, v2, e2, v3, e3,
- u, v, du, dv);
- }
- }
- /* Loops for faces connecting inner ptex part with boundary. */
- const MLoop *prev_coarse_loop =
- &coarse_mloop[coarse_poly->loopstart + coarse_poly->totloop - 1];
- for (int prev_corner = coarse_poly->totloop - 1, corner = 0;
- corner < coarse_poly->totloop;
- prev_corner = corner, corner++)
- {
- const MLoop *coarse_loop =
- &coarse_mloop[coarse_poly->loopstart + corner];
- const MEdge *coarse_edge = &coarse_medge[coarse_loop->e];
- const MEdge *prev_coarse_edge = &coarse_medge[prev_coarse_loop->e];
- const bool flip = (coarse_edge->v2 == coarse_loop->v);
- const int start_edge_vertex = ctx->vertices_edge_offset +
- coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
- const int corner_vertex_index =
- start_vertex_index + corner * num_inner_vertices_per_ptex;
- const int corner_edge_index =
- start_edge_index + corner * num_inner_edges_per_ptex_face;
- /* Create loops for polygons along U axis. */
- int v0 = ctx->vertices_corner_offset + coarse_loop->v;
- int v3, e3;
- if (prev_coarse_loop->v == prev_coarse_edge->v1) {
- v3 = ctx->vertices_edge_offset +
- prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge +
- num_subdiv_vertices_per_coarse_edge - 1;
- e3 = ctx->edge_boundary_offset +
- prev_coarse_loop->e * num_subdiv_edges_per_coarse_edge +
- num_subdiv_edges_per_coarse_edge - 1;
- }
- else {
- v3 = ctx->vertices_edge_offset +
- prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
- e3 = ctx->edge_boundary_offset +
- prev_coarse_loop->e * num_subdiv_edges_per_coarse_edge;
- }
- for (int i = 0;
- i <= ptex_face_inner_resolution;
- i++, subdiv_loop_index += 4)
- {
- int v1;
- if (flip) {
- v1 = start_edge_vertex + (resolution - i - 3);
- }
- else {
- v1 = start_edge_vertex + i;
- }
- int v2;
- if (ptex_face_inner_resolution >= 1) {
- v2 = corner_vertex_index + i;
- }
- else {
- v2 = center_vertex_index;
- }
- int e0;
- if (flip) {
- e0 = ctx->edge_boundary_offset +
- coarse_loop->e * num_subdiv_edges_per_coarse_edge +
- num_subdiv_edges_per_coarse_edge - i - 1;
- }
- else {
- e0 = ctx->edge_boundary_offset +
- coarse_loop->e * num_subdiv_edges_per_coarse_edge +
- i;
- }
- int e1 = start_edge_index +
- corner * (2 * ptex_face_inner_resolution + 1);
- if (ptex_face_resolution >= 3) {
- e1 += coarse_poly->totloop * (num_inner_edges_per_ptex_face +
- ptex_face_inner_resolution + 1) +
- i;
- }
- int e2 = 0;
- if (i == 0 && ptex_face_resolution >= 3) {
- e2 = start_edge_index +
- coarse_poly->totloop *
- (num_inner_edges_per_ptex_face +
- ptex_face_inner_resolution + 1) +
- corner * (2 * ptex_face_inner_resolution + 1) +
- ptex_face_inner_resolution + 1;
- }
- else if (i == 0 && ptex_face_resolution < 3) {
- e2 = start_edge_index +
- prev_corner * (2 * ptex_face_inner_resolution + 1);
- }
- else {
- e2 = corner_edge_index + i - 1;
- }
- const float u = du * i;
- const float v = 0.0f;
- subdiv_foreach_loops_of_poly(
- ctx, tls, subdiv_loop_index, ptex_face_index + corner,
- coarse_poly_index, corner,
- 0,
- v0, e0, v1, e1, v2, e2, v3, e3,
- u, v, du, dv);
- v0 = v1;
- v3 = v2;
- e3 = e1;
- }
- /* Create loops for polygons along V axis. */
- const bool flip_prev = (prev_coarse_edge->v2 == coarse_loop->v);
- v0 = corner_vertex_index;
- if (prev_coarse_loop->v == prev_coarse_edge->v1) {
- v3 = ctx->vertices_edge_offset +
- prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge +
- num_subdiv_vertices_per_coarse_edge - 1;
- }
- else {
- v3 = ctx->vertices_edge_offset +
- prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
- }
- e3 = start_edge_index +
- coarse_poly->totloop *
- (num_inner_edges_per_ptex_face +
- ptex_face_inner_resolution + 1) +
- corner * (2 * ptex_face_inner_resolution + 1) +
- ptex_face_inner_resolution + 1;
- for (int i = 0;
- i <= ptex_face_inner_resolution - 1;
- i++, subdiv_loop_index += 4)
- {
- int v1;
- int e0, e1;
- if (i == ptex_face_inner_resolution - 1) {
- v1 = start_vertex_index +
- prev_corner * num_inner_vertices_per_ptex +
- ptex_face_inner_resolution;
- e1 = start_edge_index +
- coarse_poly->totloop *
- (num_inner_edges_per_ptex_face +
- ptex_face_inner_resolution + 1) +
- prev_corner * (2 * ptex_face_inner_resolution + 1) +
- ptex_face_inner_resolution;
- e0 = start_edge_index +
- coarse_poly->totloop * num_inner_edges_per_ptex_face +
- prev_corner * ptex_face_inner_resolution;
- }
- else {
- v1 = v0 + ptex_face_inner_resolution + 1;
- e0 = corner_edge_index + ptex_face_inner_resolution +
- i * (2 * ptex_face_inner_resolution + 1);
- e1 = e3 + 1;
- }
- int v2 = flip_prev ? v3 - 1 : v3 + 1;
- int e2;
- if (flip_prev) {
- e2 = ctx->edge_boundary_offset +
- prev_coarse_loop->e *
- num_subdiv_edges_per_coarse_edge +
- num_subdiv_edges_per_coarse_edge - 2 - i;
- }
- else {
- e2 = ctx->edge_boundary_offset +
- prev_coarse_loop->e *
- num_subdiv_edges_per_coarse_edge + 1 + i;
- }
- const float u = 0.0f;
- const float v = du * (i + 1);
- subdiv_foreach_loops_of_poly(
- ctx, tls, subdiv_loop_index, ptex_face_index + corner,
- coarse_poly_index, corner,
- 1,
- v0, e0, v1, e1, v2, e2, v3, e3,
- u, v, du, dv);
- v0 = v1;
- v3 = v2;
- e3 = e1;
- }
- prev_coarse_loop = coarse_loop;
- }
+ const int resolution = ctx->settings->resolution;
+ /* Base/coarse mesh information. */
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_medge = coarse_mesh->medge;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const int coarse_poly_index = coarse_poly - coarse_mpoly;
+ const int ptex_face_resolution = ptex_face_resolution_get(coarse_poly, resolution);
+ const int ptex_face_inner_resolution = ptex_face_resolution - 2;
+ const float inv_ptex_resolution_1 = 1.0f / (float)(ptex_face_resolution - 1);
+ const int num_inner_vertices_per_ptex = (ptex_face_resolution - 1) * (ptex_face_resolution - 2);
+ const int num_inner_edges_per_ptex_face = num_inner_edges_per_ptex_face_get(
+ ptex_face_inner_resolution + 1);
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ const int num_subdiv_edges_per_coarse_edge = resolution - 1;
+ const int ptex_face_index = ctx->face_ptex_offset[coarse_poly_index];
+ const int center_vertex_index = ctx->vertices_inner_offset +
+ ctx->subdiv_vertex_offset[coarse_poly_index];
+ const int start_vertex_index = center_vertex_index + 1;
+ const int start_inner_vertex_index = center_vertex_index + 1;
+ const int start_edge_index = ctx->edge_inner_offset + ctx->subdiv_edge_offset[coarse_poly_index];
+ const int start_poly_index = ctx->subdiv_polygon_offset[coarse_poly_index];
+ const int start_loop_index = 4 * start_poly_index;
+ const float du = inv_ptex_resolution_1;
+ const float dv = inv_ptex_resolution_1;
+ /* Hi-poly subdivided mesh. */
+ int subdiv_loop_index = start_loop_index;
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const int corner_vertex_index = start_vertex_index + corner * num_inner_vertices_per_ptex;
+ const int corner_edge_index = start_edge_index + corner * num_inner_edges_per_ptex_face;
+ for (int y = 1; y < ptex_face_inner_resolution; y++) {
+ const float v = y * inv_ptex_resolution_1;
+ const int inner_y = y - 1;
+ for (int x = 1; x < ptex_face_inner_resolution + 1; x++, subdiv_loop_index += 4) {
+ const int inner_x = x - 1;
+ const float u = x * inv_ptex_resolution_1;
+ /* Vertex indices ordered counter-clockwise. */
+ const int v0 = corner_vertex_index +
+ (inner_y * (ptex_face_inner_resolution + 1) + inner_x);
+ const int v1 = v0 + 1;
+ const int v2 = v0 + ptex_face_inner_resolution + 2;
+ const int v3 = v0 + ptex_face_inner_resolution + 1;
+ /* Edge indices ordered counter-clockwise. */
+ const int e0 = corner_edge_index +
+ (inner_y * (2 * ptex_face_inner_resolution + 1) + inner_x);
+ const int e1 = e0 + ptex_face_inner_resolution + 1;
+ const int e2 = e0 + (2 * ptex_face_inner_resolution + 1);
+ const int e3 = e0 + ptex_face_inner_resolution;
+ subdiv_foreach_loops_of_poly(ctx,
+ tls,
+ subdiv_loop_index,
+ ptex_face_index + corner,
+ coarse_poly_index,
+ corner,
+ 0,
+ v0,
+ e0,
+ v1,
+ e1,
+ v2,
+ e2,
+ v3,
+ e3,
+ u,
+ v,
+ du,
+ dv);
+ }
+ }
+ }
+ /* Create connections between ptex faces. */
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const int next_corner = (corner + 1) % coarse_poly->totloop;
+ const int corner_edge_index = start_edge_index + corner * num_inner_edges_per_ptex_face;
+ const int next_corner_edge_index = start_edge_index +
+ next_corner * num_inner_edges_per_ptex_face;
+ int current_patch_vertex_index = start_inner_vertex_index +
+ corner * num_inner_vertices_per_ptex +
+ ptex_face_inner_resolution;
+ int next_path_vertex_index = start_inner_vertex_index +
+ next_corner * num_inner_vertices_per_ptex +
+ num_inner_vertices_per_ptex - ptex_face_resolution + 1;
+ int v0 = current_patch_vertex_index;
+ int v1 = next_path_vertex_index;
+ current_patch_vertex_index += ptex_face_inner_resolution + 1;
+ next_path_vertex_index += 1;
+ int e0 = start_edge_index + coarse_poly->totloop * num_inner_edges_per_ptex_face +
+ corner * (ptex_face_resolution - 2);
+ int e1 = next_corner_edge_index + num_inner_edges_per_ptex_face - ptex_face_resolution + 2;
+ int e3 = corner_edge_index + 2 * ptex_face_resolution - 4;
+ for (int row = 1; row < ptex_face_inner_resolution; row++, subdiv_loop_index += 4) {
+ const int v2 = next_path_vertex_index;
+ const int v3 = current_patch_vertex_index;
+ const int e2 = e0 + 1;
+ const float u = row * du;
+ const float v = 1.0f - dv;
+ subdiv_foreach_loops_of_poly(ctx,
+ tls,
+ subdiv_loop_index,
+ ptex_face_index + next_corner,
+ coarse_poly_index,
+ next_corner,
+ 3,
+ v0,
+ e0,
+ v1,
+ e1,
+ v2,
+ e2,
+ v3,
+ e3,
+ u,
+ v,
+ du,
+ dv);
+ current_patch_vertex_index += ptex_face_inner_resolution + 1;
+ next_path_vertex_index += 1;
+ v0 = v3;
+ v1 = v2;
+ e0 = e2;
+ e1 += 1;
+ e3 += 2 * ptex_face_resolution - 3;
+ }
+ }
+ /* Create loops from center. */
+ if (ptex_face_resolution >= 3) {
+ const int start_center_edge_index = start_edge_index + (num_inner_edges_per_ptex_face +
+ ptex_face_inner_resolution) *
+ coarse_poly->totloop;
+ const int start_boundary_edge = start_edge_index +
+ coarse_poly->totloop * num_inner_edges_per_ptex_face +
+ ptex_face_inner_resolution - 1;
+ for (int corner = 0, prev_corner = coarse_poly->totloop - 1; corner < coarse_poly->totloop;
+ prev_corner = corner, corner++, subdiv_loop_index += 4) {
+ const int corner_edge_index = start_edge_index + corner * num_inner_edges_per_ptex_face;
+ const int current_patch_end_vertex_index = start_vertex_index +
+ corner * num_inner_vertices_per_ptex +
+ num_inner_vertices_per_ptex - 1;
+ const int prev_current_patch_end_vertex_index = start_vertex_index +
+ prev_corner * num_inner_vertices_per_ptex +
+ num_inner_vertices_per_ptex - 1;
+ const int v0 = center_vertex_index;
+ const int v1 = prev_current_patch_end_vertex_index;
+ const int v2 = current_patch_end_vertex_index - 1;
+ const int v3 = current_patch_end_vertex_index;
+ const int e0 = start_center_edge_index + prev_corner;
+ const int e1 = start_boundary_edge + prev_corner * (ptex_face_inner_resolution);
+ const int e2 = corner_edge_index + num_inner_edges_per_ptex_face - 1;
+ const int e3 = start_center_edge_index + corner;
+ const float u = 1.0f - du;
+ const float v = 1.0f - dv;
+ subdiv_foreach_loops_of_poly(ctx,
+ tls,
+ subdiv_loop_index,
+ ptex_face_index + corner,
+ coarse_poly_index,
+ corner,
+ 2,
+ v0,
+ e0,
+ v1,
+ e1,
+ v2,
+ e2,
+ v3,
+ e3,
+ u,
+ v,
+ du,
+ dv);
+ }
+ }
+ /* Loops for faces connecting inner ptex part with boundary. */
+ const MLoop *prev_coarse_loop = &coarse_mloop[coarse_poly->loopstart + coarse_poly->totloop - 1];
+ for (int prev_corner = coarse_poly->totloop - 1, corner = 0; corner < coarse_poly->totloop;
+ prev_corner = corner, corner++) {
+ const MLoop *coarse_loop = &coarse_mloop[coarse_poly->loopstart + corner];
+ const MEdge *coarse_edge = &coarse_medge[coarse_loop->e];
+ const MEdge *prev_coarse_edge = &coarse_medge[prev_coarse_loop->e];
+ const bool flip = (coarse_edge->v2 == coarse_loop->v);
+ const int start_edge_vertex = ctx->vertices_edge_offset +
+ coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
+ const int corner_vertex_index = start_vertex_index + corner * num_inner_vertices_per_ptex;
+ const int corner_edge_index = start_edge_index + corner * num_inner_edges_per_ptex_face;
+ /* Create loops for polygons along U axis. */
+ int v0 = ctx->vertices_corner_offset + coarse_loop->v;
+ int v3, e3;
+ if (prev_coarse_loop->v == prev_coarse_edge->v1) {
+ v3 = ctx->vertices_edge_offset + prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge +
+ num_subdiv_vertices_per_coarse_edge - 1;
+ e3 = ctx->edge_boundary_offset + prev_coarse_loop->e * num_subdiv_edges_per_coarse_edge +
+ num_subdiv_edges_per_coarse_edge - 1;
+ }
+ else {
+ v3 = ctx->vertices_edge_offset + prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
+ e3 = ctx->edge_boundary_offset + prev_coarse_loop->e * num_subdiv_edges_per_coarse_edge;
+ }
+ for (int i = 0; i <= ptex_face_inner_resolution; i++, subdiv_loop_index += 4) {
+ int v1;
+ if (flip) {
+ v1 = start_edge_vertex + (resolution - i - 3);
+ }
+ else {
+ v1 = start_edge_vertex + i;
+ }
+ int v2;
+ if (ptex_face_inner_resolution >= 1) {
+ v2 = corner_vertex_index + i;
+ }
+ else {
+ v2 = center_vertex_index;
+ }
+ int e0;
+ if (flip) {
+ e0 = ctx->edge_boundary_offset + coarse_loop->e * num_subdiv_edges_per_coarse_edge +
+ num_subdiv_edges_per_coarse_edge - i - 1;
+ }
+ else {
+ e0 = ctx->edge_boundary_offset + coarse_loop->e * num_subdiv_edges_per_coarse_edge + i;
+ }
+ int e1 = start_edge_index + corner * (2 * ptex_face_inner_resolution + 1);
+ if (ptex_face_resolution >= 3) {
+ e1 += coarse_poly->totloop *
+ (num_inner_edges_per_ptex_face + ptex_face_inner_resolution + 1) +
+ i;
+ }
+ int e2 = 0;
+ if (i == 0 && ptex_face_resolution >= 3) {
+ e2 = start_edge_index +
+ coarse_poly->totloop *
+ (num_inner_edges_per_ptex_face + ptex_face_inner_resolution + 1) +
+ corner * (2 * ptex_face_inner_resolution + 1) + ptex_face_inner_resolution + 1;
+ }
+ else if (i == 0 && ptex_face_resolution < 3) {
+ e2 = start_edge_index + prev_corner * (2 * ptex_face_inner_resolution + 1);
+ }
+ else {
+ e2 = corner_edge_index + i - 1;
+ }
+ const float u = du * i;
+ const float v = 0.0f;
+ subdiv_foreach_loops_of_poly(ctx,
+ tls,
+ subdiv_loop_index,
+ ptex_face_index + corner,
+ coarse_poly_index,
+ corner,
+ 0,
+ v0,
+ e0,
+ v1,
+ e1,
+ v2,
+ e2,
+ v3,
+ e3,
+ u,
+ v,
+ du,
+ dv);
+ v0 = v1;
+ v3 = v2;
+ e3 = e1;
+ }
+ /* Create loops for polygons along V axis. */
+ const bool flip_prev = (prev_coarse_edge->v2 == coarse_loop->v);
+ v0 = corner_vertex_index;
+ if (prev_coarse_loop->v == prev_coarse_edge->v1) {
+ v3 = ctx->vertices_edge_offset + prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge +
+ num_subdiv_vertices_per_coarse_edge - 1;
+ }
+ else {
+ v3 = ctx->vertices_edge_offset + prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
+ }
+ e3 = start_edge_index +
+ coarse_poly->totloop * (num_inner_edges_per_ptex_face + ptex_face_inner_resolution + 1) +
+ corner * (2 * ptex_face_inner_resolution + 1) + ptex_face_inner_resolution + 1;
+ for (int i = 0; i <= ptex_face_inner_resolution - 1; i++, subdiv_loop_index += 4) {
+ int v1;
+ int e0, e1;
+ if (i == ptex_face_inner_resolution - 1) {
+ v1 = start_vertex_index + prev_corner * num_inner_vertices_per_ptex +
+ ptex_face_inner_resolution;
+ e1 = start_edge_index +
+ coarse_poly->totloop *
+ (num_inner_edges_per_ptex_face + ptex_face_inner_resolution + 1) +
+ prev_corner * (2 * ptex_face_inner_resolution + 1) + ptex_face_inner_resolution;
+ e0 = start_edge_index + coarse_poly->totloop * num_inner_edges_per_ptex_face +
+ prev_corner * ptex_face_inner_resolution;
+ }
+ else {
+ v1 = v0 + ptex_face_inner_resolution + 1;
+ e0 = corner_edge_index + ptex_face_inner_resolution +
+ i * (2 * ptex_face_inner_resolution + 1);
+ e1 = e3 + 1;
+ }
+ int v2 = flip_prev ? v3 - 1 : v3 + 1;
+ int e2;
+ if (flip_prev) {
+ e2 = ctx->edge_boundary_offset + prev_coarse_loop->e * num_subdiv_edges_per_coarse_edge +
+ num_subdiv_edges_per_coarse_edge - 2 - i;
+ }
+ else {
+ e2 = ctx->edge_boundary_offset + prev_coarse_loop->e * num_subdiv_edges_per_coarse_edge +
+ 1 + i;
+ }
+ const float u = 0.0f;
+ const float v = du * (i + 1);
+ subdiv_foreach_loops_of_poly(ctx,
+ tls,
+ subdiv_loop_index,
+ ptex_face_index + corner,
+ coarse_poly_index,
+ corner,
+ 1,
+ v0,
+ e0,
+ v1,
+ e1,
+ v2,
+ e2,
+ v3,
+ e3,
+ u,
+ v,
+ du,
+ dv);
+ v0 = v1;
+ v3 = v2;
+ e3 = e1;
+ }
+ prev_coarse_loop = coarse_loop;
+ }
}
-static void subdiv_foreach_loops(SubdivForeachTaskContext *ctx,
- void *tls,
- int poly_index)
+static void subdiv_foreach_loops(SubdivForeachTaskContext *ctx, void *tls, int poly_index)
{
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MPoly *coarse_mpoly = coarse_mesh->mpoly;
- const MPoly *coarse_poly = &coarse_mpoly[poly_index];
- if (coarse_poly->totloop == 4) {
- subdiv_foreach_loops_regular(ctx, tls, coarse_poly);
- }
- else {
- subdiv_foreach_loops_special(ctx, tls, coarse_poly);
- }
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const MPoly *coarse_poly = &coarse_mpoly[poly_index];
+ if (coarse_poly->totloop == 4) {
+ subdiv_foreach_loops_regular(ctx, tls, coarse_poly);
+ }
+ else {
+ subdiv_foreach_loops_special(ctx, tls, coarse_poly);
+ }
}
/* =============================================================================
* Polygons traverse process.
*/
-static void subdiv_foreach_polys(SubdivForeachTaskContext *ctx,
- void *tls,
- int poly_index)
+static void subdiv_foreach_polys(SubdivForeachTaskContext *ctx, void *tls, int poly_index)
{
- const int resolution = ctx->settings->resolution;
- const int start_poly_index = ctx->subdiv_polygon_offset[poly_index];
- /* Base/coarse mesh information. */
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MPoly *coarse_mpoly = coarse_mesh->mpoly;
- const MPoly *coarse_poly = &coarse_mpoly[poly_index];
- const int num_ptex_faces_per_poly =
- num_ptex_faces_per_poly_get(coarse_poly);
- const int ptex_resolution =
- ptex_face_resolution_get(coarse_poly, resolution);
- const int num_polys_per_ptex = num_polys_per_ptex_get(ptex_resolution);
- const int num_loops_per_ptex = 4 * num_polys_per_ptex;
- const int start_loop_index = 4 * start_poly_index;
- /* Hi-poly subdivided mesh. */
- int subdiv_polyon_index = start_poly_index;
- for (int ptex_of_poly_index = 0;
- ptex_of_poly_index < num_ptex_faces_per_poly;
- ptex_of_poly_index++)
- {
- for (int subdiv_poly_index = 0;
- subdiv_poly_index < num_polys_per_ptex;
- subdiv_poly_index++, subdiv_polyon_index++)
- {
- const int loopstart = start_loop_index +
- (ptex_of_poly_index * num_loops_per_ptex) +
- (subdiv_poly_index * 4);
- ctx->foreach_context->poly(
- ctx->foreach_context,
- tls,
- poly_index,
- subdiv_polyon_index,
- loopstart, 4);
- }
- }
+ const int resolution = ctx->settings->resolution;
+ const int start_poly_index = ctx->subdiv_polygon_offset[poly_index];
+ /* Base/coarse mesh information. */
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const MPoly *coarse_poly = &coarse_mpoly[poly_index];
+ const int num_ptex_faces_per_poly = num_ptex_faces_per_poly_get(coarse_poly);
+ const int ptex_resolution = ptex_face_resolution_get(coarse_poly, resolution);
+ const int num_polys_per_ptex = num_polys_per_ptex_get(ptex_resolution);
+ const int num_loops_per_ptex = 4 * num_polys_per_ptex;
+ const int start_loop_index = 4 * start_poly_index;
+ /* Hi-poly subdivided mesh. */
+ int subdiv_polyon_index = start_poly_index;
+ for (int ptex_of_poly_index = 0; ptex_of_poly_index < num_ptex_faces_per_poly;
+ ptex_of_poly_index++) {
+ for (int subdiv_poly_index = 0; subdiv_poly_index < num_polys_per_ptex;
+ subdiv_poly_index++, subdiv_polyon_index++) {
+ const int loopstart = start_loop_index + (ptex_of_poly_index * num_loops_per_ptex) +
+ (subdiv_poly_index * 4);
+ ctx->foreach_context->poly(
+ ctx->foreach_context, tls, poly_index, subdiv_polyon_index, loopstart, 4);
+ }
+ }
}
/* =============================================================================
* Loose elements traverse process.
*/
-static void subdiv_foreach_loose_vertices_task(
- void *__restrict userdata,
- const int coarse_vertex_index,
- const ParallelRangeTLS *__restrict tls)
+static void subdiv_foreach_loose_vertices_task(void *__restrict userdata,
+ const int coarse_vertex_index,
+ const ParallelRangeTLS *__restrict tls)
{
- SubdivForeachTaskContext *ctx = userdata;
- if (BLI_BITMAP_TEST_BOOL(ctx->coarse_vertices_used_map,
- coarse_vertex_index))
- {
- /* Vertex is not loose, was handled when handling polygons. */
- return;
- }
- const int subdiv_vertex_index =
- ctx->vertices_corner_offset + coarse_vertex_index;
- ctx->foreach_context->vertex_loose(
- ctx->foreach_context,
- tls->userdata_chunk,
- coarse_vertex_index,
- subdiv_vertex_index);
+ SubdivForeachTaskContext *ctx = userdata;
+ if (BLI_BITMAP_TEST_BOOL(ctx->coarse_vertices_used_map, coarse_vertex_index)) {
+ /* Vertex is not loose, was handled when handling polygons. */
+ return;
+ }
+ const int subdiv_vertex_index = ctx->vertices_corner_offset + coarse_vertex_index;
+ ctx->foreach_context->vertex_loose(
+ ctx->foreach_context, tls->userdata_chunk, coarse_vertex_index, subdiv_vertex_index);
}
-static void subdiv_foreach_vertices_of_loose_edges_task(
- void *__restrict userdata,
- const int coarse_edge_index,
- const ParallelRangeTLS *__restrict tls)
+static void subdiv_foreach_vertices_of_loose_edges_task(void *__restrict userdata,
+ const int coarse_edge_index,
+ const ParallelRangeTLS *__restrict tls)
{
- SubdivForeachTaskContext *ctx = userdata;
- if (BLI_BITMAP_TEST_BOOL(ctx->coarse_edges_used_map, coarse_edge_index)) {
- /* Vertex is not loose, was handled when handling polygons. */
- return;
- }
- const int resolution = ctx->settings->resolution;
- const int resolution_1 = resolution - 1;
- const float inv_resolution_1 = 1.0f / (float)resolution_1;
- const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MEdge *coarse_edge = &coarse_mesh->medge[coarse_edge_index];
- /* Subdivion vertices which corresponds to edge's v1 and v2. */
- const int subdiv_v1_index =
- ctx->vertices_corner_offset + coarse_edge->v1;
- const int subdiv_v2_index =
- ctx->vertices_corner_offset + coarse_edge->v2;
- /* First subdivided inner vertex of the edge. */
- const int subdiv_start_vertex =
- ctx->vertices_edge_offset +
- coarse_edge_index * num_subdiv_vertices_per_coarse_edge;
- /* Perform interpolation. */
- for (int i = 0; i < resolution; i++) {
- const float u = i * inv_resolution_1;
- int subdiv_vertex_index;
- if (i == 0) {
- subdiv_vertex_index = subdiv_v1_index;
- }
- else if (i == resolution - 1) {
- subdiv_vertex_index = subdiv_v2_index;
- }
- else {
- subdiv_vertex_index = subdiv_start_vertex + (i - 1);
- }
- ctx->foreach_context->vertex_of_loose_edge(
- ctx->foreach_context,
- tls->userdata_chunk,
- coarse_edge_index,
- u,
- subdiv_vertex_index);
- }
+ SubdivForeachTaskContext *ctx = userdata;
+ if (BLI_BITMAP_TEST_BOOL(ctx->coarse_edges_used_map, coarse_edge_index)) {
+ /* Vertex is not loose, was handled when handling polygons. */
+ return;
+ }
+ const int resolution = ctx->settings->resolution;
+ const int resolution_1 = resolution - 1;
+ const float inv_resolution_1 = 1.0f / (float)resolution_1;
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_edge = &coarse_mesh->medge[coarse_edge_index];
+ /* Subdivion vertices which corresponds to edge's v1 and v2. */
+ const int subdiv_v1_index = ctx->vertices_corner_offset + coarse_edge->v1;
+ const int subdiv_v2_index = ctx->vertices_corner_offset + coarse_edge->v2;
+ /* First subdivided inner vertex of the edge. */
+ const int subdiv_start_vertex = ctx->vertices_edge_offset +
+ coarse_edge_index * num_subdiv_vertices_per_coarse_edge;
+ /* Perform interpolation. */
+ for (int i = 0; i < resolution; i++) {
+ const float u = i * inv_resolution_1;
+ int subdiv_vertex_index;
+ if (i == 0) {
+ subdiv_vertex_index = subdiv_v1_index;
+ }
+ else if (i == resolution - 1) {
+ subdiv_vertex_index = subdiv_v2_index;
+ }
+ else {
+ subdiv_vertex_index = subdiv_start_vertex + (i - 1);
+ }
+ ctx->foreach_context->vertex_of_loose_edge(
+ ctx->foreach_context, tls->userdata_chunk, coarse_edge_index, u, subdiv_vertex_index);
+ }
}
/* =============================================================================
* Subdivision process entry points.
*/
-static void subdiv_foreach_single_geometry_vertices(
- SubdivForeachTaskContext *ctx,
- void *tls)
+static void subdiv_foreach_single_geometry_vertices(SubdivForeachTaskContext *ctx, void *tls)
{
- if (ctx->foreach_context->vertex_corner == NULL) {
- return;
- }
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MPoly *coarse_mpoly = coarse_mesh->mpoly;
- for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) {
- const MPoly *coarse_poly = &coarse_mpoly[poly_index];
- subdiv_foreach_corner_vertices(ctx, tls, coarse_poly);
- subdiv_foreach_edge_vertices(ctx, tls, coarse_poly);
- }
+ if (ctx->foreach_context->vertex_corner == NULL) {
+ return;
+ }
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) {
+ const MPoly *coarse_poly = &coarse_mpoly[poly_index];
+ subdiv_foreach_corner_vertices(ctx, tls, coarse_poly);
+ subdiv_foreach_edge_vertices(ctx, tls, coarse_poly);
+ }
}
static void subdiv_foreach_single_thread_tasks(SubdivForeachTaskContext *ctx)
{
- /* NOTE: In theory, we can try to skip allocation of TLS here, but in
- * practice if the callbacks used here are not specified then TLS will not
- * be requested anyway. */
- void *tls = subdiv_foreach_tls_alloc(ctx);
- /* Passes to average displacement on the corner vertices
- * and boundary edges. */
- subdiv_foreach_every_corner_vertices(ctx, tls);
- subdiv_foreach_every_edge_vertices(ctx, tls);
- /* Run callbacks which are supposed to be run once per shared geometry. */
- subdiv_foreach_single_geometry_vertices(ctx, tls);
- subdiv_foreach_tls_free(ctx, tls);
+ /* NOTE: In theory, we can try to skip allocation of TLS here, but in
+ * practice if the callbacks used here are not specified then TLS will not
+ * be requested anyway. */
+ void *tls = subdiv_foreach_tls_alloc(ctx);
+ /* Passes to average displacement on the corner vertices
+ * and boundary edges. */
+ subdiv_foreach_every_corner_vertices(ctx, tls);
+ subdiv_foreach_every_edge_vertices(ctx, tls);
+ /* Run callbacks which are supposed to be run once per shared geometry. */
+ subdiv_foreach_single_geometry_vertices(ctx, tls);
+ subdiv_foreach_tls_free(ctx, tls);
}
-static void subdiv_foreach_task(
- void *__restrict userdata,
- const int poly_index,
- const ParallelRangeTLS *__restrict tls)
+static void subdiv_foreach_task(void *__restrict userdata,
+ const int poly_index,
+ const ParallelRangeTLS *__restrict tls)
{
- SubdivForeachTaskContext *ctx = userdata;
- /* Traverse hi-poly vertex coordinates and normals. */
- subdiv_foreach_vertices(ctx, tls->userdata_chunk, poly_index);
- /* Traverse mesh geometry for the given base poly index. */
- if (ctx->foreach_context->edge != NULL) {
- subdiv_foreach_edges(ctx, tls->userdata_chunk, poly_index);
- }
- if (ctx->foreach_context->loop != NULL) {
- subdiv_foreach_loops(ctx, tls->userdata_chunk, poly_index);
- }
- if (ctx->foreach_context->poly != NULL) {
- subdiv_foreach_polys(ctx, tls->userdata_chunk, poly_index);
- }
+ SubdivForeachTaskContext *ctx = userdata;
+ /* Traverse hi-poly vertex coordinates and normals. */
+ subdiv_foreach_vertices(ctx, tls->userdata_chunk, poly_index);
+ /* Traverse mesh geometry for the given base poly index. */
+ if (ctx->foreach_context->edge != NULL) {
+ subdiv_foreach_edges(ctx, tls->userdata_chunk, poly_index);
+ }
+ if (ctx->foreach_context->loop != NULL) {
+ subdiv_foreach_loops(ctx, tls->userdata_chunk, poly_index);
+ }
+ if (ctx->foreach_context->poly != NULL) {
+ subdiv_foreach_polys(ctx, tls->userdata_chunk, poly_index);
+ }
}
-static void subdiv_foreach_boundary_edges_task(
- void *__restrict userdata,
- const int edge_index,
- const ParallelRangeTLS *__restrict tls)
+static void subdiv_foreach_boundary_edges_task(void *__restrict userdata,
+ const int edge_index,
+ const ParallelRangeTLS *__restrict tls)
{
- SubdivForeachTaskContext *ctx = userdata;
- subdiv_foreach_boundary_edges(ctx, tls->userdata_chunk, edge_index);
+ SubdivForeachTaskContext *ctx = userdata;
+ subdiv_foreach_boundary_edges(ctx, tls->userdata_chunk, edge_index);
}
-static void subdiv_foreach_finalize(void *__restrict userdata,
- void *__restrict userdata_chunk)
+static void subdiv_foreach_finalize(void *__restrict userdata, void *__restrict userdata_chunk)
{
- SubdivForeachTaskContext *ctx = userdata;
- ctx->foreach_context->user_data_tls_free(userdata_chunk);
+ SubdivForeachTaskContext *ctx = userdata;
+ ctx->foreach_context->user_data_tls_free(userdata_chunk);
}
-bool BKE_subdiv_foreach_subdiv_geometry(
- Subdiv *subdiv,
- const SubdivForeachContext *context,
- const SubdivToMeshSettings *mesh_settings,
- const Mesh *coarse_mesh)
+bool BKE_subdiv_foreach_subdiv_geometry(Subdiv *subdiv,
+ const SubdivForeachContext *context,
+ const SubdivToMeshSettings *mesh_settings,
+ const Mesh *coarse_mesh)
{
- SubdivForeachTaskContext ctx = {0};
- ctx.coarse_mesh = coarse_mesh;
- ctx.settings = mesh_settings;
- ctx.foreach_context = context;
- subdiv_foreach_ctx_init(subdiv, &ctx);
- if (context->topology_info != NULL) {
- if (!context->topology_info(context,
- ctx.num_subdiv_vertices,
- ctx.num_subdiv_edges,
- ctx.num_subdiv_loops,
- ctx.num_subdiv_polygons))
- {
- subdiv_foreach_ctx_free(&ctx);
- return false;
- }
- }
- /* Run all the code which is not supposed to be run from threads. */
- subdiv_foreach_single_thread_tasks(&ctx);
- /* Threaded traversal of the rest of topology. */
- ParallelRangeSettings parallel_range_settings;
- BLI_parallel_range_settings_defaults(&parallel_range_settings);
- parallel_range_settings.userdata_chunk = context->user_data_tls;
- parallel_range_settings.userdata_chunk_size = context->user_data_tls_size;
- if (context->user_data_tls_free != NULL) {
- parallel_range_settings.func_finalize = subdiv_foreach_finalize;
- }
- BLI_task_parallel_range(0, coarse_mesh->totpoly,
- &ctx,
- subdiv_foreach_task,
- &parallel_range_settings);
- if (context->vertex_loose != NULL) {
- BLI_task_parallel_range(0, coarse_mesh->totvert,
- &ctx,
- subdiv_foreach_loose_vertices_task,
- &parallel_range_settings);
- }
- if (context->vertex_of_loose_edge != NULL) {
- BLI_task_parallel_range(0, coarse_mesh->totedge,
- &ctx,
- subdiv_foreach_vertices_of_loose_edges_task,
- &parallel_range_settings);
- }
- if (context->edge != NULL) {
- BLI_task_parallel_range(0, coarse_mesh->totedge,
- &ctx,
- subdiv_foreach_boundary_edges_task,
- &parallel_range_settings);
- }
- subdiv_foreach_ctx_free(&ctx);
- return true;
+ SubdivForeachTaskContext ctx = {0};
+ ctx.coarse_mesh = coarse_mesh;
+ ctx.settings = mesh_settings;
+ ctx.foreach_context = context;
+ subdiv_foreach_ctx_init(subdiv, &ctx);
+ if (context->topology_info != NULL) {
+ if (!context->topology_info(context,
+ ctx.num_subdiv_vertices,
+ ctx.num_subdiv_edges,
+ ctx.num_subdiv_loops,
+ ctx.num_subdiv_polygons)) {
+ subdiv_foreach_ctx_free(&ctx);
+ return false;
+ }
+ }
+ /* Run all the code which is not supposed to be run from threads. */
+ subdiv_foreach_single_thread_tasks(&ctx);
+ /* Threaded traversal of the rest of topology. */
+ ParallelRangeSettings parallel_range_settings;
+ BLI_parallel_range_settings_defaults(&parallel_range_settings);
+ parallel_range_settings.userdata_chunk = context->user_data_tls;
+ parallel_range_settings.userdata_chunk_size = context->user_data_tls_size;
+ if (context->user_data_tls_free != NULL) {
+ parallel_range_settings.func_finalize = subdiv_foreach_finalize;
+ }
+ BLI_task_parallel_range(
+ 0, coarse_mesh->totpoly, &ctx, subdiv_foreach_task, &parallel_range_settings);
+ if (context->vertex_loose != NULL) {
+ BLI_task_parallel_range(0,
+ coarse_mesh->totvert,
+ &ctx,
+ subdiv_foreach_loose_vertices_task,
+ &parallel_range_settings);
+ }
+ if (context->vertex_of_loose_edge != NULL) {
+ BLI_task_parallel_range(0,
+ coarse_mesh->totedge,
+ &ctx,
+ subdiv_foreach_vertices_of_loose_edges_task,
+ &parallel_range_settings);
+ }
+ if (context->edge != NULL) {
+ BLI_task_parallel_range(0,
+ coarse_mesh->totedge,
+ &ctx,
+ subdiv_foreach_boundary_edges_task,
+ &parallel_range_settings);
+ }
+ subdiv_foreach_ctx_free(&ctx);
+ return true;
}
diff --git a/source/blender/blenkernel/intern/subdiv_inline.h b/source/blender/blenkernel/intern/subdiv_inline.h
index 566d54ef72b..f00c5cf7ff7 100644
--- a/source/blender/blenkernel/intern/subdiv_inline.h
+++ b/source/blender/blenkernel/intern/subdiv_inline.h
@@ -29,78 +29,79 @@
#include "BKE_subdiv.h"
-BLI_INLINE void BKE_subdiv_ptex_face_uv_to_grid_uv(
- const float ptex_u, const float ptex_v,
- float *r_grid_u, float *r_grid_v)
+BLI_INLINE void BKE_subdiv_ptex_face_uv_to_grid_uv(const float ptex_u,
+ const float ptex_v,
+ float *r_grid_u,
+ float *r_grid_v)
{
- *r_grid_u = 1.0f - ptex_v;
- *r_grid_v = 1.0f - ptex_u;
+ *r_grid_u = 1.0f - ptex_v;
+ *r_grid_v = 1.0f - ptex_u;
}
-BLI_INLINE void BKE_subdiv_grid_uv_to_ptex_face_uv(
- const float grid_u, const float grid_v,
- float *r_ptex_u, float *r_ptex_v)
+BLI_INLINE void BKE_subdiv_grid_uv_to_ptex_face_uv(const float grid_u,
+ const float grid_v,
+ float *r_ptex_u,
+ float *r_ptex_v)
{
- *r_ptex_u = 1.0f - grid_v;
- *r_ptex_v = 1.0f - grid_u;
+ *r_ptex_u = 1.0f - grid_v;
+ *r_ptex_v = 1.0f - grid_u;
}
BLI_INLINE int BKE_subdiv_grid_size_from_level(const int level)
{
- return (1 << (level - 1)) + 1;
+ return (1 << (level - 1)) + 1;
}
-BLI_INLINE int BKE_subdiv_rotate_quad_to_corner(
- const float quad_u, const float quad_v,
- float *r_corner_u, float *r_corner_v)
+BLI_INLINE int BKE_subdiv_rotate_quad_to_corner(const float quad_u,
+ const float quad_v,
+ float *r_corner_u,
+ float *r_corner_v)
{
- int corner;
- if (quad_u <= 0.5f && quad_v <= 0.5f) {
- corner = 0;
- *r_corner_u = 2.0f * quad_u;
- *r_corner_v = 2.0f * quad_v;
- }
- else if (quad_u > 0.5f && quad_v <= 0.5f) {
- corner = 1;
- *r_corner_u = 2.0f * quad_v;
- *r_corner_v = 2.0f * (1.0f - quad_u);
- }
- else if (quad_u > 0.5f && quad_v > 0.5f) {
- corner = 2;
- *r_corner_u = 2.0f * (1.0f - quad_u);
- *r_corner_v = 2.0f * (1.0f - quad_v);
- }
- else {
- BLI_assert(quad_u <= 0.5f && quad_v >= 0.5f);
- corner = 3;
- *r_corner_u = 2.0f * (1.0f - quad_v);
- *r_corner_v = 2.0f * quad_u;
- }
- return corner;
+ int corner;
+ if (quad_u <= 0.5f && quad_v <= 0.5f) {
+ corner = 0;
+ *r_corner_u = 2.0f * quad_u;
+ *r_corner_v = 2.0f * quad_v;
+ }
+ else if (quad_u > 0.5f && quad_v <= 0.5f) {
+ corner = 1;
+ *r_corner_u = 2.0f * quad_v;
+ *r_corner_v = 2.0f * (1.0f - quad_u);
+ }
+ else if (quad_u > 0.5f && quad_v > 0.5f) {
+ corner = 2;
+ *r_corner_u = 2.0f * (1.0f - quad_u);
+ *r_corner_v = 2.0f * (1.0f - quad_v);
+ }
+ else {
+ BLI_assert(quad_u <= 0.5f && quad_v >= 0.5f);
+ corner = 3;
+ *r_corner_u = 2.0f * (1.0f - quad_v);
+ *r_corner_v = 2.0f * quad_u;
+ }
+ return corner;
}
BLI_INLINE void BKE_subdiv_rotate_grid_to_quad(
- const int corner,
- const float grid_u, const float grid_v,
- float *r_quad_u, float *r_quad_v)
+ const int corner, const float grid_u, const float grid_v, float *r_quad_u, float *r_quad_v)
{
- if (corner == 0) {
- *r_quad_u = 0.5f - grid_v * 0.5f;
- *r_quad_v = 0.5f - grid_u * 0.5f;
- }
- else if (corner == 1) {
- *r_quad_u = 0.5f + grid_u * 0.5f;
- *r_quad_v = 0.5f - grid_v * 0.5f;
- }
- else if (corner == 2) {
- *r_quad_u = 0.5f + grid_v * 0.5f;
- *r_quad_v = 0.5f + grid_u * 0.5f;
- }
- else {
- BLI_assert(corner == 3);
- *r_quad_u = 0.5f - grid_u * 0.5f;
- *r_quad_v = 0.5f + grid_v * 0.5f;
- }
+ if (corner == 0) {
+ *r_quad_u = 0.5f - grid_v * 0.5f;
+ *r_quad_v = 0.5f - grid_u * 0.5f;
+ }
+ else if (corner == 1) {
+ *r_quad_u = 0.5f + grid_u * 0.5f;
+ *r_quad_v = 0.5f - grid_v * 0.5f;
+ }
+ else if (corner == 2) {
+ *r_quad_u = 0.5f + grid_v * 0.5f;
+ *r_quad_v = 0.5f + grid_u * 0.5f;
+ }
+ else {
+ BLI_assert(corner == 3);
+ *r_quad_u = 0.5f - grid_u * 0.5f;
+ *r_quad_v = 0.5f + grid_v * 0.5f;
+ }
}
-#endif /* __SUBDIV_INLINE_H__ */
+#endif /* __SUBDIV_INLINE_H__ */
diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.c
index 8ac120ec79d..d461394bc02 100644
--- a/source/blender/blenkernel/intern/subdiv_mesh.c
+++ b/source/blender/blenkernel/intern/subdiv_mesh.c
@@ -46,87 +46,77 @@
*/
typedef struct SubdivMeshContext {
- const SubdivToMeshSettings *settings;
- const Mesh *coarse_mesh;
- Subdiv *subdiv;
- Mesh *subdiv_mesh;
- /* Cached custom data arrays for fastter access. */
- int *vert_origindex;
- int *edge_origindex;
- int *loop_origindex;
- int *poly_origindex;
- /* UV layers interpolation. */
- int num_uv_layers;
- MLoopUV *uv_layers[MAX_MTFACE];
- /* Accumulated values.
- *
- * Averaging is happening for vertices along the coarse edges and corners.
- * This is needed for both displacement and normals.
- *
- * Displacement is being accumulated to a verticies coordinates, since those
- * are not needed during traversal of edge/corner vertices.
- *
- * For normals we are using dedicated array, since we can not use same
- * vertices (normals are `short`, which will cause a lot of precision
- * issues). */
- float (*accumulated_normals)[3];
- /* Per-subdivided vertex counter of averaged values. */
- int *accumulated_counters;
- /* Denotes whether normals can be evaluated from a limit surface. One case
- * when it's not possible is when displacement is used. */
- bool can_evaluate_normals;
- bool have_displacement;
+ const SubdivToMeshSettings *settings;
+ const Mesh *coarse_mesh;
+ Subdiv *subdiv;
+ Mesh *subdiv_mesh;
+ /* Cached custom data arrays for fastter access. */
+ int *vert_origindex;
+ int *edge_origindex;
+ int *loop_origindex;
+ int *poly_origindex;
+ /* UV layers interpolation. */
+ int num_uv_layers;
+ MLoopUV *uv_layers[MAX_MTFACE];
+ /* Accumulated values.
+ *
+ * Averaging is happening for vertices along the coarse edges and corners.
+ * This is needed for both displacement and normals.
+ *
+ * Displacement is being accumulated to a verticies coordinates, since those
+ * are not needed during traversal of edge/corner vertices.
+ *
+ * For normals we are using dedicated array, since we can not use same
+ * vertices (normals are `short`, which will cause a lot of precision
+ * issues). */
+ float (*accumulated_normals)[3];
+ /* Per-subdivided vertex counter of averaged values. */
+ int *accumulated_counters;
+ /* Denotes whether normals can be evaluated from a limit surface. One case
+ * when it's not possible is when displacement is used. */
+ bool can_evaluate_normals;
+ bool have_displacement;
} SubdivMeshContext;
static void subdiv_mesh_ctx_cache_uv_layers(SubdivMeshContext *ctx)
{
- Mesh *subdiv_mesh = ctx->subdiv_mesh;
- ctx->num_uv_layers =
- CustomData_number_of_layers(&subdiv_mesh->ldata, CD_MLOOPUV);
- for (int layer_index = 0; layer_index < ctx->num_uv_layers; ++layer_index) {
- ctx->uv_layers[layer_index] = CustomData_get_layer_n(
- &subdiv_mesh->ldata, CD_MLOOPUV, layer_index);
- }
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ ctx->num_uv_layers = CustomData_number_of_layers(&subdiv_mesh->ldata, CD_MLOOPUV);
+ for (int layer_index = 0; layer_index < ctx->num_uv_layers; ++layer_index) {
+ ctx->uv_layers[layer_index] = CustomData_get_layer_n(
+ &subdiv_mesh->ldata, CD_MLOOPUV, layer_index);
+ }
}
static void subdiv_mesh_ctx_cache_custom_data_layers(SubdivMeshContext *ctx)
{
- Mesh *subdiv_mesh = ctx->subdiv_mesh;
- /* Pointers to original indices layers. */
- ctx->vert_origindex = CustomData_get_layer(
- &subdiv_mesh->vdata, CD_ORIGINDEX);
- ctx->edge_origindex = CustomData_get_layer(
- &subdiv_mesh->edata, CD_ORIGINDEX);
- ctx->loop_origindex = CustomData_get_layer(
- &subdiv_mesh->ldata, CD_ORIGINDEX);
- ctx->poly_origindex = CustomData_get_layer(
- &subdiv_mesh->pdata, CD_ORIGINDEX);
- /* UV layers interpolation. */
- subdiv_mesh_ctx_cache_uv_layers(ctx);
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ /* Pointers to original indices layers. */
+ ctx->vert_origindex = CustomData_get_layer(&subdiv_mesh->vdata, CD_ORIGINDEX);
+ ctx->edge_origindex = CustomData_get_layer(&subdiv_mesh->edata, CD_ORIGINDEX);
+ ctx->loop_origindex = CustomData_get_layer(&subdiv_mesh->ldata, CD_ORIGINDEX);
+ ctx->poly_origindex = CustomData_get_layer(&subdiv_mesh->pdata, CD_ORIGINDEX);
+ /* UV layers interpolation. */
+ subdiv_mesh_ctx_cache_uv_layers(ctx);
}
-static void subdiv_mesh_prepare_accumulator(
- SubdivMeshContext *ctx, int num_vertices)
+static void subdiv_mesh_prepare_accumulator(SubdivMeshContext *ctx, int num_vertices)
{
- if (!ctx->can_evaluate_normals && !ctx->have_displacement) {
- return;
- }
- /* TODO(sergey): Technically, this is overallocating, we don't need memory
- * for an inner subdivision vertices. */
- ctx->accumulated_normals = MEM_calloc_arrayN(
- sizeof(*ctx->accumulated_normals),
- num_vertices,
- "subdiv accumulated normals");
- ctx->accumulated_counters = MEM_calloc_arrayN(
- sizeof(*ctx->accumulated_counters),
- num_vertices,
- "subdiv accumulated counters");
+ if (!ctx->can_evaluate_normals && !ctx->have_displacement) {
+ return;
+ }
+ /* TODO(sergey): Technically, this is overallocating, we don't need memory
+ * for an inner subdivision vertices. */
+ ctx->accumulated_normals = MEM_calloc_arrayN(
+ sizeof(*ctx->accumulated_normals), num_vertices, "subdiv accumulated normals");
+ ctx->accumulated_counters = MEM_calloc_arrayN(
+ sizeof(*ctx->accumulated_counters), num_vertices, "subdiv accumulated counters");
}
static void subdiv_mesh_context_free(SubdivMeshContext *ctx)
{
- MEM_SAFE_FREE(ctx->accumulated_normals);
- MEM_SAFE_FREE(ctx->accumulated_counters);
+ MEM_SAFE_FREE(ctx->accumulated_normals);
+ MEM_SAFE_FREE(ctx->accumulated_counters);
}
/* =============================================================================
@@ -134,42 +124,39 @@ static void subdiv_mesh_context_free(SubdivMeshContext *ctx)
*/
typedef struct LoopsOfPtex {
- /* First loop of the ptex, starts at ptex (0, 0) and goes in u direction. */
- const MLoop *first_loop;
- /* Last loop of the ptex, starts at ptex (0, 0) and goes in v direction. */
- const MLoop *last_loop;
- /* For quad coarse faces only. */
- const MLoop *second_loop;
- const MLoop *third_loop;
+ /* First loop of the ptex, starts at ptex (0, 0) and goes in u direction. */
+ const MLoop *first_loop;
+ /* Last loop of the ptex, starts at ptex (0, 0) and goes in v direction. */
+ const MLoop *last_loop;
+ /* For quad coarse faces only. */
+ const MLoop *second_loop;
+ const MLoop *third_loop;
} LoopsOfPtex;
-static void loops_of_ptex_get(
- const SubdivMeshContext *ctx,
- LoopsOfPtex *loops_of_ptex,
- const MPoly *coarse_poly,
- const int ptex_of_poly_index)
+static void loops_of_ptex_get(const SubdivMeshContext *ctx,
+ LoopsOfPtex *loops_of_ptex,
+ const MPoly *coarse_poly,
+ const int ptex_of_poly_index)
{
- const MLoop *coarse_mloop = ctx->coarse_mesh->mloop;
- const int first_ptex_loop_index =
- coarse_poly->loopstart + ptex_of_poly_index;
- /* Loop which look in the (opposite) V direction of the current
- * ptex face.
- *
- * TODO(sergey): Get rid of using module on every iteration. */
- const int last_ptex_loop_index =
- coarse_poly->loopstart +
- (ptex_of_poly_index + coarse_poly->totloop - 1) %
- coarse_poly->totloop;
- loops_of_ptex->first_loop = &coarse_mloop[first_ptex_loop_index];
- loops_of_ptex->last_loop = &coarse_mloop[last_ptex_loop_index];
- if (coarse_poly->totloop == 4) {
- loops_of_ptex->second_loop = loops_of_ptex->first_loop + 1;
- loops_of_ptex->third_loop = loops_of_ptex->first_loop + 2;
- }
- else {
- loops_of_ptex->second_loop = NULL;
- loops_of_ptex->third_loop = NULL;
- }
+ const MLoop *coarse_mloop = ctx->coarse_mesh->mloop;
+ const int first_ptex_loop_index = coarse_poly->loopstart + ptex_of_poly_index;
+ /* Loop which look in the (opposite) V direction of the current
+ * ptex face.
+ *
+ * TODO(sergey): Get rid of using module on every iteration. */
+ const int last_ptex_loop_index = coarse_poly->loopstart +
+ (ptex_of_poly_index + coarse_poly->totloop - 1) %
+ coarse_poly->totloop;
+ loops_of_ptex->first_loop = &coarse_mloop[first_ptex_loop_index];
+ loops_of_ptex->last_loop = &coarse_mloop[last_ptex_loop_index];
+ if (coarse_poly->totloop == 4) {
+ loops_of_ptex->second_loop = loops_of_ptex->first_loop + 1;
+ loops_of_ptex->third_loop = loops_of_ptex->first_loop + 2;
+ }
+ else {
+ loops_of_ptex->second_loop = NULL;
+ loops_of_ptex->third_loop = NULL;
+ }
}
/* =============================================================================
@@ -180,136 +167,130 @@ static void loops_of_ptex_get(
* exception cases all over the code. */
typedef struct VerticesForInterpolation {
- /* This field points to a vertex data which is to be used for interpolation.
- * The idea is to avoid unnecessary allocations for regular faces, where
- * we can simply use corner verticies. */
- const CustomData *vertex_data;
- /* Vertices data calculated for ptex corners. There are always 4 elements
- * in this custom data, aligned the following way:
- *
- * index 0 -> uv (0, 0)
- * index 1 -> uv (0, 1)
- * index 2 -> uv (1, 1)
- * index 3 -> uv (1, 0)
- *
- * Is allocated for non-regular faces (triangles and n-gons). */
- CustomData vertex_data_storage;
- bool vertex_data_storage_allocated;
- /* Infices within vertex_data to interpolate for. The indices are aligned
- * with uv coordinates in a similar way as indices in loop_data_storage. */
- int vertex_indices[4];
+ /* This field points to a vertex data which is to be used for interpolation.
+ * The idea is to avoid unnecessary allocations for regular faces, where
+ * we can simply use corner verticies. */
+ const CustomData *vertex_data;
+ /* Vertices data calculated for ptex corners. There are always 4 elements
+ * in this custom data, aligned the following way:
+ *
+ * index 0 -> uv (0, 0)
+ * index 1 -> uv (0, 1)
+ * index 2 -> uv (1, 1)
+ * index 3 -> uv (1, 0)
+ *
+ * Is allocated for non-regular faces (triangles and n-gons). */
+ CustomData vertex_data_storage;
+ bool vertex_data_storage_allocated;
+ /* Infices within vertex_data to interpolate for. The indices are aligned
+ * with uv coordinates in a similar way as indices in loop_data_storage. */
+ int vertex_indices[4];
} VerticesForInterpolation;
-static void vertex_interpolation_init(
- const SubdivMeshContext *ctx,
- VerticesForInterpolation *vertex_interpolation,
- const MPoly *coarse_poly)
+static void vertex_interpolation_init(const SubdivMeshContext *ctx,
+ VerticesForInterpolation *vertex_interpolation,
+ const MPoly *coarse_poly)
{
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MLoop *coarse_mloop = coarse_mesh->mloop;
- if (coarse_poly->totloop == 4) {
- vertex_interpolation->vertex_data = &coarse_mesh->vdata;
- vertex_interpolation->vertex_indices[0] =
- coarse_mloop[coarse_poly->loopstart + 0].v;
- vertex_interpolation->vertex_indices[1] =
- coarse_mloop[coarse_poly->loopstart + 1].v;
- vertex_interpolation->vertex_indices[2] =
- coarse_mloop[coarse_poly->loopstart + 2].v;
- vertex_interpolation->vertex_indices[3] =
- coarse_mloop[coarse_poly->loopstart + 3].v;
- vertex_interpolation->vertex_data_storage_allocated = false;
- }
- else {
- vertex_interpolation->vertex_data =
- &vertex_interpolation->vertex_data_storage;
- /* Allocate storage for loops corresponding to ptex corners. */
- CustomData_copy(&ctx->coarse_mesh->vdata,
- &vertex_interpolation->vertex_data_storage,
- CD_MASK_EVERYTHING.vmask,
- CD_CALLOC,
- 4);
- /* Initialize indices. */
- vertex_interpolation->vertex_indices[0] = 0;
- vertex_interpolation->vertex_indices[1] = 1;
- vertex_interpolation->vertex_indices[2] = 2;
- vertex_interpolation->vertex_indices[3] = 3;
- vertex_interpolation->vertex_data_storage_allocated = true;
- /* Interpolate center of poly right away, it stays unchanged for all
- * ptex faces. */
- const float weight = 1.0f / (float)coarse_poly->totloop;
- float *weights = BLI_array_alloca(weights, coarse_poly->totloop);
- int *indices = BLI_array_alloca(indices, coarse_poly->totloop);
- for (int i = 0; i < coarse_poly->totloop; ++i) {
- weights[i] = weight;
- indices[i] = coarse_mloop[coarse_poly->loopstart + i].v;
- }
- CustomData_interp(&coarse_mesh->vdata,
- &vertex_interpolation->vertex_data_storage,
- indices,
- weights, NULL,
- coarse_poly->totloop,
- 2);
- }
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ if (coarse_poly->totloop == 4) {
+ vertex_interpolation->vertex_data = &coarse_mesh->vdata;
+ vertex_interpolation->vertex_indices[0] = coarse_mloop[coarse_poly->loopstart + 0].v;
+ vertex_interpolation->vertex_indices[1] = coarse_mloop[coarse_poly->loopstart + 1].v;
+ vertex_interpolation->vertex_indices[2] = coarse_mloop[coarse_poly->loopstart + 2].v;
+ vertex_interpolation->vertex_indices[3] = coarse_mloop[coarse_poly->loopstart + 3].v;
+ vertex_interpolation->vertex_data_storage_allocated = false;
+ }
+ else {
+ vertex_interpolation->vertex_data = &vertex_interpolation->vertex_data_storage;
+ /* Allocate storage for loops corresponding to ptex corners. */
+ CustomData_copy(&ctx->coarse_mesh->vdata,
+ &vertex_interpolation->vertex_data_storage,
+ CD_MASK_EVERYTHING.vmask,
+ CD_CALLOC,
+ 4);
+ /* Initialize indices. */
+ vertex_interpolation->vertex_indices[0] = 0;
+ vertex_interpolation->vertex_indices[1] = 1;
+ vertex_interpolation->vertex_indices[2] = 2;
+ vertex_interpolation->vertex_indices[3] = 3;
+ vertex_interpolation->vertex_data_storage_allocated = true;
+ /* Interpolate center of poly right away, it stays unchanged for all
+ * ptex faces. */
+ const float weight = 1.0f / (float)coarse_poly->totloop;
+ float *weights = BLI_array_alloca(weights, coarse_poly->totloop);
+ int *indices = BLI_array_alloca(indices, coarse_poly->totloop);
+ for (int i = 0; i < coarse_poly->totloop; ++i) {
+ weights[i] = weight;
+ indices[i] = coarse_mloop[coarse_poly->loopstart + i].v;
+ }
+ CustomData_interp(&coarse_mesh->vdata,
+ &vertex_interpolation->vertex_data_storage,
+ indices,
+ weights,
+ NULL,
+ coarse_poly->totloop,
+ 2);
+ }
}
-static void vertex_interpolation_from_corner(
- const SubdivMeshContext *ctx,
- VerticesForInterpolation *vertex_interpolation,
- const MPoly *coarse_poly,
- const int corner)
+static void vertex_interpolation_from_corner(const SubdivMeshContext *ctx,
+ VerticesForInterpolation *vertex_interpolation,
+ const MPoly *coarse_poly,
+ const int corner)
{
- if (coarse_poly->totloop == 4) {
- /* Nothing to do, all indices and data is already assigned. */
- }
- else {
- const CustomData *vertex_data = &ctx->coarse_mesh->vdata;
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MLoop *coarse_mloop = coarse_mesh->mloop;
- LoopsOfPtex loops_of_ptex;
- loops_of_ptex_get(ctx, &loops_of_ptex, coarse_poly, corner);
- /* Ptex face corner corresponds to a poly loop with same index. */
- CustomData_copy_data(
- vertex_data,
- &vertex_interpolation->vertex_data_storage,
- coarse_mloop[coarse_poly->loopstart + corner].v,
- 0,
- 1);
- /* Interpolate remaining ptex face corners, which hits loops
- * middle points.
- *
- * TODO(sergey): Re-use one of interpolation results from previous
- * iteration. */
- const float weights[2] = {0.5f, 0.5f};
- const int first_loop_index = loops_of_ptex.first_loop - coarse_mloop;
- const int last_loop_index = loops_of_ptex.last_loop - coarse_mloop;
- const int first_indices[2] = {
- coarse_mloop[first_loop_index].v,
- coarse_mloop[coarse_poly->loopstart +
- (first_loop_index - coarse_poly->loopstart + 1) %
- coarse_poly->totloop].v};
- const int last_indices[2] = {coarse_mloop[first_loop_index].v,
- coarse_mloop[last_loop_index].v};
- CustomData_interp(vertex_data,
- &vertex_interpolation->vertex_data_storage,
- first_indices,
- weights, NULL,
- 2,
- 1);
- CustomData_interp(vertex_data,
- &vertex_interpolation->vertex_data_storage,
- last_indices,
- weights, NULL,
- 2,
- 3);
- }
+ if (coarse_poly->totloop == 4) {
+ /* Nothing to do, all indices and data is already assigned. */
+ }
+ else {
+ const CustomData *vertex_data = &ctx->coarse_mesh->vdata;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ LoopsOfPtex loops_of_ptex;
+ loops_of_ptex_get(ctx, &loops_of_ptex, coarse_poly, corner);
+ /* Ptex face corner corresponds to a poly loop with same index. */
+ CustomData_copy_data(vertex_data,
+ &vertex_interpolation->vertex_data_storage,
+ coarse_mloop[coarse_poly->loopstart + corner].v,
+ 0,
+ 1);
+ /* Interpolate remaining ptex face corners, which hits loops
+ * middle points.
+ *
+ * TODO(sergey): Re-use one of interpolation results from previous
+ * iteration. */
+ const float weights[2] = {0.5f, 0.5f};
+ const int first_loop_index = loops_of_ptex.first_loop - coarse_mloop;
+ const int last_loop_index = loops_of_ptex.last_loop - coarse_mloop;
+ const int first_indices[2] = {
+ coarse_mloop[first_loop_index].v,
+ coarse_mloop[coarse_poly->loopstart +
+ (first_loop_index - coarse_poly->loopstart + 1) % coarse_poly->totloop]
+ .v};
+ const int last_indices[2] = {coarse_mloop[first_loop_index].v,
+ coarse_mloop[last_loop_index].v};
+ CustomData_interp(vertex_data,
+ &vertex_interpolation->vertex_data_storage,
+ first_indices,
+ weights,
+ NULL,
+ 2,
+ 1);
+ CustomData_interp(vertex_data,
+ &vertex_interpolation->vertex_data_storage,
+ last_indices,
+ weights,
+ NULL,
+ 2,
+ 3);
+ }
}
-static void vertex_interpolation_end(
- VerticesForInterpolation *vertex_interpolation)
+static void vertex_interpolation_end(VerticesForInterpolation *vertex_interpolation)
{
- if (vertex_interpolation->vertex_data_storage_allocated) {
- CustomData_free(&vertex_interpolation->vertex_data_storage, 4);
- }
+ if (vertex_interpolation->vertex_data_storage_allocated) {
+ CustomData_free(&vertex_interpolation->vertex_data_storage, 4);
+ }
}
/* =============================================================================
@@ -317,129 +298,115 @@ static void vertex_interpolation_end(
*/
typedef struct LoopsForInterpolation {
- /* This field points to a loop data which is to be used for interpolation.
- * The idea is to avoid unnecessary allocations for regular faces, where
- * we can simply interpolate corner verticies. */
- const CustomData *loop_data;
- /* Loops data calculated for ptex corners. There are always 4 elements
- * in this custom data, aligned the following way:
- *
- * index 0 -> uv (0, 0)
- * index 1 -> uv (0, 1)
- * index 2 -> uv (1, 1)
- * index 3 -> uv (1, 0)
- *
- * Is allocated for non-regular faces (triangles and n-gons). */
- CustomData loop_data_storage;
- bool loop_data_storage_allocated;
- /* Infices within loop_data to interpolate for. The indices are aligned with
- * uv coordinates in a similar way as indices in loop_data_storage. */
- int loop_indices[4];
+ /* This field points to a loop data which is to be used for interpolation.
+ * The idea is to avoid unnecessary allocations for regular faces, where
+ * we can simply interpolate corner verticies. */
+ const CustomData *loop_data;
+ /* Loops data calculated for ptex corners. There are always 4 elements
+ * in this custom data, aligned the following way:
+ *
+ * index 0 -> uv (0, 0)
+ * index 1 -> uv (0, 1)
+ * index 2 -> uv (1, 1)
+ * index 3 -> uv (1, 0)
+ *
+ * Is allocated for non-regular faces (triangles and n-gons). */
+ CustomData loop_data_storage;
+ bool loop_data_storage_allocated;
+ /* Infices within loop_data to interpolate for. The indices are aligned with
+ * uv coordinates in a similar way as indices in loop_data_storage. */
+ int loop_indices[4];
} LoopsForInterpolation;
-static void loop_interpolation_init(
- const SubdivMeshContext *ctx,
- LoopsForInterpolation *loop_interpolation,
- const MPoly *coarse_poly)
+static void loop_interpolation_init(const SubdivMeshContext *ctx,
+ LoopsForInterpolation *loop_interpolation,
+ const MPoly *coarse_poly)
{
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- if (coarse_poly->totloop == 4) {
- loop_interpolation->loop_data = &coarse_mesh->ldata;
- loop_interpolation->loop_indices[0] = coarse_poly->loopstart + 0;
- loop_interpolation->loop_indices[1] = coarse_poly->loopstart + 1;
- loop_interpolation->loop_indices[2] = coarse_poly->loopstart + 2;
- loop_interpolation->loop_indices[3] = coarse_poly->loopstart + 3;
- loop_interpolation->loop_data_storage_allocated = false;
- }
- else {
- loop_interpolation->loop_data = &loop_interpolation->loop_data_storage;
- /* Allocate storage for loops corresponding to ptex corners. */
- CustomData_copy(&ctx->coarse_mesh->ldata,
- &loop_interpolation->loop_data_storage,
- CD_MASK_EVERYTHING.lmask,
- CD_CALLOC,
- 4);
- /* Initialize indices. */
- loop_interpolation->loop_indices[0] = 0;
- loop_interpolation->loop_indices[1] = 1;
- loop_interpolation->loop_indices[2] = 2;
- loop_interpolation->loop_indices[3] = 3;
- loop_interpolation->loop_data_storage_allocated = true;
- /* Interpolate center of poly right away, it stays unchanged for all
- * ptex faces. */
- const float weight = 1.0f / (float)coarse_poly->totloop;
- float *weights = BLI_array_alloca(weights, coarse_poly->totloop);
- int *indices = BLI_array_alloca(indices, coarse_poly->totloop);
- for (int i = 0; i < coarse_poly->totloop; ++i) {
- weights[i] = weight;
- indices[i] = coarse_poly->loopstart + i;
- }
- CustomData_interp(&coarse_mesh->ldata,
- &loop_interpolation->loop_data_storage,
- indices,
- weights, NULL,
- coarse_poly->totloop,
- 2);
- }
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ if (coarse_poly->totloop == 4) {
+ loop_interpolation->loop_data = &coarse_mesh->ldata;
+ loop_interpolation->loop_indices[0] = coarse_poly->loopstart + 0;
+ loop_interpolation->loop_indices[1] = coarse_poly->loopstart + 1;
+ loop_interpolation->loop_indices[2] = coarse_poly->loopstart + 2;
+ loop_interpolation->loop_indices[3] = coarse_poly->loopstart + 3;
+ loop_interpolation->loop_data_storage_allocated = false;
+ }
+ else {
+ loop_interpolation->loop_data = &loop_interpolation->loop_data_storage;
+ /* Allocate storage for loops corresponding to ptex corners. */
+ CustomData_copy(&ctx->coarse_mesh->ldata,
+ &loop_interpolation->loop_data_storage,
+ CD_MASK_EVERYTHING.lmask,
+ CD_CALLOC,
+ 4);
+ /* Initialize indices. */
+ loop_interpolation->loop_indices[0] = 0;
+ loop_interpolation->loop_indices[1] = 1;
+ loop_interpolation->loop_indices[2] = 2;
+ loop_interpolation->loop_indices[3] = 3;
+ loop_interpolation->loop_data_storage_allocated = true;
+ /* Interpolate center of poly right away, it stays unchanged for all
+ * ptex faces. */
+ const float weight = 1.0f / (float)coarse_poly->totloop;
+ float *weights = BLI_array_alloca(weights, coarse_poly->totloop);
+ int *indices = BLI_array_alloca(indices, coarse_poly->totloop);
+ for (int i = 0; i < coarse_poly->totloop; ++i) {
+ weights[i] = weight;
+ indices[i] = coarse_poly->loopstart + i;
+ }
+ CustomData_interp(&coarse_mesh->ldata,
+ &loop_interpolation->loop_data_storage,
+ indices,
+ weights,
+ NULL,
+ coarse_poly->totloop,
+ 2);
+ }
}
-static void loop_interpolation_from_corner(
- const SubdivMeshContext *ctx,
- LoopsForInterpolation *loop_interpolation,
- const MPoly *coarse_poly,
- const int corner)
+static void loop_interpolation_from_corner(const SubdivMeshContext *ctx,
+ LoopsForInterpolation *loop_interpolation,
+ const MPoly *coarse_poly,
+ const int corner)
{
- if (coarse_poly->totloop == 4) {
- /* Nothing to do, all indices and data is already assigned. */
- }
- else {
- const CustomData *loop_data = &ctx->coarse_mesh->ldata;
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MLoop *coarse_mloop = coarse_mesh->mloop;
- LoopsOfPtex loops_of_ptex;
- loops_of_ptex_get(ctx, &loops_of_ptex, coarse_poly, corner);
- /* Ptex face corner corresponds to a poly loop with same index. */
- CustomData_free_elem(&loop_interpolation->loop_data_storage, 0, 1);
- CustomData_copy_data(loop_data,
- &loop_interpolation->loop_data_storage,
- coarse_poly->loopstart + corner,
- 0,
- 1);
- /* Interpolate remaining ptex face corners, which hits loops
- * middle points.
- *
- * TODO(sergey): Re-use one of interpolation results from previous
- * iteration. */
- const float weights[2] = {0.5f, 0.5f};
- const int base_loop_index = coarse_poly->loopstart;
- const int first_loop_index = loops_of_ptex.first_loop - coarse_mloop;
- const int second_loop_index =
- base_loop_index +
- (first_loop_index - base_loop_index + 1) % coarse_poly->totloop;
- const int first_indices[2] = {first_loop_index, second_loop_index};
- const int last_indices[2] = {
- loops_of_ptex.last_loop - coarse_mloop,
- loops_of_ptex.first_loop - coarse_mloop};
- CustomData_interp(loop_data,
- &loop_interpolation->loop_data_storage,
- first_indices,
- weights, NULL,
- 2,
- 1);
- CustomData_interp(loop_data,
- &loop_interpolation->loop_data_storage,
- last_indices,
- weights, NULL,
- 2,
- 3);
- }
+ if (coarse_poly->totloop == 4) {
+ /* Nothing to do, all indices and data is already assigned. */
+ }
+ else {
+ const CustomData *loop_data = &ctx->coarse_mesh->ldata;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ LoopsOfPtex loops_of_ptex;
+ loops_of_ptex_get(ctx, &loops_of_ptex, coarse_poly, corner);
+ /* Ptex face corner corresponds to a poly loop with same index. */
+ CustomData_free_elem(&loop_interpolation->loop_data_storage, 0, 1);
+ CustomData_copy_data(
+ loop_data, &loop_interpolation->loop_data_storage, coarse_poly->loopstart + corner, 0, 1);
+ /* Interpolate remaining ptex face corners, which hits loops
+ * middle points.
+ *
+ * TODO(sergey): Re-use one of interpolation results from previous
+ * iteration. */
+ const float weights[2] = {0.5f, 0.5f};
+ const int base_loop_index = coarse_poly->loopstart;
+ const int first_loop_index = loops_of_ptex.first_loop - coarse_mloop;
+ const int second_loop_index = base_loop_index +
+ (first_loop_index - base_loop_index + 1) % coarse_poly->totloop;
+ const int first_indices[2] = {first_loop_index, second_loop_index};
+ const int last_indices[2] = {loops_of_ptex.last_loop - coarse_mloop,
+ loops_of_ptex.first_loop - coarse_mloop};
+ CustomData_interp(
+ loop_data, &loop_interpolation->loop_data_storage, first_indices, weights, NULL, 2, 1);
+ CustomData_interp(
+ loop_data, &loop_interpolation->loop_data_storage, last_indices, weights, NULL, 2, 3);
+ }
}
static void loop_interpolation_end(LoopsForInterpolation *loop_interpolation)
{
- if (loop_interpolation->loop_data_storage_allocated) {
- CustomData_free(&loop_interpolation->loop_data_storage, 4);
- }
+ if (loop_interpolation->loop_data_storage_allocated) {
+ CustomData_free(&loop_interpolation->loop_data_storage, 4);
+ }
}
/* =============================================================================
@@ -447,516 +414,472 @@ static void loop_interpolation_end(LoopsForInterpolation *loop_interpolation)
*/
typedef struct SubdivMeshTLS {
- bool vertex_interpolation_initialized;
- VerticesForInterpolation vertex_interpolation;
- const MPoly *vertex_interpolation_coarse_poly;
- int vertex_interpolation_coarse_corner;
-
- bool loop_interpolation_initialized;
- LoopsForInterpolation loop_interpolation;
- const MPoly *loop_interpolation_coarse_poly;
- int loop_interpolation_coarse_corner;
+ bool vertex_interpolation_initialized;
+ VerticesForInterpolation vertex_interpolation;
+ const MPoly *vertex_interpolation_coarse_poly;
+ int vertex_interpolation_coarse_corner;
+
+ bool loop_interpolation_initialized;
+ LoopsForInterpolation loop_interpolation;
+ const MPoly *loop_interpolation_coarse_poly;
+ int loop_interpolation_coarse_corner;
} SubdivMeshTLS;
static void subdiv_mesh_tls_free(void *tls_v)
{
- SubdivMeshTLS *tls = tls_v;
- if (tls->vertex_interpolation_initialized) {
- vertex_interpolation_end(&tls->vertex_interpolation);
- }
- if (tls->loop_interpolation_initialized) {
- loop_interpolation_end(&tls->loop_interpolation);
- }
+ SubdivMeshTLS *tls = tls_v;
+ if (tls->vertex_interpolation_initialized) {
+ vertex_interpolation_end(&tls->vertex_interpolation);
+ }
+ if (tls->loop_interpolation_initialized) {
+ loop_interpolation_end(&tls->loop_interpolation);
+ }
}
/* =============================================================================
* Evaluation helper functions.
*/
-static void eval_final_point_and_vertex_normal(
- Subdiv *subdiv,
- const int ptex_face_index,
- const float u, const float v,
- float r_P[3], short r_N[3])
+static void eval_final_point_and_vertex_normal(Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ float r_P[3],
+ short r_N[3])
{
- if (subdiv->displacement_evaluator == NULL) {
- BKE_subdiv_eval_limit_point_and_short_normal(
- subdiv, ptex_face_index, u, v, r_P, r_N);
- }
- else {
- BKE_subdiv_eval_final_point(
- subdiv, ptex_face_index, u, v, r_P);
- }
+ if (subdiv->displacement_evaluator == NULL) {
+ BKE_subdiv_eval_limit_point_and_short_normal(subdiv, ptex_face_index, u, v, r_P, r_N);
+ }
+ else {
+ BKE_subdiv_eval_final_point(subdiv, ptex_face_index, u, v, r_P);
+ }
}
/* =============================================================================
* Accumulation helpers.
*/
-static void subdiv_accumulate_vertex_normal_and_displacement(
- SubdivMeshContext *ctx,
- const int ptex_face_index,
- const float u, const float v,
- MVert *subdiv_vert)
+static void subdiv_accumulate_vertex_normal_and_displacement(SubdivMeshContext *ctx,
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ MVert *subdiv_vert)
{
- Subdiv *subdiv = ctx->subdiv;
- const int subdiv_vertex_index = subdiv_vert - ctx->subdiv_mesh->mvert;
- float dummy_P[3], dPdu[3], dPdv[3], D[3];
- BKE_subdiv_eval_limit_point_and_derivatives(
- subdiv, ptex_face_index, u, v, dummy_P, dPdu, dPdv);
- /* Accumulate normal. */
- if (ctx->can_evaluate_normals) {
- float N[3];
- cross_v3_v3v3(N, dPdu, dPdv);
- normalize_v3(N);
- add_v3_v3(ctx->accumulated_normals[subdiv_vertex_index], N);
- }
- /* Accumulate displacement if needed. */
- if (ctx->have_displacement) {
- BKE_subdiv_eval_displacement(
- subdiv, ptex_face_index, u, v, dPdu, dPdv, D);
- add_v3_v3(subdiv_vert->co, D);
- }
- ++ctx->accumulated_counters[subdiv_vertex_index];
+ Subdiv *subdiv = ctx->subdiv;
+ const int subdiv_vertex_index = subdiv_vert - ctx->subdiv_mesh->mvert;
+ float dummy_P[3], dPdu[3], dPdv[3], D[3];
+ BKE_subdiv_eval_limit_point_and_derivatives(subdiv, ptex_face_index, u, v, dummy_P, dPdu, dPdv);
+ /* Accumulate normal. */
+ if (ctx->can_evaluate_normals) {
+ float N[3];
+ cross_v3_v3v3(N, dPdu, dPdv);
+ normalize_v3(N);
+ add_v3_v3(ctx->accumulated_normals[subdiv_vertex_index], N);
+ }
+ /* Accumulate displacement if needed. */
+ if (ctx->have_displacement) {
+ BKE_subdiv_eval_displacement(subdiv, ptex_face_index, u, v, dPdu, dPdv, D);
+ add_v3_v3(subdiv_vert->co, D);
+ }
+ ++ctx->accumulated_counters[subdiv_vertex_index];
}
/* =============================================================================
* Callbacks.
*/
-static bool subdiv_mesh_topology_info(
- const SubdivForeachContext *foreach_context,
- const int num_vertices,
- const int num_edges,
- const int num_loops,
- const int num_polygons)
+static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_context,
+ const int num_vertices,
+ const int num_edges,
+ const int num_loops,
+ const int num_polygons)
{
- SubdivMeshContext *subdiv_context = foreach_context->user_data;
- subdiv_context->subdiv_mesh = BKE_mesh_new_nomain_from_template(
- subdiv_context->coarse_mesh,
- num_vertices,
- num_edges,
- 0,
- num_loops,
- num_polygons);
- subdiv_mesh_ctx_cache_custom_data_layers(subdiv_context);
- subdiv_mesh_prepare_accumulator(subdiv_context, num_vertices);
- return true;
+ SubdivMeshContext *subdiv_context = foreach_context->user_data;
+ subdiv_context->subdiv_mesh = BKE_mesh_new_nomain_from_template(
+ subdiv_context->coarse_mesh, num_vertices, num_edges, 0, num_loops, num_polygons);
+ subdiv_mesh_ctx_cache_custom_data_layers(subdiv_context);
+ subdiv_mesh_prepare_accumulator(subdiv_context, num_vertices);
+ return true;
}
/* =============================================================================
* Vertex subdivision process.
*/
-static void subdiv_vertex_data_copy(
- const SubdivMeshContext *ctx,
- const MVert *coarse_vertex,
- MVert *subdiv_vertex)
+static void subdiv_vertex_data_copy(const SubdivMeshContext *ctx,
+ const MVert *coarse_vertex,
+ MVert *subdiv_vertex)
{
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- Mesh *subdiv_mesh = ctx->subdiv_mesh;
- const int coarse_vertex_index = coarse_vertex - coarse_mesh->mvert;
- const int subdiv_vertex_index = subdiv_vertex - subdiv_mesh->mvert;
- CustomData_copy_data(&coarse_mesh->vdata,
- &ctx->subdiv_mesh->vdata,
- coarse_vertex_index,
- subdiv_vertex_index,
- 1);
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ const int coarse_vertex_index = coarse_vertex - coarse_mesh->mvert;
+ const int subdiv_vertex_index = subdiv_vertex - subdiv_mesh->mvert;
+ CustomData_copy_data(
+ &coarse_mesh->vdata, &ctx->subdiv_mesh->vdata, coarse_vertex_index, subdiv_vertex_index, 1);
}
-static void subdiv_vertex_data_interpolate(
- const SubdivMeshContext *ctx,
- MVert *subdiv_vertex,
- const VerticesForInterpolation *vertex_interpolation,
- const float u, const float v)
+static void subdiv_vertex_data_interpolate(const SubdivMeshContext *ctx,
+ MVert *subdiv_vertex,
+ const VerticesForInterpolation *vertex_interpolation,
+ const float u,
+ const float v)
{
- const int subdiv_vertex_index = subdiv_vertex - ctx->subdiv_mesh->mvert;
- const float weights[4] = {(1.0f - u) * (1.0f - v),
- u * (1.0f - v),
- u * v,
- (1.0f - u) * v};
- CustomData_interp(vertex_interpolation->vertex_data,
- &ctx->subdiv_mesh->vdata,
- vertex_interpolation->vertex_indices,
- weights, NULL,
- 4,
- subdiv_vertex_index);
- if (ctx->vert_origindex != NULL) {
- ctx->vert_origindex[subdiv_vertex_index] = ORIGINDEX_NONE;
- }
+ const int subdiv_vertex_index = subdiv_vertex - ctx->subdiv_mesh->mvert;
+ const float weights[4] = {(1.0f - u) * (1.0f - v), u * (1.0f - v), u * v, (1.0f - u) * v};
+ CustomData_interp(vertex_interpolation->vertex_data,
+ &ctx->subdiv_mesh->vdata,
+ vertex_interpolation->vertex_indices,
+ weights,
+ NULL,
+ 4,
+ subdiv_vertex_index);
+ if (ctx->vert_origindex != NULL) {
+ ctx->vert_origindex[subdiv_vertex_index] = ORIGINDEX_NONE;
+ }
}
-static void evaluate_vertex_and_apply_displacement_copy(
- const SubdivMeshContext *ctx,
- const int ptex_face_index,
- const float u, const float v,
- const MVert *coarse_vert,
- MVert *subdiv_vert)
+static void evaluate_vertex_and_apply_displacement_copy(const SubdivMeshContext *ctx,
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ const MVert *coarse_vert,
+ MVert *subdiv_vert)
{
- const int subdiv_vertex_index = subdiv_vert - ctx->subdiv_mesh->mvert;
- const float inv_num_accumulated =
- 1.0f / ctx->accumulated_counters[subdiv_vertex_index];
- /* Displacement is accumulated in subdiv vertex position.
- * Needs to be backed up before copying data from original vertex. */
- float D[3] = {0.0f, 0.0f, 0.0f};
- if (ctx->have_displacement) {
- copy_v3_v3(D, subdiv_vert->co);
- mul_v3_fl(D, inv_num_accumulated);
- }
- /* Copy custom data and evaluate position. */
- subdiv_vertex_data_copy(ctx, coarse_vert, subdiv_vert);
- BKE_subdiv_eval_limit_point(
- ctx->subdiv, ptex_face_index, u, v, subdiv_vert->co);
- /* Apply displacement. */
- add_v3_v3(subdiv_vert->co, D);
- /* Copy normal from accumulated storage. */
- if (ctx->can_evaluate_normals) {
- float N[3];
- copy_v3_v3(N, ctx->accumulated_normals[subdiv_vertex_index]);
- normalize_v3(N);
- normal_float_to_short_v3(subdiv_vert->no, N);
- }
+ const int subdiv_vertex_index = subdiv_vert - ctx->subdiv_mesh->mvert;
+ const float inv_num_accumulated = 1.0f / ctx->accumulated_counters[subdiv_vertex_index];
+ /* Displacement is accumulated in subdiv vertex position.
+ * Needs to be backed up before copying data from original vertex. */
+ float D[3] = {0.0f, 0.0f, 0.0f};
+ if (ctx->have_displacement) {
+ copy_v3_v3(D, subdiv_vert->co);
+ mul_v3_fl(D, inv_num_accumulated);
+ }
+ /* Copy custom data and evaluate position. */
+ subdiv_vertex_data_copy(ctx, coarse_vert, subdiv_vert);
+ BKE_subdiv_eval_limit_point(ctx->subdiv, ptex_face_index, u, v, subdiv_vert->co);
+ /* Apply displacement. */
+ add_v3_v3(subdiv_vert->co, D);
+ /* Copy normal from accumulated storage. */
+ if (ctx->can_evaluate_normals) {
+ float N[3];
+ copy_v3_v3(N, ctx->accumulated_normals[subdiv_vertex_index]);
+ normalize_v3(N);
+ normal_float_to_short_v3(subdiv_vert->no, N);
+ }
}
static void evaluate_vertex_and_apply_displacement_interpolate(
- const SubdivMeshContext *ctx,
- const int ptex_face_index,
- const float u, const float v,
- VerticesForInterpolation *vertex_interpolation,
- MVert *subdiv_vert)
+ const SubdivMeshContext *ctx,
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ VerticesForInterpolation *vertex_interpolation,
+ MVert *subdiv_vert)
{
- const int subdiv_vertex_index = subdiv_vert - ctx->subdiv_mesh->mvert;
- const float inv_num_accumulated =
- 1.0f / ctx->accumulated_counters[subdiv_vertex_index];
- /* Displacement is accumulated in subdiv vertex position.
- * Needs to be backed up before copying data from original vertex. */
- float D[3] = {0.0f, 0.0f, 0.0f};
- if (ctx->have_displacement) {
- copy_v3_v3(D, subdiv_vert->co);
- mul_v3_fl(D, inv_num_accumulated);
- }
- /* Interpolate custom data and evaluate position. */
- subdiv_vertex_data_interpolate(
- ctx, subdiv_vert, vertex_interpolation, u, v);
- BKE_subdiv_eval_limit_point(
- ctx->subdiv, ptex_face_index, u, v, subdiv_vert->co);
- /* Apply displacement. */
- add_v3_v3(subdiv_vert->co, D);
- /* Copy normal from accumulated storage. */
- if (ctx->can_evaluate_normals) {
- float N[3];
- copy_v3_v3(N, ctx->accumulated_normals[subdiv_vertex_index]);
- mul_v3_fl(N, inv_num_accumulated);
- normalize_v3(N);
- normal_float_to_short_v3(subdiv_vert->no, N);
- }
+ const int subdiv_vertex_index = subdiv_vert - ctx->subdiv_mesh->mvert;
+ const float inv_num_accumulated = 1.0f / ctx->accumulated_counters[subdiv_vertex_index];
+ /* Displacement is accumulated in subdiv vertex position.
+ * Needs to be backed up before copying data from original vertex. */
+ float D[3] = {0.0f, 0.0f, 0.0f};
+ if (ctx->have_displacement) {
+ copy_v3_v3(D, subdiv_vert->co);
+ mul_v3_fl(D, inv_num_accumulated);
+ }
+ /* Interpolate custom data and evaluate position. */
+ subdiv_vertex_data_interpolate(ctx, subdiv_vert, vertex_interpolation, u, v);
+ BKE_subdiv_eval_limit_point(ctx->subdiv, ptex_face_index, u, v, subdiv_vert->co);
+ /* Apply displacement. */
+ add_v3_v3(subdiv_vert->co, D);
+ /* Copy normal from accumulated storage. */
+ if (ctx->can_evaluate_normals) {
+ float N[3];
+ copy_v3_v3(N, ctx->accumulated_normals[subdiv_vertex_index]);
+ mul_v3_fl(N, inv_num_accumulated);
+ normalize_v3(N);
+ normal_float_to_short_v3(subdiv_vert->no, N);
+ }
}
-static void subdiv_mesh_vertex_every_corner_or_edge(
- const SubdivForeachContext *foreach_context,
- void *UNUSED(tls),
- const int ptex_face_index,
- const float u, const float v,
- const int subdiv_vertex_index)
+static void subdiv_mesh_vertex_every_corner_or_edge(const SubdivForeachContext *foreach_context,
+ void *UNUSED(tls),
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ const int subdiv_vertex_index)
{
- SubdivMeshContext *ctx = foreach_context->user_data;
- Mesh *subdiv_mesh = ctx->subdiv_mesh;
- MVert *subdiv_mvert = subdiv_mesh->mvert;
- MVert *subdiv_vert = &subdiv_mvert[subdiv_vertex_index];
- subdiv_accumulate_vertex_normal_and_displacement(
- ctx, ptex_face_index, u, v, subdiv_vert);
+ SubdivMeshContext *ctx = foreach_context->user_data;
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MVert *subdiv_mvert = subdiv_mesh->mvert;
+ MVert *subdiv_vert = &subdiv_mvert[subdiv_vertex_index];
+ subdiv_accumulate_vertex_normal_and_displacement(ctx, ptex_face_index, u, v, subdiv_vert);
}
-static void subdiv_mesh_vertex_every_corner(
- const SubdivForeachContext *foreach_context,
- void *tls,
- const int ptex_face_index,
- const float u, const float v,
- const int UNUSED(coarse_vertex_index),
- const int UNUSED(coarse_poly_index),
- const int UNUSED(coarse_corner),
- const int subdiv_vertex_index)
+static void subdiv_mesh_vertex_every_corner(const SubdivForeachContext *foreach_context,
+ void *tls,
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ const int UNUSED(coarse_vertex_index),
+ const int UNUSED(coarse_poly_index),
+ const int UNUSED(coarse_corner),
+ const int subdiv_vertex_index)
{
- subdiv_mesh_vertex_every_corner_or_edge(
- foreach_context, tls, ptex_face_index, u, v, subdiv_vertex_index);
+ subdiv_mesh_vertex_every_corner_or_edge(
+ foreach_context, tls, ptex_face_index, u, v, subdiv_vertex_index);
}
-static void subdiv_mesh_vertex_every_edge(
- const SubdivForeachContext *foreach_context,
- void *tls,
- const int ptex_face_index,
- const float u, const float v,
- const int UNUSED(coarse_edge_index),
- const int UNUSED(coarse_poly_index),
- const int UNUSED(coarse_corner),
- const int subdiv_vertex_index)
+static void subdiv_mesh_vertex_every_edge(const SubdivForeachContext *foreach_context,
+ void *tls,
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ const int UNUSED(coarse_edge_index),
+ const int UNUSED(coarse_poly_index),
+ const int UNUSED(coarse_corner),
+ const int subdiv_vertex_index)
{
- subdiv_mesh_vertex_every_corner_or_edge(
- foreach_context, tls, ptex_face_index, u, v, subdiv_vertex_index);
+ subdiv_mesh_vertex_every_corner_or_edge(
+ foreach_context, tls, ptex_face_index, u, v, subdiv_vertex_index);
}
-static void subdiv_mesh_vertex_corner(
- const SubdivForeachContext *foreach_context,
- void *UNUSED(tls),
- const int ptex_face_index,
- const float u, const float v,
- const int coarse_vertex_index,
- const int UNUSED(coarse_poly_index),
- const int UNUSED(coarse_corner),
- const int subdiv_vertex_index)
+static void subdiv_mesh_vertex_corner(const SubdivForeachContext *foreach_context,
+ void *UNUSED(tls),
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ const int coarse_vertex_index,
+ const int UNUSED(coarse_poly_index),
+ const int UNUSED(coarse_corner),
+ const int subdiv_vertex_index)
{
- BLI_assert(coarse_vertex_index != ORIGINDEX_NONE);
- SubdivMeshContext *ctx = foreach_context->user_data;
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MVert *coarse_mvert = coarse_mesh->mvert;
- Mesh *subdiv_mesh = ctx->subdiv_mesh;
- MVert *subdiv_mvert = subdiv_mesh->mvert;
- const MVert *coarse_vert = &coarse_mvert[coarse_vertex_index];
- MVert *subdiv_vert = &subdiv_mvert[subdiv_vertex_index];
- evaluate_vertex_and_apply_displacement_copy(
- ctx, ptex_face_index, u, v, coarse_vert, subdiv_vert);
+ BLI_assert(coarse_vertex_index != ORIGINDEX_NONE);
+ SubdivMeshContext *ctx = foreach_context->user_data;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MVert *coarse_mvert = coarse_mesh->mvert;
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MVert *subdiv_mvert = subdiv_mesh->mvert;
+ const MVert *coarse_vert = &coarse_mvert[coarse_vertex_index];
+ MVert *subdiv_vert = &subdiv_mvert[subdiv_vertex_index];
+ evaluate_vertex_and_apply_displacement_copy(
+ ctx, ptex_face_index, u, v, coarse_vert, subdiv_vert);
}
-static void subdiv_mesh_ensure_vertex_interpolation(
- SubdivMeshContext *ctx,
- SubdivMeshTLS *tls,
- const MPoly *coarse_poly,
- const int coarse_corner)
+static void subdiv_mesh_ensure_vertex_interpolation(SubdivMeshContext *ctx,
+ SubdivMeshTLS *tls,
+ const MPoly *coarse_poly,
+ const int coarse_corner)
{
- /* Check whether we've moved to another corner or polygon. */
- if (tls->vertex_interpolation_initialized) {
- if (tls->vertex_interpolation_coarse_poly != coarse_poly ||
- tls->vertex_interpolation_coarse_corner != coarse_corner)
- {
- vertex_interpolation_end(&tls->vertex_interpolation);
- tls->vertex_interpolation_initialized = false;
- }
- }
- /* Initialize the interpolation. */
- if (!tls->vertex_interpolation_initialized) {
- vertex_interpolation_init(ctx, &tls->vertex_interpolation, coarse_poly);
- }
- /* Update it for a new corner if needed. */
- if (!tls->vertex_interpolation_initialized ||
- tls->vertex_interpolation_coarse_corner != coarse_corner)
- {
- vertex_interpolation_from_corner(
- ctx, &tls->vertex_interpolation, coarse_poly, coarse_corner);
- }
- /* Store settings used for the current state of interpolator. */
- tls->vertex_interpolation_initialized = true;
- tls->vertex_interpolation_coarse_poly = coarse_poly;
- tls->vertex_interpolation_coarse_corner = coarse_corner;
+ /* Check whether we've moved to another corner or polygon. */
+ if (tls->vertex_interpolation_initialized) {
+ if (tls->vertex_interpolation_coarse_poly != coarse_poly ||
+ tls->vertex_interpolation_coarse_corner != coarse_corner) {
+ vertex_interpolation_end(&tls->vertex_interpolation);
+ tls->vertex_interpolation_initialized = false;
+ }
+ }
+ /* Initialize the interpolation. */
+ if (!tls->vertex_interpolation_initialized) {
+ vertex_interpolation_init(ctx, &tls->vertex_interpolation, coarse_poly);
+ }
+ /* Update it for a new corner if needed. */
+ if (!tls->vertex_interpolation_initialized ||
+ tls->vertex_interpolation_coarse_corner != coarse_corner) {
+ vertex_interpolation_from_corner(ctx, &tls->vertex_interpolation, coarse_poly, coarse_corner);
+ }
+ /* Store settings used for the current state of interpolator. */
+ tls->vertex_interpolation_initialized = true;
+ tls->vertex_interpolation_coarse_poly = coarse_poly;
+ tls->vertex_interpolation_coarse_corner = coarse_corner;
}
-static void subdiv_mesh_vertex_edge(
- const SubdivForeachContext *foreach_context,
- void *tls_v,
- const int ptex_face_index,
- const float u, const float v,
- const int UNUSED(coarse_edge_index),
- const int coarse_poly_index,
- const int coarse_corner,
- const int subdiv_vertex_index)
+static void subdiv_mesh_vertex_edge(const SubdivForeachContext *foreach_context,
+ void *tls_v,
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ const int UNUSED(coarse_edge_index),
+ const int coarse_poly_index,
+ const int coarse_corner,
+ const int subdiv_vertex_index)
{
- SubdivMeshContext *ctx = foreach_context->user_data;
- SubdivMeshTLS *tls = tls_v;
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MPoly *coarse_mpoly = coarse_mesh->mpoly;
- const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index];
- Mesh *subdiv_mesh = ctx->subdiv_mesh;
- MVert *subdiv_mvert = subdiv_mesh->mvert;
- MVert *subdiv_vert = &subdiv_mvert[subdiv_vertex_index];
- subdiv_mesh_ensure_vertex_interpolation(
- ctx, tls, coarse_poly, coarse_corner);
- evaluate_vertex_and_apply_displacement_interpolate(
- ctx,
- ptex_face_index, u, v,
- &tls->vertex_interpolation,
- subdiv_vert);
+ SubdivMeshContext *ctx = foreach_context->user_data;
+ SubdivMeshTLS *tls = tls_v;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index];
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MVert *subdiv_mvert = subdiv_mesh->mvert;
+ MVert *subdiv_vert = &subdiv_mvert[subdiv_vertex_index];
+ subdiv_mesh_ensure_vertex_interpolation(ctx, tls, coarse_poly, coarse_corner);
+ evaluate_vertex_and_apply_displacement_interpolate(
+ ctx, ptex_face_index, u, v, &tls->vertex_interpolation, subdiv_vert);
}
-static void subdiv_mesh_vertex_inner(
- const SubdivForeachContext *foreach_context,
- void *tls_v,
- const int ptex_face_index,
- const float u, const float v,
- const int coarse_poly_index,
- const int coarse_corner,
- const int subdiv_vertex_index)
+static void subdiv_mesh_vertex_inner(const SubdivForeachContext *foreach_context,
+ void *tls_v,
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ const int coarse_poly_index,
+ const int coarse_corner,
+ const int subdiv_vertex_index)
{
- SubdivMeshContext *ctx = foreach_context->user_data;
- SubdivMeshTLS *tls = tls_v;
- Subdiv *subdiv = ctx->subdiv;
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MPoly *coarse_mpoly = coarse_mesh->mpoly;
- const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index];
- Mesh *subdiv_mesh = ctx->subdiv_mesh;
- MVert *subdiv_mvert = subdiv_mesh->mvert;
- MVert *subdiv_vert = &subdiv_mvert[subdiv_vertex_index];
- subdiv_mesh_ensure_vertex_interpolation(
- ctx, tls, coarse_poly, coarse_corner);
- subdiv_vertex_data_interpolate(
- ctx, subdiv_vert, &tls->vertex_interpolation, u, v);
- eval_final_point_and_vertex_normal(
- subdiv, ptex_face_index, u, v, subdiv_vert->co, subdiv_vert->no);
+ SubdivMeshContext *ctx = foreach_context->user_data;
+ SubdivMeshTLS *tls = tls_v;
+ Subdiv *subdiv = ctx->subdiv;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index];
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MVert *subdiv_mvert = subdiv_mesh->mvert;
+ MVert *subdiv_vert = &subdiv_mvert[subdiv_vertex_index];
+ subdiv_mesh_ensure_vertex_interpolation(ctx, tls, coarse_poly, coarse_corner);
+ subdiv_vertex_data_interpolate(ctx, subdiv_vert, &tls->vertex_interpolation, u, v);
+ eval_final_point_and_vertex_normal(
+ subdiv, ptex_face_index, u, v, subdiv_vert->co, subdiv_vert->no);
}
/* =============================================================================
* Edge subdivision process.
*/
-static void subdiv_copy_edge_data(
- SubdivMeshContext *ctx,
- MEdge *subdiv_edge,
- const MEdge *coarse_edge)
+static void subdiv_copy_edge_data(SubdivMeshContext *ctx,
+ MEdge *subdiv_edge,
+ const MEdge *coarse_edge)
{
- const int subdiv_edge_index = subdiv_edge - ctx->subdiv_mesh->medge;
- if (coarse_edge == NULL) {
- subdiv_edge->crease = 0;
- subdiv_edge->bweight = 0;
- subdiv_edge->flag = 0;
- if (!ctx->settings->use_optimal_display) {
- subdiv_edge->flag |= ME_EDGERENDER;
- }
- if (ctx->edge_origindex != NULL) {
- ctx->edge_origindex[subdiv_edge_index] = ORIGINDEX_NONE;
- }
- return;
- }
- const int coarse_edge_index = coarse_edge - ctx->coarse_mesh->medge;
- CustomData_copy_data(&ctx->coarse_mesh->edata,
- &ctx->subdiv_mesh->edata,
- coarse_edge_index,
- subdiv_edge_index,
- 1);
- subdiv_edge->flag |= ME_EDGERENDER;
+ const int subdiv_edge_index = subdiv_edge - ctx->subdiv_mesh->medge;
+ if (coarse_edge == NULL) {
+ subdiv_edge->crease = 0;
+ subdiv_edge->bweight = 0;
+ subdiv_edge->flag = 0;
+ if (!ctx->settings->use_optimal_display) {
+ subdiv_edge->flag |= ME_EDGERENDER;
+ }
+ if (ctx->edge_origindex != NULL) {
+ ctx->edge_origindex[subdiv_edge_index] = ORIGINDEX_NONE;
+ }
+ return;
+ }
+ const int coarse_edge_index = coarse_edge - ctx->coarse_mesh->medge;
+ CustomData_copy_data(
+ &ctx->coarse_mesh->edata, &ctx->subdiv_mesh->edata, coarse_edge_index, subdiv_edge_index, 1);
+ subdiv_edge->flag |= ME_EDGERENDER;
}
-static void subdiv_mesh_edge(
- const SubdivForeachContext *foreach_context,
- void *UNUSED(tls),
- const int coarse_edge_index,
- const int subdiv_edge_index,
- const int subdiv_v1, const int subdiv_v2)
+static void subdiv_mesh_edge(const SubdivForeachContext *foreach_context,
+ void *UNUSED(tls),
+ const int coarse_edge_index,
+ const int subdiv_edge_index,
+ const int subdiv_v1,
+ const int subdiv_v2)
{
- SubdivMeshContext *ctx = foreach_context->user_data;
- Mesh *subdiv_mesh = ctx->subdiv_mesh;
- MEdge *subdiv_medge = subdiv_mesh->medge;
- MEdge *subdiv_edge = &subdiv_medge[subdiv_edge_index];
- const MEdge *coarse_edge = NULL;
- if (coarse_edge_index != ORIGINDEX_NONE) {
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MEdge *coarse_medge = coarse_mesh->medge;
- coarse_edge = &coarse_medge[coarse_edge_index];
- }
- subdiv_copy_edge_data(ctx, subdiv_edge, coarse_edge);
- subdiv_edge->v1 = subdiv_v1;
- subdiv_edge->v2 = subdiv_v2;
+ SubdivMeshContext *ctx = foreach_context->user_data;
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MEdge *subdiv_medge = subdiv_mesh->medge;
+ MEdge *subdiv_edge = &subdiv_medge[subdiv_edge_index];
+ const MEdge *coarse_edge = NULL;
+ if (coarse_edge_index != ORIGINDEX_NONE) {
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_medge = coarse_mesh->medge;
+ coarse_edge = &coarse_medge[coarse_edge_index];
+ }
+ subdiv_copy_edge_data(ctx, subdiv_edge, coarse_edge);
+ subdiv_edge->v1 = subdiv_v1;
+ subdiv_edge->v2 = subdiv_v2;
}
/* =============================================================================
* Loops creation/interpolation.
*/
-static void subdiv_interpolate_loop_data(
- const SubdivMeshContext *ctx,
- MLoop *subdiv_loop,
- const LoopsForInterpolation *loop_interpolation,
- const float u, const float v)
+static void subdiv_interpolate_loop_data(const SubdivMeshContext *ctx,
+ MLoop *subdiv_loop,
+ const LoopsForInterpolation *loop_interpolation,
+ const float u,
+ const float v)
{
- const int subdiv_loop_index = subdiv_loop - ctx->subdiv_mesh->mloop;
- const float weights[4] = {(1.0f - u) * (1.0f - v),
- u * (1.0f - v),
- u * v,
- (1.0f - u) * v};
- CustomData_interp(loop_interpolation->loop_data,
- &ctx->subdiv_mesh->ldata,
- loop_interpolation->loop_indices,
- weights, NULL,
- 4,
- subdiv_loop_index);
- /* TODO(sergey): Set ORIGINDEX. */
+ const int subdiv_loop_index = subdiv_loop - ctx->subdiv_mesh->mloop;
+ const float weights[4] = {(1.0f - u) * (1.0f - v), u * (1.0f - v), u * v, (1.0f - u) * v};
+ CustomData_interp(loop_interpolation->loop_data,
+ &ctx->subdiv_mesh->ldata,
+ loop_interpolation->loop_indices,
+ weights,
+ NULL,
+ 4,
+ subdiv_loop_index);
+ /* TODO(sergey): Set ORIGINDEX. */
}
static void subdiv_eval_uv_layer(SubdivMeshContext *ctx,
MLoop *subdiv_loop,
const int ptex_face_index,
- const float u, const float v)
+ const float u,
+ const float v)
{
- if (ctx->num_uv_layers == 0) {
- return;
- }
- Subdiv *subdiv = ctx->subdiv;
- const int mloop_index = subdiv_loop - ctx->subdiv_mesh->mloop;
- for (int layer_index = 0; layer_index < ctx->num_uv_layers; layer_index++) {
- MLoopUV *subdiv_loopuv = &ctx->uv_layers[layer_index][mloop_index];
- BKE_subdiv_eval_face_varying(subdiv,
- layer_index,
- ptex_face_index,
- u, v,
- subdiv_loopuv->uv);
- }
+ if (ctx->num_uv_layers == 0) {
+ return;
+ }
+ Subdiv *subdiv = ctx->subdiv;
+ const int mloop_index = subdiv_loop - ctx->subdiv_mesh->mloop;
+ for (int layer_index = 0; layer_index < ctx->num_uv_layers; layer_index++) {
+ MLoopUV *subdiv_loopuv = &ctx->uv_layers[layer_index][mloop_index];
+ BKE_subdiv_eval_face_varying(subdiv, layer_index, ptex_face_index, u, v, subdiv_loopuv->uv);
+ }
}
-static void subdiv_mesh_ensure_loop_interpolation(
- SubdivMeshContext *ctx,
- SubdivMeshTLS *tls,
- const MPoly *coarse_poly,
- const int coarse_corner)
+static void subdiv_mesh_ensure_loop_interpolation(SubdivMeshContext *ctx,
+ SubdivMeshTLS *tls,
+ const MPoly *coarse_poly,
+ const int coarse_corner)
{
- /* Check whether we've moved to another corner or polygon. */
- if (tls->loop_interpolation_initialized) {
- if (tls->loop_interpolation_coarse_poly != coarse_poly ||
- tls->loop_interpolation_coarse_corner != coarse_corner)
- {
- loop_interpolation_end(&tls->loop_interpolation);
- tls->loop_interpolation_initialized = false;
- }
- }
- /* Initialize the interpolation. */
- if (!tls->loop_interpolation_initialized) {
- loop_interpolation_init(ctx, &tls->loop_interpolation, coarse_poly);
- }
- /* Update it for a new corner if needed. */
- if (!tls->loop_interpolation_initialized ||
- tls->loop_interpolation_coarse_corner != coarse_corner)
- {
- loop_interpolation_from_corner(
- ctx, &tls->loop_interpolation, coarse_poly, coarse_corner);
- }
- /* Store settings used for the current state of interpolator. */
- tls->loop_interpolation_initialized = true;
- tls->loop_interpolation_coarse_poly = coarse_poly;
- tls->loop_interpolation_coarse_corner = coarse_corner;
+ /* Check whether we've moved to another corner or polygon. */
+ if (tls->loop_interpolation_initialized) {
+ if (tls->loop_interpolation_coarse_poly != coarse_poly ||
+ tls->loop_interpolation_coarse_corner != coarse_corner) {
+ loop_interpolation_end(&tls->loop_interpolation);
+ tls->loop_interpolation_initialized = false;
+ }
+ }
+ /* Initialize the interpolation. */
+ if (!tls->loop_interpolation_initialized) {
+ loop_interpolation_init(ctx, &tls->loop_interpolation, coarse_poly);
+ }
+ /* Update it for a new corner if needed. */
+ if (!tls->loop_interpolation_initialized ||
+ tls->loop_interpolation_coarse_corner != coarse_corner) {
+ loop_interpolation_from_corner(ctx, &tls->loop_interpolation, coarse_poly, coarse_corner);
+ }
+ /* Store settings used for the current state of interpolator. */
+ tls->loop_interpolation_initialized = true;
+ tls->loop_interpolation_coarse_poly = coarse_poly;
+ tls->loop_interpolation_coarse_corner = coarse_corner;
}
-static void subdiv_mesh_loop(
- const SubdivForeachContext *foreach_context,
- void *tls_v,
- const int ptex_face_index,
- const float u, const float v,
- const int UNUSED(coarse_loop_index),
- const int coarse_poly_index,
- const int coarse_corner,
- const int subdiv_loop_index,
- const int subdiv_vertex_index, const int subdiv_edge_index)
+static void subdiv_mesh_loop(const SubdivForeachContext *foreach_context,
+ void *tls_v,
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ const int UNUSED(coarse_loop_index),
+ const int coarse_poly_index,
+ const int coarse_corner,
+ const int subdiv_loop_index,
+ const int subdiv_vertex_index,
+ const int subdiv_edge_index)
{
- SubdivMeshContext *ctx = foreach_context->user_data;
- SubdivMeshTLS *tls = tls_v;
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MPoly *coarse_mpoly = coarse_mesh->mpoly;
- const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index];
- Mesh *subdiv_mesh = ctx->subdiv_mesh;
- MLoop *subdiv_mloop = subdiv_mesh->mloop;
- MLoop *subdiv_loop = &subdiv_mloop[subdiv_loop_index];
- subdiv_mesh_ensure_loop_interpolation(
- ctx, tls, coarse_poly, coarse_corner);
- subdiv_interpolate_loop_data(
- ctx, subdiv_loop, &tls->loop_interpolation, u, v);
- subdiv_eval_uv_layer(ctx, subdiv_loop, ptex_face_index, u, v);
- subdiv_loop->v = subdiv_vertex_index;
- subdiv_loop->e = subdiv_edge_index;
+ SubdivMeshContext *ctx = foreach_context->user_data;
+ SubdivMeshTLS *tls = tls_v;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index];
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MLoop *subdiv_mloop = subdiv_mesh->mloop;
+ MLoop *subdiv_loop = &subdiv_mloop[subdiv_loop_index];
+ subdiv_mesh_ensure_loop_interpolation(ctx, tls, coarse_poly, coarse_corner);
+ subdiv_interpolate_loop_data(ctx, subdiv_loop, &tls->loop_interpolation, u, v);
+ subdiv_eval_uv_layer(ctx, subdiv_loop, ptex_face_index, u, v);
+ subdiv_loop->v = subdiv_vertex_index;
+ subdiv_loop->e = subdiv_edge_index;
}
/* =============================================================================
@@ -967,53 +890,49 @@ static void subdiv_copy_poly_data(const SubdivMeshContext *ctx,
MPoly *subdiv_poly,
const MPoly *coarse_poly)
{
- const int coarse_poly_index = coarse_poly - ctx->coarse_mesh->mpoly;
- const int subdiv_poly_index = subdiv_poly - ctx->subdiv_mesh->mpoly;
- CustomData_copy_data(&ctx->coarse_mesh->pdata,
- &ctx->subdiv_mesh->pdata,
- coarse_poly_index,
- subdiv_poly_index,
- 1);
+ const int coarse_poly_index = coarse_poly - ctx->coarse_mesh->mpoly;
+ const int subdiv_poly_index = subdiv_poly - ctx->subdiv_mesh->mpoly;
+ CustomData_copy_data(
+ &ctx->coarse_mesh->pdata, &ctx->subdiv_mesh->pdata, coarse_poly_index, subdiv_poly_index, 1);
}
-static void subdiv_mesh_poly(
- const SubdivForeachContext *foreach_context,
- void *UNUSED(tls),
- const int coarse_poly_index,
- const int subdiv_poly_index,
- const int start_loop_index, const int num_loops)
+static void subdiv_mesh_poly(const SubdivForeachContext *foreach_context,
+ void *UNUSED(tls),
+ const int coarse_poly_index,
+ const int subdiv_poly_index,
+ const int start_loop_index,
+ const int num_loops)
{
- BLI_assert(coarse_poly_index != ORIGINDEX_NONE);
- SubdivMeshContext *ctx = foreach_context->user_data;
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MPoly *coarse_mpoly = coarse_mesh->mpoly;
- const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index];
- Mesh *subdiv_mesh = ctx->subdiv_mesh;
- MPoly *subdiv_mpoly = subdiv_mesh->mpoly;
- MPoly *subdiv_poly = &subdiv_mpoly[subdiv_poly_index];
- subdiv_copy_poly_data(ctx, subdiv_poly, coarse_poly);
- subdiv_poly->loopstart = start_loop_index;
- subdiv_poly->totloop = num_loops;
+ BLI_assert(coarse_poly_index != ORIGINDEX_NONE);
+ SubdivMeshContext *ctx = foreach_context->user_data;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index];
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MPoly *subdiv_mpoly = subdiv_mesh->mpoly;
+ MPoly *subdiv_poly = &subdiv_mpoly[subdiv_poly_index];
+ subdiv_copy_poly_data(ctx, subdiv_poly, coarse_poly);
+ subdiv_poly->loopstart = start_loop_index;
+ subdiv_poly->totloop = num_loops;
}
/* =============================================================================
* Loose elements subdivision process.
*/
-static void subdiv_mesh_vertex_loose(
- const SubdivForeachContext *foreach_context,
- void *UNUSED(tls),
- const int coarse_vertex_index,
- const int subdiv_vertex_index)
+static void subdiv_mesh_vertex_loose(const SubdivForeachContext *foreach_context,
+ void *UNUSED(tls),
+ const int coarse_vertex_index,
+ const int subdiv_vertex_index)
{
- SubdivMeshContext *ctx = foreach_context->user_data;
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MVert *coarse_mvert = coarse_mesh->mvert;
- const MVert *coarse_vertex = &coarse_mvert[coarse_vertex_index];
- Mesh *subdiv_mesh = ctx->subdiv_mesh;
- MVert *subdiv_mvert = subdiv_mesh->mvert;
- MVert *subdiv_vertex = &subdiv_mvert[subdiv_vertex_index];
- subdiv_vertex_data_copy(ctx, coarse_vertex, subdiv_vertex);
+ SubdivMeshContext *ctx = foreach_context->user_data;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MVert *coarse_mvert = coarse_mesh->mvert;
+ const MVert *coarse_vertex = &coarse_mvert[coarse_vertex_index];
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MVert *subdiv_mvert = subdiv_mesh->mvert;
+ MVert *subdiv_vertex = &subdiv_mvert[subdiv_vertex_index];
+ subdiv_vertex_data_copy(ctx, coarse_vertex, subdiv_vertex);
}
/* Get neighbor edges of the given one.
@@ -1023,154 +942,140 @@ static void find_edge_neighbors(const SubdivMeshContext *ctx,
const MEdge *edge,
const MEdge *neighbors[2])
{
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MEdge *coarse_medge = coarse_mesh->medge;
- neighbors[0] = NULL;
- neighbors[1] = NULL;
- int neighbor_counters[2] = {0, 0};
- for (int edge_index = 0; edge_index < coarse_mesh->totedge; edge_index++) {
- const MEdge *current_edge = &coarse_medge[edge_index];
- if (current_edge == edge) {
- continue;
- }
- if (ELEM(edge->v1, current_edge->v1, current_edge->v2)) {
- neighbors[0] = current_edge;
- ++neighbor_counters[0];
- }
- if (ELEM(edge->v2, current_edge->v1, current_edge->v2)) {
- neighbors[1] = current_edge;
- ++neighbor_counters[1];
- }
- }
- /* Vertices which has more than one neighbor are considered infinitely
- * sharp. This is also how topology factory treats vertices of a surface
- * which are adjacent to a loose edge. */
- if (neighbor_counters[0] > 1) {
- neighbors[0] = NULL;
- }
- if (neighbor_counters[1] > 1) {
- neighbors[1] = NULL;
- }
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_medge = coarse_mesh->medge;
+ neighbors[0] = NULL;
+ neighbors[1] = NULL;
+ int neighbor_counters[2] = {0, 0};
+ for (int edge_index = 0; edge_index < coarse_mesh->totedge; edge_index++) {
+ const MEdge *current_edge = &coarse_medge[edge_index];
+ if (current_edge == edge) {
+ continue;
+ }
+ if (ELEM(edge->v1, current_edge->v1, current_edge->v2)) {
+ neighbors[0] = current_edge;
+ ++neighbor_counters[0];
+ }
+ if (ELEM(edge->v2, current_edge->v1, current_edge->v2)) {
+ neighbors[1] = current_edge;
+ ++neighbor_counters[1];
+ }
+ }
+ /* Vertices which has more than one neighbor are considered infinitely
+ * sharp. This is also how topology factory treats vertices of a surface
+ * which are adjacent to a loose edge. */
+ if (neighbor_counters[0] > 1) {
+ neighbors[0] = NULL;
+ }
+ if (neighbor_counters[1] > 1) {
+ neighbors[1] = NULL;
+ }
}
-static void points_for_loose_edges_interpolation_get(
- SubdivMeshContext *ctx,
- const MEdge *coarse_edge,
- const MEdge *neighbors[2],
- float points_r[4][3])
+static void points_for_loose_edges_interpolation_get(SubdivMeshContext *ctx,
+ const MEdge *coarse_edge,
+ const MEdge *neighbors[2],
+ float points_r[4][3])
{
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MVert *coarse_mvert = coarse_mesh->mvert;
- /* Middle points corresponds to the edge. */
- copy_v3_v3(points_r[1], coarse_mvert[coarse_edge->v1].co);
- copy_v3_v3(points_r[2], coarse_mvert[coarse_edge->v2].co);
- /* Start point, duplicate from edge start if no neighbor. */
- if (neighbors[0] != NULL) {
- if (neighbors[0]->v1 == coarse_edge->v1) {
- copy_v3_v3(points_r[0], coarse_mvert[neighbors[0]->v2].co);
- }
- else {
- copy_v3_v3(points_r[0], coarse_mvert[neighbors[0]->v1].co);
- }
- }
- else {
- sub_v3_v3v3(points_r[0], points_r[1], points_r[2]);
- add_v3_v3(points_r[0], points_r[1]);
- }
- /* End point, duplicate from edge end if no neighbor. */
- if (neighbors[1] != NULL) {
- if (neighbors[1]->v1 == coarse_edge->v2) {
- copy_v3_v3(points_r[3], coarse_mvert[neighbors[1]->v2].co);
- }
- else {
- copy_v3_v3(points_r[3], coarse_mvert[neighbors[1]->v1].co);
- }
- }
- else {
- sub_v3_v3v3(points_r[3], points_r[2], points_r[1]);
- add_v3_v3(points_r[3], points_r[2]);
- }
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MVert *coarse_mvert = coarse_mesh->mvert;
+ /* Middle points corresponds to the edge. */
+ copy_v3_v3(points_r[1], coarse_mvert[coarse_edge->v1].co);
+ copy_v3_v3(points_r[2], coarse_mvert[coarse_edge->v2].co);
+ /* Start point, duplicate from edge start if no neighbor. */
+ if (neighbors[0] != NULL) {
+ if (neighbors[0]->v1 == coarse_edge->v1) {
+ copy_v3_v3(points_r[0], coarse_mvert[neighbors[0]->v2].co);
+ }
+ else {
+ copy_v3_v3(points_r[0], coarse_mvert[neighbors[0]->v1].co);
+ }
+ }
+ else {
+ sub_v3_v3v3(points_r[0], points_r[1], points_r[2]);
+ add_v3_v3(points_r[0], points_r[1]);
+ }
+ /* End point, duplicate from edge end if no neighbor. */
+ if (neighbors[1] != NULL) {
+ if (neighbors[1]->v1 == coarse_edge->v2) {
+ copy_v3_v3(points_r[3], coarse_mvert[neighbors[1]->v2].co);
+ }
+ else {
+ copy_v3_v3(points_r[3], coarse_mvert[neighbors[1]->v1].co);
+ }
+ }
+ else {
+ sub_v3_v3v3(points_r[3], points_r[2], points_r[1]);
+ add_v3_v3(points_r[3], points_r[2]);
+ }
}
-static void subdiv_mesh_vertex_of_loose_edge_interpolate(
- SubdivMeshContext *ctx,
- const MEdge *coarse_edge,
- const float u,
- const int subdiv_vertex_index)
+static void subdiv_mesh_vertex_of_loose_edge_interpolate(SubdivMeshContext *ctx,
+ const MEdge *coarse_edge,
+ const float u,
+ const int subdiv_vertex_index)
{
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- Mesh *subdiv_mesh = ctx->subdiv_mesh;
- if (u == 0.0f) {
- CustomData_copy_data(&coarse_mesh->vdata,
- &subdiv_mesh->vdata,
- coarse_edge->v1,
- subdiv_vertex_index,
- 1);
- }
- else if (u == 1.0f) {
- CustomData_copy_data(&coarse_mesh->vdata,
- &subdiv_mesh->vdata,
- coarse_edge->v2,
- subdiv_vertex_index,
- 1);
- }
- else {
- BLI_assert(u > 0.0f);
- BLI_assert(u < 1.0f);
- const float interpolation_weights[2] = {1.0f - u, u};
- const int coarse_vertex_indices[2] = {coarse_edge->v1, coarse_edge->v2};
- CustomData_interp(&coarse_mesh->vdata,
- &subdiv_mesh->vdata,
- coarse_vertex_indices,
- interpolation_weights, NULL,
- 2, subdiv_vertex_index);
- if (ctx->vert_origindex != NULL) {
- ctx->vert_origindex[subdiv_vertex_index] = ORIGINDEX_NONE;
- }
- }
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ if (u == 0.0f) {
+ CustomData_copy_data(
+ &coarse_mesh->vdata, &subdiv_mesh->vdata, coarse_edge->v1, subdiv_vertex_index, 1);
+ }
+ else if (u == 1.0f) {
+ CustomData_copy_data(
+ &coarse_mesh->vdata, &subdiv_mesh->vdata, coarse_edge->v2, subdiv_vertex_index, 1);
+ }
+ else {
+ BLI_assert(u > 0.0f);
+ BLI_assert(u < 1.0f);
+ const float interpolation_weights[2] = {1.0f - u, u};
+ const int coarse_vertex_indices[2] = {coarse_edge->v1, coarse_edge->v2};
+ CustomData_interp(&coarse_mesh->vdata,
+ &subdiv_mesh->vdata,
+ coarse_vertex_indices,
+ interpolation_weights,
+ NULL,
+ 2,
+ subdiv_vertex_index);
+ if (ctx->vert_origindex != NULL) {
+ ctx->vert_origindex[subdiv_vertex_index] = ORIGINDEX_NONE;
+ }
+ }
}
-static void subdiv_mesh_vertex_of_loose_edge(
- const struct SubdivForeachContext *foreach_context,
- void *UNUSED(tls),
- const int coarse_edge_index,
- const float u,
- const int subdiv_vertex_index)
+static void subdiv_mesh_vertex_of_loose_edge(const struct SubdivForeachContext *foreach_context,
+ void *UNUSED(tls),
+ const int coarse_edge_index,
+ const float u,
+ const int subdiv_vertex_index)
{
- SubdivMeshContext *ctx = foreach_context->user_data;
- const Mesh *coarse_mesh = ctx->coarse_mesh;
- const MEdge *coarse_edge = &coarse_mesh->medge[coarse_edge_index];
- Mesh *subdiv_mesh = ctx->subdiv_mesh;
- MVert *subdiv_mvert = subdiv_mesh->mvert;
- /* Find neighbors of the current loose edge. */
- const MEdge *neighbors[2];
- find_edge_neighbors(ctx, coarse_edge, neighbors);
- /* Get points for b-spline interpolation. */
- float points[4][3];
- points_for_loose_edges_interpolation_get(
- ctx, coarse_edge, neighbors, points);
- /* Perform interpolation. */
- float weights[4];
- key_curve_position_weights(u, weights, KEY_BSPLINE);
- /* Interpolate custom data. */
- subdiv_mesh_vertex_of_loose_edge_interpolate(
- ctx, coarse_edge, u, subdiv_vertex_index);
- /* Initialize */
- MVert *subdiv_vertex = &subdiv_mvert[subdiv_vertex_index];
- interp_v3_v3v3v3v3(subdiv_vertex->co,
- points[0],
- points[1],
- points[2],
- points[3],
- weights);
- /* Reset flags and such. */
- subdiv_vertex->flag = 0;
- /* TODO(sergey): This matches old behavior, but we can as well interpolate
- * it. Maybe even using vertex varying attributes. */
- subdiv_vertex->bweight = 0.0f;
- /* Reset normal, initialize it in a similar way as edit mode does for a
- * vertices adjacent to a loose edges. */
- normal_float_to_short_v3(subdiv_vertex->no, subdiv_vertex->co);
+ SubdivMeshContext *ctx = foreach_context->user_data;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_edge = &coarse_mesh->medge[coarse_edge_index];
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MVert *subdiv_mvert = subdiv_mesh->mvert;
+ /* Find neighbors of the current loose edge. */
+ const MEdge *neighbors[2];
+ find_edge_neighbors(ctx, coarse_edge, neighbors);
+ /* Get points for b-spline interpolation. */
+ float points[4][3];
+ points_for_loose_edges_interpolation_get(ctx, coarse_edge, neighbors, points);
+ /* Perform interpolation. */
+ float weights[4];
+ key_curve_position_weights(u, weights, KEY_BSPLINE);
+ /* Interpolate custom data. */
+ subdiv_mesh_vertex_of_loose_edge_interpolate(ctx, coarse_edge, u, subdiv_vertex_index);
+ /* Initialize */
+ MVert *subdiv_vertex = &subdiv_mvert[subdiv_vertex_index];
+ interp_v3_v3v3v3v3(subdiv_vertex->co, points[0], points[1], points[2], points[3], weights);
+ /* Reset flags and such. */
+ subdiv_vertex->flag = 0;
+ /* TODO(sergey): This matches old behavior, but we can as well interpolate
+ * it. Maybe even using vertex varying attributes. */
+ subdiv_vertex->bweight = 0.0f;
+ /* Reset normal, initialize it in a similar way as edit mode does for a
+ * vertices adjacent to a loose edges. */
+ normal_float_to_short_v3(subdiv_vertex->no, subdiv_vertex->co);
}
/* =============================================================================
@@ -1180,82 +1085,76 @@ static void subdiv_mesh_vertex_of_loose_edge(
static void setup_foreach_callbacks(const SubdivMeshContext *subdiv_context,
SubdivForeachContext *foreach_context)
{
- memset(foreach_context, 0, sizeof(*foreach_context));
- /* General information. */
- foreach_context->topology_info = subdiv_mesh_topology_info;
- /* Every boundary geometry. Used for dispalcement and normals averaging. */
- if (subdiv_context->can_evaluate_normals ||
- subdiv_context->have_displacement)
- {
- foreach_context->vertex_every_corner = subdiv_mesh_vertex_every_corner;
- foreach_context->vertex_every_edge = subdiv_mesh_vertex_every_edge;
- }
- else {
- foreach_context->vertex_every_corner = NULL;
- foreach_context->vertex_every_edge = NULL;
- }
- foreach_context->vertex_corner = subdiv_mesh_vertex_corner;
- foreach_context->vertex_edge = subdiv_mesh_vertex_edge;
- foreach_context->vertex_inner = subdiv_mesh_vertex_inner;
- foreach_context->edge = subdiv_mesh_edge;
- foreach_context->loop = subdiv_mesh_loop;
- foreach_context->poly = subdiv_mesh_poly;
- foreach_context->vertex_loose = subdiv_mesh_vertex_loose;
- foreach_context->vertex_of_loose_edge = subdiv_mesh_vertex_of_loose_edge;
- foreach_context->user_data_tls_free = subdiv_mesh_tls_free;
+ memset(foreach_context, 0, sizeof(*foreach_context));
+ /* General information. */
+ foreach_context->topology_info = subdiv_mesh_topology_info;
+ /* Every boundary geometry. Used for dispalcement and normals averaging. */
+ if (subdiv_context->can_evaluate_normals || subdiv_context->have_displacement) {
+ foreach_context->vertex_every_corner = subdiv_mesh_vertex_every_corner;
+ foreach_context->vertex_every_edge = subdiv_mesh_vertex_every_edge;
+ }
+ else {
+ foreach_context->vertex_every_corner = NULL;
+ foreach_context->vertex_every_edge = NULL;
+ }
+ foreach_context->vertex_corner = subdiv_mesh_vertex_corner;
+ foreach_context->vertex_edge = subdiv_mesh_vertex_edge;
+ foreach_context->vertex_inner = subdiv_mesh_vertex_inner;
+ foreach_context->edge = subdiv_mesh_edge;
+ foreach_context->loop = subdiv_mesh_loop;
+ foreach_context->poly = subdiv_mesh_poly;
+ foreach_context->vertex_loose = subdiv_mesh_vertex_loose;
+ foreach_context->vertex_of_loose_edge = subdiv_mesh_vertex_of_loose_edge;
+ foreach_context->user_data_tls_free = subdiv_mesh_tls_free;
}
/* =============================================================================
* Public entry point.
*/
-Mesh *BKE_subdiv_to_mesh(
- Subdiv *subdiv,
- const SubdivToMeshSettings *settings,
- const Mesh *coarse_mesh)
+Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv,
+ const SubdivToMeshSettings *settings,
+ const Mesh *coarse_mesh)
{
- BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
- /* Make sure evaluator is up to date with possible new topology, and that
- * is is refined for the new positions of coarse vertices.
- */
- if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh)) {
- /* This could happen in two situations:
- * - OpenSubdiv is disabled.
- * - Something totally bad happened, and OpenSubdiv rejected our
- * topology.
- * In either way, we can't safely continue. */
- if (coarse_mesh->totpoly) {
- BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
- return NULL;
- }
- }
- /* Initialize subdivion mesh creation context/ */
- SubdivMeshContext subdiv_context = {0};
- subdiv_context.settings = settings;
- subdiv_context.coarse_mesh = coarse_mesh;
- subdiv_context.subdiv = subdiv;
- subdiv_context.have_displacement =
- (subdiv->displacement_evaluator != NULL);
- subdiv_context.can_evaluate_normals = !subdiv_context.have_displacement;
- /* Multi-threaded traversal/evaluation. */
- BKE_subdiv_stats_begin(&subdiv->stats,
- SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY);
- SubdivForeachContext foreach_context;
- setup_foreach_callbacks(&subdiv_context, &foreach_context);
- SubdivMeshTLS tls = {0};
- foreach_context.user_data = &subdiv_context;
- foreach_context.user_data_tls_size = sizeof(SubdivMeshTLS);
- foreach_context.user_data_tls = &tls;
- BKE_subdiv_foreach_subdiv_geometry(
- subdiv, &foreach_context, settings, coarse_mesh);
- BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY);
- Mesh *result = subdiv_context.subdiv_mesh;
- // BKE_mesh_validate(result, true, true);
- BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
- if (!subdiv_context.can_evaluate_normals) {
- result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
- }
- /* Free used memoty. */
- subdiv_mesh_context_free(&subdiv_context);
- return result;
+ BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
+ /* Make sure evaluator is up to date with possible new topology, and that
+ * is is refined for the new positions of coarse vertices.
+ */
+ if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh)) {
+ /* This could happen in two situations:
+ * - OpenSubdiv is disabled.
+ * - Something totally bad happened, and OpenSubdiv rejected our
+ * topology.
+ * In either way, we can't safely continue. */
+ if (coarse_mesh->totpoly) {
+ BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
+ return NULL;
+ }
+ }
+ /* Initialize subdivion mesh creation context/ */
+ SubdivMeshContext subdiv_context = {0};
+ subdiv_context.settings = settings;
+ subdiv_context.coarse_mesh = coarse_mesh;
+ subdiv_context.subdiv = subdiv;
+ subdiv_context.have_displacement = (subdiv->displacement_evaluator != NULL);
+ subdiv_context.can_evaluate_normals = !subdiv_context.have_displacement;
+ /* Multi-threaded traversal/evaluation. */
+ BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY);
+ SubdivForeachContext foreach_context;
+ setup_foreach_callbacks(&subdiv_context, &foreach_context);
+ SubdivMeshTLS tls = {0};
+ foreach_context.user_data = &subdiv_context;
+ foreach_context.user_data_tls_size = sizeof(SubdivMeshTLS);
+ foreach_context.user_data_tls = &tls;
+ BKE_subdiv_foreach_subdiv_geometry(subdiv, &foreach_context, settings, coarse_mesh);
+ BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY);
+ Mesh *result = subdiv_context.subdiv_mesh;
+ // BKE_mesh_validate(result, true, true);
+ BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
+ if (!subdiv_context.can_evaluate_normals) {
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ }
+ /* Free used memoty. */
+ subdiv_mesh_context_free(&subdiv_context);
+ return result;
}
diff --git a/source/blender/blenkernel/intern/subdiv_stats.c b/source/blender/blenkernel/intern/subdiv_stats.c
index 8ea9e90ff75..56d08a591ec 100644
--- a/source/blender/blenkernel/intern/subdiv_stats.c
+++ b/source/blender/blenkernel/intern/subdiv_stats.c
@@ -29,67 +29,50 @@
void BKE_subdiv_stats_init(SubdivStats *stats)
{
- stats->topology_refiner_creation_time = 0.0;
- stats->subdiv_to_mesh_time = 0.0;
- stats->subdiv_to_mesh_geometry_time = 0.0;
- stats->evaluator_creation_time = 0.0;
- stats->evaluator_refine_time = 0.0;
- stats->subdiv_to_ccg_time = 0.0;
- stats->subdiv_to_ccg_elements_time = 0.0;
- stats->topology_compare_time = 0.0;
+ stats->topology_refiner_creation_time = 0.0;
+ stats->subdiv_to_mesh_time = 0.0;
+ stats->subdiv_to_mesh_geometry_time = 0.0;
+ stats->evaluator_creation_time = 0.0;
+ stats->evaluator_refine_time = 0.0;
+ stats->subdiv_to_ccg_time = 0.0;
+ stats->subdiv_to_ccg_elements_time = 0.0;
+ stats->topology_compare_time = 0.0;
}
void BKE_subdiv_stats_begin(SubdivStats *stats, eSubdivStatsValue value)
{
- stats->begin_timestamp_[value] = PIL_check_seconds_timer();
+ stats->begin_timestamp_[value] = PIL_check_seconds_timer();
}
void BKE_subdiv_stats_end(SubdivStats *stats, eSubdivStatsValue value)
{
- stats->values_[value] =
- PIL_check_seconds_timer() - stats->begin_timestamp_[value];
+ stats->values_[value] = PIL_check_seconds_timer() - stats->begin_timestamp_[value];
}
void BKE_subdiv_stats_reset(SubdivStats *stats, eSubdivStatsValue value)
{
- stats->values_[value] = 0.0;
+ stats->values_[value] = 0.0;
}
void BKE_subdiv_stats_print(const SubdivStats *stats)
{
-#define STATS_PRINT_TIME(stats, value, description) \
- do { \
- if ((stats)->value > 0.0) { \
- printf(" %s: %f (sec)\n", description, (stats)->value); \
- } \
- } while (false)
+#define STATS_PRINT_TIME(stats, value, description) \
+ do { \
+ if ((stats)->value > 0.0) { \
+ printf(" %s: %f (sec)\n", description, (stats)->value); \
+ } \
+ } while (false)
- printf("Subdivision surface statistics:\n");
+ printf("Subdivision surface statistics:\n");
- STATS_PRINT_TIME(stats,
- topology_refiner_creation_time,
- "Topology refiner creation time");
- STATS_PRINT_TIME(stats,
- subdiv_to_mesh_time,
- "Subdivision to mesh time");
- STATS_PRINT_TIME(stats,
- subdiv_to_mesh_geometry_time,
- " Geometry time");
- STATS_PRINT_TIME(stats,
- evaluator_creation_time,
- "Evaluator creation time");
- STATS_PRINT_TIME(stats,
- evaluator_refine_time,
- "Evaluator refine time");
- STATS_PRINT_TIME(stats,
- subdiv_to_ccg_time,
- "Subdivision to CCG time");
- STATS_PRINT_TIME(stats,
- subdiv_to_ccg_elements_time,
- " Elements time");
- STATS_PRINT_TIME(stats,
- topology_compare_time,
- "Topology comparison time");
+ STATS_PRINT_TIME(stats, topology_refiner_creation_time, "Topology refiner creation time");
+ STATS_PRINT_TIME(stats, subdiv_to_mesh_time, "Subdivision to mesh time");
+ STATS_PRINT_TIME(stats, subdiv_to_mesh_geometry_time, " Geometry time");
+ STATS_PRINT_TIME(stats, evaluator_creation_time, "Evaluator creation time");
+ STATS_PRINT_TIME(stats, evaluator_refine_time, "Evaluator refine time");
+ STATS_PRINT_TIME(stats, subdiv_to_ccg_time, "Subdivision to CCG time");
+ STATS_PRINT_TIME(stats, subdiv_to_ccg_elements_time, " Elements time");
+ STATS_PRINT_TIME(stats, topology_compare_time, "Topology comparison time");
#undef STATS_PRINT_TIME
}
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index b383c049e2e..cba391a90a8 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -89,310 +89,311 @@ static int ccgDM_use_grid_pbvh(CCGDerivedMesh *ccgdm);
static void *arena_alloc(CCGAllocatorHDL a, int numBytes)
{
- return BLI_memarena_alloc(a, numBytes);
+ return BLI_memarena_alloc(a, numBytes);
}
static void *arena_realloc(CCGAllocatorHDL a, void *ptr, int newSize, int oldSize)
{
- void *p2 = BLI_memarena_alloc(a, newSize);
- if (ptr) {
- memcpy(p2, ptr, oldSize);
- }
- return p2;
+ void *p2 = BLI_memarena_alloc(a, newSize);
+ if (ptr) {
+ memcpy(p2, ptr, oldSize);
+ }
+ return p2;
}
static void arena_free(CCGAllocatorHDL UNUSED(a), void *UNUSED(ptr))
{
- /* do nothing */
+ /* do nothing */
}
static void arena_release(CCGAllocatorHDL a)
{
- BLI_memarena_free(a);
+ BLI_memarena_free(a);
}
typedef enum {
- CCG_USE_AGING = 1,
- CCG_USE_ARENA = 2,
- CCG_CALC_NORMALS = 4,
- /* add an extra four bytes for a mask layer */
- CCG_ALLOC_MASK = 8,
- CCG_SIMPLE_SUBDIV = 16,
+ CCG_USE_AGING = 1,
+ CCG_USE_ARENA = 2,
+ CCG_CALC_NORMALS = 4,
+ /* add an extra four bytes for a mask layer */
+ CCG_ALLOC_MASK = 8,
+ CCG_SIMPLE_SUBDIV = 16,
} CCGFlags;
-static CCGSubSurf *_getSubSurf(CCGSubSurf *prevSS, int subdivLevels,
- int numLayers, CCGFlags flags)
-{
- CCGMeshIFC ifc;
- CCGSubSurf *ccgSS;
- int useAging = !!(flags & CCG_USE_AGING);
- int useArena = flags & CCG_USE_ARENA;
- int normalOffset = 0;
-
- /* (subdivLevels == 0) is not allowed */
- subdivLevels = MAX2(subdivLevels, 1);
-
- if (prevSS) {
- int oldUseAging;
-
- ccgSubSurf_getUseAgeCounts(prevSS, &oldUseAging, NULL, NULL, NULL);
-
- if ((oldUseAging != useAging) ||
- (ccgSubSurf_getSimpleSubdiv(prevSS) != !!(flags & CCG_SIMPLE_SUBDIV)))
- {
- ccgSubSurf_free(prevSS);
- }
- else {
- ccgSubSurf_setSubdivisionLevels(prevSS, subdivLevels);
-
- return prevSS;
- }
- }
-
- if (useAging) {
- ifc.vertUserSize = ifc.edgeUserSize = ifc.faceUserSize = 12;
- }
- else {
- ifc.vertUserSize = ifc.edgeUserSize = ifc.faceUserSize = 8;
- }
- ifc.numLayers = numLayers;
- ifc.vertDataSize = sizeof(float) * numLayers;
- normalOffset += sizeof(float) * numLayers;
- if (flags & CCG_CALC_NORMALS)
- ifc.vertDataSize += sizeof(float) * 3;
- if (flags & CCG_ALLOC_MASK)
- ifc.vertDataSize += sizeof(float);
- ifc.simpleSubdiv = !!(flags & CCG_SIMPLE_SUBDIV);
-
- if (useArena) {
- CCGAllocatorIFC allocatorIFC;
- CCGAllocatorHDL allocator = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "subsurf arena");
-
- allocatorIFC.alloc = arena_alloc;
- allocatorIFC.realloc = arena_realloc;
- allocatorIFC.free = arena_free;
- allocatorIFC.release = arena_release;
-
- ccgSS = ccgSubSurf_new(&ifc, subdivLevels, &allocatorIFC, allocator);
- }
- else {
- ccgSS = ccgSubSurf_new(&ifc, subdivLevels, NULL, NULL);
- }
-
- if (useAging) {
- ccgSubSurf_setUseAgeCounts(ccgSS, 1, 8, 8, 8);
- }
-
- if (flags & CCG_ALLOC_MASK) {
- normalOffset += sizeof(float);
- /* mask is allocated after regular layers */
- ccgSubSurf_setAllocMask(ccgSS, 1, sizeof(float) * numLayers);
- }
-
- if (flags & CCG_CALC_NORMALS)
- ccgSubSurf_setCalcVertexNormals(ccgSS, 1, normalOffset);
- else
- ccgSubSurf_setCalcVertexNormals(ccgSS, 0, 0);
-
- return ccgSS;
+static CCGSubSurf *_getSubSurf(CCGSubSurf *prevSS, int subdivLevels, int numLayers, CCGFlags flags)
+{
+ CCGMeshIFC ifc;
+ CCGSubSurf *ccgSS;
+ int useAging = !!(flags & CCG_USE_AGING);
+ int useArena = flags & CCG_USE_ARENA;
+ int normalOffset = 0;
+
+ /* (subdivLevels == 0) is not allowed */
+ subdivLevels = MAX2(subdivLevels, 1);
+
+ if (prevSS) {
+ int oldUseAging;
+
+ ccgSubSurf_getUseAgeCounts(prevSS, &oldUseAging, NULL, NULL, NULL);
+
+ if ((oldUseAging != useAging) ||
+ (ccgSubSurf_getSimpleSubdiv(prevSS) != !!(flags & CCG_SIMPLE_SUBDIV))) {
+ ccgSubSurf_free(prevSS);
+ }
+ else {
+ ccgSubSurf_setSubdivisionLevels(prevSS, subdivLevels);
+
+ return prevSS;
+ }
+ }
+
+ if (useAging) {
+ ifc.vertUserSize = ifc.edgeUserSize = ifc.faceUserSize = 12;
+ }
+ else {
+ ifc.vertUserSize = ifc.edgeUserSize = ifc.faceUserSize = 8;
+ }
+ ifc.numLayers = numLayers;
+ ifc.vertDataSize = sizeof(float) * numLayers;
+ normalOffset += sizeof(float) * numLayers;
+ if (flags & CCG_CALC_NORMALS)
+ ifc.vertDataSize += sizeof(float) * 3;
+ if (flags & CCG_ALLOC_MASK)
+ ifc.vertDataSize += sizeof(float);
+ ifc.simpleSubdiv = !!(flags & CCG_SIMPLE_SUBDIV);
+
+ if (useArena) {
+ CCGAllocatorIFC allocatorIFC;
+ CCGAllocatorHDL allocator = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "subsurf arena");
+
+ allocatorIFC.alloc = arena_alloc;
+ allocatorIFC.realloc = arena_realloc;
+ allocatorIFC.free = arena_free;
+ allocatorIFC.release = arena_release;
+
+ ccgSS = ccgSubSurf_new(&ifc, subdivLevels, &allocatorIFC, allocator);
+ }
+ else {
+ ccgSS = ccgSubSurf_new(&ifc, subdivLevels, NULL, NULL);
+ }
+
+ if (useAging) {
+ ccgSubSurf_setUseAgeCounts(ccgSS, 1, 8, 8, 8);
+ }
+
+ if (flags & CCG_ALLOC_MASK) {
+ normalOffset += sizeof(float);
+ /* mask is allocated after regular layers */
+ ccgSubSurf_setAllocMask(ccgSS, 1, sizeof(float) * numLayers);
+ }
+
+ if (flags & CCG_CALC_NORMALS)
+ ccgSubSurf_setCalcVertexNormals(ccgSS, 1, normalOffset);
+ else
+ ccgSubSurf_setCalcVertexNormals(ccgSS, 0, 0);
+
+ return ccgSS;
}
static int getEdgeIndex(CCGSubSurf *ss, CCGEdge *e, int x, int edgeSize)
{
- CCGVert *v0 = ccgSubSurf_getEdgeVert0(e);
- CCGVert *v1 = ccgSubSurf_getEdgeVert1(e);
- int v0idx = *((int *) ccgSubSurf_getVertUserData(ss, v0));
- int v1idx = *((int *) ccgSubSurf_getVertUserData(ss, v1));
- int edgeBase = *((int *) ccgSubSurf_getEdgeUserData(ss, e));
-
- if (x == 0) {
- return v0idx;
- }
- else if (x == edgeSize - 1) {
- return v1idx;
- }
- else {
- return edgeBase + x - 1;
- }
-}
-
-static int getFaceIndex(CCGSubSurf *ss, CCGFace *f, int S, int x, int y, int edgeSize, int gridSize)
-{
- int faceBase = *((int *) ccgSubSurf_getFaceUserData(ss, f));
- int numVerts = ccgSubSurf_getFaceNumVerts(f);
-
- if (x == gridSize - 1 && y == gridSize - 1) {
- CCGVert *v = ccgSubSurf_getFaceVert(f, S);
- return *((int *) ccgSubSurf_getVertUserData(ss, v));
- }
- else if (x == gridSize - 1) {
- CCGVert *v = ccgSubSurf_getFaceVert(f, S);
- CCGEdge *e = ccgSubSurf_getFaceEdge(f, S);
- int edgeBase = *((int *) ccgSubSurf_getEdgeUserData(ss, e));
- if (v == ccgSubSurf_getEdgeVert0(e)) {
- return edgeBase + (gridSize - 1 - y) - 1;
- }
- else {
- return edgeBase + (edgeSize - 2 - 1) - ((gridSize - 1 - y) - 1);
- }
- }
- else if (y == gridSize - 1) {
- CCGVert *v = ccgSubSurf_getFaceVert(f, S);
- CCGEdge *e = ccgSubSurf_getFaceEdge(f, (S + numVerts - 1) % numVerts);
- int edgeBase = *((int *) ccgSubSurf_getEdgeUserData(ss, e));
- if (v == ccgSubSurf_getEdgeVert0(e)) {
- return edgeBase + (gridSize - 1 - x) - 1;
- }
- else {
- return edgeBase + (edgeSize - 2 - 1) - ((gridSize - 1 - x) - 1);
- }
- }
- else if (x == 0 && y == 0) {
- return faceBase;
- }
- else if (x == 0) {
- S = (S + numVerts - 1) % numVerts;
- return faceBase + 1 + (gridSize - 2) * S + (y - 1);
- }
- else if (y == 0) {
- return faceBase + 1 + (gridSize - 2) * S + (x - 1);
- }
- else {
- return faceBase + 1 + (gridSize - 2) * numVerts + S * (gridSize - 2) * (gridSize - 2) + (y - 1) * (gridSize - 2) + (x - 1);
- }
-}
-
-static void get_face_uv_map_vert(UvVertMap *vmap, struct MPoly *mpoly, struct MLoop *ml, int fi, CCGVertHDL *fverts)
-{
- UvMapVert *v, *nv;
- int j, nverts = mpoly[fi].totloop;
-
- for (j = 0; j < nverts; j++) {
- for (nv = v = BKE_mesh_uv_vert_map_get_vert(vmap, ml[j].v); v; v = v->next) {
- if (v->separate)
- nv = v;
- if (v->poly_index == fi)
- break;
- }
-
- fverts[j] = POINTER_FROM_UINT(mpoly[nv->poly_index].loopstart + nv->loop_of_poly_index);
- }
+ CCGVert *v0 = ccgSubSurf_getEdgeVert0(e);
+ CCGVert *v1 = ccgSubSurf_getEdgeVert1(e);
+ int v0idx = *((int *)ccgSubSurf_getVertUserData(ss, v0));
+ int v1idx = *((int *)ccgSubSurf_getVertUserData(ss, v1));
+ int edgeBase = *((int *)ccgSubSurf_getEdgeUserData(ss, e));
+
+ if (x == 0) {
+ return v0idx;
+ }
+ else if (x == edgeSize - 1) {
+ return v1idx;
+ }
+ else {
+ return edgeBase + x - 1;
+ }
+}
+
+static int getFaceIndex(
+ CCGSubSurf *ss, CCGFace *f, int S, int x, int y, int edgeSize, int gridSize)
+{
+ int faceBase = *((int *)ccgSubSurf_getFaceUserData(ss, f));
+ int numVerts = ccgSubSurf_getFaceNumVerts(f);
+
+ if (x == gridSize - 1 && y == gridSize - 1) {
+ CCGVert *v = ccgSubSurf_getFaceVert(f, S);
+ return *((int *)ccgSubSurf_getVertUserData(ss, v));
+ }
+ else if (x == gridSize - 1) {
+ CCGVert *v = ccgSubSurf_getFaceVert(f, S);
+ CCGEdge *e = ccgSubSurf_getFaceEdge(f, S);
+ int edgeBase = *((int *)ccgSubSurf_getEdgeUserData(ss, e));
+ if (v == ccgSubSurf_getEdgeVert0(e)) {
+ return edgeBase + (gridSize - 1 - y) - 1;
+ }
+ else {
+ return edgeBase + (edgeSize - 2 - 1) - ((gridSize - 1 - y) - 1);
+ }
+ }
+ else if (y == gridSize - 1) {
+ CCGVert *v = ccgSubSurf_getFaceVert(f, S);
+ CCGEdge *e = ccgSubSurf_getFaceEdge(f, (S + numVerts - 1) % numVerts);
+ int edgeBase = *((int *)ccgSubSurf_getEdgeUserData(ss, e));
+ if (v == ccgSubSurf_getEdgeVert0(e)) {
+ return edgeBase + (gridSize - 1 - x) - 1;
+ }
+ else {
+ return edgeBase + (edgeSize - 2 - 1) - ((gridSize - 1 - x) - 1);
+ }
+ }
+ else if (x == 0 && y == 0) {
+ return faceBase;
+ }
+ else if (x == 0) {
+ S = (S + numVerts - 1) % numVerts;
+ return faceBase + 1 + (gridSize - 2) * S + (y - 1);
+ }
+ else if (y == 0) {
+ return faceBase + 1 + (gridSize - 2) * S + (x - 1);
+ }
+ else {
+ return faceBase + 1 + (gridSize - 2) * numVerts + S * (gridSize - 2) * (gridSize - 2) +
+ (y - 1) * (gridSize - 2) + (x - 1);
+ }
+}
+
+static void get_face_uv_map_vert(
+ UvVertMap *vmap, struct MPoly *mpoly, struct MLoop *ml, int fi, CCGVertHDL *fverts)
+{
+ UvMapVert *v, *nv;
+ int j, nverts = mpoly[fi].totloop;
+
+ for (j = 0; j < nverts; j++) {
+ for (nv = v = BKE_mesh_uv_vert_map_get_vert(vmap, ml[j].v); v; v = v->next) {
+ if (v->separate)
+ nv = v;
+ if (v->poly_index == fi)
+ break;
+ }
+
+ fverts[j] = POINTER_FROM_UINT(mpoly[nv->poly_index].loopstart + nv->loop_of_poly_index);
+ }
}
static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm, MLoopUV *mloopuv)
{
- MPoly *mpoly = dm->getPolyArray(dm);
- MLoop *mloop = dm->getLoopArray(dm);
- int totvert = dm->getNumVerts(dm);
- int totface = dm->getNumPolys(dm);
- int i, seam;
- UvMapVert *v;
- UvVertMap *vmap;
- float limit[2];
+ MPoly *mpoly = dm->getPolyArray(dm);
+ MLoop *mloop = dm->getLoopArray(dm);
+ int totvert = dm->getNumVerts(dm);
+ int totface = dm->getNumPolys(dm);
+ int i, seam;
+ UvMapVert *v;
+ UvVertMap *vmap;
+ float limit[2];
#ifndef USE_DYNSIZE
- CCGVertHDL *fverts = NULL;
- BLI_array_declare(fverts);
+ CCGVertHDL *fverts = NULL;
+ BLI_array_declare(fverts);
#endif
- EdgeSet *eset;
- float uv[3] = {0.0f, 0.0f, 0.0f}; /* only first 2 values are written into */
-
- limit[0] = limit[1] = STD_UV_CONNECT_LIMIT;
- /* previous behavior here is without accounting for winding, however this causes stretching in
- * UV map in really simple cases with mirror + subsurf, see second part of T44530. Also, initially
- * intention is to treat merged vertices from mirror modifier as seams.
- * This fixes a very old regression (2.49 was correct here) */
- vmap = BKE_mesh_uv_vert_map_create(mpoly, mloop, mloopuv, totface, totvert, limit, false, true);
- if (!vmap)
- return 0;
-
- ccgSubSurf_initFullSync(ss);
-
- /* create vertices */
- for (i = 0; i < totvert; i++) {
- if (!BKE_mesh_uv_vert_map_get_vert(vmap, i))
- continue;
-
- for (v = BKE_mesh_uv_vert_map_get_vert(vmap, i)->next; v; v = v->next)
- if (v->separate)
- break;
-
- seam = (v != NULL);
-
- for (v = BKE_mesh_uv_vert_map_get_vert(vmap, i); v; v = v->next) {
- if (v->separate) {
- CCGVert *ssv;
- int loopid = mpoly[v->poly_index].loopstart + v->loop_of_poly_index;
- CCGVertHDL vhdl = POINTER_FROM_INT(loopid);
-
- copy_v2_v2(uv, mloopuv[loopid].uv);
-
- ccgSubSurf_syncVert(ss, vhdl, uv, seam, &ssv);
- }
- }
- }
-
- /* create edges */
- eset = BLI_edgeset_new_ex(__func__, BLI_EDGEHASH_SIZE_GUESS_FROM_POLYS(totface));
-
- for (i = 0; i < totface; i++) {
- MPoly *mp = &mpoly[i];
- int nverts = mp->totloop;
- int j, j_next;
- CCGFace *origf = ccgSubSurf_getFace(origss, POINTER_FROM_INT(i));
- /* unsigned int *fv = &mp->v1; */
- MLoop *ml = mloop + mp->loopstart;
+ EdgeSet *eset;
+ float uv[3] = {0.0f, 0.0f, 0.0f}; /* only first 2 values are written into */
+
+ limit[0] = limit[1] = STD_UV_CONNECT_LIMIT;
+ /* previous behavior here is without accounting for winding, however this causes stretching in
+ * UV map in really simple cases with mirror + subsurf, see second part of T44530. Also, initially
+ * intention is to treat merged vertices from mirror modifier as seams.
+ * This fixes a very old regression (2.49 was correct here) */
+ vmap = BKE_mesh_uv_vert_map_create(mpoly, mloop, mloopuv, totface, totvert, limit, false, true);
+ if (!vmap)
+ return 0;
+
+ ccgSubSurf_initFullSync(ss);
+
+ /* create vertices */
+ for (i = 0; i < totvert; i++) {
+ if (!BKE_mesh_uv_vert_map_get_vert(vmap, i))
+ continue;
+
+ for (v = BKE_mesh_uv_vert_map_get_vert(vmap, i)->next; v; v = v->next)
+ if (v->separate)
+ break;
+
+ seam = (v != NULL);
+
+ for (v = BKE_mesh_uv_vert_map_get_vert(vmap, i); v; v = v->next) {
+ if (v->separate) {
+ CCGVert *ssv;
+ int loopid = mpoly[v->poly_index].loopstart + v->loop_of_poly_index;
+ CCGVertHDL vhdl = POINTER_FROM_INT(loopid);
+
+ copy_v2_v2(uv, mloopuv[loopid].uv);
+
+ ccgSubSurf_syncVert(ss, vhdl, uv, seam, &ssv);
+ }
+ }
+ }
+
+ /* create edges */
+ eset = BLI_edgeset_new_ex(__func__, BLI_EDGEHASH_SIZE_GUESS_FROM_POLYS(totface));
+
+ for (i = 0; i < totface; i++) {
+ MPoly *mp = &mpoly[i];
+ int nverts = mp->totloop;
+ int j, j_next;
+ CCGFace *origf = ccgSubSurf_getFace(origss, POINTER_FROM_INT(i));
+ /* unsigned int *fv = &mp->v1; */
+ MLoop *ml = mloop + mp->loopstart;
#ifdef USE_DYNSIZE
- CCGVertHDL fverts[nverts];
+ CCGVertHDL fverts[nverts];
#else
- BLI_array_clear(fverts);
- BLI_array_grow_items(fverts, nverts);
+ BLI_array_clear(fverts);
+ BLI_array_grow_items(fverts, nverts);
#endif
- get_face_uv_map_vert(vmap, mpoly, ml, i, fverts);
+ get_face_uv_map_vert(vmap, mpoly, ml, i, fverts);
- for (j = 0, j_next = nverts - 1; j < nverts; j_next = j++) {
- unsigned int v0 = POINTER_AS_UINT(fverts[j_next]);
- unsigned int v1 = POINTER_AS_UINT(fverts[j]);
+ for (j = 0, j_next = nverts - 1; j < nverts; j_next = j++) {
+ unsigned int v0 = POINTER_AS_UINT(fverts[j_next]);
+ unsigned int v1 = POINTER_AS_UINT(fverts[j]);
- if (BLI_edgeset_add(eset, v0, v1)) {
- CCGEdge *e, *orige = ccgSubSurf_getFaceEdge(origf, j_next);
- CCGEdgeHDL ehdl = POINTER_FROM_INT(mp->loopstart + j_next);
- float crease = ccgSubSurf_getEdgeCrease(orige);
+ if (BLI_edgeset_add(eset, v0, v1)) {
+ CCGEdge *e, *orige = ccgSubSurf_getFaceEdge(origf, j_next);
+ CCGEdgeHDL ehdl = POINTER_FROM_INT(mp->loopstart + j_next);
+ float crease = ccgSubSurf_getEdgeCrease(orige);
- ccgSubSurf_syncEdge(ss, ehdl, fverts[j_next], fverts[j], crease, &e);
- }
- }
- }
+ ccgSubSurf_syncEdge(ss, ehdl, fverts[j_next], fverts[j], crease, &e);
+ }
+ }
+ }
- BLI_edgeset_free(eset);
+ BLI_edgeset_free(eset);
- /* create faces */
- for (i = 0; i < totface; i++) {
- MPoly *mp = &mpoly[i];
- MLoop *ml = &mloop[mp->loopstart];
- int nverts = mp->totloop;
- CCGFace *f;
+ /* create faces */
+ for (i = 0; i < totface; i++) {
+ MPoly *mp = &mpoly[i];
+ MLoop *ml = &mloop[mp->loopstart];
+ int nverts = mp->totloop;
+ CCGFace *f;
#ifdef USE_DYNSIZE
- CCGVertHDL fverts[nverts];
+ CCGVertHDL fverts[nverts];
#else
- BLI_array_clear(fverts);
- BLI_array_grow_items(fverts, nverts);
+ BLI_array_clear(fverts);
+ BLI_array_grow_items(fverts, nverts);
#endif
- get_face_uv_map_vert(vmap, mpoly, ml, i, fverts);
- ccgSubSurf_syncFace(ss, POINTER_FROM_INT(i), nverts, fverts, &f);
- }
+ get_face_uv_map_vert(vmap, mpoly, ml, i, fverts);
+ ccgSubSurf_syncFace(ss, POINTER_FROM_INT(i), nverts, fverts, &f);
+ }
#ifndef USE_DYNSIZE
- BLI_array_free(fverts);
+ BLI_array_free(fverts);
#endif
- BKE_mesh_uv_vert_map_free(vmap);
- ccgSubSurf_processSync(ss);
+ BKE_mesh_uv_vert_map_free(vmap);
+ ccgSubSurf_processSync(ss);
- return 1;
+ return 1;
}
#ifdef WITH_OPENSUBDIV
@@ -401,179 +402,169 @@ static void UNUSED_FUNCTION(set_subsurf_osd_ccg_uv)(CCGSubSurf *ss,
DerivedMesh *result,
int layer_index)
{
- CCGFace **faceMap;
- MTFace *tf;
- MLoopUV *mluv;
- CCGFaceIterator fi;
- int index, gridSize, gridFaces, totface, x, y, S;
- MLoopUV *dmloopuv = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, layer_index);
- /* need to update both CD_MTFACE & CD_MLOOPUV, hrmf, we could get away with
- * just tface except applying the modifier then looses subsurf UV */
- MTFace *tface = CustomData_get_layer_n(&result->faceData, CD_MTFACE, layer_index);
- MLoopUV *mloopuv = CustomData_get_layer_n(&result->loopData, CD_MLOOPUV, layer_index);
-
- if (dmloopuv == NULL || (tface == NULL && mloopuv == NULL)) {
- return;
- }
-
- ccgSubSurf_evaluatorSetFVarUV(ss, dm, layer_index);
-
- /* get some info from CCGSubSurf */
- totface = ccgSubSurf_getNumFaces(ss);
- gridSize = ccgSubSurf_getGridSize(ss);
- gridFaces = gridSize - 1;
-
- /* make a map from original faces to CCGFaces */
- faceMap = MEM_mallocN(totface * sizeof(*faceMap), "facemapuv");
- for (ccgSubSurf_initFaceIterator(ss, &fi); !ccgFaceIterator_isStopped(&fi); ccgFaceIterator_next(&fi)) {
- CCGFace *f = ccgFaceIterator_getCurrent(&fi);
- faceMap[POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f))] = f;
- }
-
- /* load coordinates from uvss into tface */
- tf = tface;
- mluv = mloopuv;
- for (index = 0; index < totface; index++) {
- CCGFace *f = faceMap[index];
- int numVerts = ccgSubSurf_getFaceNumVerts(f);
- for (S = 0; S < numVerts; S++) {
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- const int delta[4][2] = {{0, 0},
- {0, 1},
- {1, 1},
- {1, 0}};
- float uv[4][2];
- int i;
- for (i = 0; i < 4; i++) {
- const int dx = delta[i][0],
- dy = delta[i][1];
- const float grid_u = ((float)(x + dx)) / (gridSize - 1),
- grid_v = ((float)(y + dy)) / (gridSize - 1);
- ccgSubSurf_evaluatorFVarUV(ss,
- index,
- S,
- grid_u, grid_v,
- uv[i]);
- }
- if (tf) {
- copy_v2_v2(tf->uv[0], uv[0]);
- copy_v2_v2(tf->uv[1], uv[1]);
- copy_v2_v2(tf->uv[2], uv[2]);
- copy_v2_v2(tf->uv[3], uv[3]);
- tf++;
- }
- if (mluv) {
- copy_v2_v2(mluv[0].uv, uv[0]);
- copy_v2_v2(mluv[1].uv, uv[1]);
- copy_v2_v2(mluv[2].uv, uv[2]);
- copy_v2_v2(mluv[3].uv, uv[3]);
- mluv += 4;
- }
- }
- }
- }
- }
- MEM_freeN(faceMap);
-}
-#endif /* WITH_OPENSUBDIV */
+ CCGFace **faceMap;
+ MTFace *tf;
+ MLoopUV *mluv;
+ CCGFaceIterator fi;
+ int index, gridSize, gridFaces, totface, x, y, S;
+ MLoopUV *dmloopuv = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, layer_index);
+ /* need to update both CD_MTFACE & CD_MLOOPUV, hrmf, we could get away with
+ * just tface except applying the modifier then looses subsurf UV */
+ MTFace *tface = CustomData_get_layer_n(&result->faceData, CD_MTFACE, layer_index);
+ MLoopUV *mloopuv = CustomData_get_layer_n(&result->loopData, CD_MLOOPUV, layer_index);
+
+ if (dmloopuv == NULL || (tface == NULL && mloopuv == NULL)) {
+ return;
+ }
+
+ ccgSubSurf_evaluatorSetFVarUV(ss, dm, layer_index);
+
+ /* get some info from CCGSubSurf */
+ totface = ccgSubSurf_getNumFaces(ss);
+ gridSize = ccgSubSurf_getGridSize(ss);
+ gridFaces = gridSize - 1;
+
+ /* make a map from original faces to CCGFaces */
+ faceMap = MEM_mallocN(totface * sizeof(*faceMap), "facemapuv");
+ for (ccgSubSurf_initFaceIterator(ss, &fi); !ccgFaceIterator_isStopped(&fi);
+ ccgFaceIterator_next(&fi)) {
+ CCGFace *f = ccgFaceIterator_getCurrent(&fi);
+ faceMap[POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f))] = f;
+ }
+
+ /* load coordinates from uvss into tface */
+ tf = tface;
+ mluv = mloopuv;
+ for (index = 0; index < totface; index++) {
+ CCGFace *f = faceMap[index];
+ int numVerts = ccgSubSurf_getFaceNumVerts(f);
+ for (S = 0; S < numVerts; S++) {
+ for (y = 0; y < gridFaces; y++) {
+ for (x = 0; x < gridFaces; x++) {
+ const int delta[4][2] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}};
+ float uv[4][2];
+ int i;
+ for (i = 0; i < 4; i++) {
+ const int dx = delta[i][0], dy = delta[i][1];
+ const float grid_u = ((float)(x + dx)) / (gridSize - 1),
+ grid_v = ((float)(y + dy)) / (gridSize - 1);
+ ccgSubSurf_evaluatorFVarUV(ss, index, S, grid_u, grid_v, uv[i]);
+ }
+ if (tf) {
+ copy_v2_v2(tf->uv[0], uv[0]);
+ copy_v2_v2(tf->uv[1], uv[1]);
+ copy_v2_v2(tf->uv[2], uv[2]);
+ copy_v2_v2(tf->uv[3], uv[3]);
+ tf++;
+ }
+ if (mluv) {
+ copy_v2_v2(mluv[0].uv, uv[0]);
+ copy_v2_v2(mluv[1].uv, uv[1]);
+ copy_v2_v2(mluv[2].uv, uv[2]);
+ copy_v2_v2(mluv[3].uv, uv[3]);
+ mluv += 4;
+ }
+ }
+ }
+ }
+ }
+ MEM_freeN(faceMap);
+}
+#endif /* WITH_OPENSUBDIV */
static void set_subsurf_legacy_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result, int n)
{
- CCGSubSurf *uvss;
- CCGFace **faceMap;
- MTFace *tf;
- MLoopUV *mluv;
- CCGFaceIterator fi;
- int index, gridSize, gridFaces, /*edgeSize,*/ totface, x, y, S;
- MLoopUV *dmloopuv = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, n);
- /* need to update both CD_MTFACE & CD_MLOOPUV, hrmf, we could get away with
- * just tface except applying the modifier then looses subsurf UV */
- MTFace *tface = CustomData_get_layer_n(&result->faceData, CD_MTFACE, n);
- MLoopUV *mloopuv = CustomData_get_layer_n(&result->loopData, CD_MLOOPUV, n);
-
- if (!dmloopuv || (!tface && !mloopuv))
- return;
-
- /* create a CCGSubSurf from uv's */
- uvss = _getSubSurf(NULL, ccgSubSurf_getSubdivisionLevels(ss), 2, CCG_USE_ARENA);
-
- if (!ss_sync_from_uv(uvss, ss, dm, dmloopuv)) {
- ccgSubSurf_free(uvss);
- return;
- }
-
- /* get some info from CCGSubSurf */
- totface = ccgSubSurf_getNumFaces(uvss);
- /* edgeSize = ccgSubSurf_getEdgeSize(uvss); */ /*UNUSED*/
- gridSize = ccgSubSurf_getGridSize(uvss);
- gridFaces = gridSize - 1;
-
- /* make a map from original faces to CCGFaces */
- faceMap = MEM_mallocN(totface * sizeof(*faceMap), "facemapuv");
- for (ccgSubSurf_initFaceIterator(uvss, &fi); !ccgFaceIterator_isStopped(&fi); ccgFaceIterator_next(&fi)) {
- CCGFace *f = ccgFaceIterator_getCurrent(&fi);
- faceMap[POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f))] = f;
- }
-
- /* load coordinates from uvss into tface */
- tf = tface;
- mluv = mloopuv;
-
- for (index = 0; index < totface; index++) {
- CCGFace *f = faceMap[index];
- int numVerts = ccgSubSurf_getFaceNumVerts(f);
-
- for (S = 0; S < numVerts; S++) {
- float (*faceGridData)[2] = ccgSubSurf_getFaceGridDataArray(uvss, f, S);
-
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- float *a = faceGridData[(y + 0) * gridSize + x + 0];
- float *b = faceGridData[(y + 0) * gridSize + x + 1];
- float *c = faceGridData[(y + 1) * gridSize + x + 1];
- float *d = faceGridData[(y + 1) * gridSize + x + 0];
-
- if (tf) {
- copy_v2_v2(tf->uv[0], a);
- copy_v2_v2(tf->uv[1], d);
- copy_v2_v2(tf->uv[2], c);
- copy_v2_v2(tf->uv[3], b);
- tf++;
- }
-
- if (mluv) {
- copy_v2_v2(mluv[0].uv, a);
- copy_v2_v2(mluv[1].uv, d);
- copy_v2_v2(mluv[2].uv, c);
- copy_v2_v2(mluv[3].uv, b);
- mluv += 4;
- }
-
- }
- }
- }
- }
-
- ccgSubSurf_free(uvss);
- MEM_freeN(faceMap);
-}
-
-static void set_subsurf_uv(CCGSubSurf *ss,
- DerivedMesh *dm,
- DerivedMesh *result,
- int layer_index)
+ CCGSubSurf *uvss;
+ CCGFace **faceMap;
+ MTFace *tf;
+ MLoopUV *mluv;
+ CCGFaceIterator fi;
+ int index, gridSize, gridFaces, /*edgeSize,*/ totface, x, y, S;
+ MLoopUV *dmloopuv = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, n);
+ /* need to update both CD_MTFACE & CD_MLOOPUV, hrmf, we could get away with
+ * just tface except applying the modifier then looses subsurf UV */
+ MTFace *tface = CustomData_get_layer_n(&result->faceData, CD_MTFACE, n);
+ MLoopUV *mloopuv = CustomData_get_layer_n(&result->loopData, CD_MLOOPUV, n);
+
+ if (!dmloopuv || (!tface && !mloopuv))
+ return;
+
+ /* create a CCGSubSurf from uv's */
+ uvss = _getSubSurf(NULL, ccgSubSurf_getSubdivisionLevels(ss), 2, CCG_USE_ARENA);
+
+ if (!ss_sync_from_uv(uvss, ss, dm, dmloopuv)) {
+ ccgSubSurf_free(uvss);
+ return;
+ }
+
+ /* get some info from CCGSubSurf */
+ totface = ccgSubSurf_getNumFaces(uvss);
+ /* edgeSize = ccgSubSurf_getEdgeSize(uvss); */ /*UNUSED*/
+ gridSize = ccgSubSurf_getGridSize(uvss);
+ gridFaces = gridSize - 1;
+
+ /* make a map from original faces to CCGFaces */
+ faceMap = MEM_mallocN(totface * sizeof(*faceMap), "facemapuv");
+ for (ccgSubSurf_initFaceIterator(uvss, &fi); !ccgFaceIterator_isStopped(&fi);
+ ccgFaceIterator_next(&fi)) {
+ CCGFace *f = ccgFaceIterator_getCurrent(&fi);
+ faceMap[POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f))] = f;
+ }
+
+ /* load coordinates from uvss into tface */
+ tf = tface;
+ mluv = mloopuv;
+
+ for (index = 0; index < totface; index++) {
+ CCGFace *f = faceMap[index];
+ int numVerts = ccgSubSurf_getFaceNumVerts(f);
+
+ for (S = 0; S < numVerts; S++) {
+ float(*faceGridData)[2] = ccgSubSurf_getFaceGridDataArray(uvss, f, S);
+
+ for (y = 0; y < gridFaces; y++) {
+ for (x = 0; x < gridFaces; x++) {
+ float *a = faceGridData[(y + 0) * gridSize + x + 0];
+ float *b = faceGridData[(y + 0) * gridSize + x + 1];
+ float *c = faceGridData[(y + 1) * gridSize + x + 1];
+ float *d = faceGridData[(y + 1) * gridSize + x + 0];
+
+ if (tf) {
+ copy_v2_v2(tf->uv[0], a);
+ copy_v2_v2(tf->uv[1], d);
+ copy_v2_v2(tf->uv[2], c);
+ copy_v2_v2(tf->uv[3], b);
+ tf++;
+ }
+
+ if (mluv) {
+ copy_v2_v2(mluv[0].uv, a);
+ copy_v2_v2(mluv[1].uv, d);
+ copy_v2_v2(mluv[2].uv, c);
+ copy_v2_v2(mluv[3].uv, b);
+ mluv += 4;
+ }
+ }
+ }
+ }
+ }
+
+ ccgSubSurf_free(uvss);
+ MEM_freeN(faceMap);
+}
+
+static void set_subsurf_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result, int layer_index)
{
#ifdef WITH_OPENSUBDIV
- if (!ccgSubSurf_needGrids(ss)) {
- /* GPU backend is used, no need to evaluate UVs on CPU. */
- /* TODO(sergey): Think of how to support edit mode of UVs. */
- }
- else
+ if (!ccgSubSurf_needGrids(ss)) {
+ /* GPU backend is used, no need to evaluate UVs on CPU. */
+ /* TODO(sergey): Think of how to support edit mode of UVs. */
+ }
+ else
#endif
- {
- set_subsurf_legacy_uv(ss, dm, result, layer_index);
- }
+ {
+ set_subsurf_legacy_uv(ss, dm, result, layer_index);
+ }
}
/* face weighting */
@@ -581,82 +572,83 @@ static void set_subsurf_uv(CCGSubSurf *ss,
typedef float FaceVertWeight[SUB_ELEMS_FACE][SUB_ELEMS_FACE];
typedef struct FaceVertWeightEntry {
- FaceVertWeight *weight;
- float *w;
- int valid;
+ FaceVertWeight *weight;
+ float *w;
+ int valid;
} FaceVertWeightEntry;
typedef struct WeightTable {
- FaceVertWeightEntry *weight_table;
- int len;
+ FaceVertWeightEntry *weight_table;
+ int len;
} WeightTable;
static float *get_ss_weights(WeightTable *wtable, int gridCuts, int faceLen)
{
- int x, y, i, j;
- float *w, w1, w2, w4, fac, fac2, fx, fy;
+ int x, y, i, j;
+ float *w, w1, w2, w4, fac, fac2, fx, fy;
- if (wtable->len <= faceLen) {
- void *tmp = MEM_callocN(sizeof(FaceVertWeightEntry) * (faceLen + 1), "weight table alloc 2");
+ if (wtable->len <= faceLen) {
+ void *tmp = MEM_callocN(sizeof(FaceVertWeightEntry) * (faceLen + 1), "weight table alloc 2");
- if (wtable->len) {
- memcpy(tmp, wtable->weight_table, sizeof(FaceVertWeightEntry) * wtable->len);
- MEM_freeN(wtable->weight_table);
- }
+ if (wtable->len) {
+ memcpy(tmp, wtable->weight_table, sizeof(FaceVertWeightEntry) * wtable->len);
+ MEM_freeN(wtable->weight_table);
+ }
- wtable->weight_table = tmp;
- wtable->len = faceLen + 1;
- }
+ wtable->weight_table = tmp;
+ wtable->len = faceLen + 1;
+ }
- if (!wtable->weight_table[faceLen].valid) {
- wtable->weight_table[faceLen].valid = 1;
- wtable->weight_table[faceLen].w = w = MEM_callocN(sizeof(float) * faceLen * faceLen * (gridCuts + 2) * (gridCuts + 2), "weight table alloc");
- fac = 1.0f / (float)faceLen;
+ if (!wtable->weight_table[faceLen].valid) {
+ wtable->weight_table[faceLen].valid = 1;
+ wtable->weight_table[faceLen].w = w = MEM_callocN(
+ sizeof(float) * faceLen * faceLen * (gridCuts + 2) * (gridCuts + 2), "weight table alloc");
+ fac = 1.0f / (float)faceLen;
- for (i = 0; i < faceLen; i++) {
- for (x = 0; x < gridCuts + 2; x++) {
- for (y = 0; y < gridCuts + 2; y++) {
- fx = 0.5f - (float)x / (float)(gridCuts + 1) / 2.0f;
- fy = 0.5f - (float)y / (float)(gridCuts + 1) / 2.0f;
+ for (i = 0; i < faceLen; i++) {
+ for (x = 0; x < gridCuts + 2; x++) {
+ for (y = 0; y < gridCuts + 2; y++) {
+ fx = 0.5f - (float)x / (float)(gridCuts + 1) / 2.0f;
+ fy = 0.5f - (float)y / (float)(gridCuts + 1) / 2.0f;
- fac2 = faceLen - 4;
- w1 = (1.0f - fx) * (1.0f - fy) + (-fac2 * fx * fy * fac);
- w2 = (1.0f - fx + fac2 * fx * -fac) * (fy);
- w4 = (fx) * (1.0f - fy + -fac2 * fy * fac);
+ fac2 = faceLen - 4;
+ w1 = (1.0f - fx) * (1.0f - fy) + (-fac2 * fx * fy * fac);
+ w2 = (1.0f - fx + fac2 * fx * -fac) * (fy);
+ w4 = (fx) * (1.0f - fy + -fac2 * fy * fac);
- /* these values aren't used for tri's and cause divide by zero */
- if (faceLen > 3) {
- fac2 = 1.0f - (w1 + w2 + w4);
- fac2 = fac2 / (float)(faceLen - 3);
- for (j = 0; j < faceLen; j++) {
- w[j] = fac2;
- }
- }
+ /* these values aren't used for tri's and cause divide by zero */
+ if (faceLen > 3) {
+ fac2 = 1.0f - (w1 + w2 + w4);
+ fac2 = fac2 / (float)(faceLen - 3);
+ for (j = 0; j < faceLen; j++) {
+ w[j] = fac2;
+ }
+ }
- w[i] = w1;
- w[(i - 1 + faceLen) % faceLen] = w2;
- w[(i + 1) % faceLen] = w4;
+ w[i] = w1;
+ w[(i - 1 + faceLen) % faceLen] = w2;
+ w[(i + 1) % faceLen] = w4;
- w += faceLen;
- }
- }
- }
- }
+ w += faceLen;
+ }
+ }
+ }
+ }
- return wtable->weight_table[faceLen].w;
+ return wtable->weight_table[faceLen].w;
}
static void free_ss_weights(WeightTable *wtable)
{
- int i;
+ int i;
- for (i = 0; i < wtable->len; i++) {
- if (wtable->weight_table[i].valid)
- MEM_freeN(wtable->weight_table[i].w);
- }
+ for (i = 0; i < wtable->len; i++) {
+ if (wtable->weight_table[i].valid)
+ MEM_freeN(wtable->weight_table[i].w);
+ }
- if (wtable->weight_table)
- MEM_freeN(wtable->weight_table);
+ if (wtable->weight_table)
+ MEM_freeN(wtable->weight_table);
}
static void ss_sync_ccg_from_derivedmesh(CCGSubSurf *ss,
@@ -664,113 +656,110 @@ static void ss_sync_ccg_from_derivedmesh(CCGSubSurf *ss,
float (*vertexCos)[3],
int useFlatSubdiv)
{
- float creaseFactor = (float) ccgSubSurf_getSubdivisionLevels(ss);
+ float creaseFactor = (float)ccgSubSurf_getSubdivisionLevels(ss);
#ifndef USE_DYNSIZE
- CCGVertHDL *fVerts = NULL;
- BLI_array_declare(fVerts);
+ CCGVertHDL *fVerts = NULL;
+ BLI_array_declare(fVerts);
#endif
- MVert *mvert = dm->getVertArray(dm);
- MEdge *medge = dm->getEdgeArray(dm);
- /* MFace *mface = dm->getTessFaceArray(dm); */ /* UNUSED */
- MVert *mv;
- MEdge *me;
- MLoop *mloop = dm->getLoopArray(dm), *ml;
- MPoly *mpoly = dm->getPolyArray(dm), *mp;
- /*MFace *mf;*/ /*UNUSED*/
- int totvert = dm->getNumVerts(dm);
- int totedge = dm->getNumEdges(dm);
- /*int totface = dm->getNumTessFaces(dm);*/ /*UNUSED*/
- /*int totpoly = dm->getNumFaces(dm);*/ /*UNUSED*/
- int i, j;
- int *index;
-
- ccgSubSurf_initFullSync(ss);
-
- mv = mvert;
- index = (int *)dm->getVertDataArray(dm, CD_ORIGINDEX);
- for (i = 0; i < totvert; i++, mv++) {
- CCGVert *v;
-
- if (vertexCos) {
- ccgSubSurf_syncVert(ss, POINTER_FROM_INT(i), vertexCos[i], 0, &v);
- }
- else {
- ccgSubSurf_syncVert(ss, POINTER_FROM_INT(i), mv->co, 0, &v);
- }
-
- ((int *)ccgSubSurf_getVertUserData(ss, v))[1] = (index) ? *index++ : i;
- }
-
- me = medge;
- index = (int *)dm->getEdgeDataArray(dm, CD_ORIGINDEX);
- for (i = 0; i < totedge; i++, me++) {
- CCGEdge *e;
- float crease;
-
- crease = useFlatSubdiv ? creaseFactor :
- me->crease * creaseFactor / 255.0f;
-
- ccgSubSurf_syncEdge(ss, POINTER_FROM_INT(i), POINTER_FROM_UINT(me->v1),
- POINTER_FROM_UINT(me->v2), crease, &e);
-
- ((int *)ccgSubSurf_getEdgeUserData(ss, e))[1] = (index) ? *index++ : i;
- }
-
- mp = mpoly;
- index = (int *)dm->getPolyDataArray(dm, CD_ORIGINDEX);
- for (i = 0; i < dm->numPolyData; i++, mp++) {
- CCGFace *f;
+ MVert *mvert = dm->getVertArray(dm);
+ MEdge *medge = dm->getEdgeArray(dm);
+ /* MFace *mface = dm->getTessFaceArray(dm); */ /* UNUSED */
+ MVert *mv;
+ MEdge *me;
+ MLoop *mloop = dm->getLoopArray(dm), *ml;
+ MPoly *mpoly = dm->getPolyArray(dm), *mp;
+ /*MFace *mf;*/ /*UNUSED*/
+ int totvert = dm->getNumVerts(dm);
+ int totedge = dm->getNumEdges(dm);
+ /*int totface = dm->getNumTessFaces(dm);*/ /*UNUSED*/
+ /*int totpoly = dm->getNumFaces(dm);*/ /*UNUSED*/
+ int i, j;
+ int *index;
+
+ ccgSubSurf_initFullSync(ss);
+
+ mv = mvert;
+ index = (int *)dm->getVertDataArray(dm, CD_ORIGINDEX);
+ for (i = 0; i < totvert; i++, mv++) {
+ CCGVert *v;
+
+ if (vertexCos) {
+ ccgSubSurf_syncVert(ss, POINTER_FROM_INT(i), vertexCos[i], 0, &v);
+ }
+ else {
+ ccgSubSurf_syncVert(ss, POINTER_FROM_INT(i), mv->co, 0, &v);
+ }
+
+ ((int *)ccgSubSurf_getVertUserData(ss, v))[1] = (index) ? *index++ : i;
+ }
+
+ me = medge;
+ index = (int *)dm->getEdgeDataArray(dm, CD_ORIGINDEX);
+ for (i = 0; i < totedge; i++, me++) {
+ CCGEdge *e;
+ float crease;
+
+ crease = useFlatSubdiv ? creaseFactor : me->crease * creaseFactor / 255.0f;
+
+ ccgSubSurf_syncEdge(
+ ss, POINTER_FROM_INT(i), POINTER_FROM_UINT(me->v1), POINTER_FROM_UINT(me->v2), crease, &e);
+
+ ((int *)ccgSubSurf_getEdgeUserData(ss, e))[1] = (index) ? *index++ : i;
+ }
+
+ mp = mpoly;
+ index = (int *)dm->getPolyDataArray(dm, CD_ORIGINDEX);
+ for (i = 0; i < dm->numPolyData; i++, mp++) {
+ CCGFace *f;
#ifdef USE_DYNSIZE
- CCGVertHDL fVerts[mp->totloop];
+ CCGVertHDL fVerts[mp->totloop];
#else
- BLI_array_clear(fVerts);
- BLI_array_grow_items(fVerts, mp->totloop);
+ BLI_array_clear(fVerts);
+ BLI_array_grow_items(fVerts, mp->totloop);
#endif
- ml = mloop + mp->loopstart;
- for (j = 0; j < mp->totloop; j++, ml++) {
- fVerts[j] = POINTER_FROM_UINT(ml->v);
- }
+ ml = mloop + mp->loopstart;
+ for (j = 0; j < mp->totloop; j++, ml++) {
+ fVerts[j] = POINTER_FROM_UINT(ml->v);
+ }
- /* this is very bad, means mesh is internally inconsistent.
- * it is not really possible to continue without modifying
- * other parts of code significantly to handle missing faces.
- * since this really shouldn't even be possible we just bail.*/
- if (ccgSubSurf_syncFace(ss, POINTER_FROM_INT(i), mp->totloop,
- fVerts, &f) == eCCGError_InvalidValue)
- {
- static int hasGivenError = 0;
+ /* this is very bad, means mesh is internally inconsistent.
+ * it is not really possible to continue without modifying
+ * other parts of code significantly to handle missing faces.
+ * since this really shouldn't even be possible we just bail.*/
+ if (ccgSubSurf_syncFace(ss, POINTER_FROM_INT(i), mp->totloop, fVerts, &f) ==
+ eCCGError_InvalidValue) {
+ static int hasGivenError = 0;
- if (!hasGivenError) {
- //XXX error("Unrecoverable error in SubSurf calculation,"
- // " mesh is inconsistent.");
+ if (!hasGivenError) {
+ //XXX error("Unrecoverable error in SubSurf calculation,"
+ // " mesh is inconsistent.");
- hasGivenError = 1;
- }
+ hasGivenError = 1;
+ }
- return;
- }
+ return;
+ }
- ((int *)ccgSubSurf_getFaceUserData(ss, f))[1] = (index) ? *index++ : i;
- }
+ ((int *)ccgSubSurf_getFaceUserData(ss, f))[1] = (index) ? *index++ : i;
+ }
- ccgSubSurf_processSync(ss);
+ ccgSubSurf_processSync(ss);
#ifndef USE_DYNSIZE
- BLI_array_free(fVerts);
+ BLI_array_free(fVerts);
#endif
}
#ifdef WITH_OPENSUBDIV
-static void ss_sync_osd_from_derivedmesh(CCGSubSurf *ss,
- DerivedMesh *dm)
+static void ss_sync_osd_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm)
{
- ccgSubSurf_initFullSync(ss);
- ccgSubSurf_prepareTopologyRefiner(ss, dm);
- ccgSubSurf_processSync(ss);
+ ccgSubSurf_initFullSync(ss);
+ ccgSubSurf_prepareTopologyRefiner(ss, dm);
+ ccgSubSurf_processSync(ss);
}
-#endif /* WITH_OPENSUBDIV */
+#endif /* WITH_OPENSUBDIV */
static void ss_sync_from_derivedmesh(CCGSubSurf *ss,
DerivedMesh *dm,
@@ -779,1680 +768,1711 @@ static void ss_sync_from_derivedmesh(CCGSubSurf *ss,
bool use_subdiv_uvs)
{
#ifndef WITH_OPENSUBDIV
- UNUSED_VARS(use_subdiv_uvs);
+ UNUSED_VARS(use_subdiv_uvs);
#endif
#ifdef WITH_OPENSUBDIV
- /* Reset all related descriptors if actual mesh topology changed or if
- * other evaluation-related settings changed.
- */
- if (!ccgSubSurf_needGrids(ss)) {
- /* TODO(sergey): Use vertex coordinates and flat subdiv flag. */
- ccgSubSurf__sync_subdivUvs(ss, use_subdiv_uvs);
- ccgSubSurf_checkTopologyChanged(ss, dm);
- ss_sync_osd_from_derivedmesh(ss, dm);
- }
- else
+ /* Reset all related descriptors if actual mesh topology changed or if
+ * other evaluation-related settings changed.
+ */
+ if (!ccgSubSurf_needGrids(ss)) {
+ /* TODO(sergey): Use vertex coordinates and flat subdiv flag. */
+ ccgSubSurf__sync_subdivUvs(ss, use_subdiv_uvs);
+ ccgSubSurf_checkTopologyChanged(ss, dm);
+ ss_sync_osd_from_derivedmesh(ss, dm);
+ }
+ else
#endif
- {
- ss_sync_ccg_from_derivedmesh(ss, dm, vertexCos, use_flat_subdiv);
- }
+ {
+ ss_sync_ccg_from_derivedmesh(ss, dm, vertexCos, use_flat_subdiv);
+ }
}
/***/
static int ccgDM_getVertMapIndex(CCGSubSurf *ss, CCGVert *v)
{
- return ((int *) ccgSubSurf_getVertUserData(ss, v))[1];
+ return ((int *)ccgSubSurf_getVertUserData(ss, v))[1];
}
static int ccgDM_getEdgeMapIndex(CCGSubSurf *ss, CCGEdge *e)
{
- return ((int *) ccgSubSurf_getEdgeUserData(ss, e))[1];
+ return ((int *)ccgSubSurf_getEdgeUserData(ss, e))[1];
}
static int ccgDM_getFaceMapIndex(CCGSubSurf *ss, CCGFace *f)
{
- return ((int *) ccgSubSurf_getFaceUserData(ss, f))[1];
+ return ((int *)ccgSubSurf_getFaceUserData(ss, f))[1];
}
static void minmax_v3_v3v3(const float vec[3], float min[3], float max[3])
{
- if (min[0] > vec[0]) min[0] = vec[0];
- if (min[1] > vec[1]) min[1] = vec[1];
- if (min[2] > vec[2]) min[2] = vec[2];
- if (max[0] < vec[0]) max[0] = vec[0];
- if (max[1] < vec[1]) max[1] = vec[1];
- if (max[2] < vec[2]) max[2] = vec[2];
+ if (min[0] > vec[0])
+ min[0] = vec[0];
+ if (min[1] > vec[1])
+ min[1] = vec[1];
+ if (min[2] > vec[2])
+ min[2] = vec[2];
+ if (max[0] < vec[0])
+ max[0] = vec[0];
+ if (max[1] < vec[1])
+ max[1] = vec[1];
+ if (max[2] < vec[2])
+ max[2] = vec[2];
}
static void ccgDM_getMinMax(DerivedMesh *dm, float r_min[3], float r_max[3])
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGVertIterator vi;
- CCGEdgeIterator ei;
- CCGFaceIterator fi;
- CCGKey key;
- int i, edgeSize = ccgSubSurf_getEdgeSize(ss);
- int gridSize = ccgSubSurf_getGridSize(ss);
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ CCGVertIterator vi;
+ CCGEdgeIterator ei;
+ CCGFaceIterator fi;
+ CCGKey key;
+ int i, edgeSize = ccgSubSurf_getEdgeSize(ss);
+ int gridSize = ccgSubSurf_getGridSize(ss);
#ifdef WITH_OPENSUBDIV
- if (ccgdm->useGpuBackend) {
- ccgSubSurf_getMinMax(ccgdm->ss, r_min, r_max);
- return;
- }
+ if (ccgdm->useGpuBackend) {
+ ccgSubSurf_getMinMax(ccgdm->ss, r_min, r_max);
+ return;
+ }
#endif
- CCG_key_top_level(&key, ss);
+ CCG_key_top_level(&key, ss);
- if (!ccgSubSurf_getNumVerts(ss))
- r_min[0] = r_min[1] = r_min[2] = r_max[0] = r_max[1] = r_max[2] = 0.0;
+ if (!ccgSubSurf_getNumVerts(ss))
+ r_min[0] = r_min[1] = r_min[2] = r_max[0] = r_max[1] = r_max[2] = 0.0;
- for (ccgSubSurf_initVertIterator(ss, &vi); !ccgVertIterator_isStopped(&vi); ccgVertIterator_next(&vi)) {
- CCGVert *v = ccgVertIterator_getCurrent(&vi);
- float *co = ccgSubSurf_getVertData(ss, v);
+ for (ccgSubSurf_initVertIterator(ss, &vi); !ccgVertIterator_isStopped(&vi);
+ ccgVertIterator_next(&vi)) {
+ CCGVert *v = ccgVertIterator_getCurrent(&vi);
+ float *co = ccgSubSurf_getVertData(ss, v);
- minmax_v3_v3v3(co, r_min, r_max);
- }
+ minmax_v3_v3v3(co, r_min, r_max);
+ }
- for (ccgSubSurf_initEdgeIterator(ss, &ei); !ccgEdgeIterator_isStopped(&ei); ccgEdgeIterator_next(&ei)) {
- CCGEdge *e = ccgEdgeIterator_getCurrent(&ei);
- CCGElem *edgeData = ccgSubSurf_getEdgeDataArray(ss, e);
+ for (ccgSubSurf_initEdgeIterator(ss, &ei); !ccgEdgeIterator_isStopped(&ei);
+ ccgEdgeIterator_next(&ei)) {
+ CCGEdge *e = ccgEdgeIterator_getCurrent(&ei);
+ CCGElem *edgeData = ccgSubSurf_getEdgeDataArray(ss, e);
- for (i = 0; i < edgeSize; i++)
- minmax_v3_v3v3(CCG_elem_offset_co(&key, edgeData, i), r_min, r_max);
- }
+ for (i = 0; i < edgeSize; i++)
+ minmax_v3_v3v3(CCG_elem_offset_co(&key, edgeData, i), r_min, r_max);
+ }
- for (ccgSubSurf_initFaceIterator(ss, &fi); !ccgFaceIterator_isStopped(&fi); ccgFaceIterator_next(&fi)) {
- CCGFace *f = ccgFaceIterator_getCurrent(&fi);
- int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
+ for (ccgSubSurf_initFaceIterator(ss, &fi); !ccgFaceIterator_isStopped(&fi);
+ ccgFaceIterator_next(&fi)) {
+ CCGFace *f = ccgFaceIterator_getCurrent(&fi);
+ int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
- for (S = 0; S < numVerts; S++) {
- CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
+ for (S = 0; S < numVerts; S++) {
+ CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
- for (y = 0; y < gridSize; y++)
- for (x = 0; x < gridSize; x++)
- minmax_v3_v3v3(CCG_grid_elem_co(&key, faceGridData, x, y), r_min, r_max);
- }
- }
+ for (y = 0; y < gridSize; y++)
+ for (x = 0; x < gridSize; x++)
+ minmax_v3_v3v3(CCG_grid_elem_co(&key, faceGridData, x, y), r_min, r_max);
+ }
+ }
}
static int ccgDM_getNumVerts(DerivedMesh *dm)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
- return ccgSubSurf_getNumFinalVerts(ccgdm->ss);
+ return ccgSubSurf_getNumFinalVerts(ccgdm->ss);
}
static int ccgDM_getNumEdges(DerivedMesh *dm)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
- return ccgSubSurf_getNumFinalEdges(ccgdm->ss);
+ return ccgSubSurf_getNumFinalEdges(ccgdm->ss);
}
static int ccgDM_getNumPolys(DerivedMesh *dm)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
- return ccgSubSurf_getNumFinalFaces(ccgdm->ss);
+ return ccgSubSurf_getNumFinalFaces(ccgdm->ss);
}
static int ccgDM_getNumTessFaces(DerivedMesh *dm)
{
- return dm->numTessFaceData;
+ return dm->numTessFaceData;
}
static int ccgDM_getNumLoops(DerivedMesh *dm)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
- /* All subsurf faces are quads */
- return 4 * ccgSubSurf_getNumFinalFaces(ccgdm->ss);
+ /* All subsurf faces are quads */
+ return 4 * ccgSubSurf_getNumFinalFaces(ccgdm->ss);
}
static void ccgDM_getFinalVert(DerivedMesh *dm, int vertNum, MVert *mv)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGElem *vd;
- CCGKey key;
- int i;
-
- CCG_key_top_level(&key, ss);
- memset(mv, 0, sizeof(*mv));
-
- if ((vertNum < ccgdm->edgeMap[0].startVert) && (ccgSubSurf_getNumFaces(ss) > 0)) {
- /* this vert comes from face data */
- int lastface = ccgSubSurf_getNumFaces(ss) - 1;
- CCGFace *f;
- int x, y, grid, numVerts;
- int offset;
- int gridSize = ccgSubSurf_getGridSize(ss);
- int gridSideVerts;
- int gridInternalVerts;
- int gridSideEnd;
- int gridInternalEnd;
-
- i = 0;
- while (i < lastface && vertNum >= ccgdm->faceMap[i + 1].startVert) {
- i++;
- }
-
- f = ccgdm->faceMap[i].face;
- numVerts = ccgSubSurf_getFaceNumVerts(f);
-
- gridSideVerts = gridSize - 2;
- gridInternalVerts = gridSideVerts * gridSideVerts;
-
- gridSideEnd = 1 + numVerts * gridSideVerts;
- gridInternalEnd = gridSideEnd + numVerts * gridInternalVerts;
-
- offset = vertNum - ccgdm->faceMap[i].startVert;
- if (offset < 1) {
- vd = ccgSubSurf_getFaceCenterData(f);
- copy_v3_v3(mv->co, CCG_elem_co(&key, vd));
- normal_float_to_short_v3(mv->no, CCG_elem_no(&key, vd));
- }
- else if (offset < gridSideEnd) {
- offset -= 1;
- grid = offset / gridSideVerts;
- x = offset % gridSideVerts + 1;
- vd = ccgSubSurf_getFaceGridEdgeData(ss, f, grid, x);
- copy_v3_v3(mv->co, CCG_elem_co(&key, vd));
- normal_float_to_short_v3(mv->no, CCG_elem_no(&key, vd));
- }
- else if (offset < gridInternalEnd) {
- offset -= gridSideEnd;
- grid = offset / gridInternalVerts;
- offset %= gridInternalVerts;
- y = offset / gridSideVerts + 1;
- x = offset % gridSideVerts + 1;
- vd = ccgSubSurf_getFaceGridData(ss, f, grid, x, y);
- copy_v3_v3(mv->co, CCG_elem_co(&key, vd));
- normal_float_to_short_v3(mv->no, CCG_elem_no(&key, vd));
- }
- }
- else if ((vertNum < ccgdm->vertMap[0].startVert) && (ccgSubSurf_getNumEdges(ss) > 0)) {
- /* this vert comes from edge data */
- CCGEdge *e;
- int lastedge = ccgSubSurf_getNumEdges(ss) - 1;
- int x;
-
- i = 0;
- while (i < lastedge && vertNum >= ccgdm->edgeMap[i + 1].startVert) {
- i++;
- }
-
- e = ccgdm->edgeMap[i].edge;
-
- x = vertNum - ccgdm->edgeMap[i].startVert + 1;
- vd = ccgSubSurf_getEdgeData(ss, e, x);
- copy_v3_v3(mv->co, CCG_elem_co(&key, vd));
- normal_float_to_short_v3(mv->no, CCG_elem_no(&key, vd));
- }
- else {
- /* this vert comes from vert data */
- CCGVert *v;
- i = vertNum - ccgdm->vertMap[0].startVert;
-
- v = ccgdm->vertMap[i].vert;
- vd = ccgSubSurf_getVertData(ss, v);
- copy_v3_v3(mv->co, CCG_elem_co(&key, vd));
- normal_float_to_short_v3(mv->no, CCG_elem_no(&key, vd));
- }
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ CCGElem *vd;
+ CCGKey key;
+ int i;
+
+ CCG_key_top_level(&key, ss);
+ memset(mv, 0, sizeof(*mv));
+
+ if ((vertNum < ccgdm->edgeMap[0].startVert) && (ccgSubSurf_getNumFaces(ss) > 0)) {
+ /* this vert comes from face data */
+ int lastface = ccgSubSurf_getNumFaces(ss) - 1;
+ CCGFace *f;
+ int x, y, grid, numVerts;
+ int offset;
+ int gridSize = ccgSubSurf_getGridSize(ss);
+ int gridSideVerts;
+ int gridInternalVerts;
+ int gridSideEnd;
+ int gridInternalEnd;
+
+ i = 0;
+ while (i < lastface && vertNum >= ccgdm->faceMap[i + 1].startVert) {
+ i++;
+ }
+
+ f = ccgdm->faceMap[i].face;
+ numVerts = ccgSubSurf_getFaceNumVerts(f);
+
+ gridSideVerts = gridSize - 2;
+ gridInternalVerts = gridSideVerts * gridSideVerts;
+
+ gridSideEnd = 1 + numVerts * gridSideVerts;
+ gridInternalEnd = gridSideEnd + numVerts * gridInternalVerts;
+
+ offset = vertNum - ccgdm->faceMap[i].startVert;
+ if (offset < 1) {
+ vd = ccgSubSurf_getFaceCenterData(f);
+ copy_v3_v3(mv->co, CCG_elem_co(&key, vd));
+ normal_float_to_short_v3(mv->no, CCG_elem_no(&key, vd));
+ }
+ else if (offset < gridSideEnd) {
+ offset -= 1;
+ grid = offset / gridSideVerts;
+ x = offset % gridSideVerts + 1;
+ vd = ccgSubSurf_getFaceGridEdgeData(ss, f, grid, x);
+ copy_v3_v3(mv->co, CCG_elem_co(&key, vd));
+ normal_float_to_short_v3(mv->no, CCG_elem_no(&key, vd));
+ }
+ else if (offset < gridInternalEnd) {
+ offset -= gridSideEnd;
+ grid = offset / gridInternalVerts;
+ offset %= gridInternalVerts;
+ y = offset / gridSideVerts + 1;
+ x = offset % gridSideVerts + 1;
+ vd = ccgSubSurf_getFaceGridData(ss, f, grid, x, y);
+ copy_v3_v3(mv->co, CCG_elem_co(&key, vd));
+ normal_float_to_short_v3(mv->no, CCG_elem_no(&key, vd));
+ }
+ }
+ else if ((vertNum < ccgdm->vertMap[0].startVert) && (ccgSubSurf_getNumEdges(ss) > 0)) {
+ /* this vert comes from edge data */
+ CCGEdge *e;
+ int lastedge = ccgSubSurf_getNumEdges(ss) - 1;
+ int x;
+
+ i = 0;
+ while (i < lastedge && vertNum >= ccgdm->edgeMap[i + 1].startVert) {
+ i++;
+ }
+
+ e = ccgdm->edgeMap[i].edge;
+
+ x = vertNum - ccgdm->edgeMap[i].startVert + 1;
+ vd = ccgSubSurf_getEdgeData(ss, e, x);
+ copy_v3_v3(mv->co, CCG_elem_co(&key, vd));
+ normal_float_to_short_v3(mv->no, CCG_elem_no(&key, vd));
+ }
+ else {
+ /* this vert comes from vert data */
+ CCGVert *v;
+ i = vertNum - ccgdm->vertMap[0].startVert;
+
+ v = ccgdm->vertMap[i].vert;
+ vd = ccgSubSurf_getVertData(ss, v);
+ copy_v3_v3(mv->co, CCG_elem_co(&key, vd));
+ normal_float_to_short_v3(mv->no, CCG_elem_no(&key, vd));
+ }
}
static void ccgDM_getFinalVertCo(DerivedMesh *dm, int vertNum, float r_co[3])
{
- MVert mvert;
+ MVert mvert;
- ccgDM_getFinalVert(dm, vertNum, &mvert);
- copy_v3_v3(r_co, mvert.co);
+ ccgDM_getFinalVert(dm, vertNum, &mvert);
+ copy_v3_v3(r_co, mvert.co);
}
static void ccgDM_getFinalVertNo(DerivedMesh *dm, int vertNum, float r_no[3])
{
- MVert mvert;
+ MVert mvert;
- ccgDM_getFinalVert(dm, vertNum, &mvert);
- normal_short_to_float_v3(r_no, mvert.no);
+ ccgDM_getFinalVert(dm, vertNum, &mvert);
+ normal_short_to_float_v3(r_no, mvert.no);
}
static void ccgDM_getFinalEdge(DerivedMesh *dm, int edgeNum, MEdge *med)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- int i;
-
- memset(med, 0, sizeof(*med));
-
- if (edgeNum < ccgdm->edgeMap[0].startEdge) {
- /* this edge comes from face data */
- int lastface = ccgSubSurf_getNumFaces(ss) - 1;
- CCGFace *f;
- int x, y, grid /*, numVerts*/;
- int offset;
- int gridSize = ccgSubSurf_getGridSize(ss);
- int edgeSize = ccgSubSurf_getEdgeSize(ss);
- int gridSideEdges;
- int gridInternalEdges;
-
- i = 0;
- while (i < lastface && edgeNum >= ccgdm->faceMap[i + 1].startEdge) {
- i++;
- }
-
- f = ccgdm->faceMap[i].face;
- /* numVerts = ccgSubSurf_getFaceNumVerts(f); */ /*UNUSED*/
-
- gridSideEdges = gridSize - 1;
- gridInternalEdges = (gridSideEdges - 1) * gridSideEdges * 2;
-
- offset = edgeNum - ccgdm->faceMap[i].startEdge;
- grid = offset / (gridSideEdges + gridInternalEdges);
- offset %= (gridSideEdges + gridInternalEdges);
-
- if (offset < gridSideEdges) {
- x = offset;
- med->v1 = getFaceIndex(ss, f, grid, x, 0, edgeSize, gridSize);
- med->v2 = getFaceIndex(ss, f, grid, x + 1, 0, edgeSize, gridSize);
- }
- else {
- offset -= gridSideEdges;
- x = (offset / 2) / gridSideEdges + 1;
- y = (offset / 2) % gridSideEdges;
- if (offset % 2 == 0) {
- med->v1 = getFaceIndex(ss, f, grid, x, y, edgeSize, gridSize);
- med->v2 = getFaceIndex(ss, f, grid, x, y + 1, edgeSize, gridSize);
- }
- else {
- med->v1 = getFaceIndex(ss, f, grid, y, x, edgeSize, gridSize);
- med->v2 = getFaceIndex(ss, f, grid, y + 1, x, edgeSize, gridSize);
- }
- }
- }
- else {
- /* this vert comes from edge data */
- CCGEdge *e;
- int edgeSize = ccgSubSurf_getEdgeSize(ss);
- int x;
- short *edgeFlag;
- unsigned int flags = 0;
-
- i = (edgeNum - ccgdm->edgeMap[0].startEdge) / (edgeSize - 1);
-
- e = ccgdm->edgeMap[i].edge;
-
- if (!ccgSubSurf_getEdgeNumFaces(e)) flags |= ME_LOOSEEDGE;
-
- x = edgeNum - ccgdm->edgeMap[i].startEdge;
-
- med->v1 = getEdgeIndex(ss, e, x, edgeSize);
- med->v2 = getEdgeIndex(ss, e, x + 1, edgeSize);
-
- edgeFlag = (ccgdm->edgeFlags) ? &ccgdm->edgeFlags[i] : NULL;
- if (edgeFlag)
- flags |= (*edgeFlag & (ME_SEAM | ME_SHARP)) | ME_EDGEDRAW | ME_EDGERENDER;
- else
- flags |= ME_EDGEDRAW | ME_EDGERENDER;
-
- med->flag = flags;
- }
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ int i;
+
+ memset(med, 0, sizeof(*med));
+
+ if (edgeNum < ccgdm->edgeMap[0].startEdge) {
+ /* this edge comes from face data */
+ int lastface = ccgSubSurf_getNumFaces(ss) - 1;
+ CCGFace *f;
+ int x, y, grid /*, numVerts*/;
+ int offset;
+ int gridSize = ccgSubSurf_getGridSize(ss);
+ int edgeSize = ccgSubSurf_getEdgeSize(ss);
+ int gridSideEdges;
+ int gridInternalEdges;
+
+ i = 0;
+ while (i < lastface && edgeNum >= ccgdm->faceMap[i + 1].startEdge) {
+ i++;
+ }
+
+ f = ccgdm->faceMap[i].face;
+ /* numVerts = ccgSubSurf_getFaceNumVerts(f); */ /*UNUSED*/
+
+ gridSideEdges = gridSize - 1;
+ gridInternalEdges = (gridSideEdges - 1) * gridSideEdges * 2;
+
+ offset = edgeNum - ccgdm->faceMap[i].startEdge;
+ grid = offset / (gridSideEdges + gridInternalEdges);
+ offset %= (gridSideEdges + gridInternalEdges);
+
+ if (offset < gridSideEdges) {
+ x = offset;
+ med->v1 = getFaceIndex(ss, f, grid, x, 0, edgeSize, gridSize);
+ med->v2 = getFaceIndex(ss, f, grid, x + 1, 0, edgeSize, gridSize);
+ }
+ else {
+ offset -= gridSideEdges;
+ x = (offset / 2) / gridSideEdges + 1;
+ y = (offset / 2) % gridSideEdges;
+ if (offset % 2 == 0) {
+ med->v1 = getFaceIndex(ss, f, grid, x, y, edgeSize, gridSize);
+ med->v2 = getFaceIndex(ss, f, grid, x, y + 1, edgeSize, gridSize);
+ }
+ else {
+ med->v1 = getFaceIndex(ss, f, grid, y, x, edgeSize, gridSize);
+ med->v2 = getFaceIndex(ss, f, grid, y + 1, x, edgeSize, gridSize);
+ }
+ }
+ }
+ else {
+ /* this vert comes from edge data */
+ CCGEdge *e;
+ int edgeSize = ccgSubSurf_getEdgeSize(ss);
+ int x;
+ short *edgeFlag;
+ unsigned int flags = 0;
+
+ i = (edgeNum - ccgdm->edgeMap[0].startEdge) / (edgeSize - 1);
+
+ e = ccgdm->edgeMap[i].edge;
+
+ if (!ccgSubSurf_getEdgeNumFaces(e))
+ flags |= ME_LOOSEEDGE;
+
+ x = edgeNum - ccgdm->edgeMap[i].startEdge;
+
+ med->v1 = getEdgeIndex(ss, e, x, edgeSize);
+ med->v2 = getEdgeIndex(ss, e, x + 1, edgeSize);
+
+ edgeFlag = (ccgdm->edgeFlags) ? &ccgdm->edgeFlags[i] : NULL;
+ if (edgeFlag)
+ flags |= (*edgeFlag & (ME_SEAM | ME_SHARP)) | ME_EDGEDRAW | ME_EDGERENDER;
+ else
+ flags |= ME_EDGEDRAW | ME_EDGERENDER;
+
+ med->flag = flags;
+ }
}
static void ccgDM_getFinalFace(DerivedMesh *dm, int faceNum, MFace *mf)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- int gridSize = ccgSubSurf_getGridSize(ss);
- int edgeSize = ccgSubSurf_getEdgeSize(ss);
- int gridSideEdges = gridSize - 1;
- int gridFaces = gridSideEdges * gridSideEdges;
- int i;
- CCGFace *f;
- /*int numVerts;*/
- int offset;
- int grid;
- int x, y;
- /*int lastface = ccgSubSurf_getNumFaces(ss) - 1;*/ /*UNUSED*/
- DMFlagMat *faceFlags = ccgdm->faceFlags;
-
- memset(mf, 0, sizeof(*mf));
- if (faceNum >= ccgdm->dm.numTessFaceData)
- return;
-
- i = ccgdm->reverseFaceMap[faceNum];
-
- f = ccgdm->faceMap[i].face;
- /*numVerts = ccgSubSurf_getFaceNumVerts(f);*/ /*UNUSED*/
-
- offset = faceNum - ccgdm->faceMap[i].startFace;
- grid = offset / gridFaces;
- offset %= gridFaces;
- y = offset / gridSideEdges;
- x = offset % gridSideEdges;
-
- mf->v1 = getFaceIndex(ss, f, grid, x + 0, y + 0, edgeSize, gridSize);
- mf->v2 = getFaceIndex(ss, f, grid, x + 0, y + 1, edgeSize, gridSize);
- mf->v3 = getFaceIndex(ss, f, grid, x + 1, y + 1, edgeSize, gridSize);
- mf->v4 = getFaceIndex(ss, f, grid, x + 1, y + 0, edgeSize, gridSize);
-
- if (faceFlags) {
- mf->flag = faceFlags[i].flag;
- mf->mat_nr = faceFlags[i].mat_nr;
- }
- else {
- mf->flag = ME_SMOOTH;
- }
-
- mf->edcode = 0;
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ int gridSize = ccgSubSurf_getGridSize(ss);
+ int edgeSize = ccgSubSurf_getEdgeSize(ss);
+ int gridSideEdges = gridSize - 1;
+ int gridFaces = gridSideEdges * gridSideEdges;
+ int i;
+ CCGFace *f;
+ /*int numVerts;*/
+ int offset;
+ int grid;
+ int x, y;
+ /*int lastface = ccgSubSurf_getNumFaces(ss) - 1;*/ /*UNUSED*/
+ DMFlagMat *faceFlags = ccgdm->faceFlags;
+
+ memset(mf, 0, sizeof(*mf));
+ if (faceNum >= ccgdm->dm.numTessFaceData)
+ return;
+
+ i = ccgdm->reverseFaceMap[faceNum];
+
+ f = ccgdm->faceMap[i].face;
+ /*numVerts = ccgSubSurf_getFaceNumVerts(f);*/ /*UNUSED*/
+
+ offset = faceNum - ccgdm->faceMap[i].startFace;
+ grid = offset / gridFaces;
+ offset %= gridFaces;
+ y = offset / gridSideEdges;
+ x = offset % gridSideEdges;
+
+ mf->v1 = getFaceIndex(ss, f, grid, x + 0, y + 0, edgeSize, gridSize);
+ mf->v2 = getFaceIndex(ss, f, grid, x + 0, y + 1, edgeSize, gridSize);
+ mf->v3 = getFaceIndex(ss, f, grid, x + 1, y + 1, edgeSize, gridSize);
+ mf->v4 = getFaceIndex(ss, f, grid, x + 1, y + 0, edgeSize, gridSize);
+
+ if (faceFlags) {
+ mf->flag = faceFlags[i].flag;
+ mf->mat_nr = faceFlags[i].mat_nr;
+ }
+ else {
+ mf->flag = ME_SMOOTH;
+ }
+
+ mf->edcode = 0;
}
/* Translate GridHidden into the ME_HIDE flag for MVerts. Assumes
* vertices are in the order output by ccgDM_copyFinalVertArray. */
-void subsurf_copy_grid_hidden(DerivedMesh *dm, const MPoly *mpoly,
- MVert *mvert, const MDisps *mdisps)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
- CCGSubSurf *ss = ccgdm->ss;
- int level = ccgSubSurf_getSubdivisionLevels(ss);
- int gridSize = ccgSubSurf_getGridSize(ss);
- int edgeSize = ccgSubSurf_getEdgeSize(ss);
- int totface = ccgSubSurf_getNumFaces(ss);
- int i, j, x, y;
-
- for (i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
-
- for (j = 0; j < mpoly[i].totloop; j++) {
- const MDisps *md = &mdisps[mpoly[i].loopstart + j];
- int hidden_gridsize = BKE_ccg_gridsize(md->level);
- int factor = BKE_ccg_factor(level, md->level);
- BLI_bitmap *hidden = md->hidden;
-
- if (!hidden)
- continue;
-
- for (y = 0; y < gridSize; y++) {
- for (x = 0; x < gridSize; x++) {
- int vndx, offset;
-
- vndx = getFaceIndex(ss, f, j, x, y, edgeSize, gridSize);
- offset = (y * factor) * hidden_gridsize + (x * factor);
- if (BLI_BITMAP_TEST(hidden, offset))
- mvert[vndx].flag |= ME_HIDE;
- }
- }
- }
- }
+void subsurf_copy_grid_hidden(DerivedMesh *dm,
+ const MPoly *mpoly,
+ MVert *mvert,
+ const MDisps *mdisps)
+{
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ int level = ccgSubSurf_getSubdivisionLevels(ss);
+ int gridSize = ccgSubSurf_getGridSize(ss);
+ int edgeSize = ccgSubSurf_getEdgeSize(ss);
+ int totface = ccgSubSurf_getNumFaces(ss);
+ int i, j, x, y;
+
+ for (i = 0; i < totface; i++) {
+ CCGFace *f = ccgdm->faceMap[i].face;
+
+ for (j = 0; j < mpoly[i].totloop; j++) {
+ const MDisps *md = &mdisps[mpoly[i].loopstart + j];
+ int hidden_gridsize = BKE_ccg_gridsize(md->level);
+ int factor = BKE_ccg_factor(level, md->level);
+ BLI_bitmap *hidden = md->hidden;
+
+ if (!hidden)
+ continue;
+
+ for (y = 0; y < gridSize; y++) {
+ for (x = 0; x < gridSize; x++) {
+ int vndx, offset;
+
+ vndx = getFaceIndex(ss, f, j, x, y, edgeSize, gridSize);
+ offset = (y * factor) * hidden_gridsize + (x * factor);
+ if (BLI_BITMAP_TEST(hidden, offset))
+ mvert[vndx].flag |= ME_HIDE;
+ }
+ }
+ }
+ }
}
/* Translate GridPaintMask into vertex paint masks. Assumes vertices
* are in the order output by ccgDM_copyFinalVertArray. */
-void subsurf_copy_grid_paint_mask(DerivedMesh *dm, const MPoly *mpoly,
+void subsurf_copy_grid_paint_mask(DerivedMesh *dm,
+ const MPoly *mpoly,
float *paint_mask,
const GridPaintMask *grid_paint_mask)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
- CCGSubSurf *ss = ccgdm->ss;
- int level = ccgSubSurf_getSubdivisionLevels(ss);
- int gridSize = ccgSubSurf_getGridSize(ss);
- int edgeSize = ccgSubSurf_getEdgeSize(ss);
- int totface = ccgSubSurf_getNumFaces(ss);
- int i, j, x, y, factor, gpm_gridsize;
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ int level = ccgSubSurf_getSubdivisionLevels(ss);
+ int gridSize = ccgSubSurf_getGridSize(ss);
+ int edgeSize = ccgSubSurf_getEdgeSize(ss);
+ int totface = ccgSubSurf_getNumFaces(ss);
+ int i, j, x, y, factor, gpm_gridsize;
- for (i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- const MPoly *p = &mpoly[i];
+ for (i = 0; i < totface; i++) {
+ CCGFace *f = ccgdm->faceMap[i].face;
+ const MPoly *p = &mpoly[i];
- for (j = 0; j < p->totloop; j++) {
- const GridPaintMask *gpm = &grid_paint_mask[p->loopstart + j];
- if (!gpm->data)
- continue;
+ for (j = 0; j < p->totloop; j++) {
+ const GridPaintMask *gpm = &grid_paint_mask[p->loopstart + j];
+ if (!gpm->data)
+ continue;
- factor = BKE_ccg_factor(level, gpm->level);
- gpm_gridsize = BKE_ccg_gridsize(gpm->level);
+ factor = BKE_ccg_factor(level, gpm->level);
+ gpm_gridsize = BKE_ccg_gridsize(gpm->level);
- for (y = 0; y < gridSize; y++) {
- for (x = 0; x < gridSize; x++) {
- int vndx, offset;
+ for (y = 0; y < gridSize; y++) {
+ for (x = 0; x < gridSize; x++) {
+ int vndx, offset;
- vndx = getFaceIndex(ss, f, j, x, y, edgeSize, gridSize);
- offset = y * factor * gpm_gridsize + x * factor;
- paint_mask[vndx] = gpm->data[offset];
- }
- }
- }
- }
+ vndx = getFaceIndex(ss, f, j, x, y, edgeSize, gridSize);
+ offset = y * factor * gpm_gridsize + x * factor;
+ paint_mask[vndx] = gpm->data[offset];
+ }
+ }
+ }
+ }
}
/* utility function */
BLI_INLINE void ccgDM_to_MVert(MVert *mv, const CCGKey *key, CCGElem *elem)
{
- copy_v3_v3(mv->co, CCG_elem_co(key, elem));
- normal_float_to_short_v3(mv->no, CCG_elem_no(key, elem));
- mv->flag = mv->bweight = 0;
+ copy_v3_v3(mv->co, CCG_elem_co(key, elem));
+ normal_float_to_short_v3(mv->no, CCG_elem_no(key, elem));
+ mv->flag = mv->bweight = 0;
}
static void ccgDM_copyFinalVertArray(DerivedMesh *dm, MVert *mvert)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGElem *vd;
- CCGKey key;
- int index;
- int totvert, totedge, totface;
- int gridSize = ccgSubSurf_getGridSize(ss);
- int edgeSize = ccgSubSurf_getEdgeSize(ss);
- unsigned int i = 0;
-
- CCG_key_top_level(&key, ss);
-
- totface = ccgSubSurf_getNumFaces(ss);
- for (index = 0; index < totface; index++) {
- CCGFace *f = ccgdm->faceMap[index].face;
- int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
-
- vd = ccgSubSurf_getFaceCenterData(f);
- ccgDM_to_MVert(&mvert[i++], &key, vd);
-
- for (S = 0; S < numVerts; S++) {
- for (x = 1; x < gridSize - 1; x++) {
- vd = ccgSubSurf_getFaceGridEdgeData(ss, f, S, x);
- ccgDM_to_MVert(&mvert[i++], &key, vd);
- }
- }
-
- for (S = 0; S < numVerts; S++) {
- for (y = 1; y < gridSize - 1; y++) {
- for (x = 1; x < gridSize - 1; x++) {
- vd = ccgSubSurf_getFaceGridData(ss, f, S, x, y);
- ccgDM_to_MVert(&mvert[i++], &key, vd);
- }
- }
- }
- }
-
- totedge = ccgSubSurf_getNumEdges(ss);
- for (index = 0; index < totedge; index++) {
- CCGEdge *e = ccgdm->edgeMap[index].edge;
- int x;
-
- for (x = 1; x < edgeSize - 1; x++) {
- /* This gives errors with -debug-fpe
- * the normals don't seem to be unit length.
- * this is most likely caused by edges with no
- * faces which are now zerod out, see comment in:
- * ccgSubSurf__calcVertNormals(), - campbell */
- vd = ccgSubSurf_getEdgeData(ss, e, x);
- ccgDM_to_MVert(&mvert[i++], &key, vd);
- }
- }
-
- totvert = ccgSubSurf_getNumVerts(ss);
- for (index = 0; index < totvert; index++) {
- CCGVert *v = ccgdm->vertMap[index].vert;
-
- vd = ccgSubSurf_getVertData(ss, v);
- ccgDM_to_MVert(&mvert[i++], &key, vd);
- }
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ CCGElem *vd;
+ CCGKey key;
+ int index;
+ int totvert, totedge, totface;
+ int gridSize = ccgSubSurf_getGridSize(ss);
+ int edgeSize = ccgSubSurf_getEdgeSize(ss);
+ unsigned int i = 0;
+
+ CCG_key_top_level(&key, ss);
+
+ totface = ccgSubSurf_getNumFaces(ss);
+ for (index = 0; index < totface; index++) {
+ CCGFace *f = ccgdm->faceMap[index].face;
+ int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
+
+ vd = ccgSubSurf_getFaceCenterData(f);
+ ccgDM_to_MVert(&mvert[i++], &key, vd);
+
+ for (S = 0; S < numVerts; S++) {
+ for (x = 1; x < gridSize - 1; x++) {
+ vd = ccgSubSurf_getFaceGridEdgeData(ss, f, S, x);
+ ccgDM_to_MVert(&mvert[i++], &key, vd);
+ }
+ }
+
+ for (S = 0; S < numVerts; S++) {
+ for (y = 1; y < gridSize - 1; y++) {
+ for (x = 1; x < gridSize - 1; x++) {
+ vd = ccgSubSurf_getFaceGridData(ss, f, S, x, y);
+ ccgDM_to_MVert(&mvert[i++], &key, vd);
+ }
+ }
+ }
+ }
+
+ totedge = ccgSubSurf_getNumEdges(ss);
+ for (index = 0; index < totedge; index++) {
+ CCGEdge *e = ccgdm->edgeMap[index].edge;
+ int x;
+
+ for (x = 1; x < edgeSize - 1; x++) {
+ /* This gives errors with -debug-fpe
+ * the normals don't seem to be unit length.
+ * this is most likely caused by edges with no
+ * faces which are now zerod out, see comment in:
+ * ccgSubSurf__calcVertNormals(), - campbell */
+ vd = ccgSubSurf_getEdgeData(ss, e, x);
+ ccgDM_to_MVert(&mvert[i++], &key, vd);
+ }
+ }
+
+ totvert = ccgSubSurf_getNumVerts(ss);
+ for (index = 0; index < totvert; index++) {
+ CCGVert *v = ccgdm->vertMap[index].vert;
+
+ vd = ccgSubSurf_getVertData(ss, v);
+ ccgDM_to_MVert(&mvert[i++], &key, vd);
+ }
}
-
/* utility function */
BLI_INLINE void ccgDM_to_MEdge(MEdge *med, const int v1, const int v2, const short flag)
{
- med->v1 = v1;
- med->v2 = v2;
- med->crease = med->bweight = 0;
- med->flag = flag;
+ med->v1 = v1;
+ med->v2 = v2;
+ med->crease = med->bweight = 0;
+ med->flag = flag;
}
static void ccgDM_copyFinalEdgeArray(DerivedMesh *dm, MEdge *medge)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- int index;
- int totedge, totface;
- int gridSize = ccgSubSurf_getGridSize(ss);
- int edgeSize = ccgSubSurf_getEdgeSize(ss);
- unsigned int i = 0;
- short *edgeFlags = ccgdm->edgeFlags;
- const short ed_interior_flag = ccgdm->drawInteriorEdges ? (ME_EDGEDRAW | ME_EDGERENDER) : 0;
-
- totface = ccgSubSurf_getNumFaces(ss);
- for (index = 0; index < totface; index++) {
- CCGFace *f = ccgdm->faceMap[index].face;
- int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
-
- for (S = 0; S < numVerts; S++) {
- for (x = 0; x < gridSize - 1; x++) {
- ccgDM_to_MEdge(&medge[i++],
- getFaceIndex(ss, f, S, x, 0, edgeSize, gridSize),
- getFaceIndex(ss, f, S, x + 1, 0, edgeSize, gridSize),
- ed_interior_flag);
- }
-
- for (x = 1; x < gridSize - 1; x++) {
- for (y = 0; y < gridSize - 1; y++) {
- ccgDM_to_MEdge(&medge[i++],
- getFaceIndex(ss, f, S, x, y, edgeSize, gridSize),
- getFaceIndex(ss, f, S, x, y + 1, edgeSize, gridSize),
- ed_interior_flag);
- ccgDM_to_MEdge(&medge[i++],
- getFaceIndex(ss, f, S, y, x, edgeSize, gridSize),
- getFaceIndex(ss, f, S, y + 1, x, edgeSize, gridSize),
- ed_interior_flag);
- }
- }
- }
- }
-
- totedge = ccgSubSurf_getNumEdges(ss);
- for (index = 0; index < totedge; index++) {
- CCGEdge *e = ccgdm->edgeMap[index].edge;
- short ed_flag = 0;
- int x;
- int edgeIdx = POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(e));
-
- if (!ccgSubSurf_getEdgeNumFaces(e)) {
- ed_flag |= ME_LOOSEEDGE;
- }
-
- if (edgeFlags) {
- if (edgeIdx != -1) {
- ed_flag |= ((edgeFlags[index] & (ME_SEAM | ME_SHARP)) | ME_EDGEDRAW | ME_EDGERENDER);
- }
- }
- else {
- ed_flag |= ME_EDGEDRAW | ME_EDGERENDER;
- }
-
- for (x = 0; x < edgeSize - 1; x++) {
- ccgDM_to_MEdge(&medge[i++],
- getEdgeIndex(ss, e, x, edgeSize),
- getEdgeIndex(ss, e, x + 1, edgeSize),
- ed_flag);
- }
- }
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ int index;
+ int totedge, totface;
+ int gridSize = ccgSubSurf_getGridSize(ss);
+ int edgeSize = ccgSubSurf_getEdgeSize(ss);
+ unsigned int i = 0;
+ short *edgeFlags = ccgdm->edgeFlags;
+ const short ed_interior_flag = ccgdm->drawInteriorEdges ? (ME_EDGEDRAW | ME_EDGERENDER) : 0;
+
+ totface = ccgSubSurf_getNumFaces(ss);
+ for (index = 0; index < totface; index++) {
+ CCGFace *f = ccgdm->faceMap[index].face;
+ int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
+
+ for (S = 0; S < numVerts; S++) {
+ for (x = 0; x < gridSize - 1; x++) {
+ ccgDM_to_MEdge(&medge[i++],
+ getFaceIndex(ss, f, S, x, 0, edgeSize, gridSize),
+ getFaceIndex(ss, f, S, x + 1, 0, edgeSize, gridSize),
+ ed_interior_flag);
+ }
+
+ for (x = 1; x < gridSize - 1; x++) {
+ for (y = 0; y < gridSize - 1; y++) {
+ ccgDM_to_MEdge(&medge[i++],
+ getFaceIndex(ss, f, S, x, y, edgeSize, gridSize),
+ getFaceIndex(ss, f, S, x, y + 1, edgeSize, gridSize),
+ ed_interior_flag);
+ ccgDM_to_MEdge(&medge[i++],
+ getFaceIndex(ss, f, S, y, x, edgeSize, gridSize),
+ getFaceIndex(ss, f, S, y + 1, x, edgeSize, gridSize),
+ ed_interior_flag);
+ }
+ }
+ }
+ }
+
+ totedge = ccgSubSurf_getNumEdges(ss);
+ for (index = 0; index < totedge; index++) {
+ CCGEdge *e = ccgdm->edgeMap[index].edge;
+ short ed_flag = 0;
+ int x;
+ int edgeIdx = POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(e));
+
+ if (!ccgSubSurf_getEdgeNumFaces(e)) {
+ ed_flag |= ME_LOOSEEDGE;
+ }
+
+ if (edgeFlags) {
+ if (edgeIdx != -1) {
+ ed_flag |= ((edgeFlags[index] & (ME_SEAM | ME_SHARP)) | ME_EDGEDRAW | ME_EDGERENDER);
+ }
+ }
+ else {
+ ed_flag |= ME_EDGEDRAW | ME_EDGERENDER;
+ }
+
+ for (x = 0; x < edgeSize - 1; x++) {
+ ccgDM_to_MEdge(&medge[i++],
+ getEdgeIndex(ss, e, x, edgeSize),
+ getEdgeIndex(ss, e, x + 1, edgeSize),
+ ed_flag);
+ }
+ }
}
static void ccgDM_copyFinalFaceArray(DerivedMesh *dm, MFace *mface)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- int index;
- int totface;
- int gridSize = ccgSubSurf_getGridSize(ss);
- int edgeSize = ccgSubSurf_getEdgeSize(ss);
- int i = 0;
- DMFlagMat *faceFlags = ccgdm->faceFlags;
-
- totface = dm->getNumTessFaces(dm);
- for (index = 0; index < totface; index++) {
- CCGFace *f = ccgdm->faceMap[index].face;
- int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
- /* keep types in sync with MFace, avoid many conversions */
- char flag = (faceFlags) ? faceFlags[index].flag : ME_SMOOTH;
- short mat_nr = (faceFlags) ? faceFlags[index].mat_nr : 0;
-
- for (S = 0; S < numVerts; S++) {
- for (y = 0; y < gridSize - 1; y++) {
- for (x = 0; x < gridSize - 1; x++) {
- MFace *mf = &mface[i];
- mf->v1 = getFaceIndex(ss, f, S, x + 0, y + 0,
- edgeSize, gridSize);
- mf->v2 = getFaceIndex(ss, f, S, x + 0, y + 1,
- edgeSize, gridSize);
- mf->v3 = getFaceIndex(ss, f, S, x + 1, y + 1,
- edgeSize, gridSize);
- mf->v4 = getFaceIndex(ss, f, S, x + 1, y + 0,
- edgeSize, gridSize);
- mf->mat_nr = mat_nr;
- mf->flag = flag;
- mf->edcode = 0;
-
- i++;
- }
- }
- }
- }
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ int index;
+ int totface;
+ int gridSize = ccgSubSurf_getGridSize(ss);
+ int edgeSize = ccgSubSurf_getEdgeSize(ss);
+ int i = 0;
+ DMFlagMat *faceFlags = ccgdm->faceFlags;
+
+ totface = dm->getNumTessFaces(dm);
+ for (index = 0; index < totface; index++) {
+ CCGFace *f = ccgdm->faceMap[index].face;
+ int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
+ /* keep types in sync with MFace, avoid many conversions */
+ char flag = (faceFlags) ? faceFlags[index].flag : ME_SMOOTH;
+ short mat_nr = (faceFlags) ? faceFlags[index].mat_nr : 0;
+
+ for (S = 0; S < numVerts; S++) {
+ for (y = 0; y < gridSize - 1; y++) {
+ for (x = 0; x < gridSize - 1; x++) {
+ MFace *mf = &mface[i];
+ mf->v1 = getFaceIndex(ss, f, S, x + 0, y + 0, edgeSize, gridSize);
+ mf->v2 = getFaceIndex(ss, f, S, x + 0, y + 1, edgeSize, gridSize);
+ mf->v3 = getFaceIndex(ss, f, S, x + 1, y + 1, edgeSize, gridSize);
+ mf->v4 = getFaceIndex(ss, f, S, x + 1, y + 0, edgeSize, gridSize);
+ mf->mat_nr = mat_nr;
+ mf->flag = flag;
+ mf->edcode = 0;
+
+ i++;
+ }
+ }
+ }
+ }
}
typedef struct CopyFinalLoopArrayData {
- CCGDerivedMesh *ccgdm;
- MLoop *mloop;
- int grid_size;
- int *grid_offset;
- int edge_size;
- size_t mloop_index;
+ CCGDerivedMesh *ccgdm;
+ MLoop *mloop;
+ int grid_size;
+ int *grid_offset;
+ int edge_size;
+ size_t mloop_index;
} CopyFinalLoopArrayData;
-static void copyFinalLoopArray_task_cb(
- void *__restrict userdata,
- const int iter,
- const ParallelRangeTLS *__restrict UNUSED(tls))
-{
- CopyFinalLoopArrayData *data = userdata;
- CCGDerivedMesh *ccgdm = data->ccgdm;
- CCGSubSurf *ss = ccgdm->ss;
- const int grid_size = data->grid_size;
- const int edge_size = data->edge_size;
- CCGFace *f = ccgdm->faceMap[iter].face;
- const int num_verts = ccgSubSurf_getFaceNumVerts(f);
- const int grid_index = data->grid_offset[iter];
- const size_t loop_index = 4 * (size_t)grid_index * (grid_size - 1) * (grid_size - 1);
- MLoop *ml = &data->mloop[loop_index];
- for (int S = 0; S < num_verts; S++) {
- for (int y = 0; y < grid_size - 1; y++) {
- for (int x = 0; x < grid_size - 1; x++) {
-
- uint v1 = getFaceIndex(ss, f, S, x + 0, y + 0,
- edge_size, grid_size);
- uint v2 = getFaceIndex(ss, f, S, x + 0, y + 1,
- edge_size, grid_size);
- uint v3 = getFaceIndex(ss, f, S, x + 1, y + 1,
- edge_size, grid_size);
- uint v4 = getFaceIndex(ss, f, S, x + 1, y + 0,
- edge_size, grid_size);
-
- ml->v = v1;
- ml->e = POINTER_AS_UINT(BLI_edgehash_lookup(ccgdm->ehash, v1, v2));
- ml++;
-
- ml->v = v2;
- ml->e = POINTER_AS_UINT(BLI_edgehash_lookup(ccgdm->ehash, v2, v3));
- ml++;
-
- ml->v = v3;
- ml->e = POINTER_AS_UINT(BLI_edgehash_lookup(ccgdm->ehash, v3, v4));
- ml++;
-
- ml->v = v4;
- ml->e = POINTER_AS_UINT(BLI_edgehash_lookup(ccgdm->ehash, v4, v1));
- ml++;
- }
- }
- }
+static void copyFinalLoopArray_task_cb(void *__restrict userdata,
+ const int iter,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ CopyFinalLoopArrayData *data = userdata;
+ CCGDerivedMesh *ccgdm = data->ccgdm;
+ CCGSubSurf *ss = ccgdm->ss;
+ const int grid_size = data->grid_size;
+ const int edge_size = data->edge_size;
+ CCGFace *f = ccgdm->faceMap[iter].face;
+ const int num_verts = ccgSubSurf_getFaceNumVerts(f);
+ const int grid_index = data->grid_offset[iter];
+ const size_t loop_index = 4 * (size_t)grid_index * (grid_size - 1) * (grid_size - 1);
+ MLoop *ml = &data->mloop[loop_index];
+ for (int S = 0; S < num_verts; S++) {
+ for (int y = 0; y < grid_size - 1; y++) {
+ for (int x = 0; x < grid_size - 1; x++) {
+
+ uint v1 = getFaceIndex(ss, f, S, x + 0, y + 0, edge_size, grid_size);
+ uint v2 = getFaceIndex(ss, f, S, x + 0, y + 1, edge_size, grid_size);
+ uint v3 = getFaceIndex(ss, f, S, x + 1, y + 1, edge_size, grid_size);
+ uint v4 = getFaceIndex(ss, f, S, x + 1, y + 0, edge_size, grid_size);
+
+ ml->v = v1;
+ ml->e = POINTER_AS_UINT(BLI_edgehash_lookup(ccgdm->ehash, v1, v2));
+ ml++;
+
+ ml->v = v2;
+ ml->e = POINTER_AS_UINT(BLI_edgehash_lookup(ccgdm->ehash, v2, v3));
+ ml++;
+
+ ml->v = v3;
+ ml->e = POINTER_AS_UINT(BLI_edgehash_lookup(ccgdm->ehash, v3, v4));
+ ml++;
+
+ ml->v = v4;
+ ml->e = POINTER_AS_UINT(BLI_edgehash_lookup(ccgdm->ehash, v4, v1));
+ ml++;
+ }
+ }
+ }
}
static void ccgDM_copyFinalLoopArray(DerivedMesh *dm, MLoop *mloop)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ CCGSubSurf *ss = ccgdm->ss;
- if (!ccgdm->ehash) {
- BLI_mutex_lock(&ccgdm->loops_cache_lock);
- if (!ccgdm->ehash) {
- MEdge *medge;
- EdgeHash *ehash;
+ if (!ccgdm->ehash) {
+ BLI_mutex_lock(&ccgdm->loops_cache_lock);
+ if (!ccgdm->ehash) {
+ MEdge *medge;
+ EdgeHash *ehash;
- ehash = BLI_edgehash_new_ex(__func__, ccgdm->dm.numEdgeData);
- medge = ccgdm->dm.getEdgeArray((DerivedMesh *)ccgdm);
+ ehash = BLI_edgehash_new_ex(__func__, ccgdm->dm.numEdgeData);
+ medge = ccgdm->dm.getEdgeArray((DerivedMesh *)ccgdm);
- for (int i = 0; i < ccgdm->dm.numEdgeData; i++) {
- BLI_edgehash_insert(ehash, medge[i].v1, medge[i].v2, POINTER_FROM_INT(i));
- }
+ for (int i = 0; i < ccgdm->dm.numEdgeData; i++) {
+ BLI_edgehash_insert(ehash, medge[i].v1, medge[i].v2, POINTER_FROM_INT(i));
+ }
- atomic_cas_ptr((void **)&ccgdm->ehash, ccgdm->ehash, ehash);
- }
- BLI_mutex_unlock(&ccgdm->loops_cache_lock);
- }
+ atomic_cas_ptr((void **)&ccgdm->ehash, ccgdm->ehash, ehash);
+ }
+ BLI_mutex_unlock(&ccgdm->loops_cache_lock);
+ }
- CopyFinalLoopArrayData data;
- data.ccgdm = ccgdm;
- data.mloop = mloop;
- data.grid_size = ccgSubSurf_getGridSize(ss);
- data.grid_offset = dm->getGridOffset(dm);
- data.edge_size = ccgSubSurf_getEdgeSize(ss);
+ CopyFinalLoopArrayData data;
+ data.ccgdm = ccgdm;
+ data.mloop = mloop;
+ data.grid_size = ccgSubSurf_getGridSize(ss);
+ data.grid_offset = dm->getGridOffset(dm);
+ data.edge_size = ccgSubSurf_getEdgeSize(ss);
- /* NOTE: For a dense subdivision we've got enough work for each face and
- * hence can dedicate whole thread to single face. For less dense
- * subdivision we handle multiple faces per thread.
- */
- data.mloop_index = data.grid_size >= 5 ? 1 : 8;
+ /* NOTE: For a dense subdivision we've got enough work for each face and
+ * hence can dedicate whole thread to single face. For less dense
+ * subdivision we handle multiple faces per thread.
+ */
+ data.mloop_index = data.grid_size >= 5 ? 1 : 8;
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.min_iter_per_thread = 1;
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.min_iter_per_thread = 1;
- BLI_task_parallel_range(0, ccgSubSurf_getNumFaces(ss),
- &data,
- copyFinalLoopArray_task_cb,
- &settings);
+ BLI_task_parallel_range(
+ 0, ccgSubSurf_getNumFaces(ss), &data, copyFinalLoopArray_task_cb, &settings);
}
static void ccgDM_copyFinalPolyArray(DerivedMesh *dm, MPoly *mpoly)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- int index;
- int totface;
- int gridSize = ccgSubSurf_getGridSize(ss);
- /* int edgeSize = ccgSubSurf_getEdgeSize(ss); */ /* UNUSED */
- int i = 0, k = 0;
- DMFlagMat *faceFlags = ccgdm->faceFlags;
-
- totface = ccgSubSurf_getNumFaces(ss);
- for (index = 0; index < totface; index++) {
- CCGFace *f = ccgdm->faceMap[index].face;
- int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
- int flag = (faceFlags) ? faceFlags[index].flag : ME_SMOOTH;
- int mat_nr = (faceFlags) ? faceFlags[index].mat_nr : 0;
-
- for (S = 0; S < numVerts; S++) {
- for (y = 0; y < gridSize - 1; y++) {
- for (x = 0; x < gridSize - 1; x++) {
- MPoly *mp = &mpoly[i];
-
- mp->mat_nr = mat_nr;
- mp->flag = flag;
- mp->loopstart = k;
- mp->totloop = 4;
-
- k += 4;
- i++;
- }
- }
- }
- }
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ int index;
+ int totface;
+ int gridSize = ccgSubSurf_getGridSize(ss);
+ /* int edgeSize = ccgSubSurf_getEdgeSize(ss); */ /* UNUSED */
+ int i = 0, k = 0;
+ DMFlagMat *faceFlags = ccgdm->faceFlags;
+
+ totface = ccgSubSurf_getNumFaces(ss);
+ for (index = 0; index < totface; index++) {
+ CCGFace *f = ccgdm->faceMap[index].face;
+ int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
+ int flag = (faceFlags) ? faceFlags[index].flag : ME_SMOOTH;
+ int mat_nr = (faceFlags) ? faceFlags[index].mat_nr : 0;
+
+ for (S = 0; S < numVerts; S++) {
+ for (y = 0; y < gridSize - 1; y++) {
+ for (x = 0; x < gridSize - 1; x++) {
+ MPoly *mp = &mpoly[i];
+
+ mp->mat_nr = mat_nr;
+ mp->flag = flag;
+ mp->loopstart = k;
+ mp->totloop = 4;
+
+ k += 4;
+ i++;
+ }
+ }
+ }
+ }
}
static void ccgdm_getVertCos(DerivedMesh *dm, float (*cos)[3])
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- int edgeSize = ccgSubSurf_getEdgeSize(ss);
- int gridSize = ccgSubSurf_getGridSize(ss);
- int i;
- CCGVertIterator vi;
- CCGEdgeIterator ei;
- CCGFaceIterator fi;
- CCGFace **faceMap2;
- CCGEdge **edgeMap2;
- CCGVert **vertMap2;
- int index, totvert, totedge, totface;
-
- totvert = ccgSubSurf_getNumVerts(ss);
- vertMap2 = MEM_mallocN(totvert * sizeof(*vertMap2), "vertmap");
- for (ccgSubSurf_initVertIterator(ss, &vi); !ccgVertIterator_isStopped(&vi); ccgVertIterator_next(&vi)) {
- CCGVert *v = ccgVertIterator_getCurrent(&vi);
-
- vertMap2[POINTER_AS_INT(ccgSubSurf_getVertVertHandle(v))] = v;
- }
-
- totedge = ccgSubSurf_getNumEdges(ss);
- edgeMap2 = MEM_mallocN(totedge * sizeof(*edgeMap2), "edgemap");
- for (ccgSubSurf_initEdgeIterator(ss, &ei), i = 0; !ccgEdgeIterator_isStopped(&ei); i++, ccgEdgeIterator_next(&ei)) {
- CCGEdge *e = ccgEdgeIterator_getCurrent(&ei);
-
- edgeMap2[POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(e))] = e;
- }
-
- totface = ccgSubSurf_getNumFaces(ss);
- faceMap2 = MEM_mallocN(totface * sizeof(*faceMap2), "facemap");
- for (ccgSubSurf_initFaceIterator(ss, &fi); !ccgFaceIterator_isStopped(&fi); ccgFaceIterator_next(&fi)) {
- CCGFace *f = ccgFaceIterator_getCurrent(&fi);
-
- faceMap2[POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f))] = f;
- }
-
- i = 0;
- for (index = 0; index < totface; index++) {
- CCGFace *f = faceMap2[index];
- int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
-
- copy_v3_v3(cos[i++], ccgSubSurf_getFaceCenterData(f));
-
- for (S = 0; S < numVerts; S++) {
- for (x = 1; x < gridSize - 1; x++) {
- copy_v3_v3(cos[i++], ccgSubSurf_getFaceGridEdgeData(ss, f, S, x));
- }
- }
-
- for (S = 0; S < numVerts; S++) {
- for (y = 1; y < gridSize - 1; y++) {
- for (x = 1; x < gridSize - 1; x++) {
- copy_v3_v3(cos[i++], ccgSubSurf_getFaceGridData(ss, f, S, x, y));
- }
- }
- }
- }
-
- for (index = 0; index < totedge; index++) {
- CCGEdge *e = edgeMap2[index];
- int x;
-
- for (x = 1; x < edgeSize - 1; x++) {
- copy_v3_v3(cos[i++], ccgSubSurf_getEdgeData(ss, e, x));
- }
- }
-
- for (index = 0; index < totvert; index++) {
- CCGVert *v = vertMap2[index];
- copy_v3_v3(cos[i++], ccgSubSurf_getVertData(ss, v));
- }
-
- MEM_freeN(vertMap2);
- MEM_freeN(edgeMap2);
- MEM_freeN(faceMap2);
-}
-
-static void ccgDM_foreachMappedVert(
- DerivedMesh *dm,
- void (*func)(void *userData, int index, const float co[3], const float no_f[3], const short no_s[3]),
- void *userData,
- DMForeachFlag flag)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGVertIterator vi;
- CCGKey key;
- CCG_key_top_level(&key, ccgdm->ss);
-
- for (ccgSubSurf_initVertIterator(ccgdm->ss, &vi); !ccgVertIterator_isStopped(&vi); ccgVertIterator_next(&vi)) {
- CCGVert *v = ccgVertIterator_getCurrent(&vi);
- const int index = ccgDM_getVertMapIndex(ccgdm->ss, v);
-
- if (index != -1) {
- CCGElem *vd = ccgSubSurf_getVertData(ccgdm->ss, v);
- const float *no = (flag & DM_FOREACH_USE_NORMAL) ? CCG_elem_no(&key, vd) : NULL;
- func(userData, index, CCG_elem_co(&key, vd), no, NULL);
- }
- }
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ int edgeSize = ccgSubSurf_getEdgeSize(ss);
+ int gridSize = ccgSubSurf_getGridSize(ss);
+ int i;
+ CCGVertIterator vi;
+ CCGEdgeIterator ei;
+ CCGFaceIterator fi;
+ CCGFace **faceMap2;
+ CCGEdge **edgeMap2;
+ CCGVert **vertMap2;
+ int index, totvert, totedge, totface;
+
+ totvert = ccgSubSurf_getNumVerts(ss);
+ vertMap2 = MEM_mallocN(totvert * sizeof(*vertMap2), "vertmap");
+ for (ccgSubSurf_initVertIterator(ss, &vi); !ccgVertIterator_isStopped(&vi);
+ ccgVertIterator_next(&vi)) {
+ CCGVert *v = ccgVertIterator_getCurrent(&vi);
+
+ vertMap2[POINTER_AS_INT(ccgSubSurf_getVertVertHandle(v))] = v;
+ }
+
+ totedge = ccgSubSurf_getNumEdges(ss);
+ edgeMap2 = MEM_mallocN(totedge * sizeof(*edgeMap2), "edgemap");
+ for (ccgSubSurf_initEdgeIterator(ss, &ei), i = 0; !ccgEdgeIterator_isStopped(&ei);
+ i++, ccgEdgeIterator_next(&ei)) {
+ CCGEdge *e = ccgEdgeIterator_getCurrent(&ei);
+
+ edgeMap2[POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(e))] = e;
+ }
+
+ totface = ccgSubSurf_getNumFaces(ss);
+ faceMap2 = MEM_mallocN(totface * sizeof(*faceMap2), "facemap");
+ for (ccgSubSurf_initFaceIterator(ss, &fi); !ccgFaceIterator_isStopped(&fi);
+ ccgFaceIterator_next(&fi)) {
+ CCGFace *f = ccgFaceIterator_getCurrent(&fi);
+
+ faceMap2[POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f))] = f;
+ }
+
+ i = 0;
+ for (index = 0; index < totface; index++) {
+ CCGFace *f = faceMap2[index];
+ int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
+
+ copy_v3_v3(cos[i++], ccgSubSurf_getFaceCenterData(f));
+
+ for (S = 0; S < numVerts; S++) {
+ for (x = 1; x < gridSize - 1; x++) {
+ copy_v3_v3(cos[i++], ccgSubSurf_getFaceGridEdgeData(ss, f, S, x));
+ }
+ }
+
+ for (S = 0; S < numVerts; S++) {
+ for (y = 1; y < gridSize - 1; y++) {
+ for (x = 1; x < gridSize - 1; x++) {
+ copy_v3_v3(cos[i++], ccgSubSurf_getFaceGridData(ss, f, S, x, y));
+ }
+ }
+ }
+ }
+
+ for (index = 0; index < totedge; index++) {
+ CCGEdge *e = edgeMap2[index];
+ int x;
+
+ for (x = 1; x < edgeSize - 1; x++) {
+ copy_v3_v3(cos[i++], ccgSubSurf_getEdgeData(ss, e, x));
+ }
+ }
+
+ for (index = 0; index < totvert; index++) {
+ CCGVert *v = vertMap2[index];
+ copy_v3_v3(cos[i++], ccgSubSurf_getVertData(ss, v));
+ }
+
+ MEM_freeN(vertMap2);
+ MEM_freeN(edgeMap2);
+ MEM_freeN(faceMap2);
+}
+
+static void ccgDM_foreachMappedVert(DerivedMesh *dm,
+ void (*func)(void *userData,
+ int index,
+ const float co[3],
+ const float no_f[3],
+ const short no_s[3]),
+ void *userData,
+ DMForeachFlag flag)
+{
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ CCGVertIterator vi;
+ CCGKey key;
+ CCG_key_top_level(&key, ccgdm->ss);
+
+ for (ccgSubSurf_initVertIterator(ccgdm->ss, &vi); !ccgVertIterator_isStopped(&vi);
+ ccgVertIterator_next(&vi)) {
+ CCGVert *v = ccgVertIterator_getCurrent(&vi);
+ const int index = ccgDM_getVertMapIndex(ccgdm->ss, v);
+
+ if (index != -1) {
+ CCGElem *vd = ccgSubSurf_getVertData(ccgdm->ss, v);
+ const float *no = (flag & DM_FOREACH_USE_NORMAL) ? CCG_elem_no(&key, vd) : NULL;
+ func(userData, index, CCG_elem_co(&key, vd), no, NULL);
+ }
+ }
}
static void ccgDM_foreachMappedEdge(
- DerivedMesh *dm,
- void (*func)(void *userData, int index, const float v0co[3], const float v1co[3]),
- void *userData)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGEdgeIterator ei;
- CCGKey key;
- int i, edgeSize = ccgSubSurf_getEdgeSize(ss);
-
- CCG_key_top_level(&key, ss);
-
- for (ccgSubSurf_initEdgeIterator(ss, &ei); !ccgEdgeIterator_isStopped(&ei); ccgEdgeIterator_next(&ei)) {
- CCGEdge *e = ccgEdgeIterator_getCurrent(&ei);
- const int index = ccgDM_getEdgeMapIndex(ss, e);
-
- if (index != -1) {
- CCGElem *edgeData = ccgSubSurf_getEdgeDataArray(ss, e);
- for (i = 0; i < edgeSize - 1; i++) {
- func(userData, index, CCG_elem_offset_co(&key, edgeData, i), CCG_elem_offset_co(&key, edgeData, i + 1));
- }
- }
- }
-}
-
-static void ccgDM_foreachMappedLoop(
- DerivedMesh *dm,
- void (*func)(void *userData, int vertex_index, int face_index, const float co[3], const float no[3]),
- void *userData,
- DMForeachFlag flag)
-{
- /* We can't use dm->getLoopDataLayout(dm) here, we want to always access dm->loopData, EditDerivedBMesh would
- * return loop data from bmesh itself. */
- const float (*lnors)[3] = (flag & DM_FOREACH_USE_NORMAL) ? DM_get_loop_data_layer(dm, CD_NORMAL) : NULL;
-
- MVert *mv = dm->getVertArray(dm);
- MLoop *ml = dm->getLoopArray(dm);
- MPoly *mp = dm->getPolyArray(dm);
- const int *v_index = dm->getVertDataArray(dm, CD_ORIGINDEX);
- const int *f_index = dm->getPolyDataArray(dm, CD_ORIGINDEX);
- int p_idx, i;
-
- for (p_idx = 0; p_idx < dm->numPolyData; ++p_idx, ++mp) {
- for (i = 0; i < mp->totloop; ++i, ++ml) {
- const int v_idx = v_index ? v_index[ml->v] : ml->v;
- const int f_idx = f_index ? f_index[p_idx] : p_idx;
- const float *no = lnors ? *lnors++ : NULL;
- if (!ELEM(ORIGINDEX_NONE, v_idx, f_idx)) {
- func(userData, v_idx, f_idx, mv[ml->v].co, no);
- }
- }
- }
+ DerivedMesh *dm,
+ void (*func)(void *userData, int index, const float v0co[3], const float v1co[3]),
+ void *userData)
+{
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ CCGEdgeIterator ei;
+ CCGKey key;
+ int i, edgeSize = ccgSubSurf_getEdgeSize(ss);
+
+ CCG_key_top_level(&key, ss);
+
+ for (ccgSubSurf_initEdgeIterator(ss, &ei); !ccgEdgeIterator_isStopped(&ei);
+ ccgEdgeIterator_next(&ei)) {
+ CCGEdge *e = ccgEdgeIterator_getCurrent(&ei);
+ const int index = ccgDM_getEdgeMapIndex(ss, e);
+
+ if (index != -1) {
+ CCGElem *edgeData = ccgSubSurf_getEdgeDataArray(ss, e);
+ for (i = 0; i < edgeSize - 1; i++) {
+ func(userData,
+ index,
+ CCG_elem_offset_co(&key, edgeData, i),
+ CCG_elem_offset_co(&key, edgeData, i + 1));
+ }
+ }
+ }
+}
+
+static void ccgDM_foreachMappedLoop(DerivedMesh *dm,
+ void (*func)(void *userData,
+ int vertex_index,
+ int face_index,
+ const float co[3],
+ const float no[3]),
+ void *userData,
+ DMForeachFlag flag)
+{
+ /* We can't use dm->getLoopDataLayout(dm) here, we want to always access dm->loopData, EditDerivedBMesh would
+ * return loop data from bmesh itself. */
+ const float(*lnors)[3] = (flag & DM_FOREACH_USE_NORMAL) ? DM_get_loop_data_layer(dm, CD_NORMAL) :
+ NULL;
+
+ MVert *mv = dm->getVertArray(dm);
+ MLoop *ml = dm->getLoopArray(dm);
+ MPoly *mp = dm->getPolyArray(dm);
+ const int *v_index = dm->getVertDataArray(dm, CD_ORIGINDEX);
+ const int *f_index = dm->getPolyDataArray(dm, CD_ORIGINDEX);
+ int p_idx, i;
+
+ for (p_idx = 0; p_idx < dm->numPolyData; ++p_idx, ++mp) {
+ for (i = 0; i < mp->totloop; ++i, ++ml) {
+ const int v_idx = v_index ? v_index[ml->v] : ml->v;
+ const int f_idx = f_index ? f_index[p_idx] : p_idx;
+ const float *no = lnors ? *lnors++ : NULL;
+ if (!ELEM(ORIGINDEX_NONE, v_idx, f_idx)) {
+ func(userData, v_idx, f_idx, mv[ml->v].co, no);
+ }
+ }
+ }
}
static void UNUSED_FUNCTION(ccgdm_pbvh_update)(CCGDerivedMesh *ccgdm)
{
- if (ccgdm->pbvh && ccgDM_use_grid_pbvh(ccgdm)) {
- CCGFace **faces;
- int totface;
+ if (ccgdm->pbvh && ccgDM_use_grid_pbvh(ccgdm)) {
+ CCGFace **faces;
+ int totface;
- BKE_pbvh_get_grid_updates(ccgdm->pbvh, 1, (void ***)&faces, &totface);
- if (totface) {
- ccgSubSurf_updateFromFaces(ccgdm->ss, 0, faces, totface);
- ccgSubSurf_updateNormals(ccgdm->ss, faces, totface);
- MEM_freeN(faces);
- }
- }
+ BKE_pbvh_get_grid_updates(ccgdm->pbvh, 1, (void ***)&faces, &totface);
+ if (totface) {
+ ccgSubSurf_updateFromFaces(ccgdm->ss, 0, faces, totface);
+ ccgSubSurf_updateNormals(ccgdm->ss, faces, totface);
+ MEM_freeN(faces);
+ }
+ }
}
static void ccgDM_foreachMappedFaceCenter(
- DerivedMesh *dm,
- void (*func)(void *userData, int index, const float co[3], const float no[3]),
- void *userData,
- DMForeachFlag flag)
+ DerivedMesh *dm,
+ void (*func)(void *userData, int index, const float co[3], const float no[3]),
+ void *userData,
+ DMForeachFlag flag)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGKey key;
- CCGFaceIterator fi;
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ CCGKey key;
+ CCGFaceIterator fi;
- CCG_key_top_level(&key, ss);
+ CCG_key_top_level(&key, ss);
- for (ccgSubSurf_initFaceIterator(ss, &fi); !ccgFaceIterator_isStopped(&fi); ccgFaceIterator_next(&fi)) {
- CCGFace *f = ccgFaceIterator_getCurrent(&fi);
- const int index = ccgDM_getFaceMapIndex(ss, f);
+ for (ccgSubSurf_initFaceIterator(ss, &fi); !ccgFaceIterator_isStopped(&fi);
+ ccgFaceIterator_next(&fi)) {
+ CCGFace *f = ccgFaceIterator_getCurrent(&fi);
+ const int index = ccgDM_getFaceMapIndex(ss, f);
- if (index != -1) {
- /* Face center data normal isn't updated atm. */
- CCGElem *vd = ccgSubSurf_getFaceGridData(ss, f, 0, 0, 0);
- const float *no = (flag & DM_FOREACH_USE_NORMAL) ? CCG_elem_no(&key, vd) : NULL;
- func(userData, index, CCG_elem_co(&key, vd), no);
- }
- }
+ if (index != -1) {
+ /* Face center data normal isn't updated atm. */
+ CCGElem *vd = ccgSubSurf_getFaceGridData(ss, f, 0, 0, 0);
+ const float *no = (flag & DM_FOREACH_USE_NORMAL) ? CCG_elem_no(&key, vd) : NULL;
+ func(userData, index, CCG_elem_co(&key, vd), no);
+ }
+ }
}
static void ccgDM_release(DerivedMesh *dm)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
-
- if (DM_release(dm)) {
- /* Before freeing, need to update the displacement map */
- if (ccgdm->multires.modified_flags) {
- /* Check that mmd still exists */
- if (!ccgdm->multires.local_mmd &&
- BLI_findindex(&ccgdm->multires.ob->modifiers, ccgdm->multires.mmd) < 0)
- {
- ccgdm->multires.mmd = NULL;
- }
-
- if (ccgdm->multires.mmd) {
- if (ccgdm->multires.modified_flags & MULTIRES_COORDS_MODIFIED)
- multires_modifier_update_mdisps(dm, NULL);
- if (ccgdm->multires.modified_flags & MULTIRES_HIDDEN_MODIFIED)
- multires_modifier_update_hidden(dm);
- }
- }
-
- if (ccgdm->ehash)
- BLI_edgehash_free(ccgdm->ehash, NULL);
-
- if (ccgdm->reverseFaceMap) MEM_freeN(ccgdm->reverseFaceMap);
- if (ccgdm->gridFaces) MEM_freeN(ccgdm->gridFaces);
- if (ccgdm->gridData) MEM_freeN(ccgdm->gridData);
- if (ccgdm->gridOffset) MEM_freeN(ccgdm->gridOffset);
- if (ccgdm->gridFlagMats) MEM_freeN(ccgdm->gridFlagMats);
- if (ccgdm->gridHidden) {
- /* Using dm->getNumGrids(dm) accesses freed memory */
- uint numGrids = ccgdm->numGrid;
- for (uint i = 0; i < numGrids; i++) {
- if (ccgdm->gridHidden[i]) {
- MEM_freeN(ccgdm->gridHidden[i]);
- }
- }
- MEM_freeN(ccgdm->gridHidden);
- }
- if (ccgdm->freeSS) ccgSubSurf_free(ccgdm->ss);
- if (ccgdm->pmap) MEM_freeN(ccgdm->pmap);
- if (ccgdm->pmap_mem) MEM_freeN(ccgdm->pmap_mem);
- MEM_freeN(ccgdm->edgeFlags);
- MEM_freeN(ccgdm->faceFlags);
- if (ccgdm->useGpuBackend == false) {
- MEM_freeN(ccgdm->vertMap);
- MEM_freeN(ccgdm->edgeMap);
- MEM_freeN(ccgdm->faceMap);
- }
-
- BLI_mutex_end(&ccgdm->loops_cache_lock);
- BLI_rw_mutex_end(&ccgdm->origindex_cache_rwlock);
-
- MEM_freeN(ccgdm);
- }
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+
+ if (DM_release(dm)) {
+ /* Before freeing, need to update the displacement map */
+ if (ccgdm->multires.modified_flags) {
+ /* Check that mmd still exists */
+ if (!ccgdm->multires.local_mmd &&
+ BLI_findindex(&ccgdm->multires.ob->modifiers, ccgdm->multires.mmd) < 0) {
+ ccgdm->multires.mmd = NULL;
+ }
+
+ if (ccgdm->multires.mmd) {
+ if (ccgdm->multires.modified_flags & MULTIRES_COORDS_MODIFIED)
+ multires_modifier_update_mdisps(dm, NULL);
+ if (ccgdm->multires.modified_flags & MULTIRES_HIDDEN_MODIFIED)
+ multires_modifier_update_hidden(dm);
+ }
+ }
+
+ if (ccgdm->ehash)
+ BLI_edgehash_free(ccgdm->ehash, NULL);
+
+ if (ccgdm->reverseFaceMap)
+ MEM_freeN(ccgdm->reverseFaceMap);
+ if (ccgdm->gridFaces)
+ MEM_freeN(ccgdm->gridFaces);
+ if (ccgdm->gridData)
+ MEM_freeN(ccgdm->gridData);
+ if (ccgdm->gridOffset)
+ MEM_freeN(ccgdm->gridOffset);
+ if (ccgdm->gridFlagMats)
+ MEM_freeN(ccgdm->gridFlagMats);
+ if (ccgdm->gridHidden) {
+ /* Using dm->getNumGrids(dm) accesses freed memory */
+ uint numGrids = ccgdm->numGrid;
+ for (uint i = 0; i < numGrids; i++) {
+ if (ccgdm->gridHidden[i]) {
+ MEM_freeN(ccgdm->gridHidden[i]);
+ }
+ }
+ MEM_freeN(ccgdm->gridHidden);
+ }
+ if (ccgdm->freeSS)
+ ccgSubSurf_free(ccgdm->ss);
+ if (ccgdm->pmap)
+ MEM_freeN(ccgdm->pmap);
+ if (ccgdm->pmap_mem)
+ MEM_freeN(ccgdm->pmap_mem);
+ MEM_freeN(ccgdm->edgeFlags);
+ MEM_freeN(ccgdm->faceFlags);
+ if (ccgdm->useGpuBackend == false) {
+ MEM_freeN(ccgdm->vertMap);
+ MEM_freeN(ccgdm->edgeMap);
+ MEM_freeN(ccgdm->faceMap);
+ }
+
+ BLI_mutex_end(&ccgdm->loops_cache_lock);
+ BLI_rw_mutex_end(&ccgdm->origindex_cache_rwlock);
+
+ MEM_freeN(ccgdm);
+ }
}
static void *ccgDM_get_vert_data_layer(DerivedMesh *dm, int type)
{
- if (type == CD_ORIGINDEX) {
- /* create origindex on demand to save memory */
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
- CCGSubSurf *ss = ccgdm->ss;
- int *origindex;
- int a, index, totnone, totorig;
+ if (type == CD_ORIGINDEX) {
+ /* create origindex on demand to save memory */
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ int *origindex;
+ int a, index, totnone, totorig;
- /* Avoid re-creation if the layer exists already */
- BLI_rw_mutex_lock(&ccgdm->origindex_cache_rwlock, THREAD_LOCK_READ);
- origindex = DM_get_vert_data_layer(dm, CD_ORIGINDEX);
- BLI_rw_mutex_unlock(&ccgdm->origindex_cache_rwlock);
- if (origindex) {
- return origindex;
- }
+ /* Avoid re-creation if the layer exists already */
+ BLI_rw_mutex_lock(&ccgdm->origindex_cache_rwlock, THREAD_LOCK_READ);
+ origindex = DM_get_vert_data_layer(dm, CD_ORIGINDEX);
+ BLI_rw_mutex_unlock(&ccgdm->origindex_cache_rwlock);
+ if (origindex) {
+ return origindex;
+ }
- BLI_rw_mutex_lock(&ccgdm->origindex_cache_rwlock, THREAD_LOCK_WRITE);
- DM_add_vert_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
- origindex = DM_get_vert_data_layer(dm, CD_ORIGINDEX);
+ BLI_rw_mutex_lock(&ccgdm->origindex_cache_rwlock, THREAD_LOCK_WRITE);
+ DM_add_vert_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
+ origindex = DM_get_vert_data_layer(dm, CD_ORIGINDEX);
- totorig = ccgSubSurf_getNumVerts(ss);
- totnone = dm->numVertData - totorig;
+ totorig = ccgSubSurf_getNumVerts(ss);
+ totnone = dm->numVertData - totorig;
- /* original vertices are at the end */
- for (a = 0; a < totnone; a++)
- origindex[a] = ORIGINDEX_NONE;
+ /* original vertices are at the end */
+ for (a = 0; a < totnone; a++)
+ origindex[a] = ORIGINDEX_NONE;
- for (index = 0; index < totorig; index++, a++) {
- CCGVert *v = ccgdm->vertMap[index].vert;
- origindex[a] = ccgDM_getVertMapIndex(ccgdm->ss, v);
- }
- BLI_rw_mutex_unlock(&ccgdm->origindex_cache_rwlock);
+ for (index = 0; index < totorig; index++, a++) {
+ CCGVert *v = ccgdm->vertMap[index].vert;
+ origindex[a] = ccgDM_getVertMapIndex(ccgdm->ss, v);
+ }
+ BLI_rw_mutex_unlock(&ccgdm->origindex_cache_rwlock);
- return origindex;
- }
+ return origindex;
+ }
- return DM_get_vert_data_layer(dm, type);
+ return DM_get_vert_data_layer(dm, type);
}
static void *ccgDM_get_edge_data_layer(DerivedMesh *dm, int type)
{
- if (type == CD_ORIGINDEX) {
- /* create origindex on demand to save memory */
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
- CCGSubSurf *ss = ccgdm->ss;
- int *origindex;
- int a, i, index, totnone, totorig, totedge;
- int edgeSize = ccgSubSurf_getEdgeSize(ss);
+ if (type == CD_ORIGINDEX) {
+ /* create origindex on demand to save memory */
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ int *origindex;
+ int a, i, index, totnone, totorig, totedge;
+ int edgeSize = ccgSubSurf_getEdgeSize(ss);
- /* Avoid re-creation if the layer exists already */
- origindex = DM_get_edge_data_layer(dm, CD_ORIGINDEX);
- if (origindex) {
- return origindex;
- }
+ /* Avoid re-creation if the layer exists already */
+ origindex = DM_get_edge_data_layer(dm, CD_ORIGINDEX);
+ if (origindex) {
+ return origindex;
+ }
- DM_add_edge_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
- origindex = DM_get_edge_data_layer(dm, CD_ORIGINDEX);
+ DM_add_edge_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
+ origindex = DM_get_edge_data_layer(dm, CD_ORIGINDEX);
- totedge = ccgSubSurf_getNumEdges(ss);
- totorig = totedge * (edgeSize - 1);
- totnone = dm->numEdgeData - totorig;
+ totedge = ccgSubSurf_getNumEdges(ss);
+ totorig = totedge * (edgeSize - 1);
+ totnone = dm->numEdgeData - totorig;
- /* original edges are at the end */
- for (a = 0; a < totnone; a++)
- origindex[a] = ORIGINDEX_NONE;
+ /* original edges are at the end */
+ for (a = 0; a < totnone; a++)
+ origindex[a] = ORIGINDEX_NONE;
- for (index = 0; index < totedge; index++) {
- CCGEdge *e = ccgdm->edgeMap[index].edge;
- int mapIndex = ccgDM_getEdgeMapIndex(ss, e);
+ for (index = 0; index < totedge; index++) {
+ CCGEdge *e = ccgdm->edgeMap[index].edge;
+ int mapIndex = ccgDM_getEdgeMapIndex(ss, e);
- for (i = 0; i < edgeSize - 1; i++, a++)
- origindex[a] = mapIndex;
- }
+ for (i = 0; i < edgeSize - 1; i++, a++)
+ origindex[a] = mapIndex;
+ }
- return origindex;
- }
+ return origindex;
+ }
- return DM_get_edge_data_layer(dm, type);
+ return DM_get_edge_data_layer(dm, type);
}
static void *ccgDM_get_tessface_data_layer(DerivedMesh *dm, int type)
{
- if (type == CD_ORIGINDEX) {
- /* create origindex on demand to save memory */
- int *origindex;
+ if (type == CD_ORIGINDEX) {
+ /* create origindex on demand to save memory */
+ int *origindex;
- /* Avoid re-creation if the layer exists already */
- origindex = DM_get_tessface_data_layer(dm, CD_ORIGINDEX);
- if (origindex) {
- return origindex;
- }
+ /* Avoid re-creation if the layer exists already */
+ origindex = DM_get_tessface_data_layer(dm, CD_ORIGINDEX);
+ if (origindex) {
+ return origindex;
+ }
- DM_add_tessface_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
- origindex = DM_get_tessface_data_layer(dm, CD_ORIGINDEX);
+ DM_add_tessface_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
+ origindex = DM_get_tessface_data_layer(dm, CD_ORIGINDEX);
- /* silly loop counting up */
- range_vn_i(origindex, dm->getNumTessFaces(dm), 0);
+ /* silly loop counting up */
+ range_vn_i(origindex, dm->getNumTessFaces(dm), 0);
- return origindex;
- }
+ return origindex;
+ }
- if (type == CD_TESSLOOPNORMAL) {
- /* Create tessloopnormal on demand to save memory. */
- /* Note that since tessellated face corners are the same a loops in CCGDM, and since all faces have four
- * loops/corners, we can simplify the code here by converting tessloopnormals from 'short (*)[4][3]'
- * to 'short (*)[3]'.
- */
- short (*tlnors)[3];
+ if (type == CD_TESSLOOPNORMAL) {
+ /* Create tessloopnormal on demand to save memory. */
+ /* Note that since tessellated face corners are the same a loops in CCGDM, and since all faces have four
+ * loops/corners, we can simplify the code here by converting tessloopnormals from 'short (*)[4][3]'
+ * to 'short (*)[3]'.
+ */
+ short(*tlnors)[3];
- /* Avoid re-creation if the layer exists already */
- tlnors = DM_get_tessface_data_layer(dm, CD_TESSLOOPNORMAL);
- if (!tlnors) {
- float (*lnors)[3];
- short (*tlnors_it)[3];
- const int numLoops = ccgDM_getNumLoops(dm);
- int i;
+ /* Avoid re-creation if the layer exists already */
+ tlnors = DM_get_tessface_data_layer(dm, CD_TESSLOOPNORMAL);
+ if (!tlnors) {
+ float(*lnors)[3];
+ short(*tlnors_it)[3];
+ const int numLoops = ccgDM_getNumLoops(dm);
+ int i;
- lnors = dm->getLoopDataArray(dm, CD_NORMAL);
- if (!lnors) {
- return NULL;
- }
+ lnors = dm->getLoopDataArray(dm, CD_NORMAL);
+ if (!lnors) {
+ return NULL;
+ }
- DM_add_tessface_layer(dm, CD_TESSLOOPNORMAL, CD_CALLOC, NULL);
- tlnors = tlnors_it = (short (*)[3])DM_get_tessface_data_layer(dm, CD_TESSLOOPNORMAL);
+ DM_add_tessface_layer(dm, CD_TESSLOOPNORMAL, CD_CALLOC, NULL);
+ tlnors = tlnors_it = (short(*)[3])DM_get_tessface_data_layer(dm, CD_TESSLOOPNORMAL);
- /* With ccgdm, we have a simple one to one mapping between loops and tessellated face corners. */
- for (i = 0; i < numLoops; ++i, ++tlnors_it, ++lnors) {
- normal_float_to_short_v3(*tlnors_it, *lnors);
- }
- }
+ /* With ccgdm, we have a simple one to one mapping between loops and tessellated face corners. */
+ for (i = 0; i < numLoops; ++i, ++tlnors_it, ++lnors) {
+ normal_float_to_short_v3(*tlnors_it, *lnors);
+ }
+ }
- return tlnors;
- }
+ return tlnors;
+ }
- return DM_get_tessface_data_layer(dm, type);
+ return DM_get_tessface_data_layer(dm, type);
}
static void *ccgDM_get_poly_data_layer(DerivedMesh *dm, int type)
{
- if (type == CD_ORIGINDEX) {
- /* create origindex on demand to save memory */
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
- CCGSubSurf *ss = ccgdm->ss;
- int *origindex;
- int a, i, index, totface;
- int gridFaces = ccgSubSurf_getGridSize(ss) - 1;
+ if (type == CD_ORIGINDEX) {
+ /* create origindex on demand to save memory */
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ int *origindex;
+ int a, i, index, totface;
+ int gridFaces = ccgSubSurf_getGridSize(ss) - 1;
- /* Avoid re-creation if the layer exists already */
- origindex = DM_get_poly_data_layer(dm, CD_ORIGINDEX);
- if (origindex) {
- return origindex;
- }
+ /* Avoid re-creation if the layer exists already */
+ origindex = DM_get_poly_data_layer(dm, CD_ORIGINDEX);
+ if (origindex) {
+ return origindex;
+ }
- DM_add_poly_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
- origindex = DM_get_poly_data_layer(dm, CD_ORIGINDEX);
+ DM_add_poly_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
+ origindex = DM_get_poly_data_layer(dm, CD_ORIGINDEX);
- totface = ccgSubSurf_getNumFaces(ss);
+ totface = ccgSubSurf_getNumFaces(ss);
- for (a = 0, index = 0; index < totface; index++) {
- CCGFace *f = ccgdm->faceMap[index].face;
- int numVerts = ccgSubSurf_getFaceNumVerts(f);
- int mapIndex = ccgDM_getFaceMapIndex(ss, f);
+ for (a = 0, index = 0; index < totface; index++) {
+ CCGFace *f = ccgdm->faceMap[index].face;
+ int numVerts = ccgSubSurf_getFaceNumVerts(f);
+ int mapIndex = ccgDM_getFaceMapIndex(ss, f);
- for (i = 0; i < gridFaces * gridFaces * numVerts; i++, a++)
- origindex[a] = mapIndex;
- }
+ for (i = 0; i < gridFaces * gridFaces * numVerts; i++, a++)
+ origindex[a] = mapIndex;
+ }
- return origindex;
- }
+ return origindex;
+ }
- return DM_get_poly_data_layer(dm, type);
+ return DM_get_poly_data_layer(dm, type);
}
static void *ccgDM_get_vert_data(DerivedMesh *dm, int index, int type)
{
- if (type == CD_ORIGINDEX) {
- /* ensure creation of CD_ORIGINDEX layer */
- ccgDM_get_vert_data_layer(dm, type);
- }
+ if (type == CD_ORIGINDEX) {
+ /* ensure creation of CD_ORIGINDEX layer */
+ ccgDM_get_vert_data_layer(dm, type);
+ }
- return DM_get_vert_data(dm, index, type);
+ return DM_get_vert_data(dm, index, type);
}
static void *ccgDM_get_edge_data(DerivedMesh *dm, int index, int type)
{
- if (type == CD_ORIGINDEX) {
- /* ensure creation of CD_ORIGINDEX layer */
- ccgDM_get_edge_data_layer(dm, type);
- }
+ if (type == CD_ORIGINDEX) {
+ /* ensure creation of CD_ORIGINDEX layer */
+ ccgDM_get_edge_data_layer(dm, type);
+ }
- return DM_get_edge_data(dm, index, type);
+ return DM_get_edge_data(dm, index, type);
}
static void *ccgDM_get_tessface_data(DerivedMesh *dm, int index, int type)
{
- if (ELEM(type, CD_ORIGINDEX, CD_TESSLOOPNORMAL)) {
- /* ensure creation of CD_ORIGINDEX/CD_TESSLOOPNORMAL layers */
- ccgDM_get_tessface_data_layer(dm, type);
- }
+ if (ELEM(type, CD_ORIGINDEX, CD_TESSLOOPNORMAL)) {
+ /* ensure creation of CD_ORIGINDEX/CD_TESSLOOPNORMAL layers */
+ ccgDM_get_tessface_data_layer(dm, type);
+ }
- return DM_get_tessface_data(dm, index, type);
+ return DM_get_tessface_data(dm, index, type);
}
static void *ccgDM_get_poly_data(DerivedMesh *dm, int index, int type)
{
- if (type == CD_ORIGINDEX) {
- /* ensure creation of CD_ORIGINDEX layer */
- ccgDM_get_tessface_data_layer(dm, type);
- }
+ if (type == CD_ORIGINDEX) {
+ /* ensure creation of CD_ORIGINDEX layer */
+ ccgDM_get_tessface_data_layer(dm, type);
+ }
- return DM_get_poly_data(dm, index, type);
+ return DM_get_poly_data(dm, index, type);
}
static int ccgDM_getNumGrids(DerivedMesh *dm)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
- int index, numFaces, numGrids;
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ int index, numFaces, numGrids;
- numFaces = ccgSubSurf_getNumFaces(ccgdm->ss);
- numGrids = 0;
+ numFaces = ccgSubSurf_getNumFaces(ccgdm->ss);
+ numGrids = 0;
- for (index = 0; index < numFaces; index++) {
- CCGFace *f = ccgdm->faceMap[index].face;
- numGrids += ccgSubSurf_getFaceNumVerts(f);
- }
+ for (index = 0; index < numFaces; index++) {
+ CCGFace *f = ccgdm->faceMap[index].face;
+ numGrids += ccgSubSurf_getFaceNumVerts(f);
+ }
- return numGrids;
+ return numGrids;
}
static int ccgDM_getGridSize(DerivedMesh *dm)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
- return ccgSubSurf_getGridSize(ccgdm->ss);
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ return ccgSubSurf_getGridSize(ccgdm->ss);
}
static void ccgdm_create_grids(DerivedMesh *dm)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGElem **gridData;
- DMFlagMat *gridFlagMats;
- CCGFace **gridFaces;
- int *gridOffset;
- int index, numFaces, numGrids, S, gIndex /*, gridSize*/;
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ CCGElem **gridData;
+ DMFlagMat *gridFlagMats;
+ CCGFace **gridFaces;
+ int *gridOffset;
+ int index, numFaces, numGrids, S, gIndex /*, gridSize*/;
- if (ccgdm->gridData)
- return;
+ if (ccgdm->gridData)
+ return;
- numGrids = ccgDM_getNumGrids(dm);
- numFaces = ccgSubSurf_getNumFaces(ss);
- /*gridSize = ccgDM_getGridSize(dm);*/ /*UNUSED*/
+ numGrids = ccgDM_getNumGrids(dm);
+ numFaces = ccgSubSurf_getNumFaces(ss);
+ /*gridSize = ccgDM_getGridSize(dm);*/ /*UNUSED*/
- /* compute offset into grid array for each face */
- gridOffset = MEM_mallocN(sizeof(int) * numFaces, "ccgdm.gridOffset");
+ /* compute offset into grid array for each face */
+ gridOffset = MEM_mallocN(sizeof(int) * numFaces, "ccgdm.gridOffset");
- for (gIndex = 0, index = 0; index < numFaces; index++) {
- CCGFace *f = ccgdm->faceMap[index].face;
- int numVerts = ccgSubSurf_getFaceNumVerts(f);
+ for (gIndex = 0, index = 0; index < numFaces; index++) {
+ CCGFace *f = ccgdm->faceMap[index].face;
+ int numVerts = ccgSubSurf_getFaceNumVerts(f);
- gridOffset[index] = gIndex;
- gIndex += numVerts;
- }
+ gridOffset[index] = gIndex;
+ gIndex += numVerts;
+ }
- /* compute grid data */
- gridData = MEM_mallocN(sizeof(CCGElem *) * numGrids, "ccgdm.gridData");
- gridFaces = MEM_mallocN(sizeof(CCGFace *) * numGrids, "ccgdm.gridFaces");
- gridFlagMats = MEM_mallocN(sizeof(DMFlagMat) * numGrids, "ccgdm.gridFlagMats");
+ /* compute grid data */
+ gridData = MEM_mallocN(sizeof(CCGElem *) * numGrids, "ccgdm.gridData");
+ gridFaces = MEM_mallocN(sizeof(CCGFace *) * numGrids, "ccgdm.gridFaces");
+ gridFlagMats = MEM_mallocN(sizeof(DMFlagMat) * numGrids, "ccgdm.gridFlagMats");
- ccgdm->gridHidden = MEM_callocN(sizeof(*ccgdm->gridHidden) * numGrids, "ccgdm.gridHidden");
+ ccgdm->gridHidden = MEM_callocN(sizeof(*ccgdm->gridHidden) * numGrids, "ccgdm.gridHidden");
- for (gIndex = 0, index = 0; index < numFaces; index++) {
- CCGFace *f = ccgdm->faceMap[index].face;
- int numVerts = ccgSubSurf_getFaceNumVerts(f);
+ for (gIndex = 0, index = 0; index < numFaces; index++) {
+ CCGFace *f = ccgdm->faceMap[index].face;
+ int numVerts = ccgSubSurf_getFaceNumVerts(f);
- for (S = 0; S < numVerts; S++, gIndex++) {
- gridData[gIndex] = ccgSubSurf_getFaceGridDataArray(ss, f, S);
- gridFaces[gIndex] = f;
- gridFlagMats[gIndex] = ccgdm->faceFlags[index];
- }
- }
+ for (S = 0; S < numVerts; S++, gIndex++) {
+ gridData[gIndex] = ccgSubSurf_getFaceGridDataArray(ss, f, S);
+ gridFaces[gIndex] = f;
+ gridFlagMats[gIndex] = ccgdm->faceFlags[index];
+ }
+ }
- ccgdm->gridData = gridData;
- ccgdm->gridFaces = gridFaces;
- ccgdm->gridOffset = gridOffset;
- ccgdm->gridFlagMats = gridFlagMats;
- ccgdm->numGrid = numGrids;
+ ccgdm->gridData = gridData;
+ ccgdm->gridFaces = gridFaces;
+ ccgdm->gridOffset = gridOffset;
+ ccgdm->gridFlagMats = gridFlagMats;
+ ccgdm->numGrid = numGrids;
}
static CCGElem **ccgDM_getGridData(DerivedMesh *dm)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
- ccgdm_create_grids(dm);
- return ccgdm->gridData;
+ ccgdm_create_grids(dm);
+ return ccgdm->gridData;
}
static int *ccgDM_getGridOffset(DerivedMesh *dm)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
- ccgdm_create_grids(dm);
- return ccgdm->gridOffset;
+ ccgdm_create_grids(dm);
+ return ccgdm->gridOffset;
}
static void ccgDM_getGridKey(DerivedMesh *dm, CCGKey *key)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
- CCG_key_top_level(key, ccgdm->ss);
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ CCG_key_top_level(key, ccgdm->ss);
}
static DMFlagMat *ccgDM_getGridFlagMats(DerivedMesh *dm)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
- ccgdm_create_grids(dm);
- return ccgdm->gridFlagMats;
+ ccgdm_create_grids(dm);
+ return ccgdm->gridFlagMats;
}
static BLI_bitmap **ccgDM_getGridHidden(DerivedMesh *dm)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
- ccgdm_create_grids(dm);
- return ccgdm->gridHidden;
+ ccgdm_create_grids(dm);
+ return ccgdm->gridHidden;
}
static const MeshElemMap *ccgDM_getPolyMap(Object *ob, DerivedMesh *dm)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
- if (!ccgdm->multires.mmd && !ccgdm->pmap && ob->type == OB_MESH) {
- Mesh *me = ob->data;
+ if (!ccgdm->multires.mmd && !ccgdm->pmap && ob->type == OB_MESH) {
+ Mesh *me = ob->data;
- BKE_mesh_vert_poly_map_create(&ccgdm->pmap, &ccgdm->pmap_mem,
- me->mpoly, me->mloop,
- me->totvert, me->totpoly, me->totloop);
- }
+ BKE_mesh_vert_poly_map_create(&ccgdm->pmap,
+ &ccgdm->pmap_mem,
+ me->mpoly,
+ me->mloop,
+ me->totvert,
+ me->totpoly,
+ me->totloop);
+ }
- return ccgdm->pmap;
+ return ccgdm->pmap;
}
static int ccgDM_use_grid_pbvh(CCGDerivedMesh *ccgdm)
{
- MultiresModifierData *mmd = ccgdm->multires.mmd;
+ MultiresModifierData *mmd = ccgdm->multires.mmd;
- /* both of multires and subsurf modifiers are CCG, but
- * grids should only be used when sculpting on multires */
- if (!mmd)
- return 0;
+ /* both of multires and subsurf modifiers are CCG, but
+ * grids should only be used when sculpting on multires */
+ if (!mmd)
+ return 0;
- return 1;
+ return 1;
}
static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
- CCGKey key;
- int numGrids;
-
- CCG_key_top_level(&key, ccgdm->ss);
-
- if (!ob) {
- ccgdm->pbvh = NULL;
- return NULL;
- }
-
- if (!ob->sculpt)
- return NULL;
-
- bool grid_pbvh = ccgDM_use_grid_pbvh(ccgdm);
- if ((ob->mode & OB_MODE_SCULPT) == 0) {
- /* In vwpaint, we may use a grid_pbvh for multires/subsurf, under certain conditions.
- * More complex cases break 'history' trail back to original vertices, in that case we fall back to
- * deformed cage only (i.e. original deformed mesh). */
- VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
-
- grid_pbvh = true;
- bool has_one_ccg_modifier = false;
- for (; md; md = md->next) {
- /* We can only accept to use this ccgdm if:
- * - it's the only active ccgdm in the stack.
- * - there is no topology-modifying modifier in the stack.
- * Otherwise, there is no way to map back to original geometry from grid-generated PBVH.
- */
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
-
- if (!modifier_isEnabled(NULL, md, eModifierMode_Realtime)) {
- continue;
- }
- if (ELEM(mti->type, eModifierTypeType_OnlyDeform, eModifierTypeType_NonGeometrical)) {
- continue;
- }
-
- if (ELEM(md->type, eModifierType_Subsurf, eModifierType_Multires)) {
- if (has_one_ccg_modifier) {
- /* We only allow a single active ccg modifier in the stack. */
- grid_pbvh = false;
- break;
- }
- has_one_ccg_modifier = true;
- continue;
- }
-
- /* Any other non-deforming modifier makes it impossible to use grid pbvh. */
- grid_pbvh = false;
- break;
- }
- }
-
- if (ob->sculpt->pbvh) {
- /* Note that we have to clean up exisitng pbvh instead of updating it in case it does not match current
- * grid_pbvh status. */
- const PBVHType pbvh_type = BKE_pbvh_type(ob->sculpt->pbvh);
- if (grid_pbvh) {
- if (pbvh_type == PBVH_GRIDS) {
- /* pbvh's grids, gridadj and gridfaces points to data inside ccgdm
- * but this can be freed on ccgdm release, this updates the pointers
- * when the ccgdm gets remade, the assumption is that the topology
- * does not change. */
- ccgdm_create_grids(dm);
- BKE_pbvh_grids_update(ob->sculpt->pbvh, ccgdm->gridData, (void **)ccgdm->gridFaces,
- ccgdm->gridFlagMats, ccgdm->gridHidden);
- }
- else {
- BKE_pbvh_free(ob->sculpt->pbvh);
- ob->sculpt->pbvh = NULL;
- }
- }
- else if (pbvh_type == PBVH_GRIDS) {
- BKE_pbvh_free(ob->sculpt->pbvh);
- ob->sculpt->pbvh = NULL;
- }
-
- ccgdm->pbvh = ob->sculpt->pbvh;
- }
-
- if (ccgdm->pbvh) {
- return ccgdm->pbvh;
- }
-
- /* No pbvh exists yet, we need to create one. only in case of multires
- * we build a pbvh over the modified mesh, in other cases the base mesh
- * is being sculpted, so we build a pbvh from that. */
- /* Note: vwpaint tries to always build a pbvh over the modified mesh. */
- if (grid_pbvh) {
- ccgdm_create_grids(dm);
-
- numGrids = ccgDM_getNumGrids(dm);
-
- ob->sculpt->pbvh = ccgdm->pbvh = BKE_pbvh_new();
- BKE_pbvh_build_grids(ccgdm->pbvh, ccgdm->gridData,
- numGrids, &key, (void **) ccgdm->gridFaces, ccgdm->gridFlagMats, ccgdm->gridHidden);
- }
- else if (ob->type == OB_MESH) {
- Mesh *me = BKE_object_get_original_mesh(ob);
- const int looptris_num = poly_to_tri_count(me->totpoly, me->totloop);
- MLoopTri *looptri;
-
- looptri = MEM_mallocN(sizeof(*looptri) * looptris_num, __func__);
-
- BKE_mesh_recalc_looptri(
- me->mloop, me->mpoly,
- me->mvert,
- me->totloop, me->totpoly,
- looptri);
-
- ob->sculpt->pbvh = ccgdm->pbvh = BKE_pbvh_new();
- BKE_pbvh_build_mesh(ccgdm->pbvh, me->mpoly, me->mloop, me->mvert, me->totvert, &me->vdata,
- looptri, looptris_num);
-
- if (ob->sculpt->modifiers_active && ob->derivedDeform != NULL) {
- DerivedMesh *deformdm = ob->derivedDeform;
- float (*vertCos)[3];
- int totvert;
-
- totvert = deformdm->getNumVerts(deformdm);
- vertCos = MEM_malloc_arrayN(totvert, sizeof(float[3]), "ccgDM_getPBVH vertCos");
- deformdm->getVertCos(deformdm, vertCos);
- BKE_pbvh_apply_vertCos(ccgdm->pbvh, vertCos, totvert);
- MEM_freeN(vertCos);
- }
- }
-
- if (ccgdm->pbvh != NULL) {
- pbvh_show_diffuse_color_set(ccgdm->pbvh, ob->sculpt->show_diffuse_color);
- pbvh_show_mask_set(ccgdm->pbvh, ob->sculpt->show_mask);
- }
-
- return ccgdm->pbvh;
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ CCGKey key;
+ int numGrids;
+
+ CCG_key_top_level(&key, ccgdm->ss);
+
+ if (!ob) {
+ ccgdm->pbvh = NULL;
+ return NULL;
+ }
+
+ if (!ob->sculpt)
+ return NULL;
+
+ bool grid_pbvh = ccgDM_use_grid_pbvh(ccgdm);
+ if ((ob->mode & OB_MODE_SCULPT) == 0) {
+ /* In vwpaint, we may use a grid_pbvh for multires/subsurf, under certain conditions.
+ * More complex cases break 'history' trail back to original vertices, in that case we fall back to
+ * deformed cage only (i.e. original deformed mesh). */
+ VirtualModifierData virtualModifierData;
+ ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+
+ grid_pbvh = true;
+ bool has_one_ccg_modifier = false;
+ for (; md; md = md->next) {
+ /* We can only accept to use this ccgdm if:
+ * - it's the only active ccgdm in the stack.
+ * - there is no topology-modifying modifier in the stack.
+ * Otherwise, there is no way to map back to original geometry from grid-generated PBVH.
+ */
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if (!modifier_isEnabled(NULL, md, eModifierMode_Realtime)) {
+ continue;
+ }
+ if (ELEM(mti->type, eModifierTypeType_OnlyDeform, eModifierTypeType_NonGeometrical)) {
+ continue;
+ }
+
+ if (ELEM(md->type, eModifierType_Subsurf, eModifierType_Multires)) {
+ if (has_one_ccg_modifier) {
+ /* We only allow a single active ccg modifier in the stack. */
+ grid_pbvh = false;
+ break;
+ }
+ has_one_ccg_modifier = true;
+ continue;
+ }
+
+ /* Any other non-deforming modifier makes it impossible to use grid pbvh. */
+ grid_pbvh = false;
+ break;
+ }
+ }
+
+ if (ob->sculpt->pbvh) {
+ /* Note that we have to clean up exisitng pbvh instead of updating it in case it does not match current
+ * grid_pbvh status. */
+ const PBVHType pbvh_type = BKE_pbvh_type(ob->sculpt->pbvh);
+ if (grid_pbvh) {
+ if (pbvh_type == PBVH_GRIDS) {
+ /* pbvh's grids, gridadj and gridfaces points to data inside ccgdm
+ * but this can be freed on ccgdm release, this updates the pointers
+ * when the ccgdm gets remade, the assumption is that the topology
+ * does not change. */
+ ccgdm_create_grids(dm);
+ BKE_pbvh_grids_update(ob->sculpt->pbvh,
+ ccgdm->gridData,
+ (void **)ccgdm->gridFaces,
+ ccgdm->gridFlagMats,
+ ccgdm->gridHidden);
+ }
+ else {
+ BKE_pbvh_free(ob->sculpt->pbvh);
+ ob->sculpt->pbvh = NULL;
+ }
+ }
+ else if (pbvh_type == PBVH_GRIDS) {
+ BKE_pbvh_free(ob->sculpt->pbvh);
+ ob->sculpt->pbvh = NULL;
+ }
+
+ ccgdm->pbvh = ob->sculpt->pbvh;
+ }
+
+ if (ccgdm->pbvh) {
+ return ccgdm->pbvh;
+ }
+
+ /* No pbvh exists yet, we need to create one. only in case of multires
+ * we build a pbvh over the modified mesh, in other cases the base mesh
+ * is being sculpted, so we build a pbvh from that. */
+ /* Note: vwpaint tries to always build a pbvh over the modified mesh. */
+ if (grid_pbvh) {
+ ccgdm_create_grids(dm);
+
+ numGrids = ccgDM_getNumGrids(dm);
+
+ ob->sculpt->pbvh = ccgdm->pbvh = BKE_pbvh_new();
+ BKE_pbvh_build_grids(ccgdm->pbvh,
+ ccgdm->gridData,
+ numGrids,
+ &key,
+ (void **)ccgdm->gridFaces,
+ ccgdm->gridFlagMats,
+ ccgdm->gridHidden);
+ }
+ else if (ob->type == OB_MESH) {
+ Mesh *me = BKE_object_get_original_mesh(ob);
+ const int looptris_num = poly_to_tri_count(me->totpoly, me->totloop);
+ MLoopTri *looptri;
+
+ looptri = MEM_mallocN(sizeof(*looptri) * looptris_num, __func__);
+
+ BKE_mesh_recalc_looptri(me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, looptri);
+
+ ob->sculpt->pbvh = ccgdm->pbvh = BKE_pbvh_new();
+ BKE_pbvh_build_mesh(ccgdm->pbvh,
+ me->mpoly,
+ me->mloop,
+ me->mvert,
+ me->totvert,
+ &me->vdata,
+ looptri,
+ looptris_num);
+
+ if (ob->sculpt->modifiers_active && ob->derivedDeform != NULL) {
+ DerivedMesh *deformdm = ob->derivedDeform;
+ float(*vertCos)[3];
+ int totvert;
+
+ totvert = deformdm->getNumVerts(deformdm);
+ vertCos = MEM_malloc_arrayN(totvert, sizeof(float[3]), "ccgDM_getPBVH vertCos");
+ deformdm->getVertCos(deformdm, vertCos);
+ BKE_pbvh_apply_vertCos(ccgdm->pbvh, vertCos, totvert);
+ MEM_freeN(vertCos);
+ }
+ }
+
+ if (ccgdm->pbvh != NULL) {
+ pbvh_show_diffuse_color_set(ccgdm->pbvh, ob->sculpt->show_diffuse_color);
+ pbvh_show_mask_set(ccgdm->pbvh, ob->sculpt->show_mask);
+ }
+
+ return ccgdm->pbvh;
}
static void ccgDM_recalcTessellation(DerivedMesh *UNUSED(dm))
{
- /* Nothing to do: CCG handles creating its own tessfaces */
+ /* Nothing to do: CCG handles creating its own tessfaces */
}
/* WARNING! *MUST* be called in an 'loops_cache_rwlock' protected thread context! */
static void ccgDM_recalcLoopTri(DerivedMesh *dm)
{
- MLoopTri *mlooptri = dm->looptris.array;
- const int tottri = dm->numPolyData * 2;
- int i, poly_index;
+ MLoopTri *mlooptri = dm->looptris.array;
+ const int tottri = dm->numPolyData * 2;
+ int i, poly_index;
- DM_ensure_looptri_data(dm);
- mlooptri = dm->looptris.array_wip;
+ DM_ensure_looptri_data(dm);
+ mlooptri = dm->looptris.array_wip;
- BLI_assert(tottri == 0 || mlooptri != NULL);
- BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num);
- BLI_assert(tottri == dm->looptris.num);
+ BLI_assert(tottri == 0 || mlooptri != NULL);
+ BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num);
+ BLI_assert(tottri == dm->looptris.num);
- for (i = 0, poly_index = 0; i < tottri; i += 2, poly_index += 1) {
- MLoopTri *lt;
- lt = &mlooptri[i];
- /* quad is (0, 3, 2, 1) */
- lt->tri[0] = (poly_index * 4) + 0;
- lt->tri[1] = (poly_index * 4) + 2;
- lt->tri[2] = (poly_index * 4) + 3;
- lt->poly = poly_index;
+ for (i = 0, poly_index = 0; i < tottri; i += 2, poly_index += 1) {
+ MLoopTri *lt;
+ lt = &mlooptri[i];
+ /* quad is (0, 3, 2, 1) */
+ lt->tri[0] = (poly_index * 4) + 0;
+ lt->tri[1] = (poly_index * 4) + 2;
+ lt->tri[2] = (poly_index * 4) + 3;
+ lt->poly = poly_index;
- lt = &mlooptri[i + 1];
- lt->tri[0] = (poly_index * 4) + 0;
- lt->tri[1] = (poly_index * 4) + 1;
- lt->tri[2] = (poly_index * 4) + 2;
- lt->poly = poly_index;
- }
+ lt = &mlooptri[i + 1];
+ lt->tri[0] = (poly_index * 4) + 0;
+ lt->tri[1] = (poly_index * 4) + 1;
+ lt->tri[2] = (poly_index * 4) + 2;
+ lt->poly = poly_index;
+ }
- BLI_assert(dm->looptris.array == NULL);
- atomic_cas_ptr((void **)&dm->looptris.array, dm->looptris.array, dm->looptris.array_wip);
- dm->looptris.array_wip = NULL;
+ BLI_assert(dm->looptris.array == NULL);
+ atomic_cas_ptr((void **)&dm->looptris.array, dm->looptris.array, dm->looptris.array_wip);
+ dm->looptris.array_wip = NULL;
}
static void ccgDM_calcNormals(DerivedMesh *dm)
{
- /* Nothing to do: CCG calculates normals during drawing */
- dm->dirty &= ~DM_DIRTY_NORMALS;
+ /* Nothing to do: CCG calculates normals during drawing */
+ dm->dirty &= ~DM_DIRTY_NORMALS;
}
static void set_default_ccgdm_callbacks(CCGDerivedMesh *ccgdm)
{
- ccgdm->dm.getMinMax = ccgDM_getMinMax;
- ccgdm->dm.getNumVerts = ccgDM_getNumVerts;
- ccgdm->dm.getNumEdges = ccgDM_getNumEdges;
- ccgdm->dm.getNumLoops = ccgDM_getNumLoops;
- /* reuse of ccgDM_getNumTessFaces is intentional here: subsurf polys are just created from tessfaces */
- ccgdm->dm.getNumPolys = ccgDM_getNumPolys;
- ccgdm->dm.getNumTessFaces = ccgDM_getNumTessFaces;
-
- ccgdm->dm.getVert = ccgDM_getFinalVert;
- ccgdm->dm.getEdge = ccgDM_getFinalEdge;
- ccgdm->dm.getTessFace = ccgDM_getFinalFace;
-
- ccgdm->dm.getVertCo = ccgDM_getFinalVertCo;
- ccgdm->dm.getVertNo = ccgDM_getFinalVertNo;
-
- ccgdm->dm.copyVertArray = ccgDM_copyFinalVertArray;
- ccgdm->dm.copyEdgeArray = ccgDM_copyFinalEdgeArray;
- ccgdm->dm.copyTessFaceArray = ccgDM_copyFinalFaceArray;
- ccgdm->dm.copyLoopArray = ccgDM_copyFinalLoopArray;
- ccgdm->dm.copyPolyArray = ccgDM_copyFinalPolyArray;
-
- ccgdm->dm.getVertData = ccgDM_get_vert_data;
- ccgdm->dm.getEdgeData = ccgDM_get_edge_data;
- ccgdm->dm.getTessFaceData = ccgDM_get_tessface_data;
- ccgdm->dm.getPolyData = ccgDM_get_poly_data;
- ccgdm->dm.getVertDataArray = ccgDM_get_vert_data_layer;
- ccgdm->dm.getEdgeDataArray = ccgDM_get_edge_data_layer;
- ccgdm->dm.getTessFaceDataArray = ccgDM_get_tessface_data_layer;
- ccgdm->dm.getPolyDataArray = ccgDM_get_poly_data_layer;
- ccgdm->dm.getNumGrids = ccgDM_getNumGrids;
- ccgdm->dm.getGridSize = ccgDM_getGridSize;
- ccgdm->dm.getGridData = ccgDM_getGridData;
- ccgdm->dm.getGridOffset = ccgDM_getGridOffset;
- ccgdm->dm.getGridKey = ccgDM_getGridKey;
- ccgdm->dm.getGridFlagMats = ccgDM_getGridFlagMats;
- ccgdm->dm.getGridHidden = ccgDM_getGridHidden;
- ccgdm->dm.getPolyMap = ccgDM_getPolyMap;
- ccgdm->dm.getPBVH = ccgDM_getPBVH;
-
- ccgdm->dm.calcNormals = ccgDM_calcNormals;
- ccgdm->dm.calcLoopNormals = CDDM_calc_loop_normals;
- ccgdm->dm.calcLoopNormalsSpaceArray = CDDM_calc_loop_normals_spacearr;
- ccgdm->dm.calcLoopTangents = DM_calc_loop_tangents;
- ccgdm->dm.recalcTessellation = ccgDM_recalcTessellation;
- ccgdm->dm.recalcLoopTri = ccgDM_recalcLoopTri;
-
- ccgdm->dm.getVertCos = ccgdm_getVertCos;
- ccgdm->dm.foreachMappedVert = ccgDM_foreachMappedVert;
- ccgdm->dm.foreachMappedEdge = ccgDM_foreachMappedEdge;
- ccgdm->dm.foreachMappedLoop = ccgDM_foreachMappedLoop;
- ccgdm->dm.foreachMappedFaceCenter = ccgDM_foreachMappedFaceCenter;
-
- ccgdm->dm.release = ccgDM_release;
-}
-
-static void create_ccgdm_maps(CCGDerivedMesh *ccgdm,
- CCGSubSurf *ss)
-{
- CCGVertIterator vi;
- CCGEdgeIterator ei;
- CCGFaceIterator fi;
- int totvert, totedge, totface;
-
- totvert = ccgSubSurf_getNumVerts(ss);
- ccgdm->vertMap = MEM_mallocN(totvert * sizeof(*ccgdm->vertMap), "vertMap");
- for (ccgSubSurf_initVertIterator(ss, &vi);
- !ccgVertIterator_isStopped(&vi);
- ccgVertIterator_next(&vi))
- {
- CCGVert *v = ccgVertIterator_getCurrent(&vi);
-
- ccgdm->vertMap[POINTER_AS_INT(ccgSubSurf_getVertVertHandle(v))].vert = v;
- }
-
- totedge = ccgSubSurf_getNumEdges(ss);
- ccgdm->edgeMap = MEM_mallocN(totedge * sizeof(*ccgdm->edgeMap), "edgeMap");
- for (ccgSubSurf_initEdgeIterator(ss, &ei);
- !ccgEdgeIterator_isStopped(&ei);
- ccgEdgeIterator_next(&ei))
- {
- CCGEdge *e = ccgEdgeIterator_getCurrent(&ei);
-
- ccgdm->edgeMap[POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(e))].edge = e;
- }
-
- totface = ccgSubSurf_getNumFaces(ss);
- ccgdm->faceMap = MEM_mallocN(totface * sizeof(*ccgdm->faceMap), "faceMap");
- for (ccgSubSurf_initFaceIterator(ss, &fi);
- !ccgFaceIterator_isStopped(&fi);
- ccgFaceIterator_next(&fi))
- {
- CCGFace *f = ccgFaceIterator_getCurrent(&fi);
-
- ccgdm->faceMap[POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f))].face = f;
- }
+ ccgdm->dm.getMinMax = ccgDM_getMinMax;
+ ccgdm->dm.getNumVerts = ccgDM_getNumVerts;
+ ccgdm->dm.getNumEdges = ccgDM_getNumEdges;
+ ccgdm->dm.getNumLoops = ccgDM_getNumLoops;
+ /* reuse of ccgDM_getNumTessFaces is intentional here: subsurf polys are just created from tessfaces */
+ ccgdm->dm.getNumPolys = ccgDM_getNumPolys;
+ ccgdm->dm.getNumTessFaces = ccgDM_getNumTessFaces;
+
+ ccgdm->dm.getVert = ccgDM_getFinalVert;
+ ccgdm->dm.getEdge = ccgDM_getFinalEdge;
+ ccgdm->dm.getTessFace = ccgDM_getFinalFace;
+
+ ccgdm->dm.getVertCo = ccgDM_getFinalVertCo;
+ ccgdm->dm.getVertNo = ccgDM_getFinalVertNo;
+
+ ccgdm->dm.copyVertArray = ccgDM_copyFinalVertArray;
+ ccgdm->dm.copyEdgeArray = ccgDM_copyFinalEdgeArray;
+ ccgdm->dm.copyTessFaceArray = ccgDM_copyFinalFaceArray;
+ ccgdm->dm.copyLoopArray = ccgDM_copyFinalLoopArray;
+ ccgdm->dm.copyPolyArray = ccgDM_copyFinalPolyArray;
+
+ ccgdm->dm.getVertData = ccgDM_get_vert_data;
+ ccgdm->dm.getEdgeData = ccgDM_get_edge_data;
+ ccgdm->dm.getTessFaceData = ccgDM_get_tessface_data;
+ ccgdm->dm.getPolyData = ccgDM_get_poly_data;
+ ccgdm->dm.getVertDataArray = ccgDM_get_vert_data_layer;
+ ccgdm->dm.getEdgeDataArray = ccgDM_get_edge_data_layer;
+ ccgdm->dm.getTessFaceDataArray = ccgDM_get_tessface_data_layer;
+ ccgdm->dm.getPolyDataArray = ccgDM_get_poly_data_layer;
+ ccgdm->dm.getNumGrids = ccgDM_getNumGrids;
+ ccgdm->dm.getGridSize = ccgDM_getGridSize;
+ ccgdm->dm.getGridData = ccgDM_getGridData;
+ ccgdm->dm.getGridOffset = ccgDM_getGridOffset;
+ ccgdm->dm.getGridKey = ccgDM_getGridKey;
+ ccgdm->dm.getGridFlagMats = ccgDM_getGridFlagMats;
+ ccgdm->dm.getGridHidden = ccgDM_getGridHidden;
+ ccgdm->dm.getPolyMap = ccgDM_getPolyMap;
+ ccgdm->dm.getPBVH = ccgDM_getPBVH;
+
+ ccgdm->dm.calcNormals = ccgDM_calcNormals;
+ ccgdm->dm.calcLoopNormals = CDDM_calc_loop_normals;
+ ccgdm->dm.calcLoopNormalsSpaceArray = CDDM_calc_loop_normals_spacearr;
+ ccgdm->dm.calcLoopTangents = DM_calc_loop_tangents;
+ ccgdm->dm.recalcTessellation = ccgDM_recalcTessellation;
+ ccgdm->dm.recalcLoopTri = ccgDM_recalcLoopTri;
+
+ ccgdm->dm.getVertCos = ccgdm_getVertCos;
+ ccgdm->dm.foreachMappedVert = ccgDM_foreachMappedVert;
+ ccgdm->dm.foreachMappedEdge = ccgDM_foreachMappedEdge;
+ ccgdm->dm.foreachMappedLoop = ccgDM_foreachMappedLoop;
+ ccgdm->dm.foreachMappedFaceCenter = ccgDM_foreachMappedFaceCenter;
+
+ ccgdm->dm.release = ccgDM_release;
+}
+
+static void create_ccgdm_maps(CCGDerivedMesh *ccgdm, CCGSubSurf *ss)
+{
+ CCGVertIterator vi;
+ CCGEdgeIterator ei;
+ CCGFaceIterator fi;
+ int totvert, totedge, totface;
+
+ totvert = ccgSubSurf_getNumVerts(ss);
+ ccgdm->vertMap = MEM_mallocN(totvert * sizeof(*ccgdm->vertMap), "vertMap");
+ for (ccgSubSurf_initVertIterator(ss, &vi); !ccgVertIterator_isStopped(&vi);
+ ccgVertIterator_next(&vi)) {
+ CCGVert *v = ccgVertIterator_getCurrent(&vi);
+
+ ccgdm->vertMap[POINTER_AS_INT(ccgSubSurf_getVertVertHandle(v))].vert = v;
+ }
+
+ totedge = ccgSubSurf_getNumEdges(ss);
+ ccgdm->edgeMap = MEM_mallocN(totedge * sizeof(*ccgdm->edgeMap), "edgeMap");
+ for (ccgSubSurf_initEdgeIterator(ss, &ei); !ccgEdgeIterator_isStopped(&ei);
+ ccgEdgeIterator_next(&ei)) {
+ CCGEdge *e = ccgEdgeIterator_getCurrent(&ei);
+
+ ccgdm->edgeMap[POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(e))].edge = e;
+ }
+
+ totface = ccgSubSurf_getNumFaces(ss);
+ ccgdm->faceMap = MEM_mallocN(totface * sizeof(*ccgdm->faceMap), "faceMap");
+ for (ccgSubSurf_initFaceIterator(ss, &fi); !ccgFaceIterator_isStopped(&fi);
+ ccgFaceIterator_next(&fi)) {
+ CCGFace *f = ccgFaceIterator_getCurrent(&fi);
+
+ ccgdm->faceMap[POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f))].face = f;
+ }
}
/* Fill in all geometry arrays making it possible to access any
@@ -2463,383 +2483,373 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm,
DerivedMesh *dm,
bool useSubsurfUv)
{
- const int totvert = ccgSubSurf_getNumVerts(ss);
- const int totedge = ccgSubSurf_getNumEdges(ss);
- const int totface = ccgSubSurf_getNumFaces(ss);
- int index;
- int i;
- int vertNum = 0, edgeNum = 0, faceNum = 0;
- int *vertOrigIndex, *faceOrigIndex, *polyOrigIndex, *base_polyOrigIndex, *edgeOrigIndex;
- short *edgeFlags = ccgdm->edgeFlags;
- DMFlagMat *faceFlags = ccgdm->faceFlags;
- int *polyidx = NULL;
+ const int totvert = ccgSubSurf_getNumVerts(ss);
+ const int totedge = ccgSubSurf_getNumEdges(ss);
+ const int totface = ccgSubSurf_getNumFaces(ss);
+ int index;
+ int i;
+ int vertNum = 0, edgeNum = 0, faceNum = 0;
+ int *vertOrigIndex, *faceOrigIndex, *polyOrigIndex, *base_polyOrigIndex, *edgeOrigIndex;
+ short *edgeFlags = ccgdm->edgeFlags;
+ DMFlagMat *faceFlags = ccgdm->faceFlags;
+ int *polyidx = NULL;
#ifndef USE_DYNSIZE
- int *loopidx = NULL, *vertidx = NULL;
- BLI_array_declare(loopidx);
- BLI_array_declare(vertidx);
+ int *loopidx = NULL, *vertidx = NULL;
+ BLI_array_declare(loopidx);
+ BLI_array_declare(vertidx);
#endif
- int loopindex, loopindex2;
- int edgeSize;
- int gridSize;
- int gridFaces, gridCuts;
- int gridSideEdges;
- int gridInternalEdges;
- WeightTable wtable = {NULL};
- MEdge *medge = NULL;
- MPoly *mpoly = NULL;
- bool has_edge_cd;
-
- edgeSize = ccgSubSurf_getEdgeSize(ss);
- gridSize = ccgSubSurf_getGridSize(ss);
- gridFaces = gridSize - 1;
- gridCuts = gridSize - 2;
- /*gridInternalVerts = gridSideVerts * gridSideVerts; - as yet, unused */
- gridSideEdges = gridSize - 1;
- gridInternalEdges = (gridSideEdges - 1) * gridSideEdges * 2;
-
- /* mvert = dm->getVertArray(dm); */ /* UNUSED */
- medge = dm->getEdgeArray(dm);
- /* mface = dm->getTessFaceArray(dm); */ /* UNUSED */
-
- mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
- base_polyOrigIndex = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX);
-
- vertOrigIndex = DM_get_vert_data_layer(&ccgdm->dm, CD_ORIGINDEX);
- edgeOrigIndex = DM_get_edge_data_layer(&ccgdm->dm, CD_ORIGINDEX);
-
- faceOrigIndex = DM_get_tessface_data_layer(&ccgdm->dm, CD_ORIGINDEX);
- polyOrigIndex = DM_get_poly_data_layer(&ccgdm->dm, CD_ORIGINDEX);
-
- has_edge_cd = ((ccgdm->dm.edgeData.totlayer - (edgeOrigIndex ? 1 : 0)) != 0);
-
- loopindex = loopindex2 = 0; /* current loop index */
- for (index = 0; index < totface; index++) {
- CCGFace *f = ccgdm->faceMap[index].face;
- int numVerts = ccgSubSurf_getFaceNumVerts(f);
- int numFinalEdges = numVerts * (gridSideEdges + gridInternalEdges);
- int origIndex = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f));
- int g2_wid = gridCuts + 2;
- float *w, *w2;
- int s, x, y;
+ int loopindex, loopindex2;
+ int edgeSize;
+ int gridSize;
+ int gridFaces, gridCuts;
+ int gridSideEdges;
+ int gridInternalEdges;
+ WeightTable wtable = {NULL};
+ MEdge *medge = NULL;
+ MPoly *mpoly = NULL;
+ bool has_edge_cd;
+
+ edgeSize = ccgSubSurf_getEdgeSize(ss);
+ gridSize = ccgSubSurf_getGridSize(ss);
+ gridFaces = gridSize - 1;
+ gridCuts = gridSize - 2;
+ /*gridInternalVerts = gridSideVerts * gridSideVerts; - as yet, unused */
+ gridSideEdges = gridSize - 1;
+ gridInternalEdges = (gridSideEdges - 1) * gridSideEdges * 2;
+
+ /* mvert = dm->getVertArray(dm); */ /* UNUSED */
+ medge = dm->getEdgeArray(dm);
+ /* mface = dm->getTessFaceArray(dm); */ /* UNUSED */
+
+ mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
+ base_polyOrigIndex = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX);
+
+ vertOrigIndex = DM_get_vert_data_layer(&ccgdm->dm, CD_ORIGINDEX);
+ edgeOrigIndex = DM_get_edge_data_layer(&ccgdm->dm, CD_ORIGINDEX);
+
+ faceOrigIndex = DM_get_tessface_data_layer(&ccgdm->dm, CD_ORIGINDEX);
+ polyOrigIndex = DM_get_poly_data_layer(&ccgdm->dm, CD_ORIGINDEX);
+
+ has_edge_cd = ((ccgdm->dm.edgeData.totlayer - (edgeOrigIndex ? 1 : 0)) != 0);
+
+ loopindex = loopindex2 = 0; /* current loop index */
+ for (index = 0; index < totface; index++) {
+ CCGFace *f = ccgdm->faceMap[index].face;
+ int numVerts = ccgSubSurf_getFaceNumVerts(f);
+ int numFinalEdges = numVerts * (gridSideEdges + gridInternalEdges);
+ int origIndex = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f));
+ int g2_wid = gridCuts + 2;
+ float *w, *w2;
+ int s, x, y;
#ifdef USE_DYNSIZE
- int loopidx[numVerts], vertidx[numVerts];
+ int loopidx[numVerts], vertidx[numVerts];
#endif
- w = get_ss_weights(&wtable, gridCuts, numVerts);
+ w = get_ss_weights(&wtable, gridCuts, numVerts);
- ccgdm->faceMap[index].startVert = vertNum;
- ccgdm->faceMap[index].startEdge = edgeNum;
- ccgdm->faceMap[index].startFace = faceNum;
+ ccgdm->faceMap[index].startVert = vertNum;
+ ccgdm->faceMap[index].startEdge = edgeNum;
+ ccgdm->faceMap[index].startFace = faceNum;
- faceFlags->flag = mpoly ? mpoly[origIndex].flag : 0;
- faceFlags->mat_nr = mpoly ? mpoly[origIndex].mat_nr : 0;
- faceFlags++;
+ faceFlags->flag = mpoly ? mpoly[origIndex].flag : 0;
+ faceFlags->mat_nr = mpoly ? mpoly[origIndex].mat_nr : 0;
+ faceFlags++;
- /* set the face base vert */
- *((int *)ccgSubSurf_getFaceUserData(ss, f)) = vertNum;
+ /* set the face base vert */
+ *((int *)ccgSubSurf_getFaceUserData(ss, f)) = vertNum;
#ifndef USE_DYNSIZE
- BLI_array_clear(loopidx);
- BLI_array_grow_items(loopidx, numVerts);
+ BLI_array_clear(loopidx);
+ BLI_array_grow_items(loopidx, numVerts);
#endif
- for (s = 0; s < numVerts; s++) {
- loopidx[s] = loopindex++;
- }
+ for (s = 0; s < numVerts; s++) {
+ loopidx[s] = loopindex++;
+ }
#ifndef USE_DYNSIZE
- BLI_array_clear(vertidx);
- BLI_array_grow_items(vertidx, numVerts);
+ BLI_array_clear(vertidx);
+ BLI_array_grow_items(vertidx, numVerts);
#endif
- for (s = 0; s < numVerts; s++) {
- CCGVert *v = ccgSubSurf_getFaceVert(f, s);
- vertidx[s] = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(v));
- }
-
- /*I think this is for interpolating the center vert?*/
- w2 = w; // + numVerts*(g2_wid-1) * (g2_wid-1); //numVerts*((g2_wid-1) * g2_wid+g2_wid-1);
- DM_interp_vert_data(dm, &ccgdm->dm, vertidx, w2,
- numVerts, vertNum);
- if (vertOrigIndex) {
- *vertOrigIndex = ORIGINDEX_NONE;
- vertOrigIndex++;
- }
-
- vertNum++;
-
- /*interpolate per-vert data*/
- for (s = 0; s < numVerts; s++) {
- for (x = 1; x < gridFaces; x++) {
- w2 = w + s * numVerts * g2_wid * g2_wid + x * numVerts;
- DM_interp_vert_data(dm, &ccgdm->dm, vertidx, w2,
- numVerts, vertNum);
-
- if (vertOrigIndex) {
- *vertOrigIndex = ORIGINDEX_NONE;
- vertOrigIndex++;
- }
-
- vertNum++;
- }
- }
-
- /*interpolate per-vert data*/
- for (s = 0; s < numVerts; s++) {
- for (y = 1; y < gridFaces; y++) {
- for (x = 1; x < gridFaces; x++) {
- w2 = w + s * numVerts * g2_wid * g2_wid + (y * g2_wid + x) * numVerts;
- DM_interp_vert_data(dm, &ccgdm->dm, vertidx, w2,
- numVerts, vertNum);
-
- if (vertOrigIndex) {
- *vertOrigIndex = ORIGINDEX_NONE;
- vertOrigIndex++;
- }
-
- vertNum++;
- }
- }
- }
-
- if (edgeOrigIndex) {
- for (i = 0; i < numFinalEdges; ++i) {
- edgeOrigIndex[edgeNum + i] = ORIGINDEX_NONE;
- }
- }
-
- for (s = 0; s < numVerts; s++) {
- /*interpolate per-face data*/
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- w2 = w + s * numVerts * g2_wid * g2_wid + (y * g2_wid + x) * numVerts;
- CustomData_interp(&dm->loopData, &ccgdm->dm.loopData,
- loopidx, w2, NULL, numVerts, loopindex2);
- loopindex2++;
-
- w2 = w + s * numVerts * g2_wid * g2_wid + ((y + 1) * g2_wid + (x)) * numVerts;
- CustomData_interp(&dm->loopData, &ccgdm->dm.loopData,
- loopidx, w2, NULL, numVerts, loopindex2);
- loopindex2++;
-
- w2 = w + s * numVerts * g2_wid * g2_wid + ((y + 1) * g2_wid + (x + 1)) * numVerts;
- CustomData_interp(&dm->loopData, &ccgdm->dm.loopData,
- loopidx, w2, NULL, numVerts, loopindex2);
- loopindex2++;
-
- w2 = w + s * numVerts * g2_wid * g2_wid + ((y) * g2_wid + (x + 1)) * numVerts;
- CustomData_interp(&dm->loopData, &ccgdm->dm.loopData,
- loopidx, w2, NULL, numVerts, loopindex2);
- loopindex2++;
-
- /*copy over poly data, e.g. mtexpoly*/
- CustomData_copy_data(&dm->polyData, &ccgdm->dm.polyData, origIndex, faceNum, 1);
-
- /*set original index data*/
- if (faceOrigIndex) {
- /* reference the index in 'polyOrigIndex' */
- *faceOrigIndex = faceNum;
- faceOrigIndex++;
- }
- if (polyOrigIndex) {
- *polyOrigIndex = base_polyOrigIndex ? base_polyOrigIndex[origIndex] : origIndex;
- polyOrigIndex++;
- }
-
- ccgdm->reverseFaceMap[faceNum] = index;
-
- /* This is a simple one to one mapping, here... */
- if (polyidx) {
- polyidx[faceNum] = faceNum;
- }
-
- faceNum++;
- }
- }
- }
-
- edgeNum += numFinalEdges;
- }
-
- for (index = 0; index < totedge; ++index) {
- CCGEdge *e = ccgdm->edgeMap[index].edge;
- int numFinalEdges = edgeSize - 1;
- int mapIndex = ccgDM_getEdgeMapIndex(ss, e);
- int x;
- int vertIdx[2];
- int edgeIdx = POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(e));
-
- CCGVert *v;
- v = ccgSubSurf_getEdgeVert0(e);
- vertIdx[0] = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(v));
- v = ccgSubSurf_getEdgeVert1(e);
- vertIdx[1] = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(v));
-
- ccgdm->edgeMap[index].startVert = vertNum;
- ccgdm->edgeMap[index].startEdge = edgeNum;
-
- if (edgeIdx >= 0 && edgeFlags)
- edgeFlags[edgeIdx] = medge[edgeIdx].flag;
-
- /* set the edge base vert */
- *((int *)ccgSubSurf_getEdgeUserData(ss, e)) = vertNum;
-
- for (x = 1; x < edgeSize - 1; x++) {
- float w[2];
- w[1] = (float) x / (edgeSize - 1);
- w[0] = 1 - w[1];
- DM_interp_vert_data(dm, &ccgdm->dm, vertIdx, w, 2, vertNum);
- if (vertOrigIndex) {
- *vertOrigIndex = ORIGINDEX_NONE;
- vertOrigIndex++;
- }
- vertNum++;
- }
-
- if (has_edge_cd) {
- BLI_assert(edgeIdx >= 0 && edgeIdx < dm->getNumEdges(dm));
- for (i = 0; i < numFinalEdges; ++i) {
- CustomData_copy_data(&dm->edgeData, &ccgdm->dm.edgeData, edgeIdx, edgeNum + i, 1);
- }
- }
-
- if (edgeOrigIndex) {
- for (i = 0; i < numFinalEdges; ++i) {
- edgeOrigIndex[edgeNum + i] = mapIndex;
- }
- }
-
- edgeNum += numFinalEdges;
- }
-
- if (useSubsurfUv) {
- CustomData *ldata = &ccgdm->dm.loopData;
- CustomData *dmldata = &dm->loopData;
- int numlayer = CustomData_number_of_layers(ldata, CD_MLOOPUV);
- int dmnumlayer = CustomData_number_of_layers(dmldata, CD_MLOOPUV);
-
- for (i = 0; i < numlayer && i < dmnumlayer; i++)
- set_subsurf_uv(ss, dm, &ccgdm->dm, i);
- }
-
- for (index = 0; index < totvert; ++index) {
- CCGVert *v = ccgdm->vertMap[index].vert;
- int mapIndex = ccgDM_getVertMapIndex(ccgdm->ss, v);
- int vertIdx;
-
- vertIdx = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(v));
-
- ccgdm->vertMap[index].startVert = vertNum;
-
- /* set the vert base vert */
- *((int *) ccgSubSurf_getVertUserData(ss, v)) = vertNum;
-
- DM_copy_vert_data(dm, &ccgdm->dm, vertIdx, vertNum, 1);
-
- if (vertOrigIndex) {
- *vertOrigIndex = mapIndex;
- vertOrigIndex++;
- }
- vertNum++;
- }
+ for (s = 0; s < numVerts; s++) {
+ CCGVert *v = ccgSubSurf_getFaceVert(f, s);
+ vertidx[s] = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(v));
+ }
+
+ /*I think this is for interpolating the center vert?*/
+ w2 = w; // + numVerts*(g2_wid-1) * (g2_wid-1); //numVerts*((g2_wid-1) * g2_wid+g2_wid-1);
+ DM_interp_vert_data(dm, &ccgdm->dm, vertidx, w2, numVerts, vertNum);
+ if (vertOrigIndex) {
+ *vertOrigIndex = ORIGINDEX_NONE;
+ vertOrigIndex++;
+ }
+
+ vertNum++;
+
+ /*interpolate per-vert data*/
+ for (s = 0; s < numVerts; s++) {
+ for (x = 1; x < gridFaces; x++) {
+ w2 = w + s * numVerts * g2_wid * g2_wid + x * numVerts;
+ DM_interp_vert_data(dm, &ccgdm->dm, vertidx, w2, numVerts, vertNum);
+
+ if (vertOrigIndex) {
+ *vertOrigIndex = ORIGINDEX_NONE;
+ vertOrigIndex++;
+ }
+
+ vertNum++;
+ }
+ }
+
+ /*interpolate per-vert data*/
+ for (s = 0; s < numVerts; s++) {
+ for (y = 1; y < gridFaces; y++) {
+ for (x = 1; x < gridFaces; x++) {
+ w2 = w + s * numVerts * g2_wid * g2_wid + (y * g2_wid + x) * numVerts;
+ DM_interp_vert_data(dm, &ccgdm->dm, vertidx, w2, numVerts, vertNum);
+
+ if (vertOrigIndex) {
+ *vertOrigIndex = ORIGINDEX_NONE;
+ vertOrigIndex++;
+ }
+
+ vertNum++;
+ }
+ }
+ }
+
+ if (edgeOrigIndex) {
+ for (i = 0; i < numFinalEdges; ++i) {
+ edgeOrigIndex[edgeNum + i] = ORIGINDEX_NONE;
+ }
+ }
+
+ for (s = 0; s < numVerts; s++) {
+ /*interpolate per-face data*/
+ for (y = 0; y < gridFaces; y++) {
+ for (x = 0; x < gridFaces; x++) {
+ w2 = w + s * numVerts * g2_wid * g2_wid + (y * g2_wid + x) * numVerts;
+ CustomData_interp(
+ &dm->loopData, &ccgdm->dm.loopData, loopidx, w2, NULL, numVerts, loopindex2);
+ loopindex2++;
+
+ w2 = w + s * numVerts * g2_wid * g2_wid + ((y + 1) * g2_wid + (x)) * numVerts;
+ CustomData_interp(
+ &dm->loopData, &ccgdm->dm.loopData, loopidx, w2, NULL, numVerts, loopindex2);
+ loopindex2++;
+
+ w2 = w + s * numVerts * g2_wid * g2_wid + ((y + 1) * g2_wid + (x + 1)) * numVerts;
+ CustomData_interp(
+ &dm->loopData, &ccgdm->dm.loopData, loopidx, w2, NULL, numVerts, loopindex2);
+ loopindex2++;
+
+ w2 = w + s * numVerts * g2_wid * g2_wid + ((y)*g2_wid + (x + 1)) * numVerts;
+ CustomData_interp(
+ &dm->loopData, &ccgdm->dm.loopData, loopidx, w2, NULL, numVerts, loopindex2);
+ loopindex2++;
+
+ /*copy over poly data, e.g. mtexpoly*/
+ CustomData_copy_data(&dm->polyData, &ccgdm->dm.polyData, origIndex, faceNum, 1);
+
+ /*set original index data*/
+ if (faceOrigIndex) {
+ /* reference the index in 'polyOrigIndex' */
+ *faceOrigIndex = faceNum;
+ faceOrigIndex++;
+ }
+ if (polyOrigIndex) {
+ *polyOrigIndex = base_polyOrigIndex ? base_polyOrigIndex[origIndex] : origIndex;
+ polyOrigIndex++;
+ }
+
+ ccgdm->reverseFaceMap[faceNum] = index;
+
+ /* This is a simple one to one mapping, here... */
+ if (polyidx) {
+ polyidx[faceNum] = faceNum;
+ }
+
+ faceNum++;
+ }
+ }
+ }
+
+ edgeNum += numFinalEdges;
+ }
+
+ for (index = 0; index < totedge; ++index) {
+ CCGEdge *e = ccgdm->edgeMap[index].edge;
+ int numFinalEdges = edgeSize - 1;
+ int mapIndex = ccgDM_getEdgeMapIndex(ss, e);
+ int x;
+ int vertIdx[2];
+ int edgeIdx = POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(e));
+
+ CCGVert *v;
+ v = ccgSubSurf_getEdgeVert0(e);
+ vertIdx[0] = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(v));
+ v = ccgSubSurf_getEdgeVert1(e);
+ vertIdx[1] = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(v));
+
+ ccgdm->edgeMap[index].startVert = vertNum;
+ ccgdm->edgeMap[index].startEdge = edgeNum;
+
+ if (edgeIdx >= 0 && edgeFlags)
+ edgeFlags[edgeIdx] = medge[edgeIdx].flag;
+
+ /* set the edge base vert */
+ *((int *)ccgSubSurf_getEdgeUserData(ss, e)) = vertNum;
+
+ for (x = 1; x < edgeSize - 1; x++) {
+ float w[2];
+ w[1] = (float)x / (edgeSize - 1);
+ w[0] = 1 - w[1];
+ DM_interp_vert_data(dm, &ccgdm->dm, vertIdx, w, 2, vertNum);
+ if (vertOrigIndex) {
+ *vertOrigIndex = ORIGINDEX_NONE;
+ vertOrigIndex++;
+ }
+ vertNum++;
+ }
+
+ if (has_edge_cd) {
+ BLI_assert(edgeIdx >= 0 && edgeIdx < dm->getNumEdges(dm));
+ for (i = 0; i < numFinalEdges; ++i) {
+ CustomData_copy_data(&dm->edgeData, &ccgdm->dm.edgeData, edgeIdx, edgeNum + i, 1);
+ }
+ }
+
+ if (edgeOrigIndex) {
+ for (i = 0; i < numFinalEdges; ++i) {
+ edgeOrigIndex[edgeNum + i] = mapIndex;
+ }
+ }
+
+ edgeNum += numFinalEdges;
+ }
+
+ if (useSubsurfUv) {
+ CustomData *ldata = &ccgdm->dm.loopData;
+ CustomData *dmldata = &dm->loopData;
+ int numlayer = CustomData_number_of_layers(ldata, CD_MLOOPUV);
+ int dmnumlayer = CustomData_number_of_layers(dmldata, CD_MLOOPUV);
+
+ for (i = 0; i < numlayer && i < dmnumlayer; i++)
+ set_subsurf_uv(ss, dm, &ccgdm->dm, i);
+ }
+
+ for (index = 0; index < totvert; ++index) {
+ CCGVert *v = ccgdm->vertMap[index].vert;
+ int mapIndex = ccgDM_getVertMapIndex(ccgdm->ss, v);
+ int vertIdx;
+
+ vertIdx = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(v));
+
+ ccgdm->vertMap[index].startVert = vertNum;
+
+ /* set the vert base vert */
+ *((int *)ccgSubSurf_getVertUserData(ss, v)) = vertNum;
+
+ DM_copy_vert_data(dm, &ccgdm->dm, vertIdx, vertNum, 1);
+
+ if (vertOrigIndex) {
+ *vertOrigIndex = mapIndex;
+ vertOrigIndex++;
+ }
+ vertNum++;
+ }
#ifndef USE_DYNSIZE
- BLI_array_free(vertidx);
- BLI_array_free(loopidx);
+ BLI_array_free(vertidx);
+ BLI_array_free(loopidx);
#endif
- free_ss_weights(&wtable);
-
- BLI_assert(vertNum == ccgSubSurf_getNumFinalVerts(ss));
- BLI_assert(edgeNum == ccgSubSurf_getNumFinalEdges(ss));
- BLI_assert(loopindex2 == ccgSubSurf_getNumFinalFaces(ss) * 4);
- BLI_assert(faceNum == ccgSubSurf_getNumFinalFaces(ss));
+ free_ss_weights(&wtable);
+ BLI_assert(vertNum == ccgSubSurf_getNumFinalVerts(ss));
+ BLI_assert(edgeNum == ccgSubSurf_getNumFinalEdges(ss));
+ BLI_assert(loopindex2 == ccgSubSurf_getNumFinalFaces(ss) * 4);
+ BLI_assert(faceNum == ccgSubSurf_getNumFinalFaces(ss));
}
/* Fill in only geometry arrays needed for the GPU tessellation. */
static void set_ccgdm_gpu_geometry(CCGDerivedMesh *ccgdm, DerivedMesh *dm)
{
- const int totface = dm->getNumPolys(dm);
- MPoly *mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
- int index;
- DMFlagMat *faceFlags = ccgdm->faceFlags;
+ const int totface = dm->getNumPolys(dm);
+ MPoly *mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
+ int index;
+ DMFlagMat *faceFlags = ccgdm->faceFlags;
- for (index = 0; index < totface; index++) {
- faceFlags->flag = mpoly ? mpoly[index].flag : 0;
- faceFlags->mat_nr = mpoly ? mpoly[index].mat_nr : 0;
- faceFlags++;
- }
+ for (index = 0; index < totface; index++) {
+ faceFlags->flag = mpoly ? mpoly[index].flag : 0;
+ faceFlags->mat_nr = mpoly ? mpoly[index].mat_nr : 0;
+ faceFlags++;
+ }
- /* TODO(sergey): Fill in edge flags. */
+ /* TODO(sergey): Fill in edge flags. */
}
-static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
- int drawInteriorEdges,
- int useSubsurfUv,
- DerivedMesh *dm,
- bool use_gpu_backend)
+static CCGDerivedMesh *getCCGDerivedMesh(
+ CCGSubSurf *ss, int drawInteriorEdges, int useSubsurfUv, DerivedMesh *dm, bool use_gpu_backend)
{
#ifdef WITH_OPENSUBDIV
- const int totedge = dm->getNumEdges(dm);
- const int totface = dm->getNumPolys(dm);
+ const int totedge = dm->getNumEdges(dm);
+ const int totface = dm->getNumPolys(dm);
#else
- const int totedge = ccgSubSurf_getNumEdges(ss);
- const int totface = ccgSubSurf_getNumFaces(ss);
+ const int totedge = ccgSubSurf_getNumEdges(ss);
+ const int totface = ccgSubSurf_getNumFaces(ss);
#endif
- CCGDerivedMesh *ccgdm = MEM_callocN(sizeof(*ccgdm), "ccgdm");
-
- if (use_gpu_backend == false) {
- BLI_assert(totedge == ccgSubSurf_getNumEdges(ss));
- BLI_assert(totface == ccgSubSurf_getNumFaces(ss));
- DM_from_template(&ccgdm->dm, dm, DM_TYPE_CCGDM,
- ccgSubSurf_getNumFinalVerts(ss),
- ccgSubSurf_getNumFinalEdges(ss),
- 0,
- ccgSubSurf_getNumFinalFaces(ss) * 4,
- ccgSubSurf_getNumFinalFaces(ss));
-
- CustomData_free_layer_active(&ccgdm->dm.polyData, CD_NORMAL,
- ccgdm->dm.numPolyData);
-
- ccgdm->reverseFaceMap =
- MEM_callocN(sizeof(int) * ccgSubSurf_getNumFinalFaces(ss),
- "reverseFaceMap");
-
- create_ccgdm_maps(ccgdm, ss);
- }
- else {
- DM_from_template(&ccgdm->dm, dm, DM_TYPE_CCGDM,
- 0, 0, 0, 0, dm->getNumPolys(dm));
- CustomData_copy_data(&dm->polyData,
- &ccgdm->dm.polyData,
- 0, 0, dm->getNumPolys(dm));
- }
-
- set_default_ccgdm_callbacks(ccgdm);
-
- ccgdm->ss = ss;
- ccgdm->drawInteriorEdges = drawInteriorEdges;
- ccgdm->useSubsurfUv = useSubsurfUv;
- ccgdm->useGpuBackend = use_gpu_backend;
-
- /* CDDM hack. */
- ccgdm->edgeFlags = MEM_callocN(sizeof(short) * totedge, "edgeFlags");
- ccgdm->faceFlags = MEM_callocN(sizeof(DMFlagMat) * totface, "faceFlags");
-
- if (use_gpu_backend == false) {
- set_ccgdm_all_geometry(ccgdm, ss, dm, useSubsurfUv != 0);
- }
- else {
- set_ccgdm_gpu_geometry(ccgdm, dm);
- }
-
- ccgdm->dm.numVertData = ccgSubSurf_getNumFinalVerts(ss);
- ccgdm->dm.numEdgeData = ccgSubSurf_getNumFinalEdges(ss);
- ccgdm->dm.numPolyData = ccgSubSurf_getNumFinalFaces(ss);
- ccgdm->dm.numLoopData = ccgdm->dm.numPolyData * 4;
- ccgdm->dm.numTessFaceData = 0;
-
- BLI_mutex_init(&ccgdm->loops_cache_lock);
- BLI_rw_mutex_init(&ccgdm->origindex_cache_rwlock);
-
- return ccgdm;
+ CCGDerivedMesh *ccgdm = MEM_callocN(sizeof(*ccgdm), "ccgdm");
+
+ if (use_gpu_backend == false) {
+ BLI_assert(totedge == ccgSubSurf_getNumEdges(ss));
+ BLI_assert(totface == ccgSubSurf_getNumFaces(ss));
+ DM_from_template(&ccgdm->dm,
+ dm,
+ DM_TYPE_CCGDM,
+ ccgSubSurf_getNumFinalVerts(ss),
+ ccgSubSurf_getNumFinalEdges(ss),
+ 0,
+ ccgSubSurf_getNumFinalFaces(ss) * 4,
+ ccgSubSurf_getNumFinalFaces(ss));
+
+ CustomData_free_layer_active(&ccgdm->dm.polyData, CD_NORMAL, ccgdm->dm.numPolyData);
+
+ ccgdm->reverseFaceMap = MEM_callocN(sizeof(int) * ccgSubSurf_getNumFinalFaces(ss),
+ "reverseFaceMap");
+
+ create_ccgdm_maps(ccgdm, ss);
+ }
+ else {
+ DM_from_template(&ccgdm->dm, dm, DM_TYPE_CCGDM, 0, 0, 0, 0, dm->getNumPolys(dm));
+ CustomData_copy_data(&dm->polyData, &ccgdm->dm.polyData, 0, 0, dm->getNumPolys(dm));
+ }
+
+ set_default_ccgdm_callbacks(ccgdm);
+
+ ccgdm->ss = ss;
+ ccgdm->drawInteriorEdges = drawInteriorEdges;
+ ccgdm->useSubsurfUv = useSubsurfUv;
+ ccgdm->useGpuBackend = use_gpu_backend;
+
+ /* CDDM hack. */
+ ccgdm->edgeFlags = MEM_callocN(sizeof(short) * totedge, "edgeFlags");
+ ccgdm->faceFlags = MEM_callocN(sizeof(DMFlagMat) * totface, "faceFlags");
+
+ if (use_gpu_backend == false) {
+ set_ccgdm_all_geometry(ccgdm, ss, dm, useSubsurfUv != 0);
+ }
+ else {
+ set_ccgdm_gpu_geometry(ccgdm, dm);
+ }
+
+ ccgdm->dm.numVertData = ccgSubSurf_getNumFinalVerts(ss);
+ ccgdm->dm.numEdgeData = ccgSubSurf_getNumFinalEdges(ss);
+ ccgdm->dm.numPolyData = ccgSubSurf_getNumFinalFaces(ss);
+ ccgdm->dm.numLoopData = ccgdm->dm.numPolyData * 4;
+ ccgdm->dm.numTessFaceData = 0;
+
+ BLI_mutex_init(&ccgdm->loops_cache_lock);
+ BLI_rw_mutex_init(&ccgdm->origindex_cache_rwlock);
+
+ return ccgdm;
}
/***/
@@ -2847,231 +2857,225 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
static bool subsurf_use_gpu_backend(SubsurfFlags flags)
{
#ifdef WITH_OPENSUBDIV
- /* Use GPU backend if it's a last modifier in the stack
- * and user chose to use any of the OSD compute devices,
- * but also check if GPU has all needed features.
- */
- return
- (flags & SUBSURF_USE_GPU_BACKEND) != 0 &&
- (U.opensubdiv_compute_type != USER_OPENSUBDIV_COMPUTE_NONE);
+ /* Use GPU backend if it's a last modifier in the stack
+ * and user chose to use any of the OSD compute devices,
+ * but also check if GPU has all needed features.
+ */
+ return (flags & SUBSURF_USE_GPU_BACKEND) != 0 &&
+ (U.opensubdiv_compute_type != USER_OPENSUBDIV_COMPUTE_NONE);
#else
- (void)flags;
- return false;
+ (void)flags;
+ return false;
#endif
}
-struct DerivedMesh *subsurf_make_derived_from_derived(
- struct DerivedMesh *dm,
- struct SubsurfModifierData *smd,
- struct Scene *scene,
- float (*vertCos)[3],
- SubsurfFlags flags)
-{
- const int useSimple = (smd->subdivType == ME_SIMPLE_SUBSURF) ? CCG_SIMPLE_SUBDIV : 0;
- const CCGFlags useAging = (smd->flags & eSubsurfModifierFlag_DebugIncr) ? CCG_USE_AGING : 0;
- const int useSubsurfUv = (smd->uv_smooth != SUBSURF_UV_SMOOTH_NONE);
- const int drawInteriorEdges = !(smd->flags & eSubsurfModifierFlag_ControlEdges);
- const bool use_gpu_backend = subsurf_use_gpu_backend(flags);
- const bool ignore_simplify = (flags & SUBSURF_IGNORE_SIMPLIFY);
- CCGDerivedMesh *result;
-
- /* note: editmode calculation can only run once per
- * modifier stack evaluation (uses freed cache) [#36299] */
- if (flags & SUBSURF_FOR_EDIT_MODE) {
- int levels = (scene != NULL && !ignore_simplify)
- ? get_render_subsurf_level(&scene->r, smd->levels, false)
- : smd->levels;
-
- /* TODO(sergey): Same as emCache below. */
- if ((flags & SUBSURF_IN_EDIT_MODE) && smd->mCache) {
- ccgSubSurf_free(smd->mCache);
- smd->mCache = NULL;
- }
-
- smd->emCache = _getSubSurf(smd->emCache, levels, 3, useSimple | useAging | CCG_CALC_NORMALS);
+struct DerivedMesh *subsurf_make_derived_from_derived(struct DerivedMesh *dm,
+ struct SubsurfModifierData *smd,
+ struct Scene *scene,
+ float (*vertCos)[3],
+ SubsurfFlags flags)
+{
+ const int useSimple = (smd->subdivType == ME_SIMPLE_SUBSURF) ? CCG_SIMPLE_SUBDIV : 0;
+ const CCGFlags useAging = (smd->flags & eSubsurfModifierFlag_DebugIncr) ? CCG_USE_AGING : 0;
+ const int useSubsurfUv = (smd->uv_smooth != SUBSURF_UV_SMOOTH_NONE);
+ const int drawInteriorEdges = !(smd->flags & eSubsurfModifierFlag_ControlEdges);
+ const bool use_gpu_backend = subsurf_use_gpu_backend(flags);
+ const bool ignore_simplify = (flags & SUBSURF_IGNORE_SIMPLIFY);
+ CCGDerivedMesh *result;
+
+ /* note: editmode calculation can only run once per
+ * modifier stack evaluation (uses freed cache) [#36299] */
+ if (flags & SUBSURF_FOR_EDIT_MODE) {
+ int levels = (scene != NULL && !ignore_simplify) ?
+ get_render_subsurf_level(&scene->r, smd->levels, false) :
+ smd->levels;
+
+ /* TODO(sergey): Same as emCache below. */
+ if ((flags & SUBSURF_IN_EDIT_MODE) && smd->mCache) {
+ ccgSubSurf_free(smd->mCache);
+ smd->mCache = NULL;
+ }
+
+ smd->emCache = _getSubSurf(smd->emCache, levels, 3, useSimple | useAging | CCG_CALC_NORMALS);
#ifdef WITH_OPENSUBDIV
- ccgSubSurf_setSkipGrids(smd->emCache, use_gpu_backend);
+ ccgSubSurf_setSkipGrids(smd->emCache, use_gpu_backend);
#endif
- ss_sync_from_derivedmesh(smd->emCache, dm, vertCos, useSimple, useSubsurfUv);
- result = getCCGDerivedMesh(smd->emCache,
- drawInteriorEdges,
- useSubsurfUv, dm, use_gpu_backend);
- }
- else if (flags & SUBSURF_USE_RENDER_PARAMS) {
- /* Do not use cache in render mode. */
- CCGSubSurf *ss;
- int levels = (scene != NULL && !ignore_simplify)
- ? get_render_subsurf_level(&scene->r, smd->renderLevels, true)
- : smd->renderLevels;
-
- if (levels == 0)
- return dm;
-
- ss = _getSubSurf(NULL, levels, 3, useSimple | CCG_USE_ARENA | CCG_CALC_NORMALS);
-
- ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple, useSubsurfUv);
-
- result = getCCGDerivedMesh(ss,
- drawInteriorEdges, useSubsurfUv, dm, false);
-
- result->freeSS = 1;
- }
- else {
- int useIncremental = (smd->flags & eSubsurfModifierFlag_Incremental);
- int levels = (scene != NULL && !ignore_simplify)
- ? get_render_subsurf_level(&scene->r, smd->levels, false)
- : smd->levels;
- CCGSubSurf *ss;
-
- /* It is quite possible there is a much better place to do this. It
- * depends a bit on how rigorously we expect this function to never
- * be called in editmode. In semi-theory we could share a single
- * cache, but the handles used inside and outside editmode are not
- * the same so we would need some way of converting them. Its probably
- * not worth the effort. But then why am I even writing this long
- * comment that no one will read? Hmmm. - zr
- *
- * Addendum: we can't really ensure that this is never called in edit
- * mode, so now we have a parameter to verify it. - brecht
- */
- if (!(flags & SUBSURF_IN_EDIT_MODE) && smd->emCache) {
- ccgSubSurf_free(smd->emCache);
- smd->emCache = NULL;
- }
-
- if (useIncremental && (flags & SUBSURF_IS_FINAL_CALC)) {
- smd->mCache = ss = _getSubSurf(smd->mCache, levels, 3, useSimple | useAging | CCG_CALC_NORMALS);
-
- ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple, useSubsurfUv);
-
- result = getCCGDerivedMesh(smd->mCache,
- drawInteriorEdges,
- useSubsurfUv, dm, false);
- }
- else {
- CCGFlags ccg_flags = useSimple | CCG_USE_ARENA | CCG_CALC_NORMALS;
- CCGSubSurf *prevSS = NULL;
-
- if (smd->mCache && (flags & SUBSURF_IS_FINAL_CALC)) {
+ ss_sync_from_derivedmesh(smd->emCache, dm, vertCos, useSimple, useSubsurfUv);
+ result = getCCGDerivedMesh(smd->emCache, drawInteriorEdges, useSubsurfUv, dm, use_gpu_backend);
+ }
+ else if (flags & SUBSURF_USE_RENDER_PARAMS) {
+ /* Do not use cache in render mode. */
+ CCGSubSurf *ss;
+ int levels = (scene != NULL && !ignore_simplify) ?
+ get_render_subsurf_level(&scene->r, smd->renderLevels, true) :
+ smd->renderLevels;
+
+ if (levels == 0)
+ return dm;
+
+ ss = _getSubSurf(NULL, levels, 3, useSimple | CCG_USE_ARENA | CCG_CALC_NORMALS);
+
+ ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple, useSubsurfUv);
+
+ result = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm, false);
+
+ result->freeSS = 1;
+ }
+ else {
+ int useIncremental = (smd->flags & eSubsurfModifierFlag_Incremental);
+ int levels = (scene != NULL && !ignore_simplify) ?
+ get_render_subsurf_level(&scene->r, smd->levels, false) :
+ smd->levels;
+ CCGSubSurf *ss;
+
+ /* It is quite possible there is a much better place to do this. It
+ * depends a bit on how rigorously we expect this function to never
+ * be called in editmode. In semi-theory we could share a single
+ * cache, but the handles used inside and outside editmode are not
+ * the same so we would need some way of converting them. Its probably
+ * not worth the effort. But then why am I even writing this long
+ * comment that no one will read? Hmmm. - zr
+ *
+ * Addendum: we can't really ensure that this is never called in edit
+ * mode, so now we have a parameter to verify it. - brecht
+ */
+ if (!(flags & SUBSURF_IN_EDIT_MODE) && smd->emCache) {
+ ccgSubSurf_free(smd->emCache);
+ smd->emCache = NULL;
+ }
+
+ if (useIncremental && (flags & SUBSURF_IS_FINAL_CALC)) {
+ smd->mCache = ss = _getSubSurf(
+ smd->mCache, levels, 3, useSimple | useAging | CCG_CALC_NORMALS);
+
+ ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple, useSubsurfUv);
+
+ result = getCCGDerivedMesh(smd->mCache, drawInteriorEdges, useSubsurfUv, dm, false);
+ }
+ else {
+ CCGFlags ccg_flags = useSimple | CCG_USE_ARENA | CCG_CALC_NORMALS;
+ CCGSubSurf *prevSS = NULL;
+
+ if (smd->mCache && (flags & SUBSURF_IS_FINAL_CALC)) {
#ifdef WITH_OPENSUBDIV
- /* With OpenSubdiv enabled we always tries to re-use previous
- * subsurf structure in order to save computation time since
- * re-creation is rather a complicated business.
- *
- * TODO(sergey): There was a good eason why final calculation
- * used to free entirely cached subsurf structure. reason of
- * this is to be investigated still to be sure we don't have
- * regressions here.
- */
- if (use_gpu_backend) {
- prevSS = smd->mCache;
- }
- else
+ /* With OpenSubdiv enabled we always tries to re-use previous
+ * subsurf structure in order to save computation time since
+ * re-creation is rather a complicated business.
+ *
+ * TODO(sergey): There was a good eason why final calculation
+ * used to free entirely cached subsurf structure. reason of
+ * this is to be investigated still to be sure we don't have
+ * regressions here.
+ */
+ if (use_gpu_backend) {
+ prevSS = smd->mCache;
+ }
+ else
#endif
- {
- ccgSubSurf_free(smd->mCache);
- smd->mCache = NULL;
- }
- }
-
+ {
+ ccgSubSurf_free(smd->mCache);
+ smd->mCache = NULL;
+ }
+ }
- if (flags & SUBSURF_ALLOC_PAINT_MASK)
- ccg_flags |= CCG_ALLOC_MASK;
+ if (flags & SUBSURF_ALLOC_PAINT_MASK)
+ ccg_flags |= CCG_ALLOC_MASK;
- ss = _getSubSurf(prevSS, levels, 3, ccg_flags);
+ ss = _getSubSurf(prevSS, levels, 3, ccg_flags);
#ifdef WITH_OPENSUBDIV
- ccgSubSurf_setSkipGrids(ss, use_gpu_backend);
+ ccgSubSurf_setSkipGrids(ss, use_gpu_backend);
#endif
- ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple, useSubsurfUv);
+ ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple, useSubsurfUv);
- result = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm, use_gpu_backend);
+ result = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm, use_gpu_backend);
- if (flags & SUBSURF_IS_FINAL_CALC)
- smd->mCache = ss;
- else
- result->freeSS = 1;
+ if (flags & SUBSURF_IS_FINAL_CALC)
+ smd->mCache = ss;
+ else
+ result->freeSS = 1;
- if (flags & SUBSURF_ALLOC_PAINT_MASK)
- ccgSubSurf_setNumLayers(ss, 4);
- }
- }
+ if (flags & SUBSURF_ALLOC_PAINT_MASK)
+ ccgSubSurf_setNumLayers(ss, 4);
+ }
+ }
- return (DerivedMesh *)result;
+ return (DerivedMesh *)result;
}
void subsurf_calculate_limit_positions(Mesh *me, float (*r_positions)[3])
{
- /* Finds the subsurf limit positions for the verts in a mesh
- * and puts them in an array of floats. Please note that the
- * calculated vert positions is incorrect for the verts
- * on the boundary of the mesh.
- */
- CCGSubSurf *ss = _getSubSurf(NULL, 1, 3, CCG_USE_ARENA);
- float edge_sum[3], face_sum[3];
- CCGVertIterator vi;
- DerivedMesh *dm = CDDM_from_mesh(me);
-
- ss_sync_from_derivedmesh(ss, dm, NULL, 0, 0);
-
- for (ccgSubSurf_initVertIterator(ss, &vi); !ccgVertIterator_isStopped(&vi); ccgVertIterator_next(&vi)) {
- CCGVert *v = ccgVertIterator_getCurrent(&vi);
- int idx = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(v));
- int N = ccgSubSurf_getVertNumEdges(v);
- int numFaces = ccgSubSurf_getVertNumFaces(v);
- float *co;
- int i;
-
- zero_v3(edge_sum);
- zero_v3(face_sum);
-
- for (i = 0; i < N; i++) {
- CCGEdge *e = ccgSubSurf_getVertEdge(v, i);
- add_v3_v3v3(edge_sum, edge_sum, ccgSubSurf_getEdgeData(ss, e, 1));
- }
- for (i = 0; i < numFaces; i++) {
- CCGFace *f = ccgSubSurf_getVertFace(v, i);
- add_v3_v3(face_sum, ccgSubSurf_getFaceCenterData(f));
- }
-
- /* ad-hoc correction for boundary vertices, to at least avoid them
- * moving completely out of place (brecht) */
- if (numFaces && numFaces != N)
- mul_v3_fl(face_sum, (float)N / (float)numFaces);
-
- co = ccgSubSurf_getVertData(ss, v);
- r_positions[idx][0] = (co[0] * N * N + edge_sum[0] * 4 + face_sum[0]) / (N * (N + 5));
- r_positions[idx][1] = (co[1] * N * N + edge_sum[1] * 4 + face_sum[1]) / (N * (N + 5));
- r_positions[idx][2] = (co[2] * N * N + edge_sum[2] * 4 + face_sum[2]) / (N * (N + 5));
- }
-
- ccgSubSurf_free(ss);
-
- dm->release(dm);
+ /* Finds the subsurf limit positions for the verts in a mesh
+ * and puts them in an array of floats. Please note that the
+ * calculated vert positions is incorrect for the verts
+ * on the boundary of the mesh.
+ */
+ CCGSubSurf *ss = _getSubSurf(NULL, 1, 3, CCG_USE_ARENA);
+ float edge_sum[3], face_sum[3];
+ CCGVertIterator vi;
+ DerivedMesh *dm = CDDM_from_mesh(me);
+
+ ss_sync_from_derivedmesh(ss, dm, NULL, 0, 0);
+
+ for (ccgSubSurf_initVertIterator(ss, &vi); !ccgVertIterator_isStopped(&vi);
+ ccgVertIterator_next(&vi)) {
+ CCGVert *v = ccgVertIterator_getCurrent(&vi);
+ int idx = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(v));
+ int N = ccgSubSurf_getVertNumEdges(v);
+ int numFaces = ccgSubSurf_getVertNumFaces(v);
+ float *co;
+ int i;
+
+ zero_v3(edge_sum);
+ zero_v3(face_sum);
+
+ for (i = 0; i < N; i++) {
+ CCGEdge *e = ccgSubSurf_getVertEdge(v, i);
+ add_v3_v3v3(edge_sum, edge_sum, ccgSubSurf_getEdgeData(ss, e, 1));
+ }
+ for (i = 0; i < numFaces; i++) {
+ CCGFace *f = ccgSubSurf_getVertFace(v, i);
+ add_v3_v3(face_sum, ccgSubSurf_getFaceCenterData(f));
+ }
+
+ /* ad-hoc correction for boundary vertices, to at least avoid them
+ * moving completely out of place (brecht) */
+ if (numFaces && numFaces != N)
+ mul_v3_fl(face_sum, (float)N / (float)numFaces);
+
+ co = ccgSubSurf_getVertData(ss, v);
+ r_positions[idx][0] = (co[0] * N * N + edge_sum[0] * 4 + face_sum[0]) / (N * (N + 5));
+ r_positions[idx][1] = (co[1] * N * N + edge_sum[1] * 4 + face_sum[1]) / (N * (N + 5));
+ r_positions[idx][2] = (co[2] * N * N + edge_sum[2] * 4 + face_sum[2]) / (N * (N + 5));
+ }
+
+ ccgSubSurf_free(ss);
+
+ dm->release(dm);
}
bool subsurf_has_edges(DerivedMesh *dm)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
#ifdef WITH_OPENSUBDIV
- if (ccgdm->useGpuBackend) {
- return true;
- }
+ if (ccgdm->useGpuBackend) {
+ return true;
+ }
#else
- (void)ccgdm;
+ (void)ccgdm;
#endif
- return dm->getNumEdges(dm) != 0;
+ return dm->getNumEdges(dm) != 0;
}
bool subsurf_has_faces(DerivedMesh *dm)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
#ifdef WITH_OPENSUBDIV
- if (ccgdm->useGpuBackend) {
- return true;
- }
+ if (ccgdm->useGpuBackend) {
+ return true;
+ }
#else
- (void)ccgdm;
+ (void)ccgdm;
#endif
- return dm->getNumPolys(dm) != 0;
+ return dm->getNumPolys(dm) != 0;
}
diff --git a/source/blender/blenkernel/intern/suggestions.c b/source/blender/blenkernel/intern/suggestions.c
index f3f919d0048..7631afaa680 100644
--- a/source/blender/blenkernel/intern/suggestions.c
+++ b/source/blender/blenkernel/intern/suggestions.c
@@ -21,7 +21,6 @@
* \ingroup bke
*/
-
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
@@ -44,23 +43,23 @@ static char *documentation = NULL;
static void txttl_free_suggest(void)
{
- SuggItem *item, *prev;
- for (item = suggestions.last; item; item = prev) {
- prev = item->prev;
- MEM_freeN(item);
- }
- suggestions.first = suggestions.last = NULL;
- suggestions.firstmatch = suggestions.lastmatch = NULL;
- suggestions.selected = NULL;
- suggestions.top = 0;
+ SuggItem *item, *prev;
+ for (item = suggestions.last; item; item = prev) {
+ prev = item->prev;
+ MEM_freeN(item);
+ }
+ suggestions.first = suggestions.last = NULL;
+ suggestions.firstmatch = suggestions.lastmatch = NULL;
+ suggestions.selected = NULL;
+ suggestions.top = 0;
}
static void txttl_free_docs(void)
{
- if (documentation) {
- MEM_freeN(documentation);
- documentation = NULL;
- }
+ if (documentation) {
+ MEM_freeN(documentation);
+ documentation = NULL;
+ }
}
/**************************/
@@ -69,26 +68,27 @@ static void txttl_free_docs(void)
void free_texttools(void)
{
- txttl_free_suggest();
- txttl_free_docs();
+ txttl_free_suggest();
+ txttl_free_docs();
}
void texttool_text_set_active(Text *text)
{
- if (activeToolText == text) return;
- texttool_text_clear();
- activeToolText = text;
+ if (activeToolText == text)
+ return;
+ texttool_text_clear();
+ activeToolText = text;
}
void texttool_text_clear(void)
{
- free_texttools();
- activeToolText = NULL;
+ free_texttools();
+ activeToolText = NULL;
}
short texttool_text_is_active(Text *text)
{
- return activeToolText == text ? 1 : 0;
+ return activeToolText == text ? 1 : 0;
}
/***************************/
@@ -97,125 +97,127 @@ short texttool_text_is_active(Text *text)
void texttool_suggest_add(const char *name, char type)
{
- const int len = strlen(name);
- int cmp;
- SuggItem *newitem, *item;
-
- newitem = MEM_mallocN(sizeof(SuggItem) + len + 1, "SuggItem");
- if (!newitem) {
- printf("Failed to allocate memory for suggestion.\n");
- return;
- }
-
- memcpy(newitem->name, name, len + 1);
- newitem->type = type;
- newitem->prev = newitem->next = NULL;
-
- /* Perform simple linear search for ordered storage */
- if (!suggestions.first || !suggestions.last) {
- suggestions.first = suggestions.last = newitem;
- }
- else {
- cmp = -1;
- for (item = suggestions.last; item; item = item->prev) {
- cmp = BLI_strncasecmp(name, item->name, len);
-
- /* Newitem comes after this item, insert here */
- if (cmp >= 0) {
- newitem->prev = item;
- if (item->next)
- item->next->prev = newitem;
- newitem->next = item->next;
- item->next = newitem;
-
- /* At last item, set last pointer here */
- if (item == suggestions.last)
- suggestions.last = newitem;
- break;
- }
- }
- /* Reached beginning of list, insert before first */
- if (cmp < 0) {
- newitem->next = suggestions.first;
- suggestions.first->prev = newitem;
- suggestions.first = newitem;
- }
- }
- suggestions.firstmatch = suggestions.lastmatch = suggestions.selected = NULL;
- suggestions.top = 0;
+ const int len = strlen(name);
+ int cmp;
+ SuggItem *newitem, *item;
+
+ newitem = MEM_mallocN(sizeof(SuggItem) + len + 1, "SuggItem");
+ if (!newitem) {
+ printf("Failed to allocate memory for suggestion.\n");
+ return;
+ }
+
+ memcpy(newitem->name, name, len + 1);
+ newitem->type = type;
+ newitem->prev = newitem->next = NULL;
+
+ /* Perform simple linear search for ordered storage */
+ if (!suggestions.first || !suggestions.last) {
+ suggestions.first = suggestions.last = newitem;
+ }
+ else {
+ cmp = -1;
+ for (item = suggestions.last; item; item = item->prev) {
+ cmp = BLI_strncasecmp(name, item->name, len);
+
+ /* Newitem comes after this item, insert here */
+ if (cmp >= 0) {
+ newitem->prev = item;
+ if (item->next)
+ item->next->prev = newitem;
+ newitem->next = item->next;
+ item->next = newitem;
+
+ /* At last item, set last pointer here */
+ if (item == suggestions.last)
+ suggestions.last = newitem;
+ break;
+ }
+ }
+ /* Reached beginning of list, insert before first */
+ if (cmp < 0) {
+ newitem->next = suggestions.first;
+ suggestions.first->prev = newitem;
+ suggestions.first = newitem;
+ }
+ }
+ suggestions.firstmatch = suggestions.lastmatch = suggestions.selected = NULL;
+ suggestions.top = 0;
}
void texttool_suggest_prefix(const char *prefix, const int prefix_len)
{
- SuggItem *match, *first, *last;
- int cmp, top = 0;
-
- if (!suggestions.first) return;
- if (prefix_len == 0) {
- suggestions.selected = suggestions.firstmatch = suggestions.first;
- suggestions.lastmatch = suggestions.last;
- return;
- }
-
- first = last = NULL;
- for (match = suggestions.first; match; match = match->next) {
- cmp = BLI_strncasecmp(prefix, match->name, prefix_len);
- if (cmp == 0) {
- if (!first) {
- first = match;
- suggestions.top = top;
- }
- }
- else if (cmp < 0) {
- if (!last) {
- last = match->prev;
- break;
- }
- }
- top++;
- }
- if (first) {
- if (!last) last = suggestions.last;
- suggestions.firstmatch = first;
- suggestions.lastmatch = last;
- suggestions.selected = first;
- }
- else {
- suggestions.firstmatch = NULL;
- suggestions.lastmatch = NULL;
- suggestions.selected = NULL;
- suggestions.top = 0;
- }
+ SuggItem *match, *first, *last;
+ int cmp, top = 0;
+
+ if (!suggestions.first)
+ return;
+ if (prefix_len == 0) {
+ suggestions.selected = suggestions.firstmatch = suggestions.first;
+ suggestions.lastmatch = suggestions.last;
+ return;
+ }
+
+ first = last = NULL;
+ for (match = suggestions.first; match; match = match->next) {
+ cmp = BLI_strncasecmp(prefix, match->name, prefix_len);
+ if (cmp == 0) {
+ if (!first) {
+ first = match;
+ suggestions.top = top;
+ }
+ }
+ else if (cmp < 0) {
+ if (!last) {
+ last = match->prev;
+ break;
+ }
+ }
+ top++;
+ }
+ if (first) {
+ if (!last)
+ last = suggestions.last;
+ suggestions.firstmatch = first;
+ suggestions.lastmatch = last;
+ suggestions.selected = first;
+ }
+ else {
+ suggestions.firstmatch = NULL;
+ suggestions.lastmatch = NULL;
+ suggestions.selected = NULL;
+ suggestions.top = 0;
+ }
}
void texttool_suggest_clear(void)
{
- txttl_free_suggest();
+ txttl_free_suggest();
}
SuggItem *texttool_suggest_first(void)
{
- return suggestions.firstmatch;
+ return suggestions.firstmatch;
}
SuggItem *texttool_suggest_last(void)
{
- return suggestions.lastmatch;
+ return suggestions.lastmatch;
}
void texttool_suggest_select(SuggItem *sel)
{
- suggestions.selected = sel;
+ suggestions.selected = sel;
}
SuggItem *texttool_suggest_selected(void)
{
- return suggestions.selected;
+ return suggestions.selected;
}
int *texttool_suggest_top(void)
{
- return &suggestions.top;
+ return &suggestions.top;
}
/*************************/
@@ -224,36 +226,37 @@ int *texttool_suggest_top(void)
void texttool_docs_show(const char *docs)
{
- int len;
-
- if (!docs) return;
-
- len = strlen(docs);
-
- if (documentation) {
- MEM_freeN(documentation);
- documentation = NULL;
- }
-
- /* Ensure documentation ends with a '\n' */
- if (docs[len - 1] != '\n') {
- documentation = MEM_mallocN(len + 2, "Documentation");
- memcpy(documentation, docs, len);
- documentation[len++] = '\n';
- }
- else {
- documentation = MEM_mallocN(len + 1, "Documentation");
- memcpy(documentation, docs, len);
- }
- documentation[len] = '\0';
+ int len;
+
+ if (!docs)
+ return;
+
+ len = strlen(docs);
+
+ if (documentation) {
+ MEM_freeN(documentation);
+ documentation = NULL;
+ }
+
+ /* Ensure documentation ends with a '\n' */
+ if (docs[len - 1] != '\n') {
+ documentation = MEM_mallocN(len + 2, "Documentation");
+ memcpy(documentation, docs, len);
+ documentation[len++] = '\n';
+ }
+ else {
+ documentation = MEM_mallocN(len + 1, "Documentation");
+ memcpy(documentation, docs, len);
+ }
+ documentation[len] = '\0';
}
char *texttool_docs_get(void)
{
- return documentation;
+ return documentation;
}
void texttool_docs_clear(void)
{
- txttl_free_docs();
+ txttl_free_docs();
}
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index ef77f847d83..ef4b9d95324 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -53,9 +53,8 @@
#include "BKE_text.h"
#include "BKE_node.h"
-
#ifdef WITH_PYTHON
-#include "BPY_extern.h"
+# include "BPY_extern.h"
#endif
/*
@@ -108,47 +107,46 @@
* undo position
*/
-
/* Undo opcodes */
enum {
- /* Complex editing */
- /* 1 - opcode is followed by 1 byte for ascii character and opcode (repeat)) */
- /* 2 - opcode is followed by 2 bytes for utf-8 character and opcode (repeat)) */
- /* 3 - opcode is followed by 3 bytes for utf-8 character and opcode (repeat)) */
- /* 4 - opcode is followed by 4 bytes for unicode character and opcode (repeat)) */
- UNDO_INSERT_1 = 013,
- UNDO_INSERT_2 = 014,
- UNDO_INSERT_3 = 015,
- UNDO_INSERT_4 = 016,
-
- UNDO_BS_1 = 017,
- UNDO_BS_2 = 020,
- UNDO_BS_3 = 021,
- UNDO_BS_4 = 022,
-
- UNDO_DEL_1 = 023,
- UNDO_DEL_2 = 024,
- UNDO_DEL_3 = 025,
- UNDO_DEL_4 = 026,
-
- /* Text block (opcode is followed
- * by 4 character length ID + the text
- * block itself + the 4 character length
- * ID (repeat) and opcode (repeat)) */
- UNDO_DBLOCK = 027, /* Delete block */
- UNDO_IBLOCK = 030, /* Insert block */
-
- /* Misc */
- UNDO_INDENT = 032,
- UNDO_UNINDENT = 033,
- UNDO_COMMENT = 034,
- UNDO_UNCOMMENT = 035,
-
- UNDO_MOVE_LINES_UP = 036,
- UNDO_MOVE_LINES_DOWN = 037,
-
- UNDO_DUPLICATE = 040,
+ /* Complex editing */
+ /* 1 - opcode is followed by 1 byte for ascii character and opcode (repeat)) */
+ /* 2 - opcode is followed by 2 bytes for utf-8 character and opcode (repeat)) */
+ /* 3 - opcode is followed by 3 bytes for utf-8 character and opcode (repeat)) */
+ /* 4 - opcode is followed by 4 bytes for unicode character and opcode (repeat)) */
+ UNDO_INSERT_1 = 013,
+ UNDO_INSERT_2 = 014,
+ UNDO_INSERT_3 = 015,
+ UNDO_INSERT_4 = 016,
+
+ UNDO_BS_1 = 017,
+ UNDO_BS_2 = 020,
+ UNDO_BS_3 = 021,
+ UNDO_BS_4 = 022,
+
+ UNDO_DEL_1 = 023,
+ UNDO_DEL_2 = 024,
+ UNDO_DEL_3 = 025,
+ UNDO_DEL_4 = 026,
+
+ /* Text block (opcode is followed
+ * by 4 character length ID + the text
+ * block itself + the 4 character length
+ * ID (repeat) and opcode (repeat)) */
+ UNDO_DBLOCK = 027, /* Delete block */
+ UNDO_IBLOCK = 030, /* Insert block */
+
+ /* Misc */
+ UNDO_INDENT = 032,
+ UNDO_UNINDENT = 033,
+ UNDO_COMMENT = 034,
+ UNDO_UNCOMMENT = 035,
+
+ UNDO_MOVE_LINES_UP = 036,
+ UNDO_MOVE_LINES_DOWN = 037,
+
+ UNDO_DUPLICATE = 040,
};
/***/
@@ -174,116 +172,116 @@ static bool undoing;
*/
void BKE_text_free_lines(Text *text)
{
- for (TextLine *tmp = text->lines.first, *tmp_next; tmp; tmp = tmp_next) {
- tmp_next = tmp->next;
- MEM_freeN(tmp->line);
- if (tmp->format) {
- MEM_freeN(tmp->format);
- }
- MEM_freeN(tmp);
- }
+ for (TextLine *tmp = text->lines.first, *tmp_next; tmp; tmp = tmp_next) {
+ tmp_next = tmp->next;
+ MEM_freeN(tmp->line);
+ if (tmp->format) {
+ MEM_freeN(tmp->format);
+ }
+ MEM_freeN(tmp);
+ }
- BLI_listbase_clear(&text->lines);
+ BLI_listbase_clear(&text->lines);
- text->curl = text->sell = NULL;
+ text->curl = text->sell = NULL;
}
/** Free (or release) any data used by this text (does not free the text itself). */
void BKE_text_free(Text *text)
{
- /* No animdata here. */
+ /* No animdata here. */
- BKE_text_free_lines(text);
+ BKE_text_free_lines(text);
- MEM_SAFE_FREE(text->name);
+ MEM_SAFE_FREE(text->name);
#ifdef WITH_PYTHON
- BPY_text_free_code(text);
+ BPY_text_free_code(text);
#endif
}
void BKE_text_init(Text *ta)
{
- TextLine *tmp;
+ TextLine *tmp;
- BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(ta, id));
+ BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(ta, id));
- ta->name = NULL;
+ ta->name = NULL;
- ta->nlines = 1;
- ta->flags = TXT_ISDIRTY | TXT_ISMEM;
- if ((U.flag & USER_TXT_TABSTOSPACES_DISABLE) == 0)
- ta->flags |= TXT_TABSTOSPACES;
+ ta->nlines = 1;
+ ta->flags = TXT_ISDIRTY | TXT_ISMEM;
+ if ((U.flag & USER_TXT_TABSTOSPACES_DISABLE) == 0)
+ ta->flags |= TXT_TABSTOSPACES;
- BLI_listbase_clear(&ta->lines);
+ BLI_listbase_clear(&ta->lines);
- tmp = (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
- tmp->line = (char *) MEM_mallocN(1, "textline_string");
- tmp->format = NULL;
+ tmp = (TextLine *)MEM_mallocN(sizeof(TextLine), "textline");
+ tmp->line = (char *)MEM_mallocN(1, "textline_string");
+ tmp->format = NULL;
- tmp->line[0] = 0;
- tmp->len = 0;
+ tmp->line[0] = 0;
+ tmp->len = 0;
- tmp->next = NULL;
- tmp->prev = NULL;
+ tmp->next = NULL;
+ tmp->prev = NULL;
- BLI_addhead(&ta->lines, tmp);
+ BLI_addhead(&ta->lines, tmp);
- ta->curl = ta->lines.first;
- ta->curc = 0;
- ta->sell = ta->lines.first;
- ta->selc = 0;
+ ta->curl = ta->lines.first;
+ ta->curc = 0;
+ ta->sell = ta->lines.first;
+ ta->selc = 0;
}
Text *BKE_text_add(Main *bmain, const char *name)
{
- Text *ta;
+ Text *ta;
- ta = BKE_libblock_alloc(bmain, ID_TXT, name, 0);
+ ta = BKE_libblock_alloc(bmain, ID_TXT, name, 0);
- BKE_text_init(ta);
+ BKE_text_init(ta);
- return ta;
+ return ta;
}
/* this function replaces extended ascii characters */
/* to a valid utf-8 sequences */
int txt_extended_ascii_as_utf8(char **str)
{
- ptrdiff_t bad_char, i = 0;
- const ptrdiff_t length = (ptrdiff_t)strlen(*str);
- int added = 0;
+ ptrdiff_t bad_char, i = 0;
+ const ptrdiff_t length = (ptrdiff_t)strlen(*str);
+ int added = 0;
- while ((*str)[i]) {
- if ((bad_char = BLI_utf8_invalid_byte(*str + i, length - i)) == -1)
- break;
+ while ((*str)[i]) {
+ if ((bad_char = BLI_utf8_invalid_byte(*str + i, length - i)) == -1)
+ break;
- added++;
- i += bad_char + 1;
- }
+ added++;
+ i += bad_char + 1;
+ }
- if (added != 0) {
- char *newstr = MEM_mallocN(length + added + 1, "text_line");
- ptrdiff_t mi = 0;
- i = 0;
+ if (added != 0) {
+ char *newstr = MEM_mallocN(length + added + 1, "text_line");
+ ptrdiff_t mi = 0;
+ i = 0;
- while ((*str)[i]) {
- if ((bad_char = BLI_utf8_invalid_byte((*str) + i, length - i)) == -1) {
- memcpy(newstr + mi, (*str) + i, length - i + 1);
- break;
- }
+ while ((*str)[i]) {
+ if ((bad_char = BLI_utf8_invalid_byte((*str) + i, length - i)) == -1) {
+ memcpy(newstr + mi, (*str) + i, length - i + 1);
+ break;
+ }
- memcpy(newstr + mi, (*str) + i, bad_char);
+ memcpy(newstr + mi, (*str) + i, bad_char);
- BLI_str_utf8_from_unicode((*str)[i + bad_char], newstr + mi + bad_char);
- i += bad_char + 1;
- mi += bad_char + 2;
- }
- newstr[length + added] = '\0';
- MEM_freeN(*str);
- *str = newstr;
- }
+ BLI_str_utf8_from_unicode((*str)[i + bad_char], newstr + mi + bad_char);
+ i += bad_char + 1;
+ mi += bad_char + 2;
+ }
+ newstr[length + added] = '\0';
+ MEM_freeN(*str);
+ *str = newstr;
+ }
- return added;
+ return added;
}
// this function removes any control characters from
@@ -291,16 +289,16 @@ int txt_extended_ascii_as_utf8(char **str)
static void cleanup_textline(TextLine *tl)
{
- int i;
+ int i;
- for (i = 0; i < tl->len; i++) {
- if (tl->line[i] < ' ' && tl->line[i] != '\t') {
- memmove(tl->line + i, tl->line + i + 1, tl->len - i);
- tl->len--;
- i--;
- }
- }
- tl->len += txt_extended_ascii_as_utf8(&tl->line);
+ for (i = 0; i < tl->len; i++) {
+ if (tl->line[i] < ' ' && tl->line[i] != '\t') {
+ memmove(tl->line + i, tl->line + i + 1, tl->len - i);
+ tl->len--;
+ i--;
+ }
+ }
+ tl->len += txt_extended_ascii_as_utf8(&tl->line);
}
/**
@@ -309,152 +307,154 @@ static void cleanup_textline(TextLine *tl)
*/
static void text_from_buf(Text *text, const unsigned char *buffer, const int len)
{
- int i, llen;
+ int i, llen;
- BLI_assert(BLI_listbase_is_empty(&text->lines));
+ BLI_assert(BLI_listbase_is_empty(&text->lines));
- text->nlines = 0;
- llen = 0;
- for (i = 0; i < len; i++) {
- if (buffer[i] == '\n') {
- TextLine *tmp;
+ text->nlines = 0;
+ llen = 0;
+ for (i = 0; i < len; i++) {
+ if (buffer[i] == '\n') {
+ TextLine *tmp;
- tmp = (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
- tmp->line = (char *) MEM_mallocN(llen + 1, "textline_string");
- tmp->format = NULL;
+ tmp = (TextLine *)MEM_mallocN(sizeof(TextLine), "textline");
+ tmp->line = (char *)MEM_mallocN(llen + 1, "textline_string");
+ tmp->format = NULL;
- if (llen) memcpy(tmp->line, &buffer[i - llen], llen);
- tmp->line[llen] = 0;
- tmp->len = llen;
+ if (llen)
+ memcpy(tmp->line, &buffer[i - llen], llen);
+ tmp->line[llen] = 0;
+ tmp->len = llen;
- cleanup_textline(tmp);
+ cleanup_textline(tmp);
- BLI_addtail(&text->lines, tmp);
- text->nlines++;
+ BLI_addtail(&text->lines, tmp);
+ text->nlines++;
- llen = 0;
- continue;
- }
- llen++;
- }
+ llen = 0;
+ continue;
+ }
+ llen++;
+ }
- /* create new line in cases:
- * - rest of line (if last line in file hasn't got \n terminator).
- * in this case content of such line would be used to fill text line buffer
- * - file is empty. in this case new line is needed to start editing from.
- * - last character in buffer is \n. in this case new line is needed to
- * deal with newline at end of file. (see [#28087]) (sergey) */
- if (llen != 0 || text->nlines == 0 || buffer[len - 1] == '\n') {
- TextLine *tmp;
+ /* create new line in cases:
+ * - rest of line (if last line in file hasn't got \n terminator).
+ * in this case content of such line would be used to fill text line buffer
+ * - file is empty. in this case new line is needed to start editing from.
+ * - last character in buffer is \n. in this case new line is needed to
+ * deal with newline at end of file. (see [#28087]) (sergey) */
+ if (llen != 0 || text->nlines == 0 || buffer[len - 1] == '\n') {
+ TextLine *tmp;
- tmp = (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
- tmp->line = (char *) MEM_mallocN(llen + 1, "textline_string");
- tmp->format = NULL;
+ tmp = (TextLine *)MEM_mallocN(sizeof(TextLine), "textline");
+ tmp->line = (char *)MEM_mallocN(llen + 1, "textline_string");
+ tmp->format = NULL;
- if (llen) memcpy(tmp->line, &buffer[i - llen], llen);
+ if (llen)
+ memcpy(tmp->line, &buffer[i - llen], llen);
- tmp->line[llen] = 0;
- tmp->len = llen;
+ tmp->line[llen] = 0;
+ tmp->len = llen;
- cleanup_textline(tmp);
+ cleanup_textline(tmp);
- BLI_addtail(&text->lines, tmp);
- text->nlines++;
- }
+ BLI_addtail(&text->lines, tmp);
+ text->nlines++;
+ }
- text->curl = text->sell = text->lines.first;
- text->curc = text->selc = 0;
+ text->curl = text->sell = text->lines.first;
+ text->curc = text->selc = 0;
}
bool BKE_text_reload(Text *text)
{
- unsigned char *buffer;
- size_t buffer_len;
- char filepath_abs[FILE_MAX];
- BLI_stat_t st;
+ unsigned char *buffer;
+ size_t buffer_len;
+ char filepath_abs[FILE_MAX];
+ BLI_stat_t st;
- if (!text->name) {
- return false;
- }
+ if (!text->name) {
+ return false;
+ }
- BLI_strncpy(filepath_abs, text->name, FILE_MAX);
- BLI_path_abs(filepath_abs, BKE_main_blendfile_path_from_global());
+ BLI_strncpy(filepath_abs, text->name, FILE_MAX);
+ BLI_path_abs(filepath_abs, BKE_main_blendfile_path_from_global());
- buffer = BLI_file_read_text_as_mem(filepath_abs, 0, &buffer_len);
- if (buffer == NULL) {
- return false;
- }
+ buffer = BLI_file_read_text_as_mem(filepath_abs, 0, &buffer_len);
+ if (buffer == NULL) {
+ return false;
+ }
- /* free memory: */
- BKE_text_free_lines(text);
- txt_make_dirty(text);
+ /* free memory: */
+ BKE_text_free_lines(text);
+ txt_make_dirty(text);
- /* clear undo buffer */
- if (BLI_stat(filepath_abs, &st) != -1) {
- text->mtime = st.st_mtime;
- }
- else {
- text->mtime = 0;
- }
+ /* clear undo buffer */
+ if (BLI_stat(filepath_abs, &st) != -1) {
+ text->mtime = st.st_mtime;
+ }
+ else {
+ text->mtime = 0;
+ }
- text_from_buf(text, buffer, buffer_len);
+ text_from_buf(text, buffer, buffer_len);
- MEM_freeN(buffer);
- return true;
+ MEM_freeN(buffer);
+ return true;
}
Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const bool is_internal)
{
- unsigned char *buffer;
- size_t buffer_len;
- Text *ta;
- char filepath_abs[FILE_MAX];
- BLI_stat_t st;
+ unsigned char *buffer;
+ size_t buffer_len;
+ Text *ta;
+ char filepath_abs[FILE_MAX];
+ BLI_stat_t st;
- BLI_strncpy(filepath_abs, file, FILE_MAX);
- if (relpath) /* can be NULL (bg mode) */
- BLI_path_abs(filepath_abs, relpath);
+ BLI_strncpy(filepath_abs, file, FILE_MAX);
+ if (relpath) /* can be NULL (bg mode) */
+ BLI_path_abs(filepath_abs, relpath);
- buffer = BLI_file_read_text_as_mem(filepath_abs, 0, &buffer_len);
- if (buffer == NULL) {
- return false;
- }
+ buffer = BLI_file_read_text_as_mem(filepath_abs, 0, &buffer_len);
+ if (buffer == NULL) {
+ return false;
+ }
- ta = BKE_libblock_alloc(bmain, ID_TXT, BLI_path_basename(filepath_abs), 0);
- ta->id.us = 0;
+ ta = BKE_libblock_alloc(bmain, ID_TXT, BLI_path_basename(filepath_abs), 0);
+ ta->id.us = 0;
- BLI_listbase_clear(&ta->lines);
- ta->curl = ta->sell = NULL;
+ BLI_listbase_clear(&ta->lines);
+ ta->curl = ta->sell = NULL;
- if ((U.flag & USER_TXT_TABSTOSPACES_DISABLE) == 0)
- ta->flags = TXT_TABSTOSPACES;
+ if ((U.flag & USER_TXT_TABSTOSPACES_DISABLE) == 0)
+ ta->flags = TXT_TABSTOSPACES;
- if (is_internal == false) {
- ta->name = MEM_mallocN(strlen(file) + 1, "text_name");
- strcpy(ta->name, file);
- }
- else {
- ta->flags |= TXT_ISMEM | TXT_ISDIRTY;
- }
+ if (is_internal == false) {
+ ta->name = MEM_mallocN(strlen(file) + 1, "text_name");
+ strcpy(ta->name, file);
+ }
+ else {
+ ta->flags |= TXT_ISMEM | TXT_ISDIRTY;
+ }
- /* clear undo buffer */
- if (BLI_stat(filepath_abs, &st) != -1) {
- ta->mtime = st.st_mtime;
- }
- else {
- ta->mtime = 0;
- }
+ /* clear undo buffer */
+ if (BLI_stat(filepath_abs, &st) != -1) {
+ ta->mtime = st.st_mtime;
+ }
+ else {
+ ta->mtime = 0;
+ }
- text_from_buf(ta, buffer, buffer_len);
+ text_from_buf(ta, buffer, buffer_len);
- MEM_freeN(buffer);
+ MEM_freeN(buffer);
- return ta;
+ return ta;
}
Text *BKE_text_load(Main *bmain, const char *file, const char *relpath)
{
- return BKE_text_load_ex(bmain, file, relpath, false);
+ return BKE_text_load_ex(bmain, file, relpath, false);
}
/**
@@ -465,73 +465,75 @@ Text *BKE_text_load(Main *bmain, const char *file, const char *relpath)
*
* \param flag: Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
*/
-void BKE_text_copy_data(Main *UNUSED(bmain), Text *ta_dst, const Text *ta_src, const int UNUSED(flag))
+void BKE_text_copy_data(Main *UNUSED(bmain),
+ Text *ta_dst,
+ const Text *ta_src,
+ const int UNUSED(flag))
{
- /* file name can be NULL */
- if (ta_src->name) {
- ta_dst->name = BLI_strdup(ta_src->name);
- }
+ /* file name can be NULL */
+ if (ta_src->name) {
+ ta_dst->name = BLI_strdup(ta_src->name);
+ }
- ta_dst->flags |= TXT_ISDIRTY;
+ ta_dst->flags |= TXT_ISDIRTY;
- BLI_listbase_clear(&ta_dst->lines);
- ta_dst->curl = ta_dst->sell = NULL;
- ta_dst->compiled = NULL;
+ BLI_listbase_clear(&ta_dst->lines);
+ ta_dst->curl = ta_dst->sell = NULL;
+ ta_dst->compiled = NULL;
- /* Walk down, reconstructing */
- for (TextLine *line_src = ta_src->lines.first; line_src; line_src = line_src->next) {
- TextLine *line_dst = MEM_mallocN(sizeof(*line_dst), __func__);
+ /* Walk down, reconstructing */
+ for (TextLine *line_src = ta_src->lines.first; line_src; line_src = line_src->next) {
+ TextLine *line_dst = MEM_mallocN(sizeof(*line_dst), __func__);
- line_dst->line = BLI_strdup(line_src->line);
- line_dst->format = NULL;
- line_dst->len = line_src->len;
+ line_dst->line = BLI_strdup(line_src->line);
+ line_dst->format = NULL;
+ line_dst->len = line_src->len;
- BLI_addtail(&ta_dst->lines, line_dst);
- }
+ BLI_addtail(&ta_dst->lines, line_dst);
+ }
- ta_dst->curl = ta_dst->sell = ta_dst->lines.first;
- ta_dst->curc = ta_dst->selc = 0;
+ ta_dst->curl = ta_dst->sell = ta_dst->lines.first;
+ ta_dst->curc = ta_dst->selc = 0;
}
Text *BKE_text_copy(Main *bmain, const Text *ta)
{
- Text *ta_copy;
- BKE_id_copy(bmain, &ta->id, (ID **)&ta_copy);
- return ta_copy;
+ Text *ta_copy;
+ BKE_id_copy(bmain, &ta->id, (ID **)&ta_copy);
+ return ta_copy;
}
void BKE_text_make_local(Main *bmain, Text *text, const bool lib_local)
{
- BKE_id_make_local_generic(bmain, &text->id, true, lib_local);
+ BKE_id_make_local_generic(bmain, &text->id, true, lib_local);
}
void BKE_text_clear(Text *text, TextUndoBuf *utxt) /* called directly from rna */
{
- const bool undoing_orig = undoing;
- undoing = (utxt == NULL);
+ const bool undoing_orig = undoing;
+ undoing = (utxt == NULL);
- txt_sel_all(text);
- txt_delete_sel(text, utxt);
+ txt_sel_all(text);
+ txt_delete_sel(text, utxt);
- undoing = undoing_orig;
+ undoing = undoing_orig;
- txt_make_dirty(text);
+ txt_make_dirty(text);
}
void BKE_text_write(Text *text, TextUndoBuf *utxt, const char *str) /* called directly from rna */
{
- const bool undoing_orig = undoing;
- undoing = (utxt == NULL);
+ const bool undoing_orig = undoing;
+ undoing = (utxt == NULL);
- txt_insert_buf(text, utxt, str);
- txt_move_eof(text, 0);
+ txt_insert_buf(text, utxt, str);
+ txt_move_eof(text, 0);
- undoing = undoing_orig;
+ undoing = undoing_orig;
- txt_make_dirty(text);
+ txt_make_dirty(text);
}
-
/* returns 0 if file on disk is the same or Text is in memory only
* returns 1 if file has been modified on disk since last local edit
* returns 2 if file on disk has been deleted
@@ -539,52 +541,54 @@ void BKE_text_write(Text *text, TextUndoBuf *utxt, const char *str) /* called di
int BKE_text_file_modified_check(Text *text)
{
- BLI_stat_t st;
- int result;
- char file[FILE_MAX];
+ BLI_stat_t st;
+ int result;
+ char file[FILE_MAX];
- if (!text->name)
- return 0;
+ if (!text->name)
+ return 0;
- BLI_strncpy(file, text->name, FILE_MAX);
- BLI_path_abs(file, BKE_main_blendfile_path_from_global());
+ BLI_strncpy(file, text->name, FILE_MAX);
+ BLI_path_abs(file, BKE_main_blendfile_path_from_global());
- if (!BLI_exists(file))
- return 2;
+ if (!BLI_exists(file))
+ return 2;
- result = BLI_stat(file, &st);
+ result = BLI_stat(file, &st);
- if (result == -1)
- return -1;
+ if (result == -1)
+ return -1;
- if ((st.st_mode & S_IFMT) != S_IFREG)
- return -1;
+ if ((st.st_mode & S_IFMT) != S_IFREG)
+ return -1;
- if (st.st_mtime > text->mtime)
- return 1;
+ if (st.st_mtime > text->mtime)
+ return 1;
- return 0;
+ return 0;
}
void BKE_text_file_modified_ignore(Text *text)
{
- BLI_stat_t st;
- int result;
- char file[FILE_MAX];
+ BLI_stat_t st;
+ int result;
+ char file[FILE_MAX];
- if (!text->name) return;
+ if (!text->name)
+ return;
- BLI_strncpy(file, text->name, FILE_MAX);
- BLI_path_abs(file, BKE_main_blendfile_path_from_global());
+ BLI_strncpy(file, text->name, FILE_MAX);
+ BLI_path_abs(file, BKE_main_blendfile_path_from_global());
- if (!BLI_exists(file)) return;
+ if (!BLI_exists(file))
+ return;
- result = BLI_stat(file, &st);
+ result = BLI_stat(file, &st);
- if (result == -1 || (st.st_mode & S_IFMT) != S_IFREG)
- return;
+ if (result == -1 || (st.st_mode & S_IFMT) != S_IFREG)
+ return;
- text->mtime = st.st_mtime;
+ text->mtime = st.st_mtime;
}
/*****************************/
@@ -593,112 +597,128 @@ void BKE_text_file_modified_ignore(Text *text)
static void make_new_line(TextLine *line, char *newline)
{
- if (line->line) MEM_freeN(line->line);
- if (line->format) MEM_freeN(line->format);
+ if (line->line)
+ MEM_freeN(line->line);
+ if (line->format)
+ MEM_freeN(line->format);
- line->line = newline;
- line->len = strlen(newline);
- line->format = NULL;
+ line->line = newline;
+ line->len = strlen(newline);
+ line->format = NULL;
}
static TextLine *txt_new_line(const char *str)
{
- TextLine *tmp;
+ TextLine *tmp;
- if (!str) str = "";
+ if (!str)
+ str = "";
- tmp = (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
- tmp->line = MEM_mallocN(strlen(str) + 1, "textline_string");
- tmp->format = NULL;
+ tmp = (TextLine *)MEM_mallocN(sizeof(TextLine), "textline");
+ tmp->line = MEM_mallocN(strlen(str) + 1, "textline_string");
+ tmp->format = NULL;
- strcpy(tmp->line, str);
+ strcpy(tmp->line, str);
- tmp->len = strlen(str);
- tmp->next = tmp->prev = NULL;
+ tmp->len = strlen(str);
+ tmp->next = tmp->prev = NULL;
- return tmp;
+ return tmp;
}
static TextLine *txt_new_linen(const char *str, int n)
{
- TextLine *tmp;
+ TextLine *tmp;
- tmp = (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
- tmp->line = MEM_mallocN(n + 1, "textline_string");
- tmp->format = NULL;
+ tmp = (TextLine *)MEM_mallocN(sizeof(TextLine), "textline");
+ tmp->line = MEM_mallocN(n + 1, "textline_string");
+ tmp->format = NULL;
- BLI_strncpy(tmp->line, (str) ? str : "", n + 1);
+ BLI_strncpy(tmp->line, (str) ? str : "", n + 1);
- tmp->len = strlen(tmp->line);
- tmp->next = tmp->prev = NULL;
+ tmp->len = strlen(tmp->line);
+ tmp->next = tmp->prev = NULL;
- return tmp;
+ return tmp;
}
void txt_clean_text(Text *text)
{
- TextLine **top, **bot;
+ TextLine **top, **bot;
- if (!text->lines.first) {
- if (text->lines.last) text->lines.first = text->lines.last;
- else text->lines.first = text->lines.last = txt_new_line(NULL);
- }
+ if (!text->lines.first) {
+ if (text->lines.last)
+ text->lines.first = text->lines.last;
+ else
+ text->lines.first = text->lines.last = txt_new_line(NULL);
+ }
- if (!text->lines.last) text->lines.last = text->lines.first;
+ if (!text->lines.last)
+ text->lines.last = text->lines.first;
- top = (TextLine **) &text->lines.first;
- bot = (TextLine **) &text->lines.last;
+ top = (TextLine **)&text->lines.first;
+ bot = (TextLine **)&text->lines.last;
- while ((*top)->prev) *top = (*top)->prev;
- while ((*bot)->next) *bot = (*bot)->next;
+ while ((*top)->prev)
+ *top = (*top)->prev;
+ while ((*bot)->next)
+ *bot = (*bot)->next;
- if (!text->curl) {
- if (text->sell) text->curl = text->sell;
- else text->curl = text->lines.first;
- text->curc = 0;
- }
+ if (!text->curl) {
+ if (text->sell)
+ text->curl = text->sell;
+ else
+ text->curl = text->lines.first;
+ text->curc = 0;
+ }
- if (!text->sell) {
- text->sell = text->curl;
- text->selc = 0;
- }
+ if (!text->sell) {
+ text->sell = text->curl;
+ text->selc = 0;
+ }
}
int txt_get_span(TextLine *from, TextLine *to)
{
- int ret = 0;
- TextLine *tmp = from;
-
- if (!to || !from) return 0;
- if (from == to) return 0;
-
- /* Look forwards */
- while (tmp) {
- if (tmp == to) return ret;
- ret++;
- tmp = tmp->next;
- }
-
- /* Look backwards */
- if (!tmp) {
- tmp = from;
- ret = 0;
- while (tmp) {
- if (tmp == to) break;
- ret--;
- tmp = tmp->prev;
- }
- if (!tmp) ret = 0;
- }
-
- return ret;
+ int ret = 0;
+ TextLine *tmp = from;
+
+ if (!to || !from)
+ return 0;
+ if (from == to)
+ return 0;
+
+ /* Look forwards */
+ while (tmp) {
+ if (tmp == to)
+ return ret;
+ ret++;
+ tmp = tmp->next;
+ }
+
+ /* Look backwards */
+ if (!tmp) {
+ tmp = from;
+ ret = 0;
+ while (tmp) {
+ if (tmp == to)
+ break;
+ ret--;
+ tmp = tmp->prev;
+ }
+ if (!tmp)
+ ret = 0;
+ }
+
+ return ret;
}
static void txt_make_dirty(Text *text)
{
- text->flags |= TXT_ISDIRTY;
+ text->flags |= TXT_ISDIRTY;
#ifdef WITH_PYTHON
- if (text->compiled) BPY_text_free_code(text);
+ if (text->compiled)
+ BPY_text_free_code(text);
#endif
}
@@ -708,22 +728,24 @@ static void txt_make_dirty(Text *text)
static void txt_curs_cur(Text *text, TextLine ***linep, int **charp)
{
- *linep = &text->curl; *charp = &text->curc;
+ *linep = &text->curl;
+ *charp = &text->curc;
}
static void txt_curs_sel(Text *text, TextLine ***linep, int **charp)
{
- *linep = &text->sell; *charp = &text->selc;
+ *linep = &text->sell;
+ *charp = &text->selc;
}
bool txt_cursor_is_line_start(Text *text)
{
- return (text->selc == 0);
+ return (text->selc == 0);
}
bool txt_cursor_is_line_end(Text *text)
{
- return (text->selc == text->sell->len);
+ return (text->selc == text->sell->len);
}
/*****************************/
@@ -732,316 +754,371 @@ bool txt_cursor_is_line_end(Text *text)
int txt_utf8_offset_to_index(const char *str, int offset)
{
- int index = 0, pos = 0;
- while (pos != offset) {
- pos += BLI_str_utf8_size(str + pos);
- index++;
- }
- return index;
+ int index = 0, pos = 0;
+ while (pos != offset) {
+ pos += BLI_str_utf8_size(str + pos);
+ index++;
+ }
+ return index;
}
int txt_utf8_index_to_offset(const char *str, int index)
{
- int offset = 0, pos = 0;
- while (pos != index) {
- offset += BLI_str_utf8_size(str + offset);
- pos++;
- }
- return offset;
+ int offset = 0, pos = 0;
+ while (pos != index) {
+ offset += BLI_str_utf8_size(str + offset);
+ pos++;
+ }
+ return offset;
}
int txt_utf8_offset_to_column(const char *str, int offset)
{
- int column = 0, pos = 0;
- while (pos < offset) {
- column += BLI_str_utf8_char_width_safe(str + pos);
- pos += BLI_str_utf8_size_safe(str + pos);
- }
- return column;
+ int column = 0, pos = 0;
+ while (pos < offset) {
+ column += BLI_str_utf8_char_width_safe(str + pos);
+ pos += BLI_str_utf8_size_safe(str + pos);
+ }
+ return column;
}
int txt_utf8_column_to_offset(const char *str, int column)
{
- int offset = 0, pos = 0, col;
- while (*(str + offset) && pos < column) {
- col = BLI_str_utf8_char_width_safe(str + offset);
- if (pos + col > column)
- break;
- offset += BLI_str_utf8_size_safe(str + offset);
- pos += col;
- }
- return offset;
+ int offset = 0, pos = 0, col;
+ while (*(str + offset) && pos < column) {
+ col = BLI_str_utf8_char_width_safe(str + offset);
+ if (pos + col > column)
+ break;
+ offset += BLI_str_utf8_size_safe(str + offset);
+ pos += col;
+ }
+ return offset;
}
void txt_move_up(Text *text, const bool sel)
{
- TextLine **linep;
- int *charp;
-
- if (sel) txt_curs_sel(text, &linep, &charp);
- else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
- if (!*linep) return;
+ TextLine **linep;
+ int *charp;
- if ((*linep)->prev) {
- int column = txt_utf8_offset_to_column((*linep)->line, *charp);
- *linep = (*linep)->prev;
- *charp = txt_utf8_column_to_offset((*linep)->line, column);
+ if (sel)
+ txt_curs_sel(text, &linep, &charp);
+ else {
+ txt_pop_first(text);
+ txt_curs_cur(text, &linep, &charp);
+ }
+ if (!*linep)
+ return;
- }
- else {
- txt_move_bol(text, sel);
- }
+ if ((*linep)->prev) {
+ int column = txt_utf8_offset_to_column((*linep)->line, *charp);
+ *linep = (*linep)->prev;
+ *charp = txt_utf8_column_to_offset((*linep)->line, column);
+ }
+ else {
+ txt_move_bol(text, sel);
+ }
- if (!sel) txt_pop_sel(text);
+ if (!sel)
+ txt_pop_sel(text);
}
void txt_move_down(Text *text, const bool sel)
{
- TextLine **linep;
- int *charp;
+ TextLine **linep;
+ int *charp;
- if (sel) txt_curs_sel(text, &linep, &charp);
- else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
- if (!*linep) return;
+ if (sel)
+ txt_curs_sel(text, &linep, &charp);
+ else {
+ txt_pop_last(text);
+ txt_curs_cur(text, &linep, &charp);
+ }
+ if (!*linep)
+ return;
- if ((*linep)->next) {
- int column = txt_utf8_offset_to_column((*linep)->line, *charp);
- *linep = (*linep)->next;
- *charp = txt_utf8_column_to_offset((*linep)->line, column);
- }
- else {
- txt_move_eol(text, sel);
- }
+ if ((*linep)->next) {
+ int column = txt_utf8_offset_to_column((*linep)->line, *charp);
+ *linep = (*linep)->next;
+ *charp = txt_utf8_column_to_offset((*linep)->line, column);
+ }
+ else {
+ txt_move_eol(text, sel);
+ }
- if (!sel) txt_pop_sel(text);
+ if (!sel)
+ txt_pop_sel(text);
}
int txt_calc_tab_left(TextLine *tl, int ch)
{
- /* do nice left only if there are only spaces */
+ /* do nice left only if there are only spaces */
- int tabsize = (ch < TXT_TABSIZE) ? ch : TXT_TABSIZE;
+ int tabsize = (ch < TXT_TABSIZE) ? ch : TXT_TABSIZE;
- for (int i = 0; i < ch; i++)
- if (tl->line[i] != ' ') {
- tabsize = 0;
- break;
- }
+ for (int i = 0; i < ch; i++)
+ if (tl->line[i] != ' ') {
+ tabsize = 0;
+ break;
+ }
- /* if in the middle of the space-tab */
- if (tabsize && ch % TXT_TABSIZE != 0)
- tabsize = (ch % TXT_TABSIZE);
- return tabsize;
+ /* if in the middle of the space-tab */
+ if (tabsize && ch % TXT_TABSIZE != 0)
+ tabsize = (ch % TXT_TABSIZE);
+ return tabsize;
}
int txt_calc_tab_right(TextLine *tl, int ch)
{
- if (tl->line[ch] == ' ') {
- int i;
- for (i = 0; i < ch; i++) {
- if (tl->line[i] != ' ') {
- return 0;
- }
- }
+ if (tl->line[ch] == ' ') {
+ int i;
+ for (i = 0; i < ch; i++) {
+ if (tl->line[i] != ' ') {
+ return 0;
+ }
+ }
- int tabsize = (ch) % TXT_TABSIZE + 1;
- for (i = ch + 1; tl->line[i] == ' ' && tabsize < TXT_TABSIZE; i++) {
- tabsize++;
- }
+ int tabsize = (ch) % TXT_TABSIZE + 1;
+ for (i = ch + 1; tl->line[i] == ' ' && tabsize < TXT_TABSIZE; i++) {
+ tabsize++;
+ }
- return i - ch;
- }
- else {
- return 0;
- }
+ return i - ch;
+ }
+ else {
+ return 0;
+ }
}
void txt_move_left(Text *text, const bool sel)
{
- TextLine **linep;
- int *charp;
- int tabsize = 0;
-
- if (sel) txt_curs_sel(text, &linep, &charp);
- else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
- if (!*linep) return;
-
- if (*charp == 0) {
- if ((*linep)->prev) {
- txt_move_up(text, sel);
- *charp = (*linep)->len;
- }
- }
- else {
- /* do nice left only if there are only spaces */
- // TXT_TABSIZE hardcoded in DNA_text_types.h
- if (text->flags & TXT_TABSTOSPACES) {
- tabsize = txt_calc_tab_left(*linep, *charp);
- }
-
- if (tabsize) {
- (*charp) -= tabsize;
- }
- else {
- const char *prev = BLI_str_prev_char_utf8((*linep)->line + *charp);
- *charp = prev - (*linep)->line;
- }
- }
-
- if (!sel) txt_pop_sel(text);
+ TextLine **linep;
+ int *charp;
+ int tabsize = 0;
+
+ if (sel)
+ txt_curs_sel(text, &linep, &charp);
+ else {
+ txt_pop_first(text);
+ txt_curs_cur(text, &linep, &charp);
+ }
+ if (!*linep)
+ return;
+
+ if (*charp == 0) {
+ if ((*linep)->prev) {
+ txt_move_up(text, sel);
+ *charp = (*linep)->len;
+ }
+ }
+ else {
+ /* do nice left only if there are only spaces */
+ // TXT_TABSIZE hardcoded in DNA_text_types.h
+ if (text->flags & TXT_TABSTOSPACES) {
+ tabsize = txt_calc_tab_left(*linep, *charp);
+ }
+
+ if (tabsize) {
+ (*charp) -= tabsize;
+ }
+ else {
+ const char *prev = BLI_str_prev_char_utf8((*linep)->line + *charp);
+ *charp = prev - (*linep)->line;
+ }
+ }
+
+ if (!sel)
+ txt_pop_sel(text);
}
void txt_move_right(Text *text, const bool sel)
{
- TextLine **linep;
- int *charp;
-
- if (sel) txt_curs_sel(text, &linep, &charp);
- else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
- if (!*linep) return;
-
- if (*charp == (*linep)->len) {
- if ((*linep)->next) {
- txt_move_down(text, sel);
- *charp = 0;
- }
- }
- else {
- /* do nice right only if there are only spaces */
- /* spaces hardcoded in DNA_text_types.h */
- int tabsize = 0;
-
- if (text->flags & TXT_TABSTOSPACES) {
- tabsize = txt_calc_tab_right(*linep, *charp);
- }
-
- if (tabsize) {
- (*charp) += tabsize;
- }
- else {
- (*charp) += BLI_str_utf8_size((*linep)->line + *charp);
- }
- }
-
- if (!sel) txt_pop_sel(text);
+ TextLine **linep;
+ int *charp;
+
+ if (sel)
+ txt_curs_sel(text, &linep, &charp);
+ else {
+ txt_pop_last(text);
+ txt_curs_cur(text, &linep, &charp);
+ }
+ if (!*linep)
+ return;
+
+ if (*charp == (*linep)->len) {
+ if ((*linep)->next) {
+ txt_move_down(text, sel);
+ *charp = 0;
+ }
+ }
+ else {
+ /* do nice right only if there are only spaces */
+ /* spaces hardcoded in DNA_text_types.h */
+ int tabsize = 0;
+
+ if (text->flags & TXT_TABSTOSPACES) {
+ tabsize = txt_calc_tab_right(*linep, *charp);
+ }
+
+ if (tabsize) {
+ (*charp) += tabsize;
+ }
+ else {
+ (*charp) += BLI_str_utf8_size((*linep)->line + *charp);
+ }
+ }
+
+ if (!sel)
+ txt_pop_sel(text);
}
void txt_jump_left(Text *text, const bool sel, const bool use_init_step)
{
- TextLine **linep;
- int *charp;
+ TextLine **linep;
+ int *charp;
- if (sel) txt_curs_sel(text, &linep, &charp);
- else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
- if (!*linep) return;
+ if (sel)
+ txt_curs_sel(text, &linep, &charp);
+ else {
+ txt_pop_first(text);
+ txt_curs_cur(text, &linep, &charp);
+ }
+ if (!*linep)
+ return;
- BLI_str_cursor_step_utf8((*linep)->line, (*linep)->len,
- charp, STRCUR_DIR_PREV,
- STRCUR_JUMP_DELIM, use_init_step);
+ BLI_str_cursor_step_utf8(
+ (*linep)->line, (*linep)->len, charp, STRCUR_DIR_PREV, STRCUR_JUMP_DELIM, use_init_step);
- if (!sel) txt_pop_sel(text);
+ if (!sel)
+ txt_pop_sel(text);
}
void txt_jump_right(Text *text, const bool sel, const bool use_init_step)
{
- TextLine **linep;
- int *charp;
+ TextLine **linep;
+ int *charp;
- if (sel) txt_curs_sel(text, &linep, &charp);
- else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
- if (!*linep) return;
+ if (sel)
+ txt_curs_sel(text, &linep, &charp);
+ else {
+ txt_pop_last(text);
+ txt_curs_cur(text, &linep, &charp);
+ }
+ if (!*linep)
+ return;
- BLI_str_cursor_step_utf8((*linep)->line, (*linep)->len,
- charp, STRCUR_DIR_NEXT,
- STRCUR_JUMP_DELIM, use_init_step);
+ BLI_str_cursor_step_utf8(
+ (*linep)->line, (*linep)->len, charp, STRCUR_DIR_NEXT, STRCUR_JUMP_DELIM, use_init_step);
- if (!sel) txt_pop_sel(text);
+ if (!sel)
+ txt_pop_sel(text);
}
void txt_move_bol(Text *text, const bool sel)
{
- TextLine **linep;
- int *charp;
+ TextLine **linep;
+ int *charp;
- if (sel) txt_curs_sel(text, &linep, &charp);
- else txt_curs_cur(text, &linep, &charp);
- if (!*linep) return;
+ if (sel)
+ txt_curs_sel(text, &linep, &charp);
+ else
+ txt_curs_cur(text, &linep, &charp);
+ if (!*linep)
+ return;
- *charp = 0;
+ *charp = 0;
- if (!sel) txt_pop_sel(text);
+ if (!sel)
+ txt_pop_sel(text);
}
void txt_move_eol(Text *text, const bool sel)
{
- TextLine **linep;
- int *charp;
+ TextLine **linep;
+ int *charp;
- if (sel) txt_curs_sel(text, &linep, &charp);
- else txt_curs_cur(text, &linep, &charp);
- if (!*linep) return;
+ if (sel)
+ txt_curs_sel(text, &linep, &charp);
+ else
+ txt_curs_cur(text, &linep, &charp);
+ if (!*linep)
+ return;
- *charp = (*linep)->len;
+ *charp = (*linep)->len;
- if (!sel) txt_pop_sel(text);
+ if (!sel)
+ txt_pop_sel(text);
}
void txt_move_bof(Text *text, const bool sel)
{
- TextLine **linep;
- int *charp;
+ TextLine **linep;
+ int *charp;
- if (sel) txt_curs_sel(text, &linep, &charp);
- else txt_curs_cur(text, &linep, &charp);
- if (!*linep) return;
+ if (sel)
+ txt_curs_sel(text, &linep, &charp);
+ else
+ txt_curs_cur(text, &linep, &charp);
+ if (!*linep)
+ return;
- *linep = text->lines.first;
- *charp = 0;
+ *linep = text->lines.first;
+ *charp = 0;
- if (!sel) txt_pop_sel(text);
+ if (!sel)
+ txt_pop_sel(text);
}
void txt_move_eof(Text *text, const bool sel)
{
- TextLine **linep;
- int *charp;
+ TextLine **linep;
+ int *charp;
- if (sel) txt_curs_sel(text, &linep, &charp);
- else txt_curs_cur(text, &linep, &charp);
- if (!*linep) return;
+ if (sel)
+ txt_curs_sel(text, &linep, &charp);
+ else
+ txt_curs_cur(text, &linep, &charp);
+ if (!*linep)
+ return;
- *linep = text->lines.last;
- *charp = (*linep)->len;
+ *linep = text->lines.last;
+ *charp = (*linep)->len;
- if (!sel) txt_pop_sel(text);
+ if (!sel)
+ txt_pop_sel(text);
}
void txt_move_toline(Text *text, unsigned int line, const bool sel)
{
- txt_move_to(text, line, 0, sel);
+ txt_move_to(text, line, 0, sel);
}
/* Moves to a certain byte in a line, not a certain utf8-character! */
void txt_move_to(Text *text, unsigned int line, unsigned int ch, const bool sel)
{
- TextLine **linep;
- int *charp;
- unsigned int i;
+ TextLine **linep;
+ int *charp;
+ unsigned int i;
- if (sel) txt_curs_sel(text, &linep, &charp);
- else txt_curs_cur(text, &linep, &charp);
- if (!*linep) return;
+ if (sel)
+ txt_curs_sel(text, &linep, &charp);
+ else
+ txt_curs_cur(text, &linep, &charp);
+ if (!*linep)
+ return;
- *linep = text->lines.first;
- for (i = 0; i < line; i++) {
- if ((*linep)->next) *linep = (*linep)->next;
- else break;
- }
- if (ch > (unsigned int)((*linep)->len))
- ch = (unsigned int)((*linep)->len);
- *charp = ch;
+ *linep = text->lines.first;
+ for (i = 0; i < line; i++) {
+ if ((*linep)->next)
+ *linep = (*linep)->next;
+ else
+ break;
+ }
+ if (ch > (unsigned int)((*linep)->len))
+ ch = (unsigned int)((*linep)->len);
+ *charp = ch;
- if (!sel) txt_pop_sel(text);
+ if (!sel)
+ txt_pop_sel(text);
}
/****************************/
@@ -1050,118 +1127,120 @@ void txt_move_to(Text *text, unsigned int line, unsigned int ch, const bool sel)
static void txt_curs_swap(Text *text)
{
- TextLine *tmpl;
- int tmpc;
+ TextLine *tmpl;
+ int tmpc;
- tmpl = text->curl;
- text->curl = text->sell;
- text->sell = tmpl;
+ tmpl = text->curl;
+ text->curl = text->sell;
+ text->sell = tmpl;
- tmpc = text->curc;
- text->curc = text->selc;
- text->selc = tmpc;
+ tmpc = text->curc;
+ text->curc = text->selc;
+ text->selc = tmpc;
}
static void txt_pop_first(Text *text)
{
- if (txt_get_span(text->curl, text->sell) < 0 ||
- (text->curl == text->sell && text->curc > text->selc))
- {
- txt_curs_swap(text);
- }
+ if (txt_get_span(text->curl, text->sell) < 0 ||
+ (text->curl == text->sell && text->curc > text->selc)) {
+ txt_curs_swap(text);
+ }
- txt_pop_sel(text);
+ txt_pop_sel(text);
}
static void txt_pop_last(Text *text)
{
- if (txt_get_span(text->curl, text->sell) > 0 ||
- (text->curl == text->sell && text->curc < text->selc))
- {
- txt_curs_swap(text);
- }
+ if (txt_get_span(text->curl, text->sell) > 0 ||
+ (text->curl == text->sell && text->curc < text->selc)) {
+ txt_curs_swap(text);
+ }
- txt_pop_sel(text);
+ txt_pop_sel(text);
}
void txt_pop_sel(Text *text)
{
- text->sell = text->curl;
- text->selc = text->curc;
+ text->sell = text->curl;
+ text->selc = text->curc;
}
void txt_order_cursors(Text *text, const bool reverse)
{
- if (!text->curl) return;
- if (!text->sell) return;
-
- /* Flip so text->curl is before/after text->sell */
- if (reverse == false) {
- if ((txt_get_span(text->curl, text->sell) < 0) ||
- (text->curl == text->sell && text->curc > text->selc))
- {
- txt_curs_swap(text);
- }
- }
- else {
- if ((txt_get_span(text->curl, text->sell) > 0) ||
- (text->curl == text->sell && text->curc < text->selc))
- {
- txt_curs_swap(text);
- }
- }
+ if (!text->curl)
+ return;
+ if (!text->sell)
+ return;
+
+ /* Flip so text->curl is before/after text->sell */
+ if (reverse == false) {
+ if ((txt_get_span(text->curl, text->sell) < 0) ||
+ (text->curl == text->sell && text->curc > text->selc)) {
+ txt_curs_swap(text);
+ }
+ }
+ else {
+ if ((txt_get_span(text->curl, text->sell) > 0) ||
+ (text->curl == text->sell && text->curc < text->selc)) {
+ txt_curs_swap(text);
+ }
+ }
}
bool txt_has_sel(Text *text)
{
- return ((text->curl != text->sell) || (text->curc != text->selc));
+ return ((text->curl != text->sell) || (text->curc != text->selc));
}
static void txt_delete_sel(Text *text, TextUndoBuf *utxt)
{
- TextLine *tmpl;
- char *buf;
+ TextLine *tmpl;
+ char *buf;
- if (!text->curl) return;
- if (!text->sell) return;
+ if (!text->curl)
+ return;
+ if (!text->sell)
+ return;
- if (!txt_has_sel(text)) return;
+ if (!txt_has_sel(text))
+ return;
- txt_order_cursors(text, false);
+ txt_order_cursors(text, false);
- if (!undoing) {
- buf = txt_sel_to_buf(text);
- txt_undo_add_blockop(text, utxt, UNDO_DBLOCK, buf);
- MEM_freeN(buf);
- }
+ if (!undoing) {
+ buf = txt_sel_to_buf(text);
+ txt_undo_add_blockop(text, utxt, UNDO_DBLOCK, buf);
+ MEM_freeN(buf);
+ }
- buf = MEM_mallocN(text->curc + (text->sell->len - text->selc) + 1, "textline_string");
+ buf = MEM_mallocN(text->curc + (text->sell->len - text->selc) + 1, "textline_string");
- strncpy(buf, text->curl->line, text->curc);
- strcpy(buf + text->curc, text->sell->line + text->selc);
- buf[text->curc + (text->sell->len - text->selc)] = 0;
+ strncpy(buf, text->curl->line, text->curc);
+ strcpy(buf + text->curc, text->sell->line + text->selc);
+ buf[text->curc + (text->sell->len - text->selc)] = 0;
- make_new_line(text->curl, buf);
+ make_new_line(text->curl, buf);
- tmpl = text->sell;
- while (tmpl != text->curl) {
- tmpl = tmpl->prev;
- if (!tmpl) break;
+ tmpl = text->sell;
+ while (tmpl != text->curl) {
+ tmpl = tmpl->prev;
+ if (!tmpl)
+ break;
- txt_delete_line(text, tmpl->next);
- }
+ txt_delete_line(text, tmpl->next);
+ }
- text->sell = text->curl;
- text->selc = text->curc;
+ text->sell = text->curl;
+ text->selc = text->curc;
}
void txt_sel_all(Text *text)
{
- text->curl = text->lines.first;
- text->curc = 0;
+ text->curl = text->lines.first;
+ text->curc = 0;
- text->sell = text->lines.last;
- text->selc = text->sell->len;
+ text->sell = text->lines.last;
+ text->selc = text->sell->len;
}
/**
@@ -1171,19 +1250,20 @@ void txt_sel_all(Text *text)
*/
void txt_sel_clear(Text *text)
{
- if (text->sell) {
- text->curl = text->sell;
- text->curc = text->selc;
- }
+ if (text->sell) {
+ text->curl = text->sell;
+ text->curc = text->selc;
+ }
}
void txt_sel_line(Text *text)
{
- if (!text->curl) return;
+ if (!text->curl)
+ return;
- text->curc = 0;
- text->sell = text->curl;
- text->selc = text->sell->len;
+ text->curc = 0;
+ text->sell = text->curl;
+ text->selc = text->sell->len;
}
/***************************/
@@ -1192,240 +1272,251 @@ void txt_sel_line(Text *text)
char *txt_to_buf(Text *text)
{
- int length;
- TextLine *tmp, *linef, *linel;
- int charf, charl;
- char *buf;
+ int length;
+ TextLine *tmp, *linef, *linel;
+ int charf, charl;
+ char *buf;
- if (!text->curl) return NULL;
- if (!text->sell) return NULL;
- if (!text->lines.first) return NULL;
+ if (!text->curl)
+ return NULL;
+ if (!text->sell)
+ return NULL;
+ if (!text->lines.first)
+ return NULL;
- linef = text->lines.first;
- charf = 0;
+ linef = text->lines.first;
+ charf = 0;
- linel = text->lines.last;
- charl = linel->len;
+ linel = text->lines.last;
+ charl = linel->len;
- if (linef == text->lines.last) {
- length = charl - charf;
+ if (linef == text->lines.last) {
+ length = charl - charf;
- buf = MEM_mallocN(length + 2, "text buffer");
+ buf = MEM_mallocN(length + 2, "text buffer");
- BLI_strncpy(buf, linef->line + charf, length + 1);
- buf[length] = 0;
- }
- else {
- length = linef->len - charf;
- length += charl;
- length += 2; /* For the 2 '\n' */
+ BLI_strncpy(buf, linef->line + charf, length + 1);
+ buf[length] = 0;
+ }
+ else {
+ length = linef->len - charf;
+ length += charl;
+ length += 2; /* For the 2 '\n' */
- tmp = linef->next;
- while (tmp && tmp != linel) {
- length += tmp->len + 1;
- tmp = tmp->next;
- }
+ tmp = linef->next;
+ while (tmp && tmp != linel) {
+ length += tmp->len + 1;
+ tmp = tmp->next;
+ }
- buf = MEM_mallocN(length + 1, "cut buffer");
+ buf = MEM_mallocN(length + 1, "cut buffer");
- strncpy(buf, linef->line + charf, linef->len - charf);
- length = linef->len - charf;
+ strncpy(buf, linef->line + charf, linef->len - charf);
+ length = linef->len - charf;
- buf[length++] = '\n';
+ buf[length++] = '\n';
- tmp = linef->next;
- while (tmp && tmp != linel) {
- strncpy(buf + length, tmp->line, tmp->len);
- length += tmp->len;
+ tmp = linef->next;
+ while (tmp && tmp != linel) {
+ strncpy(buf + length, tmp->line, tmp->len);
+ length += tmp->len;
- buf[length++] = '\n';
+ buf[length++] = '\n';
- tmp = tmp->next;
- }
- strncpy(buf + length, linel->line, charl);
- length += charl;
+ tmp = tmp->next;
+ }
+ strncpy(buf + length, linel->line, charl);
+ length += charl;
- /* python compiler wants an empty end line */
- buf[length++] = '\n';
- buf[length] = 0;
- }
+ /* python compiler wants an empty end line */
+ buf[length++] = '\n';
+ buf[length] = 0;
+ }
- return buf;
+ return buf;
}
int txt_find_string(Text *text, const char *findstr, int wrap, int match_case)
{
- TextLine *tl, *startl;
- const char *s = NULL;
-
- if (!text->curl || !text->sell) return 0;
-
- txt_order_cursors(text, false);
-
- tl = startl = text->sell;
-
- if (match_case) s = strstr(&tl->line[text->selc], findstr);
- else s = BLI_strcasestr(&tl->line[text->selc], findstr);
- while (!s) {
- tl = tl->next;
- if (!tl) {
- if (wrap)
- tl = text->lines.first;
- else
- break;
- }
-
- if (match_case) s = strstr(tl->line, findstr);
- else s = BLI_strcasestr(tl->line, findstr);
- if (tl == startl)
- break;
- }
-
- if (s) {
- int newl = txt_get_span(text->lines.first, tl);
- int newc = (int)(s - tl->line);
- txt_move_to(text, newl, newc, 0);
- txt_move_to(text, newl, newc + strlen(findstr), 1);
- return 1;
- }
- else
- return 0;
+ TextLine *tl, *startl;
+ const char *s = NULL;
+
+ if (!text->curl || !text->sell)
+ return 0;
+
+ txt_order_cursors(text, false);
+
+ tl = startl = text->sell;
+
+ if (match_case)
+ s = strstr(&tl->line[text->selc], findstr);
+ else
+ s = BLI_strcasestr(&tl->line[text->selc], findstr);
+ while (!s) {
+ tl = tl->next;
+ if (!tl) {
+ if (wrap)
+ tl = text->lines.first;
+ else
+ break;
+ }
+
+ if (match_case)
+ s = strstr(tl->line, findstr);
+ else
+ s = BLI_strcasestr(tl->line, findstr);
+ if (tl == startl)
+ break;
+ }
+
+ if (s) {
+ int newl = txt_get_span(text->lines.first, tl);
+ int newc = (int)(s - tl->line);
+ txt_move_to(text, newl, newc, 0);
+ txt_move_to(text, newl, newc + strlen(findstr), 1);
+ return 1;
+ }
+ else
+ return 0;
}
char *txt_sel_to_buf(Text *text)
{
- char *buf;
- int length = 0;
- TextLine *tmp, *linef, *linel;
- int charf, charl;
+ char *buf;
+ int length = 0;
+ TextLine *tmp, *linef, *linel;
+ int charf, charl;
- if (!text->curl) return NULL;
- if (!text->sell) return NULL;
+ if (!text->curl)
+ return NULL;
+ if (!text->sell)
+ return NULL;
- if (text->curl == text->sell) {
- linef = linel = text->curl;
+ if (text->curl == text->sell) {
+ linef = linel = text->curl;
- if (text->curc < text->selc) {
- charf = text->curc;
- charl = text->selc;
- }
- else {
- charf = text->selc;
- charl = text->curc;
- }
- }
- else if (txt_get_span(text->curl, text->sell) < 0) {
- linef = text->sell;
- linel = text->curl;
+ if (text->curc < text->selc) {
+ charf = text->curc;
+ charl = text->selc;
+ }
+ else {
+ charf = text->selc;
+ charl = text->curc;
+ }
+ }
+ else if (txt_get_span(text->curl, text->sell) < 0) {
+ linef = text->sell;
+ linel = text->curl;
- charf = text->selc;
- charl = text->curc;
- }
- else {
- linef = text->curl;
- linel = text->sell;
+ charf = text->selc;
+ charl = text->curc;
+ }
+ else {
+ linef = text->curl;
+ linel = text->sell;
- charf = text->curc;
- charl = text->selc;
- }
+ charf = text->curc;
+ charl = text->selc;
+ }
- if (linef == linel) {
- length = charl - charf;
+ if (linef == linel) {
+ length = charl - charf;
- buf = MEM_mallocN(length + 1, "sel buffer");
+ buf = MEM_mallocN(length + 1, "sel buffer");
- BLI_strncpy(buf, linef->line + charf, length + 1);
- }
- else {
- length += linef->len - charf;
- length += charl;
- length++; /* For the '\n' */
+ BLI_strncpy(buf, linef->line + charf, length + 1);
+ }
+ else {
+ length += linef->len - charf;
+ length += charl;
+ length++; /* For the '\n' */
- tmp = linef->next;
- while (tmp && tmp != linel) {
- length += tmp->len + 1;
- tmp = tmp->next;
- }
+ tmp = linef->next;
+ while (tmp && tmp != linel) {
+ length += tmp->len + 1;
+ tmp = tmp->next;
+ }
- buf = MEM_mallocN(length + 1, "sel buffer");
+ buf = MEM_mallocN(length + 1, "sel buffer");
- strncpy(buf, linef->line + charf, linef->len - charf);
- length = linef->len - charf;
+ strncpy(buf, linef->line + charf, linef->len - charf);
+ length = linef->len - charf;
- buf[length++] = '\n';
+ buf[length++] = '\n';
- tmp = linef->next;
- while (tmp && tmp != linel) {
- strncpy(buf + length, tmp->line, tmp->len);
- length += tmp->len;
+ tmp = linef->next;
+ while (tmp && tmp != linel) {
+ strncpy(buf + length, tmp->line, tmp->len);
+ length += tmp->len;
- buf[length++] = '\n';
+ buf[length++] = '\n';
- tmp = tmp->next;
- }
- strncpy(buf + length, linel->line, charl);
- length += charl;
+ tmp = tmp->next;
+ }
+ strncpy(buf + length, linel->line, charl);
+ length += charl;
- buf[length] = 0;
- }
+ buf[length] = 0;
+ }
- return buf;
+ return buf;
}
void txt_insert_buf(Text *text, TextUndoBuf *utxt, const char *in_buffer)
{
- const bool undoing_orig = undoing;
- int l = 0, len;
- size_t i = 0, j;
- TextLine *add;
- char *buffer;
-
- if (!in_buffer) return;
-
- txt_delete_sel(text, utxt);
-
- len = strlen(in_buffer);
- buffer = BLI_strdupn(in_buffer, len);
- len += txt_extended_ascii_as_utf8(&buffer);
-
- if (!undoing) {
- txt_undo_add_blockop(text, utxt, UNDO_IBLOCK, buffer);
- }
- undoing = true;
-
- /* Read the first line (or as close as possible */
- while (buffer[i] && buffer[i] != '\n') {
- txt_add_raw_char(text, utxt, BLI_str_utf8_as_unicode_step(buffer, &i));
- }
-
- if (buffer[i] == '\n') {
- txt_split_curline(text, utxt);
- i++;
-
- while (i < len) {
- l = 0;
-
- while (buffer[i] && buffer[i] != '\n') {
- i++;
- l++;
- }
-
- if (buffer[i] == '\n') {
- add = txt_new_linen(buffer + (i - l), l);
- BLI_insertlinkbefore(&text->lines, text->curl, add);
- i++;
- }
- else {
- for (j = i - l; j < i && j < len; ) {
- txt_add_raw_char(text, utxt, BLI_str_utf8_as_unicode_step(buffer, &j));
- }
- break;
- }
- }
- }
-
- MEM_freeN(buffer);
- undoing = undoing_orig;
+ const bool undoing_orig = undoing;
+ int l = 0, len;
+ size_t i = 0, j;
+ TextLine *add;
+ char *buffer;
+
+ if (!in_buffer)
+ return;
+
+ txt_delete_sel(text, utxt);
+
+ len = strlen(in_buffer);
+ buffer = BLI_strdupn(in_buffer, len);
+ len += txt_extended_ascii_as_utf8(&buffer);
+
+ if (!undoing) {
+ txt_undo_add_blockop(text, utxt, UNDO_IBLOCK, buffer);
+ }
+ undoing = true;
+
+ /* Read the first line (or as close as possible */
+ while (buffer[i] && buffer[i] != '\n') {
+ txt_add_raw_char(text, utxt, BLI_str_utf8_as_unicode_step(buffer, &i));
+ }
+
+ if (buffer[i] == '\n') {
+ txt_split_curline(text, utxt);
+ i++;
+
+ while (i < len) {
+ l = 0;
+
+ while (buffer[i] && buffer[i] != '\n') {
+ i++;
+ l++;
+ }
+
+ if (buffer[i] == '\n') {
+ add = txt_new_linen(buffer + (i - l), l);
+ BLI_insertlinkbefore(&text->lines, text->curl, add);
+ i++;
+ }
+ else {
+ for (j = i - l; j < i && j < len;) {
+ txt_add_raw_char(text, utxt, BLI_str_utf8_as_unicode_step(buffer, &j));
+ }
+ break;
+ }
+ }
+ }
+
+ MEM_freeN(buffer);
+ undoing = undoing_orig;
}
/******************/
@@ -1434,32 +1525,32 @@ void txt_insert_buf(Text *text, TextUndoBuf *utxt, const char *in_buffer)
static bool max_undo_test(TextUndoBuf *utxt, int x)
{
- /* Normally over-allocating is preferred,
- * however in this case the buffer is small enough and re-allocation
- * fast enough for each undo step that it's not a problem to allocate each time.
- * This also saves on some memory when we have many text buffers
- * that would have an empty undo memory allocated.
- */
-
- /* Add one for the null terminator. */
- utxt->len = utxt->pos + x + 1;
- if (utxt->len > TXT_MAX_UNDO) {
- /* XXX error("Undo limit reached, buffer cleared\n"); */
- MEM_freeN(utxt->buf);
- return false;
- }
- else {
- /* Small reallocations on each undo step is fine. */
- utxt->buf = MEM_recallocN(utxt->buf, utxt->len);
- }
- return true;
+ /* Normally over-allocating is preferred,
+ * however in this case the buffer is small enough and re-allocation
+ * fast enough for each undo step that it's not a problem to allocate each time.
+ * This also saves on some memory when we have many text buffers
+ * that would have an empty undo memory allocated.
+ */
+
+ /* Add one for the null terminator. */
+ utxt->len = utxt->pos + x + 1;
+ if (utxt->len > TXT_MAX_UNDO) {
+ /* XXX error("Undo limit reached, buffer cleared\n"); */
+ MEM_freeN(utxt->buf);
+ return false;
+ }
+ else {
+ /* Small reallocations on each undo step is fine. */
+ utxt->buf = MEM_recallocN(utxt->buf, utxt->len);
+ }
+ return true;
}
static void txt_undo_end(Text *UNUSED(text), TextUndoBuf *utxt)
{
- int undo_pos_end = utxt->pos + 1;
- BLI_assert(undo_pos_end + 1 == utxt->len);
- utxt->buf[undo_pos_end] = '\0';
+ int undo_pos_end = utxt->pos + 1;
+ BLI_assert(undo_pos_end + 1 == utxt->len);
+ utxt->buf[undo_pos_end] = '\0';
}
/* Call once undo is done. */
@@ -1467,923 +1558,963 @@ static void txt_undo_end(Text *UNUSED(text), TextUndoBuf *utxt)
#endif
-#if 0 /* UNUSED */
+#if 0 /* UNUSED */
static void dump_buffer(TextUndoBuf *utxt)
{
- int i = 0;
+ int i = 0;
- while (i++ < utxt->undo_pos) printf("%d: %d %c\n", i, utxt->buf[i], utxt->buf[i]);
+ while (i++ < utxt->undo_pos) printf("%d: %d %c\n", i, utxt->buf[i], utxt->buf[i]);
}
/* Note: this function is outdated and must be updated if needed for future use */
void txt_print_undo(Text *text)
{
- int i = 0;
- int op;
- const char *ops;
- int linep, charp;
-
- dump_buffer(text);
-
- printf("---< Undo Buffer >---\n");
-
- printf("UndoPosition is %d\n", utxt->pos);
-
- while (i <= utxt->pos) {
- op = utxt->buf[i];
-
- if (op == UNDO_INSERT_1) {
- ops = "Insert ascii ";
- }
- else if (op == UNDO_INSERT_2) {
- ops = "Insert 2 bytes ";
- }
- else if (op == UNDO_INSERT_3) {
- ops = "Insert 3 bytes ";
- }
- else if (op == UNDO_INSERT_4) {
- ops = "Insert unicode ";
- }
- else if (op == UNDO_BS_1) {
- ops = "Backspace for ascii ";
- }
- else if (op == UNDO_BS_2) {
- ops = "Backspace for 2 bytes ";
- }
- else if (op == UNDO_BS_3) {
- ops = "Backspace for 3 bytes ";
- }
- else if (op == UNDO_BS_4) {
- ops = "Backspace for unicode ";
- }
- else if (op == UNDO_DEL_1) {
- ops = "Delete ascii ";
- }
- else if (op == UNDO_DEL_2) {
- ops = "Delete 2 bytes ";
- }
- else if (op == UNDO_DEL_3) {
- ops = "Delete 3 bytes ";
- }
- else if (op == UNDO_DEL_4) {
- ops = "Delete unicode ";
- }
- else if (op == UNDO_DBLOCK) {
- ops = "Delete text block";
- }
- else if (op == UNDO_IBLOCK) {
- ops = "Insert text block";
- }
- else if (op == UNDO_INDENT) {
- ops = "Indent ";
- }
- else if (op == UNDO_UNINDENT) {
- ops = "Unindent ";
- }
- else if (op == UNDO_COMMENT) {
- ops = "Comment ";
- }
- else if (op == UNDO_UNCOMMENT) {
- ops = "Uncomment ";
- }
- else {
- ops = "Unknown";
- }
-
- printf("Op (%o) at %d = %s", op, i, ops);
- if (op >= UNDO_INSERT_1 && op <= UNDO_DEL_4) {
- i++;
- printf(" - Char is ");
- switch (op) {
- case UNDO_INSERT_1: case UNDO_BS_1: case UNDO_DEL_1:
- printf("%c", utxt->buf[i]);
- i++;
- break;
- case UNDO_INSERT_2: case UNDO_BS_2: case UNDO_DEL_2:
- printf("%c%c", utxt->buf[i], utxt->buf[i + 1]);
- i += 2;
- break;
- case UNDO_INSERT_3: case UNDO_BS_3: case UNDO_DEL_3:
- printf("%c%c%c", utxt->buf[i], utxt->buf[i + 1], utxt->buf[i + 2]);
- i += 3;
- break;
- case UNDO_INSERT_4: case UNDO_BS_4: case UNDO_DEL_4:
- {
- unsigned int uc;
- char c[BLI_UTF8_MAX + 1];
- size_t c_len;
- uc = utxt->buf[i]; i++;
- uc = uc + (utxt->buf[i] << 8); i++;
- uc = uc + (utxt->buf[i] << 16); i++;
- uc = uc + (utxt->buf[i] << 24); i++;
- c_len = BLI_str_utf8_from_unicode(uc, c);
- c[c_len] = '\0';
- puts(c);
- break;
- }
- }
- }
- else if (op == UNDO_DBLOCK || op == UNDO_IBLOCK) {
- i++;
-
- linep = utxt->buf[i]; i++;
- linep = linep + (utxt->buf[i] << 8); i++;
- linep = linep + (utxt->buf[i] << 16); i++;
- linep = linep + (utxt->buf[i] << 24); i++;
-
- printf(" (length %d) <", linep);
-
- while (linep > 0) {
- putchar(utxt->buf[i]);
- linep--; i++;
- }
-
- linep = utxt->buf[i]; i++;
- linep = linep + (utxt->buf[i] << 8); i++;
- linep = linep + (utxt->buf[i] << 16); i++;
- linep = linep + (utxt->buf[i] << 24); i++;
- printf("> (%d)", linep);
- }
- else if (op == UNDO_INDENT || op == UNDO_UNINDENT) {
- i++;
-
- charp = utxt->buf[i]; i++;
- charp = charp + (utxt->buf[i] << 8); i++;
-
- linep = utxt->buf[i]; i++;
- linep = linep + (utxt->buf[i] << 8); i++;
- linep = linep + (utxt->buf[i] << 16); i++;
- linep = linep + (utxt->buf[i] << 24); i++;
-
- printf("to <%d, %d> ", linep, charp);
-
- charp = utxt->buf[i]; i++;
- charp = charp + (utxt->buf[i] << 8); i++;
-
- linep = utxt->buf[i]; i++;
- linep = linep + (utxt->buf[i] << 8); i++;
- linep = linep + (utxt->buf[i] << 16); i++;
- linep = linep + (utxt->buf[i] << 24); i++;
-
- printf("from <%d, %d>", linep, charp);
- }
-
- printf(" %d\n", i);
- i++;
- }
+ int i = 0;
+ int op;
+ const char *ops;
+ int linep, charp;
+
+ dump_buffer(text);
+
+ printf("---< Undo Buffer >---\n");
+
+ printf("UndoPosition is %d\n", utxt->pos);
+
+ while (i <= utxt->pos) {
+ op = utxt->buf[i];
+
+ if (op == UNDO_INSERT_1) {
+ ops = "Insert ascii ";
+ }
+ else if (op == UNDO_INSERT_2) {
+ ops = "Insert 2 bytes ";
+ }
+ else if (op == UNDO_INSERT_3) {
+ ops = "Insert 3 bytes ";
+ }
+ else if (op == UNDO_INSERT_4) {
+ ops = "Insert unicode ";
+ }
+ else if (op == UNDO_BS_1) {
+ ops = "Backspace for ascii ";
+ }
+ else if (op == UNDO_BS_2) {
+ ops = "Backspace for 2 bytes ";
+ }
+ else if (op == UNDO_BS_3) {
+ ops = "Backspace for 3 bytes ";
+ }
+ else if (op == UNDO_BS_4) {
+ ops = "Backspace for unicode ";
+ }
+ else if (op == UNDO_DEL_1) {
+ ops = "Delete ascii ";
+ }
+ else if (op == UNDO_DEL_2) {
+ ops = "Delete 2 bytes ";
+ }
+ else if (op == UNDO_DEL_3) {
+ ops = "Delete 3 bytes ";
+ }
+ else if (op == UNDO_DEL_4) {
+ ops = "Delete unicode ";
+ }
+ else if (op == UNDO_DBLOCK) {
+ ops = "Delete text block";
+ }
+ else if (op == UNDO_IBLOCK) {
+ ops = "Insert text block";
+ }
+ else if (op == UNDO_INDENT) {
+ ops = "Indent ";
+ }
+ else if (op == UNDO_UNINDENT) {
+ ops = "Unindent ";
+ }
+ else if (op == UNDO_COMMENT) {
+ ops = "Comment ";
+ }
+ else if (op == UNDO_UNCOMMENT) {
+ ops = "Uncomment ";
+ }
+ else {
+ ops = "Unknown";
+ }
+
+ printf("Op (%o) at %d = %s", op, i, ops);
+ if (op >= UNDO_INSERT_1 && op <= UNDO_DEL_4) {
+ i++;
+ printf(" - Char is ");
+ switch (op) {
+ case UNDO_INSERT_1: case UNDO_BS_1: case UNDO_DEL_1:
+ printf("%c", utxt->buf[i]);
+ i++;
+ break;
+ case UNDO_INSERT_2: case UNDO_BS_2: case UNDO_DEL_2:
+ printf("%c%c", utxt->buf[i], utxt->buf[i + 1]);
+ i += 2;
+ break;
+ case UNDO_INSERT_3: case UNDO_BS_3: case UNDO_DEL_3:
+ printf("%c%c%c", utxt->buf[i], utxt->buf[i + 1], utxt->buf[i + 2]);
+ i += 3;
+ break;
+ case UNDO_INSERT_4: case UNDO_BS_4: case UNDO_DEL_4:
+ {
+ unsigned int uc;
+ char c[BLI_UTF8_MAX + 1];
+ size_t c_len;
+ uc = utxt->buf[i]; i++;
+ uc = uc + (utxt->buf[i] << 8); i++;
+ uc = uc + (utxt->buf[i] << 16); i++;
+ uc = uc + (utxt->buf[i] << 24); i++;
+ c_len = BLI_str_utf8_from_unicode(uc, c);
+ c[c_len] = '\0';
+ puts(c);
+ break;
+ }
+ }
+ }
+ else if (op == UNDO_DBLOCK || op == UNDO_IBLOCK) {
+ i++;
+
+ linep = utxt->buf[i]; i++;
+ linep = linep + (utxt->buf[i] << 8); i++;
+ linep = linep + (utxt->buf[i] << 16); i++;
+ linep = linep + (utxt->buf[i] << 24); i++;
+
+ printf(" (length %d) <", linep);
+
+ while (linep > 0) {
+ putchar(utxt->buf[i]);
+ linep--; i++;
+ }
+
+ linep = utxt->buf[i]; i++;
+ linep = linep + (utxt->buf[i] << 8); i++;
+ linep = linep + (utxt->buf[i] << 16); i++;
+ linep = linep + (utxt->buf[i] << 24); i++;
+ printf("> (%d)", linep);
+ }
+ else if (op == UNDO_INDENT || op == UNDO_UNINDENT) {
+ i++;
+
+ charp = utxt->buf[i]; i++;
+ charp = charp + (utxt->buf[i] << 8); i++;
+
+ linep = utxt->buf[i]; i++;
+ linep = linep + (utxt->buf[i] << 8); i++;
+ linep = linep + (utxt->buf[i] << 16); i++;
+ linep = linep + (utxt->buf[i] << 24); i++;
+
+ printf("to <%d, %d> ", linep, charp);
+
+ charp = utxt->buf[i]; i++;
+ charp = charp + (utxt->buf[i] << 8); i++;
+
+ linep = utxt->buf[i]; i++;
+ linep = linep + (utxt->buf[i] << 8); i++;
+ linep = linep + (utxt->buf[i] << 16); i++;
+ linep = linep + (utxt->buf[i] << 24); i++;
+
+ printf("from <%d, %d>", linep, charp);
+ }
+
+ printf(" %d\n", i);
+ i++;
+ }
}
#endif
static void txt_undo_store_uint16(char *undo_buf, int *undo_pos, unsigned short value)
{
- undo_buf[*undo_pos] = (value) & 0xff;
- (*undo_pos)++;
- undo_buf[*undo_pos] = (value >> 8) & 0xff;
- (*undo_pos)++;
+ undo_buf[*undo_pos] = (value)&0xff;
+ (*undo_pos)++;
+ undo_buf[*undo_pos] = (value >> 8) & 0xff;
+ (*undo_pos)++;
}
static void txt_undo_store_uint32(char *undo_buf, int *undo_pos, unsigned int value)
{
- undo_buf[*undo_pos] = (value) & 0xff;
- (*undo_pos)++;
- undo_buf[*undo_pos] = (value >> 8) & 0xff;
- (*undo_pos)++;
- undo_buf[*undo_pos] = (value >> 16) & 0xff;
- (*undo_pos)++;
- undo_buf[*undo_pos] = (value >> 24) & 0xff;
- (*undo_pos)++;
+ undo_buf[*undo_pos] = (value)&0xff;
+ (*undo_pos)++;
+ undo_buf[*undo_pos] = (value >> 8) & 0xff;
+ (*undo_pos)++;
+ undo_buf[*undo_pos] = (value >> 16) & 0xff;
+ (*undo_pos)++;
+ undo_buf[*undo_pos] = (value >> 24) & 0xff;
+ (*undo_pos)++;
}
/* store the cur cursor to the undo buffer (6 bytes)*/
static void txt_undo_store_cur(Text *text, TextUndoBuf *utxt)
{
- txt_undo_store_uint16(utxt->buf, &utxt->pos, text->curc);
- txt_undo_store_uint32(utxt->buf, &utxt->pos, txt_get_span(text->lines.first, text->curl));
+ txt_undo_store_uint16(utxt->buf, &utxt->pos, text->curc);
+ txt_undo_store_uint32(utxt->buf, &utxt->pos, txt_get_span(text->lines.first, text->curl));
}
/* store the sel cursor to the undo buffer (6 bytes) */
static void txt_undo_store_sel(Text *text, TextUndoBuf *utxt)
{
- txt_undo_store_uint16(utxt->buf, &utxt->pos, text->selc);
- txt_undo_store_uint32(utxt->buf, &utxt->pos, txt_get_span(text->lines.first, text->sell));
+ txt_undo_store_uint16(utxt->buf, &utxt->pos, text->selc);
+ txt_undo_store_uint32(utxt->buf, &utxt->pos, txt_get_span(text->lines.first, text->sell));
}
/* store both cursors to the undo buffer (12 bytes) */
static void txt_undo_store_cursors(Text *text, TextUndoBuf *utxt)
{
- txt_undo_store_cur(text, utxt);
- txt_undo_store_sel(text, utxt);
+ txt_undo_store_cur(text, utxt);
+ txt_undo_store_sel(text, utxt);
}
/* store an operator along with a block of data */
static void txt_undo_add_blockop(Text *text, TextUndoBuf *utxt, int op, const char *buf)
{
- unsigned int length = strlen(buf);
-
- if (!max_undo_test(utxt, 2 + 12 + 4 + length + 4 + 1)) {
- return;
- }
- /* 2 bytes */
- utxt->pos++;
- utxt->buf[utxt->pos] = op;
- utxt->pos++;
- /* 12 bytes */
- txt_undo_store_cursors(text, utxt);
- /* 4 bytes */
- txt_undo_store_uint32(utxt->buf, &utxt->pos, length);
- /* 'length' bytes */
- memcpy(utxt->buf + utxt->pos, buf, length);
- utxt->pos += length;
- /* 4 bytes */
- txt_undo_store_uint32(utxt->buf, &utxt->pos, length);
- /* 1 byte */
- utxt->buf[utxt->pos] = op;
-
- txt_undo_end(text, utxt);
+ unsigned int length = strlen(buf);
+
+ if (!max_undo_test(utxt, 2 + 12 + 4 + length + 4 + 1)) {
+ return;
+ }
+ /* 2 bytes */
+ utxt->pos++;
+ utxt->buf[utxt->pos] = op;
+ utxt->pos++;
+ /* 12 bytes */
+ txt_undo_store_cursors(text, utxt);
+ /* 4 bytes */
+ txt_undo_store_uint32(utxt->buf, &utxt->pos, length);
+ /* 'length' bytes */
+ memcpy(utxt->buf + utxt->pos, buf, length);
+ utxt->pos += length;
+ /* 4 bytes */
+ txt_undo_store_uint32(utxt->buf, &utxt->pos, length);
+ /* 1 byte */
+ utxt->buf[utxt->pos] = op;
+
+ txt_undo_end(text, utxt);
}
/* store a regular operator */
void txt_undo_add_op(Text *text, TextUndoBuf *utxt, int op)
{
- if (!max_undo_test(utxt, 2 + 12 + 1)) {
- return;
- }
+ if (!max_undo_test(utxt, 2 + 12 + 1)) {
+ return;
+ }
- /* 2 bytes */
- utxt->pos++;
- utxt->buf[utxt->pos] = op;
- utxt->pos++;
- /* 12 bytes */
- txt_undo_store_cursors(text, utxt);
- /* 1 byte */
- utxt->buf[utxt->pos] = op;
+ /* 2 bytes */
+ utxt->pos++;
+ utxt->buf[utxt->pos] = op;
+ utxt->pos++;
+ /* 12 bytes */
+ txt_undo_store_cursors(text, utxt);
+ /* 1 byte */
+ utxt->buf[utxt->pos] = op;
- txt_undo_end(text, utxt);
+ txt_undo_end(text, utxt);
}
/* store an operator for a single character */
static void txt_undo_add_charop(Text *text, TextUndoBuf *utxt, int op_start, unsigned int c)
{
- char utf8[BLI_UTF8_MAX];
- size_t i, utf8_size = BLI_str_utf8_from_unicode(c, utf8);
-
- if (utf8_size < 4 && 0) {
- if (!max_undo_test(utxt, 2 + 6 + utf8_size + 1)) {
- return;
- }
- /* 2 bytes */
- utxt->pos++;
- utxt->buf[utxt->pos] = op_start + utf8_size - 1;
- utxt->pos++;
- /* 6 bytes */
- txt_undo_store_cur(text, utxt);
- /* 'utf8_size' bytes */
- for (i = 0; i < utf8_size; i++) {
- utxt->buf[utxt->pos] = utf8[i];
- utxt->pos++;
- }
- /* 1 byte */
- utxt->buf[utxt->pos] = op_start + utf8_size - 1;
- }
- else {
- if (!max_undo_test(utxt, 2 + 6 + 4 + 1)) {
- return;
- }
- /* 2 bytes */
- utxt->pos++;
- utxt->buf[utxt->pos] = op_start + 3;
- utxt->pos++;
- /* 6 bytes */
- txt_undo_store_cur(text, utxt);
- /* 4 bytes */
- txt_undo_store_uint32(utxt->buf, &utxt->pos, c);
- /* 1 byte */
- utxt->buf[utxt->pos] = op_start + 3;
- }
-
- txt_undo_end(text, utxt);
+ char utf8[BLI_UTF8_MAX];
+ size_t i, utf8_size = BLI_str_utf8_from_unicode(c, utf8);
+
+ if (utf8_size < 4 && 0) {
+ if (!max_undo_test(utxt, 2 + 6 + utf8_size + 1)) {
+ return;
+ }
+ /* 2 bytes */
+ utxt->pos++;
+ utxt->buf[utxt->pos] = op_start + utf8_size - 1;
+ utxt->pos++;
+ /* 6 bytes */
+ txt_undo_store_cur(text, utxt);
+ /* 'utf8_size' bytes */
+ for (i = 0; i < utf8_size; i++) {
+ utxt->buf[utxt->pos] = utf8[i];
+ utxt->pos++;
+ }
+ /* 1 byte */
+ utxt->buf[utxt->pos] = op_start + utf8_size - 1;
+ }
+ else {
+ if (!max_undo_test(utxt, 2 + 6 + 4 + 1)) {
+ return;
+ }
+ /* 2 bytes */
+ utxt->pos++;
+ utxt->buf[utxt->pos] = op_start + 3;
+ utxt->pos++;
+ /* 6 bytes */
+ txt_undo_store_cur(text, utxt);
+ /* 4 bytes */
+ txt_undo_store_uint32(utxt->buf, &utxt->pos, c);
+ /* 1 byte */
+ utxt->buf[utxt->pos] = op_start + 3;
+ }
+
+ txt_undo_end(text, utxt);
}
/* extends Link */
struct LinkInt {
- struct LinkInt *next, *prev;
- int value;
+ struct LinkInt *next, *prev;
+ int value;
};
/**
* UnindentLines points to a #ListBase composed of #LinkInt elements, listing the numbers
* of the lines that should not be indented back.
*/
-static void txt_undo_add_unprefix_op(
- Text *text, TextUndoBuf *utxt, char undo_op,
- const ListBase *line_index_mask, const int line_index_mask_len)
-{
- struct LinkInt *idata;
-
- BLI_assert(BLI_listbase_count(line_index_mask) == line_index_mask_len);
-
- /* OP byte + UInt32 count + counted UInt32 line numbers + UInt32 count + 12-bytes selection + OP byte */
- if (!max_undo_test(utxt, 2 + 4 + (line_index_mask_len * 4) + 4 + 12 + 1)) {
- return;
- }
-
- /* 2 bytes */
- utxt->pos++;
- utxt->buf[utxt->pos] = undo_op;
- utxt->pos++;
- /* Adding number of line numbers to read
- * 4 bytes */
- txt_undo_store_uint32(utxt->buf, &utxt->pos, line_index_mask_len);
-
- /* Adding linenumbers of lines that shall not be indented if undoing.
- * 'line_index_mask_len * 4' bytes */
- for (idata = line_index_mask->first; idata; idata = idata->next) {
- txt_undo_store_uint32(utxt->buf, &utxt->pos, idata->value);
- }
-
- /* Adding number of line numbers to read again.
- * 4 bytes */
- txt_undo_store_uint32(utxt->buf, &utxt->pos, line_index_mask_len);
- /* Adding current selection.
- * 12 bytes */
- txt_undo_store_cursors(text, utxt);
- /* Closing with OP (same as above).
- * 1 byte */
- utxt->buf[utxt->pos] = undo_op;
- /* Marking as last undo operation */
- txt_undo_end(text, utxt);
+static void txt_undo_add_unprefix_op(Text *text,
+ TextUndoBuf *utxt,
+ char undo_op,
+ const ListBase *line_index_mask,
+ const int line_index_mask_len)
+{
+ struct LinkInt *idata;
+
+ BLI_assert(BLI_listbase_count(line_index_mask) == line_index_mask_len);
+
+ /* OP byte + UInt32 count + counted UInt32 line numbers + UInt32 count + 12-bytes selection + OP byte */
+ if (!max_undo_test(utxt, 2 + 4 + (line_index_mask_len * 4) + 4 + 12 + 1)) {
+ return;
+ }
+
+ /* 2 bytes */
+ utxt->pos++;
+ utxt->buf[utxt->pos] = undo_op;
+ utxt->pos++;
+ /* Adding number of line numbers to read
+ * 4 bytes */
+ txt_undo_store_uint32(utxt->buf, &utxt->pos, line_index_mask_len);
+
+ /* Adding linenumbers of lines that shall not be indented if undoing.
+ * 'line_index_mask_len * 4' bytes */
+ for (idata = line_index_mask->first; idata; idata = idata->next) {
+ txt_undo_store_uint32(utxt->buf, &utxt->pos, idata->value);
+ }
+
+ /* Adding number of line numbers to read again.
+ * 4 bytes */
+ txt_undo_store_uint32(utxt->buf, &utxt->pos, line_index_mask_len);
+ /* Adding current selection.
+ * 12 bytes */
+ txt_undo_store_cursors(text, utxt);
+ /* Closing with OP (same as above).
+ * 1 byte */
+ utxt->buf[utxt->pos] = undo_op;
+ /* Marking as last undo operation */
+ txt_undo_end(text, utxt);
}
static unsigned short txt_undo_read_uint16(const char *undo_buf, int *undo_pos)
{
- unsigned short val;
- val = undo_buf[*undo_pos]; (*undo_pos)--;
- val = (val << 8) + undo_buf[*undo_pos]; (*undo_pos)--;
- return val;
+ unsigned short val;
+ val = undo_buf[*undo_pos];
+ (*undo_pos)--;
+ val = (val << 8) + undo_buf[*undo_pos];
+ (*undo_pos)--;
+ return val;
}
static unsigned int txt_undo_read_uint32(const char *undo_buf, int *undo_pos)
{
- unsigned int val;
- val = undo_buf[*undo_pos]; (*undo_pos)--;
- val = (val << 8) + undo_buf[*undo_pos]; (*undo_pos)--;
- val = (val << 8) + undo_buf[*undo_pos]; (*undo_pos)--;
- val = (val << 8) + undo_buf[*undo_pos]; (*undo_pos)--;
- return val;
+ unsigned int val;
+ val = undo_buf[*undo_pos];
+ (*undo_pos)--;
+ val = (val << 8) + undo_buf[*undo_pos];
+ (*undo_pos)--;
+ val = (val << 8) + undo_buf[*undo_pos];
+ (*undo_pos)--;
+ val = (val << 8) + undo_buf[*undo_pos];
+ (*undo_pos)--;
+ return val;
}
/* read the cur cursor from the undo buffer */
-static void txt_undo_read_cur(const char *undo_buf, int *undo_pos, unsigned int *curln, unsigned short *curc)
+static void txt_undo_read_cur(const char *undo_buf,
+ int *undo_pos,
+ unsigned int *curln,
+ unsigned short *curc)
{
- *curln = txt_undo_read_uint32(undo_buf, undo_pos);
- *curc = txt_undo_read_uint16(undo_buf, undo_pos);
+ *curln = txt_undo_read_uint32(undo_buf, undo_pos);
+ *curc = txt_undo_read_uint16(undo_buf, undo_pos);
}
/* read the sel cursor from the undo buffer */
-static void txt_undo_read_sel(const char *undo_buf, int *undo_pos, unsigned int *selln, unsigned short *selc)
+static void txt_undo_read_sel(const char *undo_buf,
+ int *undo_pos,
+ unsigned int *selln,
+ unsigned short *selc)
{
- *selln = txt_undo_read_uint32(undo_buf, undo_pos);
- *selc = txt_undo_read_uint16(undo_buf, undo_pos);
+ *selln = txt_undo_read_uint32(undo_buf, undo_pos);
+ *selc = txt_undo_read_uint16(undo_buf, undo_pos);
}
/* read both cursors from the undo buffer */
-static void txt_undo_read_cursors(const char *undo_buf, int *undo_pos,
- unsigned int *curln, unsigned short *curc,
- unsigned int *selln, unsigned short *selc)
+static void txt_undo_read_cursors(const char *undo_buf,
+ int *undo_pos,
+ unsigned int *curln,
+ unsigned short *curc,
+ unsigned int *selln,
+ unsigned short *selc)
{
- txt_undo_read_sel(undo_buf, undo_pos, selln, selc);
- txt_undo_read_cur(undo_buf, undo_pos, curln, curc);
+ txt_undo_read_sel(undo_buf, undo_pos, selln, selc);
+ txt_undo_read_cur(undo_buf, undo_pos, curln, curc);
}
static unsigned int txt_undo_read_unicode(const char *undo_buf, int *undo_pos, short bytes)
{
- unsigned int unicode;
- char utf8[BLI_UTF8_MAX + 1];
-
- switch (bytes) {
- case 1: /* ascii */
- unicode = undo_buf[*undo_pos]; (*undo_pos)--;
- break;
- case 2: /* 2-byte symbol */
- utf8[2] = '\0';
- utf8[1] = undo_buf[*undo_pos]; (*undo_pos)--;
- utf8[0] = undo_buf[*undo_pos]; (*undo_pos)--;
- unicode = BLI_str_utf8_as_unicode(utf8);
- break;
- case 3: /* 3-byte symbol */
- utf8[3] = '\0';
- utf8[2] = undo_buf[*undo_pos]; (*undo_pos)--;
- utf8[1] = undo_buf[*undo_pos]; (*undo_pos)--;
- utf8[0] = undo_buf[*undo_pos]; (*undo_pos)--;
- unicode = BLI_str_utf8_as_unicode(utf8);
- break;
- case 4: /* 32-bit unicode symbol */
- unicode = txt_undo_read_uint32(undo_buf, undo_pos);
- break;
- default:
- /* should never happen */
- BLI_assert(0);
- unicode = 0;
- break;
- }
-
- return unicode;
+ unsigned int unicode;
+ char utf8[BLI_UTF8_MAX + 1];
+
+ switch (bytes) {
+ case 1: /* ascii */
+ unicode = undo_buf[*undo_pos];
+ (*undo_pos)--;
+ break;
+ case 2: /* 2-byte symbol */
+ utf8[2] = '\0';
+ utf8[1] = undo_buf[*undo_pos];
+ (*undo_pos)--;
+ utf8[0] = undo_buf[*undo_pos];
+ (*undo_pos)--;
+ unicode = BLI_str_utf8_as_unicode(utf8);
+ break;
+ case 3: /* 3-byte symbol */
+ utf8[3] = '\0';
+ utf8[2] = undo_buf[*undo_pos];
+ (*undo_pos)--;
+ utf8[1] = undo_buf[*undo_pos];
+ (*undo_pos)--;
+ utf8[0] = undo_buf[*undo_pos];
+ (*undo_pos)--;
+ unicode = BLI_str_utf8_as_unicode(utf8);
+ break;
+ case 4: /* 32-bit unicode symbol */
+ unicode = txt_undo_read_uint32(undo_buf, undo_pos);
+ break;
+ default:
+ /* should never happen */
+ BLI_assert(0);
+ unicode = 0;
+ break;
+ }
+
+ return unicode;
}
static unsigned short txt_redo_read_uint16(const char *undo_buf, int *undo_pos)
{
- unsigned short val;
- val = undo_buf[*undo_pos]; (*undo_pos)++;
- val = val + (undo_buf[*undo_pos] << 8); (*undo_pos)++;
- return val;
+ unsigned short val;
+ val = undo_buf[*undo_pos];
+ (*undo_pos)++;
+ val = val + (undo_buf[*undo_pos] << 8);
+ (*undo_pos)++;
+ return val;
}
static unsigned int txt_redo_read_uint32(const char *undo_buf, int *undo_pos)
{
- unsigned int val;
- val = undo_buf[*undo_pos]; (*undo_pos)++;
- val = val + (undo_buf[*undo_pos] << 8); (*undo_pos)++;
- val = val + (undo_buf[*undo_pos] << 16); (*undo_pos)++;
- val = val + (undo_buf[*undo_pos] << 24); (*undo_pos)++;
- return val;
+ unsigned int val;
+ val = undo_buf[*undo_pos];
+ (*undo_pos)++;
+ val = val + (undo_buf[*undo_pos] << 8);
+ (*undo_pos)++;
+ val = val + (undo_buf[*undo_pos] << 16);
+ (*undo_pos)++;
+ val = val + (undo_buf[*undo_pos] << 24);
+ (*undo_pos)++;
+ return val;
}
/* redo read cur cursor from the undo buffer */
-static void txt_redo_read_cur(const char *undo_buf, int *undo_pos, unsigned int *curln, unsigned short *curc)
+static void txt_redo_read_cur(const char *undo_buf,
+ int *undo_pos,
+ unsigned int *curln,
+ unsigned short *curc)
{
- *curc = txt_redo_read_uint16(undo_buf, undo_pos);
- *curln = txt_redo_read_uint32(undo_buf, undo_pos);
+ *curc = txt_redo_read_uint16(undo_buf, undo_pos);
+ *curln = txt_redo_read_uint32(undo_buf, undo_pos);
}
/* redo read sel cursor from the undo buffer */
-static void txt_redo_read_sel(const char *undo_buf, int *undo_pos, unsigned int *selln, unsigned short *selc)
+static void txt_redo_read_sel(const char *undo_buf,
+ int *undo_pos,
+ unsigned int *selln,
+ unsigned short *selc)
{
- *selc = txt_redo_read_uint16(undo_buf, undo_pos);
- *selln = txt_redo_read_uint32(undo_buf, undo_pos);
+ *selc = txt_redo_read_uint16(undo_buf, undo_pos);
+ *selln = txt_redo_read_uint32(undo_buf, undo_pos);
}
/* redo read both cursors from the undo buffer */
-static void txt_redo_read_cursors(const char *undo_buf, int *undo_pos,
- unsigned int *curln, unsigned short *curc,
- unsigned int *selln, unsigned short *selc)
+static void txt_redo_read_cursors(const char *undo_buf,
+ int *undo_pos,
+ unsigned int *curln,
+ unsigned short *curc,
+ unsigned int *selln,
+ unsigned short *selc)
{
- txt_redo_read_cur(undo_buf, undo_pos, curln, curc);
- txt_redo_read_sel(undo_buf, undo_pos, selln, selc);
+ txt_redo_read_cur(undo_buf, undo_pos, curln, curc);
+ txt_redo_read_sel(undo_buf, undo_pos, selln, selc);
}
static unsigned int txt_redo_read_unicode(const char *undo_buf, int *undo_pos, short bytes)
{
- unsigned int unicode;
- char utf8[BLI_UTF8_MAX + 1];
-
- switch (bytes) {
- case 1: /* ascii */
- unicode = undo_buf[*undo_pos]; (*undo_pos)++;
- break;
- case 2: /* 2-byte symbol */
- utf8[0] = undo_buf[*undo_pos]; (*undo_pos)++;
- utf8[1] = undo_buf[*undo_pos]; (*undo_pos)++;
- utf8[2] = '\0';
- unicode = BLI_str_utf8_as_unicode(utf8);
- break;
- case 3: /* 3-byte symbol */
- utf8[0] = undo_buf[*undo_pos]; (*undo_pos)++;
- utf8[1] = undo_buf[*undo_pos]; (*undo_pos)++;
- utf8[2] = undo_buf[*undo_pos]; (*undo_pos)++;
- utf8[3] = '\0';
- unicode = BLI_str_utf8_as_unicode(utf8);
- break;
- case 4: /* 32-bit unicode symbol */
- unicode = txt_redo_read_uint32(undo_buf, undo_pos);
- break;
- default:
- /* should never happen */
- BLI_assert(0);
- unicode = 0;
- break;
- }
-
- return unicode;
+ unsigned int unicode;
+ char utf8[BLI_UTF8_MAX + 1];
+
+ switch (bytes) {
+ case 1: /* ascii */
+ unicode = undo_buf[*undo_pos];
+ (*undo_pos)++;
+ break;
+ case 2: /* 2-byte symbol */
+ utf8[0] = undo_buf[*undo_pos];
+ (*undo_pos)++;
+ utf8[1] = undo_buf[*undo_pos];
+ (*undo_pos)++;
+ utf8[2] = '\0';
+ unicode = BLI_str_utf8_as_unicode(utf8);
+ break;
+ case 3: /* 3-byte symbol */
+ utf8[0] = undo_buf[*undo_pos];
+ (*undo_pos)++;
+ utf8[1] = undo_buf[*undo_pos];
+ (*undo_pos)++;
+ utf8[2] = undo_buf[*undo_pos];
+ (*undo_pos)++;
+ utf8[3] = '\0';
+ unicode = BLI_str_utf8_as_unicode(utf8);
+ break;
+ case 4: /* 32-bit unicode symbol */
+ unicode = txt_redo_read_uint32(undo_buf, undo_pos);
+ break;
+ default:
+ /* should never happen */
+ BLI_assert(0);
+ unicode = 0;
+ break;
+ }
+
+ return unicode;
}
void txt_do_undo(Text *text, TextUndoBuf *utxt)
{
- int op = utxt->buf[utxt->pos];
- int prev_flags;
- unsigned int linep;
- unsigned int uni_char;
- unsigned int curln, selln;
- unsigned short curc, selc;
- unsigned short charp;
- char *buf;
+ int op = utxt->buf[utxt->pos];
+ int prev_flags;
+ unsigned int linep;
+ unsigned int uni_char;
+ unsigned int curln, selln;
+ unsigned short curc, selc;
+ unsigned short charp;
+ char *buf;
+
+ if (utxt->pos < 0) {
+ return;
+ }
+
+ utxt->pos--;
+
+ undoing = 1;
+
+ switch (op) {
+ case UNDO_INSERT_1:
+ case UNDO_INSERT_2:
+ case UNDO_INSERT_3:
+ case UNDO_INSERT_4:
+ utxt->pos -= op - UNDO_INSERT_1 + 1;
+
+ /* get and restore the cursors */
+ txt_undo_read_cur(utxt->buf, &utxt->pos, &curln, &curc);
+ txt_move_to(text, curln, curc, 0);
+ txt_move_to(text, curln, curc, 1);
+
+ txt_delete_char(text, utxt);
+
+ utxt->pos--;
+ break;
- if (utxt->pos < 0) {
- return;
- }
-
- utxt->pos--;
-
- undoing = 1;
-
- switch (op) {
- case UNDO_INSERT_1:
- case UNDO_INSERT_2:
- case UNDO_INSERT_3:
- case UNDO_INSERT_4:
- utxt->pos -= op - UNDO_INSERT_1 + 1;
-
- /* get and restore the cursors */
- txt_undo_read_cur(utxt->buf, &utxt->pos, &curln, &curc);
- txt_move_to(text, curln, curc, 0);
- txt_move_to(text, curln, curc, 1);
-
- txt_delete_char(text, utxt);
-
- utxt->pos--;
- break;
-
- case UNDO_BS_1:
- case UNDO_BS_2:
- case UNDO_BS_3:
- case UNDO_BS_4:
- charp = op - UNDO_BS_1 + 1;
- uni_char = txt_undo_read_unicode(utxt->buf, &utxt->pos, charp);
+ case UNDO_BS_1:
+ case UNDO_BS_2:
+ case UNDO_BS_3:
+ case UNDO_BS_4:
+ charp = op - UNDO_BS_1 + 1;
+ uni_char = txt_undo_read_unicode(utxt->buf, &utxt->pos, charp);
- /* get and restore the cursors */
- txt_undo_read_cur(utxt->buf, &utxt->pos, &curln, &curc);
- txt_move_to(text, curln, curc, 0);
- txt_move_to(text, curln, curc, 1);
-
- txt_add_char(text, utxt, uni_char);
-
- utxt->pos--;
- break;
-
- case UNDO_DEL_1:
- case UNDO_DEL_2:
- case UNDO_DEL_3:
- case UNDO_DEL_4:
- charp = op - UNDO_DEL_1 + 1;
- uni_char = txt_undo_read_unicode(utxt->buf, &utxt->pos, charp);
-
- /* get and restore the cursors */
- txt_undo_read_cur(utxt->buf, &utxt->pos, &curln, &curc);
- txt_move_to(text, curln, curc, 0);
- txt_move_to(text, curln, curc, 1);
-
- txt_add_char(text, utxt, uni_char);
-
- txt_move_left(text, 0);
-
- utxt->pos--;
- break;
-
- case UNDO_DBLOCK:
- {
- int i;
- /* length of the string in the buffer */
- linep = txt_undo_read_uint32(utxt->buf, &utxt->pos);
-
- buf = MEM_mallocN(linep + 1, "dblock buffer");
- for (i = 0; i < linep; i++) {
- buf[(linep - 1) - i] = utxt->buf[utxt->pos];
- utxt->pos--;
- }
- buf[i] = 0;
-
- /* skip over the length that was stored again */
- utxt->pos -= 4;
-
- /* Get the cursor positions */
- txt_undo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc);
-
- /* move cur to location that needs buff inserted */
- txt_move_to(text, curln, curc, 0);
-
- txt_insert_buf(text, utxt, buf);
- MEM_freeN(buf);
-
- /* restore the cursors */
- txt_move_to(text, curln, curc, 0);
- txt_move_to(text, selln, selc, 1);
-
- utxt->pos--;
-
- break;
- }
- case UNDO_IBLOCK:
- {
- int i;
- /* length of the string in the buffer */
- linep = txt_undo_read_uint32(utxt->buf, &utxt->pos);
-
- /* txt_backspace_char removes utf8-characters, not bytes */
- buf = MEM_mallocN(linep + 1, "iblock buffer");
- for (i = 0; i < linep; i++) {
- buf[(linep - 1) - i] = utxt->buf[utxt->pos];
- utxt->pos--;
- }
- buf[i] = 0;
- linep = BLI_strlen_utf8(buf);
- MEM_freeN(buf);
-
- /* skip over the length that was stored again */
- utxt->pos -= 4;
-
- /* get and restore the cursors */
- txt_undo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc);
-
- txt_move_to(text, curln, curc, 0);
- txt_move_to(text, selln, selc, 1);
-
- if ((curln == selln) && (curc == selc)) {
- /* disable tabs to spaces since moving right may involve skipping multiple spaces */
- prev_flags = text->flags;
- text->flags &= ~TXT_TABSTOSPACES;
-
- for (i = 0; i < linep; i++)
- txt_move_right(text, 1);
-
- text->flags = prev_flags;
- }
-
- txt_delete_selected(text, utxt);
-
- utxt->pos--;
- break;
- }
- case UNDO_INDENT:
- case UNDO_COMMENT:
- case UNDO_DUPLICATE:
- case UNDO_MOVE_LINES_UP:
- case UNDO_MOVE_LINES_DOWN:
- /* get and restore the cursors */
- txt_undo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc);
- txt_move_to(text, curln, curc, 0);
- txt_move_to(text, selln, selc, 1);
-
- if (op == UNDO_INDENT) {
- txt_unindent(text, utxt);
- }
- else if (op == UNDO_COMMENT) {
- txt_uncomment(text, utxt);
- }
- else if (op == UNDO_DUPLICATE) {
- txt_delete_line(text, text->curl->next);
- }
- else if (op == UNDO_MOVE_LINES_UP) {
- txt_move_lines(text, utxt, TXT_MOVE_LINE_DOWN);
- }
- else if (op == UNDO_MOVE_LINES_DOWN) {
- txt_move_lines(text, utxt, TXT_MOVE_LINE_UP);
- }
-
- utxt->pos--;
- break;
- case UNDO_UNINDENT:
- case UNDO_UNCOMMENT:
- {
- void (*txt_prefix_fn)(Text *, TextUndoBuf *);
- void (*txt_unprefix_fn)(Text *, TextUndoBuf *);
- int count;
- int i;
- /* Get and restore the cursors */
- txt_undo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc);
- txt_move_to(text, curln, curc, 0);
- txt_move_to(text, selln, selc, 1);
-
- /* Un-unindent */
- if (op == UNDO_UNINDENT) {
- txt_prefix_fn = txt_indent;
- txt_unprefix_fn = txt_unindent;
- }
- else {
- txt_prefix_fn = txt_comment;
- txt_unprefix_fn = txt_uncomment;
- }
-
- txt_prefix_fn(text, utxt);
-
- /* Get the count */
- count = txt_undo_read_uint32(utxt->buf, &utxt->pos);
- /* Iterate! */
- txt_pop_sel(text);
-
- for (i = 0; i < count; i++) {
- txt_move_to(text, txt_undo_read_uint32(utxt->buf, &utxt->pos), 0, 0);
- /* Un-un-unindent/comment */
- txt_unprefix_fn(text, utxt);
- }
- /* Restore selection */
- txt_move_to(text, curln, curc, 0);
- txt_move_to(text, selln, selc, 1);
- /* Jumo over count */
- txt_undo_read_uint32(utxt->buf, &utxt->pos);
- /* Jump over closing OP byte */
- utxt->pos--;
- break;
- }
- default:
- //XXX error("Undo buffer error - resetting");
- utxt->pos = -1;
-
- break;
- }
-
- undoing = 0;
+ /* get and restore the cursors */
+ txt_undo_read_cur(utxt->buf, &utxt->pos, &curln, &curc);
+ txt_move_to(text, curln, curc, 0);
+ txt_move_to(text, curln, curc, 1);
+
+ txt_add_char(text, utxt, uni_char);
+
+ utxt->pos--;
+ break;
+
+ case UNDO_DEL_1:
+ case UNDO_DEL_2:
+ case UNDO_DEL_3:
+ case UNDO_DEL_4:
+ charp = op - UNDO_DEL_1 + 1;
+ uni_char = txt_undo_read_unicode(utxt->buf, &utxt->pos, charp);
+
+ /* get and restore the cursors */
+ txt_undo_read_cur(utxt->buf, &utxt->pos, &curln, &curc);
+ txt_move_to(text, curln, curc, 0);
+ txt_move_to(text, curln, curc, 1);
+
+ txt_add_char(text, utxt, uni_char);
+
+ txt_move_left(text, 0);
+
+ utxt->pos--;
+ break;
+
+ case UNDO_DBLOCK: {
+ int i;
+ /* length of the string in the buffer */
+ linep = txt_undo_read_uint32(utxt->buf, &utxt->pos);
+
+ buf = MEM_mallocN(linep + 1, "dblock buffer");
+ for (i = 0; i < linep; i++) {
+ buf[(linep - 1) - i] = utxt->buf[utxt->pos];
+ utxt->pos--;
+ }
+ buf[i] = 0;
+
+ /* skip over the length that was stored again */
+ utxt->pos -= 4;
+
+ /* Get the cursor positions */
+ txt_undo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc);
+
+ /* move cur to location that needs buff inserted */
+ txt_move_to(text, curln, curc, 0);
+
+ txt_insert_buf(text, utxt, buf);
+ MEM_freeN(buf);
+
+ /* restore the cursors */
+ txt_move_to(text, curln, curc, 0);
+ txt_move_to(text, selln, selc, 1);
+
+ utxt->pos--;
+
+ break;
+ }
+ case UNDO_IBLOCK: {
+ int i;
+ /* length of the string in the buffer */
+ linep = txt_undo_read_uint32(utxt->buf, &utxt->pos);
+
+ /* txt_backspace_char removes utf8-characters, not bytes */
+ buf = MEM_mallocN(linep + 1, "iblock buffer");
+ for (i = 0; i < linep; i++) {
+ buf[(linep - 1) - i] = utxt->buf[utxt->pos];
+ utxt->pos--;
+ }
+ buf[i] = 0;
+ linep = BLI_strlen_utf8(buf);
+ MEM_freeN(buf);
+
+ /* skip over the length that was stored again */
+ utxt->pos -= 4;
+
+ /* get and restore the cursors */
+ txt_undo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc);
+
+ txt_move_to(text, curln, curc, 0);
+ txt_move_to(text, selln, selc, 1);
+
+ if ((curln == selln) && (curc == selc)) {
+ /* disable tabs to spaces since moving right may involve skipping multiple spaces */
+ prev_flags = text->flags;
+ text->flags &= ~TXT_TABSTOSPACES;
+
+ for (i = 0; i < linep; i++)
+ txt_move_right(text, 1);
+
+ text->flags = prev_flags;
+ }
+
+ txt_delete_selected(text, utxt);
+
+ utxt->pos--;
+ break;
+ }
+ case UNDO_INDENT:
+ case UNDO_COMMENT:
+ case UNDO_DUPLICATE:
+ case UNDO_MOVE_LINES_UP:
+ case UNDO_MOVE_LINES_DOWN:
+ /* get and restore the cursors */
+ txt_undo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc);
+ txt_move_to(text, curln, curc, 0);
+ txt_move_to(text, selln, selc, 1);
+
+ if (op == UNDO_INDENT) {
+ txt_unindent(text, utxt);
+ }
+ else if (op == UNDO_COMMENT) {
+ txt_uncomment(text, utxt);
+ }
+ else if (op == UNDO_DUPLICATE) {
+ txt_delete_line(text, text->curl->next);
+ }
+ else if (op == UNDO_MOVE_LINES_UP) {
+ txt_move_lines(text, utxt, TXT_MOVE_LINE_DOWN);
+ }
+ else if (op == UNDO_MOVE_LINES_DOWN) {
+ txt_move_lines(text, utxt, TXT_MOVE_LINE_UP);
+ }
+
+ utxt->pos--;
+ break;
+ case UNDO_UNINDENT:
+ case UNDO_UNCOMMENT: {
+ void (*txt_prefix_fn)(Text *, TextUndoBuf *);
+ void (*txt_unprefix_fn)(Text *, TextUndoBuf *);
+ int count;
+ int i;
+ /* Get and restore the cursors */
+ txt_undo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc);
+ txt_move_to(text, curln, curc, 0);
+ txt_move_to(text, selln, selc, 1);
+
+ /* Un-unindent */
+ if (op == UNDO_UNINDENT) {
+ txt_prefix_fn = txt_indent;
+ txt_unprefix_fn = txt_unindent;
+ }
+ else {
+ txt_prefix_fn = txt_comment;
+ txt_unprefix_fn = txt_uncomment;
+ }
+
+ txt_prefix_fn(text, utxt);
+
+ /* Get the count */
+ count = txt_undo_read_uint32(utxt->buf, &utxt->pos);
+ /* Iterate! */
+ txt_pop_sel(text);
+
+ for (i = 0; i < count; i++) {
+ txt_move_to(text, txt_undo_read_uint32(utxt->buf, &utxt->pos), 0, 0);
+ /* Un-un-unindent/comment */
+ txt_unprefix_fn(text, utxt);
+ }
+ /* Restore selection */
+ txt_move_to(text, curln, curc, 0);
+ txt_move_to(text, selln, selc, 1);
+ /* Jumo over count */
+ txt_undo_read_uint32(utxt->buf, &utxt->pos);
+ /* Jump over closing OP byte */
+ utxt->pos--;
+ break;
+ }
+ default:
+ //XXX error("Undo buffer error - resetting");
+ utxt->pos = -1;
+
+ break;
+ }
+
+ undoing = 0;
}
void txt_do_redo(Text *text, TextUndoBuf *utxt)
{
- char op;
- char *buf;
- unsigned int linep;
- unsigned short charp;
- unsigned int uni_uchar;
- unsigned int curln, selln;
- unsigned short curc, selc;
+ char op;
+ char *buf;
+ unsigned int linep;
+ unsigned short charp;
+ unsigned int uni_uchar;
+ unsigned int curln, selln;
+ unsigned short curc, selc;
- utxt->pos++;
- op = utxt->buf[utxt->pos];
+ utxt->pos++;
+ op = utxt->buf[utxt->pos];
- if (!op) {
- utxt->pos--;
- return;
- }
+ if (!op) {
+ utxt->pos--;
+ return;
+ }
- undoing = 1;
+ undoing = 1;
- switch (op) {
- case UNDO_INSERT_1:
- case UNDO_INSERT_2:
- case UNDO_INSERT_3:
- case UNDO_INSERT_4:
- utxt->pos++;
+ switch (op) {
+ case UNDO_INSERT_1:
+ case UNDO_INSERT_2:
+ case UNDO_INSERT_3:
+ case UNDO_INSERT_4:
+ utxt->pos++;
- /* get and restore the cursors */
- txt_redo_read_cur(utxt->buf, &utxt->pos, &curln, &curc);
- txt_move_to(text, curln, curc, 0);
- txt_move_to(text, curln, curc, 1);
+ /* get and restore the cursors */
+ txt_redo_read_cur(utxt->buf, &utxt->pos, &curln, &curc);
+ txt_move_to(text, curln, curc, 0);
+ txt_move_to(text, curln, curc, 1);
- charp = op - UNDO_INSERT_1 + 1;
- uni_uchar = txt_redo_read_unicode(utxt->buf, &utxt->pos, charp);
+ charp = op - UNDO_INSERT_1 + 1;
+ uni_uchar = txt_redo_read_unicode(utxt->buf, &utxt->pos, charp);
- txt_add_char(text, utxt, uni_uchar);
- break;
+ txt_add_char(text, utxt, uni_uchar);
+ break;
- case UNDO_BS_1:
- case UNDO_BS_2:
- case UNDO_BS_3:
- case UNDO_BS_4:
- utxt->pos++;
+ case UNDO_BS_1:
+ case UNDO_BS_2:
+ case UNDO_BS_3:
+ case UNDO_BS_4:
+ utxt->pos++;
- /* get and restore the cursors */
- txt_redo_read_cur(utxt->buf, &utxt->pos, &curln, &curc);
- txt_move_to(text, curln, curc, 0);
- txt_move_to(text, curln, curc, 1);
-
- utxt->pos += op - UNDO_BS_1 + 1;
-
- /* move right so we backspace the correct char */
- txt_move_right(text, 0);
- txt_backspace_char(text, utxt);
-
- break;
-
- case UNDO_DEL_1:
- case UNDO_DEL_2:
- case UNDO_DEL_3:
- case UNDO_DEL_4:
- utxt->pos++;
-
- /* get and restore the cursors */
- txt_redo_read_cur(utxt->buf, &utxt->pos, &curln, &curc);
- txt_move_to(text, curln, curc, 0);
- txt_move_to(text, curln, curc, 1);
-
- utxt->pos += op - UNDO_DEL_1 + 1;
-
- txt_delete_char(text, utxt);
-
- break;
-
- case UNDO_DBLOCK:
- utxt->pos++;
-
- /* get and restore the cursors */
- txt_redo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc);
- txt_move_to(text, curln, curc, 0);
- txt_move_to(text, selln, selc, 1);
-
- /* length of the block */
- linep = txt_redo_read_uint32(utxt->buf, &utxt->pos);
-
- utxt->pos += linep;
-
- /* skip over the length that was stored again */
- utxt->pos += 4;
-
- txt_delete_sel(text, utxt);
-
- break;
-
- case UNDO_IBLOCK:
- utxt->pos++;
-
- /* get and restore the cursors */
- txt_redo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc);
- txt_move_to(text, curln, curc, 0);
- txt_move_to(text, curln, curc, 1);
-
- /* length of the block */
- linep = txt_redo_read_uint32(utxt->buf, &utxt->pos);
-
- buf = MEM_mallocN(linep + 1, "iblock buffer");
- memcpy(buf, &utxt->buf[utxt->pos], linep);
- utxt->pos += linep;
- buf[linep] = 0;
-
- txt_insert_buf(text, utxt, buf);
- MEM_freeN(buf);
-
- /* skip over the length that was stored again */
- utxt->pos += 4;
-
- break;
-
- case UNDO_INDENT:
- case UNDO_COMMENT:
- case UNDO_UNCOMMENT:
- case UNDO_DUPLICATE:
- case UNDO_MOVE_LINES_UP:
- case UNDO_MOVE_LINES_DOWN:
- utxt->pos++;
-
- /* get and restore the cursors */
- txt_redo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc);
- txt_move_to(text, curln, curc, 0);
- txt_move_to(text, selln, selc, 1);
-
- if (op == UNDO_INDENT) {
- txt_indent(text, utxt);
- }
- else if (op == UNDO_COMMENT) {
- txt_comment(text, utxt);
- }
- else if (op == UNDO_UNCOMMENT) {
- txt_uncomment(text, utxt);
- }
- else if (op == UNDO_DUPLICATE) {
- txt_duplicate_line(text, utxt);
- }
- else if (op == UNDO_MOVE_LINES_UP) {
- /* offset the cursor by + 1 */
- txt_move_to(text, curln + 1, curc, 0);
- txt_move_to(text, selln + 1, selc, 1);
-
- txt_move_lines(text, utxt, TXT_MOVE_LINE_UP);
- }
- else if (op == UNDO_MOVE_LINES_DOWN) {
- /* offset the cursor by - 1 */
- txt_move_to(text, curln - 1, curc, 0);
- txt_move_to(text, selln - 1, selc, 1);
-
- txt_move_lines(text, utxt, TXT_MOVE_LINE_DOWN);
- }
-
- /* re-restore the cursors since they got moved when redoing */
- txt_move_to(text, curln, curc, 0);
- txt_move_to(text, selln, selc, 1);
-
- break;
- case UNDO_UNINDENT:
- {
- int count;
- int i;
-
- utxt->pos++;
- /* Scan all the stuff described in txt_undo_add_unindent_op */
- count = txt_redo_read_uint32(utxt->buf, &utxt->pos);
- for (i = 0; i < count; i++) {
- txt_redo_read_uint32(utxt->buf, &utxt->pos);
- }
- /* Count again */
- txt_redo_read_uint32(utxt->buf, &utxt->pos);
- /* Get the selection and re-unindent */
- txt_redo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc);
- txt_move_to(text, curln, curc, 0);
- txt_move_to(text, selln, selc, 1);
- txt_unindent(text, utxt);
- break;
- }
- default:
- //XXX error("Undo buffer error - resetting");
- utxt->pos = -1;
-
- break;
- }
-
- undoing = 0;
+ /* get and restore the cursors */
+ txt_redo_read_cur(utxt->buf, &utxt->pos, &curln, &curc);
+ txt_move_to(text, curln, curc, 0);
+ txt_move_to(text, curln, curc, 1);
+
+ utxt->pos += op - UNDO_BS_1 + 1;
+
+ /* move right so we backspace the correct char */
+ txt_move_right(text, 0);
+ txt_backspace_char(text, utxt);
+
+ break;
+
+ case UNDO_DEL_1:
+ case UNDO_DEL_2:
+ case UNDO_DEL_3:
+ case UNDO_DEL_4:
+ utxt->pos++;
+
+ /* get and restore the cursors */
+ txt_redo_read_cur(utxt->buf, &utxt->pos, &curln, &curc);
+ txt_move_to(text, curln, curc, 0);
+ txt_move_to(text, curln, curc, 1);
+
+ utxt->pos += op - UNDO_DEL_1 + 1;
+
+ txt_delete_char(text, utxt);
+
+ break;
+
+ case UNDO_DBLOCK:
+ utxt->pos++;
+
+ /* get and restore the cursors */
+ txt_redo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc);
+ txt_move_to(text, curln, curc, 0);
+ txt_move_to(text, selln, selc, 1);
+
+ /* length of the block */
+ linep = txt_redo_read_uint32(utxt->buf, &utxt->pos);
+
+ utxt->pos += linep;
+
+ /* skip over the length that was stored again */
+ utxt->pos += 4;
+
+ txt_delete_sel(text, utxt);
+
+ break;
+
+ case UNDO_IBLOCK:
+ utxt->pos++;
+
+ /* get and restore the cursors */
+ txt_redo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc);
+ txt_move_to(text, curln, curc, 0);
+ txt_move_to(text, curln, curc, 1);
+
+ /* length of the block */
+ linep = txt_redo_read_uint32(utxt->buf, &utxt->pos);
+
+ buf = MEM_mallocN(linep + 1, "iblock buffer");
+ memcpy(buf, &utxt->buf[utxt->pos], linep);
+ utxt->pos += linep;
+ buf[linep] = 0;
+
+ txt_insert_buf(text, utxt, buf);
+ MEM_freeN(buf);
+
+ /* skip over the length that was stored again */
+ utxt->pos += 4;
+
+ break;
+
+ case UNDO_INDENT:
+ case UNDO_COMMENT:
+ case UNDO_UNCOMMENT:
+ case UNDO_DUPLICATE:
+ case UNDO_MOVE_LINES_UP:
+ case UNDO_MOVE_LINES_DOWN:
+ utxt->pos++;
+
+ /* get and restore the cursors */
+ txt_redo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc);
+ txt_move_to(text, curln, curc, 0);
+ txt_move_to(text, selln, selc, 1);
+
+ if (op == UNDO_INDENT) {
+ txt_indent(text, utxt);
+ }
+ else if (op == UNDO_COMMENT) {
+ txt_comment(text, utxt);
+ }
+ else if (op == UNDO_UNCOMMENT) {
+ txt_uncomment(text, utxt);
+ }
+ else if (op == UNDO_DUPLICATE) {
+ txt_duplicate_line(text, utxt);
+ }
+ else if (op == UNDO_MOVE_LINES_UP) {
+ /* offset the cursor by + 1 */
+ txt_move_to(text, curln + 1, curc, 0);
+ txt_move_to(text, selln + 1, selc, 1);
+
+ txt_move_lines(text, utxt, TXT_MOVE_LINE_UP);
+ }
+ else if (op == UNDO_MOVE_LINES_DOWN) {
+ /* offset the cursor by - 1 */
+ txt_move_to(text, curln - 1, curc, 0);
+ txt_move_to(text, selln - 1, selc, 1);
+
+ txt_move_lines(text, utxt, TXT_MOVE_LINE_DOWN);
+ }
+
+ /* re-restore the cursors since they got moved when redoing */
+ txt_move_to(text, curln, curc, 0);
+ txt_move_to(text, selln, selc, 1);
+
+ break;
+ case UNDO_UNINDENT: {
+ int count;
+ int i;
+
+ utxt->pos++;
+ /* Scan all the stuff described in txt_undo_add_unindent_op */
+ count = txt_redo_read_uint32(utxt->buf, &utxt->pos);
+ for (i = 0; i < count; i++) {
+ txt_redo_read_uint32(utxt->buf, &utxt->pos);
+ }
+ /* Count again */
+ txt_redo_read_uint32(utxt->buf, &utxt->pos);
+ /* Get the selection and re-unindent */
+ txt_redo_read_cursors(utxt->buf, &utxt->pos, &curln, &curc, &selln, &selc);
+ txt_move_to(text, curln, curc, 0);
+ txt_move_to(text, selln, selc, 1);
+ txt_unindent(text, utxt);
+ break;
+ }
+ default:
+ //XXX error("Undo buffer error - resetting");
+ utxt->pos = -1;
+
+ break;
+ }
+
+ undoing = 0;
}
/**************************/
@@ -2392,192 +2523,208 @@ void txt_do_redo(Text *text, TextUndoBuf *utxt)
void txt_split_curline(Text *text, TextUndoBuf *utxt)
{
- TextLine *ins;
- char *left, *right;
+ TextLine *ins;
+ char *left, *right;
- if (!text->curl) return;
+ if (!text->curl)
+ return;
- txt_delete_sel(text, utxt);
+ txt_delete_sel(text, utxt);
- if (!undoing) txt_undo_add_charop(text, utxt, UNDO_INSERT_1, '\n');
+ if (!undoing)
+ txt_undo_add_charop(text, utxt, UNDO_INSERT_1, '\n');
- /* Make the two half strings */
+ /* Make the two half strings */
- left = MEM_mallocN(text->curc + 1, "textline_string");
- if (text->curc) memcpy(left, text->curl->line, text->curc);
- left[text->curc] = 0;
+ left = MEM_mallocN(text->curc + 1, "textline_string");
+ if (text->curc)
+ memcpy(left, text->curl->line, text->curc);
+ left[text->curc] = 0;
- right = MEM_mallocN(text->curl->len - text->curc + 1, "textline_string");
- memcpy(right, text->curl->line + text->curc, text->curl->len - text->curc + 1);
+ right = MEM_mallocN(text->curl->len - text->curc + 1, "textline_string");
+ memcpy(right, text->curl->line + text->curc, text->curl->len - text->curc + 1);
- MEM_freeN(text->curl->line);
- if (text->curl->format) MEM_freeN(text->curl->format);
+ MEM_freeN(text->curl->line);
+ if (text->curl->format)
+ MEM_freeN(text->curl->format);
- /* Make the new TextLine */
+ /* Make the new TextLine */
- ins = MEM_mallocN(sizeof(TextLine), "textline");
- ins->line = left;
- ins->format = NULL;
- ins->len = text->curc;
+ ins = MEM_mallocN(sizeof(TextLine), "textline");
+ ins->line = left;
+ ins->format = NULL;
+ ins->len = text->curc;
- text->curl->line = right;
- text->curl->format = NULL;
- text->curl->len = text->curl->len - text->curc;
+ text->curl->line = right;
+ text->curl->format = NULL;
+ text->curl->len = text->curl->len - text->curc;
- BLI_insertlinkbefore(&text->lines, text->curl, ins);
+ BLI_insertlinkbefore(&text->lines, text->curl, ins);
- text->curc = 0;
+ text->curc = 0;
- txt_make_dirty(text);
- txt_clean_text(text);
+ txt_make_dirty(text);
+ txt_clean_text(text);
- txt_pop_sel(text);
+ txt_pop_sel(text);
}
static void txt_delete_line(Text *text, TextLine *line)
{
- if (!text->curl) return;
+ if (!text->curl)
+ return;
- BLI_remlink(&text->lines, line);
+ BLI_remlink(&text->lines, line);
- if (line->line) MEM_freeN(line->line);
- if (line->format) MEM_freeN(line->format);
+ if (line->line)
+ MEM_freeN(line->line);
+ if (line->format)
+ MEM_freeN(line->format);
- MEM_freeN(line);
+ MEM_freeN(line);
- txt_make_dirty(text);
- txt_clean_text(text);
+ txt_make_dirty(text);
+ txt_clean_text(text);
}
static void txt_combine_lines(Text *text, TextLine *linea, TextLine *lineb)
{
- char *tmp, *s;
-
- if (!linea || !lineb) return;
+ char *tmp, *s;
+ if (!linea || !lineb)
+ return;
- tmp = MEM_mallocN(linea->len + lineb->len + 1, "textline_string");
+ tmp = MEM_mallocN(linea->len + lineb->len + 1, "textline_string");
- s = tmp;
- s += BLI_strcpy_rlen(s, linea->line);
- s += BLI_strcpy_rlen(s, lineb->line);
- (void)s;
+ s = tmp;
+ s += BLI_strcpy_rlen(s, linea->line);
+ s += BLI_strcpy_rlen(s, lineb->line);
+ (void)s;
- make_new_line(linea, tmp);
+ make_new_line(linea, tmp);
- txt_delete_line(text, lineb);
+ txt_delete_line(text, lineb);
- txt_make_dirty(text);
- txt_clean_text(text);
+ txt_make_dirty(text);
+ txt_clean_text(text);
}
void txt_duplicate_line(Text *text, TextUndoBuf *utxt)
{
- TextLine *textline;
+ TextLine *textline;
- if (!text->curl) return;
+ if (!text->curl)
+ return;
- if (text->curl == text->sell) {
- textline = txt_new_line(text->curl->line);
- BLI_insertlinkafter(&text->lines, text->curl, textline);
+ if (text->curl == text->sell) {
+ textline = txt_new_line(text->curl->line);
+ BLI_insertlinkafter(&text->lines, text->curl, textline);
- txt_make_dirty(text);
- txt_clean_text(text);
+ txt_make_dirty(text);
+ txt_clean_text(text);
- if (!undoing) txt_undo_add_op(text, utxt, UNDO_DUPLICATE);
- }
+ if (!undoing)
+ txt_undo_add_op(text, utxt, UNDO_DUPLICATE);
+ }
}
void txt_delete_char(Text *text, TextUndoBuf *utxt)
{
- unsigned int c = '\n';
+ unsigned int c = '\n';
- if (!text->curl) return;
+ if (!text->curl)
+ return;
- if (txt_has_sel(text)) { /* deleting a selection */
- txt_delete_sel(text, utxt);
- txt_make_dirty(text);
- return;
- }
- else if (text->curc == text->curl->len) { /* Appending two lines */
- if (text->curl->next) {
- txt_combine_lines(text, text->curl, text->curl->next);
- txt_pop_sel(text);
- }
- else
- return;
- }
- else { /* Just deleting a char */
- size_t c_len = 0;
- c = BLI_str_utf8_as_unicode_and_size(text->curl->line + text->curc, &c_len);
+ if (txt_has_sel(text)) { /* deleting a selection */
+ txt_delete_sel(text, utxt);
+ txt_make_dirty(text);
+ return;
+ }
+ else if (text->curc == text->curl->len) { /* Appending two lines */
+ if (text->curl->next) {
+ txt_combine_lines(text, text->curl, text->curl->next);
+ txt_pop_sel(text);
+ }
+ else
+ return;
+ }
+ else { /* Just deleting a char */
+ size_t c_len = 0;
+ c = BLI_str_utf8_as_unicode_and_size(text->curl->line + text->curc, &c_len);
- memmove(text->curl->line + text->curc, text->curl->line + text->curc + c_len, text->curl->len - text->curc - c_len + 1);
+ memmove(text->curl->line + text->curc,
+ text->curl->line + text->curc + c_len,
+ text->curl->len - text->curc - c_len + 1);
- text->curl->len -= c_len;
+ text->curl->len -= c_len;
- txt_pop_sel(text);
- }
+ txt_pop_sel(text);
+ }
- txt_make_dirty(text);
- txt_clean_text(text);
+ txt_make_dirty(text);
+ txt_clean_text(text);
- if (!undoing) txt_undo_add_charop(text, utxt, UNDO_DEL_1, c);
+ if (!undoing)
+ txt_undo_add_charop(text, utxt, UNDO_DEL_1, c);
}
void txt_delete_word(Text *text, TextUndoBuf *utxt)
{
- txt_jump_right(text, true, true);
- txt_delete_sel(text, utxt);
- txt_make_dirty(text);
+ txt_jump_right(text, true, true);
+ txt_delete_sel(text, utxt);
+ txt_make_dirty(text);
}
void txt_backspace_char(Text *text, TextUndoBuf *utxt)
{
- unsigned int c = '\n';
+ unsigned int c = '\n';
- if (!text->curl) return;
+ if (!text->curl)
+ return;
- if (txt_has_sel(text)) { /* deleting a selection */
- txt_delete_sel(text, utxt);
- txt_make_dirty(text);
- return;
- }
- else if (text->curc == 0) { /* Appending two lines */
- if (!text->curl->prev) return;
+ if (txt_has_sel(text)) { /* deleting a selection */
+ txt_delete_sel(text, utxt);
+ txt_make_dirty(text);
+ return;
+ }
+ else if (text->curc == 0) { /* Appending two lines */
+ if (!text->curl->prev)
+ return;
- text->curl = text->curl->prev;
- text->curc = text->curl->len;
+ text->curl = text->curl->prev;
+ text->curc = text->curl->len;
- txt_combine_lines(text, text->curl, text->curl->next);
- txt_pop_sel(text);
- }
- else { /* Just backspacing a char */
- size_t c_len = 0;
- const char *prev = BLI_str_prev_char_utf8(text->curl->line + text->curc);
- c = BLI_str_utf8_as_unicode_and_size(prev, &c_len);
+ txt_combine_lines(text, text->curl, text->curl->next);
+ txt_pop_sel(text);
+ }
+ else { /* Just backspacing a char */
+ size_t c_len = 0;
+ const char *prev = BLI_str_prev_char_utf8(text->curl->line + text->curc);
+ c = BLI_str_utf8_as_unicode_and_size(prev, &c_len);
- /* source and destination overlap, don't use memcpy() */
- memmove(text->curl->line + text->curc - c_len,
- text->curl->line + text->curc,
- text->curl->len - text->curc + 1);
+ /* source and destination overlap, don't use memcpy() */
+ memmove(text->curl->line + text->curc - c_len,
+ text->curl->line + text->curc,
+ text->curl->len - text->curc + 1);
- text->curl->len -= c_len;
- text->curc -= c_len;
+ text->curl->len -= c_len;
+ text->curc -= c_len;
- txt_pop_sel(text);
- }
+ txt_pop_sel(text);
+ }
- txt_make_dirty(text);
- txt_clean_text(text);
+ txt_make_dirty(text);
+ txt_clean_text(text);
- if (!undoing) txt_undo_add_charop(text, utxt, UNDO_BS_1, c);
+ if (!undoing)
+ txt_undo_add_charop(text, utxt, UNDO_BS_1, c);
}
void txt_backspace_word(Text *text, TextUndoBuf *utxt)
{
- txt_jump_left(text, true, true);
- txt_delete_sel(text, utxt);
- txt_make_dirty(text);
+ txt_jump_left(text, true, true);
+ txt_delete_sel(text, utxt);
+ txt_make_dirty(text);
}
/* Max spaces to replace a tab with, currently hardcoded to TXT_TABSIZE = 4.
@@ -2587,118 +2734,126 @@ static char tab_to_spaces[] = " ";
static void txt_convert_tab_to_spaces(Text *text, TextUndoBuf *utxt)
{
- /* sb aims to pad adjust the tab-width needed so that the right number of spaces
- * is added so that the indention of the line is the right width (i.e. aligned
- * to multiples of TXT_TABSIZE)
- */
- const char *sb = &tab_to_spaces[text->curc % TXT_TABSIZE];
- txt_insert_buf(text, utxt, sb);
+ /* sb aims to pad adjust the tab-width needed so that the right number of spaces
+ * is added so that the indention of the line is the right width (i.e. aligned
+ * to multiples of TXT_TABSIZE)
+ */
+ const char *sb = &tab_to_spaces[text->curc % TXT_TABSIZE];
+ txt_insert_buf(text, utxt, sb);
}
static bool txt_add_char_intern(Text *text, TextUndoBuf *utxt, unsigned int add, bool replace_tabs)
{
- char *tmp, ch[BLI_UTF8_MAX];
- size_t add_len;
+ char *tmp, ch[BLI_UTF8_MAX];
+ size_t add_len;
- if (!text->curl) return 0;
+ if (!text->curl)
+ return 0;
- if (add == '\n') {
- txt_split_curline(text, utxt);
- return true;
- }
+ if (add == '\n') {
+ txt_split_curline(text, utxt);
+ return true;
+ }
- /* insert spaces rather than tabs */
- if (add == '\t' && replace_tabs) {
- txt_convert_tab_to_spaces(text, utxt);
- return true;
- }
+ /* insert spaces rather than tabs */
+ if (add == '\t' && replace_tabs) {
+ txt_convert_tab_to_spaces(text, utxt);
+ return true;
+ }
- txt_delete_sel(text, utxt);
+ txt_delete_sel(text, utxt);
- if (!undoing) txt_undo_add_charop(text, utxt, UNDO_INSERT_1, add);
+ if (!undoing)
+ txt_undo_add_charop(text, utxt, UNDO_INSERT_1, add);
- add_len = BLI_str_utf8_from_unicode(add, ch);
+ add_len = BLI_str_utf8_from_unicode(add, ch);
- tmp = MEM_mallocN(text->curl->len + add_len + 1, "textline_string");
+ tmp = MEM_mallocN(text->curl->len + add_len + 1, "textline_string");
- memcpy(tmp, text->curl->line, text->curc);
- memcpy(tmp + text->curc, ch, add_len);
- memcpy(tmp + text->curc + add_len, text->curl->line + text->curc, text->curl->len - text->curc + 1);
+ memcpy(tmp, text->curl->line, text->curc);
+ memcpy(tmp + text->curc, ch, add_len);
+ memcpy(
+ tmp + text->curc + add_len, text->curl->line + text->curc, text->curl->len - text->curc + 1);
- make_new_line(text->curl, tmp);
+ make_new_line(text->curl, tmp);
- text->curc += add_len;
+ text->curc += add_len;
- txt_pop_sel(text);
+ txt_pop_sel(text);
- txt_make_dirty(text);
- txt_clean_text(text);
+ txt_make_dirty(text);
+ txt_clean_text(text);
- return 1;
+ return 1;
}
bool txt_add_char(Text *text, TextUndoBuf *utxt, unsigned int add)
{
- return txt_add_char_intern(text, utxt, add, (text->flags & TXT_TABSTOSPACES) != 0);
+ return txt_add_char_intern(text, utxt, add, (text->flags & TXT_TABSTOSPACES) != 0);
}
bool txt_add_raw_char(Text *text, TextUndoBuf *utxt, unsigned int add)
{
- return txt_add_char_intern(text, utxt, add, 0);
+ return txt_add_char_intern(text, utxt, add, 0);
}
void txt_delete_selected(Text *text, TextUndoBuf *utxt)
{
- txt_delete_sel(text, utxt);
- txt_make_dirty(text);
+ txt_delete_sel(text, utxt);
+ txt_make_dirty(text);
}
bool txt_replace_char(Text *text, TextUndoBuf *utxt, unsigned int add)
{
- unsigned int del;
- size_t del_size = 0, add_size;
- char ch[BLI_UTF8_MAX];
-
- if (!text->curl) return false;
-
- /* If text is selected or we're at the end of the line just use txt_add_char */
- if (text->curc == text->curl->len || txt_has_sel(text) || add == '\n') {
- return txt_add_char(text, utxt, add);
- }
-
- del = BLI_str_utf8_as_unicode_and_size(text->curl->line + text->curc, &del_size);
- add_size = BLI_str_utf8_from_unicode(add, ch);
-
- if (add_size > del_size) {
- char *tmp = MEM_mallocN(text->curl->len + add_size - del_size + 1, "textline_string");
- memcpy(tmp, text->curl->line, text->curc);
- memcpy(tmp + text->curc + add_size, text->curl->line + text->curc + del_size, text->curl->len - text->curc - del_size + 1);
- MEM_freeN(text->curl->line);
- text->curl->line = tmp;
- }
- else if (add_size < del_size) {
- char *tmp = text->curl->line;
- memmove(tmp + text->curc + add_size, tmp + text->curc + del_size, text->curl->len - text->curc - del_size + 1);
- }
-
- memcpy(text->curl->line + text->curc, ch, add_size);
- text->curc += add_size;
- text->curl->len += add_size - del_size;
-
- txt_pop_sel(text);
- txt_make_dirty(text);
- txt_clean_text(text);
-
- /* Should probably create a new op for this */
- if (!undoing) {
- txt_undo_add_charop(text, utxt, UNDO_INSERT_1, add);
- text->curc -= add_size;
- txt_pop_sel(text);
- txt_undo_add_charop(text, utxt, UNDO_DEL_1, del);
- text->curc += add_size;
- txt_pop_sel(text);
- }
- return true;
+ unsigned int del;
+ size_t del_size = 0, add_size;
+ char ch[BLI_UTF8_MAX];
+
+ if (!text->curl)
+ return false;
+
+ /* If text is selected or we're at the end of the line just use txt_add_char */
+ if (text->curc == text->curl->len || txt_has_sel(text) || add == '\n') {
+ return txt_add_char(text, utxt, add);
+ }
+
+ del = BLI_str_utf8_as_unicode_and_size(text->curl->line + text->curc, &del_size);
+ add_size = BLI_str_utf8_from_unicode(add, ch);
+
+ if (add_size > del_size) {
+ char *tmp = MEM_mallocN(text->curl->len + add_size - del_size + 1, "textline_string");
+ memcpy(tmp, text->curl->line, text->curc);
+ memcpy(tmp + text->curc + add_size,
+ text->curl->line + text->curc + del_size,
+ text->curl->len - text->curc - del_size + 1);
+ MEM_freeN(text->curl->line);
+ text->curl->line = tmp;
+ }
+ else if (add_size < del_size) {
+ char *tmp = text->curl->line;
+ memmove(tmp + text->curc + add_size,
+ tmp + text->curc + del_size,
+ text->curl->len - text->curc - del_size + 1);
+ }
+
+ memcpy(text->curl->line + text->curc, ch, add_size);
+ text->curc += add_size;
+ text->curl->len += add_size - del_size;
+
+ txt_pop_sel(text);
+ txt_make_dirty(text);
+ txt_clean_text(text);
+
+ /* Should probably create a new op for this */
+ if (!undoing) {
+ txt_undo_add_charop(text, utxt, UNDO_INSERT_1, add);
+ text->curc -= add_size;
+ txt_pop_sel(text);
+ txt_undo_add_charop(text, utxt, UNDO_DEL_1, del);
+ text->curc += add_size;
+ txt_pop_sel(text);
+ }
+ return true;
}
/**
@@ -2708,56 +2863,60 @@ bool txt_replace_char(Text *text, TextUndoBuf *utxt, unsigned int add)
*/
static void txt_select_prefix(Text *text, const char *add)
{
- int len, num, curc_old;
- char *tmp;
+ int len, num, curc_old;
+ char *tmp;
- const int indentlen = strlen(add);
+ const int indentlen = strlen(add);
- BLI_assert(!ELEM(NULL, text->curl, text->sell));
+ BLI_assert(!ELEM(NULL, text->curl, text->sell));
- curc_old = text->curc;
+ curc_old = text->curc;
- num = 0;
- while (true) {
+ num = 0;
+ while (true) {
- /* don't indent blank lines */
- if (text->curl->len != 0) {
- tmp = MEM_mallocN(text->curl->len + indentlen + 1, "textline_string");
+ /* don't indent blank lines */
+ if (text->curl->len != 0) {
+ tmp = MEM_mallocN(text->curl->len + indentlen + 1, "textline_string");
- text->curc = 0;
- if (text->curc) memcpy(tmp, text->curl->line, text->curc); /* XXX never true, check prev line */
- memcpy(tmp + text->curc, add, indentlen);
+ text->curc = 0;
+ if (text->curc)
+ memcpy(tmp, text->curl->line, text->curc); /* XXX never true, check prev line */
+ memcpy(tmp + text->curc, add, indentlen);
- len = text->curl->len - text->curc;
- if (len > 0) memcpy(tmp + text->curc + indentlen, text->curl->line + text->curc, len);
- tmp[text->curl->len + indentlen] = 0;
+ len = text->curl->len - text->curc;
+ if (len > 0)
+ memcpy(tmp + text->curc + indentlen, text->curl->line + text->curc, len);
+ tmp[text->curl->len + indentlen] = 0;
- make_new_line(text->curl, tmp);
+ make_new_line(text->curl, tmp);
- text->curc += indentlen;
+ text->curc += indentlen;
- txt_make_dirty(text);
- txt_clean_text(text);
- }
+ txt_make_dirty(text);
+ txt_clean_text(text);
+ }
- if (text->curl == text->sell) {
- text->selc += indentlen;
- break;
- }
- else {
- text->curl = text->curl->next;
- num++;
- }
- }
- if (!curc_old) text->curc = 0;
- else text->curc = curc_old + indentlen;
+ if (text->curl == text->sell) {
+ text->selc += indentlen;
+ break;
+ }
+ else {
+ text->curl = text->curl->next;
+ num++;
+ }
+ }
+ if (!curc_old)
+ text->curc = 0;
+ else
+ text->curc = curc_old + indentlen;
- while (num > 0) {
- text->curl = text->curl->prev;
- num--;
- }
+ while (num > 0) {
+ text->curl = text->curl->prev;
+ num--;
+ }
- /* caller must handle undo */
+ /* caller must handle undo */
}
/**
@@ -2768,225 +2927,228 @@ static void txt_select_prefix(Text *text, const char *add)
*
* \note caller must handle undo.
*/
-static void txt_select_unprefix(
- Text *text, const char *remove,
- ListBase *r_line_index_mask, int *r_line_index_mask_len)
-{
- int num = 0;
- const int indentlen = strlen(remove);
- bool unindented_first = false;
-
- int curl_span_init = 0;
-
- BLI_assert(!ELEM(NULL, text->curl, text->sell));
-
- BLI_listbase_clear(r_line_index_mask);
- *r_line_index_mask_len = 0;
-
- if (!undoing) {
- curl_span_init = txt_get_span(text->lines.first, text->curl);
- }
-
- while (true) {
- bool changed = false;
- if (STREQLEN(text->curl->line, remove, indentlen)) {
- if (num == 0)
- unindented_first = true;
- text->curl->len -= indentlen;
- memmove(text->curl->line, text->curl->line + indentlen, text->curl->len + 1);
- changed = true;
- }
- else {
- if (!undoing) {
- /* Create list element for 0 indent line */
- struct LinkInt *idata = MEM_mallocN(sizeof(struct LinkInt), __func__);
- idata->value = curl_span_init + num;
- BLI_assert(idata->value == txt_get_span(text->lines.first, text->curl));
- BLI_addtail(r_line_index_mask, idata);
- (*r_line_index_mask_len) += 1;
- }
- }
-
- txt_make_dirty(text);
- txt_clean_text(text);
-
- if (text->curl == text->sell) {
- if (changed)
- text->selc = MAX2(text->selc - indentlen, 0);
- break;
- }
- else {
- text->curl = text->curl->next;
- num++;
-
- }
-
- }
-
- if (unindented_first)
- text->curc = MAX2(text->curc - indentlen, 0);
-
- while (num > 0) {
- text->curl = text->curl->prev;
- num--;
- }
-
- /* caller must handle undo */
+static void txt_select_unprefix(Text *text,
+ const char *remove,
+ ListBase *r_line_index_mask,
+ int *r_line_index_mask_len)
+{
+ int num = 0;
+ const int indentlen = strlen(remove);
+ bool unindented_first = false;
+
+ int curl_span_init = 0;
+
+ BLI_assert(!ELEM(NULL, text->curl, text->sell));
+
+ BLI_listbase_clear(r_line_index_mask);
+ *r_line_index_mask_len = 0;
+
+ if (!undoing) {
+ curl_span_init = txt_get_span(text->lines.first, text->curl);
+ }
+
+ while (true) {
+ bool changed = false;
+ if (STREQLEN(text->curl->line, remove, indentlen)) {
+ if (num == 0)
+ unindented_first = true;
+ text->curl->len -= indentlen;
+ memmove(text->curl->line, text->curl->line + indentlen, text->curl->len + 1);
+ changed = true;
+ }
+ else {
+ if (!undoing) {
+ /* Create list element for 0 indent line */
+ struct LinkInt *idata = MEM_mallocN(sizeof(struct LinkInt), __func__);
+ idata->value = curl_span_init + num;
+ BLI_assert(idata->value == txt_get_span(text->lines.first, text->curl));
+ BLI_addtail(r_line_index_mask, idata);
+ (*r_line_index_mask_len) += 1;
+ }
+ }
+
+ txt_make_dirty(text);
+ txt_clean_text(text);
+
+ if (text->curl == text->sell) {
+ if (changed)
+ text->selc = MAX2(text->selc - indentlen, 0);
+ break;
+ }
+ else {
+ text->curl = text->curl->next;
+ num++;
+ }
+ }
+
+ if (unindented_first)
+ text->curc = MAX2(text->curc - indentlen, 0);
+
+ while (num > 0) {
+ text->curl = text->curl->prev;
+ num--;
+ }
+
+ /* caller must handle undo */
}
void txt_comment(Text *text, TextUndoBuf *utxt)
{
- const char *prefix = "#";
+ const char *prefix = "#";
- if (ELEM(NULL, text->curl, text->sell)) {
- return;
- }
+ if (ELEM(NULL, text->curl, text->sell)) {
+ return;
+ }
- txt_select_prefix(text, prefix);
+ txt_select_prefix(text, prefix);
- if (!undoing) {
- txt_undo_add_op(text, utxt, UNDO_COMMENT);
- }
+ if (!undoing) {
+ txt_undo_add_op(text, utxt, UNDO_COMMENT);
+ }
}
void txt_uncomment(Text *text, TextUndoBuf *utxt)
{
- const char *prefix = "#";
- ListBase line_index_mask;
- int line_index_mask_len;
+ const char *prefix = "#";
+ ListBase line_index_mask;
+ int line_index_mask_len;
- if (ELEM(NULL, text->curl, text->sell)) {
- return;
- }
+ if (ELEM(NULL, text->curl, text->sell)) {
+ return;
+ }
- txt_select_unprefix(text, prefix, &line_index_mask, &line_index_mask_len);
+ txt_select_unprefix(text, prefix, &line_index_mask, &line_index_mask_len);
- if (!undoing) {
- txt_undo_add_unprefix_op(text, utxt, UNDO_UNCOMMENT, &line_index_mask, line_index_mask_len);
- }
+ if (!undoing) {
+ txt_undo_add_unprefix_op(text, utxt, UNDO_UNCOMMENT, &line_index_mask, line_index_mask_len);
+ }
- BLI_freelistN(&line_index_mask);
+ BLI_freelistN(&line_index_mask);
}
void txt_indent(Text *text, TextUndoBuf *utxt)
{
- const char *prefix = (text->flags & TXT_TABSTOSPACES) ? tab_to_spaces : "\t";
+ const char *prefix = (text->flags & TXT_TABSTOSPACES) ? tab_to_spaces : "\t";
- if (ELEM(NULL, text->curl, text->sell)) {
- return;
- }
+ if (ELEM(NULL, text->curl, text->sell)) {
+ return;
+ }
- txt_select_prefix(text, prefix);
+ txt_select_prefix(text, prefix);
- if (!undoing) {
- txt_undo_add_op(text, utxt, UNDO_INDENT);
- }
+ if (!undoing) {
+ txt_undo_add_op(text, utxt, UNDO_INDENT);
+ }
}
void txt_unindent(Text *text, TextUndoBuf *utxt)
{
- const char *prefix = (text->flags & TXT_TABSTOSPACES) ? tab_to_spaces : "\t";
- ListBase line_index_mask;
- int line_index_mask_len;
+ const char *prefix = (text->flags & TXT_TABSTOSPACES) ? tab_to_spaces : "\t";
+ ListBase line_index_mask;
+ int line_index_mask_len;
- if (ELEM(NULL, text->curl, text->sell)) {
- return;
- }
+ if (ELEM(NULL, text->curl, text->sell)) {
+ return;
+ }
- txt_select_unprefix(text, prefix, &line_index_mask, &line_index_mask_len);
+ txt_select_unprefix(text, prefix, &line_index_mask, &line_index_mask_len);
- if (!undoing) {
- txt_undo_add_unprefix_op(text, utxt, UNDO_UNINDENT, &line_index_mask, line_index_mask_len);
- }
+ if (!undoing) {
+ txt_undo_add_unprefix_op(text, utxt, UNDO_UNINDENT, &line_index_mask, line_index_mask_len);
+ }
- BLI_freelistN(&line_index_mask);
+ BLI_freelistN(&line_index_mask);
}
void txt_move_lines(struct Text *text, TextUndoBuf *utxt, const int direction)
{
- TextLine *line_other;
+ TextLine *line_other;
- BLI_assert(ELEM(direction, TXT_MOVE_LINE_UP, TXT_MOVE_LINE_DOWN));
+ BLI_assert(ELEM(direction, TXT_MOVE_LINE_UP, TXT_MOVE_LINE_DOWN));
- if (!text->curl || !text->sell) return;
+ if (!text->curl || !text->sell)
+ return;
- txt_order_cursors(text, false);
+ txt_order_cursors(text, false);
- line_other = (direction == TXT_MOVE_LINE_DOWN) ? text->sell->next : text->curl->prev;
+ line_other = (direction == TXT_MOVE_LINE_DOWN) ? text->sell->next : text->curl->prev;
- if (!line_other) return;
+ if (!line_other)
+ return;
- BLI_remlink(&text->lines, line_other);
+ BLI_remlink(&text->lines, line_other);
- if (direction == TXT_MOVE_LINE_DOWN) {
- BLI_insertlinkbefore(&text->lines, text->curl, line_other);
- }
- else {
- BLI_insertlinkafter(&text->lines, text->sell, line_other);
- }
+ if (direction == TXT_MOVE_LINE_DOWN) {
+ BLI_insertlinkbefore(&text->lines, text->curl, line_other);
+ }
+ else {
+ BLI_insertlinkafter(&text->lines, text->sell, line_other);
+ }
- txt_make_dirty(text);
- txt_clean_text(text);
+ txt_make_dirty(text);
+ txt_clean_text(text);
- if (!undoing) {
- txt_undo_add_op(text, utxt, (direction == TXT_MOVE_LINE_DOWN) ? UNDO_MOVE_LINES_DOWN : UNDO_MOVE_LINES_UP);
- }
+ if (!undoing) {
+ txt_undo_add_op(
+ text, utxt, (direction == TXT_MOVE_LINE_DOWN) ? UNDO_MOVE_LINES_DOWN : UNDO_MOVE_LINES_UP);
+ }
}
int txt_setcurr_tab_spaces(Text *text, int space)
{
- int i = 0;
- int test = 0;
- const char *word = ":";
- const char *comm = "#";
- const char indent = (text->flags & TXT_TABSTOSPACES) ? ' ' : '\t';
- static const char *back_words[] = {"return", "break", "continue", "pass", "yield", NULL};
-
- if (!text->curl) return 0;
-
- while (text->curl->line[i] == indent) {
- //we only count those tabs/spaces that are before any text or before the curs;
- if (i == text->curc) {
- return i;
- }
- else {
- i++;
- }
- }
- if (strstr(text->curl->line, word)) {
- /* if we find a ':' on this line, then add a tab but not if it is:
- * 1) in a comment
- * 2) within an identifier
- * 3) after the cursor (text->curc), i.e. when creating space before a function def [#25414]
- */
- int a;
- bool is_indent = false;
- for (a = 0; (a < text->curc) && (text->curl->line[a] != '\0'); a++) {
- char ch = text->curl->line[a];
- if (ch == '#') {
- break;
- }
- else if (ch == ':') {
- is_indent = 1;
- }
- else if (ch != ' ' && ch != '\t') {
- is_indent = 0;
- }
- }
- if (is_indent) {
- i += space;
- }
- }
-
- for (test = 0; back_words[test]; test++) {
- /* if there are these key words then remove a tab because we are done with the block */
- if (strstr(text->curl->line, back_words[test]) && i > 0) {
- if (strcspn(text->curl->line, back_words[test]) < strcspn(text->curl->line, comm)) {
- i -= space;
- }
- }
- }
- return i;
+ int i = 0;
+ int test = 0;
+ const char *word = ":";
+ const char *comm = "#";
+ const char indent = (text->flags & TXT_TABSTOSPACES) ? ' ' : '\t';
+ static const char *back_words[] = {"return", "break", "continue", "pass", "yield", NULL};
+
+ if (!text->curl)
+ return 0;
+
+ while (text->curl->line[i] == indent) {
+ //we only count those tabs/spaces that are before any text or before the curs;
+ if (i == text->curc) {
+ return i;
+ }
+ else {
+ i++;
+ }
+ }
+ if (strstr(text->curl->line, word)) {
+ /* if we find a ':' on this line, then add a tab but not if it is:
+ * 1) in a comment
+ * 2) within an identifier
+ * 3) after the cursor (text->curc), i.e. when creating space before a function def [#25414]
+ */
+ int a;
+ bool is_indent = false;
+ for (a = 0; (a < text->curc) && (text->curl->line[a] != '\0'); a++) {
+ char ch = text->curl->line[a];
+ if (ch == '#') {
+ break;
+ }
+ else if (ch == ':') {
+ is_indent = 1;
+ }
+ else if (ch != ' ' && ch != '\t') {
+ is_indent = 0;
+ }
+ }
+ if (is_indent) {
+ i += space;
+ }
+ }
+
+ for (test = 0; back_words[test]; test++) {
+ /* if there are these key words then remove a tab because we are done with the block */
+ if (strstr(text->curl->line, back_words[test]) && i > 0) {
+ if (strcspn(text->curl->line, back_words[test]) < strcspn(text->curl->line, comm)) {
+ i -= space;
+ }
+ }
+ }
+ return i;
}
/*******************************/
@@ -2995,90 +3157,103 @@ int txt_setcurr_tab_spaces(Text *text, int space)
int text_check_bracket(const char ch)
{
- int a;
- char opens[] = "([{";
- char close[] = ")]}";
+ int a;
+ char opens[] = "([{";
+ char close[] = ")]}";
- for (a = 0; a < (sizeof(opens) - 1); a++) {
- if (ch == opens[a])
- return a + 1;
- else if (ch == close[a])
- return -(a + 1);
- }
- return 0;
+ for (a = 0; a < (sizeof(opens) - 1); a++) {
+ if (ch == opens[a])
+ return a + 1;
+ else if (ch == close[a])
+ return -(a + 1);
+ }
+ return 0;
}
/* TODO, have a function for operators - http://docs.python.org/py3k/reference/lexical_analysis.html#operators */
bool text_check_delim(const char ch)
{
- int a;
- char delims[] = "():\"\' ~!%^&*-+=[]{};/<>|.#\t,@";
+ int a;
+ char delims[] = "():\"\' ~!%^&*-+=[]{};/<>|.#\t,@";
- for (a = 0; a < (sizeof(delims) - 1); a++) {
- if (ch == delims[a])
- return true;
- }
- return false;
+ for (a = 0; a < (sizeof(delims) - 1); a++) {
+ if (ch == delims[a])
+ return true;
+ }
+ return false;
}
bool text_check_digit(const char ch)
{
- if (ch < '0') return false;
- if (ch <= '9') return true;
- return false;
+ if (ch < '0')
+ return false;
+ if (ch <= '9')
+ return true;
+ return false;
}
bool text_check_identifier(const char ch)
{
- if (ch < '0') return false;
- if (ch <= '9') return true;
- if (ch < 'A') return false;
- if (ch <= 'Z' || ch == '_') return true;
- if (ch < 'a') return false;
- if (ch <= 'z') return true;
- return false;
+ if (ch < '0')
+ return false;
+ if (ch <= '9')
+ return true;
+ if (ch < 'A')
+ return false;
+ if (ch <= 'Z' || ch == '_')
+ return true;
+ if (ch < 'a')
+ return false;
+ if (ch <= 'z')
+ return true;
+ return false;
}
bool text_check_identifier_nodigit(const char ch)
{
- if (ch <= '9') return false;
- if (ch < 'A') return false;
- if (ch <= 'Z' || ch == '_') return true;
- if (ch < 'a') return false;
- if (ch <= 'z') return true;
- return false;
+ if (ch <= '9')
+ return false;
+ if (ch < 'A')
+ return false;
+ if (ch <= 'Z' || ch == '_')
+ return true;
+ if (ch < 'a')
+ return false;
+ if (ch <= 'z')
+ return true;
+ return false;
}
#ifndef WITH_PYTHON
int text_check_identifier_unicode(const unsigned int ch)
{
- return (ch < 255 && text_check_identifier((unsigned int)ch));
+ return (ch < 255 && text_check_identifier((unsigned int)ch));
}
int text_check_identifier_nodigit_unicode(const unsigned int ch)
{
- return (ch < 255 && text_check_identifier_nodigit((char)ch));
+ return (ch < 255 && text_check_identifier_nodigit((char)ch));
}
-#endif /* WITH_PYTHON */
+#endif /* WITH_PYTHON */
bool text_check_whitespace(const char ch)
{
- if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')
- return true;
- return false;
+ if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')
+ return true;
+ return false;
}
int text_find_identifier_start(const char *str, int i)
{
- if (UNLIKELY(i <= 0)) {
- return 0;
- }
-
- while (i--) {
- if (!text_check_identifier(str[i])) {
- break;
- }
- }
- i++;
- return i;
+ if (UNLIKELY(i <= 0)) {
+ return 0;
+ }
+
+ while (i--) {
+ if (!text_check_identifier(str[i])) {
+ break;
+ }
+ }
+ i++;
+ return i;
}
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index 8cfe3d2476d..dbbb231a18b 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -21,7 +21,6 @@
* \ingroup bke
*/
-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -65,125 +64,124 @@
TexMapping *BKE_texture_mapping_add(int type)
{
- TexMapping *texmap = MEM_callocN(sizeof(TexMapping), "TexMapping");
+ TexMapping *texmap = MEM_callocN(sizeof(TexMapping), "TexMapping");
- BKE_texture_mapping_default(texmap, type);
+ BKE_texture_mapping_default(texmap, type);
- return texmap;
+ return texmap;
}
void BKE_texture_mapping_default(TexMapping *texmap, int type)
{
- memset(texmap, 0, sizeof(TexMapping));
+ memset(texmap, 0, sizeof(TexMapping));
- texmap->size[0] = texmap->size[1] = texmap->size[2] = 1.0f;
- texmap->max[0] = texmap->max[1] = texmap->max[2] = 1.0f;
- unit_m4(texmap->mat);
+ texmap->size[0] = texmap->size[1] = texmap->size[2] = 1.0f;
+ texmap->max[0] = texmap->max[1] = texmap->max[2] = 1.0f;
+ unit_m4(texmap->mat);
- texmap->projx = PROJ_X;
- texmap->projy = PROJ_Y;
- texmap->projz = PROJ_Z;
- texmap->mapping = MTEX_FLAT;
- texmap->type = type;
+ texmap->projx = PROJ_X;
+ texmap->projy = PROJ_Y;
+ texmap->projz = PROJ_Z;
+ texmap->mapping = MTEX_FLAT;
+ texmap->type = type;
}
void BKE_texture_mapping_init(TexMapping *texmap)
{
- float smat[4][4], rmat[4][4], tmat[4][4], proj[4][4], size[3];
-
- if (texmap->projx == PROJ_X && texmap->projy == PROJ_Y && texmap->projz == PROJ_Z &&
- is_zero_v3(texmap->loc) && is_zero_v3(texmap->rot) && is_one_v3(texmap->size))
- {
- unit_m4(texmap->mat);
-
- texmap->flag |= TEXMAP_UNIT_MATRIX;
- }
- else {
- /* axis projection */
- zero_m4(proj);
- proj[3][3] = 1.0f;
-
- if (texmap->projx != PROJ_N)
- proj[texmap->projx - 1][0] = 1.0f;
- if (texmap->projy != PROJ_N)
- proj[texmap->projy - 1][1] = 1.0f;
- if (texmap->projz != PROJ_N)
- proj[texmap->projz - 1][2] = 1.0f;
-
- /* scale */
- copy_v3_v3(size, texmap->size);
-
- if (ELEM(texmap->type, TEXMAP_TYPE_TEXTURE, TEXMAP_TYPE_NORMAL)) {
- /* keep matrix invertible */
- if (fabsf(size[0]) < 1e-5f)
- size[0] = signf(size[0]) * 1e-5f;
- if (fabsf(size[1]) < 1e-5f)
- size[1] = signf(size[1]) * 1e-5f;
- if (fabsf(size[2]) < 1e-5f)
- size[2] = signf(size[2]) * 1e-5f;
- }
-
- size_to_mat4(smat, texmap->size);
-
- /* rotation */
- eul_to_mat4(rmat, texmap->rot);
-
- /* translation */
- unit_m4(tmat);
- copy_v3_v3(tmat[3], texmap->loc);
-
- if (texmap->type == TEXMAP_TYPE_TEXTURE) {
- /* to transform a texture, the inverse transform needs
- * to be applied to the texture coordinate */
- mul_m4_series(texmap->mat, tmat, rmat, smat);
- invert_m4(texmap->mat);
- }
- else if (texmap->type == TEXMAP_TYPE_POINT) {
- /* forward transform */
- mul_m4_series(texmap->mat, tmat, rmat, smat);
- }
- else if (texmap->type == TEXMAP_TYPE_VECTOR) {
- /* no translation for vectors */
- mul_m4_m4m4(texmap->mat, rmat, smat);
- }
- else if (texmap->type == TEXMAP_TYPE_NORMAL) {
- /* no translation for normals, and inverse transpose */
- mul_m4_m4m4(texmap->mat, rmat, smat);
- invert_m4(texmap->mat);
- transpose_m4(texmap->mat);
- }
-
- /* projection last */
- mul_m4_m4m4(texmap->mat, texmap->mat, proj);
-
- texmap->flag &= ~TEXMAP_UNIT_MATRIX;
- }
+ float smat[4][4], rmat[4][4], tmat[4][4], proj[4][4], size[3];
+
+ if (texmap->projx == PROJ_X && texmap->projy == PROJ_Y && texmap->projz == PROJ_Z &&
+ is_zero_v3(texmap->loc) && is_zero_v3(texmap->rot) && is_one_v3(texmap->size)) {
+ unit_m4(texmap->mat);
+
+ texmap->flag |= TEXMAP_UNIT_MATRIX;
+ }
+ else {
+ /* axis projection */
+ zero_m4(proj);
+ proj[3][3] = 1.0f;
+
+ if (texmap->projx != PROJ_N)
+ proj[texmap->projx - 1][0] = 1.0f;
+ if (texmap->projy != PROJ_N)
+ proj[texmap->projy - 1][1] = 1.0f;
+ if (texmap->projz != PROJ_N)
+ proj[texmap->projz - 1][2] = 1.0f;
+
+ /* scale */
+ copy_v3_v3(size, texmap->size);
+
+ if (ELEM(texmap->type, TEXMAP_TYPE_TEXTURE, TEXMAP_TYPE_NORMAL)) {
+ /* keep matrix invertible */
+ if (fabsf(size[0]) < 1e-5f)
+ size[0] = signf(size[0]) * 1e-5f;
+ if (fabsf(size[1]) < 1e-5f)
+ size[1] = signf(size[1]) * 1e-5f;
+ if (fabsf(size[2]) < 1e-5f)
+ size[2] = signf(size[2]) * 1e-5f;
+ }
+
+ size_to_mat4(smat, texmap->size);
+
+ /* rotation */
+ eul_to_mat4(rmat, texmap->rot);
+
+ /* translation */
+ unit_m4(tmat);
+ copy_v3_v3(tmat[3], texmap->loc);
+
+ if (texmap->type == TEXMAP_TYPE_TEXTURE) {
+ /* to transform a texture, the inverse transform needs
+ * to be applied to the texture coordinate */
+ mul_m4_series(texmap->mat, tmat, rmat, smat);
+ invert_m4(texmap->mat);
+ }
+ else if (texmap->type == TEXMAP_TYPE_POINT) {
+ /* forward transform */
+ mul_m4_series(texmap->mat, tmat, rmat, smat);
+ }
+ else if (texmap->type == TEXMAP_TYPE_VECTOR) {
+ /* no translation for vectors */
+ mul_m4_m4m4(texmap->mat, rmat, smat);
+ }
+ else if (texmap->type == TEXMAP_TYPE_NORMAL) {
+ /* no translation for normals, and inverse transpose */
+ mul_m4_m4m4(texmap->mat, rmat, smat);
+ invert_m4(texmap->mat);
+ transpose_m4(texmap->mat);
+ }
+
+ /* projection last */
+ mul_m4_m4m4(texmap->mat, texmap->mat, proj);
+
+ texmap->flag &= ~TEXMAP_UNIT_MATRIX;
+ }
}
ColorMapping *BKE_texture_colormapping_add(void)
{
- ColorMapping *colormap = MEM_callocN(sizeof(ColorMapping), "ColorMapping");
+ ColorMapping *colormap = MEM_callocN(sizeof(ColorMapping), "ColorMapping");
- BKE_texture_colormapping_default(colormap);
+ BKE_texture_colormapping_default(colormap);
- return colormap;
+ return colormap;
}
void BKE_texture_colormapping_default(ColorMapping *colormap)
{
- memset(colormap, 0, sizeof(ColorMapping));
+ memset(colormap, 0, sizeof(ColorMapping));
- BKE_colorband_init(&colormap->coba, true);
+ BKE_colorband_init(&colormap->coba, true);
- colormap->bright = 1.0;
- colormap->contrast = 1.0;
- colormap->saturation = 1.0;
+ colormap->bright = 1.0;
+ colormap->contrast = 1.0;
+ colormap->saturation = 1.0;
- colormap->blend_color[0] = 0.8f;
- colormap->blend_color[1] = 0.8f;
- colormap->blend_color[2] = 0.8f;
- colormap->blend_type = MA_RAMP_BLEND;
- colormap->blend_factor = 0.0f;
+ colormap->blend_color[0] = 0.8f;
+ colormap->blend_color[1] = 0.8f;
+ colormap->blend_color[2] = 0.8f;
+ colormap->blend_type = MA_RAMP_BLEND;
+ colormap->blend_factor = 0.0f;
}
/* ******************* TEX ************************ */
@@ -191,220 +189,219 @@ void BKE_texture_colormapping_default(ColorMapping *colormap)
/** Free (or release) any data used by this texture (does not free the texure itself). */
void BKE_texture_free(Tex *tex)
{
- BKE_animdata_free((ID *)tex, false);
+ BKE_animdata_free((ID *)tex, false);
- /* is no lib link block, but texture extension */
- if (tex->nodetree) {
- ntreeFreeNestedTree(tex->nodetree);
- MEM_freeN(tex->nodetree);
- tex->nodetree = NULL;
- }
+ /* is no lib link block, but texture extension */
+ if (tex->nodetree) {
+ ntreeFreeNestedTree(tex->nodetree);
+ MEM_freeN(tex->nodetree);
+ tex->nodetree = NULL;
+ }
- MEM_SAFE_FREE(tex->coba);
+ MEM_SAFE_FREE(tex->coba);
- BKE_icon_id_delete((ID *)tex);
- BKE_previewimg_free(&tex->preview);
+ BKE_icon_id_delete((ID *)tex);
+ BKE_previewimg_free(&tex->preview);
}
/* ------------------------------------------------------------------------- */
void BKE_texture_default(Tex *tex)
{
- /* BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(tex, id)); */ /* Not here, can be called with some pointers set. :/ */
-
- tex->type = TEX_IMAGE;
- tex->ima = NULL;
- tex->stype = 0;
- tex->flag = TEX_CHECKER_ODD;
- tex->imaflag = TEX_INTERPOL | TEX_MIPMAP | TEX_USEALPHA;
- tex->extend = TEX_REPEAT;
- tex->cropxmin = tex->cropymin = 0.0;
- tex->cropxmax = tex->cropymax = 1.0;
- tex->texfilter = TXF_EWA;
- tex->afmax = 8;
- tex->xrepeat = tex->yrepeat = 1;
- tex->sfra = 1;
- tex->frames = 0;
- tex->offset = 0;
- tex->noisesize = 0.25;
- tex->noisedepth = 2;
- tex->turbul = 5.0;
- tex->nabla = 0.025; // also in do_versions
- tex->bright = 1.0;
- tex->contrast = 1.0;
- tex->saturation = 1.0;
- tex->filtersize = 1.0;
- tex->rfac = 1.0;
- tex->gfac = 1.0;
- tex->bfac = 1.0;
- /* newnoise: init. */
- tex->noisebasis = 0;
- tex->noisebasis2 = 0;
- /* musgrave */
- tex->mg_H = 1.0;
- tex->mg_lacunarity = 2.0;
- tex->mg_octaves = 2.0;
- tex->mg_offset = 1.0;
- tex->mg_gain = 1.0;
- tex->ns_outscale = 1.0;
- /* distnoise */
- tex->dist_amount = 1.0;
- /* voronoi */
- tex->vn_w1 = 1.0;
- tex->vn_w2 = tex->vn_w3 = tex->vn_w4 = 0.0;
- tex->vn_mexp = 2.5;
- tex->vn_distm = 0;
- tex->vn_coltype = 0;
-
- tex->iuser.ok = 1;
- tex->iuser.frames = 100;
- tex->iuser.sfra = 1;
-
- tex->preview = NULL;
+ /* BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(tex, id)); */ /* Not here, can be called with some pointers set. :/ */
+
+ tex->type = TEX_IMAGE;
+ tex->ima = NULL;
+ tex->stype = 0;
+ tex->flag = TEX_CHECKER_ODD;
+ tex->imaflag = TEX_INTERPOL | TEX_MIPMAP | TEX_USEALPHA;
+ tex->extend = TEX_REPEAT;
+ tex->cropxmin = tex->cropymin = 0.0;
+ tex->cropxmax = tex->cropymax = 1.0;
+ tex->texfilter = TXF_EWA;
+ tex->afmax = 8;
+ tex->xrepeat = tex->yrepeat = 1;
+ tex->sfra = 1;
+ tex->frames = 0;
+ tex->offset = 0;
+ tex->noisesize = 0.25;
+ tex->noisedepth = 2;
+ tex->turbul = 5.0;
+ tex->nabla = 0.025; // also in do_versions
+ tex->bright = 1.0;
+ tex->contrast = 1.0;
+ tex->saturation = 1.0;
+ tex->filtersize = 1.0;
+ tex->rfac = 1.0;
+ tex->gfac = 1.0;
+ tex->bfac = 1.0;
+ /* newnoise: init. */
+ tex->noisebasis = 0;
+ tex->noisebasis2 = 0;
+ /* musgrave */
+ tex->mg_H = 1.0;
+ tex->mg_lacunarity = 2.0;
+ tex->mg_octaves = 2.0;
+ tex->mg_offset = 1.0;
+ tex->mg_gain = 1.0;
+ tex->ns_outscale = 1.0;
+ /* distnoise */
+ tex->dist_amount = 1.0;
+ /* voronoi */
+ tex->vn_w1 = 1.0;
+ tex->vn_w2 = tex->vn_w3 = tex->vn_w4 = 0.0;
+ tex->vn_mexp = 2.5;
+ tex->vn_distm = 0;
+ tex->vn_coltype = 0;
+
+ tex->iuser.ok = 1;
+ tex->iuser.frames = 100;
+ tex->iuser.sfra = 1;
+
+ tex->preview = NULL;
}
void BKE_texture_type_set(Tex *tex, int type)
{
- tex->type = type;
+ tex->type = type;
}
/* ------------------------------------------------------------------------- */
Tex *BKE_texture_add(Main *bmain, const char *name)
{
- Tex *tex;
+ Tex *tex;
- tex = BKE_libblock_alloc(bmain, ID_TE, name, 0);
+ tex = BKE_libblock_alloc(bmain, ID_TE, name, 0);
- BKE_texture_default(tex);
+ BKE_texture_default(tex);
- return tex;
+ return tex;
}
/* ------------------------------------------------------------------------- */
void BKE_texture_mtex_default(MTex *mtex)
{
- mtex->texco = TEXCO_UV;
- mtex->mapto = MAP_COL;
- mtex->object = NULL;
- mtex->projx = PROJ_X;
- mtex->projy = PROJ_Y;
- mtex->projz = PROJ_Z;
- mtex->mapping = MTEX_FLAT;
- mtex->ofs[0] = 0.0;
- mtex->ofs[1] = 0.0;
- mtex->ofs[2] = 0.0;
- mtex->size[0] = 1.0;
- mtex->size[1] = 1.0;
- mtex->size[2] = 1.0;
- mtex->tex = NULL;
- mtex->colormodel = 0;
- mtex->r = 1.0;
- mtex->g = 0.0;
- mtex->b = 1.0;
- mtex->k = 1.0;
- mtex->def_var = 1.0;
- mtex->blendtype = MTEX_BLEND;
- mtex->colfac = 1.0;
- mtex->norfac = 1.0;
- mtex->varfac = 1.0;
- mtex->dispfac = 0.2;
- mtex->colspecfac = 1.0f;
- mtex->mirrfac = 1.0f;
- mtex->alphafac = 1.0f;
- mtex->difffac = 1.0f;
- mtex->specfac = 1.0f;
- mtex->emitfac = 1.0f;
- mtex->hardfac = 1.0f;
- mtex->raymirrfac = 1.0f;
- mtex->translfac = 1.0f;
- mtex->ambfac = 1.0f;
- mtex->colemitfac = 1.0f;
- mtex->colreflfac = 1.0f;
- mtex->coltransfac = 1.0f;
- mtex->densfac = 1.0f;
- mtex->scatterfac = 1.0f;
- mtex->reflfac = 1.0f;
- mtex->shadowfac = 1.0f;
- mtex->zenupfac = 1.0f;
- mtex->zendownfac = 1.0f;
- mtex->blendfac = 1.0f;
- mtex->timefac = 1.0f;
- mtex->lengthfac = 1.0f;
- mtex->clumpfac = 1.0f;
- mtex->kinkfac = 1.0f;
- mtex->kinkampfac = 1.0f;
- mtex->roughfac = 1.0f;
- mtex->twistfac = 1.0f;
- mtex->padensfac = 1.0f;
- mtex->lifefac = 1.0f;
- mtex->sizefac = 1.0f;
- mtex->ivelfac = 1.0f;
- mtex->dampfac = 1.0f;
- mtex->gravityfac = 1.0f;
- mtex->fieldfac = 1.0f;
- mtex->normapspace = MTEX_NSPACE_TANGENT;
- mtex->brush_map_mode = MTEX_MAP_MODE_TILED;
- mtex->random_angle = 2.0f * (float)M_PI;
- mtex->brush_angle_mode = 0;
+ mtex->texco = TEXCO_UV;
+ mtex->mapto = MAP_COL;
+ mtex->object = NULL;
+ mtex->projx = PROJ_X;
+ mtex->projy = PROJ_Y;
+ mtex->projz = PROJ_Z;
+ mtex->mapping = MTEX_FLAT;
+ mtex->ofs[0] = 0.0;
+ mtex->ofs[1] = 0.0;
+ mtex->ofs[2] = 0.0;
+ mtex->size[0] = 1.0;
+ mtex->size[1] = 1.0;
+ mtex->size[2] = 1.0;
+ mtex->tex = NULL;
+ mtex->colormodel = 0;
+ mtex->r = 1.0;
+ mtex->g = 0.0;
+ mtex->b = 1.0;
+ mtex->k = 1.0;
+ mtex->def_var = 1.0;
+ mtex->blendtype = MTEX_BLEND;
+ mtex->colfac = 1.0;
+ mtex->norfac = 1.0;
+ mtex->varfac = 1.0;
+ mtex->dispfac = 0.2;
+ mtex->colspecfac = 1.0f;
+ mtex->mirrfac = 1.0f;
+ mtex->alphafac = 1.0f;
+ mtex->difffac = 1.0f;
+ mtex->specfac = 1.0f;
+ mtex->emitfac = 1.0f;
+ mtex->hardfac = 1.0f;
+ mtex->raymirrfac = 1.0f;
+ mtex->translfac = 1.0f;
+ mtex->ambfac = 1.0f;
+ mtex->colemitfac = 1.0f;
+ mtex->colreflfac = 1.0f;
+ mtex->coltransfac = 1.0f;
+ mtex->densfac = 1.0f;
+ mtex->scatterfac = 1.0f;
+ mtex->reflfac = 1.0f;
+ mtex->shadowfac = 1.0f;
+ mtex->zenupfac = 1.0f;
+ mtex->zendownfac = 1.0f;
+ mtex->blendfac = 1.0f;
+ mtex->timefac = 1.0f;
+ mtex->lengthfac = 1.0f;
+ mtex->clumpfac = 1.0f;
+ mtex->kinkfac = 1.0f;
+ mtex->kinkampfac = 1.0f;
+ mtex->roughfac = 1.0f;
+ mtex->twistfac = 1.0f;
+ mtex->padensfac = 1.0f;
+ mtex->lifefac = 1.0f;
+ mtex->sizefac = 1.0f;
+ mtex->ivelfac = 1.0f;
+ mtex->dampfac = 1.0f;
+ mtex->gravityfac = 1.0f;
+ mtex->fieldfac = 1.0f;
+ mtex->normapspace = MTEX_NSPACE_TANGENT;
+ mtex->brush_map_mode = MTEX_MAP_MODE_TILED;
+ mtex->random_angle = 2.0f * (float)M_PI;
+ mtex->brush_angle_mode = 0;
}
-
/* ------------------------------------------------------------------------- */
MTex *BKE_texture_mtex_add(void)
{
- MTex *mtex;
+ MTex *mtex;
- mtex = MEM_callocN(sizeof(MTex), "BKE_texture_mtex_add");
+ mtex = MEM_callocN(sizeof(MTex), "BKE_texture_mtex_add");
- BKE_texture_mtex_default(mtex);
+ BKE_texture_mtex_default(mtex);
- return mtex;
+ return mtex;
}
/* slot -1 for first free ID */
MTex *BKE_texture_mtex_add_id(ID *id, int slot)
{
- MTex **mtex_ar;
- short act;
-
- give_active_mtex(id, &mtex_ar, &act);
-
- if (mtex_ar == NULL) {
- return NULL;
- }
-
- if (slot == -1) {
- /* find first free */
- int i;
- for (i = 0; i < MAX_MTEX; i++) {
- if (!mtex_ar[i]) {
- slot = i;
- break;
- }
- }
- if (slot == -1) {
- return NULL;
- }
- }
- else {
- /* make sure slot is valid */
- if (slot < 0 || slot >= MAX_MTEX) {
- return NULL;
- }
- }
-
- if (mtex_ar[slot]) {
- id_us_min((ID *)mtex_ar[slot]->tex);
- MEM_freeN(mtex_ar[slot]);
- mtex_ar[slot] = NULL;
- }
-
- mtex_ar[slot] = BKE_texture_mtex_add();
-
- return mtex_ar[slot];
+ MTex **mtex_ar;
+ short act;
+
+ give_active_mtex(id, &mtex_ar, &act);
+
+ if (mtex_ar == NULL) {
+ return NULL;
+ }
+
+ if (slot == -1) {
+ /* find first free */
+ int i;
+ for (i = 0; i < MAX_MTEX; i++) {
+ if (!mtex_ar[i]) {
+ slot = i;
+ break;
+ }
+ }
+ if (slot == -1) {
+ return NULL;
+ }
+ }
+ else {
+ /* make sure slot is valid */
+ if (slot < 0 || slot >= MAX_MTEX) {
+ return NULL;
+ }
+ }
+
+ if (mtex_ar[slot]) {
+ id_us_min((ID *)mtex_ar[slot]->tex);
+ MEM_freeN(mtex_ar[slot]);
+ mtex_ar[slot] = NULL;
+ }
+
+ mtex_ar[slot] = BKE_texture_mtex_add();
+
+ return mtex_ar[slot];
}
/* ------------------------------------------------------------------------- */
@@ -419,274 +416,284 @@ MTex *BKE_texture_mtex_add_id(ID *id, int slot)
*/
void BKE_texture_copy_data(Main *bmain, Tex *tex_dst, const Tex *tex_src, const int flag)
{
- if (!BKE_texture_is_image_user(tex_src)) {
- tex_dst->ima = NULL;
- }
-
- if (tex_dst->coba) {
- tex_dst->coba = MEM_dupallocN(tex_dst->coba);
- }
- if (tex_src->nodetree) {
- if (tex_src->nodetree->execdata) {
- ntreeTexEndExecTree(tex_src->nodetree->execdata);
- }
- /* Note: nodetree is *not* in bmain, however this specific case is handled at lower level
- * (see BKE_libblock_copy_ex()). */
- BKE_id_copy_ex(bmain, (ID *)tex_src->nodetree, (ID **)&tex_dst->nodetree, flag);
- }
-
- if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
- BKE_previewimg_id_copy(&tex_dst->id, &tex_src->id);
- }
- else {
- tex_dst->preview = NULL;
- }
+ if (!BKE_texture_is_image_user(tex_src)) {
+ tex_dst->ima = NULL;
+ }
+
+ if (tex_dst->coba) {
+ tex_dst->coba = MEM_dupallocN(tex_dst->coba);
+ }
+ if (tex_src->nodetree) {
+ if (tex_src->nodetree->execdata) {
+ ntreeTexEndExecTree(tex_src->nodetree->execdata);
+ }
+ /* Note: nodetree is *not* in bmain, however this specific case is handled at lower level
+ * (see BKE_libblock_copy_ex()). */
+ BKE_id_copy_ex(bmain, (ID *)tex_src->nodetree, (ID **)&tex_dst->nodetree, flag);
+ }
+
+ if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
+ BKE_previewimg_id_copy(&tex_dst->id, &tex_src->id);
+ }
+ else {
+ tex_dst->preview = NULL;
+ }
}
Tex *BKE_texture_copy(Main *bmain, const Tex *tex)
{
- Tex *tex_copy;
- BKE_id_copy(bmain, &tex->id, (ID **)&tex_copy);
- return tex_copy;
+ Tex *tex_copy;
+ BKE_id_copy(bmain, &tex->id, (ID **)&tex_copy);
+ return tex_copy;
}
/* texture copy without adding to main dbase */
Tex *BKE_texture_localize(Tex *tex)
{
- /* TODO(bastien): Replace with something like:
- *
- * Tex *tex_copy;
- * BKE_id_copy_ex(bmain, &tex->id, (ID **)&tex_copy,
- * LIB_ID_COPY_NO_MAIN | LIB_ID_COPY_NO_PREVIEW | LIB_ID_COPY_NO_USER_REFCOUNT,
- * false);
- * return tex_copy;
- *
- * NOTE: Only possible once nested node trees are fully converted to that too. */
+ /* TODO(bastien): Replace with something like:
+ *
+ * Tex *tex_copy;
+ * BKE_id_copy_ex(bmain, &tex->id, (ID **)&tex_copy,
+ * LIB_ID_COPY_NO_MAIN | LIB_ID_COPY_NO_PREVIEW | LIB_ID_COPY_NO_USER_REFCOUNT,
+ * false);
+ * return tex_copy;
+ *
+ * NOTE: Only possible once nested node trees are fully converted to that too. */
- Tex *texn;
+ Tex *texn;
- texn = BKE_libblock_copy_for_localize(&tex->id);
+ texn = BKE_libblock_copy_for_localize(&tex->id);
- /* image texture: BKE_texture_free also doesn't decrease */
+ /* image texture: BKE_texture_free also doesn't decrease */
- if (texn->coba) texn->coba = MEM_dupallocN(texn->coba);
+ if (texn->coba)
+ texn->coba = MEM_dupallocN(texn->coba);
- texn->preview = NULL;
+ texn->preview = NULL;
- if (tex->nodetree) {
- texn->nodetree = ntreeLocalize(tex->nodetree);
- }
+ if (tex->nodetree) {
+ texn->nodetree = ntreeLocalize(tex->nodetree);
+ }
- texn->id.tag |= LIB_TAG_LOCALIZED;
+ texn->id.tag |= LIB_TAG_LOCALIZED;
- return texn;
+ return texn;
}
-
/* ------------------------------------------------------------------------- */
void BKE_texture_make_local(Main *bmain, Tex *tex, const bool lib_local)
{
- BKE_id_make_local_generic(bmain, &tex->id, true, lib_local);
+ BKE_id_make_local_generic(bmain, &tex->id, true, lib_local);
}
Tex *give_current_linestyle_texture(FreestyleLineStyle *linestyle)
{
- MTex *mtex = NULL;
- Tex *tex = NULL;
+ MTex *mtex = NULL;
+ Tex *tex = NULL;
- if (linestyle) {
- mtex = linestyle->mtex[(int)(linestyle->texact)];
- if (mtex) tex = mtex->tex;
- }
+ if (linestyle) {
+ mtex = linestyle->mtex[(int)(linestyle->texact)];
+ if (mtex)
+ tex = mtex->tex;
+ }
- return tex;
+ return tex;
}
void set_current_linestyle_texture(FreestyleLineStyle *linestyle, Tex *newtex)
{
- int act = linestyle->texact;
+ int act = linestyle->texact;
- if (linestyle->mtex[act] && linestyle->mtex[act]->tex)
- id_us_min(&linestyle->mtex[act]->tex->id);
+ if (linestyle->mtex[act] && linestyle->mtex[act]->tex)
+ id_us_min(&linestyle->mtex[act]->tex->id);
- if (newtex) {
- if (!linestyle->mtex[act]) {
- linestyle->mtex[act] = BKE_texture_mtex_add();
- linestyle->mtex[act]->texco = TEXCO_STROKE;
- }
+ if (newtex) {
+ if (!linestyle->mtex[act]) {
+ linestyle->mtex[act] = BKE_texture_mtex_add();
+ linestyle->mtex[act]->texco = TEXCO_STROKE;
+ }
- linestyle->mtex[act]->tex = newtex;
- id_us_plus(&newtex->id);
- }
- else if (linestyle->mtex[act]) {
- MEM_freeN(linestyle->mtex[act]);
- linestyle->mtex[act] = NULL;
- }
+ linestyle->mtex[act]->tex = newtex;
+ id_us_plus(&newtex->id);
+ }
+ else if (linestyle->mtex[act]) {
+ MEM_freeN(linestyle->mtex[act]);
+ linestyle->mtex[act] = NULL;
+ }
}
bool give_active_mtex(ID *id, MTex ***mtex_ar, short *act)
{
- switch (GS(id->name)) {
- case ID_LS:
- *mtex_ar = ((FreestyleLineStyle *)id)->mtex;
- if (act) *act = (((FreestyleLineStyle *)id)->texact);
- break;
- case ID_PA:
- *mtex_ar = ((ParticleSettings *)id)->mtex;
- if (act) *act = (((ParticleSettings *)id)->texact);
- break;
- default:
- *mtex_ar = NULL;
- if (act) *act = 0;
- return false;
- }
-
- return true;
+ switch (GS(id->name)) {
+ case ID_LS:
+ *mtex_ar = ((FreestyleLineStyle *)id)->mtex;
+ if (act)
+ *act = (((FreestyleLineStyle *)id)->texact);
+ break;
+ case ID_PA:
+ *mtex_ar = ((ParticleSettings *)id)->mtex;
+ if (act)
+ *act = (((ParticleSettings *)id)->texact);
+ break;
+ default:
+ *mtex_ar = NULL;
+ if (act)
+ *act = 0;
+ return false;
+ }
+
+ return true;
}
void set_active_mtex(ID *id, short act)
{
- if (act < 0) act = 0;
- else if (act >= MAX_MTEX) act = MAX_MTEX - 1;
+ if (act < 0)
+ act = 0;
+ else if (act >= MAX_MTEX)
+ act = MAX_MTEX - 1;
- switch (GS(id->name)) {
- case ID_LS:
- ((FreestyleLineStyle *)id)->texact = act;
- break;
- case ID_PA:
- ((ParticleSettings *)id)->texact = act;
- break;
- default:
- break;
- }
+ switch (GS(id->name)) {
+ case ID_LS:
+ ((FreestyleLineStyle *)id)->texact = act;
+ break;
+ case ID_PA:
+ ((ParticleSettings *)id)->texact = act;
+ break;
+ default:
+ break;
+ }
}
Tex *give_current_brush_texture(Brush *br)
{
- return br->mtex.tex;
+ return br->mtex.tex;
}
void set_current_brush_texture(Brush *br, Tex *newtex)
{
- if (br->mtex.tex)
- id_us_min(&br->mtex.tex->id);
+ if (br->mtex.tex)
+ id_us_min(&br->mtex.tex->id);
- if (newtex) {
- br->mtex.tex = newtex;
- id_us_plus(&newtex->id);
- }
+ if (newtex) {
+ br->mtex.tex = newtex;
+ id_us_plus(&newtex->id);
+ }
}
Tex *give_current_particle_texture(ParticleSettings *part)
{
- MTex *mtex = NULL;
- Tex *tex = NULL;
+ MTex *mtex = NULL;
+ Tex *tex = NULL;
- if (!part) return NULL;
+ if (!part)
+ return NULL;
- mtex = part->mtex[(int)(part->texact)];
- if (mtex) tex = mtex->tex;
+ mtex = part->mtex[(int)(part->texact)];
+ if (mtex)
+ tex = mtex->tex;
- return tex;
+ return tex;
}
void set_current_particle_texture(ParticleSettings *part, Tex *newtex)
{
- int act = part->texact;
+ int act = part->texact;
- if (part->mtex[act] && part->mtex[act]->tex)
- id_us_min(&part->mtex[act]->tex->id);
+ if (part->mtex[act] && part->mtex[act]->tex)
+ id_us_min(&part->mtex[act]->tex->id);
- if (newtex) {
- if (!part->mtex[act]) {
- part->mtex[act] = BKE_texture_mtex_add();
- part->mtex[act]->texco = TEXCO_ORCO;
- part->mtex[act]->blendtype = MTEX_MUL;
- }
+ if (newtex) {
+ if (!part->mtex[act]) {
+ part->mtex[act] = BKE_texture_mtex_add();
+ part->mtex[act]->texco = TEXCO_ORCO;
+ part->mtex[act]->blendtype = MTEX_MUL;
+ }
- part->mtex[act]->tex = newtex;
- id_us_plus(&newtex->id);
- }
- else if (part->mtex[act]) {
- MEM_freeN(part->mtex[act]);
- part->mtex[act] = NULL;
- }
+ part->mtex[act]->tex = newtex;
+ id_us_plus(&newtex->id);
+ }
+ else if (part->mtex[act]) {
+ MEM_freeN(part->mtex[act]);
+ part->mtex[act] = NULL;
+ }
}
/* ------------------------------------------------------------------------- */
-
void BKE_texture_pointdensity_init_data(PointDensity *pd)
{
- pd->flag = 0;
- pd->radius = 0.3f;
- pd->falloff_type = TEX_PD_FALLOFF_STD;
- pd->falloff_softness = 2.0;
- pd->source = TEX_PD_PSYS;
- pd->point_tree = NULL;
- pd->point_data = NULL;
- pd->noise_size = 0.5f;
- pd->noise_depth = 1;
- pd->noise_fac = 1.0f;
- pd->noise_influence = TEX_PD_NOISE_STATIC;
- pd->coba = BKE_colorband_add(true);
- pd->speed_scale = 1.0f;
- pd->totpoints = 0;
- pd->object = NULL;
- pd->psys = 0;
- pd->psys_cache_space = TEX_PD_WORLDSPACE;
- pd->falloff_curve = curvemapping_add(1, 0, 0, 1, 1);
-
- pd->falloff_curve->preset = CURVE_PRESET_LINE;
- pd->falloff_curve->cm->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
- curvemap_reset(pd->falloff_curve->cm, &pd->falloff_curve->clipr, pd->falloff_curve->preset, CURVEMAP_SLOPE_POSITIVE);
- curvemapping_changed(pd->falloff_curve, false);
+ pd->flag = 0;
+ pd->radius = 0.3f;
+ pd->falloff_type = TEX_PD_FALLOFF_STD;
+ pd->falloff_softness = 2.0;
+ pd->source = TEX_PD_PSYS;
+ pd->point_tree = NULL;
+ pd->point_data = NULL;
+ pd->noise_size = 0.5f;
+ pd->noise_depth = 1;
+ pd->noise_fac = 1.0f;
+ pd->noise_influence = TEX_PD_NOISE_STATIC;
+ pd->coba = BKE_colorband_add(true);
+ pd->speed_scale = 1.0f;
+ pd->totpoints = 0;
+ pd->object = NULL;
+ pd->psys = 0;
+ pd->psys_cache_space = TEX_PD_WORLDSPACE;
+ pd->falloff_curve = curvemapping_add(1, 0, 0, 1, 1);
+
+ pd->falloff_curve->preset = CURVE_PRESET_LINE;
+ pd->falloff_curve->cm->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
+ curvemap_reset(pd->falloff_curve->cm,
+ &pd->falloff_curve->clipr,
+ pd->falloff_curve->preset,
+ CURVEMAP_SLOPE_POSITIVE);
+ curvemapping_changed(pd->falloff_curve, false);
}
PointDensity *BKE_texture_pointdensity_add(void)
{
- PointDensity *pd = MEM_callocN(sizeof(PointDensity), "pointdensity");
- BKE_texture_pointdensity_init_data(pd);
- return pd;
+ PointDensity *pd = MEM_callocN(sizeof(PointDensity), "pointdensity");
+ BKE_texture_pointdensity_init_data(pd);
+ return pd;
}
PointDensity *BKE_texture_pointdensity_copy(const PointDensity *pd, const int UNUSED(flag))
{
- PointDensity *pdn;
+ PointDensity *pdn;
- pdn = MEM_dupallocN(pd);
- pdn->point_tree = NULL;
- pdn->point_data = NULL;
- if (pdn->coba) {
- pdn->coba = MEM_dupallocN(pdn->coba);
- }
- pdn->falloff_curve = curvemapping_copy(pdn->falloff_curve); /* can be NULL */
- return pdn;
+ pdn = MEM_dupallocN(pd);
+ pdn->point_tree = NULL;
+ pdn->point_data = NULL;
+ if (pdn->coba) {
+ pdn->coba = MEM_dupallocN(pdn->coba);
+ }
+ pdn->falloff_curve = curvemapping_copy(pdn->falloff_curve); /* can be NULL */
+ return pdn;
}
void BKE_texture_pointdensity_free_data(PointDensity *pd)
{
- if (pd->point_tree) {
- BLI_bvhtree_free(pd->point_tree);
- pd->point_tree = NULL;
- }
- if (pd->point_data) {
- MEM_freeN(pd->point_data);
- pd->point_data = NULL;
- }
- if (pd->coba) {
- MEM_freeN(pd->coba);
- pd->coba = NULL;
- }
+ if (pd->point_tree) {
+ BLI_bvhtree_free(pd->point_tree);
+ pd->point_tree = NULL;
+ }
+ if (pd->point_data) {
+ MEM_freeN(pd->point_data);
+ pd->point_data = NULL;
+ }
+ if (pd->coba) {
+ MEM_freeN(pd->coba);
+ pd->coba = NULL;
+ }
- curvemapping_free(pd->falloff_curve); /* can be NULL */
+ curvemapping_free(pd->falloff_curve); /* can be NULL */
}
void BKE_texture_pointdensity_free(PointDensity *pd)
{
- BKE_texture_pointdensity_free_data(pd);
- MEM_freeN(pd);
+ BKE_texture_pointdensity_free_data(pd);
+ MEM_freeN(pd);
}
/* ------------------------------------------------------------------------- */
@@ -695,96 +702,97 @@ void BKE_texture_pointdensity_free(PointDensity *pd)
*/
bool BKE_texture_is_image_user(const struct Tex *tex)
{
- switch (tex->type) {
- case TEX_IMAGE:
- {
- return true;
- }
- }
+ switch (tex->type) {
+ case TEX_IMAGE: {
+ return true;
+ }
+ }
- return false;
+ return false;
}
/* ------------------------------------------------------------------------- */
bool BKE_texture_dependsOnTime(const struct Tex *texture)
{
- if (texture->ima && BKE_image_is_animated(texture->ima)) {
- return true;
- }
- else if (texture->adt) {
- /* assume anything in adt means the texture is animated */
- return true;
- }
- else if (texture->type == TEX_NOISE) {
- /* noise always varies with time */
- return true;
- }
- return false;
+ if (texture->ima && BKE_image_is_animated(texture->ima)) {
+ return true;
+ }
+ else if (texture->adt) {
+ /* assume anything in adt means the texture is animated */
+ return true;
+ }
+ else if (texture->type == TEX_NOISE) {
+ /* noise always varies with time */
+ return true;
+ }
+ return false;
}
/* ------------------------------------------------------------------------- */
-void BKE_texture_get_value_ex(
- const Scene *scene, Tex *texture,
- float *tex_co, TexResult *texres,
- struct ImagePool *pool,
- bool use_color_management)
+void BKE_texture_get_value_ex(const Scene *scene,
+ Tex *texture,
+ float *tex_co,
+ TexResult *texres,
+ struct ImagePool *pool,
+ bool use_color_management)
{
- int result_type;
- bool do_color_manage = false;
+ int result_type;
+ bool do_color_manage = false;
- if (scene && use_color_management) {
- do_color_manage = BKE_scene_check_color_management_enabled(scene);
- }
+ if (scene && use_color_management) {
+ do_color_manage = BKE_scene_check_color_management_enabled(scene);
+ }
- /* no node textures for now */
- result_type = multitex_ext_safe(texture, tex_co, texres, pool, do_color_manage, false);
+ /* no node textures for now */
+ result_type = multitex_ext_safe(texture, tex_co, texres, pool, do_color_manage, false);
- /* if the texture gave an RGB value, we assume it didn't give a valid
- * intensity, since this is in the context of modifiers don't use perceptual color conversion.
- * if the texture didn't give an RGB value, copy the intensity across
- */
- if (result_type & TEX_RGB) {
- texres->tin = (1.0f / 3.0f) * (texres->tr + texres->tg + texres->tb);
- }
- else {
- copy_v3_fl(&texres->tr, texres->tin);
- }
+ /* if the texture gave an RGB value, we assume it didn't give a valid
+ * intensity, since this is in the context of modifiers don't use perceptual color conversion.
+ * if the texture didn't give an RGB value, copy the intensity across
+ */
+ if (result_type & TEX_RGB) {
+ texres->tin = (1.0f / 3.0f) * (texres->tr + texres->tg + texres->tb);
+ }
+ else {
+ copy_v3_fl(&texres->tr, texres->tin);
+ }
}
void BKE_texture_get_value(
- const Scene *scene, Tex *texture,
- float *tex_co, TexResult *texres, bool use_color_management)
+ const Scene *scene, Tex *texture, float *tex_co, TexResult *texres, bool use_color_management)
{
- BKE_texture_get_value_ex(scene, texture, tex_co, texres, NULL, use_color_management);
+ BKE_texture_get_value_ex(scene, texture, tex_co, texres, NULL, use_color_management);
}
-static void texture_nodes_fetch_images_for_pool(Tex *texture, bNodeTree *ntree, struct ImagePool *pool)
+static void texture_nodes_fetch_images_for_pool(Tex *texture,
+ bNodeTree *ntree,
+ struct ImagePool *pool)
{
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
- if (node->type == SH_NODE_TEX_IMAGE && node->id != NULL) {
- Image *image = (Image *)node->id;
- BKE_image_pool_acquire_ibuf(image, &texture->iuser, pool);
- }
- else if (node->type == NODE_GROUP && node->id != NULL) {
- /* TODO(sergey): Do we need to control recursion here? */
- bNodeTree *nested_tree = (bNodeTree *)node->id;
- texture_nodes_fetch_images_for_pool(texture, nested_tree, pool);
- }
- }
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_TEX_IMAGE && node->id != NULL) {
+ Image *image = (Image *)node->id;
+ BKE_image_pool_acquire_ibuf(image, &texture->iuser, pool);
+ }
+ else if (node->type == NODE_GROUP && node->id != NULL) {
+ /* TODO(sergey): Do we need to control recursion here? */
+ bNodeTree *nested_tree = (bNodeTree *)node->id;
+ texture_nodes_fetch_images_for_pool(texture, nested_tree, pool);
+ }
+ }
}
/* Make sure all images used by texture are loaded into pool. */
void BKE_texture_fetch_images_for_pool(Tex *texture, struct ImagePool *pool)
{
- if (texture->nodetree != NULL) {
- texture_nodes_fetch_images_for_pool(texture, texture->nodetree, pool);
- }
- else {
- if (texture->type == TEX_IMAGE) {
- if (texture->ima != NULL) {
- BKE_image_pool_acquire_ibuf(texture->ima, &texture->iuser, pool);
- }
- }
- }
+ if (texture->nodetree != NULL) {
+ texture_nodes_fetch_images_for_pool(texture, texture->nodetree, pool);
+ }
+ else {
+ if (texture->type == TEX_IMAGE) {
+ if (texture->ima != NULL) {
+ BKE_image_pool_acquire_ibuf(texture->ima, &texture->iuser, pool);
+ }
+ }
+ }
}
diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c
index 28f47cbf067..c478ce274b8 100644
--- a/source/blender/blenkernel/intern/tracking.c
+++ b/source/blender/blenkernel/intern/tracking.c
@@ -32,7 +32,7 @@
#include "DNA_gpencil_types.h"
#include "DNA_camera_types.h"
#include "DNA_movieclip_types.h"
-#include "DNA_object_types.h" /* SELECT */
+#include "DNA_object_types.h" /* SELECT */
#include "DNA_scene_types.h"
#include "BLI_utildefines.h"
@@ -64,15 +64,15 @@
#include "tracking_private.h"
typedef struct MovieDistortion {
- struct libmv_CameraIntrinsics *intrinsics;
- /* Parameters needed for coordinates normalization. */
- float principal[2];
- float pixel_aspect;
- float focal;
+ struct libmv_CameraIntrinsics *intrinsics;
+ /* Parameters needed for coordinates normalization. */
+ float principal[2];
+ float pixel_aspect;
+ float focal;
} MovieDistortion;
static struct {
- ListBase tracks;
+ ListBase tracks;
} tracking_clipboard;
/*********************** Common functions *************************/
@@ -80,25 +80,25 @@ static struct {
/* Free the whole list of tracks, list's head and tail are set to NULL. */
static void tracking_tracks_free(ListBase *tracks)
{
- MovieTrackingTrack *track;
+ MovieTrackingTrack *track;
- for (track = tracks->first; track; track = track->next) {
- BKE_tracking_track_free(track);
- }
+ for (track = tracks->first; track; track = track->next) {
+ BKE_tracking_track_free(track);
+ }
- BLI_freelistN(tracks);
+ BLI_freelistN(tracks);
}
/* Free the whole list of plane tracks, list's head and tail are set to NULL. */
static void tracking_plane_tracks_free(ListBase *plane_tracks)
{
- MovieTrackingPlaneTrack *plane_track;
+ MovieTrackingPlaneTrack *plane_track;
- for (plane_track = plane_tracks->first; plane_track; plane_track = plane_track->next) {
- BKE_tracking_plane_track_free(plane_track);
- }
+ for (plane_track = plane_tracks->first; plane_track; plane_track = plane_track->next) {
+ BKE_tracking_plane_track_free(plane_track);
+ }
- BLI_freelistN(plane_tracks);
+ BLI_freelistN(plane_tracks);
}
/* Free reconstruction structures, only frees contents of a structure,
@@ -108,8 +108,8 @@ static void tracking_plane_tracks_free(ListBase *plane_tracks)
*/
static void tracking_reconstruction_free(MovieTrackingReconstruction *reconstruction)
{
- if (reconstruction->cameras)
- MEM_freeN(reconstruction->cameras);
+ if (reconstruction->cameras)
+ MEM_freeN(reconstruction->cameras);
}
/* Free memory used by tracking object, only frees contents of the structure,
@@ -119,22 +119,22 @@ static void tracking_reconstruction_free(MovieTrackingReconstruction *reconstruc
*/
static void tracking_object_free(MovieTrackingObject *object)
{
- tracking_tracks_free(&object->tracks);
- tracking_plane_tracks_free(&object->plane_tracks);
- tracking_reconstruction_free(&object->reconstruction);
+ tracking_tracks_free(&object->tracks);
+ tracking_plane_tracks_free(&object->plane_tracks);
+ tracking_reconstruction_free(&object->reconstruction);
}
/* Free list of tracking objects, list's head and tail is set to NULL. */
static void tracking_objects_free(ListBase *objects)
{
- MovieTrackingObject *object;
+ MovieTrackingObject *object;
- /* Free objects contents. */
- for (object = objects->first; object; object = object->next)
- tracking_object_free(object);
+ /* Free objects contents. */
+ for (object = objects->first; object; object = object->next)
+ tracking_object_free(object);
- /* Free objects themselves. */
- BLI_freelistN(objects);
+ /* Free objects themselves. */
+ BLI_freelistN(objects);
}
/* Free memory used by a dopesheet, only frees dopesheet contents.
@@ -142,26 +142,26 @@ static void tracking_objects_free(ListBase *objects)
*/
static void tracking_dopesheet_free(MovieTrackingDopesheet *dopesheet)
{
- MovieTrackingDopesheetChannel *channel;
+ MovieTrackingDopesheetChannel *channel;
- /* Free channel's sergments. */
- channel = dopesheet->channels.first;
- while (channel) {
- if (channel->segments) {
- MEM_freeN(channel->segments);
- }
+ /* Free channel's sergments. */
+ channel = dopesheet->channels.first;
+ while (channel) {
+ if (channel->segments) {
+ MEM_freeN(channel->segments);
+ }
- channel = channel->next;
- }
+ channel = channel->next;
+ }
- /* Free lists themselves. */
- BLI_freelistN(&dopesheet->channels);
- BLI_freelistN(&dopesheet->coverage_segments);
+ /* Free lists themselves. */
+ BLI_freelistN(&dopesheet->channels);
+ BLI_freelistN(&dopesheet->coverage_segments);
- /* Ensure lists are clean. */
- BLI_listbase_clear(&dopesheet->channels);
- BLI_listbase_clear(&dopesheet->coverage_segments);
- dopesheet->tot_channel = 0;
+ /* Ensure lists are clean. */
+ BLI_listbase_clear(&dopesheet->channels);
+ BLI_listbase_clear(&dopesheet->coverage_segments);
+ dopesheet->tot_channel = 0;
}
/* Free tracking structure, only frees structure contents
@@ -171,150 +171,162 @@ static void tracking_dopesheet_free(MovieTrackingDopesheet *dopesheet)
*/
void BKE_tracking_free(MovieTracking *tracking)
{
- tracking_tracks_free(&tracking->tracks);
- tracking_plane_tracks_free(&tracking->plane_tracks);
- tracking_reconstruction_free(&tracking->reconstruction);
- tracking_objects_free(&tracking->objects);
+ tracking_tracks_free(&tracking->tracks);
+ tracking_plane_tracks_free(&tracking->plane_tracks);
+ tracking_reconstruction_free(&tracking->reconstruction);
+ tracking_objects_free(&tracking->objects);
- if (tracking->camera.intrinsics)
- BKE_tracking_distortion_free(tracking->camera.intrinsics);
+ if (tracking->camera.intrinsics)
+ BKE_tracking_distortion_free(tracking->camera.intrinsics);
- tracking_dopesheet_free(&tracking->dopesheet);
+ tracking_dopesheet_free(&tracking->dopesheet);
}
/* Copy the whole list of tracks. */
-static void tracking_tracks_copy(ListBase *tracks_dst, const ListBase *tracks_src, GHash *tracks_mapping, const int flag)
+static void tracking_tracks_copy(ListBase *tracks_dst,
+ const ListBase *tracks_src,
+ GHash *tracks_mapping,
+ const int flag)
{
- MovieTrackingTrack *track_dst, *track_src;
+ MovieTrackingTrack *track_dst, *track_src;
- BLI_listbase_clear(tracks_dst);
- BLI_ghash_clear(tracks_mapping, NULL, NULL);
+ BLI_listbase_clear(tracks_dst);
+ BLI_ghash_clear(tracks_mapping, NULL, NULL);
- for (track_src = tracks_src->first; track_src != NULL; track_src = track_src->next) {
- track_dst = MEM_dupallocN(track_src);
- if (track_src->markers) {
- track_dst->markers = MEM_dupallocN(track_src->markers);
- }
- if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- id_us_plus(&track_dst->gpd->id);
- }
- BLI_addtail(tracks_dst, track_dst);
- BLI_ghash_insert(tracks_mapping, track_src, track_dst);
- }
+ for (track_src = tracks_src->first; track_src != NULL; track_src = track_src->next) {
+ track_dst = MEM_dupallocN(track_src);
+ if (track_src->markers) {
+ track_dst->markers = MEM_dupallocN(track_src->markers);
+ }
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id_us_plus(&track_dst->gpd->id);
+ }
+ BLI_addtail(tracks_dst, track_dst);
+ BLI_ghash_insert(tracks_mapping, track_src, track_dst);
+ }
}
/* copy the whole list of plane tracks (need whole MovieTracking structures due to embedded pointers to tracks).
* WARNING: implies tracking_[dst/src] and their tracks have already been copied. */
-static void tracking_plane_tracks_copy(
- ListBase *plane_tracks_list_dst, const ListBase *plane_tracks_list_src,
- GHash *tracks_mapping, const int flag)
-{
- MovieTrackingPlaneTrack *plane_track_dst, *plane_track_src;
-
- BLI_listbase_clear(plane_tracks_list_dst);
-
- for (plane_track_src = plane_tracks_list_src->first;
- plane_track_src != NULL;
- plane_track_src = plane_track_src->next)
- {
- plane_track_dst = MEM_dupallocN(plane_track_src);
- if (plane_track_src->markers) {
- plane_track_dst->markers = MEM_dupallocN(plane_track_src->markers);
- }
- plane_track_dst->point_tracks = MEM_mallocN(sizeof(*plane_track_dst->point_tracks) * plane_track_dst->point_tracksnr, __func__);
- for (int i = 0; i < plane_track_dst->point_tracksnr; i++) {
- plane_track_dst->point_tracks[i] = BLI_ghash_lookup(tracks_mapping, plane_track_src->point_tracks[i]);
- }
- if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- id_us_plus(&plane_track_dst->image->id);
- }
- BLI_addtail(plane_tracks_list_dst, plane_track_dst);
- }
+static void tracking_plane_tracks_copy(ListBase *plane_tracks_list_dst,
+ const ListBase *plane_tracks_list_src,
+ GHash *tracks_mapping,
+ const int flag)
+{
+ MovieTrackingPlaneTrack *plane_track_dst, *plane_track_src;
+
+ BLI_listbase_clear(plane_tracks_list_dst);
+
+ for (plane_track_src = plane_tracks_list_src->first; plane_track_src != NULL;
+ plane_track_src = plane_track_src->next) {
+ plane_track_dst = MEM_dupallocN(plane_track_src);
+ if (plane_track_src->markers) {
+ plane_track_dst->markers = MEM_dupallocN(plane_track_src->markers);
+ }
+ plane_track_dst->point_tracks = MEM_mallocN(
+ sizeof(*plane_track_dst->point_tracks) * plane_track_dst->point_tracksnr, __func__);
+ for (int i = 0; i < plane_track_dst->point_tracksnr; i++) {
+ plane_track_dst->point_tracks[i] = BLI_ghash_lookup(tracks_mapping,
+ plane_track_src->point_tracks[i]);
+ }
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id_us_plus(&plane_track_dst->image->id);
+ }
+ BLI_addtail(plane_tracks_list_dst, plane_track_dst);
+ }
}
/* Copy reconstruction structure. */
-static void tracking_reconstruction_copy(
- MovieTrackingReconstruction *reconstruction_dst, const MovieTrackingReconstruction *reconstruction_src,
- const int UNUSED(flag))
+static void tracking_reconstruction_copy(MovieTrackingReconstruction *reconstruction_dst,
+ const MovieTrackingReconstruction *reconstruction_src,
+ const int UNUSED(flag))
{
- *reconstruction_dst = *reconstruction_src;
- if (reconstruction_src->cameras) {
- reconstruction_dst->cameras = MEM_dupallocN(reconstruction_src->cameras);
- }
+ *reconstruction_dst = *reconstruction_src;
+ if (reconstruction_src->cameras) {
+ reconstruction_dst->cameras = MEM_dupallocN(reconstruction_src->cameras);
+ }
}
/* Copy stabilization structure. */
-static void tracking_stabilization_copy(
- MovieTrackingStabilization *stabilization_dst, const MovieTrackingStabilization *stabilization_src,
- const int UNUSED(flag))
+static void tracking_stabilization_copy(MovieTrackingStabilization *stabilization_dst,
+ const MovieTrackingStabilization *stabilization_src,
+ const int UNUSED(flag))
{
- *stabilization_dst = *stabilization_src;
+ *stabilization_dst = *stabilization_src;
}
/* Copy tracking object. */
-static void tracking_object_copy(
- MovieTrackingObject *object_dst, const MovieTrackingObject *object_src, GHash *tracks_mapping, const int flag)
+static void tracking_object_copy(MovieTrackingObject *object_dst,
+ const MovieTrackingObject *object_src,
+ GHash *tracks_mapping,
+ const int flag)
{
- *object_dst = *object_src;
- tracking_tracks_copy(&object_dst->tracks, &object_src->tracks, tracks_mapping, flag);
- tracking_plane_tracks_copy(&object_dst->plane_tracks, &object_src->plane_tracks, tracks_mapping, flag);
- tracking_reconstruction_copy(&object_dst->reconstruction, &object_src->reconstruction, flag);
+ *object_dst = *object_src;
+ tracking_tracks_copy(&object_dst->tracks, &object_src->tracks, tracks_mapping, flag);
+ tracking_plane_tracks_copy(
+ &object_dst->plane_tracks, &object_src->plane_tracks, tracks_mapping, flag);
+ tracking_reconstruction_copy(&object_dst->reconstruction, &object_src->reconstruction, flag);
}
/* Copy list of tracking objects. */
-static void tracking_objects_copy(
- ListBase *objects_dst, const ListBase *objects_src, GHash *tracks_mapping, const int flag)
+static void tracking_objects_copy(ListBase *objects_dst,
+ const ListBase *objects_src,
+ GHash *tracks_mapping,
+ const int flag)
{
- MovieTrackingObject *object_dst, *object_src;
+ MovieTrackingObject *object_dst, *object_src;
- BLI_listbase_clear(objects_dst);
+ BLI_listbase_clear(objects_dst);
- for (object_src = objects_src->first; object_src != NULL; object_src = object_src->next) {
- object_dst = MEM_mallocN(sizeof(*object_dst), __func__);
- tracking_object_copy(object_dst, object_src, tracks_mapping, flag);
- BLI_addtail(objects_dst, object_dst);
- }
+ for (object_src = objects_src->first; object_src != NULL; object_src = object_src->next) {
+ object_dst = MEM_mallocN(sizeof(*object_dst), __func__);
+ tracking_object_copy(object_dst, object_src, tracks_mapping, flag);
+ BLI_addtail(objects_dst, object_dst);
+ }
}
/* Copy tracking structure content. */
-void BKE_tracking_copy(MovieTracking *tracking_dst, const MovieTracking *tracking_src, const int flag)
-{
- GHash *tracks_mapping = BLI_ghash_ptr_new(__func__);
-
- *tracking_dst = *tracking_src;
-
- tracking_tracks_copy(&tracking_dst->tracks, &tracking_src->tracks, tracks_mapping, flag);
- tracking_plane_tracks_copy(&tracking_dst->plane_tracks, &tracking_src->plane_tracks, tracks_mapping, flag);
- tracking_reconstruction_copy(&tracking_dst->reconstruction, &tracking_src->reconstruction, flag);
- tracking_stabilization_copy(&tracking_dst->stabilization, &tracking_src->stabilization, flag);
- if (tracking_src->act_track) {
- tracking_dst->act_track = BLI_ghash_lookup(tracks_mapping, tracking_src->act_track);
- }
- if (tracking_src->act_plane_track) {
- MovieTrackingPlaneTrack *plane_track_src, *plane_track_dst;
- for (plane_track_src = tracking_src->plane_tracks.first, plane_track_dst = tracking_dst->plane_tracks.first;
- !ELEM(NULL, plane_track_src, plane_track_dst);
- plane_track_src = plane_track_src->next, plane_track_dst = plane_track_dst->next)
- {
- if (plane_track_src == tracking_src->act_plane_track) {
- tracking_dst->act_plane_track = plane_track_dst;
- break;
- }
- }
- }
-
- /* Warning! Will override tracks_mapping. */
- tracking_objects_copy(&tracking_dst->objects, &tracking_src->objects, tracks_mapping, flag);
-
- /* Those remaining are runtime data, they will be reconstructed as needed, do not bother copying them. */
- tracking_dst->dopesheet.ok = false;
- BLI_listbase_clear(&tracking_dst->dopesheet.channels);
- BLI_listbase_clear(&tracking_dst->dopesheet.coverage_segments);
-
- tracking_dst->camera.intrinsics = NULL;
- tracking_dst->stats = NULL;
-
- BLI_ghash_free(tracks_mapping, NULL, NULL);
+void BKE_tracking_copy(MovieTracking *tracking_dst,
+ const MovieTracking *tracking_src,
+ const int flag)
+{
+ GHash *tracks_mapping = BLI_ghash_ptr_new(__func__);
+
+ *tracking_dst = *tracking_src;
+
+ tracking_tracks_copy(&tracking_dst->tracks, &tracking_src->tracks, tracks_mapping, flag);
+ tracking_plane_tracks_copy(
+ &tracking_dst->plane_tracks, &tracking_src->plane_tracks, tracks_mapping, flag);
+ tracking_reconstruction_copy(&tracking_dst->reconstruction, &tracking_src->reconstruction, flag);
+ tracking_stabilization_copy(&tracking_dst->stabilization, &tracking_src->stabilization, flag);
+ if (tracking_src->act_track) {
+ tracking_dst->act_track = BLI_ghash_lookup(tracks_mapping, tracking_src->act_track);
+ }
+ if (tracking_src->act_plane_track) {
+ MovieTrackingPlaneTrack *plane_track_src, *plane_track_dst;
+ for (plane_track_src = tracking_src->plane_tracks.first,
+ plane_track_dst = tracking_dst->plane_tracks.first;
+ !ELEM(NULL, plane_track_src, plane_track_dst);
+ plane_track_src = plane_track_src->next, plane_track_dst = plane_track_dst->next) {
+ if (plane_track_src == tracking_src->act_plane_track) {
+ tracking_dst->act_plane_track = plane_track_dst;
+ break;
+ }
+ }
+ }
+
+ /* Warning! Will override tracks_mapping. */
+ tracking_objects_copy(&tracking_dst->objects, &tracking_src->objects, tracks_mapping, flag);
+
+ /* Those remaining are runtime data, they will be reconstructed as needed, do not bother copying them. */
+ tracking_dst->dopesheet.ok = false;
+ BLI_listbase_clear(&tracking_dst->dopesheet.channels);
+ BLI_listbase_clear(&tracking_dst->dopesheet.coverage_segments);
+
+ tracking_dst->camera.intrinsics = NULL;
+ tracking_dst->stats = NULL;
+
+ BLI_ghash_free(tracks_mapping, NULL, NULL);
}
/* Initialize motion tracking settings to default values,
@@ -322,70 +334,70 @@ void BKE_tracking_copy(MovieTracking *tracking_dst, const MovieTracking *trackin
*/
void BKE_tracking_settings_init(MovieTracking *tracking)
{
- tracking->camera.sensor_width = 35.0f;
- tracking->camera.pixel_aspect = 1.0f;
- tracking->camera.units = CAMERA_UNITS_MM;
+ tracking->camera.sensor_width = 35.0f;
+ tracking->camera.pixel_aspect = 1.0f;
+ tracking->camera.units = CAMERA_UNITS_MM;
- tracking->settings.default_motion_model = TRACK_MOTION_MODEL_TRANSLATION;
- tracking->settings.default_minimum_correlation = 0.75;
- tracking->settings.default_pattern_size = 21;
- tracking->settings.default_search_size = 71;
- tracking->settings.default_algorithm_flag |= TRACK_ALGORITHM_FLAG_USE_BRUTE;
- tracking->settings.default_weight = 1.0f;
- tracking->settings.dist = 1;
- tracking->settings.object_distance = 1;
+ tracking->settings.default_motion_model = TRACK_MOTION_MODEL_TRANSLATION;
+ tracking->settings.default_minimum_correlation = 0.75;
+ tracking->settings.default_pattern_size = 21;
+ tracking->settings.default_search_size = 71;
+ tracking->settings.default_algorithm_flag |= TRACK_ALGORITHM_FLAG_USE_BRUTE;
+ tracking->settings.default_weight = 1.0f;
+ tracking->settings.dist = 1;
+ tracking->settings.object_distance = 1;
- tracking->stabilization.scaleinf = 1.0f;
- tracking->stabilization.anchor_frame = 1;
- zero_v2(tracking->stabilization.target_pos);
- tracking->stabilization.target_rot = 0.0f;
- tracking->stabilization.scale = 1.0f;
+ tracking->stabilization.scaleinf = 1.0f;
+ tracking->stabilization.anchor_frame = 1;
+ zero_v2(tracking->stabilization.target_pos);
+ tracking->stabilization.target_rot = 0.0f;
+ tracking->stabilization.scale = 1.0f;
- tracking->stabilization.act_track = 0;
- tracking->stabilization.act_rot_track = 0;
- tracking->stabilization.tot_track = 0;
- tracking->stabilization.tot_rot_track = 0;
+ tracking->stabilization.act_track = 0;
+ tracking->stabilization.act_rot_track = 0;
+ tracking->stabilization.tot_track = 0;
+ tracking->stabilization.tot_rot_track = 0;
- tracking->stabilization.scaleinf = 1.0f;
- tracking->stabilization.locinf = 1.0f;
- tracking->stabilization.rotinf = 1.0f;
- tracking->stabilization.maxscale = 2.0f;
- tracking->stabilization.filter = TRACKING_FILTER_BILINEAR;
- tracking->stabilization.flag |= TRACKING_SHOW_STAB_TRACKS;
+ tracking->stabilization.scaleinf = 1.0f;
+ tracking->stabilization.locinf = 1.0f;
+ tracking->stabilization.rotinf = 1.0f;
+ tracking->stabilization.maxscale = 2.0f;
+ tracking->stabilization.filter = TRACKING_FILTER_BILINEAR;
+ tracking->stabilization.flag |= TRACKING_SHOW_STAB_TRACKS;
- BKE_tracking_object_add(tracking, "Camera");
+ BKE_tracking_object_add(tracking, "Camera");
}
/* Get list base of active object's tracks. */
ListBase *BKE_tracking_get_active_tracks(MovieTracking *tracking)
{
- MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
+ MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
- if (object && (object->flag & TRACKING_OBJECT_CAMERA) == 0) {
- return &object->tracks;
- }
+ if (object && (object->flag & TRACKING_OBJECT_CAMERA) == 0) {
+ return &object->tracks;
+ }
- return &tracking->tracks;
+ return &tracking->tracks;
}
/* Get list base of active object's plane tracks. */
ListBase *BKE_tracking_get_active_plane_tracks(MovieTracking *tracking)
{
- MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
+ MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
- if (object && (object->flag & TRACKING_OBJECT_CAMERA) == 0) {
- return &object->plane_tracks;
- }
+ if (object && (object->flag & TRACKING_OBJECT_CAMERA) == 0) {
+ return &object->plane_tracks;
+ }
- return &tracking->plane_tracks;
+ return &tracking->plane_tracks;
}
/* Get reconstruction data of active object. */
MovieTrackingReconstruction *BKE_tracking_get_active_reconstruction(MovieTracking *tracking)
{
- MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
+ MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
- return BKE_tracking_object_get_reconstruction(tracking, object);
+ return BKE_tracking_object_get_reconstruction(tracking, object);
}
/* Get transformation matrix for a given object which is used
@@ -393,17 +405,17 @@ MovieTrackingReconstruction *BKE_tracking_get_active_reconstruction(MovieTrackin
*/
void BKE_tracking_get_camera_object_matrix(Scene *scene, Object *ob, float mat[4][4])
{
- if (!ob) {
- if (scene->camera)
- ob = scene->camera;
- else
- ob = BKE_view_layer_camera_find(BKE_view_layer_context_active_PLACEHOLDER(scene));
- }
+ if (!ob) {
+ if (scene->camera)
+ ob = scene->camera;
+ else
+ ob = BKE_view_layer_camera_find(BKE_view_layer_context_active_PLACEHOLDER(scene));
+ }
- if (ob)
- BKE_object_where_is_calc_mat4(ob, mat);
- else
- unit_m4(mat);
+ if (ob)
+ BKE_object_where_is_calc_mat4(ob, mat);
+ else
+ unit_m4(mat);
}
/* Get projection matrix for camera specified by given tracking object
@@ -411,51 +423,55 @@ void BKE_tracking_get_camera_object_matrix(Scene *scene, Object *ob, float mat[4
*
* NOTE: frame number should be in clip space, not scene space
*/
-void BKE_tracking_get_projection_matrix(MovieTracking *tracking, MovieTrackingObject *object,
- int framenr, int winx, int winy, float mat[4][4])
+void BKE_tracking_get_projection_matrix(MovieTracking *tracking,
+ MovieTrackingObject *object,
+ int framenr,
+ int winx,
+ int winy,
+ float mat[4][4])
{
- MovieReconstructedCamera *camera;
- float lens = tracking->camera.focal * tracking->camera.sensor_width / (float)winx;
- float viewfac, pixsize, left, right, bottom, top, clipsta, clipend;
- float winmat[4][4];
- float ycor = 1.0f / tracking->camera.pixel_aspect;
- float shiftx, shifty, winside = (float)min_ii(winx, winy);
+ MovieReconstructedCamera *camera;
+ float lens = tracking->camera.focal * tracking->camera.sensor_width / (float)winx;
+ float viewfac, pixsize, left, right, bottom, top, clipsta, clipend;
+ float winmat[4][4];
+ float ycor = 1.0f / tracking->camera.pixel_aspect;
+ float shiftx, shifty, winside = (float)min_ii(winx, winy);
- BKE_tracking_camera_shift_get(tracking, winx, winy, &shiftx, &shifty);
+ BKE_tracking_camera_shift_get(tracking, winx, winy, &shiftx, &shifty);
- clipsta = 0.1f;
- clipend = 1000.0f;
+ clipsta = 0.1f;
+ clipend = 1000.0f;
- if (winx >= winy)
- viewfac = (lens * winx) / tracking->camera.sensor_width;
- else
- viewfac = (ycor * lens * winy) / tracking->camera.sensor_width;
+ if (winx >= winy)
+ viewfac = (lens * winx) / tracking->camera.sensor_width;
+ else
+ viewfac = (ycor * lens * winy) / tracking->camera.sensor_width;
- pixsize = clipsta / viewfac;
+ pixsize = clipsta / viewfac;
- left = -0.5f * (float)winx + shiftx * winside;
- bottom = -0.5f * (ycor) * (float)winy + shifty * winside;
- right = 0.5f * (float)winx + shiftx * winside;
- top = 0.5f * (ycor) * (float)winy + shifty * winside;
+ left = -0.5f * (float)winx + shiftx * winside;
+ bottom = -0.5f * (ycor) * (float)winy + shifty * winside;
+ right = 0.5f * (float)winx + shiftx * winside;
+ top = 0.5f * (ycor) * (float)winy + shifty * winside;
- left *= pixsize;
- right *= pixsize;
- bottom *= pixsize;
- top *= pixsize;
+ left *= pixsize;
+ right *= pixsize;
+ bottom *= pixsize;
+ top *= pixsize;
- perspective_m4(winmat, left, right, bottom, top, clipsta, clipend);
+ perspective_m4(winmat, left, right, bottom, top, clipsta, clipend);
- camera = BKE_tracking_camera_get_reconstructed(tracking, object, framenr);
+ camera = BKE_tracking_camera_get_reconstructed(tracking, object, framenr);
- if (camera) {
- float imat[4][4];
+ if (camera) {
+ float imat[4][4];
- invert_m4_m4(imat, camera->mat);
- mul_m4_m4m4(mat, winmat, imat);
- }
- else {
- copy_m4_m4(mat, winmat);
- }
+ invert_m4_m4(imat, camera->mat);
+ mul_m4_m4m4(mat, winmat, imat);
+ }
+ else {
+ copy_m4_m4(mat, winmat);
+ }
}
/*********************** clipboard *************************/
@@ -463,45 +479,45 @@ void BKE_tracking_get_projection_matrix(MovieTracking *tracking, MovieTrackingOb
/* Free clipboard by freeing memory used by all tracks in it. */
void BKE_tracking_clipboard_free(void)
{
- MovieTrackingTrack *track = tracking_clipboard.tracks.first, *next_track;
+ MovieTrackingTrack *track = tracking_clipboard.tracks.first, *next_track;
- while (track) {
- next_track = track->next;
+ while (track) {
+ next_track = track->next;
- BKE_tracking_track_free(track);
- MEM_freeN(track);
+ BKE_tracking_track_free(track);
+ MEM_freeN(track);
- track = next_track;
- }
+ track = next_track;
+ }
- BLI_listbase_clear(&tracking_clipboard.tracks);
+ BLI_listbase_clear(&tracking_clipboard.tracks);
}
/* Copy selected tracks from specified object to the clipboard. */
void BKE_tracking_clipboard_copy_tracks(MovieTracking *tracking, MovieTrackingObject *object)
{
- ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
- MovieTrackingTrack *track = tracksbase->first;
+ ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
+ MovieTrackingTrack *track = tracksbase->first;
- /* First drop all tracks from current clipboard. */
- BKE_tracking_clipboard_free();
+ /* First drop all tracks from current clipboard. */
+ BKE_tracking_clipboard_free();
- /* Then copy all selected visible tracks to it. */
- while (track) {
- if (TRACK_SELECTED(track) && (track->flag & TRACK_HIDDEN) == 0) {
- MovieTrackingTrack *new_track = BKE_tracking_track_duplicate(track);
+ /* Then copy all selected visible tracks to it. */
+ while (track) {
+ if (TRACK_SELECTED(track) && (track->flag & TRACK_HIDDEN) == 0) {
+ MovieTrackingTrack *new_track = BKE_tracking_track_duplicate(track);
- BLI_addtail(&tracking_clipboard.tracks, new_track);
- }
+ BLI_addtail(&tracking_clipboard.tracks, new_track);
+ }
- track = track->next;
- }
+ track = track->next;
+ }
}
/* Check whether there're any tracks in the clipboard. */
bool BKE_tracking_clipboard_has_tracks(void)
{
- return (BLI_listbase_is_empty(&tracking_clipboard.tracks) == false);
+ return (BLI_listbase_is_empty(&tracking_clipboard.tracks) == false);
}
/* Paste tracks from clipboard to specified object.
@@ -511,20 +527,20 @@ bool BKE_tracking_clipboard_has_tracks(void)
*/
void BKE_tracking_clipboard_paste_tracks(MovieTracking *tracking, MovieTrackingObject *object)
{
- ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
- MovieTrackingTrack *track = tracking_clipboard.tracks.first;
+ ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
+ MovieTrackingTrack *track = tracking_clipboard.tracks.first;
- while (track) {
- MovieTrackingTrack *new_track = BKE_tracking_track_duplicate(track);
- if (track->prev == NULL) {
- tracking->act_track = new_track;
- }
+ while (track) {
+ MovieTrackingTrack *new_track = BKE_tracking_track_duplicate(track);
+ if (track->prev == NULL) {
+ tracking->act_track = new_track;
+ }
- BLI_addtail(tracksbase, new_track);
- BKE_tracking_track_unique_name(tracksbase, new_track);
+ BLI_addtail(tracksbase, new_track);
+ BKE_tracking_track_unique_name(tracksbase, new_track);
- track = track->next;
- }
+ track = track->next;
+ }
}
/*********************** Tracks *************************/
@@ -537,81 +553,86 @@ void BKE_tracking_clipboard_paste_tracks(MovieTracking *tracking, MovieTrackingO
* Width and height are clip's dimension used to scale track's
* pattern and search regions.
*/
-MovieTrackingTrack *BKE_tracking_track_add(MovieTracking *tracking, ListBase *tracksbase, float x, float y,
- int framenr, int width, int height)
+MovieTrackingTrack *BKE_tracking_track_add(MovieTracking *tracking,
+ ListBase *tracksbase,
+ float x,
+ float y,
+ int framenr,
+ int width,
+ int height)
{
- MovieTrackingTrack *track;
- MovieTrackingMarker marker;
- MovieTrackingSettings *settings = &tracking->settings;
+ MovieTrackingTrack *track;
+ MovieTrackingMarker marker;
+ MovieTrackingSettings *settings = &tracking->settings;
- float half_pattern = (float)settings->default_pattern_size / 2.0f;
- float half_search = (float)settings->default_search_size / 2.0f;
- float pat[2], search[2];
+ float half_pattern = (float)settings->default_pattern_size / 2.0f;
+ float half_search = (float)settings->default_search_size / 2.0f;
+ float pat[2], search[2];
- pat[0] = half_pattern / (float)width;
- pat[1] = half_pattern / (float)height;
+ pat[0] = half_pattern / (float)width;
+ pat[1] = half_pattern / (float)height;
- search[0] = half_search / (float)width;
- search[1] = half_search / (float)height;
+ search[0] = half_search / (float)width;
+ search[1] = half_search / (float)height;
- track = MEM_callocN(sizeof(MovieTrackingTrack), "add_marker_exec track");
- strcpy(track->name, "Track");
+ track = MEM_callocN(sizeof(MovieTrackingTrack), "add_marker_exec track");
+ strcpy(track->name, "Track");
- /* fill track's settings from default settings */
- track->motion_model = settings->default_motion_model;
- track->minimum_correlation = settings->default_minimum_correlation;
- track->margin = settings->default_margin;
- track->pattern_match = settings->default_pattern_match;
- track->frames_limit = settings->default_frames_limit;
- track->flag = settings->default_flag;
- track->algorithm_flag = settings->default_algorithm_flag;
- track->weight = settings->default_weight;
- track->weight_stab = settings->default_weight;
+ /* fill track's settings from default settings */
+ track->motion_model = settings->default_motion_model;
+ track->minimum_correlation = settings->default_minimum_correlation;
+ track->margin = settings->default_margin;
+ track->pattern_match = settings->default_pattern_match;
+ track->frames_limit = settings->default_frames_limit;
+ track->flag = settings->default_flag;
+ track->algorithm_flag = settings->default_algorithm_flag;
+ track->weight = settings->default_weight;
+ track->weight_stab = settings->default_weight;
- memset(&marker, 0, sizeof(marker));
- marker.pos[0] = x;
- marker.pos[1] = y;
- marker.framenr = framenr;
+ memset(&marker, 0, sizeof(marker));
+ marker.pos[0] = x;
+ marker.pos[1] = y;
+ marker.framenr = framenr;
- marker.pattern_corners[0][0] = -pat[0];
- marker.pattern_corners[0][1] = -pat[1];
+ marker.pattern_corners[0][0] = -pat[0];
+ marker.pattern_corners[0][1] = -pat[1];
- marker.pattern_corners[1][0] = pat[0];
- marker.pattern_corners[1][1] = -pat[1];
+ marker.pattern_corners[1][0] = pat[0];
+ marker.pattern_corners[1][1] = -pat[1];
- negate_v2_v2(marker.pattern_corners[2], marker.pattern_corners[0]);
- negate_v2_v2(marker.pattern_corners[3], marker.pattern_corners[1]);
+ negate_v2_v2(marker.pattern_corners[2], marker.pattern_corners[0]);
+ negate_v2_v2(marker.pattern_corners[3], marker.pattern_corners[1]);
- copy_v2_v2(marker.search_max, search);
- negate_v2_v2(marker.search_min, search);
+ copy_v2_v2(marker.search_max, search);
+ negate_v2_v2(marker.search_min, search);
- BKE_tracking_marker_insert(track, &marker);
+ BKE_tracking_marker_insert(track, &marker);
- BLI_addtail(tracksbase, track);
- BKE_tracking_track_unique_name(tracksbase, track);
+ BLI_addtail(tracksbase, track);
+ BKE_tracking_track_unique_name(tracksbase, track);
- return track;
+ return track;
}
/* Duplicate the specified track, result will no belong to any list. */
MovieTrackingTrack *BKE_tracking_track_duplicate(MovieTrackingTrack *track)
{
- MovieTrackingTrack *new_track;
+ MovieTrackingTrack *new_track;
- new_track = MEM_callocN(sizeof(MovieTrackingTrack), "tracking_track_duplicate new_track");
+ new_track = MEM_callocN(sizeof(MovieTrackingTrack), "tracking_track_duplicate new_track");
- *new_track = *track;
- new_track->next = new_track->prev = NULL;
+ *new_track = *track;
+ new_track->next = new_track->prev = NULL;
- new_track->markers = MEM_dupallocN(new_track->markers);
+ new_track->markers = MEM_dupallocN(new_track->markers);
- /* Orevent duplicate from being used for 2D stabilization.
- * If necessary, it shall be added explicitly.
- */
- new_track->flag &= ~TRACK_USE_2D_STAB;
- new_track->flag &= ~TRACK_USE_2D_STAB_ROT;
+ /* Orevent duplicate from being used for 2D stabilization.
+ * If necessary, it shall be added explicitly.
+ */
+ new_track->flag &= ~TRACK_USE_2D_STAB;
+ new_track->flag &= ~TRACK_USE_2D_STAB_ROT;
- return new_track;
+ return new_track;
}
/* Ensure specified track has got unique name,
@@ -620,8 +641,12 @@ MovieTrackingTrack *BKE_tracking_track_duplicate(MovieTrackingTrack *track)
*/
void BKE_tracking_track_unique_name(ListBase *tracksbase, MovieTrackingTrack *track)
{
- BLI_uniquename(tracksbase, track, CTX_DATA_(BLT_I18NCONTEXT_ID_MOVIECLIP, "Track"), '.',
- offsetof(MovieTrackingTrack, name), sizeof(track->name));
+ BLI_uniquename(tracksbase,
+ track,
+ CTX_DATA_(BLT_I18NCONTEXT_ID_MOVIECLIP, "Track"),
+ '.',
+ offsetof(MovieTrackingTrack, name),
+ sizeof(track->name));
}
/* Free specified track, only frees contents of a structure
@@ -631,8 +656,8 @@ void BKE_tracking_track_unique_name(ListBase *tracksbase, MovieTrackingTrack *tr
*/
void BKE_tracking_track_free(MovieTrackingTrack *track)
{
- if (track->markers)
- MEM_freeN(track->markers);
+ if (track->markers)
+ MEM_freeN(track->markers);
}
/* Set flag for all specified track's areas.
@@ -642,15 +667,15 @@ void BKE_tracking_track_free(MovieTrackingTrack *track)
*/
void BKE_tracking_track_flag_set(MovieTrackingTrack *track, int area, int flag)
{
- if (area == TRACK_AREA_NONE)
- return;
+ if (area == TRACK_AREA_NONE)
+ return;
- if (area & TRACK_AREA_POINT)
- track->flag |= flag;
- if (area & TRACK_AREA_PAT)
- track->pat_flag |= flag;
- if (area & TRACK_AREA_SEARCH)
- track->search_flag |= flag;
+ if (area & TRACK_AREA_POINT)
+ track->flag |= flag;
+ if (area & TRACK_AREA_PAT)
+ track->pat_flag |= flag;
+ if (area & TRACK_AREA_SEARCH)
+ track->search_flag |= flag;
}
/* Clear flag from all specified track's areas.
@@ -660,15 +685,15 @@ void BKE_tracking_track_flag_set(MovieTrackingTrack *track, int area, int flag)
*/
void BKE_tracking_track_flag_clear(MovieTrackingTrack *track, int area, int flag)
{
- if (area == TRACK_AREA_NONE)
- return;
+ if (area == TRACK_AREA_NONE)
+ return;
- if (area & TRACK_AREA_POINT)
- track->flag &= ~flag;
- if (area & TRACK_AREA_PAT)
- track->pat_flag &= ~flag;
- if (area & TRACK_AREA_SEARCH)
- track->search_flag &= ~flag;
+ if (area & TRACK_AREA_POINT)
+ track->flag &= ~flag;
+ if (area & TRACK_AREA_PAT)
+ track->pat_flag &= ~flag;
+ if (area & TRACK_AREA_SEARCH)
+ track->search_flag &= ~flag;
}
/* Check whether track has got marker at specified frame.
@@ -677,7 +702,7 @@ void BKE_tracking_track_flag_clear(MovieTrackingTrack *track, int area, int flag
*/
bool BKE_tracking_track_has_marker_at_frame(MovieTrackingTrack *track, int framenr)
{
- return BKE_tracking_marker_get_exact(track, framenr) != NULL;
+ return BKE_tracking_marker_get_exact(track, framenr) != NULL;
}
/* Check whether track has got enabled marker at specified frame.
@@ -686,9 +711,9 @@ bool BKE_tracking_track_has_marker_at_frame(MovieTrackingTrack *track, int frame
*/
bool BKE_tracking_track_has_enabled_marker_at_frame(MovieTrackingTrack *track, int framenr)
{
- MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, framenr);
+ MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, framenr);
- return marker && (marker->flag & MARKER_DISABLED) == 0;
+ return marker && (marker->flag & MARKER_DISABLED) == 0;
}
/* Clear track's path:
@@ -705,729 +730,762 @@ bool BKE_tracking_track_has_enabled_marker_at_frame(MovieTrackingTrack *track, i
*/
void BKE_tracking_track_path_clear(MovieTrackingTrack *track, int ref_frame, int action)
{
- int a;
+ int a;
+
+ if (action == TRACK_CLEAR_REMAINED) {
+ a = 1;
+
+ while (a < track->markersnr) {
+ if (track->markers[a].framenr > ref_frame) {
+ track->markersnr = a;
+ track->markers = MEM_reallocN(track->markers,
+ sizeof(MovieTrackingMarker) * track->markersnr);
+
+ break;
+ }
+
+ a++;
+ }
+
+ if (track->markersnr)
+ tracking_marker_insert_disabled(track, &track->markers[track->markersnr - 1], false, true);
+ }
+ else if (action == TRACK_CLEAR_UPTO) {
+ a = track->markersnr - 1;
+
+ while (a >= 0) {
+ if (track->markers[a].framenr <= ref_frame) {
+ memmove(track->markers,
+ track->markers + a,
+ (track->markersnr - a) * sizeof(MovieTrackingMarker));
+
+ track->markersnr = track->markersnr - a;
+ track->markers = MEM_reallocN(track->markers,
+ sizeof(MovieTrackingMarker) * track->markersnr);
+
+ break;
+ }
+
+ a--;
+ }
+
+ if (track->markersnr)
+ tracking_marker_insert_disabled(track, &track->markers[0], true, true);
+ }
+ else if (action == TRACK_CLEAR_ALL) {
+ MovieTrackingMarker *marker, marker_new;
+
+ marker = BKE_tracking_marker_get(track, ref_frame);
+ marker_new = *marker;
+
+ MEM_freeN(track->markers);
+ track->markers = NULL;
+ track->markersnr = 0;
+
+ BKE_tracking_marker_insert(track, &marker_new);
+
+ tracking_marker_insert_disabled(track, &marker_new, true, true);
+ tracking_marker_insert_disabled(track, &marker_new, false, true);
+ }
+}
+
+void BKE_tracking_tracks_join(MovieTracking *tracking,
+ MovieTrackingTrack *dst_track,
+ MovieTrackingTrack *src_track)
+{
+ int i = 0, a = 0, b = 0, tot;
+ MovieTrackingMarker *markers;
+
+ tot = dst_track->markersnr + src_track->markersnr;
+ markers = MEM_callocN(tot * sizeof(MovieTrackingMarker), "tmp tracking joined tracks");
- if (action == TRACK_CLEAR_REMAINED) {
- a = 1;
+ while (a < src_track->markersnr || b < dst_track->markersnr) {
+ if (b >= dst_track->markersnr) {
+ markers[i] = src_track->markers[a++];
+ }
+ else if (a >= src_track->markersnr) {
+ markers[i] = dst_track->markers[b++];
+ }
+ else if (src_track->markers[a].framenr < dst_track->markers[b].framenr) {
+ markers[i] = src_track->markers[a++];
+ }
+ else if (src_track->markers[a].framenr > dst_track->markers[b].framenr) {
+ markers[i] = dst_track->markers[b++];
+ }
+ else {
+ if ((src_track->markers[a].flag & MARKER_DISABLED) == 0) {
+ if ((dst_track->markers[b].flag & MARKER_DISABLED) == 0) {
+ /* both tracks are enabled on this frame, so find the whole segment
+ * on which tracks are intersecting and blend tracks using linear
+ * interpolation to prevent jumps
+ */
- while (a < track->markersnr) {
- if (track->markers[a].framenr > ref_frame) {
- track->markersnr = a;
- track->markers = MEM_reallocN(track->markers, sizeof(MovieTrackingMarker) * track->markersnr);
+ MovieTrackingMarker *marker_a, *marker_b;
+ int start_a = a, start_b = b, len = 0, frame = src_track->markers[a].framenr;
+ int j, inverse = 0;
- break;
- }
+ inverse = (b == 0) || (dst_track->markers[b - 1].flag & MARKER_DISABLED) ||
+ (dst_track->markers[b - 1].framenr != frame - 1);
- a++;
- }
+ /* find length of intersection */
+ while (a < src_track->markersnr && b < dst_track->markersnr) {
+ marker_a = &src_track->markers[a];
+ marker_b = &dst_track->markers[b];
- if (track->markersnr)
- tracking_marker_insert_disabled(track, &track->markers[track->markersnr - 1], false, true);
- }
- else if (action == TRACK_CLEAR_UPTO) {
- a = track->markersnr - 1;
+ if (marker_a->flag & MARKER_DISABLED || marker_b->flag & MARKER_DISABLED)
+ break;
- while (a >= 0) {
- if (track->markers[a].framenr <= ref_frame) {
- memmove(track->markers, track->markers + a, (track->markersnr - a) * sizeof(MovieTrackingMarker));
+ if (marker_a->framenr != frame || marker_b->framenr != frame)
+ break;
- track->markersnr = track->markersnr - a;
- track->markers = MEM_reallocN(track->markers, sizeof(MovieTrackingMarker) * track->markersnr);
+ frame++;
+ len++;
+ a++;
+ b++;
+ }
- break;
- }
+ a = start_a;
+ b = start_b;
- a--;
- }
-
- if (track->markersnr)
- tracking_marker_insert_disabled(track, &track->markers[0], true, true);
- }
- else if (action == TRACK_CLEAR_ALL) {
- MovieTrackingMarker *marker, marker_new;
-
- marker = BKE_tracking_marker_get(track, ref_frame);
- marker_new = *marker;
-
- MEM_freeN(track->markers);
- track->markers = NULL;
- track->markersnr = 0;
-
- BKE_tracking_marker_insert(track, &marker_new);
-
- tracking_marker_insert_disabled(track, &marker_new, true, true);
- tracking_marker_insert_disabled(track, &marker_new, false, true);
- }
-}
-
-void BKE_tracking_tracks_join(MovieTracking *tracking, MovieTrackingTrack *dst_track, MovieTrackingTrack *src_track)
-{
- int i = 0, a = 0, b = 0, tot;
- MovieTrackingMarker *markers;
-
- tot = dst_track->markersnr + src_track->markersnr;
- markers = MEM_callocN(tot * sizeof(MovieTrackingMarker), "tmp tracking joined tracks");
-
- while (a < src_track->markersnr || b < dst_track->markersnr) {
- if (b >= dst_track->markersnr) {
- markers[i] = src_track->markers[a++];
- }
- else if (a >= src_track->markersnr) {
- markers[i] = dst_track->markers[b++];
- }
- else if (src_track->markers[a].framenr < dst_track->markers[b].framenr) {
- markers[i] = src_track->markers[a++];
- }
- else if (src_track->markers[a].framenr > dst_track->markers[b].framenr) {
- markers[i] = dst_track->markers[b++];
- }
- else {
- if ((src_track->markers[a].flag & MARKER_DISABLED) == 0) {
- if ((dst_track->markers[b].flag & MARKER_DISABLED) == 0) {
- /* both tracks are enabled on this frame, so find the whole segment
- * on which tracks are intersecting and blend tracks using linear
- * interpolation to prevent jumps
- */
-
- MovieTrackingMarker *marker_a, *marker_b;
- int start_a = a, start_b = b, len = 0, frame = src_track->markers[a].framenr;
- int j, inverse = 0;
-
- inverse = (b == 0) ||
- (dst_track->markers[b - 1].flag & MARKER_DISABLED) ||
- (dst_track->markers[b - 1].framenr != frame - 1);
-
- /* find length of intersection */
- while (a < src_track->markersnr && b < dst_track->markersnr) {
- marker_a = &src_track->markers[a];
- marker_b = &dst_track->markers[b];
-
- if (marker_a->flag & MARKER_DISABLED || marker_b->flag & MARKER_DISABLED)
- break;
-
- if (marker_a->framenr != frame || marker_b->framenr != frame)
- break;
+ /* linear interpolation for intersecting frames */
+ for (j = 0; j < len; j++) {
+ float fac = 0.5f;
- frame++;
- len++;
- a++;
- b++;
- }
+ if (len > 1)
+ fac = 1.0f / (len - 1) * j;
- a = start_a;
- b = start_b;
+ if (inverse)
+ fac = 1.0f - fac;
- /* linear interpolation for intersecting frames */
- for (j = 0; j < len; j++) {
- float fac = 0.5f;
+ marker_a = &src_track->markers[a];
+ marker_b = &dst_track->markers[b];
- if (len > 1)
- fac = 1.0f / (len - 1) * j;
+ markers[i] = dst_track->markers[b];
+ interp_v2_v2v2(markers[i].pos, marker_b->pos, marker_a->pos, fac);
+ a++;
+ b++;
+ i++;
+ }
- if (inverse)
- fac = 1.0f - fac;
+ /* this values will be incremented at the end of the loop cycle */
+ a--;
+ b--;
+ i--;
+ }
+ else {
+ markers[i] = src_track->markers[a];
+ }
+ }
+ else {
+ markers[i] = dst_track->markers[b];
+ }
- marker_a = &src_track->markers[a];
- marker_b = &dst_track->markers[b];
+ a++;
+ b++;
+ }
- markers[i] = dst_track->markers[b];
- interp_v2_v2v2(markers[i].pos, marker_b->pos, marker_a->pos, fac);
- a++;
- b++;
- i++;
- }
+ i++;
+ }
- /* this values will be incremented at the end of the loop cycle */
- a--; b--; i--;
- }
- else {
- markers[i] = src_track->markers[a];
- }
- }
- else {
- markers[i] = dst_track->markers[b];
- }
+ MEM_freeN(dst_track->markers);
- a++;
- b++;
- }
+ dst_track->markers = MEM_callocN(i * sizeof(MovieTrackingMarker), "tracking joined tracks");
+ memcpy(dst_track->markers, markers, i * sizeof(MovieTrackingMarker));
- i++;
- }
+ dst_track->markersnr = i;
- MEM_freeN(dst_track->markers);
+ MEM_freeN(markers);
- dst_track->markers = MEM_callocN(i * sizeof(MovieTrackingMarker), "tracking joined tracks");
- memcpy(dst_track->markers, markers, i * sizeof(MovieTrackingMarker));
-
- dst_track->markersnr = i;
-
- MEM_freeN(markers);
-
- BKE_tracking_dopesheet_tag_update(tracking);
+ BKE_tracking_dopesheet_tag_update(tracking);
}
-MovieTrackingTrack *BKE_tracking_track_get_named(MovieTracking *tracking, MovieTrackingObject *object, const char *name)
+MovieTrackingTrack *BKE_tracking_track_get_named(MovieTracking *tracking,
+ MovieTrackingObject *object,
+ const char *name)
{
- ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
- MovieTrackingTrack *track = tracksbase->first;
+ ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
+ MovieTrackingTrack *track = tracksbase->first;
- while (track) {
- if (STREQ(track->name, name))
- return track;
+ while (track) {
+ if (STREQ(track->name, name))
+ return track;
- track = track->next;
- }
+ track = track->next;
+ }
- return NULL;
+ return NULL;
}
-MovieTrackingTrack *BKE_tracking_track_get_indexed(MovieTracking *tracking, int tracknr, ListBase **r_tracksbase)
+MovieTrackingTrack *BKE_tracking_track_get_indexed(MovieTracking *tracking,
+ int tracknr,
+ ListBase **r_tracksbase)
{
- MovieTrackingObject *object;
- int cur = 1;
+ MovieTrackingObject *object;
+ int cur = 1;
- object = tracking->objects.first;
- while (object) {
- ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
- MovieTrackingTrack *track = tracksbase->first;
+ object = tracking->objects.first;
+ while (object) {
+ ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
+ MovieTrackingTrack *track = tracksbase->first;
- while (track) {
- if (track->flag & TRACK_HAS_BUNDLE) {
- if (cur == tracknr) {
- *r_tracksbase = tracksbase;
- return track;
- }
+ while (track) {
+ if (track->flag & TRACK_HAS_BUNDLE) {
+ if (cur == tracknr) {
+ *r_tracksbase = tracksbase;
+ return track;
+ }
- cur++;
- }
+ cur++;
+ }
- track = track->next;
- }
+ track = track->next;
+ }
- object = object->next;
- }
+ object = object->next;
+ }
- *r_tracksbase = NULL;
+ *r_tracksbase = NULL;
- return NULL;
+ return NULL;
}
MovieTrackingTrack *BKE_tracking_track_get_active(MovieTracking *tracking)
{
- ListBase *tracksbase;
+ ListBase *tracksbase;
- if (!tracking->act_track)
- return NULL;
+ if (!tracking->act_track)
+ return NULL;
- tracksbase = BKE_tracking_get_active_tracks(tracking);
+ tracksbase = BKE_tracking_get_active_tracks(tracking);
- /* check that active track is in current tracks list */
- if (BLI_findindex(tracksbase, tracking->act_track) != -1)
- return tracking->act_track;
+ /* check that active track is in current tracks list */
+ if (BLI_findindex(tracksbase, tracking->act_track) != -1)
+ return tracking->act_track;
- return NULL;
+ return NULL;
}
static bGPDlayer *track_mask_gpencil_layer_get(MovieTrackingTrack *track)
{
- bGPDlayer *layer;
+ bGPDlayer *layer;
- if (!track->gpd)
- return NULL;
+ if (!track->gpd)
+ return NULL;
- layer = track->gpd->layers.first;
+ layer = track->gpd->layers.first;
- while (layer) {
- if (layer->flag & GP_LAYER_ACTIVE) {
- bGPDframe *frame = layer->frames.first;
- bool ok = false;
+ while (layer) {
+ if (layer->flag & GP_LAYER_ACTIVE) {
+ bGPDframe *frame = layer->frames.first;
+ bool ok = false;
- while (frame) {
- if (frame->strokes.first) {
- ok = true;
- break;
- }
+ while (frame) {
+ if (frame->strokes.first) {
+ ok = true;
+ break;
+ }
- frame = frame->next;
- }
+ frame = frame->next;
+ }
- if (ok)
- return layer;
- }
+ if (ok)
+ return layer;
+ }
- layer = layer->next;
- }
+ layer = layer->next;
+ }
- return NULL;
+ return NULL;
}
typedef struct TrackMaskSetPixelData {
- float *mask;
- int mask_width;
- int mask_height;
+ float *mask;
+ int mask_width;
+ int mask_height;
} TrackMaskSetPixelData;
static void track_mask_set_pixel_cb(int x, int x_end, int y, void *user_data)
{
- TrackMaskSetPixelData *data = (TrackMaskSetPixelData *)user_data;
- size_t index = (size_t)y * data->mask_width + x;
- size_t index_end = (size_t)y * data->mask_width + x_end;
- do {
- data->mask[index] = 1.0f;
- } while (++index != index_end);
+ TrackMaskSetPixelData *data = (TrackMaskSetPixelData *)user_data;
+ size_t index = (size_t)y * data->mask_width + x;
+ size_t index_end = (size_t)y * data->mask_width + x_end;
+ do {
+ data->mask[index] = 1.0f;
+ } while (++index != index_end);
}
-static void track_mask_gpencil_layer_rasterize(int frame_width, int frame_height,
+static void track_mask_gpencil_layer_rasterize(int frame_width,
+ int frame_height,
const float region_min[2],
bGPDlayer *layer,
float *mask,
int mask_width,
int mask_height)
{
- bGPDframe *frame = layer->frames.first;
- TrackMaskSetPixelData data;
-
- data.mask = mask;
- data.mask_width = mask_width;
- data.mask_height = mask_height;
-
- while (frame) {
- bGPDstroke *stroke = frame->strokes.first;
-
- while (stroke) {
- bGPDspoint *stroke_points = stroke->points;
- if (stroke->flag & GP_STROKE_2DSPACE) {
- int *mask_points, *point;
- point = mask_points = MEM_callocN(2 * stroke->totpoints * sizeof(int),
- "track mask rasterization points");
- for (int i = 0; i < stroke->totpoints; i++, point += 2) {
- point[0] = stroke_points[i].x * frame_width - region_min[0];
- point[1] = stroke_points[i].y * frame_height - region_min[1];
- }
- /* TODO: add an option to control whether AA is enabled or not */
- BLI_bitmap_draw_2d_poly_v2i_n(
- 0, 0, mask_width, mask_height,
- (const int (*)[2])mask_points, stroke->totpoints,
- track_mask_set_pixel_cb, &data);
- MEM_freeN(mask_points);
- }
- stroke = stroke->next;
- }
- frame = frame->next;
- }
+ bGPDframe *frame = layer->frames.first;
+ TrackMaskSetPixelData data;
+
+ data.mask = mask;
+ data.mask_width = mask_width;
+ data.mask_height = mask_height;
+
+ while (frame) {
+ bGPDstroke *stroke = frame->strokes.first;
+
+ while (stroke) {
+ bGPDspoint *stroke_points = stroke->points;
+ if (stroke->flag & GP_STROKE_2DSPACE) {
+ int *mask_points, *point;
+ point = mask_points = MEM_callocN(2 * stroke->totpoints * sizeof(int),
+ "track mask rasterization points");
+ for (int i = 0; i < stroke->totpoints; i++, point += 2) {
+ point[0] = stroke_points[i].x * frame_width - region_min[0];
+ point[1] = stroke_points[i].y * frame_height - region_min[1];
+ }
+ /* TODO: add an option to control whether AA is enabled or not */
+ BLI_bitmap_draw_2d_poly_v2i_n(0,
+ 0,
+ mask_width,
+ mask_height,
+ (const int(*)[2])mask_points,
+ stroke->totpoints,
+ track_mask_set_pixel_cb,
+ &data);
+ MEM_freeN(mask_points);
+ }
+ stroke = stroke->next;
+ }
+ frame = frame->next;
+ }
}
/* Region is in pixel space, relative to marker's center. */
-float *tracking_track_get_mask_for_region(int frame_width, int frame_height,
+float *tracking_track_get_mask_for_region(int frame_width,
+ int frame_height,
const float region_min[2],
const float region_max[2],
MovieTrackingTrack *track)
{
- float *mask = NULL;
- bGPDlayer *layer = track_mask_gpencil_layer_get(track);
- if (layer != NULL) {
- const int mask_width = region_max[0] - region_min[0];
- const int mask_height = region_max[1] - region_min[1];
- mask = MEM_callocN(mask_width * mask_height * sizeof(float), "track mask");
- track_mask_gpencil_layer_rasterize(frame_width, frame_height,
- region_min,
- layer,
- mask,
- mask_width, mask_height);
- }
- return mask;
-}
-
-float *BKE_tracking_track_get_mask(int frame_width, int frame_height,
+ float *mask = NULL;
+ bGPDlayer *layer = track_mask_gpencil_layer_get(track);
+ if (layer != NULL) {
+ const int mask_width = region_max[0] - region_min[0];
+ const int mask_height = region_max[1] - region_min[1];
+ mask = MEM_callocN(mask_width * mask_height * sizeof(float), "track mask");
+ track_mask_gpencil_layer_rasterize(
+ frame_width, frame_height, region_min, layer, mask, mask_width, mask_height);
+ }
+ return mask;
+}
+
+float *BKE_tracking_track_get_mask(int frame_width,
+ int frame_height,
MovieTrackingTrack *track,
MovieTrackingMarker *marker)
{
- /* Convert normalized space marker's search area to pixel-space region. */
- const float region_min[2] = {marker->search_min[0] * frame_width,
- marker->search_min[1] * frame_height};
- const float region_max[2] = {marker->search_max[0] * frame_width,
- marker->search_max[1] * frame_height};
- return tracking_track_get_mask_for_region(frame_width, frame_height,
- region_min,
- region_max,
- track);
+ /* Convert normalized space marker's search area to pixel-space region. */
+ const float region_min[2] = {marker->search_min[0] * frame_width,
+ marker->search_min[1] * frame_height};
+ const float region_max[2] = {marker->search_max[0] * frame_width,
+ marker->search_max[1] * frame_height};
+ return tracking_track_get_mask_for_region(
+ frame_width, frame_height, region_min, region_max, track);
}
-float BKE_tracking_track_get_weight_for_marker(MovieClip *clip, MovieTrackingTrack *track, MovieTrackingMarker *marker)
+float BKE_tracking_track_get_weight_for_marker(MovieClip *clip,
+ MovieTrackingTrack *track,
+ MovieTrackingMarker *marker)
{
- FCurve *weight_fcurve;
- float weight = track->weight;
+ FCurve *weight_fcurve;
+ float weight = track->weight;
- weight_fcurve = id_data_find_fcurve(&clip->id, track, &RNA_MovieTrackingTrack,
- "weight", 0, NULL);
+ weight_fcurve = id_data_find_fcurve(
+ &clip->id, track, &RNA_MovieTrackingTrack, "weight", 0, NULL);
- if (weight_fcurve) {
- int scene_framenr =
- BKE_movieclip_remap_clip_to_scene_frame(clip, marker->framenr);
- weight = evaluate_fcurve(weight_fcurve, scene_framenr);
- }
+ if (weight_fcurve) {
+ int scene_framenr = BKE_movieclip_remap_clip_to_scene_frame(clip, marker->framenr);
+ weight = evaluate_fcurve(weight_fcurve, scene_framenr);
+ }
- return weight;
+ return weight;
}
/* area - which part of marker should be selected. see TRACK_AREA_* constants */
-void BKE_tracking_track_select(ListBase *tracksbase, MovieTrackingTrack *track, int area, bool extend)
-{
- if (extend) {
- BKE_tracking_track_flag_set(track, area, SELECT);
- }
- else {
- MovieTrackingTrack *cur = tracksbase->first;
-
- while (cur) {
- if ((cur->flag & TRACK_HIDDEN) == 0) {
- if (cur == track) {
- BKE_tracking_track_flag_clear(cur, TRACK_AREA_ALL, SELECT);
- BKE_tracking_track_flag_set(cur, area, SELECT);
- }
- else {
- BKE_tracking_track_flag_clear(cur, TRACK_AREA_ALL, SELECT);
- }
- }
-
- cur = cur->next;
- }
- }
+void BKE_tracking_track_select(ListBase *tracksbase,
+ MovieTrackingTrack *track,
+ int area,
+ bool extend)
+{
+ if (extend) {
+ BKE_tracking_track_flag_set(track, area, SELECT);
+ }
+ else {
+ MovieTrackingTrack *cur = tracksbase->first;
+
+ while (cur) {
+ if ((cur->flag & TRACK_HIDDEN) == 0) {
+ if (cur == track) {
+ BKE_tracking_track_flag_clear(cur, TRACK_AREA_ALL, SELECT);
+ BKE_tracking_track_flag_set(cur, area, SELECT);
+ }
+ else {
+ BKE_tracking_track_flag_clear(cur, TRACK_AREA_ALL, SELECT);
+ }
+ }
+
+ cur = cur->next;
+ }
+ }
}
void BKE_tracking_track_deselect(MovieTrackingTrack *track, int area)
{
- BKE_tracking_track_flag_clear(track, area, SELECT);
+ BKE_tracking_track_flag_clear(track, area, SELECT);
}
void BKE_tracking_tracks_deselect_all(ListBase *tracksbase)
{
- MovieTrackingTrack *track;
+ MovieTrackingTrack *track;
- for (track = tracksbase->first; track; track = track->next) {
- if ((track->flag & TRACK_HIDDEN) == 0) {
- BKE_tracking_track_flag_clear(track, TRACK_AREA_ALL, SELECT);
- }
- }
+ for (track = tracksbase->first; track; track = track->next) {
+ if ((track->flag & TRACK_HIDDEN) == 0) {
+ BKE_tracking_track_flag_clear(track, TRACK_AREA_ALL, SELECT);
+ }
+ }
}
/*********************** Marker *************************/
-MovieTrackingMarker *BKE_tracking_marker_insert(MovieTrackingTrack *track, MovieTrackingMarker *marker)
+MovieTrackingMarker *BKE_tracking_marker_insert(MovieTrackingTrack *track,
+ MovieTrackingMarker *marker)
{
- MovieTrackingMarker *old_marker = NULL;
+ MovieTrackingMarker *old_marker = NULL;
- if (track->markersnr)
- old_marker = BKE_tracking_marker_get_exact(track, marker->framenr);
+ if (track->markersnr)
+ old_marker = BKE_tracking_marker_get_exact(track, marker->framenr);
- if (old_marker) {
- /* simply replace settings for already allocated marker */
- *old_marker = *marker;
+ if (old_marker) {
+ /* simply replace settings for already allocated marker */
+ *old_marker = *marker;
- return old_marker;
- }
- else {
- int a = track->markersnr;
+ return old_marker;
+ }
+ else {
+ int a = track->markersnr;
- /* find position in array where to add new marker */
- while (a--) {
- if (track->markers[a].framenr < marker->framenr)
- break;
- }
+ /* find position in array where to add new marker */
+ while (a--) {
+ if (track->markers[a].framenr < marker->framenr)
+ break;
+ }
- track->markersnr++;
+ track->markersnr++;
- if (track->markers)
- track->markers = MEM_reallocN(track->markers, sizeof(MovieTrackingMarker) * track->markersnr);
- else
- track->markers = MEM_callocN(sizeof(MovieTrackingMarker), "MovieTracking markers");
+ if (track->markers)
+ track->markers = MEM_reallocN(track->markers,
+ sizeof(MovieTrackingMarker) * track->markersnr);
+ else
+ track->markers = MEM_callocN(sizeof(MovieTrackingMarker), "MovieTracking markers");
- /* shift array to "free" space for new marker */
- memmove(track->markers + a + 2, track->markers + a + 1,
- (track->markersnr - a - 2) * sizeof(MovieTrackingMarker));
+ /* shift array to "free" space for new marker */
+ memmove(track->markers + a + 2,
+ track->markers + a + 1,
+ (track->markersnr - a - 2) * sizeof(MovieTrackingMarker));
- /* put new marker */
- track->markers[a + 1] = *marker;
+ /* put new marker */
+ track->markers[a + 1] = *marker;
- track->last_marker = a + 1;
+ track->last_marker = a + 1;
- return &track->markers[a + 1];
- }
+ return &track->markers[a + 1];
+ }
}
void BKE_tracking_marker_delete(MovieTrackingTrack *track, int framenr)
{
- int a = 0;
+ int a = 0;
- while (a < track->markersnr) {
- if (track->markers[a].framenr == framenr) {
- if (track->markersnr > 1) {
- memmove(track->markers + a, track->markers + a + 1,
- (track->markersnr - a - 1) * sizeof(MovieTrackingMarker));
- track->markersnr--;
- track->markers = MEM_reallocN(track->markers, sizeof(MovieTrackingMarker) * track->markersnr);
- }
- else {
- MEM_freeN(track->markers);
- track->markers = NULL;
- track->markersnr = 0;
- }
+ while (a < track->markersnr) {
+ if (track->markers[a].framenr == framenr) {
+ if (track->markersnr > 1) {
+ memmove(track->markers + a,
+ track->markers + a + 1,
+ (track->markersnr - a - 1) * sizeof(MovieTrackingMarker));
+ track->markersnr--;
+ track->markers = MEM_reallocN(track->markers,
+ sizeof(MovieTrackingMarker) * track->markersnr);
+ }
+ else {
+ MEM_freeN(track->markers);
+ track->markers = NULL;
+ track->markersnr = 0;
+ }
- break;
- }
+ break;
+ }
- a++;
- }
+ a++;
+ }
}
void BKE_tracking_marker_clamp(MovieTrackingMarker *marker, int event)
{
- int a;
- float pat_min[2], pat_max[2];
-
- BKE_tracking_marker_pattern_minmax(marker, pat_min, pat_max);
-
- if (event == CLAMP_PAT_DIM) {
- for (a = 0; a < 2; a++) {
- /* search shouldn't be resized smaller than pattern */
- marker->search_min[a] = min_ff(pat_min[a], marker->search_min[a]);
- marker->search_max[a] = max_ff(pat_max[a], marker->search_max[a]);
- }
- }
- else if (event == CLAMP_PAT_POS) {
- float dim[2];
-
- sub_v2_v2v2(dim, pat_max, pat_min);
-
- for (a = 0; a < 2; a++) {
- int b;
- /* pattern shouldn't be moved outside of search */
- if (pat_min[a] < marker->search_min[a]) {
- for (b = 0; b < 4; b++)
- marker->pattern_corners[b][a] += marker->search_min[a] - pat_min[a];
- }
- if (pat_max[a] > marker->search_max[a]) {
- for (b = 0; b < 4; b++)
- marker->pattern_corners[b][a] -= pat_max[a] - marker->search_max[a];
- }
- }
- }
- else if (event == CLAMP_SEARCH_DIM) {
- for (a = 0; a < 2; a++) {
- /* search shouldn't be resized smaller than pattern */
- marker->search_min[a] = min_ff(pat_min[a], marker->search_min[a]);
- marker->search_max[a] = max_ff(pat_max[a], marker->search_max[a]);
- }
- }
- else if (event == CLAMP_SEARCH_POS) {
- float dim[2];
-
- sub_v2_v2v2(dim, marker->search_max, marker->search_min);
-
- for (a = 0; a < 2; a++) {
- /* search shouldn't be moved inside pattern */
- if (marker->search_min[a] > pat_min[a]) {
- marker->search_min[a] = pat_min[a];
- marker->search_max[a] = marker->search_min[a] + dim[a];
- }
- if (marker->search_max[a] < pat_max[a]) {
- marker->search_max[a] = pat_max[a];
- marker->search_min[a] = marker->search_max[a] - dim[a];
- }
- }
- }
+ int a;
+ float pat_min[2], pat_max[2];
+
+ BKE_tracking_marker_pattern_minmax(marker, pat_min, pat_max);
+
+ if (event == CLAMP_PAT_DIM) {
+ for (a = 0; a < 2; a++) {
+ /* search shouldn't be resized smaller than pattern */
+ marker->search_min[a] = min_ff(pat_min[a], marker->search_min[a]);
+ marker->search_max[a] = max_ff(pat_max[a], marker->search_max[a]);
+ }
+ }
+ else if (event == CLAMP_PAT_POS) {
+ float dim[2];
+
+ sub_v2_v2v2(dim, pat_max, pat_min);
+
+ for (a = 0; a < 2; a++) {
+ int b;
+ /* pattern shouldn't be moved outside of search */
+ if (pat_min[a] < marker->search_min[a]) {
+ for (b = 0; b < 4; b++)
+ marker->pattern_corners[b][a] += marker->search_min[a] - pat_min[a];
+ }
+ if (pat_max[a] > marker->search_max[a]) {
+ for (b = 0; b < 4; b++)
+ marker->pattern_corners[b][a] -= pat_max[a] - marker->search_max[a];
+ }
+ }
+ }
+ else if (event == CLAMP_SEARCH_DIM) {
+ for (a = 0; a < 2; a++) {
+ /* search shouldn't be resized smaller than pattern */
+ marker->search_min[a] = min_ff(pat_min[a], marker->search_min[a]);
+ marker->search_max[a] = max_ff(pat_max[a], marker->search_max[a]);
+ }
+ }
+ else if (event == CLAMP_SEARCH_POS) {
+ float dim[2];
+
+ sub_v2_v2v2(dim, marker->search_max, marker->search_min);
+
+ for (a = 0; a < 2; a++) {
+ /* search shouldn't be moved inside pattern */
+ if (marker->search_min[a] > pat_min[a]) {
+ marker->search_min[a] = pat_min[a];
+ marker->search_max[a] = marker->search_min[a] + dim[a];
+ }
+ if (marker->search_max[a] < pat_max[a]) {
+ marker->search_max[a] = pat_max[a];
+ marker->search_min[a] = marker->search_max[a] - dim[a];
+ }
+ }
+ }
}
MovieTrackingMarker *BKE_tracking_marker_get(MovieTrackingTrack *track, int framenr)
{
- int a = track->markersnr - 1;
+ int a = track->markersnr - 1;
- if (!track->markersnr)
- return NULL;
+ if (!track->markersnr)
+ return NULL;
- /* approximate pre-first framenr marker with first marker */
- if (framenr < track->markers[0].framenr)
- return &track->markers[0];
+ /* approximate pre-first framenr marker with first marker */
+ if (framenr < track->markers[0].framenr)
+ return &track->markers[0];
- if (track->last_marker < track->markersnr)
- a = track->last_marker;
+ if (track->last_marker < track->markersnr)
+ a = track->last_marker;
- if (track->markers[a].framenr <= framenr) {
- while (a < track->markersnr && track->markers[a].framenr <= framenr) {
- if (track->markers[a].framenr == framenr) {
- track->last_marker = a;
+ if (track->markers[a].framenr <= framenr) {
+ while (a < track->markersnr && track->markers[a].framenr <= framenr) {
+ if (track->markers[a].framenr == framenr) {
+ track->last_marker = a;
- return &track->markers[a];
- }
- a++;
- }
+ return &track->markers[a];
+ }
+ a++;
+ }
- /* if there's no marker for exact position, use nearest marker from left side */
- return &track->markers[a - 1];
- }
- else {
- while (a >= 0 && track->markers[a].framenr >= framenr) {
- if (track->markers[a].framenr == framenr) {
- track->last_marker = a;
+ /* if there's no marker for exact position, use nearest marker from left side */
+ return &track->markers[a - 1];
+ }
+ else {
+ while (a >= 0 && track->markers[a].framenr >= framenr) {
+ if (track->markers[a].framenr == framenr) {
+ track->last_marker = a;
- return &track->markers[a];
- }
+ return &track->markers[a];
+ }
- a--;
- }
+ a--;
+ }
- /* if there's no marker for exact position, use nearest marker from left side */
- return &track->markers[a];
- }
+ /* if there's no marker for exact position, use nearest marker from left side */
+ return &track->markers[a];
+ }
- return NULL;
+ return NULL;
}
MovieTrackingMarker *BKE_tracking_marker_get_exact(MovieTrackingTrack *track, int framenr)
{
- MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
+ MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
- if (marker->framenr != framenr)
- return NULL;
+ if (marker->framenr != framenr)
+ return NULL;
- return marker;
+ return marker;
}
MovieTrackingMarker *BKE_tracking_marker_ensure(MovieTrackingTrack *track, int framenr)
{
- MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
+ MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
- if (marker->framenr != framenr) {
- MovieTrackingMarker marker_new;
+ if (marker->framenr != framenr) {
+ MovieTrackingMarker marker_new;
- marker_new = *marker;
- marker_new.framenr = framenr;
+ marker_new = *marker;
+ marker_new.framenr = framenr;
- BKE_tracking_marker_insert(track, &marker_new);
- marker = BKE_tracking_marker_get(track, framenr);
- }
+ BKE_tracking_marker_insert(track, &marker_new);
+ marker = BKE_tracking_marker_get(track, framenr);
+ }
- return marker;
+ return marker;
}
-void BKE_tracking_marker_pattern_minmax(const MovieTrackingMarker *marker, float min[2], float max[2])
+void BKE_tracking_marker_pattern_minmax(const MovieTrackingMarker *marker,
+ float min[2],
+ float max[2])
{
- INIT_MINMAX2(min, max);
+ INIT_MINMAX2(min, max);
- minmax_v2v2_v2(min, max, marker->pattern_corners[0]);
- minmax_v2v2_v2(min, max, marker->pattern_corners[1]);
- minmax_v2v2_v2(min, max, marker->pattern_corners[2]);
- minmax_v2v2_v2(min, max, marker->pattern_corners[3]);
+ minmax_v2v2_v2(min, max, marker->pattern_corners[0]);
+ minmax_v2v2_v2(min, max, marker->pattern_corners[1]);
+ minmax_v2v2_v2(min, max, marker->pattern_corners[2]);
+ minmax_v2v2_v2(min, max, marker->pattern_corners[3]);
}
-void BKE_tracking_marker_get_subframe_position(MovieTrackingTrack *track, float framenr, float pos[2])
+void BKE_tracking_marker_get_subframe_position(MovieTrackingTrack *track,
+ float framenr,
+ float pos[2])
{
- MovieTrackingMarker *marker = BKE_tracking_marker_get(track, (int) framenr);
- MovieTrackingMarker *marker_last = track->markers + (track->markersnr - 1);
+ MovieTrackingMarker *marker = BKE_tracking_marker_get(track, (int)framenr);
+ MovieTrackingMarker *marker_last = track->markers + (track->markersnr - 1);
- if (marker != marker_last) {
- MovieTrackingMarker *marker_next = marker + 1;
+ if (marker != marker_last) {
+ MovieTrackingMarker *marker_next = marker + 1;
- if (marker_next->framenr == marker->framenr + 1) {
- /* currently only do subframing inside tracked ranges, do not extrapolate tracked segments
- * could be changed when / if mask parent would be interpolating position in-between
- * tracked segments
- */
+ if (marker_next->framenr == marker->framenr + 1) {
+ /* currently only do subframing inside tracked ranges, do not extrapolate tracked segments
+ * could be changed when / if mask parent would be interpolating position in-between
+ * tracked segments
+ */
- float fac = (framenr - (int) framenr) / (marker_next->framenr - marker->framenr);
+ float fac = (framenr - (int)framenr) / (marker_next->framenr - marker->framenr);
- interp_v2_v2v2(pos, marker->pos, marker_next->pos, fac);
- }
- else {
- copy_v2_v2(pos, marker->pos);
- }
- }
- else {
- copy_v2_v2(pos, marker->pos);
- }
+ interp_v2_v2v2(pos, marker->pos, marker_next->pos, fac);
+ }
+ else {
+ copy_v2_v2(pos, marker->pos);
+ }
+ }
+ else {
+ copy_v2_v2(pos, marker->pos);
+ }
- /* currently track offset is always wanted to be applied here, could be made an option later */
- add_v2_v2(pos, track->offset);
+ /* currently track offset is always wanted to be applied here, could be made an option later */
+ add_v2_v2(pos, track->offset);
}
/*********************** Plane Track *************************/
/* Creates new plane track out of selected point tracks */
-MovieTrackingPlaneTrack *BKE_tracking_plane_track_add(MovieTracking *tracking, ListBase *plane_tracks_base,
- ListBase *tracks, int framenr)
-{
- MovieTrackingPlaneTrack *plane_track;
- MovieTrackingPlaneMarker plane_marker;
- MovieTrackingTrack *track;
- float tracks_min[2], tracks_max[2];
- int track_index, num_selected_tracks = 0;
-
- (void) tracking; /* Ignored. */
-
- /* Use bounding box of selected markers as an initial size of plane. */
- INIT_MINMAX2(tracks_min, tracks_max);
- for (track = tracks->first; track; track = track->next) {
- if (TRACK_SELECTED(track)) {
- MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
- float pattern_min[2], pattern_max[2];
- BKE_tracking_marker_pattern_minmax(marker, pattern_min, pattern_max);
- add_v2_v2(pattern_min, marker->pos);
- add_v2_v2(pattern_max, marker->pos);
- minmax_v2v2_v2(tracks_min, tracks_max, pattern_min);
- minmax_v2v2_v2(tracks_min, tracks_max, pattern_max);
- num_selected_tracks++;
- }
- }
-
- if (num_selected_tracks < 4) {
- return NULL;
- }
-
- /* Allocate new plane track. */
- plane_track = MEM_callocN(sizeof(MovieTrackingPlaneTrack), "new plane track");
-
- /* Use some default name. */
- strcpy(plane_track->name, "Plane Track");
-
- plane_track->image_opacity = 1.0f;
-
- /* Use selected tracks from given list as a plane. */
- plane_track->point_tracks =
- MEM_mallocN(sizeof(MovieTrackingTrack *) * num_selected_tracks, "new plane tracks array");
- for (track = tracks->first, track_index = 0; track; track = track->next) {
- if (TRACK_SELECTED(track)) {
- plane_track->point_tracks[track_index] = track;
- track_index++;
- }
- }
- plane_track->point_tracksnr = num_selected_tracks;
-
- /* Setup new plane marker and add it to the track. */
- plane_marker.framenr = framenr;
- plane_marker.flag = 0;
-
- copy_v2_v2(plane_marker.corners[0], tracks_min);
- copy_v2_v2(plane_marker.corners[2], tracks_max);
-
- plane_marker.corners[1][0] = tracks_max[0];
- plane_marker.corners[1][1] = tracks_min[1];
- plane_marker.corners[3][0] = tracks_min[0];
- plane_marker.corners[3][1] = tracks_max[1];
-
- BKE_tracking_plane_marker_insert(plane_track, &plane_marker);
-
- /* Put new plane track to the list, ensure it's name is unique. */
- BLI_addtail(plane_tracks_base, plane_track);
- BKE_tracking_plane_track_unique_name(plane_tracks_base, plane_track);
-
- return plane_track;
-}
-
-void BKE_tracking_plane_track_unique_name(ListBase *plane_tracks_base, MovieTrackingPlaneTrack *plane_track)
-{
- BLI_uniquename(plane_tracks_base, plane_track, CTX_DATA_(BLT_I18NCONTEXT_ID_MOVIECLIP, "Plane Track"), '.',
- offsetof(MovieTrackingPlaneTrack, name), sizeof(plane_track->name));
+MovieTrackingPlaneTrack *BKE_tracking_plane_track_add(MovieTracking *tracking,
+ ListBase *plane_tracks_base,
+ ListBase *tracks,
+ int framenr)
+{
+ MovieTrackingPlaneTrack *plane_track;
+ MovieTrackingPlaneMarker plane_marker;
+ MovieTrackingTrack *track;
+ float tracks_min[2], tracks_max[2];
+ int track_index, num_selected_tracks = 0;
+
+ (void)tracking; /* Ignored. */
+
+ /* Use bounding box of selected markers as an initial size of plane. */
+ INIT_MINMAX2(tracks_min, tracks_max);
+ for (track = tracks->first; track; track = track->next) {
+ if (TRACK_SELECTED(track)) {
+ MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
+ float pattern_min[2], pattern_max[2];
+ BKE_tracking_marker_pattern_minmax(marker, pattern_min, pattern_max);
+ add_v2_v2(pattern_min, marker->pos);
+ add_v2_v2(pattern_max, marker->pos);
+ minmax_v2v2_v2(tracks_min, tracks_max, pattern_min);
+ minmax_v2v2_v2(tracks_min, tracks_max, pattern_max);
+ num_selected_tracks++;
+ }
+ }
+
+ if (num_selected_tracks < 4) {
+ return NULL;
+ }
+
+ /* Allocate new plane track. */
+ plane_track = MEM_callocN(sizeof(MovieTrackingPlaneTrack), "new plane track");
+
+ /* Use some default name. */
+ strcpy(plane_track->name, "Plane Track");
+
+ plane_track->image_opacity = 1.0f;
+
+ /* Use selected tracks from given list as a plane. */
+ plane_track->point_tracks = MEM_mallocN(sizeof(MovieTrackingTrack *) * num_selected_tracks,
+ "new plane tracks array");
+ for (track = tracks->first, track_index = 0; track; track = track->next) {
+ if (TRACK_SELECTED(track)) {
+ plane_track->point_tracks[track_index] = track;
+ track_index++;
+ }
+ }
+ plane_track->point_tracksnr = num_selected_tracks;
+
+ /* Setup new plane marker and add it to the track. */
+ plane_marker.framenr = framenr;
+ plane_marker.flag = 0;
+
+ copy_v2_v2(plane_marker.corners[0], tracks_min);
+ copy_v2_v2(plane_marker.corners[2], tracks_max);
+
+ plane_marker.corners[1][0] = tracks_max[0];
+ plane_marker.corners[1][1] = tracks_min[1];
+ plane_marker.corners[3][0] = tracks_min[0];
+ plane_marker.corners[3][1] = tracks_max[1];
+
+ BKE_tracking_plane_marker_insert(plane_track, &plane_marker);
+
+ /* Put new plane track to the list, ensure it's name is unique. */
+ BLI_addtail(plane_tracks_base, plane_track);
+ BKE_tracking_plane_track_unique_name(plane_tracks_base, plane_track);
+
+ return plane_track;
+}
+
+void BKE_tracking_plane_track_unique_name(ListBase *plane_tracks_base,
+ MovieTrackingPlaneTrack *plane_track)
+{
+ BLI_uniquename(plane_tracks_base,
+ plane_track,
+ CTX_DATA_(BLT_I18NCONTEXT_ID_MOVIECLIP, "Plane Track"),
+ '.',
+ offsetof(MovieTrackingPlaneTrack, name),
+ sizeof(plane_track->name));
}
/* Free specified plane track, only frees contents of a structure
@@ -1437,146 +1495,135 @@ void BKE_tracking_plane_track_unique_name(ListBase *plane_tracks_base, MovieTrac
*/
void BKE_tracking_plane_track_free(MovieTrackingPlaneTrack *plane_track)
{
- if (plane_track->markers) {
- MEM_freeN(plane_track->markers);
- }
+ if (plane_track->markers) {
+ MEM_freeN(plane_track->markers);
+ }
- MEM_freeN(plane_track->point_tracks);
+ MEM_freeN(plane_track->point_tracks);
}
MovieTrackingPlaneTrack *BKE_tracking_plane_track_get_named(MovieTracking *tracking,
MovieTrackingObject *object,
const char *name)
{
- ListBase *plane_tracks_base = BKE_tracking_object_get_plane_tracks(tracking, object);
- MovieTrackingPlaneTrack *plane_track;
+ ListBase *plane_tracks_base = BKE_tracking_object_get_plane_tracks(tracking, object);
+ MovieTrackingPlaneTrack *plane_track;
- for (plane_track = plane_tracks_base->first;
- plane_track;
- plane_track = plane_track->next)
- {
- if (STREQ(plane_track->name, name)) {
- return plane_track;
- }
- }
+ for (plane_track = plane_tracks_base->first; plane_track; plane_track = plane_track->next) {
+ if (STREQ(plane_track->name, name)) {
+ return plane_track;
+ }
+ }
- return NULL;
+ return NULL;
}
MovieTrackingPlaneTrack *BKE_tracking_plane_track_get_active(struct MovieTracking *tracking)
{
- ListBase *plane_tracks_base;
+ ListBase *plane_tracks_base;
- if (tracking->act_plane_track == NULL) {
- return NULL;
- }
+ if (tracking->act_plane_track == NULL) {
+ return NULL;
+ }
- plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
+ plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
- /* Check that active track is in current plane tracks list */
- if (BLI_findindex(plane_tracks_base, tracking->act_plane_track) != -1) {
- return tracking->act_plane_track;
- }
+ /* Check that active track is in current plane tracks list */
+ if (BLI_findindex(plane_tracks_base, tracking->act_plane_track) != -1) {
+ return tracking->act_plane_track;
+ }
- return NULL;
+ return NULL;
}
void BKE_tracking_plane_tracks_deselect_all(ListBase *plane_tracks_base)
{
- MovieTrackingPlaneTrack *plane_track;
+ MovieTrackingPlaneTrack *plane_track;
- for (plane_track = plane_tracks_base->first; plane_track; plane_track = plane_track->next) {
- plane_track->flag &= ~SELECT;
- }
+ for (plane_track = plane_tracks_base->first; plane_track; plane_track = plane_track->next) {
+ plane_track->flag &= ~SELECT;
+ }
}
bool BKE_tracking_plane_track_has_point_track(MovieTrackingPlaneTrack *plane_track,
MovieTrackingTrack *track)
{
- int i;
- for (i = 0; i < plane_track->point_tracksnr; i++) {
- if (plane_track->point_tracks[i] == track) {
- return true;
- }
- }
- return false;
+ int i;
+ for (i = 0; i < plane_track->point_tracksnr; i++) {
+ if (plane_track->point_tracks[i] == track) {
+ return true;
+ }
+ }
+ return false;
}
bool BKE_tracking_plane_track_remove_point_track(MovieTrackingPlaneTrack *plane_track,
MovieTrackingTrack *track)
{
- int i, track_index;
- MovieTrackingTrack **new_point_tracks;
+ int i, track_index;
+ MovieTrackingTrack **new_point_tracks;
- if (plane_track->point_tracksnr <= 4) {
- return false;
- }
+ if (plane_track->point_tracksnr <= 4) {
+ return false;
+ }
- new_point_tracks = MEM_mallocN(sizeof(*new_point_tracks) * (plane_track->point_tracksnr - 1),
- "new point tracks array");
+ new_point_tracks = MEM_mallocN(sizeof(*new_point_tracks) * (plane_track->point_tracksnr - 1),
+ "new point tracks array");
- for (i = 0, track_index = 0; i < plane_track->point_tracksnr; i++) {
- if (plane_track->point_tracks[i] != track) {
- new_point_tracks[track_index++] = plane_track->point_tracks[i];
- }
- }
+ for (i = 0, track_index = 0; i < plane_track->point_tracksnr; i++) {
+ if (plane_track->point_tracks[i] != track) {
+ new_point_tracks[track_index++] = plane_track->point_tracks[i];
+ }
+ }
- MEM_freeN(plane_track->point_tracks);
- plane_track->point_tracks = new_point_tracks;
- plane_track->point_tracksnr--;
+ MEM_freeN(plane_track->point_tracks);
+ plane_track->point_tracks = new_point_tracks;
+ plane_track->point_tracksnr--;
- return true;
+ return true;
}
void BKE_tracking_plane_tracks_remove_point_track(MovieTracking *tracking,
MovieTrackingTrack *track)
{
- MovieTrackingPlaneTrack *plane_track, *next_plane_track;
- ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
- for (plane_track = plane_tracks_base->first;
- plane_track;
- plane_track = next_plane_track)
- {
- next_plane_track = plane_track->next;
- if (BKE_tracking_plane_track_has_point_track(plane_track, track)) {
- if (!BKE_tracking_plane_track_remove_point_track(plane_track, track)) {
- /* Delete planes with less than 3 point tracks in it. */
- BKE_tracking_plane_track_free(plane_track);
- BLI_freelinkN(plane_tracks_base, plane_track);
- }
- }
- }
+ MovieTrackingPlaneTrack *plane_track, *next_plane_track;
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
+ for (plane_track = plane_tracks_base->first; plane_track; plane_track = next_plane_track) {
+ next_plane_track = plane_track->next;
+ if (BKE_tracking_plane_track_has_point_track(plane_track, track)) {
+ if (!BKE_tracking_plane_track_remove_point_track(plane_track, track)) {
+ /* Delete planes with less than 3 point tracks in it. */
+ BKE_tracking_plane_track_free(plane_track);
+ BLI_freelinkN(plane_tracks_base, plane_track);
+ }
+ }
+ }
}
void BKE_tracking_plane_track_replace_point_track(MovieTrackingPlaneTrack *plane_track,
MovieTrackingTrack *old_track,
MovieTrackingTrack *new_track)
{
- int i;
- for (i = 0; i < plane_track->point_tracksnr; i++) {
- if (plane_track->point_tracks[i] == old_track) {
- plane_track->point_tracks[i] = new_track;
- break;
- }
- }
+ int i;
+ for (i = 0; i < plane_track->point_tracksnr; i++) {
+ if (plane_track->point_tracks[i] == old_track) {
+ plane_track->point_tracks[i] = new_track;
+ break;
+ }
+ }
}
void BKE_tracking_plane_tracks_replace_point_track(MovieTracking *tracking,
MovieTrackingTrack *old_track,
MovieTrackingTrack *new_track)
{
- MovieTrackingPlaneTrack *plane_track;
- ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
- for (plane_track = plane_tracks_base->first;
- plane_track;
- plane_track = plane_track->next)
- {
- if (BKE_tracking_plane_track_has_point_track(plane_track, old_track)) {
- BKE_tracking_plane_track_replace_point_track(plane_track,
- old_track,
- new_track);
- }
- }
+ MovieTrackingPlaneTrack *plane_track;
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
+ for (plane_track = plane_tracks_base->first; plane_track; plane_track = plane_track->next) {
+ if (BKE_tracking_plane_track_has_point_track(plane_track, old_track)) {
+ BKE_tracking_plane_track_replace_point_track(plane_track, old_track, new_track);
+ }
+ }
}
/*********************** Plane Marker *************************/
@@ -1584,68 +1631,70 @@ void BKE_tracking_plane_tracks_replace_point_track(MovieTracking *tracking,
MovieTrackingPlaneMarker *BKE_tracking_plane_marker_insert(MovieTrackingPlaneTrack *plane_track,
MovieTrackingPlaneMarker *plane_marker)
{
- MovieTrackingPlaneMarker *old_plane_marker = NULL;
+ MovieTrackingPlaneMarker *old_plane_marker = NULL;
- if (plane_track->markersnr)
- old_plane_marker = BKE_tracking_plane_marker_get_exact(plane_track, plane_marker->framenr);
+ if (plane_track->markersnr)
+ old_plane_marker = BKE_tracking_plane_marker_get_exact(plane_track, plane_marker->framenr);
- if (old_plane_marker) {
- /* Simply replace settings in existing marker. */
- *old_plane_marker = *plane_marker;
+ if (old_plane_marker) {
+ /* Simply replace settings in existing marker. */
+ *old_plane_marker = *plane_marker;
- return old_plane_marker;
- }
- else {
- int a = plane_track->markersnr;
+ return old_plane_marker;
+ }
+ else {
+ int a = plane_track->markersnr;
- /* Find position in array where to add new marker. */
- /* TODO(sergey): we could use bisect to speed things up. */
- while (a--) {
- if (plane_track->markers[a].framenr < plane_marker->framenr) {
- break;
- }
- }
+ /* Find position in array where to add new marker. */
+ /* TODO(sergey): we could use bisect to speed things up. */
+ while (a--) {
+ if (plane_track->markers[a].framenr < plane_marker->framenr) {
+ break;
+ }
+ }
- plane_track->markersnr++;
- plane_track->markers = MEM_reallocN(plane_track->markers,
- sizeof(MovieTrackingPlaneMarker) * plane_track->markersnr);
+ plane_track->markersnr++;
+ plane_track->markers = MEM_reallocN(plane_track->markers,
+ sizeof(MovieTrackingPlaneMarker) * plane_track->markersnr);
- /* Shift array to "free" space for new marker. */
- memmove(plane_track->markers + a + 2, plane_track->markers + a + 1,
- (plane_track->markersnr - a - 2) * sizeof(MovieTrackingPlaneMarker));
+ /* Shift array to "free" space for new marker. */
+ memmove(plane_track->markers + a + 2,
+ plane_track->markers + a + 1,
+ (plane_track->markersnr - a - 2) * sizeof(MovieTrackingPlaneMarker));
- /* Put new marker to an array. */
- plane_track->markers[a + 1] = *plane_marker;
- plane_track->last_marker = a + 1;
+ /* Put new marker to an array. */
+ plane_track->markers[a + 1] = *plane_marker;
+ plane_track->last_marker = a + 1;
- return &plane_track->markers[a + 1];
- }
+ return &plane_track->markers[a + 1];
+ }
}
void BKE_tracking_plane_marker_delete(MovieTrackingPlaneTrack *plane_track, int framenr)
{
- int a = 0;
+ int a = 0;
- while (a < plane_track->markersnr) {
- if (plane_track->markers[a].framenr == framenr) {
- if (plane_track->markersnr > 1) {
- memmove(plane_track->markers + a, plane_track->markers + a + 1,
- (plane_track->markersnr - a - 1) * sizeof(MovieTrackingPlaneMarker));
- plane_track->markersnr--;
- plane_track->markers = MEM_reallocN(plane_track->markers,
- sizeof(MovieTrackingMarker) * plane_track->markersnr);
- }
- else {
- MEM_freeN(plane_track->markers);
- plane_track->markers = NULL;
- plane_track->markersnr = 0;
- }
+ while (a < plane_track->markersnr) {
+ if (plane_track->markers[a].framenr == framenr) {
+ if (plane_track->markersnr > 1) {
+ memmove(plane_track->markers + a,
+ plane_track->markers + a + 1,
+ (plane_track->markersnr - a - 1) * sizeof(MovieTrackingPlaneMarker));
+ plane_track->markersnr--;
+ plane_track->markers = MEM_reallocN(plane_track->markers,
+ sizeof(MovieTrackingMarker) * plane_track->markersnr);
+ }
+ else {
+ MEM_freeN(plane_track->markers);
+ plane_track->markers = NULL;
+ plane_track->markersnr = 0;
+ }
- break;
- }
+ break;
+ }
- a++;
- }
+ a++;
+ }
}
/* TODO(sergey): The next couple of functions are really quite the same as point marker version,
@@ -1655,892 +1704,946 @@ void BKE_tracking_plane_marker_delete(MovieTrackingPlaneTrack *plane_track, int
/* Get a plane marker at given frame,
* If there's no such marker, closest one from the left side will be returned.
*/
-MovieTrackingPlaneMarker *BKE_tracking_plane_marker_get(MovieTrackingPlaneTrack *plane_track, int framenr)
+MovieTrackingPlaneMarker *BKE_tracking_plane_marker_get(MovieTrackingPlaneTrack *plane_track,
+ int framenr)
{
- int a = plane_track->markersnr - 1;
+ int a = plane_track->markersnr - 1;
- if (!plane_track->markersnr)
- return NULL;
+ if (!plane_track->markersnr)
+ return NULL;
- /* Approximate pre-first framenr marker with first marker. */
- if (framenr < plane_track->markers[0].framenr) {
- return &plane_track->markers[0];
- }
+ /* Approximate pre-first framenr marker with first marker. */
+ if (framenr < plane_track->markers[0].framenr) {
+ return &plane_track->markers[0];
+ }
- if (plane_track->last_marker < plane_track->markersnr) {
- a = plane_track->last_marker;
- }
+ if (plane_track->last_marker < plane_track->markersnr) {
+ a = plane_track->last_marker;
+ }
- if (plane_track->markers[a].framenr <= framenr) {
- while (a < plane_track->markersnr && plane_track->markers[a].framenr <= framenr) {
- if (plane_track->markers[a].framenr == framenr) {
- plane_track->last_marker = a;
+ if (plane_track->markers[a].framenr <= framenr) {
+ while (a < plane_track->markersnr && plane_track->markers[a].framenr <= framenr) {
+ if (plane_track->markers[a].framenr == framenr) {
+ plane_track->last_marker = a;
- return &plane_track->markers[a];
- }
- a++;
- }
+ return &plane_track->markers[a];
+ }
+ a++;
+ }
- /* If there's no marker for exact position, use nearest marker from left side. */
- return &plane_track->markers[a - 1];
- }
- else {
- while (a >= 0 && plane_track->markers[a].framenr >= framenr) {
- if (plane_track->markers[a].framenr == framenr) {
- plane_track->last_marker = a;
+ /* If there's no marker for exact position, use nearest marker from left side. */
+ return &plane_track->markers[a - 1];
+ }
+ else {
+ while (a >= 0 && plane_track->markers[a].framenr >= framenr) {
+ if (plane_track->markers[a].framenr == framenr) {
+ plane_track->last_marker = a;
- return &plane_track->markers[a];
- }
+ return &plane_track->markers[a];
+ }
- a--;
- }
+ a--;
+ }
- /* If there's no marker for exact position, use nearest marker from left side. */
- return &plane_track->markers[a];
- }
+ /* If there's no marker for exact position, use nearest marker from left side. */
+ return &plane_track->markers[a];
+ }
- return NULL;
+ return NULL;
}
/* Get a plane marker at exact given frame, if there's no marker at the frame,
* NULL will be returned.
*/
-MovieTrackingPlaneMarker *BKE_tracking_plane_marker_get_exact(MovieTrackingPlaneTrack *plane_track, int framenr)
+MovieTrackingPlaneMarker *BKE_tracking_plane_marker_get_exact(MovieTrackingPlaneTrack *plane_track,
+ int framenr)
{
- MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, framenr);
+ MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, framenr);
- if (plane_marker->framenr != framenr) {
- return NULL;
- }
+ if (plane_marker->framenr != framenr) {
+ return NULL;
+ }
- return plane_marker;
+ return plane_marker;
}
/* Ensure there's a marker for the given frame. */
-MovieTrackingPlaneMarker *BKE_tracking_plane_marker_ensure(MovieTrackingPlaneTrack *plane_track, int framenr)
+MovieTrackingPlaneMarker *BKE_tracking_plane_marker_ensure(MovieTrackingPlaneTrack *plane_track,
+ int framenr)
{
- MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, framenr);
+ MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, framenr);
- if (plane_marker->framenr != framenr) {
- MovieTrackingPlaneMarker plane_marker_new;
+ if (plane_marker->framenr != framenr) {
+ MovieTrackingPlaneMarker plane_marker_new;
- plane_marker_new = *plane_marker;
- plane_marker_new.framenr = framenr;
+ plane_marker_new = *plane_marker;
+ plane_marker_new.framenr = framenr;
- plane_marker = BKE_tracking_plane_marker_insert(plane_track, &plane_marker_new);
- }
+ plane_marker = BKE_tracking_plane_marker_insert(plane_track, &plane_marker_new);
+ }
- return plane_marker;
+ return plane_marker;
}
void BKE_tracking_plane_marker_get_subframe_corners(MovieTrackingPlaneTrack *plane_track,
float framenr,
float corners[4][2])
{
- MovieTrackingPlaneMarker *marker = BKE_tracking_plane_marker_get(plane_track, (int)framenr);
- MovieTrackingPlaneMarker *marker_last = plane_track->markers + (plane_track->markersnr - 1);
- int i;
- if (marker != marker_last) {
- MovieTrackingPlaneMarker *marker_next = marker + 1;
- if (marker_next->framenr == marker->framenr + 1) {
- float fac = (framenr - (int) framenr) / (marker_next->framenr - marker->framenr);
- for (i = 0; i < 4; ++i) {
- interp_v2_v2v2(corners[i], marker->corners[i],
- marker_next->corners[i], fac);
- }
- }
- else {
- for (i = 0; i < 4; ++i) {
- copy_v2_v2(corners[i], marker->corners[i]);
- }
- }
- }
- else {
- for (i = 0; i < 4; ++i) {
- copy_v2_v2(corners[i], marker->corners[i]);
- }
- }
+ MovieTrackingPlaneMarker *marker = BKE_tracking_plane_marker_get(plane_track, (int)framenr);
+ MovieTrackingPlaneMarker *marker_last = plane_track->markers + (plane_track->markersnr - 1);
+ int i;
+ if (marker != marker_last) {
+ MovieTrackingPlaneMarker *marker_next = marker + 1;
+ if (marker_next->framenr == marker->framenr + 1) {
+ float fac = (framenr - (int)framenr) / (marker_next->framenr - marker->framenr);
+ for (i = 0; i < 4; ++i) {
+ interp_v2_v2v2(corners[i], marker->corners[i], marker_next->corners[i], fac);
+ }
+ }
+ else {
+ for (i = 0; i < 4; ++i) {
+ copy_v2_v2(corners[i], marker->corners[i]);
+ }
+ }
+ }
+ else {
+ for (i = 0; i < 4; ++i) {
+ copy_v2_v2(corners[i], marker->corners[i]);
+ }
+ }
}
/*********************** Object *************************/
MovieTrackingObject *BKE_tracking_object_add(MovieTracking *tracking, const char *name)
{
- MovieTrackingObject *object = MEM_callocN(sizeof(MovieTrackingObject), "tracking object");
+ MovieTrackingObject *object = MEM_callocN(sizeof(MovieTrackingObject), "tracking object");
- if (tracking->tot_object == 0) {
- /* first object is always camera */
- BLI_strncpy(object->name, "Camera", sizeof(object->name));
+ if (tracking->tot_object == 0) {
+ /* first object is always camera */
+ BLI_strncpy(object->name, "Camera", sizeof(object->name));
- object->flag |= TRACKING_OBJECT_CAMERA;
- }
- else {
- BLI_strncpy(object->name, name, sizeof(object->name));
- }
+ object->flag |= TRACKING_OBJECT_CAMERA;
+ }
+ else {
+ BLI_strncpy(object->name, name, sizeof(object->name));
+ }
- BLI_addtail(&tracking->objects, object);
+ BLI_addtail(&tracking->objects, object);
- tracking->tot_object++;
- tracking->objectnr = BLI_listbase_count(&tracking->objects) - 1;
+ tracking->tot_object++;
+ tracking->objectnr = BLI_listbase_count(&tracking->objects) - 1;
- object->scale = 1.0f;
- object->keyframe1 = 1;
- object->keyframe2 = 30;
+ object->scale = 1.0f;
+ object->keyframe1 = 1;
+ object->keyframe2 = 30;
- BKE_tracking_object_unique_name(tracking, object);
- BKE_tracking_dopesheet_tag_update(tracking);
+ BKE_tracking_object_unique_name(tracking, object);
+ BKE_tracking_dopesheet_tag_update(tracking);
- return object;
+ return object;
}
bool BKE_tracking_object_delete(MovieTracking *tracking, MovieTrackingObject *object)
{
- MovieTrackingTrack *track;
- int index = BLI_findindex(&tracking->objects, object);
+ MovieTrackingTrack *track;
+ int index = BLI_findindex(&tracking->objects, object);
- if (index == -1)
- return false;
+ if (index == -1)
+ return false;
- if (object->flag & TRACKING_OBJECT_CAMERA) {
- /* object used for camera solving can't be deleted */
- return false;
- }
+ if (object->flag & TRACKING_OBJECT_CAMERA) {
+ /* object used for camera solving can't be deleted */
+ return false;
+ }
- track = object->tracks.first;
- while (track) {
- if (track == tracking->act_track)
- tracking->act_track = NULL;
+ track = object->tracks.first;
+ while (track) {
+ if (track == tracking->act_track)
+ tracking->act_track = NULL;
- track = track->next;
- }
+ track = track->next;
+ }
- tracking_object_free(object);
- BLI_freelinkN(&tracking->objects, object);
+ tracking_object_free(object);
+ BLI_freelinkN(&tracking->objects, object);
- tracking->tot_object--;
+ tracking->tot_object--;
- if (index != 0)
- tracking->objectnr = index - 1;
- else
- tracking->objectnr = 0;
+ if (index != 0)
+ tracking->objectnr = index - 1;
+ else
+ tracking->objectnr = 0;
- BKE_tracking_dopesheet_tag_update(tracking);
+ BKE_tracking_dopesheet_tag_update(tracking);
- return true;
+ return true;
}
void BKE_tracking_object_unique_name(MovieTracking *tracking, MovieTrackingObject *object)
{
- BLI_uniquename(&tracking->objects, object, DATA_("Object"), '.',
- offsetof(MovieTrackingObject, name), sizeof(object->name));
+ BLI_uniquename(&tracking->objects,
+ object,
+ DATA_("Object"),
+ '.',
+ offsetof(MovieTrackingObject, name),
+ sizeof(object->name));
}
MovieTrackingObject *BKE_tracking_object_get_named(MovieTracking *tracking, const char *name)
{
- MovieTrackingObject *object = tracking->objects.first;
+ MovieTrackingObject *object = tracking->objects.first;
- while (object) {
- if (STREQ(object->name, name))
- return object;
+ while (object) {
+ if (STREQ(object->name, name))
+ return object;
- object = object->next;
- }
+ object = object->next;
+ }
- return NULL;
+ return NULL;
}
MovieTrackingObject *BKE_tracking_object_get_active(MovieTracking *tracking)
{
- return BLI_findlink(&tracking->objects, tracking->objectnr);
+ return BLI_findlink(&tracking->objects, tracking->objectnr);
}
MovieTrackingObject *BKE_tracking_object_get_camera(MovieTracking *tracking)
{
- MovieTrackingObject *object = tracking->objects.first;
+ MovieTrackingObject *object = tracking->objects.first;
- while (object) {
- if (object->flag & TRACKING_OBJECT_CAMERA)
- return object;
+ while (object) {
+ if (object->flag & TRACKING_OBJECT_CAMERA)
+ return object;
- object = object->next;
- }
+ object = object->next;
+ }
- return NULL;
+ return NULL;
}
ListBase *BKE_tracking_object_get_tracks(MovieTracking *tracking, MovieTrackingObject *object)
{
- if (object->flag & TRACKING_OBJECT_CAMERA) {
- return &tracking->tracks;
- }
+ if (object->flag & TRACKING_OBJECT_CAMERA) {
+ return &tracking->tracks;
+ }
- return &object->tracks;
+ return &object->tracks;
}
-ListBase *BKE_tracking_object_get_plane_tracks(MovieTracking *tracking, MovieTrackingObject *object)
+ListBase *BKE_tracking_object_get_plane_tracks(MovieTracking *tracking,
+ MovieTrackingObject *object)
{
- if (object->flag & TRACKING_OBJECT_CAMERA) {
- return &tracking->plane_tracks;
- }
+ if (object->flag & TRACKING_OBJECT_CAMERA) {
+ return &tracking->plane_tracks;
+ }
- return &object->plane_tracks;
+ return &object->plane_tracks;
}
MovieTrackingReconstruction *BKE_tracking_object_get_reconstruction(MovieTracking *tracking,
MovieTrackingObject *object)
{
- if (object->flag & TRACKING_OBJECT_CAMERA) {
- return &tracking->reconstruction;
- }
+ if (object->flag & TRACKING_OBJECT_CAMERA) {
+ return &tracking->reconstruction;
+ }
- return &object->reconstruction;
+ return &object->reconstruction;
}
/*********************** Camera *************************/
-static int reconstructed_camera_index_get(MovieTrackingReconstruction *reconstruction, int framenr, bool nearest)
+static int reconstructed_camera_index_get(MovieTrackingReconstruction *reconstruction,
+ int framenr,
+ bool nearest)
{
- MovieReconstructedCamera *cameras = reconstruction->cameras;
- int a = 0, d = 1;
+ MovieReconstructedCamera *cameras = reconstruction->cameras;
+ int a = 0, d = 1;
- if (!reconstruction->camnr)
- return -1;
+ if (!reconstruction->camnr)
+ return -1;
- if (framenr < cameras[0].framenr) {
- if (nearest)
- return 0;
- else
- return -1;
- }
+ if (framenr < cameras[0].framenr) {
+ if (nearest)
+ return 0;
+ else
+ return -1;
+ }
- if (framenr > cameras[reconstruction->camnr - 1].framenr) {
- if (nearest)
- return reconstruction->camnr - 1;
- else
- return -1;
- }
+ if (framenr > cameras[reconstruction->camnr - 1].framenr) {
+ if (nearest)
+ return reconstruction->camnr - 1;
+ else
+ return -1;
+ }
- if (reconstruction->last_camera < reconstruction->camnr)
- a = reconstruction->last_camera;
+ if (reconstruction->last_camera < reconstruction->camnr)
+ a = reconstruction->last_camera;
- if (cameras[a].framenr >= framenr)
- d = -1;
+ if (cameras[a].framenr >= framenr)
+ d = -1;
- while (a >= 0 && a < reconstruction->camnr) {
- int cfra = cameras[a].framenr;
+ while (a >= 0 && a < reconstruction->camnr) {
+ int cfra = cameras[a].framenr;
- /* check if needed framenr was "skipped" -- no data for requested frame */
+ /* check if needed framenr was "skipped" -- no data for requested frame */
- if (d > 0 && cfra > framenr) {
- /* interpolate with previous position */
- if (nearest)
- return a - 1;
- else
- break;
- }
+ if (d > 0 && cfra > framenr) {
+ /* interpolate with previous position */
+ if (nearest)
+ return a - 1;
+ else
+ break;
+ }
- if (d < 0 && cfra < framenr) {
- /* interpolate with next position */
- if (nearest)
- return a;
- else
- break;
- }
+ if (d < 0 && cfra < framenr) {
+ /* interpolate with next position */
+ if (nearest)
+ return a;
+ else
+ break;
+ }
- if (cfra == framenr) {
- reconstruction->last_camera = a;
+ if (cfra == framenr) {
+ reconstruction->last_camera = a;
- return a;
- }
+ return a;
+ }
- a += d;
- }
+ a += d;
+ }
- return -1;
+ return -1;
}
static void reconstructed_camera_scale_set(MovieTrackingObject *object, float mat[4][4])
{
- if ((object->flag & TRACKING_OBJECT_CAMERA) == 0) {
- float smat[4][4];
+ if ((object->flag & TRACKING_OBJECT_CAMERA) == 0) {
+ float smat[4][4];
- scale_m4_fl(smat, 1.0f / object->scale);
- mul_m4_m4m4(mat, mat, smat);
- }
+ scale_m4_fl(smat, 1.0f / object->scale);
+ mul_m4_m4m4(mat, mat, smat);
+ }
}
/* converts principal offset from center to offset of blender's camera */
-void BKE_tracking_camera_shift_get(MovieTracking *tracking, int winx, int winy, float *shiftx, float *shifty)
+void BKE_tracking_camera_shift_get(
+ MovieTracking *tracking, int winx, int winy, float *shiftx, float *shifty)
{
- /* indeed in both of cases it should be winx -- it's just how camera shift works for blender's camera */
- *shiftx = (0.5f * winx - tracking->camera.principal[0]) / winx;
- *shifty = (0.5f * winy - tracking->camera.principal[1]) / winx;
+ /* indeed in both of cases it should be winx -- it's just how camera shift works for blender's camera */
+ *shiftx = (0.5f * winx - tracking->camera.principal[0]) / winx;
+ *shifty = (0.5f * winy - tracking->camera.principal[1]) / winx;
}
-void BKE_tracking_camera_to_blender(MovieTracking *tracking, Scene *scene, Camera *camera, int width, int height)
+void BKE_tracking_camera_to_blender(
+ MovieTracking *tracking, Scene *scene, Camera *camera, int width, int height)
{
- float focal = tracking->camera.focal;
+ float focal = tracking->camera.focal;
- camera->sensor_x = tracking->camera.sensor_width;
- camera->sensor_fit = CAMERA_SENSOR_FIT_AUTO;
- camera->lens = focal * camera->sensor_x / width;
+ camera->sensor_x = tracking->camera.sensor_width;
+ camera->sensor_fit = CAMERA_SENSOR_FIT_AUTO;
+ camera->lens = focal * camera->sensor_x / width;
- scene->r.xsch = width;
- scene->r.ysch = height;
+ scene->r.xsch = width;
+ scene->r.ysch = height;
- scene->r.xasp = tracking->camera.pixel_aspect;
- scene->r.yasp = 1.0f;
+ scene->r.xasp = tracking->camera.pixel_aspect;
+ scene->r.yasp = 1.0f;
- BKE_tracking_camera_shift_get(tracking, width, height, &camera->shiftx, &camera->shifty);
+ BKE_tracking_camera_shift_get(tracking, width, height, &camera->shiftx, &camera->shifty);
}
MovieReconstructedCamera *BKE_tracking_camera_get_reconstructed(MovieTracking *tracking,
- MovieTrackingObject *object, int framenr)
+ MovieTrackingObject *object,
+ int framenr)
{
- MovieTrackingReconstruction *reconstruction;
- int a;
+ MovieTrackingReconstruction *reconstruction;
+ int a;
- reconstruction = BKE_tracking_object_get_reconstruction(tracking, object);
- a = reconstructed_camera_index_get(reconstruction, framenr, false);
+ reconstruction = BKE_tracking_object_get_reconstruction(tracking, object);
+ a = reconstructed_camera_index_get(reconstruction, framenr, false);
- if (a == -1)
- return NULL;
+ if (a == -1)
+ return NULL;
- return &reconstruction->cameras[a];
+ return &reconstruction->cameras[a];
}
-void BKE_tracking_camera_get_reconstructed_interpolate(MovieTracking *tracking, MovieTrackingObject *object,
- float framenr, float mat[4][4])
+void BKE_tracking_camera_get_reconstructed_interpolate(MovieTracking *tracking,
+ MovieTrackingObject *object,
+ float framenr,
+ float mat[4][4])
{
- MovieTrackingReconstruction *reconstruction;
- MovieReconstructedCamera *cameras;
- int a;
+ MovieTrackingReconstruction *reconstruction;
+ MovieReconstructedCamera *cameras;
+ int a;
- reconstruction = BKE_tracking_object_get_reconstruction(tracking, object);
- cameras = reconstruction->cameras;
- a = reconstructed_camera_index_get(reconstruction, (int)framenr, true);
+ reconstruction = BKE_tracking_object_get_reconstruction(tracking, object);
+ cameras = reconstruction->cameras;
+ a = reconstructed_camera_index_get(reconstruction, (int)framenr, true);
- if (a == -1) {
- unit_m4(mat);
- return;
- }
+ if (a == -1) {
+ unit_m4(mat);
+ return;
+ }
- if (cameras[a].framenr != framenr && a < reconstruction->camnr - 1) {
- float t = ((float)framenr - cameras[a].framenr) / (cameras[a + 1].framenr - cameras[a].framenr);
- blend_m4_m4m4(mat, cameras[a].mat, cameras[a + 1].mat, t);
- }
- else {
- copy_m4_m4(mat, cameras[a].mat);
- }
+ if (cameras[a].framenr != framenr && a < reconstruction->camnr - 1) {
+ float t = ((float)framenr - cameras[a].framenr) /
+ (cameras[a + 1].framenr - cameras[a].framenr);
+ blend_m4_m4m4(mat, cameras[a].mat, cameras[a + 1].mat, t);
+ }
+ else {
+ copy_m4_m4(mat, cameras[a].mat);
+ }
- reconstructed_camera_scale_set(object, mat);
+ reconstructed_camera_scale_set(object, mat);
}
/*********************** Distortion/Undistortion *************************/
MovieDistortion *BKE_tracking_distortion_new(MovieTracking *tracking,
- int calibration_width, int calibration_height)
+ int calibration_width,
+ int calibration_height)
{
- MovieDistortion *distortion;
- libmv_CameraIntrinsicsOptions camera_intrinsics_options;
+ MovieDistortion *distortion;
+ libmv_CameraIntrinsicsOptions camera_intrinsics_options;
- tracking_cameraIntrinscisOptionsFromTracking(tracking,
- calibration_width,
- calibration_height,
- &camera_intrinsics_options);
+ tracking_cameraIntrinscisOptionsFromTracking(
+ tracking, calibration_width, calibration_height, &camera_intrinsics_options);
- distortion = MEM_callocN(sizeof(MovieDistortion), "BKE_tracking_distortion_create");
- distortion->intrinsics = libmv_cameraIntrinsicsNew(&camera_intrinsics_options);
+ distortion = MEM_callocN(sizeof(MovieDistortion), "BKE_tracking_distortion_create");
+ distortion->intrinsics = libmv_cameraIntrinsicsNew(&camera_intrinsics_options);
- const MovieTrackingCamera *camera = &tracking->camera;
- copy_v2_v2(distortion->principal, camera->principal);
- distortion->pixel_aspect = camera->pixel_aspect;
- distortion->focal = camera->focal;
+ const MovieTrackingCamera *camera = &tracking->camera;
+ copy_v2_v2(distortion->principal, camera->principal);
+ distortion->pixel_aspect = camera->pixel_aspect;
+ distortion->focal = camera->focal;
- return distortion;
+ return distortion;
}
-void BKE_tracking_distortion_update(MovieDistortion *distortion, MovieTracking *tracking,
- int calibration_width, int calibration_height)
+void BKE_tracking_distortion_update(MovieDistortion *distortion,
+ MovieTracking *tracking,
+ int calibration_width,
+ int calibration_height)
{
- libmv_CameraIntrinsicsOptions camera_intrinsics_options;
+ libmv_CameraIntrinsicsOptions camera_intrinsics_options;
- tracking_cameraIntrinscisOptionsFromTracking(tracking,
- calibration_width,
- calibration_height,
- &camera_intrinsics_options);
+ tracking_cameraIntrinscisOptionsFromTracking(
+ tracking, calibration_width, calibration_height, &camera_intrinsics_options);
- const MovieTrackingCamera *camera = &tracking->camera;
- copy_v2_v2(distortion->principal, camera->principal);
- distortion->pixel_aspect = camera->pixel_aspect;
- distortion->focal = camera->focal;
+ const MovieTrackingCamera *camera = &tracking->camera;
+ copy_v2_v2(distortion->principal, camera->principal);
+ distortion->pixel_aspect = camera->pixel_aspect;
+ distortion->focal = camera->focal;
- libmv_cameraIntrinsicsUpdate(&camera_intrinsics_options, distortion->intrinsics);
+ libmv_cameraIntrinsicsUpdate(&camera_intrinsics_options, distortion->intrinsics);
}
void BKE_tracking_distortion_set_threads(MovieDistortion *distortion, int threads)
{
- libmv_cameraIntrinsicsSetThreads(distortion->intrinsics, threads);
+ libmv_cameraIntrinsicsSetThreads(distortion->intrinsics, threads);
}
MovieDistortion *BKE_tracking_distortion_copy(MovieDistortion *distortion)
{
- MovieDistortion *new_distortion;
-
- new_distortion = MEM_callocN(sizeof(MovieDistortion), "BKE_tracking_distortion_create");
- *new_distortion = *distortion;
- new_distortion->intrinsics = libmv_cameraIntrinsicsCopy(distortion->intrinsics);
-
- return new_distortion;
-}
-
-ImBuf *BKE_tracking_distortion_exec(MovieDistortion *distortion, MovieTracking *tracking, ImBuf *ibuf,
- int calibration_width, int calibration_height, float overscan, bool undistort)
-{
- ImBuf *resibuf;
-
- BKE_tracking_distortion_update(distortion, tracking, calibration_width, calibration_height);
-
- resibuf = IMB_dupImBuf(ibuf);
-
- if (ibuf->rect_float) {
- if (undistort) {
- libmv_cameraIntrinsicsUndistortFloat(distortion->intrinsics,
- ibuf->rect_float,
- ibuf->x, ibuf->y,
- overscan,
- ibuf->channels,
- resibuf->rect_float);
- }
- else {
- libmv_cameraIntrinsicsDistortFloat(distortion->intrinsics,
- ibuf->rect_float,
- ibuf->x, ibuf->y,
- overscan,
- ibuf->channels,
- resibuf->rect_float);
- }
-
- if (ibuf->rect)
- imb_freerectImBuf(ibuf);
- }
- else {
- if (undistort) {
- libmv_cameraIntrinsicsUndistortByte(distortion->intrinsics,
- (unsigned char *)ibuf->rect,
- ibuf->x, ibuf->y,
- overscan,
- ibuf->channels,
- (unsigned char *)resibuf->rect);
- }
- else {
- libmv_cameraIntrinsicsDistortByte(distortion->intrinsics,
- (unsigned char *)ibuf->rect,
- ibuf->x, ibuf->y,
- overscan,
- ibuf->channels,
- (unsigned char *)resibuf->rect);
- }
- }
-
- return resibuf;
+ MovieDistortion *new_distortion;
+
+ new_distortion = MEM_callocN(sizeof(MovieDistortion), "BKE_tracking_distortion_create");
+ *new_distortion = *distortion;
+ new_distortion->intrinsics = libmv_cameraIntrinsicsCopy(distortion->intrinsics);
+
+ return new_distortion;
+}
+
+ImBuf *BKE_tracking_distortion_exec(MovieDistortion *distortion,
+ MovieTracking *tracking,
+ ImBuf *ibuf,
+ int calibration_width,
+ int calibration_height,
+ float overscan,
+ bool undistort)
+{
+ ImBuf *resibuf;
+
+ BKE_tracking_distortion_update(distortion, tracking, calibration_width, calibration_height);
+
+ resibuf = IMB_dupImBuf(ibuf);
+
+ if (ibuf->rect_float) {
+ if (undistort) {
+ libmv_cameraIntrinsicsUndistortFloat(distortion->intrinsics,
+ ibuf->rect_float,
+ ibuf->x,
+ ibuf->y,
+ overscan,
+ ibuf->channels,
+ resibuf->rect_float);
+ }
+ else {
+ libmv_cameraIntrinsicsDistortFloat(distortion->intrinsics,
+ ibuf->rect_float,
+ ibuf->x,
+ ibuf->y,
+ overscan,
+ ibuf->channels,
+ resibuf->rect_float);
+ }
+
+ if (ibuf->rect)
+ imb_freerectImBuf(ibuf);
+ }
+ else {
+ if (undistort) {
+ libmv_cameraIntrinsicsUndistortByte(distortion->intrinsics,
+ (unsigned char *)ibuf->rect,
+ ibuf->x,
+ ibuf->y,
+ overscan,
+ ibuf->channels,
+ (unsigned char *)resibuf->rect);
+ }
+ else {
+ libmv_cameraIntrinsicsDistortByte(distortion->intrinsics,
+ (unsigned char *)ibuf->rect,
+ ibuf->x,
+ ibuf->y,
+ overscan,
+ ibuf->channels,
+ (unsigned char *)resibuf->rect);
+ }
+ }
+
+ return resibuf;
}
void BKE_tracking_distortion_distort_v2(MovieDistortion *distortion,
const float co[2],
float r_co[2])
{
- const float aspy = 1.0f / distortion->pixel_aspect;
+ const float aspy = 1.0f / distortion->pixel_aspect;
- /* Normalize coords. */
- float inv_focal = 1.0f / distortion->focal;
- double x = (co[0] - distortion->principal[0]) * inv_focal,
- y = (co[1] - distortion->principal[1] * aspy) * inv_focal;
+ /* Normalize coords. */
+ float inv_focal = 1.0f / distortion->focal;
+ double x = (co[0] - distortion->principal[0]) * inv_focal,
+ y = (co[1] - distortion->principal[1] * aspy) * inv_focal;
- libmv_cameraIntrinsicsApply(distortion->intrinsics, x, y, &x, &y);
+ libmv_cameraIntrinsicsApply(distortion->intrinsics, x, y, &x, &y);
- /* Result is in image coords already. */
- r_co[0] = x;
- r_co[1] = y;
+ /* Result is in image coords already. */
+ r_co[0] = x;
+ r_co[1] = y;
}
void BKE_tracking_distortion_undistort_v2(MovieDistortion *distortion,
const float co[2],
float r_co[2])
{
- double x = co[0], y = co[1];
- libmv_cameraIntrinsicsInvert(distortion->intrinsics, x, y, &x, &y);
+ double x = co[0], y = co[1];
+ libmv_cameraIntrinsicsInvert(distortion->intrinsics, x, y, &x, &y);
- const float aspy = 1.0f / distortion->pixel_aspect;
- r_co[0] = (float)x * distortion->focal + distortion->principal[0];
- r_co[1] = (float)y * distortion->focal + distortion->principal[1] * aspy;
+ const float aspy = 1.0f / distortion->pixel_aspect;
+ r_co[0] = (float)x * distortion->focal + distortion->principal[0];
+ r_co[1] = (float)y * distortion->focal + distortion->principal[1] * aspy;
}
void BKE_tracking_distortion_free(MovieDistortion *distortion)
{
- libmv_cameraIntrinsicsDestroy(distortion->intrinsics);
+ libmv_cameraIntrinsicsDestroy(distortion->intrinsics);
- MEM_freeN(distortion);
+ MEM_freeN(distortion);
}
void BKE_tracking_distort_v2(MovieTracking *tracking, const float co[2], float r_co[2])
{
- const MovieTrackingCamera *camera = &tracking->camera;
- const float aspy = 1.0f / tracking->camera.pixel_aspect;
+ const MovieTrackingCamera *camera = &tracking->camera;
+ const float aspy = 1.0f / tracking->camera.pixel_aspect;
- libmv_CameraIntrinsicsOptions camera_intrinsics_options;
- tracking_cameraIntrinscisOptionsFromTracking(tracking,
- 0, 0,
- &camera_intrinsics_options);
- libmv_CameraIntrinsics *intrinsics =
- libmv_cameraIntrinsicsNew(&camera_intrinsics_options);
+ libmv_CameraIntrinsicsOptions camera_intrinsics_options;
+ tracking_cameraIntrinscisOptionsFromTracking(tracking, 0, 0, &camera_intrinsics_options);
+ libmv_CameraIntrinsics *intrinsics = libmv_cameraIntrinsicsNew(&camera_intrinsics_options);
- /* Normalize coordinates. */
- double x = (co[0] - camera->principal[0]) / camera->focal,
- y = (co[1] - camera->principal[1] * aspy) / camera->focal;
+ /* Normalize coordinates. */
+ double x = (co[0] - camera->principal[0]) / camera->focal,
+ y = (co[1] - camera->principal[1] * aspy) / camera->focal;
- libmv_cameraIntrinsicsApply(intrinsics, x, y, &x, &y);
- libmv_cameraIntrinsicsDestroy(intrinsics);
+ libmv_cameraIntrinsicsApply(intrinsics, x, y, &x, &y);
+ libmv_cameraIntrinsicsDestroy(intrinsics);
- /* Result is in image coords already. */
- r_co[0] = x;
- r_co[1] = y;
+ /* Result is in image coords already. */
+ r_co[0] = x;
+ r_co[1] = y;
}
void BKE_tracking_undistort_v2(MovieTracking *tracking, const float co[2], float r_co[2])
{
- const MovieTrackingCamera *camera = &tracking->camera;
- const float aspy = 1.0f / tracking->camera.pixel_aspect;
+ const MovieTrackingCamera *camera = &tracking->camera;
+ const float aspy = 1.0f / tracking->camera.pixel_aspect;
- libmv_CameraIntrinsicsOptions camera_intrinsics_options;
- tracking_cameraIntrinscisOptionsFromTracking(tracking,
- 0, 0,
- &camera_intrinsics_options);
- libmv_CameraIntrinsics *intrinsics =
- libmv_cameraIntrinsicsNew(&camera_intrinsics_options);
+ libmv_CameraIntrinsicsOptions camera_intrinsics_options;
+ tracking_cameraIntrinscisOptionsFromTracking(tracking, 0, 0, &camera_intrinsics_options);
+ libmv_CameraIntrinsics *intrinsics = libmv_cameraIntrinsicsNew(&camera_intrinsics_options);
- double x = co[0], y = co[1];
- libmv_cameraIntrinsicsInvert(intrinsics, x, y, &x, &y);
- libmv_cameraIntrinsicsDestroy(intrinsics);
+ double x = co[0], y = co[1];
+ libmv_cameraIntrinsicsInvert(intrinsics, x, y, &x, &y);
+ libmv_cameraIntrinsicsDestroy(intrinsics);
- r_co[0] = (float)x * camera->focal + camera->principal[0];
- r_co[1] = (float)y * camera->focal + camera->principal[1] * aspy;
+ r_co[0] = (float)x * camera->focal + camera->principal[0];
+ r_co[1] = (float)y * camera->focal + camera->principal[1] * aspy;
}
-ImBuf *BKE_tracking_undistort_frame(MovieTracking *tracking, ImBuf *ibuf, int calibration_width,
- int calibration_height, float overscan)
+ImBuf *BKE_tracking_undistort_frame(MovieTracking *tracking,
+ ImBuf *ibuf,
+ int calibration_width,
+ int calibration_height,
+ float overscan)
{
- MovieTrackingCamera *camera = &tracking->camera;
+ MovieTrackingCamera *camera = &tracking->camera;
- if (camera->intrinsics == NULL) {
- camera->intrinsics = BKE_tracking_distortion_new(tracking, calibration_width, calibration_height);
- }
+ if (camera->intrinsics == NULL) {
+ camera->intrinsics = BKE_tracking_distortion_new(
+ tracking, calibration_width, calibration_height);
+ }
- return BKE_tracking_distortion_exec(camera->intrinsics, tracking, ibuf, calibration_width,
- calibration_height, overscan, true);
+ return BKE_tracking_distortion_exec(
+ camera->intrinsics, tracking, ibuf, calibration_width, calibration_height, overscan, true);
}
-ImBuf *BKE_tracking_distort_frame(MovieTracking *tracking, ImBuf *ibuf, int calibration_width,
- int calibration_height, float overscan)
+ImBuf *BKE_tracking_distort_frame(MovieTracking *tracking,
+ ImBuf *ibuf,
+ int calibration_width,
+ int calibration_height,
+ float overscan)
{
- MovieTrackingCamera *camera = &tracking->camera;
+ MovieTrackingCamera *camera = &tracking->camera;
- if (camera->intrinsics == NULL) {
- camera->intrinsics = BKE_tracking_distortion_new(tracking, calibration_width, calibration_height);
- }
+ if (camera->intrinsics == NULL) {
+ camera->intrinsics = BKE_tracking_distortion_new(
+ tracking, calibration_width, calibration_height);
+ }
- return BKE_tracking_distortion_exec(camera->intrinsics, tracking, ibuf, calibration_width,
- calibration_height, overscan, false);
+ return BKE_tracking_distortion_exec(
+ camera->intrinsics, tracking, ibuf, calibration_width, calibration_height, overscan, false);
}
-void BKE_tracking_max_distortion_delta_across_bound(MovieTracking *tracking, rcti *rect,
- bool undistort, float delta[2])
+void BKE_tracking_max_distortion_delta_across_bound(MovieTracking *tracking,
+ rcti *rect,
+ bool undistort,
+ float delta[2])
{
- int a;
- float pos[2], warped_pos[2];
- const int coord_delta = 5;
- void (*apply_distortion) (MovieTracking *tracking,
- const float pos[2], float out[2]);
+ int a;
+ float pos[2], warped_pos[2];
+ const int coord_delta = 5;
+ void (*apply_distortion)(MovieTracking * tracking, const float pos[2], float out[2]);
- if (undistort) {
- apply_distortion = BKE_tracking_undistort_v2;
- }
- else {
- apply_distortion = BKE_tracking_distort_v2;
- }
+ if (undistort) {
+ apply_distortion = BKE_tracking_undistort_v2;
+ }
+ else {
+ apply_distortion = BKE_tracking_distort_v2;
+ }
- delta[0] = delta[1] = -FLT_MAX;
+ delta[0] = delta[1] = -FLT_MAX;
- for (a = rect->xmin; a <= rect->xmax + coord_delta; a += coord_delta) {
- if (a > rect->xmax)
- a = rect->xmax;
+ for (a = rect->xmin; a <= rect->xmax + coord_delta; a += coord_delta) {
+ if (a > rect->xmax)
+ a = rect->xmax;
- /* bottom edge */
- pos[0] = a;
- pos[1] = rect->ymin;
+ /* bottom edge */
+ pos[0] = a;
+ pos[1] = rect->ymin;
- apply_distortion(tracking, pos, warped_pos);
+ apply_distortion(tracking, pos, warped_pos);
- delta[0] = max_ff(delta[0], fabsf(pos[0] - warped_pos[0]));
- delta[1] = max_ff(delta[1], fabsf(pos[1] - warped_pos[1]));
+ delta[0] = max_ff(delta[0], fabsf(pos[0] - warped_pos[0]));
+ delta[1] = max_ff(delta[1], fabsf(pos[1] - warped_pos[1]));
- /* top edge */
- pos[0] = a;
- pos[1] = rect->ymax;
+ /* top edge */
+ pos[0] = a;
+ pos[1] = rect->ymax;
- apply_distortion(tracking, pos, warped_pos);
+ apply_distortion(tracking, pos, warped_pos);
- delta[0] = max_ff(delta[0], fabsf(pos[0] - warped_pos[0]));
- delta[1] = max_ff(delta[1], fabsf(pos[1] - warped_pos[1]));
+ delta[0] = max_ff(delta[0], fabsf(pos[0] - warped_pos[0]));
+ delta[1] = max_ff(delta[1], fabsf(pos[1] - warped_pos[1]));
- if (a >= rect->xmax)
- break;
- }
+ if (a >= rect->xmax)
+ break;
+ }
- for (a = rect->ymin; a <= rect->ymax + coord_delta; a += coord_delta) {
- if (a > rect->ymax)
- a = rect->ymax;
+ for (a = rect->ymin; a <= rect->ymax + coord_delta; a += coord_delta) {
+ if (a > rect->ymax)
+ a = rect->ymax;
- /* left edge */
- pos[0] = rect->xmin;
- pos[1] = a;
+ /* left edge */
+ pos[0] = rect->xmin;
+ pos[1] = a;
- apply_distortion(tracking, pos, warped_pos);
+ apply_distortion(tracking, pos, warped_pos);
- delta[0] = max_ff(delta[0], fabsf(pos[0] - warped_pos[0]));
- delta[1] = max_ff(delta[1], fabsf(pos[1] - warped_pos[1]));
+ delta[0] = max_ff(delta[0], fabsf(pos[0] - warped_pos[0]));
+ delta[1] = max_ff(delta[1], fabsf(pos[1] - warped_pos[1]));
- /* right edge */
- pos[0] = rect->xmax;
- pos[1] = a;
+ /* right edge */
+ pos[0] = rect->xmax;
+ pos[1] = a;
- apply_distortion(tracking, pos, warped_pos);
+ apply_distortion(tracking, pos, warped_pos);
- delta[0] = max_ff(delta[0], fabsf(pos[0] - warped_pos[0]));
- delta[1] = max_ff(delta[1], fabsf(pos[1] - warped_pos[1]));
+ delta[0] = max_ff(delta[0], fabsf(pos[0] - warped_pos[0]));
+ delta[1] = max_ff(delta[1], fabsf(pos[1] - warped_pos[1]));
- if (a >= rect->ymax)
- break;
- }
+ if (a >= rect->ymax)
+ break;
+ }
}
/*********************** Image sampling *************************/
static void disable_imbuf_channels(ImBuf *ibuf, MovieTrackingTrack *track, bool grayscale)
{
- BKE_tracking_disable_channels(ibuf, track->flag & TRACK_DISABLE_RED,
- track->flag & TRACK_DISABLE_GREEN,
- track->flag & TRACK_DISABLE_BLUE, grayscale);
+ BKE_tracking_disable_channels(ibuf,
+ track->flag & TRACK_DISABLE_RED,
+ track->flag & TRACK_DISABLE_GREEN,
+ track->flag & TRACK_DISABLE_BLUE,
+ grayscale);
}
-ImBuf *BKE_tracking_sample_pattern(int frame_width, int frame_height, ImBuf *search_ibuf,
- MovieTrackingTrack *track, MovieTrackingMarker *marker,
- bool from_anchor, bool use_mask, int num_samples_x, int num_samples_y,
+ImBuf *BKE_tracking_sample_pattern(int frame_width,
+ int frame_height,
+ ImBuf *search_ibuf,
+ MovieTrackingTrack *track,
+ MovieTrackingMarker *marker,
+ bool from_anchor,
+ bool use_mask,
+ int num_samples_x,
+ int num_samples_y,
float pos[2])
{
- ImBuf *pattern_ibuf;
- double src_pixel_x[5], src_pixel_y[5];
- double warped_position_x, warped_position_y;
- float *mask = NULL;
-
- if (num_samples_x <= 0 || num_samples_y <= 0)
- return NULL;
-
- pattern_ibuf = IMB_allocImBuf(num_samples_x, num_samples_y,
- 32,
- search_ibuf->rect_float ? IB_rectfloat : IB_rect);
-
- tracking_get_marker_coords_for_tracking(frame_width, frame_height, marker, src_pixel_x, src_pixel_y);
-
- /* from_anchor means search buffer was obtained for an anchored position,
- * which means applying track offset rounded to pixel space (we could not
- * store search buffer with sub-pixel precision)
- *
- * in this case we need to alter coordinates a bit, to compensate rounded
- * fractional part of offset
- */
- if (from_anchor) {
- int a;
-
- for (a = 0; a < 5; a++) {
- src_pixel_x[a] += (double) ((track->offset[0] * frame_width) - ((int) (track->offset[0] * frame_width)));
- src_pixel_y[a] += (double) ((track->offset[1] * frame_height) - ((int) (track->offset[1] * frame_height)));
-
- /* when offset is negative, rounding happens in opposite direction */
- if (track->offset[0] < 0.0f)
- src_pixel_x[a] += 1.0;
- if (track->offset[1] < 0.0f)
- src_pixel_y[a] += 1.0;
- }
- }
-
- if (use_mask) {
- mask = BKE_tracking_track_get_mask(frame_width, frame_height, track, marker);
- }
-
- if (search_ibuf->rect_float) {
- libmv_samplePlanarPatchFloat(search_ibuf->rect_float,
- search_ibuf->x, search_ibuf->y, 4,
- src_pixel_x, src_pixel_y,
- num_samples_x, num_samples_y,
- mask,
- pattern_ibuf->rect_float,
- &warped_position_x,
- &warped_position_y);
- }
- else {
- libmv_samplePlanarPatchByte((unsigned char *) search_ibuf->rect,
- search_ibuf->x, search_ibuf->y, 4,
- src_pixel_x, src_pixel_y,
- num_samples_x, num_samples_y,
- mask,
- (unsigned char *) pattern_ibuf->rect,
- &warped_position_x,
- &warped_position_y);
- }
-
- if (pos) {
- pos[0] = warped_position_x;
- pos[1] = warped_position_y;
- }
-
- if (mask) {
- MEM_freeN(mask);
- }
-
- return pattern_ibuf;
-}
-
-ImBuf *BKE_tracking_get_pattern_imbuf(ImBuf *ibuf, MovieTrackingTrack *track, MovieTrackingMarker *marker,
- bool anchored, bool disable_channels)
-{
- ImBuf *pattern_ibuf, *search_ibuf;
- float pat_min[2], pat_max[2];
- int num_samples_x, num_samples_y;
-
- BKE_tracking_marker_pattern_minmax(marker, pat_min, pat_max);
-
- num_samples_x = (pat_max[0] - pat_min[0]) * ibuf->x;
- num_samples_y = (pat_max[1] - pat_min[1]) * ibuf->y;
-
- search_ibuf = BKE_tracking_get_search_imbuf(ibuf, track, marker, anchored, disable_channels);
-
- if (search_ibuf) {
- pattern_ibuf = BKE_tracking_sample_pattern(ibuf->x, ibuf->y, search_ibuf, track, marker,
- anchored, false, num_samples_x, num_samples_y, NULL);
-
- IMB_freeImBuf(search_ibuf);
- }
- else {
- pattern_ibuf = NULL;
- }
+ ImBuf *pattern_ibuf;
+ double src_pixel_x[5], src_pixel_y[5];
+ double warped_position_x, warped_position_y;
+ float *mask = NULL;
+
+ if (num_samples_x <= 0 || num_samples_y <= 0)
+ return NULL;
+
+ pattern_ibuf = IMB_allocImBuf(
+ num_samples_x, num_samples_y, 32, search_ibuf->rect_float ? IB_rectfloat : IB_rect);
+
+ tracking_get_marker_coords_for_tracking(
+ frame_width, frame_height, marker, src_pixel_x, src_pixel_y);
+
+ /* from_anchor means search buffer was obtained for an anchored position,
+ * which means applying track offset rounded to pixel space (we could not
+ * store search buffer with sub-pixel precision)
+ *
+ * in this case we need to alter coordinates a bit, to compensate rounded
+ * fractional part of offset
+ */
+ if (from_anchor) {
+ int a;
+
+ for (a = 0; a < 5; a++) {
+ src_pixel_x[a] += (double)((track->offset[0] * frame_width) -
+ ((int)(track->offset[0] * frame_width)));
+ src_pixel_y[a] += (double)((track->offset[1] * frame_height) -
+ ((int)(track->offset[1] * frame_height)));
+
+ /* when offset is negative, rounding happens in opposite direction */
+ if (track->offset[0] < 0.0f)
+ src_pixel_x[a] += 1.0;
+ if (track->offset[1] < 0.0f)
+ src_pixel_y[a] += 1.0;
+ }
+ }
+
+ if (use_mask) {
+ mask = BKE_tracking_track_get_mask(frame_width, frame_height, track, marker);
+ }
+
+ if (search_ibuf->rect_float) {
+ libmv_samplePlanarPatchFloat(search_ibuf->rect_float,
+ search_ibuf->x,
+ search_ibuf->y,
+ 4,
+ src_pixel_x,
+ src_pixel_y,
+ num_samples_x,
+ num_samples_y,
+ mask,
+ pattern_ibuf->rect_float,
+ &warped_position_x,
+ &warped_position_y);
+ }
+ else {
+ libmv_samplePlanarPatchByte((unsigned char *)search_ibuf->rect,
+ search_ibuf->x,
+ search_ibuf->y,
+ 4,
+ src_pixel_x,
+ src_pixel_y,
+ num_samples_x,
+ num_samples_y,
+ mask,
+ (unsigned char *)pattern_ibuf->rect,
+ &warped_position_x,
+ &warped_position_y);
+ }
+
+ if (pos) {
+ pos[0] = warped_position_x;
+ pos[1] = warped_position_y;
+ }
+
+ if (mask) {
+ MEM_freeN(mask);
+ }
+
+ return pattern_ibuf;
+}
+
+ImBuf *BKE_tracking_get_pattern_imbuf(ImBuf *ibuf,
+ MovieTrackingTrack *track,
+ MovieTrackingMarker *marker,
+ bool anchored,
+ bool disable_channels)
+{
+ ImBuf *pattern_ibuf, *search_ibuf;
+ float pat_min[2], pat_max[2];
+ int num_samples_x, num_samples_y;
+
+ BKE_tracking_marker_pattern_minmax(marker, pat_min, pat_max);
+
+ num_samples_x = (pat_max[0] - pat_min[0]) * ibuf->x;
+ num_samples_y = (pat_max[1] - pat_min[1]) * ibuf->y;
+
+ search_ibuf = BKE_tracking_get_search_imbuf(ibuf, track, marker, anchored, disable_channels);
+
+ if (search_ibuf) {
+ pattern_ibuf = BKE_tracking_sample_pattern(ibuf->x,
+ ibuf->y,
+ search_ibuf,
+ track,
+ marker,
+ anchored,
+ false,
+ num_samples_x,
+ num_samples_y,
+ NULL);
+
+ IMB_freeImBuf(search_ibuf);
+ }
+ else {
+ pattern_ibuf = NULL;
+ }
+
+ return pattern_ibuf;
+}
+
+ImBuf *BKE_tracking_get_search_imbuf(ImBuf *ibuf,
+ MovieTrackingTrack *track,
+ MovieTrackingMarker *marker,
+ bool anchored,
+ bool disable_channels)
+{
+ ImBuf *searchibuf;
+ int x, y, w, h;
+ float search_origin[2];
+
+ tracking_get_search_origin_frame_pixel(ibuf->x, ibuf->y, marker, search_origin);
+
+ x = search_origin[0];
+ y = search_origin[1];
+
+ if (anchored) {
+ x += track->offset[0] * ibuf->x;
+ y += track->offset[1] * ibuf->y;
+ }
+
+ w = (marker->search_max[0] - marker->search_min[0]) * ibuf->x;
+ h = (marker->search_max[1] - marker->search_min[1]) * ibuf->y;
+
+ if (w <= 0 || h <= 0)
+ return NULL;
+
+ searchibuf = IMB_allocImBuf(w, h, 32, ibuf->rect_float ? IB_rectfloat : IB_rect);
+
+ IMB_rectcpy(searchibuf, ibuf, 0, 0, x, y, w, h);
+
+ if (disable_channels) {
+ if ((track->flag & TRACK_PREVIEW_GRAYSCALE) || (track->flag & TRACK_DISABLE_RED) ||
+ (track->flag & TRACK_DISABLE_GREEN) || (track->flag & TRACK_DISABLE_BLUE)) {
+ disable_imbuf_channels(searchibuf, track, true);
+ }
+ }
- return pattern_ibuf;
-}
-
-ImBuf *BKE_tracking_get_search_imbuf(ImBuf *ibuf, MovieTrackingTrack *track, MovieTrackingMarker *marker,
- bool anchored, bool disable_channels)
-{
- ImBuf *searchibuf;
- int x, y, w, h;
- float search_origin[2];
-
- tracking_get_search_origin_frame_pixel(ibuf->x, ibuf->y, marker, search_origin);
-
- x = search_origin[0];
- y = search_origin[1];
-
- if (anchored) {
- x += track->offset[0] * ibuf->x;
- y += track->offset[1] * ibuf->y;
- }
-
- w = (marker->search_max[0] - marker->search_min[0]) * ibuf->x;
- h = (marker->search_max[1] - marker->search_min[1]) * ibuf->y;
-
- if (w <= 0 || h <= 0)
- return NULL;
-
- searchibuf = IMB_allocImBuf(w, h, 32, ibuf->rect_float ? IB_rectfloat : IB_rect);
-
- IMB_rectcpy(searchibuf, ibuf, 0, 0, x, y, w, h);
-
- if (disable_channels) {
- if ((track->flag & TRACK_PREVIEW_GRAYSCALE) ||
- (track->flag & TRACK_DISABLE_RED) ||
- (track->flag & TRACK_DISABLE_GREEN) ||
- (track->flag & TRACK_DISABLE_BLUE))
- {
- disable_imbuf_channels(searchibuf, track, true);
- }
- }
-
- return searchibuf;
+ return searchibuf;
}
/* zap channels from the imbuf that are disabled by the user. this can lead to
* better tracks sometimes. however, instead of simply zeroing the channels
* out, do a partial grayscale conversion so the display is better.
*/
-void BKE_tracking_disable_channels(ImBuf *ibuf, bool disable_red, bool disable_green, bool disable_blue,
- bool grayscale)
-{
- int x, y;
- float scale;
-
- if (!disable_red && !disable_green && !disable_blue && !grayscale)
- return;
-
- /* if only some components are selected, it's important to rescale the result
- * appropriately so that e.g. if only blue is selected, it's not zeroed out.
- */
- scale = (disable_red ? 0.0f : 0.2126f) +
- (disable_green ? 0.0f : 0.7152f) +
- (disable_blue ? 0.0f : 0.0722f);
-
- for (y = 0; y < ibuf->y; y++) {
- for (x = 0; x < ibuf->x; x++) {
- int pixel = ibuf->x * y + x;
-
- if (ibuf->rect_float) {
- float *rrgbf = ibuf->rect_float + pixel * 4;
- float r = disable_red ? 0.0f : rrgbf[0];
- float g = disable_green ? 0.0f : rrgbf[1];
- float b = disable_blue ? 0.0f : rrgbf[2];
-
- if (grayscale) {
- float gray = (0.2126f * r + 0.7152f * g + 0.0722f * b) / scale;
-
- rrgbf[0] = rrgbf[1] = rrgbf[2] = gray;
- }
- else {
- rrgbf[0] = r;
- rrgbf[1] = g;
- rrgbf[2] = b;
- }
- }
- else {
- char *rrgb = (char *)ibuf->rect + pixel * 4;
- char r = disable_red ? 0 : rrgb[0];
- char g = disable_green ? 0 : rrgb[1];
- char b = disable_blue ? 0 : rrgb[2];
-
- if (grayscale) {
- float gray = (0.2126f * r + 0.7152f * g + 0.0722f * b) / scale;
-
- rrgb[0] = rrgb[1] = rrgb[2] = gray;
- }
- else {
- rrgb[0] = r;
- rrgb[1] = g;
- rrgb[2] = b;
- }
- }
- }
- }
-
- if (ibuf->rect_float)
- ibuf->userflags |= IB_RECT_INVALID;
+void BKE_tracking_disable_channels(
+ ImBuf *ibuf, bool disable_red, bool disable_green, bool disable_blue, bool grayscale)
+{
+ int x, y;
+ float scale;
+
+ if (!disable_red && !disable_green && !disable_blue && !grayscale)
+ return;
+
+ /* if only some components are selected, it's important to rescale the result
+ * appropriately so that e.g. if only blue is selected, it's not zeroed out.
+ */
+ scale = (disable_red ? 0.0f : 0.2126f) + (disable_green ? 0.0f : 0.7152f) +
+ (disable_blue ? 0.0f : 0.0722f);
+
+ for (y = 0; y < ibuf->y; y++) {
+ for (x = 0; x < ibuf->x; x++) {
+ int pixel = ibuf->x * y + x;
+
+ if (ibuf->rect_float) {
+ float *rrgbf = ibuf->rect_float + pixel * 4;
+ float r = disable_red ? 0.0f : rrgbf[0];
+ float g = disable_green ? 0.0f : rrgbf[1];
+ float b = disable_blue ? 0.0f : rrgbf[2];
+
+ if (grayscale) {
+ float gray = (0.2126f * r + 0.7152f * g + 0.0722f * b) / scale;
+
+ rrgbf[0] = rrgbf[1] = rrgbf[2] = gray;
+ }
+ else {
+ rrgbf[0] = r;
+ rrgbf[1] = g;
+ rrgbf[2] = b;
+ }
+ }
+ else {
+ char *rrgb = (char *)ibuf->rect + pixel * 4;
+ char r = disable_red ? 0 : rrgb[0];
+ char g = disable_green ? 0 : rrgb[1];
+ char b = disable_blue ? 0 : rrgb[2];
+
+ if (grayscale) {
+ float gray = (0.2126f * r + 0.7152f * g + 0.0722f * b) / scale;
+
+ rrgb[0] = rrgb[1] = rrgb[2] = gray;
+ }
+ else {
+ rrgb[0] = r;
+ rrgb[1] = g;
+ rrgb[2] = b;
+ }
+ }
+ }
+ }
+
+ if (ibuf->rect_float)
+ ibuf->userflags |= IB_RECT_INVALID;
}
/*********************** Dopesheet functions *************************/
@@ -2549,250 +2652,253 @@ void BKE_tracking_disable_channels(ImBuf *ibuf, bool disable_red, bool disable_g
static int channels_alpha_sort(const void *a, const void *b)
{
- const MovieTrackingDopesheetChannel *channel_a = a;
- const MovieTrackingDopesheetChannel *channel_b = b;
+ const MovieTrackingDopesheetChannel *channel_a = a;
+ const MovieTrackingDopesheetChannel *channel_b = b;
- if (BLI_strcasecmp(channel_a->track->name, channel_b->track->name) > 0)
- return 1;
- else
- return 0;
+ if (BLI_strcasecmp(channel_a->track->name, channel_b->track->name) > 0)
+ return 1;
+ else
+ return 0;
}
static int channels_total_track_sort(const void *a, const void *b)
{
- const MovieTrackingDopesheetChannel *channel_a = a;
- const MovieTrackingDopesheetChannel *channel_b = b;
+ const MovieTrackingDopesheetChannel *channel_a = a;
+ const MovieTrackingDopesheetChannel *channel_b = b;
- if (channel_a->total_frames > channel_b->total_frames)
- return 1;
- else
- return 0;
+ if (channel_a->total_frames > channel_b->total_frames)
+ return 1;
+ else
+ return 0;
}
static int channels_longest_segment_sort(const void *a, const void *b)
{
- const MovieTrackingDopesheetChannel *channel_a = a;
- const MovieTrackingDopesheetChannel *channel_b = b;
+ const MovieTrackingDopesheetChannel *channel_a = a;
+ const MovieTrackingDopesheetChannel *channel_b = b;
- if (channel_a->max_segment > channel_b->max_segment)
- return 1;
- else
- return 0;
+ if (channel_a->max_segment > channel_b->max_segment)
+ return 1;
+ else
+ return 0;
}
static int channels_average_error_sort(const void *a, const void *b)
{
- const MovieTrackingDopesheetChannel *channel_a = a;
- const MovieTrackingDopesheetChannel *channel_b = b;
+ const MovieTrackingDopesheetChannel *channel_a = a;
+ const MovieTrackingDopesheetChannel *channel_b = b;
- if (channel_a->track->error > channel_b->track->error)
- return 1;
- else
- return 0;
+ if (channel_a->track->error > channel_b->track->error)
+ return 1;
+ else
+ return 0;
}
static int channels_alpha_inverse_sort(const void *a, const void *b)
{
- if (channels_alpha_sort(a, b))
- return 0;
- else
- return 1;
+ if (channels_alpha_sort(a, b))
+ return 0;
+ else
+ return 1;
}
static int channels_total_track_inverse_sort(const void *a, const void *b)
{
- if (channels_total_track_sort(a, b))
- return 0;
- else
- return 1;
+ if (channels_total_track_sort(a, b))
+ return 0;
+ else
+ return 1;
}
static int channels_longest_segment_inverse_sort(const void *a, const void *b)
{
- if (channels_longest_segment_sort(a, b))
- return 0;
- else
- return 1;
+ if (channels_longest_segment_sort(a, b))
+ return 0;
+ else
+ return 1;
}
static int channels_average_error_inverse_sort(const void *a, const void *b)
{
- const MovieTrackingDopesheetChannel *channel_a = a;
- const MovieTrackingDopesheetChannel *channel_b = b;
+ const MovieTrackingDopesheetChannel *channel_a = a;
+ const MovieTrackingDopesheetChannel *channel_b = b;
- if (channel_a->track->error < channel_b->track->error)
- return 1;
- else
- return 0;
+ if (channel_a->track->error < channel_b->track->error)
+ return 1;
+ else
+ return 0;
}
/* Calculate frames segments at which track is tracked continuously. */
static void tracking_dopesheet_channels_segments_calc(MovieTrackingDopesheetChannel *channel)
{
- MovieTrackingTrack *track = channel->track;
- int i, segment;
+ MovieTrackingTrack *track = channel->track;
+ int i, segment;
- channel->tot_segment = 0;
- channel->max_segment = 0;
- channel->total_frames = 0;
+ channel->tot_segment = 0;
+ channel->max_segment = 0;
+ channel->total_frames = 0;
- /* TODO(sergey): looks a bit code-duplicated, need to look into
- * logic de-duplication here.
- */
+ /* TODO(sergey): looks a bit code-duplicated, need to look into
+ * logic de-duplication here.
+ */
- /* count */
- i = 0;
- while (i < track->markersnr) {
- MovieTrackingMarker *marker = &track->markers[i];
+ /* count */
+ i = 0;
+ while (i < track->markersnr) {
+ MovieTrackingMarker *marker = &track->markers[i];
- if ((marker->flag & MARKER_DISABLED) == 0) {
- int prev_fra = marker->framenr, len = 0;
+ if ((marker->flag & MARKER_DISABLED) == 0) {
+ int prev_fra = marker->framenr, len = 0;
- i++;
- while (i < track->markersnr) {
- marker = &track->markers[i];
+ i++;
+ while (i < track->markersnr) {
+ marker = &track->markers[i];
- if (marker->framenr != prev_fra + 1)
- break;
- if (marker->flag & MARKER_DISABLED)
- break;
+ if (marker->framenr != prev_fra + 1)
+ break;
+ if (marker->flag & MARKER_DISABLED)
+ break;
- prev_fra = marker->framenr;
- len++;
- i++;
- }
+ prev_fra = marker->framenr;
+ len++;
+ i++;
+ }
- channel->tot_segment++;
- }
+ channel->tot_segment++;
+ }
- i++;
- }
+ i++;
+ }
- if (!channel->tot_segment)
- return;
+ if (!channel->tot_segment)
+ return;
- channel->segments = MEM_callocN(2 * sizeof(int) * channel->tot_segment, "tracking channel segments");
+ channel->segments = MEM_callocN(2 * sizeof(int) * channel->tot_segment,
+ "tracking channel segments");
- /* create segments */
- i = 0;
- segment = 0;
- while (i < track->markersnr) {
- MovieTrackingMarker *marker = &track->markers[i];
+ /* create segments */
+ i = 0;
+ segment = 0;
+ while (i < track->markersnr) {
+ MovieTrackingMarker *marker = &track->markers[i];
- if ((marker->flag & MARKER_DISABLED) == 0) {
- MovieTrackingMarker *start_marker = marker;
- int prev_fra = marker->framenr, len = 0;
+ if ((marker->flag & MARKER_DISABLED) == 0) {
+ MovieTrackingMarker *start_marker = marker;
+ int prev_fra = marker->framenr, len = 0;
- i++;
- while (i < track->markersnr) {
- marker = &track->markers[i];
+ i++;
+ while (i < track->markersnr) {
+ marker = &track->markers[i];
- if (marker->framenr != prev_fra + 1)
- break;
- if (marker->flag & MARKER_DISABLED)
- break;
+ if (marker->framenr != prev_fra + 1)
+ break;
+ if (marker->flag & MARKER_DISABLED)
+ break;
- prev_fra = marker->framenr;
- channel->total_frames++;
- len++;
- i++;
- }
+ prev_fra = marker->framenr;
+ channel->total_frames++;
+ len++;
+ i++;
+ }
- channel->segments[2 * segment] = start_marker->framenr;
- channel->segments[2 * segment + 1] = start_marker->framenr + len;
+ channel->segments[2 * segment] = start_marker->framenr;
+ channel->segments[2 * segment + 1] = start_marker->framenr + len;
- channel->max_segment = max_ii(channel->max_segment, len);
- segment++;
- }
+ channel->max_segment = max_ii(channel->max_segment, len);
+ segment++;
+ }
- i++;
- }
+ i++;
+ }
}
/* Create channels for tracks and calculate tracked segments for them. */
static void tracking_dopesheet_channels_calc(MovieTracking *tracking)
{
- MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
- MovieTrackingDopesheet *dopesheet = &tracking->dopesheet;
- MovieTrackingTrack *track;
- MovieTrackingReconstruction *reconstruction =
- BKE_tracking_object_get_reconstruction(tracking, object);
- ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
+ MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
+ MovieTrackingDopesheet *dopesheet = &tracking->dopesheet;
+ MovieTrackingTrack *track;
+ MovieTrackingReconstruction *reconstruction = BKE_tracking_object_get_reconstruction(tracking,
+ object);
+ ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
- bool sel_only = (dopesheet->flag & TRACKING_DOPE_SELECTED_ONLY) != 0;
- bool show_hidden = (dopesheet->flag & TRACKING_DOPE_SHOW_HIDDEN) != 0;
+ bool sel_only = (dopesheet->flag & TRACKING_DOPE_SELECTED_ONLY) != 0;
+ bool show_hidden = (dopesheet->flag & TRACKING_DOPE_SHOW_HIDDEN) != 0;
- for (track = tracksbase->first; track; track = track->next) {
- MovieTrackingDopesheetChannel *channel;
+ for (track = tracksbase->first; track; track = track->next) {
+ MovieTrackingDopesheetChannel *channel;
- if (!show_hidden && (track->flag & TRACK_HIDDEN) != 0)
- continue;
+ if (!show_hidden && (track->flag & TRACK_HIDDEN) != 0)
+ continue;
- if (sel_only && !TRACK_SELECTED(track))
- continue;
+ if (sel_only && !TRACK_SELECTED(track))
+ continue;
- channel = MEM_callocN(sizeof(MovieTrackingDopesheetChannel), "tracking dopesheet channel");
- channel->track = track;
+ channel = MEM_callocN(sizeof(MovieTrackingDopesheetChannel), "tracking dopesheet channel");
+ channel->track = track;
- if (reconstruction->flag & TRACKING_RECONSTRUCTED) {
- BLI_snprintf(channel->name, sizeof(channel->name), "%s (%.4f)", track->name, track->error);
- }
- else {
- BLI_strncpy(channel->name, track->name, sizeof(channel->name));
- }
+ if (reconstruction->flag & TRACKING_RECONSTRUCTED) {
+ BLI_snprintf(channel->name, sizeof(channel->name), "%s (%.4f)", track->name, track->error);
+ }
+ else {
+ BLI_strncpy(channel->name, track->name, sizeof(channel->name));
+ }
- tracking_dopesheet_channels_segments_calc(channel);
+ tracking_dopesheet_channels_segments_calc(channel);
- BLI_addtail(&dopesheet->channels, channel);
- dopesheet->tot_channel++;
- }
+ BLI_addtail(&dopesheet->channels, channel);
+ dopesheet->tot_channel++;
+ }
}
/* Sot dopesheet channels using given method (name, average error, total coverage,
* longest tracked segment) and could also inverse the list if it's enabled.
*/
-static void tracking_dopesheet_channels_sort(MovieTracking *tracking, int sort_method, bool inverse)
-{
- MovieTrackingDopesheet *dopesheet = &tracking->dopesheet;
-
- if (inverse) {
- if (sort_method == TRACKING_DOPE_SORT_NAME) {
- BLI_listbase_sort(&dopesheet->channels, channels_alpha_inverse_sort);
- }
- else if (sort_method == TRACKING_DOPE_SORT_LONGEST) {
- BLI_listbase_sort(&dopesheet->channels, channels_longest_segment_inverse_sort);
- }
- else if (sort_method == TRACKING_DOPE_SORT_TOTAL) {
- BLI_listbase_sort(&dopesheet->channels, channels_total_track_inverse_sort);
- }
- else if (sort_method == TRACKING_DOPE_SORT_AVERAGE_ERROR) {
- BLI_listbase_sort(&dopesheet->channels, channels_average_error_inverse_sort);
- }
- }
- else {
- if (sort_method == TRACKING_DOPE_SORT_NAME) {
- BLI_listbase_sort(&dopesheet->channels, channels_alpha_sort);
- }
- else if (sort_method == TRACKING_DOPE_SORT_LONGEST) {
- BLI_listbase_sort(&dopesheet->channels, channels_longest_segment_sort);
- }
- else if (sort_method == TRACKING_DOPE_SORT_TOTAL) {
- BLI_listbase_sort(&dopesheet->channels, channels_total_track_sort);
- }
- else if (sort_method == TRACKING_DOPE_SORT_AVERAGE_ERROR) {
- BLI_listbase_sort(&dopesheet->channels, channels_average_error_sort);
- }
- }
+static void tracking_dopesheet_channels_sort(MovieTracking *tracking,
+ int sort_method,
+ bool inverse)
+{
+ MovieTrackingDopesheet *dopesheet = &tracking->dopesheet;
+
+ if (inverse) {
+ if (sort_method == TRACKING_DOPE_SORT_NAME) {
+ BLI_listbase_sort(&dopesheet->channels, channels_alpha_inverse_sort);
+ }
+ else if (sort_method == TRACKING_DOPE_SORT_LONGEST) {
+ BLI_listbase_sort(&dopesheet->channels, channels_longest_segment_inverse_sort);
+ }
+ else if (sort_method == TRACKING_DOPE_SORT_TOTAL) {
+ BLI_listbase_sort(&dopesheet->channels, channels_total_track_inverse_sort);
+ }
+ else if (sort_method == TRACKING_DOPE_SORT_AVERAGE_ERROR) {
+ BLI_listbase_sort(&dopesheet->channels, channels_average_error_inverse_sort);
+ }
+ }
+ else {
+ if (sort_method == TRACKING_DOPE_SORT_NAME) {
+ BLI_listbase_sort(&dopesheet->channels, channels_alpha_sort);
+ }
+ else if (sort_method == TRACKING_DOPE_SORT_LONGEST) {
+ BLI_listbase_sort(&dopesheet->channels, channels_longest_segment_sort);
+ }
+ else if (sort_method == TRACKING_DOPE_SORT_TOTAL) {
+ BLI_listbase_sort(&dopesheet->channels, channels_total_track_sort);
+ }
+ else if (sort_method == TRACKING_DOPE_SORT_AVERAGE_ERROR) {
+ BLI_listbase_sort(&dopesheet->channels, channels_average_error_sort);
+ }
+ }
}
static int coverage_from_count(int count)
{
- /* Values are actually arbitrary here, probably need to be tweaked. */
- if (count < 8)
- return TRACKING_COVERAGE_BAD;
- else if (count < 16)
- return TRACKING_COVERAGE_ACCEPTABLE;
- return TRACKING_COVERAGE_OK;
+ /* Values are actually arbitrary here, probably need to be tweaked. */
+ if (count < 8)
+ return TRACKING_COVERAGE_BAD;
+ else if (count < 16)
+ return TRACKING_COVERAGE_ACCEPTABLE;
+ return TRACKING_COVERAGE_OK;
}
/* Calculate coverage of frames with tracks, this information
@@ -2801,72 +2907,73 @@ static int coverage_from_count(int count)
*/
static void tracking_dopesheet_calc_coverage(MovieTracking *tracking)
{
- MovieTrackingDopesheet *dopesheet = &tracking->dopesheet;
- MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
- ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
- MovieTrackingTrack *track;
- int frames, start_frame = INT_MAX, end_frame = -INT_MAX;
- int *per_frame_counter;
- int prev_coverage, last_segment_frame;
+ MovieTrackingDopesheet *dopesheet = &tracking->dopesheet;
+ MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
+ ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
+ MovieTrackingTrack *track;
+ int frames, start_frame = INT_MAX, end_frame = -INT_MAX;
+ int *per_frame_counter;
+ int prev_coverage, last_segment_frame;
- /* find frame boundaries */
- for (track = tracksbase->first; track; track = track->next) {
- start_frame = min_ii(start_frame, track->markers[0].framenr);
- end_frame = max_ii(end_frame, track->markers[track->markersnr - 1].framenr);
- }
+ /* find frame boundaries */
+ for (track = tracksbase->first; track; track = track->next) {
+ start_frame = min_ii(start_frame, track->markers[0].framenr);
+ end_frame = max_ii(end_frame, track->markers[track->markersnr - 1].framenr);
+ }
- frames = end_frame - start_frame + 1;
+ frames = end_frame - start_frame + 1;
- /* this is a per-frame counter of markers (how many markers belongs to the same frame) */
- per_frame_counter = MEM_callocN(sizeof(int) * frames, "per frame track counter");
+ /* this is a per-frame counter of markers (how many markers belongs to the same frame) */
+ per_frame_counter = MEM_callocN(sizeof(int) * frames, "per frame track counter");
- /* find per-frame markers count */
- for (track = tracksbase->first; track; track = track->next) {
- for (int i = 0; i < track->markersnr; i++) {
- MovieTrackingMarker *marker = &track->markers[i];
+ /* find per-frame markers count */
+ for (track = tracksbase->first; track; track = track->next) {
+ for (int i = 0; i < track->markersnr; i++) {
+ MovieTrackingMarker *marker = &track->markers[i];
- /* TODO: perhaps we need to add check for non-single-frame track here */
- if ((marker->flag & MARKER_DISABLED) == 0)
- per_frame_counter[marker->framenr - start_frame]++;
- }
- }
+ /* TODO: perhaps we need to add check for non-single-frame track here */
+ if ((marker->flag & MARKER_DISABLED) == 0)
+ per_frame_counter[marker->framenr - start_frame]++;
+ }
+ }
- /* convert markers count to coverage and detect segments with the same coverage */
- prev_coverage = coverage_from_count(per_frame_counter[0]);
- last_segment_frame = start_frame;
+ /* convert markers count to coverage and detect segments with the same coverage */
+ prev_coverage = coverage_from_count(per_frame_counter[0]);
+ last_segment_frame = start_frame;
- /* means only disabled tracks in the beginning, could be ignored */
- if (!per_frame_counter[0])
- prev_coverage = TRACKING_COVERAGE_OK;
+ /* means only disabled tracks in the beginning, could be ignored */
+ if (!per_frame_counter[0])
+ prev_coverage = TRACKING_COVERAGE_OK;
- for (int i = 1; i < frames; i++) {
- int coverage = coverage_from_count(per_frame_counter[i]);
+ for (int i = 1; i < frames; i++) {
+ int coverage = coverage_from_count(per_frame_counter[i]);
- /* means only disabled tracks in the end, could be ignored */
- if (i == frames - 1 && !per_frame_counter[i])
- coverage = TRACKING_COVERAGE_OK;
+ /* means only disabled tracks in the end, could be ignored */
+ if (i == frames - 1 && !per_frame_counter[i])
+ coverage = TRACKING_COVERAGE_OK;
- if (coverage != prev_coverage || i == frames - 1) {
- MovieTrackingDopesheetCoverageSegment *coverage_segment;
- int end_segment_frame = i - 1 + start_frame;
+ if (coverage != prev_coverage || i == frames - 1) {
+ MovieTrackingDopesheetCoverageSegment *coverage_segment;
+ int end_segment_frame = i - 1 + start_frame;
- if (end_segment_frame == last_segment_frame)
- end_segment_frame++;
+ if (end_segment_frame == last_segment_frame)
+ end_segment_frame++;
- coverage_segment = MEM_callocN(sizeof(MovieTrackingDopesheetCoverageSegment), "tracking coverage segment");
- coverage_segment->coverage = prev_coverage;
- coverage_segment->start_frame = last_segment_frame;
- coverage_segment->end_frame = end_segment_frame;
+ coverage_segment = MEM_callocN(sizeof(MovieTrackingDopesheetCoverageSegment),
+ "tracking coverage segment");
+ coverage_segment->coverage = prev_coverage;
+ coverage_segment->start_frame = last_segment_frame;
+ coverage_segment->end_frame = end_segment_frame;
- BLI_addtail(&dopesheet->coverage_segments, coverage_segment);
+ BLI_addtail(&dopesheet->coverage_segments, coverage_segment);
- last_segment_frame = end_segment_frame;
- }
+ last_segment_frame = end_segment_frame;
+ }
- prev_coverage = coverage;
- }
+ prev_coverage = coverage;
+ }
- MEM_freeN(per_frame_counter);
+ MEM_freeN(per_frame_counter);
}
/* Tag dopesheet for update, actual update will happen later
@@ -2874,182 +2981,163 @@ static void tracking_dopesheet_calc_coverage(MovieTracking *tracking)
*/
void BKE_tracking_dopesheet_tag_update(MovieTracking *tracking)
{
- MovieTrackingDopesheet *dopesheet = &tracking->dopesheet;
+ MovieTrackingDopesheet *dopesheet = &tracking->dopesheet;
- dopesheet->ok = false;
+ dopesheet->ok = false;
}
/* Do dopesheet update, if update is not needed nothing will happen. */
void BKE_tracking_dopesheet_update(MovieTracking *tracking)
{
- MovieTrackingDopesheet *dopesheet = &tracking->dopesheet;
+ MovieTrackingDopesheet *dopesheet = &tracking->dopesheet;
- short sort_method = dopesheet->sort_method;
- bool inverse = (dopesheet->flag & TRACKING_DOPE_SORT_INVERSE) != 0;
+ short sort_method = dopesheet->sort_method;
+ bool inverse = (dopesheet->flag & TRACKING_DOPE_SORT_INVERSE) != 0;
- if (dopesheet->ok)
- return;
+ if (dopesheet->ok)
+ return;
- tracking_dopesheet_free(dopesheet);
+ tracking_dopesheet_free(dopesheet);
- /* channels */
- tracking_dopesheet_channels_calc(tracking);
- tracking_dopesheet_channels_sort(tracking, sort_method, inverse);
+ /* channels */
+ tracking_dopesheet_channels_calc(tracking);
+ tracking_dopesheet_channels_sort(tracking, sort_method, inverse);
- /* frame coverage */
- tracking_dopesheet_calc_coverage(tracking);
+ /* frame coverage */
+ tracking_dopesheet_calc_coverage(tracking);
- dopesheet->ok = true;
+ dopesheet->ok = true;
}
/* NOTE: Returns NULL if the track comes from camera object, */
-MovieTrackingObject *BKE_tracking_find_object_for_track(
- const MovieTracking *tracking,
- const MovieTrackingTrack *track)
-{
- const ListBase *tracksbase = &tracking->tracks;
- if (BLI_findindex(tracksbase, track) != -1) {
- return NULL;
- }
- MovieTrackingObject *object = tracking->objects.first;
- while (object != NULL) {
- if (BLI_findindex(&object->tracks, track) != -1) {
- return object;
- }
- object = object->next;
- }
- return NULL;
-}
-
-ListBase *BKE_tracking_find_tracks_list_for_track(
- MovieTracking *tracking,
- const MovieTrackingTrack *track)
-{
- MovieTrackingObject *object = BKE_tracking_find_object_for_track(tracking,
- track);
- if (object != NULL) {
- return &object->tracks;
- }
- return &tracking->tracks;
+MovieTrackingObject *BKE_tracking_find_object_for_track(const MovieTracking *tracking,
+ const MovieTrackingTrack *track)
+{
+ const ListBase *tracksbase = &tracking->tracks;
+ if (BLI_findindex(tracksbase, track) != -1) {
+ return NULL;
+ }
+ MovieTrackingObject *object = tracking->objects.first;
+ while (object != NULL) {
+ if (BLI_findindex(&object->tracks, track) != -1) {
+ return object;
+ }
+ object = object->next;
+ }
+ return NULL;
+}
+
+ListBase *BKE_tracking_find_tracks_list_for_track(MovieTracking *tracking,
+ const MovieTrackingTrack *track)
+{
+ MovieTrackingObject *object = BKE_tracking_find_object_for_track(tracking, track);
+ if (object != NULL) {
+ return &object->tracks;
+ }
+ return &tracking->tracks;
}
/* NOTE: Returns NULL if the track comes from camera object, */
MovieTrackingObject *BKE_tracking_find_object_for_plane_track(
- const MovieTracking *tracking,
- const MovieTrackingPlaneTrack *plane_track)
-{
- const ListBase *plane_tracks_base = &tracking->plane_tracks;
- if (BLI_findindex(plane_tracks_base, plane_track) != -1) {
- return NULL;
- }
- MovieTrackingObject *object = tracking->objects.first;
- while (object != NULL) {
- if (BLI_findindex(&object->plane_tracks, plane_track) != -1) {
- return object;
- }
- object = object->next;
- }
- return NULL;
-}
-
-ListBase *BKE_tracking_find_tracks_list_for_plane_track(
- MovieTracking *tracking,
- const MovieTrackingPlaneTrack *plane_track)
-{
- MovieTrackingObject *object =
- BKE_tracking_find_object_for_plane_track(tracking, plane_track);
- if (object != NULL) {
- return &object->plane_tracks;
- }
- return &tracking->plane_tracks;
-}
-
-void BKE_tracking_get_rna_path_for_track(
- const struct MovieTracking *tracking,
- const struct MovieTrackingTrack *track,
- char *rna_path,
- size_t rna_path_len)
-{
- MovieTrackingObject *object =
- BKE_tracking_find_object_for_track(tracking, track);
- char track_name_esc[MAX_NAME * 2];
- BLI_strescape(track_name_esc, track->name, sizeof(track_name_esc));
- if (object == NULL) {
- BLI_snprintf(rna_path, rna_path_len,
- "tracking.tracks[\"%s\"]",
- track_name_esc);
- }
- else {
- char object_name_esc[MAX_NAME * 2];
- BLI_strescape(object_name_esc, object->name, sizeof(object_name_esc));
- BLI_snprintf(rna_path, rna_path_len,
- "tracking.objects[\"%s\"].tracks[\"%s\"]",
- object_name_esc,
- track_name_esc);
- }
-}
-
-void BKE_tracking_get_rna_path_prefix_for_track(
- const struct MovieTracking *tracking,
- const struct MovieTrackingTrack *track,
- char *rna_path,
- size_t rna_path_len)
-{
- MovieTrackingObject *object =
- BKE_tracking_find_object_for_track(tracking, track);
- if (object == NULL) {
- BLI_strncpy(rna_path, "tracking.tracks", rna_path_len);
- }
- else {
- char object_name_esc[MAX_NAME * 2];
- BLI_strescape(object_name_esc, object->name, sizeof(object_name_esc));
- BLI_snprintf(rna_path, rna_path_len,
- "tracking.objects[\"%s\"]",
- object_name_esc);
- }
-}
-
-void BKE_tracking_get_rna_path_for_plane_track(
- const struct MovieTracking *tracking,
- const struct MovieTrackingPlaneTrack *plane_track,
- char *rna_path,
- size_t rna_path_len)
-{
- MovieTrackingObject *object =
- BKE_tracking_find_object_for_plane_track(tracking, plane_track);
- char track_name_esc[MAX_NAME * 2];
- BLI_strescape(track_name_esc, plane_track->name, sizeof(track_name_esc));
- if (object == NULL) {
- BLI_snprintf(rna_path, rna_path_len,
- "tracking.plane_tracks[\"%s\"]",
- track_name_esc);
- }
- else {
- char object_name_esc[MAX_NAME * 2];
- BLI_strescape(object_name_esc, object->name, sizeof(object_name_esc));
- BLI_snprintf(rna_path, rna_path_len,
- "tracking.objects[\"%s\"].plane_tracks[\"%s\"]",
- object_name_esc,
- track_name_esc);
- }
+ const MovieTracking *tracking, const MovieTrackingPlaneTrack *plane_track)
+{
+ const ListBase *plane_tracks_base = &tracking->plane_tracks;
+ if (BLI_findindex(plane_tracks_base, plane_track) != -1) {
+ return NULL;
+ }
+ MovieTrackingObject *object = tracking->objects.first;
+ while (object != NULL) {
+ if (BLI_findindex(&object->plane_tracks, plane_track) != -1) {
+ return object;
+ }
+ object = object->next;
+ }
+ return NULL;
+}
+
+ListBase *BKE_tracking_find_tracks_list_for_plane_track(MovieTracking *tracking,
+ const MovieTrackingPlaneTrack *plane_track)
+{
+ MovieTrackingObject *object = BKE_tracking_find_object_for_plane_track(tracking, plane_track);
+ if (object != NULL) {
+ return &object->plane_tracks;
+ }
+ return &tracking->plane_tracks;
+}
+
+void BKE_tracking_get_rna_path_for_track(const struct MovieTracking *tracking,
+ const struct MovieTrackingTrack *track,
+ char *rna_path,
+ size_t rna_path_len)
+{
+ MovieTrackingObject *object = BKE_tracking_find_object_for_track(tracking, track);
+ char track_name_esc[MAX_NAME * 2];
+ BLI_strescape(track_name_esc, track->name, sizeof(track_name_esc));
+ if (object == NULL) {
+ BLI_snprintf(rna_path, rna_path_len, "tracking.tracks[\"%s\"]", track_name_esc);
+ }
+ else {
+ char object_name_esc[MAX_NAME * 2];
+ BLI_strescape(object_name_esc, object->name, sizeof(object_name_esc));
+ BLI_snprintf(rna_path,
+ rna_path_len,
+ "tracking.objects[\"%s\"].tracks[\"%s\"]",
+ object_name_esc,
+ track_name_esc);
+ }
+}
+
+void BKE_tracking_get_rna_path_prefix_for_track(const struct MovieTracking *tracking,
+ const struct MovieTrackingTrack *track,
+ char *rna_path,
+ size_t rna_path_len)
+{
+ MovieTrackingObject *object = BKE_tracking_find_object_for_track(tracking, track);
+ if (object == NULL) {
+ BLI_strncpy(rna_path, "tracking.tracks", rna_path_len);
+ }
+ else {
+ char object_name_esc[MAX_NAME * 2];
+ BLI_strescape(object_name_esc, object->name, sizeof(object_name_esc));
+ BLI_snprintf(rna_path, rna_path_len, "tracking.objects[\"%s\"]", object_name_esc);
+ }
+}
+
+void BKE_tracking_get_rna_path_for_plane_track(const struct MovieTracking *tracking,
+ const struct MovieTrackingPlaneTrack *plane_track,
+ char *rna_path,
+ size_t rna_path_len)
+{
+ MovieTrackingObject *object = BKE_tracking_find_object_for_plane_track(tracking, plane_track);
+ char track_name_esc[MAX_NAME * 2];
+ BLI_strescape(track_name_esc, plane_track->name, sizeof(track_name_esc));
+ if (object == NULL) {
+ BLI_snprintf(rna_path, rna_path_len, "tracking.plane_tracks[\"%s\"]", track_name_esc);
+ }
+ else {
+ char object_name_esc[MAX_NAME * 2];
+ BLI_strescape(object_name_esc, object->name, sizeof(object_name_esc));
+ BLI_snprintf(rna_path,
+ rna_path_len,
+ "tracking.objects[\"%s\"].plane_tracks[\"%s\"]",
+ object_name_esc,
+ track_name_esc);
+ }
}
void BKE_tracking_get_rna_path_prefix_for_plane_track(
- const struct MovieTracking *tracking,
- const struct MovieTrackingPlaneTrack *plane_track,
- char *rna_path,
- size_t rna_path_len)
-{
- MovieTrackingObject *object =
- BKE_tracking_find_object_for_plane_track(tracking, plane_track);
- if (object == NULL) {
- BLI_strncpy(rna_path, "tracking.plane_tracks", rna_path_len);
- }
- else {
- char object_name_esc[MAX_NAME * 2];
- BLI_strescape(object_name_esc, object->name, sizeof(object_name_esc));
- BLI_snprintf(rna_path, rna_path_len,
- "tracking.objects[\"%s\"].plane_tracks",
- object_name_esc);
- }
+ const struct MovieTracking *tracking,
+ const struct MovieTrackingPlaneTrack *plane_track,
+ char *rna_path,
+ size_t rna_path_len)
+{
+ MovieTrackingObject *object = BKE_tracking_find_object_for_plane_track(tracking, plane_track);
+ if (object == NULL) {
+ BLI_strncpy(rna_path, "tracking.plane_tracks", rna_path_len);
+ }
+ else {
+ char object_name_esc[MAX_NAME * 2];
+ BLI_strescape(object_name_esc, object->name, sizeof(object_name_esc));
+ BLI_snprintf(rna_path, rna_path_len, "tracking.objects[\"%s\"].plane_tracks", object_name_esc);
+ }
}
diff --git a/source/blender/blenkernel/intern/tracking_auto.c b/source/blender/blenkernel/intern/tracking_auto.c
index bddb5315781..e93a5780b81 100644
--- a/source/blender/blenkernel/intern/tracking_auto.c
+++ b/source/blender/blenkernel/intern/tracking_auto.c
@@ -27,7 +27,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_movieclip_types.h"
-#include "DNA_object_types.h" /* SELECT */
+#include "DNA_object_types.h" /* SELECT */
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
@@ -42,54 +42,54 @@
#include "tracking_private.h"
typedef struct AutoTrackOptions {
- int clip_index; /** Index of the clip this track belogs to. */
- int track_index; /* Index of the track in AutoTrack tracks structure. */
- MovieTrackingTrack *track; /* Pointer to an original track/ */
- libmv_TrackRegionOptions track_region_options; /* Options for the region
- tracker. */
- bool use_keyframe_match; /* Keyframe pattern matching. */
-
- /* TODO(sergey): A bit awkward to keep it in here, only used to
- * place a disabled marker once the tracking fails,
- * Wither find a more clear way to do it or call it track context
- * or state, not options.
- */
- bool is_failed;
- int failed_frame;
+ int clip_index; /** Index of the clip this track belogs to. */
+ int track_index; /* Index of the track in AutoTrack tracks structure. */
+ MovieTrackingTrack *track; /* Pointer to an original track/ */
+ libmv_TrackRegionOptions track_region_options; /* Options for the region
+ tracker. */
+ bool use_keyframe_match; /* Keyframe pattern matching. */
+
+ /* TODO(sergey): A bit awkward to keep it in here, only used to
+ * place a disabled marker once the tracking fails,
+ * Wither find a more clear way to do it or call it track context
+ * or state, not options.
+ */
+ bool is_failed;
+ int failed_frame;
} AutoTrackOptions;
typedef struct AutoTrackContext {
- MovieClip *clips[MAX_ACCESSOR_CLIP];
- int num_clips;
+ MovieClip *clips[MAX_ACCESSOR_CLIP];
+ int num_clips;
- MovieClipUser user;
- int frame_width, frame_height;
+ MovieClipUser user;
+ int frame_width, frame_height;
- struct libmv_AutoTrack *autotrack;
- TrackingImageAccessor *image_accessor;
+ struct libmv_AutoTrack *autotrack;
+ TrackingImageAccessor *image_accessor;
- int num_tracks; /* Number of tracks being tracked. */
- AutoTrackOptions *options; /* Per-tracking track options. */
+ int num_tracks; /* Number of tracks being tracked. */
+ AutoTrackOptions *options; /* Per-tracking track options. */
- /* Array of all tracks, indexed by track_index. */
- MovieTrackingTrack **tracks;
+ /* Array of all tracks, indexed by track_index. */
+ MovieTrackingTrack **tracks;
- bool backwards;
- bool sequence;
- int first_frame;
- int sync_frame;
- bool first_sync;
- SpinLock spin_lock;
+ bool backwards;
+ bool sequence;
+ int first_frame;
+ int sync_frame;
+ bool first_sync;
+ SpinLock spin_lock;
- bool step_ok;
+ bool step_ok;
} AutoTrackContext;
static void normalized_to_libmv_frame(const float normalized[2],
const int frame_dimensions[2],
float result[2])
{
- result[0] = normalized[0] * frame_dimensions[0] - 0.5f;
- result[1] = normalized[1] * frame_dimensions[1] - 0.5f;
+ result[0] = normalized[0] * frame_dimensions[0] - 0.5f;
+ result[1] = normalized[1] * frame_dimensions[1] - 0.5f;
}
static void normalized_relative_to_libmv_frame(const float normalized[2],
@@ -97,16 +97,16 @@ static void normalized_relative_to_libmv_frame(const float normalized[2],
const int frame_dimensions[2],
float result[2])
{
- result[0] = (normalized[0] + origin[0]) * frame_dimensions[0] - 0.5f;
- result[1] = (normalized[1] + origin[1]) * frame_dimensions[1] - 0.5f;
+ result[0] = (normalized[0] + origin[0]) * frame_dimensions[0] - 0.5f;
+ result[1] = (normalized[1] + origin[1]) * frame_dimensions[1] - 0.5f;
}
static void libmv_frame_to_normalized(const float frame_coord[2],
const int frame_dimensions[2],
float result[2])
{
- result[0] = (frame_coord[0] + 0.5f) / frame_dimensions[0];
- result[1] = (frame_coord[1] + 0.5f) / frame_dimensions[1];
+ result[0] = (frame_coord[0] + 0.5f) / frame_dimensions[0];
+ result[1] = (frame_coord[1] + 0.5f) / frame_dimensions[1];
}
static void libmv_frame_to_normalized_relative(const float frame_coord[2],
@@ -114,8 +114,8 @@ static void libmv_frame_to_normalized_relative(const float frame_coord[2],
const int frame_dimensions[2],
float result[2])
{
- result[0] = (frame_coord[0] - origin[0]) / frame_dimensions[0];
- result[1] = (frame_coord[1] - origin[1]) / frame_dimensions[1];
+ result[0] = (frame_coord[0] - origin[0]) / frame_dimensions[0];
+ result[1] = (frame_coord[1] - origin[1]) / frame_dimensions[1];
}
static void dna_marker_to_libmv_marker(/*const*/ MovieTrackingTrack *track,
@@ -127,67 +127,55 @@ static void dna_marker_to_libmv_marker(/*const*/ MovieTrackingTrack *track,
bool backwards,
libmv_Marker *libmv_marker)
{
- const int frame_dimensions[2] = {frame_width, frame_height};
- int i;
- libmv_marker->clip = clip;
- libmv_marker->frame = marker->framenr;
- libmv_marker->track = track_index;
-
- normalized_to_libmv_frame(marker->pos,
- frame_dimensions,
- libmv_marker->center);
- for (i = 0; i < 4; ++i) {
- normalized_relative_to_libmv_frame(marker->pattern_corners[i],
- marker->pos,
- frame_dimensions,
- libmv_marker->patch[i]);
- }
-
- normalized_relative_to_libmv_frame(marker->search_min,
- marker->pos,
- frame_dimensions,
- libmv_marker->search_region_min);
-
- normalized_relative_to_libmv_frame(marker->search_max,
- marker->pos,
- frame_dimensions,
- libmv_marker->search_region_max);
-
- /* TODO(sergey): All the markers does have 1.0 weight. */
- libmv_marker->weight = 1.0f;
-
- if (marker->flag & MARKER_TRACKED) {
- libmv_marker->source = LIBMV_MARKER_SOURCE_TRACKED;
- }
- else {
- libmv_marker->source = LIBMV_MARKER_SOURCE_MANUAL;
- }
- libmv_marker->status = LIBMV_MARKER_STATUS_UNKNOWN;
- libmv_marker->model_type = LIBMV_MARKER_MODEL_TYPE_POINT;
- libmv_marker->model_id = 0;
-
- /* TODO(sergey): We currently don't support reference marker from
- * different clip.
- */
- libmv_marker->reference_clip = clip;
-
- if (track->pattern_match == TRACK_MATCH_KEYFRAME) {
- MovieTrackingMarker *keyframe_marker =
- tracking_get_keyframed_marker(track,
- marker->framenr,
- backwards);
- libmv_marker->reference_frame = keyframe_marker->framenr;
- }
- else {
- libmv_marker->reference_frame = backwards ?
- marker->framenr - 1 :
- marker->framenr;
- }
-
- libmv_marker->disabled_channels =
- ((track->flag & TRACK_DISABLE_RED) ? LIBMV_MARKER_CHANNEL_R : 0) |
- ((track->flag & TRACK_DISABLE_GREEN) ? LIBMV_MARKER_CHANNEL_G : 0) |
- ((track->flag & TRACK_DISABLE_BLUE) ? LIBMV_MARKER_CHANNEL_B : 0);
+ const int frame_dimensions[2] = {frame_width, frame_height};
+ int i;
+ libmv_marker->clip = clip;
+ libmv_marker->frame = marker->framenr;
+ libmv_marker->track = track_index;
+
+ normalized_to_libmv_frame(marker->pos, frame_dimensions, libmv_marker->center);
+ for (i = 0; i < 4; ++i) {
+ normalized_relative_to_libmv_frame(
+ marker->pattern_corners[i], marker->pos, frame_dimensions, libmv_marker->patch[i]);
+ }
+
+ normalized_relative_to_libmv_frame(
+ marker->search_min, marker->pos, frame_dimensions, libmv_marker->search_region_min);
+
+ normalized_relative_to_libmv_frame(
+ marker->search_max, marker->pos, frame_dimensions, libmv_marker->search_region_max);
+
+ /* TODO(sergey): All the markers does have 1.0 weight. */
+ libmv_marker->weight = 1.0f;
+
+ if (marker->flag & MARKER_TRACKED) {
+ libmv_marker->source = LIBMV_MARKER_SOURCE_TRACKED;
+ }
+ else {
+ libmv_marker->source = LIBMV_MARKER_SOURCE_MANUAL;
+ }
+ libmv_marker->status = LIBMV_MARKER_STATUS_UNKNOWN;
+ libmv_marker->model_type = LIBMV_MARKER_MODEL_TYPE_POINT;
+ libmv_marker->model_id = 0;
+
+ /* TODO(sergey): We currently don't support reference marker from
+ * different clip.
+ */
+ libmv_marker->reference_clip = clip;
+
+ if (track->pattern_match == TRACK_MATCH_KEYFRAME) {
+ MovieTrackingMarker *keyframe_marker = tracking_get_keyframed_marker(
+ track, marker->framenr, backwards);
+ libmv_marker->reference_frame = keyframe_marker->framenr;
+ }
+ else {
+ libmv_marker->reference_frame = backwards ? marker->framenr - 1 : marker->framenr;
+ }
+
+ libmv_marker->disabled_channels =
+ ((track->flag & TRACK_DISABLE_RED) ? LIBMV_MARKER_CHANNEL_R : 0) |
+ ((track->flag & TRACK_DISABLE_GREEN) ? LIBMV_MARKER_CHANNEL_G : 0) |
+ ((track->flag & TRACK_DISABLE_BLUE) ? LIBMV_MARKER_CHANNEL_B : 0);
}
static void libmv_marker_to_dna_marker(libmv_Marker *libmv_marker,
@@ -195,51 +183,43 @@ static void libmv_marker_to_dna_marker(libmv_Marker *libmv_marker,
int frame_height,
MovieTrackingMarker *marker)
{
- const int frame_dimensions[2] = {frame_width, frame_height};
- int i;
- marker->framenr = libmv_marker->frame;
-
- libmv_frame_to_normalized(libmv_marker->center,
- frame_dimensions,
- marker->pos);
- for (i = 0; i < 4; ++i) {
- libmv_frame_to_normalized_relative(libmv_marker->patch[i],
- libmv_marker->center,
- frame_dimensions,
- marker->pattern_corners[i]);
- }
-
- libmv_frame_to_normalized_relative(libmv_marker->search_region_min,
- libmv_marker->center,
- frame_dimensions,
- marker->search_min);
-
- libmv_frame_to_normalized_relative(libmv_marker->search_region_max,
- libmv_marker->center,
- frame_dimensions,
- marker->search_max);
-
- marker->flag = 0;
- if (libmv_marker->source == LIBMV_MARKER_SOURCE_TRACKED) {
- marker->flag |= MARKER_TRACKED;
- }
- else {
- marker->flag &= ~MARKER_TRACKED;
- }
+ const int frame_dimensions[2] = {frame_width, frame_height};
+ int i;
+ marker->framenr = libmv_marker->frame;
+
+ libmv_frame_to_normalized(libmv_marker->center, frame_dimensions, marker->pos);
+ for (i = 0; i < 4; ++i) {
+ libmv_frame_to_normalized_relative(libmv_marker->patch[i],
+ libmv_marker->center,
+ frame_dimensions,
+ marker->pattern_corners[i]);
+ }
+
+ libmv_frame_to_normalized_relative(
+ libmv_marker->search_region_min, libmv_marker->center, frame_dimensions, marker->search_min);
+
+ libmv_frame_to_normalized_relative(
+ libmv_marker->search_region_max, libmv_marker->center, frame_dimensions, marker->search_max);
+
+ marker->flag = 0;
+ if (libmv_marker->source == LIBMV_MARKER_SOURCE_TRACKED) {
+ marker->flag |= MARKER_TRACKED;
+ }
+ else {
+ marker->flag &= ~MARKER_TRACKED;
+ }
}
static bool check_track_trackable(const MovieClip *clip,
MovieTrackingTrack *track,
const MovieClipUser *user)
{
- if (TRACK_SELECTED(track) &&
- (track->flag & (TRACK_LOCKED | TRACK_HIDDEN)) == 0)
- {
- int frame = BKE_movieclip_remap_scene_to_clip_frame(clip, user->framenr);
- const MovieTrackingMarker *marker = BKE_tracking_marker_get(track, frame);
- return (marker->flag & MARKER_DISABLED) == 0;
- }
- return false;
+ if (TRACK_SELECTED(track) && (track->flag & (TRACK_LOCKED | TRACK_HIDDEN)) == 0) {
+ int frame = BKE_movieclip_remap_scene_to_clip_frame(clip, user->framenr);
+ const MovieTrackingMarker *marker = BKE_tracking_marker_get(track, frame);
+ return (marker->flag & MARKER_DISABLED) == 0;
+ }
+ return false;
}
/* Returns false if marker crossed margin area from frame bounds. */
@@ -248,29 +228,28 @@ static bool tracking_check_marker_margin(libmv_Marker *libmv_marker,
int frame_width,
int frame_height)
{
- float patch_min[2], patch_max[2];
- float margin_left, margin_top, margin_right, margin_bottom;
-
- INIT_MINMAX2(patch_min, patch_max);
- minmax_v2v2_v2(patch_min, patch_max, libmv_marker->patch[0]);
- minmax_v2v2_v2(patch_min, patch_max, libmv_marker->patch[1]);
- minmax_v2v2_v2(patch_min, patch_max, libmv_marker->patch[2]);
- minmax_v2v2_v2(patch_min, patch_max, libmv_marker->patch[3]);
-
- margin_left = max_ff(libmv_marker->center[0] - patch_min[0], margin);
- margin_top = max_ff(patch_max[1] - libmv_marker->center[1], margin);
- margin_right = max_ff(patch_max[0] - libmv_marker->center[0], margin);
- margin_bottom = max_ff(libmv_marker->center[1] - patch_min[1], margin);
-
- if (libmv_marker->center[0] < margin_left ||
- libmv_marker->center[0] > frame_width - margin_right ||
- libmv_marker->center[1] < margin_bottom ||
- libmv_marker->center[1] > frame_height - margin_top)
- {
- return false;
- }
-
- return true;
+ float patch_min[2], patch_max[2];
+ float margin_left, margin_top, margin_right, margin_bottom;
+
+ INIT_MINMAX2(patch_min, patch_max);
+ minmax_v2v2_v2(patch_min, patch_max, libmv_marker->patch[0]);
+ minmax_v2v2_v2(patch_min, patch_max, libmv_marker->patch[1]);
+ minmax_v2v2_v2(patch_min, patch_max, libmv_marker->patch[2]);
+ minmax_v2v2_v2(patch_min, patch_max, libmv_marker->patch[3]);
+
+ margin_left = max_ff(libmv_marker->center[0] - patch_min[0], margin);
+ margin_top = max_ff(patch_max[1] - libmv_marker->center[1], margin);
+ margin_right = max_ff(patch_max[0] - libmv_marker->center[0], margin);
+ margin_bottom = max_ff(libmv_marker->center[1] - patch_min[1], margin);
+
+ if (libmv_marker->center[0] < margin_left ||
+ libmv_marker->center[0] > frame_width - margin_right ||
+ libmv_marker->center[1] < margin_bottom ||
+ libmv_marker->center[1] > frame_height - margin_top) {
+ return false;
+ }
+
+ return true;
}
/* Provide Libmv side of auto track all information about given tracks. */
@@ -280,56 +259,47 @@ static void fill_autotrack_tracks(const int frame_width,
const bool backwards,
struct libmv_AutoTrack *autotrack)
{
- /* Count number of markers to be put to a context. */
- size_t num_trackable_markers = 0;
- for (MovieTrackingTrack *track = tracksbase->first;
- track != NULL;
- track = track->next)
- {
- for (int i = 0; i < track->markersnr; ++i) {
- const MovieTrackingMarker *marker = track->markers + i;
- if ((marker->flag & MARKER_DISABLED) == 0) {
- num_trackable_markers++;
- }
- }
- }
- /* Early output if we don't have any markers. */
- if (num_trackable_markers == 0) {
- return;
- }
- /* Allocate memory for all the markers. */
- libmv_Marker *libmv_markers = MEM_mallocN(
- sizeof(libmv_Marker) * num_trackable_markers,
- "libmv markers array");
- /* Fill in markers array. */
- int track_index = 0, num_filled_libmv_markers = 0;
- for (MovieTrackingTrack *track = tracksbase->first;
- track != NULL;
- track = track->next)
- {
- for (int i = 0; i < track->markersnr; ++i) {
- MovieTrackingMarker *marker = track->markers + i;
- if ((marker->flag & MARKER_DISABLED) != 0) {
- continue;
- }
- dna_marker_to_libmv_marker(
- track,
- marker,
- 0,
- track_index,
- frame_width, frame_height,
- backwards,
- &libmv_markers[num_filled_libmv_markers++]);
- }
- /* Put all markers to autotrack at once. */
- track_index++;
- }
- /* Add all markers to autotrack. */
- libmv_autoTrackSetMarkers(autotrack,
- libmv_markers,
- num_trackable_markers);
- /* Free temporary memory. */
- MEM_freeN(libmv_markers);
+ /* Count number of markers to be put to a context. */
+ size_t num_trackable_markers = 0;
+ for (MovieTrackingTrack *track = tracksbase->first; track != NULL; track = track->next) {
+ for (int i = 0; i < track->markersnr; ++i) {
+ const MovieTrackingMarker *marker = track->markers + i;
+ if ((marker->flag & MARKER_DISABLED) == 0) {
+ num_trackable_markers++;
+ }
+ }
+ }
+ /* Early output if we don't have any markers. */
+ if (num_trackable_markers == 0) {
+ return;
+ }
+ /* Allocate memory for all the markers. */
+ libmv_Marker *libmv_markers = MEM_mallocN(sizeof(libmv_Marker) * num_trackable_markers,
+ "libmv markers array");
+ /* Fill in markers array. */
+ int track_index = 0, num_filled_libmv_markers = 0;
+ for (MovieTrackingTrack *track = tracksbase->first; track != NULL; track = track->next) {
+ for (int i = 0; i < track->markersnr; ++i) {
+ MovieTrackingMarker *marker = track->markers + i;
+ if ((marker->flag & MARKER_DISABLED) != 0) {
+ continue;
+ }
+ dna_marker_to_libmv_marker(track,
+ marker,
+ 0,
+ track_index,
+ frame_width,
+ frame_height,
+ backwards,
+ &libmv_markers[num_filled_libmv_markers++]);
+ }
+ /* Put all markers to autotrack at once. */
+ track_index++;
+ }
+ /* Add all markers to autotrack. */
+ libmv_autoTrackSetMarkers(autotrack, libmv_markers, num_trackable_markers);
+ /* Free temporary memory. */
+ MEM_freeN(libmv_markers);
}
static void create_per_track_tracking_options(const MovieClip *clip,
@@ -337,42 +307,32 @@ static void create_per_track_tracking_options(const MovieClip *clip,
const ListBase *tracksbase,
AutoTrackContext *context)
{
- /* Count number of trackable tracks. */
- for (MovieTrackingTrack *track = tracksbase->first;
- track != NULL;
- track = track->next)
- {
- if (check_track_trackable(clip, track, user)) {
- context->num_tracks++;
- }
- }
- /* Allocate required memory. */
- context->options =
- MEM_callocN(sizeof(AutoTrackOptions) * context->num_tracks,
- "auto track options");
- /* Fill in all the settings. */
- int i = 0, track_index = 0;
- for (MovieTrackingTrack *track = tracksbase->first;
- track != NULL;
- track = track->next)
- {
- if (!check_track_trackable(clip, track, user)) {
- ++track_index;
- continue;
- }
- AutoTrackOptions *options = &context->options[i++];
- /* TODO(sergey): Single clip only for now. */
- options->clip_index = 0;
- options->track_index = track_index;
- options->track = track;
- tracking_configure_tracker(track,
- NULL,
- &options->track_region_options);
- options->use_keyframe_match =
- track->pattern_match == TRACK_MATCH_KEYFRAME;
- context->tracks[track_index] = track;
- ++track_index;
- }
+ /* Count number of trackable tracks. */
+ for (MovieTrackingTrack *track = tracksbase->first; track != NULL; track = track->next) {
+ if (check_track_trackable(clip, track, user)) {
+ context->num_tracks++;
+ }
+ }
+ /* Allocate required memory. */
+ context->options = MEM_callocN(sizeof(AutoTrackOptions) * context->num_tracks,
+ "auto track options");
+ /* Fill in all the settings. */
+ int i = 0, track_index = 0;
+ for (MovieTrackingTrack *track = tracksbase->first; track != NULL; track = track->next) {
+ if (!check_track_trackable(clip, track, user)) {
+ ++track_index;
+ continue;
+ }
+ AutoTrackOptions *options = &context->options[i++];
+ /* TODO(sergey): Single clip only for now. */
+ options->clip_index = 0;
+ options->track_index = track_index;
+ options->track = track;
+ tracking_configure_tracker(track, NULL, &options->track_region_options);
+ options->use_keyframe_match = track->pattern_match == TRACK_MATCH_KEYFRAME;
+ context->tracks[track_index] = track;
+ ++track_index;
+ }
}
AutoTrackContext *BKE_autotrack_context_new(MovieClip *clip,
@@ -380,266 +340,217 @@ AutoTrackContext *BKE_autotrack_context_new(MovieClip *clip,
const bool backwards,
const bool sequence)
{
- AutoTrackContext *context = MEM_callocN(sizeof(AutoTrackContext),
- "autotrack context");
- MovieTracking *tracking = &clip->tracking;
- ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
- int frame_width, frame_height;
- /* get size of frame to convert normalized coordinates to a picture ones. */
- BKE_movieclip_get_size(clip, user, &frame_width, &frame_height);
- /* TODO(sergey): Currently using only a single clip. */
- context->clips[0] = clip;
- context->num_clips = 1;
- context->user = *user;
- context->user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL;
- context->user.render_flag = 0;
- context->frame_width = frame_width;
- context->frame_height = frame_height;
- context->backwards = backwards;
- context->sequence = sequence;
- context->first_frame = user->framenr;
- context->sync_frame = user->framenr;
- context->first_sync = true;
- BLI_spin_init(&context->spin_lock);
- const int num_total_tracks = BLI_listbase_count(tracksbase);
- context->tracks =
- MEM_callocN(sizeof(MovieTrackingTrack *) * num_total_tracks,
- "auto track pointers");
- /* Initialize image accessor. */
- context->image_accessor =
- tracking_image_accessor_new(context->clips, 1,
- context->tracks, num_total_tracks,
- user->framenr);
- /* Initialize auto track context and provide all information about currently
- * tracked markers.
- */
- context->autotrack =
- libmv_autoTrackNew(context->image_accessor->libmv_accessor);
- fill_autotrack_tracks(frame_width, frame_height,
- tracksbase,
- backwards,
- context->autotrack);
- /* Create per-track tracking options. */
- create_per_track_tracking_options(clip, user, tracksbase, context);
- return context;
+ AutoTrackContext *context = MEM_callocN(sizeof(AutoTrackContext), "autotrack context");
+ MovieTracking *tracking = &clip->tracking;
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
+ int frame_width, frame_height;
+ /* get size of frame to convert normalized coordinates to a picture ones. */
+ BKE_movieclip_get_size(clip, user, &frame_width, &frame_height);
+ /* TODO(sergey): Currently using only a single clip. */
+ context->clips[0] = clip;
+ context->num_clips = 1;
+ context->user = *user;
+ context->user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL;
+ context->user.render_flag = 0;
+ context->frame_width = frame_width;
+ context->frame_height = frame_height;
+ context->backwards = backwards;
+ context->sequence = sequence;
+ context->first_frame = user->framenr;
+ context->sync_frame = user->framenr;
+ context->first_sync = true;
+ BLI_spin_init(&context->spin_lock);
+ const int num_total_tracks = BLI_listbase_count(tracksbase);
+ context->tracks = MEM_callocN(sizeof(MovieTrackingTrack *) * num_total_tracks,
+ "auto track pointers");
+ /* Initialize image accessor. */
+ context->image_accessor = tracking_image_accessor_new(
+ context->clips, 1, context->tracks, num_total_tracks, user->framenr);
+ /* Initialize auto track context and provide all information about currently
+ * tracked markers.
+ */
+ context->autotrack = libmv_autoTrackNew(context->image_accessor->libmv_accessor);
+ fill_autotrack_tracks(frame_width, frame_height, tracksbase, backwards, context->autotrack);
+ /* Create per-track tracking options. */
+ create_per_track_tracking_options(clip, user, tracksbase, context);
+ return context;
}
-static void autotrack_context_step_cb(
- void *__restrict userdata,
- const int track,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void autotrack_context_step_cb(void *__restrict userdata,
+ const int track,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- AutoTrackContext *context = userdata;
- const int frame_delta = context->backwards ? -1 : 1;
-
- AutoTrackOptions *options = &context->options[track];
- if (options->is_failed) {
- return;
- }
- libmv_Marker libmv_current_marker,
- libmv_reference_marker,
- libmv_tracked_marker;
- libmv_TrackRegionResult libmv_result;
- const int frame = BKE_movieclip_remap_scene_to_clip_frame(
- context->clips[options->clip_index],
- context->user.framenr);
- BLI_spin_lock(&context->spin_lock);
- const bool has_marker = libmv_autoTrackGetMarker(context->autotrack,
- options->clip_index,
- frame,
- options->track_index,
- &libmv_current_marker);
- BLI_spin_unlock(&context->spin_lock);
- /* Check whether we've got marker to sync with. */
- if (!has_marker) {
- return;
- }
- /* Check whether marker is going outside of allowed frame margin. */
- if (!tracking_check_marker_margin(&libmv_current_marker,
- options->track->margin,
- context->frame_width,
- context->frame_height))
- {
- return;
- }
- libmv_tracked_marker = libmv_current_marker;
- libmv_tracked_marker.frame = frame + frame_delta;
- /* Update reference frame. */
- if (options->use_keyframe_match) {
- libmv_tracked_marker.reference_frame =
- libmv_current_marker.reference_frame;
- libmv_autoTrackGetMarker(context->autotrack,
- options->clip_index,
- libmv_tracked_marker.reference_frame,
- options->track_index,
- &libmv_reference_marker);
- }
- else {
- libmv_tracked_marker.reference_frame = frame;
- libmv_reference_marker = libmv_current_marker;
- }
- /* Perform actual tracking. */
- if (libmv_autoTrackMarker(context->autotrack,
- &options->track_region_options,
- &libmv_tracked_marker,
- &libmv_result))
- {
- BLI_spin_lock(&context->spin_lock);
- libmv_autoTrackAddMarker(context->autotrack, &libmv_tracked_marker);
- BLI_spin_unlock(&context->spin_lock);
- }
- else {
- options->is_failed = true;
- options->failed_frame = frame + frame_delta;
- }
-
- /* Note: Atomic is probably not actually needed here, I doubt we could get
- * any other result than a true bool anyway.
- * But for sake of consistency, and since it costs nothing...
- */
- atomic_fetch_and_or_uint8((uint8_t *)&context->step_ok, true);
+ AutoTrackContext *context = userdata;
+ const int frame_delta = context->backwards ? -1 : 1;
+
+ AutoTrackOptions *options = &context->options[track];
+ if (options->is_failed) {
+ return;
+ }
+ libmv_Marker libmv_current_marker, libmv_reference_marker, libmv_tracked_marker;
+ libmv_TrackRegionResult libmv_result;
+ const int frame = BKE_movieclip_remap_scene_to_clip_frame(context->clips[options->clip_index],
+ context->user.framenr);
+ BLI_spin_lock(&context->spin_lock);
+ const bool has_marker = libmv_autoTrackGetMarker(
+ context->autotrack, options->clip_index, frame, options->track_index, &libmv_current_marker);
+ BLI_spin_unlock(&context->spin_lock);
+ /* Check whether we've got marker to sync with. */
+ if (!has_marker) {
+ return;
+ }
+ /* Check whether marker is going outside of allowed frame margin. */
+ if (!tracking_check_marker_margin(&libmv_current_marker,
+ options->track->margin,
+ context->frame_width,
+ context->frame_height)) {
+ return;
+ }
+ libmv_tracked_marker = libmv_current_marker;
+ libmv_tracked_marker.frame = frame + frame_delta;
+ /* Update reference frame. */
+ if (options->use_keyframe_match) {
+ libmv_tracked_marker.reference_frame = libmv_current_marker.reference_frame;
+ libmv_autoTrackGetMarker(context->autotrack,
+ options->clip_index,
+ libmv_tracked_marker.reference_frame,
+ options->track_index,
+ &libmv_reference_marker);
+ }
+ else {
+ libmv_tracked_marker.reference_frame = frame;
+ libmv_reference_marker = libmv_current_marker;
+ }
+ /* Perform actual tracking. */
+ if (libmv_autoTrackMarker(context->autotrack,
+ &options->track_region_options,
+ &libmv_tracked_marker,
+ &libmv_result)) {
+ BLI_spin_lock(&context->spin_lock);
+ libmv_autoTrackAddMarker(context->autotrack, &libmv_tracked_marker);
+ BLI_spin_unlock(&context->spin_lock);
+ }
+ else {
+ options->is_failed = true;
+ options->failed_frame = frame + frame_delta;
+ }
+
+ /* Note: Atomic is probably not actually needed here, I doubt we could get
+ * any other result than a true bool anyway.
+ * But for sake of consistency, and since it costs nothing...
+ */
+ atomic_fetch_and_or_uint8((uint8_t *)&context->step_ok, true);
}
bool BKE_autotrack_context_step(AutoTrackContext *context)
{
- const int frame_delta = context->backwards ? -1 : 1;
- context->step_ok = false;
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (context->num_tracks > 1);
- BLI_task_parallel_range(0, context->num_tracks,
- context,
- autotrack_context_step_cb,
- &settings);
-
- /* Advance the frame. */
- BLI_spin_lock(&context->spin_lock);
- context->user.framenr += frame_delta;
- BLI_spin_unlock(&context->spin_lock);
- return context->step_ok;
+ const int frame_delta = context->backwards ? -1 : 1;
+ context->step_ok = false;
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (context->num_tracks > 1);
+ BLI_task_parallel_range(0, context->num_tracks, context, autotrack_context_step_cb, &settings);
+
+ /* Advance the frame. */
+ BLI_spin_lock(&context->spin_lock);
+ context->user.framenr += frame_delta;
+ BLI_spin_unlock(&context->spin_lock);
+ return context->step_ok;
}
void BKE_autotrack_context_sync(AutoTrackContext *context)
{
- int newframe, frame_delta = context->backwards ? -1 : 1;
- int frame;
-
- BLI_spin_lock(&context->spin_lock);
- newframe = context->user.framenr;
- for (frame = context->sync_frame;
- frame != (context->backwards ? newframe - 1 : newframe + 1);
- frame += frame_delta)
- {
- MovieTrackingMarker marker;
- libmv_Marker libmv_marker;
- int clip = 0;
- int track;
- for (track = 0; track < context->num_tracks; ++track) {
- AutoTrackOptions *options = &context->options[track];
- int track_frame = BKE_movieclip_remap_scene_to_clip_frame(
- context->clips[options->clip_index], frame);
- if (options->is_failed) {
- if (options->failed_frame == track_frame) {
- MovieTrackingMarker *prev_marker =
- BKE_tracking_marker_get_exact(
- options->track,
- context->backwards
- ? frame + 1
- : frame - 1);
- if (prev_marker) {
- marker = *prev_marker;
- marker.framenr = track_frame;
- marker.flag |= MARKER_DISABLED;
- BKE_tracking_marker_insert(options->track, &marker);
- continue;
- }
- }
- if ((context->backwards && options->failed_frame > track_frame) ||
- (!context->backwards && options->failed_frame < track_frame))
- {
- continue;
- }
- }
- if (libmv_autoTrackGetMarker(context->autotrack,
- clip,
- track_frame,
- options->track_index,
- &libmv_marker))
- {
- libmv_marker_to_dna_marker(&libmv_marker,
- context->frame_width,
- context->frame_height,
- &marker);
- if (context->first_sync && frame == context->sync_frame) {
- tracking_marker_insert_disabled(options->track,
- &marker,
- !context->backwards,
- false);
- }
- BKE_tracking_marker_insert(options->track, &marker);
- tracking_marker_insert_disabled(options->track,
- &marker,
- context->backwards,
- false);
- }
- }
- }
- BLI_spin_unlock(&context->spin_lock);
-
- for (int clip = 0; clip < context->num_clips; ++clip) {
- MovieTracking *tracking = &context->clips[clip]->tracking;
- BKE_tracking_dopesheet_tag_update(tracking);
- }
-
- context->sync_frame = newframe;
- context->first_sync = false;
+ int newframe, frame_delta = context->backwards ? -1 : 1;
+ int frame;
+
+ BLI_spin_lock(&context->spin_lock);
+ newframe = context->user.framenr;
+ for (frame = context->sync_frame; frame != (context->backwards ? newframe - 1 : newframe + 1);
+ frame += frame_delta) {
+ MovieTrackingMarker marker;
+ libmv_Marker libmv_marker;
+ int clip = 0;
+ int track;
+ for (track = 0; track < context->num_tracks; ++track) {
+ AutoTrackOptions *options = &context->options[track];
+ int track_frame = BKE_movieclip_remap_scene_to_clip_frame(
+ context->clips[options->clip_index], frame);
+ if (options->is_failed) {
+ if (options->failed_frame == track_frame) {
+ MovieTrackingMarker *prev_marker = BKE_tracking_marker_get_exact(
+ options->track, context->backwards ? frame + 1 : frame - 1);
+ if (prev_marker) {
+ marker = *prev_marker;
+ marker.framenr = track_frame;
+ marker.flag |= MARKER_DISABLED;
+ BKE_tracking_marker_insert(options->track, &marker);
+ continue;
+ }
+ }
+ if ((context->backwards && options->failed_frame > track_frame) ||
+ (!context->backwards && options->failed_frame < track_frame)) {
+ continue;
+ }
+ }
+ if (libmv_autoTrackGetMarker(
+ context->autotrack, clip, track_frame, options->track_index, &libmv_marker)) {
+ libmv_marker_to_dna_marker(
+ &libmv_marker, context->frame_width, context->frame_height, &marker);
+ if (context->first_sync && frame == context->sync_frame) {
+ tracking_marker_insert_disabled(options->track, &marker, !context->backwards, false);
+ }
+ BKE_tracking_marker_insert(options->track, &marker);
+ tracking_marker_insert_disabled(options->track, &marker, context->backwards, false);
+ }
+ }
+ }
+ BLI_spin_unlock(&context->spin_lock);
+
+ for (int clip = 0; clip < context->num_clips; ++clip) {
+ MovieTracking *tracking = &context->clips[clip]->tracking;
+ BKE_tracking_dopesheet_tag_update(tracking);
+ }
+
+ context->sync_frame = newframe;
+ context->first_sync = false;
}
-void BKE_autotrack_context_sync_user(AutoTrackContext *context,
- MovieClipUser *user)
+void BKE_autotrack_context_sync_user(AutoTrackContext *context, MovieClipUser *user)
{
- user->framenr = context->sync_frame;
+ user->framenr = context->sync_frame;
}
void BKE_autotrack_context_finish(AutoTrackContext *context)
{
- int clip_index;
-
- for (clip_index = 0; clip_index < context->num_clips; ++clip_index) {
- MovieClip *clip = context->clips[clip_index];
- ListBase *plane_tracks_base =
- BKE_tracking_get_active_plane_tracks(&clip->tracking);
- MovieTrackingPlaneTrack *plane_track;
-
- for (plane_track = plane_tracks_base->first;
- plane_track;
- plane_track = plane_track->next)
- {
- if ((plane_track->flag & PLANE_TRACK_AUTOKEY) == 0) {
- int track;
- for (track = 0; track < context->num_tracks; ++track) {
- if (BKE_tracking_plane_track_has_point_track(
- plane_track,
- context->options[track].track))
- {
- BKE_tracking_track_plane_from_existing_motion(
- plane_track,
- context->first_frame);
- break;
- }
- }
- }
- }
- }
+ int clip_index;
+
+ for (clip_index = 0; clip_index < context->num_clips; ++clip_index) {
+ MovieClip *clip = context->clips[clip_index];
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking);
+ MovieTrackingPlaneTrack *plane_track;
+
+ for (plane_track = plane_tracks_base->first; plane_track; plane_track = plane_track->next) {
+ if ((plane_track->flag & PLANE_TRACK_AUTOKEY) == 0) {
+ int track;
+ for (track = 0; track < context->num_tracks; ++track) {
+ if (BKE_tracking_plane_track_has_point_track(plane_track,
+ context->options[track].track)) {
+ BKE_tracking_track_plane_from_existing_motion(plane_track, context->first_frame);
+ break;
+ }
+ }
+ }
+ }
+ }
}
void BKE_autotrack_context_free(AutoTrackContext *context)
{
- libmv_autoTrackDestroy(context->autotrack);
- tracking_image_accessor_destroy(context->image_accessor);
- MEM_freeN(context->options);
- MEM_freeN(context->tracks);
- BLI_spin_end(&context->spin_lock);
- MEM_freeN(context);
+ libmv_autoTrackDestroy(context->autotrack);
+ tracking_image_accessor_destroy(context->image_accessor);
+ MEM_freeN(context->options);
+ MEM_freeN(context->tracks);
+ BLI_spin_end(&context->spin_lock);
+ MEM_freeN(context);
}
diff --git a/source/blender/blenkernel/intern/tracking_detect.c b/source/blender/blenkernel/intern/tracking_detect.c
index 237adc80890..36d44f8fa5d 100644
--- a/source/blender/blenkernel/intern/tracking_detect.c
+++ b/source/blender/blenkernel/intern/tracking_detect.c
@@ -25,7 +25,7 @@
#include "DNA_gpencil_types.h"
#include "DNA_movieclip_types.h"
-#include "DNA_object_types.h" /* SELECT */
+#include "DNA_object_types.h" /* SELECT */
#include "BLI_utildefines.h"
@@ -38,138 +38,158 @@
/* Check whether point is inside grease pencil stroke. */
static bool check_point_in_stroke(bGPDstroke *stroke, float x, float y)
{
- int i, prev;
- int count = 0;
- bGPDspoint *points = stroke->points;
+ int i, prev;
+ int count = 0;
+ bGPDspoint *points = stroke->points;
- /* Count intersections of horizontal ray coming from the point.
- * Point will be inside layer if and only if number of intersection
- * is uneven.
- *
- * Well, if layer has got self-intersections, this logic wouldn't
- * work, but such situation is crappy anyway.
- */
+ /* Count intersections of horizontal ray coming from the point.
+ * Point will be inside layer if and only if number of intersection
+ * is uneven.
+ *
+ * Well, if layer has got self-intersections, this logic wouldn't
+ * work, but such situation is crappy anyway.
+ */
- prev = stroke->totpoints - 1;
+ prev = stroke->totpoints - 1;
- for (i = 0; i < stroke->totpoints; i++) {
- if ((points[i].y < y && points[prev].y >= y) || (points[prev].y < y && points[i].y >= y)) {
- float fac = (y - points[i].y) / (points[prev].y - points[i].y);
+ for (i = 0; i < stroke->totpoints; i++) {
+ if ((points[i].y < y && points[prev].y >= y) || (points[prev].y < y && points[i].y >= y)) {
+ float fac = (y - points[i].y) / (points[prev].y - points[i].y);
- if (points[i].x + fac * (points[prev].x - points[i].x) < x)
- count++;
- }
+ if (points[i].x + fac * (points[prev].x - points[i].x) < x)
+ count++;
+ }
- prev = i;
- }
+ prev = i;
+ }
- return (count % 2) ? true : false;
+ return (count % 2) ? true : false;
}
/* Check whether point is inside any stroke of grease pencil layer. */
static bool check_point_in_layer(bGPDlayer *layer, float x, float y)
{
- bGPDframe *frame = layer->frames.first;
+ bGPDframe *frame = layer->frames.first;
- while (frame) {
- bGPDstroke *stroke = frame->strokes.first;
+ while (frame) {
+ bGPDstroke *stroke = frame->strokes.first;
- while (stroke) {
- if (check_point_in_stroke(stroke, x, y))
- return true;
+ while (stroke) {
+ if (check_point_in_stroke(stroke, x, y))
+ return true;
- stroke = stroke->next;
- }
- frame = frame->next;
- }
+ stroke = stroke->next;
+ }
+ frame = frame->next;
+ }
- return false;
+ return false;
}
/* Get features detected by libmv and create tracks on the clip for them. */
-static void detect_retrieve_libmv_features(MovieTracking *tracking, ListBase *tracksbase,
- struct libmv_Features *features, int framenr, int width, int height,
- bGPDlayer *layer, bool place_outside_layer)
+static void detect_retrieve_libmv_features(MovieTracking *tracking,
+ ListBase *tracksbase,
+ struct libmv_Features *features,
+ int framenr,
+ int width,
+ int height,
+ bGPDlayer *layer,
+ bool place_outside_layer)
{
- int a;
-
- a = libmv_countFeatures(features);
- while (a--) {
- MovieTrackingTrack *track;
- double x, y, size, score;
- bool ok = true;
- float xu, yu;
-
- libmv_getFeature(features, a, &x, &y, &score, &size);
-
- /* In Libmv integer coordinate points to pixel center, in blender
- * it's not. Need to add 0.5px offset to center.
- */
- xu = (x + 0.5) / width;
- yu = (y + 0.5) / height;
-
- if (layer)
- ok = check_point_in_layer(layer, xu, yu) != place_outside_layer;
-
- if (ok) {
- track = BKE_tracking_track_add(tracking, tracksbase, xu, yu, framenr, width, height);
- track->flag |= SELECT;
- track->pat_flag |= SELECT;
- track->search_flag |= SELECT;
- }
- }
+ int a;
+
+ a = libmv_countFeatures(features);
+ while (a--) {
+ MovieTrackingTrack *track;
+ double x, y, size, score;
+ bool ok = true;
+ float xu, yu;
+
+ libmv_getFeature(features, a, &x, &y, &score, &size);
+
+ /* In Libmv integer coordinate points to pixel center, in blender
+ * it's not. Need to add 0.5px offset to center.
+ */
+ xu = (x + 0.5) / width;
+ yu = (y + 0.5) / height;
+
+ if (layer)
+ ok = check_point_in_layer(layer, xu, yu) != place_outside_layer;
+
+ if (ok) {
+ track = BKE_tracking_track_add(tracking, tracksbase, xu, yu, framenr, width, height);
+ track->flag |= SELECT;
+ track->pat_flag |= SELECT;
+ track->search_flag |= SELECT;
+ }
+ }
}
-static void run_configured_detector(MovieTracking *tracking, ListBase *tracksbase,
- ImBuf *ibuf, int framenr, bGPDlayer *layer, bool place_outside_layer,
+static void run_configured_detector(MovieTracking *tracking,
+ ListBase *tracksbase,
+ ImBuf *ibuf,
+ int framenr,
+ bGPDlayer *layer,
+ bool place_outside_layer,
libmv_DetectOptions *options)
{
- struct libmv_Features *features = NULL;
-
- if (ibuf->rect_float) {
- features = libmv_detectFeaturesFloat(ibuf->rect_float, ibuf->x, ibuf->y, 4, options);
- }
- else if (ibuf->rect) {
- features = libmv_detectFeaturesByte((unsigned char *) ibuf->rect, ibuf->x, ibuf->y, 4, options);
- }
-
- if (features != NULL) {
- detect_retrieve_libmv_features(tracking, tracksbase, features,
- framenr, ibuf->x, ibuf->y, layer,
- place_outside_layer);
-
- libmv_featuresDestroy(features);
- }
+ struct libmv_Features *features = NULL;
+
+ if (ibuf->rect_float) {
+ features = libmv_detectFeaturesFloat(ibuf->rect_float, ibuf->x, ibuf->y, 4, options);
+ }
+ else if (ibuf->rect) {
+ features = libmv_detectFeaturesByte((unsigned char *)ibuf->rect, ibuf->x, ibuf->y, 4, options);
+ }
+
+ if (features != NULL) {
+ detect_retrieve_libmv_features(
+ tracking, tracksbase, features, framenr, ibuf->x, ibuf->y, layer, place_outside_layer);
+
+ libmv_featuresDestroy(features);
+ }
}
/* Detect features using FAST detector */
-void BKE_tracking_detect_fast(MovieTracking *tracking, ListBase *tracksbase, ImBuf *ibuf,
- int framenr, int margin, int min_trackness, int min_distance, bGPDlayer *layer,
+void BKE_tracking_detect_fast(MovieTracking *tracking,
+ ListBase *tracksbase,
+ ImBuf *ibuf,
+ int framenr,
+ int margin,
+ int min_trackness,
+ int min_distance,
+ bGPDlayer *layer,
bool place_outside_layer)
{
- libmv_DetectOptions options = {0};
+ libmv_DetectOptions options = {0};
- options.detector = LIBMV_DETECTOR_FAST;
- options.margin = margin;
- options.min_distance = min_distance;
- options.fast_min_trackness = min_trackness;
+ options.detector = LIBMV_DETECTOR_FAST;
+ options.margin = margin;
+ options.min_distance = min_distance;
+ options.fast_min_trackness = min_trackness;
- run_configured_detector(tracking, tracksbase, ibuf, framenr, layer,
- place_outside_layer, &options);
+ run_configured_detector(
+ tracking, tracksbase, ibuf, framenr, layer, place_outside_layer, &options);
}
/* Detect features using Harris detector */
-void BKE_tracking_detect_harris(MovieTracking *tracking, ListBase *tracksbase, ImBuf *ibuf,
- int framenr, int margin, float threshold, int min_distance, bGPDlayer *layer,
+void BKE_tracking_detect_harris(MovieTracking *tracking,
+ ListBase *tracksbase,
+ ImBuf *ibuf,
+ int framenr,
+ int margin,
+ float threshold,
+ int min_distance,
+ bGPDlayer *layer,
bool place_outside_layer)
{
- libmv_DetectOptions options = {0};
+ libmv_DetectOptions options = {0};
- options.detector = LIBMV_DETECTOR_HARRIS;
- options.margin = margin;
- options.min_distance = min_distance;
- options.harris_threshold = threshold;
+ options.detector = LIBMV_DETECTOR_HARRIS;
+ options.margin = margin;
+ options.min_distance = min_distance;
+ options.harris_threshold = threshold;
- run_configured_detector(tracking, tracksbase, ibuf, framenr, layer,
- place_outside_layer, &options);
+ run_configured_detector(
+ tracking, tracksbase, ibuf, framenr, layer, place_outside_layer, &options);
}
diff --git a/source/blender/blenkernel/intern/tracking_plane_tracker.c b/source/blender/blenkernel/intern/tracking_plane_tracker.c
index 0ac8763e866..602243a7d50 100644
--- a/source/blender/blenkernel/intern/tracking_plane_tracker.c
+++ b/source/blender/blenkernel/intern/tracking_plane_tracker.c
@@ -36,203 +36,208 @@
typedef double Vec2[2];
-static int point_markers_correspondences_on_both_image(MovieTrackingPlaneTrack *plane_track, int frame1, int frame2,
- Vec2 **x1_r, Vec2 **x2_r)
+static int point_markers_correspondences_on_both_image(
+ MovieTrackingPlaneTrack *plane_track, int frame1, int frame2, Vec2 **x1_r, Vec2 **x2_r)
{
- int i, correspondence_index;
- Vec2 *x1, *x2;
+ int i, correspondence_index;
+ Vec2 *x1, *x2;
- *x1_r = x1 = MEM_mallocN(sizeof(*x1) * plane_track->point_tracksnr, "point correspondences x1");
- *x2_r = x2 = MEM_mallocN(sizeof(*x1) * plane_track->point_tracksnr, "point correspondences x2");
+ *x1_r = x1 = MEM_mallocN(sizeof(*x1) * plane_track->point_tracksnr, "point correspondences x1");
+ *x2_r = x2 = MEM_mallocN(sizeof(*x1) * plane_track->point_tracksnr, "point correspondences x2");
- for (i = 0, correspondence_index = 0; i < plane_track->point_tracksnr; i++) {
- MovieTrackingTrack *point_track = plane_track->point_tracks[i];
- MovieTrackingMarker *point_marker1, *point_marker2;
+ for (i = 0, correspondence_index = 0; i < plane_track->point_tracksnr; i++) {
+ MovieTrackingTrack *point_track = plane_track->point_tracks[i];
+ MovieTrackingMarker *point_marker1, *point_marker2;
- point_marker1 = BKE_tracking_marker_get_exact(point_track, frame1);
- point_marker2 = BKE_tracking_marker_get_exact(point_track, frame2);
+ point_marker1 = BKE_tracking_marker_get_exact(point_track, frame1);
+ point_marker2 = BKE_tracking_marker_get_exact(point_track, frame2);
- if (point_marker1 != NULL && point_marker2 != NULL) {
- /* Here conversion from float to double happens. */
- x1[correspondence_index][0] = point_marker1->pos[0];
- x1[correspondence_index][1] = point_marker1->pos[1];
+ if (point_marker1 != NULL && point_marker2 != NULL) {
+ /* Here conversion from float to double happens. */
+ x1[correspondence_index][0] = point_marker1->pos[0];
+ x1[correspondence_index][1] = point_marker1->pos[1];
- x2[correspondence_index][0] = point_marker2->pos[0];
- x2[correspondence_index][1] = point_marker2->pos[1];
+ x2[correspondence_index][0] = point_marker2->pos[0];
+ x2[correspondence_index][1] = point_marker2->pos[1];
- correspondence_index++;
- }
- }
+ correspondence_index++;
+ }
+ }
- return correspondence_index;
+ return correspondence_index;
}
/* NOTE: frame number should be in clip space, not scene space */
-static void track_plane_from_existing_motion(MovieTrackingPlaneTrack *plane_track, int start_frame,
- int direction, bool retrack)
+static void track_plane_from_existing_motion(MovieTrackingPlaneTrack *plane_track,
+ int start_frame,
+ int direction,
+ bool retrack)
{
- MovieTrackingPlaneMarker *start_plane_marker = BKE_tracking_plane_marker_get(plane_track, start_frame);
- MovieTrackingPlaneMarker *keyframe_plane_marker = NULL;
- MovieTrackingPlaneMarker new_plane_marker;
- int current_frame, frame_delta = direction > 0 ? 1 : -1;
-
- if (plane_track->flag & PLANE_TRACK_AUTOKEY) {
- /* Find a keyframe in given direction. */
- for (current_frame = start_frame; ; current_frame += frame_delta) {
- MovieTrackingPlaneMarker *next_plane_marker =
- BKE_tracking_plane_marker_get_exact(plane_track, current_frame + frame_delta);
-
- if (next_plane_marker == NULL) {
- break;
- }
-
- if ((next_plane_marker->flag & PLANE_MARKER_TRACKED) == 0) {
- keyframe_plane_marker = next_plane_marker;
- break;
- }
- }
- }
- else {
- start_plane_marker->flag |= PLANE_MARKER_TRACKED;
- }
-
- new_plane_marker = *start_plane_marker;
- new_plane_marker.flag |= PLANE_MARKER_TRACKED;
-
- for (current_frame = start_frame; ; current_frame += frame_delta) {
- MovieTrackingPlaneMarker *next_plane_marker =
- BKE_tracking_plane_marker_get_exact(plane_track, current_frame + frame_delta);
- Vec2 *x1, *x2;
- int i, num_correspondences;
- double H_double[3][3];
- float H[3][3];
-
- /* As soon as we meet keyframed plane, we stop updating the sequence. */
- if (next_plane_marker && (next_plane_marker->flag & PLANE_MARKER_TRACKED) == 0) {
- /* Don't override keyframes if track is in auto-keyframe mode */
- if (plane_track->flag & PLANE_TRACK_AUTOKEY) {
- break;
- }
- }
-
- num_correspondences =
- point_markers_correspondences_on_both_image(plane_track, current_frame, current_frame + frame_delta,
- &x1, &x2);
-
- if (num_correspondences < 4) {
- MEM_freeN(x1);
- MEM_freeN(x2);
-
- break;
- }
-
- libmv_homography2DFromCorrespondencesEuc(x1, x2, num_correspondences, H_double);
-
- copy_m3_m3d(H, H_double);
-
- for (i = 0; i < 4; i++) {
- float vec[3] = {0.0f, 0.0f, 1.0f}, vec2[3];
- copy_v2_v2(vec, new_plane_marker.corners[i]);
-
- /* Apply homography */
- mul_v3_m3v3(vec2, H, vec);
-
- /* Normalize. */
- vec2[0] /= vec2[2];
- vec2[1] /= vec2[2];
-
- copy_v2_v2(new_plane_marker.corners[i], vec2);
- }
-
- new_plane_marker.framenr = current_frame + frame_delta;
-
- if (!retrack && keyframe_plane_marker &&
- next_plane_marker &&
- (plane_track->flag & PLANE_TRACK_AUTOKEY))
- {
- float fac = ((float) next_plane_marker->framenr - start_plane_marker->framenr) /
- ((float) keyframe_plane_marker->framenr - start_plane_marker->framenr);
-
- fac = 3 * fac * fac - 2 * fac * fac * fac;
-
- for (i = 0; i < 4; i++) {
- interp_v2_v2v2(new_plane_marker.corners[i], new_plane_marker.corners[i],
- next_plane_marker->corners[i], fac);
- }
- }
-
- BKE_tracking_plane_marker_insert(plane_track, &new_plane_marker);
-
- MEM_freeN(x1);
- MEM_freeN(x2);
- }
+ MovieTrackingPlaneMarker *start_plane_marker = BKE_tracking_plane_marker_get(plane_track,
+ start_frame);
+ MovieTrackingPlaneMarker *keyframe_plane_marker = NULL;
+ MovieTrackingPlaneMarker new_plane_marker;
+ int current_frame, frame_delta = direction > 0 ? 1 : -1;
+
+ if (plane_track->flag & PLANE_TRACK_AUTOKEY) {
+ /* Find a keyframe in given direction. */
+ for (current_frame = start_frame;; current_frame += frame_delta) {
+ MovieTrackingPlaneMarker *next_plane_marker = BKE_tracking_plane_marker_get_exact(
+ plane_track, current_frame + frame_delta);
+
+ if (next_plane_marker == NULL) {
+ break;
+ }
+
+ if ((next_plane_marker->flag & PLANE_MARKER_TRACKED) == 0) {
+ keyframe_plane_marker = next_plane_marker;
+ break;
+ }
+ }
+ }
+ else {
+ start_plane_marker->flag |= PLANE_MARKER_TRACKED;
+ }
+
+ new_plane_marker = *start_plane_marker;
+ new_plane_marker.flag |= PLANE_MARKER_TRACKED;
+
+ for (current_frame = start_frame;; current_frame += frame_delta) {
+ MovieTrackingPlaneMarker *next_plane_marker = BKE_tracking_plane_marker_get_exact(
+ plane_track, current_frame + frame_delta);
+ Vec2 *x1, *x2;
+ int i, num_correspondences;
+ double H_double[3][3];
+ float H[3][3];
+
+ /* As soon as we meet keyframed plane, we stop updating the sequence. */
+ if (next_plane_marker && (next_plane_marker->flag & PLANE_MARKER_TRACKED) == 0) {
+ /* Don't override keyframes if track is in auto-keyframe mode */
+ if (plane_track->flag & PLANE_TRACK_AUTOKEY) {
+ break;
+ }
+ }
+
+ num_correspondences = point_markers_correspondences_on_both_image(
+ plane_track, current_frame, current_frame + frame_delta, &x1, &x2);
+
+ if (num_correspondences < 4) {
+ MEM_freeN(x1);
+ MEM_freeN(x2);
+
+ break;
+ }
+
+ libmv_homography2DFromCorrespondencesEuc(x1, x2, num_correspondences, H_double);
+
+ copy_m3_m3d(H, H_double);
+
+ for (i = 0; i < 4; i++) {
+ float vec[3] = {0.0f, 0.0f, 1.0f}, vec2[3];
+ copy_v2_v2(vec, new_plane_marker.corners[i]);
+
+ /* Apply homography */
+ mul_v3_m3v3(vec2, H, vec);
+
+ /* Normalize. */
+ vec2[0] /= vec2[2];
+ vec2[1] /= vec2[2];
+
+ copy_v2_v2(new_plane_marker.corners[i], vec2);
+ }
+
+ new_plane_marker.framenr = current_frame + frame_delta;
+
+ if (!retrack && keyframe_plane_marker && next_plane_marker &&
+ (plane_track->flag & PLANE_TRACK_AUTOKEY)) {
+ float fac = ((float)next_plane_marker->framenr - start_plane_marker->framenr) /
+ ((float)keyframe_plane_marker->framenr - start_plane_marker->framenr);
+
+ fac = 3 * fac * fac - 2 * fac * fac * fac;
+
+ for (i = 0; i < 4; i++) {
+ interp_v2_v2v2(new_plane_marker.corners[i],
+ new_plane_marker.corners[i],
+ next_plane_marker->corners[i],
+ fac);
+ }
+ }
+
+ BKE_tracking_plane_marker_insert(plane_track, &new_plane_marker);
+
+ MEM_freeN(x1);
+ MEM_freeN(x2);
+ }
}
/* NOTE: frame number should be in clip space, not scene space */
-void BKE_tracking_track_plane_from_existing_motion(MovieTrackingPlaneTrack *plane_track, int start_frame)
+void BKE_tracking_track_plane_from_existing_motion(MovieTrackingPlaneTrack *plane_track,
+ int start_frame)
{
- track_plane_from_existing_motion(plane_track, start_frame, 1, false);
- track_plane_from_existing_motion(plane_track, start_frame, -1, false);
+ track_plane_from_existing_motion(plane_track, start_frame, 1, false);
+ track_plane_from_existing_motion(plane_track, start_frame, -1, false);
}
static MovieTrackingPlaneMarker *find_plane_keyframe(MovieTrackingPlaneTrack *plane_track,
- int start_frame, int direction)
+ int start_frame,
+ int direction)
{
- MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, start_frame);
- int index = plane_marker - plane_track->markers;
- int frame_delta = direction > 0 ? 1 : -1;
-
- while (index >= 0 && index < plane_track->markersnr) {
- if ((plane_marker->flag & PLANE_MARKER_TRACKED) == 0) {
- return plane_marker;
- }
- plane_marker += frame_delta;
- }
-
- return NULL;
+ MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, start_frame);
+ int index = plane_marker - plane_track->markers;
+ int frame_delta = direction > 0 ? 1 : -1;
+
+ while (index >= 0 && index < plane_track->markersnr) {
+ if ((plane_marker->flag & PLANE_MARKER_TRACKED) == 0) {
+ return plane_marker;
+ }
+ plane_marker += frame_delta;
+ }
+
+ return NULL;
}
-void BKE_tracking_retrack_plane_from_existing_motion_at_segment(MovieTrackingPlaneTrack *plane_track, int start_frame)
+void BKE_tracking_retrack_plane_from_existing_motion_at_segment(
+ MovieTrackingPlaneTrack *plane_track, int start_frame)
{
- MovieTrackingPlaneMarker *prev_plane_keyframe, *next_plane_keyframe;
-
- prev_plane_keyframe = find_plane_keyframe(plane_track, start_frame, -1);
- next_plane_keyframe = find_plane_keyframe(plane_track, start_frame, 1);
-
- if (prev_plane_keyframe != NULL && next_plane_keyframe != NULL) {
- /* First we track from left keyframe to the right one without any blending. */
- track_plane_from_existing_motion(plane_track, prev_plane_keyframe->framenr, 1, true);
-
- /* And then we track from the right keyframe to the left one, so shape blends in nicely */
- track_plane_from_existing_motion(plane_track, next_plane_keyframe->framenr, -1, false);
- }
- else if (prev_plane_keyframe != NULL) {
- track_plane_from_existing_motion(plane_track, prev_plane_keyframe->framenr, 1, true);
- }
- else if (next_plane_keyframe != NULL) {
- track_plane_from_existing_motion(plane_track, next_plane_keyframe->framenr, -1, true);
- }
+ MovieTrackingPlaneMarker *prev_plane_keyframe, *next_plane_keyframe;
+
+ prev_plane_keyframe = find_plane_keyframe(plane_track, start_frame, -1);
+ next_plane_keyframe = find_plane_keyframe(plane_track, start_frame, 1);
+
+ if (prev_plane_keyframe != NULL && next_plane_keyframe != NULL) {
+ /* First we track from left keyframe to the right one without any blending. */
+ track_plane_from_existing_motion(plane_track, prev_plane_keyframe->framenr, 1, true);
+
+ /* And then we track from the right keyframe to the left one, so shape blends in nicely */
+ track_plane_from_existing_motion(plane_track, next_plane_keyframe->framenr, -1, false);
+ }
+ else if (prev_plane_keyframe != NULL) {
+ track_plane_from_existing_motion(plane_track, prev_plane_keyframe->framenr, 1, true);
+ }
+ else if (next_plane_keyframe != NULL) {
+ track_plane_from_existing_motion(plane_track, next_plane_keyframe->framenr, -1, true);
+ }
}
BLI_INLINE void float_corners_to_double(/*const*/ float corners[4][2], double double_corners[4][2])
{
- copy_v2db_v2fl(double_corners[0], corners[0]);
- copy_v2db_v2fl(double_corners[1], corners[1]);
- copy_v2db_v2fl(double_corners[2], corners[2]);
- copy_v2db_v2fl(double_corners[3], corners[3]);
+ copy_v2db_v2fl(double_corners[0], corners[0]);
+ copy_v2db_v2fl(double_corners[1], corners[1]);
+ copy_v2db_v2fl(double_corners[2], corners[2]);
+ copy_v2db_v2fl(double_corners[3], corners[3]);
}
void BKE_tracking_homography_between_two_quads(/*const*/ float reference_corners[4][2],
/*const*/ float corners[4][2],
float H[3][3])
{
- Vec2 x1[4], x2[4];
- double H_double[3][3];
+ Vec2 x1[4], x2[4];
+ double H_double[3][3];
- float_corners_to_double(reference_corners, x1);
- float_corners_to_double(corners, x2);
+ float_corners_to_double(reference_corners, x1);
+ float_corners_to_double(corners, x2);
- libmv_homography2DFromCorrespondencesEuc(x1, x2, 4, H_double);
+ libmv_homography2DFromCorrespondencesEuc(x1, x2, 4, H_double);
- copy_m3_m3d(H, H_double);
+ copy_m3_m3d(H, H_double);
}
diff --git a/source/blender/blenkernel/intern/tracking_region_tracker.c b/source/blender/blenkernel/intern/tracking_region_tracker.c
index f6e07e8b459..a66a521783b 100644
--- a/source/blender/blenkernel/intern/tracking_region_tracker.c
+++ b/source/blender/blenkernel/intern/tracking_region_tracker.c
@@ -43,142 +43,167 @@
/* **** utility functions for tracking **** */
/* convert from float and byte RGBA to grayscale. Supports different coefficients for RGB. */
-static void float_rgba_to_gray(const float *rgba, float *gray, int num_pixels,
- float weight_red, float weight_green, float weight_blue)
+static void float_rgba_to_gray(const float *rgba,
+ float *gray,
+ int num_pixels,
+ float weight_red,
+ float weight_green,
+ float weight_blue)
{
- int i;
+ int i;
- for (i = 0; i < num_pixels; i++) {
- const float *pixel = rgba + 4 * i;
+ for (i = 0; i < num_pixels; i++) {
+ const float *pixel = rgba + 4 * i;
- gray[i] = weight_red * pixel[0] + weight_green * pixel[1] + weight_blue * pixel[2];
- }
+ gray[i] = weight_red * pixel[0] + weight_green * pixel[1] + weight_blue * pixel[2];
+ }
}
-static void uint8_rgba_to_float_gray(const unsigned char *rgba, float *gray, int num_pixels,
- float weight_red, float weight_green, float weight_blue)
+static void uint8_rgba_to_float_gray(const unsigned char *rgba,
+ float *gray,
+ int num_pixels,
+ float weight_red,
+ float weight_green,
+ float weight_blue)
{
- int i;
+ int i;
- for (i = 0; i < num_pixels; i++) {
- const unsigned char *pixel = rgba + i * 4;
+ for (i = 0; i < num_pixels; i++) {
+ const unsigned char *pixel = rgba + i * 4;
- gray[i] = (weight_red * pixel[0] + weight_green * pixel[1] + weight_blue * pixel[2]) / 255.0f;
- }
+ gray[i] = (weight_red * pixel[0] + weight_green * pixel[1] + weight_blue * pixel[2]) / 255.0f;
+ }
}
/* Get grayscale float search buffer for given marker and frame. */
-static float *track_get_search_floatbuf(ImBuf *ibuf, MovieTrackingTrack *track, MovieTrackingMarker *marker,
- int *width_r, int *height_r)
+static float *track_get_search_floatbuf(ImBuf *ibuf,
+ MovieTrackingTrack *track,
+ MovieTrackingMarker *marker,
+ int *width_r,
+ int *height_r)
{
- ImBuf *searchibuf;
- float *gray_pixels;
- int width, height;
+ ImBuf *searchibuf;
+ float *gray_pixels;
+ int width, height;
- searchibuf = BKE_tracking_get_search_imbuf(ibuf, track, marker, false, true);
+ searchibuf = BKE_tracking_get_search_imbuf(ibuf, track, marker, false, true);
- if (!searchibuf) {
- *width_r = 0;
- *height_r = 0;
- return NULL;
- }
+ if (!searchibuf) {
+ *width_r = 0;
+ *height_r = 0;
+ return NULL;
+ }
- width = searchibuf->x;
- height = searchibuf->y;
+ width = searchibuf->x;
+ height = searchibuf->y;
- gray_pixels = MEM_callocN(width * height * sizeof(float), "tracking floatBuf");
+ gray_pixels = MEM_callocN(width * height * sizeof(float), "tracking floatBuf");
- if (searchibuf->rect_float) {
- float_rgba_to_gray(searchibuf->rect_float, gray_pixels, width * height,
- 0.2126f, 0.7152f, 0.0722f);
- }
- else {
- uint8_rgba_to_float_gray((unsigned char *)searchibuf->rect, gray_pixels, width * height,
- 0.2126f, 0.7152f, 0.0722f);
- }
+ if (searchibuf->rect_float) {
+ float_rgba_to_gray(
+ searchibuf->rect_float, gray_pixels, width * height, 0.2126f, 0.7152f, 0.0722f);
+ }
+ else {
+ uint8_rgba_to_float_gray(
+ (unsigned char *)searchibuf->rect, gray_pixels, width * height, 0.2126f, 0.7152f, 0.0722f);
+ }
- IMB_freeImBuf(searchibuf);
+ IMB_freeImBuf(searchibuf);
- *width_r = width;
- *height_r = height;
+ *width_r = width;
+ *height_r = height;
- return gray_pixels;
+ return gray_pixels;
}
/* Get image buffer for a given frame
*
* Frame is in clip space.
*/
-static ImBuf *tracking_context_get_frame_ibuf(MovieClip *clip, MovieClipUser *user, int clip_flag, int framenr)
+static ImBuf *tracking_context_get_frame_ibuf(MovieClip *clip,
+ MovieClipUser *user,
+ int clip_flag,
+ int framenr)
{
- ImBuf *ibuf;
- MovieClipUser new_user = *user;
+ ImBuf *ibuf;
+ MovieClipUser new_user = *user;
- new_user.framenr = BKE_movieclip_remap_clip_to_scene_frame(clip, framenr);
+ new_user.framenr = BKE_movieclip_remap_clip_to_scene_frame(clip, framenr);
- ibuf = BKE_movieclip_get_ibuf_flag(clip, &new_user, clip_flag, MOVIECLIP_CACHE_SKIP);
+ ibuf = BKE_movieclip_get_ibuf_flag(clip, &new_user, clip_flag, MOVIECLIP_CACHE_SKIP);
- return ibuf;
+ return ibuf;
}
/* Get image buffer for previous marker's keyframe. */
-static ImBuf *tracking_context_get_keyframed_ibuf(MovieClip *clip, MovieClipUser *user, int clip_flag,
- MovieTrackingTrack *track, int curfra, bool backwards,
+static ImBuf *tracking_context_get_keyframed_ibuf(MovieClip *clip,
+ MovieClipUser *user,
+ int clip_flag,
+ MovieTrackingTrack *track,
+ int curfra,
+ bool backwards,
MovieTrackingMarker **marker_keyed_r)
{
- MovieTrackingMarker *marker_keyed;
- int keyed_framenr;
+ MovieTrackingMarker *marker_keyed;
+ int keyed_framenr;
- marker_keyed = tracking_get_keyframed_marker(track, curfra, backwards);
- if (marker_keyed == NULL) {
- return NULL;
- }
+ marker_keyed = tracking_get_keyframed_marker(track, curfra, backwards);
+ if (marker_keyed == NULL) {
+ return NULL;
+ }
- keyed_framenr = marker_keyed->framenr;
+ keyed_framenr = marker_keyed->framenr;
- *marker_keyed_r = marker_keyed;
+ *marker_keyed_r = marker_keyed;
- return tracking_context_get_frame_ibuf(clip, user, clip_flag, keyed_framenr);
+ return tracking_context_get_frame_ibuf(clip, user, clip_flag, keyed_framenr);
}
/* Get image buffer which si used as reference for track. */
-static ImBuf *tracking_context_get_reference_ibuf(MovieClip *clip, MovieClipUser *user, int clip_flag,
- MovieTrackingTrack *track, int curfra, bool backwards,
+static ImBuf *tracking_context_get_reference_ibuf(MovieClip *clip,
+ MovieClipUser *user,
+ int clip_flag,
+ MovieTrackingTrack *track,
+ int curfra,
+ bool backwards,
MovieTrackingMarker **reference_marker)
{
- ImBuf *ibuf = NULL;
+ ImBuf *ibuf = NULL;
- if (track->pattern_match == TRACK_MATCH_KEYFRAME) {
- ibuf = tracking_context_get_keyframed_ibuf(clip, user, clip_flag, track, curfra, backwards, reference_marker);
- }
- else {
- ibuf = tracking_context_get_frame_ibuf(clip, user, clip_flag, curfra);
+ if (track->pattern_match == TRACK_MATCH_KEYFRAME) {
+ ibuf = tracking_context_get_keyframed_ibuf(
+ clip, user, clip_flag, track, curfra, backwards, reference_marker);
+ }
+ else {
+ ibuf = tracking_context_get_frame_ibuf(clip, user, clip_flag, curfra);
- /* use current marker as keyframed position */
- *reference_marker = BKE_tracking_marker_get(track, curfra);
- }
+ /* use current marker as keyframed position */
+ *reference_marker = BKE_tracking_marker_get(track, curfra);
+ }
- return ibuf;
+ return ibuf;
}
/* Fill in libmv tracker options structure with settings need to be used to perform track. */
-void tracking_configure_tracker(const MovieTrackingTrack *track, float *mask,
+void tracking_configure_tracker(const MovieTrackingTrack *track,
+ float *mask,
libmv_TrackRegionOptions *options)
{
- options->motion_model = track->motion_model;
+ options->motion_model = track->motion_model;
- options->use_brute = ((track->algorithm_flag & TRACK_ALGORITHM_FLAG_USE_BRUTE) != 0);
+ options->use_brute = ((track->algorithm_flag & TRACK_ALGORITHM_FLAG_USE_BRUTE) != 0);
- options->use_normalization = ((track->algorithm_flag & TRACK_ALGORITHM_FLAG_USE_NORMALIZATION) != 0);
+ options->use_normalization = ((track->algorithm_flag & TRACK_ALGORITHM_FLAG_USE_NORMALIZATION) !=
+ 0);
- options->num_iterations = 50;
- options->minimum_correlation = track->minimum_correlation;
- options->sigma = 0.9;
+ options->num_iterations = 50;
+ options->minimum_correlation = track->minimum_correlation;
+ options->sigma = 0.9;
- if ((track->algorithm_flag & TRACK_ALGORITHM_FLAG_USE_MASK) != 0)
- options->image1_mask = mask;
- else
- options->image1_mask = NULL;
+ if ((track->algorithm_flag & TRACK_ALGORITHM_FLAG_USE_MASK) != 0)
+ options->image1_mask = mask;
+ else
+ options->image1_mask = NULL;
}
/* Perform tracking from a reference_marker to destination_ibuf.
@@ -187,61 +212,70 @@ void tracking_configure_tracker(const MovieTrackingTrack *track, float *mask,
* Returns truth if tracker returned success, puts result
* to dst_pixel_x and dst_pixel_y.
*/
-static bool configure_and_run_tracker(ImBuf *destination_ibuf, MovieTrackingTrack *track,
- MovieTrackingMarker *reference_marker, MovieTrackingMarker *marker,
- float *reference_search_area, int reference_search_area_width,
- int reference_search_area_height, float *mask,
- double dst_pixel_x[5], double dst_pixel_y[5])
+static bool configure_and_run_tracker(ImBuf *destination_ibuf,
+ MovieTrackingTrack *track,
+ MovieTrackingMarker *reference_marker,
+ MovieTrackingMarker *marker,
+ float *reference_search_area,
+ int reference_search_area_width,
+ int reference_search_area_height,
+ float *mask,
+ double dst_pixel_x[5],
+ double dst_pixel_y[5])
{
- /* To convert to the x/y split array format for libmv. */
- double src_pixel_x[5], src_pixel_y[5];
-
- /* Settings for the tracker */
- libmv_TrackRegionOptions options = {0};
- libmv_TrackRegionResult result;
-
- float *patch_new;
-
- int new_search_area_width, new_search_area_height;
- int frame_width, frame_height;
-
- bool tracked;
-
- frame_width = destination_ibuf->x;
- frame_height = destination_ibuf->y;
-
- /* for now track to the same search area dimension as marker has got for current frame
- * will make all tracked markers in currently tracked segment have the same search area
- * size, but it's quite close to what is actually needed
- */
- patch_new = track_get_search_floatbuf(destination_ibuf, track, marker,
- &new_search_area_width, &new_search_area_height);
-
- /* configure the tracker */
- tracking_configure_tracker(track, mask, &options);
-
- /* convert the marker corners and center into pixel coordinates in the search/destination images. */
- tracking_get_marker_coords_for_tracking(frame_width, frame_height, reference_marker, src_pixel_x, src_pixel_y);
- tracking_get_marker_coords_for_tracking(frame_width, frame_height, marker, dst_pixel_x, dst_pixel_y);
-
- if (patch_new == NULL || reference_search_area == NULL)
- return false;
-
- /* run the tracker! */
- tracked = libmv_trackRegion(&options,
- reference_search_area,
- reference_search_area_width,
- reference_search_area_height,
- patch_new,
- new_search_area_width,
- new_search_area_height,
- src_pixel_x, src_pixel_y,
- &result,
- dst_pixel_x, dst_pixel_y);
-
- MEM_freeN(patch_new);
-
- return tracked;
+ /* To convert to the x/y split array format for libmv. */
+ double src_pixel_x[5], src_pixel_y[5];
+
+ /* Settings for the tracker */
+ libmv_TrackRegionOptions options = {0};
+ libmv_TrackRegionResult result;
+
+ float *patch_new;
+
+ int new_search_area_width, new_search_area_height;
+ int frame_width, frame_height;
+
+ bool tracked;
+
+ frame_width = destination_ibuf->x;
+ frame_height = destination_ibuf->y;
+
+ /* for now track to the same search area dimension as marker has got for current frame
+ * will make all tracked markers in currently tracked segment have the same search area
+ * size, but it's quite close to what is actually needed
+ */
+ patch_new = track_get_search_floatbuf(
+ destination_ibuf, track, marker, &new_search_area_width, &new_search_area_height);
+
+ /* configure the tracker */
+ tracking_configure_tracker(track, mask, &options);
+
+ /* convert the marker corners and center into pixel coordinates in the search/destination images. */
+ tracking_get_marker_coords_for_tracking(
+ frame_width, frame_height, reference_marker, src_pixel_x, src_pixel_y);
+ tracking_get_marker_coords_for_tracking(
+ frame_width, frame_height, marker, dst_pixel_x, dst_pixel_y);
+
+ if (patch_new == NULL || reference_search_area == NULL)
+ return false;
+
+ /* run the tracker! */
+ tracked = libmv_trackRegion(&options,
+ reference_search_area,
+ reference_search_area_width,
+ reference_search_area_height,
+ patch_new,
+ new_search_area_width,
+ new_search_area_height,
+ src_pixel_x,
+ src_pixel_y,
+ &result,
+ dst_pixel_x,
+ dst_pixel_y);
+
+ MEM_freeN(patch_new);
+
+ return tracked;
}
static bool refine_marker_reference_frame_get(MovieTrackingTrack *track,
@@ -249,28 +283,24 @@ static bool refine_marker_reference_frame_get(MovieTrackingTrack *track,
bool backwards,
int *reference_framenr)
{
- const MovieTrackingMarker *first_marker = track->markers;
- const MovieTrackingMarker *last_marker = track->markers + track->markersnr - 1;
- MovieTrackingMarker *reference = backwards ? marker + 1 : marker - 1;
-
- while (reference >= first_marker &&
- reference <= last_marker &&
- (reference->flag & MARKER_DISABLED) != 0)
- {
- if (backwards)
- reference++;
- else
- reference--;
- }
-
- if (reference < first_marker ||
- reference > last_marker)
- {
- return false;
- }
-
- *reference_framenr = reference->framenr;
- return (reference->flag & MARKER_DISABLED) == 0;
+ const MovieTrackingMarker *first_marker = track->markers;
+ const MovieTrackingMarker *last_marker = track->markers + track->markersnr - 1;
+ MovieTrackingMarker *reference = backwards ? marker + 1 : marker - 1;
+
+ while (reference >= first_marker && reference <= last_marker &&
+ (reference->flag & MARKER_DISABLED) != 0) {
+ if (backwards)
+ reference++;
+ else
+ reference--;
+ }
+
+ if (reference < first_marker || reference > last_marker) {
+ return false;
+ }
+
+ *reference_framenr = reference->framenr;
+ return (reference->flag & MARKER_DISABLED) == 0;
}
/* Refine marker's position using previously known keyframe.
@@ -278,74 +308,81 @@ static bool refine_marker_reference_frame_get(MovieTrackingTrack *track,
* which means if backwards is false, previous keyframe will be as
* reference.
*/
-void BKE_tracking_refine_marker(MovieClip *clip, MovieTrackingTrack *track, MovieTrackingMarker *marker, bool backwards)
+void BKE_tracking_refine_marker(MovieClip *clip,
+ MovieTrackingTrack *track,
+ MovieTrackingMarker *marker,
+ bool backwards)
{
- MovieTrackingMarker *reference_marker = NULL;
- ImBuf *reference_ibuf, *destination_ibuf;
- float *search_area, *mask = NULL;
- int frame_width, frame_height;
- int search_area_height, search_area_width;
- int clip_flag = clip->flag & MCLIP_TIMECODE_FLAGS;
- int reference_framenr;
- MovieClipUser user = {0};
- double dst_pixel_x[5], dst_pixel_y[5];
- bool tracked;
-
- /* Construct a temporary clip used, used to acquire image buffers. */
- user.framenr = BKE_movieclip_remap_clip_to_scene_frame(clip, marker->framenr);
-
- BKE_movieclip_get_size(clip, &user, &frame_width, &frame_height);
-
- /* Get an image buffer for reference frame, also gets reference marker. */
- if (!refine_marker_reference_frame_get(track,
- marker,
- backwards,
- &reference_framenr))
- {
- return;
- }
-
- reference_ibuf = tracking_context_get_reference_ibuf(clip, &user, clip_flag, track, reference_framenr,
- backwards, &reference_marker);
- if (reference_ibuf == NULL) {
- return;
- }
-
- /* Could not refine with self. */
- if (reference_marker == marker) {
- return;
- }
-
- /* Destination image buffer has got frame number corresponding to refining marker. */
- destination_ibuf = BKE_movieclip_get_ibuf_flag(clip, &user, clip_flag, MOVIECLIP_CACHE_SKIP);
- if (destination_ibuf == NULL) {
- IMB_freeImBuf(reference_ibuf);
- return;
- }
-
- /* Get search area from reference image. */
- search_area = track_get_search_floatbuf(reference_ibuf, track, reference_marker,
- &search_area_width, &search_area_height);
-
- /* If needed, compute track's mask. */
- if ((track->algorithm_flag & TRACK_ALGORITHM_FLAG_USE_MASK) != 0)
- mask = BKE_tracking_track_get_mask(frame_width, frame_height, track, marker);
-
- /* Run the tracker from reference frame to current one. */
- tracked = configure_and_run_tracker(destination_ibuf, track, reference_marker, marker,
- search_area, search_area_width, search_area_height,
- mask, dst_pixel_x, dst_pixel_y);
-
- /* Refine current marker's position if track was successful. */
- if (tracked) {
- tracking_set_marker_coords_from_tracking(frame_width, frame_height, marker, dst_pixel_x, dst_pixel_y);
- marker->flag |= MARKER_TRACKED;
- }
-
- /* Free memory used for refining */
- MEM_freeN(search_area);
- if (mask)
- MEM_freeN(mask);
- IMB_freeImBuf(reference_ibuf);
- IMB_freeImBuf(destination_ibuf);
+ MovieTrackingMarker *reference_marker = NULL;
+ ImBuf *reference_ibuf, *destination_ibuf;
+ float *search_area, *mask = NULL;
+ int frame_width, frame_height;
+ int search_area_height, search_area_width;
+ int clip_flag = clip->flag & MCLIP_TIMECODE_FLAGS;
+ int reference_framenr;
+ MovieClipUser user = {0};
+ double dst_pixel_x[5], dst_pixel_y[5];
+ bool tracked;
+
+ /* Construct a temporary clip used, used to acquire image buffers. */
+ user.framenr = BKE_movieclip_remap_clip_to_scene_frame(clip, marker->framenr);
+
+ BKE_movieclip_get_size(clip, &user, &frame_width, &frame_height);
+
+ /* Get an image buffer for reference frame, also gets reference marker. */
+ if (!refine_marker_reference_frame_get(track, marker, backwards, &reference_framenr)) {
+ return;
+ }
+
+ reference_ibuf = tracking_context_get_reference_ibuf(
+ clip, &user, clip_flag, track, reference_framenr, backwards, &reference_marker);
+ if (reference_ibuf == NULL) {
+ return;
+ }
+
+ /* Could not refine with self. */
+ if (reference_marker == marker) {
+ return;
+ }
+
+ /* Destination image buffer has got frame number corresponding to refining marker. */
+ destination_ibuf = BKE_movieclip_get_ibuf_flag(clip, &user, clip_flag, MOVIECLIP_CACHE_SKIP);
+ if (destination_ibuf == NULL) {
+ IMB_freeImBuf(reference_ibuf);
+ return;
+ }
+
+ /* Get search area from reference image. */
+ search_area = track_get_search_floatbuf(
+ reference_ibuf, track, reference_marker, &search_area_width, &search_area_height);
+
+ /* If needed, compute track's mask. */
+ if ((track->algorithm_flag & TRACK_ALGORITHM_FLAG_USE_MASK) != 0)
+ mask = BKE_tracking_track_get_mask(frame_width, frame_height, track, marker);
+
+ /* Run the tracker from reference frame to current one. */
+ tracked = configure_and_run_tracker(destination_ibuf,
+ track,
+ reference_marker,
+ marker,
+ search_area,
+ search_area_width,
+ search_area_height,
+ mask,
+ dst_pixel_x,
+ dst_pixel_y);
+
+ /* Refine current marker's position if track was successful. */
+ if (tracked) {
+ tracking_set_marker_coords_from_tracking(
+ frame_width, frame_height, marker, dst_pixel_x, dst_pixel_y);
+ marker->flag |= MARKER_TRACKED;
+ }
+
+ /* Free memory used for refining */
+ MEM_freeN(search_area);
+ if (mask)
+ MEM_freeN(mask);
+ IMB_freeImBuf(reference_ibuf);
+ IMB_freeImBuf(destination_ibuf);
}
diff --git a/source/blender/blenkernel/intern/tracking_solver.c b/source/blender/blenkernel/intern/tracking_solver.c
index 51bd4c3c871..c3759fd01bb 100644
--- a/source/blender/blenkernel/intern/tracking_solver.c
+++ b/source/blender/blenkernel/intern/tracking_solver.c
@@ -47,293 +47,303 @@
#include "tracking_private.h"
typedef struct MovieReconstructContext {
- struct libmv_Tracks *tracks;
- bool select_keyframes;
- int keyframe1, keyframe2;
- int refine_flags;
+ struct libmv_Tracks *tracks;
+ bool select_keyframes;
+ int keyframe1, keyframe2;
+ int refine_flags;
- struct libmv_Reconstruction *reconstruction;
+ struct libmv_Reconstruction *reconstruction;
- char object_name[MAX_NAME];
- bool is_camera;
- short motion_flag;
+ char object_name[MAX_NAME];
+ bool is_camera;
+ short motion_flag;
- libmv_CameraIntrinsicsOptions camera_intrinsics_options;
+ libmv_CameraIntrinsicsOptions camera_intrinsics_options;
- float reprojection_error;
+ float reprojection_error;
- TracksMap *tracks_map;
+ TracksMap *tracks_map;
- int sfra, efra;
+ int sfra, efra;
} MovieReconstructContext;
typedef struct ReconstructProgressData {
- short *stop;
- short *do_update;
- float *progress;
- char *stats_message;
- int message_size;
+ short *stop;
+ short *do_update;
+ float *progress;
+ char *stats_message;
+ int message_size;
} ReconstructProgressData;
/* Create new libmv Tracks structure from blender's tracks list. */
-static struct libmv_Tracks *libmv_tracks_new(MovieClip *clip, ListBase *tracksbase, int width, int height)
+static struct libmv_Tracks *libmv_tracks_new(MovieClip *clip,
+ ListBase *tracksbase,
+ int width,
+ int height)
{
- int tracknr = 0;
- MovieTrackingTrack *track;
- struct libmv_Tracks *tracks = libmv_tracksNew();
-
- track = tracksbase->first;
- while (track) {
- FCurve *weight_fcurve;
- int a = 0;
-
- weight_fcurve = id_data_find_fcurve(&clip->id, track, &RNA_MovieTrackingTrack,
- "weight", 0, NULL);
-
- for (a = 0; a < track->markersnr; a++) {
- MovieTrackingMarker *marker = &track->markers[a];
-
- if ((marker->flag & MARKER_DISABLED) == 0) {
- float weight = track->weight;
-
- if (weight_fcurve) {
- int scene_framenr =
- BKE_movieclip_remap_clip_to_scene_frame(clip, marker->framenr);
- weight = evaluate_fcurve(weight_fcurve, scene_framenr);
- }
-
- libmv_tracksInsert(tracks, marker->framenr, tracknr,
- (marker->pos[0] + track->offset[0]) * width,
- (marker->pos[1] + track->offset[1]) * height,
- weight);
- }
- }
-
- track = track->next;
- tracknr++;
- }
-
- return tracks;
+ int tracknr = 0;
+ MovieTrackingTrack *track;
+ struct libmv_Tracks *tracks = libmv_tracksNew();
+
+ track = tracksbase->first;
+ while (track) {
+ FCurve *weight_fcurve;
+ int a = 0;
+
+ weight_fcurve = id_data_find_fcurve(
+ &clip->id, track, &RNA_MovieTrackingTrack, "weight", 0, NULL);
+
+ for (a = 0; a < track->markersnr; a++) {
+ MovieTrackingMarker *marker = &track->markers[a];
+
+ if ((marker->flag & MARKER_DISABLED) == 0) {
+ float weight = track->weight;
+
+ if (weight_fcurve) {
+ int scene_framenr = BKE_movieclip_remap_clip_to_scene_frame(clip, marker->framenr);
+ weight = evaluate_fcurve(weight_fcurve, scene_framenr);
+ }
+
+ libmv_tracksInsert(tracks,
+ marker->framenr,
+ tracknr,
+ (marker->pos[0] + track->offset[0]) * width,
+ (marker->pos[1] + track->offset[1]) * height,
+ weight);
+ }
+ }
+
+ track = track->next;
+ tracknr++;
+ }
+
+ return tracks;
}
/* Retrieve refined camera intrinsics from libmv to blender. */
-static void reconstruct_retrieve_libmv_intrinsics(MovieReconstructContext *context, MovieTracking *tracking)
+static void reconstruct_retrieve_libmv_intrinsics(MovieReconstructContext *context,
+ MovieTracking *tracking)
{
- struct libmv_Reconstruction *libmv_reconstruction = context->reconstruction;
- struct libmv_CameraIntrinsics *libmv_intrinsics = libmv_reconstructionExtractIntrinsics(libmv_reconstruction);
+ struct libmv_Reconstruction *libmv_reconstruction = context->reconstruction;
+ struct libmv_CameraIntrinsics *libmv_intrinsics = libmv_reconstructionExtractIntrinsics(
+ libmv_reconstruction);
- libmv_CameraIntrinsicsOptions camera_intrinsics_options;
- libmv_cameraIntrinsicsExtractOptions(libmv_intrinsics, &camera_intrinsics_options);
+ libmv_CameraIntrinsicsOptions camera_intrinsics_options;
+ libmv_cameraIntrinsicsExtractOptions(libmv_intrinsics, &camera_intrinsics_options);
- tracking_trackingCameraFromIntrinscisOptions(tracking,
- &camera_intrinsics_options);
+ tracking_trackingCameraFromIntrinscisOptions(tracking, &camera_intrinsics_options);
}
/* Retrieve reconstructed tracks from libmv to blender.
* Actually, this also copies reconstructed cameras
* from libmv to movie clip datablock.
*/
-static bool reconstruct_retrieve_libmv_tracks(MovieReconstructContext *context, MovieTracking *tracking)
+static bool reconstruct_retrieve_libmv_tracks(MovieReconstructContext *context,
+ MovieTracking *tracking)
{
- struct libmv_Reconstruction *libmv_reconstruction = context->reconstruction;
- MovieTrackingReconstruction *reconstruction = NULL;
- MovieReconstructedCamera *reconstructed;
- MovieTrackingTrack *track;
- ListBase *tracksbase = NULL;
- int tracknr = 0, a;
- bool ok = true;
- bool origin_set = false;
- int sfra = context->sfra, efra = context->efra;
- float imat[4][4];
-
- if (context->is_camera) {
- tracksbase = &tracking->tracks;
- reconstruction = &tracking->reconstruction;
- }
- else {
- MovieTrackingObject *object = BKE_tracking_object_get_named(tracking, context->object_name);
-
- tracksbase = &object->tracks;
- reconstruction = &object->reconstruction;
- }
-
- unit_m4(imat);
-
- track = tracksbase->first;
- while (track) {
- double pos[3];
-
- if (libmv_reprojectionPointForTrack(libmv_reconstruction, tracknr, pos)) {
- track->bundle_pos[0] = pos[0];
- track->bundle_pos[1] = pos[1];
- track->bundle_pos[2] = pos[2];
-
- track->flag |= TRACK_HAS_BUNDLE;
- track->error = libmv_reprojectionErrorForTrack(libmv_reconstruction, tracknr);
- }
- else {
- track->flag &= ~TRACK_HAS_BUNDLE;
- ok = false;
-
- printf("Unable to reconstruct position for track #%d '%s'\n", tracknr, track->name);
- }
-
- track = track->next;
- tracknr++;
- }
-
- if (reconstruction->cameras)
- MEM_freeN(reconstruction->cameras);
-
- reconstruction->camnr = 0;
- reconstruction->cameras = NULL;
- reconstructed = MEM_callocN((efra - sfra + 1) * sizeof(MovieReconstructedCamera),
- "temp reconstructed camera");
-
- for (a = sfra; a <= efra; a++) {
- double matd[4][4];
-
- if (libmv_reprojectionCameraForImage(libmv_reconstruction, a, matd)) {
- int i, j;
- float mat[4][4];
- float error = libmv_reprojectionErrorForImage(libmv_reconstruction, a);
-
- for (i = 0; i < 4; i++) {
- for (j = 0; j < 4; j++)
- mat[i][j] = matd[i][j];
- }
-
- /* Ensure first camera has got zero rotation and transform.
- * This is essential for object tracking to work -- this way
- * we'll always know object and environment are properly
- * oriented.
- *
- * There's one weak part tho, which is requirement object
- * motion starts at the same frame as camera motion does,
- * otherwise that;' be a russian roulette whether object is
- * aligned correct or not.
- */
- if (!origin_set) {
- invert_m4_m4(imat, mat);
- unit_m4(mat);
- origin_set = true;
- }
- else {
- mul_m4_m4m4(mat, imat, mat);
- }
-
- copy_m4_m4(reconstructed[reconstruction->camnr].mat, mat);
- reconstructed[reconstruction->camnr].framenr = a;
- reconstructed[reconstruction->camnr].error = error;
- reconstruction->camnr++;
- }
- else {
- ok = false;
- printf("No camera for frame %d\n", a);
- }
- }
-
- if (reconstruction->camnr) {
- int size = reconstruction->camnr * sizeof(MovieReconstructedCamera);
- reconstruction->cameras = MEM_callocN(size, "reconstructed camera");
- memcpy(reconstruction->cameras, reconstructed, size);
- }
-
- if (origin_set) {
- track = tracksbase->first;
- while (track) {
- if (track->flag & TRACK_HAS_BUNDLE)
- mul_v3_m4v3(track->bundle_pos, imat, track->bundle_pos);
-
- track = track->next;
- }
- }
-
- MEM_freeN(reconstructed);
-
- return ok;
+ struct libmv_Reconstruction *libmv_reconstruction = context->reconstruction;
+ MovieTrackingReconstruction *reconstruction = NULL;
+ MovieReconstructedCamera *reconstructed;
+ MovieTrackingTrack *track;
+ ListBase *tracksbase = NULL;
+ int tracknr = 0, a;
+ bool ok = true;
+ bool origin_set = false;
+ int sfra = context->sfra, efra = context->efra;
+ float imat[4][4];
+
+ if (context->is_camera) {
+ tracksbase = &tracking->tracks;
+ reconstruction = &tracking->reconstruction;
+ }
+ else {
+ MovieTrackingObject *object = BKE_tracking_object_get_named(tracking, context->object_name);
+
+ tracksbase = &object->tracks;
+ reconstruction = &object->reconstruction;
+ }
+
+ unit_m4(imat);
+
+ track = tracksbase->first;
+ while (track) {
+ double pos[3];
+
+ if (libmv_reprojectionPointForTrack(libmv_reconstruction, tracknr, pos)) {
+ track->bundle_pos[0] = pos[0];
+ track->bundle_pos[1] = pos[1];
+ track->bundle_pos[2] = pos[2];
+
+ track->flag |= TRACK_HAS_BUNDLE;
+ track->error = libmv_reprojectionErrorForTrack(libmv_reconstruction, tracknr);
+ }
+ else {
+ track->flag &= ~TRACK_HAS_BUNDLE;
+ ok = false;
+
+ printf("Unable to reconstruct position for track #%d '%s'\n", tracknr, track->name);
+ }
+
+ track = track->next;
+ tracknr++;
+ }
+
+ if (reconstruction->cameras)
+ MEM_freeN(reconstruction->cameras);
+
+ reconstruction->camnr = 0;
+ reconstruction->cameras = NULL;
+ reconstructed = MEM_callocN((efra - sfra + 1) * sizeof(MovieReconstructedCamera),
+ "temp reconstructed camera");
+
+ for (a = sfra; a <= efra; a++) {
+ double matd[4][4];
+
+ if (libmv_reprojectionCameraForImage(libmv_reconstruction, a, matd)) {
+ int i, j;
+ float mat[4][4];
+ float error = libmv_reprojectionErrorForImage(libmv_reconstruction, a);
+
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 4; j++)
+ mat[i][j] = matd[i][j];
+ }
+
+ /* Ensure first camera has got zero rotation and transform.
+ * This is essential for object tracking to work -- this way
+ * we'll always know object and environment are properly
+ * oriented.
+ *
+ * There's one weak part tho, which is requirement object
+ * motion starts at the same frame as camera motion does,
+ * otherwise that;' be a russian roulette whether object is
+ * aligned correct or not.
+ */
+ if (!origin_set) {
+ invert_m4_m4(imat, mat);
+ unit_m4(mat);
+ origin_set = true;
+ }
+ else {
+ mul_m4_m4m4(mat, imat, mat);
+ }
+
+ copy_m4_m4(reconstructed[reconstruction->camnr].mat, mat);
+ reconstructed[reconstruction->camnr].framenr = a;
+ reconstructed[reconstruction->camnr].error = error;
+ reconstruction->camnr++;
+ }
+ else {
+ ok = false;
+ printf("No camera for frame %d\n", a);
+ }
+ }
+
+ if (reconstruction->camnr) {
+ int size = reconstruction->camnr * sizeof(MovieReconstructedCamera);
+ reconstruction->cameras = MEM_callocN(size, "reconstructed camera");
+ memcpy(reconstruction->cameras, reconstructed, size);
+ }
+
+ if (origin_set) {
+ track = tracksbase->first;
+ while (track) {
+ if (track->flag & TRACK_HAS_BUNDLE)
+ mul_v3_m4v3(track->bundle_pos, imat, track->bundle_pos);
+
+ track = track->next;
+ }
+ }
+
+ MEM_freeN(reconstructed);
+
+ return ok;
}
/* Retrieve all the libmv data from context to blender's side data blocks. */
static int reconstruct_retrieve_libmv(MovieReconstructContext *context, MovieTracking *tracking)
{
- /* take the intrinsics back from libmv */
- reconstruct_retrieve_libmv_intrinsics(context, tracking);
+ /* take the intrinsics back from libmv */
+ reconstruct_retrieve_libmv_intrinsics(context, tracking);
- return reconstruct_retrieve_libmv_tracks(context, tracking);
+ return reconstruct_retrieve_libmv_tracks(context, tracking);
}
/* Convert blender's refinement flags to libmv's. */
-static int reconstruct_refine_intrinsics_get_flags(MovieTracking *tracking, MovieTrackingObject *object)
+static int reconstruct_refine_intrinsics_get_flags(MovieTracking *tracking,
+ MovieTrackingObject *object)
{
- int refine = tracking->settings.refine_camera_intrinsics;
- int flags = 0;
+ int refine = tracking->settings.refine_camera_intrinsics;
+ int flags = 0;
- if ((object->flag & TRACKING_OBJECT_CAMERA) == 0)
- return 0;
+ if ((object->flag & TRACKING_OBJECT_CAMERA) == 0)
+ return 0;
- if (refine & REFINE_FOCAL_LENGTH)
- flags |= LIBMV_REFINE_FOCAL_LENGTH;
+ if (refine & REFINE_FOCAL_LENGTH)
+ flags |= LIBMV_REFINE_FOCAL_LENGTH;
- if (refine & REFINE_PRINCIPAL_POINT)
- flags |= LIBMV_REFINE_PRINCIPAL_POINT;
+ if (refine & REFINE_PRINCIPAL_POINT)
+ flags |= LIBMV_REFINE_PRINCIPAL_POINT;
- if (refine & REFINE_RADIAL_DISTORTION_K1)
- flags |= LIBMV_REFINE_RADIAL_DISTORTION_K1;
+ if (refine & REFINE_RADIAL_DISTORTION_K1)
+ flags |= LIBMV_REFINE_RADIAL_DISTORTION_K1;
- if (refine & REFINE_RADIAL_DISTORTION_K2)
- flags |= LIBMV_REFINE_RADIAL_DISTORTION_K2;
+ if (refine & REFINE_RADIAL_DISTORTION_K2)
+ flags |= LIBMV_REFINE_RADIAL_DISTORTION_K2;
- return flags;
+ return flags;
}
/* Count tracks which has markers at both of keyframes. */
-static int reconstruct_count_tracks_on_both_keyframes(MovieTracking *tracking, MovieTrackingObject *object)
+static int reconstruct_count_tracks_on_both_keyframes(MovieTracking *tracking,
+ MovieTrackingObject *object)
{
- ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
- int tot = 0;
- int frame1 = object->keyframe1, frame2 = object->keyframe2;
- MovieTrackingTrack *track;
-
- track = tracksbase->first;
- while (track) {
- if (BKE_tracking_track_has_enabled_marker_at_frame(track, frame1)) {
- if (BKE_tracking_track_has_enabled_marker_at_frame(track, frame2)) {
- tot++;
- }
- }
-
- track = track->next;
- }
-
- return tot;
+ ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
+ int tot = 0;
+ int frame1 = object->keyframe1, frame2 = object->keyframe2;
+ MovieTrackingTrack *track;
+
+ track = tracksbase->first;
+ while (track) {
+ if (BKE_tracking_track_has_enabled_marker_at_frame(track, frame1)) {
+ if (BKE_tracking_track_has_enabled_marker_at_frame(track, frame2)) {
+ tot++;
+ }
+ }
+
+ track = track->next;
+ }
+
+ return tot;
}
/* Perform early check on whether everything is fine to start reconstruction. */
-bool BKE_tracking_reconstruction_check(MovieTracking *tracking, MovieTrackingObject *object,
- char *error_msg, int error_size)
+bool BKE_tracking_reconstruction_check(MovieTracking *tracking,
+ MovieTrackingObject *object,
+ char *error_msg,
+ int error_size)
{
- if (tracking->settings.motion_flag & TRACKING_MOTION_MODAL) {
- /* TODO: check for number of tracks? */
- return true;
- }
- else if ((tracking->settings.reconstruction_flag & TRACKING_USE_KEYFRAME_SELECTION) == 0) {
- /* automatic keyframe selection does not require any pre-process checks */
- if (reconstruct_count_tracks_on_both_keyframes(tracking, object) < 8) {
- BLI_strncpy(error_msg,
- N_("At least 8 common tracks on both keyframes are needed for reconstruction"),
- error_size);
-
- return false;
- }
- }
+ if (tracking->settings.motion_flag & TRACKING_MOTION_MODAL) {
+ /* TODO: check for number of tracks? */
+ return true;
+ }
+ else if ((tracking->settings.reconstruction_flag & TRACKING_USE_KEYFRAME_SELECTION) == 0) {
+ /* automatic keyframe selection does not require any pre-process checks */
+ if (reconstruct_count_tracks_on_both_keyframes(tracking, object) < 8) {
+ BLI_strncpy(error_msg,
+ N_("At least 8 common tracks on both keyframes are needed for reconstruction"),
+ error_size);
+
+ return false;
+ }
+ }
#ifndef WITH_LIBMV
- BLI_strncpy(error_msg, N_("Blender is compiled without motion tracking library"), error_size);
- return false;
+ BLI_strncpy(error_msg, N_("Blender is compiled without motion tracking library"), error_size);
+ return false;
#endif
- return true;
+ return true;
}
/* Create context for camera/object motion reconstruction.
@@ -341,106 +351,111 @@ bool BKE_tracking_reconstruction_check(MovieTracking *tracking, MovieTrackingObj
* clip datablock, so editing this clip is safe during
* reconstruction job is in progress.
*/
-MovieReconstructContext *BKE_tracking_reconstruction_context_new(MovieClip *clip, MovieTrackingObject *object,
- int keyframe1, int keyframe2, int width, int height)
+MovieReconstructContext *BKE_tracking_reconstruction_context_new(MovieClip *clip,
+ MovieTrackingObject *object,
+ int keyframe1,
+ int keyframe2,
+ int width,
+ int height)
{
- MovieTracking *tracking = &clip->tracking;
- MovieReconstructContext *context = MEM_callocN(sizeof(MovieReconstructContext), "MovieReconstructContext data");
- ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
- float aspy = 1.0f / tracking->camera.pixel_aspect;
- int num_tracks = BLI_listbase_count(tracksbase);
- int sfra = INT_MAX, efra = INT_MIN;
- MovieTrackingTrack *track;
+ MovieTracking *tracking = &clip->tracking;
+ MovieReconstructContext *context = MEM_callocN(sizeof(MovieReconstructContext),
+ "MovieReconstructContext data");
+ ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
+ float aspy = 1.0f / tracking->camera.pixel_aspect;
+ int num_tracks = BLI_listbase_count(tracksbase);
+ int sfra = INT_MAX, efra = INT_MIN;
+ MovieTrackingTrack *track;
- BLI_strncpy(context->object_name, object->name, sizeof(context->object_name));
- context->is_camera = object->flag & TRACKING_OBJECT_CAMERA;
- context->motion_flag = tracking->settings.motion_flag;
+ BLI_strncpy(context->object_name, object->name, sizeof(context->object_name));
+ context->is_camera = object->flag & TRACKING_OBJECT_CAMERA;
+ context->motion_flag = tracking->settings.motion_flag;
- context->select_keyframes =
- (tracking->settings.reconstruction_flag & TRACKING_USE_KEYFRAME_SELECTION) != 0;
+ context->select_keyframes = (tracking->settings.reconstruction_flag &
+ TRACKING_USE_KEYFRAME_SELECTION) != 0;
- tracking_cameraIntrinscisOptionsFromTracking(tracking,
- width, height,
- &context->camera_intrinsics_options);
+ tracking_cameraIntrinscisOptionsFromTracking(
+ tracking, width, height, &context->camera_intrinsics_options);
- context->tracks_map = tracks_map_new(context->object_name, context->is_camera, num_tracks, 0);
+ context->tracks_map = tracks_map_new(context->object_name, context->is_camera, num_tracks, 0);
- track = tracksbase->first;
- while (track) {
- int first = 0, last = track->markersnr - 1;
- MovieTrackingMarker *first_marker = &track->markers[0];
- MovieTrackingMarker *last_marker = &track->markers[track->markersnr - 1];
+ track = tracksbase->first;
+ while (track) {
+ int first = 0, last = track->markersnr - 1;
+ MovieTrackingMarker *first_marker = &track->markers[0];
+ MovieTrackingMarker *last_marker = &track->markers[track->markersnr - 1];
- /* find first not-disabled marker */
- while (first <= track->markersnr - 1 && first_marker->flag & MARKER_DISABLED) {
- first++;
- first_marker++;
- }
+ /* find first not-disabled marker */
+ while (first <= track->markersnr - 1 && first_marker->flag & MARKER_DISABLED) {
+ first++;
+ first_marker++;
+ }
- /* find last not-disabled marker */
- while (last >= 0 && last_marker->flag & MARKER_DISABLED) {
- last--;
- last_marker--;
- }
+ /* find last not-disabled marker */
+ while (last >= 0 && last_marker->flag & MARKER_DISABLED) {
+ last--;
+ last_marker--;
+ }
- if (first <= track->markersnr - 1)
- sfra = min_ii(sfra, first_marker->framenr);
+ if (first <= track->markersnr - 1)
+ sfra = min_ii(sfra, first_marker->framenr);
- if (last >= 0)
- efra = max_ii(efra, last_marker->framenr);
+ if (last >= 0)
+ efra = max_ii(efra, last_marker->framenr);
- tracks_map_insert(context->tracks_map, track, NULL);
+ tracks_map_insert(context->tracks_map, track, NULL);
- track = track->next;
- }
+ track = track->next;
+ }
- context->sfra = sfra;
- context->efra = efra;
+ context->sfra = sfra;
+ context->efra = efra;
- context->tracks = libmv_tracks_new(clip, tracksbase, width, height * aspy);
- context->keyframe1 = keyframe1;
- context->keyframe2 = keyframe2;
- context->refine_flags = reconstruct_refine_intrinsics_get_flags(tracking, object);
+ context->tracks = libmv_tracks_new(clip, tracksbase, width, height * aspy);
+ context->keyframe1 = keyframe1;
+ context->keyframe2 = keyframe2;
+ context->refine_flags = reconstruct_refine_intrinsics_get_flags(tracking, object);
- return context;
+ return context;
}
/* Free memory used by a reconstruction process. */
void BKE_tracking_reconstruction_context_free(MovieReconstructContext *context)
{
- if (context->reconstruction)
- libmv_reconstructionDestroy(context->reconstruction);
+ if (context->reconstruction)
+ libmv_reconstructionDestroy(context->reconstruction);
- libmv_tracksDestroy(context->tracks);
+ libmv_tracksDestroy(context->tracks);
- tracks_map_free(context->tracks_map, NULL);
+ tracks_map_free(context->tracks_map, NULL);
- MEM_freeN(context);
+ MEM_freeN(context);
}
/* Callback which is called from libmv side to update progress in the interface. */
static void reconstruct_update_solve_cb(void *customdata, double progress, const char *message)
{
- ReconstructProgressData *progressdata = customdata;
+ ReconstructProgressData *progressdata = customdata;
- if (progressdata->progress) {
- *progressdata->progress = progress;
- *progressdata->do_update = true;
- }
+ if (progressdata->progress) {
+ *progressdata->progress = progress;
+ *progressdata->do_update = true;
+ }
- BLI_snprintf(progressdata->stats_message, progressdata->message_size, "Solving camera | %s", message);
+ BLI_snprintf(
+ progressdata->stats_message, progressdata->message_size, "Solving camera | %s", message);
}
/* Fill in reconstruction options structure from reconstruction context. */
static void reconstructionOptionsFromContext(libmv_ReconstructionOptions *reconstruction_options,
MovieReconstructContext *context)
{
- reconstruction_options->select_keyframes = context->select_keyframes;
+ reconstruction_options->select_keyframes = context->select_keyframes;
- reconstruction_options->keyframe1 = context->keyframe1;
- reconstruction_options->keyframe2 = context->keyframe2;
+ reconstruction_options->keyframe1 = context->keyframe1;
+ reconstruction_options->keyframe2 = context->keyframe2;
- reconstruction_options->refine_intrinsics = context->refine_flags;
+ reconstruction_options->refine_intrinsics = context->refine_flags;
}
/* Solve camera/object motion and reconstruct 3D markers position
@@ -452,45 +467,51 @@ static void reconstructionOptionsFromContext(libmv_ReconstructionOptions *recons
* do_update, progress and stat_message are set by reconstruction
* callback in libmv side and passing to an interface.
*/
-void BKE_tracking_reconstruction_solve(MovieReconstructContext *context, short *stop, short *do_update,
- float *progress, char *stats_message, int message_size)
+void BKE_tracking_reconstruction_solve(MovieReconstructContext *context,
+ short *stop,
+ short *do_update,
+ float *progress,
+ char *stats_message,
+ int message_size)
{
- float error;
-
- ReconstructProgressData progressdata;
-
- libmv_ReconstructionOptions reconstruction_options;
-
- progressdata.stop = stop;
- progressdata.do_update = do_update;
- progressdata.progress = progress;
- progressdata.stats_message = stats_message;
- progressdata.message_size = message_size;
-
- reconstructionOptionsFromContext(&reconstruction_options, context);
-
- if (context->motion_flag & TRACKING_MOTION_MODAL) {
- context->reconstruction = libmv_solveModal(context->tracks,
- &context->camera_intrinsics_options,
- &reconstruction_options,
- reconstruct_update_solve_cb, &progressdata);
- }
- else {
- context->reconstruction = libmv_solveReconstruction(context->tracks,
- &context->camera_intrinsics_options,
- &reconstruction_options,
- reconstruct_update_solve_cb, &progressdata);
-
- if (context->select_keyframes) {
- /* store actual keyframes used for reconstruction to update them in the interface later */
- context->keyframe1 = reconstruction_options.keyframe1;
- context->keyframe2 = reconstruction_options.keyframe2;
- }
- }
-
- error = libmv_reprojectionError(context->reconstruction);
-
- context->reprojection_error = error;
+ float error;
+
+ ReconstructProgressData progressdata;
+
+ libmv_ReconstructionOptions reconstruction_options;
+
+ progressdata.stop = stop;
+ progressdata.do_update = do_update;
+ progressdata.progress = progress;
+ progressdata.stats_message = stats_message;
+ progressdata.message_size = message_size;
+
+ reconstructionOptionsFromContext(&reconstruction_options, context);
+
+ if (context->motion_flag & TRACKING_MOTION_MODAL) {
+ context->reconstruction = libmv_solveModal(context->tracks,
+ &context->camera_intrinsics_options,
+ &reconstruction_options,
+ reconstruct_update_solve_cb,
+ &progressdata);
+ }
+ else {
+ context->reconstruction = libmv_solveReconstruction(context->tracks,
+ &context->camera_intrinsics_options,
+ &reconstruction_options,
+ reconstruct_update_solve_cb,
+ &progressdata);
+
+ if (context->select_keyframes) {
+ /* store actual keyframes used for reconstruction to update them in the interface later */
+ context->keyframe1 = reconstruction_options.keyframe1;
+ context->keyframe2 = reconstruction_options.keyframe2;
+ }
+ }
+
+ error = libmv_reprojectionError(context->reconstruction);
+
+ context->reprojection_error = error;
}
/* Finish reconstruction process by copying reconstructed data
@@ -498,62 +519,63 @@ void BKE_tracking_reconstruction_solve(MovieReconstructContext *context, short *
*/
bool BKE_tracking_reconstruction_finish(MovieReconstructContext *context, MovieTracking *tracking)
{
- MovieTrackingReconstruction *reconstruction;
- MovieTrackingObject *object;
+ MovieTrackingReconstruction *reconstruction;
+ MovieTrackingObject *object;
- if (!libmv_reconstructionIsValid(context->reconstruction)) {
- printf("Failed solve the motion: most likely there are no good keyframes\n");
- return false;
- }
+ if (!libmv_reconstructionIsValid(context->reconstruction)) {
+ printf("Failed solve the motion: most likely there are no good keyframes\n");
+ return false;
+ }
- tracks_map_merge(context->tracks_map, tracking);
- BKE_tracking_dopesheet_tag_update(tracking);
+ tracks_map_merge(context->tracks_map, tracking);
+ BKE_tracking_dopesheet_tag_update(tracking);
- object = BKE_tracking_object_get_named(tracking, context->object_name);
+ object = BKE_tracking_object_get_named(tracking, context->object_name);
- if (context->is_camera)
- reconstruction = &tracking->reconstruction;
- else
- reconstruction = &object->reconstruction;
+ if (context->is_camera)
+ reconstruction = &tracking->reconstruction;
+ else
+ reconstruction = &object->reconstruction;
- /* update keyframe in the interface */
- if (context->select_keyframes) {
- object->keyframe1 = context->keyframe1;
- object->keyframe2 = context->keyframe2;
- }
+ /* update keyframe in the interface */
+ if (context->select_keyframes) {
+ object->keyframe1 = context->keyframe1;
+ object->keyframe2 = context->keyframe2;
+ }
- reconstruction->error = context->reprojection_error;
- reconstruction->flag |= TRACKING_RECONSTRUCTED;
+ reconstruction->error = context->reprojection_error;
+ reconstruction->flag |= TRACKING_RECONSTRUCTED;
- if (!reconstruct_retrieve_libmv(context, tracking))
- return false;
+ if (!reconstruct_retrieve_libmv(context, tracking))
+ return false;
- return true;
+ return true;
}
-static void tracking_scale_reconstruction(ListBase *tracksbase, MovieTrackingReconstruction *reconstruction,
+static void tracking_scale_reconstruction(ListBase *tracksbase,
+ MovieTrackingReconstruction *reconstruction,
const float scale[3])
{
- MovieTrackingTrack *track;
- int i;
- float first_camera_delta[3] = {0.0f, 0.0f, 0.0f};
-
- if (reconstruction->camnr > 0) {
- mul_v3_v3v3(first_camera_delta, reconstruction->cameras[0].mat[3], scale);
- }
-
- for (i = 0; i < reconstruction->camnr; i++) {
- MovieReconstructedCamera *camera = &reconstruction->cameras[i];
- mul_v3_v3(camera->mat[3], scale);
- sub_v3_v3(camera->mat[3], first_camera_delta);
- }
-
- for (track = tracksbase->first; track; track = track->next) {
- if (track->flag & TRACK_HAS_BUNDLE) {
- mul_v3_v3(track->bundle_pos, scale);
- sub_v3_v3(track->bundle_pos, first_camera_delta);
- }
- }
+ MovieTrackingTrack *track;
+ int i;
+ float first_camera_delta[3] = {0.0f, 0.0f, 0.0f};
+
+ if (reconstruction->camnr > 0) {
+ mul_v3_v3v3(first_camera_delta, reconstruction->cameras[0].mat[3], scale);
+ }
+
+ for (i = 0; i < reconstruction->camnr; i++) {
+ MovieReconstructedCamera *camera = &reconstruction->cameras[i];
+ mul_v3_v3(camera->mat[3], scale);
+ sub_v3_v3(camera->mat[3], first_camera_delta);
+ }
+
+ for (track = tracksbase->first; track; track = track->next) {
+ if (track->flag & TRACK_HAS_BUNDLE) {
+ mul_v3_v3(track->bundle_pos, scale);
+ sub_v3_v3(track->bundle_pos, first_camera_delta);
+ }
+ }
}
/* Apply scale on all reconstructed cameras and bundles,
@@ -561,15 +583,15 @@ static void tracking_scale_reconstruction(ListBase *tracksbase, MovieTrackingRec
*/
void BKE_tracking_reconstruction_scale(MovieTracking *tracking, float scale[3])
{
- MovieTrackingObject *object;
+ MovieTrackingObject *object;
- for (object = tracking->objects.first; object; object = object->next) {
- ListBase *tracksbase;
- MovieTrackingReconstruction *reconstruction;
+ for (object = tracking->objects.first; object; object = object->next) {
+ ListBase *tracksbase;
+ MovieTrackingReconstruction *reconstruction;
- tracksbase = BKE_tracking_object_get_tracks(tracking, object);
- reconstruction = BKE_tracking_object_get_reconstruction(tracking, object);
+ tracksbase = BKE_tracking_object_get_tracks(tracking, object);
+ reconstruction = BKE_tracking_object_get_reconstruction(tracking, object);
- tracking_scale_reconstruction(tracksbase, reconstruction, scale);
- }
+ tracking_scale_reconstruction(tracksbase, reconstruction, scale);
+ }
}
diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c
index 6a0dbefd340..c98ee116df7 100644
--- a/source/blender/blenkernel/intern/tracking_stabilize.c
+++ b/source/blender/blenkernel/intern/tracking_stabilize.c
@@ -45,7 +45,6 @@
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
-
/* == Parameterization constants == */
/* When measuring the scale changes relative to the rotation pivot point, it
@@ -65,8 +64,6 @@ static float SCALE_ERROR_LIMIT_BIAS = 0.01f;
*/
static float EPSILON_WEIGHT = 0.005f;
-
-
/* == private working data == */
/* Per track baseline for stabilization, defined at reference frame.
@@ -79,89 +76,77 @@ static float EPSILON_WEIGHT = 0.005f;
* via `StabContext::private_track_data`
*/
typedef struct TrackStabilizationBase {
- float stabilization_offset_base[2];
+ float stabilization_offset_base[2];
- /* measured relative to translated pivot */
- float stabilization_rotation_base[2][2];
+ /* measured relative to translated pivot */
+ float stabilization_rotation_base[2][2];
- /* measured relative to translated pivot */
- float stabilization_scale_base;
+ /* measured relative to translated pivot */
+ float stabilization_scale_base;
- bool is_init_for_stabilization;
- FCurve *track_weight_curve;
+ bool is_init_for_stabilization;
+ FCurve *track_weight_curve;
} TrackStabilizationBase;
/* Tracks are reordered for initialization, starting as close as possible to
* anchor_frame
*/
typedef struct TrackInitOrder {
- int sort_value;
- int reference_frame;
- MovieTrackingTrack *data;
+ int sort_value;
+ int reference_frame;
+ MovieTrackingTrack *data;
} TrackInitOrder;
/* Per frame private working data, for accessing possibly animated values. */
typedef struct StabContext {
- MovieClip *clip;
- MovieTracking *tracking;
- MovieTrackingStabilization *stab;
- GHash *private_track_data;
- FCurve *locinf;
- FCurve *rotinf;
- FCurve *scaleinf;
- FCurve *target_pos[2];
- FCurve *target_rot;
- FCurve *target_scale;
- bool use_animation;
+ MovieClip *clip;
+ MovieTracking *tracking;
+ MovieTrackingStabilization *stab;
+ GHash *private_track_data;
+ FCurve *locinf;
+ FCurve *rotinf;
+ FCurve *scaleinf;
+ FCurve *target_pos[2];
+ FCurve *target_rot;
+ FCurve *target_scale;
+ bool use_animation;
} StabContext;
-
-static TrackStabilizationBase *access_stabilization_baseline_data(
- StabContext *ctx,
- MovieTrackingTrack *track)
+static TrackStabilizationBase *access_stabilization_baseline_data(StabContext *ctx,
+ MovieTrackingTrack *track)
{
- return BLI_ghash_lookup(ctx->private_track_data, track);
+ return BLI_ghash_lookup(ctx->private_track_data, track);
}
-static void attach_stabilization_baseline_data(
- StabContext *ctx,
- MovieTrackingTrack *track,
- TrackStabilizationBase *private_data)
+static void attach_stabilization_baseline_data(StabContext *ctx,
+ MovieTrackingTrack *track,
+ TrackStabilizationBase *private_data)
{
- BLI_ghash_insert(ctx->private_track_data, track, private_data);
+ BLI_ghash_insert(ctx->private_track_data, track, private_data);
}
static void discard_stabilization_baseline_data(void *val)
{
- if (val != NULL) {
- MEM_freeN(val);
- }
+ if (val != NULL) {
+ MEM_freeN(val);
+ }
}
-
/* == access animated values for given frame == */
-static FCurve *retrieve_stab_animation(MovieClip *clip,
- const char *data_path,
- int idx)
+static FCurve *retrieve_stab_animation(MovieClip *clip, const char *data_path, int idx)
{
- return id_data_find_fcurve(&clip->id,
- &clip->tracking.stabilization,
- &RNA_MovieTrackingStabilization,
- data_path,
- idx,
- NULL);
+ return id_data_find_fcurve(&clip->id,
+ &clip->tracking.stabilization,
+ &RNA_MovieTrackingStabilization,
+ data_path,
+ idx,
+ NULL);
}
-static FCurve *retrieve_track_weight_animation(MovieClip *clip,
- MovieTrackingTrack *track)
+static FCurve *retrieve_track_weight_animation(MovieClip *clip, MovieTrackingTrack *track)
{
- return id_data_find_fcurve(&clip->id,
- track,
- &RNA_MovieTrackingTrack,
- "weight_stab",
- 0,
- NULL);
+ return id_data_find_fcurve(&clip->id, track, &RNA_MovieTrackingTrack, "weight_stab", 0, NULL);
}
static float fetch_from_fcurve(FCurve *animationCurve,
@@ -169,101 +154,81 @@ static float fetch_from_fcurve(FCurve *animationCurve,
StabContext *ctx,
float default_value)
{
- if (ctx && ctx->use_animation && animationCurve) {
- int scene_framenr = BKE_movieclip_remap_clip_to_scene_frame(ctx->clip,
- framenr);
- return evaluate_fcurve(animationCurve, scene_framenr);
- }
- return default_value;
+ if (ctx && ctx->use_animation && animationCurve) {
+ int scene_framenr = BKE_movieclip_remap_clip_to_scene_frame(ctx->clip, framenr);
+ return evaluate_fcurve(animationCurve, scene_framenr);
+ }
+ return default_value;
}
-
static float get_animated_locinf(StabContext *ctx, int framenr)
{
- return fetch_from_fcurve(ctx->locinf, framenr, ctx, ctx->stab->locinf);
+ return fetch_from_fcurve(ctx->locinf, framenr, ctx, ctx->stab->locinf);
}
static float get_animated_rotinf(StabContext *ctx, int framenr)
{
- return fetch_from_fcurve(ctx->rotinf, framenr, ctx, ctx->stab->rotinf);
+ return fetch_from_fcurve(ctx->rotinf, framenr, ctx, ctx->stab->rotinf);
}
static float get_animated_scaleinf(StabContext *ctx, int framenr)
{
- return fetch_from_fcurve(ctx->scaleinf, framenr, ctx, ctx->stab->scaleinf);
+ return fetch_from_fcurve(ctx->scaleinf, framenr, ctx, ctx->stab->scaleinf);
}
-static void get_animated_target_pos(StabContext *ctx,
- int framenr,
- float target_pos[2])
+static void get_animated_target_pos(StabContext *ctx, int framenr, float target_pos[2])
{
- target_pos[0] = fetch_from_fcurve(ctx->target_pos[0],
- framenr,
- ctx,
- ctx->stab->target_pos[0]);
- target_pos[1] = fetch_from_fcurve(ctx->target_pos[1],
- framenr,
- ctx,
- ctx->stab->target_pos[1]);
+ target_pos[0] = fetch_from_fcurve(ctx->target_pos[0], framenr, ctx, ctx->stab->target_pos[0]);
+ target_pos[1] = fetch_from_fcurve(ctx->target_pos[1], framenr, ctx, ctx->stab->target_pos[1]);
}
static float get_animated_target_rot(StabContext *ctx, int framenr)
{
- return fetch_from_fcurve(ctx->target_rot,
- framenr,
- ctx,
- ctx->stab->target_rot);
+ return fetch_from_fcurve(ctx->target_rot, framenr, ctx, ctx->stab->target_rot);
}
static float get_animated_target_scale(StabContext *ctx, int framenr)
{
- return fetch_from_fcurve(ctx->target_scale, framenr, ctx, ctx->stab->scale);
+ return fetch_from_fcurve(ctx->target_scale, framenr, ctx, ctx->stab->scale);
}
-static float get_animated_weight(StabContext *ctx,
- MovieTrackingTrack *track,
- int framenr)
+static float get_animated_weight(StabContext *ctx, MovieTrackingTrack *track, int framenr)
{
- TrackStabilizationBase *working_data =
- access_stabilization_baseline_data(ctx, track);
- if (working_data && working_data->track_weight_curve) {
- int scene_framenr = BKE_movieclip_remap_clip_to_scene_frame(ctx->clip,
- framenr);
- return evaluate_fcurve(working_data->track_weight_curve, scene_framenr);
- }
- /* Use weight at global 'current frame' as fallback default. */
- return track->weight_stab;
+ TrackStabilizationBase *working_data = access_stabilization_baseline_data(ctx, track);
+ if (working_data && working_data->track_weight_curve) {
+ int scene_framenr = BKE_movieclip_remap_clip_to_scene_frame(ctx->clip, framenr);
+ return evaluate_fcurve(working_data->track_weight_curve, scene_framenr);
+ }
+ /* Use weight at global 'current frame' as fallback default. */
+ return track->weight_stab;
}
static void use_values_from_fcurves(StabContext *ctx, bool toggle)
{
- if (ctx != NULL) {
- ctx->use_animation = toggle;
- }
+ if (ctx != NULL) {
+ ctx->use_animation = toggle;
+ }
}
-
/* Prepare per call private working area.
* Used for access to possibly animated values: retrieve available F-curves.
*/
static StabContext *initialize_stabilization_working_context(MovieClip *clip)
{
- StabContext *ctx = MEM_callocN(sizeof(StabContext),
- "2D stabilization animation runtime data");
- ctx->clip = clip;
- ctx->tracking = &clip->tracking;
- ctx->stab = &clip->tracking.stabilization;
- ctx->private_track_data = BLI_ghash_ptr_new(
- "2D stabilization per track private working data");
- ctx->locinf = retrieve_stab_animation(clip, "influence_location", 0);
- ctx->rotinf = retrieve_stab_animation(clip, "influence_rotation", 0);
- ctx->scaleinf = retrieve_stab_animation(clip, "influence_scale", 0);
- ctx->target_pos[0] = retrieve_stab_animation(clip, "target_pos", 0);
- ctx->target_pos[1] = retrieve_stab_animation(clip, "target_pos", 1);
- ctx->target_rot = retrieve_stab_animation(clip, "target_rot", 0);
- ctx->target_scale = retrieve_stab_animation(clip, "target_zoom", 0);
- ctx->use_animation = true;
- return ctx;
+ StabContext *ctx = MEM_callocN(sizeof(StabContext), "2D stabilization animation runtime data");
+ ctx->clip = clip;
+ ctx->tracking = &clip->tracking;
+ ctx->stab = &clip->tracking.stabilization;
+ ctx->private_track_data = BLI_ghash_ptr_new("2D stabilization per track private working data");
+ ctx->locinf = retrieve_stab_animation(clip, "influence_location", 0);
+ ctx->rotinf = retrieve_stab_animation(clip, "influence_rotation", 0);
+ ctx->scaleinf = retrieve_stab_animation(clip, "influence_scale", 0);
+ ctx->target_pos[0] = retrieve_stab_animation(clip, "target_pos", 0);
+ ctx->target_pos[1] = retrieve_stab_animation(clip, "target_pos", 1);
+ ctx->target_rot = retrieve_stab_animation(clip, "target_rot", 0);
+ ctx->target_scale = retrieve_stab_animation(clip, "target_zoom", 0);
+ ctx->use_animation = true;
+ return ctx;
}
/**
@@ -276,94 +241,78 @@ static StabContext *initialize_stabilization_working_context(MovieClip *clip)
*/
static void discard_stabilization_working_context(StabContext *ctx)
{
- if (ctx != NULL) {
- BLI_ghash_free(ctx->private_track_data,
- NULL,
- discard_stabilization_baseline_data);
- MEM_freeN(ctx);
- }
+ if (ctx != NULL) {
+ BLI_ghash_free(ctx->private_track_data, NULL, discard_stabilization_baseline_data);
+ MEM_freeN(ctx);
+ }
}
-static bool is_init_for_stabilization(StabContext *ctx,
- MovieTrackingTrack *track)
+static bool is_init_for_stabilization(StabContext *ctx, MovieTrackingTrack *track)
{
- TrackStabilizationBase *working_data =
- access_stabilization_baseline_data(ctx, track);
- return (working_data != NULL && working_data->is_init_for_stabilization);
+ TrackStabilizationBase *working_data = access_stabilization_baseline_data(ctx, track);
+ return (working_data != NULL && working_data->is_init_for_stabilization);
}
-static bool is_usable_for_stabilization(StabContext *ctx,
- MovieTrackingTrack *track)
+static bool is_usable_for_stabilization(StabContext *ctx, MovieTrackingTrack *track)
{
- return (track->flag & TRACK_USE_2D_STAB) &&
- is_init_for_stabilization(ctx, track);
+ return (track->flag & TRACK_USE_2D_STAB) && is_init_for_stabilization(ctx, track);
}
static bool is_effectively_disabled(StabContext *ctx,
MovieTrackingTrack *track,
MovieTrackingMarker *marker)
{
- return (marker->flag & MARKER_DISABLED) ||
- (EPSILON_WEIGHT > get_animated_weight(ctx, track, marker->framenr));
+ return (marker->flag & MARKER_DISABLED) ||
+ (EPSILON_WEIGHT > get_animated_weight(ctx, track, marker->framenr));
}
-
-static int search_closest_marker_index(MovieTrackingTrack *track,
- int ref_frame)
+static int search_closest_marker_index(MovieTrackingTrack *track, int ref_frame)
{
- MovieTrackingMarker *markers = track->markers;
- int end = track->markersnr;
- int i = track->last_marker;
-
- i = MAX2(0, i);
- i = MIN2(i, end - 1);
- for ( ; i < end - 1 && markers[i].framenr <= ref_frame; ++i);
- for ( ; 0 < i && markers[i].framenr > ref_frame; --i);
-
- track->last_marker = i;
- return i;
+ MovieTrackingMarker *markers = track->markers;
+ int end = track->markersnr;
+ int i = track->last_marker;
+
+ i = MAX2(0, i);
+ i = MIN2(i, end - 1);
+ for (; i < end - 1 && markers[i].framenr <= ref_frame; ++i)
+ ;
+ for (; 0 < i && markers[i].framenr > ref_frame; --i)
+ ;
+
+ track->last_marker = i;
+ return i;
}
-static void retrieve_next_higher_usable_frame(StabContext *ctx,
- MovieTrackingTrack *track,
- int i,
- int ref_frame,
- int *next_higher)
+static void retrieve_next_higher_usable_frame(
+ StabContext *ctx, MovieTrackingTrack *track, int i, int ref_frame, int *next_higher)
{
- MovieTrackingMarker *markers = track->markers;
- int end = track->markersnr;
- BLI_assert(0 <= i && i < end);
-
- while (i < end &&
- (markers[i].framenr < ref_frame ||
- is_effectively_disabled(ctx, track, &markers[i])))
- {
- ++i;
- }
- if (i < end && markers[i].framenr < *next_higher) {
- BLI_assert(markers[i].framenr >= ref_frame);
- *next_higher = markers[i].framenr;
- }
+ MovieTrackingMarker *markers = track->markers;
+ int end = track->markersnr;
+ BLI_assert(0 <= i && i < end);
+
+ while (i < end &&
+ (markers[i].framenr < ref_frame || is_effectively_disabled(ctx, track, &markers[i]))) {
+ ++i;
+ }
+ if (i < end && markers[i].framenr < *next_higher) {
+ BLI_assert(markers[i].framenr >= ref_frame);
+ *next_higher = markers[i].framenr;
+ }
}
-static void retrieve_next_lower_usable_frame(StabContext *ctx,
- MovieTrackingTrack *track,
- int i,
- int ref_frame,
- int *next_lower)
+static void retrieve_next_lower_usable_frame(
+ StabContext *ctx, MovieTrackingTrack *track, int i, int ref_frame, int *next_lower)
{
- MovieTrackingMarker *markers = track->markers;
- BLI_assert(0 <= i && i < track->markersnr);
- while (i >= 0 &&
- (markers[i].framenr > ref_frame ||
- is_effectively_disabled(ctx, track, &markers[i])))
- {
- --i;
- }
- if (0 <= i && markers[i].framenr > *next_lower) {
- BLI_assert(markers[i].framenr <= ref_frame);
- *next_lower = markers[i].framenr;
- }
+ MovieTrackingMarker *markers = track->markers;
+ BLI_assert(0 <= i && i < track->markersnr);
+ while (i >= 0 &&
+ (markers[i].framenr > ref_frame || is_effectively_disabled(ctx, track, &markers[i]))) {
+ --i;
+ }
+ if (0 <= i && markers[i].framenr > *next_lower) {
+ BLI_assert(markers[i].framenr <= ref_frame);
+ *next_lower = markers[i].framenr;
+ }
}
/* Find closest frames with usable stabilization data.
@@ -381,71 +330,57 @@ static void find_next_working_frames(StabContext *ctx,
int *next_lower,
int *next_higher)
{
- for (MovieTrackingTrack *track = ctx->tracking->tracks.first;
- track != NULL;
- track = track->next)
- {
- if (is_usable_for_stabilization(ctx, track)) {
- int startpoint = search_closest_marker_index(track, framenr);
- retrieve_next_higher_usable_frame(ctx,
- track,
- startpoint,
- framenr,
- next_higher);
- retrieve_next_lower_usable_frame(ctx,
- track,
- startpoint,
- framenr,
- next_lower);
- }
- }
+ for (MovieTrackingTrack *track = ctx->tracking->tracks.first; track != NULL;
+ track = track->next) {
+ if (is_usable_for_stabilization(ctx, track)) {
+ int startpoint = search_closest_marker_index(track, framenr);
+ retrieve_next_higher_usable_frame(ctx, track, startpoint, framenr, next_higher);
+ retrieve_next_lower_usable_frame(ctx, track, startpoint, framenr, next_lower);
+ }
+ }
}
-
/* Find active (enabled) marker closest to the reference frame. */
static MovieTrackingMarker *get_closest_marker(StabContext *ctx,
MovieTrackingTrack *track,
int ref_frame)
{
- int next_lower = MINAFRAME;
- int next_higher = MAXFRAME;
- int i = search_closest_marker_index(track, ref_frame);
- retrieve_next_higher_usable_frame(ctx, track, i, ref_frame, &next_higher);
- retrieve_next_lower_usable_frame(ctx, track, i, ref_frame, &next_lower);
-
- if ((next_higher - ref_frame) < (ref_frame - next_lower)) {
- return BKE_tracking_marker_get_exact(track, next_higher);
- }
- else {
- return BKE_tracking_marker_get_exact(track, next_lower);
- }
+ int next_lower = MINAFRAME;
+ int next_higher = MAXFRAME;
+ int i = search_closest_marker_index(track, ref_frame);
+ retrieve_next_higher_usable_frame(ctx, track, i, ref_frame, &next_higher);
+ retrieve_next_lower_usable_frame(ctx, track, i, ref_frame, &next_lower);
+
+ if ((next_higher - ref_frame) < (ref_frame - next_lower)) {
+ return BKE_tracking_marker_get_exact(track, next_higher);
+ }
+ else {
+ return BKE_tracking_marker_get_exact(track, next_lower);
+ }
}
-
/* Retrieve tracking data, if available and applicable for this frame.
* The returned weight value signals the validity; data recorded for this
* tracking marker on the exact requested frame is output with the full weight
* of this track, while gaps in the data sequence cause the weight to go to zero.
*/
-static MovieTrackingMarker *get_tracking_data_point(
- StabContext *ctx,
- MovieTrackingTrack *track,
- int framenr,
- float *r_weight)
+static MovieTrackingMarker *get_tracking_data_point(StabContext *ctx,
+ MovieTrackingTrack *track,
+ int framenr,
+ float *r_weight)
{
- MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, framenr);
- if (marker != NULL && !(marker->flag & MARKER_DISABLED)) {
- *r_weight = get_animated_weight(ctx, track, framenr);
- return marker;
- }
- else {
- /* No marker at this frame (=gap) or marker disabled. */
- *r_weight = 0.0f;
- return NULL;
- }
+ MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, framenr);
+ if (marker != NULL && !(marker->flag & MARKER_DISABLED)) {
+ *r_weight = get_animated_weight(ctx, track, framenr);
+ return marker;
+ }
+ else {
+ /* No marker at this frame (=gap) or marker disabled. */
+ *r_weight = 0.0f;
+ return NULL;
+ }
}
-
/* Define the reference point for rotation/scale measurement and compensation.
* The stabilizator works by assuming the image was distorted by a affine linear
* transform, i.e. it was rotated and stretched around this reference point
@@ -463,11 +398,10 @@ static MovieTrackingMarker *get_tracking_data_point(
*/
static void setup_pivot(const float ref_pos[2], float r_pivot[2])
{
- zero_v2(r_pivot); /* TODO: add an animated offset position here. */
- add_v2_v2(r_pivot, ref_pos);
+ zero_v2(r_pivot); /* TODO: add an animated offset position here. */
+ add_v2_v2(r_pivot, ref_pos);
}
-
/* Calculate the contribution of a single track at the time position (frame) of
* the given marker. Each track has a local reference frame, which is as close
* as possible to the global anchor_frame. Thus the translation contribution is
@@ -488,9 +422,7 @@ static void translation_contribution(TrackStabilizationBase *track_ref,
MovieTrackingMarker *marker,
float result_offset[2])
{
- add_v2_v2v2(result_offset,
- track_ref->stabilization_offset_base,
- marker->pos);
+ add_v2_v2v2(result_offset, track_ref->stabilization_offset_base, marker->pos);
}
/* Similar to the ::translation_contribution(), the rotation contribution is
@@ -537,28 +469,27 @@ static float rotation_contribution(TrackStabilizationBase *track_ref,
float *result_angle,
float *result_scale)
{
- float len, quality;
- float pos[2];
- sub_v2_v2v2(pos, marker->pos, pivot);
+ float len, quality;
+ float pos[2];
+ sub_v2_v2v2(pos, marker->pos, pivot);
- pos[0] *= aspect;
- mul_m2v2(track_ref->stabilization_rotation_base, pos);
+ pos[0] *= aspect;
+ mul_m2v2(track_ref->stabilization_rotation_base, pos);
- *result_angle = atan2f(pos[1],pos[0]);
+ *result_angle = atan2f(pos[1], pos[0]);
- len = len_v2(pos);
+ len = len_v2(pos);
- /* prevent points very close to the pivot point from poisoning the result */
- quality = 1 - expf(-len*len / SCALE_ERROR_LIMIT_BIAS*SCALE_ERROR_LIMIT_BIAS);
- len += SCALE_ERROR_LIMIT_BIAS;
+ /* prevent points very close to the pivot point from poisoning the result */
+ quality = 1 - expf(-len * len / SCALE_ERROR_LIMIT_BIAS * SCALE_ERROR_LIMIT_BIAS);
+ len += SCALE_ERROR_LIMIT_BIAS;
- *result_scale = len * track_ref->stabilization_scale_base;
- BLI_assert(0.0 < *result_scale);
+ *result_scale = len * track_ref->stabilization_scale_base;
+ BLI_assert(0.0 < *result_scale);
- return quality;
+ return quality;
}
-
/* Workaround to allow for rotation around an arbitrary pivot point.
* Currently, the public API functions do not support this flexibility.
* Rather, rotation will always be applied around a fixed origin.
@@ -568,28 +499,28 @@ static float rotation_contribution(TrackStabilizationBase *track_ref,
* translation compensation, which is also a lateral shift (offset).
* The offset to apply is intended_pivot - rotated_pivot
*/
-static void compensate_rotation_center(const int size, float aspect,
+static void compensate_rotation_center(const int size,
+ float aspect,
const float angle,
const float scale,
const float pivot[2],
float result_translation[2])
{
- const float origin[2] = {0.5f*aspect*size, 0.5f*size};
- float intended_pivot[2], rotated_pivot[2];
- float rotation_mat[2][2];
-
- copy_v2_v2(intended_pivot, pivot);
- copy_v2_v2(rotated_pivot, pivot);
- angle_to_mat2(rotation_mat, +angle);
- sub_v2_v2(rotated_pivot, origin);
- mul_m2v2(rotation_mat, rotated_pivot);
- mul_v2_fl(rotated_pivot, scale);
- add_v2_v2(rotated_pivot, origin);
- add_v2_v2(result_translation, intended_pivot);
- sub_v2_v2(result_translation, rotated_pivot);
+ const float origin[2] = {0.5f * aspect * size, 0.5f * size};
+ float intended_pivot[2], rotated_pivot[2];
+ float rotation_mat[2][2];
+
+ copy_v2_v2(intended_pivot, pivot);
+ copy_v2_v2(rotated_pivot, pivot);
+ angle_to_mat2(rotation_mat, +angle);
+ sub_v2_v2(rotated_pivot, origin);
+ mul_m2v2(rotation_mat, rotated_pivot);
+ mul_v2_fl(rotated_pivot, scale);
+ add_v2_v2(rotated_pivot, origin);
+ add_v2_v2(result_translation, intended_pivot);
+ sub_v2_v2(result_translation, rotated_pivot);
}
-
/* Weighted average of the per track cumulated contributions at given frame.
* Returns truth if all desired calculations could be done and all averages are
* available.
@@ -610,112 +541,101 @@ static bool average_track_contributions(StabContext *ctx,
float *r_angle,
float *r_scale_step)
{
- bool ok;
- float weight_sum;
- MovieTrackingTrack *track;
- MovieTracking *tracking = ctx->tracking;
- MovieTrackingStabilization *stab = &tracking->stabilization;
- float ref_pos[2];
- BLI_assert(stab->flag & TRACKING_2D_STABILIZATION);
-
- zero_v2(r_translation);
- *r_scale_step = 0.0f; /* logarithm */
- *r_angle = 0.0f;
-
- zero_v2(ref_pos);
-
- ok = false;
- weight_sum = 0.0f;
- for (track = tracking->tracks.first; track; track = track->next) {
- if (!is_init_for_stabilization(ctx, track)) {
- continue;
- }
- if (track->flag & TRACK_USE_2D_STAB) {
- float weight = 0.0f;
- MovieTrackingMarker *marker = get_tracking_data_point(ctx,
- track,
- framenr,
- &weight);
- if (marker) {
- TrackStabilizationBase *stabilization_base =
- access_stabilization_baseline_data(ctx, track);
- BLI_assert(stabilization_base != NULL);
- float offset[2];
- weight_sum += weight;
- translation_contribution(stabilization_base, marker, offset);
- r_translation[0] += weight * offset[0];
- r_translation[1] += weight * offset[1];
- ref_pos[0] += weight * marker->pos[0];
- ref_pos[1] += weight * marker->pos[1];
- ok |= (weight_sum > EPSILON_WEIGHT);
- }
- }
- }
- if (!ok) {
- return false;
- }
-
- ref_pos[0] /= weight_sum;
- ref_pos[1] /= weight_sum;
- r_translation[0] /= weight_sum;
- r_translation[1] /= weight_sum;
- setup_pivot(ref_pos, r_pivot);
-
- if (!(stab->flag & TRACKING_STABILIZE_ROTATION)) {
- return ok;
- }
-
- ok = false;
- weight_sum = 0.0f;
- for (track = tracking->tracks.first; track; track = track->next) {
- if (!is_init_for_stabilization(ctx, track)) {
- continue;
- }
- if (track->flag & TRACK_USE_2D_STAB_ROT) {
- float weight = 0.0f;
- MovieTrackingMarker *marker = get_tracking_data_point(ctx,
- track,
- framenr,
- &weight);
- if (marker) {
- TrackStabilizationBase *stabilization_base =
- access_stabilization_baseline_data(ctx, track);
- BLI_assert(stabilization_base != NULL);
- float rotation, scale, quality;
- quality = rotation_contribution(stabilization_base,
- marker,
- aspect,
- r_pivot,
- &rotation,
- &scale);
- weight *= quality;
- weight_sum += weight;
- *r_angle += rotation * weight;
- if (stab->flag & TRACKING_STABILIZE_SCALE) {
- *r_scale_step += logf(scale) * weight;
- }
- else {
- *r_scale_step = 0;
- }
- ok |= (weight_sum > EPSILON_WEIGHT);
- }
- }
- }
- if (ok) {
- *r_scale_step /= weight_sum;
- *r_angle /= weight_sum;
- }
- else {
- /* We reach this point because translation could be calculated,
- * but rotation/scale found no data to work on.
- */
- *r_scale_step = 0.0f;
- *r_angle = 0.0f;
- }
- return true;
+ bool ok;
+ float weight_sum;
+ MovieTrackingTrack *track;
+ MovieTracking *tracking = ctx->tracking;
+ MovieTrackingStabilization *stab = &tracking->stabilization;
+ float ref_pos[2];
+ BLI_assert(stab->flag & TRACKING_2D_STABILIZATION);
+
+ zero_v2(r_translation);
+ *r_scale_step = 0.0f; /* logarithm */
+ *r_angle = 0.0f;
+
+ zero_v2(ref_pos);
+
+ ok = false;
+ weight_sum = 0.0f;
+ for (track = tracking->tracks.first; track; track = track->next) {
+ if (!is_init_for_stabilization(ctx, track)) {
+ continue;
+ }
+ if (track->flag & TRACK_USE_2D_STAB) {
+ float weight = 0.0f;
+ MovieTrackingMarker *marker = get_tracking_data_point(ctx, track, framenr, &weight);
+ if (marker) {
+ TrackStabilizationBase *stabilization_base = access_stabilization_baseline_data(ctx,
+ track);
+ BLI_assert(stabilization_base != NULL);
+ float offset[2];
+ weight_sum += weight;
+ translation_contribution(stabilization_base, marker, offset);
+ r_translation[0] += weight * offset[0];
+ r_translation[1] += weight * offset[1];
+ ref_pos[0] += weight * marker->pos[0];
+ ref_pos[1] += weight * marker->pos[1];
+ ok |= (weight_sum > EPSILON_WEIGHT);
+ }
+ }
+ }
+ if (!ok) {
+ return false;
+ }
+
+ ref_pos[0] /= weight_sum;
+ ref_pos[1] /= weight_sum;
+ r_translation[0] /= weight_sum;
+ r_translation[1] /= weight_sum;
+ setup_pivot(ref_pos, r_pivot);
+
+ if (!(stab->flag & TRACKING_STABILIZE_ROTATION)) {
+ return ok;
+ }
+
+ ok = false;
+ weight_sum = 0.0f;
+ for (track = tracking->tracks.first; track; track = track->next) {
+ if (!is_init_for_stabilization(ctx, track)) {
+ continue;
+ }
+ if (track->flag & TRACK_USE_2D_STAB_ROT) {
+ float weight = 0.0f;
+ MovieTrackingMarker *marker = get_tracking_data_point(ctx, track, framenr, &weight);
+ if (marker) {
+ TrackStabilizationBase *stabilization_base = access_stabilization_baseline_data(ctx,
+ track);
+ BLI_assert(stabilization_base != NULL);
+ float rotation, scale, quality;
+ quality = rotation_contribution(
+ stabilization_base, marker, aspect, r_pivot, &rotation, &scale);
+ weight *= quality;
+ weight_sum += weight;
+ *r_angle += rotation * weight;
+ if (stab->flag & TRACKING_STABILIZE_SCALE) {
+ *r_scale_step += logf(scale) * weight;
+ }
+ else {
+ *r_scale_step = 0;
+ }
+ ok |= (weight_sum > EPSILON_WEIGHT);
+ }
+ }
+ }
+ if (ok) {
+ *r_scale_step /= weight_sum;
+ *r_angle /= weight_sum;
+ }
+ else {
+ /* We reach this point because translation could be calculated,
+ * but rotation/scale found no data to work on.
+ */
+ *r_scale_step = 0.0f;
+ *r_angle = 0.0f;
+ }
+ return true;
}
-
/* Calculate weight center of location tracks for given frame.
* This function performs similar calculations as average_track_contributions(),
* but does not require the tracks to be initialized for stabilisation. Moreover,
@@ -725,68 +645,57 @@ static bool average_track_contributions(StabContext *ctx,
*/
static void average_marker_positions(StabContext *ctx, int framenr, float r_ref_pos[2])
{
- bool ok = false;
- float weight_sum;
- MovieTrackingTrack *track;
- MovieTracking *tracking = ctx->tracking;
-
- zero_v2(r_ref_pos);
- weight_sum = 0.0f;
- for (track = tracking->tracks.first; track; track = track->next) {
- if (track->flag & TRACK_USE_2D_STAB) {
- float weight = 0.0f;
- MovieTrackingMarker *marker =
- get_tracking_data_point(ctx, track, framenr, &weight);
- if (marker) {
- weight_sum += weight;
- r_ref_pos[0] += weight * marker->pos[0];
- r_ref_pos[1] += weight * marker->pos[1];
- ok |= (weight_sum > EPSILON_WEIGHT);
- }
- }
- }
- if (ok) {
- r_ref_pos[0] /= weight_sum;
- r_ref_pos[1] /= weight_sum;
- }
- else {
- /* No usable tracking data on any track on this frame.
- * Use data from neighbouring frames to extrapolate...
- */
- int next_lower = MINAFRAME;
- int next_higher = MAXFRAME;
- use_values_from_fcurves(ctx, true);
- for (track = tracking->tracks.first; track; track = track->next) {
- /* Note: we deliberately do not care if this track
- * is already initialized for stabilisation */
- if (track->flag & TRACK_USE_2D_STAB) {
- int startpoint = search_closest_marker_index(track, framenr);
- retrieve_next_higher_usable_frame(ctx,
- track,
- startpoint,
- framenr,
- &next_higher);
- retrieve_next_lower_usable_frame(ctx,
- track,
- startpoint,
- framenr,
- &next_lower);
- }
- }
- if (next_lower >= MINFRAME) {
- /* use next usable frame to the left.
- * Also default to this frame when we're in a gap */
- average_marker_positions(ctx, next_lower, r_ref_pos);
-
- }
- else if (next_higher < MAXFRAME) {
- average_marker_positions(ctx, next_higher, r_ref_pos);
- }
- use_values_from_fcurves(ctx, false);
- }
+ bool ok = false;
+ float weight_sum;
+ MovieTrackingTrack *track;
+ MovieTracking *tracking = ctx->tracking;
+
+ zero_v2(r_ref_pos);
+ weight_sum = 0.0f;
+ for (track = tracking->tracks.first; track; track = track->next) {
+ if (track->flag & TRACK_USE_2D_STAB) {
+ float weight = 0.0f;
+ MovieTrackingMarker *marker = get_tracking_data_point(ctx, track, framenr, &weight);
+ if (marker) {
+ weight_sum += weight;
+ r_ref_pos[0] += weight * marker->pos[0];
+ r_ref_pos[1] += weight * marker->pos[1];
+ ok |= (weight_sum > EPSILON_WEIGHT);
+ }
+ }
+ }
+ if (ok) {
+ r_ref_pos[0] /= weight_sum;
+ r_ref_pos[1] /= weight_sum;
+ }
+ else {
+ /* No usable tracking data on any track on this frame.
+ * Use data from neighbouring frames to extrapolate...
+ */
+ int next_lower = MINAFRAME;
+ int next_higher = MAXFRAME;
+ use_values_from_fcurves(ctx, true);
+ for (track = tracking->tracks.first; track; track = track->next) {
+ /* Note: we deliberately do not care if this track
+ * is already initialized for stabilisation */
+ if (track->flag & TRACK_USE_2D_STAB) {
+ int startpoint = search_closest_marker_index(track, framenr);
+ retrieve_next_higher_usable_frame(ctx, track, startpoint, framenr, &next_higher);
+ retrieve_next_lower_usable_frame(ctx, track, startpoint, framenr, &next_lower);
+ }
+ }
+ if (next_lower >= MINFRAME) {
+ /* use next usable frame to the left.
+ * Also default to this frame when we're in a gap */
+ average_marker_positions(ctx, next_lower, r_ref_pos);
+ }
+ else if (next_higher < MAXFRAME) {
+ average_marker_positions(ctx, next_higher, r_ref_pos);
+ }
+ use_values_from_fcurves(ctx, false);
+ }
}
-
/* Linear interpolation of data retrieved at two measurement points.
* This function is used to fill gaps in the middle of the covered area,
* at frames without any usable tracks for stabilization.
@@ -807,37 +716,38 @@ static bool interpolate_averaged_track_contributions(StabContext *ctx,
float *r_angle,
float *r_scale_step)
{
- float t, s;
- float trans_a[2], trans_b[2];
- float angle_a, angle_b;
- float scale_a, scale_b;
- float pivot_a[2], pivot_b[2];
- bool success = false;
-
- BLI_assert(frame_a <= frame_b);
- BLI_assert(frame_a <= framenr);
- BLI_assert(framenr <= frame_b);
-
- t = ((float)framenr - frame_a) / (frame_b - frame_a);
- s = 1.0f - t;
-
- success = average_track_contributions(ctx, frame_a, aspect, trans_a, pivot_a, &angle_a, &scale_a);
- if (!success) {
- return false;
- }
- success = average_track_contributions(ctx, frame_b, aspect, trans_b, pivot_b, &angle_b, &scale_b);
- if (!success) {
- return false;
- }
-
- interp_v2_v2v2(r_translation, trans_a, trans_b, t);
- interp_v2_v2v2(r_pivot, pivot_a, pivot_b, t);
- *r_scale_step = s * scale_a + t * scale_b;
- *r_angle = s * angle_a + t * angle_b;
- return true;
+ float t, s;
+ float trans_a[2], trans_b[2];
+ float angle_a, angle_b;
+ float scale_a, scale_b;
+ float pivot_a[2], pivot_b[2];
+ bool success = false;
+
+ BLI_assert(frame_a <= frame_b);
+ BLI_assert(frame_a <= framenr);
+ BLI_assert(framenr <= frame_b);
+
+ t = ((float)framenr - frame_a) / (frame_b - frame_a);
+ s = 1.0f - t;
+
+ success = average_track_contributions(
+ ctx, frame_a, aspect, trans_a, pivot_a, &angle_a, &scale_a);
+ if (!success) {
+ return false;
+ }
+ success = average_track_contributions(
+ ctx, frame_b, aspect, trans_b, pivot_b, &angle_b, &scale_b);
+ if (!success) {
+ return false;
+ }
+
+ interp_v2_v2v2(r_translation, trans_a, trans_b, t);
+ interp_v2_v2v2(r_pivot, pivot_a, pivot_b, t);
+ *r_scale_step = s * scale_a + t * scale_b;
+ *r_angle = s * angle_a + t * angle_b;
+ return true;
}
-
/* Reorder tracks starting with those providing a tracking data frame
* closest to the global anchor_frame. Tracks with a gap at anchor_frame or
* starting farer away from anchor_frame altogether will be visited later.
@@ -853,33 +763,29 @@ static bool interpolate_averaged_track_contributions(StabContext *ctx,
* Initialization includes disabled tracks, since they might be enabled
* through automation later.
*/
-static int establish_track_initialization_order(StabContext *ctx,
- TrackInitOrder *order)
+static int establish_track_initialization_order(StabContext *ctx, TrackInitOrder *order)
{
- size_t tracknr = 0;
- MovieTrackingTrack *track;
- MovieTracking *tracking = ctx->tracking;
- int anchor_frame = tracking->stabilization.anchor_frame;
-
- for (track = tracking->tracks.first; track != NULL; track = track->next) {
- MovieTrackingMarker *marker;
- order[tracknr].data = track;
- marker = get_closest_marker(ctx, track, anchor_frame);
- if (marker != NULL &&
- (track->flag & (TRACK_USE_2D_STAB | TRACK_USE_2D_STAB_ROT)))
- {
- order[tracknr].sort_value = abs(marker->framenr - anchor_frame);
- order[tracknr].reference_frame = marker->framenr;
- ++tracknr;
- }
- }
- if (tracknr) {
- qsort(order, tracknr, sizeof(TrackInitOrder), BLI_sortutil_cmp_int);
- }
- return tracknr;
+ size_t tracknr = 0;
+ MovieTrackingTrack *track;
+ MovieTracking *tracking = ctx->tracking;
+ int anchor_frame = tracking->stabilization.anchor_frame;
+
+ for (track = tracking->tracks.first; track != NULL; track = track->next) {
+ MovieTrackingMarker *marker;
+ order[tracknr].data = track;
+ marker = get_closest_marker(ctx, track, anchor_frame);
+ if (marker != NULL && (track->flag & (TRACK_USE_2D_STAB | TRACK_USE_2D_STAB_ROT))) {
+ order[tracknr].sort_value = abs(marker->framenr - anchor_frame);
+ order[tracknr].reference_frame = marker->framenr;
+ ++tracknr;
+ }
+ }
+ if (tracknr) {
+ qsort(order, tracknr, sizeof(TrackInitOrder), BLI_sortutil_cmp_int);
+ }
+ return tracknr;
}
-
/* Setup the constant part of this track's contribution to the determined frame
* movement. Tracks usually don't provide tracking data for every frame. Thus,
* for determining data at a given frame, we split up the contribution into a
@@ -941,116 +847,107 @@ static void initialize_track_for_stabilization(StabContext *ctx,
const float average_angle,
const float average_scale_step)
{
- float pos[2], angle, len;
- TrackStabilizationBase *local_data =
- access_stabilization_baseline_data(ctx, track);
- MovieTrackingMarker *marker =
- BKE_tracking_marker_get_exact(track, reference_frame);
- /* Logic for initialization order ensures there *is* a marker on that
- * very frame.
- */
- BLI_assert(marker != NULL);
- BLI_assert(local_data != NULL);
-
- /* Per track baseline value for translation. */
- sub_v2_v2v2(local_data->stabilization_offset_base,
- average_translation,
- marker->pos);
-
- /* Per track baseline value for rotation. */
- sub_v2_v2v2(pos, marker->pos, pivot);
-
- pos[0] *= aspect;
- angle = average_angle - atan2f(pos[1],pos[0]);
- angle_to_mat2(local_data->stabilization_rotation_base, angle);
-
- /* Per track baseline value for zoom. */
- len = len_v2(pos) + SCALE_ERROR_LIMIT_BIAS;
- local_data->stabilization_scale_base = expf(average_scale_step) / len;
-
- local_data->is_init_for_stabilization = true;
+ float pos[2], angle, len;
+ TrackStabilizationBase *local_data = access_stabilization_baseline_data(ctx, track);
+ MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, reference_frame);
+ /* Logic for initialization order ensures there *is* a marker on that
+ * very frame.
+ */
+ BLI_assert(marker != NULL);
+ BLI_assert(local_data != NULL);
+
+ /* Per track baseline value for translation. */
+ sub_v2_v2v2(local_data->stabilization_offset_base, average_translation, marker->pos);
+
+ /* Per track baseline value for rotation. */
+ sub_v2_v2v2(pos, marker->pos, pivot);
+
+ pos[0] *= aspect;
+ angle = average_angle - atan2f(pos[1], pos[0]);
+ angle_to_mat2(local_data->stabilization_rotation_base, angle);
+
+ /* Per track baseline value for zoom. */
+ len = len_v2(pos) + SCALE_ERROR_LIMIT_BIAS;
+ local_data->stabilization_scale_base = expf(average_scale_step) / len;
+
+ local_data->is_init_for_stabilization = true;
}
-
static void initialize_all_tracks(StabContext *ctx, float aspect)
{
- size_t i, track_len = 0;
- MovieClip *clip = ctx->clip;
- MovieTracking *tracking = ctx->tracking;
- MovieTrackingTrack *track;
- TrackInitOrder *order;
-
- /* Attempt to start initialization at anchor_frame.
- * By definition, offset contribution is zero there.
- */
- int reference_frame = tracking->stabilization.anchor_frame;
- float average_angle = 0, average_scale_step = 0;
- float average_translation[2], average_pos[2], pivot[2];
- zero_v2(average_translation);
- zero_v2(pivot);
-
- /* Initialize private working data. */
- for (track = tracking->tracks.first; track != NULL; track = track->next) {
- TrackStabilizationBase *local_data =
- access_stabilization_baseline_data(ctx, track);
- if (!local_data) {
- local_data = MEM_callocN(sizeof(TrackStabilizationBase),
- "2D stabilization per track baseline data");
- attach_stabilization_baseline_data(ctx, track, local_data);
- }
- BLI_assert(local_data != NULL);
- local_data->track_weight_curve = retrieve_track_weight_animation(clip,
- track);
- local_data->is_init_for_stabilization = false;
-
- ++track_len;
- }
- if (!track_len) {
- return;
- }
-
- order = MEM_mallocN(track_len * sizeof(TrackInitOrder),
- "stabilization track order");
- if (!order) {
- return;
- }
-
- track_len = establish_track_initialization_order(ctx, order);
- if (track_len == 0) {
- goto cleanup;
- }
-
- /* starting point for pivot, before having initialized any track */
- average_marker_positions(ctx, reference_frame, average_pos);
- setup_pivot(average_pos, pivot);
-
- for (i = 0; i < track_len; ++i) {
- track = order[i].data;
- if (reference_frame != order[i].reference_frame) {
- reference_frame = order[i].reference_frame;
- average_track_contributions(ctx,
- reference_frame,
- aspect,
- average_translation,
- pivot,
- &average_angle,
- &average_scale_step);
- }
- initialize_track_for_stabilization(ctx,
- track,
- reference_frame,
- aspect,
- average_translation,
- pivot,
- average_angle,
- average_scale_step);
- }
+ size_t i, track_len = 0;
+ MovieClip *clip = ctx->clip;
+ MovieTracking *tracking = ctx->tracking;
+ MovieTrackingTrack *track;
+ TrackInitOrder *order;
+
+ /* Attempt to start initialization at anchor_frame.
+ * By definition, offset contribution is zero there.
+ */
+ int reference_frame = tracking->stabilization.anchor_frame;
+ float average_angle = 0, average_scale_step = 0;
+ float average_translation[2], average_pos[2], pivot[2];
+ zero_v2(average_translation);
+ zero_v2(pivot);
+
+ /* Initialize private working data. */
+ for (track = tracking->tracks.first; track != NULL; track = track->next) {
+ TrackStabilizationBase *local_data = access_stabilization_baseline_data(ctx, track);
+ if (!local_data) {
+ local_data = MEM_callocN(sizeof(TrackStabilizationBase),
+ "2D stabilization per track baseline data");
+ attach_stabilization_baseline_data(ctx, track, local_data);
+ }
+ BLI_assert(local_data != NULL);
+ local_data->track_weight_curve = retrieve_track_weight_animation(clip, track);
+ local_data->is_init_for_stabilization = false;
+
+ ++track_len;
+ }
+ if (!track_len) {
+ return;
+ }
+
+ order = MEM_mallocN(track_len * sizeof(TrackInitOrder), "stabilization track order");
+ if (!order) {
+ return;
+ }
+
+ track_len = establish_track_initialization_order(ctx, order);
+ if (track_len == 0) {
+ goto cleanup;
+ }
+
+ /* starting point for pivot, before having initialized any track */
+ average_marker_positions(ctx, reference_frame, average_pos);
+ setup_pivot(average_pos, pivot);
+
+ for (i = 0; i < track_len; ++i) {
+ track = order[i].data;
+ if (reference_frame != order[i].reference_frame) {
+ reference_frame = order[i].reference_frame;
+ average_track_contributions(ctx,
+ reference_frame,
+ aspect,
+ average_translation,
+ pivot,
+ &average_angle,
+ &average_scale_step);
+ }
+ initialize_track_for_stabilization(ctx,
+ track,
+ reference_frame,
+ aspect,
+ average_translation,
+ pivot,
+ average_angle,
+ average_scale_step);
+ }
cleanup:
- MEM_freeN(order);
+ MEM_freeN(order);
}
-
/* Retrieve the measurement of frame movement by averaging contributions of
* active tracks.
*
@@ -1071,68 +968,53 @@ static bool stabilization_determine_offset_for_frame(StabContext *ctx,
float *r_angle,
float *r_scale_step)
{
- bool success = false;
-
- /* Early output if stabilization is disabled. */
- if ((ctx->stab->flag & TRACKING_2D_STABILIZATION) == 0) {
- zero_v2(r_translation);
- *r_scale_step = 0.0f;
- *r_angle = 0.0f;
- return false;
- }
-
- success = average_track_contributions(ctx,
- framenr,
- aspect,
- r_translation,
- r_pivot,
- r_angle,
- r_scale_step);
- if (!success) {
- /* Try to hold extrapolated settings beyond the definition range
- * and to interpolate in gaps without any usable tracking data
- * to prevent sudden jump to image zero position.
- */
- int next_lower = MINAFRAME;
- int next_higher = MAXFRAME;
- use_values_from_fcurves(ctx, true);
- find_next_working_frames(ctx, framenr, &next_lower, &next_higher);
- if (next_lower >= MINFRAME && next_higher < MAXFRAME) {
- success = interpolate_averaged_track_contributions(ctx,
- framenr,
- next_lower,
- next_higher,
- aspect,
- r_translation,
- r_pivot,
- r_angle,
- r_scale_step);
- }
- else if (next_higher < MAXFRAME) {
- /* Before start of stabilized range: extrapolate start point
- * settings.
- */
- success = average_track_contributions(ctx,
- next_higher,
- aspect,
- r_translation,
- r_pivot,
- r_angle,
- r_scale_step);
- }
- else if (next_lower >= MINFRAME) {
- /* After end of stabilized range: extrapolate end point settings. */
- success = average_track_contributions(ctx,
- next_lower,
- aspect,
- r_translation,
- r_pivot,
- r_angle,
- r_scale_step);
- }
- use_values_from_fcurves(ctx, false);
- }
- return success;
+ bool success = false;
+
+ /* Early output if stabilization is disabled. */
+ if ((ctx->stab->flag & TRACKING_2D_STABILIZATION) == 0) {
+ zero_v2(r_translation);
+ *r_scale_step = 0.0f;
+ *r_angle = 0.0f;
+ return false;
+ }
+
+ success = average_track_contributions(
+ ctx, framenr, aspect, r_translation, r_pivot, r_angle, r_scale_step);
+ if (!success) {
+ /* Try to hold extrapolated settings beyond the definition range
+ * and to interpolate in gaps without any usable tracking data
+ * to prevent sudden jump to image zero position.
+ */
+ int next_lower = MINAFRAME;
+ int next_higher = MAXFRAME;
+ use_values_from_fcurves(ctx, true);
+ find_next_working_frames(ctx, framenr, &next_lower, &next_higher);
+ if (next_lower >= MINFRAME && next_higher < MAXFRAME) {
+ success = interpolate_averaged_track_contributions(ctx,
+ framenr,
+ next_lower,
+ next_higher,
+ aspect,
+ r_translation,
+ r_pivot,
+ r_angle,
+ r_scale_step);
+ }
+ else if (next_higher < MAXFRAME) {
+ /* Before start of stabilized range: extrapolate start point
+ * settings.
+ */
+ success = average_track_contributions(
+ ctx, next_higher, aspect, r_translation, r_pivot, r_angle, r_scale_step);
+ }
+ else if (next_lower >= MINFRAME) {
+ /* After end of stabilized range: extrapolate end point settings. */
+ success = average_track_contributions(
+ ctx, next_lower, aspect, r_translation, r_pivot, r_angle, r_scale_step);
+ }
+ use_values_from_fcurves(ctx, false);
+ }
+ return success;
}
/* Calculate stabilization data (translation, scale and rotation) from given raw
@@ -1157,48 +1039,48 @@ static void stabilization_calculate_data(StabContext *ctx,
float *r_scale,
float *r_angle)
{
- float target_pos[2], target_scale;
- float scaleinf = get_animated_scaleinf(ctx, framenr);
-
- if (ctx->stab->flag & TRACKING_STABILIZE_SCALE) {
- *r_scale = expf(scale_step * scaleinf); /* Averaged in log scale */
- }
- else {
- *r_scale = 1.0f;
- }
-
- mul_v2_fl(r_translation, get_animated_locinf(ctx, framenr));
- *r_angle *= get_animated_rotinf(ctx, framenr);
-
- /* Compensate for a target frame position.
- * This allows to follow tracking / panning shots in a semi manual fashion,
- * when animating the settings for the target frame position.
- */
- get_animated_target_pos(ctx, framenr, target_pos);
- sub_v2_v2(r_translation, target_pos);
- *r_angle -= get_animated_target_rot(ctx, framenr);
- target_scale = get_animated_target_scale(ctx, framenr);
- if (target_scale != 0.0f) {
- *r_scale /= target_scale;
- /* target_scale is an expected/intended reference zoom value */
- }
-
- /* Convert from relative to absolute coordinates, square pixels. */
- r_translation[0] *= (float)size * aspect;
- r_translation[1] *= (float)size;
- r_pivot[0] *= (float)size * aspect;
- r_pivot[1] *= (float)size;
-
- /* Output measured data, or inverse of the measured values for
- * compensation?
- */
- if (do_compensate) {
- mul_v2_fl(r_translation, -1.0f);
- *r_angle *= -1.0f;
- if (*r_scale != 0.0f) {
- *r_scale = 1.0f / *r_scale;
- }
- }
+ float target_pos[2], target_scale;
+ float scaleinf = get_animated_scaleinf(ctx, framenr);
+
+ if (ctx->stab->flag & TRACKING_STABILIZE_SCALE) {
+ *r_scale = expf(scale_step * scaleinf); /* Averaged in log scale */
+ }
+ else {
+ *r_scale = 1.0f;
+ }
+
+ mul_v2_fl(r_translation, get_animated_locinf(ctx, framenr));
+ *r_angle *= get_animated_rotinf(ctx, framenr);
+
+ /* Compensate for a target frame position.
+ * This allows to follow tracking / panning shots in a semi manual fashion,
+ * when animating the settings for the target frame position.
+ */
+ get_animated_target_pos(ctx, framenr, target_pos);
+ sub_v2_v2(r_translation, target_pos);
+ *r_angle -= get_animated_target_rot(ctx, framenr);
+ target_scale = get_animated_target_scale(ctx, framenr);
+ if (target_scale != 0.0f) {
+ *r_scale /= target_scale;
+ /* target_scale is an expected/intended reference zoom value */
+ }
+
+ /* Convert from relative to absolute coordinates, square pixels. */
+ r_translation[0] *= (float)size * aspect;
+ r_translation[1] *= (float)size;
+ r_pivot[0] *= (float)size * aspect;
+ r_pivot[1] *= (float)size;
+
+ /* Output measured data, or inverse of the measured values for
+ * compensation?
+ */
+ if (do_compensate) {
+ mul_v2_fl(r_translation, -1.0f);
+ *r_angle *= -1.0f;
+ if (*r_scale != 0.0f) {
+ *r_scale = 1.0f / *r_scale;
+ }
+ }
}
static void stabilization_data_to_mat4(float pixel_aspect,
@@ -1208,33 +1090,37 @@ static void stabilization_data_to_mat4(float pixel_aspect,
float angle,
float r_mat[4][4])
{
- float translation_mat[4][4], rotation_mat[4][4], scale_mat[4][4],
- pivot_mat[4][4], inv_pivot_mat[4][4],
- aspect_mat[4][4], inv_aspect_mat[4][4];
- float scale_vector[3] = {scale, scale, 1.0f};
-
- unit_m4(translation_mat);
- unit_m4(rotation_mat);
- unit_m4(scale_mat);
- unit_m4(aspect_mat);
- unit_m4(pivot_mat);
- unit_m4(inv_pivot_mat);
-
- /* aspect ratio correction matrix */
- aspect_mat[0][0] /= pixel_aspect;
- invert_m4_m4(inv_aspect_mat, aspect_mat);
-
- add_v2_v2(pivot_mat[3], pivot);
- sub_v2_v2(inv_pivot_mat[3], pivot);
-
- size_to_mat4(scale_mat, scale_vector); /* scale matrix */
- add_v2_v2(translation_mat[3], translation); /* translation matrix */
- rotate_m4(rotation_mat, 'Z', angle); /* rotation matrix */
-
- /* Compose transformation matrix. */
- mul_m4_series(r_mat, aspect_mat, translation_mat,
- pivot_mat, scale_mat, rotation_mat, inv_pivot_mat,
- inv_aspect_mat);
+ float translation_mat[4][4], rotation_mat[4][4], scale_mat[4][4], pivot_mat[4][4],
+ inv_pivot_mat[4][4], aspect_mat[4][4], inv_aspect_mat[4][4];
+ float scale_vector[3] = {scale, scale, 1.0f};
+
+ unit_m4(translation_mat);
+ unit_m4(rotation_mat);
+ unit_m4(scale_mat);
+ unit_m4(aspect_mat);
+ unit_m4(pivot_mat);
+ unit_m4(inv_pivot_mat);
+
+ /* aspect ratio correction matrix */
+ aspect_mat[0][0] /= pixel_aspect;
+ invert_m4_m4(inv_aspect_mat, aspect_mat);
+
+ add_v2_v2(pivot_mat[3], pivot);
+ sub_v2_v2(inv_pivot_mat[3], pivot);
+
+ size_to_mat4(scale_mat, scale_vector); /* scale matrix */
+ add_v2_v2(translation_mat[3], translation); /* translation matrix */
+ rotate_m4(rotation_mat, 'Z', angle); /* rotation matrix */
+
+ /* Compose transformation matrix. */
+ mul_m4_series(r_mat,
+ aspect_mat,
+ translation_mat,
+ pivot_mat,
+ scale_mat,
+ rotation_mat,
+ inv_pivot_mat,
+ inv_aspect_mat);
}
/* Calculate scale factor necessary to eliminate black image areas
@@ -1245,145 +1131,121 @@ static void stabilization_data_to_mat4(float pixel_aspect,
*
* NOTE: all tracks need to be initialized before calling this function.
*/
-static float calculate_autoscale_factor(StabContext *ctx,
- int size,
- float aspect)
+static float calculate_autoscale_factor(StabContext *ctx, int size, float aspect)
{
- MovieTrackingStabilization *stab = ctx->stab;
- float pixel_aspect = ctx->tracking->camera.pixel_aspect;
- int height = size, width = aspect*size;
-
- int sfra = INT_MAX, efra = INT_MIN, cfra;
- float scale = 1.0f, scale_step = 0.0f;
- MovieTrackingTrack *track;
-
- /* Calculate maximal frame range of tracks where stabilization is active. */
- for (track = ctx->tracking->tracks.first; track; track = track->next) {
- if ((track->flag & TRACK_USE_2D_STAB) ||
- ((stab->flag & TRACKING_STABILIZE_ROTATION) &&
- (track->flag & TRACK_USE_2D_STAB_ROT)))
- {
- int first_frame = track->markers[0].framenr;
- int last_frame = track->markers[track->markersnr - 1].framenr;
- sfra = min_ii(sfra, first_frame);
- efra = max_ii(efra, last_frame);
- }
- }
-
- use_values_from_fcurves(ctx, true);
- for (cfra = sfra; cfra <= efra; cfra++) {
- float translation[2], pivot[2], angle, tmp_scale;
- float mat[4][4];
- const float points[4][2] = {{0.0f, 0.0f},
- {0.0f, height},
- {width, height},
- {width, 0.0f}};
- const bool do_compensate = true;
- /* Calculate stabilization parameters for the current frame. */
- stabilization_determine_offset_for_frame(ctx,
- cfra,
- aspect,
- translation,
- pivot,
- &angle,
- &scale_step);
- stabilization_calculate_data(ctx,
- cfra,
- size,
- aspect,
- do_compensate,
- scale_step,
- translation,
- pivot,
- &tmp_scale,
- &angle);
- /* Compose transformation matrix. */
- /* NOTE: Here we operate in NON-COMPENSATED coordinates, meaning we have
- * to construct transformation matrix using proper pivot point.
- * Compensation for that will happen later on.
- */
- stabilization_data_to_mat4(pixel_aspect,
- pivot,
- translation,
- tmp_scale,
- angle,
- mat);
- /* Investigate the transformed border lines for this frame;
- * find out, where it cuts the original frame.
- */
- for (int edge_index = 0; edge_index < 4; edge_index++) {
- /* Calculate coordinates of stabilized frame edge points.
- * Use matrix multiplication here so we operate in homogeneous
- * coordinates.
- */
- float stable_edge_p1[3], stable_edge_p2[3];
- copy_v2_v2(stable_edge_p1, points[edge_index]);
- copy_v2_v2(stable_edge_p2, points[(edge_index + 1) % 4]);
- stable_edge_p1[2] = stable_edge_p2[2] = 0.0f;
- mul_m4_v3(mat, stable_edge_p1);
- mul_m4_v3(mat, stable_edge_p2);
- /* Now we iterate over all original frame corners (we call them
- * 'point' here) to see if there's black area between stabilized
- * frame edge and original point.
- */
- for (int point_index = 0; point_index < 4; point_index++) {
- const float point[3] = {points[point_index][0],
- points[point_index][1],
- 0.0f};
- /* Calculate vector which goes from first edge point to
- * second one.
- */
- float stable_edge_vec[3];
- sub_v3_v3v3(stable_edge_vec, stable_edge_p2, stable_edge_p1);
- /* Calculate vector which connects current frame point to
- * first edge point.
- */
- float point_to_edge_start_vec[3];
- sub_v3_v3v3(point_to_edge_start_vec, point, stable_edge_p1);
- /* Use this two vectors to check whether frame point is inside
- * of the stabilized frame or not.
- * If the point is inside, there is no black area happening
- * and no scaling required for it.
- */
- if (cross_v2v2(stable_edge_vec, point_to_edge_start_vec) >= 0.0f) {
- /* We are scaling around motion-compensated pivot point. */
- float scale_pivot[2];
- add_v2_v2v2(scale_pivot, pivot, translation);
- /* Calculate line which goes via `point` and parallel to
- * the stabilized frame edge. This line is coming via
- * `point` and `point2` at the end.
- */
- float point2[2];
- add_v2_v2v2(point2, point, stable_edge_vec);
- /* Calculate actual distance between pivot point and
- * the stabilized frame edge. Then calculate distance
- * between pivot point and line which goes via actual
- * corner and is parallel to the edge.
- *
- * Dividing one by another will give us required scale
- * factor to get rid of black areas.
- */
- float real_dist = dist_to_line_v2(scale_pivot,
- stable_edge_p1,
- stable_edge_p2);
- float required_dist = dist_to_line_v2(scale_pivot,
- point,
- point2);
- const float S = required_dist / real_dist;
- scale = max_ff(scale, S);
- }
- }
- }
- }
- if (stab->maxscale > 0.0f) {
- scale = min_ff(scale, stab->maxscale);
- }
- use_values_from_fcurves(ctx, false);
-
- return scale;
+ MovieTrackingStabilization *stab = ctx->stab;
+ float pixel_aspect = ctx->tracking->camera.pixel_aspect;
+ int height = size, width = aspect * size;
+
+ int sfra = INT_MAX, efra = INT_MIN, cfra;
+ float scale = 1.0f, scale_step = 0.0f;
+ MovieTrackingTrack *track;
+
+ /* Calculate maximal frame range of tracks where stabilization is active. */
+ for (track = ctx->tracking->tracks.first; track; track = track->next) {
+ if ((track->flag & TRACK_USE_2D_STAB) ||
+ ((stab->flag & TRACKING_STABILIZE_ROTATION) && (track->flag & TRACK_USE_2D_STAB_ROT))) {
+ int first_frame = track->markers[0].framenr;
+ int last_frame = track->markers[track->markersnr - 1].framenr;
+ sfra = min_ii(sfra, first_frame);
+ efra = max_ii(efra, last_frame);
+ }
+ }
+
+ use_values_from_fcurves(ctx, true);
+ for (cfra = sfra; cfra <= efra; cfra++) {
+ float translation[2], pivot[2], angle, tmp_scale;
+ float mat[4][4];
+ const float points[4][2] = {{0.0f, 0.0f}, {0.0f, height}, {width, height}, {width, 0.0f}};
+ const bool do_compensate = true;
+ /* Calculate stabilization parameters for the current frame. */
+ stabilization_determine_offset_for_frame(
+ ctx, cfra, aspect, translation, pivot, &angle, &scale_step);
+ stabilization_calculate_data(ctx,
+ cfra,
+ size,
+ aspect,
+ do_compensate,
+ scale_step,
+ translation,
+ pivot,
+ &tmp_scale,
+ &angle);
+ /* Compose transformation matrix. */
+ /* NOTE: Here we operate in NON-COMPENSATED coordinates, meaning we have
+ * to construct transformation matrix using proper pivot point.
+ * Compensation for that will happen later on.
+ */
+ stabilization_data_to_mat4(pixel_aspect, pivot, translation, tmp_scale, angle, mat);
+ /* Investigate the transformed border lines for this frame;
+ * find out, where it cuts the original frame.
+ */
+ for (int edge_index = 0; edge_index < 4; edge_index++) {
+ /* Calculate coordinates of stabilized frame edge points.
+ * Use matrix multiplication here so we operate in homogeneous
+ * coordinates.
+ */
+ float stable_edge_p1[3], stable_edge_p2[3];
+ copy_v2_v2(stable_edge_p1, points[edge_index]);
+ copy_v2_v2(stable_edge_p2, points[(edge_index + 1) % 4]);
+ stable_edge_p1[2] = stable_edge_p2[2] = 0.0f;
+ mul_m4_v3(mat, stable_edge_p1);
+ mul_m4_v3(mat, stable_edge_p2);
+ /* Now we iterate over all original frame corners (we call them
+ * 'point' here) to see if there's black area between stabilized
+ * frame edge and original point.
+ */
+ for (int point_index = 0; point_index < 4; point_index++) {
+ const float point[3] = {points[point_index][0], points[point_index][1], 0.0f};
+ /* Calculate vector which goes from first edge point to
+ * second one.
+ */
+ float stable_edge_vec[3];
+ sub_v3_v3v3(stable_edge_vec, stable_edge_p2, stable_edge_p1);
+ /* Calculate vector which connects current frame point to
+ * first edge point.
+ */
+ float point_to_edge_start_vec[3];
+ sub_v3_v3v3(point_to_edge_start_vec, point, stable_edge_p1);
+ /* Use this two vectors to check whether frame point is inside
+ * of the stabilized frame or not.
+ * If the point is inside, there is no black area happening
+ * and no scaling required for it.
+ */
+ if (cross_v2v2(stable_edge_vec, point_to_edge_start_vec) >= 0.0f) {
+ /* We are scaling around motion-compensated pivot point. */
+ float scale_pivot[2];
+ add_v2_v2v2(scale_pivot, pivot, translation);
+ /* Calculate line which goes via `point` and parallel to
+ * the stabilized frame edge. This line is coming via
+ * `point` and `point2` at the end.
+ */
+ float point2[2];
+ add_v2_v2v2(point2, point, stable_edge_vec);
+ /* Calculate actual distance between pivot point and
+ * the stabilized frame edge. Then calculate distance
+ * between pivot point and line which goes via actual
+ * corner and is parallel to the edge.
+ *
+ * Dividing one by another will give us required scale
+ * factor to get rid of black areas.
+ */
+ float real_dist = dist_to_line_v2(scale_pivot, stable_edge_p1, stable_edge_p2);
+ float required_dist = dist_to_line_v2(scale_pivot, point, point2);
+ const float S = required_dist / real_dist;
+ scale = max_ff(scale, S);
+ }
+ }
+ }
+ }
+ if (stab->maxscale > 0.0f) {
+ scale = min_ff(scale, stab->maxscale);
+ }
+ use_values_from_fcurves(ctx, false);
+
+ return scale;
}
-
/* Prepare working data and determine reference point for each track.
*
* NOTE: These calculations _could_ be cached and reused for all frames of the
@@ -1394,19 +1256,18 @@ static float calculate_autoscale_factor(StabContext *ctx,
*/
static StabContext *init_stabilizer(MovieClip *clip, int size, float aspect)
{
- StabContext *ctx = initialize_stabilization_working_context(clip);
- BLI_assert(ctx != NULL);
- initialize_all_tracks(ctx, aspect);
- if (ctx->stab->flag & TRACKING_AUTOSCALE) {
- ctx->stab->scale = 1.0;
- ctx->stab->scale = calculate_autoscale_factor(ctx, size, aspect);
- }
- /* By default, just use values for the global current frame. */
- use_values_from_fcurves(ctx, false);
- return ctx;
+ StabContext *ctx = initialize_stabilization_working_context(clip);
+ BLI_assert(ctx != NULL);
+ initialize_all_tracks(ctx, aspect);
+ if (ctx->stab->flag & TRACKING_AUTOSCALE) {
+ ctx->stab->scale = 1.0;
+ ctx->stab->scale = calculate_autoscale_factor(ctx, size, aspect);
+ }
+ /* By default, just use values for the global current frame. */
+ use_values_from_fcurves(ctx, false);
+ return ctx;
}
-
/* === public interface functions === */
/* Get stabilization data (translation, scaling and angle) for a given frame.
@@ -1435,85 +1296,62 @@ void BKE_tracking_stabilization_data_get(MovieClip *clip,
float *scale,
float *angle)
{
- StabContext *ctx = NULL;
- MovieTracking *tracking = &clip->tracking;
- bool enabled = (tracking->stabilization.flag & TRACKING_2D_STABILIZATION);
- /* Might become a parameter of a stabilization compositor node. */
- bool do_compensate = true;
- float scale_step = 0.0f;
- float pixel_aspect = tracking->camera.pixel_aspect;
- float aspect = (float)width * pixel_aspect / height;
- int size = height;
- float pivot[2];
-
- if (enabled) {
- ctx = init_stabilizer(clip, size, aspect);
- }
-
- if (enabled &&
- stabilization_determine_offset_for_frame(ctx,
- framenr,
- aspect,
- translation,
- pivot,
- angle,
- &scale_step))
- {
- stabilization_calculate_data(ctx,
- framenr,
- size,
- aspect,
- do_compensate,
- scale_step,
- translation,
- pivot,
- scale,
- angle);
- compensate_rotation_center(size,
- aspect,
- *angle,
- *scale,
- pivot,
- translation);
- }
- else {
- zero_v2(translation);
- *scale = 1.0f;
- *angle = 0.0f;
- }
- discard_stabilization_working_context(ctx);
+ StabContext *ctx = NULL;
+ MovieTracking *tracking = &clip->tracking;
+ bool enabled = (tracking->stabilization.flag & TRACKING_2D_STABILIZATION);
+ /* Might become a parameter of a stabilization compositor node. */
+ bool do_compensate = true;
+ float scale_step = 0.0f;
+ float pixel_aspect = tracking->camera.pixel_aspect;
+ float aspect = (float)width * pixel_aspect / height;
+ int size = height;
+ float pivot[2];
+
+ if (enabled) {
+ ctx = init_stabilizer(clip, size, aspect);
+ }
+
+ if (enabled && stabilization_determine_offset_for_frame(
+ ctx, framenr, aspect, translation, pivot, angle, &scale_step)) {
+ stabilization_calculate_data(
+ ctx, framenr, size, aspect, do_compensate, scale_step, translation, pivot, scale, angle);
+ compensate_rotation_center(size, aspect, *angle, *scale, pivot, translation);
+ }
+ else {
+ zero_v2(translation);
+ *scale = 1.0f;
+ *angle = 0.0f;
+ }
+ discard_stabilization_working_context(ctx);
}
-
typedef void (*interpolation_func)(struct ImBuf *, struct ImBuf *, float, float, int, int);
typedef struct TrackingStabilizeFrameInterpolationData {
- ImBuf *ibuf;
- ImBuf *tmpibuf;
- float (*mat)[4];
+ ImBuf *ibuf;
+ ImBuf *tmpibuf;
+ float (*mat)[4];
- interpolation_func interpolation;
+ interpolation_func interpolation;
} TrackingStabilizeFrameInterpolationData;
static void tracking_stabilize_frame_interpolation_cb(
- void *__restrict userdata,
- const int j,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+ void *__restrict userdata, const int j, const ParallelRangeTLS *__restrict UNUSED(tls))
{
- TrackingStabilizeFrameInterpolationData *data = userdata;
- ImBuf *ibuf = data->ibuf;
- ImBuf *tmpibuf = data->tmpibuf;
- float (*mat)[4] = data->mat;
+ TrackingStabilizeFrameInterpolationData *data = userdata;
+ ImBuf *ibuf = data->ibuf;
+ ImBuf *tmpibuf = data->tmpibuf;
+ float(*mat)[4] = data->mat;
- interpolation_func interpolation = data->interpolation;
+ interpolation_func interpolation = data->interpolation;
- for (int i = 0; i < tmpibuf->x; i++) {
- float vec[3] = {i, j, 0.0f};
+ for (int i = 0; i < tmpibuf->x; i++) {
+ float vec[3] = {i, j, 0.0f};
- mul_v3_m4v3(vec, mat, vec);
+ mul_v3_m4v3(vec, mat, vec);
- interpolation(ibuf, tmpibuf, vec[0], vec[1], i, j);
- }
+ interpolation(ibuf, tmpibuf, vec[0], vec[1], i, j);
+ }
}
/* Stabilize given image buffer using stabilization data for a specified
@@ -1522,101 +1360,97 @@ static void tracking_stabilize_frame_interpolation_cb(
* NOTE: frame number should be in clip space, not scene space.
*/
/* TODO(sergey): Use r_ prefix for output parameters here. */
-ImBuf *BKE_tracking_stabilize_frame(MovieClip *clip,
- int framenr,
- ImBuf *ibuf,
- float translation[2],
- float *scale,
- float *angle)
+ImBuf *BKE_tracking_stabilize_frame(
+ MovieClip *clip, int framenr, ImBuf *ibuf, float translation[2], float *scale, float *angle)
{
- float tloc[2], tscale, tangle;
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingStabilization *stab = &tracking->stabilization;
- ImBuf *tmpibuf;
- int width = ibuf->x, height = ibuf->y;
- float pixel_aspect = tracking->camera.pixel_aspect;
- float mat[4][4];
- int filter = tracking->stabilization.filter;
- interpolation_func interpolation = NULL;
- int ibuf_flags;
-
- if (translation)
- copy_v2_v2(tloc, translation);
-
- if (scale)
- tscale = *scale;
-
- /* Perform early output if no stabilization is used. */
- if ((stab->flag & TRACKING_2D_STABILIZATION) == 0) {
- if (translation)
- zero_v2(translation);
-
- if (scale)
- *scale = 1.0f;
-
- if (angle)
- *angle = 0.0f;
-
- return ibuf;
- }
-
- /* Allocate frame for stabilization result. */
- ibuf_flags = 0;
- if (ibuf->rect)
- ibuf_flags |= IB_rect;
- if (ibuf->rect_float)
- ibuf_flags |= IB_rectfloat;
-
- tmpibuf = IMB_allocImBuf(ibuf->x, ibuf->y, ibuf->planes, ibuf_flags);
-
- /* Calculate stabilization matrix. */
- BKE_tracking_stabilization_data_get(clip, framenr, width, height, tloc, &tscale, &tangle);
- BKE_tracking_stabilization_data_to_mat4(ibuf->x, ibuf->y, pixel_aspect, tloc, tscale, tangle, mat);
-
- /* The following code visits each nominal target grid position
- * and picks interpolated data "backwards" from source.
- * thus we need the inverse of the transformation to apply. */
- invert_m4(mat);
-
- if (filter == TRACKING_FILTER_NEAREST)
- interpolation = nearest_interpolation;
- else if (filter == TRACKING_FILTER_BILINEAR)
- interpolation = bilinear_interpolation;
- else if (filter == TRACKING_FILTER_BICUBIC)
- interpolation = bicubic_interpolation;
- else
- /* fallback to default interpolation method */
- interpolation = nearest_interpolation;
-
- TrackingStabilizeFrameInterpolationData data = {
- .ibuf = ibuf, .tmpibuf = tmpibuf, .mat = mat,
- .interpolation = interpolation,
- };
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (tmpibuf->y > 128);
- BLI_task_parallel_range(0, tmpibuf->y,
- &data,
- tracking_stabilize_frame_interpolation_cb,
- &settings);
-
- if (tmpibuf->rect_float)
- tmpibuf->userflags |= IB_RECT_INVALID;
-
- if (translation)
- copy_v2_v2(translation, tloc);
-
- if (scale)
- *scale = tscale;
-
- if (angle)
- *angle = tangle;
-
- return tmpibuf;
+ float tloc[2], tscale, tangle;
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingStabilization *stab = &tracking->stabilization;
+ ImBuf *tmpibuf;
+ int width = ibuf->x, height = ibuf->y;
+ float pixel_aspect = tracking->camera.pixel_aspect;
+ float mat[4][4];
+ int filter = tracking->stabilization.filter;
+ interpolation_func interpolation = NULL;
+ int ibuf_flags;
+
+ if (translation)
+ copy_v2_v2(tloc, translation);
+
+ if (scale)
+ tscale = *scale;
+
+ /* Perform early output if no stabilization is used. */
+ if ((stab->flag & TRACKING_2D_STABILIZATION) == 0) {
+ if (translation)
+ zero_v2(translation);
+
+ if (scale)
+ *scale = 1.0f;
+
+ if (angle)
+ *angle = 0.0f;
+
+ return ibuf;
+ }
+
+ /* Allocate frame for stabilization result. */
+ ibuf_flags = 0;
+ if (ibuf->rect)
+ ibuf_flags |= IB_rect;
+ if (ibuf->rect_float)
+ ibuf_flags |= IB_rectfloat;
+
+ tmpibuf = IMB_allocImBuf(ibuf->x, ibuf->y, ibuf->planes, ibuf_flags);
+
+ /* Calculate stabilization matrix. */
+ BKE_tracking_stabilization_data_get(clip, framenr, width, height, tloc, &tscale, &tangle);
+ BKE_tracking_stabilization_data_to_mat4(
+ ibuf->x, ibuf->y, pixel_aspect, tloc, tscale, tangle, mat);
+
+ /* The following code visits each nominal target grid position
+ * and picks interpolated data "backwards" from source.
+ * thus we need the inverse of the transformation to apply. */
+ invert_m4(mat);
+
+ if (filter == TRACKING_FILTER_NEAREST)
+ interpolation = nearest_interpolation;
+ else if (filter == TRACKING_FILTER_BILINEAR)
+ interpolation = bilinear_interpolation;
+ else if (filter == TRACKING_FILTER_BICUBIC)
+ interpolation = bicubic_interpolation;
+ else
+ /* fallback to default interpolation method */
+ interpolation = nearest_interpolation;
+
+ TrackingStabilizeFrameInterpolationData data = {
+ .ibuf = ibuf,
+ .tmpibuf = tmpibuf,
+ .mat = mat,
+ .interpolation = interpolation,
+ };
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (tmpibuf->y > 128);
+ BLI_task_parallel_range(
+ 0, tmpibuf->y, &data, tracking_stabilize_frame_interpolation_cb, &settings);
+
+ if (tmpibuf->rect_float)
+ tmpibuf->userflags |= IB_RECT_INVALID;
+
+ if (translation)
+ copy_v2_v2(translation, tloc);
+
+ if (scale)
+ *scale = tscale;
+
+ if (angle)
+ *angle = tangle;
+
+ return tmpibuf;
}
-
/* Build a 4x4 transformation matrix based on the given 2D stabilization data.
* mat is a 4x4 matrix in homogeneous coordinates, adapted to the
* final image buffer size and compensated for pixel aspect ratio,
@@ -1635,25 +1469,20 @@ void BKE_tracking_stabilization_data_to_mat4(int buffer_width,
float angle,
float r_mat[4][4])
{
- /* Since we cannot receive the real pivot point coordinates (API limitation),
- * we perform the rotation/scale around the center of frame.
- * Then we correct by an additional shift, which was calculated in
- * compensate_rotation_center() and "sneaked in" as additional offset
- * in the translation parameter. This works, since translation needs to be
- * applied after rotation/scale anyway. Thus effectively the image gets
- * rotated around the desired pivot point
- */
- /* TODO(sergey) pivot shouldn't be calculated here, rather received
- * as a parameter.
- */
- float pivot[2];
- pivot[0] = 0.5f * pixel_aspect * buffer_width;
- pivot[1] = 0.5f * buffer_height;
- /* Compose transformation matrix. */
- stabilization_data_to_mat4(pixel_aspect,
- pivot,
- translation,
- scale,
- angle,
- r_mat);
+ /* Since we cannot receive the real pivot point coordinates (API limitation),
+ * we perform the rotation/scale around the center of frame.
+ * Then we correct by an additional shift, which was calculated in
+ * compensate_rotation_center() and "sneaked in" as additional offset
+ * in the translation parameter. This works, since translation needs to be
+ * applied after rotation/scale anyway. Thus effectively the image gets
+ * rotated around the desired pivot point
+ */
+ /* TODO(sergey) pivot shouldn't be calculated here, rather received
+ * as a parameter.
+ */
+ float pivot[2];
+ pivot[0] = 0.5f * pixel_aspect * buffer_width;
+ pivot[1] = 0.5f * buffer_height;
+ /* Compose transformation matrix. */
+ stabilization_data_to_mat4(pixel_aspect, pivot, translation, scale, angle, r_mat);
}
diff --git a/source/blender/blenkernel/intern/tracking_util.c b/source/blender/blenkernel/intern/tracking_util.c
index f2f3e1d56b5..4de10aca0ec 100644
--- a/source/blender/blenkernel/intern/tracking_util.c
+++ b/source/blender/blenkernel/intern/tracking_util.c
@@ -61,172 +61,182 @@
/*********************** Tracks map *************************/
-TracksMap *tracks_map_new(const char *object_name, bool is_camera, int num_tracks, int customdata_size)
+TracksMap *tracks_map_new(const char *object_name,
+ bool is_camera,
+ int num_tracks,
+ int customdata_size)
{
- TracksMap *map = MEM_callocN(sizeof(TracksMap), "TrackingsMap");
+ TracksMap *map = MEM_callocN(sizeof(TracksMap), "TrackingsMap");
- BLI_strncpy(map->object_name, object_name, sizeof(map->object_name));
- map->is_camera = is_camera;
+ BLI_strncpy(map->object_name, object_name, sizeof(map->object_name));
+ map->is_camera = is_camera;
- map->num_tracks = num_tracks;
- map->customdata_size = customdata_size;
+ map->num_tracks = num_tracks;
+ map->customdata_size = customdata_size;
- map->tracks = MEM_callocN(sizeof(MovieTrackingTrack) * num_tracks, "TrackingsMap tracks");
+ map->tracks = MEM_callocN(sizeof(MovieTrackingTrack) * num_tracks, "TrackingsMap tracks");
- if (customdata_size)
- map->customdata = MEM_callocN(customdata_size * num_tracks, "TracksMap customdata");
+ if (customdata_size)
+ map->customdata = MEM_callocN(customdata_size * num_tracks, "TracksMap customdata");
- map->hash = BLI_ghash_ptr_new("TracksMap hash");
+ map->hash = BLI_ghash_ptr_new("TracksMap hash");
- BLI_spin_init(&map->spin_lock);
+ BLI_spin_init(&map->spin_lock);
- return map;
+ return map;
}
int tracks_map_get_size(TracksMap *map)
{
- return map->num_tracks;
+ return map->num_tracks;
}
-void tracks_map_get_indexed_element(TracksMap *map, int index, MovieTrackingTrack **track, void **customdata)
+void tracks_map_get_indexed_element(TracksMap *map,
+ int index,
+ MovieTrackingTrack **track,
+ void **customdata)
{
- *track = &map->tracks[index];
+ *track = &map->tracks[index];
- if (map->customdata)
- *customdata = &map->customdata[index * map->customdata_size];
+ if (map->customdata)
+ *customdata = &map->customdata[index * map->customdata_size];
}
void tracks_map_insert(TracksMap *map, MovieTrackingTrack *track, void *customdata)
{
- MovieTrackingTrack new_track = *track;
+ MovieTrackingTrack new_track = *track;
- new_track.markers = MEM_dupallocN(new_track.markers);
+ new_track.markers = MEM_dupallocN(new_track.markers);
- map->tracks[map->ptr] = new_track;
+ map->tracks[map->ptr] = new_track;
- if (customdata)
- memcpy(&map->customdata[map->ptr * map->customdata_size], customdata, map->customdata_size);
+ if (customdata)
+ memcpy(&map->customdata[map->ptr * map->customdata_size], customdata, map->customdata_size);
- BLI_ghash_insert(map->hash, &map->tracks[map->ptr], track);
+ BLI_ghash_insert(map->hash, &map->tracks[map->ptr], track);
- map->ptr++;
+ map->ptr++;
}
void tracks_map_merge(TracksMap *map, MovieTracking *tracking)
{
- MovieTrackingTrack *track;
- ListBase tracks = {NULL, NULL}, new_tracks = {NULL, NULL};
- ListBase *old_tracks;
- int a;
+ MovieTrackingTrack *track;
+ ListBase tracks = {NULL, NULL}, new_tracks = {NULL, NULL};
+ ListBase *old_tracks;
+ int a;
- if (map->is_camera) {
- old_tracks = &tracking->tracks;
- }
- else {
- MovieTrackingObject *object = BKE_tracking_object_get_named(tracking, map->object_name);
+ if (map->is_camera) {
+ old_tracks = &tracking->tracks;
+ }
+ else {
+ MovieTrackingObject *object = BKE_tracking_object_get_named(tracking, map->object_name);
- if (!object) {
- /* object was deleted by user, create new one */
- object = BKE_tracking_object_add(tracking, map->object_name);
- }
+ if (!object) {
+ /* object was deleted by user, create new one */
+ object = BKE_tracking_object_add(tracking, map->object_name);
+ }
- old_tracks = &object->tracks;
- }
+ old_tracks = &object->tracks;
+ }
- /* duplicate currently operating tracks to temporary list.
- * this is needed to keep names in unique state and it's faster to change names
- * of currently operating tracks (if needed)
- */
- for (a = 0; a < map->num_tracks; a++) {
- MovieTrackingTrack *old_track;
- bool mapped_to_old = false;
+ /* duplicate currently operating tracks to temporary list.
+ * this is needed to keep names in unique state and it's faster to change names
+ * of currently operating tracks (if needed)
+ */
+ for (a = 0; a < map->num_tracks; a++) {
+ MovieTrackingTrack *old_track;
+ bool mapped_to_old = false;
- track = &map->tracks[a];
+ track = &map->tracks[a];
- /* find original of operating track in list of previously displayed tracks */
- old_track = BLI_ghash_lookup(map->hash, track);
- if (old_track) {
- if (BLI_findindex(old_tracks, old_track) != -1) {
- BLI_remlink(old_tracks, old_track);
+ /* find original of operating track in list of previously displayed tracks */
+ old_track = BLI_ghash_lookup(map->hash, track);
+ if (old_track) {
+ if (BLI_findindex(old_tracks, old_track) != -1) {
+ BLI_remlink(old_tracks, old_track);
- BLI_spin_lock(&map->spin_lock);
+ BLI_spin_lock(&map->spin_lock);
- /* Copy flags like selection back to the track map. */
- track->flag = old_track->flag;
- track->pat_flag = old_track->pat_flag;
- track->search_flag = old_track->search_flag;
+ /* Copy flags like selection back to the track map. */
+ track->flag = old_track->flag;
+ track->pat_flag = old_track->pat_flag;
+ track->search_flag = old_track->search_flag;
- /* Copy all the rest settings back from the map to the actual tracks. */
- MEM_freeN(old_track->markers);
- *old_track = *track;
- old_track->markers = MEM_dupallocN(old_track->markers);
+ /* Copy all the rest settings back from the map to the actual tracks. */
+ MEM_freeN(old_track->markers);
+ *old_track = *track;
+ old_track->markers = MEM_dupallocN(old_track->markers);
- BLI_spin_unlock(&map->spin_lock);
+ BLI_spin_unlock(&map->spin_lock);
- BLI_addtail(&tracks, old_track);
+ BLI_addtail(&tracks, old_track);
- mapped_to_old = true;
- }
- }
+ mapped_to_old = true;
+ }
+ }
- if (mapped_to_old == false) {
- MovieTrackingTrack *new_track = BKE_tracking_track_duplicate(track);
+ if (mapped_to_old == false) {
+ MovieTrackingTrack *new_track = BKE_tracking_track_duplicate(track);
- /* Update old-new track mapping */
- BLI_ghash_reinsert(map->hash, track, new_track, NULL, NULL);
+ /* Update old-new track mapping */
+ BLI_ghash_reinsert(map->hash, track, new_track, NULL, NULL);
- BLI_addtail(&tracks, new_track);
- }
- }
+ BLI_addtail(&tracks, new_track);
+ }
+ }
- /* move all tracks, which aren't operating */
- track = old_tracks->first;
- while (track) {
- MovieTrackingTrack *next = track->next;
- BLI_addtail(&new_tracks, track);
- track = next;
- }
+ /* move all tracks, which aren't operating */
+ track = old_tracks->first;
+ while (track) {
+ MovieTrackingTrack *next = track->next;
+ BLI_addtail(&new_tracks, track);
+ track = next;
+ }
- /* now move all tracks which are currently operating and keep their names unique */
- track = tracks.first;
- while (track) {
- MovieTrackingTrack *next = track->next;
+ /* now move all tracks which are currently operating and keep their names unique */
+ track = tracks.first;
+ while (track) {
+ MovieTrackingTrack *next = track->next;
- BLI_remlink(&tracks, track);
+ BLI_remlink(&tracks, track);
- track->next = track->prev = NULL;
- BLI_addtail(&new_tracks, track);
+ track->next = track->prev = NULL;
+ BLI_addtail(&new_tracks, track);
- BLI_uniquename(&new_tracks, track, CTX_DATA_(BLT_I18NCONTEXT_ID_MOVIECLIP, "Track"), '.',
- offsetof(MovieTrackingTrack, name), sizeof(track->name));
+ BLI_uniquename(&new_tracks,
+ track,
+ CTX_DATA_(BLT_I18NCONTEXT_ID_MOVIECLIP, "Track"),
+ '.',
+ offsetof(MovieTrackingTrack, name),
+ sizeof(track->name));
- track = next;
- }
+ track = next;
+ }
- *old_tracks = new_tracks;
+ *old_tracks = new_tracks;
}
void tracks_map_free(TracksMap *map, void (*customdata_free)(void *customdata))
{
- int i = 0;
+ int i = 0;
- BLI_ghash_free(map->hash, NULL, NULL);
+ BLI_ghash_free(map->hash, NULL, NULL);
- for (i = 0; i < map->num_tracks; i++) {
- if (map->customdata && customdata_free)
- customdata_free(&map->customdata[i * map->customdata_size]);
+ for (i = 0; i < map->num_tracks; i++) {
+ if (map->customdata && customdata_free)
+ customdata_free(&map->customdata[i * map->customdata_size]);
- BKE_tracking_track_free(&map->tracks[i]);
- }
+ BKE_tracking_track_free(&map->tracks[i]);
+ }
- if (map->customdata)
- MEM_freeN(map->customdata);
+ if (map->customdata)
+ MEM_freeN(map->customdata);
- MEM_freeN(map->tracks);
+ MEM_freeN(map->tracks);
- BLI_spin_end(&map->spin_lock);
+ BLI_spin_end(&map->spin_lock);
- MEM_freeN(map);
+ MEM_freeN(map);
}
/*********************** Space transformation functions *************************/
@@ -237,70 +247,86 @@ void tracks_map_free(TracksMap *map, void (*customdata_free)(void *customdata))
* window relative coordinates in pixels, and "frame_unified" are unified 0..1
* coordinates relative to the entire frame.
*/
-static void unified_to_pixel(int frame_width, int frame_height,
- const float unified_coords[2], float pixel_coords[2])
+static void unified_to_pixel(int frame_width,
+ int frame_height,
+ const float unified_coords[2],
+ float pixel_coords[2])
{
- pixel_coords[0] = unified_coords[0] * frame_width;
- pixel_coords[1] = unified_coords[1] * frame_height;
+ pixel_coords[0] = unified_coords[0] * frame_width;
+ pixel_coords[1] = unified_coords[1] * frame_height;
}
-static void marker_to_frame_unified(const MovieTrackingMarker *marker, const float marker_unified_coords[2],
+static void marker_to_frame_unified(const MovieTrackingMarker *marker,
+ const float marker_unified_coords[2],
float frame_unified_coords[2])
{
- frame_unified_coords[0] = marker_unified_coords[0] + marker->pos[0];
- frame_unified_coords[1] = marker_unified_coords[1] + marker->pos[1];
+ frame_unified_coords[0] = marker_unified_coords[0] + marker->pos[0];
+ frame_unified_coords[1] = marker_unified_coords[1] + marker->pos[1];
}
-static void marker_unified_to_frame_pixel_coordinates(int frame_width, int frame_height,
+static void marker_unified_to_frame_pixel_coordinates(int frame_width,
+ int frame_height,
const MovieTrackingMarker *marker,
const float marker_unified_coords[2],
float frame_pixel_coords[2])
{
- marker_to_frame_unified(marker, marker_unified_coords, frame_pixel_coords);
- unified_to_pixel(frame_width, frame_height, frame_pixel_coords, frame_pixel_coords);
+ marker_to_frame_unified(marker, marker_unified_coords, frame_pixel_coords);
+ unified_to_pixel(frame_width, frame_height, frame_pixel_coords, frame_pixel_coords);
}
-void tracking_get_search_origin_frame_pixel(int frame_width, int frame_height,
+void tracking_get_search_origin_frame_pixel(int frame_width,
+ int frame_height,
const MovieTrackingMarker *marker,
float frame_pixel[2])
{
- /* Get the lower left coordinate of the search window and snap to pixel coordinates */
- marker_unified_to_frame_pixel_coordinates(frame_width, frame_height, marker, marker->search_min, frame_pixel);
- frame_pixel[0] = (int)frame_pixel[0];
- frame_pixel[1] = (int)frame_pixel[1];
+ /* Get the lower left coordinate of the search window and snap to pixel coordinates */
+ marker_unified_to_frame_pixel_coordinates(
+ frame_width, frame_height, marker, marker->search_min, frame_pixel);
+ frame_pixel[0] = (int)frame_pixel[0];
+ frame_pixel[1] = (int)frame_pixel[1];
}
-static void pixel_to_unified(int frame_width, int frame_height, const float pixel_coords[2], float unified_coords[2])
+static void pixel_to_unified(int frame_width,
+ int frame_height,
+ const float pixel_coords[2],
+ float unified_coords[2])
{
- unified_coords[0] = pixel_coords[0] / frame_width;
- unified_coords[1] = pixel_coords[1] / frame_height;
+ unified_coords[0] = pixel_coords[0] / frame_width;
+ unified_coords[1] = pixel_coords[1] / frame_height;
}
-static void marker_unified_to_search_pixel(int frame_width, int frame_height,
+static void marker_unified_to_search_pixel(int frame_width,
+ int frame_height,
const MovieTrackingMarker *marker,
- const float marker_unified[2], float search_pixel[2])
+ const float marker_unified[2],
+ float search_pixel[2])
{
- float frame_pixel[2];
- float search_origin_frame_pixel[2];
+ float frame_pixel[2];
+ float search_origin_frame_pixel[2];
- marker_unified_to_frame_pixel_coordinates(frame_width, frame_height, marker, marker_unified, frame_pixel);
- tracking_get_search_origin_frame_pixel(frame_width, frame_height, marker, search_origin_frame_pixel);
- sub_v2_v2v2(search_pixel, frame_pixel, search_origin_frame_pixel);
+ marker_unified_to_frame_pixel_coordinates(
+ frame_width, frame_height, marker, marker_unified, frame_pixel);
+ tracking_get_search_origin_frame_pixel(
+ frame_width, frame_height, marker, search_origin_frame_pixel);
+ sub_v2_v2v2(search_pixel, frame_pixel, search_origin_frame_pixel);
}
-static void search_pixel_to_marker_unified(int frame_width, int frame_height,
+static void search_pixel_to_marker_unified(int frame_width,
+ int frame_height,
const MovieTrackingMarker *marker,
- const float search_pixel[2], float marker_unified[2])
+ const float search_pixel[2],
+ float marker_unified[2])
{
- float frame_unified[2];
- float search_origin_frame_pixel[2];
+ float frame_unified[2];
+ float search_origin_frame_pixel[2];
- tracking_get_search_origin_frame_pixel(frame_width, frame_height, marker, search_origin_frame_pixel);
- add_v2_v2v2(frame_unified, search_pixel, search_origin_frame_pixel);
- pixel_to_unified(frame_width, frame_height, frame_unified, frame_unified);
+ tracking_get_search_origin_frame_pixel(
+ frame_width, frame_height, marker, search_origin_frame_pixel);
+ add_v2_v2v2(frame_unified, search_pixel, search_origin_frame_pixel);
+ pixel_to_unified(frame_width, frame_height, frame_unified, frame_unified);
- /* marker pos is in frame unified */
- sub_v2_v2v2(marker_unified, frame_unified, marker->pos);
+ /* marker pos is in frame unified */
+ sub_v2_v2v2(marker_unified, frame_unified, marker->pos);
}
/* Each marker has 5 coordinates associated with it that get warped with
@@ -308,61 +334,68 @@ static void search_pixel_to_marker_unified(int frame_width, int frame_height,
* This function puts those 5 points into the appropriate frame for tracking
* (the "search" coordinate frame).
*/
-void tracking_get_marker_coords_for_tracking(int frame_width, int frame_height,
+void tracking_get_marker_coords_for_tracking(int frame_width,
+ int frame_height,
const MovieTrackingMarker *marker,
- double search_pixel_x[5], double search_pixel_y[5])
+ double search_pixel_x[5],
+ double search_pixel_y[5])
{
- int i;
- float unified_coords[2];
- float pixel_coords[2];
+ int i;
+ float unified_coords[2];
+ float pixel_coords[2];
- /* Convert the corners into search space coordinates. */
- for (i = 0; i < 4; i++) {
- marker_unified_to_search_pixel(frame_width, frame_height, marker, marker->pattern_corners[i], pixel_coords);
- search_pixel_x[i] = pixel_coords[0] - 0.5f;
- search_pixel_y[i] = pixel_coords[1] - 0.5f;
- }
+ /* Convert the corners into search space coordinates. */
+ for (i = 0; i < 4; i++) {
+ marker_unified_to_search_pixel(
+ frame_width, frame_height, marker, marker->pattern_corners[i], pixel_coords);
+ search_pixel_x[i] = pixel_coords[0] - 0.5f;
+ search_pixel_y[i] = pixel_coords[1] - 0.5f;
+ }
- /* Convert the center position (aka "pos"); this is the origin */
- unified_coords[0] = 0.0f;
- unified_coords[1] = 0.0f;
- marker_unified_to_search_pixel(frame_width, frame_height, marker, unified_coords, pixel_coords);
+ /* Convert the center position (aka "pos"); this is the origin */
+ unified_coords[0] = 0.0f;
+ unified_coords[1] = 0.0f;
+ marker_unified_to_search_pixel(frame_width, frame_height, marker, unified_coords, pixel_coords);
- search_pixel_x[4] = pixel_coords[0] - 0.5f;
- search_pixel_y[4] = pixel_coords[1] - 0.5f;
+ search_pixel_x[4] = pixel_coords[0] - 0.5f;
+ search_pixel_y[4] = pixel_coords[1] - 0.5f;
}
/* Inverse of above. */
-void tracking_set_marker_coords_from_tracking(int frame_width, int frame_height, MovieTrackingMarker *marker,
- const double search_pixel_x[5], const double search_pixel_y[5])
-{
- int i;
- float marker_unified[2];
- float search_pixel[2];
-
- /* Convert the corners into search space coordinates. */
- for (i = 0; i < 4; i++) {
- search_pixel[0] = search_pixel_x[i] + 0.5;
- search_pixel[1] = search_pixel_y[i] + 0.5;
- search_pixel_to_marker_unified(frame_width, frame_height, marker, search_pixel, marker->pattern_corners[i]);
- }
-
- /* Convert the center position (aka "pos"); this is the origin */
- search_pixel[0] = search_pixel_x[4] + 0.5;
- search_pixel[1] = search_pixel_y[4] + 0.5;
- search_pixel_to_marker_unified(frame_width, frame_height, marker, search_pixel, marker_unified);
-
- /* If the tracker tracked nothing, then "marker_unified" would be zero.
- * Otherwise, the entire patch shifted, and that delta should be applied to
- * all the coordinates.
- */
- for (i = 0; i < 4; i++) {
- marker->pattern_corners[i][0] -= marker_unified[0];
- marker->pattern_corners[i][1] -= marker_unified[1];
- }
-
- marker->pos[0] += marker_unified[0];
- marker->pos[1] += marker_unified[1];
+void tracking_set_marker_coords_from_tracking(int frame_width,
+ int frame_height,
+ MovieTrackingMarker *marker,
+ const double search_pixel_x[5],
+ const double search_pixel_y[5])
+{
+ int i;
+ float marker_unified[2];
+ float search_pixel[2];
+
+ /* Convert the corners into search space coordinates. */
+ for (i = 0; i < 4; i++) {
+ search_pixel[0] = search_pixel_x[i] + 0.5;
+ search_pixel[1] = search_pixel_y[i] + 0.5;
+ search_pixel_to_marker_unified(
+ frame_width, frame_height, marker, search_pixel, marker->pattern_corners[i]);
+ }
+
+ /* Convert the center position (aka "pos"); this is the origin */
+ search_pixel[0] = search_pixel_x[4] + 0.5;
+ search_pixel[1] = search_pixel_y[4] + 0.5;
+ search_pixel_to_marker_unified(frame_width, frame_height, marker, search_pixel, marker_unified);
+
+ /* If the tracker tracked nothing, then "marker_unified" would be zero.
+ * Otherwise, the entire patch shifted, and that delta should be applied to
+ * all the coordinates.
+ */
+ for (i = 0; i < 4; i++) {
+ marker->pattern_corners[i][0] -= marker_unified[0];
+ marker->pattern_corners[i][1] -= marker_unified[1];
+ }
+
+ marker->pos[0] += marker_unified[0];
+ marker->pos[1] += marker_unified[1];
}
/*********************** General purpose utility functions *************************/
@@ -376,88 +409,91 @@ void tracking_set_marker_coords_from_tracking(int frame_width, int frame_height,
* is expected to be placed, nothing will happen if overwrite
* is false.
*/
-void tracking_marker_insert_disabled(MovieTrackingTrack *track, const MovieTrackingMarker *ref_marker,
- bool before, bool overwrite)
+void tracking_marker_insert_disabled(MovieTrackingTrack *track,
+ const MovieTrackingMarker *ref_marker,
+ bool before,
+ bool overwrite)
{
- MovieTrackingMarker marker_new;
+ MovieTrackingMarker marker_new;
- marker_new = *ref_marker;
- marker_new.flag &= ~MARKER_TRACKED;
- marker_new.flag |= MARKER_DISABLED;
+ marker_new = *ref_marker;
+ marker_new.flag &= ~MARKER_TRACKED;
+ marker_new.flag |= MARKER_DISABLED;
- if (before)
- marker_new.framenr--;
- else
- marker_new.framenr++;
+ if (before)
+ marker_new.framenr--;
+ else
+ marker_new.framenr++;
- if (overwrite || !BKE_tracking_track_has_marker_at_frame(track, marker_new.framenr))
- BKE_tracking_marker_insert(track, &marker_new);
+ if (overwrite || !BKE_tracking_track_has_marker_at_frame(track, marker_new.framenr))
+ BKE_tracking_marker_insert(track, &marker_new);
}
-
/* Fill in Libmv C-API camera intrinsics options from tracking structure. */
-void tracking_cameraIntrinscisOptionsFromTracking(MovieTracking *tracking,
- int calibration_width, int calibration_height,
- libmv_CameraIntrinsicsOptions *camera_intrinsics_options)
-{
- MovieTrackingCamera *camera = &tracking->camera;
- float aspy = 1.0f / tracking->camera.pixel_aspect;
-
- camera_intrinsics_options->focal_length = camera->focal;
-
- camera_intrinsics_options->principal_point_x = camera->principal[0];
- camera_intrinsics_options->principal_point_y = camera->principal[1] * aspy;
-
- switch (camera->distortion_model) {
- case TRACKING_DISTORTION_MODEL_POLYNOMIAL:
- camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_POLYNOMIAL;
- camera_intrinsics_options->polynomial_k1 = camera->k1;
- camera_intrinsics_options->polynomial_k2 = camera->k2;
- camera_intrinsics_options->polynomial_k3 = camera->k3;
- camera_intrinsics_options->polynomial_p1 = 0.0;
- camera_intrinsics_options->polynomial_p2 = 0.0;
- break;
- case TRACKING_DISTORTION_MODEL_DIVISION:
- camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_DIVISION;
- camera_intrinsics_options->division_k1 = camera->division_k1;
- camera_intrinsics_options->division_k2 = camera->division_k2;
- break;
- default:
- BLI_assert(!"Unknown distortion model");
- break;
- }
-
- camera_intrinsics_options->image_width = calibration_width;
- camera_intrinsics_options->image_height = (int) (calibration_height * aspy);
-}
-
-void tracking_trackingCameraFromIntrinscisOptions(MovieTracking *tracking,
- const libmv_CameraIntrinsicsOptions *camera_intrinsics_options)
-{
- float aspy = 1.0f / tracking->camera.pixel_aspect;
- MovieTrackingCamera *camera = &tracking->camera;
-
- camera->focal = camera_intrinsics_options->focal_length;
-
- camera->principal[0] = camera_intrinsics_options->principal_point_x;
- camera->principal[1] = camera_intrinsics_options->principal_point_y / (double) aspy;
-
- switch (camera_intrinsics_options->distortion_model) {
- case LIBMV_DISTORTION_MODEL_POLYNOMIAL:
- camera->distortion_model = TRACKING_DISTORTION_MODEL_POLYNOMIAL;
- camera->k1 = camera_intrinsics_options->polynomial_k1;
- camera->k2 = camera_intrinsics_options->polynomial_k2;
- camera->k3 = camera_intrinsics_options->polynomial_k3;
- break;
- case LIBMV_DISTORTION_MODEL_DIVISION:
- camera->distortion_model = TRACKING_DISTORTION_MODEL_DIVISION;
- camera->division_k1 = camera_intrinsics_options->division_k1;
- camera->division_k2 = camera_intrinsics_options->division_k2;
- break;
- default:
- BLI_assert(!"Unknown distortion model");
- break;
- }
+void tracking_cameraIntrinscisOptionsFromTracking(
+ MovieTracking *tracking,
+ int calibration_width,
+ int calibration_height,
+ libmv_CameraIntrinsicsOptions *camera_intrinsics_options)
+{
+ MovieTrackingCamera *camera = &tracking->camera;
+ float aspy = 1.0f / tracking->camera.pixel_aspect;
+
+ camera_intrinsics_options->focal_length = camera->focal;
+
+ camera_intrinsics_options->principal_point_x = camera->principal[0];
+ camera_intrinsics_options->principal_point_y = camera->principal[1] * aspy;
+
+ switch (camera->distortion_model) {
+ case TRACKING_DISTORTION_MODEL_POLYNOMIAL:
+ camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_POLYNOMIAL;
+ camera_intrinsics_options->polynomial_k1 = camera->k1;
+ camera_intrinsics_options->polynomial_k2 = camera->k2;
+ camera_intrinsics_options->polynomial_k3 = camera->k3;
+ camera_intrinsics_options->polynomial_p1 = 0.0;
+ camera_intrinsics_options->polynomial_p2 = 0.0;
+ break;
+ case TRACKING_DISTORTION_MODEL_DIVISION:
+ camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_DIVISION;
+ camera_intrinsics_options->division_k1 = camera->division_k1;
+ camera_intrinsics_options->division_k2 = camera->division_k2;
+ break;
+ default:
+ BLI_assert(!"Unknown distortion model");
+ break;
+ }
+
+ camera_intrinsics_options->image_width = calibration_width;
+ camera_intrinsics_options->image_height = (int)(calibration_height * aspy);
+}
+
+void tracking_trackingCameraFromIntrinscisOptions(
+ MovieTracking *tracking, const libmv_CameraIntrinsicsOptions *camera_intrinsics_options)
+{
+ float aspy = 1.0f / tracking->camera.pixel_aspect;
+ MovieTrackingCamera *camera = &tracking->camera;
+
+ camera->focal = camera_intrinsics_options->focal_length;
+
+ camera->principal[0] = camera_intrinsics_options->principal_point_x;
+ camera->principal[1] = camera_intrinsics_options->principal_point_y / (double)aspy;
+
+ switch (camera_intrinsics_options->distortion_model) {
+ case LIBMV_DISTORTION_MODEL_POLYNOMIAL:
+ camera->distortion_model = TRACKING_DISTORTION_MODEL_POLYNOMIAL;
+ camera->k1 = camera_intrinsics_options->polynomial_k1;
+ camera->k2 = camera_intrinsics_options->polynomial_k2;
+ camera->k3 = camera_intrinsics_options->polynomial_k3;
+ break;
+ case LIBMV_DISTORTION_MODEL_DIVISION:
+ camera->distortion_model = TRACKING_DISTORTION_MODEL_DIVISION;
+ camera->division_k1 = camera_intrinsics_options->division_k1;
+ camera->division_k2 = camera_intrinsics_options->division_k2;
+ break;
+ default:
+ BLI_assert(!"Unknown distortion model");
+ break;
+ }
}
/* Get previous keyframed marker. */
@@ -465,99 +501,93 @@ MovieTrackingMarker *tracking_get_keyframed_marker(MovieTrackingTrack *track,
int current_frame,
bool backwards)
{
- MovieTrackingMarker *marker_keyed = NULL;
- MovieTrackingMarker *marker_keyed_fallback = NULL;
- int a = BKE_tracking_marker_get(track, current_frame) - track->markers;
-
- while (a >= 0 && a < track->markersnr) {
- int next = backwards ? a + 1 : a - 1;
- bool is_keyframed = false;
- MovieTrackingMarker *cur_marker = &track->markers[a];
- MovieTrackingMarker *next_marker = NULL;
-
- if (next >= 0 && next < track->markersnr)
- next_marker = &track->markers[next];
-
- if ((cur_marker->flag & MARKER_DISABLED) == 0) {
- /* If it'll happen so we didn't find a real keyframe marker,
- * fallback to the first marker in current tracked segment
- * as a keyframe.
- */
- if (next_marker == NULL) {
- /* Could happen when trying to get reference marker for the fist
- * one on the segment which isn't surrounded by disabled markers.
- *
- * There's no really good choice here, just use the reference
- * marker which looks correct..
- */
- if (marker_keyed_fallback == NULL) {
- marker_keyed_fallback = cur_marker;
- }
- }
- else if (next_marker->flag & MARKER_DISABLED) {
- if (marker_keyed_fallback == NULL)
- marker_keyed_fallback = cur_marker;
- }
-
- is_keyframed |= (cur_marker->flag & MARKER_TRACKED) == 0;
- }
-
- if (is_keyframed) {
- marker_keyed = cur_marker;
-
- break;
- }
-
- a = next;
- }
-
- if (marker_keyed == NULL)
- marker_keyed = marker_keyed_fallback;
-
- return marker_keyed;
+ MovieTrackingMarker *marker_keyed = NULL;
+ MovieTrackingMarker *marker_keyed_fallback = NULL;
+ int a = BKE_tracking_marker_get(track, current_frame) - track->markers;
+
+ while (a >= 0 && a < track->markersnr) {
+ int next = backwards ? a + 1 : a - 1;
+ bool is_keyframed = false;
+ MovieTrackingMarker *cur_marker = &track->markers[a];
+ MovieTrackingMarker *next_marker = NULL;
+
+ if (next >= 0 && next < track->markersnr)
+ next_marker = &track->markers[next];
+
+ if ((cur_marker->flag & MARKER_DISABLED) == 0) {
+ /* If it'll happen so we didn't find a real keyframe marker,
+ * fallback to the first marker in current tracked segment
+ * as a keyframe.
+ */
+ if (next_marker == NULL) {
+ /* Could happen when trying to get reference marker for the fist
+ * one on the segment which isn't surrounded by disabled markers.
+ *
+ * There's no really good choice here, just use the reference
+ * marker which looks correct..
+ */
+ if (marker_keyed_fallback == NULL) {
+ marker_keyed_fallback = cur_marker;
+ }
+ }
+ else if (next_marker->flag & MARKER_DISABLED) {
+ if (marker_keyed_fallback == NULL)
+ marker_keyed_fallback = cur_marker;
+ }
+
+ is_keyframed |= (cur_marker->flag & MARKER_TRACKED) == 0;
+ }
+
+ if (is_keyframed) {
+ marker_keyed = cur_marker;
+
+ break;
+ }
+
+ a = next;
+ }
+
+ if (marker_keyed == NULL)
+ marker_keyed = marker_keyed_fallback;
+
+ return marker_keyed;
}
/*********************** Frame accessr *************************/
typedef struct AccessCacheKey {
- int clip_index;
- int frame;
- int downscale;
- libmv_InputMode input_mode;
- bool has_region;
- float region_min[2], region_max[2];
- int64_t transform_key;
+ int clip_index;
+ int frame;
+ int downscale;
+ libmv_InputMode input_mode;
+ bool has_region;
+ float region_min[2], region_max[2];
+ int64_t transform_key;
} AccessCacheKey;
static unsigned int accesscache_hashhash(const void *key_v)
{
- const AccessCacheKey *key = (const AccessCacheKey *) key_v;
- /* TODP(sergey): Need better hashing here for faster frame access. */
- return key->clip_index << 16 | key->frame;
+ const AccessCacheKey *key = (const AccessCacheKey *)key_v;
+ /* TODP(sergey): Need better hashing here for faster frame access. */
+ return key->clip_index << 16 | key->frame;
}
static bool accesscache_hashcmp(const void *a_v, const void *b_v)
{
- const AccessCacheKey *a = (const AccessCacheKey *) a_v;
- const AccessCacheKey *b = (const AccessCacheKey *) b_v;
- if (a->clip_index != b->clip_index ||
- a->frame != b->frame ||
- a->downscale != b->downscale ||
- a->input_mode != b->input_mode ||
- a->has_region != b->has_region ||
- a->transform_key != b->transform_key)
- {
- return true;
- }
- /* If there is region applied, compare it. */
- if (a->has_region) {
- if (!equals_v2v2(a->region_min, b->region_min) ||
- !equals_v2v2(a->region_max, b->region_max))
- {
- return true;
- }
- }
- return false;
+ const AccessCacheKey *a = (const AccessCacheKey *)a_v;
+ const AccessCacheKey *b = (const AccessCacheKey *)b_v;
+ if (a->clip_index != b->clip_index || a->frame != b->frame || a->downscale != b->downscale ||
+ a->input_mode != b->input_mode || a->has_region != b->has_region ||
+ a->transform_key != b->transform_key) {
+ return true;
+ }
+ /* If there is region applied, compare it. */
+ if (a->has_region) {
+ if (!equals_v2v2(a->region_min, b->region_min) || !equals_v2v2(a->region_max, b->region_max)) {
+ return true;
+ }
+ }
+ return false;
}
static void accesscache_construct_key(AccessCacheKey *key,
@@ -568,16 +598,16 @@ static void accesscache_construct_key(AccessCacheKey *key,
const libmv_Region *region,
int64_t transform_key)
{
- key->clip_index = clip_index;
- key->frame = frame;
- key->input_mode = input_mode;
- key->downscale = downscale;
- key->has_region = (region != NULL);
- if (key->has_region) {
- copy_v2_v2(key->region_min, region->min);
- copy_v2_v2(key->region_max, region->max);
- }
- key->transform_key = transform_key;
+ key->clip_index = clip_index;
+ key->frame = frame;
+ key->input_mode = input_mode;
+ key->downscale = downscale;
+ key->has_region = (region != NULL);
+ if (key->has_region) {
+ copy_v2_v2(key->region_min, region->min);
+ copy_v2_v2(key->region_max, region->max);
+ }
+ key->transform_key = transform_key;
}
static void accesscache_put(TrackingImageAccessor *accessor,
@@ -589,10 +619,9 @@ static void accesscache_put(TrackingImageAccessor *accessor,
int64_t transform_key,
ImBuf *ibuf)
{
- AccessCacheKey key;
- accesscache_construct_key(&key, clip_index, frame, input_mode, downscale,
- region, transform_key);
- IMB_moviecache_put(accessor->cache, &key, ibuf);
+ AccessCacheKey key;
+ accesscache_construct_key(&key, clip_index, frame, input_mode, downscale, region, transform_key);
+ IMB_moviecache_put(accessor->cache, &key, ibuf);
}
static ImBuf *accesscache_get(TrackingImageAccessor *accessor,
@@ -603,85 +632,82 @@ static ImBuf *accesscache_get(TrackingImageAccessor *accessor,
const libmv_Region *region,
int64_t transform_key)
{
- AccessCacheKey key;
- accesscache_construct_key(&key, clip_index, frame, input_mode, downscale,
- region, transform_key);
- return IMB_moviecache_get(accessor->cache, &key);
+ AccessCacheKey key;
+ accesscache_construct_key(&key, clip_index, frame, input_mode, downscale, region, transform_key);
+ return IMB_moviecache_get(accessor->cache, &key);
}
static ImBuf *accessor_get_preprocessed_ibuf(TrackingImageAccessor *accessor,
int clip_index,
int frame)
{
- MovieClip *clip;
- MovieClipUser user;
- ImBuf *ibuf;
- int scene_frame;
+ MovieClip *clip;
+ MovieClipUser user;
+ ImBuf *ibuf;
+ int scene_frame;
- BLI_assert(clip_index < accessor->num_clips);
+ BLI_assert(clip_index < accessor->num_clips);
- clip = accessor->clips[clip_index];
- scene_frame = BKE_movieclip_remap_clip_to_scene_frame(clip, frame);
- BKE_movieclip_user_set_frame(&user, scene_frame);
- user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL;
- user.render_flag = 0;
- ibuf = BKE_movieclip_get_ibuf(clip, &user);
+ clip = accessor->clips[clip_index];
+ scene_frame = BKE_movieclip_remap_clip_to_scene_frame(clip, frame);
+ BKE_movieclip_user_set_frame(&user, scene_frame);
+ user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL;
+ user.render_flag = 0;
+ ibuf = BKE_movieclip_get_ibuf(clip, &user);
- return ibuf;
+ return ibuf;
}
static ImBuf *make_grayscale_ibuf_copy(ImBuf *ibuf)
{
- ImBuf *grayscale = IMB_allocImBuf(ibuf->x, ibuf->y, 32, 0);
- size_t size;
- int i;
+ ImBuf *grayscale = IMB_allocImBuf(ibuf->x, ibuf->y, 32, 0);
+ size_t size;
+ int i;
- BLI_assert(ibuf->channels == 3 || ibuf->channels == 4);
+ BLI_assert(ibuf->channels == 3 || ibuf->channels == 4);
- /* TODO(sergey): Bummer, currently IMB API only allows to create 4 channels
- * float buffer, so we do it manually here.
- *
- * Will generalize it later.
- */
- size = (size_t)grayscale->x * (size_t)grayscale->y * sizeof(float);
- grayscale->channels = 1;
- if ((grayscale->rect_float = MEM_mapallocN(size, "tracking grayscale image")) != NULL) {
- grayscale->mall |= IB_rectfloat;
- grayscale->flags |= IB_rectfloat;
+ /* TODO(sergey): Bummer, currently IMB API only allows to create 4 channels
+ * float buffer, so we do it manually here.
+ *
+ * Will generalize it later.
+ */
+ size = (size_t)grayscale->x * (size_t)grayscale->y * sizeof(float);
+ grayscale->channels = 1;
+ if ((grayscale->rect_float = MEM_mapallocN(size, "tracking grayscale image")) != NULL) {
+ grayscale->mall |= IB_rectfloat;
+ grayscale->flags |= IB_rectfloat;
- for (i = 0; i < grayscale->x * grayscale->y; ++i) {
- const float *pixel = ibuf->rect_float + ibuf->channels * i;
+ for (i = 0; i < grayscale->x * grayscale->y; ++i) {
+ const float *pixel = ibuf->rect_float + ibuf->channels * i;
- grayscale->rect_float[i] = 0.2126f * pixel[0] +
- 0.7152f * pixel[1] +
- 0.0722f * pixel[2];
- }
- }
+ grayscale->rect_float[i] = 0.2126f * pixel[0] + 0.7152f * pixel[1] + 0.0722f * pixel[2];
+ }
+ }
- return grayscale;
+ return grayscale;
}
static void ibuf_to_float_image(const ImBuf *ibuf, libmv_FloatImage *float_image)
{
- BLI_assert(ibuf->rect_float != NULL);
- float_image->buffer = ibuf->rect_float;
- float_image->width = ibuf->x;
- float_image->height = ibuf->y;
- float_image->channels = ibuf->channels;
+ BLI_assert(ibuf->rect_float != NULL);
+ float_image->buffer = ibuf->rect_float;
+ float_image->width = ibuf->x;
+ float_image->height = ibuf->y;
+ float_image->channels = ibuf->channels;
}
static ImBuf *float_image_to_ibuf(libmv_FloatImage *float_image)
{
- ImBuf *ibuf = IMB_allocImBuf(float_image->width, float_image->height, 32, 0);
- size_t size = (size_t)ibuf->x * (size_t)ibuf->y * float_image->channels * sizeof(float);
- ibuf->channels = float_image->channels;
- if ((ibuf->rect_float = MEM_mapallocN(size, "tracking grayscale image")) != NULL) {
- ibuf->mall |= IB_rectfloat;
- ibuf->flags |= IB_rectfloat;
+ ImBuf *ibuf = IMB_allocImBuf(float_image->width, float_image->height, 32, 0);
+ size_t size = (size_t)ibuf->x * (size_t)ibuf->y * float_image->channels * sizeof(float);
+ ibuf->channels = float_image->channels;
+ if ((ibuf->rect_float = MEM_mapallocN(size, "tracking grayscale image")) != NULL) {
+ ibuf->mall |= IB_rectfloat;
+ ibuf->flags |= IB_rectfloat;
- memcpy(ibuf->rect_float, float_image->buffer, size);
- }
- return ibuf;
+ memcpy(ibuf->rect_float, float_image->buffer, size);
+ }
+ return ibuf;
}
static ImBuf *accessor_get_ibuf(TrackingImageAccessor *accessor,
@@ -692,258 +718,232 @@ static ImBuf *accessor_get_ibuf(TrackingImageAccessor *accessor,
const libmv_Region *region,
const libmv_FrameTransform *transform)
{
- ImBuf *ibuf, *orig_ibuf, *final_ibuf;
- int64_t transform_key = 0;
- if (transform != NULL) {
- transform_key = libmv_frameAccessorgetTransformKey(transform);
- }
- /* First try to get fully processed image from the cache. */
- BLI_spin_lock(&accessor->cache_lock);
- ibuf = accesscache_get(accessor,
- clip_index,
- frame,
- input_mode,
- downscale,
- region,
- transform_key);
- BLI_spin_unlock(&accessor->cache_lock);
- if (ibuf != NULL) {
- CACHE_PRINTF("Used cached buffer for frame %d\n", frame);
- /* This is a little heuristic here: if we re-used image once, this is
- * a high probability of the image to be related to a keyframe matched
- * reference image. Those images we don't want to be thrown away because
- * if we toss them out we'll be re-calculating them at the next
- * iteration.
- */
- ibuf->userflags |= IB_PERSISTENT;
- return ibuf;
- }
- CACHE_PRINTF("Calculate new buffer for frame %d\n", frame);
- /* And now we do postprocessing of the original frame. */
- orig_ibuf = accessor_get_preprocessed_ibuf(accessor, clip_index, frame);
- if (orig_ibuf == NULL) {
- return NULL;
- }
- /* Cut a region if requested. */
- if (region != NULL) {
- int width = region->max[0] - region->min[0],
- height = region->max[1] - region->min[1];
-
- /* If the requested region goes outside of the actual frame we still
- * return the requested region size, but only fill it's partially with
- * the data we can.
- */
- int clamped_origin_x = max_ii((int)region->min[0], 0),
- clamped_origin_y = max_ii((int)region->min[1], 0);
- int dst_offset_x = clamped_origin_x - (int)region->min[0],
- dst_offset_y = clamped_origin_y - (int)region->min[1];
- int clamped_width = width - dst_offset_x,
- clamped_height = height - dst_offset_y;
- clamped_width = min_ii(clamped_width, orig_ibuf->x - clamped_origin_x);
- clamped_height = min_ii(clamped_height, orig_ibuf->y - clamped_origin_y);
-
- final_ibuf = IMB_allocImBuf(width, height, 32, IB_rectfloat);
-
- if (orig_ibuf->rect_float != NULL) {
- IMB_rectcpy(final_ibuf, orig_ibuf,
- dst_offset_x, dst_offset_y,
- clamped_origin_x, clamped_origin_y,
- clamped_width, clamped_height);
- }
- else {
- int y;
- /* TODO(sergey): We don't do any color space or alpha conversion
- * here. Probably Libmv is better to work in the linear space,
- * but keep sRGB space here for compatibility for now.
- */
- for (y = 0; y < clamped_height; ++y) {
- int x;
- for (x = 0; x < clamped_width; ++x) {
- int src_x = x + clamped_origin_x,
- src_y = y + clamped_origin_y;
- int dst_x = x + dst_offset_x,
- dst_y = y + dst_offset_y;
- int dst_index = (dst_y * width + dst_x) * 4,
- src_index = (src_y * orig_ibuf->x + src_x) * 4;
- rgba_uchar_to_float(final_ibuf->rect_float + dst_index,
- (unsigned char *)orig_ibuf->rect +
- src_index);
- }
- }
- }
- }
- else {
- /* Libmv only works with float images,
- *
- * This would likely make it so loads of float buffers are being stored
- * in the cache which is nice on the one hand (faster re-use of the
- * frames) but on the other hand it bumps the memory usage up.
- */
- BLI_thread_lock(LOCK_MOVIECLIP);
- IMB_float_from_rect(orig_ibuf);
- BLI_thread_unlock(LOCK_MOVIECLIP);
- final_ibuf = orig_ibuf;
- }
- /* Downscale if needed. */
- if (downscale > 0) {
- if (final_ibuf == orig_ibuf) {
- final_ibuf = IMB_dupImBuf(orig_ibuf);
- }
- IMB_scaleImBuf(final_ibuf,
- orig_ibuf->x / (1 << downscale),
- orig_ibuf->y / (1 << downscale));
- }
- /* Apply possible transformation. */
- if (transform != NULL) {
- libmv_FloatImage input_image, output_image;
- ibuf_to_float_image(final_ibuf, &input_image);
- libmv_frameAccessorgetTransformRun(transform,
- &input_image,
- &output_image);
- if (final_ibuf != orig_ibuf) {
- IMB_freeImBuf(final_ibuf);
- }
- final_ibuf = float_image_to_ibuf(&output_image);
- libmv_floatImageDestroy(&output_image);
- }
- /* Transform number of channels. */
- if (input_mode == LIBMV_IMAGE_MODE_RGBA) {
- BLI_assert(orig_ibuf->channels == 3 || orig_ibuf->channels == 4);
- /* pass */
- }
- else /* if (input_mode == LIBMV_IMAGE_MODE_MONO) */ {
- BLI_assert(input_mode == LIBMV_IMAGE_MODE_MONO);
- if (final_ibuf->channels != 1) {
- ImBuf *grayscale_ibuf = make_grayscale_ibuf_copy(final_ibuf);
- if (final_ibuf != orig_ibuf) {
- /* We dereference original frame later. */
- IMB_freeImBuf(final_ibuf);
- }
- final_ibuf = grayscale_ibuf;
- }
- }
- /* It's possible processing still didn't happen at this point,
- * but we really need a copy of the buffer to be transformed
- * and to be put to the cache.
- */
- if (final_ibuf == orig_ibuf) {
- final_ibuf = IMB_dupImBuf(orig_ibuf);
- }
- IMB_freeImBuf(orig_ibuf);
- BLI_spin_lock(&accessor->cache_lock);
- /* Put final buffer to cache. */
- accesscache_put(accessor,
- clip_index,
- frame,
- input_mode,
- downscale,
- region,
- transform_key,
- final_ibuf);
- BLI_spin_unlock(&accessor->cache_lock);
- return final_ibuf;
-}
-
-static libmv_CacheKey accessor_get_image_callback(
- struct libmv_FrameAccessorUserData *user_data,
- int clip_index,
- int frame,
- libmv_InputMode input_mode,
- int downscale,
- const libmv_Region *region,
- const libmv_FrameTransform *transform,
- float **destination,
- int *width,
- int *height,
- int *channels)
-{
- TrackingImageAccessor *accessor = (TrackingImageAccessor *) user_data;
- ImBuf *ibuf;
-
- BLI_assert(clip_index >= 0 && clip_index < accessor->num_clips);
-
- ibuf = accessor_get_ibuf(accessor,
- clip_index,
- frame,
- input_mode,
- downscale,
- region,
- transform);
-
- if (ibuf) {
- *destination = ibuf->rect_float;
- *width = ibuf->x;
- *height = ibuf->y;
- *channels = ibuf->channels;
- }
- else {
- *destination = NULL;
- *width = 0;
- *height = 0;
- *channels = 0;
- }
-
- return ibuf;
+ ImBuf *ibuf, *orig_ibuf, *final_ibuf;
+ int64_t transform_key = 0;
+ if (transform != NULL) {
+ transform_key = libmv_frameAccessorgetTransformKey(transform);
+ }
+ /* First try to get fully processed image from the cache. */
+ BLI_spin_lock(&accessor->cache_lock);
+ ibuf = accesscache_get(
+ accessor, clip_index, frame, input_mode, downscale, region, transform_key);
+ BLI_spin_unlock(&accessor->cache_lock);
+ if (ibuf != NULL) {
+ CACHE_PRINTF("Used cached buffer for frame %d\n", frame);
+ /* This is a little heuristic here: if we re-used image once, this is
+ * a high probability of the image to be related to a keyframe matched
+ * reference image. Those images we don't want to be thrown away because
+ * if we toss them out we'll be re-calculating them at the next
+ * iteration.
+ */
+ ibuf->userflags |= IB_PERSISTENT;
+ return ibuf;
+ }
+ CACHE_PRINTF("Calculate new buffer for frame %d\n", frame);
+ /* And now we do postprocessing of the original frame. */
+ orig_ibuf = accessor_get_preprocessed_ibuf(accessor, clip_index, frame);
+ if (orig_ibuf == NULL) {
+ return NULL;
+ }
+ /* Cut a region if requested. */
+ if (region != NULL) {
+ int width = region->max[0] - region->min[0], height = region->max[1] - region->min[1];
+
+ /* If the requested region goes outside of the actual frame we still
+ * return the requested region size, but only fill it's partially with
+ * the data we can.
+ */
+ int clamped_origin_x = max_ii((int)region->min[0], 0),
+ clamped_origin_y = max_ii((int)region->min[1], 0);
+ int dst_offset_x = clamped_origin_x - (int)region->min[0],
+ dst_offset_y = clamped_origin_y - (int)region->min[1];
+ int clamped_width = width - dst_offset_x, clamped_height = height - dst_offset_y;
+ clamped_width = min_ii(clamped_width, orig_ibuf->x - clamped_origin_x);
+ clamped_height = min_ii(clamped_height, orig_ibuf->y - clamped_origin_y);
+
+ final_ibuf = IMB_allocImBuf(width, height, 32, IB_rectfloat);
+
+ if (orig_ibuf->rect_float != NULL) {
+ IMB_rectcpy(final_ibuf,
+ orig_ibuf,
+ dst_offset_x,
+ dst_offset_y,
+ clamped_origin_x,
+ clamped_origin_y,
+ clamped_width,
+ clamped_height);
+ }
+ else {
+ int y;
+ /* TODO(sergey): We don't do any color space or alpha conversion
+ * here. Probably Libmv is better to work in the linear space,
+ * but keep sRGB space here for compatibility for now.
+ */
+ for (y = 0; y < clamped_height; ++y) {
+ int x;
+ for (x = 0; x < clamped_width; ++x) {
+ int src_x = x + clamped_origin_x, src_y = y + clamped_origin_y;
+ int dst_x = x + dst_offset_x, dst_y = y + dst_offset_y;
+ int dst_index = (dst_y * width + dst_x) * 4,
+ src_index = (src_y * orig_ibuf->x + src_x) * 4;
+ rgba_uchar_to_float(final_ibuf->rect_float + dst_index,
+ (unsigned char *)orig_ibuf->rect + src_index);
+ }
+ }
+ }
+ }
+ else {
+ /* Libmv only works with float images,
+ *
+ * This would likely make it so loads of float buffers are being stored
+ * in the cache which is nice on the one hand (faster re-use of the
+ * frames) but on the other hand it bumps the memory usage up.
+ */
+ BLI_thread_lock(LOCK_MOVIECLIP);
+ IMB_float_from_rect(orig_ibuf);
+ BLI_thread_unlock(LOCK_MOVIECLIP);
+ final_ibuf = orig_ibuf;
+ }
+ /* Downscale if needed. */
+ if (downscale > 0) {
+ if (final_ibuf == orig_ibuf) {
+ final_ibuf = IMB_dupImBuf(orig_ibuf);
+ }
+ IMB_scaleImBuf(final_ibuf, orig_ibuf->x / (1 << downscale), orig_ibuf->y / (1 << downscale));
+ }
+ /* Apply possible transformation. */
+ if (transform != NULL) {
+ libmv_FloatImage input_image, output_image;
+ ibuf_to_float_image(final_ibuf, &input_image);
+ libmv_frameAccessorgetTransformRun(transform, &input_image, &output_image);
+ if (final_ibuf != orig_ibuf) {
+ IMB_freeImBuf(final_ibuf);
+ }
+ final_ibuf = float_image_to_ibuf(&output_image);
+ libmv_floatImageDestroy(&output_image);
+ }
+ /* Transform number of channels. */
+ if (input_mode == LIBMV_IMAGE_MODE_RGBA) {
+ BLI_assert(orig_ibuf->channels == 3 || orig_ibuf->channels == 4);
+ /* pass */
+ }
+ else /* if (input_mode == LIBMV_IMAGE_MODE_MONO) */ {
+ BLI_assert(input_mode == LIBMV_IMAGE_MODE_MONO);
+ if (final_ibuf->channels != 1) {
+ ImBuf *grayscale_ibuf = make_grayscale_ibuf_copy(final_ibuf);
+ if (final_ibuf != orig_ibuf) {
+ /* We dereference original frame later. */
+ IMB_freeImBuf(final_ibuf);
+ }
+ final_ibuf = grayscale_ibuf;
+ }
+ }
+ /* It's possible processing still didn't happen at this point,
+ * but we really need a copy of the buffer to be transformed
+ * and to be put to the cache.
+ */
+ if (final_ibuf == orig_ibuf) {
+ final_ibuf = IMB_dupImBuf(orig_ibuf);
+ }
+ IMB_freeImBuf(orig_ibuf);
+ BLI_spin_lock(&accessor->cache_lock);
+ /* Put final buffer to cache. */
+ accesscache_put(
+ accessor, clip_index, frame, input_mode, downscale, region, transform_key, final_ibuf);
+ BLI_spin_unlock(&accessor->cache_lock);
+ return final_ibuf;
+}
+
+static libmv_CacheKey accessor_get_image_callback(struct libmv_FrameAccessorUserData *user_data,
+ int clip_index,
+ int frame,
+ libmv_InputMode input_mode,
+ int downscale,
+ const libmv_Region *region,
+ const libmv_FrameTransform *transform,
+ float **destination,
+ int *width,
+ int *height,
+ int *channels)
+{
+ TrackingImageAccessor *accessor = (TrackingImageAccessor *)user_data;
+ ImBuf *ibuf;
+
+ BLI_assert(clip_index >= 0 && clip_index < accessor->num_clips);
+
+ ibuf = accessor_get_ibuf(accessor, clip_index, frame, input_mode, downscale, region, transform);
+
+ if (ibuf) {
+ *destination = ibuf->rect_float;
+ *width = ibuf->x;
+ *height = ibuf->y;
+ *channels = ibuf->channels;
+ }
+ else {
+ *destination = NULL;
+ *width = 0;
+ *height = 0;
+ *channels = 0;
+ }
+
+ return ibuf;
}
static void accessor_release_image_callback(libmv_CacheKey cache_key)
{
- ImBuf *ibuf = (ImBuf *) cache_key;
- IMB_freeImBuf(ibuf);
-}
-
-static libmv_CacheKey accessor_get_mask_for_track_callback(
- libmv_FrameAccessorUserData *user_data,
- int clip_index,
- int frame,
- int track_index,
- const libmv_Region *region,
- float **r_destination,
- int *r_width,
- int *r_height)
-{
- /* Perform sanity checks first. */
- TrackingImageAccessor *accessor = (TrackingImageAccessor *) user_data;
- BLI_assert(clip_index < accessor->num_clips);
- BLI_assert(track_index < accessor->num_tracks);
- MovieTrackingTrack *track = accessor->tracks[track_index];
- /* Early output, track does not use mask. */
- if ((track->algorithm_flag & TRACK_ALGORITHM_FLAG_USE_MASK) == 0) {
- return NULL;
- }
- MovieClip *clip = accessor->clips[clip_index];
- /* Construct fake user so we can access movie clip. */
- MovieClipUser user;
- int scene_frame = BKE_movieclip_remap_clip_to_scene_frame(clip, frame);
- BKE_movieclip_user_set_frame(&user, scene_frame);
- user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL;
- user.render_flag = 0;
- /* Get frame width and height so we can convert stroke coordinates
- * and other things from normalized to pixel space.
- */
- int frame_width, frame_height;
- BKE_movieclip_get_size(clip, &user, &frame_width, &frame_height);
- /* Actual mask sampling. */
- MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, frame);
- const float region_min[2] = {region->min[0] - marker->pos[0] * frame_width,
- region->min[1] - marker->pos[1] * frame_height};
- const float region_max[2] = {region->max[0] - marker->pos[0] * frame_width,
- region->max[1] - marker->pos[1] * frame_height};
- *r_destination = tracking_track_get_mask_for_region(frame_width, frame_height,
- region_min,
- region_max,
- track);
- *r_width = region->max[0] - region->min[0];
- *r_height = region->max[1] - region->min[1];
- return *r_destination;
+ ImBuf *ibuf = (ImBuf *)cache_key;
+ IMB_freeImBuf(ibuf);
+}
+
+static libmv_CacheKey accessor_get_mask_for_track_callback(libmv_FrameAccessorUserData *user_data,
+ int clip_index,
+ int frame,
+ int track_index,
+ const libmv_Region *region,
+ float **r_destination,
+ int *r_width,
+ int *r_height)
+{
+ /* Perform sanity checks first. */
+ TrackingImageAccessor *accessor = (TrackingImageAccessor *)user_data;
+ BLI_assert(clip_index < accessor->num_clips);
+ BLI_assert(track_index < accessor->num_tracks);
+ MovieTrackingTrack *track = accessor->tracks[track_index];
+ /* Early output, track does not use mask. */
+ if ((track->algorithm_flag & TRACK_ALGORITHM_FLAG_USE_MASK) == 0) {
+ return NULL;
+ }
+ MovieClip *clip = accessor->clips[clip_index];
+ /* Construct fake user so we can access movie clip. */
+ MovieClipUser user;
+ int scene_frame = BKE_movieclip_remap_clip_to_scene_frame(clip, frame);
+ BKE_movieclip_user_set_frame(&user, scene_frame);
+ user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL;
+ user.render_flag = 0;
+ /* Get frame width and height so we can convert stroke coordinates
+ * and other things from normalized to pixel space.
+ */
+ int frame_width, frame_height;
+ BKE_movieclip_get_size(clip, &user, &frame_width, &frame_height);
+ /* Actual mask sampling. */
+ MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, frame);
+ const float region_min[2] = {region->min[0] - marker->pos[0] * frame_width,
+ region->min[1] - marker->pos[1] * frame_height};
+ const float region_max[2] = {region->max[0] - marker->pos[0] * frame_width,
+ region->max[1] - marker->pos[1] * frame_height};
+ *r_destination = tracking_track_get_mask_for_region(
+ frame_width, frame_height, region_min, region_max, track);
+ *r_width = region->max[0] - region->min[0];
+ *r_height = region->max[1] - region->min[1];
+ return *r_destination;
}
static void accessor_release_mask_callback(libmv_CacheKey cache_key)
{
- if (cache_key != NULL) {
- float *mask = (float *)cache_key;
- MEM_freeN(mask);
- }
+ if (cache_key != NULL) {
+ float *mask = (float *)cache_key;
+ MEM_freeN(mask);
+ }
}
TrackingImageAccessor *tracking_image_accessor_new(MovieClip *clips[MAX_ACCESSOR_CLIP],
@@ -952,38 +952,35 @@ TrackingImageAccessor *tracking_image_accessor_new(MovieClip *clips[MAX_ACCESSOR
int num_tracks,
int start_frame)
{
- TrackingImageAccessor *accessor =
- MEM_callocN(sizeof(TrackingImageAccessor), "tracking image accessor");
+ TrackingImageAccessor *accessor = MEM_callocN(sizeof(TrackingImageAccessor),
+ "tracking image accessor");
- BLI_assert(num_clips <= MAX_ACCESSOR_CLIP);
+ BLI_assert(num_clips <= MAX_ACCESSOR_CLIP);
- accessor->cache = IMB_moviecache_create("frame access cache",
- sizeof(AccessCacheKey),
- accesscache_hashhash,
- accesscache_hashcmp);
+ accessor->cache = IMB_moviecache_create(
+ "frame access cache", sizeof(AccessCacheKey), accesscache_hashhash, accesscache_hashcmp);
- memcpy(accessor->clips, clips, num_clips * sizeof(MovieClip *));
- accessor->num_clips = num_clips;
- accessor->tracks = tracks;
- accessor->num_tracks = num_tracks;
- accessor->start_frame = start_frame;
+ memcpy(accessor->clips, clips, num_clips * sizeof(MovieClip *));
+ accessor->num_clips = num_clips;
+ accessor->tracks = tracks;
+ accessor->num_tracks = num_tracks;
+ accessor->start_frame = start_frame;
- accessor->libmv_accessor =
- libmv_FrameAccessorNew((libmv_FrameAccessorUserData *) accessor,
- accessor_get_image_callback,
- accessor_release_image_callback,
- accessor_get_mask_for_track_callback,
- accessor_release_mask_callback);
+ accessor->libmv_accessor = libmv_FrameAccessorNew((libmv_FrameAccessorUserData *)accessor,
+ accessor_get_image_callback,
+ accessor_release_image_callback,
+ accessor_get_mask_for_track_callback,
+ accessor_release_mask_callback);
- BLI_spin_init(&accessor->cache_lock);
+ BLI_spin_init(&accessor->cache_lock);
- return accessor;
+ return accessor;
}
void tracking_image_accessor_destroy(TrackingImageAccessor *accessor)
{
- IMB_moviecache_free(accessor->cache);
- libmv_FrameAccessorDestroy(accessor->libmv_accessor);
- BLI_spin_end(&accessor->cache_lock);
- MEM_freeN(accessor);
+ IMB_moviecache_free(accessor->cache);
+ libmv_FrameAccessorDestroy(accessor->libmv_accessor);
+ BLI_spin_end(&accessor->cache_lock);
+ MEM_freeN(accessor);
}
diff --git a/source/blender/blenkernel/intern/undo_system.c b/source/blender/blenkernel/intern/undo_system.c
index 448fe6cb167..d32bc7c6054 100644
--- a/source/blender/blenkernel/intern/undo_system.c
+++ b/source/blender/blenkernel/intern/undo_system.c
@@ -40,7 +40,7 @@
#include "MEM_guardedalloc.h"
-#define undo_stack _wm_undo_stack_disallow /* pass in as a variable always. */
+#define undo_stack _wm_undo_stack_disallow /* pass in as a variable always. */
/** Odd requirement of Blender that we always keep a memfile undo in the stack. */
#define WITH_GLOBAL_UNDO_KEEP_ONE
@@ -68,18 +68,22 @@ static CLG_LogRef LOG = {"bke.undosys"};
#ifdef WITH_NESTED_UNDO_CHECK
static bool g_undo_callback_running = false;
# define UNDO_NESTED_ASSERT(state) BLI_assert(g_undo_callback_running == state)
-# define UNDO_NESTED_CHECK_BEGIN { \
- UNDO_NESTED_ASSERT(false); \
- g_undo_callback_running = true; \
-} ((void)0)
-# define UNDO_NESTED_CHECK_END { \
- UNDO_NESTED_ASSERT(true); \
- g_undo_callback_running = false; \
-} ((void)0)
+# define UNDO_NESTED_CHECK_BEGIN \
+ { \
+ UNDO_NESTED_ASSERT(false); \
+ g_undo_callback_running = true; \
+ } \
+ ((void)0)
+# define UNDO_NESTED_CHECK_END \
+ { \
+ UNDO_NESTED_ASSERT(true); \
+ g_undo_callback_running = false; \
+ } \
+ ((void)0)
#else
# define UNDO_NESTED_ASSERT(state) ((void)0)
# define UNDO_NESTED_CHECK_BEGIN ((void)0)
-# define UNDO_NESTED_CHECK_END ((void)0)
+# define UNDO_NESTED_CHECK_END ((void)0)
#endif
/** \} */
@@ -102,13 +106,13 @@ static ListBase g_undo_types = {NULL, NULL};
static const UndoType *BKE_undosys_type_from_context(bContext *C)
{
- for (const UndoType *ut = g_undo_types.first; ut; ut = ut->next) {
- /* No poll means we don't check context. */
- if (ut->poll && ut->poll(C)) {
- return ut;
- }
- }
- return NULL;
+ for (const UndoType *ut = g_undo_types.first; ut; ut = ut->next) {
+ /* No poll means we don't check context. */
+ if (ut->poll && ut->poll(C)) {
+ return ut;
+ }
+ }
+ return NULL;
}
/* -------------------------------------------------------------------- */
@@ -121,103 +125,103 @@ static const UndoType *BKE_undosys_type_from_context(bContext *C)
static void undosys_id_ref_store(void *UNUSED(user_data), UndoRefID *id_ref)
{
- BLI_assert(id_ref->name[0] == '\0');
- if (id_ref->ptr) {
- BLI_strncpy(id_ref->name, id_ref->ptr->name, sizeof(id_ref->name));
- /* Not needed, just prevents stale data access. */
- id_ref->ptr = NULL;
- }
+ BLI_assert(id_ref->name[0] == '\0');
+ if (id_ref->ptr) {
+ BLI_strncpy(id_ref->name, id_ref->ptr->name, sizeof(id_ref->name));
+ /* Not needed, just prevents stale data access. */
+ id_ref->ptr = NULL;
+ }
}
static void undosys_id_ref_resolve(void *user_data, UndoRefID *id_ref)
{
- /* Note: we could optimize this, for now it's not too bad since it only runs when we access undo! */
- Main *bmain = user_data;
- ListBase *lb = which_libbase(bmain, GS(id_ref->name));
- for (ID *id = lb->first; id; id = id->next) {
- if (STREQ(id_ref->name, id->name) && (id->lib == NULL)) {
- id_ref->ptr = id;
- break;
- }
- }
+ /* Note: we could optimize this, for now it's not too bad since it only runs when we access undo! */
+ Main *bmain = user_data;
+ ListBase *lb = which_libbase(bmain, GS(id_ref->name));
+ for (ID *id = lb->first; id; id = id->next) {
+ if (STREQ(id_ref->name, id->name) && (id->lib == NULL)) {
+ id_ref->ptr = id;
+ break;
+ }
+ }
}
static bool undosys_step_encode(bContext *C, Main *bmain, UndoStack *ustack, UndoStep *us)
{
- CLOG_INFO(&LOG, 2, "addr=%p, name='%s', type='%s'", us, us->name, us->type->name);
- UNDO_NESTED_CHECK_BEGIN;
- bool ok = us->type->step_encode(C, bmain, us);
- UNDO_NESTED_CHECK_END;
- if (ok) {
- if (us->type->step_foreach_ID_ref != NULL) {
- /* Don't use from context yet because sometimes context is fake and not all members are filled in. */
- us->type->step_foreach_ID_ref(us, undosys_id_ref_store, bmain);
- }
+ CLOG_INFO(&LOG, 2, "addr=%p, name='%s', type='%s'", us, us->name, us->type->name);
+ UNDO_NESTED_CHECK_BEGIN;
+ bool ok = us->type->step_encode(C, bmain, us);
+ UNDO_NESTED_CHECK_END;
+ if (ok) {
+ if (us->type->step_foreach_ID_ref != NULL) {
+ /* Don't use from context yet because sometimes context is fake and not all members are filled in. */
+ us->type->step_foreach_ID_ref(us, undosys_id_ref_store, bmain);
+ }
#ifdef WITH_GLOBAL_UNDO_CORRECT_ORDER
- if (us->type == BKE_UNDOSYS_TYPE_MEMFILE) {
- ustack->step_active_memfile = us;
- }
+ if (us->type == BKE_UNDOSYS_TYPE_MEMFILE) {
+ ustack->step_active_memfile = us;
+ }
#endif
- }
- if (ok == false) {
- CLOG_INFO(&LOG, 2, "encode callback didn't create undo step");
- }
- return ok;
+ }
+ if (ok == false) {
+ CLOG_INFO(&LOG, 2, "encode callback didn't create undo step");
+ }
+ return ok;
}
static void undosys_step_decode(bContext *C, Main *bmain, UndoStack *ustack, UndoStep *us, int dir)
{
- CLOG_INFO(&LOG, 2, "addr=%p, name='%s', type='%s'", us, us->name, us->type->name);
+ CLOG_INFO(&LOG, 2, "addr=%p, name='%s', type='%s'", us, us->name, us->type->name);
- if (us->type->step_foreach_ID_ref) {
+ if (us->type->step_foreach_ID_ref) {
#ifdef WITH_GLOBAL_UNDO_CORRECT_ORDER
- if (us->type != BKE_UNDOSYS_TYPE_MEMFILE) {
- for (UndoStep *us_iter = us->prev; us_iter; us_iter = us_iter->prev) {
- if (us_iter->type == BKE_UNDOSYS_TYPE_MEMFILE) {
- if (us_iter == ustack->step_active_memfile) {
- /* Common case, we're already using the last memfile state. */
- }
- else {
- /* Load the previous memfile state so any ID's referenced in this
- * undo step will be correctly resolved, see: T56163. */
- undosys_step_decode(C, bmain, ustack, us_iter, dir);
- /* May have been freed on memfile read. */
- bmain = G.main;
- }
- break;
- }
- }
- }
+ if (us->type != BKE_UNDOSYS_TYPE_MEMFILE) {
+ for (UndoStep *us_iter = us->prev; us_iter; us_iter = us_iter->prev) {
+ if (us_iter->type == BKE_UNDOSYS_TYPE_MEMFILE) {
+ if (us_iter == ustack->step_active_memfile) {
+ /* Common case, we're already using the last memfile state. */
+ }
+ else {
+ /* Load the previous memfile state so any ID's referenced in this
+ * undo step will be correctly resolved, see: T56163. */
+ undosys_step_decode(C, bmain, ustack, us_iter, dir);
+ /* May have been freed on memfile read. */
+ bmain = G.main;
+ }
+ break;
+ }
+ }
+ }
#endif
- /* Don't use from context yet because sometimes context is fake and not all members are filled in. */
- us->type->step_foreach_ID_ref(us, undosys_id_ref_resolve, bmain);
- }
+ /* Don't use from context yet because sometimes context is fake and not all members are filled in. */
+ us->type->step_foreach_ID_ref(us, undosys_id_ref_resolve, bmain);
+ }
- UNDO_NESTED_CHECK_BEGIN;
- us->type->step_decode(C, bmain, us, dir);
- UNDO_NESTED_CHECK_END;
+ UNDO_NESTED_CHECK_BEGIN;
+ us->type->step_decode(C, bmain, us, dir);
+ UNDO_NESTED_CHECK_END;
#ifdef WITH_GLOBAL_UNDO_CORRECT_ORDER
- if (us->type == BKE_UNDOSYS_TYPE_MEMFILE) {
- ustack->step_active_memfile = us;
- }
+ if (us->type == BKE_UNDOSYS_TYPE_MEMFILE) {
+ ustack->step_active_memfile = us;
+ }
#endif
}
static void undosys_step_free_and_unlink(UndoStack *ustack, UndoStep *us)
{
- CLOG_INFO(&LOG, 2, "addr=%p, name='%s', type='%s'", us, us->name, us->type->name);
- UNDO_NESTED_CHECK_BEGIN;
- us->type->step_free(us);
- UNDO_NESTED_CHECK_END;
+ CLOG_INFO(&LOG, 2, "addr=%p, name='%s', type='%s'", us, us->name, us->type->name);
+ UNDO_NESTED_CHECK_BEGIN;
+ us->type->step_free(us);
+ UNDO_NESTED_CHECK_END;
- BLI_remlink(&ustack->steps, us);
- MEM_freeN(us);
+ BLI_remlink(&ustack->steps, us);
+ MEM_freeN(us);
#ifdef WITH_GLOBAL_UNDO_CORRECT_ORDER
- if (ustack->step_active_memfile == us) {
- ustack->step_active_memfile = NULL;
- }
+ if (ustack->step_active_memfile == us) {
+ ustack->step_active_memfile = NULL;
+ }
#endif
}
@@ -230,146 +234,146 @@ static void undosys_step_free_and_unlink(UndoStack *ustack, UndoStep *us)
#ifndef NDEBUG
static void undosys_stack_validate(UndoStack *ustack, bool expect_non_empty)
{
- if (ustack->step_active != NULL) {
- BLI_assert(!BLI_listbase_is_empty(&ustack->steps));
- BLI_assert(BLI_findindex(&ustack->steps, ustack->step_active) != -1);
- }
- if (expect_non_empty) {
- BLI_assert(!BLI_listbase_is_empty(&ustack->steps));
- }
+ if (ustack->step_active != NULL) {
+ BLI_assert(!BLI_listbase_is_empty(&ustack->steps));
+ BLI_assert(BLI_findindex(&ustack->steps, ustack->step_active) != -1);
+ }
+ if (expect_non_empty) {
+ BLI_assert(!BLI_listbase_is_empty(&ustack->steps));
+ }
}
#else
static void undosys_stack_validate(UndoStack *ustack, bool expect_non_empty)
{
- UNUSED_VARS(ustack, expect_non_empty);
+ UNUSED_VARS(ustack, expect_non_empty);
}
#endif
UndoStack *BKE_undosys_stack_create(void)
{
- UndoStack *ustack = MEM_callocN(sizeof(UndoStack), __func__);
- return ustack;
+ UndoStack *ustack = MEM_callocN(sizeof(UndoStack), __func__);
+ return ustack;
}
void BKE_undosys_stack_destroy(UndoStack *ustack)
{
- BKE_undosys_stack_clear(ustack);
- MEM_freeN(ustack);
+ BKE_undosys_stack_clear(ustack);
+ MEM_freeN(ustack);
}
void BKE_undosys_stack_clear(UndoStack *ustack)
{
- UNDO_NESTED_ASSERT(false);
- CLOG_INFO(&LOG, 1, "steps=%d", BLI_listbase_count(&ustack->steps));
- for (UndoStep *us = ustack->steps.last, *us_prev; us; us = us_prev) {
- us_prev = us->prev;
- undosys_step_free_and_unlink(ustack, us);
- }
- BLI_listbase_clear(&ustack->steps);
- ustack->step_active = NULL;
+ UNDO_NESTED_ASSERT(false);
+ CLOG_INFO(&LOG, 1, "steps=%d", BLI_listbase_count(&ustack->steps));
+ for (UndoStep *us = ustack->steps.last, *us_prev; us; us = us_prev) {
+ us_prev = us->prev;
+ undosys_step_free_and_unlink(ustack, us);
+ }
+ BLI_listbase_clear(&ustack->steps);
+ ustack->step_active = NULL;
}
void BKE_undosys_stack_clear_active(UndoStack *ustack)
{
- /* Remove active and all following undos. */
- UndoStep *us = ustack->step_active;
-
- if (us) {
- ustack->step_active = us->prev;
- bool is_not_empty = ustack->step_active != NULL;
-
- while (ustack->steps.last != ustack->step_active) {
- UndoStep *us_iter = ustack->steps.last;
- undosys_step_free_and_unlink(ustack, us_iter);
- undosys_stack_validate(ustack, is_not_empty);
- }
- }
+ /* Remove active and all following undos. */
+ UndoStep *us = ustack->step_active;
+
+ if (us) {
+ ustack->step_active = us->prev;
+ bool is_not_empty = ustack->step_active != NULL;
+
+ while (ustack->steps.last != ustack->step_active) {
+ UndoStep *us_iter = ustack->steps.last;
+ undosys_step_free_and_unlink(ustack, us_iter);
+ undosys_stack_validate(ustack, is_not_empty);
+ }
+ }
}
/* Caller is responsible for handling active. */
static void undosys_stack_clear_all_last(UndoStack *ustack, UndoStep *us)
{
- if (us) {
- bool is_not_empty = true;
- UndoStep *us_iter;
- do {
- us_iter = ustack->steps.last;
- BLI_assert(us_iter != ustack->step_active);
- undosys_step_free_and_unlink(ustack, us_iter);
- undosys_stack_validate(ustack, is_not_empty);
- } while ((us != us_iter));
- }
+ if (us) {
+ bool is_not_empty = true;
+ UndoStep *us_iter;
+ do {
+ us_iter = ustack->steps.last;
+ BLI_assert(us_iter != ustack->step_active);
+ undosys_step_free_and_unlink(ustack, us_iter);
+ undosys_stack_validate(ustack, is_not_empty);
+ } while ((us != us_iter));
+ }
}
static void undosys_stack_clear_all_first(UndoStack *ustack, UndoStep *us)
{
- if (us) {
- bool is_not_empty = true;
- UndoStep *us_iter;
- do {
- us_iter = ustack->steps.first;
- BLI_assert(us_iter != ustack->step_active);
- undosys_step_free_and_unlink(ustack, us_iter);
- undosys_stack_validate(ustack, is_not_empty);
- } while ((us != us_iter));
- }
+ if (us) {
+ bool is_not_empty = true;
+ UndoStep *us_iter;
+ do {
+ us_iter = ustack->steps.first;
+ BLI_assert(us_iter != ustack->step_active);
+ undosys_step_free_and_unlink(ustack, us_iter);
+ undosys_stack_validate(ustack, is_not_empty);
+ } while ((us != us_iter));
+ }
}
static bool undosys_stack_push_main(UndoStack *ustack, const char *name, struct Main *bmain)
{
- UNDO_NESTED_ASSERT(false);
- BLI_assert(ustack->step_init == NULL);
- CLOG_INFO(&LOG, 1, "'%s'", name);
- bContext *C_temp = CTX_create();
- CTX_data_main_set(C_temp, bmain);
- bool ok = BKE_undosys_step_push_with_type(ustack, C_temp, name, BKE_UNDOSYS_TYPE_MEMFILE);
- CTX_free(C_temp);
- return ok;
+ UNDO_NESTED_ASSERT(false);
+ BLI_assert(ustack->step_init == NULL);
+ CLOG_INFO(&LOG, 1, "'%s'", name);
+ bContext *C_temp = CTX_create();
+ CTX_data_main_set(C_temp, bmain);
+ bool ok = BKE_undosys_step_push_with_type(ustack, C_temp, name, BKE_UNDOSYS_TYPE_MEMFILE);
+ CTX_free(C_temp);
+ return ok;
}
void BKE_undosys_stack_init_from_main(UndoStack *ustack, struct Main *bmain)
{
- UNDO_NESTED_ASSERT(false);
- undosys_stack_push_main(ustack, "original", bmain);
+ UNDO_NESTED_ASSERT(false);
+ undosys_stack_push_main(ustack, "original", bmain);
}
/* called after 'BKE_undosys_stack_init_from_main' */
void BKE_undosys_stack_init_from_context(UndoStack *ustack, bContext *C)
{
- const UndoType *ut = BKE_undosys_type_from_context(C);
- if ((ut != NULL) && (ut != BKE_UNDOSYS_TYPE_MEMFILE)) {
- BKE_undosys_step_push_with_type(ustack, C, "original mode", ut);
- }
+ const UndoType *ut = BKE_undosys_type_from_context(C);
+ if ((ut != NULL) && (ut != BKE_UNDOSYS_TYPE_MEMFILE)) {
+ BKE_undosys_step_push_with_type(ustack, C, "original mode", ut);
+ }
}
/* name optional */
bool BKE_undosys_stack_has_undo(UndoStack *ustack, const char *name)
{
- if (name) {
- UndoStep *us = BLI_rfindstring(&ustack->steps, name, offsetof(UndoStep, name));
- return us && us->prev;
- }
+ if (name) {
+ UndoStep *us = BLI_rfindstring(&ustack->steps, name, offsetof(UndoStep, name));
+ return us && us->prev;
+ }
- return !BLI_listbase_is_empty(&ustack->steps);
+ return !BLI_listbase_is_empty(&ustack->steps);
}
UndoStep *BKE_undosys_stack_active_with_type(UndoStack *ustack, const UndoType *ut)
{
- UndoStep *us = ustack->step_active;
- while (us && (us->type != ut)) {
- us = us->prev;
- }
- return us;
+ UndoStep *us = ustack->step_active;
+ while (us && (us->type != ut)) {
+ us = us->prev;
+ }
+ return us;
}
UndoStep *BKE_undosys_stack_init_or_active_with_type(UndoStack *ustack, const UndoType *ut)
{
- UNDO_NESTED_ASSERT(false);
- CLOG_INFO(&LOG, 1, "type='%s'", ut->name);
- if (ustack->step_init && (ustack->step_init->type == ut)) {
- return ustack->step_init;
- }
- return BKE_undosys_stack_active_with_type(ustack, ut);
+ UNDO_NESTED_ASSERT(false);
+ CLOG_INFO(&LOG, 1, "type='%s'", ut->name);
+ if (ustack->step_init && (ustack->step_init->type == ut)) {
+ return ustack->step_init;
+ }
+ return BKE_undosys_stack_active_with_type(ustack, ut);
}
/**
@@ -378,218 +382,223 @@ UndoStep *BKE_undosys_stack_init_or_active_with_type(UndoStack *ustack, const Un
*/
void BKE_undosys_stack_limit_steps_and_memory(UndoStack *ustack, int steps, size_t memory_limit)
{
- UNDO_NESTED_ASSERT(false);
- if (!(steps || memory_limit)) {
- return;
- }
+ UNDO_NESTED_ASSERT(false);
+ if (!(steps || memory_limit)) {
+ return;
+ }
- CLOG_INFO(&LOG, 1, "steps=%d, memory_limit=%zu", steps, memory_limit);
- UndoStep *us;
+ CLOG_INFO(&LOG, 1, "steps=%d, memory_limit=%zu", steps, memory_limit);
+ UndoStep *us;
#ifdef WITH_GLOBAL_UNDO_KEEP_ONE
- UndoStep *us_exclude = NULL;
+ UndoStep *us_exclude = NULL;
#endif
- /* keep at least two (original + other) */
- size_t data_size_all = 0;
- size_t us_count = 0;
- for (us = ustack->steps.last; us && us->prev; us = us->prev) {
- if (memory_limit) {
- data_size_all += us->data_size;
- if (data_size_all > memory_limit) {
- break;
- }
- }
- if (steps) {
- if (us_count == steps) {
- break;
- }
- if (us->skip == false) {
- us_count += 1;
- }
- }
- }
-
- if (us) {
- if (us->prev && us->prev->prev) {
- us = us->prev;
- }
+ /* keep at least two (original + other) */
+ size_t data_size_all = 0;
+ size_t us_count = 0;
+ for (us = ustack->steps.last; us && us->prev; us = us->prev) {
+ if (memory_limit) {
+ data_size_all += us->data_size;
+ if (data_size_all > memory_limit) {
+ break;
+ }
+ }
+ if (steps) {
+ if (us_count == steps) {
+ break;
+ }
+ if (us->skip == false) {
+ us_count += 1;
+ }
+ }
+ }
+
+ if (us) {
+ if (us->prev && us->prev->prev) {
+ us = us->prev;
+ }
#ifdef WITH_GLOBAL_UNDO_KEEP_ONE
- /* Hack, we need to keep at least one BKE_UNDOSYS_TYPE_MEMFILE. */
- if (us->type != BKE_UNDOSYS_TYPE_MEMFILE) {
- us_exclude = us->prev;
- while (us_exclude && us->type != BKE_UNDOSYS_TYPE_MEMFILE) {
- us_exclude = us_exclude->prev;
- }
- if (us_exclude) {
- BLI_remlink(&ustack->steps, us_exclude);
- }
- }
+ /* Hack, we need to keep at least one BKE_UNDOSYS_TYPE_MEMFILE. */
+ if (us->type != BKE_UNDOSYS_TYPE_MEMFILE) {
+ us_exclude = us->prev;
+ while (us_exclude && us->type != BKE_UNDOSYS_TYPE_MEMFILE) {
+ us_exclude = us_exclude->prev;
+ }
+ if (us_exclude) {
+ BLI_remlink(&ustack->steps, us_exclude);
+ }
+ }
#endif
- /* Free from first to last, free functions may update de-duplication info (see #MemFileUndoStep). */
- undosys_stack_clear_all_first(ustack, us->prev);
+ /* Free from first to last, free functions may update de-duplication info (see #MemFileUndoStep). */
+ undosys_stack_clear_all_first(ustack, us->prev);
#ifdef WITH_GLOBAL_UNDO_KEEP_ONE
- if (us_exclude) {
- BLI_addhead(&ustack->steps, us_exclude);
- }
+ if (us_exclude) {
+ BLI_addhead(&ustack->steps, us_exclude);
+ }
#endif
- }
+ }
}
/** \} */
-UndoStep *BKE_undosys_step_push_init_with_type(UndoStack *ustack, bContext *C, const char *name, const UndoType *ut)
-{
- UNDO_NESTED_ASSERT(false);
- /* We could detect and clean this up (but it should never happen!). */
- BLI_assert(ustack->step_init == NULL);
- if (ut->step_encode_init) {
- undosys_stack_validate(ustack, false);
-
- if (ustack->step_active) {
- undosys_stack_clear_all_last(ustack, ustack->step_active->next);
- }
-
- UndoStep *us = MEM_callocN(ut->step_size, __func__);
- CLOG_INFO(&LOG, 1, "addr=%p, name='%s', type='%s'", us, name, ut->name);
- if (name != NULL) {
- BLI_strncpy(us->name, name, sizeof(us->name));
- }
- us->type = ut;
- ustack->step_init = us;
- ut->step_encode_init(C, us);
- undosys_stack_validate(ustack, false);
- return us;
- }
- else {
- return NULL;
- }
+UndoStep *BKE_undosys_step_push_init_with_type(UndoStack *ustack,
+ bContext *C,
+ const char *name,
+ const UndoType *ut)
+{
+ UNDO_NESTED_ASSERT(false);
+ /* We could detect and clean this up (but it should never happen!). */
+ BLI_assert(ustack->step_init == NULL);
+ if (ut->step_encode_init) {
+ undosys_stack_validate(ustack, false);
+
+ if (ustack->step_active) {
+ undosys_stack_clear_all_last(ustack, ustack->step_active->next);
+ }
+
+ UndoStep *us = MEM_callocN(ut->step_size, __func__);
+ CLOG_INFO(&LOG, 1, "addr=%p, name='%s', type='%s'", us, name, ut->name);
+ if (name != NULL) {
+ BLI_strncpy(us->name, name, sizeof(us->name));
+ }
+ us->type = ut;
+ ustack->step_init = us;
+ ut->step_encode_init(C, us);
+ undosys_stack_validate(ustack, false);
+ return us;
+ }
+ else {
+ return NULL;
+ }
}
UndoStep *BKE_undosys_step_push_init(UndoStack *ustack, bContext *C, const char *name)
{
- UNDO_NESTED_ASSERT(false);
- /* We could detect and clean this up (but it should never happen!). */
- BLI_assert(ustack->step_init == NULL);
- const UndoType *ut = BKE_undosys_type_from_context(C);
- if (ut == NULL) {
- return NULL;
- }
- return BKE_undosys_step_push_init_with_type(ustack, C, name, ut);
+ UNDO_NESTED_ASSERT(false);
+ /* We could detect and clean this up (but it should never happen!). */
+ BLI_assert(ustack->step_init == NULL);
+ const UndoType *ut = BKE_undosys_type_from_context(C);
+ if (ut == NULL) {
+ return NULL;
+ }
+ return BKE_undosys_step_push_init_with_type(ustack, C, name, ut);
}
/**
* \param C: Can be NULL from some callers if their encoding function doesn't need it
*/
-bool BKE_undosys_step_push_with_type(UndoStack *ustack, bContext *C, const char *name, const UndoType *ut)
+bool BKE_undosys_step_push_with_type(UndoStack *ustack,
+ bContext *C,
+ const char *name,
+ const UndoType *ut)
{
- UNDO_NESTED_ASSERT(false);
- undosys_stack_validate(ustack, false);
- bool is_not_empty = ustack->step_active != NULL;
-
- /* Might not be final place for this to be called - probably only want to call it from some
- * undo handlers, not all of them? */
- if (BKE_override_static_is_enabled()) {
- BKE_main_override_static_operations_create(G.main, false);
- }
-
- /* Remove all undos after (also when 'ustack->step_active == NULL'). */
- while (ustack->steps.last != ustack->step_active) {
- UndoStep *us_iter = ustack->steps.last;
- undosys_step_free_and_unlink(ustack, us_iter);
- undosys_stack_validate(ustack, is_not_empty);
- }
-
- if (ustack->step_active) {
- BLI_assert(BLI_findindex(&ustack->steps, ustack->step_active) != -1);
- }
+ UNDO_NESTED_ASSERT(false);
+ undosys_stack_validate(ustack, false);
+ bool is_not_empty = ustack->step_active != NULL;
+
+ /* Might not be final place for this to be called - probably only want to call it from some
+ * undo handlers, not all of them? */
+ if (BKE_override_static_is_enabled()) {
+ BKE_main_override_static_operations_create(G.main, false);
+ }
+
+ /* Remove all undos after (also when 'ustack->step_active == NULL'). */
+ while (ustack->steps.last != ustack->step_active) {
+ UndoStep *us_iter = ustack->steps.last;
+ undosys_step_free_and_unlink(ustack, us_iter);
+ undosys_stack_validate(ustack, is_not_empty);
+ }
+
+ if (ustack->step_active) {
+ BLI_assert(BLI_findindex(&ustack->steps, ustack->step_active) != -1);
+ }
#ifdef WITH_GLOBAL_UNDO_ENSURE_UPDATED
- if (ut->step_foreach_ID_ref != NULL) {
- if (G_MAIN->is_memfile_undo_written == false) {
- const char *name_internal = "MemFile Internal (pre)";
- /* Don't let 'step_init' cause issues when adding memfile undo step. */
- void *step_init = ustack->step_init;
- ustack->step_init = NULL;
- const bool ok = undosys_stack_push_main(ustack, name_internal, G_MAIN);
- /* Restore 'step_init'. */
- ustack->step_init = step_init;
- if (ok) {
- UndoStep *us = ustack->steps.last;
- BLI_assert(STREQ(us->name, name_internal));
- us->skip = true;
-#ifdef WITH_GLOBAL_UNDO_CORRECT_ORDER
- ustack->step_active_memfile = us;
-#endif
- }
- }
- }
+ if (ut->step_foreach_ID_ref != NULL) {
+ if (G_MAIN->is_memfile_undo_written == false) {
+ const char *name_internal = "MemFile Internal (pre)";
+ /* Don't let 'step_init' cause issues when adding memfile undo step. */
+ void *step_init = ustack->step_init;
+ ustack->step_init = NULL;
+ const bool ok = undosys_stack_push_main(ustack, name_internal, G_MAIN);
+ /* Restore 'step_init'. */
+ ustack->step_init = step_init;
+ if (ok) {
+ UndoStep *us = ustack->steps.last;
+ BLI_assert(STREQ(us->name, name_internal));
+ us->skip = true;
+# ifdef WITH_GLOBAL_UNDO_CORRECT_ORDER
+ ustack->step_active_memfile = us;
+# endif
+ }
+ }
+ }
#endif
- bool use_memfile_step = false;
- {
- UndoStep *us = ustack->step_init ? ustack->step_init : MEM_callocN(ut->step_size, __func__);
- ustack->step_init = NULL;
- if (us->name[0] == '\0') {
- BLI_strncpy(us->name, name, sizeof(us->name));
- }
- us->type = ut;
- /* initialized, not added yet. */
-
- if (!undosys_step_encode(C, G_MAIN, ustack, us)) {
- MEM_freeN(us);
- undosys_stack_validate(ustack, true);
- return false;
- }
- ustack->step_active = us;
- BLI_addtail(&ustack->steps, us);
- use_memfile_step = us->use_memfile_step;
- }
-
- if (use_memfile_step) {
- const char *name_internal = "MemFile Internal (post)";
- const bool ok = undosys_stack_push_main(ustack, name_internal, G_MAIN);
- if (ok) {
- UndoStep *us = ustack->steps.last;
- BLI_assert(STREQ(us->name, name_internal));
- us->skip = true;
+ bool use_memfile_step = false;
+ {
+ UndoStep *us = ustack->step_init ? ustack->step_init : MEM_callocN(ut->step_size, __func__);
+ ustack->step_init = NULL;
+ if (us->name[0] == '\0') {
+ BLI_strncpy(us->name, name, sizeof(us->name));
+ }
+ us->type = ut;
+ /* initialized, not added yet. */
+
+ if (!undosys_step_encode(C, G_MAIN, ustack, us)) {
+ MEM_freeN(us);
+ undosys_stack_validate(ustack, true);
+ return false;
+ }
+ ustack->step_active = us;
+ BLI_addtail(&ustack->steps, us);
+ use_memfile_step = us->use_memfile_step;
+ }
+
+ if (use_memfile_step) {
+ const char *name_internal = "MemFile Internal (post)";
+ const bool ok = undosys_stack_push_main(ustack, name_internal, G_MAIN);
+ if (ok) {
+ UndoStep *us = ustack->steps.last;
+ BLI_assert(STREQ(us->name, name_internal));
+ us->skip = true;
#ifdef WITH_GLOBAL_UNDO_CORRECT_ORDER
- ustack->step_active_memfile = us;
+ ustack->step_active_memfile = us;
#endif
- ustack->step_active = us;
- }
- }
+ ustack->step_active = us;
+ }
+ }
- undosys_stack_validate(ustack, true);
- return true;
+ undosys_stack_validate(ustack, true);
+ return true;
}
bool BKE_undosys_step_push(UndoStack *ustack, bContext *C, const char *name)
{
- UNDO_NESTED_ASSERT(false);
- const UndoType *ut = ustack->step_init ? ustack->step_init->type : BKE_undosys_type_from_context(C);
- if (ut == NULL) {
- return false;
- }
- return BKE_undosys_step_push_with_type(ustack, C, name, ut);
+ UNDO_NESTED_ASSERT(false);
+ const UndoType *ut = ustack->step_init ? ustack->step_init->type :
+ BKE_undosys_type_from_context(C);
+ if (ut == NULL) {
+ return false;
+ }
+ return BKE_undosys_step_push_with_type(ustack, C, name, ut);
}
-
/**
* Useful when we want to diff against previous undo data but can't be sure the types match.
*/
UndoStep *BKE_undosys_step_same_type_next(UndoStep *us)
{
- if (us) {
- const UndoType *ut = us->type;
- while ((us = us->next)) {
- if (us->type == ut) {
- return us;
- }
- }
-
- }
- return us;
+ if (us) {
+ const UndoType *ut = us->type;
+ while ((us = us->next)) {
+ if (us->type == ut) {
+ return us;
+ }
+ }
+ }
+ return us;
}
/**
@@ -597,175 +606,180 @@ UndoStep *BKE_undosys_step_same_type_next(UndoStep *us)
*/
UndoStep *BKE_undosys_step_same_type_prev(UndoStep *us)
{
- if (us) {
- const UndoType *ut = us->type;
- while ((us = us->prev)) {
- if (us->type == ut) {
- return us;
- }
- }
-
- }
- return us;
+ if (us) {
+ const UndoType *ut = us->type;
+ while ((us = us->prev)) {
+ if (us->type == ut) {
+ return us;
+ }
+ }
+ }
+ return us;
}
-UndoStep *BKE_undosys_step_find_by_name_with_type(UndoStack *ustack, const char *name, const UndoType *ut)
+UndoStep *BKE_undosys_step_find_by_name_with_type(UndoStack *ustack,
+ const char *name,
+ const UndoType *ut)
{
- for (UndoStep *us = ustack->steps.last; us; us = us->prev) {
- if (us->type == ut) {
- if (STREQ(name, us->name)) {
- return us;
- }
- }
- }
- return NULL;
+ for (UndoStep *us = ustack->steps.last; us; us = us->prev) {
+ if (us->type == ut) {
+ if (STREQ(name, us->name)) {
+ return us;
+ }
+ }
+ }
+ return NULL;
}
UndoStep *BKE_undosys_step_find_by_name(UndoStack *ustack, const char *name)
{
- return BLI_rfindstring(&ustack->steps, name, offsetof(UndoStep, name));
+ return BLI_rfindstring(&ustack->steps, name, offsetof(UndoStep, name));
}
UndoStep *BKE_undosys_step_find_by_type(UndoStack *ustack, const UndoType *ut)
{
- for (UndoStep *us = ustack->steps.last; us; us = us->prev) {
- if (us->type == ut) {
- return us;
- }
- }
- return NULL;
-}
-
-bool BKE_undosys_step_undo_with_data_ex(
- UndoStack *ustack, bContext *C, UndoStep *us,
- bool use_skip)
-{
- UNDO_NESTED_ASSERT(false);
- if (us) {
- undosys_stack_validate(ustack, true);
- }
- UndoStep *us_prev = us ? us->prev : NULL;
- if (us) {
- /* The current state is a copy, we need to load the previous state. */
- us = us_prev;
- }
-
- if (us != NULL) {
- CLOG_INFO(&LOG, 1, "addr=%p, name='%s', type='%s'", us, us->name, us->type->name);
-
- /* Handle accumulate steps. */
- if (ustack->step_active) {
- UndoStep *us_iter = ustack->step_active;
- while (us_iter != us) {
- /* TODO:
- * - skip successive steps that store the same data, eg: memfile steps.
- * - or steps that include another steps data, eg: a memfile step includes text undo data.
- */
- undosys_step_decode(C, G_MAIN, ustack, us_iter, -1);
- us_iter = us_iter->prev;
- }
- }
-
- undosys_step_decode(C, G_MAIN, ustack, us, -1);
-
- ustack->step_active = us_prev;
- undosys_stack_validate(ustack, true);
- if (use_skip) {
- if (ustack->step_active && ustack->step_active->skip) {
- CLOG_INFO(&LOG, 2, "undo continue with skip %p '%s', type='%s'", us, us->name, us->type->name);
- BKE_undosys_step_undo_with_data(ustack, C, ustack->step_active);
- }
- }
- return true;
- }
- return false;
+ for (UndoStep *us = ustack->steps.last; us; us = us->prev) {
+ if (us->type == ut) {
+ return us;
+ }
+ }
+ return NULL;
+}
+
+bool BKE_undosys_step_undo_with_data_ex(UndoStack *ustack,
+ bContext *C,
+ UndoStep *us,
+ bool use_skip)
+{
+ UNDO_NESTED_ASSERT(false);
+ if (us) {
+ undosys_stack_validate(ustack, true);
+ }
+ UndoStep *us_prev = us ? us->prev : NULL;
+ if (us) {
+ /* The current state is a copy, we need to load the previous state. */
+ us = us_prev;
+ }
+
+ if (us != NULL) {
+ CLOG_INFO(&LOG, 1, "addr=%p, name='%s', type='%s'", us, us->name, us->type->name);
+
+ /* Handle accumulate steps. */
+ if (ustack->step_active) {
+ UndoStep *us_iter = ustack->step_active;
+ while (us_iter != us) {
+ /* TODO:
+ * - skip successive steps that store the same data, eg: memfile steps.
+ * - or steps that include another steps data, eg: a memfile step includes text undo data.
+ */
+ undosys_step_decode(C, G_MAIN, ustack, us_iter, -1);
+ us_iter = us_iter->prev;
+ }
+ }
+
+ undosys_step_decode(C, G_MAIN, ustack, us, -1);
+
+ ustack->step_active = us_prev;
+ undosys_stack_validate(ustack, true);
+ if (use_skip) {
+ if (ustack->step_active && ustack->step_active->skip) {
+ CLOG_INFO(
+ &LOG, 2, "undo continue with skip %p '%s', type='%s'", us, us->name, us->type->name);
+ BKE_undosys_step_undo_with_data(ustack, C, ustack->step_active);
+ }
+ }
+ return true;
+ }
+ return false;
}
bool BKE_undosys_step_undo_with_data(UndoStack *ustack, bContext *C, UndoStep *us)
{
- return BKE_undosys_step_undo_with_data_ex(ustack, C, us, true);
+ return BKE_undosys_step_undo_with_data_ex(ustack, C, us, true);
}
bool BKE_undosys_step_undo(UndoStack *ustack, bContext *C)
{
- return BKE_undosys_step_undo_with_data(ustack, C, ustack->step_active);
+ return BKE_undosys_step_undo_with_data(ustack, C, ustack->step_active);
}
void BKE_undosys_step_undo_from_index(UndoStack *ustack, bContext *C, int index)
{
- UndoStep *us = BLI_findlink(&ustack->steps, index);
- BLI_assert(us->skip == false);
- BKE_undosys_step_load_data(ustack, C, us);
-}
-
-bool BKE_undosys_step_redo_with_data_ex(
- UndoStack *ustack, bContext *C, UndoStep *us,
- bool use_skip)
-{
- UNDO_NESTED_ASSERT(false);
- UndoStep *us_next = us ? us->next : NULL;
- /* Unlike undo accumulate, we always use the next. */
- us = us_next;
-
- if (us != NULL) {
- CLOG_INFO(&LOG, 1, "addr=%p, name='%s', type='%s'", us, us->name, us->type->name);
-
- /* Handle accumulate steps. */
- if (ustack->step_active && ustack->step_active->next) {
- UndoStep *us_iter = ustack->step_active->next;
- while (us_iter != us) {
- undosys_step_decode(C, G_MAIN, ustack, us_iter, 1);
- us_iter = us_iter->next;
- }
- }
-
- undosys_step_decode(C, G_MAIN, ustack, us, 1);
- ustack->step_active = us_next;
- if (use_skip) {
- if (ustack->step_active && ustack->step_active->skip) {
- CLOG_INFO(&LOG, 2, "redo continue with skip %p '%s', type='%s'", us, us->name, us->type->name);
- BKE_undosys_step_redo_with_data(ustack, C, ustack->step_active);
- }
- }
- return true;
- }
- return false;
+ UndoStep *us = BLI_findlink(&ustack->steps, index);
+ BLI_assert(us->skip == false);
+ BKE_undosys_step_load_data(ustack, C, us);
+}
+
+bool BKE_undosys_step_redo_with_data_ex(UndoStack *ustack,
+ bContext *C,
+ UndoStep *us,
+ bool use_skip)
+{
+ UNDO_NESTED_ASSERT(false);
+ UndoStep *us_next = us ? us->next : NULL;
+ /* Unlike undo accumulate, we always use the next. */
+ us = us_next;
+
+ if (us != NULL) {
+ CLOG_INFO(&LOG, 1, "addr=%p, name='%s', type='%s'", us, us->name, us->type->name);
+
+ /* Handle accumulate steps. */
+ if (ustack->step_active && ustack->step_active->next) {
+ UndoStep *us_iter = ustack->step_active->next;
+ while (us_iter != us) {
+ undosys_step_decode(C, G_MAIN, ustack, us_iter, 1);
+ us_iter = us_iter->next;
+ }
+ }
+
+ undosys_step_decode(C, G_MAIN, ustack, us, 1);
+ ustack->step_active = us_next;
+ if (use_skip) {
+ if (ustack->step_active && ustack->step_active->skip) {
+ CLOG_INFO(
+ &LOG, 2, "redo continue with skip %p '%s', type='%s'", us, us->name, us->type->name);
+ BKE_undosys_step_redo_with_data(ustack, C, ustack->step_active);
+ }
+ }
+ return true;
+ }
+ return false;
}
bool BKE_undosys_step_redo_with_data(UndoStack *ustack, bContext *C, UndoStep *us)
{
- return BKE_undosys_step_redo_with_data_ex(ustack, C, us, true);
+ return BKE_undosys_step_redo_with_data_ex(ustack, C, us, true);
}
bool BKE_undosys_step_redo(UndoStack *ustack, bContext *C)
{
- return BKE_undosys_step_redo_with_data(ustack, C, ustack->step_active);
+ return BKE_undosys_step_redo_with_data(ustack, C, ustack->step_active);
}
bool BKE_undosys_step_load_data(UndoStack *ustack, bContext *C, UndoStep *us)
{
- UNDO_NESTED_ASSERT(false);
- const int index_active = BLI_findindex(&ustack->steps, ustack->step_active);
- const int index_target = BLI_findindex(&ustack->steps, us);
- BLI_assert(!ELEM(-1, index_active, index_target));
- bool ok = true;
-
- if (index_target < index_active) {
- uint i = index_active - index_target;
- while (i-- && ok) {
- ok = BKE_undosys_step_undo_with_data_ex(ustack, C, ustack->step_active, false);
- }
- }
- else if (index_target > index_active) {
- uint i = index_target - index_active;
- while (i-- && ok) {
- ok = BKE_undosys_step_redo_with_data_ex(ustack, C, ustack->step_active, false);
- }
- }
-
- if (ok) {
- BLI_assert(ustack->step_active == us);
- }
-
- return ok;
+ UNDO_NESTED_ASSERT(false);
+ const int index_active = BLI_findindex(&ustack->steps, ustack->step_active);
+ const int index_target = BLI_findindex(&ustack->steps, us);
+ BLI_assert(!ELEM(-1, index_active, index_target));
+ bool ok = true;
+
+ if (index_target < index_active) {
+ uint i = index_active - index_target;
+ while (i-- && ok) {
+ ok = BKE_undosys_step_undo_with_data_ex(ustack, C, ustack->step_active, false);
+ }
+ }
+ else if (index_target > index_active) {
+ uint i = index_target - index_active;
+ while (i-- && ok) {
+ ok = BKE_undosys_step_redo_with_data_ex(ustack, C, ustack->step_active, false);
+ }
+ }
+
+ if (ok) {
+ BLI_assert(ustack->step_active == us);
+ }
+
+ return ok;
}
/**
@@ -773,23 +787,23 @@ bool BKE_undosys_step_load_data(UndoStack *ustack, bContext *C, UndoStep *us)
*/
UndoType *BKE_undosys_type_append(void (*undosys_fn)(UndoType *))
{
- UndoType *ut;
+ UndoType *ut;
- ut = MEM_callocN(sizeof(UndoType), __func__);
+ ut = MEM_callocN(sizeof(UndoType), __func__);
- undosys_fn(ut);
+ undosys_fn(ut);
- BLI_addtail(&g_undo_types, ut);
+ BLI_addtail(&g_undo_types, ut);
- return ut;
+ return ut;
}
void BKE_undosys_type_free_all(void)
{
- UndoType *ut;
- while ((ut = BLI_pophead(&g_undo_types))) {
- MEM_freeN(ut);
- }
+ UndoType *ut;
+ while ((ut = BLI_pophead(&g_undo_types))) {
+ MEM_freeN(ut);
+ }
}
/** \} */
@@ -804,35 +818,36 @@ void BKE_undosys_type_free_all(void)
* The pointer can only be a key, we can't read it's contents. */
#define USE_LIB_SKIP
-static void UNUSED_FUNCTION(BKE_undosys_foreach_ID_ref(
- UndoStack *ustack, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data))
+static void UNUSED_FUNCTION(BKE_undosys_foreach_ID_ref(UndoStack *ustack,
+ UndoTypeForEachIDRefFn foreach_ID_ref_fn,
+ void *user_data))
{
- for (UndoStep *us = ustack->steps.first; us; us = us->next) {
- const UndoType *ut = us->type;
- if (ut->step_foreach_ID_ref != NULL) {
- ut->step_foreach_ID_ref(us, foreach_ID_ref_fn, user_data);
- }
- }
+ for (UndoStep *us = ustack->steps.first; us; us = us->next) {
+ const UndoType *ut = us->type;
+ if (ut->step_foreach_ID_ref != NULL) {
+ ut->step_foreach_ID_ref(us, foreach_ID_ref_fn, user_data);
+ }
+ }
}
typedef struct UndoIDPtrMapItem {
- /** Never changes (matches undo data). Use as sort key for binary search. */
- const void *ptr;
- /** Write the new pointers here. */
- uint index;
+ /** Never changes (matches undo data). Use as sort key for binary search. */
+ const void *ptr;
+ /** Write the new pointers here. */
+ uint index;
} UndoIDPtrMapItem;
typedef struct UndoIDPtrMap {
- UndoRefID *refs;
- /**
- * Pointer map, update 'dst' members before use.
- * This is always sorted (adds some overhead when adding, in practice it's acceptable since).
- */
- UndoIDPtrMapItem *pmap;
-
- /** Length for both 'refs' & 'pmap' */
- uint len;
- uint len_alloc;
+ UndoRefID *refs;
+ /**
+ * Pointer map, update 'dst' members before use.
+ * This is always sorted (adds some overhead when adding, in practice it's acceptable since).
+ */
+ UndoIDPtrMapItem *pmap;
+
+ /** Length for both 'refs' & 'pmap' */
+ uint len;
+ uint len_alloc;
} UndoIDPtrMap;
#ifdef DEBUG
@@ -841,13 +856,13 @@ typedef struct UndoIDPtrMap {
# define PMAP_DEFAULT_ALLOC 32
#endif
-void BKE_undosys_ID_map_foreach_ID_ref(
- UndoIDPtrMap *map,
- UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
+void BKE_undosys_ID_map_foreach_ID_ref(UndoIDPtrMap *map,
+ UndoTypeForEachIDRefFn foreach_ID_ref_fn,
+ void *user_data)
{
- for (uint i = 0; i < map->len; i++) {
- foreach_ID_ref_fn(user_data, &map->refs[i]);
- }
+ for (uint i = 0; i < map->len; i++) {
+ foreach_ID_ref_fn(user_data, &map->refs[i]);
+ }
}
/**
@@ -855,34 +870,34 @@ void BKE_undosys_ID_map_foreach_ID_ref(
*/
static bool undosys_ID_map_lookup_index(const UndoIDPtrMap *map, const void *key, uint *r_index)
{
- const UndoIDPtrMapItem *pmap = map->pmap;
- const uint len = map->len;
- if (len == 0) {
- if (r_index) {
- *r_index = 0;
- }
- return false;
- }
- int min = 0, max = len - 1;
- while (min <= max) {
- const uint mid = (min + max) / 2;
- if (pmap[mid].ptr < key) {
- min = mid + 1;
- }
- else if (pmap[mid].ptr == key) {
- if (r_index) {
- *r_index = mid;
- }
- return true;
- }
- else if (pmap[mid].ptr > key) {
- max = mid - 1;
- }
- }
- if (r_index) {
- *r_index = min;
- }
- return false;
+ const UndoIDPtrMapItem *pmap = map->pmap;
+ const uint len = map->len;
+ if (len == 0) {
+ if (r_index) {
+ *r_index = 0;
+ }
+ return false;
+ }
+ int min = 0, max = len - 1;
+ while (min <= max) {
+ const uint mid = (min + max) / 2;
+ if (pmap[mid].ptr < key) {
+ min = mid + 1;
+ }
+ else if (pmap[mid].ptr == key) {
+ if (r_index) {
+ *r_index = mid;
+ }
+ return true;
+ }
+ else if (pmap[mid].ptr > key) {
+ max = mid - 1;
+ }
+ }
+ if (r_index) {
+ *r_index = min;
+ }
+ return false;
}
/**
@@ -893,121 +908,120 @@ static bool undosys_ID_map_lookup_index(const UndoIDPtrMap *map, const void *key
*/
UndoIDPtrMap *BKE_undosys_ID_map_create(void)
{
- UndoIDPtrMap *map = MEM_mallocN(sizeof(*map), __func__);
- map->len_alloc = PMAP_DEFAULT_ALLOC;
- map->refs = MEM_mallocN(sizeof(*map->refs) * map->len_alloc, __func__);
- map->pmap = MEM_mallocN(sizeof(*map->pmap) * map->len_alloc, __func__);
- map->len = 0;
- return map;
+ UndoIDPtrMap *map = MEM_mallocN(sizeof(*map), __func__);
+ map->len_alloc = PMAP_DEFAULT_ALLOC;
+ map->refs = MEM_mallocN(sizeof(*map->refs) * map->len_alloc, __func__);
+ map->pmap = MEM_mallocN(sizeof(*map->pmap) * map->len_alloc, __func__);
+ map->len = 0;
+ return map;
}
void BKE_undosys_ID_map_destroy(UndoIDPtrMap *idpmap)
{
- MEM_SAFE_FREE(idpmap->refs);
- MEM_SAFE_FREE(idpmap->pmap);
- MEM_freeN(idpmap);
+ MEM_SAFE_FREE(idpmap->refs);
+ MEM_SAFE_FREE(idpmap->pmap);
+ MEM_freeN(idpmap);
}
void BKE_undosys_ID_map_add(UndoIDPtrMap *map, ID *id)
{
- uint index;
+ uint index;
#ifdef USE_LIB_SKIP
- if (id->lib != NULL) {
- return;
- }
+ if (id->lib != NULL) {
+ return;
+ }
#endif
- if (undosys_ID_map_lookup_index(map, id, &index)) {
- return; /* exists. */
- }
-
- const uint len_src = map->len;
- const uint len_dst = map->len + 1;
- if (len_dst > map->len_alloc) {
- map->len_alloc *= 2;
- BLI_assert(map->len_alloc >= len_dst);
- map->pmap = MEM_reallocN(map->pmap, sizeof(*map->pmap) * map->len_alloc);
- map->refs = MEM_reallocN(map->refs, sizeof(*map->refs) * map->len_alloc);
- }
-
-#if 0 /* Will be done automatically in callback. */
- BLI_strncpy(map->refs[len_src].name, id->name, sizeof(id->name));
+ if (undosys_ID_map_lookup_index(map, id, &index)) {
+ return; /* exists. */
+ }
+
+ const uint len_src = map->len;
+ const uint len_dst = map->len + 1;
+ if (len_dst > map->len_alloc) {
+ map->len_alloc *= 2;
+ BLI_assert(map->len_alloc >= len_dst);
+ map->pmap = MEM_reallocN(map->pmap, sizeof(*map->pmap) * map->len_alloc);
+ map->refs = MEM_reallocN(map->refs, sizeof(*map->refs) * map->len_alloc);
+ }
+
+#if 0 /* Will be done automatically in callback. */
+ BLI_strncpy(map->refs[len_src].name, id->name, sizeof(id->name));
#else
- map->refs[len_src].name[0] = '\0';
+ map->refs[len_src].name[0] = '\0';
#endif
- map->refs[len_src].ptr = id;
+ map->refs[len_src].ptr = id;
- if (len_src != 0 && index != len_src) {
- memmove(&map->pmap[index + 1], &map->pmap[index], sizeof(*map->pmap) * (len_src - index));
- }
- map->pmap[index].ptr = id;
- map->pmap[index].index = len_src;
+ if (len_src != 0 && index != len_src) {
+ memmove(&map->pmap[index + 1], &map->pmap[index], sizeof(*map->pmap) * (len_src - index));
+ }
+ map->pmap[index].ptr = id;
+ map->pmap[index].index = len_src;
- map->len = len_dst;
+ map->len = len_dst;
}
ID *BKE_undosys_ID_map_lookup(const UndoIDPtrMap *map, const ID *id_src)
{
- /* We should only ever lookup indices which exist! */
- uint index;
- if (!undosys_ID_map_lookup_index(map, id_src, &index)) {
- BLI_assert(0);
- }
- index = map->pmap[index].index;
- ID *id_dst = map->refs[index].ptr;
- BLI_assert(id_dst != NULL);
- BLI_assert(STREQ(id_dst->name, map->refs[index].name));
- return id_dst;
+ /* We should only ever lookup indices which exist! */
+ uint index;
+ if (!undosys_ID_map_lookup_index(map, id_src, &index)) {
+ BLI_assert(0);
+ }
+ index = map->pmap[index].index;
+ ID *id_dst = map->refs[index].ptr;
+ BLI_assert(id_dst != NULL);
+ BLI_assert(STREQ(id_dst->name, map->refs[index].name));
+ return id_dst;
}
void BKE_undosys_ID_map_add_with_prev(UndoIDPtrMap *map, ID *id, ID **id_prev)
{
- if (id == *id_prev) {
- return;
- }
- *id_prev = id;
- BKE_undosys_ID_map_add(map, id);
+ if (id == *id_prev) {
+ return;
+ }
+ *id_prev = id;
+ BKE_undosys_ID_map_add(map, id);
}
ID *BKE_undosys_ID_map_lookup_with_prev(const UndoIDPtrMap *map, ID *id_src, ID *id_prev_match[2])
{
- if (id_src == id_prev_match[0]) {
- return id_prev_match[1];
- }
- else {
+ if (id_src == id_prev_match[0]) {
+ return id_prev_match[1];
+ }
+ else {
#ifdef USE_LIB_SKIP
- ID *id_dst = BKE_undosys_ID_map_lookup(map, id_src);
+ ID *id_dst = BKE_undosys_ID_map_lookup(map, id_src);
#else
- ID *id_dst = (id_src->lib == NULL) ? BKE_undosys_ID_map_lookup(map, id_src) : id_src;
+ ID *id_dst = (id_src->lib == NULL) ? BKE_undosys_ID_map_lookup(map, id_src) : id_src;
#endif
- id_prev_match[0] = id_src;
- id_prev_match[1] = id_dst;
- return id_dst;
- }
+ id_prev_match[0] = id_src;
+ id_prev_match[1] = id_dst;
+ return id_dst;
+ }
}
/** \} */
-
/* -------------------------------------------------------------------- */
/** \name Debug Helpers
* \{ */
void BKE_undosys_print(UndoStack *ustack)
{
- printf("Undo %d Steps (*: active, #=applied, M=memfile-active, S=skip)\n",
- BLI_listbase_count(&ustack->steps));
- int index = 0;
- for (UndoStep *us = ustack->steps.first; us; us = us->next) {
- printf("[%c%c%c%c] %3d type='%s', name='%s'\n",
- (us == ustack->step_active) ? '*' : ' ',
- us->is_applied ? '#' : ' ',
- (us == ustack->step_active_memfile) ? 'M' : ' ',
- us->skip ? 'S' : ' ',
- index,
- us->type->name,
- us->name);
- index++;
- }
+ printf("Undo %d Steps (*: active, #=applied, M=memfile-active, S=skip)\n",
+ BLI_listbase_count(&ustack->steps));
+ int index = 0;
+ for (UndoStep *us = ustack->steps.first; us; us = us->next) {
+ printf("[%c%c%c%c] %3d type='%s', name='%s'\n",
+ (us == ustack->step_active) ? '*' : ' ',
+ us->is_applied ? '#' : ' ',
+ (us == ustack->step_active_memfile) ? 'M' : ' ',
+ us->skip ? 'S' : ' ',
+ index,
+ us->type->name,
+ us->name);
+ index++;
+ }
}
/** \} */
diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c
index 196083fc7fa..ac8e35cd781 100644
--- a/source/blender/blenkernel/intern/unit.c
+++ b/source/blender/blenkernel/intern/unit.c
@@ -31,7 +31,7 @@
#include "DNA_scene_types.h"
-#include "BKE_unit.h" /* own include */
+#include "BKE_unit.h" /* own include */
#ifdef WIN32
# include "BLI_winstuff.h"
@@ -44,85 +44,85 @@
#define TEMP_STR_SIZE 256
-#define SEP_CHR '#'
-#define SEP_STR "#"
+#define SEP_CHR '#'
+#define SEP_STR "#"
#define EPS 0.001
-#define UN_SC_KM 1000.0f
-#define UN_SC_HM 100.0f
-#define UN_SC_DAM 10.0f
-#define UN_SC_M 1.0f
-#define UN_SC_DM 0.1f
-#define UN_SC_CM 0.01f
-#define UN_SC_MM 0.001f
-#define UN_SC_UM 0.000001f
-
-#define UN_SC_MI 1609.344f
-#define UN_SC_FUR 201.168f
-#define UN_SC_CH 20.1168f
-#define UN_SC_YD 0.9144f
-#define UN_SC_FT 0.3048f
-#define UN_SC_IN 0.0254f
-#define UN_SC_MIL 0.0000254f
-
-#define UN_SC_MTON 1000.0f /* metric ton */
-#define UN_SC_QL 100.0f
-#define UN_SC_KG 1.0f
-#define UN_SC_HG 0.1f
-#define UN_SC_DAG 0.01f
-#define UN_SC_G 0.001f
-#define UN_SC_MG 0.000001f
-
-#define UN_SC_ITON 907.18474f /* imperial ton */
-#define UN_SC_CWT 45.359237f
-#define UN_SC_ST 6.35029318f
-#define UN_SC_LB 0.45359237f
-#define UN_SC_OZ 0.028349523125f
+#define UN_SC_KM 1000.0f
+#define UN_SC_HM 100.0f
+#define UN_SC_DAM 10.0f
+#define UN_SC_M 1.0f
+#define UN_SC_DM 0.1f
+#define UN_SC_CM 0.01f
+#define UN_SC_MM 0.001f
+#define UN_SC_UM 0.000001f
+
+#define UN_SC_MI 1609.344f
+#define UN_SC_FUR 201.168f
+#define UN_SC_CH 20.1168f
+#define UN_SC_YD 0.9144f
+#define UN_SC_FT 0.3048f
+#define UN_SC_IN 0.0254f
+#define UN_SC_MIL 0.0000254f
+
+#define UN_SC_MTON 1000.0f /* metric ton */
+#define UN_SC_QL 100.0f
+#define UN_SC_KG 1.0f
+#define UN_SC_HG 0.1f
+#define UN_SC_DAG 0.01f
+#define UN_SC_G 0.001f
+#define UN_SC_MG 0.000001f
+
+#define UN_SC_ITON 907.18474f /* imperial ton */
+#define UN_SC_CWT 45.359237f
+#define UN_SC_ST 6.35029318f
+#define UN_SC_LB 0.45359237f
+#define UN_SC_OZ 0.028349523125f
/* clang-format on */
/* define a single unit */
typedef struct bUnitDef {
- const char *name;
- /** abused a bit for the display name */
- const char *name_plural;
- /** this is used for display*/
- const char *name_short;
- /** keyboard-friendly ASCII-only version of name_short, can be NULL */
- const char *name_alt;
- /* if name_short has non-ASCII chars, name_alt should be present */
-
- /** can be NULL */
- const char *name_display;
- /** when NULL, a transformed version of the name will be taken */
- const char *identifier;
-
- double scalar;
- /** not used yet, needed for converting temperature */
- double bias;
- int flag;
+ const char *name;
+ /** abused a bit for the display name */
+ const char *name_plural;
+ /** this is used for display*/
+ const char *name_short;
+ /** keyboard-friendly ASCII-only version of name_short, can be NULL */
+ const char *name_alt;
+ /* if name_short has non-ASCII chars, name_alt should be present */
+
+ /** can be NULL */
+ const char *name_display;
+ /** when NULL, a transformed version of the name will be taken */
+ const char *identifier;
+
+ double scalar;
+ /** not used yet, needed for converting temperature */
+ double bias;
+ int flag;
} bUnitDef;
enum {
- B_UNIT_DEF_NONE = 0,
- /** Use for units that are not used enough to be translated into for common use */
- B_UNIT_DEF_SUPPRESS = 1,
- /** Display a unit even if its value is 0.1, eg 0.1mm instead of 100um */
- B_UNIT_DEF_TENTH = 2,
- /** Short unit name is case sensitive, for example to distinguish mW and MW */
- B_UNIT_DEF_CASE_SENSITIVE = 4,
+ B_UNIT_DEF_NONE = 0,
+ /** Use for units that are not used enough to be translated into for common use */
+ B_UNIT_DEF_SUPPRESS = 1,
+ /** Display a unit even if its value is 0.1, eg 0.1mm instead of 100um */
+ B_UNIT_DEF_TENTH = 2,
+ /** Short unit name is case sensitive, for example to distinguish mW and MW */
+ B_UNIT_DEF_CASE_SENSITIVE = 4,
};
/* define a single unit */
typedef struct bUnitCollection {
- const struct bUnitDef *units;
- /** basic unit index (when user doesn't specify unit explicitly) */
- int base_unit;
- /** options for this system */
- int flag;
- /** to quickly find the last item */
- int length;
+ const struct bUnitDef *units;
+ /** basic unit index (when user doesn't specify unit explicitly) */
+ int base_unit;
+ /** options for this system */
+ int flag;
+ /** to quickly find the last item */
+ int length;
} bUnitCollection;
/* Keep table lignment. */
@@ -137,109 +137,109 @@ static struct bUnitCollection buDummyCollection = {buDummyDef, 0, 0, sizeof(buDu
/* Lengths */
static struct bUnitDef buMetricLenDef[] = {
- {"kilometer", "kilometers", "km", NULL, "Kilometers", "KILOMETERS", UN_SC_KM, 0.0, B_UNIT_DEF_NONE},
- {"hectometer", "hectometers", "hm", NULL, "100 Meters", "HECTOMETERS", UN_SC_HM, 0.0, B_UNIT_DEF_SUPPRESS},
- {"dekameter", "dekameters", "dam", NULL, "10 Meters", "DEKAMETERS", UN_SC_DAM, 0.0, B_UNIT_DEF_SUPPRESS},
- {"meter", "meters", "m", NULL, "Meters", "METERS", UN_SC_M, 0.0, B_UNIT_DEF_NONE}, /* base unit */
- {"decimeter", "decimeters", "dm", NULL, "10 Centimeters", "DECIMETERS", UN_SC_DM, 0.0, B_UNIT_DEF_SUPPRESS},
- {"centimeter", "centimeters", "cm", NULL, "Centimeters", "CENTIMETERS", UN_SC_CM, 0.0, B_UNIT_DEF_NONE},
- {"millimeter", "millimeters", "mm", NULL, "Millimeters", "MILLIMETERS", UN_SC_MM, 0.0, B_UNIT_DEF_NONE | B_UNIT_DEF_TENTH},
- {"micrometer", "micrometers", "µm", "um", "Micrometers", "MICROMETERS", UN_SC_UM, 0.0, B_UNIT_DEF_NONE},
-
- /* These get displayed because of float precision problems in the transform header,
- * could work around, but for now probably people wont use these */
+ {"kilometer", "kilometers", "km", NULL, "Kilometers", "KILOMETERS", UN_SC_KM, 0.0, B_UNIT_DEF_NONE},
+ {"hectometer", "hectometers", "hm", NULL, "100 Meters", "HECTOMETERS", UN_SC_HM, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"dekameter", "dekameters", "dam", NULL, "10 Meters", "DEKAMETERS", UN_SC_DAM, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"meter", "meters", "m", NULL, "Meters", "METERS", UN_SC_M, 0.0, B_UNIT_DEF_NONE}, /* base unit */
+ {"decimeter", "decimeters", "dm", NULL, "10 Centimeters", "DECIMETERS", UN_SC_DM, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"centimeter", "centimeters", "cm", NULL, "Centimeters", "CENTIMETERS", UN_SC_CM, 0.0, B_UNIT_DEF_NONE},
+ {"millimeter", "millimeters", "mm", NULL, "Millimeters", "MILLIMETERS", UN_SC_MM, 0.0, B_UNIT_DEF_NONE | B_UNIT_DEF_TENTH},
+ {"micrometer", "micrometers", "µm", "um", "Micrometers", "MICROMETERS", UN_SC_UM, 0.0, B_UNIT_DEF_NONE},
+
+ /* These get displayed because of float precision problems in the transform header,
+ * could work around, but for now probably people wont use these */
#if 0
- {"nanometer", "Nanometers", "nm", NULL, 0.000000001, 0.0, B_UNIT_DEF_NONE},
- {"picometer", "Picometers", "pm", NULL, 0.000000000001, 0.0, B_UNIT_DEF_NONE},
+ {"nanometer", "Nanometers", "nm", NULL, 0.000000001, 0.0, B_UNIT_DEF_NONE},
+ {"picometer", "Picometers", "pm", NULL, 0.000000000001, 0.0, B_UNIT_DEF_NONE},
#endif
- NULL_UNIT,
+ NULL_UNIT,
};
static const struct bUnitCollection buMetricLenCollection = {buMetricLenDef, 3, 0, UNIT_COLLECTION_LENGTH(buMetricLenDef)};
static struct bUnitDef buImperialLenDef[] = {
- {"mile", "miles", "mi", "m", "Miles", "MILES", UN_SC_MI, 0.0, B_UNIT_DEF_NONE},
- {"furlong", "furlongs", "fur", NULL, "Furlongs", "FURLONGS", UN_SC_FUR, 0.0, B_UNIT_DEF_SUPPRESS},
- {"chain", "chains", "ch", NULL, "Chains", "CHAINS", UN_SC_CH, 0.0, B_UNIT_DEF_SUPPRESS},
- {"yard", "yards", "yd", NULL, "Yards", "YARDS", UN_SC_YD, 0.0, B_UNIT_DEF_SUPPRESS},
- {"foot", "feet", "'", "ft", "Feet", "FEET", UN_SC_FT, 0.0, B_UNIT_DEF_NONE}, /* base unit */
- {"inch", "inches", "\"", "in", "Inches", "INCHES", UN_SC_IN, 0.0, B_UNIT_DEF_NONE},
- {"thou", "thou", "thou", "mil", "Thou", "THOU", UN_SC_MIL, 0.0, B_UNIT_DEF_NONE}, /* plural for thou has no 's' */
- NULL_UNIT,
+ {"mile", "miles", "mi", "m", "Miles", "MILES", UN_SC_MI, 0.0, B_UNIT_DEF_NONE},
+ {"furlong", "furlongs", "fur", NULL, "Furlongs", "FURLONGS", UN_SC_FUR, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"chain", "chains", "ch", NULL, "Chains", "CHAINS", UN_SC_CH, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"yard", "yards", "yd", NULL, "Yards", "YARDS", UN_SC_YD, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"foot", "feet", "'", "ft", "Feet", "FEET", UN_SC_FT, 0.0, B_UNIT_DEF_NONE}, /* base unit */
+ {"inch", "inches", "\"", "in", "Inches", "INCHES", UN_SC_IN, 0.0, B_UNIT_DEF_NONE},
+ {"thou", "thou", "thou", "mil", "Thou", "THOU", UN_SC_MIL, 0.0, B_UNIT_DEF_NONE}, /* plural for thou has no 's' */
+ NULL_UNIT,
};
static struct bUnitCollection buImperialLenCollection = {buImperialLenDef, 4, 0, UNIT_COLLECTION_LENGTH(buImperialLenDef)};
/* Areas */
static struct bUnitDef buMetricAreaDef[] = {
- {"square kilometer", "square kilometers", "km²", "km2", "Square Kilometers", NULL, UN_SC_KM * UN_SC_KM, 0.0, B_UNIT_DEF_NONE},
- {"square hectometer", "square hectometers", "hm²", "hm2", "Square Hectometers", NULL, UN_SC_HM * UN_SC_HM, 0.0, B_UNIT_DEF_SUPPRESS}, /* hectare */
- {"square dekameter", "square dekameters", "dam²", "dam2", "Square Dekameters", NULL, UN_SC_DAM * UN_SC_DAM, 0.0, B_UNIT_DEF_SUPPRESS}, /* are */
- {"square meter", "square meters", "m²", "m2", "Square Meters", NULL, UN_SC_M * UN_SC_M, 0.0, B_UNIT_DEF_NONE}, /* base unit */
- {"square decimeter", "square decimetees", "dm²", "dm2", "Square Decimeters", NULL, UN_SC_DM * UN_SC_DM, 0.0, B_UNIT_DEF_SUPPRESS},
- {"square centimeter", "square centimeters", "cm²", "cm2", "Square Centimeters", NULL, UN_SC_CM * UN_SC_CM, 0.0, B_UNIT_DEF_NONE},
- {"square millimeter", "square millimeters", "mm²", "mm2", "Square Millimeters", NULL, UN_SC_MM * UN_SC_MM, 0.0, B_UNIT_DEF_NONE | B_UNIT_DEF_TENTH},
- {"square micrometer", "square micrometers", "µm²", "um2", "Square Micrometers", NULL, UN_SC_UM * UN_SC_UM, 0.0, B_UNIT_DEF_NONE},
- NULL_UNIT,
+ {"square kilometer", "square kilometers", "km²", "km2", "Square Kilometers", NULL, UN_SC_KM * UN_SC_KM, 0.0, B_UNIT_DEF_NONE},
+ {"square hectometer", "square hectometers", "hm²", "hm2", "Square Hectometers", NULL, UN_SC_HM * UN_SC_HM, 0.0, B_UNIT_DEF_SUPPRESS}, /* hectare */
+ {"square dekameter", "square dekameters", "dam²", "dam2", "Square Dekameters", NULL, UN_SC_DAM * UN_SC_DAM, 0.0, B_UNIT_DEF_SUPPRESS}, /* are */
+ {"square meter", "square meters", "m²", "m2", "Square Meters", NULL, UN_SC_M * UN_SC_M, 0.0, B_UNIT_DEF_NONE}, /* base unit */
+ {"square decimeter", "square decimetees", "dm²", "dm2", "Square Decimeters", NULL, UN_SC_DM * UN_SC_DM, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"square centimeter", "square centimeters", "cm²", "cm2", "Square Centimeters", NULL, UN_SC_CM * UN_SC_CM, 0.0, B_UNIT_DEF_NONE},
+ {"square millimeter", "square millimeters", "mm²", "mm2", "Square Millimeters", NULL, UN_SC_MM * UN_SC_MM, 0.0, B_UNIT_DEF_NONE | B_UNIT_DEF_TENTH},
+ {"square micrometer", "square micrometers", "µm²", "um2", "Square Micrometers", NULL, UN_SC_UM * UN_SC_UM, 0.0, B_UNIT_DEF_NONE},
+ NULL_UNIT,
};
static struct bUnitCollection buMetricAreaCollection = {buMetricAreaDef, 3, 0, UNIT_COLLECTION_LENGTH(buMetricAreaDef)};
static struct bUnitDef buImperialAreaDef[] = {
- {"square mile", "square miles", "sq mi", "sq m", "Square Miles", NULL, UN_SC_MI * UN_SC_MI, 0.0, B_UNIT_DEF_NONE},
- {"square furlong", "square furlongs", "sq fur", NULL, "Square Furlongs", NULL, UN_SC_FUR * UN_SC_FUR, 0.0, B_UNIT_DEF_SUPPRESS},
- {"square chain", "square chains", "sq ch", NULL, "Square Chains", NULL, UN_SC_CH * UN_SC_CH, 0.0, B_UNIT_DEF_SUPPRESS},
- {"square yard", "square yards", "sq yd", NULL, "Square Yards", NULL, UN_SC_YD * UN_SC_YD, 0.0, B_UNIT_DEF_NONE},
- {"square foot", "square feet", "sq ft", NULL, "Square Feet", NULL, UN_SC_FT * UN_SC_FT, 0.0, B_UNIT_DEF_NONE}, /* base unit */
- {"square inch", "square inches", "sq in", NULL, "Square Inches", NULL, UN_SC_IN * UN_SC_IN, 0.0, B_UNIT_DEF_NONE},
- {"square thou", "square thou", "sq mil", NULL, "Square Thou", NULL, UN_SC_MIL * UN_SC_MIL, 0.0, B_UNIT_DEF_NONE},
- NULL_UNIT,
+ {"square mile", "square miles", "sq mi", "sq m", "Square Miles", NULL, UN_SC_MI * UN_SC_MI, 0.0, B_UNIT_DEF_NONE},
+ {"square furlong", "square furlongs", "sq fur", NULL, "Square Furlongs", NULL, UN_SC_FUR * UN_SC_FUR, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"square chain", "square chains", "sq ch", NULL, "Square Chains", NULL, UN_SC_CH * UN_SC_CH, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"square yard", "square yards", "sq yd", NULL, "Square Yards", NULL, UN_SC_YD * UN_SC_YD, 0.0, B_UNIT_DEF_NONE},
+ {"square foot", "square feet", "sq ft", NULL, "Square Feet", NULL, UN_SC_FT * UN_SC_FT, 0.0, B_UNIT_DEF_NONE}, /* base unit */
+ {"square inch", "square inches", "sq in", NULL, "Square Inches", NULL, UN_SC_IN * UN_SC_IN, 0.0, B_UNIT_DEF_NONE},
+ {"square thou", "square thou", "sq mil", NULL, "Square Thou", NULL, UN_SC_MIL * UN_SC_MIL, 0.0, B_UNIT_DEF_NONE},
+ NULL_UNIT,
};
static struct bUnitCollection buImperialAreaCollection = {buImperialAreaDef, 4, 0, UNIT_COLLECTION_LENGTH(buImperialAreaDef)};
/* Volumes */
static struct bUnitDef buMetricVolDef[] = {
- {"cubic kilometer", "cubic kilometers", "km³", "km3", "Cubic Kilometers", NULL, UN_SC_KM * UN_SC_KM * UN_SC_KM, 0.0, B_UNIT_DEF_NONE},
- {"cubic hectometer", "cubic hectometers", "hm³", "hm3", "Cubic Hectometers", NULL, UN_SC_HM * UN_SC_HM * UN_SC_HM, 0.0, B_UNIT_DEF_SUPPRESS},
- {"cubic dekameter", "cubic dekameters", "dam³", "dam3", "Cubic Dekameters", NULL, UN_SC_DAM * UN_SC_DAM * UN_SC_DAM, 0.0, B_UNIT_DEF_SUPPRESS},
- {"cubic meter", "cubic meters", "m³", "m3", "Cubic Meters", NULL, UN_SC_M * UN_SC_M * UN_SC_M, 0.0, B_UNIT_DEF_NONE}, /* base unit */
- {"cubic decimeter", "cubic decimeters", "dm³", "dm3", "Cubic Decimeters", NULL, UN_SC_DM * UN_SC_DM * UN_SC_DM, 0.0, B_UNIT_DEF_SUPPRESS},
- {"cubic centimeter", "cubic centimeters", "cm³", "cm3", "Cubic Centimeters", NULL, UN_SC_CM * UN_SC_CM * UN_SC_CM, 0.0, B_UNIT_DEF_NONE},
- {"cubic millimeter", "cubic millimeters", "mm³", "mm3", "Cubic Millimeters", NULL, UN_SC_MM * UN_SC_MM * UN_SC_MM, 0.0, B_UNIT_DEF_NONE | B_UNIT_DEF_TENTH},
- {"cubic micrometer", "cubic micrometers", "µm³", "um3", "Cubic Micrometers", NULL, UN_SC_UM * UN_SC_UM * UN_SC_UM, 0.0, B_UNIT_DEF_NONE},
- NULL_UNIT,
+ {"cubic kilometer", "cubic kilometers", "km³", "km3", "Cubic Kilometers", NULL, UN_SC_KM * UN_SC_KM * UN_SC_KM, 0.0, B_UNIT_DEF_NONE},
+ {"cubic hectometer", "cubic hectometers", "hm³", "hm3", "Cubic Hectometers", NULL, UN_SC_HM * UN_SC_HM * UN_SC_HM, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"cubic dekameter", "cubic dekameters", "dam³", "dam3", "Cubic Dekameters", NULL, UN_SC_DAM * UN_SC_DAM * UN_SC_DAM, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"cubic meter", "cubic meters", "m³", "m3", "Cubic Meters", NULL, UN_SC_M * UN_SC_M * UN_SC_M, 0.0, B_UNIT_DEF_NONE}, /* base unit */
+ {"cubic decimeter", "cubic decimeters", "dm³", "dm3", "Cubic Decimeters", NULL, UN_SC_DM * UN_SC_DM * UN_SC_DM, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"cubic centimeter", "cubic centimeters", "cm³", "cm3", "Cubic Centimeters", NULL, UN_SC_CM * UN_SC_CM * UN_SC_CM, 0.0, B_UNIT_DEF_NONE},
+ {"cubic millimeter", "cubic millimeters", "mm³", "mm3", "Cubic Millimeters", NULL, UN_SC_MM * UN_SC_MM * UN_SC_MM, 0.0, B_UNIT_DEF_NONE | B_UNIT_DEF_TENTH},
+ {"cubic micrometer", "cubic micrometers", "µm³", "um3", "Cubic Micrometers", NULL, UN_SC_UM * UN_SC_UM * UN_SC_UM, 0.0, B_UNIT_DEF_NONE},
+ NULL_UNIT,
};
static struct bUnitCollection buMetricVolCollection = {buMetricVolDef, 3, 0, UNIT_COLLECTION_LENGTH(buMetricVolDef)};
static struct bUnitDef buImperialVolDef[] = {
- {"cubic mile", "cubic miles", "cu mi", "cu m", "Cubic Miles", NULL, UN_SC_MI * UN_SC_MI * UN_SC_MI, 0.0, B_UNIT_DEF_NONE},
- {"cubic furlong", "cubic furlongs", "cu fur", NULL, "Cubic Furlongs", NULL, UN_SC_FUR * UN_SC_FUR * UN_SC_FUR, 0.0, B_UNIT_DEF_SUPPRESS},
- {"cubic chain", "cubic chains", "cu ch", NULL, "Cubic Chains", NULL, UN_SC_CH * UN_SC_CH * UN_SC_CH, 0.0, B_UNIT_DEF_SUPPRESS},
- {"cubic yard", "cubic yards", "cu yd", NULL, "Cubic Yards", NULL, UN_SC_YD * UN_SC_YD * UN_SC_YD, 0.0, B_UNIT_DEF_NONE},
- {"cubic foot", "cubic feet", "cu ft", NULL, "Cubic Feet", NULL, UN_SC_FT * UN_SC_FT * UN_SC_FT, 0.0, B_UNIT_DEF_NONE}, /* base unit */
- {"cubic inch", "cubic inches", "cu in", NULL, "Cubic Inches", NULL, UN_SC_IN * UN_SC_IN * UN_SC_IN, 0.0, B_UNIT_DEF_NONE},
- {"cubic thou", "cubic thou", "cu mil", NULL, "Cubic Thou", NULL, UN_SC_MIL * UN_SC_MIL * UN_SC_MIL, 0.0, B_UNIT_DEF_NONE},
- NULL_UNIT,
+ {"cubic mile", "cubic miles", "cu mi", "cu m", "Cubic Miles", NULL, UN_SC_MI * UN_SC_MI * UN_SC_MI, 0.0, B_UNIT_DEF_NONE},
+ {"cubic furlong", "cubic furlongs", "cu fur", NULL, "Cubic Furlongs", NULL, UN_SC_FUR * UN_SC_FUR * UN_SC_FUR, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"cubic chain", "cubic chains", "cu ch", NULL, "Cubic Chains", NULL, UN_SC_CH * UN_SC_CH * UN_SC_CH, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"cubic yard", "cubic yards", "cu yd", NULL, "Cubic Yards", NULL, UN_SC_YD * UN_SC_YD * UN_SC_YD, 0.0, B_UNIT_DEF_NONE},
+ {"cubic foot", "cubic feet", "cu ft", NULL, "Cubic Feet", NULL, UN_SC_FT * UN_SC_FT * UN_SC_FT, 0.0, B_UNIT_DEF_NONE}, /* base unit */
+ {"cubic inch", "cubic inches", "cu in", NULL, "Cubic Inches", NULL, UN_SC_IN * UN_SC_IN * UN_SC_IN, 0.0, B_UNIT_DEF_NONE},
+ {"cubic thou", "cubic thou", "cu mil", NULL, "Cubic Thou", NULL, UN_SC_MIL * UN_SC_MIL * UN_SC_MIL, 0.0, B_UNIT_DEF_NONE},
+ NULL_UNIT,
};
static struct bUnitCollection buImperialVolCollection = {buImperialVolDef, 4, 0, UNIT_COLLECTION_LENGTH(buImperialVolDef)};
/* Mass */
static struct bUnitDef buMetricMassDef[] = {
- {"ton", "tonnes", "ton", "t", "Tonnes", "TONNES", UN_SC_MTON, 0.0, B_UNIT_DEF_NONE},
- {"quintal", "quintals", "ql", "q", "100 Kilograms", "QUINTALS", UN_SC_QL, 0.0, B_UNIT_DEF_SUPPRESS},
- {"kilogram", "kilograms", "kg", NULL, "Kilograms", "KILOGRAMS", UN_SC_KG, 0.0, B_UNIT_DEF_NONE}, /* base unit */
- {"hectogram", "hectograms", "hg", NULL, "Hectograms", "HECTOGRAMS", UN_SC_HG, 0.0, B_UNIT_DEF_SUPPRESS},
- {"dekagram", "dekagrams", "dag", NULL, "10 Grams", "DEKAGRAMS", UN_SC_DAG, 0.0, B_UNIT_DEF_SUPPRESS},
- {"gram", "grams", "g", NULL, "Grams", "GRAMS", UN_SC_G, 0.0, B_UNIT_DEF_NONE},
- {"milligram", "milligrams", "mg", NULL, "Milligrams", "MILLIGRAMS", UN_SC_MG, 0.0, B_UNIT_DEF_NONE},
- NULL_UNIT,
+ {"ton", "tonnes", "ton", "t", "Tonnes", "TONNES", UN_SC_MTON, 0.0, B_UNIT_DEF_NONE},
+ {"quintal", "quintals", "ql", "q", "100 Kilograms", "QUINTALS", UN_SC_QL, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"kilogram", "kilograms", "kg", NULL, "Kilograms", "KILOGRAMS", UN_SC_KG, 0.0, B_UNIT_DEF_NONE}, /* base unit */
+ {"hectogram", "hectograms", "hg", NULL, "Hectograms", "HECTOGRAMS", UN_SC_HG, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"dekagram", "dekagrams", "dag", NULL, "10 Grams", "DEKAGRAMS", UN_SC_DAG, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"gram", "grams", "g", NULL, "Grams", "GRAMS", UN_SC_G, 0.0, B_UNIT_DEF_NONE},
+ {"milligram", "milligrams", "mg", NULL, "Milligrams", "MILLIGRAMS", UN_SC_MG, 0.0, B_UNIT_DEF_NONE},
+ NULL_UNIT,
};
static struct bUnitCollection buMetricMassCollection = {buMetricMassDef, 2, 0, UNIT_COLLECTION_LENGTH(buMetricMassDef)};
static struct bUnitDef buImperialMassDef[] = {
- {"ton", "tonnes", "ton", "t", "Tonnes", "TONNES", UN_SC_ITON, 0.0, B_UNIT_DEF_NONE},
- {"centum weight", "centum weights", "cwt", NULL, "Centum weights", "CENTUM_WEIGHTS", UN_SC_CWT, 0.0, B_UNIT_DEF_NONE},
- {"stone", "stones", "st", NULL, "Stones", "STONES", UN_SC_ST, 0.0, B_UNIT_DEF_NONE},
- {"pound", "pounds", "lb", NULL, "Pounds", "POUNDS", UN_SC_LB, 0.0, B_UNIT_DEF_NONE}, /* base unit */
- {"ounce", "ounces", "oz", NULL, "Ounces", "OUNCES", UN_SC_OZ, 0.0, B_UNIT_DEF_NONE},
- NULL_UNIT,
+ {"ton", "tonnes", "ton", "t", "Tonnes", "TONNES", UN_SC_ITON, 0.0, B_UNIT_DEF_NONE},
+ {"centum weight", "centum weights", "cwt", NULL, "Centum weights", "CENTUM_WEIGHTS", UN_SC_CWT, 0.0, B_UNIT_DEF_NONE},
+ {"stone", "stones", "st", NULL, "Stones", "STONES", UN_SC_ST, 0.0, B_UNIT_DEF_NONE},
+ {"pound", "pounds", "lb", NULL, "Pounds", "POUNDS", UN_SC_LB, 0.0, B_UNIT_DEF_NONE}, /* base unit */
+ {"ounce", "ounces", "oz", NULL, "Ounces", "OUNCES", UN_SC_OZ, 0.0, B_UNIT_DEF_NONE},
+ NULL_UNIT,
};
static struct bUnitCollection buImperialMassCollection = {buImperialMassDef, 3, 0, UNIT_COLLECTION_LENGTH(buImperialMassDef)};
@@ -248,88 +248,88 @@ static struct bUnitCollection buImperialMassCollection = {buImperialMassDef, 3,
/* Velocity */
static struct bUnitDef buMetricVelDef[] = {
- {"meter per second", "meters per second", "m/s", NULL, "Meters per second", NULL, UN_SC_M, 0.0, B_UNIT_DEF_NONE}, /* base unit */
- {"kilometer per hour", "kilometers per hour", "km/h", NULL, "Kilometers per hour", NULL, UN_SC_KM / 3600.0f, 0.0, B_UNIT_DEF_SUPPRESS},
- NULL_UNIT,
+ {"meter per second", "meters per second", "m/s", NULL, "Meters per second", NULL, UN_SC_M, 0.0, B_UNIT_DEF_NONE}, /* base unit */
+ {"kilometer per hour", "kilometers per hour", "km/h", NULL, "Kilometers per hour", NULL, UN_SC_KM / 3600.0f, 0.0, B_UNIT_DEF_SUPPRESS},
+ NULL_UNIT,
};
static struct bUnitCollection buMetricVelCollection = {buMetricVelDef, 0, 0, UNIT_COLLECTION_LENGTH(buMetricVelDef)};
static struct bUnitDef buImperialVelDef[] = {
- {"foot per second", "feet per second", "ft/s", "fps", "Feet per second", NULL, UN_SC_FT, 0.0, B_UNIT_DEF_NONE}, /* base unit */
- {"mile per hour", "miles per hour", "mph", NULL, "Miles per hour", NULL, UN_SC_MI / 3600.0f, 0.0, B_UNIT_DEF_SUPPRESS},
- NULL_UNIT,
+ {"foot per second", "feet per second", "ft/s", "fps", "Feet per second", NULL, UN_SC_FT, 0.0, B_UNIT_DEF_NONE}, /* base unit */
+ {"mile per hour", "miles per hour", "mph", NULL, "Miles per hour", NULL, UN_SC_MI / 3600.0f, 0.0, B_UNIT_DEF_SUPPRESS},
+ NULL_UNIT,
};
static struct bUnitCollection buImperialVelCollection = {buImperialVelDef, 0, 0, UNIT_COLLECTION_LENGTH(buImperialVelDef)};
/* Acceleration */
static struct bUnitDef buMetricAclDef[] = {
- {"meter per second squared", "meters per second squared", "m/s²", "m/s2", "Meters per second squared", NULL, UN_SC_M, 0.0, B_UNIT_DEF_NONE}, /* base unit */
- NULL_UNIT,
+ {"meter per second squared", "meters per second squared", "m/s²", "m/s2", "Meters per second squared", NULL, UN_SC_M, 0.0, B_UNIT_DEF_NONE}, /* base unit */
+ NULL_UNIT,
};
static struct bUnitCollection buMetricAclCollection = {buMetricAclDef, 0, 0, UNIT_COLLECTION_LENGTH(buMetricAclDef)};
static struct bUnitDef buImperialAclDef[] = {
- {"foot per second squared", "feet per second squared", "ft/s²", "ft/s2", "Feet per second squared", NULL, UN_SC_FT, 0.0, B_UNIT_DEF_NONE}, /* base unit */
- NULL_UNIT,
+ {"foot per second squared", "feet per second squared", "ft/s²", "ft/s2", "Feet per second squared", NULL, UN_SC_FT, 0.0, B_UNIT_DEF_NONE}, /* base unit */
+ NULL_UNIT,
};
static struct bUnitCollection buImperialAclCollection = {buImperialAclDef, 0, 0, UNIT_COLLECTION_LENGTH(buImperialAclDef)};
/* Time */
static struct bUnitDef buNaturalTimeDef[] = {
- /* weeks? - probably not needed for blender */
- {"day", "days", "d", NULL, "Days", "DAYS", 90000.0, 0.0, B_UNIT_DEF_NONE},
- {"hour", "hours", "hr", "h", "Hours", "HOURS", 3600.0, 0.0, B_UNIT_DEF_NONE},
- {"minute", "minutes", "min", "m", "Minutes", "MINUTES", 60.0, 0.0, B_UNIT_DEF_NONE},
- {"second", "seconds", "sec", "s", "Seconds", "SECONDS", 1.0, 0.0, B_UNIT_DEF_NONE}, /* base unit */
- {"millisecond", "milliseconds", "ms", NULL, "Milliseconds", "MILLISECONDS", 0.001, 0.0, B_UNIT_DEF_NONE},
- {"microsecond", "microseconds", "µs", "us", "Microseconds", "MICROSECONDS", 0.000001, 0.0, B_UNIT_DEF_NONE},
- NULL_UNIT,
+ /* weeks? - probably not needed for blender */
+ {"day", "days", "d", NULL, "Days", "DAYS", 90000.0, 0.0, B_UNIT_DEF_NONE},
+ {"hour", "hours", "hr", "h", "Hours", "HOURS", 3600.0, 0.0, B_UNIT_DEF_NONE},
+ {"minute", "minutes", "min", "m", "Minutes", "MINUTES", 60.0, 0.0, B_UNIT_DEF_NONE},
+ {"second", "seconds", "sec", "s", "Seconds", "SECONDS", 1.0, 0.0, B_UNIT_DEF_NONE}, /* base unit */
+ {"millisecond", "milliseconds", "ms", NULL, "Milliseconds", "MILLISECONDS", 0.001, 0.0, B_UNIT_DEF_NONE},
+ {"microsecond", "microseconds", "µs", "us", "Microseconds", "MICROSECONDS", 0.000001, 0.0, B_UNIT_DEF_NONE},
+ NULL_UNIT,
};
static struct bUnitCollection buNaturalTimeCollection = {buNaturalTimeDef, 3, 0, UNIT_COLLECTION_LENGTH(buNaturalTimeDef)};
static struct bUnitDef buNaturalRotDef[] = {
- {"degree", "degrees", "°", "d", "Degrees", "DEGREES", M_PI / 180.0, 0.0, B_UNIT_DEF_NONE},
- /* arcminutes/arcseconds are used in Astronomy/Navigation areas... */
- {"arcminute", "arcminutes", "'", NULL, "Arcminutes", "ARCMINUTES", (M_PI / 180.0) / 60.0, 0.0, B_UNIT_DEF_SUPPRESS},
- {"arcsecond", "arcseconds", "\"", NULL, "Arcseconds", "ARCSECONDS", (M_PI / 180.0) / 3600.0, 0.0, B_UNIT_DEF_SUPPRESS},
- {"radian", "radians", "r", NULL, "Radians", "RADIANS", 1.0, 0.0, B_UNIT_DEF_NONE},
-// {"turn", "turns", "t", NULL, "Turns", NULL, 1.0 / (M_PI * 2.0), 0.0, B_UNIT_DEF_NONE},
- NULL_UNIT,
+ {"degree", "degrees", "°", "d", "Degrees", "DEGREES", M_PI / 180.0, 0.0, B_UNIT_DEF_NONE},
+ /* arcminutes/arcseconds are used in Astronomy/Navigation areas... */
+ {"arcminute", "arcminutes", "'", NULL, "Arcminutes", "ARCMINUTES", (M_PI / 180.0) / 60.0, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"arcsecond", "arcseconds", "\"", NULL, "Arcseconds", "ARCSECONDS", (M_PI / 180.0) / 3600.0, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"radian", "radians", "r", NULL, "Radians", "RADIANS", 1.0, 0.0, B_UNIT_DEF_NONE},
+// {"turn", "turns", "t", NULL, "Turns", NULL, 1.0 / (M_PI * 2.0), 0.0, B_UNIT_DEF_NONE},
+ NULL_UNIT,
};
static struct bUnitCollection buNaturalRotCollection = {buNaturalRotDef, 0, 0, UNIT_COLLECTION_LENGTH(buNaturalRotDef)};
/* Camera Lengths */
static struct bUnitDef buCameraLenDef[] = {
- {"meter", "meters", "m", NULL, "Meters", NULL, UN_SC_KM, 0.0, B_UNIT_DEF_NONE}, /* base unit */
- {"decimeter", "decimeters", "dm", NULL, "10 Centimeters", NULL, UN_SC_HM, 0.0, B_UNIT_DEF_SUPPRESS},
- {"centimeter", "centimeters", "cm", NULL, "Centimeters", NULL, UN_SC_DAM, 0.0, B_UNIT_DEF_SUPPRESS},
- {"millimeter", "millimeters", "mm", NULL, "Millimeters", NULL, UN_SC_M, 0.0, B_UNIT_DEF_NONE},
- {"micrometer", "micrometers", "µm", "um", "Micrometers", NULL, UN_SC_MM, 0.0, B_UNIT_DEF_SUPPRESS},
- NULL_UNIT,
+ {"meter", "meters", "m", NULL, "Meters", NULL, UN_SC_KM, 0.0, B_UNIT_DEF_NONE}, /* base unit */
+ {"decimeter", "decimeters", "dm", NULL, "10 Centimeters", NULL, UN_SC_HM, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"centimeter", "centimeters", "cm", NULL, "Centimeters", NULL, UN_SC_DAM, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"millimeter", "millimeters", "mm", NULL, "Millimeters", NULL, UN_SC_M, 0.0, B_UNIT_DEF_NONE},
+ {"micrometer", "micrometers", "µm", "um", "Micrometers", NULL, UN_SC_MM, 0.0, B_UNIT_DEF_SUPPRESS},
+ NULL_UNIT,
};
static struct bUnitCollection buCameraLenCollection = {buCameraLenDef, 3, 0, UNIT_COLLECTION_LENGTH(buCameraLenDef)};
/* (Light) Power */
static struct bUnitDef buPowerDef[] = {
- {"gigawatt", "gigawatts", "GW", NULL, "Gigawatts", NULL, 1e9f, 0.0, B_UNIT_DEF_NONE},
- {"megawatt", "megawatts", "MW", NULL, "Megawatts", NULL, 1e6f, 0.0, B_UNIT_DEF_CASE_SENSITIVE},
- {"kilowatt", "kilowatts", "kW", NULL, "Kilowatts", NULL, 1e3f, 0.0, B_UNIT_DEF_SUPPRESS},
- {"watt", "watts", "W", NULL, "Watts", NULL, 1.0f, 0.0, B_UNIT_DEF_NONE}, /* base unit */
- {"milliwatt", "milliwatts", "mW", NULL, "Milliwatts", NULL, 1e-3f, 0.0, B_UNIT_DEF_CASE_SENSITIVE},
- {"microwatt", "microwatts", "µW", "uW", "Microwatts", NULL, 1e-6f, 0.0, B_UNIT_DEF_NONE},
- {"nanowatt", "nanowatts", "nW", NULL, "Nanowatts", NULL, 1e-9f, 0.0, B_UNIT_DEF_NONE},
- NULL_UNIT,
+ {"gigawatt", "gigawatts", "GW", NULL, "Gigawatts", NULL, 1e9f, 0.0, B_UNIT_DEF_NONE},
+ {"megawatt", "megawatts", "MW", NULL, "Megawatts", NULL, 1e6f, 0.0, B_UNIT_DEF_CASE_SENSITIVE},
+ {"kilowatt", "kilowatts", "kW", NULL, "Kilowatts", NULL, 1e3f, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"watt", "watts", "W", NULL, "Watts", NULL, 1.0f, 0.0, B_UNIT_DEF_NONE}, /* base unit */
+ {"milliwatt", "milliwatts", "mW", NULL, "Milliwatts", NULL, 1e-3f, 0.0, B_UNIT_DEF_CASE_SENSITIVE},
+ {"microwatt", "microwatts", "µW", "uW", "Microwatts", NULL, 1e-6f, 0.0, B_UNIT_DEF_NONE},
+ {"nanowatt", "nanowatts", "nW", NULL, "Nanowatts", NULL, 1e-9f, 0.0, B_UNIT_DEF_NONE},
+ NULL_UNIT,
};
static struct bUnitCollection buPowerCollection = {buPowerDef, 3, 0, UNIT_COLLECTION_LENGTH(buPowerDef)};
#define UNIT_SYSTEM_TOT (((sizeof(bUnitSystems) / B_UNIT_TYPE_TOT) / sizeof(void *)) - 1)
static const struct bUnitCollection *bUnitSystems[][B_UNIT_TYPE_TOT] = {
- {NULL, NULL, NULL, NULL, NULL, &buNaturalRotCollection, &buNaturalTimeCollection, NULL, NULL, NULL, NULL},
- {NULL, &buMetricLenCollection, &buMetricAreaCollection, &buMetricVolCollection, &buMetricMassCollection, &buNaturalRotCollection, &buNaturalTimeCollection, &buMetricVelCollection, &buMetricAclCollection, &buCameraLenCollection, &buPowerCollection}, /* metric */
- {NULL, &buImperialLenCollection, &buImperialAreaCollection, &buImperialVolCollection, &buImperialMassCollection, &buNaturalRotCollection, &buNaturalTimeCollection, &buImperialVelCollection, &buImperialAclCollection, &buCameraLenCollection, &buPowerCollection}, /* imperial */
- {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
+ {NULL, NULL, NULL, NULL, NULL, &buNaturalRotCollection, &buNaturalTimeCollection, NULL, NULL, NULL, NULL},
+ {NULL, &buMetricLenCollection, &buMetricAreaCollection, &buMetricVolCollection, &buMetricMassCollection, &buNaturalRotCollection, &buNaturalTimeCollection, &buMetricVelCollection, &buMetricAclCollection, &buCameraLenCollection, &buPowerCollection}, /* metric */
+ {NULL, &buImperialLenCollection, &buImperialAreaCollection, &buImperialVolCollection, &buImperialMassCollection, &buNaturalRotCollection, &buNaturalTimeCollection, &buImperialVelCollection, &buImperialAclCollection, &buCameraLenCollection, &buPowerCollection}, /* imperial */
+ {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
};
/* clang-format on */
@@ -337,294 +337,328 @@ static const struct bUnitCollection *bUnitSystems[][B_UNIT_TYPE_TOT] = {
/* internal, has some option not exposed */
static const bUnitCollection *unit_get_system(int system, int type)
{
- assert((system > -1) && (system < UNIT_SYSTEM_TOT) && (type > -1) && (type < B_UNIT_TYPE_TOT));
- return bUnitSystems[system][type]; /* select system to use, metric/imperial/other? */
+ assert((system > -1) && (system < UNIT_SYSTEM_TOT) && (type > -1) && (type < B_UNIT_TYPE_TOT));
+ return bUnitSystems[system][type]; /* select system to use, metric/imperial/other? */
}
static const bUnitDef *unit_default(const bUnitCollection *usys)
{
- return &usys->units[usys->base_unit];
+ return &usys->units[usys->base_unit];
}
-static const bUnitDef *unit_best_fit(
- double value, const bUnitCollection *usys, const bUnitDef *unit_start, int suppress)
+static const bUnitDef *unit_best_fit(double value,
+ const bUnitCollection *usys,
+ const bUnitDef *unit_start,
+ int suppress)
{
- const bUnitDef *unit;
- double value_abs = value > 0.0 ? value : -value;
-
- for (unit = unit_start ? unit_start : usys->units; unit->name; unit++) {
-
- if (suppress && (unit->flag & B_UNIT_DEF_SUPPRESS))
- continue;
-
- /* scale down scalar so 1cm doesn't convert to 10mm because of float error */
- if (UNLIKELY(unit->flag & B_UNIT_DEF_TENTH)) {
- if (value_abs >= unit->scalar * (0.1 - EPS)) {
- return unit;
- }
- }
- else {
- if (value_abs >= unit->scalar * (1.0 - EPS)) {
- return unit;
- }
- }
- }
-
- return unit_default(usys);
+ const bUnitDef *unit;
+ double value_abs = value > 0.0 ? value : -value;
+
+ for (unit = unit_start ? unit_start : usys->units; unit->name; unit++) {
+
+ if (suppress && (unit->flag & B_UNIT_DEF_SUPPRESS))
+ continue;
+
+ /* scale down scalar so 1cm doesn't convert to 10mm because of float error */
+ if (UNLIKELY(unit->flag & B_UNIT_DEF_TENTH)) {
+ if (value_abs >= unit->scalar * (0.1 - EPS)) {
+ return unit;
+ }
+ }
+ else {
+ if (value_abs >= unit->scalar * (1.0 - EPS)) {
+ return unit;
+ }
+ }
+ }
+
+ return unit_default(usys);
}
/* convert into 2 units and 2 values for "2ft, 3inch" syntax */
-static void unit_dual_convert(
- double value, const bUnitCollection *usys,
- bUnitDef const **r_unit_a, bUnitDef const **r_unit_b,
- double *r_value_a, double *r_value_b,
- const bUnitDef *main_unit)
+static void unit_dual_convert(double value,
+ const bUnitCollection *usys,
+ bUnitDef const **r_unit_a,
+ bUnitDef const **r_unit_b,
+ double *r_value_a,
+ double *r_value_b,
+ const bUnitDef *main_unit)
{
- const bUnitDef *unit;
- if (main_unit) unit = main_unit;
- else unit = unit_best_fit(value, usys, NULL, 1);
+ const bUnitDef *unit;
+ if (main_unit)
+ unit = main_unit;
+ else
+ unit = unit_best_fit(value, usys, NULL, 1);
- *r_value_a = (value < 0.0 ? ceil : floor)(value / unit->scalar) * unit->scalar;
- *r_value_b = value - (*r_value_a);
+ *r_value_a = (value < 0.0 ? ceil : floor)(value / unit->scalar) * unit->scalar;
+ *r_value_b = value - (*r_value_a);
- *r_unit_a = unit;
- *r_unit_b = unit_best_fit(*r_value_b, usys, *r_unit_a, 1);
+ *r_unit_a = unit;
+ *r_unit_b = unit_best_fit(*r_value_b, usys, *r_unit_a, 1);
}
-static size_t unit_as_string(char *str, int len_max, double value, int prec, const bUnitCollection *usys,
+static size_t unit_as_string(char *str,
+ int len_max,
+ double value,
+ int prec,
+ const bUnitCollection *usys,
/* non exposed options */
- const bUnitDef *unit, char pad)
-{
- double value_conv;
- size_t len, i;
-
- if (unit) {
- /* use unit without finding the best one */
- }
- else if (value == 0.0) {
- /* use the default units since there is no way to convert */
- unit = unit_default(usys);
- }
- else {
- unit = unit_best_fit(value, usys, NULL, 1);
- }
-
- value_conv = value / unit->scalar;
-
- /* Adjust precision to expected number of significant digits.
- * Note that here, we shall not have to worry about very big/small numbers, units are expected to replace
- * 'scientific notation' in those cases. */
- prec -= integer_digits_d(value_conv);
- CLAMP(prec, 0, 6);
-
- /* Convert to a string */
- len = BLI_snprintf_rlen(str, len_max, "%.*f", prec, value_conv);
-
- /* Add unit prefix and strip zeros */
-
- /* replace trailing zero's with spaces
- * so the number is less complicated but alignment in a button wont
- * jump about while dragging */
- i = len - 1;
-
- if (prec > 0) {
- while (i > 0 && str[i] == '0') { /* 4.300 -> 4.3 */
- str[i--] = pad;
- }
-
- if (i > 0 && str[i] == '.') { /* 10. -> 10 */
- str[i--] = pad;
- }
- }
-
- /* Now add the suffix */
- if (i < len_max) {
- int j = 0;
- i++;
- while (unit->name_short[j] && (i < len_max)) {
- str[i++] = unit->name_short[j++];
- }
- }
-
- /* terminate no matter what's done with padding above */
- if (i >= len_max)
- i = len_max - 1;
-
- str[i] = '\0';
- return i;
+ const bUnitDef *unit,
+ char pad)
+{
+ double value_conv;
+ size_t len, i;
+
+ if (unit) {
+ /* use unit without finding the best one */
+ }
+ else if (value == 0.0) {
+ /* use the default units since there is no way to convert */
+ unit = unit_default(usys);
+ }
+ else {
+ unit = unit_best_fit(value, usys, NULL, 1);
+ }
+
+ value_conv = value / unit->scalar;
+
+ /* Adjust precision to expected number of significant digits.
+ * Note that here, we shall not have to worry about very big/small numbers, units are expected to replace
+ * 'scientific notation' in those cases. */
+ prec -= integer_digits_d(value_conv);
+ CLAMP(prec, 0, 6);
+
+ /* Convert to a string */
+ len = BLI_snprintf_rlen(str, len_max, "%.*f", prec, value_conv);
+
+ /* Add unit prefix and strip zeros */
+
+ /* replace trailing zero's with spaces
+ * so the number is less complicated but alignment in a button wont
+ * jump about while dragging */
+ i = len - 1;
+
+ if (prec > 0) {
+ while (i > 0 && str[i] == '0') { /* 4.300 -> 4.3 */
+ str[i--] = pad;
+ }
+
+ if (i > 0 && str[i] == '.') { /* 10. -> 10 */
+ str[i--] = pad;
+ }
+ }
+
+ /* Now add the suffix */
+ if (i < len_max) {
+ int j = 0;
+ i++;
+ while (unit->name_short[j] && (i < len_max)) {
+ str[i++] = unit->name_short[j++];
+ }
+ }
+
+ /* terminate no matter what's done with padding above */
+ if (i >= len_max)
+ i = len_max - 1;
+
+ str[i] = '\0';
+ return i;
}
static bool unit_should_be_split(int type)
{
- return ELEM(type, B_UNIT_LENGTH, B_UNIT_MASS, B_UNIT_TIME, B_UNIT_CAMERA);
+ return ELEM(type, B_UNIT_LENGTH, B_UNIT_MASS, B_UNIT_TIME, B_UNIT_CAMERA);
}
typedef struct {
- int system;
- int rotation;
- /* USER_UNIT_ADAPTIVE means none, otherwise the value is the index in the collection */
- int length;
- int mass;
- int time;
+ int system;
+ int rotation;
+ /* USER_UNIT_ADAPTIVE means none, otherwise the value is the index in the collection */
+ int length;
+ int mass;
+ int time;
} PreferredUnits;
static PreferredUnits preferred_units_from_UnitSettings(const UnitSettings *settings)
{
- PreferredUnits units = { 0 };
- units.system = settings->system;
- units.rotation = settings->system_rotation;
- units.length = settings->length_unit;
- units.mass = settings->mass_unit;
- units.time = settings->time_unit;
- return units;
+ PreferredUnits units = {0};
+ units.system = settings->system;
+ units.rotation = settings->system_rotation;
+ units.length = settings->length_unit;
+ units.mass = settings->mass_unit;
+ units.time = settings->time_unit;
+ return units;
}
-static size_t unit_as_string_splitted(
- char *str, int len_max, double value, int prec,
- const bUnitCollection *usys, const bUnitDef *main_unit)
+static size_t unit_as_string_splitted(char *str,
+ int len_max,
+ double value,
+ int prec,
+ const bUnitCollection *usys,
+ const bUnitDef *main_unit)
{
- const bUnitDef *unit_a, *unit_b;
- double value_a, value_b;
+ const bUnitDef *unit_a, *unit_b;
+ double value_a, value_b;
- unit_dual_convert(value, usys, &unit_a, &unit_b, &value_a, &value_b, main_unit);
+ unit_dual_convert(value, usys, &unit_a, &unit_b, &value_a, &value_b, main_unit);
- /* check the 2 is a smaller unit */
- if (unit_b > unit_a) {
- size_t i;
- i = unit_as_string(str, len_max, value_a, prec, usys, unit_a, '\0');
+ /* check the 2 is a smaller unit */
+ if (unit_b > unit_a) {
+ size_t i;
+ i = unit_as_string(str, len_max, value_a, prec, usys, unit_a, '\0');
- prec -= integer_digits_d(value_a / unit_b->scalar) - integer_digits_d(value_b / unit_b->scalar);
- prec = max_ii(prec, 0);
+ prec -= integer_digits_d(value_a / unit_b->scalar) -
+ integer_digits_d(value_b / unit_b->scalar);
+ prec = max_ii(prec, 0);
- /* is there enough space for at least 1 char of the next unit? */
- if (i + 2 < len_max) {
- str[i++] = ' ';
+ /* is there enough space for at least 1 char of the next unit? */
+ if (i + 2 < len_max) {
+ str[i++] = ' ';
- /* use low precision since this is a smaller unit */
- i += unit_as_string(str + i, len_max - i, value_b, prec, usys, unit_b, '\0');
- }
- return i;
- }
+ /* use low precision since this is a smaller unit */
+ i += unit_as_string(str + i, len_max - i, value_b, prec, usys, unit_b, '\0');
+ }
+ return i;
+ }
- return -1;
+ return -1;
}
static bool is_valid_unit_collection(const bUnitCollection *usys)
{
- return usys != NULL && usys->units[0].name != NULL;
+ return usys != NULL && usys->units[0].name != NULL;
}
static const bUnitDef *get_preferred_display_unit_if_used(int type, PreferredUnits units)
{
- const bUnitCollection *usys = unit_get_system(units.system, type);
- if (!is_valid_unit_collection(usys)) return NULL;
-
- int max_offset = usys->length - 1;
-
- switch (type) {
- case B_UNIT_LENGTH:
- case B_UNIT_AREA:
- case B_UNIT_VOLUME:
- if (units.length == USER_UNIT_ADAPTIVE) return NULL;
- return usys->units + MIN2(units.length, max_offset);
- case B_UNIT_MASS:
- if (units.mass == USER_UNIT_ADAPTIVE) return NULL;
- return usys->units + MIN2(units.mass, max_offset);
- case B_UNIT_TIME:
- if (units.time == USER_UNIT_ADAPTIVE) return NULL;
- return usys->units + MIN2(units.time, max_offset);
- case B_UNIT_ROTATION:
- if (units.rotation == 0) return usys->units + 0;
- else if (units.rotation == USER_UNIT_ROT_RADIANS) return usys->units + 3;
- break;
- default:
- break;
- }
- return NULL;
+ const bUnitCollection *usys = unit_get_system(units.system, type);
+ if (!is_valid_unit_collection(usys))
+ return NULL;
+
+ int max_offset = usys->length - 1;
+
+ switch (type) {
+ case B_UNIT_LENGTH:
+ case B_UNIT_AREA:
+ case B_UNIT_VOLUME:
+ if (units.length == USER_UNIT_ADAPTIVE)
+ return NULL;
+ return usys->units + MIN2(units.length, max_offset);
+ case B_UNIT_MASS:
+ if (units.mass == USER_UNIT_ADAPTIVE)
+ return NULL;
+ return usys->units + MIN2(units.mass, max_offset);
+ case B_UNIT_TIME:
+ if (units.time == USER_UNIT_ADAPTIVE)
+ return NULL;
+ return usys->units + MIN2(units.time, max_offset);
+ case B_UNIT_ROTATION:
+ if (units.rotation == 0)
+ return usys->units + 0;
+ else if (units.rotation == USER_UNIT_ROT_RADIANS)
+ return usys->units + 3;
+ break;
+ default:
+ break;
+ }
+ return NULL;
}
/* Return the length of the generated string. */
-static size_t unit_as_string_main(
- char *str, int len_max, double value, int prec,
- int type, bool split, bool pad, PreferredUnits units)
+static size_t unit_as_string_main(char *str,
+ int len_max,
+ double value,
+ int prec,
+ int type,
+ bool split,
+ bool pad,
+ PreferredUnits units)
{
- const bUnitCollection *usys = unit_get_system(units.system, type);
- const bUnitDef *main_unit = NULL;
-
- if (!is_valid_unit_collection(usys)) {
- usys = &buDummyCollection;
- }
- else {
- main_unit = get_preferred_display_unit_if_used(type, units);
- }
-
- if (split && unit_should_be_split(type)) {
- int length = unit_as_string_splitted(str, len_max, value, prec, usys, main_unit);
- /* failed when length is negative, fallback to no split */
- if (length >= 0) return length;
- }
-
- return unit_as_string(str, len_max, value, prec, usys, main_unit, pad ? ' ' : '\0');
+ const bUnitCollection *usys = unit_get_system(units.system, type);
+ const bUnitDef *main_unit = NULL;
+
+ if (!is_valid_unit_collection(usys)) {
+ usys = &buDummyCollection;
+ }
+ else {
+ main_unit = get_preferred_display_unit_if_used(type, units);
+ }
+
+ if (split && unit_should_be_split(type)) {
+ int length = unit_as_string_splitted(str, len_max, value, prec, usys, main_unit);
+ /* failed when length is negative, fallback to no split */
+ if (length >= 0)
+ return length;
+ }
+
+ return unit_as_string(str, len_max, value, prec, usys, main_unit, pad ? ' ' : '\0');
}
-size_t bUnit_AsString(char *str, int len_max, double value, int prec, int system, int type, bool split, bool pad)
+size_t bUnit_AsString(
+ char *str, int len_max, double value, int prec, int system, int type, bool split, bool pad)
{
- PreferredUnits units;
- units.system = system;
- units.rotation = 0;
- units.length = USER_UNIT_ADAPTIVE;
- units.mass = USER_UNIT_ADAPTIVE;
- units.time = USER_UNIT_ADAPTIVE;
- return unit_as_string_main(str, len_max, value, prec, type, split, pad, units);
+ PreferredUnits units;
+ units.system = system;
+ units.rotation = 0;
+ units.length = USER_UNIT_ADAPTIVE;
+ units.mass = USER_UNIT_ADAPTIVE;
+ units.time = USER_UNIT_ADAPTIVE;
+ return unit_as_string_main(str, len_max, value, prec, type, split, pad, units);
}
-size_t bUnit_AsString2(char *str, int len_max, double value, int prec, int type, const UnitSettings *settings, bool pad)
+size_t bUnit_AsString2(char *str,
+ int len_max,
+ double value,
+ int prec,
+ int type,
+ const UnitSettings *settings,
+ bool pad)
{
- bool do_split = (settings->flag & USER_UNIT_OPT_SPLIT) != 0;
- PreferredUnits units = preferred_units_from_UnitSettings(settings);
- return unit_as_string_main(str, len_max, value, prec, type, do_split, pad, units);
+ bool do_split = (settings->flag & USER_UNIT_OPT_SPLIT) != 0;
+ PreferredUnits units = preferred_units_from_UnitSettings(settings);
+ return unit_as_string_main(str, len_max, value, prec, type, do_split, pad, units);
}
BLI_INLINE bool isalpha_or_utf8(const int ch)
{
- return (ch >= 128 || isalpha(ch));
+ return (ch >= 128 || isalpha(ch));
}
static const char *unit_find_str(const char *str, const char *substr, bool case_sensitive)
{
- if (substr && substr[0] != '\0') {
- while (true) {
- /* Unit detection is case insensitive. */
- const char *str_found;
- if (case_sensitive)
- str_found = strstr(str, substr);
- else
- str_found = BLI_strcasestr(str, substr);
-
- if (str_found) {
- /* Previous char cannot be a letter. */
- if (str_found == str ||
- /* weak unicode support!, so "µm" won't match up be replaced by "m"
- * since non ascii utf8 values will NEVER return true */
- isalpha_or_utf8(*BLI_str_prev_char_utf8(str_found)) == 0)
- {
- /* next char cannot be alphanum */
- int len_name = strlen(substr);
-
- if (!isalpha_or_utf8(*(str_found + len_name))) {
- return str_found;
- }
- }
- /* If str_found is not a valid unit, we have to check further in the string... */
- for (str_found++; isalpha_or_utf8(*str_found); str_found++);
- str = str_found;
- }
- else {
- break;
- }
- }
- }
- return NULL;
+ if (substr && substr[0] != '\0') {
+ while (true) {
+ /* Unit detection is case insensitive. */
+ const char *str_found;
+ if (case_sensitive)
+ str_found = strstr(str, substr);
+ else
+ str_found = BLI_strcasestr(str, substr);
+
+ if (str_found) {
+ /* Previous char cannot be a letter. */
+ if (str_found == str ||
+ /* weak unicode support!, so "µm" won't match up be replaced by "m"
+ * since non ascii utf8 values will NEVER return true */
+ isalpha_or_utf8(*BLI_str_prev_char_utf8(str_found)) == 0) {
+ /* next char cannot be alphanum */
+ int len_name = strlen(substr);
+
+ if (!isalpha_or_utf8(*(str_found + len_name))) {
+ return str_found;
+ }
+ }
+ /* If str_found is not a valid unit, we have to check further in the string... */
+ for (str_found++; isalpha_or_utf8(*str_found); str_found++)
+ ;
+ str = str_found;
+ }
+ else {
+ break;
+ }
+ }
+ }
+ return NULL;
}
/* Note that numbers are added within brackets
@@ -638,146 +672,166 @@ static const char *unit_find_str(const char *str, const char *substr, bool case_
/* not too strict, (+ - * /) are most common */
static bool ch_is_op(char op)
{
- switch (op) {
- case '+':
- case '-':
- case '*':
- case '/':
- case '|':
- case '&':
- case '~':
- case '<':
- case '>':
- case '^':
- case '!':
- case '=':
- case '%':
- return true;
- default:
- return false;
- }
+ switch (op) {
+ case '+':
+ case '-':
+ case '*':
+ case '/':
+ case '|':
+ case '&':
+ case '~':
+ case '<':
+ case '>':
+ case '^':
+ case '!':
+ case '=':
+ case '%':
+ return true;
+ default:
+ return false;
+ }
}
-static int unit_scale_str(char *str, int len_max, char *str_tmp, double scale_pref, const bUnitDef *unit,
- const char *replace_str, bool case_sensitive)
+static int unit_scale_str(char *str,
+ int len_max,
+ char *str_tmp,
+ double scale_pref,
+ const bUnitDef *unit,
+ const char *replace_str,
+ bool case_sensitive)
{
- char *str_found;
+ char *str_found;
- if ((len_max > 0) && (str_found = (char *)unit_find_str(str, replace_str, case_sensitive))) {
- /* XXX - investigate, does not respect len_max properly */
+ if ((len_max > 0) && (str_found = (char *)unit_find_str(str, replace_str, case_sensitive))) {
+ /* XXX - investigate, does not respect len_max properly */
- int len, len_num, len_name, len_move, found_ofs;
+ int len, len_num, len_name, len_move, found_ofs;
- found_ofs = (int)(str_found - str);
+ found_ofs = (int)(str_found - str);
- len = strlen(str);
+ len = strlen(str);
- len_name = strlen(replace_str);
- len_move = (len - (found_ofs + len_name)) + 1; /* 1+ to copy the string terminator */
- len_num = BLI_snprintf(str_tmp, TEMP_STR_SIZE, "*%.9g"SEP_STR, unit->scalar / scale_pref); /* # removed later */
+ len_name = strlen(replace_str);
+ len_move = (len - (found_ofs + len_name)) + 1; /* 1+ to copy the string terminator */
+ len_num = BLI_snprintf(
+ str_tmp, TEMP_STR_SIZE, "*%.9g" SEP_STR, unit->scalar / scale_pref); /* # removed later */
- if (len_num > len_max)
- len_num = len_max;
+ if (len_num > len_max)
+ len_num = len_max;
- if (found_ofs + len_num + len_move > len_max) {
- /* can't move the whole string, move just as much as will fit */
- len_move -= (found_ofs + len_num + len_move) - len_max;
- }
+ if (found_ofs + len_num + len_move > len_max) {
+ /* can't move the whole string, move just as much as will fit */
+ len_move -= (found_ofs + len_num + len_move) - len_max;
+ }
- if (len_move > 0) {
- /* resize the last part of the string */
- memmove(str_found + len_num, str_found + len_name, len_move); /* may grow or shrink the string */
- }
+ if (len_move > 0) {
+ /* resize the last part of the string */
+ memmove(
+ str_found + len_num, str_found + len_name, len_move); /* may grow or shrink the string */
+ }
- if (found_ofs + len_num > len_max) {
- /* not even the number will fit into the string, only copy part of it */
- len_num -= (found_ofs + len_num) - len_max;
- }
+ if (found_ofs + len_num > len_max) {
+ /* not even the number will fit into the string, only copy part of it */
+ len_num -= (found_ofs + len_num) - len_max;
+ }
- if (len_num > 0) {
- /* its possible none of the number could be copied in */
- memcpy(str_found, str_tmp, len_num); /* without the string terminator */
- }
+ if (len_num > 0) {
+ /* its possible none of the number could be copied in */
+ memcpy(str_found, str_tmp, len_num); /* without the string terminator */
+ }
- /* since the null terminator wont be moved if the stringlen_max
- * was not long enough to fit everything in it */
- str[len_max - 1] = '\0';
- return found_ofs + len_num;
- }
- return 0;
+ /* since the null terminator wont be moved if the stringlen_max
+ * was not long enough to fit everything in it */
+ str[len_max - 1] = '\0';
+ return found_ofs + len_num;
+ }
+ return 0;
}
-static int unit_replace(char *str, int len_max, char *str_tmp, double scale_pref, const bUnitDef *unit)
+static int unit_replace(
+ char *str, int len_max, char *str_tmp, double scale_pref, const bUnitDef *unit)
{
- const bool case_sensitive = (unit->flag & B_UNIT_DEF_CASE_SENSITIVE) != 0;
- int ofs = 0;
- ofs += unit_scale_str(str + ofs, len_max - ofs, str_tmp, scale_pref, unit, unit->name_short, case_sensitive);
- ofs += unit_scale_str(str + ofs, len_max - ofs, str_tmp, scale_pref, unit, unit->name_plural, false);
- ofs += unit_scale_str(str + ofs, len_max - ofs, str_tmp, scale_pref, unit, unit->name_alt, case_sensitive);
- ofs += unit_scale_str(str + ofs, len_max - ofs, str_tmp, scale_pref, unit, unit->name, false);
- return ofs;
+ const bool case_sensitive = (unit->flag & B_UNIT_DEF_CASE_SENSITIVE) != 0;
+ int ofs = 0;
+ ofs += unit_scale_str(
+ str + ofs, len_max - ofs, str_tmp, scale_pref, unit, unit->name_short, case_sensitive);
+ ofs += unit_scale_str(
+ str + ofs, len_max - ofs, str_tmp, scale_pref, unit, unit->name_plural, false);
+ ofs += unit_scale_str(
+ str + ofs, len_max - ofs, str_tmp, scale_pref, unit, unit->name_alt, case_sensitive);
+ ofs += unit_scale_str(str + ofs, len_max - ofs, str_tmp, scale_pref, unit, unit->name, false);
+ return ofs;
}
static bool unit_find(const char *str, const bUnitDef *unit)
{
- const bool case_sensitive = (unit->flag & B_UNIT_DEF_CASE_SENSITIVE) != 0;
- if (unit_find_str(str, unit->name_short, case_sensitive)) return true;
- if (unit_find_str(str, unit->name_plural, false)) return true;
- if (unit_find_str(str, unit->name_alt, case_sensitive)) return true;
- if (unit_find_str(str, unit->name, false)) return true;
-
- return false;
+ const bool case_sensitive = (unit->flag & B_UNIT_DEF_CASE_SENSITIVE) != 0;
+ if (unit_find_str(str, unit->name_short, case_sensitive))
+ return true;
+ if (unit_find_str(str, unit->name_plural, false))
+ return true;
+ if (unit_find_str(str, unit->name_alt, case_sensitive))
+ return true;
+ if (unit_find_str(str, unit->name, false))
+ return true;
+
+ return false;
}
-static const bUnitDef *unit_detect_from_str(const bUnitCollection *usys, const char *str, const char *str_prev)
+static const bUnitDef *unit_detect_from_str(const bUnitCollection *usys,
+ const char *str,
+ const char *str_prev)
{
- /* Try to find a default unit from current or previous string.
- * This allows us to handle cases like 2 + 2mm, people would expect to get 4mm, not 2.002m!
- * Note this does not handle corner cases like 2 + 2cm + 1 + 2.5mm... We can't support everything. */
- const bUnitDef *unit = NULL;
-
- /* see which units the new value has */
- for (unit = usys->units; unit->name; unit++) {
- if (unit_find(str, unit))
- break;
- }
- /* Else, try to infer the default unit from the previous string. */
- if (str_prev && (unit == NULL || unit->name == NULL)) {
- /* see which units the original value had */
- for (unit = usys->units; unit->name; unit++) {
- if (unit_find(str_prev, unit))
- break;
- }
- }
- /* Else, fall back to default unit. */
- if (unit == NULL || unit->name == NULL) {
- unit = unit_default(usys);
- }
-
- return unit;
+ /* Try to find a default unit from current or previous string.
+ * This allows us to handle cases like 2 + 2mm, people would expect to get 4mm, not 2.002m!
+ * Note this does not handle corner cases like 2 + 2cm + 1 + 2.5mm... We can't support everything. */
+ const bUnitDef *unit = NULL;
+
+ /* see which units the new value has */
+ for (unit = usys->units; unit->name; unit++) {
+ if (unit_find(str, unit))
+ break;
+ }
+ /* Else, try to infer the default unit from the previous string. */
+ if (str_prev && (unit == NULL || unit->name == NULL)) {
+ /* see which units the original value had */
+ for (unit = usys->units; unit->name; unit++) {
+ if (unit_find(str_prev, unit))
+ break;
+ }
+ }
+ /* Else, fall back to default unit. */
+ if (unit == NULL || unit->name == NULL) {
+ unit = unit_default(usys);
+ }
+
+ return unit;
}
bool bUnit_ContainsUnit(const char *str, int type)
{
- for (int system = 0; system < UNIT_SYSTEM_TOT; system++) {
- const bUnitCollection *usys = unit_get_system(system, type);
- if (!is_valid_unit_collection(usys)) continue;
-
- for (int i = 0; i < usys->length; i++) {
- if (unit_find(str, usys->units + i)) {
- return true;
- }
- }
- }
- return false;
+ for (int system = 0; system < UNIT_SYSTEM_TOT; system++) {
+ const bUnitCollection *usys = unit_get_system(system, type);
+ if (!is_valid_unit_collection(usys))
+ continue;
+
+ for (int i = 0; i < usys->length; i++) {
+ if (unit_find(str, usys->units + i)) {
+ return true;
+ }
+ }
+ }
+ return false;
}
double bUnit_PreferredInputUnitScalar(const struct UnitSettings *settings, int type)
{
- PreferredUnits units = preferred_units_from_UnitSettings(settings);
- const bUnitDef *unit = get_preferred_display_unit_if_used(type, units);
- if (unit) return unit->scalar;
- else return bUnit_BaseScalar(units.system, type);
+ PreferredUnits units = preferred_units_from_UnitSettings(settings);
+ const bUnitDef *unit = get_preferred_display_unit_if_used(type, units);
+ if (unit)
+ return unit->scalar;
+ else
+ return bUnit_BaseScalar(units.system, type);
}
/* make a copy of the string that replaces the units with numbers
@@ -795,208 +849,213 @@ double bUnit_PreferredInputUnitScalar(const struct UnitSettings *settings, int t
*
* return true of a change was made.
*/
-bool bUnit_ReplaceString(char *str, int len_max, const char *str_prev, double scale_pref, int system, int type)
-{
- const bUnitCollection *usys = unit_get_system(system, type);
- if (!is_valid_unit_collection(usys)) return false;
-
- const bUnitDef *unit = NULL, *default_unit;
- double scale_pref_base = scale_pref;
- char str_tmp[TEMP_STR_SIZE];
- bool changed = false;
-
- /* Try to find a default unit from current or previous string. */
- default_unit = unit_detect_from_str(usys, str, str_prev);
-
- /* We apply the default unit to the whole expression (default unit is now the reference '1.0' one). */
- scale_pref_base *= default_unit->scalar;
-
- /* Apply the default unit on the whole expression, this allows to handle nasty cases like '2+2in'. */
- if (BLI_snprintf(str_tmp, sizeof(str_tmp), "(%s)*%.9g", str, default_unit->scalar) < sizeof(str_tmp)) {
- strncpy(str, str_tmp, len_max);
- }
- else {
- /* BLI_snprintf would not fit into str_tmp, cant do much in this case
- * check for this because otherwise bUnit_ReplaceString could call its self forever */
- return changed;
- }
-
- for (unit = usys->units; unit->name; unit++) {
- /* in case there are multiple instances */
- while (unit_replace(str, len_max, str_tmp, scale_pref_base, unit))
- changed = true;
- }
- unit = NULL;
-
- {
- /* try other unit systems now, so we can evaluate imperial when metric is set for eg. */
- /* Note that checking other systems at that point means we do not support their units as 'default' one.
- * In other words, when in metrics, typing '2+2in' will give 2 meters 2 inches, not 4 inches.
- * I do think this is the desired behavior!
- */
- const bUnitCollection *usys_iter;
- int system_iter;
-
- for (system_iter = 0; system_iter < UNIT_SYSTEM_TOT; system_iter++) {
- if (system_iter != system) {
- usys_iter = unit_get_system(system_iter, type);
- if (usys_iter) {
- for (unit = usys_iter->units; unit->name; unit++) {
- int ofs = 0;
- /* in case there are multiple instances */
- while ((ofs = unit_replace(str + ofs, len_max - ofs, str_tmp, scale_pref_base, unit)))
- changed = true;
- }
- }
- }
- }
- }
- unit = NULL;
-
- /* replace # with add sign when there is no operator between it and the next number
- *
- * "1*1# 3*100# * 3" -> "1*1+ 3*100 * 3"
- *
- * */
- {
- char *str_found = str;
- const char *ch = str;
-
- while ((str_found = strchr(str_found, SEP_CHR))) {
- bool op_found = false;
-
- /* any operators after this? */
- for (ch = str_found + 1; *ch != '\0'; ch++) {
- if (*ch == ' ' || *ch == '\t') {
- continue;
- }
- op_found = (ch_is_op(*ch) || ELEM(*ch, ',', ')'));
- break;
- }
-
- /* If found an op, comma or closing parenthesis, no need to insert a '+', else we need it. */
- *str_found++ = op_found ? ' ' : '+';
- }
- }
-
- return changed;
+bool bUnit_ReplaceString(
+ char *str, int len_max, const char *str_prev, double scale_pref, int system, int type)
+{
+ const bUnitCollection *usys = unit_get_system(system, type);
+ if (!is_valid_unit_collection(usys))
+ return false;
+
+ const bUnitDef *unit = NULL, *default_unit;
+ double scale_pref_base = scale_pref;
+ char str_tmp[TEMP_STR_SIZE];
+ bool changed = false;
+
+ /* Try to find a default unit from current or previous string. */
+ default_unit = unit_detect_from_str(usys, str, str_prev);
+
+ /* We apply the default unit to the whole expression (default unit is now the reference '1.0' one). */
+ scale_pref_base *= default_unit->scalar;
+
+ /* Apply the default unit on the whole expression, this allows to handle nasty cases like '2+2in'. */
+ if (BLI_snprintf(str_tmp, sizeof(str_tmp), "(%s)*%.9g", str, default_unit->scalar) <
+ sizeof(str_tmp)) {
+ strncpy(str, str_tmp, len_max);
+ }
+ else {
+ /* BLI_snprintf would not fit into str_tmp, cant do much in this case
+ * check for this because otherwise bUnit_ReplaceString could call its self forever */
+ return changed;
+ }
+
+ for (unit = usys->units; unit->name; unit++) {
+ /* in case there are multiple instances */
+ while (unit_replace(str, len_max, str_tmp, scale_pref_base, unit))
+ changed = true;
+ }
+ unit = NULL;
+
+ {
+ /* try other unit systems now, so we can evaluate imperial when metric is set for eg. */
+ /* Note that checking other systems at that point means we do not support their units as 'default' one.
+ * In other words, when in metrics, typing '2+2in' will give 2 meters 2 inches, not 4 inches.
+ * I do think this is the desired behavior!
+ */
+ const bUnitCollection *usys_iter;
+ int system_iter;
+
+ for (system_iter = 0; system_iter < UNIT_SYSTEM_TOT; system_iter++) {
+ if (system_iter != system) {
+ usys_iter = unit_get_system(system_iter, type);
+ if (usys_iter) {
+ for (unit = usys_iter->units; unit->name; unit++) {
+ int ofs = 0;
+ /* in case there are multiple instances */
+ while ((ofs = unit_replace(str + ofs, len_max - ofs, str_tmp, scale_pref_base, unit)))
+ changed = true;
+ }
+ }
+ }
+ }
+ }
+ unit = NULL;
+
+ /* replace # with add sign when there is no operator between it and the next number
+ *
+ * "1*1# 3*100# * 3" -> "1*1+ 3*100 * 3"
+ *
+ * */
+ {
+ char *str_found = str;
+ const char *ch = str;
+
+ while ((str_found = strchr(str_found, SEP_CHR))) {
+ bool op_found = false;
+
+ /* any operators after this? */
+ for (ch = str_found + 1; *ch != '\0'; ch++) {
+ if (*ch == ' ' || *ch == '\t') {
+ continue;
+ }
+ op_found = (ch_is_op(*ch) || ELEM(*ch, ',', ')'));
+ break;
+ }
+
+ /* If found an op, comma or closing parenthesis, no need to insert a '+', else we need it. */
+ *str_found++ = op_found ? ' ' : '+';
+ }
+ }
+
+ return changed;
}
/* 45µm --> 45um */
void bUnit_ToUnitAltName(char *str, int len_max, const char *orig_str, int system, int type)
{
- const bUnitCollection *usys = unit_get_system(system, type);
-
- const bUnitDef *unit;
-
- /* find and substitute all units */
- for (unit = usys->units; unit->name; unit++) {
- if (len_max > 0 && unit->name_alt) {
- const bool case_sensitive = (unit->flag & B_UNIT_DEF_CASE_SENSITIVE) != 0;
- const char *found = unit_find_str(orig_str, unit->name_short, case_sensitive);
- if (found) {
- int offset = (int)(found - orig_str);
- int len_name = 0;
-
- /* copy everything before the unit */
- offset = (offset < len_max ? offset : len_max);
- strncpy(str, orig_str, offset);
-
- str += offset;
- orig_str += offset + strlen(unit->name_short);
- len_max -= offset;
-
- /* print the alt_name */
- if (unit->name_alt)
- len_name = BLI_strncpy_rlen(str, unit->name_alt, len_max);
- else
- len_name = 0;
-
- len_name = (len_name < len_max ? len_name : len_max);
- str += len_name;
- len_max -= len_name;
- }
- }
- }
-
- /* finally copy the rest of the string */
- strncpy(str, orig_str, len_max);
+ const bUnitCollection *usys = unit_get_system(system, type);
+
+ const bUnitDef *unit;
+
+ /* find and substitute all units */
+ for (unit = usys->units; unit->name; unit++) {
+ if (len_max > 0 && unit->name_alt) {
+ const bool case_sensitive = (unit->flag & B_UNIT_DEF_CASE_SENSITIVE) != 0;
+ const char *found = unit_find_str(orig_str, unit->name_short, case_sensitive);
+ if (found) {
+ int offset = (int)(found - orig_str);
+ int len_name = 0;
+
+ /* copy everything before the unit */
+ offset = (offset < len_max ? offset : len_max);
+ strncpy(str, orig_str, offset);
+
+ str += offset;
+ orig_str += offset + strlen(unit->name_short);
+ len_max -= offset;
+
+ /* print the alt_name */
+ if (unit->name_alt)
+ len_name = BLI_strncpy_rlen(str, unit->name_alt, len_max);
+ else
+ len_name = 0;
+
+ len_name = (len_name < len_max ? len_name : len_max);
+ str += len_name;
+ len_max -= len_name;
+ }
+ }
+ }
+
+ /* finally copy the rest of the string */
+ strncpy(str, orig_str, len_max);
}
double bUnit_ClosestScalar(double value, int system, int type)
{
- const bUnitCollection *usys = unit_get_system(system, type);
- const bUnitDef *unit;
+ const bUnitCollection *usys = unit_get_system(system, type);
+ const bUnitDef *unit;
- if (usys == NULL)
- return -1;
+ if (usys == NULL)
+ return -1;
- unit = unit_best_fit(value, usys, NULL, 1);
- if (unit == NULL)
- return -1;
+ unit = unit_best_fit(value, usys, NULL, 1);
+ if (unit == NULL)
+ return -1;
- return unit->scalar;
+ return unit->scalar;
}
double bUnit_BaseScalar(int system, int type)
{
- const bUnitCollection *usys = unit_get_system(system, type);
- if (usys) return unit_default(usys)->scalar;
- else return 1.0;
+ const bUnitCollection *usys = unit_get_system(system, type);
+ if (usys)
+ return unit_default(usys)->scalar;
+ else
+ return 1.0;
}
/* external access */
bool bUnit_IsValid(int system, int type)
{
- return !(system < 0 || system > UNIT_SYSTEM_TOT || type < 0 || type > B_UNIT_TYPE_TOT);
+ return !(system < 0 || system > UNIT_SYSTEM_TOT || type < 0 || type > B_UNIT_TYPE_TOT);
}
void bUnit_GetSystem(int system, int type, void const **r_usys_pt, int *r_len)
{
- const bUnitCollection *usys = unit_get_system(system, type);
- *r_usys_pt = usys;
+ const bUnitCollection *usys = unit_get_system(system, type);
+ *r_usys_pt = usys;
- if (usys == NULL) {
- *r_len = 0;
- return;
- }
+ if (usys == NULL) {
+ *r_len = 0;
+ return;
+ }
- *r_len = usys->length;
+ *r_len = usys->length;
}
int bUnit_GetBaseUnit(const void *usys_pt)
{
- return ((bUnitCollection *)usys_pt)->base_unit;
+ return ((bUnitCollection *)usys_pt)->base_unit;
}
int bUnit_GetBaseUnitOfType(int system, int type)
{
- return unit_get_system(system, type)->base_unit;
+ return unit_get_system(system, type)->base_unit;
}
const char *bUnit_GetName(const void *usys_pt, int index)
{
- return ((bUnitCollection *)usys_pt)->units[index].name;
+ return ((bUnitCollection *)usys_pt)->units[index].name;
}
const char *bUnit_GetNameDisplay(const void *usys_pt, int index)
{
- return ((bUnitCollection *)usys_pt)->units[index].name_display;
+ return ((bUnitCollection *)usys_pt)->units[index].name_display;
}
const char *bUnit_GetIdentifier(const void *usys_pt, int index)
{
- const bUnitDef *unit = ((const bUnitCollection *)usys_pt)->units + index;
- if (unit->identifier == NULL) {
- BLI_assert(false && "identifier for this unit is not specified yet");
- }
- return unit->identifier;
+ const bUnitDef *unit = ((const bUnitCollection *)usys_pt)->units + index;
+ if (unit->identifier == NULL) {
+ BLI_assert(false && "identifier for this unit is not specified yet");
+ }
+ return unit->identifier;
}
double bUnit_GetScaler(const void *usys_pt, int index)
{
- return ((bUnitCollection *)usys_pt)->units[index].scalar;
+ return ((bUnitCollection *)usys_pt)->units[index].scalar;
}
bool bUnit_IsSuppressed(const void *usys_pt, int index)
{
- return (((bUnitCollection *)usys_pt)->units[index].flag & B_UNIT_DEF_SUPPRESS) != 0;
+ return (((bUnitCollection *)usys_pt)->units[index].flag & B_UNIT_DEF_SUPPRESS) != 0;
}
diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c
index e264856acb2..2e9591a99c7 100644
--- a/source/blender/blenkernel/intern/workspace.c
+++ b/source/blender/blenkernel/intern/workspace.c
@@ -42,15 +42,20 @@
#include "MEM_guardedalloc.h"
-
/* -------------------------------------------------------------------- */
/* Internal utils */
-static void workspace_layout_name_set(
- WorkSpace *workspace, WorkSpaceLayout *layout, const char *new_name)
+static void workspace_layout_name_set(WorkSpace *workspace,
+ WorkSpaceLayout *layout,
+ const char *new_name)
{
- BLI_strncpy(layout->name, new_name, sizeof(layout->name));
- BLI_uniquename(&workspace->layouts, layout, "Layout", '.', offsetof(WorkSpaceLayout, name), sizeof(layout->name));
+ BLI_strncpy(layout->name, new_name, sizeof(layout->name));
+ BLI_uniquename(&workspace->layouts,
+ layout,
+ "Layout",
+ '.',
+ offsetof(WorkSpaceLayout, name),
+ sizeof(layout->name));
}
/**
@@ -58,54 +63,53 @@ static void workspace_layout_name_set(
* a layout within \a workspace that wraps \a screen. Usually - especially outside
* of BKE_workspace - #BKE_workspace_layout_find should be used!
*/
-static WorkSpaceLayout *workspace_layout_find_exec(
- const WorkSpace *workspace, const bScreen *screen)
+static WorkSpaceLayout *workspace_layout_find_exec(const WorkSpace *workspace,
+ const bScreen *screen)
{
- return BLI_findptr(&workspace->layouts, screen, offsetof(WorkSpaceLayout, screen));
+ return BLI_findptr(&workspace->layouts, screen, offsetof(WorkSpaceLayout, screen));
}
-static void workspace_relation_add(
- ListBase *relation_list, void *parent, void *data)
+static void workspace_relation_add(ListBase *relation_list, void *parent, void *data)
{
- WorkSpaceDataRelation *relation = MEM_callocN(sizeof(*relation), __func__);
- relation->parent = parent;
- relation->value = data;
- /* add to head, if we switch back to it soon we find it faster. */
- BLI_addhead(relation_list, relation);
+ WorkSpaceDataRelation *relation = MEM_callocN(sizeof(*relation), __func__);
+ relation->parent = parent;
+ relation->value = data;
+ /* add to head, if we switch back to it soon we find it faster. */
+ BLI_addhead(relation_list, relation);
}
-static void workspace_relation_remove(
- ListBase *relation_list, WorkSpaceDataRelation *relation)
+static void workspace_relation_remove(ListBase *relation_list, WorkSpaceDataRelation *relation)
{
- BLI_remlink(relation_list, relation);
- MEM_freeN(relation);
+ BLI_remlink(relation_list, relation);
+ MEM_freeN(relation);
}
-static void workspace_relation_ensure_updated(
- ListBase *relation_list, void *parent, void *data)
+static void workspace_relation_ensure_updated(ListBase *relation_list, void *parent, void *data)
{
- WorkSpaceDataRelation *relation = BLI_findptr(relation_list, parent, offsetof(WorkSpaceDataRelation, parent));
- if (relation != NULL) {
- relation->value = data;
- /* reinsert at the head of the list, so that more commonly used relations are found faster. */
- BLI_remlink(relation_list, relation);
- BLI_addhead(relation_list, relation);
- }
- else {
- /* no matching relation found, add new one */
- workspace_relation_add(relation_list, parent, data);
- }
+ WorkSpaceDataRelation *relation = BLI_findptr(
+ relation_list, parent, offsetof(WorkSpaceDataRelation, parent));
+ if (relation != NULL) {
+ relation->value = data;
+ /* reinsert at the head of the list, so that more commonly used relations are found faster. */
+ BLI_remlink(relation_list, relation);
+ BLI_addhead(relation_list, relation);
+ }
+ else {
+ /* no matching relation found, add new one */
+ workspace_relation_add(relation_list, parent, data);
+ }
}
-static void *workspace_relation_get_data_matching_parent(
- const ListBase *relation_list, const void *parent)
+static void *workspace_relation_get_data_matching_parent(const ListBase *relation_list,
+ const void *parent)
{
- WorkSpaceDataRelation *relation = BLI_findptr(relation_list, parent, offsetof(WorkSpaceDataRelation, parent));
- if (relation != NULL) {
- return relation->value;
- }
- else {
- return NULL;
- }
+ WorkSpaceDataRelation *relation = BLI_findptr(
+ relation_list, parent, offsetof(WorkSpaceDataRelation, parent));
+ if (relation != NULL) {
+ return relation->value;
+ }
+ else {
+ return NULL;
+ }
}
/**
@@ -118,15 +122,15 @@ static bool workspaces_is_screen_used
#else
static bool UNUSED_FUNCTION(workspaces_is_screen_used)
#endif
- (const Main *bmain, bScreen *screen)
+ (const Main *bmain, bScreen *screen)
{
- for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
- if (workspace_layout_find_exec(workspace, screen)) {
- return true;
- }
- }
+ for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ if (workspace_layout_find_exec(workspace, screen)) {
+ return true;
+ }
+ }
- return false;
+ return false;
}
/* -------------------------------------------------------------------- */
@@ -134,8 +138,8 @@ static bool UNUSED_FUNCTION(workspaces_is_screen_used)
WorkSpace *BKE_workspace_add(Main *bmain, const char *name)
{
- WorkSpace *new_workspace = BKE_libblock_alloc(bmain, ID_WS, name, 0);
- return new_workspace;
+ WorkSpace *new_workspace = BKE_libblock_alloc(bmain, ID_WS, name, 0);
+ return new_workspace;
}
/**
@@ -146,19 +150,19 @@ WorkSpace *BKE_workspace_add(Main *bmain, const char *name)
*/
void BKE_workspace_free(WorkSpace *workspace)
{
- BKE_workspace_relations_free(&workspace->hook_layout_relations);
+ BKE_workspace_relations_free(&workspace->hook_layout_relations);
- BLI_freelistN(&workspace->owner_ids);
- BLI_freelistN(&workspace->layouts);
+ BLI_freelistN(&workspace->owner_ids);
+ BLI_freelistN(&workspace->layouts);
- while (!BLI_listbase_is_empty(&workspace->tools)) {
- BKE_workspace_tool_remove(workspace, workspace->tools.first);
- }
+ while (!BLI_listbase_is_empty(&workspace->tools)) {
+ BKE_workspace_tool_remove(workspace, workspace->tools.first);
+ }
- if (workspace->status_text) {
- MEM_freeN(workspace->status_text);
- workspace->status_text = NULL;
- }
+ if (workspace->status_text) {
+ MEM_freeN(workspace->status_text);
+ workspace->status_text = NULL;
+ }
}
/**
@@ -170,102 +174,101 @@ void BKE_workspace_free(WorkSpace *workspace)
*/
void BKE_workspace_remove(Main *bmain, WorkSpace *workspace)
{
- for (WorkSpaceLayout *layout = workspace->layouts.first, *layout_next; layout; layout = layout_next) {
- layout_next = layout->next;
- BKE_workspace_layout_remove(bmain, workspace, layout);
- }
- BKE_id_free(bmain, workspace);
+ for (WorkSpaceLayout *layout = workspace->layouts.first, *layout_next; layout;
+ layout = layout_next) {
+ layout_next = layout->next;
+ BKE_workspace_layout_remove(bmain, workspace, layout);
+ }
+ BKE_id_free(bmain, workspace);
}
WorkSpaceInstanceHook *BKE_workspace_instance_hook_create(const Main *bmain)
{
- WorkSpaceInstanceHook *hook = MEM_callocN(sizeof(WorkSpaceInstanceHook), __func__);
+ WorkSpaceInstanceHook *hook = MEM_callocN(sizeof(WorkSpaceInstanceHook), __func__);
- /* set an active screen-layout for each possible window/workspace combination */
- for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
- BKE_workspace_hook_layout_for_workspace_set(hook, workspace, workspace->layouts.first);
- }
+ /* set an active screen-layout for each possible window/workspace combination */
+ for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ BKE_workspace_hook_layout_for_workspace_set(hook, workspace, workspace->layouts.first);
+ }
- return hook;
+ return hook;
}
void BKE_workspace_instance_hook_free(const Main *bmain, WorkSpaceInstanceHook *hook)
{
- /* workspaces should never be freed before wm (during which we call this function) */
- BLI_assert(!BLI_listbase_is_empty(&bmain->workspaces));
+ /* workspaces should never be freed before wm (during which we call this function) */
+ BLI_assert(!BLI_listbase_is_empty(&bmain->workspaces));
- /* Free relations for this hook */
- for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
- for (WorkSpaceDataRelation *relation = workspace->hook_layout_relations.first, *relation_next;
- relation;
- relation = relation_next)
- {
- relation_next = relation->next;
- if (relation->parent == hook) {
- workspace_relation_remove(&workspace->hook_layout_relations, relation);
- }
- }
- }
+ /* Free relations for this hook */
+ for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ for (WorkSpaceDataRelation *relation = workspace->hook_layout_relations.first, *relation_next;
+ relation;
+ relation = relation_next) {
+ relation_next = relation->next;
+ if (relation->parent == hook) {
+ workspace_relation_remove(&workspace->hook_layout_relations, relation);
+ }
+ }
+ }
- MEM_freeN(hook);
+ MEM_freeN(hook);
}
/**
* Add a new layout to \a workspace for \a screen.
*/
-WorkSpaceLayout *BKE_workspace_layout_add(
- Main *bmain,
- WorkSpace *workspace,
- bScreen *screen,
- const char *name)
+WorkSpaceLayout *BKE_workspace_layout_add(Main *bmain,
+ WorkSpace *workspace,
+ bScreen *screen,
+ const char *name)
{
- WorkSpaceLayout *layout = MEM_callocN(sizeof(*layout), __func__);
+ WorkSpaceLayout *layout = MEM_callocN(sizeof(*layout), __func__);
- BLI_assert(!workspaces_is_screen_used(bmain, screen));
+ BLI_assert(!workspaces_is_screen_used(bmain, screen));
#ifndef DEBUG
- UNUSED_VARS(bmain);
+ UNUSED_VARS(bmain);
#endif
- layout->screen = screen;
- id_us_plus(&layout->screen->id);
- workspace_layout_name_set(workspace, layout, name);
- BLI_addtail(&workspace->layouts, layout);
+ layout->screen = screen;
+ id_us_plus(&layout->screen->id);
+ workspace_layout_name_set(workspace, layout, name);
+ BLI_addtail(&workspace->layouts, layout);
- return layout;
+ return layout;
}
-void BKE_workspace_layout_remove(
- Main *bmain,
- WorkSpace *workspace, WorkSpaceLayout *layout)
+void BKE_workspace_layout_remove(Main *bmain, WorkSpace *workspace, WorkSpaceLayout *layout)
{
- id_us_min(&layout->screen->id);
- BKE_id_free(bmain, layout->screen);
- BLI_freelinkN(&workspace->layouts, layout);
+ id_us_min(&layout->screen->id);
+ BKE_id_free(bmain, layout->screen);
+ BLI_freelinkN(&workspace->layouts, layout);
}
-void BKE_workspace_relations_free(
- ListBase *relation_list)
+void BKE_workspace_relations_free(ListBase *relation_list)
{
- for (WorkSpaceDataRelation *relation = relation_list->first, *relation_next; relation; relation = relation_next) {
- relation_next = relation->next;
- workspace_relation_remove(relation_list, relation);
- }
+ for (WorkSpaceDataRelation *relation = relation_list->first, *relation_next; relation;
+ relation = relation_next) {
+ relation_next = relation->next;
+ workspace_relation_remove(relation_list, relation);
+ }
}
/* -------------------------------------------------------------------- */
/* General Utils */
-WorkSpaceLayout *BKE_workspace_layout_find(
- const WorkSpace *workspace, const bScreen *screen)
+WorkSpaceLayout *BKE_workspace_layout_find(const WorkSpace *workspace, const bScreen *screen)
{
- WorkSpaceLayout *layout = workspace_layout_find_exec(workspace, screen);
- if (layout) {
- return layout;
- }
+ WorkSpaceLayout *layout = workspace_layout_find_exec(workspace, screen);
+ if (layout) {
+ return layout;
+ }
- printf("%s: Couldn't find layout in this workspace: '%s' screen: '%s'. "
- "This should not happen!\n",
- __func__, workspace->id.name + 2, screen->id.name + 2);
+ printf(
+ "%s: Couldn't find layout in this workspace: '%s' screen: '%s'. "
+ "This should not happen!\n",
+ __func__,
+ workspace->id.name + 2,
+ screen->id.name + 2);
- return NULL;
+ return NULL;
}
/**
@@ -274,27 +277,27 @@ WorkSpaceLayout *BKE_workspace_layout_find(
*
* \param r_workspace: Optionally return the workspace that contains the looked up layout (if found).
*/
-WorkSpaceLayout *BKE_workspace_layout_find_global(
- const Main *bmain, const bScreen *screen,
- WorkSpace **r_workspace)
+WorkSpaceLayout *BKE_workspace_layout_find_global(const Main *bmain,
+ const bScreen *screen,
+ WorkSpace **r_workspace)
{
- WorkSpaceLayout *layout;
+ WorkSpaceLayout *layout;
- if (r_workspace) {
- *r_workspace = NULL;
- }
+ if (r_workspace) {
+ *r_workspace = NULL;
+ }
- for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
- if ((layout = workspace_layout_find_exec(workspace, screen))) {
- if (r_workspace) {
- *r_workspace = workspace;
- }
+ for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ if ((layout = workspace_layout_find_exec(workspace, screen))) {
+ if (r_workspace) {
+ *r_workspace = workspace;
+ }
- return layout;
- }
- }
+ return layout;
+ }
+ }
- return NULL;
+ return NULL;
}
/**
@@ -305,47 +308,46 @@ WorkSpaceLayout *BKE_workspace_layout_find_global(
*
* \return the layout at which \a callback returned false.
*/
-WorkSpaceLayout *BKE_workspace_layout_iter_circular(
- const WorkSpace *workspace, WorkSpaceLayout *start,
- bool (*callback)(const WorkSpaceLayout *layout, void *arg),
- void *arg, const bool iter_backward)
-{
- WorkSpaceLayout *iter_layout;
-
- if (iter_backward) {
- LISTBASE_CIRCULAR_BACKWARD_BEGIN(&workspace->layouts, iter_layout, start)
- {
- if (!callback(iter_layout, arg)) {
- return iter_layout;
- }
- }
- LISTBASE_CIRCULAR_BACKWARD_END(&workspace->layouts, iter_layout, start);
- }
- else {
- LISTBASE_CIRCULAR_FORWARD_BEGIN(&workspace->layouts, iter_layout, start)
- {
- if (!callback(iter_layout, arg)) {
- return iter_layout;
- }
- }
- LISTBASE_CIRCULAR_FORWARD_END(&workspace->layouts, iter_layout, start);
- }
-
- return NULL;
-}
-
-void BKE_workspace_tool_remove(
- struct WorkSpace *workspace, struct bToolRef *tref)
-{
- if (tref->runtime) {
- MEM_freeN(tref->runtime);
- }
- if (tref->properties) {
- IDP_FreeProperty(tref->properties);
- MEM_freeN(tref->properties);
- }
- BLI_remlink(&workspace->tools, tref);
- MEM_freeN(tref);
+WorkSpaceLayout *BKE_workspace_layout_iter_circular(const WorkSpace *workspace,
+ WorkSpaceLayout *start,
+ bool (*callback)(const WorkSpaceLayout *layout,
+ void *arg),
+ void *arg,
+ const bool iter_backward)
+{
+ WorkSpaceLayout *iter_layout;
+
+ if (iter_backward) {
+ LISTBASE_CIRCULAR_BACKWARD_BEGIN (&workspace->layouts, iter_layout, start) {
+ if (!callback(iter_layout, arg)) {
+ return iter_layout;
+ }
+ }
+ LISTBASE_CIRCULAR_BACKWARD_END(&workspace->layouts, iter_layout, start);
+ }
+ else {
+ LISTBASE_CIRCULAR_FORWARD_BEGIN (&workspace->layouts, iter_layout, start) {
+ if (!callback(iter_layout, arg)) {
+ return iter_layout;
+ }
+ }
+ LISTBASE_CIRCULAR_FORWARD_END(&workspace->layouts, iter_layout, start);
+ }
+
+ return NULL;
+}
+
+void BKE_workspace_tool_remove(struct WorkSpace *workspace, struct bToolRef *tref)
+{
+ if (tref->runtime) {
+ MEM_freeN(tref->runtime);
+ }
+ if (tref->properties) {
+ IDP_FreeProperty(tref->properties);
+ MEM_freeN(tref->properties);
+ }
+ BLI_remlink(&workspace->tools, tref);
+ MEM_freeN(tref);
}
/* -------------------------------------------------------------------- */
@@ -353,84 +355,87 @@ void BKE_workspace_tool_remove(
WorkSpace *BKE_workspace_active_get(WorkSpaceInstanceHook *hook)
{
- return hook->active;
+ return hook->active;
}
void BKE_workspace_active_set(WorkSpaceInstanceHook *hook, WorkSpace *workspace)
{
- hook->active = workspace;
- if (workspace) {
- WorkSpaceLayout *layout = workspace_relation_get_data_matching_parent(&workspace->hook_layout_relations, hook);
- if (layout) {
- hook->act_layout = layout;
- }
- }
+ hook->active = workspace;
+ if (workspace) {
+ WorkSpaceLayout *layout = workspace_relation_get_data_matching_parent(
+ &workspace->hook_layout_relations, hook);
+ if (layout) {
+ hook->act_layout = layout;
+ }
+ }
}
WorkSpaceLayout *BKE_workspace_active_layout_get(const WorkSpaceInstanceHook *hook)
{
- return hook->act_layout;
+ return hook->act_layout;
}
void BKE_workspace_active_layout_set(WorkSpaceInstanceHook *hook, WorkSpaceLayout *layout)
{
- hook->act_layout = layout;
+ hook->act_layout = layout;
}
bScreen *BKE_workspace_active_screen_get(const WorkSpaceInstanceHook *hook)
{
- return hook->act_layout->screen;
+ return hook->act_layout->screen;
}
-void BKE_workspace_active_screen_set(WorkSpaceInstanceHook *hook, WorkSpace *workspace, bScreen *screen)
+void BKE_workspace_active_screen_set(WorkSpaceInstanceHook *hook,
+ WorkSpace *workspace,
+ bScreen *screen)
{
- /* we need to find the WorkspaceLayout that wraps this screen */
- WorkSpaceLayout *layout = BKE_workspace_layout_find(hook->active, screen);
- BKE_workspace_hook_layout_for_workspace_set(hook, workspace, layout);
+ /* we need to find the WorkspaceLayout that wraps this screen */
+ WorkSpaceLayout *layout = BKE_workspace_layout_find(hook->active, screen);
+ BKE_workspace_hook_layout_for_workspace_set(hook, workspace, layout);
}
ListBase *BKE_workspace_layouts_get(WorkSpace *workspace)
{
- return &workspace->layouts;
+ return &workspace->layouts;
}
const char *BKE_workspace_layout_name_get(const WorkSpaceLayout *layout)
{
- return layout->name;
+ return layout->name;
}
-void BKE_workspace_layout_name_set(WorkSpace *workspace, WorkSpaceLayout *layout, const char *new_name)
+void BKE_workspace_layout_name_set(WorkSpace *workspace,
+ WorkSpaceLayout *layout,
+ const char *new_name)
{
- workspace_layout_name_set(workspace, layout, new_name);
+ workspace_layout_name_set(workspace, layout, new_name);
}
bScreen *BKE_workspace_layout_screen_get(const WorkSpaceLayout *layout)
{
- return layout->screen;
+ return layout->screen;
}
void BKE_workspace_layout_screen_set(WorkSpaceLayout *layout, bScreen *screen)
{
- layout->screen = screen;
+ layout->screen = screen;
}
-WorkSpaceLayout *BKE_workspace_hook_layout_for_workspace_get(
- const WorkSpaceInstanceHook *hook, const WorkSpace *workspace)
+WorkSpaceLayout *BKE_workspace_hook_layout_for_workspace_get(const WorkSpaceInstanceHook *hook,
+ const WorkSpace *workspace)
{
- return workspace_relation_get_data_matching_parent(&workspace->hook_layout_relations, hook);
+ return workspace_relation_get_data_matching_parent(&workspace->hook_layout_relations, hook);
}
-void BKE_workspace_hook_layout_for_workspace_set(
- WorkSpaceInstanceHook *hook, WorkSpace *workspace, WorkSpaceLayout *layout)
+void BKE_workspace_hook_layout_for_workspace_set(WorkSpaceInstanceHook *hook,
+ WorkSpace *workspace,
+ WorkSpaceLayout *layout)
{
- hook->act_layout = layout;
- workspace_relation_ensure_updated(&workspace->hook_layout_relations, hook, layout);
+ hook->act_layout = layout;
+ workspace_relation_ensure_updated(&workspace->hook_layout_relations, hook, layout);
}
-bool BKE_workspace_owner_id_check(
- const WorkSpace *workspace, const char *owner_id)
+bool BKE_workspace_owner_id_check(const WorkSpace *workspace, const char *owner_id)
{
- if ((*owner_id == '\0') ||
- ((workspace->flags & WORKSPACE_USE_FILTER_BY_ORIGIN) == 0))
- {
- return true;
- }
- else {
- /* we could use hash lookup, for now this list is highly under < ~16 items. */
- return BLI_findstring(&workspace->owner_ids, owner_id, offsetof(wmOwnerID, name)) != NULL;
- }
+ if ((*owner_id == '\0') || ((workspace->flags & WORKSPACE_USE_FILTER_BY_ORIGIN) == 0)) {
+ return true;
+ }
+ else {
+ /* we could use hash lookup, for now this list is highly under < ~16 items. */
+ return BLI_findstring(&workspace->owner_ids, owner_id, offsetof(wmOwnerID, name)) != NULL;
+ }
}
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
index 2118f9adda9..8dcd31a13c9 100644
--- a/source/blender/blenkernel/intern/world.c
+++ b/source/blender/blenkernel/intern/world.c
@@ -21,7 +21,6 @@
* \ingroup bke
*/
-
#include <string.h>
#include <stdlib.h>
#include <math.h>
@@ -51,48 +50,48 @@
/** Free (or release) any data used by this world (does not free the world itself). */
void BKE_world_free(World *wrld)
{
- BKE_animdata_free((ID *)wrld, false);
+ BKE_animdata_free((ID *)wrld, false);
- DRW_drawdata_free((ID *)wrld);
+ DRW_drawdata_free((ID *)wrld);
- /* is no lib link block, but world extension */
- if (wrld->nodetree) {
- ntreeFreeNestedTree(wrld->nodetree);
- MEM_freeN(wrld->nodetree);
- wrld->nodetree = NULL;
- }
+ /* is no lib link block, but world extension */
+ if (wrld->nodetree) {
+ ntreeFreeNestedTree(wrld->nodetree);
+ MEM_freeN(wrld->nodetree);
+ wrld->nodetree = NULL;
+ }
- GPU_material_free(&wrld->gpumaterial);
+ GPU_material_free(&wrld->gpumaterial);
- BKE_icon_id_delete((struct ID *)wrld);
- BKE_previewimg_free(&wrld->preview);
+ BKE_icon_id_delete((struct ID *)wrld);
+ BKE_previewimg_free(&wrld->preview);
}
void BKE_world_init(World *wrld)
{
- BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(wrld, id));
+ BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(wrld, id));
- wrld->horr = 0.05f;
- wrld->horg = 0.05f;
- wrld->horb = 0.05f;
+ wrld->horr = 0.05f;
+ wrld->horg = 0.05f;
+ wrld->horb = 0.05f;
- wrld->aodist = 10.0f;
- wrld->aoenergy = 1.0f;
+ wrld->aodist = 10.0f;
+ wrld->aoenergy = 1.0f;
- wrld->preview = NULL;
- wrld->miststa = 5.0f;
- wrld->mistdist = 25.0f;
+ wrld->preview = NULL;
+ wrld->miststa = 5.0f;
+ wrld->mistdist = 25.0f;
}
World *BKE_world_add(Main *bmain, const char *name)
{
- World *wrld;
+ World *wrld;
- wrld = BKE_libblock_alloc(bmain, ID_WO, name, 0);
+ wrld = BKE_libblock_alloc(bmain, ID_WO, name, 0);
- BKE_world_init(wrld);
+ BKE_world_init(wrld);
- return wrld;
+ return wrld;
}
/**
@@ -105,66 +104,66 @@ World *BKE_world_add(Main *bmain, const char *name)
*/
void BKE_world_copy_data(Main *bmain, World *wrld_dst, const World *wrld_src, const int flag)
{
- if (wrld_src->nodetree) {
- /* Note: nodetree is *not* in bmain, however this specific case is handled at lower level
- * (see BKE_libblock_copy_ex()). */
- BKE_id_copy_ex(bmain, (ID *)wrld_src->nodetree, (ID **)&wrld_dst->nodetree, flag);
- }
-
- BLI_listbase_clear(&wrld_dst->gpumaterial);
- BLI_listbase_clear((ListBase *)&wrld_dst->drawdata);
-
- if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
- BKE_previewimg_id_copy(&wrld_dst->id, &wrld_src->id);
- }
- else {
- wrld_dst->preview = NULL;
- }
+ if (wrld_src->nodetree) {
+ /* Note: nodetree is *not* in bmain, however this specific case is handled at lower level
+ * (see BKE_libblock_copy_ex()). */
+ BKE_id_copy_ex(bmain, (ID *)wrld_src->nodetree, (ID **)&wrld_dst->nodetree, flag);
+ }
+
+ BLI_listbase_clear(&wrld_dst->gpumaterial);
+ BLI_listbase_clear((ListBase *)&wrld_dst->drawdata);
+
+ if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
+ BKE_previewimg_id_copy(&wrld_dst->id, &wrld_src->id);
+ }
+ else {
+ wrld_dst->preview = NULL;
+ }
}
World *BKE_world_copy(Main *bmain, const World *wrld)
{
- World *wrld_copy;
- BKE_id_copy(bmain, &wrld->id, (ID **)&wrld_copy);
- return wrld_copy;
+ World *wrld_copy;
+ BKE_id_copy(bmain, &wrld->id, (ID **)&wrld_copy);
+ return wrld_copy;
}
World *BKE_world_localize(World *wrld)
{
- /* TODO(bastien): Replace with something like:
- *
- * World *wrld_copy;
- * BKE_id_copy_ex(bmain, &wrld->id, (ID **)&wrld_copy,
- * LIB_ID_COPY_NO_MAIN | LIB_ID_COPY_NO_PREVIEW | LIB_ID_COPY_NO_USER_REFCOUNT,
- * false);
- * return wrld_copy;
- *
- * NOTE: Only possible once nested node trees are fully converted to that too. */
+ /* TODO(bastien): Replace with something like:
+ *
+ * World *wrld_copy;
+ * BKE_id_copy_ex(bmain, &wrld->id, (ID **)&wrld_copy,
+ * LIB_ID_COPY_NO_MAIN | LIB_ID_COPY_NO_PREVIEW | LIB_ID_COPY_NO_USER_REFCOUNT,
+ * false);
+ * return wrld_copy;
+ *
+ * NOTE: Only possible once nested node trees are fully converted to that too. */
- World *wrldn;
+ World *wrldn;
- wrldn = BKE_libblock_copy_for_localize(&wrld->id);
+ wrldn = BKE_libblock_copy_for_localize(&wrld->id);
- if (wrld->nodetree)
- wrldn->nodetree = ntreeLocalize(wrld->nodetree);
+ if (wrld->nodetree)
+ wrldn->nodetree = ntreeLocalize(wrld->nodetree);
- wrldn->preview = NULL;
+ wrldn->preview = NULL;
- BLI_listbase_clear(&wrldn->gpumaterial);
- BLI_listbase_clear((ListBase *)&wrldn->drawdata);
+ BLI_listbase_clear(&wrldn->gpumaterial);
+ BLI_listbase_clear((ListBase *)&wrldn->drawdata);
- wrldn->id.tag |= LIB_TAG_LOCALIZED;
+ wrldn->id.tag |= LIB_TAG_LOCALIZED;
- return wrldn;
+ return wrldn;
}
void BKE_world_make_local(Main *bmain, World *wrld, const bool lib_local)
{
- BKE_id_make_local_generic(bmain, &wrld->id, true, lib_local);
+ BKE_id_make_local_generic(bmain, &wrld->id, true, lib_local);
}
void BKE_world_eval(struct Depsgraph *depsgraph, World *world)
{
- DEG_debug_print_eval(depsgraph, __func__, world->id.name, world);
- GPU_material_free(&world->gpumaterial);
+ DEG_debug_print_eval(depsgraph, __func__, world->id.name, world);
+ GPU_material_free(&world->gpumaterial);
}
diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c
index f46ca79bef7..9f76f1022d1 100644
--- a/source/blender/blenkernel/intern/writeavi.c
+++ b/source/blender/blenkernel/intern/writeavi.c
@@ -23,7 +23,6 @@
* \ingroup bke
*/
-
#include <string.h>
#include "MEM_guardedalloc.h"
@@ -43,35 +42,70 @@
/* ********************** general blender movie support ***************************** */
-static int start_stub(void *UNUSED(context_v), Scene *UNUSED(scene), RenderData *UNUSED(rd), int UNUSED(rectx), int UNUSED(recty),
- ReportList *UNUSED(reports), bool UNUSED(preview), const char *UNUSED(suffix))
-{ return 0; }
+static int start_stub(void *UNUSED(context_v),
+ Scene *UNUSED(scene),
+ RenderData *UNUSED(rd),
+ int UNUSED(rectx),
+ int UNUSED(recty),
+ ReportList *UNUSED(reports),
+ bool UNUSED(preview),
+ const char *UNUSED(suffix))
+{
+ return 0;
+}
static void end_stub(void *UNUSED(context_v))
-{}
+{
+}
-static int append_stub(void *UNUSED(context_v), RenderData *UNUSED(rd), int UNUSED(start_frame), int UNUSED(frame), int *UNUSED(pixels),
- int UNUSED(rectx), int UNUSED(recty), const char *UNUSED(suffix), ReportList *UNUSED(reports))
-{ return 0; }
+static int append_stub(void *UNUSED(context_v),
+ RenderData *UNUSED(rd),
+ int UNUSED(start_frame),
+ int UNUSED(frame),
+ int *UNUSED(pixels),
+ int UNUSED(rectx),
+ int UNUSED(recty),
+ const char *UNUSED(suffix),
+ ReportList *UNUSED(reports))
+{
+ return 0;
+}
static void *context_create_stub(void)
-{ return NULL; }
+{
+ return NULL;
+}
static void context_free_stub(void *UNUSED(context_v))
-{}
+{
+}
#ifdef WITH_AVI
# include "AVI_avi.h"
/* callbacks */
-static int start_avi(void *context_v, Scene *scene, RenderData *rd, int rectx, int recty, ReportList *reports, bool preview, const char *suffix);
+static int start_avi(void *context_v,
+ Scene *scene,
+ RenderData *rd,
+ int rectx,
+ int recty,
+ ReportList *reports,
+ bool preview,
+ const char *suffix);
static void end_avi(void *context_v);
-static int append_avi(void *context_v, RenderData *rd, int start_frame, int frame, int *pixels,
- int rectx, int recty, const char *suffix, ReportList *reports);
+static int append_avi(void *context_v,
+ RenderData *rd,
+ int start_frame,
+ int frame,
+ int *pixels,
+ int rectx,
+ int recty,
+ const char *suffix,
+ ReportList *reports);
static void filepath_avi(char *string, RenderData *rd, bool preview, const char *suffix);
static void *context_create_avi(void);
static void context_free_avi(void *context_v);
-#endif /* WITH_AVI */
+#endif /* WITH_AVI */
#ifdef WITH_FFMPEG
# include "BKE_writeffmpeg.h"
@@ -79,192 +113,212 @@ static void context_free_avi(void *context_v);
bMovieHandle *BKE_movie_handle_get(const char imtype)
{
- static bMovieHandle mh = {NULL};
- /* stub callbacks in case none of the movie formats is supported */
- mh.start_movie = start_stub;
- mh.append_movie = append_stub;
- mh.end_movie = end_stub;
- mh.get_next_frame = NULL;
- mh.get_movie_path = NULL;
- mh.context_create = context_create_stub;
- mh.context_free = context_free_stub;
-
- /* set the default handle, as builtin */
+ static bMovieHandle mh = {NULL};
+ /* stub callbacks in case none of the movie formats is supported */
+ mh.start_movie = start_stub;
+ mh.append_movie = append_stub;
+ mh.end_movie = end_stub;
+ mh.get_next_frame = NULL;
+ mh.get_movie_path = NULL;
+ mh.context_create = context_create_stub;
+ mh.context_free = context_free_stub;
+
+ /* set the default handle, as builtin */
#ifdef WITH_AVI
- mh.start_movie = start_avi;
- mh.append_movie = append_avi;
- mh.end_movie = end_avi;
- mh.get_movie_path = filepath_avi;
- mh.context_create = context_create_avi;
- mh.context_free = context_free_avi;
+ mh.start_movie = start_avi;
+ mh.append_movie = append_avi;
+ mh.end_movie = end_avi;
+ mh.get_movie_path = filepath_avi;
+ mh.context_create = context_create_avi;
+ mh.context_free = context_free_avi;
#endif
- /* do the platform specific handles */
+ /* do the platform specific handles */
#ifdef WITH_FFMPEG
- if (ELEM(imtype, R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_XVID, R_IMF_IMTYPE_THEORA)) {
- mh.start_movie = BKE_ffmpeg_start;
- mh.append_movie = BKE_ffmpeg_append;
- mh.end_movie = BKE_ffmpeg_end;
- mh.get_movie_path = BKE_ffmpeg_filepath_get;
- mh.context_create = BKE_ffmpeg_context_create;
- mh.context_free = BKE_ffmpeg_context_free;
- }
+ if (ELEM(imtype,
+ R_IMF_IMTYPE_FFMPEG,
+ R_IMF_IMTYPE_H264,
+ R_IMF_IMTYPE_XVID,
+ R_IMF_IMTYPE_THEORA)) {
+ mh.start_movie = BKE_ffmpeg_start;
+ mh.append_movie = BKE_ffmpeg_append;
+ mh.end_movie = BKE_ffmpeg_end;
+ mh.get_movie_path = BKE_ffmpeg_filepath_get;
+ mh.context_create = BKE_ffmpeg_context_create;
+ mh.context_free = BKE_ffmpeg_context_free;
+ }
#endif
- /* in case all above are disabled */
- (void)imtype;
+ /* in case all above are disabled */
+ (void)imtype;
- return (mh.append_movie != append_stub) ? &mh : NULL;
+ return (mh.append_movie != append_stub) ? &mh : NULL;
}
/* ****************************************************************** */
-
#ifdef WITH_AVI
static void filepath_avi(char *string, RenderData *rd, bool preview, const char *suffix)
{
- int sfra, efra;
-
- if (string == NULL) return;
-
- if (preview) {
- sfra = rd->psfra;
- efra = rd->pefra;
- }
- else {
- sfra = rd->sfra;
- efra = rd->efra;
- }
-
- strcpy(string, rd->pic);
- BLI_path_abs(string, BKE_main_blendfile_path_from_global());
-
- BLI_make_existing_file(string);
-
- if (rd->scemode & R_EXTENSION) {
- if (!BLI_path_extension_check(string, ".avi")) {
- BLI_path_frame_range(string, sfra, efra, 4);
- strcat(string, ".avi");
- }
- }
- else {
- if (BLI_path_frame_check_chars(string)) {
- BLI_path_frame_range(string, sfra, efra, 4);
- }
- }
-
- BLI_path_suffix(string, FILE_MAX, suffix, "");
+ int sfra, efra;
+
+ if (string == NULL)
+ return;
+
+ if (preview) {
+ sfra = rd->psfra;
+ efra = rd->pefra;
+ }
+ else {
+ sfra = rd->sfra;
+ efra = rd->efra;
+ }
+
+ strcpy(string, rd->pic);
+ BLI_path_abs(string, BKE_main_blendfile_path_from_global());
+
+ BLI_make_existing_file(string);
+
+ if (rd->scemode & R_EXTENSION) {
+ if (!BLI_path_extension_check(string, ".avi")) {
+ BLI_path_frame_range(string, sfra, efra, 4);
+ strcat(string, ".avi");
+ }
+ }
+ else {
+ if (BLI_path_frame_check_chars(string)) {
+ BLI_path_frame_range(string, sfra, efra, 4);
+ }
+ }
+
+ BLI_path_suffix(string, FILE_MAX, suffix, "");
}
-static int start_avi(void *context_v, Scene *UNUSED(scene), RenderData *rd, int rectx, int recty,
- ReportList *reports, bool preview, const char *suffix)
+static int start_avi(void *context_v,
+ Scene *UNUSED(scene),
+ RenderData *rd,
+ int rectx,
+ int recty,
+ ReportList *reports,
+ bool preview,
+ const char *suffix)
{
- int x, y;
- char name[256];
- AviFormat format;
- int quality;
- double framerate;
- AviMovie *avi = context_v;
+ int x, y;
+ char name[256];
+ AviFormat format;
+ int quality;
+ double framerate;
+ AviMovie *avi = context_v;
- filepath_avi(name, rd, preview, suffix);
+ filepath_avi(name, rd, preview, suffix);
- x = rectx;
- y = recty;
+ x = rectx;
+ y = recty;
- quality = rd->im_format.quality;
- framerate = (double) rd->frs_sec / (double) rd->frs_sec_base;
+ quality = rd->im_format.quality;
+ framerate = (double)rd->frs_sec / (double)rd->frs_sec_base;
- if (rd->im_format.imtype != R_IMF_IMTYPE_AVIJPEG) format = AVI_FORMAT_AVI_RGB;
- else format = AVI_FORMAT_MJPEG;
+ if (rd->im_format.imtype != R_IMF_IMTYPE_AVIJPEG)
+ format = AVI_FORMAT_AVI_RGB;
+ else
+ format = AVI_FORMAT_MJPEG;
- if (AVI_open_compress(name, avi, 1, format) != AVI_ERROR_NONE) {
- BKE_report(reports, RPT_ERROR, "Cannot open or start AVI movie file");
- return 0;
- }
+ if (AVI_open_compress(name, avi, 1, format) != AVI_ERROR_NONE) {
+ BKE_report(reports, RPT_ERROR, "Cannot open or start AVI movie file");
+ return 0;
+ }
- AVI_set_compress_option(avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_WIDTH, &x);
- AVI_set_compress_option(avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_HEIGHT, &y);
- AVI_set_compress_option(avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_QUALITY, &quality);
- AVI_set_compress_option(avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_FRAMERATE, &framerate);
+ AVI_set_compress_option(avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_WIDTH, &x);
+ AVI_set_compress_option(avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_HEIGHT, &y);
+ AVI_set_compress_option(avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_QUALITY, &quality);
+ AVI_set_compress_option(avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_FRAMERATE, &framerate);
- avi->interlace = 0;
- avi->odd_fields = 0;
+ avi->interlace = 0;
+ avi->odd_fields = 0;
- printf("Created avi: %s\n", name);
- return 1;
+ printf("Created avi: %s\n", name);
+ return 1;
}
-static int append_avi(void *context_v, RenderData *UNUSED(rd), int start_frame, int frame, int *pixels,
- int rectx, int recty, const char *UNUSED(suffix), ReportList *UNUSED(reports))
+static int append_avi(void *context_v,
+ RenderData *UNUSED(rd),
+ int start_frame,
+ int frame,
+ int *pixels,
+ int rectx,
+ int recty,
+ const char *UNUSED(suffix),
+ ReportList *UNUSED(reports))
{
- unsigned int *rt1, *rt2, *rectot;
- int x, y;
- char *cp, rt;
- AviMovie *avi = context_v;
-
- if (avi == NULL)
- return 0;
-
- /* note that libavi free's the buffer... stupid interface - zr */
- rectot = MEM_mallocN(rectx * recty * sizeof(int), "rectot");
- rt1 = rectot;
- rt2 = (unsigned int *)pixels + (recty - 1) * rectx;
- /* flip y and convert to abgr */
- for (y = 0; y < recty; y++, rt1 += rectx, rt2 -= rectx) {
- memcpy(rt1, rt2, rectx * sizeof(int));
-
- cp = (char *)rt1;
- for (x = rectx; x > 0; x--) {
- rt = cp[0];
- cp[0] = cp[3];
- cp[3] = rt;
- rt = cp[1];
- cp[1] = cp[2];
- cp[2] = rt;
- cp += 4;
- }
- }
-
- AVI_write_frame(avi, (frame - start_frame), AVI_FORMAT_RGB32, rectot, rectx * recty * 4);
-// printf("added frame %3d (frame %3d in avi): ", frame, frame-start_frame);
-
- return 1;
+ unsigned int *rt1, *rt2, *rectot;
+ int x, y;
+ char *cp, rt;
+ AviMovie *avi = context_v;
+
+ if (avi == NULL)
+ return 0;
+
+ /* note that libavi free's the buffer... stupid interface - zr */
+ rectot = MEM_mallocN(rectx * recty * sizeof(int), "rectot");
+ rt1 = rectot;
+ rt2 = (unsigned int *)pixels + (recty - 1) * rectx;
+ /* flip y and convert to abgr */
+ for (y = 0; y < recty; y++, rt1 += rectx, rt2 -= rectx) {
+ memcpy(rt1, rt2, rectx * sizeof(int));
+
+ cp = (char *)rt1;
+ for (x = rectx; x > 0; x--) {
+ rt = cp[0];
+ cp[0] = cp[3];
+ cp[3] = rt;
+ rt = cp[1];
+ cp[1] = cp[2];
+ cp[2] = rt;
+ cp += 4;
+ }
+ }
+
+ AVI_write_frame(avi, (frame - start_frame), AVI_FORMAT_RGB32, rectot, rectx * recty * 4);
+ // printf("added frame %3d (frame %3d in avi): ", frame, frame-start_frame);
+
+ return 1;
}
static void end_avi(void *context_v)
{
- AviMovie *avi = context_v;
+ AviMovie *avi = context_v;
- if (avi == NULL) return;
+ if (avi == NULL)
+ return;
- AVI_close_compress(avi);
+ AVI_close_compress(avi);
}
static void *context_create_avi(void)
{
- AviMovie *avi = MEM_mallocN(sizeof(AviMovie), "avimovie");
- return avi;
+ AviMovie *avi = MEM_mallocN(sizeof(AviMovie), "avimovie");
+ return avi;
}
static void context_free_avi(void *context_v)
{
- AviMovie *avi = context_v;
- if (avi) {
- MEM_freeN(avi);
- }
+ AviMovie *avi = context_v;
+ if (avi) {
+ MEM_freeN(avi);
+ }
}
-#endif /* WITH_AVI */
+#endif /* WITH_AVI */
/* similar to BKE_image_path_from_imformat() */
void BKE_movie_filepath_get(char *string, RenderData *rd, bool preview, const char *suffix)
{
- bMovieHandle *mh = BKE_movie_handle_get(rd->im_format.imtype);
- if (mh && mh->get_movie_path) {
- mh->get_movie_path(string, rd, preview, suffix);
- }
- else {
- string[0] = '\0';
- }
+ bMovieHandle *mh = BKE_movie_handle_get(rd->im_format.imtype);
+ if (mh && mh->get_movie_path) {
+ mh->get_movie_path(string, rd, preview, suffix);
+ }
+ else {
+ string[0] = '\0';
+ }
}
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
index 982ee3ec01b..6bf8186e02f 100644
--- a/source/blender/blenkernel/intern/writeffmpeg.c
+++ b/source/blender/blenkernel/intern/writeffmpeg.c
@@ -20,1030 +20,1089 @@
*/
#ifdef WITH_FFMPEG
-#include <string.h>
-#include <stdio.h>
+# include <string.h>
+# include <stdio.h>
-#include <stdlib.h>
+# include <stdlib.h>
-#include <libavformat/avformat.h>
-#include <libavcodec/avcodec.h>
-#include <libavutil/rational.h>
-#include <libavutil/samplefmt.h>
-#include <libswscale/swscale.h>
+# include <libavformat/avformat.h>
+# include <libavcodec/avcodec.h>
+# include <libavutil/rational.h>
+# include <libavutil/samplefmt.h>
+# include <libswscale/swscale.h>
-#include "MEM_guardedalloc.h"
+# include "MEM_guardedalloc.h"
-#include "DNA_scene_types.h"
+# include "DNA_scene_types.h"
-#include "BLI_blenlib.h"
+# include "BLI_blenlib.h"
-#ifdef WITH_AUDASPACE
-# include <AUD_Device.h>
-# include <AUD_Special.h>
-#endif
+# ifdef WITH_AUDASPACE
+# include <AUD_Device.h>
+# include <AUD_Special.h>
+# endif
-#include "BLI_utildefines.h"
+# include "BLI_utildefines.h"
-#include "BKE_global.h"
-#include "BKE_idprop.h"
-#include "BKE_image.h"
-#include "BKE_library.h"
-#include "BKE_main.h"
-#include "BKE_report.h"
-#include "BKE_sound.h"
-#include "BKE_writeffmpeg.h"
+# include "BKE_global.h"
+# include "BKE_idprop.h"
+# include "BKE_image.h"
+# include "BKE_library.h"
+# include "BKE_main.h"
+# include "BKE_report.h"
+# include "BKE_sound.h"
+# include "BKE_writeffmpeg.h"
-#include "IMB_imbuf.h"
+# include "IMB_imbuf.h"
-#include "ffmpeg_compat.h"
+# include "ffmpeg_compat.h"
struct StampData;
typedef struct FFMpegContext {
- int ffmpeg_type;
- int ffmpeg_codec;
- int ffmpeg_audio_codec;
- int ffmpeg_video_bitrate;
- int ffmpeg_audio_bitrate;
- int ffmpeg_gop_size;
- int ffmpeg_max_b_frames;
- int ffmpeg_autosplit;
- int ffmpeg_autosplit_count;
- bool ffmpeg_preview;
-
- int ffmpeg_crf; /* set to 0 to not use CRF mode; we have another flag for lossless anyway. */
- int ffmpeg_preset; /* see eFFMpegPreset */
-
- AVFormatContext *outfile;
- AVStream *video_stream;
- AVStream *audio_stream;
- AVFrame *current_frame;
- struct SwsContext *img_convert_ctx;
-
- uint8_t *audio_input_buffer;
- uint8_t *audio_deinterleave_buffer;
- int audio_input_samples;
-#ifndef FFMPEG_HAVE_ENCODE_AUDIO2
- uint8_t *audio_output_buffer;
- int audio_outbuf_size;
-#endif
- double audio_time;
- bool audio_deinterleave;
- int audio_sample_size;
-
- struct StampData *stamp_data;
-
-#ifdef WITH_AUDASPACE
- AUD_Device *audio_mixdown_device;
-#endif
+ int ffmpeg_type;
+ int ffmpeg_codec;
+ int ffmpeg_audio_codec;
+ int ffmpeg_video_bitrate;
+ int ffmpeg_audio_bitrate;
+ int ffmpeg_gop_size;
+ int ffmpeg_max_b_frames;
+ int ffmpeg_autosplit;
+ int ffmpeg_autosplit_count;
+ bool ffmpeg_preview;
+
+ int ffmpeg_crf; /* set to 0 to not use CRF mode; we have another flag for lossless anyway. */
+ int ffmpeg_preset; /* see eFFMpegPreset */
+
+ AVFormatContext *outfile;
+ AVStream *video_stream;
+ AVStream *audio_stream;
+ AVFrame *current_frame;
+ struct SwsContext *img_convert_ctx;
+
+ uint8_t *audio_input_buffer;
+ uint8_t *audio_deinterleave_buffer;
+ int audio_input_samples;
+# ifndef FFMPEG_HAVE_ENCODE_AUDIO2
+ uint8_t *audio_output_buffer;
+ int audio_outbuf_size;
+# endif
+ double audio_time;
+ bool audio_deinterleave;
+ int audio_sample_size;
+
+ struct StampData *stamp_data;
+
+# ifdef WITH_AUDASPACE
+ AUD_Device *audio_mixdown_device;
+# endif
} FFMpegContext;
-#define FFMPEG_AUTOSPLIT_SIZE 2000000000
+# define FFMPEG_AUTOSPLIT_SIZE 2000000000
-#define PRINT if (G.debug & G_DEBUG_FFMPEG) printf
+# define PRINT \
+ if (G.debug & G_DEBUG_FFMPEG) \
+ printf
static void ffmpeg_dict_set_int(AVDictionary **dict, const char *key, int value);
static void ffmpeg_dict_set_float(AVDictionary **dict, const char *key, float value);
static void ffmpeg_set_expert_options(RenderData *rd);
-static void ffmpeg_filepath_get(FFMpegContext *context, char *string, struct RenderData *rd, bool preview, const char *suffix);
+static void ffmpeg_filepath_get(
+ FFMpegContext *context, char *string, struct RenderData *rd, bool preview, const char *suffix);
/* Delete a picture buffer */
static void delete_picture(AVFrame *f)
{
- if (f) {
- if (f->data[0]) MEM_freeN(f->data[0]);
- av_free(f);
- }
+ if (f) {
+ if (f->data[0])
+ MEM_freeN(f->data[0]);
+ av_free(f);
+ }
}
static int request_float_audio_buffer(int codec_id)
{
- /* If any of these codecs, we prefer the float sample format (if supported) */
- return codec_id == AV_CODEC_ID_AAC || codec_id == AV_CODEC_ID_AC3 || codec_id == AV_CODEC_ID_VORBIS;
+ /* If any of these codecs, we prefer the float sample format (if supported) */
+ return codec_id == AV_CODEC_ID_AAC || codec_id == AV_CODEC_ID_AC3 ||
+ codec_id == AV_CODEC_ID_VORBIS;
}
-#ifdef WITH_AUDASPACE
+# ifdef WITH_AUDASPACE
static int write_audio_frame(FFMpegContext *context)
{
- AVCodecContext *c = NULL;
- AVPacket pkt;
- AVFrame *frame = NULL;
- int got_output = 0;
-
- c = context->audio_stream->codec;
-
- av_init_packet(&pkt);
- pkt.size = 0;
- pkt.data = NULL;
-
- AUD_Device_read(context->audio_mixdown_device, context->audio_input_buffer, context->audio_input_samples);
- context->audio_time += (double) context->audio_input_samples / (double) c->sample_rate;
-
-#ifdef FFMPEG_HAVE_ENCODE_AUDIO2
- frame = av_frame_alloc();
- av_frame_unref(frame);
- frame->pts = context->audio_time / av_q2d(c->time_base);
- frame->nb_samples = context->audio_input_samples;
- frame->format = c->sample_fmt;
-#ifdef FFMPEG_HAVE_FRAME_CHANNEL_LAYOUT
- frame->channel_layout = c->channel_layout;
-#endif
-
- if (context->audio_deinterleave) {
- int channel, i;
- uint8_t *temp;
-
- for (channel = 0; channel < c->channels; channel++) {
- for (i = 0; i < frame->nb_samples; i++) {
- memcpy(context->audio_deinterleave_buffer + (i + channel * frame->nb_samples) * context->audio_sample_size,
- context->audio_input_buffer + (c->channels * i + channel) * context->audio_sample_size, context->audio_sample_size);
- }
- }
-
- temp = context->audio_deinterleave_buffer;
- context->audio_deinterleave_buffer = context->audio_input_buffer;
- context->audio_input_buffer = temp;
- }
-
- avcodec_fill_audio_frame(frame, c->channels, c->sample_fmt, context->audio_input_buffer,
- context->audio_input_samples * c->channels * context->audio_sample_size, 1);
-
- if (avcodec_encode_audio2(c, &pkt, frame, &got_output) < 0) {
- // XXX error("Error writing audio packet");
- return -1;
- }
-
- if (!got_output) {
- av_frame_free(&frame);
- return 0;
- }
-#else
- pkt.size = avcodec_encode_audio(c, context->audio_output_buffer, context->audio_outbuf_size, (short *) context->audio_input_buffer);
-
- if (pkt.size < 0) {
- // XXX error("Error writing audio packet");
- return -1;
- }
-
- pkt.data = context->audio_output_buffer;
- got_output = 1;
-#endif
-
- if (got_output) {
- if (pkt.pts != AV_NOPTS_VALUE)
- pkt.pts = av_rescale_q(pkt.pts, c->time_base, context->audio_stream->time_base);
- if (pkt.dts != AV_NOPTS_VALUE)
- pkt.dts = av_rescale_q(pkt.dts, c->time_base, context->audio_stream->time_base);
- if (pkt.duration > 0)
- pkt.duration = av_rescale_q(pkt.duration, c->time_base, context->audio_stream->time_base);
-
- pkt.stream_index = context->audio_stream->index;
-
- pkt.flags |= AV_PKT_FLAG_KEY;
-
- if (av_interleaved_write_frame(context->outfile, &pkt) != 0) {
- fprintf(stderr, "Error writing audio packet!\n");
- if (frame)
- av_frame_free(&frame);
- return -1;
- }
-
- av_free_packet(&pkt);
- }
-
- if (frame)
- av_frame_free(&frame);
-
- return 0;
+ AVCodecContext *c = NULL;
+ AVPacket pkt;
+ AVFrame *frame = NULL;
+ int got_output = 0;
+
+ c = context->audio_stream->codec;
+
+ av_init_packet(&pkt);
+ pkt.size = 0;
+ pkt.data = NULL;
+
+ AUD_Device_read(
+ context->audio_mixdown_device, context->audio_input_buffer, context->audio_input_samples);
+ context->audio_time += (double)context->audio_input_samples / (double)c->sample_rate;
+
+# ifdef FFMPEG_HAVE_ENCODE_AUDIO2
+ frame = av_frame_alloc();
+ av_frame_unref(frame);
+ frame->pts = context->audio_time / av_q2d(c->time_base);
+ frame->nb_samples = context->audio_input_samples;
+ frame->format = c->sample_fmt;
+# ifdef FFMPEG_HAVE_FRAME_CHANNEL_LAYOUT
+ frame->channel_layout = c->channel_layout;
+# endif
+
+ if (context->audio_deinterleave) {
+ int channel, i;
+ uint8_t *temp;
+
+ for (channel = 0; channel < c->channels; channel++) {
+ for (i = 0; i < frame->nb_samples; i++) {
+ memcpy(context->audio_deinterleave_buffer +
+ (i + channel * frame->nb_samples) * context->audio_sample_size,
+ context->audio_input_buffer +
+ (c->channels * i + channel) * context->audio_sample_size,
+ context->audio_sample_size);
+ }
+ }
+
+ temp = context->audio_deinterleave_buffer;
+ context->audio_deinterleave_buffer = context->audio_input_buffer;
+ context->audio_input_buffer = temp;
+ }
+
+ avcodec_fill_audio_frame(frame,
+ c->channels,
+ c->sample_fmt,
+ context->audio_input_buffer,
+ context->audio_input_samples * c->channels * context->audio_sample_size,
+ 1);
+
+ if (avcodec_encode_audio2(c, &pkt, frame, &got_output) < 0) {
+ // XXX error("Error writing audio packet");
+ return -1;
+ }
+
+ if (!got_output) {
+ av_frame_free(&frame);
+ return 0;
+ }
+# else
+ pkt.size = avcodec_encode_audio(c,
+ context->audio_output_buffer,
+ context->audio_outbuf_size,
+ (short *)context->audio_input_buffer);
+
+ if (pkt.size < 0) {
+ // XXX error("Error writing audio packet");
+ return -1;
+ }
+
+ pkt.data = context->audio_output_buffer;
+ got_output = 1;
+# endif
+
+ if (got_output) {
+ if (pkt.pts != AV_NOPTS_VALUE)
+ pkt.pts = av_rescale_q(pkt.pts, c->time_base, context->audio_stream->time_base);
+ if (pkt.dts != AV_NOPTS_VALUE)
+ pkt.dts = av_rescale_q(pkt.dts, c->time_base, context->audio_stream->time_base);
+ if (pkt.duration > 0)
+ pkt.duration = av_rescale_q(pkt.duration, c->time_base, context->audio_stream->time_base);
+
+ pkt.stream_index = context->audio_stream->index;
+
+ pkt.flags |= AV_PKT_FLAG_KEY;
+
+ if (av_interleaved_write_frame(context->outfile, &pkt) != 0) {
+ fprintf(stderr, "Error writing audio packet!\n");
+ if (frame)
+ av_frame_free(&frame);
+ return -1;
+ }
+
+ av_free_packet(&pkt);
+ }
+
+ if (frame)
+ av_frame_free(&frame);
+
+ return 0;
}
-#endif // #ifdef WITH_AUDASPACE
+# endif // #ifdef WITH_AUDASPACE
/* Allocate a temporary frame */
static AVFrame *alloc_picture(int pix_fmt, int width, int height)
{
- AVFrame *f;
- uint8_t *buf;
- int size;
-
- /* allocate space for the struct */
- f = av_frame_alloc();
- if (!f) return NULL;
- size = avpicture_get_size(pix_fmt, width, height);
- /* allocate the actual picture buffer */
- buf = MEM_mallocN(size, "AVFrame buffer");
- if (!buf) {
- free(f);
- return NULL;
- }
- avpicture_fill((AVPicture *)f, buf, pix_fmt, width, height);
- return f;
+ AVFrame *f;
+ uint8_t *buf;
+ int size;
+
+ /* allocate space for the struct */
+ f = av_frame_alloc();
+ if (!f)
+ return NULL;
+ size = avpicture_get_size(pix_fmt, width, height);
+ /* allocate the actual picture buffer */
+ buf = MEM_mallocN(size, "AVFrame buffer");
+ if (!buf) {
+ free(f);
+ return NULL;
+ }
+ avpicture_fill((AVPicture *)f, buf, pix_fmt, width, height);
+ return f;
}
/* Get the correct file extensions for the requested format,
* first is always desired guess_format parameter */
static const char **get_file_extensions(int format)
{
- switch (format) {
- case FFMPEG_DV:
- {
- static const char *rv[] = { ".dv", NULL };
- return rv;
- }
- case FFMPEG_MPEG1:
- {
- static const char *rv[] = { ".mpg", ".mpeg", NULL };
- return rv;
- }
- case FFMPEG_MPEG2:
- {
- static const char *rv[] = { ".dvd", ".vob", ".mpg", ".mpeg", NULL };
- return rv;
- }
- case FFMPEG_MPEG4:
- {
- static const char *rv[] = { ".mp4", ".mpg", ".mpeg", NULL };
- return rv;
- }
- case FFMPEG_AVI:
- {
- static const char *rv[] = { ".avi", NULL };
- return rv;
- }
- case FFMPEG_MOV:
- {
- static const char *rv[] = { ".mov", NULL };
- return rv;
- }
- case FFMPEG_H264:
- {
- /* FIXME: avi for now... */
- static const char *rv[] = { ".avi", NULL };
- return rv;
- }
-
- case FFMPEG_XVID:
- {
- /* FIXME: avi for now... */
- static const char *rv[] = { ".avi", NULL };
- return rv;
- }
- case FFMPEG_FLV:
- {
- static const char *rv[] = { ".flv", NULL };
- return rv;
- }
- case FFMPEG_MKV:
- {
- static const char *rv[] = { ".mkv", NULL };
- return rv;
- }
- case FFMPEG_OGG:
- {
- static const char *rv[] = { ".ogv", ".ogg", NULL };
- return rv;
- }
- default:
- return NULL;
- }
+ switch (format) {
+ case FFMPEG_DV: {
+ static const char *rv[] = {".dv", NULL};
+ return rv;
+ }
+ case FFMPEG_MPEG1: {
+ static const char *rv[] = {".mpg", ".mpeg", NULL};
+ return rv;
+ }
+ case FFMPEG_MPEG2: {
+ static const char *rv[] = {".dvd", ".vob", ".mpg", ".mpeg", NULL};
+ return rv;
+ }
+ case FFMPEG_MPEG4: {
+ static const char *rv[] = {".mp4", ".mpg", ".mpeg", NULL};
+ return rv;
+ }
+ case FFMPEG_AVI: {
+ static const char *rv[] = {".avi", NULL};
+ return rv;
+ }
+ case FFMPEG_MOV: {
+ static const char *rv[] = {".mov", NULL};
+ return rv;
+ }
+ case FFMPEG_H264: {
+ /* FIXME: avi for now... */
+ static const char *rv[] = {".avi", NULL};
+ return rv;
+ }
+
+ case FFMPEG_XVID: {
+ /* FIXME: avi for now... */
+ static const char *rv[] = {".avi", NULL};
+ return rv;
+ }
+ case FFMPEG_FLV: {
+ static const char *rv[] = {".flv", NULL};
+ return rv;
+ }
+ case FFMPEG_MKV: {
+ static const char *rv[] = {".mkv", NULL};
+ return rv;
+ }
+ case FFMPEG_OGG: {
+ static const char *rv[] = {".ogv", ".ogg", NULL};
+ return rv;
+ }
+ default:
+ return NULL;
+ }
}
/* Write a frame to the output file */
-static int write_video_frame(FFMpegContext *context, RenderData *rd, int cfra, AVFrame *frame, ReportList *reports)
+static int write_video_frame(
+ FFMpegContext *context, RenderData *rd, int cfra, AVFrame *frame, ReportList *reports)
{
- int got_output;
- int ret, success = 1;
- AVCodecContext *c = context->video_stream->codec;
- AVPacket packet = { 0 };
-
- av_init_packet(&packet);
-
- frame->pts = cfra;
-
- ret = avcodec_encode_video2(c, &packet, frame, &got_output);
-
- if (ret >= 0 && got_output) {
- if (packet.pts != AV_NOPTS_VALUE) {
- packet.pts = av_rescale_q(packet.pts, c->time_base, context->video_stream->time_base);
- PRINT("Video Frame PTS: %d\n", (int)packet.pts);
- }
- else {
- PRINT("Video Frame PTS: not set\n");
- }
- if (packet.dts != AV_NOPTS_VALUE) {
- packet.dts = av_rescale_q(packet.dts, c->time_base, context->video_stream->time_base);
- PRINT("Video Frame DTS: %d\n", (int)packet.dts);
- }
- else {
- PRINT("Video Frame DTS: not set\n");
- }
-
- packet.stream_index = context->video_stream->index;
- ret = av_interleaved_write_frame(context->outfile, &packet);
- success = (ret == 0);
- }
- else if (ret < 0) {
- success = 0;
- }
-
- if (!success)
- BKE_report(reports, RPT_ERROR, "Error writing frame");
-
- return success;
+ int got_output;
+ int ret, success = 1;
+ AVCodecContext *c = context->video_stream->codec;
+ AVPacket packet = {0};
+
+ av_init_packet(&packet);
+
+ frame->pts = cfra;
+
+ ret = avcodec_encode_video2(c, &packet, frame, &got_output);
+
+ if (ret >= 0 && got_output) {
+ if (packet.pts != AV_NOPTS_VALUE) {
+ packet.pts = av_rescale_q(packet.pts, c->time_base, context->video_stream->time_base);
+ PRINT("Video Frame PTS: %d\n", (int)packet.pts);
+ }
+ else {
+ PRINT("Video Frame PTS: not set\n");
+ }
+ if (packet.dts != AV_NOPTS_VALUE) {
+ packet.dts = av_rescale_q(packet.dts, c->time_base, context->video_stream->time_base);
+ PRINT("Video Frame DTS: %d\n", (int)packet.dts);
+ }
+ else {
+ PRINT("Video Frame DTS: not set\n");
+ }
+
+ packet.stream_index = context->video_stream->index;
+ ret = av_interleaved_write_frame(context->outfile, &packet);
+ success = (ret == 0);
+ }
+ else if (ret < 0) {
+ success = 0;
+ }
+
+ if (!success)
+ BKE_report(reports, RPT_ERROR, "Error writing frame");
+
+ return success;
}
/* read and encode a frame of audio from the buffer */
static AVFrame *generate_video_frame(FFMpegContext *context, uint8_t *pixels, ReportList *reports)
{
- uint8_t *rendered_frame;
-
- AVCodecContext *c = context->video_stream->codec;
- int width = c->width;
- int height = c->height;
- AVFrame *rgb_frame;
-
- if (c->pix_fmt != AV_PIX_FMT_BGR32) {
- rgb_frame = alloc_picture(AV_PIX_FMT_BGR32, width, height);
- if (!rgb_frame) {
- BKE_report(reports, RPT_ERROR, "Could not allocate temporary frame");
- return NULL;
- }
- }
- else {
- rgb_frame = context->current_frame;
- }
-
- rendered_frame = pixels;
-
- /* Do RGBA-conversion and flipping in one step depending
- * on CPU-Endianess */
-
- if (ENDIAN_ORDER == L_ENDIAN) {
- int y;
- for (y = 0; y < height; y++) {
- uint8_t *target = rgb_frame->data[0] + width * 4 * (height - y - 1);
- uint8_t *src = rendered_frame + width * 4 * y;
- uint8_t *end = src + width * 4;
- while (src != end) {
- target[3] = src[3];
- target[2] = src[2];
- target[1] = src[1];
- target[0] = src[0];
-
- target += 4;
- src += 4;
- }
- }
- }
- else {
- int y;
- for (y = 0; y < height; y++) {
- uint8_t *target = rgb_frame->data[0] + width * 4 * (height - y - 1);
- uint8_t *src = rendered_frame + width * 4 * y;
- uint8_t *end = src + width * 4;
- while (src != end) {
- target[3] = src[0];
- target[2] = src[1];
- target[1] = src[2];
- target[0] = src[3];
-
- target += 4;
- src += 4;
- }
- }
- }
-
- if (c->pix_fmt != AV_PIX_FMT_BGR32) {
- sws_scale(context->img_convert_ctx, (const uint8_t *const *) rgb_frame->data,
- rgb_frame->linesize, 0, c->height,
- context->current_frame->data, context->current_frame->linesize);
- delete_picture(rgb_frame);
- }
-
- context->current_frame->format = AV_PIX_FMT_BGR32;
- context->current_frame->width = width;
- context->current_frame->height = height;
-
- return context->current_frame;
+ uint8_t *rendered_frame;
+
+ AVCodecContext *c = context->video_stream->codec;
+ int width = c->width;
+ int height = c->height;
+ AVFrame *rgb_frame;
+
+ if (c->pix_fmt != AV_PIX_FMT_BGR32) {
+ rgb_frame = alloc_picture(AV_PIX_FMT_BGR32, width, height);
+ if (!rgb_frame) {
+ BKE_report(reports, RPT_ERROR, "Could not allocate temporary frame");
+ return NULL;
+ }
+ }
+ else {
+ rgb_frame = context->current_frame;
+ }
+
+ rendered_frame = pixels;
+
+ /* Do RGBA-conversion and flipping in one step depending
+ * on CPU-Endianess */
+
+ if (ENDIAN_ORDER == L_ENDIAN) {
+ int y;
+ for (y = 0; y < height; y++) {
+ uint8_t *target = rgb_frame->data[0] + width * 4 * (height - y - 1);
+ uint8_t *src = rendered_frame + width * 4 * y;
+ uint8_t *end = src + width * 4;
+ while (src != end) {
+ target[3] = src[3];
+ target[2] = src[2];
+ target[1] = src[1];
+ target[0] = src[0];
+
+ target += 4;
+ src += 4;
+ }
+ }
+ }
+ else {
+ int y;
+ for (y = 0; y < height; y++) {
+ uint8_t *target = rgb_frame->data[0] + width * 4 * (height - y - 1);
+ uint8_t *src = rendered_frame + width * 4 * y;
+ uint8_t *end = src + width * 4;
+ while (src != end) {
+ target[3] = src[0];
+ target[2] = src[1];
+ target[1] = src[2];
+ target[0] = src[3];
+
+ target += 4;
+ src += 4;
+ }
+ }
+ }
+
+ if (c->pix_fmt != AV_PIX_FMT_BGR32) {
+ sws_scale(context->img_convert_ctx,
+ (const uint8_t *const *)rgb_frame->data,
+ rgb_frame->linesize,
+ 0,
+ c->height,
+ context->current_frame->data,
+ context->current_frame->linesize);
+ delete_picture(rgb_frame);
+ }
+
+ context->current_frame->format = AV_PIX_FMT_BGR32;
+ context->current_frame->width = width;
+ context->current_frame->height = height;
+
+ return context->current_frame;
}
-static void set_ffmpeg_property_option(AVCodecContext *c, IDProperty *prop, AVDictionary **dictionary)
+static void set_ffmpeg_property_option(AVCodecContext *c,
+ IDProperty *prop,
+ AVDictionary **dictionary)
{
- char name[128];
- char *param;
-
- PRINT("FFMPEG expert option: %s: ", prop->name);
-
- BLI_strncpy(name, prop->name, sizeof(name));
-
- param = strchr(name, ':');
-
- if (param) {
- *param++ = '\0';
- }
-
- switch (prop->type) {
- case IDP_STRING:
- PRINT("%s.\n", IDP_String(prop));
- av_dict_set(dictionary, name, IDP_String(prop), 0);
- break;
- case IDP_FLOAT:
- PRINT("%g.\n", IDP_Float(prop));
- ffmpeg_dict_set_float(dictionary, prop->name, IDP_Float(prop));
- break;
- case IDP_INT:
- PRINT("%d.\n", IDP_Int(prop));
-
- if (param) {
- if (IDP_Int(prop)) {
- av_dict_set(dictionary, name, param, 0);
- }
- else {
- return;
- }
- }
- else {
- ffmpeg_dict_set_int(dictionary, prop->name, IDP_Int(prop));
- }
- break;
- }
+ char name[128];
+ char *param;
+
+ PRINT("FFMPEG expert option: %s: ", prop->name);
+
+ BLI_strncpy(name, prop->name, sizeof(name));
+
+ param = strchr(name, ':');
+
+ if (param) {
+ *param++ = '\0';
+ }
+
+ switch (prop->type) {
+ case IDP_STRING:
+ PRINT("%s.\n", IDP_String(prop));
+ av_dict_set(dictionary, name, IDP_String(prop), 0);
+ break;
+ case IDP_FLOAT:
+ PRINT("%g.\n", IDP_Float(prop));
+ ffmpeg_dict_set_float(dictionary, prop->name, IDP_Float(prop));
+ break;
+ case IDP_INT:
+ PRINT("%d.\n", IDP_Int(prop));
+
+ if (param) {
+ if (IDP_Int(prop)) {
+ av_dict_set(dictionary, name, param, 0);
+ }
+ else {
+ return;
+ }
+ }
+ else {
+ ffmpeg_dict_set_int(dictionary, prop->name, IDP_Int(prop));
+ }
+ break;
+ }
}
static int ffmpeg_proprty_valid(AVCodecContext *c, const char *prop_name, IDProperty *curr)
{
- int valid = 1;
+ int valid = 1;
- if (STREQ(prop_name, "video")) {
- if (STREQ(curr->name, "bf")) {
- /* flash codec doesn't support b frames */
- valid &= c->codec_id != AV_CODEC_ID_FLV1;
- }
- }
+ if (STREQ(prop_name, "video")) {
+ if (STREQ(curr->name, "bf")) {
+ /* flash codec doesn't support b frames */
+ valid &= c->codec_id != AV_CODEC_ID_FLV1;
+ }
+ }
- return valid;
+ return valid;
}
-static void set_ffmpeg_properties(RenderData *rd, AVCodecContext *c, const char *prop_name,
+static void set_ffmpeg_properties(RenderData *rd,
+ AVCodecContext *c,
+ const char *prop_name,
AVDictionary **dictionary)
{
- IDProperty *prop;
- IDProperty *curr;
-
- /* TODO(sergey): This is actually rather stupid, because changing
- * codec settings in render panel would also set expert options.
- *
- * But we need ti here in order to get rid of deprecated settings
- * when opening old files in new blender.
- *
- * For as long we don't allow editing properties in the interface
- * it's all good. bug if we allow editing them, we'll need to
- * replace it with some smarter code which would port settings
- * from deprecated to new one.
- */
- ffmpeg_set_expert_options(rd);
-
- if (!rd->ffcodecdata.properties) {
- return;
- }
-
- prop = IDP_GetPropertyFromGroup(rd->ffcodecdata.properties, prop_name);
- if (!prop) {
- return;
- }
-
- for (curr = prop->data.group.first; curr; curr = curr->next) {
- if (ffmpeg_proprty_valid(c, prop_name, curr))
- set_ffmpeg_property_option(c, curr, dictionary);
- }
+ IDProperty *prop;
+ IDProperty *curr;
+
+ /* TODO(sergey): This is actually rather stupid, because changing
+ * codec settings in render panel would also set expert options.
+ *
+ * But we need ti here in order to get rid of deprecated settings
+ * when opening old files in new blender.
+ *
+ * For as long we don't allow editing properties in the interface
+ * it's all good. bug if we allow editing them, we'll need to
+ * replace it with some smarter code which would port settings
+ * from deprecated to new one.
+ */
+ ffmpeg_set_expert_options(rd);
+
+ if (!rd->ffcodecdata.properties) {
+ return;
+ }
+
+ prop = IDP_GetPropertyFromGroup(rd->ffcodecdata.properties, prop_name);
+ if (!prop) {
+ return;
+ }
+
+ for (curr = prop->data.group.first; curr; curr = curr->next) {
+ if (ffmpeg_proprty_valid(c, prop_name, curr))
+ set_ffmpeg_property_option(c, curr, dictionary);
+ }
}
/* prepare a video stream for the output file */
-static AVStream *alloc_video_stream(FFMpegContext *context, RenderData *rd, int codec_id, AVFormatContext *of,
- int rectx, int recty, char *error, int error_size)
+static AVStream *alloc_video_stream(FFMpegContext *context,
+ RenderData *rd,
+ int codec_id,
+ AVFormatContext *of,
+ int rectx,
+ int recty,
+ char *error,
+ int error_size)
{
- AVStream *st;
- AVCodecContext *c;
- AVCodec *codec;
- AVDictionary *opts = NULL;
-
- error[0] = '\0';
-
- st = avformat_new_stream(of, NULL);
- if (!st) return NULL;
- st->id = 0;
-
- /* Set up the codec context */
-
- c = st->codec;
- c->thread_count = 0;
- c->thread_type = FF_THREAD_FRAME;
-
- c->codec_id = codec_id;
- c->codec_type = AVMEDIA_TYPE_VIDEO;
-
- /* Get some values from the current render settings */
-
- c->width = rectx;
- c->height = recty;
-
- /* FIXME: Really bad hack (tm) for NTSC support */
- if (context->ffmpeg_type == FFMPEG_DV && rd->frs_sec != 25) {
- c->time_base.den = 2997;
- c->time_base.num = 100;
- }
- else if ((float) ((int) rd->frs_sec_base) == rd->frs_sec_base) {
- c->time_base.den = rd->frs_sec;
- c->time_base.num = (int) rd->frs_sec_base;
- }
- else {
- c->time_base.den = rd->frs_sec * 100000;
- c->time_base.num = ((double) rd->frs_sec_base) * 100000;
- }
-
- c->gop_size = context->ffmpeg_gop_size;
- c->max_b_frames = context->ffmpeg_max_b_frames;
-
- if (context->ffmpeg_crf >= 0) {
- ffmpeg_dict_set_int(&opts, "crf", context->ffmpeg_crf);
- }
- else {
- c->bit_rate = context->ffmpeg_video_bitrate * 1000;
- c->rc_max_rate = rd->ffcodecdata.rc_max_rate * 1000;
- c->rc_min_rate = rd->ffcodecdata.rc_min_rate * 1000;
- c->rc_buffer_size = rd->ffcodecdata.rc_buffer_size * 1024;
- }
-
- if (context->ffmpeg_preset) {
- /* 'preset' is used by h.264, 'deadline' is used by webm/vp9. I'm not
- * setting those properties conditionally based on the video codec,
- * as the FFmpeg encoder simply ignores unknown settings anyway. */
- char const *preset_name = NULL; /* used by h.264 */
- char const *deadline_name = NULL; /* used by webm/vp9 */
- switch (context->ffmpeg_preset) {
- case FFM_PRESET_GOOD:
- preset_name = "medium";
- deadline_name = "good";
- break;
- case FFM_PRESET_BEST:
- preset_name = "slower";
- deadline_name = "best";
- break;
- case FFM_PRESET_REALTIME:
- preset_name = "superfast";
- deadline_name = "realtime";
- break;
- default:
- printf("Unknown preset number %i, ignoring.\n", context->ffmpeg_preset);
- }
- if (preset_name != NULL) {
- av_dict_set(&opts, "preset", preset_name, 0);
- }
- if (deadline_name != NULL) {
- av_dict_set(&opts, "deadline", deadline_name, 0);
- }
- }
-
- /* Deprecated and not doing anything since July 2015, deleted in recent ffmpeg */
- //c->me_method = ME_EPZS;
-
- codec = avcodec_find_encoder(c->codec_id);
- if (!codec)
- return NULL;
-
- /* Be sure to use the correct pixel format(e.g. RGB, YUV) */
-
- if (codec->pix_fmts) {
- c->pix_fmt = codec->pix_fmts[0];
- }
- else {
- /* makes HuffYUV happy ... */
- c->pix_fmt = AV_PIX_FMT_YUV422P;
- }
-
- if (context->ffmpeg_type == FFMPEG_XVID) {
- /* arghhhh ... */
- c->pix_fmt = AV_PIX_FMT_YUV420P;
- c->codec_tag = (('D' << 24) + ('I' << 16) + ('V' << 8) + 'X');
- }
-
- if (codec_id == AV_CODEC_ID_H264) {
- /* correct wrong default ffmpeg param which crash x264 */
- c->qmin = 10;
- c->qmax = 51;
- }
-
- /* Keep lossless encodes in the RGB domain. */
- if (codec_id == AV_CODEC_ID_HUFFYUV) {
- if (rd->im_format.planes == R_IMF_PLANES_RGBA) {
- c->pix_fmt = AV_PIX_FMT_BGRA;
- }
- else {
- c->pix_fmt = AV_PIX_FMT_RGB32;
- }
- }
-
- if (codec_id == AV_CODEC_ID_FFV1) {
- c->pix_fmt = AV_PIX_FMT_RGB32;
- }
-
- if (codec_id == AV_CODEC_ID_QTRLE) {
- if (rd->im_format.planes == R_IMF_PLANES_RGBA) {
- c->pix_fmt = AV_PIX_FMT_ARGB;
- }
- }
-
- if (codec_id == AV_CODEC_ID_PNG) {
- if (rd->im_format.planes == R_IMF_PLANES_RGBA) {
- c->pix_fmt = AV_PIX_FMT_RGBA;
- }
- }
-
- if ((of->oformat->flags & AVFMT_GLOBALHEADER)) {
- PRINT("Using global header\n");
- c->flags |= CODEC_FLAG_GLOBAL_HEADER;
- }
-
- /* xasp & yasp got float lately... */
-
- st->sample_aspect_ratio = c->sample_aspect_ratio = av_d2q(((double) rd->xasp / (double) rd->yasp), 255);
- st->avg_frame_rate = av_inv_q(c->time_base);
-
- set_ffmpeg_properties(rd, c, "video", &opts);
-
- if (avcodec_open2(c, codec, &opts) < 0) {
- BLI_strncpy(error, IMB_ffmpeg_last_error(), error_size);
- av_dict_free(&opts);
- return NULL;
- }
- av_dict_free(&opts);
-
- context->current_frame = alloc_picture(c->pix_fmt, c->width, c->height);
-
- context->img_convert_ctx = sws_getContext(c->width, c->height, AV_PIX_FMT_BGR32, c->width, c->height, c->pix_fmt, SWS_BICUBIC,
- NULL, NULL, NULL);
- return st;
+ AVStream *st;
+ AVCodecContext *c;
+ AVCodec *codec;
+ AVDictionary *opts = NULL;
+
+ error[0] = '\0';
+
+ st = avformat_new_stream(of, NULL);
+ if (!st)
+ return NULL;
+ st->id = 0;
+
+ /* Set up the codec context */
+
+ c = st->codec;
+ c->thread_count = 0;
+ c->thread_type = FF_THREAD_FRAME;
+
+ c->codec_id = codec_id;
+ c->codec_type = AVMEDIA_TYPE_VIDEO;
+
+ /* Get some values from the current render settings */
+
+ c->width = rectx;
+ c->height = recty;
+
+ /* FIXME: Really bad hack (tm) for NTSC support */
+ if (context->ffmpeg_type == FFMPEG_DV && rd->frs_sec != 25) {
+ c->time_base.den = 2997;
+ c->time_base.num = 100;
+ }
+ else if ((float)((int)rd->frs_sec_base) == rd->frs_sec_base) {
+ c->time_base.den = rd->frs_sec;
+ c->time_base.num = (int)rd->frs_sec_base;
+ }
+ else {
+ c->time_base.den = rd->frs_sec * 100000;
+ c->time_base.num = ((double)rd->frs_sec_base) * 100000;
+ }
+
+ c->gop_size = context->ffmpeg_gop_size;
+ c->max_b_frames = context->ffmpeg_max_b_frames;
+
+ if (context->ffmpeg_crf >= 0) {
+ ffmpeg_dict_set_int(&opts, "crf", context->ffmpeg_crf);
+ }
+ else {
+ c->bit_rate = context->ffmpeg_video_bitrate * 1000;
+ c->rc_max_rate = rd->ffcodecdata.rc_max_rate * 1000;
+ c->rc_min_rate = rd->ffcodecdata.rc_min_rate * 1000;
+ c->rc_buffer_size = rd->ffcodecdata.rc_buffer_size * 1024;
+ }
+
+ if (context->ffmpeg_preset) {
+ /* 'preset' is used by h.264, 'deadline' is used by webm/vp9. I'm not
+ * setting those properties conditionally based on the video codec,
+ * as the FFmpeg encoder simply ignores unknown settings anyway. */
+ char const *preset_name = NULL; /* used by h.264 */
+ char const *deadline_name = NULL; /* used by webm/vp9 */
+ switch (context->ffmpeg_preset) {
+ case FFM_PRESET_GOOD:
+ preset_name = "medium";
+ deadline_name = "good";
+ break;
+ case FFM_PRESET_BEST:
+ preset_name = "slower";
+ deadline_name = "best";
+ break;
+ case FFM_PRESET_REALTIME:
+ preset_name = "superfast";
+ deadline_name = "realtime";
+ break;
+ default:
+ printf("Unknown preset number %i, ignoring.\n", context->ffmpeg_preset);
+ }
+ if (preset_name != NULL) {
+ av_dict_set(&opts, "preset", preset_name, 0);
+ }
+ if (deadline_name != NULL) {
+ av_dict_set(&opts, "deadline", deadline_name, 0);
+ }
+ }
+
+ /* Deprecated and not doing anything since July 2015, deleted in recent ffmpeg */
+ //c->me_method = ME_EPZS;
+
+ codec = avcodec_find_encoder(c->codec_id);
+ if (!codec)
+ return NULL;
+
+ /* Be sure to use the correct pixel format(e.g. RGB, YUV) */
+
+ if (codec->pix_fmts) {
+ c->pix_fmt = codec->pix_fmts[0];
+ }
+ else {
+ /* makes HuffYUV happy ... */
+ c->pix_fmt = AV_PIX_FMT_YUV422P;
+ }
+
+ if (context->ffmpeg_type == FFMPEG_XVID) {
+ /* arghhhh ... */
+ c->pix_fmt = AV_PIX_FMT_YUV420P;
+ c->codec_tag = (('D' << 24) + ('I' << 16) + ('V' << 8) + 'X');
+ }
+
+ if (codec_id == AV_CODEC_ID_H264) {
+ /* correct wrong default ffmpeg param which crash x264 */
+ c->qmin = 10;
+ c->qmax = 51;
+ }
+
+ /* Keep lossless encodes in the RGB domain. */
+ if (codec_id == AV_CODEC_ID_HUFFYUV) {
+ if (rd->im_format.planes == R_IMF_PLANES_RGBA) {
+ c->pix_fmt = AV_PIX_FMT_BGRA;
+ }
+ else {
+ c->pix_fmt = AV_PIX_FMT_RGB32;
+ }
+ }
+
+ if (codec_id == AV_CODEC_ID_FFV1) {
+ c->pix_fmt = AV_PIX_FMT_RGB32;
+ }
+
+ if (codec_id == AV_CODEC_ID_QTRLE) {
+ if (rd->im_format.planes == R_IMF_PLANES_RGBA) {
+ c->pix_fmt = AV_PIX_FMT_ARGB;
+ }
+ }
+
+ if (codec_id == AV_CODEC_ID_PNG) {
+ if (rd->im_format.planes == R_IMF_PLANES_RGBA) {
+ c->pix_fmt = AV_PIX_FMT_RGBA;
+ }
+ }
+
+ if ((of->oformat->flags & AVFMT_GLOBALHEADER)) {
+ PRINT("Using global header\n");
+ c->flags |= CODEC_FLAG_GLOBAL_HEADER;
+ }
+
+ /* xasp & yasp got float lately... */
+
+ st->sample_aspect_ratio = c->sample_aspect_ratio = av_d2q(((double)rd->xasp / (double)rd->yasp),
+ 255);
+ st->avg_frame_rate = av_inv_q(c->time_base);
+
+ set_ffmpeg_properties(rd, c, "video", &opts);
+
+ if (avcodec_open2(c, codec, &opts) < 0) {
+ BLI_strncpy(error, IMB_ffmpeg_last_error(), error_size);
+ av_dict_free(&opts);
+ return NULL;
+ }
+ av_dict_free(&opts);
+
+ context->current_frame = alloc_picture(c->pix_fmt, c->width, c->height);
+
+ context->img_convert_ctx = sws_getContext(c->width,
+ c->height,
+ AV_PIX_FMT_BGR32,
+ c->width,
+ c->height,
+ c->pix_fmt,
+ SWS_BICUBIC,
+ NULL,
+ NULL,
+ NULL);
+ return st;
}
-static AVStream *alloc_audio_stream(FFMpegContext *context, RenderData *rd, int codec_id, AVFormatContext *of, char *error, int error_size)
+static AVStream *alloc_audio_stream(FFMpegContext *context,
+ RenderData *rd,
+ int codec_id,
+ AVFormatContext *of,
+ char *error,
+ int error_size)
{
- AVStream *st;
- AVCodecContext *c;
- AVCodec *codec;
- AVDictionary *opts = NULL;
-
- error[0] = '\0';
-
- st = avformat_new_stream(of, NULL);
- if (!st) return NULL;
- st->id = 1;
-
- c = st->codec;
- c->thread_count = 0;
- c->thread_type = FF_THREAD_FRAME;
-
- c->codec_id = codec_id;
- c->codec_type = AVMEDIA_TYPE_AUDIO;
-
- c->sample_rate = rd->ffcodecdata.audio_mixrate;
- c->bit_rate = context->ffmpeg_audio_bitrate * 1000;
- c->sample_fmt = AV_SAMPLE_FMT_S16;
- c->channels = rd->ffcodecdata.audio_channels;
-
-#ifdef FFMPEG_HAVE_FRAME_CHANNEL_LAYOUT
- switch (rd->ffcodecdata.audio_channels) {
- case FFM_CHANNELS_MONO:
- c->channel_layout = AV_CH_LAYOUT_MONO;
- break;
- case FFM_CHANNELS_STEREO:
- c->channel_layout = AV_CH_LAYOUT_STEREO;
- break;
- case FFM_CHANNELS_SURROUND4:
- c->channel_layout = AV_CH_LAYOUT_QUAD;
- break;
- case FFM_CHANNELS_SURROUND51:
- c->channel_layout = AV_CH_LAYOUT_5POINT1_BACK;
- break;
- case FFM_CHANNELS_SURROUND71:
- c->channel_layout = AV_CH_LAYOUT_7POINT1;
- break;
- }
-#endif
-
- if (request_float_audio_buffer(codec_id)) {
- /* mainly for AAC codec which is experimental */
- c->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
- c->sample_fmt = AV_SAMPLE_FMT_FLT;
- }
-
- codec = avcodec_find_encoder(c->codec_id);
- if (!codec) {
- //XXX error("Couldn't find a valid audio codec");
- return NULL;
- }
-
- if (codec->sample_fmts) {
- /* check if the preferred sample format for this codec is supported.
- * this is because, depending on the version of libav, and with the whole ffmpeg/libav fork situation,
- * you have various implementations around. float samples in particular are not always supported.
- */
- const enum AVSampleFormat *p = codec->sample_fmts;
- for (; *p != -1; p++) {
- if (*p == st->codec->sample_fmt)
- break;
- }
- if (*p == -1) {
- /* sample format incompatible with codec. Defaulting to a format known to work */
- st->codec->sample_fmt = codec->sample_fmts[0];
- }
- }
-
- if (codec->supported_samplerates) {
- const int *p = codec->supported_samplerates;
- int best = 0;
- int best_dist = INT_MAX;
- for (; *p; p++) {
- int dist = abs(st->codec->sample_rate - *p);
- if (dist < best_dist) {
- best_dist = dist;
- best = *p;
- }
- }
- /* best is the closest supported sample rate (same as selected if best_dist == 0) */
- st->codec->sample_rate = best;
- }
-
- if (of->oformat->flags & AVFMT_GLOBALHEADER) {
- c->flags |= CODEC_FLAG_GLOBAL_HEADER;
- }
-
- set_ffmpeg_properties(rd, c, "audio", &opts);
-
- if (avcodec_open2(c, codec, &opts) < 0) {
- //XXX error("Couldn't initialize audio codec");
- BLI_strncpy(error, IMB_ffmpeg_last_error(), error_size);
- av_dict_free(&opts);
- return NULL;
- }
- av_dict_free(&opts);
-
- /* need to prevent floating point exception when using vorbis audio codec,
- * initialize this value in the same way as it's done in FFmpeg itself (sergey) */
- st->codec->time_base.num = 1;
- st->codec->time_base.den = st->codec->sample_rate;
-
-#ifndef FFMPEG_HAVE_ENCODE_AUDIO2
- context->audio_outbuf_size = FF_MIN_BUFFER_SIZE;
-#endif
-
- if (c->frame_size == 0)
- // used to be if ((c->codec_id >= CODEC_ID_PCM_S16LE) && (c->codec_id <= CODEC_ID_PCM_DVD))
- // not sure if that is needed anymore, so let's try out if there are any
- // complaints regarding some ffmpeg versions users might have
- context->audio_input_samples = FF_MIN_BUFFER_SIZE * 8 / c->bits_per_coded_sample / c->channels;
- else {
- context->audio_input_samples = c->frame_size;
-#ifndef FFMPEG_HAVE_ENCODE_AUDIO2
- if (c->frame_size * c->channels * sizeof(int16_t) * 4 > context->audio_outbuf_size)
- context->audio_outbuf_size = c->frame_size * c->channels * sizeof(int16_t) * 4;
-#endif
- }
-
- context->audio_deinterleave = av_sample_fmt_is_planar(c->sample_fmt);
-
- context->audio_sample_size = av_get_bytes_per_sample(c->sample_fmt);
-
- context->audio_input_buffer = (uint8_t *) av_malloc(context->audio_input_samples * c->channels * context->audio_sample_size);
-#ifndef FFMPEG_HAVE_ENCODE_AUDIO2
- context->audio_output_buffer = (uint8_t *) av_malloc(context->audio_outbuf_size);
-#endif
-
- if (context->audio_deinterleave)
- context->audio_deinterleave_buffer = (uint8_t *) av_malloc(context->audio_input_samples * c->channels * context->audio_sample_size);
-
- context->audio_time = 0.0f;
-
- return st;
+ AVStream *st;
+ AVCodecContext *c;
+ AVCodec *codec;
+ AVDictionary *opts = NULL;
+
+ error[0] = '\0';
+
+ st = avformat_new_stream(of, NULL);
+ if (!st)
+ return NULL;
+ st->id = 1;
+
+ c = st->codec;
+ c->thread_count = 0;
+ c->thread_type = FF_THREAD_FRAME;
+
+ c->codec_id = codec_id;
+ c->codec_type = AVMEDIA_TYPE_AUDIO;
+
+ c->sample_rate = rd->ffcodecdata.audio_mixrate;
+ c->bit_rate = context->ffmpeg_audio_bitrate * 1000;
+ c->sample_fmt = AV_SAMPLE_FMT_S16;
+ c->channels = rd->ffcodecdata.audio_channels;
+
+# ifdef FFMPEG_HAVE_FRAME_CHANNEL_LAYOUT
+ switch (rd->ffcodecdata.audio_channels) {
+ case FFM_CHANNELS_MONO:
+ c->channel_layout = AV_CH_LAYOUT_MONO;
+ break;
+ case FFM_CHANNELS_STEREO:
+ c->channel_layout = AV_CH_LAYOUT_STEREO;
+ break;
+ case FFM_CHANNELS_SURROUND4:
+ c->channel_layout = AV_CH_LAYOUT_QUAD;
+ break;
+ case FFM_CHANNELS_SURROUND51:
+ c->channel_layout = AV_CH_LAYOUT_5POINT1_BACK;
+ break;
+ case FFM_CHANNELS_SURROUND71:
+ c->channel_layout = AV_CH_LAYOUT_7POINT1;
+ break;
+ }
+# endif
+
+ if (request_float_audio_buffer(codec_id)) {
+ /* mainly for AAC codec which is experimental */
+ c->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
+ c->sample_fmt = AV_SAMPLE_FMT_FLT;
+ }
+
+ codec = avcodec_find_encoder(c->codec_id);
+ if (!codec) {
+ //XXX error("Couldn't find a valid audio codec");
+ return NULL;
+ }
+
+ if (codec->sample_fmts) {
+ /* check if the preferred sample format for this codec is supported.
+ * this is because, depending on the version of libav, and with the whole ffmpeg/libav fork situation,
+ * you have various implementations around. float samples in particular are not always supported.
+ */
+ const enum AVSampleFormat *p = codec->sample_fmts;
+ for (; *p != -1; p++) {
+ if (*p == st->codec->sample_fmt)
+ break;
+ }
+ if (*p == -1) {
+ /* sample format incompatible with codec. Defaulting to a format known to work */
+ st->codec->sample_fmt = codec->sample_fmts[0];
+ }
+ }
+
+ if (codec->supported_samplerates) {
+ const int *p = codec->supported_samplerates;
+ int best = 0;
+ int best_dist = INT_MAX;
+ for (; *p; p++) {
+ int dist = abs(st->codec->sample_rate - *p);
+ if (dist < best_dist) {
+ best_dist = dist;
+ best = *p;
+ }
+ }
+ /* best is the closest supported sample rate (same as selected if best_dist == 0) */
+ st->codec->sample_rate = best;
+ }
+
+ if (of->oformat->flags & AVFMT_GLOBALHEADER) {
+ c->flags |= CODEC_FLAG_GLOBAL_HEADER;
+ }
+
+ set_ffmpeg_properties(rd, c, "audio", &opts);
+
+ if (avcodec_open2(c, codec, &opts) < 0) {
+ //XXX error("Couldn't initialize audio codec");
+ BLI_strncpy(error, IMB_ffmpeg_last_error(), error_size);
+ av_dict_free(&opts);
+ return NULL;
+ }
+ av_dict_free(&opts);
+
+ /* need to prevent floating point exception when using vorbis audio codec,
+ * initialize this value in the same way as it's done in FFmpeg itself (sergey) */
+ st->codec->time_base.num = 1;
+ st->codec->time_base.den = st->codec->sample_rate;
+
+# ifndef FFMPEG_HAVE_ENCODE_AUDIO2
+ context->audio_outbuf_size = FF_MIN_BUFFER_SIZE;
+# endif
+
+ if (c->frame_size == 0)
+ // used to be if ((c->codec_id >= CODEC_ID_PCM_S16LE) && (c->codec_id <= CODEC_ID_PCM_DVD))
+ // not sure if that is needed anymore, so let's try out if there are any
+ // complaints regarding some ffmpeg versions users might have
+ context->audio_input_samples = FF_MIN_BUFFER_SIZE * 8 / c->bits_per_coded_sample / c->channels;
+ else {
+ context->audio_input_samples = c->frame_size;
+# ifndef FFMPEG_HAVE_ENCODE_AUDIO2
+ if (c->frame_size * c->channels * sizeof(int16_t) * 4 > context->audio_outbuf_size)
+ context->audio_outbuf_size = c->frame_size * c->channels * sizeof(int16_t) * 4;
+# endif
+ }
+
+ context->audio_deinterleave = av_sample_fmt_is_planar(c->sample_fmt);
+
+ context->audio_sample_size = av_get_bytes_per_sample(c->sample_fmt);
+
+ context->audio_input_buffer = (uint8_t *)av_malloc(context->audio_input_samples * c->channels *
+ context->audio_sample_size);
+# ifndef FFMPEG_HAVE_ENCODE_AUDIO2
+ context->audio_output_buffer = (uint8_t *)av_malloc(context->audio_outbuf_size);
+# endif
+
+ if (context->audio_deinterleave)
+ context->audio_deinterleave_buffer = (uint8_t *)av_malloc(
+ context->audio_input_samples * c->channels * context->audio_sample_size);
+
+ context->audio_time = 0.0f;
+
+ return st;
}
/* essential functions -- start, append, end */
static void ffmpeg_dict_set_int(AVDictionary **dict, const char *key, int value)
{
- char buffer[32];
+ char buffer[32];
- BLI_snprintf(buffer, sizeof(buffer), "%d", value);
+ BLI_snprintf(buffer, sizeof(buffer), "%d", value);
- av_dict_set(dict, key, buffer, 0);
+ av_dict_set(dict, key, buffer, 0);
}
static void ffmpeg_dict_set_float(AVDictionary **dict, const char *key, float value)
{
- char buffer[32];
+ char buffer[32];
- BLI_snprintf(buffer, sizeof(buffer), "%.8f", value);
+ BLI_snprintf(buffer, sizeof(buffer), "%.8f", value);
- av_dict_set(dict, key, buffer, 0);
+ av_dict_set(dict, key, buffer, 0);
}
-static void ffmpeg_add_metadata_callback(void *data, const char *propname, char *propvalue, int len)
+static void ffmpeg_add_metadata_callback(void *data,
+ const char *propname,
+ char *propvalue,
+ int len)
{
- AVDictionary **metadata = (AVDictionary **)data;
- av_dict_set(metadata, propname, propvalue, 0);
+ AVDictionary **metadata = (AVDictionary **)data;
+ av_dict_set(metadata, propname, propvalue, 0);
}
-static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int rectx, int recty, const char *suffix, ReportList *reports)
+static int start_ffmpeg_impl(FFMpegContext *context,
+ struct RenderData *rd,
+ int rectx,
+ int recty,
+ const char *suffix,
+ ReportList *reports)
{
- /* Handle to the output file */
- AVFormatContext *of;
- AVOutputFormat *fmt;
- AVDictionary *opts = NULL;
- char name[FILE_MAX], error[1024];
- const char **exts;
-
- context->ffmpeg_type = rd->ffcodecdata.type;
- context->ffmpeg_codec = rd->ffcodecdata.codec;
- context->ffmpeg_audio_codec = rd->ffcodecdata.audio_codec;
- context->ffmpeg_video_bitrate = rd->ffcodecdata.video_bitrate;
- context->ffmpeg_audio_bitrate = rd->ffcodecdata.audio_bitrate;
- context->ffmpeg_gop_size = rd->ffcodecdata.gop_size;
- context->ffmpeg_autosplit = rd->ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT;
- context->ffmpeg_crf = rd->ffcodecdata.constant_rate_factor;
- context->ffmpeg_preset = rd->ffcodecdata.ffmpeg_preset;
-
- if ((rd->ffcodecdata.flags & FFMPEG_USE_MAX_B_FRAMES) != 0) {
- context->ffmpeg_max_b_frames = rd->ffcodecdata.max_b_frames;
- }
-
- /* Determine the correct filename */
- ffmpeg_filepath_get(context, name, rd, context->ffmpeg_preview, suffix);
- PRINT("Starting output to %s(ffmpeg)...\n"
- " Using type=%d, codec=%d, audio_codec=%d,\n"
- " video_bitrate=%d, audio_bitrate=%d,\n"
- " gop_size=%d, autosplit=%d\n"
- " render width=%d, render height=%d\n",
- name, context->ffmpeg_type, context->ffmpeg_codec, context->ffmpeg_audio_codec,
- context->ffmpeg_video_bitrate, context->ffmpeg_audio_bitrate,
- context->ffmpeg_gop_size, context->ffmpeg_autosplit, rectx, recty);
-
- exts = get_file_extensions(context->ffmpeg_type);
- if (!exts) {
- BKE_report(reports, RPT_ERROR, "No valid formats found");
- return 0;
- }
- fmt = av_guess_format(NULL, exts[0], NULL);
- if (!fmt) {
- BKE_report(reports, RPT_ERROR, "No valid formats found");
- return 0;
- }
-
- of = avformat_alloc_context();
- if (!of) {
- BKE_report(reports, RPT_ERROR, "Error opening output file");
- return 0;
- }
-
-
- /* Returns after this must 'goto fail;' */
-
- of->oformat = fmt;
-
- /* Only bother with setting packet size & mux rate when CRF is not used. */
- if (context->ffmpeg_crf == 0) {
- of->packet_size = rd->ffcodecdata.mux_packet_size;
- if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE) {
- ffmpeg_dict_set_int(&opts, "muxrate", rd->ffcodecdata.mux_rate);
- }
- else {
- av_dict_set(&opts, "muxrate", "0", 0);
- }
- }
-
- ffmpeg_dict_set_int(&opts, "preload", (int)(0.5 * AV_TIME_BASE));
-
- of->max_delay = (int)(0.7 * AV_TIME_BASE);
-
- fmt->audio_codec = context->ffmpeg_audio_codec;
-
- BLI_strncpy(of->filename, name, sizeof(of->filename));
- /* set the codec to the user's selection */
- switch (context->ffmpeg_type) {
- case FFMPEG_AVI:
- case FFMPEG_MOV:
- case FFMPEG_MKV:
- fmt->video_codec = context->ffmpeg_codec;
- break;
- case FFMPEG_OGG:
- fmt->video_codec = AV_CODEC_ID_THEORA;
- break;
- case FFMPEG_DV:
- fmt->video_codec = AV_CODEC_ID_DVVIDEO;
- break;
- case FFMPEG_MPEG1:
- fmt->video_codec = AV_CODEC_ID_MPEG1VIDEO;
- break;
- case FFMPEG_MPEG2:
- fmt->video_codec = AV_CODEC_ID_MPEG2VIDEO;
- break;
- case FFMPEG_H264:
- fmt->video_codec = AV_CODEC_ID_H264;
- break;
- case FFMPEG_XVID:
- fmt->video_codec = AV_CODEC_ID_MPEG4;
- break;
- case FFMPEG_FLV:
- fmt->video_codec = AV_CODEC_ID_FLV1;
- break;
- case FFMPEG_MPEG4:
- default:
- fmt->video_codec = context->ffmpeg_codec;
- break;
- }
- if (fmt->video_codec == AV_CODEC_ID_DVVIDEO) {
- if (rectx != 720) {
- BKE_report(reports, RPT_ERROR, "Render width has to be 720 pixels for DV!");
- goto fail;
- }
- if (rd->frs_sec != 25 && recty != 480) {
- BKE_report(reports, RPT_ERROR, "Render height has to be 480 pixels for DV-NTSC!");
- goto fail;
- }
- if (rd->frs_sec == 25 && recty != 576) {
- BKE_report(reports, RPT_ERROR, "Render height has to be 576 pixels for DV-PAL!");
- goto fail;
- }
- }
-
- if (context->ffmpeg_type == FFMPEG_DV) {
- fmt->audio_codec = AV_CODEC_ID_PCM_S16LE;
- if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE && rd->ffcodecdata.audio_mixrate != 48000 && rd->ffcodecdata.audio_channels != 2) {
- BKE_report(reports, RPT_ERROR, "FFMPEG only supports 48khz / stereo audio for DV!");
- goto fail;
- }
- }
-
- if (fmt->video_codec != AV_CODEC_ID_NONE) {
- context->video_stream = alloc_video_stream(context, rd, fmt->video_codec, of, rectx, recty, error, sizeof(error));
- PRINT("alloc video stream %p\n", context->video_stream);
- if (!context->video_stream) {
- if (error[0])
- BKE_report(reports, RPT_ERROR, error);
- else
- BKE_report(reports, RPT_ERROR, "Error initializing video stream");
- goto fail;
- }
- }
-
- if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE) {
- context->audio_stream = alloc_audio_stream(context, rd, fmt->audio_codec, of, error, sizeof(error));
- if (!context->audio_stream) {
- if (error[0])
- BKE_report(reports, RPT_ERROR, error);
- else
- BKE_report(reports, RPT_ERROR, "Error initializing audio stream");
- goto fail;
- }
- }
- if (!(fmt->flags & AVFMT_NOFILE)) {
- if (avio_open(&of->pb, name, AVIO_FLAG_WRITE) < 0) {
- BKE_report(reports, RPT_ERROR, "Could not open file for writing");
- goto fail;
- }
- }
-
- if (context->stamp_data != NULL) {
- BKE_stamp_info_callback(&of->metadata, context->stamp_data, ffmpeg_add_metadata_callback, false);
- }
-
- if (avformat_write_header(of, NULL) < 0) {
- BKE_report(reports, RPT_ERROR, "Could not initialize streams, probably unsupported codec combination");
- goto fail;
- }
-
- context->outfile = of;
- av_dump_format(of, 0, name, 1);
- av_dict_free(&opts);
-
- return 1;
-
+ /* Handle to the output file */
+ AVFormatContext *of;
+ AVOutputFormat *fmt;
+ AVDictionary *opts = NULL;
+ char name[FILE_MAX], error[1024];
+ const char **exts;
+
+ context->ffmpeg_type = rd->ffcodecdata.type;
+ context->ffmpeg_codec = rd->ffcodecdata.codec;
+ context->ffmpeg_audio_codec = rd->ffcodecdata.audio_codec;
+ context->ffmpeg_video_bitrate = rd->ffcodecdata.video_bitrate;
+ context->ffmpeg_audio_bitrate = rd->ffcodecdata.audio_bitrate;
+ context->ffmpeg_gop_size = rd->ffcodecdata.gop_size;
+ context->ffmpeg_autosplit = rd->ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT;
+ context->ffmpeg_crf = rd->ffcodecdata.constant_rate_factor;
+ context->ffmpeg_preset = rd->ffcodecdata.ffmpeg_preset;
+
+ if ((rd->ffcodecdata.flags & FFMPEG_USE_MAX_B_FRAMES) != 0) {
+ context->ffmpeg_max_b_frames = rd->ffcodecdata.max_b_frames;
+ }
+
+ /* Determine the correct filename */
+ ffmpeg_filepath_get(context, name, rd, context->ffmpeg_preview, suffix);
+ PRINT(
+ "Starting output to %s(ffmpeg)...\n"
+ " Using type=%d, codec=%d, audio_codec=%d,\n"
+ " video_bitrate=%d, audio_bitrate=%d,\n"
+ " gop_size=%d, autosplit=%d\n"
+ " render width=%d, render height=%d\n",
+ name,
+ context->ffmpeg_type,
+ context->ffmpeg_codec,
+ context->ffmpeg_audio_codec,
+ context->ffmpeg_video_bitrate,
+ context->ffmpeg_audio_bitrate,
+ context->ffmpeg_gop_size,
+ context->ffmpeg_autosplit,
+ rectx,
+ recty);
+
+ exts = get_file_extensions(context->ffmpeg_type);
+ if (!exts) {
+ BKE_report(reports, RPT_ERROR, "No valid formats found");
+ return 0;
+ }
+ fmt = av_guess_format(NULL, exts[0], NULL);
+ if (!fmt) {
+ BKE_report(reports, RPT_ERROR, "No valid formats found");
+ return 0;
+ }
+
+ of = avformat_alloc_context();
+ if (!of) {
+ BKE_report(reports, RPT_ERROR, "Error opening output file");
+ return 0;
+ }
+
+ /* Returns after this must 'goto fail;' */
+
+ of->oformat = fmt;
+
+ /* Only bother with setting packet size & mux rate when CRF is not used. */
+ if (context->ffmpeg_crf == 0) {
+ of->packet_size = rd->ffcodecdata.mux_packet_size;
+ if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE) {
+ ffmpeg_dict_set_int(&opts, "muxrate", rd->ffcodecdata.mux_rate);
+ }
+ else {
+ av_dict_set(&opts, "muxrate", "0", 0);
+ }
+ }
+
+ ffmpeg_dict_set_int(&opts, "preload", (int)(0.5 * AV_TIME_BASE));
+
+ of->max_delay = (int)(0.7 * AV_TIME_BASE);
+
+ fmt->audio_codec = context->ffmpeg_audio_codec;
+
+ BLI_strncpy(of->filename, name, sizeof(of->filename));
+ /* set the codec to the user's selection */
+ switch (context->ffmpeg_type) {
+ case FFMPEG_AVI:
+ case FFMPEG_MOV:
+ case FFMPEG_MKV:
+ fmt->video_codec = context->ffmpeg_codec;
+ break;
+ case FFMPEG_OGG:
+ fmt->video_codec = AV_CODEC_ID_THEORA;
+ break;
+ case FFMPEG_DV:
+ fmt->video_codec = AV_CODEC_ID_DVVIDEO;
+ break;
+ case FFMPEG_MPEG1:
+ fmt->video_codec = AV_CODEC_ID_MPEG1VIDEO;
+ break;
+ case FFMPEG_MPEG2:
+ fmt->video_codec = AV_CODEC_ID_MPEG2VIDEO;
+ break;
+ case FFMPEG_H264:
+ fmt->video_codec = AV_CODEC_ID_H264;
+ break;
+ case FFMPEG_XVID:
+ fmt->video_codec = AV_CODEC_ID_MPEG4;
+ break;
+ case FFMPEG_FLV:
+ fmt->video_codec = AV_CODEC_ID_FLV1;
+ break;
+ case FFMPEG_MPEG4:
+ default:
+ fmt->video_codec = context->ffmpeg_codec;
+ break;
+ }
+ if (fmt->video_codec == AV_CODEC_ID_DVVIDEO) {
+ if (rectx != 720) {
+ BKE_report(reports, RPT_ERROR, "Render width has to be 720 pixels for DV!");
+ goto fail;
+ }
+ if (rd->frs_sec != 25 && recty != 480) {
+ BKE_report(reports, RPT_ERROR, "Render height has to be 480 pixels for DV-NTSC!");
+ goto fail;
+ }
+ if (rd->frs_sec == 25 && recty != 576) {
+ BKE_report(reports, RPT_ERROR, "Render height has to be 576 pixels for DV-PAL!");
+ goto fail;
+ }
+ }
+
+ if (context->ffmpeg_type == FFMPEG_DV) {
+ fmt->audio_codec = AV_CODEC_ID_PCM_S16LE;
+ if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE &&
+ rd->ffcodecdata.audio_mixrate != 48000 && rd->ffcodecdata.audio_channels != 2) {
+ BKE_report(reports, RPT_ERROR, "FFMPEG only supports 48khz / stereo audio for DV!");
+ goto fail;
+ }
+ }
+
+ if (fmt->video_codec != AV_CODEC_ID_NONE) {
+ context->video_stream = alloc_video_stream(
+ context, rd, fmt->video_codec, of, rectx, recty, error, sizeof(error));
+ PRINT("alloc video stream %p\n", context->video_stream);
+ if (!context->video_stream) {
+ if (error[0])
+ BKE_report(reports, RPT_ERROR, error);
+ else
+ BKE_report(reports, RPT_ERROR, "Error initializing video stream");
+ goto fail;
+ }
+ }
+
+ if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE) {
+ context->audio_stream = alloc_audio_stream(
+ context, rd, fmt->audio_codec, of, error, sizeof(error));
+ if (!context->audio_stream) {
+ if (error[0])
+ BKE_report(reports, RPT_ERROR, error);
+ else
+ BKE_report(reports, RPT_ERROR, "Error initializing audio stream");
+ goto fail;
+ }
+ }
+ if (!(fmt->flags & AVFMT_NOFILE)) {
+ if (avio_open(&of->pb, name, AVIO_FLAG_WRITE) < 0) {
+ BKE_report(reports, RPT_ERROR, "Could not open file for writing");
+ goto fail;
+ }
+ }
+
+ if (context->stamp_data != NULL) {
+ BKE_stamp_info_callback(
+ &of->metadata, context->stamp_data, ffmpeg_add_metadata_callback, false);
+ }
+
+ if (avformat_write_header(of, NULL) < 0) {
+ BKE_report(reports,
+ RPT_ERROR,
+ "Could not initialize streams, probably unsupported codec combination");
+ goto fail;
+ }
+
+ context->outfile = of;
+ av_dump_format(of, 0, name, 1);
+ av_dict_free(&opts);
+
+ return 1;
fail:
- if (of->pb) {
- avio_close(of->pb);
- }
-
- if (context->video_stream && context->video_stream->codec) {
- avcodec_close(context->video_stream->codec);
- context->video_stream = NULL;
- }
-
- if (context->audio_stream && context->audio_stream->codec) {
- avcodec_close(context->audio_stream->codec);
- context->audio_stream = NULL;
- }
-
- av_dict_free(&opts);
- avformat_free_context(of);
- return 0;
+ if (of->pb) {
+ avio_close(of->pb);
+ }
+
+ if (context->video_stream && context->video_stream->codec) {
+ avcodec_close(context->video_stream->codec);
+ context->video_stream = NULL;
+ }
+
+ if (context->audio_stream && context->audio_stream->codec) {
+ avcodec_close(context->audio_stream->codec);
+ context->audio_stream = NULL;
+ }
+
+ av_dict_free(&opts);
+ avformat_free_context(of);
+ return 0;
}
/**
@@ -1065,46 +1124,46 @@ fail:
*/
static void flush_ffmpeg(FFMpegContext *context)
{
- int ret = 0;
-
- AVCodecContext *c = context->video_stream->codec;
- /* get the delayed frames */
- while (1) {
- int got_output;
- AVPacket packet = { 0 };
- av_init_packet(&packet);
-
- ret = avcodec_encode_video2(c, &packet, NULL, &got_output);
- if (ret < 0) {
- fprintf(stderr, "Error encoding delayed frame %d\n", ret);
- break;
- }
- if (!got_output) {
- break;
- }
- if (packet.pts != AV_NOPTS_VALUE) {
- packet.pts = av_rescale_q(packet.pts, c->time_base, context->video_stream->time_base);
- PRINT("Video Frame PTS: %d\n", (int) packet.pts);
- }
- else {
- PRINT("Video Frame PTS: not set\n");
- }
- if (packet.dts != AV_NOPTS_VALUE) {
- packet.dts = av_rescale_q(packet.dts, c->time_base, context->video_stream->time_base);
- PRINT("Video Frame DTS: %d\n", (int) packet.dts);
- }
- else {
- PRINT("Video Frame DTS: not set\n");
- }
-
- packet.stream_index = context->video_stream->index;
- ret = av_interleaved_write_frame(context->outfile, &packet);
- if (ret != 0) {
- fprintf(stderr, "Error writing delayed frame %d\n", ret);
- break;
- }
- }
- avcodec_flush_buffers(context->video_stream->codec);
+ int ret = 0;
+
+ AVCodecContext *c = context->video_stream->codec;
+ /* get the delayed frames */
+ while (1) {
+ int got_output;
+ AVPacket packet = {0};
+ av_init_packet(&packet);
+
+ ret = avcodec_encode_video2(c, &packet, NULL, &got_output);
+ if (ret < 0) {
+ fprintf(stderr, "Error encoding delayed frame %d\n", ret);
+ break;
+ }
+ if (!got_output) {
+ break;
+ }
+ if (packet.pts != AV_NOPTS_VALUE) {
+ packet.pts = av_rescale_q(packet.pts, c->time_base, context->video_stream->time_base);
+ PRINT("Video Frame PTS: %d\n", (int)packet.pts);
+ }
+ else {
+ PRINT("Video Frame PTS: not set\n");
+ }
+ if (packet.dts != AV_NOPTS_VALUE) {
+ packet.dts = av_rescale_q(packet.dts, c->time_base, context->video_stream->time_base);
+ PRINT("Video Frame DTS: %d\n", (int)packet.dts);
+ }
+ else {
+ PRINT("Video Frame DTS: not set\n");
+ }
+
+ packet.stream_index = context->video_stream->index;
+ ret = av_interleaved_write_frame(context->outfile, &packet);
+ if (ret != 0) {
+ fprintf(stderr, "Error writing delayed frame %d\n", ret);
+ break;
+ }
+ }
+ avcodec_flush_buffers(context->video_stream->codec);
}
/* **********************************************************************
@@ -1112,658 +1171,675 @@ static void flush_ffmpeg(FFMpegContext *context)
* ********************************************************************** */
/* Get the output filename-- similar to the other output formats */
-static void ffmpeg_filepath_get(FFMpegContext *context, char *string, RenderData *rd, bool preview, const char *suffix)
+static void ffmpeg_filepath_get(
+ FFMpegContext *context, char *string, RenderData *rd, bool preview, const char *suffix)
{
- char autosplit[20];
-
- const char **exts = get_file_extensions(rd->ffcodecdata.type);
- const char **fe = exts;
- int sfra, efra;
-
- if (!string || !exts) return;
-
- if (preview) {
- sfra = rd->psfra;
- efra = rd->pefra;
- }
- else {
- sfra = rd->sfra;
- efra = rd->efra;
- }
-
- strcpy(string, rd->pic);
- BLI_path_abs(string, BKE_main_blendfile_path_from_global());
-
- BLI_make_existing_file(string);
-
- autosplit[0] = '\0';
-
- if ((rd->ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT) != 0) {
- if (context) {
- sprintf(autosplit, "_%03d", context->ffmpeg_autosplit_count);
- }
- }
-
- if (rd->scemode & R_EXTENSION) {
- while (*fe) {
- if (BLI_strcasecmp(string + strlen(string) - strlen(*fe), *fe) == 0) {
- break;
- }
- fe++;
- }
-
- if (*fe == NULL) {
- strcat(string, autosplit);
-
- BLI_path_frame_range(string, sfra, efra, 4);
- strcat(string, *exts);
- }
- else {
- *(string + strlen(string) - strlen(*fe)) = '\0';
- strcat(string, autosplit);
- strcat(string, *fe);
- }
- }
- else {
- if (BLI_path_frame_check_chars(string)) {
- BLI_path_frame_range(string, sfra, efra, 4);
- }
-
- strcat(string, autosplit);
- }
-
- BLI_path_suffix(string, FILE_MAX, suffix, "");
+ char autosplit[20];
+
+ const char **exts = get_file_extensions(rd->ffcodecdata.type);
+ const char **fe = exts;
+ int sfra, efra;
+
+ if (!string || !exts)
+ return;
+
+ if (preview) {
+ sfra = rd->psfra;
+ efra = rd->pefra;
+ }
+ else {
+ sfra = rd->sfra;
+ efra = rd->efra;
+ }
+
+ strcpy(string, rd->pic);
+ BLI_path_abs(string, BKE_main_blendfile_path_from_global());
+
+ BLI_make_existing_file(string);
+
+ autosplit[0] = '\0';
+
+ if ((rd->ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT) != 0) {
+ if (context) {
+ sprintf(autosplit, "_%03d", context->ffmpeg_autosplit_count);
+ }
+ }
+
+ if (rd->scemode & R_EXTENSION) {
+ while (*fe) {
+ if (BLI_strcasecmp(string + strlen(string) - strlen(*fe), *fe) == 0) {
+ break;
+ }
+ fe++;
+ }
+
+ if (*fe == NULL) {
+ strcat(string, autosplit);
+
+ BLI_path_frame_range(string, sfra, efra, 4);
+ strcat(string, *exts);
+ }
+ else {
+ *(string + strlen(string) - strlen(*fe)) = '\0';
+ strcat(string, autosplit);
+ strcat(string, *fe);
+ }
+ }
+ else {
+ if (BLI_path_frame_check_chars(string)) {
+ BLI_path_frame_range(string, sfra, efra, 4);
+ }
+
+ strcat(string, autosplit);
+ }
+
+ BLI_path_suffix(string, FILE_MAX, suffix, "");
}
void BKE_ffmpeg_filepath_get(char *string, RenderData *rd, bool preview, const char *suffix)
{
- ffmpeg_filepath_get(NULL, string, rd, preview, suffix);
+ ffmpeg_filepath_get(NULL, string, rd, preview, suffix);
}
-int BKE_ffmpeg_start(void *context_v, struct Scene *scene, RenderData *rd, int rectx, int recty,
- ReportList *reports, bool preview, const char *suffix)
+int BKE_ffmpeg_start(void *context_v,
+ struct Scene *scene,
+ RenderData *rd,
+ int rectx,
+ int recty,
+ ReportList *reports,
+ bool preview,
+ const char *suffix)
{
- int success;
- FFMpegContext *context = context_v;
-
- context->ffmpeg_autosplit_count = 0;
- context->ffmpeg_preview = preview;
- context->stamp_data = BKE_stamp_info_from_scene_static(scene);
-
- success = start_ffmpeg_impl(context, rd, rectx, recty, suffix, reports);
-#ifdef WITH_AUDASPACE
- if (context->audio_stream) {
- AVCodecContext *c = context->audio_stream->codec;
- AUD_DeviceSpecs specs;
- specs.channels = c->channels;
-
- switch (av_get_packed_sample_fmt(c->sample_fmt)) {
- case AV_SAMPLE_FMT_U8:
- specs.format = AUD_FORMAT_U8;
- break;
- case AV_SAMPLE_FMT_S16:
- specs.format = AUD_FORMAT_S16;
- break;
- case AV_SAMPLE_FMT_S32:
- specs.format = AUD_FORMAT_S32;
- break;
- case AV_SAMPLE_FMT_FLT:
- specs.format = AUD_FORMAT_FLOAT32;
- break;
- case AV_SAMPLE_FMT_DBL:
- specs.format = AUD_FORMAT_FLOAT64;
- break;
- default:
- return -31415;
- }
-
- specs.rate = rd->ffcodecdata.audio_mixrate;
- context->audio_mixdown_device = BKE_sound_mixdown(scene, specs, preview ? rd->psfra : rd->sfra, rd->ffcodecdata.audio_volume);
-#ifdef FFMPEG_CODEC_TIME_BASE
- c->time_base.den = specs.rate;
- c->time_base.num = 1;
-#endif
- }
-#endif
- return success;
+ int success;
+ FFMpegContext *context = context_v;
+
+ context->ffmpeg_autosplit_count = 0;
+ context->ffmpeg_preview = preview;
+ context->stamp_data = BKE_stamp_info_from_scene_static(scene);
+
+ success = start_ffmpeg_impl(context, rd, rectx, recty, suffix, reports);
+# ifdef WITH_AUDASPACE
+ if (context->audio_stream) {
+ AVCodecContext *c = context->audio_stream->codec;
+ AUD_DeviceSpecs specs;
+ specs.channels = c->channels;
+
+ switch (av_get_packed_sample_fmt(c->sample_fmt)) {
+ case AV_SAMPLE_FMT_U8:
+ specs.format = AUD_FORMAT_U8;
+ break;
+ case AV_SAMPLE_FMT_S16:
+ specs.format = AUD_FORMAT_S16;
+ break;
+ case AV_SAMPLE_FMT_S32:
+ specs.format = AUD_FORMAT_S32;
+ break;
+ case AV_SAMPLE_FMT_FLT:
+ specs.format = AUD_FORMAT_FLOAT32;
+ break;
+ case AV_SAMPLE_FMT_DBL:
+ specs.format = AUD_FORMAT_FLOAT64;
+ break;
+ default:
+ return -31415;
+ }
+
+ specs.rate = rd->ffcodecdata.audio_mixrate;
+ context->audio_mixdown_device = BKE_sound_mixdown(
+ scene, specs, preview ? rd->psfra : rd->sfra, rd->ffcodecdata.audio_volume);
+# ifdef FFMPEG_CODEC_TIME_BASE
+ c->time_base.den = specs.rate;
+ c->time_base.num = 1;
+# endif
+ }
+# endif
+ return success;
}
static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit);
-#ifdef WITH_AUDASPACE
+# ifdef WITH_AUDASPACE
static void write_audio_frames(FFMpegContext *context, double to_pts)
{
- int finished = 0;
-
- while (context->audio_stream && !finished) {
- if ((context->audio_time >= to_pts) ||
- (write_audio_frame(context)))
- {
- finished = 1;
- }
- }
-}
-#endif
+ int finished = 0;
-int BKE_ffmpeg_append(void *context_v, RenderData *rd, int start_frame, int frame, int *pixels,
- int rectx, int recty, const char *suffix, ReportList *reports)
+ while (context->audio_stream && !finished) {
+ if ((context->audio_time >= to_pts) || (write_audio_frame(context))) {
+ finished = 1;
+ }
+ }
+}
+# endif
+
+int BKE_ffmpeg_append(void *context_v,
+ RenderData *rd,
+ int start_frame,
+ int frame,
+ int *pixels,
+ int rectx,
+ int recty,
+ const char *suffix,
+ ReportList *reports)
{
- FFMpegContext *context = context_v;
- AVFrame *avframe;
- int success = 1;
-
- PRINT("Writing frame %i, render width=%d, render height=%d\n", frame, rectx, recty);
-
-/* why is this done before writing the video frame and again at end_ffmpeg? */
-// write_audio_frames(frame / (((double)rd->frs_sec) / rd->frs_sec_base));
-
- if (context->video_stream) {
- avframe = generate_video_frame(context, (unsigned char *) pixels, reports);
- success = (avframe && write_video_frame(context, rd, frame - start_frame, avframe, reports));
-
- if (context->ffmpeg_autosplit) {
- if (avio_tell(context->outfile->pb) > FFMPEG_AUTOSPLIT_SIZE) {
- end_ffmpeg_impl(context, true);
- context->ffmpeg_autosplit_count++;
- success &= start_ffmpeg_impl(context, rd, rectx, recty, suffix, reports);
- }
- }
- }
-
-#ifdef WITH_AUDASPACE
- write_audio_frames(context, (frame - start_frame) / (((double)rd->frs_sec) / (double)rd->frs_sec_base));
-#endif
- return success;
+ FFMpegContext *context = context_v;
+ AVFrame *avframe;
+ int success = 1;
+
+ PRINT("Writing frame %i, render width=%d, render height=%d\n", frame, rectx, recty);
+
+ /* why is this done before writing the video frame and again at end_ffmpeg? */
+ // write_audio_frames(frame / (((double)rd->frs_sec) / rd->frs_sec_base));
+
+ if (context->video_stream) {
+ avframe = generate_video_frame(context, (unsigned char *)pixels, reports);
+ success = (avframe && write_video_frame(context, rd, frame - start_frame, avframe, reports));
+
+ if (context->ffmpeg_autosplit) {
+ if (avio_tell(context->outfile->pb) > FFMPEG_AUTOSPLIT_SIZE) {
+ end_ffmpeg_impl(context, true);
+ context->ffmpeg_autosplit_count++;
+ success &= start_ffmpeg_impl(context, rd, rectx, recty, suffix, reports);
+ }
+ }
+ }
+
+# ifdef WITH_AUDASPACE
+ write_audio_frames(context,
+ (frame - start_frame) / (((double)rd->frs_sec) / (double)rd->frs_sec_base));
+# endif
+ return success;
}
static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit)
{
- PRINT("Closing ffmpeg...\n");
-
-#ifdef WITH_AUDASPACE
- if (is_autosplit == false) {
- if (context->audio_mixdown_device) {
- AUD_Device_free(context->audio_mixdown_device);
- context->audio_mixdown_device = NULL;
- }
- }
-#endif
-
- if (context->video_stream && context->video_stream->codec) {
- PRINT("Flushing delayed frames...\n");
- flush_ffmpeg(context);
- }
-
- if (context->outfile) {
- av_write_trailer(context->outfile);
- }
-
- /* Close the video codec */
-
- if (context->video_stream != NULL && context->video_stream->codec != NULL) {
- avcodec_close(context->video_stream->codec);
- PRINT("zero video stream %p\n", context->video_stream);
- context->video_stream = NULL;
- }
-
- if (context->audio_stream != NULL && context->audio_stream->codec != NULL) {
- avcodec_close(context->audio_stream->codec);
- context->audio_stream = NULL;
- }
-
- /* free the temp buffer */
- if (context->current_frame != NULL) {
- delete_picture(context->current_frame);
- context->current_frame = NULL;
- }
- if (context->outfile != NULL && context->outfile->oformat) {
- if (!(context->outfile->oformat->flags & AVFMT_NOFILE)) {
- avio_close(context->outfile->pb);
- }
- }
- if (context->outfile != NULL) {
- avformat_free_context(context->outfile);
- context->outfile = NULL;
- }
- if (context->audio_input_buffer != NULL) {
- av_free(context->audio_input_buffer);
- context->audio_input_buffer = NULL;
- }
-#ifndef FFMPEG_HAVE_ENCODE_AUDIO2
- if (context->audio_output_buffer != NULL) {
- av_free(context->audio_output_buffer);
- context->audio_output_buffer = NULL;
- }
-#endif
-
- if (context->audio_deinterleave_buffer != NULL) {
- av_free(context->audio_deinterleave_buffer);
- context->audio_deinterleave_buffer = NULL;
- }
-
- if (context->img_convert_ctx != NULL) {
- sws_freeContext(context->img_convert_ctx);
- context->img_convert_ctx = NULL;
- }
+ PRINT("Closing ffmpeg...\n");
+
+# ifdef WITH_AUDASPACE
+ if (is_autosplit == false) {
+ if (context->audio_mixdown_device) {
+ AUD_Device_free(context->audio_mixdown_device);
+ context->audio_mixdown_device = NULL;
+ }
+ }
+# endif
+
+ if (context->video_stream && context->video_stream->codec) {
+ PRINT("Flushing delayed frames...\n");
+ flush_ffmpeg(context);
+ }
+
+ if (context->outfile) {
+ av_write_trailer(context->outfile);
+ }
+
+ /* Close the video codec */
+
+ if (context->video_stream != NULL && context->video_stream->codec != NULL) {
+ avcodec_close(context->video_stream->codec);
+ PRINT("zero video stream %p\n", context->video_stream);
+ context->video_stream = NULL;
+ }
+
+ if (context->audio_stream != NULL && context->audio_stream->codec != NULL) {
+ avcodec_close(context->audio_stream->codec);
+ context->audio_stream = NULL;
+ }
+
+ /* free the temp buffer */
+ if (context->current_frame != NULL) {
+ delete_picture(context->current_frame);
+ context->current_frame = NULL;
+ }
+ if (context->outfile != NULL && context->outfile->oformat) {
+ if (!(context->outfile->oformat->flags & AVFMT_NOFILE)) {
+ avio_close(context->outfile->pb);
+ }
+ }
+ if (context->outfile != NULL) {
+ avformat_free_context(context->outfile);
+ context->outfile = NULL;
+ }
+ if (context->audio_input_buffer != NULL) {
+ av_free(context->audio_input_buffer);
+ context->audio_input_buffer = NULL;
+ }
+# ifndef FFMPEG_HAVE_ENCODE_AUDIO2
+ if (context->audio_output_buffer != NULL) {
+ av_free(context->audio_output_buffer);
+ context->audio_output_buffer = NULL;
+ }
+# endif
+
+ if (context->audio_deinterleave_buffer != NULL) {
+ av_free(context->audio_deinterleave_buffer);
+ context->audio_deinterleave_buffer = NULL;
+ }
+
+ if (context->img_convert_ctx != NULL) {
+ sws_freeContext(context->img_convert_ctx);
+ context->img_convert_ctx = NULL;
+ }
}
void BKE_ffmpeg_end(void *context_v)
{
- FFMpegContext *context = context_v;
- end_ffmpeg_impl(context, false);
+ FFMpegContext *context = context_v;
+ end_ffmpeg_impl(context, false);
}
/* properties */
void BKE_ffmpeg_property_del(RenderData *rd, void *type, void *prop_)
{
- struct IDProperty *prop = (struct IDProperty *) prop_;
- IDProperty *group;
+ struct IDProperty *prop = (struct IDProperty *)prop_;
+ IDProperty *group;
- if (!rd->ffcodecdata.properties) {
- return;
- }
+ if (!rd->ffcodecdata.properties) {
+ return;
+ }
- group = IDP_GetPropertyFromGroup(rd->ffcodecdata.properties, type);
- if (group && prop) {
- IDP_FreeFromGroup(group, prop);
- }
+ group = IDP_GetPropertyFromGroup(rd->ffcodecdata.properties, type);
+ if (group && prop) {
+ IDP_FreeFromGroup(group, prop);
+ }
}
-static IDProperty *BKE_ffmpeg_property_add(RenderData *rd, const char *type, const AVOption *o, const AVOption *parent)
+static IDProperty *BKE_ffmpeg_property_add(RenderData *rd,
+ const char *type,
+ const AVOption *o,
+ const AVOption *parent)
{
- AVCodecContext c;
- IDProperty *group;
- IDProperty *prop;
- IDPropertyTemplate val;
- int idp_type;
- char name[256];
-
- val.i = 0;
-
- avcodec_get_context_defaults3(&c, NULL);
-
- if (!rd->ffcodecdata.properties) {
- rd->ffcodecdata.properties = IDP_New(IDP_GROUP, &val, "ffmpeg");
- }
-
- group = IDP_GetPropertyFromGroup(rd->ffcodecdata.properties, type);
-
- if (!group) {
- group = IDP_New(IDP_GROUP, &val, type);
- IDP_AddToGroup(rd->ffcodecdata.properties, group);
- }
-
- if (parent) {
- BLI_snprintf(name, sizeof(name), "%s:%s", parent->name, o->name);
- }
- else {
- BLI_strncpy(name, o->name, sizeof(name));
- }
-
- PRINT("ffmpeg_property_add: %s %s\n", type, name);
-
- prop = IDP_GetPropertyFromGroup(group, name);
- if (prop) {
- return prop;
- }
-
- switch (o->type) {
- case AV_OPT_TYPE_INT:
- case AV_OPT_TYPE_INT64:
- val.i = FFMPEG_DEF_OPT_VAL_INT(o);
- idp_type = IDP_INT;
- break;
- case AV_OPT_TYPE_DOUBLE:
- case AV_OPT_TYPE_FLOAT:
- val.f = FFMPEG_DEF_OPT_VAL_DOUBLE(o);
- idp_type = IDP_FLOAT;
- break;
- case AV_OPT_TYPE_STRING:
- val.string.str = (char *)" ";
- val.string.len = 80;
-/* val.str = (char *)" ";*/
- idp_type = IDP_STRING;
- break;
- case AV_OPT_TYPE_CONST:
- val.i = 1;
- idp_type = IDP_INT;
- break;
- default:
- return NULL;
- }
- prop = IDP_New(idp_type, &val, name);
- IDP_AddToGroup(group, prop);
- return prop;
+ AVCodecContext c;
+ IDProperty *group;
+ IDProperty *prop;
+ IDPropertyTemplate val;
+ int idp_type;
+ char name[256];
+
+ val.i = 0;
+
+ avcodec_get_context_defaults3(&c, NULL);
+
+ if (!rd->ffcodecdata.properties) {
+ rd->ffcodecdata.properties = IDP_New(IDP_GROUP, &val, "ffmpeg");
+ }
+
+ group = IDP_GetPropertyFromGroup(rd->ffcodecdata.properties, type);
+
+ if (!group) {
+ group = IDP_New(IDP_GROUP, &val, type);
+ IDP_AddToGroup(rd->ffcodecdata.properties, group);
+ }
+
+ if (parent) {
+ BLI_snprintf(name, sizeof(name), "%s:%s", parent->name, o->name);
+ }
+ else {
+ BLI_strncpy(name, o->name, sizeof(name));
+ }
+
+ PRINT("ffmpeg_property_add: %s %s\n", type, name);
+
+ prop = IDP_GetPropertyFromGroup(group, name);
+ if (prop) {
+ return prop;
+ }
+
+ switch (o->type) {
+ case AV_OPT_TYPE_INT:
+ case AV_OPT_TYPE_INT64:
+ val.i = FFMPEG_DEF_OPT_VAL_INT(o);
+ idp_type = IDP_INT;
+ break;
+ case AV_OPT_TYPE_DOUBLE:
+ case AV_OPT_TYPE_FLOAT:
+ val.f = FFMPEG_DEF_OPT_VAL_DOUBLE(o);
+ idp_type = IDP_FLOAT;
+ break;
+ case AV_OPT_TYPE_STRING:
+ val.string.str =
+ (char
+ *)" ";
+ val.string.len = 80;
+ /* val.str = (char *)" ";*/
+ idp_type = IDP_STRING;
+ break;
+ case AV_OPT_TYPE_CONST:
+ val.i = 1;
+ idp_type = IDP_INT;
+ break;
+ default:
+ return NULL;
+ }
+ prop = IDP_New(idp_type, &val, name);
+ IDP_AddToGroup(group, prop);
+ return prop;
}
/* not all versions of ffmpeg include that, so here we go ... */
int BKE_ffmpeg_property_add_string(RenderData *rd, const char *type, const char *str)
{
- AVCodecContext c;
- const AVOption *o = NULL;
- const AVOption *p = NULL;
- char name_[128];
- char *name;
- char *param;
- IDProperty *prop = NULL;
-
- avcodec_get_context_defaults3(&c, NULL);
-
- BLI_strncpy(name_, str, sizeof(name_));
-
- name = name_;
- while (*name == ' ') name++;
-
- param = strchr(name, ':');
-
- if (!param) {
- param = strchr(name, ' ');
- }
- if (param) {
- *param++ = '\0';
- while (*param == ' ') param++;
- }
-
- o = av_opt_find(&c, name, NULL, 0, AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ);
- if (!o) {
- PRINT("Ignoring unknown expert option %s\n", str);
- return 0;
- }
- if (param && o->type == AV_OPT_TYPE_CONST) {
- return 0;
- }
- if (param && o->type != AV_OPT_TYPE_CONST && o->unit) {
- p = av_opt_find(&c, param, o->unit, 0, AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ);
- if (p) {
- prop = BKE_ffmpeg_property_add(rd, (char *) type, p, o);
- }
- else {
- PRINT("Ignoring unknown expert option %s\n", str);
- }
- }
- else {
- prop = BKE_ffmpeg_property_add(rd, (char *) type, o, NULL);
- }
-
-
- if (!prop) {
- return 0;
- }
-
- if (param && !p) {
- switch (prop->type) {
- case IDP_INT:
- IDP_Int(prop) = atoi(param);
- break;
- case IDP_FLOAT:
- IDP_Float(prop) = atof(param);
- break;
- case IDP_STRING:
- strncpy(IDP_String(prop), param, prop->len);
- break;
- }
- }
- return 1;
+ AVCodecContext c;
+ const AVOption *o = NULL;
+ const AVOption *p = NULL;
+ char name_[128];
+ char *name;
+ char *param;
+ IDProperty *prop = NULL;
+
+ avcodec_get_context_defaults3(&c, NULL);
+
+ BLI_strncpy(name_, str, sizeof(name_));
+
+ name = name_;
+ while (*name == ' ')
+ name++;
+
+ param = strchr(name, ':');
+
+ if (!param) {
+ param = strchr(name, ' ');
+ }
+ if (param) {
+ *param++ = '\0';
+ while (*param == ' ')
+ param++;
+ }
+
+ o = av_opt_find(&c, name, NULL, 0, AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ);
+ if (!o) {
+ PRINT("Ignoring unknown expert option %s\n", str);
+ return 0;
+ }
+ if (param && o->type == AV_OPT_TYPE_CONST) {
+ return 0;
+ }
+ if (param && o->type != AV_OPT_TYPE_CONST && o->unit) {
+ p = av_opt_find(&c, param, o->unit, 0, AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ);
+ if (p) {
+ prop = BKE_ffmpeg_property_add(rd, (char *)type, p, o);
+ }
+ else {
+ PRINT("Ignoring unknown expert option %s\n", str);
+ }
+ }
+ else {
+ prop = BKE_ffmpeg_property_add(rd, (char *)type, o, NULL);
+ }
+
+ if (!prop) {
+ return 0;
+ }
+
+ if (param && !p) {
+ switch (prop->type) {
+ case IDP_INT:
+ IDP_Int(prop) = atoi(param);
+ break;
+ case IDP_FLOAT:
+ IDP_Float(prop) = atof(param);
+ break;
+ case IDP_STRING:
+ strncpy(IDP_String(prop), param, prop->len);
+ break;
+ }
+ }
+ return 1;
}
static void ffmpeg_set_expert_options(RenderData *rd)
{
- int codec_id = rd->ffcodecdata.codec;
-
- if (rd->ffcodecdata.properties)
- IDP_FreeProperty(rd->ffcodecdata.properties);
-
- if (codec_id == AV_CODEC_ID_H264) {
- /*
- * All options here are for x264, but must be set via ffmpeg.
- * The names are therefore different - Search for "x264 to FFmpeg option mapping"
- * to get a list.
- */
-
- /*
- * Use CABAC coder. Using "coder:1", which should be equivalent,
- * crashes Blender for some reason. Either way - this is no big deal.
- */
- BKE_ffmpeg_property_add_string(rd, "video", "coder:vlc");
-
- /*
- * The other options were taken from the libx264-default.preset
- * included in the ffmpeg distribution.
- */
-// ffmpeg_property_add_string(rd, "video", "flags:loop"); // this breaks compatibility for QT
- BKE_ffmpeg_property_add_string(rd, "video", "cmp:chroma");
- BKE_ffmpeg_property_add_string(rd, "video", "partitions:parti4x4"); // Deprecated.
- BKE_ffmpeg_property_add_string(rd, "video", "partitions:partp8x8"); // Deprecated.
- BKE_ffmpeg_property_add_string(rd, "video", "partitions:partb8x8"); // Deprecated.
- BKE_ffmpeg_property_add_string(rd, "video", "me:hex");
- BKE_ffmpeg_property_add_string(rd, "video", "subq:6");
- BKE_ffmpeg_property_add_string(rd, "video", "me_range:16");
- BKE_ffmpeg_property_add_string(rd, "video", "qdiff:4");
- BKE_ffmpeg_property_add_string(rd, "video", "keyint_min:25");
- BKE_ffmpeg_property_add_string(rd, "video", "sc_threshold:40");
- BKE_ffmpeg_property_add_string(rd, "video", "i_qfactor:0.71");
- BKE_ffmpeg_property_add_string(rd, "video", "b_strategy:1");
- BKE_ffmpeg_property_add_string(rd, "video", "bf:3");
- BKE_ffmpeg_property_add_string(rd, "video", "refs:2");
- BKE_ffmpeg_property_add_string(rd, "video", "qcomp:0.6");
-
- BKE_ffmpeg_property_add_string(rd, "video", "trellis:0");
- BKE_ffmpeg_property_add_string(rd, "video", "weightb:1");
-#ifdef FFMPEG_HAVE_DEPRECATED_FLAGS2
- BKE_ffmpeg_property_add_string(rd, "video", "flags2:dct8x8");
- BKE_ffmpeg_property_add_string(rd, "video", "directpred:3");
- BKE_ffmpeg_property_add_string(rd, "video", "flags2:fastpskip");
- BKE_ffmpeg_property_add_string(rd, "video", "flags2:wpred");
-#else
- BKE_ffmpeg_property_add_string(rd, "video", "8x8dct:1");
- BKE_ffmpeg_property_add_string(rd, "video", "fast-pskip:1");
- BKE_ffmpeg_property_add_string(rd, "video", "wpredp:2");
-#endif
- }
- else if (codec_id == AV_CODEC_ID_DNXHD) {
- if (rd->ffcodecdata.flags & FFMPEG_LOSSLESS_OUTPUT)
- BKE_ffmpeg_property_add_string(rd, "video", "mbd:rd");
- }
+ int codec_id = rd->ffcodecdata.codec;
+
+ if (rd->ffcodecdata.properties)
+ IDP_FreeProperty(rd->ffcodecdata.properties);
+
+ if (codec_id == AV_CODEC_ID_H264) {
+ /*
+ * All options here are for x264, but must be set via ffmpeg.
+ * The names are therefore different - Search for "x264 to FFmpeg option mapping"
+ * to get a list.
+ */
+
+ /*
+ * Use CABAC coder. Using "coder:1", which should be equivalent,
+ * crashes Blender for some reason. Either way - this is no big deal.
+ */
+ BKE_ffmpeg_property_add_string(rd, "video", "coder:vlc");
+
+ /*
+ * The other options were taken from the libx264-default.preset
+ * included in the ffmpeg distribution.
+ */
+ // ffmpeg_property_add_string(rd, "video", "flags:loop"); // this breaks compatibility for QT
+ BKE_ffmpeg_property_add_string(rd, "video", "cmp:chroma");
+ BKE_ffmpeg_property_add_string(rd, "video", "partitions:parti4x4"); // Deprecated.
+ BKE_ffmpeg_property_add_string(rd, "video", "partitions:partp8x8"); // Deprecated.
+ BKE_ffmpeg_property_add_string(rd, "video", "partitions:partb8x8"); // Deprecated.
+ BKE_ffmpeg_property_add_string(rd, "video", "me:hex");
+ BKE_ffmpeg_property_add_string(rd, "video", "subq:6");
+ BKE_ffmpeg_property_add_string(rd, "video", "me_range:16");
+ BKE_ffmpeg_property_add_string(rd, "video", "qdiff:4");
+ BKE_ffmpeg_property_add_string(rd, "video", "keyint_min:25");
+ BKE_ffmpeg_property_add_string(rd, "video", "sc_threshold:40");
+ BKE_ffmpeg_property_add_string(rd, "video", "i_qfactor:0.71");
+ BKE_ffmpeg_property_add_string(rd, "video", "b_strategy:1");
+ BKE_ffmpeg_property_add_string(rd, "video", "bf:3");
+ BKE_ffmpeg_property_add_string(rd, "video", "refs:2");
+ BKE_ffmpeg_property_add_string(rd, "video", "qcomp:0.6");
+
+ BKE_ffmpeg_property_add_string(rd, "video", "trellis:0");
+ BKE_ffmpeg_property_add_string(rd, "video", "weightb:1");
+# ifdef FFMPEG_HAVE_DEPRECATED_FLAGS2
+ BKE_ffmpeg_property_add_string(rd, "video", "flags2:dct8x8");
+ BKE_ffmpeg_property_add_string(rd, "video", "directpred:3");
+ BKE_ffmpeg_property_add_string(rd, "video", "flags2:fastpskip");
+ BKE_ffmpeg_property_add_string(rd, "video", "flags2:wpred");
+# else
+ BKE_ffmpeg_property_add_string(rd, "video", "8x8dct:1");
+ BKE_ffmpeg_property_add_string(rd, "video", "fast-pskip:1");
+ BKE_ffmpeg_property_add_string(rd, "video", "wpredp:2");
+# endif
+ }
+ else if (codec_id == AV_CODEC_ID_DNXHD) {
+ if (rd->ffcodecdata.flags & FFMPEG_LOSSLESS_OUTPUT)
+ BKE_ffmpeg_property_add_string(rd, "video", "mbd:rd");
+ }
}
void BKE_ffmpeg_preset_set(RenderData *rd, int preset)
{
- int isntsc = (rd->frs_sec != 25);
-
- if (rd->ffcodecdata.properties)
- IDP_FreeProperty(rd->ffcodecdata.properties);
-
- switch (preset) {
- case FFMPEG_PRESET_VCD:
- rd->ffcodecdata.type = FFMPEG_MPEG1;
- rd->ffcodecdata.video_bitrate = 1150;
- rd->xsch = 352;
- rd->ysch = isntsc ? 240 : 288;
- rd->ffcodecdata.gop_size = isntsc ? 18 : 15;
- rd->ffcodecdata.rc_max_rate = 1150;
- rd->ffcodecdata.rc_min_rate = 1150;
- rd->ffcodecdata.rc_buffer_size = 40 * 8;
- rd->ffcodecdata.mux_packet_size = 2324;
- rd->ffcodecdata.mux_rate = 2352 * 75 * 8;
- break;
-
- case FFMPEG_PRESET_SVCD:
- rd->ffcodecdata.type = FFMPEG_MPEG2;
- rd->ffcodecdata.video_bitrate = 2040;
- rd->xsch = 480;
- rd->ysch = isntsc ? 480 : 576;
- rd->ffcodecdata.gop_size = isntsc ? 18 : 15;
- rd->ffcodecdata.rc_max_rate = 2516;
- rd->ffcodecdata.rc_min_rate = 0;
- rd->ffcodecdata.rc_buffer_size = 224 * 8;
- rd->ffcodecdata.mux_packet_size = 2324;
- rd->ffcodecdata.mux_rate = 0;
- break;
-
- case FFMPEG_PRESET_DVD:
- rd->ffcodecdata.type = FFMPEG_MPEG2;
- rd->ffcodecdata.video_bitrate = 6000;
-
- /* Don't set resolution, see [#21351]
- * rd->xsch = 720;
- * rd->ysch = isntsc ? 480 : 576; */
-
- rd->ffcodecdata.gop_size = isntsc ? 18 : 15;
- rd->ffcodecdata.rc_max_rate = 9000;
- rd->ffcodecdata.rc_min_rate = 0;
- rd->ffcodecdata.rc_buffer_size = 224 * 8;
- rd->ffcodecdata.mux_packet_size = 2048;
- rd->ffcodecdata.mux_rate = 10080000;
- break;
-
- case FFMPEG_PRESET_DV:
- rd->ffcodecdata.type = FFMPEG_DV;
- rd->xsch = 720;
- rd->ysch = isntsc ? 480 : 576;
- break;
-
- case FFMPEG_PRESET_H264:
- rd->ffcodecdata.type = FFMPEG_AVI;
- rd->ffcodecdata.codec = AV_CODEC_ID_H264;
- rd->ffcodecdata.video_bitrate = 6000;
- rd->ffcodecdata.gop_size = isntsc ? 18 : 15;
- rd->ffcodecdata.rc_max_rate = 9000;
- rd->ffcodecdata.rc_min_rate = 0;
- rd->ffcodecdata.rc_buffer_size = 224 * 8;
- rd->ffcodecdata.mux_packet_size = 2048;
- rd->ffcodecdata.mux_rate = 10080000;
-
- break;
-
- case FFMPEG_PRESET_THEORA:
- case FFMPEG_PRESET_XVID:
- if (preset == FFMPEG_PRESET_XVID) {
- rd->ffcodecdata.type = FFMPEG_AVI;
- rd->ffcodecdata.codec = AV_CODEC_ID_MPEG4;
- }
- else if (preset == FFMPEG_PRESET_THEORA) {
- rd->ffcodecdata.type = FFMPEG_OGG; // XXX broken
- rd->ffcodecdata.codec = AV_CODEC_ID_THEORA;
- }
-
- rd->ffcodecdata.video_bitrate = 6000;
- rd->ffcodecdata.gop_size = isntsc ? 18 : 15;
- rd->ffcodecdata.rc_max_rate = 9000;
- rd->ffcodecdata.rc_min_rate = 0;
- rd->ffcodecdata.rc_buffer_size = 224 * 8;
- rd->ffcodecdata.mux_packet_size = 2048;
- rd->ffcodecdata.mux_rate = 10080000;
- break;
-
- }
-
- ffmpeg_set_expert_options(rd);
+ int isntsc = (rd->frs_sec != 25);
+
+ if (rd->ffcodecdata.properties)
+ IDP_FreeProperty(rd->ffcodecdata.properties);
+
+ switch (preset) {
+ case FFMPEG_PRESET_VCD:
+ rd->ffcodecdata.type = FFMPEG_MPEG1;
+ rd->ffcodecdata.video_bitrate = 1150;
+ rd->xsch = 352;
+ rd->ysch = isntsc ? 240 : 288;
+ rd->ffcodecdata.gop_size = isntsc ? 18 : 15;
+ rd->ffcodecdata.rc_max_rate = 1150;
+ rd->ffcodecdata.rc_min_rate = 1150;
+ rd->ffcodecdata.rc_buffer_size = 40 * 8;
+ rd->ffcodecdata.mux_packet_size = 2324;
+ rd->ffcodecdata.mux_rate = 2352 * 75 * 8;
+ break;
+
+ case FFMPEG_PRESET_SVCD:
+ rd->ffcodecdata.type = FFMPEG_MPEG2;
+ rd->ffcodecdata.video_bitrate = 2040;
+ rd->xsch = 480;
+ rd->ysch = isntsc ? 480 : 576;
+ rd->ffcodecdata.gop_size = isntsc ? 18 : 15;
+ rd->ffcodecdata.rc_max_rate = 2516;
+ rd->ffcodecdata.rc_min_rate = 0;
+ rd->ffcodecdata.rc_buffer_size = 224 * 8;
+ rd->ffcodecdata.mux_packet_size = 2324;
+ rd->ffcodecdata.mux_rate = 0;
+ break;
+
+ case FFMPEG_PRESET_DVD:
+ rd->ffcodecdata.type = FFMPEG_MPEG2;
+ rd->ffcodecdata.video_bitrate = 6000;
+
+ /* Don't set resolution, see [#21351]
+ * rd->xsch = 720;
+ * rd->ysch = isntsc ? 480 : 576; */
+
+ rd->ffcodecdata.gop_size = isntsc ? 18 : 15;
+ rd->ffcodecdata.rc_max_rate = 9000;
+ rd->ffcodecdata.rc_min_rate = 0;
+ rd->ffcodecdata.rc_buffer_size = 224 * 8;
+ rd->ffcodecdata.mux_packet_size = 2048;
+ rd->ffcodecdata.mux_rate = 10080000;
+ break;
+
+ case FFMPEG_PRESET_DV:
+ rd->ffcodecdata.type = FFMPEG_DV;
+ rd->xsch = 720;
+ rd->ysch = isntsc ? 480 : 576;
+ break;
+
+ case FFMPEG_PRESET_H264:
+ rd->ffcodecdata.type = FFMPEG_AVI;
+ rd->ffcodecdata.codec = AV_CODEC_ID_H264;
+ rd->ffcodecdata.video_bitrate = 6000;
+ rd->ffcodecdata.gop_size = isntsc ? 18 : 15;
+ rd->ffcodecdata.rc_max_rate = 9000;
+ rd->ffcodecdata.rc_min_rate = 0;
+ rd->ffcodecdata.rc_buffer_size = 224 * 8;
+ rd->ffcodecdata.mux_packet_size = 2048;
+ rd->ffcodecdata.mux_rate = 10080000;
+
+ break;
+
+ case FFMPEG_PRESET_THEORA:
+ case FFMPEG_PRESET_XVID:
+ if (preset == FFMPEG_PRESET_XVID) {
+ rd->ffcodecdata.type = FFMPEG_AVI;
+ rd->ffcodecdata.codec = AV_CODEC_ID_MPEG4;
+ }
+ else if (preset == FFMPEG_PRESET_THEORA) {
+ rd->ffcodecdata.type = FFMPEG_OGG; // XXX broken
+ rd->ffcodecdata.codec = AV_CODEC_ID_THEORA;
+ }
+
+ rd->ffcodecdata.video_bitrate = 6000;
+ rd->ffcodecdata.gop_size = isntsc ? 18 : 15;
+ rd->ffcodecdata.rc_max_rate = 9000;
+ rd->ffcodecdata.rc_min_rate = 0;
+ rd->ffcodecdata.rc_buffer_size = 224 * 8;
+ rd->ffcodecdata.mux_packet_size = 2048;
+ rd->ffcodecdata.mux_rate = 10080000;
+ break;
+ }
+
+ ffmpeg_set_expert_options(rd);
}
void BKE_ffmpeg_image_type_verify(RenderData *rd, ImageFormatData *imf)
{
- int audio = 0;
-
- if (imf->imtype == R_IMF_IMTYPE_FFMPEG) {
- if (rd->ffcodecdata.type <= 0 ||
- rd->ffcodecdata.codec <= 0 ||
- rd->ffcodecdata.audio_codec <= 0 ||
- rd->ffcodecdata.video_bitrate <= 1)
- {
- BKE_ffmpeg_preset_set(rd, FFMPEG_PRESET_H264);
- rd->ffcodecdata.constant_rate_factor = FFM_CRF_MEDIUM;
- rd->ffcodecdata.ffmpeg_preset = FFM_PRESET_GOOD;
- rd->ffcodecdata.type = FFMPEG_MKV;
- }
- if (rd->ffcodecdata.type == FFMPEG_OGG) {
- rd->ffcodecdata.type = FFMPEG_MPEG2;
- }
-
- audio = 1;
- }
- else if (imf->imtype == R_IMF_IMTYPE_H264) {
- if (rd->ffcodecdata.codec != AV_CODEC_ID_H264) {
- BKE_ffmpeg_preset_set(rd, FFMPEG_PRESET_H264);
- audio = 1;
- }
- }
- else if (imf->imtype == R_IMF_IMTYPE_XVID) {
- if (rd->ffcodecdata.codec != AV_CODEC_ID_MPEG4) {
- BKE_ffmpeg_preset_set(rd, FFMPEG_PRESET_XVID);
- audio = 1;
- }
- }
- else if (imf->imtype == R_IMF_IMTYPE_THEORA) {
- if (rd->ffcodecdata.codec != AV_CODEC_ID_THEORA) {
- BKE_ffmpeg_preset_set(rd, FFMPEG_PRESET_THEORA);
- audio = 1;
- }
- }
-
- if (audio && rd->ffcodecdata.audio_codec < 0) {
- rd->ffcodecdata.audio_codec = AV_CODEC_ID_NONE;
- rd->ffcodecdata.audio_bitrate = 128;
- }
+ int audio = 0;
+
+ if (imf->imtype == R_IMF_IMTYPE_FFMPEG) {
+ if (rd->ffcodecdata.type <= 0 || rd->ffcodecdata.codec <= 0 ||
+ rd->ffcodecdata.audio_codec <= 0 || rd->ffcodecdata.video_bitrate <= 1) {
+ BKE_ffmpeg_preset_set(rd, FFMPEG_PRESET_H264);
+ rd->ffcodecdata.constant_rate_factor = FFM_CRF_MEDIUM;
+ rd->ffcodecdata.ffmpeg_preset = FFM_PRESET_GOOD;
+ rd->ffcodecdata.type = FFMPEG_MKV;
+ }
+ if (rd->ffcodecdata.type == FFMPEG_OGG) {
+ rd->ffcodecdata.type = FFMPEG_MPEG2;
+ }
+
+ audio = 1;
+ }
+ else if (imf->imtype == R_IMF_IMTYPE_H264) {
+ if (rd->ffcodecdata.codec != AV_CODEC_ID_H264) {
+ BKE_ffmpeg_preset_set(rd, FFMPEG_PRESET_H264);
+ audio = 1;
+ }
+ }
+ else if (imf->imtype == R_IMF_IMTYPE_XVID) {
+ if (rd->ffcodecdata.codec != AV_CODEC_ID_MPEG4) {
+ BKE_ffmpeg_preset_set(rd, FFMPEG_PRESET_XVID);
+ audio = 1;
+ }
+ }
+ else if (imf->imtype == R_IMF_IMTYPE_THEORA) {
+ if (rd->ffcodecdata.codec != AV_CODEC_ID_THEORA) {
+ BKE_ffmpeg_preset_set(rd, FFMPEG_PRESET_THEORA);
+ audio = 1;
+ }
+ }
+
+ if (audio && rd->ffcodecdata.audio_codec < 0) {
+ rd->ffcodecdata.audio_codec = AV_CODEC_ID_NONE;
+ rd->ffcodecdata.audio_bitrate = 128;
+ }
}
void BKE_ffmpeg_codec_settings_verify(RenderData *rd)
{
- ffmpeg_set_expert_options(rd);
+ ffmpeg_set_expert_options(rd);
}
bool BKE_ffmpeg_alpha_channel_is_supported(RenderData *rd)
{
- int codec = rd->ffcodecdata.codec;
+ int codec = rd->ffcodecdata.codec;
- if (codec == AV_CODEC_ID_QTRLE)
- return true;
+ if (codec == AV_CODEC_ID_QTRLE)
+ return true;
- if (codec == AV_CODEC_ID_PNG)
- return true;
+ if (codec == AV_CODEC_ID_PNG)
+ return true;
- if (codec == AV_CODEC_ID_HUFFYUV)
- return true;
+ if (codec == AV_CODEC_ID_HUFFYUV)
+ return true;
-#ifdef FFMPEG_FFV1_ALPHA_SUPPORTED
- if (codec == AV_CODEC_ID_FFV1)
- return true;
-#endif
+# ifdef FFMPEG_FFV1_ALPHA_SUPPORTED
+ if (codec == AV_CODEC_ID_FFV1)
+ return true;
+# endif
- return false;
+ return false;
}
void *BKE_ffmpeg_context_create(void)
{
- FFMpegContext *context;
-
- /* new ffmpeg data struct */
- context = MEM_callocN(sizeof(FFMpegContext), "new ffmpeg context");
-
- context->ffmpeg_codec = AV_CODEC_ID_MPEG4;
- context->ffmpeg_audio_codec = AV_CODEC_ID_NONE;
- context->ffmpeg_video_bitrate = 1150;
- context->ffmpeg_audio_bitrate = 128;
- context->ffmpeg_gop_size = 12;
- context->ffmpeg_autosplit = 0;
- context->ffmpeg_autosplit_count = 0;
- context->ffmpeg_preview = false;
- context->stamp_data = NULL;
-
- return context;
+ FFMpegContext *context;
+
+ /* new ffmpeg data struct */
+ context = MEM_callocN(sizeof(FFMpegContext), "new ffmpeg context");
+
+ context->ffmpeg_codec = AV_CODEC_ID_MPEG4;
+ context->ffmpeg_audio_codec = AV_CODEC_ID_NONE;
+ context->ffmpeg_video_bitrate = 1150;
+ context->ffmpeg_audio_bitrate = 128;
+ context->ffmpeg_gop_size = 12;
+ context->ffmpeg_autosplit = 0;
+ context->ffmpeg_autosplit_count = 0;
+ context->ffmpeg_preview = false;
+ context->stamp_data = NULL;
+
+ return context;
}
void BKE_ffmpeg_context_free(void *context_v)
{
- FFMpegContext *context = context_v;
- if (context == NULL) {
- return;
- }
- if (context->stamp_data) {
- MEM_freeN(context->stamp_data);
- }
- MEM_freeN(context);
+ FFMpegContext *context = context_v;
+ if (context == NULL) {
+ return;
+ }
+ if (context->stamp_data) {
+ MEM_freeN(context->stamp_data);
+ }
+ MEM_freeN(context);
}
#endif /* WITH_FFMPEG */